Conversione di un output Pandas GroupDa serie a DataFrame


497

Sto iniziando con dati di input come questo

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

Che quando stampato appare come questo:

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

Il raggruppamento è abbastanza semplice:

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

e la stampa produce un GroupByoggetto:

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

Ma quello che voglio alla fine è un altro oggetto DataFrame che contiene tutte le righe nell'oggetto GroupBy. In altre parole, voglio ottenere il seguente risultato:

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

Non riesco a vedere come realizzarlo nella documentazione dei panda. Eventuali suggerimenti sarebbero i benvenuti.


1
A parte la domanda: quale versione di Panda usi? Se eseguo i primi 2 comandi ottengo g1 comeEmpty DataFrame Columns: [] Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]
Timofey

1
Il titolo della domanda è fuorviante per quanto riguarda la risposta accettata
matanster

@matanster posso chiederti a cosa sei venuto qui cercando di conoscere la risposta? Possiamo pensare di scrivere una risposta più accurata e di indirizzare l'attenzione degli utenti con un commento sotto la domanda.
1919

@coldspeed Questo è solo un tipico problema con SO, i titoli delle domande possono divergere in modo significativo dal contenuto della domanda e delle risposte. Se il meta non fosse così ostile, sarebbe probabilmente un aspetto utile da sollevare lì.
matanster

@matanster Sono d'accordo, tuttavia ero solo curioso di sapere che cosa stavi effettivamente cercando la risposta, in modo che ti abbia portato qui.
cs95,

Risposte:


530

g1qui è un dataframe. Ha un indice gerarchico, tuttavia:

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)

Forse vuoi qualcosa del genere?

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

O qualcosa del genere:

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

27
reset.index()fa il lavoro, fantastico!
gented

54
Avresti potuto usare:df1.groupby( [ "Name", "City"] ).size().to_frame(name = 'count').reset_index()
Nehal J Wani il

3
Il secondo esempio di utilizzo .reset_index()mi sembra il modo migliore di unire l'output da cui si otterrà df.groupby('some_column').apply(your_custom_func). Questo non era intuitivo per me.
Alexander

5
È vero anche in Python 3? Sto trovando una funzione groupby che restituisce l' pandas.core.groupby.DataFrameGroupByoggetto, no pandas.core.frame.DataFrame.
Adrian Keister,

3
Questa risposta sembra irrilevante per gli ultimi python e panda
matanster

129

Voglio cambiare leggermente la risposta data da Wes, perché richiede la versione 0.16.2 as_index=False. Se non lo si imposta, si ottiene un frame di dati vuoto.

Fonte :

Le funzioni di aggregazione non restituiranno i gruppi su cui si stanno aggregando se sono denominate colonne, quando as_index=Truepredefinite. Le colonne raggruppate saranno gli indici dell'oggetto restituito.

Il passaggio as_index=Falserestituirà i gruppi su cui si stanno aggregando, se sono denominati colonne.

Aggregano funzioni sono quelli che riducono la dimensione degli oggetti restituiti, per esempio: mean, sum, size, count, std, var, sem, describe, first, last, nth, min, max. Questo è ciò che accade quando fai ad esempio DataFrame.sum()e torni a Series.

nth può agire come un riduttore o un filtro, vedi qui .

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
#

MODIFICARE:

Nella versione 0.17.1e successive è possibile utilizzare subsetin counte reset_indexcon parametro namein 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

La differenza tra counte sizeè che sizeconta i valori NaN mentre countno.


8
Penso che questo sia il modo più semplice - un solo liner che usa il bel fatto che puoi nominare la colonna della serie con reset_index:df1.groupby( [ "Name", "City"]).size().reset_index(name="count")
Ben

1
C'è un motivo per cui as_index=False' stopped working in latest versions? I also tried to run df1.groupby (["Nome", "Città"], as_index = False) .size () `ma non influisce sul risultato (probabilmente perché il risultato del raggruppamento Seriesnon èDataFrame
Roman Pekar

1
Non sono sicuro, ma sembra che ci siano solo 2 colonne e groupbyda queste colonne. Ma non ne sono sicuro, perché non sono uno sviluppatore di Panda.
jezrael,

20

Semplicemente, questo dovrebbe svolgere il compito:

import pandas as pd

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

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

Qui, grouped_df.size()estrae il conteggio univoco di groupby e il reset_index()metodo ripristina il nome della colonna che vuoi che sia. Infine, Dataframe()viene chiamata la funzione panda per creare un oggetto DataFrame.


2
Scopri il metodo .to_frame (): grouped_df.size (). To_frame ('Group_Count')
Sealander

12

La chiave è utilizzare il metodo reset_index () .

Uso:

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()

Ora hai il tuo nuovo frame di dati in g1 :

dataframe dei risultati


9

Forse ho frainteso la domanda ma se vuoi riconvertire il groupby in un dataframe puoi usare .to_frame (). Volevo ripristinare l'indice quando l'ho fatto, quindi ho incluso anche quella parte.

codice di esempio non correlato alla domanda

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

6

Ho scoperto che ha funzionato per me.

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()

6

Di seguito la soluzione potrebbe essere più semplice:

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

4

Ho aggregato con i dati saggi di Qty e archiviato in dataframe

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

3

Queste soluzioni hanno funzionato solo parzialmente per me perché stavo facendo più aggregazioni. Ecco un output di esempio del mio raggruppato per quello che volevo convertire in un frame di dati:

Uscita Groupby

Poiché volevo qualcosa di più del conteggio fornito da reset_index (), ho scritto un metodo manuale per convertire l'immagine sopra in un frame di dati. Capisco che questo non è il modo più pythonic / panda di farlo poiché è abbastanza dettagliato ed esplicito, ma era tutto ciò di cui avevo bisogno. Fondamentalmente, utilizzare il metodo reset_index () spiegato sopra per avviare un frame di dati "impalcature", quindi scorrere gli accoppiamenti di gruppo nel frame di dati raggruppati, recuperare gli indici, eseguire i calcoli con il frame di dati non raggruppato e impostare il valore nel nuovo frame di dati aggregato .

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]

Se un dizionario non fa per te, i calcoli potrebbero essere applicati in linea nel ciclo for:

    df_aggregated['Male Count'].loc[(df_aggregated['Salary Basis'] == columns[0]) & 
                                (df_aggregated['Job Title'] == columns[1])] = df['Male Count'].iloc[ix].sum()

Potresti condividere il set di dati che hai utilizzato per la tua soluzione? Molte grazie!
JeffZheng
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.