Pandas GroupBy: группировка, суммирование и агрегация данных в Python

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

В конце этого руководства вы научитесь работать с методом .groupby() из библиотеки Pandas, используя разбиение-применение-сочетание. Этот процесс эффективно обрабатывает большие наборы данных для манипуляции данными очень мощными способами. Вы научитесь полностью освоить метод, включая доступ к группам, преобразование данных и создание производных данных.

Оглавление

Что такое метод GroupBy в Pandas?

Метод Pandas .groupby() работает аналогично оператору SQL GROUP BY. На самом деле, он разработан чтобы быть похожим на свой аналог в SQL, используя его эффективность и интуитивность. Подобно оператору GROUP BY в SQL, метод Pandas работает путем разделения данных, их агрегирования заданным образом (или способами) и повторной комбинации данных осмысленным образом.

Поскольку метод .groupby() сначала разделяет данные, мы можем работать с группами напрямую. Так как агрегация выполняется после разделения, у нас есть полная свобода в том, как агрегировать данные. Pandas затем объединяет данные, чтобы представить их в виде осмысленного DataFrame.

Что замечательно в этом, так это то, что он позволяет нам использовать метод по-разному, особенно творчески. Благодаря этому метод является основой для понимания, как Pandas можно использовать для манипуляции и анализа данных. Длина этого руководства отражает его сложность и важность!

Почему Pandas предлагает несколько способов агрегации данных?

Pandas предоставляет множество вариантов для анализа и агрегации данных. Почему существует, казалось бы, так много пересекающихся методов? Ответ заключается в том, что каждый метод, такой как .pivot(), .pivot_table(), .groupby(), предлагает уникальный подход к агрегации данных. Они не просто являются переименованными версиями, а представляют собой полезные способы для выполнения различных задач.

Загрузка образца Pandas DataFrame

Чтобы следовать этому руководству, давайте загрузим пример DataFrame из библиотеки Pandas. Загрузим воображаемые данные о продажах, используя набор данных, размещенный на странице datagy на Github. Если вы хотите следовать инструкции шаг за шагом, скопируйте приведенный ниже код для загрузки набора данных с помощью метода .read_csv()

# Загрузка образцового DataFrame из файла CSV с датами в столбце 'date'
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/datagy/data/main/sales.csv', parse_dates=['date'])
print(df.head())

# Вывод:
#         date  gender      region  sales
# 0 2022-08-22    Male  North-West  20381
# 1 2022-03-05    Male  North-East  14495
# 2 2022-02-09    Male  North-East  13510
# 3 2022-06-22    Male  North-East  15983
# 4 2022-08-10  Female  North-West  15007

Вывод первых пяти строк с помощью метода .head() дает некоторое представление о наших данных. Видно, что у нас есть столбец date, содержащий дату транзакции. У нас есть строковые столбцы, охватывающие gender и region нашего продавца. Наконец, у нас есть целочисленный столбец sales, представляющий общую стоимость продаж.

Понимание группирования объектов Pandas

Давайте впервые взглянем на метод Pandas .groupby(). Мы можем создать объект GroupBy, применив метод к нашему DataFrame и передав либо столбец, либо список столбцов. Посмотрим, как это выглядит: создадим объект GroupBy и выведем его на экран.

# Создание объекта группировки DataFrame Pandas по столбцу 'region'
print(df.groupby('region'))

# Вывод:
# <pandas.core.groupby.generic.DataFrameGroupBy object at 0x7fb78815a4f0>

Мы видим, что это вернуло объект типа DataFrameGroupBy. Поскольку это объект, мы можем изучить некоторые его атрибуты.

Pandas GroupBy Attributes

Например, эти объекты имеют атрибут .ngroups, который содержит количество групп, доступных в этом групп

# Подсчет количества групп в объекте группировки DataFrame Pandas по столбцу 'region'
print(df.groupby('region').ngroups)

# Вывод:
# 3

Мы можем увидеть, что наш объект имеет 3 группы. Аналогично, мы можем использовать атрибут .groups, чтобы получить представление о специфике получившихся групп. Вывод этого атрибута — это объект, похожий на словарь, который содержит наши группы в качестве ключей. Значения этих ключей — это индексы строк, принадлежащих этой группе!

# Доступ к группам в объекте группировки DataFrame Pandas по столбцу 'region'
print(df.groupby('region').groups)

# Вывод:
# {'North-East': [1, 2, 3, ...], 'North-West': [0, 4, 7, ...], 'South': [5, 6, 8, ...]}

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

