面向生产/多任务生产的机器学习工程介绍——多任务生产中的阶段
(图片作者来自 Canva )
关于机器学习模型生产阶段的讨论,即范围、数据、建模和部署。
欢迎回来!这将是 MLOps 系列的第二篇文章。之前,我们简要介绍了生产中面临的挑战以及应对这些挑战的一些简单解决方案。如果你没有机会看我以前的文章,你可以在这里查看。
现在,正如我们之前讨论的,生产部分可以大致分为 4 个阶段。在本文中,让我们探索这些阶段以及它们各自的真正含义。
1.辖域
简而言之,范围界定有助于确定问题的可行解决方案。让我们考虑一个例子,你正在为你的公司做一个手写识别项目。现在,解决这个问题的一些初始步骤可以是查看这个问题的基准论文/开源实现。通常,对于大多数项目来说,这是一个很好的起点,因为在你之前几乎总会有人试图解决相同的问题陈述。在此之后,您可以将您的数据提供给这个开源模型并对其进行微调,或者从开源模型中提取一些数据并制作您自己的模型。基本上,查看这些预先存在的解决方案可以让您对可达到的精度水平有一个基本的了解。这就是范围界定所需要的。范围界定中涉及的一些要点是-
- 集思广益解决商业问题
- 集思广益人工智能解决上述问题
- 评估解决方案的可行性和潜力(我认为这非常重要)
这就是范围界定的本质。它帮助你或你的团队更好地了解手头的问题以及如何着手解决它。
2。数据
众所周知,数据在很大程度上统治着人工智能世界。我们的模型,至少在监督学习的情况下,只和我们的数据一样好。重要的是,尤其是在团队中工作时,要对你所拥有的数据保持一致。考虑我们前面定义的相同的手写识别任务。假设你和你的团队决定暂时丢弃点击不好的图片。现在,什么是点击不好的图像?对你的队友和你来说可能都不一样。在这种情况下,建立一套规则来定义什么是点击不好的图像是很重要的。也许如果你很难在一页上读到 5 个以上的单词,你会决定扔掉它。诸如此类的东西。即使在研究中,这也是极其重要的一步,因为数据和标签的模糊性只会给模型带来更多的混乱。
另一件需要考虑的重要事情是您正在处理的数据的类型,即结构化或非结构化。你如何处理你拥有的数据很大程度上取决于这个方面。非结构化数据包括图像、音频信号等,在这些情况下,您可以执行数据扩充来增加数据集的大小。然而,对于结构化数据,数据扩充是不可取的。标记也是一样——作为人类,我们发现非结构化数据比结构化数据更容易标记。
处理数据时要记住的一些要点是-
- 干净的标签至关重要
- 贴标机必须就贴标的标准程序达成一致,以确保一致性
- 仅将人的水平的性能(我们将很快对此进行更多讨论)作为非结构化数据任务的基准
- 确保您在收集数据时从容不迫,但同时也开始处理模型。让数据收集方法在本质上是迭代的。
3。建模
许多人可能认为这是最重要的阶段,然而,这是不正确的。我仍然认为数据阶段要重要得多。话虽如此,我承认建模也是一个重要的阶段。它围绕着微调,开发你的模型,并试图达到一定程度的准确性。不像简单的项目,在开发/测试集上做得好可能是模型做得好的指示,这不是 MLOps 的情况。这是因为部署时模型将与之交互的真实世界的数据可能会导致模型的行为方式与预期的不同,因此了解如何处理您的模型非常重要。
有一些关键的步骤来确保你得到正确的建模部分。大致可以总结如下-
- 建立基线:一些经常被忽视的事情(个人犯了这个错误,请不要犯这个错误内心尖叫),建立基线非常重要,因为它有助于给你一个如何前进的想法。它基本上包括查阅相关领域的先前研究,或者看看做同样事情的其他公司的产品,看看他们的模型有多好。这再加上了解所需/可用的计算资源,可以帮助您复制一些最先进的(SOTA)结果。DL 社区的一个好处是 SOTA 的大部分论文都是开源的。这使得不仅建立基线变得容易,而且建立相似的或者在某些情况下甚至更好的模型也变得容易。对于非结构化数据,可以以人的水平的表现作为评判你的模型的标准。考虑前面给出的手写识别任务——如果一个开源模型能够以大约 20%的错误率阅读单词,那么这就是你的任务基线。如果你觉得你有办法复制 SOTA 的论文,那么你也可以用他们的结果来建立你的基线。都是主观的。
- 以数据为中心的方法:以数据为中心的方法正在社区中迅速获得牵引力,它涉及到关注数据而不仅仅是模型。努力尝试并确保数据的高质量并得到保持。虽然这在研究中并不常见,但在我看来,以数据为中心的方法是改善模型结果的唯一确定的方法。确保您的数据覆盖重要的测试用例,被一致地定义,并且尽可能平均地分布,这些都是以数据为中心的方法的一部分。就我个人而言,在我参与的项目中,每当我尝试采用以数据为中心的方法时,我总能看到对看不见的数据的准确性略有提高。它可以是一些小事情,比如在将图像提供给模型之前修复图像中的光照条件等等。
- 实验跟踪/版本控制:devo PS 中一个众所周知的步骤,版本控制帮助我们跟踪变化,并让我们在应用程序可能抛出错误的情况下恢复到以前的工作版本。在 MLOps 中,跟踪所用算法的代码、超参数、数据集(如果有的话)的变化,以及为某组超参数获得的结果的种类等非常重要。
4.部署
现在我们已经准备好了模型,下一步是什么?当然是部署!这包括在现实环境中发布您的模型,或者将其集成到为其开发的应用程序/边缘设备中。即使在部署中,也有某些类型的部署。这些是-
- 影子部署(Shadow Deployment):在这种类型的部署中,模型被部署,但是最终的决定由人做出,不管模型预测什么。这样做通常是为了衡量模型做得有多好以及它在哪里失败了。
- 金丝雀部署:在这种类型的部署中,模型只暴露给一小部分允许它做出决策的数据。例如,模型可能只暴露于每 1000 张图像中的 10 张。根据模型的表现,流量会逐渐增加,或者模型会被拉回并进行调整。
- 蓝绿部署:在这种部署中,流量逐渐从旧版本或蓝版本迁移到新版本或绿版本。这有助于防止任何类型的停机,并且在任何错误/错误的情况下,应用程序可以很容易地回滚到以前的稳定版本或蓝色版本。
接下来要看的是对我们部署的模型的监控。请记住,部署是一个迭代的过程。因此,总有改进的空间,唯一可以改进的方法是,即使在部署后也要监控他们的模型。有许多软件可以用来监控指标等。我可能会在以后的文章中谈到这些。现在,让我们关注一些关键点,以确保我们部署的模型能够顺利运行-
- 考虑服务器负载的种类并对其进行监控
- 检查所有可能的情况,在这些情况下你的模型可能会失败或者可能会出错,然后尝试纠正这些情况或者确保正确的错误处理
- 和你的团队一起,决定几个关键指标来判断你的模型的性能
- 不要固执于你的性能指标,对变化保持开放的态度,并且总是尝试和致力于确定最适合你的模型的指标
- 确保不仅模型而且 ML 管道都受到监控。有时,由于预处理步骤中的一个小错误可能会导致错误,这可能会导致整个系统的崩溃(在那里,搞乱了输入形状,并试图通过只查看模型的代码来解决错误;-😉
- 对于您正在处理的问题陈述,了解真实世界的数据可以/可能变化得有多快。
这就对了。关于 MLOps 的阶段,我要说的就是这些。如果你已经做到了这一步,并且想了解更多关于 MLOps 的知识,请随时查看我的 GitHub 库 。我会用相关的材料和 Jupyter 笔记本不断更新它!
参考文献
- https://www . red hat . com/en/topics/devo PS/what-is-blue-green-deployment
- https://www . coursera . org/learn/introduction-to-machine-learning-in-production
- https://cloud . Google . com/blog/products/ai-machine-learning/key-requirements-for-an-m lops-foundation
- https://blog.ml.cmu.edu/2020/08/31/3-baselines/
- https://blog . tensor flow . org/2021/01/ml-metadata-version-control-for-ml . html
面向生产/物流的机器学习工程导论——概念和数据漂移
(图片作者来自 Canva )
简要介绍数据漂移、概念漂移和 MLOps 中面临的挑战,以及解决这些问题的一些最佳实践。
可以肯定地说,我们大多数人从机器学习/深度学习开始,都能够轻松地开发基本模型,并取得不错的结果。然而,从个人经验来说,我们很少接触到我们模型的部署,特别是如果我们对 Flask、Django 等框架几乎没有经验的话。
许多机器学习课程都复习了解决某些类型问题所需的算法、代码片段和库的基础知识。然而,我还没有特别找到任何专门针对生产相关主题的课程。直到 DeepLearning.ai 就这个话题发布了他们的特殊化!这篇文章(或者可能是一系列文章)本质上是这个专业的第一门课所讲内容的总结,同时也混合了我对这个主题的看法。
每个 ML/DL 项目大致可以分为 4 个阶段——即范围界定、数据、建模、部署。现在,在我们查看每个阶段(可能在后续文章中)和最佳实践之前,重要的是要理解在现实世界中生产可伸缩模型所面临的挑战。
ML 项目开发阶段(图片由作者提供)
模型部署后经常出现的两种情况是概念漂移和数据漂移。
- 概念漂移指的是在一段时间内输入数据‘x’和输出数据‘y’之间关系的变化。 Eg- 考虑一个房价预测模型。在像疫情这样的异常情况下,房地产价格会突然发生变化,因此模型可能不再做出准确的预测。在正常情况下,一个价值 500 万印度卢比的住宅现在可能要花费 750 万印度卢比才能获得同样数量的功能,如卧室、空调、平方英尺面积等。
概念漂移(图片作者提供)
- 数据漂移是指输入特性的变化。从数学上来说,是变量分布的变化导致了它们意义的变化。考虑一个处理银行交易的模型。通常,必须有某种交易限制,超过某个阈值的任何交易都可能导致信用卡出于安全目的而被冻结。然而,再想想疫情的情况,那里由于必需品的有限供应而出现了支出增加(或囤积必需品)的情况。这将导致正常的 ML 模型阻塞每个人的卡以限制交易。因此,由于正常事务数量(输入特征)的变化,模型的性能不如预期。
数据漂移(图片由作者提供)
除了部署后面临的这些挑战之外,在部署您的模型之前需要问的一些关键问题是-
- 该模型是否将被实时使用?
- 部署模型的设备可以访问互联网吗?
- 该模型将部署在边缘设备还是云上?
- 需要哪种计算资源?
如果这些问题能够得到回答,那么作为一名机器学习工程师,你的生活会轻松很多,而且在项目中途进行更改时也不会浪费太多时间。令人惊讶的是,我还发现这些问题中的一些在开始任何以研究为导向的项目时很有用。
现在,因为我已经告诉了你们所面临的挑战,所以讨论解决这些挑战的可行方案是有意义的。这些可以大致概括如下-
- 在发生变化/漂移之前和之后,使用所有可用的数据重新训练您的模型。
- 微调模型超参数以尝试和调整模型可能遇到的新模式会有所帮助。此外,这比数据相关的方法相对容易。一个优势是模型部署不必是一次性的过程,而是本质上的迭代。每隔几周/几个月,你就可以推出你的模型的一个改进版本,而且几乎总是这样,因为现在你的模型对真实世界的数据有了更多的经验。
- 最后,如果你觉得你已经获得了足够的新数据,丢弃旧数据。数据越新鲜,你就越容易训练你的模型来适应问题陈述(在大多数情况下)。
这就对了。这是对 MLOps 的简要介绍,还有很多内容要介绍,但我认为这是结束本文的好地方。在接下来的文章中,我们将更详细地讨论开发和部署模型的 4 个阶段,并进一步深入研究用于确保平稳操作的技术。
如果你已经做到这一步,并想了解更多关于 MLOps 的信息,请随时查看我的 GitHub 库 。我会用相关的材料和 Jupyter 笔记本不断更新它!
参考
- https://machinelingmastery . com/gentle-introduction-concept-drift-machine-learning/
- https://www . explori um . ai/blog/understanding-and-handling-data-and-concept-drift/
- https://towards data science . com/machine-learning-in-production-why-you-should-care-data-and-concept-drift-d 96d 0 BC 907 FB 0
- https://youtu.be/06-AZXmwHjo
- https://www . coursera . org/learn/introduction-to-machine-learning-in-production
非概率抽样方法介绍
探索数据科学的其他采样技术
克里斯汀娜·戈塔迪在 Unsplash 上的照片
本文是上一篇文章的续篇,介绍概率抽样方法。抽样方法不仅在统计学研究中有相关作用,而且在许多机器学习方法中也有相关作用,例如 K-fold 交叉验证和基于决策树的模型。为此,我决定对这些方法进行更多的研究。此外,它们可以主要分为两大类,概率方法和非概率方法。由于概率技术在上一篇文章中已经介绍过了,现在我们将学习另一类技术。
非概率抽样方法
在非概率抽样方法中,每个被选总体元素的概率是未知。这是与概率方法最明显的区别,在概率方法中,被选择的群体中的每个单元的概率是已知的并且可以被估计。非概率抽样方法的另一个重要方面是,研究者的角色在他/她所进行的研究中起着核心作用。参与者的选择取决于数据收集者的主观性。虽然它们提供了许多优势,如简单的组织、低成本和执行速度,但使用这些技术也有缺点,在进行任何市场或其他类型的研究之前必须考虑这些缺点:
- 所选单位的选择依赖于研究者的判断,因此,样本中可能存在选择偏差。
- 样本不具有代表性,因此,对样本进行的结果不能扩展到所有总体。
- 不可能估计结果的精确度。
你可能会问自己为什么要使用这些方法,因为它们有很多缺点。这是因为概率抽样方法在金钱和时间上是昂贵的,并且不可能有一个完整的人口列表。因此,非概率方法提供了一种更简单、更便宜的收集数据的方法。
作为概率抽样方法,非概率抽样方法可以进一步分为四类。
非概率抽样方法:
- 配额抽样
- 判断取样
- 方便取样
- 雪球取样
1.定额抽样
作者插图
配额抽样可能与分层抽样相混淆,因为它们都是根据某些特征,如性别、年龄和教育程度,将人口分成不同的阶层。此外,团队需要内部同质,内部异质。
即使乍看起来相似,配额抽样在许多方面也不同于分层抽样:
- 每个组由配额表示,配额是要调查的单元的数量
- 为每个阶层选择单位时考虑了它在整个人口中的分布。
- 在每个名额内,面试官可以自由选择面试的参与者。
例如,我们可以按性别研究 2020 年人口为 1 万的超级马里奥 Run 应用内支出者。如上表所示,我们计算每一组在总体中的百分比**,**,然后,研究人员可以计算他需要每一组多少个样本来保持相同的比例。在这种情况下,我们抽取了 500 个单位的样本,其中研究者采访了 400 名男性和 100 名女性。
优点:
- 这既省时又省钱,尤其是在分层抽样方面。
缺点:
- 由于面试官的谨慎或不回答的偏见,结果可能会被扭曲
- 配额样本会产生选择偏差
2.判断抽样
判断取样。作者插图。
判断性抽样,也称为目的性抽样,考虑了研究者的判断。对于调查研究,他/她选择参与者,因为他认为他们是人群的代表。一般来说,当只有有限数量的人具有特定的特质时,这是有用的。
例如,如果你想调查技术工作中的性别差距,样本不是随机选择的,而是为特定目的而选择的。应该有一些标准来选择受访者。我们可以只考虑来自美国、加拿大和英国的 35 岁以下的男性和女性。此外,参与者至少应完成科学领域的学士学位。
优点:
- 又省时又划算
- 它适合于研究某个文化领域,在那里需要专家的知识
缺点:
- 研究人员的知识和人口的实际情况之间的差距越大,就可能导致较高的选择偏差
3.方便抽样
方便取样。作者插图
在方便抽样中,研究者选择任何对他“方便”的人,即可以立即回答问题的人,没有任何特定的标准。很多时候,参与的人都是志愿者。招募人员没有特定的策略:研究人员可以招募朋友、家人或社交媒体中的人。这种方法导致选择有偏差的样本,不能代表总体。
大多数时候,它构成了一个非常危险的数据来源,因为它会带来关于所研究现象的误导信息。一个典型的例子是,当你在网上点击一个选项,给出你对一个敏感话题的看法,比如政治。它会导致错误的结论,从而出现极端的观点。
优点:
- 它既便宜又快捷
缺点:
- 这导致样本不具有代表性
4.滚雪球抽样
滚雪球抽样。作者插图
在滚雪球抽样中,研究人员要求已经招募的人识别其他潜在的参与者,等等。因此,样本的单位像滚雪球一样增加。它特别适合于稀有人群,对于稀有人群,不可能有人群列表,并且很难在区域内定位结果,即使是很少的人。
例如,如果我们想对没有居住许可的移民的工作条件进行研究,收集数据可能会很困难。最快的方法是联系一个移民,让他联系其他他认识的人。
优点:
- 这对于市场研究或关于敏感话题的研究很有用。
缺点:
- 样本可能不具有代表性,因为它不是随机的,而是取决于研究者直接或间接接触的人
- 这很费时间
最终想法:
在这篇文章中,我提供了非概率抽样方法的概述。总的来说,它们具有成本和时间效益,但同时,获取非代表性样本的风险也很高。它们应该在没有完整的人口名单和概率方法不能应用的情况下使用。与概率抽样方法不同,非概率抽样方法用于数据收集。希望这个故事和之前关于概率抽样方法的故事帮助你掌握了抽样方法。感谢阅读!祝你有愉快的一天。
你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都可以收到电子邮件!
Python 中 Matplotlib 绘图简介
UCL 数据科学协会工作坊 7:创建一个基本图形,在同一个图形上绘制不同的信息,并创建多个支线图形
尼古拉斯·卡佩罗在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学学会的科学负责人,该学会将在整个学年举办一系列 20 场研讨会,涵盖的主题包括数据科学家工具包 Python 和机器学习方法简介。每一篇文章的目标都是创建一系列的小博客,这些小博客将概述要点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 资源库中找到,并将在全年更新新的研讨会和挑战。
本系列的第七个研讨会介绍了 matplotlib python 包,它是数据科学家工具包系列的一部分。在本次研讨会中,我们将介绍如何构建一个基本的绘图,在同一个图表上绘制不同的信息,以及跨多个轴绘制信息。虽然这里将分享一些亮点,但完整的研讨会(包括自测题)可以在这里找到。
如果您错过了我们之前的任何研讨会,您可以在以下链接中找到最后三场:
什么是 Matplotlib?
Matplotlib 是另一个应该包含在任何数据科学家工具包中的核心数据科学库,以及之前介绍的 Numpy 和 Pandas 库。这个库的主要目的是创建可视化,以便能够更好地理解您所拥有的数据,pandas 基于这个库构建了自己的功能。
在 Matplotlib 网站上描述为:
Matplotlib 是一个用于在 Python 中创建静态、动画和交互式可视化的综合库。
该库的目标和目的是使绘图尽可能简单,因为它还声明:
Matplotlib 让简单的事情变得简单,让困难的事情变得可能。
虽然 Python 中有许多其他可视化库,包括 seaborn 和 plotly ,但这通常是你学习的第一个可视化工具,因此这也是我们在一个研讨会中讨论它的原因。
创建您的第一个情节
在创建任何图之前,我们需要做的第一件事是实际创建我们将用于绘图的数据!因为我们已经了解了 Numpy 库及其丰富的功能,所以我们可以使用 Numpy 数组及其数学功能来创建我们可以绘制的数据。我们可以这样做:
# Creating an array with 100 values from 0 to 2pi
x = np.linspace(0,2*np.pi,100)# An array with the sine of all the values in array x
y = np.sin(x)
现在我们有了 x 和 y 的数据,我们可以开始创建我们的图了!
为此,我们可以从创建一个相当基本的图开始,其中我们将数据非常简单地显示为轴上的一条线,如下所示:
# Produces the figure
plt.figure()# Plots the sine function
plt.plot(x,y)
作者图片
简单来说,我们只使用了两行代码来创建我们的图表(您甚至可以删除第一行,它仍然可以工作!).那是多么美好和简单啊!
当然,这是一个相当基本的情节,所以我们可以开始改善它。我们注意到的第一件事是,我们不一定能看到数据在图上如何排列,因为没有网格来显示正弦波的波峰和波谷。因此,我们可以使用plt.grid
将网格添加到我们的图中,如下所示:
# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Plots the sine function
plt.plot(x,y)
作者图片
由此我们可以看到,y 值在 1 处达到峰值,在-1 处降至最低点,我们可以更准确地读取与 x 和 y 值相关的数据。
然后,我们可以开始定制情节的外观。例如,如果我们想将颜色从蓝色变为红色,我们可以指定颜色为r
,如果我们想将线条样式从实线变为圆点,我们可以如下指定r.
:
# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Plots the sine function with red dots
plt.plot(x,y,'r.')
作者图片
其他方法也可以使用图的color
和linestyle
参数来改变外观,包括各种颜色的线条和不同外观的线条样式。
当然,我们已经能够使我们的线条看起来更好、更清晰,但其他任何看这个情节的人可能不明白我们试图用情节本身来展示什么。因此,为此我们需要添加一个标题和标签来表明我们想要展示的内容。我们可以这样做:
# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Adds a title
plt.title("Plot of a sine function",
fontsize = 20,
pad = 15)# Adds label for the x-axis
plt.xlabel("x",
fontsize = 15,
labelpad = 20)# Adds label for the y-axis
plt.ylabel("sin(x)",
fontsize = 15,
labelpad = 15)# Plots the sine function with red + signs
plt.plot(x,y,'r+')
作者图片
我们使用了plt.xlabel
、plt.ylabel
和plt.title
函数将它们添加到图中。我们还指定了fontsize
来指定标签上使用的字体大小,并指定了labelpad
和pad
来将标签从轴上移开,以便于阅读。
由此,我们可以开始在我们的地块中添加更多的功能,并创建我们自己的风格,可以在我们创建的所有地块中使用。然而,Matplotlib 有丰富的内置样式表,我们可以使用plt.style.use(
namedstyle)
来访问。其中我最喜欢的一个是fivethirtyeight
样式表,因为它能够产生漂亮清晰的视觉效果,以及干净容易识别的调色板。我们可以这样实现:
# Changing style to fivethityeight
plt.style.use('fivethirtyeight')# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Adds a title
plt.title("Plot of a sine function",
fontsize = 20,
pad = 15)# Adds label for the x-axis
plt.xlabel("x",
fontsize = 15,
labelpad = 20)# Adds label for the y-axis
plt.ylabel("sin(x)",
fontsize = 15,
labelpad = 15)# Plots the sine function with red + signs
plt.plot(x,y, "+")
作者图片
现在看起来干净多了!更多这些,以及它们的样子的例子,可以在这里的链接找到。
同一轴上的多个图
虽然我们现在有了一个看起来不错的图,显示了我们想要的所有信息,但是如果我们想在同一个图中添加更多的信息呢?我们可以通过重用相同的轴并绘制新数据来简单地做到这一点。
在我们的例子中,由于我们已经创建了一个正弦波,我们也可以使用相同的 x 序列创建一个余弦波,以比较它们如何在相同的值上变化。我们可以这样做:
# Generates an array of cos(x) values
y1 = np.cos(x)# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Adds a title
plt.title("Plot of a sine and cosine function")# Adds label for the x-axis
plt.xlabel("x")# Adds label for the y-axis
plt.ylabel("y")# Plots the sine function with red + signs
plt.plot(x,y,'r+')# Plots the cos function with green crosses
plt.plot(x,y1,'gx')
作者图片
太好了!我们可以看到,我们已经能够使用与之前相同的函数来添加网格和标签,但现在我们已经能够添加余弦函数以及绿色十字。现在唯一的问题是,除非我们看到正弦函数开启时的原始图(或者我们知道正弦函数应该是什么样子),否则我们不一定知道如何区分它们。这就是传说派上用场的地方!
为了给我们的图添加图例,我们需要为正弦和余弦函数的图指定一个标签,以便能够区分它们。这是通过向plt.plot
函数添加一个额外的参数label=
来实现的。这个标签需要被设置为我们想要标记图的字符串。然后我们添加一行额外的plt.legend
来显示图例。这里的可选参数loc="best"
经常被使用,它只是试图确保图例被放置在图中最合适的位置。我们可以这样尝试:
# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Adds a title
plt.title("Plot of a sine and cosine function")# Adds label for the x-axis
plt.xlabel("x")# Adds label for the y-axis
plt.ylabel("y")# Plots the sine function with red + signs and defines a legend label
plt.plot(x,y,'r+',label="sin(x)")# Plots the cos function with green crosses and defines a legend label
plt.plot(x,y1,'gx',label="cos(x)")# Adds a legend in the best position
plt.legend(loc='best')
作者图片
现在我们可以清楚地分辨出哪个是正弦函数,哪个是余弦函数。唯一剩下的问题是,我们现在在绘图的两端都有一些空白空间,我们的行基本上在这里用完了。因此,我们可以尝试限制我们的轴,以便我们只显示使用plt.xlim
和plt.ylim
函数实际绘制值的位置,如下所示:
# Produces the figure
plt.figure()# Adds a grid
plt.grid(True)# Adds a title
plt.title("Plot of a sine and cosine function")# Adds label for the x-axis
plt.xlabel("x")# Adds label for the y-axis
plt.ylabel("y")# Defines a region along the x-axis to be displayed
plt.xlim(0,2*np.pi)# Plots the sine function with red + signs and defines a legend label
plt.plot(x,y,'r+',label="sin(x)")# Plots the cos function with green crosses and defines a legend label
plt.plot(x,y1,'gx',label="cos(x)")# Adds a legend in the best position
plt.legend(loc='best')
作者图片
使用多轴
到目前为止,我们已经能够创建一个显示单个数据的图,然后我们能够创建一个显示多个数据的图。如果我们有两个独立的数据,我们想在多个图中显示,但我们不想创建两个独立的图呢?嗯,我们可以通过创建一个支线剧情数组来做到这一点!
有两种方法可以做到这一点。第一个是创建一个基础图形,就像我们已经做的那样,然后向原始图形添加支线剧情,我们可以向其中添加数据。为此,我们可以使用fig.add_subplot(1,2,1)
,其中前两个数字表示创建的数组的大小(这里是 1 行 2 列),而第三个数字表示这将是哪个子情节。我们可以将它赋回一个变量,将其创建为一个轴。我们之前所做的和现在所做的唯一区别是,我们现在有了一个轴,而不是使用fig.title
或fig.xlabel
,我们现在必须使用ax.set_title
和ax.set_xlabel
。例如,我们可以像以前一样创建两个子轴来添加我们的图:
# Defines a variable for your array of subplots
fig = plt.figure(figsize=(10,5))# Adds a subplot to the array
ax1 = fig.add_subplot(1,2,1)# Plots the sine function on the first subplot
ax1.plot(x,y1,'r')
ax1.set_title("Sine function")
ax1.set_xlabel("x")
ax1.set_ylabel("y")
ax1.grid(True)# Plots the cosine function on the second subplot
ax2 = fig.add_subplot(1,2,2)
ax2.plot(x,y2,'g')
ax2.set_title("Cosine function")
ax2.set_xlabel("x")
ax2.set_ylabel("y")
ax2.grid(True)#to ensure no overlapping
plt.tight_layout()
作者图片
我们可以看到,现在我们已经创建了两个独立的轴,然后我们可以绘制我们的数据!
另一种方法是使用fig, ax = plt.subplots(1,2, figsize = (10,5))
直接指定我们正在创建子情节,其中fig
是我们的基轴,ax
是一个轴数组,我们可以像访问列表或数组一样访问它。因此,我们可以绘制出与前面相同的信息,如下所示:
fig, ax = plt.subplots(1,2, figsize = (10,5))# Plots the sine function on the first subplot
ax[0].plot(x,y1,'r')
ax[0].set_title("Sine function")
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
ax[0].grid(True)# Plots the cosine function on the second subplot
ax[1].plot(x,y2,'g')
ax[1].set_title("Cosine function")
ax[1].set_xlabel("x")
ax[1].set_ylabel("y")
ax[1].grid(True)#to ensure no overlapping
plt.tight_layout()
作者图片
我们现在有完全相同的图,但是使用了稍微不同的符号!然后,我们可以使用这些来创建多个子情节数组,以在同一个整体情节中显示多种类型的数据!
为此,后一种创建支线剧情的方法更常用,因为你直接指定你正在创建几个子轴,而不是稍后指定。当您创建一个单轴(指定1,1
)时,也经常使用它,因为它确保当您绘制多条信息时,所有内容都绘制在同一个轴上!
当然,Matplotlib 可以做的不仅仅是像这样绘制基本信息,我们还会在实际的研讨会中介绍如何创建矩阵图、choropleth 图、雷达图等等。Matplotlib 是一个非常广泛的库,它允许你用它做很多事情,包括箱线图、散点图、条形图和直方图等,但也有其他可视化库,如 seaborn 和 plotly。我建议你探索和练习绘图,包括尝试我们的问题工作表来挑战你!
完整的研讨会笔记,以及更多的例子和挑战,可以在 这里找到。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata 脸书
insta gram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他了不起的作者的故事,请随时使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership [## scikit-learn 决策树分类器简介
towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)
多项式回归导论
实践教程
R 语言中的数值例子及实现
图片来自像素
在介绍多项式回归之前,我们需要有一个概念,线性回归是做什么的。线性回归的主要思想是利用基函数的线性组合建立模型。为了引入这个概念,有一个问题需要回答。
「线性组合」是什么意思?它是几个项的组合,通过标量进行加法和乘法,形式如下
线性组合的定义。作者图片
其中 a₁、a₂,…是标量,x₁、x₂,…是项,或者用线性代数的语言来说,是向量。无论这些项是什么,模型都与参数成线性。
一个多项式回归模型可以被认为是几个单项式的线性组合并采取以下形式
多项式回归模型。作者图片
线性回归模型的变异
在线性回归领域,可能会遇到一些变化,有时很容易被看起来相似的术语搞混。
多元线性回归:试图用一个线性模型来描述一个因变量与两个或两个以上自变量之间的关系。在本文中,我们将关注多项式回归,它被认为是多元线性回归的一个特例。
简单线性回归 : 也是多元线性回归的特例,只涉及一个自变量。它使用一条直线来模拟数据,这条直线是一次多项式。
一般多元回归模型:它是几个多元线性回归同时写在一起的形式
一般多元回归模型。作者图片
其中 Y 是一个 n 乘 p 的矩阵,每列有 p 个因变量,每行有 n 个个体,X 是一个有观测数据的 n 乘 q 的已知矩阵,B 和 U 分别表示未知参数和噪声。
广义线性模型:应用 链接函数将因变量分布的参数链接到线性预测器(因变量的线性组合)。与其他线性模型不同,它允许因变量的误差项具有不同于正态分布的分布。
当连接函数为恒等式时,该模型退化为具有正态误差的普通线性模型。
拟合数据
要使用多项式找到合适的模型来拟合数据,需要完成两件事情:
- 我们需要知道它的度是多少。
- 我们需要找到每个单项的系数。
确定系数
上面描述的第一个任务实际上更困难,所以我们可以先看看第二个。为了说明线性回归的原理,让我们生成一些带有白噪声的数据
X <- seq(from=-10, to=10, by=1)
Y <- vector(mode = "double", length = length(X))
lenY <- length(Y)**for** (i **in** seq(from = 1, to = lenY)){
noise <- runif(1, min=-1, max=1)[1]
rangeNoise <- 25
Y[i] <- X[i]^2 + 2*X[i] + 2 + noise*rangeNoise
}df <- data.frame(X, Y)
当然,拟合该数据的最佳模型是二次多项式。让我们试着拟合数据,看看它是什么样子的。这很简单,这就是我们需要做的
model <- lm(Y ~ I(X^2)+ I(X), df)
事实上,使用poly(X, 2)
更好,因为它使用正交多项式,可以避免 X 和 X 之间的相关性引起的问题。然而,为了比较来自lm
的结果和来自手动计算的结果,我们仍然使用Y ~ I(X^2) + I(X)
。
拟合数据的最佳多项式看起来是这样的(显然,线性模型不一定是一条线,因为它只是一些项的线性组合,项可以是任意的,线性模型看起来可以是任意的。但是它关于参数是线性的。)
拟合的结果。作者图片
其中灰色区域描述了置信区间。
lm
函数使用了什么方法,我们获得了什么结果,如何解读?让我们用summary
来看看吧
线性模型概述
首先让我们看一下Estimate Std.
,那里的数字是我们模型的系数,也就是说得到的多项式是 f(x) = 1.0341x + 1.7416x-0.7320。计算系数的方法是最小化成本函数,在这种情况下,成本函数被选择为均方误差函数
MSE(均方差)函数。作者图片
其中,yᵢ是观测值,yᵢ哈特是预测值。由于 yᵢ是单项式 x,x,x,…和系数(我也将互换使用“权重”)w₁,w₂,…的函数,确定成本函数何时达到最小值给了我们关于 x 的 w 的表达式,x-es 是已知的,因此我们可以求解系数。这就是最小二乘法。
系数也可以通过伪逆来计算。将输入数据、权重和观察值写入矩阵
输入数据、权重和观察值。作者图片
预测值将是 XW,我们希望 XW 尽可能接近 Y。权重可以通过以下方式获得
因此,损失函数为
损失函数。作者图片
这是我们计算重量的方法
使用伪逆计算权重。作者图片
现在我们要证明这是作为最小二乘法的东西,也就是说我们可以从(2.2)推导出(2.3)。
从(2.2) (a)推导出(2.3)。作者图片
然后我们对 f 对 w 求导
从(2.2) (b)推导出(2.3)。作者图片
在转置两边乘以(X^T X)的逆后,我们立即得到(2.3)。
为了验证这一点
存储在Wm
中的结果对应于使用lm
找到的系数。(此处截距为常数)。
[,1]
X^2 1.0340966
X 1.7415511
1 -0.7320286
拟合误差及评价
线性模型概述。作者图片
Std. Error
是标准 误差的估计参数。由于我们拥有的数据是来自总体的样本,因此整个总体的最优回归模型可能在一个范围内——我们获得的最优解是而不是(对于样本来说,它是最好的,但是对于整个总体来说,基本关系可能有点不同)。在统计学中,重要的是要知道,我们谈论的是什么数据,整个人口,还是只有样本数据。这些误差用于计算距离。那我们如何计算这些误差呢?
在表格中填写我们的模型
我们例子中的线性模型。作者图片
这意味着
。作者图片
其中εᵢ是误差项,它是观测值和预测值之间的差值。
根据这个,我们可以通过以下方式计算系数
估计系数误差的计算公式。作者图片
其中,变量上的帽子表示它们是估计值,σ(X)是 X 的标准差,X_hat 是 X 的平均值。[自由度](https://www.investopedia.com/terms/d/degrees-of-freedom.asp)是 n-3 (在本例中,n-3 = 21–3 = 18,我们在样本中有 21 个点)。s 就是Residual standard error
,这里 s = 15.11。
在这个源中,符号似乎不是很常见和清晰,所以也参考了维基百科。在这两个来源中,仅给出了最简单模型(a 线 Y = aX + b)的公式,但是可以推导出我们的二次示例的公式。但是当然,鼓励读者尝试实现它们,并用一些数据验证它们。
线性模型概述。作者图片
Coefficients
中的最后两列告诉我们模型中的一个组件是否重要。方法是计算一个 t 统计量,即t value
。然后我们计算 p 值,即Pr(>|t|)
,这是反对零假设的证据(H₀: 模型中的成分在统计上不显著,我们在模型中不需要它)。如果 p 值足够小,我们可以拒绝零假设(值得注意的是,我们不能永远接受零假设,因为我们只有证据反对它)。
以 x 项为例,x 的系数为 w₁,t 值为 w₁
t 值。作者图片
t 遵循学生的 t 分布,自由度为 n-3。在这个例子的情况下,t 值简单地通过系数/标准误差来计算。
函数 lm 中 t 值是如何计算的?作者图片
而结果是3.197
。为了找到 p 值,我们需要参考学生 t 分布临界值表。我们可以看到我们的 t 值在 2.878 到 3.610 之间。所以累积概率在 0.002 和 0.01 之间——结果是0.00499
。总体中基本关系式(2.4)中参数的区间可由下式确定
总体参数的区间。作者图片
其中 t*ₙ₋₃是 tₙ₋₃分布的第(1-α/2)分位数,这个值也可以在这个表中找到。默认情况下,α = 0.05,置信区间为 1-α=0.95。如果 p 值小于α,我们可以拒绝零假设。因此,X 项在我们的例子中很重要。
这个预测将在最后一节讨论。在 R 中非常方便,我们只需要应用函数predict
。
比较和选择模型
这里我们回到第一个任务,我们要用什么样的线性模型?线性组合的项应该是什么?
当使用多元线性回归时,我们经常需要减少因变量的数量,因为如果一个更复杂的模型并不比一个更简单的模型好多少,我们应该使用更简单的模型。对于一个非常复杂的模型,我们可能会获得高性能,但它也更加难以解释。有时过度拟合也会发生。有几种简化的方法,例如,主成分分析就是一个有用的工具。
由于这里我们只处理多项式,PCA 不是很合适,逐步回归将是一个更好的方法,我们可以应用它来降低模型的阶数。但是减少多项式模型的次数的任务类似于减少任何多变量线性回归模型中的独立变量的数量。对于多项式回归模型,次数越高,多项式就能更好地拟合数据,但同时会包含更多的噪声,这将导致非常差的预测(过度拟合)。
我们可以对我们的数据使用一个 5 次多项式,当然这不是必须的,它也不利于预测。如果我们检查这个模型的摘要,我们会发现组件具有较大的 p 值—它们在统计上不显著。以下代码可用于进行逐步回归(需要库MASS
)
fullModel <- lm(Y ~ I(X^5) + I(X^4) + I(X^3) + I(X^2) + I(X) + 1, df)
stepModel <- stepAIC(fullModel, direction = "backward", trace = FALSE)
summary(stepModel)
正如我们已经知道的,结果stepModel
是一个二次多项式。
什么时候应该使用多项式回归,什么时候不应该?
1.速度和距离
使用的例子将是 R 中的内置数据集car
,它记录了汽车的速度和停车时所经过的距离。多项式回归在这里是合适的。事实上,根据我们的物理知识,这是正确的答案。
图 3.1 速度和距离。使用此处的代码制作的图像。
我们将数据分为训练集和测试集,并用测试数据绘制线性模型。
图 3.2 拟合(75%随机选择的训练数据)和预测。作者图片
如果我们运行一个 R 测试,它会告诉我们这个模型解释了测试集中 80.089%的数据可变性。
2.油价
这里是我们不应该使用线性回归的时候。假设我们想根据历史数据预测油价(数据来源:【https://finance.yahoo.com/quote/OIL/history?p=OIL】)。
图 3.3 一年的每日油价。作者图片
我们用了一个三次多项式,这个图看起来不错。(index
为天数指数,CloseP
为每天收盘价)。但在测试数据上,这似乎并不可信
图 3.4 拟合(从数据集开始的 75%的数据),和预测。作者图片
事实上,在这个例子中,它永远不会工作,因为如果我们使用一个偶数阶的多项式,当指数变大时,曲线将上升,奇数阶的曲线将下降。但是很明显,这不是商品价格的变化方式。
为什么比第一个例子差那么多?图 3.1 看起来没有图 3.3 那么混乱和嘈杂。然而,在图 3.1 中有一个时间序列,距离与速度之间的关系和油价与时间之间的关系是完全不同的故事。更多的因素使价格变化变得复杂,例如,时滞、周期性等。
摘要
本文试图介绍多项式回归,并把它与一元线性回归和多元线性回归联系起来。它还简要描述了什么是线性回归和有什么变化。
在关注多项式回归的部分,首先,我们知道如何拟合数据和如何确定系数(使用 R 中的内置函数实现,但也可以手动实现)。然后介绍了模型和评估中的误差,主要是 t 值和 p 值的计算。此外,对统计推断也作了简要介绍。
最后,我们看了两个例子,多项式回归模型分别适用和不适用。
资源
[1] 线性组合 (2015), nLab 。
[2]米歇尔·莱西*,*,多元线性回归
[3]肯特,J. T .,毕比,j .,&马迪亚,K. V. 多变量分析 (1979)。阿姆斯特丹:学术出版社。
[4]内尔德,J. A .,,威德伯恩,R. W . 广义线性模型 (1972)。英国皇家统计学会杂志:A 辑(总论), 135 (3),370–384。
[5] Jonathan Bartlett,线性回归的假设 (2013)
[6] Alboukadel Kassambara,R中的逐步回归要点(2018)
概率抽样方法介绍
为什么采样方法是您的数据科学之旅的关键
作者插图
还在学习统计学的时候就接触到了抽样技术。我记得这是我更喜欢的话题之一,因为教授深入地解释了它们,让我明白它们是许多调查研究的基础,但在那段时间里,我充满了其他课程和其他想法,以至于我一通过考试就忘记了这些有用的概念。
但是在我读数据科学硕士期间,在我的实际研究工作中,我间接看到了很多机器学习模型中涉及到的采样方法,比如决策森林、随机森林、隔离森林等等。它们还用于解决数据集中的不平衡类分布等问题,并通过使用重采样过程(称为 K-fold 交叉验证)来改进模型性能的评估。
出于这个原因,我决定进一步研究这个惊人的主题,它在处理大量数据时具有关键作用。我将从定义什么是采样开始。一旦基本概念清楚了,下一步就是解释不同的抽样技术,重点是概率抽样方法。
介绍
在统计研究中,并不总是能够获得所有案例的数据。为此,最实用的方法是纳入总体的一部分,称为样本。
在进行采样时,我们需要定义一些相关术语。首先,目标人群包括我们理论上感兴趣的所有项目。我们需要区分目标人群和研究人群,有时也称为样本人群,它是我们可以获得的目标人群的子集。
抽样本质上是从研究人群中选择样本的过程。一个重要的要求是,样本需要尽可能地代表总体,以便概括整个总体的特征。
这可以通过采用不同的采样方法来实现,这些方法可以分为两大类:
- 概率抽样方法:被选择的群体中每个单元已知的概率。
- 非概率抽样方法:总体中每个单元被选中的概率未知,与收集数据的研究者的主观性更相关。
在这篇文章中,我将重点介绍概率抽样方法。这种类型的方法可以进一步分为不同的类别,如下所示。
概率抽样方法:
- 简单随机抽样
- 系统采样
- 分层抽样
- 整群抽样
- 多级采样
1.简单随机抽样
简单随机抽样。作者插图
简单随机抽样(SRS)是对人口进行抽样的最简单的方法,人口只是项目的集合[1]。如果检查简单随机抽样的定义,你可能会在某处发现这一点:
简单的随机抽样确保了群体中的每个元素都有相等的选择概率
这并不完全错误,但这取决于提取过程的类型:
- 具有替换的 SRS:群体中的所有单元将具有相同的被选择概率 1/N 。例如,让我们考虑一个装有 4 个红球和 2 个黑球的骨灰盒。在第一次抽取中,红球是从瓮中随机抽取的。所有的球总会有 1/6 的概率被抽样。
- 无替换的 SRS:在第一次抽取时,每一个群体单元将有相等的选择概率 1/N 。在第二次提取时,剩余的 N-1 个单元将具有等于 1/(N-1) 的选择概率。在这个例子中,我们观察到选择概率在第二次提取中发生了变化。这违反了顶部显示的定义!
优势:
- 它很简单,并且不使用关于人口的辅助信息
- 选择是随机的,然后,任何单位都是受青睐的
- 样本具有代表性
缺点:
- 元素的选择是完全随机的
- 需要一份完整的人口单位清单
- 这既费时又费钱
2.系统抽样
系统抽样。作者插图
系统取样可以归纳为两个步骤:
- 计算采样间隔 k =N/n .在图示中,我们有 9 个微笑,我们想获得 3 个单位的样本,那么 N=9,n=3,k=9/3=3。
- 在 1 和 k 之间选择一个随机整数 r:1≤r≤k,例子中我随机选择 r=2,其中 1≤r≤3。
- 一旦选择了第一个单元,我们就取接下来的第 k 个项目来构建样本:r,r+k,r+2k,…,r+(n-1)k。
优点:
- 随机选择仅应用于第一个项目,而选择的其余项目取决于第一个项目的位置和选择项目的固定间隔。
缺点:
- 如果群体元素的列表呈现确定的顺序,则存在获得不具有代表性的样本的风险
3.分层抽样
分层抽样。作者插图
根据一些分类特征,如年龄、性别和教育程度,人口被分为亚人口,称为阶层。如果组内部同质,且组间异质,分层抽样是有效的。从每一层,我们提取一个简单的随机样本。这些样本的集合产生分层样本。
要计算地层样本大小,有两种常用的分配方法:
- 比例分配是实践中最简单、应用最广泛的方案。它在每个地层 nₕ/Nₕ 内提供相同的采样分数,对应于全局采样分数n/n:fₕ=nₕ/nₕ=f=n/n。在插图中,我们根据水果的类型分为两组。阶层人口分别是 N₁=6 和 N₂=9.通过比例分配,我们选择总样本量为 n=5 的样本。根据理论,我们希望相同的采样分数等于 5/15=1/3。正如你所观察到的,这个标准得到了尊重:n₁/N₁ = 2/6=1/3 作为苹果组的样本分数,n₂/N₂ = 3/9=1/3 作为橙子组的样本分数。
- 最优或奈曼分配基于每个地层中取样分数应该不同的想法,并假设地层取样大小 nₕ 与地层 S ₕ 的标准差成正比。当阶层差异不同时,这种分配比比例分配更有效、更精确。
优点:
- 这比简单的随机抽样更有效
- 获得非代表性样本的风险较小
缺点:
- 它需要获得关于人口的辅助信息。
- 对阶层有严格的条件,需要面面俱到,互相排斥。
4.巢式抽样法
整群抽样。作者插图。
整群抽样假设总体可以由基本单位的子集构成,这些子集称为群。显然,它可能看起来类似于分层抽样,但原理完全不同。
在分层抽样中,各组内部是同质的,相互之间是异质的*。*与分层抽样不同,聚类之间 相似,每个聚类包含具有不同特征的元素 。
例如,如果我们有兴趣研究纽约的居民,我们可以考虑由属于同一城市的家庭的人构成的人口。一个家族是一个典型的集群,其中包含不同的成员。
整群抽样允许从群体中随机抽取一些群体,而不是从群体中抽取一些元素。如果我们考虑将人口分成家庭,我们可以随机抽取一些家庭,如图所示。
优点:
- 当集群构成自然形成的子群时,这是有效的,因为我们不拥有群体的列表
- 如果这些单位的特点是分散在整个地区,而且有必要进行直接接触,那么只研究某些集群比简单的随机抽样花费要少。
缺点:
- 集群的条件并不总是被尊重。这些簇可以包含相似的元素。
5.多阶段取样
两阶段抽样。作者插图。
实际上,自然形成的人口子群集群,如果集群规模较小,并且集群是基于地域特征确定的,则可能包含类似的单元。
为每个集群分析一些单元可能更方便,而不是考虑所有的元素。这种设计叫做两阶段整群抽样。如果我们再次考虑居住在纽约的家庭,我们可以从已经选择的群中随机抽取两个人。
因此,多阶段抽样将大量人口分成“阶段”,以使抽样过程更有效。
优点:
- 当集群之间同质而内部异质时,多阶段采样可能比集群采样更有效。
- 抽样规模减小
- 组织起来更简单,成本效益更高
缺点:
- 在不考虑聚类条件的情况下,多阶段采样结果不如简单随机采样有效。
最终想法:
我希望这篇教程对你学习更多概率抽样方法有用。不看例子来研究这个话题是很有挑战性的。在机器学习领域,简单随机抽样和分层抽样是最广泛用于评估模型性能的方法。这里肯定还有我没有提到的其他采样方法。我的目标是关注最相关的技术。我将在下一篇文章中介绍非概率抽样方法。感谢阅读!祝你有愉快的一天。
[1]“调查抽样参考指南,样本设计和估计技术介绍”,欧盟统计局
你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都可以收到电子邮件!
回归不连续设计导论
纳丁·沙巴纳在 Unsplash 上拍摄的照片
用历史数据进行可靠的因果推断
与相关性不同,因果关系是两个变量之间更强的关系。尽管很难断言两者之间存在因果关系,但一旦被证实,它会提供有意义的见解和信息指导。在我之前的文章中,我已经讨论了关于因果推理的什么、为什么和如何:
正如文章中提到的,证明因果关系的最可靠的方法是通过随机试验,这也被称为实验。然而,进行随机试验并不总是可行的。在这种情况下,我们可以使用一些在经济研究中广泛应用的“技巧”,利用历史数据进行因果推断。当某些条件适用时,回归不连续设计(RDD)就是这些技巧之一。在本文中,我将向您展示什么是 RDD,以及使用 RDD 进行因果推理的一些应用。
为什么不实验?
随机分配对照组和治疗组可确保除治疗效果外两组间无显著差异,从而确定因果关系,无需担心混淆变量。进行实验是分析因果关系最可靠的方法,但它不是最常见的方法,主要原因有两个:
- 进行实验的成本很高:进行随机试验不仅经济上很高,而且很耗时。如果没有项目投资的坚实预算,很难进行实地试验;
- **并不总是适用于跑步实验:**跑步实验不可行的原因有很多。例如,在一些医学治疗上进行实验是不道德的。此外,有时不可能在不担心两组之间的互动的情况下将受试者分为治疗组和对照组,尤其是在社交媒体上进行实验时。
如果不可能通过实验产生新的数据来进行因果推断,其他的解决方案是对历史数据应用特殊的方法。根据场景和假设,我们可以从回归不连续设计(RDD)、差异差异(DID)、工具变量(IV)、倾向得分匹配(PSM)等中进行选择。在本文中,我将详细阐述回归不连续设计的假设和应用。
什么是 RDD?
使用历史数据进行因果推断的一个挑战是,我们永远无法知道真实的反事实结果,这意味着我们永远不知道如果治疗组的受试者被分配到对照组会发生什么,反之亦然。因此,我们通过简单地比较治疗组和对照组观察到的结果差异并不是真正的治疗效果,而是可能被其他变量所偏倚。所有的因果推理方法都包括寻找可靠的方法来估计真实的反事实效应。对于随机试验,利用随机性,我们确保两组受试者除了接受或不接受治疗之外,在各方面都相同。在倾向分数匹配中,我们根据治疗组和对照组受试者在某些特征上的匹配分数来“匹配”他们之间的比较。
回归不连续设计在截止点测量治疗效果,因此我们只能在有明确的截止点将治疗组和对照组分开的情况下应用 RDD。这可以是一个自然的截止点,如地理边界,也可以是一个干预点,如合格奖学金的分数要求。仅通过比较接近临界值两侧的受试者,我们就可以估计平均治疗效果并确定因果关系。
RDD 背后的直觉是,虽然我们知道将受试者分配到不同的组会有偏差,但我们相信接近截止值的受试者是非常相似的,随机性是他们被分配到治疗组或对照组的唯一原因。它非常类似于随机试验,但只使用历史数据。
按作者
正如上图所示,在绘制我们感兴趣的结果变量 Y 和截止值前后的赋值变量 X(截止值变量)之间的回归时,存在一个不连续点。由于治疗组和对照组的受试者之间的治疗效果和其他预先存在的差异,这种不连续性是存在的。然而,我们认为,对于接近临界值 c 的受试者,如 A 和 B,他们的结果差异主要来自治疗,因为他们在 X 变量方面非常接近。
在 RDD 的应用
RDD 第一次被应用于评估奖学金项目的效果(蓟和坎贝尔 1960) 。如果我们想知道获得奖学金(待遇)对学生未来成绩(结果变量)的影响,简单地比较有奖学金和没有奖学金的学生的成绩会在估计中引入偏差。因为过去的成绩而获得奖学金的学生即使没有奖学金也可能比其他学生得分高!简单的比较会高估治疗效果。然而,如果我们只关注接近给予奖学金分数线的学生,即几乎获得奖学金的学生(略低于分数线)和勉强获得奖学金的学生(略高于分数线),我们可以估计他们未来的成绩差异并声称因果关系。由于这些学生过去的成绩如此接近,我们相信除了是否获得奖学金之外,他们在各方面都非常相似,这正是我们进行因果推断所需要的。
另一个有趣的应用是利用 RDD 利用历史交易数据估计优步客户的价格弹性和需求曲线( Cohen et al(2016) )。价格弹性描述了顾客购买的数量和他们面对的价格之间的因果关系。价格弹性高的客户对价格变化很敏感。简单地从历史交易数据中回归价格和购买数量会导致其他因素的偏差,这些因素也会影响客户的购买决策,如季节性、客户收入等。在这篇论文中,研究人员利用优步的“激增”定价算法,并进行回归不连续设计,以估计需求曲线上几个点的需求弹性。直觉是,在价格“暴涨”期间,该算法将根据当地市场供求状况、客户特征等内生生成一个暴涨乘数。尽管市场条件下的激增乘数是内生的,但有一些随机性水平可以用来估计价格弹性。激增乘数“1.244”和“1.246”之间的市场条件彼此非常相似,但是,由于激增乘数只有两位数,前者导致“1.24”,而后者导致“1.25”。由于接近截止点的客户的市场条件非常相似,通过估计接近截止点的客户的反应(交易)的差异,他们能够估计每个点的价格弹性和需求曲线。
虽然 RDD 是估计历史数据因果关系的好方法,但这并不意味着我们不能为了因果推断而利用它来创造新数据。正如优步的例子所展示的,在算法中加入一定程度的随机性可以帮助你以后分析因果关系。另外。有时这比进行野外实验要便宜得多。
警告
尽管 RDD 提供了一个估算因果关系的方便方法,我们仍然需要在进入分析之前仔细检查这些假设是否适用:
- 受试者不应该影响他们是否可以接受治疗:在奖学金的例子中,学生不应该能够说服教授给他们奖学金,即使他们的成绩没有通过截止日期;
- 临界值不应该被具有相同临界值的治疗方法所污染:例如,赌博的法定年龄也是 21 岁,这一事实可能会污染一项使用 RDD 和 21 岁临界值分析酒精影响的研究。
这就是本文的全部内容。感谢您的阅读。这是我所有博客帖子的列表。如果你感兴趣的话,可以去看看!
https://zzhu17.medium.com/my-blog-posts-gallery-ac6e01fe5cc3 https://zzhu17.medium.com/membership
参考
[1] 回归不连续设计百科
[2]李,大卫和托马斯·雷米尔。2010."经济学中的回归不连续设计."经济文献杂志,48(2):281–355。
[3]thislethwaite,d .和 D. Campbell。"回归-不连续分析:事后实验的替代方法."教育心理学杂志51(1960):309–317。
[4]科恩,p .,哈恩,r .,霍尔,j .,莱维特,s .,&梅特卡夫,R. (2016)。利用大数据估算消费者剩余:优步案例(第 w22627 号)。美国国家经济研究局。
强化学习导论
展示支持 RL 的关键概念
最近在强化学习的帮助下取得的成功被媒体广泛报道。人们可以想到 DeepMind 的 AlphaGo 算法:使用强化学习(和大量昂贵的硬件来训练它),AlphaGo 学会了玩围棋这一古老的游戏,甚至开发了自己的游戏风格。
OpenAI 展示了另一个例子,其研究人员教会了一只机器手解魔方。有趣的是,它是在虚拟环境中训练的;因为即使拿着一个立方体转动而不掉它也是相当困难的,这是令人惊奇的第一步。
我写这篇文章的目的是首先解释使这种成功成为可能的概念。我从介绍开始,然后逐步完善 RL 的定义。
介绍
强化学习是机器学习的一个领域。您可能已经使用过监督学习(数据被标记)和非监督学习(未标记的数据,例如,用于生成技术)。这两大领域由强化学习领域补充。两个关键区别在于,数据通常不是独立且相同地分布的(即,它可能非常杂乱,没有明显的结构),并且代理的行为决定了它遇到的未来数据。
用一句非正式的话来说,强化学习学习通过互动来达到一个目标。
让我们来看看机器学习这一分支背后的基本成分:
首先,我们有提到的代理。代理既是学习者又是决策者。现实生活中的类比就是你和我,都在做决策,都在不停地学习。第二,代理可以与之交互的一切都是环境(对我们来说是我们的正常环境:其他人、建筑物、汽车、狗、猫等等)。第三,这种环境可以通过互动来改变,这是代理人产生影响的唯一方式。在每一种可能的情况下,代理人可以决定一个行动,并依次获得奖励。这种奖励会影响学习过程。
MDP
这个描述相当模糊。为了给强化学习下一个更精确的定义,我们需要一种数学方法。这就是马尔可夫决策过程的用武之地,它是一种对状态之间的转换进行建模的数学方法。我们有一个五元组(s,a,r,p,p₀) [1,2]:
S 是状态空间,包含一个代理可能遇到的所有可能的状态。因此,每一个状态 s ∈ S。
a 是动作空间,包含代理可能的动作。同样,我们有每一个动作。
R 是奖励函数,它基于当前状态 sₜ、选择的动作 aₜ和结果状态 sₜ₊₁.,传递代理动作的奖励我们包括结果状态也是为了考虑状态之间的转换。如果没有它,在不同的时间步骤在相同的状态下行动会产生相同的回报——不考虑代理人可能已经学到了什么。换句话说,动作 a 在 t 和 t+k 可以是相同的,但是可能导致不同的新状态。我们通过添加 sₜ₊₁.来考虑这一点奖励是一个实数,比如+1,-2.5 等等。
P 是将状态和动作映射到概率的函数。它决定了从 sₜ出发并选择 aₜ.行动时到达 sₜ₊₁州的概率我们的环境可能会受到我们无法控制的事件的影响。为此,我们有 P,它考虑了外部影响。如果我们没有这样的影响,我们简单地使用一个确定性的转变,也就是说,新的状态是保证达到的。
最后,我们有 p₀,这是初始状态的分布,也就是说,它包含了所有我们可以开始的状态。
你还记得手机游戏 DoodleJump 吗?还是任天堂设备上的马里奥游戏?让我们构建一个与这两个类似的设置:
我们的敌人从右侧进来(这是来自马里奥),我们向上跳一级就可以躲开他们(这是来自嘟嘟跳)。我们的状态空间 S 由两个状态组成,低和高。
在这两种状态下,我们有两种可能的动作,跳转和等待,它们构成了动作空间 A 。
每次我们从低处跳到高处或者从高处跳到高处,我们都会得到+1 的奖励。当我们被敌人击中时,我们会下降一级,奖励是-1(注意,这里的奖励不是与一个动作相关联,例如跳跃或等待,而是与我们被外部影响击中的事实相关联)。等待的回报是 0。
现在到 P ,它决定了我们达到下一个水平的可能性有多大。这是 80 %,有 20 %我们保持在目前的水平。等待可能导致停留在当前水平或被敌人击中的概率相等;因此,两者的概率都是 50 %。最后,我们的 p ₀只包含状态低。
政策
到目前为止,我们已经讨论了动作和环境,但是没有讨论如何在给定的状态下确定适当的动作。因为我们有多个状态和多个时间步,我们需要一些进一步的算法来帮助我们。这是策略的任务π,从一个状态到一个动作的映射:π(aₜ|sₜ)是在状态 sₜ选择 aₜ的概率1,2。由此出发,我们可以从所有可能的动作中抽取动作,用 aₜπ表示。|sₜ).
该策略是可以由深度 RL 中的神经网络建模的部分[1]。
对于我们的示例,我们的策略由以下映射组成:(jump|low) = (jump|high) = 50 %。这意味着在低和高的状态中,我们以 50 %的概率选择动作跳转。(等待|低)和(等待|高)的概率各为 50 %。
奖励
到目前为止,我们已经介绍了政策,但还没有介绍奖励的形式和作用。开始时,我注意到我们希望代理实现一个目标。这个比较模糊。更正式地说,我们希望代理人最大化预期报酬。
让我们来看看这个:
从我们最初的状态,s₀和 a₀把我们带到 s₁.和 a₁一起我们去了 s₂.和 a₂一起,我们前进到 s₃.这种情况可能会持续无限长的时间。这种状态和动作的序列被称为轨迹,表示为τ。此外,我们还会在每个动作之后获得奖励,奖励 rₜ₊₁(因为奖励考虑了结果状态,所以奖励也会在下一个时间步支付, t+1 )。有了轨迹和奖励,我们可以通过对所有个人奖励求和来计算我们的最终回报,或累计奖励【1,2】
回到我们的例子,考虑这个轨迹:(低,跳,高,跳,高)。由低到高过渡的奖励是+1,由高到高的奖励也是+1。对于这个轨迹,回报是 2。
在有限的动作序列的情况下,这就是我们所需要的。但是当我们处理无休止运行的环境时,这就产生了一个问题:
每个奖励目前都具有相同的重要性,无论它发生在一个近时间点(因此可能更有形)还是无限的边缘(非常无形)。此外,这也是更重要的,我们的回报是没有界限的,它不会收敛到一个固定的值。这使得比较两个策略变得很困难:一个可能总是得到+1,-1,+1,-1,…,而另一个策略可能经常得到+10,+10,+10,只是后来犯了一个严重的错误,抵消了我们到目前为止所取得的一切。换句话说,当轨迹无穷无尽时,我们不知道从长远来看哪种政策会更好,因为一切都可能发生。
幸运的是,这可以通过使用折扣回报来解决,这是一种更通用的方法:我们用折扣乘以每个奖励,这量化了它的重要性(将折扣设置为 1 导致之前的未折扣回报)[1,2]:
因此,贴现回报迫使代理人“早赢比晚赢好”[3]。
为了最大化预期回报,我们需要我们的政策(检查),我们的轨迹(检查),和回报(检查)。配备了它们,我们开始:
让我解释一下这个等式:给定一个策略π,我们想知道我们得到一个特定的状态和动作序列的可能性有多大(这是轨迹,τ)。为此,我们取我们的初始状态 s₀的概率,然后乘以所有进一步的概率(这是∏部分)。对于我们到达的每一个后来的状态 sₜ₊₁,我们检查它到达这个状态(这是 P(sₜ₊₁|sₜ,aₜ)的可能性,并且将它乘以采取引导我们到达那里的行动的可能性(这是π(aₜ|sₜ)).)
在此基础上,我们写下预期回报是我们通过政策π获得的回报,然后根据它采取行动(这为我们提供了轨迹,即状态-行动序列的列表)。如上所述,对于每个这样的轨迹,我们都有一个回报。检查所有可能的轨迹(所有可能的状态-行动序列),并总结它们各自的回报,我们就有了预期的回报[1,2]:
让我更详细地描述这个方程:我们通过写出τ∞p(⋅|π).来取每个可能的轨迹正如我上面所写的,每个轨迹都有发生的概率,每个轨迹都有回报。通过将概率乘以回报(用 R(τ)来描述),我们根据可能性对结果进行加权。这遵循了计算期望值的正常方式:
对于我们的例子,我们有这两个轨迹:(低,跳,高,跳,高)(奖励为 2),以及轨迹(低,跳,高,等待,低)(奖励为 0: +1 表示前进,-1 表示等待并被敌人击中,从而下降一级)。
现在让我们计算第一个轨迹的概率:它是 1×0.8×0.5×0.8×0.5 = 0.16;1 是开始状态低的概率,0.8 × 0.5 是前进到下一个级别的概率,乘以选择动作跳转的概率。类似地,我们继续第二个轨迹:1 × 0.8 × 0.5 × 0.5 × 0.5 = 0.1,唯一的区别是 0.5 × 0.5。这里,我们取等待的概率为 0.5(也就是在这种情况下下降一级),并将其乘以成功率,0.5。
有了每条轨迹的回报和概率,我们现在可以按照上面的等式计算预期回报:0.16 × 2 + 0.1 × 0=0.32。因此我们的预期收益是 0.32。
这样,我们可以进一步形式化我们的 RL 定义:找到最大化期望回报的策略[1,2]
这是最佳策略。
价值函数
说了这么多,我们怎么知道一个动作是好的动作,或者一个状态是好的状态呢?我们可以通过价值函数和行动价值函数找到答案。简而言之,给定一个策略π,一个状态的值就是从这个状态得出的预期回报,并且此后总是按照π行事。使用数学符号,我们把它写成
类似地,对于行动价值函数,我们也需要策略π。与之前不同,我们现在将值分配给一对状态和动作[1,2]。同样,这个价值也是我们在 s₀开始与 a₀:合作时的预期回报
有了 Q ,我们就可以简单地选择一个状态的下一个动作,作为最大化期望回报的动作
同样,我们可以通过查询 V 来检查一个状态的值。
酷的是,有了最优政策,我们可以找到最优价值和最优行动价值函数。这个最优策略对于任何 MDP 都是存在的。挑战在于找到它。
参考
[1]乔希·阿奇姆,在《极深 RL》(2020),OpenAI
[2]萨顿,理查德 S 和巴尔托,安德鲁 G,《强化学习:导论》 (2018),麻省理工学院出版社
[3]迈克尔·l·利特曼,马尔可夫博弈作为多主体强化学习的框架 (1994),机器学习论文集
强化学习导论:K 臂强盗
k 臂土匪问题引入了很多强化学习的思想。多读点了解一下。
最近有很多关于强化学习(RL)的宣传,这是理所当然的。自从 DeepMind 发表论文“用深度强化学习玩雅达利”以来,已经出现了许多有希望的结果,其中最著名的可能是 AlphaGo。然而,在我们能够理解这些模型如何工作之前,我们需要理解强化学习的一些基本原理。我认为对这些概念最好的介绍是通过一个简单得多的问题——所谓的“k 臂土匪问题”。
问题是
首先,我们来定义一下什么是 k 臂土匪问题。“k 臂强盗”这个词让人想起《星球大战》中波巴·费特和章鱼杂交的画面,但幸运的是事情没有那么疯狂。相反,你可以把强盗想象成一个老虎机,而 k 个手臂中的每一个都是一个杠杆。拉动 k 杆中的一个会给你一个正的回报。在大多数强化学习问题中,你的目标是最大化你的总回报,给定固定数量(比如 1000)的拉力。你唯一的先验信息是每个杠杆的平均回报不随时间变化。这里的最佳策略是什么?
如果我们知道每个杠杆的平均回报,这个问题就简单了。我们总是拉着平均回报最高的杠杆。所以一个可能的方法是首先使用一些拉力来计算出哪一个杠杆有最高的平均回报,然后只拉那个杠杆。
应该怎么搞清楚哪个杠杆最好?我们需要多次尝试所有的杠杆,因为即使每个杠杆的平均回报是固定的,每次拉动杠杆都会得到不同的回报。一旦我们多次尝试每个杠杆,我们可以取所有拉力的平均值作为真实回报的近似值。换句话说,一种可能的算法是:
算法 1
拉动每根杠杆 n 次,平均每根杠杆的 n 次回报。
平均值最高的杠杆就是最好的杠杆。从现在开始只拉那个。
这就有一个问题,就是我们不知道如何设置 n,比如说我们用 n = 3。对于其中一个杠杆,我们拉 3 次,我们得到 14、15 和 16 的回报,平均下来是 15。然而,那个杠杆的真实平均回报是 5——我们只是非常幸运地拉了三次。现在我们有麻烦了,因为我们总是假设这个杠杆比它实际上要好得多。我们可以使 n 变大,这将使我们更加确信我们的平均值是准确的。然而,由于我们的时间步数有限,我们不想浪费杠杆拉动。因此,设置大的 n 也有问题。
我们可以完全避免固定一个数字 n。相反,我们保留了每个杠杆的运行平均回报。另一种可能的算法是:
算法二
在做任何拉动之前,将每个杠杆的移动平均值设置为 0。
对于每个时间步长:
- 选择运行平均值最高的杠杆。如果有平局,在平局的杠杆之间随机选择。
- 拉动我们刚刚选择的杠杆,观察回报,并用回报修改该杠杆的运行平均值。
从理论上讲,这种算法的优势在于,它总是越来越接近每个杠杆的真实平均回报。没有每根杠杆 n 的拉动次数,在此之后我们停止学习。可惜行不通。在第一个时间步,这个算法将拉动一个随机杠杆,得到一个正的回报。然后,因为所有其他运行平均值都设置为 0,它将永远从第一个时间步长继续拉动杠杆。它永远不会碰到其他杠杆。
解决这个问题的一个办法是使用另一个参数 epsilon,它控制我们是拉具有最高运行平均值的杠杆,还是拉随机的杠杆。我们的算法变成了:
算法三
在做任何拉动之前,将每个杠杆的移动平均值设置为 0。
将 epsilon 设置为[0,1]中的一个数字。
对于每个时间步长:
- 在[0,1]中得到一个随机数(来自均匀分布)x。
- 如果 x >ε,选择运行平均值最高的杠杆。如果有平局,在平局的杠杆之间随机选择。
- 如果 x
- 拉动我们刚刚选择的杠杆,观察回报,并用回报修改该杠杆的运行平均值。
这个算法确实有效。通过 x 的随机性,最终我们将被迫尝试所有的杠杆足够的次数,以获得所有杠杆的精确运行平均值。然而,我们必须决定ε是什么。如果我们将 epsilon 设置得更接近 1,算法将更均匀地尝试杠杆,从而得到更好的估计,但总回报会更低。如果我们将 epsilon 设置得更接近 0,算法将更多地关注几个杠杆,导致不太准确的估计,但可能会有更高的回报。
RL 视角
现在让我们把所有这些放在强化学习的术语中。首先,我们注意到我们想要得到每个杠杆的真实平均回报的精确估计。我们称每个杠杆的真实平均回报为问题的行动价值函数。为什么叫这个?嗯,在我们的问题中,我们可以采取的可能的行动是拉动每个杠杆。每拉一次杠杆,就有一个真实的平均奖励值。更正式地说,动作值函数由 Q(a) 表示。 Q 是函数, a 代表可能的动作。我们不知道 Q ,所以我们试着估计一下,记为 Q* 。我们的希望是 Q*将接近 Q。
我们也想出了一些具体的算法来解决这个土匪问题。算法 1 有两个独立的部分。第一部分试图通过使用每个杠杆 n 次拉动的样本平均值来近似动作值函数(求 Q*)。第二部分用 Q来决定拉哪个杠杆。在高层次上,算法的第一部分,寻找 Q,被称为探索。算法的第二部分,使用由 Q*确定的最佳动作/拉动,称为利用。我们在设置该算法的参数 n 时遇到了一些问题。同样,我们很难决定如何在勘探和开采之间划分时间间隔。这是强化学习中的一个常见主题。
我们把总是利用贪婪算法的算法叫做。贪婪算法总是试图最大化每个时间步长的回报;它不探索。我们在算法 2 中看到了这个问题。因为没有进行探索,所以在短期内贪婪算法可能工作得很好,但从长期来看,它几乎肯定是次优的。
我们提出的另一个算法(算法 3)使用结合了参数ε的移动平均值。艾司隆有效地控制了勘探和开采之间的平衡。如果ε接近 0,大部分时间我们都会在做剥削,或者贪婪算法。正因为如此,这类算法被称为“ epsilon-greedy ”,因为 epsilon 控制着我们想要有多贪婪。ε-贪婪算法是非常常用的,包括在本文开头链接的 Atari 论文中。
让我们回顾一下我们已经讲过的内容。首先,我们解释了 k 臂土匪问题和几种可能的解决方案。我们注意到,逼近动作值函数是解决问题的重要一步。我们看到了平衡探索和利用的困难,这是强化学习问题中的一个常见主题。最后,我们讨论了贪婪和ε贪婪算法,并讨论了它们如何绑定到探索/开发框架中。强化学习是一个相当广泛的话题,但是我希望这篇文章能够阐明一些基本概念。
使用 OpenAI Gym、RLlib 和 Google Colab 进行强化学习的介绍
使用 OpenAI Gym、RLlib 和 Google Colab 进行强化学习的入门教程
本教程将使用强化学习(RL)来帮助平衡一个虚拟的横竿。上面来自 PilcoLearner 的视频展示了在现实生活中使用 RL 的结果。
强化学习(RL)的一个可能的定义是学习如何在与环境交互时最大化总回报的计算方法。虽然定义是有用的,但本教程旨在通过图像、代码和视频示例来说明什么是强化学习,同时介绍代理和环境等强化学习术语。
特别是,本教程探索了:
- 什么是强化学习
- 开放的健身房钢管环境
- 代理在强化学习中的作用
- 如何使用 Python 库 RLlib 训练代理
- 如何使用 GPU 加速训练
- 使用光线调节进行超参数调节
什么是强化学习
正如之前的一篇帖子提到的,人工智能的一个子领域机器学习(ML)使用神经网络或其他类型的数学模型来学习如何解释复杂的模式。ML 的两个领域由于其高度的成熟度而最近变得非常受欢迎,这两个领域是监督学习(SL)和强化学习(RL),在监督学习中,神经网络学习基于大量数据进行预测,在强化学习中,网络使用模拟器以试错的方式学习做出良好的行动决策。
作者图片
RL 是令人难以置信的成功背后的技术,例如 DeepMind 的 AlphaGo Zero 和《星际争霸 2》AI(alpha star)或 OpenAI 的 DOTA 2 AI(“open AI Five”)。请注意强化学习有许多令人印象深刻的用途,它在现实生活决策问题中如此强大和有前途的原因是因为 RL 能够持续学习——有时甚至在不断变化的环境中——从不知道要做出什么决定(随机行为)开始。
代理和环境
作者图片
上图显示了代理和环境之间的交互和通信。在强化学习中,一个或多个智能体在一个环境中相互作用,这个环境可以是本教程中类似 CartPole 的模拟,也可以是与真实世界传感器和执行器的连接。在每一步,代理接收一个观察(即环境的状态),采取一个行动,并且通常接收一个奖励(代理接收奖励的频率取决于给定的任务或问题)。代理人从重复的试验中学习,这些试验的序列被称为一个事件——从最初的观察到导致环境达到其“完成”状态的“成功”或“失败”的动作序列。RL 框架的学习部分训练关于哪些动作(即,顺序决策)导致代理最大化他们的长期累积回报的策略。
开放的健身房钢管环境
作者图片
我们试图解决的问题是试图保持一根柱子直立。具体来说,该杆通过一个非驱动关节连接到一个小车上,小车沿无摩擦轨道移动。钟摆开始直立,目标是通过增加和减少小车的速度来防止它倒下。
作者图片
本教程将使用 OpenAI Gym 而不是从头开始编写这个环境,OpenAI Gym 是一个工具包,它提供了各种各样的模拟环境(雅达利游戏、棋盘游戏、2D 和 3D 物理模拟,等等)。Gym 对您的代理的结构没有任何假设(在这个 cartpole 示例中,是什么推动小车向左或向右),并且与任何数值计算库兼容,比如 numpy。
下面的代码加载 CartPole 环境。
import gym
env = gym.make("CartPole-v0")
现在让我们通过观察动作空间来开始理解这个环境。
env.action_space
输出离散(2)意味着有两个动作。在 CartPole 中,0 对应“向左推车”,1 对应“向右推车”。请注意,在这个特定的例子中,静止不动不是一个选项。在强化学习中,代理产生一个动作输出,这个动作被发送到一个环境中,然后环境做出反应。环境会产生一个观察结果(以及奖励信号,此处未显示),我们可以在下面看到:
env.reset()
观察值是 dim=4 的向量,包含小车的 x 位置、小车的 x 速度、以弧度表示的极角(1 弧度= 57.295 度)以及极的角速度。上面显示的数字是开始新一集( env.reset()
)后的初步观察。随着每个时间步长(和动作),观察值将会改变,这取决于小车和杆子的状态。
培训代理
在强化学习中,代理的目标是随着时间的推移产生越来越聪明的行为。它通过一项政策做到了这一点。在深度强化学习中,这种策略用神经网络来表示。让我们首先在没有任何神经网络或机器学习算法的情况下与健身房环境进行交互。相反,我们将从随机运动(向左或向右)开始。这只是为了理解机制。
作者图片
下面的代码重置环境,需要 20 个步骤(20 个周期),总是采取随机操作并打印结果。
# returns an initial observation
env.reset()for i in range(20): # env.action_space.sample() produces either 0 (left) or 1 (right).
observation,reward,done,info =env.step(env.action_space.sample()) print("step", i, observation, reward, done, info)env.close()
样本输出。在钢管舞中有多种终止情节的条件。在图像中,该集因超过 12 度(0.20944 rad)而终止。情节终止的其他条件是推车位置大于 2.4(推车的中心到达显示器的边缘),情节长度大于 200,或者当 100 次连续试验的平均回报大于或等于 195.0 时的解决要求。
上面的打印输出显示了以下内容:
- 步骤(它在环境中循环了多少次)。在每个时间步中,代理选择一个动作,环境返回一个观察和一个奖励
- 环境观察[x 推车位置、x 推车速度、杆角度(rad)、杆角速度]
- 前一次行动获得的奖励。规模因环境而异,但目标始终是增加你的总回报。包括终止步骤在内,每一步的奖励是 1。之后为 0(图中的步骤 18 和 19)。
- done 是一个布尔值。它指示是否该再次重置环境。大多数任务被划分为定义明确的情节,如果 done 为 True,则表明该情节已经终止。在推车杆中,可能是杆倾斜过远(超过 12 度/0.20944 弧度),位置超过 2.4 表示推车的中心到达显示器的边缘,情节长度大于 200,或者解决的要求是在 100 次连续试验中平均回报大于或等于 195.0。
- info 是对调试有用的诊断信息。对于这种横向环境,它是空的。
虽然这些数字是有用的输出,但视频可能会更清晰。如果您在 Google Colab 中运行这段代码,需要注意的是,没有可用于生成视频的显示驱动程序。但是,可以安装一个虚拟显示驱动程序来让它工作。
# install dependencies needed for recording videos
!apt-get install -y xvfb x11-utils
!pip install pyvirtualdisplay==0.2.*
下一步是启动虚拟显示器的实例。
from pyvirtualdisplay import Display
display = Display(visible=False, size=(1400, 900))
_ = display.start()
OpenAI gym 有一个 VideoRecorder 包装器,可以录制 MP4 格式的跑步环境视频。下面的代码和前面的一样,除了它是 200 步,并且是录音。
from gym.wrappers.monitoring.video_recorder import VideoRecorderbefore_training = "before_training.mp4"video = VideoRecorder(env, before_training)# returns an initial observation
env.reset()for i in range(200):
env.render()
video.capture_frame() # env.action_space.sample() produces either 0 (left) or 1 (right).
observation, reward, done, info = env.step(env.action_space.sample()) # Not printing this time
# print("step", i, observation, reward, done, info)video.close()
env.close()
通常,当 done 为 1(真)时,您将结束模拟。上面的代码让环境在达到终止条件后继续运行。例如,在 CartPole 中,这可能是杆翻倒、杆脱离屏幕或达到其他终止条件的时候。
上面的代码将视频文件保存到 Colab 磁盘中。为了在笔记本中显示它,您需要一个助手函数。
**from** base64 **import** b64encode
**def** **render_mp4**(videopath: str) -> str:
"""
Gets a string containing a b4-encoded version of the MP4 video
at the specified path.
"""
mp4 = open(videopath, 'rb').read()
base64_encoded_mp4 = b64encode(mp4).decode()
**return** f'<video width=400 controls><source src="data:video/mp4;' \
f'base64,{base64_encoded_mp4}" type="video/mp4"></video>'
下面的代码呈现了结果。你应该得到一个类似于下面的视频。
**from** IPython.display **import** HTML
html = render_mp4(before_training)
HTML(html)
播放视频表明,随机选择一个动作并不是保持侧手翻直立的好策略。
如何使用 Ray 的 RLlib 训练代理
教程的前一部分让我们的代理做出随机的行为,而不考虑环境的观察和奖励。拥有一个代理的目标是随着时间的推移产生越来越聪明的行为,而随机的行为并不能实现这个目标。为了让代理人随着时间的推移做出更明智的行动,itl 需要一个更好的策略。在深度强化学习中,策略用神经网络来表示。
作者图片
本教程将使用 RLlib 库来训练一个更聪明的代理。RLlib 有许多优点,例如:
- 极度的灵活性。它允许您定制 RL 周期的每个方面。例如,本节教程将使用 PyTorch 创建一个定制的神经网络策略(RLlib 也有对 TensorFlow 的本地支持)。
- 可扩展性。强化学习应用程序可能是计算密集型的,并且通常需要扩展到一个集群以实现更快的训练。RLlib 不仅对 GPU 有一流的支持,而且它还建立在 Ray 之上,后者是并行和分布式 Python 的开源库。这使得将 Python 程序从笔记本电脑扩展到集群变得容易。
- 统一的 API 和对离线、基于模型、无模型、多代理算法等的支持(本教程不探讨这些算法)。
- 成为 Ray 项目生态系统的一部分。这样做的一个优点是,RLlib 可以与生态系统中的其他库一起运行,如Ray tuning,这是一个用于实验执行和任何规模的超参数调整的库(稍后将详细介绍)。
虽然有些功能在这篇文章中不会被完全利用,但是当你想做一些更复杂的事情和解决现实世界的问题时,它们是非常有用的。你可以在这里了解一些令人印象深刻的 RLlib 用例。
要开始使用 RLlib,您需要首先安装它。
!pip install 'ray[rllib]'==1.6
现在,您可以使用近似策略优化(PPO)算法来训练 PyTorch 模型。这是一个非常全面的,适合所有类型的算法,你可以在这里了解更多关于的信息。下面的代码使用了一个由 32 个神经元和线性激活函数组成的单一隐藏层的神经网络。
import ray
from ray.rllib.agents.ppo import PPOTrainerconfig = { "env": "CartPole-v0",
# Change the following line to `“framework”: “tf”` to use tensorflow
"framework": "torch",
"model": {
"fcnet_hiddens": [32],
"fcnet_activation": "linear",
},
}stop = {"episode_reward_mean": 195}ray.shutdown()ray.init(
num_cpus=3,
include_dashboard=False,
ignore_reinit_error=True,
log_to_driver=False,
)# execute training
analysis = ray.tune.run(
"PPO",
config=config,
stop=stop,
checkpoint_at_end=True,
)
这段代码应该会产生相当多的输出。最后一个条目应该是这样的:
条目显示,解决环境问题需要 35 次迭代,运行时间超过 258 秒。每次都不一样,但是每次迭代大概需要 7 秒(258 / 35 = 7.3)。注意,如果你想学习 Ray API,看看像 ray.shutdown 和 ray.init 这样的命令是做什么的,你可以看看这个教程。
如何使用 GPU 加速训练
虽然本教程的其余部分使用了 CPU,但需要注意的是,您可以通过在 Google Colab 中使用 GPU 来加速模型训练。这可以通过选择运行时>更改运行时类型并将硬件加速器设置为 GPU 来完成。然后选择运行时>重启并运行所有。
请注意,虽然训练迭代的次数可能大致相同,但是每次迭代的时间已经显著减少(从 7 秒减少到 5.5 秒)。
创建训练模型的视频
RLlib 提供了一个 Trainer 类,它保存了一个环境交互策略。通过训练器界面,可以对策略进行训练、操作计算和检查。虽然之前从ray.tune.run
返回的分析对象不包含任何训练器实例,但是它拥有从保存的检查点重建一个所需的所有信息,因为checkpoint_at_end=True
是作为参数传递的。下面的代码显示了这一点。
# restore a trainer from the last checkpoint
trial = analysis.get_best_logdir("episode_reward_mean", "max")
checkpoint = analysis.get_best_checkpoint(trial,
"training_iteration",
"max",
)trainer = PPOTrainer(config=config)
trainer.restore(checkpoint)
现在让我们创建另一个视频,但这一次选择由经过训练的模型推荐的动作,而不是随机动作。
after_training = "after_training.mp4"
after_video = VideoRecorder(env, after_training)observation = env.reset()
done = False
while not done:
env.render()
after_video.capture_frame()
action = trainer.compute_action(observation)
observation, reward, done, info = env.step(action)
after_video.close()
env.close()# You should get a video similar to the one below.
html = render_mp4(after_training)
HTML(html)
这一次,杆子平衡得很好,这意味着代理已经解决了横竿环境!
使用光线调节进行超参数调节
射线生态系统(图片由作者提供)
RLlib 是一个强化学习库,是 Ray 生态系统的一部分。Ray 是一个高度可扩展的并行和分布式 python 通用框架。它非常通用,这种通用性对于支持其图书馆生态系统非常重要。这个生态系统涵盖了从培训,到生产服务,到数据处理等等。您可以一起使用多个库,并构建完成所有这些事情的应用程序。
教程的这一部分利用了 Ray Tune ,这是 Ray 生态系统中的另一个库。这是一个用于任何规模的实验执行和超参数调整的库。虽然本教程将只使用网格搜索,但请注意,光线调整还可以让您访问更有效的超参数调整算法,如基于群体的训练,BayesOptSearch 和 HyperBand/ASHA。
现在让我们试着找出能够在最少的时间内解决 CartPole 环境的超参数。
输入以下代码,并准备好它需要一段时间才能运行:
parameter_search_config = {
"env": "CartPole-v0",
"framework": "torch",# Hyperparameter tuning
"model": {
"fcnet_hiddens": ray.tune.grid_search([[32], [64]]),
"fcnet_activation": ray.tune.grid_search(["linear", "relu"]),
},
"lr": ray.tune.uniform(1e-7, 1e-2)
}# To explicitly stop or restart Ray, use the shutdown API.
ray.shutdown()ray.init(
num_cpus=12,
include_dashboard=False,
ignore_reinit_error=True,
log_to_driver=False,
)parameter_search_analysis = ray.tune.run(
"PPO",
config=parameter_search_config,
stop=stop,
num_samples=5,
metric="timesteps_total",
mode="min",
)print(
"Best hyperparameters found:",
parameter_search_analysis.best_config,
)
通过向 ray.init 传递 num_cpus=12 来请求 12 个 CPU 内核,可以在三个 CPU 上并行运行四次试验。如果这不起作用,也许谷歌已经改变了 Colab 上可用的虚拟机。任何大于或等于 3 的值都可以。如果 Colab 因内存不足而出错,你可能需要做运行时>工厂重置运行时,紧接着运行时>运行所有。请注意,在 Colab 笔记本的右上角有一个区域显示 RAM 和磁盘的使用情况。
指定 num_samples=5 意味着您将获得学习率的五个随机样本。对于其中的每一个,隐藏层的大小有两个值,激活函数有两个值。因此,将有 5 * 2 * 2 = 20 次试验,在计算运行时,在单元的输出中显示它们的状态。
注意,Ray 会打印当前的最佳配置。这包括所有已经设置的默认值,这是找到其他可以调整的参数的好地方。
运行此命令后,最终输出可能类似于以下输出:
INFO tune.py:549 —总运行时间:3658.24 秒(调优循环为 3657.45 秒)。
找到的最佳超参数:{‘env’: ‘CartPole-v0 ‘,’ framework’: ‘torch ‘,’ model’: {‘fcnet_hiddens’: [64],’ fcnet_activation’: ‘relu’},’ lr ‘:0.006733929096170726 };’ ’ ’ ’
因此,在二十组超参数中,具有 64 个神经元、ReLU 激活函数和大约 6.7e-3 的学习率的超参数表现最好。
结论
神经 MMO 是一个模拟大型多人在线游戏的环境——一种支持数百到数千个并发玩家的类型。你可以在这里了解 Ray 和 RLlib 如何帮助实现这个项目和其他项目的一些关键特性(图片由 Joseph Suarez 提供,经许可使用)
本教程通过介绍强化学习术语,展示代理和环境如何交互,并通过代码和视频示例演示这些概念,说明了什么是强化学习。如果你想了解更多关于强化学习的知识,请查看斯文·米卡的 RLlib 教程。这是了解 RLlib 的最佳实践、多代理算法以及更多内容的好方法。如果你想了解所有关于 RLlib 和 Ray 的最新消息,可以考虑关注 twitter 上的@ Ray distributed和注册 Ray 简讯。
数据科学家的 SQL 介绍
UCL 数据科学学会工作坊 9:什么是 SQL,选择数据,查询数据,汇总统计,分组数据,连接数据
简·安东宁·科拉尔在 Unsplash 上拍摄的照片
今年,作为 UCL 数据科学协会的科学负责人,该协会将在整个学年举办一系列 20 场研讨会,主题包括 Python 简介、数据科学家工具包和机器学习方法等。每一篇文章的目标都是创建一系列的小博客,这些小博客将概述要点,并为任何希望跟进的人提供完整研讨会的链接。所有这些都可以在我们的 GitHub 资源库中找到,并将在全年更新新的研讨会和挑战。
本系列的第九个研讨会是 SQL 简介,是数据科学家工具包系列的最后一个研讨会。在本次研讨会中,我们将向您介绍在 SQL 中查询数据、从数据中提取汇总统计数据、对数据集进行分组和连接的基础知识。如果你想继续写代码,你可以在我们的 GitHub 这里找到完整的研讨会,其中包含了如何使用 docker 容器在你的系统上建立 MySQL 数据库,如何将数据推送到数据库以及如何与 MySQL workbench 交互的信息。
如果您错过了最近的任何研讨会,您可以在此找到它们:
什么是 SQL?
SQL(结构查询语言)是在关系数据库管理系统中处理数据库时使用最广泛的编程语言之一。它用于执行各种不同的操作,如选择数据、查询数据、分组数据和提取汇总度量,如下所示。在处理数据科学项目的数据时,它是一个在工业和学术界广泛使用的工具,因此理解 SQL 是任何数据科学家工具包中的一个关键工具。为此,我们向您介绍 SQL 中的一些基本命令,以及如何使用它们来操作和提取数据。
选择数据
我们想做的第一件事是能够从我们的数据库中选择数据,看看它看起来像什么。我们可以通过使用SELECT
命令来做到这一点,然后使用FROM
命令告诉我们想要这个信息的位置。在我们的例子中,我们有两个名为single_table
和double_table
的表,所以首先我们可以使用命令从第一个表中提取所有信息:
SELECT *
FROM single_table;
该命令将返回来自single_table
的所有数据,因为我们使用*
来表示我们想要所有列。
这将根据表的大小返回大量数据,因此我们可能只想查看几列,可能只查看前 100 行。我们可以通过修改我们的 SQL 语句来做到这一点,这样我们就不会使用*
变量来选择所有的列,而是使用实际的名称,然后设置一个LIMIT
来只返回前 100 行。我们可以使用以下命令来实现这一点:
SELECT `Air Date`, Category, `Value`
FROM single_table
LIMIT 100;
在这里,我们选择了 Air Date、Category 和 Value 列(第一列和第三列用’'括起来,因为它们包含一个空格或者是关键字),我们将一个LIMIT
设置为 100 行。为此,在末尾使用;
分隔语句非常重要,否则 MySQL 不会将它们识别为单独的语句。
搜索条件
上述语句将返回所选列中的所有数据,但是我们可以创建更高级的搜索,以便在特定条件下进行匹配。当您仅从数据集中搜索特定信息以便缩小分析范围时,通常会出现这种情况。
在我们的例子中,我们有Category
、Air Date
和Value
列,因此我们可以搜索属于HISTORY
类别的所有问题。这是通过使用WHERE
命令来指定我们希望数据匹配的条件,如下所示:
SELECT `Air Date`, Category, `Value`
from single_table
WHERE Category = "HISTORY"
LIMIT 100;
这个WHERE
语句允许我们添加对数据进行子集化的条件,并允许我们使用任何想要的比较运算符,例如>
、<
、==
、BETWEEN
、LIKE
和IN
。首先指定要应用条件的列,然后使用上述操作符设置条件本身。
我们还可以通过WHERE
条件组合使用AND
、OR
和NOT
的条件来进行更高级的搜索。例如,如果我们想将搜索范围缩小到类别为“历史”的问题,但该问题的价值也大于 200 美元,我们可以这样做:
SELECT `Air Date`, Category, `Value`
FROM single_table
WHERE Category = "HISTORY"
AND `Value` > 200
LIMIT 100;
汇总统计数据
除了提取信息以便稍后执行计算,SQL 还可以自己执行计算。这包括从列中提取所有不同值、计算数据集中值的数量或从数字列中提取平均值、最小值或最大值等功能。
例如,使用位于CATEGORY
列中心的DISTINCT
和COUNT
命令从数据集中提取不同类别的数量。我们可以这样做:
SELECT COUNT(DISTINCT CATEGORY)FROM single_table;
这应该会返回一个单一的数字,我们有多少独特的类别。如果我们只想要一个唯一类别的列表,我们可以放下COUNT
命令,我们将得到所有这些类别的列表。其他汇总统计包括MIN
、MAX
、AVG
和SUM
,就像我们在熊猫数据帧中预期的那样。
分组数据
对于数值,我们可以使用各自的命令从列中提取MAX
、MIN
和AVG
值,就像我们对COUNT
所做的那样。但是,我们可能希望从不同的数据组中获取这些值,然后提取每组的信息。在这种情况下,我们可以将汇总统计数据与GROUP BY
功能结合使用。
在这里,我们可以看到每个类别的平均值是多少,这样我们就可以尝试选择将为我们带来最大价值的问题。我们可以这样做:对我们想要获取统计数据的列调用 summary statistic 命令,并对我们想要按组提取信息的列使用GROUP BY
命令。这可以通过以下方式实现:
SELECT Category, AVG(`Value`)FROM single_tableGROUP BY CategoryLIMIT 100;
在这个命令中,我们对 Category 列进行了分组,并提取了每个类别的平均值。
目前,这种方法的用处有限,因为顺序与类别出现的顺序一致,而不是与值一致。因此,我们可以结合使用GROUP BY
命令和ORDER BY
命令。为此,我们指定要排序的列,然后指定是按降序还是升序排序。这里我们希望数据以降序排列,这样我们可以先看到最高值。这可以通过以下方式实现:
SELECT Category, AVG(`Value`)FROM single_tableGROUP BY CategoryORDER BY AVG(`Value`) DESCLIMIT 10;
请注意,在按问题的平均值排序时,我们仍然需要指定在使用ORDER BY
命令显示我们想要在被操作的列上执行聚合时在Value
列上执行的聚合。
连接数据集
我们要介绍的最后一件事是JOIN
功能,该功能可用于根据左表或右表中的值、两个表中的数据将两个或多个表连接在一起,或者将表与自身连接在一起。一个简单的例子是使用左连接,它使用左侧表中的所有信息,只使用右侧表中的连接信息。
在我们的例子中,我们可以使用一个INNER JOIN
,在这里我们希望根据平均值连接每个表的分组类别上的single_table
和double_table
,以查看哪个数据集在每个类别中具有更高的值。为此,我们需要为第二个表指定INNER JOIN
,并使用ON
命令指定我们希望连接的列。我们可以这样做:
SELECT a.Category, AVG(a.`Value`) as single_value,
b.Category, AVG(b.`Value`) as double_valueFROM single_table aINNER JOIN double_table bon a.Category = b.CategoryGROUP BY a.Category, b.CategoryLIMIT 100;
为此,需要注意的是,我们使用a.
和b.
符号来访问每个数据集的相关列,并且在创建了INNER JOIN
之后使用GROUP BY
。在这样做的时候,我们还使用了GROUP BY
功能在连接发生之前对每个表的类别列进行分组。虽然这可能不是最有效的方法,但它确实有效!
完整的研讨会笔记本,以及更多示例和挑战,可在的 处找到。如果您想了解我们协会的更多信息,请随时关注我们的社交网站:
https://www.facebook.com/ucldata脸书
insta gram:https://www.instagram.com/ucl.datasci/
领英:https://www.linkedin.com/company/ucldata/
如果你想了解 UCL 数据科学协会和其他了不起的作者的故事,请随时使用我下面的推荐代码注册 medium。
https://philip-wilkinson.medium.com/membership
或者看看我在 Medium 上的其他文章:
[## scikit-learn 决策树分类器简介
towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)
使用 FPL 数据的 SQL 简介
使用梦幻超级联赛数据的 SQL 基础指南
内森·罗杰斯在 Unsplash 上拍摄的照片
对于任何与数据打交道的人来说,SQL 是一项非常有用的技能。这是一个教程,为那些想学习一些基础知识,并有兴趣这样做与幻想英超联赛数据。
数据
在本教程中,我使用来自 https://github.com/vaastav/Fantasy-Premier-League的数据。这是一个用于获取游戏周数据的 FPL 库。以前的比赛周可以在资源库中找到。我用的是一个叫 merged_gw 的文件。每个玩家的每个游戏都有一行。
工具
在本教程中,我使用数据库浏览器的 SQLite(https://sqlitebrowser.org/)。我选择了这个,通常也选择了 SQL Lite,因为设置非常简单。DB Browser for SQLite 将让我们创建数据库,添加数据,然后查询数据。
创建数据库和表
我们需要做的第一件事是创建一个数据库。在数据库浏览器中:
- 转到文件>新数据库。
- 保存文件——我将其命名为 FPL.db
接下来,您将看到一个创建表的选项。在这里,我们只需单击 cancel,因为我们将利用 DB Browser 的功能,根据我们要导入的 CSV 来定义表,然后导入数据。
- 转到文件>从 CSV 导入>表。
- 选择文件并点击打开
- 给这张桌子起个名字——我把它命名为 Players_GWs
- 选中复选框,说明 CSV 中的第一行代表列名(这些将成为我们的表名列)。
这样做将创建表格。该应用程序还显示了用于创建表的查询。CREATE TABLE 后面是我们正在创建的表的名称,然后在括号中是每列的名称,后面是数据类型,每列名称用逗号分隔:
CREATE TABLE "Players_GWs" (
"name" TEXT,
"position" TEXT,
"team" TEXT,
"xP" REAL,
"assists" INTEGER,
"bonus" INTEGER,
"bps" INTEGER,
.........
探索数据
要执行 SQL,我们转到执行 SQL 选项卡:
以下示例中的所有查询都是通过输入查询并单击工具栏中的“运行”按钮(或 CTRL + Enter)来执行的:
选择基础
我们使用 SELECT 来查询数据库。下面是一个从数据库中获取数据的基本 SELECT 语句。我们说我们想要从哪个表中选择哪些列。*表示我们选择所有列。
SELECT * FROM Players_GWs
限制
这将返回我们所有的行和列。不是很有用,因为有 20,700 行。如果我们想快速查看我们拥有的数据类型,我们可以运行上面的限制,只返回指定数量的行。这里我们返回 5 行:
SELECT * FROM Players_GWs LIMIT 5
选择特定列
所以我们有更少的行,但是通过使用我们仍然可以看到所有的列,这使得我们很难看到最有趣的列。我们可以用我们想要查看的特定列替换。让我们加上姓名,职位,团队,GW,总积分,和值。
SELECT name, position, team, GW, total_points, value FROM Players_GWs LIMIT 5
同样值得注意的是,这些列可以按照我们选择的任何顺序排列。
SELECT position, GW, name, team, total_points, value FROM Players_GWs LIMIT 5
以…排序
到目前为止,我们有一个按名称字母顺序排列的记录列表(因为这就是 CSV 中的数据以及它保存到包中的方式)。更有趣的是根据某种度量标准来查看前 5 行。我们可以将 total_points 列添加到查询中,并根据它进行排序。这需要在限制前进行。
SELECT name, position, team, GW, total_points, value FROM Players_GWs ORDER BY total_points LIMIT 5
由 DESC 订购
如我们所见,数据从最小到最大。这是单场得分最低的五位选手。通过将 DESC 添加到我们的订单中,我们可以看到前五名。
在哪里
如果我们想查看某个特定团队的情况,我们可以使用 WHERE 来过滤团队。让我们看看马刺。所以就是[我们要匹配的列]=[我们要匹配的值]:
SELECT name, position, team, GW, total_points, value FROM Players_GWs WHERE team='Spurs' ORDER BY total_points DESC LIMIT 5
喜欢
“马刺队”寻找一个精确的匹配。我们也可以用 LIKE 来匹配一个模式。例如,假设我们想同时匹配曼城和曼联,我们可以用 LIKE 替换=并将’ Man% '作为我们想要匹配的。这将查找所有以“Man”开头的团队。%是一个通配符,匹配其后任意数量的字符。
SELECT name, position, team, GW, total_points, value FROM Players_GWs WHERE team LIKE 'Man%' ORDER BY total_points DESC LIMIT 5
分组依据
到目前为止,我们一直返回单行(每一行代表一个游戏)。如果我们想要查看某个特定团队或玩家在所有游戏周的一些指标的总和,我们可以使用 GROUP BY 和对 total_points 执行的 SUM 函数。
SELECT name, team, SUM(total_points) FROM Players_GWs GROUP BY name
我们也可以按多列分组。比方说,我们希望先按团队再按球员进行细分。
SELECT team, name, SUM(total_points) AS 'overall points' FROM Players_GWs GROUP BY team, name
在第一组示例中,如果玩家在整个赛季中为不同的球队效力,球队栏将随机显示一个球队。但是第二组可以让我们看到每支球队的得分——因为我们是按球队和球员的名字分组的。
如同
代表所有游戏周中每个玩家点数的列的名称不是最具描述性的。它显示为我们对数据库中的 total_points 数据执行的函数。我们可以用 AS 给它起一个更好的名字。
SELECT name, team, SUM(total_points) AS 'overall points' FROM Players_GWs GROUP BY name
这些是 SQL 入门的一些基本查询类型。这里,我们只处理一个表中的数据,但是我们可以在另一个表中包含详细的团队信息,然后使用查询从两个表中获取数据。我将在以后的教程中研究这个和更复杂的查询。
如需进一步阅读,请查看位于 https://sqlite.org/docs.html 的 SQLite 文档
作者拍摄的所有截图。由内森·罗杰斯在 Unsplash 上做的介绍性图片。
机器学习的魔力介绍
用数学代替代码
所有插图均由作者提供。
这些天我们经常听到机器学习,事实上它就在我们身边。这听起来可能有点神秘,甚至有点可怕,但事实证明,机器学习只是数学。为了证明这只是数学,我将用传统的方式写这篇文章,用手写的方程代替代码。如果你更喜欢通过听和看来学习,我在这里贴了一个涵盖本文内容的视频。否则,请继续阅读!
为了解释什么是机器学习以及数学是如何让它工作的,我们将全面演练一下逻辑回归,这是一个相当简单但基本的模型,从某种意义上说,它是神经网络等更复杂模型的构建模块。如果我必须选择一个机器学习模型来真正理解,这将是它。
最常见的情况是,我们将逻辑回归用于一个叫做二元分类的任务。在二进制分类中,我们想学习如何预测一个数据点是否属于两个组或类中的一个,标记为 0 和 1。
为了进行这些预测,我们对给定数据点属于标记为 1 的类别的概率进行建模。
在这个设置中,我们将类标签的单个观察值写成小写的" y “,它可以取值 0 或 1,并将单个数据点写成小写的” x ",带下划线以表示它是一个向量。
更具体地说,它是一个由 m 个元素组成的向量,其中 m 是我们必须描述每个数据点的信息或特征的数量。一会儿就会明白,为什么我们把 1 作为每个向量的第一个元素。
现在我们需要决定如何对这个概率建模。逻辑回归通过以下假设做到了这一点。
我将回到这个“sigma”函数是什么,但是在这个函数内部,我们注意到我们的模型是基于数据点特征的加权和。
我们现在可以看到,通过将每个数据点向量的第一个元素设置为 1,我们获得了截距或偏差项。我们为什么要那样做,以后会变得很清楚。
因此,我们使用这些 m 特征来说明该数据点属于标记为 1 的类别的概率,并且我们可以通过改变θ参数的值来控制这些特征对该概率的贡献程度。在计算这个加权和之后,我们将它传递给这个 sigma 函数。
那么什么是西格玛呢?请注意,如果我们只是计算一个加权和,我们可以得到任何实际值,因为每个数据点的特征可能呈现任何实际值。但是我们想建立一个概率模型,这个概率在 0 到 1 之间。所以我们需要一个函数,将所有实数值映射到区间[0,1]。
其中一个函数叫做逻辑函数或 sigmoid 函数,看起来像这样。
正如我们所见,它接受任何实数值,并将其压缩在 0 和 1 之间。原来在机器学习中有很多情况是我们要这么做的,包括在神经网络中,所以 sigmoid 函数出现的很多。
好了,现在的问题是,这个θ矢量应该是什么?
这取决于我们的数据。为了有一个对一般数据点进行良好预测的模型,它可以采用各种特征的许多不同值,我们需要根据各种数据点及其相应的类别标签来选择θ参数。假设我们有 n 个数据点,称它们为我们的训练数据。
这些训练数据允许我们学习最佳θ参数。最优是什么意思?一个合理且普遍的定义是,最优θ是最大化获取训练数据概率的一组参数。
这正是我们通过最大化所谓的似然函数得到的结果,它是θ的函数,定义为整个数据集(即我们所有的训练数据)的联合概率分布。假设我们的数据是独立的,我们可以把它写成每个数据点的所有个体概率分布的乘积。
但是我们如何表达一个普通数据点的概率分布,它可能属于标记为 0 或 1 的任何一类?利用我们只有两个类的事实,我们知道每个数据点属于一个类的概率就是一个减去它属于另一个类的概率。
利用指数定律,我们可以用下面的巧妙方法把这两个表达式结合起来。尝试将标签 0 和 1 插入下面的表达式,以说服自己它涵盖了这两种情况。
如果你学过概率,你可能会认识到这是一个伯努利随机变量的概率质量函数。
太好了。所以我们想最大化关于θ参数的似然函数。如果你记得一些微积分,你可能记得这将涉及到求导。很难找到这个乘积的导数,但是通过取它的对数,我们可以把这个乘积的对数重写为对数的和。我们可以这样做,因为 log 是一个单调函数,所以最大化对数似然性的θ值也会最大化似然性,我们真正关心的是这些最佳θ值。
这看起来更容易处理,但事实证明,如果我们试图找到它对θ参数的导数,我们将会没有封闭形式的解。这是机器学习中的一个常见问题,处理它的标准方法是应用类似梯度下降的迭代优化算法,这允许我们找到局部最小值。但是我们希望最大化对数似然,所以我们将该算法应用于负对数似然,因为最小化负对数似然的θ参数也将最大化原始对数似然。
有很多很棒的视频解释梯度下降是如何工作的,包括 StatQuest 的这个,如果你是算法新手,你一定要看看。对于我们的问题,我们将通过迭代应用以下更新,使用它来计算每个mθ参数的最佳值:
为了应用这种算法,我们所需要的只是负对数似然相对于每个θ参数的偏导数。
为了使事情变得简单一点,我们可以首先在给定单个数据点而不是所有训练数据的情况下找到负对数似然的偏导数。因为和的导数等于导数的和,所以给定整个训练数据集,重写这些偏导数将是容易的。单个数据点的负对数似然性很简单:
但即使这样也很难区分,所以我们可以使用链式法则将导数分成更小的块(这也用于计算神经网络中的梯度,所以这是一个很好的实践)。
利用链式法则,不是直接对每个θ参数的负对数似然进行微分,而是可以对另一个我们称之为 p 的量进行微分,然后对 z 进行微分,进而可以对θ参数进行微分。这些衍生产品都很容易找到。将它们相乘,我们得到原始导数。
最后,在给定单个数据点的情况下,我们有负对数似然的导数,我们可以通过对所有训练示例求和来使用该表达式覆盖整个数据集。
好了,现在我们可以把这个导数直接代入我们的梯度下降公式,应用算法得到优化的或“拟合的”θ参数,我们把它放入一个叫做“θ帽”的向量中
这给了我们最终模型所需要的一切,它和我们开始时的一样,但是现在——关键的是——包括了“theta hat!”
这很有用,但是请记住,我们进行逻辑回归的最初目标是进行二元分类,并预测给定的数据点是属于标记为 1 还是 0 的类别。我们将这些类预测称为“ y hat”,并说如果数据点属于标记为 1 的类的估计概率大于 0.5,那么我们预测该数据点属于该类。否则,我们预测该数据点属于标记为 0 的类。
这个临界值 0.5 定义了所谓的决策边界,它是决定是否预测一个数据点属于标记为 1 或 0 的类之间的边界。
让我们看几个例子。如果我们只有一个特征,我们可以使用第二个轴来显示相应的类标签,0 和 1。由于我们的模型,我们对每个特征值的预测概率将描绘出一条 s 形曲线,决策边界将是对应于概率 0.5 的单个特征值。
如果我们的每个数据点都有两个特征,那么我们可以再次使用一个额外的轴来显示属于这两个类的点之间的间隔。在三维空间中思考,我们可以想象所有画成十字的点将位于通过 y 等于 1 的平面中,而所有画成圆的点将位于通过 y 等于 0 的平面中。这一次,两个特征的所有组合的预测概率将形成一种看起来像波浪的 s 形表面,并且决策边界将是穿过所有这些 0.5 概率值的直线。
在一维中,决策边界是一个点。在二维中,它是一条线。你能猜出它在三维空间会是什么样子吗?事实上,我们可以通过求解这个方程,用拟合的θ参数来表示这些决策边界。试试吧!
仅此而已。我们已经在不接触计算机的情况下完成了一个非常重要的机器学习模型的完整演练。当然,我们需要计算机的帮助来进行梯度下降和计算最佳θ参数,但我希望我已经说服了你,机器学习没有什么特别或神秘的,它真的只是数学。有问题请在评论里留下!
泊松整数 ARIMA 回归模型简介
图片由 Clker-Free-Vector-Images 来自 Pixabay ( Pixabay 许可)
以及如何使用 Python 和 statsmodels 实现泊松 INAR(1)回归模型的教程
整数 ARIMA 模型用于建模由整数计数组成的时间序列数据。
这些数据集带来了一些独特的挑战:
**数据是自相关的:**时间序列数据通常是自相关的。我们为这些数据建立的任何模型都需要考虑这些序列相关性。ARIMA(自回归综合移动平均)模型旨在捕捉时间序列数据中的自相关性。
数据仅由整数计数 0、1、2、3…等组成。: ARIMA 模型设计用于模拟实值时间序列数据,而不是基于计数的时间序列数据。基于计数的数据可以使用泊松和类泊松模型进行建模,例如负二项式和广义泊松模型。不幸的是,泊松和类泊松模型是静态模型,不是为处理相关时间序列数据而设计的。
泊松整数 ARIMA 模型弥补了时间序列数据的 ARIMA 模型与基于计数的数据集的泊松和类泊松模型之间的差距。
正如我们将在下面看到的,在结构上,泊松风险模型的构建与 ARIMA 或泊松模型非常不同。
在本文中,我们将重点关注 Brannas 在*“AR(1)模型中的解释变量”*中介绍的泊松 INAR(1) 模型(参见文章底部的论文链接)。INAR(1)是具有 1 阶自回归分量的整数 ARIMA 模型,即,它仅使用第一时间滞后分量, y_(t-1)。泊松 AR(1)使用泊松过程对误差分量建模。
让我们检查泊松整数 AR(1)模型的结构。我们将经常使用 Cameron A.C .和 P.K. Trivedi 的《计数数据的回归分析》一书中所遵循的符号约定,以及该主题的一些原始论文。文章最后提到了书和论文的链接。
泊松 INAR(1)模型的结构
通用整数 AR(1)模型表示如下:
通用整数 INAR(1)回归模型(图片由作者提供)
在 INAR(1)模型中,我们将时间序列在时间 t 的值 express y_t 表示为两个量的和:
ρ ○ y_(t-1): 这一项是时间序列在前一时间步 (t-1)的值的函数。
ε_t: 这是一个随机变量,代表隐藏的,因此也是未知的变量。我们将选择通过假设随机变量 ε_t. 的某种已知概率分布(如正态分布或泊松分布)来模拟潜在变量的影响
第一项,***ρ○y _(t-1)***值得补充说明。理解这个量的方法如下:
假设我们正在对一个电子商务网站每天的点击数进行建模。这是计数的时间序列数据,人们可以合理地预期第 t 天的点击次数与前几天的点击次数相关。
现在假设在某一天 t ,点击次数 y_t =1000 。再假设我们把这个数字 1000 看做 1000 个独立的,同分布的随机变量: b_1,b_2,b_3,…b_1000 。每个变量 b_i 遵循以下伯努利分布:
伯努利随机变量 b_i(图片由作者提供)
所以我们可以把 y_t=1000 的值看做 1000 次独立伯努利试验,每一次的成功概率为 ρ。如果一次试验‘成功’,网站上就会记录一次点击。因此,一天 t 的预期点击数就是 ρ乘以 y _ t
现在我们可以看到 INAR(1)方程是如何模拟在时间索引 t 的网站点击量的,即:
- 在前一时间步 (t-1) 的预期网站点击数,以及
- 由随机变量 ε_t. ε_t 的实现值提供的对该期望值的调整用于对一些潜在数据生成过程建模。**
泊松 INAR(1)模型
由于我们希望对整数计数的时间序列数据进行建模,因此假设基础(未知)数据生成过程是泊松过程是合适的。因此,εt是一个泊松分布的随机变量。
因此,泊松 INAR(1)模型可以表示如下:
泊松 INAR(1)模型
基本上,我们所说的是在时间 t 观察到的值是前一时间步的期望值和假设泊松比为μt的泊松分布计数的组合。
如何处理回归变量
假设 X 为回归变量的矩阵, β 为回归系数的向量,如下:
回归变量矩阵 X 和回归系数向量 β (图片由作者提供)
我们将泊松过程的平均发生率μt表示为下面的函数 X 和回归系数 β 如下:
泊松平均指数(图片由作者提供)
估计
*估算包括估算 ρ和 β *。该领域的各种研究提出了许多估计技术,如最大似然估计、条件最小二乘法、加权最小二乘法和广义矩法。在“AR(1)模型中的解释变量”中,Brannas 使用条件最小二乘法和条件广义矩方法技术进行参数估计。
在本文中,我们将探讨使用最大似然估计(MLE)方法来估计 ρ和β。* 我们对 MLE 的选择很大程度上取决于 statsmodels 库中GenericLikelihoodModel类的存在。GenericLikelihoodModel 类允许您指定您选择的自定义 MLE 函数,statsmodels 将很乐意为您最大化该函数。*
泊松 INAR(1)模型的极大似然估计
在最大似然法中,我们寻求将观察整个训练数据集的可能性最大化的值 ρ和**【β】**。具体来说,我们希望找到 ρ和 β ,这将最大化 t=1 到 n 中 y_t 的联合出现概率的自然对数。 就符号而言,我们希望最大化以下对数似然函数:
对数似然函数(作者图片)
在实践中,我们通过使用以下规则将乘积的对数转换为各个概率的对数之和:
*ln(A * B * C * D ……)= ln(A)+ln(B)+ln©+ln(D)+……
最大化ℓ(⍴;β|y),我们需要构造条件概率分布 P(y_t|y_(t-1)) 。让我们看看如何做到这一点。
泊松 INAR(1)分布随机变量的概率质量函数
让我们来看看泊松 INAR(1)模型的方程:
泊松 INAR(1)模型
我们看到 y_t 由两部分组成:y_(t-1) 的期望值和一个泊松分布变量 ε_t 。因此,给定 y_(t-1) ,观察到 y_t 的概率可以表示为两个概率的乘积:
- 从 y_(t-1) 个可能事件中观察到 j 个‘事件’的二项概率,接下来,
- 观察(y _ t—j)‘事件’的泊松概率。
由于我们不知道 j 是什么,所以我们允许 j 的范围从 0 到 y_t(实际上是,从 0 到 min(y_t,y_(t-1) ,但这是一个技术问题,所以一切仍然有意义)。对于 j 的每个值,我们在(1)和(2)中计算上述两个概率的乘积。最后,我们将所有单个产品总结如下:
泊松 INAR(1)分布随机变量的 PMF(图片由作者提供)
上面的等式所表示的是,在时间步长 t 观察到前一时间步长 y_(t-1) 的 y_t 的概率,等于观察到 y_(t-1) 事件中的 0 事件的二项式概率和观察到 y_t 事件的泊松概率,或者说,观察到 1 事件中的二项式概率
让我们回忆一下,在上面的等式中,泊松过程的平均发生率 μ_t 是表示为回归变量* x_t 和回归系数 β 的如下函数:*
泊松平均指数(图片由作者提供)
让我们还记得 ρ 是二项概率,在做 MLE 时,我们不希望 ρ 出界。因此,我们定义另一个变量γ,使得:
逻辑函数(图片由作者提供)
上述逻辑函数确保当γ的范围从-∞到+∞时,伯努利概率 ρ 保持有界在 [0,1]内。
逻辑函数(图片由作者提供)
如何使用 Python 和 Statsmodels 构建和训练泊松 INAR(1)
我们将使用 STRIKES 数据集说明泊松 INAR(1)模型的使用过程:
制造业罢工数据集
为了说明模型拟合过程,我们将使用以下在回归建模文献中广泛使用的开源数据集:
该数据集是一个月度时间序列,显示了从 1968 年到 1976 年每月开始的美国制造业活动与美国制造业合同罢工数量之间的关系。
这个数据集在 R 中可用,可以使用 statsmodels 数据集包获取。
因变量 y 为击*。*
我们将从导入所有必需的包开始:
***import** math
**import** numpy **as** np
**import** statsmodels.api **as** sm
**from** statsmodels.base.model **import** GenericLikelihoodModel
**from** scipy.stats **import** poisson
**from** scipy.stats **import** binom
**from** patsy **import** dmatrices
**import** statsmodels.graphics.tsaplots **as** tsa
**from** matplotlib **import** pyplot **as** plt*
让我们使用 statsmodels 将数据集加载到内存中:
*strikes_dataset = sm.datasets.**get_rdataset**(dataname=**'StrikeNb'**, package=**'Ecdat'**)*
打印出数据集:
***print**(strikes_dataset.**data**)*
我们看到以下输出:
我们将前 92 个数据点视为训练集,其余 16 个数据点视为测试数据集:
*strikes_data = strikes_dataset.**data**.**copy**()
strikes_data_train = strikes_data.**query**(**'time<=92'**)strikes_data_test = strikes_data.**query**(**'time>92'**).**reset_index**().**drop**(**'index'**, **axis**=1)*
这是我们的回归表达式。罢工是因变量,产出是我们的解释变量。假设回归截距存在:
*expr = **'strikes ~ output'***
我们将使用 Patsy 来雕刻出 X 和 y 矩阵。Patsy 将自动添加一个回归截距列到 X :
*y_train, X_train = **dmatrices**(expr, strikes_data_train, **return_type**=**'**dataframe**'**)
**print**(y_train)
**print**(X_train)y_test, X_test = **dmatrices**(expr, strikes_data_test, **return_type**=**'**dataframe**'**)
**print**(y_test)
**print**(X_test)*
接下来,我们将扩展 GenericLikelihoodModel:
***class** INAR(GenericLikelihoodModel):
**def** __init__(self, endog, exog, **kwds):
super(INAR, self).__init__(endog, exog, **kwds)*
在我们的扩展中,我们将覆盖 nloglikeobs() 和 fit() 方法。statsmodels 调用 nloglikeobs() 方法来获取每个观测值的对数似然值 y_t. 因此,我们之前描述的泊松 INAR(1)的似然函数进入该方法。该方法返回一个对数似然数组,由 statsmodels 提供的超类对该数组中的所有值求和,以获得由 statsmodels 的优化器优化的总对数似然值。
***class PoissonINAR**(GenericLikelihoodModel):
**def** __init__(self, endog, exog, **kwds):
super(INAR, self).__init__(endog, exog, **kwds)
**def** nloglikeobs(self, params):
***#Fetch the parameters gamma and beta
#that we would be optimizing***gamma = params[-1]
beta = params[:-1]
***#Set y and X***y = self.endog
y = np.array(y)
X = self.exog
***#Compute rho as a function of gamma***rho = 1.0/(1.0+math.exp(-gamma))
***#Compute the Poisson mean mu as a dot
#product of X and Beta***mu = np.exp(X.dot(beta))
***#Init the list of log-likelihhod values,
#one value for each y***ll = []
***#Compute all the log-likelihood values for
#the Poisson INAR(1) model*****for** t **in** range(len(y)-1,0,-1):
prob_y_t = 0
**for** j **in** range(int(min(y[t], y[t-1])+1)):
prob_y_t += poisson.pmf((y[t]-j), mu[t]) *
binom.pmf(j, y[t-1], rho)
ll.append(math.log(prob_y_t))
ll = np.array(ll) ***#return the negated array of log-likelihoods*****return** -ll*
让我们也实现一下 model.fit() 方法:
***def** fit(self, **start_params**=None, **maxiter**=1000, **maxfun**=5000, **kwds):
***#Add the gamma parameter to the list of
#exogneous variables that the model will optimize***self.exog_names.append(**'gamma'**) **if** start_params == **None**:
***#Start with some initial values of Beta and gamma***start_params = np.append(np.ones(self.exog.shape[1]), 1.0)***#Call super.fit() to start the training* ****return** super(**PoissonINAR**, self).fit(**start_params**=start_params,
**maxiter**=maxiter, **maxfun**=maxfun, **kwds)*
让我们创建泊松 INAR(1)模型类的实例,并在训练数据集上对其进行训练:
*inar_model = **PoissonINAR**(y_train, X_train)
inar_model_results = inar_model.**fit**()*
打印模型培训总结:
***print**(inar_model_results.**summary**())*
我们看到以下输出:
泊松 INAR(1)模型的训练总结(图片由作者提供)
回归系数的显著性
输出变量和 gamma 的系数在 95%的置信区间都是显著的,正如它们的 p 值小于 0.05 所证明的。显著不同于零的回归截距也是如此:
回归系数的重要性(图片由作者提供)
回归系数的解释
系数的解释是而不是简单明了。伽马为-0.7039,对应于 1/(1+exp(0.7039)) = 0.33095 的 ρ 。
估算的 β 为 2.6215。
拟合模型的方程式为:
拟合泊松 INAR(1)回归模型的方程(图片由作者提供)
对于任意给定的 t ,0.33095(大约 33%)的 y_(t-1) 构成 y_t 。其余的来自泊松过程的估计平均值 μ_t ,它是时间 t 的输出和估计的 β 向量的函数。
测量产量变化对罢工频率的影响
从模型方程中,很容易看出,观察到的撞击次数随着制造产量的增加而增加。我们可能想通过它们增加了多少来衡量。
在训练数据集中,“输出”变量的标准偏差为 0.05654。通过打印以下内容可以看到这一点:
*strikes_data_train['output'].**std**()*
现在假设我们考虑 y_t 的两个假设值,即 y_t1 和 y_t2 ,使得它们各自之前的值y _(T1–1)和y _(T2–1)恰好相同。由于 β =2.6215 , “输出”增加一个标准差,将导致泊松过程的估计均值波动 e^(2.62150.05654) = 1.15977,即大约 16%。因此,产量中一个标准差的增加会导致每月观察到的罢工次数增加 16%。*
泊松 INAR(1)模型的拟合优度
模型方程中的滞后项 y_(t-1) 使得拟合优度的确定变得复杂。泊松 INAR(1)模型的非线性排除了使用基于均方误差的测量,例如 R 平方。另一方面,由于 MLE 用于模型拟合,基于偏差的测量,例如和 卡方分布似然比(LR)测试 可用于判断拟合优度。然而,伪 r 平方和 LR 检验都需要计算零模型(也称为仅截距模型)的对数似然(LL)。在泊松 INAR(1)模型中,由于模型方程中滞后项 y_(t-1) 的存在,零模型的构成并不十分明显,还存在争议。
考虑到这些困难,人们可能希望通过间接方式判断拟合优度,特别是通过检查拟合模型参数的标准误差和相应的 95%置信区间。
在对“罢工”模型采用这种方法时,我们观察到以下情况:
ρ 的 95%置信区间范围为 1/(1+exp(1.174))=0.23613 至 1/(1+exp(0.233))=0.44201,与 1/(1+exp(0.7039)) = 0.33095 的 ρ 拟合值相当接近。
不幸的是,“输出”变量有一个相当大的标准误差 1.126 和相应的宽置信区间 0.415 到 4.828。正如我们在上一节所看到的,它对“打击”的影响很弱。这对模型的拟合优度有不利影响。
预言;预测;预告
**该模型允许提前一步做出预测。预测包括在 X 矩阵和 y 的滞后值上运行拟合的模型。我们将在 X_test 和 y 的滞后值上运行拟合的模型。为此,我们将在 statsmodels 中的 model.py 上实现 predict() 方法,如下所示:
*****def** predict(self, **params**, **exog**=None, ***args**, ****kwargs**):
***#Fetch the optimized values of parameters gamma and beta***fitted_gamma = params[-1]
fitted_beta = params[:-1] ***#Compute rho as a function of gamma***rho = 1.0/(1.0+math.exp(-fitted_gamma)) ***#Get the Intercept and the regression variables,
#Don't get the last column which contains the lagged y values***X = exog[:,:-1]
***#Fetch the lagged y values***y_lag_1 = exog[:,-1] ***#Compute the predicted y using the fitted Poisson INAR(1)
#model's equation***y_pred = rho * y_lag_1 + np.exp(X.dot(fitted_beta)) **return** y_pred***
让我们准备 X 矩阵进行预测
***X_test[**'y_lag_1'**] = y_test.**shift**(1)
X_test = X_test.**fillna**(0)***
根据测试数据集生成预测。由于我们对计数感兴趣,我们将对预测进行四舍五入。
***inar_predictions = np.**round**(inar_model_results.**predict**(**exog**=X_test))
**print**(inar_predictions)***
我们得到以下输出:
让我们为 y_test 绘制一步预测图:
***predicted_counts=inar_predictions
actual_counts = y_test[**'strikes'**]fig = plt.**figure**()
fig.suptitle(**'Predicted versus actual strike counts'**)predicted, = plt.**plot**(X_test.index, predicted_counts, 'go-', **label**='Predicted counts')actual, = plt.**plot**(X_test.index, actual_counts, 'ro-', **label**='Actual counts')plt.**legend**(**handles**=[predicted, actual])plt.**show**()***
我们看到的是:
泊松 IINAR(1)模型创建的一步预测罢工数量(图片由作者提供)
提前一步预测的质量证实了我们之前通过泊松 INAR(1)模型的拟合优度强调的问题。
以下是完整源代码的链接:
使用 Python 和 statsmodels 的泊松整数 ARIMA 模型
引用和版权
书
Cameron A. Colin,Trivedi Pravin K ., 计数数据回归分析 ,计量经济学会专论№30,剑桥大学出版社,1998 年。国际标准书号:0521635675
报纸
布朗恩斯,科特。(1995).AR(1)计数数据模型中的解释变量 PDF 下载链接
荣,罗伯特 c 和 a。整数时间序列的二项式稀疏模型。统计建模6(2006):81–96。,DOI:10.1191/1471082 x 06 ST 114 OAPDF 下载链接
凯南 j ., 美国制造业的合同罢工持续时间,计量经济学杂志 ,第 28 卷,1985 年第 1 期,第 5-28 页,ISSN 0304-4076,https://doi . org/10.1016/0304-4076(85)90064-8。 PDF 下载链接
数据集
文章中使用的制造业罢工数据集是统计软件中可供公众使用和实验的几个数据集之一,最值得注意的是,这里的是 R 包。在 GPL v3 许可下, Vincent Arel-Bundock 通过vincentarelbundock.github.io/rdatasets已经可以使用 Python 访问数据集。
形象
本文中的所有图片版权归 CC-BY-NC-SA 所有,除非图片下面提到了不同的来源和版权。
相关文章
***
感谢阅读!如果您喜欢这篇文章,请 关注我 获取关于回归和时间序列分析的提示、操作方法和编程建议。***
worldfootballR 软件包介绍
使用 worldfootballR 包提取英超联赛替补数据
随着[worldfootballR](https://github.com/JaseZiv/worldfootballR)
R 包的创建;一个新的 R 包来帮助从 fbref.com 提取足球数据,我将试着强调这个包的使用方法。
发布的软件包目前是一个开发版本,仅在 GitHub 上可用,但一旦用户测试完成,将在 CRAN 上提供。
在这篇文章中,我将分析利物浦在过去三个赛季的英超联赛(EPL)中使用换人的情况,以了解当前赛季的行为是否发生了变化,以及在 2019-2020 赛季期间 COVID 爆发和随后暂停期间是否发生了变化。
数据是从过去两个半赛季中提取的,直到 2020/21 EPL 赛季第 17 轮比赛结束。
使用worldfootballR
提取数据
该软件包有一个名为get_match_summary
的功能,提取比赛 URL 的比赛摘要(进球,替补,红/黄牌)数据(以及其他关于比赛的元数据)。
要获取比赛 URL,可以使用另一个函数—get_match_urls
—它接受国家代码(“ENG”代表英格兰)、性别和赛季结束年份,并返回一个比赛 URL 向量。
devtools::install_github("JaseZiv/worldfootballR")
library(worldfootballR)match_urls <- get_match_urls(country = "ENG", gender = "M", season_end_year = c(2019:2021))match_summaries <- get_match_summary(match_url = match_urls)
该函数的输出如下所示:
大量事件数据需要分析。来源:世界足球
制造第一艘潜艇的队伍
既然包装说明已经出来了,我们就把注意力转向英超联赛换人数据的分析,特别提出这个问题,利物浦的换人行为有变化吗?
这一分析大致是受 FiveThirtyEight 在联赛重启前后关于德甲球队替代者的一篇文章的启发。
用数据解释利物浦的换人
在分析的所有赛季中,利物浦在一个赛季中的替补人数略高于联盟平均水平,上赛季重新开始后,每个赛季的平均替补人数达到了 4.67 人。本赛季已经恢复到 COVID 之前的水平。
有趣的是,虽然利物浦的第一次替补出场时间通常略晚于联赛平均水平(56 分钟比 52 分钟),但红军在赛季重新开始后一直接近他们的第一次替补出场时间,而联赛平均水平已经恢复到 COVID 之前的水平,逆转了全联盟的趋势。
现在第一个小时更?
红军在 2019-20 赛季的第一个小时进行了 12%的换人(是 2018-19 赛季的两倍),本赛季在前 16 场比赛中这一比例再次翻倍。然而,联盟经历了这一趋势的直接逆转,在 19/20 赛季重新开始的部分期间飙升至 24%,并回落到前几个赛季的联盟平均水平。
看看这种趋势如何在本赛季的后半段继续下去将会很有趣。
数据来源于 worldfootballR。使用 gt 进行可视化
包裹
这是利用worldfootballR
包中各种数据提取功能的一系列分析中的第一个。
在这里,我们看到利物浦比他们之前的趋势更早地进行了第一次换人,并且偏离了联赛平均水平。我将跟踪这一分析,看看这一趋势是否还在继续。
一如既往,任何关于作品或 R 包的问题/评论,请随时通过常规渠道联系。
加油红人!!
这篇文章的完整版本出现在 dontblamethedata.com 的这里
ARIMA 时间序列分析导论
作者图片
时间序列预测侧重于分析等距时间间隔内的数据变化。时间序列分析广泛应用于各种领域,从计量经济学到地质学和地震预测;它也被用于几乎所有的应用科学和工程。时间序列数据的例子包括标准普尔 500 指数、发病率、死亡率、血压跟踪、全球气温。这篇文章将着眼于如何自回归综合移动平均(ARIMA)模型的工作,并适合时间序列数据。在继续之前,首先要考虑的是多变量预测和单变量预测之间的区别。前者仅使用以前的时间值来预测未来值。后者利用了不同的预测值,而不是序列本身。Jupyter 笔记本及相关数据请参考我的 GitHub repo。
白噪声及其重要性
根据定义,白噪声是随机数据。如果变量是独立的且同分布(i.i.d ),均值为零,则时间序列是白噪声(随机)。换句话说,时间序列有一个均值 μ = 0 和一个恒定的标准差 σ = c 。您可以使用 df.describe()函数来检查您的平均值:
作者图片
由于我们的平均值远高于零,我们可以放心,我们的数据不是白噪音。尽管我们不需要执行以下操作,但还是让我们将数据分成两部分,看看它们各自的标准偏差:
df_1 = df[:100]
df_2 = df[100:]print(df_1.describe())
print(df_2.describe())
作者图片
这里我们可以清楚地看到,我们的σ₁ ≠σ₂.下一张图将展示一个白噪声的例子。如下图所示,信号在平均值 0 附近振荡,不难发现标准偏差随时间保持不变。
图片来自维基百科
白噪声 y =噪声(t) = ϵₜ
由于白噪声的定义隐含着随机性,你不能对它建模并做出预测。一旦你看到白噪音,不要继续任何预测模型!
ARIMA 简介
Arima 是 Auto-Regressive Integrated Moving Average 的缩写,它是一种预测算法,基于以前的值携带固有信息的假设,可用于预测未来的值。我们可以开发一个预测模型,根据过去的值来预测 xₜ。,正式表示为:
p(xₜ | xₜ₋₁,… ,x₁)
为了理解 ARIMA,我们首先要把它分成几个基本成分:
- 阿肯色州
- 我
- 马萨诸塞州
ARIMA 模型包含三个参数:
- p 是 AR 项的阶数
- q 是 MA 项的顺序
- d 是差分的数目
自回归 AR 和移动平均 MA
AR 模型仅依赖于过去的值(滞后)来估计未来的值。让我们来看看 AR 模型的一般形式:
值“p”决定了预测中要考虑的过去值 p 的数量。模型的阶数越高,考虑的过去值就越多。为了简单起见,我们来看一个 AR(1)模型。
AR 模型可以简单地认为是 p 个过去值的线性组合。
另一方面,移动平均 MA 模型依赖于过去的预测误差来进行预测。让我们看看 MA 模型的一般形式:
MA 模型可以简单地认为是 q 个过去预测误差的线性组合。
现在,在进一步讨论之前,我们必须讨论平稳数据和非平稳数据之间的区别。
静止的
平稳数据是时间序列不依赖于时间变量的数据;为了开发仅依赖于过去值的预测模型,需要这种假设。没有稳定的数据会使您的预测不令人满意,因为您的模型会将时间变量考虑在内。直观上,平均值和方差等参数不会随时间而改变。下面的两个图表说明了平稳数据和非平稳数据之间的区别:
作者图片
如上所示,非平稳数据有明显的上升趋势。
现在让我们看一个非平稳数据的具体例子,并使用 Pandas 的 diff()函数来实现平稳性:
非平稳数据
#Calculates the difference of a Dataframe element compared with another element in the Dataframe (default is element in previous row = 1).df_1.diff(1).plot()
使用 Pandas Diff 函数后的静态数据
如上所述,我们通过计算连续行之间的差值实现了平稳性。
如果 d=0: yₜ = Yₜ
如果 d=1: yₜ = Yₜ — Yₜ₋₁
如果 d = 2:yₜ=(yₜ—yₜ-₁)-(yₜ-₁—yₜ-₂)
现在让我们考虑时间序列 x 的 ARIMA(1,1,1)。为了简洁起见,省略了常数项。
yₜ = yₜ — y_t₋₁
yₜ = ϕ₁yₜ₋₁ + ϵₜ — θ₁ ϵₜ₋₁
我们如何找到参数(p,d,q)
我们可以简单的使用 Auto。Arima 和交叉验证,以便找到模型的最佳参数。首先,让我们加载数据并绘制它。
df = pd.read_csv('passengers.csv', usecols=[1], engine='python')
plt.plot(df)
作者图片
如上所示,该数据具有明显的季节性上升趋势。现在我们将简单地利用汽车。Arima 来拟合数据并进行预测
y = df.values
train, test = train_test_split(y, train_size=100)# Fit model
model = pm.auto_arima(train, seasonal=True, m=12)forecasts = model.predict(test.shape[0])x = np.arange(y.shape[0])
plt.plot(x, y, c='blue' , label = 'expected')
plt.plot(x[100:], forecasts, c='green' , label = 'predicted')
plt.legend()
plt.show()
作者图片
非常符合测试数据!
摘要
- Arima 是一个很好的时间序列分析工具,Auto Arima 软件包使微调过程变得更加容易
- 始终绘制您的数据并执行解释性数据分析 EDA,以便更好地理解数据。
- 了解不同预测模型背后的技术细节可以帮助你选择正确的模型。
参考
https://machine learning mastery . com/ARIMA-for-time-series-forecasting-with-python/
https://people.duke.edu/~rnau/411arim.htm
https://towards data science . com/understanding-ARIMA-time-series-modeling-d 99 CD 11 be 3 f 8