Гистограммы Matplotlib в Python — Полное руководство
Узнайте, как создавать и настраивать гистограммы в Python с Matplotlib: бины, плотность, KDE, кумулятивные и составные гистограммы.
Функция hist() в Matplotlib позволяет легко визуализировать распределение набора данных по числовому диапазону. Эта глава охватывает всё — от минимальной первой гистограммы до практических приёмов, которые вы будете использовать в реальных проектах: выбор правильного количества бинов, отображение плотности вместо сырых подсчётов, наложение кривой KDE, сравнение нескольких распределений и сохранение результата в файл.
Перед началом убедитесь, что Matplotlib и NumPy установлены:
pip install matplotlib numpyЕсли вы новичок в библиотеке, сначала ознакомьтесь с главами Введение в Matplotlib и Начало работы.
Что такое гистограмма?
Гистограмма делит непрерывную числовую переменную на равномерно расположенные интервалы, называемые бинами, и рисует столбец для каждого бина, высота которого равна количеству наблюдений, попадающих в этот интервал. В отличие от столбчатой диаграммы, которая сравнивает дискретные категории, гистограмма раскрывает форму распределения — симметрично ли оно, смещено, бимодально или имеет выбросы.
Используйте гистограмму, когда хотите ответить на такие вопросы:
- Где сосредоточена большая часть данных?
- Является ли распределение примерно нормальным или оно смещено?
- Есть ли пробелы или несколько пиков (бимодальные данные)?
- Есть ли выбросы, далеко отстоящие от основной массы данных?
Создание базовой гистограммы
Передайте одномерный array или список в plt.hist(), и Matplotlib автоматически выберет количество бинов:
import matplotlib.pyplot as plt
import numpy as np
# Reproducible example: 1 000 values from a normal distribution
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data)
plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()plt.tight_layout() предотвращает обрезку подписей осей — полезная привычка добавлять его перед каждым вызовом show() или savefig().
Выбор количества бинов
Параметр bins является наиболее важным регулятором гистограммы. Слишком мало бинов скрывает структуру; слишком много бинов создаёт шум.
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for ax, n_bins in zip(axes, [5, 30, 100]):
ax.hist(data, bins=n_bins, color='steelblue', edgecolor='white')
ax.set_title(f'bins={n_bins}')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
plt.suptitle('Effect of Bin Count', y=1.02)
plt.tight_layout()
plt.show()Практические рекомендации:
- 5–10 бинов — полезно для очень малых наборов данных (n < 50) или быстрого обзора.
- 20–50 бинов — хороший вариант по умолчанию для большинства наборов данных (n = 100–10 000).
- 50–100+ бинов — подходит для больших наборов данных (n > 10 000), где важна детальная структура.
- Вместо числа можно передать строковое правило:
bins='auto',bins='fd'(Фридман–Диаконис) илиbins='sturges'— Matplotlib делегирует вычисления функцииnp.histogram_bin_edges()из NumPy.
Вы также можете передать явный список граней бинов для неравномерного разбиения:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.exponential(scale=2, size=1000)
# Finer bins near 0, coarser bins in the tail
edges = [0, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 12]
plt.hist(data, bins=edges, color='darkorange', edgecolor='white')
plt.title('Custom Bin Edges (Exponential Data)')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()Настройка внешнего вида
Цвет, прозрачность и граница
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=5, scale=1.5, size=800)
plt.hist(
data,
bins=30,
color='steelblue',
edgecolor='white', # thin white line between bars
linewidth=0.5,
alpha=0.85, # slight transparency
)
plt.title('Styled Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()alpha (0 = полностью прозрачный, 1 = полностью непрозрачный) особенно полезен при наложении нескольких гистограмм, чтобы столбцы не скрывали друг друга.
Удаление лишних элементов
Удаление верхней и правой рамок придаёт гистограмме более чистый вид:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(data, bins=30, color='cornflowerblue', edgecolor='white')
ax.set_title('Clean Histogram')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()Гистограммы плотности
По умолчанию hist() отображает сырые подсчёты на оси Y. Передайте density=True, чтобы нормализовать ось Y так, чтобы суммарная площадь всех столбцов равнялась 1. Это превращает гистограмму в оценку вероятностной плотности, что упрощает сравнение наборов данных разного размера.
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, density=True, color='mediumseagreen', edgecolor='white')
plt.title('Density Histogram')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.tight_layout()
plt.show()Примечание: значения на оси Y — это плотности, а не вероятности. Умножьте плотность на ширину бина, чтобы получить вероятность для этого бина.
Наложение кривой KDE
Оценка плотности ядра (KDE) — это гладкая кривая, приближающая лежащее в основе вероятностное распределение. Наложение её на гистограмму плотности даёт наглядное представление о форме распределения. Используйте scipy.stats.gaussian_kde для её вычисления:
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, ax = plt.subplots(figsize=(8, 4))
# Density histogram
ax.hist(data, bins=30, density=True,
color='steelblue', edgecolor='white', alpha=0.6, label='Histogram')
# KDE curve
xs = np.linspace(data.min(), data.max(), 300)
kde = gaussian_kde(data)
ax.plot(xs, kde(xs), color='navy', linewidth=2, label='KDE')
ax.set_title('Histogram with KDE Overlay')
ax.set_xlabel('Value')
ax.set_ylabel('Probability Density')
ax.legend()
plt.tight_layout()
plt.show()Установите SciPy, если он ещё не доступен:
pip install scipyСравнение нескольких распределений
Чтобы сравнить два и более распределения на одних осях, вызовите hist() несколько раз и используйте alpha для полупрозрачности столбцов. Установите одинаковые bins для обоих, чтобы ширина столбцов была сопоставимой:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
group_a = rng.normal(loc=0, scale=1, size=500)
group_b = rng.normal(loc=2, scale=1.5, size=500)
shared_bins = np.linspace(-5, 8, 40)
plt.hist(group_a, bins=shared_bins, alpha=0.6, color='steelblue', label='Group A')
plt.hist(group_b, bins=shared_bins, alpha=0.6, color='darkorange', label='Group B')
plt.title('Overlapping Histograms')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.legend()
plt.tight_layout()
plt.show()Определение shared_bins через np.linspace() гарантирует, что обе гистограммы используют одинаковые грани бинов, и их столбцы выровнены визуально.
Параллельные (составные) гистограммы
Когда наложение затрудняет чтение отдельных распределений, используйте plt.subplots() для размещения их рядом:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
group_a = rng.normal(loc=0, scale=1, size=500)
group_b = rng.normal(loc=2, scale=1.5, size=500)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), sharey=True)
ax1.hist(group_a, bins=30, color='steelblue', edgecolor='white')
ax1.set_title('Group A')
ax1.set_xlabel('Value')
ax1.set_ylabel('Frequency')
ax2.hist(group_b, bins=30, color='darkorange', edgecolor='white')
ax2.set_title('Group B')
ax2.set_xlabel('Value')
plt.suptitle('Side-by-Side Histograms')
plt.tight_layout()
plt.show()sharey=True синхронизирует обе подграфики по одной шкале оси Y, чтобы высоты столбцов можно было непосредственно сравнивать. Дополнительные варианты компоновки описаны в главе Подграфики Matplotlib.
Кумулятивные гистограммы
Передайте cumulative=True, чтобы построить гистограмму, в которой каждый столбец представляет общее количество наблюдений до и включая данный бин. Это полезно для ответа на вопросы вроде «какая доля значений меньше X?»:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, cumulative=True, density=True,
color='mediumpurple', edgecolor='white')
plt.title('Cumulative Density Histogram')
plt.xlabel('Value')
plt.ylabel('Cumulative Probability')
plt.tight_layout()
plt.show()В сочетании с density=True кумулятивная гистограмма становится ступенчатым приближением эмпирической функции распределения (CDF). Ось Y принимает значения от 0 до 1.
Ориентация гистограммы
Передайте orientation='horizontal', чтобы рисовать столбцы, вытянутые влево от оси Y. Это редко используется по умолчанию, но соответствует компоновке маргинальных распределений на диаграммах рассеяния:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=500)
plt.hist(data, bins=20, orientation='horizontal',
color='tomato', edgecolor='white')
plt.title('Horizontal Histogram')
plt.ylabel('Value')
plt.xlabel('Frequency')
plt.tight_layout()
plt.show()Сохранение гистограммы в файл
Используйте plt.savefig() перед plt.show() (или вместо него). Формат задаётся расширением файла:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, color='steelblue', edgecolor='white')
plt.title('Distribution of Sample Data')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.savefig('histogram.png', dpi=150) # raster, good for web
plt.savefig('histogram.pdf') # vector, good for print/publication
plt.show()Распространённые форматы: png, pdf, svg, eps. Используйте svg или pdf, когда нужно масштабируемое изображение типографского качества.
Основные параметры hist() — краткий справочник
| Параметр | Тип | Описание |
|---|---|---|
bins | int, список или string | Количество бинов, явные грани или имя правила ('auto', 'fd', 'sturges') |
density | boolean | Нормализация так, чтобы суммарная площадь = 1 (вероятностная плотность) |
cumulative | boolean | Каждый столбец показывает кумулятивный подсчёт/плотность до этого бина |
orientation | string | 'vertical' (по умолчанию) или 'horizontal' |
color | string | Цвет заливки столбца |
edgecolor | string | Цвет границы столбца; 'white' создаёт чёткий разделитель |
alpha | float 0–1 | Прозрачность; устанавливайте ниже 1 при наложении гистограмм |
label | string | Подпись легенды для данной гистограммы |
histtype | string | 'bar' (по умолчанию), 'step', 'stepfilled' |
range | (min, max) | Обрезать данные до этого диапазона перед разбиением на бины |
Распространённые ошибки
- Случайные зерна.
np.random.randn()выдаёт разные значения при каждом запуске. Используйтеnp.random.default_rng(seed)для воспроизводимых примеров. densityпротивnormed. Старый параметрnormed=Trueбыл удалён в Matplotlib 3.x. Всегда используйтеdensity=True.- Сравнение гистограмм с разными объёмами выборок. Сырые частотные столбцы несопоставимы при разных размерах групп — используйте
density=Trueдля нормализации обеих. - Дискретные целочисленные данные. Для целых чисел (например, броски кубика, оценки в опросах) устанавливайте грани бинов на полуцелые значения —
bins=[0.5, 1.5, 2.5, ..., 6.5]— чтобы каждое целое число попадало ровно в один бин без неоднозначности на границах. plt.show()очищает фигуру. Если вы вызываетеshow(), а затемsavefig(), файл окажется пустым. Всегда вызывайтеsavefig()доshow().
Связанные главы
- Введение в Matplotlib — обзор библиотеки и установка
- Начало работы с Matplotlib — пошаговое создание первого графика
- Столбчатые диаграммы Matplotlib — сравнение дискретных категорий
- Диаграммы рассеяния Matplotlib — отношения между двумя переменными
- Круговые диаграммы Matplotlib — соотношение частей и целого
- Подписи Matplotlib — подписи осей, заголовки и аннотации
- Подграфики Matplotlib — несколько графиков на одной фигуре
- Распределение данных — статистическая основа распределений