# Доступ только к именам групп в объекте группировки DataFrame PandAs по столбцу 'region'
print(df.groupby('region').groups.keys())

# Вывод:
# dict_keys(['North-East', 'North-West', 'South'])

Мы можем видеть, насколько полезен этот метод! Он позволяет нам группировать данные значимым образом.

Выбор группы PandasПо группе

Мы также можем выбрать все записи, принадлежащие определенной группе. Это может быть полезно, если вы хотите увидеть данные каждой группы. Чтобы сделать это, мы можем применить метод .get_group() и передать имя группы, которую мы хотим выбрать. Давайте попробуем выбрать регион 'South' из нашего объекта GroupBy:

# Выбор группы из объекта группировки DataFrame Pandas по столбцу 'region'
print(df.groupby('region').get_group('South'))

# Вывод:
#           date  gender region  sales
# 5   2022-09-06    Male  South  21792
# 6   2022-08-21    Male  South  20113
# 8   2022-11-22    Male  South  14594
# 9   2022-01-16  Female  South  24114
# 10  2022-12-21    Male  South  35154
# ..         ...     ...    ...    ...
# 972 2022-06-09    Male  South  22254
# 979 2022-11-24  Female  South  25591
# 981 2022-12-05    Male  South  34334
# 985 2022-12-01  Female  South  21282
# 994 2022-09-29    Male  South  21255

# [331 rows x 4 columns]

Это может быть весьма полезно, если вы хотите получить некоторое представление о данных. Аналогично, это дает вам понимание того, как метод .groupby() на самом деле используется для агрегирования данных. В следующем разделе вы узнаете, как работает метод Pandas groupby, используя методологию разделения, применения и объединения.

Понимание Pandas GroupBy Разделение-Применение-Объединение

Метод groupby в Pandas использует процесс, известный как "разделяй, применяй и объединяй", для полезной агрегации или модификации DataFrame. Этот процесс работает точно так, как и назван.

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

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

  3. Объединение результатов в подходящую структуру данных

В предыдущем разделе, когда вы применили метод .groupby() и передали в него столбец, вы уже выполнили первый шаг! Вы смогли разделить данные на соответствующие группы, основываясь на переданных вами критериях.

Причина применения этого метода заключается в том, чтобы разбить проблему анализа больших данных на управляемые части. Это позволяет выполнять операции над отдельными частями и затем объединять их. Хотя шаги применения и объединения выполняются по отдельности, Pandas абстрагирует их, создавая впечатление единого шага.

Использование Split-Apply-Combine без GroupBy

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

  1. Разделение данных: Начнем с разделения данных – мы можем пройтись по каждому уникальному значению в DataFrame, разделяя данные по столбцу 'region'.

  2. Применение функции агрегации: Оттуда мы можем выбрать строки из DataFrame, соответствующие условию, и применить к ним функцию.

  3. Объединение данных наконец, мы можем создать словарь и добавить в него данные, а затем преобразовать обратно в DataFrame Pandas.

# Репликация процесса split-apply-combine без использования GroupBy

# Создание контейнерного словаря для хранения средних значений по каждой группе
averages = {}

# Разделение данных на различные регионы
for region in df['region'].unique():
    tempdf = df[df['region'] == region]

    # Применение функции агрегации для вычисления среднего значения продаж
    average = tempdf['sales'].mean()

    # Сборка данных в DataFrame
    averages[region] = [average]

# Создание DataFrame из словаря с средними значениями по каждому региону
aggregate_df = pd.DataFrame.from_dict(averages, orient='index', columns=['Average Sales'])
print(aggregate_df)

# Вывод:
#             Average Sales
# North-West   15257.732919
# North-East   17386.072046
# South        24466.864048

Это много кода, чтобы написать для простой агрегации! К счастью, метод groupby в Pandas делает это намного проще. В следующем разделе вы узнаете, как значительно упростить этот процесс.

Агрегирование данных с помощью Pandas GroupBy

В этом разделе вы узнаете, как использовать метод groupby из Pandas для агрегации данных различными способами. Мы попробуем воссоздать тот же результат, о котором вы узнали ранее, чтобы увидеть, насколько проще на самом деле этот процесс! Давайте посмотрим, как выглядит код, а затем разберем, как он работает:

# Агрегация данных с использованием метода .groupby() из библиотеки Pandas

averages = df.groupby('region')['sales'].mean()
print(averages)

# Вывод:
# region
# North-East    17386.072046
# North-West    15257.732919
# South         24466.864048
# Name: sales, dtype: float64

