news 2026/4/24 10:30:26

用Python和NumPy手把手教你实现10臂老虎机(附完整代码与可视化分析)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python和NumPy手把手教你实现10臂老虎机(附完整代码与可视化分析)

用Python和NumPy手把手教你实现10臂老虎机(附完整代码与可视化分析)

在强化学习的入门阶段,很多学习者都会被各种数学公式和抽象概念所困扰。今天,我们将通过一个经典的10臂老虎机问题,用Python代码带你直观理解强化学习的核心机制。不同于传统的理论讲解,我们将从零开始编写每一行代码,并通过实时可视化观察学习过程。

1. 理解多臂老虎机问题

多臂老虎机(Multi-armed Bandit)是强化学习中最基础的决策问题模型。想象你站在一个赌场里,面前有10台老虎机(slot machine),每台机器的中奖概率各不相同。你的目标是通过有限的尝试次数,找到最优的老虎机并获得最大累积奖励。

这个问题的核心在于探索-利用困境(Exploration-Exploitation Dilemma)

  • 探索:尝试不同的老虎机以收集信息
  • 利用:根据已有知识选择当前表现最好的老虎机
import numpy as np import matplotlib.pyplot as plt # 设置随机种子确保结果可复现 np.random.seed(42)

2. 构建老虎机环境

首先我们需要创建一个老虎机环境类。每个老虎机都有一个固定的中奖概率,但每次拉动臂杆的结果仍然是随机的。

class Bandit: def __init__(self, arms=10): # 随机生成10个老虎机的中奖概率 self.true_rates = np.random.rand(arms) def play(self, arm): # 模拟拉动指定老虎机臂杆的结果 rate = self.true_rates[arm] return 1 if rate > np.random.rand() else 0

提示:这里我们使用0和1作为奖励信号,1表示中奖,0表示未中奖。在实际应用中,奖励可以是任意数值。

3. 实现智能体决策逻辑

智能体需要维护两个关键信息:

  1. 每个动作的价值估计(Q值)
  2. 每个动作的尝试次数
class Agent: def __init__(self, epsilon, action_size=10): self.epsilon = epsilon # 探索率 self.Q = np.zeros(action_size) # 动作价值估计 self.counts = np.zeros(action_size) # 动作尝试次数 def update(self, action, reward): """根据新获得的奖励更新价值估计""" self.counts[action] += 1 # 增量式更新Q值 self.Q[action] += (reward - self.Q[action]) / self.counts[action] def get_action(self): """基于ε-greedy策略选择动作""" if np.random.rand() < self.epsilon: # 探索:随机选择动作 return np.random.randint(len(self.Q)) # 利用:选择当前估计价值最高的动作 return np.argmax(self.Q)

4. 完整训练流程与可视化

现在我们将环境、智能体和训练循环组合起来,并实时可视化学习过程。

def run_experiment(epsilon, steps=1000): bandit = Bandit() agent = Agent(epsilon) rewards = [] optimal_rates = [] optimal = np.argmax(bandit.true_rates) # 真实最优老虎机 for step in range(steps): action = agent.get_action() reward = bandit.play(action) agent.update(action, reward) # 记录数据用于可视化 rewards.append(reward) optimal_rates.append(action == optimal) return rewards, optimal_rates # 运行不同探索率的实验 epsilons = [0, 0.01, 0.1] results = {eps: run_experiment(eps) for eps in epsilons} # 可视化结果 plt.figure(figsize=(12, 8)) # 绘制累积奖励曲线 plt.subplot(2, 1, 1) for eps, (rewards, _) in results.items(): plt.plot(np.cumsum(rewards), label=f'ε={eps}') plt.ylabel('累积奖励') plt.xlabel('步数') plt.legend() # 绘制最优动作选择率 plt.subplot(2, 1, 2) for eps, (_, optimal_rates) in results.items(): plt.plot(np.cumsum(optimal_rates) / (np.arange(len(optimal_rates)) + 1), label=f'ε={eps}') plt.ylabel('最优动作选择率') plt.xlabel('步数') plt.legend() plt.tight_layout() plt.show()

5. 关键参数分析与调优

从实验结果可以看出,探索率ε对学习效果有显著影响:

ε值累积奖励收敛速度最优动作发现能力
0最低最快
0.01中等中等
0.1最高中等

实际应用建议

  • 初期可以设置较高的ε值(如0.1-0.3)以充分探索
  • 随着尝试次数增加,可以逐渐降低ε值(退火策略)
  • 对于确定性环境,最终可以将ε降至0
