Chapter 3 蒙特卡洛积分

3.1 Buffon投针问题

平面上画有很多平行线,其间距为 a。现向此平面投掷长为 l (l<a) 的针,则针的位置可以由两个数决定:针的中点与最接近的平行线之间的距离 x 和针与平行线的夹角 φ,则样本空间为Ω={(φ,x)0φπ,0xa2}. 所感兴趣的事件“针与平行线相交”对应的区域为g={(φ,x)xl2sinφ}. 因此,针与任一平行线相交的概率为P=|g||Ω|=π0l2sinφdφπ(a/2)=2laπ.

这一问题可以用来估计 π 的近似值。方法是重复投针 N 次,统计与平行线相交的次数 n,则根据频率与概率的关系可知,当 N 足够大时,2laπ=PnN  π2lNan.

对应的R代码如下:

a <- 2
l <- 1
N <- 100000
x <- runif(N, 0, a/2)
phi <- runif(N, 0, pi)
pihat <- 2*l/a/mean(l*sin(phi)/2>x)
pihat
## [1] 3.141394

可见结果与真实的圆周率的值十分接近。

设计一个随机试验,通过大量重复试验得到某种结果,以确定我们感兴趣的量,由此发展而成了著名的蒙特卡洛(Monte-Carlo)方法。

3.2 简易蒙特卡洛估计

现在我们感兴趣的问题是要计算定积分 baf(x)dx. 可以有几种做法:

  • 分析方法(微积分):具有局限性;
  • 数值积分:对一维情形较容易;
  • 蒙特卡洛方法:具有普适应用。

蒙特卡洛方法的想法就是利用样本均值代替总体均值,即baf(x)dx=bag(x)1badx=E[g(X)]1mmi=1g(Xi), 其中 XU(a,b)g(x)=(ba)f(x)X1,,Xm i.i.d. U(a,b),而 m 是一个充分大的正整数。

例如,要计算θ=42exdx=2E(eX),XU(2,4), 可依赖如下MC代码实现:

m <- 100000
x <- runif(m, 2, 4)
thetahat <- mean(exp(-x))*2
thetahat
## [1] 0.1170082

而积分的真值为 e2e4=0.1170196,可见十分接近。

再如,要计算θ=x0et22dt=EY[xeY22],YU(0,x),

可依赖如下MC代码实现:

m <- 100000
x <- 1
y <- runif(m, 0, x)
thetahat <- mean(x*exp(-y^2/2))
thetahat
## [1] 0.8555551

而积分的真值为 2π(Φ(1)0.5)=0.8556244,可见十分接近。

3.2.1 理论性质

考虑蒙特卡洛积分估计的一般情形,即θ=Af(x)dx=Ag(x)h(x)dx=EX[g(X)], 其中 X 是在支撑 A 上具有 p.d.f./p.m.f. h(x) 的随机变量。蒙特卡洛积分估计为ˆθ=1mmi=1g(Xi), 其中 X1,,Xm i.i.d. h(x)

不难证明 ˆθ 是无偏估计、相合估计,而它的方差为 1mVar[g(X1)],它的估计为ˆσ2m=1m(m1)mi=1(g(xi)¯g(x))2, 其中 ¯g(x)=1mmi=1g(xi)。进而可以给出 θ 的近似置信区间等。

例如,在上例中,可以进一步计算

thetas <- x*exp(-y^2/2)
se <- sd(thetas)/sqrt(m)
c(thetahat - 1.96*se, thetahat + 1.96*se)
## [1] 0.8548031 0.8563072

此即 θ 的水平为 95% 的近似置信区间。

3.3 方差缩减

为了提高蒙特卡洛估计的准确性,我们希望降低 ˆθ 的方差,当然我们可以通过增大样本量来实现这一功能,但一般地,我们还是希望能够减少 Var[g(X1)] 的值。

3.3.1 对偶变量

U1U2 均为 θ 的无偏估计量,而且负相关,则 (U1+U2)/2 也是 θ 的无偏估计量,且方差Var(U1+U22)=Var(U1)+Var(U2)+Cov(U1,U2)4<Var(U1)+Var(U2)4.

不妨设 Var(U1)=Var(U2),则如果分别用 X1,,Xm/2 (i.i.d.) 和 Y1,,Ym/2 (i.i.d.) 来计算 U1U2 的值,并且 U1U2 是负相关的,那么 (U1+U2)/2 的方差会小于用 X1,,Xm/2,Xm/2+1,,Xm (i.i.d.) 来计算的估计量的方差,这就实现了方差缩减的功能。

在实际应用中,如果要求生成的均匀随机变量来自 U(a,b),我们常常考虑基于 Ua+bU 来得到积分的(方差更小的)估计。

例如,在上面第二个例子中,我们可以考虑前 m/2 部分由 YU(0,x) 产生,而后 m/2 部分由 xY 产生(这里的 Y 是刚刚产生的随机数),即ˆθ=1mm/2i=1[xeU2i2+xe(xUi)22],UiU(0,x).

参看下述代码:

