【发布时间】:2018-01-04 11:29:37
【问题描述】:
我正在使用 PyMC3 使用必须定义的特定似然函数进行参数估计。我搜索了一下,发现我应该使用densitydist 方法来实现用户定义的似然函数,但它不起作用。如何在 PyMC3 中加入用户定义的似然函数并找出我的模型的最大 posteriori (MAP) 估计值?我的代码如下。这里L 是我的似然函数的解析形式。我有一些关于某些物体的径向速度(vr)和位置(r)的观测数据,这些数据是从 excel 文件中导入的。
data_ = np.array(pandas.read_excel('aaa.xlsx',header=None))
gamma=3.77;
G = 4.302*10**-6;
rmin = 3.0;
R = 95.7;
vr=data_[:,1];
r= data_[:,0];
h= np.pi;
class integrateOut(theano.Op):
def __init__(self,f,t,t0,tf,*args,**kwargs):
super(integrateOut,self).__init__()
self.f = f
self.t = t
self.t0 = t0
self.tf = tf
def make_node(self,*inputs):
self.fvars=list(inputs)
try:
self.gradF = tt.grad(self.f,self.fvars)
except:
self.gradF = None
return theano.Apply(self,self.fvars,[tt.dscalar().type()])
def perform(self,node, inputs, output_storage):
args = tuple(inputs)
f = theano.function([self.t]+self.fvars,self.f)
output_storage[0][0] = quad(f,self.t0,self.tf,args=args)[0]
def grad(self,inputs,grads):
return [integrateOut(g,self.t,self.t0,self.tf)(*inputs)*grads[0] \
for g in self.gradF]
basic_model = pm.Model()
with basic_model:
M=[]
beta=[]
interval=0.01*10**12
M=pm.Uniform('M',
lower=0.5*10**12,upper=3.50*10**12,transform='interval')
beta=pm.Uniform('beta',lower=2.001,upper=2.999,transform='interval')
gamma=3.77
logp=[]
arr=[]
vnew=[]
rnew=[]
theta = tt.scalar('theta')
beta = tt.scalar('beta')
z = tt.cos(theta)**(2*( (gamma/(beta - 2)) - 3/2) + 3)
intZ = integrateOut(z,theta,-(np.pi)/2,(np.pi)/2)(beta)
gradIntZ = tt.grad(intZ,[beta])
funcIntZ = theano.function([beta],intZ)
funcGradIntZ = theano.function([beta],gradIntZ)
for j in np.arange(0,59,1):
vnew.append(vr[j]+(0.05*vr[j]*float(dm.Decimal(rm.randrange(1,
20))/10)));
rnew.append(r[j]+(0.05*r[j]*float(dm.Decimal(rm.randrange(1,
20))/10)));
vn=np.array(vnew)
rn=np.array(rnew)
for beta in np.arange (2.01,2.99,0.01):
for M in np.arange (0.5,2.50,0.01):
i=np.arange(0,59,1)
q =( gamma/(beta - 2)) - 3/2
B = (G*M*10**12)/((beta -2 )*( R**(3 - beta)))
K = (gamma - 3)/((rmin**(3 - gamma))*funcIntZ(beta)*m.sqrt(2*B))
logp= -np.log(K*((1 -(( 1/(2*B) )*((vn[i]**2)*rn[i]**(beta -
2))))**(q+1))*(rn[i]**(1-gamma +(beta/2))))
arr.append(logp.sum())
def logp_func(rn,vn):
return min(np.array(arr))
logpvar = pm.DensityDist("logpvar", logp_func, observed={"rn": rn,"vn":vn})
start = pm.find_MAP(model=basic_model)
step = pm.Metropolis()
basicmodeltrace = pm.sample(10000, step=step,
start=start,random_seed=1,progressbar=True)
print(pm.summary(basicmodeltrace))
map_estimate = pm.find_MAP(model=basic_model)
print(map_estimate)
我收到以下错误消息:
ValueError: Cannot compute test value: input 0 (theta) of Op
Elemwise{cos,no_inplace}(theta) missing default value.
Backtrace when that variable is created:
由于数值积分不起作用,我无法获得输出。我已将自定义 theano op 用于从 Custom Theano Op to do numerical integration 获得的数值积分代码。如果我单独运行它并输入特定的 beta 值,但不在模型内,则集成有效。
【问题讨论】:
-
你能发布一个完整的工作示例吗?你真的想要一个 MAP,你为什么不直接使用
pm.sample()并获得一个完整的后部? -
@aloctavodia 先生,我对我的代码进行了一些编辑,并发布了一个完整的工作示例。我的 logp 问题已解决,但我无法获得准确的参数估计。
-
我无权访问文件 'aaa.xlsx',因此我无法运行您的模型。如果你只是通过
basicmodeltrace = pm.sample(1000)运行你的模型,你会得到什么。你为什么使用均匀分布作为先验?除非统一先验的边界具有某种物理意义,否则使用具有大方差的高斯通常是更好的选择。 -
这实际上是天体物理学中的一个问题,它为统一先验强加了物理意义。我已经使用 'basicmodeltrace = pm.sample(1000)' 运行了模型。我得到与以前相同的结果。我无法获取对应于 logp 最小值的 M 和 beta。 M 数组和 beta 数组只是边界值的平均值。即使我注释掉似然函数部分,我也会得到相同的输出,除了 logp 的值。那么这是否意味着先验没有输入似然函数? M 和 beta 的 for 循环是否必要? @aloctavodia
-
对不起,我之前没有注意到这一点,但你不必循环 M 和 beta。您必须让 PyMC3 对 M 和 beta 的值进行采样(而不是像您那样执行网格搜索)。此外,您的
logp_func应该返回 tt.sum(logp) (您不必计算min)。检查this 示例。此外,您可能需要将np.log替换为tt.log并将 m.sqrt(2*B) 替换为 (2*B)**0.5。
标签: python-3.x python-2.7 pymc pymc3