Перейти к содержимому

Pandas groupby как обращаться к элементам

  • автор:

Как обратиться к столбцу сводной таблицы после GROUPBY?

У меня есть таблица, из которой я делаю сводную таблицу путём группировки операций и максимальных сумм для этого типа операций. После этого я хочу взять 5 минимальных значений путём nsmallest, но возникает ошибка. Как можно в полученной сводной таблице обратиться к столбцу MAX ?Полученная сводная таблицаОшибка при обращении к столбцу max

Отслеживать

задан 27 апр 2020 в 12:12

Arkady Horse Arkady Horse

11 2 2 бронзовых знака

Приведите воспроизводимый фрагмент исходных данных и свой код в электронном виде.

27 апр 2020 в 12:19

А print(a.columns) что говорит? Возможно, столбец называется ‘amount max’, но точно не помню, проще самому проверить, просто посмотрев список столбцов. Либо там двухуровневая индексация, но с ней я уже не помню как работать.

Основы Pandas №2 // Агрегация и группировка

Во втором уроке руководства по работе с pandas речь пойдет об агрегации (min, max, sum, count и дргуих) и группировке. Это популярные методы в аналитике и проектах data science, поэтому убедитесь, что понимаете все в деталях!

Примечание: это руководство, поэтому рекомендуется самостоятельно писать код, повторяя инструкции!

Агрегация данных — теория

Агрегация — это процесс превращения значений набора данных в одно значение. Например, у вас есть следующий набор данных…

animal water_need
zebra 100
lion 350
elephant 670
kangaroo 200

…простейший метод агрегации для него — суммирование water_needs , то есть 100 + 350 + 670 + 200 = 1320. Как вариант, можно посчитать количество животных — 4. Теория не так сложна. Но пора переходить к практике.

Агрегация данных — практика

Где мы остановились в последний раз? Открыли Jupyter Notebook, импортировали pandas и numpy и загрузили два набора данных: zoo.csv и article_reads . Продолжим с этого же места. Если вы не прошли первую часть, вернитесь и начните с нее.

Начнем с набора zoo . Он был загружен следующим образом:

pd.read_csv('zoo.csv', delimiter = ',') 

 набор данных zoo

Дальше сохраним набор данных в переменную zoo .

zoo = pd.read_csv('zoo.csv', delimiter = ',') 

Теперь нужно проделать пять шагов:

  1. Посчитать количество строк (количество животных) в zoo .
  2. Посчитать общее значение water_need животных.
  3. Найти наименьшее значение water_need .
  4. И самое большое значение water_need .
  5. Наконец, среднее water_need .

Агрегация данных pandas №1: .count()

Посчитать количество животных — то же самое, что применить функцию count к набору данных zoo :

zoo.count() 

функция count pandas

А что это за строки? На самом деле, функция count() считает количество значений в каждой колонке. В случае с zoo было 3 колонки, в каждой из которых по 22 значения.

Чтобы сделать вывод понятнее, можно выбрать колонку animal с помощью оператора выбора из предыдущей статьи:

zoo[['animal']].count() 

В этом случае результат будет даже лучше, если написать следующим образом:

zoo.animal.count() 

Также будет выбрана одна колонка, но набор данных pandas превратится в объект series (а это значит, что формат вывода будет отличаться).

функция count для колонки

Агрегация данных pandas №2: .sum()

Следуя той же логике, можно с легкостью найти сумму значений в колонке water_need с помощью:

zoo.water_need.sum() 

функция sum для колонки

Просто из любопытства можно попробовать найти сумму во всех колонках:

zoo.sum() 

функция sum pandas

Примечание: интересно, как .sum() превращает слова из колонки animal в строку названий животных. (Кстати, это соответствует всей логике языка Python).

Агрегация данных pandas №3 и №4: .min() и .max()

Какое наименьшее значение в колонке water_need ? Определить это несложно:

zoo.water_need.min() 

Наименьшее значение в колонке

То же и с максимальным значением:

zoo.water_need.max() 

Максимальное значение в колонке

Агрегация данных pandas №5 и №6: .mean() и .median()

Наконец, стоит посчитать среднестатистические показатели, например среднее и медиану:

zoo.water_need.mean() 

Cреднее значение в колонке

zoo.water_need.median() 

Медиана в колонке

Это было просто. Намного проще, чем агрегация в SQL.

