TowardsDataScience 博客中文翻译 2019(八十六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

将数据引入社区科学:《我的世界》版

原文:https://towardsdatascience.com/bringing-big-data-to-the-science-of-community-minecraft-edition-25938f43961a?source=collection_archive---------34-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Credit

看看今天的互联网,很容易让人产生疑问:对民主有利的梦想到底去了哪里?好吧,看看过去的大型社交媒体的丑闻和独裁政府的黑客的可怕表演,我认为仍然有希望的空间。网络上仍然充斥着自我管理的小实验。它仍在发生,也许悄无声息,但规模如此之大,以至于我们有机会,不仅仅是复兴网络的创始梦想,而是将现代科学方法引入到关于自我管理及其如何运作的基本千年问题中。

《我的世界》?《我的世界》。

这就是为什么我花了五年时间研究《我的世界》。《我的世界》,你或你的孩子或侄女在 10 年到 5 分钟前的任何时间玩的游戏,包括加入数百万个无限虚拟世界中的一个,并用立方体积木建造东西。《我的世界》没有情节,但叙事厌恶真空,所以人们使用游戏的基本机制来创造自己的情节,并在这个过程中使游戏成为有史以来最畅销的视频游戏。比俄罗斯方块还大。

《我的世界》的玩家和他们的作品一直是游戏中最引人注目的方面,但他们得到了一群自封的业余官员的支持,这些业余官员让《我的世界》因为一个非常不同的原因而变得特别。这些人是“运营”和管理员,他们做着吃力不讨好的工作,运行《我的世界》世界的每一个副本,以便它能足够好地为所有创造者创造。

事实证明,《我的世界》的特殊之处不仅在于它的开放式游戏,还在于它是“自我托管的”:当你与其他人一起玩一个世界时,它很可能不是由微软这样的大公司来维护,而是由一个业余玩家来维护,他们以某种方式将自己束缚在各种不酷的、非立方的工作中,编写规则、解决冲突、解决问题和养猫。我们习惯于将关键的挑战留给专业人员,事实上,您使用的大多数 web 服务都是由专门公开提供 CPU、RAM 和带宽的人管理的。但是有一个由业余爱好者运营的服务器社区的整个地下世界,在这个世界中,没有接受过治理培训的人,没有薪水,可能更喜欢做其他事情,接受建立和维护一个拥有共同愿景并为之共同努力的人的社区的挑战。当这种方式奏效时,不管这种愿景是否只是极客粉丝的一个小众产物——比如说,一个星舰企业号的逐块复制品——它都是鼓舞人心的。这些人没有接受过治理方面的培训,他们在自学建立治理机构。他们创造的每个世界都是政治实验。根据我的计算,20 个中有 19 个失败了,每一个成功和失败都是探索自我管理成为一门科学的奇迹数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Creating an inspiring Minecraft creation requires coordination and governance. Credit.

这是互联网的梦想在行动,特别是如果我们能把成功率从 1/20 提高到 5%。为了真正理解健康制度的决定因素,我们必须能够观察地球上 10 万个国家的兴衰。可惜地球只有几百个国家。在线社区是下一个最好的东西:他们给了我们进行大规模比较甚至实验的规模。管理他们并不像看上去那么简单。

作为资源治理机构的在线社区

《我的世界》服务器是一个有趣的例子:公共网络服务器。web 服务器是指某人用来提供 web 服务的计算机,可以是计算机游戏、网站、邮件列表、wiki 或论坛。作为计算机,web 服务器有其局限性:有限的处理能力(以千兆赫兹为单位)、内存(以千兆字节为单位)、带宽(以每秒千兆字节为单位)和电力(以每月$$$为单位)。未能充分提供这些意味着未能提供你的社区可以依赖的服务。作为一个几乎对任何人开放的无限 3D 多人虚拟世界,《我的世界》是资源密集型的,这使得这些挑战尤为严峻。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Commons depletion in Minecraft. Communities must manage CPU, RAM, bandwidth, vandalism, and also in-game resources. Credit.

任何能够在这种情况下茁壮成长的系统,尽管整个人类都可以使用,从冲动控制能力差的匿名青少年到专业黑客团队,都是在做一些特殊的事情。默认情况下,公共 web 服务器是“公共”的。加入你的小世界的每一个额外的用户或玩家都会增加它的负担。即使你的所有用户都是善意的,如果太多人做得太多,你的服务器也会停止工作,你的社区也会受到影响。当一种有价值的有限资源可供所有人使用时,我们称之为公共池资源,我们密切关注经典的公地悲剧:太多人获取太多,直到每个人都一无所有。

信息时代与市场交易的全球主导地位的巧合是,几乎每一项先进技术的应用都在走向让共有资源灭绝。任何能让小玩意变得更小或更便宜的东西,都会让私人更容易拥有,也更容易被那些把商品理解为你拥有和买卖的东西的系统识别。这可以追溯到像铁丝网这样的技术,它将西部荒野从造就牛仔的巨大牧场变成了一个可行的栅栏,将大片以前的荒地隔开,并允许私有财产的想法。(牛仔是常见的池资源管理者,他们在西部游荡,通过围捕将牛群带回给它们的主人。).像《我的世界》那样的私人服务器与这种说法正好相反。随着现代技术对公共领域的不利影响,每次你偶然发现由技术创造的公共领域时都很有趣。好像他们不会离开。

这带来了一个大问题。公地会消失吗?它们能被私有化和科技化吗?这是加密货币背后的自由主义意识形态的一个基础。但是赌注比最新的技术更高。

几乎每一位民主哲学家都说过,成功的自治不仅取决于良好的规则,还取决于拥有持有关键规范和价值观的成员。民主有几个众所周知的弱点,规范和价值观是其免受煽动家、独裁者、精英或暴民统治的唯一可靠保护。这种对文化的敏感性使得民主制度与市场、等级制度和专制制度形成对比,后者对胡萝卜和大棒的依赖使它们更加独立于价值体系。经济学家萨姆·鲍尔斯(Sam Bowles)区分了马基雅维利式和亚里士多德式的制度,即对最坏的公民稳健的制度,以及创造良好制度的制度。愤世嫉俗与文化驱动的机构。

让愤世嫉俗的机构变得愤世嫉俗的同样的事情也让它们变得容易分析、设计和工程化。我们已经变得善于建设它们,它们已经占据了世界秩序的顶端。这是他们的合法地位吗?在培养我的传统中,只有文化驱动的机构才能在不诉诸独裁的情况下应对管理公地的挑战。如果技术不能从我们的未来中获取公共资源,我们需要像工程市场和指挥链一样擅长工程文化驱动的机构。《我的世界》看起来只是一场游戏,但在它成功的背后是定义民主在 21 世纪角色的紧张局势。

不幸的是,那些让愤世嫉俗的机构容易建立和研究的因素同样让文化驱动的机构变得困难。有可能复制成千上万个层次结构并测试其变化:这就是特许经营:星巴克、麦当劳、复制、粘贴。相比之下,你在生活中发现的每一个鼓舞人心的参与性社区都是一片独特的雪花,其精华可能无法复制,无论是好是坏。

通过研究互联网上的自组织社区,无论它们出现在哪里,我们都利用了一个历史性的机会,将“科学”放在“政治科学”中,达到了一个曾经不可想象的程度。当你记录一个人试图在他们自己的小社会沙盒里扮演上帝时,你就是在实践历史。当你记录了一百万,你就是在实践社会物理学。我们可以看着数百万人试图建立他们自己的小乌托邦,看着他们成功和失败,区分坏选择和坏运气,确定在大多数情况下一个坏主意在其他地方什么时候会是好主意,并根据所有这些经验,建立制度有效性的一般理论。

有几个特点使得在线社区非常适合研究文化驱动的机构。他们的低准入门槛意味着他们的数量会更多。业余服务器也更透明,它们较小的规模使它们更简单,它们较短的数字记录的历史允许洞察制度变化的过程,并且它们提供已知软件的相同副本的事实使得进行苹果到苹果的比较成为可能,这使得地球上的国家的比较通过比较看起来像苹果到大象。

正式治理的产生研究

伟大的想法是好的,但是你必须把它们固定在某个地方。我开始了我的研究,问了一个更狭隘的问题:社区如何以及为什么在增加整合和正规化的方向上发展他们的治理系统?这是一个国家从哪里来的问题,官僚主义和规则。我们需要规则吗?有没有一个正确的方法来利用他们来治理国家?大人口和小人口有区别吗?为了回答这个问题,我写了一个程序,在两年的时间里每隔几个小时扫描一次互联网,访问社区以获得关于它们如何运行、谁访问它们以及这些访问者多久回来一次的信息。我将社区成功定义为核心群体的出现,即在一个月内每周至少一次返回特定服务器的玩家数量,从他们可能访问过的数千个社区中选择该服务器。因为一台服务器的典型寿命是 9 周,所以可以观察超过 15 万个社区的整个生命周期。每一个都从本质上相同的初始条件开始,一个矛盾的“无政府状态”,只有一个统治者,没有规则。每一个都是根据一个主权管理者对于是什么把人们聚集在一起的天真想法而演变的。随着这种意识的发展,管理员可以安装一些软件来实现治理的各个方面,包括私有财产权、同行监督、社会等级、贸易、通信等等。大多数人失败,一些人成功。

根据我的分析,大型社区越积极地应对各种各样的资源管理挑战,而且有趣的是,他们越是授权给唯一的管理员,它们似乎就越成功。领导力是成功社区的重要组成部分,尤其是在社区成长的过程中。当我们把焦点转向小社区时,这个故事变得更难与最喜欢的意识形态保持一致。事实证明,如果你的目标是管理一个 4 人社区,而不是 400 名普通用户,那么没有哪种治理方式明显比其他方式更有效:做一个专制者,做一个社会主义者,使用共识或骰子,在参与人数足够少的情况下,理论上不可能的安排在实践中也行之有效。

今后

这个项目表明,对大量有据可查的政治实验进行严格的比较,有可能理解治理成功的预测因素。这对参与性的、赋权的治理机构的未来非常重要。除非有效的社区建设可以简化为一个公式,否则有效的社区将是罕见的,我们人类将继续无法挖掘互联网的全部潜力,使文化驱动的机构成为主导我们互动的愤世嫉俗的机构的可扩展、可复制、可行的竞争对手。

每天都有更多关于侵犯我们的隐私和操纵我们的观点的坏消息,很难对互联网以及它将对我们机构的健康做出的贡献感到乐观。但是在后台勤奋工作的是整整一代年轻人,他们一直在训练自己设计和领导成功的社区。他们对于是什么让人们走到一起的感觉并不是来自于一个有魅力的人的高谈阔论,而是对他们自己过去没能让所爱的人走到一起的回应。他们能够识别新生独裁者的警告信号,不是因为他们读过过去的独裁统治,而是因为他们亲身经历了对一个小小虚拟王国的绝对权力的诱惑。随着科学家间接地学习这些经验,大规模的在线自治不仅有望培养出更多精明的民主捍卫者,还能为现实世界中健康、知情的参与式文化的设计和发展提供信息。

Seth Frey 是计算社会科学家,也是这项工作的主要作者。他在的发博客,发微博@ enf ascing*。*

将 Colab 带到您身边的 Jupyter 笔记本电脑上…

原文:https://towardsdatascience.com/bringing-colab-to-a-jupyter-notebook-near-you-3f326f89fae7?source=collection_archive---------13-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Google 在 Colab 中构建了一些不错的功能。现在你可以从 Jupyter 笔记本中受益。

一直以来都是错误

当用 Python 编程时,当您在嵌套函数调用的堆栈中遇到错误时,这可能会令人不知所措。Python 的优势之一是它有大量高质量的可用库,并且这些库的源代码很容易获得。有时候,为了能够理解正在发生的事情,能够深入了解它是很有用的。

为了帮助您做到这一点,Google Colab 会在堆栈跟踪中自动显示指向源文件的可点击链接,以及一个方便的按钮来搜索堆栈溢出中的错误。如果 Jupyter 笔记本也能这样不是很好吗?我也是这么想的,所以我决定创建一个笔记本扩展来实现这个功能。

转到错误笔记本扩展

如果你还没有安装 Jupyter 笔记本扩展,你可以通过输入

pip install jupyter_contrib_nbextensions

从 GitHub 下载 Goto 错误代码

git clone git://github.com/teticio/nbextension-gotoerror

像这样安装它

jupyter nbextension install nbextension-gotoerror

最后,让它如此

jupyter nbextension enable nbextension-gotoerror/main

如果一切按计划进行,您应该能够在 Jupyter 记事本的 nbextensions 选项卡中配置 Goto 错误扩展。

由于 Jupyter 服务器只能访问运行它的目录或子目录中的文件,为了使笔记本能够打开源文件,有必要提供一个到源文件目录的软链接。例如,如果您不使用虚拟环境,在 Jupyter 启动目录中创建到您的 Python 安装的 site-packages 目录的软链接(例如~/lib/python3.6/site-packages),并将其称为site-packages。然后将 nbextension 配置中的前缀参数设置为~/lib/python3.6

如果您确实使用虚拟环境,那么将软链接指向envs目录,并相应地设置前缀参数。

要在 Linux 中创建软链接:

ln -s ~/.local/lib/python3.6/site-packages site-packages

要在 Windows 中创建软链接:

mklink -d envs C:\users\teticio\Anaconda\python\envs

它现在应该像下面的例子一样工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你还要吗?

Google Colab 还有其他一些很棒的功能(除了免费访问 GPU 和 TPU!).例如,如果你在行尾添加一个#@param注释,它会自动创建一个允许用户输入值的表单。例如

fred = 123 #@param {type : 'number'}

弹出一个有“弗雷德”和数字 123 的表格。例如,如果您将表单中的数字更改为 456,代码将更改为

fred = 456 #@param {type : 'number'}

我想为 Jupyter Notebook 开发一个做同样事情的扩展,当我在做的时候,把这两个扩展都移植到 Jupyter 实验室。请让我知道,如果这是你会使用的东西。

将数据带入生活—让他们通过数据可视化讲述他们的故事

原文:https://towardsdatascience.com/bringing-data-to-life-let-them-tell-their-story-with-data-visualisation-13e71f6553a6?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有人可能会认为,数据科学,由于其名称以及与统计学和软件开发的密切关系,是一个纯粹的技术领域。但是当一个人深入挖掘现代数据分析的应用时,他们可能会发现清晰而公正地呈现分析结果几乎和分析本身一样重要。正确的数据可视化不仅需要一些高级图表类型的技术技能和知识,还需要绘制图片和用数据讲述故事的能力,这使它成为数据科学的一个“艺术”部分。

数据可视化在商业中起着特别重要的作用,在商业中数据分析被广泛应用。数据建模和分析的结果通常会影响利益相关者的想象力并激发他们的决策,因此他们正确理解分析的结果是至关重要的。然而,最高管理层很少对预测模型和统计有深入的了解(或者有时间去钻研它们的数学细节)。以清晰、全面和吸引人的方式直观地呈现数据,对他们以数据为导向的决策过程有很大帮助。在这篇短文中,我们提出了一些如何将数据转化为有效的、发人深省的故事的技巧。

了解业务

在商业领域,数据科学家的工作是通过数据分析帮助公司发展和解决问题。数据科学家可以对战略业务决策和公司发展方式产生巨大影响。随着数据科学对公司运营方式的影响越来越大,其对财务结果的影响也将增加。这意味着数据科学家了解他们工作的行业并了解他们公司的当前目标至关重要。他们需要知道最关键的问题是什么,以及可以应用什么实际手段来解决这些问题。这样,数据科学家的注意力将总是最有效地集中,他们的工作成果将在实践中适用。

消除杂乱

在一张图上放太多的视觉元素会使它变得复杂和难以理解。如果一个图表太混乱,你可能会失去你的听众的注意力,他们会专注于“解读”它,而不是听你想告诉他们的故事。这样,非但不会强化,反而会模糊你的信息。因此,你应该再三考虑你想在你的图表上放什么,以及每一项的目的是什么。确保你演讲的每一个元素都有助于观众理解你想告诉他们的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Chart 1. The number of subscribers of two versions of a mobile app (illustrative data). Additional elements can help tell the story of the data. The vertical line in the graph above splits its area into two parts corresponding to time periods before and after the release of a new version of an application. Displaying number values only on the right-hand side of the line focuses the attention on what happened after the upgrade, and eliminates unnecessary clutter on the left-hand side.

将注意力集中在你想要的地方

为了集中你的观众的注意力,重要的是你要思考他们是谁,他们的背景是什么,以及他们如何看待这个世界。对于一个非常技术性的工程师小组,以及一个教室里的一群中学生,你可能会使用不同的图表。您可以使用大小、颜色、形状和在页面上的位置等属性,使图表引人入胜,并将受众的注意力吸引到您希望他们看到的区域。这将有助于你以你认为最好的方式引导他们完成你的演示。不要害怕偏离一些“标准”的数据呈现方式,或者添加额外的元素,如箭头、圆圈甚至文本框。如果有东西可以讲述你的数据的故事,那就使用它!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Chart 2. The share of opinions of 5 selected features of a mobile app (illustrative data). A stacked horizontal bar is a good choice for presenting percentage data in groups. Choosing the right order and position of groups (‘Features’ in the above graph), as well as color and order of bar segments (‘Dislike’/’Neutral’/’Dislike’), we can focus the audience’s attention on the selected elements and — more importantly — facts they represent. Note that in the above graph, using contrasting colors, and specifying numerical values highlights extreme bar segments, and tells the central message at first glance at the chart.

像设计师一样思考

在进行数据可视化的时候,把它当成你想卖给观众的产品。像设计师一样思考,并回答你的观众将如何与你的演示互动的问题。布局是否清晰?图表中是否有可能引起混淆的内容?随后的图表是否按逻辑顺序排列,从而创建一个易于理解的演示文稿?另一方面,观众是会对他们看到的提出问题,还是只听你的解释?他们可能会对你的工作进行评论或补充吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Chart 3. The number of subscribers, user satisfaction level, and average time spent daily in an application for selected cities, along with information about the cities’ population (illustrative data, except population values). Bubble chart can help tell a comprehensive data story with only one picture. Adding colors based on one of the data features to each of the bubbles, increases the dimensionality of the graph, broadening and enriching its message. Just remember to keep it all visually clear, and to add a complete legend, to keep your audience from getting lost in the abyss of the presented data.

讲故事

故事是神奇的。用一个故事与你的听众交流,并从情感上吸引他们。通过在演示开始时给你的听众一点提示,让他们对你将要演示的结果感到兴奋。但是不要一开始就告诉他们一切!悬念是抓住和保持注意力的关键。因此,在此基础上,让你的观众对接下来的内容感到好奇和兴奋。

此外,从更实际的角度来说,事先想想你的听众在看你的演讲时可能会有什么问题,然后把这些问题的答案融入到你的叙述中。这样你的故事会更完整,你的陈述会更少被打断。

总结:

每个数据集中都有一个隐藏的故事。你讲这个故事讲得有多好,你如何激励你的观众采取行动,都取决于你自己。请记住,要格外注意你在故事中绘制数据的方式,因为*“一张图胜过千言万语”*。伟大的故事激发伟大的思想。确保你的听众不仅记得他们所听到的,而且被数据可视化的神奇魅力所激励。

参考资料:

科尔努斯鲍默克纳弗利克,用数据讲故事。面向商业专业人士的数据可视化指南

作者:michahrabia,Miquido
的数据科学家,合著者/致谢: Karolina Holewa ,Miquido 的初级数据科学家

如何在亚马逊红移中模糊匹配数据集

原文:https://towardsdatascience.com/bringing-fuzzy-matching-to-redshift-d487ce98d170?source=collection_archive---------11-----------------------

使用 Python UDF 实现 Amazon 红移中的模糊匹配连接

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fuzzy Merging — Photo by Markus Spiske on Unsplash

如果幸运的话,当在数据仓库中处理多个数据集时,会有某种类型的连接列可用于您想要放在一起的表。

当这种情况发生时,生活是美好的。然而,现代大数据解决方案正在开辟一个用例,将来自不同来源的各种数据整合在一起。

虽然我们可以轻松地将这些数据存储在一个地方,但是将它们连接起来进行分析并不总是那么简单,因为这些数据集通常不是由同一个源系统生成的,所以要连接的干净的 ID 列并不总是可用的。即使为您提供相同信息的列也不总是以相同的格式提供,如果是用户捕获的,您永远无法保证一致性。

基于相似性将数据集连接在一起的一种方法是模糊匹配,特别是当您知道每个数据集中有基于文本的字段几乎相似时,例如用户输入的公司名称或产品名称。

这篇文章不会详细讨论模糊匹配的所有细节,但是会向你展示如何在 Redshift 中使用 Python 实现。

模糊匹配

在最简单的层面上,模糊匹配看起来产生两个事物有多相似的相似性分数。我将着重比较字符串来解释这个概念。

作为人类,我们很容易发现打字错误,或者在概念上理解两个相似的东西是相同的。模糊匹配算法试图帮助计算机做到这一点。两个字符串之间的匹配不是布尔真或假,即完全相同或不相同,模糊匹配给出的是接近度分数。

以“布鲁克林大桥”和“布鲁克林大桥”为例。即使在第二个字符串中有拼写错误,人类也很容易发现这是同一个东西。

一种模糊匹配算法,例如给出相似性百分比分数的 Levenshtein distance ,可能会将这两个字符串评分为至少 90%相似。我们可以使用它来设置我们希望“相似”的阈值,即任何两个模糊分数超过 80%的字符串都是匹配的。

Python 实现

这些天你可以找到很多 Python 包,所以我不打算重新发明轮子。一个体面的使用 Levenshtein 实现模糊匹配的 python 包是 fuzzy wuzzy

按照文档中说明的安装过程,您最终会得到一堆用于比较字符串的函数。

我在这个例子中使用的是一个简单的比率函数,它接受两个字符串并给出一个接近比率。这里有一个示例实现,展示了前面的布鲁克林大桥示例。

>from fuzzywuzzy import fuzz
>fuzz.ratio(“brooklyn bridge”, “brooklin bridge”)> 93

正如所料,这返回了一个相当高的分数,因为两者非常相似。

红移 UDF

用户定义的函数允许您使用 SQL 或 Python 向 Redshift 添加可重复的代码块。python 支持将允许我们采用上一节中的实现并添加到 Redshift 中,这样我们就可以像调用任何其他原生 SQL 函数一样简单地调用它。

首先,我们需要添加 fuzzywuzzy 库到红移。有一些完整的文档,但是我将在下面概述基本步骤。

  1. 从 github 下载 fuzzywuzzy 回购
  2. 在回购中复制一份 fuzzywuzzy 文件夹,并将其压缩。
  3. 将此压缩文件夹复制到 S3 桶中
  4. 在 Redshift 中运行以下命令来导入 fuzzywuzzy 库
CREATE LIBRARY fuzzywuzzy LANGUAGE plpythonu FROM 's3://<bucket_name>/fuzzywuzzy.zip' CREDENTIALS 'aws_access_key_id=<access key id>;aws_secret_access_key=<secret key>'

完成后,我们现在可以继续使用红移中的这个库来创建函数。

CREATE FUNCTION fuzzy_test (string_a TEXT,string_b TEXT) RETURNS FLOAT IMMUTABLE
AS
$$
  FROM fuzzywuzzy import fuzz 
  RETURN fuzz.ratio (string_a,string_b) 
$$ LANGUAGE plpythonu;

我们现在可以测试它,并检查我们看到的结果是否与我们在本地看到的结果相同。

SELECT fuzzy_test('brooklyn bridge', 'brooklin bridge');> 93

包裹

就这么简单。这是一个很好的特性,由于 Python 中可用的库的范围,Python UDF 给了你很大的灵活性。

由于红移星团的力量,这意味着大规模的模糊匹配是可能的,这可能永远不会在笔记本电脑上完成。然而…

如果您打算将它用于连接,需要考虑的一件事是,它显然会比通常慢,因为在连接上不会发生太多优化。因此,如果您要匹配大型字符串数据集,那么请做好等待的准备:)

