Идентификация последовательных вхождений значения

У меня есть df, например:

Count
1
0
1
1
0
0
1
1
1
0

и я хочу вернуть 1 в новый столбец, если есть два или более последовательных вхождения 1 в Count и a 0, если их нет. Таким образом, в новом столбце каждая строка будет получать 1 на основе этого критерия, который встречается в столбце Count. Тогда мой желаемый результат:

Count  New_Value
1      0 
0      0
1      1
1      1
0      0
0      0
1      1
1      1 
1      1
0      0

Я думаю, мне, возможно, придется использовать itertools, но я читал об этом и не сталкивался с тем, что мне нужно. Я хотел бы иметь возможность использовать этот метод для подсчета количества последовательных событий, а не только для двух. Например, иногда мне нужно подсчитать 10 последовательных явлений, я просто использую 2 в примере здесь.

Ответ 1

Вы можете:

df['consecutive'] = df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count

чтобы получить:

   Count  consecutive
0      1            1
1      0            0
2      1            2
3      1            2
4      0            0
5      0            0
6      1            3
7      1            3
8      1            3
9      0            0

Отсюда вы можете, для любого порога:

threshold = 2
df['consecutive'] = (df.consecutive > threshold).astype(int)

чтобы получить:

   Count  consecutive
0      1            0
1      0            0
2      1            1
3      1            1
4      0            0
5      0            0
6      1            1
7      1            1
8      1            1
9      0            0

или, за один шаг:

(df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count >= threshold).astype(int)

С точки зрения эффективности использование методов pandas обеспечивает значительное ускорение при увеличении размера проблемы:

 df = pd.concat([df for _ in range(1000)])

%timeit (df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count >= threshold).astype(int)
1000 loops, best of 3: 1.47 ms per loop

по сравнению с:

%%timeit
l = []
for k, g in groupby(df.Count):
    size = sum(1 for _ in g)
    if k == 1 and size >= 2:
        l = l + [1]*size
    else:
        l = l + [0]*size    
pd.Series(l)

10 loops, best of 3: 76.7 ms per loop

Ответ 2

Не уверен, что это оптимизировано, но вы можете попробовать:

from itertools import groupby
import pandas as pd

l = []
for k, g in groupby(df.Count):
    size = sum(1 for _ in g)
    if k == 1 and size >= 2:
        l = l + [1]*size
    else:
        l = l + [0]*size

df['new_Value'] = pd.Series(l)

df

Count   new_Value
0   1   0
1   0   0
2   1   1
3   1   1
4   0   0
5   0   0
6   1   1
7   1   1
8   1   1
9   0   0