Próbuję utworzyć nową kolumnę z groupby
obliczeń. W poniższym kodzie otrzymuję poprawne obliczone wartości dla każdej daty (patrz grupa poniżej), ale kiedy próbuję utworzyć nową kolumnę ( df['Data4']
) za jej pomocą, otrzymuję NaN. Więc próbuję utworzyć nową kolumnę w ramce danych z sumą Data3
wszystkich dat i zastosować ją do każdego wiersza dat. Na przykład 2015-05-08 znajduje się w 2 wierszach (łącznie 50 + 5 = 55) iw tej nowej kolumnie chciałbym mieć 55 w obu wierszach.
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
python
pandas
group-by
pandas-groupby
fe ner
źródło
źródło
df.groupby('Date')['Data3'].transform('sum')
(co wydaje mi się nieco łatwiejsze do zapamiętania).Są dwa sposoby - jeden prosty, a drugi nieco bardziej interesujący.
Ulubiony przez wszystkich:
GroupBy.transform()
z'sum'
Odpowiedź @Ed Chum może być nieco uproszczona. Zadzwoń
DataFrame.groupby
zamiastSeries.groupby
. Powoduje to prostszą składnię.# 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
To odrobinę szybciej
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)
Niekonwencjonalne, ale warte uwagi:
GroupBy.sum()
+Series.map()
Natknąłem się na interesującą osobliwość w API. Z tego, co mówię, możesz to odtworzyć na dowolnej większej wersji powyżej 0.20 (testowałem to na 0.23 i 0.24). Wygląda na to, że konsekwentnie możesz skrócić o kilka milisekund czasu, który zajmuje,
transform
jeśli zamiast tego użyjesz bezpośredniej funkcjiGroupBy
i nadasz ją za pomocą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
Porównać z
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
Moje badania pokazują, że
map
jest to nieco szybciej, jeśli można sobie pozwolić, aby skorzystać z bezpośredniejGroupBy
funkcji (takich jakmean
,min
,max
,first
, etc). W większości ogólnych sytuacji jest mniej więcej szybszy do około 200 tysięcy rekordów. Po tym wydajność naprawdę zależy od danych.(Po lewej: v0.23, po prawej: v0.24)
Dobra alternatywa, którą warto znać, i lepiej, jeśli masz mniejsze ramki z mniejszą liczbą grup. . . ale polecam
transform
jako pierwszy wybór. I tak pomyślałem, że warto się tym podzielić.Kod porównawczy, w celach informacyjnych:
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 )
źródło