Skip to content

5. Визуализация распределений: Гистограммы и анализ частот ​

Построение частотных гистограмм через ax.hist() ​

Математический и инженерный смысл гистограмм в EDA ​

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

Для решения этой задачи используется метод координатной сетки ax.hist(x). Он принимает на вход одномерную последовательность числовых значений x и строит частотную гистограмму.

Понятие «корзин» (bins) и дискретизация непрерывного диапазона ​

Физически гистограмма работает по следующему алгоритму:

  1. Находит минимальное и максимальное значения в массиве, определяя полный размах данных.
  2. Делит этот непрерывный диапазон на несколько равных интервалов — «корзин» (bins). По умолчанию Matplotlib создает 10 корзин.
  3. Подсчитывает, сколько элементов массива физически попало внутрь каждого интервала.
  4. Отрисовывает вертикальный столбик над каждой корзиной, высота которого строго пропорциональна количеству (частоте) попавших туда элементов.

Выбор оптимального параметра bins

Количество корзин (bins) — это важнейший гиперпараметр визуализации. Если выставить слишком маленькое значение (например, bins=2), график сожмет данные и скроет структуру распределения. Если выставить слишком большое значение (например, bins=100 для выборки из 50 элементов), график превратится в разрезанную «гребёнку», где большинство столбиков будут пустыми. Стандартным инженерным компромиссом для средних батчей данных является диапазон от 20 до 50 корзин.

python
import matplotlib.pyplot

fig, ax = matplotlib.pyplot.subplots()

# Simulated features dataset vector array
feature_values = [1.2, 1.4, 1.5, 2.1, 2.5, 2.6, 2.7, 3.5, 4.1]

# Drawing a histogram splitting data into 5 dense continuous bins
ax.hist(feature_values, bins=5)
ax.grid(True)

Дебаг ошибок и выбросов в датасетах ​

Поиск брака и анализ распределения абсолютных ошибок (MAE) ​

В задачах регрессии (например, предсказание стоимости недвижимости или температуры) главным индикатором качества модели является вектор её ошибок: errors = y_true - y_pred. Пропустив этот вектор через ax.hist(), вы мгновенно увидите форму распределения ошибок. В идеальном случае гистограмма должна напоминать колокол (нормальное распределение) с центром в районе нуля. Если на графике виден длинный «хвост» в правой или левой части, это сигнализирует о систематическом сдвиге или наличии грубых аномалий (выбросов), которые модель не смогла обработать.

Управление наложением распределений через параметр alpha ​

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

Если просто вызвать метод ax.hist() дважды, столбики второго графика будут жестко непрозрачными и физически перекроют собой первый график. Чтобы этого избежать, используется параметр alpha (коэффициент прозрачности от 0.0 — полностью невидим, до 1.0 — абсолютно непрозрачен). Оптимальным значением для наложения слоев является alpha=0.5 или alpha=0.6.

python
import matplotlib.pyplot

fig, ax = matplotlib.pyplot.subplots()

# Overlaying two histograms layers using custom bins and alpha transparency channels
ax.hist(train_errors, bins=30, alpha=0.5, color="blue", label="Train Errors")
ax.hist(val_errors, bins=30, alpha=0.5, color="orange", label="Validation Errors")

ax.set_title("Errors Distribution Density Analysis")
ax.legend()
ax.grid(True)

Чтение текущих границ осей: ax.get_ylim() ​

Метод ax.get_ylim() выполняет обратную операцию: возвращает кортеж (lower, upper) с текущими автоматически вычисленными границами оси Y. Это не инструмент ручного контроля, а механизм позиционирования: координаты вспомогательных объектов удобнее привязывать к фрейму графика, а не подбирать их вслепую в абсолютных единицах данных.

python
import numpy
import matplotlib.pyplot

# Simulated one-hour API latency log in milliseconds
latency = [18 + 12 * ((i % 7) / 6) + (340 if i % 250 == 0 else 0) for i in range(5000)]
p95 = numpy.percentile(latency, 95)

fig = matplotlib.pyplot.figure()
ax = fig.add_subplot(1, 1, 1)
ax.hist(latency, bins=40, color="steelblue", edgecolor="white")

# Vertical marker line at the 95th percentile boundary
ax.axvline(x=p95, color="crimson", linestyle="--")

