Skip to content

Latest commit

 

History

History
207 lines (104 loc) · 23.8 KB

dynamic-pricing-with-contextual-bandits-learning-by-doing-b88e49f55894.md

File metadata and controls

207 lines (104 loc) · 23.8 KB

使用上下文强盗进行动态定价:通过实践学习

原文:towardsdatascience.com/dynamic-pricing-with-contextual-bandits-learning-by-doing-b88e49f55894

将上下文添加到你的动态定价问题中可以增加机会,同时也带来挑战

Massimiliano CostacurtaTowards Data Science Massimiliano Costacurta

·发表于 Towards Data Science ·阅读时间 17 分钟·2023 年 10 月 5 日

--

照片由 Artem BeliaikinUnsplash 上提供

从多臂强盗到上下文强盗

在我的 上一篇文章 中,我对使用简单的多臂强盗应对动态定价问题的最流行策略进行了详细分析。如果你是从那篇文章过来的,首先,感谢你。那绝不是一篇容易阅读的文章,我非常感激你对这个话题的热情。其次,做好准备,因为这篇新文章会更加具有挑战性。然而,如果这是你首次接触这个话题,我强烈建议你先从上一篇文章开始阅读。在那篇文章中,我介绍了基础概念,这些概念在本讨论中我会假设读者已经熟悉。

不管怎样,简单回顾一下:之前的分析旨在模拟一个动态定价场景。主要目标是尽快评估各种价格点,找到能够产生最高累计奖励的价格。我们探索了四种不同的算法:贪婪算法、ε-贪婪算法、汤普森采样和 UCB1,详细描述了每种算法的优缺点。尽管那篇文章中采用的方法在理论上是可靠的,但它存在一些简化,这些简化在更复杂的现实世界情况下并不成立。其中最具问题的是假设基本过程是稳定的——即最优价格在外部环境无论如何都保持不变。这显然不符合实际。例如,节假日期间需求波动、竞争对手价格的突然变化或原材料成本的变化。

为了解决这个问题,上下文赌博机应运而生。上下文赌博机是多臂赌博机问题的扩展,其中决策代理不仅为每个行动(或“臂”)获得奖励,而且在选择臂之前还可以访问上下文或环境相关信息。上下文可以是任何可能影响结果的信息,例如客户的人口统计数据或外部市场条件。

它们的工作方式如下:在决定拉哪个臂(或者在我们的例子中,设置哪个价格)之前,代理会观察当前的上下文,并利用它做出更明智的决策。代理随后随着时间的推移学习哪些行动在特定上下文中效果最佳,并根据所获得的奖励以及这些奖励获得的上下文来调整其策略。这种持续学习和适应机制可以帮助企业动态调整其定价策略,以应对不断变化的外部因素,从而可能提高表现和增加利润。

上下文赌博机:架构、建模与挑战

上下文赌博机问题的架构可以被视为多臂赌博机问题的一个推广。这两种方法的最终目标都是在时间上最大化奖励,即找到探索新行动和利用已知行动之间的最佳平衡。此外,它们都从历史中学习:所做的决策以及所获得的相应奖励。

然而,它们做出决策和学习的方式存在根本的不同。最显著的区别在于上下文的概念。在多臂赌博机问题中,决策完全基于与每个臂相关的历史奖励记录,而上下文赌博机则将额外的外部信息或上下文纳入其决策框架。这些上下文通常提供了关键见解,可以显著影响所选择行动的结果。

上下文赌博机反馈循环的架构。注意到来自客户和/或环境的信息现在是赌博机的输入。图片由作者提供。

然而,上下文赌博机问题中的上下文存在,需要更复杂的建模方法。在这里,需要一个针对每个臂的预测模型(通常称为“预言机”),以帮助基于给定的上下文识别最佳动作。这涉及利用线性回归、逻辑回归、神经网络或其他预测算法等技术,这些技术能够有效地融入上下文以预测奖励。

