在Python中使用statsmodels和PyMC3(MCMC模拟)估算两个比例之差的p值

时间:2018-11-01 18:15:54

标签: python statsmodels pymc3

在黑客的概率编程和贝叶斯方法中,提出了一种计算两个比例不同的p值的方法。

(您可以在此处找到包含整章内容的jupyter笔记本 http://nbviewer.jupyter.org/github/CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/blob/master/Chapter2_MorePyMC/Ch2_MorePyMC_PyMC2.ipynb

代码如下:

import pymc3 as pm
figsize(12, 4)

#these two quantities are unknown to us.
true_p_A = 0.05
true_p_B = 0.04


N_A = 1700
N_B = 1700

#generate some observations
observations_A = bernoulli.rvs(true_p_A, size=N_A)
observations_B = bernoulli.rvs(true_p_B, size=N_B)

print(np.mean(observations_A))
print(np.mean(observations_B))

0.04058823529411765
0.03411764705882353

# Set up the pymc3 model. Again assume Uniform priors for p_A and p_B.
with pm.Model() as model:
    p_A = pm.Uniform("p_A", 0, 1)
    p_B = pm.Uniform("p_B", 0, 1)

    # Define the deterministic delta function. This is our unknown of interest.
    delta = pm.Deterministic("delta", p_A - p_B)


    # Set of observations, in this case we have two observation datasets.
    obs_A = pm.Bernoulli("obs_A", p_A, observed=observations_A)
    obs_B = pm.Bernoulli("obs_B", p_B, observed=observations_B)

    # To be explained in chapter 3.
    step = pm.Metropolis()
    trace = pm.sample(20000, step=step)
    burned_trace=trace[1000:]

p_A_samples = burned_trace["p_A"]
p_B_samples = burned_trace["p_B"]
delta_samples = burned_trace["delta"]

# Count the number of samples less than 0, i.e. the area under the curve
# before 0, represent the probability that site A is worse than site B.
print("Probability site A is WORSE than site B: %.3f" % \
    np.mean(delta_samples < 0))

print("Probability site A is BETTER than site B: %.3f" % \
    np.mean(delta_samples > 0))

Probability site A is WORSE than site B: 0.167
Probability site A is BETTER than site B: 0.833

但是,如果我们使用statsmodels计算p值,则会得到非常不同的结果:

from scipy.stats import norm, chi2_contingency
import statsmodels.api as sm


s1 = int(1700 * 0.04058823529411765)
n1 = 1700
s2 = int(1700 * 0.03411764705882353)
n2 = 1700
p1 = s1/n1
p2 = s2/n2
p = (s1 + s2)/(n1+n2)
z = (p2-p1)/ ((p*(1-p)*((1/n1)+(1/n2)))**0.5)

z1, p_value1 = sm.stats.proportions_ztest([s1, s2], [n1, n2])

print('z1 is {0} and p is {1}'.format(z1, p))

z1 is 0.9948492584166934 and p is 0.03735294117647059

使用MCMC时,p值似乎为0.167,但是使用statsmodels时,p值为0.037。

能帮我理解吗?您的建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

看起来像您打印了错误的值。尝试以下方法:

print('z1 is {0} and p is {1}'.format(z1, p_value1))

此外,如果要检验假设p_A> p_B,则应将函数调用中的alternative参数设置为larger,如下所示:

z1, p_value1 = sm.stats.proportions_ztest([s1, s2], [n1, n2], alternative='larger')

docs上有更多使用示例。