脆弱的人工智能:渴望和僵化之间的联系

原文:https://towardsdatascience.com/brittle-ai-the-connection-between-eagerness-and-rigidity-23ea7c70cb9f?source=collection_archive---------21-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PatiencePhoto by Michel Porro on Unsplash

AI 为什么脆?

今天困扰人工智能的是脆性。有人推出了这个神奇的人工智能程序,它在一些任务上表现出超人的性能,但对输入的微小调整就让它屈服了。在识别图像中的物体方面表现出色的人工智能系统可以被欺骗,通过改变单个像素来看到不存在的长颈鹿。自动驾驶汽车,它尖叫着“AI!!!"比其他任何人都更容易被仅仅是贴纸的东西蒙骗,在错误的道路上行驶。

是什么让 AI 变脆了?我提出了一个被忽视的原因,我认为这是这种脆弱性的关键:对热切方法的严重依赖,这是我从编程语言中借用的术语。渴望是尽早决定,除了关闭选择和混合多种选择的大门。渴望是板球击球手丑陋的预先思考的镜头,是新生的高斯林将第一个移动的物体视为妈妈的“决定”,是阿尔伯特·爱因斯坦哀叹的信念诱导的认知固定性,当他提出 19 世纪物理学停滞的发生是因为物理学家“在经典力学中看到了所有物理学的坚实和最终的基础,是的,确实是所有自然科学的基础”。

在构建计算机系统的过程中,渴望表现为一种信念,让人联想到认知的固定性,即系统的某些方面是固有的,是一成不变的,因此我们必须在一开始就设计好,然后冻结。一些这样的假设是没有根据的,现有的系统没有这样的假设。例子包括“一种编程语言有固定的语法”“一个深度学习系统的神经网络有固定的形状”;现代编程语言和 AutoML 分别显示了这种假设的谬误。其他假设弥漫在今天的人工智能中,有些是因为它们看起来如此明显地固定,例如 backprop 中的损失函数,有些是因为将某些东西视为固定是方便的,有些是因为我们还没有想出如何改变这些。此外,我们急切地将假设融入到问题的定义中,正如我们希望我们的情感分类系统将电影评论分为积极和消极两类时所做的那样(但是,唉,评论作者不合作,他们添加细微差别,列出好和坏的方面,而不是一劳永逸地给我们一个好-坏光谱上的单点)。

脆性源于对语义不连续性的错误处理。社会学家 Eviatar Zerubavel 的优秀著作《细线》充满了任意不连续的例子:如果两个点相隔几英寸,它们之间有不同的法律,如果相隔几分钟,相隔几分钟的两个时间看起来不一样。加里·马库斯认为,常识是人工智能中缺失的成分。常识往往依赖于这种不连续性:动物在死亡前几分钟还活着,但在死亡后几分钟还活着,在鸡肉盘中放蔬菜是可以的,但在素食盘中放鸡肉却不行。

一种使用其对类似情况的了解来推理一种情况的技术——基于案例的推理和想到的向量空间表示——最好对相似性有高超的掌握。脆性将是一种技术,这种技术将两种食谱之间的相似性建立在共享成分的比例上,因为这种技术对单一成分越过的重要界限不敏感:围绕素食、围绕犹太食品、围绕无花生食品的界限。健康食品和不健康食品之间的界限更模糊,也更典型,但即使在这里,重叠的成分列表也可能与这种粗略划分两边的食品相同。

如果一个计算机系统对分界线两侧的两点使用相同的表示,我们说该表示对该边界不敏感,至少在那里是如此。渴望导致了这种代表性的崩溃,抹去了界限,如果它建立了什么样的区别需要关心,因此什么样的区别可以安全地忽略的话。

在这篇文章中,我从显著性决策和随之而来的代表性崩溃(1)开始,接着是渴望和僵化在两个领域的相互作用:动物行为中的固定动作模式(2)和编程语言(3)。并非所有的人工智能都渴望,许多最近的发展,如 BERT,AutoML 和 AlphaZero,比他们改进的系统更有耐心(4),但许多人工智能链,包括这三个,保留了大量的渴望和随之而来的脆弱性(5)。下一篇文章将描述展现出某种耐心的算法,从我与丹·罗斯和锡德·米塔尔的合作,到我与道格拉斯·霍夫施塔特在一个名为的认知架构上的合作。

我应该强调,我的目标不是诋毁渴望;渴望有它的用处,如果我们试图消除它,我们的工具箱会变得更穷。我的目标是指出效率和刚性之间的权衡,并建议如果我们理解脆性在哪里蔓延,那么在保持效率的同时保持灵活性是可能的。

1。显著性决策和表征崩溃

我们并不代表世界的全部细节——要代表的东西太多了,我们忽略了大多数微小的差异。对变化视而不见的现象证明了我们表征的简单性:我们不会注意到根本性的变化,甚至是如此彻底的变化,以至于我们刚才与之交谈的人被另一个人取代了。在一个变化盲的例子中,一名实验者向一名路人询问去一栋建筑的方向。在路人完成他的回答之前,另外两个实验者扛着一扇大门闯进了他们中间,在混乱中,其中一个扛门的人和原来的实验者交换了位置。令人惊讶的是,过路人并没有察觉到这种转换,从而强调了他所形成的不完整的表象。变化盲是一个经过彻底测试的强健现象,你可以在这里观看视频。

简而言之,我们关注对我们重要的事情。威利安·詹姆士很好地抓住了这一点:

让四个人去欧洲旅行。一个人只能带回家如画的印象——服装和颜色、公园和风景、建筑作品、图画和雕像。对另一个人来说,这一切都不存在;距离和价格,人口和排水系统的安排,门和窗户的紧固,和其他有用的统计数据将取代它们的位置。第三个会给一个丰富的剧院,餐厅,公共舞会,除此之外什么也没有;而第四将可能是如此包裹在自己的主观沉思,告诉比几个他通过的地方的名字。每个人都从大量呈现的对象中选择了适合自己兴趣的对象,并由此获得了经验。

通过选择重要的东西,我们含蓄地决定了我们可以忽略什么。仅仅在这些不重要的细节上不一致的截然不同的情况因此可以被一致地表示出来。一个普通的袖珍计算器的“记忆”功能就是一个极好的例子。计算器的内存只够存储三个数字,但它可以“跟踪”数百万个数字,并报告它们的总和、平均值和标准偏差。它实现这一壮举的方式是,它不是跟踪所有的数字——这些数字太多了,无法跟踪——而是记住三个量:它看到了多少个数字,它们的总和,以及它们的平方和。这三个总结足以计算出现在已经被遗忘很久的序列的标准差。
因此,不同的数字序列可能导致相同的状态。因此,如果它看到了数字 1、5、6、8 和 8,它会记住这五个数字,它们的和是 28,它们的平方和是 190。相反,如果它看到 3、4、4、7 和 10,它会达到相同的状态。因此,这两个不同的序列合并成一个单一的表示。注意,对于它支持的计算,这两个序列是等价的。对于不同的任务,比如说计算几何平均值,汇总表示是不够的。

这种极端的减少在计算器的正常使用中很难察觉,但也不是完全没有问题。它会导致计算器支持的一个操作出现奇怪的行为。为了告诉计算器要计算的一组数字,我们对每个数字按“M+”。另一个标有“M-”的按钮会删除一个数字,以防不小心输入了一个数字。在上面的例子中,如果我们从集合{1,5,6,8,8}中去掉 20(事实上它并不在那里,这个事实必然会在计算器上丢失),新的状态是:四个数字,它们的和是 8,它们的平方和是-210。奇怪的结果,因为平方和总是正的。稍微超出正常的使用范围,我们就会看到这个优雅而高效的算法中令人想起的漏洞。

原始的一组数字将永久丢失,并且无法从压缩版本中恢复。生成表示(即数字序列)所消耗的成分已经完全融合到最终的表示(三个摘要)中。这种不可逆转的崩溃对我的论点很重要,我们稍后将看到人工智能系统如何做出急切的显著决策,并丢弃“无关紧要的细微差别”,这些细微差别最终证明并不那么无关紧要。

在崩溃的“等价”情况下隐藏的危险是,尽管这种崩溃成为一种节俭的表现是有效的,但在现实世界中,等价是短暂的。在一个世界中,两个国际象棋位置可能是等价的——比如说,在标准国际象棋的世界中——但在一个略有不同的世界中,这些位置可能相距数英里——比如说,等级膨胀国际象棋,这是我发明的一种国际象棋变体,棋子不是在第八行提升,而是在第七行提升。或者,对于一个不需要改变规则的更轻微的变化,对于一个专业棋手来说,当与一个新手(他天生缺乏利用微妙弱点的专业知识)对弈时,两个位置实际上可能是相等的,但是当与卡斯帕罗夫对弈时,同样的两个位置可能是截然不同的。

2。极度渴望:基因中的选择

舞台魔术师兼哲学家丹尼尔·丹尼特喜欢指出,魔术对观众来说很难理解,因为当观众认为魔术开始时,魔术师已经完成了魔术。我们的一些“决定”和选择也可能发生同样的情况,这些决定和选择可能早在出生之前就已经为我们做出了,动物世界提供了一些很好的例证。

Sphex 黄蜂有一个奇怪的仪式,很好地适应了它的环境。道格拉斯·霍夫施塔特在哥德尔、埃舍尔和巴赫中引用了这种无脑者和智者的奇怪组合:

当产卵的时间到了,黄蜂 Sphex 为此建造了一个洞穴,并找到了一只蟋蟀,她用这种方式刺它,使它瘫痪但不杀死它。她把蟋蟀拖进洞穴,在旁边产下卵,关上洞穴,然后飞走,再也没有回来。在适当的时候,卵孵化,黄蜂幼虫以瘫痪的蟋蟀为食,它没有腐烂,一直被保存在黄蜂相当于深度冷冻的地方。对人类来说,这样一个精心组织的、看似有目的的例行程序传达了一种令人信服的逻辑和思考的味道——直到更多的细节被检验。例如,黄蜂的惯例是把瘫痪的蟋蟀带到洞穴,放在门槛上,进去看看一切正常,出来,然后把蟋蟀拖进去。如果蟋蟀被移动了几英寸远,而黄蜂正在里面进行初步检查,黄蜂从洞穴出来后,会把蟋蟀带回门槛,但不是在里面,然后会重复进入洞穴的准备程序,以确保一切正常。如果当黄蜂在里面时,蟋蟀又被移开几英寸,她会再一次把蟋蟀移到门槛上,重新进入洞穴做最后的检查。黄蜂从没想过把蟋蟀直接拉进来。有一次,这个过程重复了四十次,总是得到同样的结果。

黄蜂在这件事上没有真正的选择。它不能选择不验证陋居的安全性——这个决定在她出生前几千年就已经做出了,编码在她的基因中(或者更准确地说,是基因与黄蜂的宏观和微观环境的相互作用,但这并没有改变我的论点)。

这种硬编码行为很常见。在斑尾鹟养父母的巢中,一只新生的早期孵出的布谷鸟,通过有目的地滚动和投掷巢中的蛋来杀死它未孵化的鹟“兄弟姐妹”。与其说它选择这样做,不如说它感到懊悔。另一个著名的例子是灰雁本能地与它们看到的第一个移动物体结合——同样不是有意识的选择。

我们可以说这种固定的行动模式在动物的大脑中是根深蒂固的。它们不同寻常之处在于它们相对来说不受环境的影响。不变行为是可预测的,这可能导致它们被人类或其他动物利用。如果环境改变了,这样的行为就变得不适应了。因此,在复杂动物中生存下来的固定行为对于生命来说是必不可少的,或者在速度(即缺乏学习)至关重要的地方。一个这样的例子是人类新生儿的吮吸反射,当父母的贿赂和哄骗不太可能有效时,它保持良好的喂养。

如前一节所述,等效是短暂的,我们看到情况的不良影响被隐含地视为等效,因此值得同样的反应。正如诺贝尔奖得主尼科·丁伯根用银鸥展示的那样,银鸥的父母喙上有一个红点,当被雏鸟啄时,父母会给雏鸟喂食,雏鸟会强迫性地啄任何红点甚至黑点,即使那些点是在棍子上,而不是在喙上。上面画有圆点的棍子在自然界是不存在的,没有理由增加任何机械来处理那种情况。

在基因中编码行为是热切的。进化预测到了——很有能力,但没有理解——一个物种的动物可能面临的一些情况,并将某些触发因素与特定行为联系起来。这种行为可以拯救生命,并且可以有效地实施,但对于我们人类乐于称之为智能的东西来说,这是不够的。

对大脑发育和性别决定有耐心

这些例子来自《依赖基因》一书(感谢@freerecall 推荐!).

在胚胎成长为成人的过程中,大脑与各种“外围设备”相连:眼睛、耳朵、四肢等等。但是对于每种有多少,信息是如何存储的呢?令人惊讶的答案是,也许不是,这种联系是机会主义的。大脑抓住一切可以利用的东西,通过它们的化学特征吸引潜在的目标;没有连接起来的神经元得不到“营养因子”化学物质并枯萎。如果更少(因为意外或实验操纵),它们被连接起来,每个得到更多的大脑处理;如果有更多,那也很好。不需要硬编码“分支数量”——这可以是运行时的决定。

同样,我们认为个体的性别是固定的和固有的。然而,对于珊瑚鱼来说,一只雄性鱼控制着一群雌性鱼。当雄性死去,最大的雌性,在几个小时内,变成雄性,完成精液的产生。

软件解决方案

与硬编码动作模式的盲目能力相比,“软件解决方案”提供了一个更灵活的系统来组织从刺激到动作的映射。这里的类比是,计算机硬件可以支持不同的软件。如果我们可以将触发器与一些内部符号挂钩,并将它们与动作挂钩,而不是将触发器和结果动作硬连接在一起,这种松散耦合将像在计算机编程中一样实现间接性,我们将在下一节中看到这一点。人类婴儿并不是生来就被硬编码为英语、汉语或原始印欧语,但是我们可以在这些设置中的任何一个或几个设置中对其进行配置。这样的配置并不急切——其环境的特殊性将允许婴儿说英语或克林贡语。一个出生时就有任何特殊天赋的婴儿在当今世界将会是一个不适应的人。

进化并没有预料到当今世界所需要的许多职业能力:小鸡性别鉴定师、爵士乐教练、迪斯尼世界的公主、保险承保人等等。目前还不清楚如何将基因和蛋白质表达的正确序列连接起来,以产生这些职业所必需的行动模式。这种灵活性似乎在很大程度上归功于语言和形成抽象、命名具体和抽象事物以及引用这些抽象的能力。接下来,我们将看到一组几乎相同的附加功能是如何在编程语言中实现灵活性的。

3。耐心使编程语言更加灵活

我们倾向于假设任何编程语言都有固定的语法。事实上,传统编程语言的语法被正式指定为语法,任何不符合这种严格语法的程序都是无效的,不会被编译。由于其固定的语法,即使研究 C++程序的一个很小的片段,将它分割成记号,并将这些记号分类为变量、函数调用或其他东西,都是可能的。

