Konvertieren einer Pandas GroupBy-Ausgabe von Series in DataFrame

495

Ich beginne mit solchen Eingabedaten

df1 = pandas.DataFrame( { 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"] } )

Was beim Drucken so aussieht:

   City     Name
0   Seattle    Alice
1   Seattle      Bob
2  Portland  Mallory
3   Seattle  Mallory
4   Seattle      Bob
5  Portland  Mallory

Die Gruppierung ist einfach genug:

g1 = df1.groupby( [ "Name", "City"] ).count()

und Drucken ergibt ein GroupByObjekt:

                  City  Name
Name    City
Alice   Seattle      1     1
Bob     Seattle      2     2
Mallory Portland     2     2
        Seattle      1     1

Was ich aber irgendwann möchte, ist ein anderes DataFrame-Objekt, das alle Zeilen im GroupBy-Objekt enthält. Mit anderen Worten, ich möchte das folgende Ergebnis erhalten:

                  City  Name
Name    City
Alice   Seattle      1     1
Bob     Seattle      2     2
Mallory Portland     2     2
Mallory Seattle      1     1

Ich kann in der Pandas-Dokumentation nicht genau sehen, wie dies erreicht werden kann. Hinweise wären willkommen.

saveenr
quelle
1
Neben der Frage: Welche Pandas-Version verwenden Sie? Wenn ich die ersten 2 Befehle ausführe, bekomme ich g1 alsEmpty DataFrame Columns: [] Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]
Timofey
1
Der Titel der Frage ist in Bezug auf die akzeptierte Antwort irreführend
Matanster
@matanster darf ich fragen, was du hierher gekommen bist, um die Antwort zu wissen? Wir können darüber nachdenken, eine genauere Antwort zu schreiben und die Aufmerksamkeit der Benutzer mit einem Kommentar unter der Frage zu lenken.
CS95
@coldspeed Dies ist nur ein typisches Problem bei SO. Fragetitel können erheblich vom Inhalt der Frage und der Antworten abweichen. Wenn Meta nicht so feindselig wäre, wäre dies wahrscheinlich ein nützlicher Aspekt, um es dort anzusprechen.
Matanster
@matanster Ich stimme zu, aber ich war nur neugierig zu wissen, wonach Sie tatsächlich gesucht haben, so dass es Sie hierher führte.
CS95

Antworten:

530

g1Hier ist ein DataFrame. Es hat jedoch einen hierarchischen Index:

In [19]: type(g1)
Out[19]: pandas.core.frame.DataFrame

In [20]: g1.index
Out[20]: 
MultiIndex([('Alice', 'Seattle'), ('Bob', 'Seattle'), ('Mallory', 'Portland'),
       ('Mallory', 'Seattle')], dtype=object)

Vielleicht willst du so etwas?

In [21]: g1.add_suffix('_Count').reset_index()
Out[21]: 
      Name      City  City_Count  Name_Count
0    Alice   Seattle           1           1
1      Bob   Seattle           2           2
2  Mallory  Portland           2           2
3  Mallory   Seattle           1           1

Oder so etwas wie:

In [36]: DataFrame({'count' : df1.groupby( [ "Name", "City"] ).size()}).reset_index()
Out[36]: 
      Name      City  count
0    Alice   Seattle      1
1      Bob   Seattle      2
2  Mallory  Portland      2
3  Mallory   Seattle      1
Wes McKinney
quelle
27
reset.index()macht den Job, toll!
Gented
54
Sie hätten verwenden können:df1.groupby( [ "Name", "City"] ).size().to_frame(name = 'count').reset_index()
Nehal J Wani
3
Das zweite Beispiel .reset_index()scheint mir der beste Weg zu sein, um die Ausgabe zu verbinden, die Sie erhalten df.groupby('some_column').apply(your_custom_func). Das war für mich nicht intuitiv.
Alexander
5
Gilt das auch für Python 3? Ich finde eine Groupby-Funktion, die das pandas.core.groupby.DataFrameGroupByObjekt zurückgibt , nicht pandas.core.frame.DataFrame.
Adrian Keister
3
Diese Antwort scheint für die neuesten Python und Pandas
Matanster
127

Ich möchte die Antwort von Wes leicht ändern, da Version 0.16.2 dies erfordert as_index=False. Wenn Sie es nicht einstellen, erhalten Sie einen leeren Datenrahmen.

Quelle :

Aggregationsfunktionen geben die Gruppen, über die Sie aggregieren, nicht zurück, wenn sie als Spalten bezeichnet werden as_index=True. Die gruppierten Spalten sind die Indizes des zurückgegebenen Objekts.

Beim Übergeben as_index=Falsewerden die Gruppen zurückgegeben, über die Sie aggregieren, wenn sie als Spalten bezeichnet werden.

Aggregieren von Funktionen sind diejenigen , die die Dimension der zurückgegebenen Objekte zu reduzieren, zum Beispiel: mean, sum, size, count, std, var, sem, describe, first, last, nth, min, max. Dies ist, was passiert, wenn Sie zum Beispiel tun DataFrame.sum()und a zurückbekommen Series.

nth kann als Reduzierer oder Filter wirken, siehe hier .

import pandas as pd

df1 = pd.DataFrame({"Name":["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"],
                    "City":["Seattle","Seattle","Portland","Seattle","Seattle","Portland"]})
print df1
#
#       City     Name
#0   Seattle    Alice
#1   Seattle      Bob
#2  Portland  Mallory
#3   Seattle  Mallory
#4   Seattle      Bob
#5  Portland  Mallory
#
g1 = df1.groupby(["Name", "City"], as_index=False).count()
print g1
#
#                  City  Name
#Name    City
#Alice   Seattle      1     1
#Bob     Seattle      2     2
#Mallory Portland     2     2
#        Seattle      1     1
#

BEARBEITEN:

In der Version 0.17.1und höher können Sie subsetin countund reset_indexmit Parameter namein verwenden size:

print df1.groupby(["Name", "City"], as_index=False ).count()
#IndexError: list index out of range

print df1.groupby(["Name", "City"]).count()
#Empty DataFrame
#Columns: []
#Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]

print df1.groupby(["Name", "City"])[['Name','City']].count()
#                  Name  City
#Name    City                
#Alice   Seattle      1     1
#Bob     Seattle      2     2
#Mallory Portland     2     2
#        Seattle      1     1

print df1.groupby(["Name", "City"]).size().reset_index(name='count')
#      Name      City  count
#0    Alice   Seattle      1
#1      Bob   Seattle      2
#2  Mallory  Portland      2
#3  Mallory   Seattle      1

Der Unterschied zwischen countund sizebesteht darin, dass sizeNaN-Werte gezählt werden, während countdies nicht der Fall ist.

jezrael
quelle
8
Ich denke, dies ist der einfachste Weg - ein Einzeiler, der die nette Tatsache nutzt, dass Sie die Serienspalte mit reset_index benennen können:df1.groupby( [ "Name", "City"]).size().reset_index(name="count")
Ben
1
Gibt es einen Grund, warum as_index=False' stopped working in latest versions? I also tried to run df1.groupby (["Name", "Stadt"], as_index = False) .size () `aber das Ergebnis nicht beeinflusst (wahrscheinlich, weil das Ergebnis der Gruppierung Seriesnicht istDataFrame
Roman Pekar
1
Ich bin nicht sicher, aber es scheint, dass es nur 2 Spalten gibt und groupbydurch diese Spalten. Aber ich bin mir nicht sicher, weil ich kein Pandas-Entwickler bin.
Jezrael
20

Dies sollte einfach die Aufgabe erfüllen:

import pandas as pd

grouped_df = df1.groupby( [ "Name", "City"] )

pd.DataFrame(grouped_df.size().reset_index(name = "Group_Count"))

Hier grouped_df.size()zieht die einzigartige groupby Zählen und reset_index()Verfahren setzt den Namen der Spalte , die Sie es haben wollen. Schließlich wird die Pandas- Dataframe()Funktion aufgerufen, um ein DataFrame-Objekt zu erstellen.

Surya
quelle
2
Schauen Sie sich die .to_frame () -Methode an: grouped_df.size (). To_frame ('Group_Count')
Sealander
12

Der Schlüssel ist die Verwendung der Methode reset_index () .

Verwenden:

import pandas

df1 = pandas.DataFrame( { 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"] } )

g1 = df1.groupby( [ "Name", "City"] ).count().reset_index()

Jetzt haben Sie Ihren neuen Datenrahmen in g1 :

Ergebnisdatenrahmen

Ferd
quelle
9

Vielleicht verstehe ich die Frage falsch, aber wenn Sie die Gruppe zurück in einen Datenrahmen konvertieren möchten, können Sie .to_frame () verwenden. Ich wollte den Index zurücksetzen, als ich das tat, also habe ich auch diesen Teil aufgenommen.

Beispielcode ohne Bezug zur Frage

df = df['TIME'].groupby(df['Name']).min()
df = df.to_frame()
df = df.reset_index(level=['Name',"TIME"])
brandog
quelle
6

Ich fand das funktionierte für mich.

import numpy as np
import pandas as pd

df1 = pd.DataFrame({ 
    "Name" : ["Alice", "Bob", "Mallory", "Mallory", "Bob" , "Mallory"] , 
    "City" : ["Seattle", "Seattle", "Portland", "Seattle", "Seattle", "Portland"]})

df1['City_count'] = 1
df1['Name_count'] = 1

df1.groupby(['Name', 'City'], as_index=False).count()
thefebruaryman
quelle
6

Die folgende Lösung kann einfacher sein:

df1.reset_index().groupby( [ "Name", "City"],as_index=False ).count()
Xiao QianYu
quelle
4

Ich habe mit mengenweisen Daten aggregiert und im Datenrahmen gespeichert

almo_grp_data = pd.DataFrame({'Qty_cnt' :
almo_slt_models_data.groupby( ['orderDate','Item','State Abv']
          )['Qty'].sum()}).reset_index()
Manivannan Murugavel
quelle
3

Diese Lösungen haben bei mir nur teilweise funktioniert, da ich mehrere Aggregationen durchgeführt habe. Hier ist eine Beispielausgabe meiner Gruppe, nach der ich in einen Datenrahmen konvertieren wollte:

Groupby-Ausgabe

Da ich mehr als die von reset_index () bereitgestellte Anzahl wollte, habe ich eine manuelle Methode zum Konvertieren des obigen Bildes in einen Datenrahmen geschrieben. Ich verstehe, dass dies nicht die pythonischste / pandasischste Art ist, dies zu tun, da es ziemlich ausführlich und explizit ist, aber es war alles, was ich brauchte. Verwenden Sie grundsätzlich die oben erläuterte Methode reset_index (), um einen "Gerüst" -Datenrahmen zu starten, durchlaufen Sie dann die Gruppenpaarungen im gruppierten Datenrahmen, rufen Sie die Indizes ab, führen Sie Ihre Berechnungen für den nicht gruppierten Datenrahmen durch und legen Sie den Wert in Ihrem neuen aggregierten Datenrahmen fest .

df_grouped = df[['Salary Basis', 'Job Title', 'Hourly Rate', 'Male Count', 'Female Count']]
df_grouped = df_grouped.groupby(['Salary Basis', 'Job Title'], as_index=False)

# Grouped gives us the indices we want for each grouping
# We cannot convert a groupedby object back to a dataframe, so we need to do it manually
# Create a new dataframe to work against
df_aggregated = df_grouped.size().to_frame('Total Count').reset_index()
df_aggregated['Male Count'] = 0
df_aggregated['Female Count'] = 0
df_aggregated['Job Rate'] = 0

def manualAggregations(indices_array):
    temp_df = df.iloc[indices_array]
    return {
        'Male Count': temp_df['Male Count'].sum(),
        'Female Count': temp_df['Female Count'].sum(),
        'Job Rate': temp_df['Hourly Rate'].max()
    }

for name, group in df_grouped:
    ix = df_grouped.indices[name]
    calcDict = manualAggregations(ix)

    for key in calcDict:
        #Salary Basis, Job Title
        columns = list(name)
        df_aggregated.loc[(df_aggregated['Salary Basis'] == columns[0]) & 
                          (df_aggregated['Job Title'] == columns[1]), key] = calcDict[key]

Wenn ein Wörterbuch nicht Ihr Ding ist, können die Berechnungen inline für die for-Schleife angewendet werden:

    df_aggregated['Male Count'].loc[(df_aggregated['Salary Basis'] == columns[0]) & 
                                (df_aggregated['Job Title'] == columns[1])] = df['Male Count'].iloc[ix].sum()
John Galt
quelle
Könnten Sie bitte den Datensatz teilen, den Sie für Ihre Lösung verwendet haben? Vielen Dank!
JeffZheng