在R中使用均匀(0,1)生成N(0,1)

时间:2017-04-25 18:32:42

标签: r statistics simulation probability normal-distribution

我正在尝试使用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)

3 个答案:

答案 0 :(得分:3)

您似乎将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)是双变量正常,零均值和同一性协方差。

答案 1 :(得分:3)

我所有评论的来源:

Averill M. Law,W。David Kelton, Simulation Modeling and Analysis ,第三版,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)随机变量,如果U1和{{U2,则存在严重的困难。 1}}实际上是由线性同余生成器产生的相邻随机数。 (第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.   
  3. 如果W > 1,请返回步骤1.否则,请Y = sqrt(-2 log(W)/W)X[1] = V[1] * YX[2] = V2 * Y。然后X[1]X[2]是IID N(0,1)随机变量。 (第466页)
  4.   

实现:

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

答案 2 :(得分:0)

如果你想从倒置的CDF真正采样,那么CDF = 1/2(1 + erf(x-mu / sigma * sqrt(2)))

要反转它,你需要erf -1 (x),可以用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和分位数函数here