2017-08-03 3 views
2

Je travaille actuellement avec des données de panel en Python et j'essaie de calculer la moyenne mobile pour chaque observation de séries temporelles dans un groupe donné (ID). Compte tenu de la taille de mon ensemble de données (des milliers de groupes avec plusieurs périodes), les fonctions .groupby et .apply() prennent beaucoup trop de temps à calculer (a duré plus d'une heure et toujours rien - entier l'ensemble de données contient seulement environ 300k observations).Application de la fonction à Pandas Groupby

Je suis finalement vouloir itérer sur plusieurs colonnes, procédez comme suit:

  1. Calculer une moyenne mobile pour chaque pas de temps dans une colonne donnée, par groupe ID
  2. Créer une nouvelle colonne contenant la différence entre la valeur d'origine et la moyenne mobile [x_t - (x_t-1 + x_t)/2]
  3. Stocke la colonne dans un nouveau DataFrame, qui serait identique à l'ensemble de données d'origine, sauf qu'il a le résidu de # 2 au lieu de la valeur d'origine.
  4. Répéter et ajouter de nouveaux résidus à df_resid (comme on le voit ci-dessous)

    df_resid 
    date  id rev_resid exp_resid 
    2005-09-01 1   NaN   NaN 
    2005-12-01 1  -10000  -5500 
    2006-03-01 1  -352584 -262058.5 
    2006-06-01 1  240000 190049.5 
    2006-09-01 1 82648.75 37724.25 
    2005-09-01 2   NaN   NaN 
    2005-12-01 2  4206.5  24353 
    2006-03-01 2  -302574  -331951 
    2006-06-01 2  103179 117405.5 
    2006-09-01 2  -52650 -72296.5 
    

Voici petit échantillon des données originales.

df 
date  id  rev  exp 
2005-09-01 1 745168.0 545168.0  
2005-12-01 1 725168.0 534168.0  
2006-03-01 1 20000.0 10051.0 
2006-06-01 1 500000.0 390150.0 
2006-09-01 1 665297.5 465598.5 
2005-09-01 2 956884.0 736987.0 
2005-12-01 2 965297.0 785693.0 
2006-03-01 2 360149.0 121791.0 
2006-06-01 2 566507.0 356602.0 
2006-09-01 2 461207.0 212009.0 

Et le (très lent):

df['rev_resid'] = df.groupby('id')['rev'].apply(lambda x:x.rolling(center=False,window=2).mean()) 

J'espère qu'il ya une façon beaucoup plus efficace de faire informatiquement ce (surtout en ce qui concerne # 1), et pourrait être étendu à plusieurs colonnes.

Toute aide serait vraiment appréciée.

+0

espère que le lien peut aider https://stackoverflow.com/questions/13996302/python-rolling-functions-for-groupby-object – Wen

Répondre

2

Pour accélérer le calcul, si dataframe est déjà triée sur 'id' alors vous ne devez pas faire rolling dans un groupby (si ce ne sont pas triées ... faire). Puis puisque votre fenêtre est seulement la longueur 2 puis nous masquons le résultat en vérifiant où id == id.shift Cela fonctionne parce qu'il est trié.

d1 = df[['rev', 'exp']] 
df.join(
    d1.rolling(2).mean().rsub(d1).add_suffix('_resid')[df.id.eq(df.id.shift())] 
) 

     date id  rev  exp rev_resid exp_resid 
0 2005-09-01 1 745168.0 545168.0  NaN  NaN 
1 2005-12-01 1 725168.0 534168.0 -10000.00 -5500.00 
2 2006-03-01 1 20000.0 10051.0 -352584.00 -262058.50 
3 2006-06-01 1 500000.0 390150.0 240000.00 190049.50 
4 2006-09-01 1 665297.5 465598.5 82648.75 37724.25 
5 2005-09-01 2 956884.0 736987.0  NaN  NaN 
6 2005-12-01 2 965297.0 785693.0 4206.50 24353.00 
7 2006-03-01 2 360149.0 121791.0 -302574.00 -331951.00 
8 2006-06-01 2 566507.0 356602.0 103179.00 117405.50 
9 2006-09-01 2 461207.0 212009.0 -52650.00 -72296.50 
+1

solution de Nice sans 'groupby' devrait être rapide ~ – Wen

+0

Merci @Wen ! – piRSquared