Як створити новий стовпець з виводу pandas groupby (). Sum ()?


84

Спроба створити новий стовпець з groupbyрозрахунку. У наведеному нижче коді я отримую правильні обчислені значення для кожної дати (див. Групу нижче), але коли я намагаюся створити новий стовпець ( df['Data4']) з ним, я отримую NaN. Тому я намагаюся створити новий стовпець у фреймі даних із сумою Data3всіх дат і застосувати це до кожного рядка дати. Наприклад, 08.05.2015 є у 2 рядки (загалом 50 + 5 = 55), і в цьому новому стовпці я хотів би мати 55 в обох рядках.

import pandas as pd
import numpy as np
from pandas import DataFrame

df = pd.DataFrame({
    'Date' : ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 
    'Sym'  : ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 
    'Data2': [11, 8, 10, 15, 110, 60, 100, 40],
    'Data3': [5, 8, 6, 1, 50, 100, 60, 120]
})

group = df['Data3'].groupby(df['Date']).sum()

df['Data4'] = group

Відповіді:


192

Якщо ви хочете використовувати transformце, ви повернете серію з індексом, вирівняним до df, щоб потім можна було додати її як новий стовпець:

In [74]:

df = pd.DataFrame({'Date': ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 'Sym': ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 'Data2': [11, 8, 10, 15, 110, 60, 100, 40],'Data3': [5, 8, 6, 1, 50, 100, 60, 120]})
​
df['Data4'] = df['Data3'].groupby(df['Date']).transform('sum')
df
Out[74]:
   Data2  Data3        Date   Sym  Data4
0     11      5  2015-05-08  aapl     55
1      8      8  2015-05-07  aapl    108
2     10      6  2015-05-06  aapl     66
3     15      1  2015-05-05  aapl    121
4    110     50  2015-05-08  aaww     55
5     60    100  2015-05-07  aaww    108
6    100     60  2015-05-06  aaww     66
7     40    120  2015-05-05  aaww    121

Що станеться , якщо у нас є другий GroupBy , як тут: stackoverflow.com/a/40067099/281545
Mr_and_Mrs_D

@Mr_and_Mrs_D вам довелося б скинути індекс і виконати ліве злиття загальних стовпців у такому випадку, щоб додати стовпець назад
EdChum,

10
Як варіант, можна використовувати df.groupby('Date')['Data3'].transform('sum')(що мені трохи легше запам’ятати).
Кліб,

43

Як створити новий стовпець за допомогою Groupby (). Sum ()?

Є два шляхи - один прямий, а інший трохи цікавіший.


Улюблений усіма: GroupBy.transform()с'sum'

Відповідь @ Ed Chum можна дещо спростити. Зателефонуйте, DataFrame.groupbyа не Series.groupby. Це призводить до спрощення синтаксису.

# The setup.
df[['Date', 'Data3']]

         Date  Data3
0  2015-05-08      5
1  2015-05-07      8
2  2015-05-06      6
3  2015-05-05      1
4  2015-05-08     50
5  2015-05-07    100
6  2015-05-06     60
7  2015-05-05    120

df.groupby('Date')['Data3'].transform('sum')

0     55
1    108
2     66
3    121
4     55
5    108
6     66
7    121
Name: Data3, dtype: int64 

Це трохи швидше,

df2 = pd.concat([df] * 12345)

%timeit df2['Data3'].groupby(df['Date']).transform('sum')
%timeit df2.groupby('Date')['Data3'].transform('sum')

10.4 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8.58 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Нетрадиційний, але вартий уваги: GroupBy.sum()+Series.map()

Я натрапив на цікаву ідіосинкразію в API. З того, що я розповідаю, ви можете відтворити це на будь-якій основній версії понад 0,20 (я тестував це на 0,23 та 0,24). Здається, ви постійно можете голити кілька мілісекунд часу, зайнятого, transformякщо замість цього використовуєте пряму функцію GroupByта передаєте її за допомогою map:

df.Date.map(df.groupby('Date')['Data3'].sum())

0     55
1    108
2     66
3    121
4     55
5    108
6     66
7    121
Name: Date, dtype: int64

Порівняйте з

df.groupby('Date')['Data3'].transform('sum')

0     55
1    108
2     66
3    121
4     55
5    108
6     66
7    121
Name: Data3, dtype: int64

Мої тести показують , що mapтрохи швидше , якщо ви можете дозволити собі використовувати пряму GroupByфункцію (наприклад mean, min, max, firstі т.д.). Це більш-менш швидше для більшості загальних ситуацій приблизно до ~ 200 тис. Записів. Після цього продуктивність дійсно залежить від даних.

(Ліворуч: v0.23, праворуч: v0.24)

Приємну альтернативу знати, і краще, якщо у вас менші кадри з меншою кількістю груп. . . але я б рекомендував transformяк перший вибір. Думав, цим все-таки варто поділитися.

Бенчмаркінг-код, для довідки:

import perfplot

perfplot.show(
    setup=lambda n: pd.DataFrame({'A': np.random.choice(n//10, n), 'B': np.ones(n)}),
    kernels=[
        lambda df: df.groupby('A')['B'].transform('sum'),
        lambda df:  df.A.map(df.groupby('A')['B'].sum()),
    ],
    labels=['GroupBy.transform', 'GroupBy.sum + map'],
    n_range=[2**k for k in range(5, 20)],
    xlabel='N',
    logy=True,
    logx=True
)

1
Це добре знати! Ви не могли б включити (принаймні в майбутні парфюмери) номери версій? Різниця в продуктивності цікава, але це, врешті-решт, деталі реалізації, які можуть бути виправлені в майбутньому. Особливо, якщо розробники беруть до уваги ваші дописи.
jpp

@jpp yup це справедливо! Додали версії. Це було перевірено на 0,23, але я вважаю, що різниця спостерігається до тих пір, поки у вас є версія більше 0,20.
cs95
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.