Отримайте статистику для кожної групи (наприклад, кількість, середнє значення тощо) за допомогою pandas GroupBy?


438

У мене є кадр даних, dfі я використовую кілька його стовпців для groupby:

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

Вищенаведеним способом я майже отримую потрібну мені таблицю (кадр даних). Не вистачає додаткового стовпця, який містить кількість рядків у кожній групі. Іншими словами, я маю на увазі, але я також хотів би знати, скільки було використано для отримання цих засобів. Наприклад, у першій групі є 8 значень, а в другій - 10 тощо.

Коротше кажучи: як отримати групову статистику для фрейму даних?

Відповіді:


427

На groupbyоб'єкті aggфункція може взяти список для застосування декількох методів агрегації одночасно. Це має дати вам необхідний результат:

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

2
Я думаю, вам потрібна посилання стовпця, щоб бути списком. Ви, мабуть, маєте на увазі: df[['col1','col2','col3','col4']].groupby(['col1','col2']).agg(['mean', 'count'])
rysqui

43
Це створює чотири колонки для підрахунку, але як отримати лише один? (Питання задає "додатковий стовпчик", і це теж я хотів би.)
Ян

16
Будь ласка, дивіться мою відповідь, якщо ви хочете отримати лише один countстовпець у групі.
Педро М Дуарте

Що робити, якщо у мене є окремий під назвою Counts і замість того, щоб рахувати рядки згрупованого типу, мені потрібно додати вздовж стовпця Counts.
Абхішек Бхатія

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

911

Швидкий відповідь:

Найпростіший спосіб отримати кількість рядків для групи - зателефонувавши .size(), що повертає Series:

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


Зазвичай ви хочете, щоб цей результат був DataFrame(замість Series), щоб ви могли:

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


Якщо ви хочете дізнатися, як обчислити кількість рядків та інші статистичні дані для кожної групи, продовжуйте читати нижче.


Детальний приклад:

Розглянемо наступний приклад фрейму даних:

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

Спершу давайте скористаємося, .size()щоб отримати кількість рядків:

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

Тоді давайте скористаємося .size().reset_index(name='counts')для отримання кількості рядків:

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


Включаючи результати для отримання додаткової статистики

Коли потрібно обчислити статистику для згрупованих даних, це зазвичай виглядає так:

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

Вищенаведений результат є трохи прикрою для вирішення через вкладені мітки стовпців, а також тому, що кількість рядків визначається на основі стовпців.

Для отримання більшого контролю над результатами я зазвичай розбиваю статистику на окремі агрегації, які потім комбіную join. Це виглядає приблизно так:

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



Виноски

Код, який використовується для створення тестових даних, показаний нижче:

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


Відмова:

Якщо деякі стовпці, які ви агрегуєте, мають нульові значення, то ви дійсно хочете розглянути підрахунки рядкових груп як незалежне агрегування кожного стовпця. В іншому випадку вас можуть ввести в оману щодо того, скільки записів фактично використовується для обчислення таких речей, як середнє значення, тому що панди будуть скидати NaNзаписи в середньому обчисленні, не повідомляючи про це.


1
Гей, мені дуже подобається ваше рішення, особливо останнє, де ви використовуєте прив'язку методів. Однак, оскільки часто необхідно застосовувати різні функції агрегації до різних стовпців, можна також сформулювати отримані кадри даних за допомогою pd.concat. Це, можливо, легше читати, ніж підпорядкований ланцюжок
Quickbeam2k1

4
приємне рішення, але для In [5]: counts_df = pd.DataFrame(df.groupby('col1').size().rename('counts')), можливо, краще встановити розмір () як новий стовпець, якщо ви хочете маніпулювати фреймом даних для подальшого аналізу, який має бутиcounts_df = pd.DataFrame(df.groupby('col1').size().reset_index(name='counts')
LancelotHolmes,

2
Дякуємо за біт "Включаючи результати для отримання більшої статистики"! Оскільки мій наступний пошук стосувався вирівнювання отриманого мультиіндексного стовпчика, я посилаюсь на відповідь тут: stackoverflow.com/a/50558529/1026
Миколай

Чудово! Скажіть, будь ласка, підказку, як додати isnullдо цього запиту, щоб він був також в одному стовпчику? 'col4': ['median', 'min', 'count', 'isnull']
Peter.k

38

Одна функція, щоб правило їх: GroupBy.describe

Повертає count, mean, std, та інші корисні статистичні дані за групою.

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

Щоб отримати конкретні статистичні дані, просто виберіть їх,

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

describeпрацює для декількох стовпців (змінити ['C']на['C', 'D'] - або видалити їх взагалі - і подивитися, що станеться, результат - MultiIndexed стовпчиковий кадр даних).

Ви також отримуєте різні статистичні дані для рядкових даних. Ось приклад,

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

Для отримання додаткової інформації дивіться документацію .


Не всі розподіли є нормальними. IQR був би дивним.
Бред

7

Ми можемо легко зробити це за допомогою groupby і підрахунку. Але ми повинні пам’ятати про використання reset_index ().

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

3
Це рішення працює до тих пір, поки в стовпцях немає нульового значення, інакше воно може ввести в оману (підрахунок буде нижчим за фактичну кількість спостережень за групами).
Адріан Тихоокео

4

Щоб отримати декілька статистичних даних, згортайте індекс та зберігайте назви стовпців:

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

Виробляє:

** сюди введіть опис зображення **


1

Створіть об’єкт групи та методи виклику, як наведено нижче:

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

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

1

Будь ласка, спробуйте цей код

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

Я думаю, що цей код додасть стовпчик під назвою "порахуй його", який підрахунок кожної групи

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.