用三行代码优化你的交易策略
使用 fastquant 自动轻松优化您的交易策略参数!
回溯测试的目标是了解空间中的哪些区域会产生更好的结果
如果你想通过投资持续赚钱,回溯测试是评估交易策略有效性的最好方法之一——当然,前提是你要正确实施。这个想法是,你可以为你选择的策略试验不同的参数,看看哪个组合能给你的投资带来最好的回报。
然而,这很容易变得乏味,因为您必须手动运行数百甚至数千个参数组合。
为了解决这个问题,我们可以使用 fastquant 来实现一种称为“网格搜索”的技术,它基本上允许您对您想要为您的策略运行的每个参数组合运行回溯测试。
在本文的其余部分,我将演示如何在回溯测试您的交易策略时应用自动网格搜索。
注意:如果你还不熟悉如何用 fastquant 做基本的回溯测试,你可能想看看我以前的 文章 中关于如何用 3 行代码做这件事。
顺便说一句,如果你对执行这种类型的分析感兴趣,甚至不需要编码,请注册我正在构建的这个新工具以使高级投资分析更容易使用!
好的,让我们从通过 pip 安装 fastquant 开始。
# Run this on your terminal
pip install fastquant
# Alternatively, you can run this from jupyter this way
!pip install fastquant
例如,让我们使用 Jollibee Food corp .(JFC)2018 年 1 月 1 日至 2019 年 12 月 31 日的股票作为我们的样本数据。
注: *get_stock_data*
支持从 雅虎财经 和 PSE 访问的所有公司。
from fastquant import get_stock_data
df = get_stock_data("JFC", "2018-01-01", "2019-12-31")
df.head()# dt close
# 2018-01-03 255.4
# 2018-01-04 255.0
# 2018-01-05 255.0
# 2018-01-08 256.0
# 2018-01-09 255.8
假设你想在 JFC 股票上用 15 天的快速周期和 40 天的慢速周期来回溯测试一个简单的移动平均交叉(SMAC)策略。
from fastquant import backtest
backtest("smac", df, fast_period=15, slow_period=40)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 68742.36
你会注意到,你的最终投资组合价值下降了很多(~31%),通过查看下面的图表,你会发现这是因为当股票处于整体下降趋势时,该策略仍在推荐交易(绿色和红色箭头)。
即使股票整体下跌,你也会看到交易发生(绿色和红色箭头)
所以现在,我们想看看是否有一个“慢速期”和“快速期”的组合会导致 SMAC 策略知道不要在整体下降趋势中交易。
一种方法是尝试大量可能的快速周期和慢速周期组合。在这个例子中,我们将慢速周期设置为取 20 到 241 范围内的值(每隔 5 秒跳过一次),而快速周期可以取 1 到 20 范围内的值。
这意味着快速周期可以取 20 个可能值,而慢速周期可以取 45 个可能值。总的来说,这意味着 900 (20 x 45)种可能的组合!想象一下这样一个一个做对。
幸运的是,我们可以通过使用迭代器(例如list
、range
)而不是单个数字作为输入,使用 fastquant 的内置网格搜索功能来轻松实现这一点。
results = backtest("smac", df, fast_period=range(1, 21), slow_period=range(20, 241, 5))
results[["fast_period", "slow_period", "final_value"]].head()# fast_period slow_period final_value
#0 3 105 107042.02
#1 8 205 103774.66
#2 11 170 103774.66
#3 8 200 103774.66
#4 9 95 103388.12
注意“backtest”返回一个 pandas data frame(“results”),其中包含每行上每次迭代的结果。数据帧的每一列对应于所使用的一个参数(如fast_period
)或策略的一个性能指标(如final_value
)。
方便的是,这些行根据每次迭代的投资组合回报按降序排列,因此“最佳”参数组合是在数据框顶部的那些。
在这种情况下,似乎最上面的参数组合是:fast_period=3,slow_period=105,投资组合收益为 7,042.02。这表明,当我们在 JFC 股票上使用 SMAC 策略时,我们可能要使用这个参数组合。
注意:很有可能该参数组合仍然过度适合所选的周期。参见之前 文章 中回测的注意事项和保障措施。
现在,让我们运行我们的最优策略!
from fastquant import backtest
backtest("smac", df, fast_period=3, slow_period=105)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 107042.02
如下图所示,上面的参数组合会建议我们在整体下跌趋势之前卖出我们的股票——看到下跌之前的红色向下箭头。这解释了它如何能够避免我们在本文开始时看到的在我们最初实施 SMAC 战略时的损失。
有了结果数据框架,您甚至可以用如下热图来直观显示每个参数组合的有效性!
查看本技术教程以了解如何绘制该热图
恭喜你!现在,您应该熟悉如何使用 fastquant 内置的网格搜索功能自动优化您的交易策略。下次您发现自己手动插入参数组合到backtest
时,请考虑使用这种自动化方法!
同样重要的是要注意,这是一个改编自 backtrader 包的功能,fastquant 就是建立在这个包之上的。不同之处在于 fastquant 允许您用更少的代码行(少至 3 行)来完成这项工作,这样您就可以花更多的时间来测试您的假设,而不是设置代码。
要查看以上示例的更详细版本和完整代码,包括没有“内置网格搜索”时的代码演示,请查看 Jerome de Leon 的技术教程。
如果你对这份材料有任何问题,请随时在下面发表评论,或者在 Twitter 或 Linkedin 上给我发消息。
最后,如果你想对这个软件包有所贡献,或者想了解更多关于其他人如何使用 fastquant 的信息,请加入我们的社区 Slack workspace ,在这里我们每两周与其他 quant 成员会面一次!
想完全不用编码就做到这一点?
如果你想让这种分析变得更加简单,而根本不需要编码(或者想避免做所有必需的设置的痛苦),你可以订阅这个我正在构建的新的无代码工具来使数据驱动的投资大众化。
希望让更多的人能够接触到这些强大的分析!
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
仅用 3 行 Python 代码回溯测试你的交易策略
介绍 fastquant ,一个面向数据驱动型投资者的简单回溯测试框架
自从我在大学开始投资以来,我接触到了不同的股票分析方法——技术分析和基本面分析。我甚至读过关于这些技术的书籍和无数文章。
简而言之,技术分析认为,你可以利用基于股票历史价格和成交量变动的技术指标来确定买卖股票的正确时机。另一方面,基本面分析认为,你可以根据公司财务报表中的基本面信息来衡量股票的实际内在价值。
这两种分析对我都有意义,我渴望用它们来指导我的交易;然而,我总是对一件主要的事情感到沮丧:
有许多可能的策略,但没有系统的方法来选择一个。在实践中,大多数交易仍然以“直觉”决定告终,而不是由数据驱动。
那么我们如何评估这些策略呢?我们可以通过比较每种方法的预期投资回报(ROI)来做到这一点。最好的方法是使用一种叫做回溯测试的方法,这种方法是通过模拟你过去使用策略时的表现来评估策略。
现在,已经有相当多的回溯测试框架,但是大多数都需要高级的编码知识。一个简单的 hello world 实现通常需要大约 30 行代码。
为了填补这一空白,我决定创建 fastquant ,目标是通过尽可能简化回溯测试,使其成为主流。用fast quant,我们可以用少至 3 行的代码回测交易策略!
fastquant 本质上是流行的 backtrader 框架的包装器,它允许我们大大简化回溯测试的过程,从 backtrader 上至少需要 30 行代码,到 fastquant 上只有 3 行代码。
在本文的其余部分,我将带您了解如何通过 Jollibee Food Corp .的历史数据对简单的移动平均交叉(SMAC)策略进行回溯测试。
此外,如果你有兴趣在无需编码的情况下进行这种类型的分析,一定要尝试一下鹰眼,这是我最近开发的一个新工具,它让高级投资分析变得更容易使用——即使对于非编码人员来说也是如此!
我们开始吧!
回溯测试我们的第一个策略
安装 fastquant
就像使用 pip install 一样简单!
# Run this on your terminal
pip install fastquant
# Alternatively, you can run this from jupyter this way
!pip install fastquant
获取股票数据
从 fastquant 导入 get_stock_data 函数,用它拉取 Jollibee Food corp .(JFC)2018 年 1 月 1 日到 2019 年 1 月 1 日的股票数据。注意,我们有对应于日期(dt)和收盘价(close)的列。
from fastquant import get_stock_data
jfc = get_stock_data("JFC", "2018-01-01", "2019-01-01")
print(jfc.head())
# dt close
# 2019-01-01 293.0
# 2019-01-02 292.0
# 2019-01-03 309.0
# 2019-01-06 323.0
# 2019-01-07 321.0
回溯测试你的交易策略
使用 fastquant 的回溯测试功能,通过 Jollibee Food Corp. (JFC)的历史股票数据对简单的移动平均交叉(SMAC)策略进行回溯测试。
在 SMAC 策略中,快速周期(fast_period)是指用于快速移动平均线的周期,而慢速周期(slow_period)是指用于慢速移动平均线的周期。当快速移动平均线从下方穿过慢速移动平均线到上方时,这被认为是“买入”信号,而如果它从上方穿过到下方,这被认为是“卖出”信号。关于如何工作的更多信息,请查看我以前的文章中的解释。
首先,让我们将 fast_period 和 slow_period 分别初始化为 15 和 40。
您应该会在日志底部看到最终的投资组合价值。这个价值可以被解释为你的投资组合在回溯测试期结束时(在这种情况下是 2019 年 1 月 1 日)的价值。如果你得到了“最终投资组合价值”和“初始投资组合价值”之间的差额,这将是你基于回溯测试的同期预期收益(在本例中为 PHP 411.83)。
from fastquant import backtest
backtest('smac', jfc, fast_period=15, slow_period=40)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 100411.83
将所有这些放在一起——用 3 行 Python 代码进行回溯测试
下面的代码展示了我们如何只用 3 行 python 代码就能执行上述所有步骤:
**from** **fastquant** **import** backtest, get_stock_data
jfc = get_stock_data("JFC", "2018-01-01", "2019-01-01")
backtest('smac', jfc, fast_period=15, slow_period=40)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 100411.83
简单移动平均线交叉(15 日均线对 40 日均线)
改进我们的 SMAC 战略
增加快周期和慢周期
这显示了微小的变化是如何迅速将一个成功的策略变成一个失败的策略的。在将 fast_period 和 slow_period 分别增加到 30 和 50 之后,我们的最终投资组合价值从 100,412 菲律宾比索下降到 83,947 菲律宾比索(下降了 16,465 菲律宾比索)。
backtest('smac', jfc, fast_period=30, slow_period=50)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 83946.83
缩短慢周期,同时保持快周期不变
在这种情况下,我们的策略的性能实际上提高了!我们的最终投资组合价值从 100,412 菲律宾比索上升到 102,273 菲律宾比索(增加了 1,861 菲律宾比索),在此之前,将慢速期减少到 35,快速期保持在 15。
backtest('smac', jfc, fast_period=15, slow_period=35)# Starting Portfolio Value: 100000.00
# Final Portfolio Value: 102272.90
简单移动平均线交叉(15 日均线对 35 日均线)
下表比较了我们 3 种 SMAC 战略的绩效:
基于我们的回溯测试,策略 3(用黄色突出显示)是最准确的 SMAC 策略!
克服回溯测试的局限性
现在,这是不是意味着我们应该继续用最好的 SMAC 策略交易 JFC?也许还不是时候。
回溯测试有相当多的限制,克服这些限制通常需要额外的步骤来增加我们对回溯测试结果和建议可靠性的信心。
下面是回溯测试的两个局限性,以及克服这些局限性的安全措施:
过拟合
这是指这样一种情况,即您得出的“最佳参数”与前一个时间段的模式过于吻合。这意味着当你决定使用你的策略时,你的策略的预期盈利能力不会转化为实际盈利能力。
对此的一个保障是在样本外测试你的策略,这类似于在机器学习中使用“测试集”。这个想法是,你拿出一些数据,当你想评估你的交易策略的盈利能力时,你只使用一次。这样,你就很难过度调整你的参数,因为你没有根据数据集来优化你的策略。
前瞻偏差
这是由于在回溯测试中利用了在测试期间不可用的信息而产生的偏差。例如,您可以在 JFC 上测试一个策略的有效性,该策略假设您在它实际公开之前一个月就已经知道它的财务表现(例如净收入)。这会让你对自己的策略产生不可靠的信心,这可能会让你以后损失很多钱。
在这种情况下,避免这种偏见的最好方法之一就是彻底验证你在回溯测试策略时所做的假设。严格评估你的策略和正确执行策略所需的信息是值得的。
这些只是回溯测试带来的众多限制中的两个。我确实计划在将来写一篇文章来更详细地讨论这些,所以请继续关注!
在解决了上述限制之后,我们应该对我们选择的策略更有信心;然而,请记住,虽然我们可以对我们的策略更有信心,但它在未知的真实世界中的表现永远不会是 100%确定的。
我建议,一旦你在现实世界中采用了一个策略,开始时投入相对较少的资金,只有当这个策略显示出更加持续的成功时,才增加投入;否则,如果它在现实世界中被证明效果不佳,就要做好消灭它的准备。
记下 fastquant 的默认参数
“获取股票数据”功能
为了使“get_stock_data”函数尽可能简单易用,我们将它设计为只返回股票的收盘价(用于大多数交易策略),它遵循格式“c”(c =收盘价)。但是,如果您想要更多的定价数据点(例如,OHLCV 表示“开盘价”、“最高价”、“最低价”、“收盘价”、“成交量”),只需将“get_stock_data”中的“格式”参数设置为您想要的数据格式。
下面是 Tesla 股票的格式(OHLCV)示例:
tsla = get_stock_data("TSLA", "2018-01-01", "2019-01-01", format="ohlcv")
注:对于在 雅虎金融 e 上市的国际股票,这种格式特征应该是稳定的。对于来自【PSE的符号,我们建议坚持默认的“c”格式。
“回溯测试”功能
对于“回溯测试”函数,我们还假设您买入时使用的现金比例(buy_prop)为 1 (100%),您卖出时持有的股票比例(sell_prop)为 1 (100%),每笔交易的佣金(commission)为 0.75%。您可以通过设置括号中参数的值来编辑这些默认值。
下面的例子中,我回测特斯拉,假设 buy_prop = 50%,sell_prop = 50%,commission_per_transaction = 1%。
backtest("smac", tsla, buy_prop=0.50, sell_prop=0.50, commission=0.01)
为 fastquant 贡献更多策略
记住 fastquant 的策略和它现有的策略库中的策略一样多。到目前为止,有 8 种策略可供选择,包括简单的移动平均交叉(SMAC),相对强弱指数(RSI),甚至还有基于情绪分析的策略!
正如我在这篇文章的引言中提到的,有很多不同的策略可以用于交易。有了这个,fastquant 开发团队和我真的可以利用一些帮助来将更多这些策略添加到 *fastquant 中。*如果你有兴趣投稿,请务必查看 fastquant 包中的 策略模块 。
如果你不熟悉财务概念或正在使用的低级回溯测试框架,不要担心!我们有一个强大的贡献者社区,一旦你发送了你的第一份 PR,他们就可以帮助你。只要遵循这些关于投稿的文档,你应该会很顺利!
如果你想直接与我们互动,你也可以通过鹰眼不和联系我们。欢迎在#反馈建议和#错误报告频道中询问有关 fastquant 的问题。
在 fastquant 系列的下一篇文章中,我将讨论如何应用网格搜索来自动优化您的交易策略,超过数百个参数组合!
感谢您阅读这篇文章,如果您对*fast quant*或任何与将数据科学应用于金融相关的问题有任何进一步的疑问,请随时在下面评论或通过电子邮件( lorenzo.ampil@gmail.com)、 twitter 或 linkedin 与我联系!
想完全不用编码就做到这一点?
如果你想让这种分析变得更简单,而根本不需要编码(或者想避免做所有必要的设置的痛苦),你可以尝试一下hawk sight——这是我最近为民主化数据驱动投资而开发的新的无代码工具。
我们刚刚推出了开放测试版,所以任何人都可以注册,并免费使用该工具。希望让更多的人能够接触到这些强大的分析!
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
使用 Quantopian 对苹果股票的布林线进行回溯测试
我们将创建一个使用双布林线策略交易 APPL 股票的机器人,并用 5 年的数据进行回溯测试,将其与买入并持有进行比较。
尼古拉·切尔尼琴科在 Unsplash 上拍摄的照片
学习技术分析的最大挑战之一(如果不是最大的话)是把你的钱押在一个策略上,而你并不知道这个策略是否有效。互联网上有很多好的和坏的信息,但通过经济损失找出什么有效什么无效是一个难以下咽的药丸。幸运的是,我们不再需要拿我们辛苦赚来的钱去测试我们在网上学到的东西了。我们可以在开始操作前用量子力学进行回溯测试。
我想提出一个简单的练习:用一个最著名的指标来交易 2015 年到 2020 年的苹果股票。是双布林线策略。这是我们要做的:
1-计算 2 组布林线。
一组距离 20 天简单移动平均线(SMA 20)1 个标准差,另一组距离 SMA 20 2 个标准差。
https://www . pro real code . com/pro real time-indicators/blai 5-b b-double/
2-定义操作区域
两个上部带之间的区域将是‘购买区’(上图中的红色区域)。两个较低带之间的区域将是‘销售区’(绿色区域)。以及中央区域,即‘中性区域’。
3-实施战略
- 如果当前价格在买入区*,我们在 APPL 上做多。*
- 如果当前价格处于“中性区”,我们就按兵不动。**
- 如果当前价格在“卖出区”内,我们做空 APPL。
除此之外,我们还将测试该算法的不同参数。但是首先我们需要一个基准。让我们看看购买 APPL 并持有 5 年的表现。
在 APPL (sid=24)上,每天重新平衡投资组合,使其为 100%多头
APPL 买入并持有业绩
不算太坏,5 年内 194.63%的回报率或每年大约 15%。然而,贝塔系数和下降幅度非常高。同样,希望增加α和夏普比率。让我们编写一个机器人来执行双布林线策略,并在相同的时间内对其进行回测:
**# Original Double BB strategyimport numpy as npdef initialize(context):
context.stock = sid(24)
schedule_function(buy_and_hold, date_rules.every_day())
context.sell = False
context.buy = Falsedef bollinger_bands(context, data):
period = 20
current_price = data.current(context.stock, 'price')
prices = data.history(context.stock, 'price', period, '1d')
avg_20 = prices.mean()
std = prices.std()
upper_band1 = avg_20 + std
upper_band2 = avg_20 + 2*std
lower_band1 = avg_20 - std
lower_band2 = avg_20 - 2*std
stop_loss = 0.0
if ((current_price > upper_band1) and (current_price < upper_band2)) and not context.buy:
order_target_percent(context.stock, 1.0)
context.buy = True
context.sell = False
print('Long position')
elif ((current_price < lower_band1) and (current_price > lower_band2)) and not context.sell:
order_target_percent(context.stock, -1.0)
context.buy = False
context.sell = True
print('Short position')
elif (current_price < (1 - stop_loss) * lower_band1) and context.buy:
order_target_percent(context.stock, 0)
context.buy = False
context.sell = False
print('Stop loss on long')
elif (current_price > (1 + stop_loss) * upper_band1) and context.sell:
order_target_percent(context.stock, 0)
context.buy = False
context.sell = False
print('Stop loss short')
record(upper = upper_band2, lower = lower_band2, price = current_price)**
在这个代码中,使用了 SMA20 和 0%的止损。除此之外,一旦当前价格脱离买入或卖出区域,算法就会平仓。让我们看看这段代码将如何执行:
原创双 BB 性能
回报率大幅下降,但所有其他基本面都有所改善。让我们看看是否可以通过稍微调整我们的算法来做得更好。我提议 3 个改变:
1-不要用 SMA20,我们试试 SMA13。互联网会告诉你在 8 到 12 之间选择一个 SMA,但我认为最好对它进行回溯测试,选择一个最适合你想要使用的安全性的。我测试了几个,13 是最好的。
2-允许当前价格有更多的空间来“T2”呼吸“T3”。让价格在简单移动平均线(上下带)的 2 个标准差内反弹。
3-设置 2%的止损。
**# Modified Double BB strategyimport numpy as npdef initialize(context):
context.stock = sid(24)
schedule_function(bollinger_bands, date_rules.every_day())
context.sell = False
context.buy = False
def buy_and_hold(context, data):
order_target_percent(context.stock, 1.0)
print('Buy APPL')def bollinger_bands(context, data):
period = 13
current_price = data.current(context.stock, 'price')
prices = data.history(context.stock, 'price', period, '1d')
avg_20 = prices.mean()
std = prices.std()
upper_band1 = avg_20 + std
upper_band2 = avg_20 + 2*std
lower_band1 = avg_20 - std
lower_band2 = avg_20 - 2*std
stop_loss = 0.02
if ((current_price > upper_band1) and (current_price < upper_band2)) and not context.buy:
order_target_percent(context.stock, 1.0)
context.buy = True
context.sell = False
print('Long position')
elif ((current_price < lower_band1) and (current_price > lower_band2)) and not context.sell:
order_target_percent(context.stock, -1.0)
context.buy = False
context.sell = True
print('Short position')
elif (current_price < (1 - stop_loss) * lower_band2) and context.buy:
order_target_percent(context.stock, 0)
context.buy = False
context.sell = False
print('Stop loss on long')
elif (current_price > (1 + stop_loss) * upper_band2) and context.sell:
order_target_percent(context.stock, 0)
context.buy = False
context.sell = False
print('Stop loss short')
record(upper = upper_band2, lower = lower_band2, price = current_price)**
让我们回测一下这段代码:
改进的双 BB 性能
很好!我们能够提高回报率、阿尔法和夏普比率,同时降低贝塔和下降。
结论
在本文中,我们研究了苹果股票的双 BB 策略与买入并持有策略的绩效。
与买入并持有相比,自动双 BB 的回报率增加了 100%以上,同时降低了市场风险β和提款。此外,机器人增加了阿尔法和夏普比率。
我很想在评论区听到你关于如何改进这个算法的想法。
谢谢!
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
使用 Python 进行回溯测试
回溯测试移动平均线
在本帖中,我们将使用 Python 对简单的移动平均(MA)策略进行回溯测试。在我最近的一篇文章中,我展示了如何使用 Python 计算和绘制移动平均策略。现在,我们将学习通过回溯测试我们的算法来模拟移动平均线策略在过去几个月的表现。
重述移动平均线策略
让我们首先快速回顾一下我们在上一篇文章中构建的内容。我们的模型很简单,我们构建了一个脚本来计算和绘制短期移动平均线(20 天)和长期移动平均线(250 天)。
我推荐你看一下这篇文章,了解更多关于移动平均线和如何构建 Python 脚本的细节。在这篇文章中,我将只发布获取所选股票的移动平均线和股价的代码:
import requests
import pandas as pd
import matplotlib.pyplot as plt
def stockpriceanalysis(stock):
stockprices = requests.get(f"https://financialmodelingprep.com/api/v3/historical-price-full/{stock}?serietype=line")
stockprices = stockprices.json()
#Parse the API response and select only last 1200 days of prices
stockprices = stockprices['historical'][-1200:]
#Convert from dict to pandas datafram
stockprices = pd.DataFrame.from_dict(stockprices)
stockprices = stockprices.set_index('date')
#20 days to represent the 22 trading days in a month
stockprices['20d'] = stockprices['close'].rolling(20).mean()
stockprices['250d'] = stockprices['close'].rolling(250).mean()
stockpriceanalysis('aapl')
回溯测试策略
为了执行回溯测试,我们将:
- 当短期移动平均线穿越长期移动平均线上方时,做多 100 只股票(即买入 100 只股票)。这就是所谓的黄金交叉。
- 几天后卖出股票。例如,我们会保留库存 20 天,然后出售。
- 计算利润
这是一个非常简单的策略。我们将有所选股票的每日收盘价。该策略也可以用于分钟或小时数据,但我将保持简单,并基于每日数据执行回溯测试。
因为我不期望有很多进入点,也就是当我们购买股票时,为了简单起见,我将忽略交易成本。
还记得我们之前的帖子吗,如果我们通过将股票名称作为参数传递给 analyse 来运行脚本,我们将获得一个名为 stockprices 的 Pandas 数据帧,其中包含最近 1200 天的收盘价和移动平均线。
stockpriceanalysis('aapl')
#Outcome stored in a DataFrame call stockprices
close 20d 250d
date
2020-02-07 320.03 316.7825 224.76192
2020-02-10 321.55 317.3435 225.36456
2020-02-11 319.61 317.4760 225.96228
2020-02-12 327.20 318.2020 226.58788
Python 中的回溯测试策略
为了建立我们的回溯测试策略,我们将首先创建一个包含我们每个多头头寸利润的列表。
首先(1),我们创建一个新列,它将包含数据帧中所有数据点的 True ,在该数据帧中,20 天移动平均线与 250 天移动平均线相交。
当然,我们只对交叉发生的第一天或第二天感兴趣(即 20 日均线越过 250 日均线)。因此,我们定位交叉发生的第一个或第二个日期(行)( 2)。
正如在这篇文章中所述,我们将使用两天规则(,即只有在被多一天的收盘确认后,我们才开始交易,并且只有当连续两天 20 日均线高于 250 日均线时,我们才会保留该日期作为进场点。
这种方法将帮助我们避免日常交易噪音波动。当这种情况发生时,我们将在列 firstbuy 中设置入口点,其中值等于 True:
#Start longposiiton list
longpositions = []
# (1)
stockprices['buy'] =(stockprices['20d'] > stockprices['250d'])
# (2)
stockprices['firstbuy'] = ((stockprices['buy'] == True) & (stockprices['buy'].shift(2) == False)& (stockprices['buy'].shift(1) == True))
# (3) identify the buying points
buyingpoints = np.where(stockprices['firstbuy'] == True)
print(buyingpoints)
#Outcome
(array([ 307, 970, 1026]),)
规则*(股票价格【买入】。shift(2) == False)* ,帮助我们找出交叉发生后的第一个日期。
现在我们有了变量买入点 (3),我们应该用我们的长期策略进入市场的日期。
数组 buyingpoints 中的每个元素代表我们需要做多的行。因此,我们可以通过它们循环得到接近的价格,并购买 100 只股票(4)。
然后,我们保留这些股票 20 天(5),并以+20 天收盘价卖出这 100 只股票。
#(4)
for item in buyingpoints[0]:
#close price of the stock when 20MA crosses 250 MA
close_price = stockprices.iloc[item].close
#Enter long position by buying 100 stocks
long = close_price*100
# (5) sell the stock 20 days days later:
sellday = item + 20
close_price = stockprices.iloc[sellday].close
#Sell 20 days later:
sell = close_price*100
# (6) Calculate profit
profit = sell - long
longpositionsprofit.append(profit)
最后,我们计算利润,并将策略的结果添加到 longpositionprofit 数组(6)中。
我们战略的结果
要了解我们的策略执行得如何,我们可以打印出多头头寸利润列表并计算总额:
print(longpositionsprofit)
#outcome
(array([ 307, 970, 1026]),)
print(sum(longpositionsprofit))
#outcome
2100.0
太好了,我们对苹果的回溯测试策略显示,在 1200 多天里,我们进入了一个多头头寸,并在 20 天后总共卖出了三次。
第一次,我们获得了 307 美元的利润,第二次,970 美元,最后一个多头头寸,我们获得了 1026 美元的利润。总共是 2100 美元。
一点也不差。但是如果我们在 1200 天前买了这只股票并一直持有到今天会怎么样呢?通过在我们的股票价格数据框架中获得最后一个可用价格和第一个可用价格,我们可以很容易地计算出买入和持有的利润。
firstdayprice = stockprices.iloc[0].close
lastdayprice = stockprices.iloc[-1].close
profit = 100*(lastdayprice - firstdayprice)
profit
#Outcome
15906.999999999996
有趣的是,只要持有股票 1,200 天,我们的利润就是 15,906 美元加上年度股息。比我们采用移动平均线策略要高得多。
包扎
我们使用了一个简单的策略,当 20 日均线穿过 250 日均线时买入股票。然后,我们把股票保留了 20 天,然后才卖出。
我们可能还遵循了其他策略。例如,我们可以在移动平均线交叉时买入股票,并持有到最后。或者,如果 250 天移动平均线低于 20 天移动平均线,我们可以卖掉股票。
我会让你知道如何试验和测试这些其他的策略。很高兴在我的 Twitter 账户上收到您的反馈。
查看下面的 Python 脚本,对任何公司的移动平均线策略进行回溯测试。只要把苹果的 换成其他公司的 就行了
#Moving Averages and backtesting
import requests
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
def stockpriceanalysis(stock):
stockprices = requests.get(f"https://financialmodelingprep.com/api/v3/historical-price-full/{stock}?serietype=line")
stockprices = stockprices.json()
#Parse the API response and select only last 1200 days of prices
stockprices = stockprices['historical'][-1200:]
#Convert from dict to pandas datafram
stockprices = pd.DataFrame.from_dict(stockprices)
stockprices = stockprices.set_index('date')
#20 days to represent the 22 trading days in a month
stockprices['20d'] = stockprices['close'].rolling(20).mean()
stockprices['250d'] = stockprices['close'].rolling(250).mean()
###STARTING BACKTESTING STRATEGY
#Start longposiiton list
longpositionsprofit = []
shortpositions = []
stockprices['buy'] =(stockprices['20d'] > stockprices['250d'])
#We find the first True since it is first day when the line has crossed. Also, ensure that we have at least two days where sticoprices
stockprices['firstbuy'] = ((stockprices['buy'] == True) & (stockprices['buy'].shift(2) == False)& (stockprices['buy'].shift(1) == True))
buyingpoints = np.where(stockprices['firstbuy'] == True)
for item in buyingpoints[0]:
#close price of the stock when MA crosses
close_price = stockprices.iloc[item].close
#Enter long position
long = close_price*100
sellday = item + 20
close_price = stockprices.iloc[sellday].close
#Sell 20 days later:
sell = close_price*100
#Calculate profti
profit = sell - long
longpositionsprofit.append(profit)
#Result of Moving Average Strategy of going long
print(longpositionsprofit )
print(str(sum(longpositionsprofit)) + ' is the profit of Moving Averag Strategy')
#Result of just holding the stock over 1200 days
firstdayprice = stockprices.iloc[0].close
lastdayprice = stockprices.iloc[-1].close
profit = 100*(lastdayprice - firstdayprice)
print(str(profit) + ' is the profit of holding over the selected period of 1200 days')
#Change apple for the ticker of any company you want to backtest
stockpriceanalysis('AAPL')
原载于 2020 年 3 月 8 日 https://codingandfun.com*。*
回溯:如何处理搜索编程面试问题
用三个例子直观地解释:N 皇后、飞行路线和数独
图片来源:作者
回溯是解决常见编程面试算法问题的有效方法。回溯深度——搜索解决方案,然后一到达终点就回溯到最近的有效路径(也就是说,我们不能再前进了)。这种方法减少了搜索空间,因为我们知道的无效路径都从解空间中排除了。
然而,使用回溯需要测试部分解决方案的能力——如果没有进度指标表明我们当前的解决方案路径是否通向一个解决方案,该方法就不能找到全局最优。然而,像数独这样的事情可以用回溯来解决——比方说,如果在一行、一列或一个正方形中有两个相同的数字,那么当前的解决路径是否无效就一目了然了。
回溯由三部分组成:一个递归函数,它接受一个解集(可能是不完整的 n ),一个对 n 的变异或添加,它添加到集合 n ,以及一个完成和有效性检查,它检查一个解集变异的完成(解是完整的吗?)和有效性(是否符合有效性的要求?对于当前填写的值,这是一个可接受的解决方案吗?).
图片来源:作者
回溯基于非常简单的元素自动创建一个干净且计算高效的搜索树。
在本文中,我将通过视觉演示回溯如何被用来解决三个经典的编程面试式搜索问题。
n 皇后问题
N-皇后问题是一个经典的回溯问题:给定一个 N 乘 N 大小的棋盘,你可以用多少种方式排列 N 个皇后棋子,使它们不会互相威胁(一个不在一个皇后的列、行或对角线上)?
举例来说,这个格子是一个无效的移动,因为八个皇后中至少有两个在另一个的行、列或对角线上,用红色方块标记。
这个问题的强力解决方案是尝试在每个 N 乘 N 地点中的 N 个皇后的每一个组合— N 选择 N 种可能性。
画出来,其中 x 代表 N 和 y 代表搜索的可能性的数量,它扶摇直上。
图片来源:作者
仅仅对于一个标准的 8 乘 8 网格,就有 4,426,165,368 种组合,慢得令人痛苦。这可以通过不将两个皇后放在同一行或列中得到部分改善,但我们仍然需要迭代每一行和每一行中的每个单元格——运行时间为 O ( N ),不够快。
现在,让我们通过一个问题清单来确定回溯是否有帮助。
可以构造部分解吗?
是的,可以构建部分解决方案。通过在棋盘上放置一定数量的皇后,我们可以部分地构建一个解。
那些部分解决方案可以被验证为有效或无效吗?
是的,我们可以通过检查任意两个皇后是否相互威胁来验证部分解决方案是否有效。这可以通过承认原来的女王不互相威胁来加速,并且只检查新增加的女王是否威胁任何其他女王。
可以验证解决方案是否完整吗?
是的,当所有的 N 皇后都被放到棋盘上时,解决方案就完成了。回溯的伟大之处在于,当解决方案完成时,它也是正确的,因为所有不正确的解决方案路径都已被事先排除。
让我们构造一个回溯方法来更快地解决 N 皇后问题。
功能n_queens
:
- 摄入
N
和board
,一串数字。 - 如果没有指定,将
board
初始化为空列表,并将count
初始化为 0。 - 对于
*N*
中的每列*X*
, -
将列
*X*
’ 的索引添加到board
。 -
如果
board
有效,将n_queens
的输出与输入N
和board
相加到count
(这将初始化函数的另一个循环,是回溯的隧道或树构建过程。由于在这种情况下部分解决方案被认为是有效的,它启动了函数n_queens
的另一个实例。 -
否则,删除列
*X*
。 - 返回
count
。
伸缩式树型建筑
评估电路板是否有效的函数如下:
- 入口
board
,一个数字列表,其中每个数字对应一列。 - 最近添加的皇后行是棋盘的当前长度减一(因为索引从 0 开始),当前皇后列是棋盘的最后一个元素。
- 对于棋盘中的每一行
R
和每一列C
(仅由放置的皇后组成), -
找出新添加的皇后列和当前列的区别
C
。如果等于 0(两列相同),返回False
并从函数中中断。 -
找出新添加的女王排和当前排
R
的区别。如果等于 0(两行相同),返回False
并从函数中中断。 - 否则,返回
True
。
通过在一个构建函数中递归迭代一个构建函数的新实例,回溯能够构建一个智能树,在情况无望时不再继续:它是基于过程而不是基于结果的。
结果,其中索引指示 N 的值:
1, 1, 0, 0, 2, 10, 4, 40, 92, 352
航班路线问题
给定某人的航班的无序列表,每一个都用(起点、目的地)对和起始机场表示,计算此人的行程。如果不存在,返回 na-必须在旅程中使用所有航班。
让我们以这些航班为例:
- HNL ➔ AKL
- 尤尔·➔订单
- SFO ➔ HNL
- 订单➔ SFO
这个问题的强力解决方案是尝试航班的每一种排列,并验证它是否是一个有效的旅程,使它成为 O ( n !)时间。
让我们再问一下使用回溯的三个问题清单。
可以构造部分解吗?
是的,部分解决方案可以通过列出一个不完整的行程来构建,比如 SFO ➔ HNL ➔奥德➔?。
那些部分解决方案可以被验证为有效或无效吗?
如果没有从旅程中的最后目的地出发的航班,并且仍然有剩余的航班可以乘坐,则该解决方案可以被验证为无效。因为必须使用所有航班,所以我们到达了终点。
可以验证解决方案是否完整吗?
是的,当旅程使用所有航班时,解决方案就完成了。
构建解决方案的逻辑:
一个功能get_itinerary
:
- 获取一个无序列表
flights
,其元素形式为(origin, destination)
和current_itinerary
,即一个旅程列表(其中第一个元素是起始机场,第二个元素是第一个航班的目的地和第二个航班的出发地,依此类推)。 - 如果
flights
已经用完,返回current_itinerary
。 last_stop
将等于current_itinerary
的最后一个元素。- 对于航班中的每个
(origin, destination)
对, -
将
destination
添加到current_itinerary
中。 -
如果
origin
等于last_stop
(这是检查,确保航班是有效的连接), -
用除当前
(origin, destination)
对之外的所有航班返回另一个get_itinerary
运行,并退出该功能。 -
否则,删除最近的
destination
。 - 如果先前的树搜索都不能返回任何解决方案,则返回
None
。
回溯构建的树的简化版本
您可能会观察到,实现回溯的很大一部分与多次使用一个函数和构建一个自动化的递归搜索树有关。
注意,对于这个特殊的问题,有一个更有效的方法来解决它。我们只是用回溯作为例子。实际上,更快的方法是选择出发机场(例如 SFO),在航班中找到中转机场(SFO 到 HNL),然后将目的地添加到旅程中,循环进行。
九宫格游戏
我们能用回溯法解决一个标准的数独难题吗?
可以构造部分解吗?
是的,我们可以部分填充数独板上的位置。
那些部分解决方案可以被验证为有效或无效吗?
是的,如果部分解决方案中有任何数字在行、列或正方形中具有相同的数字,则该解决方案无效。否则有效。
可以验证解决方案是否完整吗?
是的,当整个数独板被填满时,解决方案就完成了。
让我们尝试一个接一个地填充每个空单元格,一旦遇到无效状态就返回。看起来会像这样:
功能sudoku
:
- 获取变量
board
,这是一个数组,每个值代表数独棋盘上的一个单元格。 - 如果
board
完成,返回board
并退出该功能。 - 设
r
和c
代表板上第一个空值的行和列。 - 对于
[1, 2, 3, 4, 5, 6, 7, 8, 9]
中的每个值i
, -
将第
r
行第c
列单元格设置为i
。 -
如果
board
至今有效, -
给定
board
,运行sudoku
的另一个实例。
数独的 4x4 版本如何与回溯一起工作
使用回溯法来解决像困难的数独棋盘这样复杂的事情,简单而又干净,这是非常美妙的。只要勾勒出一个递归函数、一个部分解检查和一个评估解是否完整的函数,程序就会自动为你构建一棵树,找到最佳解(如果有的话)。
结论
我希望这篇文章能够让你理解,概述回溯的三个简单组成部分如何能够概述程序的规则,以便自己进行排序并找到最佳解决方案。
袋装树:每个数据科学家都需要的机器学习算法
袋装树简介
在还没有深入细节的情况下,对决策树有一些基本的了解是很重要的。
从每个算法的评估方法到算法本身,都有很多相似之处。
如果你还不熟悉决策树,我推荐你快速复习一下这里。
也就是说,准备好成为袋装树专家吧!袋装树以提高单个决策树的预测能力而闻名,是一种非常有用的机器学习工具带算法。
什么是袋装树&是什么让它们如此有效?
为什么使用袋装树
袋装树之间的主要思想是,你不是依赖于单个决策树,而是依赖许多许多决策树,这允许你利用许多模型的洞察力。
偏差-方差权衡
当考虑模型的性能时,我们通常会考虑我们输出的偏差-方差权衡。方差与我们的模型处理小错误的方式有关,也与我们的模型偏离的程度有关,偏差会导致拟合不足。该模型实际上对变量之间的关系做出了不正确的假设。
你可以说,变异的问题是,虽然你的模型可能是方向正确的,但它不是非常准确,而如果你的模型非常有偏差,那么变异可能很小;它可能完全方向不正确。
一般来说,决策树的最大问题是它们有很高的方差。这带来的问题是,数据的任何微小变化都可能导致模型和未来预测的重大变化。
这在这里起作用的原因是袋装树的好处之一,它有助于在保持偏差一致的同时最小化变化。
为什么不用袋装树
袋装树的一个主要问题是它们难以解释。在决策树的课程中,我们了解到决策树的一个主要优点是它们非常容易解释。袋装树在这方面证明是相反的,因为它的过程增加了复杂性。我稍后会对此进行更深入的解释。
什么是装袋?
Bagging 代表引导聚集;这就是所谓的集成方法——这是一种有效地将不同的模型、数据、算法等分层的方法。
所以现在你可能会想…好吧,酷,那么什么是引导聚合…
所发生的是,模型将对数据的子集进行采样,并将训练决策树;到目前为止,与决策树没有什么不同…但接下来发生的是获取额外的样本(替换,这意味着相同的数据可以被多次包含),训练新的模型,然后对预测进行平均。一棵袋装树可以包括 5 棵树、50 棵树、100 棵树等等。集合中的每棵树可能有不同的特征、终端节点数、数据等。
可以想象,一棵袋装的树是很难解读的。
培养一棵袋装树
首先,我们将开始训练和测试。这里就不多说火车测试拆分了。我们将用titanic
包中的泰坦尼克号数据集来做这件事
n <- nrow(titanic_train)n_train <- round(0.8 * n)set.seed(123)
train_indices <- sample(1:n, n_train)
train <- titanic_train[train_indices, ]
test <- titanic_train[-train_indices, ]
现在我们已经有了训练和测试集,让我们加载ipred
包。这将允许我们运行装袋功能。
需要记住的几件事是,公式表明我们想通过(~
) Pclass + Sex + Age + SibSp + Parch + Fare + Embarked
来理解Survived
从这里您可以看到,我们正在使用训练数据集来训练这个模型。&最后可以看到这个参数coob
。这是为了确认我们是否想测试袋外样品的性能。
还记得我说过每棵树都重新采样数据吗?这个过程会留下一些记录,这些记录永远不会用于训练&组成一个优秀的数据集来测试模型的性能。这个过程发生在bagging
函数中,当我们打印模型时你会看到。
library(ipred)
set.seed(123)
model <- bagging(formula = Survived ~ Pclass + Sex + Age + SibSp + Parch + Fare + Embarked, data = train, coob = TRUE)
print(model)
如你所见,我们在袋装树模型中训练了默认的 25 棵树。
我们使用与决策树相同的过程来预测我们的测试集。
pred <- predict(object = model, newdata = test, type = "class") print(pred)
性能赋值
现在,我们已经训练了我们的模型,预测了我们的测试集,现在是时候分解不同的性能评估方法了。
ROC 曲线和 AUC
ROC 曲线或受试者工作特征曲线是一种可视化二元分类模型正确诊断或预测能力的方法。ROC 曲线绘出了不同阈值下的真阳性率与假阳性率的关系。
我们对于 ROC 曲线的目标是真阳性率 100%,假阳性率 0%。那条曲线会落在图的左上角。
AUC 旨在确定可分性的程度,或正确预测类别的能力。AUC 越高越好。1 是完美的,0.5 是随机的。
我们将使用metrics
包来计算数据集的 AUC。
library(Metrics)
pred <- predict(object = model, newdata = test, type = "prob") auc(actual = test$Survived, predicted = pred[,"yes"])
在这里,您可以看到我将type
更改为"prob"
以返回百分比可能性,而不是分类。这是计算 AUC 所需要的。
这返回了 0.89 的 AUC,一点也不差。
截止阈值
在分类中,临界值的概念意味着给定一个给定结果的一定百分比的可能性,你会相应地对它进行分类。哇,这是一个满嘴。换句话说,如果你预测 99%的存活率,那么你可能会把它归类为存活率。好吧,假设你看着另一个乘客,你预测他有 60%的可能性活下来。嗯,他们仍然更有可能幸存,所以你可能会把他们归类为幸存。选择type = "pred"
时,您可以灵活指定自己的截止阈值。
准确(性)
这个指标很简单,你的预测有多少是正确的。caret
的混淆矩阵函数就包含了这个。
混淆矩阵
caret
包中的confusionMatrix
功能非常有用。用于评估分类模型性能。加载这个包,把你的预测和实际数据传给它。
library(caret)
confusionMatrix(data = test$pred, reference = test$Survived)
这个函数向你展示的第一件事就是所谓的混淆矩阵。这将向您显示一个预测值和实际值如何匹配的表格。所以预测值和参考值相同的对角线单元格代表我们得到的正确值。将这些记录加起来 149 (106 + 43)并除以记录总数,178;我们达到了 83.4%的准确率。
True positive:象限中引用和预测都为 1 的单元格。这表明你预测了存活,而他们确实存活了下来。
假阳性:这里你预测为阳性,但你错了。
真阴性:当你预测为阴性,并且你是正确的。
假阴性:当你预测为阴性,而你是不正确的。
需要记住的几个关键指标是灵敏度和特异性。敏感度是您正确预测的真实记录的百分比。
另一方面,特异性是衡量实际错误记录中你正确预测的部分。
在不平衡数据集上进行预测时,要记住特异性。一个非常常见的例子就是对垃圾邮件进行分类。99%的情况下它不是垃圾邮件,所以如果你预测没有垃圾邮件,你有 99%的准确率,但你的特异性是 0,导致所有的垃圾邮件都被接受。
结论
总之,我们已经了解了使用袋装树的正确时间,以及使用它们的错误时间。
我们定义了什么是装袋以及它如何改变模型。
我们建立并测试了自己的模型,同时定义和评估了各种性能指标。
我希望你喜欢这个关于袋装树的快速课程。让我知道你是否想要更多的信息,或者你是否想要我在另一篇文章中报道一些事情。
祝数据科学快乐!
装袋、增压和梯度增压
易于理解的解释
埃里克·穆尔在 Unsplash 上拍摄的照片
制袋材料
Bagging 是在 bootstrap 样本上训练的机器学习模型的聚合(Bootstrap AGGregatING)。什么是引导样本?这些是几乎独立同分布(iid)样本——因为样本之间的相关性很低,而且它们来自同一个分布。引导过程用于创建这些样本。这包括从数据集中抽取样本并替换掉,记住如果这些样本足够大,它们将代表抽取样本的数据集,假设抽取样本的数据集也足够大以代表总体。在我们的数据集中有大量的观察值也意味着 bootstrap 样本更有可能在样本之间具有低相关性。
图一。样本取自数据集,数据集也是取自总体的样本。
为什么我们不简单地从总体中抽取更多的样本,而不是从我们的数据集中抽取样本?我们可能没有资源或能力从人群中获取更多样本——通常,在研究和工业中,我们必须完全依赖我们已经获得的或以前收集的数据。在这种情况下,bootstrapping 已经被证明是一种准确且计算效率高的估计人口分布的方法。
例如,如果我们有关于一个人是否拖欠贷款的数据,带有伯努利分布响应变量(0 或 1 表示此人是否拖欠),我们可以计算响应变量的平均值,以快速估计我们的数据集中类的表现程度。为了找到响应变量均值的分布(了解其可变性以及我们的数据集对总体的代表性),我们必须从总体中重新取样几次,并计算每个样本的均值,以便更好地了解响应变量的真实分布。然而,这并不总是可能的,我们只限于一个样本(我们的数据集)。经验表明,通过 bootstrapping,仅使用我们通过从数据集本身中抽取替换样本而获得的数据,有可能获得我们采样统计(响应变量的平均值)的真实分布的相当准确的估计值。
图二。左图:样本统计量α估计值的直方图,该估计值是根据总体中的 1,000 个样本(本例中为数据集)计算得出的。中心:从单个数据集的 1000 个 bootstrap 样本中获得的α估计值的直方图。右图:显示在左图和中间图中的α估计值显示为箱线图。在每个面板中,粉色线表示α的真实值。(詹姆斯等人,未注明)
bagging 的想法自然来自 bootstrapping,因为独立、同质的机器学习模型是在几乎独立的 bootstrap 样本上训练的,并且它们的结果是通过加权平均值聚合的。在这些 bootstrap 样本上进行训练的原因是,样本具有低相关性,因此我们可以更好地代表总体。流行的 bagging 算法,random forest,在为每个引导样本拟合决策树时,也对一小部分特征进行子采样,从而进一步降低样本之间的相关性。Bagging 提供了真实总体的良好表示,因此最常用于具有高方差的模型(如基于树的模型)。
助推
在高层次上,所有提升算法都以相似的方式工作:
- 数据集中的所有观察值最初被赋予相同的权重。
- 在这个数据集上训练机器学习模型。
- 来自步骤 2 的模型被添加到带有与其相关联的误差的集合中,该误差是误分类观测值的权重之和。
- 错误分类的观察值被赋予更大的权重。
- 步骤 2-4 会重复许多个时期。
这里的想法是使错误分类的观察在随后的学习迭代中显得更加重要。在这一点上应该注意的是,boosting 是一种非常强大的集合技术,但是由于其关注困难观测的性质,它容易过拟合。因此,它通常用于相对有偏差的基础模型,例如浅树。
最容易理解的升压算法是 AdaBoost,其工作原理如下:
- 初始化变量。
M = Number of models to fitN = Number of observations in datasetm = 1 # Iteration counter, m <= M.w_i = 1/N # For i = 1, 2, 3, ..., N.F_0 = 0 # Ensemble model.
- 使用最小化加权误差
e_m = sum(w_misclassified)
的观察权重w_i
训练模型f_m
。 - 最新合奏模型
F_m = F_m_minus_1 + (alpha_m * f_m)
哪里alpha_m = log(1 — e_m) / e_m
。 - 以与
alpha_m
成比例的增量更新错误分类观测值的权重。 - 递增迭代计数器。
m += 1if m <= M:
go to step 2
- 最终模型是各个模型的预测总和乘以各自的 alpha 系数。
F = (alpha_1 * f_1) + (alpha_2 * f_2) + ... + (alpha_m * f_m)
梯度推进
这种方法被称为梯度推进,因为它使用梯度下降算法来最小化向集合添加模型时的损失。后续模型被拟合到伪残差而不是调整权重。随机梯度下降(如 XGBoost 所用)通过对每个阶段的观察值和特征进行采样来增加随机性,这类似于随机森林算法,只是采样是在没有替换的情况下进行的。
梯度推进算法通过构建新的模型来改进每次迭代,该新的模型添加了估计器 h 以提供更好的模型。完美的 h 意味着:
其中 y 是目标。或者简单地说:
这是目标和前一次迭代的模型预测之间的残差。为了近似这个残差,我们使用前面提到的伪残差,这在下面的步骤中解释:
- 最初,像往常一样在数据集上训练,并获得每个观察的预测。
- 根据步骤 1 中的预测,将伪残差计算为损失函数偏导数的负值。
- 使用伪残差作为下一个模型的新目标,并像以前一样获得每个观测值的预测。
- 重复步骤 2-3,进行 M 次迭代。
图三。按照步骤 2 的伪残差。该值用作在每个训练时期预测 F(x)和目标 y 之间的“距离”的度量。m 是每个基础模型,N 是之前数据集中的观察次数。
在进行上述操作时,我们有效地预测了每次迭代中残差的近似值,因此,我们得到了以下集合模型:
带 h ,如中所述:
取而代之的是我们的伪残值。
参考
詹姆斯·g·威滕·d·哈斯蒂·t·蒂布希拉尼·r(未注明)。统计学习入门。
基于低方差模型的 Bagging
入门
简单线性回归装袋的奇特案例
Bagging(也称为 bootstrap aggregation)是一种技术,在这种技术中,我们根据均匀的概率分布重复地采取多个样本进行替换,并在其上拟合一个模型。它将多个预测组合在一起,通过多数投票或汇总预测来给出更好的预测。这种技术对于倾向于过度拟合数据集的模型(高方差模型)是有效的。Bagging 减少了方差而不会使预测有偏差。这项技术是许多合奏技术的基础,所以理解它背后的直觉是至关重要的。
如果这种技术这么好,为什么我们只在显示高方差的模型上使用它?当我们将它用于低方差模型时会发生什么?让我们借助演示来理解潜在的问题。
我们将在决策树上使用 bagging 来证明 bagging 提高了高方差模型的准确性,并将其与基于简单线性回归的 bagging 进行比较,后者因数据集而有偏差。当预测值与目标变量不完全相关时,简单线性回归是有偏差的。
偏差和方差
我们将在整篇文章中讨论偏差和方差,所以让我们先了解一下它是什么。
偏置
高偏差是指模型过于简化。即当我们不能捕捉数据的真实关系时。我们创建模型的目的是捕捉数据的真实性质,并根据趋势进行预测,这使得高偏差成为一种不受欢迎的现象。
在这种情况下,正在使用的模型并不合适。作者图片
差异
高方差指的是模型过于复杂的情况。即,在捕捉模型的真实性质的过程中,我们正在创建一个模型,该模型很好地学习了训练数据,以至于它的准确性在任何其他数据集上都恶化了。这种情况也是不希望的,因为我们的目标是对看不见的数据进行预测。
在这种情况下创建的模型不适用于训练数据集中不存在的数据。作者提供的图片
偏差-方差权衡
当我们创建一个模型时,我们希望在偏差和方差之间取得平衡。偏差和方差是相反的,所以每当我们试图减少方差时,我们就同时增加了模型的偏差。这种过拟合/欠拟合的困境被称为偏差-方差权衡。这张图片很好地展示了他们之间的关系。
偏差-方差权衡。作者图片
高方差模型—决策树
决策树对目标变量进行分类,在默认设置下,它不会停止,除非它对每个类别进行了完美的分类。这使得树过度适应所提供的数据,并且模型在测试数据集上的准确性将会很低。让我们用一个数据集来验证这一点。我们将使用皮马印第安人糖尿病数据集。
决策树的准确性:
作者图片
决策树的打包
正如我们之前讨论的,bagging 应该在不增加偏差的情况下减少我们预测的方差。这一特性的直接影响可以从预测准确性的变化中看出。装袋会让训练精度和测试精度的差异变小。我们可能不会总是观察到训练精度的变化,但是在这种情况下,测试精度总是更好。让我们检查一下装袋对数据集的影响。
作者图片
这个结果证明了我们的观点!装袋提高了高方差模型的性能!
低方差模型—简单线性回归
到目前为止,我们在本文中讨论的一切都是已知和直观的,但是当我们试图在简单线性回归这样的低方差模型上使用 bagging 时会发生什么呢?让我们通过演示每个袋装模型会发生什么来探索这个场景。我们可以直观地宣称,由于 bagging 只影响高方差模型,它应该对有偏模型没有影响。我们将在文章的其余部分验证我们的假设是否正确。
我们将使用金县房价数据集。我们只使用一个变量来简化可视化。让我们看看 price 和 sqft_living 之间的散点图,以大致了解它们之间的关系,并在此基础上建立一个简单的线性回归模型。
作者提供的图片
这种情况下简单线性回归模型的准确性:
作者图片
简单线性回归装袋
在讨论“简单线性回归装袋的奇怪案例”之前,让我们快速检查装袋简单线性回归后的准确性是否提高或甚至保持模型性能不变。
作者图片
尽管打包了 200 个简单的线性回归模型,RMSE(均方根误差)还是下降了 2.7 个百分点!简单线性回归的有偏性是其背后的原因。我们观察到 RMSE 的变化非常小,因为我们的模型能够很好地捕捉数据集的趋势。sqft_living 和价格之间的相关性为 0.7,简单线性回归模型捕捉了变量之间的线性关系。如果简单线性回归的相关性较低,RMSE 的差异会更大。让我们在下一节讨论为什么。
为什么简单线性回归对装袋效果不好?
简单线性回归是一种有条件偏差的模型。即当变量之间存在明确的线性关系时,该模型可以被认为是稳定的。在这种情况下,即使我们对其使用 bagging,模型的准确性也不会降低。当变量之间的这种关系改变时,简单线性回归试图创建一条直线来捕捉数据的趋势。在这种情况下,单个袋装模型的偏差会增加。
由于我们的变量之间的相关性是 0.7,它不是完全相关的,但它足够好,在这里使用简单的线性回归是有意义的。这就是为什么当我们在 RMSE 装袋时,它没有大幅度下降的原因。bagging 技术创建多个线性回归模型,并取其预测值的平均值。所有这些点将位于回归线上,该回归线可以通过取每个模型的截距和系数的平均值来产生。让我们将平均回归线的预测与最终的袋装预测进行比较。
作者图片
该图中的每条灰线代表单独的简单线性回归模型。它们的偏差高于直接从原始数据集获得的回归线,因为 bootstrap 样本中存在许多重复点。这使得一些点比其余的点更有影响力。这导致平均回归线偏离了我们在没有装袋的情况下可以获得的回归线。
这意味着我们假设 bagging 对高偏差模型没有影响是不正确的!Bagging 确实会影响具有高偏差的模型,但它反而会降低其准确性。这是不是意味着对有高偏差的模型进行打包,总会得到比我们从原始模型中得到的结果更差的结果?让我们再看几张图来总结一下。
引导样本数= 10。作者图片
引导样本数= 100。"作者图片"
引导样本数= 200。作者图片
我们观察到,随着自助样本数量的增加,范围、标准偏差会缩小。RMSE 中值也向简单线性回归线的 RMSE 移动。这表明袋装预测越来越接近简单的线性回归预测,而没有偏离太多。
结论
从这篇文章中可以得出以下几点:
- 在高方差模型上装袋:在不增加偏差的情况下,模型的方差会减少。这种模型的性能会更好,所以建议装袋。
- 对高偏差模型进行 Bagging:与没有 bagging 的模型相比,模型的准确性总是会下降。查看上面的直方图,我们可以得出结论,装袋精度随着装袋模型数量的增加而增加,并且随着 n 达到无穷大,装袋模型的精度将等于直接模型的精度。由于在有偏差模型的情况下,模型的准确性不会增加,因此不建议使用 bagging。
本文的重点是展示当我们使用 bagging 中方差较低的模型时会发生什么。目的是让读者直观地了解哪种模型适合装袋。
请注意,文章中给出的一些代码可能无法工作,因为 python 中没有这些函数。我不得不从头开始编写代码来展示每个模型的偏见,所以如果你正在寻找代码,请参考这个链接— GitHub
参考
[1] Aishwarya Singh,《集成学习综合指南》(附 Python 代码)(2018)
【2】Daniel t . la rose-Chantal d . la rose,7.5 偏差-方差权衡,数据挖掘和预测分析
【3】Trevor Hastie 等人,8.7 Bagging,The Elements of Statistical Learning
【4】Bradley Boehmke 等人,10 Bagging,Hands on Machine Learning
用 Streamlit 烤面包—
Hojicha 泡制酸面团面包
去拿面包屑!
大家好,让我先说这不是 streamlit 的付费帖子,也不是我的上一篇。我再次写 Streamlit,因为我在那里做了一些工作。
如果你像我一样,在冠状病毒封锁期间,你已经烤了很多。我的旅程始于一月份,当时我在巴黎,在附近的面包店吃到了我有生以来吃过的最好的面包。回来后,我受到启发,自己做了面包。我以前用过商业酵母,但这一次,我打算用酸面团的方法来做更美味的面包。经过一周半的尝试,我终于得到了一个功能启动。遇见巴克斯:
现在,巴克斯很酷,但我们不是真的在这里谈论他。巴克斯帮我做了很棒的酸面团面包,真的很棒。但是做面包可能是一个乏味的过程。这涉及到一点数学,因为你必须知道面包师的百分比,这是一套方便的预设计算方法,可以帮助面包师做出好的面包。让我们看一下,好吗?
一点关于烘焙的科学
你可能意识到了,也可能没有意识到,烘焙更像是一门科学,而不是艺术。你不能反复无常地使用你的配料,否则你的面包会惩罚你的。面包师的百分比有助于我们调整精确的比例,以生产出特定口径的面包。所有的面包都是从面粉、水、盐和酵母开始的。这四种原料以不同的比例混合在一起,可以生产出不同质量的面包。太多的面粉,你最终会做出只适合面包屑的超级厚煎饼。水太多,你会看到一团不会变成面包的汤。盐太多,你会杀死所有的酵母,你不会发酵,你还可能做硬面饼。你明白了。
为了解决这个问题,人们开始使用贝克百分比。这些是使用每种配料的理想比例,稍加调整,就能做出像样的面包。这些百分比是基于面粉的初始数量,一切都从那里开始。
例如,以下是亚瑟王面粉公司关于面包师百分比的一个公式:
来源:https://www . kingarthurflour . com/pro/reference/bakers-percentage
你会注意到面粉是 100%,所有其他成分都是 100%的百分比。盐一般固定在 2%,有些多一些,有些少一些,但我见过的食谱中没有一个超过 2.5%或低于 1.75%。对于发酵面团,一般来说,你可以用酵母代替 25%的成熟发酵剂。所有的面包食谱都会相应地调整,因此,一般来说,面包师们传递的食谱更像是数学公式,而不是实际的食谱。
然而,在这些公式中有一个关键变量是水。水合作用是制作面包的关键。水的存在不仅促进了酵母及其非常理想的副产品二氧化碳的生长,而且对面筋的形成也是必不可少的,面筋有助于捕获酵母产生的气体。一般来说,水合程度越高,你的面筋越有弹性和强度,这增加了你面包中的气泡大小,从而增加了你最终面包的膨松度。如果你喜欢有大气泡的面包,你会想要更高的水分含量,特别是在不揉的食谱中,面筋的发展是非常不干涉的。
为了得到更高的水合作用,你必须计算加入面团的水的百分比。这包括摆弄信封背面的计算,计算出你的开胃菜中有多少水和面粉,将它加回到你的总数中,并找到最终的百分比。这实际上是非常简单的数学,但是当你想要修改食谱的时候,它变得很乏味。为了简化这项任务,我想,为什么不用电脑呢?
终于说到重点了!
首先,我用 Python 写了一个简单的公式。这在 Jupyter 笔记本上很容易做到。任何时候我想修改食谱,只要启动它,输入我的变量,瞧!我有完美的比例。这个公式是这样的:
看,我告诉过你数学很简单。但是我不喜欢做数学,因为犯粗心错误的可能性太大了。这个函数会处理好这个问题,永远不会出错。计算机万岁!我需要做的就是用我的起始面粉重量、我想要的水合百分比和一个增加水合的可选参数(如果我使用全麦,全麦非常渴,所以通常需要增加 5-10%的额外水合)调用函数。
这很好,但唯一的问题是,我必须去我的笔记本电脑,启动 Jupyter 笔记本,手动输入数值。如果我在家计划一个食谱,这没问题,但是如果我想在厨房里做这个呢?此外,我认识的其他人可能想做他们自己的计算,我是否想在每次我想提供一些有用的建议时启动它?
输入 Streamlit。对于那些不了解情况的人来说,Streamlit 正在成为当今创建数据科学应用程序最受欢迎的框架之一。在几个小时内,你可以使用 Python 直接从你的 Jupyter 笔记本上创建一个用于机器学习、神经网络等的应用或前端,不需要额外的工作。我要用它来做面包。
S-S-S-S-stttrreaaaaaammmlitttt!!!!
我们要做的第一件事是把我们珍贵的公式粘贴到一个新的笔记本上。然后,因为这个应用程序将是一个首页,扔在一个标题,和一些介绍性的文字解释我为什么做这个计算器,以及它是如何工作的。
这就行了。正如你所看到的,streamlit 有一个标题功能,可以自动在页面顶部粘贴一个大标题,还有一个 markdown 功能,可以让我们输入文本作为 markdown,这很方便。它会根据屏幕大小自动设置文本换行,所以你不必担心像以前蹩脚的 html 编码那样,大段的文本会超出你的页面大小。
下一步是创建交互式小部件,使拨入菜谱变得容易。我从一个单选按钮开始,询问食谱是否包括全麦。正如我前面提到的,全麦面粉一般比普通白面粉更渴。此外,它的麸皮含量往往会切断面筋,额外的水浸泡或自溶有助于软化麸皮,使其更有利于面筋。第一个单选按钮是为白面粉面团或全麦含量最低的面团预设的。我的开胃菜含有黑麦,但它不是整个面团的重要组成部分,所以我会选择这个选项。如果一个面团含有少于 50%的全麦,他们会选择“少于 50%”选项,如果它含有超过 50%,他们会选择“超过 50%”选项。这个选择之后是 If、Elif 脚本,分别为我们的全麦选项参数增加 5%或 10%的水合作用。
现在我们已经建立了变量,下一步是创建一个滑块来设置面粉重量和水合百分比变量。我更喜欢在这里使用滑块,而不是让用户手动输入金额,因为它允许我控制用户的错误。无论是我自己还是用户,在面对空白字段时,都不必担心输入错误或不确定性。只需滑动你的面粉重量,你想要的水合百分比,它会照顾自己。可以想象,该公式可以处理滑块设置的重量和百分比,但大多数家庭烘焙师不需要每批烘焙那么多。1000 克面粉足够做两个大面包,足够 4 个人吃一天。下面是代码:
st.slider(最小值、最大值、起始值、增量)
所以现在我们已经建立了一个方便易用的应用程序来设计我们自己的酸奶配方。这是我们最后一页的样子!
我已经把它上传到 Heroku,所以每个人都可以使用它,它是每个人都可以使用的快速参考。对于在厨房外工作的人来说,它也是移动友好的。
可以在这里找到 app 。请试运行一下,让我知道你的想法!祝你烘焙好运!
平衡数据扩充的正则化效果
利用卫星图像上的图像分割应用程序来识别水体,通过数据扩充来平衡过拟合和欠拟合的需要。
数据扩充的效果
在训练神经网络时,数据扩充是最常用的预处理技术之一。**“增强”*这个词的字面意思是“在尺寸或数量上变得更大的行为或过程”,概括了这种技术的结果。但是另一个重要的影响是它增加或扩大了数据的多样性。*多样性的增加意味着,在每个训练阶段,模型都会遇到不同版本的原始数据。
按作者
为什么我们需要数据的这种“增加的多样性”? 答案就在机器学习的核心宗旨——偏差-方差权衡。更复杂的模型,如深度神经网络,具有较低的偏差,但存在较高的方差。这意味着,这些模型过度拟合训练数据,并会在测试数据或数据上表现不佳,这是他们以前从未见过的。这将导致更高的 预测误差。因此,通过使模型在 一般化 时变得更好,来自数据扩充的增加的多样性减少了模型的方差。
对于图像,一些常见的数据增强方法是截取部分、放大/缩小、沿轴旋转、垂直/水平翻转、调整亮度和绝对强度。音频数据的数据扩充包括添加噪声、改变速度和音调。
虽然数据增强可以防止模型过度拟合,但一些 增强组合实际上会导致 拟合不足。这降低了训练速度,导致可用处理时间、GPU 配额等资源的巨大压力。此外,该模型无法学习足够多的信息来给出准确的预测,这再次导致高预测误差。在这篇博文中,我们以卫星图像的语义分割为例,来看看数据增强的不同组合对训练的影响。
关于数据集
这个 Kaggle 数据集给出了来自哨兵 2 号的卫星图像及其相应的分割水体的遮罩。使用归一化差异水指数或 NDWI 计算掩膜。在数据集中总共 2841 幅图像中,分别为训练集提取了 2560 幅,为验证集提取了 256 幅,为测试集提取了 25 幅。整个分析和建模是在 GPU 支持下在 Google Colab 上完成的。
U 网的结构
简而言之,U-NET 是一个自动编码器,具有从编码器中的每个卷积块到解码器中其对应部分的剩余或跳过连接。这导致了对称的“U”形结构。这篇文章从原始论文开始,对 U-NET 的结构给出了全面的逐行解释。
我们使用稍微修改的 U-NET 版本,如下所示。
所使用的 UNET 块的快照(由作者提供)
看看数据扩充的不同案例
在 Keras ImageDataGenerator 的帮助下,我们探讨了 5 种不同的数据增强情况。我们想看看增强如何导致训练期间过度适应或适应不足。因此,为了对 5 个案例进行比较,使用了培训&验证期间的准确度和损失;其中二进制交叉熵作为损失函数。
在处理语义分割时,需要记住的重要一点是将相同的增强应用于图像及其相应的遮罩!
在所有 5 种情况下,图像和蒙版的像素值都以 1/255 的因子重新缩放。验证和测试集中的所有图像及其遮罩也被重新缩放。
案例 1: 这是基础案例。只有图像及其遮罩的像素值被重新缩放。没有应用任何增强。这个案例产生了一个方差最小的训练集。
**案例二:**除了重新缩放,还随机垂直或水平翻转图像及其蒙版。
情况 3: 对于这种情况,重新缩放、随机垂直或水平翻转以及[-20,20]度之间的随机旋转被应用于图像及其相应的遮罩。
情况 4: 图像和它们对应的蒙版沿着宽度和高度以因子 0.3 随机移动。
情况 5: 使用因子 20 将透明变换随机应用于图像及其相应的遮罩。它们也在范围[0.2,0.5]之间随机放大。
同一图像及其遮罩上的不同类型的增强(由作者提供)
结果的比较
在所有 5 个案例中,模型被训练了 250 个时期,批次大小为 16。Adam 优化器的学习率为 0.00001,beta 1 为 0.99,beta 2 为 0.99。在下面的图表中,我们可以看到,每个数据扩充案例都为相同的模型提供了不同的性能,这些模型在相同的优化器初始状态下接受了相同数量的时期训练。
训练历史的情节(作者)
基准案例在训练准确性和损失方面表现最佳。然而,这可能意味着过度拟合。另一方面,第三、第四和第五种情况的表现更差。这三种情况的训练准确度没有超过 80%,训练损失没有低于 0.1。这可能意味着不合身。在第二种情况下,数据增强由随机翻转图像及其相应的遮罩组成,这似乎显示了平衡的性能。尽管它的表现比基本情况稍差,但它比最后三种情况具有更高的准确性和更低的损失。
验证历史图(按作者)
验证的准确性和损失,显示了类似的趋势。最后一种情况在这两个指标上表现最差。仔细观察我们会发现,案例 3 和案例 4 在损失方面表现出与训练相似的性能,但验证准确性略高于训练。这表明不合适。对于基本情况,验证损失和准确性比它们的训练对应物差得多,这再次指向过度拟合。虽然我们看到第二种情况的验证准确性和损失波动非常大,但平均来看,它似乎是五种情况中表现最好的。
从这四个图中,我们还可以看到,对于相同数量的时期和相同的优化器初始状态,在训练期间,每个数据增加的情况都收敛在不同的点。这几乎就像 每一个案例都遵循着一条独立的轨迹 。
下表显示了训练和验证的最大准确度和最小损失。该表支持从图表中得出的结论。第二种情况似乎很好地平衡了训练中的过度适应和欠适应。
按作者
对 5 种情况的测试图像的预测
我们在使用 3 幅测试图像的五个案例中的每一个案例中看到了卫星图像中水体的预测分割。再次值得注意的是,使用 5 个不同的数据扩充组合训练的相同模型为每个测试图像预测了 5 个不同的图像。
应注意的是,测试图像在格式方面与基础案例最为相似,因为基础案例没有使用增强。因此,对于所有三个图像,基本情况模型能够分割水体的整体形状。然而,案例 2 也能够捕捉微小的边缘。这证实了我们从图表中得出的结论,即基本情况模型略微超过了训练数据(由于方差最小)。
按作者
情况 3 和 4 的性能随着每个测试图像而变化。情况 5 给出了所有三幅图像(尤其是第二幅和第三幅图像)的最差预测。这可能意味着,为了在这样的数据集上训练该模型,改变绝对强度或放大太多可能会导致糟糕的预测结果。这可以归因于这样一个事实,即模型欠拟合训练数据,一个非常高的方差。
按作者
按作者
最后, 又回到了核心原则——平衡偏差和方差 。虽然数据扩充确实具有显式的正则化效果,但利用它实际上会导致模型学习不足,从而导致预测结果不佳。因此,我们可以看到,有必要尝试不同的数据扩充组合,以找到最适合问题陈述数据集的组合。
完整代码可以在Github上找到!
作为数据科学家平衡理论和实践
推论和发现之间的权衡
照片致谢: Unsplash
理论和实践在人类努力的地图上是一条双行道。许多发现和发明都是偶然和修补的结果,而不是根据基本原理进行的预测和设计。蒸汽机早于热力学定律,空气阻力和帆自古以来就为人所知,但对空气动力学的正式描述出现得要晚得多。
另一个方向也有一些。T4 希格斯玻色子 T5 在被实验观测到之前就被预言了。在爱丁顿的远征之前,广义相对论在很长一段时间内仍然是一个理论。因此,重要的是要认识到这两种方法都是我们寻求知识的重要工具。
机器学习的快速发展归功于这两种方法,但它是 2017 年激烈辩论的主题,一个小组将这个主题比作炼金术,并很快被反驳说:
“将太多精力从尖端技术转移到核心理解可能会减缓创新。
这不是炼金术,这是工程学。工程很乱”
一方认为实践者“操之过急”,而理论家则被批评为“把婴儿和洗澡水一起泼出去”。
根据基本原则构建的领域具有“可解释的失败”的优势——这是生产逐渐可靠的系统所需的关键原则,也是每个工程领域努力的目标。
但是当我们评估不使用它的成本时,实用方法的重要性就凸显出来了。在某些情况下,如果人们坚持要有一个公理化的描述,整个研究领域就不会开始——现代飞机设计的关键贡献者计算流体动力学,为完全依赖尚未解决的千年问题的一面提供了一个典型的例子。
机器学习的中间立场后来被澄清,并开始讨论更好的实践。特别强调了经验评估的标准,无论环境如何,都必须遵循这些标准。
作为一名数据科学家,在执行分析时,有哪些要点[1]需要牢记在心?
- 分享您的调整方法 应该对所有模型(包括基线和共享模型)执行所有关键超参数的调整(使用既定方法)。
- 切片分析 对完整测试集的准确性或曲线下面积(AUC)等性能测量可能会掩盖重要的影响,例如在一个区域质量提高,但在另一个区域质量下降。根据不同维度或不同类别的数据分解绩效指标是全面实证分析的关键部分。
- 消融研究
测试模型架构中的每一个组件从之前的基线单独或组合变化。 - 使用测试分布之外的数据 对模型行为的理解应该由测试分布之外的数据提供信息。例如,对于来自不同人口分布的用户的数据,模型的表现如何?
- 报告负面结果 发现并报告新方法的表现不如先前基线的领域。会有这样一个地区是因为没有免费的午餐。
请注意,任何用于解决现实世界问题的机器学习框架,其核心都是“模型”——区分好的模型已经在这个博客中讨论过了。
非常感谢下面这篇文章开启了这个方向的对话
[1]d .斯卡利,Snoek,j .,Wiltschko,a .,& Rahimi,A. (2018)。赢家的诅咒?关于速度、进度和经验主义的严谨性。
此外,请务必查看以下关于此主题的视频
[2] 深度学习的认识论
[3] 深度学习简介和“炼金术”之争
运动中的机器学习。
快速浏览自动球检测的可用解决方案
🚩 目标
我们希望评估在体育赛事中检测球的最快方法,以便开发一种体育人工智能,而无需在技术或开发人员上花费一百万美元。 我们很快发现,探测球是开发一个健壮的体育 AI 的关键组成部分。
(我不是我团队中的技术人员,这意味着这篇文章中提供的观点不会让你深入了解任何算法或神经网络)。
🚩你为什么要关心?为什么是舞会?
如果你是在人工智能运动利基完全相关 为你 **了解球探的艺术状态,**这个物体永远是任何运动的主要关注中心。如果你能探测到球(即使是在高速下),那么你就能探测到比赛中更容易的关键事件、度量和更多有用的信息。
🚩 玩家呢?
拥有一个成功的体育人工智能是一套出色的计算机视觉检测的结果,现在有许多可用的神经网络擅长检测人体(例如 OpenPose ),所以球员将很容易被检测到,但球却不容易…更不用说在高速下… 这就是为什么我们创建这个帖子来评估最快的球探方法。
仅仅能够探测到球不会带你去那里但是我们相信,使用一个好的球探测器和来自预训练神经网络的真人探测器是最快的开始方式。
简介:跟踪和检测运动物体
正如我们之前所说的检测 和 跟踪移动物体是人工智能在这个领域取得成功和发展的关键任务。运动相当于运动,人和物体以不同的速度和方向运动。
跟踪移动物体并对其进行分析的能力起着至关重要的作用**。对我们来说,开发并教会一个人工智能去观看一场足球比赛并检测比赛中的元素或事件听起来像是一个简单的任务,但实际上非常具有挑战性…**
这里有几个原因
有时,即使是人类也很难理解复杂的体育比赛中发生了什么。看看 2010 年世界杯赛场上发生了多少疯狂的事情。很难注意到苏亚雷斯实际上是用手触球来阻止进球。对加纳来说幸运的是,裁判发现了这一点,并给了他们点球和最后一次晋级半决赛的机会。
- 相机不断地平移、变焦,有时倾斜,有时从一个完全不同的角度回放,我们的大脑非常善于否定这种运动,以至于我们甚至没有注意到它。
- 以不同的速度和不可预测的轨迹向各个方向移动的物体和人的数量
- 背景中混有球员和球,物体和外形几乎相同的人
- 假阳性,游戏外的相同物体(板凳上穿着相同服装的球员,游戏外的运动球与“游戏中”的球相同)
但是我们人类在这项任务中表现出色!
或者迷失在人(球员)和物体(球、网等)的快速且有时无规律的运动中。人工智能很难与人类竞争。
我们开始吧!—我的球探之旅
我的目标是尝试我在谷歌搜索 5 小时内遇到的球探测器让这个实验非常简单,没有人工智能行业的内部观点。
为了做到这一点,我使用了一种**“即插即用”**的方法,我不修改我找到的检测器和神经网络的代码,我只是下载并运行我的本地示例,只做了很小的修改。
我成功地想在下面的视频中跟踪球,当然我的期望不是太高,我意识到球移动得难以置信的快…
让我们看看发生了什么!!
这是我将使用 3 个球检测器选项进行分析的视频。
乌拉圭 vs 加哈纳[2010 年南非世界杯四分之一决赛]
1st — PyImageSearch,OpenCV 球检测器
好得难以置信!我搜索的第一个结果!
📹以 32fps 的速度在 CPU 上运行🤯
✅实时功能。
参考链接源代码:
https://www . pyimagesearch . com/2015/09/14/ball-tracking-with-opencv/
用和 PyImageSearch 进行球检测和跟踪。
这篇 PyImageSearch 文章描述了一种非常简单的检测和跟踪网球的方法:只需在图像上寻找一个绿色区域,然后找到该区域的封闭圆。轻松点。
报告的结果显示,球实际上被很好地跟踪,即使被手部分遮挡,它甚至以 32 FPS 的速度运行,这是非常高的,并允许实时检测。
到目前为止还不错,完全符合我的需求,所以我需要在我的视频上试一试!
这是应用该检测器的结果。
这里做个小澄清: 我们确实把颜色检测器从绿色改成了白色,以便尝试检测足球,因为被设置为绿色。
根本不起作用,它与屏幕上的其他白色物体混淆了,球从未被检测到或跟踪到。
第二个检测器 2(来自脸书的预训练神经网络)
📹在 GPU (Nvidia GTX 1060Ti 6Gb Ram)上以 2 fps 运行,
❌ 非实时能力
参考链接源代码:
https://nol.cs.nctu.edu.tw:234/open-source/TrackNet/
我不拥有这个图像的权利。摘自侦探 2 Github
在第二个选项中,我将尝试实现一个由脸书提供的神经网络,该网络已经用大量对象(包括运动球)进行了预训练。我对“开箱即用”的结果很感兴趣。另外,我想看看它是否能够探测到玩家的身体。
这是应用该检测器的结果:
探测器 2 的结果对球来说不是很好,但对球员来说却很棒。我不拥有这个图像的权利。
球员们都被完美地探测到了。关于球,它在几帧内被探测到但这是我第一次看到它被探测到!
只有静止或缓慢运动时,才能以良好的精度检测到球对象。
我们发现当球处于静止位置时,它能够被探测器 2 检测到,并且具有高置信度得分。
但是这种预先训练的神经网络对于像球这样快速移动的物体有问题。
这让我想到了最后一个实验,一个定制的跟踪器,特别是基于热图解决快速移动的物体这下一个发展是有希望的,因为对网球的近乎完美的检测(这是一个更小的球,移动更快!)
第三轨道网
📹在文档中说明它能够以 22fps 的速度运行!允许实时能力但不是那么正确…
在我的 GPU 上(英伟达 GTX 1060Ti 6Gb Ram) 它以 2 fps 的速度运行…
没有实时能力。
参考链接源代码:
https://nol.cs.nctu.edu.tw:234/open-source/TrackNet/
*这是我跟踪球的最佳选择,尽管探测是在网球上**我相信它可以更容易地探测到一个更大的球,并且永远不会以那么高的速度运行,*但是…
这看起来很适合我们的提议,小网球被完美地检测和跟踪。我不拥有这个图像的权利。摘自 TrackNet Github
应用该检测器的结果:
我错了,结果很糟糕 …尽管与 PyImageSearch 检测器相比,足球的检测有所改进,但帧中有太多的误报…这意味着 TrackNet 即使在根本没有球的情况下也能检测到球…
此外它以 2 fps 运行,而不是文档中提到的 22 fps ,这阻碍了实时分析和检测的可能性。
一个很大的优势是,这个 TrackNet 神经网络在如何用你自己的数据训练方面有很好的文档和建议。这可能是解决足球上的球检测的一个解决方案,但这显然不是一件容易的事情。
如果任何人有足球数据集(真实的和/或合成的),我们有兴趣合作训练这个神经网络或开发一个定制的解决方案,请发送电子邮件到 gcor@eidos.ai
从结果得出的结论
总之,在人工智能运动中,没有“即插即用”的神经网络会把你带到那里,在这个领域没有全局解决方案。这对于那些早期进入这一领域并开发全球解决方案的人来说是一个不可思议的优势。这还没有到来…
但是,即使没有全球解决方案,每个不同的情况都可以用不同的方法来解决,为每个问题创建定制的解决方案。
这就是为什么你需要联系一个团队来开发这种类型的人工智能。
如果你有兴趣与我们合作或建立你的人工智能。
伸手!
我们是一家专注于机器学习,特别是计算机视觉的软件公司,你可以通过 info@eidos.ai 联系我们,我们的网站是https://eidos . ai
敬请关注我们下个月在 medium 上的下一篇文章!
用 OpenCV 和 Tensorflow 实现排球中的球跟踪
运动技术中的计算机视觉和神经网络
介绍
在第一次在运动中应用 AI 的经历之后,我受到了继续下去的启发。家庭练习看起来是一个无关紧要的目标,我的目标是团队合作。
人工智能在体育领域是一个相当新的事物。有几个有趣的作品:
我是个打排球的大粉丝,那就说说最后一个参考吧。这是一个分析当地业余联赛的奥地利机构的网站。
有些文档需要阅读,更重要的是——打开视频数据集。
排球是一项复杂的运动,有许多不同的方面。所以我从一个小但非常重要的东西开始——球。
跟踪球是一项非常著名的任务。谷歌给出了很多链接,但其中许多只是一个演示。显然,在摄像机前识别和跟踪颜色不同的大球无法与真实游戏球检测相比,真实游戏球检测中的球很小,移动很快,并融入背景中。
最后,我们想得到这样的东西:
开始之前,让我们注意一下视频数据集的一些细节:
- 摄像机是静态的,位于球场后面
- 技术水平允许自由看球(职业选手击球太狠,没有电视回放几乎不可能看球)
- 不幸的是,球的颜色,蓝色和黄色,与地面没有太大的对比。这使得所有基于颜色的方法变得毫无意义
解决办法
到目前为止,最明显的方法——用颜色——不起作用,我用了一个事实,球在移动。然后让我们找到移动的物体并捡球,听起来很容易。
OpenCV 包含检测移动物体和背景移除的工具:
mask = backSub.apply(frame)
mask = cv.dilate(mask, None)
mask = cv.GaussianBlur(mask, (15, 15),0)
ret,mask = cv.threshold(mask,0,255,cv.THRESH_BINARY | cv.THRESH_OTSU)
还有这样的图片:
转化为:
在这个例子中,球在顶部,人的大脑和眼睛可以很容易地发现它。我们是怎么决定的?从这幅图中可以推断出一些规律:
- 这个球是一团
- 这是图片上最高的斑点
第二条规则不太管用。例如,在这张图片中,最高的斑点是裁判的肩膀。
但是最高斑点方法为进一步的步骤提供了初始数据。
我们可以收集这些斑点,并训练一个分类器来区分球。
这个数据集看起来像这样:
在人工智能方面——它是彩色图像的二进制分类,非常类似于猫对狗挑战。
有许多方法可以实现,但最流行的方法是用 VGG 神经网络。
一个问题-球图片非常小,多个卷积层不适合在那里。所以我不得不把 VGG 切割成一个非常简单的建筑:
model = Sequential([Convolution2D(32,(3,3), activation='relu', input_shape=input_shape), MaxPooling2D(), Convolution2D(64,(3,3), activation='relu'),
MaxPooling2D(),
Flatten(),
Dense(64, activation='relu'),
Dropout(0.1),
Dense(2, activation='softmax')
])
model.compile(loss="categorical_crossentropy", optimizer=SGD(lr=0.01), metrics=["accuracy"])
这个模型很简单,产生的结果一般:大约 20%的假阳性和大约 30%的假阴性。
这当然比什么都没有强,但还不够。
应用于游戏的模型产生许多假球:
实际上有两种假球:
- 他们在随机的时间出现在随机的地方
- 这个模型总是犯错误,把别的东西当成球
轨道
作为下一步,有一个想法,球不是随机运动,而是遵循抛物线或直线轨迹。
对该几何图形上的斑点运动的验证将切断随机和一致的错误。
有一个在一场球赛中记录轨迹的例子:
其中定向路径用蓝色表示,静态路径用绿色表示,随机路径用灰色表示。
只有蓝色的轨迹才有趣。它们至少由 3 个点组成,并且有一个方向。方向非常重要,因为如果下一个点在实际流中丢失并且没有检测到新的路径,则可以预测下一个点。
应用于片段的这一逻辑生成了非常逼真的跟踪:
链接
利用时空上下文改进体育活动识别
乔治·瓦尔特纳、托马斯·毛特纳和霍斯特·比朔夫
在 Proc。DVS-体育领域计算机科学会议(DVS/GSSS),2014 年
自动化体育游戏分析的室内活动检测与识别
乔治·瓦尔特纳、托马斯·毛特纳和霍斯特·比朔夫
在 Proc。奥地利模式识别协会(AAPR/OAGM)研讨会,2014 年
强盗算法
婴儿机器人强化学习指南
多武装匪徒:第三部分
概观
机器人宝宝在商场走失。利用强化学习,我们想帮助他找到回到妈妈身边的路。然而,在他开始寻找她之前,他需要从一组电源插座充电,每个插座的电量略有不同。
使用多臂强盗问题中的策略,我们需要在最短的时间内找到最好的插座,让机器人宝宝充电上路。
这是关于多重武装匪徒的六集系列的第三集。到目前为止,我们已经介绍了在 Multi-Armed Bandits 中使用的数学框架和术语以及Bandit 框架,其中我们描述了我们试图解决的问题,并给出了我们将用来定义和测试问题环境的基本代码块的细节。
现在我们已经有了合适的术语、符号和测试框架,所有缺少的是一个可以解决强盗问题的实际算法,在给出不同奖励级别的行动之间进行选择,以寻找最佳行动。在接下来的几个部分中,我们将研究几个这样的算法,它们的复杂度越来越高。
为了让我们开始,我们将首先看看解决 Bandit 问题的一些最基本的方法,并检查以下算法:
此外,为了让我们评估解决 Bandit 问题的不同方法,我们将描述 后悔 的概念,其中您将您的算法的性能与理论上最佳的算法的性能进行比较,然后后悔您的方法没有表现得更好一点!
bandit 算法和测试框架的所有代码都可以在 github 上找到: Multi_Armed_Bandits
概述
机器人宝宝进入了一个充电室,里面有 5 个不同的电源插座。每个插座返回的电荷数量略有不同。我们希望在最短的时间内给机器人宝宝充电,所以我们需要找到最好的插座,然后使用它,直到充电完成。
这和多臂强盗问题是一样的,除了我们不是在找一个能给出最好回报的吃角子老虎机,而是在找一个能给出最多电量的电源插座。
贪婪算法
每次我们插入一个插座,我们都会得到一个奖励,以一定数量的电荷的形式,我们得到的每个奖励都可以让我们计算出一个插座的真实输出的更准确的估计。如果我们随后选择具有最高估计值的插座,希望这将是最佳可用插座。
当选择具有最高值的动作时,在时间步’ t 【T3 ')选择的动作可以由公式表示:
其中“ argmax ”指定选择动作“ a ”,其中 Qₜ(a) 被最大化。记住’ Qₜ(a)’ 是动作’ a 在时间步 *'t ',*的估计值,所以我们选择当前估计值最高的动作。
当采用这种方法时,选择具有最高估计值的动作,我们称之为“贪婪地选择”,具有最大值的动作(可能不止一个)称为*“贪婪动作”。*
所有这些听起来像是选择一个好的动作的合理方法,但是有一个主要的缺陷:贪婪算法想要选择具有最佳估计的动作,但是没有提供形成这些估计的方法。它纯粹利用可用的信息,但不做生成这些信息所需的任何探索。
因此,贪婪算法最初是从尚未尝试的动作中进行选择,因此对它们的真实值没有估计。此外,即使选择了一个好的操作,也不能保证这是最好的操作,因为贪婪算法现在已经锁定了所选择的操作,所以不会测试其他操作来确认当前的操作是否是最好的。因此,可以提供更高长期回报的行动将被错过。
乐观贪婪算法
修改贪婪算法的一个非常简单的方法是将初始动作估计值设置为非常高的值,以使其在搜索最优动作时探索可用动作的集合。
在电源插座问题中,如果动作估计被初始化为零,一旦采取一个动作,假设插座返回甚至最小量的电荷,该动作的平均回报将变得大于零。结果,在贪婪算法的眼里,这个动作会比其他所有动作都好,因此会永远是被选中的动作。
相反,如果动作估计被初始化为高于任何可能的套接字输出的值,则当首次尝试套接字时,其平均回报降低。然后,它的估计值低于任何其他值,因此在下一个时间步中不被选择。这导致在第一个’ k ‘时间步中尝试每个套接字(其中’ k 是套接字的数量)。
如果我们实现这个算法,我们就能确切地看到发生了什么:
因此,在上面的代码中,我们从我们在[第 2 部分](http://link to Part 2)中定义的标准 PowerSocket 类中派生出一个新的 OptimisticPowerSocket 。唯一的区别是,现在将套接字奖励值的估计值’ Q ‘初始化为所提供的初始估计值,并且将该套接字被尝试的次数’ n '设置为 1,以考虑初始化。
如果我们将插座估计值初始化为略高于最大可能奖励值的值,那么这将鼓励在早期步骤中进行探索,而不会花费太长时间来发现哪个插座产生最高奖励。
回顾每个插座的奖励分布的小提琴图,最高输出是大约 16 秒的充电。因此,我们选择了值 20,这比最大可能的奖励稍高,并初始化了所有的套接字估计值,如下表所示。
表 1:使用乐观-贪婪算法对 20 个时间步长的插座回报估计。
表 1 显示了在 20 个时间步长上对 5 个插座中的每一个插座的回报估计。黄色高亮显示的单元显示在每个时间步长选择的套接字。需要注意的要点是:
- 最初,所有套接字的估计值都设置为 20。
- 在每个时间步长,使用贪婪算法选择插座,因此选择具有当前最大估计值的插座。当不止一个插座具有最大值时,随机选择其中一个。可以看出,这发生在前四个时间步长(0–3)。
- 在时间步骤 4,只有一个插座仍未测试(插座 4)。因为它的初始估计值仍然是 20,所以它的估计值是所有套接字中最高的,因此被选为贪婪操作。
- 作为初始化的结果,在前 5 个时间步骤中,5 个插座中的每一个都被尝试一次。这推广到标准的 Bandit 问题,其中在第一个“ k 时间步中,每个“ k ”动作将被尝试一次。
- 在接下来的几个时间步骤(5–13)中,可以看到尝试了各种插座。这是该过程的探索阶段,因为该算法搜索具有最高回报的套接字(要采取的最佳行动)。
- 从时间步骤 14 向前,算法已经锁定到插座 4。这是开发阶段,在此期间发现了最佳行动,并且只有这一行动将被采取。
下图显示了相同的结果(尽管这里显示的是前 30 个时间步)。可以看出,对于每个插座,估计的回报如何从初始值 20 开始,然后随着时间的推移而减少。一旦非最佳插座的估计值低于最佳插座的真实值(如图中的黑线所示),则不会再次尝试。在除了最佳插座(插座 4)之外的所有插座都发生这种情况之后,只有它将被选择,并且只有它的估计值将向真实值收敛。非最优行为的回报估计永远不会收敛到它们的真实回报。
图 3.1:电源插座输出的乐观初始化。
从上面的图表可以看出,乐观贪婪算法工作得很好。不需要太长的时间,次优行动就会被丢弃,焦点就会转向最优行动,如果我们想在最短的时间内获得最大的电量,我们就要采取最优行动。
然而,我们的实验有几个问题:
- 首先,我们作弊了!基于我们对套接字输出的了解,我们选择了最初的套接字估计值 20。在现实世界中,在机器人宝宝的例子中,我们可能没有这方面的知识。
- 其次,我们不太擅长作弊!我们选择值 20,因为它略高于我们在查看套接字输出时获得的最高输出(参见上面 violin-plot 中 socket 4 的输出)。然而,事实证明这并不是最好的价值。
看看下面的图,显示了平均总回报和插座选择百分比,是在一系列初始值的 30 个时间步长内获得的。
图 3.2:乐观初始化。
在上面的图中,有几点需要注意:
- 当初始插座值被设置为零时,平均总回报具有大约 8 的值。在这种情况下,实现的是纯粹的贪婪算法。没有探索,只有剥削,所以会随机选择插座。在我们的例子中,平均套接字输出是 4、6、8、10 和 12,所以平均套接字回报是 8。这也可以从插座选择百分比图中看出。在初始化值为零的情况下,以相等的概率选择所有的插座,并且因为有 5 个插座,所以每个插座以 20%的概率被选择。
- 类似地,对于非常大的初始值,平均总回报开始向值 8 下降,这标志着所有插座以相等的概率被选择的点。在这种情况下,从每个套接字返回的奖励比选择的初始值小得多。因此,估计的回报要花更长的时间才能降到接近真实的最大回报。在此期间,每个插座将有近似相等的真实回报的高估。
- 最大平均总奖励不会在初始值为 20 时出现。相反,如下图 3.3 所示,当初始估计值设置为 11 时,实际上会发生这种情况。这也可以在上面的选择概率图中看到,其中,对于初始值 11,选择最佳插座的概率增加到最大值,而同时对于所有其他插座降低到最小值。由于该初始化值大于除了最佳插座奖励之外的所有值,一旦选择了最佳插座,其估计奖励将被设置为高于所有其他值(假设其返回接近其平均奖励值),因此它将被贪婪地选择用于所有剩余的时间步骤。因此,最佳套接字只需要测试一次,使其成为贪婪操作。
图 3.3:乐观初始化——平均总报酬与初始值。
乐观贪婪算法是一种在测试早期鼓励探索的简单方法。最初将尝试所有动作,并且如果使用合适的初始化值,该算法将快速丢弃非最佳动作并聚焦于最佳动作。然而,如上所示,一个选择不当的初始值会导致次优的总回报,如果事先不知道可能的回报范围,就很难选择最佳的初始值。
另一个主要缺点是,探索局限于最初的时间步骤,将其应用限制在 静止 问题上,其中每个行动的回报从不改变。它不适合 非平稳 的情况,在这种情况下,由于缺乏持续的探索,行动奖励会随时间而变化。
ε-贪婪算法(ε-贪婪)
正如我们已经看到的,一个纯粹的贪婪策略有很高的风险选择一个次优插座,然后坚持这个选择。结果就是永远找不到最好的插座。
克服这个问题的一个简单方法是引入探索元素。这正是 Epsilon-Greedy 所做的:
- 默认情况下,行动是贪婪地选择的。具有最高估计奖励的动作是所选择的动作。
- 然而,在每个时间步长,可以从所有可能动作的集合中随机选择一个动作。以概率’ε’(ε)选择随机动作。
以这种方式,探索被添加到标准贪婪算法中。随着时间的推移,每一个行为都将被反复取样,以给出对其真实回报价值越来越准确的估计。
实现ε-贪婪策略的代码如下所示。注意,这改变了 socket tester 类的行为,修改了它在可用套接字之间的选择方式,而不是对实际套接字的改变。
在每个时间步’ select_socket ‘被调用。如果随机值’ p '小于ε,则将选择随机动作,否则将选择具有最高当前估计回报的插座。
查看下图,可以看出 ε 的值如何影响对套接字问题的探索和利用:
图 3.4: Epsilon-Greedy —每次运行 100 个时间步。
- 当 ε 值为零时,这就是贪婪算法。每个插座以相等的概率被选择。没有插座是随机选择的,也没有探索。
- 随着 ε 的增加,行动的随机选择也增加,因此,探索也增加。最初,这导致以增加的频率定位和选择最佳插座。与此同时,非最佳插座开始被较少地选择。
- 最佳插座的选择,以及平均总奖励的相应增加,持续到大约为 0.2 的 ε 值。这一点代表了勘探\开发权衡的顶峰。探索是寻找最好的行动,而开发是选择这个行动。
- 在选择最佳插座的高峰之后,勘探和开发之间的平衡开始向有利于勘探的方向转变。随机选择插座的可能性越来越大。结果,非最佳插座开始被更频繁地选择,因此平均总报酬开始下降。
- 套接字的随机选择继续增加,直到 ε 的值为 1,此时算法已经切换为没有利用的纯探索策略。插座再次被完全随机地选择,并且每个插座以相等的概率被选择,而不考虑其估计的回报。
ε-贪婪策略是在基本贪婪算法中增加探索的一种简单方法。由于行动的随机抽样,所有行动的估计奖励值将收敛于其真实值。这可以从上面显示的最终插座估算图中看出。在 ε 值高于大约 0.2 的情况下,估计的套接字值都与其真实值匹配。这也是 Epsilon-Greedy 算法的缺点:非最优的行动继续被选择,它们的回报估计被改进,即使它们已经被确定为非最优。因此,对最佳行动的利用没有最大化,总的整体回报也低于预期。
遗憾
在插座选择问题中,如果在每个时间步都选择了最好的插座,将获得最大可能的回报。每次选择一个非最佳插座,可以获得的总的可能回报从这个理论上的最大值进一步减少。结果你 后悔 选择了这个插座,反而希望你选择了最好的那个。正如术语后悔所暗示的,你可能无法提前知道你正在做一个非最优的选择,只有在事后你才会意识到你的错误。
尽管您可能无法提前判断是否选择了最佳操作,但您可以计算出您的选择策略与最佳策略相比的表现,在最佳策略中,最佳操作是在每个时间步选择的。这两种政策获得的总回报的差异代表了遗憾。
最佳动作由下式给出:
最佳行动是在每个时间步选择时,最大化预期(平均)回报的行动。
通过在总共’ T ‘个时间步长内,取所实施政策获得的奖励与如果遵循最优政策本应获得的奖励之间的差值,计算遗憾’ L ':
因此,对于所有的’ T '时间步,最优策略获得了在每个时间步采取最优行动时所获得的期望报酬。由此我们减去从我们的策略所选择的行动中返回的预期回报的总和,其中所选择的行动,以及因此它的预期回报,可以在每个时间步长变化。
通过最小化遗憾的价值,我们可以最大化回报的总和。
ε-贪婪的后悔
ε-Greedy 通过以概率’ ε ‘随机选择任何可能的动作来实现探索。因此,在’ T ‘时间步的过程中,行动的’ εT 将被随机选择。
此外,在插座选择问题的一般形式中,有’ k ‘个不同的插座可供选择,其中只有一个会给出最大可能的回报。剩下的’ k-1’ 插座会给出一个次优奖励。结果,存在选择次优插座的’ εT(k-1)/k’ 轮。
如果在选择次优行动的几轮中,我们幸运地选择了第二好的插座,其中奖励与最好的插座相差一个固定的量“δ”(delta),那么这将使我们对ε贪婪的后悔最小。这由下式给出:
对于所有其他非最佳插座,所获得的奖励和最佳奖励之间的差将高于“δ”,因此大于或等于符号,因为在这种情况下遗憾将更大。
由于’ε’,‘δ’和’ k '都是常数,因此ε-Greedy 的结果最低界限遗憾与时间成线性关系( T '将只是乘以一个常数值)。这意味着在找到最佳行动后,遗憾将继续增加。
这可以从下图中看出。在最初的几个时间步骤之后,通过ε贪婪方法获得的总累积奖励线性增加。然而,由于随机探索仍在发生,这一增长率略低于最佳行动积累其回报的速率,导致后悔随时间线性增加。在运行的早期阶段,遗憾的增加率稍高,这是由于还没有找到最佳动作,因此在这些时间步骤中更有可能选择次优插座。
摘要
在这一部分,我们来看看多臂强盗,我们最终研究了一些可以用来解决强盗问题的算法。
纯粹的贪婪算法,除非它有一些可能的行动奖励的初始知识,并不比简单的随机选择方法好多少。然而,通过一些轻微的修改,例如乐观-贪婪使用大的初始值或者ε贪婪引入随机探索的方法,选择性能可以大大提高。
然而,即使有了这些改进,总回报仍然远远低于最佳水平。乐观-贪婪的表现非常依赖于为其初始奖励选择的值,并且 Epsilon Greedy 继续探索所有行动的集合,即使它已经获得足够的知识来知道这些行动中哪些是不好的行动。结果, Epsilon Greedy 算法被证明具有线性后悔,其中返回的奖励和最优奖励之间的差异继续随着时间线性增加。
在本系列的剩余部分中,我们将看看解决 Bandit 问题的几个更复杂的方法,即 置信上限 算法和 Thompson 采样 ,这两种方法都降低了后悔的程度,从而产生了更高的回报水平。使用这些,我们可以在超快的时间内给机器人宝宝充电!
**< Part 2:** [**The Bandit Framework**](/multi-armed-bandits-part-2-5834cb7aba4b) **Part 4:** [**UCB Bandit Algorithm**](/the-upper-confidence-bound-ucb-bandit-algorithm-c05c2bf4c13f) **>**
万隆市公共交通:服务覆盖分析
万隆附近的街道网络(来源:作者,2020;OpenStreetMap 贡献者)
实践教程
万隆市的公共交通服务覆盖怎么样?万隆市的公共交通网络尚未覆盖哪些区域?
介绍
万隆市是印度尼西亚西爪哇省的省会,也有自己的交通问题。一度被认为是印尼最拥堵的城市之一,亚洲第 14(ADB,2019 )。这是令人震惊的,因为预计雅加达是最拥堵的城市,因为雅加达是首都,也因其拥堵而受欢迎,但雅加达是第二名(例如,椰子雅加达(2019) ,D etik (2019) 等等)。万隆市甚至比孟买还糟糕。这让身为万隆市居民的我思考;是什么让拥堵如此严重?我们如何解决拥堵问题?
万隆市 1 天的时空干扰因子(来源:作者分析,2020;底图:OpenStreetMap 贡献者;CARTO 在知识共享署名-相似分享 2.0 许可下获得许可(CC BY-SA 2.0)
好吧,不可避免的解决办法是市民步行,骑自行车,或者根本不旅行。虽然步行和骑自行车限制了旅行者的耐力,但公共交通成为了解决方案。公共交通支持长途旅行,因为它使用石油/另一种能源,因此节省了旅行者的体力。通过共享空间,公共交通使交通更节能,空间效率更高,这也是它被推广的原因。
在这篇文章中,公共交通成为了讨论的主题。对于市民来说,使用公共交通应该是容易和合理的。如上所述,这种通路依赖于人的耐力,而耐力有限,旅行距离也有限。因此,到公共交通的距离应该尽可能地靠近市民。我敢打赌,你不会乘坐公共交通工具进行 7 公里的步行,但如果只是 300 米的步行呢?缩短距离确保了市民步行或骑自行车到公共交通站的低能耗。在我看来,这是公共交通规划的第一要务。于是我想到一个问题:公共交通的距离分布如何?和万隆市哪个区域距离公共交通最远?
通过了解远离公共交通的区域,我们可以规划或建议一条提供公共交通服务的新路线。通过了解距离的分布,我们可以了解公共交通可达性的现状。这种分布可以与其他城市进行比较,甚至可以与人口数据一起进行分析,以进行进一步的相关性分析,但这是另一篇文章的另一个主题。让我们先把注意力集中在简单的问题上。
本文分为六个部分。
- 首先,简介:你现在正在阅读。这一部分解释了本文的背景;
- 二、目标与方法:本文试图达到的目标和实现的途径;
- 三、**关于万隆市:**万隆在哪里,与雅加达的关系以及万隆市公共交通的大致描述;
- 第四,分析:进行分析;
- 五、结论:回答主问题,总结结果;
- 六、建议:下一步做什么解决问题,做改进。
目标和方法
本文的目标是描述万隆市到最近公共交通网络的距离,以及识别离公共交通网络最远的区域(****)。
**主要的地理分析技术是公共交通网络的欧氏距离分析。**该欧几里得距离的结果是连续空间数据(栅格)的形式,因此在统计上可视为间隔/比率数据。与传统/典型统计数据的不同之处在于,它具有空间属性,因此我们可以制作一个关于它的地图。
距离的描述将通过理解由欧几里德距离产生的距离的分布来完成。这将使用直方图分析来完成,我们不需要空间信息。
将使用地图对地理区域标识进行可视化和分析。光栅数据实际上是一幅图像,所以我们可以用一种颜色来显示这些值。为了使官僚机构和政策规划变得具体和实用,我将采用基于最小行政边界单位的分区统计( Kelurahan )。之所以这样做,是因为这种分析产生的栅格的解释性质是模糊的(罗宾逊(2009 ),扎德(1988) )。虽然我必须说,我喜欢模糊地做,因为它清楚地表明它是什么,但要制定一项政策,我们必须明确界限。
此外,上述识别(使用地图)将通过进行 Anselin Local Moran’s I(聚类)分析来完成。进行这种分析是为了确定需要干预的战略区域。这种分析考虑到了地理关系,因此可以推断出空间关系和因果关系。别担心,我不会用数学来烦你的。这种分析的目的只是为了识别集群。
论文框架(来源:作者,2020)
关于万隆市
对于这一部分,我将分为两个小节。第一小节是雅加达和万隆;这解释了万隆和雅加达之间的地理特征和关系。第二分段是**万隆市公共交通;**这是万隆公共交通的简要信息。
雅加达和万隆
的地图爪哇岛的雅加达和万隆建成环境,Landsat 影像的假着色(来源:作者分析,2019;包含来自美国地质调查局 提供的 Landsat-8 图像的修改内容)
万隆市位于印度尼西亚爪哇岛。它是西爪哇省的首府。该市是万隆都市区的核心,包括西万隆县、万隆县和 Cimahi 市。如上图所示,万隆没有雅加达宽。万隆与雅加达的关系多年来一直在加强。连接雅加达和万隆的 Cipularang 收费公路的开发甚至为万隆市带来了更多的交通和投资( Dorodjatoen (2009 ))。下图中的粗线显示了 Cipiularang 收费公路;这条路位于城市的南部。
****万隆市路网图1:275.000 比例尺(来源:作者分析,2020;OpenStreetMap 贡献者许可证(CC BY-SA 2.0)
万隆市公共交通
城市公共交通主要有两种类型:公交网络和小巴网络。小型巴士网络类似于菲律宾的吉普尼。这辆小巴叫“ angkot ”,无处不在。公交网络只是一种在世界任何地方都能找到的典型公交。这辆巴士由一家国有企业 Damri 公司运营。虽然城市间的公共交通是存在的,而且通常由私人公司运营,但这不在本文的主题范围之内。该网络如下图所示。
****图中的图万隆都市区公共交通网络及万隆市行政边界(来源:作者,2020;OpenStreetMap 贡献者许可(CC BY-SA 2.0);路线数据: angkot.web.id
根据经验,万隆系统的一个主要功能是没有公共交通停靠点。你可以在任何地方上船,也可以在任何地方下船,只要你是在线路内上船/下船。公共交通站是有的,但在社会中并没有制度化。
另一种公共交通工具是由 Gojek 和 Grab 提供的出租车和叫车服务(就像优步一样)。打车有它自己的问题,因为政府的政策不承认打车是公共交通。然而,这些非路线基础的公共交通工具不是这个话题的议题。
分析
本节分为两小节:距离分布,和最远距离地理标识**。**
距离分布
使用欧几里德距离,可以生成分辨率为 10 米的栅格。Y 轴表示细胞的频率。所以,下面的 Y 轴图代表了实际面积,如果我们把它乘以 100 平方米。如图所示,平均距离为 387.4 米。这很好,因为空间规划指导部规定,以公交为导向的开发区距离交通设施 800 米。虽然,我们必须注意,387,4 m 是欧几里得的,不是基于网络分析的。这意味着我们假设人们直接飞往交通网络,因此这种分析更多的是一种近似。然而,仍有一些地区的距离超过 800 米。
到最近交通网络的距离直方图(来源:作者的分析,2020 年)
地理标识欧几里得距离
下面这张地图是欧几里德距离分析的结果。这是一幅分辨率为 10 米的栅格图像,其中包含的数字表示到最近交通网络的距离。较暗的单元格表示离最近的蓝线(公共交通网络)较远。最远距离 3918.99 米。
使用欧氏距离的模糊分析(来源:作者分析,2020;路线数据: angkot.web.id
原始欧氏距离栅格是模糊的。没有界限来决定哪个区域高或者低。当然,我们可以将其与前面提到的 800 米 TOD 距离进行比较,但它截断了远距离的统计特性。例如,这将距离为 900 米的区域视为距离为 3,000 公里的区域。对我来说,更合理的方法是识别聚类。识别集群是有帮助的,因为我们可以创建到达集群的新路径。这是合理的,因为通过将网络的一条线添加到一个集群(假设是一个区域),它会影响集群周围的区域。这有效地缩短了距离。
Anselin Moran 的-I 是一种空间统计方法,用于通过了解数据的空间关系来识别聚类。结果是每个地理单元的分类,有 4 类:高-高、高-低、低-高和低-低。高-高意味着该区域的值(或地理单元)被高值区域包围。高低意味着该区域的值被低值区域包围,以此类推。一个地理单元的低/高通过与其他单元进行比较来统计确定。
在这种情况下,有 3 个识别的聚类:高-高、低-低和高-低,如下图所示。有 8 个高-高区域,有 1 个高-低区域。低-低区域意味着该区域周围的距离很短,这很好,但现在这不是本文的兴趣所在。高低点区域是一个距离网络很远的区域,但它被距离很近的区域所包围。现在,在城市的东部有许多高-高区域,我会说:这些(东部)区域在万隆市的公共交通可达性方面是最差的。
距离聚类分析(来源:作者分析,2020;路线数据: angkot.web.id
结论
万隆市被认为是印尼最拥堵的城市(亚行,2019)。为此,公共交通不可避免地必须得到促进。其中一个方法是缩短到公共交通的距离。这样,公共交通的可达性可以得到改善,因为人们更容易步行。本文探讨万隆市与公共交通的距离,本文使用的主要方法是进行欧氏距离分析。
首先,本文从欧氏距离的角度分析了距离的分布。这些区域的平均距离是 387.4 米。这很棒,因为它低于空间规划部 TOD 指南建议的 800 米步行距离。但是,直方图显示,有些区域距离最近的公共交通超过 800 米。
其次,本文制作了两张地图:欧氏距离地图,这是一种模糊分析;和聚类图(使用区域统计和安瑟林·莫兰的 I 到最低行政边界(凯鲁拉汉))来支持政策规划。大多数远离公共交通的地区位于城市的东部。这些东部地区对于即将制定的新公共交通计划具有战略意义。
建议
现在我们知道,城市东部的公共交通可达性很差。在未来,这个问题需要通过规划新的路线来解决。必须咨询当地人,以便更好地规划路线目的地。
这项研究只确定了距离,但有些地区不需要公共交通。例如,作为跑道的机场跑道占用了大量土地。这项研究将机场跑道确定为远离公共交通网络的区域,因此我们需要考虑距离背后的土地利用。也许,这些区域无法进入是有原因的。下一步的研究应该考虑土地利用(或土地覆盖)。
最后,下一次分析需要考虑人口因素。就像土地使用一样,也许,有些地区就是没有居民。尽管这些地区远离公共交通网络,但规划一条通往无人居住的荒凉地区的交通路线是不合理的(以确保商业可行性)。除此之外,还有一些地区发展规划考虑在内。
银行机构定期存款预测模型
循序渐进的方法
在 Unsplash 上由 Carlos Muza 拍摄的照片
感谢 10 学院培训项目,通过参与不同的项目,我了解了许多数据科学概念,每个项目都以自己的方式面临挑战。
银行机构定期存款预测模型是我觉得有意思的一个项目。它的主要目标是建立一个模型,预测客户是否会订阅银行定期存款,本文旨在分享我建立模型的一步一步的方法。
内容
- 数据
- 探索性数据分析
- 数据预处理
- 机器学习模型
- 比较结果
- 预言;预测;预告
- 结论
- 继续教育
数据
此项目中使用的数据集(Bank-additional-full.csv)包含银行客户的数据。数据集及其信息可以在这里获得。执行数据分析的第一步是导入必要的库和数据集。
# importing the necessary libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')#importing the dataset
dataset = pd.read_csv('bank-additional-full.csv', sep=';')
dataset.name = 'dataset'
dataset.head()
作者图片
探索性数据分析
EDA 是机器学习模型开发的重要组成部分,因为它帮助我们理解我们的数据并提取有用的见解,这将有助于特征工程。本项目中执行的一些 EDA 包括但不限于以下内容:
- 数据集的形状和大小
# function to check the shape of a dataset
def data_shape(data):
print(data.name,'shape:',data.shape)# function to check the size of a dataset
def data_size(data):
print(data.name,'size:',data.size)# Getting the shape of the dataset
data_shape(dataset)# Getting the size of the dataset
data_size(dataset)
数据集形状:(41188,21)
数据集大小:864948
。shape 返回数据集的行数和列数。
。size 返回数据中元素的数量,即行数乘以列数。
- 信息和统计汇总
# function to ckeck the information of a dataset
def data_info(data):
print(data.name,'information:')
print('---------------------------------------------')
print(data.info())
print('---------------------------------------------')# Getting the information of the dataset
data_info(dataset)
作者图片
。info() 用于获得数据集的简明摘要。
# Getting the statistical summary
dataset.describe().T
作者图片
。describe() 用于查看一些基本的统计细节,如百分位数、平均值、标准差等。数据集中的数字列。
- 唯一值和缺失值
# function to get all unique values in the categorical variables
def unique_val(data):
cols = data.columns
for i in cols:
if data[i].dtype == 'O':
print('Unique values in',i,'are',data[i].unique())
print('----------------------------------------------')# Getting the unique values in the categorical columns
unique_val(dataset)
作者图片
。unique() 返回数据集分类列中的唯一值。
# function to check for missing values
def missing_val(data):
print('Sum of missing values in', data.name)
print('------------------------------')
print(data.isnull().sum())
print('------------------------------')# Getting the missing values in the dataset
missing_val(dataset)
作者图片
。isnull()。sum() 返回数据集中每一列缺失值的总和。幸运的是,我们的数据集没有缺失值。
- 分类变量和数值变量
# Categorical variables
cat_data = dataset.select_dtypes(exclude='number')
cat_data.head()# Numerical variables
num_data = dataset.select_dtypes(include='number')
num_data.head()
分类变量
数字变量
**。select _ dtypes(exclude = ’ number)**返回所有不具有数值数据类型的列。
**。select _ dtypes(exclude = ’ number)**返回所有具有数字数据类型的列。
- 单变量和双变量分析
我利用 tableau(一种数据可视化工具)进行单变量和双变量分析,tableau 的故事可以在这里找到。
- 相关性
# using heatmap to visualize correlation between the columns
fig_size(20,10)
ax = sns.heatmap(dataset.corr(), annot=True, fmt='.1g',
vmin=-1, vmax=1, center= 0)# setting the parameters
fig_att(ax, "Heatmap correlation between Data Features",
"Features", "Features", 35, 25, "bold")
plt.show()
作者图片
相关性显示数据集中变量之间的关系。
- 异常值
Seaborn boxplot 是检查数据集异常值的方法之一。
# Using boxplot to identify outliers
for col in num_data:
ax = sns.boxplot(num_data[col])
save(f"{col}")
plt.show()
上面的代码将数据集中的数值列可视化,并使用四分位间距(IQR)方法处理检测到的异常值。代码可以在这个 GitHub 库中找到。
在 EDA 过程中,我发现了我们的目标变量“y”——客户是否订阅了定期存款?(二进制:“是”,“否”),是高度不平衡的,这可能会影响我们的预测模型。这一点很快就会被注意到,本文给出了一些处理职业不平衡的技巧。
数据预处理
在构建机器学习模型时,对数据进行预处理以获得高效的模型是很重要的。
# create list containing categorical columns
cat_cols = ['job', 'marital', 'education', 'default', 'housing',
'loan', 'contact', 'month', 'day_of_week', 'poutcome']# create list containing numerical columns
num_cols = ['duration', 'campaign', 'emp.var.rate',"pdays","age", 'cons.price.idx', 'cons.conf.idx', 'euribor3m', 'nr.employed', 'previous']
在此阶段完成了以下预处理:
- 编码分类列
机器学习算法只读取数值,这就是为什么我们需要将分类值改为数值。我使用 pandas get_dummies 方法和类型转换对列进行一次性编码。
# function to encode categorical columns
def encode(data):
cat_var_enc = pd.get_dummies(data[cat_cols], drop_first=False)
return cat_var_enc# defining output variable for classification
dataset_new['subscribed'] = (dataset_new.y == 'yes').astype('int')
作者图片
- 重新调整数值列
另一种数据预处理方法是重新调整我们的数字列;这有助于在特定范围内使我们的数据正常化。这里使用了 Sklearn 预处理 StandardScaler()。
# import library for rescaling
from sklearn.preprocessing import StandardScaler# function to rescale numerical columns
def rescale(data):
# creating an instance of the scaler object
scaler = StandardScaler()
data[num_cols] = scaler.fit_transform(data[num_cols])
return data
作者图片
- 指定因变量和自变量
为了继续建立我们的预测模型,我们必须指定我们的因变量和自变量。
独立变量—是被分析过程的输入。
因变量—因变量是流程的输出。
X = data.drop(columns=[ "subscribed", 'duration'])
y = data["subscribed"]
列“duration”已被删除,因为它对输出目标有很大影响(例如,如果 duration=0,则 y =“no”)。
- 分割数据集
在构建机器学习模型时,总是将数据集分为训练集和测试集是合理的,因为这有助于我们评估模型的性能。
# import library for splitting dataset
from sklearn.model_selection import train_test_split# split the data
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size = 0.1,random_state=1)
- 降维
在我们有大量变量的情况下,建议考虑通过保留最重要的变量来减少这些变量,有各种技术可以做到这一点,例如:主成分分析、TSNE、自动编码器等。对于这个项目,我们将考虑 PCA。
# import PCA
from sklearn.decomposition import PCA# create an instance of pca
pca = PCA(n_components=20) # fit pca to our data
pca.fit(X_train)
pca_train = pca.transform(X_train)
X_train_reduced = pd.DataFrame(pca_train)
作者图片
- 阶层失衡
如前所述,我们有一个高度不平衡的阶层,如果不加以处理,这会影响我们的预测。
作者图片
在这个项目中,我利用 SMOTE(合成少数过采样技术)来处理类不平衡。
# importing the necessary function
from imblearn.over_sampling import SMOTE# creating an instance
sm = SMOTE(random_state=27)# applying it to the training set
X_train_smote, y_train_smote = sm.fit_sample(X_train_reduced, y_train)
**注意:**对训练数据使用 SMOTE 为宜。
机器学习模型
咻!,我们终于成功地建立了模型;当试图建立机器学习模型时,数据预处理可能是如此困难。我们不要浪费时间,直接开始吧。
本项目中考虑的机器学习算法包括:
- 逻辑回归
- XGBoost
- 多层感知器
所使用的交叉验证(这是非常重要的,尤其是在我们有不平衡类的情况下)方法包括:
- K-Fold: K-Fold 将给定的数据集分割成 K 个部分/折叠,其中每个折叠在某个点被用作测试集。
- 分层 K-Fold: 这是返回分层褶皱的 K-Fold 的变体。折叠是通过保留每个类别的样本百分比来完成的。
# import machine learning model libraries
from sklearn.linear_model import LogisticRegression
from xgboost import XGBClassifier
from sklearn.neural_network import MLPClassifier# import libraries for cross validation
from sklearn.model_selection import KFold
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validatemetrics = ['accuracy', 'roc_auc', f1', 'precision', 'recall']# function to build machine learning models
def model(model, cv_method, metrics, X_train, X_test, y_train):
if (model == 'LR'):
# creating an instance of the regression
model_inst = LogisticRegression()
print('Logistic Regression\n----------------------')
elif (model == 'XGB'):
# creating an instance of the classifier
model_inst = XGBClassifier()
print('XGBoost\n----------------------')
elif (model == 'MLP'):
# creating an instance of the classifier
model_inst = MLPClassifier()
print('Multi Layer Perceptron\n----------------------')
# cross validation
if (cv_method == 'KFold'):
print('Cross validation: KFold\n--------------------------')
cv = KFold(n_splits=10, random_state=100)
elif (cv_method == 'StratifiedKFold'):
print('Cross validation: StratifiedKFold\n-----------------')
cv = StratifiedKFold(n_splits=10, random_state=100)
else:
print('Cross validation method not found!')
try:
cv_scores = cross_validate(model_inst, X_train, y_train,
cv=cv, scoring=metrics)
# displaying evaluation metric scores
cv_metric = cv_scores.keys()
for metric in cv_metric:
mean_score = cv_scores[metric].mean()*100
print(metric+':', '%.2f%%' % mean_score)
print('')
except:
metrics = ['accuracy', 'f1', 'precision', 'recall']
cv_scores = cross_validate(model_inst, X_train, y_train,
cv=cv, scoring=metrics)
# displaying evaluation metric scores
cv_metric = cv_scores.keys()
for metric in cv_metric:
mean_score = cv_scores[metric].mean()*100
print(metric+':', '%.2f%%' % mean_score)
print('') return model_inst
评估指标
- **精度:**正确预测的数据点个数。对于不平衡的数据集,这可能是一个误导性的指标。因此,建议考虑其他评估指标。
- AUC(ROC 曲线下的面积):它提供了对所有可能的分类阈值的综合性能测量。
- **精度:**计算为正确预测的正例数除以预测的正例总数的比率。
- **召回:**指被你的算法正确分类的相关结果总数的百分比。
- **F1 评分:**这是准确率和召回率的加权平均值。
k 倍交叉验证评估指标
分层 K 倍评估指标
比较结果
- K 线折叠 vs 层状 k 线折叠
从上表中可以看出,与 K 倍交叉验证相比,分层 K 倍验证呈现出更好的结果。K 倍交叉验证未能提供逻辑回归和 XGBoost 模型的 AUC 评分。因此,为了进一步比较,将使用分层的 K 倍结果。
- 机器学习模型
从得到的结果来看,XGBoost 被证明是比逻辑回归和 MLP 更好的预测模型,因为它在 4/5 的评价指标中具有最高的百分比值。
预言;预测;预告
XGboost 是性能最好的模型,用于预测。
# fitting the model to the train data
model_xgb = xgb.fit(X_train_smote, y_train_smote)# make predictions
y_pred = xgb.predict(X_test_pca)
结论
这个项目的主要目标是建立一个模型来预测将订阅银行定期存款的客户,我们通过考虑三个不同的模型并使用最佳模型来进行预测,从而实现了这一目标。我们还经历了为模型准备数据和选择各种评估指标来衡量模型性能的严格步骤。
在得到的结果中,我们观察到 XGBoost 是最好的模型,在 4/5 的评估指标中有很高的百分比值。
深造
在这个项目中,我只用了三种机器学习算法。然而,算法如;SVM、随机森林、决策树等。可以探索。
这个项目的详细代码可以在这个 GitHub 库中找到。
我知道这是一个很长的旅程,但谢谢你陪我到最后。我也再次感谢学院和我的同学们给了我参与这个项目的绝佳机会。