Ансамбли прогонов и доверительные интервалы
Вы запустили стохастическую модель один раз и получили результат 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] очерчивает разброс результата.
- Результат внутри интервала неотличим от шума; выход за пределы — повод заподозрить реальный эффект. Всегда прогоняйте стохастическую модель много раз и приводите разброс.