使用逆CDF在R中生成随机变量

时间:2014-04-24 02:04:21

标签: r newtons-method cdf

首先,我不知道教授是否提出了错误的问题。无论如何,我尝试生成F(x)~U(0,1),其中CDF F(x)=1-(1+x)exp(-x)(对于此CDF,您无法手动计算x=g(F(x)))。然后计算F(x)的根来实现问题所需。

因为从0INF的根范围,uniroot()是不可能的。因此,我使用牛顿法写一个。

然后,我的代码是这样的:

f=function(x) {
      ifelse(x>=0,x*exp(-x),0)
  }

in.C=function(n) {
         a=runif(n)
         G=NULL
         for(i in 1:n) {
             del=1
             x=2
             while(abs(del)>1e-12){
               del=(1-(1+x)*exp(-x)-a[i])/f(x)
               x=x-del

             }
             G[i]=x
         }
         G
     }
system.time(tt<-in.C(100000))

但是,如果F(x)太小,而牛顿法中的一步,结果可能小于零,则会发生错误。此外,我修改了我的代码:

f=function(x) {
      ifelse(x>=0,x*exp(-x),0)
  }

in.C=function(n) {
         a=runif(n)
         G=NULL
         for(i in 1:n) {
             del=1
             x=2
             while(abs(del)>1e-12){
               if(x>=0){    del=(1-(1+x)*exp(-x)-a[i])/f(x)
                   x=x-del
                   }
                   else break
             }
             if(x>=0) G[i]=x
         }
         G[!is.na(G)]
     }
system.time(tt<-in.C(100000))
hist(tt, breaks=70, right=F, freq=F)
curve(f(x),from=0,to=20,add=T)

显然,代码是错误的,因为我拒绝接近零的结果。

所以,我的问题是我的代码是否可以修改为正确计算,如果没有,是否有另一种方法可以做到。任何协助都表示赞赏。

1 个答案:

答案 0 :(得分:1)

可以使用uniroot(...)

[注意:如果本练习的目的是实现您自己的Newton Raphson技术版本,请告诉我,我将删除答案。]

如果我正确理解这一点,您希望从概率密度函数f和累积密度F的分布中生成随机样本,其中

f = x*exp(-x)
F = 1 - (1+x)*exp(-x)

正如您所暗示的,这可以通过从U[0,1]生成随机样本并根据F的逆CDF对其进行转换来完成。该过程与发布herehere的过程非常相似,只是您已经有了CDF的表达式。

f <- function(x) x*exp(-x)
F <- function(x) 1-(1+x)*exp(-x)

F.inv <- function(y){uniroot(function(x){F(x)-y},interval=c(0,100))$root}
F.inv <- Vectorize(F.inv)

x <- seq(0,10,length.out=1000)
y <- seq(0,1,length.out=1000)

par(mfrow=c(1,3))
plot(x,f(x),type="l",main="f(x)")
plot(x,F(x),type="l",main="CDF of f(x)")
plot(y,F.inv(y),type="l",main="Inverse CDF of f(x)")

然后,生成X ~ U[0,1]Z = F.inv(X)

set.seed(1)
X <- runif(1000,0,1)   # random sample from U[0,1]
Z <- F.inv(X)

par(mfrow=c(1,1))
hist(Z, freq=FALSE, breaks=c(seq(0,10,length=30),Inf), xlim=c(0,10))
lines(x,f(x),type="l",main="Density function", col="red",lty=2)