Посмотрите на код! Мы смогли сократить шесть строк кода до одной! Давайте разберем это по элементам:

  1. df.groupby('region') вам уже знакомо. Оно разделяет данные на различные группы на основе столбца region.

  2. ['sales'] выбирает только этот столбец из групп

  3. .mean() применяет метод вычисления среднего для каждого столбца в группе.

  4. Данные объединены в результирующий DataFrame, averages

Давайте более наглядно рассмотрим весь процесс. Чтобы упростить понимание, давайте посмотрим только на первые семь записей DataFrame:

Understanding Split Apply and Combine in Pandas GroupBy
Understanding how the split-apply-combine procedure works in Pandas .groupby()

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

Другие агрегации с Pandas GroupBy

Теперь, когда вы понимаете, как работает процедура разделения, применения и объединения, давайте рассмотрим некоторые другие способы агрегации в Pandas. Таблица ниже предоставляет обзор доступных функций агрегации:

Aggregation Method
Description

.count()

Количество ненулевых записей

.sum()

Сумма значения

.mean()

Среднее арифметическое значений

.median()

Медиана значений

.min()

Минимальное значение группы

.max()

Максимальное значение группы

.mode()

Наиболее часто встречающееся значение в группе

.std()

Стандартное отклонение группы

.var()

Дисперсия группы

Например, если мы захотим вычислить стандартное отклонение для каждой группы, мы могли бы просто написать:

# Вычисление стандартного отклонения продаж для каждой группы по региону

standard_deviations = df.groupby('region')['sales'].std()
print(standard_deviations)

# Вывод:
# region
# North-East    2032.541552
# North-West    3621.456493
# South         5253.702513
# Name: sales, dtype: float64

Применение множественных агрегаций с использованием Pandas GroupBy

Pandas также предоставляет дополнительный метод .agg(), который позволяет применять несколько агрегирующих функций в методе .groupby(). Этот метод позволяет передавать список вызовов (т. е. функции без скобок). Давайте посмотрим, как мы можем использовать некоторые функции из библиотеки numpy для агрегации.

# Применение нескольких агрегатных функций с использованием метода .agg()

import numpy as np

aggs = df.groupby('region')['sales'].agg([np.mean, np.std, np.var])
print(aggs)

# Вывод:
#                     mean          std           var
# region                                             
# North-East  17386.072046  2032.541552  4.131225e+06
# North-West  15257.732919  3621.456493  1.311495e+07
# South       24466.864048  5253.702513  2.760139e+07

Метод .agg() позволяет легко генерировать сводные статистические данные по различным группам. Без этого нам пришлось бы применять метод .groupby() три раза, но здесь мы смогли сократить это до одного вызова метода!

Преобразование данных с помощью Pandas GroupBy

Еще один невероятно полезный способ использовать метод groupby в Pandas — это трансформация данных. Что это значит? Трансформируя данные, вы выполняете операцию, специфичную для этой группы. Это может включать, например, стандартизацию данных только на основе этой группы с использованием z-оценки или заполнение отсутствующих данных, вводя значение на основе этой группы.

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

Метод .transform() вернет одно значение для каждой записи в оригинальном наборе данных. Поэтому, гарантируется, что размер результата будет совпадать.

Использование .transform в GroupBy

Давайте рассмотрим пример преобразования данных в Pandas DataFrame. В этом примере мы рассчитаем, какой процент от общих продаж региона составляет каждая продажа. Для этого мы можем применить метод .transform() к объекту GroupBy. Мы можем передать функцию 'sum', чтобы вернуть сумму для всей группы в каждой строке. Наконец, мы делим исходный столбец 'sales' на эту сумму.

Давайте посмотрим, как выглядит этот код:

# Вычисление процента продаж региона

df['Percent Of Region Sales'] = df['sales'] / df.groupby('region')['sales'].transform('sum')
print(df.head())

# Вывод:
#         date  gender      region  sales  Percent Of Region Sales
# 0 2022-08-22    Male  North-West  20381                 0.004148
# 1 2022-03-05    Male  North-East  14495                 0.002403
# 2 2022-02-09    Male  North-East  13510                 0.002239
# 3 2022-06-22    Male  North-East  15983                 0.002649
# 4 2022-08-10  Female  North-West  15007                 0.003055

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

Преобразование данных без .transform

В предыдущем разделе вы преобразовали данные с помощью функции .transform(), но мы также можем применить функцию, которая вернет одно значение без агрегации. Например, давайте применим метод .rank() к нашей группировке. Это позволит нам ранжировать значения в каждой группе. Вместо использования метода .transform(), мы непосредственно применим метод .rank()

