websitelytics

Menu

Потайная дверь в A/B тестирование, часть 2 - PDF, CDF

Опубликовано: 08 сен 2021

В части первой была представлена концепция генерирования данных для построения модели A/B теста. Идея заключается в следующем - если мы можем описать наши реальные данные с помощью модели, мы можем изучать эту модель и проверять правильность наших методик оценки результатов эксперимента.

Disclaimer: эта статья скорее представляет из себя рассуждения и нуждается в дальнейшей проверке.

Давайте посмотрим на то, что можно взять за основу такой модели данных. На мой взгляд — это Probability density function (функция плотности вероятности), которая задаёт отношение вероятностей для непрерывной случайной величины. Другими словами она показывает участки (интервалы), где вероятность попадания случайной величины больше или меньше, и мы можем визуализировать это с помощью кривой.

PDF, немного теории

Вероятность попадания случайной величины в интервал между a и b равна площади S под графиком функции плотности вероятности f(x).

Чтобы пример с непрерывной случайной величиной был нагляднее, давайте также вспомним, что могла бы представлять из себя функция "плотности" вероятности для дискретной величины (здесь мы не можем говорить о плотности в том же смысле, что и для непрерывной величины, поэтому слово взято в кавычки).

Рассмотрим классический пример игрального кубика (d6).

import numpy as np
from matplotlib import pyplot as plt
import matplotlib.ticker as mtick
2021-09-08T06:06:57.841367 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

Чтобы посчитать вероятность выпадания, к примеру, 3 или 4 (одного из двух) нужно просто просуммировать вероятности всех удовлетворяющих нас результатов: 1/6+1/6=1/3 или ~ 33,33%. Вероятность выпадания любого значения соответственно равна 1/6+1/6+1/6+1/6+1/6+1/6 = 1.

Для непрерывной величины, мы не можем применить простое сложение, но по аналогии мы можем проинтегрировать функцию плотности:

$$ \int_{-\infty}^{\infty} f(x) \; dx = 1. $$

Случайная величина должна принимать некоторое число, соответственно значение интеграла на всем множестве равно 1.

И для любого интервала вероятность попадания случайной величины между a и b:

$$ P(X\in(a, b]) = \int _ {a}^{b} f(x) \; dx. $$

Мы можем аппроксимировать это в коде, используя методы дискретной аппроксимации. В этом случае мы можем приблизительно оценить вероятность попадания в закрашенную область:

# Approximate probability using numerical integration
epsilon = 0.01
x = np.arange(-5, 5, 0.01)

#the probability density function for some random variable
p = 0.2*np.exp(-(x - 3)**2 / 2) / np.sqrt(2 * np.pi) + \
    0.8*np.exp(-(x + 1)**2 / 2) / np.sqrt(2 * np.pi)

plt.plot(x, p)
plt.fill_between(x.tolist()[300:800], p.tolist()[300:800])
plt.ylabel("Плотность")
plt.xlabel("х")
plt.show()
f'Аппроксимированная вероятность: {np.sum(epsilon*p[300:800])}' # Approximate the integral of the PDF
2021-09-08T06:06:58.088723 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
'Аппроксимированная вероятность: 0.7736171925899021'
#аппроксимированная вероятность выпадания любого значения (в реале = 1)
np.sum(epsilon*p)
0.9953709966191726

PDF и типы распределения

Примеры распределений:

Нормальное распределение

Построим PDF (функцию плотности вероятности) нормального распределения. Функция следующая:

$$\mathcal{N}(x \mid \mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2} } e^{ -\frac{(x-\mu)^2}{2\sigma^2} }$$

Где

PDF с помощью python и matplotlib:

dist_norm = np.random.normal(0,1,1000) # Mean, Standard deviation, Size
import seaborn as sns
g = sns.displot(dist_norm, kind="kde", aspect=5/3)
g.set(ylim=(-0.02, 0.6));
2021-09-08T06:06:58.511131 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

Другой способ создания выборки с помощью модуля stats.norm:

from scipy import stats

Создаем объект dist_norm2, представляющий нормальное распределение со средним значением 0 и стандартным отклонением 1.

dist_norm2 = stats.norm(0, 1) # Mean, Standard deviation

И используем его, чтобы нарисовать выборку из 1000 значений, как и в примере выше.

sample = dist_norm2.rvs(1000) # Выборка с размером 1000
sample.mean(), sample.std()
(0.009605850578821618, 1.0040143072264596)
g = sns.displot(sample, kind="kde", aspect=5/3)
g.set(ylim=(-0.02, 0.6));
2021-09-08T06:06:58.912597 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

График PDF самого распределения из которого была сделана выборка:

