GroupBy в Pandas намного сложнее и мощнее, чем groupby в SQL.

Одной из популярных функций пакета Pandas является функция группировки. Я считаю, что почти каждый, кто использовал Pandas раньше, также должен использовать функцию groupby. Он так популярен, потому что эффективно дает обобщенные, но подробные результаты. Как описано в документе пакета Pandas,

Под «группировкой по» мы подразумеваем процесс, включающий один или несколько из следующих шагов:

Разделение данных на группы по некоторым критериям.

Применение функции к каждой группе независимо.

Объединение результатов в структуру данных. [1]

В SQL также есть функция группировки. Поэтому для тех, кто имеет опыт работы с SQL, изучение групповых функций в Python не является сложной задачей. Но дело в том, что groupby в Pandas может выполнять гораздо больший анализ, чем в SQL, и это делает groupby в Pandas общей, но важной функцией.

Причина, по которой groupby в Pandas более мощная, заключается в том, что второй шаг «Применение». В SQL большинство действий в шагах «Применение» связаны статистически, например min, max, count и т. Д. Однако в Pandas «Применение» может выполнять гораздо больше.

Из документа Панд,

На этапе применения нам может потребоваться одно из следующего:

Агрегирование: рассчитайте сводную статистику (или статистику) для каждой группы.

Преобразование: выполните некоторые вычисления для конкретных групп и верните объект с похожим индексом.

Фильтрация: отбросьте некоторые группы в соответствии с групповым вычислением, которое оценивает True или False. [1]

В этой статье я расскажу о некоторых групповых приложениях. Эти приложения не только показывают мне понимание данных, но также помогают мне определить, как я буду дальше анализировать данные.

Давай начнем.

В этой статье используются данные student-por.csv в Потребление алкоголя студентами от Kaggle. Вы можете скачать данные по этой ссылке.

# Input
import pandas as pd 
data = pd.read_csv('student-por.csv')
data.info()
# Output
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 649 entries, 0 to 648
Data columns (total 33 columns):
school        649 non-null object
sex           649 non-null object
age           649 non-null int64
address       649 non-null object
famsize       649 non-null object
Pstatus       649 non-null object
Medu          649 non-null int64
Fedu          649 non-null int64
Mjob          649 non-null object
Fjob          649 non-null object
reason        649 non-null object
guardian      649 non-null object
traveltime    649 non-null int64
studytime     649 non-null int64
failures      649 non-null int64
schoolsup     649 non-null object
famsup        649 non-null object
paid          649 non-null object
activities    649 non-null object
nursery       649 non-null object
higher        649 non-null object
internet      649 non-null object
romantic      649 non-null object
famrel        649 non-null int64
freetime      649 non-null int64
goout         649 non-null int64
Dalc          649 non-null int64
Walc          649 non-null int64
health        649 non-null int64
absences      649 non-null int64
G1            649 non-null int64
G2            649 non-null int64
G3            649 non-null int64
dtypes: int64(16), object(17)
memory usage: 167.4+ KB

Шаг 1. Разделение данных

Первый шаг довольно простой - группировка данных на основе значения в одном или нескольких столбцах. Вам нужно только указать, как выполнять группировку. Большинство людей уже знают, что для группировки можно использовать имя столбца или список имен столбцов. Однако вы также можете передать функцию для группировки. Функция будет использовать значение индекса в качестве параметра и выполнять группировку. Для получения дополнительной информации, [2]

Объект, возвращаемый функцией groupby, - это «объект DataFrameGroupBy». После группировки вы можете использовать group, чтобы увидеть группы.

#Groupby one column
# Input
data.groupby('school')
# Output
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024D28C9DF98>
# Input
data.groupby('school').groups
# Output
{'GP': Int64Index([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
...413, 414, 415, 416, 417, 418, 419, 420, 421, 422],
dtype='int64', length=423),
 'MS': Int64Index([423, 424, 425, 426, 427, 428, 429, 430, 431, 432,
...639, 640, 641, 642, 643, 644, 645, 646, 647, 648],
dtype='int64', length=226)}
# Groupby a function 
# Input
def grouping(int):
    if int%10==0:
        return 'Group1'
    if int%5==0:
        return 'Group2'
    return 'Group3'
data.groupby(grouping).groups
# Output
{'Group1': Int64Index([  0,  10,  20,  30,  40,  50,  60,  70,  80,  90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 640], dtype='int64'),
 'Group2': Int64Index([  5,  15,  25,  35,  45,  55,  65,  75,  85,  95, 105, 115, 125,135, 145, 155, 165, 175, 185, 195, 205, 215, 225, 235, 245, 255, 265, 275, 285, 295, 305, 315, 325, 335, 345, 355, 365, 375, 385, 395, 405, 415, 425, 435, 445, 455, 465, 475, 485, 495, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 605, 615, 625, 635, 645], dtype='int64'),
 'Group3': Int64Index([  1,   2,   3,   4,   6,   7,   8,   9,  11,  12,... 637, 638, 639, 641, 642, 643, 644, 646, 647, 648],dtype='int64', length=519)}

В приведенном выше примере с использованием функции для группировки индекс в кадре данных - это номер строки. Следовательно, строка назначается одной из трех групп на основе номера строки. Затем функция groupby группирует эти три группы.

Чтобы получить данные для каждой группы, вы можете затем использовать функцию get_group() и ввести имя группы.

#Input
data.groupby(grouping).get_group('Group1')

Кроме того, если вы хотите сгруппировать данные по столбцу, не являющемуся индексом, вы можете использовать для группировки вместе apply и лямбда-функции.

# Input
data.groupby(data['famsize'].apply(lambda x: x.startswith('GT'))).get_group(False)

