Условный подсчет накопленной суммы Dataframe - цикл по столбцам - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь вычислить кумулятивную сумму со сбросом в пределах кадра данных, основываясь на знаке каждого значения.Идея состоит в том, чтобы выполнить одно и то же упражнение для каждого столбца в отдельности.

Например, предположим, что у меня есть следующий кадр данных:

df = pd.DataFrame({'A': [1,1,1,-1,-1,1,1,1,1,-1,-1,-1],'B':[1,1,-1,-1,-1,1,1,1,-1,-1,-1,1]},index=[0, 1, 2, 3,4,5,6,7,8,9,10,11])

Для каждого столбца я хочу вычислить накопленную сумму доЯ нахожу изменение в знаке;в этом случае сумма должна быть сброшена до 1. Для приведенного выше примера я ожидаю следующий результат:

df1=pd.DataFrame({'A_cumcount':[1,2,3,1,2,1,2,3,4,1,2,3],'B_cumcount':[1,2,1,2,3,1,2,3,1,2,3,4],index=[0,1,2,3,4,5,6,7,8,9,10,11]})

Подобная проблема обсуждалась здесь: Панды: условный скользящий счет

Я пробовал следующий код:

nb_col=len(df.columns) #number of columns in dataframe


for i in range(0,int(nb_col)): #Loop through the number of columns in the dataframe

    name=df.columns[i] #read the column name
    name=name+'_cumcount' 


    #add column for the calculation
    df=df.reindex(columns=np.append(df.columns.values, [name])) 

    df=df[df.columns[nb_col+i]]=df.groupby((df[df.columns[i]] != df[df.columns[i]].shift(1)).cumsum()).cumcount()+1

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

Полученные ответы (все работает нормально): От @nixon df.apply(lambda x: x.groupby(x.diff().ne(0).cumsum()).cumcount()+1).add_suffix('_cumcount')

От @jezrael df1 = (df.apply(lambda x: x.groupby((x != x.shift()).cumsum()).cumcount() + 1).add_suffix('_cumcount'))

От @Scott Бостон:

df.apply(lambda x: x.groupby(x.diff().bfill().ne(0).cumsum()).cumcount() + 1)

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

Вы можете попробовать это:

df.apply(lambda x: x.groupby(x.diff().bfill().ne(0).cumsum()).cumcount() + 1)

Вывод:

    A  B
0   1  1
1   2  2
2   3  1
3   1  2
4   2  3
5   1  1
6   2  2
7   3  3
8   4  1
9   1  2
10  2  3
11  3  1
0 голосов
/ 04 декабря 2018

Я думаю, что в пандах нужна петля, например, по apply:

df1 = (df.apply(lambda x: x.groupby((x != x.shift()).cumsum()).cumcount() + 1)
         .add_suffix('_cumcount'))
print (df1)
    A_cumcount  B_cumcount
0            1           1
1            2           2
2            3           1
3            1           2
4            2           3
5            1           1
6            2           2
7            3           3
8            4           1
9            1           2
10           2           3
11           3           1
0 голосов
/ 04 декабря 2018

Вы можете начать с группировки, по которой происходят изменения в последовательности, выполнив x.diff().ne(0).cumsum() и используя cumcount над группами:

df.apply(lambda x: x.groupby(x.diff().ne(0).cumsum())
                    .cumcount()+1).add_suffix('_cumcount')

        A_cumcount  B_cumcount
0            1           1
1            2           2
2            3           1
3            1           2
4            2           3
5            1           1
6            2           2
7            3           3
8            4           1
9            1           2
10           2           3
11           3           1
...