Зарегистрируйтесь, чтобы продолжить обучение

Визуализация статистических данных Python: Визуализация данных

Графическое представление статистических значений и распределений дает аналитику возможность извлекать значимые характеристики из больших объемов данных. В этом уроке мы рассмотрим основные графики и диаграммы, которые используются аналитиками в своей работе, а именно:

  • Гистограммы распределений — hist
  • Ящики с усами — boxplot
  • Скрипичные графики — violinplot
  • Круговые диаграммы — pie

Импорт библиотек и подготовка данных

Для работы нам понадобятся модули sklearn.datasets для получения данных и matplotlib.pyplot для их визуализации:

import matplotlib.pyplot as plt
from sklearn.datasets import load_iris

В качестве данных возьмем тренировочный датасет с классификацией цветков ириса. Подробнее об этом можно прочитать в документации:

data = load_iris()
X = data.data
y = data.target
n = 0

print("Data example:")
print(X[n])
# => Data example:
# [5.1 3.5 1.4 0.2]

print("Data feature names:")
print(data.feature_names)
# => Data feature names:
# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

print("Target example:")
print(y[n])
# => Target example:
# 0

print("Target name:")
print(data.target_names[n])
# => Target name:
# setosa

Код выше инициализирует две переменные. Переменная X отвечает за работу с характеристиками цветков. В ней обозначена длина и ширина лепестков и листочков в сантиметрах. В нашем случае есть четыре признака:

  • sepal length (cm)
  • sepal width (cm)
  • petal length (cm)
  • petal width (cm)

Перейдем к переменной y, которая нужна для работы с классификацией цветков. У нее есть три значения (таргета), каждое число обозначает один из видов ириса:

  • 0setosa
  • 1verticolor
  • 2virginica

На датасете цветков ириса аналитики часто учатся работе с табличными данными. Далее мы проанализируем статистические характеристики признаков и количественные показатели таргетов с использованием визуализации.

Гистограмма распределения

Один из частых подходов к визуализации — это графические представление распределения данных.

Для этого подходит гистограмма, которая реализуется с использованием метода hist(). Аналитик выбирает нужно количество интервалов и задает его через значение bins. Мы выбрали значение 8:

# Гистограмма распределения
fig, ax = plt.subplots(2, 2)
fig.suptitle("Features of iris flowers")
fig.set_size_inches((10, 10))

n = 0
feature_name = data.feature_names[n]
ax[0, 0].hist(X[:, n], bins=8, linewidth=0.5, edgecolor="white", label=feature_name)
ax[0, 0].legend()
ax[0, 0].grid()

n = 1
feature_name = data.feature_names[n]
ax[0, 1].hist(X[:, n], bins=8, linewidth=0.5, edgecolor="white", label=feature_name)
ax[0, 1].legend()
ax[0, 1].grid()

n = 2
feature_name = data.feature_names[n]
ax[1, 0].hist(X[:, n], bins=8, linewidth=0.5, edgecolor="white", label=feature_name)
ax[1, 0].legend()
ax[1, 0].grid()

n = 3
feature_name = data.feature_names[n]
ax[1, 1].hist(X[:, n], bins=8, linewidth=0.5, edgecolor="white", label=feature_name)
ax[1, 1].legend()
ax[1, 1].grid()

plt.show()

align=center

Для построения гистограммы все значения раскладываются по соответствующим числовым интервалам и подсчитывается их количество в каждом интервале. В нашем случае интервалов 8 — столько же столбцов на графике. Ширина столбца и его позиция по горизонтальной оси описывает интервал, а высота — количество значений, которые в него попали.

Код выше можно сократить, если использовать циклы. Положение каждого из признаков на соответствующей области визуализации определяется через выражения n // 2 и n % 2:

fig, ax = plt.subplots(2, 2)
fig.set_size_inches((10, 10))
fig.suptitle("Features of iris flowers")