# Преобразование DataFrame с использованием GroupBy

df['ranked'] = df.groupby('region')['sales'].rank(ascending=False)
print(df.sort_values(by='sales', ascending=False).head())

# Вывод:
#           date  gender region  sales  ranked
# 61  2022-02-22  Female  South  43775     1.0
# 673 2022-04-19    Male  South  37878     2.0
# 111 2022-10-31  Female  South  36444     3.0
# 892 2022-09-05    Male  South  35723     4.0
# 136 2022-02-27    Male  South  35485     5.0

В этом случае метод .groupby() возвращает серию Pandas такой же длины, как и исходный DataFrame. Поэтому мы можем просто присвоить эту серию новому столбцу.

Фильтрация данных с помощью Pandas GroupBy

Замечательный способ использования метода .groupby() — фильтрация DataFrame. Этот подход значительно отличается от обычной фильтрации, так как позволяет применять метод фильтрации на основе некоторых агрегаций значений группы. Например, мы можем отфильтровать наш DataFrame, чтобы удалить строки, где средняя цена продажи группы меньше 20,000.

# Фильтрация строк, где средняя цена продаж в группе меньше 20,000

df = df.groupby('region').filter(lambda x: x['sales'].mean() < 20000)
print(df.head())

# Вывод:
#         date  gender      region  sales
# 0 2022-08-22    Male  North-West  20381
# 1 2022-03-05    Male  North-East  14495
# 2 2022-02-09    Male  North-East  13510
# 3 2022-06-22    Male  North-East  15983
# 4 2022-08-10  Female  North-West  15007

Let’s break down how this works:

  1. We group our data by the 'region' column

  2. We apply the .filter() method to filter based on a lambda function that we pass in

  3. The lambda function evaluates whether the average value found in the group for the 'sales' column is less than 20,000

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

Группировка Pandas DataFrame по нескольким столбцам

Мы можем расширить функциональность метода Pandas .groupby(), группируя данные по нескольким столбцам. Ранее вы группировали DataFrame только по одному столбцу, передавая строку, представляющую столбец. Однако можно также передать список строк, представляющих различные столбцы. Это позволяет разделить данные еще более детально.

Давайте вычислим сумму всех продаж, разделенных по 'region' и по 'gender' , написав.

# Агрегация данных по нескольким столбцам

sums = df.groupby(['region', 'gender'])['sales'].sum()
print(sums.head())

# Вывод:
#                      sales
# region     gender         
# North-East Female  3051132
#            Male    2981835
# North-West Female  2455899
#            Male    2457091
# South      Female  4135688

Более того, все методы, которые мы рассмотрели ранее, также возможны и в этом случае. Например, мы могли бы применить функцию .rank() снова и определить топ-продажи в каждой комбинации регион

# Ранжирование продаж по регионам и полам

df['rank'] = df.groupby(['region', 'gender'])['sales'].rank(ascending=False)
print(df.head())

# Вывод:
#         date  gender      region  sales   rank
# 0 2022-08-22    Male  North-West  20381   11.0
# 1 2022-03-05    Male  North-East  14495  154.0
# 2 2022-02-09    Male  North-East  13510  168.0
# 3 2022-06-22    Male  North-East  15983  138.0
# 4 2022-08-10  Female  North-West  15007   89.5

Использование пользовательских функций с Pandas GroupBy

Еще одна отличная функция метода .groupby() в Pandas заключается в том, что мы можем применять наши собственные функции. Это позволяет определять функции, которые соответствуют потребностям нашего анализа. Вы уже видели это в примере фильтрации с использованием метода .groupby(). Мы можем использовать либо анонимную лямбда-функцию, либо сначала определить функцию и применить ее.

Давайте посмотрим, как это может работать. Мы можем определить пользовательскую функцию, которая будет возвращать диапазон группы, вычисляя разницу между минимальным и максимальным значениями. Давайте определим эту функцию и применим её к нашему вызову метода .groupby() .

# Использование пользовательской функции в объекте GroupBy

def group_range(x):
    return x.max() - x.min()

ranges = df.groupby(['region', 'gender'])['sales'].apply(group_range)
print(ranges)

# Вывод:
# region      gender
# North-East  Female    10881
#             Male      10352
# North-West  Female    20410
#             Male      17469
# South       Female    30835
#             Male      27110
# Name: sales, dtype: int64

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

Полезные примеры Pandas GroupBy

