Гистограммы: hist()

Гистограммы: hist() Matplotlib / Seaborn

Привет! Ты уже умеешь строить столбчатые диаграммы для сравнения категорий. Но что, если нужно понять, как распределены числовые данные? Например, сколько людей в каждом возрастном диапазоне или как часто встречаются зарплаты определённого размера? Для этого есть гистограммы.

В этой статье мы разберём:

  • Что такое гистограмма и чем она отличается от столбчатой диаграммы
  • Как строить гистограммы с hist()
  • Настройка количества интервалов (bins)
  • Нормализация гистограммы (density)
  • Сравнение нескольких распределений
  • Добавление кривой нормального распределения

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный Matplotlib (pip install matplotlib)
  • Базовое понимание графиков из предыдущих статей
  • Желание анализировать распределения данных

Совет: Гистограмма — это лучший способ «увидеть» распределение данных. Она показывает, где данных много, а где мало, есть ли выбросы и какова форма распределения.

Основная часть

Что такое гистограмма?

Гистограмма — это график, который показывает распределение числовых данных. Данные разбиваются на интервалы (бины), и для каждого интервала показывается, сколько значений в него попало.

Отличие от столбчатой диаграммы:

ГистограммаСтолбчатая диаграмма
Для числовых данныхДля категориальных данных
Интервалы имеют порядокКатегории могут быть в любом порядке
Столбцы касаются друг другаСтолбцы разделены промежутками

Совет: Если столбцы не касаются друг друга — это столбчатая диаграмма. Если касаются — гистограмма.

Простая гистограмма

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)

# Генерируем нормально распределённые данные
data = np.random.normal(0, 1, 1000)

# Строим гистограмму
plt.hist(data, bins=30)
plt.title('Простая гистограмма')
plt.xlabel('Значение')
plt.ylabel('Частота')
plt.grid(True, alpha=0.3)
plt.show()

Совет: bins=30 — количество интервалов. Чем больше бинов, тем детальнее гистограмма. Для начала используй 20–30 бинов.

Настройка гистограммы

Количество бинов (bins)

plt.hist(data, bins=10, edgecolor='black', alpha=0.7, color='skyblue')
plt.title('10 бинов')
plt.show()
plt.hist(data, bins=50, edgecolor='black', alpha=0.7, color='skyblue')
plt.title('50 бинов')
plt.show()

Совет: Слишком мало бинов — теряется детализация. Слишком много — шум и пустые интервалы. Начни с bins=30 и корректируй.

Цвет и прозрачность

plt.hist(data, bins=30, color='green', alpha=0.7, edgecolor='black', linewidth=1)
plt.title('Гистограмма с настройками')
plt.show()

Вертикальная (горизонтальная) ориентация

# Горизонтальная гистограмма
plt.hist(data, bins=30, orientation='horizontal', color='purple', edgecolor='black')
plt.title('Горизонтальная гистограмма')
plt.show()

Нормализация гистограммы (density)

density=True показывает не абсолютные частоты, а плотность вероятности. Площадь под гистограммой становится равна 1. Это позволяет сравнивать данные разного размера и накладывать теоретические распределения.

# Нормализованная гистограмма
plt.hist(data, bins=30, density=True, alpha=0.7, edgecolor='black')
plt.title('Нормализованная гистограмма (плотность)')
plt.ylabel('Плотность')
plt.show()

Совет: density=True полезен для сравнения распределений разных выборок и для проверки, насколько данные соответствуют нормальному распределению.

Сравнение нескольких распределений

# Генерируем два распределения
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 0.8, 1000)

plt.hist(data1, bins=30, alpha=0.6, label='Распределение 1', density=True, edgecolor='black')
plt.hist(data2, bins=30, alpha=0.6, label='Распределение 2', density=True, edgecolor='black')
plt.title('Сравнение двух распределений')
plt.xlabel('Значение')
plt.ylabel('Плотность')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Совет: Используй density=True и полупрозрачность (alpha) для наложения гистограмм.

Добавление кривой нормального распределения

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm

np.random.seed(42)

# Данные
data = np.random.normal(0, 1, 1000)

