Metropolis Hastings 算法双变量法线

机器算法验证 r 马尔可夫链蒙特卡罗 混合分布
2022-03-28 05:37:27

我需要一些帮助来实现(1)独立高斯建议和(2)随机游走高斯建议,以从混合二元正态分布中进行模拟。

“如果我们有一个连续的状态空间,则可以使用局部模式下的 Hessian H在此处输入图像描述来定义高斯提议分布的协方差。”

“有两种明显的方法:(1)独立提议在此处输入图像描述或(2)随机游走提议在此处输入图像描述在此处输入图像描述其中Dw的维数,导致接受率为 0.234。”

这里也讨论了这个问题:https : //forum.dynare.org/t/finding-the-right-draws-from-proposals-in-a-metropolis-hastings/12812 “在 Dynare 中,默认的跳跃分布是高斯分布分布以链的前一个状态为中心,协方差矩阵由在后验模式下评估的后验核的 Hessian 矩阵的逆矩阵给出。”

但是,我不知道在后验模式下评估的后验核处的 Hessian 矩阵是什么意思。这是我实现 MH 算法的尝试。

第一部分:独立提案

这就是混合双变量分布的样子。

在此处输入图像描述

这是我从我的代码中得到的。我选择了一个固定为在此处输入图像描述方差矩阵的提案在此处输入图像描述这似乎只得到两种混合物。不用说,这不符合我应该在某个时候使用 Hessian 的说明。本地模式下的 Hessian 是什么意思?

在此处输入图像描述

library(MASS)
mu=c(2,2)
Sigma=matrix(c(1, 1/2*1*sqrt(2), 1/2*1*sqrt(2), 2), nrow=2)
mu2=c(2,8)
Sigma2=matrix(c(1, -1/2*1*sqrt(2), -1/2*1*sqrt(2), 2), nrow=2)
mu3=c(6,4)
Sigma3=matrix(c(3, -1/2*sqrt(3)*sqrt(2), -1/2*sqrt(3)*sqrt(2), 2), nrow=2)
dat=data.frame(matrix(0, nrow=0, ncol=2))
for (i in 1:3000) {
  u=runif(1)
  if (u<1/3) {
    dat[i,]=mvrnorm(1, mu, Sigma)
  } else if (u<2/3) {
    dat[i,]=mvrnorm(1, mu2, Sigma2)
  } else {
    dat[i,]=mvrnorm(1, mu3, Sigma3)
  }
}
library(ggplot2)
ggplot(dat, aes(X1, X2)) + stat_density_2d(aes(fill=..level..), geom="polygon", color="white")

d=function(x) {
  a=1/(2*pi)/sqrt(det(Sigma))*exp(-.5*t(x-mu)%*%solve(Sigma)%*%(x-mu))
  b=1/(2*pi)/sqrt(det(Sigma2))*exp(-.5*t(x-mu2)%*%solve(Sigma2)%*%(x-mu2))
  c=1/(2*pi)/sqrt(det(Sigma3))*exp(-.5*t(x-mu3)%*%solve(Sigma3)%*%(x-mu3))
  return(1/3*(a+b+c))
}

#Independence

sig=matrix(c(4, 1/2*2*2, 1/2*2*2, 4), nrow=2)
y=data.frame(matrix(0, nrow=0, ncol=2))
x=c(4,4)
accepteds=0
for (i in 1:10000) {
  print(i)
  xp=mvrnorm(1, c(4,4), sig)
  a=d(xp)/d(x)
  r=min(1, a)
  u=runif(1)
  if (u<r) {
    x=xp
    accepteds=accepteds+1
  }
  y[i,]=x
}
accepteds/10000
ggplot(y, aes(X1, X2)) + stat_density_2d(aes(fill=..level..), geom="polygon", color="white")

这是正确的 Hessian,如果是,我将使用什么均值和方差?

在此处输入图像描述

hessian=function(x, mu, Sigma) {
  return(1/(2*pi)/sqrt(det(Sigma))*exp(-1/2* (t(x-mu) %*% solve(Sigma) %*% (x-mu))[1,1]) * (-1/2*2*solve(Sigma)))
}

第二部分:随机游走提案

我决定将其保留在同一个问题中。随机游走提议不起作用,因为在此处输入图像描述结果不是正定的(不是有效的方差矩阵)。知道我做错了什么吗?

