У меня есть следующий фрагмент из более крупного фрейма данных:
pd.DataFrame({
'sig_2':[False, False, True, True, True, True, True, True, True, True, True, False, False, False,
False, True, False, True, True, True, True, True, True, True, True, True, False, False,
False, False, True, True, True, True, False, True, True],
'tr_cnt':[0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2],
'fls_cnt':[53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 1, 0, 0],
'test1':[0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 4, 4, 4, 4, 0, 16, 16],
'test2':[54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 1, 0, 0],
'check1':[False, False, True, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, True, False, False, False, False, False, False]})
tr_cnt
— это просто количество последовательных истинных строк в sig_2
, а fls_cnt
делает то же самое для ложных строк. test1
и test2
— общее количество последовательных строк. check1
— это когда следующее условие истинно:
df['test1'] > 2) & (df['fls_cnt'].shift(1) >= 2)
Я хотел бы заполнить истинные значения в столбце check1
соответствующим значением в столбце test1
.
Например, первая строка True в столбце check1
имеет соответствующее значение 9 в столбце test
. Таким образом, я хотел бы переслать это значение еще на 8 строк. Следующее значение True имеет соответствующее значение 4, поэтому я хочу, чтобы оно перенаправило заполнение еще на 3 строки.
Я пробовал следующие разные методы:
mask = (df['test1'] > 2) & (df['fls_cnt'].shift(1) >= 2)
# Trial 1
groups = mask.ne(mask.shift()).cumsum()
df['test1'] = df.groupby(groups)['test1'].ffill().astype(bool)
# Trial 2
df['test2'] = df.groupby(mask)['test1'].ffill().astype(bool)
# Trial 3
groups = (~mask).cumsum()
df['test3'] = df.groupby(groups)['test1'].ffill().astype(bool)
# Trial 4
df["test4"] = df.groupby(mask.cumsum())['test1'].ffill().fillna(False).astype(bool)
Кажется, что во всех этих методах они делают то, что я хочу, когда условие истинно, но они также включают строки, которые не удовлетворяют этому условию, что является странным.
Как отмечает @mozway в комментариях к вашему вопросу, немного неясно, что вы пытаетесь сделать. Предлагаю здесь свою интерпретацию вашей логики. Если это не то, что вы ожидали, я просто удалю ответ. Но в этом случае я также предлагаю вам пересмотреть свой вопрос и уточнить, быть более ясным:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'sig_2': [False, False, True, True, True, True, True, True, True, True, True, False, False, False,
False, True, False, True, True, True, True, True, True, True, True, True, False, False,
False, False, True, True, True, True, False, True, True],
'tr_cnt': [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2],
'fls_cnt': [53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 1, 0, 0],
'test1': [0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 4, 4, 4, 4, 0, 16, 16],
'test2': [54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 1, 0, 0],
'check1': [False, False, True, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, True, False, False, False, False, False, False]
})
df['forward_fill'] = False
for i in df.index[df['check1']]:
end_index = i + df.at[i, 'test1']
if end_index > len(df):
end_index = len(df)
df.loc[i:end_index, 'forward_fill'] = True
print(df)
Который дает:
sig_2 tr_cnt fls_cnt test1 test2 check1 forward_fill
0 False 0 53 0 54 False False
1 False 0 54 0 54 False False
2 True 1 0 9 0 True True
3 True 2 0 9 0 False True
4 True 3 0 9 0 False True
5 True 4 0 9 0 False True
6 True 5 0 9 0 False True
7 True 6 0 9 0 False True
8 True 7 0 9 0 False True
9 True 8 0 9 0 False True
10 True 9 0 9 0 False True
11 False 0 1 0 4 False True
12 False 0 2 0 4 False False
13 False 0 3 0 4 False False
14 False 0 4 0 4 False False
15 True 1 0 1 0 False False
16 False 0 1 0 1 False False
17 True 1 0 9 0 False False
18 True 2 0 9 0 False False
19 True 3 0 9 0 False False
20 True 4 0 9 0 False False
21 True 5 0 9 0 False False
22 True 6 0 9 0 False False
23 True 7 0 9 0 False False
24 True 8 0 9 0 False False
25 True 9 0 9 0 False False
26 False 0 1 0 4 False False
27 False 0 2 0 4 False False
28 False 0 3 0 4 False False
29 False 0 4 0 4 False False
30 True 1 0 4 0 True True
31 True 2 0 4 0 False True
32 True 3 0 4 0 False True
33 True 4 0 4 0 False True
34 False 0 1 0 1 False True
35 True 1 0 16 0 False False
36 True 2 0 16 0 False False
Обновление. Альтернативный способ (более векторизованный):
import pandas as pd
import numpy as np
df = pd.DataFrame({
'sig_2': [False, False, True, True, True, True, True, True, True, True, True, False, False, False,
False, True, False, True, True, True, True, True, True, True, True, True, False, False,
False, False, True, True, True, True, False, True, True],
'tr_cnt': [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2],
'fls_cnt': [53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 1, 0, 0],
'test1': [0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 4, 4, 4, 4, 0, 16, 16],
'test2': [54, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 1, 0, 0],
'check1': [False, False, True, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False, False, False, False, False,
False, False, False, False, True, False, False, False, False, False, False]
})
indices = np.repeat(df.index[df['check1']], df['test1'][df['check1']])
ranges = np.concatenate([np.arange(start, start + length) for start, length in zip(df.index[df['check1']], df['test1'][df['check1']])])
mask = np.zeros(len(df), dtype=bool)
mask[ranges] = True
df['forward_fill'] = mask
print(df)
который возвращает тот же вывод:
sig_2 tr_cnt fls_cnt test1 test2 check1 forward_fill
0 False 0 53 0 54 False False
1 False 0 54 0 54 False False
2 True 1 0 9 0 True True
3 True 2 0 9 0 False True
4 True 3 0 9 0 False True
5 True 4 0 9 0 False True
6 True 5 0 9 0 False True
7 True 6 0 9 0 False True
8 True 7 0 9 0 False True
9 True 8 0 9 0 False True
10 True 9 0 9 0 False True
11 False 0 1 0 4 False False
12 False 0 2 0 4 False False
13 False 0 3 0 4 False False
14 False 0 4 0 4 False False
15 True 1 0 1 0 False False
16 False 0 1 0 1 False False
17 True 1 0 9 0 False False
18 True 2 0 9 0 False False
19 True 3 0 9 0 False False
20 True 4 0 9 0 False False
21 True 5 0 9 0 False False
22 True 6 0 9 0 False False
23 True 7 0 9 0 False False
24 True 8 0 9 0 False False
25 True 9 0 9 0 False False
26 False 0 1 0 4 False False
27 False 0 2 0 4 False False
28 False 0 3 0 4 False False
29 False 0 4 0 4 False False
30 True 1 0 4 0 True True
31 True 2 0 4 0 False True
32 True 3 0 4 0 False True
33 True 4 0 4 0 False True
34 False 0 1 0 1 False False
35 True 1 0 16 0 False False
36 True 2 0 16 0 False False
Спасибо за быстрый ответ. То, что вы сделали, во многом соответствует тому, что я хотел, единственное, что я ожидал, это изменить end_index
на end_index = i + df.at[i, 'test1'] - 1
. Можно ли это сделать, используя подход векторизации?
@MichaelFelman Я обновляю свой ответ, чтобы также ответить на ваш комментарий.
IIUC, вам нужен простой transform('any')
на последующем True
, если у вас есть True
в check1
:
group = df['sig_2'].ne(df['sig_2'].shift()).cumsum()
df['out'] = df['check1'].groupby(group).transform('any')
Выход:
sig_2 tr_cnt fls_cnt test1 test2 check1 out
0 False 0 53 0 54 False False
1 False 0 54 0 54 False False
2 True 1 0 9 0 True True
3 True 2 0 9 0 False True
4 True 3 0 9 0 False True
5 True 4 0 9 0 False True
6 True 5 0 9 0 False True
7 True 6 0 9 0 False True
8 True 7 0 9 0 False True
9 True 8 0 9 0 False True
10 True 9 0 9 0 False True
11 False 0 1 0 4 False False
12 False 0 2 0 4 False False
13 False 0 3 0 4 False False
14 False 0 4 0 4 False False
15 True 1 0 1 0 False False
16 False 0 1 0 1 False False
17 True 1 0 9 0 False False
18 True 2 0 9 0 False False
19 True 3 0 9 0 False False
20 True 4 0 9 0 False False
21 True 5 0 9 0 False False
22 True 6 0 9 0 False False
23 True 7 0 9 0 False False
24 True 8 0 9 0 False False
25 True 9 0 9 0 False False
26 False 0 1 0 4 False False
27 False 0 2 0 4 False False
28 False 0 3 0 4 False False
29 False 0 4 0 4 False False
30 True 1 0 4 0 True True
31 True 2 0 4 0 False True
32 True 3 0 4 0 False True
33 True 4 0 4 0 False True
34 False 0 1 0 1 False False
35 True 1 0 16 0 False False
36 True 2 0 16 0 False False
Неясно, каковы входные данные и ожидаемый результат, можете ли вы уточнить?