Метод обратной функции
У нас есть равномерные числа из [0, 1) — и есть потребность в выборках из совсем других распределений: экспоненциального для времени между отказами, нормального для шумов измерений, какого угодно. Как перекинуть мост от ровного ковра равномерности к нужной форме? Самый изящный и универсальный способ — метод обратной функции.
Метод обратной функции (inverse transform sampling) — приём генерации случайной величины с заданным распределением: берут равномерное число u из [0, 1) и подставляют его в обратную функцию распределения, получая выборку нужной формы.
В основе метода лежит одно ключевое понятие — функция распределения. Напомним: CDF (cumulative distribution function), обозначаемая F(x), — это вероятность того, что случайная величина окажется не больше x. Она всегда монотонно растёт от 0 (слева) до 1 (справа). И вот ключевое наблюдение: значения самой CDF равномерно распределены на [0, 1). Значит, если «прочитать формулу наоборот» — взять равномерное u и найти такой x, что F(x) = u, — мы получим величину как раз с нужным распределением.
Рецепт из трёх шагов
Метод сводится к универсальному алгоритму, который работает для любого распределения с обратимой CDF:
- Взять CDF целевого распределения
F(x)— формулу, описывающую накопленную вероятность. - Приравнять её к равномерному числу:
F(x) = u, гдеuвзято изrandom.random(). - Решить уравнение относительно x: выразить
x = F^(-1)(u). Полученноеxи есть выборка из нужного распределения.
Геометрически это «отражение через диагональ»: мы переходим от вопроса «какова вероятность не превысить x?» к обратному «какому x соответствует данная накопленная вероятность u?». Поскольку u бежит равномерно по [0, 1), а CDF в густонаселённых областях распределения растёт круто, туда же чаще и «приземляются» наши x — так и воспроизводится нужная плотность.
Разбор на экспоненциальном распределении
Экспоненциальное распределение — классика моделирования: им описывают время до отказа прибора, интервалы между приходами клиентов, длительность телефонного разговора. У него один параметр λ (лямбда) — интенсивность событий. Его CDF имеет вид F(x) = 1 − e^(−λx) для x ≥ 0.
Применим рецепт. Приравниваем к равномерному числу и решаем относительно x:
F(x) = u 1 − e^(−λx) = u e^(−λx) = 1 − u −λx = ln(1 − u) x = −ln(1 − u) / λ
Готова формула генерации: x = −ln(1 − u) / λ. Каждое равномерное u мы прогоняем через неё и получаем число, распределённое экспоненциально. Проверим это эмпирически: сгенерируем десять тысяч выборок при λ = 0.5 и сравним среднее с теоретическим. Для экспоненциального распределения математическое ожидание равно 1/λ, то есть при λ = 0.5 должно получиться 2.0:
import random, math, statistics
random.seed(3)
lam = 0.5
samples = [-math.log(1 - random.random()) / lam for _ in range(10000)]
print(f"Сгенерировано выборок: {len(samples)}")
print(f"Среднее выборки: {statistics.mean(samples):.4f}")
print(f"Теоретическое 1/lambda: {1 / lam}")
Вывод:
Сгенерировано выборок: 10000 Среднее выборки: 2.0107 Теоретическое 1/lambda: 2.0
Среднее выборки — 2.0107 — почти в точности совпало с теоретическим значением 2.0. Расхождение в сотых — это нормальный статистический «шум» конечной выборки; на ещё большем числе экспериментов оно стало бы ещё меньше. Метод сработал: мы взяли равномерные числа и арифметической формулой превратили их в честную экспоненциальную выборку, ни разу не обратившись к специальной функции вроде random.expovariate.
Как работает под капотом
Почему «отражение CDF» вообще даёт правильное распределение? Здесь работает фундаментальный факт теории вероятностей. Возьмём случайную величину X с непрерывной строго возрастающей CDF F. Тогда величина U = F(X) равномерно распределена на [0, 1) — этот результат называют интегральным преобразованием вероятности. Метод обратной функции просто читает его «задом наперёд»: если U равномерно, то X = F^(-1)(U) имеет ровно распределение с функцией F.
Интуиция — в скорости роста CDF. Там, где плотность распределения высокая, CDF поднимается круто: небольшому шагу по x соответствует большой шаг по вероятности. А поскольку u ложится равномерно по вертикали [0, 1), на крутые (плотные) участки приходится больше попаданий, на пологие (редкие) — меньше. Так равномерность по вертикали превращается в нужную неравномерность по горизонтали.
Маленькая, но важная деталь реализации: в формуле стоит 1 − u, а не просто u. Математически 1 − u и u распределены одинаково равномерно, так что обе версии корректны. Но 1 − u с random.random() гарантированно лежит в полуинтервале (0, 1], то есть никогда не обращается в ноль, — а ln(0) не определён. Запись через 1 − u страхует от логарифма нуля, если генератор вдруг вернёт ровно 0.0.
Частые ошибки
- Пытаться применить метод там, где CDF не обращается аналитически. Для нормального распределения обратной CDF в элементарных функциях не существует — приходится использовать численные приближения или совсем другой метод. Главное ограничение приёма: нужна обратимая (хотя бы численно) функция распределения.
- Подставлять плотность вместо функции распределения. В рецепте участвует именно CDF
F(x)(накопленная вероятность), а не плотностьf(x). Подстановка плотности даёт бессмысленный результат. - Брать ln(u) и натыкаться на ln(0). Если
random.random()вернёт ровно 0.0, тоln(0)вызовет ошибку. Запись через1 − uустраняет эту опасность, оставляя аргумент логарифма строго положительным. - Путать λ и 1/λ. Параметр
λ— это интенсивность (сколько событий в единицу времени), а среднее экспоненциального распределения равно1/λ. При λ = 0.5 среднее равно 2, а не 0.5 — лёгкая, но частая путаница. - Забывать про область определения. Экспоненциальная CDF задана для x ≥ 0; формула
−ln(1 − u)/λпри положительном λ всегда даёт неотрицательное число — и это правильно. Если знак или область перепутаны, можно получить отрицательные «времена», лишённые смысла.
Итоги
- Метод обратной функции превращает равномерное
uв выборку любого распределения с обратимой CDF:x = F^(-1)(u). - Универсальный рецепт: взять CDF, приравнять
F(x) = u, решить относительноx. - Для экспоненциального распределения это даёт формулу
x = −ln(1 − u) / λ; среднее выборки сходится к теоретическому1/λ. - Метод работает, потому что
F(X)всегда равномерно (интегральное преобразование вероятности), а крутизна CDF переносит плотность в нужные места. - Главное ограничение — нужна обратимая CDF; для нормального распределения, например, аналитической обратной функции нет.