鉴于这种额外的上下文维度,很明显上下文赌博机呈现出一种超越多臂赌博机的复杂性。它不仅仅是跟踪奖励,还需要更复杂的分析来学习不同上下文如何与不同动作的奖励相关联。从本质上讲,多臂赌博机提供了一个较简单、以历史为中心的视角,而上下文赌博机则提供了一个更丰富、更具适应性的视角,适应于变化的环境及其对潜在奖励的影响。

现在是坏消息。正如前面提到的,预言机通常是预测模型。它们可以是任何能够在特定上下文下生成预测和相关概率的机器学习模型。不幸的是,虽然大多数机器学习算法在生成预测和估计概率方面表现优异,但许多算法在提供预测的不确定性度量方面存在不足。不确定性对利用诸如汤普森采样或上置信界等方法至关重要。对于上下文赌博机来说,实施这些方法特别具有挑战性,因为创建一个不确定性度量(也许通过自助法或集成方法)将使本已复杂的架构更加复杂。虽然有框架融入了这些特性,但在这次讨论中我将把它们搁置,专注于两个主要的无不确定性算法:贪婪算法和ε-贪婪算法。

上下文建模

在对上下文赌博机有了更清晰的理解后,现在是时候建立环境来测试它们了。在上一篇文章中,我使用逻辑函数设计了一个简单的需求曲线。这个函数的目的是提供在任何给定价格点的假设客户的购买预期概率。

如前所述,参数b决定需求曲线的陡峭程度,指示曲线收敛到 0 的速度。这反过来会影响最优价格的确定。在多臂老虎机场景中,我们为ab分配了单一值。然而,在上下文设置中,虽然我们仍将保持a不变(等于 2),但我们打算使b取决于我们上下文的值。具体来说,在我们的模拟中,我们将定义一个由两个特征组成的上下文:地理区域和年龄。本质上,我们假设我们的需求曲线——由b值表示——会根据这两个参数变化。

为了简化我们的分析,我们将限制输入空间。对于地理区域,我们将考虑两个区域:‘EU’和‘US’。对于年龄,我们将其分成四个不同的桶,而不是使用连续范围。因此,我们将有总共八个独特的上下文进行分析。显然,这是一个简化模型,它作为基础可以通过引入额外的上下文特征来发展更复杂的场景。另一个相关的假设是,上下文仅决定需求曲线的非平稳性。换句话说,虽然不同的上下文导致不同的需求曲线,但这些需求曲线是时间独立的,这意味着其参数不随时间步骤变化。

在我们明确了上下文之后,下一步是为每个上下文分配一个特定的b值。这将使我们能够确定针对每个上下文的最优价格点(有关如何找到给定需求曲线的最优价格的更多细节,请参见之前的文章)。

上下文映射与需求参数‘b’相关的值以及相应的最优价格。图片由作者提供。

上表阐明了上下文和b值的组合,以及相应的最优价格。我故意选择了b值,以便轻松生成一组候选价格来测试我们的模型。这些价格是(15, 20, 25, 30, 35, 40, 45, 50, 55, 60),它们代表了我们的‘臂’,即我们可以选择的可能行动,以最大化累积奖励。

为了让您更清楚我们老虎机的目标,我们来关注定价为 30 的臂/价格集合。管理这个臂的神谕需要确定所有 8 个上下文的购买概率。尽管这些概率在实际中是未知的,但在我们的模拟中,可以通过将价格=30,a=2,并根据特定上下文调整b,使用前面提供的需求曲线函数进行计算。作为参考,这里是神谕需要学习的与此臂相关的概率集合:

每个上下文的购买概率,价格=30。图片由作者提供。

毋庸置疑,其他所有臂部将处理各自特定的概率集。

为了实践这一点,这里是动态生成运行时上下文的代码。此外,在这段代码中,我们还构建了一个字典,将上下文与相关的最佳价格进行映射。这些字典在稍后计算遗憾时会特别有用:

设置预言机:逻辑回归

就像在简单的多臂赌博机场景中一样,我们的奖励函数将返回 1 或 0,反映客户是否进行了购买。实质上,对于每个可能的价格点,我们将逐步编译数据集,格式为:(地理区域,年龄范围,奖励)。乍一看,这确实像是一个典型的二分类问题,这使我们考虑测试最常见的二分类模型之一:逻辑回归。

