Lấy số liệu thống kê cho từng nhóm (chẳng hạn như đếm, trung bình, v.v.) bằng cách sử dụng gấu trúc GroupBy?


437

Tôi có một khung dữ liệu dfvà tôi sử dụng một số cột từ nó để groupby:

df['col1','col2','col3','col4'].groupby(['col1','col2']).mean()

Theo cách trên tôi gần như có được bảng (khung dữ liệu) mà tôi cần. Điều còn thiếu là một cột bổ sung có chứa số lượng hàng trong mỗi nhóm. Nói cách khác, tôi có ý nghĩa nhưng tôi cũng muốn biết có bao nhiêu số đã được sử dụng để có được những phương tiện này. Ví dụ: trong nhóm đầu tiên có 8 giá trị và trong nhóm thứ hai 10, v.v.

Tóm lại: Làm cách nào để tôi có được số liệu thống kê theo nhóm cho một khung dữ liệu?

Câu trả lời:


427

Trên groupbyđối tượng, agghàm có thể lấy một danh sách để áp dụng một số phương thức tổng hợp cùng một lúc. Điều này sẽ cung cấp cho bạn kết quả bạn cần:

df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).agg(['mean', 'count'])

2
Tôi nghĩ rằng bạn cần tham chiếu cột là một danh sách. Bạn có lẽ có nghĩa là: df[['col1','col2','col3','col4']].groupby(['col1','col2']).agg(['mean', 'count'])
rysqui

43
Điều này tạo ra bốn cột đếm, nhưng làm thế nào để chỉ có một? (Câu hỏi yêu cầu "một cột bổ sung" và đó cũng là điều tôi muốn.)
Jaan

16
Vui lòng xem câu trả lời của tôi nếu bạn chỉ muốn nhận một countcột cho mỗi nhóm.
Pedro M Duarte

Điều gì sẽ xảy ra nếu tôi có một Số được gọi riêng là Đếm và thay vì đếm các hàng của loại được nhóm, tôi cần thêm dọc theo Đếm cột.
Abhishek Bhatia

@Jaan result = df['col1','col2','col3','col4'].groupby(['col1', 'col2']).mean() ; counts = times.groupby(['col1', 'col2']).size() ; result['count'] = counts
alvitawa

910

Câu trả lời nhanh:

Cách đơn giản nhất để có được số lượng hàng cho mỗi nhóm là bằng cách gọi .size(), trả về a Series:

df.groupby(['col1','col2']).size()


Thông thường bạn muốn kết quả này là một DataFrame(thay vì a Series) để bạn có thể làm:

df.groupby(['col1', 'col2']).size().reset_index(name='counts')


Nếu bạn muốn tìm hiểu cách tính tổng số hàng và số liệu thống kê khác cho mỗi nhóm, hãy tiếp tục đọc phần bên dưới.


Ví dụ chi tiết:

Hãy xem xét các khung dữ liệu mẫu sau:

In [2]: df
Out[2]: 
  col1 col2  col3  col4  col5  col6
0    A    B  0.20 -0.61 -0.49  1.49
1    A    B -1.53 -1.01 -0.39  1.82
2    A    B -0.44  0.27  0.72  0.11
3    A    B  0.28 -1.32  0.38  0.18
4    C    D  0.12  0.59  0.81  0.66
5    C    D -0.13 -1.65 -1.64  0.50
6    C    D -1.42 -0.11 -0.18 -0.44
7    E    F -0.00  1.42 -0.26  1.17
8    E    F  0.91 -0.47  1.35 -0.34
9    G    H  1.48 -0.63 -1.14  0.17

Trước tiên hãy sử dụng .size()để có được số lượng hàng:

In [3]: df.groupby(['col1', 'col2']).size()
Out[3]: 
col1  col2
A     B       4
C     D       3
E     F       2
G     H       1
dtype: int64

Sau đó, hãy sử dụng .size().reset_index(name='counts')để có được số lượng hàng:

In [4]: df.groupby(['col1', 'col2']).size().reset_index(name='counts')
Out[4]: 
  col1 col2  counts
0    A    B       4
1    C    D       3
2    E    F       2
3    G    H       1


Bao gồm kết quả để biết thêm số liệu thống kê

Khi bạn muốn tính toán số liệu thống kê về dữ liệu được nhóm, nó thường trông như thế này:

In [5]: (df
   ...: .groupby(['col1', 'col2'])
   ...: .agg({
   ...:     'col3': ['mean', 'count'], 
   ...:     'col4': ['median', 'min', 'count']
   ...: }))
