\(Z\)-критерій

Прикладний статистичний аналіз

Ігор Мірошниченко

КНУ імені Тараса Шевченка, ФІТ

Критерії порівняння середніх

Навіщо аналізувати середні?

  1. Приріст виручки.
    • Якщо зростає сумарне значення \(\rightarrow\) зростає середнє значення. Тому це завдання можна переформулювати як зростання середнього чека, або ARPU.
  2. Збільшення числа покупок.
  3. Зменшення відтоку користувачів.

Далі, для виведення всіх критеріїв нам потрібен нормальний розподіл. Потому що саме цьому розподілу підпорядковується середнє вибірок.

Нормальний розподіл

Нормальний розподіл \(\xi \sim \mathcal{N}(\mu, \sigma^2)\) — неперервний розподіл, у якому щільність спадає зі збільшенням відстані від \(\mu\) за експонентою квадрата.

\[ f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp^{-\frac{1}{2}\left(\frac{x-\mu}{\sigma}\right)^2} \]

де

  • \(\mu\) — параметр зміщення: наскільки центр зсунутий відносно 0
  • \(\sigma^2\) — параметр масштабу: наскільки «пологим» буде графік розподілу

Python та нормальний розподіл

Нехай ми хочемо задати розподіл \(\mathcal{N}(\mu, \sigma^2)\). Для цього є клас norm.

Параметри ініціалізації

  • loc — це \(\mu\)
  • scale — це \(\sigma\), або стандартне відхилення. Не дисперсія!

Методи класу:

  • norm().cdf(x) — функція розподілу в точці x. \(P(\xi \leq x)\)
  • norm().ppf(q) — отримати квантиль розподілу
  • norm().pdf(x) — отримати щільність розподілу в точці x.

Python та нормальний розподіл

# ініціалізація
stand_norm = norm(loc=0, scale=1)

# кумулятивна функція розподілу
print(f"P(X <= 2)  = {stand_norm.cdf(x=2)}")
print(f"или так {norm(loc=0, scale=1).cdf(x=2)}")
# можна вказувати масиви
print(f"[P(X <= 2), P(X <= -1)] = {stand_norm.cdf([2, -1])}")
P(X <= 2)  = 0.9772498680518208
или так 0.9772498680518208
[P(X <= 2), P(X <= -1)] = [0.97724987 0.15865525]


# квантиль
print(f"quantile 0.975 = {stand_norm.ppf(0.975)}")
quantile 0.975 = 1.959963984540054


# щільність
print(f"pdf(0) = {stand_norm.pdf(0)}")
pdf(0) = 0.3989422804014327

Python та нормальний розподіл

Код
numpy.random.seed(2024)

check_distr = norm(loc=0, scale=2)
x = numpy.linspace(-8, 8, 1000) # розставить на рівних відстанях одна від одної 1000 точок від -8 до 8
pdf = check_distr.pdf(x)
cdf = check_distr.cdf(x)
sample = check_distr.rvs(10000)

pyplot.figure(figsize=(22, 5))

pyplot.subplot(1, 2, 1)
pyplot.title('Візуалізація щільності', fontsize=12, color=slate)
pyplot.hist(sample, bins='auto', density=True, alpha=0.6, label='згенеровані значення') # rvs
pyplot.plot(x, pdf, label='щільність розподілу') # pdf
pyplot.legend(fontsize=12)
pyplot.subplot(1, 2, 2)
pyplot.plot(x, cdf) # cdf
pyplot.show()

Властивості нормального розподілу

  1. \(\xi_1 \sim \mathcal{N}(\mu_1, \sigma_1^2),\ \xi_2 \sim \mathcal{N}(\mu_2, \sigma_2^2) \Rightarrow \\ \xi_1 + \xi_2 \sim \mathcal{N}(\mu_1 + \mu_2, \sigma_1^2 + \sigma_2^2)\)1

  2. \(a \xi_1 \sim \mathcal{N}(a\mu_1, a^2\sigma_1^2)\)

Python та перша властивість нормального розподілу

# приклади
first_mean = 3
first_var = 4

second_mean = -1
second_var = 2

