Как кодировать модель иерархической смеси многомерных нормалей с помощью PYMC
Я успешно реализовал смесь из 3 нормалей с помощью PyMC (показано по адресу https://drive.google.com/file/d/0Bwnmbh6ueWhqSkUtV1JFZDJwLWc и похож на вопрос, заданный в разделе Как смоделировать смесь из 3 нормалей в 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 )
В результате я думаю, что проблема заключается в том, как вводится средний вектор ("среднее") и ковариационная матрица ("пред"), я просто не знаю, как. Как я уже сказал, это хорошо работало со смесью нормальных распределений, но смеси многомерных нормалей добавляют сложность, которую я не могу понять.
1 ответ
Это хороший пример трудности, с которой PyMC сталкивается с векторами многомерных переменных. Не то чтобы это сложно - просто не так элегантно, как должно быть. Вы должны создать список понимания узлов MVN и обернуть его как наблюдаемый стохастик.
@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))