我正在研究一个嵌套的逻辑回归模型,其中3个结果代表选择A,B或C.第一个级别代表A和B或C之间的选择,第二个级别代表B和C之间的选择。一些组成数据的代码如下,但我不确定我是否正确指定了模型。根据定义,B或C的概率大于B的概率,但是当从非常小的样本大小的后方采样时,“BorC”可能小于B.这样的小样本大小可能不会出现在实际数据中我很感兴趣,但事实发生这种情况让我觉得我做错了什么。谢谢!
import numpy as np
import pandas as pd
import pymc3 as pm
from scipy.special import logit
import matplotlib.pyplot as plt
from theano import shared
import cPickle as pickle # python 2
def hierarchical_normal(name, shape, mu=0.,cs=5.):
delta = pm.Normal('delta_{}'.format(name), 0., 1., shape=shape)
sigma = pm.HalfCauchy('sigma_{}'.format(name), cs)
return pm.Deterministic(name, mu + delta * sigma)
NUTS_KWARGS = {'target_accept': 0.99}
SEED = 4260026 # from random.org, for reproducibility
np.random.seed(SEED)
ndraws = 1000
counts =[[19, 50, 37],
[21, 67, 55],
[11, 53, 38],
[17, 54, 45],
[24, 93, 66],
[27, 53, 70]]
counts = pd.DataFrame(counts,columns=["A","B","C"])
counts["BorC"] = counts[["B","C"]].sum(axis=1)
counts["n"] = counts[["A","B","C"]].sum(axis=1)
print counts
group = counts.index.values
n_group = np.unique(group).size
obs_B = counts.B.values
obs_BorC = counts.BorC.values
obs_n = counts.n.values
obs_n_ = shared(obs_n)
with pm.Model() as model:
beta0 = pm.Normal('beta0', 0.,sd=5.)
beta_group = hierarchical_normal('beta_group', n_group)
eta_BorC = beta0 + beta_group[group]
p_BorC = pm.math.sigmoid(eta_BorC)
like_BorC = pm.Binomial('obs_BorC', obs_n_, p_BorC, observed=obs_BorC)
alpha0 = pm.Normal('alpha0', 0.,sd=5.)
alpha_group = hierarchical_normal('alpha_group', n_group)
eta_BgivenBorC = alpha0 + alpha_group[group]
p_BgivenBorC = pm.math.sigmoid(eta_BgivenBorC)
like_BgivenBorC = pm.Binomial('obs_BgivenBorC', obs_BorC, p_BgivenBorC, observed=obs_B)
p_B = p_BgivenBorC*p_BorC
like_B = pm.Binomial('obs_B', obs_n_, p_B, observed=obs_B)
trace = pm.sample(draws=ndraws, random_seed=SEED,nuts_kwargs=NUTS_KWARGS)
obs_n_.set_value(np.array([10]*6))
pp_trace = pm.sample_ppc(trace, model=model)
C = pp_trace['obs_BorC']-pp_trace['obs_B']
print np.min(np.min(C))
B = pp_trace['obs_B']
C = np.sum(C,axis=1)
B = np.sum(B,axis=1)
diff = C-B
plt.figure()
plt.hist(diff,50)
plt.show()
编辑:我从浏览pymc3代码看到,日志似然性自动在所有变量上求和,这意味着我对like_B的规范是多余的。在这种情况下,我想我只需要弄清楚如何正确设置obs_BorC进行后验采样。
答案 0 :(得分:0)
这是一个尝试的解决方案,如果没有更好的解决方案,我认为这是一种解决方法。我刚刚制作了一个自定义的后验采样器,其中每次迭代都会重置obs_BorC。
import numpy as np
import pandas as pd
import pymc3 as pm
from scipy.special import logit
import matplotlib.pyplot as plt
from theano import shared
from collections import defaultdict
from scipy.stats import norm
def hierarchical_normal(name, shape, mu=0.,cs=5.):
delta = pm.Normal('delta_{}'.format(name), 0., 1., shape=shape)
sigma = pm.HalfCauchy('sigma_{}'.format(name), cs)
return pm.Deterministic(name, mu + delta * sigma)
NUTS_KWARGS = {'target_accept': 0.99}
SEED = 4260026 # from random.org, for reproducibility
np.random.seed(SEED)
ndraws = 1000
counts =[[19, 50, 37],
[21, 67, 55],
[11, 53, 38],
[17, 54, 45],
[24, 93, 66],
[27, 53, 70]]
counts = pd.DataFrame(counts,columns=["A","B","C"])
counts["BorC"] = counts[["B","C"]].sum(axis=1)
counts["n"] = counts[["A","B","C"]].sum(axis=1)
print counts
group = counts.index.values
n_group = np.unique(group).size
obs_B = counts.B.values
obs_BorC = counts.BorC.values
obs_n = counts.n.values
obs_n_ = shared(obs_n)
obs_BorC_ = shared(obs_BorC)
with pm.Model() as model:
beta0 = pm.Normal('beta0', 0.,sd=5.)
beta_group = hierarchical_normal('beta_group', n_group)
eta_BorC = beta0 + beta_group[group]
p_BorC = pm.math.sigmoid(eta_BorC)
like_BorC = pm.Binomial('obs_BorC', obs_n_, p_BorC, observed=obs_BorC)
alpha0 = pm.Normal('alpha0', 0.,sd=5.)
alpha_group = hierarchical_normal('alpha_group', n_group)
eta_BgivenBorC = alpha0 + alpha_group[group]
p_BgivenBorC = pm.math.sigmoid(eta_BgivenBorC)
like_BgivenBorC = pm.Binomial('obs_BgivenBorC', obs_BorC_, p_BgivenBorC, observed=obs_B)
trace = pm.sample(draws=ndraws, random_seed=SEED,nuts_kwargs=NUTS_KWARGS)
#plt.figure()
#axs = pm.forestplot(trace,varnames=['beta0','beta_group','alpha0','alpha_group'])
#plt.savefig("Forest.png")
#plt.close()
obs_n_.set_value(np.array([10000]*6))
indices = np.random.randint(0, len(trace), 1000)
ppc = defaultdict(list)
for idx in indices:
param = trace[idx]
n_BorC = model["obs_BorC"].distribution.random(point=param,size=None)
obs_BorC_.set_value(np.array(n_BorC))
n_B = model["obs_BgivenBorC"].distribution.random(point=param,size=None)
ppc["obs_BorC"].append(n_BorC)
ppc["obs_B"].append(n_B)
pp_trace = {k: np.asarray(v) for k, v in ppc.items()}
#pp_trace = pm.sample_ppc(trace, model=model,samples=20000)
C = pp_trace['obs_BorC']-pp_trace['obs_B']
print np.min(np.min(C))
B = pp_trace['obs_B']
C = np.sum(C,axis=1)
B = np.sum(B,axis=1)
diff = (C-B)/60000.
plt.figure()
x = np.linspace(np.min(diff),np.max(diff),200)
mean = np.mean(diff)
std = np.std(diff)
plt.hist(diff,50,normed=True)
plt.plot(x,norm.pdf(x,mean,std))
plt.plot()
plt.show()