x = np.linspace(-4,4,80)
plt.plot(x,dist_norm2.pdf(x)); # plot x and y using default line style and color
2021-09-08T06:06:59.150578 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

CDF, как дополнение PDF.

Общая вероятность на всем поле значений равна 1 (вероятность выпадания любого значения). Этот тезис отражает функция CDF (comulative dencity). По сути это функция, отражающая вероятность того, что случайная величина X примет значение, меньшее х.

from empiricaldist import Cdf
cdf = Cdf.from_seq(sample)
cdf.plot(label='CDF выборки', lw=5)

xs = np.linspace(-4, 4)
ps = dist_norm2.cdf(xs)
plt.plot(xs, ps, label='CDF Нормального распределения', lw=2)
plt.xlabel("х")
plt.legend();
2021-09-08T06:10:49.637111 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

В этом примере мы знаем, что выборка была взята из нормального распределения, поэтому неудивительно, что кривые почти совпадают. Но если бы выборка была получена из реальных измерений, мы могли бы использовать этот рисунок, чтобы показать, что нормальное распределение хорошая модель для этих данных.

Экспоненциальное распределение

PDF для экспоненциального распределения:

$$ f(x ∣ \lambda) = \begin{cases} \frac{1}{\beta} e^{-\frac{1}{\beta} x} & x \ge 0, \\ 0 & x < 0. \end{cases}$$

где $\beta$ - scale parameter. $\frac{1}{\beta}$ часто называется rate parameter $\lambda$

Построение модели выборки с помощью модуля stats.expon

dist_expon = stats.expon(0, 1) #loc, scale
sample = dist_expon.rvs(1000) # Выборка с размером 1000
x = np.linspace(0,6,61)
g = sns.displot(sample, kind='kde', label='PDF выборки', lw=5, bw_adjust=.35)
g.set(xlim=(0.1, 6))
g.set(ylim=(-0.02,1.02))
plt.plot(x, dist_expon.pdf(x), label='PDF Экспоненциального распределения', lw=2, color='#FF5252')
plt.xlabel("х")
plt.legend();
2021-09-08T06:10:50.039060 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
cdf = Cdf.from_seq(sample)
cdf.plot(label='CDF выборки', lw=5)
plt.plot(x, dist_expon.cdf(x), label='CDF Экспоненциального распределения', lw=2)
plt.xlabel("х")
plt.legend();
2021-09-08T06:10:50.371421 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

Равномерное распределение

Если мы полагаем, что случайная величина $x$ равномерно распределена на промежутке $[a,b]$, то PDF для такого распределния будет следующей функцией:

$$ f(x ∣ a,b) = \begin{cases} \frac{1}{b-a} \quad x \in [a,b] \\ 0 \quad \quad \mathrm{вне \ интервала} \end{cases} $$

Построение модели выборки с помощью модуля stats.uniform

dist_uniform = stats.uniform(-1, 2) #loc, scale
sample = dist_uniform.rvs(1000) # Выборка с размером 1000
x = np.linspace(-3,3,61)
g = sns.displot(sample, kind='kde', label='PDF выборки', lw=5, bw_adjust=.5)
g.set(ylim=(-0.05,1.02))
plt.plot(x, dist_uniform.pdf(x), label='PDF Равномерного распределения', lw=2, color='#FF5252')
plt.xlabel("х")
plt.legend();
2021-09-08T06:10:50.754143 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/
cdf = Cdf.from_seq(sample)
cdf.plot(label='CDF выборки', lw=5)
plt.plot(x, dist_uniform.cdf(x), label='CDF Равномерного распределения', lw=2)
plt.xlabel("х")
plt.legend();
2021-09-08T06:10:51.070535 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

Нестандартные распределения

Что делать, если данные сложные и не являются явным примером какого-либо стандартного типа распределения? Например, как на графике ниже, это может быть сочитание двух нормальных распределений с разными коэффициентами.

s1 = np.random.normal(-5, 2.0, 1000)
s2 = np.random.normal(5, 3.0, 1000)
all_s = np.concatenate([s1, s2])
sns.displot(all_s, kde=True);
2021-09-08T06:10:51.487188 image/svg+xml Matplotlib v3.3.4, https://matplotlib.org/

В реальности сложное распределение может быть сочетанием не обязательно двух, но и большего количества распределений разного типа. Описание данного типа моделей выходит за рамки этой статьи.

В целом же мы видим, что процесс создания и использования модели будет состоять из нескольких шагов:

*Стоит сделать оговорку, что для реальных данных PDF может не всегда существовать. CDF - в этом плане более фундаментальна.

Понимание структуры реальных данных участвующих в эксперименте (a/b тесте), их распределения вероятности и возможность моделирования данного распределения - это дополнительные факторы, способствующие правильной оценке полученных результатов.