Mengonversi output Pandas GroupBy dari Series ke DataFrame

496

Saya mulai dengan input data seperti ini

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

Yang ketika dicetak muncul sebagai ini:

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

Pengelompokan cukup sederhana:

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

dan mencetak menghasilkan GroupByobjek:

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

Tapi yang saya inginkan pada akhirnya adalah objek DataFrame lain yang berisi semua baris dalam objek GroupBy. Dengan kata lain saya ingin mendapatkan hasil sebagai berikut:

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

Saya tidak bisa melihat bagaimana melakukannya di dokumentasi panda. Petunjuk apa pun akan diterima.

saveenr
sumber
1
Selain pertanyaan: versi panda apa yang Anda gunakan? Jika menjalankan 2 perintah pertama saya mendapatkan g1 sebagaiEmpty DataFrame Columns: [] Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]
Timofey
1
Judul pertanyaan itu menyesatkan sehubungan dengan jawaban yang diterima
matanster
@ matanster, bolehkah saya bertanya apa yang Anda datang ke sini untuk mengetahui jawabannya? Kami dapat berpikir tentang menulis jawaban yang lebih akurat dan mengarahkan perhatian pengguna dengan komentar di bawah pertanyaan.
cs95
@coldspeed Ini hanya masalah biasa dengan SO, judul pertanyaan dibiarkan menyimpang secara signifikan dari konten pertanyaan dan jawaban. Jika meta tidak bermusuhan itu mungkin akan menjadi aspek yang berguna untuk muncul di sana.
matanster
@ matanster saya setuju, namun saya hanya ingin tahu apa yang sebenarnya Anda cari jawabannya, sehingga itu membawa Anda ke sini.
cs95

Jawaban:

530

g1di sini adalah DataFrame. Ini memiliki indeks hierarkis, meskipun:

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)

Mungkin Anda menginginkan sesuatu seperti ini?

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

Atau sesuatu seperti:

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
sumber
27
reset.index()melakukan pekerjaan, bagus!
gented
54
Anda bisa menggunakan:df1.groupby( [ "Name", "City"] ).size().to_frame(name = 'count').reset_index()
Nehal J Wani
3
Contoh kedua menggunakan .reset_index()bagi saya adalah cara terbaik untuk bergabung dengan hasil yang akan Anda dapatkan df.groupby('some_column').apply(your_custom_func). Ini tidak intuitif untuk saya.
Alexander
5
Apakah ini juga benar dalam Python 3? Saya menemukan fungsi groupby mengembalikan pandas.core.groupby.DataFrameGroupByobjek, bukan pandas.core.frame.DataFrame.
Adrian Keister
3
Jawaban ini tampaknya tidak relevan untuk python dan panda terbaru
matanster
128

Saya ingin sedikit mengubah jawaban yang diberikan oleh Wes, karena versi 0.16.2 membutuhkan as_index=False. Jika Anda tidak mengaturnya, Anda mendapatkan kerangka data kosong.

Sumber :

Fungsi agregasi tidak akan mengembalikan grup yang Anda himpun jika mereka diberi nama kolom, ketika as_index=True, default. Kolom yang dikelompokkan akan menjadi indeks dari objek yang dikembalikan.

Lulus as_index=Falseakan mengembalikan grup yang Anda gabungkan, jika mereka diberi nama kolom.

Menggabungkan fungsi-orang yang mengurangi dimensi dari obyek yang dikembalikan, misalnya: mean, sum, size, count, std, var, sem, describe, first, last, nth, min, max. Inilah yang terjadi ketika Anda melakukannya misalnya DataFrame.sum()dan kembali a Series.

dan dapat bertindak sebagai peredam atau filter, lihat di sini .

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
#

EDIT:

Dalam versi 0.17.1dan kemudian Anda dapat menggunakan subsetdi countdan reset_indexdengan parameter namedi 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

Perbedaan antara countdan sizeadalah yang sizemenghitung nilai NaN sementara counttidak.

jezrael
sumber
8
Saya pikir ini adalah cara termudah - satu liner yang menggunakan fakta bagus bahwa Anda dapat memberi nama kolom seri dengan reset_index:df1.groupby( [ "Name", "City"]).size().reset_index(name="count")
Ben
1
Apakah ada alasan mengapa as_index=False' stopped working in latest versions? I also tried to run df1.groupby (["Name", "City"], as_index = False) .size () `tetapi itu tidak mempengaruhi hasil (mungkin karena hasil pengelompokannya SeriestidakDataFrame
Roman Pekar
1
Saya tidak yakin, tetapi tampaknya hanya ada 2 kolom dan groupbykolom-kolom ini. Tapi saya tidak yakin, karena saya bukan pengembang panda.
jezrael
20

Cukup, ini harus melakukan tugas:

import pandas as pd

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

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

Di sini, grouped_df.size()tarik ke atas kelompok unik dengan hitungan, dan reset_index()metode mengatur ulang nama kolom yang Anda inginkan. Akhirnya, Dataframe()fungsi panda dipanggil untuk membuat objek DataFrame.

Surya
sumber
2
Lihat metode .to_frame (): grouped_df.size (). To_frame ('Group_Count')
Sealander
12

Kuncinya adalah menggunakan metode reset_index () .

Menggunakan:

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

Sekarang Anda memiliki kerangka data baru di g1 :

hasil dataframe

Ferd
sumber
9

Mungkin saya salah paham pertanyaannya tetapi jika Anda ingin mengonversi grup dengan kembali ke dataframe, Anda dapat menggunakan .to_frame (). Saya ingin mengatur ulang indeks ketika saya melakukan ini jadi saya memasukkan bagian itu juga.

contoh kode yang tidak terkait dengan pertanyaan

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

Saya menemukan ini bekerja untuk saya.

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
sumber
6

Solusi di bawah ini mungkin lebih sederhana:

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

Saya telah mengumpulkan dengan data bijaksana Qty dan menyimpannya ke dataframe

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

Solusi ini hanya berfungsi sebagian untuk saya karena saya melakukan banyak agregasi. Berikut ini adalah contoh hasil pengelompokan saya yang ingin saya konversikan ke kerangka data:

Keluaran Groupby

Karena saya menginginkan lebih dari hitungan yang disediakan oleh reset_index (), saya menulis metode manual untuk mengubah gambar di atas menjadi kerangka data. Saya mengerti ini bukan cara yang paling pythonic / panda melakukan ini karena cukup verbose dan eksplisit, tapi itu semua yang saya butuhkan. Pada dasarnya, gunakan metode reset_index () yang dijelaskan di atas untuk memulai kerangka data "perancah", kemudian lewati kelompok pasangan dalam kerangka data yang dikelompokkan, ambil indeks, lakukan perhitungan Anda terhadap kerangka data yang tidak dikelompokkan, dan tetapkan nilai dalam kerangka data yang baru Anda kumpulkan .

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]

Jika kamus bukan milik Anda, perhitungan bisa diterapkan inline di dalam for loop:

    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
sumber
Bisakah Anda membagikan dataset yang Anda gunakan untuk solusi Anda? Terima kasih banyak!
JeffZheng