# Anchoring the label inside the auto-computed upper Y boundary
ymax = ax.get_ylim()[1]
ax.text(p95 + 2, ymax * 0.85, f"p95 = {p95:.1f} ms", color="crimson")

Без get_ylim() позицию надписи пришлось бы подбирать вручную, рискуя вывести текст за пределы видимой области. Полученное значение ymax гарантирует, что аннотация всегда останется внутри рассчитанной рамки графика.

Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию) ​

1. Построение базовой частотной гистограммы ​

Задача: Дан массив числовых признаков metrics = [1.1, 1.2, 1.2, 2.5, 2.6, 2.7, 2.7, 2.7, 3.1]. Создайте холст и осей, постройте по этим данным гистограмму со значением по умолчанию для корзин и включите координатную сетку.

Посмотреть решение
python
import matplotlib.pyplot

metrics = [1.1, 1.2, 1.2, 2.5, 2.6, 2.7, 2.7, 2.7, 3.1]

# Instantiating default 10-bins histogram plot node
fig, ax = matplotlib.pyplot.subplots()
ax.hist(metrics)
ax.grid(True)

2. Дискретизация диапазона через кастомные bins ​

Задача: На основе массива metrics из предыдущего упражнения постройте гистограмму, принудительно разбив весь числовой диапазон данных ровно на 4 корзины с помощью параметра bins=4. Выведите график.

Посмотреть решение
python
import matplotlib.pyplot

metrics = [1.1, 1.2, 1.2, 2.5, 2.6, 2.7, 2.7, 2.7, 3.1]

# Forcing exact continuous interval partitions counts
fig, ax = matplotlib.pyplot.subplots()
ax.hist(metrics, bins=4)
ax.grid(True)

3. Текстовое аннотирование осей гистограммы ​

Задача: Постройте гистограмму для вектора абсолютных ошибок модели. Добавьте главный заголовок "Model Errors Histogram Analysis", подпись горизонтальной оси X — "Absolute Error Magnitude", подпись вертикальной оси Y — "Frequency Occurrences Count".

Посмотреть решение
python
import matplotlib.pyplot

errors = [0.1, 0.15, 0.02, 0.4, 0.55, 0.01, 0.11, 0.23, 0.04]

fig, ax = matplotlib.pyplot.subplots()
ax.hist(errors, bins=5)

# Attaching explicit metadata contexts definitions to structural graph text nodes
ax.set_title("Model Errors Histogram Analysis")
ax.set_xlabel("Absolute Error Magnitude")
ax.set_ylabel("Frequency Occurrences Count")
ax.grid(True)

4. Наложение двух распределений с полупрозрачностью alpha ​

Задача: Даны два списка: group_first = [1, 2, 2, 3] и group_second = [2, 3, 3, 4]. Нарисуйте их гистограммы на одной координатной сетке. Сделайте первую группу синей ("blue"), вторую — красной ("red"), установив для обоих вызовов коэффициент прозрачности alpha=0.6. Добавьте легенду.

Посмотреть решение
python
import matplotlib.pyplot

group_first = [1, 2, 2, 3]
group_second = [2, 3, 3, 4]

fig, ax = matplotlib.pyplot.subplots()

# Layering styled histograms columns via alpha channel blending configurations
ax.hist(group_first, bins=3, alpha=0.6, color="blue", label="Group First")
ax.hist(group_second, bins=3, alpha=0.6, color="red", label="Group Second")

ax.legend()
ax.grid(True)

5. Подавление бэкенд-массивов вывода в гистограммах ​

Задача: Метод ax.hist() возвращает сложный кортеж из трех массивов (значения частот, границы корзин, объекты отрисовки). Из-за этого в Jupyter над графиком печатается огромный блок системного текста. Напишите пример вызова гистограммы, заблокировав этот вывод с помощью точки с запятой ; в самом конце строки кода.

Посмотреть решение
python
import matplotlib.pyplot

data_samples = [10, 20, 20, 30]

fig, ax = matplotlib.pyplot.subplots()

# Trailing semicolon suppresses non-graphical terminal matrix arrays dump
ax.hist(data_samples, bins=2);

Упражнения смешанные (5 шт) (включают материал прошлых уроков) ​

6. Headless-рендеринг гистограммы нормального распределения весов из NumPy ​