В этом разделе вы узнаете о полезных вариантах использования метода Pandas .groupby(). Примеры в этом разделе призваны продемонстрировать более креативные способы использования метода. Эти примеры предназначены для вдохновения и расширения вашего понимания различных способов использования метода.

Получение первых n строк группы PandasАвтор

Давайте посмотрим, как вы можете вернуть пять строк из каждой группы в результирующий DataFrame. Это может быть особенно полезно, когда вы хотите получить представление о том, как могут выглядеть данные в каждой группе. Если порядок сортировки данных в DataFrame не имеет значения, вы можете просто использовать функцию .head(), чтобы вернуть любое количество записей из каждой группы.

Давайте рассмотрим, как вернуть две записи из каждой группы, где каждая группа определяется регионом и полом:

# Возврат первых двух записей из каждого группы

print(df.groupby(['region', 'gender']).head(2))

# Вывод:
#          date  gender      region  sales
# 0  2022-08-22    Male  North-West  20381
# 1  2022-03-05    Male  North-East  14495
# 4  2022-08-10  Female  North-West  15007
# 5  2022-09-06    Male       South  21792
# 7  2022-07-08    Male  North-West  13650
# 9  2022-01-16  Female       South  24114
# 11 2022-04-30  Female  North-West  19631
# 12 2022-11-25  Female  North-East  18262
# 13 2022-08-14  Female  North-East  13733
# 20 2022-01-21  Female       South  32313

Получение n-го самого большого ряда группы PandasАвтор

В этом примере вы узнаете, как выбрать n-е по величине значение в заданной группе. Для этого мы можем использовать метод .nlargest(), который вернет n-е по величине значение. Например, если мы хотим вернуть второе по величине значение в каждой группе, мы можем просто передать значение 2. Давайте посмотрим, как это выглядит:

# Получение второй по величине значения в каждой группе

print(df.groupby(['region', 'gender'])['sales'].nlargest(2))

# Вывод:
# region      gender     
# North-East  Female    407    22545.0
#             Male      560    22361.0
#                     442    21951.0
# North-West  Female    758    26813.0
#             Male      844    23553.0
#                     576    23485.0
# South       Female    61     43775.0
#             Male      673    37878.0
#                     892    35723.0
# Name: sales, dtype: float64

Упражнения

Пора проверить свои знания! Используйте упражнения ниже, чтобы попрактиковаться в использовании метода .groupby(). Решения можно найти, нажав на раздел под каждым вопросом.

Вернуть DataFrame, содержащий минимальное значение дат для каждого региона.
print(df.groupby('region')['date'].min())

# Returns:
# region
# North-East   2022-01-02
# North-West   2022-01-02
# South        2022-01-04
# Name: date, dtype: datetime64[ns]
Какое наименьшее стандартное отклонение продаж?
print(df.groupby('region')['sales'].std().min())
# Вывод:
# 2032.5415517362096
Как вернуть последние 2 строки каждой группы по региону и полу?
print(df.groupby(['region', 'gender']).tail(2))

# Вывод:
#           date  gender      region  sales
# 979 2022-11-24  Female       South  25591
# 981 2022-12-05    Male       South  34334
# 985 2022-12-01  Female       South  21282
# 988 2022-07-10    Male  North-West  12500
# 990 2022-07-07  Female  North-East  16468
# 993 2022-06-11    Male  North-West  14942
# 994 2022-09-29    Male       South  21255
# 995 2022-06-02  Female  North-West  14015
# 996 2022-05-20  Female  North-East  15503
# 997 2022-04-02    Male  North-East  18714
# 998 2022-12-07    Male  North-East  19910
# 999 2022-12-19  Female  North-West  16589

Заключение и резюме

В этом уроке вы узнали о методе .groupby() в Pandas. Этот метод позволяет анализировать, агрегировать, фильтровать и преобразовывать ваши данные множеством полезных способов. Ниже вы найдёте краткое резюме метода .groupby() в Pandas:

  • Метод .groupby() в Pandas позволяет выполнять агрегирование, преобразование и фильтрацию DataFrame

  • Метод работает с использованием операций разделения, преобразования и применения

  • Вы можете сгруппировать данные по нескольким столбцам, передав список столбцов

  • Вы можете легко применять несколько агрегатов, используя метод .agg()

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

Официальную документацию для метода Pandas .groupby() можно найти здесь

Дополнительные ресурсы

To learn more about related topics, check out the tutorials below:

  • Pandas: подсчет уникальных значений в объекте GroupBy

  • Python Defaultdict: обзор и примеры

  • Вычислить средневзвешенное значение в Pandas и Python

Last updated