После группировки вы уже можете применить ряд функций вычисления или статистики. Например, size() может дать вам количество строк для каждой группы; sum() возвращает сумму для всех числовых столбцов для каждой группы. Чтобы узнать больше о применимых функциях, [3]

#Input
data.groupby(data['famsize'].apply(lambda x: x.startswith('GT'))).size()
#Output
famsize
False    192
True     457
dtype: int64

Шаг 2. Применение функции и объединение результатов

Пришло время осветить важную часть groupby. Функция Groupby в Pandas намного мощнее, чем в SQL, потому что вы можете использовать не только общие статистические функции, такие как min(), max(), mean(),..., но также и множество более сложных функций. Вы также можете применять свои определенные функции. В следующем разделе я объясню эти три действия по отдельности.

Агрегация (агрегирование)

Простое объяснение агрегирования - это выполнение вычислений на основе ранее сгруппированных данных. Агрегирование применяется к каждой группе и возвращает соответствующий результат.

Некоторые общие вычисления похожи на sum, min, max,… Вы можете выполнить вычисление для всех числовых столбцов, или вы также можете указать столбец для выполнения вычисления.

#Input 
mjob_gp = data.groupby('Mjob')
mjob_gp.agg('mean')

#Input
mjob_gp['age'].agg('mean')
#Output
Mjob
at_home     16.955556
health      16.312500
other       16.802326
services    16.661765
teacher     16.583333
Name: age, dtype: float64

Менее широко известно об агрегировании, что вы можете одновременно выполнять несколько вычислений для одного или нескольких столбцов. Это полезно, если вы хотите исследовать статистику столбца.

#Input 
mjob_gp.agg({'age':['mean','max']})

Однако одна проблема заключается в том, что столбцы находятся в многоиндексном режиме, что не очень хорошо для дальнейшей обработки (и мне лично не нравится многоиндексность). Таким образом, мы можем сделать еще один шаг и включить pd.NamedAgg (Новое в версии Pandas 0.25.0) в aggfunction. Для получения дополнительной информации о pd.NamedAgg, [4]

#Input
mjob_gp.agg(avg_age=pd.NamedAgg(column='age', aggfunc='mean'),
            min_age=pd.NamedAgg(column='age', aggfunc='min'),
            max_age=pd.NamedAgg(column='age', aggfunc='max'))

Использование pd.NamedAgg дает два преимущества. Первое преимущество - это, конечно, отсутствие мультииндекса для столбцов. И второе преимущество заключается в том, что вы можете самостоятельно определять имена столбцов.

Неудивительно, что вы также можете использовать при агрегировании пользовательские функции.

#Input 
def range_function(x):
    return max(x) - min(x)
mjob_gp.agg(max_age = pd.NamedAgg(column='age',aggfunc='max'),
            min_age = pd.NamedAgg(column='age',aggfunc='min'),
            range_age = pd.NamedAgg(column='age',aggfunc=range_function),)

Преобразование (преобразование)

Вернемся к описанию трансформации,

Преобразование: выполните некоторые вычисления для конкретных групп и верните объект с похожим индексом.

Ключевой частью являются «групповые вычисления». Вычисления в разных группах различаются. Например, max даст вам максимум столбца для каждой группы, но не для всего набора данных.

Другой характеристикой преобразования является то, что вычисление применяется к каждой строке и возвращает результаты с одинаковой длиной каждой группы, в отличие от агрегации с уменьшенной длиной. Если вы знакомы с оконной функцией в SQL, преобразование в Pandas аналогично этому. (PS: вы все еще не знаете оконную функцию в SQL?!?! Посмотрите мою предыдущую статью, которая поможет вам понять, почему оконная функция в SQL так важна)



#Input 
mjob_gp['G1','G2','G3'].transform(lambda x: (x-x.mean())/x.std())

В приведенном выше примере для каждой группы значения от G1 до G3 нормализованы на основе среднего значения и стандартного отклонения для соответствующей группы.

Фильтр

Из описания в пандах,

Вернуть копию DataFrame, исключая элементы из групп, которые не удовлетворяют логическому критерию, заданному функцией func. [5]

Вы можете использовать filterфункцию, чтобы отфильтровать любые группы, не удовлетворяющие критериям.

#Input 
mjob_gp.filter(lambda x: x['G1'].mean() > 12)

В приведенном выше примере возвращаются только Mjob в разделах «здоровье» и «учитель», поскольку их средние значения «G1» больше 12.

#Input 
mjob_gp['G1'].mean()
#Output
Mjob
at_home     10.451852
health      12.395833
other       11.275194
services    11.610294
teacher     12.555556
Name: G1, dtype: float64

Закрытие

Функция Groupby в Pandas - удобный инструмент для выполнения большого количества анализов и преобразований данных. Я надеюсь, что эта статья поможет вам понять мощь и полезность groupby в Pandas. Я уверен, что теперь вы знаете больше о том, как использовать groupby в обычном анализе данных. Удачи с пандами и увидимся в следующий раз.

Другая моя статья

Добавьте это в закладки, если вы новичок в Python (особенно если вы изучаете Python самостоятельно)

(Часть 2) Добавьте это в закладки, если вы новичок в Python (особенно если вы изучаете Python самостоятельно)

Как использовать Pandas для анализа числовых данных?

Веб-парсинг Twitter с помощью Python Selenium (Часть 1)

Веб-парсинг Twitter с помощью Python Selenium (Часть 2)

Цитирование / Ссылка

[1]: Группировать по: разделить-применить-объединить

[2]: pandas.DataFrame.groupby

[3]: Вычисления / описательная статистика

[4]: Именованная агрегация

[5]: pandas.core.groupby.DataFrameGroupBy.filter