first_dist = norm(loc=first_mean, scale=numpy.sqrt(first_var))
second_dist = norm(loc=second_mean, scale=numpy.sqrt(second_var))
# Важливо scale=numpy.sqrt(first_var + second_var)
checking_sum_distr = norm(loc=first_mean + second_mean, scale=numpy.sqrt(first_var + second_var))
  1. Згенеруємо вибірку з 1 і 2 розподілів та підсумуємо їх.
  2. Далі, побудуємо емпіричну щільність розподілу та порівняємо її зі справжньою на графіку.

Python та перша властивість нормального розподілу

Код
first_sample = first_dist.rvs(10000)
second_sample = second_dist.rvs(10000)
sum_sample = first_sample + second_sample

x = numpy.linspace(-8, 12, 1000)

pyplot.figure(figsize=(10, 5))
pyplot.title('Перевірка розподілів', fontsize=12)
# Ця функція будує як гісторгамму значень, так і емпіричний розподіл
distplot(sum_sample, label='Емпіричний розподіл')
pyplot.plot(x, checking_sum_distr.pdf(x), label='Перевірюваний розподіл')
pyplot.legend(fontsize=12)
pyplot.xlabel('X', fontsize=12)
pyplot.ylabel('Щільність', fontsize=12)
pyplot.show()

Центральна гранична теорема

Нехай \(\xi_1, ..., \xi_n\)незалежно однаково розподілені випадкові величини, в яких існують мат. сподівання та дисперсія:

  • \(E [\xi_i] = \mu < \infty\)
  • \(Var[\xi_i] = \sigma^2 < \infty\).

Тоді \(\sqrt{n}\dfrac{\overline \xi - \mu}{\sqrt{\sigma^2}}\) сходиться за розподілом до \(\mathcal{N}(0, 1)\).

Центральна гранична теорема

  • \(\xi\) — випадкова величина з невідомим розподілом.
  • \(\mathbb{E}(\xi) = \mu\) — математичне сподівання.
  • \(\text{Var}(\xi) = \sigma^2\) — дисперсія.


  • \(\sum_{i=1}^n \xi_i \sim \mathcal{N}(n\mu, n\sigma^2)\)
  • \(\frac{\sum_{i=1}^n \xi_i}{n} = \bar{\xi} \sim \mathcal{N}(\mu, \frac{\sigma^2}{n})\)

Приведемо цей результат до стандартного нормального розподілу: віднімемо математичне сподівання та поділимо на \(\frac{\sigma}{\sqrt{n}}\).

  • \(\bar{\xi} - \mu \sim \mathcal{N}(0, \frac{\sigma^2}{n})\)

\[\sqrt{n} \frac{\bar{\xi} - \mu}{\sigma} \sim \mathcal{N}(0, 1)\]

Примітка

Випадкові величини можуть бути слабко залежні одна від одної і злегка по-різному розподілені. Центральна гранична теорема все ще буде правильною.

Візуалізація ЦГТ

Генеруємо \(N\) вибірок по \(M\) елементів у кожній:

  • По кожній вибірці треба порахувати нормовану середню за \(M\) елементами.
  • У підсумку ми отримаємо вибірку з N елементів.
  • Вона і має бути з нормального розподілу.
Код
def visualize_CLT(sample_generator, expected_value, variance):
    """
        Функція-візуалізатор ЦГТ. Будує:
            - гісторгаму статистики ЦГТ,
            - емпіричну щільність,
            - щільність нормального розподілу.
        Параметри:
            - sample_generator: функція-генератор вибірки. Не приймає нічого на вхід
            - expected_value: мат. сподівання вибірки
            - variance: дисперсія вибірки
    """

    numpy.random.seed(2024)
    N = 5000
    clt_sample = []
    for _ in range(N):
        # генеруємо N разів вибірку
        sample = sample_generator()

        # рахуємо статистику з ЦГТ
        sample_size = len(sample)
        statistic = numpy.sqrt(sample_size) * (numpy.mean(sample) - expected_value) / numpy.sqrt(variance)

        #зберігаємо
        clt_sample.append(statistic)

    x = numpy.linspace(-4, 4, 1000)
    pyplot.figure(figsize=(10, 5))
    pyplot.title('Розподіл середніх значень', fontsize=12)
    seaborn.distplot(clt_sample, label='Емпіричний розподіл')
    pyplot.plot(x, norm().pdf(x), label='$\mathcal{N}(0, 1)$')
    pyplot.legend(fontsize=12)
    pyplot.xlabel('X', fontsize=12)
    pyplot.ylabel('Щільність', fontsize=12)
    pyplot.show()

