2017-10-17 4 views
2

J'ai une trame de données comme:Réinitialiser la base de somme cumulative sur l'état Pandas

customer spend hurdle 
A   20 50  
A   31 50  
A   20 50  
B   50 100  
B   51 100  
B   30 100  

Je veux calculer colonne supplémentaire pour cumulative qui base de réinitialisation sur le même client lorsque la somme cumulée supérieure ou égale à l'obstacle comme suit:

customer spend hurdle Cumulative 
A   20 50  20 
A   31 50  51 
A   20 50  20 
B   50 100  50 
B   51 100 101 
B   30 100  30 

je l'cumsum et groupby en pandas géants pour mais je ne sais pas comment réinitialiser la base de l'état.

Après sont le code que je suis actuellement en utilisant:

df1['cum_sum'] = df1.groupby(['customer'])['spend'].apply(lambda x: x.cumsum()) 

que je sais qu'il est juste une somme cumulative normale. J'apprécie beaucoup pour votre aide.

Répondre

1

Une façon serait le code ci-dessous. Mais c'est un one-liner vraiment inefficace et inélégant.

df1.groupby('customer').apply(lambda x: (x['spend'].cumsum() *(x['spend'].cumsum() > x['hurdle']).astype(int).shift(-1)).fillna(x['spend'])) 
+0

J'ai ajouté une version améliorée sur la vôtre. – Zero

1

Il pourrait y avoir un moyen plus rapide et efficace. Voici une façon inefficace de le faire.

In [3270]: def custcum(x): 
     ...:  total = 0 
     ...:  for i, v in x.iterrows(): 
     ...:   total += v.spend 
     ...:   x.loc[i, 'cum'] = total 
     ...:   if total >= v.hurdle: 
     ...:   total = 0 
     ...:  return x 
     ...: 

In [3271]: df.groupby('customer').apply(custcum) 
Out[3271]: 
    customer spend hurdle cum 
0  A  20  50 20.0 
1  A  31  50 51.0 
2  A  20  50 20.0 
3  B  50  100 50.0 
4  B  51  100 101.0 
5  B  30  100 30.0 

Vous pouvez envisager d'utiliser cython ou numba pour accélérer le custcum


[Mise à jour]

version améliorée de Ido s réponse.

In [3276]: s = df.groupby('customer').spend.cumsum() 

In [3277]: np.where(s > df.hurdle.shift(-1), s, df.spend) 
Out[3277]: array([ 20, 51, 20, 50, 101, 30], dtype=int64)