# Немного про Байесовскую статистику ## Задача Представим, что у нас есть монета, честность которой нам неизвестна (если быть точным, мы не знаем с каким шансом выпадает орёл, с каким — решка). Поэтому мы бы хотели оценить вероятность $p$ — шанс выпадения орла[^1]. В [классической статистике](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0) эта задача бы решалась бы так: - Монета подбрасывается $n$ раз. - Из них $m$ — количество выпавших орлов. - Отношение $\frac{m}{n}$ будет оценкой $p$. В [Байесовской статистике](https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D0%B9%D0%B5%D1%81%D0%BE%D0%B2%D1%81%D0%BA%D0%B0%D1%8F_%D1%81%D1%82%D0%B0%D1%82%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0) подход иной: 1. Обозначим монету как [бернуллевскую случайную величину](https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%91%D0%B5%D1%80%D0%BD%D1%83%D0%BB%D0%BB%D0%B8) $\xi$ с параметром $\theta$, у которой $1$ — это выпадение орла, $0$ — решки. 2. Предполагается априорное распределение $\pi(\theta)$ (т.е. распределение, которое мы предполагаем, исходя из того, что нам известно о параметре $\theta$), как правило, это [равномерное распределение](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%BF%D1%80%D0%B5%D1%80%D1%8B%D0%B2%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5) $U \left(0,1\right)$. 3. Монета подбрасывается. 4. Распределение $\theta$ уточняется по формуле[^2]: $$\Large \pi(\theta | \xi) = \frac{p(\xi|\theta)p(\theta)} {\int\limits_{\Theta}p(\xi|\theta)p(\theta)d\theta} $$ 5. Повторить пункты 2-4, предполагая $\pi(\theta) = \pi(\theta|\xi)$ Тогда оценкой $\theta$ будет: $$\Large \hat \theta = \arg \max_\theta \pi ( \theta | \xi ) $$ Иначе говоря, [мода](https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B0_%28%D1%81%D1%82%D0%B0%D1%82%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0%29) апостериорного распределения. Мы, в качестве априорного распределения, взяли [Бета-распределения](https://ru.wikipedia.org/wiki/%D0%91%D0%B5%D1%82%D0%B0-%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5) $Beta(2,2)$. В таком случае, если на $i$-ом шаге мы имеем: $$\Large \theta \sim Beta \left( \alpha_i, \beta_i \right) $$ то апостериорное распределение будет: $$\Large Beta \left( \alpha_i, \beta_i \right) = \begin{cases} Beta \left( \alpha_i + 1, \beta_i \right), &\xi_i = 1 \\ Beta \left( \alpha_i, \beta_i + 1 \right), &\xi_i = 0 \\ \end{cases} $$ Тогда не нужно интегрировать на каждом шаге, что существенно упрощает вычисления. ## Решение Приведем решение на `python`. ### Библиотеки Сначала нужно импортировать и настроить библиотеки: ```python import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from tqdm import tqdm plt.rcParams.update({'font.size': 14}) ``` ### Константы и функции Обозначим константы: - `p` — истинная вероятность выпадения орла. - `NMODEL` — количество бросков монеты. ```python p = 0.523 NMODEL = 7501 ``` Введем функции: - `beta` — объект для Бета-распределения - `coin` — функция одиночного броска монеты ```python from scipy.stats import beta coin = lambda: np.random.binomial(n=1, p=p) ``` ### Моделирование В качестве априорного распределения тут используется Бета-распределение $Beta(2,2)$. Это сделано потому, что расчет моды накладывает ограничение, что оба параметра должны быть строго больше 1. Мода расчитывается по формуле: $$\Large \text{Mode} = \frac{\alpha - 1}{\alpha + \beta - 2} $$ ```python alphas = np.zeros(NMODEL) betas = np.zeros(NMODEL) alphas[0], betas[0] = 2,2 for i in tqdm(range(1, NMODEL)): A = coin() if A == 0: betas[i] = 1 else: alphas[i] = 1 betas = np.cumsum(betas) alphas = np.cumsum(alphas) Es = (alphas - 1) / (alphas + betas - 2) ``` ### График #### Мода Построим график зависимости моды от количества бросков. ```python fig, ax = plt.subplots(1, 1, figsize=(10,8), dpi=80) sns.lineplot(x=np.arange(NMODEL), y=Es, ax=ax, label=r"arg$\max_p \; f(p|\mathbb{X})$", ) sns.lineplot(x=np.arange(NMODEL), y=p, ax=ax, label=r"Истинное $p = {:.3f}$".format(p)) ax.grid() ax.set(ylabel=r"$E(p|\mathbb{X})$", xlabel=r"$i$"); ``` ![mode.jpg](assets/baes/mode.jpg) Гифка Сделаем гифку на тему. Сначала нужно импортировать библиотеку `imageio` и зададим шаг `STEP` (так как, потом нужно будет сохранять каждый график в опертивной памяти, что проблематично при большом `NMODEL`): ```python import imageio STEP = NMODEL//150 ``` После, создадим список функций плотности вероятности: ```python pi = [] for i in tqdm(range(0, NMODEL)): pi.append(beta(alphas[i], betas[i])) ``` И по ним сделаем gif-изображение: ```python def create_frame(i): fig, ax = plt.subplots(1, 1, figsize=(10,8), dpi=80) x = np.linspace(0,1,500) y = pi[i].pdf(x) i_max = np.argmax(y) x_max = x[i_max] y_max = y[i_max] ax.grid() ax.plot(x,y, label=r"$f(p|\mathbb{X})$") ax.axvline(x = p, color = 'red', label = f"Истинное $p={p}$") plt.scatter([x_max], [y_max], color="green", marker="o", label=r"Мода $f(p|\mathbb{X})$") plt.xlim([0,1]) plt.xlabel('x', fontsize = 14) plt.ylim([0,100]) plt.ylabel(r'$f(p|\mathbb{X})$', fontsize = 14) plt.title(r'Распределение p, $i={}$'.format(i+1), fontsize=14) ax.legend() plt.savefig(f'./img/img_{i:04d}.png', transparent = False, facecolor = 'white' ) plt.close() for i in tqdm(range(0, NMODEL, STEP)): create_frame(i) frames = [] for i in tqdm(range(0, NMODEL, STEP)): image = imageio.v2.imread(f'./img/img_{i:04d}.png') frames.append(image) imageio.mimsave('./distributions.gif', frames, fps = 30) ``` Результат: ![gif](assets/baes/video.gif) [^1]: Понятно, что вероятность выпадения решки равна $1 - p$ [^2]: $p(\theta|\xi)$ -- это функция правдоподобия.