Візуалізація ЦГТ: біноміальний розподіл

def binom_generator(p, n, size):
    return binom(p=p, n=n).rvs(size)

p = 0.01
n = 20
size = 5000

# ми обертаємо binom_generator в lambda, щоб функція не приймала параметри на вхід
visualize_CLT(lambda: binom_generator(p, n, size), 
              expected_value = p * n, 
              variance = n * p * (1 - p)
             )

😊
def binom_generator(p, n, size):
    return binom(p=p, n=n).rvs(size)

p = 0.01
n = 20
size = 40

# ми обертаємо binom_generator в lambda, щоб функція не приймала параметри на вхід
visualize_CLT(lambda: binom_generator(p, n, size), 
              expected_value = p * n, 
              variance = n * p * (1 - p)
             )

🤨

Візуалізація ЦГТ: експоненційний розподіл

Код
def expon_generator(expected_value, size):
    return expon(scale=expected_value).rvs(size)

expected_value = 24
size = 400

visualize_CLT(lambda: expon_generator(expected_value, size), 
              expected_value=expected_value, variance=expected_value ** 2)

Еквівалентні формулювання ЦПТ

\[\begin{align} \sqrt{n}\dfrac{\overline \xi - \mu}{\sqrt{\sigma^2}} &\sim \mathcal{N}(0, 1) \stackrel{вл. 2}{\Leftrightarrow}\\ \overline \xi - \mu &\sim \mathcal{N}\left(0, \dfrac{\sigma^2}{n} \right) \Leftrightarrow\\ \dfrac{\underset{i=1}{\overset{n}{\sum}} \xi_i}{n} &\sim \mathcal{N}\left(\mu, \dfrac{\sigma^2}{n} \right) \Leftrightarrow\\ \underset{i=1}{\overset{n}{\sum}} \xi_i &\sim \mathcal{N}\left(n \cdot \mu, n \cdot \sigma^2 \right) \end{align}\]

\(Z\)-критерій Фішера

📈 Задача 🚚: біноміальний розподіл

  • \(T(X^n) = \underset{i=1}{\overset{n}{\sum}} X_i,\ T \overset{H_0}{\sim} \text{Binom} (n, \mu_0)\)
  • Нехай реалізація \(T(X^n) = t\). Минулого разу 19.
  • \(\text{p-value} = P_{H_0}(T(X^n) \geq t) = 1 - P_{H_0}(T(X^n) < t)\)
  • Або, якщо переписати мовою Python p-value = 1 - binom.cdf(t - 1, n, mu0)
def get_pvalue_by_old_logic(n, mu0, t):
    return 1 - binom.cdf(t-1, n=n, p=mu0)

n = 30
mu0 = 0.5
t = 19

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-значення, отримане за старою, коректною формулою: {old_p_value}")
p-значення, отримане за старою, коректною формулою: 0.10024421103298664

📈 Задача 🚚: нормальний розподіл

  • За досить великого розміру вибірки \(\underset{i=1}{\overset{n}{\sum}} X_i \sim \mathcal{N}\left(n \cdot \mu_0, n \cdot \sigma^2 \right)\),
  • \(X_i \overset{H_0}{\sim} \text{Bernoulli} (\mu_0)\)
  • \(\sigma^2 = \mu_0 \cdot (1 - \mu_0)\)
  • \(\text{p-значення} = P_{H_0}(T(X^n) \geq t)\).

Або p-value = 1 - norm(loc=sum_mu, scale=sum_std).cdf(t).

При цьому цього разу ми дивимося статистику не в точці t-1, як робили раніше, а в точці t. Так як у нас неперервний розподіл, то нам не потрібно віднімати 1:

  • у разі нормального розподілу: \(P(T(X^n) \geq t) = P(T(X^n) > t) = 1 - P(T(X^n) \leq t)\);
  • у разі біноміального розподілу: \(P(T(X^n) \geq t) = 1 - P(T(X^n) \leq t - 1)\).