# Гистограмма
plt.hist(data, bins=30, density=True, alpha=0.7, edgecolor='black', label='Данные')

# Кривая нормального распределения
x = np.linspace(-4, 4, 100)
plt.plot(x, norm.pdf(x, 0, 1), color='red', linewidth=2, label='Нормальное распределение')

plt.title('Гистограмма с кривой нормального распределения')
plt.xlabel('Значение')
plt.ylabel('Плотность')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Совет: Если данные хорошо ложатся на кривую нормального распределения — значит, они примерно нормальны. Это полезно для многих статистических методов.

Сравнение групп с помощью гистограмм

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)

# Данные о зарплатах в двух отделах
sales = np.random.normal(50000, 10000, 200)
it = np.random.normal(70000, 15000, 200)
hr = np.random.normal(45000, 8000, 200)

# Группируем данные для boxplot (для сравнения)
data = [sales, it, hr]
labels = ['Продажи', 'IT', 'HR']

# Строим гистограммы для каждой группы
fig, axes = plt.subplots(1, 3, figsize=(12, 4), sharex=True, sharey=True)

for i, (group, label) in enumerate(zip(data, labels)):
    axes[i].hist(group, bins=20, alpha=0.7, edgecolor='black', density=True)
    axes[i].set_title(label)
    axes[i].set_xlabel('Зарплата')
    axes[i].grid(True, alpha=0.3)
    # Добавляем среднее значение
    mean = np.mean(group)
    axes[i].axvline(mean, color='red', linestyle='--', linewidth=2, label=f'Среднее: {mean:.0f}')
    axes[i].legend()

axes[0].set_ylabel('Плотность')
plt.suptitle('Сравнение распределений зарплат по отделам')
plt.tight_layout()
plt.show()

Кумулятивная гистограмма

# Кумулятивная гистограмма (накопленная частота)
plt.hist(data, bins=30, cumulative=True, alpha=0.7, edgecolor='black')
plt.title('Кумулятивная гистограмма')
plt.xlabel('Значение')
plt.ylabel('Накопленная частота')
plt.grid(True, alpha=0.3)
plt.show()

Совет: Кумулятивная гистограмма показывает, сколько процентов данных находится ниже определённого значения.

Практический пример: анализ возраста клиентов

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)

# Данные о возрасте клиентов
ages = np.random.normal(35, 12, 500)
ages = np.clip(ages, 18, 70)  # Ограничиваем от 18 до 70

# Анализ распределения
plt.figure(figsize=(10, 6))

# Гистограмма с настройками
plt.hist(ages, bins=20, alpha=0.7, edgecolor='black', density=True, color='steelblue')

# Добавляем среднее и медиану
mean_age = np.mean(ages)
median_age = np.median(ages)
plt.axvline(mean_age, color='red', linestyle='--', linewidth=2, label=f'Среднее: {mean_age:.1f}')
plt.axvline(median_age, color='green', linestyle='--', linewidth=2, label=f'Медиана: {median_age:.1f}')

# Кривая нормального распределения
x = np.linspace(18, 70, 100)
from scipy.stats import norm
plt.plot(x, norm.pdf(x, mean_age, np.std(ages)), color='darkred', linewidth=2, label='Нормальное распределение')

plt.title('Распределение возраста клиентов', fontsize=14, fontweight='bold')
plt.xlabel('Возраст', fontsize=12)
plt.ylabel('Плотность', fontsize=12)
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# Вывод статистик
print(f"Количество клиентов: {len(ages)}")
print(f"Средний возраст: {mean_age:.1f}")
print(f"Медианный возраст: {median_age:.1f}")
print(f"Стандартное отклонение: {np.std(ages):.1f}")
print(f"Минимальный возраст: {np.min(ages)}")
print(f"Максимальный возраст: {np.max(ages)}")

Результат:

Количество клиентов: 500
Средний возраст: 34.9
Медианный возраст: 35.0
Стандартное отклонение: 11.9
Минимальный возраст: 18
Максимальный возраст: 70

Гистограмма с логарифмической шкалой

