Kümülatif toplama göre Pandalar


93

Pandalar veri çerçeveme kümülatif toplam sütunu eklemek istiyorum, böylece:

name | day       | no
-----|-----------|----
Jack | Monday    | 10
Jack | Tuesday   | 20
Jack | Tuesday   | 10
Jack | Wednesday | 50
Jill | Monday    | 40
Jill | Wednesday | 110

şu hale gelir:

Jack | Monday     | 10  | 10
Jack | Tuesday    | 30  | 40
Jack | Wednesday  | 50  | 90
Jill | Monday     | 40  | 40
Jill | Wednesday  | 110 | 150

Çeşitli kombinasyonları denedim df.groupbyve df.agg(lambda x: cumsum(x))boşuna.


Hafta içi günlerde birleştirme istediğinizden gerçekten emin misiniz? Bu, endeksi kaybeder ve ayrıca kümülatif toplam, birden fazla hafta varsa daha az anlamlıdır. Dmitry-andreev ve @vjayky tarafından verilen cevaplar, bunun yerine her isim için gün dizisi üzerinden cumsum'u hesaplar. Bir tarih sütunu olsaydı, girişlerin gruplama ve toplamadan önce sıralanabileceği şekilde bunun nasıl genişletilebileceğini düşünün.
Elias Hasle

Yanıtlar:


89

Bunu yapmalı, groupby()iki kez gerek :

df.groupby(['name', 'day']).sum() \
  .groupby(level=0).cumsum().reset_index()

Açıklama:

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

İlk toplamdan elde edilen veri çerçevesi, tarafından 'name've tarafından indekslenir 'day'. Yazdırarak görebilirsiniz

df.groupby(['name', 'day']).sum().index 

Kümülatif toplamı hesaplarken, bunu 'name'ilk endekse (seviye 0) karşılık gelecek şekilde yapmak istersiniz .

Son olarak, reset_indexisimleri tekrar ettirmek için kullanın.

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

3
Cevap için teşekkürler. Yine de bazı sorularım vardı: 1. 'level = [0]' ne anlama geliyor, lütfen açıklar mısınız? 2. Ayrıca, gördüğünüz gibi, veri çerçevenizde daha önce satır numaralarınız vardı ve bu satır numaraları, kümülatif toplamı yaptığınızda kaybolur. Onları geri almanın bir yolu var mı?
user3694373

5
1), Toplamlar birden çok satırdan olduğu için dizin numarası gitmeli, örneğin 2. sayı olan 40, 10 + 20 + 10, hangi dizin değerini almalı? 1, 2 veya 3? Öyleyse, kullanalım nameve daykullanalım multiIndex, hangisi daha mantıklı ( istenirse indeks reset_index()almak için int). 2) level=[0]araç groupby, 1. seviye MultiIndex, yani kolon tarafından çalıştırılmaktır name.
CT Zhu

Teşekkürler CT. Bunu daha sonra anladım ve sorunumu çözmek için reset_index () denedim. Detaylı açıklama için teşekkürler!
user3694373

4
Küçük bir hata var: İlk groupby()varsayılan anahtarları sıralamaktır, bu nedenle giriş veri kümesinin altına bir Jack-Perşembe satırı eklerseniz beklenmedik sonuçlar alırsınız. Ve groupby()seviye isimleriyle çalışabildiğim için df.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()daha az şifreli buluyorum .
Nickolay

Sütunu nasıl yeniden adlandırırsınız?
Jonathan Lam

47

Bu, Pandalar 0.16.2'de çalışır

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

Df'ye nasıl geri ekleneceğini göstermek gerçekten yararlıdır. Bir dönüşüm kullanmayı denedim, ancak bu cumsum () ile iyi oynamadı.
zerovector

2
Bu cevabın ( @vjayky'nin daha basit çözümüne eşdeğer görünüyor ) kümülatif toplamı hesaplamadan önce nameve dayönce toplanmadığını nameunutmayın (not: sonuçta Jack + Tuesday için 2 satır vardır). CT Zhu'nun cevabından daha basit yapan şey budur .
Nickolay

39

@ Dmitry'nin cevabında değişiklik. Bu daha basittir ve Pandalar 0.19.0'da çalışır:

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

2
Soruda talep edildiği gibi , iki aşamalı toplamaya ihtiyacınız yoksa bu en basit çözüm gibi görünüyor .
Nickolay

Özellikle sevmediğim tek kısım, int dtype'ımı bir float'a dönüştürmesi.
Chris Farr

Bu, grup bölümündeki cumsum için kabul edilen cevap olmalıdır. @ChrisFarr Pandalar 1.0.3'ten itibaren benim için artık float'a dönüşmeyecek gibi görünüyor.
Louis Yang

8

kullanmalısın

df['cum_no'] = df.no.cumsum()

http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.cumsum.html

Bunu yapmanın başka bir yolu

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

görüntü açıklamasını buraya girin


3
Bu, her grup için ayrı bir toplam yerine genel bir değişen toplamı hesaplar. Yani Jill-Monday'e 130 değeri atanır 90(tüm Jack'in değerlerinin toplamı olarak, + 40, Jill-Monday değeri).
Nickolay

@Nickolay az önce başka bir cevap ekledi, işe
yarayıp yaramadığını


Neden burada pandas.series.cumsum () yerine lambda x: x.cumsum () kullanıyorum?
Jinhua Wang

7

df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum() (Yukarıya bakın) yerine bir dedf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()

  • df.groupby(by=['name','day']).sum() aslında her iki sütunu da bir MultiIndex'e taşımak
  • as_index=False daha sonra reset_index'i aramanıza gerek olmadığı anlamına gelir

Bunu gönderdiğiniz için teşekkürler, burada neler olduğunu anlamama yardımcı oldu! Not groupby().sum()değildir sadece MultiIndex hem sütunları taşıma - o da Jack + Salı iki değer özetliyor. Ve as_index=Falsebu durumda herhangi bir etkiye sahip görünmüyor, çünkü dizin zaten groupby. Ve groupby().cumsum()adı / günü veri çerçevesinin sütunlarından aldığından, sonuçta elde edilen sayısal sütunu orijinal veri çerçevesine eklemeniz (vjayky ve Dmitry'nin önerdiği gibi) ya da adı / günü dizine taşımanız ve daha sonra reset_index'i yapmanız gerekir.
Nickolay

0

data.csv:

name,day,no
Jack,Monday,10
Jack,Tuesday,20
Jack,Tuesday,10
Jack,Wednesday,50
Jill,Monday,40
Jill,Wednesday,110

Kod:

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)

Çıktı:

   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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.