Метод обратной функции

У нас есть равномерные числа из [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:

  1. Взять CDF целевого распределения F(x) — формулу, описывающую накопленную вероятность.
  2. Приравнять её к равномерному числу: F(x) = u, где u взято из random.random().
  3. Решить уравнение относительно 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; для нормального распределения, например, аналитической обратной функции нет.
Проверьте себя
1. Что лежит в основе метода обратной функции?
AБерут равномерное u и подставляют его в обратную функцию распределения, получая выборку нужного распределения
BБерут любое число и умножают его на плотность распределения
CСкладывают много равномерных чисел и усредняют их
DГенерируют точки в прямоугольнике и отбрасывают лишние
2. Каким будет правильный порядок шагов рецепта метода обратной функции?
AВзять плотность, продифференцировать её, подставить u
BВзять CDF F(x), приравнять её к равномерному u, решить уравнение относительно x
CСгенерировать точки в прямоугольнике, принять те, что под кривой
DВзять среднее распределения и прибавить случайный шум
3. Почему в формуле для экспоненциального распределения используют ln(1 − u), а не ln(u)?
AПотому что 1 − u даёт другое распределение, чем u
BПотому что ln(u) считается медленнее
CПотому что 1 − u при random.random() строго положителен и страхует от ln(0)
DПотому что иначе результат станет отрицательным
4. Почему метод обратной функции нельзя напрямую применить к нормальному распределению?
AУ нормального распределения нет функции распределения
BЕго CDF не выражается обратимой функцией в элементарных функциях
CНормальное распределение не является случайным
DДля него не существует равномерных чисел