J'ai un objet de série chronologique grouped
du type <pandas.core.groupby.SeriesGroupBy object at 0x03F1A9F0>
. grouped.sum()
donne le résultat souhaité mais je ne peux pas faire rouler_sum avec l'objet groupby
. Existe-t-il un moyen d'appliquer des fonctions de roulement aux objets groupby
? Par exemple:
x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']
df = DataFrame(Zip(id, x), columns = ['id', 'x'])
df.groupby('id').sum()
id x
a 3
b 12
Cependant, je voudrais avoir quelque chose comme:
id x
0 a 0
1 a 1
2 a 3
3 b 3
4 b 7
5 b 12
Remarque: comme identifié par @kekert, le modèle pandas a été déconseillé. Voir les solutions actuelles dans les réponses ci-dessous.
In [16]: df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)
Out[16]:
0 0.0
1 0.5
2 1.5
3 3.0
4 3.5
5 4.5
In [17]: df.groupby('id')['x'].cumsum()
Out[17]:
0 0
1 1
2 3
3 3
4 7
5 12
Pour les Googleurs qui tombent sur cette vieille question:
Concernant le commentaire de @ kekert sur la réponse de @ Garrett pour utiliser le nouveau
df.groupby('id')['x'].rolling(2).mean()
plutôt que le désormais obsolète
df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)
curieusement, il semble que la nouvelle approche .rolling (). mean () renvoie une série multi-indexée, indexée d'abord par la colonne group_by puis par l'index. Alors que l'ancienne approche renvoyait simplement une série indexée singulièrement par l'index df d'origine, ce qui est peut-être moins logique, mais rendait très pratique l'ajout de cette série en tant que nouvelle colonne dans la trame de données d'origine.
Je pense donc avoir trouvé une solution qui utilise la nouvelle méthode rolling () et fonctionne toujours de la même manière:
df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)
qui devrait vous donner la série
0 0.0
1 0.5
2 1.5
3 3.0
4 3.5
5 4.5
que vous pouvez ajouter en colonne:
df['x'] = df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)
Voici un autre moyen qui se généralise bien et utilise la méthode expand de pandas.
Il est très efficace et fonctionne également parfaitement pour calculs de fenêtres déroulantes avec des fenêtres fixes, comme pour les séries chronologiques.
# Import pandas library
import pandas as pd
# Prepare columns
x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']
# Create dataframe from columns above
df = pd.DataFrame({'id':id, 'x':x})
# Calculate rolling sum with infinite window size (i.e. all rows in group) using "expanding"
df['rolling_sum'] = df.groupby('id')['x'].transform(lambda x: x.expanding().sum())
# Output as desired by original poster
print(df)
id x rolling_sum
0 a 0 0
1 a 1 1
2 a 2 3
3 b 3 3
4 b 4 7
5 b 5 12
Je ne suis pas sûr de la mécanique, mais cela fonctionne. Remarque, la valeur renvoyée est juste un ndarray. Je pense que vous pouvez appliquer n'importe quelle fonction cumulative ou "glissante" de cette manière et cela devrait avoir le même résultat.
Je l'ai testé avec cumprod
, cummax
et cummin
et ils ont tous retourné un ndarray. Je pense que pandas est assez intelligent pour savoir que ces fonctions renvoient une série et donc la fonction est appliquée comme une transformation plutôt qu'une agrégation.
In [35]: df.groupby('id')['x'].cumsum()
Out[35]:
0 0
1 1
2 3
3 3
4 7
5 12
Edit: j'ai trouvé curieux que cette syntaxe retourne une série:
In [54]: df.groupby('id')['x'].transform('cumsum')
Out[54]:
0 0
1 1
2 3
3 3
4 7
5 12
Name: x