Как мне создать новый столбец с помощью 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
)