然而,当涉足强化学习领域时,学习方法与传统的监督学习范式不同。具体来说,在强化学习中,模型会不断更新,每次引入新记录时都会进行更新。这种转变要求采用‘在线’算法,这些算法可以随着新记录的引入逐步更新。这样的算法对于优化计算效率和节省内存资源至关重要。由于这一要求,sklearn提供的传统逻辑回归实现——不支持在线训练或“部分拟合”——变得不太理想。

进入SGDClassifier。随机梯度下降(SGD)分类器是一个通过 SGD 优化的线性分类器。实质上,SGD 不是处理整个数据集来计算目标函数的梯度,而是使用一个或几个训练样本来近似计算。这使得它在在线学习场景中高度高效。为了将SGDClassifier配置为模拟逻辑回归,我们需要将其损失函数设置为'log_loss'。这样,我们实际上采用了逻辑回归模型,但增加了 SGD 能够随着每个新数据点逐步更新模型的优势,完美契合我们的强化学习框架。

首先,我们将创建一个Model辅助类。这个类不仅会封装SGDClassifier实例,还会包含所有在模拟过程中需要使用的相关方法。此外,这个设置为快速集成其他模型到模拟中奠定了基础。还有,剧透警告,我们稍后会需要这样做。

这是类方法的简要描述:

  • add_sample:接收新的数据点和标签,并将它们附加到现有数据集中。

  • can_predict:确定模型是否能够进行预测。它确保数据集中既有正例也有负例,以避免由于缺乏多样化数据导致模型无法做出有意义预测的“冷启动”问题。

  • get_prob:给定一个数据点,此方法返回它属于标记为‘1’的类别的概率。这个概率表示我们对在模型参考的价格下发生购买的可能性的估计。

  • fit:一种特定于逻辑回归模型的部分拟合方法。它在最新数据点上增量训练模型,而无需重新训练整个数据集。

设置模拟

准备好Model类后,我们可以创建一个模拟决策过程的函数:

run_simulation代码模拟了选择最佳价格以最大化奖励的过程。它接受以下参数:

  1. prices:要提供的潜在价格列表。

  2. nstep:模拟的步骤或迭代次数。

  3. strategy:要使用的决策策略,可以是'random'、'greedy'或'epsgreedy'。

  4. model_type:要使用的预测模型类型,默认为'logistic'。

在这些参数的基础上,函数根据选择的策略为每次迭代选择一个价格(称为arm)。在每一步,使用generate_context()函数生成一个客户上下文。根据策略,arm要么随机选择(这是我们的评估基线),要么基于贪婪或ε-贪婪算法选择。然后使用get_reward()函数模拟客户对选择价格的反馈,计算并累计遗憾(即采用最优价格与选择价格之间的奖励差异)。然后使用新数据更新与所选arm对应的模型,并重新训练。该函数还处理“冷启动”问题,在早期迭代中,预测模型可能没有足够的数据来进行预测。在这种情况下,选择第一个无法预测的arm

贪婪和ε-贪婪算法在之前的文章中有详细描述。在本节中,我们将仅展示在新的上下文场景中实现这些算法的代码。它与多臂赌博机中的使用方式大致相同,主要区别在于这里我们使用模型概率来计算arms的期望回报(即概率与相关价格的乘积)。

模拟函数的输出本质上是随机的。为了全面评估模型和策略,我们将运行此模拟 1,000 次。每次模拟将持续 10,000 个时间步骤,收集相关的中间数据以产生汇总的和统计上更可靠的结果。我们关注的两个主要指标是:

  1. 平均累计遗憾:就像在多臂赌博机的情况一样,这是一个在每次模拟运行中汇总这一错失机会的指标。我们将累计每次运行计算出的遗憾曲线,然后对它们进行平均。我们可以计算这个指标,因为在这次模拟中我们知道每个上下文的最优价格。显然,这在任何真实场景中都不适用。

  2. 每个上下文的平均最优价格估计:这代表了在所有模型预测中,每个上下文值的最高概率价格。简单来说,每次模拟运行后,对于每个可能的上下文,我们“询问”模型提供它们的概率。然后,我们选择具有最高预期回报的模型——更准确地说,是与该模型相关的价格。每次运行生成的价格估计随后被汇总并平均。通过将这些估计价格与最优价格进行比较,我们可以评估模型“理解”基本需求曲线的整体能力。

