Chuyển đổi đầu ra Pandas GroupBy từ Sê-ri sang Khung dữ liệu


495

Tôi đang bắt đầu với dữ liệu đầu vào như thế này

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

Mà khi in xuất hiện như thế này:

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

Nhóm là đủ đơn giản:

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

và in ấn mang lại một GroupByđối tượng:

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

Nhưng điều tôi muốn cuối cùng là một đối tượng DataFrame khác chứa tất cả các hàng trong đối tượng GroupBy. Nói cách khác, tôi muốn nhận được kết quả sau:

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

Tôi hoàn toàn không thể thấy làm thế nào để thực hiện điều này trong tài liệu về gấu trúc. Bất kỳ gợi ý sẽ được chào đón.


1
Bên cạnh câu hỏi: bạn sử dụng phiên bản gấu trúc nào? Nếu thực hiện 2 lệnh đầu tiên, tôi nhận được g1 làEmpty DataFrame Columns: [] Index: [(Alice, Seattle), (Bob, Seattle), (Mallory, Portland), (Mallory, Seattle)]
Timofey

1
Tiêu đề của câu hỏi gây hiểu nhầm liên quan đến câu trả lời được chấp nhận
matanster

@matanster tôi có thể hỏi những gì bạn đến đây để tìm câu trả lời? Chúng tôi có thể suy nghĩ về việc viết một câu trả lời chính xác hơn và hướng sự chú ý của người dùng bằng một bình luận dưới câu hỏi.
cs95

@coldspeed Đây chỉ là một vấn đề điển hình với SO, tiêu đề câu hỏi được phân tách đáng kể khỏi nội dung câu hỏi và câu trả lời. Nếu meta không phải là thù địch thì có lẽ sẽ là một khía cạnh hữu ích để nâng cao ở đó.
matanster

@matanster Tôi đồng ý, tuy nhiên tôi chỉ tò mò muốn biết bạn thực sự đang tìm kiếm câu trả lời để làm gì, vì vậy nó dẫn bạn đến đây.
cs95

Câu trả lời:


530

g1đây một DataFrame. Nó có một chỉ mục phân cấp, mặc dù:

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)

Có lẽ bạn muốn một cái gì đó như thế này?

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

Hoặc một cái gì đó như:

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()làm công việc, tuyệt vời!
gents

54
Bạn có thể đã sử dụng:df1.groupby( [ "Name", "City"] ).size().to_frame(name = 'count').reset_index()
Nehal J Wani

3
Ví dụ thứ hai sử dụng .reset_index()dường như là cách tốt nhất để tham gia đầu ra mà bạn sẽ nhận được df.groupby('some_column').apply(your_custom_func). Điều này không trực quan đối với tôi.
Alexander

5
Điều này cũng đúng trong Python 3? Tôi đang tìm một hàm nhóm trả về pandas.core.groupby.DataFrameGroupByđối tượng, không phải pandas.core.frame.DataFrame.
Adrian Keister

3
Câu trả lời này có vẻ không liên quan đến trăn và gấu trúc mới nhất
matanster

127

Tôi muốn thay đổi một chút câu trả lời do Wes đưa ra, vì phiên bản 0.16.2 yêu cầu as_index=False. Nếu bạn không đặt nó, bạn sẽ có một khung dữ liệu trống.

Nguồn :

Các hàm tổng hợp sẽ không trả về các nhóm mà bạn đang tổng hợp nếu chúng được đặt tên cột, khi nào as_index=True, mặc định. Các cột được nhóm sẽ là các chỉ số của đối tượng được trả về.

Passing as_index=Falsesẽ trả về các nhóm mà bạn đang tổng hợp, nếu chúng được đặt tên cột.

Tập hợp các chức năng được người mà làm giảm kích thước của các đối tượng quay trở lại, ví dụ: mean, sum, size, count, std, var, sem, describe, first, last, nth, min, max. Đây là những gì xảy ra khi bạn làm ví dụ DataFrame.sum()và lấy lại a Series.

