Гистограмма: как построить, выбрать интервалы и прочитать форму
Что показывает гистограмма распределения и чем она отличается от столбчатой диаграммы, как выбрать число интервалов, построить её в SQL, Python и Excel и не ошибиться.
Содержание статьи
Менеджер просит ответить, как часто пользователи возвращаются в приложение. Средняя пауза между открытиями в учебной базе — 5,1 дня, и на слайде это выглядит как «заходят раз в пять дней». Гистограмма показывает другое: самая частая пауза — одни сутки, у половины пауз срок не больше трёх дней, а среднее тянет вверх хвост до 58 дней. Гистограмма — это график, на котором значения разложены по соседним интервалам, а высота столбца показывает, сколько значений попало в каждый. Ниже — как её построить и прочитать, сколько интервалов взять и где этот простой график чаще всего вводит в заблуждение.
Коротко
Гистограмма показывает распределение числовой величины: какие значения встречаются часто, какие редко и где лежит основная масса.
- Ось X — сама величина, разбитая на интервалы без промежутков. Высота столбца — число значений в интервале, их доля или плотность.
- Столбчатая диаграмма сравнивает категории, гистограмма — значения одной непрерывной величины. Переставить столбцы гистограммы нельзя.
- По форме читают симметрию, скошенность, хвосты, несколько пиков и выбросы. Два пика почти всегда означают смесь двух групп.
- Число интервалов меняет вывод. Правило Стёрджеса даёт мало интервалов на больших данных, правило Фридмана — Диакониса может дать гребёнку на целых числах.
- Группы разного размера сравнивают по долям, а не по числу наблюдений. Длинный хвост показывают на логарифмических интервалах.
Что такое гистограмма простыми словами
Построить гистограмму можно на бумаге. Берёте все значения, делите диапазон от минимума до максимума на равные отрезки, считаете, сколько значений попало в каждый отрезок, и рисуете над отрезком столбец такой высоты. Столбцы стоят вплотную: отрезки идут подряд, и между соседними нет пустого места на шкале.
Пример из учебной базы: сколько раз каждый пользователь открыл приложение за первые 14 дней после регистрации. Берём тех, кто зарегистрировался не позже 16 августа, — у них все 14 дней уже прошли к моменту выгрузки. Это 3 661 человек, значения от 1 до 11. Величина целая, поэтому каждый интервал — одно значение.
Высоту столбца задают тремя способами. Частота — число наблюдений в интервале. Доля — частота, делённая на общее число наблюдений; так сравнивают группы разного размера. Плотность — доля, делённая ещё и на ширину интервала; она нужна, когда интервалы разной ширины. У плотности площадь всех столбцов равна единице, поэтому поверх неё можно наложить теоретическую кривую, например нормальную.
частота = kᵢ; доля = kᵢ / n; плотность = kᵢ / (n · hᵢ)kᵢ — число значений в i-м интервале, n — всего значений, hᵢ — ширина интервала. При равной ширине доля и плотность отличаются только масштабом оси.
Учебная база «Маяк», 3 661 пользователь с регистрацией по 16 августа 2026. Распределение почти симметричное: среднее 4,16, медиана 4.
WITH opens AS (
SELECT u.user_id, COUNT(e.event_id) AS opens_14d
FROM users u
LEFT JOIN events e
ON e.user_id = u.user_id
AND e.event_name = 'app_open'
AND CAST(e.event_time AS date) < u.signup_date + 14
WHERE u.signup_date <= DATE '2026-08-16'
GROUP BY u.user_id
)
SELECT opens_14d,
COUNT(*) AS users,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS percent
FROM opens
GROUP BY opens_14d
ORDER BY opens_14d;Чем гистограмма отличается от столбчатой диаграммы
Внешне оба графика состоят из столбцов, но отвечают на разные вопросы. Столбчатая диаграмма сравнивает отдельные категории: выручку по каналам, число пользователей по странам. Порядок столбцов можно менять, промежутки между ними ничего не значат. Гистограмма описывает одну числовую величину: ось — это шкала, интервалы идут по порядку, и пустой интервал сам по себе информация.
Путаницу добавляет русский Excel. В нём словом «Гистограмма» названа обычная столбчатая диаграмма: в справке Microsoft «Типы диаграмм в Office» так подписан тип с вертикальными столбцами, а горизонтальные столбцы называются линейчатой диаграммой. Статистическая гистограмма, которая сама раскладывает значения по интервалам, живёт в Excel 2016 и новее в группе статистических диаграмм. Если школьное задание или коллега просит «построить гистограмму» по таблице «канал — выручка», почти наверняка имеется в виду столбчатая диаграмма.
| Гистограмма | Столбчатая диаграмма | |
|---|---|---|
| Что по оси X | Интервалы одной числовой величины | Категории: каналы, страны, тарифы |
| Промежутки между столбцами | Нет: интервалы идут подряд | Есть, ничего не означают |
| Можно переставить столбцы | Нет, порядок задаёт шкала | Да, например по убыванию |
| Высота столбца | Частота, доля или плотность | Значение показателя |
| Ширина столбца | Ширина интервала, выбирает аналитик | Не несёт смысла |
| Вопрос | Как распределены значения? | Какая категория больше? |
Как читать форму гистограммы
Смотрите на гистограмму в четыре приёма: где центр, симметрична ли форма, сколько вершин и что происходит на краях. Каждое наблюдение подсказывает, какой статистикой описывать данные и что проверить дальше.
Число открытий за 14 дней из предыдущего раздела — почти симметричная гора: вершина на 4, медиана 4, среднее 4,16. Для такой формы среднее и стандартное отклонение честно описывают типичного пользователя. Паузы между открытиями устроены иначе: высокий столбец слева и длинный хвост вправо, медиана 3 дня, среднее 5,09. Это правосторонняя скошенность, при ней среднее больше медианы, и для отчёта лучше подходят медиана и перцентили.
Две вершины почти всегда означают, что в данных смешаны две группы. Число регистраций по дням августа даёт яркий пример: 20 будних дней лежат в диапазоне 72–88 регистраций, 9 выходных — в диапазоне 28–38, а между 39 и 71 нет ни одного дня. Среднее по месяцу, около 65, попадает как раз в пустоту, где не было ни одного реального дня. Правильный шаг — найти признак, который разделяет группы, и описывать их отдельно.
Одиночные столбцы далеко от основной массы — кандидаты в выбросы. Среди пауз есть по одной длиной 53 и 58 дней, среди открытий за 14 дней — по одному пользователю с 10 и 11. Прежде чем их удалять, проверьте, ошибка это или редкое, но настоящее поведение.
| Форма | Что означает | Что делать |
|---|---|---|
| Симметричная гора | Значения рассеяны вокруг центра | Среднее и стандартное отклонение подходят |
| Хвост вправо | Много малых значений, мало крупных | Медиана, перцентили, логарифмические интервалы |
| Хвост влево | Упор в верхнюю границу шкалы | Проверить потолок шкалы или лимит |
| Две вершины и больше | Смесь групп | Найти признак-разделитель, разбить данные |
| Одиночные столбцы вдали | Выбросы или редкие события | Проверить источник, не удалять вслепую |
| Обрыв на краю | Обрезанные данные или лимит | Проверить фильтры и окно наблюдения |
Учебная база «Маяк», 29 дней августа 2026. Левая вершина — выходные, правая — будни.
SELECT FLOOR(signups / 10) * 10 AS bin_start,
COUNT(*) AS days,
MIN(signups) AS min_signups,
MAX(signups) AS max_signups
FROM (
SELECT signup_date, COUNT(*) AS signups
FROM users
WHERE signup_date >= DATE '2026-08-01'
GROUP BY signup_date
) AS daily
GROUP BY 1
ORDER BY 1;Почему гистограмма суммы оплат похожа на частокол
Возьмём суммы оплат из таблицы payments. Это кажется числовой величиной, но в учебной базе всего три тарифа: 19, 29 и 39. Если отдать такие данные в numpy.histogram, plt.hist или Series.plot.hist без настроек, получится 10 интервалов шириной 2 от 19 до 39, и семь из них пустые. Три столба и провалы между ними — это частокол, а не распределение: пустоты говорят о цене тарифа, а не о поведении пользователей.
Для величины с несколькими значениями гистограмма не нужна. Нужна таблица частот: значение, сколько раз встретилось и какая это доля. Нарисовать её можно столбчатой диаграммой. Тот же частокол появляется, когда данные округлены (оценки 1–5, возраст в годах, суммы, кратные 100), — и тогда ширину интервала стоит брать кратной шагу округления.
Учебная база «Маяк», 1 251 оплата. Интервалы numpy.histogram: последний включает правую границу 39.
SELECT amount,
COUNT(*) AS payments,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS percent
FROM payments
GROUP BY amount
ORDER BY amount;import numpy as np
# Суммы оплат из таблицы payments: три тарифа, 1 251 оплата
amounts = np.repeat([19, 29, 39], [706, 403, 142])
counts, edges = np.histogram(amounts) # по умолчанию 10 интервалов
for lo, hi, c in zip(edges[:-1], edges[1:], counts):
print(f"{lo:4.0f}–{hi:<4.0f} {c:5d}")
print("пустых интервалов:", (counts == 0).sum(), "из", counts.size)
# Для дискретной величины честнее таблица частот
values, freq = np.unique(amounts, return_counts=True)
print(dict(zip(values.tolist(), freq.tolist())))Как построить гистограмму в SQL
В SQL гистограмма — это группировка по номеру интервала. Номер даёт формула начало + FLOOR((x − начало) / ширина) · ширина: она возвращает левую границу интервала, в который попало значение. В PostgreSQL для того же есть функция width_bucket, но в DuckDB её нет, поэтому переносимый способ — FLOOR. Хвост удобно собрать в последний интервал «N и больше», иначе десятки почти пустых строк займут весь экран.
Возьмём паузы между соседними открытиями приложения одним пользователем в календарных днях. В базе 24 080 таких пауз у 4 433 пользователей: от 1 до 58 дней. Запрос ниже раскладывает их по суткам и собирает всё, что длиннее 20 дней, в одну строку. Меняя width в первой строке, вы сразу видите, как меняется картина.
Учебная база «Маяк», 24 080 пауз. Самая частая пауза — 1 день (29,2%), последняя строка собирает паузы от 21 дня (2,9%).
WITH params AS (
SELECT 1 AS lo, 1 AS width, 21 AS cap -- начало, ширина интервала, начало хвоста
),
opens AS (
SELECT user_id,
CAST(event_time AS date) AS day,
LAG(CAST(event_time AS date)) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_day
FROM events
WHERE event_name = 'app_open'
),
pauses AS (
SELECT day - prev_day AS days
FROM opens
WHERE prev_day IS NOT NULL
)
SELECT
CASE WHEN days >= cap THEN cap
ELSE lo + FLOOR((days - lo) / width) * width
END AS bin_start,
COUNT(*) AS pauses,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS percent
FROM pauses CROSS JOIN params
GROUP BY 1
ORDER BY 1;Сколько интервалов выбрать: правила Стёрджеса и Фридмана — Диакониса
Универсального числа интервалов нет, есть правила для первого приближения. Правило Стёрджеса (1926) смотрит только на размер выборки: интервалов log₂(n) + 1. Оно выведено для данных, близких к нормальным, и на больших выборках даёт слишком мало интервалов. Правило Фридмана — Диакониса (1981) задаёт ширину интервала через межквартильный размах и устойчиво к выбросам: крайние значения на IQR почти не влияют.
Применим оба правила к 24 080 паузам. По Стёрджесу выходит 15,56 интервала; numpy переводит это в ширину и округляет число вверх — 16 интервалов шириной 3,56 дня. В первый интервал, от 1 до 4 дней, попадает 63,6% пауз. Гистограмма выглядит как плавный спуск, и главный факт — почти каждая третья пауза длится ровно сутки — растворяется в одном столбце.
По Фридману — Диаконису: IQR = 7 − 1 = 6, ширина 2 · 6 / ∛24 080 ≈ 0,416 дня. Для величины, которая принимает только целые значения, это ловушка: интервалов 138, из них 87 пустые, и график превращается в гребёнку. Так происходит, когда данные пришли как дробные числа, например из CSV или после деления. С версии 2.1 numpy не опускает автоматическую ширину ниже 1, если массив целочисленный, и даёт 57 интервалов шириной 1. Надёжнее задать границы явно — посередине между целыми: 0,5; 1,5; 2,5 и так далее.
Значения по умолчанию в инструментах тоже разные. numpy.histogram, plt.hist и Series.plot.hist в pandas берут 10 интервалов, функция hist в R — правило Стёрджеса, автоматический режим Excel — правило Скотта, которое опирается на стандартное отклонение. В numpy вариант bins="auto" выбирает меньшую ширину из Стёрджеса и Фридмана — Диакониса. Правило — стартовая точка: посмотрите на 2–3 варианта ширины и выберите ту, что отвечает на ваш вопрос. Для пауз в днях это одни сутки.
Стёрджес: k = log₂(n) + 1; Фридман — Диаконис: h = 2 · IQR / ∛nk — число интервалов, h — ширина, n — число наблюдений, IQR — межквартильный размах (Q3 − Q1). Число интервалов по ширине: (максимум − минимум) / h с округлением вверх.
| Вариант | Интервалов | Ширина, дней | Пустых | В первом интервале |
|---|---|---|---|---|
| Стёрджес | 16 | 3,56 | 0 | 63,6% |
| Фридман — Диаконис, дробные данные | 138 | 0,41 | 87 | 29,2% |
| Фридман — Диаконис, целые (numpy ≥ 2.1) | 57 | 1,00 | 6 | 29,2% |
| Границы между целыми днями | 58 | 1,00 | 7 | 29,2% |
Учебная база «Маяк», 24 080 пауз. В интервал 1–4 дня попадает 63,6% пауз: пик на одних сутках не виден. Дробная ширина кладёт в интервалы то 3, то 4 целых дня.
import numpy as np
# Паузы между соседними открытиями приложения, в календарных днях:
# число дней → сколько таких пауз (результат SQL-запроса при cap = 100)
pauses = {1: 7028, 2: 3784, 3: 2607, 4: 1898, 5: 1498, 6: 1189, 7: 958,
8: 823, 9: 657, 10: 535, 11: 426, 12: 397, 13: 317, 14: 268,
15: 214, 16: 193, 17: 175, 18: 161, 19: 139, 20: 121, 21: 99,
22: 78, 23: 56, 24: 70, 25: 56, 26: 32, 27: 47, 28: 35, 29: 37,
30: 24, 31: 19, 32: 23, 33: 14, 34: 16, 35: 16, 36: 8, 37: 9,
38: 9, 39: 4, 40: 5, 41: 5, 42: 6, 43: 6, 44: 2, 45: 5, 46: 3,
47: 3, 48: 2, 49: 1, 53: 1, 58: 1}
x = np.repeat(list(pauses), list(pauses.values())) # целые числа, int64
n = x.size
q1, q3 = np.percentile(x, [25, 75])
print(f"n={n} медиана={np.median(x):.0f} среднее={x.mean():.2f} IQR={q3 - q1:.0f}")
print(f"Стёрджес: log2(n) + 1 = {np.log2(n) + 1:.2f} интервала")
print(f"Фридман — Диаконис: h = 2·IQR / n^(1/3) = {2 * (q3 - q1) / n ** (1 / 3):.3f} дня")
variants = {
"Стёрджес": (x, "sturges"),
"ФД, float": (x.astype(float), "fd"), # так данные часто приходят из CSV
"ФД, int": (x, "fd"), # numpy ≥ 2.1 не даёт ширину < 1
"по суткам": (x, np.arange(0.5, x.max() + 1.5)), # границы между днями
}
for name, (data, bins) in variants.items():
counts, edges = np.histogram(data, bins=bins)
print(f"{name:>10}: интервалов {counts.size:3d}, ширина {edges[1] - edges[0]:.2f}, "
f"пустых {np.sum(counts == 0):3d}, в первом {100 * counts[0] / n:.1f}%")
# Логарифмические интервалы: 1, 2–3, 4–7, 8–15, 16–31, 32–63 дня
edges = 2 ** np.arange(0, 7)
counts, _ = np.histogram(x, bins=edges)
for lo, hi, c in zip(edges[:-1], edges[1:], counts):
print(f"{lo:2d}–{hi - 1:<2d} дн.: пауз {c:5d}, на один день ширины {c / (hi - lo):7.1f}")Как показать длинный хвост: логарифмическая шкала
На гистограмме пауз по суткам хвост от 21 до 58 дней почти не виден: 692 паузы размазаны по диапазону в 38 дней. Если хвост и есть предмет вопроса — например, сколько пользователей возвращаются после долгого перерыва, — интервалы делают растущими: 1 день, 2–3, 4–7, 8–15, 16–31, 32–63. Каждый следующий вдвое шире предыдущего, и на логарифмической оси они выглядят одинаковыми.
Здесь важна оговорка про высоту столбца. Интервалы разной ширины, поэтому число пауз в них сравнивать нельзя: в интервале 2–3 дня 6 391 пауза, в интервале 4–7 — 5 543, и кажется, что спад небольшой. На один день ширины это 3 195,5 против 1 385,8 — разница в 2,3 раза. Для неравных интервалов высотой столбца должна быть плотность, а ось Y тоже стоит сделать логарифмической, иначе последний столбец, 4,3 паузы на день, сольётся с нулём.
| Интервал, дней | Ширина | Пауз | Пауз на один день ширины |
|---|---|---|---|
| 1 | 1 | 7 028 | 7 028,0 |
| 2–3 | 2 | 6 391 | 3 195,5 |
| 4–7 | 4 | 5 543 | 1 385,8 |
| 8–15 | 8 | 3 637 | 454,6 |
| 16–31 | 16 | 1 342 | 83,9 |
| 32–63 | 32 | 139 | 4,3 |
Как сравнить гистограммы двух групп
Сравним паузы пользователей из органики и из партнёрского канала. Органических пауз 10 518, партнёрских — 3 762, почти втрое меньше. Если положить рядом две гистограммы с числом пауз, органика выигрывает в каждом столбце: однодневных пауз 3 194 против 914, пауз от 15 дней — 618 против 396. Напрашивается вывод «органика и возвращается быстрее, и пропадает надолго чаще», и его вторая половина — артефакт размера групп.
В долях картина другая. Однодневных пауз у органики 30,4%, у партнёрского канала 24,3%: органика действительно возвращается быстрее. А длинных пауз от 15 дней у партнёрского канала 10,5% против 5,9%, почти вдвое больше. Сравнивать группы можно только по нормированным гистограммам: доля в SQL, density=True в matplotlib или stat="percent" в seaborn, и с одинаковыми границами интервалов у обеих групп.
Учебная база «Маяк»: 10 518 пауз органики и 3 762 партнёрского канала. Интервалы 4–7, 8–14 и 15+ шире остальных: сравнивайте группы внутри интервала, а не соседние интервалы.
WITH opens AS (
SELECT e.user_id, u.channel,
CAST(e.event_time AS date) AS day,
LAG(CAST(e.event_time AS date)) OVER (PARTITION BY e.user_id ORDER BY e.event_time) AS prev_day
FROM events e
JOIN users u ON u.user_id = e.user_id
WHERE e.event_name = 'app_open'
),
binned AS (
SELECT channel,
CASE WHEN day - prev_day <= 3 THEN day - prev_day
WHEN day - prev_day <= 7 THEN 4
WHEN day - prev_day <= 14 THEN 8
ELSE 15 END AS bin_start
FROM opens
WHERE prev_day IS NOT NULL AND channel IN ('organic', 'partner')
)
SELECT bin_start,
COUNT(*) FILTER (WHERE channel = 'organic') AS organic,
COUNT(*) FILTER (WHERE channel = 'partner') AS partner,
ROUND(100.0 * COUNT(*) FILTER (WHERE channel = 'organic')
/ SUM(COUNT(*) FILTER (WHERE channel = 'organic')) OVER (), 1) AS organic_pct,
ROUND(100.0 * COUNT(*) FILTER (WHERE channel = 'partner')
/ SUM(COUNT(*) FILTER (WHERE channel = 'partner')) OVER (), 1) AS partner_pct
FROM binned
GROUP BY bin_start
ORDER BY bin_start;Типичные ошибки при построении гистограммы
Группы разного размера без нормировки. Разобрано выше: в абсолютных числах большая группа выигрывает везде, и форма распределения теряется за масштабом.
Слишком мало или слишком много интервалов. Пять широких интервалов превращают любые данные с хвостом в одну высокую ступень: на паузах первый интервал шириной 11,4 дня собирает 90,5% значений. Сотня интервалов уже одного дня на целых числах рисует гребёнку. Проверяйте два-три варианта ширины и выбирайте ту, что отвечает на вопрос.
Обрезанный хвост. Он бывает двух видов. Первый — видимый: ограничили ось или отфильтровали значения выше порога, и на краю появился обрыв. Второй коварнее — окно наблюдения. Пользователи, зарегистрированные в августе, наблюдались меньше месяца, поэтому самая длинная их пауза — 26 дней, а пауз длиннее двух недель у них 1,0% против 9,8% у июньских. Такое сравнение смешивает поведение с длиной окна: у августовских пользователей просто не было времени на долгую паузу. Сравнивайте гистограммы только при одинаковом окне наблюдения, например за первые 30 дней после регистрации у тех, кто их уже прожил.
Гистограмма средних вместо значений. Если сначала посчитать среднюю паузу каждого пользователя, а потом построить гистограмму этих средних, получится другое распределение. Самый населённый интервал сдвигается с одних суток на 4–5 дней, доля пауз длиннее 14 дней падает с 7,0% до 2,6%, стандартное отклонение — с 5,73 до 3,84. Разброс средних меньше разброса самих значений, хвост у них короче. Если вопрос про паузы, стройте гистограмму пауз; если про пользователей — так и подпишите: «средняя пауза пользователя».
Дробная ширина на целых данных. При ширине 3,56 дня одни интервалы содержат три целых значения, другие четыре, и высота столбцов скачет без причины в данных. Ширину для целых величин берите целой, а границы ставьте между значениями.
Гистограмма, ящик с усами или KDE
Ящик с усами сжимает распределение до пяти чисел. Для пауз это Q1 = 1, медиана 3, Q3 = 7, а верхний ус по правилу 1,5 IQR заканчивается на 16 днях. Всё, что дальше, — 5,3% пауз — нарисуется точками-выбросами, хотя это обычный хвост скошенного распределения. Зато пять-десять ящиков легко поставить рядом и сравнить группы, где несколько гистограмм уже не читаются. Пик на одних сутках и две вершины ящик не покажет.
KDE (ядерная оценка плотности) рисует гладкую кривую вместо столбцов и не зависит от того, где начинаются интервалы. Но у неё свой параметр — ширина окна, и она размазывает данные за их границы. На паузах scipy по правилу Скотта берёт окно 0,76 дня, и 2,8% площади кривой оказывается левее нуля, хотя отрицательных пауз не бывает, а 7,9% — левее половины дня. Для величин с жёсткой границей, целых и дискретных данных гистограмма честнее.
| График | Что показывает | Когда выбрать | Что скрывает |
|---|---|---|---|
| Гистограмма | Форму целиком: пики, хвосты, пустоты | Одна-две группы, первый взгляд на данные | Зависит от ширины и начала интервалов |
| Ящик с усами | Медиану, квартили, крайние значения | Сравнение многих групп | Число вершин, пустоты внутри |
| KDE | Гладкую оценку плотности | Наложение 2–3 групп на одном графике | Границы: заходит за ноль и минимум |
| Таблица частот | Каждое значение и его частоту | Дискретные величины с несколькими значениями | Ничего, но плохо читается на сотнях значений |
import numpy as np
import matplotlib
matplotlib.use("Agg") # рисуем в файл; в Jupyter строка не нужна
import matplotlib.pyplot as plt
from scipy import stats
# Число пауз длиной 1, 2, …, 58 календарных дней (тот же результат SQL)
counts = [7028, 3784, 2607, 1898, 1498, 1189, 958, 823, 657, 535, 426, 397,
317, 268, 214, 193, 175, 161, 139, 121, 99, 78, 56, 70, 56, 32, 47,
35, 37, 24, 19, 23, 14, 16, 16, 8, 9, 9, 4, 5, 5, 6, 6, 2, 5, 3, 3,
2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1]
x = np.repeat(np.arange(1, 59), counts)
fig, axes = plt.subplots(1, 3, figsize=(13, 3.6))
axes[0].hist(x, bins="sturges")
axes[0].set_title("Стёрджес: 16 интервалов")
axes[1].hist(x, bins=np.arange(0.5, 59.5), density=True)
axes[1].set_title("По суткам, доля на день")
axes[2].hist(x, bins=2 ** np.arange(0, 7), density=True)
axes[2].set_xscale("log", base=2)
axes[2].set_yscale("log")
axes[2].set_title("Удваивающиеся интервалы, лог. оси")
for ax in axes:
ax.set_xlabel("Пауза между открытиями, дней")
fig.tight_layout()
fig.savefig("gistogramma-pauz.png", dpi=150)
# Ящик с усами и KDE на тех же данных
q1, med, q3 = np.percentile(x, [25, 50, 75])
upper = q3 + 1.5 * (q3 - q1)
print(f"Q1={q1:.0f} медиана={med:.0f} Q3={q3:.0f}, ус до {upper:.0f}; "
f"за усом {100 * np.mean(x > upper):.1f}% пауз")
kde = stats.gaussian_kde(x)
print(f"KDE: ширина окна {kde.factor * x.std(ddof=1):.2f} дня, "
f"доля плотности ниже 0,5 дня {100 * kde.integrate_box_1d(-np.inf, 0.5):.1f}%, "
f"ниже нуля {100 * kde.integrate_box_1d(-np.inf, 0):.1f}%")Как построить гистограмму в Excel
В Excel 2016 и новее статистическая гистограмма строится без ручного подсчёта интервалов. Порядок такой.
- Выделите столбец с числами, без текста и пустых ячеек.
- Вкладка «Вставка» → группа статистических диаграмм → «Гистограмма». Не путайте с кнопкой гистограммы в группе обычных диаграмм: это столбчатая диаграмма.
- Щёлкните правой кнопкой по горизонтальной оси → «Формат оси». Там задаются ширина интервала или их число, а также отдельные интервалы для всего, что выше или ниже заданного порога, — так собирают хвост в один столбец, как
capв SQL-запросе выше. - По умолчанию Excel считает ширину по правилу Скотта, которое рассчитано на нормальные данные. Для скошенных величин и целых чисел задайте ширину сами.
Частые вопросы
Чем гистограмма отличается от столбчатой диаграммы?
Гистограмма показывает распределение одной числовой величины по интервалам, столбцы стоят вплотную и порядок задан шкалой. Столбчатая диаграмма сравнивает категории, порядок столбцов можно менять. В русском Excel столбчатая диаграмма тоже называется «Гистограмма», поэтому уточняйте, что от вас хотят.
Сколько интервалов должно быть в гистограмме?
Для первого взгляда — по правилу Стёрджеса (log₂ n + 1) на небольших выборках и по правилу Фридмана — Диакониса на больших. Затем проверьте 2–3 соседние ширины. Для целых величин ширина должна быть целой, для округлённых — кратной шагу округления.
Что откладывается по оси Y гистограммы?
Число значений в интервале, их доля или плотность. Доля нужна для сравнения групп разного размера, плотность — когда интервалы разной ширины или поверх рисуется теоретическая кривая.
Как построить гистограмму распределения в Python?
plt.hist(x, bins=...) в matplotlib или np.histogram(x, bins=...), если нужны сами числа. Без параметра bins вы получите 10 интервалов; передайте правило ("fd", "sturges") или массив границ.
Что значат два пика на гистограмме?
Почти всегда смесь двух групп: будни и выходные, новые и старые пользователи, два тарифа. Найдите признак, который их разделяет, и постройте гистограммы по отдельности.
Итог
Гистограмма — первый график, который стоит построить по новой числовой величине. Она за минуту показывает, можно ли описывать данные средним, есть ли хвост, смешаны ли группы и откуда взялись выбросы. Ширину интервала выбираете вы, поэтому смотрите на два-три варианта, нормируйте группы разного размера, а длинный хвост показывайте на растущих интервалах с плотностью.
Все запросы из статьи выполняются на учебной базе «Маяк». На той же базе в Симуляторе SQL-аналитика считают метрики продукта от первого запроса до записки менеджеру.
Материалы по теме

Логарифмическая шкала: что это, как читать график и когда она нужна
Логарифмическая шкала — ось, где равные отрезки означают равные отношения. Как читать такой график, когда он нужен и когда вредит, как построить в Excel, Python и SQL.

Визуализация данных: принципы, ошибки и инструменты
Как превратить расчёт в понятный график: восприятие, масштаб, подписи, цвет, аннотация и проверка. На бронированиях показываем честный и ложный вывод.
Среднее, медиана и мода: какую середину ставить в отчёт
Почему средний чек врёт на данных с длинным хвостом, что означает разрыв между средним и медианой, когда осмысленна мода и что ставить рядом со средним в отчёте.