Исследование данных с помощью Pandas и Seaborn

Шестаков А.В. Майнор по анализу данных - 19/01/2016

Модуль Pandas существенно упрощает работу с табличными данными в Python. Работа в нем во многом напоминает работу с таблицами в SQL с тем отличием, что в Pandas тебе не хочется рвать волосы на голове это делать гораздо проще, и в нем заложены некоторые дополнительные инструменты по работе с данными.

Как уже было оговорено на предыдущем семинаре, помимо стандартной библиотеки matplotlib, для "рисования" в Python можно использовать достойную альтернативу, чем сейчас и займемся.

In [ ]:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

plt.style.use('ggplot')

%matplotlib inline

Основные структуры

Основными структурами являются Series и DataFrame.
Series – это проиндексированный одномерный массив значений. Он похож на простой словарь типа dict, где имя элемента будет соответствовать индексу, а значение – значению записи.

In [ ]:
ser = pd.Series(np.random.rand(5), index=['a', 'b', 'c', 'd', 'e'])

В Pandas предусмотрены разные способы индексирования

In [ ]:
ser.index
In [ ]:
ser['a']
In [ ]:
ser[['a', 'b']]
In [ ]:
ser.loc['a']
In [ ]:
ser[0]
In [ ]:
# ser.iloc['a']
ser.iloc[0]
In [ ]:
idx = ser>0.5
ser[idx]
In [ ]:
# Автоматическое выравнивание по индексу
print ser + ser[1:]

DataFrame — это проиндексированный многомерный массив значений, соответственно каждый столбец DataFrame, является структурой Series. Индексирование в DataFrame ровно тоже, что и в Series, с тем отличием, что добавляется второе измерение.

In [ ]:
df = pd.DataFrame(np.random.randn(10, 3),
                  index=range(10),
                  columns=['A', 'B', 'C'])
In [ ]:
print df.index
print df.columns
In [ ]:
df[['A', 'B']]
In [ ]:
df.loc[1:3, ['A', 'B']]
In [ ]:
df.iloc[1:3, 0:2]
In [ ]:
df.ix[1:3, ['A', 'B']]
In [ ]:
idx = df>0
idx

Есть некоторые нюансы с форматом индексов, а так же нюансы, возникающие при присваивании значений в DataFrame. С ними вы встретитесь на практике. В общем RTFM!

Достаточно полезная команда, позволяющая "мельком" взглянуть на вашу таблицу с данными

In [ ]:
df.head()

Краткая описательная статистика

In [ ]:
df.describe()

Перевод данных в нужный тип

In [ ]:
df.dtypes
In [ ]:
df.A = df.A.astype(int)
df.head()
In [ ]:
df.dtypes

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

В DataFrame можно хранить данные разной природы

In [ ]:
df.loc[0, 'A'] = 'lalaley'
df.head()
In [ ]:
df.dtypes
In [ ]:
df.iloc[0:4, 0].values

Удаление\добавление строк

In [ ]:
df.drop(0)
In [ ]:
df.loc[0] = [1,2,3] 
In [ ]:
df

Продолжим обучение на реальных "данных"

В 1968 году была опубликована статья под интригующем названием Correlation of Performance Test Scores with Tissue Concentration of Lysergic Acid Diethylamide in Human Subjects.

К статье приложен небольшой набор данных, состоящий из 7 наблюдений

In [ ]:
data_types = {'Drugs': float,
              'Score': float}
df = pd.read_csv('drugs-and-math.csv', index_col=0, sep=',', dtype=data_types)
In [ ]:
print df.shape
print df.columns
print df.index
In [ ]:
df

Таблица уже отсортирована по колонке Drugs, сделаем сортировку по Score

In [ ]:
df.sort_values('Score', 
               ascending=False, 
               inplace=True)
In [ ]:
df.describe().T # Иногда так лучше

Рисунки

In [ ]:
df.plot(kind='box')
In [ ]:
df.plot(x='Drugs', y='Score', kind='bar')
In [ ]:
# df.plot(x='Drugs', y='Score')
df.plot(x='Drugs', y='Score', kind='scatter')

Мы явно видим тенденцию..

In [ ]:
df.corr(method='pearson')

Ну и напоследок графичек от seaborn!

In [ ]:
import seaborn as sns
In [ ]:
# sns.regplot(x='Drugs', y='Score', data=df)
sns.jointplot(x='Drugs', y='Score', 
              data=df, kind='reg')

Еще больше данных!

Давайте рассмотрим какой-нибудь большой датасет. Скачайте и распакуте следующий архив. Описание полей таблицы дано здесь.

Данные должны содержать перелеты между аэропортами США в 2008 году.

In [ ]:
df = pd.read_csv('2008.csv', parse_dates=4)
In [ ]:
print df.shape
print df.columns
In [ ]:
df.head().T
In [ ]:
df.describe().T
In [ ]:
# Посмотрим, сколько уникальных рейсов у нас представлено
df['FlightNum'].nunique()

Мы можем выполнять какую-нибудь группировку, что того, чтобы расчитывать различные аггрегированные статистики.

In [ ]:
# Например, найдите топ-3 рейсов, совершивших самые длинные перелеты за 2008 год?
df.groupby('FlightNum')['Distance']\
  .sum().sort_values(ascending=False)\
  .iloc[0:3]
In [ ]:
# Можно так:
df.groupby('FlightNum')\
  .agg({'Distance': [np.mean, np.sum, 'count'],
        'Cancelled': {'_total': np.sum}})\
  .sort_values(('Distance', 'sum'), ascending=False)\
  .iloc[0:3]

Еще полезная функция - построение сводной таблицы

In [ ]:
pd.crosstab(df.Month, df.DayOfWeek)
In [ ]:
# Иногда на такого рода таблицы проще смотреть так
plt.imshow(pd.crosstab(df.Month, df.DayOfWeek),
           cmap='seismic',interpolation='none')

Гистограммы!

In [ ]:
df.hist('Distance', bins=20)

Смотрим на даты!

In [ ]:
df['Date'] = pd.to_datetime(df.Year*10000 + df.Month*100 + df.DayofMonth, 
                            format='%Y%m%d')
In [ ]:
res = df.groupby('Date')['FlightNum'].agg('count')

Ничего не заметили?

In [ ]:
res.plot()
In [ ]:
pd.rolling_mean(res, 7).plot()

Задачи

  1. Рассчитать топ-10 массовых перевозчиков.
  2. Построить распределение причин отмены рейсов
  3. Найти самый популярный маршрут, выдать статистику по данному маршруту.
  4. Найти топ-5 рейсов по каждому из типов delay. Каким перевозчикам они принадлежат?
  5. Определить, как распределено количество рейсов от времени дня?
  6. Определить "сезонность" во временных рядах по количеству вылетов на каждый день.