ε-Greedy 老虎机算法

一、代码概述

本代码实现了一个基于 ε-Greedy 算法的多臂老虎机实验。通过模拟多个具有不同真实收益均值的老虎机,在一定次数的尝试中,使用 ε-Greedy 策略来决定选择哪个老虎机进行拉动,以平衡探索(尝试不同的老虎机以发现更好的选择)和利用(选择当前认为最好的老虎机以获取最大收益)。最终,通过可视化展示累积平均收益随尝试次数的变化,并输出每个老虎机的估计均值。

二、依赖库

  1. numpy:用于数值计算,包括生成随机数、数组操作和数学运算等。
  2. matplotlib.pyplot:用于数据可视化,绘制累积平均收益曲线和图表。

三、代码详解

1. 定义老虎机类 Bandit

python

class Bandit:
    def __init__(self, true_mean):
        """
        初始化老虎机。
        :param true_mean: 老虎机的真实均值(收益的期望值)
        """
        self.true_mean = true_mean  # 老虎机的真实均值
        self.estimated_mean = 0  # 对老虎机均值的估计值,初始为0
        self.N = 0  # 老虎机被尝试的次数,初始为0

    def pull(self):
        """
        模拟拉老虎机的过程,返回一个随机收益。
        :return: 返回一个服从正态分布的随机值,均值为true_mean,标准差为1
        """
        return np.random.randn() + self.true_mean

    def update(self, x):
        """
        更新对老虎机均值的估计值。
        :param x: 本次拉老虎机得到的收益
        """
        self.N += 1  # 尝试次数加1
        # 更新估计均值:使用增量式更新公式
        self.estimated_mean = (1 - 1.0 / self.N) * self.estimated_mean + 1.0 / self.N * x

  • __init__方法:初始化老虎机对象,接受一个参数true_mean表示老虎机的真实收益均值。同时初始化estimated_mean(估计均值)为 0,N(尝试次数)为 0。
  • pull方法:模拟拉老虎机的操作,返回一个随机收益。收益是一个服从正态分布的随机值,均值为老虎机的真实均值true_mean,标准差为 1(通过np.random.randn()生成标准正态分布随机数再加上true_mean实现)。
  • update方法:根据本次拉老虎机得到的收益x,更新对老虎机均值的估计值。使用增量式更新公式,随着尝试次数N的增加,新的收益对估计均值的影响逐渐减小。

2. 运行实验的函数 run_experiment

python

def run_experiment(true_means, N, eps):
    """
    运行ε-Greedy算法的实验。
    :param true_means: 每个老虎机的真实均值列表
    :param N: 总尝试次数
    :param eps: ε值,控制探索与利用的比例
    :return: 累积平均收益列表和最终的老虎机列表
    """
    # 初始化老虎机列表,每个老虎机的真实均值由true_means提供
    bandits = [Bandit(m) for m in true_means]
    data = np.empty(N)  # 用于存储每次尝试的收益

    for i in range(N):
        # ε-Greedy策略:以概率ε随机选择一个老虎机(探索),否则选择当前估计均值最大的老虎机(利用)
        if np.random.random() < eps:
            j = np.random.choice(len(bandits))  # 随机选择一个老虎机
        else:
            j = np.argmax([b.estimated_mean for b in bandits])  # 选择估计均值最大的老虎机

        # 拉选中的老虎机,获得收益
        x = bandits[j].pull()
        # 更新该老虎机的估计均值
        bandits[j].update(x)
        # 记录本次收益
        data[i] = x

    # 计算累积平均收益:累积收益除以尝试次数
    cumulative_average = np.cumsum(data) / (np.arange(N) + 1)

    return cumulative_average, bandits

  • 参数说明
    • true_means:一个列表,包含每个老虎机的真实收益均值。
    • N:总尝试次数,即实验中拉动老虎机的总次数。
    • eps:ε 值,一个介于 0 和 1 之间的概率值,用于控制探索(随机选择老虎机)和利用(选择当前估计均值最大的老虎机)的比例。
  • 函数逻辑
    • 初始化一个老虎机列表bandits,每个老虎机的真实均值由true_means提供。
    • 创建一个长度为N的空数组data,用于存储每次尝试的收益。
    • N次尝试的循环中:
      • 根据 ε-Greedy 策略决定选择哪个老虎机。如果随机生成的一个 0 到 1 之间的数小于eps,则随机选择一个老虎机;否则选择当前估计均值最大的老虎机。
      • 拉选中的老虎机,获得收益x,更新该老虎机的估计均值,并将本次收益记录到data数组中。
    • 计算累积平均收益cumulative_average,通过对data数组的累积求和并除以尝试次数(np.arange(N) + 1)得到。
    • 最后返回累积平均收益列表和最终的老虎机列表。

3. 参数设置与实验运行

python

# 参数设置
true_means = [1.0, 2.0, 3.0]  # 每个老虎机的真实均值
N = 1000  # 总尝试次数
eps = 0.1  # ε值,控制探索与利用的比例

# 运行实验
cumulative_average, bandits = run_experiment(true_means, N, eps)

