TowardsDataScience-博客中文翻译-2019-五十七-
TowardsDataScience 博客中文翻译 2019(五十七)
火箭(数据)科学
过去几年,中东集团相当吵闹。作为一个被许多敌人包围的小国,以色列一直处于冲突之中。简言之(根据以色列外交部的说法):
来自东北——因“隔壁”叙利亚战争引发的边境事件
来自北方——来自黎巴嫩边境的真主党威胁
来自南方——ISIS 在埃及边境附近的敌对活动
来自西方——伊斯兰圣战组织/哈马斯试图从加沙地带发动恐怖袭击
来自东部——朱迪亚和萨马拉暴力再起
据谷歌称,自 2001 年以来,巴勒斯坦武装分子从加沙地带向以色列发动了数千次火箭/迫击炮袭击,作为持续的巴以冲突的一部分。
如果你在以色列生活了几个月以上,你很可能熟悉臭名昭著的警报“红色代码”(希伯来语:צבע אדום),这意味着由于火箭发射,人们必须立即找到避难所。
撇开政治不谈,我认为尝试对火箭发射进行可视化建模(通过使用警报日志)可能是一个很酷的项目,由于我在以前的文章中被多次问到,我决定尝试并详细说明我在处理这样一个项目时使用的方法和工具。
A 部分—获取相关数据
第一步是在谷歌上搜索以色列警报的某种“记录”数据。
上面提到的搜索引导我进入“Home Front Command”网站,在那里我可以查询以色列过去的警报:

Home Front Command’s site
结果产生了一长串过去的警报:

Small portion of the data
就我个人而言,我更喜欢使用纯文本/表格数据,快速浏览 Chrome 的 DevTools 可以发现查询请求/响应的 API(这只是使用搜索按钮时“在幕后”发出的网络请求),这使得可以立即获取纯文本答案:

The query URL

The website’s text response
总之,我提取了从 2014 年 7 月(可用的较早日期)到 2019 年 5 月的警报历史。
B 部分—丰富数据
首先,原始数据没有指定确切的位置,而只是“区号”(由于历史和技术原因),所以我必须以某种方式构建“区号到城市列表转换器”。
尽管没有公开的“字典”来记录后方司令部的代号,但谷歌搜索发现,每个代号在维基百科上都有一个独特的页面,囊括了该地区城市的完整列表:

Google search results show a re-occurring pattern of Wikipedia page per area code
因此,使用一个简短的 Python 脚本使我能够获得每个区域的城市列表(没什么特别的,使用 GET request per area,并提取页面主体中的所有 URL 名称)。
第二,我不得不分解数据集,以使每个警报作为一个独特的行出现在对等城市,这样它就可以在以后作为独立的数据呈现。
最后,我使用开源的地理 API 将城市名称转换成 GPS 坐标。
总而言之——这是数据经历的过程:

The procedure — visually
C 部分—数据清理/完整性
在这一部分中,我必须进行一些合理性检查,包括:
1.手动修复错误刮取的值——因为刮取永远不会完美。
2.手动修复不可能的 GPS 坐标-由于模糊的城市名称,一些城市似乎不在以色列境内。
3.删除不相关的数据-警报系统测试或国家危机演习等事件也包含在数据集中,因此特定的时间/日期被删除(它们很容易过滤掉,因为它们总是在特定的月份在所有城市同时发生)。
4.标记不适用数据—例如由于缺乏维基百科/谷歌中的信息,一些地区无法翻译成城市列表——不幸的是,这些数据没有出现在项目中。
D 部分—可视化数据
我第一个也是最喜欢的可视化聚合工具是 Tableau,使用这个工具可以非常容易地呈现数据:

Heat map of “Code Red” alarms over the past 5 years

Heat map of “Code Red” alarms per month (interesting to notice the increase during summer periods of July-August, the Israeli summer)

Full Heat map of “Code Red” alarms per distinct months. note: data is available only from July 2014
除此之外,一个朋友向我介绍了一个神奇的开源工具,叫做开普勒,用于地理空间数据,在其中你可以看到数据的动画,甚至可以自己重塑它:

Top siren activity
(note when exploring the animated data: while the launch destination is an exact GPS coordinate, the launch source was added only for aesthetic purposes and it is not accurate)
bird’s eye view of alarms in the past 5 years
你也可以在下面的链接中使用这些数据,自己制作其他很酷的动画:
Kepler.gl 是一个强大的基于网络的地理空间数据分析工具。基于高性能渲染引擎和…
E 部分——留在上下文中
这一部分与数据无关,我只是想利用这个平台来强调,即使一些数据可能看起来很迷人/美丽,但人们永远不要忘记背后的故事。在这种情况下,尽管我很喜欢这个项目,但我希望这些数据一开始就不存在。
希望你觉得这篇文章有趣/有用,一如既往地欢迎你的反馈。
火箭 vs 裁判?
NBA 季后赛即将来临,每个人都很高兴看到联盟的巨头们为赢得梦寐以求的冠军而对决。在东部联盟,扬尼斯·阿德托昆博和密尔沃基雄鹿队希望横扫科怀·伦纳德和多伦多猛龙队。在勇士队在第六场比赛中主场击败休斯顿火箭队后,金州勇士队现在发现自己处于横扫波特兰开拓者队的位置。
在整个系列赛中,詹姆斯·哈登表达了他的沮丧,尤其是在第一场比赛后的采访中。
“我是说,我只是想要一个公平的机会,伙计,”
他认为裁判让他输掉了系列赛的第一场比赛。他并不孤单,因为粉丝们也有同感。他们的抗议有一定的合理性吗?
2015 年,NBA 实施了最后两分钟报告。它详细记录了裁判在比赛最后两分钟做出的每个决定。通常在比赛后一天发布,一份报告详细说明了裁判在比赛最后两分钟内必须做出的每一个决定。在汇总了系列赛中的每一份报告(除了第六场比赛,因为 NBA 没有发布它)后,我们可以看到裁判在比赛的最后阶段有多准确。
这些报告将呼叫分为以下类别:
错误呼叫(IC):进行了错误呼叫
不正确的非通话(INC):应该打电话但没有打
正确的呼叫(CC):做出了正确的呼叫
纠正不判罚(CNC):裁判没有判罚是正确的
这个系列是这样分解的:

总的来看,裁判在最后时刻要做出 136 个判罚。在被要求做出决定的次数中,只有 16 次是错误的。这意味着在整个系列赛中,裁判 88%的时间都是正确的。

对于每一种叫牌类型,报告都会分配一个承诺玩家/球队和一个劣势玩家/球队。当我们看数据时,我们看到火箭的犯规几乎是勇士的两倍(13 次对勇士的 7 次)。火箭犯规更多,但他们应该得到判罚,所以说裁判作弊或有偏见是不公平的。
好吧,火箭犯规更多,所以他们应该为他们的失败负责,对吗?让我们先深入一点。
到目前为止,我们只分析了正确的调用。我们的目标是考虑可能显示偏见的呼叫。
正确的判断(顾名思义)是正确的,因此不能用来确定偏见。在这些情况下,正确的呼叫是应该的,因此我们无法确定恶意意图。
相反,查看不正确的电话可能能够说明问题。
不正确的吹罚可能是裁判对情况视而不见,而不正确的吹罚可能表明裁判在积极帮助球队获胜。
确定了衡量偏差的最佳方法后,我们可以查看数据,看看裁判的表现如何。

看起来犯规判罚并没有偏袒一方。在 16 次不正确的吹/不吹中,每个队有 8 次处于劣势。因此,尽管裁判 88%的时候都是正确的,但他们对两队来说都是同样错误的。
在第一场比赛后,金州勇士队的德雷蒙德·格林指出,
“我想我们可以在每场比赛后都坐在这里抱怨裁判的判罚。这就是我们玩的游戏的本质。裁判是一门不精确的科学。原来如此。”
德雷蒙德·格林可能是对的,但正如证据所表明的,裁判可能不是这次的问题。
数据科学在人工智能中的作用
电子表格的时代已经结束。谷歌搜索,护照扫描,你的网上购物记录,一条微博。所有这些都包含可以收集、分析和货币化的数据。超级计算机和算法使我们能够实时理解越来越多信息。在不到 10 年的时间里,CPU 有望达到人脑的处理能力。
随着大数据和快速计算能力的兴起,许多组织的首席执行官、首席技术官和决策者都在想办法创新他们的公司。当他们想要推出新产品或服务时,他们希望通过数据分析来洞察市场、需求和目标人群等。人工智能和机器学习正在快速被企业采用。这一趋势很可能会上升。
让我们来看一些统计数据:
根据 IDC 的数据,2018 年全球在人工智能和认知技术上的支出将达到 191 亿美元,比一年前增长 54.2%。到 2021 年,人工智能和认知支出将达到 522 亿美元。
人工智能技能是 LinkedIn 上增长最快的技能之一,从 2015 年到 2017 年增长了 190%。
当我们谈论“人工智能技能”时,我们指的是创造人工智能技术所需的技能,包括诸如神经网络、深度学习和机器学习、等领域的专业知识,以及实际的“工具”,如 Weka 和 Scikit-Learn。
招聘:人工智能专家
在人工智能领域,职位空缺比求职者上升得更快。

AI-related jobs include machine learning engineer, predictive modeler, cmt analytics manager, data scientist, computer vision engineer, computational linguist, and information strategy manager.
Source: Indeed.com
没有什么能减缓人工智能的传播。科技公司正在大力投资 it,普华永道的一份报告估计,到 2030 年,人工智能可以为全球经济增加 15.7 万亿美元——并推动北美的 GDP 增长 14%。
也许机器学习最引人注目的方面是它看似无限的适用性。已经有很多领域受到 ML 和现在 AI 的影响,包括教育、金融等等。机器学习技术已经应用于医疗保健领域的关键领域,影响了从减少护理差异到医学扫描分析的方方面面。
AI 到底是什么?
人工智能是“貌似智能的算法”的一般领域,目前机器学习是该领域的前沿。
随着时间的推移,我们对人工智能的定义发生了变化。从 1939 年的智能机器人开始,我们已经走了很长一段路,如下图所示。
Source: 1939 I AM A SMART FELLOW ROBOT TALKS Stock Footage
人工智能只是一台能够模仿或模拟人类思维或行为的计算机。其中,有一个子集叫做机器学习,它现在是人工智能最令人兴奋的部分的基础。通过允许计算机学习如何自己解决问题,机器学习取得了一系列突破,这些突破一度似乎几乎不可能。这就是电脑可以在照片中认出朋友的脸或者驾驶汽车的原因。这就是人们积极谈论类人人工智能到来的原因。

A simplified explanation of AI, Machine Learning, and Data Science. Source: Suraj Jena, June 10, 2018
那么,机器学习和数据科学是如何交叉的呢?
机器学习是人工智能的一个分支,其中一类数据驱动的算法使软件应用程序能够高度准确地预测结果,而不需要任何显式编程。
这里的基本前提是开发能够接收输入数据并利用统计模型预测输出的算法,同时随着新数据的出现更新输出。
所涉及的过程与预测建模和数据挖掘有许多共同之处。这是因为这两种方法都需要搜索数据来识别模式并相应地调整程序。
我们大多数人都以这样或那样的形式体验过机器学习。如果你在亚马逊上购物,或者在网飞上看了一些东西,这些个性化的(产品或电影)推荐就是机器学习在起作用。
另一方面,数据科学采用数学和统计学等计算机科学学科,并融合了数据挖掘、聚类分析、可视化以及机器学习等技术。
因此,两者之间的主要区别在于,作为一个更广泛的术语,数据科学不仅关注算法和统计,还关注整个数据处理方法。
机器学习是人工智能的一个子集。虽然数据科学是从数据中提取知识或见解的跨学科领域

VENN diagram of AI, Big Data and Data Science Fraunhofer FOKUS
人工智能技术中如何使用数据科学领域的例子
IBM Watson 是一项人工智能技术,可以帮助医生快速识别患者病历中的关键信息,以提供相关证据并探索治疗方案。它接受患者的医疗记录,然后根据来自 300 多种期刊、200 多本教科书和 15 多页文本的信息提供基于证据的个性化建议,这使医生可以即时访问大量针对患者治疗计划的个性化信息。
蓝莓。这个机器人在被喂以成千上万部电影的字幕后,可以表演即兴喜剧。科里·马修森,埃德蒙顿阿尔伯塔大学的人工智能研究员,创造了一种算法,旨在与他在舞台上即兴表演。他训练它创造用于即兴表演的对话线,当对话有意义时奖励它,当它吐出胡言乱语时惩罚它。
虽然蓝莓不会很快在第二城市试镜,但这个可爱的机器人偶尔会用有趣的台词击中要害。我将展示一个蓝莓的短片作为结束。
Kory Mathewson, inventor of Blueberry. Video Credit: Bloomberg, Hello World, Is AI Ready for Improv Comedy
参考文献:
“随着公司拥抱人工智能,这是一个求职者的市场”,Ann Saphir,2018 年 10 月 15 日
“人工智能能否取代数据科学家?”佩德罗·乌里亚-雷西奥,2018 年 9 月 14 日
"AI 准备好即兴喜剧了吗",彭博商业周刊,《你好世界》第一季第 16 集,2018 年 6 月 11 日
"专家谈:数据科学 vs .数据分析 vs .机器学习",Sarihari Sasikumar,2018 年 10 月 18 日
“ I .将‘G’放在‘AI’中:人工智能(狭义/应用)中使用的术语概述——以及它们彼此的意义”,Suraj Jena,2018 年 6 月 10 日
“媒体领域的人工智能和机器学习”,弗劳恩霍克·福库斯
“人工智能通过生产力和个性化改进推动 GDP 增长 15.7 万亿美元”,普华永道出版社,2017 年 6 月 27 日
"根据 IDC 2018 年 3 月 22 日发布的新支出指南,到 2018 年,全球在认知和人工智能系统上的支出将增长至 191 亿美元
“领英 2018 新兴工作报告”,领英,2018 年 12 月 13 日
机器学习在重新定义零售银行业务中的作用

Photo by Sean Pollock on Unsplash
随着高级分析算法在核心银行日常业务中的广泛应用,银行业正在经历一场转型之旅。通过各种渠道获取客户、现有的客户参与度、预测信用卡或贷款申请的违约者等等,这些都是分析做了大量工作的几个领域。我将解释一些我过去在一家领先的跨国银行的高级分析团队工作的经历,在那里我们使用了一些来自分析和机器学习的有趣概念来解决复杂的业务问题。
顾客就是上帝(或者是这样?)
跟踪上帝是不可能的,但你可以借助先进的分析算法来跟踪你的潜在客户。银行可以提供有关他们购买模式、人口统计、交易、服务请求等的大量信息。这被有效地用于预测顾客购买特定产品的倾向。在分析部门工作时,我与许多销售团队合作,他们需要一份潜在未来客户的排序列表,用于直接邮件/电话营销活动。这些活动通常包含针对该产品的有吸引力的优惠,如信用卡的低利率、储蓄账户的高利率等。这是由于相信来自排名列表的大量顾客将准备购买该产品,而不是随机联系的顾客。不仅预测了产品的潜在客户,还预测了哪些客户打算关闭他们的账户(客户流失)。
逻辑回归等数据科学算法在预测客户购买倾向概率或客户流失概率方面表现出色。例如,考虑以下现实生活中的业务问题:
一家领先的跨国银行希望制定一项战略,以遏制其储蓄账户产品不断增加的客户流失。他们联系高级分析部门,通过预测他们中的哪一个有关闭账户的倾向来帮助他们留住最好的客户,以便他们可以与他们联系,并提供有吸引力的交易来继续他们的宝贵关系。
高级分析团队首先缩小问题范围并定义损耗,例如,客户取出他们的存款,关闭他们的储蓄账户,并且不将他们的钱再投资于同一家银行提供的另一种产品。企业希望提前 3 个月预测流失,以便有足够的时间来设计保留策略。
然后,团队继续收集所需的数据,这通常会占用项目的大部分时间,例如收集哪些数据、收集多长时间、需要哪些额外数据等问题。是非常关键的要求。一旦舞台设置好,数据科学家就要执行他们的最后一步——机器学习。这些算法将读取数据,并根据之前的账户关闭情况,找出导致流失行为的模式。然后,它将利用当前场景中新的可用客户信息,预测流失的可能性。
我遇到了一个令人震惊的项目,预测 10 年后客户购买零售银行产品的倾向!猜猜这些算法的驱动特征是什么?—在商业社交媒体网站上追踪的当前教育背景和成就有助于了解这个人将来想把钱投到哪里。
自然语言处理算法(如零售银行中的朴素贝叶斯分类器)的一个非常有趣的用途是分析交易。每笔交易都有一个代码和一个简短的描述。数据科学家使用语言解析从生成的海量文本中提取关键词或标记,以通读描述并发现更多关于交易的信息。它可以识别您是否在零售店购买过产品,是否向您持有的另一个银行账户转账,或者是否支付了另一家银行的信用卡账单。然后,可以将交易与您如何评价您当前与银行的关系联系起来,企业可以根据这些重要信息决定各种客户拓展策略。
他们看到什么就买什么
根据经济学定律,选择会宠坏我们。摆在顾客面前的选择越多,他们就变得越困惑,不购买该产品的可能性就越大。利用硬核机器学习算法的一个非常利基的领域是有针对性的数字营销,零售银行业务不断利用这一点来识别和抓住访问网站的潜在客户,方法是显示定制的 web 内容,以满足访问者的需求并提供他们正在寻找的产品。企业如何知道客户想要什么?数字足迹!
数以百万计的网站访问者生成数千千兆字节的数据,这些数据包含的信息包括:他们来自什么渠道,银行网站上最常见的登录页面是哪个,他们浏览了哪些页面,他们花了多少时间阅读内容,他们每天或每周进行了多少次独特的访问,等等。这些数据被称为网站访问者的数字足迹,也称为点击流数据。银行和金融机构一直在处理这些数据,以生成关于访问者正在寻找什么的准确信息,并且他们有效地向访问者显示定制内容,在主页上显示他们感兴趣的产品。这促使访问者点击展示链接,了解更多关于产品的信息,正如俗话所说,他们看到什么就买什么。你不应该显示太多的内容,因为这会让访问者感到困惑,他们可能会不做任何交易就注销,或者没有留下他们的信息以便以后联系。来自数字足迹的信息可以被定制到访问者愿意转换的百分比!定制内容的显示基于哪些当前访问者显示了过去已转化的其他访问者的特征。由于转换率极低,因为该银行网站上的数百万访问者中只有少数人会在网上购买产品或服务,因此我们需要使用一些非常强大的机器学习算法,这些算法可以在有限的数据量下捕捉模式以进行学习。此外,由于每秒都会生成数字足迹,因此算法需要读取大量数据。机器学习算法,如随机森林(使用 Bagging 方法)或梯度推进(使用推进方法)在这里工作得很好。这些算法在处理大量数据时是有效的,并且可以以良好的准确度识别模式。数据科学家还使用一种称为堆叠或集成的技术,其中不同算法的输出被组合并输入到另一个模型中,以计算各种机器学习算法组合的概率。
所以,下次你访问一家银行的网站,弹出窗口显示提供诱人的住房贷款利率时,请确保后台运行的重载机器学习算法已经监控了你在网站上的活动,并知道你在寻找什么。
集群—一站式分析解决方案
银行和金融机构的大部分决策都是通过将具有相似特征和特定行为方式的事物分组来完成的,这样就可以批量应用决策,从而节省时间、精力和金钱。聚类算法来拯救!我数不清有多少次我们提议用集群来解决业务问题,但我会分享两个例子,我清楚地记得我们是在哪里这样做的。
第一个是为一家银行设计的,它想从不太忠诚的客户中找出最忠诚的客户。我们的方法是基于三个指标来定义忠诚度:交易的新近性、交易的频率和交易的货币价值(在分析界更为人所知的是 RFM 模型)。这三个指标结合起来,根据对业务更重要的因素赋予每个指标一定的权重,使我们能够对哪些客户与其他客户相比互动更多进行排名(这些客户最终会处于休眠状态,并属于不太忠诚的类别)。一个重要的考虑是深入研究交易,否则错误可能会悄悄进入。例如,这非常有趣,当我们根据 RFM 评分发展分类时,我们看到每个储蓄账户持有人在近期价值上得分很高。这对我们来说非常有趣,我们花了几天时间来确定发生了什么,后来才意识到每个储蓄账户都有账户持有人的应收利息,并且在每个月底贷记到账户中。
第二种情况是,业务部门希望确定绩效低于平均水平的银行分支机构,衡量标准包括获得的新客户、账户中保持的平均余额、发送给总行审批的房屋贷款申请的质量、客户的发起人得分、员工流失等。使用 k-means 聚类,我们从较低的分支中识别并区分了这些指标上的所有高性能分支。这有助于银行做出决策,如审查绩效较低的分支机构的财务目标或关注员工培训,并激励绩效较高的分支机构激励他人。
所有高级分析和数据科学算法背后的核心理念是帮助企业更快地做出更好的决策。他们说数据是新的石油,分析是将石油转化为燃料的过程。
在深度学习中滚动
在现有艺术家身上训练人工智能来创作新颖的音乐
我用几种机器学习技术制作了这个音乐视频。音乐是由一个人工智能在阿黛尔的专辑“21”上训练了两周产生的。视觉效果是由一个人工智能生成的,该人工智能从她的歌曲“在深渊中翻滚”的每一行歌词中创建了图像。他们一起创造了一个有趣的,也许是令人不安的机器辅助创作的观点。
这一切都始于我和我的朋友们玩的一个叫做 Cover Me Badd 的活动/游戏。这有点像带回家的卡拉 ok,或者 DIYMTV。每个季度,你组建一个乐队,然后选择一首翻唱歌曲。但你不能翻唱这首歌。我们把所有的歌曲放进一顶帽子里(嗯,一顶虚拟的帽子),把它们混在一起,然后随机分发给每个乐队,所以你必须翻唱别人提交的一首歌。然后你录下这首歌,制作一个音乐视频,我们在最后聚在一起开一个大派对,看所有的视频。
这个季度,我被安排去采访阿黛尔的《在深渊中翻滚》。我知道我不可能唱好这首歌,因为我的声音太难听了。所以我训练了一个机器人为我唱歌。
训练“Adeldroid”
我最近发现了 SampleRNN,这是一种机器学习算法,可以从音频样本中学习,然后吐出类似的声音作为输出。达达机器人小组已经使用 SampleRNN 制作了一个无尽的死亡金属电台。他们还训练了一名披头士乐队的模特,创作了《深入披头士》专辑。
这个概念有点简单:你把一个音乐源(作为 PCM。wav 文件),将其分割成小段,然后从这些小段中随机选取,并将它们输入到递归神经网络中。每次你给它输入一些片段,这个模型就能更好地模仿那个声音。前 500-1000 次迭代将是噪音和静态的,但过一会儿它的输出将开始成形,听起来类似于你喂它的东西。它可以模仿声音、吉他、钢琴、鼓——如果你的训练数据是这样的话,甚至可以同时模仿。
Here’s what successive trainings of SampleRNN on Ariana Grande sounds like
现在,如果你在你的家用电脑上训练这个模型,可能需要几个月才能得到有用的东西。你需要的是一个特别为机器学习而构建的非常强大的 GPU。在我写这篇文章的时候,最好的是 NVidia Tesla P100,如果你想要自己的,价格在 10,000 美元左右。幸运的是,我们可以简单地从云中租用一个(这仍然是一个很大的成本,但比投资自己的硬件要少得多)。
有几家公司会让你在云中使用他们花哨的 GPU。由于我在谷歌工作,我决定使用谷歌云平台的计算引擎。他们有一个预构建的虚拟机映像,其中已经安装了所有 NVidia CUDA 驱动程序和 Tensorflow 等机器学习软件,并准备好在他们的 Google Cloud 深度学习虚拟机映像中使用。你只需点击按钮,它就会为你提供一个带有 Tesla GPU 的虚拟机,然后你登录并复制你的音乐文件和用于 Tensorflow 代码的 SampleRNN,并立即开始训练。
提示:确保在运行训练命令之前运行屏幕 Linux 实用程序,这样它就不会在你退出时被杀死。
那你等着。我对我的模型进行了大约 4500 次迭代,持续了大约两周。(按照特斯拉虚拟机每小时 50 美分的价格,大约是 170 美元。所以,是的,创造你自己的唱歌机器人并不便宜。)
我会每天登录,检查最新的样品,以确保它们是好的。有几次,代码因为超出界限的无限值而崩溃。没关系,你可以删除最后几个快照,然后从那里重新开始训练,这样通常就可以了。
一旦我对进度感到满意(大约在第 3500 次迭代时),我停止了训练,并将样本输出持续时间从每 10 次迭代生成 3 秒剪辑(这对测试很有好处,因为它们会减慢训练过程)提高到每一次迭代生成 8 秒剪辑。我又让它运行了几天,以产生一个我可以从中提取的好的素材集。
拼凑机器人的散文诗
然后,我把我从云端生成的所有样本下载到我的电脑上,开始了漫长而艰苦的分类过程。人工智能创造的背后隐藏着大量的人类劳动,从收集人类创造的内容的数据,到使用发展中国家的数字劳动力(例如机械土耳其人)来标记训练数据,到聚合和排序模型的输出并微调参数。
我亲身经历了后者。我的分类系统是基于 macOS 的 Finder 颜色标签:
- 红色/橙色/黄色:人声(红色最好,黄色……不太好)
- 绿色:环境/旋律乐器
- 紫色/蓝色:鼓/低音/背景节奏
- 灰色:怪异/另类/最爱

由于我对将近 1500 个剪辑进行了分类(只有迭代 3000 到 4500 是可列表的),并且每个迭代有 10 个剪辑,我将从每个迭代中抽取几个剪辑。如果某件事真的很有希望,我会在同一个迭代中听更多,否则我会尽可能快地完成它们。
一旦我完成了对最好的样本的标记,我必须将它们排列成某种“歌曲”,有开头、中间和气候结尾,希望能创造出一种旅程,而不是仅仅将随机的片段连接在一起。我真的受到了乐队 Yacht 与机器学习合作的技术的启发,并试图适应他们在与 AI 合作时强加给他们创作过程的“规则”:
你们中的一些人可能知道,使用机器学习来制作一首有结构的歌曲,有开头,中间和结尾,有独唱,合唱,独唱,仍然有点,超出了我们的能力范围。但这是一件好事,因为旋律是模特的工作,但编曲和表演完全是我们的工作。
所以对我们来说,我们决定用这个过程创作的每一首歌都必须从我们备份目录中的现有旋律中插入…我们还决定不能添加任何音符。我们无法添加任何和声。我们不能即兴演奏或解释,或者从根本上说,不能以任何方式创新。没有加法改变,只有减法或换位改变……我们可以随心所欲地构造、剪切和拼贴。
现在,他们想出的规则是处理由人工智能生成的纯 MIDI 音符,而不是实际的音频样本,所以他们有更多的自由,但我喜欢他们的坚韧,并决定在同样的限制下工作。最终我想出了你一开始听到的音乐。
如果我再做一次,我想我会稍微放松一下约束,并尝试将人工智能生成的样本分层到一些更连贯的节拍上,至少保持稳定的节奏,因为人工智能样本非常有节奏和混乱。或者我会从生成的样本中拼接出某些声音,并在采样器中使用它们来创作我自己的旋律。
我还有一个假设,可能会提高模特的节奏感。不是以固定的 3 秒钟间隔随机切割训练输入并将其投入到模型中,而是将所有歌曲的时间扭曲为相同的速度。然后根据速度将它们分割成一个小节的持续时间或其他固定数量的节拍,并将其输入神经网络。如果你能给它输入训练数据,所有数据都有相同的规律节奏,它可能会选择更有节奏的队列,并学会发出更稳定的鼓声。下次要尝试的东西。
生成视觉效果
因为 Cover Me Badd 需要一个音乐视频,我需要一些视觉效果。我刚刚听说了这个叫做 Runway 的新应用,它非常棒,尤其是对于那些想要开始 ML 的艺术家来说。它开放了几十种不同的机器学习模型,经过预先训练,点击按钮即可使用。你只需输入或拖放你的输入(文本、图像、视频等),它将在你的本地机器或云中运行它,并给你结果。它也有一个很棒的 API,可以通过 MIDI、OSC 或 HTTP/JSON 接受输入并产生输出,所以你可以将其连接到许多不同的乐器/应用程序或你自己的代码中。

The image for the lyric “You had my heart inside your hand”
我决定在 Runway 中使用 AttnGAN 模型,它接受文本作为输入,生成图像作为输出。我把它连接到我写的 Javascript 上,一行一行地输入阿黛尔的“在深渊中翻滚”的歌词,每行一张图片。我真的很喜欢它所产生的抽象但令人不寒而栗的可识别的图像。
我首先想滚动所有的图像以及产生它们的歌词,然而,结果是一次看太多了。所以我删除了歌词,并使用 P5.js 编写了一个小算法,在图像滚动时将它们“融合”到一起。把它们扔在一起,还有维奥拉!我成功地避免了为我的封面和提交播放任何音乐!
我的朋友在聆听聚会上说的一句令人难忘的话是,“这个机器人需要学习让音乐变得更好!”嗯,是的,但是 200 美元是它能学会的最好的了。
数据去神秘化— DIKW 模型

首先了解全局将为这一旅程的成功奠定基础
总体而言,数据是科技和商业领域最大的新趋势之一。数据“专家”正迅速成为行业中薪酬最高的个人,每家公司都希望在数据能力的浪潮中冲浪。
它正在成为理解我们周围世界的一种基本方式。我们可以将数据科学视为认识论或一种认知方式。我们可以想一想,处理问题和解决问题的方法。
但正如任何新趋势一样,我们必须问自己:所有这些流行语实际上意味着什么?
什么是数据科学家?简而言之,比任何软件工程师更擅长统计,比任何统计学家更擅长软件工程的人。
本文的目标是揭开数据分析的神秘面纱。我们将解释这些流行语的含义,大数据能做什么和不能做什么,以及如果您要加入数据列车,应该探索哪些技术
本文是关于数据分析的四篇系列文章的第一篇。我们将从一些基础知识开始,然后在此基础上一步一步地解释计算和思维过程中更复杂和更强大的系统,并帮助您理解为什么每个人都对数据如此着迷。
迪克夫金字塔
在开始讨论数据分析之前,让我们从一个简单但极其重要的概念开始:DIKW 金字塔。虽然许多人熟悉金字塔,但很少有人了解如何解读它,如何使用它,以及他们自己的立场。

DIKW Pyramid
要详细说明这个概念,请听 Jennifer Rowley (2007):“通常信息是根据数据定义的,知识是根据信息定义的,智慧是根据知识定义的。”
现在让我们来解释金字塔的每一层。
数据只是一组信号或符号。仅此而已——只有噪音。它可能是服务器日志、用户行为事件或任何其他数据集。它是无组织的,未经加工的。它是惰性的。如果我们不知道这意味着什么,这是没有用的。
当你开始让数据变得有用时,你就获得了信息。当我们应用系统来组织和分类数据时,我们可以将这种非结构化的噪音转化为信息。这个阶段应该回答“什么”、“什么时候”和“谁”的问题。简而言之,信息是有意义的数据。这个“意义”可能是有用的,但并不总是有用的。
知识是旅程的下一步,也可能是最重要的一步。它隐含地需要学习。这意味着我们可以获取数据,对其进行分类和处理,生成信息,然后以一种有用的方式组织所有这些信息。信息可以帮助我们理解关系,而知识让我们发现模式。这是让我们建立预测模型并产生真实见解的基础。我喜欢的一个定义是,知识是一种心理结构,由积累的学习和对信息的系统分析构成。
智慧是最后的边疆。它允许我们正确地预测未来,不仅通过检测和理解模式,而且深入理解这些模式背后的“为什么”。智慧是关于未来的:它依赖于知识和模式模型,但它可以帮助塑造你的“直觉”和直觉,给你一个指数级的竞争优势。知识会因为现实的快速变化而快速老化,但智慧会更加僵化。目前,这是一项纯粹的人类技能,但人工智能正在快速追赶。当人工智能变得比人类智慧更好时,结果将是不可预测的。
下图完美地展示了这种思维模式:

A different view of the DIK(I)W Pyramid
这个例子还引入了'洞察力的概念,有时也称为'智能。这是智慧的零星体现。洞察力是连接知识和智慧的纽带。
虚假的例子
数据:下雨了
信息:一小时内气温下降了 5 度,湿度上升了 5%,下午 3 点开始下雨。
知识:湿度的快速增加,伴随着低压区引起的温度下降,将可能使大气无法保持水分和雨水。
智慧:根据观察和数学模型,我们可以预测未来下雨的原因和时间,而且我们可以如此快速系统地预测,不需要太多的分析。我们已经了解了蒸发、气流、温度梯度、变化和降雨之间发生的所有相互作用。
奖励积分
代表性启发式 被我们的大脑用来推断模式。我们的大脑使用其大部分能力来创造模式,并沉迷于试图理解和预测现实世界中的模式。这意味着在处理数据时,我们需要非常小心,避免过早下结论。知道我们有这种到处追逐和看到模式的倾向,可以帮助我们在推断模式时慢下来。这是一个值得单独写一篇文章的主题,但是最好从一开始就记住。
可用性偏差 与前面的概念有些关系。这是一种思维捷径,依赖于即时、紧急的信息,并试图仅使用最明显的信息来概括研究结果。在这种偏见下,人们倾向于对更近的信息做出更重的判断,使新的观点偏向最新或最接近的新闻。你可以在下面的文章中了解更多。
它是什么?它如何影响我们的决策过程
medium.com](https://medium.com/@anthony.figueroa/availability-heuristic-8b70e38afec8)
DIKW 等级的起源
不是数据科学。即使是工程领域也不行。这种心理框架的起源是诗歌。诗人 T.S .艾略特是第一个提到“DIKW 等级制度”的人,尽管他没有用那个名字来称呼它。1934 年艾略特在《岩石》中写道:
Where is the Life we have lost in living?
Where is the wisdom we have lost in Knowledge?
Where is the Knowledge we have lost in Information?
虽然这是第一次提到艺术中的等级制度,但不是唯一的一次。在管理和信息科学流行起来之前,弗兰克·扎帕在 1979 年提到了等级制度:
Information is not Knowledge,
Knowledge is not wisdom,
Wisdom is not truth,
Truth is not beauty,
Beauty is not love,
Love is not music,
and Music is THE BEST
参考
- 拉塞尔·l·阿科夫,“从数据到智慧”,《应用系统分析杂志》16(1989):3–9。
- 米兰·泽莱尼,“管理支持系统:走向综合知识管理”,《人类系统管理》7,第 1 期(1987):59–70。
- 米(meter 的缩写))库利,建筑还是蜜蜂?(伦敦:霍加斯出版社,1987 年)。
- 哈兰德·克利夫兰,“作为资源的信息”,《未来学家》,1982 年 12 月,第 34-39 页。
- 艾略特,岩石(费伯和费伯 1934)。
- 弗兰克·扎帕,“帕卡德鹅”在专辑乔的车库:第二和第三幕(塔记录,1979)。
- Nikhil Sharma,“数据信息知识智慧(DIKW)层次结构的起源”,(谷歌公司,2008 年 2 月)。
罗森布拉特的感知机,第一个现代神经网络
初学者深度学习快速入门。

在过去的十年里,机器学习已经在许多领域产生了变革性的影响,如认知神经科学、图像分类、推荐系统或工程。最近,神经网络和深度学习吸引了更多的关注,它们的成功被科学和主流媒体定期报道,例如 Deep Mind 的 AlphaGo 和 AlphaGo Zero 或最近的 AlphaStar 。这种新的兴趣部分是由于对开源库的访问,例如 TensorFlow 、 PyTorch 、 Keras 或 Flux.jl 等等。
虽然这种对高效和多功能库的更多访问通过减少实现深度学习算法所需的计算机科学知识,打开了创新应用的大门,但仍然需要对基础数学理论的良好理解,以提出用于所考虑任务的高效神经网络架构。不幸的是,社会对数学的形象可能会吓跑学生(参见纪录片 我是如何开始讨厌数学的 以获得例证)。缺乏数学素养也可能是政治和非技术行业经常对深度学习的表现和能力持怀疑态度或过于乐观的原因之一。此外,苏珊娜·沙特克最近发表了一篇文章,讨论为什么人们不信任人工智能以及为什么业界可能不愿意采用它。她列举的一个关键原因(尽管不是唯一的原因)如下:
在 IBM2018 年的一项研究中,63%的受访者认为缺乏技术技能是人工智能实施的障碍。
94%的高管认为人工智能是业务的关键,但只有 18%的高管大规模采用了人工智能。问题是对人工智能的不信任——我们…
towardsdatascience.com](/people-dont-trust-ai-we-need-to-change-that-d1de5a4a0021)
本系列的历史观点和目标
尽管深度学习只是在最近才成为主流媒体,但它的历史可以追溯到 20 世纪 40 年代初,由麦卡洛克和皮茨建立的第一个人工神经元数学模型。从那以后,科学文献中提出了许多架构,从 Frank Rosenblatt (1958 年)的单层感知器到最近的神经常微分方程 (2018 年),以解决各种任务(例如,下围棋、时间序列预测、图像分类、模式提取等)。下面的时间线(由法维奥·巴斯克斯提供)提供了深度学习历史的一幅相当准确的图片。

Thanks to Favio Vázquez for this amazing figure. Check out his posts, they are really good!
正如你所看到的,这段历史很复杂。因此,在数量有限的博文中涵盖所有这些不同的架构是不现实的。此外,这些神经网络结构中的一些可以从高级数学领域或者甚至从统计物理学中提取。这些系列不是详细讨论这些架构中的每一个,而是旨在逐步向初学者介绍深度学习背后的数学理论,它使用的基本算法,以及提供一些关于其发展的历史观点。为此,我们将从简单的线性分类器开始,如 Rosenblatt 的单层感知或逻辑回归,然后转到完全连接的神经网络和其他广泛的架构,如卷积神经网络或 LSTM 网络。其他各种主题,如凸和非凸优化,通用近似定理,或技术和道德的良好做法也将在路上解决。因为我们的目标是帮助初学者理解深度学习算法的内部工作原理,所以所有将要介绍的实现基本上都依赖于 SciPy 和 NumPy,而不是像 TensorFlow 这样高度优化的库,至少在可能的情况下。此外,为了教学和科学推广,本系列中使用的所有代码都可以在 GitHub [ 此处 ]上免费获得。事不宜迟,让我们开始吧!
麦卡洛克和皮茨的人工神经元模型(1943 年)
人工神经元的第一个数学模型是由沃伦·麦卡洛克(1898-1969,美国神经生理学家)和小沃尔特·h·皮茨(1923-1969,美国逻辑学家)在 1943 年提出的阈值逻辑单元。然而,在深入研究他们的模型之前,让我们先快速回顾一下生物神经元实际上是如何工作的。


Left: Warren S. McCulloch. Right: Walter H. Pitts Jr.
生物神经元的高级描述
神经元是大脑的组成部分。简而言之,神经元是电可兴奋的细胞,通过专门的连接与其他细胞进行交流。存在不同的生物模型来描述它们的属性和行为,例如
- 早在 1907 年,路易斯·拉皮克(1866-1952,法国神经科学家)就提出了整合-发射模型。
- 霍奇金-赫胥黎模型,以获得 1963 年诺贝尔生理学和医学奖的艾伦·a·霍奇金(1914–1998,英国生理学家和生物物理学家)和安德鲁·f·赫胥黎(1917–2012,英国生理学家和生物物理学家)命名。
- 以理查德·菲茨休(1922–2007,美国生物物理学家)和 j·南云(日本工程师)命名的菲茨休-南云模型,基本上是霍奇金-赫胥黎模型的简化。
- 或者是尤金·m·伊兹基科维奇(生于 1967 年,俄罗斯数学家)最近的脉冲神经元模型。
尽管这些模型中的一些开始被采用作为复杂神经网络的构建模块(例如,参见脉冲神经网络),我们此后将限制我们自己对神经元的非常高级的描述。下图显示了示意图。出于我们的目的,我们只对以下元素感兴趣:

Schematic representation of biological neuron. From Wikipedia.
- 树突,也称为树突,是一个神经细胞的分支原生质延伸,它将从其他神经细胞接收到的电化学刺激传播到细胞体(或细胞体)。
- 胞体是从树突接收到的信号汇合并传递的地方。它包含许多细胞器以及细胞核。
- 轴突丘是连接轴突的细胞体的特殊部分。正是它控制着神经元的放电。如果它接收到的信号的总强度超过了阈值,神经元就会向轴突发出一个信号(称为动作电位)。
- 轴突是从胞体向下延伸到末端的细长纤维。它的作用是通过它的突触将神经信号传递给其他神经元。
- 突触是位于连接神经元和其他神经细胞的轴突末梢最末端的小间隙。在那里,神经递质被用来将信号通过突触传递给其他神经元。
生物神经元的工作原理可以总结如下。首先,它从其树突(即,从其他神经元)获取输入。第二步,在 soma 中对这些输入进行加权求和。结果然后传递给轴突小丘。如果这个加权和大于阈值限制,神经元将会触发。否则,它将保持静止。我们神经元的状态(开或关)然后通过其轴突传播,并通过其突触传递给其他连接的神经元。虽然非常简单,但这种对生物神经元工作原理的高级描述足以理解麦卡洛克和皮茨在 1943 年提出的人工神经元的数学模型。
人工神经元的数学模型
基于对神经元工作原理的基本理解,麦卡洛克和皮茨在他们的开创性论文中提出了第一个人工神经元的数学模型,这是早在 1943 年神经活动中固有思想的逻辑演算。尽管非常简单,他们的模型已经被证明是非常通用和容易修改的。今天,他们最初模型的变体现在已经成为大多数神经网络的基本构建模块,从简单的单层感知器一直到微软用来赢得 2016 年 ImageNet 竞赛的 152 层深度神经网络。
麦卡洛克&皮茨的神经元模型,以下简称为 MCP 神经元,可由以下规则定义:
- 它有一个二进制输出 y ∈ {0,1},其中 y =1 表示神经元启动, y =0 表示它处于静止状态。
- 它有 n 个兴奋性二进制输入 xₖ ∈ {0,1}。
- 它有一个单一的抑制输入 i 。如果它是开着的,神经元就不能激发。
- 它有一个阈值θ。如果它的输入总和大于这个临界值,神经元就会触发。否则,它将保持静止。
给定输入x=【x₁、x₂、x₃、 … 、xₙ ]ᵀ,抑制输入 i 和阈值θ,输出 y 计算如下

对于任何具有神经网络基础知识的人来说,这样的模型看起来可疑地像现代人工神经元,这正是因为它是!
许多不同的论文和博客帖子已经展示了如何使用 MCP 神经元来实现不同的布尔函数,如 OR、and 或 NOT。下面用马文·明斯基的符号来说明这些。

Three boolean functions are modeled using MCP neurons. For more details, see the post mentioned below by Akshay Chandra Lagandula
必须强调的是,通过堆叠多个 MCP 神经元,还可以表示更复杂的功能(例如,触发器、除以 2 等)。尽管有这种灵活性,MCP 神经元仍有很大的局限性,即
- 单个 MCP 神经元不能代表 XOR 布尔函数或任何其他非线性函数。
- 所有的突触权重都被设置为 1,这意味着所有的输入对输出的贡献是相等的。
- 所考虑的功能需要由用户硬编码。无法从数据中得知。
- 绝对抑制规则(即如果抑制输入 i 开启,神经元不能触发)限制性太强。
尽管如此,MCP 神经元在当时的研究界引起了极大的兴奋,半个多世纪后,引发了现代深度学习。在这个过程中,最重要的改进之一,解决了 MCP 神经元的一些限制,来自于弗兰克·罗森布拉特和他的感知机。
注: 阿克谢·钱德拉·拉甘杜拉去年夏天出版了一本关于麦卡洛克·皮茨的《神经元》的精彩介绍。最值得注意的是,他举例说明了布尔函数(例如 AND、OR 等)是如何使用这个模型实现的。对于更深入的细节(和漂亮的数字),强烈鼓励感兴趣的读者去看看。
[## 麦卡洛克-皮茨神经元——人类第一个生物神经元的数学模型
众所周知,深度神经网络的最基本单元被称为人工神经元/感知器…
towardsdatascience.com](/mcculloch-pitts-model-5fdf65ac5dd1) [## 感知器:人工神经元(麦卡洛克-皮茨神经元的本质升级)
深度神经网络的最基本单元被称为人工神经元,它接受输入,处理它…
towardsdatascience.com](/perceptron-the-artificial-neuron-4d8c70d5cc8d)
罗森布拉特的单层感知器(1957 年)
在麦卡洛克和皮茨之后大约 15 年,美国心理学家弗兰克·罗森布拉特(1928-1971)受到突触可塑性(即学习过程中大脑神经元的适应)的赫比理论的启发,提出了感知器,这是对 MCP 神经元模型的一个重大改进。这项发明让他获得了国际认可,迄今为止,电气和电子工程师协会(IEEE),“世界上最大的专业协会,致力于推动技术创新和卓越,造福人类”,以他的名字命名其年度奖项。


Left: Frank Rosenblatt, from Wikipedia. Right: Mark I Perceptron machine, the first implementation of the perceptron algorithm. From Wikipedia as well.
罗森布拉特的主要成就是表明,通过放松 MCP 的一些规则(即绝对抑制、所有输入的平等贡献以及它们的整数性质),人工神经元实际上可以从数据中学习。更重要的是,他为这种改进的 MCP 神经元模型提出了一种监督学习算法,使人工神经元能够自己直接从训练数据中计算出正确的权重。在深入机器学习有趣的东西之前,让我们快速讨论一下感知器可以解决的问题类型。
二元分类
二进制(或二项式)分类是基于规定的规则将给定集合的元素分类成两组(例如,分类图像是描绘猫还是狗)的任务。下图描述了此类问题的两个实例。在左边,任务是识别两个线性可分的类之间的分界线(即分界线是简单的直线),而在右边,两个类是非线性可分的(即分界线是而不是简单的直线)。

Examples of linear and nonlinear binary classification problems. In the rest of this post, we will consider only example (a).
正如我们将看到的,罗森布拉特的感知器只能处理线性可分类的分类任务。然而,必须注意的是,右图中的例子也可能被感知器处理,尽管它需要一个称为特征工程的输入预处理,以将其转换成一个线性可分问题。这将在以后的帖子中解决(希望如此)。
为了更好地理解感知器处理二元分类问题的能力,让我们考虑它所依赖的人工神经元模型。

Artificial neuron used by the perceptron. From Wikipedia.
正如你所看到的,这个神经元与麦卡洛克&皮茨在 1943 年提出的非常相似。然而,它有一些主要的区别,即
- 神经元接受与突触权重 b 相关的额外恒定输入(在上图中表示为θ),也称为偏差。关于 MCP 神经元,偏差 b 仅仅是激活阈值的负值。
- 突触权重 wₖ 不限于一,因此允许一些输入比其他输入对神经元的输出有更大的影响。
- 它们也不局限于严格为正。因此,一些输入可能具有抑制性影响。
- 绝对抑制法则不再适用。
在数学术语中,感知器所依赖的人工神经元的非线性是

该函数对应于 Heaviside 函数(即 H ( z ) = 0,如果 z < 0,否则 H ( z ) = 1)。请注意,感知器的等效公式(其中二进制输出定义为 y ∈ {-1,1})考虑的是符号函数,而不是亥维赛函数,即

无论公式是什么,感知器(和许多其他线性分类器)的决策边界是这样的

或者,使用我们简洁的数学符号

该决策函数线性依赖于输入 xₖ ,因此得名线性分类器。此外,这个方程是一个超平面(1D 的一个简单点,2D 的一条直线,3D 中的一个规则平面,等等)的方程。突触权重的向量 w 垂直于该平面,而偏差 b 是从原点的偏移。既然我们对罗森布拉特的感知器为什么可以用于线性分类有了更好的理解,那么有待回答的问题是
给定一组 m 个例子( x ₘ,yₘ),感知器如何学习正确的突触权重 w 和 bias b 以正确区分两类?
感知机学习算法
如前所述,Rosenblatt 的主要成就不仅表明他对 MCP 神经元的修改实际上可以用于执行二进制分类,而且还提出了一种相当简单但相对有效的算法,使感知器能够从示例中学习正确的突触权重 w 。该算法如下所示

在继续讨论 Python 实现之前,让我们考虑四个简单的思想实验来说明它是如何工作的。
- 假设 mᵗʰ示例 x ₘ 属于类别 yₘ =0,并且感知器正确预测 ŷₘ =0 。在这种情况下,重量修正由δw=(0-0)xₘ给出,即我们不改变重量。这同样适用于偏见。
- 同样,如果 mᵗʰ例子 x ₘ 属于类 yₘ =1,感知器正确预测 ŷₘ =1,那么权重修正为δw= 0。这同样适用于偏差。
- 现在假设 mᵗʰ例子 x ₘ 属于类别 yₘ =0,并且感知机错误地预测 ŷₘ =1 。在这种情况下,权重修正由δw=(0–1)xₘ=–xₘ给出,而偏差更新为b=b–1。
- 最后,如果 mᵗʰ例子 x ₘ 属于类 yₘ =1 而感知器错误预测 ŷₘ =0,权重修正为δw=xₘ。偏差也根据 b = b+ 1 更新。
如你所见,这个算法非常简单。然而,乍一看,为什么这样一个简单的算法实际上可以收敛到一组有用的突触权重,这可能还不清楚。虽然相对简单,收敛的证明将不会在这里提出,实际上将是一个即将到来的职位的主题。对于这篇文章的其余部分,只要做出一个信念的飞跃,相信我,它确实会收敛。与此同时,如果你是一个怀疑论者或者仅仅是不相信,你可以看看阿克谢·钱德拉·拉甘杜拉的帖子,从几何学的角度直观地了解它为什么有效。
本帖将讨论 Minsky 和 Papert 在 1969 年提出的著名的感知器学习算法。这是一个…
towardsdatascience.com](/perceptron-learning-algorithm-d5db0deab975)
现在让我们继续有趣的事情,用 Python 实现这个简单的学习算法。假设您已经熟悉 Python,下面的代码应该是不言自明的。
请注意,为了清晰和易用,我们将在整个课程中尽量坚持使用 scikit-learn API。在我的 towards data science Github repo(此处)上可以免费获得该代码的扩展版本(带有各种健全性检查和其他内容)。我们的模型学习到的最终决策边界如下所示

Linear decision boundary learned by the perceptron.
对于这个特定的例子,我们的感知器在整个数据集上经过三次,才正确地学习到这个决策边界。虽然它正确地对我们训练数据集中的所有例子进行了分类,但我们将在后面的帖子中看到,感知器的泛化能力相当有限,特别是由于它的边缘很小,并且对有噪声的数据非常敏感,这甚至可能阻止学习算法收敛。尽管如此,请不要犹豫,从 Github 下载相应的脚本,并使用这个简单的实现来建立您对它为什么工作、如何工作以及它的局限性的直觉。毕竟,
锻造造就铁匠,航海造就水手,熟能生巧。
感知器的消亡
这种学习算法对于线性可分问题的简单性和效率是它在 20 世纪 50 年代末和 60 年代初如此流行的一些关键原因。然而,这种受欢迎程度导致罗森布拉特夸大了他的感知学习能力,在科学界引起了不切实际的期望,媒体也报道了这一点。正如我们将在后面的文章中看到的,这种感知机确实有很大的局限性,极大地限制了它在现实生活中的应用。的奇招来自马文·明斯基(1927–2016,美国认知科学家)和西蒙·派珀特(1928–2016,南非裔美国数学家),他们在 1969 年出版了臭名昭著的名著感知机:计算几何导论。在本书中,作者展示了 Rosenblatt 的感知器(以及任何其他单层感知器)实际上是多么有限,而且值得注意的是,它无法学习简单的逻辑异或函数。有人认为,这本书的出版和对感知机极限的展示引发了 20 世纪 80 年代所谓的人工智能冬天…
结论
本文是我在法国巴黎国立高等艺术学院教授的深度学习入门系列文章的第一篇。由于我们必须先学会走,然后才能跑,因此我们的注意力一直集中在深度学习的非常初步的方面,从历史和数学的角度来看,即麦卡洛克&皮茨的人工神经元模型和罗森布拉特的单层感知器。因为这些是现代神经网络的非常基本的构建模块,所以在进入现代深度学习之前,不要犹豫,尽可能多地阅读它们,并玩 Jupyter 笔记本,以确保您完全掌握它们的属性和限制。我知道在单层感知器上给一个帖子贴上深度学习的标签可能有些牵强。然而,即使可以在网上找到大量的教程(有些真的很好,有些有点可疑)来运行深度学习库,如 TensorFlow,而不需要对底层数学的深刻理解(没有双关语),拥有这样的见解将被证明是非常有价值的,并防止你后来屈服于深度学习的常见陷阱。所以我们一步一步来,好吗?
在接下来的几篇文章中,我们将讨论以下主题:
- 感知器收敛定理。
- 罗森布拉特感知器的极限,走向灭亡的途径。
自适应线性神经元和 Delta 规则
towardsdatascience.com](/improving-upon-rosenblatts-perceptron-d0517d3c5939)
最后,你会在下面找到一个关于麦卡洛克&皮茨神经元和罗森布拉特感知器的历史和数学的附加在线资源列表。不要犹豫,看看这些,因为它们可能会处理一些我们只见过的方面!
PS:如果你知道任何其他相关链接,不要犹豫给我发消息,我会编辑帖子来添加它:)
其他在线资源
- Sebastian Raschka 关于 单层神经网络和梯度下降 的博文。
- Jonty Sinai 的博客文章简单地命名为 感知器 。
- Amanda Gefter Nautilus 关于 Walter Pitts 不可思议的历史。
想阅读更多此类内容吗?查看我其他关于低秩结构和数据驱动建模 的文章或者干脆我的 机器学习基础知识 !
有没有想过我们为什么使用它,它来自哪里,如何有效地优化它?这里有一个解释(代码…
towardsdatascience.com](/binary-cross-entropy-and-logistic-regression-bf7098e75559)
清除编程面试任务:Python 中的 RSS 提要解析器
如何使用 Python 完成数据科学和数据工程面试编程任务
最近一直在面试数据科学家的职位。其中一家公司给了我一个任务,用 python 创建一个 RSS 提要解析器。它以增量方式获取提要条目,并将它们存储在数据库中。
完整代码可以在github上找到。
问题阐述
因此,与其深入技术细节,我想回顾一下问题的背景。
对于那些不知道的人来说,RSS 是一种基于网络的内容(或提要)共享格式。(https://en.wikipedia.org/wiki/RSS)。以下是手头问题的细节:
- 要解析的 RSS 提要是 印(https://audioboom.com/channels/4930693.rss)
- 需要设计一个合适的数据模型来表示每个帖子
- 任何支持 python 连接的关系数据库都可以用来存储 post 数据
- 禁止使用能够进行 RSS 解析的库(如 feedparser)
- 负载应该是递增的,即只有先前没有处理的记录应该被处理
- 应该安排脚本每天运行一次以获取更新
方法和系统设计
显然我决定用 python 3.7 ,用生命终结支持来换 python 2.7 。以上基本上意味着我必须自己实现 RSS 解析器。考虑到 1 天的时间限制,所有其他决定都非常简单,为这项工作留出 3-4 个小时(假设每天工作 8-9 个小时)。下面是我最终使用的方法:
1。RSS 解析器库的限制,基本上指望我自己写解析器。由于它最终是基于 xml 的内容,我决定使用一直可靠的 BeautifulSoup 库(【https://www.crummy.com/software/BeautifulSoup/bs4/doc/】) 2。我选择的关系数据库是postgres(https://www.postgresql.org/)。没有特别的原因,除了易用性和熟悉度,显然还有疯狂流行的开源支持。
3。库 自动调度器(【https://apscheduler.readthedocs.io/en/latest/index.html】)每天调度一次任务(简单的库开始, 气流(【https://airflow.apache.org/】库此外,由于没有给出环境规范,我决定使用两个docker(https://www.docker.com/)容器来构建所有这些,一个用于,一个用于**
有了上面分享的方法,让我们开始实施吧!
设置事物
首先设置 docker 环境和容器:
1.为容器创建一个单独的网络进行交互:
***docker network create rss***
2.使用数据库名称、密码的环境变量创建 postgres 容器。公开端口,设置绑定挂载和工作目录:
***docker run -d --name rss-postgres \
--net=rss \
-e POSTGRES_DB=audioboom \
-e POSTGRES_PASSWORD=parserssfeed \
-p 5432:5432 \
-v $(PWD):/home \
-w /home \
postgres***
3.创建 python 容器,绑定挂载,设置工作目录并运行它:
***docker run -dt --name rss-python \
--net=rss \
-v $(PWD)/src:/home/src \
-w /home/src \
conda/miniconda3-centos6 bash***
4.为 python 安装必要的库:
***docker exec rss-python conda update -c base -c defaults conda
docker exec rss-python conda install beautifulsoup4 lxml psycopg2
docker exec rss-python conda install -c conda-forge apscheduler***
让我们现在开始构建我们的数据模型…
创建数据模型
看了一些帖子后,我意识到需要三个实体:
1。 帖子:保存 feed 上发布的每个帖子的条目
2。itunes_data: 一篇文章可以有选择地包含它的 itunes 列表的链接。媒体:一篇文章可以呈现 0 个或多个媒体对象
跟踪这三个实体几乎包含了整篇文章。
请使用此 github 链接 进行精确的创建表查询(因为它们非常简单)
可以通过运行以下命令一次性创建表:
***docker exec -it rss-postgres psql -U postgres -d audioboom -f create_db.sql***
编码开始…
助手模块 除了主脚本之外,还创建了三个脚本来抽象一些带有函数调用的底层功能:
****1。content _ fetcher . py:用于半健壮地处理网页请求,并返回其内容
2。data _ parser . py:将网页内容转换为 BeautifulSoup 对象进行解析,解析 feed 中给定的 RSS post 记录,并返回相同的字典。
3。DB _ connect . py:包含 DB helper 函数,用于获取连接、获取已有记录的计数(用于增量加载)以及执行给定的查询。
Main.py!!!
最后,让我们构建将所有部分连接在一起的脚本…
1。 导入:下面几行将导入所需的模块和对象
***from data_parser import get_soup, parse_record, store_tags
from db_connect import get_connection, get_max_records,execute_query
from apscheduler.schedulers.blocking import BlockingScheduler***
****2。我们还将定义一些全局变量(我知道这不是一个推荐的做法,但考虑到时间限制,这是我们都必须采取的一个折衷方案)
***# Query to find the max record processed so far
get_max_query = 'SELECT COALESCE(max(itunes_episode),0) FROM tasteofindia.posts;'# Query template to insert values in any table
query_string = 'INSERT INTO tasteofindia.{0} ({1}) VALUES ({2}{3});'# List of columns present in the table
col_list = {
'posts' : [<check the github script for the actual names>]
,'itunes_data' : [<check the github script for the actual names>]
,'media' : ['itunes_episode','url','type','duration','lang','medium']
}# Creating insert queries for all the tables from template
query_strings = {k: query_string.format(k , ','.join(col_list[k]),('%s,'*(len(col_list[k])-1) ),'%s' ) for k in col_list}***
未显示 帖子& itunes_data 的列列表。同样请参考 github 链接 。放给itunes _ episode看,了解一下大意。****
3。begin(feed _ URL,db _ credential _ file):获取凭据文件上的的连接,并开始解析来自 feed url 的 feed:****
***def begin(feed_url,db_credential_file):
try:
connection = get_connection(db_credential_file)
update_feed_data(feed_url,connection)
except Exception as e:
print('Error Received...')
print(e)
finally:
print('Closing connection')
connection.close()***
一个简单的功能,开始所有的骚动,让事情动起来。
4。update _ feed _ data(feed,* conn ): 请求给定 url 的 BeautifulSoup 对象并尝试处理其中的任何记录:*****
***def update_feed_data(feed,conn):
content = get_soup(feed)
print(f"Processing Records for : {feed}")
records = content.find_all('item')
process_records(records,conn)
return***
同样,按照函数范式,它通过检索 BeautifulSoup 对象来完成工作,并传递内容以供进一步处理。
5。process_records(
***def process_records(content,conn):
record_count = len(content)
current_max = get_max_records(conn,get_max_query)
print('Current Max : ',current_max)
records = {} if record_count == current_max:
print("No new records found!!")
return records print(f"Total Records Found: {record_count}. Currently present: {current_max}") # List comprehension on the result of map operation on records
[persist_taste_of_india_record(conn,record) for record in map(parse_record, content[record_count-current_max-1::-1])] return records***
这是最大的功能。它检查是否找到新记录。如果是,它首先为每个记录调用parse _ record(),然后继续保存记录。****
6。persist _ tastse _ of _ India _ record(conn,* data ): 它尝试分别持久化帖子的每个组成部分(基于定义的实体)*****
***def persist_taste_of_india_record(conn,data):
persist_record(conn,data,'posts')
persist_record(conn,data['itunes'],'itunes_data')
for media in data['media']:
persist_record(conn,media,'media')
conn.commit()
return True***
conn.commit() 是必需的,否则数据库中的更改不是永久的,并且会在会话过期后丢失。
7。persist _ record(conn,* data ,TB _ name):根据对象类型执行插入查询:*****
***def persist_record(conn,data,tb_name):
query_param = tuple(
list(map(lambda k : data[k],col_list[tb_name]))) execute_query(conn,query_strings[tb_name],query_param)
return***
query_param 只是将列顺序中的值存储在一个元组中。
execute _ query()最后将数据插入数据库
8.执行并调度它:脚本通过调用 begin 函数并调度它每天执行一次来完成,如下所示:****
***if __name__ == '__main__':
feed_url = 'https://audioboom.com/channels/4930693.rss'
db_credentials = 'connection.json' print('Main Script Running...')
begin(feed_url,db_credentials)
scheduler = BlockingScheduler()
scheduler.add_job(begin, 'interval',[feed_url,db_credentials], hours=24) try:
scheduler.start()
except Exception as e:
print('Stopping Schedule!!') print('Main Script Exiting!!')***
我在这里使用了阻塞调度程序,因此 python 线程总是活跃的。如果您想要停止执行,那么 try…catch 块将干净地退出。现在,您只需使用以下命令执行主脚本,立即运行一次,并安排在每天同一时间运行一次:
***docker exec -d rss-python python main.py***
瞧啊。
就是这样。您已经准备好一个 RSS 解析器,每天运行并更新数据库。
提高
显然,许多升级和增强是可能。许多最佳实践没有被遵循。坚实的原则,后台调度程序,使用 docker 编写文件等可能是第一步。在构建这个系统的时候,我首先关注的是得到一个功能性的系统,并在重构和设计上花费最少的精力。
尽管如此,请留下您的评论,并随时通过 github 联系我。
RTest:R 包的漂亮测试
specflow 和 cucumber.io 支持非编码人员解释 R 包的测试报告,此外还允许非编码人员创建测试用例。简单 r 包验证的一步。

by startupstockphotos http://startupstockphotos.com/post/143841899156
目录
- 为什么要 RTest?
- 【RTest 有什么特别之处?
- RTest的测试实现示例。
- 延伸阅读
为什么是 RTest?

在 R 中测试似乎很简单。从使用usethis::test_name("name")开始,然后在test that中用类似expect_equal的功能编写测试代码。网上可以找到很多教程,甚至有一整本书都是关于“[测试 R 代码](https://www.amazon.de/gp/product/1498763650/ref=as_li_tl?ie=UTF8&camp=1638&creative=6742&creativeASIN=1498763650&linkCode=as2&tag=zappingseb-21&linkId=ca15df0c474acdcf98c8750db741c4e3">Testing R Code (Chapman & Hall/Crc the R)<img src="//ir-de.amazon-adsystem.com/e/ir?t=zappingseb-21&l=am2&o=3&a=1498763650)”的。可悲的是,这不是我能走的路。正如我几次提到的,我在一个受到严格监管的 T21 环境中工作。在这样的环境中,你的测试不仅会被编码员检查,也会被不会编码的人检查。你的一些测试甚至会由不会编码的人来编写。像 specflow 或 cucumber 这样的东西会真正帮助他们编写这样的测试。但是这些在 r 中是不存在的。另外,这些人不能阅读命令行测试报告。你可以训练他们这样做,但我们认为为我们和他们提供一个漂亮的测试环境更容易,这个环境叫做 RTest 。
如果你想了解更多关于开发这样一个环境的原因,你可以阅读文章:为什么我们需要对一种编程语言进行人类可读的测试。
RTest 有什么特别之处?
为了解释我们将哪些特性放入 RTest 中,我将开始描述一个基本的测试工作流程。
1 测试代码从写代码开始。你的 R 包将包含函数、类和方法。应对这些进行测试。
2 编写测试现在主要包括这样的调用:
*my_function(x,y){sums_up(x,y) return(z)}x=3
y=4
z=7stopifnot(my_function(x,y)==z)*
很容易看出,如果你的函数my_function不能将两个值相加,你的测试将会失败。您将创建一组这样的测试,并将它们存储在您的包的一个单独的文件夹中,通常称为tests。
3 之后你可以运行所有这样的测试。您可以在tests文件夹中包含一个脚本,或者使用 testthat 并运行testthat::test_dir()。
4 如果你的一个测试失败了,脚本会停止并告诉你哪个测试在控制台中失败了。这描述了下图所示的 4 个步骤。

RTest 现在的特别之处在于两个主要步骤。
- 测试的定义
- 测试执行的报告
对于测试的定义,我们决定使用 XML。为什么是 XML?XML 不仅仅比纯 R 代码更容易阅读,它还有一个特性,叫做 XSD;“XML 架构定义”。我们创建的每个 XML 测试用例都可以立即对照开发人员设计的模式进行检查。它也可以与我们自己的Rtest.xsd进行核对。这意味着测试人员可以在执行测试用例之前仔细检查它们。这为我们节省了大量的时间,并且给所有的测试用例一个固定的结构。
报告是用 HTML 实现的。这是因为 HTML 自带了许多用于报告的特性。它允许测试结果着色,链接到测试用例并包含图像。 RTest 和test之间的 HTML 报告的主要区别在于,RTest 报告每个应该执行的测试,而不仅仅是失败的测试。测试报告还将包括由函数调用创建的值和作为参考给出的值。读者可以看到比较是否正确。这样,测试报告包含的信息比测试和控制台日志包含的信息多得多。
使用 RTest 的测试实现示例
请注意,整个示例存储在一个 github gist 中。如果你喜欢这个例子,请列出要点。
- 给定一个对两列求和的函数:
*my_function <- function(data = data.frame(x=c(1,2),y=c(1,2))){stopifnot(dim(data)[2]==2)data[,"sum"] <- apply(data,1,function(x){sum(x)})return(data)}*
2.我们希望有一个成功的和一个不成功的测试。两者在 XML 文件中都有三个部分:
*<params><reference><testspec>*
params账户输入参数
reference为输出数据帧
testspec测试是否静默运行,容差是多少
对于成功的测试,我们的测试应该是这样的:
您可以立即看到 RTest 的一个特殊功能。它允许为多个测试使用数据集,我们将这些数据集存储在input-data标签中。这可以节省文件中的空间。这里将使用数据集test01。此外,可以为每个测试给出测试描述。对于存储在 XML 中的每个 data.frame,列的类型可以在col-defs中给出。这些都是数字。
这里给出了input-data:
这是一个数据帧,其中 x 列只携带 1,而 y 列只携带 2。该测试应创建一个数据帧,每行的 sum 列为 3。
我们可以通过改变reference标签让测试失败,而不是在sum列中只有 3,我们可以添加一个 3.5 让测试失败。整个测试用例可以在有 90 行的 github gist 中找到。
3.测试用例的执行只是一行代码。您应该在 XML 文件目录中有您的工作目录,并且应该在全局环境中定义my_function。
*RTest.execute(getwd(),"RTest_medium.xml")*
4.测试报告现在包含一个成功测试和一个失败测试。两者都将被可视化:

General test outcome in RTest test report
所有测试都有附加信息。对于失败的测试,我们将总和设置为 3.5 而不是 3。它在表的末尾报告:

example of a failed data frame comparison in RTest
此外,报告还包含测试运行环境的信息:

System information for an RTest test report
就是这样。现在你可以用 RTest 测试任何包。
进一步阅读
- RTest github 知识库
- RTest 文档网站
- 为什么我们需要对编程语言进行人类可读的测试?
- 作者的 LinkedIn p 年龄
RTX 2060 Vs GTX 1080Ti 深度学习基准:最便宜的 RTX 卡 Vs 最贵的 GTX 卡
使用带有 fast.ai 和 PyTorch 库的 CIFAR-10 和 CIFAR-100 数据集对 2060 和 1080Ti 进行训练时间比较。

TLDR #1 : 尽管只有一半的 VRAM,一半的零售价格,RTX 2060 在计算机视觉中可以突破 1080Ti,一旦它的张量核心在py torch+Fastai中被激活。
不到一年前,凭借其 GP102 芯片+ 3584 个 CUDA 内核+ 11GB 的 VRAM, GTX 1080Ti 是上一代英伟达帕斯卡系列(泰坦版除外)的顶级 GPU。需求如此之大,以至于零售价格经常超过 900 美元,远远高于 699 美元的官方建议零售价。
2018 年秋季,英伟达推出了最新的图灵阵容,命名为“RTX”,拥有光线追踪核心和张量核心。整体价格大幅上涨:例如,RTX 2080Ti 的零售价为 1150 美元甚至更高。
图灵/ RTX 范围内的机器学习的一个关键特征是 张量核心 :根据英伟达的说法,这使得计算可以在“浮点 16”而不是常规的“浮点 32”中运行,并将训练深度学习模型的时间缩短了 50%。
大约一个月前(2019 年 1 月 7 日),英伟达发布了图灵系列中最便宜的 GPU:RTX 2060。
使用 Jupyter 笔记本,我在每个 Cifar 数据集上用 FP32 和 FP16 训练了 ResNet 模型 18 到 152,以比较 30 个时期所需的时间。
有了 Fastai,从 FP32 切换到 FP16 训练就像添加 * 一样简单。to_fp16() * 在你的常规代码的末尾。
- 常规 FP32 版本,带有预训练的 Resnet 18 模型:
learn = create_cnn(data, models.resnet18, metrics = accuracy)
- FP16 版本:
learn = create_cnn(data, models.resnet18, metrics = accuracy)***.to_fp16()***
就这样,你现在可以访问 RTX 张量核心了!
注:关于“FP16”训练的更多信息,也称为“混合精确训练(MPT)”,查看那些优秀的帖子。
TLDR 排名第二。
****
注:“bs * 2”表示 batch_size 大两倍,如 256 比 128。
设置
****硬件:我使用的是一台“现实生活”的高端游戏电脑,具有以下规格
- AMD 锐龙 7 1700X 3.4GHz 8 核处理器
- MSI X370 Krait 游戏主板
- 32 GB DDR 4–2400 内存
- 1 TB Nvme 三星 960 EVO
- 华硕 GTX 1080 ti-11GB Turbo(800 美元)
- 巴利特 RTX 2060–6GB(350 美元)
这些零件是我个人使用的,没有任何公司、出版商或供应商支付或赞助。
****软件:我双开机用的是 Ubuntu 和 Windows 10。
- Ubuntu 18.04 + Anaconda/Python 3.7
- CUDA 10
- PyTorch 1.0 + fastai 1.0
- Nvidia 驱动程序 415.xx
注意:在每次培训之前,这些卡被切换到一个辅助 PCie 插槽(x8 ),不处理 PC 双显示器,从而确保他们的计算能力 100%集中在培训上。
我提到这一点是因为我在一台 2007 Ergotron LX 双支架 (我有史以来购买的最好的长期电脑!):一个 24 英寸的 1080p(垂直)和一个 27 英寸的 1440p(横向)都连接到同一个 GPU,因此人们可以认为它会从培训中窃取“一些”计算能力。

A screenshot of my dual monitors: the 24" vertical on left, the 27" landscape on right.
顺便说一句,如果你想检查双显示器对训练表现的影响,请使用 1080Ti 向下滚动文章底部进行比较。
两种 GPU 规格的快速总结。
GTX 10 人阵容中的 1080 Ti(最后一位):

RTX 20 强阵容中的 2060(第一个):

要点:
- RTX 2060 的 CUDA 内核数量大约是 1080Ti 的一半(1920 对 3584)
- 它的内存带宽大约是 1080Ti 的 70%(336 对 484 GB/s)
- 它有 240 个张量核(来源)用于深度学习,1080Ti 没有。
- 它的额定功耗为 160W,带有一个 8 针连接器,而 1080Ti 的额定功耗为 250W,需要一个双 8+6 针连接器。
- 它的价格不到 1080Ti(在瑞典斯德哥尔摩)零售价的一半。
附加信息:
- 方法:为了保持可比性,我在三个版本中运行了每个基准测试。
-版本“ FP32 ”和版本“ FP16 ”对 1080Ti 和 2060 使用了相同的 batch_size(有人可能认为 1080Ti 的 VRAM 大约是 2060 的两倍,但我选择了这种方法。您可以自行运行测试)。
-版本“ FP16 bs*2 ”使用了两倍大的 batch_size,以受益于 FP16 训练背后的理论(详见上面两个链接的帖子)。 - 我使用的 Jupyter 笔记本,包括 30 个纪元的所有持续时间,都可以在我的 GitHub repo 中找到。你需要法斯泰·V1 来运行它们。
- 我用来计算持续时间、时间尺度和图表的电子表格也在回购协议中。
CIFAR-10 基准测试
Resnet 18
- “完成 30 个周期的时间”的持续时间(秒):

- 时标:

Resnet-34
- 持续时间(秒):

- 时标:

Resnet 50
- 持续时间(秒):

- 时标:

Resnet 101
- 持续时间(秒):

- 时标:

Resnet 152
- 持续时间(秒):

- 时标:

CIFAR-100 基准测试
Resnet 18
- 持续时间(秒):

- 时标:

Resnet 34
- 持续时间(秒):

- 时标:

Resnet 50
- 持续时间(秒):

- 时标:

Resnet 101
- 持续时间(秒):

- 时标:

Resnet 152
- 持续时间(秒):

- 时标:

奖金:
我比较了 1080Ti 作为红色独立 GPU(无显示器)和蓝色主 GPU(处理双显示器,参见前面的讨论)的性能。
注:我用的是 Cifar-10。
- 持续时间(秒):

- 时标:

我们如何重新控制个人数据
回归去中心化网络
数据是驱动我们经济的“新石油”,但最近的数据泄露事件表明,我们或许应该对分享我们的数据保持警惕。重新控制我们个人数据的方法是回到一个去中心化的网络,这对消费者和公司来说都是一个双赢的局面。
服务的交易数据
2018 年 3 月,很明显,剑桥分析公司出于政治目的使用了数百万脸书用户的个人数据。这一丑闻痛苦地表明,我们以前多么不担心自己的个人数据。事实上,我们对自己数据缺乏控制是万维网发明者蒂姆·伯纳斯·李在 2017 年表达的担忧之一,他声称今天的互联网不像过去那样开放。
尽管最初的意图是“向所有人开放的免费空间”,但网络已经演变成一个由谷歌和脸书等少数互联网巨头管理的中央集权系统。
他们的共同点是共享的商业模式,乍一看似乎很有吸引力:他们不为他们的服务向我们收费。然而,如果我们阅读他们的数据政策中的小字,我们很快就会意识到我们正在付费——不是用钱,而是用我们的个人数据。
这十年的口号是“数据是新的石油”,因此显然,公司拥有的数据越多,就越强大。以脸书为例,一个普通用户的数据据说相当于大约 20 美元的年收入。这似乎是一个相当大的数字——特别是考虑到该网站有 22.7 亿活跃用户——但从我们作为消费者的角度来看,实际上并没有那么多。让我们反过来:假设你丢失了所有的私人信息和照片,你愿意花多少钱把它们找回来?当然,20 美元对于重新控制你的数据来说是一个很小的代价。

我们不断地创造关于我们个人生活、职业生活、购物习惯等的数据。很长一段时间以来,似乎没有人特别担心我们“提供”给脸书、谷歌等公司的信息量。但在不久的将来,人们会希望重新控制自己的个人数据。
今天的集中式网络商业模式不仅影响了我们的隐私,也扼杀了创新。只能有一个赢家,即拥有最多数据的赢家。在许多领域,这些赢家已经确立。这使得他们几乎没有创新的动力。毕竟,你为什么要改变一场胜利的游戏?
社交媒体公司不是大数据游戏的唯一参与者。几乎每家公司都会收集客户的信息,在某种程度上,它们都是大数据公司。甚至超市也会跟踪和分析你买的东西,并根据你的个人资料给你发送个性化广告。对许多这样的公司来说,数据只是达到目的的一种手段:他们需要数据来优化他们的服务或销售,但他们实际上对拥有或管理数据没有直接的兴趣。此外,拥有数据越来越成为公司的一项责任,特别是自从 GDPR(通用数据保护条例)生效以来:如果他们存储数据,他们也必须能够保护它。
想象一个分散的网络
到 2035 年,我们将重新控制我们的个人数据。这意味着我们可以选择将数据存储在任何我们想存储的地方,与我们使用的应用程序无关。我们的个人数据将存储在我们自己控制的所谓的“数据舱”中。在理想情况下,我们将为每个用户提供多个数据容器,例如,一个用于个人数据,一个用于工作相关信息,一个用于官方文档等。我们发布的所有内容都将保存在我们自己的数据舱中,这些数据舱存储在我们选择的服务器上。
为了实现类似社交网络的东西,我们当然需要分享我们的一些数据。只是,在 2035 年的去中心化网络中,我们将可以选择——分别为每个应用程序——我们想要提供哪个数据容器。
我们仍将是数据的所有者——不会制作任何副本——相反,我们只是将应用程序链接到我们愿意开放的数据窗格部分。要实现这一点,必须满足一个重要条件:应用程序必须能够重用其他应用程序创建的数据。
用一个现在的例子来解释这一点:假设你所有的朋友都在脸书,但你更喜欢像 Ello 这样不太受欢迎的替代品。2019 年,选择 Ello 将意味着你不能与你的任何朋友互动(除非你是一个潮流引领者,并能说服他们加入你的 Ello——但我们只是用另一个点取代了一个中心化点)。2035 年,你的朋友使用哪个社交网站将不再重要。由于应用程序将不再拥有任何数据,它们将仅仅成为不同的界面来查看来自你朋友的数据荚的信息。因此,在 Ello 上,你可以看到朋友在脸书上的帖子,并与之互动。因此,应用程序之间的切换将变得容易,它们之间的竞争将基于服务质量,而不是数据所有权。
目前,互联网的一半隐藏在属于少数公司的数据仓库中。这就好像是你的浏览器决定了你可以访问哪些网站。想象一下,Safari 用户看不到谷歌 Chrome 用户创建的任何网站。这就像社交网站决定你可以联系哪些朋友或联系人一样毫无意义。

在去中心化的愿景中,数据存储和应用将成为两个独立的市场。社交网站将试图通过其服务的用户友好性而不是其拥有的用户数量来超越彼此。提供数据存储的服务器也将有一个新的市场。
大数据时代的终结:然后呢?
网络去中心化颠覆了大数据商业模式。它改变了应用程序的竞争方式:它们将不得不通过创新来说服客户,例如用户友好的界面、最好的客户服务、完美的数据安全性等,而不是通过已经拥有大量关于现有成员的数据来吸引新成员。更重要的是,他们还必须通过另一种方式赚钱,比如收取年费。或者有些会给你付费或者(有意识地)出售你的数据的选择。关键是这种思维方式创造了选择和多样性,从而创造了机会。
夺回对我们数据的控制权的影响当然将远远超出社交媒体的范围。例如,今天的大多数消费者并不真正知道他们的超市有哪些关于他们的信息,更不用说他们对这些信息施加任何控制了。在一个分散的系统中,客户将拥有他们所有的数据。乍一看,这似乎是超市的一大劣势,但事实上,这也是一个获得比他们自己可能收集的更多数据的机会。这变成了一场交易游戏:顾客可能会同意分享他们所有的个人购物数据——来自每家超市——以换取个性化的交易。如果超市 Y 注意到你总是在他们竞争对手的店里买酸奶,他们可以给你提供个性化的乳制品降价。它使他们能够分析客户的完整购物行为,为他们提供宝贵的见解,以优化他们的产品。

今天的大多数消费者并不真正知道他们的超市有什么关于他们的信息。在一个去中心化的系统中,客户将拥有他们所有的数据,并且可以选择(有意识地)“出售”它们。例如,对于超市来说,这可能是一个很大的优势,因为他们可以要求访问客户的完整购物数据,也可以了解他们从竞争对手那里购买了什么。这将使他们能够分析客户的完整购物行为,为优化他们的产品提供有价值的见解。
为什么现在是收回我们隐私的好时机?
向一个去中心化的网络转移——或者实际上是回归——首先是要让人们相信这样做的重要性。对数据隐私的日益关注无疑是朝着正确方向迈出的一步。2018 年,欧盟也发出了一个重要信号,推出了《一般数据保护条例》(GDPR),旨在让个人对自己的个人数据拥有更多控制权。
像 GDPR 这样的法规也使得公司拥有数据更加昂贵,这可能会刺激他们转向不同的商业模式;尤其是对于那些只将大数据作为达到目的的手段,而不是作为其商业模式的核心组成部分的公司。
公司需要开始以不同的方式思考数据。像石油一样,数据不应该被保存和储存,而应该成为推动引擎运转的物质。
有趣的是,让人们重新控制自己的数据并不意味着会更少。事实上,从分散的角度来看,将会有更多的数据,因为公司也将能够请求访问竞争对手收集的数据。
魔方?不,机器人和人工智能还没有出现
再来说说目前备受关注的 OpenAI 灵巧机械手。
这是一个炒作疫苗的帖子。换句话说,我会试着让人们不再对机器人技术的最新发展大肆宣传。具体来说,OpenAI 声称在学习用机器人手解决魔方方面取得了一些相当惊人的成果。不考虑他们强大的广告机器,效果究竟有多惊人?
有什么大惊小怪的?
惊人的结果显然不是解开魔方。它是用相对非平凡的机器人系统处理魔方的能力。我们说的是暗影灵巧 E 系列手办:

实际上,这手牌就是去年玩这个方块的那手牌:

所以,最后我们还是在说旋转立方体。
控制手的难点在于它有 20 个自由度。此外,用一只手拿着魔方并解决它是非常困难的,即使对一个人来说也是如此(虽然我可以想象同时控制两只机器手是相当困难的,原因将在后面介绍)。
解决这个问题有许多障碍,如估计手的姿态、跟踪立方体、学习旋转立方体等等。令人印象深刻的是,在模拟训练控制策略后,他们能够在基于摄像机输入的真实系统上做到这一点。此外,手能够适应突然的扰动,即玩具长颈鹿在旋转立方体时触摸它。
简而言之,人们可以将他们的方法分为三个重要部分:计算机视觉(感知)强化学习和领域随机化。
自适应域随机化
当你可以进行受控实验时,强化学习效果很好。这意味着你有一个模拟,你可以重置,快速执行。如果你想在一个真实的系统上尝试这一点…好吧,祝你好运,也许你可以问问你的曾曾孙辈学习得如何,对机器人和/或它周围的各种物体/人的一些轻微伤害,因为它的随机探索行为。
为了将策略转移到真实的系统中(假设我们有一个可用的系统模拟),我们可以使用域随机化。这可以归结为将扰动应用到我们现有的模拟中来创造更多的模拟。这样,我们也许就能捕捉到现实世界的复杂性。
这不是一个非常新的想法,它可以追溯到很久以前,实际上,OpenAI 在他们以前的机器人手论文中使用了简单的扰动进行域随机化,但是基于他们之前的许多人的工作。唉,这里显然有些新奇的东西,“自适应域随机化”。它有什么适应性?他们声称,通过从学习到的生成性分布中取样,他们可以为政策生成越来越困难的模拟。好吧,这似乎是合乎逻辑的,生成式发行版是 21 世纪的东西,它们以某种方式让它发挥了作用。不错,但是…
假设有一个模型(模拟)相当方便……
我们设定这个目标是因为我们相信,成功训练这样一只机器手来完成复杂的操纵任务,为通用机器人奠定了基础。1
是的,通用机器人……我想知道假设我们有通用机器人可能遇到的所有情况的模拟是否合理。我会让你得出自己的结论,这是一个相当哲学的问题。
政策升华,有何新意?
因此,因为训练会花费太多时间,他们用某种好的开始策略初始化不同的实验(模拟的实例)。他们并行积累了很多数据,这些数据来自不同的政策。学习理论中一个众所周知的事实是,如果你的训练数据没有反映实际的数据分布,你的模型将训练得很差。为此,他们采用 DAGGER 算法进行行为克隆,以有效地适应初始策略。这里没什么新东西。
处理太多数字的问题
对于块重定向任务,我们使用 4 × 8 = 32 个 NVIDIA V100 GPUs 和 4 × 100 = 400 个工作机,每个工作机有 32 个 CPU 核心。对于魔方任务,我们使用 8 × 8 = 64 个 NVIDIA V100 GPUs 和 8 × 115 = 920 个工作机,每个工作机有 32 个 CPU 内核。1
这项任务需要大量的计算能力,让我重复一遍,大量的计算能力。光看这些数字就让我头晕。920x32 CPUs???都是为了控制这一手一个任务。然后它让你想知道…花了多少时间?嗯…

我们已经连续几个月以这种规模训练魔方策略,同时改进模拟保真度、ADR 算法、调整超参数,甚至改变网络架构。魔方训练所使用的经验的累积量大约是 13000 年,与 OpenAI Five 1所使用的 40000 年处于同一数量级
嗯,这真是太神奇了。我们需要 13 000 年才能学会解魔方(其实不是从零开始解,而是雇佣一个解算师来解),nice:)。当然,支持这种计算的主要论点是人类有很长的进化时间,数百万年的进化。既然我们正在建造这些系统,我们应该能够通过分享我们的一些进化经验来加快它们的学习,即添加足够的先验知识,这样我们就不必等待 13000 年才能让我们的机器人学会如何拖地板。
事实上,即使在所有的训练之后:
用机器手解魔方还是不容易。我们的方法目前解决魔方的 20%的时间时,应用最困难的争夺的[需要 26 面旋转。对于需要 15 次旋转才能撤销的更简单的加扰,成功率是 60%。1](http://cube20.org/qtm/)
结论
总而言之,我认为 OpenAI 的贡献在某种意义上是相关的,它显示了通过一些聪明的工程技术,计算能力可以带给我们多远。实际上,在无限计算能力的假设下,你可以解决任何问题。有趣的是,随着处理能力的提高,我们正在实现什么。
另一方面,我不得不提到,这种研究是不可持续的,也许处理这么多数字来解魔方是不合理的,而且是多余的。 13000 年,64 个 GPU,训练几个月,这些数字都得往下走。

参考文献
1OpenAIhttps://openai.com/blog/solving-rubiks-cube
基本 k 近邻
初级 ML
最直观的 ML 模型

有时在数据科学中,你会发现自己拿起一个导弹发射器就是为了杀死一只蚂蚁。
不过,在这种情况下,我们将讨论可能是最直观的机器学习算法。然而,不要被愚弄了,尽管它很简单,kNN 算法在某些情况下仍然非常有效。
一些快速注释:
首先,kNN 是一种非参数算法,这意味着它不假设您的数据遵循任何特定的分布。另一个很酷的事情是,它可以执行分类和回归任务,这两个我们将在这篇文章中触及。
直觉
首先,我们将使用一个数据集的简单表示来说明我们将如何使用 kNN 来执行一个分类任务。

设洋红色为 A 型,黑色为 b 型。这些点将组成给定的数据。假设蓝色是我们希望根据给定数据进行分类的数据点。
为此,我们将选择一个值 k ,它将是与我们的新数据点“最相似”的点数。
在这个二维例子中,我们将选择我们的相似性度量作为欧几里德距离。
因此,例如,如果我们让 k=2 ,那么我们将寻找与我们的新数据点最相似的 2 个点。如果我们用距离来表示,我们会寻找最近的两个点。

The red line touches precisely 2 points.
之后,我们计算每种类型的数据点在 k 个最近点的集合中所占的比例。然后,我们选择具有最高比例的类型,并将我们的新数据点分配给该类型。
在我们的例子中,最近的两个点都是黑色的。
Prop of black = 2/2
Prop magenta = 0/2
因此,我们将把我们的新数据点归类为 b 类。
另一方面,如果我们选择 k 为 8,我们将:
Prop of black = 3/8
Prop magenta = 5/8
在这种情况下,我们会将新的数据点分配给类型 a。
回归设置
在这种情况下,我们在很大程度上遵循同样的想法。
例如,如果我们要使用 kNN 来预测房子的价格,我们可能有如下设置:

我们希望找到 k 个最相似的点,并使用这些点的响应值的平均值作为所讨论的新数据点的预测值。
如果我们让 k 为 6,并且我们想要使用这个数据集来预测一个有两个卫生间的房子的价格,那么最相似的数据点将首先是其他有两个卫生间的房子,然后是有一个和三个卫生间的房子。

实际上,相应的预测价格值是洋红色点的平均价格。得到的预测是蓝点。
k 的选择
正如我们所见,K 的选择确实很重要。
请注意 K 值如何在数据没有任何变化的情况下改变模型的性能。任何这样的变量被称为超参数。
的确超参数优化本身就值得一整篇帖子。
然而,出于本文的目的,我们将只提及网格搜索算法。
内容如下:
- 选择一组超参数值
- 使用这些值中的每一个值来训练模型
- 评估每个模型的性能,并选择导致误差最小的值。
这是一个关于 k 值增加时,这个过程的大概情况。

Generic Graph Showing How Test Error(Magenta) and Training Errors(Blue) Change over 1/K
最后的想法
首先,kNN 受到维数灾难的困扰,因此随着输入变量数量的增加,kNN 可能会越来越困难。值得考虑使用降维技术来解决这个问题。
此外,kNN 需要适当缩放的数据。换句话说,您可能必须对数据进行归一化,因为测量值之间的单位差异会严重损害模型的有效性。
另一件需要考虑的事情是,只要数据中的真实关系符合参数模型的假设,线性回归等参数方法往往会优于 kNN 等非参数方法。有趣的是,在一些不遵循所有假设的数据上,参数方法甚至可能比非参数方法表现得更好——所以不要排除它们!
总之,kNN 理解和实现起来相对简单,因此它是一个很好的方法,可以作为其他技术的基准。
我希望你喜欢这本书,并发现它在某种程度上是有用的,无论是学习新的东西还是刷新已经存在的东西。
我本人是数学金融专业的应届毕业生,所以我既是一名教师,也是一名学习者。
也就是说,我非常乐意接受任何建议、更正或你在阅读这篇文章时想到的任何一般性反馈。
请随时在 LinkedIn 上与我联系—
[## 约万·梅德福德-加拿大滑铁卢大学| LinkedIn
查看约万·梅德福德在全球最大的职业社区 LinkedIn 上的个人资料。Jovan 的教育列在…
www.linkedin.com](https://www.linkedin.com/in/jovanmedforddataanalyst)
如果你愿意,你也可以在 Twitter 上关注我—
约万·梅德福德的最新推文(@JovanMedford)。一点特别的东西🤯|数学、金融和科技作家…
twitter.com](https://twitter.com/JovanMedford)
使用 Docker 容器在本地运行 Amazon SageMaker 笔记本

Photo by Aleks Dorohovich on Unsplash
A mazon SageMaker,AWS 的云机器学习平台,由 4 个主要产品组成,支持数据科学工作流程中的不同流程:

Source: https://docs.aws.amazon.com/sagemaker/latest/dg/how-it-works-mlconcepts.html
- 真相:大规模按需数据标注服务的托管服务。
(生成示例数据,用于监督算法) - 培训:培训和调整任何规模模型的托管服务。
(训练一个模型) - 推理:托管预建模型并对新数据运行推理的托管服务。
(部署模型) - 总而言之,Notebook:AWS 托管的服务器,供数据科学家访问和管理上述 3 项功能以及许多其他数据科学任务。
虽然托管的笔记本服务提供了一种非常方便的方式来获得与 Amazon SageMaker 一起工作的完整服务器,但在许多情况下,出于成本、访问便利性或“可定制性”的考虑,需要进行本地设置。
在这篇文章中,我将详细介绍本地托管的笔记本 Docker 容器背后的动机,并描述已经复制的 Amazon SageMaker 笔记本实例的各种功能。
这篇帖子的目标读者是正在使用或计划使用亚马逊 SageMaker 的数据科学家和机器学习工程师。对 Amazon SageMaker 及其笔记本实例的基本了解加上 Docker 的知识将是有用的。
TL;速度三角形定位法(dead reckoning)
对于忙碌的人,这里有一个快速总结:
- 托管的 SageMaker Notebook 实例预构建了许多重要功能,包括一套全面的工具和库、具有最新机器学习框架的多个内核、GPU 支持、Git 集成和许多真实世界的示例。
- 尽管如此,它需要钱,要求所有数据都在线上传,需要互联网接入,特别是 AWS 控制台登录,并且很难定制。
- 为了克服这些缺点,我创建了一个 Docker 容器,它提供了一个类似的设置,可以在任何笔记本电脑/台式机上本地使用。
- 复制的功能包括完整的 Jupyter 笔记本和实验室服务器、多个内核、AWS & SageMaker SDKs、AWS 和 Docker CLIs、Git 集成、Conda 和 SageMaker 示例选项卡。
- AWS 托管的实例和本地容器并不相互排斥,应该一起使用来增强数据科学体验。
Docker 图片的完整源代码存放在 Github 上:https://github.com/qtangs/sagemaker-notebook-container
Docker 图片已经发布到 Docker Hub:https://hub.docker.com/r/qtangs/sagemaker-notebook
在这篇文章中,
我将探索:
- 为什么我们首先需要一个笔记本实例?
- 为什么我们需要本地笔记本容器?
- 复制了哪些功能?
- 缺少哪些功能?
- 如何开始使用容器?
为什么我们首先需要一个笔记本实例?
在探索本地实例之前,让我们深入了解一下 Amazon SageMaker 笔记本实例提供的好处:
- 完整的按需系统:对于一个不怎么处理基础设施的数据科学家来说,这是开始使用 Amazon SageMaker 最简单的方法。使用 AWS 控制台,只需点击几下鼠标,您就可以访问配备了最常用库和工具的综合系统。
- 多个机器学习内核:Notebook 实例提供了各种内置内核,包括标准的 Python 2 和 3,流行的框架如 TensorFlow、MXNet、PyTorch 和 Chainer,以及其他运行时如 R、PySpark。
- 适用于不同工作负载的多种机器规模:您可以选择最基本的多用途实例类型,如 t2、t3 或 m4、m5、计算优化型(r4、r5)以及强大的基于 GPU 的类型(p2、p3)。
- 使用 GPU 机器的弹性推理:虽然使用 p2,p3 产生 GPU 驱动的性能提升,但是它们很贵。相反,您可以附加一个额外的弹性推理实例(eia1 类型)来使用 GPU 训练和测试您的模型,其成本只是 p2、p3 的一小部分。
- 安全性:默认情况下,笔记本实例是安全的,您需要登录 AWS 控制台才能访问它。
- Git 集成:您可以将 Notebook 实例与 Git 存储库(由 AWS CodeCommit 或 Github 或任何其他 Git repo 托管)相链接,以便对您的所有工作进行代码版本控制。如果你在团队中工作,这一点尤其重要。
- 大量示例:为了让你快速入门,AWS 在每个实例中都嵌入了大量示例,大多数来自 Github 上托管的 AWS 示例。只需很少的努力,您就可以将一个示例的完整源代码导入到您自己的实例中。
为什么我们需要本地笔记本容器?
尽管 AWS 托管的笔记本实例有很多好处,但是本地笔记本容器也有一些缺点。以下是本地笔记本容器的一些好处:
- 降低成本:运行一个 AWS 托管的实例要花钱;此外,还没有办法使用 spot 实例,它通常用于降低 EC2 实例的成本。运行本地容器不需要任何成本。
- 易于使用本地数据:由于 SageMaker 笔记本实例运行在云中,它只能访问在线数据。任何本地数据都必须首先上传到 S3 或其他在线存储器。本地容器不需要这样,它可以使用简单的 Docker 卷挂载。
- 跳过 AWS 控制台:访问 AWS 托管的实例需要登录 AWS 控制台,有 12 个小时的超时,这意味着每天至少要登录一次。使用本地容器,您只需配置一次 AWS 凭证,之后就不再需要登录了(除非需要访问 S3 或其他 AWS 服务)。
- 离线访问:本地容器的另一个优点是,你可以在没有互联网连接的情况下随时访问它,尤其是当你想专注于数据清理、特征工程、数据分析等等的时候。不需要培训服务器的功能。
- 定制:虽然 AWS 提供的 Notebook 实例已经包含了许多通用的库和工具,但是可能仍然需要针对特定的用例进行进一步的定制。SageMaker 通过生命周期配置和直接终端访问实现了这一点。然而,这有时会感觉受到限制,尤其是需要 shell 脚本知识。对于本地容器来说,能够使用数据科学家团队需要的所有工具轻松配置 Docker 映像是一个优势。
- 灵活性:有了 Docker 映像,一组数据科学家可以决定将其集中托管在一个高容量服务器中,或者设置笔记本实例集群。选择是无限的。
注意:AWS 托管的实例和本地容器并不互斥。您可以同时使用两者,如果您正确设置了 Git 集成,它们可以同步,这样您就可以在日常工作的两种选择之间无缝切换。
复制了哪些功能?
本地 Docker 容器的主要目的是尽可能多地维护 AWS 托管的实例的最重要的特性,同时增强本地运行能力的体验。以下是已复制的功能:
Jupyter 笔记本和 Jupyter 实验室
这只是从 Jupyter 的官方 Docker 图片中截取的,做了一些修改以匹配 SageMaker 的笔记本设置,包括:
- 将默认用户命名为
*ec2-user*,并允许无密码*sudo*访问。 - 允许定制 Miniconda 和 conda 版本。
- 跳过 Jupyter 集线器
- 将笔记本目录设置为
*/home/ec2-user/SageMaker*
多核
使用 Conda environments ( *conda env create*)创建多个与 SageMaker 内核名称相匹配的内核。例如:
*conda_python2**conda_python3**conda_tensorflow_p36*
内核列表是动态的,即 docker 映像可以包含一个或多个内核。它是在构建 Docker 映像时由参数*CONDA_ENVS*设置的。最初支持的 Conda 环境包括*python2*、*python3*、*tensorflow_p36*、*mxnet_p36*。通过在*base/utils/envs*文件夹中添加 Conda 环境文件,可以简单地创建额外的内核。
AWS 和 SageMaker SDKs
每个内核都包括 AWS Boto3 SDK 和 SageMaker SDK。这对于所有与 AWS 服务交互的 Python 代码都是必不可少的,包括 SageMaker 的培训和部署服务。
AWS CLI
AWS CLI 是为与 AWS 交互的 shell 脚本安装的。
注意:AWS SDK 和 CLI 都需要在主机中配置一次 AWS 凭证。
Docker CLI
许多 SageMaker 示例使用*docker*来构建用于训练的定制图像。我们没有在 Docker 上安装一个完整的 Docker,这是一个复杂的操作,而是利用了主机的 Docker 引擎。为了实现这一点,我们在 Docker 映像上安装了 Docker CLI,并依靠主机的 Docker 套接字来连接主机的 Docker 引擎。这是通过在运行容器时包含*-v /var/run/docker.sock:/var/run/docker.sock:ro*来实现的。
注意:在 Windows 上,将挂载更新为:
*-v //var/run/docker.sock:/var/run/docker.sock:ro*。
Jupyter 实验室中的 Git 集成
安装 Git 是为了允许直接从容器访问 git。此外,jupyterlab 上安装了 jupyterlab-git 扩展,用于与 git 进行快速 GUI 交互。
康达标签
就像 AWS 托管的实例一样,基于 Docker 的实例包含一个 Conda 选项卡来管理 Conda 环境。
注意:虽然这是为了模拟实际情况,但是不建议您在这里对 Conda 环境进行修改。相反,更新
*base/utils/envs*下相应的 YAML 文件并重建 Docker 映像,这样您的更改就会被记录下来并可以与其他人共享。
SageMaker 示例选项卡
AWS 提供的所有 SageMaker 示例都与简单的 2-click 复制功能一起反映在 Docker 映像中,因此您可以轻松地使用现有示例并进行尝试。其他例子(来自 fast.ai 和 PyTorch )还没有包括在内,但将来会包括在内。
缺少哪些功能?
GPU 支持
目前,该容器仅为 CPU 工作负载而构建。对于任何使用 GPU 的本地培训和测试,您必须使用 AWS 托管的实例。注意,如果您使用 SageMaker 的培训作业运行 GPU 驱动的培训,那么您不需要本地容器上的 GPU。
其他内核
使用 Conda 可以很容易地添加其他基于 Python 的内核。然而,对于 R 和 Spark 运行时,未来还需要做更多的工作。
局部训练和推理
使用 AWS 托管的实例,您可以使用 SageMaker 的本地模式在该实例上运行训练和推理。目前,Docker 容器没有为此而设置。将来,将添加网络配置来支持这一点。
使用最新的 SageMaker 设置自动更新
目前,每当 SageMaker Notebook 实例更新时(新的 SageMaker 版本),内核配置都需要手动更新。将来,这些可以使用 CloudWatch 事件和 AWS Lambda 函数自动更新。
Python 库
为了保持 Docker 映像尽可能精简,许多库没有包含在给定的内核中。如果您需要容器中的某些库,您可以在*base/utils/envs*文件夹中使用自定义环境 YAML 文件构建自己的容器。在未来,我的目标是使它更容易定制。
其他工具
一些工具,如 nbdime 、Jupyter Notebook Diff 和 Merge 工具以及 plotlywidget (一个开源的、用于 Python 的交互式图形库)应该会在未来被集成。
如何开始使用容器?
可以在 Github 库找到说明:https://github.com/qtangs/sagemaker-notebook-container
摘要
亚马逊 SageMaker 的笔记本实例是 AWS 云机器学习平台的重要组成部分。
在 Docker 容器映像中复制它有望进一步简化对 SageMaker 世界的访问。
在未来的帖子中,我将继续关注使用 Amazon SageMaker 的机器学习基础设施,以及我们如何应用最佳实践来简化和巩固这些基础设施组件。
感谢您的阅读。请在下面评论分享你的想法。
这项工作的完整项目托管在Github上。
用一个命令在 AWS 上运行深度学习容器

有许多公开可用的 Docker 图像,如 TensorFlow 、 PyTorch 、 Jupyter Docker Stacks 或 AWS 深度学习容器,可用于训练深度学习模型。
有了 Spotty 你只需要一个命令就可以在 AWS 上运行 Docker 容器。Spotty 为您管理所有必要的 AWS 资源,包括卷、快照和 SSH 密钥,将本地项目与实例同步,并使用 tmux 将远程进程从其终端分离。
你所需要的只是在你的项目的根目录下有一个名为 **spotty.yaml** 的配置文件。
装置
要求:
使用 pip 安装或升级 Spotty:
pip install -U spotty
配置文件
一个配置文件描述了 EC2 实例的参数和 Docker 容器的参数,这些参数将被用作项目的环境。这里有一个例子:
有了上面的配置,Spotty 将在 us-east-2 (俄亥俄州)地区运行一个按需 p2.xlarge 实例。随意更改这个配置:例如,您可以将参数image更改为pytorch/pytorch:latest来运行 PyTorch 容器。
如果您想启动一个 Spot 实例,而不是一个按需实例,请删除onDemandInstance参数。要找到所选实例类型的最低价格区域,使用spotty aws spot-prices -i <INSTANCE_TYPE>命令。
在文档中阅读更多关于配置的信息。
启动容器
一旦项目目录中有了一个spotty.yaml文件,就可以使用下面的命令启动容器:
spotty start
该命令将启动一个 EC2 实例,将本地项目与该实例同步,并运行容器。

使用spotty ssh命令连接到容器。
不要忘记稍后使用 **spotty stop** 命令停止实例!
AWS 深度学习容器
AWS 深度学习容器是预装深度学习框架的 Docker 映像,针对最高性能进行了优化:
AWS DL 容器包括对流行框架(如 TensorFlow 和 Apache MXNet)的最新版本的 AWS 优化和改进,以及为云中的训练和推理提供最高性能的库。例如,AWS TensorFlow 优化通过显著改进的 GPU 扩展使模型的训练速度提高了一倍。
Docker 图片在亚马逊 ECR 有售。在这里你可以找到一个图像 URL 列表,可以在一个不稳定的配置文件中使用。
要运行 AWS DL 容器,实例应该能够访问 Amazon ECR:
- 使用
managedPolicyArns参数将arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess策略附加到实例角色。 - 在容器运行之前使用
commands参数登录 Amazon ECR:$(aws ecr get-login --no-include-email --region us-east-2 --registry-ids 763104351884)。
确保图像名称中的区域和登录命令中的区域与 **region** 参数匹配。
结论
Spotty 是一种使用 Docker 容器在 AWS 上训练深度学习模型的快速简便的方法。它将节省您管理 AWS 资源的时间,并通过将项目与实例同步、运行自定义远程脚本和使用 tmux 分离远程进程来帮助工作流。
如果你喜欢这篇文章,请在 GitHub 上启动 项目,并与你的朋友分享这篇文章。
运行更多的特技播放

[Via hence-the-boom on Unsplash](http://Photo by HENCE THE BOOM on Unsplash)
受穆罕默德·萨努的启发,对 2009-2019 年美国国家橄榄球联盟特技表演进行了分析
介绍
足球中的恶作剧是这项运动中最有趣的部分之一。双逆转,假摔,跳蚤闪烁通常会成为亮点。它们在本质上是高度变化的:要么你抓住防守放松警惕并轻松触地得分,要么你让你的跑卫把鸭子扔进双包并把球放在银盘子里给对方。对于任何一个经常看足球比赛的人来说,特技表演的高变化性是直观的。可能不直观的是它们的实际价值。直到最近,公众还不容易获得客观评估特技表演所需的数据。感谢罗恩·尤尔科的出色工作,以及本·鲍德温和 Github 用户@德里克 97 的精彩教程,任何像我这样的笨蛋都可以花几个小时分析高飞在 10 年期间发挥的价值。
预期增加的点数(EPA)
你如何捕捉一部戏的价值?显然,在几乎所有情况下,50 码的完成比 2 码的跑更有价值。然而,第一次 4 码跑比第三次 1 码跑更有价值吗?那是一个很难准确回答的问题。然而很明显,并不是所有的码都是平等的。随着时间的流逝,结束半场对抗防守的传球可能会增加 30 码。所做的只是填充统计数据。任何 NFL 教练都宁愿在关键情况下进行第三次向下转换,不管多短。Ron Yurko 撰写了一篇论文,详细介绍了预期加分指标。在论文中(见此处),他能够确定一个球队在比赛中任何一点的得分。如果在一次游戏之后,预期点数度量较高,则该玩家增加预期点数。当然,诸如麻袋或拦截之类的游戏会导致负面的 EPA。
显然,90 码以上的进攻型打法有最高的 EPA,红区失误有最差的 EPA。以下是数据集中排名前五的 EPA 行动:
Description (3:15) (Shotgun) B.Roethlisberger pass deep middle to J.Smith-Schuster for 97 yards, TOUCHDOWN.
EPA 9.5
Description (10:06) (Shotgun) C.Johnson up the middle for 91 yards, TOUCHDOWN.
EPA 9.3
Description (7:44) (Shotgun) C.Palmer pass short middle to M.Floyd for 91 yards, TOUCHDOWN.
EPA 9.2
Description (8:51) (Shotgun) P.Mahomes pass deep middle to D.Robinson for 89 yards, TOUCHDOWN. PENALTY on KC-D.Robinson, Taunting, 15 yards, enforced between downs.
EPA 9.1
Description (11:51) (Shotgun) D.Carr pass deep middle to A.Cooper for 87 yards, TOUCHDOWN.
EPA 8.9
你明白了。下面是倒数 5 名:
Description (12:14) (No Huddle, Shotgun) M.Vick to WAS 10 for -6 yards (R.Kerrigan). FUMBLES (R.Kerrigan), touched at WAS 10, RECOVERED by WAS-D.Hall at WAS 25\. D.Hall for 75 yards, TOUCHDOWN. Lateral batted by 91 - Kerrigan The Replay Assistant challenged the backward pass ruling, and the play was Upheld.
EPA -12.8
Description (11:14) (Shotgun) J.Tuel pass short right intended for T.Graham INTERCEPTED by S.Smith at KC 0\. S.Smith for 100 yards, TOUCHDOWN.
EPA -12.7
Description (6:05) (Shotgun) M.Cassel sacked at DEN 25 for -17 yards (M.Haggan). FUMBLES (M.Haggan), RECOVERED by DEN-J.Hunter at DEN 25\. J.Hunter for 75 yards, TOUCHDOWN.
EPA -12.1
Description (2:51) M.Vick pass short left intended for B.Celek INTERCEPTED by P.Robinson at NO 1\. P.Robinson for 99 yards, TOUCHDOWN. PENALTY on PHI-M.Vick, Low Block, 15 yards, enforced between downs. The penalty for a low block during the interception return will be assessed on the ensuing kickoff.
EPA -12.1
Description (7:50) (Shotgun) E.Manning pass short left intended for H.Nicks INTERCEPTED by B.McCann at DAL -1\. B.McCann for 101 yards, TOUCHDOWN.
EPA -12.1
环保局是一个有趣的事情,因为在进攻中,它可以大于触地得分。这是有道理的,因为如果你在自己的端区防守,你预计 1)不会在一次击球中得分,2)由于场地短,另一个队更有可能在下一次击球中得分。它也可以是-12,因为在红区 1)你预计平均得分约为 5 分,2)防守队的下一次控球应该是在开球后,可能是在他们自己的半场。
特技表演
现在我们有了一个衡量一部戏价值的标准,我们可以开始将不同类型的戏分组并进行比较。比如摘自@Deryck97 上面链接的教程,2018 年 rush vs. pass 打法对比:

Both the mean and the standard deviation of pass plays are higher.
那么,使用 nflscrapR 数据,我们如何知道一个游戏是否是一个技巧游戏?不幸的是,没有简单的指示变量来表示“特技播放”。相反,我们必须想出创造性的方法来识别它们。
假踢
最容易开始的比赛是假踢。大部分剧本描述都包含了剧本的形成。如果一场比赛被标为“踢阵型”或“射门阵型”,但比赛类型是跑动或传球,那么它很可能是假球。我不得不手动过滤一些其他类型的游戏,比如当玩家错过了一个快照并中止游戏时,但这很容易。以下是 python 代码:
punts = df.loc[df.desc.str.contains('punt|Punt')]
fake_punts = punts.loc[(punts['play_type']=='run')|(punts['play_type']=='pass')]# drop enforced penalties
fake_punts = fake_punts.loc[fake_punts.penalty!=1]# drop non enforced penalties
fake_punts =fake_punts.loc[~fake_punts.desc.str.contains('Penalty')]# drop punter mishandles fake_punts=fake_punts.loc[~fake_punts.desc.str.contains('Aborted|Shotgun')] # drop plays where punter intentionally runs out of end zone (not likely to fake a punt in own redzone)
fake_punts = fake_punts.loc[~fake_punts.desc.str.contains('SAFETY
')] # drop plays without description
fake_punts.dropna(subset=['desc'], inplace=True)
然后,我将同样的过滤器应用到以平手结束的游戏中。最终,在大约 22,000 次试踢(常规赛和季后赛)中,我发现了 177 次假球。不到 1%的假率!
让我们也想出一些基线。我将展示汤姆·布拉迪的平底船的平均 EPA、传球的平均 EPA、跑动的平均 EPA 和传球的平均 EPA🐐。

哇!假船票的价值大约是汤姆·布拉迪船票的 7 倍。当然,EPA 的标准偏差也要高得多。非假平手的 EPA 的标准偏差是 1.16,而假平手的标准偏差是 3.17。很明显,如果你造假失败,那么你就有一个很大的负面 EPA。
假球也一样有价值吗?根据我简单的分析,没有。扔出失球,糟糕的抢断,点球等等——假球的 EPA 是 0.06。这比你的平均通过率高,但不是超级令人兴奋,因为我是在伪造的投注号码后跑的。我相信这是因为你放弃了一个投篮机会。如果你在一个假动作中失败了,你就会失去一些你原本可以从尝试中得到的分数。如果你所做的只是得到第一次得分,你甚至不会得到那么多预期的分数。他们有一个类似假平底船的大标准差。因此,如果你落后几个点,你可能还是会更好地掷骰子,用一个假的。
特技跑/传球
不幸的是,技巧跑位和传球并不容易区分。作为免责声明,本文的重点是从 NFL 的比赛数据开始。我不是在写关于假戏的论文。因此,虽然我竭尽全力成功地隔离了特技播放,但我并不声称 100%准确或最好的可能过程。
让我们从传球开始。我开始时抛出了明显的战术(点球,两分转换尝试)以及我已经分析过的战术(踢法)。我也放弃了具有极端获胜概率的策略(<5% & > 95%的获胜概率)。这里的想法是避免孤注一掷的后期横向游戏,如钩和后者。
然后,我在游戏描述中搜索了数据集中尝试次数少于 30 次的玩家的跳蚤闪烁和传球。跳蚤闪烁覆盖了 QB 的侧边,理论上,任何其他的技巧传球都会涉及到一个通常不会传球的跑卫或宽接球员的侧边。最后,我把那些只出现了很短时间并被我的过滤器过滤掉的 QB 列入黑名单。他们很容易找到,因为整个系列的戏剧都在描述中突出了出来。
快到了。对于跑位戏,我分离出了有横向或反向描述的戏。幸运的是,没有太多防守球员在摸索恢复后落后的情况。我最终得到了 180 个剧本的样本(手动删除了一两个奇怪的剧本)。我选择排除两点转换的尝试,所以不幸的是这一优点没有包括在内:
Two-point attempt starts at 0:43s
咻。结果如下:

我很惊讶地发现反转和横向跑动是如此的有价值!理论上,他们就像拥有一个传球能力是汤姆·布拉迪两倍的球员。因为跑位通常没有传球有价值,所以我期望技巧传球有更高的 EPA。特技通行证仍然是有价值的,但是许多 EPA 仅仅是由跳蚤市场驱动的。事实上,只计算跑锋和 WR 传球(n=194),EPA 是 0.024——比正常传球还糟糕!跳蚤-闪烁,当单独分组时(n=66),EPA 为 0.3——非常有价值。我估计你非 QB 扔拦截的风险太高了。
理论与实践
当然,如果一个团队总是假摔,那么防御将会调整,EPA 将会下降。这里恰当的批评是,正是这出戏的新颖之处让它们变得有价值。尽管如此,我的分析表明,球队肯定应该运行更多的逆转和假摔。
换一种说法,我认为风险承受能力并不是避免假踢或转身的好理由。这里打个比方。在 21 点中,打到 16 点感觉不舒服。你经常崩溃,觉得自己很愚蠢。然而,这几乎总是数学上最好的玩法,因为庄家通常会赢 16。当你住在 16 楼的时候,通常你只是给了房子额外的优势。
就像打 16 分一样,在自己的场地假装踢了一脚,然后失败了,这可能感觉很愚蠢。然而,这在数学上是有利的。有足够的空间尝试超过 1%的时间。
同样,我认为很重要的一点是,所有这些特技都有很高的标准差。这表明,即使这些打法的 EPA 与正常打法相同,有时当一支球队被击败时,尝试它们仍然是有利的。如果你有 80%的胜算,游戏理论说不要尝试一系列疯狂的游戏,这些游戏可能会立即逆转胜算。出于同样的原因,当团队遥遥领先时,他们会聪明地跑得更快。另一方面,如果你的胜率是 30-40 %,那么你的球队可能需要一个假摔或射门来达到 55%的胜率。让我们看看团队实际上是怎么做的:
Average Win Prob at time of punt attempt: 0.462
Average Win Prob at time of fake punt attempt: 0.398
Average Win Prob at time of field goal attempt: 0.578
Average Win Prob at time of fake field goal attempt: 0.561
Average Win Prob at time of run attempt: 0.559
Average Win Prob at time of trick run attempt: 0.534
Average Win Prob at time of pass attempt: 0.490
Average Win Prob at time of trick pass attempt: 0.557
似乎只有在困难的情况下,球队才会正确地使用假摔。投篮、技巧传球和技巧跑动都是在球队(平均)已经领先的情况下进行的。这是次优的,可能是因为教练太保守了。
当然,尽管如此,还是有一些技巧永远不是最佳的:
自从我看到一条令人印象深刻的 Mohamed Sanu 统计线,这篇文章就一直在我的脑海中萦绕。我一定会大声喊出来。在 Sanu 传球的 8 次尝试中,他平均每场比赛得 2 分!这太疯狂了。这是 8 个通行证:
(14:53) (Shotgun) Direct snap to M.Sanu. M.Sanu pass deep middle to A.Green for 73 yards, TOUCHDOWN.
(12:48) M.Sanu pass deep right to G.Bernard pushed ob at CLE 9 for 25 yards (B.Mingo). {Ball lateraled from Dalton to Sanu} Cleveland challenged the pass completion ruling, and the play was Upheld. (Timeout #2.)
(1:03) M.Sanu pass deep right to B.Tate pushed ob at ATL 24 for 50 yards (D.Lowery).
(:06) (Shotgun) M.Sanu pass short left to A.Dalton for 18 yards, TOUCHDOWN. {Dalton pitched out to Sanu, who then passed to Dalton.}
(3:28) (Shotgun) M.Sanu pass short right to A.Green to TB 27 for 11 yards (B.McDougald). #14 lateral to #12
(12:44) Direct snap to M.Sanu. M.Sanu pass deep left to Ju.Jones for 51 yards, TOUCHDOWN.
(8:56) T.Sambrailo reported in as eligible. Direct snap to M.Sanu. M.Sanu pass incomplete deep left to J.Jones.
(8:55) (Shotgun) M.Sanu pass short right to M.Ryan for 5 yards, TOUCHDOWN.
所以,还有其他变量在起作用。如果你的一个外接球手有一个金色的深球,那么数学就简单多了。这段视频让它更加令人印象深刻:
综上所述,NFL 球队应该更经常地进行特技表演。别的不说,就是好玩。代码可以在这里找到。
*取决于许多因素
如何管理一个出色的数据科学团队

© Blake / Adobe Stock
操作框架
从一开始就做好!
我们正在见证对数据科学家的需求爆炸式增长——“21 世纪最性感(也最受追捧)的工作”。大学正在迅速创建数据科学项目。学生们争相报名。不断听到数据科学如何改变业务的高管们都遭受了严重的 FOMO。在这种爆炸中,隐藏着对没有任何成功计划的团队梦想破灭的伤害。
这是从一开始就应该做的。
“快而不急” —约翰·伍登
仅仅寄希望于新的数据科学家能够从你的数据宝库中发掘出真知灼见是不现实的。失败的几率高得惊人— 行业专家认为只有六分之一的大数据项目会成功。一些原因是一般性的——缺乏领导、团队合作、支持和沟通。有些是数据科学特有的,比如有缺陷的数据架构、无效的遗留技术以及团队内部的技能差距。
两位作者(他们曾在 Credit Sesame 共事)在数据科学领域共同度过了半个多世纪。我们已经看到该领域从“管理科学”(科学原理,包括大量使用数据和分析,应用于商业)发展到“商业智能”、“商业分析”,并最终发展到今天的“数据科学”。我们使用分析技术创建了第一个直接小型企业小额贷款机构,准确预测谁最有可能离开公司,并确定准确的时间点来展示任何给定客户最有可能购买的产品。在这篇文章中,我们提出了一个框架来增加你的努力取得成果的几率。

Data visualization of how food ingredients are connected 1
框架(我们将以餐饮业为例)
数据科学是关于将原始成分(数据)转化为有用的东西(知识和见解)。餐饮业也认同这一首要原则。此外,数据科学和优秀餐厅中的成功团队也非常擅长三个要素:伙伴关系、领导力和赞助。
暂时用餐馆的比喻来说——一家成功的餐馆不全是厨师(甚至是名厨),而是“房子前面”(用餐空间)和“房子后面”(厨房)的合作关系。
向食客展示整个餐厅所能实现的目标的餐馆老板提供了领导能力来协调团队中每个人的激励。领导者知道团队需要什么样的技能组合(厨师、糕点师),并且清楚地知道团队的每个成员以及整个团队的伟大意味着什么。
最后,餐厅需要那些相信它能实现目标并愿意提供他们的赞助来实现目标的人的支持。
成功的活动流程
❶ 了解你的消费者——他们的偏好和对你服务的熟悉程度。
餐厅需要了解自己的食客。你的团队需要了解你的分析的内部消费者。
❷ 寻找、储存并正确准备高质量的食材。
餐馆从供应商那里购买食物原料,然后准备好并储存在小型冷藏箱中。您从数据库中提取数据,对其进行转换,然后将其存储在仓库中。
❸ 使用正确的技术和技能来创造让你的消费者满意的产品。 一个厨艺大师的技术是烹饪的。你是分析型的。
❹ 确保饭菜精美并及时送到。
出色的展示能吸引食客和消费者。
❺ 获得关于你的消费者如何享受你努力创造的东西的反馈。
优秀的团队拥抱持续改进。没有反馈,这是不可能的。
够理智了吧?但是你有没有发展你的分析过程来有效地完成所有这些活动?对于一个餐厅来说,连一项活动都完成不了,就意味着失败。数据科学团队也是如此。下面我们将描述与您的团队相关的每项活动。

© zinkevych / Adobe Stock
1 |了解你的消费者——他们的偏好和对你产品的熟悉程度。
理解——甚至预测——消费者的需求对于确保创造价值至关重要。但是,简单地理解你的分析性见解的消费者想要有价值的见解来帮助他们解决问题,就像知道食客想要一顿美味的晚餐——这是必然的。你得深入挖掘。
你的消费者分析能力如何?换句话说,他们的分析商数2是多少?他们能以什么形式消化自己的见解?他们是希望定期获得易于理解的见解,还是希望获得更大的、改变游戏规则的见解,这些见解可能需要更多的时间来开发,以及更精细的演示?如果消费者不懂得分析,你怎么能确保你提供的不仅仅是只是暂时满足对分析的渴望的空卡路里呢?
了解你的消费者对于了解洞察应该如何产生、产生什么以及产生的频率是至关重要的。这意味着发展强大的关系,以便更容易理解和预测他们试图解决的业务问题以及他们必须做出的决定。

© karandaev / Adobe Stock
2 |采购、储存并正确准备高质量的配料。
与餐馆不同,数据科学只有一个主要成分:原始数据。但是它有无限多的种类和口味,必须可靠地获得、准备和储存,就像餐馆餐具室里的配料一样。有些数据是脏的。其他数据非常容易损坏。所有数据应:
- 来源于数据库、数据湖和其他数据源。(想想农民、鱼贩和觅食者。)
- 已转换,因此它们很容易用于提取-转换-加载(“ETL”)过程。(想想 prep 大厨。)
- 存储在数据仓库中。(想想步入式冰箱。)

3 |使用正确的技术和技能来创造一个让你的消费者满意的产品。
做这件事的最好的人是高技能、非常受欢迎的专业人士,他们从事接近艺术的工作。他们经常处于聚光灯下。最好的团队依靠他们取得成功。像顶级厨师一样,您的分析师也需要设备、空间和支持才能大放异彩。你需要满足他们不断发展和推动自己的欲望。你必须向你的厨师展示,如何确保他们做出的东西——尽管他们认为可能会很棒——会让你的消费者喜欢。Credit Sesame 的经验法则是,任何数据科学工作产品都应该易于实施,为我们的成员改善信用健康,并启发公司内所有的分析消费者。


Yuck v. Yum 3
4 |确保你的产品被恰当地展示,被很好地组合在一起,并且被及时地交付。
你展示最终产品的方式可能会吸引或者排斥你的消费者。优秀的餐厅明白视觉外观的重要性— 多项研究表明,盘子里食物的外观会影响食客对味道的感知。
对于分析的消费者来说也是如此——明智地使用颜色,避免混乱,逻辑流程和有吸引力的图形一起工作来教育,也许还能激起进一步启发的欲望。有效的数据可视化和数据故事将吸引你的消费者,并帮助他们消化你的产品。
餐馆确保食客在汤热的时候得到汤,在冰的时候得到冰淇淋。同样,您的消费者应该及时收到他们的分析。分析的延迟——瘫痪可能会导致你的消费者不想使用或者不能使用的陈旧产品。

5 |获得关于消费者如何享受你努力创造的东西的反馈。
顶级餐馆老板知道哪些菜单最受欢迎。他们寻找留在盘子里的东西,或者更糟的是,送回厨房的东西。调查反馈、投诉、在线评论——餐馆老板利用所有这些来了解什么可行,什么不可行。有时候侦查对于发现问题是必要的。许多用餐者可能不愿意给出反馈,因为害怕冒犯他人或显得不知情。
同样,您需要知道您的工作产品的哪一部分被执行了?哪些部分没有被触及?你是否注意到对你认为最有价值的见解缺乏兴趣?是因为洞察力不够清晰,还是因为您的团队在开发洞察力时没有合适的业务环境?
成功=经验丰富的数据科学团队
您还需要以下调味元素来确保您的数据科学团队保持卓越。
- 合伙关系。房子的正面和背面一定要配合好。例如,与数据架构师和数据工程师的密切关系意味着可以随时访问准备充分的数据。招聘团队站在你这边意味着你可以获得你需要的人才。与你的分析消费者建立密切的伙伴关系将有助于你的团队更好地了解他们的业务。
- 领导。数据科学领导者应该推动为团队设定方向的愿景,并使团队与消费者保持一致。这一愿景应该清晰地向分析的消费者传达可以产生的价值。这种价值最终将来自团队通过数据科学从数据中释放价值的能力。例如,在 Credit Sesame,我们团队的愿景是通过数据科学释放我们数据的价值,从而改善信用健康。
- 赞助。强大的高管支持对于促进数据驱动的文化是必要的,在这种文化中,每个人都明白产生改变游戏规则的见解需要时间、资源和投资。赞助意味着数据科学家不太可能被视为只提供仪表盘和报告的快餐厨师,而不是推动战略的思想领袖。

Virtuous cycle of data science greatness
外卖食品
食客可以指望他们最喜欢的餐馆提供精心准备的美味佳肴。要引导您的数据科学团队走向伟大,请从那些伟大的餐厅中获得启示。
❶了解你的消费者的需求,他们的 AQ,和他们的业务。
❷使用正确的设备采集、存储和正确准备数据。(是的,觅食可能是必须的!)
❸使用正确的技术和技能来创造工作产品,愉悦和滋养你的消费者。避免空卡路里!
❹介绍你的作品,让它平易近人。迅速递送它。
❺得到反馈。如果不明确,寻找表明反馈的线索。回到第一点。冲洗,重复。
最后,再加入三种调味料来完成你的成功秘诀:
- 合作关系
- 领导力
- 赞助
想打造米其林 3 星数据科学团队?使用这个五步框架,加上上面的三种调料,你的团队将会持续地提供让你的消费者高兴的热辣、美味的商业见解。
参考
1图像功劳:“味道网的中坚力量。由 Yong-Yeol Ahn、Sebastian E. Ahnert、James P. Bagrow 和 Albert-拉斯洛 Barabási 在 Nature 杂志上发表的文章由 CC 于 3.0 授权。
2尼科·莫尔和霍尔格·胡尔根。(2018 年 4 月)。"利用数据实现业务影响:洞察价值链的全面视角。"数字麦肯锡。
3意大利面图的灵感:C. N. Knaflic,《避免意大利面图的策略》(2013),用数据讲故事。凌乱的意大利面图片致谢:何塞·路易斯·斯蒂芬斯 / 土坯股票。旋转的意大利面图片来源: denio109 / 土坯股票。
延伸阅读
关于作者
Raj DevRaj 是利用数据科学和分析技术做出人才和人员决策的倡导者。Raj 是 EleveneX 的管理合伙人。此前,Raj 是不可能食品公司的人力运营副总裁。在此之前,他曾在 Credit Sesame 和特斯拉担任高级管理职务。Raj 拥有耶鲁管理学院的工商管理硕士学位。
马修·拉斐尔森马修是一名管理顾问,他通过数据科学帮助公司增加收入。此前,他是一名高级财务主管,拥有 25 年应用定量建模和数据科学来启动和管理数十亿美元业务的经验。他是 ProbabilityManagement.org 大学金融应用系主任,拥有斯坦福大学商学院的工商管理硕士学位。
设计和图表由Corrina Reffof谜语创意 。
在 AWS 上运行 Julia + Gurobi + Jupyter
如果你在麻省理工学院参加任何数据科学课程,你可能已经处于这种状态:

如果像我一样,你没有一个超级 16gb 内存的计算机,你可能会发现自己不得不等待几个小时才能运行完你的模型。
考虑到你可能不会把一周的每个小时都花在运行 Julia 模型上,你可以让它们在云上运行,只需运行时间的一小部分。今天我们来看看如何让 Julia 和 Gurobi 一起运行在云上。

1.设置 AWS 实例
您应该做的第一件事是在 AWS 上设置一个服务器。我假设你已经有一个帐户(如果没有,请在这里检查)。
为此,我决定使用一个 r5a.large 实例,运行 16gb 内存的 ubuntu 16。对于那些需要 GPU 的人,亚马逊也有一大堆。

一旦你继续通过审查(8gb 磁盘对我来说很好,所以没有必要改变什么)你将需要生成一个密钥对。这是访问服务器所需的密钥文件。我把我的命名为朱丽娅,把它下载到你电脑上的一个安全位置。

然后继续运行实例。因为我们将在默认端口上运行 jupyter 笔记本,所以我们需要在实例上打开端口 8888。单击列表中的实例,向下滚动到安全组并单击该组(如果您没有选择自定义组,名称应该以 launch-wizard-XX 开头)。

进入安全组页面后,单击您的安全组并向下滚动到入站选项卡。点击编辑并打开 TCP 端口 8888,允许所有连接。

您已经为新服务器做好了一切准备!我们现在将 ssh 到它,并开始安装我们需要的文件。
2.安装必要的软件包
以下假设你在 Macbook 或 Linux 机器上。如果你用的是 windows,那么我建议用 Putty 来访问服务器。在这里阅读如何做。
打开一个终端,首先对您之前下载的密钥文件授予适当的权限:
chmod 400 ~/Desktop/julia.pem
Sssh 进入您的服务器(在 AWS 的实例页面上找到公共 DNS 名称):
ssh-I ~/Desktop/Julia . PEM ubuntu@ec2–XX.compute-1.amazonaws.com

更新和升级必要的 ubuntu 软件包:
sudo apt 更新;sudo apt 升级-y
安装 Julia 1.2.0
在撰写本文时,最新的稳定版本是 1.2.0,下载页面在这里。
在服务器上运行:
wgethttps://Julia lang-S3 . Julia lang . org/bin/Linux/x64/1.2/Julia-1 . 2 . 0-Linux-x86 _ 64 . tar . gz
tar xvfz Julia-1 . 2 . 0-Linux-x86 _ 64 . tar . gz
安装 Gurobi
为了让它工作,你需要安装 Gurobi v7.x.x(稍后会详细介绍)。
在服务器上运行:
https://packages.gurobi.com/7.5/gurobi7.5.2_linux64.tar.gzwget
tar xvfz guro bi 7 . 5 . 2 _ Linux 64 . tar . gz
然后将 Julia 和 Gurobi 添加到文件系统路径中。打开 ~/。bashrc 使用您最喜欢的文本编辑器,并将其附加到末尾:
export guro bi _ HOME = "//HOME/Ubuntu/guro bi 752/Linux 64 "
导出 LD _ LIBRARY _ PATH = "/home/Ubuntu/guro bi 752/Linux 64/lib "
导出 GRB 许可证文件= "/home/Ubuntu/guro bi 752/Linux 64/guro bi . lic "
导出路径= "/home/Ubuntu/guro bi 752/Linux 64/bin:/home/Ubuntu/Julia-1 . 2 . 0/bin:$ PATH "
要测试新添加的变量,请运行:
来源~/。bashrc
朱莉娅
如果您看到提示,就可以开始了!
设置 Gurobi 许可证(棘手的部分)
我们现在需要激活古罗比。现在的困难是,我们将使用学术许可证在云上运行 Gurobi。但是为了提取激活所需的许可文件,主机必须在麻省理工学院的网络上。我们将使用另一种方法来获取许可证的详细信息。它假设你的个人电脑连接到麻省理工学院的网络,并只与 Gurobi 的 v7 版本。
首先,通过在服务器上运行以下命令来获取主机信息的详细信息:
grbprobe

头部到https://www.gurobi.com/downloads/free-academic-license/,在底部拿到你的执照密钥。
您现在必须构建这个 URL(用实际数据替换):
http://apps.gurobi.com/keyserver?id =
在我的例子中,url 是:
在你连接到麻省理工网络的个人电脑上运行这个。在文本编辑器中格式化输出,如下所示:

现在在 AWS 服务器上将它粘贴到一个新文件中,该文件位于/home/Ubuntu/gurobi 752/Linux 64/gurobi . lic
(如果您更改这些位置中的任何一个,请更新之前设置的环境变量)。
要检查激活是否成功,请在服务器上运行以下命令:
gurobi.sh

如果命令返回与上面相同的输出,就可以开始了!
安装 Jupyter 笔记本
安装 jupyter 笔记本很容易,只需运行这 3 个命令:
卷发https://bootstrap.pypa.io/get-pip.py|须藤蟒 3
sudo apt-get -y 安装 ipython
pip3 安装 jupyter
最后安装下面的 julia 包
朱莉娅
使用 Pkg
Pkg.add("JuMP ")
Pkg.add("Gurobi ")
Pkg.add("IJulia ")
运行笔记本
我更喜欢使用存储所有笔记本的特定目录。当然这是可选的
mkdir ~/笔记本
CD ~/笔记本
在后台启动 jupyter 笔记本
nohup jupyter 笔记本>日志&
将日志文件打开到带有令牌的 url
尾部原木

3.打开个人电脑上的笔记本
您首先需要打开一个从您的计算机到远程服务器的隧道。运行以下命令(或通过 putty 执行):
ssh -i ~/Desktop/julia.pem -L 8888:本地主机:8888 ubuntu@ec2–XX.compute-1.amazonaws.com
现在,您可以在浏览器中粘贴带有上图中令牌的 url,并开始使用笔记本!
希望这样你可以更快地在后台运行你的模型!
下一个 :我会试着建立一个亚马逊 AMI 镜像,这样你就可以开始一个预装了所有东西的新服务器了!
在远程服务器上运行 Jupyter 笔记本电脑

Jupyter 笔记本是许多数据科学家工具箱中的必备工具。作为一个工具,Jupyter Notebook 可以通过以交互方式更容易地执行数据分析、模型原型制作和实验来提高生产力,从而缩短从编码到看到结果的反馈循环。
在许多情况下,在笔记本电脑或工作站上运行 Jupyter 笔记本就足够了。然而,如果您正在处理大型数据集,进行计算成本高昂的数据处理,或者学习复杂的模型,您可能需要比笔记本电脑更强大的功能。也许你正在大型图上运行图卷积网络,或者在大型文本语料库上使用递归神经网络进行机器翻译,并且需要更多的 CPU 内核、RAM 或几个 GPU。幸运的是,您可能在远程服务器上拥有这些资源!
如果您的远程服务器有图形用户界面(GUI ),那么您很幸运。您可以使用远程桌面软件访问远程服务器,或者像在笔记本电脑上一样使用 Jupyter Notebook。
然而,许多服务器没有 GUI。如果您处于这种情况,您可以通过在您的笔记本电脑上编写 Python 脚本来设置您的实验,在您的一小部分数据上运行它以验证它可以运行,将它复制到远程服务器,并从命令行执行它。您甚至可以在笔记本中设置实验,并使用jupyter nbconvert --to script your_notebook.ipynb将笔记本导出到脚本中。尽管这种工作流确实允许您在远程服务器上运行代码,但是您不能再使用 Jupyter Notebook 来进行交互操作,例如,试验您的模型和可视化您的结果。太可惜了!
在这篇文章中,我将向你展示如何在远程服务器上运行 Jupyter 笔记本,以及如何在你的笔记本上访问它。我还将展示如何设置两个bash命令来简化整个过程。
启动远程笔记本服务器
我们将使用安全 Shell 协议 (SSH)在远程服务器上启动 Jupyter 笔记本服务器。SSH 允许我们向远程服务器发送命令。基本语法如下:
ssh username:password@remote_server_ip command
您应该发送的确切命令在一定程度上取决于您的上下文。在我的例子中,我与其他人共享一个远程服务器,因此没有在共享环境中安装 Jupyter。因此,我的第一步是转到我的项目文件夹,激活虚拟环境,并启动笔记本服务器。特别是,我想在远程服务器上执行以下三个bash命令:
cd project_folder
. virtual_environment/bin/activate
jupyter notebook --no-browser --port=8889
我执行带有--no-browser标志的jupyter notebook命令来启动 Jupyter 笔记本,启动一个浏览器,因为远程服务器如果没有 GUI 就不能显示浏览器。我还使用--port=8889标志将端口从默认端口 8888 更改为端口 8889。这是个人喜好;将本地和远程笔记本放在不同的端口上,以便更容易看到我的代码在哪里运行。
为了在远程服务器上执行命令,我们运行组合命令
nohup ssh -f username:password@remote_server_ip "cd project_folder; . virtual_environment/bin/activate; jupyter notebook --no-browser --port=8889"
请注意,我将这三个命令排成一行,并用;代替换行符将它们分开。执行此命令将在端口 8889 上启动 Jupyter 笔记本服务器,并让它在后台运行。最后,我在ssh命令中添加了-f标志,将进程推到后台,并在前面添加了nohup命令,使进程的所有输出静音,这样您就可以继续使用终端窗口。你可以在这里阅读更多关于nohup命令的内容。
访问您的笔记本
您现在可以通过输入 url 来访问笔记本
remote_server_ip:8889
该命令要求您记忆 IP 地址或标记网页。然而,我们可以通过使用端口转发让访问远程笔记本就像访问本地笔记本一样简单:
nohup ssh -N -f -L localhost:8889:localhost:8889 username:password@remote_server_ip
-N标志告诉ssh不会执行任何远程命令。此时,我们不需要执行任何远程命令。如前所述,-f标志将ssh进程推到后台。最后,-L标志使用语法local_server:local_port:remote_server:remote_port指定端口转发配置。该配置指定所有发送到本地机器上端口8889的请求,例如,您的笔记本电脑,发送到远程机器上username:password@remote_server_ip的端口8889。如前所述,nohup命令被添加到前面,以使输出静音。
上述命令的效果是,您现在可以在浏览器中访问远程 Jupyter 笔记本服务器
localhost:8889
就像您在本地运行笔记本一样。
停止远程笔记本服务器
原则上,您可以让笔记本服务器在远程服务器上无限期运行(除非重启或崩溃),但是您可能需要停止服务器,例如升级您的jupyter版本。如果你需要停止它有两种方法:通过浏览器或命令行。
通过浏览器窗口
在 Jupyter 笔记本的最新版本中,您可以在浏览器窗口的右上角找到一个退出按钮,如下图中的箭头所示。如果您按下它,您将不得不使用我们之前看到的启动命令重新启动服务器。

The Quit Button
通过命令行
如果您无法升级到具有 Quit 按钮的较新版本的 Jupyter,或者只是喜欢通过终端工作,您也可以从命令行停止服务器。Jupyter 有一个停止笔记本的 shell 命令:
jupyter notebook stop 8889
其中8889是端口号。您可以使用命令在远程服务器上执行它
ssh username:password@remote_server_ip "jupyter notebook stop 8889"
不幸的是,这个命令目前正在被调试,但是我已经把它包含在这里,希望它在将来能够工作。但是,作为一种变通方法,您可以使用以下命令终止jupyter进程:
ssh username:password@remote_server_ip "pkill -u username jupyter"
其中-u username表示只有由username启动的jupyter进程应该被终止。这样做的缺点是,如果您同时运行多个笔记本服务器,您将关闭所有的笔记本服务器。最后,您当然可以通过登录到远程服务器、启动笔记本服务器并保持终端窗口打开来手动管理服务器。这允许您使用常用的CTRL+C键盘命令关闭笔记本服务器。
简化您的工作流程
记住所有这些命令可能相当麻烦。幸运的是,我们可以通过为每个命令创建 bash 别名来简化工作。将下面几行添加到您的~/.bashrc文件中:
通过在终端中键入source .bashrc来加载命令。现在,您可以在终端中使用命令remote_notebook_start和remote_notebook_stop分别启动远程笔记本服务器(并设置端口转发)和关闭它。
总结
在这篇文章中,我向您展示了如何使用 bash 命令在远程服务器上启动、访问和停止 Jupyter 笔记本,并展示了如何创建 bash 别名来简化这些操作。
我希望这些命令可以提高您的数据科学生产力,几乎无缝地允许您获得 Jupyter 笔记本和远程服务器上可用的任何计算资源的好处。
喜欢你读的书吗?考虑在Twitter上关注我,在那里,除了我自己的帖子之外,我还分享与数据科学和机器学习的实践、理论和伦理相关的论文、视频和文章。
如需专业咨询,请在LinkedIn上联系我,或在Twitter上直接留言。
在 STM32 MCUs 上运行 Mobilenet
作者:Alessandro Capotondi&Manuele Rusci,博洛尼亚大学
人工智能驱动的高能效边缘设备
物联网现已成为现实。今天,主要的供应商正在通过他们的在线平台向提供数十种云服务来加工和存储个人数据。另一方面,边缘设备的技术仍然存在一些限制。例如,你们中的任何人想要在他家门口放置无线摄像机,都很可能会遇到缺少电源插头或电池组的情况,如果连续播放图像,就需要经常更换。因此,始终在线功能的最终目标与能源限制密切相关。
为了打破这一障碍,驱动关键词是智能:边缘的物体应该表现得像小大脑一样,高效地执行数据到信息的转换,对数据流量的减少产生明显的影响,从而在能源方面节省大量资金。
当遇到深度学习(DL)方法时,节能智能提出了两个主要挑战,如以下问题所示:
- 哪种深度学习模型最适合我们能源受限设备的可用资源,以及我们如何在其上高效运行该模型?我们能否在不降低准确性指标的情况下,对模型进行微调,以适应目标架构上的实现?
- 我们能否改进边缘设备架构,以有效支持给定的 DL 模型工作平台?
我们认为回答这些问题没有正确的顺序。相反,两边同时工作会产生最好的结果。在这篇文章中,我们将描述最近的深度学习模型,已经针对能效进行了训练和优化,如何通过我们优化的 CMSIS-NN 库扩展映射到 STM32H7 MCU 等边缘设备上。我们的代码是在线。
高能效嵌入式深度学习
谷歌通过发布新的工具和方法来拦截这种必要性,以支持将最先进的深度学习模型从能源昂贵的 GPU 转移到资源受限的边缘设备。可以观察到两个主要趋势:
- 网络拓扑很重要。为什么不缩小模型来减少参数和 MAC 运算量呢?尽管这一过程听起来像是魔法,但 Mobilenet 的经验表明,这是一种可行的方法,可以在模型大小和识别准确性指标之间实现最佳平衡。
- Tensorflow Lite 现在是一个众所周知的工具,用于将现有模型压缩到一个“更简单”的数值域(例如 8 位定点数据),目标是减少内存占用并加快计算。压缩的成本包括一个“特殊的”重新训练过程,需要达到与原始未压缩模型相同的精度水平。
在应用压缩后,8 位版本的 Mobilenet 在浮点基线方面没有表现出精度下降,目前用于分类任务或作为对象识别框架的主干 (TF Lite on Raspberry )。
基于 ARM Cortex-M7 的 MCU 上的 MobileNet
现在,要在能源受限的设备上运行压缩的 DL 模型,还缺少什么?ARM 试图通过发布 Cortex-M target 的 CMSIS NN 库来回答这个问题。不幸的是,该库没有跟踪 DL 模型压缩和量化的最新特性。事实上,有效的量化过程包括不对称范围内的线性量化。假设卷积层的权重参数在范围[a,b]内被量化,其中 a > 0 和 b < 0,则

asymmmetric quantization of real values r
因此,量化卷积核的内环可以计算为:

asymmetric convolution between q1 and q2 inputs
很容易注意到,现在 8 位卷积核必须执行偏置卷积运算,然后是缩放(和箝位)运算。我们在发布的 CMSIS-NN 扩展中提供了这些新的卷积内核。
最后但同样重要的是,内存!存储器很可能是 MCU 系统中最珍贵的构建模块。能量游戏的最大部分是在从存储器来回移动数据时进行的。
创新的架构解决方案在这里可以发挥关键作用(你还记得帖子开头的第二个问题吗?).然而,当试图在 ST32H7 设备上实现 MobileNet 时,内存限制是存在的(2MB 闪存+ 512kB L2 SRAM ),我们需要面对它。最简单的解决方案是使用 R/W L2 存储器存储临时层激活(输入和输出),同时将网络参数存储在只读闪存中。下一个问题是:哪种类型的 MobileNet 符合这些限制?

memory footprint requirement to map mobilenet networks on a STM32H7 MCU
上图中的每个点代表一个 Mobilenet 模型,具有特定的输入大小(128、160、192、224)和宽度乘数(0.25、0.5、0.75、1.0)。激活记忆要求在 x 轴上,权重参数在 y 轴上。红框界定了符合 STM32H7 MCU 存储器限制的模型的解空间。您会发现,并不是所有的网络都适合有限的内存空间(实际上,top1 得分最高的网络不适合)。
因此,我们从 TensorFlow 下载了一个 8 位量化 Mobilnet 160_0.25,并通过使用我们的库扩展移植到 STM32H7 中。结果:一个 1000 类的分类任务可以在 165 毫秒内运行(在 400MHz 下 65 个周期)。如果你想了解更多,你可以查看我们的 github 回购。关于这个话题的更多见解将很快出现。敬请期待!
使用 MagicStat 运行 Pearson 关联
相关性衡量两个变量之间的关系,例如,一个人的智商与他们的收入有关吗?
对于皮尔逊相关,我们需要两个变量。通常,两个变量都需要是连续的、正态分布的、无界的,比如身高或年龄。如果一个变量是绝对的,就像职业,或者如果有很多有界限的分数,就像一次考试中有很多 0 或 100 分,那么它就不起作用。
皮尔逊相关性的测试分数是 r ,其范围从-1 到+1。 r 分数告诉你两个变量之间关系的两件事:关系的强度和方向。 r 得分的绝对值越大,关系越强。如果数字是正数,那么这两个变量是直接相关的:一个变量上升,另一个也上升。如果值是负的,那么它们成反比:一个上升,另一个下降,反之亦然。

皮尔逊相关性的测试分数是 r ,其范围从-1 到+1。 r 得分告诉你两个变量之间关系的两件事:关系的强度和方向。 r 得分的绝对值越大,关系越强。如果数字是正数,那么这两个变量是直接相关的:一个变量上升,另一个也上升。如果值是负的,那么它们成反比:一个上升,另一个下降,反之亦然。
重要的是要记住,虽然皮尔逊相关可以确定两个变量之间的关系,但它不能(本身)确定是否存在因果关系,更不用说哪个变量导致了另一个变量。有些关系显然是第三个变量的产物。例如,冰淇淋销量与溺水呈正相关。现在,买冰淇淋会导致人淹死吗?当然不是。事实上,第三个变量(温度)负责冰淇淋和溺水之间的关系:随着天气变热,人们更有可能吃冰淇淋,也更有可能去游泳。
r 分数还与一个 p 值相关联,用于测试统计显著性。如果零假设为真,p 值评估我们偶然获得该数据集的可能性。因此, p 值越低,零假设为真的可能性就越小。通常,我们的阿尔法水平,统计显著性的阈值,被设置为 0.05。也就是说,如果我们的 p 值低于 0 . 05,那么我们拒绝零假设。
皮尔逊相关性的 p 值由两个因素决定:关系的强度和自由度。关系越强(无论是负的还是正的),p 的值越低。皮尔逊相关的自由度是 N 减 2,所以你的样本越大,自由度就越多,你的 p 值就越低。
现在我们知道了什么是相关性,让我们来看一个例子。假设我们想知道一个人的智商和收入是否相关。我们有下面的数据集。

我们的假设是,更聪明的人更有技能,需求更高,因此赚更多的钱。然而,智商和收入之间的关系并不完美,不是吗?影响一个人收入的不仅仅是他们的智商:他们在哪个领域工作,他们有多少经验,甚至他们住在哪里。所以,智商和收入之间不会是完美的关系,甚至可能不会是特别强的关系。因此,我们将假设智商和收入之间存在适度的正相关关系。一般来说,我们希望有理论支持的假设。这样我们就可以避免“钓鱼探险”,这种探险会将变量随机放在一起。在没有基于理论的假设的情况下进行测试,会增加你可能发现的任何关系只是由于偶然的可能性。在最后一栏,我们也有每个人的脚的大小。显然,我们不会假设脚的大小与智商或收入之间有任何差异。
现在我们有了假设,让我们看看如何在 MagicStat (版本 1.0.8)上执行关联。
1-)选择一个数据文件
通过单击“选择数据文件”按钮选择您自己的数据集。如果您想使用样本数据文件,请单击工具栏上的“样本数据集”,将其保存到您的硬盘上,然后单击“选择数据文件”并导航到您保存它的位置。

2-)浏览数据集
选择数据集后,单击“浏览”按钮。

选择数据集后,单击“浏览”按钮。窗口右侧是数据集的一览信息,包括变量信息、条形图和直方图。

4-选择“皮尔逊相关”模型
单击“选择一个模型来分析您的数据”,并在下拉列表中选择“Pearson Correlation”。

5-选择变量
单击“选择变量”按钮,并选择您想要在模型中包含的变量。在这里,我们选择“智商”、“收入”和“脚的大小”。

6-分析数据集
最后,单击“分析”按钮。


口译结果
现在是解释我们在前面步骤中获得的结果的时候了。
在皮尔逊相关中,自由度纯粹是样本大小的函数,N 减 2。所以,是 52。
接下来是我们的相关表。正如我们假设的那样,在 0.41 的时候,智商和收入之间有一个适度的相关性,而脚的大小和智商或收入之间没有相关性。
下面是每种关系的 p 值,我们看到智商和收入之间的中度相关性的 p 值为 0.02,这意味着如果智商和收入之间没有关系,我们预计得到的数据集大约是千分之二——不太可能!。脚的尺寸-智商和脚的尺寸-收入的 p 值接近 1,这意味着它们之间不太可能有关系。
在相关表之后, MagicStat 给了我们一些图表。首先是关联热图,显示最强的关系在哪里。我们可以看到紫色表示智商和收入之间的适度关系,蓝色表示与脚的大小没有关系。
然后,我们可以选择一个散点图来可视化关系并检查异常值。如果我们看看智商-收入散点图,似乎没有任何明显的异常值。有了这个散点图和智商与收入之间的理论联系,我们可以对我们在数据集中发现的关系充满信心。
注:本文有两位作者,法提赫恩(PhD) 和布伦特摩根(PhD) 。
在 TPU 运行 PyTorch:一包把戏
在写这几行的时候,在 TPUs 上运行 PyTorch 代码还不是一个常用的方法。当然,TPU 已经针对 TensorFlow 进行了优化,并且主要用于 tensor flow。但 Kaggle 和谷歌在其一些比赛中分配了免费的 TPU 时间,人们不会简单地改变他最喜欢的框架,因此这是我与 TPU 在 GCP 训练 PyTorch 模型的经验(大部分是成功的)的备忘录。

Image by author
PyTorch/XLA 是允许这么做的项目。它仍在积极发展,问题得到解决。希望在不久的将来,运行它的体验会变得更加顺畅,一些错误会得到修复,最佳实践会得到更好的传播。
设置事物
我的设置包括:
- 带有预建 PyTorch/XLA 映像的 GCP 计算引擎虚拟机。按照 PyTorch/XLA github 第页的“使用预构建的计算虚拟机映像”部分进行设置。
- TPU 节点,使用本指令与“GCP 控制台”选项为自己创建一个。如果您的 GCP 项目有一个免费的 TPU 配额,您会收到一封电子邮件,描述您可以使用的版本和区域。除此之外,我没有找到一个直接的方法来验证创建 TPU 节点确实是免费的,除了看法案。
- Jupyter 笔记本,跟着这篇搞笑文章来套吧。没有朱庇特我再也无法工作了。你可能会注意到,当它对你起作用时,你会深呼吸。
- 我还发现,在某些情况下,使用谷歌云存储传输文件非常方便。例如,您可以在虚拟机上使用以下代码行来复制 Kaggle API 令牌,并使用它下载竞争数据。还可以使用
gsutil cp将文件复制回 GS bucket。
gcloud auth login
gsutil cp gs://bucket-name/kaggle-keys/kaggle.json ~/.kaggle
chmod 600 ~/.kaggle/kaggle.json
kaggle competitions download -c recursion-cellular-image-classification
除了 google storage,我还使用 github repository 将数据和代码从我的本地机器转移到 GCP 虚拟机,然后再转移回来。
请注意,TPU 节点上也运行着一些软件版本。它必须与您在虚拟机上使用的 conda 环境相匹配。由于 PyTorch/XLA 目前正在积极开发中,所以我使用夜间 TPU 版本:

与 TPU 一起训练
让我们来看看代码。PyTorch/XLA 有自己运行多核的方式,由于 TPU 是多核的,所以你想利用它。但是在此之前,您可能希望将模型中的device = ‘cuda’替换为
import torch_xla_py.xla_model as xm...
device = xm.xla_device()...
xm.optimizer_step(optimizer)
xm.mark_step()
...
只在 TPU 的一个核心上测试你的模型。上面代码片段中的最后两行替换了常规的optimizer.step()调用。
对于多核培训,PyTorch/XLA 使用自己的 DataParallel 类。在测试目录的中可以找到一个带有数据并行的训练循环的例子,我想强调与之相关的以下三点。
- DataParallel 保存模型对象的副本(每个 TPU 设备一个),这些副本以相同的权重保持同步。用户可以通过访问其中一个模型来保存重量:
torch.save(model_parallel._models[0].state_dict(), filepath)
2)每个数据并行内核必须运行相同数量的批处理,并且只允许运行完整的批处理。因此,每个历元使用少于 100%的样本运行,残差被忽略。对于数据集洗牌,这对于训练循环来说不是大问题,但是对于推断来说却是个问题。我使用单核运行进行推理,如上所述。
3)直接从 jupyter 笔记本上运行数据并行代码对我来说非常不稳定。它可以运行一段时间,但之后会抛出系统错误、内核死亡甚至 jupyter 崩溃。将它作为脚本运行似乎是稳定的,所以我创建了第二个笔记本来运行,代码如下:
!jupyter nbconvert --to script MyModel.ipynb
!python MyModel.py
绕过限制
PyTorch/XLA 设计导致 PyTorch 功能上的一系列限制。事实上,这些限制对 TPU 设备是通用的,显然也适用于张量流模型,至少部分适用。明确地
- 建议张量形状在迭代之间是相同的,这也限制了遮罩的使用。
- 要避免步骤之间迭代次数不同的循环。
不遵循这些准则会导致(严重的)性能下降。不幸的是,在我的损失函数中,我需要同时使用遮罩和循环。就我而言,我把所有东西都移到了 CPU 上,现在速度快多了。在你所有的张量上做my_tensor.cpu().detach().numpy()就行了。当然,它在需要跟踪梯度的张量上不起作用,而且由于转移到 CPU 上,它本身也会导致速度变慢。
性能比较
我的 Kaggle 比赛队友 Yuval Reina 已经善意地同意在本节分享他的机器配置和训练速度以供比较。我还为我的笔记本(一台物理机器,这次不是 jupyter)添加了一个专栏,但是它与这些重量级的不匹配,并且在其上运行的代码没有针对性能进行很好的优化。
网络的输入是具有 6 个通道的 512×512 图像。我们测量了训练循环中每秒处理的图像,在这个指标上,所描述的 TPU 配置以 110 比 57 的比例优于 Yuval 的 Tesla V100。
TPU vs GPU performance comparison
如上所述(不含DataParallel)单核 TPU 的性能为每秒 26 幅图像,比全部 8 个内核加在一起大约慢 4 倍。
我们没有透露 Yuval 使用的架构,因为竞争仍在进行中,但它在大小上与 resnet50 没有明显不同。但是请注意,由于我们没有运行相同的架构,这种比较是不公平的。
试图切换到 GCP SSD 磁盘的火车图像并没有提高性能。
结论
总之,我在 PyTorch/XLA 的经历是复杂的。我遇到了几个 bugs 工件(这里没有全部提到),现有的文档和例子是有限的,TPU 固有的限制对于更有创造性的架构来说可能太过禁止。另一方面,它大部分是有效的,并且当它有效时,性能是好的。
最后,也可以说是最重要的,完成后不要忘记停止 GCP 虚拟机!
在本地模式下连续运行 StormCrawler,不使用 Storm cluster

在之前的文章中,我分享了我如何使用 StormCrawler 抓取网页并将其索引到 Elasticsearch 服务器的经验。然而,我使用了 Apache Flux 在本地模式下运行注入器和爬虫拓扑。运行这两种拓扑的缺点是,flux 使用 60 秒的 TTL,我们必须重复运行注入器和爬虫。此外,我们使用一个 FileSpout 从注入器拓扑中的一个文本文件中读取预定义的 URL。
在本文中,我将解释如何在没有 Storm 集群的情况下,在本地模式下同时运行注入器和爬虫拓扑。此外,我将使用 AWS 的简单队列服务(SQS)向注入器提供 URL,而不是从文本文件中读取 URL。
我将跳过最初的步骤,因为我在上一篇文章中简要地解释了它们。此外,我将本文分为两个部分。
第 1 部分— StormCrawler 基本配置
第一步
使用以下命令创建 maven 项目。假设你已经在你的电脑上安装了 maven 。
mvn archetype:generate -DarchetypeGroupId=com.digitalpebble.stormcrawler -DarchetypeArtifactId=storm-crawler-archetype -DarchetypeVersion=1.15
我已经给了 com.cnf271 和 stormcrawlersqs 分别作为 groupId 和 artifactId。
第二步
删除 crawler.flux 文件,并将以下文件从 StormCrawler GitHub 资源库的/external/elastic search文件夹添加到 source 文件夹。
- ES_IndexInit.sh
- es-conf.yaml
另外,删除src/main/Java/com/{ your-group-name }文件夹中的以下文件
- 爬虫拓扑
第三步
将storm crawler elastic search依赖项和 AWS Java SQS SDK 添加到 pom.xml 文件中。
<dependency>
<groupId>com.digitalpebble.stormcrawler</groupId>
<artifactId>storm-crawler-elasticsearch</artifactId>
<version>1.15</version>
</dependency><dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>LATEST</version>
</dependency>
第四步
更改 ES_IndexInit.sh bash 脚本中的配置以启用内容存储。
..."_source": {
"enabled": true
},
"properties": {
"content": {
"type": "text",
"index": "true",
"store": true
}
}
}...
第五步
执行 ES_IndexInit.sh bash 脚本在 Elasticsearch 服务器中创建索引。
E:\stormcrawlersqs\stormcrawlersqs>ES_IndexInit.sh
既然基本配置已经完成,我将继续讨论本文的实际目标。
第 2 部分-为 URL 注入和 web 爬行创建单独的实例
在没有风暴集群的情况下,在本地模式下连续运行 StormCrawler,实际上是什么意思?
我将解释我是如何设法在没有任何风暴集群在后台运行的情况下连续运行爬虫的。为了做到这一点,我创建了两个单独的 StormCrawler 实例,Injector 和 Crawler 分别执行 URL 注入和 web 抓取。此外,我还创建了一个 SQSSpout 来读取来自 AWS SQS 的队列消息。下图给出了它是如何发生的大致情况。

从上图中可以明显看出,AWS SQS 已被用于向注入器实例发送队列消息,注入器实例用状态索引的域细节更新 Elasticsearch 服务器。
Crawler 实例,另一方面,持续寻找新的 URL(处于 DISCOVERED 状态的 URL ),这些 URL 已经由 Injector 实例发送到 ES 服务器。Crawler 实例将从相关页面中抓取数据,并用内容数据更新 Elasticsearch 服务器。
在源文件夹中为 Injector 和 Crawler 以及 SQSSpout 类创建两个单独的类。
- 注射拓扑
- 爬虫拓扑
- 风暴 sqsqqueuespout
注射器实例( 注射器拓扑 )
如前所述,注入器实例将使用stormsqqueuespout从 AWS 的 SQS 读取消息,我已经实现了类似于FileSpout的 StormCrawler 核心库。
因此,Injector 实例包含一个 spout 和两个 bolts,用于从队列中读取消息、过滤 URL 和更新爬行状态。
以下要点显示了使用stormsqsquespout从 SQS 队列中读取数据的注入器实例。我使用了一个 config.properties 文件来存储和读取 AWS 凭证以访问 SQS 消息。
保存在 config.properties 文件中的 AWS 信息如下*、*
*# AWS SQS CREDENTIALS
aws.sqs.followerQueueUrl={queueUrl}
aws.sqs.accessKey={accessKey}
aws.sqs.secretAccessKey={secretAccessKey}
aws.sqs.region={Region}*
SQS 壶嘴(stormsqqueuespout)
stormsqsquespout 是本文的重点之一。当注入器实例启动并运行时,它使用 StormSqsQueueSpout 来读取由 SQS 发送的要被爬网的 URL。
注意,我使用了下面的 json 格式来发送 url 到使用 SQS 的注射器实例。
*{"url":"[https://www.bbc.co.uk/](https://www.bbc.co.uk/)"}*
以下要点显示了如何使用 ISpout 接口的 nextTuple() 来接收和处理发送到消息队列的 SQS 消息。
next tuple()-调用此方法时,Storm 请求 Spout 向输出收集器发出元组。此方法应该是非阻塞的,因此如果 Spout 没有要发出的元组,此方法应该返回。nextTuple、ack 和 fail 都是在 spout 任务的单线程中的一个紧循环中调用的。当没有元组要发出时,礼貌的做法是让 nextTuple 休眠一小段时间(比如一毫秒),以免浪费太多 CPU。
爬虫实例( 爬虫拓扑 )
顾名思义,Crawler 实例使用单个喷口和几个螺栓来完成实际的爬行部分。
以下要点是如何使用aggregation spout从 ES 服务器检索 URL,以及如何使用其他 bolts 获取、过滤、抓取和索引抓取的内容的示例。**
一旦正确配置了所有必需的类,就可以构建 maven 项目。
**mvn clean package**
现在项目已经打包,您可以使用下面的命令启动两个独立的注入器和爬虫实例。打开两个终端并运行以下命令。
喷油器
**java -cp target\stormcrawlersqs-1.0-SNAPSHOT.jar com.cnf271.InjectorTopology -conf es-conf.yaml -local**
履带
**java -cp target\stormcrawlersqs-1.0-SNAPSHOT.jar com.cnf271.CrawlerTopology -conf es-conf.yaml -local**
继续发送 SQS 消息,并检查 Elasticsearch 服务器不断更新。
使用 ExecutorService 在一个实例中同时运行注入器和爬虫
您可以使用 util.concurrent 包中的 ExecutorService 来运行单个实例,而不是分别运行两个实例。
**ExecutorService executorService = Executors.*newFixedThreadPool*(2);
executorService.execute(new InjectorTopology());
executorService.execute(new CrawlerTopology());**
我已经将示例项目添加到我的 GitHub 资源库中,供您参考。
使用数据运行
2019 波士顿马拉松赛分析

距离 TCS 纽约市马拉松还有不到一个月的时间,这让我们这些跑步者开始思考我们为穿越五个区的 26.2 英里旅程做了多少准备。虽然我们都在分析课程,继续训练,并对比赛日的天气感到压力,但我想对 2019 年波士顿马拉松赛进行统计分析。我选择这场马拉松有 3 个原因:这是世界上最大的马拉松之一,2019 年 4 月 15 日的结果已经公布,很多波士顿马拉松选手来自纽约(你会在下面看到)。
美国每年大约有 570 场马拉松比赛。波士顿马拉松是世界上最古老的马拉松,始于 1897 年。我想从统计分析开始这个项目。分析包括图表和描述,随后是数据的结论。
网页抓取
我从网上收集数据开始这个项目。用来抓取比赛结果的来源是 https://www.baa.org/races/boston-marathon/results.的
我使用 python 库 Beautiful Soup 将结果放入 list/dataframe。然后对数据进行了统计。
统计观测结果
在 26647 名跑步者中,平均年龄为 42 岁,平均正式时间为 3 小时 53 分 2 秒。年龄最大的选手是 83 岁,年龄最小的选手是 18 岁。
下图显示了每个年龄组的参与者。你会发现 40 到 50 岁之间的年龄相当高。

下图中橙色的男性通常比参加 2019 年马拉松比赛的女性年龄大。男性平均年龄约为 45 岁,而女性平均年龄约为 40 岁。

下面的最后一张图表显示了居民来自的前 20 个城市。

年龄反映了跑步者的总体排名吗?
让我们来看看…

你可以看到我们 42 岁时正常化前的分布。标准化后显示为粉红色。我们希望将官方时间转换为秒,以便查看年龄和时间之间是否存在相关性。
重要的是要注意我们的自变量和因变量。自变量是独立的变量,不能被其他变量改变。在这种情况下,我们的独立变量是跑步者的年龄。因变量是依赖于自变量的值的变量。在这种情况下,我们认为官方时间取决于跑步者的年龄。
- 官方时间。应用(lambda x: x.total_seconds()/3600)
- lr_model = ols(公式= '年龄~官方 _ 时间',数据=df2)。适合()

y = 3.16 + 0.017x
你可以看到我们有一个极低的 R 平方值。这可能是因为我们的数据集非常大(超过 26,000)。所以我们想通过绘制两个变量的相关性来进一步挖掘。
相互关系
我想分析年龄变量与参与者的总体排名之间的相关性有多强。我对此的想法是,年龄越大,速度越慢,这意味着整体排名越高。我们的总体排名和年龄之间的相关性= 0.3,这意味着这两个变量具有正的但低的相关性。

y = 3.16 + 0.017x
如你所见,在我们的分析中有许多观察结果。穿过观测值的线称为回归线。这条线符合我们所有的观察。回归线基于最小二乘法。
请注意,y 轴截距为 3.16,斜率为 0.017(这就是为什么我们的回归线略有倾斜。我们的线性方程表明,y(因变量)是跑步者年龄的结果。
Mean Age - 42
Mean Official Time - 3.88(42, 3.88) is the point at which the X and Y cross

上面的 Q-Q(分位数-分位数)图是一个概率图,这是一种通过绘制两个概率分布的分位数来比较它们的图形方法。这是根据要求的分布对数据的整体形状进行的直观检查。
结论
我们可以在上面的图表中看到,跑步者的年龄和跑步者的官方时间之间存在正相关关系。我们有低相关性和低 r 平方,这可能是因为我们有超过 26,000 个观察值。
我是一名顾问,试图找出公司对这些数据感兴趣的原因。当分析一个公司的营销组合时,你用 4 P 制定战略:产品、价格、促销和地点。
假设你是一家刚起步的服装公司,你想在大城市的跑步者中有效地推广你的产品(产品)。根据上面分析的研究,我建议春天在波士顿地区(地点/促销)设立一个 popup 位置。如上所述,波士顿马拉松是美国最古老和最著名的马拉松之一。让你的目标市场年龄组在 40-50 岁之间,你的定价策略要针对这个年龄段(价格)。
集成学习案例研究:在 Google Colab 免费 GPU 上运行 XGBoost
本文是一个案例研究的第二部分,我们正在探索 1994 年人口普查收入数据集。在的第一部分中,我们深入研究了数据集,比较了一些集成方法的性能,然后探索了一些有助于模型可解释性的工具。
在第二部分中,我们将探索一种叫做梯度增强的技术和谷歌合作实验室,这是一个免费的 Jupyter 笔记本环境,不需要设置,完全在云中运行。
什么是梯度增强和 XGBoost?
梯度推进是一种集成方法,很像我们上次讨论的打包和粘贴。然而,Boosting 与前面提到的方法的不同之处在于它如何进行这种模型组合。它使用技术将几个弱学习者组合成一个强学习者。
其他集成方法依赖于同时构建几个孤立的基础学习器,然后用于进行预测,而 Boosting 算法依赖于顺序过程,其中每个模型试图纠正以前模型的错误。这导致了一个主要的效率缺陷,因为模型是一次创建一个,并且依赖于先前迭代获得的结果
梯度推进采用梯度下降算法来最小化顺序模型中的误差。因此,本质上,它是一个优化问题,目标是最小化误差(损失)函数。
XGBoost(极限梯度增强)反过来也是梯度增强算法的优化实现。它的特点(除了其他增强):并行树构建,缓存感知访问,稀疏感知,正则化(L1 和 L2),加权分位数草图。该库已经成为近年来赢得许多数据科学竞赛的首选解决方案之一。
一些 XGBoost 超参数
原作者将 XGBoost 超参数分为 3 类:
- 通用参数:控制算法整体功能的超参数;
- 助推器参数:在算法的每一步控制单个助推器(树或回归)的超参数;
- 学习任务参数:配置要执行的优化的超参数;
XGBoost 最大的优势之一是可定制的数量。要查看可用超参数的完整列表(它非常广泛),我强烈建议您查看项目文档页面。
XGBoost 提供了一个 scikit-learn 兼容的 API,一些参数的名称略有不同,但它们的工作方式与常规库 API 相同。
我们将简要回顾一些将在案例研究中调整的超参数,以便更好地理解它们:
- booster: 允许我们选择要使用的每个 booster:GB tree,用于基于树的模型,或者 gblinear,用于线性模型。
- 目标:是学习任务超参数的一部分,它规定了优化过程中要使用的学习任务(回归、分类、排序等)和函数。
- tree_method: 我们将使用选项“gpu_exact”在 gpu 上运行
- eval_metric: 用于评估训练数据性能的指标。我们可以以 python 列表的格式传递多个指标,因此,我们将在案例研究中使用“error”(二进制分类错误)和“auc”。
- learning_rate (eta): 在每一步树提升之后,对新增加的权重进行缩放。这种技术被称为“收缩”,负责减少每棵树的影响,为未来的树留下空间来改进模型。通常,发现低于 0.1 的 learning_rates 产生更好的泛化误差。
- gamma: 当产生的分裂产生损失函数的正减少时,树节点被分裂。gamma 参数指定执行这种分割所需的最小缩减。它的值取决于所使用的损失函数。
- max_depth: 限制树木允许生长的最大深度。较大的树容易过度生长。
- colsample_bytree: 设置拟合每棵树时随机使用的要素(数据集列)的分数。
- 子样本:设置拟合每棵树时随机使用的观察值(数据集行)的分数。
- reg_alpha: 控制 L1 正则化。由于 L1 正则化倾向于将权重拉至零,因此当使用线性增强器或高维数据时,更推荐使用 L1 正则化。
- reg_lambda: 控制 L2 正则化。由于 L2 正则化鼓励较低的权重(但不一定是 0),它可以用于树助推器。
- n_estimators: 要拟合的树的数量
正如您所看到的,有多个超参数需要优化,上面给出的这些参数甚至还没有接近全部参数。
评估 XGBoost 性能
首先,我们将安装一个现成的 XGBoost 分类器,以获得对模型性能的基本了解,这意味着我们不会调整模型的大多数参数。
XGBoost 库实现了两个用于模型训练的主要 API:默认的学习 API 、,对模型进行更精细的控制;以及 Scikit-Learn API ,这是一个 Scikit-Learn 包装器,使我们能够将 XGBoost 模型与 scikit-learn 对象结合使用,如管道和随机搜索 CV 。
我们现在将主要关注于 Scikit-Learn API 。这个 API 提供了一种方法来评估随着新树的增加模型的性能变化。为此,我们必须向 fit 方法提供以下附加参数: eval_set ,要使用的评估集(通常是训练集和测试集),以及 eval_metric ,执行评估时要使用的度量。如果提供了这两个参数,评估结果将由拟合模型的 eval_results 属性提供。
但是说够了,让我们最后展示一些代码!由于本文是案例研究的第 2 部分,我们将不讨论预处理管道步骤的开发,因为这已经在本系列的第 1 部分中讨论过了。
首先,我们加载数据集,将其转换为 X 特征矩阵和 y 目标向量,执行预处理步骤,最后,将数据分成训练集和测试集。下面的代码突出显示了这个过程:
# load the dataset
income = pd.read_csv("income.csv")# Create the X feature matrix and the y target vector
X = income.drop(labels=["high_income", 'fnlwgt'], axis=1)
y = income["high_income"]# the only step necessary to be done outside of pipeline
# convert the target column to categorical
col = pd.Categorical(y)
y = pd.Series(col.codes)# validate the preprocessing pipeline by passing data through it
clean_X = preprocessing_pipeline.fit_transform(X)
clean_X_df = pd.DataFrame(clean_X, columns=X.columns)# split the clean_X into train and test sets
X_train, X_test, y_train, y_test = train_test_split(clean_X, y, test_size=0.20, random_state=seed, shuffle=True, stratify=y)
这样,我们终于可以训练我们的第一个 XGBoost 分类器了!为了更好地理解模型的演变,我们将把 n_estimators 超参数设置为 500。下面的代码片段突出显示了模型训练:
import time
from xgboost import XGBClassifier# create a default XGBoost classifier
model = XGBClassifier(n_estimators=500, random_state=seed)# define the eval set and metric
eval_set = [(X_train, y_train), (X_test, y_test)]
eval_metric = ["auc","error"]# fit the model
%time model.fit(X_train, y_train, eval_metric=eval_metric, eval_set=eval_set, verbose=False)
jupyter magic 命令返回 Python 语句或表达式的执行时间。在这种情况下,训练花费了 11.2 秒完成,对于一个开始来说还不错。
然后,我们可以通过进行一些预测来衡量模型性能:
# final model assessment
pred_test = model.predict(X_test)
pred_train = model.predict(X_train)print('Train Accuracy: ', accuracy_score(y_train, pred_train))
print('Test Accuraccy: ', accuracy_score(y_test, pred_test))print('Classification Report:')
print(classification_report(y_test,pred_test))

Figure 1: Default XGBoost performance
默认模型已经给了我们比上一篇文章中的 tunned random forest 更好的测试精度!让我们看看随着新估计量的增加,模型的表现如何:
# retrieve performance metrics
results = model.evals_result()
epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)fig, ax = plt.subplots(1, 2, figsize=(15,5))# plot auc
ax[0].plot(x_axis, results['validation_0']['auc'], label='Train')
ax[0].plot(x_axis, results['validation_1']['auc'], label='Test')
ax[0].legend()
ax[0].set_title('XGBoost AUC-ROC')
ax[0].set_ylabel('AUC-ROC')
ax[0].set_xlabel('N estimators')# plot classification error
ax[1].plot(x_axis, results['validation_0']['error'], label='Train')
ax[1].plot(x_axis, results['validation_1']['error'], label='Test')
ax[1].legend()
ax[1].set_title('XGBoost Classification Error')
ax[1].set_ylabel('Classification Error')
ax[1].set_xlabel('N estimators')plt.show()
plt.tight_layout()

嗯,看起来我们的模型运行良好,直到大约 300 个估计器,然后训练集的误差继续下降,而测试集的误差或多或少保持稳定。那可能是过度适应的迹象!避免这种情况的一种方法是使用 early_stopping_rounds 参数,一旦在指定的轮数后没有观察到改进,就停止执行。
使用随机搜索调整超参数
因此,看起来我们的默认模型通过其开箱即用的配置表现得相当好。然而,我们仍然可以通过调整一些超参数来从中获取更多信息,但是我们应该如何做呢?
想象一下,如果我们想要调整 7 个超参数,并为每个参数测试 3 个不同的值。手动调谐是不可能的,因为有大量不同的可能组合。如果我们随后决定使用简单的网格搜索来完成这项工作,我们将使用 37 = 2187 个不同的模型来结束 um!在这种情况下,如果我们将拟合默认模型所需的时间(11.2 秒)视为一般经验法则,那么训练将需要大约 408 分钟或 6.8 小时!
因此,正如我们上次所做的,我们将使用随机搜索来调整参数,它可能不会找到最佳解决方案,但会在合理的时间内找到“足够好”的解决方案。
使用 scikit-learn 的randomzedsearccv,我们配置了搜索空间,以包括 learning_rate 、 colsample_bytree 、子样本、 max_depth 、 n_estimators 、 reg_lambda、和 gamma 超参数。我们还将迭代次数限制为 50 次,这样实验不会运行太长时间。配置和安装该模型的过程如下所示:
# create a default XGBoost classifier
model = XGBClassifier(
random_state=seed,
eval_metric=["error", "auc"]
)# Create the grid search parameter grid and scoring funcitons
param_grid = {
"learning_rate": [0.1, 0.01],
"colsample_bytree": [0.6, 0.8, 1.0],
"subsample": [0.6, 0.8, 1.0],
"max_depth": [2, 3, 4],
"n_estimators": [100, 200, 300, 400],
"reg_lambda": [1, 1.5, 2],
"gamma": [0, 0.1, 0.3],
}scoring = {
'AUC': 'roc_auc',
'Accuracy': make_scorer(accuracy_score)
}# create the Kfold object
num_folds = 10
kfold = StratifiedKFold(n_splits=num_folds, random_state=seed)# create the grid search object
n_iter=50grid = RandomizedSearchCV(
estimator=model,
param_distributions=param_grid,
cv=kfold,
scoring=scoring,
n_jobs=-1,
n_iter=n_iter,
refit="AUC",
)# fit grid search
%time best_model = grid.fit(X_train,y_train)
我们再次使用 %time 命令来测量训练过程的执行速度。这一次大约花了 20 分 19 秒在执行 50 轮后返回最佳模型。如果我们使用更大的搜索空间和更多的迭代次数,你现在可以知道这个过程是如何变得非常耗时的。
然后,我们可以检查最佳模型 AUC 分数和超参数:
print(f'Best score: {best_model.best_score_}')
print(f'Best model: {best_model.best_params_}')

Figure 3: XGBoost AUC score and hyperparameters after running on CPU
最后,我们可以进行一些预测来评估模型的整体性能:
pred_test = best_model.predict(X_test)
pred_train = best_model.predict(X_train)print('Train Accuracy: ', accuracy_score(y_train, pred_train))
print('Test Accuraccy: ', accuracy_score(y_test, pred_test))print('\nConfusion Matrix:')
print(confusion_matrix(y_test,pred_test))
print('\nClassification Report:')
print(classification_report(y_test,pred_test))

Figure 4: Tunned XGBoost performance
看起来我们在训练和测试的准确性上都有了一点点的提高,但是说实话并没有那么多。
利用 GPU 的力量
我们终于到达了你可能正在等待的部分!我们将使用 Google 联合实验室的免费 GPU 访问,有望加快拟合 XGBoost 模型的过程。
但是你如何配置你的工作空间呢?这是一个相当简单的两步过程:首先,你需要进入编辑>笔记本偏好设置,然后,在硬件加速器下拉菜单中选择 GPU 并按保存。就是这样!您的运行时将重新启动,然后就可以运行了。
在 XGBoost 方面,唯一改变的是包含了 tree_method 超参数。在创建模型时,随机搜索的其他内容保持不变!模型创建的变化可以在下面的代码片段中看到:
model = XGBClassifier(
tree_method = "gpu_hist",
random_state=seed,
eval_metric=["error", "auc"]
)
在用这种配置重新训练模型后,我们证实完成整个过程大约需要 18 分钟。这可能看起来不是一个很大的进步,但它比之前的运行快了大约10%****!使用 GPU 的优势在较大的数据集上更容易看到,其中并行化开销将更多地由并行化速度的提高来补偿。
之后,我们重复这个过程来检查最佳的模型参数和性能。结果如下图所示:

Figure 5: XGBoost AUC score and hyperparameters after running on GPU

Figure 6: GPUtunned XGBoost performance
我们可以看到培训和测试准确性的又一次轻微提高,这总是很好的,不是吗!?
模型的可解释性如何?
因此,为了帮助更好地理解 XGBoost 模型预测,我们可以使用本系列最后一部分中介绍的任何技术:检查并绘制拟合模型的 feature_importances_ 属性;使用 ELI5 特征权重表和预测说明;最后,使用 SHAP 图。
然而,XGBoost 库还有另一个锦囊妙计,它提供了一个内置的绘图 API,用于生成 boosting 中使用的各个树的特性重要性和表示图!
为了绘制全局特征重要性,我们可以使用 plot_importances 方法。可以指定三个度量之一来计算单个特征分数:
- ****特征权重:根据特征在树中出现的次数计算得分
- ****增益:根据使用该特性的拆分的平均增益计算得分
- ****覆盖率:根据使用该特性的分割的平均覆盖率(受分割影响的样本数)计算得分
下面的代码显示了这三个示例:
# store the winning model in a new variable
xgc = best_model_gpu.best_estimator_
# saving the feature names to the model
xgc.get_booster().feature_names = X.columns.to_list()# Create the feature importances plot
fig, ax = plt.subplots(1, 3, figsize=(15,5))# plot importances with feature weight
xgb.plot_importance(
booster=xgc,
importance_type='weight',
title='Feature Weight',
show_values=False,
height=0.5,
ax=ax[0],
)# plot importances with split mean gain
xgb.plot_importance(
booster=xgc,
importance_type='gain',
title='Split Mean Gain',
show_values=False,
height=0.5,
ax=ax[1]
)# plot importances with sample coverage
xgb.plot_importance(
xgc,
importance_type='cover',
title='Sample Coverage',
show_values=False,
height=0.5,
ax=ax[2]
)plt.tight_layout()
plt.show()

Figure 7: XGBoost feature importances
最后,为了绘制特定的树,我们可以使用如下所示的 plot_tree 方法:
# Create the feature importances plot
fig, ax = plt.subplots(figsize=(20,20))# plot a decision tree from the booster
xgb.plot_tree(booster=xgc, num_trees=0, ax=ax, rankdir='LR')plt.tight_layout()
plt.show()

Figure 8: XGBoost tree
结论
至此,我们结束了这个关于整体学习的两部分系列,我希望它是令人愉快的,也许还有点用处!
感谢阅读!请在下面留下你的想法。
在 Windows 10 上运行 Apache Kafka

卡夫卡的成长呈爆炸式增长。超过三分之一的财富 500 强公司使用卡夫卡。这些公司包括顶级旅游公司、银行、十大保险公司中的八家、十大电信公司中的九家,等等。LinkedIn、微软和网飞每天用 Kafka 处理四个逗号的消息(10 亿条)。
Kafka 用于实时数据流,收集大数据,或进行实时分析(或两者兼有)。Kafka 与内存中的微服务一起使用,以提供耐用性,并可用于向 CEP (复杂事件流系统)和 IoT/IFTTT 风格的自动化系统提供事件。— DZone
网上有很多关于这个话题的文章,但是很多都是断章取义的,或者只是从不能在 Windows 上运行的文章中复制粘贴而来的。虽然这是一个简单的安装有一些问题。
这篇文章将帮助你远离陷阱,在 Windows 10 平台上培养 Kafka。
Kafka 依赖 Zookeeper 作为其分布式消息传递核心。所以 zookeeper 服务器需要先启动并运行,这样 Kafka 服务器才能连接到它。
在你下载 Zookeeper 和 Kafka 之前,确保你的系统已经安装了 7-zip。(处理 tar 和 gz 文件的伟大工具。)
在本文中,首先,我们将确保我们有一些必要的工具。然后我们将安装、配置和运行 Zookeeper。之后,我们将安装、配置和运行 Kafka。
所以,让我们开始吧。
安装工具
《动物园管理员》和《卡夫卡》是用 Java 写的,所以你需要 JDK。许多网站会告诉你只安装 JRE。不用麻烦了。只需安装 JDK。这是 JRE 附带的。然后设置 HOME 和 PATH 变量。但首先,7 比 0。
安装 7-zip
你可以在这里找到 7-zip—
英文中文更简单。中国传统。世界语法语德语印度尼西亚语日语葡萄牙语巴西西班牙语泰语…
www.7-zip.org](https://www.7-zip.org/download.html)
当您安装 7-zip 时,请确保将其添加到您的右键菜单快捷方式中。这会让你的生活更轻松。
安装 JDK
它过去是免费的,现在仍然是免费的,只是现在你需要在 Oracle 创建一个帐户才能下载它。这是链接-
Java SE 13.0.1 是 Java SE 平台的最新版本了解更多信息寻找 Oracle OpenJDK 版本?甲骨文…
www.oracle.com](https://www.oracle.com/technetwork/java/javase/downloads/index.html)
JDK 将首先安装自己,然后它会问你要安装 JRE 的位置。
默认安装位置是“C:\Program Files\…”
通常把 Java 放在那里是没问题的,但是最好不要放在你的 Kafka 系统中。卡夫卡是为 Linux 设计的。我不会用包含空格的 Windows 目录名来推它。
我把我的 JDK 和 JRE 放在一个没有空格的路径中。我的安装位置是 C:\Java
设置路径
我们需要为所有的安装设置路径。因此,我们将在本文中多次讨论这个问题。我们将设置两种路径变量——用户变量和系统变量。在用户变量中,我们将添加安装位置的路径,在系统变量中,我们将设置 bin 目录的路径。
在 Windows 搜索栏中键入“Environment”。它会出现一个选项来编辑控制面板中的系统变量。点击它,你就会进入系统属性。点击右下角写着环境变量…的按钮。
用户变量
在顶部框中的用户变量下,单击 New 并添加 JAVA_HOME 和 JRE_HOME。对于 JAVA_HOME 的值,单击浏览目录按钮并导航到安装 JDK 的位置。我用的是 C:\Java\jdk1.8.0_221\
对于 JRE_HOME 的值,单击 Browse Directories 按钮并导航到安装 JRE 的位置。对我来说,那就是 C:\Java\jre1.8.0_221\
系统变量
在系统变量框中,双击路径并在末尾添加以下两个条目
%JAVA_HOME%\bin
%JRE_HOME%\bin
试验
如果设置正确,可以在任何目录下打开命令提示符。(一种快速的方法是使用 windows 文件资源管理器转到任何目录,然后在文件资源管理器的地址栏中键入“cmd”(不带引号)。它会在那个位置打开一个提示。)
导航到一个不同于 Java 安装的目录,这样您就可以真正知道您的路径变量是否在工作。
java 类型-版本
你应该看看这个-
C:\>java -version
java version “1.8.0_221”
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
如果您得到类似于 java 不被识别为内部或外部命令,那么您的路径设置不正确。为了确保这不是安装本身的问题,您可以转到 JDK 的 bin 目录并键入上面的命令。如果它在那里工作,但在其他地方不工作,这意味着系统找不到它。
对于在命令提示符下键入的每个命令,您的计算机都会在路径变量列表中查找匹配项。这就是为什么像这样的错误通常是路径问题。
安装动物园管理员
下载 Zookeeper 二进制文件。这里有一个可以下载的镜像
确保下载名称中包含 bin 的文件,而不是另一个文件。如果你下载了非 bin 文件,那么当你试图启动服务器时,你会得到一个错误。
[http://apache-mirror.8birdsvideo.com/zookeeper/stable/](http://apache-mirror.8birdsvideo.com/zookeeper/stable/)
右键单击该文件,并使用 7-zip 在同一位置提取它。这将提取 tar 文件,但它仍然不是真正的文件,所以您将该文件提取到哪里并不重要。
对于下一步,位置很重要:
右键单击 tar 文件,将其解压缩到名称中没有空格的目录。我把我的目录放在 C:\Apache
中,所以我得到了一个类似这样的目录。所以
C:\Apache\apache-zookeeper-3.5.6-bin
截至本文撰写之时,zookeeper 的稳定版是 3.5.6。你的可能不一样。
请注意名称后面的-bin。如果你没有看到这个,那么你已经下载并提取了错误的文件。回到镜子前。这很重要,否则当你启动 Zookeeper 服务器时,你会得到一个类似这样的错误
Error: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain
配置 Zookeeper
所有的配置都发生在一个文件中——配置文件,它在 conf 目录中。
转到 zookeeper 安装的 conf 目录。对我来说,它在
C:\Apache\apache-zookeeper-3.5.6-bin\conf
将 zoo_sample.cfg 文件重命名为 zoo.cfg
用文本编辑器打开它。
在这个文件中,您将看到一个名为 dataDir 的条目,其值为/tmp。它基本上告诉你该做什么
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
大多数网上的文章都告诉你用类似 dataDir=:\zookeeper-3.5.6\data 这样的东西来替换这一行
如果你这样做,你会遇到这样的错误-
ERROR— Unable to access datadir, exiting abnormally
Unable to create data directory :zookeeper-3.5.6data\version-2
Unable to access datadir, exiting abnormally
为了避免这个错误,请将您的日志指向比 bin 目录高一级的路径,如下所示
dataDir=../logs
(它可以是更高一级,也可以在同一目录中。您也可以键入从根目录 C:\)开始的绝对 windows 路径
这将在你的 zookeeper 安装目录中创建一个日志目录,当你运行服务器时,它将存储快照。
配置完成。让我们设置路径变量,这样系统可以从任何地方找到它。
设置路径
像以前一样,开始在 Windows 搜索栏中键入 Environment。它会出现一个选项来编辑控制面板中的系统变量。点击它,你就会进入系统属性。点击右下角写着环境变量…的按钮。
用户变量
在顶框的用户变量下,点击 New 并添加 ZOOKEEPER_HOME。对于该值,单击浏览目录按钮并导航到 Zookeeper 的安装位置。对我来说,那就是 C:\ Apache \ Apache-zookeeper-3 . 5 . 6-bin
系统变量
在系统变量框中,双击路径并在末尾添加以下内容
%ZOOKEEPER_HOME%\bin
启动 Zookeeper 服务器
在 zookeeper bin 目录下打开命令提示符,输入
zkserver
它会开始发出一大堆信息。下面是一些有趣的例子。(为了视觉上的清晰,我已经清理了多余的词语)。它们看起来像这样
2019–11–19 11:17:17986[myid:]—信息-> 获取信息
2019–11–19 11:17:17986[myid:]—WARN->获取警告
myid 为空,因为我的 dataDir 中没有 myid 文件。Zookeeper 通过 id 跟踪集群中的每台机器。要给机器分配一个 id,只需输入一个包含一个数字的文件名 myid(没有任何扩展名)。我在单一服务器模式下运行 Zookeeper 进行开发,因此没有必要设置 id。但是,如果我创建一个编号为 5 的文件(可以是任意的,但是如果集群中有多台机器,则需要是唯一的),那么命令行应该是这样的
2019–11–19 12:05:21400[myid:5]—INFO[main:FileSnap @ 83]—读取快照..\ logs \版本 2\snapshot.a6
Server environment:os.name=Windows 10
Server environment:os.arch=amd64
Server environment:os.version=10.0
Server environment:user.name=Bivas Biswas
Server environment:user.home=C:\Users\Bivas Biswas
Server environment:user.dir=C:\Apache\apache-zookeeper-3.5.6-bin\bin
Server environment:os.memory.free=946MB
Server environment:os.memory.max=14491MB
Server environment:os.memory.total=977MB
minSessionTimeout set to 4000
maxSessionTimeout set to 40000
Created server with tickTime 2000 minSessionTimeout 4000 maxSessionTimeout 40000 datadir ..\logs\version-2 snapdir ..\logs\version-2
Logging initialized [@5029ms](http://twitter.com/5029ms) to org.eclipse.jetty.util.log.Slf4jL
最后一行中对 log4j 的引用是对 zookeeper 使用的日志基础设施的引用。您还会注意到,它正在将快照记录到我们之前在配置文件中指定的日志目录中。
Snapshotting: 0x0 to C:Apachezookeeper-3.5.6-binlogs\version-2\snapshot.0
经过几秒钟的数据喷涌,它应该来到这些黄金线
Started AdminServer on address 0.0.0.0, port 8080 and command URL /commands
Using org.apache.zookeeper.server.NIOServerCnxnFactory as server connection factory
Configuring NIO connection handler with 10s sessionless connection timeout, 3 selector thread(s), 40 worker threads, and 64 kB direct buffers.
binding to port 0.0.0.0/0.0.0.0:2181
现在 Zookeeper 服务器运行在 localhost:2181 上。端口 8080 上的 AdminServer 是新增的。我们可以使用浏览器上的端口来监控 zookeeper。
但是,你不能去运行 zookeeper 的 2181 端口。Zookeeper 是 Kafka 用来作为 Kafka 集群的核心内核的。如果您在浏览器上导航到该端口,这将向它发送一些它不期望的 TCP 流量,您将使服务器崩溃。这是你将得到的—
Exception causing close of session 0x0: Len error 1195725856
所以,就这样了。你的 Zookeeper 可以在 Windows 10 上运行,而不需要使用 docker composer 或 Linux VM。
下一个——卡夫卡
卡夫卡是一个信息经纪人。它可以让你创建你认为像聊天室的话题。您在该主题上发布一条消息,订阅该主题的人将会收到该消息。接受者被称为消费者。信息张贴者被称为生产者。
Kafka 还有另外两种能力。一个是流处理 API,它基本上接收这些消息,并在接收者收到之前将它们转换为不同的值。这在实时数据流中实时发生。
另一个是连接器 API,让 Kafka 连接到数据库或存储系统来存储数据。然后,这些数据可用于 Hadoop、Map Reduce 等集群的进一步处理。除了向消费者实时传递消息之外,这种情况也会发生。
如今,卡夫卡是一个一体化的解决方案。以前,你需要一个像 Apache Storm 这样的流处理框架来转换流,但是有了 Kafka 的原生流 API,我们就不像以前那样需要 Storm 了。这取决于您的使用案例和对您有意义的拓扑,但最好有选择。
安装卡夫卡
从这里下载卡夫卡-
http://kafka.apache.org/downloads.html
获取二进制下载。在这一部分,你可能会看到多个标有 Scala x.xxx 的版本。如果你使用 Scala 作为客户端,那么就获取与你的 Scala 版本相匹配的版本。我使用 NodeJS 作为我的客户端,所以我得到哪个并不重要。在撰写本文时,Apache 推荐Kafka _ 2.12–2 . 3 . 1 . tgz所以这是我得到的版本。
使用 7-zip 将 tgz 解压缩到一个 tar 文件中。然后使用 7-zip 将 tar 文件解压到一个路径中没有空格的位置。我用 C:\Apache,所以解压后,我的卡夫卡住在这里——
C:\Apache\kafka_2.12–2.3.1
这篇文章越来越长,所以我打算把它分成两部分。接下来,我们将了解如何设置和配置 Kafka 服务器。
配置 Kafka
我们不会为 Kafka 设置任何环境变量。卡夫卡是寻找动物园管理员和 JDK 的人。甚至生产者和消费者都生活在卡夫卡生态系统中。它们不是在你的电脑上寻找卡夫卡的独立应用程序。简而言之,没有环境变量可以乱来。
但是,需要设置配置文件。
转到您的 Kafka 配置目录。对我来说是在
C:\Apache\kafka_2.12–2.3.1\config
我们可以从一个示例 server.properties 文件开始。
对于一个经纪人,我们只需要建立这一个文件。如果我们需要多个代理,那么为每个代理复制一次这个文件。例如,如果您需要两个消息代理,那么您最终会得到 server.b1.properties 和 server.b2.properties。
在每个文件中,您将更改以下内容—
- 经纪人 id
# The id of the broker. This must be set to a unique integer for each broker.broker.id=0
如果您只使用 1 个代理,则将其保留为 0。没什么好改变的。如果您有另一个代理,那么更改其他文件中的 id,使它们是唯一的。
# The id of the broker. This must be set to a unique integer for each broker.broker.id=1
- 更改日志目录。我坚持我的绝对路线。您可以在这里使用任何 Windows 风格的路径
# A comma separated list of directories under which to store log fileslog.dirs=C:\Apache\kafka_2.12–2.3.1\logs
- 复制因素就像硬盘上的 RAID。它将数据从一个代理复制到另一个代理,以实现冗余和容错。对于开发,我将把它保持在 1
浏览该文件中的字段。您会注意到超时值、分区值和默认 Zookeeper 端口号,如果出现问题,这些都将在以后的调试中派上用场。
默认情况下,Apache Kafka 将在端口 9092 上运行,Apache Zookeeper 将在端口 2181 上运行。
至此,我们完成了卡夫卡的配置。让我们启动服务器。
运行卡夫卡
确保 Zookeeper 服务器仍在运行。
导航到 Kafka 安装目录中的 bin 目录。在那里你会看到一个 windows 目录,进入那里。这是所有令人敬畏的 windows 实用程序存储的地方。对我来说,就是这里-
打开一个新的终端窗口
C:\Apache\kafka_2.12–2.3.1\bin\windows
(如果您忘记进入 windows 目录,而只是从 bin 目录启动,下面的命令将只是在 Visual Studio 代码中打开 shell 文件,而不是运行批处理文件)
kafka-server-start.bat C:\Apache\kafka_2.12–2.3.1\config\server.properties
你会看到这样的结果-
Client environment:java.compiler=<NA> (org.apache.zookeeper.ZooKeeper)
Windows 10 (org.apache.zookeeper.ZooKeeper)
Client environment:os.arch=amd64 (org.apache.zookeeper.ZooKeeper)
Client environment:os.version=10.0 (org.apache.zookeeper.ZooKeeper)
Client environment:user.name=Bivas Biswas
Client environment:user.home=C:\Users\Bivas Biswas Client environment:user.dir=C:\Apache\kafka_2.12–2.3.1\bin\windows (org.apache.zookeeper.ZooKeeper)
Initiating client connection, connectString=localhost:2181 sessionTimeout=6000 watcher=kafka.zookeeper.ZooKeeperClient$ZooKeeperClientWatcher$@57c758ac (org.apache.zookeeper.ZooKeeper)
[ZooKeeperClient Kafka server] Waiting until connected. (kafka.zookeeper.ZooKeeperClient)
此时,如果服务器等待 Zookeeper 响应超时,请转到运行 Zookeeper 的命令终端,然后按 enter 键。有时候如果《动物园管理员》空闲一段时间,我见过卡夫卡超时。
如果一切顺利,您将看到来自组协调器的一些元数据转储和偏移消息,看起来像这样,带有闪烁的等待光标
[GroupCoordinator 0]: Preparing to rebalance group console-consumer-83701 in state PreparingRebalance with old generation 1 (__consumer_offsets-10) (reason: removing member consumer-1–9bf4ef2d-97af-4e59–964e-5bb57b457289 on heartbeat expiration) (kafka.coordinator.group.GroupCoordinator)[GroupCoordinator 0]: Group console-consumer-83701 with generation 2 is now empty (__consumer_offsets-10) (kafka.coordinator.group.GroupCoordinator)
你会在动物园管理员终端看到一些活动。它可能会拍摄新的快照并启动新的日志文件。此时,您的卡夫卡已经启动并运行。
包扎
动物园管理员需要记住的几件事——
我们设置为日志目录的 dataDir 将很快被快照填满。
在我的测试中,用一个主题运行 Kafka 不到 15 分钟,产生了两个 65MB 的快照文件。这些快照是事务性日志文件,每次检测到节点发生变化时都会写入这些文件。
当 Zookeeper 将几个日志文件合并成一个更大的文件时,它会创建副本,但不会清理旧文件。所以自己清理这个目录。您可以使用 bin 目录中的 zkTxnLogToolkit 来配置日志保留策略。
如果您在 AWS 上部署 EC2 实例,并且使用 t2.micro 的免费层,服务器不会启动。
这是因为 zookeeper 和 Kafka 的默认堆大小约为 1 GB,而 t2.micro 上的内存为 1GB,因此它会抱怨内存空间不足。
为了避免这个错误,请在具有 4GB 内存的 t3.medium 实例上运行 Kafka,而不是在配置文件中减少堆大小。
没有什么比跟随一篇文章更令人沮丧的了,这篇文章的步骤并不像它所说的那样有效。这就是我开始写这篇文章的原因,当时我浏览了大量的破碎的文章并修复了错误。
如果您在这些步骤中遇到任何错误,请告诉我。如果你有困难,请在下面留言,我会尽快回复你。
快乐流媒体!
俄语开放语音转文本(STT/ASR)数据集
4000 小时的俄语 STT 数据

如果你不付铁价,你知道有人替你付了。生活的方方面面都是这样
原帖spark-in . me2019 年 5 月 1 日
TLDR
这是我们发布的俄语开放语音转文本(STT/ASR)数据集的附带帖子。这意味着有点轻松和开玩笑。所有的观点都是我自己的,可能我的同事们的观点不一样。这是非技术性的总结。不要太认真,可能 50%的文字是某种微妙的玩笑(如果你找到所有的复活节彩蛋,请敲我一下!).
总之,这里是数据集:

Dataset composition
TLDR:
- 我们已经收集并发布了一个具有4000+小时的数据集,用于训练俄语的语音到文本模型;
- 数据非常多样,跨领域,注释的质量从足够好到几乎完美不等。我们的目的是收集一个数据集,以某种方式将现实生活/商业应用联系起来。以学术的方式只收集纯粹/干净的数据没什么意思。理想情况下,该数据集是使用预先训练好的 STT 模型进行回购的第一步;
- 我们打算将这一数量增加到大约 10,000 小时,甚至可能增加到 20,000 小时,如果情况合适的话(我们知道如何达到 6-7k,我们会随机应变);
- 我们没有投入任何真金白银来创建这个数据集(当然除了我们的时间和精力),所以我们在 cc-by-nc 许可下发布它。如果您想将数据集用于商业目的,请点击此处;
- 你可以在这里看到发布历史;
加速 Imagenet 时刻
理想情况是这样的:
- 提取现有的公共模型和数据集;
- 收集一些你所在领域的 MVP 数据集;
- 建立一个 MVP 模型;
- 增加更多疑难病例;
- 验证、测试、冲洗和重复;
在计算机视觉(CV)和自然语言处理(NLP)等领域,有一些东西可以建立,这些东西只在 95%的情况下有效:
- 广泛共享的 Imagenet 预训练模型。每个框架都有一个类似于 this 的回购——在这里你可以得到任何种类的带有权重的 CV 模型。加水就行了;
- 在 NLP 中,根据我的经验,像 FastText 这样的工具效果最好。像伯特这样的现代巨大网络也能工作,但是在现实生活中我们并没有发现它们实用;
但是在俄罗斯的 STT,没有什么可以真正建设的
- 当然也有付费的 APIs 商业最新产品/来自政府相关实体的产品——但是它们有它们的缺点(除了是私有的或者是由不太透明的技术构建的);
- 公共数据集充其量是稀缺的(<100 hours) and non-diverse / too clean at worst;
- Even English public datasets … are academic and detached from real life usage;
- STT has a long history, and it has a bias towards being developed by large tech companies;
- Unlike Google / Facebook / Baidu which are known to publish stellar research (FAIR’s papers are awesome and accessible, Google less so), Yandex is not really known to add anything to the community;
在 STT 也有几个较少讨论的“抓住你”的好处:
- 有一种推测,即您需要多少数据来进行适当的归纳-估计范围从 5,000 小时到 20,000 小时。例如,Librispeech ( LS ,最流行的数据集之一)是 1000 小时,非常“干净”。谷歌和百度在各种论文中报告了针对各种设置的 10,000-100,000 小时数据的培训;
- 如果在 CV 中,你学习特征的“领域”是例如在 STT 的“猫”(也就是说,在某些位置上,参见 Hinton 关于这个的 CapsNets 的解释),那就有点复杂了。你的数据可以是干净的/嘈杂的。另外每种声音都有自己的领域,模特对声音的适应能力惊人。词汇也是一个问题。因此,基本上当有人报告 LS 提高了 3 个百分点(即 10%的 WER 降低到 7%的 WER)时,你应该对此持保留态度。我在 1-2 天内建立的初始管道能够很好地在 LS 上工作;
- 跨领域转移(即,当你在书本上训练,在电话上验证)是可行的,但效果很差。你很容易得到+20 便士的 WER。一些小事情也很重要,比如在嘈杂的环境中语调/说话方式的不同;
所以——你可以把我们的冒险视为第一步,为社区提供一套我们语言的公共模型(俄语,我们的大部分方法可以扩展到其他语言),让 Imagenet 时刻更近一步/为公众制作相当好的 STT 模型。
你可以说现在我们深陷在数据中。为了成功,我们需要更深入!请阻止我说出这些可怕的双关语。

寻求贡献者
如果你愿意为我们的数据集/事业做出合理的贡献,我们欢迎你!我们将确保尽可能友好地发布尽可能多的内容。
请在这里联系我们。
可以这样框。如果 4 个人(不是只在这个项目上花费 100%的时间)可以有所作为,那么你的加入可能会使天平向构建一个真正灵活的可部署模型倾斜?
如何不共享数据集
首先,这里列出了我不喜欢人们在分享数据集时一直做的事情:
- 显然,付费墙没有办法预先检查你将得到什么;
- 学术象牙塔态度——“我们的数据集很酷,很大,但在现实生活中毫无用处”;
- 注册墙。是的,“我们的数据集是公开的,但我们将只为被选中者共享它”。这东西。是的,如果我们决定不与你分享,你不会得到通知。或者最有可能的是——没人付钱给版主;
- 通过 Google Drive 分享(顺便说一句,你可以通过 Google Drive 使用
wget,你需要下载一个 cookie 并使用他们的链接结构)或者依靠临时/动态链接的东西。理想情况下,你应该能够使用wget或者更好的aria2c来获取数据; - 托管差,CDN 差,速度差。当人们共享一个数据集时,这是可笑的,这可能会花费 10 万美元以上——从零开始手工注释需要 100 万美元,但每月节省 100 美元用于真正正确地托管数据集;
- 通过 torrent 共享…没有至少 100 Mbit/s 上行速度的活动种子。学术洪流是伟大的,但任何时候都没有种子;
- 文件夹组织不好,没有元数据文件,结构不合逻辑;
- 用于加载数据集(hello
xml和对象检测数据集)的臃肿、过时的工具和文件格式; - 晦涩难懂的代码来读取这样的数据。你可以在熊猫身上创造奇迹。不,真的;
- 没有办法检查你的数据;
- 一般不关心用户;
- 以专有格式共享数据/推动某种形式的议程;
我们尽了最大努力不犯任何错误:
- 首先,所有链接都是公开的。我们的大部分数据来源于互联网,所以我们尽可能地分享数据。
- 我们还没有做到这一点(帮助美国,为什么不),但你可以写一个脚本,将下载一切,解压一切,检查 md5 和文件一气呵成;
- 数据集是托管在 AWS 兼容桶与 CDN 下载速度会很好。您可以使用带有-x 标志的
aria2c来更快地加载文件; - 数据大多以相同的格式检查和写入;
- 数据被收集在一个优化的磁盘数据库中(详情见 repo ),即使在硬盘上也能工作(我们没有测试)。我相信 RAID 阵列或 NVME 高速缓存将完全解决 IO 问题(我们自己使用 SSD NVME 驱动器);
- 元数据文件;
- 一些基本的可破解代码片段,以便更容易开始;
寻找动机,有所作为,道德和动机
最后,我想提出一组观点:
- 在我做了一些基线原型和数据集之后,我对结果非常失望。如果没有尤里的建议、经验和合作,我可能会放弃这个项目。尤里,我永远感激你的帮助。是的,我看到 STT 在俄罗斯是成熟的“ImageNet 时刻”采摘,但我们不会保持动力,如果没有你;
- 显然,即使我们无法为公众提供可用/稳健的模型,我们的数据/模型也将作为这一方向的第一步;
- “哦,这样的数据集应该很贵”。是的,从头开始建造这样的东西可能会花费数百万美元。但我们并不孤独,生活也不是零和游戏——所以更容易;
- 生活不是零和游戏——因此我们看到了公开数据集的机会——我们做到了;
- 不,以我们使用数据的方式使用数据并不是不道德的。首先,对于我们使用的 100%的数据— 我们没有放在那里。有人做到了。我们不会将数据用于与上传时相同的目的;
- 最后,房间里的大象。通过发布这样一个数据集,我们让奥威尔在《1984》中描述的即将到来的末日更加接近。是也不是。你看,我不相信这是可行的,以达到这样的准确性,实际上根据 STT 的结果关押人在经济上是有意义的。如果你有 10%的真实 WER——对于大多数商业应用程序来说,你已经开发出了惊人的产品!但是把人关进监狱太过分了——你最终只会处理假阳性。据我所知,在更文明的国家,采取这种行动需要法院裁决。我相信其他一些技术天生比 STT 更有毒(比如人脸识别)。毕竟——如果你想私下说点什么——私下说点什么(使用加密或者只是当面说)。你不能私下出去。我知道我们正在谈论这种技术的大规模应用,但即使你正在做一些粗略的事情,你也可以选择打电话给某人来谈论它。去购物中心,因为看起来像少数民族而被逮捕(I)首先在许多国家已经是一个问题(ii)不是你的选择。隐藏你的外表也可能会带来问题;
- “你的数据集烂是因为 X”!是的,请给出反馈,但要有逻辑性,最好给我们发一封电子邮件或 Github 问题。大多数情况下,我们只是收集了所有能得到的数据。但如果你这么在意,欢迎投稿!;
- 我也喜欢像这样的批评“你假装通过做某事(例如,分享数据集)来采取一种高尚的道德立场,你为什么这么做”。我在上面主要提到了这两点;
俄罗斯巨魔推文:使用 BERT 分类

Photo by Alex Knight on Pexels
网络部队,也被称为俄罗斯巨魔机器人,是国家支持的匿名政治评论员。他们经常通过 Twitter 和脸书等社交媒体平台传播政治分裂内容。网络部队瞄准了一些事件,如 MH17 坠机事件、2014 年 T2 乌克兰冲突事件和 2016 年 T4 美国大选事件。考虑到政治分裂内容的大规模传播可能会产生严重后果,例如干扰选举,因此开发有助于准确检测这些不良行为者的方法非常重要。在本文中,我们将使用 BERT 构建一个机器学习分类器,来预测一条推文是否来自俄罗斯机器人。我们将使用来自 Kaggle 的俄罗斯巨魔推文数据集,可以在这里找到。
在我们进入数据之前,我们将简要回顾一下伯特。BERT 代表来自变压器的双向编码器表示。描述 BERT 算法的论文由 Google 发布,可以在这里找到。BERT 的工作原理是随机屏蔽单词标记,并用基于上下文的向量来表示每个被屏蔽的单词。BERT 的两个应用是“预训练”和“微调”。
预训练 BERT
对于预训练 BERT 算法,研究人员训练了两个无监督学习任务。第一个任务被描述为屏蔽 LM。其工作原理是随机屏蔽 15%的文档,并预测这些被屏蔽的标记。第二个任务是下一句预测(NSP)。这是由问答和自然语言推理等任务激发的。这些任务需要模型来准确捕捉句子之间的关系。为了解决这个问题,他们对二进制预测任务进行了预训练,该任务可以从单一语言的任何语料库中轻松生成。他们在论文中给出的例子如下:如果你有句子 A 和 B,A 有 50%的时间被标注为“isNext”,另外 50%的时间是从语料库中随机选取的句子,被标注为“notNext”。针对这一任务的预训练被证明对于问题回答和自然语言推理任务是有益的。
微调伯特
微调 BERT 的工作原理是用自我关注对连接在一起的文本对进行编码。自我注意是学习当前单词和先前单词之间相关性的过程。这一点的早期应用是在长短期记忆()论文(Dong2016)中,研究人员使用自我注意进行机器阅读。BERT 的好处在于,通过对具有自我关注的串联文本进行编码,可以捕捉句子对之间的双向交叉关注。
在本文中,我们将应用 BERT 来预测一个文档是否是假新闻。数据集的名称是弄真假新闻,在这里可以找到。这篇文章的灵感来自于BERT to Rescue,它使用 BERT 对 IMDB 数据集进行情感分类。从 伯特到营救 的代码可以在这里找到。
BERT 算法的输入是单词序列,输出是编码的单词表示(向量)。对于单句分类,我们使用每个单词的向量表示作为分类模型的输入。
现在让我们开始吧!
- 导入包
import pandas as pd
import numpy as np
import torch.nn as nn
from pytorch_pretrained_bert import BertTokenizer, BertModel
import torch
from torchnlp.datasets import imdb_dataset
from keras.preprocessing.sequence import pad_sequences
from sklearn.metrics import classification_report
2.数据探索
俄罗斯巨魔推文数据集只包括俄罗斯巨魔推文,所以我们需要提取一些额外的数据,我们可以将其标记为“非机器人”或“正常”推文。我使用 twitter python API Tweepy 来提取使用流行关键字的额外推文。关于使用 Tweepy 的综合教程,你可以阅读我写的另一篇文章:来自 Twitter 的患者对药物的看法。我使用的关键词是' #followfriday ',' #tuesdaymotivation ',' # thankful ',' #birthday ',' #pet ',' #funny '和' #influencer ',它们取自 twitter 上 2018 年以来的热门标签列表,可以在这里找到。拉“正常”推文的代码将在 GitHub 上提供。
现在让我们将数据读入 dataframe 并打印前五行。我们还可以将最大显示列数设置为“无”。为简单起见,让我们看看“文本”和“类型”列:
pd.set_option('display.max_columns', None)
df = pd.read_csv("training_data.csv")
df = df[['text', 'type']]
print(df.head())

3.数据准备
使用“计数器”方法,我们可以了解数据中“机器人”和“正常”值的分布情况:
print(Counter(df['type'].values))

让我们也放弃“南”值:
df.dropna(inplace = True)
接下来,我们希望平衡我们的数据集,使我们有相同数量的“机器人”和“正常”类型。我们还应该随机改变目标:
df_bot = df[df['type'] == 'bot']
df_normal = df[df['type'] == 'normal']
df_bot = df_bot.sample(n=len(df_normal))
df = df_normal.append(df_bot)
df = df.sample(frac=1, random_state = 24).reset_index(drop=True)
再次验证我们得到了想要的结果:
print(Counter(df['type'].values))

接下来,我们要格式化数据,这样它就可以用作我们的 BERT 模型的输入。我们将数据分为训练集和测试集。我们总共使用 100 条记录进行培训和测试:
train_data = df.head(50)
test_data = df.tail(50)
我们用“文本”和“类型”关键字生成一个字典列表:
train_data = [{'text': text, 'type': type_data } for text in list(train_data['text']) for type_data in list(train_data['type'])]
test_data = [{'text': text, 'type': type_data } for text in list(test_data['text']) for type_data in list(test_data['type'])]
从字典列表中生成元组列表:
train_texts, train_labels = list(zip(*map(lambda d: (d['text'], d['type']), train_data)))
test_texts, test_labels = list(zip(*map(lambda d: (d['text'], d['type']), test_data)))
生成令牌和令牌 id:
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)
train_tokens = list(map(lambda t: ['[CLS]'] + tokenizer.tokenize(t)[:511], train_texts))
test_tokens = list(map(lambda t: ['[CLS]'] + tokenizer.tokenize(t)[:511], test_texts))train_tokens_ids = list(map(tokenizer.convert_tokens_to_ids, train_tokens))
test_tokens_ids = list(map(tokenizer.convert_tokens_to_ids, test_tokens))train_tokens_ids = pad_sequences(train_tokens_ids, maxlen=128, truncating="post", padding="post", dtype="int")
test_tokens_ids = pad_sequences(test_tokens_ids, maxlen=128, truncating="post", padding="post", dtype="int")
请注意,我们将输入字符串截断为 128 个字符。BERT 可以处理的最大长度是 512,但是为了节省计算时间,我们将使用 128。
最后,为我们的测试和训练集生成一个基于“type”值的布尔数组:
train_y = np.array(train_labels) == 'bot'
test_y = np.array(test_labels) == 'bot'
4.模型建筑
我们创建了我们的 BERT 分类器,它包含一个“初始化”方法和一个返回令牌概率的“转发”方法:
class BertBinaryClassifier(nn.Module):
def __init__(self, dropout=0.1):
super(BertBinaryClassifier, self).__init__()self.bert = BertModel.from_pretrained('bert-base-uncased')self.dropout = nn.Dropout(dropout)
self.linear = nn.Linear(768, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, tokens, masks=None):
_, pooled_output = self.bert(tokens, attention_mask=masks, output_all_encoded_layers=False)
dropout_output = self.dropout(pooled_output)
linear_output = self.linear(dropout_output)
proba = self.sigmoid(linear_output)
return proba
接下来,我们生成训练和测试掩码:
train_masks = [[float(i > 0) for i in ii] for ii in train_tokens_ids]
test_masks = [[float(i > 0) for i in ii] for ii in test_tokens_ids]
train_masks_tensor = torch.tensor(train_masks)
test_masks_tensor = torch.tensor(test_masks)
生成用于训练和测试的令牌张量:
train_tokens_tensor = torch.tensor(train_tokens_ids)
train_y_tensor = torch.tensor(train_y.reshape(-1, 1)).float()
test_tokens_tensor = torch.tensor(test_tokens_ids)
test_y_tensor = torch.tensor(test_y.reshape(-1, 1)).float()
最后,准备我们的数据加载器:
train_dataset = torch.utils.data.TensorDataset(train_tokens_tensor, train_masks_tensor, train_y_tensor)
train_sampler = torch.utils.data.RandomSampler(train_dataset)
train_dataloader = torch.utils.data.DataLoader(train_dataset, sampler=train_sampler, batch_size=BATCH_SIZE)test_dataset = torch.utils.data.TensorDataset(test_tokens_tensor, test_masks_tensor, test_y_tensor)
test_sampler = torch.utils.data.SequentialSampler(test_dataset)
test_dataloader = torch.utils.data.DataLoader(test_dataset, sampler=test_sampler, batch_size=BATCH_SIZE)
5.微调
我们使用 Adam 优化器来最小化二进制交叉熵损失,并且我们使用 1 个时期的批量大小 1 来训练:
BATCH_SIZE = 1
EPOCHS = 1bert_clf = BertBinaryClassifier()
optimizer = torch.optim.Adam(bert_clf.parameters(), lr=3e-6)for epoch_num in range(EPOCHS):
bert_clf.train()
train_loss = 0
for step_num, batch_data in enumerate(train_dataloader):
token_ids, masks, labels = tuple(t for t in batch_data)
probas = bert_clf(token_ids, masks)
loss_func = nn.BCELoss()
batch_loss = loss_func(probas, labels)
train_loss += batch_loss.item()
bert_clf.zero_grad()
batch_loss.backward()
optimizer.step()
print('Epoch: ', epoch_num + 1)
print("\r" + "{0}/{1} loss: {2} ".format(step_num, len(train_data) / BATCH_SIZE, train_loss / (step_num + 1)))
我们评估我们的模型:
bert_clf.eval()
bert_predicted = []
all_logits = []
with torch.no_grad():
for step_num, batch_data in enumerate(test_dataloader):token_ids, masks, labels = tuple(t for t in batch_data)logits = bert_clf(token_ids, masks)
loss_func = nn.BCELoss()
loss = loss_func(logits, labels)
numpy_logits = logits.cpu().detach().numpy()
bert_predicted += list(numpy_logits[:, 0] > 0.5)
all_logits += list(numpy_logits[:, 0])
print(classification_report(test_y, bert_predicted))

Classification Report
鉴于我们没有太多的训练数据,结果证明性能精度相当低。尝试将模型拟合到更多的数据,看看是否可以提高准确性。此外,你可以尝试使用 Tweepy 和一些常用的关键字来增加额外的推文,从而增强“正常”标签。
在BERT to the Rescue中可以找到对代码的更详细的介绍。这篇文章的代码可以在 GitHub 上找到。感谢阅读,机器学习快乐!
标准普尔 500 再创历史新高!

Photo Credit: Sam Valadi, “Charging Bull”, taken on 7/22/2011, Flickr. (CC BY 2.0)
那又怎样?“历史新高”有点武断,而且毫无意义。
从 1950 年 1 月 3 日到 2019 年 4 月 24 日,标准普尔 500 有 1251 天以“创纪录高位”收盘,这是比以前记录的“创纪录高位”高的任何数字,可以小到一位数。在 17,438 天中,只有 7%的日子里数字上升——或者在大多数情况下飙升——达到新的“历史新高”
然而,据我所知,当我们看到这些数字在 70 多年里一点一点地增长时,达到一个新的“历史新高”并没有什么特别令人震惊的。从更大的角度来看,只有一位总统在任期间至少一次没有创下历史新高,那就是杰拉尔德·福特(Gerald Ford),所有人都认为他在尼克松辞职后遭遇了政治困境。
下图显示了 1950 年至 2019 年的标准普尔 500。结果是,自 1950 年初以来,这一指数已经增长了 17,540%——这是一个毫无意义的数值,只能说它比过去高了很多。更重要的是,任意宣布“历史新高”的事实是,平均而言,标准普尔 500 每个交易日的增长率为 1.0058%。(当我们包括周末/假期时,当交易不发生时,我们谈论的是每天 0.69%——这仍然具有向上移动的净影响。)

Figure 1
第二个图像显示了两种不同的度量。蓝柱显示的是 S&P 在每位总统的整个任期内达到的最大值。注意,每一个蓝色的柱子都比前一个柱子高(除了杰拉德·福特——如果你能看出来的话)。绿色的柱子代表总统宣誓就职时的标准普尔值。你会注意到从乔治·w·布什到巴拉克·奥巴马这一栏出现了非常显著的下降——37%——这是由于经济衰退。这也发生在尼克松于 1974 年 8 月辞职后,福特总统被迫就职时。但是总的来说,对于每一位宣誓就职的总统来说,绿色的柱子应该比他们的前任高。

Figure 2
下图显示了从第一次就职演说的收盘价格到最后一天任期的增长(或亏损——红色)。例如,S&P(当时是 S&P 90 指数)在德怀特·戴维·艾森豪威尔的就职日收于 26.41,在他担任总统的最后一天收于 59.77——上涨了 129%。而对于乔治·w·布什总统来说,经济遭受了-37%的下降。看待这个问题的一种方式是,理查德·尼克松(Richard Nixon)和乔治·w·布什(George W. Bush)离任时,S&P 收盘价低于他们宣誓就职时的水平。

Figure 3
下一张图显示了每位总统在任期间最小值收盘值和最大值收盘值的增长情况(或方差)。例如,罗纳德·里根总统任期内的最低收盘价为 102.42,最高收盘价为 336.77,相差 229%。**

Figure 4
下一张图显示了 S&P 以“新高”收盘的在任天数百分比

Figure 5
请注意,福特总统没有看到破纪录的天数,乔治·w·布什总统看到了第二少的天数,不到 1%。中位数为 7%。值得指出两件事:杜鲁门和特朗普分别有 1109 天和 825 天的任期,这反映在这些图表中。
在这方面,杜鲁门看到了 109 个新的“历史新高”,特朗普看到了 80 个。我建议谨慎对待这些数据,因为如果没有完整的总统任期,这些数据将会失真。例如,乔治·w·布什看到了技术的增长,至少在延续良好的经济方面,但随后就崩溃了。这是图 5 的弱点,但是在图 1 的上下文中,您可以看到它的价值。
延续同样的趋势,我们看不到在巴拉克·奥巴马总统的第一个任期内有没有“历史新高”。他的所有成长都发生在担任总统的最后三年里——这令人震惊。如果我们将这个图表按任期细分,我们会看到,在奥巴马第二个任期的前 825 天里,他看到了 104 个新的“创纪录高点”——比特朗普目前的第一个任期高出 20%。
为什么是标准普尔 500?
标准普尔,即 S&P,自 1860 年以来一直存在,但它的现代版本是 1941 年普尔出版公司和标准统计局合并的结果。在这次合并之前,普尔出版公司已经在 1923 年创建了它的第一个“综合指数”。从 1926 年到 1957 年,综合指数由 90 种股票组成,这里称为 S&P 90。1957 年这一指数扩大到 500,尽管今天是 505。
纳斯达克综合指数成立于 1971 年,所以我认为为了趋势,增加 21 年的数据会很好。道琼斯工业平均指数(DJI),虽然它已经存在了一段时间,但这些股票都包含在标准普尔 500 中,所以与 DJI 一起做二次分析是多余的。此外,S&P 是市场中行业的代表,这使其成为分析的理想基准。
我是如何获得“历史新高”的
我从雅虎上下载了这些数据,然后煞费苦心地在每个高于前一个记录高点的数值旁边加上 1,并因此构成了一个“新高”。例如:
110.55 | 1
111.00 | 1
108.87 | 0
105.20 | 0
114.68 | 1
114.68 | 0
总共有 17438 天的记录。然后我统计(合计)了每位总统的天数,得出标准普尔 500 收盘创“新高”的总天数我四舍五入到两位小数(尽管雅虎给出了 10 位以上),以便找到新记录的高点。你可能会想“这是一个武断的”决定,这是真的,但是考虑到“创纪录的 S & P 高点”是相当小的。
但是,我决定保留小数点后两位的主要原因是,这是指数通常的显示方式。这意味着在我的分析中,如果之前的记录是 15.00,那么 15.01 将被视为新高。
总统对经济或标准普尔 500 有什么影响?
研究表明很少。艾伦·布林德和马克·沃森(美国国家经济研究局)的一份工作报告发现,民主党总统的 GDP 增长率比共和党总统高 1.8%,但至少有 50%是由总统无法控制的市场因素造成的——如石油冲击、消费者支出等。实际上,他们认为共和党在这方面运气较差,但经济更稳定,而民主党则增长更快,问题更少,也更脆弱。
类似的观点——总统对经济几乎没有控制力——在538、、、、、《纽约时报》、、国家评论和彭博的人们都提出过。教训是:1)总统对经济的实时影响非常小,最大的整体影响是他们对美联储主席的选择,但这种影响甚至是最小的。2)无论你如何衡量或定义,运气都有更大的影响。在经济衰退中期当选的总统(例如福特、奥巴马),起步时大有作为。3)经济政策往往会在相关总统离任后很久才产生影响。需要年。
结论
虽然看到“破纪录”的数字令人兴奋,但这一切都是在某种背景下发生的,而且几乎完全是在西翼(或高尔夫球场)范围之外的背景下发生的。
例如,4 月 23 日标准普尔 500 创下历史新高的反弹更令人兴奋,因为它弥补了自 9 月以来的损失(超过 25 点)。从经济角度来看,这种情况比 S&P 创造新纪录更令人兴奋。
但是,考虑到标准普尔 500 和其他市场指数没有理论上的最大值,也就是说,它将永远继续向上移动(在熊市、衰退、萧条和典型波动之外)。
这篇文章更重要的一点是,它是武断地继续吹嘘“新的历史新高”,而不是简单地因为除非资本主义、通货膨胀、市场等。不再存在,而是因为它是一个被放弃的结论。例如,除了杰拉尔德·福特,每一位总统都看到了历史新高。

Figure 6
上图显示了每位总统在给定的 30 天内的平均“创纪录高点”数量。例如,唐纳德·特朗普(Donald Trump)目前每 10 天就会看到一次新高。奥巴马总统大约每 23 天就会看到一个新的记录。但是,从长远来看,奥巴马直到 2013 年 3 月 28 日才开始看到新的纪录(在他的第二个任期内)。一旦开始,他看到每 11 天就有一个新的记录。理查德·尼克松每 58 天就看到一次新纪录,而乔治·w·布什每 325 天才看到一次新纪录——这是有道理的,因为经济崩溃了。
这幅图的目的是为了强调一点,我们将会看到平均一周一次的新高。这个实际上看起来会是什么样子,我们会经历几周或几个月的下降和停滞,然后是几个创纪录的日子。有点像我们现在在4 月 23 日,然后在4 月 26 日看到的,市场观察在一周内两次惊呼我们看到了 S & P 500 创下的“新纪录”。
背景很重要,我想说这是区分好消息和任意消息的地方。
有人脸识别的那个。
全面互动的人脸识别入门指南。跟随并创建一个自定义的人脸识别程序,它能够检测和识别视频或直播网络摄像头流中的人脸。
这是一个繁忙的市场场景;七月刺目的阳光照耀着头顶。酷热并没有阻止顾客的到来。人们不知道的是,在他们中间隐藏着一个怀有恶意的人。他伪装成一副正常人的样子,步行去实现他邪恶的目的。在一个角落里,一个监控摄像头定期扫描这个区域,这时它瞥见了这个家伙。它看到的每一张脸都会立刻被认出来,而且碰巧这家伙是个通缉犯。在几毫秒的时间里,他附近的警察得到了警报,他们开始着手消除这一威胁。这个故事曾经出现在科幻小说中,但现在情况大不相同了。事实上,中国使用人工智能驱动的监控工具来监视其公民。智能手机制造商也在积极利用人脸识别来验证手机用户的身份。人脸识别有许多不同的应用,不管你想用它做什么,在这篇文章中,我将指导你创建一个自定义的人脸识别程序。您将构建一个小程序,该程序将在视频剪辑或网络摄像头流中识别您选择的人脸。

Like what you see? This is what we will get.
在本文中,我们将构建一个自定义的人脸识别程序。这篇文章很容易理解,也阐明了这个机器学习项目的理论方面。如果你愿意,请使用目录来确定重要的部分并浏览文章。
目录
专业提示:如果你想快速完成工作,请随意跳过理论部分,直接进入第二部分。
- Facenet
一、什么事?
二。Facenet 是如何工作的?
三。三重损失 - 让我们开始建造吧!
一、前提条件
二。数据变脏
三。下载 Facenet
四。对齐
v .获取预训练模型
vi。根据我们的数据训练模型
vii。在视频上测试我们的模型 - 弊端
- 结论
- 参考文献
Facenet
在这个项目中,我们将采用一个名为 Facenet 的系统来为我们进行人脸识别。
这是什么?
Facenet1是由 Florian Schroff、Dmitry Kalenichenko、James Philbin。他们也写了一篇关于它的论文。它直接学习从人脸图像到紧致欧几里得空间的映射,其中距离直接对应于人脸相似性的度量。一旦创建了这些嵌入,就可以利用这些嵌入作为特征来完成像人脸识别和验证这样的过程。
Facenet 是如何工作的?
Facenet 使用卷积层直接从面部的像素学习表示。这个网络是在一个大数据集上训练的,以实现对光照、姿态和其他可变条件的不变性。该系统在野生的 (LFW)数据集中的标记的人脸上进行训练。该数据集包含从网络上收集的 13,000 多张不同人脸的图像,每张人脸都有一个名称(标签)。
Facenet 从图像中创建 128 维嵌入并将它们插入到特征空间中,以这种方式,不管成像条件如何,相同身份的所有人脸之间的平方距离很小,而来自不同人物的一对人脸图像之间的平方距离很大。下图描述了模型架构:

Model Structure: The model contains a batch input layer, followed by a Deep CNN architecture, and an L2 layer. This results in the creation of facial embeddings.
三重损失
该系统采用一种称为三重态损耗的特殊损耗函数。三元组损失最小化相同身份的图像之间的 L2 距离,最大化不同人物的面部图像之间的 L2 距离。
该系统采用三重损失,因为它更适合于面部验证。使用三重损失背后的动机是,它鼓励一个身份的所有图像被投影到嵌入空间中的单个点。

Triplet loss: Before and after the learning process.
创作者设计了一种有效的三重选择机制,每次智能地选择三幅图像。这些图像有以下三种类型:
1。 主播 :一个随机出现的人的形象。
2。 正面 形象 :同一个人的另一个形象。
3。 负面 形象 :一个不同的人的形象。
测量两个欧几里德距离:一个是锚和正图像之间的距离,我们称之为 A。另一个是锚和负图像之间的距离,我们称之为 B。训练过程旨在减小 A 并最大化 B,使得相似的图像彼此靠近,而不同的图像位于嵌入空间的远处。
好了,Facenet 很酷,现在怎么办?
最好的部分是前方的路。我们可以使用 Facenet 为我们自己选择的人脸创建嵌入,然后训练 SVM(支持向量机)使用这些嵌入进行分类。让我们开始构建一个自定义的人脸识别程序吧!
你可以看看这个项目的 Github 库,因为它包含一个自定义数据集和脚本来检测视频中的人脸。
先决条件
在我们开始之前,请确保您的系统上安装了以下库:
- 张量流==1.7
- scipy
- sci kit-学习
- opencv-python
- h5py
- matplotlib
- 枕头
- 要求
- psutil
被数据弄脏
在这个项目中,我们将创建一个人脸识别程序,它将能够识别 90 年代情景喜剧《老友记》中的核心人物。如果你想建立这个来识别一组不同的面孔,那么就用你的图像来代替。只要确保你遵循类似的目录结构——为你想要被识别的每个身份创建一个文件夹,并将这些文件夹存储在名为‘raw’的文件夹中。

Dataset Directory: Note how each character has a folder of its own.
用这些人的脸的照片填满每个文件夹。请注意,每张图片只有一张清晰可见的脸。我为每个角色添加了 20 张图片,尽管更少的图片就足够了。每个文件夹都有相同数量的图片。你可以在这里下载我从创建的朋友的数据集。哦,对了,这是【钱德勒】文件夹的样子:

Could it be any more fuller?
下载 Facenet
既然收集数据已经结束。请继续下载 Facenet repo 。下载它,提取它,并将‘Dataset’文件夹放入其中。
远离对齐
关于该模型的一个问题是,它可能会错过一些面部标志,为了解决这个问题,我们必须对齐数据集中的所有图像,以使眼睛和嘴唇出现在所有照片的相同位置。我们将使用 M.T.C.N.N .(多任务 C.N.N .)来做同样的事情,并将所有对齐的图像存储在一个名为 processed 的文件夹中。
打开终端/命令提示符并导航到 Facenet 目录。然后运行 align_dataset_mtcnn.py 以及以下参数。
python src/align_dataset_mtcnn.py \
./Dataset/Friends/raw \
./Dataset/Friends/processed \
--image_size 160 \
--margin 32 \
--random_order \
--gpu_memory_fraction 0.25
运行此命令将对齐所有图像,并将它们存储在各自的文件夹中,然后将所有内容存储在'已处理'文件夹中。下图将让您了解对齐是如何工作的:

All images are cropped and aligned to a standard 160x160 pixel image.
获取预先训练的模型
现在,为了在您自己的图像上训练模型,您需要下载预训练的模型。请从这里下载。
在 Facenet 根目录下创建一个名为“Models”的文件夹。下载完成后,将 zip 文件的内容解压到名为‘facenet’的目录中,并将该文件夹放在‘Models’文件夹中。

Here you go, another direcTREE image. Get it?
这个模型是在 LFW 数据集上训练的,因此所有的面部嵌入都存储在这些文件中。这让我们有机会冻结图表,并根据我们自己的图像对其进行训练。这样做将把我们提供的所有面嵌入到维度空间中。
根据我们的数据训练模型
我们已经万事俱备了!我们有一个预先训练好的模型,我们的自定义数据集已经对齐并准备就绪。现在,该训练模型了!
python src/classifier.py TRAIN \
./Dataset/Friends/processed \
./Models/facenet/20180402-114759.pb \
./Models/Friends/Friends.pkl \
--batch_size 1000
执行上述命令将加载预训练模型并开始训练过程。一旦训练结束,嵌入新图像的图像将被导出到模型/朋友/ 中。
由于我们使用预先训练的模型和相对较少数量的图像,训练过程很快就结束了。
在视频上测试我们的模型
为了测试我们的模型,我使用了朋友们的摘录。你可以使用自己的视频,甚至使用网络摄像头。在这一节中,我们将编写脚本来促进视频提要中的人脸识别。您可以继续学习以更好地理解这个脚本,或者从这里下载这个脚本。
导航到‘src’文件夹,创建一个新的 python 脚本。我将其命名为 faceRec.py。接下来,我们导入所有需要的库。
这个脚本将只接受一个参数,那就是视频文件的路径。如果没有提到路径,那么我们将通过网络摄像头传输视频。因此,该参数的默认值为 0。
我们将初始化一些变量。确保根据文件夹结构改变路径。
加载自定义分类器。
设置一个张量流图,然后加载面网模型。使用 GPU 将加快检测和识别过程。
设置输入和输出张量。
pnet、rnet 和 onet 是 M.T.C.N.N .的组成部分,将用于检测和对齐人脸。
接下来,我们将创建一个集合和一个集合来跟踪检测到的每个身份。
设置视频捕获对象。
因此,如果在运行程序时没有将 VIDEO_PATH 作为参数传递,它将采用默认值 0。如果发生这种情况,视频捕获对象将从网络摄像头传输视频。
然后,视频被逐帧捕获,并且通过 detect_face 模块在这些帧中检测人脸。找到的面数存储在 faces_found 变量中。
如果找到了面,那么我们将迭代每个面,并将边界框的坐标保存在变量 bb 中。
然后这些脸被提取、裁剪、缩放、整形并输入字典。
我们将使用该模型来预测人脸的身份。我们提取最佳类别概率或置信度。它是我们的模型在多大程度上确定预测的身份属于给定的脸的度量。
最后,我们将在脸部周围画一个边界框,并在边界框旁边写下预测的身份以及置信度。如果置信度低于某个阈值,我们会将该名称填充为未知。
务必放置 except 语句。这将确保任何抛出的错误被成功忽略。确保放置 except 语句。这样做有助于我们忽略错误。
except: pass
过程结束后,显示视频并关闭视频显示窗口。由于每一帧都要经过大量处理,视频回放可能会很慢。
恭喜你,你的耐心有了回报!我们已经完成了剧本,准备隆隆作响!快速启动 cmd 并执行以下命令来启动人脸识别程序。确保将待测试视频的路径作为参数传递,或者留空以从网络摄像头传输视频。
python src/faceRec.py --path ./Dataset/Friends/friends.mp
维奥拉。

My reaction when I saw this program work.
这个系统并不完美,也有一些缺点。
缺点
- 该系统总是试图将每张脸放入一个给定的身份中。如果一个新面孔出现在屏幕上,系统会给它分配一个身份。这个问题可以通过仔细选择阈值来解决。
- 身份之间的混淆。在上面的 gif 中,你可以观察到乔伊和钱德勒之间的预测是如何波动的。而且,置信度得分很低。用更多图像训练模型将解决这个问题。
- 在一定距离内无法识别人脸,即如果人脸看起来很小。
让我们结束这一切。
结论
不管是无形地照顾你的员工还是在野外寻找违法者。人脸识别技术可以证明是一个真正的宝石。这个项目包括创建一个人脸识别程序,它可以识别你选择的人脸。您创建了一个自定义数据集,训练了模型,并编写了在视频剪辑上运行人脸识别系统的脚本。然而,有一些缺点,但我们的系统运行良好。
祝你愉快。
参考文献
1 Florian Schroff、Dmitry Kalenichenko 和 James Philbin, FaceNet:人脸识别和聚类的统一嵌入 (2015),arxiv.org
安全人工通用智能

Photo by @the_las_memperor
未来生命研究所的 AGI 安全研究人员 2018 项目
未来生命研究所(FLI)已经出现在人工智能领域的各种文章和领域中,至少在我看来是这样。他们似乎关心未知的未来以及它对我们的影响。由于我一直在探索人工智能安全的话题,现在它确实有意义,因为 FLI 在过去五年里资助了一系列不同的项目,特别是两轮,都是由埃隆·马斯克和不同的研究机构资助的。第一轮似乎是在 2015 年,重点是人工智能安全研究人员,第二轮是在 2018 年,重点是人工通用智能(AGI)安全研究人员。由于项目总结都在网上,我决定依次思考一下。
关于生命的未来研究所
FLI 有一个使命:促进和支持保护生命和发展未来乐观愿景的研究和倡议,包括人类在考虑新技术和挑战的情况下引导自身发展的积极方式。 FLI 目前正专注于保持人工智能的益处,他们也在探索降低核武器和生物技术风险的方法。他们位于波士顿,并于 2014 年在麻省理工学院举行了发布会。他们在 2015 年组织了一次关于人工智能未来的会议。5000 名研究人员在一封信上签名,让人工智能变得强大。2015 年,埃隆·马斯克宣布他将提供 1000 万美元的支持,第一笔 600 万美元的资金将在那时到位。37 名研究人员被选中,获奖者发表了超过 45 篇科学论文。我可能会从 2015 年开始接触这些出版物,但首先我将重点关注最近一轮及其大纲。
FLI 2018 资助轮项目总结及对技术摘要的思考
2018 年春天,FLI 启动了他们的第二个人工智能安全研究计划,这次专注于人工通用智能(AGI。到夏天, 10 名研究人员获得了超过 200 万美元的奖金,以解决与筹备 AGI 相关的技术和战略问题。我已经重新发布了技术摘要,并将给出一些想法,或者看看我是否发现任何值得简单探索的术语或方向。如果你觉得这太简单,我很抱歉,我这样做是为了更好地理解这些建议。
1。艾伦·达福
“技术摘要: 人工通用智能(AGI)可能在本世纪内开发出来。虽然这一事件可以带来巨大的好处,如科学和经济进步的急剧加速,但它也带来了重大的风险。最近的一项调查显示,中等人工智能研究人员认为,至少有二十分之一的可能性会出现像人类灭绝这样极端的负面结果。确保 AGI 得到安全有益的发展,避免最坏的风险,将需要尚不存在的机构。
然而,设计和理解这些机构的需求迄今为止还没有激发出多少学术工作。我们的项目旨在解决治理高级人工智能系统的几个基本问题。我们将朝着这一目标追求四个工作流,涉及中国人工智能研究和政策思想的状态,政府和人工智能研究公司之间不断发展的关系,验证人工智能使用和发展协议的前景,以及可能指导各国人工智能治理方法的人工智能系统的战略相关属性。该计划的产出将包括学术出版物,研讨会,以及与人工智能发展和政策的主要行为者的磋商。”
主线程:
- 这是一个研究项目,旨在了解开发人工智能的机构,着眼于人工智能治理和国际关系的方法。
它有四个【工作流】;
- 中国人工智能研究与政策思想
- 政府和人工智能研究公司的关系。
- 验证人工智能使用和开发协议的前景
- 人工智能系统的战略相关属性,这些属性可以 指导国家对人工智能治理的方法
Allan Dafoe 是人类未来研究所人工智能治理中心的主任。他是人工智能国际政治副教授。他的背景是政治学和经济学。他是和平与冲突研究部的客座研究员。
你可以在这里找到更多关于 GovAI 的信息:【https://www.fhi.ox.ac.uk/GovAI/
如果你想要一个关于这个主题的介绍和艾伦·达福的讲座,你可以在 Youtube 上看看这个视频。
2。斯特凡诺·埃尔蒙
"技术摘要: 报酬规范是价值调整中的一个关键挑战,在有多个主体的环境中尤其困难,因为设计者必须在个人收益和整体社会效用之间进行平衡。我们考虑逆向强化学习(IRL ),而不是手工设计奖励,这是一种模仿学习技术,代理直接从人类演示中学习。这些技术是为单个代理开发的,虽然它们有局限性,但它们通常被认为是解决价值一致性问题的关键组件。然而,多代理设置相对来说还没有被探索过。
我们建议填补这一空白,开发专门为多智能体设置设计的模仿学习和逆向强化学习算法。我们的目标是:1)开发模仿观察到的人类行为和交互的技术,2)显式地恢复可以解释多智能体系统中复杂策略行为的奖励,使智能体能够对人类行为进行推理并安全共存,3)开发可解释的技术,以及 4)处理非理性智能体以最大限度地提高安全性。这些方法将极大地提高我们理解和推理复杂环境中多主体间相互作用的能力。”
主线程:
- 通过模仿学习和反向强化学习算法在复杂的多主体设置中平衡奖励规范。
目标。
- 开发技法 模仿观察人类行为 以及互动
- 显式 恢复奖励 能够解释多智能体系统中复杂的策略行为,使智能体能够对人类行为进行推理并安全共存
- 培养 可解释性 技巧
- 对付不理智的特工 最大化安全。
Stefano Ermon 是斯坦福大学计算机科学系的助理教授和伍兹环境研究所的研究员。他隶属于人工智能实验室。他拥有电子工程教育背景,计算机科学博士学位,辅修应用数学。你可以在这里阅读他关于 arXiv 的一篇论文。
如果你想看斯特凡诺的演讲,请点击这里。他谈到了他对这个话题的一些想法,这些想法可能更符合当前的情况:
3。欧文·埃文斯
"技术摘要: 我们的目标是了解机器学习如何以一种“安全可扩展”的方式用于 AGI,即随着 ML 组件的改进,变得越来越符合人类的利益。现有的 AGI 方法(包括 RL 和 IRL)被认为是不安全的:一旦智能体的认知资源超过人类监督者的认知资源,智能体就会变得不一致。Christiano 的迭代蒸馏和放大(IDA)是一个有前途的替代方案。在 IDA 中,通过允许人类调用代理的前一次迭代,人类和代理被“放大”成一个足智多谋(但缓慢)的监督者。从结构上来说,这个监督者总是要走在被监督者的前面。
如果有足够先进的 ML 成分,IDA 能生产出高性能的校准试剂吗?虽然我们今天无法直接获得经验证据,但我们可以通过将人类作为人工智能的替身进行放大来间接研究它。这对应于对“分解认知”的研究,即复杂的推理是否可以被分解成许多小的和大部分独立的子任务。我们将根据经验探索分解认知的方案,并通过 ML 开发自动化来处理更大的任务。”
主螺纹:
- 如何在迭代提取和放大(IDA)中使用分解认知通过允许人类调用代理的前一次迭代,人类和代理被“放大”成一个足智多谋(但缓慢)的监督者。
你可以在这里阅读更多关于因子认知的内容:
注:本帖(最初发布于此[https://ough . org/presentations/factured-cognition-2018-05])是…
www.alignmentforum.org](https://www.alignmentforum.org/posts/DFkGStzvj3jgXibFG/factored-cognition)
我认为这篇文章中的一幅图片可以更简洁地解释它,然而我可能是错的:

欧文·埃文斯是牛津大学人工智能领域的亚历山大·塔马斯研究科学家。他是在人类未来研究所(由尼克·博斯特罗姆导演)从事人工智能安全和强化学习研究的科学家。他的博士学位来自麻省理工学院,在那里他研究了认知科学、人工智能和哲学。
4。韩英豪
"技术摘要:AI 为了技术优势而向强大的 AI 系统的竞赛可能会导致严重的负面后果,尤其是当伦理和安全程序被低估甚至忽视的时候。为了让所有人都享受到安全、道德和值得信赖的人工智能所带来的好处,关键是要制定适当的激励策略,确保所有相关方的互利、规范行为和安全合规性。使用进化博弈论的方法,该项目将开发计算模型(分析和模拟),捕捉人工智能竞赛的关键因素,揭示在竞赛的不同条件和假设场景中可能出现的战略行为。
此外,应用激励和协议建模的方法,我们将系统地分析不同类型的激励(即积极与消极、同行与机构及其组合)如何随着时间的推移影响安全合规行为,以及应如何配置此类行为以确保预期的全球结果,同时避免会减缓发展的不当限制。因此,该项目将提供基础,在此基础上,激励将刺激这种结果,以及如何需要在适合玩家类型的激励边界内使用和部署它们,以便在合作安全协议中实现高水平的合规性,并避免 AI 灾难。”
主螺纹:
- 用进化博弈论的方法模拟和分析人工智能竞赛建筑计算模型,以观察随着时间的推移影响安全合规行为的不同激励。
Anh Han 目前是蒂塞德大学计算、媒体和艺术学院的计算机科学高级讲师。
5。何塞·埃尔南德斯-奥拉洛
"技术摘要: 存在许多范式,并且将会创造更多,用于开发和理解 AI。在这些范式下,关键的利益和风险以非常不同的方式出现。贯穿所有这些范式的一个维度是一般性的概念,它起着核心作用,并提供了中间的字母,在 AGI,人工一般智能。该项目从一般性措施的角度探索了目前和未来 AGI 范式的安全问题,作为性能的补充维度。
我们考察以下研究问题:
1 .我们应该根据任务、目标或优势来定义一般性吗?通用性与能力、计算资源以及最终的风险有什么关系?
2。在具有有限能力的通用系统和具有更高能力的不太通用的系统之间的安全权衡是什么?这与自动化的效率和风险有什么关系?
3。我们可以用广度增长来取代性能爆炸的单一概念吗?这如何帮助开发更强大的 AGI 系统的安全途径?
对这些问题进行了范例分析,例如强化学习、反向强化学习、对抗设置(图灵学习)、神谕、认知即服务、通过演示、控制或跟踪进行学习、教学情景、课程和迁移学习、自然化归纳、认知架构、大脑启发的人工智能等。”
主线程:
- 探索一般性测量的观点,作为绩效的补充维度:(1)定义,(2)权衡,(3)替代。
José Hernández-Orallo 是西班牙瓦棱西亚理工大学的信息系统和计算教授。他已经出版了四本书和一百多篇关于人工智能、机器学习、数据挖掘、认知科学和信息系统的文章和论文。他在机器智能评估领域的工作已经被科学和大众媒体报道,包括《经济学人》和《新科学家》。他率先将算法信息论应用于人工智能测试的开发。
6。马库斯·哈特
《技术摘要: 智能体框架、期望效用原理、顺序决策理论以及归纳推理和机器学习的信息论基础,已经为人工智能(AI)这个以前异构分散的领域带来了显著的秩序。在此基础上,在过去的十年里,我发展了通用人工智能理论。这是第一个也是目前唯一一个数学上严格的自顶向下的方法来形式化人工智能。
这个项目将推动通用人工智能理论的发展,以解决可能是 21 世纪最重大的存在风险:解决控制问题,即随着人工超级智能代理的产生而出现的独特的委托代理问题。目标是扩展现有的理论,使一般智能代理的控制问题的正式调查成为可能。我们的重点是通用人工智能理论所缺乏的最基本的属性,即嵌入现实世界的智能体理论:它不能可靠地建模,它是对单个智能体的约束,它不能安全地探索,以及它不能很好地理解如何指定与人类价值观一致的目标。”
主线程:
- 推进通用人工智能理论,通过嵌入现实世界的智能体理论来解决超级智能体产生的控制问题的风险。
马库斯·赫特是澳大利亚国立大学( ANU )计算机科学研究院( RSCS )的教授。之前他在瑞士和 IDSIA 以及 NICTA 在一起。他在 RSCS/ANU/NICTA/IDSIA 的研究围绕着通用人工智能,这是一种自上而下的人工智能数学方法,基于 Kolmogorov 复杂性、算法概率、通用 Solomonoff 归纳、奥卡姆剃刀、莱文搜索、序列决策理论、动态编程、强化学习和理性代理。
7。詹姆斯·米勒
【技术摘要: 经济学家长期以来致力于创造描述超理性人行为的数学工具,他们可能已经设计出了一种模拟未来计算机超级智能的出色方法。本指南解释了效用函数的用途、假设和限制,希望成为人工通用智能(AGI)理论家的宝贵资源。
该指南将对 AGI 关于工具收敛的文献进行评论,该文献认为对于许多类型的效用函数,AGI 将具有相似的中间目标。该指南考虑了正交性论题,该论题认为增加 AGI 的智能并不缩小它可能具有的效用函数集。本指南探讨了在 AGI 中可能出现但在经济研究中通常不会出现的效用函数,例如不稳定的效用函数、总是增加的边际效用函数、极高或极低的贴现率函数、可以自我修改的效用函数,或者偏好违反冯诺依曼-摩根斯坦效用定理假设之一的效用函数。
该指南考虑了外星人已经开发出计算机超级智能的可能性,这种智能已经收敛于与费米悖论一致的效用函数。最后,探索了 AGI 从人类效用函数中获取其值的合理性,即使给定了人类具有不同偏好的挑战。”
主线程:
- 一本评论 AGI 文学和探索效用函数的指南。
让我来解释两个看起来容易混淆的概念。
冯诺依曼-摩根斯坦效用定理 表明,在理性行为的某些公理下,面对不同选择的风险(概率)结果的决策者会表现得好像他或她正在最大化定义在未来某个特定点的潜在结果上的某个函数的期望值。
费米悖论:暗示我们应该寻求基于天文观测的科学数据,而这些数据是远古时代的文明无法获得的,我们应该制造机器,在我们的文明崩溃的情况下,用无线电信号淹没我们的星系。
费米悖论可能听起来令人困惑,确实如此,所以这里有一个 Kurzgesagt 视频可能有助于解释。
8。多尔萨·萨迪格
"技术摘要: 人工智能(AI)的最新发展使我们能够建造能够执行复杂任务的 AI 智能体和机器人,包括许多与人类互动的智能体和机器人。在这些任务中,机器人需要建立人类行为和偏好的预测性和鲁棒性模型:与人类合作的机器人操作者需要预测她的未来轨迹,或者坐在自动驾驶汽车中的人类可能对汽车应该如何谨慎驾驶有偏好。
在现实中,人类有不同的偏好,这些偏好可以以混合奖励函数的形式被捕获。由于有不同类型的人,学习这种混合可能具有挑战性。通常还假设这些人在近似优化习得的奖励函数。然而,在许多安全关键场景中,由于缺乏数据或对奖励函数结构的错误描述,人类遵循的行为不容易用学习到的奖励函数来解释。我们在这个项目中的目标是通过从一组混合的人类中引出比较来主动学习一种混合的奖励函数,并进一步分析这种模型的可推广性和鲁棒性,以便与 AI 代理进行安全和无缝的交互。”
主线程:
- 目标是从具有不同偏好的不同人那里学习混合的奖励函数。在安全至关重要的场景中,人类遵循的行为不容易用习得的奖励函数来解释。
多尔萨·辛格是斯坦福大学计算机科学系和电子工程系的助理教授。她的工作专注于自主系统的算法设计,这些系统可以安全可靠地与人交互。
她在斯坦福大学 HAI 的发布会上谈到了这个话题,在这方面,一个特别的图像引起了我的注意。

你可以在这里看到图片拍摄的完整视频:
9。皮特·斯通
【技术摘要: 随着技术的发展,智能体将能够长期(通用)自主,即在很长一段时间内需要自己选择自己的行为,这只是时间问题。因此,在许多情况下,代理将不能预先与它们可能交互的所有其他代理进行协调。
相反,代理将需要合作,以便在没有预先协调的情况下完成意想不到的联合目标。因此,“特别团队合作”问题,即队友必须一起工作以获得共同的目标,而事先没有任何关于如何做到这一点的协议,已经成为人工智能文献中最近的研究领域。
然而,到目前为止,还没有人关注代理人行为的道德方面。在这项研究中,我们介绍了 M-TAMER 框架(TAMER 的一种新变体),用于向代理传授人类道德的理念。使用混合团队(代理人和人),如果采取被认为是道德上不好的行动,代理人将收到来自人类队友的负面反馈。使用 M-TAMER,代理人将能够发展一种“内心良知”,这将使他们的行为与人类道德一致。"
主线程:
- 代理人专门解决问题的团队合作引起了关于代理人行为的道德方面的问题。驯兽师框架用于通过负反馈向代理传授人类道德的理念。
皮特·斯通是德克萨斯大学奥斯汀分校计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系的创始人和主任,德克萨斯大学计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系计算机科学系。
你可以在这里观看他关于机器人世界杯的 TED 演讲:
10。乔希·特南鲍姆
《技术摘要: 人类认知的一个标志就是在存在不确定性的情况下,与他人一起跨越新奇情境进行规划的灵活性。我们与各种复杂程度和知识的合作伙伴一起行动,对抗那些自身既不同又灵活的对手。虽然一个代理团队可能因为共同的目标而团结在一起,但是这个团队通常有多种方式来实际实现这些目标。
在缺乏集中规划或感知以及受限或昂贵的通信的情况下,代理团队必须针对代理之间的潜在差异有效地协调他们的计划。不同的代理可能具有不同的技能、能力或获取知识的途径。当环境和目标发生变化时,这种协调具有临时性的因素。
不协调会导致不安全的互动,并造成伤害和财产损失,因此人类和代理之间的特别团队合作必须不仅高效,而且稳健。我们将研究人类的特别和动态合作,并建立正式的计算模型,逆向工程这些能力。这些模型是构建能够像人一样协作并与人协作的机器的关键一步。"
主线程:
- 这项研究将调查人类的特别和动态合作,并建立正式的计算模型,逆向工程这些能力。这是制造能够协作的机器的关键一步。
约书亚·布雷特·特南鲍姆是麻省理工学院认知科学和计算教授。他因对数学心理学和贝叶斯认知科学的贡献而闻名。
他在 2018 年的视频中谈到了这一研究方向:
结论
从 2018 年开始,未来生命研究所项目中有很多有趣的研究人员。因此,我现在确实比以前有更多的东西需要探索。对于人工通用智能安全,似乎既有批判性的方法,也有好奇心。
这是#500daysofAI 的第 68 天。我目前第 50-100 天的重点是人工智能安全。如果你喜欢这个,请给我一个答复,因为我确实想提高我的写作或发现新的研究,公司和项目。
基于显著性的图像分割
一种寻找物体的自主方法
通常当我们看到一幅图像时,图像中会有一个焦点。这可能是一个人,一座建筑,甚至是一个桶。图像中有些清晰的部分没什么意思。这种区域通常以图像中缺少焦点、单调着色或平滑纹理为特征。当呈现这样一类图像时,可能希望从图像的其余部分中分割出感兴趣的对象。本文探讨了这种突出的图像分割。

Examples of salient images. The bucket (left) and person (right) are the objects of interest.
这个项目最初源于开发一种自动生成图像三分图的方法的兴趣。三分图是图像遮罩,当与抠图算法结合时,用于分割图像,同时注意前景和背景之间的细节。三分图通常包含定义前景的白色区域、定义背景的黑色区域以及代表不确定区域的灰色区域。

Example of Trimap from 2
大多数抠图算法的问题是,它们期望三分图由用户提供,这是一项耗时的任务。我引用的两篇主要论文试图解决自主三分图生成【1】【2】。在第一篇论文中,Hsieh 等人使用了一种相当简单且易于实现的方法。不幸的是,他们的方法不是完全自主的,因为它要求用户为 Grabcut 算法提供一个矩形区域。相反,Gupta 等人使用显著性方法来预测感兴趣的区域是什么。然而,他们的显著性方法相当复杂,结合了三种不同的显著性算法的结果。其中一种算法利用了复杂的神经网络,这是一种我为了易于实现而想避免的技术。
除了需要人工协助之外,Hsieh 等人的算法产生了合理的结果。我想如果我能自动完成论文的 Grabcut 部分,他们算法的其余部分将解决最初的问题。我从古普塔等人提出的创造这种自主性的方法中获得了灵感。
方法
对于大多数形式的图像分割,目标是将图像二值化为感兴趣的区域。这个项目的目标没有什么不同。首先,我想大致确定感兴趣的对象在哪里。对图像应用高斯模糊滤波器。从模糊的图像中,产生平均 15 像素大小的超级像素。超级像素算法旨在根据像素区域中的颜色和距离值来分割图像。具体来说,使用了简单的线性迭代聚类(SLIC)算法。

Superpixel map of a bucket and a person
超像素将图像分割成大致相同的区域。这样做的一个优点是超像素允许区域的一般化。我们可以假设超像素中的大多数像素具有相似的属性。
在确定图像中超像素的同时,计算图像的显著图。使用了两种不同的显著性技术。第一种方法使用内置的 OpenCV 方法,称为细粒度显著性。第二种方法包括取精细颗粒显著性图像的平均值,并将其从图像的高斯模糊版本中减去,随后是新图像的绝对值。
这两种方法在结果的激进程度上有所不同。下图都突出显示了感兴趣的区域。由细颗粒显著性产生的图像要柔和得多。此外,细粒度显著性图像主要勾勒出显著图像的边界,而替代方法也捕捉显著图像的内部。与细粒度方法相比,主动方法确实会拾取更多噪声。噪声去除是该过程的下一步。

Salience images for the bucket and person using fine grain approach.

Salience images for the bucket and person using aggressive saliency.
下面的技术是从 Gupta 等人的论文中挖掘出来的。为了将图像二值化,迭代从彩色图像生成的每个超像素。如果显著性图像内的超像素区域的中值像素值大于阈值T1,则整个超像素被二值化为白色。否则,整个超像素保持黑色。T1,由用户选择。在2中,T1被设置为显著性图像中最大像素值的 30%,然而,在该项目中使用了 25%的值。
在图像的二值化之后,基于所使用的显著性技术对图像进行膨胀。在细粒度显著性方法中,图像被放大了平均超像素大小的两倍。积极凸极法没有扩大。图像中的噪声越大,任何扩张都有风险。

Bucket after dilated with fine grain saliency (left) and binarized aggressive saliency (right)
最后一步还是取决于使用哪种显著性方法。在这两种情况下,白色像素的最大区域被提取。在 OpenCV 中,这样的操作是通过在图像中找到轮廓并选择具有最大面积的轮廓来执行的。边界框适合所选区域。
据观察,细粒度显著性方法经常导致碎片化的区域。生成边界框后,落入该框中不属于最大区域的任何其他白色区域都被添加到该框中。盒子的边界增加到包括这些区域。积极的显著性方法不需要这样做。经常地,最大的地区捕获了比期望更多的东西。
最后一步是将最终找到的边界框提供给 Grabcut 算法。 Grabcut 是一种常用的图像分割方法。赋予 Grabcut 函数的边界框将算法认为明确的背景和前景分开。在大多数包含 Grabcutting 应用程序的软件包中,用户可以编辑矩形区域,并可以为算法提供更多信息,以获得更清晰的结果。在这个项目中,使用了 OpenCV 的内置 Grabcut 函数。

In the case of the bucket, both approaches produced the same solution.
此过程在1开始的地方结束。在未来,我计划继续开发这个自动旅行地图生成器。
结果
在这两者中,积极的显著图似乎为大多数图像产生了精确的遮罩。精细颗粒方法难以处理突出物体不“庞大”的图像。如果图像很长或有卷须,这些片段与图像的其余部分断开是很常见的。然而,由于其保守性,当图像特别嘈杂时,细粒度方法更好。蒙版不一定能捕捉到完整的图像,但它不会像侵略性方法那样频繁溢出。

Sample results of the two methods
还需要指出的是,对于1中开发的算法,不发达的掩模并不坏。因为最终目标是开发一个三分图图像,所以遮罩将由一个灰色区域填充。这个灰色区域将有助于区分前景和背景。
对于任何周刊读者来说,学习 C++中的 OpenCV 并实现这个算法都是惊人的耗时。抱歉的延误,但期待这个项目在未来的延续以及更多的内容!
Github 代码:
用于分割显著的彩色图像并确定抓取的代码。- TimChinenov/GraspPicture
github.com](https://github.com/TimChinenov/GraspPicture)
参考
1 C. Hsieh 和 M. Lee,“数字图像抠图的自动三分图生成”, 2013 年亚太信号与信息处理协会年度峰会和会议,高雄,2013 年,第 1–5 页。
2古普塔,维卡斯&拉曼,尚穆加纳坦。(2017).用于图像抠图的三分图自动生成。
样本手形生物特征识别系统
生物识别建模过程的一个简单示例
这篇文章改编自我完成的一项任务——我认为这个项目很好地展示了数据建模的基本过程,并且有一个直观的应用程序,使人们更容易理解。这个例子强调了数据分析的 6 个一般步骤,并讨论了它将涉及哪种元素。
1.0 实验目标
本报告解释了一种使用监督学习实现“基于手形的实体识别”系统的方法。提供带标签的训练数据,测试数据必须由设计的系统进行分类和标记。分类系统将通过准确性来衡量。
准确度定义为所有评估中正确评估的百分比。
Accuracy = (TN + TP)/ (TN + TP + FN + FP)
2.0 数据准备
我们得到了训练和测试数据——每个数据由 23 个 2D 点的 100 个样本组成,描绘了手的几何形状(图 2.0) 。训练数据被标记(我们知道这是谁的手),而测试数据是我们必须识别的(这是谁的手?).

Figure 2.0: Hand Geometry Data Points
训练和测试数据被加载到数据帧中,23 个 2D 点中的每一个都相应地标注在适当的栏中。为了以后的计算和分类目的,所有分类标签都被转换成整数代码。所有原始数据点都被确认为非空的和数字的。
下面的图 2.1 显示了训练和测试数据的六进制图,以查看数据点的高级概述。他们展示了一个手印的轮廓。


Figure 2.1: Hex-bin plots of training (left) and test (right) datasets
3.0 特征工程
为数据集中的每个轮廓生成了以下要素:
- 欧几里得和曼哈顿任意两点之间的距离
- 任意 3 个点的三角形周长和面积
图 3.1 描绘了这些几何特征,它们似乎是理解手部轮廓和位置的直观方法。

Figure 3.1: Geometric Feature Extraction
在去除原始原始数据点之后,这导致了4049总特征。进行相关性分析以去除高度相关的特征(因为它们不具有辨别能力)。这导致剩下总共460个特征,用于后续步骤。
4.0 分类
该实验的分类需要特征缩放、特征缩减或选择,以及训练分类器。
4.1 特征缩放
由于我们准备了特征来区分不同标签的手形轮廓,因此特征缩放将我们的特征转换为相对于任何给定特征的其余值的相对度量。特征缩放还经常用于将特征空间转换为固定范围的值,以减少标准偏差,从而减少异常值的影响。在本实验中,比较了两种流行的缩放方法:最小-最大缩放和标准缩放。
最小-最大缩放将特征缩放到[0,1]之间的固定范围内,而标准缩放通过移除平均值和缩放来转换特征空间,使得每个特征分布具有单位方差。
4.2 特征简化或选择
特征缩减或选择将特征空间缩减为一个极小的高鉴别特征集。这有助于训练分类器,从而更好地进行归纳以及提高计算效率。当训练集只有很少的样本(只有 100 个)时,使用 as 的所有特征会导致过度拟合,从而无法准确预测测试集中的样本。该实验比较 PCA(称为PCA)来减少特征,以及 ANOVA F 值分数(称为*SelectKBest*)来选择顶部的N特征。尝试了各种N值,以找到最高精度的值。
4.3 训练分类器
使用缩放和简化的特征,执行监督学习任务以使用提供的分类标签训练分类器。四个分类器— LinearSVC、SVC、a Gaussian Process Classifier和 a Random Forest Classifier —与它们各自的超参数一起进行了超参数调整实验。进行超参数调整是为了根据经验确定分类器的哪个设置会产生最佳结果。这些参数很难从理论上推导出来,因为它们的效果严重依赖于训练数据的种类和形式。
4.4 交叉验证
对特征缩放、特征缩减/选择(具有不同的N值)和分类(具有不同的超参数值)的所有组合进行了模拟,总共产生了 500 次模拟。
分层的五重交叉验证方法——因此每类中的一个标签被留出作为验证数据——被用于评估每个模拟的准确性。这导致一起选择特征减少/选择和分类器的最佳组合,其导致跨交叉验证集的最佳准确度。执行交叉验证是为了有效地判断模型的准确性——训练和验证样本的简单分割可能会让模型变得幸运。将每个类的 5 个样本中的每一个作为验证样本放入我们的训练集中,保证了模型的准确性将由所有的拆分组合来判断。
5.0 培训和验证结果
模拟的最终精度分布如图 5.1 中的所示。可以看出,大多数模拟导致了[0.8,0.98]之间的精确度。

Figure 5.1: Accuracy Probability Density Distribution across 500 simulations
图 5.2 比较了各种预处理(特征缩放+特征缩减/选择)方案的精度,发现方差分析 F 值评分(SelectKBest)特征选择方法通常会在系统中产生更好的精度。这在某种程度上是意料之中的,因为 ANOVA F 值方法通过根据类别标签执行统计测试来直接确定特征区分,而 PCA 是一种“无监督”的特征约简方法,并不直接处理分类的特征区分。这也可能是为什么缩放方法的选择似乎显著影响 PCA 而不是 ANOVA F 值分数的原因。

Figure 5.2: Comparing Accuracy distributions for various Pre-processing schemes
图 5.3 比较了各种分类器的准确度。SVC和Gaussian Process Classifier的表现普遍优于其他品牌,SVC的得分更为稳定。

Figure 5.3: Comparing Accuracy distributions for various Classifiers
图 5.4 给出了更详细的视图,显示了不同预处理方案、分类器以及特征减少/选择组件数量的精度分布(跨超参数值)。图 5.5 中的表格显示了超参数调整后,通过不同配置获得的最大精度。
与线性 SVC 相比,SVC 的优异表现表明非线性决策边界更好地区分不同的类别。高斯过程分类器在正确的条件下也表现得和 SVC 一样好,并且在其模拟中具有 0 的标准偏差。这显示了 SVC 相对于高斯过程分类器的灵敏度——正则化超参数C必须被调整以获得最佳结果,而高斯过程分类器隐式地学习正则化参数本身,而不管你从哪个随机状态开始。这表明高斯过程分类器一般更稳定。高斯过程分类器在寻找类之间的最佳决策边界时也隐式地学习核,而 SVC 核必须预先定义(在这个实验中它被设置为rbf)。然而,SVC 对于训练来说要快得多,并且当 hyper 参数调整正确时可以做得稍微好一点。

Figure 5.4: Box Charts of Accuracies for each classifier, preprocessing scheme, and # of reduced components

Figure 5.5: Final Results (max Accuracy obtained by configuration with best hyper-parameters)
6.0 结论和分析
从上述数据中,系统的最佳配置(导致平均交叉验证准确度为98%)选择如下:
- 特征定标器:标准定标器
- 特征选择: ANOVA F-value 得分,用于选择顶部的
15特征 - 分类器:带正则化超参数的 SVC
C=10.0
6.1 最显著的特征
功能选择方法选择了以下 15 大功能:
{P1}_e_{P2} = Euclidean Distance between P1 and P2
TA_{P1}_{P2}_{P3} = Area of Triangle made with P1, P2, and P*where Point #s correspond to the positions in Figure 3.1.
Top 15 Features:['01_e_19',
'01_e_20',
'04_e_06',
'06_e_08',
'08_e_10',
'12_e_14',
'14_e_16',
'16_e_19',
'TA_01_08_09',
'TA_01_12_13',
'TA_01_16_17',
'TA_01_21_22',
'TA_04_06_10',
'TA_08_10_14',
'TA_08_19_21']
图 6.1 显示了手部轮廓样本图像上最具鉴别性的特征。红色实线形成三角形,黑色实线表示欧几里得距离。似乎自动特征选择已经找到了我们可能凭直觉猜测为最具辨别能力的特征——主要是三角形和从指尖到手的边缘或手指开始的长度,这将在很大程度上定义手的大小和范围。

Figure 6.1: Discriminative Features (Black= Euclidean Distance, Red=Triangles)
图 6.2 显示了所选区别特征之间的相关性——表明它们相关性不高,并且各自提供了有价值(或至少不同)的信息。

Figure 6.2: Correlation Heat map between Top Discriminative Features
6.4 推理
然后,所选择的分类器以及预处理方法被用于在测试数据集上进行预测。虽然由于我们有未标记的样本,很难看到测试数据集的结果,但我们可以通过将特征空间缩减到 2D(使用 PCA 或 TSNE)并绘制出结果来了解预测的质量。(这丢失了信息,但只是粗略地了解我们结果的聚类结构)。在图 6.3 中,方块是测试分类——视觉表明分类器确实在将测试样本分类到一个标签中,该标签的训练样本表现出与测试特征向量相似的特征集。图中出现的聚集行为是一个很好的迹象,表明我们的特征具有足够的区分能力,可以将相同标签的样本分组在一起。

Figure 6.3: 2D Reduced Mapping for Visualization of Results (Squares are test classifications)
总之,分类系统成功地选择了有价值的区别特征,导致正的 98%确认分数,并预测测试样本标签,使得它们在缩减的特征空间中接近相应的训练样本。
样本大小和相关性
面临的一个典型问题是多少数据被认为是足够的。答案是视情况而定。首先,我们需要知道总人口是由什么组成的。如果人口很少,并且有足够的资源来获得你想要的关于总人口的任何信息,那么这就足够了——事实上,这是最好的情况。在这种情况下(大多数情况下都是这样),我们会进行调查。下一个问题是调查多少人。同样,答案是视情况而定。1.这取决于总人口的规模。2.这取决于你愿意接受的误差幅度。3.这取决于置信区间(通常为 0.95)。此外,我们必须确保在进行样本选择时,样本能够代表总体,并且是随机选择的(即每个人都有平等的机会被选中)。
有一些在线计算器可以为我们提供在一定的误差范围和置信水平下收集的适当数量的回答,以估计平均值和比例的影响大小。样本量越大,我们就越有可能检测到小的效应量。在相关性的情况下,我们通常对大的相关系数感兴趣(因为这意味着我们可以尝试改变一个变量来影响另一个变量),情况如何?这是否意味着样本量越大,我们就越能发现强相关性?根据经验,统计学家认为 0.7 的 r 值是很强的。
让我们看看这个例子。对某一水平的三分之二的学生群体进行了一项调查,我们观察到,对任何一对问题的回答之间都没有很强的相关性。



基于 116 份调查问卷,我们发现相关系数在 0.11 到 0.59 之间。接下来,我想知道在较小的样本量下是否有不同的结果。

All survey respondents (N=116)
然后,我执行了 bootstrapping,从全部调查对象中随机抽取了 50 名受访者的样本十次。即使样本量现在变小了,自举样本 6(学校对数学,学校对人文,数学对科学)和样本 10(学校对数学)观察到了很强的相关性。因此,如果我们实际上只对 bootstrapped 样本 6 中的受访者样本进行了调查(以代表整个人口),我们就会得出这些变量之间有很强相关性的结论。这表明,样本量大并不意味着我们更有可能观察到更强的相关性;在这种情况下,较大的样本量实际上会削弱相关性。这表明,更重要的是理解人口的同质性和我们如何进行抽样(即样本是否是随机选择的,是否代表人口的分层)。具有高同质性的较小样本将比具有低同质性(高异质性)的较大样本显示出更大的相关系数。因此,如果我们选择关注同质人群,我们可能不需要大样本量来反映相关性。当然,如果要保守一点,可以调整我们认为强相关的阈值,同时考虑相关系数的置信区间。R 中有在线计算器和包,可用于计算相关系数的置信区间。它考虑了观察到的样本相关系数、样本大小和置信水平(通常为 0.95)。
在这里,我还想引用一篇关于“相关性在多大的样本量下稳定?”的论文,其结果表明,在典型情况下,稳定估计的样本大小应接近 250。在这种情况下,这将是一个微不足道的解决方案,因为这意味着我必须调查整个人群(学生群体是< 250)。换句话说,我们应该尽可能地获取更多的样本。克里斯·德拉海姆在的一个帖子中的评论,“运行皮尔逊 R 的最小样本量是多少?”,也强调了小样本的不稳定性:“没有至少 50 或 60 次观察,我不会相信任何相关性,80-100 次在我感觉舒适的范围内。根据我处理试点数据和分析数据集子集或在正在进行的研究中展示数据的经验,与 20-40 名受试者的相关性可能会与 80-100 名受试者的相关性明显不同,我甚至看到当观察值加倍时,两项任务之间的相关性从. 70 到+40。识别异常值也很重要,即使样本量较大,一两个异常值也会对相关性的大小产生很大影响,因为这毕竟是最小二乘法。”
另外,研究自举样本 6 的分布如何不同于其余样本以显示相关性分析中的这种差异将是有趣的。


Correlation coefficients for bootstrapped sample 1 and bootstrapped sample 2


Correlation coefficients for bootstrapped sample 3 and bootstrapped sample 4


Correlation coefficients for bootstrapped sample 5 and bootstrapped sample 6


Correlation coefficients for bootstrapped sample 7 and bootstrapped sample 8


Correlation coefficients for bootstrapped sample 9 and bootstrapped sample 10
参考资料:
https://www . check market . com/blog/how-to-estimate-your-population-and-survey-sample-size/
https://www . r-bloggers . com/how-to-calculation-confidence-intervals-of-of-correlations-with-r/
原载于https://projectosyo.wixsite.com。
数据科学家职位的家庭编码练习示例

Image Source: Photo by Lee Campbell on Unsplash
将编码练习带回家是数据科学家工作面试流程的重要组成部分。数据科学家工作面试流程通常从一些初步接触开始,例如通过 LinkedIn 等平台从招聘人员那里,或者从申请的公司或组织的代表那里。随后通常会进行 Skype 或电话面试,以了解申请人的资格。一旦 Skype 或电话面试完成,下一步就是带回家编码挑战。
我认为带回家的挑战是数据科学家工作面试过程中最重要的一步。在此过程中,您会被指派解决一个数据科学问题。带回家练习的难度因组织而异。有时,如果你幸运的话,你可能会得到一个清晰的数据集,上面有关于做什么的明确说明,也就是说,这个练习会准确地告诉你要构建的模型的类型。如果你不是很幸运,你可能会得到一个非常复杂的数据集(需要一些清理和结构化)和一个开放的问题。在这种情况下,您必须仔细研究问题,然后决定哪种预测模型适合给定的问题。此外,关于完成“带回家”挑战的时间,根据公司的不同,时间可能从 2 天到 7 天不等。
在本文中,我将展示一个数据科学家工作岗位的带回家编码练习示例。这是你能要求的最简单的带回家练习之一。数据集结构良好且干净,相对较小(9 个要素和 159 个观测值),没有缺失值。我对一个有 50,000 个观察值和如此多缺失值的数据集做了一次带回家的练习。
现在我将展示带回家练习的样本,然后我会在最后做一些评论。
数据科学家职位的家庭编码练习示例
指令
这个编码练习应该用 python 来执行(python 是团队使用的编程语言)。你可以自由使用互联网和任何其他图书馆。请将您的作品保存在 Jupyter 笔记本中,并通过电子邮件发送给我们进行审核。
数据文件: cruise_ship_info.csv (该文件将通过电子邮件发送给您)
目标:建立一个回归方程,为潜在的船只购买者推荐“船员”数量。
请执行以下步骤(提示:使用 numpy、scipy、pandas、sklearn 和 matplotlib)
1.读取文件并显示列。
2.计算数据的基本统计数据(计数、平均值、标准差等),检查数据并陈述你的观察结果。
3.选择对预测“团队”规模可能很重要的列。
4.如果您删除了列,请解释为什么要删除这些列。
5.对分类特征使用一次性编码。
6.创建训练集和测试集(将 60%的数据用于训练,其余用于测试)。
7.建立一个机器学习模型来预测“船员”的规模。
8.计算训练集和测试数据集的皮尔逊相关系数。
9.描述模型中的超参数,以及如何更改它们来提高模型的性能。
10.什么是正规化?你的模型中的正则化参数是什么?
11.绘制正则化参数值与测试集和训练集的 Pearson 相关性,并查看您的模型是否有偏差问题或方差问题。
关于带回家练习示例的一般说明
这里展示的带回家的编码练习是一个非常简单的问题。数据集是干净的,结构良好的,它是一个相对较小的数据集,并且做什么的指令非常清楚。
有时,带回家的编码练习可能非常复杂和具有挑战性。不管是什么情况,你都需要尽最大努力提供最好的解决方案。
此外,如果你发现自己被困在这个问题上,你可以随时给你的数据科学面试团队发电子邮件,他们可以提供一些指导或提示。
将编码练习带回家的一般建议
数据科学带回家挑战练习为您提供了展示数据科学项目工作能力的机会。你需要在这里展示出非凡的能力。例如,如果要求您构建多元回归模型,请确保您能够充分理解以下高级概念:
(一)特征标准化
(二)超参数调谐
㈢交叉验证
(四)降维技术,如 PCA(主成分分析)和 Lasso 回归
(五)泛化误差
㈥不确定性量化
㈦展示使用先进的数据科学技术的能力,例如 sklearn 的管道工具来建立模型。
(viii)能够根据实际应用解释您的模型。
总之,我们已经讨论了数据科学家职位的家庭编码练习。这里给出的示例编码练习只是一个例子。有时,带回家的编码练习可能非常广泛,提供的数据集可能非常复杂。无论情况如何,带回家的编码练习为求职者提供了一个展示他们的数据科学技能的绝佳机会。
如果你对我提出的带回家编码练习的解决方案感兴趣,请发邮件到benjaminobi@gmail.com 给我。
采样!
一种解决鸟类计数问题的方法
当你有一个很大的数据集,而你的算法需要很长时间才能运行时,你会怎么做?或者说如果你想知道一天内喝星巴克的总人数?你打算一整天都站在星巴克外面数进入星巴克的人数吗?好吧,那将是荒谬和浪费时间的!因此,这里我们使用抽样技术,选择一部分数据进行分析。获得感兴趣的整个数据集太昂贵或太耗时。此外,处理收集到的所有数据既耗时又昂贵。因此,使用采样算法可以减少数据量,但可以使用更好但更昂贵的算法。取样有助于回答与鸟类计数问题有关的问题,即地震中幸存的人数。

有效抽样的关键是样本应该和使用整个数据集一样有效。以星巴克为例,如果我只收集上午 9 点到 11 点的数据,那么显然会有更多的人喝星巴克,因为现在是早上,人们已经养成了早上上班前喝咖啡的习惯。因此,应该选择一种有效且无偏的方法从大数据集中进行采样,该方法将覆盖在大数据集中发现的所有变化。
采样方式:
一一。随机抽样:对于这种类型的抽样,选择任何特定项目的概率是相等的。例如:从 1-100 中挑选 10 个数字。在这里,每个数字被选中的概率是相等的。
- 替换取样:在这种技术中,物体不会从群体中移除。假设在一包 52 张牌中,我想选一张,这里所有牌的概率都是 1/52。所以,如果我随机抽了一张红心,现在我必须再抽一张牌,但是如果我不放红心,那么我的概率是 1/51。但在这种技巧中,我放回了一张红心 k,这样所有牌的概率都是一样的。在这里,先取出的东西不应该影响第二个或任何其他东西。数学上,两个样本之间的协方差为零。当我们有一个大的数据集时,我们应该使用替换抽样。因为如果我们使用没有替换的抽样,那么每件商品被挑选的概率将会不断变化,在某个点之后将会变得太复杂。替换抽样可以告诉我们在我们的数据中什么是更频繁的。
- 无替换取样:在这种技术中,对象从群体中被移除。在这里,无论我们先取出什么,都会影响第二个。没有替换的采样有助于数据集变小。数学上,两个样本之间的协方差不为零。
我们使用的取样类型在很大程度上取决于我们试图回答的问题。
当总体由具有大量对象的不同类型的对象组成时,简单的随机抽样可能无法代表出现次数较少的那些类型的对象。这可能会给分析带来问题,因为样本中不包括稀有类。因此,采用分层抽样的方法。
B. 分层抽样:在这种技术中,我们从总体中的一组特定对象中进行抽样。即使各组的大小不同,也会从每组中抽取相同数量的对象。此外,还有一种变化,即从每个组中抽取的对象数量与该组的大小成比例。让我们以一个著名的泰坦尼克号问题为例,在这个问题上女性幸存者多于男性。因此,如果我们随机抽取男性和女性样本,那么我们将得到一个错误的答案,我们的训练模型将会不平衡。我们必须使用分层抽样方法,仔细地对男性和女性进行抽样。我们可以根据男性和女性的存活情况进行取样。
取样并不总是有用的。有时会丢失信息。确定合适的样本量也非常重要。人们已经开始使用自适应或渐进采样。这种方法从小样本开始,然后增加样本量,直到获得足够的样本。
看看这个很好的例子,当班级不平衡时,抽样是如何帮助学生的:
[## 解决阶级失衡
下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…
www.kaggle.com](https://www.kaggle.com/shahules/tackling-class-imbalance) 
结论:
采样技术广泛用于解决各种问题。取样有助于降低成本,节省时间,有助于组织数据,它收集密集和详尽的数据,适用于我们资源有限的情况。然而,我们需要领域知识来从人群中取样。此外,当测量单位不一致时,采样没有意义,当然也有可能出现偏差。
参考:
庞-谭宁,密歇根州立大学,迈克尔·斯坦巴克,明尼苏达大学
www-users.cs.umn.edu](https://www-users.cs.umn.edu/~kumar001/dmbook/index.php)
旧金山的技术工作?先查房价!

房价让旧金山技术人员的高薪相形见绌。
如果你有一份技术工作,并且住在加州以外的地方,你可能会考虑搬到科技世界的中心——硅谷或旧金山。快速浏览一下求职网站,你会赚很多钱!但在你接受 12 万美元的薪水之前,请确保你仔细看看住房成本。
点击下面的互动图表,详细了解旧金山独户住宅有多贵。该图表按中位数销售价格、最低收入要求、平均销售价格、每平方英尺平均销售价格、平均平方英尺和销售数量(10 年的数据)对单户家庭房屋销售进行了细分。
2009–2018旧金山独栋房屋销售互动图
让我们根据计算机和数学职业的最高平均工资来比较一下旧金山和美国前 20 大科技都市地区。

现在,让我们以 2018 年住房差异为依据,对这 20 个科技大都会中心进行排名。住房差异是指技术工人的平均工资减去购买一套家庭住房所需的收入。例如,一名旧金山的技术工人平均收入为 120,730 美元,但需要 133,731 美元的收入才能购买中值住房——因此,该工人需要 13,001 美元的工资才能购买住房!

正如你所看到的,旧金山和硅谷(圣何塞大都会区)显示出负的住房差距。换句话说,你的高技术工资不够支付抵押贷款!
你的技术工资最高在哪里?你可能会惊讶地发现,在阿拉巴马州的亨特维尔,有近 4000 名航空航天工程师为波音和蓝色起源等公司工作。与房价相比,它的工资相对较高。亨茨维尔的一名技术工人平均收入为 97,340 美元,但只需要 27,816 美元就能买到中等价位的房子。
我欢迎建设性的批评和反馈,请随时给我发私信。这篇文章最初发表在 jimking100.github.io/2019–09–02-Post-2/的。
在 Twitter 上关注我 @The_Jim_King
这是探索旧金山房地产数据系列文章的第 1 部分
旧金山房地产数据来源:旧金山 MLS,2009–2018 年数据
工资数据:劳动统计局—职业就业统计,2018 年数据
全国单户家庭房屋销售价格中位数数据:美国全国房地产经纪人协会,2018 年数据
最低收入要求——使用加州房地产经纪人协会住房负担指数——传统方法。它使用中位数价格、20%的首付、基于每年 4%的利率、1%的税率和. 38%的保险费率的每月房屋付款,并假设不超过 30%的家庭收入可用于房屋付款。
讽刺检测:走向情感分析的一步
人类具有社会性。社会性意味着我们以积极友好的方式相互交往,也意味着我们知道如何以非常消极的方式操纵他人。
讽刺在人类社会交往中起着重要的作用,它既有积极的滑稽,也有消极的下流。

但是有时候很难察觉有人是不是带着某种讽刺在取笑我们。所以为了简单起见,我们建立了一些东西来帮助你发现讽刺的文字,但是在进入更多细节之前,让我们来定义一下讽刺
讥讽是“尖锐、尖刻或尖刻的表达或言论”。用讽刺来嘲弄或表达轻蔑。
所以现在是时候充电开始讽刺检测之旅了。
让我们从定义问题开始:-
问题描述:-
我们已经给出了新闻标题数据集,我们的目标是预测一个给定的文本是否是讽刺的。
这个用于讽刺检测的新闻标题数据集收集自旨在制作时事讽刺版本的洋葱网站和收集真实新闻标题的赫芬顿邮报网站。
你可以从令人惊叹的网站 Kaggle ,轻松获得这个数据集,下面是链接:-
我们的数据集有三列,其中
article_link(类型:对象):包含新闻文章的链接。headline(类型:对象):包含新闻文章的标题。is_sarcastic(类型:int64):包含 0(非讽刺文本)和 1(讽刺文本)。
源代码(Python):-
T 他的讽刺检测器是内置的 Python 语言,所以是时候导入基本的库和模块了,如果你不知道这些模块,不要担心,我们将在下一步中学习这些
import pandas as pd, numpy as np, re, time
from nltk.stem.porter import PorterStemmer
现在是时候获取我们的模型和一些依赖项了
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.svm import LinearSVC
from sklearn.model_selection import cross_val_score
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
不要担心,如果您没有任何模块,您可以使用:-
pip install <module/library Name>
安装任何依赖项。
在获得所有的依赖关系之后,是时候将我们的数据集加载到 Pandas Dataframe 中了。
# Loading data from json file
data = pd.read_json(‘Sarcasm_Headlines_Dataset.json’, lines = True)
现在让我们使用熊猫数据帧的data.head()方法来看看我们数据集的前五行。

Fig: a glimpse of our dataset
最好是先检查数据集中的空值。
print(data.isnull().any(axis = 0))
# Output :-
# ----------------------
# article_link False
# headline False
# is_sarcastic False
# dtype: bool
# ----------------------
因为我们的数据集没有任何空值。因此,我们可以继续清理数据。
清理数据:-
虽然看起来我们的数据是干净的,但是标题栏中有一些特殊的符号需要被删除。
所以,我们使用正则表达式来消除特殊符号。
# Relacing special symbols and digits in headline column
# re stands for Regular Expression
data['headline'] = data['headline'].apply(lambda s : re.sub('[^a-zA-Z]', ' ', s))
特征和标签提取:-
是时候从我们的数据中提取特征和标签了。看来我们可以把 article_link 和 headline 当做特色。但是, article_link 在预测标签方面并没有起到重要作用。因此,我们仅有的功能是标题栏。而是 _ 讽刺是唯一的标签。
# getting features and labels
features = data['headline']
labels = data['is_sarcastic'**]**
特征词干:-
S temming 是将一个单词简化为词干的过程,词干附加于后缀和前缀或单词的词根,称为引理。词干在自然语言理解(NLU)和自然语言处理(NLP)中很重要。
例如:-
原话:【读书】****【读书人】。
词干后:读作(以上两个词都适用)。
# Stemming our data
ps = PorterStemmer()features = features.apply(lambda x: x.split())
features = features.apply(lambda x : ‘ ‘.join([ps.stem(word) for word in x]))
使用 TF-IDF 矢量器对特征进行矢量化:-
TF-IDF是 术语频率-逆文档频率 的缩写,是一种非常常见的算法将 文本转换成有意义的数字表示。该技术广泛用于在各种 NLP 应用中提取特征。
# vectorizing the data with maximum of 5000 features
from sklearn.feature_extraction.text import TfidfVectorizer
tv = TfidfVectorizer(max_features = 5000)
features = list(features)
features = tv.fit_transform(features).toarray()
训练和测试数据:-
做完所有重要的事情后,是时候把我们的数据分成训练和测试部分了。
# getting training and testing data
features_train, features_test, labels_train, labels_test = train_test_split(features, labels, test_size = .05, random_state = 0)
模型的训练和测试:-
现在是表演时间,我们将使用不同的机器学习算法来训练我们的模型。
# model 1:-# Using linear support vector classifier
lsvc = LinearSVC()
# training the model
lsvc.fit(features_train, labels_train)
# getting the score of train and test data
print(lsvc.score(features_train, labels_train)) # 90.93
print(lsvc.score(features_test, labels_test)) # 83.75# model 2:-# Using Gaussuan Naive Bayes
gnb = GaussianNB()
gnb.fit(features_train, labels_train)
print(gnb.score(features_train, labels_train)) # 78.86
print(gnb.score(features_test, labels_test)) # 73.80# model 3:-# Logistic Regression
lr = LogisticRegression()
lr.fit(features_train, labels_train)
print(lr.score(features_train, labels_train)) # 88.16
print(lr.score(features_test, labels_test)) # 83.08# model 4:-# Random Forest Classifier
rfc = RandomForestClassifier(n_estimators = 10, random_state = 0)
rfc.fit(features_train, labels_train)
print(rfc.score(features_train, labels_train)) # 98.82
print(rfc.score(features_test, labels_test)) # 79.71
应用上述所有模型后,得分如下

Table: Score(Accuracy) of different models
可以看出,最好的评分器是线性支持向量分类器,其准确率为的 83.75% 。并且剩余模型具有更接近于线性支持向量分类器的精度。因此,我们选择了最好的一个。
用户界面:-
F 或者为了让它对用户友好,我们还使用 HTML、CSS 和 Bootstrap 构建了一个用户界面,它由 The Flask 支持。
这就是我们的用户界面的样子

Fig: Home Page

Fig: Result Page
基于输入的文本,我们的模型预测它是否是讽刺的。
总结:-
由此可见,我们可以多么好地利用机器学习算法的力量,让这个情感分析变得更加容易。
特别感谢:-
这个项目的实现是在了不起的导师们的指导下在 Forsk-Labs 完成的,他们在建造这个奇妙的项目时给了我们很多帮助。我将永远感谢他们的支持和善意。
关于我们:-
我们(作为一个由两名成员组成的团队- DIGVIJAY SINGH 和 Sourabh Prajapati )在Forsk Technologies的暑期实习期间构建了这个项目。
GitHub 回购二维码:-

QR Code to GitHub Repository
Android 中基于单词嵌入的讽刺检测
📱移动机器学习
在 Android 中使用单词嵌入的惊人力量。

Photo by Kelly Sikkema on Unsplash
喜欢在 TensorFlow Keras 中使用预训练嵌入?他们只是把验证精度提高到 80 和 90。无论是 GloVe 还是 Word2Vec ,单词嵌入在自然语言处理(NLP ) 中都显示出了巨大的成效。我们如何在您的 Android 应用中利用这种强大的嵌入功能?此外,没有使用任何第三方库和 API,只有 TensorFlow Lite 和 Android SDK。兴奋吧?我们走吧!
Python 项目的源代码可从→https://github . com/Shu bham 0204/sarcash _ Detection _ NLP _ tensor flow获得
Android 应用程序的代码→https://github.com/shubham0204/Sarcaso_for_Android
一目了然。
See the code!
我们将创建一个应用程序,检测 Android 应用程序中讽刺的推文/文本。
我们的主要挑战是将
tf.keras.layers.Embedding层导出到包含单词嵌入对的 JSON 文件。
JSON 文件将在我们的 Android 应用程序中被解析。它将包含成对的单词嵌入,其中嵌入将是 50 个浮点数的数组。
什么是单词嵌入?
单词嵌入是属于某个语料库的单词的密集表示。比如,
[ [ 'king' ] , [ 'queen' ] ] = [ [ 0.1 , 0.78 ] , [ 0.456 , 0.23 ] ]

当投影到 2 或 3 维空间时,嵌入向量在方向或接近度上表现出某种相似性。因此,在我们的例子中,一个单词的上下文(来自语料库)被打包在一个 50 维的向量中。
它们建立文档之间的关系。被分类为同一类别的文档在它们的嵌入中具有相似性,这由神经网络学习。
在张量流和 Keras 的背景下。
在 Keras ( TensorFlow)中,我们在tf.keras.layers模块中有一个[Embedding](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Embedding)层。
embedding = tf.keras.layers.Embedding( input_dim , output_dim , input_length )
input_dim:一个值为max_index_in_vocab + 1的int对象。max_index_in_vocab是分配给词汇表中一个单词的最大索引。
output_dim:嵌入的维度。每个记号/单词将被转换成一个output_dim维嵌入向量。
input_length:输入序列的长度。
Keras 模型入门。
Keras with TensorFlow is just…
我建议看一下下面的文章,以便更好地理解。有些步骤已经在里面详细说明了。
[## 基于 TensorFlow 的 Android 文本分类
事实证明,机器学习在一些使用案例中非常出色,例如垃圾邮件分类,我们将在…
medium.com](https://medium.com/dataseries/spam-classification-in-android-with-tensorflow-lite-cde417e81260)
Snippet: 1.1
这是我们的 Keras 模型。我们将使用Conv1D层而不是LSTM层(尽管LSTM层提供了更高的精度),因为 TensorFlow Lite 不支持该 op(操作)。见此处。
Snippet: 1.2
我们将模型转换为带有TFLiteConverter和post_training_quantize=标志的.tflite模型,以减小模型的大小。见此处。
注意: 我们需要先从模型中去掉 *Embedding* 图层。TF Lite 中也不支持 *Embedding* 图层。我们将在推理时直接向模型提供 Android 中的嵌入。
将嵌入层权重导出到 JSON 文件。
下面是代码中发生的事情的摘要:
Snippet: 1.3
- 从文件中加载模型。使用
model.layers[0].get_weights()[0]获得第一层的权重,在我们的例子中是Embedding层。 - 加载分词器的
word_index。word_index是一个dict,它将单词映射到它们的索引。我们对这个dict进行转换,以便它将索引映射到单词(为了方便)。 - 使用
embedding_matrix和修改过的word_index,我们创建一个新的dict,命名为embedding_dict,它将单词映射到嵌入。这是一个简单的 for 循环。 - 使用 Python 的
[json](https://docs.python.org/3/library/json.html)模块将embedding_dict转换成 JSON 文件。
代码片段中也标记了这些步骤。
*tokenizer.pkl* 是 [*tf.keras.preprocessing.text.Tokenizer*](https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/text/Tokenizer?hl=en) 的腌制版。最终,我们需要分词器的 *word_index* 。还有, 注: 在提供的源代码中,我自己创建了一个自定义的分词器,同样包含 *word_index* 。看这里。
源代码中的代码片段引用:
现在在安卓。
I just you can try this in iOS too!
我们需要读取使用[JSONObject](https://developer.android.com/reference/org/json/JSONObject?hl=en)在 Python 中创建的嵌入的 JSON 文件。对于嵌入了 50 维的大约 18000 个单词的词汇表,JSON 文件的大小是 17–19mb。这就足够挂 Android 里的 UI 线程了。我们需要解析一个[AsyncTask](https://developer.android.com/reference/android/os/AsyncTask)中的文件。
Snippet: 2.1
嵌入已经被解析为一个DoubleArray,并且该单词已经被传递给一个String。VocabCallback用于在词汇表或 JSON 文件加载后调用方法。
原始文本的填充和标记也有所改变。这些是填充和标记原始字符串文本的方法。
Snippet: 2.2
这里,embeddingDim是嵌入的维数,在我们的例子中是 50。embeddingData是Hashmap,我们通过解析 snippet-2.1 中的 JSON 文件创建的。这里的可以看到Tokenizer.getTokens()方法。
加载 TFLite 模型和词汇表。
Snippet: 2.3
loadModelFile()返回存储在应用程序的 assets 文件夹中的 TFLite 模型的MappedByteBuffer。
由于 TensorFlow Lite 不支持Double数据类型,classifySequence()做出最终推断,并将Array<DoubleArray>转换为Array<FloatArray>。
我们创建了一个回调函数,当词汇表加载到后台线程中时,这个回调函数就会被触发。
Snippet: 2.4
当点击“分类”按钮时,我们执行最后的推断。
Snippet: 2.5
源代码中的代码段引用。
对 TensorFlow 和 Android 有帮助的资源。
我知道上面的东西对初学者来说可能是惊人的。参考这些资料。
还有呢!
仅此而已。
有一个专业建议。在源代码中,我使用了手套字嵌入。自己看代码实现。
Machine Learning on Android!
希望你喜欢。机器学习快乐!
Python 和 Jupyter 笔记本中的卫星图像访问和分析
使用 Python 在 Jupyter 笔记本中访问、预处理、分析和可视化卫星图像。

SENTINEL-2 GLOBAL COVERAGE. Source
全球每天收集的大量卫星图像是巨大的。地球的频繁全球覆盖和公众随时可获得的高分辨率数据有助于监测地球及其环境。
在本教程中,我们将学习如何使用 python 在 Jupyter 笔记本环境中访问、分析和可视化卫星图像。卫星图像是像素化的数据,就像你用过的任何其他类型的图像一样。在地理和遥感术语中,这被称为栅格。光栅图像主要由卫星图像、激光雷达数据以及地理参考地图组成。正如我们将看到的,栅格由像元和行的矩阵组成,每个像元/行包含位置信息,如高程、温度和植被。
我们将在本教程中介绍以下内容:
- 在 Jupyter 笔记本中直接用 Python 查询、检索、下载卫星图片。
- 在 Python 中读写光栅图像。
- 从 Sentinel 2 波段创建 RGB 和 NDVI 图像
访问数据
在本教程中,我们将使用 Sentinel 2 数据。访问 Sentinel 2 图像有许多选择,其中大多数都需要你通过网站交互来访问,无论是直接通过下载服务实用程序还是通过云。然而,由于我们使用的是 Jupyter notebook,我们将在这里使用一个 python 库来访问它们,这个库使搜索、检索和下载 Sentinel 卫星图像变得容易。所以让我们通过 pip 开始安装sentinelsat。
pip install sentinelsat
在我们能够使用[sentinelsat](https://github.com/sentinelsat/sentinelsat)之前,我们需要在 Copernicus Open Access Hub 中注册一个用户名,记下你的用户名和密码,并将它们粘贴到代码中。
Set up sentinelsat python library authentication
您已经准备好使用sentinelsat并下载 Sentinel 卫星图像。在本教程中,我们将使用意大利罗马市的边界数据。在罗马的南部,有一个名为 Castel Porziano 的自然保护区,我们将使用它作为边界,从整个卫星图像切片中进行裁剪。
我将自然保护区的边界作为 Shapefile,我们将使用 Geopandas 读取它,并使用 yellow python 库可视化它(请注意,我已经在这里提供的 3 部分系列文章中介绍了 Geopandas 和矢量数据分析:第 1 部分、第 2 部分和第 3 部分)
Read boundary data and visualize
使用上面的代码,我们已经在 Geopandas 中读取了自然保护区 shapefile,并将其命名为nReserve,然后在 foyl 中创建了一个以该区域坐标为中心的空底图,我们将其命名为m。最后,我们可以将 Geopandas 数据添加到我们创建的底图中,以可视化我们感兴趣的自然保护区边界。下面你可以看到地图。

Castel Porziano natural reserve, Souther part of Roma, Italy.
在我们可以搜索和下载哨兵 2 图像之前的最后一步是从nReserve几何体创建一个足迹。这里我们将使用 Shapely Python 库,因为我们的数据位于 Shapefiles 中,并且已经作为 Geopandas GeodataFrame 读取。(注意,如果您有 Geojson 数据,sentinelsat提供了一种简便的方法,可以在查询中将您的数据转换成适当的格式)。
Create a footprint for the query.
现在我们可以在上面创建的api上运行一个查询。根据您的用例,这里有不同的方法来构造您的查询。在本例中,我们将创建 Sentinel 2 影像等级 2A 的查询,其云覆盖率介于 0 和 10 之间,与覆盖区(研究区域)相交。对于该时间段,我们只对“20190601”和“20190626”之间拍摄的哨兵级别 2A 卫星图像感兴趣(关于有效搜索查询的参考,请参考 scihub )。
Query for satellite images available
我们用查询规范得到一个包含这一时期所有可用产品的字典。在这种情况下,我们只接收到 6 张拍摄的图像,但是您可以针对您的用例示例调整查询,扩展时间段或增加云覆盖百分比。
在这里,我们可以从product字典创建地理数据框架或数据框架,并根据云覆盖百分比对它们进行排序。我更喜欢地理数据框架,而不是普通的数据框架,因为前者包含每个卫星图像切片的几何图形。一旦我们创建了地理数据框架并对其进行排序。因为我们这里没有很多产品,所以我们直接调用products_gdf_sorted表来查看所有 6 行的属性。
Convert satellite images available metadata into GeoDataFrame.
下表只显示了products_gdf_sorted表的前几列。在索引中,您有可以用来下载特定图像的图块。其他列还包括一个标题,其中包含切片的全名和一些其他有用的列,如云覆盖率。

Sorted Products table by Cloud coverage percentage
假设我们对第一幅卫星图像感兴趣,因为这是所有可用图像中云层覆盖最少的。我们可以简单的调用 download,提供产品名称(注意可以用 api.download_all()函数一次性下载所有图片)。
这需要一段时间(Sentinel 2 卫星图像切片大约为 1 GB)。一旦下载完成,我们可以简单地解压它。在下一节中,我们将使用下载的卫星图像来处理、分析和可视化它们。
使用 Rasterio 探索卫星图像
一旦我们解压缩下载的文件夹,我们会得到许多子文件夹,有时很难浏览这些文件夹。这是一个文件夹树。

Sentinel 2 downloaded data tree.
Sentinel-2 的数据是多光谱的,在可见光、近红外和短波红外光谱中有 13 个波段。这些波段具有不同的空间分辨率,从 10 米到 60 米不等,因此图像可被归类为高-中分辨率。虽然有其他更高分辨率的卫星可用(1 米至 0.5 厘米),但 Sentinel-2 数据是免费的,重访时间长(5 天),这使其成为研究环境挑战的绝佳选择。这是一个有用的 sentinel 2 波段颜色表。

Sentinel-2 Bands, Wavelength, and Resolution
创建 RGB 图像
卫星图像的真实颜色通常是由红、绿、蓝三种颜色组合而成的。让我们首先用 Rasterio 读取数据,并从波段 4、3 和 2 创建一个 RGB 图像。
首先,我们在 Rasterio 中用相同的参数打开一个空的 RGB.tiff 文件,即宽度、高度、CRS 等..—波段 4(您可以选择三个波段中的任何一个)。然后,我们需要将这些条带写入空的 RGB 图像。

RGB Image tile visualized with QGIS — Souther part of Roma, Italy.
剪辑卫星图像
裁剪或遮蔽研究区域的一项重要预处理任务。由于这个 RGB 图像很大,你可以节省计算能力和时间,只使用感兴趣的区域。我们将从 RGB 图像中截取自然保护区。
这里,我们首先用与原始图像相同的投影重新投影我们的自然保护区。接下来,我们打开 RGB 图像,获取元数据并使用投影边界进行蒙版。

Masked image from RGB.
结果只是如上图所示的被遮罩/裁剪的感兴趣区域。
创造 NDVI
计算归一化植被指数(NDVI)是从卫星影像上评估绿色植被存在与否的一个重要指标。为了计算 NDVI,你需要红色波段和近红外波段(NIR)。不同的卫星图像为这些波段分配不同的编号。哨兵图像在第 4 波段有红色,在第 8 波段有 NIR。NDVI 的计算公式是:
nir - red /(nir + red)
为了在 Rasterio 中实现这一点,我们首先需要将第 4 和第 8 个波段作为数组读取。我们还需要确保数组是浮点数。
Write an NDVI image from the bands
输出是一幅 NDVI 图像,显示了卫星图像中区域的植被水平,如下所示。例如,水的植被很少(在图像中显示为红色)。

NDVI image visualized in QGIS.
结论
使用 Python 访问 Sentinel 2 图像通过sentinelsat变得简单。在本教程中,我们介绍了如何构建查询并从可用图像中检索信息,以及如何在 Jupyter 笔记本中下载 Sentinel 2 图像。我们还了解了如何预处理、创建 RGB 和 NDVI 图像以及用 Rasterio 可视化光栅图像。本教程的代码可以在这个 Github 存储库中找到,带有 Google Colab 笔记本,您可以直接运行。请随意尝试,如果您有任何意见或问题,请告诉我。
Python 遥感教程。通过在…上创建帐户,为 shakasom/rs-python-tutorials 开发做出贡献
github.com](https://github.com/shakasom/rs-python-tutorials)
作为一名数据科学家,你能挣多少钱

简介
SaturnCloud.io 团队与 Reddit 的顶级数据可视化专家之一 thiagobc23 合作,深入研究世界各地、各行各业的数据科学家的薪酬,以及许多个人资料属性。(数据来源于 Kaggle DS & ML 调查 2018 )。
您可以在此查看和使用我们的笔记本:
点击跑土星!执行笔记本。
披露:我们让发布和分享笔记本变得非常容易
为什么要看这个?
在这篇文章中,你会对这个世界上发展最快的工作的实际收入有多高有一个很好的认识。也许你会得到一些想法,如何把你的职业塑造成你喜欢的东西,同时还能得到很好的报酬。

应该学什么?
想象你又是一个孩子,你不知道该选哪个专业。
在美国,科学、技术、工程和数学(STEM)专业的平均薪酬往往比商业和人文科学、社会科学或生命科学专业的同龄人高出 20%。与此同时,在欧洲,分布完全相反,STEM 比他们的 HSSLS 同行少挣大约 20%。

一旦你选择了一个专业,你最终会面临选择是继续深造还是加入劳动大军。
你的岔路口时刻
想读研吗?有些人会指出,你会再花几年时间积累债务,放弃薪水;但是你的平均工资会高出 10-20%。你也将受到更多的教育,并开始做许多有趣的研究。
读研以增加你的收入潜力值得吗?

除非你留在学术界,否则你会(希望)在某个时候毕业,得到很多面试,一些工作机会,以及一个有聪明同事的工作场所。
但是哪个行业为其宝贵的数据科学家付出的代价最高呢?
按行业支付
这并不奇怪,但它是技术(计算机/技术&在线服务/基于互联网的服务)。如果你是一名拥有生物医学背景的数据科学家,你仍然有很高的收入潜力,可以留在你的领域内,尽管你的收入明显低于你在风投支持的科技公司 WeWork 的邻居。如果你留在学术界,你的收入基本上只有科技行业的一半。在这一点上,真正的问题是你的激情是什么。

你在申请目标行业的工作——但是这些不同的头衔是怎么回事呢?工作会有所不同,但报酬会有很大影响。
附注——我们正在土星云招聘员工,所以如果你有兴趣与一家构建下一代数据科学平台的科技公司合作,请查看我们的职位空缺!您将与一些世界最大品牌的数据科学家合作。
按职位支付工资
这就像顾问对临时承包商;如果你想赚尽可能多的钱,做一个数据科学家,而不是统计学家。也就是说,这些其他角色的性质可能涉及一些非常有趣的工作,如果那是你正在寻找的。

现在让我们来看看地形。(平均年薪,以美元计)。
按地域和经验付费
如果你刚出校门,很少有地方能让你快速赚到六位数。

幸运的是,在你进入职业生涯的第一个五年后,这种情况会发生变化,那时你的薪水可以接近 20 万美元。

职业生涯 15 年:

所以你有它。数据科学家的全球报酬率。
祝你好运!
希望这有助于你的教育、职业和未来成为一名数据科学家。
土星云是一个数据科学平台,它实际上自动化了您的开发运营。从 Anaconda、NumPy 和 SciPy 的创建者来看,Saturn Cloud 使发布和共享笔记本、定制您的环境、在 GPU 上运行以及与您的工作流程的许多关键集成一起工作变得容易。
请登录 www.saturncloud.io 查看我们的网站,了解为什么有数十家科技公司在使用我们的平台。
神经网络的学者综合症

Illustration by Frank Zielen (puzzle images shop.korsches-hits-for-kids.de)
配备了惊人的能力,但为特定任务量身定制的神经网络表现得像数字世界中的专家。在这篇文章中,我们通过挑战一个简单的马赛克图片图像识别模型,展示了他们强大的技能。我们发现了惊人的“雨人”行为。为了更好地理解,我们深入到网络的隐藏层,通过相关性分析可视化其逻辑,并看到数据的混合性质在神经连接中变得明显。
我喜欢通过简单的模型来研究基本问题,例如,神经网络(NN)可以在多大程度上复制人类行为。因此,让我们用一个“令人困惑”的任务来处理一个简单的用于图像识别的神经网络。
设置和传统培训
为此,我们依靠时尚-MNIST 数据集,该数据集包含服装图片(60.000 用于训练,10.000 用于测试)以及相关类别(套头衫、裤子、运动鞋等),并设置一个神经网络进行分类。因此,我们可以输入一张图片,神经网络预测类别。我们使用一个完全连接的 3 层模型:一个 784 节点的输入层捕获 28x28 灰度图像(每个像素一个节点),一个 128 节点的隐藏层,最后一个 10 节点的输出层用于分类。这个用例是众所周知的,例如,你可以在 TensorFlow Keras 框架的教程中找到它。
这个简单的神经网络的性能相当不错。经过 5 个时期(用 300,000 幅图像训练)后,它已经显示出 87%的准确度。
混乱的图像
现在我们来挑战 NN。为此,我们通过应用一个规则的 4x4 网格并随机洗牌来转换图像,以便每个块都改变位置(这被称为固定点自由排列或错位)。这种图像此后被称为“混洗”。

Example for an original and a shuffled Fashion-MNIST image
然后我们洗牌 10000 张测试图片,要求预测。准确率下降到 11%。这意味着 NN 任意选择类别(因为从 10 个类别中随机选择的命中率是 10%)。只是猜测而已!
这是可以理解的,因为混洗的图像对神经网络来说是全新的,并且从来没有建立神经连接来解开这样的输入。
用混洗的图像训练
但是如果我们把它倒过来会怎么样呢?我们用混洗图像(还是 60.000)训练网络,并验证原始和混洗测试数据集的性能。在下图中,您可以看到所有结果的组合。

Accuracy of NNs
用混洗图像训练的 NN(“混洗 NN”)获得 63%的性能,即大约 3 个图像中的 2 个被正确分类。这是一个非常好的表现,绝对了不起,如果你记住有!16 ≈ 7,7 万亿个选项来混洗一幅图像的 16 个网格块(这里是符号!n 表示第 n 个错位数)。
我们还注意到,正常图片的准确率仅为 32%,远低于混洗输入的预测水平。这可能是因为我们仅用错位来训练神经网络,即,没有图片的任何一部分保持在相同的位置。因此 NN 被触发来混洗输入数据,而原始图像不需要混洗。
通过相关性分析揭示神经联系
NN 必须学习两项技能:
- 根据 10 个服装类别进行适当分类
- 碎片图片的正确组合
对于第二种技能,NN 必须认识到输入图像由 4×4 块组成。所以我问我自己:被打乱的 NN 是否意识到被碎片化的图像喂养?
为此,我们将混合神经网络与“原始神经网络”(用原始图片训练)进行比较,并查看隐藏层的权重,该权重将所有输入像素与所有隐藏层神经元连接起来(我们使用完全连接的神经网络)。请记住权重的矩阵结构:每个像素都有一个关联的权重向量,所有权重都将像素连接到隐藏层神经元。大的正权重值(向量中的条目)意味着该像素是相应隐藏层神经元的相关输入,因为该像素的值被放大,而小的(零或负)权重值意味着该像素与隐藏层神经元不相关。
但是我们如何从权值中提取神经网络包含关于输入数据的网格结构的知识呢?为此,我们计算两个权重向量之间的相关系数 R,由下式给出

Definition of correlation between weight vectors of two pixels
相关系数值在-1 和 1 之间。如果两个像素在隐藏层中触发相似的节点区域,则相关权重的相关性往往较高,目标为 1。然而,如果两个像素寻址隐藏层中的不同区域,R 趋向于零甚至-1。
现在我们在最后一英里。我们假设网格结构反映在隐藏层中。因此,如果像素对位于同一网格块内,相邻像素的相关性应该是高的,如果像素位于不同网格块的边界内,相邻像素的相关性应该是低的。因此,我们为每个像素计算与其向右下方最近的邻居的相关性的平均值。

Definition of weight vector correlation between adjacent pixel pairs
如果我们将这两个 NNs 的值可视化,我们将获得以下热图:

Weight vector correlation between adjacent pixel pairs for original NN and shuffled NN
这表明,混合神经网络进化出一个单独的隐藏层,其区域专用于每个网格段,而原始神经网络考虑图像整体。
结束语
请注意,我们使用了一个简单的 3 层稠密神经网络用于分类。特别是,我们没有使用卷积网络。然而,我们的网络能够识别困惑的图像。
有人可能会认为,迷惑只是图像表现的一个额外自由度,即一只鞋可以显示为原始的,也可以显示为几个迷惑的变体,然而,所有这些图片仍然只是一只鞋(尽管迷惑的版本在现实生活中非常罕见)。但是如果是这样,NN 将整体处理输入图像,并且不显示分离的权重结构。
此外,我问自己,所应用的令人困惑的算法是否也是一种形式的数据扩充。至少它不是像旋转或缩放那样的经典变换来放大训练数据量。
最后,随意浏览我的代码。所以你可以复制我上面提到的所有发现。用 Python 写的 TensorFlow Keras。
感谢阅读这篇文章!如果你喜欢这个神经会议,我会很高兴听到你鼓掌。但也许我的发现是一顶旧帽子?如果您能提供进一步的见解、替代方法或了解相关主题,请随时添加您的评论!
进入地牢前保存!Git 简介

所以你是勇敢的冒险者,站在深渊的入口处,黑暗,未知的表面之下。你已经做好了所有的准备。你的包里装满了有用的药水、工具和滋补品。你磨快了你的刀刃,增强了你的盔甲。你鼓起勇气,穿过了这片土地上最臭名昭著的地牢的入口。你准备好了。
…但是如果你不是呢?即使是最勇敢的英雄也需要后备计划。你应该保存你的游戏,以防事情变得糟糕或者致命。
还有你,卑微的程序员,站在一个项目的开端,一个伟大的,未知的潜在未来的开端。你也应该保存你的游戏,用 Git!

Git 是一个分布式版本控制系统,用于在软件开发过程中跟踪源代码的变化。它是为协调程序员之间的工作而设计的,但也可以用来跟踪任何一组文件中的变化。
那么它是如何工作的呢?一旦你在你的机器上安装了它(如果你还没有的话,点击这里获取)第一步是创建一个 Git 库。当您在本地机器上构建项目时,您可能会将它放在某个本地工作目录中。Git 存储库只是一个启用了 Git 的目录。
有两种方法可以启动 Git 存储库。第一种是将现有目录转换成 Git 存储库,这是通过以下方式完成的:
$ git init
这将向目录中添加一个. git 文件,并允许您开始跟踪对文件所做的更改。第二种方法用于克隆现有的 Git 存储库:
$ git clone
从 GitHub (一个用于共享项目和代码的网站)克隆仓库是非常普遍的,并且受到高度鼓励!在 GitHub 上创建一个空的项目资源库,然后将其克隆到您的本地机器上是非常正常的。
所以现在让我们开始跟踪一些变化吧!事实上,制作存储库本身就是一个跟踪变更。现在,您的存储库看起来像这样:

没什么了不起的,对吧?但是让我们为你的项目做一点工作。假设你花了几个小时在你的项目上,但是你不确定如何继续下去。现在是使用 git commit 保存您的工作的最佳时机。提交您的工作就像告诉 git 您想要将哪些文件添加到提交中一样简单:
$ git add <files you want to include in the commit>
添加您已经更改的任何文件,或者如果您不确定哪些文件已经更改,请使用:
$ git status
已修改的文件将以红色显示。一旦决定了要将哪些文件添加到提交中,请使用:
$ git commit -m "Left a commit message because it's best practice"
重要的是留下描述你所做的改变的信息,这样你未来的自己就能发现它们,以防出错。现在,如果你不得不回到这个“保存”它会更容易找到。我们现在可以想象您的存储库是这样的:

在任何时候,当您将变更提交到您的存储库时,如果您从 GitHub 克隆了您的存储库,您可以通过以下方式将您的变更推回到远程 GitHub 存储库:
$ git push
好的,很好!但是,假设你已经为你的项目工作了一段时间,你意识到别人,肯定不是你,犯了一个严重的错误,危及了项目。你知道这个错误是在他们更新“Rom 驱动器数据”时犯的,所以你想回到那个提交并修复它。

这可以通过使用:
$ git log
检查你以前犯下的罪行。这将显示类似这样的内容:

Feel free to email me. I don’t bite often 😃
这里有很多信息。这些是以前的提交,从最近的开始在顶部。您可以看到每个提交的唯一 id、提交者、提交时间以及提交消息。为了返回到以前的提交,复制提交的唯一 id,点击“q”退出 Git 日志,然后使用:
$ git checkout <unique id>
您将会收到如下消息:

啊!你是个无头僵尸!不完全是。它说的是你不再在树枝上了。Git 中的流是在分支中建立的,而在新的存储库中只有一个分支,称为“主”它看起来像这样:

在超脱的头部状态下,你可以尝试其他事情,添加其他提交,随心所欲地自由实验。但是,如果您想要保存这些更改,您必须创建一个新的分支。这可以通过以下方式轻松实现:
$ git checkout -b <new-branch-name>
它创建了一个新的分支(“b”部分),然后转移到它(“checkout”部分)。如果您在分离的 head 状态下发出此命令,它将自动使分支脱离您的当前状态。
就像我们这个大胆的冒险者穿过地牢,来到一个十字路口。他在走左边的路之前保存了他的游戏,在那里他找到了黄金和战利品,但是也许他也想知道如果他走右边的路会发生什么。所以我们做了一个分支:

如前所述,使用以下命令在分支之间导航:
$ git checkout <branch you want to go to>
使用 Git 可以做的事情太多了!开始学习的一个好地方是 Git 文档。愿你所有的版本控制都快乐而明亮!周三快乐:)
从垃圾箱中保存数据研究
将数字转化为有用见解的秘诀

Source: Steve Johnson, Pexels
想象一下,你是一个热门的新移动支付服务的首席执行官。每天晚上,你都梦见杰夫·贝索斯买下你的公司,给你大把大把的钞票。但是为了让杰夫在乎,你需要尽快扩大你的用户群。怎么会?
决策总是归结为这类问题。我们应该如何做某事?我们应该采取哪种行动?
然而,即使淹没在数据中,你似乎也永远没有做出明智决策所需的信息。这篇文章不仅解释了为什么这种情况不断发生,而且实际上提供了一个解决方案。就在我们之间,这是我知道的最有用的东西。
有一点是肯定的,我们缺少的不是的数字。例如,在你想象中的移动支付公司,你会遇到大量看似深刻的统计数据,通常以图表的形式呈现,就像这个:

它当然告诉你,在移动支付 app 中,微信的用户基数最大。
因为你已经在这个行业呆了至少两个月了,你知道支付宝和微信都主要针对中国市场。所以,看看这些列的相对大小,你就可以推断出使用移动支付的中国客户比世界其他地方的都多。
但差不多就是这样了。这张图表没有告诉我们的是:

一个超级有用的心智模型
当寻求解决一个商业问题时,我们有一些——也许很多——关于如何解决它的潜在想法。我们对更多的想法持开放态度,但我们真正想要的是指出哪些想法可能效果最好。
为了找出回答这些问题我们需要知道的东西,使用一个叫做 DIKW 金字塔的心智模型是很有用的。

它的名字是你能知道的四层东西的缩写:数据、信息、知识和智慧。我们将很快分解每一层的含义。
但是最突出的一点是,并非所有类型的“知道”都是一样的——有些比其他的更有价值。
这里有一个很好的例子:尽管商业解决方案爆炸式增长,但营销分析仍未能给人留下深刻印象,在过去的六年里,它对公司整体业绩的贡献一直是微不足道的。
你不觉得奇怪吗,公司拥有所有这些数据,却一直在努力利用它们?

Chief Marketing Officer Survey, February 2019
进行调查的研究人员非常清楚需要改变什么:
“企业应该先决定做什么,然后决定需要哪些数据,而不是创建数据,然后再决定如何处理这些数据。”
这看起来很简单,但是当我们看金字塔时,问题突然变得很明显:

我们追求的可操作的洞察在智慧层,一路在顶端;但是我们为了获得洞察力而收集的东西是数据,就在底部。
因此,要获得商业问题的有意义的答案,仅仅收集数据,甚至分析数据是远远不够的。这是一个从数据到智慧的过程。
拥有这样的路线图意味着你可以从一个业务问题回溯到你想要的那种数据。因此,在设计调查问卷或决定收集哪些数据的最初阶段,你就能知道以后需要什么。
考虑到这一点,你能想象如果从一个级别到下一个级别仅仅是一个具体的正式步骤的问题,那会有多好吗?
我说过这是我所知道的最有用的东西之一。
数据
有了数据,你什么都不懂。
数据仅仅是观察的集合:计算机服务器日志;交易清单;项目的集合。在一无所知的情况下,我们从数据中获得的任何洞察力都将是处理数据的结果。
信息
我们通过询问关于数据的可量化的问题来获取信息。一个简单但有用的经验法则是,信息本质上是计算数据点:

为什么或如何永远无法在数据上要求导出信息。所以,当我们获得信息时,我们知道了一些事情,但是没有什么有用的,因为我们缺乏背景。
看看这些杂乱的信息点。每个看似有见地,但实际上告诉你的很少,因为你没有任何参考点。

Useless.
知识
当我们比较和对比两个或更多的单位或信息时,我们就获得了知识。请注意,它总是使用信息位,而不是数据位。要看到这一点,回想一下数字支付图表。
想想看,如果说:微信有 6 亿用户,Paypal 在周一 08:35GMT 记录了一笔英国交易,这将是多么毫无意义。
一个是信息点,一个是数据点;这两者不一致。
相反,我们统计了每个支付平台有多少用户。这是从数据中获得的信息。通过对这些结果进行排序,我们可以看出微信拥有最大的用户群。这就是知识——一个相关的事实。
更一般地说,从信息点获取知识的方法是使用逻辑量词进行推理:

请注意,您可以使用来自不同数据集的信息点。例如,我们的图表没有说明每个应用程序的用户群位于何处。微信和支付宝的客户大多来自中国,这是我们从别处得到的信息。
不过要小心!逻辑推理必须有效。例如,我们不能说下面的话,因为这个推论是错误的:

我看到很多研究、调查和分析都落入了这个陷阱:它们给出了一个结论,却从未停下来考虑其他同样有效的解释。(经济学家是一个特别的惯犯。)
通过列出不同的可能解释,你会显得更有洞察力,而不是直接选择你碰巧更喜欢的那个。
智慧
所有先前类型的认知都有一个共同的特征;他们都可以被两个简单的词击垮:那又怎样?

相比之下,智慧是一种可操作的洞察力。你可以把它区分开来,因为它不能被类似地击倒:

智慧是非常可取的,因为它是将数据研究变得有用的唯一结果。它通常解决因果关系问题——比如如何和为什么——这些正是我们真正想要回答的问题。
解决商业问题的逻辑方法从来都不是只有一种,因为总会有几种相互竞争的可能答案。不过,这里有两个从知识到智慧的有用的提示。
第一,智慧来源于知识,再次使用逻辑量词,这次是在知识陈述之间。像以前一样,试图混淆知识和信息是没有用的。
第二,你不可能从一个数据集中获得所有需要的知识。
请再读一遍最后一句话。无论你的客户调查、每日网站流量日志或 Kaggle 数据集多么精彩,这可能都是不够的。你要么需要更多的信息(来组合成新的知识),要么需要预先获得的知识。
综合考虑
到目前为止,我们已经意识到,在做决策时,我们追求的是金字塔顶端的东西,而我们实际收集的数据是金字塔底部的东西。如果没有事先的计划,我们很可能永远不会收集到正确的数据来考虑完整的逻辑推理链。
因此,为了用数据驱动的方法评估行动的替代过程,您需要沿着支持每个行动的逻辑链回溯:
首先,这将给您一堆知识陈述,由逻辑绑定在一起。但是每一个都可以分解成一系列的信息陈述。这些会准确地告诉您需要计数的内容,直接建议您应该收集哪些数据点。
然后,一旦你真的收集了数据,你就开始按照你的步骤。这时你会发现数据、信息或知识是否在现实中积累起来:
也许你认为瞄准低收入客户是个好主意,因为他们更喜欢支付应用程序,因为交易成本更低。但随后你收集并统计了数据,得到的信息显示,使用支付应用的大多是中等收入人群。或者你可能认为在富裕的顾客中,拥有更多信用卡的人会对数字支付持更好的态度。通过回溯,你现在意识到你想知道你的潜在客户持有多少张信用卡。一旦你对数据进行了统计和分类——你所获得的知识表明这实际上没什么区别。
肯定,这些瞄准的想法原来是哑弹。但是你能够预先知道你需要什么数据来判断这些选项,因为你已经设计了从行动过程到数据的完整路径。
遗言
这篇文章几乎没有发表,尽管我已经写了几个星期了。当我把早期的草稿给我信任的聪明读者看时,他们有点畏缩:
“太抽象了”。他们说。
"此外,没人关心数字支付."
心智模型是抽象的,但这并没有降低它们的有用性。知道要问哪些问题具有难以置信的商业价值,我袖手旁观我说过:DIKW 金字塔模型是一种生成可操作见解的实用工具,因为它穿透了从数据层到智慧层的迷雾。
所以我还是发表了这篇文章。
在 Kaggle 中保存和加载 Pytorch 模型
在 Kaggle 上训练 Pytorch 模型的初学者指南

你听说过卡格尔很棒。你也在努力提高你的数据科学技能,并开始深度学习或刚刚开始 Kaggle。
就在你认为你正在 Kaggle 上训练你的深度神经网络的时候,你卡住了。
那么问题出在哪里?
所以你已经知道你可以保存 Pytorch 模型(严格地说,是状态字典)并在以后方便的时候加载它们。你已经在 Kaggle 上训练了你的模型并保存了它。当您需要访问保存的模型时,您就是找不到它,这可能会迫使您重新开始。😓😓😓
我们都知道训练一个模特可能是一个非常痛苦的过程,所以不得不从头再来一遍不是一个选择。别担心,我(和卡格尔)抓住你了!
在本文中,我将向您展示如何通过 5 个简单的步骤加载您训练过的 Pytorch 模型。
假设
我将假设:
- 你已经知道如何训练一个模特了。
- 你理解 Pytorch 的模型状态字典的概念。查看该资源了解更多信息。
- 您至少对如何保存和加载 Pytorch 模型有了基本的了解。如果没有,这个帖子是一个很好的起点。
我正在进行的项目以及随后撰写这篇文章的需要都源于我对 Udacity Pytorch 挑战赛的参与。
第一步:训练你的模型
在这个例子中,我编写了一个名为 train()的函数,它将历元数作为参数。

Step 1: Training the model
第二步:保存你的模型

Step 2: Save your model
注意:上述方法(仅保存状态字典)可能不是最好的,因为当您加载时,您将需要构建一个与您保存的模型具有相同架构的模型。
第三步:提交你的内核
Step 3: Committing your Kernel in Kaggle
完整的提交看起来像什么。

Successfully completed commit
您可能需要等待几分钟,Kaggle 服务器才会发布您保存的文件。然后您可以打开您的内核,您将在输出部分看到您的文件,如下所示。

Viewing the saved checkpoint file
第四步:添加你的内核作为数据集
这还不是结束。转到最右边的 +dataset 选项卡,点击它来添加您的内核输出文件作为数据源。
Adding your kernel output as a dataset
您的内核现在被列为数据源。打印输入文件夹的内容会将您的内核列为来源之一。
有关如何使用代码查看和访问输出文件,请参见下图。

Accessing your saved output file
要在侧边栏上查看您的文件,单击 Workspace -> input,然后您会看到您的内核被列为输入目录中的内核下的一个文件。
第五步:加载你的模型
现在你知道如何访问你保存的检查点,你准备好加载你的重量!
确保您构建的模型与您保存其状态字典的模型具有相同的架构。有一种方法可以将架构和状态字典都保存在一个文件中,这样你就不用去记忆了,但这不是本教程的重点。

Loading the state dictionary to your model
就是这样!
我希望这个->😃😃😃是您成功加载第一个模型后的心情。勇往直前,繁荣昌盛!当然,请在下面的评论区留下您的反馈。
从假货和人工智能滥用中拯救民主

Photo by abi ismail on Unsplash
今天是柏林又一个下雨的星期五下午。下午 4 点整,我的一位亲爱的同事来到我工作的地方,带我去喝杯咖啡。一边走,一边避开地板上的小水坑,她说:“昨天我看了一部关于这对夫妇的电影。在一起 9 年还爱着对方,分手了。女孩在另一个地方有一个惊人的工作机会,而男孩不想要异地恋。严重交配,令人心碎。”一件事接着一件事,突然我说:“听着,不管大家怎么说。我相信,当两个人相爱,真心相爱,一切都可以解决。他们可以克服一切。我理解并尊重他人的观点,但爱是我所做的一切的核心。“但是,伙计,真的,为什么你不能从你周围的其他人的经历中培养自己。你难道看不出生活是残酷的,意识到爱是不够的吗?”,她回答道。
与你已经想到的相反,这篇文章不是关于爱情的。这篇文章是关于民主、观点和不可理解的人工智能技术被低估的缺点。你看到我们喝咖啡的时候发生了什么吗?即使我没有告诉你,我的同事和我,我们都有非常有效和强有力的论点。问题原来是概念的定义。我们可以把它留在那里,然后继续前进。但是我们没有。我们是开放和好奇的。我们决定花几分钟时间试着更好地理解对方。结果如何?对我们双方来说都是重要的教训,共同的现实让我们能够继续沟通。
如今,我们中的许多人根据我们在新闻中看到的东西、我们在媒体上读到的东西、instagram 上展示给我们的广告或一些有影响力的人说的话来定义我们的概念和我们的现实是什么样子的。尽管人类总是自然而然地选择与认同我们世界观的人和想法互动,但这是历史上第一次如此强烈地强化我们的身份。只需在谷歌搜索为什么爱情不够,统计会出现的文章数量。
让我们以丽莎为例。丽莎是一名 30 岁的女同性恋者。她住在纽约的一个时尚街区,阅读《纽约时报》,支持民主党,最近还在推特上谈论大麻合法化。如果我们要推广一个关于进步政治的新博客,丽莎将是我们的完美搭档。Lisa 可能会用她的 iphone 打开我们的博客。她可能会读几篇文章,欣赏它们,并幸运地与她在脸书的朋友分享一两篇。她的朋友可能也会喜欢它们。他们可能属于同一个社交圈。在打开 Lisa 分享的内容后,这种行为会转化为数据,并输入算法来预测 Lisa 的朋友是否对另一个类似的事情感兴趣。
你知道这是怎么回事吗?今天比以往任何时候都更难逃避对我们身份的确认。我们喜欢它。我们的自我喜欢它。我们的孤独感减少了。但是我们个人和集体必须付出的代价是高昂的。
就个人而言,我们最终会为缺乏与其他世界观和经验的互动而付出代价。我们因此失去了多少个人成长?你还记得我喝咖啡的时间吗?总的来说,代价是社会凝聚力的崩溃和民主制度面临风险。我们不再能在我们的政治体系中找到迫切需要的共同点。我们避免任何持相反观点的互动。它们威胁着我们的身份,我们的自我。它威胁着我们。我们开始怀疑我们是否一直站在错误的一边。但是,即使我们愿意敞开心扉,对他人的立场感到好奇,也很难做到。我们不再具备积极参与这种对话的技能。我们失去了工具。我们的数字生活不是为此而设计的。
但是让我们再深入一层。如果你看到的和读到的都不是真的呢?如果我们正在消费的信息,以及通过不透明的算法得到强化的信息,是虚假的,或者是对现实的过度简化,那该怎么办?如果给我们提供这类信息的目的是为了获得政治权力呢?现在它开始变得不仅可怕而且危险。
一旦我们把眼睛从屏幕上移开,体验这个世界,我们看到的并不像我们想象的那样客观。如果我们走出去,我们消费的信息是假的,被操纵的,或者是我们复杂社会的过度简化,现实不再与我们被鼓励相信的相匹配。我们不再知道什么是真实的,什么不是。这正是我们感到最孤独的时刻。作为一种反应,我们倾向于全力抓住自己的身份,避免与相反的观点有任何接触。媒体向我们展示了一个现实,如果我们想继续成为我们团体的一部分,我们就必须捍卫它。我们注册了一个现实,我们不想退订。
民主的最高目标之一是辩论并以辩论取胜。一个健康的民主制度中的政治家希望说服人们一条需要采取的特殊道路,以通过争论来克服我们当前的挑战。但是那艘船很久以前就起航了。今天的政客们试图用金钱和扭曲的现实而不是争论来赢得胜利。社交媒体和人工智能的滥用是做到这一点的完美结合。为了拯救民主,我们必须认识到,我们离其最高的崇高目标还差一步。我们首先需要解决基础上的问题:我们愿意并有能力倾听其他意识形态的人,并对他们保持建设性的好奇。
大概深度假货和假新闻的解药不是只能在另一个算法里找。或许这更多的是与我们的人性联系在一起。我们需要开始对我们的信仰充满信心,并意识到没有一个单一的真理,而是许多;我们都是能力有限的人,没有机会拥有客观的真理。或许这也与赋予不同的政治观点权力有关,让它们在数字领域有发言权。只有到那时,我们才能面对我们现在的现实,而不会对未知感到恐惧,也不会对被过分美化的过去感到怀旧;极右翼和民粹主义政客的众所周知的秘方。
卡洛斯·阿胡马达是宇航员&公司的数据科学家,这是一家总部位于柏林的公司,旨在帮助政治和社会行为者在数字空间进行有效沟通。他们的使命是支持这些行动者使用技术和数据来建立对民主话语的信任。
用熊猫为英国国民保健服务节省数百万英镑

Photo by Debbie Molle on Unsplash
介绍
自 2010 年 data.gov.uk 创立以来,英国就有了开放数据的倡议。9 年后,我们现在在网站上有大量可浏览的数据集,可以下载并用于您自己的分析。
其中一个较大的数据集是 GP 实践处方数据,每月约有 1000 万行数据。对于普通的电子表格来说,这需要处理大量的数据,所以像熊猫这样的工具就派上了用场。Pandas 是 python 的一个数据分析库,可以处理数百万行数据,并对它们进行统计分析,以尝试提取有用的信息。
我们发现了什么?
全英国国民保健服务的总处方支出约为每月 7 亿英镑。它每个月都在上下波动,但是它保持在同一个值附近。在这 7 亿美元中,超过一半的支出用于非专利药物,其余用于品牌药物。完整的逐月分析记录如下:
NHS 时间序列分析——Jupyter 笔记本](https://github.com/simonh10/nhs-notebooks/blob/master/nhs-generic-branded-time-series.ipynb)
需要明确的是,品牌药和仿制药的平均成本非常相似,而且在很多情况下,标有品牌的药物比同等的仿制药便宜。但是这个平均值隐藏了大量的细节。

Total Prescription costs by month
如果我们看原始数据,你会看到它是如何呈现的,以及我们可以从中提取的信息。初级保健信托和个人处方实践是有用的信息,将在未来的地理分布分析中使用,但在本次分析中将被忽略。这种分析的主要信息是 BNF 代码、实际成本和数量。

First few rows of the raw prescription data available.
BNF 什么?
自 1949 年第一版以来,BNF 或英国国家处方集一直是医生手边的基础医学信息。它每 3 年出版一次,有多种数字格式。该出版物的一部分是编码标准,描述了通过国民医疗服务体系提供给患者的每一种药物。它遵循标准的层级结构,这对于分析药物组的分配是有用的,牛津大学有关于这方面的优秀资源。
OpenPrescribing 从 NHS Digtal 和 NHS Business Services Authority 获取开放数据集,并使人们更容易…
ebmdatalab.net](https://ebmdatalab.net/prescribing-data-bnf-codes/)
BNF 编码的一个特点是每个编码描述了一种获得等效仿制药的 BNF 编码的方法。BNF 代码的最后两个字母给出了通用等效物的强度和配方代码。例如
- 040702040 biac(AM)—Tradorec XL 片 300mg
- 040702040 aa(AM)(AM)—*同等通用版本*
我们给自己设定的挑战
我们能否通过将一些药物转换成使用非专利药而不是品牌药来为国民保健服务系统节省一大笔钱?我们用于计算的源信息都包含在这个数据集中。
使用这个单一数据集,我们仅限于:
- 只考虑已经由至少一个 NHS 处方实践开出的仿制药。
- 使用品牌和非专利药物的现有定价,因为它已经由 NHS 进行了成本核算。
我们是如何进行分析的
我们在 2018 年 10 月随机选择了一个最近的数据集,并以下列方式处理了数据:
- 我们为每种药品生成了等效的通用代码,并标记了它是否已经是一种仿制药。
- 我们为每个通用 BNF 代码创建了所有数量和所有成本的总和,一组总和用于品牌等价物,另一组用于通用版本。
- 我们计算了同等品牌药物和非专利药物之间的单位成本差异,并将其乘以所开品牌药物的数量。
- 这就造成了对每一种仿制药的超额成本计算,而在这种情况下也开了品牌药。
结果呢
如果所有可能的仿制药替代品牌药品,将为 NHS 节省 11,347,859.11 英镑,每月仅超过 1,100 万英镑。这是为所有可能的产品提取所有可能的节约。如果我们只取了 10 种最节省成本的药物替代品。

计算出替换这些品牌产品的总成本,我们每月将节省 5,469,671.30 英镑,即大约 550 万英镑。
结论
要明确的是,我不是一个健康专业人士。我们在此概述的成本节约只是一个数字分析,并没有考虑到处方或配药实践可能做出的任何医疗决策。
考虑到 NHS 每月在处方上的花费,我们只能在处方费用上节省 1-2 %,我认为他们在降低药物费用方面做得很好,应该对他们已经做的工作给予高度赞扬。
有关用于这些计算的完整分析和注释代码,可以在以下位置找到该项目:
NHS 仿制药与品牌成本节约分析。
github.com](https://github.com/simonh10/nhs-notebooks/blob/master/nhs-prescription-analysis.ipynb)
进一步分析的方向
这只是触及处方数据集的表面,还有很多事情可以做。以下是我考虑对该数据集进行的一些未来分析:
- 使用数据集中的地理信息创建健康状况流行的热图。例如抗抑郁药、他汀类药物、糖尿病等。
- 找出一贯偏爱品牌药而非仿制药的做法。
- 使用美国和 SNOMED 数据集计算美国医疗保险系统比国民保健系统多支付多少同等药物。
- 确定仿制药可用但目前未在 NHS 中使用的品牌药物。*
向 PySpark 的异步搜索问好
PySpark 异步搜索简介
Rich Sutton 教授——强化学习之父
TLDR;Hopsworks 使用 PySpark 在许多容器上并行化机器学习应用程序,如果您需要的话,可以包含 GPU。PySpark 的基于阶段的执行模型与用于分布式训练的最新方法 Collective-AllReduce 配合得很好,但与超参数优化配合得不太好,在超参数优化中,最新方法涉及异步定向搜索。以前,为了利用最先进的超参数优化,研究人员使用了像 Ray 这样的框架,但在这篇博客文章中,我们将这一能力引入到我们的新框架玛吉中,该框架为黑盒子超参数优化提供了 PySpark 上的异步定向搜索。
当有足够数量的高质量标记训练数据可用时,Deep 学习是一种强大的监督学习方法,用于建立预测模型。当一个组织选择深度学习的平台时,它需要迎合尽可能多的潜在用例,而一个越来越频繁出现的用例是使用具有更多训练数据的更大模型3。神经机器翻译和图像分类等不同领域的实证研究表明,对于可用的每多一个数量级的训练数据,预测模型的准确性都会有对数提高。AutoML,即建立机器学习模型的自动化,已被证明在设计模型架构方面优于人类,ImageNet 分类挑战的最准确模型已由搜索算法设计。我们能得出的唯一结论是,从长远来看,更多的数据和更多的计算将产生更好的模型,拥有更好模型的公司将在他们的业务领域具有竞争优势。
水平扩展机器学习
在图 1 中,我们可以看到扩展深度学习面临的挑战。在内循环中,通过添加大量 GPU 来减少训练模型所需时间的当前最佳实践是数据并行、同步随机梯度下降。为了找到好的超参数(在我们用大量 GPU 训练模型之前),定向的 搜索算法(如遗传算法、贝叶斯优化、HyperOpt、ASHA)被认为是最先进的。
在 Hopsworks 中,我们使用 PySpark 来扩展机器学习的内循环和外循环,见图 1(下图)。内部循环是我们训练模型的地方——这里的扩展意味着添加更多的 GPU 以使训练进行得更快(数据并行训练)。外部循环是我们运行许多实验来为我们要训练的模型建立良好的超参数的地方。我们通常运行许多实验,因为我们需要搜索好的超参数——超参数在训练期间不更新,超参数空间通常不平滑,因此基于梯度的方法通常不起作用——无向和有向搜索通常效果更好。
Spark 为分布式计算提供了批量同步并行计算框架,该框架很好地映射到内循环(同步随机梯度下降是分布式训练的最新技术水平),但是 Spark 不能有效地扩展用于超参数调整的定向搜索。为此,我们稍后介绍了一个新的框架,玛吉,并描述了玛吉的新的异步基于任务的计算模型,以实现更高效的超参数调优。但最重要的是,我们展示了如何只需几行代码,就可以更新您的单主机 Python 程序,使其成为一个庞然大物,可以使用数百个并行 GPU 调整其超参数,或者在数百个 GPU 上并行训练。我们向您展示了如何在 Jupyter 笔记本电脑中完成这一切——即使 GPU 将位于集群中,您也可以在 Jupyter 笔记本电脑中舒适地实时查看并行培训任务的日志。

图 1:横向扩展训练 ML/DL 需要横向扩展内循环(采用同步随机梯度下降的数据并行训练)和外循环(超参数搜索——定向或非定向)。向外扩展外循环使您能够并行运行大量实验,以找到具有良好超参数的良好模型。向外扩展内循环将减少训练模型所需的时间,当在大量数据上训练大型模型时,可以看到更多收益。
具有 Hopsworks 的可水平扩展的 ML 流水线
Hopsworks 是一个开发和运营数据密集型 AI 应用的开源平台。Hopsworks 利用 PySpark 为 Python 提供集群支持。借助 PySpark,TensorFlow/Keras/PyTorch 程序只需修改几行代码,就可以在集群中多达数百个 GPU 上运行超参数优化或分布式训练。从图 2 中可以看出,通过在许多 GPU 上并行化 ML/DL,我们不仅可以加快 ML 管道的速度,还可以大大提高数据科学家的工作效率。

图 2: Hopsworks 支持构建水平可伸缩的 ML 管道。机器学习阶段可以扩展到 ML 实验和训练(数据并行训练),从而大幅提高数据科学家的工作效率。
PySpark 上的同步超参数调谐
Hopsworks 从版本 0.4(2018 年 10 月发布)开始就支持使用 PySpark 进行超参数调优。在图 3 中,我们可以看到 PySpark (workers)中的执行器是如何并行运行超参数试验的,其中每个执行器也可能有一个或多个 GPU 来运行训练函数。在超参数调优中,试验是用一组给定的超参数进行的实验(训练运行),其结果作为度量返回。在同步超参数调优(参见图 4)中,试验(指标)的结果被写入 HopsFS ,驱动程序读取结果,然后可以将新试验作为 Spark 任务发布给执行器,不断迭代,直到超参数优化完成。

图 3:在右边显示的 GridSearch 示例代码中,使用所有不同的 learning_rate (lr)和 dropout 组合运行了六次试验。执行者将并行运行这些试验,因此如果您用 6 个执行者运行这个 Gridsearch 代码,它将比顺序运行试验快 6 倍。HopsFS 用于存储 TensorBoard 的试验结果、日志、任何经过训练的模型和任何可视化数据。
虽然同步方法对非定向搜索算法(如网格搜索和随机搜索)很有效,但对定向搜索算法(基于群体的方法、贝叶斯优化等)效率较低。在图 4 中,我们可以看到 3 个 Spark 阶段(即 3 个障碍),每个阶段有 N 个 Spark 任务,在单独的 Spark 执行器上执行。在 Spark 的批量同步执行模型中,一旦启动了一个作业,Spark 就创建了要执行的任务和阶段的有向非循环图,就不可能动态地停止、添加或删除阶段中的任务。此外,只有前一阶段的所有任务完成后,新阶段才能开始。因为我们评估每个任务的一个试验,这引入了低效率——早期停止不会释放执行者进行新的试验,它只能在下一阶段开始时接收新的试验。如果任何一个执行者速度慢(掉队)或者失败,就会拖慢所有其他执行者的速度。由于不同的超参数设置,试验自然会有不同的训练时间。与基于阶段的执行一起,这对于诸如 Bayesian 优化之类的定向搜索算法来说是次优的。贝叶斯优化器能够根据试验的最终性能指标来整合反馈,只要它一完成就产生更好的新样本。然而,元级贝叶斯优化器只会在完成后用一个阶段的所有指标进行更新。因此,我们希望在试验结束后尽快更新我们的知识。

图 4:由 3 个阶段组成的 Spark 作业,每个阶段有 N 个任务。每个任务都是一次试验,评估一些超参数的组合。只有当一个阶段中的所有任务完成时,该阶段的试验才结束。也就是说,驱动程序从共享文件系统中读取所有试验的结果,然后可以将新的试验作为任务发布给执行者。如果一个试验执行得很差,提前停止将没有帮助,因为执行者无论如何都必须等到阶段结束才能接收新的试验。
使用浪费的 GPU 提前停止
在超参数调优中,一些试验的性能会很差,在试验执行的早期,很明显可以停止试验,因为相对于其他正在执行的试验,它的性能非常差。在 Hyperband 上使用 RESNET-50 进行的实验中,他们看到通过提前停止节省了高达 96.5%的成本。然而,要获得这些节约,提前停止需要在执行者之间共享审判的当前表现,以了解审判的相对表现是否差。在图 5 中,我们引入了提前停止来触发——红色箭头表示提前停止的试验。在这里,我们可以看到有大量的计算浪费(GPU ),在试验停止后,执行器一直闲置到阶段结束。在这个例子中,早期停止决策不是最优的,因为它们是由执行者本地做出的——执行者不知道其他执行者试验的性能。在 Spark 中,任务是独立的工作单元,它们之间没有通信。可以通过将空闲的执行器列入黑名单来释放资源,以便其他作业可以使用这些资源,但是在多租户平台上,很难重新获得这些资源。

图 5:提前停止的超参数搜索导致大量 GPU 周期浪费。PySpark 的执行者必须等到下一阶段(关卡)到达,才能执行新的审判。为了让提前终止法更好地发挥作用,执行者应该不断地分享他们审判的当前表现,这样最差的相对表现者就可以被提前终止。
玛吉异步超参数搜索
玛吉是一个框架,在优化器的指导下,利用全局知识进行异步试验和提前停止。开发者可以使用现有的优化器,比如异步连续减半(ASHA),或者提供他们自己的优化器。参见图 6,我们遵循的基本方法是添加对驱动程序和执行器通过 RPC 进行通信的支持。引导超参数搜索的优化器位于驱动程序上,它将试验分配给执行者。执行器会定期向驱动程序发送其试验的当前性能,优化器可以决定提前停止正在进行的试验,然后向执行器发送新的试验。由于试验和 Spark 的基于阶段/任务的执行模型之间的阻抗不匹配,我们正在阻止具有长时间运行任务的执行者为每个任务运行多个试验。通过这种方式,执行器总是忙于运行试验,高效提前停止所需的全局信息在优化器中进行汇总。

图 6 使用玛吉的定向异步搜索。执行器运行单个长时间运行的任务,并接收来自驱动程序(优化器)的命令,以便执行试验。执行器还定期向驱动程序发送指标,以使优化器能够采取全局提前停止决策。
玛吉提供了两个高级 API:一个用于黑盒优化实验(超参数调整),另一个用于并行消融研究。由于玛吉有一个通用的 RPC 框架用于从驱动程序的执行者那里收集事件,我们也从执行者生成的训练中收集日志,这样这些日志可以在 Jupyter 笔记本中实时显示。这样,用户可以直接在笔记本上调试和跟踪超参数调整。
集体分散培训减少
一旦设计了好的超参数和好的模型架构,就可以在整个数据集上训练模型。如果训练很慢,可以通过添加更多的 GPU 进行并行训练来加快速度,这就是所谓的数据并行训练,其中每个工作人员(执行者)都在训练数据的不同片段上进行训练。这种类型的分布式培训从拥有分布式文件系统(Hopsworks 中的 HopsFS)中受益匪浅,在该系统中,工作人员可以读取相同的培训数据,并写入相同的目录,这些目录包含所有工作人员的日志、培训因某种原因崩溃时的恢复检查点、TensorBoard 日志以及培训结束时生成的任何模型。
同步随机梯度下降是当前最先进的算法,用于更新深度学习模型中的权重,它很好地映射到 Spark 基于阶段的执行模型。CollectiveAllReduce 是同步随机梯度下降的当前最先进的实现,因为与参数服务器模型相比,它是带宽最优的(为所有工作线程使用上传和下载带宽),参数服务器模型可以在参数服务器上绑定 I/O。
在 CollectiveAllReduce 中,在一个阶段内,每个工人将读取其小批量的碎片,然后将其梯度(作为学习算法的结果,其权重发生变化)发送到其在环上的继任者,同时并行接收来自其在环上的前任的梯度。假设所有工人在每次迭代中以相似的批量进行训练,并且没有掉队者,那么 GPU 的使用将会非常高效。发布 TensorFlow/Keras 程序所需的代码更改很少,如图 7 所示。

图 7 使用 Ring-all reduce(collective AllReduce)的分布式训练。Hopsworks 确保用于构建环的共享TF _ CONFIG环境变量由驱动程序分发给 Spark 执行器(或 TensorFlow 术语中的 Workers)。如果您运行 1 个或 1000 个工人,这里显示的代码片段保持不变。train 函数将在 Workers 上运行,每个 Worker 将在训练期间从 HopsFS 中读取它的小批量碎片。
入门笔记本
我们有许多示例笔记本可以帮助您使用 Keras/TensorFlow 在 Hopsworks 上开始分布式深度学习:
- 使用差分进化对 MNIST 进行同步超参数优化
- 使用 FashionMNIST (GridSearch)的同步超参数优化
- 使用 FashionMNIST(玛吉的随机搜索)进行异步超参数优化
- 使用遗传算法的同步定向搜索
- 在 Keras/TensorFlow 上使用 CollectiveAllReduce 进行分布式培训
- 使用玛吉的平行消融研究
对于 PyTorch,我们有超参数优化示例:
外卖
借助 PySpark,我们可以将 ML 程序从单主机扩展到集群应用,使我们能够执行更快的实验,更快地训练模型并使用更多数据,成为全方位更高效的 ML 工程师。PySpark 在支持异步搜索方面有局限性,GPU 利用率会受到影响,我们引入玛吉作为框架,向 Spark 添加异步任务,实现新的高效定向超参数搜索算法。Hopsworks 还为简单的分布式训练提供框架支持,使用来自 TensorFlow 的 PySpark 和 CollectiveAllReduce,使模型能够在更多的 GPU 上更快地训练,实现更精确的模型,从而推动业务向前发展。
[1]https://www.youtube.com/watch?v=EeMCEQa85tw
http://www.incompleteideas.net/IncIdeas/BitterLesson.html
https://www.logicalclocks.com/blogs
https://github.com/logicalclocks/maggy
对适应和转变说是!
理解 Fit 和 Transform Python 方法的简单寓言
我注意到数据科学的同学们正在努力理解方法“fit”和“transform”之间的区别和应用。所以,这里有一个简单的比喻(下面的 python 元素用斜体显示)。
你需要一件新年晚会礼服。

如果你不穿礼服,那么你可以想象你需要一套定制的西装或者一辆自行车。这个寓言仍然有效,但是我想要一件漂亮的衣服。有口袋!
所以,你需要一件新衣服。你当然只是在预测什么样的裙子会在除夕夜感觉良好,因为现在才六月。
你需要一个可以用来根据 x 预测 y 的模型
拆分您的数据
就像我们说的,现在才六月,但是这个派对将会像孩子们说的那样充满活力。你需要尽快订购这条裙子。所以,虽然你不确定你在 12 月会有什么样的外观和感觉,但你现在已经把它建立在你的身体上了。
将数据集分为训练数据和测试数据。您不知道测试数据看起来如何,所以您将根据训练数据建立模型。
拟合训练数据
你去当地的裁缝店,她给你量尺寸。她根据你的尺寸做衣服。
您根据训练数据拟合您的模型。你根据 X_train 建立模型。
转换训练数据
这件衣服大约一周后到达。你试穿一下,看看感觉如何。不出所料,感觉棒极了。那是因为你一个星期都没怎么变,傻瓜。
您可以转换您的训练数据,但该模型可能会几乎符合您的训练数据,如果不是完全完美的话。那是因为你只是把你的模型放在上面,傻瓜。
转换测试数据
今天是除夕!六个月后,你的身体与七月时不同。你试穿了这件衣服,但它的手感和外观都没有你第一次试穿时好。
你转换测试数据。这是我们保留的数据,因此它不同于模型所基于的训练数据。我们转换测试数据,它不能完美地预测一切。
过度拟合
这条裙子很完美——如果你还有七月的身材。当裁缝做的时候,她把它做得太特别了,不允许有任何改动。所以,现在,不管是太紧还是从你身上掉下来,这条裙子在除夕夜都不能穿了。
该模型生成的预测对训练集来说非常好,但无论是超出还是低于其预测,它都不能很好地预测测试数据目标。它太专为你的训练数据而调整了,而且它不能作为一个模型使用。
欠拟合
因为你的衣服不适合你,你考虑买一件均码的新衣服。它是否适合你过新年完全是个未知数,因为它甚至不一定适合你在七月。
欠拟合模型不能很好地预测训练数据。它是否能很好地预测测试数据完全是个未知数。
正规化
你决定修改裙子。那只是意味着裁缝会在不适合你的地方把它改小或改大。你可以得到不同种类的修改。
为了惩罚有大量错误的模型,你决定使用正则化。有几个常见的像套索,脊。
为什么准确性不是一个很好的评估标准
在聚会上,一群人告诉你,你穿这件衣服看起来很棒,非常合身。是真的。你看起来棒极了!但问题是。你花了一大笔钱在裁缝、衣服、修改上……你怎么知道它值不值?你将如何评价这是一件好衣服?花那么多时间难道不比从你的朋友谢尔比那里借一条裙子好吗?
通常,模型的准确性是一个倾斜的数字,因为我们忽略了随机猜测并得到相同预测的模型的准确性。当评估您的预测模型时,评估指标应该基于您的业务用例。
这里有很多不同的方法来扩展或改变这个寓言,但我希望它对认识 fit 和 transform Python 方法的不同和有用性有所帮助。
PS 拟合 _ 转换
难道你不希望你能得到一件衣服,它的材料考虑到了你的曲线,而且立即合身,有点像 90 年代的泡泡衫吗?

These shirts are the same shirts!
拟合变换适用于您要立即形成并使用您要拟合的对象的情况,这就是为什么当您的对象是模型时不常见,但当您使用 StandardScaler 或其他数据准备对象时却很常见。
构建时间序列预测管道的可扩展方法
以较少的工程负担解决更复杂的问题

https://unsplash.com/photos/WY70Ay0WHRg
这篇文章的目的和文章概述
写这篇文章的动机是分享如何构建工具来帮助定义 ML 管道以预测复杂过程的结果。
本文不是要解决一个具体的问题,而是要介绍一种提高工程师和数据科学家工作效率的方法(众多方法中的一种),这种方法是通过对重复性任务(如存储/检索特征、训练模型和从基本块构建管道)引入更高层次的抽象。
[免责声明]开源目前没有计划这个框架,但是,我希望下面描述的观点可能对社区有所帮助。
为了了解要解决的问题,我们将首先查看领域问题示例。然后将愿望清单定义到我们的工具箱中,并进行高级解决方案概述。接下来的章节将深入介绍该方法的各个方面。
问题示例
假设我们想要预测上市公司的净收入。虽然我们可能使用统计和最大似然法来预测净收入的最终值,但是让我们检查一下通过预测我们的目标所包含的变量是否可以提高准确性。以下是净收入计算的简化分类:

Decomposition of Net Income calculation (simplified)
其他可能有用的功能:
- 公司财务报告
- 宏观经济数据
- 行业趋势
- 竞争对手指标
根据过去的经验,我们知道我们希望:
- 进行重复的实验——当你试图重复一周前的好实验时,这是非常令人难过的
- 使用不同类型的 ML 模型
- 在另一个计算中引用一个计算的结果
- 有一个比较模型和实验结果的标准方法
- 有一个简单的方法来验证单元测试的功能
- 系综和堆栈模型
随着预测中使用的公司数量超过 5000 家,似乎有一种框架来帮助我们解决这个问题会很好。
框架概述
一个可能的解决方案是将问题表达为一个计算图(有向和无环),节点是处理步骤,边是依赖关系。
节点类型:
- 数据提供者(data Provider )-将数据纳入管线并创建一组初始特征
- 特征提取器-将一个或多个数据源作为输入并产生输出的任何操作。最常见的是数学运算或时移
- 统计/最大似然模型训练和预测
- 服务步骤,如生成指标或选择最佳模型以传递到下一步
每个计算步骤输出数据,这些数据被保存在一个共享的存储库中,如果需要,其他步骤可以从这里请求这些数据。

Forecast new feature from inputs and put into a repository
以下是净收入计算的明细:

Defining Net Income forecast as a graph
有一个框架来简化这些图的构造、执行并允许在另一个计算中使用一个计算的结果将是很好的。
高级需求
- 声明性和可测试的图形定义
- 惰性图形处理,仅重新计算缺失的特征
- 定义新计算类型的容易程度
- 支持特征和特征块元数据
- 支持时间序列和数据的关系性质
- [ML]内置交叉验证和堆叠
声明性计算图定义
计算的每一步都可以抽象为一个函数,它获取输入参数并输出数据。不同类型的运算(移动平均计算或差值计算)是不同的函数。无状态和幂等也是计算步骤的有用属性。
节点声明则是包含以下参数的容器:
- 将处理此工作单元的类名—提取器
- 如果不可用,则计算依赖项-输入要素
- 要处理的功能组的名称
以下是此类节点声明的示例,它计算功能组中所有功能的相对增长:
Computing relative growth of all input features
另一个将两个块链接在一起的例子是,假设我们想要计算过去的收益估计和预测收益之间的差异。要做到这一点,我们可以在第一个块中及时移动过去的收益估计,然后在另一个块中加入并计算相对差异:
Computing relative difference between variables shifted in time
需要机器学习训练的计算由稍微不同的块表示,其需要许多附加参数:
- 模型工厂名称
- 模型参数
- 目标变量名
Example of Training Configuration
这个处理步骤由工作流引擎以稍微不同的方式处理,具有交叉验证支持和按时间滚动训练。
将图声明从执行上下文中分离出来允许自动化测试和配置生成。
图形处理
定义了计算图后,只需将我们想要计算的特征传递给处理引擎就足够了,处理引擎随后会展开依赖关系,并只重新计算存储库中缺失的数据。
计算步骤的类型
数据提供者 —将不同种类的数据注入系统。提供商示例:
- 公司特有的功能—股票价格、季度报告
- 全国范围的数据—通货膨胀、国内生产总值
对特征进行一元运算
- 滚动窗口上的计算。示例—移动平均计算
- 时移
二元运算 —按时间和关键字连接两个特征并执行数学运算:
- 加入和减去。使用示例—通过从收入中减去成本得出营业收入
- 合而分之。使用示例—将收入与随时间转移的收入结合起来定义增长
- 加入并倍增。使用示例—将过去的收入与增长预测相结合,得出未来的收入
其他类型的服务步骤
- 选择前 N 名最佳功能预测
- 计算用于分析的预测质量指标
通过实现这样的基本块,然后组合成更高级的结构,可以定义相当复杂的逻辑。每种类型的特征提取器都是一个实现公共接口的类,在负责计算特征的组件中注册,并通过名称从图中引用。
功能元数据
保存与要素相关联的元数据也很方便-如果是未来预测、要素类型等,则该要素的直接父要素是什么。
有了这些元数据,就很容易找到某个特征的所有预测,计算它们的准确度,选择 N 个最佳预测,计算置信区间,并创建一个新的特征块供以后使用
支持时间序列和数据的关系性质
每一个计算步骤都会产生一些特征,这些特征被组合成一种特征块——特征库。
为了支持时序定位(要素可以按时间进行索引),为了支持关系(按关键字分组)。
例如,股票价格的每日变化将按天索引,并按股票代号(公司标识符)分组
块的描述和示例:

计算时,将特征块与从提取器名称和参数计算的关键字一起放入存储库中,不同的参数会导致不同的块名称。
在计算阶段,如果可用,从存储库中读取特征块,否则进行计算。
特征的顺序定位
为了支持序列不变算法(如决策树或回归)中的时间序列问题性质,常规特征存储(平面)被转换为序列的,其中要包括的时间步数是提取器的参数。
以下是微软季度收入和收入成本的一个例子:

Regular orientation
到顺序表示:

Sequential orientation
为了防止有关未来事件的信息泄漏到 ML 模型中,从传递到模型的要素视图中过滤掉元数据中具有 Seq 0 且不是预测的所有连续要素。
训练 ML 模型
该框架与不同 ML 模型的细节无关,所需要的只是实现一个标准接口。默认的训练模式是训练和预测时间滑动,在此期间,模型根据过去的事件{0:t-1}进行训练,以预测未来的事件{t}。在完成对周期{t}的所有预测后,训练数据将扩展到{0:t},并再次训练以预测{t + 1}

每个时间步长的训练被分成个 k 倍,保持集用于检测早期停止点(对于基于树的模型)和选择超参数:

My wife calls this Mattress split — looks like old Soviet mattress
尽管现在验证和预测集不是同分布,但这种分解足以检测过度拟合。
另一种经常用于执行快速实验的训练模式是所有事件的简单 k 倍分割。虽然这种方法并不完善,并且会导致关于未来事件的信息泄露,但是它已经被证明是默认训练模式的良好近似。
堆叠是通过对不同的模型一个接一个的排序来实现的。
结果评估和误差分析
有许多服务特征提取器,当放置在图中的 ML 模型之后时,可以将预测值与原始数据(标签)相关联,并产生不同种类的度量和结构以供进一步分析:
- 与其他模型相比,预测精度有所提高
- 预测区间
- 残差分析
- 自相关检查
- 正态分布检验
- 边缘校验

工作进展
自动图形构建
手动迭代可能的配置选项可能会耗费时间和精力。下一个逻辑步骤是将图形构造公式化为具有约束(例如计算时间)和优化目标(例如精度)的优化问题
调整解决方案以在多台机器上运行
框架中易于并行化的部分:
- 图形中孤立部分的处理
- 分层特征——我们可以将公司 A 的特征与公司 B 的特征分开计算
- 时间特征
我们在准确性方面有什么提高吗?
虽然这篇文章是关于一般的框架,而不是关于解决具体的预测问题,但我们仍然想知道与更简单的 ML 算法相比,结果是否有所改善?
答案是肯定的,对于所有要预测的变量来说,准确性都有相当大的提高。
以下是 awesome library Prophet 和 Pipeline models 预测公司(本例中为 ROST )的收入预测对比:

Earnings Per Share for POST ticker — Actual (Label), Prophet and Pipeline forecasts

POST Relative Error comparison
另一家随机公司 EBAY 的盈利预测

Earnings Per Share for EBAY — Actual (Label), Prophet and Pipeline forecasts

EBAY Relative Error comparison
结论
虽然这是一项相当重要的初始投资,但拥有一个类似于上述框架的框架可以:
- 缩短每次实验->验证->整合周期的时间
- 花在修复错误和编写测试上的时间更少
- 不同模型、超参数和特征对最终预测影响的整体观点
- 减少重复过去实验的时间
这个解决方案是从自动化和改进日常活动逐步发展而来的。如果需要从头实现这样一个框架,我也会考虑在现有开源技术的基础上构建,例如——https://airflow.apache.org
感谢您阅读这篇文章,我们非常欢迎您的反馈或对具体领域的更详细深入的要求。
使用 MinHash 和 Spark 的可扩展 Jaccard 相似性
一个简单的算法使得大规模计算相似矩阵变得容易得多。

不久前我想到,除了算术平均值之外,Jaccard 相似系数在我的作品中出现的次数可能比其他任何统计都多。如果你有两组事物(词、词的一部分、属性、类别或其他),你可以用集合交集中的事物数除以集合并集中的事物数。由此产生的度量是一个有意义的相似性度量,其额外的优点是非常容易向非技术人员解释。
Jaccard 相似性在规模上直接计算有点困难。如果您有一个非常大的实体-属性对列表,并且您想要一个逐个实体的相似性矩阵,您基本上必须执行一个内部连接,按实体分组并计数,然后执行一个外部连接,按实体分组并计数,然后将两个连接的结果连接在一起。如果你的工作流程使用 Spark,就像我的一样,那就是一大堆混乱。它是昂贵的。
不久前,一位同事给我指出了一件我觉得我应该知道但却不知道的事情: MinHash 。对于每个实体,随机排列属性,然后散列它们(将它们转换成整数),然后取最小值。这样做很多次,然后计算两个实体的相同绘制的最小灰度匹配的百分比。我们可以用解释这两个实体属性集之间的 Jaccard 相似性的方式来解释这个度量。所以它把问题从大量的属性归结为少量的散列;但是更好的是,它带来的问题从可变数量的属性——伴随着键偏斜的所有痛苦——到所有实体中相同数量的最小散列。
以下代码片段中从第 36 行到第 52 行的大部分内容都来自 Patrick Nicholson,他是我的同事,告诉我 MinHash 的事情,他改编了 Spark 的spark.ml.feature.MinHashLSH实现中的散列算法。我构建了连接逻辑,将 MinHash 结果转化为实际的 Jaccard 相似性,并将整个过程包装在一个函数中,使其更具可移植性。
该函数需要一个 Spark 数据帧,一个指示数据帧中包含节点标签的列的字符串(我们希望在它们之间找到相似性的实体),以及包含边的列(我们将散列的属性)。该函数输出一个包含两列节点标签的数据框——每列都有一个由suffixes关键字参数指定的后缀——以及 Jaccard 相似性。
随着抽牌次数的增加,Jaccard 的相似性变得更加精确。一百次绘制(下面代码中的默认值)给出的精度最高为 0.01。500 次抽奖的精确度高达 0.005。1000 次绘制的精度最高可达 0.001。你明白了。
在过去的几个月里,这个小东西为我节省了很多时间和麻烦。我觉得值得分享一下。
使用 Apache Spark 的可扩展日志分析—综合案例研究
半结构化数据的大规模数据分析和可视化

Photo by Robin Pierre on Unsplash
介绍
当今利用分析的最流行和最有效的企业案例研究之一是日志分析。如今,几乎每个小型和大型组织都有多个系统和基础架构日复一日地运行。为了有效地保持业务运营,组织需要知道其基础架构是否发挥了最大潜力。这包括分析系统和应用程序日志,甚至可能对日志数据应用预测分析。日志数据量通常很大,这取决于组织基础架构的类型以及在其上运行的应用程序。由于计算限制,我们只能尝试在单台机器上分析数据样本的日子已经一去不复返了。

Source: Doug Henschen
在大数据、更好的分布式计算、大数据处理和 Spark 等开源分析框架的支持下,我们可以每天对潜在的数百万甚至数十亿条日志消息执行可扩展的日志分析。本案例研究导向教程的目的是采用实践方法展示我们如何利用 Spark 对半结构化日志数据执行大规模日志分析。如果您对 Spark 的可伸缩 SQL 感兴趣,可以随意查看 Spark 的 SQL 和 Spark 的 。
今天,我们将在本文中讨论以下主要话题。
虽然有很多优秀的开源日志分析框架和工具,包括 elasticsearch,但本教程的目的是展示如何利用 Spark 来大规模分析日志。在现实世界中,当分析日志数据时,您可以自由选择工具箱。我们开始吧!
主要目标——NASA 日志分析
正如我们之前提到的,Apache Spark 是一个优秀的、理想的开源框架,用于大规模地对结构化和非结构化数据进行辩论、分析和建模!在本教程中,我们的主要目标是关注业界最流行的案例研究之一——日志分析。通常,服务器日志是企业中非常常见的数据源,通常包含可操作的见解和信息的金矿。企业中的日志数据有许多来源,如 web、客户端和计算服务器、应用程序、用户生成的内容、平面文件。它们可以用于监控服务器、提高业务和客户智能、构建推荐系统、欺诈检测等等。

Spark 允许您廉价地将日志转储和存储在磁盘上的文件中,同时仍然提供丰富的 API 来执行大规模的数据分析。这个动手案例研究将向您展示如何在 NASA 的真实生产日志上使用 Apache Spark,并学习数据争论和探索性数据分析中的基本而强大的技术。在本案例研究中,我们将分析来自佛罗里达州 NASA 肯尼迪航天中心 web 服务器的日志数据集。完整的数据集可以免费下载 这里 。
这两个数据集包含了两个月来对佛罗里达州 NASA 肯尼迪航天中心 WWW 服务器的所有 HTTP 请求。您可以前往 网站 并根据需要下载以下文件(或直接点击以下链接)。
- 07 月 01 日至 07 月 31 日,ASCII 格式,T0:ftp://ita.ee.lbl.gov/traces/NASA_access_log_Jul95.gz
- 04 年 8 月至 08 月 31 日,ASCII 格式,T1:ftp://ita.ee.lbl.gov/traces/NASA_access_log_Aug95.gz
确保这两个文件与包含教程的笔记本在同一个目录下,该教程可以在my GitHub上找到。
设置相关性
第一步是确保您能够访问 Spark 会话和集群。为此,您可以使用自己的本地设置或基于云的设置。一般来说,目前大多数云平台都会提供 Spark 集群,你也可以免费选择,包括 Databricks 社区版。本教程假设您已经有了 Spark 设置,因此我们不会花费额外的时间从头开始配置或设置 Spark。
通常,当您启动 jupyter 笔记本服务器时,预先配置的 Spark 设置已经预先加载了必要的环境变量或依赖项。在我的情况下,我可以使用笔记本中的以下命令来检查它们。
**spark**

这表明我的集群目前运行的是 Spark 2.4.0。我们还可以使用下面的代码检查**sqlContext** 是否存在。
**sqlContext****#Output:
<pyspark.sql.context.SQLContext at 0x7fb1577b6400>**
现在,如果您没有预先配置这些变量并得到一个错误,您可以加载它们并使用下面的代码配置它们。除此之外,我们还加载了一些其他库来处理数据帧和正则表达式。
使用正则表达式将是解析日志文件的主要方面之一。正则表达式是一种非常强大的模式匹配技术,可用于提取和发现半结构化和非结构化数据中的模式。

Source: xkcd
正则表达式可能非常有效和强大,但它们有时可能令人不知所措或困惑。不过不要担心,通过更多的练习,你可以真正发挥它的最大潜力。以下示例展示了在 Python 中使用正则表达式的方法。
**<_sre.SRE_Match object; span=(0, 25), match="I'm searching for a spark"> 0 25
<_sre.SRE_Match object; span=(25, 36), match=' in PySpark'> 25 36**
让我们进入分析的下一部分。
加载和查看 NASA 日志数据集
假设我们的数据存储在下面提到的路径中(以平面文件的形式),让我们将它加载到 DataFrame 中。我们会一步一步来。下面的代码获取我们磁盘中的日志数据文件名。
**['NASA_access_log_Jul95.gz', 'NASA_access_log_Aug95.gz']**
现在,我们将使用**sqlContext.read.text()**或**spark.read.text()**来读取文本文件。这将产生一个 DataFrame,其中有一个名为**value**的字符串列。
**root
|-- value: string (nullable = true)**
这使我们可以看到日志数据的模式,它看起来很像文本数据,我们将很快对其进行检查。您可以使用下面的代码查看保存日志数据的数据结构的类型。
**type(base_df)****#Output:**
**pyspark.sql.dataframe.DataFrame**
我们将在整个教程中使用 Spark 数据帧。但是,如果您愿意,也可以将数据帧转换为 RDD,即 Spark 的原始数据结构(弹性分布式数据集)。
**base_df_rdd = base_df.rdd
type(base_df_rdd)****#Output
pyspark.rdd.RDD**
现在让我们看一下数据帧中的实际日志数据。
**base_df.show(10, truncate=False)**

这肯定看起来像半结构化的标准服务器日志数据,我们肯定需要做一些数据处理和争论,然后才能有用。请记住,从 rdd 访问数据与下面看到的略有不同。
**base_df_rdd.take(10)**

现在我们已经加载并查看了日志数据,让我们来处理和讨论它。
数据争论
在这一节中,我们将尝试清理和解析我们的日志数据集,以真正从每个日志消息中提取具有有意义信息的结构化属性。
日志数据理解
如果您熟悉 web 服务器日志,您会发现上面显示的数据是以通用日志格式显示的。
这些字段是:**remotehost rfc931 authuser [date] "request" status bytes**
我们将需要使用一些特定的技术来从日志数据中解析、匹配和提取这些属性。
用正则表达式解析和提取数据
接下来,我们必须将半结构化日志数据解析成单独的列。我们将使用特殊的内置[**regexp_extract()**](http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.functions.regexp_extract)函数来进行解析。该函数将一列与一个或多个捕获组的正则表达式进行匹配,并允许您提取一个匹配的组。我们将为希望提取的每个字段使用一个正则表达式。
到目前为止,您一定听说过或使用过相当多的正则表达式。如果您发现正则表达式令人困惑(它们当然也可能困惑),并且您想了解更多关于它们的知识,我们建议查看一下 RegexOne 网站。你可能还会发现 Goyvaerts 和 Levithan 的 正则表达式手册 作为参考很有用。
让我们看看我们在数据集中处理的日志总数。
**print((base_df.count(), len(base_df.columns)))****#Output
(3461613, 1)**
看起来我们总共有大约 346 万条日志消息。不是一个小数目!让我们摘录并查看一些示例日志消息。

提取主机名
让我们尝试编写一些正则表达式来从日志中提取主机名。
**['199.72.81.55',
'unicomp6.unicomp.net',
'199.120.110.21',
'burger.letters.com',
...,
...,
'unicomp6.unicomp.net',
'd104.aa.net',
'd104.aa.net']**
提取时间戳
现在让我们尝试使用正则表达式从日志中提取时间戳字段
**['01/Jul/1995:00:00:01 -0400',
'01/Jul/1995:00:00:06 -0400',
'01/Jul/1995:00:00:09 -0400',
...,
...,
'01/Jul/1995:00:00:14 -0400',
'01/Jul/1995:00:00:15 -0400',
'01/Jul/1995:00:00:15 -0400']**
提取 HTTP 请求方法、URIs 和协议
现在让我们尝试使用正则表达式从日志中提取 HTTP 请求方法、URIs 和协议模式字段。
**[('GET', '/history/apollo/', 'HTTP/1.0'),
('GET', '/shuttle/countdown/', 'HTTP/1.0'),
...,
...,
('GET', '/shuttle/countdown/count.gif', 'HTTP/1.0'),
('GET', '/images/NASA-logosmall.gif', 'HTTP/1.0')]**
提取 HTTP 状态代码
现在让我们尝试使用正则表达式从日志中提取 HTTP 状态代码。
**['200', '200', '200', '304', ..., '200', '200']**
正在提取 HTTP 响应内容大小
现在让我们尝试使用正则表达式从日志中提取 HTTP 响应内容大小。
**['6245', '3985', '4085', '0', ..., '1204', '40310', '786']**
把所有的放在一起
现在让我们尝试利用我们之前构建的所有正则表达式模式,并使用**regexp_extract(...)**方法来构建我们的数据帧,将所有日志属性整齐地提取到它们自己的单独列中。

查找缺失值
缺失值和空值是数据分析和机器学习的祸根。让我们看看我们的数据解析和提取逻辑工作得有多好。首先,让我们验证原始数据帧中没有空行。
**0**
一切都好!现在,如果我们的数据解析和提取工作正常,我们不应该有任何可能为空值的行。让我们来测试一下吧!
**33905**
哎哟!看起来我们的数据中有超过 33K 个丢失的值!我们能处理这件事吗?
请记住,这不是一个常规的 pandas 数据框架,您可以直接查询并获得哪些列为空。我们所谓的大数据集驻留在磁盘上,它可能存在于 spark 集群的多个节点中。那么我们如何找出哪些列有潜在的空值呢?
查找空计数
我们通常可以使用下面的技术来找出哪些列有空值。
(注:此方法改编自 StackOverflow 上的一个精彩回答。)

嗯,看起来我们在**status** 列中少了一个值,其他的都在**content_size**列中。让我们看看是否能找出问题所在!
在 HTTP 状态下处理空值
我们最初解析status列的正则表达式是:
**regexp_extract('value', r'\s(\d{3})\s', 1).cast('integer')
.alias( 'status')**
会不会是数字多了让我们的正则表达式错了?还是数据点本身不好?让我们试着找出答案吧!
注:在下面的表达式中,**~**的意思是“不是”。
**1**
我们来看看这个不良记录是什么样的!
**null_status_df.show(truncate=False)**

看起来像是有很多缺失信息的记录!让我们通过我们的日志数据解析管道来传递它。

看起来记录本身是一条不完整的记录,没有任何有用的信息,最好的选择是删除这条记录,如下所示!

处理 HTTP 内容大小中的空值
基于我们之前的正则表达式,我们对**content_size** 列的原始解析正则表达式为:
**regexp_extract('value', r'\s(\d+)$', 1).cast('integer')
.alias('content_size')**
我们的原始数据集本身会有缺失的数据吗?让我们试着找出答案吧!我们首先尝试找出基本数据帧中可能缺少内容大小的记录。
**33905**
该数量似乎与我们处理的数据帧中缺失的内容大小值的数量相匹配。让我们来看看数据框中缺失内容大小的前十条记录。
**null_content_size_df.take(10)**

很明显,坏的原始数据记录对应于错误响应,没有内容被发回,服务器为**content_size**字段发出一个“**-**”。
因为我们不想从分析中丢弃这些行,所以让我们将它们估算或填充为 0。
修复 content_size 为空的行
最简单的解决方案是像我们之前讨论的那样用 0 替换**logs_df**中的空值。Spark DataFrame API 提供了一组专门用于处理空值的函数和字段,其中包括:
[**fillna()**](http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrame.fillna),用指定的非空值填充空值。[**na**](http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrame.na),它返回一个[**DataFrameNaFunctions**](http://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrameNaFunctions)对象,该对象具有许多用于操作空列的函数。
有几种方法可以调用这个函数。最简单的方法是用已知值替换所有的空列。但是,为了安全起见,最好传递一个包含**(column_name, value)**映射的 Python 字典。这就是我们要做的。文档中的一个示例如下所示
**>>> df4.na.fill({'age': 50, 'name': 'unknown'}).show()
+---+------+-------+
|age|height| name|
+---+------+-------+
| 10| 80| Alice|
| 5| null| Bob|
| 50| null| Tom|
| 50| null|unknown|
+---+------+-------+**
现在我们使用这个函数,用 0 填充**content_size**字段中所有缺失的值!

看看,没有丢失值!
处理时态字段(时间戳)
现在我们有了一个干净的、解析过的数据帧,我们必须将时间戳字段解析成一个实际的时间戳。通用日志格式时间有些不标准。用户定义的函数(UDF)是解析它最直接的方法。
现在让我们使用这个函数来解析 dataframe 中的**time**列。

事情看起来不错!让我们通过检查数据帧的模式来验证这一点。
**logs_df.printSchema()****root
|-- host: string (nullable = true)
|-- method: string (nullable = true)
|-- endpoint: string (nullable = true)
|-- protocol: string (nullable = true)
|-- status: integer (nullable = true)
|-- content_size: integer (nullable = false)
|-- time: timestamp (nullable = true)**
现在让我们缓存**logs_df**,因为我们将在下一部分的数据分析部分广泛使用它!
**logs_df.cache()**
对我们的网络日志进行数据分析
现在我们有了一个数据帧,其中包含了作为数据帧的经过解析和清理的日志文件,我们可以执行一些有趣的探索性数据分析(EDA)来尝试获得一些有趣的见解!
内容大小统计
让我们计算一些关于 web 服务器返回的内容大小的统计数据。特别是,我们想知道平均、最小和最大内容大小是多少。
我们可以通过调用**logs_df**的**content_size**列上的**.describe()**来计算统计数据。**.describe()**函数返回给定列的计数、平均值、标准偏差、最小值和最大值。

或者,我们可以使用 SQL 直接计算这些统计数据。您可以在文档的**pyspark.sql.functions**模块中探索许多有用的功能。
在我们应用了**.agg()**函数之后,我们调用**toPandas()**来提取结果并将其转换成一个**pandas**数据帧,这个数据帧在 Jupyter 笔记本上有更好的格式。

我们可以验证结果,看它们是否和预期的一样。
HTTP 状态代码分析
接下来,让我们看看日志中出现的状态代码值。我们想知道哪些状态代码值出现在数据中,出现了多少次。我们再次从**logs_df**开始,然后按**status** 列分组,应用**.count()**聚合函数,并按**status** 列排序。
**Total distinct HTTP Status Codes: 8**
看起来我们总共有 8 个不同的 HTTP 状态代码。让我们以频率表的形式来看看它们的出现情况。

看起来状态代码 200 OK 是最常见的代码,这是一个很好的迹象,表明大部分时间工作正常。让我们想象一下。

HTTP Status Code occurrences
不算太差!但是由于数据中的巨大偏差,几个状态代码几乎不可见。让我们进行一次对数变换,看看情况是否有所改善。

结果肯定看起来不错,似乎已经处理了偏斜,让我们通过可视化这些数据来验证这一点。

HTTP Status Code occurrences — Log Transformed
这绝对看起来更好,更少歪斜!
分析频繁主机
让我们看看频繁访问服务器的主机。我们将尝试获得每个**host** 的总访问次数,然后按次数排序,只显示前十个最频繁的主机。

这看起来不错,但是让我们更仔细地检查第 9 行中的空白记录。
**host_sum_pd_df = host_sum_df.toPandas()
host_sum_pd_df.iloc[8]['host']****''**
看起来我们有一些空字符串作为顶级主机名之一!这给我们上了宝贵的一课,不仅要检查空值,还要在数据冲突时检查潜在的空字符串。
显示前 20 个常用端点
现在,让我们来看看日志中对端点(URIs)的点击数。为了执行这个任务,我们从我们的**logs_df** 开始,按**endpoint**列分组,按计数聚合,并像上一个问题一样按降序排序。

毫不奇怪,gif、主页和一些 CGI 脚本似乎是最常被访问的资产。
十大错误终点
请求的没有返回代码 200 (HTTP 状态正常)的前十个端点是什么?我们创建一个排序列表,其中包含端点和它们被访问的次数,返回代码不为 200,并显示前十名。

看起来 gif(动画\静态图像)加载失败最多。你知道为什么吗?考虑到这些日志是 1995 年的,考虑到当时的网速,我一点也不惊讶!
唯一主机的总数
在这两个月中,访问 NASA 网站的独特主机的总数是多少?我们可以通过几个变换找到这个答案。
**137933**
每日唯一主机的数量
作为一个高级示例,我们来看一种方法,它可以每天确定整个日志中唯一主机的数量。该计算将为我们提供每日唯一主机的数量。
我们希望有一个数据帧,按月中增加的一天排序,其中包括一个月中的一天,以及这一天的唯一主机的相关数量。
考虑一下您需要执行哪些步骤来计算每天发出请求的不同主机的数量。由于日志仅涵盖一个月,您可以忽略该月。您可能想要使用**pyspark.sql.functions**模块中的[**dayofmonth**](https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.functions.dayofmonth) 功能(我们已经将其作为**F**导入)。
**host_day_df** : 有两列的数据帧

对于**logs_df**中的每一行,该数据帧中将有一行。本质上,我们只是在变换**logs_df**的每一行。例如,对于**logs_df**中的这一行:
**unicomp6.unicomp.net - - [01/Aug/1995:00:35:41 -0400] "GET /shuttle/missions/sts-73/news HTTP/1.0" 302 -**
你的**host_day_df** 应该有:**unicomp6.unicomp.net 1**

**host_day_distinct_df** : 该数据帧具有与**host_day_df**相同的列,但删除了重复的 ( **day** , **host** ) 行。

**daily_unique_hosts_df** : 有两列的数据帧:


这为我们提供了一个很好的数据框架,显示了每天唯一主机的总数。让我们想象一下!

Unique Hosts per Day
每台主机的平均每日请求数
在前面的示例中,我们研究了一种方法来确定每天整个日志中唯一主机的数量。现在让我们试着根据我们的日志找出每台主机每天向 NASA 网站发出的平均请求数。我们希望有一个数据帧,按一个月中增加的日期排序,包括一个月中的某一天,以及每台主机在这一天发出的平均请求数。

我们现在可以直观地看到每台主机的平均每日请求。

Average Daily Requests per Host
看起来第 13 天每个主机的请求数达到了最大值。
统计 404 个响应代码
创建一个只包含带有 404 状态代码(未找到)的日志记录的数据帧。我们确保**cache()**``**not_found_df**数据帧,因为我们将在这里的其余示例中使用它。你觉得日志里有多少 404 记录?
**Total 404 responses: 20899**
列出前二十个 404 响应代码端点
使用我们之前缓存的仅包含带有 404 响应代码的日志记录的数据帧,我们现在将打印出生成最多 404 错误的前 20 个端点的列表。记住,顶部端点应该是有序的。

列出前二十个 404 响应代码主机
使用我们之前缓存的仅包含带有 404 响应代码的日志记录的数据帧,我们现在将打印出生成最多 404 错误的前 20 台主机的列表。请记住,顶级主机应该按顺序排列。

给了我们一个好主意,哪个主机最终为 NASA 网页产生了最多的 404 错误。
每天可视化 404 个错误
现在让我们暂时(按时间)探索我们的 404 记录。类似于显示每日唯一主机数量的示例,我们将按天分解 404 个请求,并在**errors_by_date_sorted_df**中按天排序每日计数。

现在让我们想象一下每天总共有 404 个错误。

Total 404 Error per Day
404 错误的前三天
根据前面的情节,一个月中出现 404 错误最多的前三天是哪三天?为此,我们可以利用我们之前创建的**errors_by_date_sorted_df**。

可视化每小时 404 次错误
使用我们之前缓存的 DataFrame **not_found_df** ,我们现在将按照一天中的小时以升序进行分组和排序,以创建一个 DataFrame,其中包含一天中每个小时(午夜从 0 开始)对 HTTP 请求的 404 个响应的总数。然后,我们将从数据帧构建一个可视化。

Total 404 Error per Hour
看起来 404 错误在下午最多,在凌晨最少。我们现在可以将 pandas 显示的最大行数重置为默认值,因为我们之前已经将其更改为显示有限的行数。
**pd.set_option('max_rows', def_mr)**
结论
我们在一个关于日志分析的非常常见但重要的案例研究中,采取了动手操作的方法来进行大规模的数据争论、解析、分析和可视化。虽然从规模或数量的角度来看,我们在这里处理的数据可能不是传统意义上的“大数据”,但这些技术和方法足够通用,可以扩展到更大数量的数据。我希望这个案例研究能够让您很好地了解如何轻松地利用 Apache Spark 这样的开源框架来处理大规模的结构化和半结构化数据!
本文附带的所有代码和分析都可以在 我的 GitHub 资源库 中找到。
你可以在这个 Jupyter 笔记本 里找到一步一步的方法。
我利用数据科学、人工智能、机器学习和深度学习来解决现实世界的问题。我也在业余时间做一些咨询、研究和指导。如果您需要集中咨询、培训课程,希望我在活动中发言,或者如果您想发表一篇关于TDS*的文章,请随时通过LinkedIn联系我。*****
*** [## Dipanjan Sarkar -数据科学家-红帽| LinkedIn
查看 Dipanjan Sarkar 在世界最大的职业社区 LinkedIn 上的个人资料。Dipanjan 有 9 份工作列在…
www.linkedin.com](https://www.linkedin.com/in/dipanzan/)***
带有熊猫 UDF 的可伸缩 Python 代码:一个数据科学应用

Source: https://pxhere.com/en/photo/1417846
让 Python 代码在云中大规模运行
PySpark 是一个非常强大的工具,因为它能够编写可以从单台机器扩展到大型集群的 Python 代码。虽然 MLlib 等库很好地覆盖了数据科学家可能希望在这种环境中执行的标准任务,但 Python 库提供的大量功能并不适合在这种分布式环境中工作。虽然像koala这样的库应该可以更容易地将 Python 库移植到 PySpark,但是在开发人员希望在可伸缩运行时中应用的库集和支持分布式执行的库集之间仍然存在差距。这篇文章讨论了如何使用 Spark 2.3+中的熊猫 UDF提供的功能来弥合这一差距。
我遇到了熊猫 UDF,因为我在 Zynga 开发的一个项目需要一种扩大自动化特征工程的方法。我们有几十个具有不同事件分类的游戏,需要一种自动化的方法来为不同的模型生成功能。计划是使用功能工具库来执行这个任务,但是我们面临的挑战是它只能在一台机器上处理熊猫。我们的用例需要扩展到大型集群,我们需要以并行和分布式模式运行 Python 库。我能够在 2019 年 Spark 峰会上展示我们实现这一规模的方法。
我们采用的方法是首先使用数据样本在 Spark 集群中的驱动程序节点上执行任务,然后使用 Pandas UDFs 扩展到完整的数据集,以处理数十亿条数据记录。我们在建模流程中的特征生成步骤中使用了这种方法。这种方法还可以应用于数据科学工作流中的不同步骤,也可以用于数据科学以外的领域。在 Medium 上的以下帖子中,我们将深入探讨我们的方法:
自动化几十个游戏的预测模型
medium.com](https://medium.com/zynga-engineering/portfolio-scale-machine-learning-at-zynga-bda8e29ee561)
这篇文章介绍了一个例子,在这个例子中,Pandas UDFs 用于按比例增加批量预测管道的模型应用步骤,但是 UDF 的用例比这篇博客中介绍的要广泛得多。
数据科学应用
熊猫 UDF 可用于数据科学的各种应用,从特征生成到统计测试到分布式模型应用。然而,这种扩展 Python 的方法并不局限于数据科学,而是可以应用于各种各样的领域,只要您可以将数据编码为数据框,并且可以将任务划分为子问题。为了演示如何使用 Pandas UDFs 来扩展 Python 代码,我们将通过一个示例,在这个示例中,使用批处理来创建购买模型的可能性,首先使用单台机器,然后使用集群来扩展到潜在的数十亿条记录。这篇文章的完整源代码可以在 github 上获得,我们将使用的库预装在 Databricks 社区版上。
我们笔记本中的第一步是加载我们将用来执行分布式模型应用程序的库。我们需要 Pandas 来加载数据集并实现用户定义的函数,需要 sklearn 来构建分类模型,需要 pyspark 库来定义 UDF。
接下来,我们将加载一个数据集来构建分类模型。在这个代码片段中,使用 Pandas read_csv函数将一个 CSV 文件急切地提取到内存中,然后转换成 Spark 数据帧。该代码还为每条记录附加了一个唯一的 ID,以及一个分区 ID,用于在使用 PDF 时分发数据帧。
这一步的输出如下表所示。Spark 数据帧是记录的集合,其中每个记录指定用户以前是否购买过目录中的一组游戏,标签指定用户是否购买了新的游戏版本,user_id 和 parition _ id 字段是使用上面代码片段中的 spark sql 语句生成的。

我们现在有了一个 Spark 数据框架,可以用来执行建模任务。然而,在这个例子中,我们将重点关注在将数据集样本拉至驱动程序节点时可以执行的任务。当运行toPandas()命令时,整个数据帧被急切地提取到驱动程序节点的存储器中。对于这个例子来说,这很好,因为我们正在处理一个小的数据集。但是在使用 toPandas 函数之前,最好对数据集进行采样。一旦我们将数据框拉到驱动节点,我们就可以使用 sklearn 来构建逻辑回归模型。
只要您的完整数据集能够放入内存,您就可以使用下图所示的单机方法对应用程序进行建模,将 sklearn 模型应用于新的数据框。但是,如果您需要对数百万或数十亿条记录进行评分,那么这种单机方法可能会失败。
这一步的结果是用户 id 和模型预测的数据框。

在笔记本的最后一步,我们将使用熊猫 UDF 来缩放模型应用程序流程。我们可以使用 Pandas UDFs 在 spark 集群中分发数据集,并使用 pyarrow 在 Spark 和 Pandas 数据框表示之间进行转换,而不是将整个数据集放入驱动程序节点的内存中。结果与上面的代码片段相同,但在这种情况下,数据帧分布在集群中的工作节点上,任务在集群上并行执行。
结果和以前一样,但是现在计算已经从驱动程序节点转移到一个工作节点集群。这个过程的输入和输出是一个火花数据帧,即使我们使用熊猫在我们的 UDF 内执行任务。

要了解更多关于建立熊猫 UDF 的细节,请查看我之前发布的关于使用 PySpark 的帖子。
PySpark 是一种很棒的语言,可以进行大规模的探索性数据分析,构建机器学习管道,以及…
towardsdatascience.com](/a-brief-introduction-to-pyspark-ff4284701873)
这是一个介绍,展示了如何将 sklearn 处理从 Spark 集群中的驱动节点转移到工作节点。我还使用该功能来扩展 Featuretools 库,以处理数十亿条记录并创建数百个预测模型。
结论
Pandas UDFs 是一个使 Python 代码能够在分布式环境中运行的特性,即使该库是为单节点执行开发的。数据科学家在构建可伸缩数据管道时可以受益于这一功能,但是许多不同领域也可以受益于这一新功能。我提供了一个批处理模型应用程序的例子,并链接到一个使用 Pandas UDFs 进行自动特征生成的项目。UDF 的许多应用还没有被探索,Python 开发人员现在可以使用新的计算规模。
本·韦伯是 T2 Zynga 公司的杰出科学家,也是 T4 恶作剧公司的顾问。
使用 Scikit-Learn 进行扩展、标准化或规范化
何时使用最小最大缩放器、鲁棒缩放器、标准缩放器和规格化器
当要素处于相对相似的规模并且接近正态分布时,许多机器学习算法会工作得更好。 MinMaxScaler 、 RobustScaler 、 StandardScaler 和 Normalizer 是 scikit-learn 方法,用于为机器学习预处理数据。您需要哪种方法(如果有)取决于您的模型类型和特征值。
本指南将重点介绍这些方法之间的差异和相似之处,并帮助您了解何时使用哪种工具。

Scales
这些方法经常出现在机器学习工作流中,我发现很难找到关于何时使用哪种方法的信息。评论员经常交替使用术语标度、标准化和正常化。然而,它们也有一些不同之处,我们将研究的四个 scikit-learn 函数做不同的事情。
首先,请注意以下几点:
- 这篇文章所基于的 Jupyter 笔记本可以在这里找到。
- 在本文中,我们不考虑对数变换或其他旨在减少误差异方差的变换。
- 本指南自 scikit-learn v0.20.3 起生效。
这些术语是什么意思?
缩放一般是指改变数值的范围。分布的形状不会改变。想想一个建筑的比例模型是如何与原始模型具有相同的比例,只是比例更小。这就是为什么我们说它是按比例绘制的。该范围通常设置为 0 到 1。
标准化通常是指改变数值,使分布的 标准 偏差等于 1。缩放通常是隐含的。
Normalize 可以用来表示以上任何一种(以及更多!).我建议你避免使用术语 normalize,,因为它有很多定义,容易造成混淆。
如果你在交流中使用这些术语,我强烈建议你定义它们。
为什么要扩展、标准化或规范化?
当特征处于相对相似的规模和/或接近正态分布时,许多机器学习算法执行得更好或收敛得更快。这种算法族的例子包括:
- 线性和逻辑回归
- 最近的邻居
- 神经网络
- 具有径向偏向核函数的支持向量机
- 主成分分析
- 线性判别分析
缩放和标准化可以帮助这些算法以更易理解的形式获得特性。
我们正在检查的四个 scikit-learn 预处理方法遵循如下所示的 API。 X_train 和 X_test 是通常的数字数组或熊猫数据帧。
from sklearn import preprocessingmm_scaler = preprocessing.MinMaxScaler()
X_train_minmax = mm_scaler.fit_transform(X_train)mm_scaler.transform(X_test)
我们将查看一些发行版,并对它们应用四种 scikit-learn 方法中的每一种。
原始资料
我创建了四个具有不同特征的发行版。这些分布是:
- 贝塔——负偏斜
- 指数——正偏斜
- 轻微型 —正常,轻微型
- 板状软骨 —正常,板状软骨
- 双峰 —双峰
这些值都具有相对相似的比例,如下面的内核密度估计图(kdeplot)的 x 轴所示。

然后我添加了第六个分布,它有更大的值(正态分布)——正态。
现在我们的 kdeplot 看起来像这样:

仔细看显示器,你可能会注意到右边有一个绿色的大数值小条。这是我们特征的描述性统计数据。

好吧,让我们开始缩放!
最小最大缩放器
对于特性中的每个值,最小最大值缩放器减去特性中的最小值,然后除以范围。该范围是原始最大值和原始最小值之间的差值。
MinMaxScaler 保留原始分布的形状。它不会有意义地改变嵌入在原始数据中的信息。
注意,MinMaxScaler 不会降低异常值的重要性。
MinMaxScaler 返回的特征的默认范围是 0 到 1。
下面是应用 MinMaxScaler 后的 kdeplot。

请注意这些特征是如何以相同的相对比例呈现的。每个要素值之间的相对间距保持不变。
MinMaxScaler 是一个不错的起点,除非您知道您希望您的要素具有正态分布,或者您有异常值,并且您希望它们具有较小的影响。


Different types of scales
鲁棒定标器
RobustScaler 通过减去中值,然后除以四分位数范围(75%值-25%值)来转换特征向量。

像 MinMaxScaler 一样,我们的具有大值的特征—normal—big—现在与其他特征具有相似的比例。请注意,RobustScaler 不像 MinMaxScaler 那样将数据缩放到预定的间隔。它不符合我前面介绍的规模的严格定义。
请注意,应用 RobustScaler 后,各功能的范围比应用 MinMaxScaler 时更大。
相对于最小最大缩放器,如果要减少异常值的影响,请使用鲁棒缩放器。
现在让我们转向 StandardScaler。
标准缩放器
StandardScaler 是业界公认的算法。🙂
标准缩放器通过减去平均值然后缩放至单位方差来标准化特征。单位方差是指所有值除以标准偏差。StandardScaler 不符合我前面介绍的标度的严格定义。
StandardScaler 产生标准差等于 1 的分布。方差也等于 1,因为方差=标准差的平方。而 1 的平方= 1。
StandardScaler 使分布的平均值约为 0。

在上图中,你可以看到所有四个分布都有一个接近于零的平均值和单位方差。这些值的比例相似,但范围比 MinMaxScaler 之后的更大。
深度学习算法通常要求零均值和单位方差。回归型算法也受益于小样本的正态分布数据。
现在让我们看看规格化器。
标准化者
规格化器作用于行,而不是列!我觉得这很不直观。在文档中很容易遗漏这些信息。
默认情况下,L2 归一化应用于每个观测值,以便一行中的值具有单位范数。具有 L2 的单位范数意味着如果每个元素被平方并求和,则总和等于 1。或者,可以应用 L1(又名出租车或曼哈顿)归一化来代替 L2 归一化。

Normalizer 确实将所有特征转换为-1 和 1 之间的值(此文本更新于 2019 年 7 月)。在我们的示例中, normal_big 的所有值都转换为. 9999999。
你找到 Normalizer 的好用例了吗?如果有,请在 Twitter @discdiver 上告诉我。
在大多数情况下,上面的其他预处理工具会更有帮助。
同样,scikit-learn 的规格化器作用于行,而不是列。
比较
以下是应用最小最大缩放器、鲁棒缩放器和标准缩放器之前和之后的原始分布图。

请注意,在这三种变换中的任何一种变换之后,这些值的比例都是相似的。🎉
包装
扩展和标准化您的数据通常是一个好主意。我强烈建议在将数据输入深度学习算法之前,使用标准缩放器,或者使用依赖于观察相对距离的算法,或者使用 L2 正则化的算法。请注意,标准缩放会使回归系数的解释变得有点棘手。😉
小贴士:
- 如果希望每个要素都具有零均值、单位标准差,请使用 StandardScaler。如果您想要更多正态分布的数据,并且愿意转换您的数据。查看 scikit-learn 的
[QuantileTransformer(output_distribution='normal')](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.QuantileTransformer.html)。 - 如果你想轻触,使用 MinMaxScaler。它不失真。
- 如果您有异常值并希望减少它们的影响,您可以使用 RobustScaler。
- 谨慎使用规格化器——它规格化样本行,而不是特征列。它可以使用 l2 或 l1 归一化。
这里有一个我在谷歌表单中做的备忘单,帮助你保持选项的直线性:

在本文中,您看到了 scikit-learn 如何帮助您对数据进行缩放、标准化和规范化。* * 我在 2021 年 8 月更新了这篇文章的图片和一些文字。感谢读者的反馈!**
深入研究的资源:
- 这里有一个关于预处理数据的 scikit-learn 文档。
- 这是另一篇关于 sci kit-learn scaler 对异常值的影响的文档。
- 肖恩·欧文为概率分布提供了一个很好的指导。
- 这是 Ben Alex Keen 的另一个比较这些功能的指南。
我希望这个指南对你有所帮助。如果你有,请分享到你最喜欢的社交媒体频道。👏
我写关于 Python 、 Docker 、 SQL 、熊猫以及其他数据科学主题。如果你对这些话题感兴趣,阅读更多这里并关注我的 Medium。😃
Scale on!
为机器学习工作流扩展 Apache 气流
了解如何在云上轻松执行 Airflow 任务,并获得每个机器学习任务的自动版本控制。

Apache Airflow 是一个用 Python 创建、调度和监控工作流的流行平台。它在 Github 上有超过 15k 颗星,被 Twitter、Airbnb 和 Spotify 等公司的数据工程师使用。
如果您使用的是 Apache Airflow,那么您的架构可能已经根据任务的数量及其需求进行了改进。在 Skillup.co 工作时,我们首先有几百个 Dag 来执行我们所有的数据工程任务。然后我们开始做机器学习。
我们希望继续使用气流来编排机器学习管道,但我们很快意识到我们需要一种解决方案来远程执行机器学习任务。
在本文中,我们将看到:
- 在气流中扩展工作节点的不同策略。
- 机器学习任务与传统 ETL 管道的不同之处。
- 如何在云上轻松执行气流任务?
- 如何获得每个机器学习任务的自动版本控制?
使用执行器扩展 Apache 气流
Apache Airflow 具有基于调度器、工作节点、元数据数据库、web 服务器和队列服务的多节点架构。

Example Airflow architecture.
使用气流时的首选之一是执行器的类型。执行器与调度器通信,在任务排队时为每个任务分配资源。遗嘱执行人之间的区别在于他们拥有的资源。
顺序执行者
默认的执行器使得在本地测试气流变得很容易。它在一台机器上顺序运行任务,并使用 SQLite 存储任务的元数据。
本地执行者
本地执行器可以并行运行任务,并且需要像 PostgreSQL 这样支持并行性的数据库。虽然您可以在生产环境中运行本地执行器,但通常会迁移到 Celery executor 来提高可用性和可伸缩性。
芹菜执行者
Celery executor 要求设置 Redis 或 RabbitMQ 来向工作人员分发消息。气流然后将任务分配给芹菜工人,他们可以在一台或多台机器上运行。这是我们在 Skillup.co 使用的执行器,能够运行多达 256 个并发数据工程任务。
库伯内特遗嘱执行人
Kubernetes 执行器为每个任务实例创建一个新的 pod。它允许您根据任务需求动态地伸缩。
与运营商一起扩展 Apache 气流
另一种扩展气流的方法是让操作员远程执行一些任务。2018 年,杰西卡·拉夫林认为我们都在错误地使用气流,正确的方法是只使用 Kubernetes 算子。她认为应该有一个单一的无 bug 操作符来执行任意任务,而不是一个不断增长的特定功能操作符列表。
Kubernetes 算子
Kubernetes 操作员将在一个新的 pod 中启动一个任务。当您有一组需要定期运行的任务时,我发现只对有特定需求的任务使用 Kubernetes 操作符是一个更好的主意。
我认为 Kubernetes 操作符的主要问题是,您仍然需要理解 Kubernetes 配置系统并设置一个集群。例如,Dailymotion 在谷歌 Kubernetes 引擎上的一个集群中部署了 Airflow,并决定通过 KubernetesPodOperator 来扩展 Airflow 用于机器学习任务。
在我们的案例中,我们是一个小型数据团队,几乎没有资源来建立一个 Kubernetes 集群。我们希望专注于构建机器学习模型,而不是管理基础设施。
机器学习任务与 ETL 任务有何不同?
在 Skillup.co,我们不得不作为一个小团队在一年内构建和部署几个数据产品。我们知道我们想要使用开源库来构建我们的模型,从经典的机器学习模型到深度学习。我们也在寻找一个机器学习平台来帮助我们扩展和版本控制我们所有的模型。
Airflow 在跟踪元数据数据库中的每个任务细节方面做得很好,但机器学习任务与 ETL 任务有不同的要求。机器学习任务与数据、代码、环境、参数和指标相关联。这些信息不是由气流收集和显示的。Kubernetes 只在基础设施方面帮助你。
在一个地方收集每次执行的所有相关信息有助于调试机器学习模型。在下表中,你可以看到我们跟踪的信息,以更快地迭代机器学习模型。

Important information for machine learning version control.
我们对扩展机器学习任务的选择
你已经可以找到几个像谷歌数据流,亚马逊 SageMaker 和 Databricks 这样的机器学习平台的气流运营商。这些操作符的问题在于,它们都有不同的规范,并且仅限于在这些平台上执行代码。
在我们开始在 Skillup.co 做任何机器学习之前,我们将 Airflow 用于所有数据工程,这些工程主要由 Airflow BashOperator 调用的 Python CLIs 组成。
然后我们决定使用 Valohai ,一个基于开放标准构建的机器学习平台,帮助我们远程启动机器学习任务,并获得自动版本控制。
拥有一个混合解决方案使我们能够将敏感数据保存在我们的 Airflow 装置中,并将机器学习委托给 Valohai。

Machine learning workflow with an Airflow DAG. Blue tasks are executed remotely thanks to Valohai.
感谢 Valohai 的开放 API ,我们开发了开源的 airflow-valohai-plugin 来整合两个平台。去年,我们用它在生产中发布了四个机器学习模型。
瓦罗海算子
Valohai 运算符背后的思想类似于 Kubernetes 运算符。好处是你不需要理解 Kubernetes,你也可以获得机器学习的自动版本控制。
Valohai 将根据您的需求、代码和数据启动和停止云实例。Valohai 操作符只是在 Docker 容器中执行一个命令,轮询它的完成情况并返回最终的状态代码。
通过提供 Docker 映像和您的代码库,您可以执行任何语言和库的代码。你还可以访问 AWS、Google 和 Azure 中的 50 多个云环境。
要创建一个关于 Airflow 的任务,您只需要指定要执行的 Valohai 项目和步骤。如果需要,您还可以覆盖默认的云环境、输入和参数。
Sample code to submit an execution to Valohai from Airflow [source].
另一方面,您需要通过创建 valohai.yaml 在 Valohai 端进行一些简单的配置。 valohai.yaml 作为一个配置文件来设置默认值,并验证机器环境、docker 映像、要运行的命令、参数和每次执行的输入数据文件。
从一开始就拥有机器版本控制有助于我们调试数据、代码和参数,从而更快地进行预测和修复。就像你希望你的气流任务是幂等的,以避免重新启动它们时的副作用一样,你希望你的机器学习模型基于代码和数据的审计版本。如果您总是使用存储在数据湖中的文件来训练您的模型,这很容易做到。下面你可以在 Valohai UI 中看到一个执行的解析配置。

Valohai UI with execution details [source code].
Valohai 建立在两个明智的选择之上,这两个选择使得它可以很容易地与任何编程语言和库集成。
首先,选择一个对所有编程语言通用的 CLI 优先接口。CLI 是一个流行的接口,用来包装您的函数,以便在本地执行它们。CLI 也是 Bash、Kubernetes 和 Valohai 操作符的接口。
第二,从标准输出中收集执行指标,而不是为每种语言安装一个定制的库。所有语言都有将 JSON 对象写入标准输出的工具。Valohai 将自动解析该对象,例如,帮助您比较每个模型的准确性。

Valohai UI to compare execution’s parameters and accuracy.
您还可以在 Valohai UI 中手动启动执行,而不会有任何副作用。在 Airflow 中,清除一个任务的状态将触发下游任务。
最后但同样重要的是,新的 Valohai 操作符允许您轻松地将一次执行的输出作为下一次执行的输入。这帮助我们创建了管道,数据在 S3 上自动版本化。此外,每个新的执行都在与 S3 bucket 相同的云提供商和区域上运行,这使得 Valohai 可以快速地将它下载到 AWS EC2 实例上。
结论
Apache Airflow 是创建、调度和监控工作流的强大工具,但它是为 ETL 任务而构建的。机器学习任务需要特定的资源,并且它们的执行细节应该受到版本控制。
如果你有资源来维护一个 Kubernetes 集群,你可以用 KubernetesPodOperator 来扩展机器学习任务。
如果你想专注于建立模型,你可以用ValohaiSubmitExecutionOperator来缩放用于机器学习任务的气流。通过这种方式,您还可以通过 Valohai 获得每次执行的自动版本控制。
有用的资源
从 0 到数百万用户扩展机器学习—第 1 部分
突破笔记本电脑
我认为大多数机器学习(ML)模型都是在白板或餐巾纸上构思出来的,诞生于笔记本电脑上。当这些羽翼未丰的生物开始咿咿呀呀地说出它们的第一个预言时,我们充满了自豪,并对它们未来的能力寄予厚望。唉,我们内心深处知道,并非所有人都会成功,远非如此。
当我们建造它们时,一小部分很快就让我们失望了。其他的看起来很有希望,并显示出一定程度的预测能力。然后,我们面临着在生产环境中部署它们的严峻挑战,在生产环境中,它们要么证明自己传奇的勇气,要么不光彩地死去。

One day, your models will rule the world… if you read all these posts and pay attention 😉
在这一系列观点鲜明的帖子中,我们将讨论如何训练 ML 模型并将其部署到生产中,从卑微的开始到统治世界。在这一过程中,我们将努力采取公正合理的措施,与过度设计、炒作驱动的开发以及“为什么不直接用 XYZ 呢?”的邪恶势力作斗争。
尽可能享受您的数据科学沙盒的安全舒适,并为寒冷、严酷的生产世界做好准备。
第 0 天
所以你想建立一个 ML 模型。嗯。让我们停下来想一想:
- 你的业务问题能否由的高级 AWS 服务解决,比如亚马逊认证、亚马逊 Polly 等。?
- 还是通过嵌入在其他 AWS 服务中的不断增长的应用 ML 特性列表?
不要对此置之不理:没有机器学习比没有机器学习更容易管理。找到一种使用高级服务的方法可以为你节省几周甚至几个月的时间。
如果答案是“是”
请扪心自问:
- 为什么您要费尽周折构建一个冗余的定制解决方案呢?
- 你真的是“缺失功能”吗?什么是真正的业务影响?
- 你真的需要“更高的精确度”你怎么知道你能达到呢?
如果你不确定,为什么不用你自己的数据进行一次快速概念验证呢?这些服务是完全托管的(不需要…更多…服务器),并且非常容易集成到任何应用程序中。弄清楚它们不需要花太多时间,然后你就会有可靠的数据来做出有根据的决定,决定你是否真的需要训练你自己的模型。
如果这些服务对你来说足够好,那么恭喜你,你基本上完成了!如果你决定建造,我希望听到你的反馈。请保持联系。
如果这个答案是“否”
请再问自己一次这个问题!我们大多数人都有扭曲现实和欺骗自己的惊人能力:)如果诚实的答案真的是“不”,那么我仍然建议考虑一下您可以使用高级服务的子流程,例如:
- 使用 Amazon 翻译支持的语言对,并使用您自己的解决方案来翻译其余的语言对。
- 在将人脸输入到你的模型之前,使用亚马逊的识别功能来检测人脸,
- 使用 Amazon Textract 来提取文本,然后将其提供给 NLP 模型。
这不是推销 AWS 服务(我看起来像销售人员吗?).我只是想让你免于重新发明轮子(或轮子的部件):你真的应该专注于手头的业务问题,而不是建造你在博客帖子中读到的或在会议上看到的卡片房子。是的,它在你的简历上可能看起来很棒,这个轮子最初是一个有趣的旋转木马…然后,它变成了痛苦之轮,你被拴在它上面,别人拿着鞭子。

Why did I blindly trust that meetup talk? Crom! Help me escape and bash that guy’s skull with his laptop.
反正消极够了:)你确实需要一个模型,我们继续吧。
第一天:一个用户(你)
我们将从您在本地机器(或本地开发服务器)上训练模型的阶段开始我们的旅程,使用流行的开源库,如 scikit-learn 、 TensorFlow 或 Apache MXNet 。也许你甚至已经实现了自己的算法(数据科学家,你们这些魔鬼)。
您已经使用测试集测量了模型的准确性,情况看起来不错。现在您想要将模型部署到生产中,以便检查它的实际行为,运行 A/B 测试,等等。从哪里开始?
批量预测还是实时预测?
首先,您应该弄清楚您的应用程序是否需要批量预测(即收集大量数据点,定期处理它们并将结果存储在某个地方),或者实时预测(即向 web 服务发送一个数据点并接收一个即时预测)。我之所以提前提出这一点,是因为它对部署复杂性有很大的影响。
乍一看,实时预测听起来更有吸引力(因为…实时,耶!),但它也带来了 web 服务固有的更强的需求:高可用性、处理流量突发的能力等。批处理更加轻松,因为它只需要时不时地运行:只要不丢失数据,没有人会看到它是否在中间被破坏了;)
缩放现在不是一个问题:您关心的只是部署您的模型、测试轮胎、运行一些性能测试等等。从我的经验来看,您可能选择了最短的路线,将所有东西部署到一个 Amazon EC2 实例。每个人都知道一点 Linux CLI,你在某处读到过使用“IaaS 将保护你免受邪恶的供应商锁定”。哈!那就 EC2 吧!
我听到 AWS 时空连续体中充满恐惧和怀疑的尖叫声,也许还有一些类似“哦,这太愚蠢了,没有人真的这么做!”。嗯,我敢打赌,到目前为止,大多数人都是这样开始的。如果你没有,恭喜你,但是请让我告诉这些好人,在他们真正伤害自己之前,哪条路是出路;)
所以,盯着我的魔镜,我看到…
批量预测
您已经将模型、批处理脚本和应用程序复制到 EC2 实例中。您的批处理脚本作为 cron 作业定期运行,并将预测数据保存到本地存储。您的应用程序在启动时加载模型和初始预测数据,并使用它来做任何它必须做的事情。它还会定期检查更新的预测,并在它们可用时加载它们。
实时预测
您已经将模型嵌入到应用程序中,在启动时加载它,并使用各种数据(用户输入、文件、API 等)提供预测。).
不管怎样,你现在正在云中运行预测,生活是美好的。你用一品脱黑啤酒来庆祝…或者可能是无麸质、公平交易的有机豆奶拿铁,因为毕竟是 2019 年了。
第一周:一个抱歉的用户(你)
该模型预测得很好,并且您希望投入更多时间来收集更多数据和添加功能。不幸的是,没过多久事情就变糟了,你现在陷入了各种各样的问题(下面是不完整的列表):
- 在您的笔记本电脑上进行培训并手动部署到云是一件痛苦且容易出错的事情。
- 您意外地终止了 EC2 实例,不得不从头开始重新安装。
- 你' pip 安装了-Python 库,现在你的 EC2 实例全乱了。
- 您必须为您的同事手动安装另外两个实例,现在您真的不能确定你们都在使用相同的环境。
- 您的第一个负载测试失败了,但是您不确定应该归咎于什么:应用程序?模特?阴间的古人巫师?
- 您希望在 TensorFlow 中实现相同的算法,也许在 Apache MXNet 中也是如此:更多的环境,更多的部署。没时间了。
- 当然还有大家的最爱:销售听说“你的产品现在有 AI 能力了”。你害怕他们会把它卖给一个客户,然后让你下周去大规模现场。
这样的例子不胜枚举。如果不是真的会很搞笑(欢迎在评论里补充自己的例子)。突然之间,这个 ML 的冒险听起来不那么令人兴奋了,不是吗?你将大部分时间花在救火上,而不是建立最好的模型上。不能这样下去了!

I’ve revoked your IAM credentials on ‘TerminateInstances’. Yes, even in the dev account. Any questions?
第 2 周:反击
团队中有人观看了这个非常酷的 AWS 视频,其中展示了一个名为亚马逊 SageMaker 的新 ML 服务。您记住了这一点,但是现在,没有时间重新构建一切:销售人员正紧盯着您,几天后您有一个客户演示,您需要强化现有的解决方案。
很有可能,你还没有堆积如山的数据:训练可以等等。你需要专注于让预测变得可靠。这里有一些可靠的技术措施,实施起来不会超过几天。
使用深度学习 AMI
由 AWS 维护的这个亚马逊机器映像带有预装的许多你可能需要的工具和库:开源、NVIDIA 驱动程序等。不必管理它们将为您节省大量时间,并且还将保证您的多个实例以相同的设置运行。
AMI 还附带了 Conda 依赖和环境管理器,它可以让您快速轻松地创建许多隔离的环境:这是一个用不同的 Python 版本或不同的库测试您的代码的好方法,而不会意外地破坏一切。
最后但同样重要的是,这个 AMI 是免费的,就像任何其他 AMI 一样,如果你真的有必要,你可以定制。
打破巨石
您的应用程序代码和您的预测代码有不同的需求。除非你有令人信服的理由这样做(超低延迟可能是一个),否则它们不应该生活在同一个屋檐下。让我们来看一些原因:
- 部署:每次更新模型都要重启或者更新 app 吗?或者 ping 你的应用程序重新加载它或其他什么?不不不,保持简单:说到解耦,没有什么比构建独立的服务更好的了。
- 性能:如果您的应用程序代码在内存密集型实例上运行得最好,而您的 ML 模型需要 GPU,该怎么办?你将如何处理这种权衡?你为什么会偏爱其中一个?将它们分开让你为每个用例挑选最佳的实例类型。
- 可伸缩性:如果您的应用程序代码和您的模型具有不同的可伸缩性配置文件,那该怎么办?在 GPU 实例上横向扩展是一种耻辱,因为您的一小部分应用程序代码正在热运行…同样,最好将事情分开,这将有助于采取最适当的扩展决策以及降低成本。
那么,预处理/后处理代码呢,也就是说,你需要在预测之前和之后对数据采取的行动。它该何去何从?很难给出一个明确的答案:我会说独立于模型的动作(格式化、日志记录等)。)应该留在应用程序中,而依赖于模型的动作(特征工程)应该靠近模型以避免部署不一致。
构建预测服务
将预测代码从应用程序代码中分离出来并不一定很痛苦,您可以重用可靠的、可扩展的工具来构建预测服务。让我们来看看一些选项:
- Scikit-learn :说到用 Python 构建 web 服务,我是 Flask 的忠实粉丝。它整洁、简单并且可伸缩性好。不用再找了。你的代码应该是这样的。
# My awesome API
from flask import Flask
import pickleapp = Flask(__name__)
model = pickle.load(open("my_awesome_model.sav", 'rb'))
...
@app.route('/predict', methods=['POST'])
def predict():
# Grab data from the HTTP request
...
model.predict(...)
...
- 张量流:不需要编码!您可以使用tensor flow Serving来提供大规模预测。一旦训练好模型并将其保存为正确的格式,为预测服务所需要做的就是:
docker run -p 8500:8500 \
--mount type=bind,source=/tmp/myModel,target=/models/myModel \
-e MODEL_NAME=myModel -t tensorflow/serving &
- Apache MXNet :同样的,Apache MXNet 提供了一个 模型服务器,能够服务 MXNet 和 ONNX 模型(后者是 PyTorch、Caffe2 等支持的常用格式)。它既可以作为独立的应用程序运行,也可以在 Docker 容器中运行。
两个模型服务器都预装在深度学习 AMI: 这是使用它的另一个原因。为了简单起见,您可以将您的前/后处理留在应用程序中,并调用由模型服务器部署的模型。但是,有一个警告:这些模型服务器既不实现认证也不实现节流,所以请确保不要将它们直接暴露给互联网流量。
- 还有什么:如果你正在使用另一个环境(比如定制代码)或者非 web 架构(比如消息传递),同样的模式应该适用:构建一个可以独立部署和扩展的独立服务。
(可选)容器化您的应用程序
既然你已经决定拆分你的代码,我强烈建议你利用这个机会将不同的部分打包到 Docker 容器中:一个用于训练,一个用于预测,一个(或多个)用于应用。这个阶段严格来说没有必要,但是如果你能抽出时间,我相信过早的投资是值得的。
如果你一直生活在岩石下,或者从未真正关注过容器,现在可能是赶上的时候了:)我强烈推荐运行 Docker 教程,它将教你为了我们的目的需要知道的一切。
容器使得跨不同环境(开发、测试、生产等)移动代码变得容易。)和实例。它们解决了各种依赖问题,即使您只管理少量实例,这些问题也会突然出现。随后,容器也将成为 Docker clusters 或 Amazon SageMaker 等大型解决方案的先决条件。
第二周结束
经过一个艰难的开始,事情正在好转!
- 深度学习 AMI 提供了一个稳定的、维护良好的基础。
- 容器帮助您移动和部署您的应用程序,比以前少了很多基础设施。
- 预测现在存在于您的应用程序之外,使得测试、部署和扩展更加简单。
- 如果您可以使用它们,模型服务器将为您省去编写预测服务的大部分麻烦。
不过,不要太激动。是的,我们回到了正轨,并准备好做更大的事情,但仍有大量的工作要做。那么对多个实例的伸缩预测、 高可用性、管理成本等呢?当堆积如山的训练数据开始堆积时,我们该怎么办?面对现实吧,我们仅仅触及了表面。
“老傻瓜!负载平衡器!自动缩放!自动化!“我听到你的哭声。哦,你是说你又急着管理基础设施了?我以为你们想要机器学习。)
这个重磅炸弹,是时候收工了。在下一篇中,我们将开始比较和挑战更大规模 ML 培训的选项:EC2vsECS/EKSvsSageMaker。一场史诗般的战斗,毫无疑问。
感谢阅读。同意吗?不同意?太好了!乐于在此讨论或在 Twitter 上讨论。
有史以来最佳电影配乐。是的,魔戒团契只排第二:)
将 Transformer-XL 扩展至 128 个 GPU
本·曼,雅罗斯拉夫·布拉托夫,大流士·拉姆
TL;DR: 我们在 AWS 上的 128 个 GPU 上高效地进行了 Transformer-XL 训练。该代码可在https://github.com/cybertronai/transformer-xl获得

We achieved almost linear throughput scaling on AWS p3dn.24xlarge instances with 8 V100–32GB each on a 100Gbps network
概观
研究语言模型的困难之一是,你通常不知道你的想法是否可行,直到你在真实世界的数据集上尝试它们。然而,在一台机器上对这样的数据集进行训练可能需要数周时间。
幸运的是,有一个简单的方法可以加速这个过程:
- 找一个好的单机型号
- 在 N 台机器上并行运行模型的 N 个副本,每一步都要同步
- 解决所有剩余的技术挑战
我们使用这个方法将 ImageNet 培训时间从 2 周减少到 18 分钟。您还可以应用相同的优化在 2 周内训练一个模型,这原本需要 4 年,因此您可以选择扩大您的研究范围,而不是迭代时间。
通过几分钟的训练,图像模型训练“基本上解决了”,而语言模型训练时间仍然是创新的障碍。我们的目标是看看通过在云中分布我们的培训,我们可以增加多少培训吞吐量。
对于单机模型,我们选定了 Transformer-XL 的正式实现。这种体系结构在语言建模方面取得了几项最先进的成果。作者通过发布代码和指令,使得重现他们的结果变得很容易。
一旦我们在他们的自述文件中重现了准确性,我们就迭代性能,在不影响质量的情况下获得大约 2.6 倍的吞吐量提升。
然后,我们将这个模型扩展到在多台机器上训练,使用 all-reduce 来同步梯度。分布式语言模型每一步发送的数据至少比典型的图像模型多 10 倍,因此我们使用 AWS p3dn 实例来实现 100 Gbps 的网络连接。这些实例有 32GB 的 GPU 内存,因此我们能够通过增加每个 GPU 的批处理大小来将培训效率再提高 25%。最终结果是:一个 64 GPU 版本的 small Transformer-XL 模型的训练速度比原来“慢”的 4 GPU 实现快 44 倍。我们的 Transformer-XL 具有 75M 参数(相当于论文中的 186M),在 128 GPUss 上的训练速度比在 8 GPU 上快 13.2 倍。
训练程序需要改变,以防止更大批量的数值发散,所以我们遵循谷歌在他们的 1024 TPU 缩放论文中提供的配方。我们在一个独立的回购中开源了这个优化器。
技术细节
资料组
我们主要用 Wikitext-103 进行实验,这是一个由维基百科的预标记子集组成的标准语言建模数据集。训练集在 515MB 中包含大约 1 亿个标记和 267K 个唯一单词。它使用了修改过的摩西记号化,用< UNK >符号替换 0.4%的单词来限制 vocab 的大小。Transformer-XL 代码库在训练开始时将整个数据集加载到 GPU 内存中。
为了在训练时加快速度,我们对数据集进行了预编码,并将它们放入 AWS 磁盘映像中。
基础设施
我们已经自动化了许多常见的任务,这些任务来自于分布式培训系统的原型设计,并将它们打包成一个工具 ncluster 。其理念是任何频繁的任务都应该是单一的命令行调用。一些例子:
- 提出一些实例,以现货价格进行测试
- 修复一个错误,并在 30 秒内重新启动多机实验。
- 登录到最近的机器,看看它在做什么
- 保持远程计算机上的文件夹与本地文件夹同步
- 登录到另一个用户的计算机来解决问题
以太网
我们尝试了各种网络配置来寻找可以优化吞吐量的设置。运行 iperf3 测试,我们可以看到机器之间的吞吐量为 93 Gbps,而 NCCL all-reduce 性能下降到大约 50 Gbps 的。AWS 网络设置的一个特点是每个网络流量被限制在大约 10 Gbps,因此我们使用多个 NCCL 环来支持多个流量。由于 NCCL 最新版本中的一个错误,我们不得不恢复到旧版本,旧版本支持多个流,但是没有有效地利用带宽。特别是,随着我们增加 GPU 的数量,传输的字节量增加了 4 倍,这是像 ring-allreduce 这样的带宽恒定算法所没有预料到的。然而,当我们让 LAMB 工作并且我们的本地批处理大小达到 32GB RAM 的饱和时,我们的网络需求下降得足够多,即使每台机器的通信负载过大,我们也没有达到带宽限制。
在某个时候,我们注意到我们最高效的带宽运行表现不佳,性能下降了 30%(见左下图)。一些调查显示,过于接近内存限制会导致 CUDA 缓存分配器反复耗尽内存,并在垃圾收集期间导致额外的同步(下图)。解决方案是通过降低批处理大小来稍微减少内存使用,这样问题就消失了。

Left: backwards time in ms, right: torch.cuda.memory_cached()
我们发现运行之间存在一些吞吐量差异。例如,一个不幸运的 64 GPU 运行将需要 2.5 分钟来完成 wt103 的一个纪元,而一个“幸运的”128 GPU 运行可以在 1 分钟内完成。我们认为这是由于 AWS 集群放置组是近似的:AWS 试图将放置组中的所有实例放置到本地连接的配置或“砖”上,但当这不可能时,一些实例将溢出到相邻的砖。
混合精度
依靠 16 位精度,我们可以利用 Volta TensorCores 减少内存使用,提高处理速度。我们测试了两种形式的 fp16 训练——纯 fp16 和混合精度训练。在纯 fp16 模式下,所有操作的精度都会降低。我们无法匹配纯 fp16 中的准确性数字,因为训练会很快变得不稳定。
在混合精度训练中,我们在 fp32 中保留一个权重的主副本,并在每个优化器步骤中对该主副本进行更新,然后将权重转换为 fp16,以便向前传递。这使我们能够在节省空间的同时保持精度。动态损耗缩放增加了传播的梯度信息量,同时保持了数值稳定性。为了实现这些,我们使用了 NVidia 开发的 Apex 和威震天包中的代码。
在合成实验中,我们发现张量核没有被完全激活,除非维度是 8 的倍数。

Figure 1: Time to multiply n x n matrices. Orange is fp32, blue is fp16. The Y axis shows log seconds averaged over three runs.
使用 tensorcores,fp16 矩阵乘法对于大的 n 几乎快 10 倍。注意,对于小的 n ,使用半精度带来的性能提升可以忽略不计。

Figure 2: However, when n is shifted by one, so that n is not a multiple of 8, fp16 performs equally with fp32, ie there is no performance increase at all and we simply save memory.
通过修改模型大小,我们能够显著提高速度,从最初的 1.2 倍提高到 2 倍,方法是转换为混合精度并增加批量大小。
小绵羊
LAMB optimizer 使用了这是一个简单的调整,据说它允许学习率随着工人的全局批量大小而线性增长。LAMB 将每个参数的学习率乘以权重(r1)的范数与 Adam 步骤(r2)的范数之比(r)。
如何解释下面的左图:Y 轴显示处理的令牌数的时间步长,第一个在顶部。X 轴是直方图桶,例如 N 个样本的值在 0 和 1、1 和 2 之间,等等。Z 轴是网络中每个参数值的直方图频率,例如 X%的图层权重落在 0 到 1 的范围内。你可以把它想象成每个时间步长的一个直方图,按时间堆叠,这样我们就可以看到直方图是如何随时间变化的。右图显示了相同的数据,但显示为面积图。颜色越深意味着越多的直方图柱在阴影区域中具有值,X 轴是时间,Y 轴是值(例如 r1 的权重的范数)。

大多数参数权重(r1)始终接近 0,但一些会增长和扩散,一些会变得相当大(最大 6.5 桶)

亚当步长规范(r2)在开始时非常大,但很快稳定在 0 到 0.5 之间。

上述两个影响导致信任比(r)促使一些参数长时间持续增长,在剪辑值为 10 时达到最大值。
在我们的测试中,我们发现 LAMB 甚至在一台全局批量为 768 的 p3dn . 24x 大型机器上也产生了影响,而 Adam 立即出现了分歧。我们还发现,我们可以完全消除学习速率计划中的预热,因为在训练开始时,梯度很大,这导致 LAMB 信任比很小,并降低了最不稳定层的学习速率。
也就是说,我们没有看到兰姆论文描述的线性缩放。他们没有公布他们的代码,甚至没有公布他们的超参数的细节,所以需要什么来使这个工作仍然有待观察。
字节对编码与自适应嵌入
Wikitext-103 的 vocab 大小为 267K,这需要很大的模型空间来表示。我们尝试切换到字节对编码(BPE),这在机器翻译中已经显示出了性能优势。我们使用 OpenAI 的 BPT 实现,因为它可以处理超出词汇表的序列。
Transformer-XL 有一个非常大的 vocab 大小(267K),所以大多数参数都在令牌嵌入中。我们能够使用 vocab 大小为 50K 的 BPE 来减少模型大小,这将我们的小模型配置从 186M 减少到 75M 参数,同时具有相同的表示能力。最初的 Transformer-XL 代码使用自适应输入和 softmax 来减少嵌入大小。
一个稍微棘手的细节是,BPE 产生的标记比 Wikitext-103 长 15%。这是意料之中的,因为 Wikitext-103 已经被标记化了(比如把“不”分成“不”。如果不是这样,BPE 可能会把“不”作为一个单独的标记来处理,而 Wikitext-103 的标记器会把它分开。在 BPE,通过将字符分割成单独的字节,将词汇表以外的单词分解成词汇表中的子单词片段,即使是 unicode 也是如此。这种行为是标记化长度增加 15%的原因。
在我们的消融研究中,我们发现,在考虑标记化长度后,以每个标记的训练损失衡量的性能几乎相同。由于模型规模更小,每秒令牌数增加了约 10%,而对于相同的批处理规模,GPU 利用率显著下降,从约 90%降至约 55%。这意味着当我们扩展到更大的模型时,我们可以保持每个 GPU 更高的批处理大小。
为了公平起见,我们还在大型模型配置上将 BPE 与自适应嵌入进行了比较:

为了验证困惑进行转换是 math . exp(math . log(26.25)* 1950/1699)= 42.5,所以令人印象深刻的等价(尽管上面看起来不一样)!尽管我们使用的 BPE 编码是在网络的一般样本(OpenAI 的网络文本数据集)上训练的,而不是在我们的训练集 Wikitext-103 上训练的。
这两种技术是兼容的,所以将它们结合起来可能会很有趣。也就是说,由于 BPE 如此灵活,代码也更简单,我们倾向于在未来的实验中只使用它。
学习率探测器
在 fast.ai part 2 中了解到这个想法后,Ben 很兴奋地看到它的工作。亚当的情况很好:

上图的最小值恰好就是文中用到的学习率(0.00025)!我们只需要运行几分钟就可以发现这一点,这比传统的完整超参数搜索要便宜得多,在传统的完整超参数搜索中,您将使用您打算稍后使用的单个 LR 时间表运行至少一个时期。
当应用于兰姆时,发现者明显高估了学习率。

灰色曲线最小损失处的学习率为 0.0263;橙色(使用重量衰减 1e-4)为 0.0435。但是当我们以 0.01 的学习率运行它时,它仍然发散。我们不得不一直降到 0.005,以获得稳定的收敛。我们认为这是因为 LAMB 导致实际的每层学习率在训练的不同时间差异很大,导致学习率查找器不在分布范围内。我们或许可以通过运行学习率查找器更长时间来解决这个问题,或者在训练中的一个检查点上。相反,我们选择做一个更传统的学习率超参数搜索。
批量缩放
在我们的许多实验中,我们发现当我们通过使用更多的 GPU 来增加全局批量时,收敛速度在短期内会下降。为了试验这种效果,我们尝试在单台机器上调度批量大小。我们发现,尽管这在短期内有所帮助,但随着我们训练时间的延长,这种好处消失了。

对初始收敛速度增加的一个解释是,我们在不同的批量中使用了恒定的学习速率,这导致了每个例子的学习速率更高。最后蓝色和灰色线之间的差距约为 1 亿个令牌(1 小时),因此它确实有大约 10%的帮助,即使我们没有使用整个 GPU 容量。

然而,如果我们保持基本学习速率不变,并应用线性学习速率缩放来调整不同批量的学习速率,则训练会发散。

对这些影响的更原则性的解释可能来自于梯度噪声标度。可以通过将工人批次中的梯度范数与全局批次中的梯度进行比较来估计噪声等级。在训练开始时或对于小数据集,噪声尺度较小,因此高温(η/B)训练更快。随着损耗的减少,我们需要降低温度来继续训练。
所有的维基百科
下图显示了 Wikitext-103 上大模型配置的训练损失与验证损失。你可以在下面的图表中看到,在仅仅 8 亿个令牌(1.5 小时)中,我们的验证损失停止下降,这表明我们过度拟合了数据集。

出于这个原因,我们很高兴尝试在 NVIDIA 的所有维基百科转储上进行培训,这比 Wikitext-103 大 25 倍。
- 它是 12GB 的文本,所以我们不能将它全部加载到 GPU 内存中
- 它被存储为 JSON,所以首先需要在保持文章边界的情况下将其扁平化
- 它包含任意的唯一标记,所以需要一些技巧来限制 vocab 的大小
幸运的是,Transformer-XL 已经包含了一个用于 10 亿单词语料库的多文件数据加载器,所以只需要一点点按摩就可以让它工作了。请注意,因为标记化不同,所以不应比较损失数字。下面,我们展示了使用 64 个 GPU 在所有维基百科上以每小时约 6 亿个令牌的速度运行两次。我们发现验证损失对学习速率非常敏感。

在进一步的实验中,我们发现在不降低学习率的情况下,损失并没有减少。我们将继续试验学习率计划以提高性能。我很想尝试的一种方法是波动-耗散关系,它试图动态降低学习率。
结论
我们已经展示了如何在 Transformer-XL 的小型配置上,通过使用
- AWS 100Gbps 网络
- Pytorch 的分布式数据并行+ NCCL
- BPE
- 小绵羊
- 混合精度
我们进行了数百次实验来提高收敛速度。到目前为止,我们还没有在标准基准测试中击败最先进的技术。也就是说,我们的高通量使我们能够以同样的成本更快地进行实验。我们还在用 spot 实例进行实验,这对于运行一个小时或更短时间的实验开始变得可行。
你是在做 AWS 的语言建模研究吗?试试我们的代码库,让我们知道你的想法!
承认
这项工作是以下各方共同努力的结果
Ben —数据管道、LAMB、参数搜索和调整
Darius —使用混合精确训练在单机模型上实现 2 倍加速
Yaroslav —实验基础设施、分布式训练
另外感谢 AWS 提供计算资源。
数字时代的稀缺
焦点
如何分配 21 世纪最重要的资源
稀缺。这是我们必须做出决定的原因。我们不能拥有一切。尽管菜单上摆满了令人垂涎的菜肴,但我们知道我们(通常)不可能把它们都吃光。稀缺资源的其他例子是金钱、时间和精力。在本文中,我介绍了另一种稀缺资源,它的分配可能需要您的一些关注。

FOCUS
创新不能欺骗我们的大脑
我们的大脑以不同的方式关注我们周围的世界。我们可以有选择地关注一个单独的观察。这需要主动忽略其他干扰物。我们也可以对多种输入给予不同的关注。
最近,我们正在处理比过去更多的感官输入。我们的生活变得如此简单,而我们的大脑似乎比以往任何时候都更忙碌。推荐系统确切地知道展示什么来引起我们的注意。
认知的下一步:记忆
当我们确实关注某些感官输入时,目标是 处理 这个并从中获得一些价值。这里的价值可以是娱乐性的,也可以是知识性的。尽管如此,信息过载使处理变得更加复杂。

Screens, notifications, we are always ‘ON’
信息过载与我们的大脑
因此,接收信息和处理信息都需要集中注意力。我们接触到的信息量越来越多,这就增加了我们关注焦点的需求。与此同时,我们不能简单地“增加”我们的关注。可以通过几种方法来提高注意力。然而,这并不容易,也不是无限的。这种不断增加的需求和固定的供给使我们专注于一种 稀缺 良好。
如何找到稀缺商品的最优配置?
在经济学中,商品的最优配置是通过设定一个单位的附加值等于一个单位的附加成本来计算的。出现的问题是,焦点的 值 是什么?这无法用货币单位来衡量。专注带来进步和思维清晰,它帮助你完成任务。

Be guided by your values through the forest of information!
从为什么开始
以西蒙·西内克为例,我们从为什么开始。‘你为什么要关注 x?’。为了衡量专注的价值,我看的是完成我所专注的任务的价值。是学习我感兴趣的东西吗?朝着我的个人或商业目标努力?
价值观,兴趣,目标…
如果这些话让你畏缩,我很抱歉。这些概念对我来说也不算什么。然而,我决定认真对待它,并参加了“个人领导力”课程。发现我的个人价值,并将这些与我的兴趣和目标联系起来,帮助我专注于对我来说重要的事情。

Think deeply, then act.
采取行动
无处可逃。尽管我建议花时间仔细思考你的价值观、兴趣和目标。你必须采取行动。采取行动将在两个方面帮助你进步:
- 你前进
- 你重新调整
要么你通过从经验、导师或课程中学习来提高,要么你意识到你必须做出调整。两者都向前迈进了一步。
那么,如何分配你的注意力,战胜信息过载呢?
一旦你知道你需要什么样的输入,你就可以扭转这个故事,利用信息过载。利用你对自己需求和匮乏的意识,明智地使用你的注意力。

The solution is in the problem
工业化信息处理
总结这篇文章,大量的数据让我们的注意力变得麻木。我们被娱乐、信息、社交信息等淹没了。所有这些输入都需要处理,而我们的认知过程无法处理。
信息处理是数据科学的全部内容。数据科学是将大量数据转化为有洞察力的信息的方法。最大的困难是让社会承认和使用数据科学。
一旦我们的社会变得有数据素养,我们就可以使用聚类和降维等技术来为我们处理信息。我们也可以建立模型来模拟势不可挡的过程。一旦这样的模型适合,我们可以调整输入来分析单一事件,而不是一次全部。
呼唤数据科学的场景
好莱坞恐怖片如何激励我们关注产生可衡量结果的问题

数据科学家充满好奇心、创造力和足智多谋。他们来自不同的背景,他们能够在平凡的事物中发现奇迹。他们不断地问为什么和如果会怎样,并在这个过程中找到乐趣。有时这些问题会产生有趣的结果,但是有趣并不意味着有影响。如果数据科学家想要证明他们工作的价值,他们需要偶尔强调其影响。他们必须将他们的好奇心应用到能够产生可测量结果的场景中。他们必须关注迫切需要数据科学的场景。
这些场景看起来像什么?
开始识别它们的一个好方法是寻找具有以下特征的属性:
- 系统设计固有的和任意分配的。就像网页上的推荐位置。如果有任何推荐,它们必须在页面上以某种顺序呈现。有时,这种放置是任意决定的,例如,通过分配给每个建议的随机整数对建议进行数字排序。有时,这些推荐会按字母顺序排列,以便按名称查找,即使最终用户不熟悉内容,不知道首先要查找什么名称。在这两种情况下,推荐都需要放在某个地方,但是从来没有人仔细考虑过这个地方应该放在哪里。在其他情况下,你会发现人们对物体的放置考虑了很多,但他们的决定基于过时或次优的指标,比如棒球经理只依赖球员的击球率来确定他在击球阵容中的位置,而不是使用他的上垒率。这些位置属性的其他示例可能包括您的区域销售办公室的物理位置;您的服务车队使用的维修车间的工作时间;配送中心内放置货物的过道、货架、 和箱柜;或者将专家人力资源分配给世界各地的销售团队。所有这些属性都是母系统设计所固有的(毕竟,专家员工需要被分配到某个地方),但是它们通常是基于什么是方便的,或者当系统第一次被设计时什么是已知的。
- 易变。有了足够的时间和金钱,你可以改变任何事情。没有什么是永恒的。理想情况下,你应该寻找那些你 可以以可接受的代价改变的属性。如果你自己不能改变它,考虑你对你的利益相关者团队的影响以及他们将会产生的成本。在车间里改变装配线的顺序,比把所有的机器打包搬到一个新的地方要便宜得多。
- 体积充足的。如果你能在你的网页上重新排列推荐,这是很好的,但是如果没有人首先点击它们,那么你就是在对着一个空房间大喊大叫。你应该首先关注你的漏斗,发展你的获取渠道。接受有规模的问题。如果你的领域中不存在大规模的问题,你应该把认为是你的第一个问题。
你有没有注意到每年这个时候电影里的蒙面杀手会追逐尖叫的人?这些虚构的杀手无视沉默的受害者,因为娱乐价值太低。他们想要一个奇观。他们想要一场表演。他们想为刺激而优化。从恐怖电影中学习,找到尖叫的问题。寻找具有足够容量的可变属性的事物,它们作为一个更大系统的一部分被任意分配。这些场景迫切需要数据科学。他们真的在演戏。
纱线中的调度器:从概念到配置
先进先出,容量或公平调度,选择权在你。

Like this picture? See more here.
当我们开始深入大数据世界时,许多新词和缩略语开始出现——YARN 也是其中之一。Apache YARN(另一个资源协商者)是一个用于分布式计算范例的集群资源管理平台,它最常与 Hadoop 一起使用,但它也足够通用于其他平台。
在本文中,我们将不会把纱线作为一个整体来讨论,而是讨论它的一个很小但很重要的子集:调度。调度器通常处理提交给 YARN 的作业的资源分配。简而言之,例如,如果一个计算机应用程序/服务想要运行,并且需要 1GB 的 RAM 和 2 个处理器才能正常运行,那么 YARN scheduler 的工作就是根据定义的策略为该应用程序分配资源。
YARN 中有三种类型的调度器:FIFO、容量和公平。FIFO(先进先出)最容易理解,不需要任何配置。它通过将应用程序放入队列中,按照提交顺序运行应用程序。首先提交的应用程序首先获得资源,完成后,调度程序为队列中的下一个应用程序服务。然而,FIFO 不适合共享集群,因为大型应用程序将占用所有资源,并且队列将由于较低的服务率而变得更长。

Source: Hadoop: The Definitive Guide
图 1 展示了三个调度器之间的区别。现在很明显,在 FIFO 的情况下,一个小任务会阻塞,直到大任务完成。Capacity scheduler 为小型作业维护一个单独的队列,以便在请求启动时立即启动它们。但是,这是有代价的,因为我们正在划分群集容量,因此大型作业将需要更多时间来完成。
公平调度器对预留容量没有任何要求。它动态地将资源平衡到所有接受的作业中。当一个作业启动时(如果它是唯一正在运行的作业),它将获得群集的所有资源。当第二个作业启动时,它会在一些容器(容器是固定数量的 RAM 和 CPU)空闲时立即获得资源。小作业完成后,调度程序将资源分配给大作业。这消除了 FIFO 和容量调度程序中的两个缺点,即总体效果是以高集群利用率及时完成小型作业。
现在让我们来看看一些配置。我们在沙盒环境中使用 HDP 2.4(对任何 HDP 2.x 都有效)进行了这些配置。然而,默认情况下,Hortonworks 使用容量调度程序;Cloudera 默认是 Fair scheduler。合并后,他们仍然使用相同的惯例,保持业务如常,但这可能会在未来发生变化。
让我们假设您想要为您部门的需求配置能力计划程序。我们可以从将作业分为三类开始:默认、工作流和首选项。提交给调度程序的普通临时作业、摄取和 ETL 流程的工作流以及需要立即关注的任何作业的首选项的默认值。尽管 Hortonworks 默认的是容量调度器,但是您仍然可以通过使用一种叫做“”的东西来模仿公平调度的行为。
首先,登录 Ambari web 控制台,从右上角的虚线菜单中选择纱线队列管理器。

在这里,您可以看到默认设置:只有一个队列(根)和一个子队列(默认),当前分配了 100 %的资源。

接下来,点击 添加队列 ,再添加两个作业队列。根据需要,您可以将资源分配给队列。

在这种情况下,让我们将 20%分配给默认值,它可以增加到 40 %,最需要资源的工作流可以获得 60–80%的资源,而 20%的首选项可以增加到 80 %,总计为 100%。

这就是我们所说的具有队列弹性的能力调度,例如,如果有人在优先队列中提交一个作业,它肯定会获得 20%的资源,而如果没有未完成的作业,它最多可以获得 80%的资源。保存您的更改以使其在操作菜单中生效。

以下是 Hortonworks 沙盒中容量调度程序的一些基本队列配置。
在结束之前,我将简单解释一下从采访角度来看很重要的先发制人的概念。如果一个队列占用的容器多于其合理的资源份额,而另一个作业正在等待其合理份额下的资源,抢占允许它从第一个队列中删除容器,并将其分配给第二个队列。然而,这是以降低集群效率为代价的。可以从yarn.scheduler.fair.preemption 属性启用抢占,并将其设置为True。
我想链接一下可以帮助理解纱线调度概念的参考资料。
1。 Hadoop:权威指南
2。 用 Apache Ambari 配置纱线产能调度器
3。 纱—产能调度
学术网络分析(SNA)
深入分析
科研网络研究导论

Photo by Alfons Morales on Unsplash
R 科学和研究的飞速发展导致每天产生和收集大量的数字学术数据。这些学术数据可以是科学出版物、书籍、教材和许多其他学术信息源的形式。随着时间的推移,这些信息来源开始通过引用、合著在它们之间建立复杂的关系,并导致形成大型学术网络,这些网络变得越来越难以破解。

Figure 1: An Example of Heterogeneous Scholarly Network¹³
在这种情况下,学术网络分析(SNA)是对这一科学研究网络的研究,旨在发现有意义的见解,以实施数据驱动的研究决策。
学术网络中的重要分析点
考虑图 2 所示的原始图上的 SNA,至少有七个关注点:

Figure 2: Overview of Scholarly Network Analysis on raw graphs¹⁴
- 在论文上合作的作者(合著网络)
合著网络分析可用于发现作者之间的科学合作,描绘作者的个体科学想法如何通过合作聚集在一起,以引起科学发现的爆炸。
2.相互引用的文档(引用网络)
3。被共同引用的文献(共引网络)
引用和共引网络分析用于发现被引用论文和引用这些论文的一组论文之间的关系。这在作为网络分析的基本任务之一的社区检测中证明是有用的。
4.以类似方式引用其他文件的文件(书目耦合)
书目耦合还包括引文分析,以查找在 bibliography⁴.中引用第三次引用作品的文献
5.文档集中的内容聚类(主题网络)
从底层网络中提取主题有助于发现当前的研究领域及其随时间的演变。
6.一起出现的词群(共词)
共词 analysis⁵通过发现关键词的共现来帮助识别特定研究领域中主题之间的关系。
7.类型和关系的多样性(异构网络)
异构网络 analysis⁶,⁷涉及两个或多个耦合网络的研究。例如,通过耦合合著和引文网络,发现引文随时间的演变或未来的引文。
那么,如何从学术网络分析开始呢?
基于分而治之的方法,SNA 的第一个起点是从大的出版网络中缩小范围并创建一个可管理的学术网络图。该学术图表可以基于从学术数据库收集的信息,以我们当前的研究领域(如数据库、数据科学、机器人、能源)为重点创建,可用的学术图表如 DBLP⁸作为计算机科学的书目数据库,微软学术 Graph⁹.这进一步需要一个公式化的设计方法来策划最终的学术图表进行分析。可以考虑一个起点,其可以包括从基础研究论文节点开始,通过爬行相关节点来形成学术图。
一旦我们创建了最终的图表,下一步包括制定要回答的研究问题,并相应地设计分析的切入点。根据数据所需的信息,可以有不同的入口点。其中一些包括发现网络中的潜在主题,基于引用计数或作者联系信息的分析。
图 3 描绘了在名为 Codd 的世界的数据库发布网络的子集上执行的一个这样的 SNA 的概述,其中学术图从 Edgar Codd 关于关系数据库⁰ 的基础论文开始创建,并利用入口点来发现网络中的底层主题(主题建模)以基于主题及其在数据库社区发布图中的演变来驱动进一步的分析。此外,利用不同切入点的一些其他 SNA 研究实例包括分析引用关系以评估给定论文或作者的影响,或研究合著者行为以确定科学界分布。

Figure 3: Scholarly Network Analysis on the heterogeneous network named as Codd’s World¹⁴
本文作为学术网络分析主题的介绍性文章,分享了科学 SNA 研究工作出版物 Codd 的世界:数据库社区出版物 Graph 中的主题及其演变,作者为 Rutuja Shivraj Pawar、Sepideh Sobhgol、Gabriel Campero Durand、Marcus Pinnecke、David Broneske 和 Gunter Saake,德国马格德堡奥托-冯葛利克大学
参考文献
1夏风,王巍,特肖梅格尔萨贝克勒和刘欢。大学术数据:一项调查。IEEE 大数据汇刊,3(1):18–35,2017。
2黄子豪和毛。用于理解学术合作和单个研究人员的知识领域的合著网络的分析和可视化。计算机图形学,成像和可视化,2006 年国际会议,18-23 页。IEEE,2006 年
3萨特里奥·巴斯库洛·尤多阿特莫霍和穆罕默德·李北·萨穆尔。基于 linkrank 算法的 dblp 数据样本集引文网络社区发现。Procedia 计算机科学,124:29–37,2017。
[4]凯文·博亚克和理查德·克莱文斯。共引分析、书目耦合和直接引用:哪种引用方法最准确地代表了研究前沿?
[5]秦和。透过共词分析的知识发现》1999
[6]严尔嘉和丁樱。学术网络分析。《社会网络分析和挖掘百科全书》,第 1643-1651 页。斯普林格,2014。
[7]严尔嘉和丁樱。学术网络的相似性:书目耦合网络、引用网络、共同引用网络、主题网络、共同作者网络和共同词汇网络如何相互联系。美国信息科学与技术学会杂志,63(7):1313–1326,2012
8 迈克尔·莱伊。dblp 计算机科学书目:进化,研究问题,观点。在字符串处理和信息检索国际研讨会上,第 1-10 页。斯普林格,2002 年。
[9]阿纳·辛哈、、、达林·艾德、许宝俊和王宽山。microsoft 学术服务(mas)和应用程序概述。《第 24 届万维网国际会议论文集》,第 243-246 页。美国计算机学会,2015。
[10]埃德加·F·科德。大型共享数据库的数据关系模型。美国计算机学会通讯,13(6):377–387,1970 年。
[11]马克·纽曼.网络.牛津大学出版社,2018 年。
[12],,,,,张,,等。挖掘学术大数据中的顾问-被顾问关系:一种深度学习方法。第 16 届 ACM/IEEE-CS 数字图书馆联合会议论文集,第 209-210 页。ACM,2016。
[13]严,尔嘉,,和。" P-Rank:衡量异质学术网络声望的指标."贾斯特 62(2011):467–477。
[14] Pawar,R.S .,Sobhgol,s .,Durand,G.C .,Pinnecke,m .,Broneske,d .和 Saake,g .,2019 年。Codd 的世界:数据库社区出版图中的主题及其演变。在 Grundlagen von Datenbanken (第 74–81 页)。
非科幻科学
人工智能将改变你的生活。问题是,没有人真正知道怎么做。

In this article we will talk about artificial intelligence (hereinafter referred to as AI), and about the risks and consequences that could come from its development. You may not be interested on the subject a tiny bit or be just fed up with headlines about it. But the thing is, AI will affect your life sooner or later, and most likely in a profound way. We’ll try to give you here a good take on the topic, so that you at least know what to expect. As always, if you want to go deeper, follow the links throughout the text to access other articles and videos with much more info.
Let’s start with a quote from I.J. Good, an English mathematician who worked with the legendary Alan Turing in the mid-twentieth century in the design of the first modern computers: “The first ultra intelligent machine is the last invention that man need ever make, provided that the machine is docile enough to tell us how to keep it under control. It is curious that this point is made so seldom outside of science fiction. It is sometimes worthwhile to take science fiction seriously”.
Maybe so. The blogger Tim Urban thinks otherwise: he says that when we hear about AI we think about things like Star Wars or Terminator, and that makes us associate the term with fiction, making us not take it too seriously.
Tim is right. When you start reading in depth about AI, the first reaction is one of absolute surprise, because one realizes that the general level of knowledge and concern about this issue is so very far from where it should be. The rapid development of Artificial Intelligence could be described as an 8-axle trailer truck that is hurdling towards us at 300 mph. So how come we are looking the other way?
It seems a relevant question, don’t you think? It doesn’t seem normal that we are arguing all the time over some nonsense that always seems to be a matter of life and death, while issues that may not be a matter of life or death but of immortality or extinction are considered by most as stories for nerds. This may seem like an exaggeration, but actually, it isn’t.
We’ll go over that question in the second part of Science Non-Fiction, which will be posted next. This first part has the goal of describing for you the truck and its speed; enough in detail to maybe erase that smile you have right now.
The topic of AI is actually a very broad one. Yes, AI is behind you getting all those advertisements for hotels in London after doing a search for flights over the internet; and maybe you’ve also read about AI beating every human at chess and at that Chinese board game (it’s called Go). Nowadays many AI tools and applications are being developed across many fields with sweeping advances. Some of that stuff could actually deliver great outcomes for us, such as the ability to diagnose diseases much more accurately, or the breaking of communication barriers with natural language processing. In the case of the financial industry, which is our main concern at Goonder, AI can help algorithms not only to be able to better predict market fluctuations, but also to be able to learn from the individual evolution of each investor, allowing us to offer a much more personalized service. But some other stuff already in development can be really scary, such as the police use of facial recognition (especially when there are clear signs of gender and skin type biased systems), lethal autonomous weapons or the use in China of social credits for citizen behavior.
Beyond all these developments and the debate over the possible implications, the general perception today for ordinary mortals seems to be that if one of these AI tools has not yet taken my job, so far so good.
Looking into the future, things could get seriously unsettling if we get to the next step, which is not a step but a huge leap, one that would make Neil Armstrong look like a child playing hopscotch. It would be to get to AGI, or Artificial General Intelligence: a system that would be as efficient as a human not just in concrete tasks, but in every task. Put another way, a system that has the same level of intelligence as we do. From today’s perspective it may seem that we are very far from reaching that point. But are we?
The classic way to measure progress in the field of AI is the famous Turing test. A machine will have passed the test when the evaluator considers that its answers are indistinguishable from those of a human. 5 or 10 years ago this seemed a distant goal. Nowadays you talk to Siri or Alexa and yeah, if you ask them about the meaning of life they’ll probably answer some nonsense, but you may have noticed that they give fewer and fewer nonsense answers. According to 2016 measurements, Google’s AI was approaching the intelligence level of a 6-year-old child. And like children, these things grow fast. Catching up with us seems to be getting more likely and less far away.
In terms of technological evolution, reaching AGI basically depends on achieving significant increases in process and learning capacities. Regarding the first one, the process capacity to have an AGI system actually already exists; we just have to make it more efficient and cheaper. At the current pace, it would be a matter of a few years. The second increase is the most difficult: how do you improve the learning capacity of a system? Contrary to what one could intuitively think, it seems that the fastest way is not to feed the system with all available knowledge, but to program it so that it can learn on its own, based on trial and error. In fact, one of the strategies that is making more progress today is programming the systems using neural networks and what is called deep reinforcement learning, so they learn and improve alone.
Here’s an illustrative example. Do you remember Deep Blue, the system created by IBM that in 1997 beat the then world chess champion, Gary Kasparov? Deep Blue was a system that was fed with all the knowledge accumulated in chess, millions of games. With that and raw process capacity, it was able to choose better strategies than the best human and thus defeat him. Since then, systems created under that approach have routinely won over any chess grandmaster, and since a couple of years they also beat us at go, an even more complex and abstract game. However, the artificial intelligence company DeepMind (owned by Google) has achieved a huge evolutionary breakthrough this last year with AlphaZero, a system that they fed with just the rules of three complex board games: chess, shogi, and go. The idea, and hence the name, is that the system learned to play all three games from scratch using neural networks and deep reinforcement learning, and without it being contaminated with any prior human knowledge. Thus, it began playing ultra-fast games against itself, and it took the thing a few hours to reach the most advanced strategies of the grandmasters, and a little while more to discover absolutely unthinkable strategies for us pitiful humans. Of course, AlphaZero is now the unofficial world champion of all three disciplines. And even when playing with a hand tied behind its back, it’s a walk in the park: of 100 games of go, and with the tenth of chips and time to move, AlphaZero crushed 100–0 the previous champion, its older brother AlphaGo (which was the system that in 2016 had defeated the last human champion, Lee Sedol, as you can see in this documentary).
So, summarizing a bit: for a system to reach a level of human intelligence, the problem of process capacity will be solved in the medium term, and solving the problem of learning ability is achieving huge qualitative leaps with the use of neural networks and machine deep learning techniques.
Now before we go on with the description of the truck, a word about the growing speed in which it’s coming. There is a concept that may be not that difficult to understand, but which is in fact really hard to visualize: exponential growth. In this case, we can see that the more a system learns and improves, the better it will be at learning and improving afterwards, since each improvement cycle will allow for better and faster increases in capacity, eventually leading to exponential growth. But this concept is at the same time very difficult to grasp, since us humans are designed to think in linear, not exponential terms. Tim Urban explains it very well with the help of really funny and illustrative graphics in his blog Wait but why, where he has published two posts about the AI revolution: The road to superintelligence and Immortality or extinction (if you’re interested in AI, reading these two posts is highly recommended: they’re quite exhaustive and very entertaining). At the end of his first post, Tim presents us with the following conclusion: for a system that is learning exponentially, getting to AGI state will be just something that happened for a second, and was left behind the next one. This is exactly what AlphaZero did with the game strategies that humans had been able to come up with.
Reached this point, let’s introduce two new concepts: Singularity and ASI. Both concepts are based on the ability of technology to generate that exponential growth that will go faster and faster and over which we will have less and less control. The singularity would be that moment in which a system’s capacity for recurrent self-improvement reaches such a degree that an intelligence explosion happens. ASI means Artificial Superintelligence, or the system that would emerge from that intelligence explosion. ASI is something that could leave humans so far behind that we would have about the same capacity for understanding and controlling it as that of an ant colony on the generation of atomic energy. (Actually, much smaller. See the stairs graph in Tim Urban’s second post).
So that’s the truck.
Before going over possible consequences, maybe it’s worth stopping here a moment to consider what you just read. You’re thinking you’ve seen this before, aren’t you? Skynet in Terminator, Hal 9000 in 2001, Agent Smith in The Matrix… Science fiction. Right?
Actually, it’s a logical path, one that many experts think that is going from possible to probable. It has even been predicted by one of the pioneers of computing. Do you remember that quote we started with? Alright, so you never heard of that I.J. Good. Well, here are more quotes from people you should know. Stephen Hawking: “The development of full artificial intelligence could spell the end of the human race.” Bill Gates: “I don’t understand why some people are not concerned.” Elon Musk: “We are summoning the demon.”
Okay, maybe lately Elon Musk is not the most credible source of news in the world. So, what do the experts think? Surveys of those leading the AI field from 2011, 2013 and 2018 show some powerful data. For starters, the number of those who consider that all this remains pure science fiction and that a system will never reach human intelligence, depending on the survey you look at, vary between 2 and 20%. That is, the vast majority of experts disagree on the when, not in the if. Regarding the when, the median in the experts’ answers is that we would have an AGI system between 2040 and 2060, and that an ASI would arrive afterwards, either very quickly, or at the most 30 years later.
Put another way: if you are between 20 and 40 years old, there is a 50% chance that your children will be run over by the truck. And your grandchildren’s odds look very ugly.
Or very beautiful. Because maybe when the time comes the truck instead of running over us, picks us up and take us to an instantaneous future in which almost all our limitations will disappear, starting with death (and maybe even taxes.)
It’s now time to introduce you to Ray Kurzweil, or as they call him in a documentary, “The Transcendent Man”. Scientist, inventor, writer, musician, entrepreneur, creator of the Singularity University, lately director of engineering at Google. A guy that even those who think he is nuts admit that he is a genius. 21 honoris causa doctorates, an off-the-chart IQ and a quite impressive fulfilled predictions track record. He’s the equivalent of a rock superstar for technologists. You can see him in action in TED talks, read profiles on him by The New Yorker or Rolling Stone, or interviews with him in Playboy or The Guardian.
Ray is one of the optimists. He believes that everything will happen for the better, and that it will happen much faster than his colleagues believe: he assures that a machine will pass the Turing test in 2029 and that the Singularity will happen by 2045. He also believes that exponential growth of knowledge across several fields will end up making us immortal. He predicts that the whole process will be controlled, and that very soon there will be breakthroughs that will overcome the classical barriers of biology, turning us effectively into a new species, with a human base and artificial evolutions. Ray is taking great care of himself because he’s not that young anymore and of course he’d like to get to live forever. In fact, just in case he doesn’t make it, his plan B is to freeze his brain. He also intends to make his father alive again using DNA.
There’s that smile again. Who could blame you? But leave aside Ray’s ability to generate headlines and think about it a bit, and you’ll see that it’s not such a deranged scenario. We know that we are not biologically designed for today’s living conditions, but for a time when we were hunter-gatherers, just one more animal trying to survive and transmit our genes. Biological evolution, which uses roughly the same tools as AlphaZero, (a trial-and-error system with rewards for the most successful strategies), works in temporary terms that have nothing to do with the artificial capacity for improvement that we have achieved. Therefore, if we aspire to get on the truck and not to be run over, any future evolution minimally appreciable, and needless to say if it is so radical, must necessarily have a technological base.
Let’s try with a more visual example: Who runs faster, Usain Bolt or your grandmother? Ok. Yes. Usain Bolt. But what if we give your grandmother a Ferrari? She’ll probably have some trouble getting to handle the gears, she might crash into a tree or run over some pedestrians… but hypothetically it’s clear that she’ll run much faster than Usain Bolt, right? Change that Ferrari for exponential advances in AI and biotechnology, and suddenly it’s not that crazy to foresee all those things that Ray imagines will be common for future generations. Direct access with the mind to all the data in the cloud. Daily backups of our brain: memories, sensations, thoughts, emotions. Possibility of using nanotechnology and augmented reality to inhabit other bodies, other realities. Nanobots circulating through our bloodstream and our brain, repairing and improving all biological systems, giving us physical and mental abilities that can only be described as post-human. Building genetic and enhanced copies of ourselves and of our parents, in case we don’t make it to the party. And immortality.
Of course to Ray, who is more than 70 years old, all this seems like a great prospect. For Charlie Brooker, who is in his forties, it inspired Black Mirror.
Charlie is a storyteller. The dystopias he imagines in Black Mirror stem from a dark vision of the human condition mixed with technological developments that don’t seem so distant. And the most worrying thing is not that these projections seem so creepy; it’s that these are scenarios in which the truck doesn’t run over us. Therefore, they are optimistic scenarios.
Because another possible scenario is that the ASI system that comes after the singularity may have the same interest in the survival of humans as any human would in the survival of mosquitoes, except maybe for Greenpeace members. And yet another scenario is that the ASI system has strategic goals incompatible with human existence, as in Nick Bostrom’s famous example of the paperclip maximizer.
Nick Bostrom is not like Ray Kurzweil at all. Maybe they have similar IQs and areas of interest, but that’s about it. Nick is definitely no rock star. Philosopher, thinker, author of more than 200 papers, he’s an expert in ethics and technology, and the director of the Future of Humanity Institute at Oxford University. If you have the time and you like the topic, you should read his book Superintelligence. If you don’t have that much time, you might enjoy reading his profile in The New Yorker and watching the talk he gave at Google. And if you have no time at all, maybe you can watch this TED talk for a quick summary.
Nick sees the arrival of the ASI as an existential risk for the human species, the most likely candidate to be the black ball that we take out of the bag of new technologies and that means our doom. He wonders if it is not a Darwinian mistake to create something that is smarter than us. He concludes that, whether or not we end up creating a superintelligent system, it would be a good idea to start laying some solid foundations so that the outcome is as benevolent as possible for humanity. Sounds pretty logical, right?
Because if it happens, regardless of when it happens, the truth is that no one knows for sure what would come next. Whether it will be good or bad for the species, or very good for a few and very bad for the majority. Or maybe it won’t be better or worse, but very different, like Black Mirror. Those surveys that we talked about earlier show much more diverse results on this point. In the 2013 survey, experts who thought that the result would be good or very good for humanity added up to 52%, and those who thought it would be bad or very bad, 31%. So, when Nick was asked at the end of that talk he gave at Google if he thought we were going to make it, he answered the question laterally. “Yeah, probably less than 50% risk of doom, I don’t know what the number is”, he said. And then he added, “But the more important question I guess is what is the best way to push it down.”
This may be the most important issue that we have to face in the coming years.
googler2019 年
脸书广告的科学方法
需要多少次浏览才能确定新创意不起作用,设计师们又一次不得不为他们的晚餐而歌唱?有多少浏览网站的用户意识到弹出购买按钮是个坏主意?

这篇文章是为谁写的
从事广告活动和登录页面有效性优化的专家总是发现他们自己在问完全相同或相似的问题。对于那些用于测试新渠道和假设的计划预算也是如此。在寻找答案的时候,你可以依靠直觉,但是最好回到概率论的基础上,让你计算出所需的顺序。
引入术语
直觉表明,测试时间越长(在其他条件相同的情况下),结果就越精确。但是更精确是什么意思,什么时候会变得足够精确?为了回答这些问题,让我们通过广告浏览量和点击量来介绍一些概率论术语。
让一个随机事件成为我们广告的单一视图。这种事件有两种结果:用户要么点击具有 CTR 概率的广告,要么不点击具有 100% CTR 概率的广告。
一个随机的点击数被记录在一系列默认长度的视图中,这个数字就是我们的随机值。因为,如果我们再次用同样数量的视图重复这个实验,我们会得到不同数量的点击。我们永远也不能提前说出准确的点击次数,但我们可以通过计算一系列视图的点击期望来推测。
我们只需要将一次浏览中的点击概率,即我们的点击率,乘以适当的浏览次数。例如,当点击率为 1%时,250 次浏览的点击率期望值为 2.5。按照纯粹的逻辑,我们理解一半的用户(可能是美人鱼?)不会点击我们的广告,因此在广告管理器中,我们会看到大约两三次点击。
但是,如果我们继续测试我们的 250 个视图系列,并记录每个系列的点击数,我们将得到一个接近预期的平均值。这里,这种实验的次数越多,平均值就越接近预期值。这是对符合我们直觉的概率论大数定律的一种相当轻率的解释。
导致需要计算置信区间
你可能会问:“很明显,精确是指接近期望(即,一个更小的变量范围),但我们为什么需要这个?”
在广告管理器中,如果有一千次点击,我们会得到十次点击,系统会自豪地说点击率是 1%。高兴得要命,我们会去旅行,但回来后我们会发现,在第一次数千次浏览后,点击率只有 0.6%。真是一团糟!但是,当然,我们既没有考虑到观众,也没有考虑到创作倦怠。问题是,你的第一千次浏览比平均水平要好,经理显示的点击率与实际相差甚远。但是随着一系列更长的观点,它接近了它的真正价值。单独使用 CTR 很方便,因为它不依赖于视图的数量。它的精确程度直接取决于点击次数的精确程度。
作为一个真正的 CTR,我会考虑我们在文章开头定义随机事件时提到的概率。因为该值被设置为无穷大,并且广告管理器中的 CTR 倾向于在延长一系列视图时达到该值,因为真实的 CTR 被用于计算点击期望。
预测你创意的未来效果需要了解真实的 CTR。但这是不可能的(除非你的预算是无穷无尽的),因此你只能通过钥匙孔进行窥探。用数学术语来说,真实 CTR 的潜在范围可以根据我们用测试预算购买的数据来粗略估计。现在是公式登场的时候了。
关于泊松分布
一个意想不到的免责声明:不要把这篇文章当作精确计算的正式指南。它的科学特性只是用来粗略地计算。
泊松分布可以帮助定义在 n 个视图上获得 m 次点击的概率,

其中 p 是真实的 CTR,λ是从真实的 CTR 和 n 个视图中得出的,是对这种大小的采样的点击期望。不幸的是,这只适用于 10 阶的λ,这会降低所有进一步计算的精度。
但是不要害怕公式,因为我们只需要它的图形

该图显示了 n 次浏览的真实点击率转化为随机点击数的概率。您可能会看到概率峰值的形式,以及在 n 个视图上的点击期望及其在峰值上的近似值。在图表的底部(或峰值的根部),当点击数量远离预期时,我们的一系列视图的实现可能性较小。因此,确定一系列视图的点击数的可能值的范围意味着确定我们的峰值有多宽。
随机值相对于其期望值的程度范围称为离差,其根是标准偏差(图上的 s ),实际上决定了峰宽。
最终,为了进行计算,需要弄清楚实现一系列视图的概率是在顶部还是在底部。换句话说,某个样本的点击量不会超过期望值的标准差的概率是多少?而恰好是 70%左右。

计算置信区间
有问题的音程,

被称为置信水平为 70%的置信区间。我们将进一步关注它。
我们非常幸运,因为泊松分布的离差等于它的期望,即等于 λ,以及标准偏差值——等于λ的根。因此,70%置信区间如下

假设我们广告的真实点击率是 1%,那么 900 次点击的预期点击率就是 9。因此,我们有

这意味着,在 900 次浏览后,70%的情况下,我们将获得 6 到 12 次点击(9 次仍然是最有可能的)。将这些值除以浏览量,我们很容易猜到广告经理显示的点击率在 0.67%到 1.33%之间。在 ads 管理器中,这个范围可以称为 CTR 的置信区间。
因此,如果你对点击率超过 1%感到满意,而你的前 900 次浏览没有幸运地获得 0.67%的点击率,那么这个在未来会表现良好的广告可能会被不必要的删除。在这种情况下,测试期应该被延长。
但是等等,你很可能会问为什么我们要预测真实的点击率,并在此基础上做出结论,如果事实上任务恰恰相反——在广告管理器的点击率基础上定义潜在的真实点击率。你是对的。从技术上来说,这样的计算应该更复杂,但最终它会在上述相同的领域结束。所以,不要害怕表面上的困难。现在让我们对提到的每件事做一个简短的总结。
间歇结论
理解误差比比理解置信区间更容易,置信区间中的比率误差是期望偏差与正确期望的比率。在我们的情况下,我们有

除了与我们没有包括在 70%置信区间中的 30%的情况相关的误差之外,前面提到的例子的误差率不小于 33%。在这 30%中,我们可以得到不包含在置信区间中的任意随机点击数。
那么,我们得出的结论是什么?例如,我们可以得出结论测试的准确性(即比率误差的小)不取决于累积的随机事件的数量,而是取决于成功的数量,或者不取决于查看的数量,而是取决于点击的数量。
这就是为什么没有共同的边界来决定进行测试的正确程度。如果除了从测试运行依赖的持续时间来谈论登录页面,我们需要提到 CTR 依赖和转换依赖。但是你必须随时准备好自己定义每个特定案例的边界。
就固定的真实 CTR 值而言,精确度随着视图数量的增加而增加。让我回忆一下,点击期望值是通过将固定的真实点击率值乘以点击次数来确定的,并向您显示,当点击期望值增加时,错误率在下降







此外,您可能会注意到下降的以下规律性— 我们测试的时间越长,准确性增长得越慢,意味着测试应该按时结束。否则,时间和预算就没有得到有效的利用。
但是准时是什么意思呢?要求的准确度是多少?那要由你来决定。唯一可以确定的是,在点击 25-30 次之后,准确率会以一种非常缓慢的速度增长。
一个逆向任务
让我们回到计算置信区间,并最终弄清楚如何在广告管理器中粗略地绘制潜在的真实点击率。
我们已经确定,在广告管理器中,n 个视图的真实 CTR 有 70%的概率被实现为相关置信区间内的一个值,这意味着管理器中的每个 CTR 是各种真实 CTR 的过多置信区间的一部分。我们只需要确定哪些最小和最大真实点击率可以在我们的经理身上实现(具有给定的准确度)。长话短说,我们需要找到这样的真实点击率,它们与经理的点击率在置信区间的边界上相对应。
因此,看看广告经理,在那里看到一定的点击率,我们将最终回答关于我们广告的潜在真实点击率的问题。答案将是真实 CTR 的范围

让我们通过将上面提到的图片翻译成点击期望的语言来找出 CTR1 和 CTR2,回忆置信区间的宽度。因此,λ是广告管理器中的点击次数,而带有数字的λs 对应于 CTR1 和 CTR2

等式的左边部分对应于左置信区间的右边界。它的右边部分是右音程的左边界。他们的交汇点正好对应我们的点击量。
这是方程式的解


可能看起来很恶心。但是如果管理器中的点击次数明显大于 1,就可以丢弃它,这样解决方案就相当不错了。因此,点击次数的计算置信区间为

看起来是不是很眼熟?所以,结果是我们不需要解任何方程,因为在精确度上有一点点误差,我们已经把逆向任务转换成了直接任务。
例证
好吧,让我们用一个恰当的例子来说明上述的方法。
- 我们在管理器中看到每 1000 次点击有 25 次。系统会为我们计算点击率。也就是 2.5%。
- 现在我们计算点击次数的平方根。因此,我们得到了我们的标准差,即置信区间的宽度。对我们来说,是 5。
- 然后我们计算点击次数的置信区间(25–5;25+5)= (20;30)
- 然后我们计算真实 CTR 的相关区间。我们只需将之前计算的值除以点击次数(并计算百分比)(2%;3%)
- 利润
顺便说一下,评估测试准确度的程度需要误差比,误差比是通过将标准偏差除以点击次数来计算的

基准表
为了方便起见,我会在下面放一个表格,说明上面提到的所有内容,并展示广告测试所需的浏览次数(一组 25 次点击,之后准确度会慢慢增加),具体取决于其 CTR

AB 测试
如果在你看来,70%的置信区间加上 20%的误差率给出了相当不准确的结果,欢迎你使用宽度不是两倍而是四倍于标准差的 95%的置信区间。在这种情况下,我们需要用点击次数的根来代替它的双倍值。所以,20%的相对准确度将在 100 次点击时达到。
上述推理很可能为测试持续时间设置一个理论下限。对于较短的测试,样品将没有代表性。然而,我们很少对适当测试的准确性感兴趣,因为我们通常需要将我们的结果与默认结果进行比较,例如,在媒体计划中详细说明或通过其他(已经测试过的)广告获得的结果,或者与 A/B 测试中第二个变量的结果进行比较。
就第一种情况而言,如果测试结果即使在置信区间的上界也不令人满意,测试可以提前完成。例如,如果我们有 9 次点击率为 0.9%的点击,而真实点击率的 70%范围是(0.6%;1.2%)而我们需要不低于 2%的点击率,等待 25 次点击是没有用的。达到这种结果的机会非常小,因为即使是 95%的真实 CTR 范围也只有(0.3%;1.5%).
在 A/B 测试的情况下,有两个图形有自己的宽度。测试的准确度取决于它们重叠的程度(指数随时间变化)。你可能会问为什么。事情是这样的,在某个特定的时刻,我们变量的每一个结果看起来都像图表上的一条垂直线(或者水平轴上的一个点)。如果这种重叠很大,在某个时刻,左边的结果可能实际上属于右边的图,而右边的结果属于左边的图。如果我们提前完成测试,我们将选择一条死路,尽管在那一刻它似乎是一条胜利之路。左图上的测试准确度与右图相比还有很大的差距。

然而,电子邮件营销或 UX/XI 专家可以在他们专业工具的界面上计算 A/B 测试的程度,或者至少使用在线服务。因此,与广告经理打交道的人以及因此进行大量 A/B 测试的人可以使用下面的建议。
计算图表的准确交叉点是一项具有挑战性的任务,因此我们只能根据真实 CTR 范围的交叉点做出决定。在这种情况下,最好使用 95%的间隔。如果最初相关区间彼此远离,我们可以提前完成测试。但是,如果它们重叠,我们应该继续进行测试,直到缺少重叠的时刻或达到代表性抽样的时刻。代表性的程度取决于重叠的程度。如果 90%的区间重叠,而 70%的区间不重叠,那么每个变量点击 30 次就足够了。但是,如果 70%的区间也重叠,这意味着各种变体的有效程度彼此非常接近,那么没有一百次点击就不行。
结案陈词
最后,我要提醒你的是,上面提到的一切都可能在漏斗的任何阶段使用,不仅适用于视图(条目)和点击,也适用于从销售线索到购买的转化。唯一的保留是指泊松分布,因为它只对低概率的随机值有效。因此,我们将无法使用我们的方法来实现从填充铅表格的一行到另一行的高转换系数。
很有可能将漏斗作为一个整体来分析,即从广告点击到整个漏斗的最终转化的转化准确率,尽管中间有过多的微转化。因此,我们只需要将我们的随机事件称为广告点击,将结果称为最终的转化或缺乏转化。这最终有助于我们定义(我不能说计算)必要的方法,根据随机事件的相同 25-30 个成功结果,通过媒体规划进行假设检验。
sci kit-学习决策树解释
使用决策树进行训练、可视化和预测

Photo by Lukasz Szmigiel on Unsplash
D 决策树是随机森林中最重要的元素。它们能够拟合复杂的数据集,同时允许用户看到决策是如何做出的。当我在网上搜索的时候,我找不到一篇清晰的文章可以很容易地描述它们,所以我在这里写下我到目前为止学到的东西。值得注意的是,一个单独的决策树不是一个很好的预测器;然而,通过创建它们的集合(森林)并收集它们的预测,可以获得最强大的机器学习工具之一——所谓的随机森林。
Make sure you have installed pandas and scikit-learn on your machine. If you haven't, you can learn how to do so [here](https://medium.com/i-want-to-be-the-very-best/installing-keras-tensorflow-using-anaconda-for-machine-learning-44ab28ff39cb).
Scikit 学习决策树
让我们从使用 iris 花卉数据 se t 创建决策树开始。iris 数据集包含四个特征、三类花卉和 150 个样本。
功能:萼片长(厘米)、萼片宽(厘米)、花瓣长(厘米)、花瓣宽(厘米)
类:刚毛藻、云芝、海滨草
从数字上看,刚毛花用 0 表示,杂色花用 1 表示,海滨花用 2 表示。
为简单起见,我们将使用所有特征训练决策树,并将深度设置为 2。
可视化决策树
当然,我们仍然不知道这个树是如何对样本进行分类的,所以让我们通过首先使用 Scikit-Learnexport _ graphviz模块创建一个点文件,然后使用 graphviz 处理它来可视化这个树。
这将创建一个名为 tree.dot 的文件,需要在graphviz上进行处理。这里有一个 YouTube 教程向你展示如何用 graphviz 处理这样一个文件。最终结果应该类似于图-1 所示;但是,即使训练数据相同,也可能会生成不同的树!

Figure-1) Our decision tree: In this case, nodes are colored in white, while leaves are colored in orange, green, and purple. More about leaves and nodes later.
单一决策树是一种被称为白盒的分类器的经典例子。白盒分类器做出的预测很容易理解。这里有一篇关于黑白盒分类器的优秀文章。
了解节点的内容
在图-1 中,可以看到每个盒子都包含几个特征。让我们从描述最顶层节点的内容开始,最常见的是称为根节点。根节点深度为零,参见图-2 。节点是决策树上的一个点,在这里提出一个问题。该操作将数据分成更小的子集。

Figure-2) The depth of the tree: The light colored boxes illustrate the depth of the tree. The root node is located at a depth of zero.
花瓣长度(cm) < =2.45: 决策树问的第一个问题是花瓣长度是否小于 2.45。根据结果,它要么遵循正确的路径,要么遵循错误的路径。
Gini = 0.667:Gini score 是一个量化节点/叶子纯度的指标(一点关于叶子的更多内容)。大于零的基尼系数意味着包含在该节点内的样本属于不同的类别。基尼系数为零意味着该节点是纯的,在该节点中只存在一类样本。你可以在这里找到更多关于杂质测量的信息。请注意,我们的基尼系数大于零;因此,我们知道包含在根节点中的样本属于不同的类。
samples = 150: 由于 iris flower 数据集包含 150 个样本,因此该值设置为 150。
value = [50,50,50]:value列表告诉你在给定的节点上有多少样本属于每个类别。列表的第一个元素显示属于 setosa 类的样本数,列表的第二个元素显示属于 versicolor 类的样本数,列表的第三个元素显示属于 virginica 类的样本数。注意这个节点不是一个纯粹的节点,因为不同类型的类包含在同一个节点中。我们已经从基尼系数中知道了这一点,但是真的看到这一点还是很好的。
class = setosa:class值显示给定节点将做出的预测,它可以从value列表中确定。节点中出现次数最多的类将被选为class值。如果决策树在根节点结束,它将预测所有 150 个样本都属于 setosa 类。当然这没有意义,因为每个类都有相同数量的样本。在我看来,如果每个类别的样本数量相等,决策树被编程为选择列表中的第一个类别。
理解树是如何分裂的
为了确定使用哪个要素进行第一次分割(即生成根结点),该算法选择一个要素并进行分割。然后,它会查看子集,并使用基尼系数来衡量它们的不纯度。它对多个阈值这样做,并确定给定特征的最佳分割是产生最纯子集的分割。对训练集中的所有特征重复这一过程。最终,根节点由产生具有最纯子集的分裂的特征来确定。一旦确定了根节点,树的深度就会增长到 1。对树中的其他节点重复相同的过程。
理解一棵树如何做出预测
假设我们有一朵花,有petal_length = 1和petal_width = 3。如果我们遵循图-1 所示的决策树的逻辑,我们会看到我们最终会出现在橙色框中。在图-1 中,如果一个节点问的问题结果是真(假),我们就向左(右)移动。橙色框深度为 1,参见图-2 。因为这个盒子里没有东西生长出来,所以我们称它为叶节点。注意这与真实的树有相似之处,参见图-3 。此外,请注意基尼系数为零,这使它成为一片纯粹的树叶。样本总数为 50。在结束于橙色叶节点的 50 个样本中,我们可以看到它们都属于 setosa 类,参见这个叶的value 列表。因此,树将预测样本是 setosa 花。

Figure-3) Real tree vs Decision Tree Similarity: The tree on the left is inverted to illustrate how a tree grows from its root and ends at its leaves. Seeing the decision tree on the right should make this analogy more clear.
让我们挑选一个更有趣的样本。比如petal_length = 2.60和petal_width = 1.2。我们从询问花瓣长度是否小于 2.45 的根节点开始。这是假的;因此,我们移至右侧的内部节点,这里基尼系数为 0.5,样本总数为 100。这个深度为 1 的内部节点会问“花瓣宽度小于 1.75 吗?”在我们的例子中,这是真的,所以我们向左移动,最后到达深度为 2 的绿色叶子节点。决策树会预测这个样本是杂色花。你可以看到这是最有可能的情况,因为在绿叶节点结束的 54 个样本中有 49 个是杂色花,见这个叶子的value列表。
使用训练树对新样本进行预测
现在我们知道了决策树是如何工作的,让我们来做预测。输入应在一个列表中,并按[sepal length, sepal width, petal length, petal width]排序,其中萼片长度和萼片宽度不会影响图-1 所示决策树的预测;因此,我们将可以给它们分配一个任意的值。
输出应该是:

This is exactly what we predicted by following the Decision Tree logic.
sci kit-学习决策树参数
如果你看一下决策树分类器可以采用的参数,你可能会感到惊讶,让我们来看看其中的一些。
标准:该参数决定如何测量分割的杂质。默认值是“基尼系数”,但你也可以用“熵”来衡量杂质。
拆分器:这是决策树搜索拆分特征的方式。默认值设置为“最佳”。也就是说,对于每个节点,该算法考虑所有特征并选择最佳分割。如果您决定将分割器参数设置为“随机”,则将考虑要素的随机子集。然后,将由随机子集中的最佳特征进行分割。随机子集的大小由 max_features 参数决定。这也是随机森林得名的部分原因。
max_depth: 这决定了树的最大深度。在我们的例子中,我们使用深度为 2 来构建决策树。默认值设置为无。这通常会导致过度拟合的决策树。深度参数是我们可以调整树的方式之一,或者限制它的增长方式以防止过度拟合。在图-4 中,你可以看到如果不设置树的深度会发生什么——纯粹的疯狂!

Figure-4) A fully grown Decision Tree: In the tree shown above, none of the parameters were set. The tree grows to a fully to a depth of five. There are eight nodes and nine leaves. Not limiting the growth of a decision tree may lead to over-fitting.
min_samples_split: 为了考虑分裂,节点必须包含的最小样本数。默认值是 2。您可以使用此参数来调整您的树。
min_samples_leaf: 需要被视为叶节点的最小样本数。默认值设置为 1。使用此参数来限制树的增长。
max_features: 寻找最佳分割时要考虑的特征数量。如果未设置该值,决策树将考虑所有可用的功能来进行最佳分割。根据您的应用,调整这个参数通常是个好主意。这里有一篇文章推荐如何设置 max_features。
出于语法目的,让我们设置一些参数:
结束语
现在您知道了如何使用 Scikit-learn 创建决策树。更重要的是,你应该能够将它可视化,并理解它是如何对样本进行分类的。需要注意的是,我们需要限制决策树的自由度。有几个参数可以正则化一棵树。默认情况下,max_depth 设置为 none。所以一棵树会长满,往往会造成过拟合。此外,单个决策树不是一个非常强大的预测器。
决策树的真正力量在培养大量决策树时表现得更加明显,同时限制它们的增长方式,并收集它们各自的预测以形成最终结论。换句话说,你种植了一片森林,如果你的森林在性质上是随机的,使用 bagging 的概念,并带有splitter = "random",我们称之为随机森林。Scikit-Learn 随机森林中使用的许多参数与本文中解释的参数相同。因此,在使用大家伙之前,理解什么是单个决策树以及它是如何工作的是一个好主意。
sci kit-了解设计原则
优雅、进步、务实
介绍
这篇博客文章是对 Scikit-Learn 库的设计原则的简要反思。需要澄清的是:这是而不是使用 Scikit-Learn 的教程。Scikit-Learn 是一个强大、丰富和广泛的 Python 库,用于实现机器学习。该库提供用于建模(例如,分类、回归和聚类算法)、模型选择(例如,网格搜索)、预处理(例如,特征提取)等的工具。我坚持认为,这个库的成功与其强大而深刻的功能一样,与它的界面和易用性密切相关。
如下面的 Scikit-Learn“算法备忘单”图所示,这个库非常大,非常丰富:

但是在这篇博客中,我采用了一种不同的方法,从一个不同的角度来看问题:我不太关注 Scikit-Learn 的功能,而更关注它的设计能力,这样,我借此机会反思了一些我最喜欢的软件模式和设计主题。这篇文章的灵感来自经典论文“机器学习软件的 API 设计:来自 scikit-learn 项目的经验”(以及其他来源——见下面的参考文献)。Scikit-Learn 文档(通过scikit-learn.org,在下面的参考资料中注明)也是最棒的,反映了与库本身一样的深思熟虑和清晰的设计和组织。
Scikit-Learn 库提醒人们设计模式在软件设计中的力量。关于设计模式的开创性工作——设计模式:可重用面向对象软件的元素——提倡“编程对接口的重要性,而不是对实现的重要性。”Scikit-Learn 在其语义非常简单的接口后面隐藏了巨大的复杂性。换句话说,这个库非常容易“开箱即用”。当然,理解机器学习算法的细节很重要,成功的 Scikit-Learn 模型需要进行适当的调整以产生良好的预测;但是,即使是默认的超参数通常也会产生合理的结果。(事实上,对于最近的分类模型,我发现在运行网格搜索后,决策树的 fit 方法的默认参数比推荐的超参数产生了更好的结果!)
此外,因为 Scikit-Learn 是一个库而不是一个框架,所以使用起来要简单得多。该库的用户只需要导入他们想要使用的给定功能所需的包,然后从具体的类中实例化对象。不需要从指定的类层次结构继承,也不需要反转控制。
接口
该库是围绕三个基本 API(接口)组织的:预测器 和 转换器 。重要且关键的是,这些接口是互补的——它们并不代表类之间的严格界限或精确的语义分离,而是一种重叠。例如,决策树分类器既是估计器又是预测器——稍后会详细介绍。
评估者
估计器代表 Scikit-Learn 中的核心接口。所有的学习算法,不管是有监督的还是无监督的,分类,回归,还是聚类,都实现了 Estimator 接口,并公开了一个 fit 方法。
估计器的 拟合 方法将(训练)特征向量(“样本”或“预测器”)以及(训练)目标标签(在监督学习的情况下)作为输入,通过这种方式,估计器“学习”如何对看不见的数据进行预测(同样,在监督学习的情况下)。
一个关键的设计原则是,估计器的实例化(例如,您表示模型的超参数)与学习过程(您用训练数据(您的特征向量,例如,“X_train”)拟合模型)是分离的;以及您的训练标签/目标变量,例如“Y_train”)。也就是说,当你构造一个估计器(比如前面提到的决策树分类器)时,你传入超参数,但是你传入的是训练数据的 而不是;训练数据通过 fit 方法传入。正如“API 设计…”一文中提到的,这种分离类似于“部分函数应用”的思想,其中某些参数被绑定(或冻结)到一个函数,然后该函数(及其冻结的参数)被传递到另一个函数——一种高阶函数,或函数组合。事实上,这种“模式”可以说是由 Python 标准库通过 functools.partial 支持的。
这种解耦也可以通过更具侵入性的类机制来实现,也就是说,通过引入另一个类层次结构。然而,Scikit-Learn 的创建者明智地选择了更务实的道路,即使表面上看起来 Estimator 类似乎合并了两个语义边界。
从机器学习的角度来看,估计器是一个
管理模型的估计和解码的对象。该模型被估计为以下确定性函数:
-对象构造中提供的参数或 set_params 提供的参数;
-如果估计量的 random_state 参数设置为 None,则为全局 numpy.random 随机状态;
-以及传递到最近一次对 fit、fit_transform 或 fit_predict 的调用的任何数据或样本属性,或者在对 partial_fit 的一系列调用中以类似方式传递的数据。" (Scikit-Learn 词汇表)
预言者
Scikit-Learn 界面选择的一个令人困惑的方面是预测器与估计器的分离;预测器扩展了估计器接口,对于一个要“工作”的给定模型,它必须实现(并公开)一个 预测 方法。事实上,Scikit-Learn 的词汇表将预测器定义为“支持预测和/或 fit_predict 的估计器”然而 Scikit-Learn 通过 API 在语义上将这两个概念分开。虽然这不是一个关于如何使用库的教程,虽然这可能是显而易见的,但是模型作为预测器接口的一部分实现的方法做了预测结果的工作——给定测试特性;并且在模型被训练之后,预测器返回给定输入特征向量的预测标签。预测器也可以提供概率和预测分数,这是另一个设计原则的一部分(稍后讨论)。**
下面的类图表示了一个通用分类器——决策树——的特定类层次结构,其中我们看到该类既作为一个估计器(事实上它的 通过继承是 一个估计器)又作为一个预测器——因为它实现了 预测 方法。此外,它提供的 score 方法(返回给定测试数据和标签的平均准确度),源自一个“mixin”类——“classifier mixin”。所谓的“mixin”类是分离和打包特定功能(通常通过单个类方法提供)的标准方式,用于简单继承,同时避免“可怕的菱形模式”,这是多重继承的一个危险。

虽然类机制很好地协调和平衡了设计和实现的复杂性,但代码接口非常简单易用,允许您用三行代码实例化、拟合和使用模型:
变形金刚(电影名)
毫不奇怪,变压器会修改数据。“API 设计…”一文说得好:
预处理、特征选择、特征提取和降维算法都作为库中的转换器提供。
像模型一样,变形金刚也需要安装,一旦安装完成,就可以调用它们的 转换 方法。为了保持库的优雅和一致的简单性, fit 方法总是返回它所调用的 估计器 ,允许您链接 fit 和 transform 方法。为了方便起见,变形金刚还支持一个fit _ transform方法,因此用户可以一步完成这两个操作。
下面的类图显示了 StandardScaler 转换器也是一个估计器,并且也混合了 TransformerMixin 类。然而,使用这个转换器的代码非常简单。

透明度
用于构建估计器和转换器的所有超参数,以及拟合和预测的结果,对于界面的用户来说都是可见的公共属性。从表面上看,这似乎违背了封装和信息隐藏原则,这些原则长期以来一直是面向对象设计的标志,在面向对象设计中,对象状态通常只能通过类方法的中介来实现。但是这种设计选择极大地简化了库(通过避免访问方法的扩散):因为接口已经是一致的(并且既清晰又有说服力),添加免费的方法来获取关键的模型属性或预测结果只会降低其有效性。
核心数据结构
该库的设计者同样做出了直接而具体的决定,将机器学习所需的核心数据表示基于 Numpy 多维数组——而不是引入一组定制的类来封装表示特征和标签/目标的数据。与许多其他选择一样,这降低了进入的障碍,可以说,用户不必学习机器学习数据表示的新的类层次结构,以及确保时间和空间方面的性能,因为 Numpy 使用 c 针对性能进行了优化。
合成估算器-管道
所有核心语义组件——估计器、预测器和转换器——之间的一致和统一接口为该库提供了额外的能力和灵活性,允许用户通过将估计器链接在一起来组成新的或增强的功能。记住,变压器是一种估计器(回想一下上面的 StandardScaler 的类图,从 BaseEstimator 派生而来),Scikit-Learn 提供了一个管道类,允许用户将多个变压器链接在一起;因为所有的转换器共享相同的接口,所以管道可以将用户的数据适配到所有的转换器(通过迭代构造它的转换器的集合),然后,如果 fit_transform 也被调用,则应用转换并返回转换后的数据。下面的代码片段演示了用相似特征的平均值填充缺失值(通过 SimpleImputer 类),然后缩放数据(通过 StandardScaler 类)是多么容易。
通过 Duck-Typing 的可扩展性
我想提到的最后一个设计原则是库对所谓的鸭式输入的依赖,以允许对库进行扩展。鸭子类型化意味着如果一个类支持一个特定的方法——也就是说,如果它“看起来像一只鸭子”——那么它可以与同一接口的其他对象互换使用——也就是说,它 是一只 鸭子。这避免了对继承的需要,从理论上讲,这使得代码不那么紧密耦合、脆弱和复杂。也就是说,如果用户想要扩展库,例如,通过编写定制的转换器,他们不一定需要从 Scikit-Learn 类继承。通过这种方式,库的创建者将 Pythonic 的灵活性和实用性带到了 Scikit-Learn。
结论
数据科学家,无论是学生还是专业人士,都很幸运拥有如此丰富和设计良好的库,如 Scikit-Learn,它允许我们用漂亮和设计良好的代码来处理复杂的机器学习问题。
参考
Lars Buitinck,Gilles Louppe,Mathieu Blondel,Fabian Pedregosa,Andreas Mueller,Olivier Grisel,Vlad Niculae,Peter Prettenhofer,Alexandre Gramfort,Jaques Grobler,Robert Layton,Jake Vanderplas,Arnaud 乔利,Brian Holt,gal Varoquaux,“机器学习软件的 API 设计:scikit-learn 项目的经验”,https://arxiv.org/abs/1309.0238,2013 年。
aurel in géRon,使用 Scikit-Learn 和 TensorFlow 进行机器学习,O'Reilly Media,2013 年
编辑描述
scikit-learn.org](https://scikit-learn.org)**
Scikit-Learn 与机器学习的 MLR
检查两个库的 ML 工作流

Image Source: stokpic
Scikit-Learn 以其易于理解的 API 而闻名,对于 Python 用户来说,MLR 成为了流行的 Caret 包的替代品,提供了更多的算法套件和一种调整超参数的简单方法。这两个包在某种程度上是相互竞争的,因为许多参与自动分析的人转向 Python 进行机器学习,R 进行统计分析。
偏爱 Python 的原因之一可能是因为当前机器学习的 R 包是通过包含该算法的其他包提供的。这些包通过 MLR 调用,但是仍然需要额外的安装。甚至需要外部特征选择库,并且它们还需要满足其他外部依赖性。
Scikit-Learn 被称为许多机器学习算法的统一 API,不需要用户调用任何库。
这绝不意味着怀疑 R。不管在线调查结果如何,R 仍然是数据科学领域的一个重要组成部分。任何有统计学或数学背景的人都会知道为什么你应该使用 R(不管他们自己是否使用它,他们认识到了它的吸引力)。
现在,我们将看看用户如何经历典型的机器学习工作流。在 Scikit-Learn 中,我们将继续学习 MLR 中的逻辑回归和决策树。
创建您的培训和测试数据
train <- sample(1:nrow(data), 0.8 * nrow(data))test <- setdiff(1:nrow(train), train)- MLR 没有用于子集数据集的内置函数,因此用户需要依赖其他 R 函数来实现这一点。这是一个创建 80/20 训练测试集的例子。
选择算法
makeLearner('classif.rpart')。这个算法被称为学习器,这个函数被调用来初始化它。makeClassifTask(data=, target=)。如果我们正在做分类,我们需要进行一个调用来初始化一个分类任务。这个函数将接受两个参数:训练数据和目标变量的名称。
超参数调谐
在任一软件包中,优化超参数时都有一个过程要遵循。您首先需要指定要更改哪些参数以及这些参数的间距。然后进行网格搜索或随机搜索,以找到参数估计的最佳组合,从而获得最佳结果(即误差最小化或精度最大化)。
Scikit-Learn
C = np.logspace(0, 4, 10)
max_iter= [100,110,120,130,140]
hyperparameters = dict(C=C, penalty=penalty, dual=dual, max_iter=max_iter)
GridSearchCV(logreg, hyperparameters, cv=5, verbose=0)
clf.fit(x_train, y_train)
最低贷款利率(minimumlendingrate)
makeParamSet( makeDiscreteParam("minsplit", values=seq(5,10,1)), makeDiscreteParam("minbucket", values=seq(round(5/3,0), round(10/3,0), 1)), makeNumericParam("cp", lower = 0.01, upper = 0.05), makeDiscreteParam("maxcompete", values=6), makeDiscreteParam("usesurrogate", values=0), makeDiscreteParam("maxdepth", values=10) )
ctrl = makeTuneControlGrid()
rdesc = makeResampleDesc("CV", iters = 3L, stratify=TRUE)
tuneParams(learner=dt_prob, resampling=rdesc, measures=list(tpr,auc, fnr, mmce, tnr, setAggregation(tpr, test.sd)), par.set=dt_param, control=ctrl, task=dt_task, show.info = TRUE) )
setHyperPars(learner, par.vals = tuneParams$x)
培养
这两个软件包都提供了训练模型的单行代码。
这可以说是这个过程中最简单的步骤之一。最困难的步骤是调整超参数和特征选择。
预言;预测;预告
就像训练模型一样,预测只需要一行代码就可以完成。
Scikitlearn 将返回预测标签的数组,而 MLR 将返回预测标签的数据帧。
模型评估
评估监督分类器最流行的方法是一个混淆矩阵,你可以从中获得准确度、误差、精确度、召回率等。
Scikit-Learn
confusion_matrix(y_test, prediction)或者classification_report(y_test,prediction)
MLR
performance(prediction, measures = list(tpr,auc,mmce, acc,tnr))或calculateROCMeasures(prediction)
这两个软件包都提供了多种获取混淆矩阵的方法。然而,对于尽可能简单的信息视图,python 不如 r 信息丰富。第一个 Python 代码将只返回一个没有标签的矩阵。用户不得不返回到文档中去辨认哪些列和行对应于哪个类别。第二种方法具有更好和更丰富的输出,但它只会产生精确度、召回率、F1 分数和支持度;但这也是不平衡分类问题中更重要的性能指标。
判定阈值(即改变分类阈值)
分类问题中的阈值是将每个实例分类到预测类别中的给定概率。默认阈值将始终为 0.5(即 50%)。这是在 Python 和 R. R 中进行机器学习时的一个主要区别。R . R 提供了一行代码的解决方案来操纵阈值以解决类的不平衡。Python 对此没有内置函数,而是由用户通过定义自己的自定义脚本/函数来以编程方式操纵阈值。

pair of graphs showing decision thresholds
Scikit-Learn
- 在 Scikitlearn 中没有一种标准的阈值方法。查看这篇文章,你可以自己实现它:在 Scikit-Learn 中微调分类器
MLR
setThreshold(prediction, threshold)。mlr 中的这一行代码将自动更改您的阈值,并可以作为参数来计算您的新绩效指标(即混淆矩阵等)。)
结论
最后,在处理机器学习时,mlr 和 Scikitlearn 都有各自的优点和缺点。这是使用其中一种进行机器学习的比较,并不能作为使用其中一种而不是另一种的理由。对这两方面都有所了解,才能给职场上的人带来真正的竞争优势。对流程的概念性理解将使工具的使用更加容易。
原载于 2019 年 8 月 21 日【https://blog.exxactcorp.com】。
体育界数据科学/分析的范围
你好世界!!在本文中,我们将讨论在体育界,先进的分析和预测建模如何胜过常规的定制/传统分析。我们已经见证了人工智能和最先进的机器学习模型如何超越旧的分析师方法,其分析已经重塑了许多企业的运营。令人惊讶的是,尽管有如此丰富的数据,体育分析的采用却相当坎坷和不均衡。
只是在最近,体育分析已经成熟,即使如此,还有足够的渗透空间。2016–2022 年体育分析预测估计,2022 年,40.1%的 CAGR 可能达到 39.7 亿美元的价值。认识到我们将在体育世界中处理的数据范围,利用分析是非常有意义的。每天,体育界都在不断提高其使用体育分析工具来提高胜率的能力。
为什么体育分析正在改变世界?
基本上,体育分析是为直接参与比赛的运动队或体育博彩公司进行的。
体育分析可以解释为使用与任何体育或游戏相关的数据。像统计球员,天气情况,球队最近的胜败等。有了这些数据,我们可以创建预测性的机器学习模型,代表管理层做出明智的决策。运动分析的主要目标是提高团队表现,增加赢得比赛的机会。一场胜利的价值说明了一切,并以不同的形式表现出来,如涓涓细流渗透到体育场座位上的球迷、电视合同、球迷商店商品、停车、特许权、赞助、注册、保留和当地自豪感。
主要团队及其分析合作伙伴
- 皇家马德里和微软,世界上最大的足球俱乐部之一-皇家马德里-正在使用微软技术来转变其运营、性能、健身以及与 5 亿全球球迷的关系。
- 曼联和怡安,像全球成千上万的企业一样,曼联足球俱乐部依赖怡安作为长期值得信赖的顾问,寻找创新的解决方案,使他们在竞争中保持领先地位。
正如我们所见,顶级全球体育品牌使用先进的体育分析,在整体表现、健身和与粉丝的关系方面保持领先。
体育分析用例
预测分析
主要用例是进行预测分析,这可以提供关于团队在比赛日应该如何的见解。哪个实习生给的团队表现更好,增加了团队的获胜概率。
使用我们的机器学习模型,我们可以预测比赛日哪个球员在哪个位置上表现更好。我们的模型将建立在球员的数据基础上,他在与对手的比赛中表现如何,比赛条件如比赛是主场还是客场,等等。因此,在给定比赛条件和我们面对的对手的情况下,我们可以预测哪些球员适合哪个位置。
- 球员分析 ,我们可以通过分析每个球员的训练模式和饮食图表来改善他们在球场上的表现和健康水平,然后根据我们的分析改进这些。
- 团队分析 ,使用团队统计数据,我们可以建立最先进的机器学习模型,如深度神经网络、支持向量机等,以帮助团队管理人员计算获胜组合及其概率。
- 粉丝管理分析 ,有了社交把手数据,我们可以在粉丝群内发现模式,使用聚类算法形成聚类/群组,针对目标群体开展活动。知道了最能吸引粉丝的因素,团队管理层就可以专注于改善这一方面,从而获得新的粉丝群并留住老粉丝。
使用高级可视化技术提供见解
在当今以数据为中心的世界中,数据可视化是一个至关重要的工具,体育领域也不例外。使用表格格式的原始数据,管理层无法获得清晰的见解,并且需要很长时间来浏览整个数据并掌握内容。因此,以图形格式呈现数据使管理层能够看到通过图形和图表直观呈现的分析,因此他们可以掌握困难的概念或识别新的见解。
图形表示的下一步是交互式可视化,您可以通过使用 tableau、clickview 和 rshiny 应用程序等技术深入了解图表和图形,以获得区域级别的更多详细信息和洞察力,从而以交互方式改变您看到的数据深度及其处理方式,从而将这一概念向前推进一步。
- 球队经理仪表盘, 球员比赛表现统计数据将以互动仪表盘格式呈现,以便更好地了解比赛情况。
- 球迷仪表盘 ,球迷可以获得自己喜欢的球员的比赛数据,并可以与对手或同队的其他球员进行比赛对比。

了解粉丝网络
每个运动队都有自己热情的粉丝群,他们需要一种方式来更好地与他们联系,无论他们在世界的哪个角落。我们的反应式仪表板允许他们与粉丝一对一互动,创建有针对性的促销活动,并使用收集的数据来跟踪和分析粉丝行为。这样管理层就知道,是什么驱使他们的球迷为他们的球队疯狂,并为此付出更多。
- 找到共同兴趣,利用从脸书、推特、Instagram 等社交平台收集的数据,我们可以分析最吸引球队热情粉丝的因素,并据此开展宣传活动。
进入体育赌博的世界
体育分析不仅对体育领域内外产生了巨大影响,还促进了体育博彩行业的发展,该行业约占全球博彩行业的 13%。价值在 7,000-1,000 亿美元之间的体育博彩在各种群体中非常流行,从狂热的体育迷到休闲赌徒,你很难找到一项职业体育赛事不依赖结果。许多赌徒被体育赌博所吸引,因为他们在做决定时有大量的信息和分析。
我们到此结束,希望我已经给了一些体育分析世界的介绍。查看其他作品这里。关于未来的讨论,请联系媒体、 Linkedin 、脸书。
酷热:随着全球纪录的暴跌,圣保罗遭遇了有史以来最热的第三季度之一
7 月至 9 月是这个城市国家过去 36 年来经历的最热的三个月之一,2019 年将打破气温纪录。

File photo, circa Singapore 2015. Photo: Chua Chin Hon
新加坡也未能幸免于最近席卷全球的创纪录热浪。
如果有什么不同的话,对这个城市国家 2019 年 7 月至 9 月的天气数据的检查表明,新加坡遭受了一场长时间的热浪,其强度明显高于同期的长期平均水平(即 2019 年第三季度数据与往年第三季度数据的对比)。
在 2019 年第三季度的 92 天中,有 84 天,即 10 天中的 9 天,日平均气温超过了 7 月至 9 月 27.92 摄氏度的长期平均值,这是自 1983 年以来的最高水平。
2019 年第三季度还有 81 天的日最高气温超过了同期 31.39 摄氏度的长期平均气温,与 1997 年新加坡和世界遭受厄尔尼诺效应冲击时创下的当前纪录持平。
气象局早些时候表示,2019 年 8 月可能是自 1929 年有记录以来最干燥和最温暖的 8 月,2019 年将创造新的温度记录。
目前还不清楚新加坡的天气是否已经转向新常态。但是趋势线确实指向一个令人担忧的方向。
数据和基准
比较天气记录总是很棘手,即使对于像新加坡这样的小城市国家也是如此。这在很大程度上取决于您使用的数据,以及用于比较的基准和时间框架。
在这篇文章中,我将使用 36 年的天气数据集,这是我之前从新加坡气象局的网站上收集的。因此,这里提到的“长期”是指 1983 年至 2019 年(9 月)之间的时期。这些数据在早期的 Jupyter 笔记本中进行了预处理,我已经用 2019 年 7 月至 9 月的数据进行了更新。
为了确保进行同类比较,我主要将 2019 年第三季度的数据与前几年的第三季度数据进行比较。如果你对所有季度进行比较,结果会有所不同,包括 12 月这样较冷的月份。
数据探测和温度记录
浏览数据,很快就发现 2019 年第三季度没有打破任何单日气温记录。
例如,在过去的 36 年里,最高日最高温度是 36 摄氏度,记录在一个闷热的 1998 年 3 月 26 日。但 2019 年第三季度记录的最高日最高气温“仅”为 34.3 摄氏度(9 月 28 日),远低于该数据集中的纪录。
1998 年 5 月的两天——5 月 21 日和 5 月 28 日——共同保持了 30.9 摄氏度的最高日平均气温纪录,比 1983 年至 2019 年期间的日平均气温高出约 3.23 摄氏度。这一长期纪录几乎没有受到 2019 年第三季度最高日平均气温 29.8℃(8 月 12 日和 8 月 16 日记录)的威胁。
虽然 2019 年第三季度的数据没有打破任何单日记录,但仔细观察发现,这一时期的平均气温都高于长期平均水平。
例如,2019 年 7 月至 9 月的日平均最高气温为 32.59 摄氏度,比 1983 年至 2019 年期间的长期平均气温 31.52 摄氏度高出 1.07 摄氏度。
同样,2019 年第三季度的日平均气温和日平均最低气温分别比这两个类别的长期平均气温高 1.39 摄氏度和 1.97 摄氏度。
当你比较苹果和苹果时,这种趋势变得更加明显,也就是说,相互比较第三季度的温度记录,而不是整体的长期平均值,其中包含较冷的月份。
2019 年第三季度的日平均最高气温(32.59 摄氏度)比 1983 年至 2019 年期间同类第三季度长期平均气温 高 1.2 摄氏度。
同样,2019 年第三季度的日平均气温和日平均最低气温都高于 1983 年至 2018 年第三季度的长期平均气温。


这可以通过一些图表得到最好的说明。
2019 年第三季度与第三季度长期天气数据
至少可以说,这种对比是惊人的。2019 年第三季度的平均气温在所有三个类别中都明显升高,包括最低日气温,这意味着我们将迎来更热的白天和更温暖的夜晚。

By default, Seaborn line plots aggregate over multiple y values at each value of x and shows an estimate of the central tendency and a confidence interval for that estimate — which was turned off for this chart.
2019 年第三季度的记录也违背了长期趋势,如灰色线条所示。总的来说,从七月到九月,气温往往会下降。
但引人注目的是,2019 年第三季度的最高日气温随着月份的推移而飙升,从 7 月到 9 月平均呈现持续上升的趋势。与此同时,2019 年 9 月底的日平均气温几乎与 7 月初持平,与第三季度末略有降温的长期趋势形成鲜明对比。
2019 年第三季度的最低日气温遵循了更符合长期趋势的形状,但它比我们在 1983 年至 2018 年期间经历的温度高得多,如上图的第三个子图所示。
2019 年第三季度与 2016 年第三季度和 1997 年第三季度
我们还可以做单年对比。对于下面的图表,我选择了 2016 年和 1997 年第三季度的数据,因为这两年都有很长的高温期。
新加坡气象局称 2016 年是这个城市国家有记录以来最热的一年。1997 年,由于“T4”厄尔尼诺现象,新加坡和当时世界上的许多地方一样,遭受了长时间的酷热和干燥天气。

一眼看去,很明显,2019 年第三季度的温度-由红色实线代表-比 2016 年和 1997 年的类似时期更高。
正如媒体今年早些时候报道的那样,2019 年看起来肯定会打破新加坡的年度气温记录。
快乐图或堆积密度图
流行的 joyplots 提供了另一种方式来可视化 2019 年第三季度与过去 36 年同期相比有多激烈。我将绘制一个版本来比较日平均气温。


这些差异再次显而易见:2019 年第三季度的日平均气温分布(右侧图表)与长期趋势(左侧图表)相比,显示出明显的右移,标志着一个更高的温度时期。
比较日平均温度和日最高温度高于长期平均温度的天数
说明 2019 年第三季度相对于其他年份的第三季度有多热的另一种方法是比较数据集中汞飙升至第三季度长期平均值以上的天数。
我要用的两个基准是:
*31.39℃:1983 年至 2018 年间 7 月至 9 月间记录的日平均最高气温。
*27.92℃:1983 年至 2018 年间 7 月至 9 月间记录的日平均气温。

2019 年第三季度,有 81 天的日最高气温超过了同期 31.39 摄氏度的长期平均气温,与 1997 年创下的当前纪录持平。

在 2019 年第三季度的 10 天中有 9 天(准确地说是 92 天中的 84 天),日平均气温超过了 7 月至 9 月 27.92 摄氏度的长期平均值。按照这个标准,这是我们自 1997 年以来看到的最高水平。如果您使用不同的基准进行比较,结果会明显不同。
2019 年第三季度是有记录以来最热的第三季度吗?
没有完整的数据——新加坡有文字记载的温度记录可以追溯到 1929 年——很难说清楚。这在很大程度上还取决于您采用的比较基准和时间框架。
我不是训练有素的气象学家,也不是新加坡天气专家,所以我不能说我在这里使用的基准和假设是否反映了该领域可接受的规范。
但 2019 年第三季度肯定是我们在新加坡过去 36 年中看到的最温暖的三个月之一,也可能是未来更不舒服的时期的一个迹象。
这篇文章的 Jupyter 笔记本可以在这里找到,旁边还有处理过的数据集。
我之前尝试想象和分析新加坡不断变化的天气模式,可以在这里找到这里和这里。
像往常一样,如果你发现任何错误,ping 我@
推特: @chinhon
领英:www.linkedin.com/in/chuachinhon
评分和排列
深入分析
和 Nick Scavo 对 20,783 个 Pitchfork 评论的探索性数据分析

数据集使用:20783 条干草叉评论
尼克·詹姆斯·斯加沃 是一位居住在纽约的音乐家和作家。他与实际的学校合作进行各种个人和合作项目,定期向微型混音带提供评论和论文,并与现代艺术博物馆 PS1、艺术家空间、新博物馆、根茎、控制合成器和电子设备合作,并在 NTS 电台常驻。他是 发行项目室 的传播总监兼助理策展人。
在整个访谈中,“钟形曲线”一词被不严格地用来指任何单峰分布,其中中间值附近的值表示评估分数的中间值,而不是指对称分布。
安德鲁·汤普森(Andrew Thompson):我认为应该从 Pitchfork 的分数分布图开始,看看 Pitchfork 是如何对事物进行评级的,以此来考虑 Pitchfork 评级的想法和这个评估系统。

Fig. 1
这是他们分数分布的直方图。干草叉的平均分数几乎正好是 7,中位数是 7.3。从你的角度来看,干草叉评级系统是什么?它的意图和效果是什么?
尼克·斯加沃:当你看到这样一个模型时,我不禁会想到根据钟形曲线来评分。因此,很明显,从专家或教授到评论家,都存在一种假定的教育权力动态,以某种方式给表演打分。我觉得在批评史上,你通常没有一个实际的数值。在很大程度上,在 20 世纪艺术史中,你有某种智力参与。但在 21 世纪初,随着 Pitchfork 和类似的出版物的出现,评论家们通过在工业化条件下运作来反映他们正在处理的内容——他们开始给美学作品赋予数字价值。我认为这可能是相对特定于音乐形式的——例如,在视觉艺术中看到量化的价值是很奇怪的。你能想象有人给 MoMA 最近的展览打分吗?
没有,但是你会看到一些量化电影的尝试,这可以追溯到 90 年代
像罗杰·伊伯特一样
在:右,拇指向上拇指向下,这已经转移到烂番茄汇总成元评论的任何内容。有了 Pitchfork,它总是把像罗杰·伊伯特这样的人和使用这种系统的其他人区分开来,这是他们声称评估一件作品的准确性——这是一种分米精度,可以衡量一件事情的好坏。当你说某样东西是 7.7 时,你是说它不是 7.6 或 7.8,它就是这么有价值。甚至没有恒星系统的模糊性,比如一到五颗恒星。就像他们试图超越任何一种分数的可解释性或三星级评论可能暗示的任何普遍性的承认,相反,它传达了这种科学主义。
NS :这很奇怪,因为虽然它看起来像是精确或科学的,就像钟形曲线一样,但它是一种更相关的数字。之所以评分是 7.7 而不是 7.6,是因为也许另一张专辑被给了 7.6,我们需要看着那张专辑断言这张专辑更好。因此,在某种程度上,它遵循一条线,这条线是根据一系列相互发展的点绘制的——这就是你在这里看到的:音乐评论的独特分布。当你回顾过去的一年,回顾 2010 年所有最好的新音乐时,你会看到 Pitchfork 的作者给出的一系列文化价值观,然后你会看到给它们的不同的数字分数。这总是很奇怪,因为你会有人给某张专辑打 10 分,但往往这张专辑不是年度最佳专辑。这是一个非常松散的,有争议的,相关的数字情况,几乎有一个错误的或伪量化发生。
是的,我的意思是,毫无疑问这是假的。这里面也有愤世嫉俗的唯物主义。我记得在我听了 Sote 的设计的神圣恐怖之后,我想这是我去年听到的最好的事情之一,我认为我真正理解了艺术体验的概念,当我听到这个想法时,就像打开了世界。干草叉给了它…让我看看他们给了它什么。他们有 7.8 分。这张专辑的体验是完全非物质的,对吗?看到这张专辑的评分降到 7.8 分,我对音乐的精神感到非常矛盾。
我百分之百同意。归根结底,这是建立权力或权威的一种方式。这是对客观性的一种尝试,但我认为它不适用于这种情况。我的意思是,很明显,干草叉评论是一个作家量化的尝试。但是,作为一名读者,我们的任务是对量化做出回应——我是同意还是不同意这一点?人们对这种情况很着迷。这就是为什么人们总的来说对社论或专栏文章着迷——他们想不同意作者的观点,当他们看到一个分数时,这几乎是一种耸人听闻的挑衅。他们甚至不用读任何东西。他们只是看到这个荒谬的数字,只是对它吐口水,然后你在午夜的时候在互联网上等待下一个 Pitchfork 评论——我真的不认为现在是这样了,但在其全盛时期,有一段时间我会在午夜刷新页面,看看新的 Pitchfork 对一张专辑的评论,只是看看它被赋予了什么价值。在 2008 年和 2009 年左右,那是独立在线网络博客“品味制作”的巅峰时期。我觉得这已经从信息来源的纯粹多样性中扩散了一点点。当你看这个分布时,我认为你能做的最安全的事情就是给某样东西打 7.8 分。它本质上只是确认记录——你必须质疑以这种方式写评论的目的。在这种情况下,我认为这是公关周期的一部分。一个极低的评价或者一个极高的评价都有一种耸人听闻的性质,这将在公共话语中造成某种破裂。如果一张专辑获得了 Pitchfork 10,这是非常罕见的事情。记录低于 3、2 或 1 的情况同样罕见。我会对这些数据提出这样的问题:也许从 2009 年、2010 年开始,随着音乐变得更加工业化,通过 Pitchfork 这样的东西在我们的消费中变得更加普遍,我只能猜测平庸、中值/均值评论的实际数量只会上升。

Fig. 2.1

Fig 2.2
在:好吧,让我们看看……中间值有一点移动(图 2,顶部),但方差实际上已经下降了(图 2,底部)。
NS :相当狂野。早期互联网音乐评论的自由自在的日子。
自 2001 年以来,它下降了…那是什么…超过 30%。所以你在某种程度上是对的。随着时间的推移,分数越来越接近中间值。
我认为这表明它已经变得不那么独立了。当你有一个更大的分数偏差时,你会有非常不同的观点,对音乐做出非常不同的断言。你会看到人们一路向左,然后一路向右,而不是更多的中间路线评论,我认为这是一种正常化,反映了我们在过去 20 年里看到的每一种经济趋势——包括美国的政治话语。
AS :万物无情同质化。
NS :不要太随意地使用这个词,但这是一种超正常化,这种字面意义上的将偏差挤压到更紧密的集合中。东西靠得更近了,它们受到限制,不能像以前那样移动。
AT :我的意思是,一方面,看着这张原始图表,也许可以说,工作确实是按照这种形状进行的,大部分工作都很一般:有大量糟糕的工作,但有一小部分确实很棒。那么有没有什么可以说这反映了艺术的现实呢?即使他们的数字系统是一种虚假的客观性,在这种虚假的客观性中,它正在描绘出事物的形状?
我认为这是一个我们必须质疑的说法。我认为这是一个在我们看待事物的方式中占主导地位的模型,钟形曲线,其中大部分作品是平庸的,很少一部分是精选的,天才的作品。这是一个我们不得不质疑的神话,因为它在西方思想和资本主义中占据主导地位。这是一个模型,我们已经被编程为定期查看。我会说——我不相信品味的完全相对主义,但我想也许有一个更少等级,也许更分散的模型,来描述我们如何思考我们与艺术和审美体验的关系,这也许会看起来完全不同于钟形曲线。
在:你几乎可以把这两个图表连在一起【图 1 和图 2,底部】,并且说评论感觉几乎应该反映自然模型的想法。我刚才说的这个想法:这难道不反映自然吗?钟形曲线是自然的。显然,我们已经通过相信一切都必然符合钟形曲线,展示了历史上各种各样的问题。干草叉持续的时间越长,他们就越觉得自己需要为了牛市曲线而坚持下去,如果他们偏离了 7.3,7.4,这在某种意义上是不自然的。我认为这是一个好主意:也许有更多的作品,如果不是天才的话——也许我们应该完全抛弃天才作品的想法。
是的,我觉得我们有很多实验性的和批判性的模型来量化我们听音乐的体验,这真的很令人兴奋,值得谈论和思考。你可以提出一个又一个完全破坏钟形曲线的模型。你也可以用全新的方式用这些模型来写音乐。Pitchfork 特别令人沮丧的一点是,他们的音阶变得如此之小,这是他们一遍又一遍地使用同一个模型的近 20 年历史。我认为你看着这些数据并从中提取各种假设是正确的。当我们看这些数据时,我们看到的是我们在世界其他地方看到的同样令人沮丧的现实,那就是事情变得越来越不明显,越来越中间,越来越自动连接,在同样的 7.8 或 7.3 或 7.4 之后也是如此。如果你看看过去五年中最好的新音乐,实际上我们有更多市场准备好的,市场友好的最好的新音乐。所以它实际上是在执行一个行业功能。它以一种野心家的方式表现的能力被赋予了价值,因为这关系到音乐行业对它的期望,即销售唱片,成功巡演,在流媒体平台上表现出色。
这可能很难做到,因为它受制于历史的经济流动,但我很好奇,过去五年最好的新音乐是否比 90 年代或 21 世纪初或那个时候最好的新音乐有更好的盈利能力。
:如果不引入外部数据,只看评论本身,很难说,比如巡演收入、专辑销量或流媒体数据等等。但是我之前看这些数据时发现,Pitchfork 给 10 分的东西往往是这些怀旧的回顾。

Fig. 3.1

Fig. 3.2
NS :哦耶。再版。
****在处:右,龙刚。
NS :在这里,我们有后知之明是 20/20 的想法。当你能够回顾文化并说,那正是那个时代的时代精神时,你会有一个更完美的愿景。那张唱片确实总结了发生的 X 件事或其他什么。现在真正弄清楚什么是重要的要困难得多,尤其是当它变得模糊到第 n 度的时候。
****在的时候:感觉那个时候评审也不再冒险了,对吧?如果你对一个已经确立的批评意见表示肯定,你们两个都不会冒险,同时也把自己描绘成一个圣徒,对一张专辑的名声和它在音乐史上的地位负责。
越往后,分数越高。所以当你到了 10 年、20 年的时候,事情并不真的…过去有一些神圣的东西。
NS :我记忆中最难忘的 10 叉之一是电台司令的小子 A 。那是 2000 年左右的事了,当时我还很年轻,我觉得这个记录无可否认是完美的 10 分。根据我当时的教育和音乐听力,这是一本关于什么是好的实验音乐唱片的大部头。尽管我在 2000 年的时候认为这是一张晦涩难懂、声音怪异的专辑,但这时候电台司令并不是一个小乐队。Pitchfork 给这个记录打 10 分是一个非常有品牌效应的决定。许多其他出版物,大众媒体音乐出版物,都在谴责和反对他们从 OK 电脑转移声音。每个人都表现得很惊讶。但这也是 Pitchfork 的一个转变,因为我认为他们的受欢迎程度在 2003 年后呈指数增长,并持续到后期。**
我也想知道,在音乐评论文本中存在的形容词的分布是怎样的。
AT :你是说形容词的数量?
是的,比如音乐评论家在多大程度上依赖于用形容词来描述声音,以及形容词对我们理解声音的意义有多大帮助?有一种趋势是叙述音乐,用描述性的词来描述它,比如“粗糙”或者用隐喻,比如“往钢铁上泼水”。
形容词使用 Python 的空间库及其最大的英语语料库来识别。SpaCy 非常好,但是像所有自然语言处理工具一样,它并不完美。这里存在一些小错误,主要是在很少使用的单词的尾部,像“gyaaaah”这样的单词被标记为形容词。少数单词也没有被正确地识别为形容词,其中包括“天才”,不幸的是,图书馆总是将其识别为名词。
AT :在你看来,这些词有什么问题,一个人应该如何写音乐?
随着写作音乐和定期量化音乐并试图证实这种量化的实践,我们常常不得不去看实际的文本,去看那些用来赋予事物意义的词。因此,为了支持某事的 8.8 或其他什么,我们必须看看用来庆祝它们的形容词,并确定其在英语中的含义。通常这种语言无论如何都不是对音乐的实际辩护。这种写作不包含政治论点主张其意义,或社会评论。我们可能会在评论中偶尔看到这种情况,但我想说的是,捍卫可量化分数地位的主要方法是这种类型的描述性语言,这些脆弱的词——你可以像剥颜料一样剥下它们,它们就这样脱落了,当你剥去所有这些词时,你还剩下什么?《音乐评论》本身的实际主张是什么?
当你看这些评论时,这个人到底想说什么?这是一件很奇怪的事情?这就像一首时髦的音乐?在语言中,很难找到什么是真实的,用数字表示的量。这就是为什么我对形容词或者陈词滥调感兴趣,因为我觉得这些是第一道防线。
****在:所以这几乎就像量化的价值必须证明自己,几乎通过使用这些词,每个词本身都有一个值,并聚集在所有其他词的顶部,这相当于这个等于 8.1 或什么的马赛克。
NS :是的,因为正如我们已经说过的,数字使语言尴尬。作者知道这一点,必须用语言来证实。那是给作者的简报——他们必须以书面形式证实它,他们不能只给出一个数字。我们看到的一件事是大量的假设,这些假设反映了量化音乐本身的基本假设。你知道,我只是在意识形态上有所不同。我们必须——我的意思是,我也一直这么做,我经常用这样的语言来描述音乐。
我也一直在使用这样的语言。和“斯塔克”一样,我也一直用“斯塔克”这个词。不一定用声音,但是我们用形容词来描述事物,比如“缥缈的”。如果是“缥缈”,是不是一定要不说是缥缈?
我真的对这些词没有问题,事实上,我认为它们让人联想到某些画面。通常,这些单词是我们已经非常具体地理解的关系建立的单词——这是语言的惊人之处之一,它被编码为具有这些特定的互文意义,当你将它们配对在一起时,它们创建了这些富有诗意和表现力的酷结构,可以触及事物的核心。我想说的是,这些词和数字之间的关系完全是个问题,在语言中用来捍卫数字的策略是我希望看到进一步证实的东西,我希望梳理出这些说法。也可能只是纯粹的诗歌。如果这只是纯粹的诗歌,那就更让人质疑这个数字的用途了。
基本上你要做的就是描述…这有点,我确定在电影中有这些书面的比喻。在影评中,影评人经常说:“不要只叙述情节”,这在影评中是不被认可的。而在很多方面,音乐评论不具备这一点。音乐评论希望你讲述专辑的架构,因为它在大多数时候并不明显。实际上只是不明显。听音乐只是一种幻觉。
****在:我想我总是在 Pitchfork 的语言中看到的是他们总是无法做到这一点,对吗?你对写声音有自己的想法。我不认为写声音是不可能的,但我认为写声音比写其他任何东西都难。
NS :当然,我认为音乐的幻觉性质让我们真的依赖某些语言修辞,真的让我们特别依赖形容词和这种真正描述性的语言来赋予它实质。从本质上来说,我们通过使用这些东西,自动地将叙事雕刻成声音,或者我们在谈论它时,给它一些它不具备的东西——那就是语言。或者我们必须通过隐喻来谈论它,或者我们必须赋予它社会或政治的价值来做到这一点。我认为在实际的评论文章中,有一些非常正式或结构性的东西是我想要注意的。如果我们在一个段落试图做的事情中分离出某些段落,比方说评论是七个段落,你可能会有三个或四个段落只是描述专辑。你可能会有一两个段落给出某种社会或政治背景,更广泛,然后具体到艺术家的职业生涯或什么的。所以你有这些非常具体的关键议程,它们实际上被编码到音乐评论的各个段落中。这可能是一个更大的数据项目,但几乎像给那些数字或东西。
就我而言,如果我们看看这个偏差[图 2,底部],如果我们得到越来越多相似的评分评论,我也会争论这些评论的实际形状,评论的文本变得越来越相似。所以基本上我们得到了这些回流的形式,它们遵循非常特定的脚本,以相似的方式给可能相同的音乐赋予相同的乐谱。所以我的意思是,在那个关头,除了肯定一般的公关活动,还有什么意义呢?在那一点上,它就变成了一种存在主义。就像,嗯,我们为什么要写音乐?这就是为什么我认为这个钟形曲线模型会破裂。实际发生了什么?
如果你回去读一些早期的干草叉评论,有一些真正奇怪的写作。在某种程度上,这是一个实验平台,随着事情沿着轨迹发展,这条线穿过更长的轨迹,你只会得到更多的一致性。你说的关于新询价 T3 的也有点像。作为一个出版平台,我认为新的调查最初是为一些非常狂热的写作或其他东西而设计的——论战、评论、文化下层阶级自由写作的一些出口。但是当它本身成为一个机构时,你就有了为新的调查写的东西意味着什么,你就有了你最终的这种形状或这种形式——这是它实际上试图做的事情的代表。
AT :这只是评论的长度。

Fig. 4. During the interview, the standard deviation (bottom right) was used to measure the variance of article length. This was arguably a mistake, although arguably not: While the standard deviation is considered formally improper method for the measure of variance for non-normal distributions (like the right-skewed distributions of review length), it is considered so because of the weight it places on outliers — in this case, unusually long articles. The discussion surrounded the idea of a normalization of writing in Pitchfork. If that type of homogenization had occurred, it would essentially preclude the existence of outliers almost altogether. It’s possible that although even if formally improper, the standard deviation, given the weight it does place on outliers, is a valid measurement in this particular instance. Still, the median absolute deviation is included in this array for clarity (bottom left). It shows no such increase in variance. Regardless, both graphs refute the hypothesis at hand — that Pitchfork’s articles have become more regular in size — and either statistic was capable of momentarily disrupting a stream of criticism and prompting a consideration of Pitchfork’s virtues.
在采访过程中,标准差(右下)用于测量文章长度的方差。这可能是一个错误,但也可能不是:虽然标准偏差被正式认为是非正态分布(如综述长度的右偏分布)方差测量的不当方法,但它被认为是如此,因为它对异常值(在这种情况下,异常长的文章)施加了权重。讨论围绕着干草叉书写规范化的想法。如果这种类型的均质化已经发生,它将基本上完全排除离群值的存在。尽管形式上不合适,但考虑到标准差对异常值的权重,它可能是这种特定情况下的有效度量。
尽管如此,为了清楚起见,这个数组中包含了中值绝对偏差(左下方)。它显示方差没有这样的增加。无论如何,这两个图表都驳斥了手头的假设——Pitchfork 的文章在大小上变得更加规则——并且这两个统计数据都能够暂时打断一连串的批评,并促使人们考虑 Pitchfork 的优点。
NS :长度上去了。
****在:嗯,长度的方差上升了【图 4,右下】。这些年来的长度是全面的(图 4,右上方),没有真正的模式。这是所有评论的评论长度分布图(图 4,左上角)。这并不能告诉你太多,事实上中值评论大约是 700 字。但这是长度的方差。所以现在的差异比以前要大得多。
NS :是有评论还是有特写?
AS :一切都是有分数的。因此,至少就评论的规模而言,我们可能必须在这方面对他们宽容一点。这就引出了另一个问题,干草叉有什么好的地方吗?在一天结束的时候,我宁愿干草叉存在,也不愿干草叉不存在,没有任何东西可以替代它。它仍然是康泰纳仕旗下的音乐出版物,根本不用写 Sote。他们可以完全忽略这些音乐,也不会有主流出版物讨论它们。所以在看到他们的方差上升的图表中,我想借此机会说一些关于他们的好话。
可能只是因为他们出版了更多,所以基于他们出版的规模会有更多的差异。有各种各样的事情可能会发生。
AS: 但它们实际上已经趋于平稳[图 5]。现在一年大概有 1200 条评论。我不知道这两者相比如何—

Fig. 5
NS :很多。我是说那就像一台机器,写了那么多东西。这很酷,我是说我喜欢这个事实。我想我要强调的一件事是,我认为这个模型有一系列的假设,我认为像 Pitchforks 这样的网站以他们这样做的方式量化审美体验,我认为这就是你所说的那种叙事性的东西,它如何与其他领域中存在的某些经济模型相匹配。但我也认为它存在于可量化的列表和内容排名中,这种情况不在审查范围之内。但我认为这最终是一种资本主义的思维方式。
AT :就像美国大学已经被这个系统毁了,对吗?我自己的大学,天普大学,他们的商学院因为捏造这些数据而陷入排名丑闻。
因为他们可以通过夸大这些数字来吸引更多的钱。
在**:在美国新闻中拥有更高的排名所带来的全部好处。
这是我们在几乎所有事情中都会遇到的同样的问题。在某种程度上,我几乎喜欢这种扁平化。如果说资本主义现实主义做了什么,那就是平抑了这种极端化,我们认为音乐是我们可以逃避的特殊的小东西,但当我们看到它如何在文化上改变自己时,我们看到的是同样的老一套。在这种情况下,我认为扁平化是有益的,因为它允许我们看到事物的本来面目,以及在出版和批评中使用的某些策略的动机,评论排名或其他。但是我的想法是,我们可以用很多其他的模式来谈论音乐。它必须是这个非常明显的,反映了一套非常具体的价值观吗?那是…当然,问题是,我们怎么才能爬上去呢?我们怎样才能让人们用这些术语或其他什么来写作呢?因为这就是我们所理解的。然后我们进入一个非常具体的政治讨论。
AT :这是很多数据可视化本身的问题。希望这不是我们现在正在做的事情的问题。但我为组件制作的第一件作品,就像是对顺序和数字的盲目崇拜。当你把一个数字或一种定量方法的出现与某样东西联系起来的时候,你就把它放在了遥不可及的地方,不仅仅是因为大多数人不使用这些方法,而且即使是那些真正理解这些方法的人也被它的存在所吸引,事实上你知道这种光芒来自哪里,你会情不自禁地感觉到它的温暖。
数字的出现几乎让语言变得尴尬,如果这有意义的话。说某事得到负面评价。就像今天,詹姆斯·布雷克,歌手,制作人,2010 年,2011 年我最喜欢的艺术家之一,因为他开始了这种新的制作风格,喜欢空间配音音乐,同时也是一个歌手兼作曲家,他制作了这张新专辑,他变得非常主流,我仍然尊重的少数几个干草叉作家之一发表了一篇评论,一个叫菲利普·舒尔伯恩的家伙,他给了这张唱片 5.8 分。我和他是脸书的朋友,他发了一条微博,“今天在 Twitter 上过得很糟糕”,因为他被这位艺术家的粉丝们激怒了,因为他给了这张唱片 5.8 分,而 Pitchfork 有着给他的唱片提供最佳新音乐的巨大历史。所以基本上就像,你知道他是一个非凡的作家,但 5.8 级的出现对詹姆斯·布雷克的粉丝来说是如此的可耻,以至于他们可以看看菲利普·舒尔伯恩的作品,然后就把他撕成碎片。文字变成了这种脆弱的防御,数字的存在和它如此强大的权威几乎吸引了人们去看这种语言,他们开始把它撕裂。在那一点上,这种语言实际上变得很可笑,因为你开始看它,这个数字只是在嘲笑这种语言。这个数字根本不在乎语言,整个事情就这样分崩离析了。
****在:谁也不在乎谁。
NS :差不多就是这诡异古怪的一对。然后你看着语言,模因开始产生,引用作者的话。如果你从中抽象出任何一句话,它看起来都很可笑。但是他有一个关于詹姆斯·布雷克职业生涯的观点,他在某种程度上做了很好的讨论。如果你只是边喝啤酒边和那个人聊他对音乐的看法——他住在巴塞罗那,在巴塞罗那的一个酒吧里,我肯定你会更开心地谈论唱片,或者实际上更多地了解他对唱片的看法。
AT :但是,你可以有一个没有号码的对话版本。去掉这个号码,你就可以在酒吧里进行那次谈话了。
再次,我认为是权威赋予了它那种耸人听闻的品质,并基本上使整个事情成为这个机器的一部分,你希望人们有那种反应,因为你想把事情放在美好的小地方并对它们进行排序。每个人都喜欢列清单。这是人类喜欢做的一件大事。我也喜欢列清单。我认为,列出一个 100 比 1 的列表,其中 1 是最好的,100 是最差的,与列出一个向各个不同方向扩散的疯狂的分形列表有很大的区别。
AT :对分类顺序的需求是如此强烈,以至于即使我们知道这个数字是扯淡,我们还是会情不自禁地对它做出反应,并以某种方式受到它的影响。
T2:我们要么庆祝它的存在,要么被它压迫。它实际上是权力的替身。它最终消除了关于音乐的语言和文字所能有效做到的细微差别,这是一个人在聆听体验中非常微妙、亲密的反映。这个数字的存在是荒谬的。这是荒谬的。就像…什么?它以最粗俗的方式困扰着写作。
****在:虽然数字是干草叉存在的必要条件,对吧?康泰纳仕拥有 Pitchfork 是因为 Pitchfork 公布了一个数字,人们点击就能看到。去掉这个数字,它们就不是康泰纳仕的财产了。这又回到了这个问题上—
NS :资本主义现实主义。
当然,我的意思是一切都回到那个问题上。但是问题是没有干草叉,没有任何东西可以替代它,还是有它。资本主义现实主义者对此的反应是,这实际上是你能得到的最好的了。在我们生活的这个系统的范围内,我们需要量化,测量任何时候的一切,Pitchfork 可能是你能得到的最好的版本。我是说,你还能得到什么?他妈的滚石?
是的,也许是大规模的。我认为这就是为什么我们把实验主义视为次要形式。你会看到这些本土的音乐写作社区或杂志或各种类型的东西,人们蜂拥而至来解决这个问题。

最初发表于components . one。**
用 5 行 Python 代码抓取并总结新闻文章
好程序员写的代码,伟大的先搜 github。

Photo by Thomas Charters on Unsplash
想从一群只做机器学习和可视化的数据科学家中脱颖而出?然后,您可以通过收集自己的数据集,而不是使用 Kaggle 中过时的 CSV 文件,提前一步开始。
在这篇文章中,我将向你展示如何以一种统一的方式从许多来源收集大量的新闻数据。因此,你将使用 newspaper3k 自动提取结构化信息,而不是花费数月时间为每个新闻网站编写脚本。
安装软件包:
$ pip install newspaper3k
现在让 newspaper3k 把文章刮下来,摘抄信息,给我们总结一下。
>>> from newspaper import Article>>> article = Article('https://www.npr.org/2019/07/10/740387601/university-of-texas-austin-promises-free-tuition-for-low-income-students-in-2020')>>> article.download()>>> article.parse()>>> article.nlp()
这是所有的乡亲。5 行代码,包括包导入。
如果您执行了之前的所有步骤,并且没有出现错误,您应该可以访问以下信息:
>>> article.authors['Vanessa Romo', 'Claire Mcinerny']>>> article.publish_datedatetime.datetime(2019, 7, 10, 0, 0)>>> article.keywords['free', 'program', '2020', 'muñoz', 'offering', 'loans', 'university', 'texas', 'texasaustin', 'promises', 'families', 'lowincome', 'students', 'endowment', 'tuition']
关于文本本身,您可以选择访问全文:
>>> print(article.text)University of Texas-Austin Promises Free Tuition For Low-Income Students In 2020toggle caption Jon Herskovitz/ReutersFour year colleges and universities have difficulty recruiting...
除此之外,您还可以获得内置摘要:
>>> print(article.summary)University of Texas-Austin Promises Free Tuition For Low-Income Students In 2020toggle caption Jon Herskovitz/ReutersFour year colleges and universities have difficulty recruiting talented students from the lower end of the economic spectrum who can't afford to attend such institutions without taking on massive debt.To remedy that — at least in part — the University of Texas-Austin announced it is offering full tuition scholarships to in-state undergraduates whose families make $65,000 or less per year.The endowment — which includes money from oil and gas royalties earned on state-owned land in West Texas — more than doubles an existing program offering free tuition to students whose families make less than $30,000.It also expands financial assistance to middle class students whose families earn up to $125,000 a year, compared to the current $100,000.In 2008, Texas A&M began offering free tuition to students whose families' income was under $60,000.
对于一个内置功能来说还不错。
要从所有功能中获益,包括自动订阅杂志和访问热门话题,请参考官方文档。
使用 newspaper3k,您可以收集独特的数据集来训练您的模型。更重要的是,在模型准备好之后,您将有一个真实的数据馈送,因此您也将能够看到真实的性能。
首先定义一个问题,然后才搜索数据,而不是相反。试着成为一个真正的问题解决者,思考你的模型如何解决真正的商业问题,因为这是你将会得到报酬的。
如果你喜欢这篇文章,我想强调的是,你应该读一下启发我的那篇文章。
用 Scrapy 刮多页
一个用 Scrapy 成功完成你的网络抓取项目的完整例子

Tetiana Yurchenko/Shutterstock.com
在这篇文章中,我将开发一个网络爬虫,它将从myanimelist上可用的每个漫画中收集信息。为此,我们将迭代几个页面和子页面来创建一个完整的数据集。
什么是 Scrapy?
Scrapy是“一个从网站提取你需要的数据的开源协作框架”。
我为什么选择 Scrapy?
有几种类型的框架库允许我们进行网络抓取。尤其是 Scrapy、Selenium、BeautifulSoup,仅举几个最著名的例子。
Scrapy 是一个专门创建的工具,用于请求、抓取和保存 web 上的数据,它本身就足以构建一个健壮的 web 抓取项目,而 BeautifulSoup 是一个实用程序包,只对我们访问 web 页面的元素有用,它通常需要导入额外的库,如 requests 或 urllib2 和其他库,以具有 Scrapy 功能的范围。
此外,
- Scrapy 强加了关于代码结构的习惯用法,这使得新手可以在网上找到非常有意义的例子,并很快掌握这个框架。
- 我们有一个特定于 scrapy 的 Shell,在准备部署之前,它可以用来调试脚本。
- 在一个 Scrapy 命令行中创建项目构建所需的所有附加文件(如 Django)。
- 最后 Scrapy 非常快,可以同时刮几十页。此外,还可以调整脚本的速度或其他参数。
开始你的项目吧!
我将向你展示完成一个抓取项目所需的每个步骤,并用 Scrapy 建立你的第一个数据集,在本教程中,我们将只使用:
- Anaconda 的命令提示符(任何其他要安装 scrapy 和 python 的命令提示符都可以)
- Scrapy 的壳
- Python 3.x
开始我们的项目,我们将安装 Scrapy。
pip install scrapy
conda install scrapy
然后,仍然在 anaconda 命令提示符下,我们将指向我们选择的文件,并告诉 Scrapy 我们想要开始一个新项目。我们将这个文件夹称为 MEDIUM_REPO。
cd /d c://path/MEDIUM_REPO
scrapy startproject WebCrawler
因此,Scrapy 已经创建了我的刮刀所需的每个文件,让我们来看看。其结构如下:
WebCrawler
│ scrapy.cgf
└───WebCrawler
│ │ __init__
│ │ items.py
│ │ middlewares.py
│ │ pipelines.py
│ │ settings.py
│ │
│ └───__pycache__
│ │ scrapy.cgf
│ │
│ └─── spiders
│ │ __pycache__
│ │ __init__
│ │ your spider here
我们需要知道什么?Scrapy 给了我们几个. py 文件,我们不一定要接触它们,但有时它会很有用,这就是你需要知道的:
- settings.py 给了你修改每秒/每个 ip 的请求数量的权利,添加一些扩展,错误处理程序和其他一些特性
- Pipelines.py 让你有可能编写一些管道来以你想要的格式编写你的输出,尽管 scrapy 已经有了一些内置的命令来编写 json、csv、jsonlines 等等。
- Items.py,抓取的主要目标是从非结构化数据源中提取结构化数据,Scrapy spiders 可以将提取的数据以 Python dicts 的形式返回。为了定义通用的输出数据格式,Scrapy 提供了
[Item](https://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Item)类。[Item](https://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Item)对象是用来收集抓取数据的简单容器。它们提供了一个类似于字典的 API,用一种方便的语法来声明它们的可用字段。这个文件就是在这里定义了那些[Item](https://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Item) - 允许你编写自己的蜘蛛中间件。
写你的刮刀
在这个阶段,我们将能够开始编写我们的蜘蛛。首先,让我们看看我们要抓取什么,更准确地说是我们要抓取的页面的 HTML 代码。在这个项目中,我们的目标是收集网站上所有的漫画及其相关的各种信息。因此,我们将尝试抓取的网站结构如下:
[https://myanimelist.net](https://myanimelist.net)
└───https://myanimelist.net/manga.php
│ │ page A
│ │ └─── Page 1 to n
│ │ └─── informations of several manga
│ │ page B
│ │ page C
│ │ ....
│ │ page Z
我们可以看到漫画是按字母顺序排序的,在每个漫画中,都有 n 个子页面,包含了具有相同字母的其他漫画。如果我们点击其中的一个页面,我们可以看到有几个漫画的子页面,包括分数、概要、标题、数量和漫画类型。

我们可以看到的另一点是,对于每个页面,子页面的确切数量是未知的。我们将如何处理这些多个页面和子页面呢?让我们分阶段进行。
- 首先,我们需要确定如何检索单个页面上的信息。
- 然后我们必须找出如何从一个子页面移动到下一个子页面。
- 最后是如何从一个字母转到另一个字母。
刮你的第一页!
让我们从一个页面开始,不管它是哪一个,我们将检索它的 URL 并通过 Scrapy 的 Shell 打开它。

让我们让 Scrapy 向一个 URL 发送一个请求。
url = 'https://myanimelist.net/manga.php?letter=B]'
fetch(url)
这里,我们在 anaconda 命令提示符中启用了 Scrapy shell 接口。Scrapy 在我们的请求返回给我们一个响应对象,我们将使用它来访问页面的 HTML 代码元素。
type(response)
scrapy.http.response.html.HtmlResponse
由于这个响应对象,我们将能够访问页面的特定元素。为此,我们将使用开发者工具或 google chrome 工具来检查 HTML 代码。为此,只需将自己定位在您想要右键单击的页面上,然后单击已检查。

我们现在可以访问该页面的源代码。我们可以看到,列表形式的第一页上的所有漫画都包含在属于类“class = " js-categories-seasonal js-block-list list”的 division 标签< div >中,我们将对该列表进行迭代,以提取每个漫画的特征。

#css
for sub_block in response.css('div.js-categories-seasonal tr ~ tr') :
do_something
#xpath
for sub_block in response.xpath('//div[@class="js-categories-seasonal js-block-list list"]/tr') :
do_something
- 标题
我们编写了第一行代码来迭代列表中的每个漫画。现在我们需要编写允许我们访问感兴趣的元素的代码。通过我们的 devs 工具,我们试图检索标题,我们可以看到它包含在一个标签< a >下,这个标签指定了一个锚或者一个超链接。
<a class="hoverinfo_trigger fw-b" href="[https://myanimelist.net/manga/4499/B_-_Wanted](https://myanimelist.net/manga/4499/B_-_Wanted)" id="sarea4499" rel="#sinfo4499">
<strong> B - Wanted </strong> == $0
</a>
这个标题实际上链接到几个元素,一个唯一的 id,一个指向关于这个特定漫画的更多信息的 URL,以及用粗体写的标题(见:强标签)。这里,我们只需要标题,所以我们将寻找标签< strong >下的文本。要选择 HTML 代码中的特定元素,有两种常用的方法,可以通过 css 路径(参见:级联样式表)或 xpath (xpath 是一种查询语言,用于选择 XML 文档中的节点)进行访问。
#Take the first manga as illustration
sub = response.css('div.js-categories-seasonal tr ~ tr')[0]
#xpath method
title = sub.xpath('//a[@class="hoverinfo_trigger fw-b"]/strong/text()').extract_first().strip()#css method
title = sub.css('a[id] strong::text').extract_first().strip()
print(title)
'B - Wanted'
我们做了什么?
- 通过语法“//”使用 xpath,我们可以选择 HTML 代码中出现的所有< a >,并指出将 URL 链接到标题的特定类,现在我们在这个标签中,所以我们可以选择粗体文本,并通过 scrapy
[extract_firs](https://docs.scrapy.org/en/latest/topics/selectors.html)t方法提取它,这相当于 extract()[0]。 - 对于 CSS 方法,我们直接在标签中使用 id,它和 URL 一样是唯一的,所以这是相同的操作。
#xpath
synopsis = sub.xpath('//div[@class="pt4"]/text()').extract_first()
#css
synopsis = sub.css("div.pt4::text").extract_first()
- 类型|分数|卷数
寻找分数时,我们发现了一个相当有趣的结构,其中我们感兴趣的下 3 条信息彼此相邻。让我们详细介绍一下这个结构:
<tr>
└─── <td> ... </td>
└─── <td>
│ │ └─── div
│ │ └─── a
│ │ └─── div
</td>
└─── td (type informations) </td>
└─── td (numbers of volumes informations) </td>
└─── td (rating informations) </td>
</tr>
我们的 3 条信息包含在标签< tr >中,它只是 HTML 中的一行。这一行可以包含几个单元格< td >。因此,这里有几种方法来选择可用的元素。我们可以通过指示元素在结构中的位置来访问元素,或者指示信息的特定类别,并自己索引结果。
#we can acces of the child of our 3 previous td and extract it
#css
type_= sub.css('td:nth-child(3)::text').extract_first()
volumes= sub_block .css('td:nth-child(4)::text').extract_first().strip()
rating = sub_block .css('td:nth-child(5)::text').extract_first().strip()#xpath
informations = sub.xpath("//tr/td[@class='borderClass ac bgColor0']/text()").extract().strip()
#the 3 first information are type - volumes- score so :
type_ = d[:1]
volumes = d[:2]
rating = d[:3]
所以,写在一块,我们得到:
for sub_block in response.css('div.js-categories-seasonal tr ~ tr'):
{ "title": sub_block .css('a[id] strong::text').extract_first().strip(),
"synopsis": tr_sel.css("div.pt4::text").extract_first(),
"type_": sub_block .css('td:nth-child(3)::text').extract_first().strip(),
"episodes": sub_block .css('td:nth-child(4)::text').extract_first().strip(),
"rating": sub_block .css('td:nth-child(5)::text').extract_first().strip(),
}
我们在一页纸上收集了所有的数据。现在我们进入第二步,从当前页面过渡到下一个页面。如果我们检查允许我们访问下一个页面的图,我们会看到所有指向下一个页面的 URL 都包含在一个< span >中,它允许我们通过指示这个标签的类来对元素进行分组,我们访问超链接< a >和定义链接目的地的元素 href 。
response.xpath('//span[@class="bgColor1"]//a/@href').extract()
#output
['/manga.php?letter=B&show=50',
'/manga.php?letter=B&show=100',
'/manga.php?letter=B&show=950',
'/manga.php?letter=B&show=50',
'/manga.php?letter=B&show=100', '/manga.php?letter=B&show=950'
]
发生了什么事?我们拿到了接下来的两页,最后一页,一式两份。如果我们更仔细地观察,我们会看到页面呈现如下:1 2 3 … 20],这就是为什么我们没有获得所有的 URL,因为在3和[20]之间没有指向 URL 的指针。为了弥补这一点,我们将迭代页面1以获得2和2以获得3到[n],这里 n=950)。
next_urls = response.xpath('//span[@class="bgColor1"]//a/@href').extract()for next_url in next_urls:
yield Request(response.urljoin(next_url), callback=self.parse_anime_list_page)
为了用 Scrapy 做到这一点,我们将使用一个名为[url_join](https://doc.scrapy.org/en/latest/topics/request-response.html)的函数,它将允许我们简单地将我们项目的基本 URL[https://myanimelist.net]与下一页的 URL[manga.php?letter=B&show=50]连接起来。
既然已经定义了这一步,我们仍然需要找到迭代每个字母的方法,以获得字母表中的所有漫画。仍然感谢我们应用于字母选择栏的检查工具,我们可以看到每个 URL 都包含在一个 division < div >中,并且有一个唯一的 id 指向一个导航栏。所有这些都包含在一个条目列表< li >中,最后是一个锚和一个 href(具体地说,URL 总是包含在一个 href 标签中)。
"""
we can define the xpath of every url easily thanks to navbar id
then each url are stored in a < li > = list of item then an hyperlink tag < a > followed by a href so we can wrote that :
"""
xp = "//div[@id='horiznav_nav']//li/a/@href"
一旦完成这些,我们就已经编写了成功完成项目所需的 99%的代码!现在有必要将所有这些形式化,以便在页面上迭代并启动我们的蜘蛛。我们主要在 shell 上工作,现在我们必须写一个集成了 Scrapy 的习惯用法的脚本。
当我们开始我们的项目时,我们定义了一个 URL,并在上面启动了一个[fetch](https://doc.scrapy.org/en/latest/topics/request-response.html)命令来发送请求,Scrapy 提出了一个与函数[Requests](https://doc.scrapy.org/en/latest/topics/request-response.html)功能相同的函数,除了发送一个请求之外,这个函数将参数[Callbacks](https://doc.scrapy.org/en/latest/topics/request-response.html)作为参数,或者我们传递另一个函数,在这个函数中,我们编写所有指向要废弃的元素的脚本。
重要的一点是,我们的 python 类必须继承scrapy . Spider 类,以便访问它的所有组件,并通过命令行授权启动蜘蛛。也可以给我们的蜘蛛命名,这将是一个启动快捷方式,使我们的任务更容易。
我们的机器人已经准备好抓取网页,所以现在你必须把它保存在蜘蛛文件夹中,如上图所示。现在让我们打开一个命令提示符,指向包含我们的蜘蛛的文件夹。
cd /d C:\Users\xxxxx\Documents\MEDIUM_REPO\WebCrawler\WebCrawler\spidersscrapy crawl Manga -o dataset_name.jsonlines
您的数据集准备好了,祝贺您!
总结
在数据是一种非常珍贵的资源的时代,知道如何创建自己的数据集可能是一笔可观的资产。这有时需要做大量的工作,但这种技能在数据科学中是必不可少的,而且它也是构建贴近您内心的开发项目的主要资产。如果你对这篇文章有任何问题或评论,请在下面随意评论。
使用 Python 和 Google BigQuery 抓取 Reddit 数据
访问 Reddit API 和 Google Bigquery 的用户友好方法

Reddit 是最古老的社交媒体平台之一,就其用户和每年产生的内容而言,它仍然保持着强劲的势头。在古老的用户界面背后,是数百万用户每天以问题和评论的形式创造的信息宝库。
在这篇文章中,我们将一步一步地看到如何使用 python 和 Google Bigquery 从 Reddit 网站获取数据。为了说明这一过程,我决定提取关于插队者的数据,这些人切断了他们的电缆连接并购买了流媒体网站订阅,因为这一现象令我感兴趣。
作为第一步,让我们了解 Reddit 网站的结构。
Reddit 中的信息是如何组织的?
这个网站被分成不同的子栏目,每个用户根据自己的兴趣选择他们想要订阅的子栏目。这些包括音乐子编辑区,在那里可以分享关于音乐的链接,体育子编辑区,人们可以详细谈论体育,或者在我们的例子中,人们可以讨论有线连接或他们新的流媒体订阅。
向上投票和向下投票系统是 Reddit 的精髓,因为它显示了社区成员对特定主题的一致意见。一个帖子获得的支持票越多,它在网站上的显示就越显著。值得注意的是,评论和帖子一样重要,因为它们经常成为扩展的嵌套讨论。
让我们从 Reddit 的数据收集开始
Reddit API:
而网络抓取是著名的(或臭名昭著的!)从网站收集数据的方式,很多网站都提供 API 来访问它们在网站上托管的公共数据。这是为了避免抓取机器人产生的不必要的流量,经常导致网站崩溃,给用户带来不便。甚至 Reddit 也提供这种易于访问的 API。
以下是你在这个练习中需要的东西:
- Python 3.x :你可以在这里下载
- Jupyter 笔记本电脑:我们将把它作为我们的交互控制台
- Reddit 账户:你必须创建一个 Reddit 账户
在获得所需主题的数据之前,您需要遵循几个步骤。
- 创建一个应用:
注册后的第一步是创建一个应用程序来获取 Oauth 密钥以访问数据。点击这里开始。

creating an app
单击创建一个应用程序,如快照所示。然后出现如下所示的对话框。

在对话框中输入应用程序的名称,然后单击脚本,因为我们将把它用于个人用途。确保在重定向 URL 框中输入 http://localhost:8080 。如果您需要任何澄清,您可以参考 praw 文档。现在点击底部的创建应用程序按钮。

现在您的应用程序已经创建好了。将您的 14 字符个人使用脚本和 27 字符密钥存储在安全的地方。现在,您已经拥有了 OAuth2 身份验证连接到 Reddit API 所需的所有凭证。
现在是时候打开 Jupyter 笔记本了!
2。建立连接
我们在这个练习中需要的包装是 praw 和熊猫。PRAW 是说唱歌手的缩写,我们将使用它向 Reddit API 发出请求。确保您已经安装了这两个软件。第一步是导入这些包
import praw
import pandas
导入包后的下一步是使用我们之前创建的凭证建立与 Reddit API 的连接。Client_id 将是您的 14 个字符的个人使用脚本密钥,client_secret 是您的 27 个字符的秘密密钥。用户名和密码是您的 Reddit 帐户凭据。其余的代码将保持不变。
reddit = praw.Reddit(user_agent='Comment Extraction (by /u/USERNAME)',client_id='**********',client_secret="***********",username='********', password='*******')
通过运行上面的代码片段,我们将建立连接并将该信息存储在一个名为 reddit 的变量中。
3。获取数据
正如我们之前所讨论的,我们将专注于为“cordcutter”子编辑获取数据。
标题、分数、url、id、评论数量、创建日期、正文是从 Reddit API 获取数据时可用的字段。但是在我们的分析中,我不会考虑任何时间方面,我们主要关注的是从子编辑中获取正文(评论)。参考 praw 文档了解不同种类的实现。这里,我将代码限制为所需的输出,它只是所有注释的正文文本。
为了让所有的评论都包含嵌套回复,我必须想出一个包含 3 个部分的嵌套代码。
获取评论 id 列表
comm_list = []
header_list = []
i = 0
for submission in reddit.subreddit('cordcutters').hot(limit=2):
submission.comments.replace_more(limit=None)
comment_queue = submission.comments[:]
在这个循环中,首先我们在循环开始时获取每个提交信息,然后提取所有的评论 id 并将它们存储在 list 中。
在这里。hot(limit)可以是任何数字,具体取决于您的要求。我在这里将它设置为 2 来说明输出,但是将其设置为 None 将获取 cordcutter subreddit 中所有的顶级提交。replace_more(limit=None)将帮助我们考虑包含嵌套回复的评论。
该循环的输出如下所示:
[Comment(id='ed5ssfg'),
Comment(id='ed64a72'),
Comment(id='edth3nc'),
Comment(id='ed680cg'),
Comment(id='ed699q2'),
Comment(id='ed80ce8'),
Comment(id='edau9st'),
Comment(id='edcx477'),
Comment(id='ee0fp3g'),
Comment(id='ed5qrvh')]
获取所有嵌套回复
我们就要得到我们想要的数据了。在这部分代码中,我们将获得之前获得的每个注释 id 的主体。如果评论有嵌套回复,它将进入下一个循环,并以类似的方式提取信息。
while comment_queue:
header_list.append(submission.title)
comment = comment_queue.pop(0)
comm_list.append(comment.body)
t = []
t.extend(comment.replies)
while t:
header_list.append(submission.title)
reply = t.pop(0)
comm_list.append(reply.body)
到目前为止,我们从 Reddit 下载了评论,并且需要一些预处理来将其下载为 csv 格式。
下面是经过整理的代码
comm_list = []
header_list = []
i = 0
for submission in reddit.subreddit('cordcutters').hot(limit=2):
submission.comments.replace_more(limit=None)
comment_queue = submission.comments[:] # Seed with top-level
while comment_queue:
header_list.append(submission.title)
comment = comment_queue.pop(0)
comm_list.append(comment.body)
t = []
t.extend(comment.replies)
while t:
header_list.append(submission.title)
reply = t.pop(0)
comm_list.append(reply.body)df = pd.DataFrame(header_list)
df['comm_list'] = comm_list
df.columns = ['header','comments']
df['comments'] = df['comments'].apply(lambda x : x.replace('\n',''))
df.to_csv('cordcutter_comments.csv',index = False)
您可以在我的 github 资源库中找到代码的最终版本。
[## akhilesh-Reddy/使用 Reddit 数据的电缆切割升降机和情感分析
从 Reddit 抓取数据并执行命名实体识别,对评论进行主题建模以了解公众…
github.com](https://github.com/akhilesh-reddy/Cable-cord-cutter-lift-and-sentiment-analysis-using-Reddit-data)
我们的最终输出如下所示:

我们有自己的数据,但这里有一个挑战。一般来说,使用 Reddit API 获取几个月的历史数据需要更多的时间。感谢pushshift . io(Reddit 上的又名 /u/Stuck_In_The_Matrix )的杰森·迈克尔·鲍姆加特纳,我们清理了多年的 Reddit 历史数据,并将其存储在 Bigquery 中,这是本文的第二部分。
big query 中的 Reddit 数据:
对于那些不知道 Bigquery 是什么的人来说,
Google BigQuery 是一个企业数据仓库,它通过使用 Google 基础设施的处理能力实现超快速 SQL 查询来解决这个问题。
最好的部分是查询这些数据将是免费的。Google 免费提供第一个 10GB 的存储和第一个 1 TB 的查询内存,作为免费层的一部分,我们的任务需要不到 1 TB 的内存。
让我们看看如何查询这些信息。
首先点击这个 Google BigQuery 链接开始。Google 会自动使用您浏览器中存储的 Google 凭据让您登录。如果这是您第一次使用 BigQuery,将会出现一个对话框,要求您创建一个项目。

点击创建一个项目按钮。

为该组织命名,然后单击顶部的 create project。

给出项目的名称,您可以暂时保留位置框。然后点击创建。现在您已经创建了您的项目,一个仪表板出现在屏幕上。

现在在这之后,点击 链接 。这将在您创建的项目下打开 reddit 数据集。在左侧,您将看到在模式名 fh-bigquery 下每个月更新的数据集。

让我们运行查询,从表中获取一个月的数据。
select subreddit,body,created_utc
from `fh-bigquery.reddit_comments.2018_08`
where subreddit = 'cordcutters'

这将得到所有关于“割线者”subreddit 的评论。但是请确保您没有选中选项中的“使用遗留 sql”复选框,因为上面的代码片段是在标准 SQL 中。但是,您可以选择您所选择的 sql,并相应地对代码进行更改。
这是结果的样子,您可以通过单击“下载为 csv”按钮下载 CSV 格式的结果。

在这里,我只是专注于获取我们需要的数据。如果你想在 bigquery 上更多地使用 reddit 数据,你可以参考 Max Woolf 的这篇文章,这篇文章更详细地介绍了 Bigquery 中的 Reddit 数据。
总结:
在这篇文章中,我们看到了如何创建 OAuth2 凭据以连接到 Reddit,向 Reddit API 发出数据请求以获取最新数据,并通过 Google Bigquery 快速查询历史数据。
除了通过 API 和 Bigquery 获取数据,您可能会发现使用 Selenium 和 python 进行 web 抓取很有趣。下面是一篇由 UT Austin 的同学( Atindra Bandi )写的文章。
[## 使用 Selenium-Python 进行 Web 抓取
在这篇文章中,你将学习如何浏览一个网站的多个页面并收集大量数据…
towardsdatascience.com](/web-scraping-using-selenium-python-8a60f4cf40ab)
那都是乡亲们!请继续关注我在未来几周发布的关于推荐系统、数据科学统计和数据可视化的一系列文章的更新。
收集和探索体育博彩数据——套利可能吗?用代码进行实际分析。

Photo by Richard Boyle on Unsplash
如何下载实时体育博彩时间序列数据,解析它并使用 Python 分析套利机会
谁不想拥有一台无风险盈利机?我想每个人都想有一个。利用不同市场或博彩公司之间的价格差异(在这种情况下是博彩利率差异)的做法也被称为套利。这个想法是在样本空间的每一个结果上下赌注,并在每一个案例中产生利润。在足球比赛中,你可以打赌哪个玩家赢了一场比赛,也就是说,样本空间将由三种结果组成:“玩家 1 赢”、“平局”和“玩家 1 输”。
在我们深入分析之前,我们应该先看看数据收集和我们将涉及的更多主题:
- 网页抓取现场投注数据( BeautifulSoup )
- 将结果存储在数据帧 ( 熊猫)中
- 自动化带有功能的刮削过程
- 使用 matplotlib-pyplot 的结果可视化
- 首先进行套利分析和利润计算
关于这个数据,我已经提出了许多其他令人兴奋的主题,但是我现在将它们排除在范围之外。(可能会在下一篇文章中跟进。)
- 来自多个网站的网络抓取和数据整合
- 衍生投注/交易策略的规则,包括模拟和评估自动化策略的性能
- 驱动因素分析:是什么驱动了下注率的演变(可能包括来自会议直播行情的文本分析)
- 大概还有很多更有趣的话题;很高兴听取您的意见
法律免责声明:我不是法律专家,也不在这里提供任何行动建议,只是纯粹的技术解释。网站的大规模抓取会导致高流量,从而加重他们的负担。我相信,如果你在访问网站,你应该始终考虑他们的服务条款,最好事先获得像刮擦这样的项目的许可。此外,我不提倡赌博,不管是哪种赌博。
1.网络抓取现场投注数据(BeautifulSoup)
为了收集数据,我们将使用 library BeautifulSoup。我已经通过命令行下载并安装了它:
pip 安装美丽组 4
安装完成后,我们可以开始导入所有相关的库。
from bs4 import BeautifulSoup
import urllib.request
import re
我们现在可以使用它们来检索任何页面的源代码并解析它。
我选择了德国博彩网站 tipico.de 的现场投注页面。
url = “[https://www.tipico.de/de/live-wetten/](https://www.tipico.de/de/live-wetten/)"try:
page = urllib.request.urlopen(url)
except:
print(“An error occured.”)soup = BeautifulSoup(page, ‘html.parser’)
print(soup)
上面的代码检查它是否可以访问页面,然后打印出页面的整个 html 源代码。按照惯例,这将被分配给一个名为“soup”的变量,长度大约为 200-300 页 A4 纸,取决于当前在线下注的数量。
下一步,我们希望以一种结构良好的方式只提取相关的信息。让我们看看网站,看看我们关注哪些信息。

首先,我们可以尝试提取用绿色标记的七个值:时间、玩家的名字、当前分数和每种可能结果的比率。这里,比率 1 对应于玩家 1 赢,比率 2 对应于平局,比率 3 对应于玩家 1 输。要做到这一点,用浏览器检查元素是很方便的(右击并用 Chrome ' Inspect ')。

我们看到费率存储在“c_but_base c_but”类的按钮中。为了提取费率,我们将使用 soup.find_all 来获取该类的所有按钮。
regex = re.compile(‘c_but_base c_but’)
content_lis = soup.find_all(‘button’, attrs={‘class’: regex})
print(content_lis)

为了去掉 html 代码,我们使用。getText()函数,然后将所有按钮的值存储在一个列表中,并删除换行符和制表符。
content = []
for li in content_lis:
content.append(li.getText().replace(“\n”,””).replace(“\t”,””))
print(content)

其他变量可以类似地查询。你可以在 Github 上的我的笔记本里找到细节。如果有不清楚的地方,不要犹豫问问题。
2.将结果存储在数据框中(熊猫)
有了原始的和解析过的数据,我们现在想以一种实用的方式来构造它。我们理解游戏有一个时间,两个玩家,一个分数,每排十一个比率。至于比率,我们只想存储“谁赢了比赛”的三个比率和“谁进了下一个球”的三个比率,因为这些在大多数下注方上都是可用的,并且以后将允许我们有高度的可比性。
N_games = 10 # number of games observed, say we want the first 10
N_players = 2 # number of players per game
N_outcomes = 11 # number of possible outcomes (Win, lose, tie, Next goal etc.)
df = []
for i in range(N_games):
df.append([datetime.now(), content_names[i*N_players], content_names[1+i*N_players], content_minute[i],
content_score[i], content[i*N_outcomes], content[1+i*N_outcomes], content[2+i*N_outcomes],
content[6+i*N_outcomes], content[7+i*N_outcomes], content[8+i*N_outcomes]])pdf = pd.DataFrame(df, columns = ['Time', 'Player_1', 'Player_2', 'MinuteOfGame', 'Score', 'Win_1', 'Win_X', 'Win_2', 'NextGoal_1' , 'NextGoal_X' , 'NextGoal_2' ])pdf.head()

(注:在我的笔记本里,还有两个变量,j 和 k,它们是用来除 bug 的,当每场比赛多了一行‘上半场比赛结果’。为了简单起见,我将它排除在描述之外。)
3。具有功能的刮削过程的自动化
要多次重复这个刮削过程,可以方便地写成一个函数:
**def get_soccer_rates_tipico**():
"""
This function creates a table with the live betting information,
this includes a timestamp, the players, the score and the rates
for each party winning and scoring the next goal.
Arguments:
None
Returns:
pdf -- pandas dataframe with the results of shape (N_games, 11)
"""
... FULL CODE ON GITHUBreturn pdf
返回的表格的形状取决于当前正在进行的游戏的数量。我已经实现了一个功能,查找第一个网球比赛条目,以计算实况足球比赛的总数,并获得所有比赛。
现在我们可以把它写成一个循环,以固定的时间间隔重复这个刮擦函数。
**def repeat_scraping**(timedelay, number_of_scrapes, filename = 'bet_rates_scraping_tipico.csv'):
"""
This function repeadetly calls the scraping function to create a timeseries of scraping data. The time interval between scrapes and number of scrapes in total are taken as argument. The result is saved in a csv-file.
Arguments:
timedelay -- delay between each scrape request in seconds (min. 15 sec recommended due to processing time) number_of_scrapes -- number of scrape requests
Returns:
Void
"""
... FULL CODE ON GITHUB dataframe = pdf.to_csv(filename, index=False)
# Check processing time and add sleeping time to fit the timedelay
time_run = time.time() - start_time
time.sleep(timedelay - time_run)
请注意,页面的加载和解析可能需要 10 秒钟。我们可以使用时间库来跟踪我们的函数从睡眠时间中减去它需要多长时间来调整时间延迟(假设所有查询花费的时间大致相同)。
我们可以调用这个函数来抓取整个游戏,例如 15 秒的时间延迟和 500 个查询,即覆盖 125 分钟。
repeat_scraping(15, 500, 'scraping_500x15s.csv')
4。使用 matplotlib-pyplot 对结果进行可视化和分析
作为第一步,在导入数据后,我们需要做一些数据清理。这包括用零填充所有汇率的 NaNs,用点替换逗号,并将它们转换为浮点类型。
dataframe = pd.read_csv('scraping_500x15s.csv', encoding = 'unicode_escape')
dataframe = dataframe.fillna(0)
ratecols = ['Win_1','Win_X','Win_2','NextGoal_1','NextGoal_X','NextGoal_2']
dataframe[ratecols] = dataframe[ratecols].apply(lambda x: x.str.replace(',','.')).astype(float)
因为我们希望每分钟查询多次,所以“游戏的一分钟”不够精确,因此,我们添加了查询时间戳。
dataframe['Time_parsed'] = 0
# Check for dates without milliseconds and add .000 to have a consistent formatting
dataframe.Time.iloc[np.where(dataframe.Time.apply(lambda x: True if len(x) == 19 else False))] \
= dataframe.Time.iloc[np.where(dataframe.Time.apply(lambda x: True if len(x) == 19 else False))].apply(lambda t: t + ".000")
dataframe.Time_parsed = dataframe.Time.apply(lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S.%f').time())
dataframe = dataframe.drop(['Time'], axis=1)
现在,我们可以探索第一场比赛的数据并可视化结果。让我们看看牌桌上的第一位玩家:
df1 = dataframe[dataframe[‘Player_1’] == dataframe[‘Player_1’][0]]
df1

我们现在有拜仁慕尼黑 vs 1 的数据。科隆俱乐部比赛从第 5 分钟开始,每 15 秒一次。下面的图表显示了下一个进球得分率的变化。我在 y 轴上使用了对数标度来计算超过 30 的比率。此外,我还加入了一条比率为 3 的水平线,表明了一种简单的套利形式:如果所有报价都大于 3,那么你可以通过对所有三种结果进行均匀分布的押注(例如,每人 100 €)来产生无风险利润。
# Data for plotting
t = df1.Time_parsed.values
w1 = df1.NextGoal_1.values
w2 = df1.NextGoal_X.values
w3 = df1.NextGoal_2.values# Plot setup
fig, ax = plt.subplots(figsize=(15, 6))
ax.plot(t, w1, marker ='', label = 'Player 1 scores next' ,color = 'green', linewidth = 2)
ax.plot(t, w2, marker ='', label = 'No more goals', color = 'orange', linewidth = 2)
ax.plot(t, w3, marker ='', label = 'Player 2 scores next', color = 'red', linewidth = 2)
plt.axhline(y=3., label = 'Critical line', color='grey', linewidth = 2, linestyle='--') # Line for arbitrage detectionax.set(xlabel='Time', ylabel='Betting rates', title=str(np.unique(df1.Player_1)[0]) + ' vs ' + \
str(np.unique(df1.Player_2)[0]) + ': Rates for "Who scores next?"')
ax.grid()
plt.legend()ax.set_yscale('log')

在我的笔记本里,你会发现一个自动为所有游戏创建剧情并保存为图片的功能。
5.首先进行套利分析和利润计算
回到我们寻找套利交易的想法,很可能不太可能在一个网站上找到它们。我相信利用多个庄家之间的信息差异实现套利投注的可能性更大。但是,我们现在将只研究对 Tipico 数据的分析。这种分析可以很容易地扩展到多个网站。
一个简单的数学问题:
假设 n 是一个事件的可能结果的数量,q_i 是每个结果的比率,那么如果所有 1/q_i 之和小于 1,套利是可能的。
df2['Check_a_1'] = df2.Win_1.apply(lambda x: 1/x)
df2['Check_a_2'] = df2.Win_X.apply(lambda x: 1/x)
df2['Check_a_3'] = df2.Win_2.apply(lambda x: 1/x)
df2['Check_a_sum']=0
df2['Check_b_1'] = df2.NextGoal_1.apply(lambda x: 1/x)
df2['Check_b_2'] = df2.NextGoal_X.apply(lambda x: 1/x)
df2['Check_b_3'] = df2.NextGoal_2.apply(lambda x: 1/x)
df2['Check_b_sum']=0
df2['Check_a_sum'] = df2.Check_a_1 + df2.Check_a_2 + df2.Check_a_3
df2['Check_b_sum'] = df2.Check_b_1 + df2.Check_b_2 + df2.Check_b_3
df2['Arbitrage_flag']=0
arb_idx = np.unique(np.append(np.where(df2.Check_a_sum <= 1)[0],np.where(df2.Check_b_sum <= 1)[0]))
df2.Arbitrage_flag[arb_idx] = 1
如果我们想获得一个独立于结果的利润,我们需要根据利率来分配赌注。当你考虑利率 q 乘以金额 s 等于利润 p 以满足 p_i = p_j,你得到 s_j = q_i/q_j * s_i。
# Give the first bet the weight of 1 and adjust the other two bets accordingly
df2['Win_1_betting_fraction'] = 1
df2['NextGoal_1_betting_fraction'] = 1
... FULL CODE ON GITHUB
df2['Win_profit_percentage'] = df2.Win_1 * df2.Win_1_betting_amount * 100 - 100
在我收集的数据中,我发现了以下例子:
下一个进球得分率:
球员 1: 1.70
不再进球:4.70
球员 2: 7.00这就导致了如下投注金额分布:
投注 1: 62.32%
投注 2: 22.54%
投注 3: 15.14%这导致了 5.9%的确定利润。
(在我看来很奇怪,我在一个单一的网站上找到了套利的机会。可能是抓取数字时出现了错误,我会对此进行调查。)
正如所展示的,这个过程使你能够计算出一个赌注组合的确定利润。现在就看你自己去寻找积极的价值观了!
包扎
在本文中,您可以学习如何使用 Python 和 BeautifulSoup 加载和解析 web 页面,只提取想要的信息并将其加载到结构化数据表中。为了提取时间序列,我们研究了如何将其实现为函数,并以固定的时间间隔重复我们的查询。之后,我们编写代码来自动清理数据,然后进行可视化和额外的计算,使数据可以被解释。
我们已经看到,套利赌博很可能是可能的——如果不是在一个网站上,那么通过与多家博彩公司联合下注。(请注意,我不是在推广赌博和/或网络搜集,即使是套利交易也可能存在风险,例如延迟或取消交易。)
非常感谢您花时间阅读这篇文章!
我非常感谢并欢迎您的反馈和意见。
你可以通过 LinkedIn 联系我:https://www.linkedin.com/in/steven-eulig-8b2450110/
……你可以在这里找到我的 github 包括 Jupyter 笔记本:
https://github.com/Phisteven/scraping-bets
干杯,
史蒂文
搜集和探索整个英语有声目录
上周,我使用 Python 的 HTML-Requests 包编写了一个脚本,从 Audible 获取有关他们当前的“买一送一”信用销售中的程序的信息。在对线程超参数进行试验后,我设法让我的脚本的性能达到每秒 55 个条目,这意味着 Audible 的大约 40 万个程序的整个英文目录可以在大约两个小时内完成。几个小时后,我有了一个完整的数据集。
(注:如果你喜欢代码,可以直接跳转到刮痧笔记本和分析笔记本。你也可以下载整个数据集。)
在加载和处理数据以消除重复并转换对象类型后,我有 352,686 个条目,包含以下字段:标题、作者、类别(流派)、长度、讲述者、价格、评级(在源处四舍五入到 0.5 的增量)、评级计数、发布日期和 URL。
#我们的数据中音频的总长度是多少?
230 年,235 天,15 小时
#哪几个类别的时长和收视率最高?

有趣的是,总时长排名前三的类别与收视率排名前三的类别正好相反。换句话说,“科幻&奇幻”节目每小时的参与度(即评论数量)比“小说”节目高得多。看看能不能进一步量化。由于每小时的评论数量可能比每个标题的评论数量更不公平(我们假设一些流派的标题平均比其他流派的长),让我们采用后者。让我们看看这一替代指标是否会延续敬业度趋势。

Categories sorted from left to right by mean number of reviews.
这里有几个有趣的发现:首先,按每个标题的平均评论数计算,“科幻与幻想”仍然是最高的参与度。然而,现在当考虑评论的中位数而不是平均数时,它输给了“浪漫”(22 对 23)。此外,“浪漫”评论的分布比任何其他类别都要紧密。综合这些发现,表明“浪漫”比其他类别有更多的双峰分布。我们应该预料到更多的书很少或者没有评论,这就降低了平均值。然而,受欢迎的书籍都有很多评论,提高了中位数。换句话说,“浪漫”的听众在节目选择上没有其他类型的听众大胆。
各书的评分是如何分布的?

注意:第一个情节不是错误。没有非线性轴的绘图意味着评论很少的标题数量主导了绘图。事实上,在我们大约 35 万个程序中,超过 20 万个程序的总评论数不到 10 条。第二个图是一个直的 x 轴和对数标度的 y 轴,展示了超过 100,000 条评论的极少数图书——准确地说是 7 个。第三个图向我们展示了评级计数的对数与评级计数频率的对数大致呈线性变化。换句话说,高层是孤独的。
#那些少有的> 100k 收视率的书是什么?

Ready Player One dominates the field in number of ratings.
需要注意的是:所有这些产品都比整个 Audible 目录 15.42 美元的平均价格要贵得多。所代表的类别比我们想象的更加多样化:两部科幻小说,一部奇幻小说,一部惊悚小说,两部自传和一部自助小说。除了一本,所有的书都是在过去十年发行的。一号玩家有大量的评论。事实上,这个标题的评论比其他 174,000 个节目加起来还多。
#哪些作者的评分最高?

斯蒂芬·金以超过 600,000 条评论赢得了他的书籍评论总数的冠军。令人印象深刻的是他收视率最高的头衔只有 51695。他在排行榜的首位证明了他的多产。他在 Audible 上有 130 个单独的录音,没有被我们的重复搜索筛选掉。
在第二个图中,我们考虑了 Audible 上有两个以上标题的作者的每个节目的平均评论数(以便筛选“一炮走红的奇迹”及其样本/替代版本)。在《火星人》的鼓舞下,安迪·威尔摘得桂冠,后者是第二大冠军。
#哪些作者的书名数量和记录小时数最多?

继续调查我们数据集中最多产的作者,我们查看音频的总持续时间和录音数量(不包括期刊)。查尔斯·狄更斯(Charles Dickens)在 audible 上以近 5000 小时的总时长独占鳌头。他和排名第二的阿瑟·柯南·道尔似乎都从 Audible 上对他们作品的多次翻译中受益匪浅。单单《双城记》就有 37 个不同的版本!詹姆斯·帕特森没有这种优势,他在当代作家中胜出。
多伊尔和狄更斯切蛋糕的方式略有不同,他们交换了 Audible 的唱片数量。亚瑟·柯南·道尔的作品在 Audible 上总共有 706 个版本。
#哪些解说员收视率最高?

斯科特·布里克叙述的标题(658 个!)获得了最高的收视率,几乎是原来的两倍。同上,我们看右边有最大“影响”的叙述者(至少按每部作品的评分数)。罗伊·多特里斯(拥有 10 本书)因其讲述《冰与火之歌》的作品而位居榜首,该书是我们七本收视率突破 10 万的书中的第一本。
#哪些解说员在 Audible 上的时间最长?

我们看到了同一枚硬币的两面——Scott Brick 在小时数方面的产量最高,有 658 本书,平均每本书 12 小时 39 分钟。凯茜·多布森以 1161 个冠军的数量获胜,平均每个冠军 2 小时 53 分钟。
#标题发布日期与评论数量有什么关系

We can see a spike for each of the 7 outliers above.
虽然我们可能会认为老书会因为有更多时间积累评分而受益,但我们看到了相反的趋势。最近的节目更有可能获得更多的评论。
从 1996 年开始,每个季度发行了多少本书?

Histogram of release dates with one bin per quarter.
请注意,在 1999 年的最后一个季度,有一个大箱子。事实上,在我们的数据集中最常见的日期是 1999 年 12 月 16 日。虽然你可能认为这个日期是追溯到所有早期的标题,但事实并非如此。数据集中的最小日期是 1995 年 12 月 1 日,也就是 Audible 成立的那一年。此外,谷歌没有从 1999 年 12 月有关 Audible 的新闻中得到多少回报,尽管该公司经历了多事之秋。最初的创始人在 10 月份刚刚去世。
另一个有趣的发现是,2015 年期间,电影发行量连续三个季度下降。事实上,这种下降使得 2015 年成为自 2002 年以来唯一一个发行数量少于前一年的年份。
旁注:数据集中最新的日期是莎伦·波顿的《投毒者》2020 年 12 月 10 日。
#所有节目的价格分布是怎样的?

所有书籍的平均价格是 15.43 美元,顺便提一下,这个价格接近某些每月有声计划的 15 美元的价格。在每 5 美元的区间都有峰值,正如我们所预期的给出 4.99 和 9.99 美元的定价方案。
不同类别的价格有何不同?

Categories ranked, left to right, by mean price
《神秘与恐怖小说》的平均价格最高,为 20.53 美元。报纸和杂志的平均价格最低,为 2.81 美元。这里没有什么大的惊喜。
我们可以从我们的箱线图中看到我们可能最昂贵的标题——“语言教学”类别中的异常值。让我们找出它是什么。
# Audible 上最贵的节目是什么?
173.27 美元可以买到所有音频中最贵的英文标题,以及 982 分钟(约 16 小时)的西班牙语教学。
#每小时最贵的节目是什么?
每单位长度最贵的节目是杰夫·哈撒韦的 1 分钟长的节目杰作,价格为 10.49 美元——或每小时 629.40 美元。
#节目时长分布(不含期刊)?

报纸和杂志、广播和电视、现场活动和戏剧和诗歌不包括在这个图表中,因为它们主要是非常短的节目。我们可以看到还是有不少短的(<5 hour) programs, but there’s a nice bell curve of longer titles with median right around 7 hours.
We might infer that this length plot is a composite result of combining a long-form distribution with a shorter-form distribution. Let’s look at categories and see if we can pinpoint which are which.
#按类别划分长度分布是怎样的?

Categories ordered, left to right, by decreasing mean length
事实上,我们发现不同类别的长度分布不同。“报纸和杂志”的平均节目长度最短,为 28 分钟。《科幻与幻想》的平均时长最长,刚刚超过 9 小时。
我们马上会在箱线图中看到一些长度异常值,我们稍后会探讨这些异常值,但首先,让我们验证一下关于复合分布的理论。

最后,Audible 上最长的书有哪些?
df.nlargest(5, 'length')

Audible 上 5 个最长的节目中有 4 个属于“宗教与精神”类别。最长 154 小时。唯一不属于这一类别的书名是爱德华·吉本 19 世纪的长篇历史《罗马帝国的衰亡》(The Decline and Fall of The Roman Empire),多年来,这本书都让我在夜里不时地眼皮上下起伏。
所以我们有它。我们已经依次查看了我们的大部分功能:作者、叙述者、收视率、发布日期、长度、价格和类别。我们查看了业内最多产的名字以及最长、最贵的图书。我们还没有探索的唯一功能是“评级”栏本身,这是因为当我们抓取时,我们只能从我们可以访问的 html 中捕捉 0.5 的等级。有了这些链接,我们就可以自由地从页面中为单个节目重新抓取更精细的评级,但我们会把它留到以后再做。
150 万条有声评论的情感分析
在这个项目的第一部分中,我们收集并探索了一个数据集,其中包括 Audible 上每个英语节目的 ASIN 、收视率和一个单独的 URL。
我们将通过使用这些字段收集尽可能多的文本评论和附带评级来继续我们离开的地方。然后,我们将训练一些 LSTM 神经网络,将评论分为正面或负面。
(注:此处可跳转至刮痧笔记本,此处可跳转至数据预处理及情绪分析笔记本。你可以在这里下载所有评论的数据集。)
1.抓取 150 万条评论

我们之前检查了 Audible 目录中的收视率分布,注意到收视率极度集中于顶部的少数几个节目(标题排名的对数和评论数量的对数之间大致呈线性关系)。
今天,我们将利用这种偏态优势,最大限度地提高每小时的评论数量。假设每个标题的书面评论数量与每个标题的评级数量成比例,我们可以预计大约 50%的网站评论将集中在我们数据集中前 1%的节目中。
从 HTML 中抓取这些评论有一个障碍。大多数最受欢迎图书的评论都隐藏在“查看更多”按钮下。

单击该按钮时检查网络请求为我们提供了一个解决方案。我们找到一个链接,指向一个只有评论文本和评级的备用页面。通过增加这个 URL 中的页码,直到 HTML 变成空白,我们可以收集给定节目的所有评论和评级。因为这个页面加载速度非常快(并且因为我们使用了 16 个线程),我们能够在合理的时间内从排名前 6% (26,101)的节目中抓取排名前 80%的评论。
刮的时候,我们会趁机做一些家务。我们将使用我们的文本来训练一个机器学习模型,以将评论分为好评(4 或 5 星)或不好评(1、2 或 3 星)。如果我们把标题和作者留在我们的评论文本中,我们的模型很可能会“记住”,比如说,一个给定的程序有非常高的评论分数。这对于归纳来说不是一个好兆头,所以我们想从评论中删除作者和标题。我们现在就做,这样我们就不需要为每次审核存储这些信息了。
用一个普通的词来替换单词的过程叫做“解块”。除了取消每个评论的作者和标题,我们还会用单词“stop”替换句号,去掉所有其他标点符号,并将所有文本改为小写。这减少了数据集中的“单词”数量。
几个小时后,我们有超过 150 万的评论和评级。
2.准备数据
虽然我们实际上为每个评论刮出了三个评级,“总体”、“故事”和“表现”,但我们将专注于“总体”列作为我们的标签。我们将为将来的分析保存另外两列。
为了使我们的数据和目标形成我们需要训练的模型,我们需要完成以下预处理任务:
- 根据频率从我们数据中的顶部 vocab_size 单词创建一个词汇表,其中 vocab_size 是一个超参数。
- ‘unk’—即替换为“
”—我们的数据集中不在我们的词汇表中的所有单词。 - 将所有条目填充或截断到某个公共长度, seq_length ,也是一个超参数。
- 对数据集中的所有单词进行标记化(即转换为整数)。
- 从“总体”列创建二进制标签。
我们的目标是将数据 X 作为形状为 (num_reviews,seq_length) 的整数数组,将标签 y 作为长度为 num_reviews 的整数向量。

The first few entries. Text normalized and authors and titles removed.
为了决定上限和下限,让我们来看看分布。

Distributions of text character and word length over all reviews.

上面的长度与频率图显示了类似指数衰减的现象。96.4%的评论短于 250 字。我们将选择它作为我们的 seq_length 。

下限呢?左边的图表向我们展示了我们的数据集中剩下的绝大多数(> 98%)评论(在之前删除了带有空白文本的条目之后)都超过了 10 个单词。我们将用它作为下限。
按字符长度排序,我们看到最短的评论超过 10 个“单词”。

Shortest reviews with >10 ‘words’. Note that ‘words’ are everything between spaces.
我们的下一个任务是从我们所有的评论中构建一个词汇表。我们将使用一个计数器字典来统计每个单词在我们的数据集中的频率,然后我们将选择最频繁的 10,000 个单词来构建我们的词汇表,我们将使用这些单词来“取消”我们的数据集,即使用单词“unk”替换我们词汇表中没有的每个单词。我们还想将数据集转换成一个数字数组,即“令牌”,我们可以在同一个函数中完成这两项任务。
在一些示例文本上测试我们的功能:
sample = ‘i really loved dfalkjf especially the introduction’
...
print(tokenize_text(sample))Unk ID: 24
[4, 56, 79, 24, 301, 1, 1190]
请注意,无法识别的“dfalkjf”被赋予了“unk”标记 24。其余的标记对应于单词在我们的词汇表中的排名。
在填充、截断和标记之后,我们的数据看起来是这样的:
array([[ 24, 0, 0, ..., 24, 24, 24],
[ 24, 9, 11, ..., 24, 24, 24],
[ 149, 149, 149, ..., 24, 24, 24],
...,
[ 131, 32, 873, ..., 24, 24, 24],
[ 5, 3312, 368, ..., 24, 24, 24],
[ 172, 195, 1, ..., 24, 24, 24]])
注意每行末尾的 24 列,这是用“unk”标记填充的。
最后,我们根据“总体”评级创建二元标签,发现大约 79%的评论获得 4 星或 5 星评级。这个数字值得注意,因为它意味着即使是最简单的模型(总是预测 1)也能获得 79%的准确率。那是要打破的数字。
3.训练模型
既然准备步骤已经完成,我们就可以训练我们的模型了。使用 TensorFlow 和 Keras 层,我们可以使用不同数量的参数尝试许多不同的架构。我们所有的模型都将有一个嵌入作为第一层,它将每个单词转化为一定长度的向量,一个超参数。
我们所有的模型也将至少有一个 RNN 层(特别是长短期记忆或 LSTM 层)。该层将在向前和向后传递中使用。在每种情况下,LSTM 层将输入具有 relu 激活函数的密集层和具有 sigmoid 激活函数的输出层,这将产生 0 和 1 之间的值,该值将被阈值化以提供类别预测。
我们将添加的其他层将是丢弃层,以减少过度拟合,包括嵌入层后的一种特殊类型的丢弃层,它会丢弃整个一维特征图而不是单个单词,以及一个一维卷积层,它将学习一组过滤器,这些过滤器将从相邻单词之间的关系中提取特征。我们还将尝试堆叠两层 LSTMs。
我们将利用二进制交叉熵损失、Adam 优化器,并且我们将采用早期停止回调,这将在验证损失开始增加时停止训练。

The training set and validation set accuracy for one of our best models. The validation loss bottomed out on the 5th epoch and training was stopped early.
3.结果
表现最好的模型确实是最复杂的——在大约 155,000 条评论的未知测试集上有 93.8%的准确率。然而,值得注意的是,最不复杂的模型达到了 93.1%的准确率。
我们最简单的模型只包含三个隐藏层:一个嵌入长度只有 8 的嵌入层,一个只有 8 个单元的 LSTM,一个只有 16 个单元的全连接层。它共有 81k 个参数,训练时间为 53 分钟。
model = tf.keras.Sequential([ **tf.keras.layers.Embedding(vocab_size, 8),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(8)),
tf.keras.layers.Dense(16, activation='relu'),** tf.keras.layers.Dense(1, activation='sigmoid')
])
我们最复杂的模型,也是最终的赢家,除了 LSTM 层之外,还有 7 个隐藏层,包括下降层、卷积层和池层:
model = tf.keras.Sequential([ **tf.keras.layers.Embedding(vocab_size, 128),
tf.keras.layers.SpatialDropout1D(rate=0.4),
tf.keras.layers.Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling1D(pool_size=2),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(rate=0.4),** tf.keras.layers.Dense(1, activation='sigmoid')
])

对于二元分类,受试者工作特征(ROC)曲线给出了模型区分能力的良好概念。它反映了这样一个事实,即随着您降低最终概率输出的阈值,您会捕获更多的真阳性,但也会捕获更多的假阳性。一个完美的模型会给正面例子分配比负面例子更高的概率,因此降低阈值会捕获更多的正面例子,而不会捕获更多的负面例子。因此,曲线将切割靠近左上角。AUC 相当于测量 ROC 曲线下的面积(越接近 1 越好)。这里,我们的模型对测试数据的 AUC 为 0.975。
让我们通过例子来测试我们的模型,并输入几段文本。我们给它四个序列。小于 0.5,模型预测为负;大于 0.5,为正。
“这本可怕的书太可怕了。真的,太可怕了。”
我们的模型对此的正确评分为 0.01,即尽可能接近 0。
“我喜欢这本书。这太棒了,太搞笑了,太神奇了。”
这个得了 0.99 分。不如来点暧昧的:
“这本书还可以,但它让我感到难过。”
0.52.我们的模型被撕破了。把积极的和消极的词语结合起来怎么样:
“故事确实很棒,但叙述者很恐怖。”
0.72.该模型更重视“非常棒”部分,而不是“讲述者很可怕”部分。也许如果我们在“性能”评级上重新训练我们的模型,我们会得到不同的结果。
最后,让我们看看我们的模型已经学习的单词嵌入。我们词汇表中每个单词的学习向量应该反映关于该单词的一些有用信息,用于预测正面或负面评论。为了可视化这些表示之间的空间关系,我们需要将单词向量减少到更易于人类理解的维数。
主成分分析(PCA)是一种转换数据的方法,使其信息最丰富的维度(即包含最大方差的维度)与轴对齐(即结果的第一维)。我们将使用 PCA 将我们的 128 维嵌入向量减少到 2 维,以便我们可以可视化单词之间的关系:

A 2D representation (the first two principal components) of our learned word embeddings for 61 key words.
我们词汇中 61 个常用词的前两个主要成分形成了上面这张惊人的图表。在这里,一般不喜欢的词,如“迷人的”和“优秀的”,被渲染成蓝色;喜欢的词,如“可怕的”和“无聊的”,用红色呈现,中性的词,如“表演”和“书”用黑色呈现。
我们的嵌入清楚地反映了这些术语的极性。甚至更好的关系似乎被表现出来。例如,我们凭直觉知道“单调”和“单调”、“更差”和“最差”、“乏味”和“无聊”、“声音”和“讲述者”、“音频”和“质量”等密切关系。
通过在整个词汇上重复这个过程,并且只看第一个主成分,我们可以识别出具有最积极和最消极显著性的单词。价值最高的词是‘well spent’[原文如此]。
价值最低的那个词?
“退款”。
最后,让我们对整个训练集进行预测,找出“最差”和“最好”的评论。
“最差”评论:
浪费,浪费,浪费。保存您的信用。
怎样才能让<标题>更好?
没有什么能让这本书变得更好。被警告。这本书甚至没有一些人说的那么有趣。为什么要买一本很搞笑的僵尸恐怖书?
你认为你的下一首歌会是什么?
不确定,除了说一些关于僵尸或天启的事情,但肯定不是这本书的作者或叙述者。
你不喜欢<解说员>的什么表现?
她的声音。这样她让所有的角色听起来都一样。
你不喜欢这本书……但它有什么可取之处吗?
零…更糟糕的是,因为它是数字媒体而不是实体书,我甚至不能烧它来预热。我读过比这本书更好听/读的服务条款。
还有其他意见吗?
我是任何形式的僵尸和启示录故事的忠实粉丝..这本书虽然不应该被写,更不用说…
“最佳”评论:
牛逼
牛逼牛逼牛逼牛逼牛逼
牛逼 牛逼牛逼 牛逼 牛逼 牛逼 牛逼 牛逼 牛逼牛逼
抓取继续:用 Python 下载图像
大约一周前,我写了一篇关于网络抓取的文章。本文介绍了使用 Python 的 BeautifulSoup 库获取数据的一些基本概念,并进一步利用 Pandas 的能力将获取的数据存储到 DataFrame 对象中。

Photo by Max Duzij on Unsplash
浏览那篇文章是这篇文章的先决条件,因为你还能如何获得数据?如果你已经熟悉网页抓取的概念,你就不必通读了,只需在底部抓取代码即可。总之,这里有一个链接:
使用 Python 和 BeautifulSoup 的强大功能来收集对您重要的数据。
towardsdatascience.com](/no-dataset-no-problem-scrape-one-yourself-57806dea3cac)
如果你是阅读这篇文章的人之一,你可能会想知道整个故事就是这样( 剧透警告: 它不是)。
快速浏览一下获取的数据,你会看到雄伟的 缩略图 栏,如果你把它和这篇文章的标题联系起来,就不难得出这个故事还没有结束的结论。
今天的文章将处理从缩略图 URL 下载图像的过程。
但是我为什么要下载图片呢?
我很高兴你问了。也许你的数据科学项目需要通过卷积神经网络进行图像分类。让我们想象下面的场景——你想开发一个算法,它能够根据一些缩略图的特征来预测图书的主题(流派)(嗯,实际上是一个很好的项目想法!)。
我绝不是 CNN 的专家,但我将向您展示如何根据流派将图像下载到各自的子目录中。事不宜迟,我们开始吧!
一点点准备工作
你真的认为没有这个你就能逃脱吗?
虽然,我会尽量把这部分说得简短一些。归结起来就是做一些库导入和导入以前抓取的数据。代码如下:
Imports — https://gist.github.com/dradecic/04cbe16e067ea66bf750eb8fdd1c4845
简单回顾一下——下面是 df 的样子:

Head of df
所有的准备工作现在都完成了——没那么糟糕,对吧?
下载图像
你期待已久的部分来了。但是在给你代码之前,这里是应该发生的事情的概要:
- 一个变量 BASE_DIR 被声明,为图像存储根目录的名称
- 声明了一个变量 SUB_DIRS ,它是一个数组,保存了数据集中所有不同的主题
- 将创建根目录以及所有子目录(如果它们不存在的话)
- 基于不同的主题值过滤数据集
- 使用 urllib 下载缩略图
- 执行一些替换以使文件名格式正确
呀呀。听起来工作量很大。但它实际上不是——拜托,我们谈论的是 Python!
下面是代码片段。我强烈建议您阅读每一行,甚至可以一行一行地执行,以便更好地理解为什么所有东西都是这样工作的。
Image Downloader — https://gist.github.com/dradecic/d26d44d7e145577a1ded06f28559499b
运行此代码单元将创建以下目录结构:

Directory Structure
此外,在每个子目录中,您会看到一堆图像:

Music Subdirectory
结论
这是一篇相当短的文章——但我更喜欢那些较长的文章。使您不想立即关闭浏览器窗口。
像往常一样,在您选择的数据集上使用这项新获得的技能。看看有没有可能不下载图片而下载别的东西(有可能)。如果你对 CNN 和深度学习感兴趣,但在网上找不到相关的数据集,那就自己做一个。没有限制。
感谢阅读…
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
使用 Python 抓取飞行数据
计划下一次周末旅行的无聊方式

假设我们想计划下一次周末旅行。计划是去米兰或马德里。关键是我们真的不在乎,我们只是在寻找最好的选择。这有点像德国足球运动员安迪·穆勒曾经说过:米兰或者马德里,只要是意大利。
第一步,我们只是像往常一样寻找航班。对于这个例子我们使用 皮艇 。一旦我们输入了搜索标准,并设置了一些额外的过滤器,如 Nonstop ,我们可以看到,有趣的是,我们浏览器中的 URL 也相应地进行了调整

我们实际上可以将这个 URL 分解成不同的部分:起点、终点、开始日期、结束日期和一个后缀,告诉 Kayak 只寻找直接连接,并按价格对结果进行排序。
现在,总的想法是从网站的底层 html 代码中获取我们想要的信息(例如,价格、出发和到达时间)。要做到这一点,我们主要依靠两个包。第一个是硒,基本控制你的浏览器,自动打开网站。第二个是美汤,它帮助我们将杂乱的 HTML 代码重塑为更有结构性和可读性的格式。从这道汤里,我们可以很容易地得到我们想要的美味。
所以让我们开始吧。首先我们需要设置元素。为此,我们需要下载一个浏览器驱动程序,例如 ChromeDriver (确保它对应于您安装的 Chrome 版本),我们必须将它放在与我们的 Python 代码相同的文件夹中。现在我们加载几个包,告诉 selenium 我们要使用 ChromeDriver ,让它从上面打开我们的 URL。
一旦网站加载完毕,我们需要找出如何获取与我们相关的信息。以出发时间为例,使用浏览器的 inspect 特性,我们可以看到 8:55pm 出发时间包含在一个名为出发时间基准时间的 span 中。

如果我们现在将网站的 html 代码传递给 BeautifulSoup ,我们可以专门搜索我们感兴趣的课程。然后可以用一个简单的循环提取结果。因为对于每个搜索结果,我们得到一组两个出发时间,我们还需要将结果重新整形为逻辑出发-到达时间对。
我们用类似的方法计算价格。但是,在检查价格元素时,我们可以看到 Kayak 喜欢为其价格信息使用不同的类。因此,我们必须使用正则表达式来捕捉所有情况。此外,价格本身被进一步包装,这就是为什么我们需要使用一些额外的步骤来达到它。
现在,我们将所有内容放入一个漂亮的数据框架中,得到

差不多就是这样了。我们已经将最初飞行中的 html 代码中混乱的所有信息整理成形。繁重的工作完成了。
为了方便起见,我们现在可以将上面的代码封装到一个函数中,并在三天的旅程中使用不同的目的地和起始日组合来调用该函数。当发送几个请求时, Kayak 可能会不时地认为我们是一个机器人(谁能责怪他们呢),解决这个问题的最好方法是不断地改变浏览器的用户代理,并且在请求之间等待一段时间。我们的整个代码将会是这样的:
一旦我们指定了所有的组合并收集了各自的数据,我们就可以使用来自 seaborn 的热图很好地可视化我们的结果

就这样决定了。下一站:马德里!仅 108 美元,这是我们在 9 月份挑选的三个周末中最便宜的选择。期待着吃一些美味的小吃。
用 Python 和 BeautifulSoup 刮汉萨德
使用网络搜集脚本自动收集议会官方报告中的数据

Photo by Deniz Fuchidzhiev on Unsplash
请注意:我是以个人身份写这篇文章的。表达的任何观点都不是我雇主的观点。
我最近有一个问题:众议院议长约翰·伯科主持了多少次首相问答时间(PMQs)?
通常我会通过搜索议会资料来回答这样的问题,这种搜索服务包含议员的贡献、议会会议记录、议会文件以及下议院和上议院图书馆的简报。
这项服务可在https://search-material . parliament . uk获得
对于这个特定的问题,我无法从搜索议会材料中得到这个问题的直接答案,原因可以填充几个中等职位。相反,我决定通过网上搜集英国议会议事录来寻找答案。
我从一个粗略的计划开始,我认为我可以找到 John Bercow 主持了多少次 PMQs 会议:
- 在https://hansard . parliament . uk上查找约翰·伯科任职期间发生的所有 pmq 记录
- 对于这些 PMQs 记录中的每一条,浏览页面并找到一位演讲者所做的贡献。
- 对于演讲者所做的每项贡献,提取该人的具体姓名、他们做出贡献的日期以及当天 PMQ 记录的 URL。
- 计算返回的唯一 PMQs 记录的数量,并从该数量中减去主持会议的发言人不是 John Bercow(即副发言人)的记录。
在我进入代码之前,我应该指出,在开始这个项目之前,我知道一些事情,它们在我的道路上帮助了我:
- 我知道英国议会议事录中所有的 PMQs 记录都有一个标准的名字:他们都被称为“首相”。
- 我知道演讲者所做的贡献总是被列为演讲者,而不是成员的名字。
- 我知道当‘partial = True’放在 URL 的末尾时,Hansard HTML 更容易阅读。
查询议会信息通常需要知道数据是如何格式化的,以及信息是如何存储的。我发现 Twitter 是一个询问有关议会数据问题的好地方,那里有很多知识渊博的人很乐意提供帮助。
对,对代码。
需要的包
这些是我用过的包
import csv
from bs4 import BeautifulSoup
import pandas as pd
import requests
- csv 允许您操作和创建 csv 文件。
- BeautifulSoup 是网络抓取库。
- 熊猫将被用来创建一个数据框架,把我们的结果放到一个表中。
- Requests 用于发送 HTTP 请求;查找网页并返回其内容。
找到所有的 PMQ 记录
首先,我需要为英国首相收集所有的英国议会议事录辩论记录。
hansardurls = []
for i in range(1,20):
url = '[https://hansard.parliament.uk/search/Debates?endDate=2019-10-28&house=Commons&searchTerm=%22Prime+Minister%22&startDate=2009-06-23&page={}&partial=true'.format(i)](https://hansard.parliament.uk/search/Debates?endDate=2019-10-28&house=Commons&searchTerm=%22Prime+Minister%22&startDate=2009-06-23&page={}&partial=true'.format(i))
rall = requests.get(url)
r = rall.content
soup = BeautifulSoup(r,"lxml")
titles = soup.find_all('a',class_="no-underline")
for t in titles:
if t['title'].lower() == "prime minister [house of commons]":
hurl = '[https://hansard.parliament.uk'+t['href'](https://hansard.parliament.uk/'+t['href')]
hansardurls.append(hurl)
print(len(hansardurls))
我打开 https://hansard . parliament . uk,点击查找辩论,然后搜索约翰·伯科担任议长期间的“首相”。这给了我一组长达 19 页的搜索结果。

Results set from Hansard
代码首先创建一个名为‘hansardurls’的空列表,我将 PMQ 记录的 URL 放在那里。
然后代码在 19 页的搜索结果中循环。每个循环执行以下操作:
- 请求 URL 并返回所请求页面的内容
- 使用 BeautifulSoup 处理 HTML
- 在 HTML 中搜索以找到该页面上每个辩论的链接,并给它们分配变量“title”。我进入结果页面,右键单击一个辩论标题,然后选择“Inspect ”,找到了这些链接。这会将您带到控制台,向您显示该页面元素的 HTML。
- 查找仅包含“首相”的头衔。有一些辩论题目提到了首相,但不是 pmq,所以这些被排除了
- 有些标题是大写的,所以所有的标题都用小写。降低()以捕捉所有相关的辩论标题
- “if”语句是说,如果辩论的标题是“首相”,则为该辩论创建一个完整的 URL,并将其添加到名为“hansardurls”的列表中。title 元素中的链接前面没有“hansard.parliament.uk ”,这需要首先添加以使它们成为可用的链接。
- 最后一行打印出找到并添加到列表中的 PMQ URL 的数量: 327 。
导出 PMQ 网址
我想在一个单独的 CSV PMQ 的网址,原因我将进入稍后。
with open(‘hansardurls.csv’, ‘w’, newline=’’) as myfile:
wr = csv.writer(myfile, quoting=csv.QUOTE_ALL)
wr.writerow(hansardurls)
这段代码创建了一个名为“hansardurls.csv”的文件,并将列表“hansardurls”中的每个对象写入该 csv 中的单独一行。
查找每次 PMQ 会议的演讲者贡献
现在我有了约翰·伯科担任议长期间所有 PMQ 会议的链接,我想看看每个 pmq,看看是否有一位议长做出了贡献,如果有,是约翰·伯科还是他的副手。
Speakercontrib = []
Speakingtime = []
urloftime = []
首先,我创建了 3 个单独的列表:一个保存在提问时间发言的人的名字,一个保存成员发言的日期,一个保存他们发言的 pmq 的 URL。
for h in hansardurls:
rall = requests.get(h)
r = rall.content
soup = BeautifulSoup(r,"lxml")
time = soup.find('div',class_="col-xs-12 debate-date").text
contributors = soup.find_all('h2',class_="memberLink")
然后,我编写了一个 for 循环来请求每个 PMQs URL,返回该页面的 HTML,然后使用 BeautifulSoup 来查找页面上对应于发言成员姓名的元素。我通过打开一个 PMQs 页面,右键单击一个成员的名字,找到这个名字是什么类型的元素以及这个元素的类,找到了这个问题。

The screen you see after clicking inspect on a page element.
for c in contributors:
link = c.find('a')
try:
member = link.text
except:
print(c)
if "Speaker" in member:
Speakercontrib.append(member)
Speakingtime.append(time)
urloftime.append(h)
然后,我对 PMQs 页面上每个成员的名字运行了一个 for 循环。该循环执行以下操作:
- 在成员的名称页面元素中查找链接。包含成员姓名文本和 ID 的实际链接嵌套在 h2 标记中,如上面的屏幕截图所示。
- 尝试找到包含成员姓名的链接文本。我在这里使用了一个 try 语句,因为在《英国议会议事录》中有一些投稿没有附上姓名。这些通常是当几个成员同时站起来或叫出来。如果没有 try 语句,这个脚本在遇到“Hon. Members rose”投稿时就会停止。该语句打印出成员名称,让我知道这是不是“Member rose”的贡献,或者是否有其他错误发生。

An example of the phantom contribution, “Members rose — “
- 运行一个 if 语句,如果成员的名字包含“Speaker ”,将名字、投稿日期和页面的 URL 添加到各自的列表中。
创建表格
所有数据都是从英国议会议事录中收集来的,但这些数据是在 3 个不同的列表中。我使用 Pandas 创建了一个数据框架,并将 3 个列表添加到数据框架中,以创建一个可用的结果表。
speakersdf = pd.DataFrame(
{'Date': Speakingtime,
'Speaker': Speakercontrib,
'url': urloftime
})
这段代码创建了一个名为“speakersdf”的数据帧,并将三个列表作为列添加进来。
然后,我将数据帧导出为 CSV 文件:
speakersdf.to_csv('speakerspmqdf.csv')
我浏览了一下电子表格,发现约翰·伯科在 319 个下午问中讲过话,副议长林赛·霍伊尔在 1 个下午问中讲过话。
但是等等…有 327 个 PMQs 网址…少了 7 个 PMQs】。
这就是我在单独的文档中导出 PMQs URLs 的原因。我从 speakersdf 表中取出 URL,并将其与 hansardurls 列表中的 URL 进行比较(我在 Excel 中完成了此操作),找到了 7 个缺失的 PMQs URLs。
当我进入这 7 个网页时,我发现演讲者在这 7 次 PMQ 会议中没有做出贡献,所以他们没有被脚本选中。在这种情况下,我会手动查看议事录,找出在 PMQs 开始前是哪位发言者在主持会议。
最终结果:
约翰·伯科在任内主持了 326 场 PMQ 会议(至 2019 年 10 月 28 日)*
- 这取决于我从英国议会议事录中收集的数据是否完整和正确,以及我收集这些数据的工作流程是否准确。请不要把它当作真理。
如何改进这段代码?
这段代码并不完美。
我想改进的代码部分:
- 引入一个函数,该函数在查找演讲者贡献时自动对照收集的 URL 列表检查 hansardurls 列表,以找到丢失的 URL。
- 我想用演讲者的贡献创建数据框架,而不需要先创建和填充 3 个单独的列表。
如果你认为这段代码可以在其他方面改进,请告诉我。我仍然在学习,非常感谢任何建议或指导。
抓取 Reddit 数据
如何使用 Python Reddit API 包装器从 Reddit 抓取数据(PRAW)

Photo by Fabian Grohs on Unsplash
顾名思义,PRAW 是 Reddit API 的 Python 包装器,它使你能够从子编辑中抓取数据,创建机器人等等。
在这篇文章中,我们将学习如何使用 PRAW 从不同的子编辑中抓取帖子,以及如何从特定的帖子中获取评论。
入门指南
PRAW 可以使用 pip 或 conda 安装:
现在 PRAW 可以通过写:
import praw
在它被用来收集数据之前,我们需要验证自己的身份。为此,我们需要创建一个 Reddit 实例,并为其提供一个client_id、client_secret和一个user_agent。
为了获得认证信息,我们需要创建一个 reddit 应用程序,方法是导航到此页面并单击创建应用程序或创建另一个应用程序。

Figure 1: Reddit Application
这将打开一个表单,您需要在其中填写名称、描述和重定向 uri。对于重定向 uri,你应该选择http://localhost:8080,正如优秀的 PRAW 文档中所描述的。

Figure 2: Create new Reddit Application
按下创建应用程序后,一个新的应用程序将会出现。在这里,您可以找到创建praw.Reddit 实例所需的认证信息。

Figure 3: Authentication information
获取子编辑数据
现在我们有了一个praw.Reddit实例,我们可以访问所有可用的函数并使用它,例如从机器学习子编辑中获取 10 个“最热门”的帖子。
输出:
[D] What is the best ML paper you read in 2018 and why?
[D] Machine Learning - WAYR (What Are You Reading) - Week 53
[R] A Geometric Theory of Higher-Order Automatic Differentiation
UC Berkeley and Berkeley AI Research published all materials of CS 188: Introduction to Artificial Intelligence, Fall 2018
[Research] Accurate, Data-Efficient, Unconstrained Text Recognition with Convolutional Neural Networks
...
我们还可以通过指定“all”作为子编辑的名称,得到所有子编辑的 10 个“最热门”的帖子。
输出:
I've been lying to my wife about film plots for years.
I don’t care if this gets downvoted into oblivion! I DID IT REDDIT!!
I’ve had enough of your shit, Karen
Stranger Things 3: Coming July 4th, 2019
...
这个变量可以被迭代,包括文章标题、id 和 url 在内的特征可以被提取并保存到一个.csv文件中。

Figure 4: Hottest ML posts
使用 subreddit 对象上的.description函数可以获得 subreddit 的一般信息。
输出:
**[Rules For Posts](https://www.reddit.com/r/MachineLearning/about/rules/)**
--------
+[Research](https://www.reddit.com/r/MachineLearning/search?sort=new&restrict_sr=on&q=flair%3AResearch)
--------
+[Discussion](https://www.reddit.com/r/MachineLearning/search?sort=new&restrict_sr=on&q=flair%3ADiscussion)
--------
+[Project](https://www.reddit.com/r/MachineLearning/search?sort=new&restrict_sr=on&q=flair%3AProject)
--------
+[News](https://www.reddit.com/r/MachineLearning/search?sort=new&restrict_sr=on&q=flair%3ANews)
--------
...
从特定帖子中获取评论
您可以通过创建/获取一个Submission对象并遍历comments属性来获取帖子/提交的评论。要获得 post/submission,我们可以遍历 subreddit 的提交,或者使用reddit.submission指定一个特定的提交,并向其传递提交 url 或 id。
要获得顶级注释,我们只需迭代submission.comments即可。
这对于某些提交是有效的,但是对于其他有更多评论的提交,这段代码将抛出一个 AttributeError,表示:
AttributeError: 'MoreComments' object has no attribute 'body'
这些MoreComments 对象代表在网站上遇到的“加载更多评论”和“继续此主题”链接,在评论文档中有更详细的描述。
去掉了MoreComments对象,我们可以在打印正文之前检查每个注释的数据类型。
但是 Praw 已经提供了一个名为replace_more的方法,它取代或移除了MoreComments。该方法采用一个名为 limit 的参数,当该参数设置为 0 时,将删除所有的MoreComments。
以上两个代码块都成功地迭代了所有的顶级注释,并打印了它们的正文。输出如下所示。
Source: [https://www.facebook.com/VoyageursWolfProject/](https://www.facebook.com/VoyageursWolfProject/)
I thought this was a shit post made in paint before I read the title
Wow, that’s very cool. To think how keen their senses must be to recognize and avoid each other and their territories. Plus, I like to think that there’s one from the white colored clan who just goes way into the other territories because, well, he’s a badass.
That’s really cool. The edges are surprisingly defined.
...
然而,评论部分可以任意深入,大多数时候我们当然也想得到评论的评论。CommentForest提供了.list 方法,可以用来获取评论区内的所有评论。
上面的代码将首先输出所有的顶级注释,然后是二级注释,依此类推,直到没有剩余的注释。
推荐阅读
如何使用 Selenium 在页面之间导航,并使用它来废弃加载了 JavaScript 的 HTML。
towardsdatascience.com](/web-scraping-using-selenium-and-beautifulsoup-99195cd70a58)
结论
Praw 是 Reddit API 的 Python 包装器,它使我们能够通过一个干净的 Python 接口使用 Reddit API。该 API 可用于网络抓取,创建一个机器人以及许多其他。
本文介绍了身份验证、从子编辑获取帖子以及获取评论。要了解更多关于 API 的信息,我建议看一看他们的优秀文档。
如果你喜欢这篇文章,可以考虑订阅我的 Youtube 频道,在社交媒体上关注我。
本文涵盖的代码可以从 Github 资源库获得。
如果你有任何问题、建议或批评,可以通过 Twitter 或评论区联系我。
一步一步地刮财富 500 强公司的招聘板

Photo by: Matthew Henry
我想你同意我的观点,Linkedin 在整合工作岗位和激励专业人士方面非常成功。招聘人员更有可能在 Linkedin 上搜索候选人,比所有其他招聘平台加起来还要多。
事实上,这是一个真实的事实:谁拥有求职者市场,谁就拥有数十亿美元的市场。的确,怪物,招募者知道这一点。甚至谷歌也在 2017 年开始分享就业市场的馅饼。
公司不断花钱寻找适合合适工作的候选人。因此,我们仍然有很大的潜力去开拓就业市场。
在这篇文章中,我将带你从零开始构建一个财富 500 强招聘网站的整个过程。此外,我将解析 Linkedin 的商业模式来推动你的业务。
一个招聘网站就像一个媒体代理,为合适的候选人和潜在的公司牵线搭桥。雇主付费在网站上发布职位列表,求职者向感兴趣的公司发送简历和求职信。因此,工作列表的质量和数量对你的网站生存至关重要。有两种方法可以增加招聘网站上的招聘数量:
1。从公司网站的职业栏中搜集工作列表
2。从工作列表搜索引擎上刮下来的,像确然和 Monster.com
第一种方法:
因为每个公司都有自己的网站,我们需要为他们所有人建立一个蜘蛛。一个传统的方法是用美汤写 python。这导致高的初始成本和维护成本。由于每个网站都有独特的布局,我们需要为每个公司写一个单独的脚本。此外,该网站可能会改变其网页结构。因此,我们必须重写脚本,并建立一个新的蜘蛛抓取网站。此外,有这么多的网站,只有由一群技术专家来完成,才能使你的网站持续下去。多增加一个劳动力的高边际成本对企业来说是站不住脚的。
网页抓取工具作为成本低得多的最有效的替代工具派上了用场。它允许我们自动化整个抓取过程,而无需编写脚本。Octoparse 脱颖而出,成为最好的网页抓取工具。它将使首次入门者和有经验的技术专家都能通过点击式可视化界面提取数据。
由于有 500 个网站,我将在本文中以脸书就业委员会为例。(这是财富 500 强企业网站排行榜,欢迎充分利用 )。)

可以看到,该网页包含十个列表,分布在多个页面上。我们将点击每个工作列表,提取每个职位、位置、职责、最低和首选要求。对于像这样带有嵌套列表 ( 列表包含额外列表)的网页,我们可以预处理 URL 列表,这样我们就可以获得所有列表页面的 URL,而无需分页。
1。一个 URL 遵循一个一致的模式,在末尾有一个固定的主机名和一个页面标签。当您分页时,编号会相应地改变。因此,我们将第一个页面的 URL 复制到一个电子表格中,向下拖动以获得网站 URL 的列表。

2。然后我们用 Octoparse 建立了一个带有这个列表 URL 的爬虫。
现在你可以开始提取了
通过内置的浏览器,我们可以用给定的命令提取网页上的目标元素。在这种情况下,我们单击页面中的一个工作列表,并选择“全选”来创建一个包含所有列表的循环。

3。然后选择循环点击每个元素来浏览每个详细页面。
你应该可以得到一个工作列表,像这样提取出来。同样,从详细页面中选择提取元素,包括演示 _ 脸书 _ 职业 _ 列表 职位、地点、职责、最低和首选要求。
遵循同样的想法,我们可以用 Octoparse 创建任意多的爬虫。因此,高维护成本的风险被最小化。您可以设置擦除计划,并通过 API 将最新作业列表传送到您的数据库。
第二种方法:
像 Monster.com 的这样的工作搜索引擎提供了大量的工作列表。我们可以用一个爬虫从大公司和小公司获得这些工作信息。另一方面,如果你从求职引擎上找工作,这不会给你带来竞争优势。最平易近人的解决办法就是找个小众。我们可以缩小到特定的群体,而不是一个范围很广的网站。它可以根据供求关系进行创作。在这种情况下,我收集了 10000 份工作列表和相关的位置,并将它们与地图进行比较,以查看数据科学职位在地理上是如何分布的。****

数据科学职位主要集中在沿海地区,西雅图和纽约的需求最高。考虑到这一点,这将是一个绝佳的机会,可以帮助更多的科技公司通过当地的数据科学家社区找到合适的候选人。
我有一个类似的视频,指导如何搜集工作列表。
Linkedin 为什么成功?
从一个昙花一现的人物到一个巨人,Linkedin 在商业策略上非常老练。以下是受它们启发的四个因素,它们将在许多层面上有益于您的企业:
- 找到合适的传播者:首先要邀请“冠军”和行业领袖来宣传你的网站。这些冠军具有魅力效应,将转化为精英聚集。
- 社交网络社区:用户一旦聚集在一起,就承载了更多的商业价值。社区产生 UGC(用户生成内容),吸引更多优质用户分享自己的想法。这些是提高竞争力的资产。
- 可信度:求职网站的目标是帮助他们获得职业发展。说“帮助别人就是帮助自己”有点老生常谈,但如果你在追求一个成功的企业,这是正确的心态。
最后的想法?
我相信边做边学。就像布兰森说的,“你不是靠遵守规则学会走路的。你在实践中学习,在跌倒中学习。”这就是你成功的方法。
引用:
https://www . statista . com/statistics/976194/annual-revenue-of-LinkedIn/
https://towards data science . com/influencer-marketing-using-web-scraping-568 ef4c 072 C3
原载于 2019 年 8 月 16 日【https://www.octoparse.com】。
NLP 第 1 部分|使用 BeautifulSoup 和 Python 抓取 Web

Photo by Patrick Selin on Unsplash
数据是任何数据科学项目的核心,然而我们常常认为数据的可用性是理所当然的,尤其是当它整齐地出现在 SQL 数据库中或者更好地出现在我们的收件箱中时。
也就是说,由于其特定的性质,有时您正在寻找的数据并不容易获得。这个问题的一个可能的解决方案是网络抓取的想法,或者通过仔细阅读特定网站的 HTML 从该网站提取信息。例如,让我们说你正在计划一个假期,你在寻找机票何时开始销售。是的,你可以每小时浏览同一个旅游网站,希望价格会下降,但更有效的方法是每小时浏览旅游网站,并有一个输出文件为你提供最新的票价。
放弃
许多网站不希望自己的数据被窃取,尤其是当这些数据包含可识别的用户信息时(如脸书、Linkedin 等)。).请考虑您选择刮取哪些数据以及刮取的频率。
NLP 系列
这个简短的教程是关于自然语言处理(NLP)的 3 部分系列的第一部分。在这个系列中,我们将探索抓取网站数据的技术,预处理并准备好数据以供分析,最后从我们的 NLP 数据中收集见解。
从 Indeed.com 搜集公司评论
在这个例子中,让我们尝试抓取 indeed.com,但具体来说是公司评论。让我们针对员工的评分、评估职称、评估描述以及优点和缺点。

HTML 基础
在我们真正开始收集信息之前,我们需要熟悉 HTML 的基本结构,因为我们实际上将使用 HTML 标签来标识我们希望收集的信息。
我们可以通过在您当前的浏览器中打开开发者工具来访问网站的 HTML。比如 Firefox(选项→ Web Developer → Inspector)。所有这些蓝色的“div”标签、箭头、类和 id 就是你当前所在网站的 HTML。

在我们研究 indeed.com 的 HTML 之前,让我们用下面的例子回顾一下它的基本结构。

HTML 描述了网站的底层结构。换句话说,它标识了网站将有一个标题,多个段落,一个嵌入的视频,一个结束页脚,等等。HTML 不会描述这些组件将如何排列,它们的样式、大小、颜色等。
HTML 代码本质上是分层的,缩进的标签(即。
、
Python 代码
首先,我们需要导入所需的库。
from bs4 import BeautifulSoup
import lxml
import requests
import pandas as pd
import numpy as np
导入的“request”库有一个 get()函数,它将向 indeed.com 服务器请求 URL 的内容,并将服务器的响应存储在“base_url”变量中。如果我们打印“base_url”变量,我们将实际看到页面的整个 HTML。
base_url = requests.get('[https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start='](https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start='), timeout=5)print(base_url.text)

让我们首先定义一个名为“parse”的函数,它需要一个参数,这个参数将是我们试图解析/抓取的页面的实际 URL。接下来,我们将使用 BeautifulSoup 类创建器来解析所提供网站的内容(HTML 代码)。我们将使用“lxml”解析器,以防 HTML 格式不完美。更多关于 BeautifulSoup 可用的不同解析器的信息,请访问这个链接。
请记住,网站通常会通过更改容器中项目的名称或父/子关系来调整其 HTML 脚本。这些变化需要你调整你的职能。该函数于 6 月 20 日进行了调整,以修复新实现的 indeed.com HTML 脚本
def parse(full_url):
**page_content = BeautifulSoup(full_url.content, 'lxml')**
containers = page_content.findAll('div',
{'class':'cmp-Review-container'})
df = pd.DataFrame(columns =
['rating', 'rating_title', 'rating_description',
'rating_pros', 'rating_cons'])
for item in containers:
try:
rating = item.find('div',
{'class': 'cmp-ReviewRating-text'})
.text.replace('\n', '')
except:
rating = None
try:
rating_title = item.find('div',
{'class': 'cmp-Review-title'})
.text.replace('\n', '')
except:
rating_title = None
try:
rating_description = item.find('span',
{'itemprop': 'reviewBody'})
.text.replace('\r', '. ')
except:
rating_description = None
try:
rating_pros = item.find('div',
{'class': 'cmp-ReviewProsCons-prosText'})
.text.replace('\n', '')
except:
rating_pros = None
try:
rating_cons = item.find('div',
{'class': 'cmp-ReviewProsCons-consText'})
.text.replace('\n', '')
except:
rating_cons = None
df = df.append({'rating': rating,
'rating_title': rating_title,
'rating_description': rating_description,
'rating_pros': rating_pros,
'rating_cons': rating_cons}, ignore_index=True)
return df
接下来,我们需要更仔细地检查 HTML 以识别哪个根容器(即哪个父标签)容纳包含我们要抓取的信息的子/嵌套标签。让我们导航到“https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start =”,因为我们将收集员工对谷歌的评论。打开您的开发工具,观察网站的 HTML。请注意,一旦您访问了网站的 HTML,在网站上移动鼠标光标会导致特定区域高亮显示,并且 HTML 似乎会随着您移动光标而改变。当您移动光标时,您的开发者工具会自动将您带到网页上突出显示部分的 HTML 部分。这非常有帮助,因为我们可以快速识别 HTML 代码中需要更详细检查的部分。
如果您还记得,在本教程中,我们感兴趣的是收集员工的总体评分、考核标题、考核描述、优点和缺点。我们需要识别哪个 HTML 标签是所有这些信息的容器或家。通过将鼠标光标移动到适当的位置,我们看到所有我们想要抓取的信息都整齐地包含在一个根元素中。通过检查下面的 HTML,我们可以看到“
”现在移动到一个不同的评论,您将看到名为“cmp-Review-container”的同一个类属性,它存储该评论的数据。
因此,我们将使用“findall()”方法提取所有具有“cmp-Review-container”类属性的“div”容器。接下来,我们将创建一个名为“df”的空 pandas 数据帧,我们将把抓取的数据追加到该数据帧中。
def parse(full_url):
page_content = BeautifulSoup(full_url.content, 'lxml')
**containers = page_content.findAll('div',
{'class':'cmp-Review-container'})
df = pd.DataFrame(columns =
['rating', 'rating_title', 'rating_description',
'rating_pros', 'rating_cons'])**
for item in containers:
try:
rating = item.find('div',
{'class': 'cmp-ReviewRating-text'})
.text.replace('\n', '')
except:
rating = None
try:
rating_title = item.find('div',
{'class': 'cmp-Review-title'})
.text.replace('\n', '')
except:
rating_title = None
try:
rating_description = item.find('span',
{'itemprop': 'reviewBody'})
.text.replace('\r', '. ')
except:
rating_description = None
try:
rating_pros = item.find('div',
{'class': 'cmp-ReviewProsCons-prosText'})
.text.replace('\n', '')
except:
rating_pros = None
try:
rating_cons = item.find('div',
{'class': 'cmp-ReviewProsCons-consText'})
.text.replace('\n', '')
except:
rating_cons = None
df = df.append({'rating': rating,
'rating_title': rating_title,
'rating_description': rating_description,
'rating_pros': rating_pros,
'rating_cons': rating_cons}, ignore_index=True)
return df
既然我们已经为所有想要抓取的数据确定了容器,那么让我们更深入地研究 HTML,以确定包含实际数据的元素。首先,评论评级再次位于“cmp-Review-container”容器中,但是向下钻几层,我们会发现“< div”标记具有“cmp-ReviewRating-text”类属性,它实际上存储了“5.0”评级。让我们记下存储这些数据的标签和类属性,因为下面的 python 脚本需要这些信息。我们对希望提取的所有剩余数据重复该过程。


这是对你的挑战。为什么我们要用(")替换回车(" \r "))为我们评分 _ 描述?提示:标题为“工作环境棒”和“工作环境好”的评论有什么区别?在下面的评论中发表你的答案吧!😉
一旦我们为数据确定了合适的标签,让我们把注意力转回到 python 代码上。我们可以在 for 循环中使用 try/except 块,通过 find()方法在容器中搜索已识别的标签。我们使用 find()而不是 findall(),因为我们只希望返回第一个匹配,因为我们使用了 for 循环。最后,我们将抓取的数据追加回之前创建的空数据帧中。
def parse(full_url):
page_content = BeautifulSoup(full_url.content, 'lxml')
containers = page_content.findAll('div',
{'class':'cmp-Review-container'})
df = pd.DataFrame(columns =
['rating', 'rating_title', 'rating_description',
'rating_pros', 'rating_cons']**)**
for item in containers:
try:
**rating = item.find('div',
{'class': 'cmp-ReviewRating-text'})
.text.replace('\n', '')**
except:
rating = None
try:
**rating_title = item.find('div',
{'class': 'cmp-Review-title'})
.text.replace('\n', '')**
except:
rating_title = None
try:
**rating_description = item.find('span',
{'itemprop': 'reviewBody'})
.text.replace('\r', '. ')**
except:
rating_description = None
try:
**rating_pros = item.find('div',
{'class': 'cmp-ReviewProsCons-prosText'})
.text.replace('\n', '')**
except:
rating_pros = None
try:
**rating_cons = item.find('div',
{'class': 'cmp-ReviewProsCons-consText'})
.text.replace('\n', '')**
**except:
rating_cons = None
df = df.append({'rating': rating,
'rating_title': rating_title,
'rating_description': rating_description,
'rating_pros': rating_pros,
'rating_cons': rating_cons}, ignore_index=True)**
return df
我们还没有完成,因为如果您要执行“parse()”函数,您将获得一个只有 20 条记录的数据帧,这是因为我们只抓取了一页。
为了抓取所有剩余的评论页面,我们首先创建一个新的空数据框架,在遍历所有页面时收集所有的评论。接下来,我们初始化一个计数器变量 20,因为每页有 20 条评论。接下来,我们创建一个 while-loop,它将迭代直到评论的数量等于或大于 4000。为什么是 4000?所有页面上有将近 4000 条个人评论(在撰写本文时)。接下来,当 while 循环遍历每个页面时,我们在 base_url 的末尾添加增量 20。在 base_url 的末尾增加 20 将为您希望访问的页面创建一个新的 url。例如,“https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start =40”将把我们带到评论的第二页。接下来,我们再次请求并获取 while 循环正在迭代的页面的整个 HTML。我们在页面上应用 parse()函数,将新抓取的评论添加到我们的数据帧中。最后,我们将计数器增加 20,以便 while 循环在下一页上迭代。
base_url = '[https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start='](https://www.indeed.com/cmp/Google/reviews?fcountry=ALL&start=')all_reviews_df = pd.DataFrame(columns = ['rating', 'rating_title',
'rating_description','rating_pros', 'rating_cons'])num_reviews = 20# you can adjust this number on how many reviews you which to scrape
while num_reviews < 3000:
full_url = base_url + str(num_reviews)
get_url = requests.get(full_url, timeout=5)
partial_reviews_df = parse(get_url) all_reviews_df = all_reviews_df.append(
partial_reviews_df, ignore_index=True)
num_reviews += 20

剩下要做的就是将我们的数据帧移动到一个 csv 文件中。
all_reviews_df.to_csv('indeed_scrape.csv')
我希望你喜欢这个教程。我喜欢你的反馈,欢迎在下面评论。
别忘了挑战!
谢谢!
通过 CenPy 的美国人口普查数据
用 API 争论人口普查数据

Source: Census.gov (The United States Census logo® is a Federally registered trademark of the U.S. Census Bureau, U.S. Department of Commerce.)
在承担了一个团队项目来检查自然灾害对特定地区的经济影响(通过工资损失)后,我们的假设是使用季节性自动回归综合移动平均(SARIMA) 预测来确定没有自然灾害时的历史就业、失业和工资水平。通过将我们的预测与灾后的实际影响进行比较,我们可以估算出该事件的经济影响。
考虑到时间紧迫,我立即惊慌地想到了这样一种可能性,即必须导航一个笨重的 SQL 界面,或者为每个州手动下载不同的 CSV 来获取我需要的信息。此外,我甚至不太确定我最终需要的指标或时间框架。有了这些不确定性,我认为我最好的选择是利用 API 或 webscraper 来获取我需要的数据。然而,我的 API & BeautifulSoup 技能仍然需要一些练习,所以我开始寻找一种替代方法。
幸运的是,Python 社区中充满了富有创造力的开发人员,他们创建了库和包装器来更容易地与 CenPy 这样的数据进行交互。根据创作者的说法,“CenPy ( sen - pie)是一个包,它公开了美国人口普查局的 API,并使其易于下载和处理熊猫的人口普查数据。”虽然我将探索我使用的几个特性,但我鼓励大家查看他们的 GitHub 和入门笔记本以获取更多信息。
入门指南
我在这个练习中使用的唯一进口商品是熊猫和熊猫:
import pandas as pd
import cenpy as cen
通过调用explorer.available,您可以访问cenpy知道的所有 API 的标识符列表。幸运的是,我知道我想要访问哪个 API/数据系列,但是如果您想要查看所有可用的 API,您可以通过字典输出或者转换为 Pandas 数据帧来实现,以便于阅读。
# Call list of available datasets, verbose = True to include dataset title
datasets = list(cen.explorer.available(verbose=**True**).items())# Convert dictionary to dataframe
datasets = pd.DataFrame(datasets, columns = ['code', 'dataset name'])
code在这里很重要,因为这将允许您指定您想要建立连接的数据库。connection类允许您构造一个查询字符串,并从人口普查服务器发出请求。然后将结果解析成 JSON 并返回。我从季度工作指标 (QWI)开始我最初的查询,这是一组 32 个经济指标,包括就业、就业创造/破坏、工资、雇佣和其他就业流动的衡量标准。
qwi_connection = cen.base.Connection('QWISA')
构造查询
根据 Census API 文档,在调用它们的 API 时,有几个参数/变量需求必须使用:端点、指示器、地理和时间。如果没有指定,则采用其他分类变量的默认值。以下是完整基本查询的最低要求示例:
api.census.gov/data/timeseries/qwi/sa?get=Emp&for=state:02&year=2012&quarter=1&key=[userkey]
我从设置一些默认参数开始:
# Specify all counties
g_unit = 'county:*'# Start with one state (chosen arbitrarily)
g_filter = {'state': '01'}# Specify time period
time = 'from 2003-Q1 to 2018-Q1'# Uses .varslike to pull in all indicator names
cols = qwi_connection.varslike('Emp') # Employment
hir = qwi_connection.varslike('HirA') # Hiring
earns = qwi_connection.varslike('Earn') # Earning
payroll = qwi_connection.varslike('Pay') # Payroll
firm = qwi_connection.varslike('Frm') # Firm Job Stats
sep = qwi_connection.varslike('sep') # Seperations # Extend cols to add additional variables
cols.extend(hir)
cols.extend(earns)
cols.extend(payroll)
cols.extend(firm)
cols.extend(sep)
循环所有状态
我想构建一个循环,允许我遍历所有状态,并将所有结果连接到一个主数据帧中。我首先创建了一个“主”数据帧,可以在其上附加其他状态,而不是创建一个空白数据帧,以确保列顺序匹配,并且新的查询可以适当地连接。
# Create the first query / dataframe (with state 01)
master = qwi_connection.query(cols = cols, time = time, geo_filter = g_filter, geo_unit = g_unit)
然后,我利用这个州 FIPS 代码字典创建一个州代码列表,并对其进行迭代:
state_codes = {
'WA': '53', 'DE': '10', 'DC': '11', 'WI': '55', 'WV': '54', 'HI': '15',
'FL': '12', 'WY': '56', 'NJ': '34', 'NM': '35', 'TX': '48',
'LA': '22', 'NC': '37', 'ND': '38', 'NE': '31', 'TN': '47', 'NY': '36',
'PA': '42', 'AK': '02', 'NV': '32', 'NH': '33', 'VA': '51', 'CO': '08',
'CA': '06', 'AL': '01', 'AR': '05', 'VT': '50', 'IL': '17', 'GA': '13',
'IN': '18', 'IA': '19', 'MA': '25', 'AZ': '04', 'ID': '16', 'CT': '09',
'ME': '23', 'MD': '24', 'OK': '40', 'OH': '39', 'UT': '49', 'MO': '29',
'MN': '27', 'MI': '26', 'RI': '44', 'KS': '20', 'MT': '30', 'MS': '28',
'SC': '45', 'KY': '21', 'OR': '41', 'SD': '46'
} # Extract numerical state codes
states = list(state_codes.values())
最后,我创建了一个for循环来迭代所有的州代码,并将结果与我现有的master数据帧结合起来:
**for** s **in** states:
print(f'Scraping **{s}**')
**try**:
# Iterate over states 's' g_filter = {'state': s}
df = qwi_connection.query(cols=cols, time=time, geo_filer=g_filter, geo_unit = g_unit)
# Concat new df with master df master = pd.concat([master, df])
**except** requests.exceptions.HTTPError:
**pass**
请注意,您可以在单个 API 查询中包含多达 50 个变量,并且每天可以对每个 IP 地址进行多达 500 次查询。每天每个 IP 地址超过 500 次查询需要您注册一个普查密钥。该密钥将是您在建立connection时指定的数据请求 URL 字符串的一部分。
我发现我对所有州的所有县的查询超过了总的 IP 限制,即使在使用了我的 API 密钥之后也是如此,并且它使我在系统之外超时。这迫使我在两天内将我的查询分成两部分。
我希望这是对你有帮助的入门,并且你能够探索 CenPy 的所有可能性!
seaborn——让绘图变得有趣
Python 中的 Seaborn 库简介

Photo by Isaac Smith on Unsplash
如果您曾经在 Python 中使用过诸如线图、条形图和其他图,您一定会遇到名为 matplotlib 的库。当我开始使用 Python 进行可视化时,我甚至写了一篇关于如何使用 matplotlib 使数据可视化变得有趣的激动人心的文章,您可以在下面阅读:
使用 Matplotlib 创建世界各地人口密度的美丽可视化。
towardsdatascience.com](/matplotlib-making-data-visualization-interesting-8bac1eb3d25c)
虽然 matplotlib 库相当复杂,但情节并不那么精炼,不会是任何人出版的首选。这就是 seaborn 参与进来的原因。
Seaborn 是一个基于 matplotlib 的 Python 数据可视化库。它提供了一个高层次的界面来绘制有吸引力的和信息丰富的统计图形。— seaborn
这个库是可视化的下一步。我们可以制作美丽的情节,甚至只需一个命令就可以制作多个情节。让我们开始探索 seaborn 吧。随附的 GitHub 存储库如下:
[## kb22/理解-Seaborn
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/kb22/Understanding-Seaborn)
输入数据
为了理解不同的情节,我从 Kaggle 中选择了一个关于加州房价的数据集。因此,我的第一步是导入允许我读取 CSV 文件的pandas库,然后使用head(5)打印行数、列名和前 5 行。
我们的数据集有 20640 行和 10 列,它们的名称在上面的要点中有描述。我们也来看看前 5 排是什么样子的。

dataset.csv
海生的
先从进口matplotlib说起吧。请注意,我使用的是 matplotlib 版本 3.0.3,而不是最新版本,因为有一个错误会破坏热图,使其变得无用。然后,我导入了seaborn。最后,为了确保 Jupyter 中的情节显示在笔记本中,我们使用了命令%matplotlib inline。
让我们开始探索剧情吧!
散点图
当我们想要显示两个要素或一个要素与标注之间的关系时,散点图非常有用。这很有用,因为我们还可以描述每个数据点的大小,给它们涂上不同的颜色,并使用不同的标记。让我们看看 seaborn 中的基本命令是做什么的。

Scatter plot in seaborn
上图描述了total_rooms和total_bedrooms之间的关系。仅仅一个命令就完成了这一切,但是等等,还有更多。
使用 figsize,我将大小增加到 12x8。然后,我用基于median_house_value的每个数据点的大小、基于ocean_proximity的使用hue的颜色和基于ocean_proximity的使用style的标记更新了散点图命令。此外,没有适当的标题和轴标签的图是不完整的,所以我也添加了它们。

Updated scatter plot using seaborn
正如你所看到的,这个情节看起来比上一个好得多,还包括一个很好的图例,所以任何人都可以看到和理解这个情节——这是它应该的方式。
计数图
计数图根据某个分类列自动计算数据点,并将数据显示为条形图。这在分类问题中非常有用,我们想看看不同的类是否有相同的大小。然而,由于这不是一个分类数据,并且只有一个分类列,所以我决定使用它。
seaborn 中的情节允许我们使用annotate将text添加到每个条形中。仔细观察数据集,我们会发现许多元数据信息都丢失了。例如,列ocean_proximity的值<1H OCEAN在任何地方都没有描述过。人们应该始终收集元数据信息,并使用具有适当信息的数据集。因为这只是理解图的参考数据集,所以没什么大不了的。

Count plot using seaborn
在上面的图中,我们可以看到该列的数据高度倾斜。让文本和条形在一起真的很有用,因为仅从图上看,最后一个类型ISLAND看起来像是零值。
直方图
直方图是显示连续数据点并查看其分布情况的有效方法。我们可以看到,大部分值都在较低的一侧,或较高的一侧,或均匀分布。
seaborn 的dist图根据数据生成直方图和密度线。我定义了总共 10 个容器,这样整个median_house_value被分配到 10 个不同的桶中。

Histogram (with density) in seaborn
正如我们所看到的,分布似乎很正常,在较高的一侧有一个轻微的峰值。上图中的蓝线定义了密度的分布。
小提琴情节
在与 seaborn 合作之前,我总是在各种文章中看到这些看起来很奇怪的情节,并想知道它们是什么。然后,我阅读了它们,发现它们是小提琴图,非常类似于箱线图,根据密度描绘宽度,以反映数据分布。在 seaborn,创建一个小提琴情节只是一个命令。

Violin plot in seaborn
在我们继续之前,让我们看看如何理解这些情节。考虑绿色地块INLAND。从零延伸到大约 250000 的黑线是 95%的置信区间。内部的黑色厚块是四分位数范围,意味着大约 50%的数据位于该范围内。图的宽度基于数据的密度。我们可以理解为这个特定数据集的直方图,以黑线为 x 轴,被完全平滑并旋转 90 度。
热图
相关矩阵有助于我们了解所有特性和标签之间的相互关系以及依赖程度。pandas数据帧有一个名为corr()的函数,它会生成一个关联矩阵,当我们将它输入到 seaborn 热图时,我们会得到一个漂亮的热图。将annot设置为 True 可确保相关性也用数字定义。

Heatmap in seaborn
虽然整个情节很有用,但我们可以从最后一栏开始,注意每个特征如何与标签median_house_value相关联。median_income与值为0.69的标签最相关。
联合地块
联合图是散点图与密度图(直方图)的组合,用于我们尝试绘制的两种特征。seaborn 的联合图允许我们甚至使用kind作为reg单独绘制一个线性回归。我用height作为8定义了正方形的尺寸,用green定义了颜色。

Joint plot in seaborn
绿线表示基于数据点的线性回归。
带群图的箱线图
箱线图将信息分成独立的四分位数和中位数。当与swarm图重叠时,数据点分布在其位置上,因此完全没有重叠。

Box plot (and swarm plot) in seaborn
从上面的印迹中,我们可以看到ocean_proximity中五个类别的箱线图是如何描述的。数据点揭示了数据是如何分布的。
配对图
成对绘图会在每对要素和标注之间产生大量绘图。对于要素/标注的每个组合,此图显示一个散点图,对于每个组合本身,它显示一个直方图。该图本身对于获取手头数据的精华非常有用。

Pait plot in seaborn
上面的图包含了大量的信息,而且只需要一个命令。
结论
在本文中,我们探索了一些无限的 seaborn 情节,可以更好地理解该库如何工作以及它能够做什么。不断练习和试验,因为选择几乎是无限的。
这里还有一些你可能会喜欢的文章:
使用 Matplotlib 创建世界各地人口密度的美丽可视化。
towardsdatascience.com](/matplotlib-making-data-visualization-interesting-8bac1eb3d25c) [## 使用 Python 中的多个绘图库在地图上绘制商业位置
比较地图打印库
towardsdatascience.com](/plotting-business-locations-on-maps-using-multiple-plotting-libraries-in-python-45a00ea770af) [## numpy——Python 变得高效
文章列举了几个提高 Python 效率和速度的 Numpy 函数,并介绍了 4 个 Numpy 函数
towardsdatascience.com](/numpy-python-made-efficient-f82a2d84b6f7) [## Google Colab——您在云上的 Python 工作空间
了解 Google Colab
towardsdatascience.com](/google-colab-your-python-workspace-on-cloud-c3aed424de0d)
欢迎分享你的想法、想法和建议。我很乐意收到你的来信。也可以通过 LinkedIn 联系我。
将深度学习环境与 Terraform、Google cloud、Gitlab 和 Docker 无缝集成

当你开始一些严肃的深度学习项目时,你通常会遇到需要一个合适的 GPU 的问题。购买适合深度学习工作负载的合理工作站很容易变得非常昂贵。幸运的是,云中有一些选项。我尝试的一个方法是使用美妙的谷歌计算引擎。在 GCE 中,GPU 可以作为实例的外部加速器。目前,有这些 GPU 可用(价格为美国中心 1)。
- 英伟达特斯拉 P4:每月每 GPU 1267.28 美元
- NVIDIA Tesla V100:每个 GPU 每月 306.60 美元
- 英伟达特斯拉 P100:每月每 GPU 746.06 美元
- NVIDIA Tesla K80:每月每 GPU 229.95 美元
手动配置通常不是您可以轻松扩展的事情,所以我做了一些调查,看是否有方法可以尽可能无缝地扩展我的环境,并以同样的方式破坏它。因此,我找到了一个解决方案,使用 terraform 在谷歌计算平台上建立基础设施。源代码从 Git 部署,Docker 容器自动启动,安装了所有必要的依赖项,如 tensorflow、keras 和 jupyter。在这篇博文中,我将指导你如何轻松设置环境的各个步骤。一些工作基于这个 git 库:https://github.com/Cheukting/GCP-GPU-Jupyter
你会从博文中学到什么?
- 以自动化的方式使用 GPU 设置 GCE 实例
- 如何与 GCP 一起使用 terraform
- 如何将 Gitlab 存储库的代码部署到 GCE 实例中

What we will build in this blog post.
如上图所示,我将向您展示如何编写一个 terraform 脚本,该脚本自动启动一个 Google compute engine 虚拟机,在其上安装 CUDA、Docker 等,并最终使用来自另一个外部 Git 存储库(在我们的例子中是来自 gitlab)的代码启动一个 Docker 容器。这个 Docker 容器运行的是 jupyter 笔记本服务器,可以通过浏览器从外部访问。此外,我将向您展示如何使用 Docker 在虚拟机中运行笔记本之外的更长时间的任务。
TL;速度三角形定位法(dead reckoning)
只是想试试,那就去看看 TL;DR 部分,列出了所有必要的命令。
为您的 python 代码创建 Gitlab 库
如果你已经有一个想要给我们的知识库,请随意。否则,现在应该创建一个新的存储库。https://gitlab.com/。你所有的 ml 和 data exploration 代码都将进入这个库。我们将把它与基础设施代码分开。
同样,在这个 Gitlab 存储库中,您现在可以添加所有代码,例如,创建一个简单的 train.py python 文件来训练神经网络,并在最后保存训练好的权重。这里可以找到一个非常简单的例子:https://gitlab.com/dice89/deep-learning-experiments
这个 repo 只包含一个用于数据探索的 Jupyter 笔记本和一个用于训练 RNN·LSTM 文本生成模型的 train.py 。
创建您自己的 Docker 图像/使用现有的图像
您可以采用现有的 Docker 图像,也可以创建自己的图像。为了简单起见,我们将使用预构建的 Docker 映像,其中安装了 python 3.5 环境,并包含了合理的深度学习用例所需的所有库。它应该包含第一次尝试所需的一切:python 3。x,tensorflow-gpu,numpy,pandas,sklearn,keras
如果你感兴趣,你可以看看这张图片:https://hub.docker.com/r/dice89/ubuntu-gpu-python-dl/
使用 Terraform 配置和启动实例
Terraform 是一个“基础设施即代码”工具包,允许您通过编写代码来定义、创建和销毁基础设施。这带来了很多好处:例如,你不需要像在 GCP 控制台中那样通过 UI 来配置任何东西。此外,默认情况下,您的整个基础设施配置都有文档记录,因为它是可读的代码,在 git 存储库中有理想的版本。我一年前才发现 Terraform,已经无法想象没有它如何建立基础设施。Hashicorp 发现了可编码和可版本化基础设施的完美结合,这可以用编码者的心态来理解。您只需要一些 terraform 文件和 terraform CLI 来创建您的基础架构。
添加新的 Google compute 实例很容易创建,如下所示:
Example of a gcloud compute instance creation with terraform.
在创建实例之前,您需要预先执行一些步骤:
- 创建 gcloud 帐户(https://cloud.google.com/)
- 安装 gcloud CLI 工具作为 Google Cloud SDK 的一部分
- 使用您的终端“gcloud auth login”登录 gcloud
在下面的代码片段中,您将创建一个 gcloud 项目,将执行上下文设置为您的当前帐户,创建一个能够创建新实例的服务帐户,最后下载私钥以在 terraform 中使用该服务帐户。
在您的 CLI 中执行这些命令,并用您想要的项目名称替换
在我们开始实例之前,让我们看一下关于如何配置一个支持 GPU 的 Google compute 实例的细节。不幸的是,你必须为 GPU 申请一个配额(直到 2018 年 12 月没有它,它一直为我工作)。请听从本 Stackoverflow 文章 的建议。处理此请求可能需要 2 个工作日。
Google Compute Instance with a GPU
正如您在第 19 行中看到的,我们向该实例添加了一个 Tesla K80 GPU,启动时我们在一个脚本中执行一些操作( start-up-script.sh )。如下所示:
Setting up Ubuntu VM to run with CUDA
在这个脚本中,我们安装所有需要的库,为用户添加一个 ssh 密钥,并运行 Docker 容器,将端口 80 暴露给外界。因此,我们可以到达 jupyter 笔记本服务器。请注意,创建此实例后,任何知道 IP 的人都可以访问您的笔记本。即使对于像这样的短命环境,这也应该改变。现在创建一个新的 ssh 密钥,以便能够将我们的代码从 Gitlab 部署到实例中。
ssh-keygen -t rsa -b 4096 -C “your_email@example.com”
为了使它工作,您必须将占位符“在此添加您的 SSH 密钥”替换为您生成的私有(!!!)在启动脚本. sh 中输入 ssh 密钥。请注意:不要与任何人分享您的密钥!从这个存储库中克隆完整的配置,然后更改您的 ssh 密钥:https://gitlab.com/dice89/google-cloud-gpu-vm.(不要将您的私钥提交给任何 git 存储库)另外,确保您的 credentials.json 在这个文件夹的根目录中(不要提交 credentials.json)。您还必须将这个 ssh 密钥添加到您的 gitlab 帐户,以便可以部署来自 Gitlab 存储库的代码。
现在我们准备创建机器。这仅用 3 个 bash 命令就可以实现!🚀
填写您的 GCP 项目 id 类型“是”,您的实例将被创建(还要考虑这将导致的成本,免费层不包括 GPU)。创建实例后,您将看到一个发布到命令行的 IP 地址。这是您的公共 IP,您的 jupyter 实例将在该 IP 下可用。可能需要几分钟的时间,直到启动脚本. sh 完成并安装好所有东西。
在脚本完成之前,让我们花点时间来研究一下这个实例。为了做到这一点,你必须 ssh 到它。幸运的是,谷歌为我们提供了一个命令。
gcloud compute --project “<your>_dl” ssh --zone “europe-west1-d” “gpu-vm”
start-up-script.sh 作为根用户运行,因此,您必须切换到您的根控制台来查看发生了什么。
sudo su
cd /var/log
tail -f syslog | grep startup-script
现在我们在实例上,可以检查,例如,是否安装并使用了 GPU。
nvidia-smi -l 1
我们还可以安装 htop,因为它可以方便地监控正在运行的进程的内存消耗:
sudo apt-get install htop
过一会儿,您可以检查是否已经有 Docker 容器在运行:
docker ps
如果你在这个概览上看到你的 Docker 容器,你已经准备好在显示的 IP 下登录你的 jupyter 笔记本。
此外,如果你进入路径~/data science/deep-learning-experiments,你会看到它会自动挂载到你的 Docker 容器中的 /root/project 下,并包含你的 gitlab 库的内容,如 train.py 。
在 jupyter 外执行训练任务
Jupyter 非常适合一些数据探索或实验代码。然而,训练深度学习模型需要很多时间,你不能承受 jupyter 会话崩溃和丢失所有训练进度。幸运的是,有一种补救方法。通过运行 Docker 容器作为守护进程,运行 python 脚本来训练您的模型,您可以非常容易地训练一个新模型。例如,在我们的示例类型中,您需要做的所有事情都是。
docker run --runtime=nvidia -d -v ~/datascience:/root/project dice89/ubuntu-gpu-python-dl python3 /root/project/deep-learning-experiments/train.py
如果您现在检查 docker ps ,您会看到类似这样的内容:

要查看训练任务的日志,只需输入:
docker logs <your_container_id_from docker ps>
最后,您将使用 Git 存储库中的代码以可重复的方式训练您的模型。当您完成并保存和储存了您的体重后,您只需输入:
terraform destroy \
-var 'project_id=<your>-dl' \
-var 'region=europe-west1-d'
如果您需要相同的环境,只需输入:
terraform apply \
-var 'project_id=<your>-dl' \
-var 'region=europe-west1-d'
所以,这就是这个关于如何使用云资源创建深度学习环境的小演练。祝你试用愉快,如果你有任何改善环境的建议,请给我一些反馈。
TL;速度三角形定位法(dead reckoning)
下面是使用预定义的 Docker 容器创建环境的说明。用你喜欢的前缀替换
1.创建 gcloud 帐户
2.安装 g cloud CLI:https://cloud.google.com/sdk/docs/downloads-interactive
curl [https://sdk.cloud.google.com](https://sdk.cloud.google.com) | bash
exec -l $SHELL
gcloud init
3.创建 Gcloud 帐户和项目(替换
gcloud projects create <your>-dl --enable-cloud-apis
gcloud config set project <your>-dl
gcloud services enable compute.googleapis.com
4.安装地形:https://www.terraform.io/intro/getting-started/install.html
brew install terraform
6.(如果你想给它部署一些代码的话是可选的)Fork 和 git 克隆深度学习实验
https://git lab . com/dice 89/deep-learning-experiments/forks/new
git clone [git@gitlab.com](mailto:git@gitlab.com):<your_user>/deep-learning-experiments.git
7.Git 克隆代码,用 GPU 定义 Google 计算引擎 VM
git clone git@gitlab.com:dice89/google-cloud-gpu-vm.git
cd google-cloud-gpu-vm
6.创建 ssh 密钥
ssh-keygen -t rsa -b 4096 -C “your_email@example.com”
7.将私有 ssh 密钥添加到 Google 云基础架构“start_up_script.sh”
8.将公共 ssh 密钥添加到您的 Gitlab 帐户
9.创建一个 GCP 服务帐户并获取凭据
gcloud iam service-accounts create gcp-terraform-dl --display-name gcp-terraform-dlgcloud projects add-iam-policy-binding <your>-dl \
--member='serviceAccount:gcp-terraform-dl@<your>-dl.iam.gserviceaccount.com' --role='roles/owner'gcloud iam service-accounts keys create 'credentials.json' --iam-account='gcp-terraform-dl@<your>-dl.iam.gserviceaccount.com'
10.初始化你的地形环境
terraform init
11.启动环境
terraform apply \
-var 'project_id=<your>-dl' \
-var 'region=europe-west1-d'
稍等片刻(大约 5-10 分钟),查看您的 jupyter 笔记本电脑服务器的 IP 地址:
terraform show | grep assigned_nat_ip
要 ssh 到您计算实例:
gcloud compute — project “<your>-dl” ssh — zone “europe-west1-d” “gpu-vm”
12.破坏环境
terraform destroy \
-var 'project_id=<your>-dl' \
-var 'region=europe-west1-d'
如果你发现教程有什么问题,请向我反映!我非常希望它保持最新。
搜索算法介绍-广度优先搜索
搜索
从头开始 Python 实现
搜索是关于规划的,广泛应用于自动驾驶汽车和路线规划。在本帖中,我们来谈谈在给定的静态环境下寻找可行路径的问题。结构遵循这里的课程,我们直接进入一个问题,基于问题设置引入 first search。
设置
假设我们生活在 2D 网格世界中:
网格大小为 5 乘 6,0 表示可用,1 表示堵塞。我们从点[0, 0]开始,目标位于右下角[4, 5]。有 4 个动作可用left, right, up and down对应delta_name中列出的 4 个符号。现在的问题是找到一条从起点到目标的可行路径。
横向优先搜索
有许多搜索算法,让我们从广度优先搜索开始。与深度优先搜索相反,广度优先搜索开始水平扩展搜索路径:

refer to wiki
如图所示,从节点1开始,在深入到下一层之前,它会探索它的所有邻居。与我们的问题设置相同,我们的 2d 网格世界也可以被视为一个可扩展的树,我们从初始点[0, 0]开始,从这里,我们只能向下到[1, 0]或直接到[0, 1],只有在迭代完所有这些邻居之后,我们才会探索下一级的节点。
因此,让我们考虑一下实现广度优先搜索需要哪些组件。首先,我们肯定需要维护一个当前扩展路径的队列或列表,并且能够弹出下一个最低级别的节点。其次,我们应该维护另一个列表来跟踪所有被访问过的节点,这样我们就不会两次访问一个节点。
所以这里的close是我们追踪所有访问过的节点并用值1表示它们的列表,而open_list是扩展路径,其中每个元素记录了节点的级别和节点位置→ [g_value, x, y]。
搜索路径不断扩展,直到:
- 没有可浏览的节点:
len(open_list) == 0 - 找到目标:
[cur_x, cur_y] == goal
sort和reverse确保每次弹出最小级别的节点。如果在那个层次上没有找到目标,它将通过迭代所有可能的动作来扩展节点,同时通过nxt_g = cur_g + cost添加层次。
最后,我们打印出结果:
[11, 4, 5]
所以需要 11 步才能达到我们的目标[4, 5]。你可以算出 11 实际上是我们的最优值。
上面的代码贯穿了整个过程,但是好像缺了点什么……我们并没有真正找到我们的路径并打印出来!
要打印出我们的路径,我们需要在扩展时跟踪每个单元格中采取的每个动作,然后以相反的方式从目标到初始点,以获得我们的最终路径。
列表action在展开过程中跟踪每个动作,就像在 for 循环中一样:
action[nxt_x][nxt_y] = delta.index(d)
扩展后的行动列表包括:
[-1, 3, -1, 0, 3, 3]
[2, 2, -1, 0, 3, 3]
[2, 2, 3, 3, -1, 2]
[2, 2, -1, -1, -1, 2]
[2, 2, 3, 3, -1, 2]
策略列表从目标状态开始,以相反的方式打印出代表动作的符号,最后,我们得到最终结果:
['>', 'v', ' ', ' ', ' ', ' ']
[' ', 'v', ' ', '>', '>', 'v']
[' ', '>', '>', '^', ' ', 'v']
[' ', ' ', ' ', ' ', ' ', 'v']
[' ', ' ', ' ', ' ', ' ', '*']
您可能会注意到有多条最佳路径,但是该算法只能根据扩展顺序打印一条路径。我们将在下一篇文章中介绍另一个实现,它给出了所有的最优路径。
最后,广度优先搜索可以找到给定条件下的最优结果:
如果路径代价是节点深度的非减函数,则广度优先搜索是最优的。最常见的情况是所有的行为都有相同的成本。
一个直观的理解是,由于广度优先搜索仅在当前级别的所有节点都已被访问时探索下一级别,所以它总是在可能的最低级别中找到目标。
参考:
在 GCP 上用人工智能搜索外星人

Photo by Austin Johnson on Unsplash
一个使用 SETI 开放数据的项目
他们说学习数据科学的最好方法是创造一些东西。
一旦你使用教科书、博客文章,当然还有 MOOCs(大规模开放在线课程)覆盖了数据处理、编码和统计的基础知识,接下来要做的就是做一个你感兴趣的项目。通过这种方式,您可以使用您所学的各种工具和技术,另外,您可以以一种现实而有意义的方式进行数据科学研究,因为您必须实际找到数据,为分析做好准备,最重要的是,您必须提出要问的问题。
对我来说,这就是我最近花了几年时间学习无数在线课程的地方。我已经达到了 MOOC 疲劳的暂时状态,我想做一些长期而深入的工作。我开始四处寻找有趣的数据,最终偶然发现了来自 SETI 研究所(搜寻外星智能)的各种文件和 GitHub 知识库。
最初,看起来我需要的所有数据和代码都是可用的,包括 IBM 托管的一些大数据集,加上一些分析代码。然后我意识到,相当一部分是来自已经停止的项目,留给我许多零碎的东西,但没有具体的东西。
令人欣慰的是,在收到几封邮件后,SETI 的人热心地帮助我,并明确表示,让“公民科学家”参与进来是他们希望在未来做得更多的事情。我加入了他们的 Slack 频道,打了一个 Skype 电话,并获得了几个额外数据集的链接。这是一种惊人的、令人耳目一新的接触数据爱好者的方法,我以前从未遇到过。
满怀热情的我接着回顾了 SETI 过去和现在的所有公众参与项目,以便找到我的项目想法。
SETI 和公民科学
2016 年 1 月,伯克利大学伯克利 SETI 研究中心启动了一项名为突破倾听的计划,被描述为“迄今为止最全面的外星通讯搜索”。无线电数据目前由西弗吉尼亚州的格林班克天文台和新南威尔士的巴夏礼天文台收集,光学数据由加利福尼亚州的自动行星探测器收集。
为了吸引公众,Breakthrough listen 的主要方法是一种名为 SETI@Home 的东西,可以下载并安装一个程序,空闲时可以用你的电脑下载数据包并对其进行各种分析。
除此之外,他们还共享了一些启动脚本和一些数据。脚本可以在 GitHub 这里找到,数据存档可以在这里找到(虽然大部分是“基带”格式,与我一直使用的“滤波器库”格式相比,这是一种更原始的格式)。请注意,来自自动行星探测器的光学数据也是一种不同的格式,称为“FITS”文件。
SETI 让公众参与的第二个举措是 2016 年 9 月启动的 SETI@IBMCloud 项目。这为公众提供了通过 IBM 云平台访问大量数据的机会。这个项目也附带了一个优秀的启动脚本集合,这个集合仍然可以在 GitHub 这里找到。不幸的是,在编写本报告时,该项目被搁置,数据无法访问。
SETI 对深度学习的运用
SETI 还有一些其他的在线数据来源。2017 年夏天,他们举办了一场机器学习挑战,向参与者提供了各种大小的模拟数据集以及盲测集。获胜团队使用卷积神经网络实现了 94.7%的分类准确率。这项挑战的目的是尝试一种新的信号检测方法,即超越传统的信号分析方法,在将信号转换为光谱图后,将问题转化为图像分类任务。

A squiggly signal in simualated SETI data
主要训练数据已被删除,但数据的“基本”、“小型”和“中型”版本仍在 GitHub 页面上。这些信号的详细性质以及更详细的挑战描述可以在这里找到。
注意,许多由 SETI 编写的托管在 Github 上的脚本使用了一个名为 ibmseti 的非标准 Python 包。
SETI 在机器学习方面的工作最近成为头条新闻,当时一种深度学习算法被应用于来自绿色银行望远镜的大量数据,这些数据与一个名为 FRB 121102 的射电源有关。被认为来自 30 亿光年外的一个矮星系,一些神秘的信号被发现,让媒体陷入外星人引发的狂热。然而,这些信号的一些细节,如它们的极化,表明它们已经通过了一个极其强大的磁场,导致了它们来自一颗中子星的假设,也许是在一个大质量黑洞附近。
进一步的细节可以在张,格里等人的论文“快速无线电突发 121102 脉冲检测和周期性:机器学习方法”中找到天体物理学报 866.2 (2018): 149。
这项工作的所有数据和相应论文的链接可以在这里找到。
ABACAD 寻找 ET 的方法
一些 SETI 数据寻找非常快速的信号,即在很宽的频率范围内存在很短时间的信号。来自上述快速射电爆发论文的数据使用了这样的数据。另一种 SETI 数据被用来做相反的事情,即信号在很窄的频率窗口在较长的时间帧。这类数据从一开始就让我更感兴趣,因为它似乎更有可能包含任何有目的的外星信号。
然后我看到了下面这篇文章:对智慧生命的突破性监听搜索:对 692 颗邻近恒星的 1.1-1.9 GHz 观测。天体物理学报 849.2 (2017): 104。
在其中,使用非机器学习技术分析了来自 692 颗恒星的此类数据,其中许多基础数据是共享的(从现在起我将把这项工作称为“突破 692”论文/项目)。使用的一种技术被称为“ABACAD”方法。思路如下:从目标恒星(第一个“A”)收集数据,然后将望远镜移动到不同的目标(“B”)。然后,回到 A,然后是另一个目标 C,再次回到 A,然后是最后一个不同的目标 d。这个想法是,如果信号来自主要目标恒星,它将出现在所有 3 A 扫描中。然而,如果一个信号来自陆地,它可能会在所有 6 次扫描中出现。
这篇论文让我产生了将这些数据用于机器学习的想法。我找到了我的项目!
我的项目
最初,我开始玩 2017 年 SETI 夏季机器学习挑战的模拟数据。起初我在本地这样做(即使用我的家用台式电脑),然后很快转移到在 Kaggle 上工作,这要感谢他们免费的数据托管和 GPU 支持。我创建了一个笔记本(在 Kaggle 上称为“内核”),介绍了典型的 SETI 数据和 filterbank 文件格式,随后是一个使用深度学习区分不同类型模拟数据的笔记本(根据夏季挑战)。
然后,我转向突破性的 692 数据,并决定尝试使用云计算来实现这一点,因为我知道,在 ABACAD 搜索中生成的大量 filterbank 文件中翻腾将受益于云平台提供的缩放能力。不幸的是,我对这个主题知之甚少,所以我暂停了这个项目,直到我在 Coursera 上完成了出色的谷歌云平台专业化数据工程。
一旦完成,我就开始在 GCP 数据实验室(谷歌的云版 Jupyter 笔记本)上整理代码。我把这个问题分成 4 个部分,
- 创建谱图图像——将滤波器组数据转换成谱图图像文件
- 模拟数据 —这必须与 ABACAD 搜索得出的数据类型相似,与夏季挑战赛的模拟数据截然不同
- 构建深度学习模型 —使用模拟数据创建和评估模型
- 从 ABACAD filterbank 文件中进行预测 —使用模型发现信号,不仅仅是每个图像,还包括 ABACAD 扫描技术的背景
模拟数据
为了模拟数据,我想出了一些类别(部分基于夏季挑战类别,部分基于我在突破 692 结果中看到的)。这些是:噪音、线条、断续线、抖动和曲线。我试图确保信号水平和背景噪声水平的种类,以及像素的数量,与突破 692 项目中看到的数据种类相匹配。下面是每种方法的一些例子,
线

维布尔

斩线

曲线

噪音

该代码有一个变量列表,它可以取某个范围内的任何值。这些包括数值变量,例如背景噪声水平、信号强度、线的梯度、截断线中间隙的大小等。这些是每次随机选择的,允许批量创建每个图像类别的变体。还有一些更多的实验变量,如一个叫做“幽灵”的变量,其中信号的副本被复制到主信号的左侧和右侧。然而,我还没有探究它的影响。
构建深度学习模型
对于这个项目的深度学习方面,我最初使用了 VGG19 和 InceptionNet 等预构建模型。然而,我后来得出结论,对于这个应用程序来说,这些可能过于复杂,所以最终使用 Keras 框架来构建一个简单的模型架构(受我读过的一些 Keras 博客帖子的启发)。我使用的模型总结如下:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 188, 188, 32) 9632
_________________________________________________________________
activation_1 (Activation) (None, 188, 188, 32) 0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 94, 94, 32) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 94, 94, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 90, 90, 32) 25632
_________________________________________________________________
activation_2 (Activation) (None, 90, 90, 32) 0
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 45, 45, 32) 0
_________________________________________________________________
dropout_2 (Dropout) (None, 45, 45, 32) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 43, 43, 64) 18496
_________________________________________________________________
activation_3 (Activation) (None, 43, 43, 64) 0
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 21, 21, 64) 0
_________________________________________________________________
dropout_3 (Dropout) (None, 21, 21, 64) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 28224) 0
_________________________________________________________________
dense_1 (Dense) (None, 197) 5560325
_________________________________________________________________
dropout_4 (Dropout) (None, 197) 0
_________________________________________________________________
dense_2 (Dense) (None, 5) 990
然后,我使用 RMSprop 优化器对其进行了 100 多个时期的训练,给出了以下准确度和损耗图。

这实现了大约 84%的测试数据准确性。下面是测试阶段的混淆矩阵,

单幅图像预测
一旦模型被创建,我需要一些图像来测试。我从突破 692 论文里取了一些,看看模型给出了什么。下面是几张来自 HIP4436 的图片,第一张是噪点,

这是模型的预测,

如你所见,它正确地将其归类为噪声。接下来,有信号存在的图像,

这个预测,

“line”类是明显的赢家。
根据 ABACAD 过滤器库文件进行预测
从 filterbank 文件中提取一部分并对其进行分类是很好的,但正如前面提到的,SETI 使用 ABACAD 搜索技术来决定目标是否是感兴趣的。为此,我编写了一个“评分函数”(我在代码中实际上称之为“外星人探测器”,因为这样听起来更酷),对 6 幅图像进行预测,对应于 6 个 filterbank 文件的相同频率范围,然后应用一些简单的规则,通过分配点数来决定整体模式是否令人感兴趣。评分工作如下,

例如,6 个“噪音”结果得零分。事实上,6 手任何一个相同的信号都不得分(例如线-线-线-线-线)。一个或多个 A 扫描中的一种信号类型与 B、C 和 D 扫描中的不同类型得到一些点,最大值分配给 3 A 扫描中的一种信号类型,B、C 和 D 为噪声(例如wibble-noise-wibble-noise-wibble-noise)。
这似乎工作得很好。例如,在 Breakthrough 692 论文中,使用非 ML 信号检测方法将以下标记为可能的候选者(HIP65352 ),

使用深度学习,这得到一个很低的分数,因为 B 扫描(倒数第二个),你可以仅仅用眼睛看到有一条微弱的线存在,被检测到。
回到前面使用的 HIP4436 示例,我们有以下图像集合,

用深度学习模型给出以下预测:‘线’,‘噪声’,‘线’,‘噪声’,‘线’,‘噪声’,,如预期。这得到最高分。
新建数据
上面的例子使用了从突破 692 论文中共享的小数据文件。然而,SETI 向公众公开了大量未经处理的数据。分析单个目标所需的 x6 filterbank 文件高达令人瞠目的 100GB。我将这些文件用于 HIP4436,并将这 6 个文件中的前 3000 个频率片转换成 PNG 图像文件。
这些然后通过深度学习模型发送,然后通过评分功能,最后结果被保存到 csv 文件中。对于如此少量的频率,这将产生一个微小且易于使用的文件,但如果处理整个滤波器组范围,产生的 csv 文件将有 50 万个条目(尽管您总是只能保存“命中”,这将少得多)。
为了将结果转换成更加“云友好”的格式,我测试了从结果中创建一个 BigQuery 数据库。这非常简单,并且可以作为处理管道的一部分来完成,然后允许感兴趣的团体搜索高分目标。举个例子,
SELECT *
FROM SETI _ results . SETI _ results _ table
其中分数> 0
按分数排序 DESC
给出最高得分目标。
整体流程
下图显示了如何将此流程放入一个简单的管道中,不同的流交错排列,以显示扫描完成后可以立即开始处理 A1 数据(在所有流完成并输入评分功能后,结果将与其他 5 个流合并)。
这些独立的流甚至可以由 6 个不同的 GCP 实例来处理,从而大大加快速度。

时间就是金钱
据我所知,SETI 数据的一个问题似乎是它的剪切比例。单个 filterbank 文件是 17GB,我们每个目标处理 6 个。在每个单独图像的频率分辨率下,每个滤波器组生成 500,000 个图像。因此,每个目标都需要通过深度学习模型处理惊人的 300 万张图像。
我在一个 GCP 实例上测试了一些东西,具体来说,是一个带有 1 个 NVIDIA Tesla K80 GPU 的 n1-standard-8 (8 个 vCPUs,30 GB 内存)。利用这一点,我能够对每次扫描的 2999 幅图像做出预测,或者在大约 187 秒内总共 17,994 幅图像。基于此,300 万次预测需要大约 8 个小时。
我们可以从下面的成本计算器中看到,如果我永久保留这个实例,成本将是每天 15 美元左右。因此,使用这种方法可以处理全套 6 个滤波器组文件,费用约为 5 美元。

因为这是云计算,如果可以承受更高的成本水平,这个价格可以降低以节省资金,或者分析一组 filterbank 文件的时间可以减少(甚至大大减少)。
下一步去哪里?
由于我不是 SETI 的专业研究人员,毫无疑问,上述所有方面都可以改进,包括:
- 数据模拟 —改善信号类别(信号形状、信号电平、信号噪声等)。在给定图像中包括不止一个信号(例如几行而不是一行)。我最初生成了一个名为“brightpixel”的图像类,用于夏季 ML 挑战赛。然而,这似乎破坏了我的模型。这可以进一步调查
- 深度学习模型 —尝试不同的模型配置、不同的超参数、不同的预处理方法等。针对更多数据和更多时期进行训练
- ABACAD 评分 —为决定 ABACAD 功能的结果设计一个更好的评分系统
- 大规模模型部署 —使用 GCP 允许过滤器库集合(来自 ABACAD 搜索的 x6)通过部署的模型自动运行
- 代码优化 —通过提高代码效率来加速预测
欢迎专业人士的任何意见或建议。
这个项目的代码可以在这里找到。
感谢 Emilio Enriquez、Andrew Siemion 和 Steve Croft 在这方面的帮助,以及 SETI 对让公民科学家研究这些迷人数据的普遍开放态度。
在洛杉矶县寻找食物沙漠

img source: robrogers.com
在最近的一个数据科学项目中,我与其他几位 Lambda 学校的学生合作,在洛杉矶县寻找食物沙漠。食物沙漠的一般定义是在一英里范围内没有杂货店/市场提供新鲜、健康的食物,如水果、蔬菜、肉类等。我们想验证低收入社区更有可能生活在食物沙漠的理论。
第一步:获取数据
我们需要为这个项目找到 3 种主要类型的数据:洛杉矶县的杂货店/市场的数据,洛杉矶县每个邮政编码的地理数据,最后是每个邮政编码的收入数据。
对于杂货店,我们从 SNAP retailers 数据库获取所有加州的数据,然后过滤洛杉矶县的数据。不幸的是,这一数据过于宽泛,因为它包含了许多便利店、酒类商店和其他随机机构,这些机构不应该有资格提供健康和新鲜的食物。使用 regex,我们试图尽可能多地消除这些不合格的机构。最后,我们使用每个市场的纬度和经度,并使用 Shapely 库生成一个点对象。

接下来,我们能够找到洛杉矶县每个邮政编码的地理信息。然而,由于地球的曲率,我们需要将这些数据转换成二维表示,或投影,以便我们可以用图形显示它。我们将数据读入 geopandas 数据帧,然后调用 to_crs() 方法,并传入“epsg=4326 ”,该方法将地理数据从 GIS 坐标转换为纬度/经度,并格式化邮政编码多边形对象,以便在二维可视化中正确显示。


我们获得的最终数据是洛杉矶县每个邮政编码的家庭收入中值,我们将其存储在 pandas 数据框架中,以便在项目的后期与 food desert 和杂货密度合并。
.
第二步:在整个洛杉矶县进行网格搜索
我们希望对整个洛杉矶县进行彻底的网格搜索,以确定任何食品沙漠的位置,并为每个邮政编码汇编一些汇总统计数据,如 1 英里内杂货店的平均数量,以计算每个邮政编码的杂货店密度指标。然后,我们将这些数据与每个邮政编码的平均收入进行比较,并检查结果。
首先,对于每个邮政编码,我们在邮政编码的地理边界周围创建了一个矩形,然后从西北角开始,以四分之一英里的步长水平(向东)迭代,然后再次从西边开始,但向下走四分之一英里,再次水平迭代,重复这个过程,直到整个区域都被遍历完。在每一步,我们都生成一个 Shapely Point 对象,并附加到该邮政编码的列表中。我们将每个邮政编码内的点列表添加到地理数据框架的新列中。对于整个洛杉矶县来说,这导致了将近 58,000 点。

接下来,对于每个邮政编码,我们遍历点列表中的每个点。对于每个点,我们使用 buffer() 方法在每个点周围画一个半径为一英里的圆,并将该圆保存为一个形状良好的多边形对象。因为每个形状良好的多边形对象都包含组成该对象形状外部的所有坐标的值,所以我们可以为该多边形调用 contains() 方法并传入一个坐标。无论给定坐标是否位于多边形对象的内部,该方法都会返回一个布尔值 True 或 False。
为了测试食物沙漠,我们可以检查所有市场的坐标,看看它们是否存在于那个圆圈的边界内。然而,数据框包含几千个市场,对洛杉矶县的每个市场的每个生成点执行这种检查在计算上是非常昂贵的。不用遍历数据框架中的每个市场,我们可以通过首先过滤坐标在我们的圆的正方形边界内的市场来大大加快这个过程,我们可以使用圆的 bounds 属性(一个形状良好的多边形对象)来访问它。现在,我们要测试的市场列表大大减少了。对于正方形内的每个市场,如果圆圈对象包含市场坐标,我们增加圆圈内食品杂货的数量。

最后,为了创建一个食品杂货密度统计数据以及一个包含所有食物沙漠点的主列表(在该点的一英里半径范围内没有找到市场),我们创建了一个函数来迭代每个邮政编码,然后迭代点列表中的每个点。我们为每个邮政编码初始化了一个计数器,记录在点列表中找到的食物沙漠的数量。我们还初始化了两个空列表,一个记录找到的食物沙漠的位置,另一个记录列表中每个点的圆圈内的食品数量。
遍历每个邮政编码后,我们对结果进行解包,以创建一个所有找到的食物沙漠的主列表,并按邮政编码计算汇总统计数据,如杂货密度(找到的附近杂货的平均数量,以及每个邮政编码的食物沙漠的总数)。
步骤 3:分析结果并创建可视化:
在解开详尽的网格搜索结果后,我们首先想要创建一个食物沙漠发现位置的可视化。如你所见,大部分位于洛杉矶县的北半部和西部。这些地区通常要么是国家公园,山区,甚至是真正的沙漠,所以这些食物沙漠的存在是完全有道理的。

接下来,我们根据邮政编码绘制了杂货店的密度。如你所见,城市中心的密度最高。

最后,我们想检查相对于收入的食品杂货密度,所以我们将收入分成 4 个范围,并绘制每个范围的平均食品杂货密度。

有趣的是,我们的结果似乎表明,低收入地区实际上比高收入地区有更高的杂货店密度。
结论/要点:
在考虑了为什么我们的结果与我们的预期相矛盾之后,我们学到了一些很好的数据科学经验。首先,任何数据科学项目的结果通常最终取决于底层数据的质量。在我们的例子中,市场和杂货店列表的基础数据过于宽泛。即使我们尽了最大努力使用 regex 手动过滤掉不合格的机构,仍然有数百到数千个“市场”可能不符合资格。不幸的是,我们没有足够的工时来逐一检查每一家店,并确定是否有健康/新鲜的食物。
此外,由于洛杉矶独特的地形,许多富人区位于蔓延的丘陵/山腰和海滨地区。这些较富裕的家庭大多拥有汽车,开车去一英里以外的杂货店没有问题。相反,收入较低的家庭往往位于人口更稠密的城市地区。这些家庭的成员通常没有汽车,但可以通过步行、骑自行车或使用公共交通工具出行。由于这些地区的总体密度较高,并且因为我们的市场数据框架包括许多街角商店、杂货店或民族商店/零售机构,这些地区的杂货密度最终高于高收入邮政编码地区。
总的来说,我认为这是一个伟大和令人愉快的项目。我在一些新的 python 库方面获得了一些经验,包括 GeoPandas、Shapely、pyproj,制作了一些简洁的地理数据可视化,并在此过程中学习了一些有价值的数据科学课程。
如果有兴趣看看我们的一些代码,这里有一个链接指向这个博客的笔记本,这里有一个链接指向我们的团队回购
西雅图 AirBnB 市场价格分析
查看 AirBnB 西雅图公共数据集进行价格预测,并了解预测变量

Fig.1.Dr. Frasier Crane looks out on Seattle in the series finale, on March 23, 2004. FROM NBC/NBCU PHOTO BANK/GETTY IMAGES.
每当我看到“西雅图”时,这句名言就在我脑海中回响:“下午好,西雅图。这是弗雷泽·克雷恩博士。”。看过这部电视剧的人都知道克雷恩博士有一套华丽的公寓。我敢肯定,如果他的公寓在 airbnb 上,就不会一直空着。我告诉你,我们会看看能有多少。
我们的数据集来自 Kaggle。1
文档和笔记本也可以在https://github.com/elifinspace/udacity_crispdm找到。
快速浏览一下数据,让我们从一些问题开始:
- 西雅图的高峰日是什么时候?
- 哪些地区比其他地区更贵?
- 决定价格的主要因素是什么?
数据探索
让我们开始探索数据集。我们有 3 个数据文件:
- 日历. csv
- listings.csv
- 点评. csv
日历数据集有每个列表的日期和价格。通过简单地计算工作日和月份的平均值,结果是周六是最昂贵的工作日,平均值为86.69 美元,而七月是最昂贵的月份,平均值为94.76 美元。

Fig.2

Fig.3
我们的第二个数据集 listings.csv 包含位置、便利设施、运营成本和价格等信息。
通过邮政编码或邻近地区计算平均值将有助于我们了解哪些地区价格更高。我选择使用邻居,因为它比邮政编码或邻居组更细粒度。我已经用叶子来绘图了。3

Fig.4. Mean Price by Neighbourhood Group Cleansed
近距离观察西雅图市中心:

Fig.5 Mean Price by Neighbourhood Group Cleansed (zoomed)
原来安妮女王是最贵的地区。随着我们远离中心,平均价格越来越低。
不仅是西雅图市中心,西雅图南部的一些地方似乎也很贵,比如西西雅图的滨水区和贝尔镇(西雅图的西北部),如下图所示。

Fig.6 Mean Price by Neighbourhood Group Cleansed (zoomed)
克兰博士虚构的公寓位于安妮女王区,有 3 间卧室,3.5 间浴室。快速搜索位置,卧室和浴室的数量,整个公寓的价格将在 750 美元左右。
我们的第三个数据集 reviews.csv 包含评论、按日期排列的评论和列表。经过一些数据争论,我决定使用评论极性。我看到评论不仅是英语的,还有法语、德语和其他几种语言的。我只使用了英语评论,并按邻里群体划分了评论的极性。

Comment Polarity by Neighbourhood Group
评论极性图与邻近地区的平均价格一致。虽然安妮女王有更大的极性(更积极),但大学区与其他街区相比极性较低。类似地,其他昂贵的地区如西西雅图也有很高的评论极性。这个结果告诉我们,邻居在定价中起着重要的作用,这是合理的。
特征选择
让我们看一下列表数据,看看哪些字段与邻居相关。除了“邻里”和“邻里 _ 团体 _ 净化”之外,我们还有一些自由文本栏“邻里概况”、“描述”和“交通”。为了简单起见,我选择只使用这些列的极性,而不是更复杂的语义分析。
我添加了几个特性,如“time_to_first_review”和“time_since_last_review”作为流行度的指标,并删除了原来的日期列。计算结果见。
我使用的另一个分类特征是列表中的“便利设施”。我们知道,就顾客满意度和价格而言,便利设施非常重要。后来我们会发现我们没有错。
回归
我选择了 RandomForestRegressor 来预测价格[4]。在这种情况下,Ridge 和 SVR 不起作用。
为了评估我们回归器的性能,我们可以看看 mse(均方误差)和 r2 得分,这是数据与拟合回归线接近程度的统计度量。
r2 得分为 0.63,这很好,下图也显示了回归变量的预测效果。回归器对于大值的表现不是很好,可能是因为缺少训练样本。

Measured vs Predicted Values (Scaled Prices with a factor 100)
那么我们的回归变量用于预测的特征是什么呢?
首先,请记住,在基于树的算法中,每个特征的贡献不是单个预定值,而是取决于特征向量的其余部分,该特征向量确定了遍历树的决策路径,从而确定了沿途经过的保护/贡献。[5]
绝对特征重要性与特征:
index feature coefficient
0 12 bedrooms 0.413892
1 15 cleaning_fee 0.053380
2 101 private room 0.039854
3 81 description_polarity 0.036671
4 14 security_deposit 0.030007
5 10 accommodates 0.029731
6 7 latitude 0.027472
7 36 reviews_per_month 0.027280
8 11 bathrooms 0.025478
9 23 availability_365 0.023142
当我们看上面的特征重要性表时,“卧室”是最重要的因素。此外,一些相关的功能,如“容纳”和“浴室”也在最重要的 10 个功能。我们知道容纳更多人的房间总是更贵。此外,我们可以看到,房间类型“私人房间”在定价中也起着重要作用。
“清洁费”似乎与“保证金”和“可用性 _365”一样对定价有显著影响。这些是与运营成本相关的变量。成本越高,价格就越高。
供求定律是一种经济理论,它解释了供给和需求之间的关系,以及这种关系如何影响商品和服务的价格。这是一个基本的经济原则,当商品或服务供大于求时,价格就会下跌。当需求超过供给时,价格就会上涨。[6]这解释了为什么我们在这个表格中有“每月评论”。
“纬度”和“描述极性”是与邻里关系相关的变量。如果你看一下列表,你会看到“描述”有时包括关于便利设施和邻居的信息。所以描述越正面,价格越高。而“纬度”,即一个点相对于赤道的南北位置,被证明是一个重要的因素。因为西雅图有一个狭长的形状,这意味着纬度比经度变化更大,因此纬度而不是经度对价格的影响更大。
结论
我们看到,位置、运营成本、便利设施和受欢迎程度是决定价格的主要因素。
从而通过谈判降低运营成本,在中心位置有一个宽敞的地方,提供私人房间而不是共享或整个公寓。而且,公开露面有助于空中旅馆赚更多的钱。此外,为什么不通过提供折扣或其他活动在高峰期吸引更多的客人呢?
感谢您的阅读!
参考资料:
【2】:【https://pypi.org/project/folium/
3:https://www . thrillist . com/home/photo-tour-of-frasi er-crane-s-Seattle-apartment
[4]:https://sci kit-learn . org/stable/tutorial/machine _ learning _ map/index . html
【5】:https://blog.datadive.net/interpreting-random-forests/
[6]:https://www . investopedia . com/ask/answers/033115/how-law-supply-and-demand-affect-prices . ASP
帮助我学习机器学习的秘密元素!

Photo by Emily Morter on Unsplash
这段旅程开始于将近一年半前。
我还记得我以前看那些机器学习需要的复杂的数学概念的时候会觉得不舒服。更糟糕的是,我非常焦虑和不知所措,因为有大量的概念需要学习。
我曾经怀疑,质疑自己。
我能做到吗?
你数学不是很好,你还能做到吗?
有那么多东西要学,你还能做到吗?
但在所有这些问题中,有一件事没有让我停下来。这更加激励了我的学习。秘密且通常被遗忘的元素。
我过去常常问这么多问题。好奇心达到顶峰。我很想知道:这些东西是如何工作的?为什么只有这种方式?为什么不是这条路?,如果我们把这块换成这块呢?
"尽可能以最散漫、最不敬和最原始的方式努力学习你最感兴趣的东西."理查德·费曼
伴随着好奇心而来的是学习的意愿。它不再是一个负担。现在你学习不是因为外在的官能,你想学习是因为你想知道和理解事物,你想知道你早就问过自己的问题的答案,你只是不想成为一个旁观者,你想成为这个领域的参与者。
如果你不够好奇,你只是在强迫自己去学东西。近期是不行了。你要么放弃,要么把自己打得太狠!两者都将导致不幸。
相信我,一旦你足够好奇,你会把学习放在首位,像孩子一样开始提问。
机器学习主要是关于实验的。这是一个反复的过程。你有一种直觉,认为这东西可以工作,你尝试了。它不起作用。你试了另一个。它也不起作用。别担心,让我们试试这个,看看是否可行。而且它起作用了,现在你可以愉快地记录下你已经尝试了什么,什么起作用了,什么不起作用了,并给出最好的理由。你将这些知识融入到你的下一个项目中。
这就是我学习机器学习的方式。
甚至在理解任何新概念的时候,都是从好奇心开始的。如此多的问题开始出现。这个概念带来了什么不同的东西或想法?和以前的方法有什么不同?它在其他环境中也会起作用吗?从中可以学到什么?
明白重点了吗?都是问题。
在这个快节奏的世界里,时间紧迫,压力重重,我们常常会忘记真正的要点。这篇文章是对你的一个善意的提醒。
“重要的是不要停止提问。好奇心有它存在的理由。”
― 阿尔伯特·爱因斯坦
你不需要为难自己。你只需要更加好奇。
如果您发现它在任何方面都有帮助,请确保帮助我传播这个消息,并关注我以获得更多这样的文章。和平与力量。
谷歌基于网络的 OCR 服务的秘密
光学字符识别简介

Photo by Edward Ma on Unsplash
光学字符识别(OCR)是连接现实世界和虚拟世界的方法之一。第一个 OCR 系统是在 20 世纪 20 年代末推出的。OCR 的目标是从图像中识别文本。然而,由于许多因素,实现非常高的精度是非常具有挑战性的。在下面的故事中,我将介绍谷歌如何构建解决方案,这是谷歌云视觉 API 之一,以解决这个问题。

谈到 OCR, tesseract 是一个著名的开源库,每个人都可以利用它来执行 OCR。宇宙魔方由惠普发现,自 2006 年以来一直由谷歌赞助开发。Tesseract 3.x 模型是旧版本,而 4.x 版本是由深度学习(LSTM)构建的。如果你想了解 3.x 和 4.x 的区别,你可以访问分享了解更多细节。
由于 tesseract 是由 C++实现的,我们不能像调用其他 python 库一样调用它。事实上,我们可以在 python 中调用 C-API,但是它对用户不太友好。因此,python 包装器pytesserac的引入让我们的生活变得更加轻松。
定义
在介绍架构设计之前,需要介绍一些定义。
- 脚本 vs 语言:脚本不同于语言。文字指的是书写系统,而语言大多数时候指的是口语。在下图中,“数据科学家”是罗马体的英语,而“书局科学家”是罗马体的中文。

Script vs Language
- 边界框:与其他 OCR 系统不同,边界框包括单行检测文本,而不是单个字符或单个单词。
- 模型考虑:除了准确性,成本,通用性和可维护性也被考虑来建立模型。

给出一幅图像,它要经过 5 个阶段才能在谷歌视觉 API 中得到最终结果。

Google Cloud Vision API Architecture (Walker et al., 2018)
文本检测
第一步是使用传统的基于神经网络(CNN)的模型来检测和定位文本行,并生成一组边界框。
方向识别
按边界框对方向进行分类。如果需要,一些边界框将被过滤掉,因为它被错误地检测为文本。
脚本识别
标识每个边界框的脚本。假设每个边界框有一个脚本,但允许每个图像有多个脚本。
文本识别
这是 OCR 的核心部分,它从图像中识别文本。它不仅包括基于字符的语言模型,还包括初始风格的光学模型和自定义解码算法。

Inception Model (Fujii et al., 2017)
布局分析
确定订单的阅读和区分标题、页眉等。
实验
如前所述,宇宙魔方是由谷歌赞助的。我想这也是作者拿结果和宇宙魔方比较的原因之一。模型比较采用字符差错率(CER)。它被定义为编辑距离除以参考长度并乘以 100。越低越好。

Tesseract vs Google Cloud Vision API (Walker et al. 2018)
拿走
持有一,为什么图像处理步骤不包括在管道中?论文没有提到原因。我相信这是由于神经网络模型已经能够捕捉那些特征。
除了性能,速度是另一个考虑因素。从我的经验来看,宇宙魔方在识别方面做得很好,但速度相当慢。
关于我
我是湾区的数据科学家。专注于数据科学、人工智能,尤其是 NLP 和平台相关领域的最新发展。你可以通过媒体博客、 LinkedIn 或 Github 联系我。
参考
沃克 j,藤井 y,Popat A. C..2018.基于网络的文档 OCR 服务。
王晓东,王晓东,王晓东,王晓东,王晓东,王晓东。..2017.用于多语言 OCR 的序列到标签文字识别。
成功的数据科学面试秘诀
所以,你被叫去参加一个数据科学面试…但是,你不清楚如何破解数据科学面试吗?你担心在数据科学面试中被拒绝吗?您是否对数据科学面试准备什么感到困惑?如果你有以上问题,那么你就来对地方了。我们有兴趣分享我们从作为被采访者和采访者的经历中学到的东西。
您正在阅读本文档,这反映了您作为一名成功的数据科学家的认真态度。在数据科学这个已经非常广泛且迅速发展的领域中面试,对你和面试官来说都是一个挑战。面试试图分几轮评估您的数据科学能力,每轮持续一小时,而您的学习将持续一生。这让面试官(我们去过!)处于一个不值得羡慕的位置,也就是说,如何评估像你这样充满热情、知识渊博的人?好的面试官会将你视为潜在的未来同事:他们需要你的帮助。我们相信,如果你是采访者,而我们是被采访者,你也许会要求我们按照下面提到的方式进行合作。
如何开始?
这一切都从你在简历中写了什么开始。期待你的简历中与数据科学相关的问题。这是可以理解的,他们在你的过去很深(>三年),但不要被他们困扰。我们相信你有能力给自己的简历上的任何东西一个很好的证明。请重访记忆巷。重新认识你的过去。假设你过去用方法 X 解决了某个问题,如果你现在要解决它,你有更好的方法 Y 吗?此外,问问你自己:我是否在简历上写了一些东西只是为了让面试官留下深刻印象,而不是根据这些来提问?如果你是面试官,你觉得公平吗?注意:这同样适用于技术博客,以及简历中的 github 链接。
解决问题:开放式和封闭式
您的数据科学深度将根据您解决问题的能力进行评估。这些问题可能是:
- 给定一个要求,如何解决。例如,你的企业正在失去客户,找到原因和解决方案。
- 给定一个解决方案,它能改进吗?例如,现有解决方案的“转换率”为 90%,您如何使其达到 91%。
你能重用你过去的方法,并使它们在一个新的但不同的环境中工作吗?你是否也能在最近所学的背景下反思你的旧方法?
这些是开放式问题,在面试范围内可能没有完整的解决方案。请记住,这些问题不是为了从你那里免费获得十亿美元的创业想法或可申请专利的想法;远非如此,这些纯粹是为了评估你解决问题的能力。事实上,他们中的一些人可能会对面试官试图解决的数据科学问题产生共鸣。
既然我们已经完成了开放式问题,这里有一个封闭式问题的样本:推导 CNN 的反向传播,解释梯度推进等。前者帮助面试官评估你对意外情况的反应,而后者建立了一个植根于标准理解的基线过滤器。尽你最大努力两者兼得。练习是关键。
机器学习
数据科学使用机器学习作为关键技术之一。是的,它可能还会用到神经科学、行为经济学、博弈论、统计力学、复杂性理论、非欧几何以及你所擅长的无数领域。然而,你被期望在工业环境中解决的问题需要作为主要技能的 ML 技术的健全知识;如果你是其他领域的专家,面试官会很高兴,但也请你是 ML 领域的专家。
这是他们将如何评估你的 ML 技能。
- 标准机器学习课程和书籍涵盖的主题:CS229(斯坦福),CS4780(康奈尔),6–034(麻省理工),PRML(克里斯·毕晓普),海量数据集的挖掘。
注意:PRML 是指示性的,我们并不是说你必须通读整本书。只要有可能,就用这些标准书籍来强化课程内容。 - 简历中提到的 ML 方法,但不是课程或书籍的一部分。
- ML 数学:线性代数、概率统计、多变量微积分、最优化基础(通常这些都包含在标准 ML 课程中)
深度学习
你是个深度学习的忍者。尽管你有强烈的感觉,为什么我们仍然认为你也需要对‘传统的’机器学习有一个良好的理解?深度学习模型的“黑箱”性质(你可能完全不同意)使得面试官很难知道你做了什么和模型做了什么。然而,ML 的传统形式似乎是所有候选人的良好公分母。如果一个人建造了一个双向 LSTM,却不知道 SVM 是如何工作的,会是什么样子?请继续,用你的 DL 技能让面试官眼花缭乱,但是在你用你的 ML 印章证明一两点之后。
你应该知道为什么你选择了一个模型/算法/方法/架构。超参数在 DL 中起着关键作用。培养对模型调整的良好理解。一个好的模型和一个不太好的模型之间的区别可能在于你对超参数的选择。
我们建议在参加面试前阅读以下材料:
- deeplearning.ai 在 Coursera 提供的深度学习专业化(5 门课程)
- Geoff Hinton 的 Coursera 神经网络课程,以加深对概念的理解。
- 涵盖编码器的全面深度学习课程http://www.cse.iitm.ac.in/~miteshk/CS7015.html
- 从长远来看,你可以去看看 Yoshua Bengio 和 Ian Goodfellow 写的深度学习书。
注意:我们并没有说你必须经历所有这些。通过细读高质量的内容来熟悉主题会给你信心,这种信心可以在不同的情况下转移。
使用工具的经验
公司会优先考虑那些不仅能清晰表达良好的数据科学解决方案,而且能够使用正确的工具高效实施的候选人。如果你能让自己对业内可用的工具感到舒适,那就太好了。你至少应该从语言的角度了解 python 或者 R,ML 算法的 scikit learn 库,深度学习的 Keras / tensorflow / pytorch / caffe。不要忽视查询语言,如 HQL、SQL 和分布式框架,如 hadoop 和 spark。好的组织对所有这些技能都有培训计划。被选中的候选人经常参加这些培训课程。熟悉以上工具会给你的候选人带来急需的优势。在你被选中后,一定要接受培训。这将暴露组织解决的问题,并有机会与组织中的其他科学家互动。作为一名新员工,这些都是非常重要的经验。
模型的生产和部署
面试官希望你知道机器学习模型是如何使用的,它是如何生产和部署的,以及你的模型的整体端到端架构。很难雇佣一个不知道客户/服务/顾客/产品将如何使用他的模型的人。没有部署,您构建的只是一个概念验证。在最好的情况下,它可以在您的笔记本电脑上进行演示。为了使你的 ML 模型有用,它需要成为软件管道的一部分。知道如何与工程师互动来部署模型。准备好卷起袖子,在没有任何人提示的情况下行动起来。通过这样做,你提高了自己的价值和在团队中的地位。
模型的生命周期管理
作为一名伟大的数据科学家,你应该了解 ML 模型的整个生命周期。你应该知道当你的模型试图模拟的世界改变时,你的模型应该如何改变。(这种情况比你想象的更频繁,因为现实世界并不在你的控制之下。)您将决定您的模型需要多长时间重新培训一次,以保持新鲜感。你可能还想自动化再培训过程,以节省你的宝贵时间。将迭代模型构建中节省的时间重新用于提高性能。为自己创造机会,解释你是如何在一个模型的生命周期中管理它的。
调试 ML 模型
调试是软件行业非常重要的技能。如果一个软件不能被调试,它就有很高的风险。你应该深入了解你的模型。你应该知道你所使用的算法的内部原理。您应该知道如何进行根本原因分析和调试您的模型。面试官希望你知道当模型有高偏差或高方差时,你将如何改善结果,你将如何避免爆炸梯度和消失梯度,以及你将如何在训练期间优化记忆等。
为什么反转链表仍然是一个好主意?
虽然数据结构和算法确实被外包给了软件包,但是您从数据中进行推理的能力是由您对算法和数据结构的理解所帮助的。虽然面试官不会要求你实现跳过列表或平衡 k-d 树,但他们仍然希望你理解算法的顺序复杂性,熟悉基本的数据结构,如链表、堆栈、树、哈希表和堆,并熟悉排序、最短路径、字符串处理等算法。换句话说,来自数据结构和算法的卫生问题。你可能认为通过这个镜头来评判你是不合适的,但是请记住你是在为比赛制造方便。我们相信你能胜任。
了解公司
你被要求参加面试的事实表明,你之前的经历已经被 HR 和 HM(招聘经理)认为是潜在的合适人选。不要停在那里!你有责任研究并了解你被叫去面试的团队是做什么的,以及你如何能增加价值——这是一个很好的区分。
问什么问什么,你有什么问题吗?
注意,这不是讨好面试官的邀请。像你在整个面试过程中一样正式礼貌。
这是展示您对如何作为数据科学团队的一员发挥作用的理解的绝佳机会。这也是一个让面试官看到你在面试中没有的优势的机会。例如,你可能擅长代码审查。你可以询问代码审查是如何工作的。你可以突出你最喜欢的方法,比如说走查。您可能想知道使用的开发平台。您可能会问团队中是否有开源贡献者(如果您是开源贡献者,这是再次强调的时候了)。你可以问交货周期。如果团队分布在不同的时区,检查交互是如何工作的。如果适用,分享您在此类团队中的工作经验。
询问你是否可以从高层次了解面试官参与的项目。比起想了解 WFH 政策或数据科学家的日常生活,这些问题要好得多。小心地措辞这些问题,因为你不是面试官!当然,最好只问两个问题,因为接下来的对话不会给你更多的机会。所以要小心选择,并根据面试的环境来选择。最重要的是,做一个耐心的倾听者,这是难忘对话的关键。
注意:不要试图通过夸大事实来催眠面试官。一如既往,要有尊严。记住,没有什么工作比你的尊严更重要。
一些有用的提示
- 请澄清。如果你认为问题不明确,问面试官澄清问题。其实这是数据科学家的一个重要技能,即理解需求。你越早问这些问题越好,因为这样可以节省时间,反过来也有助于面试官更好地评估你。
- 不要将讨论从 ML 主题移开。假设你没有做好深入某个话题的准备,但是面试官在向你这个方向提问。相信我们,转移话题不是一个好主意,原因有三。
- 这是不道德的。
- 如果成功了,你被选中了,你可能会得到一些你在面试中没有准备深入的工作。
- 大多数情况下是行不通的。面试官和你一样聪明,他们知道你何时试图回避或转移话题。你最终会给人留下不好的印象。
承认你对这个话题不太熟悉是值得尊敬的。如果可能的话,你可能仍然希望根据基本原则进行尝试,并问一些澄清性的问题。别担心,面试官会从你的简历转移到另一个话题。
处理拒绝
万一你这次没有成功,请放心,面试官不是为了好玩才这么做的。公司投入大量的时间和金钱来评估你,如果你没有做到,这仅仅意味着你需要更多的准备。你的申请没有被拒绝,只有你的 T2 申请被拒绝。此外,考虑这样一个事实,除了你之外,许多其他聪明能干的候选人也在面试你申请的职位。只选择几个候选人是这一过程的本质。如果不是你,对你来说也不是世界末日。(坦白地说,不要给任何人那种控制你的权力。)记下不带任何判断地问你的问题。但是先不要分析;让一两天时间让你恢复镇静。然后不带怨恨地思考下一次你如何成为更好的候选人。找出改进的机会,制定一个行动计划,并开始付诸行动,因为生活在过去或无所作为的状态中是没有用的。公司非常希望你在下一个周期再次申请(与人力资源部门核实一下时间)——我们中的许多人在被选中之前已经申请了不止一次。你的人力资源联系人也会努力提供反馈,但是请…请…请…不要开始反驳链。在这种情况下,表现得像一个数据科学家:如果数据(面试结果)与你的假设(你的准备)不一致,那么转向一个更好的假设,也就是说,下次做更好的准备。
好吧,这听起来可能有点哲学。然而,我们认为这是实用的,也是重要的,它能让你成为一个更好的候选人和一个更好的人。培养两种自我意识:内在的和外在的。前者是关于你有多了解自己;后者是关于你如何意识到别人对你的看法。应该清楚这两者是如何结合在一起为你创造一个富有成效的面试经历的。我们推荐你去看看塔莎·欧里奇的《洞察》。
什么是公平面试?
你可能在想,这看起来像是一个冗长的、充满了人造友好的长长的列表,以一种做作的方式对我提出了很多要求(这不是我的意图,也不是人造的友好;抱歉,我说的太多了)。你可能想知道作为公平面试过程的一部分,你会得到什么样的回报。以下是我们为候选人提供的内容。你可能期望从其他知名组织获得类似的经验。
公正的评价
- 没有问题映射到:我想出了一个 10 位数的随机数,猜对了。不,我们不指望你给出我们心中的答案;只要是正确答案,你的答案和我们的一样好。
- 我们不会把我们的个性投射到你身上。我觉得这很容易,因此你也应该觉得这很容易。
- 问题一完成就期待答案。在你回答之前,我们听听你的沉默或大声思考是完全没问题的。
- 没有技巧性问题或误导性问题。
- 我们两天前才知道的,我们不指望你一辈子都知道。因此,尽管我们最近读了一堆伟大的媒体文章,这些文章真的让我们觉得自己是天才,但我们不会基于它们问任何问题(嗅!)
- 一两个糟糕的答案会被良好的整体表现所补偿。
与你的经验和知识相关的问题
- 如果你的简历足够丰富,足以让你被邀请参加面试,那么它肯定也足够丰富,足以让我们把问题限制在简历的内容上。简历中没有的东西足以证明它超出了你的专业范围。这不包括基本的 ML 概念。
礼貌的对待
- 面试官自我介绍。
- 面试官会告诉你面试是如何组织的。
- 面试官会问你是否需要茶点。
- 面试官关注你。
- 面试官绝对不会做不道德的事情。例如,对你现在或过去的组织或教育机构进行粗鲁或讽刺的评论;鼓励你打破你的 NDA。
- 面试官永远不会让你不舒服。他们不会吓唬你或取笑你的答案。
- 面试官陪你去吃午饭,或者把你交给愿意带你去吃午饭的人。
祝你做好充分的准备。愿原力与你同在!!!
我们希望听到您的反馈。不要忘记与我们分享您的经验,告诉我们这些技巧如何帮助您成功通过数据科学面试。
联系我们:
- Suresh(沃尔玛实验室首席数据科学家)——【suresh.venkatasubramanian@gmail.com T2
- Himanshu(沃尔玛实验室数据科学家)——【himanshu6589@gmail.com
免责声明:以上观点是个人观点,不代表我们组织的立场。然而,我们确实希望任何专业组织都有一个公平的选择过程,反映上述各点。
安全外壳(SSH)提示和技巧

Photo by Jefferson Santos on Unsplash
作为一名程序员,我最喜欢的一点是我可以坐在沙滩上远程工作。但作为一名数据科学家,事情稍微有点棘手,因为我无法在本地笔记本电脑上执行任何大数据处理(我不会带着一台高规格但笨重的电脑去海滩……)。我仍然需要在拥有更多资源的远程服务器上运行我的下一个模型训练。尽管如此,不要担心,我们仍然有远程安全 shell 来拯救我们!
在这篇文章中,我将分享一些我在日常工作中使用过的 ssh 技巧。在做任何事情之前,让我们首先定义 bash 脚本的变量。
#!/bin/bash
user=usernameString
password=passwordString
serverAddr=IPAddressOfTheRemoteServer
serverPort=PortToBeTunnelledFromTheRemoteServer
sourceLoc=locationOfTheFolderToBeCopied
通过 SSH 仅复制更新的文件
有时候,我需要将大量文件从本地笔记本电脑复制到远程服务器。我在技术上可以使用 SCP 。然而,缺点是,如果我需要重复复制许多文件,其中大多数文件自上次操作以来没有更新过,SCP 仍然会盲目地将所有文件复制到服务器。为了减少复制所需的负载和时间,我们可以使用 rsync。Rsync 将只向服务器发送更新的文件。
rsync -avh -e ssh $sourceLoc $user@$serverAddr:$remoteLoc
远程运行脚本
假设我有一个名为 script.sh 的 shell 脚本,我想在远程服务器上执行它。我可以把它和前缀“bash -s”一起传递给 ssh 命令。
ssh ${user}@${serverAddr} 'bash -s' < script.sh
建立端口隧道(仅推荐用于调试!)
有些情况下,您可能无法在服务器外部公开端口(很可能是由于安全问题)。例如,假设我在服务器的端口 5000 上运行一个 web 服务。不幸的是,这个端口不能从外部 ping 通。我可以通过 ssh 执行隧道操作,将我的本地计算机的端口 5000(技术上可以是任何选择的\(localPort)链接到服务器的端口 5000(同样,任何\)serverPort 都可以)。这样,只要我保持 SSH 连接,当我在本地浏览器中访问 localhost:5000 时,我就会看到来自远程服务器的 web 服务的内容。
ssh -N -L localhost:$localPort:localhost:$serverPort ${user}@${serverAddr}
在终端的变量中写入密码(不推荐,仅用于调试)
使用基于密码的 ssh 意味着每次我们执行 SSH 命令时,都会提示我们输入密码。如果您曾经希望有一种方法可以将密码存储在终端的临时变量中(很可能太懒了),您会发现 sshpass 很有用。事实上,我们所需要做的就是将 sshpass -p $password 添加到任何普通的 ssh 命令中。下面是一个如何将 sshpass 与前面所有命令一起使用的示例。
sshpass -p $password rsync -avh -e ssh $sourceLoc $user@$serverAddr:$remoteLocsshpass -p $password ssh ${user}@${serverAddr} 'bash -s' < script.shsshpass -p $password ssh -N -L localhost:$localPort:localhost:$serverPort ${user}@${serverAddr}
结论
请谨慎使用 SSH。必须认真对待 IT 安全,尤其是考虑到最近网络攻击越来越普遍。如果您在公共网络中,请确保您只连接到安全的接入点。实际上,我并不推荐远程工作,比如在海滩上(这是个玩笑!)和 ssh-ing 到工作服务器。最安全的方法是只从内部网络访问资源(或者至少激活 VPN 连接)。
使用 Anaconda 保护带有环境变量的 API 密钥
如何在公共论坛分享项目时保证私人信息的安全?

如果您正在阅读本文,我假设您已经熟悉 API、令牌、私钥和公钥。您的私钥和公钥作为一种身份验证的形式,通过开发人员的 API 来识别您的身份并跟踪您的活动。这意味着,如果有人得到了你的密钥,他们就可以冒充你访问 API 中的数据,这可能会产生一些可怕的后果。
大多数崭露头角的数据科学家面临的挑战是,他们希望在公共论坛上推广他们的项目工作。如果这些项目中的任何一个使用 API,个人将不得不把他们的密钥加载到他们的笔记本中。换句话说,公开笔记本意味着危及 API 密钥的安全。
这个问题有几种常见的解决方案:第一种是用类似于******或YOUR_PRIVATE_KEY_HERE的东西来替换这个键。这在一定程度上是可行的,但是这种方法容易出现人为错误。对于单个项目的多次提交,每次都必须删除并重新添加令牌。当您按下 commit 并忘记清除密钥时,它就被破坏了。这不是会不会发生的问题,而是什么时候发生的问题。另一种选择是将 API 密钥保存到一个单独的 JSON 文件中,读取私钥,并在推送到 GitHub 时排除该文件。虽然这稍微好一点,但这里的问题是,其他想要探索您的工作的人必须对分叉的存储库进行编辑才能运行代码。此外,这并不能完全消除人为错误的可能性。
如果有一种方法可以将密钥和令牌保存到我们的系统文件中,以便在需要时调用,这不是很好吗?如果其他人可以使用相同的代码从他们自己的系统中调用他们自己的密钥和令牌,那不是更好吗?事实证明,有一个办法:环境变量!
什么是环境变量?
环境变量顾名思义:保存在本地环境中的变量,可以在任何项目中调用。因为它们不是存储库本身的一部分,所以没有必要限制推送到 GitHub 的信息。在下面的例子中,一个私有 API 密匙已经被保存为一个名为PRIVATE_API_KEY的环境变量。稍后我们将看看如何创建变量本身。
import osapi_key = os.environ.get("PRIVATE_API_KEY")
正如我们所见,这看起来非常干净简单。每当我们需要使用密钥时,我们所要做的就是调用api_key变量。更有经验的数据科学家在审查这段代码时应该会立即意识到需要使用他们自己的私钥,并将它们保存在他们自己的环境中。一旦完成,程序应该可以正常运行,不会出现任何问题。
这里需要注意的是,审查者需要使用相同的变量名保存 API 键。如果这个人已经使用不同的变量名将相关的键保存到了他们的环境中,他们可能会选择修改代码而不是他们的环境。如果 API 开发人员在他们的文档中为这些键提供推荐的命名约定,将会使这个过程更加优雅。但那是另一天的话题。
创建环境变量
在这篇文章中,我们不打算讨论跨项目管理环境的最佳实践。相反,我假设您已经在合适的环境中工作,并且知道如何使用 Anaconda 在它们之间切换。如果你不熟悉这个,我推荐你看看这个视频,作为这篇文章的基础。
创建这些变量的总体过程如下:
- 导航到存储包和详细信息的环境路径。
- 创建文件和目录,用于在调用时激活变量,并在使用完变量后停用变量。
- 将变量添加到相关文件中。
我将向您展示如何在 macOS、Linux 和 Windows 中处理所有这三个步骤。所有的指令都直接改编自 Anaconda 文档。
macOS 和 Linux
以下命令可用于使用终端处理步骤 1 和 2:
cd $CONDA_PREFIX
mkdir -p ./etc/conda/activate.d
mkdir -p ./etc/conda/deactivate.d
touch ./etc/conda/activate.d/env_vars.sh
touch ./etc/conda/deactivate.d/env_vars.sh
因此,我们现在有两个名为env_vars.sh的文件,它们分别存储在不同的目录中。我们需要在您选择的文本编辑器中打开这些文件来创建变量。对于activate.d目录中的文件,我们将添加以下内容:
*#!/bin/sh*
export PRIVATE_API_KEY='YOUR_PRIVATE_KEY_HERE'
对于 deactivate.d 目录中的文件,我们添加以下内容:
*#!/bin/sh*
unset MY_KEY
第一行#!/bin/sh让操作系统知道这些文件是 shell 脚本,以确保export和unset命令被正确执行。
一旦这些文件被保存并关闭,在终端输入conda activate analytics将YOUR_PRIATE_KEY_HERE保存到环境变量PRIVATE_API_KEY。使用完这些变量后,可以使用conda deactivate将它们从环境中删除。
Windows 操作系统
使用命令 shell,可以使用以下命令来处理步骤 1 和 2:
cd %CONDA_PREFIX%
mkdir .\etc\conda\activate.d
mkdir .\etc\conda\deactivate.d
type NUL > .\etc\conda\activate.d\env_vars.bat
type NUL > .\etc\conda\deactivate.d\env_vars.bat
因此,我们现在有两个名为env_vars.bat的文件,它们分别存储在不同的目录中。我们需要在您选择的文本编辑器中打开这些文件来创建变量。对于activate.d目录中的文件,我们将添加以下内容:
set PRIVATE_API_KEY='YOUR_PRIVATE_KEY_HERE'
对于 deactivate.d 目录中的文件,我们添加以下内容:
unset PRIVATE_API_KEY=
一旦保存并关闭这些文件,在终端中输入conda activate analytics将YOUR_PRIATE_KEY_HERE保存到环境变量PRIVATE_API_KEY。使用完这些变量后,可以使用conda deactivate将它们从环境中删除。
结论
正如您所看到的,虽然将 API 键保存为环境变量需要几个步骤,但这本身并不困难或复杂。一旦就位,这些变量就可以快速而容易地访问,并且当您使用完它们时,只需一个命令就可以停用它们。这比每次你想对 GitHub 进行更新或提交新的提交时添加和删除键要有效得多。在向外界展示您的项目时,它会为您提供更多安全保障。
保护学习机器:
在尝试保护产品之前,先了解机器学习、人工神经网络和人工智能背后的基础知识

The Perceptron — The Simplest Model by Geoff Hinton
场景:
你刚刚被位于昂贵的硅谷某处的一家有前途且资金充足的“人工智能和人工智能”技术初创公司聘用为他们的第一名安全工程师。
你满足了他们对“技术堆栈”体验的所有要求,在面试中,你对如何处理复杂的安全问题表现出了热情和激情。你同意了这个提议,你已经准备好开始你的第一天。
有一个问题。
你对机器学习(ML)、人工神经网络(ANN)和营销界的新宠“人工智能”(A.I .)一无所知,也没有任何经验。为了简单起见,在整个故事中,我们将这一技术堆栈称为 ML/ANN/AI。
想象一下,您只有两周时间来熟悉支持产品堆栈的技术。
你从哪里以及如何开始?书籍?网络课程?只是谷歌的东西?

Don’t just Google stuff. Prepare a learning path. (Photo by Jacky Chiu on Unsplash)
首先,不要自责。你不是落后者。这些都是尖端技术,由于可使用的现成框架的爆炸式增长,它们最近悄悄进入了主流软件产品。
这些框架包括 Caffe,TensorFlow,PyTorch,NVIDIA DIGITS 和 RAPIDS,以及亚马逊 AWS,谷歌云平台和微软 Azure 基于云计算的产品。
所有人都称之为“机器学习的民主化”
我个人认为,如果有足够的动力和时间,即使没有 ML/ANN/AI 的实践经验,你仍然可以赶上技术,成为一名有效的安全工程师。
那么如何开始呢?
理解 ML/ANN/AI 的基础和构建模块是你的首要任务。
其余的,也就是你所支持的产品的代码和基础设施的实际实现,你可以边做边学。
对于安全工程师来说,在不了解其背后的基本原理或核心原则的情况下,保护基于尖端技术的新产品或服务是一场艰苦的战斗。
以下是我的一些个人建议,告诉你如何在短时间内掌握基本知识,以便开始帮助保护产品:
“理解 ML/ANN/AI 的基础和构建模块是你的首要任务。剩下的,就是你所支持的产品在代码和基础设施中的实际实现,你可以边做边学。”
(注:这是个人推荐,也是我熟悉 ML/ANN/AI 技术栈所走的路。绝不是唯一的办法,随便挑你喜欢的就行。我与课程的创建者和书籍作者没有业务关系)
在线课程
我建议在开始学习之前,先复习一下 Python 脚本/编码知识。在我开始学习之前,我已经不再每天写代码了,所以我在 Python 上有点吃力。但如果我能做到,你也能。
以下是我的学习经历:
1。 IBM 数据科学基础—一级 (免费)
数据科学概念、方法、工具包和业务用例介绍。完成时间:3 小时
2。 IBM 数据科学基础—二级 (免费)
1 级课程的延续。回顾数据科学工具和数据科学方法的介绍性概念、更深入的讨论和实践。完成时间:13 小时
3。 IBM 应用数据科学与 Python (免费)
现在是时候应用您在之前的数据科学基础课程中学到的数据科学概念和方法了。本课程将教你如何使用 Python 语言来清理、分析和可视化数据。课堂实验很短但很有帮助,因此你可以获得处理有趣数据问题的实践经验。使用 Python 深入研究数据分析和数据可视化。了解如何将事实上的 Python 库的基础知识用于数据科学 pandas、Matplotlib、Seaborn 和 Folium。完成时间:23 小时。
4。 IBM 机器学习用 Python (免费)
本课程将向您介绍使用 Python 进行机器学习的基础知识。它将向您介绍有监督和无监督的机器学习,流行的算法,如分类,回归,聚类和降维,以及流行的模型训练/测试分裂,均方根误差和随机森林。完成时间:12 小时。
5。 深度学习。人工智能神经网络和深度学习 ($$$)
由全球公认的机器学习先驱吴恩达创建和教授。深入探究神经网络和深度学习进化背后的理论和数学。
为繁重的数学和线性代数复习做准备。本课程将深入探讨深度学习介绍、神经网络基础知识以及浅层和深层神经网络。
由于大量的符号和公式,白板会议可能会让你睡着,请确保你及时休息,以便吸收关键概念。练习在自己的备忘单或白板上写下注释,以加强学习和视觉识别。

Computing gradients: One of Andrew Ng’s whiteboard session in his course.
这门课的编程练习完全值得一试。你将使用 Jupyter 笔记本,在复习了前面的基础课程后,你现在应该已经知道了。完成时间:18 小时。
"练习在你自己的备忘单或白板上书写符号,以加强学习和视觉识别."
6。 英伟达($ $)
这是一门优秀的入门课程,包括在 NVIDIA 的 DIGITS 平台上进行图像分类和对象检测的实际配置和编码练习。了解已经在平台上使用的图像分类中获奖的预训练模型 AlexNet、GoogleLeNet、LeNet 和 UNET。
您将探索深度学习的基础,并学习如何训练和提高神经网络的性能,学习深度学习工作流,实验数据、训练参数(也称为超参数调整)、网络结构和其他调整,以提高神经网络的性能和能力。

You will learn how to classify, train and tweak hyperparameters quickly using NVIDIA’s DIGITS platform.
完成本课程后,我立即获得了许多使用该平台进行图像分类的想法和业务用例。完成时间:8 小时以上。
书籍
按顺序排列,下面是我推荐给你的书籍,你可以阅读它们来提高你的基础知识或者扩展它们。
我还没有 100%看完所有这些书,但是从一本书跳到另一本书来改变一下步调,对你的学习道路很有帮助。
可能是我读过的关于神经网络的最好的入门材料。像伟大的理查德·费曼会如何解释一样解释(像我五岁/ELI5 一样解释)
2。 务实的艾乘诺亚的礼物
Noah 是一位好朋友兼柔术实践者写的,他已经在数据科学领域工作多年了。了解现代开发人员工作流程,以及如何利用云计算服务来运行机器学习工作负载。在职场上非常有用。
工程师的理想伴侣书。介绍深度学习概念和模型。了解如何使用 Python、Tensorflow 和 Keras。大量的示例代码和编码练习。在职场上非常有用。
4。 机器学习的向往:深度学习时代 AI 工程师的技术策略吴恩达
注册并获得该领域全球公认的领导者吴恩达的书的草稿。雄辩的文字说明,易于阅读。技术或数学方面没那么重。提倡简化工作流程,您可以从 Andrew 本人那里获得提示和指导!
5。 深度学习的 TensorFlow:从线性回归到强化学习拉姆伦达和扎德
通过 TensorFlow 学习机器学习的基础知识,tensor flow 是谷歌著名的深度学习软件库,使工程师可以直接设计和部署复杂的深度学习架构。了解如何使用 TensorFlow 构建能够检测图像中的对象、理解人类文本和预测潜在药物属性的系统。

Photo by NeONBRAND on Unsplash
总而言之,我想重申一下这个学习途径的目标:
作为一名新创公司的安全工程师,您需要了解使用 ML/ANN/AI 创建软件产品所涉及的基本原则、理论、技术和现代工具,以便您拥有保护产品的最基本的知识和背景。
拥有适当的上下文是生成您负责保护的产品的最小可行威胁模型的必要条件。
(精通是一件不同的事情,通常需要至少 10,000 小时对你的技能或专业领域的刻意练习。)
如果加上完成在线课程的总预计时间,总计 80 多个小时,大约三天。实际上,我会用一周的时间来完成这些课程,其中主要包括通过 Stack Overflow 和 GitHub 进行编码练习的研究。我可以在家连续两周从早上 9 点到晚上 12 点学习来完成这些课程。
目前,我正享受着翻阅我提供的书单,探索很酷的 GitHub 项目,如优步的 Ludwig 项目和 NVIDIA 的 DIGITS 平台,以及它如何帮助美国安全工程师快速原型化由 ML/ANN/AI 增强的信息安全工具。
如果你刚刚开始你的学习之路,犹豫不决,停滞不前,请告诉我,我会尽我所能给予回应和帮助。
享受你的学习之路。会有障碍和难以消化的概念,特别是如果你来自非计算机科学教育背景,但正如俗话所说,“这不是目的地,而是旅程”
去找你的 y 吧。明白吗?
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
您可能一直在犯的安全和加密错误
让我们澄清一些关于加密和安全的常见误解…

一般来说,关于密码学和安全性有很多神话和错误的假设。人们经常滥用密码原语,假设某些东西默认是安全的,或者使用过时的技术/算法。所以,让我们来看看这些误区和常见错误,这样你就可以在将来避免它们。
已经停止使用/dev/random
几乎所有人都会说,出于加密的目的,应该总是使用/dev/random。嗯,那是错误的。/dev/urandom和/dev/random都使用完全相同的 CSPRNG 。它们之间的区别是,/dev/random会阻塞,直到它有足够的熵。这是另一个问题——你不希望你的应用程序等待熵,并围绕/dev/random阻塞的可能性设计逻辑,特别是考虑到你不需要那么多熵...你所需要的是大约 256 比特的熵,这将从/dev/urandom中得到。如果你想更深入地研究这个话题,那么请看这里的文章。
永远不要使用 AES ECB
你肯定知道 AES 是一种分组密码。它以 128 位的块加密纯文本。好吧,听起来不错,那么使用 ECB(电子密码本)模式有什么问题呢?它在每个块上使用一个不变的密钥,所以如果你加密超过 128 位的数据,你的密文将看起来像这样:


这算不上什么加密,对吧?那么,你应该用什么来代替 ECB ?计数器模式(CTR)!为什么?因为加密可以并行完成,它使用 IV (nonce)来消除未更改的密钥问题,这是 ECB 模式所具有的。记住永远不要重复使用第四代。
这是密文在 CTR 模式下的样子:


可以用 *openssl* : 自己试试
永远不要对任何东西使用 MD5
当我们谈到永远不使用东西的话题时…忘掉 MD5 ,就像现在。它被设计用作一种安全的加密散列算法,但是在这一点上没有什么安全可言。它有冲突漏洞,您可以创建一对具有相同 MD5 哈希的文件,这意味着您可以伪造 SSL 或 CA 证书。那么,你应该用什么来代替呢?这取决于使用案例——对于密码散列使用bcrypt或scrypt。你用哪一个,在我看来是个人喜好- scrypt被设计成【更好】比bcrypt好,但它更新,所以它面临的审查更少。我个人仍然使用bcrypt。至于其他用例,使用来自 SHA-2 家族的哈希函数,最好是像 SHA-512 这样的长摘要。
总是先加密后 MAC
这一节的标题说“Encrypt-then-MAC”,但是让我们先回溯一点。很多人没有意识到他们应该始终将加密与消息认证结合使用。我不想详细解释为什么你应该验证消息,我要说的是,如果你不验证消息,那么你的应用程序就很容易受到攻击,比如重放攻击或主动攻击。
既然这样,为什么先加密然后 MAC ?简单地说,这是获得可证明安全性的唯一方法,这并不总是必要的,但这意味着当使用这种结构时,基本上不可能在密码上搞乱。
如果你想要更深入的解释,那么我推荐科林·帕西瓦尔的文章。
特殊字符不会让您的密码变得更好
不一定,至少。一个好的密码是你能记住的,所以加入像!@#$%^&*这样的字符会让你或你的应用程序的用户更有可能忘记它或者把它写在别人能看到的地方。
最初在密码中添加特殊字符的原因是什么?是熵,那么如果我们不想强迫用户在密码中包含特殊字符,那么有什么替代方案可以让熵保持足够高呢?
让它 loooong 。正如流行的 xkcd 密码强度漫画所示,使用由几个随机单词串联而成的密码比试图记住一些胡言乱语更有意义。创建这些类型的密码满足了人类和计算机两方面的要求,换句话说,它很容易记住并且很难猜测(高熵,无法暴力破解)。
注意:在理想世界中,每个人都会使用密码管理器并生成他们随机的超高熵密码,但这不是我们对普通非技术用户的期望。
加密密钥轮换误解
有人可能已经告诉过你,你应该每隔一段时间旋转你的密钥,没错,你绝对应该这么做。然而,许多人认为他们应该这样做以降低密钥被破解的可能性,而对于加密密钥来说,情况并非如此。您应该轮换加密密钥,以减少该密钥加密的数据量,从而降低单个密钥泄露造成的潜在损害。这种误解并没有改变你应该旋转键的事实,但是知道你为什么这样做是很重要的,这样你就可以正确地评估应该使用什么间隔。
不要存储用户密码
再次回到“千万不要做傻事”的话题。这是一个有点夸张的说法,我见过很多次了,一个网站在我注册后通过电子邮件给我发了一个密码…就像…当你从一个用户那里得到一个密码时,你应该做的第一件事就是散列它并扔掉密码的明文版本,如果你是通过电子邮件给我发的,那么你显然没有这样做(夸张结束)!
所以,让我们深呼吸一下…那么如何存储那些密码呢?
收到用户的密码后,立即使用工作系数至少为 12 的慢速哈希函数(如bcrypt)对其进行哈希运算,并从内存中删除明文密码。工作系数 12 在发布时是有效的现在是有效的,一年后仍然不够。我会亲自拍摄长达 400 毫秒的密码验证,你可以在你的机器上检查哪个工作因素会给你。
如果你不打算使用bcrypt,请确保在密码中添加盐,以防止预计算攻击,就像彩虹表攻击一样。
集装箱不安全
很多人认为默认情况下 Docker 容器是安全的,但事实并非如此。它们是为了解决部署问题而构建的,而不是安全问题。
甚至还有漏洞允许攻击者获得对主机系统的root访问权,而所需要的只是对容器的外壳访问权。那么,如何避免这些安全问题和漏洞呢?
- 使用最少的基础图像来减少攻击面 —这些图像的例子有基于
alpine的图像或 Red Hat 通用基础图像。 - 只安装必要的库 —容器中的库越少,被利用的可能性就越低。
- 使用受信任的图像——不要只是从 Docker Hub 下载任何图像。使用那些由值得信赖的团队审查、维护并有大量下载的网站。
- 不要使用
*latest*标签——通过使用固定标签,你可以确保在你的下一个版本中不会引入任何漏洞。 - 使用特权最低的用户(永远不要在
*root*)——用USER 1001命令结束Dockerfiles是一个很好的做法,这样可以确保你使用的用户没有特权,不会打开你的容器,从而暴露额外的漏洞。
你可以做更多的事情来保护你的图像,你可以稍后谷歌,但我认为上面的列表是每个人在使用图像/容器时应该记住的最低要求。
结论
每个软件开发者/DevOps 工程师都要对应用和系统的安全性负责,至少在一定程度上是这样(不管你喜不喜欢)。因此,我认为我们所有人都应该花一点时间做必要的研究,以确保避免类似上述的愚蠢错误和误解。
不要只相信别人告诉你的(人总是会犯错)。当涉及到安全和加密时,自己查找和检查—根据事实做出决定。
注:这最初发布在martinheinz . dev
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
人工智能和机器学习中的安全和隐私考虑—第 6 部分:近距离接触隐私
注意:这是“人工智能中的安全和隐私&机器学习”系列文章的第 6 部分。以下是所有文章的链接(到目前为止):

Photo by Jason Blackeye on Unsplash
在本系列的前一篇文章中,我们研究了攻击者如果也开始利用 AI/ML 的能力(这是不可避免的),可能造成的损害的性质和程度。在这一部分,我们将把注意力转移到另一个方面,在机器学习的背景下更仔细地研究隐私。
就隐私而言,人工智能/人工智能的进步带来了巨大的挑战。每一个新的场景——无论从功能和效用的角度来看多么引人注目——似乎都带来了影响和损害数据隐私的可怕的新方式。
让我们来看看隐私在人工智能/人工智能环境中的表现——治理、个人和组织的动机、隐私保证的技术机制、监管方面等等。
美丽新世界中的隐私治理
鉴于人工智能/人工智能场景的巨大利润可能性,在介绍隐私治理挑战时,很少有什么比近距离观察“剑桥分析”争议更好的了。
如果你没有听说过剑桥分析,首先,欢迎回到地球!😃.事情的要点是,2014 年,剑桥大学的一名心理学教授在脸书应用平台上发布了一款名为“这是你的数字生活”的“心理测量”/“个性档案”应用。该应用程序至少在纸面上征得了用户的同意,收集了他们的一些个人资料/个人信息。作为一项个性测试,它变得非常受欢迎,到 2016 年,约有 5000 万美国公民注册并参加了测试(这使作者能够了解和洞察 5000 万公民的个性!).
然而,在如何和为什么这样做方面存在一些问题。首先,该应用程序收集的个人数据远远超过了它获得同意的数量。第二,这位教授与一家名为 Cambridge Analytica (CA)的公司有业务往来,该公司专门为大型竞选活动提供咨询。这位教授(碰巧部分是俄罗斯人,部分是美国人)将这些数据以大约 2 亿美元的价格卖给了 CA。此外,剑桥分析公司的大投资者之一是一名共和党参议员,他也是特朗普总统竞选活动的重要助手。剩下的就是让我们把这些点联系起来。
下面的截图来自教授和他在加州大学的团队之间的电子邮件交流(克里斯·怀利成为了其中的一个告密者)。

“This is a start to get you thinking about what you may want…”
CA 争议不仅凸显了如何使用大数据分析/AI&ML 世界的技术来“大规模社会工程化”像民主这样的长期制度,它还对跨几个系统和组织边界的治理失败进行了出色的研究。这是一个严重的提醒:保护我们的隐私是如何建立在站不住脚的承诺之上的,而这些承诺可能会被一股令人信服的商业价值主张冲掉。
随着基于人工智能和人工智能的商业机会的扩大和变得更加普遍,各行各业的隐私和安全专业人士可能会面临类似的困境,即在收集和保留个人数据以及对其使用保持透明方面,应该在哪里划定界限。从一开始就没有非黑即白的事情——但是现在可能会有更多的灰色阴影。
正如我们所看到的,不幸的消费者记住这一点很重要:


On the internet you are the product!
说到这个话题,另一件需要注意的事情是,我们在社交网络平台上留下的“赞”已经被证明是关于我们的丰富信息来源。这项研究表明,只要知道 10 个赞,计算机模型就能判断或理解某人的个性,就像判断或理解同事一样,70 个赞时,它能胜过朋友,150 个赞时,它能胜过家庭成员,300 个赞时,它能胜过配偶!!
大数据、隐私和匿名
尽管 AI/ML 将挑战推向了一个全新的水平,但自大数据本身的早期以来(即远在机器学习回归主流之前),对隐私的担忧就一直很普遍。
许多大数据场景带来的一个经典问题是“推理控制”的挑战,即在不泄露数据集中个人隐私敏感信息的情况下,为各种研究/调查项目共享大规模数据集的摘录的能力。在深入研究机器学习环境中的隐私方面之前,让我们探索一下在挖掘大型数据集时多年来开发和使用的技术。

Privacy concerns have been around since early days of Big Data
包含人员数据的数据库通常具有列/属性,从隐私的角度来看,这些列/属性可以是以下类型之一:
(a)【PII】—这些栏目可以直接链接或识别一个人(例如,社会保险号、电子邮件地址等)。).
(b) 准标识符(QI) —这些列本身可能没有用处,但可以与其他 QI、查询结果和一些外部信息结合使用,以识别个人身份(例如,邮政编码、年龄、性别等)。).
(c) 敏感栏 —这些属性不是 PII 或 QI,但构成出于各种原因(如工资、HIV 诊断、居住地理位置等)需要保护的个人的数据。).
(d) 非敏感列 —这些是不符合上述(a)、(b)或(c)的剩余属性(例如,国家)。

Types of attributes from a privacy standpoint
显然,在合格中介机构存在的情况下,仅仅从数据集中删除 PII 列不足以保护隐私。例如,如果一个数据集中存在基本的人口统计数据(称为 QI ),那么它可以与其他公共数据源(如选民登记名单)相结合,以非常准确地识别个人。几年前,研究人员使用了这种方法,当时他们发现为 Netflix Prize 比赛共享的“匿名化”数据集可能会通过与另一个公共数据源的一些数据相关联而受到损害。IMDB 上用户对电影的评级。在这种情况下,研究人员利用 IMDB 公开提供的几个数据点来挖掘网飞数据集,并揭示了个人的整个电影观看历史(这被认为是敏感的,受美国隐私法规保护)。
那么什么可能有用呢?
向'k-匿名 '、'l-多样性 '和't-亲密度 '问好。
K-匿名用于保证对大型数据集的任何任意(基于 QI 的)查询都不会暴露有助于将群体缩小到“K”个人阈值以下的信息。也就是说,该技术提供了一种保证,即对于任何使用他们对特定个人的 qi 的知识从数据集中挖掘隐私敏感属性的人来说,将保持“至少 k”个记录的模糊性。
在这种情况下,具有一个或多个 qi 的相同值的数据集子集被称为“等价组”(或“等价类”)。例如,'在某个邮政编码的所有 30 岁以下的女性可以构成一个等价组。目标是确保攻击者无法利用此类查询来缩小范围并获取特定人员的敏感信息。本质上,“k-匿名”确保数据集的所有可能等价组至少有“k”条记录。
这是通过使用以下技术实现的:( a) 清除记录或列,其中一些记录可能被完全清除,或者某些 QI(例如,性别)可能在其他记录中被替换为“*”;或者(b) 概括,其中特定 QI 值被范围(例如,63 年→55-70 年)或数字替换为分类值(例如,87% →“通过”)—从而降低基于 QI 的查询对数据集的精确度。

A ‘k-anonymized’ result set (k=3)
对 k-匿名的攻击— 如果来自数据集的不同子集(可能出于不同目的发布)的结果未经排序,则“k-匿名”中使用的技术可能会受到攻击。例如,为不太敏感的场景发布的子集可能有一个有用的 QI,攻击者碰巧将它链接到使用其他信息的个人。然后,攻击者可以查看同一数据的一个更敏感的子集,如果这些行恰好处于相同的顺序,则将个人与敏感信息(例如,疾病)相关联。对此的缓解是随机化每个释放子集的顺序。
如果在每个等价组中包含敏感属性的记录没有足够的多样性,则另一类攻击开始起作用。在这种情况下,攻击者可以使用个人的一些背景信息来推断他们的敏感数据。在极端情况下,如果一个等价组中的所有记录都具有相同的敏感属性的值,那么攻击者甚至可以在没有背景信息的情况下做出推断。例如,如果匿名化的数据集揭示某一年龄范围(例如,20-30 岁)的个人的所有记录都患有特定疾病,并且如果攻击者知道特定的人(例如,该年龄组中的邻居)在数据集中,则他们可以断定此人患有相同的疾病。
因此,虽然 k-匿名提供了对 ' 成员推断 ' 攻击的抵抗,但是它不能防止“属性推断”攻击(这种攻击来自等价组的同质性)。

k-anonymized data lacking attribute diversity can leak sensitive info
L-Diversity 试图通过确保等价组具有“属性多样性”来解决这个问题。也就是说,它确保具有相同 QI 值(例如,相同年龄组)的数据集子集具有敏感属性的“足够多样性”(至少“l”个不同值)。此外,它试图在所有可能的等价组中达到这一点。请注意,“l-多样性”与“k-匿名”携手工作——它将“属性推断”保护添加到受“k-匿名”保护的“成员推断”数据集。
虽然“l-多样性”涵盖了“k-匿名”的弱点,但在具有许多 qi 的数据集上实现这一点是复杂和困难的(因为这会导致需要处理大量等价组)。此外,攻击者可以利用(a)属性值之间的语义关系或者(b)属性值具有非常不同的敏感度级别的情况来提取私人信息。它还假设攻击者不知道敏感属性在整个数据集中的实际全局分布(这通常是不正确的)。
T-closure通过有意识地保持每个敏感属性在等价组中的分布“接近”其在完整数据集中的分布来缓解这些弱点。在“t-接近度”中,敏感属性在等价组中的分布与该属性在整个表(或群体)中的分布之间的距离不超过阈值“t”。此外,它使用推土机距离(EMD)的概念来表示分布之间的“距离”,因为它具有消除不同属性敏感性影响的优点。
输入 AI/ML
当我们将 AI/ML 的算法和技术引入大数据领域时,挑战会上升到一个完全不同的水平。这是因为,与传统的基于查询/规则的数据提取/三角测量方法不同,ML & AI 场景可以以任意复杂的方式组合数百个输入维度/特征,因此,可以以迄今为止未知和不可理解的方式危及隐私。
大数据时代的技术在这个生态系统中苦苦挣扎。例如,“k-匿名”依赖于找到附近“k 记录”的能力,以返回进行查询——这是超维空间中一个已知的挑战/模糊的概念。例如,一个在线购物网站存储了数百个关于其客户的属性。当每个记录有如此多的维度时,“近邻”的概念变得很难确定——忘记能够对所有等价组都这样做吧!
现在让我们来看看一些有帮助的基本原则和当前的努力。
将隐私融入机器学习
差异隐私
最近许多分析 AI/ML 算法隐私保证的工作都利用了一个叫做差分隐私 (DP)的概念。
差分隐私提供了一个数学框架,可用于理解机器学习算法在多大程度上“记住”了它不应该记住的个人信息——从而提供了评估 ML 算法的隐私保证的能力。这是非常宝贵的,因为我们希望模型从数据集学习一般概念(例如,工资高于 X 的人比工资低于 Y 的人购买无人机的可能性高 90%),而不是可以揭示组成数据集的个人的身份或敏感数据的特定属性(例如,约翰的工资是 X)。此外——与“k-匿名”及其同类假设的攻击模型不同——差分隐私不假设攻击者可获得的背景知识的水平或范围。

DP — the adversary cannot tell if the training set contained a specific record
尽管“差异隐私”这个术语已经成为一个时髦的词(特别是在苹果宣布这种方法支持他们在各种 iOS 设备上的隐私保护工作之后),但它是基础性的,因为研究人员正在各个人工智能/人工智能领域投入大量努力,以确保算法和机器学习的构建模块可以变得“差异隐私”。
差分隐私通过在处理期间添加受控量的“噪声”来实现其目标,以便在下游生成足够的模糊性,使得不能基于来自系统的预测做出影响隐私的推断。此外,这样做的同时还能确保预测足够准确,具有实用性。它基于固定“隐私预算”的概念,并为评估各种数据操作的隐私损失提供了一个基础——最终指定如何限制损失,同时实现数据效用损失的可接受折衷。

The mathematical gist of Differential Privacy (Image from this deck.)
在 iOS 用例中(采用差分隐私),苹果使用三种关键机制来保护隐私,同时仍然了解用户在各种环境下的一般行为模式。例如,在寻找“的过程中,哪些表情符号是流行的?’,首先,哈希用于确保他们的后端服务不会获得任何关于用户的直接识别数据。其次,通过仅报告每个用户活动的随机子集来采用子采样(即,不是发送可能感兴趣的每个数据点,而是仅发送子集)。最后,即使对于 T2 发送的数据,噪声也会被注入,因此特定用户的击键模式在后端看到时也只是大致准确。隐私感知后端算法能够在跨设备聚合数据的同时“过滤”噪音,以了解用户行为的一般模式,并在此基础上改善用户体验。因此,例如,如果确定某个特定的表情符号越来越受欢迎,它就会被添加到所有用户都能看到的快速访问表情符号集中。同样,一旦确定特定的“本地”词典单词已经被许多用户添加,它就被添加到所有用户的词典中。

Trending emojis learned with local (client-side) differential privacy on iOS
PATE 框架
差分隐私提供了一种通用技术,可以在 AI/ML 环境中以各种方式应用。教师集合的私有聚集(PATE)框架应用差别隐私来为根据用户数据训练的模型提供整体隐私保证。PATE 框架中的关键直觉是“如果两个基于独立数据训练的模型在某些结果上达成一致,那么向消费者分享该结果就不太可能泄露任何关于特定用户的敏感数据”。
该框架将私有数据划分为子集,并在每个子集上独立训练不同的模型(称为“教师”)。总体预测是通过组合教师模型“整体”的各个预测而生成的。这本身并没有增加任何隐私成分。这是通过两个重要步骤实现的。首先,在组合单个教师的结果时会添加噪声,因此组合的结果是单个教师预测的“有噪声的集合”。第二,来自教师总体的这些有噪声的预测被用作“标记的训练数据”来训练下游的“学生”模型。就是这个学生模型被暴露给终端用户消费。PATE 框架的作者撰写的这篇文章更为详细。

Private Aggregation of Teacher Ensembles (PATE)
联合学习
联合学习采取了一种有些不同的方法来保护众包学习场景中的隐私。关键的想法是,如果我们可以设计出从数据子集(孤岛)中学习的方法,然后有效地汇总我们的学习,为什么还要把所有的数据聚集在一起呢?’。
这使得在几种有趣的情况下学习成为可能。例如,一组医院可能对应用 ML 技术来改善患者的医疗保健感兴趣,但是(a)单个医院可能没有足够的数据来独自完成这项工作,以及(b)他们可能不想冒险将他们的数据用于集中汇总和分析。这是应用联合学习的理想场景。
另一个常见的场景是使用机器学习来改善跨设备平台的用户体验,而无需将用户活动数据从单个设备移动到中央服务(此处描述为)。在后一种情况下,每个设备从中央位置下载一个(定期改进的)模型,并在本地应用 ML 来对要提交回中央服务器的模型进行“微改进”。这种方法越来越受欢迎,还因为每个设备上本地可用的数据越来越丰富(因此本地学习非常有益,隐私约束更少),以及与过去相比更强大的设备端处理器(使得计算密集型 ML 算法可行)。
同态加密
最后,通过利用一种称为同态加密(HE)的加密技术,人们也在努力使用密码术来提供机器学习中的隐私保证。
当使用传统技术对数据进行加密时,就不可能对加密形式的数据进行任何有意义的计算。随着云计算的广泛采用,人们经常会遇到这样的情况:拥有敏感数据的一方想要将对该数据的一些计算外包给它不信任明文数据的第三方。同态加密基本上提供了对加密数据执行各种有意义的操作的能力,而无需直接访问加密密钥或纯文本数据本身。使用同态加密,服务可以对加密数据执行请求的计算,并将(加密的)结果返回给客户端。然后,客户端可以使用加密密钥(从未与服务共享)来解密返回的数据并获得实际结果。
同态加密本身是一个不断发展的领域。性能是一个很大的问题,某些限制——例如只计算多项式函数的限制(ML 中的许多激活函数是非多项式的)和只计算整数模 n 的加法和乘法(大多数学习算法需要浮点计算)——意味着仍然有许多挑战要克服。然而,随着机器学习即服务(MLaaS)的日益流行,人们对改进利用同态加密来执行“加密”机器学习的技术产生了浓厚的兴趣。这两种变体都在探索中——对加密数据执行学习/预测的能力,以及使用加密模型对明文数据进行学习的能力。

Privacy regulations and machine learning
GDPR 和机器学习
《通用数据保护条例》(GDPR)于 2018 年 5 月生效,这是欧盟让全球组织认真对待个人数据的最新尝试。简而言之,GDPR 将任何处理(或外包处理)欧盟公民数据的实体/组织的隐私保护门槛推得更高。在同意处理、数据保护、违规披露和擦除方面有着严格的要求,对故意违规行为会处以重罚。此外,与它的前身数据保护指令(DPD)不同,它是一个“指令”(被成员国用作制定法律的指导方针),GDPR 是一个“法规”(一个法律本身)。

The GDPR went into effect from May 2018
《GDPR》中的一些条款就其对人工智能/洗钱的潜在影响激起了许多讨论和辩论。让我们简单地看看几个突出的例子。
“潜在可识别”数据的解释
在“适用范围”部分,GDPR 声明该法规适用于“所有可能识别数据主体的欧盟公民数据”。这本身就提出了一个有趣的难题。鉴于人工智能/人工智能算法的巨大能力和洞察力,是否有可能将任何处理关于人的数据(以任何形式和出于任何目的)的系统明确排除在 GDPR 的管辖范围之外?你能确定你正在处理的关于人的数据不会以任何方式被用来识别任何对象吗?
此外,探索性数据分析(EDA)是帮助数据科学项目走向创新和有趣见解的最有价值的活动之一。GDPR 规定,未经数据主体的进一步同意,数据处理者不得将数据用于超出原始意图的任何目的。这最多会大大减慢探索的速度。
明确禁止人们服从“自主”决定
GDPR 明确禁止数据主体受制于自主决策的结果。但这就是这么多 AI/ML 主流用例的全部本质,对吧?这一条款是否意味着不能将 ML 应用于欧盟公民的数据?当有人浏览一个网站时显示广告是否构成了自动决策?有许多这样的问题需要解释。当谈到 AI/ML 的使用时,似乎有一个出路,大多数组织可能会依靠它。基本上,如果自主决策是(a)履行合同义务所必需的或出于法律原因所需要的,或(b)当数据主体明确同意时,这一禁令不适用。
解释的权利
这是一个棘手的问题。GDPR 要求应向数据主体提供充分的解释,这些主体可能希望了解为什么基于对其数据的使用做出某个(自动)决定。这样做的目的是提高透明度,并确保这种系统是公正的。
然而,机器学习模型的复杂性以及解释它们如何得出预测或结果的严重困难,使这成为一项艰巨的任务。尚不完全清楚这些解释需要“细化”到何种程度才能被监管机构接受。例如,如果使用深度神经网络(DNN),数据处理器是否需要解释随机梯度下降(SGD)的内部工作原理,显示各层的权重向量,并解释卷积和丢失的逻辑等。大多数深度学习专家说,很多时候,甚至他们也不明白为什么这一切都行得通——但它确实行得通!还有知识产权保护的问题可能会在某个时候出现。
当每个人都在等待“案例法”出现并澄清这方面的确切立场时,让机器学习变得可以解释的工作正在进行中。一个例子是局部可解释模型不可知解释(LIME) 中概述的方法。LIME 基本上将潜在的非常复杂的实际模型视为一个黑盒,并试图纯粹通过研究更复杂的模型提供的输入和做出的决策来重新创建一个更简单(更容易解释)的表示。此外,它试图“局部地”这样做,也就是说,它采用要寻求解释的特定预测,并对输入向量进行扰动,以查看输入的哪些方面在所做的决策中具有显著影响或更大权重。这承认了一个事实——尽管对一个模型的每一个方面进行彻底的解释可能令人望而生畏——我们仍然可以努力理解具体的决策。
被遗忘的权利
根据 GDPR 的说法,数据主体可以要求处理器删除他们可能已经存储的关于该主体的所有数据(相当于撤回过去同意使用个人数据)。这项规定旨在授权数据主体控制各种数据处理者对其数据的长期使用和保留。(它最初是由引入的,因为它认识到保护改过自新的个人不被互联网上关于他们过去罪行的信息永久玷污的基本需要。)
当数据主体的数据用于机器学习时,当他们撤回同意或请求删除数据时,会出现一个有趣的问题。是否应该要求数据处理器在没有特定对象数据的情况下重新训练先前训练过的模型?显然不是!GDPR 明确表示,撤销不影响或不适用于最初同意生效时所做的过去的处理。所以这应该是一种解脱。然而,正如我们在上一节中看到的,模型可能会记住它们不应该记住的东西,因此从训练好的模型开始重新创建潜在的可识别数据是可能的。这意味着,虽然您可能认为您已经删除了数据主体的数据,但它可能仍然是可恢复的!目前,这种风险似乎已经被学术界忽略了。
接下来呢?
前面关于 GDPR 及其许多规定背后的意图的讨论提出了关于人工智能/人工智能的社会含义的有趣问题。算法决策的公平性和偏见、伦理和道德等考虑因素可以在最深层次上激发我们的社会安全感。在下一篇文章中,我们将探索这些领域,并且可能从我们到目前为止所做的最广泛的意义上来看待 AI/ML 环境中的“安全性”。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
透过编号的颜色看世界
香港 2016 年中期人口统计结果互动地图
起初,我只是想得到一些普查结果。这是了解我居住的地方和我周围的人的一个很好的来源。当我在香港政府网站找到 2016 年中期人口统计结果时,首先看到的是一张地图,然后在它的下面,是无数的表格。尽管被这些表淹没了,我仍然有一些控制权。我可以选择一个区域,它会返回给我一些表格。

Table Streak! (source)
我决定制作一些彩色地图来缓解我的眼睛,而不是看那些表格和数字来找出各个地区的人口特征。
中期人口统计数据
中期人口统计的结果包含了很多关于人口统计、教育、经济等方面的有价值的数据。这些数据按区议会、三级规划单位、新市镇和主要屋分组。要了解更全面的情况,区议会的人口特征是一个很好的起点。这些数据可以用 Excel 格式下载。全港共有 18 个区议会,因此,最简单的方法是下载全部 18 个 Excel 档案。每个文件代表一个区,有 11 个电子表格。每个电子表格都包含一个表,例如,电子表格 D4 包含“按种族和性别划分的人口”表。
为了使它更灵活,我创建了一个类“District”来处理数据。当读取 Excel 文件时,将创建一个实例,该实例将解析数据并将其转换为 DataFrame 和 Series。这里有一个例子。

District 类有一个 summary()方法,用来计算一些有用的统计量和比率,保存为熊猫系列。为了数据可视化,所有区议会摘要都保存为 demographic_summary_2016.csv。
地理空间数据
第二部分数据是地区边界的地理空间数据。

就是因为找不到已经可用的 GeoJson 数据,所以在 geojson.io 上划了 18 个区的界限,把它们标绘在地图上。以下是 GeoJson 数据的快照:

The name of the district is stored in the “properties”, and the coordinates are stored in “geometry”.
地图可视化
当数据准备好了,就该绘制等值线图了。这是一个有多个阴影或图案区域的地图,每个区域都根据统计变量按比例测量。可视化一个地理区域中的统计测量是如何变化的是非常有用的。制作 choropleth 地图有不同的方法。Folium 提供了一个有效的选项,让我可以更少地担心美观,而是更多地关注数据部分。

District name and the median age are displayed as tooltip
从上面的 choropleth 图,我们可以很容易地确定哪个地区的平均年龄最高。当光标位于选区边界内时,将显示选区的名称和年龄中位数。图层控件允许我们选择要可视化的数据。然而,当有更多的层时,屏幕可能会很混乱,因为所有的图例将同时显示。
幸运的是,Ipywidgets 提供了有用的小部件。它们是支持为 Jupyter 笔记本构建交互式 GUI 的多事件 python 对象。有各种类型的小部件可以让你的笔记本更加有趣和互动。为了使用 Ipywigets.interact 来显示地图,我们将地图保存为 HTML 文件。
现在,它有一个用于地图选择的下拉菜单。地图中的颜色表示该地区的种族密度百分比。举例来说,湾仔有 180123 人,其中 14706 人是菲律宾人,因此,湾仔约有 8%的人口是菲律宾人。

1 Map + 1 Legend at a time
所有的代码和地图都可以在 GitHub 库中找到。为了避免任何法律问题,Excel 文件不会放在存储库中,但可以从政府网站下载。我用于可视化的摘要 csv 文件可以在存储库数据文件夹中找到。
人口普查数据是一个很好的探索资源。给出正确的演示,所有这些数字都可以成为鼓舞人心的。我在上面制作的地图只是一个简单的例子,展示了如何使用 follow 和 Ipywidgets 将来自表格和数字的人口普查数据转化为丰富多彩的 choropleth 地图。我相信在这些资料中还有许多其他的选择和未被探索的故事。一如既往,我欢迎任何类型的建议,如果你有任何想法,请随时发表评论或通过 Twitter@ HLH _ 丹尼尔联系我。
只见树木不见森林:随机森林导论

随机森林非常整洁。他们利用集成学习来使用通常被认为是弱学习者的东西(决策树来创建一个更强更健壮的建模方法。

随机森林模型由决策树组成,因此在进入森林之前,确保您了解这些树是非常重要的。如果你需要复习决策树,请花点时间查看播种——决策树介绍。
正如你可能知道的,决策树的两个主要限制是,它们容易过度拟合,并且它们往往不健壮,这意味着训练数据的微小变化会导致非常不同的树。随机森林模型通过生成许多决策树,然后将每棵树的预测聚合为单个模型预测,克服了决策树的这两个缺点。
创建然后组合一堆决策树的结果看起来很基本,然而,简单地从完全相同的训练数据中创建多个树不会有成效——它会产生一系列强相关的树。所有这些树都以相同的方式对数据进行排序,因此这种方法与单一决策树相比没有优势。这就是随机森林的奇特之处开始发挥作用。为了去相关组成随机森林的树木,进行了一个被称为引导聚集(也称为装袋)的过程。Bagging 通过用替换对原始训练数据进行采样来从原始数据集生成新的训练数据集(引导)。对于构成随机森林的尽可能多的决策树,重复这一过程。然后,每个单独的自举数据集被用于构建树。这个过程有效地降低了模型的方差(训练数据中随机噪声引入的误差,即过拟合),而不增加偏差(欠拟合)。就其本身而言,将训练数据打包以生成多棵树创建了所谓的打包树模型。
称为随机子空间方法(也称为属性装袋或特征装袋)的类似过程也用于创建随机森林模型。对于每棵树,对可能的预测变量的子集进行采样,从而为每棵树产生一个较小的预测变量集以供选择。这通过防止主要预测变量成为被选择来在每个单独的决策树中创建分裂的第一个或唯一的变量,进一步去相关树。如果不实施随机子空间方法,则存在一个或两个主要预测变量被一致地选为每个决策树的第一分裂变量的风险,并且所得的树将是高度相关的。bagging 和随机子空间方法的结合产生了随机森林模型。

bootstrap 聚合的聚合部分来自于组合这些决策树中每一个的预测,以确定总体模型预测。对于每个单独的记录,整个模型的输出是类的模式(分类)或单独的树的所有预测的平均预测(回归)。

在这种情况下,插入到(简化的)随机森林模型中的记录在大多数树(2/3)中被分类为杂色,因此随机森林会将该记录分类为杂色。

随机森林还有几个重要的组成部分需要强调。
出袋错误
Bagging 有效地导致大约 1/3 的原始训练数据被排除在每个单独的决策树之外。这些被排除的数据被称为袋外(OOB)观察值。这种效应已经被用来创建出袋 (OOB)误差估计,它可以用来代替交叉验证指标。
通过在每个决策树中运行不属于训练数据的记录,然后将这些结果聚合到单个预测中,可以计算出超出范围的误差。可以为所有训练记录确定 OOB 预测,这意味着可以计算总体 OOB MSE,并将其用作模型误差率。
可变重要性
关于随机森林的另一个巧妙之处是,在它们的实现过程中,预测变量重要性是通过利用基尼重要性来计算的,基尼重要性用于确定各个决策树的节点,以生成杂质的平均减少(MDI)。
MDI 是一个变量的节点杂质总减少量的平均值(mean ),通过随机森林中每个单独决策树中到达该节点的样本比例进行加权。用于创建随机森林模型的每个预测变量都有一个结果 MDI 值,该值用于对变量对模型的重要性进行排序。基尼系数的平均降幅越大,表明变量的重要性越高。

随机森林的局限性
随机森林在模型鲁棒性方面比决策树有所提高,但在可解释性和可接近性方面有所损失。在决策树中,您可以看到用于对目标变量进行排序的单个变量分割和阈值。这在随机森林中是不可能的,在随机森林中,数百棵树被聚集在一起以创建一个估计值。因为随机森林模型不太容易接近,也不容易解释,所以它们通常被视为“黑箱”
优势
随机森林与组成它们的决策树有许多相同的优点。它们可以应用于分类或连续目标变量,并且可以处理不平衡数据集、异常值和非线性关系。除了这些优势,随机森林往往比单个决策树有更好的预测能力,并且不容易过度拟合。随机森林模型在估计分类数据时往往表现很好。
总之……
随机森林是一种集成机器学习方法,通过创建多个决策树,然后通过聚合各个树的预测将这些树组合成一个模型,来利用决策树的个体预测能力。随机森林比决策树更健壮,并且往往具有更好的预测能力。然而,它们也更不透明,看起来更令人生畏。希望这篇文章已经让你看到了(决策)树的森林,并向你展示了随机森林是多么整洁。

https://www.youtube.com/watch?v=Hm3JodBR-vs
原文。经允许重新发布。
OCR 中的分割!!
OCR 系统使用的不同分段级别的基本说明。
欢迎来到关于 OCR 系统工作的第三部分。在 上一篇 中,我们已经看到了 OCR 系统中基本且广泛使用的预处理技术。
在这一部分,我们将介绍 OCR 系统的另一个最重要的阶段的技术,。
分割 无非是 将整幅图像分割成子块,以便进一步处理 。
图像的分割按以下顺序进行:
→行级分割
→词级分割
→字符级分割
对于上述所有级别的分割,我们将使用直方图投影技术。
直方图投影法
下面我给大家简单介绍一下直方图投影法。一旦彩色图像被转换成二进制图像,图像中就只存在黑色和白色像素。
在二值图像中,代表有用信息的像素称为,非前景像素的称为 背景像素。 我们在对图像进行二值化时,选择前景像素应该是白色还是黑色。**
水平直方图投影: 在这种方法中,我们沿着图像的行统计前景像素的号,得到的数组的大小等于图像中行的号(图像的高度)。
**# img be binarized image of size height x width and foregound pixel is white i.e pixel value = 255
**horizontal_hist = np.sum(img,axis=1,keepdims=True)/255**
# axis = 1 is used to take sum along the row
# horizontal_hist is an array of size height x 1# If the img has foreground pixel as black i.e pixel value = 0
**horizontal_hist = img.shape[1] - np.sum(img,axis=1,keepdims=True)/255**
# Logic :- No.of columns - No.of white pixels**
将 horizontal_hist 绘制成直方图,如下所示

No.of White pixels (foreground) in each row. Source: researchgate.net
在上图中,
- 较高的峰值意味着相应行中前景像素的数量较高。
- 较低的峰值意味着相应行中个前景像素的数量较低
垂直直方图投影: 该方法中,我们统计前景像素沿图像列的个数。结果数组的大小等于图像中列的号(图像的宽度)。
**# img be binarized image of size height x width and foregound pixel is white i.e pixel value = 255
**vertical_hist = np.sum(img,axis=0,keepdims=True)/255**
# axis = 0is used to take sum along the column
# vertical_hist is an array of size 1 x width# If the img has foreground pixel as black i.e pixel value = 0
**vertical_hist = img.shape[0] - np.sum(img,axis=0,keepdims=True)/255**
# Logic :- No.of rows - No.of white pixels**
将 vertical_hist 绘制成直方图,如下所示

No.of Black pixels (foreground) in each column. Source: researchgate.net
注意:上图中,前景像素为黑色,背景像素为白色。
在上图中,
- 较高的峰值意味着相应列中的前景像素的数量较高。
- 较低的峰值意味着相应列中的个前景像素的数量较低。
既然我们已经理解了水平和垂直直方图投影,我们就准备知道不同层次的 分割 是如何执行的。
- 线级分割: 在这一级分割中,我们被提供一个倾斜校正图像包含以线的形式书写的文本。线级分割的目的是将的图像分割成线条** 。**
写作的一般规则:我们应该在行间留有足够的空间。
这个想法是,如果我们水平投影二进制图像,
- 表示一行中文本的行具有高数量的前景像素 ,其对应于直方图中较高的峰值。
- 表示线间间隙的行具有高数量的背景像素 ,其对应于直方图中的较低的峰值。

Horizontal Projection of image, Counting No.of Foreground pixels in each row. Source: Image by the author.
对应于直方图中较低峰值的行可以被选择作为分割线来分离这些线。

Segmenting the image as lines by selecting the rows which have lower peaks. Source: Image by the author.
2.单词级分割的目的是 将图像分割成单词 。****
写作的一般规则:我们应该在单词之间留有足够的空间。
这个想法与上一步类似,但唯一的变化是,这里我们必须垂直投影图像(沿列求和),因为我们必须垂直分割单词。
如果我们垂直投影二进制图像,
- 表示文本的列具有高数量的前景像素 ,其对应于直方图中较高的峰值。
- 表示单词之间间隙的列具有高背景像素数 ,其对应于直方图中的较低峰值。

Vertical Histogram Projection of image. Source: researchgate.net
注:上图中,前景像素为黑色像素,背景像素为白色。
我想你已经搞清楚上图的分词是怎么做的了。可以选择对应于直方图中较低峰值的列作为分割线来分隔单词。
对于分割单词,应该以这样的方式选择较低的峰值,即它们应该跨越一定的宽度(阈值)。这是因为我们会发现较低的峰值,这些峰值对应于一个单词中不相连的字符之间的间隙,这是我们不感兴趣的。众所周知,单词之间的间隙大于单词内字符之间的间隙,阈值的选择应忽略单词内字符之间的细小间隙。
3. 字符级分割: 在这一级别的分割中,我们得到一个包含一个单词(在前面的步骤中被分割)的图像,该单词由一系列字符组成。字符级分割的目的是 将图像分割成单个字符 。
这一级别的分割是可选的,这取决于使用 OCR 的上下文。
- 如果将 OCR 系统应用于文本,其中一个单词中的 字符是单独的 ,字符级分割是不需要的。由于一个单词中的字符之间保持一致的间隙(即使它很小),我们可以在前面的步骤中分割字符(通过设置非常低的阈值)。
- 如果将 OCR 系统应用于文本,其中一个单词中的 字符被连接 (草书),必须执行字符级分割来分割字符。
通过利用字符之间的小间隙,我们可以使用我们用于单词级分割的相同思想,即通过垂直投影图像,我们可以分割字符。
在字符级切分中,字符的切分并不简单,因为草书中的 连字 的概念。
什么是连字??
连字是连接草书中两个连续字符的纽带。

Source: Image by the author.
现在你可能在想, 这个连写产生了什么问题……..对吗?
在英文剧本中,我们有两种类型的人物**
- 闭合字符: 这些字符有一个循环,垂直投影时,横跨这些字符的所有列至少有 2 个前景像素 。如 a、b、c、d 、
- 开放字符: 这些字符没有循环,垂直投影时,跨越这些字符的所有列中,至少有一列只有 1 个前景像素。如 u,v,w
因此,OCR 系统无法将带有曲线的连字与开放字符区分开,并认为两者都是有效的分割候选。这个问题被称为 过度分割问题 。

Ligature problem for the word “umn” written in Cursive. Source: Image by the author.
注意: 上图中,为了分割,有效候选是连字(u,m & m,n 之间的连接),无效候选是那些,是开放字符 u,m,n 的一部分【我们不能在字符之间分割】
**到目前为止,我们还没有解决这个问题的完美方法,但是这里有一个基本的和广泛使用的方法来克服这个问题。
我们假设 细化 到 1 像素宽。因此,垂直直方图数组中可能的 sum 为
→ sum=0 ,如果列
→ sum=1 ,如果列
→sum>1中存在连字或部分开放字符,如果列中存在部分封闭字符。例如 o,p(在每一列中具有一个以上的前景像素)**

Source: Reference1
在上图中,用红色标记的列要么有垂直直方图 sum=0 要么有 sum=1 。这些列被称为 PSC ( 潜在分割列)。
遵循以下规则选择有效线段(不总是选择有效线段,但大多数时候选择有效线段):-
- 两个连续字符之间的垂直空白,即沿该列的【sum = 0】,** ,表示不存在前景像素。所以我们可以在这些连续的列中选择中间的列。**
- 当有一列 sum=1, 表示存在连字或部分开放字符时,在这种情况下, 过度分割问题 通过取所有那些距离小于特定值(阈值)的 PSC 的平均值并通过将它们合并成单个 SC(分割列)在很大程度上得以消除。阈值是沿着连续 PSC 之间的单词图像宽度的最小距离,并且被选择为使得其值必须小于单词图像中可能的最细字符的宽度(例如,I,l)。现在,所有这些 SC 都通过用大量数据训练的机器学习模型来验证。如果 SC 成为有效分段线的概率很高,则认为它是有效分段线;否则,它将被忽略。
通过遵循上述规则,我们可以在 90%的情况下正确分割字符。

Word Images Showing all types of Segmentation Errors. Source: Reference1
最后的话
在这个由 3 部分组成的系列中,我们对 OCR 系统的工作有了一个较高层次的概述,并涵盖了 OCR 系统的两个最重要的阶段和 分割 。
我希望你能理解并喜欢阅读这篇文章!!!
欢迎任何质疑、建议、指正。
快乐学习……结束😀😀
参考资料:
1 Choudhary,Amit & Rishi,Rahul & Savita,Ahlawat。(2013).一种新的脱机手写草书字符分割方法。计算机科学。17.88–95.10.1016 年 5 月 13 日
2桑切斯、a .和苏亚雷斯、P.D .和梅洛、卡洛斯和奥利维拉、阿德里亚诺和阿尔维斯..(2008).手写历史文献图像中的文本行分割。1–6.10.1109/ipta . 2008 . 436386363637
3库尔尼亚万、法杰里和沙夫里、莫哈末和拉希姆、莫哈末和马图斯、尼和拉赫马迪、阿克毛和穆罕默德、祖尔基弗利。(2011).基于轮廓分析和神经网络验证的草书手写体字符分割。ITB 信息与通信技术杂志。5.10.5614/itbj.ict
图片来源: 谷歌
利用机器学习细分信用卡客户
利用无监督机器学习识别可销售细分市场

Photo by Ryan Born on Unsplash
市场营销中的细分是一种技术,用于根据行为或人口统计等属性将客户或其他实体分成不同的群体。确定可能以类似方式对特定营销技术(如电子邮件主题行或展示广告)做出反应的客户群非常有用。因为它使企业能够定制营销消息和时机,以产生更好的响应率并提供改善的消费者体验。
在接下来的文章中,我将使用一个包含信用卡客户行为属性的数据集。数据集可以从 Kaggle 网站下载。我将使用 scikit-learn python 机器学习库来应用一种称为聚类的无监督机器学习技术,以识别人类认知可能不会立即显现的片段。
该数据集由 18 个信用卡客户行为特征组成。这些变量包括当前卡上的余额、账户上的购物次数、信用额度等。完整的数据字典可在数据下载页面找到。
设置
我在JupyterLab中运行以下代码。我正在使用iPython magic扩展水印来记录我正在运行的工具的版本。如果您在运行代码时遇到任何问题,其输出如下所示。库导入也显示在下面。
%load_ext watermark
%watermark -d -m -v -p numpy,matplotlib,sklearn,seaborn,pandas -g

import pandas as pd
import numpy as npfrom sklearn.cluster import KMeans
from sklearn import preprocessingimport matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
数据清理
首先,我们需要检查数据,找出可能需要的清理和转换。scikit-learn 库要求所有数据都没有空值,并且所有值都必须是数字。
首先,我已经阅读了下载的 csv 文件。
TRAIN_FILE = 'CC GENERAL.csv'
train_data = pd.read_csv(TRAIN_FILE)
首先,我运行下面的代码来检查数据类型,看看是否有需要转换的分类变量。从结果中我们可以看到,除了CUST_ID以外,所有的特征都是数字。但是因为我们不需要这个特性来训练模型,所以我们不需要在这里做任何转换。
print("Data Types:", train_data.dtypes)output:
Data Types: CUST_ID object
BALANCE float64
BALANCE_FREQUENCY float64
PURCHASES float64
ONEOFF_PURCHASES float64
INSTALLMENTS_PURCHASES float64
CASH_ADVANCE float64
PURCHASES_FREQUENCY float64
ONEOFF_PURCHASES_FREQUENCY float64
PURCHASES_INSTALLMENTS_FREQUENCY float64
CASH_ADVANCE_FREQUENCY float64
CASH_ADVANCE_TRX int64
PURCHASES_TRX int64
CREDIT_LIMIT float64
PAYMENTS float64
MINIMUM_PAYMENTS float64
PRC_FULL_PAYMENT float64
TENURE int64
运行下面的代码告诉我,只有两个特性具有空值“CREDIT_LIMIT”和“MINIMUM_PAYMENTS”。此外,每列中只有不到 5%的部分为空。这意味着我们应该可以用合理的替换值来填充它们,并且应该仍然能够使用该特性。
train_data.apply(lambda x: sum(x.isnull()/len(train_data)))Output:
CUST_ID 0.000000
BALANCE 0.000000
BALANCE_FREQUENCY 0.000000
PURCHASES 0.000000
ONEOFF_PURCHASES 0.000000
INSTALLMENTS_PURCHASES 0.000000
CASH_ADVANCE 0.000000
PURCHASES_FREQUENCY 0.000000
ONEOFF_PURCHASES_FREQUENCY 0.000000
PURCHASES_INSTALLMENTS_FREQUENCY 0.000000
CASH_ADVANCE_FREQUENCY 0.000000
CASH_ADVANCE_TRX 0.000000
PURCHASES_TRX 0.000000
CREDIT_LIMIT 0.000112
PAYMENTS 0.000000
MINIMUM_PAYMENTS 0.034972
PRC_FULL_PAYMENT 0.000000
TENURE 0.000000
下面的代码用列中最常出现的值填充缺少的值。我们同样可以使用均值或中值,或者其他方法,但如果需要,我们将从这里开始迭代。
train_clean = train_data.apply(lambda x:x.fillna(x.value_counts().index[0]))
我还将删除CUST_ID列,因为我们在培训中不需要它。
cols_to_drop = 'CUST_ID'
train_clean = train_clean.drop([cols_to_drop], axis=1)
特征缩放
在训练模型之前,我要做的最后一项处理是缩放特征。
我在这篇文章中使用的聚类模型是 K-Means。简单来说,下面是该算法的工作原理:
- 取预定数量的簇。
- 找到每个聚类的质心,实质上就是平均值。
- 根据平方欧几里得距离将每个数据点分配给其最近的聚类。
- 一旦训练了新的看不见的数据点的聚类,就可以基于欧几里德距离来识别。
因为它依赖于这种距离度量特征,所以缩放是一个非常重要的考虑因素。在我使用的数据集的例子中,让我们取两个特征PURCHASES_FREQUENCY和BALANCE。特征PURCHASES_FREQUENCY是一个介于 0 和 1 之间的数字,而BALANCE在这个数据集中是一个介于 0 和 19,043 之间的货币值。这些特征具有非常不同的尺度,这意味着如果我们不对它们进行标准化,使它们处于相同的尺度上。可能存在算法将给予一个变量更多权重的情况。
以下代码缩放数据框中的所有要素。我在第一次迭代中使用了 min_max_scaler。不同的缩放技术可能会产生不同的结果。
x = train_clean.values
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
train_clean = pd.DataFrame(x_scaled,columns=train_clean.columns)
为了说明这一点,这里是缩放前的PURCHASES_FREQUENCY和BALANCE 列。

缩放后。

有多少个集群?
我之前提到过,我们需要告诉 K-Means 算法它应该使用的聚类数。有许多技术可以用来找到最佳数量。对于这个例子,我将使用肘方法,这样命名是因为它产生的图表在形状上类似于肘的曲线。此方法计算聚类 k 的距离平方和。随着使用的聚类越来越多,方差将会减少,直到达到某个点,在该点上增加聚类不再会产生更好的模型。从这篇文章中借用的代码说明了这一点。谢谢托拉孙心怡!
Sum_of_squared_distances = []
K = range(1,15)
for k in K:
km = KMeans(n_clusters=k)
km = km.fit(train_clean)
Sum_of_squared_distances.append(km.inertia_)plt.plot(K, Sum_of_squared_distances, 'bx-')
plt.xlabel('k')
plt.ylabel('Sum_of_squared_distances')
plt.title('Elbow Method For Optimal k')
plt.show()

您可以看到,在 8 个集群之后,添加更多集群对模型的好处微乎其微。因此,我将使用 8 个聚类来训练我的模型。
培养
在训练之前,我将把数据集分为训练集和测试集。下面的代码划分数据,保留 20%用于测试。
np.random.seed(0)
msk = np.random.rand(len(train_clean)) < 0.8
train = train_clean[msk]
test = train_clean[~msk]
然后,我将训练集和测试集都转换成 numpy 数组。
X = np.array(train)
X_test = np.array(test)
接下来,我使用 8 个集群调用 KMeans fit 方法。
kmeans = KMeans(n_clusters=8, random_state=0).fit(X)
使用训练好的模型,我现在将预测测试集上的聚类。
y_k = kmeans.predict(X_test)
现在,我将把预测指定为原始测试数据框上的一个新列,以分析结果。
test['PREDICTED_CLUSTER'] = y_k
分析集群
我将使用 pandas groupby 函数来分析聚类的一些选定特征,以了解模型是否成功识别了独特的片段。
train_summary = test.groupby(by='PREDICTED_CLUSTER').mean()
train_summary = train_summary[['BALANCE', 'PURCHASES',
'PURCHASES_FREQUENCY','CREDIT_LIMIT',
'ONEOFF_PURCHASES_FREQUENCY',
'MINIMUM_PAYMENTS','PRC_FULL_PAYMENT',
'PAYMENTS']]
train_summary
这给出了以下输出。

只需查看“PURCHASES_FREQUENCY ”,我们就可以看到该模型已经识别出一些高频购买细分市场,即集群 2 和集群 3。让我们了解这两个部分之间的差异,以进一步确定它们为什么在不同的群集中。我们可以看到,集群 3 的总购买次数更多,信用额度更高,他们经常进行一次性购买,更有可能全额支付。我们可以得出结论,这些都是高价值的客户,因此几乎可以肯定的是,你如何向这些客户营销会有所不同。
作为模型的第一次迭代,这似乎是识别一些有用的部分。我们可以通过多种方式调整模型,包括替代数据清理方法、特征工程、删除高相关性特征和超参数优化。然而,出于这篇文章的目的,我想给出一个关于如何启动一个执行无监督聚类的机器学习模型的高级端到端视图。
细分网站导航会话
使用主题建模发现网站导航模式

Photo by Rodion Kutsaev on Unsplash
目标和应用
本文将展示一种方法,使用主题建模方法,根据访问的页面对网站导航会话进行分段。
这有一些可能的应用:描述性分析、面向细分市场的营销、定制网站导航模式等等。它还可以让你了解人们如何使用你的网站,什么类型的内容经常一起出现,等等。
你也可以尝试同样的方法来细分用户而不是会话,并在营销活动中以不同的方式针对这些细分市场,或者将这些数据与现有的交易细分市场进行交叉,以了解每个细分市场如何使用你的网站。
使聚集
聚类意味着根据相似性对对象进行分组。有许多方法可以做到这一点,这也是因为什么是集群有许多不同的定义。共同点是集群是一组数据对象。
硬聚类方法将每个对象分类为仅属于一个聚类;而软聚类给予这些对象每个对象属于一个聚类的程度(例如使用可能性)。
主题建模
另一方面,主题建模用于根据经常一起出现的单词从文本中推断主题。一种可用于此的算法是潜在狄利克雷分配(LDA)。在 LDA 中,我们给它一组文档,我们设置我们认为有多少个主题,它返回给我们一个主题列表,每个主题都由一个最能识别它们的单词列表来描述。
用于识别导航模式的 LDA
好的,那么我们如何使用 LDA 来分割网站会话呢?这实际上非常简单:我们将每个会话视为一个文档,其中每个页面都是一个单词(您可以使用 URL 或页面名称,只要有助于您唯一地标识每个页面)。如果有帮助的话,把会话想象成一个用户写的文本,他试图告诉你他想从你的网站得到什么,用页面代替文字。
主题的正确数量并不总是显而易见的,仅仅纯粹的优化并不一定会产生最好的结果。用不同的数字试几次,看看结果,看看有没有道理。
LDA 是一种软聚类算法,这意味着最终它不会告诉您哪个会话属于哪个组。相反,它会给你一个向量,每个会话属于每个组的概率。然后,你可以将其归入概率最高的那一组(如果你想最后有一个硬聚类的方法的话)。
Python 代码教程
我们导入必要的库:
然后,我们从原始数据帧中提取会话,并为其安装计数矢量器。CountVectorizer 将文本转换成密集的向量。
警告:页面必须用空格分隔,并且它们的名称/URL 不应该包含标点符号,如点和逗号。用下划线“_”替换所有这些字符。
在下一步中,我们执行网格搜索:我们遍历 LDA 函数的所有可能的参数组合,以找到哪一个将产生最好的组,然后将该组合应用于我们的数据。警告:此步骤可能需要一段时间…
最后,我们打印所有的主题,连同最能描述它的单词列表和它们的重要性。
对结果满意后,如果需要,最终可以对结果进行硬聚类:
结论
一旦这项工作适应了您现有的数据和基础设施,您就可以以几种不同的方式使用它,或者尝试扩展这项工作。一种可能的方法是使用概率向量来测量会话或用户之间的距离,而不是对聚类进行硬编码。这可能会打开内容推荐的大门(例如,一旦你计算了用户之间的距离,通过计算概率向量之间的距离,你可以根据向量接近他们的其他用户向新用户推荐内容)。这里介绍的方法的另一个可能的扩展是考虑页面被访问的顺序(根据上下文,这可能是非常相关的)。
这种方法显示了有时跳出框框思考的重要性,以及将算法应用于问题的重要性,这些问题不一定是它们的预期应用,但却有一个等价的框架。在这个特定的例子中,它帮助把用户想象成一个作者,用页面名称而不是单词来写他们的想法。
我希望你喜欢这篇文章,并请让我知道你是否应用了它或以某种方式改进了它。
芝加哥的隔离和消费选择
— —利用 K-Means 聚类和多项逻辑回归探索芝加哥公共消费空间的潜在模式
维多利亚·王

77 Chicago communities, clustered by recurrent venue types
种族隔离一直是芝加哥的一个重要问题。虽然这座城市的总人口分布相当均匀——大约 32%是白人,30%是黑人,29%是西班牙裔,但这些人被分成 77 个不同的社区,过着截然不同的生活。
伊利诺伊大学社会学教授 Maria Krysan 在哥伦比亚广播公司的一篇报道中说:“你居住的地方深刻地塑造了你生活的方方面面。”。事实上,不同种族或经济背景的芝加哥市民不仅居住在不同的居住环境中,而且接触到极其不同的公共空间和资源,这反过来又塑造了他们的生活方式。这个项目研究了芝加哥居民生活的一个特定方面——他们在各自生活空间的消费选择。
消费是一种建立和表达社会归属和区别的方式,这些目的地针对特定用户,包括一些人,而排除其他人( Bolzoni 2016 )。有理由假设芝加哥市的种族隔离可以反映在人们的日常消费中——换句话说,他们在食物、零售商品、活动等方面的花钱选择。本项目旨在验证这一假设。 除了居住隔离,不同社会背景的市民在公共消费空间上接触到的选择是否不同?
这可能是进一步研究美国城市地区社会经济隔离的第一步。以往的研究主要集中在城市人口的居住分布,而本项目旨在发现与公共消费空间的使用和可达性相关的空间隔离模式。这项研究的结果可能会引起学者、政策制定者、社会工作者和/或活动家以及直接受到这种隔离影响的人的兴趣。
数据采集和预处理
一个社区对某类场馆的可达性是通过该类场馆的流行程度(或出现频率)来衡量的。如果某种类型的场所通常出现在社区区域中,则可以推断该社区中的居民更容易接触到这些类型的场所。使用 FourSquare API,我搜索了每个社区中心周围 2.5 公里半径内的场地,每个社区的上限是 100 个场地。值得注意的是,2.5km 的搜索半径对于获取小型社区(社区区域半径小于 2.5km)的场地并不完全令人满意,这可能导致错误地包含属于其相邻社区的场地。

Part of data obtained from FourSquare API
单个社区的居民特征由从芝加哥市人口数据的两个来源提取的数据给出,包括芝加哥 2017 年人口普查数据和芝加哥社区快照。这些指标为每个社区的居民的个人发展、经济状况和种族身份提供了足够的信息。

Part of Chicago Communities Demographic Data
K-均值聚类
这个项目的第一步是根据每个地区最常见的 10 种场所类型对 77 个芝加哥社区区域进行分类。从 FourSquare 获得的数据集计算每个社区区域中每个场馆类别的出现频率。为每个社区区域挑选出前 10 个最常出现的场所类型。

Part of Communities’ top-10 most recurrent venues data
为了将具有相似类型场馆的社区归入相同的组,我对场馆数据集应用了 K-Means 聚类方法。
K 均值模型的准确性在很大程度上取决于为该模型选择的聚类数,即 K 值。为了确定该模型的最佳 K 值,我应用了两种方法来交叉评估值为 3 到 10 的 K 值:
- 弯头判据方法。该方法旨在找到 SSE(标准误差之和-样本到其最近聚类质心的距离)急剧接近 0 时的最小 k 值。一个相对最优的 SSE 显示在 k = 5 或 6。
- 轮廓系数的测量。较高的轮廓系数表示较密集的聚类和每个聚类之间更明显的边界。虽然所有的 k 都产生相当低的轮廓系数,但当 k = 3、4 或 5 时,该数值较高。

Two plots for finding the optimal K
给定上述两种方法的结果,如果将芝加哥社区分成 5 个群,则是最佳的。本博客开头的地图显示了用聚类标签着色的 77 个芝加哥社区。直观上,在这张地图上用相同颜色标记的社区应该有相似的场馆出现模式。
探索跨集群的场馆模式
首先,我单独查看聚类数据。我在这五个组中找出了最常出现的前五种场地类型,以检查组内模式和组间差异。下面的气泡图显示了结果。

就餐馆而言,集群 0 和集群 2 中的社区几乎只有快餐店,从常识来看,这些快餐店很不健康,但很饱,更方便,最重要的是更便宜。相比之下,集群 3 中的社区有很多咖啡店、中高端的意大利和日本餐馆。他们也可以选择享受博物馆和酒店。群组 1 和群组 4 中的社区具有更均匀分布的场所,尚未注意到明显的模式。
通过集群探索社区居民属性
然后,将聚类数据与表示每个社区的常驻属性的数据一起进行检查。首先,我研究了社区整体财务状况、教育状况、就业率和年龄构成的指标:

Per-capita income, unemployment, education, age composition by cluster labels
集群 0、2 和 4 中的社区拥有低收入居民。对于集群 1 和集群 3,虽然存在低收入社区,但这两个集群中的社区的平均财务状况较高。集群 0 和集群 4 的失业率明显较高;群组 2 的低教育率特别高。最后,如最后一个方框图所示,虽然前四个图具有相似的年轻人和老年人百分比,但在这一部分中,聚类 4特别高。****
这些结果与上一节的发现一致,这表明第 1 和第 3 集群中的社区拥有相对较高价格的消费空间,而其余集群中的社区拥有相反的。
接下来,我研究了每个集群中社区居民的种族构成。尽管有一些异常值,但这些图表显示了集群之间清晰的种族分割。
如第一个方框图所示,白人居民比例高的社区主要集中在集群 1 和集群 3 ,这里的高端消费空间非常普遍。集群 0 和 4 充斥着黑人社区,其中一些黑人居民比例超过 95%;聚类 2 显示了西班牙裔居民的相同特征。这三个社区群是快餐和折扣店聚集区。
虽然在以亚裔为中心的社区的分布中没有明显的趋势,但第 1 类确实包括两个亚裔居民比例很高的边远社区。正如美国其他城市的情况所表明的那样,亚裔居民的总人口较少,而且倾向于集中居住在一两个小的集中空间。这两个社区大概就是芝加哥的空间。

Race compositions by clusters
简而言之,探索性分析表明这些由场所产生的芝加哥社区集群之间存在一些居民属性的差异。具体来说,对于倾向于拥有更高端和更高价格消费选择的社区,居民一般都是受过高等教育、收入高的成年人,其中大多数也是白人。另一方面,在充斥着快餐店和旧货店的社区里,大量居民——通常是非白人——接受的教育和收入较低。
多项逻辑回归
那么,公共消费空间(即场馆)与居民经济/种族特征之间是否存在真实的关系?基于上述探索性分析得出的结论,我使用了一个多项逻辑回归模型来检验上一节中考察的居民特征是否真的与场馆产生的社区聚类相关。
多项式逻辑回归适用于该数据集有两个原因。首先,它允许因变量类别有两个以上的级别。在这种情况下,聚类标签被视为因变量,因为有五个聚类,所以它有五个级别;常驻特征被视为独立变量。第二,它不假设独立变量的正态性、线性或同方差性。在这种情况下,自变量不易呈正态分布,很难证明具有线性和同方差性。
逻辑回归模型的汇总统计提供了一个有点复杂的信息,但总的来说,结果合理地倾向于自变量和因变量之间存在真实关系的结论。
完整模型的总体总结如下所示。伪 R 平方是基于零模型“M0”和全模型“M1”的最大化对数似然函数的比率来计算的。伪 R 平方值接近 0 意味着模型不会显著提高估计因变量分类的确定性,而接近 1 意味着模型完全符合,对数优势比最大化为 0。在这个模型中,这个值在~0.6,这表明完整的模型比平庸的模型工作得稍好。
LLR 指标评估的是完整模型相对于零模型(零模型中不考虑任何指标)的绩效。特别是,LLR p 值表示观察假设总体系数为零的零假设(H0)的检验统计量的概率。在这个模型中,4.166e^-14 的 p 值非常低,这表明我们可以拒绝零模型比全模型更好的零假设。

Analytic model summary
讨论
探索性分析给人的印象是,芝加哥社区居民的社会、经济和文化属性与他们各自的消费空间类型之间存在着强有力的联系。
另一方面,逻辑回归模型有其缺点。虽然显示消费空间类型确实与所有居民的属性整体相关,但其结果可能会受到多重共线性的破坏,多重共线性是一种统计现象,其中逻辑回归模型中的预测变量高度相关。不可避免的是,社会、种族和经济隔离是深深交织在一起的现象,相互影响。因此,使用这些变量表示这三个方面的分离会使模型面临一定的多重共线性风险,阻止模型观察单个指标和因变量之间的一些显著相关性。
未来的研究可能会采用更严格的方法,例如使用岭回归或主成分分析(CPA)来最小化多重共线性的混杂影响;或者分解完整模型,比较不同局部模型的性能。
结论
日常经验告诉我们,不同的消费空间服务于不同的社会群体,这个项目为这种普遍的看法提供了一个粗略的证明。
该项目对芝加哥社区的公共消费选择和居民的社会、经济和文化分割之间的关系进行了相当全面但初步的分析。尽管下面的逻辑回归分析没有完全证实,但两者之间存在相关性。
分析发现,某些食物和活动消费选择在低收入和少数种族居民社区更为普遍,如快餐店。另一方面,收入较高且大多为白人的社区群体可以选择在高级餐厅和更好的娱乐场所消费,如酒店和博物馆。
未来的研究可能会对不同类型的场馆在不同社区开放的潜在原因进行更严格的调查。研究还可以更深入地考察这种消费选择差异对芝加哥市民生活各个方面的影响,比如他们的身体、精神或社会福祉。
癫痫发作分类 ML 算法
Python 中的二元分类机器学习算法

介绍
癫痫是一种中枢神经系统(CNS)疾病,在美国影响约 1.2%(340 万人),全球超过 6500 万人。此外,大约 1/26 的人会在他们一生中的某个时候患上癫痫。癫痫发作有很多种,每种都有不同的症状,如失去知觉、抽搐或意识模糊。有些癫痫发作很难用肉眼发现;患者通常会出现短时间无反应或发呆等症状。癫痫发作可能会意外发生,并可能导致受伤,如跌倒、咬伤舌头或无法控制大小便。因此,这些就是为什么癫痫发作检测对于在医疗监督下被怀疑有癫痫发作倾向的患者是至关重要的一些原因。这个项目将使用二元分类方法来预测一个人是否有癫痫发作。
该数据集可在 UCI 的机器学习知识库这里获得。该数据集包括每名患者在 23.5 秒内的 4097 次脑电图(EEG)读数,总共有 500 名患者。然后将 4097 个数据点平均分成每个患者 23 个块;每个块被转换成数据集中的一行。每行包含 178 个读数,这些读数被转换成列;换句话说,有 178 列组成了一秒钟的脑电图读数。总之,有 11,500 行和 180 列,第一列是患者 ID,最后一列包含患者的状态,无论患者是否有癫痫发作。
在这个项目中,我将演示用 Python 构建二元分类机器学习算法的步骤。
我的 Github 上有 Jupyter 笔记本。
数据探索
该数据集包含一个散列的患者 ID 列、一秒钟内的 178 个 EEG 读数和一个描述该秒钟患者状态的 Y 输出变量。当患者癫痫发作时,y 表示为 1,而所有其他数字都是我们不感兴趣的其他状态。所以当我们把我们的 Y 变量变成二元变量的时候,这个问题就变成了二元分类问题。

我们还将选择删除第一列,因为患者 id 是散列的,我们无法使用它。我们使用下面的代码来完成所有这些工作。

下一步是计算患病率,它被定义为样本在类中呈阳性的比例;换句话说,在我们的数据集中,这是癫痫发作患者的比例。

我们的患病率是 20%。当涉及到平衡类和使用“提升”度量评估我们的模型时,了解这一点是很有用的。
数据处理和建立训练/验证/测试集
这里不需要做任何特征工程,因为我们所有的特征都是脑电图读数的数值;将我们的数据集转储到我们的机器学习模型中不需要任何处理。
将预测变量和响应变量从数据集中分离出来是一种很好的做法。

cols_input are our predictor variables & OUTPUT_LABEL is our response variable
现在是时候将我们的数据集分成训练集、验证集和测试集了!多刺激啊!通常,验证集和测试集的大小相同,定型集通常占主数据集的 50%到 90%,具体取决于数据集拥有的样本数。数据集拥有的样本越多,我们就有越多的样本可以转储到我们的训练集中。
第一步是打乱我们的数据集,以确保我们的样本没有某种顺序。

然后,选择的分割是 70/15/15,所以让我们这样分割数据集。我们将首先选择将我们的验证和测试集与我们的训练集分开,这是因为我们希望我们的验证和测试集具有相似的分布。

然后我们可以检查每组的患病率,以确保它们大致相同,也就是 20%左右。

接下来,我们希望平衡我们的数据集,以避免创建一个错误地将样本分类为属于多数类的模型;在我们的案例中,是病人没有癫痫发作。这被称为准确性悖论,例如,当我们的模型的准确性告诉我们有 80%的准确性时,如果类别不平衡,它将只反映底层的类别分布。因为我们的模型看到我们的大多数样本没有癫痫发作,所以获得高准确度分数的最好方法是将样本分类为没有癫痫发作,而不管我们要求它预测什么。有两种简单易用的方法可以帮助我们解决这个问题。欠采样和过采样。我们可以通过减少属于较主导类的样本数量来对较主导类进行子采样,或者我们可以通过多次粘贴少数类的相同样本来进行过采样,直到两个类的数量相等。我们将选择在这个项目中使用二次抽样。

然后,我们将train_all、train、valid和test集合保存为。csv 文件。在开始导入sklearn并构建我们的第一个模型之前,我们需要调整我们的变量以使我们的一些模型能够工作。由于我们将构建九个不同的分类模型,我们应该用StandardScaler来调整我们的变量。

We dump our scaler as a .csv file for quick access if we want to use it in other python notebooks
分类模型
让我们设置一下,这样我们就可以用一个函数print_report打印所有的模型指标。

由于我们已经平衡了数据,我们将阈值设为 0.5。阈值用于确定样本被分类为阳性还是阴性。这是因为我们的模型返回样本属于正类的百分比机会,所以在不设置阈值的情况下,它不会是二进制分类。如果样本返回的百分比高于我们的阈值,那么它将被归类为阳性样本,等等。
分类模型
我们将介绍以下型号:
- k 个最近邻居
- 逻辑回归
- 随机梯度下降
- 朴素贝叶斯
- 决策树
- 随机森林
- 极端随机森林
- 梯度推进
- 极端梯度增强(XGBoost)
我们将对所有模型使用基线默认参数,然后选择具有最高验证分数的模型来执行超参数调整。
k 最近邻(KNN)
当谈到分类模型时,KNN 是人们最先学习的模型之一。该模型根据与其最接近的 k 个样本对样本进行分类。例如,如果 k = 3,并且所有三个最接近的样本都是正类,那么该样本将被分类为类 1。如果三个最接近的样本中有两个是阳性类别,那么该样本将有 66%的概率被分类为阳性。

我们得到了一个非常高的曲线下训练面积(AUC)、受试者操作曲线(ROC ),以及一个很高的验证 AUC。此指标用于衡量分类模型的性能。AUC 告诉我们模型能够在多大程度上区分类别,AUC 越高,模型在区分类别方面就越好。如果 AUC 是 0.5,那你还不如猜样本。
逻辑回归
逻辑回归是一种广义线性模型,它是常规线性模型的概念和能力的概括。
在逻辑回归中,模型预测某事是真还是假,而不是预测连续的事情。该模型适合两个类别的线性决策边界,然后通过 sigmoid 函数从几率对数转换为样本属于阳性类别的概率。因为该模型试图找到正类和负类之间的最佳分离,所以当数据分离明显时,该模型表现良好。这是一个要求缩放所有要素的模型,并且因变量是二分的。

随机梯度下降
梯度下降是一种算法,可以最小化许多不同模型中的许多损失函数,如线性回归、逻辑回归和聚类模型。它类似于逻辑回归,其中梯度下降用于优化线性函数。不同之处在于,随机梯度下降允许小批量学习,其中模型使用多个样本来采取单个步骤,而不是整个数据集。这在数据中存在冗余的情况下尤其有用,这通常是通过聚类发现的。因此,SGD 比逻辑回归快得多。

朴素贝叶斯
朴素贝叶斯分类器使用贝叶斯定理来执行分类。它假设如果所有的特征彼此不相关,那么一起看到这些特征的概率只是每个特征发生的概率的乘积。给定所有不同的特征组合,它找出样本被分类为阳性的概率。该模型通常是有缺陷的,因为模型的“幼稚”部分假设所有的特性都是独立的,而大多数时候情况并非如此。

决策树
决策树是一种模型,其中它运行多个“问题”的样本来确定其类别。分类算法通过重复地将数据分成相同类别的子区域来工作,并且当算法已经将所有样本分成纯的类别时,或者通过满足分类器属性的一些标准,树结束。
决策树是弱学习者,我的意思是它们不是特别准确,它们通常只比随机猜测好一点点。他们也几乎总是过度拟合训练数据。

随机森林
由于决策树可能会过度适应,随机森林就是为了减少这种情况而创建的。许多决策树组成了一个随机森林模型。随机森林包括引导数据集,并使用每个决策树的随机特征子集来降低每个树的相关性,从而降低过度拟合的可能性。我们可以通过使用没有用于任何树来测试模型的“袋外”数据来衡量随机森林有多好。随机森林也几乎总是优于决策树,因为该模型具有较低的方差;因此,该模型可以更好地推广。

极度随机化的树
树外分类器类似于随机森林,除了:
- 当在拆分时选择变量时,样本是从整个训练集中抽取的,而不是引导样本
- 节点拆分是随机选择的,而不是像在随机森林中那样被指定
这使得树外分类器不容易过度拟合,并且它通常可以产生比随机森林更一般化的模型。

梯度推进
梯度推进是另一种对抗决策树过度拟合的模型。然而,GB 和 RF 之间存在一些差异。梯度推进一次建立一棵更短的树,每棵新树都减少了前一棵树的错误。这个误差叫做伪残差。梯度推进比随机森林更快,在许多现实应用中很有用。然而,当数据集包含噪声数据时,梯度增强效果不佳。

极端梯度推进
XGBoost 类似于梯度增强,除了
- 树有不同数量的终端节点
- 用较少证据计算的树的叶子重量收缩得更厉害
- 牛顿推进提供了比梯度下降更直接的到达最小值的路线
- 额外的随机化参数用于减少树之间的相关性
- 由于标准 GBM 没有正则化,因此使用更正则化的模型来控制过拟合,这使其性能优于 GBM。
- XGB 实现并行处理,比 GBM 快很多。

模型选择和验证
下一步是在一个图表中可视化我们所有模型的性能;这使得我们更容易选择要调哪个。我选择了 AUC 曲线来评估我的模型。您可以选择任何想要优化的指标,如精度或提升,但是,AUC 不受您选择的阈值的影响,因此它是大多数人用来评估其模型的指标。

九个模型中的七个具有非常高的性能,这很可能是由于癫痫发作和非癫痫发作患者之间 EEG 读数的极端差异。决策树看起来像预期的那样过度拟合,请注意训练 AUC 和验证 AUC 之间的差距。
我将选择 XGBoost 和 ExtraTrees 分类器作为要调优的两个模型。
学习曲线
学习曲线是我们在模型中可视化偏差-方差权衡的一种方式。我们利用了scikit-learn中的学习曲线代码,但绘制了 AUC,因为这是我们选择用来评估模型的指标。

训练和 CV 曲线都很高,因此这表明我们的树外分类器中的低方差和低偏差。
然而,如果你看到两条曲线的分数都很低,而且很相似,那就是高偏差的信号。如果你的曲线有一个很大的差距,这是一个高方差的迹象。
以下是在这两种情况下如何做的一些提示:
高偏差:
-增加模型复杂性
-减少正则化
-改变模型架构
-增加新特性
高方差:
-添加更多样本
-减少特征数量
-添加/增加正则化
-降低模型复杂度
-组合特征
-改变模型架构
特征重要性
就像在回归模型中,你可以从特征系数中分辨出影响的大小;你可以在分类模型中做同样的事情。

根据您的偏差-方差诊断,您可以选择删除一些特征,或者通过组合一些新的变量,如下图所示。然而,对于我的模型,没有必要这样做。从技术上来说,脑电图读数是我唯一的特征,读数越多,分类模型就越好。
超参数调谐
下一步应该执行的是调整我们模型中的旋钮,也称为超参数调整。有几种方法可以做到这一点。
网格搜索
这是一种传统的超参数调整技术,这意味着它是第一个在手动调整每个超参数之外开发的技术。它需要相关超参数的所有输入(例如,您想要测试的所有学习率),并通过遍历超参数值的所有可能组合,使用交叉验证来测量模型的性能。这种方法的缺点是,当我们有很多想要优化的超参数时,要花很长时间进行评估。
随机搜索
随机搜索使用超参数的随机组合来寻找性能最佳的模型。您仍然需要输入想要调整的超参数的所有值,但是该算法在网格中随机搜索,而不是搜索超参数的所有值的所有组合。根据本文所述,由于其随机性,这通常在时间上胜过网格搜索,因为模型可以比网格搜索更快地达到其优化值。
遗传表演程序
遗传编程或遗传算法(GA)是基于查尔斯·达尔文的适者生存理论。GA 对当前超参数应用小的、缓慢的和随机的改变。它的工作原理是给一个解决方案分配一个适应值,适应值越高,解决方案的质量越高。然后,它会选择具有最高适应值的个体,并将它们放入“交配池”中,其中两个个体将产生两个后代(对后代进行一些更改),预计后代的质量将高于其父母。这种情况一次又一次地发生,直到我们达到期望的最佳值。
TPOT 是一个正在积极开发中的开源库,最初由宾夕法尼亚大学的研究人员开发。它获取整个训练数据集的多个副本,并执行自己的一键编码变体(如果需要),然后使用遗传算法优化超参数。

我们将在 tpot 的 automl 中使用dask来执行此操作。我们将xgboost和extratrees分类器传递到tpot配置中,告诉它我们只希望算法在这两个分类模型中执行搜索。我们还告诉tpot把生产的每一款车型都出口到一个目的地,以防我们想早点停下来。
模型评估
AUC 为 0.997 的最佳性能模型是优化的 extratrees 分类器。下面是它在所有三个数据集上的性能。

我们还创建了 ROC 曲线图来显示上述 AUC 曲线。

结论
现在,向副总裁或首席执行官传达项目的要点通常是工作中最困难的部分,所以下面是我想对高层利益相关者简明扼要地说的话。
在这个项目中,我们创建了一个分类机器学习模型,可以通过脑电图读数预测患者是否癫痫发作。表现最好的模型的提升度量为 4.3,这意味着它比随机猜测要好 4.3 倍。它在预测测试集中的阳性类别方面也有 97.4%的正确率。如果将该模型投入生产以预测患者是否有癫痫发作,那么您可以预期该模型在正确预测癫痫发作患者方面的性能。
感谢您的阅读!
这是东北大学 Andrew Long 教授的硕士课程中的一个顶点项目。
从 sql 中选择答案
一些带有直观答案的常见 SQL 面试问题的回顾

Modded from photo by Ashim D’Silva on Unsplash
对于任何对数据分析或数据科学感兴趣的人来说,重要的一点是:不要低估 SQL 的效用!使用 Python 和 pandas、numpy 之类的包很容易上手,但有许多业务是用 SQL 完成的,许多报告和分析工作可以用它快速高效地完成。如果您对大数据感兴趣,并且使用 PySpark 之类的包与 Apache Spark 进行交互,那么编写 SQL 查询可能是过滤和分析数据最清晰、最快捷的方式。
为了帮助巩固这些概念,下面是一些关于 SQL 的常见面试问题的分类。我从我最近查阅的其他人的列表中提取了这些信息(更多信息请点击底部的链接),我只是针对我个人在最近的采访中遇到的一些问题给出了解释:
SQL、MySQL 和 SQL Server 之间的区别
非常基础的,SQL 代表结构化查询语言。它是用于设计、管理和查询结构化关系数据库的语言本身。mySQL 是一个开源的关系数据库管理系统。SQL Server(也称为 Microsoft SQL Server)是由 Microsoft 为其服务器平台创建的关系数据库管理系统。这两个平台都使用一种通用语言(SQL ),但也有各自的细微差别。还有一些你可能听说过的,比如 Oracle,但是要注意的是 SQL 是语言,而其他的是数据库平台。
哪里与拥有
如果你需要一个一句话的答案: HAVING 专门用于使用集合函数对表进行过滤,而 WHERE 不是。对于更长的上下文: WHERE 子句根据满足特定条件的行进行过滤。它在行中寻找特定数据的匹配。 HAVING 子句用于对整个表中的数据条件进行过滤。下面是这种情况的快速分析。让我们假设我们有一张桌子,看起来像这样一个随机分类的《权力的游戏》角色:
╔═══════════╦════════════════════╦════════╗
║ name ║ house ║ age ║
╠═══════════╬════════════════════╬════════╣
║ Eddard ║ Stark ║ 40 ║
║ Catelyn ║ Stark ║ 35 ║
║ Rob ║ Stark ║ 17 ║
║ Sansa ║ Stark ║ 13 ║
║ Cersei ║ Lannister ║ 35 ║
║ Jaime ║ Lannister ║ 35 ║
║ Tyrion ║ Lannister ║ 30 ║
║ Daenerys ║ Targaryen ║ 15 ║
║ Theon ║ Greyjoy ║ 19 ║
╚═══════════╩════════════════════╩════════╝
如果您想要查找大于或等于 30 的字符,我们可以编写如下查询:
SELECT name, age
FROM got_table
WHERE age >= 30
此函数查看表,根据列出的年龄大于或等于 30 的行进行筛选。它查看表中的可用数据,并从中进行过滤。但是假设你想使用集合函数。让我们从基于 house 聚合这个表开始,只是为了计算每个表中列出了多少人:
SELECT house, COUNT(*)
FROM got_table
GROUP BY house
我们做到了!但是,如果我们只想查看在这个聚合表中创建的具有多个成员的行,我们需要使用具有的而不是 WHERE :
SELECT house, COUNT(*)
FROM got_table
GROUP BY house
HAVING COUNT(*) < 2
简而言之,如果你在寻找行在哪里或者组在哪里。
主键与外键
一个主键 键是数据库表中一条记录的唯一标识符。外键是一个表中的一个字段,它是另一个表中的主键。主键在每个表中只能出现一次,而外键可以出现多次。在这里,我将制作几个表格来说明(为了好玩,请容忍我的假数据和混合位置):
╔════════╦═══════════╦═════════╗ ╔════════╦═══════════╦════════╗
║group_id║ name ║army_size║ ║planetid║ name ║group_id║
╠════════╬═══════════╬═════════╣ ╠════════╬═══════════╬════════╣
║ 0001 ║Cpt. Planet║ 1 ║ ║ 7001 ║ Earth ║ 0001 ║
║ 0002 ║First Order║ 800,000 ║ ║ 7020 ║ Cybertron ║ 0001 ║
║ 0003 ║ Autobots ║ 1,000 ║ ║ 7044 ║ Tatooine ║ 0003 ║
║ 0004 ║Silverhawks║ 10 ║ ║ 5084 ║ Alderan ║ 0004 ║
║ 0005 ║ C.H.U.D.s ║ 35,000 ║ ║ 2001 ║ Mars ║ 0002 ║
╚════════╩═══════════╩═════════╝ ╚════════╩═══════════╩════════╝
TABLE 1 TABLE 2
因此,假设我们有一些派系(主要取自大脑的后部)在为几个不同的星球而争斗。我们将它们放在单独的表中,以存储每一个的单独特征。这些表格是基于哪个群体控制哪个星球而联系在一起的。在表 1 中,主键是 group_id。它是用来标识每条记录的唯一 id。在表 2 中,主键是 planetid,而外键是 group_id。你可以看到我们如何证明行星船长已经接管了地球和赛博顿,这是一个相当有力的举动!表 2 中使用的 group_id 显示了两个表之间的关系,但是拥有一个外键允许我们为每个集合拥有唯一的表。在较大的数据库中,您的系统会有几个以这种方式连接的表。
连接和联合
基础如下,假设我们有两个表,我们并排连接数据,它们有一些共同的键或值来匹配:

- 内部连接:只记录在两个表中有匹配的值(B)
- 左连接:最左侧表中的所有记录和右侧匹配的记录(A & B)
- 右连接:最右边的表中的所有记录和最左边的记录相匹配(B & C)
- 完全外部连接:来自两者的所有记录(A & B & C)
还不错,只是需要时间记住布局。这是很好的思考通过加入他们并排的性质。有了工会,我们只需要改变我们看待表格的角度:

- 联合:两个表的组合,一个堆叠在另一个的上面,但是第二个没有重复(A & B)
- 联合所有:两张桌子整体叠放在一起的组合(A & B & C)
删除、截断和丢弃
快速回答: DELETE 可以用来从表中删除一些记录, TRUNCATE 删除整个表的行, DROP 从数据库中删除对象。当使用 DELETE 时,您将指定一个 WHERE 子句来选择记录:
DELETE FROM got_table WHERE house = "Stark"
TRUNCATE 清除表格中的所有行,没有修饰符:
TRUNCATE TABLE got_table
DROP 实际上是从数据库中删除表对象和行:
DROP TABLE got_table
每一个都有用途,但是根据你的情况,明智地选择你需要的。
操纵字符串
有很多函数可以帮助进行字符串操作,但是一个重要的事情是索引从 1 开始(尽管在其他编程语言中通常从 0 开始)。下面是一些可能会出现的快速重要功能:
- SUBSTR()text,position,length ) 将获取文本并抓取任意部分
- LEFT( text,length)&RIGHT(text,length ): 两者都从最右边或最左边的固定位置开始并从那里修剪。
- REPLACE( text,string_to_find,string _ to _ REPLACE _ with):相当直接的文本替换。
- CONCAT()T26【text _ 1】、text_2 等 。 ): 简单组合的文字
以下是对每一种可能出现的情况的简要介绍:
╔═══════════╦══════════╦══════════════════════════╗
║ first ║ last ║ line ║
╠═══════════╬══════════╬══════════════════════════╣
║ Inigo ║ Montoya ║ "Prepare to battle!" ║
╚═══════════╩══════════╩══════════════════════════╝**SELECT** LEFT(first, 1), last **FROM** pb_table
╔═════╦══════════╗
║ I ║ Montoya ║
╚═════╩══════════╝
**SELECT** CONCAT(last, "," , first) **FROM** pb_table
╔════════════════╗
║ Montoya, Inigo ║
╚════════════════╝
**SELECT** last, REPLACE(line, "battle", "die") **FROM** pb_table
╔══════════╦════════════════════╗
║ Montoya ║ "Prepare to die!" ║
╚══════════╩════════════════════╝
我发现一些面试问题来源很有帮助:
2019 年需准备的 65 大 SQL 面试问题(Edureka)
我喜欢的一些 SQL 学习资源:
模式分析(免费,可以用自己的平台做一些互动练习)
代码教程(喜欢他们的互动平台和详尽的讲解)
W3Schools (也是一些示例交互的非常好的书面参考)
谢谢!
为组学集成选择特征
生命科学的数理统计和机器学习
单变量与多变量特征选择

Idea of Integrative OMICs from Yugi et al., Trends Biotechnol. 2016 Apr;34(4):276–290
这是 生命科学的数理统计和机器学习 专栏的第六篇文章,我试图在这里解释一些在生物医学、生物信息学、细胞生物学、遗传学、进化生物学等领域常见的神秘分析技术。接下来的几篇文章将致力于综合组学分析,这是对计算生物学的现代挑战。这里我讨论了如何使用深度学习进行数据整合。现在,我将后退一步,解释在将各种类型的生物信息合并在一起之前,将对数据执行的基本预处理步骤。
什么是整合组学?
下一代测序(NGS) 技术催生了多种生物和生物医学大数据,如基因组学、蛋白质组学、表型组学、转录组学、代谢组学、表观组学、宏基因组学、脂质组学等。,由于它们共同的后缀,常被称为。快速增长的数据量和多样性提供了新的独特的机会,也带来了大量的分析挑战。一个挑战是,我们假设组学数据应该具有协同效应,这允许更准确地模拟生物细胞的行为。以这种方式,组学整合可以识别新的生物学途径,这些途径在单个组学层中不一定是可区分的。然而,尽管开发了暗黑混合组学等有前途的工作流程,目前仍缺乏用于执行组学整合的数学方法学。

DIABLO Integrative OMICs pipeline from mixOmics R package, image source
为什么要选择信息丰富的特征?
另一个挑战是组合不同类型的生物信息增加了分析特征 的数量,同时保持统计观察(样本)的数量不变。考虑到即使是单个组学也可能是非常高维的,如果没有严格的降维或正则化,它们的集成是困难的,这归结为对最有信息的特征的选择 ,同时丢弃有噪声的特征。
假设我们对解释我们感兴趣的表型 Y 的变异感兴趣,例如疾病状态,我们有一个解释变量(基因)的矩阵 X,我们假设这些变量对 Y 的变异负责。问题是:X 中的所有解释变量对 Y 的变异都有同等贡献吗?由于生物数据中存在大量噪声,有理由假设一些基因是信息性的,而一些基因是有噪声的。由于我们通常只有有限数量的统计观测值,我们不能包含噪声基因,而必须专注于信息基因,即在继续建模之前选择特征 。

Feature selection is an important step in biological analysis workflow, image source
为了进行选择,我们必须针对表型 y 测试 X 中的基因。然而,我们应该如何做呢:一起测试X 中的所有基因(多变量特征选择)还是逐个测试(单变量特征选择)?这里我们要比较两种方式。
单变量特征选择
为了演示单变量与多变量特征选择,我将使用来自人类骨骼肌的 RNAseq 基因表达数据,来自 GTEx 人类组织基因表达 联合体 V7 。数据集包括 n=157 个样本,为了简单和快速起见,我随机抽取了 p=1000 个基因。

The Genotype-Tissue Expression (GTEx) project. Nature Genetics. 29 May 2013. 45(6):580–5.
在这里,我们加载基因表达矩阵 X,并删除低表达基因。为简单起见,感兴趣的表现型将是性别。换句话说,在我们的案例中,我们将发现人类骨骼肌中哪些基因的表达显示了 99 名男性和 58 名女性之间的表型差异。让我们通过显示 PCA 图 来可视化 157 个男女样本。

PCA 图显示了 PC1 和 PC2 中的样本之间的大量差异,但是基于它们的骨骼肌基因表达数据,没有明确的雄性和雌性分离。了解样本之间差异背后的基因的一种方法是测试每个个体基因与性别的相关性,在我们的情况下,这相当于差异基因表达(DGE)的分析。这里,我们将使用简单的非参数 Spearman 相关性 来推断 X 和 Y 之间的关系,我们将对照 Y 逐一测试 X 中的所有基因,使用错误发现率调整多重测试相关性的 p 值,并通过 FDR 对基因进行排序。

我们根据基因与性别的个体关联对基因进行排序,并可以应用传统的截止值 FDR=0.05 来选择**信息性//显著性**基因。接下来,我们可以将这些选择的基因组合成一个预测得分,这似乎是一个有吸引力的想法。然而,在实践中,这种基于单变量特征选择的预测效果很差,因为它有两个问题:****
上述缺点可以用稀疏线性模型来解决,即具有正则化惩罚的模型,如 【套索/脊/弹性网】 或 偏最小二乘(PLS) 回归或判别分析,多变量特征选择的基本技术。
多元特征选择
同时考虑 X 矩阵中所有解释变量的最简单方法是将它们一起放入多重或多元线性模型,并执行 普通最小二乘(OLS) 最小化:

这里为了简单起见,我们只使用了两个预测值 X1 和 X2,但是可以有成千上万个。这意味着,为了最小化 OLS 成本函数,我们必须在高维空间中工作,由于维数灾难,这本来就很困难。这导致多元线性回归的解非常不稳定。为了克服这个障碍,我们可以在上述 OLS 成本函数中增加一个惩罚项:

在这里, λ 被称为拉格朗日乘数,它是我们想要在我们的线性模型上放置多少惩罚的度量,它的最优值是通过交叉验证找到的。参数 α 通常是固定的,但原则上也可以通过交叉验证找到,正则化的类型称为: 1) LASSO if α =1,2) Ridge if α =0,3)Elastic Net ifα= 0.5。这些惩罚方法有一些不同之处,当您选择分析方法时,请记住这些不同之处。LASSO 是最严格的惩罚,在有大量噪音的数据上表现最好。LASSO 的问题在于它不能完全处理预测因子之间的多重共线性。如果两个变量强相关,LASSO 将只选择其中一个(偶然),并将另一个变量前面的系数设置为零。有时,如果被忽略/省略的特征比 LASSO 选择的特征有更多的物理/生物意义,这种类型的特征选择可能会有问题。这个问题可以通过脊罚函数来避免,此外,脊对于数值最小化更加稳定,因为它在高维空间中提供了完全凸流形。然而,在超高维空间中,Ridge 可能过于宽松,会选择许多噪声特征,这可能是不可取的。弹性净惩罚在套索和脊之间提供了一种折衷,通常是机器学习从业者的首选和推荐。让我们使用 LASSO,进行交叉验证,检查选择了哪些基因:
****
正如我们所见,LASSO 选择了大约 30 个信息丰富的特征,并根据其内部得分对它们进行了排名。与单变量特征选择相比,排序看起来非常不同,即使基因 MAP7D2 出现在两种特征选择方法的顶部。
另一种优雅的多元特征选择技术是偏最小二乘法(PLS)** 回归和判别分析,其也被(其作者)称为潜在结构投影(PLS)。PLS 背后的思想是,它通过最大化 X 和 Y 之间的协方差来执行特征选择:**

让我们使用性别 Y 对基因表达矩阵 X 进行 PLS 判别分析(PLS-DA)用于监控。它可以被认为是基因的多元选择,提供了雄性和雌性之间最大的分离。

在这里,我们可以清楚地看到男性和女性之间的分离,将该图与上面的 PCA 图进行比较,我们没有看到任何分离。为了观察哪些基因提供了性别分离,我们显示了 PLS 负荷:
****
我们再次得出结论,通过 PLS 的多变量特征选择提供了一组看起来与单价特征选择非常不同的基因。此外,我们将使用以多元方式选择的基因组来整合不同的组学层。
摘要
在本文中,我们了解到组学集成为生物过程的精确建模提供了一个有希望的下一步。然而,为了克服维数灾难,通常必须在集成之前进行特征预选。单变量特征选择很简单,但是它的泛化能力很差,并且没有考虑多重共线性。多元特征选择LASSO、Ridge、Elastic Net 和 PLS 等方法更适合处理高维生物数据。
在下面的评论中让我知道生命科学中的哪些分析对你来说似乎特别神秘,我会在这个专栏中尝试回答它们。在我的 github 上查看完整的笔记本。在 Medium 关注我,在 Twitter @NikolayOskolkov 关注我,在 Linkedin 关注我。下次我们将讨论监督组学整合方法,敬请关注。
为 XGBoost 模型训练选择最佳参数
所描述的方法有助于找到用 XGBoost 为机器学习模型训练选择参数的方法

XGBoost training results
在为机器学习模型训练选择参数时,总会涉及一点运气。最近,我在研究渐变增强树,特别是 XGBoost。我们在企业中使用 XGBoost 来自动化重复性的人工任务。在用 XGBoost 训练 ML 模型时,我创建了一个选择参数的模式,这有助于我更快地构建新模型。我会在这个帖子里分享它,希望你也会觉得有用。
我使用皮马印第安人糖尿病数据库进行训练,CSV 数据可以从这里下载。
这是运行 XGBoost 训练步骤并构建模型的 Python 代码。通过传递成对的训练/测试数据来执行训练,这有助于在模型构建期间特别评估训练质量:
XGBoost 中的关键参数(将极大影响模型质量的参数),假设您已经选择了 max_depth(更复杂的分类任务,树更深)、子样本(等于评估数据百分比)、目标(分类算法):
- n _ estimators—XGBoost 将尝试学习的运行次数
- 学习速率 —学习速度
- early _ stop _ rounds—防止过拟合,如果学习没有改善,则提前停止
当在 verbose=True 的情况下执行 model.fit 时,您将看到每个训练运行评估质量被打印出来。在日志的末尾,您应该看到哪个迭代被选为最佳迭代。可能训练轮数不足以检测最佳迭代,那么 XGBoost 将选择最后一次迭代来构建模型。
使用 matpotlib 库,我们可以绘制每次运行的训练结果(来自 XGBoost 输出)。这有助于理解被选择来构建模型的迭代是否是最好的。这里我们使用 sklearn 库来评估模型精度,然后用 matpotlib 绘制训练结果:
让我们描述一下我为 XGBoost 训练选择参数的方法( n_estimators , learning_rate , early_stopping_rounds )。
第一步。根据你的经验,从你认为最有效的或者有意义的事情开始
- n _ 估计量 = 300
- 学习率 = 0.01
- 提前 _ 停止 _ 回合 = 10
结果:
- 停止迭代= 237
- 准确率= 78.35%
结果图:

通过第一次尝试,我们已经在 Pima Indians 糖尿病数据集上获得了良好的结果。训练在迭代 237 时停止。分类误差图显示了在迭代 237 附近较低的误差率。这意味着学习率 0.01 适用于该数据集,并且提前停止 10 次迭代(如果结果在接下来的 10 次迭代中没有改善)是可行的。
第二步。尝试学习率,尝试设置一个较小的学习率参数,并增加学习迭代次数
- n _ 估算者 = 500
- 学习率 = 0.001
- 提前 _ 停止 _ 回合 = 10
结果:
- 停止迭代=没有停止,花费了所有 500 次迭代
- 准确率= 77.56%
结果图:

较小的学习率对这个数据集不起作用。即使迭代 500 次,分类误差几乎不变,XGBoost 对数损失也不稳定。
第三步。尽量提高学习率。
- n _ estimates= 300
- 学习率 = 0.1
- 提前 _ 停止 _ 回合 = 10
结果:
- 停止迭代= 27
- 准确率= 76.77%
结果图:

随着学习速率的增加,算法学习得更快,它已经在迭代 Nr 处停止。27.XGBoost log loss 误差趋于稳定,但总体分类精度并不理想。
第四步。从第一步开始选择最优学习率,增加提前停止(给算法更多机会找到更好的结果)。
- n _ 估算者 = 300
- 学习率 = 0.01
- 提前 _ 停止 _ 回合 = 15
结果:
- 停止迭代= 265
- 准确率= 78.74%
结果图:

稍微好一点的结果是 78.74%的准确度,这在分类误差图中是可见的。
资源:
博文— Jupyter 笔记本—忘记 CSV,用 Python 从 DB 获取数据
博客文章— 通过在 Python 中使用 XGBoost 来避免过度拟合
选择正确的预测建模技术
使用统计、概率和数据挖掘来预测未来的结果。
什么是预测建模?
预测建模是获取已知结果并开发一个可以预测新事件值的模型的过程。它使用历史数据来预测未来事件。有许多不同类型的预测建模技术,包括方差分析、线性回归(普通最小二乘法)、逻辑回归、岭回归、时间序列、决策树、神经网络等等。在项目开始时选择正确的预测建模技术可以节省大量时间。选择不正确的建模技术会导致不准确的预测和经历非恒定方差和/或均值的残差图。
回归分析
回归分析用于从一个或多个独立变量预测一个连续的目标变量。通常,回归分析用于自然发生的变量,而不是通过实验操纵的变量。如上所述,有许多不同类型的回归,所以一旦我们决定了应该使用回归分析,我们如何选择应该应用哪种回归技术?
方差分析

A scatterplot for data that may be best modeled by an ANOVA model looks as so
当目标变量是连续的且因变量是分类的时,使用 ANOVA 或方差分析。该分析中的无效假设是不同组之间没有显著差异。总体应呈正态分布,样本病例应相互独立,且组间方差应大致相等。
线性回归

当目标变量是连续的,因变量是连续的或者是连续变量和分类变量的混合,并且自变量和因变量之间的关系是线性的时,将使用线性回归。此外,所有预测变量应正态分布,具有恒定的方差,并且彼此之间应很少或没有多重共线性或自相关。
逻辑回归

https://www.researchgate.net/figure/Linear-Probability-Versus-Logistic-Regression-6_fig2_224127022
逻辑回归不需要目标和因变量之间的线性关系。目标变量是二元的(假设值为 0 或 1)或二元的。逻辑回归的误差/残差不需要是正态分布的,并且残差的方差不需要是常数。但是,因变量是二元的,观察值必须相互独立,数据中必须很少或没有多重共线性或自相关,并且样本量应该很大。最后,虽然该分析不要求自变量和因变量线性相关,但自变量必须与对数概率线性相关。

If the scatter plot between the independent variable(s) and the dependent variable looks like the plot above, a logistic model might be the best model to represent that data.
岭回归

For variables that experience high multicollinearity, such as X1 and X2 in this case, a ridge regression may be the best choice in order to normalize the variance of the residuals with an error term.
岭回归是一种分析经历多重共线性的多重回归变量的技术。岭回归采用普通的最小二乘法,并通过向回归估计值添加一定程度的偏差来减少标准误差,从而承认残差经历了较高的方差。假设遵循多元回归的假设,散点图必须是线性的,必须有不含异常值的恒定方差,并且因变量必须表现出独立性。
时间序列

https://simplystatistics.org/2016/05/05/timeseries-biomedical/
时间序列回归分析是一种基于响应历史预测未来响应的方法。时间序列的数据应该是变量在不同时间点的一组观察值。数据是二元的,自变量是时间。序列必须是稳定的,这意味着它们是正态分布的:序列的均值和方差在很长一段时间内是恒定的。此外,残差还应在长时间内呈均值和方差恒定的正态分布,并且不相关。该系列不应包含任何异常值。如果随机冲击是存在的,它们确实应该随机分布,平均值为 0,方差为常数。
分类分析
决策树

https://hackernoon.com/what-is-a-decision-tree-in-machine-learning-15ce51dc445d
决策树是一种监督学习算法,它基于关于样本的某些问题重复分割样本。这些对于分类问题非常有用。它们相对容易理解并且非常有效。决策树表示几个决策,后面跟着不同的发生几率。这项技术帮助我们定义最重要的变量以及两个或更多变量之间的关系。
神经网络
神经网络有助于对数据进行聚类和分类。这些算法大致模仿人脑,旨在识别模式。神经网络往往非常复杂,因为它们由一组算法组成。这种类型的分析可能非常有用,但是,如果你试图确定为什么发生了什么,这可能不是最好的模型。

http://www.asimovinstitute.org/neural-network-zoo/
总之,这些只是可用于数据建模的不同预测技术的一小部分选项。需要注意的是,在使用预测分析技术时,在变量之间建立因果关系是非常危险的。在预测分析中,我们不能说一个变量导致了另一个,相反,我们可以说一个变量对另一个变量有影响,以及这种影响是什么。
我们来连线:
https://www.linkedin.com/in/mackenzie-mitchell-635378101/
在 GitHub 上注册您自己的个人资料,这是托管代码、管理项目和与 40…
github.com](https://github.com/mackenziemitchell6)
资源:
https://www.statisticssolutions.com/manova-analysis-anova/
https://skymind.ai/wiki/neural-network
https://www . analyticsvidhya . com/blog/2015/01/decision-tree-simplified/2/
为偏态分类问题选择正确的度量
偏斜精度!!让我们尝试一些其他的分类标准!!

Skew Accuracy
这是关于不平衡和噪声数据系列文章的第 2 部分。第 1 部分关于数据生成到此为止。
那么,为什么我们需要关心我们的度量呢?TLDR;这将帮助你的企业更好地理解你的模型。这将有助于您的模型更快地优化自身,并获得更加面向业务的结果。
接下来是一个很长的答案。解决有监督的 ML 问题可以从不同的角度来看。
解决模糊问题
天气预测、股票价格预测或信用欺诈检测等都试图通过建立数据模式来解决看似模糊的问题。我们试图找到我们观察到的数据和观察到的目标标签之间的关系。我们进一步使用这些发现的关系进行预测。
“我们发现的数据和预测目标之间的关系质量如何?”
寻找函数近似值
我们相信,给定所有可能的数据,每个事件都是可预测的,因此我们相信,每个目标观察都可以用一个采用正确预测集的函数来解释。
*f*(All Predictors)->y
or
*f*(All Predictors) gives target
然后,我们试图找到一个函数 g,,这是一个很好的近似函数f。不可能在所有情况下找到函数 f 本身,因为你有时没有所有的预测值和所有的观测值。所以我们发现
*g*(Some subset of Predictors) -> y [Correct in most cases]
“g和 f有多接近?”
现在,**" g逼近 f"** 的程度将取决于我们的预测器有多好,以及我们的学习算法有多好。
所以我们有两个问题,我们的函数逼近有多好?我们发现数据和目标之间的关系有多好?这些是我们的指标帮助我们回答的问题。
需要一个好的度量标准:预测第二天的降雨
我们试图预测明天是否会下雨?我明天应该带一把伞吗?现在,我们每天都对一整年(365)的第二天进行预测。
让我们检查一些假设的数据。
它只下了 87 天雨,整整 278 天没下雨。我们预测了 42 天。但总的来说,我们说会下雨 122 天。我们在 87 天中对了 42 天,278–80 = 278 天中的 198 天,42+198 = 240 天。所以 240/365 正确或 65%的时间。但是如果我们的目的是保护我们的用户不被淋湿,那么我们失败了 87–42 = 45 次。下雨有一半是我们没有预料到的。因此,尽管我们有 65%的时间是正确的,但我们还是在 45 天里淋湿了,而且只在 42 天里得救了。
现在,我们使用的度量标准(总体正确率%)是问题的正确度量标准吗?考虑两种情况
- 案例一:避雨:客户利用你的预测来计划外出。或许你可以用不同的方法来衡量成功?像、、、【TTL/N 天前预测】、因为我们的用户想避免下雨,所以如果我们检测大多数天会更好。此外,在这种情况下,我们提前提供预测(第二个指标)以便用户进行规划是很重要的。所以我们努力优化这两者。
- 案例 2:通勤的交通路线选择:在这里,您可以预测每个小时,没有必要找到所有的雨天,而是重要的是大多数时候是正确的,这样用户(或地图应用程序)就可以在大多数日子选择正确的路线。所以这里的“%总体正确次数”确实是一个很好的指标。
从上面的例子中,我们看到一个成功的 ML 解决方案需要定义的不仅仅是精度/召回率/准确度。您的指标可能会考虑重要的业务因素,如何时应该进行预测?,你需要预测未来多久?(需求预测领域),你的算法需要多长时间?等。
在这篇文章中,我关注分类问题的一个子集,偏斜标签分类问题。在这些问题中,目标标签不是均匀分布的。我们的示例问题本身存在偏差,其中阳性标签(下雨)只有 87 个,而阴性标签有 278 个,偏差为 1:3。
许多像信用欺诈这样的问题有更高的偏差,99%的例子是负面的(非欺诈),只有 1%(欺诈)。因为像准确度/精确度/召回率这样的通用指标不能捕捉业务意图。许多组织也有一套好的精确/召回的概念(90%的精确,95%的召回)。但是对于这些扭曲的问题来说,这样的数字很大程度上是无法实现的。因此,正确的问题是:ML 模型能提供商业价值吗?你的度量应该反映这个问题。
分类问题可用的度量
我提供了一个在流行的 scikit 库中可用的分类指标的列表。在链接的文档页面上可以看到它们如何工作的详细信息。
我认为最好到最坏的安排(对于偏斜问题)
不平衡/偏斜问题的分类度量的行为
我们将创建一些人工数据,然后倾斜正负类。接下来,我们将使用一个分类算法和一些指标来检查这些指标如何应对不断增加的不对称。
理想情况下,在不对模型进行微调或对数据进行重采样的情况下,合适的指标应该从好变坏。另一方面,没有考虑偏斜的指标不会显示出太大的变化,甚至可能显示出偏斜越大的改进。
首先让我们看看不平衡的数据是什么样子的,我们将使用 scikit 的 make_moons api(在以前关于数据生成的博客中已经介绍过)。

Interactive Imbalance Plot Code
随着我们增加不平衡的结果

Increasing Imbalance
接下来,让我们看看在不平衡加剧的情况下,各种指标会是什么样子。

Generating Data
接下来,我们定义一个函数来连续构建模型。

Model builder function
最后,我们编写一个函数,循环遍历各种不平衡值、我们提供的指标,并制作一个指标与不平衡的图表。

Function to plot metrics vs imbalance
注意,我使用np.logspace来生成不平衡值。这帮助我生成更多接近 0 的值,和更少接近 1 的值。第 8 行对imbalance的函数调用使数据不平衡,这是一个自定义函数,可以在同一文件夹的[lib.py](https://github.com/faizanahemad/data-science/blob/master/exploration_projects/imbalance-noise-oversampling/lib.py)中找到。其他自定义函数在同一个文件中。
最后让我们运行它。我们使用 f1、准确度、召回率和精确度作为我们的衡量标准。

Metrics vs Imbalance — I
我们的观察如下。
准确度对不平衡完全不敏感,而精度、召回率和 f1 则敏感。
接下来,让我们尝试几个其他指标。我们定义了两个新的指标:precision@recall=75和recall@precision=75,因此我们将召回率/精确度保持在一个设定的阈值,然后检查这种不平衡如何影响另一个。

Metrics vs Imbalance — II
请注意,所有这些指标对不平衡都很敏感。为了改进它们,你需要改进你的模型。另一方面,精确度对不平衡不敏感,呈现出良好性能的虚假舒适画面。发生这种情况是因为随着偏斜的增加,预测最频繁的类将给出高精度。在 1:99 的偏差情况下(1 个正例,99 个负例),如果你总是预测为负,那么你的准确率是 99%。Accuracy = Num correctly predicted / Total examples
最后,我们将比较 AUC-ROC 和平均精度与准确性。

Metrics vs Imbalance — III
注意,AUC-ROC 对不平衡不敏感。因此,如果数据集有偏差,那么 AUC-ROC 就不是一个好的指标。让我们找出原因。
解释为什么 AUC-ROC 对不平衡不敏感
公然从上面的文章复制粘贴(避免写的东西和别人写的一样)。

Roc Curve and Terms
所以 ROC 曲线对于不同的阈值(0-1)是真阳性对假阳性。最低值可以是 0.5,用于随机猜测。
让我们看看它对增加不平衡有什么作用。
我们想证明的是:随着失衡的增加,TPR 和 FPR 相对保持不变。
等式 1: TPR = TP/(TP+FN)
随着不平衡的增加,TPR 将大部分保持不变,因为它依赖于错误分类的正面例子。如果我们的算法具有 90%的检测,则 TPR = 90/(90+10) = 0.9,即 TPR 不取决于偏斜,而是取决于我们的算法仅能够多好地检测正类。
等式 2: FPR = FP/(TN+FP)
有趣的是,随着偏斜的增加,我们将有更多的 FP,假设我们的算法将每 100 个负样本中的 1 个分类为正样本(FP),那么当我们有高偏斜时,我们将有许多负样本与正样本相比,以及许多 FP。但是这里我们不考虑 FP,我们考虑 FPR,注意分母中的 TN,真负数(TN)也会随着负数类的增加而增加。结果,FPR 还是老样子。
鉴于这两个方程在直觉上保持一致,AUC-ROC 对偏斜不敏感也就不足为奇了。
对不平衡/偏斜问题使用衍生指标
我建议根据您的业务需求使用以下两种方法中的任何一种。
- 精确度@召回=x 或 FPR @召回=x
- Recall@Precision=x
为什么这些有用?
以欺诈检测为例,你想检测 95%的欺诈,所以你的召回率=0.95,现在你想确保你没有太多的 FPs。精度= TP/(TP+FP),所以精度越高,FPs 越低。你的企业在我们的公式中修正了x。你知道召回,现在你用持续召回来优化你的模型,以提高精度或降低 FPR。
同样,考虑癌症的药物管理(化学疗法)。你要确保没有患病的人不会服用这种药物,因为它对健康有巨大的不良影响。你的医院认定只有 1/1000 的诊断是不正确的。或者你的精度= 999/(999+1) = 0.999。所以你的精度是固定的,现在你的模型必须增加检测/召回。因此,Recall@Precision=0.999 是一个很好的指标。
除了使用这些特定于问题的派生指标,您的指标还可以由多个约束组成。例如,在我们讨论的降雨预测问题中,您可以有一个类似于Precision@Recall=0.8,Duration=7 Days的度量,即您想要检测 80%的降雨天,并且您想要在下雨前至少 7 天预测这一情况。有了这些约束,您就可以优化精度。
选择正确指标时需要注意的事项
基于问题和度量的数学性质
如果你的分布是偏斜的,那么准确性和 AUC-ROC 就不好。最好使用精度/召回率或一些派生的度量标准。
基于商业效用
派生指标在这里是赢家,因为它们最好地转化为业务用例。上面我们展示了 Precision@Recall=x 和 Recall@Precision=x 如何很好地编码您的业务需求。
关于为什么不使用曲线下面积/f1 得分/AP 作为衡量标准的信息很少
仅供参考:这是一种意见。

F1 Formula
请注意,当精度和召回互换时,F1 可以是相同的值。取精度=0.9,召回=0.3,那么 f1=0.45,反过来取召回=0.9,精度=0.3,还是 f1 = 0.45。现在,如果您将 f1 作为您的模型指标,那么精确度和召回率的值是多少。你的企业准备好接受这两种价值观了吗?他们能理解这个吗?
现在来看 AP/AUC-ROC,他们有类似的问题,你的曲线下面积可能是相同的,这是两条看起来非常不同的曲线,它们优化的东西不同。
结论
让我总结一下我们的学习
- 不要使用 AUC-ROC、PR-曲线面积(平均精确度分数)等进行业务报告。
- 不要使用 F1 分数等过于复杂的指标进行报告。
- 使用衍生指标,因为它们很容易抓住你的业务的本质
- 如果你的数据不平衡,就不要用 accuracy 或者 auc-roc。
将您的模型指标建立在您业务成功的基础上!!
感谢阅读!!
我利用数据科学、人工智能、机器学习和深度学习来解决现实世界的问题。随时联系我 LinkedIn 。
为机器学习选择正确的评分模式

根据 Gartner 的 2019 年首席信息官调查,企业对人工智能的采用在过去四年增长了 270%,超过 37%的企业已经在某个方面实施了人工智能。企业正在以惊人的速度采用这项技术,首席信息官和数据科学家正面临着艰难的决定,即哪种人工智能速度适合他们的业务需求。
人工智能可以分为三种评分模式:批处理、事件驱动和实时。根据模型的目标,每个评分模式提供不同的功能。例如,虽然批处理计算在工资单设置中可能工作得很理想,但它不是跟踪银行交易中欺诈的有效方法。
通过探索这三种方法及其潜力,公司能够最大限度地发挥其宝贵的洞察力。
1.成批处理
批处理是人工智能处理大量数据的有效方式。在一段时间内收集事务,然后进行批处理。历史上,批处理用于建模预测分析,因为大量的数据可确保更准确的结果和见解。随着流数据的发展,处理选项正在扩展,但批处理仍然是将大量数据提取到业务策略中的最常见方式。
这种形式的数据处理通常用于在下班后执行银行交易、运行业务报告以及在正确的时间间隔内向客户开账单。批量模型还可用于对客户忠诚度、终身价值或细分会员资格进行评分,时间间隔从每天多次到每月一次不等。任何不需要实时数据输入的任务都适合批处理。
最后,当模型和数据量数量有限时,批处理允许时间灵活性,以及成本和网络能量的效率。对于许多不需要持续数据处理的场景,批处理可能是最好的选择。对于拥有数百个模型的环境,并且这些模型应用于数 TB 或数 GB 的数据,时间和成本很快就会成为问题。
2.事件驱动处理
并非所有数据都是平等的。随着物联网设备、传感器和应用程序的激增,数据科学家面临着确定优先级的任务。大多数数据都是无关紧要的,不需要对模型进行评分;然而,当一个非典型事件发生时,人工智能可以介入并管理最佳的后续步骤。
事件可以被认为是状态的任何重大变化;可能是购买一辆新车,买一栋房子,生一个孩子,或者收到一大笔钱。另一方面,事件可以是小规模的,例如发送电子邮件、访问特定网站或设备达到某个温度。无论系统被设计来跟踪什么事件,当事件发生时,它允许 AI 遵循最佳实践。
事实证明,事件驱动的处理对营销非常有用,因为当企业适应了消费者的日常生活时,他们会变得更加敏感。这种类型的处理对于企业自动化库存控制之类的事情也很有价值,或者对于人工智能知道某人何时到家或离开也很有价值。
当企业能够预先确定应该与一致的行动相关联的指标时,它们应该实施事件驱动的处理。人工智能既可以用来识别这些指标,也可以用来采取行动。
3.实时处理
随着与互联网浏览和生成数据相关的数字标识符的增长,数据科学家努力以接收数据的相同速率处理数据,即实时处理。这种方法需要不断的输入、处理和输出。流媒体催生了快速数据的存在,世界各地的公司都在这种方式中发现了新的价值。
人工智能实时处理数据的一个例子是信用卡购买的欺诈报告。在几毫秒内,银行必须登记输入的信息,应用评分模型,并确定后续步骤。根据信息的得分,银行要么批准购买,要么将其报告为欺诈。实时人工智能处理对于医疗诊断、语音识别、市场分析、消费者推荐和机器人等许多领域都是必要的。
实时处理是关于实现更快的结果,使用上下文线索、即时分析和毫不犹豫的行动;然而,这项技术也有其局限性。某些情况下的质量水平值得怀疑。虽然丢失的数据流可能不会严重影响营销计划的准确性,但对于许多工业目的来说,这种影响可能会产生有害的影响。其他 AI 模型可能依赖于不可用于实时检索的数据源,或者它们不支持可接受的 SLA。这当然限制了它们被实时调用的能力。然而,如果环境包括在非常特定的场景下评分或不经常评分的 AI 模型,那么对这些模型采取实时或按需方法通常比花费资源批量生成很少使用的分数更好。
确定后续步骤
为了实施有效的人工智能战略,公司必须考虑每个用例或场景的需求参数。虽然批处理在历史上是主要的处理模型,但事件驱动和实时处理使结果成为可能,使人工智能数据科学家能够探索新的视野,并在他们的模型中利用实时的上下文数据。
重要的是要记住,所有这些方法都可以一起工作。由于精确度最高,批处理驱动可能是建立人工智能模型的最明智的方式;事件驱动的处理可以在必要时发出危险信号,并推动高度直观的营销活动。最后,实时处理允许成本有效的客户服务和许多类型的个性化。一个熟练的人工智能数据科学家和 ML 工程团队必须一起工作,以确定哪种类型的处理最适合给定的用例及其约束。
原载于 2019 年 7 月 1 日【https://www.quickpath.com】。
为深度神经网络选择正确的权重初始化
两部分系列的第一部分
您为神经网络选择的权重初始化技术可以决定网络收敛的速度或是否收敛。虽然这些权重的初始值只是许多要调整的参数中的一个,但是它们非常重要。它们的分布影响梯度,从而影响训练的有效性。
在神经网络中,权重表示相邻网络层中单元之间的连接强度。这些权重和前一层中的值的线性变换通过非线性激活函数来产生下一层的值。这个过程在正向传播期间逐层发生;通过反向传播,可以找出这些权重的最佳值,以便在给定输入的情况下产生精确的输出。
在本文中,我们将介绍:
- 为什么重量初始化很重要
- 围绕权重初始化的活跃研究领域
我们将不涉及这些初始化方法的数学推导。如果你对这类材料感兴趣,我们可以在文章的内部和结尾(在“进一步阅读”部分)链接到几个很好的资源📚。
为什么权重初始化很重要?
不正确初始化的权重会导致消失或爆炸梯度问题,从而对训练过程产生负面影响。对于消失梯度问题,权重更新较小,导致收敛较慢——这使得损失函数的优化较慢,在最坏的情况下,可能会使网络完全停止收敛。相反,使用太大的权重进行初始化可能会导致正向传播或反向传播过程中梯度值爆炸(参见更多此处)。
Deeplearning.ai 最近发布了一个互动帖子在这里你可以选择不同的初始化方式,观看网络列车。这里有一个例子:

你会注意到设置一个太小的初始化方法几乎不能让网络学习(即降低成本函数),而过大的初始化方法会导致发散(检查决策边界)。
权重初始化方法发生了怎样的变化?
2012 年,该年 ImageNet 大规模视觉识别挑战赛(ILVSRC)的获胜者 AlexNet 推广了“使用均值等于零、标准差设置为 0.01、某些层的偏差等于一的高斯(正态)噪声进行初始化”的权重初始化方法(参见 Krizhevsky et al. 2012 )。
然而,由于前面提到的消失和爆炸梯度问题,这种正常的随机初始化方法不适用于训练非常深的网络,尤其是那些使用 ReLU(校正线性单元)激活函数的网络。
为了解决这些问题,Xavier 和 Bengio (2010)提出了“Xavier”初始化,在初始化权重时考虑网络的大小(输入和输出单元的数量)。这种方法通过使权重与前一层中单元数量的平方根成反比来确保权重保持在合理的值范围内(称为扇入)。关于如何找到给定单元的扇入和扇出,请参见下图:

激活函数的选择最终在确定初始化方法的有效性方面起着重要的作用。激活函数是可微分的,并将非线性属性(即曲率)引入我们的神经网络,这些神经网络对于解决机器学习和深度学习旨在解决的复杂任务至关重要。
激活函数是我们对输入信号进行的非线性变换。然后,这个转换后的输出被发送到下一层单元作为输入。这些非线性激活函数的一些例子是:
- 乙状结肠的
- Softmax
- 双曲正切
- 热卢
- 泄漏 ReLU
通常使用校正线性单元(ReLU)(和泄漏 ReLU),因为它们对消失/爆炸梯度问题相对鲁棒。对于像 ReLU 这样的激活函数,何等人(2015)引入了一种更稳健的权重初始化方法,该方法考虑到了它是不对称的这一事实(参见下文何等人论文中引用的性能差异)。这两种方法都使用了相似的理论分析:它们为从中提取初始参数的分布找到了良好的方差。该方差适用于所使用的激活函数,并且是在没有明确考虑分布类型的情况下导出的。

图来自何等人(2015)的论文,显示了他们改进的初始化策略(红色)如何比(P)ReLUs 的 Xavier 方法(蓝色)更快地降低错误率,并说明了其不对称的事实。
关于 Xavier 和 he 初始化方法的可访问证明,请参见 Pierre Ouannes 的精彩帖子“如何初始化深度神经网络?泽维尔和明凯初始化'。
值得注意的是,权重初始化仍然是一个活跃的研究领域。已经出现了几个有趣的研究项目,包括数据相关初始化、稀疏权重矩阵和随机正交矩阵初始化。
该领域最有趣的发展之一是麻省理工学院的彩票假说,该假说详细描述了这些大型神经网络如何包含比完整网络小 10 倍的较小“子网”。根据研究小组的说法,这些子网也可以学习,做出同样精确的预测,有时比完整的神经网络更快。
“彩票假说:寻找稀疏的、可训练的神经网络”的作者 Carbin 和 Frankle 通过执行一个称为修剪的过程来测试他们的彩票假说和子网的存在,该过程涉及根据网络优先级或权重从训练过的网络中删除不需要的连接,以使它们适合低功耗设备。
事实上, TensorFlow 最近宣布了一个新的权重修剪 API:
权重修剪意味着消除权重张量中不必要的值。我们实际上是将神经网络参数值设置为零,以去除我们估计的神经网络各层之间不必要的连接。这是在训练过程中完成的,以允许神经网络适应这些变化。
点击阅读更多关于权重修剪 API 的信息。
互动演示
点击这里试试这个互动演示。权重值的大小很重要,但确保权重随机初始化也很关键。这种随机初始化方法基于一种称为打破对称性的已知特性,其中:
- 如果两个隐单元有相同的输入和相同的激活函数,那么它们一定有不同的初始参数
- 最好初始化每个单元来计算不同的函数
如果仅用零初始化权重,网络中的每个神经元将计算相同的输出,并且梯度将经历完全相同的参数更新。换句话说,如果神经网络中的单元的权重被初始化为相同的值,则它们将在训练期间学习相同的特征。

通过迁移学习,您可以使用以前网络中保存的权重作为新实验的初始权重,而不是从随机初始化的权重开始(即微调预训练的网络)。
Selenium 和 SQL 组合——顶级英超球员
用 Selenium 抓取并将数据列表到 SQL 数据库表中

Source: Jannes Glas via unsplash
英超 2019/20 赛季计划于 2019 年 8 月 10 日星期六开始。虽然对新赛季的期望越来越高,但我想我会调查刚刚过去的这个赛季中表现最好的球员。
这篇教程将演示我们如何简单地收集 2018/19 赛季最佳球员的数据,并将这些数据列表到数据库管理系统(DMS)MySQL 中。然后可以使用 SQL 查询收集的数据。
开始本教程,第一个目标是找到一个关于顶级英超球员的关键统计数据的合适来源。快速搜索将我带到 BBC 足球选项卡上的“英超最佳射手”页面,如下所示。

数据挖掘
我想收集的每个球员的数据的关键统计指标是:他们各自的名字和他们竞争的球队,进球和助攻,他们的射门准确性,最后是他们的每球上场时间比率。
首先,我需要找到一个包装器,其中包含我渴望收集的每个玩家的所有统计数据。我在我的 chrome 浏览器中右击感兴趣的页面,将鼠标悬停在我正在搜索的 web 元素上。显然,包装器“div . top-player-stats _ _ item . top-player-stats _ _ item-no-image”包含了所有感兴趣的信息(如下图中突出显示的)。
在编写任何 Python 代码之前,我鼓励的一个工作习惯是切换到开发者工具的控制台选项卡,搜索感兴趣的元素。这种方法被认为是最佳实践,因为我们可以直观地检查是否找到了感兴趣的元素。
要使用此功能,请键入 2 个美元符号$$,然后在括号内输入标签和标识符名称。

现在已经找到了包装器,还需要找到包装器中的关键信息,这样我们以后就可以遍历包装器,提取每个玩家感兴趣的所有信息。
如下所示,我可以清楚地看到播放器“Mohamad Salah”包含在 h2 标签中,在浏览器和元素选项卡中,类名都以蓝色文本指定。

有用的验证:我的建议
控制台实用程序 API 包含一组用于执行常见任务的便利函数:选择和检查 DOM 元素以及以可读格式显示数据。
如图所示,这里我执行了一些快速但有用的验证步骤。从视觉上检查页面,我知道应该有 25 个玩家,实际上通过使用控制台中的 length 函数得到的长度实际上是 25!
此外,让我们确认球员的名字是正确的。我想知道这 25 个元素列表中的第一个元素是否是“Mohamad Salah”,所以我简单地使用了控制台文本功能,一切似乎都如预期的那样工作。

最后,让我们确认列表中的最后一个玩家实际上是“勒鲁瓦·萨内”,我用第 25 个元素([24],由于 Python 的第 0 计数索引系统)索引我的搜索查询,并滚动到网页的底部。事实上,“勒鲁瓦·萨内”是名单上的最后一名球员。

我对我想从这个网页上获取的每一条数据都重复这个过程,比如球队、进球、助攻和进球率。
使用硒
为了提取、制表并传输到 SQL 数据库,我首先需要导入 selenium webdriver、pandas 库和 sqlalchemy 模块。
sqlalchemy 模块中的 create_engine 函数支持与数据库的交互。提供了一个连接字符串,告诉引擎对象我们正在连接到 MySQL 数据库。
然后,我创建一个 webdriver 对象并将其分配给变量 browser,并使用 browser 对象上的 get 方法导航到 BBC 页面。
我使用 find_elements_by_css_selector 方法找到所有玩家及其数据,并在括号中输入前面找到的包装器。我将该列表分配给变量,明智地称为玩家。
在开发人员工具的控制台选项卡中验证元素的一个很大的优点是,它们可以直接复制并粘贴到‘find _ element(s)_ by _ CSS 选择器方法中,它们是有效的查询!
我现在可以遍历球员列表,提取像进球等关键信息。然后可以将这些附加到适当的列表中。为了确认一切工作正常,我打印出列表,并删除任何我不想要的文本。
例如,我想在我的 SQL 数据库中把“每个目标 140 分钟”作为一个数字,所以我确保删除任何填充和“每个目标分钟”。最后,尽管不是绝对必要的,我退出了浏览器,这样当我在每次迭代中检查我的列表时,页面就不会堆积。
最后,我创建了一个 DataFrame,将我的列表压缩在一起,并将它们分配给合理命名的列。然后,我通过填写下面 GitHub 要点中显示的参数连接到 MySQL。
我需要在底层数据库中存在一个表,以便将我新创建的数据帧 df 插入其中。我用 SQL 语言编写了一个查询来创建一个表,并为每一列分配一个数据类型。
然后执行查询(MySQL 中的表现在已经完成)。现在,剩下要做的就是使用。to_sql 方法,并将我的 DataFrame (df)插入到名为 top_players 的新表中。
刷新 schemas 图标显示 top_players 表已经创建。一个简单的 SQL 查询从表中提取所有列,显示 selenium 抓取的数据现在驻留在一个 SQL 表中。

最后,让我们执行一个信息查询。我们很想知道,哪些球员的投篮命中率在 60%以上,每分钟进球率低于 185 分钟。使用 WHERE 子句进行过滤会返回满足这些条件的玩家。

摘要
这篇教程演示了如何使用 selenium 收集数据,然后将数据制成数据帧,再传输到 MySQL 等 SQL 数据库。
气流上的硒:在网络上自动化日常任务!
这篇文章演示了如何构建一个使用 Selenium WebDriver 的气流插件来自动化日常在线任务。

Photo by Jehyun Sung on Unsplash
自动化提供了一系列好处
- 提高生产力。
- 更高的质量。
- 消除人为错误的可能性并减少体力劳动。
- 额外的频率和一致性(周末工作!).
如果您的日常任务涉及到网络,那么在 Airflow 上使用 Selenium 每年可能会节省数百个小时,并提高您工作的质量和一致性。
简介
这篇文章的目标是开发一个插件,利用 Selenium 来自动完成关于气流的日常任务。
- 设置气流环境。
- 开发 Selenium 插件。
- 在气流 DAG 中使用 Selenium 插件。
如果你想跳过,这篇文章中讨论的所有代码都可以在我的 GitHub 这里找到。
以下是所涵盖主题和软件的简要概述:
Selenium: 简而言之,Selenium 自动化了浏览器。它主要用于自动化测试目的的 web 应用程序,但是它并不局限于此。selenium 的一个关键组件是 WebDriver,WebDriver API 直接向浏览器发送命令。示例命令可以是导航到网页、填写表格,甚至下载文件。在这篇文章中使用的网络驱动将是 Selenium/standalone-chrome 驱动。
Airflow: Airflow 是一个以编程方式创作、调度和监控工作流的平台。Airflow 的关键组件是 web 服务器、调度器和工作器。web 服务器指的是 Airflow 用户界面,而调度程序根据预定义的指令在一组工作线程上执行您的任务。
最后,为了同时使用 Selenium 和 Airflow,还需要集装箱化软件 docker。
Docker 是一款通过使用容器来简化软件部署和开发的软件。容器允许开发人员将应用程序及其所有需求打包在一起,还可以将软件与其环境隔离开来,以确保它可以在不同的开发环境中工作。Docker 的一大特色是 compose 工具,它用于定义和运行多容器 Docker 应用程序。
我们将首先使用 Docker 来设置我们的气流环境,然后作为我们插件的一部分增加一个额外的 Selenium 容器。
设置气流环境
基础环境:
如上所述,Docker 将用于设置气流环境。为此,请访问https://github.com/puckel/docker-airflow并下载docker-compose-celery executor . yml文件。这是一个 docker-compose 文件,由 Github 用户 Puckel 创建,允许您快速启动并运行气流。compose 文件选择 Celery executor,如果您需要并发运行任务,那么这是必要的,因为它扩展了工作线程的数量。
docker-compose 文件有一些基本的变化。
- 重命名合成文件:docker-compose.yml。
- 取消自定义插件卷的注释。
- ./plugins:/usr/local/airflow/plugin
要确保 Airflow 容器对插件和 Dag 目录拥有正确的权限,请在运行合成之前确保主机上存在这些目录。
使用 docker-compose up 命令测试环境在本地运行,UI 应该在 http://localhost:8080 可用。

修改环境以适应 Selenium 插件
在完成环境之前,有必要简要解释一下 Selenium 插件是如何工作的,因为它的一些功能会直接影响设置。这个插件将会在后面的文章中详细介绍。
该插件将执行以下步骤:
- 启动 Selenium docker 容器
- 配置远程硒驱动程序
- 向驱动程序发送命令:这将导致从互联网下载一个文件。
- 移除运行中的容器
上述步骤可以归纳为两类:
- 从气流中使用 Docker。
- 与远程容器交互
从气流中使用 Docker
气流工作者需要能够创建 Selenium 容器,然后发送命令来执行任务。正如 jérme Petazzoni 在这篇文章中很好地解释的那样,在另一个容器中旋转 Docker 容器是不好的做法,只要容器存在并且可访问,就没有必要这样做。允许工作人员创建容器的最简单的方法是通过将主机 Docker 套接字作为一个卷安装在 docker-compose 文件中,从而向工作人员公开它。
worker:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
由于没有正确的权限,气流工人仍然无法访问主机 Docker 套接字,因此必须更改这些权限。这可以通过创建名为“Dockerfile-airflow”的新 docker 文件来实现,该文件扩展了 puckel/docker-airflow 基本映像,如下所示:
FROM puckel/docker-airflow:1.10.4USER root
RUN groupadd --gid 999 docker \
&& usermod -aG docker airflow
USER airflow
- docker 文件首先调用 puckel/docker-airflow 基础映像
- 作为根用户,创建 id 为 999 的 docker 用户组,并将 airflow 用户添加到该组中。
- 设置气流用户。
工作者和主机上的 docker 组 id (999)必须相同。要找出主机 docker 组 id,请使用以下命令:
grep 'docker' /etc/group
创建新的 docker 图像:
docker build -t docker_airflow -f Dockerfile-selenium .
接下来要做的是在 Docker-compose 文件中将气流图像名称从puckel/docker-airflow:latest更改为docker_airflow:latest。这意味着合成文件将使用新创建的图像。
Airflow worker 现在可以在主机上创建 Docker 容器,但是仍然需要 Docker python 包。附加安装也可以在 Dockerfile 文件中处理。下面的安装是 Selenium 插件和 DAG 所必需的。
RUN pip install docker && \
pip install selenium && \
pip install bs4 && \
pip install lxml && \
pip install boto3
要使用插件启动 Selenium 容器,映像必须已经存在于主机上:
docker pull selenium/standalone-chrome
最后,为了让 worker 容器向新的 Selenium 容器发送命令,它们需要在同一个 Docker 网络上。两个容器都将位于外部网络上:使用以下命令创建的“container_bridge ”:
docker network create container_bridge
容器桥网络也需要添加到合成文件中。
worker:
networks:
- default
- container_bridgenetworks:
default:
container_bridge:
NB 需要注意的是,上述将主机 docker sock 暴露给 worker 容器并设置权限的方法只能在 linux 环境下工作,要为 MacOS 配置开发环境,请参考这两篇精彩的文章:
与远程容器交互
Selenium 插件通过远程驱动程序向 docker 容器发送命令,它通过 container_bridge 网络连接到远程驱动程序。Selenium 命令将作为主目录中的挂载卷添加到环境中:{AIRFLOW_USER_HOME}
volumes:
# Selenium scripts
- ./selenium_scripts:/usr/local/airflow/selenium_scripts
这些命令将来自一个定制的 Python 模块(selenium_scripts ),它需要位于 Python 路径中。这可以在 Airflow Dockerfile 文件中完成。
ENV PYTHONPATH=$PYTHONPATH:${AIRFLOW_USER_HOME}
气流环境的最后一个变化是允许 Selenium 容器和气流工作者共享文件和内容。当使用 Selenium 从互联网下载内容时,这是必需的,并且可以使用外部命名卷来实现。
docker volume create downloads
需要将“下载”卷添加到 docker-compose 文件:
worker:
volumes:
- downloads:/usr/local/airflow/downloadsvolumes:
downloads:
external: true
在容器上创建 Docker 卷时,如果没有预先存在的相应目录,它们将由 root 用户创建,这意味着容器用户没有写权限。规避这一点的最简单的方法是在初始构建期间以容器用户的身份创建目录。
对于 Airflow Dockerfile 文件,添加以下行:
RUN mkdir downloads
必须为 Selenium 容器创建一个新的 Dockerfile,这将被称为 Dockerfile-selenium。
FROM selenium/standalone-chromeRUN mkdir /home/seluser/downloads
构建两个新映像:
docker build -t docker_selenium -f Dockerfile-selenium .docker build -t docker_airflow -f Dockerfile-airflow .
环境现已完成,完整的环境如下:
气流 Dockerfile 文件:
Selenium Dockerfile 文件:
docker-撰写:
Selenium 插件
Airflow 的一个很大的特性是插件,插件是扩展 Airflow 现有特性集的一个简单方法。要将新插件与现有的气流环境集成,只需将插件文件移动到插件文件夹中。
Selenium 插件的工作方式如下:
- 在主机环境中启动 Selenium Docker 容器。
- 在 docker 容器上配置远程 Selenium WebDriver。
- 向 WebDriver 发送命令来完成任务。
- 停下来,取出容器。
这种方法比使用独立的 Docker 操作符更常用,因为它提供了更好的控制,并且便于调试。
Selenium 插件将包含一个钩子和操作符,钩子处理外部连接并构成操作符的构件。操作员将执行我们的任务。插件文件夹结构如下:
。
├── README.md
├── init。py
├──勾手
│ ├── init。py
│ └──硒 _hook.py
└──算子
├── init。py
└──硒 _operator.py
要创建一个插件,你需要派生 AirflowPlugin 类并引用你想插入到 Airflow 中的对象,我们在 init 中做了这些。py 文件:
硒钩
Selenium 钩子继承自 BaseHook 模块,它是所有钩子的基类。这个钩子由启动、停止和向 Selenium 容器发送命令的几个方法组成。
创建容器:钩子利用 Python Docker 库向主机 Docker 套接字发送命令,并在主机上创建 Selenium 容器。外部命名卷(下载)安装在本地下载目录中,该目录将被配置为浏览器的默认下载位置。为了支持与工人的交互,还包括了 container_bridge 网络。
配置驱动程序:一旦执行了 create_container 方法,下一步就是配置并连接驱动程序,使其满足任务需求。
因为 Selenium 容器位于 container_bridge 网络上,所以可以在网络 IP 的以下位置找到 web driver:<network IP>:4444/wd/hub。可以使用 WebDriver 遥控器将驱动程序连接到。
配置驱动程序的第一步是使用 Options 类使驱动程序能够在 headless 模式下运行,并设置窗口大小以确保页面内容正确加载。无头模式本质上意味着驱动程序没有用户界面。
options = Options()
options.add_argument("--headless")
options.add_argument("--window-size=1920x1080")
第二步是启用浏览器以无头模式下载。这是通过向驱动程序发送 post 请求来完成的,该请求修复了下载行为。
driver.command_executor._commands["send_command"] = (
"POST", '/session/$sessionId/chromium/send_command')
params = {'cmd': 'Page.setDownloadBehaviour',
'params': {'behavior': 'allow',
'downloadPath': <DOWNLOADS>}}
driver.execute("send_command", params)
执行任务:为了使插件尽可能保持任务不可知,Selenium 命令被抽象为一个单独的 python 模块,在运行时导入 DAG。每个脚本的一个条件是它们作为函数导入,第一个参数是驱动程序。这将在后面详细介绍。
移除容器:一旦任务完成,容器就可以被移除。
硒算子
如上所述,气流挂钩是运营商的积木。下面的操作符使用 Selenium 钩子和 Airflow 的执行上下文来运行 Selenium 任务。
所有气流操作符必须继承 BaseOperator 类,该类创建成为 DAG 中节点的对象。Airflow 操作符的一个重要特性是能够定义模板字段;这些是 Jinjafied 字段,在执行时可以接受 Airflow 宏。airflow_args 变量是一个 template_field,这意味着它们可以在运行时使用宏动态设置。
在气流 DAG 中使用 Selenium 插件
由于气流环境和 Selenium 插件现在已经完成,下一步是将它们以气流 DAG 的形式组合在一起。气流 DAG 以预定义的方式运行一组任务。
下面的 DAG 示例旨在从 BBC 下载每日播客:醒来发现钱,并将 mp3 文件上传到 S3 供以后使用。《为钱而醒》是英国广播公司第五电台的一档早间财经广播节目,每周日早上 5 点播出新一集。
Selenium 脚本:
唤醒赚钱脚本使用 Selenium WebDriver 导航到 URL:https://www . BBC . co . uk/programs/b 0070 lr 5/episodes/downloads并下载最新一集。

一旦浏览器呈现了页面,就会使用 Beautiful soup 来解析下载链接的 html。在下载链接上调用driver.get方法启动下载,并轮询完成。下载后,该文件会被重命名,以便于在任务之间进行跟踪。
正如在插件部分提到的,Selenium 脚本需要是一个可执行的函数,将驱动程序设置为第一个参数。
完成后,确保 Selenium 脚本位于在 Airflow 环境中挂载并在前面的步骤中添加到 Python 路径的文件夹中。
匕首
如上所述,DAG 是任务的集合,创建 DAG 的第一步是描述这些任务将如何运行。创建 DAG 对象时使用的参数就是这样做的。
由于播客在每个工作日的早上 5 点播出,DAG schedule_interval 将被设置为在早上 7 点播放每集。将气流时间表达式设置为仅在工作日运行并不容易,因此 DAG 将每天运行,分支操作符将用于根据一周中的某一天来设置任务。
现在已经定义了 DAG 计划,下一步是添加任务。DAG 任务包括:
- 启动:启动 DAG
- 工作日分支:根据执行日是否为工作日,确定遵循 DAG 的哪个分支。
- 获取播客:下载播客。
- 上传播客到 S3: 上传播客到 S3。
- 删除本地播客:删除播客的本地副本。
- 结束:结束 DAG。
开始和结束任务利用气流虚拟操作器,它们除了在任务分组时有用之外什么也不做。
Selenium 插件将在下载播客任务中使用。SeleniumOperator 将在运行时执行从 Selenium 脚本模块导入的 download_podcast 函数。一旦播客被下载,它将被保存在新的名称下:episode_{{ds_nodash}}.mp3,但是由于文件名是一个模板字段,这将在运行时呈现。例如,2019 年 10 月 13 日的文件名将为episode_20191013.mp3。
工作日分支任务根据执行日是工作日还是周末将 DAG 分成两个分支。分支任务使用 Airflow Python 分支运算符根据 weekday_branch 函数的输出设置下一个任务。
如果执行日是工作日,DAG 运行的下一个任务是 get_podcast 任务,如果执行日是周末,运行的下一个任务是 end。
最后两个任务是:上传播客到 S3 和移除本地播客。这两种方法都使用 PythonOperator,它被扩展为“Jinjafy”参数。根据 Selenium 操作符,这对于跟踪 podcast 文件名是必要的。
S3 函数将需要一个名为 S3 _ 康恩 _id 的 S3 连接。
最后,最后一步是定义任务顺序,注意 weekday_branch 任务如何先于 get_podcast 和 end 任务。
start >> weekday_branch
weekday_branch >> get_podcast
get_podcast >> upload_podcast_to_s3
upload_podcast_to_s3 >> remove_local_podcast
remove_local_podcast >> end
weekday_branch >> end

我希望你喜欢这篇文章;如果你有任何问题或建议,甚至是对未来帖子的想法,请在评论区告诉我,我会尽最大努力回复你。
请检查我的其他气流职位:
自我评估神经网络

A diagram of a Self-Assessment layer
我发明了一种新型的神经网络层,我希望得到反馈。
新的层使网络能够评估其自身特征的可靠性。这使得它可以根据问题改变每个特征的权重。
问题
当正常的神经网络解决回归问题时,它只提供原始输出。它不提供对输出正确性的确定程度的度量。
如果网络不知道输出实际上应该是什么,这就是一个问题。它不会告诉你它的输出只不过是瞎猜。
这两种不确定性是有区别的:
- “我已经检查了我能找到的所有数据源,答案是 0.3”
- “我甚至不知道从哪里开始,但平均值是 0.3,所以我们就这样吧”
当代的神经网络没有捕捉到它们之间的差异,因为它们都给出相同的输出。
对我来说,这一信息显然应该是有用的。
解决办法
我介绍自我评估层:
自我评估层是神经网络的一种新型层。它由平行训练的两部分组成:
1.主组件,其行为类似于普通层。
2.自我评估部分,学习预测主要部分的有用性。
有许多不同的方法来实现细节。在我尝试的例子中,它是这样实现的:
主要成分是线性层。
自我评估组件像正向传递中的正常线性层一样工作。在向后传递时,它忽略它接收到的梯度并替换它。自我评估部分的新梯度来自最小二乘损失函数。该损失的目标是由主分量接收的梯度的平均绝对值。
因此,自我评估组件学习预测主组件梯度的平均绝对值。
每当主成分做出一个完美的预测,自评成分应该预测为零。每当主成分做出差的预测时,自我评估成分应该预测高的值。
自我评估部分最终成为在计算了其他特征之后剩下的不确定性的度量。
了解网络的可靠性对您在设计网络架构时做出决策非常有用。此外,这些信息还可以帮助您提高网络的准确性:
将网络层分成许多平行的层,并对每一层进行自我评估。网络应该从中获得有价值的信息以改进其自身的性能。原因如下:将一个层的特征想象为人们给下一层的人提供建议。增加一个自我评估层可以让你知道哪些顾问实际上对他们的建议有信心,哪些没有。
用例
自我评估层至少有两种不同的用途:
- 来评估你的网络预测的可靠性。
- 通过使网络能够对其自身的每项功能进行评级来提高网络的整体性能。这使得网络能够对其自身特征的不确定性进行建模,从而提高性能。
PyTorch 中的实现
我已经在 PyTorch 中实现了自我评估层。
查看我的 Github 代码:https://github.com/FlorianDietz/selfAssessment
背景和更多信息
这项发明是我私人研究项目的副产品。
在一次小规模试验中,使用该图层可使 MNIST 数据集略有改善。然而,这种改进太小了,无法确定它是否有用。
这个项目与我的主要研究方向不同。这就是为什么我不打算继续追查下去。然而,它似乎很有前途,完全忽视它是一种浪费。
也许这更符合其他人的研究兴趣,或者也许它只是帮助激发某人有一个相关的想法。
有关我已经进行的实验、未来可能的改进以及自我评估层的其他潜在使用案例的更多信息,请查看这篇更详细的文章:
【https://floriandietz.me/neural_networks_self_assessment/ 号
自我关注和变形金刚
从关注到自我关注到变形金刚

这实际上是早先关于“ 注意力 介绍”的帖子的延续,在那里我们看到了注意力架构所解决的一些关键挑战(并在下面的图 1 中提到)。

Fig 1: From “Introduction to Attention”, based on paper by Bahdanau et al.
一个单独的上下文向量(编码器 RNN 中的最终隐藏状态,保存整个句子/输入序列的含义)的挑战通过用为每个解码器步骤生成的基于注意力的上下文向量来替换来解决,如 图 1 所示。
但是它引入了为解码器的每一步计算单独的上下文向量的增加的计算复杂性的挑战。这超出了现有的与并行化相关的挑战。即 RNNs 中所需的处理的顺序性质——假设需要隐藏状态 h1 来计算下一个隐藏状态 h2,则这些操作不能并行进行。 这两种挑战都由图 1 左半部分的红色虚线 (在图 3 中也称为 )表示。
说到顺序处理,你可能还会想,假设我们用为每个输出步骤生成的上下文向量来替换最后一个隐藏状态,我们还需要“h”状态吗?毕竟,注意力对齐应该定义给定的输出步骤应该关注输入的哪一部分,而“h”只是“x”的间接表示。它表示所有输入步骤的上下文,直到“x ”,而不仅仅是“x”。直接用“x”不是更有意义吗?
事实证明确实如此。

Fig 2: End to End Memory Networks by Sukhbaatar et al
将此与我们之前看到的基本注意力模型进行比较,就会发现“相似之处”。虽然两者之间存在差异,但“端到端记忆网络”提出了跨句子和多次“跳跃”的记忆来生成输出,我们可以借用“键”、“查询”和“值”的概念来获得我们基本模型的概括视图。 图 3 将这些概念应用于基础模型。

Fig 3: Challenges in the attention model from “Introduction to Attention” based on paper by Bahdanau et al to Transformers
图 3 还强调了我们想要解决的两个挑战。对于挑战#1,我们也许可以直接用输入(x)代替隐藏状态(h)作为密钥。但是如果我们直接使用单词嵌入,这就不是丰富的表示了。端到端的记忆网络对输入和输出记忆表示使用不同的嵌入矩阵,这更好,但它们仍然是单词的独立表示。将其与隐藏状态(h)进行比较,隐藏状态(h)不仅代表单词,还代表给定句子上下文中的单词。
有没有一种方法可以消除生成隐藏状态的顺序性,但仍然产生更丰富的上下文表示向量?

Fig 4: Sequence to Sequence with self attention — Moving from being “RNN based” to “attention only”
图 4 说明了这样做的一种可能方式。如果我们不使用注意力来连接编码器和解码器,而是分别在编码器和解码器内部使用注意力,会怎么样?毕竟,注意力是一种丰富的表示——因为它考虑了所有的键和值。因此,我们可以使用基于注意力的替换,而不是使用 RNN 来导出隐藏状态,其中输入(x)被用作“键”和“值”。(如下面的 图 5 所示,用“x”代替“h”)。

Fig 5: Self Attention
在编码器端,我们可以使用自我关注来生成给定输入步长 xi 相对于输入 x1,x2…xn 中所有其他项的更丰富的表示。与基于 RNN 的编码器中的隐藏状态生成不同,这可以对所有输入步骤并行完成。我们基本上是将 图 4 左半部分的十字交叉线向下移动,如右半部分所示,从而消除代表向量之间的红色虚线。
在解码器方面,我们可以做一些类似的事情。我们将基于 RNN 的解码器替换为基于注意力的解码器。即不再有隐藏状态,并且不再为每个解码器步骤计算单独的上下文向量。相反,我们对迄今为止生成的所有输出进行自我关注,并随之消耗整个编码器输出。换句话说,我们正在将注意力应用到目前为止我们所知道的任何事物上。(注意,变压器中绝对不会出现这种情况,变压器中对生成输出和编码器输出的关注是在两个独立的层中一个接一个地完成的)。
瓦斯瓦尼等人在论文“注意力是你所需要的全部”中介绍的“变形金刚”模型,见下面的 图 6 ,做了我们上面讨论的事情。

Fig 6: From “Attention Is All You Need” by Vaswani et al.
Transformer 模型使用“缩放点积”注意机制。它在图 6 的右侧以及图 7 中示出。比较图 7 和图 1,感受一下这两种模型在计算注意力的“方式”上的差异。(注意:“在哪里”也不同,我们将在下一步讨论)。transformer 模型还使用了所谓的“多头注意力”(Multi-Head Attention),而不是为给定的“xi”只计算一个“ai”(注意力),而是使用不同的 Ws 集计算多个注意力分数“ai”。这允许模型在不同的位置关注不同的“表示子空间”,类似于使用不同的过滤器在 CNN 的单个层中创建不同的特征地图。

Fig 7: Scaled Dot Product used in “Attention Is All You Need” by Vaswani et al.
编码器
所提出的变压器模型中的编码器具有多个“编码器自关注”层。每一层的构造如下:
- 输入将是第一层的单词嵌入。对于后续层,它将是前一层的输出。
- 在每一层中,首先使用该层的输入作为键、查询和值来计算多头自我关注。
-
2 的输出被发送到前馈网络层。这里,每个位置(即每个单词表示)都通过相同的前馈来馈送,该前馈包含两个线性变换,后跟一个 ReLU(输入向量->线性变换的隐藏 1->线性变换的隐藏 2 ->ReLU 输出)。
解码器
解码器也将具有多层。每一层的构造如下:
- 输入将是到目前为止为第一层生成的单词嵌入。对于后续层,它将是前一层的输出。
- 在每一层内,首先使用该层的输入作为关键字、查询和值(即,到目前为止生成的解码器输出,为其余位置填充)来计算多头自我关注。
-
2 的输出被发送到“多头-编码器-解码器-注意”层。这里,使用#2 输出作为查询,使用编码器输出作为键和值,来计算另一个注意。
-
3 的输出被发送到类似编码器中的位置式前馈网络层。
虽然摆脱顺序性在很多方面都有帮助,但它有一个关键的优势——知道单词在输入序列中的顺序。如果没有它,出现在同一个句子中不同位置的同一个单词可能会以相同的输出表示结束(因为它将具有相同的键、值等)。因此,该模型使用“位置编码”——基本上是一个表示位置的向量,它被添加到编码器和解码器堆栈底部的输入嵌入中。Shaw 等人的另一篇论文在这里提出了一种基于相对位置的替代方案,它比原始 Transformer 模型论文中建议的绝对位置编码实现了更好的结果——如果您能花时间在位置嵌入上,我建议您研究一下。
希望这在某些方面有所帮助。
计算机视觉中的自我注意

自从引入 Transformer networks,深度学习中的注意力机制在机器翻译和 NLP 社区中非常受欢迎。然而,在计算机视觉中,卷积神经网络(CNN)仍然是标准,自我关注刚刚开始慢慢进入研究的主体,要么补充现有的 CNN 架构,要么完全取代它们。在这篇文章中,我将试图阐明视觉自我关注的最新发展,并强调其可能的好处。对于这项任务,我将提交三篇不同的论文(包括一篇被即将举行的 NeurIPS 2019 会议接受的论文),在我看来,这些论文很好地说明了计算机视觉中自我关注的最新水平。
我将提交的第一篇论文由 Guan 等人1撰写,来自医学图像分析社区,这是我的家。与自然图像(照片)不同,医学图像通常在外观上非常相似。它们是使用相似的采集参数从标准化位置采集的。对于放射科医生来说,阅读图像的经验主要来自于知道准确地在哪里寻找,以便找到某种病理。因此,毫不奇怪,注意力在医学图像分析中扮演着重要的角色,甚至比其他研究领域更重要。
该论文试图提高胸部 X 射线图像上自动胸部疾病分类的性能。以前,已经提出了仅通过查看全局图像来检测和分类胸部 X 射线上的病理的网络。因此,通过使用二进制交叉熵** (BCE)作为损失函数或一些其他标记机制(例如,编码器-解码器框架使用 LSTM 作为解码器来捕获标签之间的相互依赖性2)来执行多标签分类。使用整个 X 射线图像进行分类的问题在于,在医学图像中,与整个图像相比,病变区域可能非常小,甚至可能位于沿着边界的某处,导致分类器的大量噪声并降低检测精度。此外,胸部 X 射线图像经常会出现错位(例如图 1 第二行中的例子)。这种未对准导致图像周围的边界不规则,并且还可能对分类产生负面影响。**
在论文中,作者使用递归硬注意(即硬自我注意)来提高检测精度,方法是裁剪掉图像的有区别部分,并将全局图像和裁剪部分分类在一起(左侧的整个图像和右侧的裁剪部分见图 1)。

Figure 1: Two training images from 1 including heatmaps extracted from a specific convolutional layer in the network in as well as the resulting cropped image. Both the global and the cropped image are used for classification.
该网络由三个分支组成:
- 全局分支处理整个图像并确定裁剪 ROI,
- 局部分支展现注意机制,处理裁剪后的图像,
- 融合分支连接全局和局部分支的汇集输出,并使用密集层执行最终分类。
所有分支都是分类网络,最终执行多类分类(如图 2 所示)以预测病理的存在。除了分类之外,全局分支还用于生成确定裁剪区域的热图。热图是通过对某个高级层上通道的最大值进行计数而生成的。则生成与热图大小相同的遮罩。如果在某个位置 (x,y) 的每通道最大化热图的值大于某个阈值,则在该位置掩码被分配为 1。否则,掩码的值将为 0。然后,确定裁剪区域,使得所有掩码值为 1 的点都在裁剪区域内。然后,图像的裁剪部分通过局部分支运行。此外,两个分支的输出在融合分支中融合,以执行附加分类。
网络分三步训练:
- ImageNet 预训练的全局分支的微调。
- 屏蔽推断以获得裁剪的图像并执行局部分支的微调。因此,全局分支中的权重是固定的。
- 连接全局和局部分支输出以及微调融合分支,同时冻结其他分支的权重。
融合分支用于产生模型的最终分类结果,因为它比其他两个分支执行得更好,正如预期的那样。

Figure 2: Architecture of the AG-CNN presented in 1 with a ResNet-50 backbone as an example. The local lesion patch is cropped from the global image using the heatmap (attention) layer. BCE represents binary cross-entropy loss.
为了从注意力的角度理解这个模型在做什么,我们必须首先知道软注意力和硬注意力之间的区别。本质上,注意力根据一些外部或内部(自我注意)提供的权重对网络的某些特征进行重新加权。因此,软注意允许这些权重是连续的,而硬注意要求它们是二进制的,即 0 或 1。这个模型是硬注意的一个例子,因为它裁剪了图像的某个部分,因此本质上是重新加权原始图像,使得裁剪部分的权重为 1,其余部分的权重为 0。
hard attention 的主要缺点是不可微,不能端到端训练。相反,作者使用某一层的激活来确定 ROI,并在复杂的多阶段过程中训练网络。为了训练注意门,我们必须使用软注意(例如使用 sigmoid 或 softmax)。接下来我们将看看一些软注意模型。
压缩和激励网络
胡等人3没有使用硬注意,而是根据特征图的裁剪来重新校准权重,而是通过使用软自注意来模拟卷积特征的通道之间的相互依赖性,对 CNN 的某一层中的通道式响应进行重新加权。为此,作者引入了挤压和激励模块(见图 3)。

Figure 3: Squeeze-And-Excitation block presented in 3.
挤压和激励块工作如下:对于从 X 到 U (例如卷积),的特征 F_tr 的任何变换,存在聚集跨空间范围的全局特征响应的变换F _ sq(H, W )。这是挤压操作。挤压操作之后是激励操作 F_ex ,这是一种自门控操作,可构建通道权重响应。 F_tr 的输出随后按通道乘以激励结果(这在图 3 中表示为 F_scale )。挤压操作的数学描述是

因此 u_c 是运算 F_tr 的输出。挤压操作通过使用全局平均池创建全局嵌入。也可以使用全局最大池,尽管作者指出平均池会略微提高整体性能。另一方面,激励模块描述如下

因此,激励将挤压块的输出乘以学习到的权重 W1,将输出通过 ReLU 函数 δ ,将输出乘以另一组权重 W2 ,并在最后使用 sigmoid 函数以确保得到的通道权重为正。据此, W1 通过因子 r (可视为超参数)降低维度,而 W2 再次将其增加到原始通道数。最后,F_tr 的信道特征响应乘以从激励块获得的权重。这可以被视为使用全局信息的通道上的自我关注功能。
挤压和激励模块背后的主要思想是在网络的决策过程中包含全局信息;卷积只查看某个半径内的局部空间信息,而挤压和激发模块聚集来自整个感受野的信息。作者的一个有趣的观察是,在网络的早期阶段,不同类别的激励权重相对相似,在后期阶段变得更加具体。这与通常的假设相关,即较低层学习输入的更多一般特征,而较高层的辨别能力越来越强。此外,挤压-激励模块在网络的最后一级没有太大意义,因为大多数激励变为 1。这可以通过以下事实来解释,即网络的最后一级已经包含了大部分全局信息,并且没有通过挤压和激励操作引入新的信息内容。
挤压和激励方法的主要优势是它非常灵活:作者提到了在广泛使用的架构中的集成,如 ResNet(见图 4)、Inception 或 ResNeXt。在实践中,该块可以被添加到网络的每一级,或者只是在特定的级。此外,在可学习参数的数量方面,它只引入了一点点开销。例如,与已包含 2500 万个参数的原始 ResNet 相比,使用挤压和激励模块的 SE-ResNet-50 仅使用了约 250 万个附加参数。因此,这仅增加了 10%的复杂性。**

Figure 4: The original ResNet block (left) and the Squeeze-And-Excitation ResNet block (right) as presented in 3.
在该论文中,作者给出了通过挤压和激励块增强的训练结构的大量例子。特别是,他们能够在 ILSVRC 2017 挑战赛中实现最先进的分类性能,前 5 名的误差仅为 2.251%。
独立的自我关注
我将提交的最后一篇文章是 NeurIPS 2019 提交的文章,它通过使用独立的自我关注模块,而不是仅仅通过自我关注来增强卷积层,将 CNN 中的自我关注概念进一步发展。事实上,作者提出了一个自我注意层,它可以用来代替卷积,同时减少参数的数量。
让我们回顾一下卷积运算来激励替换。卷积运算包括在位置 (i,j) 将一定大小(例如 3×3)的权重矩阵与每个邻域相乘,并在空间上对结果求和。这使得不同空间位置之间的重量分担成为可能。此外,权重的数量与输入大小无关。
与卷积类似,论文提出的自我注意层也作用于 (i,j) 周围的一个小邻域,称为记忆块。对于每个内存块,单头注意力计算如下:

因此, q_ij=W_q x_ij 是查询, k_ab=W_k x_ab 是关键字, v_ab=W_v x_ab 是从位置 (i,j) 及其邻域处的特征作为线性变换计算的值。矩阵 W 是学习转换。从公式中可以看出,变换后的中心像素 x_ij 用作查询,在邻域内对键和值求和。softmax 函数也应用于 logits,以获得权重,然后乘以这些值。如果你不知道查询、键和值是什么,那就看看这篇文章。作者在本文中使用了多头注意力,简单地说就是将像素特征沿深度方向分成大小相同的 N 组,用不同的矩阵 W 分别计算每组的注意力,并将结果连接起来。图 6 提供了视觉自我注意块的图形描述。

Figure 6: Local attention layer with spatial extent k=3 in [4].
使用上述方法的一个问题是,在关注块中没有编码位置信息,因此该公式对于各个像素的排列是不变的。位置信息对于视觉任务很重要:例如,如果你想检测人脸,你需要知道哪里可以找到嘴、鼻子、耳朵等等。在最初的 transformer 论文[5]中,作者使用位置的正弦嵌入作为附加输入。然而,在[4]中,相对 2D 位置嵌入被使用,因为它们对于计算机视觉任务具有更好的准确性。这些相对嵌入通过计算位置 (i,j) 到每个邻域像素 (a,b) 的相对距离来获得。这些距离分为行和列距离 r_a-i 和 r_b-j 。这些嵌入被连接成矩阵形式,并乘以查询 q_ij ,如下所示:

这确保了由 softmax 函数计算的权重受到键和查询的距离和内容的调制。
从上面的描述我们可以看出,视觉自我注意是局部注意的一种形式。注意层只关注内存块而不是整个特征图。这种方法的优点是参数的数量大大减少,并且不同空间位置之间的权重是共享的。作者提到,他们的自我注意网络在训练和推理方面仍然比他们的 CNN 同行慢,但是他们将此归因于高度优化的卷积核以及注意力层缺乏优化的硬件。
作者还介绍了他们在 ImageNet 上通过用他们的自我注意块代替 ResNet 中的 3×3 卷积而获得的一些结果。请注意,它们保留了 1x1 卷积(基本上是按像素计算的全连接层)和卷积干(网络中的前几个卷积层)不变。有了这些变化,它们在所有测试架构(ResNet-26、ResNet-38 和 ResNet-50)中的表现都优于基准(标准 ResNet ),同时使用的触发器和参数减少了 12%和 29%。
参考
1关,庆吉,等.“像放射科医生一样诊断:注意力引导卷积神经网络在胸部疾病分类中的应用” arXiv 预印本 arXiv:1801.09927 (2018)。
2姚,李等,“利用标签间的依赖关系从零开始学习诊断” arXiv 预印本 arXiv:1710.10501 (2017)。
3胡、杰、、。"挤压和激励网络."IEEE 计算机视觉和模式识别会议论文集。2018.
[4] Ramachandran,Prajit 等,“视觉模型中的独立自我注意” arXiv 预印本 arXiv:1906.05909 (2019)。
[5]瓦斯瓦尼、阿希什等人,“你所需要的只是关注。”神经信息处理系统的进展。2017.
自动驾驶汽车—本地化
自动驾驶汽车如何知道自己在任何给定时间的位置?

Image by Pixabay
一直让我着迷的人工智能项目之一就是自动驾驶汽车。这是我学习更多深度学习和人工智能的主要动机。
自动驾驶汽车要实现其他功能,最重要的事情之一就是本地化。不仅是自动驾驶汽车,移动机器人也要先预测它在哪里。自动驾驶汽车的所有其他功能都取决于它的真实位置。在本文中,我们将尝试找出如何使用蒙特卡洛定位来预测汽车的位置。
知道物体或汽车位置的一种方法是使用 GPS。通过打开智能手机中的 GPS 服务,我们可以在卫星的帮助下轻松地看到我们在世界上的位置。但是使用 GPS 作为定位工具有一个问题。GPS 的不确定性接近 10 米。如果一辆自动驾驶汽车有这么大的误差,它很可能会撞上路边的一座建筑,认为它是道路的一部分。因此,自动驾驶汽车使用摄像头、激光、红外传感器来识别其在已知路线图上的位置
为了便于理解,让我们考虑一辆只做 1D 运动的汽车,它的世界由红色和绿色方块组成。

Figure 1: World consists of blocks of the green and red color [image by author]
一开始,当汽车没有用传感器从环境中获取任何数据时,它不知道自己在哪里。所以不确定性的程度是最高的,它不知道它在哪里。如果我们试着画出它所在位置的概率分布,它会是这样的:

Figure 2: Probability of the car to be in block i (1,2,…,6) [image by author]
在这里,我们可以看到每个位置都有 0.167 的概率。这意味着汽车可以在 6 个街区中的任何一个。
现在让我们假设传感器已经进行了一次测量,它以 80%的把握感知到了绿色(由于传感器误差,测量有时可能是错误的)。那么你现在会相信你的车在那些绿色街区的前面。因此,我们将 0.8(确定性)乘以与我们的测量相匹配的块的先验概率。在块颜色与测量颜色不匹配的情况下,我们将先验乘以 0.2。归一化后,概率分布如下所示:

Figure 3:Probability of the car to be in block i (1,2,…,6) [image by author]
测量后,你的信念改变了,现在你相信你在绿色方块前的概率(0.2672)比在红色方块前的概率高。红色块仍有一些剩余概率(0.0668)。这是因为你的传感器不是 100%准确。所以有很小的可能是你的传感器出错了,而你实际上是在一个红色方块的前面。这些小概率用图表表示。如果传感器是 100%准确的,你将绝对肯定你是在一个绿色块的前面,红色块的概率将是 0。
上述计算基于贝叶斯法则。
在感知颜色之前,我们有一个先验概率分布 P(Xi) →图表中表示的每个块的概率。在我们进行测量后,我们有把握地感觉到了颜色。P(Z | Xi)=0.8 →如果我们在块 Xi 中,感知正确颜色的概率是 0.8,这对于所有具有与测量颜色匹配的颜色的块是恒定的。对于具有不同颜色的块,其值为 0.2(对于不同的传感器可能不同)。因此,进行测量后的后验概率是 P(Xi | Z)=进行测量 Z(感知颜色)后处于位置 Xi 的概率→ P(Xi)* P(Z | Xi)
我们正是这么做的。我们随后将这些值标准化,使总概率等于 1。
现在考虑运动。我们假设这是一个循环的世界。如果一辆车从第六个街区向右移动,它会停在第一个街区。汽车是借助运动的机械部件运动的,这也有不确定性。让我们假设汽车一次移动一个街区,它的移动确定性为 0.9。这意味着,如果它试图移动一个街区,有 90%的可能性它实际上移动了期望的一个街区,有 10%的可能性它从未移动并停留在当前位置。
如果运动是 100%准确的,向特定方向移动将意味着概率分布也将向该方向移动一个街区。

Figure 4: Probability of the car to be in block i (1,2,…,6) [image by author]
这里我们假设世界是圆形的。所以当我们绝对确定地移动时,我们的概率分布向那个方向移动。原因是,如果目前很可能在第四街区发现汽车,那么在向右移动一定距离后,很可能在第五街区发现汽车。所以概率分布随着运动而变化。
但是如果我们没有 100%确定的运动,那么我们就必须使用全概率来预测运动后的最终概率分布。在运动之后,一个块的概率分布可能来自它的前一个块,确定性为 0.9,如果汽车根本没有运动,当前的分布也可能不变,确定性为 0.1。所以新的概率分布是这两个的加权和。
P(Xi)= P(Xi-1)P(动议)+P(Xi) P(暂停)
因此,如果我们以 0.9 的概率移动,那么概率分布应该是:

Figure 5: Probability of the car to be in block i (1,2,…,6) [image by author]
这里我们可以看到,现在的分布更为分散。我们可以很容易地注意到,在每次测量后,不确定性水平下降,但在运动后,不确定性水平增加或保持不变。
现在让我们进行多次测量,并测量我们是否能在这种方法中实际确定我们的位置。

Figure 6: 1D world comprising green and red blocks [image by author]
让我们从自动驾驶汽车的角度来思考。
动作:
1.它感觉到一个绿色的障碍物
2.它向右移动一个街区
3.它感觉到红色
4.它移动了一个街区
5.它感觉到红色
6.它不动
7.它感觉到红色
8.它向右移动一个街区
9.它感觉绿色
10.它移动了一个街区
现在告诉我,根据先前的行动,这辆车现在可能在哪里?
是的,现在应该在第五街区。让我们看看计算显示了什么。
根据动作,测量向量=['绿色,'红色','红色','红色,'绿色']
运动矢量=[1,1,0,1,1]
我写了一个代码(下面给出了链接),如果你把这些向量,它会给你概率分布。
代码链接:https://github . com/ishtiakm/self _ driving _ car/blob/master/senseandmov1d . py

Figure 7: The probability of the car being in each of these blocks
概率分布在第 5 块最大。

Figure 8: Probability of the car to be in block i (1,2,…,6) [image by author]
经过多次测量后,赛车对自己的位置非常确定,我们可以看到它的预测与我们的相符。
上述方法实际上是自动驾驶汽车在现实世界中识别其位置的核心算法。在现实中,世界不仅是绿色或红色的,运动也不是一维的。真实世界引入了更多的噪音和更不利的情况,如雨、雪等。但是我们在这里学到的算法保持不变。汽车已经从谷歌地球上知道了它的“世界”列表(见代码)。它的相机拍摄图像,并将其用作测量。在匹配这两个之后,它更新它的概率分布,并了解它在哪里以及它是否在车道的右侧。
这个逻辑也可以在具有绿色和红色块的 2D 世界中实现。尝试通过为 1D 编辑给定代码的 1D 函数来实现它。下面也给出了 2D 世界代码的链接。但是试着自己实现,自己摆弄。我向你保证这是相当惊人的。
代码链接:https://github . com/ishtiakm/self _ driving _ car/blob/master/senseandmov1d . py
印度道路上的自动驾驶汽车
计算机视觉引导的深度学习网络&机器学习技术打造全功能自动驾驶汽车。
“如果你认识到自动驾驶汽车可以预防事故,人工智能将有助于减少世界上主要的死亡原因之一。” —马克·扎克伯格

Cartoon Courtesy: http://www.cartoonistgroup.com/store/add.php?iid=169867
如果像优步& Ola 这样的按需乘车服务已经在运输理念上进行了一场革命,那么自动驾驶汽车将是下一个撼动整个运输行业的复兴。这个新想法正在成为价值数万亿美元的生意,比亚马逊和沃尔玛加起来还要大。据世界经济论坛称,汽车行业的这一巨大飞跃将通过减少车祸数量、减少紧急服务需求、节省工时、降低汽车拥有成本&每年带来 3.1 万亿美元的收入,同时还能通过缩短通勤距离和减少碳排放间接节省成本。
最重要的是,一旦你不再需要方向盘和司机,就有无限的设计可能性。汽车可以是小巧的蛋形或箱形的活动房屋,它们提供的不仅仅是移动性。截然不同的汽车设计意味着截然不同的道路。道路本身可以建议一条更快、更安全的路线,嵌入车辆和基础设施中的智能设备可以即时通信以适应交通。
自动驾驶汽车比赛中值得注意的参赛者是:
- 特斯拉
- Waymo
- 巡航
- Mobileye
- 福特、通用等。
特斯拉的 Autopilot 和英特尔的 Mobileye 的一些版本使用高度可信的视觉,基于摄像头的自动驾驶技术,与激光雷达(LIDAR)技术相反。
视觉技术,
- 能在环境下工作,激光雷达不行。恶劣的天气
- 比激光雷达便宜多了
- 对车辆设计不那么突兀。
但是为了让它工作,视觉技术需要巨大的计算能力来处理所有的视觉数据。这就是人工智能算法发挥作用的地方。在这个项目中,我使用了以下人工智能子领域来解决汽车的单个功能,以建立一个功能齐全的汽车。
来预测,
- 转向角度:采用深度学习
- 加速和刹车:计算机视觉&深度学习
- 齿轮和离合器:使用机器学习
Self Driving System in Action. All Controls are driven by ML/ DL Prediction.
这个项目的源代码可以在 这里找到
数据收集
有几个公开可用的驾驶数据集,但是每个数据集都有这样或那样的缺点,如下所示:
a) Sully Chen 的驾驶数据 (25 分钟)
- 仅包含转向角作为参数
- 需要更多的参数,来建造一辆功能齐全的汽车
b) Comma.ai 研究数据 (7 小时)
- 包含转向、加速和制动。没有“齿轮”数据。图像质量较差
- 他们的大部分驾驶数据都是在车道分离的高速公路上,那里弯道很少,车辆也少,这与印度的道路相反。
c)百度的appolo 开放平台(巨大)
- 包含所有复杂的激光雷达和 3D 数据
- 庞大的数据库:庞大得不合理要在 PC 上处理
所有可用的开放数据集都记录在西方设置中,那里的车道很宽,标志&分隔线也很清晰。但是对于人工智能算法来说,印度的道路比西方的道路更难,因为没有足够的印度路况数据。因此,在西方数据集上训练的算法在印度条件下可能表现不佳。
上述数据集都不适合在个人电脑上制造一辆功能齐全的汽车。此外,我很好奇人工智能算法如何在印度环境中工作。因此,我决定录制自己的视频。首先,我把一部 iPhone 挂在车外的挡风玻璃上,沿着印度狭窄弯曲的道路行驶。为了录制视频,我试图使用 Nexar AI dashcam 应用程序,但我的尝试失败了,因为它会自动检测并只存储碰撞帧。然后,我使用 iPhone 内置的录像机,沿着多条线路行驶了大约 1-1.5 小时。

External mounted dash-cam to record driver view video
但是录制的视频不足以训练一个自动驾驶系统。为了制造一辆功能齐全的汽车,汽车驾驶员在驾驶时提供的所有基本输入,即必须预测转向角、加速度、制动、离合器和档位。因此,训练数据也需要具有所有这些参数。
汽车控制台界面
为了记录驾驶时的转向角,我们可以使用汽车的车载诊断系统,以每毫秒一次的速度找到转向角。同样,我们可以破解汽车的机械和电子设备,以获得其他参数,如加速度,制动,离合器和齿轮等。作为一个生成训练数据的黑客,在不篡改汽车 OBD 的情况下,我用 Python 编写了一个汽车控制接口,记录来自键盘的扫描码。这个界面是用来模拟驾驶的,就像你用键盘玩电子游戏一样。
录制的视频和控制台界面是并排运行的,所以我可以使用箭头键来模拟在录制的视频中看到的驾驶。在驾驶模拟过程中,使用了七个关键控件来计算参数:
向上和向下箭头:加速&刹车
左右箭头:方向/转向角度
‘a’:升档
‘z’:降档【T8’‘g’:空挡

Car Console Interface & Recorded Video running side-by-side. Input from keyboard is driving all the console controls (Left) based on the turns and traffic in recorded video (Right)
接口程序将视频中每一帧的转向角、加速度、制动和档位值写入输出文件。如果视频以 30 fps 的速度录制,则必须每隔 1000/30 = 33 ms 循环写入参数值。要获得这种准确性有点困难,因为它取决于写入输出的“while”循环的执行时间。您可能需要每 30–33 毫秒写一次,才能与以 30 fps 录制的视频正确同步。将“写入频率”视为超参数,因为它取决于机器速度。您可以通过进行 1 分钟的驾驶模拟来调整写入频率,并检查它离 60x30 = 1800 帧有多远。在下面的代码中,您可以以纳秒级的精度调整“writeFrequency”参数。
Car Console Interface in Python
数据预处理
自我录制的驾驶视频需要一些预处理步骤,然后才能传送到网络。按顺序使用以下软件:
a) 无损剪切 —无损剪切相关视频。
b) 随时视频转换器 —调整视频大小以减少数据。
c) 视频到 JPG 转换器 —从视频中提取帧。
使用汽车控制台界面生成的提取视频帧和相应驾驶控制参数的印度驾驶数据集上传到 Kaggle 。提取的帧与相应的参数值(由模拟器生成)一起输入卷积神经网络进行训练。
如果你想使用一个开放的数据集,你必须写一个程序来解析给定的文件格式。下面的解析器代码读取. h5 文件,以及来自 comma.ai 数据集的参数值。上述预处理步骤,例如“帧尺寸调整”可以在下面的解析器代码本身中实现。
Parser code for .h5 files in comma.ai
模型构建
到目前为止,我们已经有了包含帧图像和相应参数值的训练数据集,即转向角、加速度、制动和档位。
为了从图像中预测转向角度,我们可以使用深度学习(CNN)或计算机视觉技术。这两种方法的可行性将在后面的章节中进行分析。但是即使是人,也不能从单个帧中预测刹车或加速。因此,这种帧反馈 CNN 模型不足以预测加速度或制动参数,因为我们遗漏了一个重要信息,即帧的“序列”。
为了解决“序列”问题,我们可以使用
- 复杂的 CNN-RNN 架构
- 计算机视觉辅助技术。
我们选择了 CV 技术来量化“序列”信息,因为它可以很容易地从记录的视频中计算出来。这种量化值用于辅助加速和制动预测。可以根据所有剩余参数预测档位,即转向、加速、制动&序列信息。因此,使用了机器学习技术。离合器可以很容易地根据档位计算出来。
a)转向角预测
为了预测转向角度,CNN 网络有大量的信息可以学习,例如车道线的角度、道路的曲率、标志牌、其他车辆和行人的转向角度、道路中间分隔带的曲率等。此外,还有计算机视觉技术来寻找道路上车道线的角度,这反过来有助于决定转向角度。下面我们介绍两种方法来分析更好的西装。
# 使用霍夫变换
为了估计所需的转向角度,可以对提取的帧应用霍夫变换,以使用 OpenCV 找到“车道线”的系数& theta(由 Github 项目提供)
图像处理步骤的顺序如下所示:

1. Input image 2. Greyscale 3. Gaussian Blur, 4. Canny Edge Detection 5. Mask 6. Hough lines 7. Lane Lines
霍夫变换可以帮助从图像中的点扩散估计线条。

Hough Transformation Implementation for Polygons
边缘检测后断开的车道线也可以通过分析累加器阵列的蝶形宽度来检测,如下所示:

霍夫空间中正弦波的交点将给出待估计的线的参数 。对于每一帧,估计车道线的角度将有助于确定转向角度。在下面的可视化中,对应于 3 条线的三个点扩散云生成 3 个正弦波,在右侧霍夫空间中有 3 个交点。

Matlab Implementation: Multiple Lane Line Detection from Edge Detected Point Spreads
但是,上述计算机视觉技术不适合制造我们的自动驾驶汽车,因为我们想在印度道路上自动驾驶,那里可能没有车道线或分隔线这样一致的信息。因此,我们使用鞋底深度学习来预测转向角度。
# 使用深度学习模型
我们需要预测每个单独帧的转向角度。我们可以采用一组转向角和相应的帧图像来馈送 CNN 模型,并尝试最小化 MSE 训练损失。经过多次迭代和历元训练的模型,可以用来预测转向角,即使是在不平坦的印度环境中。为此,使用了英伟达用于自动驾驶汽车的端到端 CNN 架构。1

Nvidia’s CNN architecture: contains 27 million connections & 250 thousand parameters
模型可解释性:理解深度学习模型内部正在发生的事情是很重要的。对于 CNN 模型,我们可以将隐藏层可视化,以了解单个过滤器拾取的特征。
CNN Visualization Code
输入图像帧和隐藏层可视化输出如下所示:

Input Image Frame

CNN Hidden Layer Visualization for different filters
三个驾驶控制参数,即转向角、加速度和制动在不同的车型上进行训练,并在运行时同时执行以驱动汽车。训练一个控制参数的代码如下。
To Train the ‘Acceleration’ control variable. Similar training is done for Steer & Brake.
b)加速和制动预测
由于加速和刹车固有地依赖于视频中的帧序列,我们借助计算机视觉来预测这两个参数。
光流表示由观察者和场景之间的相对运动引起的场景中物体和边缘的明显运动。在录制的视频中,我们可以分析强角点的光流,通过先前的帧来估计未来的帧流。

Visualization of Sparse Optical Flow along narrow Indian roads
假设在第(n-1)和第(n-2)帧中有“k”个强角,其中“n”是当前帧。比方说在拐角处,c 从一帧移到下一帧。光流可以通过对先前帧中所有角点的距离偏移求和来量化。
但是,已经发现该和将与检测到的角点数量成比例地平方增加。此外,和将沿着曲线急剧增加,因为帧中的像素将从左向右或从右向左移动。
基于上述逻辑,下面的等式已经根据经验计算出来,以量化来自光流的加速度。

Steering Angle is in Degrees
下面的 python 程序分析记录的视频&计算视频中每个相邻帧的光流参数‘gamma’并输出到文件。
由于计算的光学参数值是无界的,应用 sigmoid 函数或双曲线正切函数来挤压这些值。由于 tanh 将所有正值限制在 0 & 1 之间,而 sigmoid 的范围是 0.5 比 1,所以 tanh 成为我们的自然选择。挤压量可通过“alpha”参数进行调整,如下图所示。

基于“伽马”值的分布,我们可以决定“阿尔法”值以匹配记录的加速度值的分布,然后乘以最大加速度值,以从 0 到 1 进行缩放。在这种情况下,我们计算出 alpha = 0.18 以避免在双曲正切曲线的渐近端出现任何 gamma 值。

Here, alpha is denoted by delta symbol
结合这两个值来预测加速度和制动值。

当汽车行驶时,计算来自仪表板摄像头视频的光流值,并且上述计算是在运行中完成的,以预测加速度和制动。上述公式的实现在下面的并发执行部分。
为了计算上述等式中的“DL 预测”,使用了受著名的 LeNet 架构启发的 3-卷积层模型。因此,对于 steer 来说,NVidia 端到端 CNN 架构以及对于 Accel 和 Brake LeNet 来说,受启发的架构与光流参数特征相结合。
不同模型的原型制作在 Keras 中完成,如下所示。

LeNet Architecture
LeNet-inspired 3-Convolution Layer Architecture in Keras
c)齿轮和离合器预测
档位不依赖于单个帧图像,而是所有参数的组合,即转向角、加速度、制动&也是序列信息。因此,我们可以使用机器学习算法,使用上述参数作为输入特征来预测因变量“齿轮”。
我们知道基于树的最大似然算法在特征较少时表现更好,就像在这种情况下。在尝试了逻辑回归、朴素贝叶斯、GBDT 等多种算法后,发现 RandomForest 给出了最大的准确性。自动驾驶汽车只有在最后“n”帧的档位预测相同时才会换档,而不是依赖于单个帧的档位预测,。换档时离合器可以轻松计算。
RandomForest Algorithm to predict gear of last ’n’ frames.
并发模型执行
转向、加速、制动和档位模型在不同的会话中同时执行,并带有相应的计算图表,以预测每一帧的所有驾驶控制值。
Concurrent Execution of all models at Run-time
预测输出
下面的汽车正在根据 dash-cam 视频输入进行自动驾驶。它可以很好地处理新曲目,在训练网络时看不到。

All the controls are guided by prediction
该项目的源代码可以在 这里 找到
结束语
想象我们的世界拥有自动驾驶汽车的所有优势,这似乎不亚于一部科幻电影,其中无人驾驶的摆渡物体(UFO)正在我们的道路上蜿蜒前行。对普通大众来说,可能是《爱丽丝梦游仙境》。
但是今天的仙境可以在未来变成令人惊叹的现实,那时人类驾驶汽车将会是一个故事,由老奶奶们讲给他们的孙子们听。但要实现这一点,它必须通过所有的障碍,即伦理,技术和后勤,成为一个现实世界的乌托邦。例如,基础设施需要彻底检修,技术应该处理所有极端情况,特别是在崎岖的印度道路上,以防止类似优步的事件发生。
西北大学教授 Jeremy P Birnholtz 说,“人的变化很慢,技术的变化很快”。人类和自动驾驶汽车相互适应的效率如何,最好留给时间来检验。
人类驾驶汽车的能力如此之差,以至于计算机不必好到比人类好太多~马克·安德森
参考
1马留什 b,达维德 D,丹尼尔 D 等。艾尔。、(2016) 自动驾驶汽车端到端学习。检索自 Arxiv: 1604.07316v1 [cs。简历]
2菲利普·f·阿列克谢·d·等人艾尔。,(2015) FlowNet:用卷积网络学习光流。检索自 Arxiv:1504.06852 v2【cs。简历]
3 Abdoulaye S .,Eric A .,(2013) 扩展标准霍夫变换用于分析线识别。检索自 IJACSA)国际高级计算机科学与应用杂志,2013 年第 4 卷第 3 期。
这份英伟达论文的 TensorFlow 实现:有一些变化的 https://arxiv.org/pdf/1604.07316.pdf…
github.com](https://github.com/SullyChen/Autopilot-TensorFlow) [## 自动驾驶汽车将如何重塑我们的世界
自动驾驶汽车只是拼图的一部分。前纽约市交通专员塞缪尔·施瓦茨(又名…
www.wsj.com](https://www.wsj.com/articles/how-autonomous-vehicles-will-reshape-our-world-1539871201) [## 应用课程
应用机器学习课程研讨会案例研究
www.appliedaicourse.com](https://www.appliedaicourse.com/)
自动驾驶汽车:更大的道路安全,更少的隐私
他们应该减少道路伤亡,但他们还需要什么?

汽车是当今最普遍的交通工具。他们提供舒适,自由,可用性,各种各样的费用和一个微小的,但不是微不足道的被卷入事故的可能性。
伤亡人数正在减少,然而汽车仍然是最致命的交通系统之一,仅次于摩托车。根据世界卫生组织的数据,它们也是一个难以承受的经济负担,占每个国家 GDP 的 1%到 3%。
政府和汽车制造商正在共同努力,努力大幅降低这一比率:例如,欧洲联盟委员会制定了若干战略,其中包括合作智能交通系统,重点是减少人为错误和创造环境友好型解决方案。
根据 2017 年道路安全初步统计数据,2017 年的死亡人数比 2010 年减少了 20%,比 2016 年减少了 2%。委员会发布了 2010 年至 2020 年道路交通死亡人数减半的目标,设定了一些目标2,但不幸的是,这些目标并没有实现,这意味着实现这一目标将具有挑战性。

Photo by Denys Nevozhai on Unsplash
我们如何提高道路安全?
大量的努力和资源对于提高道路安全至关重要,行业已经提出了大数据和自动驾驶汽车等解决方案。既然大多数车祸都是由于人为因素而不是太多技术故障,那么用软件代替人为因素听起来就顺理成章了。
可能的解决方案:无人驾驶汽车
第一个挑战是建立一个能够比最好的人类司机更好地感知道路的自动驾驶系统,这不会很快发生。目前的地图也不够精确。但是自动驾驶是什么意思呢?
简而言之,汽车自治有 5 个级别:
- 0 级车没有自动化功能,
- 第三级意味着人类和机器之间的交换,根据研究,这是最致命的级别3。
- 在 5 级[4]的所有条件下,车辆完全自动驾驶。
- 截至 2018 年,市场上最先进的汽车都在 2 级的中途。
当前的自动驾驶汽车配备了内部和外部传感器、激光雷达单元、摄像头和强大的软件,包括驾驶员的语音和手势识别、语言翻译和强化学习算法[5]。汽车通过捕捉附近物体的大小和速度的数据并预测可能的变化,不断渲染封闭的环境。该算法的主要任务可以分为目标检测、识别、定位和运动预测。
在强化学习算法中,奖励被分配给某些结果,推动算法学习相应的行为。数据越多,算法更新其参数以实现奖励的精度就越高。
因果关系是这样的:自动驾驶汽车收集的数据越多,算法就越强大,适应性越强,事故就越少。
然而仅仅收集数据是不够的;道路、环境和人类司机的行为可能会有很大的不同,这取决于该地区是城市还是农村、特定国家的习俗和非书面法律。
因此,用尽可能多的不同数据来训练这些汽车是必不可少的。下面的困境出现了:需要多少数据?自动驾驶汽车什么时候可以被允许上路?
在开发和测试的哪个阶段,我们可以允许汽车上路?
兰德研究所的高级研究人员认为[6],在制造商能够确认它们在统计上与人类驾驶员一样安全之前,自动驾驶汽车需要行驶很长的距离。
他们提出了这样一个问题:“对人们来说什么是重要的,他们希望他们比人类司机更安全吗?这个答案会随着时间而改变吗?”。制造商需要的数据量取决于公司对风险的厌恶程度,以及对公众的信任程度。
最佳切入点是一个有争议的话题[7]:
比起机器犯的错误,人们更能接受其他人犯的错误,即使机器总体表现比人好[8][9]。
在寻求减少死亡事故的过程中,自动驾驶汽车必须面对创建和维护地图、掌握复杂的社会互动、应对恶劣天气条件以及应对网络攻击的挑战[10]。
数据保密
考虑到汽车和私人公司将知道司机最常去的地方,并可能(并将)建立客户偏好和习惯的档案,隐私和数据保护问题不容忽视。
如今,理论上没有人知道汽车在哪里。如果乘客随身携带他们的手机并激活定位服务,操作系统可以跟踪他们的位置,知道他们移动的速度以及他们何时/何地停下来。但其他的就不多了。
在涉及更多软件和互联网连接的汽车中,用户可以发出语音命令,已经有一些软件公司在处理语音命令。当然,这些公司非常重视隐私,但已经存在数据泄露的风险,即使这种风险很小。亚马逊 Echo 设备已经出现了一些数据隐私问题。
在自动驾驶汽车中,用户将他们的生活和隐私交给了一家软件公司,这是对已经存在几十年的传统汽车制造商的一大飞跃。例如,优步只有 10 岁。也许明智的做法是警惕我们信任谁来驾驶我们。
自动驾驶汽车背后的技术监管等其他问题存在争议,但超出了本文的范围。
哪些公司领先?
当进入竞争激烈的自动驾驶汽车行业时,有三家公司处于前列,即谷歌、特斯拉,最近还有优步。
谷歌每周收集 15000 英里的自动驾驶里程,迄今为止在美国已经积累了 170 万英里的自动驾驶里程[11],与欧洲不同,美国的死亡事故正在增加[12]。美国人在致命事故发生前行驶了 1 亿英里;因此,按照目前的速度,谷歌需要数年才能行驶同样的距离。
特斯拉,另一方面,有一个不同的方法。通过使用他们的“自动驾驶模式”,特斯拉已经行驶了 13 亿英里[13],其中汽车由人类在自动驾驶模式下驾驶。尽管如此,将顾客作为试驾者也有缺点,正如少数有争议的致命车祸所显示的那样。
优步最初是一家拼车公司,现在已经迅速转向送餐和自行车共享,以及他们自己的无人驾驶汽车,甚至有一段时间还有无人驾驶卡车。在一系列事故之后,优步继续在匹兹堡[15][16]和多伦多[17]测试他们的赛车(低速)。关于他们收集的数据的性质和数量,没有多少公开信息。他们的汽车扩展到其他城市也没有截止日期[18]。
结论
总之,自动驾驶汽车正在逐渐加入道路,这一过程可能会因公众的不情愿而推迟,但不会停止。
许多公司正在投资开发和增强他们的自动驾驶算法,在美国,主要城市的道路已经成为他们的游乐场。
随着司机习惯于驾驶自动驾驶汽车上路,后者的相关性必然会增加,完全自动驾驶和联网汽车网络的乌托邦可能并不遥远。
参考
**1: 世卫组织世界报道(2013)
【2】:欧盟自 2001 年以来的道路死亡人数
【3】:众包地图应该有助于无人驾驶汽车更安全地在我们的城市中导航(2019)
【4】:用 3D 绘制世界将让我们用增强现实绘制街道(2019)
【5】:未来自动驾驶汽车驾驶员研究
【6】:汽车的自主水平
【7】:使用深度强化学习的自动驾驶汽车在闭塞的路口导航(2018)
【8】:驾驶到安全的地方:需要行驶多少英里才能证明自动驾驶汽车的可靠性(2016)
【9】:为什么等待完美的自动驾驶汽车可能会付出生命的代价 (2017)
【12】:自动驾驶汽车的挑战与障碍(2016)
【13】:way mo,在路上
【14】:美国道路安全法律滞后,而死亡事故攀升(2018)
【15】:[特斯拉、 自动驾驶数据](https://spectrum.ieee.org/cars-that-think/transportation/self-driving/tesla-reveals-its-crowdsourced-autopilot-data, https://electrek.co/2016/11/13/tesla-autopilot-billion-miles-data-self-driving-program/)(2016)
【16】:我们的自动驾驶车辆之路(2017)
【17】:优步的自动驾驶汽车自致命车祸以来首次重返公共道路(2018)
【18】:优步刚刚被批准恢复在匹兹堡和该州其他地方的自动驾驶测试(2018)**
自我激励通常与生活的宗教方面有关
如何使用自然语言处理来检查体裁之间的相似性,从而洞察整本书的写作内容
我们都同意桔子更像柠檬,而不是菠萝。像大小、形状和水果种类这样的属性很快就会进入我们的脑海。检查对象之间的相似性可以洞察它们的属性和总体特征。
在我最近的项目中,我通过使用自然语言处理(NLP)分析不同流派的书籍的导语,对它们的写作方式有了深入的了解。这个简单的项目展示了 NLP 在实践中的应用,以及文本分析在数据科学中的重要性。关于这个项目的更多细节和完整代码,请查看这个 资源库。
什么是广告词?
简介是对一本书、一部电影或其他产品的简短描述,是为促销目的而写的。书的简介通常很短,大多数情况下超过 100 个单词。
一个 200 字的导语可以用来代表一本 58000 字左右的书。
我对这个项目的主要目标包括找出以下内容:
- 导语是整本书的准确表达吗?
- 导语可以用来区分书籍的类别吗?
- 使用自然语言处理的不同类型的书籍/小说之间的相似性。
数据是从哪里得到的

我从非洲最受欢迎的电子书店 okadabooks 网上搜集数据,以用于此次分析。我选择这个网站的原因之一是它种类繁多,致力于出版非洲文学。查看 此处 了解更多关于网页抓取算法的细节。
规范化简介
为了进行正确的文本分析,最初的广告必须规范化。这包括删除标点符号、数字,并将所有大写字母改为小写。我用df['norm_blurb']= df.blurb创建了一个广告的副本,然后用df.norm_blurb= df.norm_blurb.astype(str)将其类型改为 strings。我使用 lambda 映射函数来帮助完成剩下的工作,如下所示。每行代码上的注释显示了每行代码在做什么。
标准化后的数据框如下所示:

sample of the data frame
选择要使用的类型
为了提高我的结果的准确性,我选择 norm_blurb 列中包含至少总共 100,000 个单词的流派。所有的广告词大约有 110 万字。这也有助于降低该项目的复杂性。

Breakdown of blurb words in all categories
我选择了上图中下划线标出的四种类型:自助类、小说类、浪漫类和宗教类。为四种类型创建了数据帧,另一个标记为random_df的长度为 2000 的数据帧通过使用df.sample(l=2000).函数使用四种类型的随机行创建。
消除停用词并创建每个词的频率字典
停用词 是语言中最常见的词。大多数句子需要包含停用词才能成为有意义的完整句子。它们是对语义关系没有影响/影响很小的词。通常,停用词会被删除,因为它们不重要,会扭曲词频分析。使用**from** **sklearn.feature_extraction** **import** stop_words导入库。stopwords.ENGLISH_STOP_WORDS将在功能中用来删除停用词。英语停用词的例子包括:

使用了一个函数来返回所需结果。这个函数创建一个字典,计算一个单词出现的次数,然后删除停用的单词。每一行都有一个注释解释它的作用。
导语是书籍的准确表达吗?/导语可以用来区分书籍的类别吗?
第一个问题有助于回答第二个问题。是的!在所选的类别中,10 个最常见的单词让我们对这些问题有了深入的了解。

当一个人寻找浪漫小说时,他/她是在寻找某种爱情故事。对于宗教类书籍,难免看不到神、教会之类的字眼。大多数励志书籍(自助)通常会讲述如何在一段时间内获得成功的秘诀。用最简单的术语来说,小说就是某种故事。
注意上面加粗的单词在它们各自的体裁中是 10 个最常见的单词。
可以从最常用的词中做出更多的推断:
- 上帝、基督和耶稣是宗教范畴中最常见的 10 个词。这是意料之中的。这也暗示了很多宗教书籍都是关于 okadabooks.com 的基督教的
- 自助书籍(也称为励志书籍)中多次提到成功,这些书籍倾向于宣扬激励/提供通往成功的秘诀。
- 上帝是自助(励志)书籍中第十常见的词。这表明成功有时与生活的精神层面联系在一起。这个推论耐人寻味。
- 爱情是言情小说中最常见的词。由此得出结论,言情类的导语是整本书的准确表达。
从这些频繁出现的词汇中,可以推断出很多关于 okadabooks.com 的书籍。虽然大多数导语确实是用于促销目的,但它们是整本书的伟大代表。
体裁之间的相似性

因为我们已经确定导语是书籍的一种很好的表现形式,相似性度量可以通过比较词频来计算。在这篇文章中,我将只集中在宗教书籍和其余选择的流派之间的相似性。哪个类别与宗教书籍最相似?哪个最不相似?
Jaccard 相似度 比较两个集合的成员,看哪些成员是共享的,哪些是不同的。简单地说,它是通过寻找集合的交集除以它的并集得到的。下面的函数用于获得所需的结果。
**def** jaccard_similarity(genre1, genre2):
intersection = len(set(genre1).intersection(set(genre2)))
union = len(set(genre1).union(set(genre2)))
**return** intersection/union
该值的范围从 0 到 1,其中 1 表示两个数据集 100%相似。然后用环形图将相似性可视化。

除了自我相似性之外,宗教书籍与自助书籍最为相似,约占 34%。这又回到了我们最初的推断:
上帝是自助(励志)书籍中第十个最常见的词。这表明成功有时与生活的精神层面联系在一起。
为了更深入的了解,我研究了这两个类别中最常见的单词。结果很有趣。

广告样本
这两个类别的示例让我们对一些书面广告有所了解。这只限于自助和宗教类别。
宗教信仰类别:

简介上写着:
性格的力量是一个 31 天的奉献和姐妹部长的工作手册。这本书将教你如何建立你的祷告生活,成为一个更好的人,并改善你与上帝的关系。
自助类别:

这是一本激励个人发展和商业策略的书。它是为了平衡贫富差距而写的。每个青年都需要成为有用的青年,最大限度地发挥他们的潜力,并发现他们的目的。
结论

这个简短的项目研究了两个物体之间的相似性,并证实了两个物体之间的相似性度量可以洞察它们的属性和整体特征。在这种情况下,通过使用自然语言处理来比较几种体裁,这给出了对不同类别书籍的写作内容的理解。
我很想听听你对此的想法。感谢您的阅读!
如果你喜欢这篇文章,请关注并看看我的其他数据科学文章🙏🙏。
自组织地图
(科霍宁的地图)
简介
自组织映射或 Kohenin 映射是由 Teuvo Kohonen 在 20 世纪 80 年代推出的一种人工神经网络。(论文链接)
SOM 使用无监督学习来训练,它与其他人工神经网络略有不同,SOM 不是通过 SGD 的反向传播来学习,而是使用竞争学习来调整神经元中的权重。我们使用这种类型的人工神经网络进行降维,通过创建空间组织的表示来减少我们的数据,还帮助我们发现数据之间的相关性。
SOM 的架构:
自组织地图有两层,第一层是输入层,第二层是输出层或要素地图。
与其他神经网络类型不同,SOM 在神经元中没有激活函数,我们直接将权重传递给输出层,而不做任何事情。
SOM 中的每个神经元被分配一个与输入空间具有相同维数 d 的权重向量。

自组织地图训练
正如我们之前提到的,SOM 不使用 SGD 的反向传播来更新权重,这种类型的无监督人工神经网络使用竞争学习来更新其权重。
竞争学习基于三个过程:
- 竞争
- 合作
- 适应
让我们解释一下那些过程。
1)竞争:
正如我们之前所说的,SOM 中的每个神经元都被分配了一个与输入空间维数相同的权重向量。
在下面的例子中,在输出层的每个神经元中,我们将有一个维数为 n 的向量。
我们计算每个神经元(来自输出层的神经元)与输入数据之间的距离,距离最小的神经元将成为竞争的赢家。
欧几里德度量通常用于测量距离。

2)公司:
我们将在最后的过程(适应)中更新获胜神经元的向量,但它不是唯一的一个,它的邻居也将被更新。
我们如何选择邻居?
为了选择邻居,我们使用邻域核函数,该函数取决于两个因素:时间(每次新输入数据增加的时间)和获胜神经元与另一个神经元之间的距离(该神经元离获胜神经元有多远)。
下图向我们展示了如何根据距离和时间因素选择获胜神经元(中间最绿的神经元)的邻居。

Time and distance factors
3)改编:
在选择胜出的神经元和它的邻居后,我们计算神经元更新。这些选择的神经元将被更新,但不是相同的更新,神经元和输入数据之间的距离越大,我们调整它,如下图所示:

neurons of the output layer update
将使用以下公式更新优胜神经元及其相邻神经元:


这个学习率表明了我们想要调整权重的程度。
在时间 t(正无穷大)之后,这个学习速率将收敛到零,因此我们将没有更新,即使对于神经元赢家也是如此。

邻域核取决于赢家神经元和另一个神经元之间的距离(它们成比例地相反:d 增加使 h(t)减少)和邻域大小,邻域大小本身取决于时间(随着时间增加而减少),这也使邻域核函数减少。
完整 SOM 算法:

例子:
现在让我们看一些例子
示例 1:

正如你在这个例子中所看到的,特征图采用了在二维空间中描述数据集的形状。
示例 2:
SOM with 3D feature map
自定进度多任务学习——综述
更新:
- 2021 年 8 月 14 日:从 GUPNet (ICCV 2021)添加 HTL(分层任务学习)
多任务学习使用相同的模型来执行多重回归和分类任务。多任务通常被认为可以提高网络性能,因为多个相关的任务有助于相互调整,并且可以学习更健壮的表示。此外,将所有任务合并到同一个模型中也有助于减少计算,这是自动驾驶等实时应用的关键要求。

A typical network structure for multi-task learning
通常,同一个主干(编码器)用于从原始输入中提取常见的低级特征,多个特定于任务的头(解码器)连接到主干。每项任务都有一个或多个损失项,总损失通常是所有损失项的加权平均值。深度神经网络中的每个可学习参数通过优化方法根据基于该总损失计算的梯度来更新。
现代优化方法,如随机梯度下降法和我们最喜欢的替代方法 Adam,无情地将总损失项减少到局部最优值。优化方法本身并不知道每个单独的损失项和每个单独任务的进度。因此,基于深度学习的多任务学习的性能对分配给每个任务的相对权重非常敏感。在极端情况下,如果除了一个任务之外的所有任务的权重都被设置为零,那么只有那个特定的任务将被适当地优化。
我曾经听过这个笑话(可能来自吴恩达在 Coursera 上的深度学习专业,但我不确定),它是这样的:如果一个人工智能算法被告知根据整个人类的平均幸福来最大化一个目标,它会做什么?这个目标听起来很合理,但人工智能可能会消灭大多数人类,只最大化少数人的幸福,最大化人类的平均幸福。

Well this graph of local optima is definitely from Andrew Ng’s course
多任务学习中损失的一般公式是

其中λ是分配给特定于任务 t 的损失 L_t 的权重,现在的问题是,如何选择λ来平衡多个任务?
标准基线
最简单的做法是在所有任务中使用统一的权重。然而,来自不同任务的损失通常具有非常不同的尺度,并且均匀地平均它们淹没了来自小损失任务的梯度。
一种典型的方法是通过网格搜索手动调整权重。然而,搜索空间随着任务的数量呈指数增长。当任务的数量超过两个时,执行网格搜索通常会非常繁琐,并且在计算上非常困难,尤其是当您有其他超参数需要优化时。(稍微好一点的方法是随机搜索,它给出了搜索优化参数的固定预算,但仍然需要多次运行相同的实验来搜索优化的参数。)此外,在整个训练过程中,搜索到的权重是静态的,正如我们在下面看到的,这可能不是最优的。
自定进度学习
一种更有原则的方法是根据某种标准自动为每项任务分配权重。有两个相关的学习领域:课程学习和自定进度学习。
课程学习最初是为了提高多任务子集的训练。它指出从小处着手很重要,用简单的例子初始化培训过程,然后继续进行更具挑战性的。这通常会带来更好的性能(参见这篇博文中的示例)。它在强化学习社区的应用比在计算机视觉领域更广泛。听起来它为我们的多任务问题提供了一个解决方案——我们可以从简单的任务开始,然后从困难的任务开始。然而,如何确定每个任务的难度是一个公开的问题,并且任务的难度可能在训练过程中发生变化。显然,手工制作课程表很有挑战性(对于动态的课程表来说更是如此),所以我们需要一种自动化的方式来做这件事。另外,课程学习有一个很强的假设 所有任务都有一个恒定的底层分布 。
自定进度学习是一种自动化的课程学习方法,其中课程由模型的能力决定。基本思想是监控学习进度信号,并设计或学习调整任务相对权重的策略。这种方法将学习每个任务的动态权重。这实际上非常类似于人类学生的学习方式——学生根据他们在特定科目上的表现来决定在每个科目上投入多少精力。
在接下来的会议中,我将简要概述文献中关于自定进度多任务学习的三种流行方法。
- 使用不确定性衡量场景几何和语义损失的多任务学习 (CVPR 2018)
- GradNorm:深度多任务网络中自适应损耗平衡的梯度归一化 (ICML 2018)
- DTP:多任务学习的动态任务优先级 (ECCV 2018)
使用不确定性衡量损失的多任务学习
这篇论文的作者(特别是 Alex Kendall)是深度学习中不确定性研究的先驱。这项工作是他们之前在不确定性方面的研究的一个特殊应用,例如我们在计算机视觉的贝叶斯深度学习中需要哪些不确定性? (NIPS 2017)和贝叶斯 SegNet:场景理解的深度卷积编码器-解码器架构中的模型不确定性 (BMVC 2017)。

The famous illustration of Aleatoric Uncertainty and Epistemic Uncertainty. This has become the de facto namecard for Bayesian Deep Learning.
深度学习中不确定性的一些背景知识:不确定性有两种,认知不确定性,和任意不确定性。认知不确定性是可以用更多数据解释的模型不确定性。任意不确定性是不能用更多的数据来解释的数据不确定性。随机不确定性可进一步分为两类,数据相关的异方差不确定性和任务相关的同方差不确定性。具体来说,作者建议使用同方差不确定性来衡量不同的任务。
嗯,这是一个相当复杂的问题,但这个想法是明确的。存在一种特定类型的不确定性,它不随输入数据而改变,并且是特定于任务的,作者正建议了解这种不确定性,并使用它来降低每个任务的权重。
本文推导了基于同方差不确定性下高斯似然最大化的多任务损失公式。这里就不赘述了,但是简化的形式是惊人的简单。

Modified weight based on task uncertainty
在上面的等式中,σ是与每个任务相关的不确定性(具体地说是同方差不确定性),不确定性越大,任务损失对总损失的贡献就越小。为了避免神经网络通过将所有任务的不确定性设置得非常高来学习琐碎的解决方案,第二项开始起作用并避免不确定性被设置得太高。第二项可以看作是一个正则化项,或“不确定性预算”。(这其实让我想起了另一篇论文:神经网络中用于分布外检测的学习置信度,其中也有神经网络跳过不确定性高的例子的“作弊预算”。你可以在这里找到我对这篇论文的笔记。

Task weight changes during training (uncertainty weighting)
这篇论文可能是最著名的,因为它简单明了。github 上有 Tensorflow 实现、 Keras 实现和 pyTorch 实现。
GradNorm:深度多任务网络中自适应损耗平衡的梯度归一化
GradNorm 用学习率代替不确定性作为学习进度信号。他们认为,任务不平衡阻碍了适当的训练,因为它们表现为反向传播梯度之间的不平衡。
训练率可以通过损失率或训练率的倒数 r(t)= 1(t)/1(0)来估计,即损失减少的速度有多快。这在所有任务中都是正常的。
然后,我们计算特定层(通常是主干最后一层的特征图)的每个任务的平均梯度范数。G(t) = ||∇wL(t)||_2.这在所有任务中也是正常的。

Without GradNorm and With GradNorm
使用来自以下损失的梯度来动态更新权重。

GradNorm loss for dynamically updating weights
等式中有一个超参数α,用于调整不同任务的平衡强度。α越高,不同任务之间的损失越不对称。如果α=0,则任务的权重相等。作者发现网络性能对(0,3)中的α相对不敏感。看起来α=1 可能是一个很好的默认值。
此外,GradNorm 总是确保权重被重新归一化为 1,这有助于更平滑的训练。
作者还发现,时间平均加权因子非常接近通过网格搜索选择的最优加权因子。这意味着 GradNorm 也可以用于找到最佳的静态权重,但只需运行一次实验(不像网格搜索所需的指数增长的实验数量)。
我在 github 上只找到了 pyTorch 的一个实现。

Task weight changes during training (GradNorm)
DTP:多任务学习的动态任务优先级
动态任务优先级不是用损失率作为学习进度信号,而是用 KPI κ(t)来代替,实际上更有意义。L(0)或初始损失中有太多的噪声,并且严重依赖于初始化方法。
DTP 借鉴了 Focal Loss(FAIR 的 RetinaNet 论文)的思想,将任务权重设置为 FL(κ)。γ是一个超参数,默认值为 1。

The formulation of Focal loss, an extension to Cross Entropy loss
这篇论文实际上也谈到了在网络体系结构中通过任务层次的实例级优先化和任务优先化,但是我个人认为那些新奇的东西不切实际。

Task weight changes during training (DTP)
HTL:分层任务学习
有时手头的多项任务并不相等,最好先训练一些不确定性低的任务,然后再开始训练不确定性高的任务。 GUPNet (用于单目 3D 物体检测的几何不确定性投影网络,ICCV 2021) 提出了一种分层任务学习(HTL)方法来解决单目图像深度预测的高度不适定问题。
HTL 受到这样一种动机的启发,即每项任务都应该在其前置任务训练好之后开始训练。HTL 确保只有当一项任务学得足够好时,才开始另一项任务的训练。

The 3 training stages of GUPNet and the evolution of loss curves and loss weights
具体地,在 GUPNet 的公式中,深度预测严重依赖于 2D 和 3D 尺寸的预测。HTL 解决了在初始训练阶段 2D/3D 尺寸的估计会有噪声,导致可怕的深度预测的问题。

通过比较最后 K 个时期和最初 K 个时期的学习趋势来定义任务是否已经被很好地学习的学习情况(ls)。一个任务只有当它所有的前置任务都学习好了才能开始训练。
外卖食品

Comparison of different self-paced learning method
这三种方法实际上都很容易实现,尤其是在 pyTorch 中。需要注意的是,流入和流出加权因子的梯度可能需要分离。
没有强有力的证据表明一种方法比另一种好得多。当然,GradNorm 和 DTP 论文都说它们比不确定性加权要好,但是在实践中这种改进非常小。考虑到实现的容易程度,也许应该首先尝试不确定性加权。
结束注释:对于 DTP 或 GradNorm 来说,更好的方法可能是,分别训练每个任务,并大致了解目标损失 L(∞)或 KPI κ(∞),并使用与预训练网络的目标值的比率作为学习进度信号。
关于我
作为一名物理学家,我曾在 X 射线探测器设计(我的博士论文)、半导体设备异常检测、医疗人工智能和自动驾驶等领域工作。我目前在一家快速发展的初创公司工作,致力于感知(传统的相机感知和新兴的基于 DL 的雷达感知)。我们在圣地亚哥和硅谷都有办公室。如果你对深度学习充满热情,或者你是个硬核 DSP 算法工程师,或者只是想打个招呼,请在 patrickl@xsense.ai 给我留言。
自我监督的甘斯
甘斯
如果你不熟悉生成对抗网络(GANs),它们是一种非常流行的生成建模技术,由两个深度神经网络(一个生成器和一个鉴别器)相互对抗而形成。这种对抗性的损失引发了许多深度学习和人工智能研究人员的兴趣。然而,尽管 GAN 公式很美,最先进的架构也令人大开眼界,但 GAN 通常很难训练。使用 GANs 获得更好结果的最好方法之一是提供类别标签。这是有条件 GAN 模型的基础。本文将展示自我监督学习如何克服训练 GAN 对类别标签的需求,并与条件 GAN 模型的性能相媲美。
自我监督学习
在我们进入自我监督学习如何改进 GANs 之前,我们将介绍自我监督学习的概念。与监督和非监督学习的流行系列相比,自我监督学习与非监督学习最为相似。自我监督的任务包括图像着色、预测从图像中提取的补丁的相对位置,或者在这种情况下,预测图像的旋转角度。这些任务被称为“自我监督的”,因为这些数据有助于这些替代任务。在这个意义上,自监督任务采用(X,Y)对的形式,然而,X,Y 对是从数据集本身自动构建的,并且不需要人工标记。这篇文章中讨论的论文将自我监督学习总结为“一个人可以对给定的图像进行编辑,并要求网络预测编辑的部分”。这是自我监督学习背后的基本思想。
有条件和无条件的 GANs
现在,我们将把自我监督学习与训练 GANs 的相关问题联系起来。在其理想形式中,GANs 是一种无监督的生成建模形式,其中您可以只提供数据,并让模型从中创建合成数据。然而,最先进的 GANs 使用一种称为条件 GANs 的技术,该技术将生成建模任务转变为监督学习任务,需要标记数据。在 Conditional-GANs 中,类标签被嵌入到生成器和鉴别器中,以便于生成性建模过程。无条件 GANs 指的是 Goodfellow 最初的想法,即生成式建模不需要类标签。本文将向您展示自我监督的学习任务如何能够消除对带有 GANs 的标记数据的需求。

Conditional GANs require class labels to work, (pictured in green)
辅助旋转任务
本文将讨论在以下论文中提出的自监督学习 GAN 架构的细节:
[## 自我监督的生成对抗网络
条件甘处于自然图像合成的前沿。这种模型的主要缺点是需要…
arxiv.org](https://arxiv.org/abs/1811.11212)
从高层次来看,本文中的辅助的、自我监督的学习任务是容易理解的。(如下图)

GAN 的发生器部分完全不知道辅助旋转任务,除了它必须学会在旋转时产生与真实图像共享相似特征的图像。轮换任务对鉴别器网络有巨大的影响。鉴别器现在有两个任务。第一个是预测图像是来自原始训练集还是由生成器创建的,就像所有的 GANs 一样。第二个任务是这篇论文如此有趣的原因。这组真实和虚假图像被旋转成 0、90、180 和 270 度旋转的相等分区,并且鉴别器必须对这些图像的旋转角度进行分类。鉴别器的旋转误差仅在真实图像上的误差上受到惩罚,以阻止来自生成器的不健康的收敛。
鉴别器遗忘
作者提出,由于难以从非平稳分布中学习,无条件 gan 表现不佳。这是持续学习中重点研究的问题,本文讨论了许多方法,如连接持续学习和 GANs 的弹性权重分配。提出的一个有趣的观点是,在最优生成器的情况下,鉴别器不需要学习有用的特征。
为了展示自监督 GAN 如何减轻鉴别器遗忘,他们从鉴别器中提取特征,并使用它来训练逻辑回归模型,以在监督的鉴别任务中对数据进行分类。

上面的图表明,无条件 GAN 将无法学习用于辨别任务的有用特征,而自监督 GAN(具有辅助旋转分类任务)学习的特征在训练期间继续学习用于监督学习模型的有用特征。

关于图像输出的质量,上图显示了通常用于定量评估两种自监督 GAN 以及有条件和无条件 GAN 模型的图像质量的 FID 分数。这些图显示,具有自调制批量标准化(sBN)的 SS-GAN 在 ImageNet 和 CIFAR-10 上的性能与有条件 GAN 一样好,右上方的图显示了无条件 GAN 在 ImageNet 生成任务上的性能。

上面的图比较了使用鉴别器特征在其他流行的自我监督学习任务中训练分类模型的结果。有许多不同的方法来设置自我监督的学习任务,我发现看到这种比较非常有趣。
感谢您的阅读!这是一个非常有趣的结果,通过使用辅助的自我监督任务来探索完全无监督的生成建模,请查看论文以了解更多细节!
使用辅助旋转损耗的自监督 GANs
TL;DR-自监督 GANs 结合了对抗学习和自监督学习,以弥补监督和无监督图像生成之间的差距,即有条件和无条件的 GANs。
你可以通过使用这篇准备训练 Pytorch 实现的论文来训练自己的 SS-GAN——【Github。
首先,什么是甘?
GANs 是生成对抗网络的缩写,它是一个神经网络系统,其中两个神经网络(生成器或鉴别器)一起工作,玩一个极大极小游戏,以学习它们生成图像和分别尝试检测图像是真是假的任务。换句话说,鉴别器的目标是区分生成器生成的数据和我们试图建模的真实数据。Ian Goodfellow 在 2014 年提出的这种结合两种网络的方法被证明是图像生成的神奇答案。然而,训练甘是一个棘手的问题。正如在深度学习领域一直以来的那样,在训练 GAN 时添加标记数据是一种拯救,该系统现在被称为条件 GAN 或 cgan。然而,监督图像生成虽然方便,但需要大量数据。为了补救这个问题,我们可以使用半监督学习技术来自己创建一个标签。这样,我们可以在有条件的和无条件的图像生成之间架起一座桥梁。
鉴别器遗忘
接下来,我们讨论传统 GANs 中的一个问题,这篇论文的作者强调了这个问题,叫做鉴别器遗忘。下图中描述的两个场景证明了这一点:


左图显示,尽管任务相似,但 Cifar10 数据集上的普通 1 对 1 分类器倾向于显示大量遗忘。每次任务发生变化,准确率都会大幅下降。然而,当损失函数由自我监督辅助时,情况就不是这样了。这表明,在这样一个不断变化的环境中,该模型没有保留可概括的表示。
右图显示了 GAN 训练期间的类似效果。每 100k 次迭代,鉴别器被用于 IMAGENET 分类,并且这显示了相同的遗忘模式,这与自我监督的情况不同。
自监督 GAN
在详细介绍 SS-GAN 之前,我们先来快速了解一下什么是自我监督学习。这个想法是在一个可以定义的托词任务上训练一个模型,每个样本的标签可以根据活动来决定。该活动可以是输入中的任何变化,例如,预测输入的旋转或预测图像块的相对位置。现在讨论它的用途,作者已经将预测旋转角度的任务加入到鉴别器中。因此,随着假对真的对抗性预测,它还试图预测图像在一组{0,90,180 和 270}角度之间的倾斜。这是借鉴了文献1中提出的自我监督方法。这使得鉴别器有两个头,模型的整体功能如下图所示:

合作对抗训练
该模型中的生成者和鉴别者仍然在使用标准的对抗损失并辅以谱范数和梯度惩罚来对抗地进行极小极大博弈。然而,我们正试图模仿有条件的 GAN 从标签中获得的好处(换句话说就是信息)。标签帮助生成器决定生成哪种图像,而不是随机生成像素。类似的还有 SS-GAN 的努力。该生成器并不是完全有条件的,因为它总是生成“直立”的图像,这些图像被进一步旋转以供鉴别器预测。另一方面,正如作者所说
"鉴别器被训练成仅基于真实数据来检测旋转角度."
这阻止了生成器生成易于预测旋转的图像。
总结一下,鉴别器有两个头。非旋转图像鉴别器的目标是预测真假。在旋转的实像上,预测 4 个旋转角度中的一个。
实验
他们将基于标准 resnet 的架构用于鉴别器和生成器,这些架构取自他们与 SS-GAN 进行比较的无条件 GAN。使用两个超参数来控制旋转损失的权重,一个用于真实图像,一个用于虚假图像。
为了比较样品质量,作者使用 FID。
此外,可以使用下图描述结果:

值得注意的重要一点是,自我监督比无条件监督提供了更好的绩效。
结论
在我看来,这项工作开辟了一条新的 gan 线,我们可以在不使用标记数据的情况下获得条件 gan 的稳定图像生成。用最先进的型号替换鉴别器有助于进一步改进。作者还提出了在半监督环境中使用少量标签进行进一步改进的想法。
参考
1 Spyros Gidaris,Praveer Singh 和 Nikos Komodakis。通过预测图像旋转的无监督表示学习。
参加 2018 年
(ICLR)国际学习代表大会。
自我监督学习的模式

Photo by Kevin Gent on Unsplash
为了乐趣和利益探索自我
自我监督在空中(与会谈)。解释自我学习、无监督学习、弱监督学习、半监督学习、远程学习和完全监督学习(当然还有 RL)之间的区别变得更加困难。)尽管如此,我们还是要努力。
在上下文中,问题是将一个对象(一个单词、句子、图像、视频、音频……)编码成一个足够通用的表示(数字块),这对于解决多任务是有用的(保留足够的对象特征),例如,找到一个句子的情感,将其翻译成另一种语言,在图像中定位事物,使其分辨率更高,检测正在说的文本,识别扬声器开关,等等。
鉴于图像、视频或语音的多样性,我们必须经常将与几个任务(甚至是一个任务)联系起来,如果我们遇到新的例子或新的任务,这些任务就会中断。从新的例子(标有预期输出的输入)中不断地重复学习是我们的首要策略(监督学习)。我们私下里(并且雄心勃勃地)希望这种令人厌倦的重复学习过程最终会消失,我们会学到这些物体的好的通用表示。 学一次,永远重用 。但是,所谓的无监督学习范式( only-input-no-labels) 并没有带来太多(像 GANs 和 learn-to-cluster 模型这样的轻微例外)。
进入自我监督:谢天谢地,散布在人工智能研究网络中的一种新的学习模式已经悄然出现,它有望更接近难以实现的目标。原理非常简单:为了给一个对象编码,你试着在它的部分或它(自我)的不同视图之间设置学习任务。
给定对象的一部分(输入),你能预测/生成另一部分(输出)吗?
这个原则有几种不同的味道。
- 例如,给定一个句子上下文围绕一个单词,你能(学会)预测出遗漏的单词 (skip-grams,BERT)。
- 或者,修改输入对象的视图 并预测发生了什么变化(旋转图像并预测旋转角度)。
- 或者,修改输入视图,确保输出不改变。
因为你只是简单地摆弄这个物体,所以这些是 免费午餐 任务——不需要外部标签。
幸运的是,我们现在有了(大量)自动生成的输入输出示例,我们又回到了游戏中。继续使用你的监督学习工具包中的每一把锤子来学习一个伟大的(通用的?)表示这些例子中的对象。
通过尝试从自我输入中预测自我输出,您最终了解了对象的内在属性/语义,否则将需要大量的示例来学习。

自我监督损失现在已经成为沉默的英雄有一段时间了,跨多个领域的表征学习(如自动编码器、单词嵌入器、辅助损失、许多数据增强、… )。一个非常漂亮的滑梯在这里。现在,有了 NLP 的 ImageNet moment(ELMo,BERT 和其他人),我想他们自己已经成功了。监管光谱中缺失的空白,每个人(包括 AGI;)一直在等。
可以理解的是,围绕着更新的自我监督技巧,用更少的例子获得 SoTA,以及混合各种监督(你好 NeurIPS !).迄今为止,自监督方法大多试图将对象的组成部分联系起来,以一部分作为输入,预测另一部分。或者,通过数据增广改变对象的视图,预测相同的标签。
接下来,让我们看看这个社区在玩新锤子的时候变得多么有创造力。还有许多问题有待解决:例如,你如何比较多种不同的自我监督技巧——哪一个比其他人学得更好?你如何选择输出?例如, UDA 使用内在输出分布 D 作为标签,而不是使用显式标签作为输出——确保当输入 x 的视图改变时,D 变化最小。
另外,我很好奇谁声称他们是第一个做这件事的人:)
更新:一个有趣的 twitter 帖子讨论自我监督是否是无监督(或其他)的品牌重塑。
tldr : 自我监督学习是非监督学习的一个优雅子集,在这里你可以通过暴露对象的部分或对象的不同视图之间的关系,从数据对象中“内在地”生成输出标签。
关于我:我是一名独立的计算机科学研究员、工程师和演讲者,喜欢提炼复杂的技术并将其转化为可消费的产品。我在学术界、工业界和初创公司都工作过。我帮助公司理解和应对复杂、不断发展的人工智能空间,并构建基于深度学习的解决方案,以最大化投资回报。如果你喜欢这篇文章,请鼓掌并发表你的评论。你可以关注我,在这里阅读我的其他文章,在 linkedin 上找到我,或者直接给我发邮件。
PS: 如果你想找人‘监督’你(弱监督、完全监督、远程监督甚至共同监督)解决一些非常有趣的文字、视觉和言语问题,请联系 nishant@offnote.co 的我!
卖给我这个…分类器?
您可能没有意识到,但在您的数据科学职业生涯中,您一直在不断地进行销售。当你不在你的黑色大风衣下兜售数据和算法时,你会反复尝试买入你的项目,并确立你工作的价值。
最近看了一本书,叫《向 出售的是人类 ,作者是 Daniel Pink。在这篇文章中,他发现 90%不直接参与销售的人花了大量时间做“非销售销售”。这种类型的行为包括说服或影响他人采取行动或进行交换。当我读到这里的时候,我的脑海里突然一亮。作为一名数据科学家,我在工作中的几乎每一次人际交往中都这样做。
虽然销售历来名声不好,但几乎所有与“非销售销售”相关的技能都可以帮助你改善人际关系,提高工作质量。我希望这篇文章和相关的销售技巧能够帮助您改善沟通,并促进您的数据科学事业。

为什么销售对数据科学家很重要?
我们甚至在获得数据科学头衔之前就开始销售。为了得到一份数据科学家的工作,你需要推销自己。你必须向未来的雇主推销你的个性、抱负、技能和背景。
随着我们在该领域的发展,我们需要销售我们创造的解决方案和我们使用的方法。我们必须得到老板、内部客户和同事的认可,才能真正对我们的工作产生影响。
如果您对管理层或总监级别的培训更感兴趣,您需要学会向您的组织推销数据科学这一概念。你必须推销你的团队正在做的项目,并解释为什么这比其他潜在的项目更能利用时间和资源。如果你试图建立你的团队,你必须向未来的员工推销你的组织和你所做的工作。
在数据科学层级的每个级别,销售技能都可以帮助我们在工作中产生更大的影响。如果我们能稍微提高我们的销售技巧,我们可能会有更多的工作机会,更酷的项目和更好的员工。
销售到底是什么?
当你提到销售时,大多数人会想到一个二手车推销员,他试图让你为一些旧车多付钱。在数据科学领域,我们的销售技能围绕倾听和展示我们创造的价值。了解我们的“客户”需要什么,并清楚地解释我们的工作将如何提供解决方案,这对我们来说非常重要。
虽然这听起来很简单,但由于数据科学的复杂性,有些人确实不理解我们提供的价值。我们必须能够为我们非常具体的目标受众将我们的工作浓缩成有用的金块。
如何提高自己的销售能力?
在对这个话题有了更多的了解后,我继续阅读其他各种销售书籍和资料。下面的清单是从这些书中摘录的:
- 出售的是人类 由丹宁粉红
- 大卫·霍夫菲尔德的《销售科学》
- 柳文欢·克拉夫
如果你有兴趣深入了解这些概念,一定要读这些书。
虽然我不是销售专家,但我已经使用了这些最佳实践,并看到它们在现实世界中发挥作用。如果你想提高你的销售技巧,这里有一些小贴士可以帮助你:
倾听——虽然这可能是最明显的建议,但也是最重要的。大多数销售人员关注的是他们认为自己产品的价值。他们不一定关注客户试图解决的问题。如果你专注于理解客户的最终目标,专注于解决他们问题的产品属性,你的结果会直线上升。
让别人说出你提供的价值——当我们说了什么,我们就开始相信它。如果你在获得认同方面有困难,询问你的“客户”他们正在试图解决的问题。接下来问他们你的解决方案如何帮助解决这个问题。这个简单的模式让他们有效地推销自己。你还会学到很多关于他们如何思考和他们的价值观在哪里的知识。
我在面试新角色时成功地运用了这一技巧。到了你提问的时候,试着问问你的技能和背景如何能为团队创造价值;你可能会对你所听到的感到惊讶!
利用镜像——潜意识里,我们喜欢和自己相似的人。镜像是一种技巧,你巧妙地模仿你的“顾客”的手势和说话方式。研究表明,使用这种技巧可以促进销售,增加受欢迎程度。
重要的是,这个动作不要太明显,你不想让别人觉得你在嘲笑他们。我建议从模仿某人的姿势开始(如果他们向后靠在椅子上,也向后靠,等等)。)或者镜像几个手势和腿的位置。当你掌握它的窍门后,它将开始成为你的第二天性。我也建议采用他们用来描述他们的问题和产品的词语。除了具有镜像效应,这还表明你确实在听他们说话。
做出小承诺——大多数人认为交易是在谈话结束时达成的;这就是所谓的“关闭”。事实上,销售是在整个谈话或一系列谈话中逐步进行的。如果你想增加某人同意你的可能性,你应该从让他们做出小的承诺开始,随着时间的推移逐渐积累。这可以从让他们同意在项目的第一阶段给你反馈开始,或者让他们使用你更复杂的解决方案的一个部分。这种做法让你的“客户”对你的工作感到舒服,并让他们习惯于对你说“是”。
展示价值,珍惜你的时间 —人们希望使用需求量大的产品或服务。提醒人们你之前为他们创造的价值,或者你为他们的同事创造的价值,可以加强你当前请求的重要性。强调你过去的成功也减少了你显得贫穷的机会。需求扼杀了你的动力,并可能导致别人利用你。
另外一个减少贫困的方法是我们如何管理时间。为我们的会议设置硬性停止意味着我们的时间是宝贵的(确实如此),应该认真对待。
引发情绪反应——作为数据科学家,我们被训练根据数字做出决策。不幸的是,在我们的世界之外,大多数决定都是由情绪决定的。许多人并不真正理解数据,当有人缺乏理解时,他们通常会抵制。当与我们的“客户”交流时,也要吸引他们情感的一面,这一点很重要,因为他们天生就能理解。
我们引发情感反应的方式是通过讲故事。编织一个(真实的)叙事,讲述该项目如何帮助拯救患者生命或增加利润,同时丰富客户体验。这些概念是有形的,可以帮助你和那些对数据感到不舒服的人讲道理。
给多种选择 —当人们只有一种选择时,他们会感到被困住了。很多时候,他们会回到他们的基线,也就是什么都不做。当我们给某人多种选择时,他/她现在在这件事上有了一些实际的发言权,而不仅仅是“是”或“否”。你仍然对他们选择哪条路有很大的控制权,因为你可以让一个选项明显优于另一个。
拥有多种选择也有助于你从“我们应该这样做吗?”到“我们应该做哪个选择?”。你可以跳过可怕的是或否的问题,直接投入到承诺中。
有了这个,重要的是不要给太多的选项。人们可能会被太多的选择淹没,所以最好将你的选择保持在 2-5 之间。
在“关闭”中
虽然这些建议有助于提高听到“是”的几率,但重要的是要注意,其中一些可能会被认为是操纵。这些应该是半信半疑的,应该集中在提高清晰度上,而不是蒙人的眼睛。
作为数据科学家,我们的销售永远要有数据基础。我们的产品应该有利于我们的“客户”和我们的公司,而不是为了我们的个人利益(可能在采访之外)。
请善用这些新技能!
半结构化表格的带类型约束的神经语义分析
将这篇高水平的人工智能研究论文总结成字节大小的片段

Photo by Startaê Team on Unsplash
这是对
针对半结构化表格的具有类型约束的神经语义解析
由贾扬特·克里希那穆提、帕拉德普·达西格和马特·加德纳在此发现:
http://ai2-website . S3 . Amazon AWS . com/publications/wikitables . pdf
两句外卖
不关注语言语义的自然语言处理(NLP ),只产生哪些单词更常用/不常用以及哪些单词可能与这些单词相关的基本统计数据;因此,如果没有类型约束,就无法实现真正的自然语言理解(NLU ),因为语言的结构(对理解意义至关重要)没有传达给模型。

Their technique checks all the boxes. Image from the authors’ slide deck on this paper.
为了克服这个障碍,作者实现了一种新的编码器-解码器解析器,使用约束来确保他们的 NLU 模型理解语言如何构造的逻辑,从而能够学习不同的实体如何相互关联,推动神经语义解析器的发展。
过去的方法
以前已经通过各种方法解决了这个问题,作者从这些方法中吸取了好的方面,同时避免了大部分的缺点。其中包括:
- 形式主义,使用隐藏变量或机器翻译将数据转换成词汇化的语法形式(如 CCG )。然而,前一种方法很难训练,后一种方法不精确。
- 实体链接将相关单词/概念连接在一起,但通常是通过固定规则或词典手动或粗略完成的。
- 监督,涉及数据中的标记逻辑形式或被限制为问答对。贴标签证明是昂贵的/困难的;同时,问答配对的效用有限,但应用灵活。
他们的第一个新方法:类型约束解码
Krishnamurthy 等人的模型通过将编码器-解码器框架捆绑到他们的 LSTM 中来解决这些限制,以将输入单词向量转换成逻辑形式(类似于古老的 seq2seq 方法),但关键是他们还在语法上分配了类型约束。这种方法实现了前面提到的前一种方法的精度,自动对实体链接进行编码,同时还无需手动标记即可进行缩放。

Image from the authors’ slide deck on this paper.
他们工作的真正关键在于对解码后的语法实施类型约束:约束是参数的必要条件。使用自动分配的类型约束,他们能够仅使用以下 4 类规则来导出每个有效的逻辑形式:
Application“通过将从β到τ的函数应用于β类型的参数,重写τ类型的非终结符。我们也允许有多个参数的应用程序。
constant-“其中 constant const 的类型为τ。该规则生成与表无关的操作(如 argmax)和特定于表的实体(如 united_states),"
Lambda –"生成 lambda 表达式,其中参数的类型为α。x 代表一个新的变量名。这个规则的右边用 x 的绑定来扩展范围γ,然后生成τ类型的表达式。”
变量-“此规则在当前范围内的先前生成的 lambda 表达式中生成一个变量绑定。”

The parser starts off by predicting the logical form’s root type then decodes all the data into logical forms using the rules and constraints. Image from the authors’ slide deck on this paper.
基本上,最大的湖的名称是通过按照以 km 为单位的面积的类型约束从最大到最小对所有湖的列表进行排序来找到的,并且再次使用类型约束来返回名称而不是另一个数据点,例如面积。
一个更简单的例子可以是找到等式的结果:35 x 1.2 =这将通过应用以下类型约束来实现:
- 整数类型约束将应用于 35,以使它只关注数字,而不是事实,如史密斯大厦的观景台在第 35 层。
- 将应用乘法函数类型约束来进行数学运算,而不是使用字母“x”。
- 浮点数类型约束将应用于 1.2,以防止数字向下舍入到整数 1。
- 并且将所有这些放在一起将得到“35 * 1.2 = 42”的计算结果
他们的第二个贡献是:用语义解析器训练实体链接
除了训练他们的核心模型来解析问答对的语义之外,他们还训练了一个独立的 LSTM 模型来处理与主模型并行的实体链接。研究人员没有依赖于手动完成的每个单词嵌入(单词的数字表示)的冗长的实体链接,或者在手头任务的上下文之外创建的通用的、不可变的实体链接词典,而是创建了一个单独的模型来映射上下文感知的实体链接矩阵,该矩阵是随着他们的主要语义解析器学习更多而创建和更新的,从而在良性循环中加强语义解析器。

Image from the authors’ slide deck on this paper.
链接的创建部分基于单词的相似性,部分基于单词如何一起使用。因此,单词“Boatswain”与“Boathouse”的联系比“Cummerbund”更紧密,但如果解析描述“Cummerbund”可以存储在“boathouse”中的所有不同方式和数量的语料库,这两个单词将开始在此上下文中建立紧密的联系。这种学习术语在当前主题的上下文中如何相互关联的能力使得它们的语义解析器能够实现令人印象深刻的性能;它可以以类似于人类学习的方式建立利基领域的专业知识,不仅在当前“阅读”的内容中建立联系,还可以联系到它“阅读”的其他内容,这种影响随着“阅读”的增加而加剧。
第三:关于外延的动态规划(DPD)
将所有这些改进结合在一起,他们在每个表格/语料库/主题上使用 DPD,计算将导致答案的所有逻辑一致的约束组合。通常,如果可能的预测数量相对较少,则来自解析器的结果/进程相对容易评估,但是随着该数量的增加,以传统方式(通过网络架构处理它们)评估这些选项的难度/成本会呈指数级增加,对于复杂的主题来说很快变得不可行。

Image from the authors’ slide deck on this paper.
Krishnamurthy 等人通过将他们的评估限制在最可能的最佳预测的限度内来解决这个问题。以前的方法在选择它们的边际对数似然最佳预测时,要么需要使用非常高的限制。或者先前的尝试使用了强化学习技术,由于较差的信噪比,该技术不适合复杂的对象。这种新颖的方法在合理的限制范围内有效,因为他们首先使用 DPD 限制了可能的选项集,因此只有有效的选项是可能的。这使得他们能够以更低的成本获得更好的结果。
数据
由于其复杂性(深度)和广泛的信息范围(广度),研究人员选择在 WikiTableQuestions 数据集上测试他们的结果。这个数据集由维基百科上各种主题的数据表组成:具体来说是 2108 个表。此外,它包含 22033 个复杂程度不同的问题,需要语义解析器来真正理解数据以及数据之间的关系,以便更好地执行。此外,该数据集有一个基于新鲜表格的隐藏测试问题集,允许模型接受未知数据的挑战,以证明其归纳新主题的能力,并表明它不仅仅是记住问答对。
此处信息的巨大广度和深度为语义理解机器通过克服以下挑战展示能力提供了几个机会:
- 图式映射——理解不同的词可能被用来指代相同的想法
- 组合性——大短语通常由许多小短语组成,每个小短语都相对简单。
- 各种操作——问题中的每一个小短语都可能是需要对数据进行的不同类型的操作,例如:过滤数据、精确定位数据、计算统计数据和比较数量

Complex questions like this are available to train on and to test the true capabilities of a semantic parsing model. Image from the authors’ slide deck on this paper.
以前对 QA 数据集的尝试倾向于要么强烈关注深度,而广度非常狭窄(例如"哪些州与德克萨斯州接壤,有一条主要河流?"但是只关注地理)或者他们覆盖了广泛的问题而没有深入到任何主题(例如“世界上有哪些国家说法语?”).
表演
使用类型约束解码,用语义解析器和 DPD 训练的实体链接,Krishnamurthy 等人能够在 WikiTableQuestions 数据集上超越现有技术水平,证明他们的方法除了理论之外也是实用的。由于这个数据集如此之深和庞大,这些不是简单的是/否问题;因此,45.9%是一个非常令人印象深刻的结果。

Comparison with the other cutting edge approaches. Image from the authors’ slide deck on this paper.
他们训练了使用单一模型和模型集合的语义解析器版本,以显示这些方法可以跨多种实现工作。总体基本上是一组不同的(有时非常不同,有时只是略有不同)模型,所有这些模型一起接受训练,每个模型做出一个预测,并比较它们的答案,以在大多数情况下得出一个更好的选择。想要更好的解释,请看这个:https://towards data science . com/two-is-better-one-ensembling-models-611 ee 4 fa 9 BD 8


Type constraint (left) and entity linking (right) experiments’ results. Images from the authors’ slide deck on this paper.
除了测试各种实现之外,他们还通过有选择地关闭特定模块来测试这 3 种贡献,以查看对整体性能的影响。

When the team dug into the reasons for the model’s errors, they seemed to be due to a variety of reasons, all with rather intuitive explanations. Image from the authors’ slide deck on this paper.
这些结果表明,所有这三种方法一起对语义分析和自然语言处理的整体技术水平产生了显著的进步。虽然还有改进的空间,但这些贡献解决了解析器在真实用例中实际实现所需的许多挑战。

Image from the authors’ slide deck on this paper.
Krishnamurthy 等人的代码:
一个基于 PyTorch 的开源 NLP 研究库。- allenai/allennlp
帕拉德普·达西吉介绍他们的研究:
演示本文结果的幻灯片:
https://nlp.stanford.edu/seminar/details/jkrishnamurthy.pdf
我期待着听到您对本文或讨论的主题的任何反馈或问题,无论是在这里还是在社交媒体上。随时联系我(只要告诉我你看到这篇文章了)→
【linkedin.com/in/theNathanielWatkins 号
语义搜索
关于语义、搜索和语义搜索的简短帖子

Photo by Kayla Farmer on Unsplash
⚠️在我的博客⚠️中读到了的原帖
语义学是语言学的一个分支,研究单词的含义、它们的符号用法,也包括它们的多重含义。
“一天早上,我射杀了一头穿着睡衣的大象。我永远也不会知道他是怎么穿上我的睡衣的。”格劳乔·马克斯
这句话在语义上是模棱两可的:不清楚作者是穿着睡衣射杀了一头大象,还是他射杀了一头大象,而大象恰好穿着睡衣。显然,在这个例子中,两者中只有一个有意义,但两种情况都是语法正确的。
"约翰和玛丽结婚了。"(对彼此?还是分开?)
约翰吻了他的妻子,萨姆也吻了。(山姆吻了约翰的妻子还是他自己?)
词汇搜索引擎
起初,搜索引擎 (Google,Bing,DuckDuckGo,Yahoo 等。)是词汇:搜索引擎寻找查询词的字面匹配,而不理解查询的含义,并且仅返回包含精确查询的链接。
例如,如果用户寻找“cis lmu”,来自 lmu 大学的 cis 中心的主页匹配该查询,因为:
- CIS 中心的主页包含这两个词
- 主页的 url 包含这两个词
- 该页面位于域的顶级
- 以及由搜索引擎指定的许多其他原因
所有这些标准都很容易检查,它们本身就使这个页面成为这个查询的首选。不需要更深入地理解查询实际“意味着”什么或者主页实际“关于”什么。
语义搜索
语义搜索是有意义的搜索。此“意为”可以指搜索过程的各个部分:
- 理解查询,而不是简单地寻找文字匹配,
- 或者以适合有意义检索的方式表示知识。
语义搜索超越了查询的“静态”字典含义,以理解搜索者在特定上下文中的意图。通过从过去的结果中学习并创建实体之间的链接,搜索引擎可以利用出现在可搜索数据库中的术语的上下文含义来生成更相关的结果。
它还允许用户提出自然语言问题,而不是让计算机理解我们的语言:“我如何开始数据科学的职业生涯?”vs .“数据科学职业步骤和技巧”。在第二种情况下,没有动词或不必要的单词,只有用户认为与搜索引擎相关的关键字。
语义搜索结果还要求将来自几个不同来源的信息汇集在一起,以令人满意地回答查询。

在这个例子中,主要结果是关于吉米·基梅尔和吉列尔莫关于 Maddie Zieger 的 YouTube 视频,Maddie zie ger 是“Sia 枝形吊灯音乐视频的明星”。
- 谷歌“理解”查询“谁是 X”的结果必须是一个人的名字。
- 请注意,“麦迪·齐格勒”和“吉列尔莫”都被突出显示,这是谷歌的一个不正确的结果。另一方面,“吉米”没有突出显示。可能是因为 Guillermo 比 Jimmy 更接近句子中的动词 dance。对于更高级的读者来说,你可能会注意到第三行中的代词“他”指的是吉米,两个男人属于同一类别,因此同样接近动词“舞蹈”,但成功地将“他”与“吉米”联系起来是另一个语言学问题,称为共指消解,在本例中没有得到很好的解决。(维基百科链接, 斯坦福 NLP 小组的实现)
- “吊灯视频中的舞者”和“吊灯音乐视频中的明星…谁是一个非凡的舞者”没有字面上的匹配。这些词没有出现在彼此旁边,但搜索引擎将“音乐视频中的明星”和“舞者”联系起来。

在这个例子中,结果不仅正确显示,而且有一个用户友好的部分,有一张图片,以及其他类似的建筑和它们的高度。

显示的例子是谷歌的结果。即使近年来其他搜索引擎已经实现了语义搜索功能,谷歌是第一个这样做的,2013 年更新了蜂鸟,也是迄今为止最准确的一个。
奖金:怎么用?
谷歌在 2012 年包括了一个知识图,一个本体,以图形格式表示人、地点和事物之间的语义关系。这些关系可以是同义词、同音异义词等。随着 2013 年蜂鸟的更新,谷歌拥有了一个巨大的知识图表,其中收集了大约5.7 亿个概念和关系。
当一个新的查询到达系统时,首先通过使用自然语言处理(NLP)算法,如词性标注检索、命名实体识别、纠错、转换为单词嵌入、搜索同义词等,将查询分解成根术语。
然后,将这些术语匹配到本体中,从庞大的图中获得最接近的术语。这些术语或链接与输入更相关。好的系统使本体独立于语言,这样西班牙语的查询可以匹配英语的本体术语。
其他链接
方法的综述和分类,](https://www.semanticscholar.org/paper/A-survey-and-classification-of-semantic-search-Mangold/344885b612ddbe5ede930571bd433f195245147d)斯图加特大学,2007
Github 工程,走向自然语言语义码搜索, 2018
Hamel Husain,如何用深度学习为任意对象创建自然语言语义搜索,2018
神经网络时代的语义分割
图像分割是计算机视觉和目标识别与检测的基本任务之一。在语义分割中,目标是将图像的每个像素分类到特定的类别。与图像分类的不同之处在于,我们不是将整个图像分类到一个类中,而是对每个单独的像素进行分类。因此,我们有一组预定义的类别,我们希望在图像的每个像素中分配一个标签。我们根据图像中不同物体的上下文来完成这项任务。

我们可以在上图中看到一个真实的例子。图像的每个像素都被分配了一个特定的标签,并用不同的颜色表示。红色代表人,蓝色代表车,绿色代表树等等。
值得一提的是,语义分段不同于实例分段,在实例分段中,我们为同一类的实例区分标签。在那种情况下,人们会有不同的肤色。
但是我们在乎吗?(对了,如果你不知道 frak 是什么意思,就去狂看《太空堡垒卡拉狄加》吧。太牛逼了)。为什么我们需要这种高细节的处理?
事实证明,语义分割有许多不同的应用。你可以从上图中猜出第一种。自动驾驶汽车。自动驾驶汽车需要知道自己看到了什么。他们需要知道一切。每个该死的像素。另一个普遍的应用当然是在机器人领域(工业或非工业)。我不能列举更多。地理传感,农业,医学图像诊断,面部分割,时尚。
如果你被说服了,让我们来看看如何完成这个任务。这并不难理解。
深度学习
深度神经网络彻底改变了计算机视觉,尤其是图像分类,这不是什么秘密。从 2012 年到今天,它大幅超越了它的前辈。计算机比人类更擅长图像分类,这是现在的事实。不可避免地,我们也使用相同的技术进行语义分割。他们成功了吗?
当然,他们做到了。卷积神经网络现在是这类问题的行业标准。我不会用这个领域中所有架构的历史倒叙来烦你。相反,我将向你展示 2019 年出现的最先进的技术。
但首先让我们更具体地定义我们的问题:
- 图像的每个像素必须被分配到一个类别,并相应地着色
- 输入和输出图像应该具有完全相同的大小
- 输入中的每个像素必须与输出中完全相同位置的像素相对应
- 我们需要像素级的精度来区分不同的类。
考虑到这些因素,我们来看一下架构:
全卷积网络(FCN)
全卷积网络只包括卷积层和汇集层,不需要完全连接。最初的方法是使用一堆相同大小的卷积层将输入图像映射到输出图像。

Stanford University School of Engineering
正如你可能想象的那样,它产生了相当好的结果,但是它的计算量非常大。问题是,他们不能使用任何缩减像素采样或合并图层,因为这将搞乱实例的位置。为了保持图像分辨率,他们需要添加许多层来学习低级和高级特征。因此,它最终变得非常低效。
为了解决这个问题,他们提出了一种编码器-解码器架构。编码器是一个典型的卷积网络,如 AlexNet 或 ResNet,解码器由去卷积(虽然我不喜欢这个术语)和上采样层组成。下采样步骤的目标是捕获语义/上下文信息,而上采样的目标是恢复空间信息。

Stanford University School of Engineering
这样,他们设法大大降低了时间和空间的复杂性。而且,最终的结果。因为编码器降低了图像分辨率,所以分割缺少定义明确的边缘,这意味着图像之间的边界没有明确定义。
拯救:跳过连接。
跳过连接绕过层,将信息原封不动地传递给下一层。在我们的例子中,我们使用它们将信息从编码器的早期层传递到解码器,绕过下采样层。事实上,这有助于改善分割的细节,使形状和边缘更加精确。
优信网
基于全编解码和跳连接概念,全卷积网络的思想扩展到了 U-net 。U-net 通过增加解码器的大小来匹配编码器,从而在 FCN 中引入对称性,并使用级联来取代跳过连接中的求和操作。
由于对称性,我们可以将更多的信息从下采样层传输到上采样层(因为现在有更多的要素地图),从而提高最终输出的分辨率。

https://datascience.stackexchange.com
U-nets 最初是为生物医学图像分割而开发的,但它们也用于各种不同的应用中,如添加完全连接的层或残差块。
为了完全掌握 U-net 的思想,让我们写一些代码来实现它是多么简单。我们将使用 python 和 keras 框架来进一步简化事情。
你认为我在开玩笑吗?就是这样。堆叠在一起的一堆卷积层、池层和上采样层,以及实现跳过连接的一些连接。非常简单还是什么?
当然,我们仍然需要做大量的工作,比如预处理我们的输入数据,扩充它们,更重要的是找到它们。我的意思是,为我们的训练收集地面图像根本不是一件容易的事情。试想,对于每一幅输入图像,我们都希望它的分割能够找到它们之间的误差。我们如何构建地面真实分段?用手吗?那是做这件事的一种可能的方法。通过一个精心制作的剧本?也许吧。有一点是肯定的。这并不容易。
最后,我想提一下,还有其他非常聪明的方法来执行语义分割,但大多数都是建立在 FCN 和 U-Net 之上的。其中一些是:
语义分割是一个非常活跃的研究领域,因为它在现实世界的应用中非常重要和紧急,所以我们期待在未来几年看到更多的论文。计算机视觉和深度学习的结合非常令人兴奋,并在复杂的任务中给了我们巨大的进步。你认为如果没有深度学习,特斯拉自动驾驶汽车今天已经行驶了 12 亿英里吗?我个人不这么认为。让我们看看未来会怎样…
如果你有任何想法、评论、问题或者只是想了解我的最新内容,请随时在Linkedin,Twitter,insta gram,Github
原载于 2019 年 1 月 25 日sergioskar . github . io。**
基于深度学习的航空图像语义分割

source: matheen faiz on unsplash.
在计算机视觉和图像处理中,逐像素图像分割是一项具有挑战性和高要求的任务。这篇博客是关于从航空(卫星/无人机)图像中分割建筑物的。高分辨率遥感数据的提供为有趣的应用开辟了可能性,例如更详细地按像素对单个物体进行分类。通过使用卷积神经网络(CNN ),图像的分割和分类变得非常有效和智能。在本文中,我们使用了非常高分辨率和尺寸的图像,因此图像被裁剪并减小了尺寸,以便在具有正常规格的中等水平的计算机中容易地进行处理。该模型受 UNET 模型的启发,后者广泛用于输出与输入格式相同的网络。该模型通常用于医学科学领域,以检测医学图像中的异常,如发现骨折或肿瘤。微调或迁移学习也用于提高模型的准确性。微调超参数可以有助于改进模型的学习,因为使用了先前训练的模型的编码器。为了针对不同的挑战情况训练我们的模型,以便我们的模型可以产生更准确的结果,我们使用了数据扩充,即拍摄一幅图像并对其进行一些更改,如改变色调、饱和度、亮度值、缩放和改变角度、旋转等,以提供广泛的训练情况,这在训练数据较少或不足的情况下也有帮助。总的来说,经过充分的数据训练后,该模型能够得到高精度的结果。
什么是语义切分??它的实际应用有哪些??
对无人机图像进行语义分割以对不同属性进行分类是一项非常具有挑战性的工作,因为差异非常大,你不能指望这些地方是相同的。手动分割这些图像以用于不同的应用是一项挑战,也是一个永无止境的过程。因此,需要自动化和智能系统来自动完成我们的工作。所以,剧中的神经网络来了。近年来,神经网络和深度学习在不同领域的应用达到了高峰,解决这一挑战性问题的有趣和智能的方法吸引了不同领域的人们的注意。因此,由于数据的不规则性,通过应用神经网络的概念来解决这个问题是一个有点挑战性的任务。
卷积神经网络(CNN),是处理图像的深度学习概念。在正常的神经网络操作中,每个节点都是相互连接的,创建了一个复杂的网络,但如果我们在图像中应用相同的东西(它本身就是一个大矩阵),事情就不会那么好了,因为每个像素在那里充当一个节点,当这几百万个像素与另一层连接时,就会有几百万或几十亿个连接,所以在那种情况下计算太复杂了,所以为图像创建了一种新的方式,我们称之为卷积神经网络。这里的概念基本上是我们卷积图像到另一层。
该计划可以在各种商业目的中实施,例如:无人机是一种新的广泛使用的技术,具有广泛的实施范围,如检查任何区域或交付产品,因此该计划有助于定位准确的位置并提高准确性。通过自动检测建筑物,我们可以使用这些数据来预测人口密度或计算住宅区、商业区或无人居住区的面积。在线地图是目前广泛使用的技术,通过自动检测建筑物等属性,可以很容易地在地图上显示特定区域,这可以有多种应用,如标记区域或使用地图创建建筑物的三维模型。这个项目的另一个主要应用是它在灾害管理中非常有用,例如,如果一个地方遭受了地震或洪水等灾害,那么可以使用飞行器来救援或运送食物,如果建筑物在更短的时间内以高精度定位,就可以做到这一点。此外,这在实际生活中还有许多其他的应用,也可以有益于社会和商业目的。
使用神经网络来创建一些自动化的工作,改变了传统的和缓慢的做事方式,从而产生高精度的结果,这既节省时间又节省成本,而无需任何忙乱的工作;由于航空图像分割是一个重要的挑战,其实际应用是巨大的,自动化是一个很好的解决方案。这里用于语义分割的 UNET 模型受到医学领域的启发。UNET 的真正应用是用于医学图像,即当与正常图像的大数据集比较时,检测像肿瘤或骨折等异常。由于这些敏感的工作需要非常高的精度,所以 CNN 的层被做得更深以学习更重要的特征。这一点启发我们将该模型用于航空图像,因为建筑物之间的差异是完全独特的,并且有许多参数和特征要学习,如果将其用于实际应用,高精度也是必要的。
使用的基本概念/技术
神经网络- 人工神经网络(ANN)是一种信息处理范式,其灵感来自生物神经系统(如大脑)处理信息的方式。这个范例的关键要素是信息处理系统的新颖结构。它由大量高度互联的处理元件(神经元)组成,这些元件协调工作以解决特定的问题。人工神经网络像人一样,通过例子来学习。通过学习过程,人工神经网络被配置用于特定的应用,例如模式识别或数据分类。生物系统中的学习涉及对神经元之间存在的突触连接的调整。

Fig. A Simple Neural Network Architecture.
卷积神经网络- U-Net 架构由捕获上下文的收缩路径和实现精确定位的对称扩展路径组成。收缩路径遵循卷积网络的典型架构,具有交替的卷积和汇集操作,并逐渐向下采样特征地图,同时增加每层的特征地图的数量。扩展路径中的每一步都包括特征图的上采样,然后是卷积。
U-Net 能够从相对较小的训练集中学习。在大多数情况下,用于图像分割的数据集最多由数千个图像组成,因为手动准备掩模是非常昂贵的过程。通常,U-Net 是从随机初始化的权重开始从头开始训练的。众所周知,没有过拟合的训练网络的数据集应该是相对较大的,数百万张图像。在 Image-net 数据集上训练的网络被广泛用作其他任务中网络权重的初始化源。以这种方式,可以对网络的非预训练的几层(有时仅对最后一层)进行学习过程,以考虑数据集的特征。

Fig. A Simple Convolutional Network Structure.
UNET 模型——U-Net 架构由一个捕捉上下文的收缩路径和一个支持精确定位的对称扩展路径组成。收缩路径遵循卷积网络的典型架构,具有交替的卷积和汇集操作,并逐渐向下采样特征地图,同时增加每层的特征地图的数量。扩展路径中的每一步都包括特征图的上采样,然后是卷积。
UNET 能够从相对较小的训练集中学习。在大多数情况下,用于图像分割的数据集最多由数千个图像组成,因为手动准备掩模是非常昂贵的过程。通常,U-Net 是从随机初始化的权重开始从头开始训练的。众所周知,没有过拟合的训练网络的数据集应该是相对较大的,数百万张图像。在 Image-net 数据集上训练的网络被广泛用作其他任务中网络权重的初始化源。以这种方式,可以对网络的非预训练的几层(有时仅对最后一层)进行学习过程,以考虑数据集的特征。

Fig. A Simple U-NET Structure.
使用 VGG-16 编码器进行微调(在 image-net 上进行了预训练) -作为我们 U-Net 网络中的编码器,我们使用了相对简单的 VGG 系列 CNN,由 11 个连续层组成,称为 VGG16。VGG16 包含七个卷积层,每个卷积层后面都有一个 ReLU 激活函数,以及五个最大轮询操作,每个操作将特征映射减少 2。所有卷积层都有 3×3 个内核。第一个卷积层产生 64 个信道,然后,随着网络的加深,在每次最大池化操作之后,信道的数量加倍,直到它达到 512。在随后的层上,通道的数量不变。为了构建编码器,我们删除了完全连接的层,并用 512 个信道的单个卷积层代替,该卷积层充当网络的瓶颈中心部分,将编码器与解码器分开。
为了构造解码器,我们使用转置卷积层,它将特征图的大小加倍,同时将通道的数量减少一半。并且转置卷积的输出然后与解码器的相应部分的输出连接。通过卷积运算来处理所得到的特征图,以保持通道的数量与对称编码器项中的相同。这个上采样过程重复 5 次,以与 5 个最大池配对。从技术上讲,完全连接的层可以接受任何大小的输入,但因为我们有 5 个最大池层,每个层对图像进行两次下采样,所以只有边长可被 32 整除的图像可以用作当前网络实施的输入。
提议的模型/工具
数据集 -我将我的模型应用于 Iniria 航空影像标注数据集。该数据集由 180 幅欧洲和美国城市居民区的航空影像组成,并被标记为建筑物和非建筑物类别。数据集中的每幅图像都是 RGB 格式,分辨率为 5000×5000 像素,每个像素对应一个 30 厘米×30 厘米的地球表面。但是我们不能把这么大尺寸的图像直接放到我们的代码中,所以我们需要截取这些图像。每个裁剪图像的分辨率必须能被 32 整除。因此,我对这些图像进行了 512x512 分辨率的裁剪,然后将其用于我的算法中。首先,我尝试使用双线性插值来调整图像的大小,但这种技术未能保留图像的重要细节,所以我只是正常地裁剪它。从总数据集来看,80%的图像作为测试数据,其余 20%作为验证集。
平台和软件要求-
Jupyter Notebook 中的 Python 3.5 用于编码目的(Anaconda 环境)。
- Keras 与 Tensorflow(后端)用于开发代码。
图像增强和图像数据生成器——图像增强通过不同的处理方式或多种处理方式的组合,如随机旋转、平移、剪切和翻转等,人工生成训练图像。在 Keras 中,有一个名为图像数据生成器的预定义功能,专门用于此目的。我旋转它,放大我的数据集的随机图像。这有助于创建一个模型,更智能地识别不同情况下的建筑物。并且它还增加了数据中的图像数量,这与结果的良好预测成正比。
带有预训练 vgg16 编码器的 UNET 模型 -我使用预训练的权重来微调我的模型。预训练模型在不同于手头任务的任务上被训练,但是提供了非常有用的起点,因为在旧任务上训练时学到的特征对于新任务是有用的。我已经采取了 vgg16 的编码器部分,并把它的权重是“预先训练的图像网络”使用相同的名称。然后,我根据编码层的结构创建了解码层,通过相应地对其进行上采样,并将这些层“连接”到它们各自的编码层。然后我已经把激活函数取为“亚当”,损耗取为“二元交叉熵”。
迭代——迭代/历元数我取 100。并且相应地使用等于测试图像除以所取批量的 step_per_epoch。这同样适用于验证集。
实施情况和结果


raw image(left)………………………………………………………………………………….. processed image(right)
优点和缺点
优点-
这是一种非常有效和简单的技术,可以获得高精度的结果。
这是一项不断改进的最新技术,会定期更新,以便我们将来拥有更好的模型。
您可以在很少的数据中获得很高的准确性。
- 它易于学习和实施
缺点-
它需要非常高的计算能力,这使得它是一个有点昂贵的过程。
高端 GPU(图形处理单元)是先决条件,否则将花费太多时间进行训练。
某些标记图像的边界部分有时不太清晰,但这可以通过使用大型数据集或应用 CRF(条件随机场)来解决。
超参数调整是一个耗时的过程。
结论
因此,我的结论是,通过使用 UNET,预先训练的 VGG-16 作为编码器,我们可以用非常有限的数据集获得高精度。我只拍摄了 200 张图像,经过训练,准确率达到了 98.5%。我还尝试了不同数量的数据来检查结果,如 2000 张图像,6000 张图像,结果令人满意。由于它的学习与数据的数量成正比,所以提供大数据有助于获得智能学习和更好的结果。我还应用了图像增强,这也有助于通过提高训练数据集的质量来获得更好的结果。因此,总的来说,这是一种非常有效的图像分割技术,用于提取航空图像中的建筑物等特征。
语义分割—流行的架构
用数据做很酷的事情!

Semantic Segmentation
什么是语义切分?
语义分割的任务是将图像中的每个像素分类,如下图所示。在这里你可以看到所有的人都是红色的,道路是紫色的,车辆是蓝色的,街道标志是黄色的,等等。
语义分割不同于实例分割,实例分割是同一类的不同对象将具有不同的标签,如在 person1、person2 中,因此具有不同的颜色。下图非常清晰地说明了实例分割和语义分割的区别。

Different tasks in computer vision
一个重要的问题可能是,为什么我们需要这种逐像素理解像素位置的粒度?
我想到的一些例子有:
I)自动驾驶汽车——可能需要知道另一辆汽车在路上的确切位置,或者过马路的人的位置
ii)机器人系统——如果机器人知道两个部件的确切位置,那么它们将会表现得更好
iii)损坏检测——在这种情况下,了解损坏的确切程度可能很重要
面向语义分割的深度学习模型架构
现在让我们来讨论 3 种进行语义分割的模型架构。
1。【FCN】
FCN 是一种流行的语义分割算法。该模型使用各种卷积块和最大池层,首先将图像解压缩到其原始大小的 1/32。然后,它在这个粒度级别上进行分类预测。最后,它使用采样和反卷积层来调整图像的大小到原始尺寸。

Fully Convolutional Network
这些模型通常没有任何完全连接的层。下采样步骤的目标是捕获语义/上下文信息,而上采样的目标是恢复空间信息。图像大小也没有限制。最终图像与原始图像大小相同。为了完全恢复下采样中丢失的细粒度空间信息,使用了跳过连接。跳过连接是至少绕过一个层的连接。这里,它用于将信息从下采样步骤传递到上采样步骤。合并不同分辨率级别的要素有助于将上下文信息与空间信息结合起来。
我训练了一个 FCN 来为自动驾驶汽车执行语义分割或道路与非道路像素。
2。U-Net
U-Net 架构建立在完全卷积网络(FCN)的基础上,并经过修改,在医学成像中能够产生更好的分割效果。
与 FCN-8 相比,两个主要区别是:
(1)U-网是对称的,并且
(2)下采样路径和上采样路径之间的跳跃连接应用串联运算符而不是求和。
这些跳跃连接旨在向上采样时向全局信息提供局部信息。由于其对称性,网络在上采样路径中具有大量特征图,这允许传递信息。B
U 形网因其对称的形状而得名,不同于其他 FCN 变体。
U-Net 架构分为 3 个部分:
1:收缩/下采样路径
2:瓶颈
3:扩展/上采样路径

U-net model
我已经实现了用于烟雾分割的 U-net。U-net 的一个主要优点是运行速度比 FCN 或 Mask RCNN 快得多。
3。屏蔽 RCNN
先来温柔的介绍一下 Mask RCNN。

Mask RCNN Model
更快的 RCNN 是一个非常好的算法,用于物体检测。更快的 R-CNN 由两个阶段组成。第一阶段,称为区域提议网络(RPN),提议候选对象包围盒。第二阶段本质上是快速 R-CNN,使用 RoIPool 从每个候选框中提取特征,并执行分类和包围盒回归。这两个阶段所使用的特征可以被共享以用于更快的推断。
屏蔽 R-CNN 在概念上很简单:更快的 R-CNN 对每个候选对象有两个输出,一个类标签和一个边界框偏移量;为此,我们添加了第三个分支,输出对象遮罩—这是一个二进制遮罩,指示对象在边界框中的像素位置。但是额外的遮罩输出不同于类和框输出,需要提取对象的更精细的空间布局。为此,RCNN 使用全卷积网络(FCN)。
简而言之,我们可以说 Mask RCNN 将两种网络——更快的 RCNN 和 FCN——结合在一个大型架构中。模型的损失函数是进行分类、生成包围盒和生成掩模的总损失。
掩模 RCNN 有几个额外的改进,使它比 FCN 更准确。你可以在他们的论文中读到更多关于他们的内容。
我已经使用 Keras Matterport github 和 Tensorflow 对象检测训练了自定义掩膜 RCNN 模型。要学习如何自己制作一个面具 RCNN,请跟随车损检测博客的教程。
我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/来看看我们吧。
你也可以在 https://medium.com/@priya.dwivedi 的看到我的其他作品
如果你有一个我们可以合作的项目,请通过我的网站或 info@deeplearninganalytics.org 联系我
参考资料:
使用深度可分离残差神经网络的语义分割

Semantic segmentation using Google deep-lab v3
在这篇博客中,我们将看到如何使用深度可分离残差神经网络来执行语义分割。使用可分离的卷积神经网络代替传统的 2D 卷积也被阐明。
数据集描述
对于图像分割任务,我们将使用由 Divam Gupta 准备的示例数据。分割数据可从- 驱动器获得。总共有 12 个分割类和总共 367 个图像及其相应的注释。
数据的可视化
使用下面用 python 3 编写的代码块可以很容易地将数据可视化。
下面提到的代码代表下载数据的目录。
dir_data = “dataset1/”
dir_seg = dir_data + “/annotations_prepped_train/”
dir_img = dir_data + “/images_prepped_train/”
可视化部分如下。
import cv2, os
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns## seaborn has white grid by default so I will get rid of this.
sns.set_style(“whitegrid”, {‘axes.grid’ : False})ldseg = np.array(os.listdir(dir_seg))
## pick the first image file
fnm = ldseg[300]
print(fnm)## read in the original image and segmentation labels
seg = cv2.imread(dir_seg + fnm ) # (360, 480, 3)
img_is = cv2.imread(dir_img + fnm )
print(“seg.shape={}, img_is.shape={}”.format(seg.shape,img_is.shape))## Check the number of labels
mi, ma = np.min(seg), np.max(seg)
n_classes = ma — mi + 1
print(“minimum seg = {}, maximum seg = {}, Total number of segmentation classes = {}”.format(mi,ma, n_classes))fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(1,1,1)
ax.imshow(img_is)
ax.set_title(“original image”)
plt.show()fig = plt.figure(figsize=(15,10))
for k in range(mi,ma+1):
ax = fig.add_subplot(3,n_classes/3,k+1)
ax.imshow((seg == k)*1.0)
ax.set_title(“label = {}”.format(k))plt.show()

The visualization output consisting of 12 classes of annotations for a single image.
数据预处理
数据预处理步骤仅包括将图像的尺寸调整到(224,224)的形状。这是用于 ResNet -50 网络的常规形状,因此也用于我们的可分离残差神经网络。
调整大小的图像的可视化。
import randomdef give_color_to_seg_img(seg,n_classes):
‘’’
seg : (input_width,input_height,3)
‘’’
if len(seg.shape)==3:
seg = seg[:,:,0]
seg_img = np.zeros( (seg.shape[0],seg.shape[1],3) ).astype(‘float’)
colors = sns.color_palette(“hls”, n_classes)
for c in range(n_classes):
segc = (seg == c)
seg_img[:,:,0] += (segc*( colors[c][0] ))
seg_img[:,:,1] += (segc*( colors[c][1] ))
seg_img[:,:,2] += (segc*( colors[c][2] ))return(seg_img)input_height , input_width = 224 , 224
output_height , output_width = 224 , 224ldseg = np.array(os.listdir(dir_seg))
for fnm in ldseg[np.random.choice(len(ldseg),3,replace=False)]:
fnm = fnm.split(“.”)[0]
seg = cv2.imread(dir_seg + fnm + “.png”) # (360, 480, 3)
img_is = cv2.imread(dir_img + fnm + “.png”)
seg_img = give_color_to_seg_img(seg,n_classes)fig = plt.figure(figsize=(20,40))
ax = fig.add_subplot(1,4,1)
ax.imshow(seg_img)
ax = fig.add_subplot(1,4,2)
ax.imshow(img_is/255.0)
ax.set_title(“original image {}”.format(img_is.shape[:2]))
ax = fig.add_subplot(1,4,3)
ax.imshow(cv2.resize(seg_img,(input_height , input_width)))
ax = fig.add_subplot(1,4,4)
ax.imshow(cv2.resize(img_is,(output_height , output_width))/255.0)
ax.set_title(“resized to {}”.format((output_height , output_width)))
plt.show()

The resized images.
从上面的图片中我们可以看到,调整图片的大小确实改变了图片的长宽比,但是对文件的注释图片没有太大的影响。
现在,让所有的图像调整到(224,224)的大小。下面的代码可以用来做这件事。
def getImageArr( path , width , height ):
img = cv2.imread(path, 1)
img = np.float32(cv2.resize(img, ( width , height ))) / 127.5–1
img1 = cv2.cvtColor(img,cv2.COLOR_BGR2LAB)
img = cv2.merge((img,img1))
#print(img.shape)
return imgdef getSegmentationArr( path , nClasses , width , height ):seg_labels = np.zeros(( height , width , nClasses ))
img = cv2.imread(path, 1)
img = cv2.resize(img, ( width , height ))
img = img[:, : , 0]for c in range(nClasses):
seg_labels[: , : , c ] = (img == c ).astype(int)
##seg_labels = np.reshape(seg_labels, ( width*height,nClasses ))
return seg_labelsimages = os.listdir(dir_img)
images.sort()
segmentations = os.listdir(dir_seg)
segmentations.sort()
X = []
Y = []
for im , seg in zip(images,segmentations) :
X.append( getImageArr(dir_img + im , input_width , input_height ) )
Y.append( getSegmentationArr( dir_seg + seg , n_classes , output_width , output_height ) )X, Y = np.array(X) , np.array(Y)
print(X.shape,Y.shape)

The data and the label shape.
模型开发
该模型是一个深度可分离的残差神经网络。用可分离卷积范式代替传统的 2D 卷积运算,降低了模型的参数复杂度。
传统的卷积方法使用基于梯度的学习,因此消失梯度和精度下降是卷积范例的两个主要问题,卷积范例指出,随着参数复杂性的增加,由于模型损失的增加,模型的精度降低。
残余建筑
残差架构类似于 ResNet-50 模型,其避免了基于梯度的学习,但是使得残差学习范式能够通过模型获得最佳结果。所提出的残差模型具有 4 个残差块,其中每个残差块依次具有 3 个可分离卷积层以及与单个可分离卷积方法的快捷连接。
剩余网络定义如下。
def residual_block(mod_, f_in, f_out, strides_ = (1,1), use_shortcut_ = False):
shortcut_ = mod_
k_ = (3,3)
mod_ = SeparableConv2D(f_in, kernel_size=k_, strides=(1,1), padding = “same”)(mod_)
mod_ = BatchNormalization()(mod_)
mod_ = ELU()(mod_)
mod_ = SeparableConv2D(f_in, kernel_size=k_, strides=strides_, padding = “same”)(mod_)
mod_ = BatchNormalization()(mod_)
mod_ = ELU()(mod_)
mod_ = SeparableConv2D(f_out, kernel_size=k_, strides=(1,1), padding = “same”)(mod_)
mod_ = BatchNormalization()(mod_)
mod_ = ELU()(mod_)
if use_shortcut_ == True or strides_ != (1,1):
shortcut_ = SeparableConv2D(f_out, kernel_size=k_, strides=strides_, padding = “same”)(shortcut_)
shortcut_ = BatchNormalization()(shortcut_)
mod_ = Add()([shortcut_, mod_])
mod_ = ReLU()(mod_)
return mod_
剩余网络可以图示如下。

Residual block of our proposed network.
上采样反卷积层
上采样层将低分辨率图像提高到高分辨率。有各种各样的上采样方法。所提出的方法将转置卷积层用于上采样,这可以被最好地描述如下。该方法简单地反转卷积的向前和向后传递,并在 Keras 的 Conv2DTranspose 中实现。
def model_build(in_):
IMAGE_ORDERING = “channels_last”
k_=(3,3)
mod_ = Conv2D(16, kernel_size=k_, strides = (1,1), padding = “same”)(in_)
mod_ = BatchNormalization()(mod_)
mod_ = ReLU()(mod_)
mod_ = MaxPooling2D()(mod_)
mod_ = residual_block(mod_, 16, 32, use_shortcut_=True)
mod_ = MaxPooling2D()(mod_)
mod_ = residual_block(mod_, 32, 64, use_shortcut_=True)
mod_ = MaxPooling2D()(mod_)
pool3 = mod_
mod_ = residual_block(mod_, 64, 96, use_shortcut_=True)
mod_ = MaxPooling2D()(mod_)
pool4 = mod_
mod_ = residual_block(mod_, 96, 128, use_shortcut_=True)
mod_ = MaxPooling2D()(mod_)
pool5 = mod_
n = 2048
nClasses = 12
o = ( Conv2D( n , ( 7 , 7 ) , activation=’relu’ , padding=’same’, name=”conv6", data_format=IMAGE_ORDERING))(pool5)
conv7 = ( Conv2D( n , ( 1, 1 ) , activation=’relu’ , padding=’same’, name=”conv7", data_format=IMAGE_ORDERING))(o)
## 4 times upsamping for pool4 layer
conv7_4 = Conv2DTranspose( nClasses , kernel_size=(4,4) , strides=(4,4) , use_bias=False, data_format=IMAGE_ORDERING )(conv7)
## (None, 224, 224, 10)
## 2 times upsampling for pool411
pool411 = ( Conv2D( nClasses , ( 1 , 1 ) , activation=’relu’ , padding=’same’, name=”pool4_11", data_format=IMAGE_ORDERING))(pool4)
pool411_2 = (Conv2DTranspose( nClasses , kernel_size=(2,2) , strides=(2,2) , use_bias=False, data_format=IMAGE_ORDERING ))(pool411)
pool311 = ( Conv2D( nClasses , ( 1 , 1) , activation=’relu’ , padding=’same’, name=”pool3_11", data_format=IMAGE_ORDERING))(pool3)
o = Add(name=”add”)([pool411_2, pool311, conv7_4 ])
o = Conv2DTranspose( nClasses , kernel_size=(8,8) , strides=(8,8) , use_bias=False, data_format=IMAGE_ORDERING )(o)
o = (Activation(‘softmax’))(o)
return o## The model input and summary##in_ = Input((224,224,3))
model_f = model_build(in_)
model = Model(input = in_, output = model_f)
model.compile(optimizer = RMSprop(), loss = "categorical_crossentropy", metrics=["accuracy"])model.summary()
通过执行上面的代码,可以绘制和可视化模型摘要。RMSprop 已经被用作具有分类交叉熵损失的优化器。
数据集的训练和测试分割。
关于训练和测试数据,数据集已经以 85:15 的比例分割。训练和测试数据没有任何重叠图像。
from sklearn.utils import shuffle
train_rate = 0.85
index_train = np.random.choice(X.shape[0],int(X.shape[0]*train_rate),replace=False)
index_test = list(set(range(X.shape[0])) — set(index_train))
X, Y = shuffle(X,Y)
X_train, y_train = X[index_train],Y[index_train]
X_test, y_test = X[index_test],Y[index_test]
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
模特培训
训练参数如下。
nb_epochs = 180
nb_batch = 32earlyStopping=EarlyStopping(monitor=’val_loss’, patience=10, verbose=0, mode=’auto’)lr_reduce = ReduceLROnPlateau(monitor=’val_acc’, factor=0.01, epsilon=0.0001, patience=2, verbose=1)save_path=”weights/sep_kernel3_res4_85_lab.h5"checkpoint = ModelCheckpoint(save_path, monitor=’val_acc’, verbose=1, save_best_only=True, mode=’max’)
模特培训
hist1=model.fit(X_train, y_train, epochs = nb_epochs, batch_size = nb_batch, callbacks=[checkpoint,earlyStopping,lr_reduce], validation_data=(X_test, y_test), verbose = 1)
模型评估
绘制培训损失曲线
for key in [‘loss’, ‘val_loss’]:
plt.plot(hist1.history[key],label=key)
plt.legend()
plt.show()

Training Loss
并集或 IOU 的交集计算如下:
def IoU(Yi,y_predi):
## mean Intersection over Union
## Mean IoU = TP/(FN + TP + FP)IoUs = []
Nclass = int(np.max(Yi)) + 1
for c in range(Nclass):
TP = np.sum( (Yi == c)&(y_predi==c) )
FP = np.sum( (Yi != c)&(y_predi==c) )
FN = np.sum( (Yi == c)&(y_predi != c))
IoU = TP/float(TP + FP + FN)
print(“class {:02.0f}: #TP={:6.0f}, #FP={:6.0f}, #FN={:5.0f}, IoU={:4.3f}”.format(c,TP,FP,FN,IoU))
IoUs.append(IoU)
mIoU = np.mean(IoUs)
print(“_________________”)
print(“Mean IoU: {:4.3f}”.format(mIoU))
IoU(y_testi,y_predi)

The classwise IOU and the mean IOU
模型性能的可视化
该模型的预测能力通过下面这段代码来可视化。
shape = (224,224)
n_classes= 10for i in range(10):
img_is = (X_test[i] + 1)*(255.0/2)
seg = y_predi[i]
segtest = y_testi[i]fig = plt.figure(figsize=(10,30))
ax = fig.add_subplot(1,3,1)
ax.imshow(img_is/255.0)
ax.set_title(“original”)
ax = fig.add_subplot(1,3,2)
ax.imshow(give_color_to_seg_img(seg,n_classes))
ax.set_title(“predicted class”)
ax = fig.add_subplot(1,3,3)
ax.imshow(give_color_to_seg_img(segtest,n_classes))
ax.set_title(“true class”)
plt.show()
以下代码的输出如下。

The prediction ability of the model is fine but can be optimized.
语义分割:通过 TensorBoard 可视化学习进度
介绍
神经网络的构建和训练不是一个简单的过程,除非你使用 MNIST 数据集,这是深度学习世界中的一种“Hello world”应用程序。很容易犯错误,花几天时间去想为什么网络没有达到您期望的性能。通常,深度学习库有一些 API,允许在训练期间探索模型和模型行为。但是它们非常受限制,并且需要额外的可视化编程。在本文中,我们将使用 TensorBoard 来可视化 CNN 的训练。例如,我们将对 ISBI 挑战赛 2012 数据集使用语义分段。本文的完整代码可以在 Github 上找到。
什么是 TensorBoard?
TensorBoard 是一个工具,用于可视化张量流图、关于图形执行的量化指标以及可以帮助您了解神经网络行为的附加数据。
从软件的角度来看,TensorBoard 是一个网络服务器,它监控某个目录,并将存储在其文件中的数据显示为图形、图表、直方图、图像等。TensorFlow 程序在执行过程中向目录提供数据。服务器读取数据并将其可视化。由开发人员决定必须显示哪些数据。TensorBoard 可以绘制标量图(例如,损失、准确度的线图)、图像(例如,当前预测图像)、直方图(作为权重分布)。除此之外,TensorBoard 还可以将您的模型显示为交互式图形。
使用 TensorBoard 服务很简单:在你的程序代码中添加中间训练数据,启动 TensorBoard,你就可以监控你的模型的训练进度。
TensorBoard 预装了 TensorFlow。以下命令启动 TensorBoard 服务:
tensorboard —-logdir *logs*
其中日志是包含要监控的数据的目录的路径。
如果要在特定端口上启动 TensorBoard,可以使用端口参数:
tensorboard —-logdir *logs --port=9000*
默认情况下,TensorBoard 仅在本地主机上提供服务。参数 bind_all 允许在所有网络接口上绑定。
tensorboard —-logdir *logs --port=9000 --bind_all*
或者,您可以使用 host 参数指定主机名或 IP 地址,将 TensorBoard 暴露给特定的主机。
你的数据怎么写?
TensorFlow 提供了一组 API,用于以 TensorBoard 可以理解的格式序列化您的数据。以下是可用的序列化函数:
- 标量 —写入单个值的历史,如损失、准确性等。
- 图像 —写入图像的历史。
- 直方图 —记录某个张量的数据分布历史。
- text —写一个字符串型张量的历史。
- 音频 —写入音频样本的历史(包含音频数据的张量)。
- tensor_summary —写一个任意张量的历史。
每个函数都接受一个张量作为输入数据,并返回一个 protobuf 字符串,该字符串可以由一个 FileWriter 对象写入磁盘。此外,可以使用函数 merge 和 merge_all 将摘要合并到集合中。
如果你使用 Keras,你不必直接使用函数。Keras 提供了一个方便的 TensorBoard 回调,它将为您完成大部分工作。
TensorBoard 的一个很好的特性是可以在同一个图上显示几次运行的指标。通过这种方式,可以比较不同超参数的模型行为。你要做的只是把不同跑步的日志保存在 TensorBoard 文件夹的不同子目录下。您可以随时打开/关闭管路的可视化。
电镜图像中神经元突起的 2D 分割
在下面的例子中,我们将使用 TensorBoard 对 EM 堆叠中神经元结构分割的模型训练进行可视化( ISBI 挑战数据集)。
数据集描述
训练数据是来自连续切片透射电子显微镜(ssTEM)的一组 30 个图像。
相应的二进制标签以进出的方式提供,即白色用于分割对象的像素,黑色用于其余像素(主要对应于膜)。
换句话说,我们在一个 tiff 文件中组合了 30 个灰度图像(每个图像在一个单独的页面中),在另一个 tiff 文件中组合了 30 个黑/白蒙版。

A sample image and corresponded label mask from the ISBI dataset
显然,30 幅图像不足以训练一个卷积网络,因此使用了诸如旋转、移位、剪切、缩放和翻转之类的增强。
网络架构
在本文中,我们使用了一个对称变体的 U-net 卷积神经网络(https://github.com/zhixuhao/unet)。通过在原始模型中使用“相同”填充而不是“有效”来实现对称。

U-net neural network
上面的模型在 Keras 中实现。完整的源代码可以在 Github 资源库中找到。
Keras TensorBoard 复试
Keras 提供了一个方便的回调函数,使得 TensorBoard 的使用更加容易。
在本文中,我们将使用以下参数:
- log_dir —保存数据的目录路径。
- histogram_freq —权重直方图的保存频率。1-对于每个时期,2-对于每第二个时期,等等。
- write_graph — 一个布尔标志。如果应保存模型图,则为 True。
- 更新频率— 数据序列化的频率。可能的值:“batch”代表每一批,“epoch”代表每一个 epoch,或者是一个以样本数定义序列化频率的整数。
网络图
将参数 write_graph 设置为 True 会触发模型图形的序列化。为您的图层提供用户友好的名称非常重要,以便您可以在图表中识别它们。下图是 TensorBoard 为本文使用的 U-net 架构制作的。请注意,该图与上面的网络图非常相似。TensorBoard 的一个很好的特性是用相同的颜色给相同结构的层着色。

Model graph produced by TensorBoard (rotated)
标量图
参数 update_freq 控制指标序列化的频率。在本文中,除了损失之外,我们还序列化了准确度和一个自定义指标——错误分类像素的相对数量:
注意:该函数将在训练期间执行,因此我们必须使用 TensorFlow 函数来操纵张量。Numpy 函数在这里不起作用。
这是你需要为 TensorBoard 编写的序列化模型图形和度量的全部代码。注意,在示例中,TensorBoard 目录包含损失函数的名称和学习率。因为我想探索我的模型如何收敛于不同的损失函数和不同的速率,所以我将每次运行的文件输出到 log 文件夹的不同子目录中。它允许我比较同一地块上的可视化不同运行,并比较模型性能:

直方图和分布图
将参数 histogram_freq 设置为 1 导致权重的串行化和每个时期的网络层的激活。两个新菜单项:分布和直方图出现在 TensorBoard 仪表盘中。重要的是要知道,如果我们想要可视化直方图,我们不能使用验证数据的生成器。如果你尝试这样做,TensorFlow 会抛出一个错误。

Distribution plots produced by TensorBoard

Histograms produced by TensorBoard
自定义图像的序列化
Keras 的 TensorBoard 回调提供了参数 write_images ,该参数触发网络层图像的序列化。因为语义分割有助于可视化预测结果,以获得网络表现如何的感觉。这可以通过创建自定义回调和使用 TensorFlow 图像汇总 API 来实现。让我们来看看 Keras 自定义回调的结构:
自定义回调类包含几个将在特定事件上执行的方法。为了监控训练过程的进展,我们使用 on_batch_end 方法,并为每批生成预测结果和相应标签的图像。
现在我们创建该类的一个实例,并将其添加到回调列表中。
现在—开始训练,启动 TensorBoard 并监控进度。下图显示了 TensorBoard dashboard 的屏幕截图,比较了均方误差和二元交叉熵损失函数的分割进度。

结论
我发现 TensorBoar 对于监控模特的训练过程非常有用。它允许用几行代码可视化中间步骤。
语义相似度分类器和基于语义相似度的句子聚类。

最近,我们一直在做一些实验,通过利用预先训练的模型来聚集语义相似的消息,这样我们就可以在不使用标记数据的情况下获得一些东西。这里的任务是给定一个句子列表,我们对它们进行聚类,使得语义相似的句子在同一个聚类中,并且聚类的数量不是预先确定的。
语义相似度分类器的任务是:对给定的两个句子/消息/段落进行语义等价的分类。
第一步:通过嵌入来表示每个句子/信息/段落。对于这个任务,我们使用了 infersent,它工作得很好。
*InferSent* is a *sentence embeddings* method that provides semantic representations for English sentences. It is trained on natural language inference data and generalizes well to many different tasks.
推断句嵌入。在 GitHub 上创建一个帐户,为 Facebook research/INF sent 开发做贡献。
github.com](https://github.com/facebookresearch/InferSent)
代码如下:
*# Load infersent model*
model_version = 2
MODEL_PATH = "infersent_sentence_encoder/infersent**%s**.pkl" % model_version
params_model = {'bsize': 64, 'word_emb_dim': 300, 'enc_lstm_dim': 2048,
'pool_type': 'max', 'dpout_model': 0.0, 'version': model_version}
model = InferSent(params_model)
model.load_state_dict(torch.load(MODEL_PATH))*# If infersent1 -> use GloVe embeddings. If infersent2 -> use InferSent embeddings.*
W2V_PATH = 'infersent_sentence_encoder/GloVe/glove.840B.300d.txt' **if** model_version == 1 **else** 'infersent_sentence_encoder/fastText/crawl-300d-2M.vec'
model.set_w2v_path(W2V_PATH)#load data
ds = pd.read_msgpack('./ds.mp')
sentences = ds['text']# generate infersent sentence embeddings
model.build_vocab(sentences, tokenize=**True**)
embs = model.encode(sentences, tokenize=**True**)
步骤 2:寻找语义相似的句子/信息/段落的候选
这里的想法是索引每个句子/消息/段落的表示(嵌入),并基于距离阈值为每个句子挑选 k (=10)个 NN(最近邻)候选。我们发现 nmslib 非常快速高效。
**import** **nmslib**
NTHREADS = 8
**def** create_index(a):
index = nmslib.init(space='angulardist')
index.addDataPointBatch(a)
index.createIndex()
**return** index**def** get_knns(index, vecs, k=3):
**return** zip(*index.knnQueryBatch(vecs, k=k,num_threads=NTHREADS))nn_wvs = create_index(embs)to_frame = **lambda** x: pd.DataFrame(np.array(x)[:,1:])idxs, dists = map(to_frame, get_knns(nn_wvs, embs, k=10))catted = pd.concat([idxs.stack().to_frame('idx'), dists.stack().to_frame('dist')], axis=1).reset_index().drop('level_1',1).rename(columns={'level_0': 'v1', 'idx': 'v2'})
第三步:获得候选对在语义相似度分类器上的预测概率。(关于语义相似性分类器的细节将在以后的博客文章中介绍)
把第二步想成候选生成(侧重于召回),第三步想成侧重于精度。在所有被认为是潜在重复的候选者中,我们给每一对分配概率。
步骤 4:聚集聚类以合并聚类
基于在步骤 3 中被认为是重复的候选者,我们使用 scikit 中的凝聚聚类实现来合并聚类。在凝聚聚类中,所有观察值都从它们自己的聚类开始,并且使用指定的合并标准合并聚类,直到收敛,此时不再发生合并。
[## sk learn . cluster . agglomerate clustering-sci kit-learn 0 . 21 . 2 文档
连通性矩阵。为每个样本定义遵循给定数据结构的相邻样本。这可以…
scikit-learn.org](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html)
这在实践中工作得相当好,并且形成的集群具有良好的语义等价性。
规模语义学:BERT + Elasticsearch

随着 BERT、bert-as-service 等工具的出现,以及对弹性搜索中密集向量操作的支持,大规模语义搜索成为可能。虽然程度可能因使用案例而异,但搜索结果肯定会受益于用语义结果增加基于关键字的结果…
跨文本库的基于关键字的搜索是一项众所周知的技术。Lucene 库和像 Elasticsearch 这样的工具擅长闪电般快速地检索给定查询的匹配文档。搜索结果由术语/令牌及其周围的 tf-idf 指标驱动。一般来说,与查询不共享任何公共术语的文档不会成为结果集的一部分。这是基于关键字的搜索的特征。这可以清楚地排除许多否则相关的文档,但是那些不与查询共享任何关键词的文档。仔细使用同义词和词干有助于提高回忆。但是什么时候同义词意味着完全平等了?我们可能认为 sunny 是 bright 的同义词。有明月却没有晴月——从来没有。至少在我们的星球上没有!此外,用于扩展查询的罕见同义词可能会将本来较差的结果推到最前面。还有词干?是的,让我们甚至不要谈论它。一个流道不同于流道或流道!显然,所有这些围绕关键词的阴谋诡计都无法解决文本中的语义问题。
诸如潜在语义分析(LSA)的方法在过去已经被用于在搜索结果中包括语义相关的文档。但是奇异值分解(SVD)在从分布在节点集群上的数百万个文档构建的术语-文档矩阵上的应用不是微不足道的。基于奇异值分解的语义搜索在弹性搜索处理的规模和吞吐量上是不切实际的。那么,如果我们想用 Elasticsearch 实现语义,我们该怎么办呢?
最近流行的单词固定大小的数字向量会有所帮助。使用单词包方法的单词嵌入可以将一个句子或一个文档变成一个短的密集的数字向量。我们已经在以前的 文章中详细讨论过这个问题。像从像 BERT 这样的语言模型中获得的嵌入是上下文敏感的,也不同于一键单词向量或 fastText 嵌入。也就是说,对于“吃饭为了活着”vs“活着为了吃饭”,我们用 BERT 得到不同的句子向量,让我们可以区分它们。实现大规模语义搜索的关键是将这些向量与弹性搜索相结合。
幸运的是,Elasticsearch 的当前版本(7.3+)支持一个具有各种相关性度量的 dense_vector 字段,如余弦相似性、欧几里德距离等,可以通过 script_score 计算。这正是我们所需要的,因为我们可以通过查询的密集向量表示,根据这些指标的得分对索引中的文档进行排序。弹性搜索闪电般的速度适用于分布在一群节点上的数百万个密集向量。这基本上是这篇文章的主旨。让我们开始吧。
1.作为经纪人的伯特
架构再简单不过了。这些部分都在开源中,我们所要做的就是把它们放在一起。我们使用 bert-as-service 来获得文档和查询的密集向量表示。索引和搜索请求通过 BERT 服务器代理,该服务器为所提供的文档或查询文本生成密集向量。

Figure 1. Indexing and querying BERT dense vectors in an Elasticsearch index
下面是一个简单的配置,它用一个句子(在我们的例子中是一个短引号)和它的数字向量作为唯一的字段定义了一个索引。根据无壳基 BERT (无壳 _L-12_H-768_A-12),向量定义为 768 长。
从文件中读取报价,通过调用 bert-as-service 计算密集向量,并批量索引到 Elasticsearch 中。
2.使用密集向量的相关性评分
Elasticsearch 采用 Lucene 的实用评分功能进行传统的基于关键字的搜索。它不适用于我们这里,因为我们处理的是数值向量。我们可以用密集向量周围的任何定制评分函数来覆盖缺省值。但出于效率原因,最好使用弹性搜索预定义的函数,如余弦相似性、L1 或 L2 范数。搜索结果的相关性顺序当然会根据使用的度量标准而有所不同。不确定是否其中一个总是比其他的好,但是余弦相似性似乎对我的测试很好。让我们看一个简单的例子。考虑下面一个文件中的三句话 sentences.txt 。
- 在公园玩耍的孩子们
- 在草地上奔跑的孩子们
- 今天交通很糟糕
明明前两句差不多。它们都与第三个不同。我们可以很容易地计算每个句子的向量,并计算不同的度量。运行Bert _ sentence _ similarity . py与:
pipenv run python ./bert_sentence_similarity.py sentences.txt
我们得到:
1 & 2 1 & 2 2 & 3
Cosine Similarity: 0.852 0.677 0.69
Inv. Manhattan Distance (L1): 0.083 0.056 0.058
Inv. Euclidean Distance (L2): 1.839 1.243 1.27
所有指标都做了正确的事情,为 1–2 对得出了最高分。在这篇文章的剩余部分,我们将坚持使用 BERT 查询的余弦相似度&句子密集向量作为弹性搜索的相关性分数。如果我们选择 L1 或 L2,热门搜索的顺序会有所不同,但我们在这里的任务是比较 BERT powered 搜索与传统的基于关键字的搜索。
3.引文索引
为了测试这个方案对我们的效果如何,我们准备了一个相当大的索引,由不同的人引用的话组成。该索引类似于第 1 节中的索引。引语长度不超过 50 个单词。该索引有几千条引用,其中肯定有一些重复的。以下是一个示例:
一旦游戏结束,国王和士兵回到同一个盒子里
他使用统计学,就像一个醉汉用灯柱来支撑而不是照明一样
你应该经常去参加别人的葬礼;否则他们不会去你家。
其他星球上的智慧生命?我甚至不确定地球上有没有!
我们知道许多不同的引语表达了相似的意思。我们用一个引用(或它的转述版本)查询索引,并检查顶部结果的质量。我们希望看到最热门的搜索结果与我们所理解的查询引用**——最相似。我们可以用 Elasticsearch 提供的更像这个 (MLT)的查询直接做到这一点,当然还有我们的 BERT 衍生向量的余弦相似性,如图 1 所示。任务是评估伯特向量是否有意义地提高了结果的质量。
查询弹性搜索
对于 MLT 查询,我们覆盖了一些默认值,以便不排除查询或文档中的任何术语。对于我们用于语义搜索的 script_score 查询,我们从 bert-as-service 获得密集的 query_vector。我们从以下内容开始:
bert-serving-start -model_dir $BERT_BASE_DIR -max_seq_len=52 -num_worker=1
其中 BERT_BASE_DIR 指向磁盘上uncased _ L-12 _ H-768 _ A-12所在的目录。下面是以这两种不同方式查询同一索引的代码片段。
4.结果
设备准备就绪后,剩下要做的就是运行一些示例查询/报价,看看 BERT powered Elasticsearch 是否能够返回比仅基于关键字丰度更有意义的结果。我们挑选了一些引言,并列比较了伯特& MLT 公司的 10 大业绩。每个结果都是根据比赛质量评分的——红色 1 分,蓝色 0.5 分,默认 0 分——当然是主观的。让我们从第一个开始。

抓住愤怒不放就像抓住一块热煤想要扔向别人——你才是那个被烧伤的人
佛

Figure 2. BERT 6 & MLT 2.5
MLT 的热门歌曲完全不相关,因为它已经被“某人”这个词劫持了。它的第八次点击被“煤”误导了,这是一个在引语库中可能很少见的术语。但是 MLT 的第六支安打被伯特错过了。总的来说,我们看到 BERT 能够提取出与查询意思相同但使用了与查询不同的单词的引号(参见 4、6 和 7)。让我们看看另一个。

对于大多数人来说,他们认定自己有多幸福,就有多幸福
亚伯林罕·林肯

Figure 3. BERT 3 & MLT 0
在这种情况下,对 MLT 来说不幸的问题是查询中使用的词的选择。最热门的话题是伯特锁定了它,但 MLT 错过了它,因为它正在寻找术语“头脑”或“制造”,但看到了“头脑”和“制造”。它自己的热门搜索完全被短语“下定决心”所占据——与查询完全匹配。使用词干分析器可能有助于 MLT 抓住伯特的热门歌曲。对于它的第二部热播剧,MLT 可能被一个可能很少见的词岔开了,比如“乡亲”和短语“化妆”,因为这句话肯定不是关于打扮的!
但是基于以上两个例子,认为 BERT 已经对传统的一键词向量造成了致命的打击还为时过早。以最后这个例子为例。

命运站在敢于冒险的人一边
维吉尔

Figure 4. BERT 0 & MLT 4
敢这个词可能是回购协议中一个罕见的词,MLT 很好地坚持了这个词,也许是整个短语谁敢。另一方面,BERT 认为(从逻辑上来说,我们可以加上) dares 与激情、灾难等相关,并发现非常不同的匹配。这通常是过度思考的问题,有人可能会说——这是对伯特不友好的攻击。
5.结论
我们已经证明,我们可以通过 Elasticsearch 获得大规模的语义搜索结果。随着 BERT、bert-as-service 等工具的出现,以及对弹性搜索中密集向量操作的支持,这一切都成为可能。语义搜索结果的质量将取决于索引中文档的性质以及语义在这些文档中是否重要。语义在大多数自由流动的文本和演讲中是很重要的,除非你在谈论方程式!这是我们结束前的最后一段引言。
数学课本如此深奥和专业的一个原因是因为所有的规范和条件都必须放在定理上,以防止它们出现裂缝。从这个意义上说,它们就像法律文件,读起来也同样有趣。
大卫·埃德加·华莱士
因此,可能会有一些没有语义或文字游戏的枯燥文本,但很少有人会想去读它,更不用说去搜索它了。所以我们开始了——任何值得搜索的文本都有语义相关的文档。
总结一下:
- 我们已经看到,用 BERT 向量增强的 Elasticsearch 可以从文档报告中提取出语义相关的结果
- 坚持使用实际的关键词有时是正确的做法,而不是像 BERT 那样试图找到向量之间的关系。在这种情况下,基于关键字的搜索占了上风。
- 有了基于关键字的结果,我们可以很容易地解释为什么一个结果上升到顶部。甚至有一个解释 api 来挖掘如何获得相关性分数的细节。这对于基于关键字的方法来说是一个明显的优势。
- 有了 BERT 驱动的语义结果,就很难理解为什么一个结果出现在最上面或者没有出现。正是密集向量决定了相关性分数。谁知道这些密集向量的所有参数是什么……除此之外,还有 1.1 亿个密集向量!
那么,我们准备好用这些语义结果取代传统的基于关键词的结果了吗?不。但是增加他们并让最终用户投票也许没有坏处!
….
原载于 2019 年 10 月 29 日【http://xplordat.com。
半监督人脸标记
使用人工智能构建您自己的自动人脸标记应用程序
自动面部标记是指当你从手机中点击一张新图片并将其上传到社交媒体时,它能够识别图像中的人,并建议你标记他们。它广泛出现在各种应用程序和平台中,包括谷歌照片和脸书。
我的目标是构建一个应用程序,可以将所有相似的面孔组合在一起。该应用程序应该是健壮的,应该根据添加的图像进行调整,而不需要任何人工干预。
这可能是你的数据科学项目之一,可以为你的简历增加价值。
这是我期望系统做的-
- 将相似的图像分组在一起;我只需要给它们贴上标签。
- 在任何新图像的情况下,它应该自动处理它们。它应该直接问我新面孔的标签。
- 只需点击一个按钮或脚本,即可改进(重新培训)系统。
这是我遵循的方法。
无人监督的
我想到的第一个方法是使用 K-Means 聚类算法。我想把相似的面孔聚集在一起,但有一个问题。您需要指定想要组成的组的数量。这给你如何决定一个最佳的 k 值制造了许多障碍。
例如,如果你有 400 张照片想要添加标签,但令人惊讶的是,所有的照片都是同一个人。在这种情况下,确定 k 的最佳值几乎是不可能的。
这种方法没有像我预期的那样奏效。
监督
我需要某种监督学习,因此我决定用 KNN 算法。我创建了一个文件夹,其中有以图像名称作为标签的唯一图像。它的工作,但这不是我最初想要的。
如果我试着在一些相似的新图像上使用它,那么它不会把它们聚集在一起。它只是要告诉他们是否属于被监督的组。
此外,随着不同的新面孔的加入,我需要在代表该群体的独特图像上重新训练模型。工作量太大了。
半监督的
如果你的算法超级聪明,可以像聚类一样将相似的脸分组在一起,但没有指定 k 值,那会怎么样?这就是为什么我称这种方法为半监督。
所以,这就是我们要做的。
- 将所有需要标记的图像复制到一个文件夹中。
- 迭代图像,找到所有图像的面部标志点,并将它们存储在字典中。
- 获取第一幅图像及其面部标志点,并在其上训练 KNN。
- 迭代所有剩余的图像,并尝试用新的关键点预测结果。如果它们匹配,则认为它是相同的图像,否则在其上训练新的分类器。
- 最终,每个集群都有一个单独的 KNN 模型。
这种方法可能看起来有点奇怪,但是让我们了解一下在处理一些新图像时它的一些好处。
我们正在考虑一些新图像需要预处理的情况。
- 我们将通过已经存在的每个分类器来预测新图像的结果。如果它与其中任何一个匹配,那么它将被添加到该组。
- 在不匹配的情况下,将执行类似于训练的步骤,并且将训练新的分类器,并且将在其上预测所有剩余的图像。
这是开始自动面部标记的最基本的方法之一。
那么,我们如何给被创建的组贴标签呢?
我有一个想法,但不是最聪明的。您需要创建一个映射,将一个人的名字与该组进行映射。每当添加新图像时,它会告诉使用该映射的人的姓名。听起来很酷,对吧?
这是 GitHub 回购协议的链接。
装置
我在普通的 python 环境下安装 dlib 有困难,这就是我选择 Docker 的原因。
如果你已经成功安装了工作 dlib,那么只需将face _ recognition _ API . py文件复制到半监督或监督文件夹,你需要将方法从 docker 改为 direct type。
如果你不想要这种混乱,那么就使用 docker。如果你想了解更多关于 Docker 的信息,这里有一个链接。
使用 Docker 的机器学习模型部署中的动手学习,并提供各种示例。
towardsdatascience.com](/docker-made-easy-for-data-scientists-b32efbc23165)
要使用 Docker way(假设您已经安装了 Docker ),请在面部标志 API 文件夹中键入以下命令。
$ docker build -t facial_landmark_api .
$ docker run -d -p 5000:5000 facial_landmark_api
要检查 docker 容器是否正在运行,请键入
$ docker ps -a
你会看到一个集装箱在运行。
在此之后,将所有您想要分类的图像复制到图像文件夹中(在半监督文件夹中)。然后简单运行 classify.py 文件。
这个项目从一开始就很好。
这里有一些你可以贡献的东西。
- 将重新训练模型的脚本。
- 考虑到我们希望面向百万用户进行扩展,这是一个更好的架构。
- 任何你想补充的东西。
快乐学习!
使用 Python SMTP 发送数据警报
数据专业人员权威指南(商业智能)
使用 Python smtplib 发送业务报告和电子邮件

Source: Unsplash
问题陈述:
对于数据科学家来说,将报告传达给非技术用户是非常重要的,尤其是当数据中存在异常时。根据我的工作经验,大多数分析师会手动向用户发送业务报告,他们会处理数据,运行一些验证,并生成报告通过 Outlook/gmail 发送。所有这些都需要很多时间,并为人为错误留有余地。
如果我们可以通过分析我们数据的同一个 Python 程序来自动化业务报告和警报,那会怎么样?
这将节省大量的时间和麻烦!
输入 Python SMTP 库

简单邮件传输协议(SMTP)允许用户向另一个用户发送邮件。当您从 Python 应用程序推送邮件时,用户将通过邮局协议(POP)和互联网消息访问协议(IMAP)接收邮件。这些是 Outlook 和 Gmail 等标准电子邮件界面的基础。
SMTP 允许服务器通过 TCP 连接监听电子邮件请求,然后通过端口 587 发送电子邮件。
Python SMTP 的实际应用

Our Application in Big Picture, today we are going to learn how to build Python Alerts with SMTP
在本教程中,您将学习如何使用 Python SMTP 生成电子邮件提醒。
我们将访问我们以前在构建仪表板 Web 应用的项目,使用任务调度器到从 Lazada (电子商务)网站抓取数据,并将其转储到 SQLite RDBMS 数据库。根据用户确认的产品,我们将检查价格是否从原始价格下降,并使用它来生成警报。
请随意欣赏这篇文章或访问我的 Github Repo 获取完整代码。或者向下滚动,欣赏这篇文章。
对于不熟悉我提到的仪表板 Web 应用程序的人来说。我正在建立一个基于 Lazada 报废产品价格变化的仪表板。每当用户修改输入下拉菜单时,如果产品价格下降,应用程序会提醒用户。
我们的任务是分配一个 webhook,一旦你修改了下拉菜单参数,它就会发送一封电子邮件。

Price Optimization Dashboard Scraped from Lazada over 3 days + Email SMTP
以下是实现这一目标的关键步骤:
- 导入 Python SMTP
- 生成电子邮件和 SMTP 服务器属性
- 发送电子邮件请求
- 使用我们的 Python Dash 仪表板准备 Webhooks
- 为电子邮件验证机密创建配置文件
导入和激活 Python SMTP
当您下载 Python 包时,Python smtplib 已经内置。如果您已经运行了它,您可以像下面这样导入 smtplib
import smtplib
要激活 SMTP 连接,您需要通过替换如下标记来插入您的身份验证凭据:
gmail_user = '<input your gmail user. No need to use @gmail.com>'
gmail_password = '<input your gmail password>'
仅此而已!非常容易。

Source: Giphy
生成电子邮件和 SMTP 服务器属性
创建电子邮件时,您需要考虑两个部分:电子邮件属性和电子邮件发送请求。
在邮件属性中,您可以设置:
#email properties
sent_from = gmail_user
to = [<email_send_address>]
subject = 'Alert for reduced in price'
email_text =
"""
Alert for reduced in price
"""
sent_from:发送邮件的发件人to:邮件的收件人subject:邮件主题email_text:邮件正文的内容。
在电子邮件发送请求中,这是设置 SMTP 服务器的位置:
#email send request
try:
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.ehlo()
server.login(gmail_user, gmail_password)
server.sendmail(sent_from, to, email_text)
server.close()
print ('Email sent!')
except Exception as e:
print(e)
print ('Something went wrong...')
smtplib正在设置带有 gmail 安全套接字层(SSL)通道和端口 465 的 SMTP 服务器。这将允许我们从自己的 gmail 帐户发送邮件。ehlo()用于向服务器表明您的身份。这将检查我们设置的 gmail 服务器的 SMTP 服务扩展(e SMTP)。login非常简单。我们将使用自己的用户名和密码登录 gmail 服务器。- 然后,我们将使用我们的帐户
sendmail来使用我们之前设置的电子邮件属性。 - 最后,我们将
close服务器,这将为服务器释放我们的端口 465 和内存使用。
发送电子邮件请求
一旦设置了属性,一切都设置好了。你只需要运行它。还有…
您遇到了问题。
解决您的问题
您很可能会遇到这个错误

Troubleshooting credentials/gmail server error
如果您遇到此错误,并且您已经仔细检查了您的用户名和密码是否正确,那么您需要打开您的 Gmail 设置并打开不太安全的应用程序访问选项。这将允许 Python SMTP 访问您的 gmail 帐户并代表您发送电子邮件。
当然,为了维护您的 gmail 安全,您可以在不再使用该功能后将其关闭。

Activating the option “Less Secure App Access” from your gmail setting
最后,一旦你运行你的脚本。你会收到这封邮件。(注意,目前我正在使用我自己的电子邮件来测试应用程序)。

恭喜你。您刚刚发送了您的第一个自动电子邮件发送请求!

Source: Makeameme
使用我们的 Python Dash 仪表板准备 Webhooks
现在我们知道我们的警报起作用了,让我们设置 web 挂钩。
Web hooks 是服务器端应用程序的资源灯事件反应,用于通知客户端应用程序触发事件。在这种情况下,我们将设置 Dash,以便在用户修改仪表板的下拉菜单时激活警报逻辑。如果我们的产品降价,我们会发出警报。

Additional Callback to call alerts
product_df_specific将按日期对特定产品的值进行排序。original_price取产品的最早日期latest_price取产品的最新日期- 然后,一旦我们发现
latest_price比original_price低,就会发送电子邮件。
最终结果是,我们将有一个特定的电子邮件详细信息,列出用户关心的所有产品和价格警报。

Inserting alerts in emails
为电子邮件验证机密创建配置文件
还记得步骤 1 中的凭证吗?
gmail_user = '<input your gmail user. No need to use @gmail.com>'
gmail_password = '<input your gmail password>'
让我们将这些敏感信息放在一个属性文件中,您可以轻松地保护和配置该文件。
首先让我们创建一个名为 properties.ini 的 Python 属性文件:
**[EMAIL]** user= <gmail username>
password = <gmail password>
这些是你需要保护的私人文件。要访问它,只需使用 Python 内置的 configparser 库。
import configparserconfig = configparser.ConfigParser()
config.read('properties.ini')
gmail_user = config['EMAIL']['user']
gmail_password = config['EMAIL']['password']
你将首先启动一个config parser,这将把你的属性组织成一个树形目录来提取。
然后您将read properties ini 文件并提取您的用户名和密码,就像您如何从 2D 数组中提取一个元素一样。
最终结果
恭喜你!!您已经在仪表板中创建了第一个 SMTP。如果你做得好,你会得到这个结果。如果没有,请随意查阅我的 Github 代码或者在这里提出你的问题。

Email sent when users update the product dropdown
现在释放并创建您自己的 Dash Dashboard 和 Python SMTP!
更多参考
如果您需要更多的例子和对 Python SMTP 能做什么的更好的理解。请随意访问以下链接。
最后…

Source: Unsplash
我真的希望这是一本很棒的读物,是你发展和创新的灵感来源。
请在下面评论出来建议和反馈。就像你一样,我也在学习如何成为一名更好的数据科学家和工程师。请帮助我改进,以便我可以在后续的文章发布中更好地帮助您。
谢谢大家,编码快乐:)
关于作者
Vincent Tatan 是一名数据和技术爱好者,拥有在 Visa Inc .和 Lazada 实施微服务架构、商业智能和分析管道项目的相关工作经验。
Vincent 是土生土长的印度尼西亚人,在解决问题方面成绩斐然,擅长全栈开发、数据分析和战略规划。
他一直积极咨询 SMU BI & Analytics Club,指导来自不同背景的有抱负的数据科学家和工程师,并为企业开发他们的产品开放他的专业知识。
请通过 LinkedIn ,Medium或 Youtube 频道 联系文森特
发送电子邮件与美丽的形式在安卓系统
在本文中,我们将发送一封包含精心设计的表单的电子邮件,以显示随邮件发送的数据。

Image from Unsplash
众所周知,使用电子邮件对我们所有人来说已经变得必要和重要。有各种电子邮件服务提供商,如雅虎、Outlook、iCloud 和 Gmail 等。这些科技巨头为每个用户提供免费电子邮件服务。如果你使用互联网,那么就没有办法忽视它,因为无论何时你访问任何网站/应用程序来在线购买/销售产品。首先,你必须在这些网站/应用上注册,以证明你在现实世界中的身份。
在本文中,我们将学习如何使用 JavaMail API 将 Gmail 收件箱中的电子邮件发送到指定的电子邮件地址。我们将发送普通用户数据,如用户名、电子邮件地址、手机号码等。
所以让我们开始吧。
第一步
- 首先用空活动创建 android 项目,并在根目录下创建名为 MailSender.java 和 JSSEProvider.java 的 java 类。
- 现在我们需要将 Java 邮件 API jar 文件导入到我们的项目中。从这里下载 jar 文件,解压后粘贴到 libs 文件夹中。
- 如果你的项目不能识别你的库,那么重启 Android studio。
- 右键单击应用程序->新建->文件夹->资产文件夹,创建资产文件夹。我们将把 HTML 文件放在这里,以便在 Gmail 上显示数据。
- 要发送电子邮件,你的应用需要互联网连接,所以在你的 AndroidManifest.xml 文件中声明这个权限。
<**uses-permission android:name="android.permission.INTERNET"**/>
第二步
- 在 MailSender.java 类中创建一些实例变量
*// change this host name accordingly* **private** String **mailhost** = **"webmail.xyz.in"**;
**private** String **user**;
**private** String **password**;
**private** Session **session**;
Context **context**;
**private** Multipart **_multipart** = **new** MimeMultipart();
- 现在在 MailSender.java 文件中创建静态块来调用 JSSEProvider.java 类。JSSEProvider 用于链接 SSLContext、X509 的 KeyManagerFactory、X509 的 TrustManagerFactory 和 AndroidCAstore 的修改版本。
**static** {
Security.*addProvider*(**new** JSSEProvider());
}
- 创建参数化的构造函数(传递上下文,“发件人电子邮件 id”和“密码”等。)来初始化实例变量,并创建一个 Properties 类的对象来设置构造函数内部的属性。在其中传递上下文、用户电子邮件 id 和密码。看一看构造函数代码。
**public** MailSender(Context context,String user, String password) {
**this**.**user** = user;
**this**.**password** = password;
**this**.**context** = context;
Properties props = **new** Properties();
props.setProperty(**"mail.transport.protocol"**, **"smtp"**);
props.setProperty(**"mail.host"**, **mailhost**);
props.put(**"mail.smtp.auth"**, **"true"**);
props.put(**"mail.smtp.port"**, **"465"**);
props.put(**"mail.smtp.socketFactory.port"**, **"465"**);
props.put(**"mail.smtp.socketFactory.class"**, **"javax.net.ssl.SSLSocketFactory"**);
props.put(**"mail.smtp.socketFactory.fallback"**, **"false"**);
props.setProperty(**"mail.smtp.quitwait"**, **"false"**);
**session** = Session.*getDefaultInstance*(props, **this**);
}
- 创建密码验证器方法来验证您的帐户。
**protected** PasswordAuthentication getPasswordAuthentication() {
**return new** PasswordAuthentication(**user**, **password**);
}
- 最后,创建用户定义的方法 sendUserDetailWithImage()将数据发送到邮件。下面的代码片段从 assets 文件夹中提取 user_profile.html,将其转换为一个缓冲区,然后从缓冲区中读取它,最后将其转换为一个 string 对象,用实际的用户名替换关键字“$$username$$”等等。查看完整的senduserdetailwithiimage()代码。
看看完整的 MainSender.java 代码
第三步
要在表单中显示数据,请在 assets 文件夹中创建名为 user_profile.html 的 HTML 文件,并粘贴以下代码。
HTML 代码的输出看起来像这样

第四步
最后,将下面的代码粘贴到 MainActivity 中。
结果

Data received on Gmail
注意:如果你这边一切正常,但还是没有收到邮件,请检查你的垃圾邮件文件夹,如果有,点击“标记为非垃圾邮件”。
结论
我创建了一个 android 项目,以电子邮件的形式发送用户数据。我使用过 JavaMail API 发送电子邮件。在本文中,我发送了 HTML 表单和数据。
如果你对这篇文章有任何疑问,请在评论区问我。另外,你可以在我的 Github 账户上找到这篇文章的完整源代码。
我希望你喜欢读这篇文章,你也可以访问我的 网站 ,在那里我会定期发布文章。
订阅 我的邮件列表,以便直接在您的收件箱中提前获得我的文章,或者关注我自己在 Medium 上发表的文章The Code Monster以完善您的技术知识。
了解你的作者
希曼舒·维尔马毕业于印度勒克瑙的 APJ 阿卜杜勒·卡拉姆大学博士。他是 Android & IOS 开发人员、机器学习和数据科学学习者、金融顾问和博客作者。
使用 Python 从 Blackbaud CRM (BBEC)发送自动电子邮件
Blackbaud CRM Python 教程
连接到 BBEC 的基本设置
我的新工作使用 Blackbaud CRM 作为他们数据基础设施的主干,我的经验主要是 Python。令我惊讶的是,关于使用 Python 连接到 Blackbaud Enterprise CRM (BBEC)的资源并不多。最近,我需要拉一个选民名单,并给他们发送一封定制的电子邮件,其中包含他们的帐户信息。这比我预想的要困难得多,我想分享一下我的技巧和工具,以备其他人想要处理类似的问题时使用。我发现的主要方法是使用 API,特别是 AppFxWebService 端点。
要实现这一点,需要几个主要步骤。API 是基于 SOAP 的,这意味着我们必须使用 HTTP 和 XML 来与之通信。我发现通过创建 Jinja2 模板可以很容易地将这些合并到 Python 脚本中。之后,我们将使用pandas和xmltodict将 XML 响应转换成数据帧。一旦数据变得更易于管理,我们将向选出的选民发送一些个性化的电子邮件。这篇文章将重点介绍如何使用 Python 建立到 Blackbaud CRM 的连接。我将在以后的文章中更详细地介绍这些其他主题,但这里是从 CRM 中提取信息并使用 Python 发送电子邮件所需的整个过程的概述:
- 使用 Python 建立与 Blackbaud CRM 的连接
- 使用 Jinja2 模板与 API 通信
- 将 XML 结果解析成熊猫数据帧
- 使用我们从 CRM 收到的数据发送电子邮件
在这个过程中, Blackbaud CRM API 文档非常有用。根据您对这些概念的熟悉程度,您可能需要阅读入门指南。但是要注意,当我搜索这些文档时,我找不到任何 Python 示例。希望这篇指南能让你在下一个涉及 Blackbaud CRM 的项目中使用 Python。
另外,应该注意的是,这只是一个人解决这个问题的方法。如果你有任何建议或不同的方法来解决这些问题,我很乐意听到你的想法。
本指南假设您有一些 Python 经验,一些使用requests包的经验,也许还有一些使用pandas和数据分析的经验。如果你认为你能处理,我们将通过打开 IDE 或编辑器直接进入。我更喜欢 PyCharm,这也是本指南中的演示将使用的。然而,我会尽可能地包含使用替代方法完成这些步骤的链接。
第一步是在 PyCharm 中创建新项目。如果您选择另一条路线,主要步骤是为您的项目创建一个新目录,创建并激活一个虚拟环境,并安装一些必需的包。如果你像我一样使用 PyCharm,你需要从欢迎界面选择“创建一个新项目”。然后在接下来的屏幕上从列表顶部选择“纯 Python”。默认情况下,我的配置是用 conda 创建一个新环境。通过将“位置”栏中的“无标题”更改为项目的描述性名称来更改项目名称。对于这个例子,我选择了bbec_demo。PyCharm 很好地自动创建了一个同名的新 conda 环境,并将其指定为这个项目的项目解释器。
接下来,我们想要在我们的项目中创建一个名为config.py的新 Python 文件。如果您非常喜欢 PyCharm 快捷方式,那么当您选择了项目根目录时,可以使用 Alt + Insert +'pf '创建一个新的 python 文件。然后,我们要将以下代码添加到该文件中:
from requests import Session
from requests.auth import HTTPBasicAuth
为了向 API 发送请求,我们将结合使用requests包和其他一些工具。如果您使用 PyCharm,它可能会为您建立一个虚拟环境,您只需安装 requests 包。在 PyCharm 中,最简单的方法是将光标放在标有红色下划线的包(requests)上,然后按 Alt + Shift + Enter。这将自动选择最合适的上下文菜单项,即“安装包请求”
接下来,在开始与 Blackbaud CRM 通信之前,我们需要收集一些不同的 URL。您可能会发现关于制作 HTTP 请求的文档页面和 Fiddler 演示有助于找到这些请求。如果你登录了你公司的客户关系管理系统,你可以通过这个网址找到你需要的信息。例如,您可能有一个如下所示的 URL:
[https://bbisec02pro.blackbaudhosting.com/1234ABC_](https://bbisec04pro.blackbaudhosting.com/4249COL_fa341b46-12a4-4119-a334-8379e2e59d29/webui/WebShellLogin.aspx?databaseName=4249COL&url=https%3A%2F%2Fbbisec04pro.blackbaudhosting.com%2F4249COL_fa341b46-12a4-4119-a334-8379e2e59d29%2Fwebui%2FWebShellPage.aspx%3FdatabaseName%3D4249COL)fbd2546c-1d4d-4508-812c-5d4d915d856a[/webui/WebShellLogin.aspx](https://bbisec04pro.blackbaudhosting.com/4249COL_fa341b46-12a4-4119-a334-8379e2e59d29/webui/WebShellLogin.aspx?databaseName=4249COL&url=https%3A%2F%2Fbbisec04pro.blackbaudhosting.com%2F4249COL_fa341b46-12a4-4119-a334-8379e2e59d29%2Fwebui%2FWebShellPage.aspx%3FdatabaseName%3D4249COL)
可能有一个以“?”开头的查询字符串紧跟在[WebShellLogin.aspx](https://bbisec04pro.blackbaudhosting.com/4249COL_fa341b46-12a4-4119-a334-8379e2e59d29/webui/WebShellLogin.aspx?databaseName=4249COL&url=https%3A%2F%2Fbbisec04pro.blackbaudhosting.com%2F4249COL_fa341b46-12a4-4119-a334-8379e2e59d29%2Fwebui%2FWebShellPage.aspx%3FdatabaseName%3D4249COL)之后,但是我们可以忽略该信息。在本例中,我们希望所有内容都达到/webui。我们将把它记录在配置文件中,现在完整的文件应该是这样的:
from requests import Session
from requests.auth import HTTPBasicAuthbase_url = 'https://bbisec02pro.blackbaudhosting.com/'
database_name = '1234ABC_fbd2546c-1d4d-4508-812c-5d4d915d856a'
我把 URL 分成两部分,这样我们的代码可读性更好一些。我们需要的最后一部分是 AppFxWebService 端点,即/appfxwebservice.asmx。我们将使用 f 弦把所有这些放在一起。请注意,f 字符串仅在 Python 3.6 及更高版本中可用,如果您使用的是 Python 的旧版本,则必须使用.format()字符串方法。我们的配置文件现在应该如下所示:
from requests import Session
from requests.auth import HTTPBasicAuth
# URLs used for various API calls
base_url = 'https://bbisec02pro.blackbaudhosting.com/'
database_name = '1234ABC_fbd2546c-1d4d-4508-812c-5d4d915d856a'
appfx = '/AppFxWebService.asmx'
api = f'{base_url}{database_name}{appfx}'
我们现在已经精心制作了将用于与 API 通信的 URL。我们需要的下一部分是登录数据库的凭证。我选择使用 AWS Secret Management 来存储我的凭据。这相对容易,但是设置它可能超出了本文的范围。你需要按照[boto3](https://pypi.org/project/boto3/)和的设置指南添加一个新的秘密。与此相关的成本很小,但它非常安全,只需几分钱。如果你以前没有用过,甚至可以免费试用 30 天。
如果 AWS 方法不适合您,一个快速的替代方法是创建一个名为secret.py的新 Python 文件,但是要确保这个文件不受源代码控制(将其添加到您的.gitignore文件中)。这个文件应该和config.py在同一个目录下。它可以简单到:
username = 'BLACKBAUDHOST\your_username1234ABC'
password = 'your password'
我在这里遇到的一个问题是你用户名前后的前缀和后缀。如果您的环境由 Blackbaud 托管(如果您正在阅读本文,很可能就是这样),那么合适的前缀是“BLACKBAUDHOST\”。请注意,它只适用于反斜杠,不适用于正斜杠。后缀通常作为用户名的一部分显示在 Blackbaud 中,但它应该是数据库名称。登录 Blackbaud CRM 后,您可以通过查看 URL 中的查询字符串来确认这一点:
.../WebShellPage.aspx?databaseName=1234ABC
1234ABC是需要添加到您的用户名后面的内容。确认您的用户名格式正确的另一种方法是在 Blackbaud CRM 中导航至管理>安全>应用程序用户,并查看您的姓名旁边列出的“登录名”内容。这将为您提供我们进行身份验证所需的完整登录名。我还想包含 AWS 的这个代码片段,展示如何访问存储在秘密管理器中的秘密,以防您决定走这条路:
import boto3
import base64
from botocore.exceptions import ClientError
def get_secret():
secret_name = "credentials"
region_name = "us-east-1"
# Create a Secrets Manager client
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name
)
# In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
# See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
# We rethrow the exception by default.
try:
get_secret_value_response = client.get_secret_value(
SecretId=secret_name
)
except ClientError as e:
if e.response['Error']['Code'] == 'DecryptionFailureException':
# Secrets Manager can't decrypt the protected secret text using the provided KMS key.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response['Error']['Code'] == 'InternalServiceErrorException':
# An error occurred on the server side.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response['Error']['Code'] == 'InvalidParameterException':
# You provided an invalid value for a parameter.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response['Error']['Code'] == 'InvalidRequestException':
# You provided a parameter value that is not valid for the current state of the resource.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
elif e.response['Error']['Code'] == 'ResourceNotFoundException':
# We can't find the resource that you asked for.
# Deal with the exception here, and/or rethrow at your discretion.
raise e
else:
# Decrypts secret using the associated KMS CMK.
# Depending on whether the secret is a string or binary, one of these fields will be populated.
if 'SecretString' in get_secret_value_response:
secret = get_secret_value_response['SecretString']
secret = secret.strip('{}').replace('"', '')
username, password = secret.split(':')
else:
decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])
return username, password
它包括一些基本的错误处理,我只需要为自己的目的添加三行代码。
secret = secret.strip('{}').replace('"', '')
username, password = secret.split(':')
...
return username, password
这只是一些文本解析,将响应格式化为用户名和密码对。一旦完成,我就在函数的末尾添加return username, password。我要说的是,由于“\”字符,在我的用户名中包含“BLACKBAUDHOST”前缀时,我得到了一些奇怪的结果。我无法让它正确地转义,所以我选择从 AWS 中存储的秘密中删除它,并在检索到秘密后添加它。因为它不是用户名的唯一部分,我不认为这里有任何安全问题。
如果您走第一条路,将用户名和密码作为明文存储在源代码控制之外的文件中,那么您会想要将这个 import 语句添加到config.py:
from secret import username, password
如果您走 AWS Secrets Manager 路线,您的导入看起来会稍有不同,您必须分配用户名和密码:
import secretusername, password = secret.get_secret()
username = 'BLACKBAUDHOST\\' + username
由于get_secret()函数返回一个带有用户名密码对的元组,我们可以编写username, password来告诉 Python 解包元组并分别分配变量。然后我们会加上我之前提到的前缀。这里需要一个双反斜杠,因为单反斜杠是转义序列的开始,您需要第二个反斜杠来表示被转义的字符(" \ ")。
现在凭证已经处理好了,并且可以安全地访问它们,我们只需要做最后一点设置。我们必须用requests包创建一个会话,并使用我们的凭证授权该会话。
session = Session()
session.auth = HTTPBasicAuth(username, password)
我将在这里包括一个其他的位,这是我们所有的 API 调用将使用的头。在发送请求之前,我们将添加一点点信息,但是我喜欢设置一个默认的信息。一旦我们包含了这些,完整的config.py文件应该是这样的:
from requests import Session
from requests.auth import HTTPBasicAuth
import secret
# URLs used for various API calls
base_url = 'https://bbisec02pro.blackbaudhosting.com/'
database_name = '1234ABC_fbd2546c-1d4d-4508-812c-5d4d915d856a'
appfx = '/AppFxWebService.asmx'
api = f'{base_url}{database_name}{appfx}'
base_endpoint = 'Blackbaud.AppFx.WebService.API.1/'# Credentials
username, password = secret.get_secret()
username = 'BLACKBAUDHOST\\' + username# Authorization
session = Session()
session.auth = HTTPBasicAuth(username, password)# Headers
headers = {'Content-Type': 'text/xml; charset=utf-8',
'Host': 'bbisec02pro.blackbaudhosting.com',
'SOAPAction': ''}
我还偷偷添加了一行代码来定义base_endpoint。这是我们将用来配置我们的 SOAP 请求的东西。不是超级关键,但是为了方便可能要加上。Content-Type头将根据您使用的 SOAP 版本(1.1 或 1.2)而变化。到目前为止,我只使用了 1.1,所以这就是这里所反映的。您也可以通过自己导航到端点来找到此信息。登录你的 Blackbaud CRM,用.../appfxwebservice.asmx替换网址的.../webui/WebShellPage.aspx?部分和其后的所有内容。在这里,您将能够看到所有可用的操作以及使用它们所需的 SOAP 模板。模板显示了填充了你的数据库信息的标题,如果对你来说更容易的话,你可以窃取这些并把它们放在如上图所示的config.py中。
我们就要连接到数据库了,但是我们需要再创建一个名为api.py的文件。在这里,让我们多写一点代码来测试我们的连接:
import config
action = 'AdHocQueryGetIDByName'
body = '''<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AdHocQueryGetIDByNameRequest >
<ClientAppInfo REDatabaseToUse="1234ABC"
ClientAppName="bbec_demo"
TimeOutSeconds="5"/>
<Name>Interaction Data List Query</Name>
</AdHocQueryGetIDByNameRequest>
</soap:Body>
</soap:Envelope>'''
现在,我从/appfxwebservice.asmx 端点借用了一个模板,具体来说就是名为“AdHocQueryGetIDByName”的模板,这就是为什么action = ‘AdHocQueryGetIDByName'。然后,我将文本直接粘贴到我们的文件中。我去掉了所有我不会使用的不重要的标签,然后我必须输入一些其他的信息。你可能会注意到ClientAppInfo标签。这不会出现在/appfxwebservice.asmx端点的模板中,但是我们的请求必须有效。他们只是在文档中简单地提到了它,当我第一次开始做这个的时候,它对我来说绝对是一个陷阱。不过,你所要做的就是将REDatabaseToUse设置为你的数据库名称(在你的 CRM 的 URL 的查询字符串中找到)并为ClientAppName输入一些名称。按照惯例,我喜欢将它设置为我们的项目名称,但它可以是您想要的任何名称。我们需要做的最后一件事是在Name标签中输入我们的信息库中存在的查询的名称。我选择“交互数据列表查询”是因为它是一个现成的报告,应该默认包含在您的 CRM 中。
接下来,让我们使用给定的操作创建一个函数来设置我们的标题:
def set_head(endpoint):
headers = config.headers.copy()
headers.update({'SOAPAction': f'{config.base_endpoint}{endpoint}'})
return headers
这将更新我们在config.py文件中定义的头的副本,并返回给SOAPAction合适的头。
最后一步是使用我们在config.py文件中设置的requests和session发送 POST 请求。我们将添加我们的头部和身体,我们应该准备好了。
res = config.session.post(config.api, headers=set_head(action), data=body)
print(res)
我们的api.py文件作为一个整体现在应该看起来像这样:
import config
action = 'AdHocQueryGetIDByName'
body = '''<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AdHocQueryGetIDByNameRequest >
<ClientAppInfo REDatabaseToUse="1234ABC"
ClientAppName="bbec_demo"
TimeOutSeconds="5"/>
<Name>AdHocQueryGetIDByName</Name>
</AdHocQueryGetIDByNameRequest>
</soap:Body>
</soap:Envelope>'''
def set_head(endpoint):
headers = config.headers.copy()
headers.update({'SOAPAction': f'{config.base_endpoint}{endpoint}'})
return headers
res = config.session.post(config.api, headers=set_head(action), data=body)
print(res)
运气好的话,当您运行它时,它会打印出<Response [200]>。这意味着我们已经成功地建立了到数据库的连接,我们可以开始从中提取信息了!
在下一节中,我们将去掉 body 的那个难看的三重引号字符串,并用一些漂亮的 Jinja2 模板替换它。欢迎在下面提出建议或问题。你可以在我的 GitHub 上找到本节涉及的所有代码。
感知空气质量
基于 RaspberryPi 4 的低成本物联网空气质量监测仪

Santiago, Chile during a winter environmental emergency
我有幸生活在世界上最美丽的国家之一,但不幸的是,这并不总是美好的。智利冬季空气污染严重,主要是由灰尘和烟雾等颗粒物质造成的。

由于天气寒冷,在南部,空气污染主要是由于木材引起的,而在圣地亚哥(该国中部的主要首都),空气污染则是由工业、汽车以及两大山脉之间的独特地理位置造成的。


如今,空气污染是全世界的一个大问题,在这篇文章中,我们将探讨如何开发一个廉价的自制空气质量监测器,基于树莓皮。
如果你有兴趣了解更多关于空气质量的信息,请访问 “世界空气质量指数”项目 。
颗粒物(PM)是什么,它是如何进入空气中的?
因此,要了解污染或空气污染,我们必须研究与之相关的颗粒,也就是众所周知的颗粒物。查看上一部分的图表,我们可以发现他们提到了 PM2.5 和 PM10 。让我们对此进行一个快速的概述。
PM 代表颗粒物质(也称为颗粒污染):空气中固体颗粒和液滴混合物的术语。有些微粒,如灰尘、污垢、煤烟或烟雾,很大或很暗,足以用肉眼看到。其他的非常小,只有用电子显微镜才能发现。
颗粒的尺寸范围很广。直径小于或等于 10 微米的颗粒非常小,以至于它们可以进入肺部,潜在地导致严重的健康问题。十微米还不到一根人类头发的宽度。

颗粒污染包括:
- 粗尘粒(PM10) :可吸入颗粒物,直径一般在 10 微米及以下。来源包括破碎或研磨作业以及道路上车辆扬起的灰尘。
- 细颗粒物(PM2.5) :可吸入的细颗粒物,直径一般在 2.5 微米及以下。所有类型的燃烧都会产生细颗粒物,包括机动车、发电厂、住宅木材燃烧、森林火灾、农业燃烧和一些工业过程
你可以在环保局网站上找到更多关于颗粒物的信息: 美国环境保护局
为什么重要的是关心那些颗粒物?
正如 GERARDO ALVARADO Z .在他在智利大学的工作中所描述的那样,对 1930 年默兹山谷(比利时)、1948 年多诺拉(宾夕法尼亚州)和 1952 年伦敦的高度空气污染事件的研究是第一个将死亡率与颗粒污染联系起来的文献资料来源(Préndez,1993 年)。在调查空气污染对人们健康的影响方面取得的进展已经确定,健康风险是由可吸入颗粒造成的,这取决于它们在呼吸系统不同部分的渗透和沉积,以及对沉积物质的生物反应。
最厚的颗粒,约 5 微米,通过鼻腔纤毛和覆盖鼻腔和气管的粘膜的共同作用被过滤。直径在 0.5 和 5 微米之间的颗粒可以沉积在支气管中,甚至沉积在肺泡中,然而,几小时后它们被支气管和细支气管的纤毛清除。小于 0.5 微米的颗粒可以穿透很深,直到它们沉积在肺泡中,保留几周到几年,因为没有促进消除的粘膜纤毛运输机制。
下图显示了颗粒在呼吸系统中的渗透程度,取决于它们的大小。

因此,发现这两种类型的颗粒(PM2.5 和 PM10)非常重要,好消息是这两种颗粒都可以通过简单且不昂贵的传感器 SDS011 读取。
粒子传感器— SDS011
空气质量监测是众所周知的既定科学,始于 80 年代。当时,技术相当有限,用于量化空气污染的解决方案复杂、繁琐且非常昂贵。
幸运的是,如今,利用最新的现代技术,用于空气质量监测的解决方案不仅变得更加精确,而且测量速度也更快。设备变得越来越小,价格也比以前便宜得多。
在本文中,我们将重点介绍一种粒子传感器,它可以检测空气中的灰尘量。虽然第一代传感器只能检测不透明度,但最近的传感器,如从暨南大学(山东)剥离出来的 INOVAFIT 公司的 SDS011 ,现在可以检测 PM2.5 和 PM10。

就其尺寸而言,SDS011 可能是精度和价格(低于 40.00 美元)最好的传感器之一。
规范
- 测量值:PM2.5,PM10
- 范围:0–999.9 微克/立方米
- 电源电压:5V(4.7–5.3V)
- 功耗(工作):70mA 10mA
- 功耗(睡眠模式激光和风扇):< 4mA
- 储存温度:-20 至+60C
- 工作温度:-10 至+50C
- 湿度(储存):最大值。90%
- 湿度(工作):最大值。70%(水蒸气凝结会伪造读数)
- 精度:0.3μm 为 70%,0.5μm 为 98%
- 尺寸:71x70x23 毫米
- 认证:CE,FCC,RoHS
SD011 使用 PCB 作为外壳的一面,可以降低成本。接收器二极管安装在 PCB 侧(这是强制性的,因为应避免二极管和 LNA 之间的任何噪声)。发射器激光器安装在塑料盒上,并通过软线连接到 PCB。

简而言之,Nova Fitness SDS011 是一款专业的激光粉尘传感器。安装在传感器上的风扇自动吸入空气。该传感器使用激光散射原理*来测量悬浮在空气中的灰尘颗粒值。该传感器提供高精度和可靠的 PM2.5 和 PM10 值读数。环境的任何变化都可以在 10 秒以下的短响应时间内被观察到。标准模式下的传感器以 1 秒的间隔报告读数。
*激光散射原理:当颗粒通过检测区时,会引起光散射。散射光被转换成电信号,这些信号将被放大和处理。由于信号波形与颗粒直径有一定的关系,通过分析可以得到颗粒的数量和直径。
但是 SDS011 如何捕捉这些粒子呢?
如前所述,SDS011 使用的原理是光散射或更好的说法,动态光散射(DLS),这是一种物理学技术,可用于确定悬浮液中的小颗粒或溶液中的聚合物的尺寸分布。在 DLS 范围内,通常通过强度或光子自相关函数(也称为光子相关光谱或准弹性光散射)来分析时间波动。在时域分析中,自相关函数(ACF)通常从零延迟时间开始衰减,并且由于更小的粒子,更快的动态导致散射强度轨迹的更快去相关。已经表明,强度 ACF 是功率谱的傅立叶变换,因此 DLS 测量可以在谱域中同样很好地执行。
下面是两个样品的假设动态光散射:较大的颗粒(如 PM10)在顶部;较小的颗粒(如 PM2.5)在底部;

观察传感器内部,我们可以看到光散射原理是如何实现的:

二极管上捕获的电信号进入低噪声放大器,然后通过 ADC 转换为数字信号,再通过 UART 发送到外部。
要了解更多关于 SDS011 的真实科学体验,请看看 Konstantinos et al .低成本便携式 PM2.5 浓度监测系统的开发和现场测试2018 年的工作。
表演时间到了。
让我们暂时放下这些理论,专注于如何使用 Raspberry Pi 和 SDS011 传感器测量颗粒物

硬件连接实际上非常简单。该传感器与 USB 适配器一起出售,以将其 7 针 UART 的输出数据与 RPi 的标准 USB 连接器之一进行接口。
SDS011 引脚排列:
- 引脚 1 —未连接
- 针 2—pm 2.5:0–999 微克/立方米;PWM 输出
- 引脚 3–5V
- 针 4—PM10:0–999 微克/立方米;PWM 输出
- 引脚 5 — GND
- 引脚 6 — RX UART (TTL) 3.3V
- 引脚 7 — TX UART (TTL) 3.3V
对于本教程,我第一次使用全新的树莓-Pi 4。但是当然,任何以前的模型也可以很好地工作。
一旦您将传感器连接到 RPi USB 端口之一,您将自动开始听到其风扇的声音。噪音有点烦人,所以也许你应该拔下它,等你用软件设置好了再说。
传感器和 RPi 之间的通信将通过串行协议进行。关于这个协议的细节可以在这里找到:激光灰尘传感器控制协议 V1.3 。
但是对于这个项目来说,最好是用一个 python 接口来简化要开发的代码。你可以创建自己的界面,或者使用互联网上的一些界面,比如弗兰克·豪雅的或者伊万·卡尔切夫的。我们将使用最后一个,它非常简单并且运行良好(您可以从它的 GitHub 或 mine 下载 sds011.py 脚本)。
文件 sds011.py 必须位于创建脚本的同一目录下。
在开发阶段,我将使用 Jupyter 笔记本,但您可以使用任何您喜欢的 IDE(例如,作为 Raspberry Pi Debian 软件包一部分的 Thonny 或 Geany 都非常好)。
开始导入 sds011,并创建传感器实例。 SDS011 提供了一种使用 UART 从传感器读取数据的方法。
from sds011 import *
sensor = SDS011("/dev/ttyUSB0")
你可以用命令睡眠打开或关闭你的传感器:
# Turn-on sensor
sensor.sleep(sleep=False)# Turn-off sensor
sensor.sleep(sleep=True)
打开传感器后,您可以使用以下方法从传感器获取数据:
pmt_2_5, pmt_10 = sensor.query()
测量前至少等待 10 秒钟稳定,至少等待 2 秒钟开始新的测量:

这就是使用传感器所需了解的所有软件。但是,让我们更深入地了解空气质量控制!在本文的开始,如果你已经浏览了提供空气好坏信息的网站,你应该意识到颜色与这些值相关联。每种颜色都是一个索引。其中最著名的是在美国和其他几个国家使用的空气质量指数。
空气质量指数
空气质量指数是报告每日空气质量的指数。它告诉你你的空气有多干净或被污染,以及你可能担心的相关健康影响。空气质量指数关注的是呼吸污染空气后几小时或几天内你可能经历的健康影响。
例如,EPA(美国环境保护局)不仅计算颗粒污染(PM2.5 和 PM10)的 AQI,还计算《清洁空气法案》规定的其他主要空气污染物:地面臭氧、一氧化碳、二氧化硫和二氧化氮。对于每一种污染物,环境保护局已经建立了国家空气质量标准来保护公众健康。
AQI 值,颜色和健康信息关联:

如前所述,这些 AQI 值和颜色与每一种污染物相关,但如何将传感器产生的值与它们联系起来呢?
一个附加表将它们全部连接起来:

但是当然,使用这样的表是没有意义的。最后,这是一个简单的数学算法,使计算。为此,我们将导入 AQI 值与污染物浓度(g/m)之间的转换库:
python-aqi 。
使用 PIP 安装库:
pip install python-aqi

智利怎么样?
智利也使用了类似的指数,ICAP: 可吸入颗粒物的空气质量指数。共和国总统府秘书长部 1998 年 3 月 16 日颁布的第 59 号最高法令在其第 1 条 g)款中规定,定义 ICAP 可吸入颗粒物 ICA 的水平如下表所示:

各部分之间的数值将呈线性变化,数值 500 将对应于极限值,当暴露于这些浓度时,超过该极限值将对人群产生风险。根据 ICAP 值,建立了类别(见下表),限定了人们接触的 MP10 的浓度水平:

Bueno:Good → Peligroso: Danger
本地记录数据
在这一点上,我们有所有的工具来捕捉来自传感器的数据,并将其转换为更“可读”的值,即 AQI 指数。
让我们创建一个函数来捕获这些值。我们将依次获取 3 个值,取其中的平均值:
def get_data(n=3):
sensor.sleep(sleep=False)
pmt_2_5 = 0
pmt_10 = 0
time.sleep(10)
for i in range (n):
x = sensor.query()
pmt_2_5 = pmt_2_5 + x[0]
pmt_10 = pmt_10 + x[1]
time.sleep(2)
pmt_2_5 = round(pmt_2_5/n, 1)
pmt_10 = round(pmt_10/n, 1)
sensor.sleep(sleep=True)
time.sleep(2)
return pmt_2_5, pmt_10
让我们来测试一下:


Ben Orlin — MathWithBadDrawings
我们再来做一个函数,转换 AQI 指数中 PM 的数值:
def conv_aqi(pmt_2_5, pmt_10):
aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5))
aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10))
return aqi_2_5, aqi_10
并一起测试这两种功能:

但是该拿它们怎么办呢?
最简单的答案是创建一个函数来保存捕获的数据,将它们保存在本地文件中:
def save_log():
with open("YOUR PATH HERE/air_quality.csv", "a") as log:
dt = datetime.now()
log.write("{},{},{},{},{}\n".format(dt, pmt_2_5, aqi_2_5, pmt_10,aqi_10))
log.close()
通过一个循环,您可以在本地文件中定期记录数据,例如,每分钟:
while(True):
pmt_2_5, pmt_10 = get_data()
aqi_2_5, aqi_10 = conv_aqi(pmt_2_5, pmt_10)
try:
save_log()
except:
print ("[INFO] Failure in logging data")
time.sleep(60)

每 60 秒,时间戳加上数据将被“附加”到这个文件中,正如我们在上面看到的。
向云服务发送数据
至此,我们已经了解了如何从传感器捕获数据,并将其保存在本地 CSV 文件中。现在,是时候看看如何将这些数据发送到物联网平台了。在本教程中,我们将使用ThingSpeak.com。
“ThingSpeak 是一个开源的物联网(IoT)应用程序,使用 REST 和 MQTT APIs 来存储和检索数据。ThingSpeak 支持创建传感器日志应用程序、位置跟踪应用程序和具有状态更新的社交网络。”
首先,你必须在 ThinkSpeak.com 有一个账户。接下来,按照说明创建一个通道,记下它的通道 ID 和写 API 键。

创建频道时,您还必须定义将上传到 8 个字段中的每个字段的信息,如上所示(在我们的示例中,仅使用其中的 4 个字段)。
MQTT 协议和 ThingSpeak 连接
MQTT 是一种发布/订阅架构,主要用于通过无线网络连接带宽和功率受限的设备。它是一个简单的轻量级协议,运行在 TCP/IP 套接字或 web 套接字上。WebSockets 上的 MQTT 可以用 SSL 保护。发布/订阅体系结构使得消息能够被推送到客户端设备,而无需设备持续轮询服务器。
MQTT 代理是通信的中心点,它负责在发送者和合法接收者之间分发所有消息。客户机是连接到代理的任何设备,可以发布或订阅主题以访问信息。主题包含代理的路由信息。每个想要发送消息的客户端将消息发布到某个主题,每个想要接收消息的客户端订阅某个主题。代理将带有匹配主题的所有消息传递给适当的客户端。
ThingSpeak 在 URLmqtt.thingspeak.com和端口 1883 有一个 MQTT 代理。ThingSpeak 代理支持 MQTT 发布和 MQTT 订阅。
在我们的例子中,我们将使用 MQTT 发布。

MQTT 发布
首先,让我们安装 Eclipse Paho MQTT Python 客户端库,它实现了 MQTT 协议的 3.1 和 3.1.1 版本
sudo pip install paho-mqtt
接下来,让我们导入 paho 库:
import paho.mqtt.publish as publish
并启动 Thingspeak 通道和 MQTT 协议。这种连接方法最简单,需要的系统资源最少:
channelID = "YOUR CHANNEL ID"
apiKey = "YOUR WRITE KEY"
topic = "channels/" + channelID + "/publish/" + apiKey
mqttHost = "mqtt.thingspeak.com"
现在我们必须定义我们的“有效载荷”:
tPayload = "field1=" + str(pmt_2_5)+ "&field2=" + str(aqi_2_5)+ "&field3=" + str(pmt_10)+ "&field4=" + str(aqi_10)
就是这样!我们准备好开始向云发送数据了!
让我们重写前面的循环函数,使其包含 ThingSpeak 部分。
# Sending all data to ThingSpeak every 1 minute
while(True):
pmt_2_5, pmt_10 = get_data()
aqi_2_5, aqi_10 = conv_aqi(pmt_2_5, pmt_10)
tPayload = "field1=" + str(pmt_2_5)+ "&field2=" + str(aqi_2_5)+ "&field3=" + str(pmt_10)+ "&field4=" + str(aqi_10)
try:
publish.single(topic, payload=tPayload, hostname=mqttHost, port=tPort, tls=tTLS, transport=tTransport)
save_log()
except:
print ("[INFO] Failure in sending data")
time.sleep(60)
如果一切正常,您一定会在 thingspeak.com 上看到数据也出现在您的频道上:

最终剧本
需要指出的是,Jupyter Notebook 对于开发和报告来说是一个非常好的工具,但是不适合创建代码投入生产。您现在应该做的是获取代码的相关部分,创建一个. py 脚本,并在您的终端上运行它。
例如,“ts_air_quality_logger.py”,您应该使用以下命令运行:
python 3 ts_air_quality_logger.py
这个脚本以及 Jupyter 笔记本和 sds011.py 可以在我的存储库 RPi_Air_Quality_Sensor 中找到。
请注意,该脚本仅适用于测试。最好不要在最终循环中使用延迟(这会使代码处于“暂停”状态),而是使用计时器。或者对于一个真正的应用程序,最好不要使用循环,让 Linux 程序定期用 crontab 执行脚本。
测试显示器
当我的 Raspberry Pi 空气质量监测器工作时,我将 RPi 组装在一个塑料盒中,将传感器放在外面,并将其放置在我家外面。




有两个经验:
- 汽油发动机燃烧:传感器放置在距离兰姆布雷塔汽车气景约 1 米处,发动机开启:

我让发动机运转了几分钟,然后关掉了。从日志文件,这是我得到的结果:

有趣的是证实了 PM2.5 是发动机产生的最危险的微粒。
2.燃木:燃木火放在鼻子正下方;

查看日志文件:

传感器数据瞬间“超出范围”,AQI 转换库无法很好地捕获,因此我更改了以前的代码来处理它:
def conv_aqi(pmt_2_5, pmt_10):
try:
aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5))
aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10))
return aqi_2_5, aqi_10
except:
return 600, 600
这种情况在外地也能发生,这是可以的。请记住,实际上,您应该使用移动平均线来真正获得 AQI(至少每小时一次,但通常每天一次)。
结论
一如既往,我希望这个项目可以帮助其他人找到进入令人兴奋的电子和数据科学世界的方法!
详情和最终代码请访问我的 GitHub 仓库: RPi_Air_Quality_Sensor
来自世界南部的 Saludos!
我的下一篇文章再见!
谢谢你,
马塞洛
基于双 LSTM 的句子分类
基于双向 LSTM 模型的句子分类及其与其他基线模型的比较
因此,有各种各样的方法来进行句子分类,如单词袋方法或神经网络等。在这篇文章中,我将主要讨论使用深度学习模型(特别是双 LSTM)的句子分类任务
本文主要关注一些基本的介绍,然后直接进入实现。如果您需要更深入的信息,我在参考资料中提供了链接。
我把文章按不同的类别组织起来,
- 介绍
- 实现:(预处理和基线模型)
- 双 LSTM 模型
- 结果和结论
随意跳到一个特定的类别。
一、简介
对于句子分类,我们主要有两种方法:
- 单词袋模型(BOW)
- 深度神经网络模型
BOW 模型的工作原理是分别对待每个单词,并对每个单词进行编码。对于 BOW 方法,我们可以使用 TF-IDF 方法,但它不能保留句子中每个单词的上下文。
因此,为了更好地完成命名实体抽取、情感分析等任务,我们使用深度神经网络。
二世。实施
数据集:
在这篇文章中,我使用了 Reddit - 数据集 2,它基于四种情绪类别,如愤怒、快乐、血腥和毛骨悚然。
对于深度神经模型,我们需要文本的嵌入。嵌入捕捉了单词在更高维度平面中的表示。通过嵌入,我们创建了单词的向量表示,通过理解单词的上下文来学习单词。我们可以使用预先训练的嵌入,如 glove、fasttext,它们在数十亿个文档上进行训练,或者我们可以使用 gensim 包等创建自己的嵌入(在我们自己的语料库上进行训练)。
在本文中,我使用了预先训练好的 glove-twitter 嵌入,它适用于我们的社交网络数据环境。此外,我选择 100 维嵌入,它表现很好,不需要花太多时间训练。可以选择其他(25、50、300 D 也可以)。
embedding_path = "~/glove.twitter.27B.100d.txt" ## change
# create the word2vec dict from the dictionary
def get_word2vec(file_path):
file = open(embedding_path, "r")
if (file):
word2vec = dict()
split = file.read().splitlines()
for line in split:
key = line.split(' ',1)[0] # the first word is the key
value = np.array([float(val) for val in line.split(' ')[1:]])
word2vec[key] = value
return (word2vec)
else:
print("invalid fiel path")w2v = get_word2vec(embedding_path)
文本预处理:
所以他们的数据有四个代表四种不同情绪的文件,所以我们需要合并这些文件来完成多类别分类任务。
df_rage = pd.read_csv(os.path.join(dir_path,'processed_rage.csv'))
df_happy = pd.read_csv(os.path.join(dir_path,'processed_happy.csv'))
df_gore = pd.read_csv(os.path.join(dir_path,'processed_gore.csv'))
df_creepy = pd.read_csv(os.path.join(dir_path,'processed_creepy.csv'))# create a random balances dataset of all of the categories
length = np.min([len(df_rage),len(df_happy),len(df_creepy),len(df_gore)])df_final = pd.concat([df_rage[:length], df_happy[:length], df_gore[:length], df_creepy[:length]], ignore_index=True)
标记化:
为了将句子分解成更简单的记号或单词,我们对文本进行记号化。在这里,我们将使用 nltk Tweet tokenizer,因为它可以很好地处理社交网络数据。
import nltk
from nltk.corpus import stopwords
stopwords = set(stopwords.words('english'))
nltk.download('wordnet')
nltk.download('stopwords')
from nltk.tokenize import TweetTokenizer
from nltk.corpus import wordnet as wn
tknzr = TweetTokenizer()def get_tokens(sentence):
# tokens = nltk.word_tokenize(sentence) # now using tweet tokenizer
tokens = tknzr.tokenize(sentence)
tokens = [token for token in tokens if (token not in stopwords and len(token) > 1)]
tokens = [get_lemma(token) for token in tokens]
return (tokens)def get_lemma(word):
lemma = wn.morphy(word)
if lemma is None:
return word
else:
return lemmatoken_list = (df_final['title'].apply(get_tokens))
准备输入变量
# integer encode the documents
encoded_docs = t.texts_to_sequences(sentences)
# pad documents to a max length of 4 words
max_length = max_len
X = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
输出变量:
from sklearn import preprocessing
le = preprocessing.LabelEncoder()
Y_new = df_final['subreddit']
Y_new = le.fit_transform(Y_new)
将数据拆分为培训和测试
## now splitting into test and training data
from sklearn.model_selection import train_test_split
X_train,X_test, Y_train, Y_test = train_test_split(X, y,test_size =0.20,random_state= 4 )
基准模型
在获得 LSTM 模型的分数之前,我已经从我们的基线模型中获得了一些指标:
对于基线模型,我们可以简单地计算 word2vec 嵌入的平均值。
# the object is a word2vec dictionary with value as array vector,
# creates a mean of word vecotr for sentences
class MeanVect(object):
def __init__(self, word2vec):
self.word2vec = word2vec
# if a text is empty we should return a vector of zeros
# with the same dimensionality as all the other vectors
self.dim = len(next(iter(word2vec.values())))
# pass a word list
def transform(self, X):
return np.array([
np.mean([self.word2vec[w] for w in words if w in self.word2vec]
or [np.zeros(self.dim)], axis=0)
for words in (X)
])
SVM
def svm_wrapper(X_train,Y_train):
param_grid = [
{'C': [1, 10], 'kernel': ['linear']},
{'C': [1, 10], 'gamma': [0.1,0.01], 'kernel': ['rbf']},]
svm = GridSearchCV(SVC(),param_grid)
svm.fit(X_train, Y_train)
return(svm)
韵律学
# svm
svm = svm_wrapper(X_train,Y_train)
Y_pred = svm.predict(X_test)
score = accuracy_score(Y_test,Y_pred)
print("accuarcy :", score)0.70
对于基线,你可以进一步应用其他分类器(如随机森林等),但我用 SVM 得到了最好的 F1 分数。
对于语言环境中的神经模型,最流行的是 LSTMs(长短期记忆),这是一种 RNN(递归神经网络),它保留了文本的长期依赖性。我在参考文献中加入了链接,这些参考文献似乎详细解释了 LSTM 的观点。
三世。双向 LSTM:
对于双向 LSTM,我们有一个嵌入层,而不是加载随机权重,我们将从手套嵌入中加载权重
# get the embedding matrix from the embedding layer
from numpy import zeros
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
embedding_vector = w2v.get(word)
if embedding_vector is not None:
embedding_matrix[i] = embedding_vector
我们还想计算神经模型的 vocab 大小。
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(token_list)
vocab_size = len(t.word_index) + 1# integer encode the documents
encoded_docs = t.texts_to_sequences(sentences)
# pad documents to a max length of 4 words
max_length = max_len
X = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
y = Y_new
最终模型
# main model
input = Input(shape=(max_len,))
model = Embedding(vocab_size,100,weights=[embedding_matrix],input_length=max_len)(input)
model = Bidirectional (LSTM (100,return_sequences=True,dropout=0.50),merge_mode='concat')(model)
model = TimeDistributed(Dense(100,activation='relu'))(model)
model = Flatten()(model)
model = Dense(100,activation='relu')(model)
output = Dense(3,activation='softmax')(model)
model = Model(input,output)
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam', metrics=['accuracy'])
对于我们的神经模型,上面的 max_len 必须是固定的,它可以是具有最大字数的句子,也可以是静态值。我把它定义为 60。
模型总结-
Layer (type) Output Shape Param #
=================================================================
input_32 (InputLayer) (None, 60) 0
_________________________________________________________________
embedding_34 (Embedding) (None, 60, 100) 284300
_________________________________________________________________
bidirectional_29 (Bidirectio (None, 60, 200) 160800
_________________________________________________________________
time_distributed_28 (TimeDis (None, 60, 100) 20100
_________________________________________________________________
flatten_24 (Flatten) (None, 6000) 0
_________________________________________________________________
dense_76 (Dense) (None, 100) 600100
_________________________________________________________________
dense_77 (Dense) (None, 3) 303
=================================================================
Total params: 1,065,603
Trainable params: 1,065,603
Non-trainable params: 0
_________________________________________________________________
因此,在针对 ner 模型的通用架构的论文1中,他们在双 LSTM 之上使用了 CRF 层,但是对于简单的多类别句子分类,我们可以跳过它。
使训练数据符合模型:
model.fit(X_train,Y_train,validation_split=0.25, nb_epoch = 10, verbose = 2)
四:成绩
评估模式
# evaluate the model
loss, accuracy = model.evaluate(X_test, Y_test, verbose=2)
print('Accuracy: %f' % (accuracy*100))Accuracy: 74.593496
分类报告
from sklearn.metrics import classification_report,confusion_matrix
Y_pred = model.predict(X_test)
y_pred = np.array([np.argmax(pred) for pred in Y_pred])
print(' Classification Report:\n',classification_report(Y_test,y_pred),'\n')Classification Report:
precision recall f1-score support
0 0.74 0.72 0.73 129
1 0.75 0.64 0.69 106
2 0.76 0.89 0.82 127
3 0.73 0.72 0.72 130
micro avg 0.75 0.75 0.75 492
macro avg 0.75 0.74 0.74 492
weighted avg 0.75 0.75 0.74 492

Comparison with other models
结论:
因此,我们看到,对于保留文本序列及其上下文的神经模型,我们得到了比 BOW 模型更好的分数,但这取决于上下文和应用。因此,在某些情况下,与复杂的神经模型相比,简单的模型可能是有益的。此外,我们有一个较小的数据集,所以训练时间很短,但对于较大的数据集(> 100k),可能需要 1 个多小时的训练。
希望你喜欢,如果你有任何疑问或意见,请随时添加到评论区。谢了。
参考资料:
1:兰普尔、纪尧姆、米格尔·巴列斯特罗斯、桑迪普·苏布拉曼尼安、川上和也和克里斯·戴尔。"命名实体识别的神经架构." arXiv 预印本 arXiv:1603.01360 (2016)。
2 Duong、Chi Thang、Remi Lebret 和 Karl Aberer。"用于分析社交媒体的多模态分类."2017 年第 27 届欧洲机器学习和数据库知识发现原理与实践会议(ECML-PKDD)
[## 了解 LSTM 网络——colah 的博客
这些循环使得循环神经网络看起来有点神秘。然而,如果你想得更多一点,事实证明…
colah.github.io](http://colah.github.io/posts/2015-08-Understanding-LSTMs/) [## 如何用 Keras 在 Python 中开发用于序列分类的双向 LSTM
双向 LSTMs 是传统 LSTMs 的扩展,可以提高模型在序列分类上的性能
machinelearningmastery.com](https://machinelearningmastery.com/develop-bidirectional-lstm-sequence-classification-python-keras/) [## 嵌入|机器学习速成班|谷歌开发者
嵌入是一个相对低维的空间,您可以将高维向量转换到其中。嵌入…
developers.google.com](https://developers.google.com/machine-learning/crash-course/embeddings/video-lecture) [## 用 Word2Vec 进行文本分类
在上一篇文章中,我谈到了主题模型对于非 NLP 任务的有用性,这次又回到了 NLP 领域。我…
nadbordrozd.github.io](http://nadbordrozd.github.io/blog/2016/05/20/text-classification-with-word2vec/)
单词暗示特征背后的语言模型概念
N 元语法的简单介绍

Photo by Ksenia Makagonova on Unsplash
介绍
你可能在智能手机上见过单词建议功能。当您键入一个单词时,键盘会理解您键入的内容,并建议下一个相关的单词。如果你选择了建议的单词,它会建议另一个,一个又一个,直到你得到这些有趣的句子。
这是一个简单的概念,称为 语言建模 。所以语言建模所做的是,它阅读书面文本,并试图为下一个单词分配概率。让我们看一个例子。

Figure 1: Language model tries to guess what the next word is. (number on the right is probability)
直观地,假设我们有 100 个单词要考虑下一个单词,语言模型会考虑上一个单词,并给出这 100 个单词的概率。然后,作为单词建议功能的一部分,它可以向用户提供前 3 个选项。现在,让我们给 LM 一个正式的定义。
语言模型

Figure 2: An example sentence with its notation
通常,语言模型被称为,一种赋予句子概率的方式。
但是等等!我们之前不是提到过 LM 给下一个单词分配概率吗?让我们分解上面的等式来进一步研究这个问题。

Equation 1: Probability of a sentence based on probability of predicting next word
正如你在等式 1 中看到的,LM 不仅可以给下一个给定的单词分配概率,还可以给整个句子分配概率。然后,LM 可以理解哪个句子听起来好,哪个不好。

Figure 3: Language model determines which sentence is more suitable than the others
太棒了,对吧?但是在如此强大的功能背后有什么呢?有许多方法可以创建这种语言模型。在这篇文章中,我们将探索一个简单的方法,叫做 n-gram 。
n 元语法
一个关键的想法是 ngram 一次只看 n 个单词。让我们以“猫坐在垫子上”为例。

Figure 4: Behavior of bigram
假设 n=2(也称为 bigram),它会尝试根据第一个词预测第二个词。例如:
- 猫 : Bigram 试图记住“the”后面应该是“cat”。
- cat sat:“cat”后面应该是“sat”。
- 坐在上:“坐”之后是“开”
n=3 的情况也是如此。对于单词“猫坐”,三元模型知道“坐”在“猫”之后。我想你明白了。
这个概念可扩展到 n 个单词(n-gram)。那么,ngram 如何知道所有这些模式呢?是概率论。
二元模型
为了简单起见,我们将看看二元模型的情况。从上面的例子中,我们知道“cat”在“the”之后,可以表示为 P(cat | the) 。
P (cat | the):给定单词“the”,下一个单词是“cat”的概率。
要计算这个概率,只需使用下面的公式。

Equation 2: Probability for Bigram
其中 c(猫)是“猫”在整个语料库中的出现次数。同样的道理也适用于 c(the) 。直观地说,这个等式表示:在所有的单词“the”中,有多少个单词后面是“cat”?瞧,现在我们有了。
二元模型与三元模型
Bigram 很简单,功能也很强大,但是在很多情况下它无法执行。例如:

Figure 3: Bigram fails when it has the same previous word
在句子的开头,模型看到“the”后面跟着“cat”。如果我们使用 bigram,并且仅依靠之前的一个单词,则很难猜出下划线单词是“mat ”,因为它可能再次生成“cat”。幸运的是,三元模型或四元模型可以解决这个问题。也就是说,如果我们看到“坐在”,下一个词很可能是“垫子”。
然而,这并不意味着我们考虑的序列越长,预测就越好。例如,对于 6-gram 来说,可能很难看到确切的“猫坐在”。因此,它不是很有效。
大多数时候,二元模型和三元模型是常见的选择。
后退和插值
也有这样的时候,你的数据集很小,3-gram 不能识别一些精确的单词;因此,导致概率为 0。这将使您的整个 3-gram 实现不再有用。
你可以很容易地做一个简单的 if-else,并在 3-gram 失败的情况下使用 2-gram。或者在 2 克失败的情况下使用 1 克。有种叫做,退避。
另一种技术,插值,是同时考虑不同的 ngrams。这个想法是给你的 n-gram 赋予权重(λ),这样你的 3-gram 模型也可以查看 2-gram 和 1-gram 的值。即
- 3 克装 60%
- 2 克装 35%
- 1 克含 05%

Equation 3: Interpolation of 3-gram
手动配置重量,直到你觉得它是正确的。你也可以使用一些自动的方法,但是我们不会在这篇文章中讨论。有关如何正确设置这些重量的更多信息,您可以参考和。
履行
现在让我们试着用这个 LM 来生成一个基于随机首字的句子。对于这个任务,我们将使用哈利波特与魔法石电影剧本来训练我们的 ngram。对于下面的代码,你也可以在上找到这个内核。
然后,我们就可以统计出一元词、二元词和三元词的出现频率。这将在以后用于计算概率。
既然我们可以计算 n-gram 的数目,我们就可以计算它的概率。对于 1 克、2 克和 3 克,我们将分别使用 0.01、0.4 和 0.5 的线性插值。
让我们试着造 20 个单词。首字母将被随机化,并选择最好的下一个单词。
那么,这将如何表现呢?下面是每一代的结果。
Generation #1:
protecting the stone , but i think i 'll be a wizard . . . . . . . .Generation #2:
platform 9 3/4 ? think you 're going to be the same . . . . . . . Generation #3:
sacrifice himself , he 's got a little bit . . . . . . . . . . .
结论
N-gram 是一种简单而强大的语言建模技术,只需查看 2 到 3 个单词。由于计算简单快速,它在许多应用中非常实用,例如移动设备上的单词建议。然而,N-gram 在生成长句时并不健壮,因为长句中的当前单词依赖于句子中的第一个单词。这种长期依赖关系更适合神经网络之类的模型,但这是以后文章的主题。
参考
- https://web.stanford.edu/~jurafsky/slp3/3.pdf
- https://towards data science . com/introduction-to-language-models-n-gram-e 323081503d 9
- http://www . cs . UMD . edu/class/fall 2018/cmsc 470/slides/slides _ 10 . pdf
情感分析:一个实用的基准
使用 FCNNs、CNN、RNNs 和 Python 中的嵌入对客户评论进行分类。
通过动手实践 Python 代码,我们展示了简单递归神经网络的局限性,并展示了嵌入如何改进用于情感分类的全连接神经网络和卷积神经网络。

我们通过对电影评论数据集进行情感分类,展示了如何处理序列数据。情感基本上是感情,包括用自然语言写的情感、态度和观点。

IMDB 电影评论数据集
我们首先使用 Keras API 加载 IMDB 数据集。评论已经被符号化了。我们希望有一个有限的词汇表,以确保我们的单词矩阵不是任意小的。我们还希望有一个有限长度的评论,而不是必须处理非常长的句子。我们的训练数据集有 25,000 条客户评论,以及它们的正确标签(正面或负面)。

上面你可以看到一个例子,是一个数字列表,也叫做单词向量。每个数字代表一个单词在词汇表中的索引。如果您需要更深入地了解机器学习的文本表示,您可能想在继续之前看看下面的文章。
理解书面单词:温习 Word2vec、GloVe、TF-IDF、单词袋、N-grams、1-hot 编码…
towardsdatascience.com](/representing-text-in-natural-language-processing-1eead30e57d8)
通过将单词 vectors 转换回文本,下面的代码可以用来以纯文本显示评论。我们运行一个样本正面和一个样本负面审查的代码。

FCNN、CNN、RNN 的情感分析基准
一个句子可以被认为是一系列具有跨时间语义联系的单词。就语义联系而言,我们的意思是,出现在句子前面的词在句子的后半部分影响句子的结构和意义。在理想情况下,一个句子中还有向后的语义联系。它们通常是通过将句子以相反的顺序输入到一个模型中来捕获的。
递归神经网络可用于提取、识别或表征文本的情感内容,并将其分类为正面或负面。
一个有趣的和有插图的指南来理解直觉。
towardsdatascience.com](/recurrent-neural-networks-explained-ffb9f94c5e09)
我们将这种方法与全连接神经网络、卷积神经网络以及两者的组合进行比较。
下面的代码运行 ca。在 Google Cloud 的 GPU 实例上运行 2 小时。

未看过的电影评论(测试数据集)的分类精度如上表所示。令人惊讶的是,具有嵌入的全连接神经网络优于其余的网络。这是一个 250 个节点完全连接的单层网络。卷积神经网络具有类似的精度。虽然 CNN 被设计为尊重图像数据中的空间结构,同时对场景中学习到的对象的位置和方向具有鲁棒性,但这一相同的原理也可以用于序列,例如电影评论中的一维单词序列。使 CNN 模型对于学习识别图像中的对象有吸引力的相同属性可以帮助学习单词段落中的结构,即对于特征的特定位置的技术不变性。在研究社区中,关于 CNNs vs RNNs 仍然存在公开的争论。在电影评论分类的情况下,与没有嵌入的全连接网络相比,简单的 RNN 在处理序列数据中是有用的。
自由文本上的情感预测
下面我们在自由文本评论上测试我们的模型。每个评论首先被标记化,然后被转换成用于预测的词向量。正面评论的概率被选择为大于 0.5。

带有嵌入的完全连接的神经网络对所有四种情绪都是正确的,而其余的模型有假阳性和假阴性。我们的 RNN 和 CNN 的性能肯定可以通过在更强的 GPU 机器上增加训练时段的数量来提高。
结论
在本文中,我们展示了神经网络如何解决电影评论的分类问题,同时对卷积神经网络的全连接方法进行了基准测试。简单的 RNN 是一个“非常深”的前馈网络(当在时间上展开时)。除了爆炸和消失梯度的问题,在实践中,他们不能学习长期的依赖关系。LSTMs 的明确设计是为了避免长期依赖问题。这里没有涉及它们,也没有涉及朴素贝叶斯,朴素贝叶斯是一种概率性的情感分析方法。
有助于理解 RNN 和 LSTM 运作的两个最好的博客是:
- http://karpathy.github.io/2015/05/21/rnn-effectiveness/
- http://colah.github.io/posts/2015-08-Understanding-LSTMs/
你也可以看看我的其他文章,详细解释 LSTMs 和一般的深度学习。
厌倦了德法数据集?看看 Yemba,脱颖而出。力学的 LSTM,GRU 解释和应用,与…
towardsdatascience.com](/lstm-based-african-language-classification-e4f644c0f29e) [## 深度学习为什么有效:解决一个农民的问题
在开始是神经元:梯度下降,反向传播,回归,自动编码器,细胞神经网络…
towardsdatascience.com](/why-deep-learning-works-289f17cab01a)
情感分析——电影评论指南
现实世界中的数据科学
你觉得情感分析怎么样?好/坏?到这篇文章结束的时候,你会觉得积极向上!

Image retrieved from Kaggle
那么,到底什么是情操?情感与一个单词或一系列单词的意思有关,通常与一种观点或情感有关。还有分析?嗯,这是看数据,做推论的过程;在这种情况下,使用机器学习来学习和预测电影评论是正面还是负面。
也许你有兴趣知道电影评论是正面还是负面,公司在各种场合使用情感分析,特别是出于营销目的。用途包括社交媒体监控、品牌监控、客户反馈、客户服务和市场研究(“情绪分析”)。
这篇文章将涵盖:
- 竞争
- 预处理数据
- 特征
- 系统模型化
- 估价
- 后续步骤
竞争
我们将使用 IMDB 电影数据集,其中有 25,000 条带标签的评论用于训练,25,000 条评论用于测试。 Kaggle 挑战赛要求二进制分类(“一袋单词和一袋爆米花”)。
让我们来看看数据集的一些汇总统计(李,2019)。我们被告知,积极和消极的电影评论平分秋色。以下是一些正面和负面的评论:

Selection of reviews including all the formatting and typos.
看到电影评论(字数)长度的分布根据情绪分裂也很有趣。这两种类型的评论的传播形状相似,但是负面评论平均来说要短一些。

Graph of word count frequency according to sentiment.
预处理
文字是杂乱的,人们喜欢通过添加过多的标点符号和拼写错误来更清楚地表达自己。然而,机器学习模型无法处理作为输入的文本,因此我们需要将字符和单词映射为数字表示。
文本的基本预处理包括删除非字母字符、停用词(一组非常常见的词,如 the、a 和等)。)并将所有单词改为小写。在这种情况下,我们还需要从电影评论中删除 HTML 标签。这些步骤可以打包成以下函数。
Code to process movie reviews.
下表显示了当停用词从评论中删除后,最常用的词是如何变化的。

Table of frequent words with and without stop words.
特征
我们应该如何将单词表示转换成模型可以解释的数字形式?有许多方法,但是现在,让我们尝试一些简单的方法。
一袋单词
我们从语料库(整个文本数据集)中获得词汇表。词汇表的长度等于我们应用单词包(BOW)时输出的向量的长度。对于每一项(可能是一个条目、一句话、一行文本),我们将文本转换成向量形式的频率计数。在这种情况下,我们将其限制为前 5000 个单词,以限制数据的维度。我们通过从 sklearn 的库中设置一个计数矢量器来对此进行编码,使其适合训练数据,然后转换训练和测试数据。
下面的灰框中给出了一个例子。我们查看语料库中所有独特的单词,然后计算这些单词在每段文本中出现的次数,从而得到每段文本的向量表示。
Text:It was the best of times,it was the worst of times,it was the age of wisdom,it was the age of foolishness.Unique words:
"it", "was", "the", "best", "of", "times", "worst", "age", "wisdom" "foolishness""it was the worst of times" = [1, 1, 1, 0, 1, 1, 1, 0, 0, 0]"it was the age of wisdom" = [1, 1, 1, 0, 1, 0, 0, 1, 1, 0]"it was the age of foolishness" = [1, 1, 1, 0, 1, 0, 0, 1, 0, 1]
Word2Vec
Word2vec (Word to Vector)是一个处理文本的两层神经网络。它的输入是一个文本语料库,输出是一组向量:语料库中单词的特征向量。该算法由谷歌在 2013 年创建。50 维空间可以通过使用经典的投影方法(例如 PCA)来可视化,以将向量减少到可以在图上绘制的二维数据。
为什么我们要用 Word2vec 而不是 BOW?它更擅长在周围环境中学习单词。这个过程比实现 BOW 要复杂一些,所以我不会在这里概述,但可以在的 GitHub 文件夹中找到(Dar,Green,Kurban & Mitchell,2019)。简而言之,它需要将评论标记为句子而不是单词,确定向量表示,然后适当地平均它们。
Tf-Idf
这是 Term-Frequency-Inverse-Document-Frequency 的缩写,它为我们提供了一个衡量单词在文档中的重要性的方法。
术语频率(与单词袋相同):

逆文档频率衡量一个术语在所有文档中的稀有程度(值越高,单词越稀有)【1】:

我们将这两者结合起来得到 Tf-Idf,如下所示:

为了实现这个表示,我们使用了来自 sklearn 库的 TfidfTransformer 函数。对训练集进行拟合,并为测试集确定相同单词的值。
Code for some of the features.
【1】其中 ln 为自然对数。
系统模型化
我们为这个数据集尝试了两种不同的模型:朴素贝叶斯和随机森林。朴素贝叶斯建立在贝叶斯定理的基础上,而随机森林是一组决策树。这两个实现的合并代码可以在 GitHub 存储库中的 NLP _ IMDb·朱皮特笔记本中找到(Dar 等人,2019)。
朴素贝叶斯
这是一个用于分类的概率机器学习模型,基于贝叶斯定理:

b 是证据,而 A 是假设(Gandhi,2018)。我们必须假设这些特征是独立的(一个不影响另一个)。
根据这个问题,我们用 y 表示正面或负面的评论,X 表示评论的特征向量。我们最后得到的寻找类的等式是:

这是使用 sklearn 的朴素贝叶斯包实现的!
随机森林
随机森林是一系列决策树,其中的叶节点表示预测的类别。我们可以使用 sklearn 的 ensemble 包中的 RandomForestClassifier 函数。
每个决策树都包含一组特征,并在最后输出一个决策。然后将所有决策树的结果结合起来,给出最终的类别预测。来自 DataCamp 的下图很好地展示了这一过程。

Image retrieved from DataCamp
估价
Kaggle 指定使用 ROC 曲线下的面积作为本次比赛的衡量标准。ROC 是接收运营商特征的缩写,是一种概率曲线。它将真阳性率与假阳性率进行对比。【2】这条曲线下的面积越高,模型预测产量就越好。下面是单词袋和随机森林的图表。虚线表示基线,如果预测是随机的,那么这是可以预期的。

The area under the ROC curve for Bag of Words with a Random Forest.
我们可以在下表中检查一些不同的排列。

Table of results for various feature and model combinations.
有趣的是,与随机森林相比,Tf-Idf 表现稍好,而朴素贝叶斯表现稍好。然而,具有 Word2Vec 特性的朴素贝叶斯的性能会显著下降。这可能是因为当表示转换为正数时丢失了一些信息(因为朴素贝叶斯只允许正值),而使用了高斯朴素贝叶斯。
[2](#_ftnref1) True positive 表示当一个项目为正数时,它被预测为正数。假阳性表示阴性项目被预测为阳性。
后续步骤
这只是情感分析的开始。进一步的方法可以使用二元模型(两个单词的序列)来试图保留更多的上下文含义,使用 LSTMs(长短期记忆)等神经网络来扩展评论中单词之间的关系距离等。
参考
一袋文字遇上一袋爆米花。(未注明)。从https://www.kaggle.com/c/word2vec-nlp-tutorial/取回
达尔,奥,格林,s,库尔班,r .,,米切尔,C. (2019)。冲刺三,一队。从 https://github.com/shiaoligreen/practical-data-science取回
甘地,R. (2018 年 5 月 5 日)。朴素贝叶斯分类器。检索自https://towards data science . com/naive-Bayes-classifier-81d 512 f 50 a7c
李,s .(2019 . 3 . 18)。一个完整的探索性数据分析和文本数据的可视化。检索自https://towards data science . com/a-complete-explorative-data-analysis-and-visualization-for-text-data-29fb 1b 96 FB 6a
情感分析。(未注明)。从 https://monkeylearn.com/sentiment-analysis/取回
情感分析和登月
应用机器学习结合基于规则的方法来理解第一次载人登月 50 周年后的情绪

The lunar lander ‘The Eagle’ on its descent towards the surface of the moon. Nasa
1969 年 7 月 20 日,月球着陆器向休斯顿报告:
休斯敦,这里是宁静湾。老鹰着陆了。
在过去的几天里,世界各地的媒体参加了庆祝首次将我们带到月球的史诗般的月球任务 50 周年的活动。从存档材料中可以清楚地看出,这一里程碑被广泛誉为人类成就的巅峰。然而,与此同时,人们也对阿波罗计划的巨额费用提出了质疑。这些资源本可以更明智地使用吗?这种观点认为,我们仍然在地球上与挑战作斗争,所以为什么要去太空寻找更多的挑战。
我们如何去了解今天的普遍意见呢?自 1969 年以来发生了一些戏剧性的变化,使我们能够对最普遍的情绪有一个更广泛的了解。通过社交媒体以及强大算法的出现,我们拥有了丰富的信息,这些算法允许我们以各种方式自动处理数据。想象一下拥有可以告诉我们一个陈述的情感内容的机器!情感分析的应用在我们的社会中扮演着越来越重要的角色,从产品开发到衡量不同公共政策的受欢迎程度。我们将探索情绪分析是如何完成的,并看看如何利用它来解码基于 50 周年前后收集的 twitter 数据的公众情绪。
为什么要进行情绪分析,这是怎么一回事?
情感分析,或观点挖掘,是关于发现人们对产品、服务或话题的观点、情感和感受。自动情绪分析的效用来自于这样一个事实,即可用的结构化反馈,如从您的酒店评论部分的星级评级中收集的反馈,通常非常稀少且缺乏深度。我们更倾向于在社交媒体上发布更微妙的反馈和评论。随着处理大量文本形式的非结构化数据的现代工具的出现,公司和组织开始挖掘这个洞察力的金矿。
情绪分析涵盖不同的类别,如极性、主观性,甚至包括快乐、悲伤、愤怒和惊讶等情绪:

我们在本文中关注的情绪类型与书面陈述的“极性”有关,即特定推文的整体积极或消极程度。需要注意的是,情感分析并不是一个完全被征服的领域。即使对于最先进的算法,这仍然是一项艰巨的任务,这使得它成为研究人员和商业开发人员非常感兴趣的领域。
对社交媒体数据进行情感分析时面临的挑战
我们表达自己的方式因个体差异和文化背景而异。甚至我们一时的情绪也会影响我们选择如何表达自己,并且会在一天中发生变化。不同文化之间也有很大的差异,例如,我们表达不同感情的强烈程度。在社交媒体数据的情感分析方面,一些最常见的挑战是:
俚语、拼写错误和非常规的语言使用
b)一条推文中不同主题的多种观点
c)修饰词和否定词(强化/弱化或转化情感)
d)模棱两可的话(“生病”可能意味着你生病了,或者某事实际上非常好)
e)符号、表情符号和表情符号;-)
f)讽刺和讽刺,甚至人类犯的错误比我们想象的还要多

除了这些特定语言的挑战,还有偏见和不平衡数据的挑战。与某些主题相关的各种社交媒体平台可能有偏见,不代表全体民众的意见。不平衡的数据对于机器学习模型来说可能是具有挑战性的。想象一下,90%的“训练”数据有积极的情绪,那么模型在区分中性和消极情绪方面可能表现不佳。语言也不是一成不变的,而是不断发展的,任何模型都需要不断地被监控和更新。甚至人类也不能总是完全处理与情感分析相关的所有挑战,尤其是在文本形式中,其中存在有限的视觉线索,例如发送者的面部表情。
基于规则 vs 机器学习
进行情感分析有两种主要方法:
- 基于规则的专家系统(又称词典方法)
- 机器学习(人工智能的子领域)
基于规则的方法依赖于“词典”,它是一个包含大量单词的词汇表,每个单词都有一个预定义的情感值。例如,单词“恨”的情感值为-0.57,而“爱”的情感值为+0.63。在其最简单的形式中,该算法将文本中每个单词的所有情感值相加,以计算整体情感。基于规则的方法的优点是,给定足够大的词典,它们是相当准确的,并且人们可以容易地描述每个情感分类是如何形成的。
第二种方法基于机器学习,像人类一样从经验中学习。一般来说,经历或训练越多,这些模型在预测情绪方面就越好。有许多机器学习算法,数据科学家的任务之一是了解哪些算法与哪种类型的问题相关。机器学习方法有可能比基于规则的方法更好地扩展,并且已经被证明是惊人地准确。然而,与更透明的基于规则的方法相比,它需要大量的训练数据,并且对于一些算法来说,更难解释如何做出某个预测。我们将进一步研究如何应用机器学习和基于规则的方法来进行情感分析,并对它们进行比较。第三种选择,通常在工业中使用,是使用一种结合了两者优点的混合方法。
让我们开始吧
在我们准备好计算整体情绪之前,我们需要执行许多步骤。我们采用的方法是数据科学家的方法:
1.阐明假设和定义目标
2.获取和探索数据
3.训练和评估模型
4.预测情绪并分析结果
1。 制定假设,明确目标
在我们进入数据之前,定义一个明确的目标并决定如何衡量我们的成功率是非常重要的。我们的目的是看看我们是否能对当前与美国宇航局在阿波罗计划期间进行的太空探索有关的情绪有所了解。假设是,我们将会注意到登月 50 周年所带来的所有关注所带来的更大影响。这项任务是预测 7 月 20 日前后几天 Twitter 消息的极性。极性将被定义为属于三类之一:正、负和中性。极性还会有一个振幅,例如,一条推文可以是正的(+0.23)或非常正的(+0.91)。
如上所述,我们将评估两种不同的情感分析方法,基于规则和基于机器学习。为了比较它们,我们将使用一个所谓的“混淆矩阵”。混淆矩阵通常用于这些类型的分类任务,并以结构化格式展示正确和不正确的分类:

The confusion matrix
我们希望最大化正确预测情感(绿色)的数量占所有预测情感的比例。这被称为模型的准确性。相反,我们希望最大限度地减少错误预测情绪的数量(黄色和红色)。由于我们对积极情绪和消极情绪之间的比例感兴趣,我们将格外关注避免假阴性和假阳性(用红色标记)。这些类型的错误分类将在最大程度上影响正面和负面之间的比率。错误分类的中性情绪(黄色)也值得最小化,但不如假阳性/假阴性率优先。

混淆矩阵有时会令人混淆,所以让我们来看一个例子。看看下面这条推文:
“阿波罗 11 号的一个伟大时刻是美国国家航空航天局宣布发射期间宇航员的心率”
一个情绪模型预测它带有积极的情绪(+0.62,其中+1.00 是最积极的),这与人类对它的评价一致,使它成为真正积极的:

Confusion matrix with one correctly made sentiment prediction
现在考虑这条推文:
“美国国家航空和宇宙航行局只是隐藏秘密太空计划和其中的先进技术的烟幕”
它显然是负面的,但一个情绪模型预测它是正面的* (+0.08),使它成为一个假正面的预测(使用 0 的截止值,所有低于 0 的都被归类为负面)😗

Confusion matrix with one incorrectly made sentiment prediction
另一个值得注意的评估分类器的方法是接收器操作特性。但是为了简单起见,我们将在这里集中讨论混淆矩阵。
因此,总结一下:我们希望通过捕获每个类别中的所有情感(回忆)来最大化绿盒(准确性),同时我们希望尽可能多的预测是正确的(精确度)。我们预计会有一部分未分类的推文。但是,由于我们正在寻找积极/消极情绪的比率,我们理想地想要一个在分类积极和消极情绪方面同样好(或坏)的模型。
2。 数据的采集和勘探
为了获取 Twitter 数据,我们设置了一个 Twitter 开发者账户来访问 Twitter API。有了安全的 api,我们将使用 Python 和开源库 Tweepy 连接到 API 并收集 tweets:

具体来说,我们正在查看 7 月 14 日至 7 月 22 日期间收集的英语推文。总共收集了数百万条推文,其中 21 000 条包含关键词[NASA,Apollo,Saturn V 等等。].这些推文被收集到一个数据库中( SQLite ),然后就可以使用 Python 的 Pandas 库进行访问和操作。
此外,我们需要另一个带有标签数据的 twitter 数据集,以便训练和评估我们的两个竞争模型。带标签的数据是指我们知道正确情绪的推文。为了进行适当的评估,我们应该尽可能使用与手头任务相似的数据,例如主题、长度、语言、音调等。一个流行的数据集是斯坦福 Twitter 数据集。它包含了自 2009 年 4 月以来的 160 万条带有注释的推文。

Two datasets: the “Stanford Twitter” for Training & evaluation and the newly scraped sentiments using Twitters API
仔细观察“训练和评估”数据集,我们可以看到它在负(0)和正(4)之间达到了完美的平衡,各有 80 万。请注意,数据集缺乏我们在评估模型时需要处理的任何中性情绪:

Balanced ‘training & evaluation’ dataset
该数据集的标签是使用机器学习算法(参见论文此处)而不是人工注释创建的,因此可能包含一些奇怪和误导性的分类。这个例子似乎普遍适用:
使用牙线。我总是害怕晚上的这个时候(0,即消极)
3。 训练和评估模型
基于规则的模型(无需培训)
如前所述,我们希望评估基于规则和机器学习模型的准确性。对于基于规则的评估,我们将研究一个开源框架 VADER (效价感知词典和情感推理机)。Vader(让我们坚持使用小写字母)是一个基于词汇和规则的情绪分析工具,专门针对社交媒体中表达的情绪。通过规则引擎,Vader“倾听”修饰词(加强/削弱),使用大写字母和感叹号(加强感情)。维达甚至支持表情符号和表情符号。

***from** vaderSentiment.vaderSentiment **import** SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()analyzer.polarity_scores('great minds think alike')['compound']0.6249*
compound分数是通过对词典中每个单词的化合价分数求和计算出来的,根据规则进行调整,然后归一化到-1(最极端的负面)和+1(最极端的正面)之间。
让我们对来自“培训和评估”数据集的推文子集(100 k)进行情感分析,并评估:
*df['Vader_compound'] = df['SentimentText'].apply(**lambda** x: analyzer.polarity_scores(x)['compound'])df.sample()*

基于这些分数,我们可以使用维德文章建议的默认临界值来决定情感分类:
正面情绪:compound得分> = 0.05
中性情绪:(compound得分> -0.05) & ( compound得分< 0.05)
负面情绪:compound得分< = -0.05
根据上述截止值,我们得出以下基于 100 k 样本的混淆矩阵(四舍五入到最接近的 1000):

这相当于 51%的总体准确率(从左上角到右下角的对角线总和,并按预测总数进行划分)。这不是一个令人印象深刻的数字。跳过中性的(在这种情况下,不会影响正/负的总比率,因为它们是近似平均分布的),我们得到 71% 的准确度。请记住,该数据集不包含任何被标记为中性的推文,但模型预测约有 28%属于这一类别。让我们看看这与基于机器学习的方法相比如何。
机器学习
如上所述,我们不仅有一个机器学习模型可供选择,而是有一个由不同算法和方法组成的生态系统。我们将利用所谓的人工神经网络,这种网络近年来以深度学习的名义引起了很多热议。这些神经网络最初是受人脑如何通过以各种方式连接计算机模拟的神经元来运作的启发。这些人工神经元可以被视为实际生物神经元的数学表示。如同生物学上的对应物一样,学习和记忆并不编码在神经元本身,而是编码在神经元之间的连接中。多年来,已经尝试和测试了各种专门的神经网络架构。出于我们的目的,我们将更密切地关注所谓的递归神经网络,它特别能够处理数据序列,如文本,它可以被视为一系列单词和以特定顺序设置的其他令牌。在循环神经网络家族中,我们发现了一种叫做长短期记忆* ( LSTM )的变体。开发 LSTM 是为了应对与测序数据相关的特定挑战,即长期依赖性。对于文本数据,这意味着 LSTM 可以连接跨越大跨度文本序列的模式。其他架构往往会“忘记”,并主要关注文本序列的最后部分。*

如上所述,这些模型需要大量的培训。这意味着我们必须向神经网络“展示”数千条不同的推文以及正确的答案,然后才能用它来预测情绪。

我们可以花很多很多文章来研究神经网络,尤其是 LSTM 是如何工作的。但是在这篇文章中,我们将集中讨论如何设置它们来进行分类情感的特定任务的训练。对于那些对 LSTM 详细工作原理感兴趣的人,我推荐 Christopher Olah 关于这个话题的博客文章。
在获取和探索我们的数据之后,我们继续进行数据清理或其他预处理步骤。我们将删除任何无助于神经网络将特定文本输入与特定情感相关联的内容。这包括:超链接、用户名、转发前缀、数字和标点符号。其他预处理步骤通常包括移除非常频繁的单词(停用单词)、纠正拼写错误的单词、移除表情符号/表情符号以及将单词简化为其基本形式(词干)。人们必须注意,这些结构中的一些可能实际上包含有助于预测情绪的信息。例如,当删除非常频繁的单词时,我们可能会意外地删除否定词(例如,不要,不会),这些否定词可以通过颠倒句子的整个情感来发挥重要作用。
在我们将清理过的推文输入神经网络之前,我们需要将单词转换成数值,以便模型能够消化它们。这意味着我们需要使用以下方法之一将每个单词映射成一个数字:
- 为文本中出现的每个单词分配一个数字,例如,第一个单词被赋予数字 1,最后一个单词将被映射到 38041(如果所有推文中有那么多独特的单词)
- 使用一种叫做TF-IDF(Term Frequency-Inverse Document Frequency)的技术:我们给每个单词分配一个实数,这个实数与该单词在一条推文中出现的频率除以该单词在整个推文中出现的频率成比例。这个词在所有推文中出现的频率越高,实际数字就越低。理论是,一个词在所有推文中越不寻常,它能提供的信息就越多。最常见的词不太可能帮助我们区分不同的推文,以预测情绪。
- 应用单词嵌入(例如 Word2Vec):一种复杂的方法,不仅将每个单词映射到单个数字,还映射到一系列数字(向量),旨在捕捉一个单词可能包含的许多细微差别和维度。这些向量的一个特别有用的特性是,两个单词彼此越相关,向量就越相似。
为简单起见,我们将使用(1)并将单词映射到出现时的数字,并将单词限制在最常见的前 20 000 个:
*# Encode the tweets into sequences of integers
**from** keras.preprocessing.text **import** Tokenizertokenizer = Tokenizer(num_words=20000)
tokenizer.fit_on_texts(X_train)
sequences_train = tokenizer.texts_to_sequences(X_train)
sequences_test = tokenizer.texts_to_sequences(X_test)*
例如,下面这条推文:“现在要睡觉了,晚安各位”
映射到:[43,2,137,27,456,181]
最后,我们需要让推文具有相同的维度(长度),我们可以通过将序列“填充”到最大 25 个单词的长度来实现这一点:
*# Pad sequences
max_length = 25X_train = pad_sequences(tokenizer.texts_to_sequences(X_train), maxlen= max_length)*
tweets 现在是填充的,前面的例子是:
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,2,137,27,456,181]
巧妙的是,0 位数字就是为了这个目的而保留的。
现在我们终于准备好训练神经网络了。我们将使用谷歌称为 Tensorflow 的深度学习开源框架来定义、编译和训练神经网络。为了让它更容易访问,我们将使用 Keras API,它工作在 Tensorflow 之上,非常适合像我们这样的实验性探索。用于训练的数据是来自我们“训练&评估”数据集的一百万条推文。

*# Define neural network modelmodel = Sequential()
model.add(Embedding(20000, 64))
model.add(Bidirectional(LSTM(64, dropout=0.8, recurrent_dropout=0.8)))
model.add(Dense(1, activation=’sigmoid’))model.summary()*

*# Compile model
model.compile(loss=’binary_crossentropy’, optimizer=’Adam’, metrics=[‘accuracy’])# Train the neural network
model.fit(X_train, y_train, batch_size=32, epochs=5, verbose=2, validation_split=0.1)*

经过近两个小时的培训,我们已经准备好对它进行评估。使用与 Vader 相同的数据进行评估,我们达到了 82%的准确率!这意味着在这个测试集中,神经网络可以正确区分 82%的推文中的消极和积极情绪。想象一下,在几行代码中,我们已经能够建立和训练一个“阅读”推特的神经网络,并且可以相当准确地判断情绪是积极的还是消极的。)神经网络在以适当的格式给出足够的训练数据的情况下,其识别模式的能力简直令人敬畏。
与仅使用 CPU(英特尔 i7–7700 HQ)运行相比,GPU (Nvidia GeForce GTX 1060)帮助将训练时间减少了不到一半。
神经网络的混淆矩阵;

神经网络的这种特殊配置(参见上面代码中的“sigmoid”激活函数)输出一个从 0 到 1 的分数(1 是最积极的情绪)。0.5 左右的值介于两个极端之间,可以解释为这些预测更不确定是正还是负。为了减少错误分类的积极和消极情绪的数量,同时使其与 Vader 结果更具可比性,我们可以更仔细地研究这些更中性的预测分数。
下面是一种使用 0.5 左右的临界值引入中性情绪的方法,从而整理出模型对极性不太确定的情绪:
正面情绪:activation function > = 0.65
中性情绪:(activation function < 0.65) & ( activation function ≥ 0.35)
负面情绪:activation function < 0.35
这产生了以下混淆矩阵:

我们已经设法降低了假阴性和假阳性的比例。但我们同时妥协,通过引入 15 k 中性情绪预测,降低了真正正面和真正负面的数量。忽略中性预测,我们现在的准确率为 86% 。设置截止值是为了以平衡的方式分割不正确的预测。我们现在终于可以比较这两个模型了。机器学习模型以 86%的准确率优于基于规则的 Vader 模型,而当孤立地看正面和负面预测时,准确率为 71%。我们有相当大比例的中性错误分类(分别为 28%和 15%),至少在测试的推文中是这样。但我们应该注意的是,我们想要对其进行预测的 twitter 数据可能与“训练评估”数据集中发现的数据具有不同的特征。例如,我们知道我们想要预测的 twitter feed 实际上会包含中性或中性倾向的推文:
在月球形成之前,地球上的一天只有 6 个小时
(中性情绪)
我们实际上不能说不同的模型在识别中性情绪方面有多好,因为评估数据只包含积极和消极的标签。此外,我们可能会遇到带有大量表情符号、大写字母和感叹号的推文,我们还没有训练我们的机器学习模型来融入这些内容。为了这个效果,我们将使用一个混合版本,使用基于 Vaders 规则的预测结合基于机器学习的。为此,我们将采用“协商一致”的方法。这意味着,当神经网络预测与 Vader 模型相同的情绪(积极或消极)时,我们将继续使用神经网络分数作为情绪的基础。当神经网络和维达之间缺乏共识时,我们会将推文分类为中性。

4。 预测情绪,分析结果
最后,我们准备好预测收集的 tweets 上的情绪,并看看结果。我们只需要根据我们定义的关键词过滤掉所有的推文
关键词=[美国宇航局,阿波罗,土星五号,登月,陆地月球]*
查看最频繁出现的转发,我们注意到一些与实际的太空任务无关,所以我们去掉了这些。我们让神经网络和 Vader 算法就情感达成一致,对通过神经网络的推文应用所有需要的预处理。为了使视觉化更直观地解释,我们将把消极情绪和积极情绪分开。我们将转换来自神经网络的负面情绪得分,因此我们最终得到的情绪得分范围是从-1 到 1(而不是从 0 到 1)。我们使用基于 Python 的图形工具 Plotly 及其图表工作室,通过分别绘制所有积极情绪和消极情绪的总和(采用移动平均值使其不那么跳动)来可视化结果:

Predicted sentiments visualized using Plotly’s Chart studio. Times are in UCT (formerly known as GMT)
总体趋势偏向积极情绪,但有趣的是,在登月日前夕,我们看到了明显的消极情绪。此外,向积极情绪高峰的快速转变几乎与实际着陆时间(世界协调时 7 月 20 日 20:17)完全一致。最有可能的是,积极的洪水更多的是由美国晚间新闻广播的时间和影响,全面关注 50 周年。为了进行深入的分析,我们需要仔细观察实际的推文,寻找不同的主题。通过统计 7 月 20 日期间最常用的词(停用词和“关键词”已删除),可以获得一个概览:
*('years', 2302),
('anniversary', 2170),
('ago', 1475),
('one', 1264),
('astronauts', 1213),
('today', 1199),
('go', 1075),
('rocket', 953),
('mission', 938),
('day', 904),*
我们还需要分析任何可能触发特定推文的外部因素。这些外部触发因素可能是与我们想要研究的主题相关的本地或全球新闻。在我们的场景中,这方面的一个例子是 7 月 22 日印度号月船 2 号的成功发射,现在它正在登陆月球表面的路上。
我们用几条示例推文及其预测情绪来总结这一分析。你自己会如何评价这些推文的情绪?
我厌倦了听到我的手机今天的计算能力比美国宇航局阿波罗 11 号的休斯敦任务控制中心还要强
“阿波罗 11 号”的一个伟大时刻是美国宇航局宣布宇航员在发射期间的心率(+0.72)
沃利不是我们家乐高土星五号火箭的粉丝(-0.90)

What is not to like about the LEGO Saturn V rocket?
结论
我个人认为,阿波罗计划执行的登月任务是一项真正鼓舞人心的成就。在我看来,积极的贡献远远超过了成本,主要是通过激励人们追求科学和工程职业。这些地区的受欢迎程度的提高对我们现代的、以技术为基础的经济产生了深远的影响。
在 2018 年期间,许多方法变得出名,这些方法进一步提高了基于机器学习的情感分析的准确性。谷歌的 BERT (变形金刚的双向编码器表示)引起了特别的兴趣。BERT 代表了一个非常大的神经网络,它利用预训练来实现对语言的上下文理解(而不是仅仅在独立的基础上理解不同的单词)。这种上下文理解是通过在海量数据集上对神经网络进行预训练来实现的(想想整个英文维基百科)。在对神经网络进行预训练以“模拟”一种语言之后,它可以通过更有限的训练集来进一步调整以用于特定的任务,例如,用于情感分析,具有最先进的准确性。
除了新的和令人兴奋的神经网络架构之外,还有旨在不仅捕捉文本的极性,而且解码更微妙的情感,例如情感方面(快乐、悲伤、愤怒、惊讶等)的努力。)关于基于机器学习的情感分析的最新发展,请查看代码为的论文。
感谢您花时间阅读这篇文章。希望你已经学到了一些新的东西:
- 情感分析,它的目的和挑战
- 从目标定义到可视化的数据科学周期
- 如何使用混淆矩阵评估分类器
- 如何将基于规则的模型和机器学习模型应用于情感分析
最美好的祝愿/彼得
参考文献
VADER:
休顿,C.J .和吉尔伯特,E.E. (2014 年)。VADER:基于规则的社交媒体文本情感分析的简约模型。第八届网络日志和社交媒体国际会议。密歇根州安阿伯,2014 年 6 月。
LSTM:
Hochreiter,Sepp 和 Jürgen Schmidhuber。"长短期记忆"神经计算9(1997):1735–1780。





浙公网安备 33010602011771号