Ich denke, das muss verglichen werden. Verwenden des ursprünglichen DataFrame von OP,
df = pd.DataFrame({
'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
'office_id': range(1, 7) * 2,
'sales': [np.random.randint(100000, 999999) for _ in range(12)]
})
Wie in seiner Antwort kommentiert, nutzt Andy die Vektorisierung und die Indizierung von Pandas voll aus.
c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()
3,42 ms ± 16,7 µs pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
state = df.groupby(['state']).agg({'sales': 'sum'})
state_office.div(state, level='state') * 100
4,66 ms ± 24,4 µs pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
Dies ist die langsamste Antwort, da sie x.sum()
für jede x
in Stufe 0 berechnet wird .
Für mich ist dies immer noch eine nützliche Antwort, wenn auch nicht in der aktuellen Form. Für eine schnelle EDA bei kleineren Datensätzen apply
können Sie die Methodenverkettung verwenden , um diese in eine einzelne Zeile zu schreiben. Wir müssen daher nicht mehr über den Namen einer Variablen entscheiden, was für Ihre wertvollste Ressource (Ihr Gehirn !!) tatsächlich sehr rechenintensiv ist .
Hier ist die Modifikation,
(
df.groupby(['state', 'office_id'])
.agg({'sales': 'sum'})
.groupby(level=0)
.apply(lambda x: 100 * x / float(x.sum()))
)
10,6 ms ± 81,5 µs pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
Bei einem kleinen Datensatz kümmert sich also niemand um 6 ms. Dies ist jedoch eine dreifache Beschleunigung, und bei einem größeren Datensatz mit Gruppen mit hoher Kardinalität wird dies einen massiven Unterschied bewirken.
Zusätzlich zum obigen Code erstellen wir einen DataFrame mit der Form (12.000.000, 3) mit 14412 Statuskategorien und 600 office_ids.
import string
import numpy as np
import pandas as pd
np.random.seed(0)
groups = [
''.join(i) for i in zip(
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
)
]
df = pd.DataFrame({'state': groups * 400,
'office_id': list(range(1, 601)) * 20000,
'sales': [np.random.randint(100000, 999999)
for _ in range(12)] * 1000000
})
Mit Andys,
2 s ± 10,4 ms pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 1 Schleife)
und exp1orer
19 s ± 77,1 ms pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 1 Schleife)
Jetzt wird x10 bei großen Datensätzen mit hoher Kardinalität schneller.
Achten Sie darauf, diese drei Antworten zu UV, wenn Sie diese UV!
df['sales'] / df.groupby('state')['sales'].transform('sum')
scheint die klarste Antwort zu sein.