nth có thể hoạt động như một bộ giảm tốc hoặc bộ lọc, xem tại đây .

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
#

BIÊN TẬP:

Trong phiên bản 0.17.1trở lên, bạn có thể sử dụng subsettrong countreset_indexvới tham số nametrong 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

Sự khác biệt giữa countsizesizetính giá trị NaN trong khi countkhông.


8
Tôi nghĩ rằng đây là cách dễ nhất - một lớp lót sử dụng một thực tế thú vị là bạn có thể đặt tên cho cột sê-ri bằng reset_index:df1.groupby( [ "Name", "City"]).size().reset_index(name="count")
Ben

1
Có một lý do tại sao as_index=False' stopped working in latest versions? I also tried to run df1.groupby ([ "Name", "Thành phố"], as_index = False) .size () `nhưng nó không ảnh hưởng đến kết quả (có thể là bởi vì kết quả của nhóm là SerieskhôngDataFrame
La Mã Pekar

1
Tôi không chắc chắn, nhưng dường như chỉ có 2 cột và groupbybởi các cột này. Nhưng tôi không chắc lắm, vì tôi không phải là nhà phát triển gấu trúc.
jezrael

20

Đơn giản, điều này sẽ làm nhiệm vụ:

import pandas as pd

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

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

Ở đây, grouped_df.size()kéo lên số đếm nhóm duy nhất và reset_index()phương thức đặt lại tên của cột mà bạn muốn. Cuối cùng, Dataframe()hàm gấu trúc được yêu cầu tạo đối tượng DataFrame.


2
Kiểm tra phương thức .to_frame (): grouped_df.size (). To_frame ('Group_Count')
Sealander

12

Điều quan trọng là sử dụng phương thức reset_index () .

Sử dụng:

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

Bây giờ bạn có khung dữ liệu mới của mình trong g1 :

khung dữ liệu kết quả


9

Có thể tôi hiểu nhầm câu hỏi nhưng nếu bạn muốn chuyển đổi nhóm trở lại một khung dữ liệu, bạn có thể sử dụng .to_frame (). Tôi muốn thiết lập lại chỉ mục khi tôi làm điều này vì vậy tôi cũng bao gồm phần đó.

mã ví dụ không liên quan đến câu hỏi

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

6

Tôi tìm thấy điều này làm việc cho tôi.

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

Giải pháp dưới đây có thể đơn giản hơn:

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

4

Tôi đã tổng hợp với dữ liệu khôn ngoan của Qty và lưu trữ vào khung dữ liệu

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

3

Những giải pháp này chỉ làm việc một phần cho tôi vì tôi đang thực hiện nhiều tập hợp. Đây là một đầu ra mẫu của nhóm mà tôi muốn chuyển đổi thành một khung dữ liệu:

Đầu ra của nhóm

Vì tôi muốn nhiều hơn số lượng được cung cấp bởi reset_index (), tôi đã viết một phương thức thủ công để chuyển đổi hình ảnh ở trên thành một khung dữ liệu. Tôi hiểu rằng đây không phải là cách pythonic / gấu trúc nhất để làm điều này vì nó khá dài dòng và rõ ràng, nhưng đó là tất cả những gì tôi cần. Về cơ bản, sử dụng phương thức reset_index () đã giải thích ở trên để bắt đầu một khung dữ liệu "giàn giáo", sau đó lặp qua các cặp nhóm trong khung dữ liệu được nhóm, truy xuất các chỉ mục, thực hiện các tính toán của bạn theo khung dữ liệu chưa được nhóm và đặt giá trị trong khung dữ liệu tổng hợp mới của bạn .

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]

Nếu một từ điển không phải là thứ của bạn, các tính toán có thể được áp dụng nội tuyến trong vòng lặp for:

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

Bạn có thể vui lòng chia sẻ dữ liệu bạn đã sử dụng cho giải pháp của bạn? Cảm ơn rất nhiều!
JeffZheng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.