Задача: С помощью современного случайного генератора ИИ rng = numpy.random.default_rng(seed=42) сгенерируйте одномерный вектор из 1 000 случайных весов, подчиняющихся нормальному распределению со средним 0.0 и стандартным отклонением 1.0 (Урок 17 модуля NumPy). Переведите Matplotlib в режим работы без графического интерфейса (Урок 3 модуля Matplotlib). Создайте холст размером (9, 5) (Урок 2 модуля Matplotlib). Постройте частотную гистограмму весов, разбив диапазон строго на 40 корзин (Урок 5 модуля Matplotlib). Подпишите оси и сохраните полученную Гауссову кривую в файл "weights_distribution.png" (Урок 3 / Урок 4 модуля Matplotlib).

Посмотреть решение
python
import numpy
import matplotlib
# Activating server-side non-interactive execution engine (Lesson 3)
matplotlib.use('Agg')
import matplotlib.pyplot

# Generating Gaussian normal random tensor allocation (NumPy Lesson 17)
rng = numpy.random.default_rng(seed=42)
weights_tensor = rng.normal(loc=0.0, scale=1.0, size=1000)

# Configuring explicit plotting layout architectures (Matplotlib Lesson 2)
fig, ax = matplotlib.pyplot.subplots(figsize=(9, 5))

# Plotting dense frequency distributions histogram (Matplotlib Lesson 5)
ax.hist(weights_tensor, bins=40, color="purple", label="Weights Distribution")

ax.set_title("Neural Network Layer Weights Initialization Grid")
ax.set_xlabel("Weight Scalar Value")
ax.set_ylabel("Occurrences Density")
ax.legend()
ax.grid(True)

# Export byte data buffer assets to folder storage directly (Matplotlib Lesson 3)
fig.savefig("weights_distribution.png")

7. Сравнительный анализ частот признаков датасета из Parquet-файла ​

Задача: Загрузите бинарный колоночный файл табличных признаков "features_vault.parquet" (Урок 8 модуля Pandas). С помощью двумерного оператора .loc[] извлеките полностью столбец "feature_raw_A" и столбец "feature_raw_B" (Урок 6 модуля Pandas). Настройте неинтерактивный режим работы (Урок 3 модуля Matplotlib). Нарисуйте гистограммы распределений обоих этих признаков на одной общей координатной сетке холста: для признака A задайте синий цвет, для признака B — оранжевый, выставив сквозной коэффициент прозрачности alpha=0.55 и количество корзин bins=30 (Урок 5 модуля Matplotlib). Снабдите график заголовком, легендой и экспортируйте в "features_comparison.png".

Посмотреть решение
python
import pandas
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot

# Loading columnar parquet records database from file system (Pandas Lesson 8)
features_df = pandas.read_parquet(path="features_vault.parquet")

# Slicing target named vectors channels components (Pandas Lesson 6)
data_vector_A = features_df.loc[:, "feature_raw_A"]
data_vector_B = features_df.loc[:, "feature_raw_B"]

fig, ax = matplotlib.pyplot.subplots()

# Blending overlaying histograms blocks charts together transparently (Matplotlib Lesson 5)
ax.hist(data_vector_A, bins=30, alpha=0.55, color="blue", label="Feature A")
ax.hist(data_vector_B, bins=30, alpha=0.55, color="orange", label="Feature B")

# Enforcing text labels metadata contexts declarations (Matplotlib Lesson 4)
ax.set_title("Comparative Exploratory Data Analysis (EDA)")
ax.set_xlabel("Feature Numeric Range Magnitude")
ax.set_ylabel("Density Frequency")
ax.legend()
ax.grid(True)

fig.savefig("features_comparison.png")

8. Гистограмма ошибок регрессии для отслайсенного батча строк после очистки NaN ​

