模拟(非标准)密度函数的数据

时间:2013-04-21 18:38:58

标签: r simulation probability

我想模拟非标准密度函数的数据。我已经找到以下链接(How do I best simulate an arbitrary univariate random variate using its probability function?)。然而,这给出了奇怪的结果。不知何故,这个累积密度函数(cdf())不能很好地工作。从某些值来看,它给出了非常奇怪的结果。例如,请查看以下代码:

density=function(x)(25*200.7341^25/x^26*exp(-(200.7341/x)^25))
cdf<-function(x) integrate(density,1,x)[[1]]

cdf(9701)
[1] 1

cdf(9702)
[1] 6.33897e-05

所以我的问题是,如何创建一个“好”的CDF功能?或者更直接地说,我如何模拟PDF中的数据?

3 个答案:

答案 0 :(得分:5)

正如@pjs所指出,我们可以使用Rejection sampling(查看维基详情)。

以下是此方法的一种实现方式。

最重要的步骤是找到我们可以从中采样并且从中存在M的分布g,使得M * g> 1。 f为所有点

f <- function(x) (25 * 200.7341^25 / x^26 * exp(-(200.7341/x)^25))
g <- function(x) dnorm(x, mean = 200.7341, sd = 40)
M <- 5
curve(f, 0, 500)
curve(M * g(x), 0, 500, add = TRUE, lty = "dashed")

enter image description here

现在,我们可以执行算法

set.seed(42)
k <- 1
count <- 0
res <- vector(mode = "numeric", length = 1000)
while(k < 1001) {
          z <- rnorm(n = 1, mean = 200.7341, sd = 40)
          R <- f(z) / (M * g(z))
          if (R > runif(1)) {
              res[k] <- z
              k  <- k + 1
          }
          count <- count + 1
    }

(accept_rate <- (k / count) * 100)
## [1] 19.7086

require(MASS) ## for truehist
truehist(res)
curve(f, 0, 250, add = TRUE)

enter image description here

接受率不高。您可以尝试找到更好的信封功能或使用Metropolis Hasting算法。

答案 1 :(得分:4)

如果积分间隔非常大, 密度的峰值很难找到:integrate很容易错过它, 并认为你所整合的功能(几乎)无处不在。

如果你知道峰值在哪里,你可以将积分切成三个: 在高峰期,之前和之后。

# Density
A <- 200.7341
f <- function(x) 25*A^25 / x^26 * exp( -(A/x)^25 )
a <- 150
b <- 400

# Numeric integration
F1 <- function(x) {
  if( x < a )      integrate(f, 1, x)[[1]] 
  else if( x < b ) integrate(f, 1, a)[[1]] + integrate(f, a, x)[[1]] 
  else             integrate(f, 1, a)[[1]] + integrate(f, a, b)[[1]] + integrate(f, b, x)[[1]] 
}

# Compare with the actual values
F2 <- function(x) exp( -(A/x)^25 )
F1(200); F2(200)
F1(1e4); F2(1e4)
F1(1e5); F2(1e5) # Imprecise if b is too low...

在检查您的间隔是否足够大之后,您可以删除之前的&#34;&#34; &#34;&#34;&#34;&#34;间隔:他们的贡献是零。

F1 <- function(x) {
  if( x < a )      0
  else if( x < b ) integrate(f, a, x)[[1]] 
  else             1
}

答案 2 :(得分:0)

当我玩你的CDF时,很快就会出现大部分动作是在180到350之间的x,我通过绘制该范围内的密度来确认。

我很确定x = 9702时的结果反映了当你涉及第25和第26次幂时计算的数值不稳定性。如果你不相信你的CDF或者它不可逆,那么另一个基于pdf的选项是acceptance/rejection。您应该能够使用一个简单的三角形,其中min = 180,最大值约为300,模式约为200作为边界函数g(x),并遵循维基百科上描述的算法以获得相当不错的结果。

一般情况下,如果反转不适用于任意分布,那么您的其他选择是1)基于pdf相对于边界函数的接受/拒绝,2)组合(可以将您的分布解构为更易于生成的组件)并使用条件概率选择合适的组件,或3)“特殊技巧” - 是否存在卷积或参数化给出分布等价的情况(例如,N(0,1)^ 2 =卡方(1),卡方(k)= k个独立卡方(1)的总和,exp(2)=卡方(2)等...)。有关您的选项的综合处理,请参阅非均匀随机变量生成的Luc Devroye's book