Me gustaría agregar una columna de suma acumulativa a mi marco de datos Pandas para que:
name | day | no
-----|-----------|----
Jack | Monday | 10
Jack | Tuesday | 20
Jack | Tuesday | 10
Jack | Wednesday | 50
Jill | Monday | 40
Jill | Wednesday | 110
se convierte en:
Jack | Monday | 10 | 10
Jack | Tuesday | 30 | 40
Jack | Wednesday | 50 | 90
Jill | Monday | 40 | 40
Jill | Wednesday | 110 | 150
Probé varios combos de df.groupbyy df.agg(lambda x: cumsum(x))sin éxito.

Respuestas:
Esto debería hacerlo, necesita
groupby()dos veces:df.groupby(['name', 'day']).sum() \ .groupby(level=0).cumsum().reset_index()Explicación:
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 150El marco de datos resultante de la primera suma se indexa por
'name'y por'day'. Puedes verlo imprimiendodf.groupby(['name', 'day']).sum().indexAl calcular la suma acumulada, desea hacerlo por
'name', correspondiente al primer índice (nivel 0).Por último, utilice
reset_indexpara que se repitan los nombres.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 150fuente
nameydaycomomultiIndex, que tiene más sentido (reset_index()para obtener unintíndice, si lo desea). 2), ellevel=[0]mediogroupbyes operar por el 1er nivel deMultiIndex, a saber, la columnaname.groupby()predeterminado para ordenar las claves, por lo que si agrega una fila Jack-Thursday en la parte inferior del conjunto de datos de entrada, obtendrá resultados inesperados. Y comogroupby()puedo trabajar con nombres de nivel, me parecedf.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()menos críptico.Esto funciona en 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 150fuente
nameydayantes de calcular la suma acumulada porname(nota: hay 2 filas para Jack + Tuesday en el resultado). Esto es lo que lo hace más simple que la respuesta de CT Zhu .Modificación a la respuesta de @ Dmitry. Esto es más simple y funciona en 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 150fuente
Deberías usar
df['cum_no'] = df.no.cumsum()http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html
Otra forma de hacerlo
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()) dffuente
90como la suma de todos los valores de Jack, +40, el valor de Jill-Monday).En lugar de
df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum()(ver arriba) también puede hacer undf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()df.groupby(by=['name','day']).sum()en realidad, solo mueve ambas columnas a un MultiIndexas_index=Falsesignifica que no necesita llamar a reset_index despuésfuente
groupby().sum()no solo está moviendo ambas columnas a MultiIndex, sino que también resume los dos valores para Jack + Tuesday. Yas_index=Falseno parece tener ningún efecto en este caso, ya que el índice ya se estableció antes degroupby. Y dado quegroupby().cumsum()extrae el nombre / día de las columnas del marco de datos, debe agregar la columna numérica resultante al marco de datos original (como sugirieron vjayky y Dmitry), o mover el nombre / día al índice, y luego reiniciar_index.data.csv:
name,day,no Jack,Monday,10 Jack,Tuesday,20 Jack,Tuesday,10 Jack,Wednesday,50 Jill,Monday,40 Jill,Wednesday,110Có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)Salida:
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 150fuente