Получить статистику для каждой группы (например, количество, среднее и т.д.) с помощью pandas GroupBy?
У меня есть DataFrame df
, и я использую несколько его столбцов для выполнения операции groupby
:
df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).mean()
Таким образом, я почти получаю нужную таблицу (DataFrame). Однако мне не хватает дополнительного столбца, который содержал бы количество строк в каждой группе. Другими словами, я получаю среднее значение, но также хотелось бы знать, сколько элементов было использовано для их вычисления. Например, в первой группе 8 значений, а во второй — 10 и так далее.
Вкратце: Как мне получить статистику для DataFrame по группам?
5 ответ(ов)
Быстрый ответ:
Самый простой способ получить количество строк по группам — это использовать метод .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)
...:
Отказ от ответственности:
Если некоторые из столбцов, которые вы агрегируете, содержат пропущенные значения, тогда вам следует рассматривать количество строк в группах как независимую агрегацию для каждого столбца. В противном случае вы можете быть введены в заблуждение относительно того, сколько записей на самом деле используется для вычисления таких значений, как среднее, поскольку pandas будет игнорировать NaN
значения в расчете среднего без уведомления об этом.
Мы можем легко сделать это, используя groupby
и count
. Не забудьте применить reset_index()
.
df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).count().reset_index()
Пожалуйста, попробуйте этот код:
new_column = df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).count()
df['count_it'] = new_column
df
Однако в вашем коде есть небольшая ошибка. При попытке добавить new_column
, который представляет собой результат группировки, в исходный DataFrame df
, возникнет ошибка, так как индексы не совпадают. Вам нужно будет использовать метод reset_index()
на new_column
, чтобы преобразовать его в обычный DataFrame, и затем объединить его с исходным df
, например, с помощью метода merge
:
new_column = df[['col1', 'col2', 'col3', 'col4']].groupby(['col1', 'col2']).count().reset_index()
new_column.rename(columns={'col3': 'count_it'}, inplace=True) # Измените имя столбца на подходящее
df = df.merge(new_column[['col1', 'col2', 'count_it']], on=['col1', 'col2'], how='left')
Теперь в вашем DataFrame df
будет новая колонка под названием 'count_it', которая содержит количество каждой группы.
Чтобы создать объект группы и вызывать методы, как в приведённом примере, вы можете использовать метод groupby
библиотеки pandas
. Вот как это сделать:
Сначала убедитесь, что у вас установлен
pandas
. Если нет, вы можете установить его с помощью pip:pip install pandas
Затем, импортируйте
pandas
и создайте DataFrame:import pandas as pd # Пример данных data = { 'col1': ['A', 'A', 'B', 'B'], 'col2': [1, 1, 2, 2], 'col3': [10, 15, 10, 20], 'col4': [100, 150, 200, 250] } df = pd.DataFrame(data)
Теперь вы можете создать объект группы и вызывать методы
max()
,mean()
, иdescribe()
:grp = df.groupby(['col1', 'col2', 'col3']) max_values = grp.max() mean_values = grp.mean() description = grp.describe()
Результаты будут содержать агрегированные данные по группам, которые вы определили с помощью столбцов
col1
,col2
иcol3
.
Пример кода полностью:
import pandas as pd
# Пример данных
data = {
'col1': ['A', 'A', 'B', 'B'],
'col2': [1, 1, 2, 2],
'col3': [10, 15, 10, 20],
'col4': [100, 150, 200, 250]
}
df = pd.DataFrame(data)
# Создание объекта группы
grp = df.groupby(['col1', 'col2', 'col3'])
# Вызов методов
max_values = grp.max()
mean_values = grp.mean()
description = grp.describe()
print("Max values:\n", max_values)
print("Mean values:\n", mean_values)
print("Description:\n", description)
Таким образом, вы сможете легко агрегировать данные в зависимости от нужных вам столбцов и получать различные статистики для каждой группы.
Вот альтернативный способ решения задачи с использованием библиотеки pandas
:
import pandas as pd
import numpy as np
# Создаем DataFrame с случайными данными
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)})
df
A B C D
0 foo one 0.808197 2.057923
1 bar one 0.330835 -0.815545
2 foo two -1.664960 -2.372025
3 bar three 0.034224 0.825633
4 foo two 1.131271 -0.984838
5 bar two 2.961694 -1.122788
6 foo one -0.054695 0.503555
7 foo three 0.018052 -0.746912
Вы можете использовать метод pd.crosstab
для создания кросс-таблицы, а затем применить метод .stack()
и .reset_index()
для получения сгруппированного результата с подсчетом.
pd.crosstab(df.A, df.B).stack().reset_index(name='count')
Результат будет следующим:
A B count
0 bar one 1
1 bar three 1
2 bar two 1
3 foo one 2
4 foo three 1
5 foo two 2
Таким образом, вы получаете количество вхождений каждой комбинации значений из столбцов A
и B
.
Переименование названий столбцов в Pandas
"Красивая печать всей Series / DataFrame в Pandas"
Запись DataFrame pandas в CSV файл
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas