Как мне создать новый столбец из вывода pandas groupby(). Sum()?
Попытка создать новый столбец из groupby
расчета. В приведенном ниже коде я получаю правильные рассчитанные значения для каждой даты (см. Группу ниже), но когда я пытаюсь создать новый столбец (df['Data4']
), я получаю NaN. Поэтому я пытаюсь создать новый столбец в кадре данных с суммой данных Data3
для всех дат и применить ее к каждой строке даты. Например, 2015-05-08 состоит из 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
Ответы
Ответ 1
Вы хотите использовать 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
Ответ 2
Как создать новый столбец с помощью Groupby(). Sum()?
Есть два способа - один простой, а другой чуть более интересный.
Любимый всем: GroupBy.transform()
с 'sum'
@Ред Чум ответ может быть упрощен, немного. Вызовите 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). Похоже, что вы постоянно можете GroupBy
время, затрачиваемое на 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 тысяч записей. После этого производительность действительно зависит от данных.
![w66EQm.png]()
![4d2pVm.png]()
(Слева: 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
)