Група панд за сукупною сумою


93

Я хотів би додати стовпець сукупної суми до мого кадру даних Pandas, щоб:

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

стає:

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

Я пробував різні комбінації df.groupbyі df.agg(lambda x: cumsum(x))безрезультатно.


Ви справді впевнені, що хочете агрегування за тижні? Це втрачає індекс, а також сукупна сума має менший сенс, якщо є кілька тижнів. Відповіді dmitry-andreev та @vjayky замість цього обчислює cumsum протягом послідовності днів для кожного імені. Подумайте, як це можна було б продовжити, якби також був стовпець дати, щоб записи можна було відсортувати перед групуванням та агрегуванням.
Еліас Хасле

Відповіді:


89

Це слід зробити, потрібно groupby()двічі:

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

Пояснення:

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

Кадр даних, отриманий з першої суми, індексується за 'name'допомогою 'day'. Ви можете побачити це, надрукувавши

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

Під час обчислення сукупної суми ви хочете це зробити за 'name', що відповідає першому індексу (рівень 0).

Нарешті, використовуйте reset_indexдля повторення імен.

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
Дякую за відповідь. У мене були декілька запитань: 1. Чи можете ви пояснити, що означає "рівень = [0]"? 2. Крім того, як ви можете бачити, раніше у вашому фреймі даних були номери рядків, і ці номери рядків зникають, коли ви робите сукупну суму. Чи є спосіб повернути їх назад?
user3694373

5
1), Номер індексу повинен йти, оскільки сукупність складається з декількох рядків, наприклад, друге число, 40, дорівнює 10 + 20 + 10, яке значення індексу воно має отримати? 1, 2 або 3? Отже, давайте продовжувати використовувати nameта dayяк multiIndex, які мають кращий сенс ( reset_index()отримати intіндекс, якщо потрібно). 2), level=[0]засіб groupbyмає діяти на 1-му рівні MultiIndex, а саме на колонці name.
CT Zhu

Дякую КТ. Я зрозумів це пізніше і спробував reset_index () вирішити мою проблему. Дякуємо за детальне пояснення!
user3694373

4
Існує незначна помилка: перші groupby()за замовчуванням сортують ключі, тому, якщо ви додасте рядок Джека-Четверга внизу набору даних, ви отримаєте несподівані результати. А оскільки я groupby()можу працювати з іменами рівнів, то я вважаю df.groupby(['name', 'day'], sort=False).sum().groupby(by='name').cumsum().reset_index()менш загадковим.
Ніколай

Як перейменувати стовпець?
Джонатан Лам,

47

Це працює в пандах 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

Показати, як додати його назад у df, дуже корисно. Я спробував використати перетворення, але це не дуже добре зіграло з cumsum ().
zerovector

2
Зверніть увагу, що ця відповідь (здається еквівалентною більш простому рішенню @vjayky ) не узагальнює до nameі dayдо обчислення сукупної суми за name(примітка: у результаті є 2 рядки для Джека + вівторок). Це робить його простішим, ніж відповідь КТ Чжу .
Ніколай

39

Модифікація відповіді @ Dmitry. Це простіше і працює в пандах 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

2
Це здається найпростішим рішенням, якщо вам не потрібне двоступеневе агрегування , як це вимагається у питанні.
Ніколай

Єдине, що мені особливо не подобається, це те, що він перетворив мій тип int dt на float.
Кріс Фарр

Це має бути прийнятою відповіддю для закінчення у груповій частині. @ChrisFarr Здається, це не перетворюється на плаваючий для мене станом на панди 1.0.3.
Луї Ян

8

ви повинні використовувати

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

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

Інший спосіб зробити це

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

введіть тут опис зображення


3
Це обчислює загальний загальний підсумок, замість окремої суми для кожної групи окремо. Тож Джилл-Понеділок отримує значення 130 ( 90як сума всіх значень Джека + 40, значення Джил-Понеділок).
Ніколай

@Nickolay щойно додав ще одну відповідь, дайте мені знати, якщо це спрацює
sushmit

Я не впевнений, чи обчислює загальний загальний підсумок відповідно до мого прикладу рядок 3 отримує значення 4
sushmit

Чому я використовую лямбда x: x.cumsum () тут, а не pandas.series.cumsum ()?
Jinhua Wang

7

Замість df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum() (див. Вище) ви також можете зробити adf.set_index(['name', 'day']).groupby(level=0, as_index=False).cumsum()

  • df.groupby(by=['name','day']).sum() насправді просто переміщує обидва стовпці до MultiIndex
  • as_index=False означає, що вам не потрібно буде викликати reset_index згодом

Дякуємо, що розмістили це, це допомогло мені зрозуміти, що тут відбувається! Зверніть увагу, що groupby().sum()це не просто переміщення обох стовпців до MultiIndex - це також підсумовує два значення для Jack + Tuesday. І, as_index=Falseздається, не має жодного ефекту в цьому випадку, оскільки індекс був уже встановлений до groupby. І оскільки groupby().cumsum()нуклеотиди ім'я / день обробляються зі стовпців кадру даних, вам доведеться або додати отриманий числовий стовпець до вихідного кадру даних (наприклад, vjayky та Дмитро), або перемістити ім'я / день до індексу, а потім reset_index.
Ніколай

0

data.csv:

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

Код:

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)

Вихід:

   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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.