MCtheta <- function(x, R = 1000, antithetic = TRUE) {
  u <- runif(R/2,0,x)
  if (!antithetic) v <- runif(R/2,0,x) else v <- x - u
  y <- c(u, v)
  thetahat <- mean(x*exp(-y^2/2))
  return(thetahat)
}
m <- 1000
MC1 <- MC2 <- numeric(m)
x <- 1
for (i in 1:m) {
  MC1[i] <- MCtheta(x, R = 1000, anti = FALSE)
  MC2[i] <- MCtheta(x, R = 1000)
}
c(sd(MC1), sd(MC2), sd(MC2)/sd(MC1))
## [1] 0.003814995 0.001128930 0.295919151

从最后一个值中可以看到,采用对偶变量法大大减少了估计量的方差。

3.3.2 控制变量

注意到如果 g(X)θ 的一个无偏估计量,那么g(X)+c(f(X)E[f(X)]) 也是 θ 的无偏估计量,这里 c 是一个常数,而 f(x) 是任意期望存在且有限的函数。

可以计算得到该估计量方差最小时对应的 cc=Cov(g(X),f(X))Var(f(X)), 对应的最小方差为Var[g(X)][1Corr2(g(X),f(X))].

由此可以实现方差缩减。但是需要注意以下几个问题:

  • E[f(X)] 需要有显式表达,否则无偏估计量的形式无法得到;
  • 当且仅当 f(X)g(X) 相关时,这种方法才有效,而且强相关情况下,方差缩减的性能更佳。
  • c 的值可以分析计算也可以数值计算。

例如,要计算 θ=E(eU)=10eudu,考虑控制函数 f(U)=UeUU=0 处的一阶Taylor展开),于是E[f(U)]=0.5,c=Cov(eU,U)Var(U)=6e18.

不难计算得Var[g(U)]0.242,Var[g(U)c(U0.5)]0.00394.

理论上看,方差得到了很大程度上的缩减。下面用代码验证之。

m <- 100000
cstar <- 6*exp(1)-18
U <- runif(m)
T1 <- exp(U)
T2 <- exp(U) + cstar*(U - 0.5)
c(mean(T1), mean(T2), exp(1)-1)
## [1] 1.716906 1.718269 1.718282

可以看到控制变量的方法得到的结果更接近真值。

c(var(T1), var(T2), (var(T1)-var(T2))/var(T1))
## [1] 0.241758782 0.003932706 0.983732933

而方差也是控制变量的结果更小,跟理论值一致,而方差也是缩减了98.37%之多。

cor(T1, U)
## [1] 0.9918333

可见 f(U)g(U) 之间的相关性很强。


下面这个例子是 c 不容易分析计算而要采用数值计算的情况。

要计算 θ=E(eU1+U2)=10eu1+u2du,考虑控制函数 f(U)=e0.51+U2,于是E[f(U)]=e0.5π/4,c 的值需要数值计算。参看如下代码:

f <- function(u) exp(-0.5)/(1+u^2)
g <- function(u) exp(-u)/(1+u^2)
u <- runif(10000)
cstar <- - cov(f(u), g(u)) / var(f(u))
m <- 100000
u <- runif(m)
T1 <- g(u)
T2 <- g(u) + cstar * (f(u) - exp(-0.5)*pi/4)
c(mean(T1), mean(T2))
## [1] 0.5243167 0.5246916

故积分的真值应约为0.524

c(var(T1), var(T2), (var(T1)-var(T2))/var(T1))
## [1] 0.059914090 0.003098884 0.948277880

可见方差缩减了94.83%之多。

3.3.3 重要性采样

回到蒙特卡洛积分的一般情形,即θ=Ag(x)dx=Ag(x)f(x)f(x)dx=EX[g(X)f(X)], 其中 X 是在支撑 A 上具有 p.d.f./p.m.f. f(x) 的随机变量。蒙特卡洛积分估计为ˆθ=1mmi=1g(Xi)f(Xi), 其中 X1,,Xm i.i.d. f(x)

前面所讲述的方法都取了 f(x) 为对应支撑上的均匀分布,也就是说将所有的都赋予相同的权重,但这有时候在计算时效率不是很高,这从前面两种方差缩减方法中也可以看出来。

重要性采样的思想是用一个十分接近 g(x) 且容易采样的概率密度函数 f(x) 来进行重要性采样,这种估计的方差Var(ˆθ)=1mVar[g(X1)f(X1)]g()=cf() 对某个常数 c 成立时达到最小值0,这里的 f() 称为 g() 的重要性函数。

同样考虑上例中的积分 θ=10ex1+x2dx,考虑以下几个重要性函数:

f1(x)=1,0<x<1,f2(x)=ex,0<x<,f3(x)=1π(1+x2),<x<,f4(x)=ex1e1,0<x<1,f5(x)=4π(1+x2),0<x<1.

记被积函数为 g(x)=ex1+x2,0<x<1,先在同一坐标系中画出 0~1 范围内各自的函数图像比较。

