{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Графическая визуализация данных\n",
"\n",
" \n",
"**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
"\n",
"Date: **Mar 31, 2020**\n",
"\n",
"Одной из важных частей в анализе данных является графическое\n",
"визуализация. Это может быть частью исследовательского процесса —\n",
"например, чтобы помочь идентифицировать выбросы или необходимые\n",
"преобразования данных, или как способ генерирования идей для\n",
"моделей. В Python есть много дополнительных библиотек для создания\n",
"статических или динамических визуализаций, но мы сосредоточемся в\n",
"основном на `matplotlib` и библиотеках, которые построены на её\n",
"основе. \n",
"\n",
"Со временем `matplotlib` породила ряд дополнительных наборов инструментов\n",
"для визуализации данных, которые используют `matplotlib` в качестве\n",
"«ядра». Одним из таких инструментов является `seaborn`.\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Краткий пример использования `matplotlib`\n",
"
\n",
"\n",
"Для импорта библиотеки `matplotlib` будем использовать следующее\n",
"соглашение:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ниже приведен пример построения простой прямой:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"data = np.arange(10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"plt.plot(data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Рисунки и подграфики\n",
"\n",
"\n",
"Графики в `matplotlib` находятся внутри объекта `Figure`. Новый\n",
"рисунок можно создать с помощью `plt.figure`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"В интерпретаторе IPython будет построено пустое окно, а в блокноте\n",
"Jupyter ничего не произойдет. Нельзя создавать окно с пустым\n",
"рисунком. Нужно создать один или несколько подграфиков (subplots),\n",
"используя функцию `add_subplot`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig.add_subplot(2, 2, 1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Это означает, что рисунок должен быть размером $2 \\times 2$\n",
"(т.е. содержать максимум 4 графика), и мы выбрали первый из четырех\n",
"графиков (нумерация начинается с единицы). Можно выбрать следующие 2\n",
"графика:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"ax2 = fig.add_subplot(2, 2, 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"ax3 = fig.add_subplot(2, 2, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Если выполнить команду построения графика, например, `plt.plot([1.5, 3.5, -2, 1.6])`,\n",
"вывод будет осуществляться в последний график последнего созданного\n",
"рисунка. Например, выполнение команды"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"plt.plot(np.random.randn(50).cumsum(), 'k--')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выражение `'k--'` задает стиль линии: черная штриховая линия. \n",
"Метод `fig.add_subplot` возвращает объект `AxesSubplot`, в который\n",
"можно напрямую выводить график:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"_ = ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Полный каталог типов графиков можно найти на сайте .\n",
"\n",
"Как вы заметили представленные выше команды, выполняемые в отдельных\n",
"ячейках, в блокноте Jupyter не работают. Для того чтобы строить\n",
"подграфики в Jupyter нужно все команды выполнять в одной ячейке:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure()\n",
"fig.add_subplot(2, 2, 1)\n",
"ax1 = fig.add_subplot(2, 2, 2)\n",
"ax2 = fig.add_subplot(2, 2, 3)\n",
"plt.plot([1.5, 3.5, -2, 1.6])\n",
"_ = ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)\n",
"ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Цвет, маркеры и стили линий\n",
"\n",
"\n",
"Основная функция `plot` библиотеки `matplotlib` принимает массивы\n",
"координат `x` и `y` и (опционально) строку, задающую цвет и стиль\n",
"линии. Например, для того чтобы построить зависимость `y` от `x`\n",
"зелеными штрихами, необходимо выполнить:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" ax.plot(x, y, 'g--')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Таким образом, мы задали и цвет и стиль линии в виде строки. На\n",
"практике при программном создании графиков использование строк не\n",
"удобно. Такой же график можно построить с помощью команды:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" ax.plot(x, y, linestyle='--', color='g')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Графики могут иметь также маркеры для выделения точек данных. Так как\n",
"`matplotlib` создает непрерывные линии, интерполируя значения между\n",
"заданными точками, может быть не ясно, где находятся заданные\n",
"значения. Маркеры могут быть частью строки, задающей стиль линии:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from numpy.random import randn"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"plt.plot(randn(30).cumsum(), 'ko--')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Это же можно было записать более явно:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" plot(randn(30).cumsum(), color='k', linestyle='dashed', marker='o')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Как видно, между последовательными точками строится линейная\n",
"интерполяция. Это поведение можно изменить с помощью параметра\n",
"`drawstyle`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"data = np.random.randn(30).cumsum()\n",
"plt.plot(data, 'k--', label='Default')\n",
"plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post')\n",
"plt.legend(loc='best')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Подписи к осям, масштаб и легенда\n",
"\n",
"\n",
"Для иллюстрации настройки графиков создадим простой рисунок и\n",
"отобразим график случайного блуждания:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure()\n",
"ax = fig.add_subplot(1, 1, 1)\n",
"ax.plot(np.random.randn(1000).cumsum())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Для изменения подписей на оси $x$ воспользуемся методами `set_xticks`\n",
"и `set_xticklables`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure()\n",
"ax = fig.add_subplot(1, 1, 1)\n",
"ax.plot(np.random.randn(1000).cumsum())\n",
"ticks = ax.set_xticks([0, 250, 500, 750, 1000])\n",
"labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Параметр `rotation` поворачивает метки надписей на оси $x$ на 30\n",
"градусов. И, наконец, зададим название графика и метку для оси $x$ с\n",
"помощью методов `set_title` и `set_xlabel`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure()\n",
"ax = fig.add_subplot(1, 1, 1)\n",
"ax.plot(np.random.randn(1000).cumsum())\n",
"ticks = ax.set_xticks([0, 250, 500, 750, 1000])\n",
"labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')\n",
"ax.set_title('Первый график matplotlib')\n",
"ax.set_xlabel('Шаги')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Модификация оси $y$ осуществляется точно также, только нужно заменить\n",
"`x` на `y` в приведенном выше коде. У класса осей есть метод `set`,\n",
"который допускает пакетную настройку свойств графика. В предыдущем \n",
"примере можно было также написать:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" props = {\n",
" 'title': 'Первый график matplotlib',\n",
" 'xlabel': 'Шаги\n",
" }\n",
" ax.set(**props)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Для вывода легенды графика есть несколько способов. Простейший\n",
"заключается в передаче аргумента `label` при построении графиков:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = plt.figure(); ax = fig.add_subplot(1, 1, 1)\n",
"ax.plot(randn(1000).cumsum(), 'k', label='one')\n",
"ax.plot(randn(1000).cumsum(), 'k--', label='two')\n",
"ax.plot(randn(1000).cumsum(), 'k.', label='three')\n",
"ax.legend(loc='best')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Сохранение рисунков в файл\n",
"\n",
"\n",
"Можно сохранить активный рисунок в файл с помощью метода\n",
"`plt.savefig`. Например, чтобы сохранить рисунок в формате SVG\n",
"достаточно набрать:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" plt.savefig('figpath.svg')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Тип файла определяется расширением. Есть пара важных параметров:\n",
"`dpi`, который задает разрешение рисунка (точек на дюйм),\n",
"`bbox_inches`, который может обрезать пустое пространство вокруг\n",
"рисунка. Например, чтобы сохранить тот же график в формате PNG с\n",
"разрешением 400 DPI, нудно выполнить:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" plt.savefig('figpath.png', dpi=400, bbox_inches='tight')\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Функция `savefig` сохраняет не только на диск. Она может записывать\n",
"график в любой файлоподобный объект, например в `BytesIO`:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```Python\n",
" from io import BytesIO\n",
" buffer = BytesIO()\n",
" plt.savefig(buffer)\n",
" plot_data = buffer.getvalue()\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Таблица 1 : Метод `savefig`: параметры\n",
"\n",
"\n",
"\n",
"\n",
"| Параметр | Описание |
\n",
"\n",
"\n",
" fname | Строка, содержащая путь к файлу или файлоподобный объект Python. Формат рисунка определяется расширением файла |
\n",
" dpi | Разрешение рисунка в точках на дюйм. По умолчанию 100 |
\n",
" facecolor, edgecolor | Цвет фона рисунка вне графика. По умолчанию w (белый) |
\n",
" format | Явное задание формата файла |
\n",
" bbox_inches | Часть рисунка для сохранения. Если задано 'tight', 2будет попытка обрезать пустое пространство вокруг |
\n",
"\n",
"
\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Построение графиков с помощью `pandas` и `seaborn`\n",
"\n",
"\n",
"Библиотека `matplotlib` может быть инструментом довольно низкого\n",
"уровня. График собирается из его базовых компонентов: отображения\n",
"данных (т.е. тип графика: линия, полоса, прямоугольник, разброс,\n",
"контур и т.д.), легенды, заголовка, меток и других аннотаций. В\n",
"библиотеке `pandas` мы можем получить множество столбцов данных, а\n",
"также метки строк и столбцов. В `pandas` имеются встроенные методы,\n",
"которые упрощают визуализацию объектов `DataFrame` и `Series`. Еще\n",
"одна библиотека для статистических графиков — `seaborn`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Линейные графики\n",
"\n",
"\n",
"Объекты `Series` и `DataFrame` имеют метод `plot` для создания базовых\n",
"типов графиков. По умолчанию `plot()` создает линейные графики"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"s = pd.Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10))\n",
"s.plot()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Индекс объекта `Series` передается в `plot` библиотеки `matplotlib`\n",
"для оси $x$. При этом такое поведение можно отключить с помощью\n",
"параметра `use_index = False`. В таблице\n",
"[visual:plt-with-pandas:tbl:1](#visual:plt-with-pandas:tbl:1) дается полный список\n",
"параметров функции `Series.plot`.\n",
"\n",
"Большинство графических методов `pandas` принимают опциональный\n",
"параметр `ax`, который может являться объектом `subplot`. Это\n",
"позволяет размещать подграфики на сетке.\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Таблица 2 : Параметры метода `Series.plot` \n",
"\n",
"\n",
"\n",
"\n",
"| Параметр | Описани |
\n",
"\n",
"\n",
" label | Метка для легенды |
\n",
" ax | Объект subplot из matplotlib, в который выводится график. Если не задан — вывод идет в активный подграфик |
\n",
" style | Строка, задающая стиль графика (например, ko--) |
\n",
" alpha | Прозрачность заполнения графика (от 0 до 1) |
\n",
" kind | Тип графика. Может быть: 'area' , 'bar' , 'barh' , 'density', 'hist' , 'kde' , 'line' , 'pie' |
\n",
" logy | Использовать ли логарифмический масштаб по оси y |
\n",
" use_index | Использовать ли объект индекс для меток оси |
\n",
" rot | Поворот меток оси |
\n",
" xticks | Значения для меток оси x |
\n",
" yticks | Значения для меток оси x |
\n",
" xlim | Границы по оси x (например, [0, 10]) |
\n",
" ylim | Границы по оси y |
\n",
" grid | Отображать ли сетку по осям (включено по умолчанию) |
\n",
"\n",
"
\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Метод `plot` объекта `DataFrame` выводит график для каждого столбца\n",
"данных в виде линии на одном и том же подграфике, создавая при этом\n",
"легенду автоматически:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df = pd.DataFrame(np.random.randn(10, 4).cumsum(0), columns=['A', 'B', 'C', 'D'], index=np.arange(0, 100, 10))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df.plot()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Атрибут `plot` содержит «семейство» методов для различных типов\n",
"графиков. Например, `df.plot()` эквивалентно `df.plot.line()`.\n",
"\n",
"В `DataFrame` есть несколько параметры, которые обеспечивают некоторую\n",
"гибкость при обработке столбцов. Например, следует ли разместить их\n",
"все на одном подграфике или создавать отдельные. В таблице\n",
"[visual:plt-with-pandas:tbl:2](#visual:plt-with-pandas:tbl:2) представлены такие параметры.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Таблица 3 : Специфичные для `DataFrame` параметры `plot` \n",
"\n",
"\n",
"\n",
"\n",
"| Параметр | Описание |
\n",
"\n",
"\n",
" subplots | Рисовать ли каждый столбец DataFrame в отдельном подграфике |
\n",
" sharex | Если subplots=True, использовать ли одну и ту же ось x, связывая метки оси |
\n",
" sharey | Если subplots=True, использовать ли одну и ту же ось y |
\n",
" figsize | Размер рисунка для создания в виде кортежа |
\n",
" title | Заголовок рисунка в виде строки |
\n",
" legend | Добавлять ли легенду на рисунок (по умолчанию True) |
\n",
" sort_columns | Отображать ли столбцы в алфавитном порядке |
\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Столбчатые диаграммы\n",
"\n",
"\n",
"Методы `plot.bar()` и `plot.barh()` строят вертикальные и\n",
"горизонтальные столбчатые диаграммы. В этом случае индексы объектов\n",
"`Series` и `DataFrame` в качестве меток на оси `x` (`bar`) или `y`\n",
"(`barh`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))\n",
"data.plot.bar(ax=axes[0], color='k', alpha=0.7)\n",
"data.plot.barh(ax=axes[1], color='k', alpha=0.7)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Параметры `color='k`' и `alpha=0.7` устанавливают цвет графика в\n",
"черный и частичную прозрачность для заполнения.\n",
"\n",
"В `DataFrame` столбчатые диаграммы группируют каждую строку значений\n",
"вместе в группу столбиков, соответствующих каждому значению в строке:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df = pd.DataFrame(np.random.rand(6, 4), index=['one', 'two', 'three', 'four', 'five', 'six'], columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df.plot.bar()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Обратите внимание на то, что имя столбцов `'Genus'` используется в\n",
"качестве заголовка легенды. Для создания столбчатых диаграмм с\n",
"накоплением для `DataFrame` задается параметр `stacked=True`, в\n",
"результате чего значение в каждой строке будут сгруппировано вместе"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"df.plot.barh(stacked=True, alpha=0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Предположим, что есть набор данных по счетам и чаевым в ресторане, и\n",
"нам нужно построить столбчатую диаграмму с накоплением, показывающую\n",
"процентное соотношение точек данных для каждого размера группы в\n",
"каждый день. Загрузим данные из файла\n",
"[tips.csv](src-visual/tips.csv.txt) и создадим сводную по дням и размеру вечеринки\n",
"(количество человек):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips = pd.read_csv('src-visual/tips.csv')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_counts = pd.crosstab(tips['day'], tips['size'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_counts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_counts = party_counts.loc[:, 2:5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Теперь нормализуем данные так, чтобы сумма в каждой строке была равна\n",
"$1$ и построим столбчатую диаграмму:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_pcts = party_counts.div(party_counts.sum(1), axis=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_pcts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"party_pcts.plot.bar()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Таким образом, видно, что количество участников вечеринок\n",
"в данном наборе увеличивается в выходные дни.\n",
"\n",
"В случае, если требуется агрегировать или суммировать данные перед\n",
"построением графика, использование пакета `seaborn` может значительно\n",
"упростить задачу. Давайте посмотрим на процент чаевых в день с помощью\n",
"библиотеки `seaborn`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"import seaborn as sns"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips['tip_pct'] = tips['tip']/(tips['total_bill'] - tips['tip'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.barplot(x='tip_pct', y='day', data=tips, orient='h')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Функция `barplot` библиотеки `seaborn` принимает параметр `data`, который\n",
"может быть объектом `DataFrame`. Остальные параметры ссылаются на\n",
"имена столбцов. Поскольку в день имеется несколько наблюдений, то\n",
"столбцы диаграммы представляют собой среднее значение параметра\n",
"`tip_pct`. Черные линии, нарисованные на столбцах диаграммы,\n",
"представляют 95-процентный доверительный интервал (это можно настроить\n",
"с помощью опционального параметра). \n",
"\n",
"Функция `barplot` имеет параметр `hue`, который позволяет разделить\n",
"отображение по дополнительному категориальному значению:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Гистограммы и графики плотности распределения\n",
"\n",
"\n",
"*Гистограмма* — это своего рода столбчатая диаграмма, которая дает\n",
"дискретное отображение частоты значений. Составим гистограмму\n",
"процентных долей от общего счета, используя метод `plot.hist` объекта\n",
"`Series`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips['tip_pct'].plot.hist(bins=50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Связанный с гистограммой тип графиков — *график плотности*, \n",
"который формируется путем вычисления оценки непрерывного распределения\n",
"вероятности, которое могло бы генерироваться наблюдаемыми данными.\n",
"Обычная процедура заключается в аппроксимации этого распределение как\n",
"смеси «ядер», то есть более простых распределений, таких как нормальное\n",
"распределение. Таким образом, графики под графиками плотности также\n",
"можно понимать графики оценки плотности ядра\n",
"(*K*ernel *D*ensity *E*stimate). Функции `plot.kde` и `plot.density`\n",
"строят график плотности, используя подход KDE:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"tips['tip_pct'].plot.kde()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Библиотека `seaborn` упрощает создание гистограмм и графиков плотности\n",
"с помощью метода `distplot`, который позволяет одновременно строить как\n",
"гистограмму, так и непрерывную оценку плотности. В качестве примера\n",
"рассмотрим бимодальное распределение, состоящее из двух разных\n",
"стандартных нормальных распределений:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"comp1 = np.random.normal(0, 1, size=200)\n",
"comp2 = np.random.normal(10, 2, size=200)\n",
"values = pd.Series(np.concatenate([comp1, comp2]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.distplot(values, bins=100, color='k')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Диаграммы рассеяния или точечные графики\n",
"\n",
"\n",
"Диаграммы рассеяния полезны при изучении связей между двумя одномерными\n",
"рядами данных. Например, загрузим набор данных из файла\n",
"[macrodata.csv](src-visual/macrodata.csv.txt) проекта\n",
"[Statmodels](https://www.statsmodels.org/stable/index.html). Выберем\n",
"некоторые переменные и вычислим «логарифмические разности»:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"macro = pd.read_csv('src-visual/macrodata.csv')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"trans_data = np.log(data).diff().dropna()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"trans_data[-5:]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Теперь воспользуемся функцией `regplot` библиотеки `seaborn`, которая\n",
"строит графики рассеяния и предлагает график линейной регрессии:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.regplot('m1', 'unemp', data=trans_data)\n",
"plt.title('Зависимость $\\log$ {} от $\\log$ {}'.format('m1', 'unemp'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"При анализе данных полезно иметь возможность просматривать все\n",
"диаграммы рассеяния среди группы переменных, т.е. строить, так\n",
"называемые, *парные графики* или *матрицу диаграмм рассеяния*. В\n",
"библиотеке `seaborn` для этого есть удобная функция `pairplot`,\n",
"которая, в частности, поддерживает размещение гистограмм или оценок\n",
"плотности каждой переменной по диагонали:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Категориальные данные\n",
"\n",
"\n",
"Одним из способов визуализации данных с множеством категориальных\n",
"переменных является использование сетки фасетов (*facet grid*). В\n",
"библиотеке `seaborn` есть удобная функция `catplot`, которая\n",
"упрощает создание сетки фасетов:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Вместо отображения разными цветами столбцов диаграмм в фасете мы\n",
"также можем расширить сетку фасетов, добавив одну строку по времени:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.catplot(x='day', y='tip_pct', row='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Функция `catplot` поддерживает другие типы графиков, которые могут быть\n",
"полезны. Например, блочные графики, которые показывают медиану,\n",
"квартили и выбросы:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"sns.catplot(x='tip_pct', y='day', kind='box', data=tips[tips.tip_pct < 0.5])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Можно создавать свои собственные сетки фасетов,\n",
"используя более общий класс `seaborn.FacetGrid` (см.\n",
"[документацию seaborn](https://seaborn.pydata.org/)).\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}