Біноміальний vs. нормальний розподіл

📈 Задача 🚚: нормальний розподіл

def get_pvalue_by_normal_approx(n, mu0, t):
    sum_mu = n * mu0
    sum_variance = n * mu0 * (1 - mu0)
    sum_std = numpy.sqrt(sum_variance)

    return 1 - norm(loc=sum_mu, scale=sum_std).cdf(t)

normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
p-value, отримане з наближення нормальним розподілом: 0.07206351740800765



n = 3000
mu0 = 0.5
t = 1544

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
p-value, отримане за старою, коректною формулою: 0.056090883742957565
p-value, отримане з наближення нормальним розподілом: 0.05406527265575145

\(Z\)-критерій Фішера

\(H_0: \mu = \mu_0\ vs.\ H_1: \mu > \mu_0\)

  • Статистика \(Z(X) = \sqrt{n}\dfrac{\overline X - \mu_0}{\sqrt{\sigma^2}}\)
  • За досить великого розміру вибірки \(Z(X) \overset{H_0}{\sim} \mathcal{N}(0, 1)\) (за ЦГТ)
  • Односторонній критерій: \(\left\{Z(X) \geq z_{1 - \alpha} \right\}\)
    • p-value = \(1 - \Phi(z)\), де \(z\) — реалізація статистики \(Z(X)\), \(\Phi(z)\) — функція розподілу \(\mathcal{N}(0, 1)\)
  • Двосторонній критерій: \(\left\{Z(X) \geq z_{1 - \frac{\alpha}{2}} \right\} \bigcup \left\{Z(X) \leq -z_{1 - \frac{\alpha}{2}} \right\}\)
    • p-value = \(2\cdot \min \left[{\Phi(z), 1 - \Phi(z)} \right]\), де \(z\) — реалізація статистики \(Z(X)\)

Python та \(Z\)-критерій Фішера: мала вибірка

def z_criterion_pvalue(sample_mean, sample_size, mu0, variance):
    Z_statistic = numpy.sqrt(sample_size) * (sample_mean - mu0) / numpy.sqrt(variance)
    return 1 - norm().cdf(Z_statistic)

n = 30
t = 19
mu0 = 0.5
variance = mu0 * (1 - mu0)

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-значення, отримане за старою, коректною формулою: {old_p_value}")
normal_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-значення, отримане з наближення нормальним розподілом: {normal_p_value}")
z_pvalue = z_criterion_pvalue(t/n, n, mu0, variance)
print(f"Z-тест p-value: {z_pvalue}")
p-значення, отримане за старою, коректною формулою: 0.10024421103298664
p-значення, отримане з наближення нормальним розподілом: 0.07206351740800765
Z-тест p-value: 0.07206351740800765

Python та \(Z\)-критерій Фішера: більша вибірка

def z_criterion_pvalue(sample_mean, sample_size, mu0, variance):
    Z_statistic = numpy.sqrt(sample_size) * (sample_mean - mu0) / numpy.sqrt(variance)
    return 1 - norm().cdf(Z_statistic)

n = 3000
t = 1544
mu0 = 0.5
variance = mu0 * (1 - mu0)

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-значення, отримане за старою, коректною формулою: {old_p_value}")
normal_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-значення, отримане з наближення нормальним розподілом: {normal_p_value}")
z_pvalue = z_criterion_pvalue(t/n, n, mu0, variance)
print(f"Z-тест p-value: {z_pvalue}")
p-значення, отримане за старою, коректною формулою: 0.056090883742957565
p-значення, отримане з наближення нормальним розподілом: 0.05406527265575145
Z-тест p-value: 0.054065272655750785

Поправка на неперервність

Чи можна уточнити результати \(Z\)-тесту для біноміального розподілу за малих розмірів вибірок?

  • \(Z\)-тест: \(p\)-значення = 0.07
  • Точний \(p\)-значення = 0.10