Но можно усложнить все немного с помощью группировки.

Группировка в pandas

Работая аналитиком или специалистом Data Science, вы наверняка постоянно будете заниматься сегментациями. Например, хорошо знать количество необходимой воды ( water_need ) для всех животных (это 347,72 ). Но удобнее разбить это число по типу животных.

Вот упрощенная репрезентация того, как pandas осуществляет «сегментацию» (группировку и агрегацию) на основе значений колонок!

Функция .groupby в действии

Проделаем эту же группировку с DataFrame zoo .

Между переменной zoo и функцией . mean() нужно вставить ключевое слово groupby :

zoo.groupby('animal').mean() 

Группировка данных в pandas

Как и раньше, pandas автоматически проведет расчеты . mean() для оставшихся колонок (колонка animal пропала, потому что по ней проводилась группировка). Можно или игнорировать колонку uniq_id или удалить ее одним из следующих способов:

zoo.groupby(‘animal’).mean()[[‘water_need’]] — возвращает объект DataFrame.

zoo.groupby(‘animal’).mean().water_need — возвращает объект Series.

Можно поменять метод агрегации с . mean() на любой изученный до этого.

Проверить себя №1

Вернемся к набору данных article_read .

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

Если все готово, вот первое задание:

Какой источник используется в article_read чаще остальных?

Правильный ответ:
Reddit!

Получить его можно было с помощью кода:

article_read.groupby('source').count() 

Взять набор данных article_read , создать сегменты по значениям колонки source ( groupby(‘source’) ) и в конце концов посчитать значения по источникам ( .count() ).

Какой источник используется в article_read чаще остальных

Также можно удалить ненужные колонки и сохранить только user_id :

article_read.groupby('source').count()[['user_id']] 

Проверить себя №2

Вот еще одна, более сложная задача:

Какие самые популярные источник и страна для пользователей country_2 ? Другими словами, какая тема из какого источника принесла больше всего просмотров из country_2 ?

Правильный ответ: Reddit (источник) и Азия (тема) с 139 прочтениями.

Вот Python-код для получения результата:

article_read[article_read.country == 'country_2'].groupby(['source', 'topic']).count() 

Какие самые частые источник и страна для пользователей country_2

Вот краткое объяснение:

В первую очередь отфильтровали пользователей из country_2 ( article_read[article_read.country == ‘country_2’] ). Затем для этого подмножества был использован метод groupby . (Да, группировку можно осуществлять для нескольких колонок. Для этого их названия нужно собрать в список. Поэтому квадратные скобки используются между круглыми. Это что касается части groupby([‘source’, ‘topic’]) ).

А функция count() — заключительный элемент пазла.

Итого

Это была вторая часть руководства по работе с pandas. Теперь вы знаете, что агрегация и группировка в pandas— это простые операции, а использовать их придется часто.

Примечание: если вы ранее пользовались SQL, сделайте перерыв и сравните методы агрегации в SQL и pandas. Так лучше станет понятна разница между языками.

В следующем материале вы узнаете о четырех распространенных методах форматирования данных: merge , sort , reset_index и fillna .

3 функции Pandas для группировки и агрегирования данных

При работе с данными в Pyth on у программистов есть инструмент, который никогда не подведет: pandas. Это полнофункциональная и интуитивно понятная библиотека с открытым ПО, предоставляющая структуры данных для работы с высокоразмерными датасетами.

Выделяют 2 основные структуры данных:

  • Series для одномерных массивов;
  • DataFrame для двухмерных таблиц, содержащих строки и столбцы.

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

Вы научитесь применять функции apply , cut , groupby и agg . Они могут весьма пригодиться для лучшего понимания данных на основе их графического представления .

Содержание:1. Импорт данных 
2. Простые агрегации
3. Множественные агрегации

1. Импорт данных

Начнем с импорта библиотек и датасетов. В работе будем использовать датасет с ценами на недвижимость Бостона, доступный в библиотеке Scikit-learn.

import numpy as np # линейная алгебра
import pandas as pd # обработка данных, CSV файл ввода-вывода (например, pd.read_csv)
from sklearn.datasets import load_boston

boston = load_boston()
df = pd.DataFrame(data=boston.data,columns=boston.feature_names)
df['price']=boston.target
df.head()

Данный DataFrame содержит только числовые признаки, а нам нужны категориальные переменные для разделения датасета на группы. Следовательно, займемся их созданием с помощью его описательной статистики:

