Python для вероятностного программирования
Как я рассказывал ранее для моделирования реальных процессов исключительно полезным инструментом являются распределения случайных величин. С их помощью определяется пространство событий и задаются вероятности, соответствующие каждому из них (например, множество голосов за/против в ходе опроса или серия A/B тестирований с результатами наличия/отсутствия конверсий).
В предыдущей статье мы разобрались с тем, как создавать распределения вероятностей, а теперь рассмотрим функции для работы с ними. Остановимся на возможностях библиотеки SciPy.
В частности, в ней реализован метод rvs, с помощью которого осуществляется случайная выборка из распределения. При этом, задав параметр size, можно запрашивать сразу массивы таких выборок. Например, получим 1000 значений из нормального распределения со средним 0 и стандартным отклонением 1:
import scipy.stats as stats
import seaborn as sns
sns.set()
loc, scale = 0,1
distr = stats.norm(loc=loc, scale = scale)
points_num=10000
distr.rvs(size=points_num)
На основе полученных 10000 значений можно построить график распределения, применяя функцию kdeplot библиотеки Seaborn (подробнее о ней я рассказывал здесь):
sns.kdeplot(distr.rvs(size=points_num), label = f'Нормальное распределение со средним {loc}\nи стандартным отклонением {scale},\nполученное путем случайной выборки {points_num} точек')
Другой важной задачей является получение значения кумулятивной функции распределения в заданной точке (вероятность того, что случайная величина не превышает этого числа), для чего используется метод cdf. Например, с помощью рассмотренного метода rvs случайно извлечем для равномерного распределения на отрезке [0,1] 1000 точек и для каждой из них посчитаем кумулятивную функцию распределения:
beg = 0
width = 1
distr = stats.uniform(loc = beg, scale = width)
points_num=10000
x = distr.rvs(size=points_num)
distr.cdf(x)
Визуализируем полученные результаты с помощью функции sns.lineplot (подробнее рассказывал здесь):
sns.lineplot(x,distr.cdf(x), label = f'Кумулятивная функция распределения\nдля равномерного распределения на отрезке [{beg},{beg+width}]')
Теперь остановимся на методах, извлекающих значение вероятности (для дискретных случайных величин) или функции плотности вероятности (для абсолютно непрерывных случайных величин) в заданных точках.
Для дискретных случайных величин мы можем извлечь вероятность точек путем вызова метода pmf. Например, зададим Пуассоновское распределение вероятности с параметром mu=3 и для 10 точек (0:9) посчитаем их вероятность с выводом значений и визуализацией на графике.
mu=3
distr = stats.poisson(mu=mu)
points_num=10
x = np.arange(10)
plt.vlines(x,0,distr.pmf(x),label = f'Пуассоновское распределение вероятности {points_num} неотрицательных\nцелых значений с параметром mu = {mu}')
plt.legend()
Для абсолютно непрерывных случайных величин (множество точек не счетно и вероятность каждой равна нулю) для визуализации распределения вероятностей применяют функцию плотности вероятности - pdf. Например, зададим ее для 10000 точек на отрезке [0,3] экспоненциального распределения с параметром lambda_=4 и отобразим результаты:
x = np.linspace(0,3,10000)
lambda_ = 4
distr = stats.expon(scale=1/lambda_)
distr.pdf(x)
plt.plot(x,distr.pdf(x), label= f'Распределение экспоненциальной случайной\nвеличины с параметром lambda_ равным {lambda_}')
plt.legend()
Полезным методом является ppf, применяемый для извлечения значения случайной величины, которое с заданной вероятностью не меньше всех других значений (квантиль, процентиль). Данное значение часто используется при различных проверках, например, истинности нулевой гипотезы (подробнее читай здесь). Давайте приведем пример для нормальной случайной величины с математическим ожиданием 0 и стандартным отклонением 1:
loc, scale = 0,1
distr = stats.norm(loc=loc, scale = scale)
distr.ppf(0.975)
distr.ppf(0.95)
Также для распределений вычисляются такие описательные статистики, как математическое ожидание, дисперсия ... (подробнее здесь). Для их получения можно воспользоваться методом stats c параметром moments. Так, для получения математического ожидания и дисперсии предыдущей случайной величины можно поступить так:
distr.stats(moments='mv')