Das ist natürlich einfach, aber als numpy Neuling stecke ich fest.
Ich habe eine CSV-Datei, die 3 Spalten enthält, den Status, die Büro-ID und den Vertrieb für dieses Büro.
Ich möchte den Prozentsatz des Umsatzes pro Büro in einem bestimmten Bundesstaat berechnen (die Summe aller Prozentsätze in jedem Bundesstaat beträgt 100%).
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)]})
df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
Dies gibt zurück:
sales
state office_id
AZ 2 839507
4 373917
6 347225
CA 1 798585
3 890850
5 454423
CO 1 819975
3 202969
5 614011
WA 2 163942
4 369858
6 959285
Ich kann anscheinend nicht herausfinden, wie man das state
Niveau von "erreicht", groupby
um das sales
für das Ganze state
zu summieren, um den Bruch zu berechnen.
df['sales'] / df.groupby('state')['sales'].transform('sum')
scheint die klarste Antwort zu sein.Antworten:
Die Antwort von Paul H ist richtig, dass Sie ein zweites
groupby
Objekt erstellen müssen, aber Sie können den Prozentsatz auf einfachere Weise berechnen - nurgroupby
diestate_office
und dividieren Sie diesales
Spalte durch ihre Summe. Kopieren Sie den Anfang von Paul Hs Antwort:Kehrt zurück:
quelle
x
handelt es sich um eine Tabelle,100 * x
die intuitiv keinen Sinn ergibt (insbesondere, wenn einige der Zellen Zeichenfolgen wieAZ
... enthalten).state_office
ist eine Serie mit einem Multi-Index - es ist also nur eine Spalte, deren Werte alle numerisch sind. Nachdem Sie die Gruppierung durchgeführt haben, ist jedex
eine Teilmenge dieser Spalte. Ist das sinnvoll?level=0
dasSie müssen ein zweites groupby-Objekt erstellen, das nach den Status gruppiert, und dann die folgende
div
Methode verwenden:Das
level='state'
kwarg indiv
weist Pandas an, die Datenrahmen basierend auf den Werten auf der Indexebene zu senden / zu verbindenstate
.quelle
div
doch mit zu benutzenlevel=["index1", "index2"]
aber es sagt mir dasJoin on level between two MultiIndex objects is ambiguous
.Aus Gründen der Übersichtlichkeit würde ich die SeriesGroupBy verwenden:
Für mehrere Gruppen müssen Sie transform verwenden (mit Radicals df ):
Dies scheint etwas performanter zu sein als die anderen Antworten (nur weniger als doppelt so schnell wie Radicals Antwort, für mich ~ 0,08 s).
quelle
Ich denke, das muss verglichen werden. Verwenden des ursprünglichen DataFrame von OP,
1. Andy Hayden
Wie in seiner Antwort kommentiert, nutzt Andy die Vektorisierung und die Indizierung von Pandas voll aus.
3,42 ms ± 16,7 µs pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
2. Paul H.
4,66 ms ± 24,4 µs pro Schleife
(Mittelwert ± Standardabweichung von 7 Läufen, jeweils 100 Schleifen)
3. Exp1orer
Dies ist die langsamste Antwort, da sie
x.sum()
für jedex
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,
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.
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!
quelle
(Diese Lösung ist von diesem Artikel https://pbpython.com/pandas_transform.html inspiriert. )
Ich finde die folgende Lösung am einfachsten (und wahrscheinlich am schnellsten)
transformation
:So verwenden
transformation
, ist die Lösung 1-Liner:Und wenn Sie drucken:
quelle
transform('max')
Ich weiß, dass dies eine alte Frage ist, aber die Antwort von exp1orer ist für Datensätze mit einer großen Anzahl eindeutiger Gruppen (wahrscheinlich aufgrund des Lambda) sehr langsam. Ich habe aus ihrer Antwort aufgebaut, um daraus eine Array-Berechnung zu machen, und jetzt ist es super schnell! Unten ist der Beispielcode:
Erstellen Sie den Testdatenrahmen mit 50.000 eindeutigen Gruppen
In Gruppen sieht es so aus:
Array-Methode zum Ermitteln des Prozentsatzes:
Diese Methode dauert ca. 0,15 Sekunden
Top-Antwortmethode (mit Lambda-Funktion):
Diese Methode benötigt ca. 21 Sekunden, um das gleiche Ergebnis zu erzielen.
Das Ergebnis:
quelle
Mir ist klar, dass es hier bereits gute Antworten gibt.
Ich möchte dennoch meinen eigenen Beitrag leisten, da ich der Meinung bin, dass es für eine elementare, einfache Frage wie diese eine kurze Lösung geben sollte, die auf einen Blick verständlich ist.
Es sollte auch so funktionieren, dass ich die Prozentsätze als neue Spalte hinzufügen kann, wobei der Rest des Datenrahmens unberührt bleibt. Last but not least sollte es auf offensichtliche Weise auf den Fall verallgemeinert werden, in dem es mehr als eine Gruppierungsebene gibt (z. B. Staat und Land statt nur Staat).
Das folgende Snippet erfüllt diese Kriterien:
Beachten Sie, dass Sie, wenn Sie noch Python 2 verwenden, das x im Nenner des Lambda-Terms durch float (x) ersetzen müssen.
quelle
* 100
, es zu einem Prozentsatz zu machen.groupby
Objekts, ist sehr präzise und liest sich sehr logisch von links nach rechts.Die eleganteste Methode zum Auffinden von Prozentsätzen in Spalten oder Indizes ist die Verwendung
pd.crosstab
.Beispieldaten
Der Ausgabedatenrahmen ist wie folgt
Geben Sie einfach den Index, die Spalten und die zu aggregierenden Werte an. Das Schlüsselwort normalize berechnet je nach Kontext% über Index oder Spalten hinweg.
quelle
Sie können
sum
das GanzeDataFrame
und durch diestate
Summe teilen :Kehrt zurück
Beachten Sie jedoch, dass dies nur funktioniert, weil alle Spalten außer
state
numerisch sind und die Summierung des gesamten DataFrame ermöglichen. Wenn beispielsweiseoffice_id
stattdessen ein Zeichen angezeigt wird, wird eine Fehlermeldung angezeigt:quelle
groupby
Spalte numerisch sind. Aber sonst ist es ziemlich elegant. Gibt es eine Möglichkeit, damit es mit anderenstr
Spalten funktioniert ?Ich denke, das würde den Trick in einer Zeile machen:
quelle
Die einfache Art und Weise, die ich verwendet habe, ist eine Zusammenführung nach den beiden Gruppen, die dann eine einfache Division durchführen.
quelle
Kehrt zurück:
quelle
Als jemand, der auch Pandas lernt, fand ich die anderen Antworten etwas implizit, da Pandas den größten Teil der Arbeit hinter den Kulissen verbirgt. Das heißt, wie die Operation funktioniert, indem Spalten- und Indexnamen automatisch abgeglichen werden. Dieser Code sollte einer schrittweisen Version der von @ exp1orer akzeptierten Antwort entsprechen
Mit dem
df
werde ich es beim Alias nennenstate_office_sales
:state_total_sales
wirdstate_office_sales
nach Gesamtsummen inindex level 0
(ganz links) gruppiert .Da die beiden Datenrahmen einen Indexnamen und einen Spaltennamen gemeinsam haben, finden Pandas die entsprechenden Speicherorte über gemeinsam genutzte Indizes wie:
Um dies noch besser zu veranschaulichen, ist hier eine Teilsumme mit einer
XX
, die kein Äquivalent hat. Pandas stimmen mit der Position basierend auf Index- und Spaltennamen überein, wobei es keine Überlappung gibt. Pandas ignorieren dies:Dies wird sehr deutlich, wenn keine gemeinsam genutzten Indizes oder Spalten vorhanden sind. Hier
missing_index_totals
ist gleich,state_total_sales
außer dass es keinen Indexnamen hat.quelle
Einzeilige Lösung:
Dies gibt eine Reihe von Pro-Office-Verhältnissen zurück - kann einzeln verwendet oder dem ursprünglichen Datenrahmen zugewiesen werden.
quelle