Dapatkan statistik untuk setiap grup (seperti jumlah, rata-rata, dll) menggunakan panda GroupBy?

439

Saya memiliki bingkai data dfdan saya menggunakan beberapa kolom dari itu ke groupby:

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

Dengan cara di atas saya hampir mendapatkan tabel (frame data) yang saya butuhkan. Yang hilang adalah kolom tambahan yang berisi jumlah baris di setiap grup. Dengan kata lain, saya memiliki maksud tetapi saya juga ingin tahu berapa banyak angka yang digunakan untuk mendapatkan cara ini. Misalnya di grup pertama ada 8 nilai dan yang kedua 10 dan seterusnya.

Singkatnya: Bagaimana cara saya mendapatkan statistik bijaksana-kelompok untuk kerangka data?

Roma
sumber

Jawaban:

427

Pada groupbyobjek, aggfungsi dapat mengambil daftar untuk menerapkan beberapa metode agregasi sekaligus. Ini akan memberi Anda hasil yang Anda butuhkan:

df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).agg(['mean', 'count'])
Dengan keras
sumber
2
Saya pikir Anda perlu referensi kolom menjadi daftar. Apakah maksud Anda: df[['col1','col2','col3','col4']].groupby(['col1','col2']).agg(['mean', 'count'])
rysqui
43
Ini membuat empat kolom jumlah, tetapi bagaimana cara mendapatkannya hanya satu? (Pertanyaannya menanyakan "kolom tambahan" dan itulah yang saya inginkan juga.)
Jaan
16
Silakan lihat jawaban saya jika Anda ingin mendapatkan hanya satu countkolom per grup.
Pedro M Duarte
Bagaimana jika saya memiliki Hitungan yang disebut terpisah dan alih-alih menghitung baris dari tipe yang dikelompokkan, saya perlu menambahkan sepanjang Jumlah kolom.
Abhishek Bhatia
@Jaan result = df['col1','col2','col3','col4'].groupby(['col1', 'col2']).mean() ; counts = times.groupby(['col1', 'col2']).size() ; result['count'] = counts
alvitawa
913

Jawaban cepat:

Cara paling sederhana untuk mendapatkan jumlah baris per grup adalah dengan menelepon .size(), yang mengembalikan Series:

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


Biasanya Anda menginginkan hasil ini sebagai DataFrame(bukan a Series) sehingga Anda dapat melakukan:

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


Jika Anda ingin mengetahui cara menghitung jumlah baris dan statistik lainnya untuk setiap grup, baca terus di bawah ini.


Contoh terperinci:

Pertimbangkan contoh kerangka data berikut:

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

Pertama mari kita gunakan .size()untuk mendapatkan jumlah baris:

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

Kemudian mari kita gunakan .size().reset_index(name='counts')untuk mendapatkan jumlah baris:

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


Termasuk hasil untuk lebih banyak statistik

Saat Anda ingin menghitung statistik pada data yang dikelompokkan, biasanya akan terlihat seperti ini:

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

Hasil di atas agak menjengkelkan untuk ditangani karena label kolom bersarang, dan juga karena jumlah baris berdasarkan basis kolom.

Untuk mendapatkan kontrol lebih besar atas output, saya biasanya membagi statistik menjadi agregat individu yang kemudian saya gabungkan menggunakan join. Ini terlihat seperti ini:

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



Catatan kaki

Kode yang digunakan untuk menghasilkan data uji ditunjukkan di bawah ini:

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)
   ...: 


Penolakan:

Jika beberapa kolom yang Anda agregasikan memiliki nilai nol, maka Anda benar-benar ingin melihat jumlah baris grup sebagai agregasi independen untuk setiap kolom. Kalau tidak, Anda dapat disesatkan mengenai berapa banyak catatan yang sebenarnya digunakan untuk menghitung hal-hal seperti mean karena panda akan menjatuhkan NaNentri dalam perhitungan rata-rata tanpa memberi tahu Anda tentang hal itu.

Pedro M Duarte
sumber
1
Hei, saya sangat suka solusi Anda, terutama yang terakhir, di mana Anda menggunakan metode chaining. Namun, karena sering diperlukan, untuk menerapkan fungsi agregasi yang berbeda ke kolom yang berbeda, orang juga dapat menyimpulkan frame data yang dihasilkan menggunakan pd.concat. Ini mungkin lebih mudah dibaca daripada rantai subsqeuent
Quickbeam2k1
4
solusi yang bagus, tetapi untuk In [5]: counts_df = pd.DataFrame(df.groupby('col1').size().rename('counts')), mungkin lebih baik untuk mengatur ukuran () sebagai kolom baru jika Anda ingin memanipulasi kerangka data untuk analisis lebih lanjut, yang seharusnyacounts_df = pd.DataFrame(df.groupby('col1').size().reset_index(name='counts')
LancelotHolmes
2
Terima kasih untuk bit "Termasuk hasil untuk statistik lebih banyak"! Karena pencarian saya berikutnya adalah tentang meratakan multi-indeks yang dihasilkan pada kolom, saya akan menautkan ke jawaban di sini: stackoverflow.com/a/50558529/1026
Nickolay
Bagus! Bisakah Anda memberi saya petunjuk bagaimana menambahkan isnullkueri ini ke dalam satu kolom juga? 'col4': ['median', 'min', 'count', 'isnull']
Peter.k
38

Satu Fungsi untuk Memerintah Mereka Semua: GroupBy.describe

Pengembalian count, mean, std, dan statistik lainnya yang berguna per-kelompok.

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

Untuk mendapatkan statistik tertentu, cukup pilih,

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

describeberfungsi untuk beberapa kolom (ubah ['C']ke ['C', 'D']—atau hapus sama sekali — dan lihat apa yang terjadi, hasilnya adalah kerangka data kolom MultiIndexed).

Anda juga mendapatkan statistik berbeda untuk data string. Ini sebuah contoh,

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

Untuk informasi lebih lanjut, lihat dokumentasi .

cs95
sumber
Tidak semua distribusi normal. IQR akan luar biasa.
Brad
7

Kita dapat dengan mudah melakukannya dengan menggunakan groupby dan menghitung. Tapi, kita harus ingat untuk menggunakan reset_index ().

df[['col1','col2','col3','col4']].groupby(['col1','col2']).count().\
reset_index()
Nimesh
sumber
3
Solusi ini berfungsi selama tidak ada nilai nol dalam kolom, jika tidak bisa menyesatkan (jumlah akan lebih rendah dari jumlah sebenarnya pengamatan oleh kelompok).
Adrien Pacifico
4

Untuk mendapatkan beberapa statistik, tutup indeks, dan pertahankan nama kolom:

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

Menghasilkan:

** masukkan deskripsi gambar di sini **

Jake Drew
sumber
1

Buat objek grup dan panggil metode seperti contoh di bawah ini:

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

grp.max() 
grp.mean() 
grp.describe() 
Mahendra
sumber
1

Silakan coba kode ini

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

Saya pikir kode itu akan menambahkan kolom yang disebut 'hitung' yang menghitung setiap kelompok

Ichsan
sumber