Задача: Дан DataFrame ответов модели: df_predictions = pandas.DataFrame({"true_y": [24.5, pandas.NA, 18.0, 31.2, 40.0], "pred_y": [23.0, 15.0, 19.5, 30.0, 35.0]}) (Урок 5 модуля Pandas). Жестко удалите из таблицы любые строки, содержащие маркеры пустот NaN по оси axis=0 (Урок 9 модуля Pandas). Вычислите вектор отклонений (ошибок) по векторизованной формуле: errors_vector = clean_df["true_y"] - clean_df["pred_y"] (Урок 7 модуля Pandas). Переведите Matplotlib в headless-режим (Урок 3). Постройте частотную гистограмму полученного вектора ошибок, окрасив столбики в зеленый цвет ("green") с параметром bins=5 (Урок 5 модуля Matplotlib). Проведите вертикальную реперную линию идеального нулевого сдвига ошибки x=0.0 красным пунктиром (Урок 4 модуля Matplotlib). Сохраните в "regression_errors.png".

Посмотреть решение
python
import pandas
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot

df_predictions = pandas.DataFrame({"true_y": [24.5, pandas.NA, 18.0, 31.2, 40.0], "pred_y": [23.0, 15.0, 19.5, 30.0, 35.0]})

# Step 1: Discard row slots containing computational NaN anomalies (Pandas Lesson 9)
clean_df = df_predictions.dropna(axis=0)

# Step 2: Compute element-wise residuals array (Pandas Lesson 7)
errors_vector = clean_df["true_y"] - clean_df["pred_y"]

# Step 3: Graphical rendering pipeline chart assembly (Matplotlib Lessons 2, 3 & 5)
fig, ax = matplotlib.pyplot.subplots()
ax.hist(errors_vector, bins=5, color="green", label="Residuals")

# Step 4: Overlay reference line indicators and text structures (Matplotlib Lesson 4)
ax.set_title("Regression Model Residuals Analysis Profile")
ax.set_xlabel("Prediction Error Deviation (True - Pred)")
ax.set_ylabel("Samples Count")

ax.axvline(x=0.0, color="red", linestyle="--", label="Ideal Prediction Zero")
ax.legend()
ax.grid(True)

fig.savefig("regression_errors.png")

9. Анализ физического веса и гистограмма среза унаследованной матрицы весов ​

Задача: Создайте 2D-матрицу из диапазона целых чисел от 0 до 19 через numpy.arange(20).reshape(5, 4) (Урок 3 / Урок 11 модуля NumPy). Оберните её в таблицу pandas.DataFrame (Урок 5 модуля Pandas). С помощью позиционного оператора .iloc[] извлеките подматрицу средних трех строк (индексы 1, 2, 3), включая все столбцы (Урок 6 модуля Pandas). Сплющите полученную подматрицу в одномерный плоский 1D-вектор с помощью метода .ravel() без лишнего копирования памяти (Урок 18 модуля NumPy / Урок 2 модуля Pandas). В неинтерактивном режиме постройте гистограмму распределения значений этого плоского вектора, применив bins=6 (Урок 3 / Урок 5 модуля Matplotlib). Сохраните результат в файл "flattened_hist.png".

Посмотреть решение
python
import numpy
import pandas
import matplotlib
# Headless context block setup initialization (Lesson 3)
matplotlib.use('Agg')
import matplotlib.pyplot

# Generating core multi-dimensional integer grids tensors (NumPy Lessons 3 & 11)
numpy_grid = numpy.arange(20).reshape(5, 4)
dataset_df = pandas.DataFrame(numpy_grid)

# Extracting sub-dataset slice row indices boundaries (Pandas Lesson 6)
sub_df_slice = dataset_df.iloc[1:4, :]

# Collapsing multi-dimensional blocks coordinates down to a 1D vector tracking parent references (NumPy Lesson 18 & Pandas Lesson 2)
flat_values_vector = sub_df_slice.values.ravel()

# Render frequency statistics layout to disk directly (Matplotlib Lessons 2 & 5)
fig, ax = matplotlib.pyplot.subplots()
ax.hist(flat_values_vector, bins=6, color="teal")
ax.grid(True)

fig.savefig("flattened_hist.png")

10. Сквозной поиск документации по распределениям и гистограммам в Jupyter ​

Задача: Напишите строку кода для выполнения в ячейке Jupyter Notebook, которая открывает интерактивную Docstring-инструкцию по встроенному методу построения гистограмм matplotlib.axes.Axes.hist с помощью символа интроспекции (Урок 1 модуля NumPy / Урок 1 модуля Pandas).

Посмотреть решение
python
import matplotlib.axes

# Running this statement inside a notebook layout pops up the comprehensive API configuration instructions
?matplotlib.axes.Axes.hist