Обнаружение последовательности данных: найдите группы, в которых три строки подряд имеют отрицательные значения - PullRequest
3 голосов
/ 14 марта 2020

Допустим, у меня есть столбец df['test']:

-1, -2, -3, 2, -4, 3, -5, -4, -3, -7

Поэтому я хотел бы отфильтровать группы, которые имеют по крайней мере три отрицательных значения в строке. Итак,

groups = my_grouping_function_by_sequence()
groups[0] = [-1,-2-3]
groups[1] = [-5,-4,-3,-7] 

Есть ли какие-то заранее определенные проверки при проверке последовательностей в числовых данных для pandas? Это не обязательно должно быть pandas, но я ищу быстрое и адаптируемое решение. Любые советы будут полезны. Спасибо!

Ответы [ 3 ]

3 голосов
/ 14 марта 2020

Использование GroupBy и cumsum для создания групп последовательных отрицательных чисел.

grps = df['test'].gt(0).cumsum()
dfs = [d.dropna() for _, d in df.mask(df['test'].gt(0)).groupby(grps) if d.shape[0] >= 3]

Вывод

for df in dfs:
    print(df)

   test
0  -1.0
1  -2.0
2  -3.0
   test
6  -5.0
7  -4.0
8  -3.0
9  -7.0

Пояснение

Давайте go пройдем этот шаг за шагом: Первая строка создает группы для последовательных отрицательных чисел

print(grps)
0    0
1    0
2    0
3    1
4    1
5    2
6    2
7    2
8    2
9    2
Name: test, dtype: int32

Но, как мы видим, она также включает в себя положительные числа, которые мы не хотим учитывать в нашем выводе. Поэтому мы используем DataFrame.mask для преобразования этих значений в NaN:

df.mask(df['test'].gt(0))
# same as df.mask(df['test'] > 0)

   test
0  -1.0
1  -2.0
2  -3.0
3   NaN
4  -4.0
5   NaN
6  -5.0
7  -4.0
8  -3.0
9  -7.0

Затем мы группируем данные на этом кадре данных и сохраняем только те группы, которые >= 3 строки:

for _, d in df.mask(df['test'].gt(0)).groupby(grps):
    if d.shape[0] >= 3:
        print(d.dropna())

   test
0  -1.0
1  -2.0
2  -3.0
   test
6  -5.0
7  -4.0
8  -3.0
9  -7.0
2 голосов
/ 14 марта 2020

Слишком признателен, что ответ @erfan изящен, но не так легко понять. Моя попытка ниже.

df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})

Условно выделите строки с отрицательными значениями

df['j'] = np.where(df['test']<0,1,-1)
df['k']=df['j'].rolling(3, min_periods=1).sum()
df2=df[df['k']==3]

slice Итеративно кадр данных получает 3-й и 2-й последовательные строки выше

for index, row in df2.iterrows():
    print(df.loc[index - 2 : index + 0, 'test'])
1 голос
/ 14 марта 2020

@ Эрфан, твой ответ великолепен, и я все еще пытаюсь понять вторую строку. Ваша первая строка заставила меня начать писать ее собственным, менее эффективным способом.

import pandas as pd
df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
df['+ or -'] = df['test'].gt(0)
df['group'] = df['+ or -'].cumsum()

df_gb = df.groupby('group').count().reset_index().drop('+ or -', axis=1)

df_new = pd.merge(df, df_gb, how='left', on='group').drop('+ or -', axis=1)
df_new = df_new[(df_new['test_x'] < 0) & (df_new['test_y'] >=3)].drop('test_y', 
axis=1)

for i in df_new['group'].unique():
    j = pd.DataFrame(df_new.loc[df_new['group'] == i, 'test_x'])
    print(j)
...