Out[5]: 
            col4                  col3      
          median   min count      mean count
col1 col2                                   
A    B    -0.810 -1.32     4 -0.372500     4
C    D    -0.110 -1.65     3 -0.476667     3
E    F     0.475 -0.47     2  0.455000     2
G    H    -0.630 -0.63     1  1.480000     1

Kết quả ở trên là một chút khó chịu để giải quyết vì các nhãn cột lồng nhau và cũng vì số lượng hàng trên cơ sở mỗi cột.

Để có thêm quyền kiểm soát đầu ra, tôi thường chia các số liệu thống kê thành các tập hợp riêng lẻ mà sau đó tôi kết hợp sử dụng join. Nó trông như thế này:

In [6]: gb = df.groupby(['col1', 'col2'])
   ...: counts = gb.size().to_frame(name='counts')
   ...: (counts
   ...:  .join(gb.agg({'col3': 'mean'}).rename(columns={'col3': 'col3_mean'}))
   ...:  .join(gb.agg({'col4': 'median'}).rename(columns={'col4': 'col4_median'}))
   ...:  .join(gb.agg({'col4': 'min'}).rename(columns={'col4': 'col4_min'}))
   ...:  .reset_index()
   ...: )
   ...: 
Out[6]: 
  col1 col2  counts  col3_mean  col4_median  col4_min
0    A    B       4  -0.372500       -0.810     -1.32
1    C    D       3  -0.476667       -0.110     -1.65
2    E    F       2   0.455000        0.475     -0.47
3    G    H       1   1.480000       -0.630     -0.63



Chú thích

Mã được sử dụng để tạo dữ liệu thử nghiệm được hiển thị bên dưới:

In [1]: import numpy as np
   ...: import pandas as pd 
   ...: 
   ...: keys = np.array([
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['A', 'B'],
   ...:         ['C', 'D'],
   ...:         ['C', 'D'],
   ...:         ['C', 'D'],
   ...:         ['E', 'F'],
   ...:         ['E', 'F'],
   ...:         ['G', 'H'] 
   ...:         ])
   ...: 
   ...: df = pd.DataFrame(
   ...:     np.hstack([keys,np.random.randn(10,4).round(2)]), 
   ...:     columns = ['col1', 'col2', 'col3', 'col4', 'col5', 'col6']
   ...: )
   ...: 
   ...: df[['col3', 'col4', 'col5', 'col6']] = \
   ...:     df[['col3', 'col4', 'col5', 'col6']].astype(float)
   ...: 


Tuyên bố từ chối trách nhiệm:

Nếu một số cột mà bạn đang tổng hợp có giá trị null, thì bạn thực sự muốn xem hàng được tính là một tập hợp độc lập cho mỗi cột. Mặt khác, bạn có thể bị nhầm lẫn là có bao nhiêu bản ghi đang thực sự được sử dụng để tính toán những thứ như giá trị trung bình bởi vì gấu trúc sẽ bỏ NaNcác mục trong phép tính trung bình mà không cho bạn biết về nó.


1
Này, tôi thực sự thích giải pháp của bạn, đặc biệt là giải pháp cuối cùng, nơi bạn sử dụng phương pháp xích. Tuy nhiên, vì thường là cần thiết, để áp dụng các hàm tổng hợp khác nhau cho các cột khác nhau, người ta cũng có thể nối các khung dữ liệu kết quả bằng pd.concat. Đây có lẽ dễ dàng hơn để đọc hơn subsqeuent chain
Quickbeam2k1

4
giải pháp hay, nhưng đối với In [5]: counts_df = pd.DataFrame(df.groupby('col1').size().rename('counts')), có lẽ tốt hơn là đặt kích thước () làm cột mới nếu bạn muốn thao tác khung dữ liệu để phân tích thêm, nên làcounts_df = pd.DataFrame(df.groupby('col1').size().reset_index(name='counts')
LancelotHolmes

2
Cảm ơn bit "Bao gồm kết quả để biết thêm số liệu thống kê"! Vì tìm kiếm tiếp theo của tôi là về việc làm phẳng đa kết quả trên các cột, tôi sẽ liên kết với câu trả lời ở đây: stackoverflow.com/a/50558529/1026
Nickolay

Tuyệt quá! Bạn có thể vui lòng cho tôi một gợi ý làm thế nào để thêm isnullvào truy vấn này để có nó trong một cột không? 'col4': ['median', 'min', 'count', 'isnull']
Peter.k

38

Một chức năng để cai trị tất cả: GroupBy.describe

Returns count, mean, std, và thống kê hữu ích khác cho mỗi nhóm.

df.groupby(['col1', 'col2'])['col3', 'col4'].describe()

# Setup
np.random.seed(0)
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
                          'foo', 'bar', 'foo', 'foo'],
                   'B' : ['one', 'one', 'two', 'three',
                          'two', 'two', 'one', 'three'],
                   'C' : np.random.randn(8),
                   'D' : np.random.randn(8)})

