Pandas заполняет условие другого столбца

У меня есть следующий фрагмент из более крупного фрейма данных:

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 27.04.2024 16:44
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Как отмечает @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. Можно ли это сделать, используя подход векторизации?

Michael Felman 27.04.2024 17:39

@MichaelFelman Я обновляю свой ответ, чтобы также ответить на ваш комментарий.

Serge de Gosson de Varennes 27.04.2024 17:50

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

Другие вопросы по теме