dmvrnorm=function(x, mu, Sigma) {
  return(1/(2*pi)/sqrt(solve(Sigma))*exp(-.5*(t(x-mu)%*%solve(Sigma)%*%(x-mu))[1,1]))
}

sig=matrix(c(4, 1/2*2*2, 1/2*2*2, 4), nrow=2)
y=data.frame(matrix(0, nrow=0, ncol=2))
x=c(4,4)
accepteds=0
for (i in 1:10000) {
  print(i)
  sig=solve(hessian(x, x, sig))*2.38^2/2
  print(sig)
  xp=mvrnorm(1, x, sig)
  a=d(xp)*dmvrnorm(x, xp, sig)/d(x)/dmvrnorm(xp, x, sig)
  r=min(1, a)
  u=runif(1)
  if (u<r) {
    x=xp
    accepteds=accepteds+1
  }
  y[i,]=x
}
accepteds/10000
ggplot(y, aes(X1, X2)) + stat_density_2d(aes(fill=..level..), geom="polygon", color="white")

错误:Error in mvrnorm(1, x, sig) : 'Sigma' is not positive definite

2个回答

由于独立的 Metropolis-Hastings 算法在形式上是有效的,因此问题在于对提案的校准不足,无法完全支持目标(混合)分布。我只是通过选择更大的方差矩阵来修改代码

sig=5*matrix(c(4, 1/2*2*2, 1/2*2*2, 4), nrow=2)

运行链 10⁵ 迭代,并在一定程度上恢复了整个目标:

在此处输入图像描述 但是,代码中存在错误,可能是对独立 Metropolis-Hastings 算法的误解。接受概率

a=d(xp)/d(x)
r=min(1, a)

应该将目标的比率除以提案的比率

a=d(xp)/d(x)/dmvnorm(xp,c(4,4), sig)*dmvnorm(x,c(4,4), sig)
r=min(1, a) #superfluous for the acceptance

在 10⁴ 次迭代后返回目标的更好表示:

在此处输入图像描述

编辑:请参阅上面的正确答案:

请注意,这是 NORMALS 的混合问题,而不是双变量 NORMALS:

这里的问题是提案密度没有覆盖整个感兴趣区域。您将相应地对其进行校准以覆盖 ROI,如上述答案中所述。这是使用网格/均匀分布的另一个示例,即

我们可以从图中看到 x 和 y 轴从 -2 到 12。然后你可以用它来提出建议。并且由于它是对称/恒定的,我们可以简单地实现 Metropolis 而不是 Metropolis Hastings。

您的代码:

library(mvtnorm)
mu <- c(2,2)
Sigma <- matrix(c(1, 1/2*1*sqrt(2), 1/2*1*sqrt(2), 2), nrow=2)
mu2 <- c(2,8)
Sigma2 <- matrix(c(1, -1/2*1*sqrt(2), -1/2*1*sqrt(2), 2), nrow=2)
mu3 <- c(6,4)
Sigma3 <- matrix(c(3, -1/2*sqrt(3)*sqrt(2), -1/2*sqrt(3)*sqrt(2), 2), nrow=2)

n <- 3000
s <- rmultinom(1, n, c(1,1,1))
dat <- mapply(rmvnorm, s, mean = list(mu, mu2, mu3), sigma = list(Sigma, Sigma2, Sigma3))
dat1 <- setNames(do.call(rbind.data.frame, dat), c("X1", "X2"))

ggplot(dat1, aes(X1, X2)) +
  stat_density_2d(aes(fill=..level..), geom="polygon", color="white")

d <- function(x) {
  a <- dmvnorm(x, mu, Sigma)
  b <- dmvnorm(x, mu2, Sigma2)
  c <- dmvnorm(x, mu3, Sigma3)
  mean(c(a,b,c))
}

在此处输入图像描述

大都会的实现:

B <- 40000
y <- data.frame(matrix(nrow = B, ncol = 2))
colnames(y) <- c("X1", "X2")
y[1, ] <-colMeans(dat1)
accept<- 1
for(i in seq(2,B)){
  prop <- c(runif(1, -2, 12),runif(1, -2,12))# 
  if( runif(1)<d(prop)/d(y[i-1, ])) {
    y[i, ]<- prop
    accept <- accept + 1
  }
  else y[i, ]<- y[i-1, ]
}

##Burn the first 5000 points
ggplot(y[-seq(5000), ], aes(X1, X2)) +
  stat_density_2d(aes(fill=..level..), geom="polygon", color="white")
print(accept/B)

从网格中采样数据