from IPython.display import display

with pd.option_context('precision', 2):
    display(df.groupby(['A', 'B'])['C'].describe())

           count  mean   std   min   25%   50%   75%   max
A   B                                                     
bar one      1.0  0.40   NaN  0.40  0.40  0.40  0.40  0.40
    three    1.0  2.24   NaN  2.24  2.24  2.24  2.24  2.24
    two      1.0 -0.98   NaN -0.98 -0.98 -0.98 -0.98 -0.98
foo one      2.0  1.36  0.58  0.95  1.15  1.36  1.56  1.76
    three    1.0 -0.15   NaN -0.15 -0.15 -0.15 -0.15 -0.15
    two      2.0  1.42  0.63  0.98  1.20  1.42  1.65  1.87

Để có được số liệu thống kê cụ thể, chỉ cần chọn chúng,

df.groupby(['A', 'B'])['C'].describe()[['count', 'mean']]

           count      mean
A   B                     
bar one      1.0  0.400157
    three    1.0  2.240893
    two      1.0 -0.977278
foo one      2.0  1.357070
    three    1.0 -0.151357
    two      2.0  1.423148

describehoạt động cho nhiều cột (thay đổi ['C']thành Bộ ['C', 'D']lọc loại bỏ nó hoàn toàn và xem điều gì xảy ra, kết quả là một khung dữ liệu cột nhiều chỉ số).

Bạn cũng có được số liệu thống kê khác nhau cho dữ liệu chuỗi. Đây là một ví dụ,

df2 = df.assign(D=list('aaabbccc')).sample(n=100, replace=True)

with pd.option_context('precision', 2):
    display(df2.groupby(['A', 'B'])
               .describe(include='all')
               .dropna(how='all', axis=1))

              C                                                   D                
          count  mean       std   min   25%   50%   75%   max count unique top freq
A   B                                                                              
bar one    14.0  0.40  5.76e-17  0.40  0.40  0.40  0.40  0.40    14      1   a   14
    three  14.0  2.24  4.61e-16  2.24  2.24  2.24  2.24  2.24    14      1   b   14
    two     9.0 -0.98  0.00e+00 -0.98 -0.98 -0.98 -0.98 -0.98     9      1   c    9
foo one    22.0  1.43  4.10e-01  0.95  0.95  1.76  1.76  1.76    22      2   a   13
    three  15.0 -0.15  0.00e+00 -0.15 -0.15 -0.15 -0.15 -0.15    15      1   c   15
    two    26.0  1.49  4.48e-01  0.98  0.98  1.87  1.87  1.87    26      2   b   15

Để biết thêm thông tin, xem tài liệu .


Không phải tất cả các bản phân phối là bình thường. IQR sẽ là tuyệt vời.
Brad

7

Chúng ta có thể dễ dàng làm điều đó bằng cách sử dụng nhóm và đếm. Nhưng, chúng ta nên nhớ sử dụng reset_index ().

df[['col1','col2','col3','col4']].groupby(['col1','col2']).count().\
reset_index()

3
Giải pháp này hoạt động miễn là không có giá trị null trong các cột, nếu không nó có thể gây hiểu nhầm (số lượng sẽ thấp hơn số lượng quan sát thực tế theo nhóm).
Adrien Pacifico

4

Để có nhiều số liệu thống kê, thu gọn chỉ mục và giữ lại tên cột:

df = df.groupby(['col1','col2']).agg(['mean', 'count'])
df.columns = [ ' '.join(str(i) for i in col) for col in df.columns]
df.reset_index(inplace=True)
df

Sản xuất:

** nhập mô tả hình ảnh ở đây **


1

Tạo một đối tượng nhóm và gọi các phương thức như ví dụ dưới đây:

grp = df.groupby(['col1',  'col2',  'col3']) 

grp.max() 
grp.mean() 
grp.describe() 

1

Vui lòng thử mã này

new_column=df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).count()
df['count_it']=new_column
df

Tôi nghĩ rằng mã đó sẽ thêm một cột gọi là 'đếm nó', tính của từng nhóm

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.