Физтех.Статистика
Информация не актуальна. Сайт переехал на miptstats.github.io
Скачать ipynb
Python для анализа данных¶
Библиотека Seaborn¶
1. Введение¶
Seaborn — популярная библиотека готовых шаблонов для статистической визуализации, написанная на бэкенде matplotlib. Две основные причины не проходить мимо:
- Выразительный высокоуровневый интерфейс: построение большинства простых графиков происходит в одну строчку кода.
- Более эстетичные графики: часто встроенные в
seabornстили достаточно хороши и без вашего вмешательства.
Автор seaborn — Michael Waskom, PhD, сотрудник Center for Neural Research (Нью-Йорк), выпускник Стэнфорда. Разработка seaborn это его хобби, которое делает жизни тысяч людей чуть лучше.
Малоизвестный факт: библиотека названа в честь Сэмюела Нормана Сиборна (S.N.S. — именно поэтому import seaborn as sns), героя сериала The West Wing, "один из самых важных телесериалов в истории по версии журнала Times". Таким образом автор отдал дань уважения любимому сериалу. Доказательство можно найти среди issues в репозитории проекта.
import numpy as np
import pandas as pd
import scipy.stats as sps
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
Начнём с простого: рассмотрим отрисовку нескольких траекторий синусов при помощи matplotlib и улучшим её с помощью seaborn.
def sinplot(flip=1):
x = np.linspace(0, 14, 100)
for i in range(1, 7):
plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)
sinplot()
2. Основные параметры¶
2.1. Стили¶
Установка эстетических параметров графиков:
sns.set(context='notebook', style='darkgrid', palette='deep', font='sans-serif', font_scale=1, color_codes=False, rc=None)
context— параметры контекста, влияет на размер меток, линий и других элементов, но не на общий стиль. Контекст:notebook,paper,talk,poster;style— стиль осей:darkgrid(серый фон с сеткой),whitegrid(белый фон с сеткой),dark(серый фон без сетки),white(белый фон без сетки),ticks;palette— цветовая палитра:deep,muted,bright,pastel,dark,colorblind, а так же палитры изmatplotlib;font— шрифт текста;font_scale— масштабирование размера текста.
Посмотрим вид графиков для разных контекстов:
plt.figure(figsize=(15, 9))
for i, context in enumerate(['notebook', 'paper',
'talk', 'poster']):
sns.set(context=context) # Устанавливаем стиль
plt.subplot(2, 2, i+1)
sinplot()
plt.title(context)
Вид графиков в разных стилях
plt.figure(figsize=(15, 12))
for i, style in enumerate(['darkgrid', 'whitegrid',
'dark', 'white', 'ticks']):
sns.set(style=style) # Устанавливаем стиль
plt.subplot(3, 2, i+1)
sinplot()
plt.title(style)
В seaborn можно убрать рамку вокруг картинки, причём любую из четырёх сторон. В matplotlib это нетривиально.
sns.despine(fig=None, ax=None, top=True, right=True, left=False, bottom=False, offset=None, trim=False)
fig— фигураmatplotlib. ЕслиNone, то текущая;top,right,left,bottom— указатели границ. Левую и нижнюю оставляют, т.к. вдоль них расположены метки на координатных осях.
sns.set(style='white')
sinplot()
sns.despine()
Большой недостаток подхода выше — использование sns.set. Дело в том, что эта функция меняет глобальные переменные: все последующие графики отрисовываются в том же стиле. Иногда это уместно: можно один раз вызвать sns.set в самом начале ноутбука и получить стилизованные графики с минимумом усилий. Во всех остальных ситуациях нужно использовать контекстные менеджеры sns.plotting_context и sns.axes_style вместо sns.set.
sns.set()
with sns.plotting_context("notebook"), sns.axes_style("ticks"):
sinplot()
sns.despine()
sns.palplot(sns.color_palette('viridis', n_colors=10))
sns.palplot(sns.color_palette('magma', n_colors=10))
sns.palplot(sns.color_palette('inferno', n_colors=10))
Здесь стоит сделать отступление, т.к. именно с этим типом палитр люди сталкиваются чаще всего. Стандартные последовательные палитры в seaborn — viridis, inferno, magma и другие — хороши плавным изменением интенсивности цвета. Они не искажают восприятие и подходят в том числе для дальтоников. О том, как индустрия пришла к своим палитрам, можно узнать в видеолекции с SciPy 2015 — ежегодной всемирной конференции энтузиастов библиотеки scipy.
Расходящиеся (diverging)¶
sns.palplot(sns.color_palette('coolwarm', n_colors=10))
sns.palplot(sns.color_palette('rainbow', n_colors=10))
В прошлом большой популярностью пользовалась палитра jet, очень похожая на rainbow. Более того, долгое время это была палитра по умолчанию в matplotlib. Тем не менее, от jet отказались: выяснилось, что она искажает восприятие картинки из-за неравномерной интенсивности отдельных цветов палитры. Есть интересная статья, в которой подробно поясняются причины такого решения.
Забавный факт: даже если просто попытаться отрисовать её, seaborn скажет безапеляционное "Нет".
sns.palplot(sns.color_palette('jet', n_colors=10))
Категориальные (qualitative)¶
sns.palplot(sns.color_palette('muted', n_colors=10))
sns.palplot(sns.color_palette('Set2', n_colors=10))
Пользовательские¶
В seaborn можно сделать свою палитру: либо на основании имеющихся, либо совсем с нуля. Для примера, сделаем палитру из десяти оттенков оранжевого
sns.palplot(sns.dark_palette("xkcd:blood orange", n_colors=10))
Внимательный читатель обратит внимание на странный формат цвета. В 2010 году популярный онлайн-комикс xkcd провёл соцопрос, по результатам которого подобрал названия для 954 самых используемых RGB-цветов. Это упрощает жизнь огромному количеству людей, от дизайнеров до аналитиков и учёных.
Бонус: нарисуем радугу с помощью группы линий
count = 100
colors = sns.color_palette('rainbow', count)
layers = np.linspace(1, 2, count)
plt.figure(figsize=(8, 4))
plt.title("Радуга")
# Отрисовка по полуокружностям
for i in np.arange(count):
grid = np.linspace(-layers[i], layers[i], 100)
y = np.sqrt(layers[i]**2 - grid**2)
sns.lineplot(grid, y, c=colors[i])
plt.xticks([]);
plt.yticks([]);
sns.despine(left=True, bottom=True);
Больше о палитрах можно прочитать в официальной документации.
Теперь можно перейти и к более практичным примерам. Рассмотрим основные типы графиков, с которыми люди сталкиваются при анализе данных.
3. Оценки плотности¶
Пусть $X = (X_1, ..., X_n)$ — выборка из непрерывного распределения. Выберем
- $q(x)$ — некоторая "базовая" плотность, называемая ядром. Чаще всего в качестве ядра рассматривают плотность нормального распределения $\mathcal{N}(0, I_n)$.
- $h > 0$ — величина, отвечающая за масштабирование ядра, называемая шириной ядра.
Тогда ядерной оценкой плотности (kernel density estimation, KDE) по выборке $X$ называется плотность $$\widehat{p}_h(x) = \frac{1}{nh}\sum_{i=1}^n q\left(\frac{x-X_i}{h}\right).$$
Смысл: в каждую точку выборки поставили отмасштабированное ядро так, будто эта точка — центр ядра, а затем усреднили значения соседних точек с весами, заданными этим ядром. Вместо тысячи слов — интерактивная иллюстрация.
Ядерные оценки плотности — KDE, Kernel Density Estimates — способ что-то понять о распределении, когда неизвестно ничего. Такого рода методы называют непараметрическими, они иллюстрируют разницу подходов в статистике и теории вероятностей: если в теории вероятности известно распределение и исследуются его свойства, то в статистике зачастую известны только данные, и по их свойствам угадывается распределение.
3.1 Функция sns.kdeplot¶
Построение и отрисовка KDE (в 1D или 2D):
sns.kdeplot(data, data2=None, shade=False, vertical=False, kernel='gau', bw='scott', gridsize=100, cut=3, clip=None, legend=True, cumulative=False, shade_lowest=True, cbar=False, cbar_ax=None, cbar_kws=None, ax=None, **kwargs)
data— выборка;data2— вторая координата в двумерном случае;shade— закрашивать ли области. В 1D закрашивает область под графиком, в 2D закрашивает области между линиями уровня;vertical— повернуть график;kernel— метка ядра. В 1D доступныgau,cos,biw,epa,tri,triw; в 2D только гауссовское;bw— ширина ядра. Можно указатьscott,silvermanили число. В 2D можно указать пару чисел.gridsize— размер сетки для отрисовки графика. Влияет только на точность отрисовки, а не на точность оценки плотности;cut— задает границы отрисовки kde: график будет нарисован на величину cut * bw от крайних точек выборки;clip— нижняя и верхняя граница точек, по которым строится kde. Параметр имеет вид(low, high)в 1D и((low_x, high_x), (low_y, high_y))в 2D;legend— отрисовка легенды;cumulative— еслиTrue, то рисует функцию распределения, соответствующую построенной KDE;shade_lowest— нужно ли закрашивать последний контур для 2D. ФлагFalseможет быть полезен при отрисовке нескольких kde на одном графике;cbar— в 2D добавляет colorbar (шкала цветов);cbar_kws— аргументы, соответствующиеfig.colorbar;kwargs— другие аргументы, соответствующиеplt.plotилиplt.contour. Например,color— цвет,cmap— цветовая схема,n_levels— количество линий уровня.
3.2 Функция sns.distplot¶
Гибко настраиваемый график оценки одномерного распределения по выборке.
Совмещает возможности функций plt.hist, sns.kdeplot, sns.rugplot и функций fit из scipy.stats.
sns.distplot(a, bins=None, hist=True, kde=True, rug=False, fit=None, hist_kws=None, kde_kws=None, rug_kws=None, fit_kws=None, color=None, vertical=False, norm_hist=False, axlabel=None, label=None, ax=None)
a— выборка;bins— число бинов гистограммы. ЕслиNone, то выставляется по правилу Freedman-Diaconis;hist— рисовать ли гистограмму;kde— рисовать ли kde;rug— рисовать ли точки выборки в виде штрихов;hist_kws,kde_kws,rug_kws— параметры гистограммы, kde и rugplot в виде словарей;fit— семейство распредений. Объект должен иметь методfit, который вернет ОМП в видеtuple, и методpdf, который по сетке посчитает плотность распределения с параметрами, соответствующими ОПМ. Например, подойдет распределение изscipy.stats. Если параметр указан, что будет нарисована плотность, соответствующая ОМП в данном классе;color— цвет;vertical— повернуть график;norm_hist— нормировать ли гистограмму.
Пример distplot для всех четырех типов графиков для выборки из нормального распределения. В качестве параметрического семейства распределений использованы все нормальные распределения. Плотность, соответствующая ОМП, нарисована черным цветом.
x = sps.norm.rvs(size=100)
with sns.plotting_context(font_scale=1.5), sns.axes_style('whitegrid'):
plt.figure(figsize=(12, 7))
plt.title(r"Ядерная оценка плотности $\mathcal{N}(0, 1)$")
sns.distplot(x, rug=True, fit=sps.norm, color='red');
Многомерная оценка плотности
x, y = sps.multivariate_normal(cov=[[2, 1], [1, 2]]).rvs(size=1000).T
plt.figure(figsize=(12, 7))
plt.title(r"Ядерная оценка плотности $\mathcal{N}(\mathbf{0}, \mathbf{\Sigma})$")
sns.kdeplot(x, y, n_levels=15, shade=True, cmap="magma");
Ирисы Фишера¶
Теперь более интересный пример. Загрузим датасет Ирисы Фишера — классический учебный датасет, который встроен в seaborn. Числовые столбцы отвечают за длину и ширину наружной и внутренней доли околоцветника для трех сортов ириса: setosa, virginica, versicolor.
iris = sns.load_dataset('iris')
iris.head()
Выделим отдельные таблицы под каждый тип цветка
setosa = iris.loc[iris.species == 'setosa']
virginica = iris.loc[iris.species == 'virginica']
versicolor = iris.loc[iris.species == "versicolor"]
Построим для них ядерную оценку плотности
plt.figure(figsize=(12, 8))
with sns.axes_style("darkgrid"):
ax = sns.kdeplot(setosa.sepal_length, setosa.sepal_width,
label="setosa", cmap='Blues')
ax = sns.kdeplot(versicolor.sepal_length, versicolor.sepal_width,
label="versicolor", cmap='Greens')
ax = sns.kdeplot(virginica.sepal_length, virginica.sepal_width,
label="virginica", cmap='Reds')
ax.set_title("Ирисы Фишера");
ax.legend().get_frame().set_facecolor("white");
Обратите внимание на то, как отрисована легенда! Если не выставить цвет фона вручную, она будет серой, что неэстетично.
Грамотный исследовательский анализ данных — Exploratory Data Analysis, EDA — это залог правильного выбора модели машинного обучения. По графику видно, что два вида в этом признаковом пространстве разделяются прямой линией. Т.е. вид цветка можно определить по значениям признаков sepal_width и sepal_length.
Значит, для классификации цветков можно использовать т.н. обобщённо-линейные модели — а именно, т.н. логистическую регрессию. Что это такое и какие ещё есть подходы к задаче классификации вам расскажут на третьем курсе.
4. Box plot¶
Box plot — график, использующийся в описательной статистике, компактно изображающий одномерное распределение вероятностей.
Такой вид диаграммы в удобной форме показывает медиану (или, если нужно, среднее), нижний и верхний квартили, минимальное и максимальное значение выборки и выбросы. Несколько таких ящиков можно нарисовать бок о бок, чтобы визуально сравнивать одно распределение с другим; их можно располагать как горизонтально, так и вертикально. Расстояния между различными частями ящика позволяют определить степень разброса (дисперсии) и асимметрии данных и выявить выбросы.
seaborn.boxplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, orient=None, color=None, palette=None, saturation=0.75, width=0.8, dodge=True, fliersize=5, linewidth=None, whis=1.5, notch=False, ax=None, **kwargs)
x,y,hue— одномерные данные или имена переменных изdata. Параметрhueотвечает за категории данных;data— данные;orient:"v"|"h"— ориентация (вертикальная или горизонтальая);colorиpalette— задают цвет.
Простой пример:
data = sps.norm.rvs(size=(1000, 6)) + np.arange(6) / 2
plt.figure(figsize=(8, 7))
sns.boxplot(data=data, palette='Set2');
Загрузим датасет tips, который встроен в seaborn. Изначально датасет составлен официантом, который записывал информацию о каждых чаевых, который он получал в течение нескольких месяцев работы в ресторане. Имена переменных:
total_bill— общая сумма счета;tip— сумма чаевых;sex— пол клиента;smoker— курящий ли клиент;day— день недели (официант работал не все дни);time— время дня;size— количество людей в компании клиента.
tips = sns.load_dataset('tips')
tips.head()
С помощью box plot визуализируем зависимость общей суммы счета от дня недели.
plt.figure(figsize=(15, 6))
plt.subplot(121)
sns.boxplot(x='day', y='total_bill', data=tips, palette='Set3')
plt.ylabel('Сумма счета')
plt.subplot(122)
sns.boxplot(x='day', y='tip', data=tips, palette='Set3')
plt.ylabel('Размер чаевых');
Посмотрим на ту же зависимость отдельно по двум группам, определяемых столбцом smoker, который передадим в аргумент hue. Для удобства сравнения результата между группами, их ящики рисуются рядом.
plt.figure(figsize=(15, 6))
plt.subplot(121)
ax = sns.boxplot(x='day', y='total_bill', hue='smoker',
data=tips, palette='Set3')
ax.legend().get_frame().set_facecolor("white")
plt.ylabel('Сумма счета')
plt.subplot(122)
ax = sns.boxplot(x='day', y='tip', hue='smoker',
data=tips, palette='Set3')
ax.legend().get_frame().set_facecolor("white")
plt.ylabel('Размер чаевых');
Теперь посмотрим на зависимость от пола
plt.figure(figsize=(15, 6))
plt.subplot(121)
ax = sns.boxplot(x='day', y='total_bill', hue='sex',
data=tips, palette='Set3')
ax.legend().get_frame().set_facecolor("white")
plt.ylabel('Сумма счета')
plt.subplot(122)
ax = sns.boxplot(x='day', y='tip', hue='sex',
data=tips, palette='Set3')
ax.legend().get_frame().set_facecolor("white")
plt.ylabel('Размер чаевых');
Отступление¶
Сравните два графика. Какой выглядит лучше?
data = sps.norm.rvs(size=(20, 6)) + np.arange(6) / 2
plt.figure(figsize=(15, 7))
with sns.plotting_context(font_scale=1.5), sns.axes_style("darkgrid"):
plt.subplot(121)
sns.boxplot(data=data, palette='Set2')
with sns.plotting_context(font_scale=1.5), sns.axes_style("whitegrid"):
plt.subplot(122)
sns.boxplot(data=data, palette='Set2');
А из этих? В предположении, что необходима сетка, которая помогает при необходимости извлечения количественной информации из графика.
data = sps.norm.rvs(size=(20, 6)) + np.arange(6) / 2
plt.figure(figsize=(15, 5))
with sns.plotting_context(font_scale=1.5), sns.axes_style("darkgrid"):
plt.subplot(121)
sinplot()
with sns.plotting_context(font_scale=1.5), sns.axes_style("whitegrid"):
plt.subplot(122)
sinplot()
- Тему
darkgridстоит применять для "легких" графиков (точки, линии), поскольку белый цвет сетки на сером фоне помогает избежать конфликта сетки с линиями, представляющими данные. - Темы
whiteиwhitegridпохожи, но лучше подходят для графиков с "тяжелыми элементами" (например, закрашенные области).
5. Violin plot¶
Некоторая комбинация boxplot и ядерной оценки плотности. Внутри облака изображен обычный ящик с усами, только в сжатом виде и без выбросов. Форма облака соответствует ядерной оценке плотности.
sns.violinplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, bw='scott', cut=2, scale='area', scale_hue=True, gridsize=100, width=0.8, inner='box', split=False, dodge=True, orient=None, linewidth=None, color=None, palette=None, saturation=0.75, ax=None, **kwargs)
x,y,hue— одномерные данные или имена переменных изdata;data— данные;bw— ширина ядра;gridsize— размер сетки для отрисовки ядерной оценки плотности;orient:"v"|"h"— ориентация (вертикальная или горизонтальая);colorиpalette— задают цвет.
Простой пример
data = sps.norm.rvs(size=(20, 6)) + np.arange(6) / 2
plt.figure(figsize=(8, 7))
sns.violinplot(data=data, palette='Set2', bw=.2, cut=1, linewidth=1);
Более сложный пример: вместо двух boxplot-ов в примере с чаевыми можно постоить один сдвоенный violinplot
with sns.plotting_context("notebook", font_scale=1.5):
plt.figure(figsize=(8, 7))
sns.violinplot(x="day", y="tip", hue="smoker",
data=tips, palette="Set2", split=True);
plt.ylabel('Размер чаевых');
plt.xlabel('День недели');
6. PairGrid¶
Сетка графиков для визуализации попарных отношений в данных.
class sns.PairGrid(data, hue=None, hue_order=None, palette=None, hue_kws=None, vars=None, x_vars=None, y_vars=None, diag_sharey=True, size=2.5, aspect=1, despine=True, dropna=True)
data— данные;hue— категории, которые будут закрашиваться в разные цвета;palette— цветовая схема, может быть задана в виде словаря цветов;height— высота каждой грани (в дюймах).
Возвращает объект, у которого доступны перечисленные ниже функции. В эти функции нужно передать функцию func, с помощью которой будет построен график по паре переменных (или по одной на диагонали), а так же параметры этой функции.
map(func, **kwargs)— для каждой клетки применитьfunc;map_diag(func, **kwargs)— для каждой клетки на диагонали применитьfunc;map_offdiag(func, **kwargs)— для каждой клетки вне диагонали применитьfunc;map_lower(func, **kwargs)— для каждой клетки под диагональю применитьfunc;map_upper(func, **kwargs)— для каждой клетки над диагональю применитьfunc.
Визуализируем данные об ирисах Фишера.
- на диагонали расположим одномерные ядерные оценки плотности;
- под диагональю — двумерные;
- над диагональю изобразим сами точки.
sns.set(style='white', font_scale=1.3)
df = sns.load_dataset('iris')
g = sns.PairGrid(df, diag_sharey=False)
g.map_lower(sns.kdeplot, cmap='Blues_d')
g.map_upper(plt.scatter, alpha=0.5)
g.map_diag(sns.kdeplot, lw=3);
Зададим классы с помощью параметра hue
g = sns.PairGrid(df, hue='species', height=4)
g.map_lower(sns.kdeplot, cmap='Blues_d')
g.map_upper(plt.scatter)
g.map_diag(sns.kdeplot, lw=3);
7. Heatmap¶
Визуализирует двумерную таблицу в виде тепловой карты.
sns.heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False, annot=None, fmt='.2g', annot_kws=None, linewidths=0, linecolor='white', cbar=True, cbar_kws=None, cbar_ax=None, square=False, xticklabels='auto', yticklabels='auto', mask=None, ax=None, **kwargs)
data— 2D-данные;vminиvmax— минимальное и максимальное значения цветов;cmap— цветовая схема;robust— если не указаныvminиvmax, то не используются выбросы при определении минимума и максимума;annot— в какие ячейки записывать данные;fmt— формат записи данных;linewidths— ширина линий между ячейками;linecolor— цвет линий между ячейками;cbar— рисовать ли colorbar.
Типичное применение — визуализация корреляции между признаками.
Для примера загрузим данные о количестве пассажиров самолетов за каждый месяц с 1949 по 1960 года.
flights_long = sns.load_dataset('flights')
flights_long.head()
Двумерную таблицу меяц-год создадим с помощью pivot_table. Подробнее об этом можно будет посмотреть скоро во второй части материалов по Pandas.
flights = flights_long.pivot_table(index='month',
columns='year',
values='passengers')
flights
Визуализируем ее с помощью heatmap, что более наглядно, чем просто смотреть на числа в таблице выше.
sns.set(font_scale=1.3)
f, ax = plt.subplots(figsize=(12, 7))
sns.heatmap(flights, annot=True, fmt='d', ax=ax, cmap="viridis")
plt.ylim((0, 12));
Замечание: sns.heatmap не умеет обрабатывать пропуски в данных! Если передать матрицу с пропусками, функция выкинет TypeError
sns.heatmap(np.array([1., np.nan], [3., 4.]))
8. Clustermap¶
Аналог sns.heatmap, который автоматически группирует похожие строки и/или столбцы таблицы. Бывает очень полезно в тех случаях, когда нужно найти структуру в данных — скажем, разбить объекты на группы.
Пример из медицинской практики — разделить клетки опухоли на клональные линии — клетки, получившиеся неконтролируемым делением одной родительской раковой клетки — на основании таблицы генетических мутаций, где каждой клетке — свой столбец.
seaborn.clustermap(data, pivot_kws=None, method='average', metric='euclidean', z_score=None, standard_scale=None, figsize=(10, 10), cbar_kws=None, row_cluster=True, col_cluster=True, row_linkage=None, col_linkage=None, row_colors=None, col_colors=None, mask=None, dendrogram_ratio=0.2, colors_ratio=0.03, cbar_pos=(0.02, 0.8, 0.05, 0.18), tree_kws=None, **kwargs)
У функции очень много технических параметров, так что рассмотрим только основные из тех, которых нет среди параметров heatmap:
data— 2D-данные;row_cluster,col_cluster— группировать ли строки или столбцы соотв-но;row_colors,col_colors— цветовые метки отдельных строк и столбцов (позволяет следить за их порядком);method— метод группировки (см. документацию к иерархической кластеризации в scipy);mask— позволяет указать, какие значения в таблице не показывать (по умолчанию скрываются только пропуски);z_score— привести ли все строки (если 0) или столбцы (если 1) к одному масштабу ((x - mean(x)) / std(x));standard_scale— перевести ли все строки (если 0) или столбцы (если 1) в диапазон [0, 1] ((x - min(x)) / (max(x) - min(x)));
Для примера загрузим встроенный в seaborn датасет brain_networks, любезно предоставленный автором библиотеки. В примере похожие участки мозга объединяются в группы по корреляции профилей их активности
data = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)
# выберем подмножество отделов мозга
used_networks = [1, 5, 6, 7, 8, 12, 13, 17]
used_columns = (data.columns.get_level_values("network")
.astype(int)
.isin(used_networks))
data = data.loc[:, used_columns]
# создадим для них категориальную палитру
network_pal = sns.husl_palette(len(used_networks), s=.45)
network_lut = dict(zip(map(str, used_networks), network_pal))
# окрасим строки и столбцы в соответствии с отделом
networks = data.columns.get_level_values("network")
network_colors = pd.Series(networks, index=data.columns).map(network_lut)
# нарисуем график корреляции паттернов активности участков мозга
# и убедимся, что участки из одного отдела попадают в одну группу
# после иерархической кластеризации
sns.clustermap(data.corr(), center=0, cmap="vlag",
row_colors=network_colors, col_colors=network_colors,
linewidths=.75, figsize=(13, 13));
9. Jointplot¶
График двух переменных, соеднияющий функции 1D и 2D графиков.
sns.jointplot(x, y, data=None, kind='scatter', stat_func=<function pearsonr>, color=None, size=6, ratio=5, space=0.2, dropna=True, xlim=None, ylim=None, joint_kws=None, marginal_kws=None, annot_kws=None, **kwargs)
x,y— данные или имена переменных вdata;data— данные;kind: {"scatter"|"reg"|"resid"|"kde"|"hex"} — тип графика (точки, регрессия, остатки регрессии, ядерная оценка плотности, гексаэдры);stat_func— функция-критерий, который возвращает статистику и pvalue. По умолчанию критерий для проверки некоррелированности на основе коэффициента корреляции Пирсона;color— цвет;height— размер фигуры;dropna— удаление пропущенных значений;xlim,ylim— ограничения по осям.
Сгенерируем выборку из двумерного нормального распределения
x, y = sps.multivariate_normal(cov=[[2, 1], [1, 2]]).rvs(size=200).T
Визуализируем двумерную оценку плотности и две одномерных
with sns.plotting_context("notebook", font_scale=1.5), sns.axes_style("white"):
sns.jointplot(x, y, kind='kde', height=7, space=0);
Если не указать тип визуализации, то будут нарисованы точки и гистограммы
sns.jointplot(x, y, height=7, space=0);
Отметим, что sns.jointplot можно конфигурировать вручную! У объекта JointGrid, который эта функция возвращает, можно настраивать все три части графика:
ax_marg_x— верхний график;ax_marg_y— правый график;ax_joint— центральный график;
На них можно отрисовать что угодно, в том числе вещи, совершенно не связанные с исходными данными. Но если хочется построить другой график на тех же данных, то на выручку приходят функции plot_joint и plot_marginals
with sns.plotting_context("notebook"), sns.axes_style("darkgrid"):
# центральный график
graph = sns.jointplot(x, y, color="xkcd:dark sea green")
# верний график
graph.ax_marg_x.clear()
sns.kdeplot(x, shade=True, color="xkcd:azure", ax=graph.ax_marg_x)
# правый график
graph.ax_marg_y.clear()
sns.distplot(y, vertical=True, kde=False,
color="xkcd:orange", ax=graph.ax_marg_y);
Бонус¶
with sns.axes_style("ticks"):
plt.figure(figsize=(7, 7))
plt.imshow(plt.imread('./pic.png'))
sns.despine();
Больше примеров https://seaborn.pydata.org/examples/ и https://python-graph-gallery.com/