Группировка: split-apply-combine
Под «группировкой» мы подразумеваем процесс, включающий один или несколько из следующих шагов:
- Разделение данных на группы на основе определенных критериев.
- Применение функции к каждой группе независимо.
- Объединение результатов в структуру данных.
Из этих шагов этап разделения является наиболее простым. На самом деле, во многих ситуациях мы можем разделить набор данных на группы и что-то сделать с этими группами. На этапе применения мы можем захотеть сделать одно из следующего:
-
Агрегирование: вычислить сводные статистические данные (или статистику) для каждой группы. Некоторые примеры:
- Вычислить групповые суммы или средние значения.
- Вычислить размер/количество элементов в группах.
-
Преобразование: выполнить некоторые вычисления, специфичные для группы, и вернуть похожий индексированный объект. Некоторые примеры:
- Стандартизировать данные (z-оценка) внутри группы.
- Заполнить пропуски (NaN) в группах значением, полученным из каждой группы.
-
Фильтрация: отбросить некоторые группы в соответствии с вычислением по группам, которое вычисляет True или False. Некоторые примеры:
- Отбросить данные, которые принадлежат группам с небольшим количеством элементов.
- Отфильтровать данные на основе групповой суммы или среднего значения.
- Некоторое сочетание вышеперечисленного: GroupBy будет проверять результаты этапа применения и попытается вернуть разумно объединенный результат, если он не подходит ни под одну из вышеперечисленных категорий.
Поскольку набор методов экземпляров объектов в структурах данных pandas обычно богат и выразителен, мы часто просто хотим вызвать, скажем, функцию DataFrame для каждой группы. Название GroupBy должно быть знакомо тем, кто работал с инструментом на основе SQL (или itertools), в котором вы можете писать код, подобный:
SELECT Column1, Column2, mean(Column3), sum(Column4) FROM SomeTable GROUP BY Column1, Column2
Мы стремимся сделать такие операции естественными и простыми для выражения с помощью pandas. Мы рассмотрим каждый раздел функциональности GroupBy, а затем предоставим некоторые нетривиальные примеры / варианты использования.
См. пособие для некоторых расширенных стратегий.
Разделение объекта на группы
Объекты pandas могут быть разделены по любым их осям. Абстрактное определение группировки — это предоставление отображения меток к именам групп. Для создания объекта GroupBy (подробнее об объекте GroupBy позже) вы можете сделать следующее:
In [1]: df = pd.DataFrame([('bird', 'Falconiformes', 389.0),
...: ('bird', 'Psittaciformes', 24.0),
...: ('mammal', 'Carnivora', 80.2),
...: ('mammal', 'Primates', np.nan),
...: ('mammal', 'Carnivora', 58)],
...: index=['falcon', 'parrot', 'lion', 'monkey', 'leopard'],
...: columns=('class', 'order', 'max_speed'))
...:
In [2]: df
Out[2]:
class order max_speed
falcon bird Falconiformes 389.0
parrot bird Psittaciformes 24.0
lion mammal Carnivora 80.2
monkey mammal Primates NaN
leopard mammal Carnivora 58.0
# default is axis=0
In [3]: grouped = df.groupby('class')
In [4]: grouped = df.groupby('order', axis='columns')
In [5]: grouped = df.groupby(['class', 'order'])
Картирование может быть задано множеством способов:
- Функция Python, вызываемая для каждой метки оси.
- Список или массив NumPy той же длины, что и выбранная ось.
- Словарь или
Series, предоставляющийlabel -> group nameсопоставление. - Для
DataFrameобъектов, строка, указывающая столбец, используемый для группировки. Конечно,df.groupby('A')это всего лишь синтаксический сахар дляdf.groupby(df['A']), но это упрощает жизнь. - Для
DataFrameобъектов, строка, указывающая уровень индекса, используемый для группировки. - Список любых из вышеперечисленных объектов.
В совокупности мы называем объекты группировки ключами. Например, рассмотрим следующий DataFrame:
Примечание
Строка, переданная в groupby, может относиться как к столбцу, так и к уровню индекса. Если строка совпадает как с именем столбца, так и с именем уровня индекса, будет поднято ValueError.
In [6]: 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)})
...:
In [7]: df
Out[7]:
A B C D
0 foo one 0.469112 -0.861849
1 bar one -0.282863 -2.104569
2 foo two -1.509059 -0.494929
3 bar three -1.135632 1.071804
4 foo two 1.212112 0.721555
5 bar two -0.173215 -0.706771
6 foo one 0.119209 -1.039575
7 foo three -1.044236 0.271860
Для DataFrame мы получаем объект GroupBy, вызвав groupby(). Естественно, мы можем сгруппировать данные по столбцам A или B, или по обоим:
In [8]: grouped = df.groupby('A')
In [9]: grouped = df.groupby(['A', 'B'])
Введено в версии 0.24.
Если у нас также есть многоуровневый индекс по столбцам A и B, мы можем сгруппировать по всем столбцам, кроме указанных:
In [10]: df2 = df.set_index(['A', 'B'])
In [11]: grouped = df2.groupby(level=df2.index.names.difference(['B']))
In [12]: grouped.sum()
Out[12]:
C D
A
bar -1.591710 -1.739537
foo -0.752861 -1.402938
Это разделит DataFrame по его индексу (строки). Мы также можем разделить по столбцам:
In [13]: def get_letter_type(letter): ....: if letter.lower() in 'aeiou': ....: return 'vowel' ....: else: ....: return 'consonant' ....: In [14]: grouped = df.groupby(get_letter_type, axis=1)
Объекты pandas Index поддерживают дубликаты значений. Если в качестве ключа группировки используется не уникальный индекс, все значения для одного и того же значения индекса будут считаться одной группой, и, следовательно, вывод функций агрегирования будет содержать только уникальные значения индекса:
In [15]: lst = [1, 2, 3, 1, 2, 3] In [16]: s = pd.Series([1, 2, 3, 10, 20, 30], lst) In [17]: grouped = s.groupby(level=0) In [18]: grouped.first() Out[18]: 1 1 2 2 3 3 dtype: int64 In [19]: grouped.last()
© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.25.0/user_guide/groupby.html