第 10 章 Monte Carlo 方法

上一章介绍了如何生成随机数。本章讨论如何用随机数解决计算问题。Monte Carlo 方法的核心思想很简单:如果一个量可以写成某个随机变量函数的期望,就可以用大量随机样本的平均值来近似它。

在经济统计中,很多问题都可以用这种思路处理。例如,复杂收入分布下的贫困率、税收规则的平均负担、预测模型的未来误差、抽样调查估计量的抽样分布,都可以通过模拟来近似。Monte Carlo 方法不一定给出解析公式,但它给出了可执行、可诊断、可复现的计算路径。

10.1 Monte Carlo 积分

\(X\) 的密度为 \(f(x)\),我们希望计算

\[ \mu=E\{g(X)\}=\int g(x)f(x)\,dx. \]

若可以从 \(f(x)\) 中独立抽取样本 \(X_1,\ldots,X_N\),则 Monte Carlo 估计量为

\[ \hat\mu_N=\frac{1}{N}\sum_{i=1}^N g(X_i). \]

其中 \(N\) 是模拟次数,\(g(X_i)\) 是第 \(i\) 次模拟得到的函数值。根据大数定律,当 \(N\) 增大时,\(\hat\mu_N\) 会趋近于 \(\mu\)。根据中心极限定理,

\[ \hat\mu_N \approx N\left(\mu,\frac{\sigma_g^2}{N}\right), \]

其中 \(\sigma_g^2=\operatorname{Var}\{g(X)\}\)。因此,Monte Carlo 标准误可以估计为

\[ \widehat{\operatorname{se}}(\hat\mu_N) = \frac{s_g}{\sqrt{N}}, \]

这里 \(s_g\)\(g(X_1),\ldots,g(X_N)\) 的样本标准差。

10.2 例:补贴规则的平均支出

延续第 7 章的模拟收入分布。设家庭收入 \(Y\) 服从对数正态分布,低收入补贴函数为

\[ g(y)= \begin{cases} 2(1-y/4), & 0<y<4,\\ 0, & y\geq 4. \end{cases} \]

我们用 Monte Carlo 方法估计每户平均补贴支出。

set.seed(2026)
N <- 100000
income <- rlnorm(N, meanlog = log(8), sdlog = 0.6)
subsidy <- ifelse(income < 4, 2 * (1 - income / 4), 0)

mc_est <- mean(subsidy)
mc_se <- sd(subsidy) / sqrt(N)

c(estimate = mc_est,
  mc_se = mc_se,
  lower = mc_est - 1.96 * mc_se,
  upper = mc_est + 1.96 * mc_se)
#>  estimate     mc_se     lower     upper 
#> 0.0586503 0.0006198 0.0574354 0.0598652

这个区间不是传统意义上由抽样调查误差形成的置信区间,而是 Monte Carlo 计算误差的近似区间。它回答的是:在给定模型和模拟次数下,随机模拟本身带来的误差有多大。

10.3 模拟次数与误差

Monte Carlo 误差通常按 \(1/\sqrt{N}\) 的速度下降。也就是说,如果希望误差大约减半,模拟次数需要增加到原来的 4 倍。这一点和许多数值积分方法不同:Monte Carlo 在低维问题中未必最快,但在高维问题中非常有价值。

set.seed(1)
Ns <- c(100, 1000, 10000, 100000)
out <- data.frame(N = Ns, estimate = NA, mc_se = NA)

for (j in seq_along(Ns)) {
  y <- rlnorm(Ns[j], meanlog = log(8), sdlog = 0.6)
  g <- ifelse(y < 4, 2 * (1 - y / 4), 0)
  out$estimate[j] <- mean(g)
  out$mc_se[j] <- sd(g) / sqrt(Ns[j])
}

out
#>       N estimate     mc_se
#> 1 1e+02  0.03701 0.0147815
#> 2 1e+03  0.07073 0.0069786
#> 3 1e+04  0.06045 0.0020103
#> 4 1e+05  0.05891 0.0006216

实际工作中,不能只报告模拟均值,也要报告 Monte Carlo 标准误或至少说明模拟次数。否则读者无法判断结果的小数位是否有意义。

10.4 用模拟研究估计量性质

Monte Carlo 方法还可以用来研究估计量在重复抽样下的表现。假设我们关心一个简单消费函数

\[ C_i=\beta_0+\beta_1 Y_i+\varepsilon_i, \]

其中 \(C_i\) 是消费支出,\(Y_i\) 是收入,\(\varepsilon_i\) 是随机扰动。若真实边际消费倾向为\(\beta_1=0.6\),我们可以反复生成样本并估计线性回归,观察 \(\hat\beta_1\) 的抽样分布。

set.seed(2)
R <- 1000
n <- 200
beta1_hat <- numeric(R)

for (r in seq_len(R)) {
  income <- rlnorm(n, meanlog = log(8), sdlog = 0.5)
  consumption <- 1 + 0.6 * income + rnorm(n, sd = 2)
  beta1_hat[r] <- coef(lm(consumption ~ income))[2]
}

c(mean = mean(beta1_hat),
  sd = sd(beta1_hat),
  true_value = 0.6)
#>       mean         sd true_value 
#>    0.60085    0.03018    0.60000

这个实验帮助我们把“估计量是随机变量”这句话具体化。每次样本不同,估计结果也不同;重复模拟后,我们可以近似观察估计量的偏差、方差和均方误差。

10.5 重要性抽样

有时我们关心的是罕见事件,例如高收入尾部概率、极端亏损概率或违约概率。如果直接从原分布抽样,罕见事件出现次数很少,估计会很不稳定。重要性抽样通过改变抽样分布来提高效率。

设目标积分为

\[ \mu=\int g(x)f(x)\,dx. \]

如果从另一个更容易覆盖重要区域的密度 \(q(x)\) 抽样,则

\[ \mu=\int g(x)\frac{f(x)}{q(x)}q(x)\,dx =E_q\left\{g(X)\frac{f(X)}{q(X)}\right\}. \]

其中 \(w(x)=f(x)/q(x)\) 称为重要性权重。关键是 \(q(x)\) 要在 \(g(x)f(x)\) 贡献大的区域给出足够概率。

下面估计收入超过 20 万元的尾部概率。直接模拟可能需要很大样本,重要性抽样则从均值更高的对数正态分布中抽样,再用权重修正。

set.seed(3)
N <- 20000
threshold <- 20

# 直接 Monte Carlo
y_direct <- rlnorm(N, meanlog = log(8), sdlog = 0.6)
p_direct <- mean(y_direct > threshold)

# 重要性抽样:从更偏向高收入区域的分布中抽样
y_imp <- rlnorm(N, meanlog = log(12), sdlog = 0.6)
log_w <- dlnorm(y_imp, log(8), 0.6, log = TRUE) -
  dlnorm(y_imp, log(12), 0.6, log = TRUE)
w <- exp(log_w)
p_imp <- mean((y_imp > threshold) * w)
se_imp <- sd((y_imp > threshold) * w) / sqrt(N)

c(direct = p_direct,
  importance = p_imp,
  importance_se = se_imp)
#>        direct    importance importance_se 
#>     0.0645500     0.0639562     0.0009438

重要性抽样不是简单地“换一个分布抽样”。如果 \(q(x)\) 选得不好,权重可能极端不稳定,估计反而变差。因此,实际使用时要检查权重分布,例如是否有少数样本权重特别大。

10.6 方差缩减的基本思想

Monte Carlo 方法的成本主要来自随机误差。除了增加 \(N\),还可以通过更聪明的抽样降低方差。最简单的例子是对偶变量法。若要估计

\[ E\{h(U)\},\quad U\sim U(0,1), \]

可以同时使用 \(U\)\(1-U\)

\[ \hat\mu=\frac{1}{N}\sum_{i=1}^N \frac{h(U_i)+h(1-U_i)}{2}. \]

\(h\) 是单调函数时,两者往往负相关,从而降低方差。

set.seed(4)
R <- 1000
N <- 200
plain <- anti <- numeric(R)

for (r in seq_len(R)) {
  u <- runif(N)
  plain[r] <- mean(exp(u))
  anti[r] <- mean((exp(u) + exp(1 - u)) / 2)
}

c(plain_sd = sd(plain), antithetic_sd = sd(anti))
#>      plain_sd antithetic_sd 
#>      0.034165      0.004358

本书不系统展开所有方差缩减技术,但重要性抽样和对偶变量法说明了一个共同原则:模拟不是越蛮力越好,合理利用问题结构可以显著提高效率。

10.7 本章小结

Monte Carlo 方法用随机样本平均值近似期望和积分。它的理论基础是大数定律和中心极限定理,实际报告中应给出模拟次数和 Monte Carlo 标准误。Monte Carlo 不仅可以计算复杂积分,也可以通过重复抽样研究估计量的偏差、方差和均方误差。重要性抽样和方差缩减方法进一步说明,模拟设计本身也是统计计算的重要部分。

10.8 练习

  1. 用 Monte Carlo 方法估计标准正态分布下 \(P(X>2)\),并与 pnorm() 的结果比较。
  2. 在消费函数模拟中,把样本量从 50 改为 1000,观察 \(\hat\beta_1\) 的标准差如何变化。
  3. 用重要性抽样估计 \(P(Y>25)\),尝试不同的提议分布均值,并比较权重的稳定性。
  4. 解释为什么 Monte Carlo 误差下降速度是 \(1/\sqrt{N}\),这对模拟次数选择意味着什么?