Як створити новий стовпець за допомогою Groupby (). Sum ()?
Є два шляхи - один прямий, а інший трохи цікавіший.
Улюблений усіма: GroupBy.transform()
с'sum'
Відповідь @ Ed Chum можна дещо спростити. Зателефонуйте, DataFrame.groupby
а не Series.groupby
. Це призводить до спрощення синтаксису.
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
)