Попытка создать новый столбец из 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
df.groupby('Date')['Data3'].transform('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 )
источник