这种“一种语言一种语法”的假设被一些所谓的动态编程语言打破了——或者说粉碎了。在 Perl 这种语言中,程序员可以切换到完全不同的语法,甚至在一个文件中混合几种语法。标准的 Perl 语法充斥着符号%、$、和@,而且词序很重要:像任何其他编程语言一样,语句“a=b”不同于“b=a”。虽然 Perl 的设计者没有预见到用格式良好的语法拉丁语(通过-um 和-o 这样的大小写结尾实现词序的流动性)编码的渴望,但他们预见到了 Perl 的灵活性。漫威在达米安·康威的大师展示了这个完全合法的 Perl 程序的拉丁语编程,它使用被称为厄拉多塞筛的算法一个接一个地打印所有的质数。正如康威博士指出的,如果你必须问为什么有人可能希望用拉丁语编程,答案对你来说不太可能有意义。

use Lingua::Romana::Perligata;
maximum inquementum tum biguttam egresso scribe.
meo maximo vestibulo perlegamentum da.
da duo tum maximum conscribementa meis listis.
dum listis decapitamentum damentum nexto
fac sic
    nextum tum novumversum scribe egresso.
    lista sic hoc recidementum nextum cis
    vannementa da listis.
cis.

在我们考虑是什么实现了这种灵活性,这种中途改变语法的能力之前,让我们看两个进一步的例子,对比传统语言的刚性和 Perl 的流动性。

首先是变量的类型的概念(即变量是否存储整数、字符串等等),以及传统语言坚持在运行程序之前(用技术术语来说,“在编译时”)知道每个变量的类型,这种坚持导致它还要求知道每个数组的类型,并且该数组的所有成员共享一个类型。相比之下,Perl 是悠闲的,在编译时不需要知道变量的类型。当它运行那一行代码时,它只需要知道类型,如果一个数组包含不相关类型的混合,没有问题。

第二个区别要深刻得多,因为它涉及到语言如何在内存中表示对象,如何为这些对象分派方法,如何构造一个类的新对象。这些问题是语言设计的核心,对于任何语言来说都是不可避免的。但是对于像 Perl 和 Python 这样的语言,使用所谓的元类,即使这样我们也可以改变,我们可以在一个程序中自由地混合几种类型的对象。在这里,我们也看到,我们认为对于特定语言来说是铁板一块的东西,实际上是可以混合搭配的。

所有这些因素使得用动态语言编写代码变得更加简单。这种灵活性可能会有问题,但这不是我们在这里关心的问题。问题是,对于由数百名程序员执行的超大型项目,如果不同的程序员选择不同的方法来实现相同的目标,这种灵活性可能是灾难性的。正如 Perl 的创造者拉里·沃尔喜欢说的那样,Perl 给了你足够的绳索来搬起石头砸自己的脚。但是,我们不要让这分散我们对手头业务的注意力,理解灵活性的起源。

顺便说一下,在编程语言中,早和晚的区别有好几个名称。“早期”通常被称为急切或编译类型或静态,而“后期”被称为懒惰或运行时或动态。

刚性来源

传统编程语言的大部分刚性来自于静态分析——在编译过程中,在将程序翻译成机器代码的同时对其进行分析。这个过程自然是“早期”的——在它运行任何代码之前。这个过程删除了“不相关的”信息——它通过将“等同的”程序映射到相同的机器代码来折叠它们。

正如您可能猜到的,不相关的信息对于实现上面讨论的灵活性是必不可少的。那么这个不相关的信息是什么呢?名字。变量名、函数名和类名。除了替换这些名称之外,两个无法区分的程序将产生相同的机器代码。

但是等等。只有当我们不能以任何方式引用变量名时,两个具有不同变量名的程序才是等价的。那么,在这些编程语言中,我们不能写“对于每个名字包含 *x、*的变量,将值增加 1”。

这里的刚性来自于强加的等价。通过将这种等价性分割开来,仅仅通过存储变量名和数据类型并允许通过名称引用它们,新的编程技术就变得可用,包括“动态分派”,它选择在运行时而不是在编译时调用函数。

使用变量、函数和类的名称来定位它们的能力打开了一个全新的可能性领域:现在可以在运行时创建新的函数和类,反过来又可以创建更多的函数和类,令人厌烦。在我们的日常生活中,我们创造新的概念,随着概念在语义空间的任何区域迅速增长,我们也看到新的单词在那里出现,因为如果我们要使用它们,能够引用概念是必要的。我们也在“运行时”创造概念和新词。

有一个普遍的原则,有时被称为“软件工程的基本定理”,并归功于大卫惠勒:“我们可以通过引入一个额外的间接层来解决任何问题。”有时这句话会被修改,加上“除了过多间接引起的问题”。在这里,间接指的是两个事物是如何联系在一起的:直接,或者通过一个中间标签,或者一系列这样的标签。

我们在这里看到的灵活性来自于间接性:我们不是将一个对象(比如一个名为 lion 的变量)连接到我们可以调用这个对象的方法(比如 roareat 等等),而是将这个对象连接到一个中间抽象(比如 animal ),然后连接到这些方法。这样,我们可以通过单个中介将几个对象连接到这些方法,并且改变中介的特性是影响许多变量的一种廉价方式。这种添加单词、名称或符号的好处的概念在安迪·克拉克的论文 Magic Words 中得到了呼应,他在论文中指出了单词可以增强我们计算能力的几种方式,包括基于其他概念构建概念的能力。

4。今天耐心等待 AI

最近的三项人工智能进展之所以超过了它们的前辈,是因为它们推迟了某些选择。

从 W2V 到 Elmo 和 BERT

所谓的“语义嵌入”将单词映射到向量空间中的点,将相似的单词映射到附近的点。直到几年前,最先进的系统还在使用上下文无关的嵌入:它将单词 jaguar 的每个实例映射到同一点。尽管一个是动物,另一个是汽车,但每个句子中的美洲虎都接收到相同的向量:“美洲虎幼崽咕噜咕噜”和“美洲虎经销商咕噜咕噜”。

ELMo 是最近推出的一个提供上下文嵌入的 NLP 系统,它更有耐心。它一直等到在句子中看到这个单词,才产生一个向量。因此,这两个捷豹将获得不同的表现。W2V 将所有的美洲虎折叠成相同的表示,心照不宣地忽略了各种美洲虎之间的“无关紧要的差异”——动物、汽车、吉他、战斗机、阿兹特克战士、杰克逊维尔的足球运动员等等——而 ELMo 跳过了这种急切的折叠。

如果我们相信 NLP 基准,ELMo 和它的继任者 BERT 在各种各样的任务上表现得非常好。

从香草深度学习到 AutoML

普通的深度学习项目从精确定位要使用的架构开始。架构的选择是一个早期的决定,还有几个超参数的设置。现在,通过参数网格搜索,甚至通过模型空间的搜索,我们可以推迟这样的决定。

从启发式计算机象棋到 AlphaZero

深度学习的早期承诺之一是学习功能。无人监管的方法,如自动编码器,是承诺的乌托邦,将把我们从手动识别特征和手动调整权重中解放出来,通过允许“数据自己说话”,提供最稳健的权重集。特征工程是昂贵的和繁重的,并且需要技巧,如果有成千上万的问题我们想要解决,为每一个设计特征是行不通的。

现在最好的“传统”国际象棋系统是 Stockfish。它利用启发式方法来评估棋盘位置:它评估每个位置对白棋的有利程度,以厘泊为单位,领先 100 厘泊相当于拥有一个额外的棋子。为了评估一个位置,它会检查一些方面,如物质优势,兵的发展,国王的安全,两个主教是否幸存,打开的文件,一个骑士是否在前哨,等等——有数百个组成部分。在许多世纪的游戏中,人类玩家已经认识到这些方面的重要性。

Stockfish 是一个非常强大的玩家。它与中村光对弈,后者是 FIDE 国际象棋比赛中闪电战和快速棋类最高级别的棋手。电脑玩的时候有一个障碍:它在缺了一个棋子的情况下下黑棋,但却打败了人类冠军。

尽管它很强大,但在 2017 年,一个更先进更强大的 Stockfish 版本严重输给了谷歌的 AlphaZero。AlphaZero 没有从启发式规则开始,而是使用神经网络作为评估函数。人们可以把手工调整的试探法列表看作是急切的——对重要问题的早期决定。相比之下,AlphaZero 将重要的事情推迟到以后选择,从而使游戏更加灵活,更好地适应它在训练中探索的国际象棋位置的空间区域。

这些耐心的方法结出了果实,但这些(和其他深度学习解决方案)有一个共同的热切核心,我们接下来将讨论这个核心。

5。今日 AI 急切

让我们暂停一下,考虑一下前面讨论过的这些系统表现出的耐心:编程语言 Perl ( 3)、ELMo、AutoML 和 AlphaZero ( 5)。每一个都取代了系统中看似内在的东西,由于这种内在的东西在整个系统中是一致的,因此必须在一开始就决定。这些不可侵犯的单色外观被一种色彩丰富的拼布所取代,其选择可能会被推迟。Perl 不同意语法是固定的,或者整个程序用一种语法编写,或者只有一种最好的方法来表示对象和方法分派的工作方式。被认真对待的 Perl 的座右铭贯穿了它的设计:“有不止一种方法可以做到”,缩写为 TIMTOWDI,拉里·沃尔的 Twitter 昵称是@TimToady。AutoML 不相信网络的形状是固定的(因此我们不必在任何工作开始之前决定形状),AlphaZero 不相信一个单一的象棋位置评估函数(因此可以跳过选择),ELMo 不相信对某个单词的所有实例使用相同的向量。

从优秀的老式人工智能到现代深度学习系统,人工智能系统已经做出了急切的决定,这些决定被硬编码到他们的程序中。这些不胜枚举,我仅列举几个。

热切选择的表征和语义原子主义

