Рассчитать полосу в пандах без применения - PullRequest
3 голосов
/ 08 октября 2019

У меня есть DataFrame, подобный следующему:

date       | type | column1
----------------------------
2019-01-01 |   A  |    1
2019-02-01 |   A  |    1
2019-03-01 |   A  |    1
2019-04-01 |   A  |    0
2019-05-01 |   A  |    1
2019-06-01 |   A  |    1
2019-07-01 |   B  |    1
2019-08-01 |   B  |    1
2019-09-01 |   B  |    0

Я хочу иметь столбец с именем "streak", имеющий полосу, но сгруппированный по столбцу "type":

date       | type | column1 | streak
-------------------------------------
2019-01-01 |   A  |    1    |   1
2019-02-01 |   A  |    1    |   2
2019-03-01 |   A  |    1    |   3
2019-04-01 |   A  |    0    |   0
2019-05-01 |   A  |    1    |   1
2019-06-01 |   A  |    1    |   2
2019-07-01 |   B  |    1    |   1
2019-08-01 |   B  |    1    |   2
2019-09-01 |   B  |    0    |   0

Мне удалось сделать это следующим образом:

def streak(df):
    grouper = (df.column1 != df.column1.shift(1)).cumsum()
    df['streak'] = df.groupby(grouper).cumsum()['column1']
    return df

df = df.groupby(['type']).apply(streak)

Но мне интересно, возможно ли сделать это встроенным без использования группировки и применения, потому что мой DataFrame содержит около 100 миллионов строк, и это занимает несколько часов, чтобыпроцесс.

Любые идеи о том, как оптимизировать это для скорости?

Ответы [ 2 ]

4 голосов
/ 08 октября 2019

IIUC, это то, что вам нужно.

m = df.column1.ne(df.column1.shift()).cumsum()
df['streak'] =df.groupby([m , 'type'])['column1'].cumsum()

Вывод

       date     type    column1     streak  
0   1/1/2019    A             1     1   
1   2/1/2019    A             1     2   
2   3/1/2019    A             1     3   
3   4/1/2019    A             0     0   
4   5/1/2019    A             1     1   
5   6/1/2019    A             1     2   
6   7/1/2019    B             1     1   
7   8/1/2019    B             1     2   
8   9/1/2019    B             0     0   
4 голосов
/ 08 октября 2019

Требуется группировка cumsum из 'column1' по 'type' + cumsum логического ряда, который сбрасывает группировку через каждые 0.

df['streak'] = df.groupby(['type', df.column1.eq(0).cumsum()]).column1.cumsum()

         date type  column1  streak
0  2019-01-01    A        1       1
1  2019-02-01    A        1       2
2  2019-03-01    A        1       3
3  2019-04-01    A        0       0
4  2019-05-01    A        1       1
5  2019-06-01    A        1       2
6  2019-07-01    B        1       1
7  2019-08-01    B        1       2
8  2019-09-01    B        0       0
...