Выбор строк на основе кадра данных 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

149
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, потому что они отсчитываются от нуля.


Код

Чтобы получить строки, соответствующие всем условиям, существующим выше 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)]

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

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