Работа с данными среднего размера в Python. Pandas и Seaborn

от автора

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

Я попробовал много инструментов: Excel, Python+Matplotlib, R+ggplot, Python+ggplot, и остановился на связке Python+Pandas+Seaborn. Решил с их использованием уже много задач и хотел бы поделиться наблюдениями.


Я покажу процесс исследования одного странного датасета. Речь пойдёт о расписании всех спортивных мероприятий с участием российских спортсменов за последние 8 лет. Кстати, если у кого-то после прочтения появятся идеи, что с этими данными делать, пожалуйста, напишите, потому что я ничего толкового так и не придумал.

Захватывающий этап парсинга rst и doc-файликов с сайта Минспорта я пропускаю. Предположим, что все данные уже есть в виде DataFrame’a:

data.head() 

Таблица не большая, но и не маленькая:

len(data) 
76601 

Первым делом хотелось бы посмотреть, какие виды спорта представлены:

table = data.groupby('section').size() table 
section R4                                                             11 Авиамодельный спорт                                          1206 Автомобильный спорт                                          2787 Автомодельный спорт                                           160 Айкидо                                                         26 Айсшток                                                        49 Академическая гребля                                          358 Акробатический рок-н-ролл                                     293 Альпинизм                                                     355 Американский футбол                                            86 Армейский рукопашный бой                                       15 Армспорт                                                      159 Бадминтон                                                     698 Баскетбол                                                    1160 Бейсбол                                                       176 Биатлон                                                      1101 Бильярдный спорт                                              442 Бобслей                                                        53 Бобслей (скелетон)                                            368 Бодибилдинг                                                    94 Бокс                                                         1374 Борьба на поясах                                              144 Боулинг                                                       134 ... 

Отсортируем:

table = data.groupby('section').size() table = table.sort(inplace=False, ascending=False) table 
section Автомобильный спорт                                          2787 Спорт лиц с поражением ОДА                                   2469 Фехтование                                                   2253 Мотоциклетный спорт                                          2025 Дзюдо                                                        2022 Теннис                                                       1770 Велоспорт-шоссе                                              1561 Легкая атлетика                                              1511 Футбол                                                       1432 Парусный спорт                                               1418 Бокс                                                         1374 Конный спорт                                                 1297 Спорт глухих                                                 1277 Волейбол                                                     1208 Авиамодельный спорт                                          1206 Художественная гимнастика                                    1196 ... 

Достаточно странный топ. Отсортируем не по числу мероприятий, а по числу участников:

table = data.groupby('section').participants.sum() table = table.sort(inplace=False, ascending=False) table 
Футбол                                                       535305 Баскетбол                                                    460100 Автомобильный спорт                                          401397 Танцевальный спорт                                           307731 Дзюдо                                                        297023 Самбо                                                        219013 Легкая атлетика                                              217761 Тхэквондо                                                    202859 Киокусинкай                                                  191995 Велоспорт-шоссе                                              190293 Комплексные мероприятия                                      187294 Спортивная борьба                                            177312 Мотоциклетный спорт                                          176387 Спортивный туризм                                            153417 Бокс                                                         148654 Хоккей                                                       136849 Кикбоксинг                                                   136099 ... 

Так лучше. Теперь нарисуем график для топ-30:

table = data.groupby('section').participants.sum() table = table.sort(inplace=False, ascending=False) table.head(30).plot(kind='bar') 

Я не фанат супер-сурового инженерного дизайна, поэтому всегда импортирую Seaborn:

import seaborn  table = data.groupby('section').participants.sum() table = table.sort(inplace=False, ascending=False) table.head(30).plot(kind='bar') 

Идеально! Никакой другой функциональности Seaborn здесь использовано не будет. У меня чаще всего так и получается — Seaborn появляется только, чтобы графики стали красивыми. Это уже немало, но, вообще, библиотека умеет много чего другого.

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

table = data.groupby('start').size() table.plot() 

Почти готово. Нужно сделать детализацию, например, по неделям, а не по дням:

table = data.groupby('start').size() table = table.resample('M', how='sum') table.plot() 
  • Спортивная жизнь зимой наименее активна.
  • Тренд до последнего времени восходящий.
  • В 2010 был какой-то провал.

Было бы интереснее посмотреть на этот граф в разбивке по видам спорта. Для этого нужно сгруппировать данные по дате и виду спорта:

table = data.pivot_table(index='start', columns='section', values='participants', aggfunc=len) table.head() 

И нарисовать:

table.plot() 

Блестяще, ничего не понятно. Для начала уберём всё кроме топ-40 видов спорта, кстати, код для расчёта топа уже есть, заново не надо писать:

table = data.groupby('section').size() table = table.sort(inplace=False, ascending=False) order = table.head(40).index  table = data.pivot_table(index='start', columns='section', values='participants', aggfunc=len) table = table.reindex(columns=order) table.plot() 

Ладно, сделаем детализацию по неделям:

table = data.groupby('section').size() table = table.sort(inplace=False, ascending=False) order = table.head(40).index  table = data.pivot_table(index='start', columns='section', values='participants', aggfunc=len) table = table.reindex(columns=order) table = table.resample('M', how='sum') table.plot() 

Почти то, что надо, теперь расположим каждую линию на отдельном графике:

table = data.groupby('section').size() table = table.sort(inplace=False, ascending=False) order = table.head(40).index  table = data.pivot_table(index='start', columns='section', values='participants', aggfunc=len) table = table.reindex(columns=order) table = table.resample('M', how='sum') table.plot(subplots=True, layout=(8, 5), figsize=(20, 20)) 
  • Для некоторых видов наблюдаются тренды в числе мероприятий:
    • Сильно растёт спорт для инвалидов (лиц с поражением ОДА) и автомобильный спорт.
    • Слегка растёт мотоциклетный спорт, дзюдо, самбо, парусный спорт, волейбол, тхэквондо, бадминтон.
    • У футбола какой-интересный тренд.
    • Бокс перестал расти в 2012 году.
    • Надо отметить что падения числа мероприятий нигде не наблюдается.
  • Иногда есть периодичность в числе мероприятий, что не удивительно:
    • Парусный спорт, конные спорт, авиамодельный спорт, велоспорт замирают зимой.
    • Вообще зимой у многих видов затишье. Но бывает и наоборот, например, во фристайле.
    • Интересный рисунок у тенниса и лёгкой атлетики, который повторяется каждый год

Что мне нравится в этом подходе? Функция plot очень простая, у неё всего несколько важных аргументов: kind, subplots, figsize. Результат зависит в основном от структуры данных, для которых вызывается plot. То есть не нужно осваивать отдельно инструмент для рисования графиков. Нужно научиться преобразовывать данные. С Pandas это сделать не очень сложно. Достаточно выучить несколько «кирпичиков»: groupby, sort, head, pivot_table, reindex, resample, и применять их в разных комбинациях.

ссылка на оригинал статьи http://habrahabr.ru/post/266289/


Комментарии

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

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