Выбор строк на основе кадра данных Padas с двумя столбцами

У меня есть фрейм данных панды. Я хочу создать подкадры данных на основе некоторых условий. Если typeId == 15, возьмите все предыдущие строки только с typeId == 1 и результатом == 1 и сохраните их в подкадре данных.

идентификатор типа результат 1 2 3 2 4 1 3 1 1 4 1 1 5 15 1 6 3 4 7 2 1 8 1 1 9 1 1 10 15 1 11 4 4 12 3 3

У меня должно быть два подкадра данных, первый из которых

идентификатор типа результат 3 1 1 4 1 1 5 15 1

И второй

идентификатор типа результат 8 1 1 9 1 1 10 15 1

Можете ли вы красиво отформатировать примеры?

Milos Stojanovic 02.09.2024 22:42

Извините за ошибки. Я обновил вопрос

WilliamAshoti 02.09.2024 22:48
0
2
149
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Что-то подобное работает для вас?

subdataframes = []
start_idx = 0

for idx in df[df['typeId'] == 15].index:
    subdf = df.loc[start_idx:idx][(df['typeId'] == 1) & (df['result'] == 1)]
    subdf = pd.concat([subdf, df.loc[[idx]]])
    subdataframes.append(subdf)
    start_idx = idx

Результат:

Subdataframe 1:
   typeId  result
2       1       1
3       1       1
4      15       1

Subdataframe 2:
   typeId  result
7       1       1
8       1       1
9      15       1

Индексы отклонены на 1, потому что они отсчитываются от нуля.

Привет, Милош, спасибо за быстрый ответ. Это работает, но не тот результат, который я хочу. Код выбирает все строки с typeId == 1 и результатом == 1, даже если есть строка, которая не равна typeId 1 и результату 1.

WilliamAshoti 02.09.2024 23:14

Можете ли вы поделиться примером, где это не работает? Должен ли подфрейм данных включать строку с typeId == 15, если результат в этой строке не равен 1?

Milos Stojanovic 02.09.2024 23:17

Можете ли вы проверить, установлен ли начальный индекс в переменную start_idx. Когда я впервые опубликовал сообщение, я его не разместил, но отредактировал ответ за несколько секунд, поэтому не думаю, что это проблема, но лучше перестраховаться, чем потом сожалеть.

Milos Stojanovic 02.09.2024 23:28

Я проверю это. Спасибо.

WilliamAshoti 02.09.2024 23:34

Код

Чтобы получить строки, соответствующие всем условиям, существующим выше 15, на основе 15, используйте следующий код (строки, соответствующие условию, даже если они не смежны с 15, будут импортированы)

cond1 = df['typeId'].eq(15)
grp = cond1.cumsum() - cond1
cond2 = df['typeId'].eq(1) & df['result'].eq(1)
cond3 = cond1.groupby(grp).transform(any)
out = [d for _, d in df[cond1 | (cond2 & cond3)].groupby(grp)]

вне:

[   typeId  result
 3       1       1
 4       1       1
 5      15       1,
     typeId  result
 8        1       1
 9        1       1
 10      15       1]

Если вы хотите извлечь только строки, соответствующие условию, смежному с 15, на основе 15, используйте следующий код (получить последовательные строки 1–1, смежные с 15).

cond1 = df['typeId'].eq(15)
grp = cond1.cumsum() - cond1
cond2 = df['typeId'].eq(1) & df['result'].eq(1)
cond3 = df['typeId'].mask(cond2).bfill().eq(15)
out = [d for _, d in df[cond3].groupby(grp)]

Очень рад видеть несколько вариантов. Всем большое спасибо.

WilliamAshoti 03.09.2024 10:00

Если вы хотите сохранить только смежные строки:

res = []

for i, g in df.groupby((df["typeId"].eq(15))[::-1].cumsum()):
    g = g[(g["typeId"].eq(15) | (g["typeId"].eq(1) & g["result"].eq(1)))]
    if not g.empty:
        m = g.index.to_series().diff().fillna(1).ne(1).cumsum()
        m = m[m == m.max()].index
        g = g.loc[m]
        res.append(g)
for df in res:
    print(df)
    typeId  result
8        1       1
9        1       1
10      15       1
   typeId  result
3       1       1
4       1       1
5      15       1

Вы можете добиться этого с помощью простой группы . Определите участки typeId==1/result==1, сгруппируйте их со следующей строкой (с обратной совокупной суммой), сохраните группу только в том случае, если последний typeId==15:

# identify stretches of typeId==1/result==1
m = df['typeId'].eq(1) & df['result'].eq(1)

# group with following row
# only keep it last typeId==15
out = [g for _,g in df.groupby((~m)[::-1].cumsum(), sort=False)
       if g['typeId'].iloc[-1] == 15]

Выход:

[   typeId  result
 3       1       1
 4       1       1
 5      15       1,
     typeId  result
 8        1       1
 9        1       1
 10      15       1]

Примечание. если вы хотите, чтобы выходные кадры данных содержали строки с единицами, измените условие фильтрации на if len(g)>1 and g['typeId'].iloc[-1] == 15.

Промежуточные продукты:

    typeId  result      m  group keep
1        2       3  False      8     
2        4       1  False      7     
3        1       1   True      6    |
4        1       1   True      6    |
5       15       1  False      6    X
6        3       4  False      5     
7        2       1  False      4     
8        1       1   True      3    |
9        1       1   True      3    |
10      15       1  False      3    X
11       4       4  False      2     
12       3       3  False      1     

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