Chapter 3 蒙特卡洛积分
3.1 Buffon投针问题
平面上画有很多平行线,其间距为 a。现向此平面投掷长为 l (l<a) 的针,则针的位置可以由两个数决定:针的中点与最接近的平行线之间的距离 x 和针与平行线的夹角 φ,则样本空间为Ω={(φ,x)∣0≤φ≤π,0≤x≤a2}. 所感兴趣的事件“针与平行线相交”对应的区域为g={(φ,x)∣x≤l2sinφ}. 因此,针与任一平行线相交的概率为P=|g||Ω|=∫π0l2sinφdφπ(a/2)=2laπ.
这一问题可以用来估计 π 的近似值。方法是重复投针 N 次,统计与平行线相交的次数 n,则根据频率与概率的关系可知,当 N 足够大时,2laπ=P≈nN ⇒ π≈2lNan.
对应的R代码如下:
<- 2
a <- 1
l <- 100000
N <- runif(N, 0, a/2)
x <- runif(N, 0, pi)
phi <- 2*l/a/mean(l*sin(phi)/2>x)
pihat pihat
## [1] 3.141394
可见结果与真实的圆周率的值十分接近。
设计一个随机试验,通过大量重复试验得到某种结果,以确定我们感兴趣的量,由此发展而成了著名的蒙特卡洛(Monte-Carlo)方法。
3.2 简易蒙特卡洛估计
现在我们感兴趣的问题是要计算定积分 ∫baf(x)dx. 可以有几种做法:
- 分析方法(微积分):具有局限性;
- 数值积分:对一维情形较容易;
- 蒙特卡洛方法:具有普适应用。
蒙特卡洛方法的想法就是利用样本均值代替总体均值,即∫baf(x)dx=∫bag(x)1b−adx=E[g(X)]≈1mm∑i=1g(Xi), 其中 X∼U(a,b),g(x)=(b−a)f(x),X1,…,Xm i.i.d. ∼U(a,b),而 m 是一个充分大的正整数。
例如,要计算θ=∫42e−xdx=2E(e−X),X∼U(2,4), 可依赖如下MC代码实现:
<- 100000
m <- runif(m, 2, 4)
x <- mean(exp(-x))*2
thetahat thetahat
## [1] 0.1170082
而积分的真值为 e−2−e−4=0.1170196,可见十分接近。
再如,要计算θ=∫x0e−t22dt=EY[xe−Y22],Y∼U(0,x),
可依赖如下MC代码实现:
<- 100000
m <- 1
x <- runif(m, 0, x)
y <- mean(x*exp(-y^2/2))
thetahat 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) 的随机变量。蒙特卡洛积分估计为ˆθ=1mm∑i=1g(Xi), 其中 X1,…,Xm i.i.d. ∼h(x)。
不难证明 ˆθ 是无偏估计、相合估计,而它的方差为 1mVar[g(X1)],它的估计为ˆσ2m=1m(m−1)m∑i=1(g(xi)−¯g(x))2, 其中 ¯g(x)=1mm∑i=1g(xi)。进而可以给出 θ 的近似置信区间等。
例如,在上例中,可以进一步计算
<- x*exp(-y^2/2)
thetas <- sd(thetas)/sqrt(m)
se c(thetahat - 1.96*se, thetahat + 1.96*se)
## [1] 0.8548031 0.8563072
此即 θ 的水平为 95% 的近似置信区间。
3.3 方差缩减
为了提高蒙特卡洛估计的准确性,我们希望降低 ˆθ 的方差,当然我们可以通过增大样本量来实现这一功能,但一般地,我们还是希望能够减少 Var[g(X1)] 的值。
3.3.1 对偶变量
设 U1 和 U2 均为 θ 的无偏估计量,而且负相关,则 (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.) 来计算 U1 和 U2 的值,并且 U1 和 U2 是负相关的,那么 (U1+U2)/2 的方差会小于用 X1,…,Xm/2,Xm/2+1,…,Xm (i.i.d.) 来计算的估计量的方差,这就实现了方差缩减的功能。
在实际应用中,如果要求生成的均匀随机变量来自 U(a,b),我们常常考虑基于 U 和 a+b−U 来得到积分的(方差更小的)估计。
例如,在上面第二个例子中,我们可以考虑前 m/2 部分由 Y∼U(0,x) 产生,而后 m/2 部分由 x−Y 产生(这里的 Y 是刚刚产生的随机数),即ˆθ′=1mm/2∑i=1[xe−U2i2+xe−(x−Ui)22],Ui∼U(0,x).
参看下述代码:
<- function(x, R = 1000, antithetic = TRUE) {
MCtheta <- runif(R/2,0,x)
u if (!antithetic) v <- runif(R/2,0,x) else v <- x - u
<- c(u, v)
y <- mean(x*exp(-y^2/2))
thetahat return(thetahat)
}<- 1000
m <- MC2 <- numeric(m)
MC1 <- 1
x for (i in 1:m) {
<- MCtheta(x, R = 1000, anti = FALSE)
MC1[i] <- MCtheta(x, R = 1000)
MC2[i]
}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) 是任意期望存在且有限的函数。
可以计算得到该估计量方差最小时对应的 c⋆ 为c⋆=−Cov(g(X),f(X))Var(f(X)), 对应的最小方差为Var[g(X)][1−Corr2(g(X),f(X))].
由此可以实现方差缩减。但是需要注意以下几个问题:
- E[f(X)] 需要有显式表达,否则无偏估计量的形式无法得到;
- 当且仅当 f(X) 和 g(X) 相关时,这种方法才有效,而且强相关情况下,方差缩减的性能更佳。
- c⋆ 的值可以分析计算也可以数值计算。
例如,要计算 θ=E(eU)=∫10eudu,考虑控制函数 f(U)=U(eU 在 U=0 处的一阶Taylor展开),于是E[f(U)]=0.5,c⋆=−Cov(eU,U)Var(U)=6e−18.
不难计算得Var[g(U)]≈0.242,Var[g(U)−c⋆(U−0.5)]≈0.00394.
理论上看,方差得到了很大程度上的缩减。下面用代码验证之。
<- 100000
m <- 6*exp(1)-18
cstar <- runif(m)
U <- exp(U)
T1 <- exp(U) + cstar*(U - 0.5)
T2 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(e−U1+U2)=∫10e−u1+u2du,考虑控制函数 f(U)=e−0.51+U2,于是E[f(U)]=e−0.5π/4, 而 c⋆ 的值需要数值计算。参看如下代码:
<- function(u) exp(-0.5)/(1+u^2)
f <- function(u) exp(-u)/(1+u^2)
g <- runif(10000)
u <- - cov(f(u), g(u)) / var(f(u))
cstar <- 100000
m <- runif(m)
u <- g(u)
T1 <- g(u) + cstar * (f(u) - exp(-0.5)*pi/4)
T2 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) 的随机变量。蒙特卡洛积分估计为ˆθ=1mm∑i=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(⋅) 的重要性函数。
同样考虑上例中的积分 θ=∫10e−x1+x2dx,考虑以下几个重要性函数:
f1(x)=1,0<x<1,f2(x)=e−x,0<x<∞,f3(x)=1π(1+x2),−∞<x<∞,f4(x)=e−x1−e−1,0<x<1,f5(x)=4π(1+x2),0<x<1.
记被积函数为 g(x)=e−x1+x2,0<x<1,先在同一坐标系中画出 0~1 范围内各自的函数图像比较。
<- seq(0, 1, 0.01)
x <- exp(-x) / (1+x^2)
g <- replicate(length(x), 1)
f1 <- exp(-x)
f2 <- 1 / (1+x^2) / pi
f3 <- exp(-x) / (1 - exp(-1))
f4 <- 4 / (1+x^2) / pi
f5
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)
<- 10000
m <- se <- numeric(5)
thetahat <- function(x) {exp(-x) / (1+x^2) * (x>0) * (x<1)}
g
<- runif(m) # f1
x <- g(x)
gf 1] <- mean(gf)
thetahat[1] <- sd(gf)
se[
<- rexp(m, 1) # f2
x <- 1/(1+x^2) * (x<1)
gf 2] <- mean(gf)
thetahat[2] <- sd(gf)
se[
<- rcauchy(m) # f3
x <- x * (x>0) * (x<1) # Note the range of x
x <- pi * exp(-x) * (x>0) * (x<1)
gf 3] <- mean(gf)
thetahat[3] <- sd(gf)
se[
<- runif(m) # f4
u <- - log(1 - u * (1 - exp(-1)))
x <- (1 - exp(-1)) / (1 + x^2)
gf 4] <- mean(gf)
thetahat[4] <- sd(gf)
se[
<- runif(m) # f5
u <- tan(pi * u / 4)
x <- pi * exp(-x) / 4
gf 5] <- mean(gf)
thetahat[5] <- sd(gf)
se[
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=k∑i=1wiˆθi 其中每一层的采用MC估计 ˆθi,wi 是每一层的权重。不难证明 Var(ˆθS)≤Var(ˆθM),这里 ˆθM 是直接采用 M 个样本做的简单MC估计。
命题. 记 ˆθM=1MM∑i=1g(Ui) 为直接采用 M 个样本做的简单MC估计,ˆθS=1kk∑j=1ˆθj 为分层估计量(这里假设均匀分层,即 m=M/k),其中 ˆθj=1mm∑i=1g(Uji)。于是Var(ˆθS)=1k2k∑j=1Var(ˆθj)=1k2k∑j=11mσ2j=1Mkk∑j=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)+1kk∑j=1σ2j)=1MVar(θJ)+Var(ˆθS)≥Var(ˆθS).
同样考虑上例中的积分 θ=∫10e−x1+x2dx,注意到
∫10e−x1+x2dx=k∑i=1∫i/k(i−1)/ke−x1+x2dx=1kk∑i=1∫i/k(i−1)/ke−x1+x2kdx=1kk∑i=1E(e−Xi1+X2i),Xi∼U(i−1k,ik).
因此,分层采样的代码实现如下:
<- 10000
M <- 10
k <- M / k
m <- 100
N <- numeric(k)
T2 <- matrix(0, N, 2)
est <- function(x) {
g exp(-x)/(1+x^2) * (x>0) * (x<1)
}for (i in 1:N) {
1] <- mean(g(runif(M)))
est[i, for (j in 1:k) {
<- mean(g(runif(m, (j-1)/k, j/k)))
T2[j]
}2] <- mean(T2)
est[i,
}= apply(est, 2, mean)
mu = apply(est, 2, sd)
se rbind(mu, se)
[,1] [,2]
mu 0.524716298 0.524775325
se 0.002444945 0.000222032
可见分层采样的方差比简单MC方法的方差要小得多。