定义了实验的参数:true_means为每个老虎机的真实均值列表,N为总尝试次数,eps为 ε 值。然后调用run_experiment函数运行实验,得到累积平均收益列表cumulative_average和最终的老虎机列表bandits

4. 可视化结果

python

# 可视化结果
plt.plot(cumulative_average, label='Cumulative Average Reward')  # 绘制累积平均收益曲线
# 绘制最优收益水平线(即真实均值最大的老虎机的收益)
plt.plot(np.ones(N) * true_means[np.argmax(true_means)], label='Optimal Reward')
plt.legend()  # 显示图例
plt.xlabel('Number of Trials')  # x轴标签
plt.ylabel('Average Reward')  # y轴标签
plt.title('ε-Greedy Bandit Algorithm')  # 图表标题
plt.show()  # 显示图表

使用matplotlib.pyplot绘制累积平均收益曲线,并绘制一条表示最优收益(真实均值最大的老虎机的收益)的水平线。添加图例、轴标签和图表标题,最后显示图表。

5. 打印每个老虎机的估计均值

python

# 打印每个老虎机的估计均值
for i, bandit in enumerate(bandits):
    print(f"Bandit {i+1}: Estimated Mean = {bandit.estimated_mean}")

遍历最终的老虎机列表bandits,打印每个老虎机的估计均值。

四、注意事项

  1. 代码中的 ε-Greedy 策略是一种简单的平衡探索与利用的方法,但可能不是最优的。在实际应用中,可以尝试不同的 ε 值或其他更复杂的算法来优化结果。
  2. 实验结果可能会受到随机因素的影响,每次运行代码得到的具体数值和图表可能会有所不同。
  3. 代码中假设老虎机的收益服从正态分布且标准差为 1,这是一个简化的模型。在实际场景中,收益分布可能更加复杂,需要根据具体情况进行调整。

完整代码

import numpy as np
import matplotlib.pyplot as plt

# 定义老虎机类
class Bandit:
    def __init__(self, true_mean):
        """
        初始化老虎机。
        :param true_mean: 老虎机的真实均值(收益的期望值)
        """
        self.true_mean = true_mean  # 老虎机的真实均值
        self.estimated_mean = 0  # 对老虎机均值的估计值,初始为0
        self.N = 0  # 老虎机被尝试的次数,初始为0

    def pull(self):
        """
        模拟拉老虎机的过程,返回一个随机收益。
        :return: 返回一个服从正态分布的随机值,均值为true_mean,标准差为1
        """
        return np.random.randn() + self.true_mean

    def update(self, x):
        """
        更新对老虎机均值的估计值。
        :param x: 本次拉老虎机得到的收益
        """
        self.N += 1  # 尝试次数加1
        # 更新估计均值:使用增量式更新公式
        self.estimated_mean = (1 - 1.0 / self.N) * self.estimated_mean + 1.0 / self.N * x


def run_experiment(true_means, N, eps):
    """
    运行ε-Greedy算法的实验。
    :param true_means: 每个老虎机的真实均值列表
    :param N: 总尝试次数
    :param eps: ε值,控制探索与利用的比例
    :return: 累积平均收益列表和最终的老虎机列表
    """
    # 初始化老虎机列表,每个老虎机的真实均值由true_means提供
    bandits = [Bandit(m) for m in true_means]
    data = np.empty(N)  # 用于存储每次尝试的收益

    for i in range(N):
        # ε-Greedy策略:以概率ε随机选择一个老虎机(探索),否则选择当前估计均值最大的老虎机(利用)
        if np.random.random() < eps:
            j = np.random.choice(len(bandits))  # 随机选择一个老虎机
        else:
            j = np.argmax([b.estimated_mean for b in bandits])  # 选择估计均值最大的老虎机

        # 拉选中的老虎机,获得收益
        x = bandits[j].pull()
        # 更新该老虎机的估计均值
        bandits[j].update(x)
        # 记录本次收益
        data[i] = x

    # 计算累积平均收益:累积收益除以尝试次数
    cumulative_average = np.cumsum(data) / (np.arange(N) + 1)

    return cumulative_average, bandits


# 参数设置
true_means = [1.0, 2.0, 3.0]  # 每个老虎机的真实均值
N = 1000  # 总尝试次数
eps = 0.1  # ε值,控制探索与利用的比例

# 运行实验
cumulative_average, bandits = run_experiment(true_means, N, eps)

# 可视化结果
plt.plot(cumulative_average, label='Cumulative Average Reward')  # 绘制累积平均收益曲线
# 绘制最优收益水平线(即真实均值最大的老虎机的收益)
plt.plot(np.ones(N) * true_means[np.argmax(true_means)], label='Optimal Reward')
plt.legend()  # 显示图例
plt.xlabel('Number of Trials')  # x轴标签
plt.ylabel('Average Reward')  # y轴标签
plt.title('ε-Greedy Bandit Algorithm')  # 图表标题
plt.show()  # 显示图表

# 打印每个老虎机的估计均值
for i, bandit in enumerate(bandits):
    print(f"Bandit {i+1}: Estimated Mean = {bandit.estimated_mean}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值