如何使用PYMC编写多元正态的层次混合模型

2 投票
1 回答
1530 浏览
提问于 2025-04-18 07:13

我成功地用PyMC实现了三种正态分布的混合(具体情况可以查看这个链接,也和在这个问题中提到的类似)。

我接下来的步骤是尝试编写多元正态分布的混合代码。

不过,数据中还有一个额外的复杂性——有一个层级结构,观察数据是属于某个父观察的。聚类是基于父观察进行的,而不是单独的观察数据。这个第一步生成了代码(60个父观察,每个父观察有50个观察数据),运行得很好。

import numpy as np
import pymc as mc
n = 3  #mixtures
B = 5  #Bias between those at different mixtures
tau = 3 #Variances
nprov = 60 #number of parent observations
mu = [[0,0],[0,B],[-B,0]]
true_cov0 = np.array([[1.,0.],[0.,1.]])
true_cov1 = np.array([[1.,0.],[0.,tau**(2)]])
true_cov2 = np.array([[tau**(-2),0],[0.,1.]])
trueprobs = [.4, .3, .3]   #probability of being in each of the three mixtures

prov = np.random.multinomial(1, trueprobs, size=nprov)
v = prov[:,1] + (prov[:,2])*2
numtoeach = 50
n_obs = nprov*numtoeach
vAll = np.tile(v,numtoeach)
ndata = numtoeach*nprov
p1 = range(nprov)
prov1 = np.tile(p1,numtoeach)

data = (vAll==0)*(np.random.multivariate_normal(mu[0],true_cov0,ndata)).T \
  + (vAll==1)*(np.random.multivariate_normal(mu[1],true_cov1,ndata)).T \
  + (vAll==2)*(np.random.multivariate_normal(mu[2],true_cov2,ndata)).T
data=data.T

但是,当我尝试用PyMC进行采样时,我遇到了问题(‘错误:在将第三个参数 `tau` 从 flib.prec_mvnorm 转换为 C/Fortran 数组时失败’)。

p = 2  #covariates
prior_mu1=np.ones(p)
prior_mu2=np.ones(p)
prior_mu3=np.ones(p)
post_mu1 = mc.Normal("returns1",prior_mu1,1,size=p)
post_mu2 = mc.Normal("returns2",prior_mu2,1,size=p)
post_mu3 = mc.Normal("returns3",prior_mu3,1,size=p)
post_cov_matrix_inv1 = mc.Wishart("cov_matrix_inv1",n_obs,np.eye(p) )
post_cov_matrix_inv2 = mc.Wishart("cov_matrix_inv2",n_obs,np.eye(p) )
post_cov_matrix_inv3 = mc.Wishart("cov_matrix_inv3",n_obs,np.eye(p) )

#Combine prior means and variance matrices
meansAll= np.array([post_mu1,post_mu2,post_mu3])
precsAll= np.array([post_cov_matrix_inv1,post_cov_matrix_inv2,post_cov_matrix_inv3])

dd = mc.Dirichlet('dd', theta=(1,)*n)
category = mc.Categorical('category', p=dd, size=nprov)

#This step accounts for the hierarchy: observations' means are equal to their parents mean
#Parent is labeled prov1

@mc.deterministic
def mean(category=category, meansAll=meansAll):
lat = category[prov1]
new = meansAll[lat]
return new

@mc.deterministic
def prec(category=category, precsAll=precsAll):
lat = category[prov1]
return precsAll[lat]

obs = mc.MvNormal( "observed returns", mean, prec, observed = True, value = data)

我知道问题不在于模拟观察数据的格式,因为如果用其他步骤替代上面的步骤,这一部分会运行得很好:

obs = mc.MvNormal( "observed returns", post_mu3, post_cov_matrix_inv3, observed = True, value = data )

因此,我认为问题出在均值向量(‘mean’)和协方差矩阵(‘prec’)的输入上,我就是不知道该怎么做。正如我所说,这在处理正态分布的混合时运行得很好,但多元正态分布的混合增加了我无法解决的复杂性。

1 个回答

4

这是一个很好的例子,说明了PyMC在处理多变量向量时遇到的困难。其实并不是说很难,只是没有那么优雅。你应该创建一个包含多变量正态分布节点的列表理解,并将其包装成一个观察到的随机变量。

@mc.observed
def obs(value=data, mean=mean, prec=prec):
    return sum(mc.mv_normal_like(v, m, T) for v,m,T in zip(data, mean, prec))

这里是IPython笔记本

撰写回答