# 退火ε-greedy策略实现 class AnnealingAgent(Agent): def __init__(self, action_size=10): super().__init__(1.0, action_size) # 初始ε=1.0 self.steps = 0 def get_action(self): self.epsilon = 1.0 / (self.steps + 1) self.steps += 1 return super().get_action()

6. 高级改进与扩展思路

基础版本实现后,我们可以考虑以下改进方向:

  1. 置信区间上界(UCB)算法
    • 不仅考虑Q值,还考虑动作的不确定性
    • 平衡探索和利用的更优方式
class UCBAgent: def __init__(self, c=2, action_size=10): self.Q = np.zeros(action_size) self.counts = np.zeros(action_size) self.c = c # 探索系数 self.total_counts = 0 def get_action(self): if self.total_counts == 0: return np.random.randint(len(self.Q)) # UCB计算公式 ucb_values = self.Q + self.c * np.sqrt(np.log(self.total_counts) / (self.counts + 1e-5)) return np.argmax(ucb_values) def update(self, action, reward): self.counts[action] += 1 self.total_counts += 1 self.Q[action] += (reward - self.Q[action]) / self.counts[action]
  1. 非平稳环境处理
    • 真实场景中老虎机的中奖概率可能随时间变化
    • 可以使用加权平均替代算术平均
class NonStationaryAgent(Agent): def __init__(self, epsilon=0.1, alpha=0.1, action_size=10): super().__init__(epsilon, action_size) self.alpha = alpha # 固定学习率 def update(self, action, reward): self.Q[action] += self.alpha * (reward - self.Q[action])

7. 实战技巧与常见问题

在实现过程中,可能会遇到以下典型问题及解决方案:

  • 初始Q值设置
    • 全零初始化可能导致智能体过于保守
    • 解决方案:使用乐观初始值(Optimistic Initial Values)
class OptimisticAgent(Agent): def __init__(self, epsilon=0, initial_value=5, action_size=10): super().__init__(epsilon, action_size) self.Q[:] = initial_value # 设置乐观初始值
  • 随机性处理
    • 确保实验可重复性
    • 解决方案:固定随机种子
np.random.seed(42) # 在实验开始前设置
  • 性能优化
    • 对于大规模实验,使用向量化操作
    • 避免Python循环,尽量使用NumPy
# 向量化实现示例 def vectorized_update(Q, counts, actions, rewards): counts[actions] += 1 Q[actions] += (rewards - Q[actions]) / counts[actions]

在完成基础实现后,我通常会先测试极端参数情况(如ε=0和ε=1)来验证代码逻辑是否正确。一个常见错误是忘记在ε-greedy策略中处理探索和利用的边界条件,这会导致智能体无法学习到最优策略。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 10:25:55

雅特力AT32F403A GPIO模拟XY2-100协议,实现500KHZ高频率振镜控制

1. XY2-100协议与振镜控制基础 振镜系统在激光打标、精密加工等领域扮演着关键角色&#xff0c;而XY2-100协议则是驱动这类设备的核心通信标准。这个协议本质上是一种串行通信协议&#xff0c;专门为双轴振镜系统设计。它采用20位数据帧结构&#xff0c;包含同步头、X/Y轴坐标数…

作者头像 李华
网站建设 2026/4/24 10:25:34

从一道CTF题出发,手把手教你用Wireshark和Python破解二战Enigma密码机

二战密码传奇&#xff1a;用Wireshark和Python还原Enigma破译实战 当我们在网络安全竞赛中遇到历史密码学题目时&#xff0c;往往会被那些充满年代感的加密方式所吸引。Enigma密码机作为二战期间纳粹德国的核心加密工具&#xff0c;曾被认为是不可破解的。直到图灵和他的团队在…

作者头像 李华
网站建设 2026/4/24 10:25:26

Uniapp 集成抖音短剧播放器 video-player 实战避坑指南

1. 为什么要在Uniapp中集成抖音video-player组件 最近两年短剧市场爆发式增长&#xff0c;很多开发者都接到了开发短剧小程序的需求。抖音作为短剧内容的主要平台&#xff0c;其官方推出的video-player组件自然成为首选。但实际集成过程中&#xff0c;我发现很多团队都遇到了各…

作者头像 李华
网站建设 2026/4/24 10:25:25

Windows 11远程桌面多用户连接终极解决方案:RDP Wrapper完整指南

Windows 11远程桌面多用户连接终极解决方案&#xff1a;RDP Wrapper完整指南 【免费下载链接】rdpwrap RDP Wrapper Library 项目地址: https://gitcode.com/gh_mirrors/rd/rdpwrap RDP Wrapper Library是一款强大的开源工具&#xff0c;能够为Windows 11家庭版及其他简…

作者头像 李华