如何从 R 中的自定义分布 运行 monte carlo 模拟

How to run monte carlo simulation from a custom distribution in R

我想从 R 中的自定义分布中提取 1000 个样本

我有以下自定义分布

library(gamlss)
mu    <- 1    
sigma <- 2 
tau   <- 3   
kappa <- 3
rate  <- 1
Rmax  <- 20

x <- seq(1, 2e1, 0.01)
points <- Rmax * dexGAUS(x, mu = mu, sigma = sigma, nu = tau) * pgamma(x, shape = kappa, rate = rate)
plot(points ~ x)

如何通过 Monte Carlo 模拟从这个分布中随机抽样?

我的第一次尝试是下面的代码,它产生了我没想到的直方图形状。

hist(sample(points, 1000), breaks = 51)

这不是我想要的,因为它与 pdf 不遵循相同的分布。

如果你想要一个 Monte Carlo 模拟,你需要从分布中多次抽样,而不是一次性抽取大量样本。

您的对象 points 的值随着索引增加到 400 附近的阈值而增加,趋于平稳,然后下降。这就是 plot(points ~ x) 显示的内容。它可能描述了一种分布,但 points 中值的实际分布是​​不同的。这显示了值在特定范围内的频率。您会注意到直方图的 x 轴类似于 plot(points ~ x) 图的 y 轴。 points 对象中值的实际分布很容易看到,它类似于您在随机采样 1000 个值时看到的情况,而无需从其中包含 1900 值的对象进行替换.这是 points 中的值分布(无需模拟):

hist(points, 100)

我特意使用了 100 个中断,这样您就可以看到一些细节。

请注意顶部尾部的小凸起,如果您希望直方图看起来像值与指数(或一些递增的 x)的关系图,您可能不会想到这一点。这意味着 points2 附近的值多于 1 附近的值。看看当值在 2 左右时 plot(points ~ x) 的曲线如何变平,以及在 0.51.5 之间如何变得非常陡峭。还要注意直方图低端的大驼峰,再次查看 plot(points ~ x) 曲线。您是否看到大多数值(无论它们位于该曲线的低端还是高端)如何接近 0,或至少小于 0.25。如果您查看这些细节,您可能会说服自己直方图实际上正是您所期望的 :)

如果您想 Monte Carlo 模拟此对象的样本,您可以尝试类似的操作:

samples <- replicate(1000, sample(points, 100, replace = TRUE))

如果您想使用 points 作为概率密度函数生成数据,已提出并回答了该问题

您反转分布的 ECDF:

 ecd.points <- ecdf(points)
 invecdfpts <- with( environment(ecd.points), approxfun(y,x) )
 samp.inv.ecd <- function(n=100) invecdfpts( runif(n) )
 plot(density (samp.inv.ecd(100) ) )
 plot(density(points) )
 png(); layout(matrix(1:2,1)); plot(density (samp.inv.ecd(100) ),main="The Sample" )
  plot(density(points) , main="The Original"); dev.off()

让我们将您的(未归一化的)概率密度函数定义为函数:

library(gamlss)
fun <- function(x, mu = 1, sigma = 2, tau = 3, kappa = 3, rate = 1, Rmax = 20)
  Rmax * dexGAUS(x, mu = mu, sigma = sigma, nu = tau) * 
  pgamma(x, shape = kappa, rate = rate)

现在一种方法是使用一些MCMC(马尔可夫链Monte Carlo)方法。例如,

simMCMC <- function(N, init, fun, ...) {
  out <- numeric(N)
  out[1] <- init
  for(i in 2:N) {
    pr <- out[i - 1] + rnorm(1, ...)
    r <- fun(pr) / fun(out[i - 1])
    out[i] <- ifelse(runif(1) < r, pr, out[i - 1])
  }
  out
}

它从 init 点开始,给出 N 次平局。该方法可以在很多方面进行改进,但我只是从 init = 5 开始,包括 20000 的老化周期和 select 每秒绘制以减少重复次数:

d <- tail(simMCMC(20000 + 2000, init = 5, fun = fun), 2000)[c(TRUE, FALSE)]
plot(density(d))

这是另一种方法,它借鉴了 and

x <- seq(1, 2e1, 0.01)
points <- 20*dexGAUS(x,mu=1,sigma=2,nu=3)*pgamma(x,shape=3,rate=1)
f <- function (x) (20*dexGAUS(x,mu=1,sigma=2,nu=3)*pgamma(x,shape=3,rate=1))
C <- integrate(f,-Inf,Inf)

> C$value
[1] 11.50361

# normalize by C$value
f <- function (x) 
(20*dexGAUS(x,mu=1,sigma=2,nu=3)*pgamma(x,shape=3,rate=1)/11.50361)

random.points <- approx(cumsum(pdf$y)/sum(pdf$y),pdf$x,runif(10000))$y
hist(random.points,1000)

hist((random.points*40),1000) 将像您的原始函数一样进行缩放。