以下是运行模拟 1,000 次、收集所需数据并计算汇总指标的代码。

在我们深入探讨模拟结果之前,让我简要评论一下每次模拟中的数据量。说明每次模拟将运行 10,000 步,表明我们在每次运行中收集了 10,000 个数据点。在机器学习领域,10,000 条数据通常被视为获取有意义见解的最小阈值。然而,我们的情况更具挑战性。这 10,000 条记录实际上是“分布”在对应于每个价格候选(我们的行动)的 10 个模型中。因此,每个模型用于训练的记录可能不超过一千条,这通常是不够的。这带来了一个关于上下文赌博的关键见解:如果你有多个行动,可能需要大量数据才能获取有用的信息。而这个大量,就是很多。

结果

话不多说,来看一下累计遗憾的图表:

作者提供的图片

看着这个图表,你的初步反应可能是:“这个家伙搞错了图例标签!贪婪策略不可能优于ε-贪婪策略!”至少,这就是我第一次看到这个输出时的想法。惊讶的是,这个图表是准确的,尽管它非常违反直觉。让我们深入探讨,了解发生了什么,通过考虑平均价格估计来理解。

作者提供的图片

价格估算图基本上是“揭示罪魁祸首”。如果你观察前四个上下文并将它们与第二个上下文进行比较,你会很容易发现逻辑回归预测的价格在下降(如两个箭头所示)。问题的根源很简单:逻辑回归本质上是一个线性模型,即使我们对其进行非线性转换。遗憾的是,我们的数据本质上是非线性的,如红点所示。因此,逻辑回归仅仅是在努力适应数据,但显然不是这个场景下合适的模型。

我们所见的是:以某些初始的积极结果‘贪婪’地进行调整,比依赖模型的概率更少有害。这是因为模型从数据中学习得越多,它们在预测中的一致性误差就越大。归根结底,‘ε’探索仅仅确保了一些数据被用来完善模型,但这些模型学习得越多,就越会把我们引入歧途。

对于那些对这个解释不信服的人,考虑一个简单的一维场景:只有四个点(0,1,2,3),其分别获得 1 的概率为:0.01,0.08,0.95,0.97。在这种情况下,大家都很满意,因为逻辑回归效果很好,甚至可以得到一个漂亮的“按部就班”的图:

作者提供的图片

逻辑回归输出的概率表示曲线在特定点的值,在这里它们非常接近实际值(绿色点)。然而,让我们看看如果我们将概率修改为(0.1,0.8,0.5,0.3),更接近我们的定价场景,会发生什么:

作者提供的图片

在这种情况下,事情变得棘手,因为四个概率预测中的三个将完全错误(那些与输入 0,1 和 3 相关的)。现在,在每次迭代中,我们根据期望回报选择最佳的臂,即模型概率与相应臂价格的乘积。如果概率完全错误,那么我们将面临一个大问题。

那么,我们现在该怎么办?直接的诱惑可能是选择一个复杂的非线性模型,比如神经网络,甚至更好的是,选择一个深入学习领域的复杂架构。这当然是一个选择,确实有公司在探索这种定价方向。然而,我们首先想要考虑是否有更简单的解决方案。如果有一个算法可以根据在任何给定区域获得‘1’的概率来划分输入空间就好了……

调整预言机:决策树

最后一段应该向你耳边呐喊两个简单的词:决策树。为什么?因为这正是决策树的本质。决策树通过根据特定特征阈值递归地划分输入空间,从而形成了一个节点和分支的层次结构。每一次分裂或决策,都是以最佳方式将数据根据目标变量进行区分——在我们的上下文中,‘一’的概率在某个区域内相对均匀。

