Группировка: 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, позже) вы можете сделать следующее:
# default is axis=0 >>> grouped = obj.groupby(key) >>> grouped = obj.groupby(key, axis=1) >>> grouped = obj.groupby([key1, key2])
Сопоставление можно указать многими способами:
- Функция Python, которая вызывается для каждой метки оси.
- Список или массив NumPy той же длины, что и выбранная ось.
- Словарь или
Series, предоставляющийlabel -> group nameотображение. - Для объектов
DataFrame, строка, указывающая столбец для группировки. Конечно,df.groupby('A')— это просто синтаксический сахар дляdf.groupby(df['A']), но это упрощает жизнь. - Для объектов
DataFrame, строка, указывающая уровень индекса для группировки. - Список из любого из вышеперечисленного.
В совокупности мы называем объекты группировки ключами. Например, рассмотрим следующий DataFrame.
Примечание
Новое в версии 0.20.
Строка, переданная в groupby, может относиться как к столбцу, так и к уровню индекса. Если строка совпадает как с именем столбца, так и с именем уровня индекса, выдается предупреждение, и приоритет отдаётся столбцу. В будущих версиях это приведёт к ошибке неоднозначности.
In [1]: 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 [2]: df
Out[2]:
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 [3]: grouped = df.groupby('A')
In [4]: grouped = df.groupby(['A', 'B'])
Это разделит DataFrame по своему индексу (строкам). Мы также можем разделить по столбцам:
In [5]: def get_letter_type(letter): ...: if letter.lower() in 'aeiou': ...: return 'vowel' ...: else: ...: return 'consonant' ...: In [6]: grouped = df.groupby(get_letter_type, axis=1)
Объекты pandas Index поддерживают дублирующие значения. Если в операции groupby используется не уникальный индекс в качестве ключа группировки, все значения для одного значения индекса будут считаться одной группой, и поэтому в результате агрегационных функций будут содержаться только уникальные значения индекса:
In [7]: lst = [1, 2, 3, 1, 2, 3] In [8]: s = pd.Series([1, 2, 3, 10, 20, 30], lst) In [9]: grouped = s.groupby(level=0) In [10]: grouped.first() Out[10]: 1 1 2 2 3 3 dtype: int64 In [11]: 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.23.4/groupby.html