繁体   English   中英

使用R中的uniform(0,1)生成N(0,1)

[英]generate N(0,1) using uniform(0,1) in R

我正在尝试使用uniform(0,1)生成N(0,1)进行仿真,但是无法运行代码。

首先,通过使X成为正常CDF的主题,然后找出直方图来找到我的x。 接下来,施加法线以查看其是否适合。 下面是我的代码。

sigma=1; mu=0
u<-runif(n)
x<-mu + sqrt(2*sigma(log(u*sigma*sqrt(2*pi))))
hist(x, Freq=F)
xpt<-seq(-5,5,0.1)
ypt<-dnorm(xpt,0,1)
lines(xpt,ypt,col=2)

您似乎倒置了PDF(概率密度函数)而不是CDF(累积密度函数)。

实际上,反型CDF不会生成正态随机变量,因为其CDF并不是封闭形式。

查看Box-Muller变换 您模拟两组独立的统一随机变量:

u <- runif(1000)
v <- runif(1000)
x <- sqrt(-2 * log(u)) * cos(2 * pi * v)
# y <- sqrt(-2 * log(u)) * sin(2 * pi * v)

然后x来自N(0, 1)(x, y)是二元正态,均值和恒等协方差为零。

我所有评论的来源:

Averill M. Law,W。David Kelton,《 模拟建模与分析》 ,第三版,McGraw-Hill,2000年。ISBN:0-07-058290-4

可以通过生成两个U(0,1)随机变量来使用Box-Muller变换。

`x1 = sqrt(-2 * log(u1)) * cos(2 * pi * u2)`
`x2 = sqrt(-2 * log(u1)) * sin(2 * pi * u2)`

概括如下:

box_muller <- function(n = 1, mean = 0, sd = 1)
{
  x <- vector("numeric", n)

  i <- 1
  while(i <= n)
  {
    u1 <- runif(1, 0, 1)
    u2 <- runif(1, 0, 1)

    x[i] <- sqrt(-2 * log(u1)) * cos(2 * pi * u2)

    if ((i + 1) <= n)
    {
      x[i + 1] <- sqrt(-2 * log(u1)) * sin(2 * pi * u2)
      i <- i + 1
    }

    i <- i + 1
  }

  x * sd + mean
}

hist(box_muller(1000))

但是请注意,

尽管该方法在原理上是有效的,即如果U1U2确实是IID U(0,1)随机变量,但是如果U1U2实际上是由线性同余生成器生成的相邻随机数,则存在严重的困难。 (第465页)

Marsaglia Bray极地方法

此方法分为两步,其中

  1. 生成U1U2作为IID U(0,1); V[i] = 2 * U[i] - 1因为i = 1,2 W = V[1]^2 + V[2]^2
  2. 如果W > 1 ,则返回步骤1。否则,让Y = sqrt(-2 log(W)/W)X[1] = V[1] * Y ,而X[2] = V2 * Y 然后X[1]X[2]是IID N(0,1)个随机变量。 (第466页)

执行:

marsaglia_bray <- function(n = 1, mean = 0, sd = 1)
{
  x <- vector("numeric", n)

  i <- 1

  while(i <= n)
  {
    u <- runif(2, 0, 1)
    v <- 2 * u - 1
    w <- sum(v^2)

    if (w < 1)
    {
      y <- sqrt(-2 * log(w) / w)

      z <- v * y

      x[i] <- z[1] 

      if ((i + 1) <= n)
      {
        x[i + 1] <- z[2]
        i <- i + 1
      }

      i <- i + 1
    }
  }

  x * sd + mean
}

hist(marsaglia_bray(1000))

您也可以考虑使用Ziggurat Alogrithm

如果要从反转CDF中真正采样,则CDF = 1/2(1 + erf(x-mu / sigma * sqrt(2)))

要反转它,您需要erf -1 (x),可以使用qnorm表示qnorm 沿线

erfinv <- function (x) {
    qnorm((1.0 + x)/2.0)/sqrt(2.0)
}

sample <- function(U01, mu, sigma) {
    N01 = sqrt(2.0) * erfinv( 2.0 * U01 - 1.0 )
    mu + sigma*N01
}

n = 10

u <- runif(n)
q <- sample(u, 0.0, 1.0)

print(u)
print(q)

在这里检查CDF和分位数功能

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM