Eu gostaria de adicionar uma coluna de soma cumulativa ao meu dataframe do Pandas para que:
name | day | no
-----|-----------|----
Jack | Monday | 10
Jack | Tuesday | 20
Jack | Tuesday | 10
Jack | Wednesday | 50
Jill | Monday | 40
Jill | Wednesday | 110
torna-se:
Jack | Monday | 10 | 10
Jack | Tuesday | 30 | 40
Jack | Wednesday | 50 | 90
Jill | Monday | 40 | 40
Jill | Wednesday | 110 | 150
Tentei vários combos de df.groupby
e df.agg(lambda x: cumsum(x))
sem sucesso.
Respostas:
Isso deve bastar, preciso
groupby()
duas vezes:df.groupby(['name', 'day']).sum() \ .groupby(level=0).cumsum().reset_index()
Explicação:
print(df) name day no 0 Jack Monday 10 1 Jack Tuesday 20 2 Jack Tuesday 10 3 Jack Wednesday 50 4 Jill Monday 40 5 Jill Wednesday 110 # sum per name/day print( df.groupby(['name', 'day']).sum() ) no name day Jack Monday 10 Tuesday 30 Wednesday 50 Jill Monday 40 Wednesday 110 # cumulative sum per name/day print( df.groupby(['name', 'day']).sum() \ .groupby(level=0).cumsum() ) no name day Jack Monday 10 Tuesday 40 Wednesday 90 Jill Monday 40 Wednesday 150
O dataframe resultante da primeira soma é indexado por
'name'
e por'day'
. Você pode ver isso imprimindodf.groupby(['name', 'day']).sum().index
Ao calcular a soma cumulativa, você deseja fazer isso por
'name'
, correspondendo ao primeiro índice (nível 0).Finalmente, use
reset_index
para repetir os nomes.df.groupby(['name', 'day']).sum().groupby(level=0).cumsum().reset_index() name day no 0 Jack Monday 10 1 Jack Tuesday 40 2 Jack Wednesday 90 3 Jill Monday 40 4 Jill Wednesday 150
fonte
name
eday
asmultiIndex
, o que faz mais sentido (reset_index()
para obter oint
índice, se desejar). 2), olevel=[0]
meiogroupby
é operar pelo 1º nível deMultiIndex
, nomeadamente colunaname
.groupby()
padrão é classificar as chaves, portanto, se você adicionar uma linha Jack-Thursday na parte inferior do conjunto de dados de entrada, obterá resultados inesperados. E comogroupby()
posso trabalhar com nomes de níveis, achodf.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()
menos enigmático.Isso funciona no pandas 0.16.2
In[23]: print df name day no 0 Jack Monday 10 1 Jack Tuesday 20 2 Jack Tuesday 10 3 Jack Wednesday 50 4 Jill Monday 40 5 Jill Wednesday 110 In[24]: df['no_cumulative'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum()) In[25]: print df name day no no_cumulative 0 Jack Monday 10 10 1 Jack Tuesday 20 30 2 Jack Tuesday 10 40 3 Jack Wednesday 50 90 4 Jill Monday 40 40 5 Jill Wednesday 110 150
fonte
name
eday
antes de calcular a soma cumulativa porname
(nota: há 2 linhas para Jack + terça-feira no resultado). Isso é o que o torna mais simples do que a resposta de CT Zhu .Modificação da resposta de @Dmitry. Isso é mais simples e funciona no pandas 0.19.0:
print(df) name day no 0 Jack Monday 10 1 Jack Tuesday 20 2 Jack Tuesday 10 3 Jack Wednesday 50 4 Jill Monday 40 5 Jill Wednesday 110 df['no_csum'] = df.groupby(['name'])['no'].cumsum() print(df) name day no no_csum 0 Jack Monday 10 10 1 Jack Tuesday 20 30 2 Jack Tuesday 10 40 3 Jack Wednesday 50 90 4 Jill Monday 40 40 5 Jill Wednesday 110 150
fonte
você deveria usar
df['cum_no'] = df.no.cumsum()
http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html
Outra maneira de fazer isso
import pandas as pd df = pd.DataFrame({'C1' : ['a','a','a','b','b'], 'C2' : [1,2,3,4,5]}) df['cumsum'] = df.groupby(by=['C1'])['C2'].transform(lambda x: x.cumsum()) df
fonte
90
como a soma de todos os valores de Jack, +40
, o valor de Jill-Monday).Em vez de
df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum()
(veja acima), você também pode fazer umdf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()
df.groupby(by=['name','day']).sum()
está na verdade apenas movendo ambas as colunas para um MultiIndexas_index=False
significa que você não precisa chamar reset_index depoisfonte
groupby().sum()
não se trata apenas de mover ambas as colunas para MultiIndex - também soma os dois valores de Jack + Tuesday. Eas_index=False
não parece ter nenhum efeito neste caso, uma vez que o índice já foi definido antes degroupby
. E já quegroupby().cumsum()
nukes o nome / dia das colunas do quadro de dados, você deve adicionar a coluna numérica resultante ao quadro de dados original (como vjayky e Dmitry sugeriram) ou mover nome / dia para o índice e reset_index depois.data.csv:
name,day,no Jack,Monday,10 Jack,Tuesday,20 Jack,Tuesday,10 Jack,Wednesday,50 Jill,Monday,40 Jill,Wednesday,110
Código:
import numpy as np import pandas as pd df = pd.read_csv('data.csv') print(df) df = df.groupby(['name', 'day'])['no'].sum().reset_index() print(df) df['cumsum'] = df.groupby(['name'])['no'].apply(lambda x: x.cumsum()) print(df)
Resultado:
name day no 0 Jack Monday 10 1 Jack Tuesday 20 2 Jack Tuesday 10 3 Jack Wednesday 50 4 Jill Monday 40 5 Jill Wednesday 110 name day no 0 Jack Monday 10 1 Jack Tuesday 30 2 Jack Wednesday 50 3 Jill Monday 40 4 Jill Wednesday 110 name day no cumsum 0 Jack Monday 10 10 1 Jack Tuesday 30 40 2 Jack Wednesday 50 90 3 Jill Monday 40 40 4 Jill Wednesday 110 150
fonte