一旦树构建完成,每个终端节点(或叶子)代表输入空间中的一个特定区域,其中数据表现出类似的特征。对于给定输入的概率预测,然后是从落入相应叶子中的数据样本的‘一’的比例中得出的。例如,如果一个叶子节点有 80 个样本,其中 40 个被标记为‘一’,那么对于到达该叶子的输入,预测的概率将是 40/80=0.5。

所以,它们似乎正是我们问题所需的。遗憾的是,决策树没有在线实现,这意味着在每一步我们需要从头开始重新训练模型。好的一面是,决策树训练非常迅速,但如果你计划在实际应用中实时重新训练模型,可能需要记住这一点。

好的,首先我们需要更新我们的Model类以将决策树作为一个选项。很简单——只需一系列的 if-then 语句以确保我们根据初始配置调用适当的函数:

接下来,我们可以通过简单地将‘dectree’添加到外部循环迭代的列表中来重新执行模拟。就这样,经过一段时间,我们得到了最终结果:

图片来源:作者

现在我们可以深入探讨了。首先,决策树表现最佳,确认了我们最初直觉的正确性。此外,ε-贪婪算法显著优于简单的贪婪算法,正如预期的那样。这表明,从上下文中学习确实有助于模型做出更好的预测,并且最终促进了更好的决策。比较预测价格与最优价格的图表看起来也更有希望:

图片来源:作者

ε-贪婪算法本质上识别了所有的最优价格,在每种上下文中都优于贪婪方法。

经验教训与下一步

  • 数据越多越好(?): 你可能认为只要有数据就应该使用它。一般来说,这是对的。在 Contextual Bandits 领域,将数据(背景)添加到你的算法中可以导致更明智的决策和量身定制的行动。然而,有一个陷阱。‘Bandits’ 算法的主要目的是加速做出最佳决策的过程。添加背景会增加复杂性,可能会减缓达成预期结果的速度。过渡到 Contextual Bandits 也可能妨碍有效策略的利用,如 Thompson 采样或 UCB。正如数据科学中的许多选择一样,在目标和限制之间存在权衡。

  • 了解你的数据和算法:必须小心对数据做出的假设。常见的观点是,逻辑回归通常适用于机器学习任务,因为“线性假设经常成立”。虽然这可能经常是这样,但并非绝对。错误的假设可能导致重大陷阱。这强调了利用指标的重要性,以确保我们能够快速评估初步假设的准确性,并在需要时调整我们的策略。

  • 保持简单(尽可能长时间):即便在数据科学领域,也很容易被最新的趋势所吸引。在撰写本文时,人工智能领域正热衷于深度学习方法。虽然强大,但必须记住,有许多更简单且稳健的策略可能完全适合你的问题,不多也不少。

总之,Contextual Bandits 是一个令人兴奋的研究领域,确实值得更多关注。本文探讨了一个相对简单的背景,但背景可以在数据维度和类型(如文本或图像)上变得非常复杂。即使这似乎与关于简单性的前一点相矛盾,分析的逻辑进程是探索更复杂的算法,如深度学习。虽然我不打算在这一系列中添加更多章节,但我很想听听你在这个领域的经验。如果你已经深入研究过这个领域,请留下评论或直接联系我!

代码库

github.com/massi82/contextual_bandits

参考文献

contextual-bandits.readthedocs.io/en/latest/

www.youtube.com/watch?v=sVpwtj4nSfI

## Contextual Bandits 和 强化学习

如果你为网站或应用开发个性化用户体验,Contextual Bandits 可以帮助你。使用……

[towardsdatascience.com [## 如何构建更好的上下文策略带机器学习模型 | Google Cloud Blog

上下文策略带:它是什么,企业如何应用它,以及如何使用 AutoML 实现它

cloud.google.com

courses.cs.washington.edu/courses/cse599i/18wi/resources/lecture10/lecture10.pdf

你喜欢这篇文章吗?如果你对人工智能、自然语言处理、机器学习和数据分析在解决现实世界问题中的应用感兴趣,你可能也会喜欢我的其他作品。我的目标是撰写出展示这些变革性技术在实际场景中应用的可操作性文章。如果这也是你的兴趣所在,请在 Medium 上关注我,以获取最新文章!