我试图用机器学习来预测比特币的价格
使用时间序列模型预测加密货币价格
Photo by André François McKenzie on Unsplash
更新:点击下方查看下一篇描述用深度学习预测比特币价格过程的文章
利用神经网络预测加密货币价格
towardsdatascience.com](/predicting-bitcoin-prices-with-deep-learning-438bc3cf9a6f)
预测未来不是一件容易的事。许多人尝试过,许多人失败了。但是我们中的许多人都想知道接下来会发生什么,并竭尽全力去弄清楚。想象一下知道未来会发生什么的可能性!想象一下,回到 2012 年,当比特币不到 15 美元,知道它将超过 18000 美元时,你会怎么做!许多人可能会后悔当时没有购买比特币,但他们一开始怎么会知道呢?这是我们现在在加密货币方面面临的困境。我们不想错过下一次价格上涨,但我们不知道这何时会发生或不会发生。那么,我们怎样才能潜在地解决这个困境呢?也许机器学习可以告诉我们答案。
机器学习模型可能会给我们提供了解加密货币未来所需的洞察力。它不会告诉我们未来,但它可能会告诉我们价格移动的一般趋势和方向。让我们尝试使用这些机器学习模型,并通过用 Python 编码来预测比特币的未来!
建模时间序列
我们要实现的机器学习模型叫做 时间序列 模型 。这些模型将研究过去,寻找预测未来的模式和趋势。如果没有这些模型,我们将不得不自己做所有这些分析,这将花费太多的时间。幸运的是,我们可以用 Python 编写这些时间序列模型来为我们做所有的工作,这就是我们今天要做的!
我们今天要用的时间序列模型有: 萨里玛 和一个由 脸书先知 实现的加法模型。萨里玛或 ARIMA 是一个相对基本的时间序列模型,我们将在必要时对其进行编码和解释。脸书 Prophet 使用一种快速可调的加法模型来预测时间序列数据。建模后,我们将比较每个模型对比特币未来的独特见解。
对 SARIMA 建模的步骤如下:
- 收集、探索和可视化数据。
- 对数据求差并检查平稳性。
- 绘制差异数据的 ACF 和 PACF。
- 通过搜索最佳参数开始建模。
- 用优化的参数训练和测试模型。
- 预测未来!
这些描述非常简单明了,但我们很快会更详细地介绍每个步骤。以下代码片段摘自文末分享的 Github。
比特币价格数据
我们要做的第一件事是检索比特币的历史数据,这些数据可以从雅虎财经下载为一个方便的 CSV 文件。一旦我们有了这些,我们就可以开始将 CSV 文件格式化为一个熊猫数据帧。然后,我们使用相同的数据帧进行其余的绘图和计算。
另一种选择是使用财务数据 API,如 EOD 历史数据 。注册是免费的,你可以获得大量的金融数据。披露:我通过上面的链接从任何购买中赚取一小笔佣金。
Formatting/Organizing the Dataset
接下来,我们绘制数据图表,看看过去两年比特币的价格走势。选择过去两年是因为比特币和加密货币总体上变得非常受欢迎,并且更好地代表了当前的市场趋势。
平稳性
让我们通过使数据静止来为建模准备数据。我们通过简单地对数据进行差分并使用所谓的 迪基-富勒测试 来测试平稳性。我们的目标是使 P 值小于临界值 5%,或者只是尽可能接近零。对于更低的 P 值,我们取价格的对数,然后求对数的差,而不仅仅是求价格的差。
This gives a P-Value of 5.879487529183016e-25
你可能想知道为什么我们关心平稳性。简而言之,平稳性从数据集中移除趋势,这可能会极大地干扰我们的模型。基本上,平稳性使我们的模型表现和预测更好。
Our stationary differenced log of BTC.
ACF 和 PACF
接下来,我们必须绘制出自相关函数(ACF) 和部分自相关函数(PACF) 。由于我们处理的是每日数据,ACF 向我们展示了过去的哪一天与当前日期的相关性最大。PACF 通过忽略中间的日子,向我们展示了过去的哪一天与今天直接相关。
The ACF and PACF for the Log of BTC
萨里玛造型
通过了解 PACF 和 ACF,我们现在可以更好地理解我们的数据集和可能选择的参数。现在,我们可以继续使用 SARIMA 模型来建模我们的数据。
优化参数
为了获得模型的最佳性能,我们必须找到最佳参数。我们通过尝试许多不同的参数组合并选择具有相对最低的 AIC 分数 的组合来实现这一点。别担心,我们已经写了一个函数来完成这个任务。
According to this function, our best parameters are (1,0,0) for pdq and (0,0,0,0) for pdqs
根据您的电脑,寻找最佳参数的过程可能需要一段时间。对于像我们这样的人来说,我们将不得不满足于受计算机规格限制的最佳参数。不幸的是,并不是所有的计算机都是一样的,有些型号会根据运行它们的计算机而表现得更好。
装配和培训
现在我们有了参数,让我们继续训练并使模型适合比特币的价格。
为了进一步测试该模型的性能,我们可以通过绘制它们来看看它的预测与我们已经知道的值是如何一致的。
模型测试还可以,因为实际值仍然在我们的置信区间内(灰色阴影部分),价格也如预测的那样上涨。其余的训练数据似乎很好地符合我们的区间(绿色阴影),并与模型的预测值一致。
预测未来价格
现在我们可以进入我们真正想知道的部分了——预测比特币的未来价格!我们通过对今天的预测来做到这一点,并观察它在未来可能的走向。
General forecast of BTC
我们可能需要仔细看看。。。
根据该模型,比特币似乎将在未来一个月继续小幅上涨。但是,不要把这当成事实。阴影区域向我们展示了比特币价格在未来一个月的潜在走向,但它也碰巧显示了比特币可能会下跌。虽然,模型似乎在向价格上升而不是下降倾斜。
萨里玛的预测不应该是唯一需要考虑的预测。还有其他时间序列模型和程序需要考虑,其中一个实际上是由脸书的数据科学团队创建的!
脸书先知
使用脸书先知将比使用萨里玛建模相对容易。这是由于 FB Prophet 的简单易用。你将会看到与萨里玛相比,这要容易得多。
使用脸书先知的步骤是:
- 为 Prophet 格式化数据。
- 根据数据拟合和训练模型。
- 创建要预测的未来日期。
- 预测和想象未来!
下面是对脸书先知使用上述步骤的代码:
脸书先知崩溃
在第一步中,我们通过为日期和价格创建两列来格式化之前的数据。然后,我们可以通过拟合和训练数据直接进入建模!无需调整参数或检查稳定性!
建模之后,我们现在可以前进到预测未来,首先创建我们希望 Prophet 为我们预测价格的未来日期。我们还可以绘制这些日期,这也将向我们展示模型如何与过去的价值相比较,以及价格接下来可能会走向哪里。
放大以近距离观察未来预测。。。
FB Prophet zoomed in
- 蓝线=预测值
- 黑点=观察值(实际值)
- 蓝色阴影区域=不确定性区间
据 FB Prophet 报道,比特币将在未来一个月内上涨。但还是那句话,这不是事实。相比萨里玛,FB Prophet 有更清晰的预测和方向。FB Prophet 有更多的特性和参数可以实验,但是我们在这里没有一一介绍。如果你觉得你需要改变模型,然后点击这里FB Prophet 的文件。
结束语
现在我们对比特币的未来有了两种预测,请随意对两者做出自己独特的观察,以确定比特币的未来。除了 SARIMA 和 FB Prophet,还有更多时间序列模型可以学习和实验。不要觉得仅限于这两个!我们刚刚做了时间序列、建模和机器学习的简要概述。还有更多的话题可以覆盖和研究!
预测比特币的未来几乎是不可能的,但通过机器学习,我们可以高度自信地理解它可能会走向何方。我们不建议使用这些机器学习模型来做出所有的投资决策,但很高兴看到比特币和加密货币的未来可能会发生什么!
资源:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/marcosan93/BTC-Forecaster) [## 我尝试了深度学习模型来预测比特币价格
towardsdatascience.com](/predicting-bitcoin-prices-with-deep-learning-438bc3cf9a6f)
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
用机器学习预测衰退
收益率曲线反转真正告诉我们什么
“这是最好的时代,这是最坏的时代,这是智慧的时代,这是愚蠢的时代,这是信仰的时代,这是怀疑的时代,”
这是一部经典文学作品的开场白,它在两个半世纪前的今天同样适用。在《双城记》中,查尔斯·狄更斯描述了法国大革命时期字面意义和隐喻意义的对立。虽然没有那么极端,但我们可以从它的段落中找到与当前环境的相似之处;当我们看到股市飙升至历史高点,收益率跌至历史低点时,全球经济的经济基本面仍然受到顽固的抑制。
众所周知,为了应对大衰退(GFC ),世界各地的中央银行同步向市场提供流动性,希望重新点燃增长和通胀。然而,这几乎是真正的狄更斯式的风格,对刺激工资增长和消费几乎没有什么作用。相反,较低的利率只会将资产推高到前所未有的估值水平,这对资产所有者非常有利,但却让普通人懊恼不已。简言之,富人变得更富了。
经济和定价的潜在驱动因素之间的这种错位,揭示了一种深刻而反常的动态绑定货币政策和市场预期。市场已经开始预期央行会继续放松货币政策,事实上,即使是也需要放松货币政策,以保持同样的上升势头。任何挑战这一共识的信息都引起了强烈的负面膝跳反应。值得注意的是,两周前,美联储十年来首次降息,这在理论上正是保持积极表现所需要的,但是降息的幅度(小于最初的预期)和鲍威尔主席的会后评论不利于持续的资产通胀叙事。因此,冒险行为会受到惩罚。
更近的是发生了收益率曲线反转现象。在过去 7 次美国经济衰退之前,两年期和十年期美国国债收益率之间被广泛关注的利差已被视为负值,导致许多市场评论员和从业者密切关注这一数据点作为领先指标。许多人已经注意到,经济逆转和衰退之间的历史时滞可能从几个月到近两年不等。作为注重数据的观察者,这为我们的调查奠定了完美的基础;鉴于市场对这一指标的持续和不相称的关注, 我们可以通过仅使用 10 年期和 2 年期美国国债之间的利差来实现机器学习以预测美国经济衰退吗?
设置
Photo by Todd Quackenbush on Unsplash
技术性衰退被定义为连续两个季度的负增长(GDP),因此我们可以从圣路易斯联邦研究经济数据库 这里 **获得符合这一描述的日期。**该时间序列采用二进制形式,1 表示衰退期,0 表示衰退期。
Source: St Louis Fed, Hamilton, James
接下来我们从同一个数据库 这里 **获取收益率曲线利差数据。**计算方法为月末 10 年期国债收益率减去 2 年期国债收益率。
Source: St Louis Fed
我们选择的机器学习工具是 逻辑回归 ,这是经济学家和数据科学家都喜欢的工具。我们使用这种特殊算法有三个原因:
- 该模型相对简单且易于理解,
- 该分析相对简单且本质上是单变量的,
- 市场修辞暗示了曲线反转和衰退之间的线性决策边界。
由于美国 GDP 数据的季度报告频率,需要进行两项调整:
- 我们将衰退数据集从季度数据集扩展到月度数据集,方法是隐含假设衰退季度内所有月份的增长都是负的。
- 我们将收益率曲线利差数据后移四分之一,这是必要的,因为我们对 2y 和 10y 利差的预测能力感兴趣,在其原始形式中,两个数据点**同时出现。**使用一个数据点来预测同时可用的另一个数据点是一项毫无意义的任务。
结果
借助广义线性模型(glm)函数和 R 中的 Caret 包,我们将时间序列分成 70%的训练集和 30%的测试集。我们在训练集上拟合了 logit 模型,并根据测试进行了验证,结果如下:
Evaluation Metrics
预测精度简直太棒了! 87% !收益率曲线反转肯定是衰退的一个很好的预测指标!但是,等等,这里有些不对劲,让我们仔细看看评估指标。虽然准确率很高,但流行率、灵敏度和检出率都低得惊人。对混淆矩阵的检查可以提供一些额外的见解。
Confusion Matrix
我们可以立即看到,该模型非常擅长预测真正的否定(130 个正确预测),坦率地说,其他方面并不多。这说明了这个特定数据集的一个重要问题。虽然有数百个非逆转/非衰退的例子,但逆转/衰退的例子要少得多。这实际上是一个非常不平衡的数据集,如果我们预测测试集中的每一个实例都是非衰退的,我们仍然可以得到 85%的准确率。如果我们在评估指标中查看平衡的准确率(调整了不平衡),我们会发现该模型比掷硬币好不了多少(58%)。这似乎与评论和新闻会让我们相信的相矛盾,那么,收益率曲线反转到底告诉了我们什么?
结论
虽然收益率曲线的期限结构中有关于经济增长前景的信息,这得到了大量学术文献和理论的支持(见 FRB 文章 此处 和 Ang,Piazzesi and Wei,2003 ),但我们不应通过孤立地查看一个数据点来设计错误的精确度。经济作为一系列不断相互作用的运动部分而存在,因此需要被视为一个整体。与未来前景同样相关的是通胀机制和货币政策方向。仅使用曲线反转作为衰退的预测指标,是一个精选数据来拟合预先构建的描述的典型例子。这种类型的行为偏见并非没有先例,诺贝尔奖获得者丹尼尔·卡内曼和阿莫斯·特沃斯基推测,当面临不确定性时,人类会求助于启发法/经验法则来帮助我们做出决定。虽然我们都只是人类,但我们仍然有独特的能力使用机器学习等定量工具来客观验证未经证实的说法,如果有机会,我们应该行使这一权利。虽然没有提供代码,但如果有兴趣的话,我很乐意在另一篇文章中用 R 代码完整地讨论这种方法。
参考文献
安,皮亚泽西,米和魏,米(2003)。关于 GDP 增长,收益率曲线告诉了我们什么?。 SSRN 电子杂志。
免责声明:本帖纯属个人观点和看法的表达。它不代表任何建议,也不反映我的雇主的观点。
使用 Fastai 预测房地产图像中的丰富属性
大卫·塞缪尔和纳文·库马尔
概观
视觉属性搜索可以极大的提升用户体验,针对家居房源和旅游网站的 SEO。尽管 Zillow、Redfin、Airbnb 和猫途鹰已经有了一些关于房产设施的元数据,但他们可以通过用视觉模型分析房产图像来扩展可搜索的属性。
在本帖中,我们分享了我们对预测房产属性(如景观、厨房岛、游泳池、高天花板、硬木地板、壁炉等)的几个镜头模型的初步方法。由于这些属性通常依赖于房间和环境,我们从一个精确的分类模型开始,将我们的图像分组到酒店的内部和外部设置中。
在训练我们最初的房间类型模型的过程中,我们注意到这些丰富的属性中的一些很容易在 platform.ai 中分离。
背景
以前的工作集中在使用图像来改善价格估计[1],但是将图像特征添加到定价模型的增量收益很小;与使用一些传统属性(如位置和物业大小)相比,性能提高了 2.3%。虽然构建这些模型的价格数据已经很容易获得,但预测丰富属性(如景观、厨房岛、游泳池、高天花板、硬木地板、壁炉等)的数据集却很稀缺。
我们的初始数据集,以前用于价格估算[1],由 146,791 张图片和七个类别组成:客厅、餐厅、卧室、浴室、厨房、室内和室外。
Fig 1. Class count of real estate images
浴室是最缺乏代表性的一个类别,其图片数量比任何其他类别都少近一半。我们使用 fastai 的 vision.transform 方法【4】解决了这种类别不平衡,使用默认图像增强对数据进行过采样。
Fig 2. Example image augmentation of the classes: bathroom, dining room, kitchen, living room, bedroom, interior, and exterior.
这些图像是使用 fast.ai 的内置变换进行预处理的。数据被随机分成 60%训练、20%验证和 20%测试。
该模型用 ImageNet-ResNet34 权重初始化。网络的定制头被训练 3 个时期,随后解冻整个网络,并使用区别性学习速率微调另外 10 个时期。微调提高了模型拟合度,实现了 97%的总体测试集精度。
通过将网络容量增加到 ResNet50,实现了 98%的最终准确性——比之前结果的 91%准确性有了显著提高[1]。
构建丰富的属性数据集
我们通过抓取房产列表网站构建了一个丰富的属性数据集。爬行器捕获了图像和感兴趣的属性。总共获得了 18,790 个列表和 350,000 张图片。
要素类分布
我们的 web scraper 捕获了非结构化的 html,并提取了清单的 details 表中包含的丰富属性。
Fig 3. Example scraped listing text metadata
Figure 4. Feature class distribution from crawled data
最终的数据集由 18,790 个单独的列表组成,每个列表平均包含 21 张图片。我们已经确定了照片中可见的几个特征,如水池、天井、厨房岛和壁炉。在我们的数据集中,近一半的房源有游泳池或露台,只有大约 25 个房源有酒窖。此外,可以在不同的空间中看到属性的外观;现代酒窖倾向于在地面上。
Fig 5a. Example feature from listings dataset: wine cellar
Fig 5b. Example feature from listings dataset: wine cellar
Fig 5c. Example feature from listings dataset: wine cellar
Fig 5d. Example feature from listings dataset: wine cellar
预测
我们将我们的模型和来自我们数据集的 20,000 张图像的样本上传到 platform.ai ,以便将其性能与预先构建的 ImageNet 模型进行比较。我们的模型形成了整齐的集群,很容易用眼睛分开,具有相似的兴趣属性,如壁炉、水池和厨房岛。相比之下,ImageNet 倾向于形成具有不同属性的更宽的集群。
Fig 6. Pictured: Our Model’s Projection
Fig 7. Pictured: ImageNet Projection
Fig 8. Zoomed in projections show a fireplace cluster.
Fig 9. Zoomed in projections show a kitchen islands cluster.
Fig 10. Zoomed in Projections, and selected images from our model show an outdoor swimming pool cluster.
使用投影作为视觉辅助,感兴趣的集群被突出显示,并使用 platform.ai 选择性地过滤。我们的模型投影的放大视图显示了我们通过模型识别的三个丰富的特征:壁炉、厨房岛和游泳池。与 ImageNet 相比,我们可以看到更多与丰富属性紧密相关的群集,而不是标记的房间类别功能。
聚类分析
下载我们的投影后,我们能够评估一个聚类解决方案,将我们的模型的轮廓分数与 ImageNet 进行比较。结果表明,我们的侧影得分明显大于 ImageNet 在 K = 5k-均值聚类侧影得分上的 t-检验结果。因此,我们的模型比 ImageNet-ResNet 更一致地产生相似的聚类。
Fig 9. Similarity “Silhouette” scores for k=5 K-Means clusters.
Table I. Silhouette Score summary statistics
结论
应用现代机器学习实践,我们开发了一个计算机视觉模型,它不仅可以预测房间类别,还可以预测我们居住的房屋的深层属性。通过将我们的嵌套属性更紧密地聚集在一起,它比 ImageNet 表现得更好,允许视觉上可分离的组被提取和标记。开发一个精确的属性搜索模型可以作为一个重要的搜索工具来找到合适的房屋或出租。
我们计划进一步开发我们的模型,使用来自我们数据集的有限标记数据和关系网络(RN) [2]来分类图像中的多个属性。
承认
我们要感谢 Arshak Navruzyan 在这个项目中给予的支持和指导。我们还要感谢 fastai 团队提供了一个方便的深度学习库。
参考
- Poursaeed,Omid 等基于视觉的房地产价格估算。机器视觉与应用 29(2018):667–676。
- 桑托罗、亚当等人一个用于关系推理的简单神经网络模块。NIPS (2017 年)。
- 何,等.【深度残差学习用于图像识别】。2016 年 IEEE 计算机视觉和模式识别大会(CVPR)(2016):770–778。
- 霍华德、杰瑞米等人法斯泰图书馆。2019.
- Clarke,Adrian 等人在 fastai 中优化图像数据集的超参数。2019
预测销售额
使用 Python 实现数据驱动的增长
与 LSTM 一起预测月销售额
这一系列文章旨在解释如何以一种简单的方式使用 Python,通过将预测方法应用于您的所有行动来推动您公司的发展。它将是编程、数据分析和机器学习的结合。
我将在以下九篇文章中讨论所有主题:
1- 了解你的衡量标准
2- 客户细分
3- 客户终身价值预测
4- 流失预测
6- 预测销售额
文章将有自己的代码片段,使您可以轻松地应用它们。如果你是编程的超级新手,你可以在这里很好地介绍一下 Python 和 Pandas (一个我们将在任何事情上使用的著名库)。但是仍然没有编码介绍,您可以学习概念,如何使用您的数据并开始从中产生价值:
有时候你得先跑,然后才能走——托尼·斯塔克
作为先决条件,确保你的电脑上安装了 J upyter Notebook 和 P ython 。代码片段只能在 Jupyter 笔记本上运行。
好吧,我们开始吧。
第 6 部分:预测销售额
在本节之前,我们几乎所有的预测模型都是基于客户层面的(例如,流失预测、下一个购买日等)。).缩小视野,看看更广阔的图景也是有用的。通过考虑我们在客户方面的所有努力,我们如何影响销售?
时间序列预测是机器学习的主要组成部分之一。文献中有许多方法可以实现这一点,如自回归综合移动平均(ARIMA)、季节自回归综合移动平均(SARIMA)、向量自回归(VAR)等。
在本文中,我们将重点关注长短期记忆(LSTM)方法,如果你想使用深度学习,这是一种非常流行的方法。我们将在我们的项目中使用 Keras 来实现 LSTM。
最后,了解未来销售对我们的业务有什么帮助?
首先,它是一个标杆。如果我们的战略没有任何变化,我们可以将它作为我们将要实现的业务照常水平。此外,我们可以在这个基准之上计算我们新行动的增量价值。
第二,它可以用于规划。我们可以通过查看预测来计划我们的需求和供应行动。这有助于了解在哪些方面投资更多。
最后但同样重要的是,它是一个规划预算和目标的优秀指南。
现在是时候跳入编码,建立我们的第一个深度学习模型了。我们模型的实施将有 3 个步骤:
- 数据争论
- 数据转换,使其稳定并受到监督
- 建立 LSTM 模型和评估
数据争论
在这个例子中,我们使用来自 Kaggle 竞赛的数据集。它表示每个商店和商品的每日销售额。
像往常一样,我们从导入所需的库和从 CSV 导入数据开始:
我们的数据如下所示:
我们的任务是预测每月的总销售额。我们需要按月汇总我们的数据,并对销售列求和。
#represent month in date field as its first day
df_sales['date'] = df_sales['date'].dt.year.astype('str') + '-' + df_sales['date'].dt.month.astype('str') + '-01'
df_sales['date'] = pd.to_datetime(df_sales['date'])#groupby date and sum the sales
df_sales = df_sales.groupby('date').sales.sum().reset_index()
应用上面的代码后, df_sales 现在显示了我们需要的总销售额:
数据转换
为了更容易、更准确地模拟我们的预测,我们将进行以下转换:
- 如果不是,我们将把数据转换成静态的
- 从时间序列转换为受监督的,以获得我们的 LSTM 模型的特征集
- 缩放数据
首先,我们如何检查数据是否不稳定?让我们画出来看看:
#plot monthly sales
plot_data = [
go.Scatter(
x=df_sales['date'],
y=df_sales['sales'],
)
]plot_layout = go.Layout(
title='Montly Sales'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
月度销售图表:
Monthly Sales — not stationary
显然,它不是静止不变的,在几个月内有增加的趋势。一种方法是获得与前一个月相比的销售差额,并在此基础上建立模型:
#create a new dataframe to model the difference
df_diff = df_sales.copy()#add previous sales to the next row
df_diff['prev_sales'] = df_diff['sales'].shift(1)#drop the null values and calculate the difference
df_diff = df_diff.dropna()
df_diff['diff'] = (df_diff['sales'] - df_diff['prev_sales'])df_diff.head(10)
现在我们有了建模差异所需的数据框架:
让我们画出它并检查它现在是否是静止的:
#plot sales diff
plot_data = [
go.Scatter(
x=df_diff['date'],
y=df_diff['diff'],
)
]plot_layout = go.Layout(
title='Montly Sales Diff'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
Monthly Sales Difference — stationary
完美!现在我们可以开始构建我们的特性集了。我们需要用以前的月度销售数据来预测下一个月。每个型号的回顾期可能会有所不同。在这个例子中,我们的将是 12。
所以我们需要做的是创建从 lag_1 到 lag_12 的列,并通过使用 shift() 方法赋值:
#create dataframe for transformation from time series to supervised
df_supervised = df_diff.drop(['prev_sales'],axis=1)#adding lags
for inc in range(1,13):
field_name = 'lag_' + str(inc)
df_supervised[field_name] = df_supervised['diff'].shift(inc)#drop null values
df_supervised = df_supervised.dropna().reset_index(drop=True)
查看我们名为 df_supervised 的新数据框架:
我们现在有了自己的功能集。让我们再好奇一点,问这个问题:
我们的特征对预测有多大用处?
调整后的 R 平方就是答案。它告诉我们我们的特征如何很好地解释了我们标签中的变化(在我们的例子中,对于 diff,从 lag_1 到 lag_12)。
让我们看一个例子:
# Import statsmodels.formula.api
import statsmodels.formula.api as smf# Define the regression formula
model = smf.ols(formula='diff ~ lag_1', data=df_supervised)# Fit the regression
model_fit = model.fit()# Extract the adjusted r-squared
regression_adj_rsq = model_fit.rsquared_adj
print(regression_adj_rsq)
那么上面发生了什么?
基本上,我们拟合一个线性回归模型(OLS——普通最小二乘法),并计算调整后的 R 平方。对于上面的例子,我们只是使用了 lag_1 来看看它在多大程度上解释了列 diff 中的变化。这个代码块的输出是:
lag_1 解释了 3%的变异。让我们看看其他的:
再增加四个功能,得分从 3%增加到 44%。
如果我们使用整个功能集,得分如何:
结果令人印象深刻,因为分数是 98%。现在,我们可以在扩展数据后自信地构建我们的模型。但是在缩放之前还有一个步骤。我们应该将数据分成训练集和测试集。作为测试集,我们选择了过去 6 个月的销售额。
#import MinMaxScaler and create a new dataframe for LSTM model
from sklearn.preprocessing import MinMaxScaler
df_model = df_supervised.drop(['sales','date'],axis=1)#split train and test set
train_set, test_set = df_model[0:-6].values, df_model[-6:].values
作为缩放器,我们将使用 MinMaxScaler,它将在-1 和 1:
#apply Min Max Scaler
scaler = MinMaxScaler(feature_range=(-1, 1))
scaler = scaler.fit(train_set)
# reshape training set
train_set = train_set.reshape(train_set.shape[0], train_set.shape[1])
train_set_scaled = scaler.transform(train_set)# reshape test set
test_set = test_set.reshape(test_set.shape[0], test_set.shape[1])
test_set_scaled = scaler.transform(test_set)
建立 LSTM 模式
一切准备就绪,构建我们的第一个深度学习模型。让我们从缩放数据集创建要素和标注集:
X_train, y_train = train_set_scaled[:, 1:], train_set_scaled[:, 0:1]
X_train = X_train.reshape(X_train.shape[0], 1, X_train.shape[1])X_test, y_test = test_set_scaled[:, 1:], test_set_scaled[:, 0:1]
X_test = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])
让我们来拟合我们的 LSTM 模型:
model = Sequential()
model.add(LSTM(4, batch_input_shape=(1, X_train.shape[1], X_train.shape[2]), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(X_train, y_train, nb_epoch=100, batch_size=1, verbose=1, shuffle=False)
上面的代码块显示了模型如何自我改进并减少每个时期的误差:
让我们做预测,看看结果是什么样的:
y_pred = model.predict(X_test,batch_size=1)#for multistep prediction, you need to replace X_test values with the predictions coming from t-1
y_pred vs y_test
结果看起来相似,但它并没有告诉我们太多,因为这些是显示差异的缩放数据。我们如何能看到实际的销售预测?
首先,我们需要进行缩放的逆变换:
#reshape y_pred
y_pred = y_pred.reshape(y_pred.shape[0], 1, y_pred.shape[1])#rebuild test set for inverse transform
pred_test_set = []
for index in range(0,len(y_pred)):
print np.concatenate([y_pred[index],X_test[index]],axis=1)
pred_test_set.append(np.concatenate([y_pred[index],X_test[index]],axis=1))#reshape pred_test_set
pred_test_set = np.array(pred_test_set)
pred_test_set = pred_test_set.reshape(pred_test_set.shape[0], pred_test_set.shape[2])#inverse transform
pred_test_set_inverted = scaler.inverse_transform(pred_test_set)
第二,我们需要建立一个有日期和预测的数据框架。转变后的预测显示了不同之处。我们应该计算预测的销售数字:
#create dataframe that shows the predicted sales
result_list = []
sales_dates = list(df_sales[-7:].date)
act_sales = list(df_sales[-7:].sales)
for index in range(0,len(pred_test_set_inverted)):
result_dict = {}
result_dict['pred_value'] = int(pred_test_set_inverted[index][0] + act_sales[index])
result_dict['date'] = sales_dates[index+1]
result_list.append(result_dict)
df_result = pd.DataFrame(result_list)#for multistep prediction, replace act_sales with the predicted sales
输出:
太好了!我们已经预测了未来六个月的销售数字。让我们在图中检查它们,看看我们的模型有多好:
#merge with actual sales dataframe
df_sales_pred = pd.merge(df_sales,df_result,on='date',how='left')#plot actual and predicted
plot_data = [
go.Scatter(
x=df_sales_pred['date'],
y=df_sales_pred['sales'],
name='actual'
),
go.Scatter(
x=df_sales_pred['date'],
y=df_sales_pred['pred_value'],
name='predicted'
)
]plot_layout = go.Layout(
title='Sales Prediction'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
实际与预测:
对于一个简单的模型来说看起来相当不错。
我们可以对这个模型做的一个改进是添加假期、休息和其他季节性影响。它们可以简单地作为新功能添加。
通过使用这个模型,我们有了基线销售预测。但是我们如何预测促销对销售的影响呢?我们将在第 7 部分对此进行研究。
你可以在这里找到这篇文章的 Jupyter 笔记本。
需要帮助来发展你的公司吗?点击这里,与我一起预订免费课程。
利用深度学习和卫星图像预测融雪模式
听完整的播客插曲:苹果 | 谷歌 | SPOTIFY | 其他
与 Kaggle 数据科学家 Jessica Li 的对话
大家好!
前几天,我在走向数据科学播客中采访了 Kaggle 的数据科学家 Jessica Li。在这篇文章中,我想呈现一些采访中的亮点。
下面,我将分享一些我问她的问题,以及她回答的摘要。
注:您可以在Twitter @ Jessica Li 9530上关注 Jessica,了解她未来的更新。
问:你是如何从学习地理变成一名数据科学家的?
地理过去更多的是制作地图,但现在不是了。
随着越来越多的卫星/空间图像变得可用,并且随着计算大量数据变得更加高效,对地理空间数据运行机器学习模型变得可能。这也是我在学校学到的。
当我开始申请数据科学工作时,我注意到肯定有一些重叠。这些技能包括 Python、R,显然还有数据科学和机器学习。
问:所以你在学校学到了这些技能?
是的,但是大学对我来说是一段有趣的时光,因为我有 4 年没有单一的专业。我经常跳来跳去,从医学预科到会计学,再到我喜欢的地理。我大学只学了两年地理。
这也是为什么我说我还在学习。大学毕业才 1.5 年,和很多人一样,我非常自学数据科学。所以,我的学习之旅还在继续。
问:你是如何在 Kaggle 获得数据科学工作的?
就像他们说的,人脉是关键。我搬到了纽约,在完成学位后的 2-3 个月里,我没有找到工作。所以,不知道我的工作将会是什么会有一些不确定性。
在我第三个月的时候,我去了一个在 meetup.com 上找到的聚会。如果你在找工作,我强烈推荐你去看看这个网站。
我去的聚会叫做 Geo NYC。在那里,人们分享他们在工作或闲暇时所做的大量地理空间分析。我在那里遇到了一个人,他把我介绍给了车队,剩下的就是历史了。
问:所以你搬到了纽约,却没有得到那里的工作机会?
是的,我会说这是我做过的最冒险的举动之一。我以前搬过几次家。我是澳大利亚人,但我在中国住过一段时间,为了上学我搬到了洛杉矶。所以,搬家本身并不可怕,但是搬到一个我不认识很多人的城市绝对是一个冒险的举动。
然而,当我想到让我走到今天的重要时刻时,所有这些都是冒险的决定。所以,我觉得如果我谨慎行事,我就不会有今天。
问:我今天想采访你的原因之一是因为你与美国宇航局合作的项目。你能给我们讲讲吗?
当然可以!这是一个与美国宇航局合作的为期 10 周的独立研究项目。这是 2018 年的夏天。我和另外两个队友一起工作。
该项目的范围是预测犹他州弗里蒙特河流域的水资源可利用性。那里的国家公园管理局想要一种工具来评估每年融雪季节后他们从流域获得的水量。河流流量评估很糟糕,他们也没有得到关于他们每年将得到多少水的准确预测。
这对他们来说是一个重要的项目,因为弗里蒙特河流域提供了大约 16,000 英亩的农业灌溉面积。因此,对于核电厂来说,知道他们将得到多少水,以便他们能够做出正确的水资源管理决策,这是非常重要的。然而,情况并不乐观。这就是为什么美国宇航局希望我们的团队建立一个模型,可以更好地预测这一点。
NASA’s explainer video on the project
问:为了预测这些水资源,你是预测降雪还是仅仅预测融雪?
好问题。花了一些时间来思考目标变量是什么。在这种情况下,我们感兴趣的是降雪后会发生什么。换句话说,我们决定将 streamflow 作为我们的目标变量。Streamflow 就是在给定的点流入河流的水量。
问:所以,基本上,你知道给定年份有多少雪,你想预测你会得到多少流量?
没错。现在,在一个典型的机器学习项目中,您开始探索您的数据,以确定哪种信息与您的项目相关。然后,您将想要识别您的目标变量——在本例中是 streamflow。下一部分将是数据收集和特征工程。在这一部分,你需要收集所有你认为会影响或有助于预测目标变量的预测变量。
我认为让这个项目更合适的是我们有卫星图像作为预测变量。
所以,美国宇航局有一套地球观测和卫星图像。最后,我们需要进行大量的计算,因为这些数据由许多像素组成。这是很多数据,但它们被证明是预测河流流量的很好的预测变量。
问:有多少数据?
我们有 MODIS,它给了我们两种不同的信息——这是两个变量。PERSIANN-CDR——这些都是卫星名称——是指降水量,所以是三个。再加上一些数据源,我们总共有 8 或 9 个变量。这些都是日常信息,我们有超过 2-3 年的时间。所以,你可以想象这是一个很大的数据。我们最终的数据集是 13-14 列数据,包含大约 3 年的观察值。
问:那可能是几百兆字节或几千兆字节?
绝对成千兆字节。卫星将信息记录为地球某一部分的图像。例如,卫星可以每天一次测量美国的地表温度。所以,这将是一幅图像,每一个像素代表地球上一个特定位置的温度。
由于这是大量的数据,我们决定对其中一些进行平均。我们想得到不同地区的粗略地表温度,最后,我们将流域地区分成三个不同的区域,并计算每个区域的日平均温度。
我们也为被雪覆盖的地区做了同样的事情。对于这一个,我们想计算总面积,而不是取平均值。就像我们对温度所做的一样,我们将所有对应于雪的像素相加,并找到总面积。
问:你的数据中有哪些像素是雪,哪些不是雪的信息?
是的,我要研究一下卫星图像是如何工作的。这真的是地理吸引我去学这个专业的部分。
现在,当我们给任何东西拍照时,我们实际上是在记录某种信息。
这对卫星图像和数码摄影来说意味着每个像素都有某种电磁波谱信息。
因此,地球上的每样东西都以某种方式反射电磁波谱中的光。一种你可以数字化识别雪的方法是通过它独特的反射光谱。雪是白色的,它的化学成分使它具有独特的特征。
记住这一点,你遍历每个像素,寻找一条特定形状的曲线。通过这种类型的计算,您将能够识别哪些像素是雪,哪些不是。
在这里,重要的是要记住,这不是一个二元的事情。你会得到一个连续的光谱,显示每个像素与电磁信号的相似程度。例如,一个给定的区域可能有 80%与之匹配。因此,您最终会得到一个置信度,例如,“这更有可能是雪”,以及“这不太可能是雪。”在此基础上对每个像素进行重新分类后,你将能够更清楚地了解给定图片中的实际降雪量。
问:好,回到这个分析。我记得你提到过你有 7 或 8 个预测变量?
我们有 10-11 个预测变量,其中 4 个是卫星图像。
问:有像图像一样的数据,也有非像图像一样的数据?
没错。非图像类数据基本上是表格。一个例子是每天的雪水当量,我认为这与雪中所含的水量有关——本质上是雪能制造多少水。那是以表格形式给出的信息。
目标变量也是表格形式——日流量。
所以,本质上,我们有一堆图像式的数据和表格数据。
然后,我们将它分成训练数据和测试数据。
如果我们有,比如说,2-3 年的数据,只有最近 6 个月的数据才算测试数据。其余的被当作训练数据。
问:你最后用的是什么型号?
我们最终使用了 LSTM 模型,它代表长短期记忆模型。
问:我听说过它,但我对它不太熟悉——你能解释一下它是如何工作的吗?
神经网络有许多变量,LSTM 是其中之一。这是一种循环神经网络。我可能不是解释这件事的最佳人选,但我会尽力而为!
从很高的层面来看,递归网络就像神经网络一样,但问题是它们有循环。它们适用于时间预测问题,在这种情况下,您会发现之前发生的一些事情会影响以后的分析。
例如,在我们的项目中,融雪肯定有时间滞后因素。仅仅因为我们的卫星图像显示我们那天有这么多雪,这并不意味着我们在同一天会有一些水流。所以,我们需要考虑一些时间因素。递归神经网络有很好的记忆成分来捕捉这些信息。它使我们能够将昨天的变量与明天的流量联系起来。
有一篇很好的 TDS 文章解释了 LSTM 神经网络的数学原理。我认为文章中使用的比喻是一个人在阅读一篇文章。当你读一个句子时,你是基于你在句子中读到的更早的单词来理解它的。这里有一些连续性,你必须着眼于大局来理解正在发生的一切。传统的神经网络无法捕捉这种类型的信息。另一方面,RNN 氏症可以。
问:在你的分析中,你尝试过使用其他模型吗?
对于任何类型的问题,我喜欢做的是首先尝试所有的标准模型。因此,你也许能够考虑你的问题的范围,并开始对你的问题进行分类。比如是不是二元分类问题?是多分类问题吗?就是这个时间序列,表格,情绪分析等。?对于这个问题,它显然看起来像一个时间预测问题。
基于此,我上了 scikit-learn 并尝试了一些行业标准模型。尝试简单回归总是好的,我们尝试了。然后,我们把它喂给了 SVM。当然,我们尝试了 XGBoost。
问:我明白了。所以你尝试了回归、SVM、XGBoost 和 LSTM。
在我们尝试 LSTM 之前,我们先尝试了一个 ARIMA 模型。在 LSTM 变得流行之前,ARIMA 曾经更主流。众所周知,它能够考虑到我前面提到一些时间关系。然而,它没有产生非常准确的结果。
帮助我选择 LSTM 作为我们预测模型的是和一个解决过类似问题的人交谈。我在网上找到了一篇类似的论文,也是关于使用卫星图像数据进行预测的。
我联系了这个人,他能够倾听我的问题,并建议我使用 LSTM。结果成功了,这给他带来了很大的荣誉。
问:和 ARIMA 相比怎么样?LSTM 超过它了吗?
是的,LSTM 的表现远远超过了其他任何一个国家。我们要么经历了不准确的预测,要么经历了太多的 ARIMA。当我们对测试数据进行测试时,预测是错误的——感觉预测非常静态。
融雪有潮起潮落的现象,虽然所有的模型都能够理解它,但它们不一定能捕捉到多年来融雪速度的差异。在过去的 17 年里,该地区的融雪时间越来越早,径流量也在减少。许多模型无法捕捉这种长期趋势,即使它们可以捕捉基本的上下波动。
问:LSTM 模型能够捕捉到这一点吗?
是的,那很棒。我记得,去年的数据里,streamflow 肯定是有减少的,但是很微妙。LSTM 是唯一能够抓住它的人。
问:当你着手解决这个问题时,有没有遇到什么特别的挑战?
这里有许多挑战,功能工程是其中之一。在这方面,让这个问题变得特别困难的一点是,人们需要了解像温度趋势这样的事情。一个特别具有挑战性的方面是理解雪是如何工作的。
在学校,我的专业是研究水资源,在这个项目中,水和雪的不同表现令人惊讶。我不得不学习许多关于雪的随机知识。例如,有人可能会说,我们应该考虑一个捕捉融雪下山速度的参数。也就是说,雪可能在某些天融化得更快,而在另一些天融化得更慢。我们试图找到一个参数来捕捉这一点,这涉及到学习大量的水科学。
问:还有其他挑战吗?
是的。本来这个项目的推荐范围并没有建议在任何地方使用机器学习。我们进来了,问题是简单地预测水流。有一些推荐的论文可以阅读,NASA 也有一些他们认为我们可以在其上工作的框架。
作为项目领导,这是一个挑战,因为看起来建议的方法可行,但这并不是我们真正想要做的。我认为这说明了从传统编程到数据科学的范式,以及尝试将其应用于我们周围更多事物的努力。
这个模型是以传统方式构建的,这意味着许多值和算法都是硬编码的,专门用于构建它的目的。
我记得这个模型是为智利的一个水资源项目建造的,所以我们必须重新创建这个模型。所有的权重和算法都适合那个特定的项目。
总而言之,这是这个项目中的一个压力点。我们已经进行了 10 周的 3 周。我很快学会了 MATLAB 来查看模型,感觉这不是我的团队想要采取的方法。在那种情况下,我不得不上报给我的经理和其他人,告诉他们我们想尝试其他方式。
很自然,如果你想改变项目的范围,你必须提出一个建议。当我们与这些人交谈时,我们已经想到用机器学习来代替。因此,我们提出了一个新的范围,指定了我们想要尝试的数据和模型的类型。
这需要一些说服力,因为机器学习仍然是一个相对较新的领域。即使这是每个人都在谈论的技术,当你推断到政府和 NPS 之类的东西时,许多人仍然不熟悉它。这将是一个过程,可能需要几年或几代人才能让他们理解它是如何工作的。
机器学习的倡导对我来说非常重要,在这个项目中,我们能够倡导这一点。最后,他们让我们做了,对此我也很高兴。
使用分类预测启动失败
这个项目是名为 Metis 的沉浸式数据科学项目的一部分。你可以在我的 GitHub 和幻灯片 这里 找到这个项目的文件。最终的模型在这里是可访问的
一点背景知识
最近,我测试了一系列分类算法,看看我能否使用 CrunchBase 数据集预测一家初创公司是否会失败。通常,有人需要一个企业帐户来访问这些数据,但我能够在不久前找到一个副本。CrunchBase 是风险投资公司了解他们可能投资的公司的绝佳资源。他们中的许多人为企业访问支付额外费用,以获得高级搜索等附加功能。
对于这些公司来说,使用这些数据和机器学习工具来预测潜在投资在未来可能会如何发展将是有利的。这是因为风险投资会接触大量不同的公司,但只投资其中的一小部分,审查所有公司真的很乏味。拥有相关的领域知识会有所帮助,但是,有了 CrunchBase 上的所有可用数据,应该可以在没有太多先验知识的情况下做出一些决策。
此外,随着初创公司保持更长时间的私有,后期投资最近变得越来越受欢迎。这产生了更多关于早期业绩的数据,我用这些数据构建了一个工具(将在 CrunchBase Enterprise 等平台上使用),以帮助比较公司并预测它们的成功机会。
该过程
CrunchBase 数据集提供了一个全面的公司列表,其中包含大量关于它们的信息,以及它们每一轮融资和单个投资的明细。由于创业环境不断变化,我只研究了过去 10 年内成立的公司。我也排除了那些只进行了一轮融资就失败的公司。成千上万的公司被分为两组:失败的公司和成功的公司(仍处于早期阶段的公司也被排除在外)。这给我留下了大约 10000 家公司。
清理完所有数据后,我就可以设置所有感兴趣的特性了。这些信息包括每家公司的融资轮次、行业和地点。一旦我做好了所有这些准备,我测试了相当多的分类模型,以找到最好的一个。下面是每个基线模型的 ROC 曲线图。
ROC Curves for each baseline classification model
我用它和另一个指标来比较每个模型:f_beta,它是召回率和精确度之间的加权调和平均值。我将 beta 值设置为 3,这意味着召回比精确更重要。当考虑风险资本投资时,大部分回报通常来自不到 20%的投资。更重要的是抓住所有潜在的独角兽,即使是以投资相当多的废物为代价。考虑到一只独角兽可以轻松获得超过原始投资 100 倍的回报,取消其中一项需要相当多的“哑弹”。
结果
在建立了最初的模型后,我挑选了最有希望的模型,并调整了它们的各种超参数,以找到预测能力最强的模型。(为了简单起见,这个我就不赘述了。如果对这个过程有任何疑问,请随时联系我们。)考虑到用例,可解释性对我来说也是一个优先考虑的问题,所以我更关注逻辑回归和基于树的模型,它们具有很高的可解释性。
选择的模型是逻辑回归,它将公司的成功几率作为前面描述的特征的函数来计算。这款车型的 f_beta 评分是 0.85 分满分 1 分,相当不错。
作为一个基线,任何拥有超过一轮融资的公司都有 31%的成功机会,其自身的一系列功能可以提高或降低这个数字。下面是这些特征系数的细目分类。如果条形向左延伸,会增加失败的几率,向右延伸会增加成功的几率。
Logistic Regression Coefficients in terms of Log Odds
不足为奇的是,一家公司筹集的资金越多,就越有可能成功。我发现,一家公司每轮融资额外增加 100 万美元(平均而言),他们成功的几率就会增加 16%。我对两轮融资之间的时间间隔感到惊讶。一般来说,一家公司在两轮融资之间的时间越长,对他们越有利;融资周期之间每增加一个月,成功几率就会增加 5%。种子期和首轮融资之间的情况不同,每增加一个月,这些几率实际上会降低 3%。
我发现的另一个特别有趣的特征是在行业内部。所有最受欢迎的硬件行业(包括制造业、清洁技术和生物技术)中的公司更有可能失败。这很可能是因为在寻找可随公司发展而扩展的可靠供应商时,成本和复杂性增加了。
如果你想亲自尝试一下,请访问我通过 Heroku 这里部署的应用程序。有任何问题,请随时联系和。
预测股市崩盘
统计机器学习技术和神经网络的尝试
在这篇博文中,我将介绍一种机器学习算法的设计,该算法旨在仅基于过去的价格信息来预测股市崩盘。我从这个问题的背景开始,详细阐述我的方法和发现。所有的代码和数据都可以在 GitHub 上找到。
股市崩盘是指市场总价值急剧快速下跌,价格通常在几天内下跌超过 10%。股市大崩盘的著名例子是 1987 年的黑色星期一和 2008 年的房地产泡沫。崩盘通常归因于价格泡沫的破裂,是由于大多数市场参与者试图同时出售其资产时发生的大规模抛售。
价格泡沫的出现意味着市场不是有效的。在低效市场中,价格并不总是反映基本资产价值,而是根据交易者的预期而上涨或下跌。这些预期被交易者随后进一步抬高(或压低)价格的行为所强化。这导致正(或负)价格泡沫最终破裂。这种现象被乔治·索罗斯描述为反身性,是技术分析中预测方法的基本假设。
如今,对于金融市场是否存在泡沫,已经没有太多争论。然而,理解这些低效率并预测价格泡沫何时破裂是一项非常困难的任务。想象一下,你可以识别一个即将形成的泡沫,并预测市场何时崩溃。你不仅可以在价格上涨时获利,还可以在合适的时机卖出以避免损失。
一些数学家和物理学家试图通过研究价格结构背后的数学来解决这个问题。其中一位物理学家是 Didier Sornette 教授,他成功预测了多次金融危机。Sornette 使用对数周期幂定律(LPPLs)来描述价格泡沫是如何形成和破裂的。本质上,LPPL 将导致崩盘的价格运动拟合为一个比指数增长更快的函数,该函数具有对数周期成分(反映价格波动幅度和频率的增加)。
这就是这个项目的灵感来源。如果研究人员发现的循环价格结构存在,那么机器学习算法是否有可能学习这些模式并预测崩溃?这种算法不需要知道潜在的数学规律,而是根据预先识别的崩溃数据进行训练,并自行识别和学习这些模式。
数据和崩溃
第一步是收集财务数据和识别崩溃。我在寻找低相关性主要股票市场的每日价格信息。低互相关对于模型的有效交叉验证和测试很重要。下面的矩阵显示了 11 个主要股票市场日收益率的交叉相关性。
Correlation matrix of daily price returns for 11 major stock market indices
为了避免任何两个数据集的交叉相关性大于 0.5,我只收集了标准普尔 500(美国)、日经(日本)、恒指(香港)、上交所(上海)、BSESN(印度)、SMI(瑞士)和 BVSP(巴西)的数据。
为了识别每个数据集中的崩溃,我首先计算了价格下降。跌价是指连续几天内价格从上一个最高价到下一个最低价的持续下降。下面的例子显示了 2018 年 7 月底至 8 月中旬期间标准普尔 500 的三次提款。
Example of three drawdowns. The first one shown lasted from July 25th to July 30th 2018 and has a total loss of approximately (2846–2803)/2846 = 1.5%
我考虑了两种不同的方法来识别崩溃。第一个是根据 Emilie Jacobsson [2]的建议,他将每个市场的崩溃定义为 99.5%分位数的下降。用这种方法,我找到了划分崩盘的提款阈值,从波动性较小的市场(如标准普尔 500)的 10%左右,到波动性较大的市场(如巴西)的 20%以上。第二种方法遵循 Johansen 和 Sornette [3]的建议,他们将崩溃确定为异常值,即当绘制数据集中压降等级的对数与压降幅度时,压降远离拟合的威布尔分布。
Distribution of drawdowns by rank as an example for the Shanghai index since 1996.
我用两种碰撞识别方法测试了我的算法,并得出结论,第一种方法(雅各布森)是有利的,原因有二。首先,Sornette 没有明确说明偏离威布尔分布的程度如何才能将压降归类为崩溃,因此需要人工判断。第二,他的方法导致识别更少的碰撞,这导致严重不平衡的数据集。这使得为机器学习算法收集足够多的数据进行训练变得更加困难。
通过收集上面提到的七个数据集,我总共收集了 59,738 行每日股票价格,并确定了总共 76 次崩盘。
问题陈述和功能选择
我制定了一个分类问题,目标是预测每个时间点(例如每个交易日)在未来 1 个月、3 个月或 6 个月内是否会发生崩盘。
如果过去的价格模式是未来价格事件的指示,则在某一天做出预测的相关信息包含在该天之前所有天的每日价格变化中。因此,为了预测在第 t 天的崩溃,从第 t 天之前的每天的每日价格变化可以被用作特征。然而,由于模型提供了太多的特征,确实会变得更慢、更不准确(“维数灾难”),因此提取一些特征来捕捉任何时间点上过去价格运动的本质是有意义的。因此,我定义了 8 个不同的时间窗口来衡量过去一年(252 个交易日)每天的平均价格变化。我使用了从 5 天(直到第 t 天)到 126 天(对于 t-₁₂₆ 到 t-₂₅₂ )的递增窗口大小来获得最近时间价格变化的更高分辨率。因为在对多日价格变化进行平均时,没有捕捉到价格波动,所以我为相同时间窗口内的平均价格波动添加了 8 个特征。对于每个数据集,我将平均价格变化和波动性标准化。
为了评估特征选择,我进行了逻辑回归并分析了回归系数。逻辑回归系数对应于相关特征的对数概率的变化,意味着当所有其他特征保持不变时,概率(碰撞概率与非碰撞概率的比率)如何随着该特征的变化而变化的对数。对于下图,我将对数赔率转换为赔率。赔率大于 1 表示碰撞概率随着相应特征的增加而增加。
Logistic regression coefficients indicating the influence of the features on the predictive variable
系数分析显示,过去几天的波动性是即将发生崩盘的最强指标。然而,最近的价格上涨似乎并不意味着崩盘。乍一看这很令人惊讶,因为泡沫的典型特征是价格的指数增长。然而,许多发现的崩盘并不是在价格见顶后立即发生的,相反,价格在一段时间内下降导致崩盘。过去 6 至 12 个月的高价格增长增加了预测崩盘的可能性,这表明长期价格的普遍上涨使崩盘的可能性更大,更长时期的价格变动包含了对崩盘预测有价值的信息。
培训、验证和测试集
我选择了标准普尔 500 数据集进行测试,剩下的 6 个数据集用于训练和验证。我选择标准普尔 500 进行测试,因为它是最大的数据集(自 1950 年以来的每日价格信息)并且包含最大数量的崩溃(20)。对于培训,我进行了 6 重交叉验证。这意味着每个模型运行六次,使用五个数据集进行训练,剩下的一个用于验证。
得分
为了评估每个模型的性能,我使用了 F-beta 分数。F-beta 分数是精确度和召回率的加权调和平均值。beta 参数决定了精确度和召回率的权重。大于 1 的β优先考虑召回,小于 1 的β优先考虑精确度。
我选择的β值为 2,它更强调回忆,这意味着未被发现的碰撞比预测的未发生的碰撞受到更严厉的惩罚。在风险厌恶方法下,这是有意义的,假设不预测发生的崩溃比预期不发生的崩溃(错过潜在利润)有更严重的后果(金钱损失)。
回归模型、支持向量机和决策树
我从线性和逻辑回归模型开始。回归模型通过最小化所有训练样本上的预测和实际目标变量的差异来寻找函数的最佳系数。线性回归估计连续的目标变量,而逻辑回归估计概率,因此通常更适合于分类问题。然而,当我比较两种模型的预测结果时,逻辑回归仅在某些情况下优于线性回归。虽然这令人惊讶,但重要的是要注意,即使逻辑回归可能为估计碰撞概率提供更好的拟合,如果选择的阈值有效地分离二元预测,线性回归的次优拟合在实践中不一定是缺点。该阈值被优化以最大化训练集上的 F-beta 分数。
接下来,我测试了支持向量机。支持向量机使用核函数将输入特征投影到多维空间中,并确定一个超平面来分离正样本和负样本。要考虑的重要参数是惩罚参数 C(应避免多少误分类的度量)、核函数(多项式或径向基函数)、核系数γ(确定核函数的维数)和类权重(确定如何平衡正面预测和负面预测)。最好的 SVM 模型获得了与回归模型相似的分数。这使得回归模型更受欢迎,因为它们的训练速度更快。决策树无法与任何其他测试模型在同一水平上运行。
递归神经网络
下一步是实现递归神经网络(RNNs)。与传统的机器学习算法和传统的人工神经网络相反,递归神经网络能够考虑它们接收输入数据序列的顺序,从而允许信息持续存在。这似乎是处理时间序列数据(如每日股票回报)的算法的一个重要特征。这是通过连接单元的循环来实现的,以便在时间步长 t 时,输入不仅是特征 xₜ 而且是来自先前时间步长 hₜ-₁ 的输出。下图说明了这个概念。
Recurrent Neural Network
然而,常规 rnn 的一个主要问题是它们在学习长期依赖性方面存在问题。如果在 xₜ-ₙ 和 hₜ 、 hₜ 之间有太多的步骤,可能从 xₜ-ₙ 那里学不到任何东西。为了帮助解决这个问题,长短期记忆网络(LSTMs)已经被引入。基本上,lstms 不仅将来自前一个单元 hₜ-₁的输出,而且将“单元状态” cₜ-₁ 传递到下一个单元。单元状态基于输入( xₜ 和 hₜ-₁ )在每一步得到更新,并且反过来更新输出 hₜ 。在每个 LSTM 单元中,四个神经网络层负责输入 xₜ 、 hₜ-₁ 、 cₜ-₁ 和输出 hₜ和 cₜ 之间的交互。有关 LSTM 单元架构的详细描述,请参考 colah 的博客【4】。
Recurrent Neural Network with Long Short Term Memory (LSTM)
具有 LSTM 的 rnn 具有检测简单回归模型不能发现的关系和模式的能力。因此,如果 RNN LSTM 能够学习崩溃前的复杂价格结构,这样的模型难道不能胜过之前测试过的模型吗?
为了回答这个问题,我用 Python 库 Keras 和 LSTM 实现了两个不同的 rnn,并进行了严格的超参数调整。第一个决定是每层输入序列的长度。每个时间步 t 的输入序列由从 t 开始的一系列日子的每日价格变化组成。必须小心选择这个数字,因为较长的输入序列需要更多的内存,并且会降低计算速度。理论上,RNN LSTM 应该能够找到长期依赖关系,然而,在 Keras 的 LSTM 实现中,如果参数 stateful 设置为真,则单元状态仅从一个序列传递到下一个序列。实际上,这种实现很麻烦。为了避免网络在训练期间识别不同数据集和时期的长期依赖性,每当训练数据切换数据集时,我实现了状态的手动重置。这种算法没有提供很好的结果,所以我将 stateful 设置为 false ,但是将序列长度从 5 个时间步长增加到 10 个时间步长,并为网络提供了从 10 天之前的时间窗口到 252 个交易日之前的平均价格变化和平均波动率的附加序列(类似于为之前测试的模型选择的特征)。最后,我调整了超参数,并尝试了不同的损失函数,层数,每层神经元的数量以及辍学与不辍学。性能最好的 RNN LSTM 具有顺序层,其后是两个 LSTM 层,每个层具有 50 个神经元,使用 adam 优化器、二元交叉熵损失函数和用于最后一层的 sigmoid 激活函数。
估价
虽然超参数调整和增加序列长度以及添加长期特征导致更快的训练(大约 10 个时期后验证集的最佳结果),但没有一个 RNN LSTM 模型能够胜过之前测试的模型。
Recall vs precision for all models
上图显示了不同模型的精度和召回性能。不同的颜色表示不同的模型,不同的形状表示不同的预测变量(1 个月、3 个月或 6 个月的崩盘)。下面的柱状图展示了所有模型在 1 个月、3 个月和 6 个月的碰撞预测中的 F-beta 分数。 Random 代表没有预测能力的模型的预期性能,该模型预测崩溃的频率与测试模型一样高。
F-Beta score for all models
最好的结果显示,预测 6 个月、3 个月和 1 个月内发生崩溃的 F-beta 值分别为 41、37 和 29。准确率在 12-16%之间,召回率在 45-71%之间。这意味着,虽然大约 50%的碰撞被检测到,但大约 85%的碰撞信号是“假警报”。
结论
首先是坏消息。RNN LSTM 似乎无法学习复杂的价格模式,而复杂的价格模式能让它超越简单的回归模型。这表明,没有任何复杂的价格模式会在所有(或几乎所有)崩盘之前出现,但不会在其它时候出现。这并不意味着 Sornette 的假设,崩溃之前的某些价格模式符合对数周期幂定律是无效的。然而,这意味着,如果这样的模式存在,(1)这些模式也发生在没有跟随它们的碰撞的情况下,(2)有许多碰撞没有跟随这些模式,或者(3)没有足够的数据供 RNN 学习这些模式。虽然更多的数据肯定会提供更多的清晰度,部分问题可能是(1)和(2)的组合。Sornette 将对数周期幂律拟合到某些被识别为异常值的崩溃,但并不是对所有下降幅度相似的崩溃都是如此。为了提供一个找到 Sornette 所描述的崩溃的算法,训练数据将需要被特别地标记为仅符合这些模式的崩溃。这可能会提高对这些碰撞的识别,但对(2)没有帮助,因为不同类型的碰撞不会被检测到。然而,如果有足够的数据和足够多的已识别事故清单,重新运行 RNN LSTM 模型肯定是值得的。
好消息是,简单的价格模式,通过价格的长期变化和波动性的变化来定义,似乎在崩溃前定期发生。最好的模型能够学习这些模式,并比可比较的随机模型更好地预测崩盘。例如,对于 3 个月内的崩溃预测,最佳回归模型在测试集上实现了 0.15 的精度和 0.59 的召回率,而不具有预测能力的可比较随机模型预期将实现 0.04 的精度和 0.16 的召回率。对于 1 个月和 6 个月的崩溃预测,结果看起来相似,F-beta 分数对于 6 个月的预测最好,对于 1 个月的预测最差。这些结果是否足以优化投资策略仍有争议。然而,如果讨论的回归崩溃指标持续警告即将到来的崩溃,风险厌恶型投资者肯定会更加保守地分配他们的投资组合头寸。
Prediction for a crash in 3 months by the logistic regression model for the S&P 500 from 1958 to 1976
查看碰撞时的测试数据价格指数图表和碰撞预测指标表明,虽然一些碰撞被检测得非常好,但其他碰撞发生时没有或几乎没有来自碰撞预测的警告。上图显示了一个没有预测到的崩溃(在 1962 年)和连续三次预测很好的崩溃(在 1974 年)的例子。一些崩盘比其他崩盘被更好地检测出来,这与以下假设是一致的:某些典型的价格模式确实先于一些崩盘,但不是所有崩盘。不同的算法大部分都与相同的崩溃作斗争,这就是为什么我没有试图结合不同的模型。
通过对过去 21 天的二元崩溃预测进行加权平均,(最近的预测加权更强),逻辑回归模型预测截至 2018 年 11 月 5 日标准普尔 500 在 6 个月内崩溃的可能性为 98.5%,3 个月内为 97%,一个月内为 23%。读完这项研究后,我让你来决定如何处理这些信息。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
参考
[1]为什么股票市场崩溃,迪迪埃·索尔内特。此处有书可用。
[2]如何用对数周期幂定律预测金融市场的崩溃,Emilie Jacobsson。在这里找到论文。
[3]股票市场价格大幅下跌是异常值,(2001) Anders Johansen 和 Didier Sornette。在这里找到论文。
[4]理解 LSTM 网络,colah 的博客。链接此处。
用 LSTM 预测股票价格
近年来,机器学习在许多有趣的领域得到了应用。驯服股市就是其中之一。很长一段时间以来,我一直想试一试。主要是为了巩固我对 LSTMs 的工作知识。最后,我完成了这个项目,非常兴奋地分享我的经验。
动机和目标受众
我将在一系列博客上写下我的经历。本系列的目的不是解释 LSTM 或机器学习概念的基础。因此,我会假设读者已经开始了他/她的机器学习之旅,并具备 Python 等基础知识,熟悉 SkLearn、Keras、LSTM 等。原因是已经有关于“LSTMs 如何工作?”更有资格解释其背后的数学原理的人。但是我会分享这些文章的链接,只要我觉得缺少背景知识。虽然有很多文章告诉你如何在给定数据集的情况下预测股票价格,但大多数作者都没有揭示/解释他们如何达到神经网络的特定配置,或者他们如何选择特定的超参数集。所以这篇文章的真正目的是分享这样的步骤,我的错误和一些我觉得很有帮助的步骤。因此,本文不限于股票价格预测问题。
以下是我们将关注的内容:
- 读取和分析数据。(熊猫)
- 标准化数据。(SkLearn)
- 将数据转换为时间序列和监督学习问题。
- 创建模型(Keras)
- 微调模型(在下一篇文章中)
- 训练、预测和可视化结果。
- 我发现非常有用的提示和工具(系列的最后一篇文章
请注意,第一篇文章讨论的是 LSTM 的预处理步骤和术语。如果你对这些步骤相当有信心,你可以跳到下一篇文章。
我们开始吧!
读取和分析数据
在这篇文章中,我将使用通用电气的历史股价数据。你可以在我的网站这里找到数据。我不记得数据的来源了,因为我很久以前就下载了。我们可以将数据读入如下所示的帧:
df_ge = pd.read_csv(os.path.join(INPUT_PATH, "us.ge.txt"), engine='python')
df_ge.tail()
如您所见,大约有 14060 个项目,每个项目代表该公司一天的股票市场属性。让我们看看它在图上的样子:
from matplotlib import pyplot as pltplt.figure()
plt.plot(df_ge["Open"])
plt.plot(df_ge["High"])
plt.plot(df_ge["Low"])
plt.plot(df_ge["Close"])
plt.title('GE stock price history')
plt.ylabel('Price (USD)')
plt.xlabel('Days')
plt.legend(['Open','High','Low','Close'], loc='upper left')
plt.show()
看起来价格——开盘价、收盘价、最低价、最高价——彼此之间没有太大的差异,除了偶尔的小幅低价下跌。
现在让我们来看看体积图:
plt.figure()
plt.plot(df_ge["Volume"])
plt.title('GE stock volume history')
plt.ylabel('Volume')
plt.xlabel('Days')
plt.show()
哼。你看到有趣的东西了吗?时间线上 12000 天左右交易数量出现相当大的激增,恰好与股价的突然下跌相吻合。也许我们可以回到那个特定的日期,翻出旧的新闻文章,找出是什么原因造成的。
现在让我们看看是否有任何 null/Nan 值需要担心。事实证明,我们没有任何空值。太好了!
print("checking if any null values are present\n", df_ge.isna().sum())
标准化数据
数据没有标准化,每一列的范围各不相同,尤其是数量。标准化数据有助于算法收敛,即有效地找到局部/全局最小值。我将使用 Sci-kit Learn 中的 MinMaxScaler。但在此之前,我们必须将数据集分为训练数据集和测试数据集。在这个过程中,我还会将 DataFrame 转换为 ndarray。
将数据转换为时间序列和监督学习问题
这很重要,也有点棘手。这就是知识 LSTM 需要的地方。我将简要描述这里需要的关键概念,但我强烈建议阅读 Andre karpathy 的博客这里,它被认为是关于 LSTM 和这个的最佳资源之一。或者你也可以看看吴恩达的视频(顺便提一下,其中也提到了安德烈的博客)。
LSTMs 以格式[ batch_size,time_steps,Features ]消耗输入;三维数组。
- 批量大小表示在更新权重之前,您希望您的神经网络看到多少个输入样本。假设您有 100 个样本(输入数据集),并且您想在每次 NN 看到输入时更新权重。在这种情况下,批量大小为 1,总批量为 100。就像 wise 一样,如果您希望您的网络在看到所有样本后更新权重,批次大小将为 100,批次数量将为 1。事实证明,使用非常小的批量会降低训练速度,另一方面,使用太大的批量(如整个数据集)会降低模型归纳不同数据的能力,并且还会消耗更多的内存。但是找到目标函数的最小值需要更少的步骤。所以你必须在你的数据上尝试不同的值,并找到最佳点。这是一个相当大的话题。我们将在下一篇文章中看到如何更智能地搜索这些内容。
- 时间步长定义你想让你的网络看到多少时间单位。例如,如果您正在处理一个字符预测问题,您有一个文本语料库要训练,您决定一次向您的网络输入 6 个字符。那么你的时间步长就是 6。在我们的例子中,我们将使用 60 作为时间步长,即我们将研究 2 个月的数据来预测第二天的价格。稍后将详细介绍。
- 特征是用来表示每个时间步的属性数。考虑上面的字符预测示例,并假设您使用大小为 100 的独热编码向量来表示每个字符。那么这里的特征尺寸是 100。
现在我们已经弄清楚了一些术语,让我们将股票数据转换成合适的格式。为简单起见,假设我们选择 3 作为时间步长(我们希望我们的网络回顾 3 天的数据来预测第 4 天的价格),然后我们将像这样形成数据集:
样本 0 到 2 将是我们的第一个输入,样本 3 的收盘价将是其相应的输出值;两者都被绿色矩形包围。类似地,样本 1 到 3 将是我们的第二个输入,样本 4 的收盘价将是输出值;用蓝色矩形表示。诸如此类。所以到目前为止,我们有一个形状矩阵(3,5),3 是时间步长,5 是特征的数量。现在想想上图中有多少这样的输入输出对?4.
也把批量和这个混在一起。假设我们选择批量为 2。那么输入输出对 1(绿色矩形)和对 2(蓝色矩形)将构成第一批。诸如此类。下面是实现这一点的 python 代码片段:
“y_col_index”是输出列的索引。现在,假设在将数据转换为监督学习格式后,如上所示,您的训练数据集中有 41 个样本,但您的批量大小为 20,那么您将必须调整您的训练集,以删除遗漏的奇数样本。我会寻找一个更好的方法来解决这个问题,但现在我已经这样做了:
现在使用上述函数,让我们形成我们的训练,验证和测试数据集
x_t, y_t = build_timeseries(x_train, 3)
x_t = trim_dataset(x_t, BATCH_SIZE)
y_t = trim_dataset(y_t, BATCH_SIZE)
x_temp, y_temp = build_timeseries(x_test, 3)
x_val, x_test_t = np.split(trim_dataset(x_temp, BATCH_SIZE),2)
y_val, y_test_t = np.split(trim_dataset(y_temp, BATCH_SIZE),2)
现在我们的数据已经准备好了,我们可以专注于构建模型。
创建模型
我们将使用 LSTM 来完成这项任务,它是递归神经网络的一种变体。创建 LSTM 模型就像这样简单:
既然您已经编译了模型并准备好进行训练,就像下面这样训练它。如果您想知道使用什么值作为参数,如时期、批量大小等。别急,我们将在的下一篇文章中看到如何解决这些问题。
训练该模型(具有微调的超参数)给出了 3.27e-4 的最佳误差和 3.7e-4 的最佳验证误差。以下是培训损失与验证损失的对比情况:
Training error vs Validation error
这是上述模型的预测结果:
prediction vs real data
我发现 LSTM 的这种配置是我尝试过的所有组合中最好的(对于这个数据集),和我已经尝试了 100 多种!所以问题是你如何为你的神经网络找到完美的(或者在大多数情况下,接近完美的)架构?这将引导我们进入下一个重要的部分,在的下一篇文章中继续。
你可以在我的 Github 简介这里找到所有完整的程序。
**注意:**向读者提出一个小小的请求——欢迎你们在 LinkedIn 或 Twitter 上与我联系,但是如果你们对我的博客有任何疑问,请在各自博客的评论区而不是个人信息区发表,这样,如果其他人有同样的疑问,他们也可以在这里找到,我就不必单独解释了。然而,仍然欢迎你向我个人发送与博客或一般技术问题无关的问题。谢谢:-)
2019 年 13 月 4 日更新
- 据我所知,自从我写了这篇文章,我的博客使用的模型可能已经过度拟合了。虽然我还没有确认,但很有可能。所以在你的项目中实现时请小心。你可以尝试更少的时代,更小的网络,更多的辍学等等。
- 我对最后一层使用了 Sigmoid 激活,这可能会受到无法预测数据集中高于“最高”价格的价格的限制。你可以尝试“线性”激活最后一层来解决这个问题。
- 修复了“将数据转换为时间序列”部分的一个拼写错误。
感谢读者让我注意到这些。
2020 年 1 月 21 日更新
正如在一些评论中提到的,我正在探索解决股票预测问题的其他方法。我终于让它工作了。感兴趣的读者可以在这里阅读。
机器学习预测股票价格
金融中的人工智能
利用 LSTM 模型预测股票趋势
随着金融机构开始接受人工智能,机器学习越来越多地被用来帮助做出交易决策。虽然有大量的股票数据供机器学习模型训练,但高信噪比和影响股票价格的众多因素是预测市场困难的几个原因之一。同时,这些模型不需要达到很高的精确度,因为即使 60%的精确度也能带来稳定的回报。预测股票价格的一种方法是使用长短期记忆神经网络(LSTM)进行时间序列预测。
LSTM:简要说明
LSTM diagram (source)
LSTMs 是递归神经网络(RNNs)的改进版本。rnn 类似于人类的学习。当人类思考时,我们并不是每秒钟都从零开始思考。例如,在句子“鲍勃打篮球”中,我们知道鲍勃是打篮球的人,因为我们在阅读句子时保留了过去单词的信息。类似地,rnn 是具有环路的网络,这允许它们在到达最终输出之前使用过去的信息。然而,随着时间间隔的增长,RNNs 只能连接最近的先前信息,而不能连接信息。这就是 LSTMs 发挥作用的地方;LSTMs 是一种 RNN,可以长时间记忆信息,这使它们更适合预测股票价格。有关 LSTMs 的技术解释,请点击此处。
导入/初始数据
为了开始我们的项目,我们导入 numpy 来进行科学计算,导入 pandas 来加载和修改数据集,导入 matplotlib 来绘制图形。
import numpy as npimport matplotlib.pyplot as pltimport pandas as pd
在进行必要的导入后,我们加载 Tata Global Beverage 过去股价的数据。从数据中,我们选择第一列和第二列的值(分别为“Open”和“High”)作为我们的训练数据集。“开盘价”栏代表当天股票的开盘价,“高价”栏代表当天股票的最高价格。
url = 'https://raw.githubusercontent.com/mwitiderrick/stockprice/master/NSE-TATAGLOBAL.csv'dataset_train = pd.read_csv(url)training_set = dataset_train.iloc[:, 1:2].values
为了查看我们正在使用的数据集,我们可以检查头部,它向我们显示了数据集的前五行。
dataset_train.head()
“低”代表当天的最低股价,“最后”代表股票最后一次交易的价格。“收盘”代表股票当天的收盘价。
数据标准化
规范化是将数据集中的数值列的值更改为通用的比例,这有助于提高模型的性能。为了缩放训练数据集,我们使用 Scikit-Learn 的 MinMaxScaler,其数字介于 0 和 1 之间。
from sklearn.preprocessing import MinMaxScalersc = MinMaxScaler(feature_range=(0,1))training_set_scaled = sc.fit_transform(training_set)
将时间步长并入数据
我们应该将数据以 3D 数组的形式输入到 LSTM 模型中。首先,在使用 numpy 将数据转换成数组之前,我们用 60 个时间步长创建数据。最后,我们将数据转换成一个 3D 数组,其中包含 X_train 样本、60 个时间戳以及每步一个特征。
X_train = []y_train = []for i in range(60, 2035):X_train.append(training_set_scaled[i-60:i, 0])y_train.append(training_set_scaled[i, 0])X_train, y_train = np.array(X_train), np.array(y_train)X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
创造 LSTM 模式
在开发 LSTM 之前,我们必须从 Keras 进行一些导入:Sequential 用于初始化神经网络,LSTM 用于添加 LSTM 层,dropout 用于防止与 Dropout 层过度拟合,Dense 用于添加密集连接的神经网络层。
from keras.models import Sequentialfrom keras.layers import LSTMfrom keras.layers import Dropoutfrom keras.layers import Dense
添加 LSTM 图层时使用了以下参数:50 个单位是输出空间的维度,return_sequences=True 是堆叠 LSTM 图层所必需的,因此后续的 LSTM 图层具有三维序列输入,input_shape 是训练数据集的形状。
在 Dropout 层中指定 0.2 意味着 20%的层将被丢弃。在 LSTM 和下降图层之后,我们添加了指定一个单位输出的密集图层。为了编译我们的模型,我们使用 Adam 优化器,并将损失设置为均方误差。之后,我们将模型拟合为运行 100 个时期(时期是学习算法将通过整个训练集工作的次数),批次大小为 32。
model = Sequential()model.add(LSTM(units=50,return_sequences=True,input_shape=(X_train.shape[1], 1)))model.add(Dropout(0.2))model.add(LSTM(units=50,return_sequences=True))model.add(Dropout(0.2))model.add(LSTM(units=50,return_sequences=True))model.add(Dropout(0.2))model.add(LSTM(units=50))model.add(Dropout(0.2))model.add(Dense(units=1))model.compile(optimizer='adam',loss='mean_squared_error')model.fit(X_train,y_train,epochs=100,batch_size=32)
对测试集进行预测
我们从导入测试集开始
url = 'https://raw.githubusercontent.com/mwitiderrick/stockprice/master/tatatest.csv'dataset_test = pd.read_csv(url)real_stock_price = dataset_test.iloc[:, 1:2].values
在预测未来的股票价格之前,我们必须修改测试集(注意我们对训练集所做的编辑的相似之处):合并 0 轴上的训练集和测试集,再次将 60 设置为时间步长,使用 MinMaxScaler,并重塑数据。然后,inverse_transform 将股票价格转换成正常可读的格式。
dataset_total = pd.concat((dataset_train['Open'], dataset_test['Open']), axis = 0)inputs = dataset_total[len(dataset_total) - len(dataset_test) - 60:].valuesinputs = inputs.reshape(-1,1)inputs = sc.transform(inputs)X_test = []for i in range(60, 76):X_test.append(inputs[i-60:i, 0])X_test = np.array(X_test)X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))predicted_stock_price = model.predict(X_test)predicted_stock_price = sc.inverse_transform(predicted_stock_price)
绘制结果
完成所有这些步骤后,我们可以使用 matplotlib 来可视化我们预测的股价和实际股价的结果。
plt.plot(real_stock_price, color = 'black', label = 'TATA Stock Price')plt.plot(predicted_stock_price, color = 'green', label = 'Predicted TATA Stock Price')plt.title('TATA Stock Price Prediction')plt.xlabel('Time')plt.ylabel('TATA Stock Price')plt.legend()plt.show()
虽然我们的预测价格的准确价格点并不总是接近实际价格,但我们的模型仍然表明了整体趋势,如上涨或下跌。这个项目告诉我们 LSTMs 在时间序列预测中可以有些效果。
点击此处查看完整代码
参考
[1]德里克·姆维蒂,股票价格预测数据与笔记本教程 (2018),Github
先别走!
我是 Roshan,16 岁,对人工智能和金融的交叉领域充满热情。关于人工智能在金融中的广泛观点,请查看这篇文章:https://becoming human . AI/artificial-intelligence-and-its-application-in-finance-9f1e 0588 e 777。
在 Linkedin 上联系我:https://www.linkedin.com/in/roshan-adusumilli-96b104194/
用回声状态网络预测股票价格
几十年来,人们一直试图可靠地预测股市看似混乱的本质,但都失败了。神经网络是关键吗?
“在看似完全混乱的事物中,有秩序,甚至是伟大的美。如果我们足够仔细地观察我们周围的随机性,模式就会开始出现。” ― 阿伦·索尔金
**编辑:**由于对本文中概述的方法的怀疑和批评,本教程中使用的所有代码和数据以及结果都在相关的 GitHub 资源库中提供,可以在这里找到。
时间序列预测的动机
股票市场通常被视为一个混沌的时间序列,公司经常应用先进的随机方法来尝试并做出合理准确的预测,以便他们能够占上风并赚钱。这本质上是所有投资银行背后的想法,尤其是那些市场交易者。
我并不自称对股票市场了解很多(毕竟,我是科学家,不是投资银行家),但我确实对机器学习和随机方法有一定的了解。这一领域最大的问题之一是试图以可靠的方式准确预测混沌时间序列。预测混沌系统动态的想法有点违反直觉,因为根据定义,混沌的东西不会以可预测的方式表现。
对时间序列的研究在股票市场出现之前就有了,但随着个人试图利用股票市场来“击败系统”并变得富有,时间序列的研究变得越来越受欢迎。为了做到这一点,人们不得不开发可靠的方法,根据先前的信息来估计市场趋势。
首先,让我们谈谈时间序列的一些属性,这些属性使时间序列易于分析,这样我们就可以理解为什么当我们观察股票市场时,时间序列分析会变得相当困难。
所有相关代码都可以在我的 GitHub 资源库中找到:
[## GitHub-mpstewart 1/EchoStateNetworks:与媒体文章“预测股票…
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/mpstewart1/EchoStateNetworks)
时间序列属性
时间序列最重要的属性之一就是它是平稳的。如果一个时间序列的统计属性如均值和方差随时间保持不变,则称该时间序列为平稳。但是为什么重要呢?
大多数模型都假设时间序列是平稳的。直观上,我们可以说,如果一个时间序列在一段时间内具有特定的行为,那么它很有可能在未来也会遵循相同的行为。与非平稳序列相比,平稳序列的相关理论更加成熟,也更容易实现。
使用非常严格的标准来定义平稳性。然而,出于实际目的,如果该序列在一段时间内具有恒定的统计特性,即以下特性,我们可以假设该序列是平稳的:
- 恒定平均值。这应该是直观的,因为如果均值在变化;那么时间序列可以被看作是移动的,通过对比下面两个图可以看出。
2.恒定方差。这种性质称为同质性。下图描述了违反此属性的静态与非静态示例。
3.不依赖于时间的自相关。在下图中,你会注意到随着时间的增加,传播变得越来越近。因此,对于非平稳情况,协方差不随时间恒定。
为什么我关心一个时间序列的平稳性?
我首先讨论这一部分的原因是,您需要您的时间序列是平稳的,以便构建一个时间序列模型。如果违反了平稳时间序列的标准,首先要做的是转换时间序列,使其平稳,然后尝试随机模型来预测该时间序列。有多种方法可以实现这种稳定性。其中一些是去趋势、差分等。
对于不熟悉时间序列分析的人来说,这可能有点愚蠢。然而,它比第一次出现时要复杂一点(不总是这样吗…).事实证明,处理时间序列的最佳方式是首先将其“固定化”,并将其解耦为几个不同的特征,如线性趋势,分离出具有不同季节性的时间序列,然后在最后将它们重新加在一起。
An example of decoupling a time series into multiple series with desirable properties.
对于任何熟悉傅立叶变换的人来说,这是一个非常相似的类比。傅立叶变换的作用是分离出时间序列中的不同频率特性,并将它们转换到频域,以便更简单地表示。然后,在将这些信号转换回时域之前,可以更容易地对其进行处理或分析。
我如何测试平稳性?
从视觉观察来看,时间序列是否平稳并不总是显而易见的。因此,更正式地说,我们可以使用下面的方法来检查平稳性:
- **绘制滚动统计:**我们可以绘制移动平均线或移动方差,看它是否随时间变化。移动平均值/方差是指在任何时刻’ t ',我们将取去年的平均值/方差,即过去 12 个月。但是这更多的是一种视觉技术。
- Dickey-Fuller 检验:这是检验平稳性的统计检验之一。这里的零假设是 TS 是非平稳的。测试结果包括一个测试统计和一些临界值用于不同的置信水平。如果“检验统计量”小于“临界值”,我们可以拒绝零假设,说序列是平稳的。详见本文。
现在我们对时间序列有了更多的了解,我们可以看看人们研究时间序列的传统方式,他们如何开发他们的模型,以及为什么他们不适合研究股票市场。
时间序列预测的基本方法
最基本的方法非常简单,我认为大多数人不用上时间序列分析课就能想出这些方法。有些用处的最简单的模型是移动平均线。本质上,移动平均采用最后的 t 值,并将这些值的平均值作为下一点的预测值。
移动平均惊人地准确,对异常值和短期波动的稳健性可以通过改变平均过程中使用的先前点的数量来控制。
更复杂的程序自然地从这里开始,例如指数平滑。这类似于移动平均,只是它是一个加权过程,对最近的数据点给予更高的重要性。指数平滑中使用的特定加权函数(不奇怪)是一个指数函数,但是可以使用不同的方法对该过程进行加权。
这些方法适用于相对一致和周期性的时间序列,但那些表现出季节性和持续线性趋势或任何显著随机性或混沌性质的方法很难用于此。例如,如果我有一个周振荡,并且我使用的是移动平均模型,该模型对上周的数据进行平均,那么我的模型将完全忽略这种振荡行为。
一种用于分析具有不同自相关水平的时间序列(例如,每周趋势与每月和每年趋势相结合)的非常流行的方法被称为霍尔茨线性模型。Holt 扩展了简单的指数平滑法,允许用趋势预测数据。它只不过是应用于水平(系列中的平均值)和趋势的指数平滑。为了用数学符号来表达这一点,我们现在需要三个等式:一个用于水平,一个用于趋势,一个用于结合水平和趋势来获得预期的预测 ŷ。
另一种最流行的技术是使用 ARIMA。这代表自回归综合移动平均线。正如你可能猜到的,它结合了移动平均值和自回归特性(查看后续时间步长之间的相关性)。ARIMA 模型遵循一种特定的方法。
本质上,我们获取原始数据,对时间序列进行解耦,使其成为平稳和非平稳的组成部分。然后,我们可以研究被称为自相关或部分自相关图的图表,这些图表查看特定值与其前身相比的相关性有多强。由此,我们可以确定如何建立 ARIMA 模型来进行预测。
所有这些方法都依赖于具有某种自相关和/或周期性的平稳时间序列。这是股票市场固有的特征。股票市场确实有波动的时候,这些在大学的任何经济学课上都有详细的研究。它们是基钦周期(3-5 年的周期)朱格拉周期(7-11 年的周期)库兹涅茨摆动(15-25 年的周期)和康德拉季耶夫波(45-60 年的周期——尽管这个周期经济学家还在争论)。但是,个别公司的股票一般不会遵循这种趋势,有些人赢了,有些人输得比别人多。从时间序列模型的角度来看,它们受政治、社会经济和社会因素的影响,这些因素本质上是随机和混乱的。此外,人们对这些波动的理解还不够准确,无法根据它们的存在对经济市场的未来做出有用的预测——这是有道理的,因为否则的话,每个人都会这么做。
神经网络怎么样?
神经网络似乎适用于任何涉及非线性特征空间的事物。事实上,递归神经网络可以并且已经被用于预测股票市场。然而,在预测股票价格方面,递归神经网络(RNNs)面临着几个挑战,最明显的是与 RNNs 相关的消失梯度问题,以及非常嘈杂的预测。点击这里可以找到一个全面的演示,展示如何实现一个叫做 LSTM 的基本类型的 RNN 来预测股票价格。
到目前为止,RNNs 最重要的问题是消失梯度问题。这个问题源于这样一个事实,即通过称为反向传播的程序优化的非常深的神经网络使用每层之间的导数来“学习”。这些导数可以相对较小,也可以相对较大。如果我的网络有 100 个隐藏层,我将一个小数字乘以 100 次,这个值基本上就消失了。这是一个问题,如果我所有的梯度都是零,我的网络什么也学不到,所以我能做什么?
对此有 3 种解决方案:
- 剪切梯度法
- 具有漏单元的特殊 RNN,如长短期记忆(LSTM)和门控循环单元(GRU)
- 回声状态 RNNs
渐变裁剪阻止我们的渐变变得太大或太小,但是这样做我们仍然会丢失信息,所以这不是一个理想的方法。具有泄漏单元的 rnn 是好的,并且是大多数将 rnn 用于商业目的的个人和公司使用的标准技术。这些算法通过某种形式的梯度下降来适应所有连接(输入、循环、输出)。这使得这些算法很慢,更麻烦的是,这使得学习过程容易被分叉打断;不能保证收敛。因此,rnn 很少在实际工程应用中使用。
这就是回声状态网络的用武之地。回声状态网络是一个相对较新的发明,它本质上是一个递归神经网络,具有一个松散连接的隐藏层,称为“水库”,在存在混沌时间序列的情况下工作得非常好。在回声状态网络中,我们只需训练网络的输出权重,这样可以加快神经网络的训练速度,通常可以提供更好的预测,并解决我们之前用时间序列分析讨论过的所有问题。与其他方法相比,ESN 训练速度快,不会出现分叉,并且易于实现。在一些基准任务上,ESNs 明显优于所有其他非线性动力学建模方法。
回声状态网络是被称为水库计算的计算科学类别的一部分,我们将在下一节更详细地研究它。
回声状态网络
因此,我们已经证明,没有任何方法可以处理混乱的时间序列,不幸的是,这恰好是我们对股票市场建模的方式。避免这种困难的一种方法是固定递归和输入权重,并且只学习输出权重:回声状态网络(ESN)。隐藏单元形成了从历史输入中捕获不同方面的时间特征的“库”。
ESN 背后的数学论证相当复杂,因此为了本文的缘故,我将尽量避免它。相反,我们将讨论 ESN 背后的概念,并看看如何使用 Python 相对简单地实现它。
原始论文中概述为什么它被称为“回声”网络的描述是
贯穿所有这些变化的统一主题是使用固定的 RNN 作为随机非线性可激发介质,其对驱动输入(和/或输出反馈)的高维动态“回声”响应被用作非正交信号基础,以通过线性组合重建期望的输出,从而最小化一些误差标准
ESN 取任意长度的序列输入向量( u )并且(1)将其映射到高维特征空间(即,递归的储层状态 h ),并且应用线性预测器(线性回归)来找到 ŷ.
Schematic diagram of an echo state network.
我们基本上只训练输出权重,这大大加快了训练的速度。这就是油藏计算的巨大优势。通过设置和固定输入和循环权重来表示丰富的历史,我们获得:
- 作为接近稳定性的动力系统的循环状态——稳定性意味着雅可比矩阵都接近 1(没有消失或爆炸梯度)
- 部分记忆先前状态的泄漏隐藏单元——它们避免爆炸/消失梯度,同时不需要训练。
回声状态属性
为了使 ESN 原理工作,储层必须具有回波状态属性 (ESP),这将受激储层动态的渐近属性与驱动信号相关联。直观地说,电潜泵表明储层将从初始条件中逐渐洗去任何信息。如果储层权重矩阵(和泄漏率)在奇异值方面满足某些代数条件,则对于附加 sigmoid 神经元储层,ESP 是有保证的。
培训
所以你可能想知道,首先我们如何选择隐藏状态的值?输入和递归权重被随机初始化,然后被固定。所以,我们没有训练他们。我们应该如何修正它们以优化预测?
训练非常容易和快速,但是存在超参数,例如控制权重的随机生成、储层节点的程度、储层节点的稀疏性、谱半径的超参数。不幸的是,不存在优化超参数的系统方法,因此这通常是使用验证集来完成的。由于特征空间中存在固有的自相关,交叉验证对于时间序列数据是不可行的。
概括一下:
- 每个网络节点都有不同的动态行为
- 信号的时间延迟可能沿着网络链路出现
- 网络隐藏部分具有循环连接
- 输入和内部权重是固定的,并且是随机选择的
- 在训练期间,仅调整输出权重。
编码回声状态网络
现在到了你们期待已久的时刻,你们实际上是如何对这些神秘的网络进行编码的?我们使用一个 Python 库,它可以从这个 GitHub 库中获得。这个库叫做 PyESN 。为了安装这个库,您必须克隆这个库并将pyESN.py
文件放在您当前的 Jupyter 笔记本文件夹中。然后,当你在 Python 3 笔记本中时,你可以简单地称之为import pyESN
。
你称 RC 为:
有关参数的简要说明:
n_inputs:
输入维数
n_outputs:
输出尺寸的数量
n_reservoir:
水库神经元的数量
ranodom_state:
种子为随机发生器
sparsity:
将经常性权重的比例设置为零
spectral_radius:
递归权重矩阵的谱半径
noise:
添加到每个神经元的噪声(正则化)
预测亚马逊股票价格
现在,我将介绍一个使用 echo state networks 预测未来亚马逊股票价格的示例。首先,我们导入所有必要的库,并导出数据(在本例中,数据是从互联网上搜集来的)。
然后,我们使用 pyESN 库中的 ESN 来部署 RC 网络。这里的任务是通过使用之前的 1500 点预测未来两天,并对未来的 100 点进行预测(查看下图)。所以,最后你会有一个 100 时间步的预测,预测窗口= 2。我们将使用它作为验证集。
首先,我们使用一些合理的值创建我们的回声状态网络实现,并指定我们的训练和验证长度。然后,我们创建函数来计算均方误差,并针对频谱半径、噪声和窗口长度的特定输入参数运行回声状态网络。
现在,我们可以简单地运行一个函数,获得我们的预测,然后我们可以绘制这个图,看看我们做得有多好。
上面的代码产生了下面的情节。
如果我们放大这个图,我们可以看到这个预测实际上是多么令人印象深刻。
不错吧?唯一的警告是,它似乎在短时间内(大约 1 或 2 天)工作得很好,具有合理的准确性,但随着估计值的进一步外推,误差会变得越来越大。上面的模型是用两天的预测窗口制作的,这意味着我们在任何给定的时间只能预测未来的两天。
我们可以通过增加窗口长度来说明这一点。对于 10 天的窗口长度,预测仍然惊人地准确,尽管它明显比两天的预测窗口差。
为了获得这么好的结果,我们必须进行大量的超参数优化;以下是获得上述结果中使用的超参数的步骤。
上面的代码需要一段时间来优化,这只是针对两个参数。当在热图上绘制 MSE 时,我们得到以下结果。
然而,当窗口函数很小时,它在我们的验证集上给了我们一个相当好的结果。这使得 ESN 有利于股票价格的短期预测,但如果你试图推断结果,事情会变得更加不确定和有风险。
在未来预测中,误差随时间传播,因此它随时间增加。这就是当窗口长度增加时精度降低的原因。我们可以在下图中看到这种行为,其中 MSE 是预测窗口的单调递增函数,因此预测越长意味着 MSE 越大。
最后一句话
回声状态网络分析混沌时间序列的能力使其成为数据高度非线性和混沌的金融预测的有趣工具。但是,除了预测股票市场,我们还可以利用这些网络做更多的事情。我们还可以:
- 预报天气
- 控制复杂动力系统
- 执行模式识别
预计未来会听到更多关于这类网络的信息,尤其是随着人们进入 DeepESN 模型的开发阶段,这些模型能够在更高维度的潜在空间中工作,具有时间特征,能够处理一些最困难的时间序列问题。
如果你对这些网络感兴趣,有更多讨论这些的文章和研究论文可以免费获取。
回声状态网络(ESN)为递归神经网络提供了架构和监督学习原理
www.scholarpedia.org](http://www.scholarpedia.org/article/Echo_state_network) [## 深度回声状态网络(DeepESN):简要综述
深层递归神经网络(RNNs)的研究,特别是深层油藏计算(RC)的研究,正在获得越来越多的关注
arxiv.org](https://arxiv.org/abs/1712.04323)
所有上述工作都在我的 GitHub 资源库中列出,可以在这里找到。
机器学习快乐!
用机器学习预测股票
需要注意的 3 件重要事情
Photo by Aron Visuals on Unsplash
机器学习的激增是前所未有的。需要基于数据的决策制定的领域很少没有得到广泛应用。投资领域也不例外。人们只需在谷歌上联合搜索“ML”和“股票预测”,就会看到大量的时间序列预测和递归神经网络相关内容。尽管股票价格数据可能看起来是这些类型算法的完美候选,但我们应该谨慎从事,小心处理这项任务(尤其是如果涉及到您辛苦赚来的现金)。
那些开始接触机器学习的神秘预测艺术的人会回忆起他们在这个主题中的第一堂课,是下面维恩图的一些迭代:
这一点很清楚。机器学习(或数据科学)跨越了技术技能(如编程和数学)与领域专业知识形式的主题知识的融合。如果没有这三种形式,我们只是简单地回归到各自领域中更纯粹的形式之一。
这种描述对于金融机器学习尤其适用。时间序列金融数据极其微妙,将现成的算法应用于未处理的价格数据是错误发现或更糟的资本损失的完美方法。因此,使用这些数据需要一些特殊的考虑,最重要的是应用领域知识。因此,这篇文章旨在传授一些直觉,这些直觉经常被该领域的新手所忽视。我们将主要关注问题的讨论方面,因为相关的数学和编码资源已经非常丰富。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
1。数据,数据,数据
Photo by Markus Spiske on Unsplash
这可能不足为奇,因为数据是任何 ML 模型的关键因素,股票预测也不例外。为了理解我们的谨慎,我们需要首先理解数据生成过程。用于股票预测的常用分析领域数据集,如宏观经济、基本面和价格数据,都是时间序列数据的例子。这类数据有一种现象叫做****。简单来说,每次观测的值锚定到前一个时间间隔观测的值。
为了在实践中说明这一点,让我们以价格为例。如果我们观察任何一只股票,并每天跟踪它的价格变动,我们会发现每只股票的收盘价都与前一天的收盘价紧密相连,只有一些“微小的”偏差,但这是为什么呢?最简单的形式是,股票是基础公司的所有权份额,其价值由永恒的会计等式决定, 资产减去负债等于权益 。股权是公司的基本价值,占股价的大部分,投资者情绪、交易行为和噪音驱动着每日偏离。公司资产即机器、土地、建筑物和存货的价值不会在一夜之间发生重大变化,其负债也不会发生重大变化(并不总是如此),因此,除了重大会计丑闻之外,公司的基本价值每天都应该相对稳定。****
这对机器学习意味着什么?这意味着一个模型可以通过“博弈”其损失函数并选择前一天的价格作为当天价格的预测来表现得相当好。当许多“表现良好的预测模型”的预测输出非常类似于实际股票价格的滞后移动平均值时,可以清楚地观察到这一点。任何这样的模型都会不断追逐真实价格。
类似的,是平稳性的问题。许多最大似然模型和预处理技术的基础是假设生成数据的分布参数是恒定的。或者,这可以解释为特征的均值和标准差不随时间变化,并且数据中没有趋势。随着时间的推移,看看常用的美国季度 GDP 数据就会很快打消这种想法。这些数据中显然有一个趋势,也应该有,如果一个经济体在增长,你会预期它的产出(以及这些产出的价格)会随着时间的推移而增长。
Source: BEA, US Nominal GDP over time
资料来源:BEA,美国一段时间的名义 GDP
该数据中的平均值和标准偏差是时变的,并且在盲目应用诸如回归的算法和诸如标准化和主成分分析的普通预处理技术时造成一些不便。
在(投资)文献和实践中,应对时间序列数据异常的一种常用技术是采用两个时期之间的股票价格回报(或其他数据的变化率),而不是绝对值。这背后的直觉类似于时间序列预测中的去趋势或差分,旨在使数据平稳。如果我们将此应用于美国 GDP 数据,我们会得到一些开始类似于正常 iid 变量的东西。
Source: BEA, GDP % change from prior period
这种方法并不完美,并且会引入各种其他问题,但是它是被广泛接受的方法。
尽管用户需要了解财务数据的许多其他方面,但为了简洁起见,我将在以后的帖子中更全面地讨论这些方面。
2。任意误差项-现实世界的后果
Photo by Emily Morter on Unsplash
大多数有监督的机器学习方法是通过估计或优化一组权重来拟合的,这些权重使一些目标函数最小化。在回归问题中这个函数常常是 【均方根误差】【RMSE】和在分类中的 【交叉熵】 。对于许多经典的基准数据集,如 ImageNet 大规模视觉识别挑战赛(【ils vrc】),这已经成为一场“逐底竞赛”,高素质的团队成功地(并成功地)年复一年地大幅降低错误率。虽然这对于推进研究的目的来说可能是合适的,但是 ML 对强制减少一些任意误差项的关注鼓励了对现实世界问题的抽象。****
在投资中,找到一个能够以 95%的准确率对何时买入或卖出股票进行分类的模型似乎是一个很好的结果,但通常这个模型不会模仿真实的投资组合行为,最重要的是不会考虑错误的成本。市场变化无常,尽管看似有利的投资环境可能持续数年,但调整或“ 黑天鹅 ”事件(由 纳西姆·塔勒布 杜撰)可能在几分钟内展开。
如果表征你 5%错误率的实例之一与这些罕见但灾难性的事件之一同时发生,几乎可以肯定的是,你的投资组合将遭受损失,可能会达到 95%的正确率(假设没有泛化错误)所带来的累积回报完全消失的程度。对于专业投资经理来说,这个问题更加严重,因为 10%的提款就足以引发投资者大规模撤离他们的基金。由收益和痛苦的不对称产生的后果在经验丰富的从业者心中根深蒂固。这就是为什么该行业既关注创造回报,也关注管理风险。
对于机器学习者/数据科学家来说,这里的课程是理解他们的模型的含义,不要只知道错误率和损失函数,执行 向前走测试 ,就好像你一直持有你预测的交易,并引入成本敏感的措施,这些措施是惩罚你的模型是错误的。
3。战胜市场——比你想象的要难
Photo by Inactive. on Unsplash
要理解为什么我们需要引入机会成本的概念,仅仅有一个能获得正回报的好的 ML 模型是不够的。这个关键的经济原则说明了放弃下一个最佳机会的代价。如果我们不使用提议的 ML 模型投资我们的钱,下一个最好的机会和一个需要很少技巧的机会是购买市场,大概是通过购买 ETF。这些产品以相对较低的成本给你带来类似标准普尔 500 指数的回报。因此,我们必须问一个问题,如果你的模型的表现,在调整交易成本后,没有明显超过标准普尔 500 指数的 18.74%&【你真的把钱用好了吗?专业投资经理几乎总是被某种基准所束缚,他们的技能是通过超越基准的能力来衡量的,这与机器学习者/数据科学家形成了对比,他们通常会孤立地评估自己的财务预测。
结论
虽然这个列表既不完整也不全面,但我希望我已经给了你一些直觉,告诉你在构建股票预测的 ML 模型时需要考虑的关键问题。与任何其他与数据相关的任务一样,ML 可能会给你一套工具来利用,但是找到解决方案仍然需要对问题有深入的了解。
免责声明:本帖纯属个人观点和看法的表达。它不代表任何建议,也不反映我的雇主的观点。
使用谷歌云人工智能平台预测纽约市的出租车价格(十亿多行)第 1 部分
Taxis | Photo by Francesco Ungaro on pexels.com
该项目旨在创建一个机器学习模型,使用 BigQuery 中托管的出租车乘坐数据集来估计纽约市的出租车费用。有超过 a 十亿行的大小为 130 GB。你可以在这里找到。这篇文章是基于我在谷歌云平台专业化上使用 TensorFlow 进行机器学习的经验。
首先,我们必须在 Google 云平台上建立一个项目,并启动一个笔记本实例。
这个实例将花费我们大约每小时0.14 美元。我们还需要启用计算引擎 API 并创建一个存储桶。
数据准备
安装 BigQuery 库并预览数据
我们使用 RAND() 函数从这个庞大的数据集中抽取一个小样本。
缺点是我们每次运行这个查询都会得到不同的样本。因此,我们将使用散列函数。
MOD(ABS(FARM_FINGERPRINT(CAST(pickup_datetime AS STRING))), 5000)= 1
此功能使我们能够获得原始数据的 0.02% 的恒定样本。利用整个数据集进行探索需要巨大的计算能力。我计划将来使用整个数据集建立一个模型。
将数据加载到熊猫数据框架中
我们肯定需要清理我们的数据。比如经纬度值关(纬度应该在-90°到 90°之间;经度应该在-180 到 180 之间)。有些行程的票价为负数,有些行程的乘客数为零。
让我们画出行程 _ 距离 vs 车费 _ 金额
一些坏数据被编码为零。此外,我们不打算在预测中包括小费,因为他们往往是不可预测的。我们的目标变量将是票价 _ 金额+通行费 _ 金额
我们的预测值是:
拾取日期时间
收件人 _ 经度
皮卡 _ 纬度
经度下降
下降纬度
我们选择这些是因为它们最符合我们的目标。有人可能会争辩说, trip_distance 可以帮助我们确定费用,但是我们排除了它,因为它并不总是可以提前知道的。我们的项目可能会应用于打车行业,我们可以提前预测出行成本,为了准确起见,应该选择源/目的地的位置坐标而不是 trip_distance。
数据清理
我们遵循以下原则来过滤不合理的数据:
- 票价金额应大于 $2.5
- 出发地/目的地位置坐标应在纽约市限制范围内
- 乘客数量不能为零
- 行程距离不能为零
SELECT
(tolls_amount + fare_amount) AS fare_amount, -- label
pickup_datetime,
pickup_longitude,
pickup_latitude,
dropoff_longitude,
dropoff_latitude
FROM
`nyc-tlc.yellow.trips`
WHERE
-- Clean Data
trip_distance > 0
AND passenger_count > 0
AND fare_amount >= 2.5
AND pickup_longitude > -78
AND pickup_longitude < -70
AND dropoff_longitude > -78
AND dropoff_longitude < -70
AND pickup_latitude > 37
AND pickup_latitude < 45
AND dropoff_latitude > 37
AND dropoff_latitude < 45
-- repeatable 1/5000th sample
AND MOD(ABS(FARM_FINGERPRINT(CAST(pickup_datetime AS STRING))),5000) = 1
让我们通过从 pickup _datetime 中获取 dayofweek 和 hourofday 来创建一些分类特征
SELECT
(tolls_amount + fare_amount) AS fare_amount, -- label
EXTRACT(DAYOFWEEK from pickup_datetime) AS dayofweek,
EXTRACT(HOUR from pickup_datetime) AS hourofday,
------------------
------------------
将数据分为训练集、验证集和测试集
我们将我们的1/5000样本分成 70–15–15
将数据写入 CSV
在接下来的步骤中,我们将使用 TensorFlow 创建一个机器学习模型,它直接从 BigQuery 读取文件很慢。因此,我们将数据写成**。csv** 文件
假设我们只使用了总数据的一个样本(0.02%),我们还有 151k 行可以训练,这已经很不错了。
我们讨论模型创建的下一篇文章可以在这里找到。
在 LinkedIn 上和我联系。你可以在这里找到完整的代码。
干杯!!
使用谷歌云人工智能平台预测纽约市的出租车价格(十亿多行)第 2 部分
Taxis | Photo by Life of Pix on pexels.com
在这一系列文章中,我们正在处理一个真实世界的纽约出租车乘坐数据集,该数据集托管在 BigQuery 中,以便能够估计车费金额。
在上一篇中,我们在 Google 云平台上建立了一个项目,启动了一个预装 TensorFlow 的 AI 笔记本实例,并准备/清理/采样了数据。现在到了我们建立一个模型来预测目标变量的部分。
我们将使用 tf.estimator ,一个高级 TensorFlow API 来构建我们的模型。详细信息可以在这里找到。
使用这个 API 有四个主要步骤。
- 创建一个函数来导入数据集
- 定义特征列
- 实例化评估者
- 培训/评估
创建一个函数来导入数据集
另一种方法是使用tf.data.experimental.make_csv_dataset
函数来读取数据集。
对于较小的数据集,我们可以将它们加载到 pandas 数据帧中,因为它们适合内存。我们可以使用tf.data.Dataset.from_tensor_slices
读取这些数据帧
导入训练和验证集的函数
定义特征列
任何预测分析项目中最重要的步骤之一是特征工程。有了一些经验、领域专业知识和良好的老式尝试和错误,您可以设计出显著改善最终结果的特性。
存储纬度和经度
一个热编码
TF . feature _ column . crossed _ column
使用 TF . feature _ column . crossed _ column 创建一个为我们提供时间和星期组合信息的要素。例如,周五晚上和周日晚上的票价可能会有很大不同。
fc_crossed_day_hr = tf.feature_column.crossed_column(keys = [fc_dayofweek, fc_hourofday], hash_bucket_size = 24 * 7)
创建一个函数,以便我们可以在读取数据的同时创建新的功能。
我们创建坐标之间的欧几里德距离作为一个特征,以及单独的纬度差和经度差,这将为我们提供关于行驶方向的信息。
最后,创建我们决定用来训练模型的特征列的列表,并创建服务输入接收器函数
培训/评估
线性模型
RMSE 是 7.4
现在,让我们使用 DNN 回归器来训练我们的模型,这将更好地理解非线性关系。
我们得到的均方根误差为 4.13
在下一篇文章中,我们将调整超参数来改进这个结果,并对包含 10 亿次以上乘坐的整个数据进行训练。正如你所猜测的,我们不能在我们的笔记本电脑上这样做。是时候转向云计算了。
资源:Google 云平台上 TensorFlow 的机器学习
在 LinkedIn 上与我联系。你可以在这里找到完整的代码。
干杯!!
使用谷歌云人工智能平台预测纽约市的出租车价格(十亿多行)第 3 部分
Taxis | Photo by Nout Gons on pexels.com
这一系列文章的目标是创建一个机器学习模型,能够在乘坐开始之前估计纽约市的出租车费用。这种模式的一个版本已经应用于拼车行业,用户喜欢在选择目的地后立即知道乘车的费用。
在前两篇帖子中,我们在谷歌云平台上创建了一个项目,清理了数据,创建了功能,并最终在本地这个庞大数据集的一个小样本上训练了一个模型。我们能够达到 4.13 的 RMSE。
[## 使用谷歌云人工智能平台预测纽约市的出租车价格(十亿多行)第 1 部分
这个项目旨在创建一个机器学习模型,使用数据集来估计纽约市的出租车费用…
towardsdatascience.com](/predicting-taxi-fares-in-nyc-using-google-cloud-ai-platform-billion-rows-part-1-ac121832babf) [## 使用谷歌云人工智能平台预测纽约市的出租车价格(十亿多行)第 2 部分
在这一系列文章中,我们正在处理一个真实世界的纽约出租车乘坐数据集,该数据集由 BigQuery 托管,以…
towardsdatascience.com](/predicting-taxi-fares-in-nyc-using-google-cloud-ai-platform-billion-rows-part-2-f0191a70dea8)
在这篇文章中,我们对整个数据集进行训练,并执行超参数调整。我们开始吧。
我已经将来自 Bigquery 的整个 130 GB 数据集作为分片 CSV 文件存储到我在 GCP 的存储桶中。TensorFlow 可以直接从 BigQuery 中读取,但这个过程非常慢,而且最好是使用 CSV 文件,就像我在之前的帖子中使用示例所做的那样。
云人工智能平台
在云上训练有两个主要步骤:
- 把代码做成 Python 包(创建 **init)。py、task.py、**和 model.py 文件)
- 将使用 gcloud 的 Python 包提交到云 AI 平台
创建 task.py
%%writefile your_path/task.py
import argparse
import json
import osfrom . import modelif __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--hidden_units",
help = "Hidden layer sizes,
type = str,
default = "16,16"
)
parser.add_argument(
"--train_data_path",
help = "Path to training data",
required = True
)
parser.add_argument(
"--train_steps",
help = "Training steps",
type = int,
default = 1000
)
parser.add_argument(
"--eval_data_path",
help = "Path to evaluation data",
required = True
)
parser.add_argument(
"--output_dir",
help = "Output Directory",
required = True
)
parser.add_argument(
"--job-dir",
help="Required by gcloud",
)
args = parser.parse_args().__dict__
# Append trial_id r
args["output_dir"] = os.path.join(
args["output_dir"],
json.loads(
os.environ.get("TF_CONFIG", "{}")
).get("task", {}).get("trial", "")
)
# Run
model.train_and_evaluate(args)
创建 model.py
需要优化的超参数需要作为命令行参数传入
%%writefile your_path/model.py
import tensorflow as tf
import numpy as np
import shutil
print(tf.__version__)CSV_COLUMN_NAMES = ["fare_amount","dayofweek","hourofday","pickuplon","pickuplat","dropofflon","dropofflat"]
CSV_DEFAULTS = [[0.0],[1],[0],[-74.0],[40.0],[-74.0],[40.7]]def read_dataset(csv_path):
def _parse_row(row):
# Every row into a list of tensors
fields = tf.decode_csv(records = row, record_defaults = CSV_DEFAULTS)# All the features into a dictionary
features = dict(zip(CSV_COLUMN_NAMES, fields))
# Feature Engineering
features = add_engineered_features(features)
# Pop the fare_amount
label = features.pop("fare_amount")return features, label
# Create a dataset
dataset = tf.data.Dataset.list_files(file_pattern = csv_path) # (i.e. data_file_*.csv)
dataset = dataset.flat_map(map_func = lambda filename:tf.data.TextLineDataset(filenames = filename).skip(count = 1))
dataset = dataset.map(map_func = _parse_row)
return datasetdef train_input_fn(csv_path, batch_size = 128):
# Create the training dataset
dataset = read_dataset(csv_path)
# Shuffle
dataset = dataset.shuffle(buffer_size = 1000).repeat(count = None).batch(batch_size = batch_size)
return datasetdef eval_input_fn(csv_path, batch_size = 128):
# Create the Validation dataset
dataset = read_dataset(csv_path)# Shuffle and batch
dataset = dataset.batch(batch_size = batch_size)
return dataset
# One Hot Encoding
fc_dayofweek = tf.feature_column.categorical_column_with_identity(key = "dayofweek", num_buckets = 7)
fc_hourofday = tf.feature_column.categorical_column_with_identity(key = "hourofday", num_buckets = 24)# Bucketize latitudes and longitudes
NBUCKETS = 16
latbuckets = np.linspace(start = 38.0, stop = 42.0, num = NBUCKETS).tolist()
lonbuckets = np.linspace(start = -76.0, stop = -72.0, num = NBUCKETS).tolist()
fc_bucketized_plat = tf.feature_column.bucketized_column(source_column = tf.feature_column.numeric_column(key = "pickuplon"), boundaries = lonbuckets)
fc_bucketized_plon = tf.feature_column.bucketized_column(source_column = tf.feature_column.numeric_column(key = "pickuplat"), boundaries = latbuckets)
fc_bucketized_dlat = tf.feature_column.bucketized_column(source_column = tf.feature_column.numeric_column(key = "dropofflon"), boundaries = lonbuckets)
fc_bucketized_dlon = tf.feature_column.bucketized_column(source_column = tf.feature_column.numeric_column(key = "dropofflat"), boundaries = latbuckets)# Crossed Column
fc_crossed_day_hr = tf.feature_column.crossed_column(keys = [fc_dayofweek, fc_hourofday], hash_bucket_size = 24 * 7)def add_engineered_features(features):
features["latdiff"] = features["pickuplat"] - features["dropofflat"]
features["londiff"] = features["pickuplon"] - features["dropofflon"]
features["euclidean_dist"] = tf.sqrt(x = features["latdiff"]**2 + features["londiff"]**2)
features["dayofweek"] = features["dayofweek"] - 1return features#1\. Created using tf.feature_column module
tf.feature_column.indicator_column(categorical_column = fc_crossed_day_hr),
fc_bucketized_plat,
fc_bucketized_plon,
fc_bucketized_dlat,
fc_bucketized_dlon,
#2\. Created in the input functions
tf.feature_column.numeric_column(key = "latdiff"),
tf.feature_column.numeric_column(key = "londiff"),
tf.feature_column.numeric_column(key = "euclidean_dist")
]def serving_input_receiver_fn():
receiver_tensors = {
'dayofweek' : tf.placeholder(dtype = tf.int32, shape = [None]), # shape is vector to allow batch of requests
'hourofday' : tf.placeholder(dtype = tf.int32, shape = [None]),
'pickuplon' : tf.placeholder(dtype = tf.float32, shape = [None]),
'pickuplat' : tf.placeholder(dtype = tf.float32, shape = [None]),
'dropofflat' : tf.placeholder(dtype = tf.float32, shape = [None]),
'dropofflon' : tf.placeholder(dtype = tf.float32, shape = [None]),
}
features = add_engineered_features(receiver_tensors) # 'features' is what is passed on to the model
return tf.estimator.export.ServingInputReceiver(features = features, receiver_tensors = receiver_tensors)
def train_and_evaluate(params):
OUTDIR = params["output_dir"]model = tf.estimator.DNNRegressor(
hidden_units = params["hidden_units"].split(","),
feature_columns = feature_cols,
model_dir = OUTDIR,
config = tf.estimator.RunConfig(
tf_random_seed = 1, # for reproducibility
save_checkpoints_steps = max(100, params["train_steps"] // 10)
)
)def my_rmse(labels, predictions):
pred_values = tf.squeeze(input = predictions["predictions"], axis = -1)
return {"rmse": tf.metrics.root_mean_squared_error(labels = labels, predictions = pred_values)}
model = tf.contrib.estimator.add_metrics(model, my_rmse)train_spec = tf.estimator.TrainSpec(
input_fn = lambda: train_input_fn(params["train_data_path"]),
max_steps = params["train_steps"])exporter = tf.estimator.FinalExporter(name = "exporter", serving_input_receiver_fn = serving_input_receiver_fn)eval_spec = tf.estimator.EvalSpec(
input_fn = lambda: eval_input_fn(params["eval_data_path"]),
steps = None,
start_delay_secs = 1,
throttle_secs = 1,
exporters = exporter)tf.logging.set_verbosity(v = tf.logging.INFO) # so loss is printed during training
shutil.rmtree(path = OUTDIR, ignore_errors = True) # start fresh each timetf.estimator.train_and_evaluate(model, train_spec, eval_spec)
创建超参数调整配置
云 AI 平台默认使用贝叶斯优化。当只调整几个参数时,我们也可以使用网格搜索或随机搜索。
这里我们只调整一个参数,即隐藏单元的数量。所有试验都是平行进行的。
启用 AI 平台 API
运行培训作业
我们可以在数据集的一部分上运行这个来获得更好的想法,然后在整个数据上尝试最佳组合。
我发现隐藏单元的最佳配置是“ 64,64,64,8 ”,RMSE 为 3.98。
我们的三部分系列到此结束。通过采用不同的方法,如设计新功能、选择不同的模型、调整更多的超参数等,可以实现许多改进。创造最好的模型需要耐心和大量的尝试和错误。
资源:Google 云平台上 TensorFlow 的机器学习
在 LinkedIn 上与我联系。你可以在这里找到完整的代码。
干杯!!
使用更少的数据预测更多训练数据的效果
使用地理空间深度学习的案例研究,一步一步地估计增加的训练数据的价值
A satellite image and its building footprint ground truth mask from our geospatial case study.
场景是这样的:你付出了巨大的困难和代价来收集一些训练数据,并使用这些数据来训练一个深度神经网络。然而,你发现自己在想,“我有足够的钱吗?”更多的训练数据会带来有意义的性能提升吗,或者只是为了无关紧要的收益而浪费时间和金钱?起初,这看起来几乎是矛盾的:如果不知道收集更多数据会有多大帮助,你就无法做出明智的决定,但除非你已经做出决定并获得了额外的数据,否则你无法衡量它会有多大帮助。
然而,有一个解决办法。通过用现有的不同大小的训练数据子集重复训练深度神经网络,有可能将性能外推至超出目前可用的训练数据量。
我们将使用计算机视觉领域的一个重要的测试案例来完成这个过程:在卫星照片中描绘出建筑物的轮廓。自动绘制建筑物地图的能力,而不是每次事情发生变化都依赖大量的人工劳动,其应用范围从救灾到城市规划。
我们的案例研究:在卫星图像中构建足迹
数据
要对卫星图像进行研究,我们需要从获取一些图像开始!为此,我们求助于 SpaceNet ,它维护着一个免费、开源、随时可用的数据存储库,存储了数千平方公里的带标签的高分辨率卫星图像。
我们将使用 SpaceNet 的最新(截至本文撰写时)数据发布:Maxar 的 WorldView-2 卫星在佐治亚州亚特兰大上空采集的一系列数据。影像中包含高质量的建筑物覆盖区(轮廓)标注。这个数据集是现在已经完成的 SpaceNet4 挑战的基础。这些影像从 27 个不同的视角显示了同一区域,这使得它非常适合研究视角如何影响地理空间深度学习算法的性能。为了简单起见,我们将我们的结果分为三类:“天底”,视角在天底 25 度以内(垂直向下),“离天底”,视角从天底 26 度到 40 度,以及“远离天底”,视角超过天底 40 度。我们还将“总体”绩效定义为三个类别绩效的简单平均值。图 1 示出了从不同角度成像的例子。
Fig. 1: Different viewing angles for the same physical location, including (a) an on-nadir view, (b) an off-nadir view from the north, and © a far-off-nadir view from the south. Image (d) shows the corresponding building footprint mask, used in training to tell the model what is or isn’t a building.
模型
我们将训练的寻找建筑物的模型也来自 SpaceNet。我们将使用第五名提交的 SpaceNet4 挑战赛。虽然其他一些提交稍微优于这个模型,但这个模型由于其快速的推理时间和简单的架构而更受欢迎。该模型的推理速度比顶级 SpaceNet4 获胜者快十倍以上。它使用带有 VGG-16 编码器的 U-Net 进行像素分割,然后根据像素图生成建筑物覆盖区多边形。为了加快训练,最初提交的三个神经网络的集合被削减为一个网络,仅导致适度的性能下降,这在别处讨论过。
为了量化模型性能,为模型识别的建筑足迹计算 F1 分数。出于计算目的,如果一个占地面积与地面真实建筑占地面积的 IoU (交集/并集)至少为 0.5,则认为该占地面积是正确的。
结果呢
若要了解模型性能如何依赖于训练数据量,请使用不同的数据量对同一模型进行训练。
数据被切割成 900 像素的方块,每个方块显示 450 米的面积。平均每个瓦片有 63 个建筑。在训练数据中有 1064 个独特的图块位置,每个位置有 27 个视图。由于我们的算法留出了四分之一的数据用于验证,因此对完整数据集的训练给了我们 1064 * 27 * (3/4) = 21546 幅图像。图 2 显示了如果我们用更少的数据训练会发生什么。训练和评估过程重复十次。但是每一次,我们从零开始,使用的数据只有上次的一半。当数据不足时,性能会随着新数据的增加而迅速提高,但当数据充足时,回报会逐渐减少。
Fig. 2: Model performance, as measured by F1 score, versus number of training images. Images are 900x900 pixel regions of satellite photos with 0.5m resolution.
既然我们都同意我们的案例研究,是时候把它作为解决我们主要问题的环境了:在数据可用之前,我们如何用大量数据对模型性能做出有根据的猜测?要做到这一点,有几个步骤。
第一步:知道何时停止训练
对于这个过程,我们将需要使用不同数量的数据从头开始多次训练模型。如果模型是硬编码的,以训练一定数量的时期或一定数量的时间(无论是使用该时期后的最终权重还是最佳中间权重),则值得努力研究所有这些时间是否真的有必要。图 3 示出了对于不同数量的数据,作为训练时间的函数的模型性能。最上面的一行使用完整的数据集,随后的每一行使用其上一行的大约一半的训练数据。
Fig. 3: Model performance, as measured by F1 score, versus amount of training time. Training time is expressed as number of image views and also approximate GPU-days on Nvidia Titan Xp GPUs.
回想一下,当训练数据集大小减半时,训练时期的数量必须加倍,以获得相同的图像视图总数。但是,达到最高性能所需的图像视图数量可能会随着数据的减少而减少。对于我们的地理空间案例研究,使用 21546 幅图像的完整训练数据集,需要大约 60 个历元才能达到最佳性能。但是当只使用了几百个图像时,必要的图像视图的数量下降到低于全部训练数据集的 5 个时期的当量。使用完整的数据集进行训练大约需要四个 GPU 日(在 Nvidia Titan Xp 上)。虽然这是不可避免的,但知道我们至少可以在减少数据的情况下进行较少的培训,这带来了一些值得欢迎的时间节省。
一旦我们用不同数量的数据进行了训练,并评估了模型的每个版本,我们就可以在图 2 中绘出这些点。但是我们还没有准备好去拟合一条曲线。
步骤 2:生成误差线
许多深度学习论文引用性能数据时没有误差线。然而,在没有误差线的情况下,不清楚观察到的性能改进是否具有统计意义,或者结果是否可重复。对于我们的外推任务,误差线是必要的。在案例研究中,我们有十个数据点,每个数据点代表不同数量的训练数据。为了节省时间,我们将只计算其中四个的误差线,并对其余的进行对数插值。为了计算误差线,我们只需用给定数量的数据多次重复模型训练/测试过程,并取结果的标准偏差。图 4 示出了与图 2 相同的信息,但是具有对数 x 轴以更好地显示少量数据的误差条。
Fig. 4: Identical to Fig. 2, but with a logarithmic x-axis.
我将在后续研究中使用的一种更好的方法是,针对所考虑的每个训练数据量重复训练模型,然后绘制一个不是单个结果而是每个训练数据量的结果平均值的图。
第三步:拟合曲线
接下来,为了理解 F1 分数对训练数据量的依赖性,我们希望能够对这些变量的关系进行建模,最好是用一条简单的曲线。
为了获得灵感,我们求助于文献。关于我们特定类型的案例研究(地理空间环境中语义分割的 F1 分数的数据大小依赖性)还没有太多的著述。但是深度学习分类问题已经有了很多工作[ 1 、 2 、 3 、 4 ]。对于这些,发现精度的数据集大小依赖性与常数减去逆幂律项成比例(图 5)。令人高兴的是,相同的函数形式非常适合我们的测试用例,尽管这不是一个分类问题。事实上,图 2 和图 4 中虚线所示的拟合曲线是使用这种函数形式生成的。
Fig. 5: A constant minus an inverse power law. The variable x is the amount of training data; y is the estimated F1 score; and a, b, and c are positive free parameters.
一旦我们有了一条拟合曲线,我们就可以用它来推断给定的大量数据的性能。总结一下这个过程:用不同数量的数据训练同一个模型,估计每个数量的误差线,并使用加权回归来生成一个简单的模型,说明性能如何随训练数据的数量而变化。现在是时候尝试这个过程了,看看在训练数据量有限的情况下它的表现如何。
对方法进行测试
假设我们没有完整的训练数据集,只有它的十六分之一。只有 1,323 张图像需要训练,而不是 21,546 张,我们希望通过获取 16 倍的训练数据来评估改进。图 6 显示了当我们遵循上面的三个步骤时会发生什么。这里,我们在拟合曲线时简单地忽略了超过 1,323 个图像的点。这种测试有些人为,因为低训练数据样本并不局限于从全部数据集的十六分之一中抽取。然而,预计这不会实质性地改变结果。
Fig. 6: F1 score vs. amount of training data (solid lines), along with fitted curves (dotted lines) that are based on only the points with 1,323 training images or fewer.
从 1,323 幅图像开始,表 1 显示了将训练数据增加一倍和将其增加 16 倍后的实际和预测性能提高。在每一种情况下,预测都是正确的,误差在 2 倍以内,在大多数情况下,误差在 25%以内。这些数字指的是 F1 分数中的估计改进,而估计 F1 分数本身的百分比误差要低得多。随着训练数据的增加,测量和预测的结果往往会逐渐偏离。然而,F1 分数随着更多的数据而增加,这限制了百分比误差的增长。因此,在这个案例研究中,该方法给出了训练数据增长 16 倍的估计值,这与其仅增长 2 倍的估计值相当。作为比较,用简单的对数曲线拟合数据,而不是常数减去幂律,会产生最大百分比误差,几乎是这里看到的两倍。
Table 1: Comparison of measured and estimated improvement with a 2-fold data increase and a 16-fold data increase. “Measure” is the actual increase in F1 score, “predict” is the increase predicted by the model, and “% Error” is the percentage error between them.
结论和警告
在这个建筑物占地面积案例研究中,我们可以预测训练数据从 16 倍增长到 2 倍以内的性能改善。虽然在数据科学中没有放之四海而皆准的解决方案,但这种方法可以帮助您在下一次发现自己不知道是否要获取更多训练数据时做出决定。
有几个警告值得一提。在这种外推方法中隐含了一种假设,即我们已经拥有的训练数据和我们可能获得的新训练数据来自同一分布。例如,如果我们试图获取的新的训练数据来自不同的城市,或者来自同一城市的不同部分,它们在整体外观上与我们已经可用的数据源不同,那么这就不成立。即使假设成立,也不能保证 F1 分数对训练数据集大小的依赖性与本案例研究中看到的一样。没有一种方法可以取代深思熟虑的判断和对数据独特性的深刻理解。然而,这可能是为您的数据科学项目做出最佳决策的建设性起点。
用泊松过程预测小行星撞击的频率
泊松过程和泊松分布在模拟地球小行星撞击中的应用
这里有一些好消息:如果你花了几个小时通过阅读理论书籍和课堂笔记来研究一个概念,但你似乎无法理解,有一种更好的学习方法。从理论开始总是困难和令人沮丧的,因为你看不到一个概念最重要的部分:如何用它来解决问题。相比之下,边做边学——解决问题——更有效,因为它给你背景,让你把技巧融入你现有的思维框架。此外,对于那些被解决问题的内在愿望所驱动的来说,通过应用程序学习更令人愉快。
在本文中,我们将应用泊松过程和泊松分布的概念来模拟地球小行星撞击。我们将在中介绍的原则基础上构建泊松过程和泊松分布解释,用真实世界的数据将想法付诸实践。通过这个项目,我们将了解如何使用统计概念来解决问题,以及如何将观察到的结果与理论上的预期结果进行比较。
本文的完整代码(包括交互式应用)可以通过点击图片在 mybinder.org 上运行。Jupyter 笔记本在 GitHub 上。
Click to launch a Jupyter Notebook on mybinder.org for this article.
Probability Mass Function of Number of Asteroid Impacts
泊松过程和泊松分布基础
我们不会涵盖全部细节(见此处),但这些是我们需要的基本信息:泊松过程是一个罕见事件的模型——比如小行星撞击——其中我们知道事件之间的平均时间,但任意两个事件之间的实际时间是随机分布的(随机)。每个事件都是独立于所有其他事件的,这意味着我们不能使用自上一个事件以来的时间来预测下一个事件将在何时发生。泊松模型是二项式模型的扩展,适用于预期成功次数远少于试验次数的情况。
泊松过程中的每个子区间都是伯努利试验,事件要么发生(成功),要么不发生。在我们的小行星例子中,事件是小行星撞击,子间隔是一年,所以每年,撞击要么发生,要么不发生(我们假设每年最多一次撞击,并且撞击是独立的)。幸运的是,小行星撞击很少发生,所以与我们将要考虑的年数(试验)相比,成功的总数很低。此外,我们知道撞击的平均间隔时间(我们从数据中获得),但不知道撞击发生的确切时间。
为了计算在一个时间间隔内发生的大量泊松过程生成事件的概率,我们使用泊松分布和概率质量函数(PMF):
Poisson Probability Mass Function (PMF) Distribution
其中事件/时间是频率,如影响/年。这个公式有些复杂,所以我们将(事件/时间)*时间简化为一个参数, λ。 Lambda 是分布的速率参数,也是我们定义泊松所需的唯一参数:
Poisson PMF
Lambda 是时间段内事件的预期(最有可能)数量。当我们改变λ时,不同数量的事件的概率改变:
Poisson PMF Distribution with differing values of lambda (rate parameter)
最后,事件之间的时间分布(等待时间)是一个指数衰减。事件之间等待时间超过 t 的概率为:
Probability of waiting longer than t in a Poisson process
泊松过程中的等待时间是*无记忆的,意味着它们彼此不依赖。事件之间的平均等待时间为 1 /频率。泊松分布很容易理解,因为它只需要一个参数,即频率参数,即间隔内事件的预期数量,或频率时间。
小行星撞击数据
为了使用泊松过程和小行星撞击的分布,我们需要的是小行星撞击的平均频率。坏消息是没有足够的数据来精确地确定利率。好消息是,科学家们已经根据我们现有的数据(如近地小行星的数量)和稳健的模拟得出了一些估计。我们将使用近地天体科学定义小组的 NASA 2017 年报告中的数据,在大量有趣的信息中,这些数据提供了对不同大小的小行星撞击频率的估计。
一旦我们加载了数据并清理了列,我们就有了这些数据:
Data from NASA 2017 NEO SDT (5 of the 27 rows)
每一行都是不同大小的小行星(平均diameter
公里),关键列是impact_frequency
。这给出了每年撞击的平均次数,我们可以通过取倒数将其转换成time_between_impacts
。impact_frequency
随着体积的增大而减小,因为大的小行星较少(由number
指定)。
虽然这不是必须的,但我喜欢从数据分析开始,比如按直径查看撞击能量或按直径查看撞击间隔时间:
请注意,这两个图都是对数标度,撞击能量以百万吨当量 TNT 表示。作为比较,最大的人体炸弹大约是 100 兆吨,而最大的小行星是 1000 万兆吨(在地球附近只有两个)。从撞击间隔时间图来看,随着小行星的大小增加到撞击间隔超过 1 亿年,撞击的频率迅速降低。
为了探索数据,笔记本中有一个交互式探索工具。
Interactive data exploration tool in notebook.
根据数据探索,我们应该预计来自较大小行星的撞击较少,因为它们的撞击频率较低。如果我们的建模结果与这个结论不一致,那么很可能有问题!
模拟小行星撞击
我们的目标是确定每个大小类别中预期影响数量的概率分布,这意味着我们需要一个时间范围。为了保持客观,我们从 100 岁开始,大约是一个人的寿命。这意味着我们的分布将显示人类一生中撞击次数的概率。因为我们使用的是概率模型,所以我们进行了多次试验,然后得出结果的分布,而不是使用一个数字。对于一个大样本,我们将对一个人的一生模拟 10,000 次。
在 Python 中使用np.random.poisson
函数模拟泊松分布很简单,该函数根据给定速率参数lam
的泊松分布生成大量事件。为了运行 10,000 次试验,我们将其设置为size
。下面是运行最小小行星类别撞击频率模拟的代码。
# Simulate 1 lifetime 10,000 times
years = 100
trials = 10_000# Extract the first frequency and calculate rate parameter
freq = df['impact_frequency'].iloc[0]
lam = freq * years# Run simulation
impacts = np.random.poisson(lam, size=trials)
结果在直方图中最直观:
Simulation results showing frequency of each number of impacts
我们看到,在 10,000 次模拟寿命中,最常见的撞击次数是 0。鉴于 rate 参数的值(这是最有可能的结果),这是意料之中的:
print(f'The most likely number of impacts is {lam:.2f}.')**The most likely number of impacts is 0.47.**
(由于泊松分布仅在离散数量的事件中定义,我们应该将其四舍五入为最接近的整数)。
为了将模拟结果与理论预期结果进行比较,我们使用泊松概率质量函数和速率参数计算了每次撞击的理论概率:
from scipy.special import factorial# Possible number of impacts
n_impacts = np.arange(0, 10, 0.25)# Theoretical probability of each number of impacts
theoretical = np.exp(-lam) * (
np.power(lam * n_impacts) / factorial(n_impacts))
(我们使用分数事件来获得平滑曲线。)
然后,我们将它绘制在条形的顶部(在归一化以获得概率之后):
Observed and theoretical number of impacts over 100 years for the smallest asteroids.
当观察到的(在这种情况下是模拟的)结果与理论相符时,感觉真好!我们可以使用相同的poisson
函数和矢量化numpy
运算将我们的分析扩展到所有大小的小行星:
# Each trial is a human lifetime
trials = 10000
years = 100# Use all sizes of asteroids
lambdas = years * df['impact_frequency'].values
impacts = np.random.poisson(lambdas, size=(10000, len(lambdas)))
impacts.shape**(10000, 27)**
这给了我们 27 种大小的小行星中每一种的一万次生命模拟。为了直观显示这些数据,我们将绘制每个尺寸范围的平均冲击次数以及预期冲击次数(速率参数)。
Average observed and theoretical number of impacts for all asteroid sizes.
同样,结果与理论相符。对于大多数小行星来说,一生中观察到一次撞击的机会微乎其微。
对于另一个可视化,我们可以绘制所有小行星大小的泊松 PMF:
Poisson PMF for all asteroids
在超过 100 年的时间里,最有可能的影响次数是 0。对于我们这些生活在 2013 年的人来说,我们已经经历了一次小行星事件(尽管不是撞击),当时一颗直径 20 米(0.02 公里,此处使用的单位)的近地小行星在车里雅宾斯克州上空爆炸。然而,因为泊松过程的等待时间是无记忆的,所以得出现在看到另一次小行星撞击的可能性较低的结论是错误的,因为最近就有一次。
增加模拟长度以获得更多影响
为了看到更多的影响,我们可以在更长的时间内运行模拟。由于属人(我们的属)已经存在了 200 万年,让我们运行 200 万年的 10000 次模拟,看看小行星撞击的预期次数。我们所要做的就是改变年数,这反过来会影响速率参数。
# Simulate 2 million years 10,000 times
years = 2_000_000
trials = 10_000# Run simulation for all asteroid sizes
lambdas = years * df['impact_frequency'].values
impacts = np.random.poisson(lambdas, size=(10000, len(lambdas)))
绘制模拟的和理论的平均撞击次数,这次是以对数标度,我们得到以下结果:
Observed and theoretical asteroid impacts over 2 million years.
现在我们观察到更多的影响,这是有意义的,因为我们正在考虑一个更长的时间段。
超过 200 万年的所有小行星的泊松 PMF 是:
Poisson PMF for all asteroid sizes over 2 million years.
同样,预期(平均)撞击次数将是每个小行星大小的速率参数 λ 。
对于长期的模拟,我们确实观察到了较大小行星的撞击。
Observed and theoretical impacts for larger asteroids over longer time period
记住,在俄罗斯上空爆炸的车里雅宾斯克流星直径是 20 米(0.020 公里)。我们正在谈论这张图表中的一些大质量小行星。
撞击间隔时间
我们可以使用泊松过程模型的另一种方法是计算事件之间的时间。事件之间的时间超过 t 的概率由以下等式给出:
计算理论值非常简单:
# Frequency for smallest asteroids
freq = df['impact_frequency'].iloc[0]# Possible waiting times
waiting_times = np.arange(0, 2500)
p_waiting_times = np.exp(-freq * waiting_times)
这种关系遵循指数衰减规律:
Probability distribution for waiting time between asteroid impacts.
为了使用实际数据模拟等待时间,我们可以将 1 亿年建模为单独的伯努利试验(影响或不影响)。每一年成功的概率只是频率。等待时间就是两次撞击之间的年差(对最小的小行星进行研究):
years = 100_000_000# Simulate Bernoulli trials
impacts = np.random.choice([0, 1], size=years, p=[1-freq, freq])# Find time between impacts
wait_times = np.diff(np.where(impacts == 1)[0])
将其绘制成直方图,得出以下结果:
Observed waiting time between asteroid impacts for smallest asteroids.
为了确保观察到的数据与理论相符,我们可以将这两者绘制在彼此之上(归一化和宁滨后):
Waiting time observed and theoretical for smallest size of asteroids.
作为最后一幅图,我们可以看看所有小行星大小的平均撞击间隔时间,包括观察到的(模拟的)和理论上的:
Average observed and theoretical waiting time between impacts for all asteroid sizes.
即使超过 1 亿年,最大的小行星也没有受到撞击(或者只有一颗,这意味着我们无法计算等待时间)。这是有道理的,因为撞击之间的预期时间超过 1 亿年!
交互作用分析
笔记本的最后一部分是一个交互式分析,您可以使用参数来观察效果。您可以更改运行模拟的时间长度、要检查的直径以及试验次数。
Interactive asteroid impacts analysis in Jupyter Notebook.
我鼓励你亲自进行分析,看看这些参数如何改变结果,方法是到mybinder.org的 Jupyer 笔记本上。
结论
在学校的时候,我有过很多次这样的经历:在课堂上,我认为我对一个主题的理解是完整的,但却打开了作业,不知道从哪里开始。这种理论与应用的不匹配在家庭作业中已经够糟糕了,当涉及到现实世界的问题时甚至更糟。直到我大学的最后两年,当我开始通过做问题来学习时,我应用概念的能力(同样重要的是,我在学习中的快乐)才得到发展。虽然理论仍然很重要(我通常会在看到使用中的概念后再回去研究),但仅仅通过严格的推导很难掌握一个概念。
任何时候你遇到一个你难以理解的话题,寻找真实世界的数据,并开始尝试用这种技术解决问题。在最坏的情况下,你仍然会被卡住(记住寻求帮助是好的),但在最好的情况下,你会掌握方法,并享受学习过程。
在本文中,我们看到了如何将统计概念(泊松过程模型和泊松分布)应用到现实世界中。虽然小行星可能不会影响我们的日常生活,但这个项目显示了我们可以应用于其他类似问题的方法的潜在用途。由于问题的多样性,数据科学需要不断扩展自己的技能。每当我们学习一项新技术时,我们会变得更有效,如果我们能通过将一个概念应用到新数据中来享受这个过程,那就更好了。
一如既往,我欢迎反馈和建设性的批评。你可以在推特上找到我。
预测(音乐的)未来
利用 Python 和线性回归预测音乐流行度
泰勒·福格蒂,彼得·伍斯特,拉塔·古德尔
在大数据时代,我们在预测方面拥有空前的优势。有了像 Kaggle.com 和 OurWorldinData.org 这样的网站,我们手头有无穷无尽的数据——我们可以用这些数据来预测 2020 年谁会赢得 NCAA 锦标赛,下个月全球会卖出多少鳄梨,或者 10 年后芝加哥的犯罪率。当然这些都还是预测,但是这些预测没有合适的数据是做不出来的。
例如,我们花了一个美丽的夏日进行测试,看看你能否根据一组给定的指标预测一首歌在 Spotify 百强排行榜上的排名。
https://variety.com/2018/music/news/spotify-reveals-its-top-songs-of-the-summer-1202917332/
目标和数据描述
**重要提示:**在评估和比较模型时,应该使用所有这 3 个指标。就我们的目的而言,它们被分成“方法”,但是为了最好地评估一个模型的准确性,应该结合使用。
方法 1:误差分析
一旦开发出一个模型,下一步就是看它的表现如何。为了衡量模型的成功,数据科学家开发了误差指标来判断预测值和实际值的匹配程度。我们的预期值和预测值之间的差异被称为残差集,本质上是数据与我们用来预测的拟合回归线有多远的度量。虽然我们可以检查每个数据点的残差来衡量模型的有用性,但对于大型数据集来说,这可能特别繁琐。有许多统计数据总结了残差,但我们将坚持使用均方误差、平均绝对误差、均方根误差和平均绝对百分比误差。
为了解释这些,让我们来看一下我们的简化模型,它是通过逐步选择过程建立的*:
人气=响度+活跃度+节奏+关键
均方差和均方根误差是目前最常用的误差指标。MSE 是残差平方的平均值,通常被称为模型的方差。RMSE 是 MSE 的平方根,或模型的标准差,最适用于比较不同模型之间的差异,因为 RMSE 的单位与目标变量相同。使用 scikit-learn 库可以很容易地找到这两者:
mse = mean_squared_error(test_act,predicted)
print(mse) #Mean Square Error
math.sqrt(mse) #Root Mean Square Error
该模型的均方误差和 RMSE 分别为 2196.52 和 46.87。这意味着当你记住我们的目标只是从 1 到 100 时,数据是非常分散的。然而,如果你看看下面的残差图,虽然预测的流行度与实际排名相差甚远,但似乎有一个异常值,或者至少是一个意想不到的值。我们应该记住,MSE 和 RMSE 可能会受到异常值的严重影响,因为残差是平方的,并查看其他指标。
我们还可以使用平均绝对误差,它可以更好地解释异常值,因为它采用残差的绝对值,而不是对它们求平方。这也可以通过平均绝对百分比误差来报告,即百分比当量。也可以使用 scikit 找到 MAE 学习起来非常容易:
mae = mean_absolute_error(test_act,predicted)
print(mae) #Mean Absolute Error
同样,考虑到我们所拥有的数据,这个值 46.42 是很高的,所以我们可以得出结论,在给定这些参数的情况下,该模型很难准确预测一首歌的流行度。然而,我们仍然希望找到一个模型来估计一首歌的受欢迎程度,所以我们将继续使用一些不同的预测方程和一些不同的评估指标。
方法二:测定
相反,我们可以通过查看 R 平方和调整后的 R 平方值来评估基于确定的模型。前者通常称为决定系数,是模型解释的可变性的百分比,或数据与回归线的拟合程度。目标是使 R 的平方为 1,这意味着模型可以解释 100%的变化,但由于随机误差,这种情况很少发生。大多数统计分析会查看 R 平方值来评估模型的准确性,因此使用 scikit-learn 也很容易找到:
model = LinearRegression()
model.fit(X, y)
R = model.score(X, y)
print(R)
不幸的是,完整模型的 R 平方并不高,为 0.164。该模型仅解释了 16.4%的变化,这意味着大约 84%的变化来自其他地方,无论是来自我们没有的第 14 个变量,还是来自歌曲的流行程度是随机的。为了更好地理解这个模型有多精确,我们还应该看一下调整后的 R 平方,它惩罚了一个模型,因为它包含了没有添加到变异解释中的变量。本质上,如果我们有一个非常简化的流行度=节奏的模型,并决定看看是否增加能量,流行度=节奏+能量,并且增加能量并没有使预测更接近,调整后的 R 平方会减少。这一点很重要,因为未调整的 R 平方总是会随着更多参数的增加而增加,但这可能会导致模型过度拟合。我们可以在下面看到这出戏,我们从除了响度和持续时间之外的所有参数的简化模型开始。通过重新加入这些变量,未调整的 R 平方增加很少,但调整后的 R 平方明显减少。
model = LinearRegression()
model.fit(X, y)
aR = 1 - (1-model.score(X, y))*(len(y)-1)/(len(y)-X.shape[1]-1)
print(aR)
正如你所看到的,调整后的 R 平方比未调整的 T2 低得多,这表明该模型包含了无助于预测的参数。所以,让我们回头看看我们的预测方程:
人气=速度+基调+活跃度+响度
X = data.iloc[:100,3:16]
y = data.iloc[:100,16:]
X = X[['liveness','loudness','key','tempo']]model = LinearRegression()
model.fit(X, y)
print(str(model.score(X, y))) #R-squared
print(str(1 - (1-model.score(X, y))*(len(y)-1)/(len(y)-X.shape[1]-1))) #adjusted R-squared
虽然未调整的 R 平方下降到 13.3%,但调整后的 R 平方增加到 9.6%,这使我们有信心这是一个比完整模型更好的模型。可悲的是,它仍然是一个可怜的模型。我们不能用这个模型准确地做出预测,但这是我们最好的…
方法 3:信息标准
现在,假设我们想要比较这个模型比完整模型好多少。为此,我们将使用两个指标:赤池信息标准(AIC)和贝叶斯信息标准(BIC) 。与误差统计和决定系数相比,这两个评估器的使用频率较低,但在比较模型时非常有用。
AIC 和 BIC 都衡量模型的质量,并解释过度拟合和欠拟合的模型。两者之间的主要区别是 BIC 倾向于简约的模型,惩罚复杂性或添加更多类似于调整后的 R 平方的参数。
#function to calculate the Akaike Information Criterion
def AICcalc(X):
y = X['popularity']
del X['popularity']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1) #takes training set
model = LinearRegression()
model.fit(X_train, y_train) #fits linear regression line to training data
inter = model.intercept_
betas = model.coef_
y_pred = model.predict(X_test) #predicts popularity of test data
residuals = y_test - y_pred #finds difference between actual popularity and predicted popularity
K= len(betas)
n= len(X_test)
AIC = float(n*math.log(sum(residuals**2)/n) + 2*K) #calculates AIC
X['popularity'] = popularity
return AICdef BICcalc(X):
y = X['popularity']
del X['popularity']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)
model = LinearRegression()
model.fit(X_train, y_train)
inter = model.intercept_
betas = model.coef_
y_pred = model.predict(X_test)
residuals = y_test - y_pred
K= len(betas)
n= len(X_test)
BIC = float(K*math.log(n) + n*math.log(sum(residuals**2)/n)) #calculates BIC
X['popularity'] = popularity
return BIC
对于具有取自数据的随机训练集的完整模型,AIC 和 BIC 分别是 94.446 和 100.373。正如您所猜测的,由于更多参数的惩罚因子,BIC 略高。然而,AIC 和 BIC 经常被报道与最佳车型相比较。
为了比较这些模型,我们对每个模型进行了 10,000 次迭代计算,以找出 AIC 和 BIC 的平均值。这一点很重要,因为我们的样本量很小,其值很大程度上取决于为训练集选择的观察值。
def find_crit(X):
rep = 10000
totalA = 0
totalB = 0
for i in range(rep):
totalA += AICcalc(X)
totalB += BICcalc(X)
return [totalA,totalB]
avgAIC = totalA/rep
avgBIC = totalB/rep
return [avgAIC,avgBIC]
从图中可以清楚地看到,参数的增加增加了 AIC 和 BIC,但是可能的最佳模型具有 3 个参数(活跃度、响度和速度)。该模型的 AIC 为 78.04,BIC 为 75.97,R 平方为 0.105,调整后的 R 平方为 0.077,平均相对误差为 43.9,均方误差为 1933.7。
print(criterion[3:4]) #AIC and BIC for modelX= data.iloc[:100,3:16]
y=data.iloc[:100,16:]
X= X[['liveness','loudness','tempo']]model= LinearRegression()
model.fit(X,y)
print(model.score(X,y)) #R-squared
print(str(1-(1-model.score(X,y))*(len(y)-1)/(len(y)-X.shape[1]-1)))train_exp = X.iloc[:95,:]
train_res = y.iloc[:95,:]
test_exp = X.iloc[95:,:]
test_act = y.iloc[95:,:]matr_exp = MLR(train_exp,train_res, test_exp, test_act)
predicted = matr_exp.fit_pred()mae = mean_absolute_error(test_act,predicted)
print(mae) #Mean Absolute Error
mse = mean_squared_error(test_act,predicted)
print(mse) #Mean Squared Error
结论
总的来说,我们可以得出结论,使用数据集中的这些变量,我们无法准确预测一首歌的受欢迎程度。我们甚至不能真正靠近。即使最好的模型也预测在点 100 的歌曲在点 50 附近上升。
Residual plot for final model
从数据来看,任何变量都没有明显的趋势。这令人惊讶吗?不。音乐流行是一件非常复杂的事情,艺术家的声誉、歌词的含义、流派以及一首歌曲在一年中的发布时间等变量都会影响它的流行程度,而不仅仅是人类对已经在文化上流行的歌曲的快速痴迷。
*逐步选择程序以 0.1 的进入水平和 0.1 的停留水平进行。这些是比大多数程序更高的α水平,但是由于变量通常是弱预测器,标准程序产生了包含零变量的模型,这不是很有帮助。
关键词汇:
- 逐步选择:特征选择的方法,根据变量在帮助预测响应变量中的重要性来删除和添加变量
- 残差:实际响应减去预测响应
- 参数:用于预测目标变量的值
- 过度拟合:用过多的变量拟合模型,导致模型只适合你训练的数据
- 欠拟合:用比所需更少的变量拟合模型,导致模型不适合或预测不佳
- 均方误差(MSE) :残差平方的平均值;差异
- 均方根误差(RMSE) :以响应变量为单位的 MSE 的平方根,使其在模型之间具有可比性;标准偏差
- 平均绝对误差(MAE) :残差绝对值的平均值
- 平均绝对百分比误差(MAPE) :以百分比表示的平均误差
- R 平方:又名决定系数,模型解释的方差的百分比
- 调整后的 R 平方:修改后的 R 平方,对添加无关紧要的参数进行惩罚
- 赤池信息标准(AIC) :模型的相对质量,通常报告为与最佳模型的差异
- 贝叶斯信息标准(BIC) :修改后的 AIC,对增加参数进行处罚