# Логарифмическая шкала для y (полезно при больших разбросах)
plt.hist(data, bins=30, log=True, alpha=0.7, edgecolor='black')
plt.title('Гистограмма с логарифмической шкалой')
plt.ylabel('Логарифм частоты')
plt.grid(True, alpha=0.3)
plt.show()

Гистограмма с подписями на столбцах

# Получаем значения гистограммы
counts, bins, patches = plt.hist(data, bins=20, alpha=0.7, edgecolor='black')

# Добавляем подписи
for count, bin_edge in zip(counts, bins[:-1]):
    if count > 0:
        plt.text(bin_edge + (bins[1] - bins[0])/2, count + 0.5, str(int(count)),
                 ha='center', va='bottom', fontsize=8)

plt.title('Гистограмма с подписями значений')
plt.show()

Задачи для закрепления

Задача 1. Построй гистограмму для случайных 1000 точек из нормального распределения с параметрами mean=0, std=1.

Задача 2. Настрой гистограмму: bins=20, цвет blue, прозрачность 0.6, обводка black.

Задача 3. Добавь density=True и сравни гистограмму с теоретической кривой нормального распределения.

Задача 4. Построй кумулятивную гистограмму для тех же данных.

Задача 5. Сравни два распределения на одном графике с прозрачностью.

Ответы:

Задача 1.

import matplotlib.pyplot as plt
import numpy as np

data = np.random.normal(0, 1, 1000)
plt.hist(data, bins=30)
plt.show()

Задача 2.

plt.hist(data, bins=20, color='blue', alpha=0.6, edgecolor='black')

Задача 3.

from scipy.stats import norm

plt.hist(data, bins=30, density=True, alpha=0.7, edgecolor='black')
x = np.linspace(-4, 4, 100)
plt.plot(x, norm.pdf(x, 0, 1), color='red', linewidth=2)
plt.show()

Задача 4.

plt.hist(data, bins=30, cumulative=True, alpha=0.7, edgecolor='black')
plt.show()

Задача 5.

data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 0.8, 1000)

plt.hist(data1, bins=30, alpha=0.5, label='Data1', density=True)
plt.hist(data2, bins=30, alpha=0.5, label='Data2', density=True)
plt.legend()
plt.show()

Нюансы и подводные камни

Выбор количества бинов

  • Слишком мало бинов → теряем детали
  • Слишком много бинов → шум
  • Используй правило: bins = int(np.sqrt(len(data))) как стартовую точку

density=True vs нормировка

density=True делает площадь под гистограммой равной 1. Это полезно для сравнения с теоретическими распределениями.

Выбросы

Выбросы могут растянуть гистограмму и сделать её нечитаемой. Рассмотри обрезку данных.

Частые ошибки и как их избежать

Ошибка 1: Путаница между hist() и bar()

# bar() для числовых данных (неправильно)
plt.bar(data, data)

# hist() для числовых данных
plt.hist(data)

Ошибка 2: Слишком много бинов

# Шумная гистограмма
plt.hist(data, bins=200)

# Оптимальное количество
plt.hist(data, bins=30)

Ошибка 3: Забыл параметр bins для лучшей читаемости

# По умолчанию 10 бинов
plt.hist(data)

# Настроенные бины
plt.hist(data, bins=30)

Шпаргалка

Что нужноКак пишется
Простая гистограммаplt.hist(data)
Количество биновbins=30
Цвет и прозрачностьcolor='blue', alpha=0.7
Обводкаedgecolor='black'
Нормализацияdensity=True
Горизонтальнаяorientation='horizontal'
Кумулятивнаяcumulative=True
Логарифмическая шкалаlog=True
Несколько гистограммнесколько вызовов plt.hist() с alpha
Сравнение с нормальным распределениемplt.hist(... density=True)plt.plot(x, norm.pdf(x, mean, std))

Заключение

Сегодня мы научились:

  • Строить гистограммы для визуализации распределений
  • Настраивать количество бинов, цвет и прозрачность
  • Сравнивать несколько распределений на одном графике
  • Добавлять кривую нормального распределения
  • Анализировать реальные данные с помощью гистограмм

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×