Для початку давайте візуалізуємо функцію p-value(t) критеріїв, описаних вище:

  • p-value критерію, заснованого на нормальному наближенні
    • тут проста формула: треба реалізувати 1 - norm.cdf(t)
  • p-value біноміального критерію. Порахуємо його у 2 випадках:
    • t — неціле число. Розглянемо на прикладі
      • Нехай t=19.5. p-value \(= P(T(X) \geq t) = P(T(X) \geq 19.5) = 1 - P(T(X) < 19.5) =|P(T(X) = 19.5) = 0|= 1 - P(T(X) \leq 19.5)\). Зауважимо, що остання ймовірність — функція розподілу. Тому
        • p-value = 1 - binom.cdf(t, n, mu0)
    • t — ціле число.
      • Нехай t=19. p-value \(= P(T(X) \geq t) = P(T(X) \geq 19) = 1 - P(T(X) < 19) = 1 - P(T(X) \leq 18)\).
        • p-value = 1 - binom.cdf(t-1, n, mu0)
        • а також p-value(t) = 1 - binom.cdf(t-a, n, mu0) = p-value(t-a), де 0 < a < 1. Наприклад, p-value(19) = p-value(18.9).
    • Тобто, щоб зобразити біноміальне p-value, треба зобразити функцію p-value = 1 - binom.cdf(t, n, mu0). Значення p-value у цілих точках лежатимуть на правих кінцях вертикальних відрізків.

Поправка на неперервність

Код
def cmp_pvalue_binom_and_norm(n, mu0, t, add_to_x=0):
    """
        Функція для порівняння функцій pvalue у біноміального критерію і нормальної апроксимації.
        Будує графіки:
            - binom pvalue
            - norm pvalue
            - великими крапками позначено pvalue у точці t, отримані 2 способами.
        Параметри:
            - n: кількість значень у вибірці
            - mu0: конверсія за умови коректності нульової гіпотези
            - t: кількість доставок з оплатою
            - add_to_x: параметр для додавання до T(X) у нормальному розподілі.
    """

    x_axis = numpy.linspace(0, n, 1000)
    dots_to_show = numpy.arange(0, n + 1, 1)
    # параметри нормального розподілу
    sum_mu = n * mu0
    sum_variance = n * mu0 * (1 - mu0)
    sum_std = numpy.sqrt(sum_variance)

    # самі розподіли
    binom_dist = binom(n=n, p=mu0)
    norm_dist = norm(loc=sum_mu, scale=sum_std)

    pyplot.figure(figsize=(20, 7))
    pyplot.title('Порівняння p-value: біноміального і нормального', fontsize=12)
    # будуємо красивий дискретний бернулліївський розподіл
    # спочатку горизонтальні лінії
    pyplot.hlines(1 - binom_dist.cdf(x_axis[:-1]), x_axis[:-1],
                x_axis[1:], color=slate, linestyle='-')
    # вертикальні лінії, яких насправді немає
    pyplot.vlines(x_axis[:-1], 1 - binom_dist.cdf(x_axis[:-1]), 1 - binom_dist.cdf(x_axis[1:]),
                color=slate, linestyle=':')
    # дискретні точки в розподілі
    pyplot.scatter(dots_to_show, 1 - binom_dist.cdf(dots_to_show-1), color=slate, 
                alpha=1, linewidths=0.5,
                label=f'Binom pvalue = 1-binom.cdf(x-1)')
    # pvalue через біноміальний розподіл
    pyplot.scatter(t, 1 - binom_dist.cdf(t - 1), color=slate, marker='o',
                alpha=1, s=100, label=f'binom p-value({t})')
    # нормальний розподіл, що апроксимує, нормальний розподіл
    add_str = "" if add_to_x == 0 else f"{add_to_x}"
    pyplot.plot(x_axis, 1 - norm_dist.cdf(x_axis + add_to_x), color=red_pink, alpha=0.5,
             label=f'Normal pvalue = 1-norm.cdf(x{add_str})')
    # pvalue через нормальний розподіл
    pyplot.scatter(t, 1 - norm_dist.cdf(t + add_to_x), color=red_pink, 
                alpha=1, marker='o', s=100, label=f'norm p-value({t})')

    pyplot.legend(fontsize=12)
    pyplot.xlabel('t', fontsize=12)
    pyplot.ylabel('p-value', fontsize=12)
    pyplot.show()

