Wie erstelle ich eine neue Spalte aus der Ausgabe von pandas groupby (). Sum ()?

82

Es wird versucht, eine neue Spalte aus der groupbyBerechnung zu erstellen . Im folgenden Code erhalte ich die korrekt berechneten Werte für jedes Datum (siehe Gruppe unten), aber wenn ich versuche, eine neue Spalte ( df['Data4']) damit zu erstellen, erhalte ich NaN. Ich versuche also, eine neue Spalte im Datenrahmen mit der Summe Data3aller Daten zu erstellen und diese auf jede Datumszeile anzuwenden. Zum Beispiel ist der 08.05.2015 in 2 Zeilen (insgesamt 50 + 5 = 55) und in dieser neuen Spalte möchte ich 55 in beiden Zeilen haben.

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
zB ner
quelle

Antworten:

189

Wenn Sie dies verwenden möchten, transformwird eine Serie zurückgegeben, deren Index an der df ausgerichtet ist, sodass Sie sie dann als neue Spalte hinzufügen können:

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
EdChum
quelle
Was passiert, wenn wir eine zweite Gruppe wie hier haben: stackoverflow.com/a/40067099/281545
Mr_and_Mrs_D
@Mr_and_Mrs_D Sie müssten den Index zurücksetzen und in diesem Fall eine
Linkszusammenführung
10
Alternativ kann man verwenden df.groupby('Date')['Data3'].transform('sum')(was ich etwas leichter zu merken finde).
Cleb
39

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.groupbylieber an als Series.groupby. Dies führt zu einer einfacheren Syntax.

# 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 

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, transformwenn Sie stattdessen eine direkte Funktion von verwenden GroupByund 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 mapist ein bisschen schneller , wenn Sie sich leisten können , die direkt zu verwenden , GroupByFunktion (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
)
cs95
quelle
1
Das ist gut zu wissen! Würde es Ihnen etwas ausmachen, (zumindest in zukünftigen Perfplots) Versionsnummern aufzunehmen? Der Leistungsunterschied ist interessant, aber es handelt sich schließlich um Implementierungsdetails, die möglicherweise in Zukunft ausgebügelt werden. Vor allem, wenn Entwickler Ihre Beiträge zur Kenntnis nehmen.
jpp
@jpp yup das ist fair! Habe Versionen hinzugefügt. Dies wurde auf 0,23 getestet, aber ich glaube, der Unterschied wird gesehen, solange Sie eine Version über 0,20 haben.
CS95