for n in range(4):
    feature_name = data.feature_names[n]
    ax_position = ax[n // 2, n % 2]
    ax_position.hist(
        X[:, n], bins=8, linewidth=0.5, edgecolor="white", label=feature_name
    )
    ax_position.legend()
    ax_position.grid()

plt.show()

align=center

Гистограммы хорошо описывают то, какие наиболее типичные значения признаков встречаются в данных. В примере выше значения sepal width (cm) сосредоточены в районе 3.

Чтобы получить ту же информацию о квантилях и медианных значениях, построим еще один график.

Ящик с усами

Чтобы построить этот график, воспользуемся методом boxplot(). Первый необходимый параметр для него — это набор данных. В нашем случае мы используем ранее инициализированную переменную X, в которой хранятся значения признаков.

Остальные параметры отвечают за формат и расположение ящиков на области визуализации. Стоит помнить, что positions должно быть столько, сколько признаков. Мы указали четыре значения, поскольку у нас ровно четыре признака:

fig, ax = plt.subplots()
# fig.set_size_inches((10, 10))
fig.suptitle("Features of iris flowers")

ax.boxplot(X, positions=[2, 4, 6, 8], widths=1.5, patch_artist=True)
ax.grid()
plt.show()

align=center

Это тип графиков читают так:

  • Синий ящик — это область, в которую попадают большая часть всех значений
  • Линия в ящике — значение, меньше которого столько же признаков, сколько и больше него (медиана)
  • Усы — границы, в пределах которых лежат практически все признаки (вариативность признаков)

Не всегда удобно размещать признаки на одной области визуализации, потому что значения признаков могут сильно отличаться. В нашем примере этого не происходит — все значения расположены в интервале от 0 до 8. Для примера представим, что среди признаков есть зарплата работника и его возраст. В таком случае лучше выделить отдельную область под каждый признак.

Посмотрим, как сделать это с помощью циклов. При этом мы ограничиваемся каждый раз только одним признаком, вырезая его из данных вот так:

X[:, n]

Так это выглядит на практике:

fig, ax = plt.subplots(2, 2)
fig.set_size_inches((10, 10))
fig.suptitle("Features of iris flowers")

for n in range(4):
    ax_position = ax[n // 2, n % 2]
    feature_name = data.feature_names[n]
    ax_position.set_title(feature_name)
    ax_position.boxplot(
        X[:, n],
        positions=[2],
        widths=1.5,
        patch_artist=True,
    )
    ax_position.grid()
plt.show()

align=center

Посмотрим на графики выше. Какие-то признаки выходят за пределы усов — значит, в данных есть некоторые нехарактерные значения. Обычно аналитик находит эти значения и выясняет причину их появления — это либо редкий реальный случай, либо ошибка в данных. В нашем примере у признака sepal width (cm) наблюдаются такие значения.

Рассмотрим еще один график, который добавляет немного статистической информации о данных.

Скрипичная диаграмма

Чтобы построить этот график, заменим метод boxplot() на violinplot() в коде предыдущего примера:

fig, ax = plt.subplots(2, 2)
fig.set_size_inches((10, 10))
fig.suptitle("Features of iris flowers")

for n in range(4):
    ax_position = ax[n // 2, n % 2]
    feature_name = data.feature_names[n]
    ax_position.set_title(feature_name)
    ax_position.violinplot(
        X[:, n],
        positions=[2],
        widths=1.5,
    )
    ax_position.grid()
plt.show()

align=center

Таким образом мы строим график распределения значений. Там где он толще, туда и попадает наибольшее количество значений. Иногда этот график рассматривают горизонтально. Для этого необходимо добавить параметр vert=False:

fig, ax = plt.subplots(2, 2)
fig.set_size_inches((10, 10))
fig.suptitle("Features of iris flowers")

for n in range(4):
    ax_position = ax[n // 2, n % 2]
    feature_name = data.feature_names[n]
    ax_position.set_title(feature_name)
    ax_position.violinplot(X[:, n], positions=[2], widths=1.5, vert=False)
    ax_position.grid()
plt.show()

align=center

Мы разобрались с признаками, но оставили без внимания значения целевых переменных. Поработаем и с ними с помощью круговой диаграммы.

Круговая диаграмма

Для работы с целевыми переменными мы сперва посчитаем их количество. Воспользуемся методами библиотеки Numpy:

unique, counts = np.unique(y, return_counts=True)
y_counts = np.asarray((unique, counts)).T
print(y_counts)
# =>
# [[ 0 50]
#  [ 1 50]
#  [ 2 50]]

Теперь мы можем построить круговую диаграмму. Воспользуемся методом pie(). Возьмем количество наших таргетов y_counts[:, 1] в качестве данных для отрисовки.

Зададим параметр autopct лямбда-функцией, которая формирует подписи на секторах. Этот метод можно дополнительно параметризировать положением на области визуализации и размером. Не забудем также добавить легенду для наших секторов и отрисовать ее в отдельном окошке:

fig, ax = plt.subplots()
fig.set_size_inches((7, 7))
fig.suptitle("Targets of iris flowers")


def autopct_func(pct, y_values):
    return f"{pct:.1f}%"


wedges, texts, autotexts = ax.pie(
    y_counts[:, 1],
    autopct=lambda pct: autopct_func(pct, y_counts[:, 1]),
    radius=5,
    center=(6, 6),
    wedgeprops={"linewidth": 1, "edgecolor": "white"},
    frame=True,
)

legend_text = [
    f"{name} ({value})" for name, value in zip(data.target_names, y_counts[:, 1])
]
ax.legend(
    wedges,
    legend_text,
    title="Target count",
    loc="upper left",
)

ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

plt.show()

align=center

График выше показывает, сколько цветков ириса мы рассмотрели. В этом случае все классы имеют одинаковый размер по 50 штук. Размеры целевых классов существенно влияют на построение методов машинного обучения и подбор метрик качества обучаемых алгоритмов, поэтому к круговой диаграмме часто прибегают при первичном анализе данных.

Выводы

На этом уроке мы изучили методы статистического анализа данных с использованием визуализации:

  • Гистограммы распределений — hist
  • Ящики с усами — boxplot
  • Скрипичные графики — violinplot
  • Круговые диаграммы — pie

На практических примерах разобрали, когда и как правильно применять рассмотренные методы. Это стандартный набор любого аналитика, с помощью которого можно производить первичный анализ данных, выявлять ошибки в них и даже формулировать гипотезы о их свойствах.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff