强化学习篇---蒙特卡洛算法
蒙特卡洛方法深度解析:用随机性解决确定性问题
什么是蒙特卡洛方法?
蒙特卡洛方法(Monte Carlo Method)是一类通过随机采样和统计模拟来求解数学问题的计算方法。它的核心思想是:用大量的随机试验,用频率来估计概率,用样本均值来估计期望值。
名字来源于摩纳哥的蒙特卡洛赌场——因为赌博本身就是随机性的游戏。
想象一下:
-
要估算一个不规则图形的面积 → 往图形所在的方形区域随机扔豆子,看落在图形内的比例
-
要计算π的近似值 → 往正方形里随机投点,统计落在内切圆内的比例
-
要预测明天股票价格 → 模拟成千上万条可能的价格路径,取平均值
生活中的蒙特卡洛方法
例子1:估算圆形面积
import random
def estimate_circle_area(radius, num_points):
"""
用蒙特卡洛方法估算圆的面积
原理:正方形面积 × (圆内点数/总点数)
"""
count_inside = 0
for _ in range(num_points):
x = random.uniform(-radius, radius)
y = random.uniform(-radius, radius)
if x*x + y*y <= radius*radius:
count_inside += 1
square_area = (2*radius) ** 2
circle_area = square_area * (count_inside / num_points)
return circle_area
# 估算半径为1的圆面积(理论值π ≈ 3.14159)
print(f"1000个点: {estimate_circle_area(1, 1000)}")
print(f"10000个点: {estimate_circle_area(1, 10000)}")
print(f"100000个点: {estimate_circle_area(1, 100000)}")
例子2:估算π值
def estimate_pi(num_points):
"""
用蒙特卡洛方法估算π
原理:π ≈ 4 × (圆内点数/总点数)
"""
count_inside = 0
for _ in range(num_points):
x = random.random() # 0到1之间的随机数
y = random.random()
if x*x + y*y <= 1:
count_inside += 1
return 4 * count_inside / num_points
print(f"估算的π值: {estimate_pi(100000)}")
蒙特卡洛方法的核心思想
大数定律——理论基础
随着试验次数增加,样本均值会收敛到真实期望值
通俗理解:抛硬币次数越多,正面朝上的比例越接近50%
中心极限定理——误差估计
告诉我们估计值的误差范围
通俗理解:10000次抛硬币,正面比例在49%-51%之间的概率是95%
蒙特卡洛方法的三大应用领域
1. 数值积分(计算复杂积分)
问题:计算∫₀¹ e^(-x²) dx,这个积分没有解析解
def monte_carlo_integration(func, a, b, num_samples):
"""
用蒙特卡洛方法计算定积分
∫_a^b f(x) dx ≈ (b-a) × 平均f(x)
"""
total = 0
for _ in range(num_samples):
x = random.uniform(a, b)
total += func(x)
average = total / num_samples
return (b - a) * average
# 计算 ∫₀¹ e^(-x²) dx
result = monte_carlo_integration(lambda x: math.exp(-x*x), 0, 1, 100000)
print(f"积分结果: {result}")
2. 最优化问题(随机搜索)
问题:在复杂函数中寻找全局最优解
def monte_carlo_optimization(func, bounds, num_samples):
"""
用蒙特卡洛方法寻找函数最大值
bounds: [(x1_min, x1_max), (x2_min, x2_max), ...]
"""
best_x = None
best_y = float('-inf')
for _ in range(num_samples):
# 随机生成一个点
x = [random.uniform(low, high) for low, high in bounds]
y = func(x)
if y > best_y:
best_y = y
best_x = x
return best_x, best_y
3. 概率模拟(风险评估)
问题:评估投资组合的风险
def portfolio_risk_simulation(initial_investment, returns, volatilities, correlations, num_simulations):
"""
蒙特卡洛模拟投资组合风险
"""
final_values = []
for _ in range(num_simulations):
# 模拟一年的收益率
yearly_return = generate_correlated_returns(returns, volatilities, correlations)
final_value = initial_investment * (1 + yearly_return)
final_values.append(final_value)
# 计算风险指标
var_95 = np.percentile(final_values, 5) # 95% VaR
expected_shortfall = np.mean([v for v in final_values if v <= var_95])
return {
'mean': np.mean(final_values),
'std': np.std(final_values),
'var_95': var_95,
'expected_shortfall': expected_shortfall
}
蒙特卡洛在强化学习中的应用
蒙特卡洛强化学习——从完整轨迹学习
智能体玩完整局游戏,记录每一步的状态、动作、奖励,然后回头计算每个状态的真实价值。
class MonteCarloRL:
"""
蒙特卡洛强化学习
特点:必须等到回合结束才能学习
"""
def __init__(self, states, actions, gamma=0.9):
self.gamma = gamma
self.Q = {} # 动作价值函数
self.returns = {} # 记录每个状态-动作对的回报
self.policy = {} # 策略
def generate_episode(self, env):
"""生成一个完整的回合"""
episode = []
state = env.reset()
done = False
while not done:
# 根据策略选择动作
action = self.get_action(state)
next_state, reward, done = env.step(action)
episode.append((state, action, reward))
state = next_state
return episode
def update(self, episode):
"""用整个回合的经验更新Q值"""
G = 0 # 累积奖励
visited = set() # 记录已经更新过的状态-动作对
# 从后往前遍历
for t in range(len(episode)-1, -1, -1):
state, action, reward = episode[t]
G = self.gamma * G + reward # 计算累积奖励
# 首次访问蒙特卡洛
if (state, action) not in visited:
visited.add((state, action))
# 初始化returns列表
if (state, action) not in self.returns:
self.returns[(state, action)] = []
# 记录这次回报
self.returns[(state, action)].append(G)
# 更新Q值为平均值
self.Q[(state, action)] = np.mean(self.returns[(state, action)])
# 更新策略:选择Q值最大的动作
self.update_policy(state)
蒙特卡洛 vs 时序差分学习
| 特性 | 蒙特卡洛方法 | 时序差分学习 |
|---|---|---|
| 更新时机 | 回合结束后 | 每一步 |
| 需要模型 | 不需要 | 不需要 |
| 偏差 | 无偏估计 | 有偏估计 |
| 方差 | 高 | 低 |
| 学习速度 | 慢(需要完整回合) | 快(在线学习) |
| 适用场景 | 回合制游戏 | 连续任务 |
蒙特卡洛树搜索(MCTS)——AlphaGo的核心技术
什么是MCTS?
一种结合了树搜索和蒙特卡洛模拟的决策方法,在巨大搜索空间中高效寻找最优决策。
MCTS的四步循环
class MCTSNode:
"""蒙特卡洛树搜索节点"""
def __init__(self, state, parent=None):
self.state = state
self.parent = parent
self.children = {}
self.visits = 0
self.value = 0
def ucb_score(self, exploration_constant=1.41):
"""计算UCB分数(平衡探索与利用)"""
if self.visits == 0:
return float('inf')
exploitation = self.value / self.visits
exploration = exploration_constant * math.sqrt(
math.log(self.parent.visits) / self.visits
)
return exploitation + exploration
def mcts_search(root_state, num_iterations):
"""蒙特卡洛树搜索主循环"""
root = MCTSNode(root_state)
for _ in range(num_iterations):
# 1. 选择(Selection)
node = root
while node.children and not node.state.is_terminal():
node = select_best_child(node)
# 2. 扩展(Expansion)
if not node.state.is_terminal():
node = expand_node(node)
# 3. 模拟(Simulation)
result = simulate_random_play(node.state)
# 4. 回溯(Backpropagation)
backpropagate(node, result)
# 返回访问次数最多的子节点
return best_child(root)
MCTS在AlphaGo中的应用
-
选择:根据神经网络评估的价值选择最有希望的走法
-
扩展:将新状态加入搜索树
-
模拟:用快速走子策略快速模拟到终局
-
回溯:将结果向上传播,更新节点价值
蒙特卡洛方法的优缺点
优点
✅ 简单直观:容易理解和实现
✅ 适用范围广:几乎可以解决任何概率问题
✅ 并行性好:可以轻松并行计算
✅ 维度灾难免疫:计算复杂度与维度无关
✅ 不需要解析解:适合复杂系统
缺点
❌ 收敛速度慢:需要大量样本,精度与√N成正比
❌ 计算量大:要达到高精度需要海量计算
❌ 伪随机数依赖:随机数质量影响结果
❌ 维度诅咒(在高维空间):虽然复杂度与维度无关,但需要更多样本覆盖空间
蒙特卡洛方法的改进技术
1. 重要性采样(Importance Sampling)
用已知分布采样,再加权调整
def importance_sampling_integration(func, proposal_dist, target_dist, num_samples):
"""
重要性采样:用容易采样的分布代替难采样的分布
"""
total = 0
for _ in range(num_samples):
x = proposal_dist.sample()
weight = target_dist.pdf(x) / proposal_dist.pdf(x)
total += func(x) * weight
return total / num_samples
2. 马尔可夫链蒙特卡洛(MCMC)
当分布复杂时,用马尔可夫链生成样本
def metropolis_hastings(target_dist, initial_state, num_samples, proposal_std=1.0):
"""
Metropolis-Hastings MCMC算法
"""
samples = [initial_state]
current = initial_state
for _ in range(num_samples - 1):
# 提议新状态
proposal = current + np.random.normal(0, proposal_std)
# 计算接受概率
acceptance_ratio = target_dist(proposal) / target_dist(current)
# 决定是否接受
if np.random.random() < acceptance_ratio:
current = proposal
samples.append(current)
return samples
3. 准蒙特卡洛(Quasi-Monte Carlo)
用低差异序列代替随机数,提高收敛速度
import sobol_seq # Sobol序列库
def quasi_monte_carlo_integration(func, a, b, num_samples):
"""
准蒙特卡洛:用确定性的低差异序列
"""
# 生成Sobol序列
sobol_points = sobol_seq.i4_sobol_generate(1, num_samples)
total = 0
for x_norm in sobol_points:
x = a + (b - a) * x_norm[0]
total += func(x)
return (b - a) * total / num_samples
实际应用案例
案例1:金融衍生品定价
def monte_carlo_option_pricing(S0, K, T, r, sigma, num_simulations):
"""
蒙特卡洛方法定价欧式看涨期权
S0: 初始股价
K: 行权价
T: 到期时间
r: 无风险利率
sigma: 波动率
"""
payoffs = []
for _ in range(num_simulations):
# 模拟股价路径(几何布朗运动)
ST = S0 * np.exp((r - 0.5 * sigma**2) * T +
sigma * np.sqrt(T) * np.random.normal())
# 计算期权收益
payoff = max(ST - K, 0)
payoffs.append(payoff)
# 折现到当前时间
option_price = np.exp(-r * T) * np.mean(payoffs)
return option_price
案例2:机器人路径规划
def prm_path_planning(obstacles, start, goal, num_samples, connection_radius):
"""
概率路线图(Probabilistic Roadmap)路径规划
"""
# 1. 随机采样配置空间
nodes = [start, goal]
while len(nodes) < num_samples + 2:
sample = random_configuration()
if not collision(sample, obstacles):
nodes.append(sample)
# 2. 构建连接图
graph = {}
for node in nodes:
graph[node] = []
for other in nodes:
if node != other and distance(node, other) < connection_radius:
if not collision_path(node, other, obstacles):
graph[node].append(other)
# 3. 用A*或Dijkstra搜索路径
path = shortest_path(graph, start, goal)
return path
蒙特卡洛方法的收敛性分析
误差估计
误差 ∝ σ / √N 其中: σ 是样本标准差 N 是样本数量
要达到更高精度需要多少样本?
-
误差减半 → 样本数量需要增加4倍
-
误差降到1/10 → 样本数量需要增加100倍
Mermaid总结框图

蒙特卡洛方法的选择指南
| 问题类型 | 推荐方法 | 原因 |
|---|---|---|
| 简单积分 | 简单蒙特卡洛 | 实现简单,足够用 |
| 高维积分 | 准蒙特卡洛 | 收敛更快 |
| 复杂分布采样 | MCMC | 通用性强 |
| 强化学习 | 蒙特卡洛RL/MCTS | 适合回合制任务 |
| 稀有事件 | 重要性采样 | 提高采样效率 |
实战技巧
1. 方差缩减技术
def antithetic_variates(func, num_pairs):
"""
对偶变量法:用正负相关的样本对减少方差
"""
total = 0
for _ in range(num_pairs):
u = random.random()
total += (func(u) + func(1 - u)) / 2
return total / num_pairs
2. 控制变量法
def control_variates(func, control_func, expected_control, num_samples):
"""
控制变量法:用已知期望的函数减少方差
"""
samples_func = []
samples_control = []
for _ in range(num_samples):
x = random.random()
samples_func.append(func(x))
samples_control.append(control_func(x))
# 估计最优系数
cov = np.cov(samples_func, samples_control)[0,1]
var_control = np.var(samples_control)
c = cov / var_control
# 调整估计
adjusted_mean = np.mean(samples_func) - c * (np.mean(samples_control) - expected_control)
return adjusted_mean
一句话总结:蒙特卡洛方法是"用随机性对抗复杂性"的智慧——当问题太复杂无法精确求解时,就用海量随机采样,让大数定律帮你找到答案。从计算π到AlphaGo,从金融定价到物理模拟,蒙特卡洛方法无处不在。
更多推荐



所有评论(0)