有意义的原子可以结合起来形成,或者一个人被引导去相信,任何和所有的意义。我最早接触 AI 的一个领域是罗杰·尚克(Roger Schank)的“概念依赖”(Conceptual Dependency)系统,该系统试图用少量的原语(如 PTRANS(物理运动)、MTRANS(信息的运动)和 ATRANS(抽象转移,如给予)来表示所有的意义,包括完整的故事。那么,这是一个不到 100 个有意义原子的清单。在更大的范围内,今天的 WSD 系统倾向于也是意义的库存,并且每个术语有一组固定的含义。他们可能会为某个术语列出 4 个意义,而为另一个术语列出 10 个意义,但通常每个术语都有一个固定的集合,并且该集合的成员是离散的。另一个中等大小的感官库存是 WordNet。如今,也有免费的基础和知识图。

人类的概念不是这样工作的,将几个原子结合到我们所拥有的感官的细微层次中。我很熟悉“太阳底下没有新东西”这句话,以及所有思想都是先前思想的混合物或类似的说法,但新概念可以而且确实会产生。这是如何发生的将是另一篇文章的主题,重点是亚瑟·库斯勒、迈克尔·阿加尔、吉勒·福康尼耶和马克·特纳等人的想法。

当像 WordNet 这样的系统被用作人工智能系统的目标输出时,我们已经对可能的含义集做出了早期的决定。更糟糕的是,这些意义不符合人类的意义,人类的意义显示出灰色和等级隶属关系的阴影,以及在适当的时候通过隐喻、转喻或类比延伸意义的显著能力。

一组有限的意义意味着有限数量的歧视,许多有意义的边界被抹去。

监督与强化:固定损失函数还是固定效用函数

人们的一生,甚至一个小时,都不会有固定的损失函数。我们的目标变化很快,有些受饥渴等因素的影响,有些受吸引我们注意力的事情的影响,有时我们只关注正在进行的任务中的一个子问题。随着目标的改变,成功的标准也会改变。

我没有在训练中替换损失函数的建议,但我不认为应该只有一个。

固定输出类

我把我认为 NLP 中最大的问题留到最后:期望输出的固定和有限的范围。许多任务是分类任务,实际上是问“输入属于这三个类中的哪一个?”。具体的任务可能是“将句子分类为正确的情感,可以是这四种中的一种”或者唯一稍微开放一点的“在输入句子中找到一个双关语(顺便说一句,在 WordNet 中是双关语)”。

为什么我认为这些限制是急切的,为什么我们会变得脆弱?考虑将产品评论分为两类的任务,正面的负面的,想象你已经训练了一个系统来处理这个问题。但是由于负面并不是一个铁板一块的类别,它实际上是由许多重叠的原因形成的,这些原因使评论变得糟糕:也许产品很糟糕,也许卖家不知何故搞砸了,很粗鲁,等等,这根本不会反映在产品上。系统没有压力分别表示否定的这两个子类——这两个之间的表示会崩溃。在一个一切都是积极或消极的世界里,消极的子类之间的区别无关紧要。消除这些区别会使系统概括得很糟糕,并阻止它学习抽象概念,例如“如果一个评论在一个维度上是正面的,但在另一个维度上是负面的,我们就称之为正面的。”

我能坚持下去

上面的例子仅仅触及了表面。我们还没有讨论我的导师道格拉斯·霍夫施塔特(Douglas Hofstadter)在认知的计算模型方面的工作,他在那里展示了认知和识别是如何相互交织、相互依存的,这是一个论点,即表征不应该是先验固定的。例如,当我们着手一个研究项目时,我们可能甚至不知道我们应该向自己提出的精确问题,而要测量的精确数量只有随着时间的推移才会变得清楚。同样,这篇博文一开始是一个非常简单的想法,经过六次重大修改,抛弃了许多文本,杀死了许多宠儿,它达到了目前的形式,与我想象的相去甚远。

如果我们希望我们的计算机最终具有创造力并能够深刻理解,我们还有很长的路要走,而这段旅程将需要许多层面来解开我们目前认为是港口甚至是固体陆地的锚。

布鲁克林九九遇上数据科学

原文:https://towardsdatascience.com/brooklyn-nine-nine-meets-data-science-d846a901e12c?source=collection_archive---------24-----------------------

探索布鲁克林九九的试播集的 Seaborn 可视化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这份工作(数据科学家)正在活生生地吞噬我。我不能再呼吸了。这些年来我一直想做个好人,戴白帽子的人。我没有变得像他们一样…我就是他们——杰克·佩拉尔塔,飞行员

我最近疯狂地看了网飞的一个名为的节目,我真的很喜欢。当我急切地等待下一季的发布时,我认为对《T4》试播集进行探索性的数据分析和情感分析会很有趣。

我在网上找到了脚本,并将文本提取为 CSV 文件格式。您可以在我的 Github 资源库中找到本文的所有代码。

我们开始吧!

试播里哪个角色台词最多?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Of course, Jake has the most lines

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image of Jake Peralta, played by Andy Samberg

考虑到杰克·佩拉尔塔是我们的主要主角和主角,他在该剧的试播集里拥有最多台词是有道理的。

接下来,我们将探索并可视化这一集的单词分布。

试播中哪些人物平均用词最多**?**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Gina… What does this mean?

非常有趣…虽然 Gina 的台词比 Jake 少,但当她有机会说话时,她平均使用更多的单词。

试播中哪些人物使用最多的词语*?***

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们已经很好地理解了单词在试验中的分布,我们可以继续下一步了。我们应该清理我们的文本,看看我们的角色在对话中是否使用了有意义的词语。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image of Gina Linetti, played Chelsea Peretti

clean过程包括:

  • 标记和降低文本
  • 删除标点符号
  • 删除字母数字字符
  • *移除停用字词(不提供意义的常用字词,如’*、或’ a’ )

每个字符的总字数与干净字数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有意思。即使采用我们的clean流程,吉娜平均仍在使用更多的单词。

她的秘密是什么?

我们应该通过探索情感分析来更深入地研究文本分析。情感分析是一种非常流行的文本分析方法,用于确定文本中单词的态度或情感。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image of Captain Raymond Holt, played by Andre Braugher

一些流行的情感分析工具包括:

  • 维德情绪
  • AFINN 词典
  • 文本 Blob

有关情感分析的更多信息,请查看下面的链接:

** [## 情感和情绪分析:NLP - KDnuggets 实践指南

情感分析被广泛使用,特别是作为任何领域的社交媒体分析的一部分,无论是商业,还是文化

www.kdnuggets.com](https://www.kdnuggets.com/2018/08/emotion-sentiment-analysis-practitioners-guide-nlp-5.html)

试播中普遍情绪如何?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们人物台词的感悟是什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后一步,我们现在可以深入单词本身。我们来看看杰克、吉娜和霍尔特船长使用的最常见的词语。

杰克最常用的单词是什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

吉娜最常说的话是什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

霍尔特最常用的词是什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

耶,我们完成了!如果你喜欢这个,请随时查看我下面的参考资料。

参考资料:

【飞行员】布鲁克林九九。2013 年 9 月 17 日。电视。

[## 如何用 Python 清理机器学习的文本

你不能直接从原始文本去拟合机器学习或深度学习模型。你必须清理你的文字…

machinelearningmastery.com](https://machinelearningmastery.com/clean-text-machine-learning-python/) [## 水平条形图- seaborn 0.9.0 文档

编辑描述

seaborn.pydata.org](https://seaborn.pydata.org/examples/horizontal_barplot.html) [## 飞行员成绩单

我们从杰克·佩拉尔塔走出汽车开始。我们听到了他的画外音,当他跳过一些磁带,走向…

brooklyn99.fandom.com](https://brooklyn99.fandom.com/wiki/Pilot_Transcript) [## 非常简单的 Python 脚本,用于从故事中提取最常见的单词

人们经常需要快速检查和绘制像故事这样的大型文本文件中最常用的单词。怎么做?

towardsdatascience.com](/very-simple-python-script-for-extracting-most-common-words-from-a-story-1e3570d0b9d0)**

分类问题中变量选择的强力技术

原文:https://towardsdatascience.com/brute-force-variable-selection-techniques-for-classification-problems-5bca328977e5?source=collection_archive---------7-----------------------

变量选择是建立准确可靠的预测模型的重要一步,需要大量的创造力、直觉和经验。你一定看到过数百篇讨论变量选择技术的文章,其中很多都是关于理解数据,从统计学的角度感受数据。检查哪些变量具有低方差,哪些变量彼此之间以及与目标变量之间高度相关,等等。所有这些都是有用的技术,除非您遇到一个包含大约 20k 个变量的数据集,而没有全面的元数据!我以数据科学家的身份为一家大型汽车公司工作,并试图使用 ADAS(自动驾驶辅助系统)生成的内部信号建立一个模型。这些信号通常包括不同的速度、加速度、与被检测物体的距离、制动踏板状态和系统的许多状态变量。

现在,我有许多需要预测建模的用例,但我们将考虑其中一个,以便我们可以更好地关联。ADAS 有一个碰撞警告系统,每当它检测到可能与附近的物体发生碰撞时,就会发出警告。该警告通常是正确的或真实的,但有时它给出错误的警告,这对驾驶员来说是不方便的。我们的目标是建立一个模型,可以预测碰撞警告是否是假的。让我们不要被问题所左右,把注意力集中在数据上。我们的目标变量是二元的,我们有大约 20,000 个变量,包括连续变量、分类变量和离散变量。

因此,基于我们的需求,我们的变量选择技术将有两个方向——我们需要能够向最终用户详细解释我们的模型,并陈述我们的模型所基于的变量吗?还是我们只想得到最大的准确性?如果是前者,我们需要根据变量的预测能力或对目标变量的影响来筛选变量。

点双列相关

如果目标变量是二元的,点双列相关是选择变量的一个好方法。点双列相关用于测量一个连续变量和一个二分变量之间的关联强度和方向。这是皮尔逊积差相关的一个特例,适用于有两个连续变量的情况,而在这种情况下,其中一个变量是名义二进制变量。和其他相关系数一样,点双列的范围从 0 到 1,其中 0 表示没有关系,1 表示完全关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们用目标变量计算每个连续变量的系数,然后根据阈值系数(例如 0.5)选择最高的高度相关变量。使用这个,我能够从我的数据集中的大约 15,000 个变量中过滤出 50 个变量。

卡方

下一项技术是卡方检验——用于检验两个事件的独立性。如果给定两个事件的数据集,我们可以得到观察到的计数和预期的计数,这个测试测量两个计数相互之间的偏差。卡方统计通常用于测试分类变量之间的关系。卡方检验的无效假设是总体中的分类变量之间不存在关系。你可以在这里阅读更多关于如何进行测试的信息:https://www . statistics solutions . com/using-chi-square-statistic-in-research。所以,我不会深入测试的细节,但这个想法是使用测试过滤独立的分类变量。

特性差异

另一种用于过滤掉不会给我们的模型增加价值的变量的技术是方差阈值方法,该方法移除方差不满足某个阈值的所有特征。该方法可以在上述任何方法之前使用,作为一个起点,并且与目标变量没有太大关系。通常,它会移除所有零方差特征,这意味着所有样本中具有相同值的所有特征。

特征重要性

我们可以使用基于树的分类器模型的特征重要性特征来获得每个特征相对于目标变量的重要性:

我们可以基于特征重要性选择前 n 个特征,这对于我们可能想要使用的任何分类算法都会给出好的结果。

线性判别分析

接下来,让我们看看一些转换技术,在这些技术中,我们不能保留原始变量,但可以获得更高的精度。LDA 和 PCA 是两种这样的技术,尽管已知 PCA 在许多情况下表现良好,但我们将主要关注 LDA 及其应用。但是首先,让我们快速看一下 LDA 和 PCA 之间的一些主要区别:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当类别标签已知时,线性判别分析在多类别分类任务中通常优于 PCA。然而,在某些情况下,PCA 表现得更好。这通常是当每个类的样本量相对较小时。一个很好的例子是图像识别技术中使用的分类精度之间的比较。线性判别分析 Python 有助于将高维数据集降低到低维空间。我们的目标是做到这一点,同时在类之间有一个体面的分离,并减少资源和计算成本。我们可以使用 LDA 类的解释方差比属性来决定最适合我们需要的组件数量。看一看:

如果我们对保留原始特征集不感兴趣,LDA 提供了一种很好的方法来将我们的数据转换到选定数量的新维度空间,这是分类算法的更好输入。

现在,让我们把我们为非转换情况讨论的所有技术放在一起,作为代码形式的一系列步骤:

函数 variable_selection 返回一个新的 dataframe,其中只包含通过各种过滤器后选择的列。应该仔细选择函数的输入,例如方差阈值、点双列系数阈值、卡方统计阈值和特征重要性阈值,以获得期望的输出。

请注意,这只是一个变量选择的框架,而本质上在很大程度上是一个手动练习。我写这段代码是因为我觉得很多过程可以自动化或半自动来节省时间。我的建议是使用这个函数作为起点,对特定的数据集和问题陈述进行任何您认为合适的更改,然后使用它。

祝你好运!

布宜诺斯艾利斯自行车道:让我们一起去兜风

原文:https://towardsdatascience.com/buenos-aires-bicycle-lanes-ii-1a40b13ccc25?source=collection_archive---------18-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Riding a bike in BA. Isn’t the Women’s Bridge beautiful?

谁不喜欢在公园里骑自行车呢?布宜诺斯艾利斯人(“porteos”,这个词指的是我们的港口),显然喜欢它。

在本文中,我们将继续进行一些分析,目的是识别和理解隐藏在布宜诺斯艾利斯 Ecobicis 公开数据中的社会模式。

该数据集提供了自行车站点的地理定位和以下方面的数据点:

  • 谁(当然是匿名的)骑了一辆自行车。
  • 他们从哪里拿走的,又放在哪里。
  • 确切的时间。
  • 全程旅行。

我的好朋友费德·卡塔拉诺谈了很多关于这个数据集的特征,并展示了一些不错的统计分布。它是西班牙语的,但你不需要懂这种语言就能欣赏美丽的情节。

他关注的是上下班的人。我们要分析一些隐藏在数据中的社会聚类。也就是说,我们将尝试检测一起使用自行车的人群。

考虑到这个目标,我们应该将数据限制在人们将自行车归还给他们从那里拿走的同一个站点的事件上。通过这种方式,我们清理了数据,只考虑与人们骑自行车出行相关的事件。

一个人去兜风很有趣,但我也很喜欢朋友和我一起去。为了检查其他人是否同意我的观点,我们建立了一个图表,其中两个用户共享一个链接,当且仅当他们中的至少一个人在几乎相同的时间从同一个车站骑走了一辆自行车,并一起归还(也是到同一个车站)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5%的事件是人们把自行车归还到他们把自行车拿走的地方。那些事件。90%的人是一个人去的。但是另外 10%的人是一起去的。由此,模式开始出现。

网络具有幂律度分布,就像大多数真实世界的网络一样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The person with 15 different friends to go for a ride with must be having a great time!

我们还可以检查人们的年龄与友谊的关系。不出所料,年龄相同的人更有可能一起出去玩:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Heat map for relations based on age and gender.

也许你希望看到家庭,但不幸的是,孩子们很难为这项服务创建用户。在我们的实验中,最小的人是 15 岁。

我们从图表中可以观察到的是 40 岁以上的男女关系的强烈模式,这是同性友谊所缺乏的。也许,由于异性性关系在统计上比其他性关系更丰富,我们所看到的是已婚夫妇在一起的快乐?我打赌我们是!

团体

如果我们把网络分成相连的部分,结果是——正如你可能怀疑的那样——许多人只是成对外出,但也有许多团体!我们找到了 300 个 5 人以上的小组。连通分量的大小分布也遵循幂律,最大的组是大小为 195 的异常值。这是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Bicycle users and friendships.

  • 节点颜色等于性别,红色为雌性,蓝色为雄性。
  • 节点大小与年龄成正比。
  • 边缘宽度与共享的行程量成比例。

查看我的笔记本(即将推出)了解其他小组。好,再来一个:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

That pair are really good friends!

然而,连接组件并不是检测社区的好方法(也许我会在另一篇文章中详细讨论)。

检测社区的一个好方法是卢万算法。对于这个项目,我们使用了简单有效的 Python 实现。结果如下——你可以想象成群结队的骑自行车者在布宜诺斯艾利斯各处享受他们的闲暇时光:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Cyclists’ communities — social interaction is everywhere

这些社区在地理上是如何分布的?它们是如何随着时间进化的?更多将在新的职位。

附录

最后一件事。费德里科是社会科学家,我是数学家。但是,为了这个项目,我们交换了帽子。如你所见,他处理了数据集的大部分数字分析——他在这方面很棒——而我处理了隐藏的社会模式。

永远不要害怕换帽子,只是去兜风。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Credit: gastonroel

通过机器学习构建免佣金的 Algo 交易机器人季度收益报告[完整指南]

原文:https://towardsdatascience.com/build-a-commission-free-algo-trading-bot-by-machine-learning-quarterly-earnings-reports-full-b414e5d759e8?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简介

以下是一个完整的指南,将教你如何创建自己的算法交易机器人,它将根据美国上市公司提交给 SEC 的季度收益报告(10-Q)进行交易。我们将涵盖从下载历史 10-Q 文件,清理文本,并建立您的机器学习模型的一切。ML 模型的训练集使用来自这些历史归档的文本和归档后的第二天价格动作作为特征标签。

然后,我们下载并清理每天的 10-Q 文件,并使用我们训练有素的模型对每个文件进行预测。根据预测,我们将自动在该公司的股票代码上执行免佣金交易。

属国

0.我们的项目代码:

https://github . com/plator solutions/quarterly-income-machine-learning-algo

1.基础依赖:Python 3.4,Pandas,BeautifulSoup,yfinance,fuzzywuzzy,ntlk

对于这样的项目,Python 一直是我首选的语言,原因与许多其他人选择它的原因相同——快速的开发、可读的语法和大量可用于大量任务的高质量库。

Pandas 是任何数据科学项目存储、操作和分析数据框架表中的数据的经典之作。

yfinance 是一个 python 库,用于从 Yahoo Finance 检索股票价格。

fuzzywuzzy 为创建我们的 10-Q 差异提供了模糊文本相似性结果。

Ntlk 允许我们根据句子拆分 10-Q 报告的文本。

2.羊驼免佣金交易 API(https://alpaca.markets/)

我研究并尝试了几个股票经纪人的解决方案,这些经纪人声称为散户交易者提供 API。羊驼是最容易使用的,文档最清晰。(我与他们没有关系)我测试的其他经纪人有:

互动经纪人

在网上搜索,这些家伙似乎有一个在该领域的“黄金标准”的声誉。然而,在测试他们的软件时,它真的让大多数零售交易 API 的可悲状态大开眼界。事实证明,他们没有你所期望的实际 API,而是一个令人震惊的古老桌面应用程序,供你安装,然后库自动控制桌面应用程序。

他们的文件杂乱而复杂。在几次尝试运行他们的示例代码和尝试一些测试交易后,我可以说,将 IB 作为 algo 交易机器人的稳定部分是可能的,但这本身就是一个重要的项目。

TD Ameritrade 思考或游泳

很明显,ToS 的 API 比互动经纪人的更新更好用。然而,同样明显的是,这不是一个成熟的解决方案。虽然我确实让它工作了,但是甚至使用 API 的初始认证过程也很奇怪,并且需要在各种论坛上找到的未记录的信息才能让它工作。交易执行 API 本身看起来很容易使用,但是关于它们的书面文档非常少。

3.谷歌云 AutoML 自然语言

由于其作为搜索引擎的业务性质,Google 自然在 ML 自然语言处理方面拥有丰富的经验和投资。在尝试了其他几种 ML 技术和解决方案后,Google 的商业解决方案产生了模型的最佳准确性,同时提供了一种足够容易使用的解决方案,该项目不会陷入对各种 ML 算法进行无休止的手动调整和测试的学术练习中。

测试了其他 ML 库:最初我尝试了以下 ML 库,并从归档文本中创建了一个二元模型包用作特性集:h2o.ai、Keras、auto-sklearn 和 AWS Sagemaker。

这种技术的一个大挑战是,对来自二元模型包的文本进行矢量化,会为训练集的每个数据点创建大量的特征。有各种技术可用于处理这种情况,但预测质量可能会或不会有不同程度的损失。

4.Python-edgar :一个整洁的小 Python 库,用于批量下载 SEC 历史文件列表(https://github.com/edouardswiac/python-edgar/)

第一步。下载历史 10-Q SEC 文件列表

为此,我们将从 https://github.com/edouardswiac/python-edgar/下载并安装 python-edgar

使用 run.py 将目录切换到文件夹,并使用以下命令下载历史归档:

>python run . py-y 2010

我选择下载近 10 年的数据(从 2010 年开始)来构建我们的 ML 模型。您可以一直下载到 1993 年,也可以用不同的年份参数少下载一些。

完成后,我们可以将结果编译成一个主文件:

>猫。tsv > master.tsv*

现在使用 quarterly-earnings-machine-learning-algo/download _ raw _ html . py 下载我们刚刚创建的索引中列出的所有原始 html 10-Q 文件:

>python download _ raw _ html . py path/to/master . tsv

这将需要大量的时间来运行,因为它将从 SEC.gov 网站下载许多 GB 的数据。每个文件平均有几十兆的数据。当它完成时,我们将有一个文件夹"./filings" 包含所有文件的原始 html。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

文件名的格式为: _ _ _ 。超文本标记语言

第二步。清理锉屑

我们将运行 quarterly-earnings-machine-learning-algo 项目中的以下命令,将每个文件中的 html 清理为准备好的文本:

>python filing _ cleaner . py

这将使用上一步中创建的“归档”目录中的 html 文件,并输出到包含已清理文本文件的“清理 _ 归档”目录中。

这将进行以下清理,为自然语言处理准备文本:

  1. 条带 HTML
  2. 删除通常包含定量财务数据的大部分数字表格
  3. 移除链接
  4. 去除空白
  5. 删除有限数量的停用字词(特定日期、数字等)
  6. 规范化文本

这也将根据美国证券交易委员会用来识别公司的 CIK 号码来查找交易的股票代码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

文件名的格式为: _ _ _ _ 。文本文件(textfile)

第三步。下载财务数据

在这一步中,我们下载公司在每次 SEC 备案后当天的股票市场开盘价,然后下载备案后两天的开盘价。我们使用这个百分比价格变化作为我们想要为我们的机器学习数据点预测的目标标签。最初,我创建了一个算法,以开盘价和当天收盘价进行交易。然而,在实时交易中使用它需要一个日内交易账户,对于一些读者来说,25,000 美元的最低账户可能是遥不可及的。

此外,我们将使用的 SEC 备案文件限制在收盘后提交的文件。在盘后发布季度收益是大多数公司普遍采用的做法。我们有大量的数据点可以使用,所以我们将把它限制在这些数据点上,因为对市场时段发布的季度收益使用价格行为会在我们的数据样本中产生异质性。

如果在运行这个命令之前您还没有安装 yfinance,请使用 pip 来安装它。

>python add _ financial . py

它从上一步创建的“cleaned_filings”目录中读取带有股票代码的文件名,并输出 financials.pkl,这是一个 Pandas 数据帧,包含每个文件的所有次日价格变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第四步。从公司最近的 10 季度报告中产生每个季度收益的文本增量

在这一步中,我们将获取每一份清理过的季度收益报告,并逐句对该公司上一份 10-Q 文件进行模糊区分,以删除也出现在他们上一份文件中的文本。这是一个重要的步骤,它去除了大量多余的文本,并创建了一个清晰的报告,说明该公司自上一季度收益报告以来增加了什么。

这为我们建立机器学习模型创造了一个非常干净的信号,因为只有公司认为足够重要的信息才会添加到他们的最新文件中,才会成为我们训练数据的一部分。

记得在运行之前使用 pip 安装 nltk 和 fuzzywuzzy 依赖项。

>python diff _ cleaned _ filings . py

该命令将从“cleaned_filings”目录中获取已清理的文本文件,并输出“whole_file_diffs”目录中每个已清理文本文件的文本增量。

第五步。准备我们的训练数据的 CSV 以上传到 Cloud AutoML 自然语言

现在,我们将整理 10-Q diffs(培训功能),并将其与第二天的价格变化(培训标签)一起编译成 CSV。我们将通过在每个第 20 百分位将价格变化分成 5 个时段来创建谨慎的培训标签。因此,我们的 0 桶将有底部的 20%(最显著的价格下降),我们的 4 桶将有顶部的 20%(最显著的价格上升)。

python cloudml _ prepare _ local _ CSV . py

这将在当前目录中输出一个名为“training_data.csv”的文件,准备上传到 Google。

第六步。在 Cloud AutoML 自然语言上上传、训练和评估我们的 ML 模型

如果你还没有谷歌云平台账户,你可以在这里注册:【https://cloud.google.com/free/

一旦你有了一个帐户,我们就可以在这里访问 Cloud AutoML 自然语言控制台:https://console.cloud.google.com/natural-language/dashboard

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,我们将点击“自动情感分析”。虽然我们不是在分析文本的情绪,但本质上,我们将使用股票价格反应作为季度收益报告“情绪”的衡量标准,将此建模为情绪分析问题。

单击“new dataset”,选择情绪分析,并将最大情绪得分设置为 4,因为我们有在上一步中创建的 5%价格变化时段。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们现在将导入在上一步中创建的 CSV 文件,然后单击 import。导入完成后,您将收到一封电子邮件。然后,您可以返回到仪表板,并单击培训。如果你有任何问题,你可以参考谷歌的文件在这里:https://cloud . Google . com/natural-language/automl/sensation/docs/

该模型将需要几个小时的训练,当它完成时,我们会收到一封电子邮件。然后我们可以分析结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里我们看到了模型的混淆矩阵。如果你不确定如何解释,你可以谷歌一下“困惑矩阵”。我们可以看到,我们实现了近 30%的准确率和召回率,而由于我们有 5 个存储桶,随机机会应该是 20%。那比随机几率好 50%!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们看一下情绪得分为 0 的结果(记住这是价格变化最负的 20 个百分点),我们会看到我们得到了最好的准确性。当我们使用我们的模型预测季度收益报告将产生最剧烈的价格下跌时,我们将有 35.63%的时间是正确的。这比随机机会好了 75%以上!

我们用这个桶做得最好是有道理的。它告诉我们,当一份季度收益报告包含某些负面指标语言时,它将更可预见地产生戏剧性的股价下跌。这符合一句古老的谚语“卖新闻”。

第七步。下载今天的 10-Q 文件,进行在线预测,并开始交易!

注册羊驼经纪人账户开始交易:【https://alpaca.markets/

他们允许你快速方便地在纸币账户上交易,而不需要输入任何银行信息,这非常好。我们可以用这个纸币账户开始。

注册后,您需要从仪表板中检索您的 API 密钥:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们还需要从谷歌控制台检索我们的模型名称。在与上一步相同的仪表板上,单击您训练过的机器学习模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转到“测试和使用”选项卡。单击“使用您的自定义模型”下的“Python”选项卡。记下上面用黑色圈出的型号名称。

我们现在可以使用以下命令行参数运行我们的命令:

> python MakeTrades.py <羊驼 API 密钥 ID > <羊驼秘钥> <谷歌型号名称>

该命令将:

1.从美国证券交易委员会网站https://www.sec.gov/cgi-bin/current?q1=0&Q2 = 1&Q3 =下载最新的上市日 10-Q 文件

这应该只在交易日晚些时候运行,因为这是当天所有文件都可用的时候。如果你想早点运行它,它会给你昨天的文件。

2.清理每一份 10-Q 文件,并与公司最近的 10-Q 文件进行比较,就像我们在培训准备中所做的那样。如果该公司在过去 3 个月左右没有 10-Q 文件,它将跳过它。

3.提交文本 delta,用我们的 ML 模型做一个在线预测。

4.如果我们的模型返回的预测值为 0(它预测的是最剧烈的价格下跌类别),那么它将使用羊驼 API 为该股票下一个空头订单,该订单将在第二天的开市时执行。

你应该记得在持有空头头寸一天后平仓。如果你愿意,你可以为此写一个脚本。您还可以将该命令与 cron 作业一起安排在每个交易日结束时运行,以实现完全自动化。

第八步。翻转它来生活,让金钱滚滚而来

希望,这个指南是有价值的,可以被使用,并扩大到现场交易盈利。如果有什么不清楚或者你需要任何帮助,请联系我。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

原载:【https://www.platorsolutions.com/】T21

我可以为贵公司的任何项目提供软件咨询。点击此处免费预约初诊:https://www.platorsolutions.com/book-online

为快乐和利润建立一个公司 R 包

原文:https://towardsdatascience.com/build-a-corporate-r-package-for-pleasure-and-profit-78b73ce4ff4b?source=collection_archive---------12-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的经济正在进行“大重组”。这是我们所知道的正在发生的事情的官方名称:最好的正在上升到顶端,而平庸的正在沉入底部。这是马太效应在起作用。

在 Brynjolfsson 和 McAfee 2011 年的著作与机器赛跑中,他们详细描述了这种新经济将如何有利于那些拥有技能或资本来对接和投资深度学习和机器人等新技术的人,这些新技术正变得越来越普遍。

Cal Newport 的深度作品概述了在新经济中蓬勃发展的两个核心能力:

1.能够快速掌握难的东西

2.能够在质量和速度方面达到精英水平。这种对速度的需求(抱歉)将是我们关注的重点。

**不要重复自己(干)**是软件开发中众所周知的格言,大多数 R 程序员都遵循这个规则,构建函数以避免重复代码。但是你多久会:

  • 在不同的分析中引用相同的数据集
  • 创建到数据库的相同 ODBC 连接
  • 在 ggplot 中修补相同的颜色和主题
  • 从同一模板生成降价文档

诸如此类?注意到模式了吗?“同”字撒在每一个要点里。我嗅到了干敷的机会!

如果你像我一样在公司或学术机构工作,你可能会经常做这些事情。我将向你展示如何将所有这些任务打包成一个极简的 R 包来节省你的时间,正如我们所知,这是你在新经济中取得成功的关键之一。

工具

首先做一些基础工作。如果你用 R 工作,我假设你用的是 RStudio,这是必须的。我用的是 Windows 10 机器上的 R 版本 3.5.1(啊,美国公司…)。请注意,我们将要开发的包是极简主义的,这是一种说我们要抄近路来制造最小可行产品的方式。我们不会深入讨论文档和依赖项,因为我们在新包中需要的包很可能已经在您的本地机器上了。

创建空的包项目

我们将为咨询公司 Ketchbrook Analytics 创建一个包,这是一家来自康涅狄格州的精品店,他们比任何人都更了解自己的道路。

打开 RStudio 并在新目录中创建一个项目:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

选择 R 包并命名。我叫我的凯彻。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RStudio 现在将使用示例“hello”函数启动一个新会话。看来我们准备好进入正题了。

自定义功能

让我们从向我们的包中添加一个函数开始。Ketchbrook 的一项常见任务是将客户数据与市场区域或足迹的轮廓对应起来。我们可以很容易地把它包装成一个简单的函数。

创建一个新的 R 文件,并将其命名为 ketchR.R。我们将把所有的函数放在这里。

所以我们所做的是创建一个函数,利用 tigris 包来获取我们足迹中各州的 shapefiles。然后,该函数将这些状态合并成一个连续的多边形,这样我们就可以很容易地使用传单、ggmap 等来覆盖它。

尝试你的新功能:

你会看到一个漂亮的西部小海岸:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您可以在包中添加的自定义函数的种类没有限制。机器学习算法,客户细分,无论你想要什么,你都可以在你的包中放入一个易于访问的功能。

数据集

让我们继续我们的地理空间爱好。分公司或商店级别的分析在分布于一个大的地理区域的公司中很常见。在我们的例子中,Ketchbrook 的客户从提华纳到西雅图有八家分行。每次我们需要引用这些位置时,不用手动存储和导入 CSV 或 R 数据文件,我们可以简单地将数据集保存到我们的包中。

为了将数据集添加到我们的包中,我们首先需要通过读取 csv 或从其他地方获取数据集,将它放入我们的本地环境中。我只是从本地电脑上读取了一个 csv 文件:

这是数据集的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,我们必须将这些数据放在一个非常具体的地方,否则我们的包将无法找到它。就像当我妻子把洗碗机藏起来的时候,我被迫不情愿地把脏盘子放在柜台上。

首先,在当前目录中创建一个名为“data”的文件夹顺便说一句,你的目录现在应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

额外好处:使用 RStudio 中的终端功能可以轻松创建目录:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们需要将这个分支数据集作为。RData 文件:

现在,我们建造

让我们测试一下这个包,因为我们很有可能没有搞砸任何事情。当我们构建这个包时,我们正在把它编译成我们所知道的实际的包。在 RStudio 中,这非常简单。导航到“构建”选项卡,然后单击“安装并重启”

如果您已经完成了,您应该不会看到任何错误,但是如果您确实看到了错误,请尝试更新您的本地包。

现在,我们应该能够直接调用我们的包并使用我们的分支数据集:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

酷,这很有效。现在让我们用传单快速绘制我们的分支,以确保 footprint_poly()有效:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

尼利斯。

数据库连接

数据科学中最常见的任务之一是从数据库中提取数据。假设 Ketchbrook 将数据存储在 SQL 服务器中。与其手动复制和粘贴连接脚本或依赖 RStudio 会话来缓存连接字符串,不如让我们直接创建一个该死的函数。

在这里,我们构建了一个函数,让我们可以输入任何我们想要针对这个 SQL Server 的查询。该函数创建连接,每次都提示我们输入密码(我们不在代码中存储密码……),并在连接完成时关闭连接。

让我们更进一步。很多时候,您可能会使用一个通用的 SELECT *查询来利用 dplyr 进行真正的数据管理。在这种情况下,更简单的方法就是创建一个这样的函数。

让我们创建另一个从客户那里提取 SELECT *的函数。

啊,当我开始在自己的实践中使用它时,仅这一项就为我每周节省了 15 分钟。仔细想想你可能经常复制和粘贴的任何一段代码——那是你的函数包的候选者。

品牌 ggplot 可视化

好了,现在我们进入了最重要的部分,真正节省时间的部分,我们一揽子计划中给分析师留下深刻印象的部分。我们将使产生一致的数据可视化变得容易,这些数据可视化用定制的颜色和主题来反映公司的形象。

虽然我个人认为绿色调色板是有史以来最好的配色方案,但它并不一定符合凯奇布鲁克公司的调色板。所以让我们自己制作一套函数来使用凯奇布鲁克的调色板是一种‘懒惰’的方式。(非常感谢这篇 Simon Jackson 的伟大文章)。

获取颜色

让我们直接从他们的网站上下载颜色。我们可以使用 Chrome 插件 Colorzilla 来获取我们需要的颜色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将这些十六进制颜色代码粘贴到这个块中,就像这样:

这将给我们一个很好的调色板,对于分类数据有足够不同的颜色,对于连续数据有足够相似的颜色。为此,我们甚至可以将它分成两个单独的子调色板:

创建函数

我不打算一行一行地介绍这些函数;如果您有任何问题,请发邮件至 bradley . lindblad[at]Gmail[dot]com 联系我,在 Github repo 上创建一个问题。以下是完整的代码片段:

让我们来测试一下:

生产:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很好。在 Ketchbrook 的视觉效果中使用一致的颜色将有助于为他们的品牌建立知名度,并在市场上更快地得到认可。

降价模板

现在我们已经更快地获取数据并绘制数据,最后一步是交流我们的分析结果。同样,我们希望能够快速、一致地做到这一点。定制降价模板已准备就绪。

我发现这一部分是最难做对的,因为所有的东西都需要在文件结构中的正确位置,所以请密切关注。(大部分功劳归于切斯特·伊斯梅的这篇文章。)

1.创建框架目录

这将创建一个嵌套目录来保存我们的模板。Rmd 和。yaml 文件。您的目录中应该有一个名为“ketchbrookTemplate”的新文件夹:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.创建骨架。中矢状直径之比

接下来,我们创建一个新的 RMarkdown 文件:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这将为我们提供一个基本的 RMarkdown 文件,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,让我们修改模板来满足我们的需求。首先,我会用一个我觉得很适合我的主题来替换顶部的内容,你可以随意撕掉它:

我喜欢遵循分析模板,因此这是结合我的基本 EDA 模板的首要问题:

将这个文件保存在 skeleton 文件夹中,我们就完成了。

3.创建 yaml 文件

接下来,我们需要创建一个 yaml 文件。只需在 RStudio 中创建一个名为“template.yaml”的新文本文档,并保存它,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

重新构建包并打开一个新的 RMarkdown 文档,选择“From Template ”,您应该会看到您的新模板可用:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

太好了。您现在可以编织 html pretty,并得到如下甜美的输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果遇到问题,请确保您的文件结构与此匹配:

 ├───inst
│   └───rmarkdown
│       └───templates
│           └───ketchbrookTemplate
│               │   template.yaml
│               │
│               └───skeleton
│                       skeleton.nb.html
│                       skeleton.Rmd

下一步是什么?

因此,我们基本上做了一个炸弹包,让你做任何事情都快一点,好一点:拉数据,引用公共数据,创建数据和交流结果。

从这里,您可以在本地使用这个包,或者将它推送到一个远程 Github 仓库,在您的团队中传播代码。

这个包的完整代码可以在为它设立的 Github repo 获得。随意分叉,让它成为自己的。我不擅长说再见,所以我要走了。

我可以在有限的基础上提供数据科学咨询。通过 gmail[dot]com 联系我

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

感谢阅读!

在 AWS 上构建一个数据管道来收集 PUBG 数据

原文:https://towardsdatascience.com/build-a-data-pipeline-on-aws-to-collect-pubg-data-5b222ba4e2cc?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Quinten de Graaf on Unsplash

我在与 PUBG 相关的 Kaggle 竞赛中开始了这个项目,目标是根据一些比赛结束时的统计数据(如比赛中跑的距离等)来预测比赛中的球员排名。我想了解数据源(看看是否有一些故意遗漏的统计数据/信息),并尝试亚马逊的一些服务,如 AWS Glue 和 Athena,以在 AWS 中建立一个数据管道。

在这篇文章中,我将解释:

  • 什么是 PUBG,游戏的原理等等
  • 项目的方法
  • 数据的收集和清理

PUBG 的描述

PUBG 是一款名为 battle royale 的视频游戏类型的旗舰之一(首先也是最受欢迎的之一),主要是 100 名玩家(或多或少)被丢在一个岛上,没有装备,他们必须通过收集材料,武器,装备和车辆在这个岛上生存。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了促使人们去战斗,随着游戏的进行,可用的区域变得越来越小,所以这种形式促使人们互相战斗,因为最终只能有一个幸存者。有两个非常受欢迎的游戏支持这一运动,它们是 PUBG 和堡垒之夜,它们可以在所有可能的平台上使用(主机上的 PUBG 不好),现在你可以看到所有其他受欢迎的游戏(使命召唤,战场)都想在里面添加自己的皇家战役模式,但让我们诚实地说,堡垒之夜正在击败所有人(查看谷歌趋势 PUBG VS Fornite)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我对这类游戏的看法是,原则很酷,你可以在游戏过程中建立一些紧张的令人惊讶的情况,但我认为你不能出售(全价)一个只是皇家战役的游戏。Epic 对堡垒之夜很聪明,因为他们通过提出一个免费的独立应用程序,将一个制作时间长且销售情况不好的项目变成了一个非常有利可图的项目,该应用程序使用的资产与原始游戏相同,但只专注于皇家战役(我希望有想法的人能加薪)。

让我们看看数据收集的项目。

项目方法

这个项目背后的想法是:建立一个系统,从 PUBG 公司提供的 API 收集数据清洁数据,使所有的数据可用,而不是下载我的机器上的一切

为了建立管道,我决定使用 AWS,因为与微软、谷歌等相比,我更喜欢他们的服务,但我确信同样的系统也可以在这些平台上建立。

为了完成任务,我决定使用以下服务:

  • EC2 实例运行一台机器来进行收集
  • S3 存储收集到的数据并进行处理
  • 粘合使数据清晰可用
  • Athena 是 S3 数据存储的接口

这是 AWS 上不同步骤的流程部署的高级视图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们来详细看看过程。

从 PUBG API 收集数据

PUBG 公司已经建立了一个非常好的开放的 API,有多个端点开放不同的数据源。为了简单起见,您可以访问与以下内容相关的数据:

  • 由他们的帐户 id 定义的 PUBG 播放器
  • 由其 matchid 定义的匹配

有来自不同地区(美洲、欧洲和亚洲)的多个平台(pc、xbox 和 ps4)的数据。在这篇文章中,我将重点介绍 PC 平台和北美地区。这个 API 有多个端点,但让我们把重点放在:

  • 样本端点:提供对每天更新的一些 matchid 的访问
  • 匹配端点:给出了匹配的细节,比如最终结果,更重要的是下载事件压缩包的链接。

你可以找到一个仓库,里面有我构建的收集、清理和发送数据的函数。这个笔记本能让你深入了解收集到的数据。有三种类型的数据:

  • 结束比赛统计数据,它们存储在 s3 存储桶的“文件夹”中
  • 存储在另一个文件夹中的完整事件
  • 存储在单独文件夹中的分解事件

关于事件包,API 上有多个可用的事件,有一个模式包含这些事件的详细信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我计划每天在 EC2 实例上运行一个脚本,该脚本触发了从样本中获取新数据,并将其存储在正确的文件夹和 day 文件夹中。

为了获得一般信息,比赛的细节被收集到一个 dynamodb 表中(比如人数,地图名称等)。

当你存储数据时,我能给你的一些建议是:

  • 妥善保存。gz 文件
  • 明确分隔符、空格符和引号符
  • 删除索引
  • 对于 Dynamodb,将浮点数据转换为十进制数据

这是关于我如何收集数据的简单概述,现在让我们看看云部分。

用胶水抓取 S3 和 Dynamodb 中的数据数据(这么多名字掉线)

AWS glue setup 仪表板分为两个部分,分别是数据目录部分和 ETL 部分(我将重点介绍仪表板的上部)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们首先关注数据目录。

数据目录和爬虫部分

在这一部分中,您可以找到一个 database 选项卡,它包含所有数据库和您用 Glue 创建的相关表。为了这个项目,我创建了我的第一个数据库。有趣的部分是爬虫标签,在那里你可以设置爬虫在 S3 导航,Dynamodb 和 AWS 的一些其他服务(像 RDS)。在上图中,有一个我为这个项目创建的所有爬虫的列表。让我们看看爬虫里面有什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,当您设置爬虫时,需要:

  • 为你的爬虫取一个名字
  • 定义数据源,在本例中,我将关注三个事件和我的 Dynamodb 表
  • 为您的 crawler 定义一个 AWS 角色,使其能够访问所有要被爬网的数据源
  • 定义爬虫的执行频率,我决定让它每周运行一次
  • 定义爬虫的输出

我强烈建议激活复选框,用表中的元数据更新所有新的和现有的分区,以避免在读取数据期间出现一些分区问题,如果你不像我一样控制你正在接收的内容。

瞧,你只需要从 AWS Glue 的主页运行爬虫程序,现在你就可以通过 Athena 中的爬虫程序访问你的数据摘录(SQL 方式访问数据)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是数据仍然很原始,所以我决定给爬虫添加一个新的层来清理数据和添加一些信息。

ETL 部分

对于 ETL 部分,这是管道的数据处理部分。我本来可以在数据到达 S3 存储桶时对其进行分析,但是我注意到一些记录不太好(比如说损坏了),所以我想为这些数据应用一个转换状态:

  • 删除损坏的记录(带有错误的 matchid 格式)
  • 使用 dynamodb 表中收集的匹配细节进行连接(并在之前进行爬网)
  • 计算事件和比赛开始之间的时间差(秒和分)
  • 在事件函数中进行一些简单的字符串操作(比如清除武器的名称)

这里有代码的插图,你可以在中找到这段代码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我尝试了代码方法,但有一个选项 ETL 配置,您可以有更多的图表方法来进行数据操作,因为我想使用 rdd 映射和 spark 的数据帧,我决定不使用此功能,但我做了一些简单的测试,它工作得很好。所以现在只需要构建一个爬虫来用 ETL 部分生成的新数据更新数据目录。

在下面的模式中,有 AWS Glue 中操作的时间表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在让我们在 AWS 上做一个快速测试,从 web 界面请求流程数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些数据可以从 Athena 访问,但你可以连接 AWS quicksight,它有更像 Tableau 的体验(我不喜欢的是,我不喜欢所有这些对我来说太黑的 BI 工具),更重要的是,你可以从笔记本上访问这些数据(在中有一个 python 环境的副本)。

这是对我从 PUBG API 收集数据的数据管道的描述,系统每天收集大约 1000 个匹配,这不是一个很大的数量,但我想从小的开始。

我是一个好人,你可以在这个 kaggle 数据集 中找到我为这个项目建立的表格的摘录(这是 2019 年 1 月 27 日的数据摘录)。

我希望你喜欢阅读,如果你有任何意见,请不要犹豫。

原载于 2019 年 2 月 1 日 the-odd-dataguy.com

用你的机器学习模型构建一个 Docker 容器

原文:https://towardsdatascience.com/build-a-docker-container-with-your-machine-learning-model-3cf906f5e07e?source=collection_archive---------3-----------------------

Docker 初学者模板脚本完全指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Chris Leipelt on Unsplash

作为一名数据科学家,我没有太多的软件工程经验,但是我肯定听过很多关于容器的很棒的评论。我听说过与传统虚拟机相比,它们是多么的轻量级,它们在确保您的代码有一个安全一致的环境方面有多好,以及我的 devops 工作如何节省,以便您可以专注于您的代码。

然而,当我试图将我自己的模型分类时,我很快意识到它并不那么直观。这一点也不像在 EC2 引导脚本前面加上RUN那么简单。我发现不一致和不可预测的行为经常发生,学习调试一个新工具可能会令人沮丧。

所有这些促使我创建了这篇文章,其中包含了将 Python 中的 ML 模型分解到 Docker 容器所需的所有代码片段。我将指导您安装您需要的所有 pip 包,并构建您的第一个容器映像。在这篇文章的第二部分的中,我们将设置所有必要的 AWS 环境,并在这个系列的第三部分也是最后一部分开始批处理容器。

免责声明 1:我这里说的模型是单个实例上的批处理作业,不是有 API 端点的 web 服务,不是分布式并行作业。如果您遵循本教程,将代码放入容器的整个过程应该不会超过 25 分钟。

免责声明 2:如果这是你第一次阅读关于容器的文章,这篇文章可能不会提供理解容器如何工作的必要信息,我强烈建议你在继续之前查阅一些在线教程。

先决条件

创建 Dockerfile 文件👷🏻‍♀️

要将您的代码放入容器,您需要创建一个Dockerfile,它告诉 Docker 您在应用程序中需要什么。

一个Dockerfile是一个文本文档,它包含了用户可以在命令行上调用的所有命令来组合一个图像。

(您可以从Dockerfiledocker-compose.yml构建 Docker 映像。如果你的代码可以被重构为一个多容器 Docker 应用程序,你可能想看看docker compose,但是现在一个Dockerfile应该足够了。)

Docker 映像从基础映像开始,由只读层构建而成,每一层都添加了一些依赖关系。最后,您告诉容器如何触发您的模型。

minimal Dockerfile for a Python application

在上面的 other 文件中,我从基本的 Python 3.6 伸展映像开始,apt-get更新了系统库,安装了一些makebuild的东西,检查了我的 Python 和pip版本以确保它们是好的,建立了我的工作目录,将requirements.txt复制到容器中,pip 在其中安装了所有的库,最后将所有其他代码文件复制到容器中,列出了所有文件以确保我需要的都在那里,并触发了我的入口点main.py文件。

如果你的代码文件夹结构是这样的,这个Dockerfile应该对你有用。

- app-name
     |-- src
          |-- main.py
          |-- other_module.py
     |-- requirements.txt
     |-- Dockerfile

如果您的代码还没有一个main.py或 shell 脚本来触发模型训练/推理,那么您可能想要首先重构您的代码。还记得用pipreqs path/to/project将库依赖关系冻结到一个requirements.txt文件中。我推荐使用pipreqs而不是pip freeze,因为当你运行pip freeze > requirements.txt时,它会输出该环境中所有已安装的包,而pipreqs只给你这个项目实际导入的包。(如果还没有pip(3) install pipreqs安装pipreqs

如果你的代码已经有了一个入口点,你需要做的就是把<app- name>改成你的应用程序的名字,我们就可以把它构建成一个图像了。

有很多让Dockerfile变得更小更高效的最佳实践,但是大多数都超出了本文的范围。但是,您可能需要注意以下几点:

1.1 使用 Python 拉伸作为基础图像

人们说不要从一个普通的 Ubuntu 镜像开始,而是使用一个官方的基础镜像,比如 Alpine Python。Alpine Python 是一个基于 Alpine Linux 的非常小的 Python Docker 映像,比默认的 docker python 映像小得多,但仍然拥有最常见的 Python 项目所需的一切。但是我发现使用它非常困难,尤其是在安装包的时候。

另一方面,Ubuntu 基础映像将提供更可预测的行为,但是您需要自己安装所有 Python 的东西。

所以我建议你从 Python 3.6 stretch 开始,这是基于 Debian 9(又名 stretch)的官方 Python 镜像。Python stretch 附带了 Python 环境和 pip 安装,并且是最新的,如果你选择 Ubuntu,你需要弄清楚如何安装所有这些。

1.2 仅安装您需要的东西

复制和粘贴一些网上发布的Dockerfile模板也很有诱惑力,尤其是如果这是你的第一个 Docker 项目。但是建议只安装你实际需要的东西来控制图像的大小。如果你看到其他人安装了一大堆makebuild的东西,试着先不要包括它们,看看你的容器是否能工作。较小的映像通常意味着构建和部署速度更快。(你应该试试我上面的极简主义模板的另一个原因!)

同样为了保持图像尽可能的简洁,使用.dockerignore,它的工作方式和.gitignore完全一样,忽略那些不会影响模型的文件。

an example .dockerignore file

1.3 在代码前增加requirements.txt

在您的Dockerfile中,总是在复制源代码之前添加您的requirements.txt文件。这样,当您更改代码并重新构建容器时,Docker 将重用缓存层,直到安装了包,而不是在每次构建时执行pip install命令,即使库依赖关系从未更改。没有人愿意仅仅因为你在代码中添加了一个空行就多等几分钟。

如果你有兴趣了解更多关于Dockerfile的信息,在附录 I 中有我们使用的一些基本命令的快速总结。或者你可以在这里查看 Dockerfile 文档。

现在可以随意跳到第 2 步,用刚刚创建的Dockerfile构建一个容器。

第二步——用你的 docker 文件建立一个图像👩🏻‍🍳

准备好Dockerfile之后,就该构建容器映像了。docker build根据Dockerfile中给出的指令创建图像。你所需要做的就是给你的图像一个名字(一个可选的版本标签)。

$ docker build -t IMAGE_NAME:TAG .
$ # or
$ docker build -t USERNAME/IMAGE_NAME:TAG .

这两个命令的唯一区别是图像名称前是否有一个USERNAME/。映像名称由斜杠分隔的名称组成,通常前缀是注册表主机名。USERNAME/IMAGE_NAME一般不是指定图像名称的强制格式。但是亚马逊 ECR 存储库中的图像确实遵循完整的REGISTRY/REPOSITORY:TAG命名约定。比如aws_account_id.dkr.ecr.region.amazonaws.com/my-web-app:latest

上面的命令中发生了一些事情。

首先,我们告诉 Docker 守护进程获取当前目录中的Dockerfile(这就是末尾的.所做的)。

接下来,我们告诉 Docker 守护进程构建图像并给它指定标签。标记对我来说一直很困惑。通常标记图像就像给它一个别名。这与给现有图像指定另一个名称来引用它是一样的。这有助于区分 Docker 图像的版本。

指定标记名不是强制性的。在没有指定特定标签的情况下运行构建时,:latest标签是默认标签。因此,如果您想维护一个好的版本历史,建议您在每次构建之后都明确地标记您的映像。

$ docker build -t USERNAME/IMAGE_NAME .
$ docker tag USERNAME/IMAGE_NAME USERNAME/IMAGE_NAME:1.0
$ ...
$ docker build -t USERNAME/IMAGE_NAME .
$ docker tag USERNAME/IMAGE_NAME USERNAME/IMAGE_NAME:2.0
$ ...

您可以在使用docker build -t USERNAME/IMAGE_NAME:TAG .构建图像时标记图像,或者在构建后像docker tag SOURCE_IMAGE:TAG TARGET_IMAGE:TAG一样显式标记图像。

现在,如果您运行docker images,您应该看到本地存在一个图像,它的存储库是USERNAME/IMAGE_NAME,标签是TAG

$ docker images

我还建议您此时在本地机器上测试您的容器,以确保一切正常。

$ docker run USERNAEM/IMAGE_NAME:TAG

请随意查看附录 II,获取一些基本 Docker CLI 命令的快速摘要,或在此处查看官方文档。

恭喜你!您只是将您的模型放入一个可以在任何安装了 Docker 的地方运行的容器中。请加入我这篇文章的第二部分,来配置您的 AWS 环境,以满足调度批处理作业的先决条件。

附录 I — Dockerfile 命令👩🏻‍🏫

  • FROM启动Dockerfile。要求Dockerfile必须以FROM命令开始。图像是在层中创建的,这意味着您可以使用另一个图像作为您自己的基础图像。FROM命令定义了你的基础层。作为参数,它采用图像的名称。可选的,你可以添加维护者和镜像版本的 Docker Cloud 用户名,格式 username/imagename:version
  • RUN用于构建您正在创建的图像。对于每个RUN命令,Docker 将运行命令,然后创建一个新的图像层。这样,您可以轻松地将映像回滚到以前的状态。RUN指令的语法是将 shell 命令的全文放在RUN之后(例如RUN mkdir /user/local/foo)。这将在一个/bin/sh外壳中自动运行。您可以像这样定义一个不同的 shell:RUN /bin/bash -c 'mkdir /user/local/foo'
  • COPY将本地文件复制到容器中。
  • CMD定义启动时将在图像上运行的命令。与RUN不同,这不会为图像创建一个新层,而只是运行命令。每个 Dockerfile/Image 只能有一个CMD。如果您需要运行多个命令,最好的方法是让CMD运行一个脚本。CMD要求你告诉它在哪里运行命令,不像RUN
  • EXPOSE为镜像用户创建一个提示,提示哪些端口提供服务。它包含在可通过docker inspect <container-id>检索的信息中。
  • 注意:EXPOSE命令实际上并没有让主机访问任何端口!相反,这需要在使用docker run时通过-p标志发布端口。
  • 将您的映像推送到私有或云注册表。

附录 II — Docker CLI 命令👩🏻‍🏫

一些基本的 Docker CLI 命令包括:

  • docker build从 Dockerfile 文件构建图像
  • docker images显示机器上的所有 Docker 图像
  • 启动一个容器并在其中运行命令
  • docker run选项:
  • -p指定主机和 Docker 容器中的端口
  • -it打开交互式控制台
  • -d以守护模式启动容器(在后台运行)
  • -e设置环境变量
  • docker ps显示所有正在运行的容器
  • docker rmi删除一个或多个图像
  • docker rm移除一个或多个容器
  • docker kill杀死一个或多个运行中的容器
  • docker tag用别名标记图像,以便以后参考
  • docker login登录您的 Docker 注册表

关于作者

我是一名机器学习工程师,除了技术教程之外,我还撰写关于生产力和自我发展的文章。我在 7 月 4 日参观了黄石公园,这就是封面图片。

让我们建立一个时尚-MNIST 有线电视新闻网,PyTorch 风格

原文:https://towardsdatascience.com/build-a-fashion-mnist-cnn-pytorch-style-efb297e22582?source=collection_archive---------2-----------------------

如何使用 Google Colab 和 TensorBoard 从头开始构建 PyTorch ML 项目的逐行指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当谈到技术中的框架时,一件有趣的事情是,从一开始,似乎总是有各种各样的选择。但随着时间的推移,竞争将演变为只剩下两个强有力的竞争者。典型的例子有“PC vs Mac”、“iOS vs Android”、“React.js vs Vue.js”等。而现在,我们在机器学习方面有了‘py torch vs tensor flow’。

由谷歌支持的 TensorFlow 无疑是这方面的领跑者。它于 2015 年作为开源机器学习框架发布,迅速获得了大量关注和接受,特别是在生产准备和部署非常关键的行业。 PyTorch 由脸书在 2017 年推出,但由于其动态计算图和’python 式’风格,很快获得了从业者和研究人员的喜爱。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image from The Gradient

The Gradient 最近的研究表明,PyTorch 在研究人员中表现出色,TensorFlow 在业界占据主导地位:

2019 年,ML 框架的战争还有两个主要竞争者:PyTorch 和 TensorFlow。我的分析表明,研究人员正在放弃 TensorFlow,成群结队地涌向 PyTorch。与此同时,在行业中,Tensorflow 是目前的首选平台,但这种情况可能不会持续太久。— 坡度

最近发布的 PyTorch 1.3 引入了 PyTorch Mobile、quantization 和其他好东西,它们都朝着缩小差距的正确方向前进。如果你对神经网络基础有点熟悉,但想尝试 PyTorch 作为一种不同的风格,那么请继续阅读。我将尝试解释如何使用 PyTorch 为时尚-MNIST 数据集从头构建一个卷积神经网络分类器。如果你没有强大的本地环境,这里的代码可以在 Google Colab 和 Tensor Board 上使用。事不宜迟,我们开始吧。您可以在下面找到 Google Colab 笔记本和 GitHub 链接:

📙谷歌 Colab 笔记本

👽 GitHub

导入

首先,让我们导入必要的模块。

# import standard PyTorch modules
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter # TensorBoard support

# import torchvision module to handle image manipulation
import torchvision
import torchvision.transforms as transforms

# calculate train time, writing train data to files etc.
import time
import pandas as pd
import json
from IPython.display import clear_output

torch.set_printoptions(linewidth=120)
torch.set_grad_enabled(True)     # On by default, leave it here for clarity

PyTorch 模块非常简单。

火炬

torch是主模块,包含了张量计算所需的所有东西。您可以单独使用张量计算来构建一个全功能的神经网络,但这不是本文要讨论的内容。我们将利用更强大、更方便的torch.nntorch.optimtorchvision类来快速构建我们的 CNN。对于那些有兴趣知道如何从“从抓到开始做这件事的人,请访问这个奇妙的 PyTorch 官方 tutoria l 作者杰瑞米·霍华德

torch.nn 和 torch.nn 功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Alphacolor on Unsplash

torch.nn模块提供了许多构建神经网络的类和函数。你可以把它想象成神经网络的基本构件:模型、各种层、激活函数、参数类等等。它允许我们像组装乐高玩具一样来建造模型。

火炬. optim

torch.optim提供所有优化器,如 SGD、ADAM 等。,这样就不用从头开始写了。

火炬视觉

torchvision包含大量流行的数据集、模型架构和计算机视觉的常见图像转换。我们从中获取时尚 MNIST 数据集,并使用其变换。

摘要记录器(张量板)

SummaryWriter使 PyTorch 能够为张量板生成报告。我们将使用 Tensor Board 查看我们的训练数据,比较结果并获得直觉。张量板曾经是 TensorFlow 相对于 PyTorch 的最大优势,但是现在从 v1.2 开始 PyTorch 正式支持张量板。

我们还引入了其他一些实用模块,如timejsonpandas等。

资料组

torchvision已经有了时尚 MNIST 数据集。如果你不熟悉时尚 MNIST 数据集:

Fashion-MNIST是一个由 Zalando 的文章图像组成的数据集,由 60,000 个示例的训练集和 10,000 个示例的测试集组成。每个示例都是 28x28 灰度图像,与 10 个类别的标签相关联。我们打算将Fashion-MNIST作为原始 MNIST 数据集的直接替代,用于机器学习算法的基准测试。它共享训练和测试分割的相同图像大小和结构。— 来自 Github

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fashion MNIST Dataset — From GitHub

# Use standard FashionMNIST dataset
train_set = torchvision.datasets.FashionMNIST(
    root = './data/FashionMNIST',
    train = True,
    download = True,
    transform = transforms.Compose([
        transforms.ToTensor()                                 
    ])
)

这个不需要过多解释。我们指定根目录来存储数据集,抓取训练数据,如果本地机器上没有,允许下载它,然后应用transforms.ToTensor将图像转换成张量,这样我们就可以在我们的网络中直接使用它。数据集存储在名为train_set.dataset类中

网络

在 PyTorch 中构建实际的神经网络既有趣又简单。我假设你对卷积神经网络的工作原理有一些基本的概念。如果没有,可以参考 deeplizard 的这个视频:

时尚 MNIST 只有 28x28 px 大小,所以我们实际上不需要非常复杂的网络。我们可以像这样建立一个简单的 CNN:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们有两个卷积层,每个卷积层有 5x5 个内核。在每个卷积层之后,我们有一个跨度为 2 的最大池层。这允许我们从图像中提取必要的特征。然后我们展平张量,将它们放入密集层,通过多层感知器(MLP)来执行我们的 10 个类别的分类任务。

现在我们已经清楚了网络的结构,让我们看看如何使用 PyTorch 来构建它:

# Build the neural network, expand on top of nn.Module
class Network(nn.Module):
  def __init__(self):
    super().__init__()

    # define layers
    self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
    self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)

    self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
    self.fc2 = nn.Linear(in_features=120, out_features=60)
    self.out = nn.Linear(in_features=60, out_features=10)

  # define forward function
  def forward(self, t):
    # conv 1
    t = self.conv1(t)
    t = F.relu(t)
    t = F.max_pool2d(t, kernel_size=2, stride=2)

    # conv 2
    t = self.conv2(t)
    t = F.relu(t)
    t = F.max_pool2d(t, kernel_size=2, stride=2)

    # fc1
    t = t.reshape(-1, 12*4*4)
    t = self.fc1(t)
    t = F.relu(t)

    # fc2
    t = self.fc2(t)
    t = F.relu(t)

    # output
    t = self.out(t)
    # don't need softmax here since we'll use cross-entropy as activation.

    return t

首先 PyTorch 中所有的网络类都是在基类上扩展的:nn.Module。它包含了所有的基础知识:权重、偏差、正向方法以及一些实用属性和方法,如.parameters().zero_grad(),我们也将使用它们。

我们的网络结构在__init__ dunder 函数中定义。

def __init__(self): 
  super().__init__()   # define layers 
  self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
  self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)
  self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
  self.fc2 = nn.Linear(in_features=120, out_features=60)
  self.out = nn.Linear(in_features=60, out_features=10)

nn.Conv2dnn.Linear是在torch.nn模块中定义的两个标准 PyTorch 层。这些都是不言自明的。需要注意的一点是,我们在这里只定义了实际的层。激活和最大池化操作包含在下面解释的转发功能中。

# define forward function  
def forward(self, t):  
  # conv 1  
  t = self.conv1(t)  
  t = F.relu(t)  
  t = F.max_pool2d(t, kernel_size=2, stride=2)     # conv 2  
  t = self.conv2(t)   
  t = F.relu(t)  
  t = F.max_pool2d(t, kernel_size=2, stride=2)     # fc1   
  t = t.reshape(-1, 12*4*4)  
  t = self.fc1(t)  
  t = F.relu(t)     # fc2  
  t = self.fc2(t)  
  t = F.relu(t)    # output  
  t = self.out(t)    # don't need softmax here since we'll use cross-entropy as activation.   
  return t

一旦定义了层,我们就可以使用层本身来计算每一层的转发结果,加上激活函数(ReLu)和最大池操作,我们可以很容易地编写我们的网络的转发函数,如上所述。注意,在fc1(完全连接第 1 层)上,我们使用 PyTorch 的张量运算t.reshape来展平张量,这样它就可以传递给后面的致密层。此外,我们没有在输出层添加 softmax 激活函数,因为 PyTorch 的 CrossEntropy 函数会为我们处理这个问题。

超参数

通常情况下,我们可以只手动选择一组超参数,并用它们做一些实验。在这个例子中,我们想通过引入一些结构化来做更多的事情。我们将构建一个系统来生成不同的超参数组合,并使用它们来执行训练“运行”。每次“运行”使用一组超参数组合。将每次跑步的训练数据/结果导出到 Tensor Board,以便我们可以直接比较并查看哪个超参数集表现最佳。

我们将所有的超参数存储在一个 有序指令 中:

# put all hyper params into a OrderedDict, easily expandable
params = OrderedDict(
    lr = [.01, .001],
    batch_size = [100, 1000],
    shuffle = [True, False]
)
epochs = 3

lr:学习率。我们想为我们的模型尝试 0.01 和 0.001。

batch_size:批量,加速训练过程。我们会用 100 和 1000。

shuffle : Shuffle toggle,我们是否在训练前洗牌。

一旦参数下降。我们使用两个助手类:RunBuilderRunManager来管理我们的超参数和训练过程。

运行生成器

RunBuilder的主要目的是提供一个静态方法get_runs。它将 OrderedDict(其中存储了所有超参数)作为一个参数,并生成一个名为元组 Run,每个run元素代表超参数的一种可能组合。这个命名元组稍后由训练循环使用。代码很容易理解。

# import modules to build RunBuilder and RunManager helper classes
from collections  import OrderedDict
from collections import namedtuple
from itertools import product

# Read in the hyper-parameters and return a Run namedtuple containing all the 
# combinations of hyper-parameters
class RunBuilder():
  @staticmethod
  def get_runs(params):

    Run = namedtuple('Run', params.keys())

    runs = []
    for v in product(*params.values()):
      runs.append(Run(*v))

    return runs

运行管理器

RunManager 类有四个主要目的。

  1. 计算并记录每个时期和运行的持续时间。
  2. 计算每个历元和运行的训练损失和准确度。
  3. 记录训练数据(如损耗、准确度、重量、梯度、计算图等)。)并运行,然后将它们导出到张量板以供进一步分析。
  4. 将所有训练结果保存在csvjson中,以备将来参考或提取 API。

如你所见,它帮助我们处理后勤工作,这对我们成功训练模型也很重要。让我们看看代码。这有点长,请原谅:

# Helper class, help track loss, accuracy, epoch time, run time, 
# hyper-parameters etc. Also record to TensorBoard and write into csv, json
class RunManager():
  def __init__(self):

    # tracking every epoch count, loss, accuracy, time
    self.epoch_count = 0
    self.epoch_loss = 0
    self.epoch_num_correct = 0
    self.epoch_start_time = None

    # tracking every run count, run data, hyper-params used, time
    self.run_params = None
    self.run_count = 0
    self.run_data = []
    self.run_start_time = None

    # record model, loader and TensorBoard 
    self.network = None
    self.loader = None
    self.tb = None

  # record the count, hyper-param, model, loader of each run
  # record sample images and network graph to TensorBoard  
  def begin_run(self, run, network, loader):

    self.run_start_time = time.time()

    self.run_params = run
    self.run_count += 1

    self.network = network
    self.loader = loader
    self.tb = SummaryWriter(comment=f'-{run}')

    images, labels = next(iter(self.loader))
    grid = torchvision.utils.make_grid(images)

    self.tb.add_image('images', grid)
    self.tb.add_graph(self.network, images)

  # when run ends, close TensorBoard, zero epoch count
  def end_run(self):
    self.tb.close()
    self.epoch_count = 0

  # zero epoch count, loss, accuracy, 
  def begin_epoch(self):
    self.epoch_start_time = time.time()

    self.epoch_count += 1
    self.epoch_loss = 0
    self.epoch_num_correct = 0

  # 
  def end_epoch(self):
    # calculate epoch duration and run duration(accumulate)
    epoch_duration = time.time() - self.epoch_start_time
    run_duration = time.time() - self.run_start_time

    # record epoch loss and accuracy
    loss = self.epoch_loss / len(self.loader.dataset)
    accuracy = self.epoch_num_correct / len(self.loader.dataset)

    # Record epoch loss and accuracy to TensorBoard 
    self.tb.add_scalar('Loss', loss, self.epoch_count)
    self.tb.add_scalar('Accuracy', accuracy, self.epoch_count)

    # Record params to TensorBoard
    for name, param in self.network.named_parameters():
      self.tb.add_histogram(name, param, self.epoch_count)
      self.tb.add_histogram(f'{name}.grad', param.grad, self.epoch_count)

    # Write into 'results' (OrderedDict) for all run related data
    results = OrderedDict()
    results["run"] = self.run_count
    results["epoch"] = self.epoch_count
    results["loss"] = loss
    results["accuracy"] = accuracy
    results["epoch duration"] = epoch_duration
    results["run duration"] = run_duration

    # Record hyper-params into 'results'
    for k,v in self.run_params._asdict().items(): results[k] = v
    self.run_data.append(results)
    df = pd.DataFrame.from_dict(self.run_data, orient = 'columns')

    # display epoch information and show progress
    clear_output(wait=True)
    display(df)

  # accumulate loss of batch into entire epoch loss
  def track_loss(self, loss):
    # multiply batch size so variety of batch sizes can be compared
    self.epoch_loss += loss.item() * self.loader.batch_size

  # accumulate number of corrects of batch into entire epoch num_correct
  def track_num_correct(self, preds, labels):
    self.epoch_num_correct += self._get_num_correct(preds, labels)

  @torch.no_grad()
  def _get_num_correct(self, preds, labels):
    return preds.argmax(dim=1).eq(labels).sum().item()

  # save end results of all runs into csv, json for further analysis
  def save(self, fileName):

    pd.DataFrame.from_dict(
        self.run_data, 
        orient = 'columns',
    ).to_csv(f'{fileName}.csv')

    with open(f'{fileName}.json', 'w', encoding='utf-8') as f:
      json.dump(self.run_data, f, ensure_ascii=False, indent=4)

**__init__**:初始化必要的属性,如计数、丢失、正确预测数、开始时间等。

**begin_run**:记录运行开始时间,以便当运行结束时,可以计算运行的持续时间。创建一个SummaryWriter对象来存储我们在运行过程中想要导出到张量板的所有内容。将网络图和样本图像写入SummaryWriter对象。

**end_run**:运行完成后,关闭 SummaryWriter 对象,并将历元计数重置为 0(准备下一次运行)。

**begin_epoch**:记录历元开始时间,以便在历元结束时计算历元持续时间。复位epoch_lossepoch_num_correct

这个函数是大多数事情发生的地方。当一个时期结束时,我们将计算时期持续时间和运行持续时间(直到这个时期,而不是最后的运行持续时间,除非是运行的最后一个时期)。我们将计算这个时期的总损耗和精确度,然后将损耗、精确度、权重/偏差、梯度导出到张量板中。为了便于在 Jupyter 笔记本中跟踪,我们还创建了一个 OrderedDict 对象results,并将我们所有的运行数据(损失、准确度、运行计数、历元计数、运行持续时间、历元持续时间、所有超参数)放入其中。然后我们将使用熊猫来读取它,并以整洁的表格格式显示出来。

**track_loss** **track_num_correct** **_get_num_correct**:这些是累计损失的效用函数,每批的正确预测数,以便以后计算历元损失和精度。

**save**:将所有运行数据(所有运行的results OrderedDict 对象列表)保存为csvjson格式,以便进一步分析或 API 访问。

这门课有很多东西要学。恭喜你走到这一步!最困难的部分已经过去了。从现在开始,一切都会变得有意义。

培养

终于,我们准备好进行一些训练了!在我们的RunBuilderRunManager课程的帮助下,培训过程变得轻而易举:

m = RunManager()

# get all runs from params using RunBuilder class
for run in RunBuilder.get_runs(params):

    # if params changes, following line of code should reflect the changes too
    network = Network()
    loader = torch.utils.data.DataLoader(train_set, batch_size = run.batch_size)
    optimizer = optim.Adam(network.parameters(), lr=run.lr)

    m.begin_run(run, network, loader)
    for epoch in range(epochs):

      m.begin_epoch()
      for batch in loader:

        images = batch[0]
        labels = batch[1]
        preds = network(images)
        loss = F.cross_entropy(preds, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        m.track_loss(loss)
        m.track_num_correct(preds, labels)

      m.end_epoch()
    m.end_run()

# when all runs are done, save results to files
m.save('results')

首先,我们使用RunBuilder创建超参数的迭代器,然后遍历每个超参数组合来执行我们的训练:

for run in RunBuilder.get_runs(params):

然后,我们从上面定义的Network类创建我们的network对象。network = Network()。这个network物体承载了我们需要训练的所有重量/偏差。

我们还需要创建一个DataLoader 对象。它是一个 PyTorch 类,保存我们的训练/验证/测试数据集,它将遍历数据集,并按指定的batch_size批量给我们训练数据。

loader = torch.utils.data.DataLoader(train_set, batch_size = run.batch_size)

之后,我们将使用torch.optim类创建一个优化器。optim类获取网络参数和学习率作为输入,将帮助我们逐步完成训练过程并更新梯度等。我们将使用 Adam 作为优化算法。

optimizer = optim.Adam(network.parameters(), lr=run.lr)

好的。现在我们已经创建了网络,准备好了数据加载器,选择了优化器。让我们开始训练吧!

我们将遍历所有我们想要训练的纪元(这里是 3 个),所以我们将所有东西都放在一个“纪元”循环中。我们还使用我们的RunManager类的begin_run方法来开始跟踪跑步训练数据。

m.begin_run(run, network, loader)    
for epoch in range(epochs):

对于每个时期,我们将遍历每批图像来进行训练。

m.begin_epoch()    
for batch in loader:              
  images = batch[0]      
  labels = batch[1]      
  preds = network(images)      
  loss = F.cross_entropy(preds, labels)

  optimizer.zero_grad()  
  loss.backward()      
  optimizer.step()

  m.track_loss(loss)      
  m.track_num_correct(preds, labels)

上面的代码是真正的训练发生的地方。我们从批处理中读入图像和标签,使用network类进行前向传播(还记得上面的forward方法吗?)并得到预测。通过预测,我们可以使用cross_entropy函数计算该批次的损失。一旦计算出损失,我们用.zero_grad()重置梯度(否则 PyTorch 会累积梯度,这不是我们想要的),使用loss.backward()方法进行一次反向传播,以计算权重/偏差的所有梯度。然后,我们使用上面定义的优化器来更新权重/偏差。现在网络已经为当前批次更新,我们将计算正确预测的损失和数量,并使用我们的RunManager类的track_losstrack_num_correct方法累积/跟踪它们。

一旦全部完成,我们将使用m.save('results')将结果保存在文件中。

笔记本中运行的输出如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

张量板

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image from Tensorboard.org

传感器板是一个 TensorFlow 可视化工具,现在 PyTorch 也支持它。我们已经努力将所有内容输出到。/runs '文件夹,Tensor Board 将在其中查找要使用的记录。我们现在需要做的只是启动张量板并进行检查。由于我在 Google Colab 上运行这个模型,我们将使用一个名为ngrok的服务来代理和访问我们在 Colab 虚拟机上运行的张量板。先安装ngrok :

!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip!unzip ngrok-stable-linux-amd64.zip

然后,指定我们要从中运行张量板的文件夹,并启动张量板 web 界面。/runs 是默认值):

LOG_DIR = './runs'get_ipython().system_raw('tensorboard --logdir {} --host 0.0.0.0 --port 6006 &'.format(LOG_DIR))

启动ngrok代理:

get_ipython().system_raw('./ngrok http 6006 &')

生成一个 URL,以便我们可以从 Jupyter 笔记本中访问我们的张量板:

! curl -s http://localhost:4040/api/tunnels | python3 -c \"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"

正如我们在下面看到的,TensorBoard 是一个非常方便的可视化工具,让我们可以深入了解我们的训练,并可以极大地帮助超参数调整过程。我们可以很容易地找出哪个超参数组件表现最好,然后用它来做我们真正的训练。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

正如你所看到的,PyTorch 作为一个机器学习框架是灵活的、强大的和富有表现力的。你只需要写 Python 代码。由于本文的主要重点是展示如何使用 PyTorch 构建一个卷积神经网络,并以结构化的方式对其进行训练,因此我没有完成整个训练时期,精度也不是最佳的。你可以自己试试,看看模型表现如何。

这篇文章很大程度上受到了 deeplizard 在 YouTube 上的 PyTorch 视频系列的启发。甚至大部分代码片段都是直接抄袭过来的。我想感谢他们的伟大内容,如果你觉得有必要深入研究,随时去看看,并订阅他们的频道。

觉得这篇文章有用?在 Medium 上关注我(李立伟)或者你可以在 Twitter @lymenlee 或者我的博客网站wayofnumbers.com上找到我。你也可以看看我下面最受欢迎的文章!

[## “这是 CS50”:开始数据科学教育的愉快方式

为什么 CS50 特别适合巩固你的软件工程基础

towardsdatascience.com](/this-is-cs50-a-pleasant-way-to-kick-off-your-data-science-education-d6075a6e761a) [## 一枚硬币的两面:杰瑞米·霍华德的 fast.ai vs 吴恩达的 deeplearning.ai

如何不通过同时参加 fast.ai 和 deeplearning.ai 课程来“过度适应”你的人工智能学习

towardsdatascience.com](/two-sides-of-the-same-coin-fast-ai-vs-deeplearning-ai-b67e9ec32133) [## 我完成了吴恩达的机器学习课程,感觉棒极了!

好的,坏的,美丽的

medium.com](https://medium.com/datadriveninvestor/thoughts-on-andrew-ngs-machine-learning-course-7724df76320f)

构建一个机器学习推荐器

原文:https://towardsdatascience.com/build-a-machine-learning-recommender-72be2a8f96ed?source=collection_archive---------8-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Background vector created by starline — www.freepik.com

用几行 Python 代码构建机器学习推荐器的快速入门指南

在这篇文章中,我将展示如何使用机器学习快速组装推荐器。我将使用 LightFM 推荐库训练一个预测模型,该库可以很好地扩展到 2000 万到 4000 万次交互的中小型数据集,并训练一个关于用户特征和项目特征的模型。然后,我将进一步介绍推荐系统的典型实现,并汇总单个用户的预测,为一个群体提供推荐。

关键定义

在深入研究代码之前,先快速回顾一下用来描述推荐系统机制的一些关键定义。

条目–这是评级或分数的内容(例如,一本书、一部电影等。)

标签 —这些是推荐器的可能的输出。(例如评级或分数)。我们会用带标签的项目来训练推荐器,也就是已经被用户评分过的项目。

交互–这是一个输入和相关输出值的列表,我们希望根据这些值来训练我们的推荐器。(例如,用户和项目参考以及相关评级。)

用户特征–这些值代表每个用户的不同特征、行为和属性(如年龄、位置、性别)。

物品特征–这些值代表物品的不同特征(如产品类别、颜色、尺寸)

我将使用的数据

我将使用 Goodbooks-10k 数据集来演示推荐器,可以从这里下载:http://www2.informatik.uni-freiburg.de/" " ~齐格勒/BX/BX-CSV-Dump.zip

Goodbooks-10K 数据集由三个文件组成:

BX-用户用户特征,具体为 user_id、年龄和位置。

BX-图书条目特征包括ISBN、Book_Author 等一堆特征。

BX-图书评级–用户给出的图书评级交互,特别是 user_id、ISBN 和评级。

导入库

首先,我们需要从 LightFM 库中导入一些库和一些库。

import numpy as np
from lightfm.data import Dataset
from lightfm import LightFM
from lightfm.evaluation import precision_at_k
from lightfm.evaluation import auc_score
from lightfm.cross_validation import random_train_test_split
from scipy.sparse import coo_matrix as sp

导入数据

我们将导入 GoodBooks-10K 数据,然后创建以下三个函数,以便在需要时获得数据的新副本。

#fetch the interactions data
def get_ratings():
return get_data()[0]#fetch the item features
def get_book_features():
return get_data()[1]#fetch the user features
def get_user_features():
return get_data()[2]

准备数据

为了使用 LightFM 训练模型,我们将提供以下内容:

[1] 交互作为一个 sparse . COO _ matrix–我们的交互将是 BX-图书-评级. csv 中提供的用户 ID 和 ISBN

[2] user_features 作为包含用户特征的可迭代字符串——我们将简单地包括 BX 用户. csv 中提供的年龄

[3] item_features 作为包含项目特性的可迭代字符串——我们将简单地包括 BX-Books.csv 中提供的图书作者

LightFM 有一个数据集构造器,它有许多方便的方法来准备好数据输入到模型中。由于我们希望在模型中包含用户和项目特征,因此准备数据将是一个两步过程。

步骤 1:创建特性映射

首先,我们在数据集对象上使用 fit()方法来创建 BX-图书-评级. csv 中的映射

dataset = Dataset()dataset.fit((x[‘User-ID’] for x in get_ratings()), (x[‘ISBN’] for x in get_ratings()))num_users, num_items = dataset.interactions_shape()
print(‘Num users: {}, num_items {}.’.format(num_users, num_items))

我们使用 dataset.fit_partial()方法为 user_features 和 model_features 创建特性映射。

dataset.fit_partial(users=(x[‘User-ID’] for x in get_user_features()), items=(x[‘ISBN’] for x in get_book_features()), item_features=(x[‘Book-Author’] for x in get_book_features()), user_features=(x[‘Age’] for x in get_user_features()))

第二步:建立交互、用户特征和物品特征矩阵

其次,可以在 dataset 对象上调用 build_interactions()方法来构建交互矩阵。

(interactions, weights) = dataset.build_interactions(((x[‘User-ID’], x[‘ISBN’]) for x in get_ratings()))

我们在数据集对象上调用 build_item_features()和 build_user_features()方法来构建 item_features 和 user_features。这些函数根据 LightFM 的要求返回 sparse.coo_matrix 类型的对象。

item_features = dataset.build_item_features(((x[‘ISBN’], [x[‘Book-Author’]]) for x in get_book_features()))user_features = dataset.build_user_features(((x[‘User-ID’], [x[‘Age’]]) for x in get_user_features()))

指定型号

为了训练推荐器,我们将使用 LightFM 库中提供的加权近似等级成对(WARP)损失函数。WARP 处理(用户,正项,负项)三元组。

LightFM 对 WARP 算法提供了以下解释:

[1]对于给定的(用户,正项目对),从所有剩余项目中随机抽取一个负项目。计算两项的预测值;如果负项的预测值超过了正项的预测值加上一个差值,则执行梯度更新,将正项的等级提高,将负项的等级降低。如果没有等级违规,则继续对负项目进行采样,直到发现违规为止。

[2]如果您在第一次尝试时发现了一个违反负面示例,请进行大梯度更新:这表明在给定模型的当前状态下,许多负面项目的排名高于正面项目,并且模型必须进行大量更新。如果需要大量的采样来找到一个违规的例子,执行一个小的更新:模型可能接近最优,应该以较低的速率更新。

下面是我们如何用翘曲损失函数指定模型:

 model = LightFM(loss=’warp’)

该模型可以用许多超参数来指定,但是我将在这里跳过这些。值得一提的是,LightFM 还允许贝叶斯个性化排名损失,尽管这通常表现不太好。

训练模型

此时,您可能希望拆分训练数据,以评估模型训练的性能。LightFM 有一个方法,random_train_test_split()为我们做了这件事。我们可以打电话。fit()将模型拟合到交互、项目和用户特征集。

(train, test) = random_train_test_split(interactions=interactions, test_percentage=0.2)model.fit(train, item_features=item_features, user_features=user_features, epochs=2)

我不打算在这里详细介绍模型训练和评估,尽管下面的代码块显示了如何使用我们使用上面的 random_train_test_split()方法创建的训练集和测试集来测量模型训练精度和以 k 间隔报告的 AUC 分数。

train_precision = precision_at_k(model, train,item_features=item_features, k=10).mean()test_precision = precision_at_k(model, test, item_features=item_features,k=10).mean()train_auc = auc_score(model, train,item_features=item_features).mean()test_auc = auc_score(model, test,item_features=item_features).mean()print(‘Precision: train %.2f, test %.2f.’ % (train_precision, test_precision))print(‘AUC: train %.2f, test %.2f.’ % (train_auc, test_auc))print(“testing testing testing”)print(‘printing labels’, get_ratings()[‘ISBN’])

使用模型为一个组进行预测

为了对小组进行预测,我们需要汇总单个用户的评分,以确定某个项目(书)对小组中所有用户的相对重要性。这里我们可以使用多种聚合策略,比如最小痛苦和混合方法。为了简单起见,我将简单地计算该组中所有用户的每个项目(书籍)的预测得分的平均值。

首先,我们创建一个函数来遍历给定组中的所有用户,并使用 item_features 和 user_features 调用 model.predict()来预测每个项目的得分。该函数将每个用户的分数堆叠到我们称为 all_scores 的数组中,以便我们执行一些聚合。

def sample_recommendation(model, data, user_ids):n_users, n_items = data.shapeall_scores = np.empty(shape=(0,n_items))for user_id in user_ids:scores =. model.predict(user_id,np.arange(n_items),item_features,user_features)all_scores = np.vstack((all_scores, scores))

现在让我们通过对每一项取平均来合计分数。然后,让我们对分数进行排序,并按照我们的模型对标签进行评分的相反顺序获取所有标签(ISBN)。

item_averages = np.mean(all_scores.astype(np.float), axis=0)labels = np.array([x[‘ISBN’] for x in get_ratings()])

top_items_for_group = labels[np.argsort(-item_averages)]

现在,我们可以打印本组的前 5 项。

print(“ Top Recommended ISBN for Group:”)for x in top_items_for_group[:5]:print(“ %s” % x)

取样组建议

最后,我们可以为一个组抽样推荐。值得一提的是,虽然 LightFM 的伸缩性很好,但采样建议不一定需要同步,就像我在这里演示的那样。相反,可以异步计算推荐值,并定期为所有组重新计算推荐值。

group = [3,26,451,23,24,25]sample_recommendation(model, interactions, group)

这就是如何构建一个机器学习推荐器,用不多的 Python 代码就能做出基于组的推荐。

有关完整的代码,请参见:https://github . com/jamesdhope/recommender/blob/master/recommender . py

如果你喜欢这个,请给我一些掌声。

参考

[1] LightFM,https://github.com/lyst/lightfm

[2] LightFM,【https://lyst.github.io/lightfm/docs/examples/dataset.html】T4

[3]Bluedatalab.com,客户项目

用 Keras 和 OpenCV 构建多位数检测器

原文:https://towardsdatascience.com/build-a-multi-digit-detector-with-keras-and-opencv-b97e3cd3b37?source=collection_archive---------2-----------------------

用数据做很酷的事情!

介绍

数字在我们身边无处不在。无论是闹钟、健身追踪器还是条形码,甚至是亚马逊精心包装的快递包裹,数字无处不在。通过 MNIST 数据集,机器学习被用来读取单个手写数字。现在我们可以扩展到读取多个数字,如下所示。底层神经网络既进行手指定位又进行手指检测。这在各种 ML 应用中非常有用,比如读取商店中的标签、车牌、广告等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Reading multiple digits

但是为什么不仅仅使用 OCR 呢?是的,OCR 可以是自动检测数字的一个很好的起点,但 OCR 并不总是有效,有时我们需要为我们的特定任务训练一个神经网络。

数字检测流水线

数字检测问题可以分为两个部分

  1. 数字本地化
  2. 数字识别

数字本地化:

图像可以在任何位置包含数字,对于要检测的数字,我们需要首先找到包含这些数字的区域。数字可以有不同的大小和背景。

有多种方法可以检测手指的位置。我们可以利用简单的图像形态学操作,如二值化、腐蚀、膨胀来提取图像中的数字区域。然而,由于阈值、内核大小等调整参数的存在,这些可能变得对图像过于具体。我们还可以使用复杂的无监督特征检测器、深度模型等。

数字识别:

定位的手指区域用作手指识别过程的输入。 MNIST 数据集是手写数字识别的规范数据集。大多数数据科学家都用这个数据集做过实验。它包含大约 60,000 个用于训练的手写数字和 10,000 个用于测试的数字。一些例子看起来像:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MNIST Images

然而,现实生活场景中的数字通常非常不同。它们有不同的颜色,通常像下面的箱子一样印刷。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Day to day digit images

稍加研究,我们就可以看到另一个公共数据集SVHN——街景门牌号数据集 。该数据集由从谷歌街景中收集的门牌号图像组成,并附有注释。下面是来自 SVHN 的示例图像:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SVHN Images

该数据集具有针对许多背景的各种数字组合,并且将更好地用于通用模型。

在 Keras 中建模

我们选择这个 repo 来实现多位数检测器。它写得很好,容易理解。

使用作为稳定特征检测器的最大稳定极值区域(MSER) 方法进行手指定位。MSER 主要用于图像中的斑点检测。斑点是像素的连续集合,其外部边界像素强度比内部边界像素强度高(给定阈值)。如果这些区域在变化的强度范围内没有太大的变化,那么这些区域被认为是最稳定的。MSER 的运行时复杂度较低,为 O(nlog(log(n))),其中 n 是图像上的像素总数。该算法对模糊和缩放也是鲁棒的。这使得它成为提取文本/数字的良好候选。想了解更多关于 MSER 的信息,请点击链接

使用具有卷积、最大池和 FC 层的 CNN 来完成数字识别,这些层将每个检测到的区域分类成 10 个不同的数字。该分类器在测试集上达到 95%的准确率。

我们在各种例子上测试了回购,发现它运行得相当好。见上面分享的例子。

有一些差距,要么是定位器没有完美地工作(没有检测到数字 1 的位置),要么是检测器失败了(检测为 5)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

我们希望这篇博客能成为理解多位数检测管道如何工作的良好起点。我们分享了一个很好的 github 链接,可以用来在 SVHN 数据集上建立模型。如果这种模式效果不好。你可以收集自己的数据,对训练好的模型进行微调。

我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/来看看我们。如果你有一个我们可以合作的项目,那么请通过我的网站或在info@deeplearninganalytics.org联系我

你也可以在https://medium.com/@priya.dwivedi看到我的其他作品

参考文献:

构建一个收集中顶级作者数据的渠道

原文:https://towardsdatascience.com/build-a-pipeline-for-harvesting-medium-top-author-data-c4d7ed73729f?source=collection_archive---------9-----------------------

如何使用 Luigi 和 Docker 为 Medium 构建简单的数据工程管道

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

介绍

当我为数据工程管道编写的一些 Python 脚本失去控制时,这个项目的想法开始了:

  • 管道需要数千个 API 调用 REST 服务,每个调用下载一个 JSON 文件。
  • 管道的某些部分需要很长时间来运行,并且该过程有时会失败。

我的过程是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些累积的 API 调用累积起来:

  • 获取父对象( 1 请求
  • 对于每个父节点获取子节点( 150 个请求
  • 为每个孩子获取信息( 5000 个请求)
  • 对于每个 info fetch 配置项( 14,000 个请求……这已经很多了!)

这是我使用的 API 的一个怪癖;没有办法进行批量请求。有许多问题:

  • 这个序列运行了几个小时
  • 如果出现故障,很难确定从哪里重新开始
  • 没有办法检查进度;如果脚本已经运行了一个小时,它们是不是就要完成了?

咨询谷歌,我发现我的设计与这个不做事的例子非常相似:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这东西已经长成了一个怪物。

路易吉来救援了

我四处寻找一个轻量级的数据工程框架,它可以支持:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A famous plumber

  • 工作流程编排
  • 并行处理
  • 简单部署
  • 快速学习曲线

考虑到这些要求, Spotify Luigi 看起来刚刚好:

Luigi 是一个 Python 模块,帮助您构建批处理作业的复杂管道。它处理依赖性解析、工作流管理、可视化等。

Spotify 使用 Luigi 进行推荐音乐的数据工程批处理工作,例如 Discover Weekly 播放列表(尽管最近流行迪斯科,但我对 Discover Weekly 的选择还是很满意)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

My face when I saw Luigi do all the things

与 Luigi 一起工作令人惊讶地满足,我想知道如何在我的日常工作之外再次使用它。我想到在管道中重用这种方法来收集关于顶级媒体作者的数据,下面的文本描述了一个可以在其他领域重用的数据工程管道的简单框架。

这是面向数据工程和数据科学的,尽管 Luigi 的模块化架构应该可以直接添加分析组件。换句话说,这是一个用于提取数据的系统设计,而不是一种用于分析和从数据中获得洞察力的方法(可能是未来故事的主题)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Luigi gets to work on the pipes

从媒体中获取有趣的顶级作者数据

我们的管道将收集出版物中顶级作者的数据:

  1. 这位顶级故事作者关注的作者列表
  2. 他们写的故事总数
  3. 每个故事获得了多少掌声
  4. 他们故事的平均标题长度
  5. 他们故事的平均字数
  6. 他们为之写作的出版物

关于 Medium API 的一个简短说明。API 本身相当有限。然而,您可以将?format=json附加到许多标准的中型 URL,这将返回通常显示在页面上的数据的 JSON 表示,以及一些额外的元数据。例如,《走向数据科学》的首页用?format=json参数渲染成这样:

{"success":true,"payload":{"collection":{"id":"7f60cf5620c9","name":"Towards Data Science","slug":"towards-data-science","tags":["DATA SCIENCE","MACHINE LEARNING","ARTIFICIAL INTELLIGENCE","BIG DATA","ANALYTICS"],"creatorId":"895063a310f4","description":"Sharing concepts, ideas, and codes.","shortDescription":"Sharing concepts, ideas, and codes.","image":{"imageId":"1*F0LADxTtsKOgmPa-_7iUEQ.jpeg","filter":"","backgroundSize":"","originalWidth":1275,"originalHeight":1275,"strategy":"resample","height":0,"width":0},"metadata":{"followerCount":171879,"...etc

感谢 Radu Raicea 的精彩文章我如何使用 Python 找到有趣的人来关注 Medium 为我指出了这个特性。

JSON 结果需要一点清理:

Remove invalid characters from the response

具体细节

一个关键需求是使我的 Luigi 工作流的部署非常简单。关于部署环境,我只想假设一件事;Docker 守护进程是可用的。有了 Docker,我就不需要担心 Python 版本不匹配或其他环境差异。

不过,我花了一点时间才弄明白如何在 Docker 中运行 Luigi。

第一步是在它自己的容器中启动中央调度程序。你可以用一张现有的图片来做这件事,比如这张。

您可以向调度程序提交作业,如下所示:

PYTHONPATH='.' luigi --module top_artists Top10Artists  --date-interval 2012-07

这是用 Luigi docs 里的一个例子。

所以对于部署,这是我采取的方法;一个 docker 编写文件,包括:

  • Luigi 中央调度程序
  • Luigi 任务的独立的基于 Python 的容器
  • 公开报告的 nginx 容器

tasks 容器的入口点休眠一段时间,然后启动 Luigi 管道,这个sleep代替了 cron 作业。

使用 Luigi 进行并行处理

我的脚本非常慢,我需要一种方法来并行运行多个 URL 获取过程,这导致了这样的设计:

  • 一个WrapperTask包装了管道的所有组件
  • 第一次 URL 获取获得需要单独查询的许多项目的列表(这是一个单独的请求)
  • 这些块在工人之间划分,他们的工作结果被放入一个以每个工人 id 命名的文件中(例如1.json)
  • 从这一点来看,这些文件被下游工人使用

该方法改编自这篇文章

数据收集任务

对于中型数据采集管道,WrapperTask如下所示:

Pipeline wrapper

requires()方法完成了这里的大部分工作,建立了一个在PipelineTask被认为完成之前需要完成的任务列表。

流水线中的第一个任务是FetchUserList。这将从媒体出版物的首页获取媒体作者的列表。作者列表放在一个文件中,供下游任务使用。

Fetch a list of authors from a publication

在《走向数据科学》出版物上运行它,会给我们一个页面上提到的作者列表:

A list of publication authors

您可能会注意到,此结果中返回的作者列表与页面上显示的不匹配;那是怎么回事?原来,页面在加载时会向 Medium API 提交一系列请求,每个返回的 JSON 结果都包含一个指向该系列中下一组结果的指针。我们需要在获取数据时处理这种分页行为:

Handle Medium API paging

这个实现很大程度上借用了 Radu Raicea 的文章。

注意,在一个给定的管道中,只有一个FetchUserList任务将被执行,因为我们没有包含一个file_number参数。

下一个任务是FetchUserFollowings。这个任务将由许多工作器并发执行,并行化由workers配置参数控制。当任务开始执行时,它决定负责处理 JSON 文件的哪个部分。确定截面的逻辑由get_part_of_list()控制:

Split the whole list, so we can delegate a chunk to each worker

ExtractUserMetrics任务从帖子数据中挑选出一些有趣的数据点,例如每篇文章的总鼓掌次数:

Extract metrics

然后,我们可以从提取的故事数据中得出几个平均值:

Calculate averages

最后,这一行启动了这个过程:

luigi.build([PipelineTask()], workers=worker_count)

公开结果

您可能希望向最终用户公开这些报告,例如向您团队中的数据科学家公开。一个简单的方法是添加一个 nginx web 服务器,并列出输出目录的内容。这将允许任何人点击一个 URL 并下载报告,每天都有一个报告目录。

尝试一下

好吧,让我们踢轮胎这件事…

首先,通过在 luigi.conf 文件中指定一个collection_id来指定 URL 抓取的起点。

配置完成后,有几种方法可以运行代码:

  1. 开发时,可以直接运行__main__.py。如果你想这样做,你需要先启动 Luigi。
  2. 您还可以使用 docker-compose 运行整个应用程序堆栈:
docker-compose up -d

这将启动 Luigi、nginx 和任务容器,这将触发__main__.py

检查总结报告,我们可以获得一些关于目前为《走向数据科学》撰写文章的一些顶级作者的信息。例如,我们可以获得当前顶级作者之一 Will Koehrsen 的一些汇总统计数据:

Some example metrics

干得好,威尔!

单元测试

我选择了 pytest 作为测试框架。我喜欢 pytest 有两个主要原因:

  • 它需要更少的样板代码
  • 您可以使用常规的 assert 语句,而不需要记住特殊的语法

为了使用与生产版本不同的配置进行测试,您可以在测试中使用luigi.configuration.add_config_path()。这将从特定位置加载配置:

Find and load test configuration

我使用了MockTarget类,这样我可以以可重复的方式运行测试。我不希望一个测试依赖于前一个测试创建的数据,或者测试在完成运行后留下结果文件。MockTarget模拟一个 Luigi 目标,它将结果存储在内存中,而不是将它们写到文件系统中。

最后,为了允许在不要求端点可用的情况下测试 URL 请求,我使用了[requests_mock](https://pypi.org/project/requests-mock/)库。

Github 上提供了该示例管道的完整源代码:

[## 吕克拉塞尔/多克尔-路易吉

从 Medium 获取顶级作者数据的数据工程管道— lucrussell/docker-luigi

github.com](https://github.com/lucrussell/docker-luigi)

结论

这个项目是一个 Luigi 管道,用于从 Medium 收集顶级作者数据。该项目一开始只是一个简单的框架,用于编排一个有问题的数据工程过程。管道通过抓取出版物首页的 URL 来提取关于作者及其故事的信息,然后收集关于顶级作者的一些基本指标。它使用 Luigi 来协调 Python 逻辑,使用 Docker 来简化部署。

快速建立投资组合网站

原文:https://towardsdatascience.com/build-a-portfolio-website-in-a-flash-9d5ec30a73a7?source=collection_archive---------16-----------------------

使用 GitHub 页面和 Google 域名创建静态网站的 12 个步骤

如果你是一名开发人员、数据科学家或设计师,你可能会被建议建立一个作品集网站。你的作品集向其他人展示了你能做什么,以及为什么他们应该与你合作发展一项事业、一个副业或一项新的事业。

但是导航选项来创建一个安全、便宜、响应迅速的网站是一个障碍,它经常阻止人们将他们的网站投入使用。我已经做了研究,建立了一个网站,将与您分享如何快速制作作品集网站。好消息是只需要 12 个步骤。😁

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是我网站的截图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://jeffhale.net/

我不是说我的设计很壮观。😀我的重点是帮助你通过这个过程,让你可以在瞬间建立一个网站。然后,您可以对其进行样式化,并包含您喜欢的任何内容。

我们开始吧!🚀

12 步

  1. 制作 GitHub repo
  2. 克隆回购
  3. 做一个 gh-pages 分公司
  4. 创造 index.html
  5. 添加引导启动代码
  6. 添加内容
  7. 本地查看网站
  8. 推送至 GitHub
  9. 在网上查看
  10. 从谷歌域名购买自定义网址(可选)
  11. 将您的自定义域指向 GitHub 页面(可选)
  12. 启用 SSL(如果使用自定义 URL)

迭代!🔃

制作 GitHub Repo

如果您没有 GitHub 帐户,请参阅我的 GitHub 工作流文章了解如何获得一个。给你的回购命名。创造。gitignore、README.md 和许可证文件。

克隆回购

在本地机器上克隆您的 repo。如果您的本地机器上没有 git,请参考上面的文章获取它。

切换到您的本地存储库。创建一个名为 gh-pages 的新分支。

默认情况下,GitHub Pages 会根据名为 gh-pages 的分支中的内容自动更新您的站点。默认情况下,GitHub Pages 不会从您的主分支自动更新。

创造 index.html

移动到您的项目目录。用touch index.html做一个名为index.html的文件。如果你想学习 shell 常用命令,比如touch,请点击这里查看我的文章

在代码编辑器中打开您的index.html文件。

添加引导启动代码

我们将使用超级流行的 Bootstrap 框架,以最小的努力提供响应性 CSS 功能。

从 Bootstrap 复制并粘贴 starter 模板代码。如果你不需要 JavaScript 功能,那就去掉这一部分来加速你的站点。我在下面的代码片段中省略了 JavaScript 代码。

Bootstrap starter code without JavaScript

引导文档非常好。如果你以前没有用过 Bootstrap,我建议你花几分钟时间使用 Bootstrap grid docs ,这样你就知道如何修改页面布局了。如果您需要提神剂(或清新剂😃)在 HTML 和 CSS 方面,建议你去看看 w3schools.com 的。

添加内容

标题标签和正文标签的内容更改为 Your_name 的作品集— 或您喜欢的任何内容。

添加您的 HTML。我使用了三栏布局,在移动设备上切换到一栏。

如果你想制作其他的 CSS 样式,创建 addedstyles.css 并在你的 index.htmlhead标签中包含<link rel=”stylesheet” href=”addedstyles.css”>

我的代码可在本回购获得。再说一次,我不是说我的设计很棒。我的重点是帮助你快速建立一个网站。

本地查看网站

您的网站可以在本地查看,而无需提供任何服务,因为这是一个静态网站。只要双击你电脑上的index.html文件,然后**砰!**你应该会在浏览器中看到你的投资组合。

推送至 GitHub

在 Git 中添加文件并提交您的工作。然后用git push origin HEAD:gh-pages推送到你的 gh-pages 分支。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GitHub Repo

在网上查看

导航到http://your _ git hug _ username . github . io/your _ repo _ name。例如,我的站点在 http://discdiver.github.io/show/(现在它被转发到一个自定义域名)。您应该会看到与您在本地看到的相同的网页。

如果你想要一个每年 12 美元(税前,在美国是美元)的个性化网址,你可以这么做。

从谷歌域名购买自定义网址(可选)

如果你想要一个自定义域名,而不是 GitHub 页面的网址,我建议你从谷歌域名购买一个域名。多年来,我尝试了很多域名注册商,发现谷歌域名是目前最好的。

用你的谷歌账户登录,开始搜索域名。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Probably not what you want for your portfolio URL. 🚗

完成您的交易。您将在一分钟后回来管理 DNS 设置。

将您的自定义 URL 指向 GitHub 页面(可选)

GitHub 最近使得创建一个 CNAME 文件来链接你的自定义域名变得更加容易。👍

转到您的存储库的设置选项卡。向下滚动到 GitHub 页面,在自定义域名字段输入你的域名,按保存。GitHub 现在会自动为你的回购协议中的 DNS 创建一个 CNAME 记录。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Adding a custom url. Note that the Enforce HTTPS checkbox will be unchecked after you save.

现在我们需要修改连接的 Google Domains 端的内容。

在您的 Google Domains 帐户中,选择 DNS 选项卡并向下滚动到自定义资源记录。留着@。在 IPv4 地址字段中键入以下内容:185.199.108.153

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

After updating Google Domains DNS tab.

然后添加一个 CNAME 记录,这样就可以解析你的 url 的版本。将 www 放入第一个字段,从下一个下拉字段中选择 CNAME ,并将 @ 放入 IPv4 地址字段。

应该可以了!拿一杯水🚰当您的更改传播时。然后导航到 http://your_custom_url 。你应该看看你的网站。酷!

启用 SSL(如果使用自定义 URL)

启用 SSL 是个好主意,这样你的站点会更安全,你的 https 前缀也会起作用。启用 SSL 只需在您的 repo 的设置选项卡中点击一下。我不知道为什么添加自定义域时设置会关闭。

在 GitHub 页面部分,点击强制 HTTPS 的复选框。请注意,选中复选框后,您不必保存任何内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Check the box for HTTPS

现在当你导航到 https://your_url 时,你应该会看到你的站点,而不是一个错误。你有一个功能正常的投资组合网站。酷毙了。😀

不要忘记更新你的 GitHub master 分支中的自述文件,这样人们就知道在哪里可以找到你的 live 站点。GitHub 上的编辑按钮也可以让你包含一个网站链接。👍

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Note the Edit button on the right

是时候让你的网站变得更漂亮了。

重复

有许多关于如何建立你的作品集内容的文章。这是一个有很多好建议的人。

有些人推荐大项目,有些人推荐小项目,有些人推荐混合项目。我不打算参加这场辩论,但我将提出一些一般性建议。

  • 添加一些链接和图片。如果你不是设计师,你不需要走极端——只要确保你的作品集看起来干净专业。
  • 确保你的作品集在手机和桌面上都很好看。Bootstrap 的响应式设计让这变得相当简单。
  • 除非你在自述文件、博客帖子或 Jupyter 笔记本中讨论一个项目,否则我建议你在文件夹中谈一谈。
  • 如果你把你的投资组合放在一起,发现它有缺口,开始填补这些缺口。如果你正在做你的第一个项目,不要气馁。每个人都从第一个项目开始了他们的旅程。😁
  • 将你的作品集交给几个你信任的人,他们会给出诚实的反馈。
  • 当你准备好与全世界分享你的作品集时,用你作品集的 URL 更新你的 LinkedIn 个人资料。
  • 如果你怀疑自己有冒名顶替综合症,担心你的作品集永远不会准备好,当你认为已经完成 95%的时候,分享你的作品集。您可能会发现设置上线截止日期很有帮助。
  • 记住你的作品集是一项正在进行的工作。更新它,因为你有更多的项目要添加。

随意给你的网站添加更多的复杂性:杰基尔、T2、盖茨比。你可能想用 Sass 来管理风格。

我网站的代码可以在 GitHub repo 中找到。随意叉它去镇上。🍴

包装

在这篇文章中,你看到了如何用 12 个步骤建立你的投资组合网站。我希望这个指南对你有用。如果你有,请在你最喜欢的社交媒体上分享,这样其他人也可以找到它。😀

你可以用同样的方法建立任何静态网站,而不仅仅是作品集网站。

我撰写关于数据科学、Python、云计算和其他技术主题的文章。如果你对其中的任何一个感兴趣,请查看它们并在这里跟随我。

为了确保你不会错过精彩的内容,请加入我的邮件列表。👍

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你用这个指南做一个项目或作品集——我很想看看你会做些什么——在 Twitter @discdiver 上给我加标签。

快乐组合!😁

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值