Ансамбли прогонов и доверительные интервалы

Вы запустили стохастическую модель один раз и получили результат 3.0. Сосед запустил ту же модель и получил 4.0. Кто прав? Оба — и в этом проблема: по одному прогону случайной модели судить нельзя в принципе.

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

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

Зачем это критично. Без ансамбля вы рискуете принять случайную флуктуацию за реальный эффект: «новая стратегия дала 4.0 против старых 3.5 — она лучше!» — а на самом деле 4.0 попало в обычный разброс шума. Ансамбль и доверительный интервал отделяют настоящий сигнал от случайности.

Один прогон против ансамбля

Смоделируем простую вещь: бросаем кубик 30 раз и считаем среднее. Теоретически среднее одного броска кубика равно 3.5. Но среднее 30 бросков — случайная величина: иногда выпадет 3.1, иногда 3.9. Один такой прогон — это one_run(). Чтобы оценить, насколько он надёжен, повторим эксперимент 200 раз (это и есть ансамбль) и посмотрим на разброс между прогонами.

import random, statistics
random.seed(99)

def one_run():
    return statistics.mean(random.randint(1, 6) for _ in range(30))

runs = [one_run() for _ in range(200)]
m = statistics.mean(runs)
sd = statistics.pstdev(runs)
print(f"Прогонов: {len(runs)}")
print(f"Среднее по прогонам: {m:.3f} (теория 3.5)")
print(f"Стд между прогонами: {sd:.3f}")
print(f"95% доверительный интервал: [{m - 1.96 * sd:.2f}, {m + 1.96 * sd:.2f}]")

Вывод:

Прогонов: 200
Среднее по прогонам: 3.480 (теория 3.5)
Стд между прогонами: 0.324
95% доверительный интервал: [2.85, 4.12]

Смотрим на результат. Среднее по 200 прогонам — 3.480, почти точно теоретические 3.5: ансамбль дал надёжную оценку. А стандартное отклонение между прогонами — 0.324: вот насколько гуляет результат одного прогона. Теперь понятно, почему одному прогону доверять нельзя — отдельное one_run() вполне могло выдать и 3.0, и 4.0, и оба значения были бы «нормальными».

Доверительный интервал: среднее ± 1.96·стд

Доверительный интервал — диапазон значений, в который результат отдельного прогона попадает с заданной вероятностью; для 95% это примерно «среднее ± 1.96 стандартных отклонения».

Множитель 1.96 — это квантиль нормального распределения: около 95% значений нормально распределённой величины лежат в пределах 1.96 стандартных отклонений от среднего. Применяя его к нашему ансамблю, получаем интервал [2.85, 4.12]. Это и есть честный ответ: «среднее 30 бросков с вероятностью около 95% окажется между 2.85 и 4.12». Значение 3.0 и значение 4.0 оба внутри интервала — значит, ни одно из них не «удивительно», оба объясняются случайностью.

Как работает под капотом

Здесь работают сразу две статистические идеи. Первая — закон больших чисел: среднее по большому ансамблю (3.480) сходится к истинному значению (3.5), сглаживая случайность отдельных прогонов. Вторая — центральная предельная теорема: средние из 30 бросков распределены приблизительно нормально, поэтому к ним применимо правило «1.96·стд» для 95% интервала. statistics.pstdev считает стандартное отклонение по всему ансамблю как по генеральной совокупности прогонов. А random.seed(99) фиксирует поток случайных чисел, чтобы вывод воспроизводился точь-в-точь.

Ключевой приём — разделение уровней случайности: внутри одного прогона случайны броски, а между прогонами случайно само среднее. Доверительный интервал описывает именно второй уровень — разброс результата от прогона к прогону.

Как отличить эффект от шума

Новая стратегия дала 4.0. Реальный эффект или шум?

ДИ старой модели: [2.85, 4.12]
4.0 ВНУТРИ интервала  скорее всего просто шум, эффекта нет
4.5 ВНЕ интервала     выходит за разброс случайности, возможен реальный эффект

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

Частые ошибки

  • Делать выводы по одному прогону. Отдельная реализация стохастической модели может сильно отклоняться от истины — это не результат, а одна точка из распределения.
  • Не фиксировать seed при отладке. Без random.seed вывод нельзя воспроизвести, и баг от шума не отличить.
  • Брать слишком маленький ансамбль. На 5 прогонах оценка среднего и стд сами по себе шумные; нужны десятки-сотни запусков.
  • Сообщать только среднее без разброса. «Результат 3.48» без интервала [2.85, 4.12] скрывает, насколько он может гулять.
  • Считать любое отклонение эффектом. Значение внутри доверительного интервала неотличимо от шума — это не открытие.

Итоги

  • Один прогон стохастической модели — это одна реализация из многих; по нему судить нельзя.
  • Ансамбль (здесь 200 прогонов с разными состояниями генератора) даёт надёжную оценку: среднее 3.480 близко к теории 3.5.
  • Стандартное отклонение между прогонами (0.324) показывает, насколько гуляет отдельный прогон.
  • 95% доверительный интервал «среднее ± 1.96·стд» = [2.85, 4.12] очерчивает разброс результата.
  • Результат внутри интервала неотличим от шума; выход за пределы — повод заподозрить реальный эффект. Всегда прогоняйте стохастическую модель много раз и приводите разброс.
Проверьте себя
1. Почему нельзя делать выводы по одному прогону стохастической модели?
AОдин прогон работает слишком быстро
BЭто лишь одна случайная реализация из многих — она могла дать и 3.0, и 4.0
CОдин прогон всегда даёт ошибку
DБиблиотека random это запрещает
2. Что показывает стандартное отклонение между прогонами (0.324) в выводе?
AСреднее значение броска кубика
BНасколько результат отдельного прогона гуляет от прогона к прогону
CКоличество прогонов в ансамбле
DТеоретическое среднее 3.5
3. Откуда берётся множитель 1.96 в формуле доверительного интервала?
AЭто число прогонов делёное на 100
BЭто квантиль нормального распределения: около 95% значений лежат в пределах 1.96 стд от среднего
CЭто среднее значение кубика
DЭто случайное число
4. Новая стратегия дала результат 4.0, а ДИ базовой модели = [2.85, 4.12]. Какой вывод корректен?
AНовая стратегия точно лучше
B4.0 внутри интервала, поэтому отличие от шума не доказано
C4.0 выходит за интервал, эффект реальный
DНужно сравнивать только средние без интервалов