Je voudrais ajouter une colonne de somme cumulée à mon dataframe Pandas afin que:
name | day | no
-----|-----------|----
Jack | Monday | 10
Jack | Tuesday | 20
Jack | Tuesday | 10
Jack | Wednesday | 50
Jill | Monday | 40
Jill | Wednesday | 110
devient:
Jack | Monday | 10 | 10
Jack | Tuesday | 30 | 40
Jack | Wednesday | 50 | 90
Jill | Monday | 40 | 40
Jill | Wednesday | 110 | 150
J'ai essayé divers combos df.groupby
et df.agg(lambda x: cumsum(x))
en vain.
Réponses:
Cela devrait le faire, besoin de
groupby()
deux fois:df.groupby(['name', 'day']).sum() \ .groupby(level=0).cumsum().reset_index()
Explication:
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
Le dataframe résultant de la première somme est indexé par
'name'
et par'day'
. Vous pouvez le voir en imprimantdf.groupby(['name', 'day']).sum().index
Lors du calcul de la somme cumulée, vous voulez le faire par
'name'
, correspondant au premier index (niveau 0).Enfin, utilisez
reset_index
pour répéter les noms.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
la source
name
etday
asmultiIndex
, ce qui est plus logique (reset_index()
pour obtenir l'int
index, si vous le souhaitez). 2), lelevel=[0]
moyengroupby
est de fonctionner par le 1er niveau deMultiIndex
, à savoir la colonnename
.groupby()
défaut consiste à trier les clés, donc si vous ajoutez une ligne Jack-Thursday au bas de l'ensemble de données d'entrée, vous obtiendrez des résultats inattendus. Et commegroupby()
je peux travailler avec des noms de niveau, je trouvedf.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()
moins cryptique.Cela fonctionne dans les 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
la source
name
etday
avant de calculer la somme cumulée parname
(note: il y a 2 lignes pour Jack + mardi dans le résultat). C'est ce qui le rend plus simple que la réponse de CT Zhu .Modification de la réponse de @ Dmitry. C'est plus simple et fonctionne dans les 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
la source
Tu devrais utiliser
df['cum_no'] = df.no.cumsum()
http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html
Une autre façon de faire
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
la source
90
, en tant que somme de toutes les valeurs de Jack, +40
, la valeur de Jill-Monday).Au lieu de
df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum()
(voir ci-dessus), vous pouvez également faire undf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()
df.groupby(by=['name','day']).sum()
déplace simplement les deux colonnes vers un MultiIndexas_index=False
signifie que vous n'avez pas besoin d'appeler reset_index par la suitela source
groupby().sum()
ne s'agit pas simplement de déplacer les deux colonnes vers MultiIndex - cela résume également les deux valeurs pour Jack + Tuesday. Etas_index=False
ne semble pas avoir d'effet dans ce cas, puisque l'index était déjà défini avant legroupby
. Et commegroupby().cumsum()
nukes le nom / jour des colonnes de la trame de données, vous devez soit ajouter la colonne numérique résultante à la trame de données d'origine (comme vjayky et Dmitry suggéré), ou déplacer nom / jour vers index, et reset_index par la suite.data.csv:
name,day,no Jack,Monday,10 Jack,Tuesday,20 Jack,Tuesday,10 Jack,Wednesday,50 Jill,Monday,40 Jill,Wednesday,110
Code:
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)
Production:
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
la source