Доверительные интервалы для двух долей


In [19]:
import numpy as np
import pandas as pd

import scipy
from statsmodels.stats.weightstats import *
from statsmodels.stats.proportion import proportion_confint

Загрузка данных


In [20]:
data = pd.read_csv('banner_click_stat.txt', header = None, sep = '\t')
data.columns = ['banner_a', 'banner_b']

In [21]:
data.head()


Out[21]:
banner_a banner_b
0 0 0
1 1 1
2 0 0
3 0 0
4 0 0

In [22]:
data.describe()


Out[22]:
banner_a banner_b
count 1000.000000 1000.000000
mean 0.037000 0.053000
std 0.188856 0.224146
min 0.000000 0.000000
25% 0.000000 0.000000
50% 0.000000 0.000000
75% 0.000000 0.000000
max 1.000000 1.000000

Интервальные оценки долей

$$\frac1{ 1 + \frac{z^2}{n} } \left( \hat{p} + \frac{z^2}{2n} \pm z \sqrt{ \frac{ \hat{p}\left(1-\hat{p}\right)}{n} + \frac{z^2}{4n^2} } \right), \;\; z \equiv z_{1-\frac{\alpha}{2}}$$


In [23]:
conf_interval_banner_a = proportion_confint(sum(data.banner_a), 
                                            data.shape[0],
                                            method = 'wilson')
conf_interval_banner_b = proportion_confint(sum(data.banner_b), 
                                            data.shape[0],
                                            method = 'wilson')

In [24]:
print ('interval for banner a [%f, %f]' % conf_interval_banner_a)
print ('interval for banner b [%f, %f]' % conf_interval_banner_b)


interval for banner a [0.026961, 0.050582]
interval for banner b [0.040747, 0.068675]

Как их сравнить?

Доверительный интервал для разности долей (независимые выборки)

$X_1$ $X_2$
1 a b
0 c d
$\sum$ $n_1$ $n_2$
$$ \hat{p}_1 = \frac{a}{n_1}$$$$ \hat{p}_2 = \frac{b}{n_2}$$$$\text{Доверительный интервал для }p_1 - p_2\colon \;\; \hat{p}_1 - \hat{p}_2 \pm z_{1-\frac{\alpha}{2}}\sqrt{\frac{\hat{p}_1(1 - \hat{p}_1)}{n_1} + \frac{\hat{p}_2(1 - \hat{p}_2)}{n_2}}$$

In [25]:
def proportions_confint_diff_ind(sample1, sample2, alpha = 0.05):    
    z = scipy.stats.norm.ppf(1 - alpha / 2.)   
    p1 = float(sum(sample1)) / len(sample1)
    p2 = float(sum(sample2)) / len(sample2)
    
    left_boundary = (p1 - p2) - z * np.sqrt(p1 * (1 - p1)/ len(sample1) + p2 * (1 - p2)/ len(sample2))
    right_boundary = (p1 - p2) + z * np.sqrt(p1 * (1 - p1)/ len(sample1) + p2 * (1 - p2)/ len(sample2))
    
    return (left_boundary, right_boundary)

In [26]:
print ("confidence interval: [%f, %f]" % proportions_confint_diff_ind(data.banner_a, data.banner_b))


confidence interval: [-0.034157, 0.002157]

Доверительный интервал для разности долей (связанные выборки)

$X_1$ \ $X_2$ 1 0 $\sum$
1 e f e + f
0 g h g + h
$\sum$ e + g f + h n
$$ \hat{p}_1 = \frac{e + f}{n}$$$$ \hat{p}_2 = \frac{e + g}{n}$$$$ \hat{p}_1 - \hat{p}_2 = \frac{f - g}{n}$$$$\text{Доверительный интервал для }p_1 - p_2\colon \;\; \frac{f - g}{n} \pm z_{1-\frac{\alpha}{2}}\sqrt{\frac{f + g}{n^2} - \frac{(f - g)^2}{n^3}}$$

In [38]:
def proportions_confint_diff_rel(sample1, sample2, alpha = 0.05):
    z = scipy.stats.norm.ppf(1 - alpha / 2.)
    sample = zip(sample1, sample2)
    #n = len(sample)
    #test_data = list(sample)
    n = len(sample1) 
    
    
    f = sum([1 if (x[0] == 1 and x[1] == 0) else 0 for x in sample])
    g = sum([1 if (x[0] == 0 and x[1] == 1) else 0 for x in sample])
    
    left_boundary = float(f - g) / n  - z * np.sqrt(float((f + g)) / n**2 - float((f - g)**2) / n**3)
    right_boundary = float(f - g) / n  + z * np.sqrt(float((f + g)) / n**2 - float((f - g)**2) / n**3)
    return (left_boundary, right_boundary)

In [40]:
print ("confidence interval: [%f, %f]" % proportions_confint_diff_rel(data.banner_a, data.banner_b))


confidence interval: [0.001833, 0.012167]