Продолжаем тему с визуализацией данных. В прошлый раз мы рассказали про 5 популярных способов представить большой объём информации на графиках, а сегодня — новое и иногда не такое очевидное. Расчехляйте Python и доставайте файлы с данными.
Как установить Python на компьютер и начать на нём писать
Что понадобится
Кроме Python нам нужны датасеты, на которых можно тренироваться визуализировать разное. Можно подключать прямо так, но на всякий случай сохраните копии — мало ли что.
https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv — данные об автомобилях, их базовых характеристиках и производителях.
https://github.com/selva86/datasets/raw/master/AirPassengers.csv — данные о количестве пассажиров, которые летали самолётами в 1949—1960 годах.
https://raw.githubusercontent.com/selva86/datasets/master/economics.csv — данные об экономической ситуации в США в 1967—2015 годах.
На всякий случай повторим, как мы это делали в первой части.
Перед тем как заниматься графикой, сделаем общие настройки визуализации:
- подключим библиотеки для работы с данными и с графикой;
- укажем нужные параметры отображения;
- выберем стиль оформления графиков.
Это будут общие настройки для каждого типа визуализации. Это значит, что в скрипт сначала нужно закинуть этот код, а следом за ним — код для конкретного графика. Если компьютер будет ругаться, что у него нет какой-то библиотеки, например pandas, установите их командой
pip install имя_библиотеки
# подключаем библиотеки для работы с данными и графикой
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
# переменные для настройки графиков
large = 22; med = 16; small = 12
# параметры графиков
params = {'axes.titlesize': large,
'legend.fontsize': med,
'figure.figsize': (16, 10),
'axes.labelsize': med,
'axes.titlesize': med,
'xtick.labelsize': med,
'ytick.labelsize': med,
'figure.titlesize': large}
# обновляем параметры
plt.rcParams.update(params)
# выбираем стили оформления
plt.style.use('seaborn-whitegrid')
sns.set_style("white")
График плотности
Этот график используется, когда нужно визуализировать то, как распределяются значения переменных. Если их сгруппировать по одному параметру, можно проверить взаимосвязь между ним и другим параметром. Например, вот как меняется среднее количество пробега миль на галлон в зависимости от количества цилиндров в машине.
В отличие от европейского и российского способа расчёта расхода топлива литров на 100 километров, в Америке используется другая система — мили на галлон. Она показывает, сколько миль может проехать машина на одном галлоне топлива.
# берём исходные данные из файла
df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")
# готовим график
plt.figure(figsize=(16,10), dpi= 80)
# группируем по количеству цилиндров
sns.kdeplot(df.loc[df['cyl'] == 4, "cty"], shade=True, color="g", label="Cyl=4", alpha=.7)
sns.kdeplot(df.loc[df['cyl'] == 5, "cty"], shade=True, color="deeppink", label="Cyl=5", alpha=.7)
sns.kdeplot(df.loc[df['cyl'] == 6, "cty"], shade=True, color="dodgerblue", label="Cyl=6", alpha=.7)
sns.kdeplot(df.loc[df['cyl'] == 8, "cty"], shade=True, color="orange", label="Cyl=8", alpha=.7)
# добавляем общую надпись
plt.title('Распределение пробега на одном галлоне в зависимости от количества цилиндров', fontsize=22)
# подписываем оси
plt.gca().set(xlabel='Плотность распределения', ylabel='Миль на галлон')
# добавляем легенду
plt.legend()
# выводим график
plt.show()
Joy-график или карта распределения
Joy-график показывает плотности распределения разных групп данных. Особенность графика в том, что значения одних данных могут перекрывать визуально другие, но это не мешает видеть всю картину в целом.
Для работы с этим графиком нужно установить библиотеку joypy:
pip install joypy
позволяет перекрывать кривые плотности разных групп, это отличный способ визуализировать распределение большого числа групп по отношению друг к другу. Это выглядит приятным для глаз и чётко передаёт только правильную информацию.
# берём исходные данные из файла
mpg = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")
# подключаем библиотеку для графика
import joypy
# группируем данные по запасу хода на галлон на трассе и в городе
fig, axes = joypy.joyplot(mpg, column=['hwy', 'cty'], by="class", ylim='own')
# добавляем надпись
plt.title('Пробег в милях на галлон в городе и на трассе в зависимости от типа автомобиля', fontsize=22)
# выводим график
plt.show()
Гистограмма для категорий
Гистограмма категориальной переменной показывает, как распределяется частота этой переменной. Если раскрасить категории в разные цвета, можно увидеть, как они распределяются по разным переменным в зависимости от их значения.
С помощью гистограмм для категорий можно посмотреть, например, как разные производители автомобилей выпускают определённые типы машин:
# берём исходные данные из файла
df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")
# указываем данные, с которыми будем работать
x_var = 'manufacturer'
groupby_var = 'class'
# готовим данные
df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)
vals = [df[x_var].values.tolist() for i, df in df_agg]
# формируем цвета и категории
colors = [plt.cm.Spectral(i/float(len(vals)-1)) for i in range(len(vals))]
n, bins, patches = plt.hist(vals, df[x_var].unique().__len__(), stacked=True, density=False, color=colors[:len(vals)])
# добавляем легенду
plt.legend({group:col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})
# и общую надпись
plt.title(f"Гистограмма с категориями по классам машин для разных производителей", fontsize=22)
# подписываем оси
plt.xlabel('Производитель')
plt.ylabel("Частота")
plt.ylim(0, 40)
# выводим график
plt.show()
Временные ряды с пиками и впадинами
Такой способ отображения данных показывает все пики и впадины, а также отмечает отдельно значимые события, которые выбиваются из соседних значений. С помощью такого графика можно наглядно проследить, как менялся в течение сезона пассажиропоток в авиации: явный рост пассажиров в марте и июле и сильный спад зимой.
# берём исходные данные из файла
df = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')
# получаем пики
data = df['value'].values
doublediff = np.diff(np.sign(np.diff(data)))
peak_locations = np.where(doublediff == -2)[0] + 1
# и падения
doublediff2 = np.diff(np.sign(np.diff(-1*data)))
trough_locations = np.where(doublediff2 == -2)[0] + 1
# готовим график
plt.plot('date', 'value', data=df, color='tab:blue', label='Количество пассажиров')
# добавляем указатели на пики и провалы
plt.scatter(df.date[peak_locations], df.value[peak_locations], marker=mpl.markers.CARETUPBASE, color='tab:green', s=100, label='Пики')
plt.scatter(df.date[trough_locations], df.value[trough_locations], marker=mpl.markers.CARETDOWNBASE, color='tab:red', s=100, label='Просадки')
# подписываем указатели
for t, p in zip(trough_locations[1::5], peak_locations[::3]):
plt.text(df.date[p], df.value[p]+15, df.date[p], horizontalalignment='center', color='darkgreen')
plt.text(df.date[t], df.value[t]-35, df.date[t], horizontalalignment='center', color='darkred')
# формируем разбивку по годам
plt.ylim(50,750)
xtick_location = df.index.tolist()[::6]
xtick_labels = df.date.tolist()[::6]
plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=90, fontsize=12, alpha=.7)
# добавляем общую надпись
plt.title("Пики и просадки в авиапассажиропотоке в 1949—1960 годах)", fontsize=22)
plt.yticks(fontsize=12, alpha=.7)
# настраиваем внешний вид границ графика
plt.gca().spines["top"].set_alpha(.0)
plt.gca().spines["bottom"].set_alpha(.3)
plt.gca().spines["right"].set_alpha(.0)
plt.gca().spines["left"].set_alpha(.3)
# добавляем легенду
plt.legend(loc='upper left')
plt.grid(axis='y', alpha=.3)
# выводим график
plt.show()
Диаграмма площади
Эта диаграмма показывает, как ведут себя два ряда данных друг относительно друга. Особенность диаграммы в том, что на ней явно видно пересечение закрашенных графиков, что позволяет оценить влияние одной переменной на другую.
Например, можно построить диаграмму, которая покажет зависимость среднего уровня сбережений (какой процент от дохода человек откладывает в копилку) от длительности безработицы. На графиках видно, что чем дольше длится безработица, тем меньший процент сбережений откладывается про запас.
# берём исходные данные из файла
df = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv")
# готовим данные
x = df['date'].values.tolist()
# формируем сведения по сбережениям и безработице
y1 = df['psavert'].values.tolist()
y2 = df['uempmed'].values.tolist()
# цвета
mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']
# категории
columns = ['Уровень сбережений', 'Длительность безработицы']
# готовим изображение
fig, ax = plt.subplots(1, 1, figsize=(16,9), dpi= 80)
# добавляем графики сбережений и безработицы
ax.fill_between(x, y1=y1, y2=0, label=columns[0], alpha=0.5, color=mycolors[1], linewidth=2)
ax.fill_between(x, y1=y2, y2=0, label=columns[1], alpha=0.5, color=mycolors[0], linewidth=2)
# добавляем общую подпись
ax.set_title('Влияние длительности безработицы на уровень сбережений', fontsize=18)
ax.set(ylim=[0, 30])
ax.legend(loc='best', fontsize=12)
# добавляем числа на оси
plt.xticks(x[::50], fontsize=10, horizontalalignment='center')
plt.yticks(np.arange(2.5, 30.0, 2.5), fontsize=10)
plt.xlim(-10, x[-1])
# рисуем горизонтальные линии
for y in np.arange(2.5, 30.0, 2.5):
plt.hlines(y, xmin=0, xmax=len(x), colors='black', alpha=0.3, linestyles="--", lw=0.5)
# настраиваем внешний вид границ графика
plt.gca().spines["top"].set_alpha(0)
plt.gca().spines["bottom"].set_alpha(.3)
plt.gca().spines["right"].set_alpha(0)
plt.gca().spines["left"].set_alpha(.3)
# выводим график
plt.show()