我尝试通过使用PyMC3将简单的2D高斯模型拟合到观测数据。
import numpy as np
import pymc3 as pm
n = 10000;
np.random.seed(0)
X = np.random.multivariate_normal([0,0], [[1,0],[0,1]], n);
with pm.Model() as model:
# PRIORS
mu = [pm.Uniform('mux', lower=-1, upper=1),
pm.Uniform('muy', lower=-1, upper=1)]
cov = np.array([[pm.Uniform('a11', lower=0.1, upper=2), 0],
[0, pm.Uniform('a22', lower=0.1, upper=2)]])
# LIKELIHOOD
likelihood = pm.MvNormal('likelihood', mu=mu, cov=cov, observed=X)
with model:
trace = pm.sample(draws=1000, chains=2, tune=1000)
虽然我可以通过将sd
传递到pm.Normal
来在一维中完成此操作,但是在将协方差矩阵传递给pm.MvNormal
时遇到了一些麻烦。
我要去哪里错了?
答案 0 :(得分:1)
PyMC3分发对象不是简单的数字对象或numpy数组。相反,它们是theano计算图中的节点,通常需要来自pymc3.math
或theano.tensor
的运算来对其进行操作。此外,由于PyMC3对象已经是多维的,因此不必将它们放置在numpy数组中。
按照您的代码意图,工作版本会像这样
import numpy as np
import pymc3 as pm
import theano.tensor as tt
N = 10000
np.random.seed(0)
X = np.random.multivariate_normal(np.zeros(2), np.eye(2), size=N)
with pm.Model() as model:
# use `shape` argument to define tensor dimensions
mu = pm.Uniform('mu', lower=-1, upper=1, shape=2)
# diagonal values on covariance matrix
a = pm.Uniform('a', lower=0.1, upper=2, shape=2)
# convert vector to a 2x2 matrix with `a` on the diagonal
cov = tt.diag(a)
likelihood = pm.MvNormal('likelihood', mu=mu, cov=cov, observed=X)
我假设您提供的示例只是一个用来传达问题的玩具。但是以防万一,我要提到的是,当将协方差矩阵限制为对角线时,将失去使用多元法线(参数之间的建模协方差)的主要优势。此外,协方差矩阵的先验理论已经得到了很好的发展,因此考虑现有的解决方案值得花时间。特别是,有a PyMC3 example using the LKJ prior for covariance matrices。
在这种情况下,以下是该示例的简单应用:
with pm.Model() as model_lkj:
# use `shape` argument to define tensor dimensions
mu = pm.Uniform('mu', lower=-1, upper=1, shape=2)
# LKJ prior for covariance matrix (see example)
packed_L = pm.LKJCholeskyCov('packed_L', n=2,
eta=2., sd_dist=pm.HalfCauchy.dist(2.5))
# convert to (2,2)
L = pm.expand_packed_triangular(2, packed_L)
likelihood = pm.MvNormal('likelihood', mu=mu, chol=L, observed=X)