df.describe()

Допустим, нам нужны категориальные признаки для RM (число комнат) и price (цены), которые представляют собой среднее число комнат на жилое помещение и медиану цен на жилье в размере $10,000 соответственно. В зависимости от диапазона значений указанных числовых признаков у этих переменных должны быть разные уровни (level), для создания которых задействуем значения первого и третьего квантиля. С целью генерирования этих новых переменных воспользуемся функцией apply .

df['RM_levels']=df['RM'].apply(lambda x: 'low' if xdf['price_levels']=df['price'].apply(lambda x: 'low' if xdf[['RM','RM_levels','price','price_levels']].head()

Новые столбцы появились благодаря функции apply , которая по умолчанию работает с каждой строкой датасета. Она по порядку проверяет условия. Первый уровень содержит значения числовых признаков, не превышающих первый квантиль. “Средний” уровень включает значения, располагающиеся в диапазоне между первым и третьим квантилем. Третий и последний уровень охватывают только значения, превосходящие третий квантиль.

Функция cut — альтернативный и более эффективный способ создания таких переменных, в особенности тех, что обладают несколькими уровнями. Как и в предыдущем случае, делим значения price на 3 группы: [3,5.8),[5.8,6.6),[6.6,9), где 3 и 9 соответствуют минимальной и максимальной границам переменной. Эту же логику применяем и к числу комнат. Передав только интервальные значения и аргумент right=False для игнорирования правого максимума, получаем следующие группы:

df['RM_levels'] = pd.cut(df['RM'],bins=[3,5.8,6.6,9],right=False)
df['price_levels'] = pd.cut(df['price'],bins=[5,17,25,51],right=False)
df[['RM','RM_levels','price','price_levels']].head()

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

df[df.price_levels=='[17, 25)']

Если проверить тип столбца price_levels , взяв лишь первую строку, то увидим, что у нас есть на самом деле:

type(df['price_levels'][0])

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

l=[[3,5.8,6.6,9],[5,17,25,51]]
lbs1 = ['[<>,<>)'.format(l[0][i],l[0][i+1]) for i in range(len(l[0])-1)]
lbs2 = ['[<>,<>)'.format(l[1][i],l[1][i+1]) for i in range(len(l[1])-1)]

df['RM_levels'] = pd.cut(df['RM'],bins=[3,5.8,6.6,9],right=False,labels=lbs1)
df['price_levels'] = pd.cut(df['price'],bins=[5,17,25,51],right=False,labels=lbs2)
print(type(df['price_levels'][0]))

Теперь у вас есть строковые объекты! В любом случае в данной статье я буду сохранять метки, как показано ниже, всегда устанавливая аргумент labels :

df['RM_levels'] = pd.cut(df['RM'],bins=[3,5.8,6.6,9],labels=['low','middle','high'],right=False)
df['price_levels'] = pd.cut(df['price'],bins=[5,17,25,51],labels=['low','middle','high'],right=False)

2. Простые агрегации

Итак, первый этап пройден, и мы приступаем к группировке датасета на основании заданных признаков. Допустим, нужно узнать среднее значение каждого столбца для каждого типа price:

df_price = df.groupby(by=['price_levels']).mean()
df_price

Как видно, по каждому уровню мы получили строку, содержащую соответствующие средние значения всех переменных, представленных в датасете. Переменная price_levels считается индексом, поскольку groupby по умолчанию в качестве такого индекса возвращает метку группы. Обратите внимание на произвольный порядок уровней. Выясним причину:

df.info()

На данный момент новые переменные сохранены в памяти как объекты. Очевидно, что их необходимо преобразовать в категории. Как только мы это сделали, определяем порядок уровней переменных.

df['price_levels']=df['price_levels'].astype('category')
df['price_levels'].cat.reorder_categories(['low','middle','high'], inplace=True)

df['RM_levels']=df['RM_levels'].astype('category')
df['RM_levels'].cat.reorder_categories(['low','middle','high'], inplace=True)

Попробуем заново сгруппировать датасет для каждого уровня price. Если установить аргумент as_index в значение False , то метка группы более не будет рассматриваться в качестве индекса:

df_price = df.groupby(by=['price_levels'],as_index=False).mean()
df_price

В результате получаем упорядоченные уровни и переменную price_levels , которая более не является индексом. Как видим, датасет содержит много столбцов. Их число можно сократить, если выбрать лишь несколько признаков (например, RM и price). Кроме того, расположим ценовые уровни по возрастанию.

df_price = df.groupby(by=['price_levels'],as_index=False)[['price','RM']].mean().sort_values(by='price_levels', ascending=True)
df_price

С увеличением числа комнат повышается стоимость жилплощади. Но что если мы не хотим ограничиваться вычислением среднего, минимального и максимального значений? В таком случае нам потребуется функция apply . Выясним диапазон значений столбцов CRIM и LSTAT, имена которых соответственно означают уровень преступности на душу населения по городу и процент граждан с низким социальным статусом.

df_price = df.groupby(by=['price_levels'],as_index=False)[['CRIM','LSTAT']].apply(lambda v: v.max()-v.min())
df_price

Как видно, уровень преступности и процент населения с низким социальным положением уменьшаются с ростом цен на жилплощадь. Представим это соотношение в виде гистограммы:

import plotly.express as px

fig = px.bar(df_price, x='price_levels', y='CRIM', labels=)
fig.show()

3. Множественные агрегации

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

df_price = df.groupby(by=['price_levels'],as_index=False)[['price','AGE','CRIM']].agg(['mean','min','max','std'])
df_price

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

df_price = df.groupby(by=['price_levels'])[['price','AGE','CRIM']].agg(['mean','min','max','std']).reset_index()
df_price

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

df_price.columns

Работа с двойными индексами может стать обременительной. Чтобы не создавать лишних сложностей, можно заменить имена столбцов следующим образом:

stats = ['mean','min','max','std']
df_price.columns = ['price_levels']+['price_<>'.format(stat) for stat in stats]+['age_<>'.format(stat) for stat in stats]+['age_<>'.format(stat) for stat in stats]
df_price

С таким DataFrame работается уже намного легче.

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

df_price = df.groupby(by=['price_levels','RM_levels'],as_index=False).agg()
df_price

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

import plotly.express as px

stats = ['count','mean','max','min']
df_price.columns = ['price_levels','RM_levels']+['CRIM_<>'.format(stat) for stat in stats]+['price_mean']
df_price
fig = px.bar(df_price[df_price.RM_levels=='high'], x='price_levels', y='CRIM_count', labels=)
fig.show()

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

Выводы

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

Благодарю за внимание!

Полезные ссылки

  • https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.apply.html
  • https://pandas.pydata.org/docs/reference/api/pandas.cut.html
  • https://www.google.com/search?q=groupby+pandas&oq=groupby+pandas&aqs=chrome..69i57j0j0i20i263j0l2j69i60j69i61j69i60.5962j0j7&sourceid=chrome&ie=UTF-8
  • https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.agg.html
  • 7 полезных операций в Pandas при работе с DataFrame
  • Новая библиотека превосходит Pandas по производительности
  • 7 трюков pandas для науки о данных

Работа с групповыми статистиками в pandas GroupBy

Visual representation of data grouping and statistical analysis.

Работа с данными часто требует группировки и агрегации информации. В Python библиотека pandas предоставляет удобный и мощный инструмент для этого — метод groupby() . Он позволяет группировать данные по одному или нескольким столбцам и вычислять различные статистики для каждой группы.

Рассмотрим простой пример. Пусть имеется следующий датафрейм:

import pandas as pd data = df = pd.DataFrame(data)

Допустим, требуется найти среднее значение столбцов ‘D’ и ‘E’ для каждой комбинации значений в столбцах ‘A’ и ‘B’. Для этого можно использовать метод groupby() :

df.groupby(['A', 'B']).mean()

В результате получается датафрейм, в котором индексами являются уникальные комбинации значений столбцов ‘A’ и ‘B’, а значениями — средние значения столбцов ‘D’ и ‘E’ для каждой группы.

Однако, помимо среднего значения, часто требуется знать количество элементов в каждой группе. В pandas это можно сделать с помощью метода size() :

df.groupby(['A', 'B']).size()

Этот код вернет серию, где индексами будут уникальные комбинации значений столбцов ‘A’ и ‘B’, а значениями — количество строк в каждой группе.

Если требуется добавить эту информацию в исходный датафрейм, можно использовать метод merge() :

grouped = df.groupby(['A', 'B']).size().reset_index(name='counts') df = pd.merge(df, grouped, on=['A', 'B'], how='left')

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *