Wie erstelle ich mit Groupby () eine neue Spalte. Sum ()?
Es gibt zwei Möglichkeiten - eine einfache und eine etwas interessantere.
Jedermanns Favorit: GroupBy.transform()
mit'sum'
Die Antwort von @Ed Chum kann ein wenig vereinfacht werden. Rufen Sie DataFrame.groupby
lieber an als Series.groupby
. Dies führt zu einer einfacheren Syntax.
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
Es ist ein bisschen schneller,
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)
Unkonventionell, aber eine Überlegung wert: GroupBy.sum()
+Series.map()
Ich bin auf eine interessante Eigenart in der API gestoßen. Nach allem, was ich erzähle, können Sie dies auf jeder Hauptversion über 0,20 reproduzieren (ich habe dies auf 0,23 und 0,24 getestet). Es scheint, als könnten Sie konsequent einige Millisekunden der Zeit sparen, die Sie benötigen, transform
wenn Sie stattdessen eine direkte Funktion von verwenden GroupBy
und diese senden mit 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
Vergleichen mit
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
Meine Tests zeigen , dass map
ist ein bisschen schneller , wenn Sie sich leisten können , die direkt zu verwenden , GroupBy
Funktion (wie mean
, min
, max
, first
, etc.). Es ist mehr oder weniger schneller für die meisten allgemeinen Situationen bis zu etwa 200.000 Datensätzen. Danach hängt die Leistung wirklich von den Daten ab.
(Links: v0.23, rechts: v0.24)
Schöne Alternative zu wissen, und besser, wenn Sie kleinere Frames mit einer geringeren Anzahl von Gruppen haben. . . aber ich würde empfehlentransform
als erste Wahl . Ich dachte, das wäre es trotzdem wert, geteilt zu werden.
Benchmarking-Code als Referenz:
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
)