Физтех.Статистика
Скачать 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.histplot
¶
У Seaborn есть одна специализированная функция для создания гистограмм: seaborn.histplot()
функция (для построения одномерных или двумерных гистограмм). Отличие sns.histplot
от hist
заключается в том, что в histplot по умолчанию количествово бинов подбирается лучше чем в hist от matplotlib.
seaborn.histplot(data, x, y, hue, stat, bins, binwidth, discrete, KDE, log_scale)
data
— это входные данные, предоставляемые в основном в виде фрейма данных или массива NumPy;x, y
— числовые переменные которые вы хотите построить. Другими словами, это переменные, на основе которых Seaborn создаст гистограмму;hue
— параметр позволяющий сопоставить категориальную переменную с цветом полос;stat
— (необязательно) указывает частоту, количество, плотность или вероятность;bin
— параметр позволяет управлять ячейками гистограммы (т.е. Количеством баров).;binwidth
— ширина каждой ячейки переопределяет ячейки, но может использоваться с binrange;discrete
— если значение True, по умолчанию установливается значение binwidth=1 и рисуются полосы так, чтобы они были центрированы по соответствующим точкам данных. Это позволяет избежать “пробелов”, которые в противном случае могут появиться при использовании дискретных (целочисленных) данных;KDE
— это один из механизмов, используемых для сглаживания графика гистограммы;color
— определяет цвет графика.
3.3 Функция 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');sns.histplot(x,
stat="density",
bins=20,
fill=False,
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/