x <- seq(0, 1, 0.01)
g <- exp(-x) / (1+x^2)
f1 <- replicate(length(x), 1)
f2 <- exp(-x)
f3 <- 1 / (1+x^2) / pi
f4 <- exp(-x) / (1 - exp(-1))
f5 <- 4 / (1+x^2) / pi

plot(x, g, type = 'l', xlab='x', ylab='', xlim=c(0,1), ylim=c(0,2), lwd=2)
lines(x, f1, col=2, lty=2, lwd=1.5)
lines(x, f2, col=7, lty=3, lwd=1.5)
lines(x, f3, col=3, lty=4, lwd=1.5)
lines(x, f4, col=4, lty=5, lwd=1.5)
lines(x, f5, col=5, lty=6, lwd=1.5)
legend("topright", c(expression(g(x)==e^{-x}/(1+x^2)),
                     expression(f[1](x)==1),
                     expression(f[2](x)==e^{-x}),
                     expression(f[3](x)==1/pi/(1+x^2)),
                     expression(f[4](x)==e^{-x}/(1-e^{-1})),
                     expression(f[5](x)==4/pi/(1+x^2))),
       col=c(1, 2, 7, 3, 4, 5), lty=c(1, 2, 3, 4, 5, 6), lwd=c(2, 1.5, 1.5, 1.5, 1.5, 1.5),
       x.intersp=0.5, y.intersp=1.2, inset = 0.02, bty = 'o', text.width=0.25)

m <- 10000
thetahat <- se <- numeric(5)
g <- function(x) {exp(-x) / (1+x^2) * (x>0) * (x<1)}

x <- runif(m)  # f1
gf <- g(x)
thetahat[1] <- mean(gf)
se[1] <- sd(gf)

x <- rexp(m, 1) # f2
gf <- 1/(1+x^2) * (x<1)
thetahat[2] <- mean(gf)
se[2] <- sd(gf)

x <- rcauchy(m) # f3
x <- x * (x>0) * (x<1) # Note the range of x
gf <- pi * exp(-x) * (x>0) * (x<1)
thetahat[3] <- mean(gf)
se[3] <- sd(gf)

u <- runif(m) # f4
x <- - log(1 - u * (1 - exp(-1)))
gf <- (1 - exp(-1)) / (1 + x^2)
thetahat[4] <- mean(gf)
se[4] <- sd(gf)

u <- runif(m) # f5
x <- tan(pi * u / 4)
gf <- pi * exp(-x) / 4
thetahat[5] <- mean(gf)
se[5] <- sd(gf)

rbind(thetahat, se)
              [,1]      [,2]     [,3]       [,4]      [,5]
thetahat 0.5236325 0.5159951 0.523879 0.52507935 0.5277204
se       0.2448966 0.4204343 0.952761 0.09674458 0.1397128

可以看到,用与目标函数形式较一致的重要性函数所最终得到的结果更加精确,标准差也更小。

3.3.4 分层采样

考虑将 M 个样本分层为 k 层,每层样本数为 mi (i=1,,k),考虑分层估计量ˆθS=ki=1wiˆθi 其中每一层的采用MC估计 ˆθiwi 是每一层的权重。不难证明 Var(ˆθS)Var(ˆθM),这里 ˆθM 是直接采用 M 个样本做的简单MC估计。


命题.ˆθM=1MMi=1g(Ui) 为直接采用 M 个样本做的简单MC估计,ˆθS=1kkj=1ˆθj 为分层估计量(这里假设均匀分层,即 m=M/k),其中 ˆθj=1mmi=1g(Uji)。于是Var(ˆθS)=1k2kj=1Var(ˆθj)=1k2kj=11mσ2j=1Mkkj=1σ2j.

另外,设 J 是随机选择的层,它服从概率为 1/k 的离散均匀分布,于是

Var(ˆθM)=Var(g(U))M=1M[Var(E[g(U)J])+E[Var(g(U)J)]]=1M(Var(θJ)+E(σ2J))=1M(Var(θJ)+1kkj=1σ2j)=1MVar(θJ)+Var(ˆθS)Var(ˆθS).


同样考虑上例中的积分 θ=10ex1+x2dx,注意到

10ex1+x2dx=ki=1i/k(i1)/kex1+x2dx=1kki=1i/k(i1)/kex1+x2kdx=1kki=1E(eXi1+X2i),XiU(i1k,ik).

因此,分层采样的代码实现如下:

M <- 10000
k <- 10
m <- M / k
N <- 100
T2 <- numeric(k)
est <- matrix(0, N, 2)
g <- function(x) {
  exp(-x)/(1+x^2) * (x>0) * (x<1)
}
for (i in 1:N) {
  est[i, 1] <- mean(g(runif(M)))
  for (j in 1:k) {
    T2[j] <- mean(g(runif(m, (j-1)/k, j/k)))
  }
  est[i, 2] <- mean(T2)
}
mu = apply(est, 2, mean)
se = apply(est, 2, sd)
rbind(mu, se)
          [,1]        [,2]
mu 0.524716298 0.524775325
se 0.002444945 0.000222032

可见分层采样的方差比简单MC方法的方差要小得多。