cmp_pvalue_binom_and_norm(30, 0.5, 15)
  • \(p_{\text{binom}} > p_{\text{norm}}\)
  • При збільшенні розміру вибірки ці значення збігаються.

Поправка на неперервність

n = 20
t = 10

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
print(f"Різниця: {round(abs(old_p_value - normal_dist_p_value), 3)}")
p-value, отримане за старою, коректною формулою: 0.5880985260009766
p-value, отримане з наближення нормальним розподілом: 0.5
Різниця: 0.088


# При зростанні t
n = 20
t = 14

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
print(f"Різниця: {round(abs(old_p_value - normal_dist_p_value), 3)}")
p-value, отримане за старою, коректною формулою: 0.057659149169921875
p-value, отримане з наближення нормальним розподілом: 0.03681913506015133
Різниця: 0.021


# При зростанні n
n = 200
t = 100

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
print(f"Різниця: {round(abs(old_p_value - normal_dist_p_value), 3)}")
p-value, отримане за старою, коректною формулою: 0.5281742395046283
p-value, отримане з наближення нормальним розподілом: 0.5
Різниця: 0.028

Поправка на неперервність

\[F_{\text{new}}(x) = F_{\text{old}}(x - 0.5)\]

cmp_pvalue_binom_and_norm(30, 0.5, 15, add_to_x=-0.5)

Поправка на неперервність

def get_pvalue_by_normal_approx_with_addition(n, mu0, t):
    sum_mu = n * mu0
    sum_variance = n * mu0 * (1 - mu0)
    sum_std = numpy.sqrt(sum_variance)

    return 1 - norm(loc=sum_mu, scale=sum_std).cdf(t - 0.5)


n = 30
mu0 = 0.5
t = 19

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_dist_p_value = get_pvalue_by_normal_approx(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом: {normal_dist_p_value}")
normal_with_add_p_value = get_pvalue_by_normal_approx_with_addition(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом із поправкою: {normal_with_add_p_value}")
p-value, отримане за старою, коректною формулою: 0.10024421103298664
p-value, отримане з наближення нормальним розподілом: 0.07206351740800765
p-value, отримане з наближення нормальним розподілом із поправкою: 0.10062131047886202

Поправка та критерій Фішера

def z_criterion_pvalue(sample_mean, sample_size, mu0, variance, use_continuity_correction=False):
    if use_continuity_correction:
        # коригуємо значення суми, як робили це раніше
        sample_mean = (sample_mean * sample_size - 1/2) / sample_size
    Z_statistic = numpy.sqrt(sample_size) * (sample_mean - mu0) / numpy.sqrt(variance)
    return 1 - norm().cdf(Z_statistic) 

Переглянемо результати для малої вибірки:

n = 30
t = 19
mu0 = 0.5
variance = mu0 * (1 - mu0)

old_p_value = get_pvalue_by_old_logic(n, mu0, t)
print(f"p-value, отримане за старою, коректною формулою: {old_p_value}")
normal_with_add_p_value = get_pvalue_by_normal_approx_with_addition(n, mu0, t)
print(f"p-value, отримане з наближення нормальним розподілом із поправкою: {normal_with_add_p_value}")
z_pvalue = z_criterion_pvalue(t/n, n, mu0, variance, use_continuity_correction=True)
print(f"Z-тест p-value: {z_pvalue}")
p-value, отримане за старою, коректною формулою: 0.10024421103298664
p-value, отримане з наближення нормальним розподілом із поправкою: 0.10062131047886202
Z-тест p-value: 0.10062131047886202

Підсумок

У цьому занятті ми:

  • Пригадали, що таке нормальний розподіл і які в нього є властивості.
  • Згадали, як формулюється Центральна гранична теорема і як її можна використовувати.
  • Дізналися про \(Z\)-критерій Фішера і розв’язали за його допомогою задачу про конверсії.
    • Крім того, на практиці побачили, що таке поправка на неперервність і навіщо вона потрібна.
    • Єдине але: в цьому критерії потрібно знати дисперсію вибірки. Але на практиці вона не завжди відома.

Дякую за увагу!



Матеріали курсу

ihor.miroshnychenko@knu.ua

Data Mirosh

@ihormiroshnychenko

@aranaur

aranaur.rbind.io