建立对机器学习恶意软件检测器的信任
我们能相信 ML 系统做出的决定吗?
图片:来源
每一次我们创造一个更强大的技术,我们就创造了改变世界的下一个层次。在 AI 中,我们不会给它们自己学习的机器编程。对人工智能最大的误解之一是,它是一个超级智能的存在,或者我们称之为广义人工智能,它知道一切,比我们所有人都聪明,这完全是一种误解。尽管取得了这些进展,但仍有许多挑战需要更多的科学突破。
“当言行一致时,信任就产生了.”—克里斯·巴特勒
介绍
新通信技术的广泛传播不可避免地促使人们不断改进保护各种数字系统中信息的手段和方法,这些数字系统在现代公共生活的几乎所有领域中运行,从银行、制造业到国防和政府部门。这些系统的特点是各种各样的网络威胁。事实上,计算机网络和互联网已经成为恶意软件作者传播和分发恶意软件的主要工具。网络安全专家普遍认为,由人工智能和人工智能支持的反恶意软件工具和系统将成为现代恶意软件攻击的解决方案。然而,创建一个完美的恶意软件检测系统,检测所有类型的恶意软件,零误报似乎是不可能的。
我们知道,网络安全分析师总是更喜欢可解释和可理解的解决方案,如基于规则或基于签名的检测。这就是为什么本文的重点是回顾恶意软件检测的当前技术水平,指出它们的局限性,并讨论可能的解决方案,以增加对人工智能系统的信任。
目录
- 恶意软件检测的机器学习综述
- 限制由 ML 支持的恶意软件检测成功的挑战
- 克服挑战的解决方案
恶意软件检测的机器学习综述
机器学习是一种数据分析工具,用于在没有明确指示的情况下有效执行特定任务。近年来,ML 能力已经被用于设计用于恶意软件检测的静态和动态分析技术。在这种情况下,我将使用 ML 方法设置恶意软件检测的一些技术状态。
- Hassen 等人提出了一种新的恶意软件分类技术,他们使用静态分析将恶意软件实例分类到新的已知恶意软件家族中。通过从反汇编的恶意二进制文件中提取特征,并使用随机森林算法使用提取的特征对恶意软件进行分类(Hassen et al .,2017)。使用 10,260 个恶意软件实例的数据集,他们报告的准确率高达 99.21%。
- Naeem 等人提出了一种静态分析技术来检测物联网恶意软件(Naeem 等人,2018)。所提出的技术将恶意软件文件转换为灰度图像,并从恶意软件图像中提取一组视觉特征来训练 SVM 分类器,该分类器可以使用视觉特征来区分恶意软件家族。使用来自 25 个恶意软件家族的 9342 个样本的数据集,他们报告了 97.4%的准确率。
- 已经提出了几项工作来使用静态分析技术检测 Android 恶意软件应用。Sahin 等人提出了一种 Android 恶意软件检测模型,使用应用程序权限来检测恶意应用程序(OSahn 等人,2018)。他们使用应用程序所需的权限和加权距离函数以及 KNN 和朴素贝叶斯分类器来检测恶意应用程序。他们报告的准确率高达 93.27%。
- Yeo 等人通过监测网络流量中的恶意行为,提出了一种新的恶意软件检测方法(Yeo 等人,2018)。他们设计了 35 个特征来描述恶意软件实例的恶意流量。他们测试了几种机器学习算法,包括 CNN、MLP、SVM 和随机森林。当使用 CNN 或随机森林时,该方法达到了 85%以上的准确率。
这些技术试图提高恶意软件检测系统的质量和性能,以建立一个健壮的系统。
限制由 ML 支持的恶意软件检测成功的挑战
虽然使用机器学习进行恶意软件检测在静态和动态分析中都显示出有希望的结果,但是存在限制基于 ML 的恶意软件检测器成功的重大挑战。
1.培训费用
第一个挑战是在生产环境中培训和更新恶意软件的成本。不幸的是,恶意软件检测不同于 ML 技术已经成功应用的其他领域,例如计算机视觉、自然语言处理和电子商务。恶意软件实例在短时间内进化并改变它们的行为;反恶意软件供应商的一些研究报告称,新的恶意软件实例可以在发布后不到 24 小时内改变他们的行为。这意味着我们需要经常重新培训我们的恶意软件检测器,以便能够检测新的和变异的恶意软件实例。因此,恶意软件检测的 ML 模型的适应性是一个至关重要的要求,而不仅仅是一个辅助功能。
与计算机视觉、自然语言处理和其他利用 ML 的领域不同,恶意软件实例会继续发展和变化。这通常需要在生产中重新训练 ML 模型,这是一项昂贵而复杂的任务。因此,当使用 ML 进行恶意软件检测时,我们需要换一种方式思考。
2.了解恶意软件检测器
网络安全分析师总是倾向于可解释和可理解的解决方案。因为他们需要调整和优化这些解决方案,以减轻和控制误报和漏报的影响。理解和解释 ML 模型对他们来说是一个新的挑战。任何恶意软件检测器都会产生误报。我们知道恶意软件分析师不会接受那些黑盒恶意软件检测器。这就是为什么我们需要专注于对 ML 模型的解释,以使恶意软件分析师可以接受,他们不需要成为机器学习专家。
3.敌对恶意软件
众所周知,机器学习模型对对手精心制作的输入缺乏鲁棒性。你可以在这里查看我之前关于对抗性攻击的文章。事实上,利用 ML 的恶意软件检测系统可以使用敌对的恶意软件样本来绕过。Kolosnjaji 等人表明,通过使用智能规避攻击,他们可以击败(Raff 等人,2017 年)中提出的深度学习检测系统。
克服这些挑战的解决方案
为了克服我们之前讨论的挑战,我将提出一些新的解决方案。
- 受微服务架构启发的新方法。这意味着构建多个小型、廉价、集中的 ML 模型来检测恶意软件实例。每个模型被构建来检测特定恶意软件实例(例如,、 WannaCry )或单个恶意软件家族(一组相似的恶意软件实例)的行为。此外,每个模型或检测器都是使用相似的特征构建的,例如具有相同的计算成本,或者对于特定的执行环境是唯一的。
使用微型聚焦检测机降低了生产中再培训和部署的成本。这是因为可以训练和添加新恶意软件的检测器,而不需要重新训练现有的检测器。此外,当恶意软件检测器由于恶意软件进化行为而变得过时时,过时的检测器被移除并被新的检测器取代。 - 使用进化计算,我们可以使用一组 IF-Then 规则来描述恶意软件检测器的决策。唯一需要的信息是恶意软件检测器用来做出决定的输入特征。
IF-Then 规则有助于解释触发恶意软件检测器做出特定决定(如恶意或良性)的行为。网络安全和恶意软件分析师对使用“如果-那么”规则感到满意。这些规则将有助于理解恶意软件检测器做出的决定,解释检测的范围,并识别可能导致假阳性或假阴性的潜在过度概括或过度拟合。 - 培训和更新恶意软件检测器是对抗恶意软件的最有效的解决方案。正如我之前提到的,我们无法创建一个完美的恶意软件检测系统。我也相信我们不能设计完美的恶意软件。为此,使用混合机器学习模型(当使用两种或更多种不同的 ML 算法来构建模型时)将有效对抗敌对的恶意软件。这种方法将为恶意软件检测器提供深度防御。
结论
“人们担心计算机会变得太聪明并接管世界,但真正的问题是它们太笨了,它们已经接管了世界。” ― 佩德罗·多明戈斯。
总之,我的文章旨在清理 ML 恶意软件检测器的视野。因为我相信透明度是建立信任的第一把钥匙。通过这篇文章,我们知道目前机器学习模型缺乏鲁棒性。我们知道他们有能力发现隐藏的关系,以解决复杂的问题,如网络安全问题。当然,这方面还需要进一步的研究。而也许有一天我们可以相信 AI 在安全领域做出的决定。就目前而言,我认为在我们能够回答这个问题之前还有很多工作要做。
请关注我,阅读我关于 AI 在安全领域的文章,因为这只是一个开始。✌ ✌ 👌
**快乐阅读,快乐学习,快乐编码。👏
参考资料:
[1] Hassen,m .,Carvalho,M. M .,和 Chan,P. K. 使用基于静态分析的特征进行恶意软件分类
。 2017 年。
[2] Naeem,h .、Guo,b .和 Naeem,M. R. 一种用于物联网基础设施的轻量级
恶意软件静态可视化分析。 2018。
[3]d . OSahn、o . e . Kural、s . akley lek 和 e .基里奇Android 恶意软件基于许可的静态分析的新结果。 (2018)。
[4]萨阿德,s;Briguglio,w .和 Elmiligi,H. 恶意软件检测中机器学习的奇特案例。 2019。
[5] Yeo,m .,Koo,y .,Yoon,y .,Hwang,t .,Ryu,j .,Song,j .,和 Park,C. 使用卷积神经网络进行基于流的恶意软件检测。 2018 年。
[6] Raff,e .,Barker,j .,Sylvester,j .,Brandon,r .,Catanzaro,b .,Nicholas,C. K. 通过吃掉整个 exe 文件来检测恶意软件。 2017。
[7] Kolosnjaji,b .、Demontis,a .、Biggio,b .、Maiorca,d .、Giacinto,g .、埃克特,c .和花小蕾,F. 敌对的恶意软件二进制文件:规避深度学习以检测可执行文件中的恶意软件。 2018
用石灰建立信任:解释机器学习预测
Joshua Hoehne 在 Unsplash 上拍摄的照片
解释机器学习预测,用石灰建立信任
作者:杨紫琼 — 6 分钟阅读
不用说:机器学习是强大的。
在最基本的层面上,机器学习算法可以用来对事物进行分类。给定一组可爱的动物图片,分类器可以将图片分成“狗”和“不是狗”两类。给定关于顾客餐馆偏好的数据,分类器可以预测用户接下来去哪家餐馆。
梯度下降优化器对神经网络训练的影响
由 Daryl Chang 和 Apurva Pathak — 23 分钟读取
欢迎来到我们深度学习实验系列的另一部分,在这里我们进行实验来评估关于训练神经网络的常见假设。我们的目标是更好地理解影响模型训练和评估的不同设计选择。为了做到这一点,我们提出了关于每个设计选择的问题,然后运行实验来回答它们。
Sean Lim 在 Unsplash 上拍摄的照片
实用 Cython —音乐检索:短时傅立叶变换
通过 Stefano Bosisio — 10 分钟阅读
我非常喜欢 Cython,因为它吸取了两个主要编程领域的精华:C 和 Python。这两种语言可以以一种简单明了的方式结合在一起,以便为您提供计算效率更高的 API 或脚本。此外,用 Cython 和 C 编写代码有助于您理解常见 python 包(如sklearn
)下的内容,让数据科学家更进一步,这与简单的import torch
和预定义算法用法相去甚远。
作者形象
互换:soft max-加权平均池
肖恩·贾恩和布莱克·埃利亚斯——7 分钟阅读
我们提出了一种卷积神经网络的池化方法,作为最大池化或平均池化的替代方法。我们的方法 softmax-加权平均池(SWAP)应用平均池,但是通过每个窗口的 soft max 对输入重新加权。虽然向前传递的值与最大池化的值几乎相同,但 SWAP 的向后传递具有这样的属性,即窗口中的所有元素都接收渐变更新,而不仅仅是最大值。
Fatos Bytyqi 在 Unsplash 上拍摄的照片
零到 Jupyter 与 Docker 在亚马逊网络服务上
由约书亚·库克 — 11 分钟阅读
AWS 是占主导地位的云服务提供商。我们不赞同他们的统治地位是使用他们服务的理由的想法。相反,我们提出了一个 AWS 解决方案,它最容易被大多数人采用。我们相信,这种方法将推广到其他基于云的产品,如 DigitalOcean 或 Google Cloud Platform,前提是读者可以通过安全外壳(ssh)访问这些系统,并且它们运行的是 Linux 版本。
GitHub 动作介绍
作者:德博拉·梅斯基塔(Déborah Mesquita)
如果您是 DevOps 和 CI/CD 世界的新手,GitHub 操作可能会有点混乱,所以在本文中,我们将探索一些特性,看看我们可以使用该工具做些什么。
从 CI/CD 的角度来看,GitHub 动作和工作流的主要目标是在每次有变化的时候测试我们的软件。这样我们可以发现错误,并在错误出现时立即纠正。
基于预期目标的场馆调整 RAPM 建设:起源、过程和结果(上)
起源:是什么激励我建造这一切?
据Evolving-Hockey.com报道,在 2019 年至 2020 年常规赛中,明尼苏达州野生滑冰运动员在 NHL 的 goals above replacement (GAR)中领先。换句话说,他们的计算通过调整赛程强度和背靠背等背景因素来隔离团队表现,并将团队守门员的表现与他们的运动员分开,从而得出结论:如果你用一名替补级别的球员(一名容易被替换的球员,低于他们球队图表上的第 13 名前锋、第 7 名防守队员或第 2 名守门员)替换明尼苏达野外的每一名运动员,那么他们的净胜球差将比你对 NHL 中的其他球队做同样的事情时下降更多。更简洁地说:通过这种模式,除了守门之外,明尼苏达野生队是 2019-20 常规赛中 NHL 最好的球队。
如果你不熟悉替代以上的目标,我会列出一些快速的基础:这是一个由 EvolvingWild 制作的非常有效的模型,允许我们通过将玩家的个人贡献与各种外部因素(如竞争、队友和使用)隔离开来,然后将他们的贡献与典型的替代级别玩家的贡献进行比较,并确定他们增加了多少价值,来改善我们的玩家评估。该模型是在单个玩家级别上从头开始构建的,团队价值仅仅是聚合的玩家价值,但统计数据也可以用于团队级别。自 2007-2008 年以来,常规赛进球超过替补的球队赢得了 60.5%的季后赛系列赛,而常规赛排名更高的球队仅赢得了 55.9%的系列赛,这表明该模型具有可靠的预测能力,尽管它本质上是描述性的。我不会进一步深入细节,但这是一个很好的模型,可以说是比目前存在的任何其他曲棍球统计数据更好的“全面”反映球员价值的快照。您可以从这个由模型创建者撰写的 3 部分系列文章中了解更多详细信息:
胜于替补(WAR)是一个由 sabermetric 社区在过去的几年中创建和发展的棒球度量标准…
hockey-graphs.com](https://hockey-graphs.com/2019/01/16/wins-above-replacement-history-philosophy-and-objectives-part-1/)
现在,回到野外。考虑到他们的运动员在净胜球上排名第 19,在得分率上排名第 21,这似乎有点令人惊讶。如果我们假设模型是有效的和准确的——我很乐意这样做——那么模型输出和真实排名结果之间的差异只能用两个因素来解释:
- 荒野有着联盟中最艰难的赛程,每隔一个晚上与联盟中的顶级球队背靠背比赛。
- 荒野的守门员太糟糕了,他们把一个真正的斯坦利杯竞争者降到了第 21 位。
从模型本身来看,多半是后者。他们的守门员以 6.8 个进球 排在 替补之后,排名倒数第一。这意味着,如果你把一个典型的第三阵容守门员放在网上,他们的净胜球将会 提高 大约 7 个球。这比第二差的守门员差得多,第二差的守门员属于底特律红翼队,贡献了 1.2 个进球。这些数字不太容易用储蓄百分比来调和;明尼苏达州守门员的综合扑救百分比为 90.25%,而底特律的守门员的综合扑救百分比为 89.36%。那么,《进化中的曲棍球》是如何计算出底特律有明显更好的守门员的呢?
答案在于调整拍摄质量。Evolving Hockey 根据各种因素(例如报告的离网距离(到目前为止最重要的因素)、报告的离网角度和比赛强度)计算射门得分或失球得分的概率,以计算每次射门得分的概率,并根据射门得分的概率为该射门分配“预期得分”值。(举个例子,一个有 35%机会成为进球的危险射门,其预期进球值为 0.35。)他们的计算发现,与底特律的守门员面对的平均射门相比,明尼苏达的守门员面对的平均射门明显不太可能成为进球——以至于当你调整这些射门的质量时,底特律的守门员看起来要好得多,尽管他们的扑救百分比较低。直觉上,这是有道理的。我们知道,决定射门成为进球概率的最大因素是离网的距离。我们还知道,底特律守门员面对的平均射门距离为 32.2 英尺,而明尼苏达守门员面对的平均射门距离为 36.69 英尺。所以,你有它:野生动物只是需要更好的守门员,他们将是联盟中最好的球队。对吗?
不完全是。虽然明尼苏达州的守门员面对的射门平均来说比底特律的守门员面对的更容易,但我刚刚列出的统计数据可能没有描述实际发生的事情,这也是事实。如果你仔细再读一遍前面的段落,你会发现我很小心地指出这是每次射门的距离。我做出这种区分是因为我有充分的理由相信 Xcel 能源中心(明尼苏达州的主场)的记分员报告说,那些射门的距离比实际距离稍微远一些,并且这些记分员对那些没有入网的射门也是如此。
注:在本文的剩余部分,我将使用术语“射门”不仅指球门上的射门,也指没有入网的射门。这些射门被分析界称为 Fenwicks(以分析师 Matt Fenwick 命名),我用它们来代替射门,因为我相信迫使射门偏出和射门入网是守门员和溜冰者分别拥有的技能,我希望表扬那些在这些技能上表现出熟练程度的人,惩罚那些没有的人。
现在,回到野外:指责明尼苏达州的记分员工作不力似乎有些苛刻,但有太多的证据表明不能置之不理。在过去 13 个赛季中的每一个赛季,明尼苏达主场比赛在冰场两端的平均报道击球距离都比客场比赛的平均报道距离远得多。以下是每一个赛季的数字,显示在联赛平均水平旁边,让你对分布有个概念:
图片由 TopDownHockey
在客场,明尼苏达的比赛风格在比联盟平均水平更接近外线和比联盟平均水平更接近球网之间来回摇摆,但从来没有巨大的差异。在这段时间里,明尼苏达客场比赛报道的平均投篮距离是 34.69 英尺,而所有 NHL 比赛报道的平均投篮距离是…34.69 英尺。相比之下,明尼苏达的主场比赛报道的平均投篮距离是 37.27 英尺。
图片由 TopDownHockey
这不仅仅是一次性事件;在超过 500 场主场比赛、超过 500 场客场比赛和超过 15,000 场 NHL 比赛的样本量中,这种现象年复一年地存在。
对错误的计分假设的一个有效的反驳是,野生动物只是在家里玩的风格不同于在路上。也许他们在主场会加强控制,减少冒险,因为他们觉得自己能够控制比赛的进程,但在客场他们会采用对手更典型的风格。这是有可能的,但是这种趋势也不太可能持续十三季。当你考虑到野外有四个总经理和六个不同的主教练负责这个样本时,这种可能性就更小了,他们每个人都可能部署不同的策略。在这些赛季的每一个赛季中,无论是谁执掌球队,他们客场比赛的平均射门距离从未在任何一个方向上偏离联盟平均水平超过 1.5 英尺,而他们主场比赛的平均射门距离一直超过联盟平均水平 1.5 英尺以上。因此,虽然我们不能 100%确定明尼苏达州的记分员跟踪投篮数据是错误的,但这显然比任何其他结论更合理,需要的假设也明显更少。考虑到这一点,我将继续假设明尼苏达州的记分员确实表现出一种错误地跟踪比实际距离更远的投篮的模式,我将把这种行为模式称为**“记分员偏见”****
现在,我们已经为记分员偏见奠定了基础,并同意在假设它确实存在的情况下继续工作,下一个问题是,这究竟如何影响曲棍球在明尼苏达野生动物替代排名之上的目标。这个问题的答案是防御。在运动员层面,这一指标的防守部分主要是通过预期目标来量化的,正如我们已经提到的,该统计的最大组成部分是报告的允许击球距离。如果明尼苏达州的记分员报告射门距离球网比实际距离远,那么他们的运动员允许的射门的预期进球值将低于这些射门成为进球的“真实”概率,因此看起来这些运动员在抑制预期进球方面比实际情况做得更好。
这是另一种形象化的方式:想象一个对手在投币口击球。如果该射门被正确记录,预期目标模型可以计算出它有 25%的得分概率,并且该射门将被分配相应的预期目标值 0.25。但是,如果明尼苏达州的记分员将此记录为从圆圈外射门,预期目标模型可能会使用报告的距离来计算它只有 10%的得分机会,并且该射门只会被分配 0.1 的预期目标值。这将会不准确地吹捧明尼苏达州的滑冰运动员的防守表现,暗示他们允许一个比他们实际做的更不危险的射门。而且,如果明尼苏达队的守门员在那次射门中允许进球,他们将被错误地记为比预期低 0.9 球,而不是比预期低 0.75 球。这听起来不多,但在一个赛季的过程中,或者在许多赛季的过程中,这加起来是一个非常重要的数字:
图片由jfreshchoke提供。数据来自自然属性绝招。
正如你所看到的,明尼苏达一直被糟糕的守门员表现所困扰。但是这个问题由于记分员的偏见而变得更加复杂,当他们在客场比赛时,这种偏见并不存在。
进攻呢?上表中明尼苏达州的主客场比赛显示了两个队的射门,这意味着明尼苏达州的记分员也报告说,主场比赛中的射门距离球网比实际距离要远。因此,从逻辑上来说,明尼苏达投篮的预期进球值也会不准确地低,因此他们制造危险投篮的进攻能力应该被高估,就像他们压制危险投篮的防守能力被高估一样,对吗?从上面同样的视觉化,看进球 得分 ,而不是扑出,上面的主客场预期支持了这一点:
图片由jfreshchoke提供。数据来自自然属性绝招。
正如你所看到的,明尼苏达的滑手在家里看起来像精英射手,但在路上略低于平均水平。从逻辑上讲,人们可能会怀疑这些问题本质上是相互平衡的。他们确实这么做了。双方的预期目标是平等的。但与防守不同,替换目标以上使用实际目标而不是预期目标来衡量进攻贡献。由于 NHL 审查每一个进球,以确保它进入网内,记分员的偏见将不会在实际进球中发挥作用。从理论上讲,如果野生动物表现出一般的进球能力,不管他们是通过糟糕的射门质量和出色的射门还是相反的方式做到这一点;他们高于替补的进攻目标将是一般球队的目标。
然而,明尼苏达队本赛季实际上并不是一支普通的进攻球队。他们明显高于平均水平。这可能会让你感到惊讶(这让我感到惊讶),但明尼苏达实际上在每小时 5 对 5 进球方面排名第五,在每小时强力进攻进球方面排名第十。这与他们在替补得分上的排名是一致的:在力量进攻部分排名第五,在力量进攻部分排名第九。鉴于这些信息,我可以很舒服地说,这种模式给了他们的进攻一个公平的震动,而防守是这种特定模式的唯一问题。
在我们继续之前,让我们记住我们从哪里开始:发展曲棍球的目标高于替代是一个非常有效的评估指标,它表明在 2019-2020 NHL 常规赛中,明尼苏达野生队拥有联盟中最好的滑冰运动员和联盟中最差的守门员。但是我们有理由非常有信心地相信,明尼苏达州主场馆的记分员一直报告说,射门距离球网比实际距离稍远,我们知道,如果他们和这样做,那么高于替换的进球将高估明尼苏达州滑冰运动员的防守性能,代价是守门员,而他们的进攻没有受到惩罚。
虽然我只关注 XCel 能源中心的记分员,但他们并不是唯一表现出记分员偏见的人。他们甚至不是最糟糕的罪犯。历史上,迄今为止最糟糕的犯规者是麦迪逊广场花园的记分员,他们与明尼苏达的记分员相反,报告说射门比他们更靠近球网,不知何故甚至不如明尼苏达的记分员准确。此外,虽然麦迪逊广场花园在过去两个赛季中实际上已经改善了他们的问题,但明尼苏达仍然没有他们主客场投篮距离之间的最大差异。
图片由 TopDownHockey
正如你所看到的,费城飞人队主场在富国银行中心的平均击球距离的绝对值实际上比在野外要大。达拉斯、阿纳海姆和芝加哥也很近。会不会是大部分冰场都有某种程度的记分员偏见?下面的图像表明情况可能是这样的:
图片由 TopDownHockey
正如你所看到的,球队在主场比赛时比在客场比赛时平均投篮距离的差异要大得多。在客场,每支球队的平均投篮距离在 32.5 英尺和 35.5 英尺之间,而在主场,球队的平均投篮距离在 30.5 英尺和 37.5 英尺之间。另外,主场距离的方差是 2.06 英尺,而客场距离的方差只有 0.31 英尺!
因此,公平地说,明尼苏达州的 Xcel 能源中心可能不是唯一一个遭受记分员偏见的溜冰场。我认为这是有道理的,从逻辑上讲,人为错误在这里发挥作用,大多数记分员做的事情与其他记分员略有不同。在一个完美的世界中,我们会让记分员前往不同的竞技场,以便随机处理这个问题,但这个世界并不完美,这样做会产生大量的旅行费用,所以我们必须利用现有的数据。
我还应该指出,我不是唯一认识到这一点的人,我也不是第一个。2007 年,我十岁的时候,艾伦·赖德发布了“关于‘镜头质量’的产品召回通知”,他在通知中介绍了这个问题并声明:
我们显然有一个 RTSS 得分手偏见的问题。这个问题在麦迪逊广场花园看起来很残酷,但在其他地方显然也很重要。NHL 需要认真审视这一过程的一致性。
许多其他曲棍球分析家认为这是一个问题,并提供了额外的证据来支持他们的立场。很明显,记分员偏见在 NHL 是一个真实的现象。
现在,我们已经确定 XCel 能源中心存在记分员偏见,解释了它如何导致我们不准确地评估明尼苏达州野生的滑冰运动员和守门员,并确定 XCel 能源中心不是唯一存在记分员偏见的竞技场,它只是逻辑上遵循许多其他滑冰运动员和守门员可能会由于记分员偏见而被高估或低估。例如,据报道,过去两年在本田中心举行的阿纳海姆鸭队比赛中,平均射门距离球网 2.56 英尺,比这个样本中阿纳海姆鸭队客场比赛的平均射门距离近 2.56 英尺。如果这个数字实际上是射门距离被不准确报告的结果,那么从逻辑上来说,阿纳海姆的防守表现将被低估,他们的守门员将被高估。达拉斯也是如此,费城反过来也是如此。这里的底线是记分员的偏见导致我们对运动员和守门员的一些不准确的评估,特别是在进球高于替补的情况下。**
我们如何解决这个问题?嗯,我不要。模型不是我做的,我也无权决定如何修复我认为是问题的东西。这甚至不是由我来决定这是一个问题还是需要解决。我在这里的目的只是简单地提供一个估计,即记分员偏差的影响可能在多大程度上歪曲了滑冰运动员和守门员在冰上的实际表现,并允许我们在分析不断发展的曲棍球目标高于替换和其他高级曲棍球统计数据时记住这些估计的影响,这些统计数据使用预期目标,并不考虑记分员偏差的影响。
为了做到这一点,我要做三件事:
- 建立一个预期目标模型,它在测试中表现得足够好,以至于我可以放心地将它作为一个描述性模型来评估已经发生的投篮质量。
- 确定记分员偏差的调整,当我用我计算的调整后的射门距离替换我获得的报告射门距离时,该调整不会损害我的预期目标模型的性能。
- 建立一个规则的调整正负(RAPM)模型,允许我提供一个球员对预期目标的孤立进攻,防守和净影响的点估计。我会这样做,因为 goals above replacement 使用球员对预期目标的孤立影响来对抗来自发展中的曲棍球的 RAPM 模型,作为评估滑冰运动员防守的主要组成部分之一,他们使用的大多数其他组成部分与这一措施密切相关。因此,RAPM 将提供一个坚实的估计,什么样的运动员的贡献将是上述目标的防守组成部分替换。(此外,RAPM 本身也被许多粉丝和分析师用作评估运动员的工具,对球员进攻对预期目标的影响的分数估计在那里比在替代目标中更有分量。)
此过程的最终目标是使用报告的击球距离提供一名选手的单独进攻、防守和净影响的单点估计,使用调整后的击球距离提供一名选手的单独进攻、防守和净影响的单点估计,然后并排显示它们,以便根据这些模型之一提供对记分员偏差的调整如何影响选手或球队的单独影响的估计。我还希望对守门员做同样的事情,使用报告的射门距离提供守门员孤立表现的一分估计,使用调整的射门距离提供守门员孤立表现的一分估计。我的假设是,像明尼苏达州的亚历克斯·斯塔洛克和德万·杜布尼克这样的守门员,在调整了记分员的偏见后,看起来会明显更好。
在第 2 部分中,我将回顾这个过程。敬请关注。
基于预期目标的场馆调整 RAPM 建设:起源、过程和结果(下)
过程:我是如何建立这一切的?
在本文的第一部分,我为几个关键概念奠定了基础:
- 不断发展的曲棍球的高效目标高于替代模型得出结论,明尼苏达州荒野在 2019-2020 年常规赛中拥有 NHL 最好的滑冰选手和最差的守门员。
- Xcel Energy Center 是明尼苏达野生动物队主场比赛的场地,该中心的记分员表现出一种错误的报告模式,即投篮距离球网比实际距离远,我称之为“记分员偏差”。
- 如果射门(定义为射门和失球)被报告为离球网比拍摄时更远,这将导致上述目标高于替代模型以守门员为代价高估明尼苏达州运动员的防守性能,而不会影响运动员的进攻性能。
- Xcel 能源中心的记分员并不是唯一表现出记分员偏见的人。他们甚至不是最差的。
我最后说,我的目的不是“解决”这个问题,而是提供一个估计,记分员的偏见在多大程度上歪曲了滑冰运动员和守门员在容易发生这种情况的冰场上的行为。然后我概述了我打算做的三件事:
- 建立一个预期目标模型,它在测试中表现得足够好,以至于我可以放心地将它作为一个描述性模型来评估已经发生的投篮质量。
- 确定记分员偏差的调整,当我用我计算的调整后的射门距离替换我获得的报告射门距离时,该调整不会损害我的预期目标模型的性能。
- 建立一个正则化的调整正负(RAPM)模型,允许我提供一个滑冰运动员对预期目标的孤立进攻,防守和净影响的点估计。这将允许我比较一个运动员在调整记分员偏差前后的单独影响,并确定记分员偏差对他们未调整结果的影响。
如果您还没有阅读本文的第一部分,我建议您在继续阅读之前先阅读一下。它会让你更好地理解手头的主要概念,并解释为什么我能在我所做的假设下舒服地工作。话虽如此,如果你已经很好地理解了替代目标、预期目标、RAPM 和记分员偏差等概念,并且你真的只是对我最近在 Twitter 上发布的一些图表和统计数据背后的方法论感兴趣,那么请随意继续阅读。
我以最少的编码经验开始了这个过程。我学过一点 Python,包括一门大学入门课程,还完成了 EDX 的免费在线“统计和 R”课程。大概就是这样。虽然我在 Python 方面有更多的经验,但我选择了使用 R,因为在我有限的时间里,我觉得使用 R 更舒服,更重要的是因为 Evolving Hockey scraper 是用 R 编写的。虽然我在这个 Scraper 的主题上,但我不能不感谢 EvolvingWild 创建了这个 Scraper 并向公众提供它。
我用这个刮刀从 2018-2019 和 2019-2020 NHL 赛季的每一场记录比赛中提取数据。我想使用不止一年的样本量,因为我正在研究的所有指标都被认为在多年样本中更可靠,但我选择不使用三年或更长时间的样本量,因为NHL 在 2018-2019 赛季之前缩小了最大守门员垫尺寸。这一根本性的变化对任何投篮成为进球的概率都产生了重大影响,我过去曾注意到,2018-2019 年之前建立的预期进球模型表现出严重低估投篮质量的模式;我不想我的孩子遭受同样的问题。
一旦我确定了我想要的样本并为它收集了数据,下一步就是构建预期的目标模型。我首先对预期目标模型的历史和理论做了一些研究,发现它们通常是用两种方法之一构建的:
- 逻辑回归:一种统计建模技术,使用其他预测变量来预测一个二元变量的概率。在这种情况下,二元变量是投篮是否成为进球,预测变量是距离、投篮角度、比赛实力状态、投篮是否是篮板等。
- 梯度推进:一种用于回归和分类问题的机器学习技术。
这里的两个关键区别是,基于梯度推进的模型比基于逻辑回归的模型产生的结果稍好,但是逻辑回归更容易编码和实现,并且仍然提供良好的结果。因为我的目标是构建一个可靠的模型,我可以轻松地使用它,而不一定是构建最好的模型,所以我选择了逻辑回归。
在确定我可以使用逻辑回归建立一个可接受的模型之后,下一个问题是我如何确定一个模型是可接受的。你如何让一个预期目标模型经得起推敲?我过去“测试”公共模型的一种方法是在团队级别检查预期目标份额(xGF%)和实际目标份额(GF%)之间的相关性。大多数公共模型的 R 在 0.4 到 0.46 之间,因此 R 为 0.4 的预期目标模型将通过该测试。但是这种测试也有问题——一些球队的射门和守门能力比其他球队更好——我从来没有见过一个可信的分析师这样测试一个模型。我想确保我用来测试我的模型的任何方法都是已经被其他分析师使用过的可靠方法,所以我着手确定测试我的模型的最佳过程。
我的研究发现,测试预期目标模型最常见的方法是测量曲线下面积(AUC);通过接收机工作特性(ROC)测试获得的值。如果你不熟悉这些东西,你和几周前的我没什么不同,所以让我来给你解释一下:在第二次世界大战中,雷达接收器操作员是一个分析雷达并确定雷达上的光点是友军船只、敌军船只还是随机碎片/噪音的人。他们进行这些区分的熟练程度被称为他们的“接收器操作特征”接收器工作曲线在 x 轴上绘出了信号检测器的假阳性率,在 y 轴上绘出了信号检测器的真阳性率,曲线穿过并示出了给定假阳性率的对应真阳性率。
无用或完全随机的模型的 AUC 为 0.5,而“一般”模型通常被认为是 AUC 在 0.7 到 0.8 之间的模型。据我所知,他的是每个公众期望的目标模型的范围,大多数更受欢迎的模型在该范围的上端。(作为参考,发展曲棍球的预期目标模型的平均力量击球的 AUC 为 0.7822,强力击球的 AUC 为 0.7183,短手击球的 AUC 为 0.7975。)
请记住,我在这里的目标不是创建现有的最佳预期目标模型,而是创建一个足够可靠的模型,我可以用它作为过去事件的描述模型。我建立的第一个模型使用距离作为唯一的变量,我仍然获得了 0.7045 的 AUC,这在技术上意味着它符合公平模型的条件。为了给你一个形象的描述,我的 ROC 曲线是这样的:
图片由 TopDownHockey
在这一点上,我很兴奋我已经看到了一些结果,但我也意识到我还没有做那么多,我可能应该尽我的努力在前进之前对这个模型的做一些改进。
接下来的几天,我修补了一些我认为可能会提高模型性能的变量。这里的过程只是我构建不同的虚拟变量(值为 0 或 1 的分类变量,表示该变量是否存在),并在添加它们之前和之后测试我的模型的 AUC,以查看它们是否有任何改进。以下是我在最终模型中使用的变量:
- 射击距离。(连续)
- 拍摄角度。(连续)
- 拍摄和之前事件之间的时间差。(连续)
- 射击类型。(分类)
- 射手实力。(分类)
- 游戏实力状态。(分类)
- 之前的事件是否是拍摄团队的外卖。(假人)
- 之前的事件是否是对手的赠品。(假人)
- 一个投篮是否跟随对方球队的一个被阻挡的投篮。(假人)
- 一枪到底是不是冲。(假人)
- 一次击球是否是前一次击球零秒后发生的反弹。(假人)
- 一次击球是否是前一次击球后一秒钟发生的反弹。(假人)
- 一次击球是否是前一次击球后两秒钟发生的反弹。(假人)
- 一次投篮是否是在前一次投篮后三秒钟发生的反弹。(假人)
为什么我在选择篮板球的分类上如此小心翼翼?因为我发现篮板对进球几率的影响有很大的不同,这取决于它们发生的时间。以下是我对每个系数的估计:
图片由 TopDownHockey
我完全可以猜到零秒的篮板最有可能成为进球。这很有道理。我想不到的是,一秒钟的篮板比两三秒钟的篮板更不容易得分。这是为什么呢?我不能肯定地说,但我的理论是:零秒篮板是快速的,没有给守门员时间回到位置的 bang-bang 比赛,而一秒篮板通常是“强迫”射门的结果,守门员只有足够的时间回到位置并准备做出扑救。相比之下,2 秒和 3 秒的篮板更多的是在第一次射门后传球或偏转的结果,这使得守门员离开了位置,造成了更多的“混乱”
这只是我的理论,不管它是不是真的,最终都无关紧要;重要的是,包含这些变量为模型增添了独特的风格,并提高了性能。最后,我得到了 0.7707 的 AUC,仅次于预期目标模型的 AUC。这是我改进的模型中的大鹏鸟的图像:
图片由托普顿曲棍球
如果你回头看第一个只使用距离的 ROC 曲线,你会发现有很大的改善。我对自己在这一点上所做的感到非常自豪,我很高兴能够继续这一过程的下一步,即进行场地调整,以解决记分员的偏见。
创建场地调整是这个过程中最简单的部分,因为已经有很多关于场地调整的优秀作品可供公众使用。在我发现的场地调整中,我发现最可行的两个是迈克尔·舒克斯(Michael Schuckers)(在这篇文章的第 9 页)和肯·克日维奇(Ken Krzywicki)(在这篇文章的第 2 页)。
我实现了两种调整,并使用调整后的距离数据再次测试了模型。我发现 Schuckers 的调整稍微损害了模型性能,而 Krzywicki 的稍微改善了模型性能,将 AUC 从 0.7707 增加到 0.7708,所以我选择了 Krzywicki 的。这是一个非常小的改进,但这正是我所需要的。以下是 Krzywicki 调整背后的方法论:
调整后的距离=(报告距离)-(Rink 平均报告距离)
有时候最简单的方法也管用。
现在,我已经建立了一个预期目标模型,并实施了一个可接受的场地调整,我对 2018-2019 和 2019-2020 赛季的每一个畅通的镜头都有两套预期目标值:一套在场地调整之前,一套在场地调整之后。下一步是建立一个正则化的调整正负模型(RAPM)模型,使用根据报告的击球距离计算的预期目标值来隔离每个运动员的进攻、防守和净影响,然后根据调整的击球距离的预期目标值进行同样的操作。
这是这个过程中最难的部分。请记住,在这个项目之前,我的编码经验非常有限,虽然我通过搜集数据、创建预期目标模型和应用场地调整学到了很多东西,但我仍然远远不是编程专家。不过,在讨论我的经验之前,我将向您概述一下什么是 RAPM 以及我为什么在这里使用它。
我之前说过,一旦我建立了一个 RAPM 模型,我将“对一个球员的单独进攻、防守和对预期目标的净影响进行点估计。”但是你如何得到它呢?曲棍球是一项流动性很强的运动,以至于很难对一名球员的单独冲击做出哪怕是一点点的估计。当你说 RAPM 是在没有使用任何单个结果的情况下计算出的*,而仅仅是冰上结果时,这听起来就更加困难了。*
说实话,这不是一个简单的概念。我花了一段时间来理解它,我已经尝试解释了很多次,几乎每次都失败了。这一次,为了解释 RAPM 是如何工作的,我将从我建立这些模型的经验中吸取教训,并通过尽可能少的数据点来解释这个概念。
让我们假设影响冰上进攻结果的唯一背景因素是康纳·麦克戴维是否在场外的冰上比赛。其他一切——所有其他队友和对手,转变开始于哪个区域,比分是多少——这些都不重要。这听起来是不是很傻?是的,确实是这样,而且完全是愚蠢的,但是我保证这将有助于理解这一点。
这个傻乎乎的虚构世界与现实世界有一个共同点:康纳·麦克戴维(Connor McDavid)极其擅长进攻,并对他的团队产生进攻的速度产生强烈影响,这种速度是以每小时的预期进球数(xGF/60)来衡量的。我们有十个数据点可以让我们准确地确定麦克戴维的影响:没有康纳·麦克戴维的五个班次,球队的进攻率为 2.5 xGF/60;有康纳·麦克戴维的五个班次,球队的进攻率为 3.0 xGF/60。如果我们创建一个名为“Connor McDavid”的虚拟变量,当 McDavid 在冰上时,该变量的值为 1,当他不在冰上时,该变量的值为 0,我们的数据如下所示:
图片由 TopDownHockey
如果我们使用 xGF/60 作为我们的目标变量对该数据进行非常简单的回归,我们的斜率截距形式的趋势线将是 xGF/60 = 2.5 + 0.5*(Connor McDavid)。这意味着,对于没有康纳·麦克达维的典型转变,我们预计球队的冰上进攻预期进球率为 2.5 xGF/60,康纳·麦克达维的存在将该值增加了 0.5,因此我们预计有康纳·麦克达维的转变将看到进攻以 3.00 xGF/60 的比率产生。这意味着康纳·麦克戴维的孤立影响使他的球队的进攻率增加了 0.5 xGF/60。
现在,让我们介绍另一名球员,他也可以影响他们球队的冰上进攻率。记住,除了麦克戴维之外,没有什么比 T4 更重要的了,但是这个球员也很重要。但是我们不知道它们到底有多重要。
幸运的是,有了我们现有的数据,我们可以很容易地计算出它们有多重要。假设这个玩家在没有 Connor McDavid 的情况下跳出来进行转换,他们的冰上 xGF/60 是 2.8。我们知道,除了一名球员的控制之外,绝对没有其他外部因素影响这个比率,我们知道正常的比率是 2.5 xGF/60,所以我们可以得出结论,这名球员对他们球队的进攻率的孤立影响是增加了 0.3 xGF/60。我们不需要观察这种转变,我们不需要计算这个球员有多少进球或助攻——我们确切地知道他们的影响是什么。
现在,如果这个玩家跳出来和 Connor MC David 换班**,他们以 2.9 xGF/60 的比率产生进攻,会怎么样?除了 McDavid 之外,我们不知道其他任何事情,但是 McDavid 在这种转变中在那里,所以我们从他们的冰上率中减去 3.0 xGF/60 的比率,发现他们对他们球队进攻率的单独影响是减少了0.1 xGF/60。同样,我们不需要观察这种转变来知道这个玩家的影响是什么。这是自上而下曲棍球分析的精髓:使用冰上结果来隔离球员的影响。**
现在,回到现实世界。一切又变得重要了。不仅是康纳·麦克达维,还有其他每一个队友,每一个对手,是在进攻区还是防守区开始转移,比分是多少,等等。哦,我们不仅要隔离球员的进攻影响,还要隔离他们的防守影响。这一切都让事情变得更加复杂,给我们的最终价值增加了许多不确定性,这就是为什么我尽可能使用“点估计”这个术语来衡量一个玩家的影响。
虽然事情现在变得更加复杂,但 McDavid 的例子为我们提供了一个如何隔离每个人的影响的例子:除了表示游戏强度、分数、转换开始的区域和其他一些变量的虚拟变量之外,还创建表示溜冰者是否在冰上的虚拟变量,因为我们知道这些事情很重要,并且我们希望对它们进行说明。此外,对于每个滑冰运动员,我们必须创建一个虚拟变量来表示他们是否在冰上,而是一个表示他们是否在冰上进行进攻,一个表示他们是否在冰上进行防守,因为我们想隔离他们的进攻和防守影响,并为每个影响找到单独的点估计。
为了举例说明这一点,我将通过拉 2018-2019 赛季第二场比赛第三阶段发生的一次转变来“分块”我的真实数据集。关于这种转变,你需要知道以下几点:
- 华盛顿首都队主场迎战波士顿布鲁因斯队。
- 华盛顿首都队领先三个或更多的球。
- 这一转变持续了 24 秒。
- 这种转变始于波士顿进攻区的对抗。
- 布鲁因斯拍摄了一个未被阻挡的镜头,该镜头的值为 0.1 xGF。
- 首都队在这一次转移中拍摄了一个未被阻挡的镜头,其值为 0.02 xGF。
- 波士顿的五名选手是布兰登·卡罗、约阿金·诺德斯特龙、克里斯·瓦格纳、诺埃尔·阿恰里和兹德诺·查拉。
- 华盛顿的滑冰选手有安德烈·布拉科夫斯基、布鲁克斯·奥尔皮克、钱德勒·斯蒂芬森、拉斯·埃勒和麦迪逊·鲍威。
这是 RAPM 准备格式转变的局部视图:
图片由托普顿曲棍球
正如您所看到的,顶行从主队的角度将这种转变显示为“进攻”,而从客队的角度将这种转变显示为“防守”,而底行从主队的角度将这种转变显示为“进攻”。上面的图像只显示了一些防守的选手,但这里是进攻的选手。
图片由 TopDownHockey
请记住,整个顶行是从华盛顿首都的角度来看的。在顶行中,xGF/60 是首都队进攻的比率,标记为“进攻”的选手是那些为首都队效力的选手,标记为“防守”的选手是那些为布鲁因斯队效力的选手。相比之下,底部一行是从波士顿布鲁因斯的角度来看的,这意味着 xGF/60 是布鲁因斯产生进攻的速率,标记为“进攻”的选手是那些为布鲁因斯效力的选手,标记为“防守”的选手是那些为首都效力的选手。首都也领先至少 3 个球,所以他们被标记为“上升 3”,而布鲁因斯被标记为“下降 3”
要锁定两个特定的球员,只需看看安德烈·布拉科夫斯基和布兰登·卡洛。从首都的角度来看——第一排——布兰登·卡罗在防守,安德烈·布拉科夫斯基在进攻。从布鲁因斯(最下面一排)的角度来看,布兰登·卡罗在进攻,安德烈·布拉科夫斯基在防守。
这个例子是一个班次对应两行。我使用的样本大小的整个数据集包含 544,502 个移位,总共 1,089,004 行。这听起来很多,但这里的关键概念仍然存在:从每个团队的角度来看,每个班次包含两行,从虚拟变量返回的系数将确定某个变量(如 Connor McDavid 进攻)的存在对团队的预期进球率的影响。
这种使用回归分析曲棍球运动员的概念是基于他们在冰上发生的一切事情,这是大多数现代公共曲棍球分析的核心。我喜欢这样想,RAPM 不是通过专注于进球和助攻等个人统计数据,或者更“高级”的个人统计数据,如封锁传球和区域出口,来从头到尾分析曲棍球,而是从自上而下——因此有了用户名。如果一名球员阻挡了很多传球,并因此阻止了对手积累危险的得分机会,这将显示在他们的防守 RAPM 统计中。如果一名球员在防守区表现一般,努力阻挡传球,但他们是一名出色的前锋,不断阻止对手在转换中建立进攻,这也会在他们的防守 RAPM 统计数据中显示出来。如果他们做好了其中的一些事情,但他们也做了一些其他的事情,这些事情阻止了他们产生强大的影响,谁会真正在乎呢?这是我的哲学。
我的解释清楚地表明,我是 RAPM 的超级粉丝,但我没有在这里使用它,因为我喜欢它。我使用它是因为球员对预期目标的 RAPM 影响是替代目标以上防守部分最重要的指标之一,替代目标以上的其他部分与 RAPM 密切相关,因此提供场地调整前后球员 RAPM 的点估计将显示场地调整对替代目标以上某些部分的影响程度。(RAPM 本身也是一个非常受欢迎的指标,我认为它有助于了解场馆调整可能如何影响 RAPM 本身。)
既然我已经解释了自上而下曲棍球分析的概念,RAPM,以及为什么我选择使用它,是时候解释我是如何实现它的了。如上所示,我的数据框包含过去两个赛季中每次换班的两行:一行是主队“进攻”,一行是客场队“进攻”。我的目标是运行一个回归,通过获得系数估计值来隔离每个外部变量对 xGF/60 结冰速率的影响。
不幸的是,不像前面的例子中虚构的 Connor McDavid 数据,我不能只运行一个标准的多元线性回归。这有三个原因:
- xGF/60 表示某事物发生的速率,不考虑结冰时间。两次移动的速率可能相等,都是 4.0 xGF/60,但是如果其中一次发生在两分钟内,而另一次发生在两秒内,我们就不能简单地将它们组合起来,就好像它们是同一件事一样。两分钟内发生的那次更有意义。
- 数据中存在大量多重共线性。这是一种奇特的说法,表明这些数据中的许多变量彼此高度相关,这是一种奇特的说法,表明像肖恩·莫纳汉和约翰尼·高德罗这样的球员几乎所有的时间都在一起打球。具有多重共线性的数据集上的传统线性回归导致极不稳定的系数估计。
- 这种不稳定性也会存在于在非常小的样本中发布极端结果的玩家身上。如果你运行一个简单的多元线性回归,“最好的”球员可能会成为某个打了 13 分钟,冰上命中率达到 72%的人,或者类似的荒谬的人。
对于第一个问题,有一个非常简单的解决方法:使用轮班持续时间作为权重,将其转换为加权多元线性回归。砰,简单,搞定。
还有一个解决方案可以同时解决第二个和第三个问题,但是有点不太简单:正则化(RAPM 的 R)。正则化是一种数学技术,它使系数估计值偏向总体均值零。为了简化这个概念,并把它变成曲棍球术语,我们本质上是说,直到我们有足够的数据来准确地估计一个球员到底是什么,我们将假设他们大致是平均水平。这不仅适用于自己玩过很小样本的选手,也适用于玩过大样本,但是没有某个队友的小样本的选手。
我使用的正则化版本被称为岭正则化或吉洪诺夫正则化,我将这些系数偏向零或“收缩”它们的程度由我通过对我的原始数据集进行交叉验证测试获得的λ值决定。运行的最终回归被认为是“加权岭回归我可以更详细地解释这在数学上到底意味着什么,但是现在,这个模型仍处于测试阶段,我宁愿坚持从曲棍球的角度用尽可能少的数学来解释这个过程。
这整个过程与 Evolving Wild 用来建造他们的 RAPM 模型的过程极其相似。我非常感谢他们的赞扬;如果没有它,我不确定我能不能造出自己的模型。我有意密切跟踪他们的过程,因为正如我在第一篇文章中所述,他们的 RAPM 模型的防守部分在他们的目标替换模型中起着很大的作用,而大多数其他部分与 RAPM 密切相关,因此根据 RAPM 在场地调整前后对球员防守影响的点估计将使我了解场地调整如何影响替换后的防守目标。
虽然我的过程在设计上非常相似,但它在两个方面有所不同:我使用了不同的预期目标模型来构建它,并且我同时使用了两年时间。一次使用两年时间给了我更大的样本量,这意味着我通过交叉验证获得的 Lambda 值比我只对一年的数据进行交叉验证获得的值要小。因此,我的系数在那里“缩小”或偏向零,比进化的 Wild 的系数小度,我在光谱的两端得到更大的值。
虽然这是本文的第二部分,我不应该在第三部分之前讨论结果,但我仍然觉得有必要提供一个结果作为较小的 Lambda 值所做的示例,所以我将与 Mark Stone 一起讨论。在过去的两年里,根据我们的两个模型,他在平均实力下对预期目标的净影响是所有球员中最高的。但是他们的模型对他的净影响的系数估计是+0.46 xG/60;在场地调整之前,我的模型的系数估计值为+0.701 xG/60。
直观地说,我更喜欢同时使用多个年份的*,因为*的λ值较低,因此系数估计值较大。换句话说,我认为像 Mark Stone 这样的精英玩家的真实孤立影响可能比他们更接近我的系数估计,我更喜欢使用一种方法来使这种类型的结果成为可能。但这是个人喜好的问题,两种方式都有各自的优缺点。
一旦我使用通过报告的击球距离计算的预期目标值完成了这个过程,我就使用通过调整的击球距离计算的预期目标值重复了相同的精确过程。
结果非常有趣。它们将在第 3 部分中讨论。敬请关注。
基于预期目标的场馆调整 RAPM 建设:起源、过程和结果(下)
结果:记分员偏差有多大?
在为本文的第一部分和第二部分写了超过 7000 个单词之后,我很兴奋终于可以分享结果了。如果你一直在阅读,我相信你也是,我想感谢你花时间阅读我的作品。我希望你喜欢它。
如果你没有跟着读,没关系。我强烈建议你在阅读本文之前先阅读第一和第二部分;它们并不短,但它们会让你很好地理解为什么这对我很重要,为什么你也应该关心它。但是如果你对阅读不感兴趣,你只想看到结果,我不会责怪你,也不会阻止你阅读。但是,我将为您快速回顾一下我在第一部分和第二部分中介绍的内容:
- 明尼苏达州的记分员错误地报告说,射门距离球网比实际距离远,这导致他们的滑冰运动员的防守性能被高估,他们的守门员被高效的模型低估,如发展曲棍球的目标高于替换。明尼苏达州的记分员也不是唯一表现出这种行为模式的人,我称之为“记分员偏见”
- 我的目的不是“修复”这个问题,而是提供一个对它所导致的不准确性的估计。为此,我构建了一个预期目标模型,对击球距离进行了场地调整,从而提高了我的预期目标模型的性能,并构建了一个 RAPM 模型,它提供了一个溜冰者孤立影响的点估计。
对于结果,我将从团队层面开始分析,然后转移到守门员,最后是个人选手。
在团队层面,我会从防守开始。以下是每支球队在过去两个赛季的防守表现,以每小时预期进球数(xGA/60)衡量,地点调整前后:
图片由托普顿曲棍球
既然明尼苏达从本文开始就一直走在前列,那我们就重点关注他们吧。正如你所看到的,他们的防守在这次调整中受到了最大的惩罚。在调整之前,他们的 2.52 的 xGA/60 是联盟中最好的,第二名哥伦布以 2.66 的 xGA/60 舒适地坐在他们的后面。调整后,明尼苏达以 2.75 的成绩跌至 xGA/60 的第 6 位。他们的防守仍然很好,但是他们不再是最好的防守球队了。
在光谱的另一端,芝加哥的进步程度与明尼苏达的衰退程度差不多。他们是调整前防守最差的球队,调整后防守第四差的球队。阿纳海姆和纽约流浪者队也看到了重大的改善,而蒙特利尔和费城看到他们的防守人数下降到类似的程度。其他六个团队的 xGA/60 比率变化至少为 0.1,其中三个团队有所改善,三个团队有所下降。
我发现这里非常有趣的是这个图案的对称性。光谱两端各有一个团队,他们看到的极端变化彼此相同,两端各有两个团队,他们稍微不太极端的变化实际上相同,光谱两端各有三个团队,他们非极端但仍然显著的变化实际上相同。让我们看看同样的模式是否在进攻中持续,这是通过每小时的预期目标(xGF/60)和同一两年样本的数据来衡量的:
图片由 TopDownHockey
团队进攻没有团队防守那么对称,但模式是相似的:明尼苏达和蒙特利尔等球队的记分员报告说,投篮距离球网比实际距离远,他们的进攻有所加强,而芝加哥和阿纳海姆等球队的进攻有所下降。
让我感到惊讶的一件事是,明尼苏达的进攻比他们的防守下降了更大的程度。这意味着他们的预期目标差异有了显著的改善。他们是一个异数,还是这发生在许多不同的团队?让我们通过查看加减值来找出答案,这是通过在同一两年样本中每小时的预期目标差异(xG+/-/60)来衡量的:
图片由托普顿曲棍球
事实证明,明尼苏达是唯一一支预期净胜球率显著上升的球队。蒙特利尔的变化足以令人惊讶,但其他人都在误差范围内。明尼苏达为什么进步了?我不完全确定,但我有一个理论:明尼苏达在主场是一支很好的控球球队,有 51.93%的芬威克投篮命中率。他们拍摄的和允许的拍摄值通过调整增加了,但是因为有更多的主场拍摄,这给了他们一个整体的提升。这一理论也适用于蒙特利尔和波士顿,这两支球队的预期净胜球率分别排名第二和第三。
他们主场芬威克的命中率分别是 54.74%和 53.71%,经过我的调整,他们在主场的支持和反对投篮变得稍微更有价值。这只是一个理论,我需要做更多的研究来确定为什么会这样。这也没什么大不了的,因为没有一支球队会看到他们的预期目标差异率变化太大。
为了更好地了解这些调整是如何影响我做了重大调整的球队在联盟范围内的排名,请查看以下可视化内容:
图片由 TopDownHockey
图片由托普顿曲棍球
正如你所看到的,一个好的团队通常仍然是一个好的团队,一个坏的团队通常仍然是一个坏的团队。但是,对于记分员有严重偏见的球队来说,他们擅长不同事情的程度会有很大的不同。
现在是时候转向守门员了。对于可视化,我选择使用超出预期的扑救目标(GSAx)来代替德尔塔芬威克扑救百分比(dfSV%)或另一个每射门/每分钟指标,因为我想提供一个守门员的综合指标受到了多大影响的想法。如果我使用一个每次射门的指标,一个无关紧要的守门员在 Xcel 能源中心或麦迪逊广场花园玩了一个小样本大小的游戏,大部分时间都在玩,可能会看到一个疯狂膨胀的“调整影响”。
在我的第一次可视化中,我任意设定了最少 75 场游戏。我这样做是因为我知道我需要为设定某种最小值,因为包括每个守门员将产生大约 100 个数据点——太多了,无法显示——我计算出每个球队自 2019-2020 赛季以来至少打了 150 场比赛,所以守门员需要至少打了他球队一半的比赛才能达到最低阈值。以下是达到我的最低门槛的守门员,按照场地调整对他们的 GSAx 的影响进行排名:
图片由 TopDownHockey
Dubnyk、Price 和 Gibson 都受到此次调整的巨大影响。杜布尼克从联盟中最差的守门员变成了……一个比少数人更好的非常差的守门员。凯里·普莱斯从一个低于平均水平的守门员变成了十佳守门员。约翰·吉布森从最好的国家之一发展到略高于平均水平。克劳福德、伦奎斯特、雷纳和毕晓普也受到重创。莱纳尤其有趣,因为尽管他在过去两个赛季为三支不同的球队效力,但他上场时间最多的两支球队的主场记分员历史上报告说,射门距离球网比实际距离更近,所以他因场地调整而受到重罚是有道理的。
创建了最后一个可视化后,我仔细检查了一下,发现卡特·哈特不见了。我可以发誓他是费城过去两年的首发,但结果却是他打了整整 74 场比赛。尽管他的样本很小,但他是受我的调整影响最大的球员之一,所以我讨厌我的想象没有包括他。Alex Stalock 也出现在本文第一部分的特色图片中,他也受到了我的调整的严重影响。我没有办法忘记这些人的存在,所以我为守门员创造了两个可视化效果来展示那些没有达到我最低出场次数的守门员:一个是受到场地调整最积极影响的十个守门员,一个是受到最消极影响的十个守门员。他们在这里:
图片由 TopDownHockey
图片由托普顿曲棍球
这里的要点很简单:像乔尔杰夫和谢斯特金比赛的麦迪逊广场花园这样的场地导致他们的守门员被没有考虑场地的指标高估,而像卡特哈特和布莱恩埃利奥特比赛的富国银行中心这样的场地导致他们的守门员被没有考虑场地的指标低估。
既然每个人都喜欢最好和最差球员的排名,我觉得我应该按照调整后的 GSAx 列出前 15 名和后 15 名的守门员,没有最低的比赛门槛。以下是前 15 名:
图片由 TopDownHockey
这是倒数 15 名:
图片由 TopDownHockey
正如你所看到的,这一调整对像 Devan Dubnyk 和 Alex Stalock 这样的守门员产生了非常重大的影响,他们在 Xcel Energy Center 打主场比赛,记分员报告说射门距离球网比实际距离远。这也对像 Ben Bishop 和 Anton Khudobin 这样的守门员产生了重大影响,他们在美国航空中心打主场比赛,记分员报告说,射门距离球网比实际距离近。但这种调整并没有显著到颠倒世界,告诉我们明尼苏达的守门员是好的,达拉斯的守门员是坏的。Bishop 和 Khudobin 仍然在 GSAx 排名前 15 位,而 Dubnyk 仍然在排名后 15 位,Stalock 只是勉强错过了晋级。
为了更好地了解这些调整如何影响守门员相对于他们的同行,请查看以下可视化:
图片由 TopDownHockey
图片由托普顿曲棍球
最后,在我进入滑冰者之前:我特此授予德万·杜布尼克“圣何塞鲨鱼队最差守门员”的称号。
请记住,我使用加权岭回归来计算一个称为正则化调整正负(RAPM)的指标,这是一个玩家的孤立影响的点估计。我这样做是因为进化曲棍球的目标高于替换使用一个球员的孤立(通过 RAPM)对预期目标的影响作为滑冰运动员防守的主要组成部分之一,因为大多数其他组成部分与 RAPM 密切相关。
在这里,我要做的第一件事是将我的 RAPM 在场地调整前的结果与所有玩了至少 200 分钟的冰上曲棍球 RAPM 模型的结果进行比较:
图片由 TopDownHockey
如您所见,两个模型的结果非常相似。这是我一直以来的目标:建立一个类似他们的模型,但是是我自己的,这样我就可以在场地调整前后比较我自己的模型。如果我只是建立了一个有场地调整的模型,并与他们的进行比较,我不会知道哪些差异是由场地调整引起的,哪些差异是由模型差异引起的。
正如我对团队所做的那样,我将从他们的防守开始我对运动员的分析。在我公布这些数字之前,我应该指出,这些数据大致遵循正态分布,原始 RAPM xGA/60 的标准偏差为 0.117,而调整后的 RAPM xGA/60 的标准偏差为 0.115。现在我已经澄清了这一点,以下是防守受到这一调整最消极和最积极影响的运动员:
图片由 TopDownHockey
图片由托普顿曲棍球
(记住,负数是好的,减少玩家 RAPM xGA/60 的调整意味着调整奉承他们。)
这与我们的预期大致相符:来自明尼苏达、费城和蒙特利尔的选手在调整后防守看起来稍差,而来自阿纳海姆、芝加哥和纽约流浪者的选手看起来稍好。但是他们受影响有多大?记住,这里的标准差大致是 0.116,所以没有球员的防守影响改变了哪怕一个标准差,只有大约十几个人看到他们的防守影响在任一方向上改变了半个标准差。虽然像阿纳海姆和明尼苏达这样的球队在进行场地调整后看起来有很大的不同,但他们的个人选手都没有看到巨大的变化。
进攻呢?进攻的标准偏差略大于防守:原始 RAPM xGF/60 的标准偏差为 0.122,调整后的 RAPM xGF/60 的标准偏差为 0.121。以下是进攻冲击最大的球员:
图片由 TopDownHockey
图片由 TopDownHockey
还记得在我实施场地调整后,明尼苏达看到他们的进攻比他们看到的防守下降有了更大程度的提高吗?嗯,这只能说明他们的选手看到了迄今为止所有队伍中进攻方面最大的进步。这也是有道理的,唯一一个看到他们的进攻或防守孤立影响改变至少一个标准差的球员是明尼苏达野生动物队的贾里德·司布真,这种改变是他进攻影响的增加。
加号/减号呢?既然记分员的偏见是双向的,那么大多数球员在场地调整前后不应该有相似的净影响吗?我们将深入探讨这一点,但在此之前,我们需要确定标准差,以便了解任何调整的幅度。原始预期目标差异率的标准偏差为 0.170,调整后预期目标差异率的标准偏差为 0.169。这比进攻或防守的规模要大得多,我们应该记住这一点。
现在我们已经确定了这一点,让我们来看看那些净影响受场地调整影响最大的玩家:
图片由 TopDownHockey
图片由 TopDownHockey
如你所见,大多数进攻调整基本上被防守调整抵消了;Jared Spurgeon 的调整是唯一一个甚至在净影响标准偏差的三分之一以内的调整。因此,公平地说,记分员偏见在球员对预期净胜球的净影响中没有发挥很大作用,如果我们只看这个指标,记分员偏见就不是问题。
以下是另一个形象化的例子,让您了解在场地调整前后,玩家相对于其他玩家的影响力会发生怎样的变化:
图片由托普顿曲棍球
上面的可视化是为了强调场地调整可以对球员的进攻影响做出重大改变,但他们的防守影响通常会在相反的方向上看到类似幅度的变化,因此他们的净影响将非常相似。在 Jonas Brodin 的例子中,你是使用原始的还是调整后的指标并不重要:他的净影响非常好。
当我们关注净影响之外的东西时,问题就出现了。正如我上面提到的,某些指标,如发展曲棍球的目标高于替代使用预期目标的防守,但实际目标的进攻。如果我们看看上面乔纳斯·布洛丁图表中间的两列,很明显,在我们调整了记分员的偏见后,他的防守明显变弱了。同样,这对于预期的净胜球差来说不是一个大问题,因为他的进攻被记分员的偏见所拖累,其程度与他的防守被支撑的程度大致相同,但如果我们使用一个不容易出现记分员偏见的不同指标(如进球),我们将高估他的防守影响,而不惩罚他的进攻。
当我们分析一个运动员时,这也不是什么大问题。如上所述,只有一名选手看到他们的进攻或防守影响改变了一个标准差,只有少数其他选手接近。但是,当我们分析一个全队的运动员时,平均每个运动员的防守都比实际情况好大约半个标准差,所有这些不准确性加起来会导致我们得出一些相当不准确的结论。请记住,无论记分员的偏见导致我们高估一支球队的防守,它导致我们随后低估他们的守门员(反之亦然)。
现在我们已经建立了所有这些,我们从这里去哪里?这不是我能决定的。就我个人而言,我仍然计划使用不断发展的曲棍球目标高于替代和 RAPM 模型来评估 NHL 滑冰运动员和守门员,以及其他没有纳入场地调整的模型,因为尽管记分员有偏见,它们仍然非常有效。我还计划交叉引用我自己的模型的结果,以确定记分员偏差是否影响其他模型的输出,以及影响的程度。但重要的是,现在我已经研究了这个问题,并做了一些工作来确定它可能会导致我对某些球员的评估有多不准确,我处于一个更好的位置来细微地处理这些数字,并且比以前更少错误地看待曲棍球。希望你看了我的研究也有同感。
如果你想与我进一步讨论这些细节,或者你只是想看到一些你最喜欢的球队或球员的可视化效果,请随时在 Twitter 上联系我,地址是 TopDownHockey 。
使用 Streamlit 为 NLP 项目构建 Web 应用程序
实践教程
在解决 NLP 任务(如情感分析、NER 和文本摘要)时,Streamlit 基础知识的代码演示和解释。
图片来自 Unsplash
数据科学家面临的最常见的任务之一是以一种用户交互的格式呈现他们的模型/项目。如果模型不能在某种类型的应用程序中呈现,那么它对任何外部用户都没有多大用处。这介绍了 web/app 开发的广阔领域,然后引出了更多的语言和工具,如 HTML、CSS、ReactJS、Dash、Flask 等,它们可以帮助您创建一个前端界面,供用户与您的模型进行交互并从中获得结果。这个广阔的领域起初可能会令人生畏,并且与传统的数据科学技能集格格不入。
Streamlit 是一个简单的 Python API,它提供了一种方式来缩短这个学习曲线,并消除数据科学家了解这些工具的需要。一般的全栈库应该是大规模项目的首选,但是如果您的数据科学项目需要一个快速前端,Streamlit 不仅仅是为了这个目的。在本文中,我想演示 Streamlit 的基础知识,同时构建一个 web 应用程序,允许用户使用模型解决常见的 NLP 任务,如情感分析、命名实体识别和文本摘要。
注意:虽然我们可以为这些任务中的每一项构建定制模型,但我还是使用了 Python 库中预先训练好的模型,因为本文更侧重于构建一个 web 应用程序来通过 Streamlit 显示您的 ML/NLP 项目。
目录
- Web 应用程序设置
- 数据
- 情感分析
- 命名实体识别(NER)
- 文本摘要
- 整个代码和结论
1.Web 应用程序设置
在构建任何模型之前,我们需要一个应用程序外观的模板。让我们先导入 streamlit(为了安装使用 pip3 为 Python3 安装 streamlit)。
导入 streamlit
为了解释我们的应用程序是什么,让我们添加一个标题和一个小标题,询问用户希望从我们的三个选项中选择哪一个 NLP 服务。 Streamlit.title() 、 Streamlit.header() 和 Streamlit.subheader() 是按降序排列的不同标题级别。对于纯非标题文本数据,您可以使用 Streamlit.text() 。
用于创建应用程序标题的代码
Streamlit 的航向代码结果
现在我们有了应用程序的主要问题,我们可以构建一个下拉菜单,让用户从我们的模型可以完成的三个任务中进行选择。这可以使用 Streamlit.selectbox() 调用来完成。
用于创建带有选项的下拉菜单的代码
NLP 服务使用的下拉菜单
从三个选项中选择的服务作为字符串存储在选项变量中。需要输入的下一条信息是用户想要输入的文本文本,以便我们的模型处理/执行所选择的任务。为此我们可以使用 Streamlit.text_input() 调用,它类似于 HTML 中的 textarea 标签。
用于输入文本进行分析的代码
供用户输入模型的文本区域
然后,文本输入被存储在文本变量中。现在我们有了包含所有需要处理的信息的选项和文本变量,我们需要创建一个区域来显示结果。
现在我们的模板设置,我们有一些东西看起来像下面的。
用 Streamlit 制作的整体模板
只用了大约 10 行 Python 代码,就创建了一个非常简单而有效的模板。现在我们有了前端,我们可以处理/向我们的模型提供这些信息,并将结果返回给用户。
2.数据
对于 NLP 任务,我们将使用以下一篇名为“ 微软推出智能云中心以提升人工智能&云技术的学生的文本数据。文章/正文是通过中的文章找到链接的。我们将使用下面的文本块作为所有三个 NLP 任务的输入文本。
In an attempt to build an AI-ready workforce, Microsoft announced Intelligent Cloud Hub which has been launched to empower the next generation of students with AI-ready skills. Envisioned as a three-year collaborative program, Intelligent Cloud Hub will support around 100 institutions with AI infrastructure, course content and curriculum, developer support, development tools and give students access to cloud and AI services. As part of the program, the Redmond giant which wants to expand its reach and is planning to build a strong developer ecosystem in India with the program will set up the core AI infrastructure and IoT Hub for the selected campuses. The company will provide AI development tools and Azure AI services such as Microsoft Cognitive Services, Bot Services and Azure Machine Learning.According to Manish Prakash, Country General Manager-PS, Health and Education, Microsoft India, said, "With AI being the defining technology of our time, it is transforming lives and industry and the jobs of tomorrow will require a different skillset. This will require more collaborations and training and working with AI. That’s why it has become more critical than ever for educational institutions to integrate new cloud and AI technologies. The program is an attempt to ramp up the institutional set-up and build capabilities among the educators to educate the workforce of tomorrow." The program aims to build up the cognitive skills and in-depth understanding of developing intelligent cloud connected solutions for applications across industry. Earlier in April this year, the company announced Microsoft Professional Program In AI as a learning track open to the public. The program was developed to provide job ready skills to programmers who wanted to hone their skills in AI and data science with a series of online courses which featured hands-on labs and expert instructors as well. This program also included developer-focused AI school that provided a bunch of assets to help build AI skills.
3.情感分析
对于情感分析,我们将使用 textblob 库来生成输入文本的极性和主观性。(使用 pip3 为 Python3 安装 textblob)
为了标记数据,我们使用 NLTK 库将文本分割成句子,这样我们就可以将较大的文本分割成较小的部分进行可视化分析。使用 textblob 库,我们得到了每句话的情感来创建贯穿文本的情感的可视情节。注:对于图书馆,情绪用-1 到 1 表示,1 表示最积极,-1 表示最消极。
策划每句话的情绪
使用 Streamlit.line_chart() 中的另一个简洁的 Streamlit 特性,我们可以用线图绘制每个句子的情感,以便用户直观地分析第二部分中显示的文本数据。
文本中每句话的情感得分图
如果我们想要对文本有一个总体的看法,我们可以对整个数据字符串使用 TextBlob API 调用。
整篇文章的整体情绪
使用 st.write() 调用,我们可以显示从 textblob 返回的情感。返回的两个特征是极性和主观性**。极性在[-1,1]之间,主观性在[0,1]之间,0.0 为客观,1.0 为主观。**
输入文本的总体情感
4.命名实体识别(NER)
对于 NER,我们将在空间中使用另一个流行的 NLP 库。
Spacy 有一个很好的特性,它提供了类型的实体以及它所识别的实体。这方面的例子包括:人、组织、日期、金钱等等。为了提取实体及其标签,我们可以遍历找到的实体的整个列表,并将它们加入到一个字典中。
使用空间提取实体和实体类型
为了让我们的用户获得每种类型实体的直观表示,我们可以创建一个助手函数,列出每种类型的所有实体。
提取每种类型的实体的辅助函数
使用这个函数,我们可以提取每种类型的实体,并将结果写出来让用户清楚地看到。
将函数应用于编写每种类型的实体
文本数据中每种类型的实体
5.文本摘要
对于文本摘要,我们将使用 gensim 库,它有一个简单的摘要调用**。**
Gensim 进口
使用 summary 调用,我们可以轻松地生成输入文本的摘要。注意:总结电话需要不止一句话来配合 gensim。
使用 gensim 的文本摘要
输入的摘要文本
6.整个代码和结论
完整代码
** [## RamVegiraju/NLPStreamlit
一个 Streamlit 应用程序,可以执行 NLP 任务,如情感分析、命名实体识别(NER)和文本…
github.com](https://github.com/RamVegiraju/NLPStreamlit)
Streamlit 允许您无缝集成流行的数据科学/ML 库,以在简单而简洁的 web 应用程序/仪表板上显示您的项目。虽然更常见的全栈技能组合将更好地服务于大规模项目,但使用 Streamlit 所需的短时间和简单性大大有助于数据科学家和 ML 工程师展示他们的项目。
我希望这篇文章对那些试图在 ML/NLP 项目中使用 Streamlit 的人有用。如果你对谈论 ML &数据科学感兴趣,请随时在评论中留下任何反馈或通过 Linkedln 与我联系。感谢您的阅读!**
打造您在数据科学领域的品牌
苹果 | 谷歌 | SPOTIFY | 其他
肯·吉在 TDS 播客
背景图片由 Markus Spiske 提供
编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris 主持。Jeremie 帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:
众所周知,数据科学是一个品牌非常重要的领域。
事实上,如果说我从帮助求职者在sharpes minds获得工作的 A/B 测试方法中学到了什么,那就是写博客、在社交媒体上保持良好形象、做开源贡献、播客和在聚会上演讲是获得雇主注意的最佳方式之一。
品牌很重要。如果有一个人对数据科学中的品牌价值以及如何建立品牌有深刻的理解,那就是数据科学家兼 YouTuber Ken Jee。Ken 不仅拥有数据科学家和体育分析师的经验,曾在 DraftKings 和 GE 工作过,而且他还创办了许多公司——他的 YouTube 频道拥有超过 60 000 名订户,是他今天的主要项目之一。
在今天的节目中,我和 Ken 讨论了数据科学中的品牌建设策略,以及为那些希望获得第一份数据相关职位的人提供的求职技巧。以下是我最喜欢的一些外卖食品:
- 许多公司积极寻找不仅将数据科学作为一种工具,而且作为看待世界的一种方式的候选人。这是因为一名优秀的数据科学家需要能够解决数据科学问题,还需要能够发现这些问题,这意味着要学会通过数据的镜头来思考和看待世界。
- 例如,我们讨论了将求职视为数据科学项目的想法:用 NLP 对职位描述进行聚类,以确定可能值得申请的角色,并且重要的是,测量您的申请转化率。最后一个技巧是关键:转化率是你知道你需要投入多少工作才能达到每周面试的目标数量的唯一方法。
- 认识到求职中你能控制的方面和你不能控制的方面是很重要的——因为不这样做可能会导致你因为不可避免的失败而责怪自己。例如,面试官的低血糖可能会导致他们过于严厉,招聘经理在你现场的早上起床就心情不好,可能无法与你以及他前一天面试的人沟通。
- 研究你申请的公司。你应该带着对公司业务的清晰想法去参加面试,以及对他们最大的问题可能是什么的一些有根据的猜测。如果您准备好了一些关于工业或经济趋势如何影响他们的业务的问题,将会得到加分!(提示:COVID 是许多公司的一个重要因素)
你也可以点击这里在 Twitter 上关注肯,点击这里查看的 YouTube 频道,了解他的工作。另外,点击这里查看肯最新的 66 天数据计划!
你可以在推特上关注我这里。
使用 Python 构建您自己的新冠肺炎流行病简单模型
理解基本的动力学和概念,同时编写一个简单的计算流行病模型
如果你生活在这个世界上,很有可能你还没有听说过这种新型冠状病毒新冠肺炎和它在全世界引起的疫情。事实上,这是一个很好的机会,当你在家中自我隔离,远离公众,像许多人一样,有很多额外的时间来处理。所以,如果你熟悉编程,为什么不试试这个:在家里建立自己的流行病模型。这有助于提高你的编程能力,并帮助你理解流行病的概念和基本动态。
但首先请注意,这只是一篇展示如何使用 Python 为新冠肺炎疫情准备一个基本模型的文章。另一方面,这意味着:它不是一个你可以用来预测未来的模型。这是而不是你的 DIY 模型,它让你能够简单地忽略官方机构推荐你做的事情。它也不是在社交媒体上向其他人证明我们注定要失败的可视化工具!如果你同意这些免责声明,现在让我们开始编码。
我们在此假设的主要概念是,模拟一个样本社会中有限数量的个体每天相互作用,以及每次相互作用带来的污染机会。为了简单起见,我随机生成了这个组,邻近度代表每个人与其最近的 邻居 的互动量。注意,一个人的邻居可能是他/她的家人、同事、同学或他/她每天接触的任何人。我假设这种相互作用对于样本中的大多数人来说是相同的,但是为了使事情更有趣,让我们假设一部分群体,我取了 10%,我们称之为 运输者 ,在模型中每天随机移动;这意味着他们的邻居每天都在变化。我添加了这些组来代表那些店主、出租车司机、警察等等。他们每天都和新的人打交道。我用圆圈标记了运输者和他们的号码来跟踪他们。
最后,为了完成我们的零日初始化,我们更需要的是零号患者!我把它涂成红色。
初始化后,模拟每天都是这样进行的:
- 运输者随机移动。
- 人们与他们的邻居互动。
- 在互动过程中,感染会随机传播,并有预先确定的机会从一个病人传染给一个健康人。
- 一定比例的患者,新冠肺炎(+),随机住院,假设他们的症状变得最糟糕。
- 随机选择的住院病人中有一部分死亡。
- 那些已经忍受了疾病期,比如说 14 天,症状轻微的患者将被治愈,并对疾病产生免疫力。
- 还有明天。。。我们再次重复以上所有内容。这种情况一直持续到不可能再有新的感染为止。
对所有编程语言来说,编写上面提到的算法是一件容易的事情,但是对于可视化来说,Python 使用matplotlib
提供了很多。
让我们看看,如果我们用 1000 个人的随机数据集运行这个模拟,并且在每次交互中感染机会为 25%,会发生什么:
让我们看看模拟过程中的统计数据是什么样的:
由于模拟需要一些时间,我让 python 在日志中报告我的社会在模拟期间到底发生了什么:
-------------------------------
Day: 0
- - - - - - - - - - - - - - - -
Healthy 999
Covid-19(+) 1
Hospitalized 0
Cured 0
Dead 0
Name: 0, dtype: int64
-------------------------------
Day: 1
- - - - - - - - - - - - - - - -
Healthy 987.0
Covid-19(+) 13.0
Hospitalized 0.0
Cured 0.0
Dead 0.0
Name: 1, dtype: float64
-------------------------------
Day: 2
- - - - - - - - - - - - - - - -
Healthy 977.0
Covid-19(+) 23.0
Hospitalized 0.0
Cured 0.0
Dead 0.0
Name: 2, dtype: float64
-------------------------------
.
. .
. . .
. . . .
-------------------------------
Day: 53
- - - - - - - - - - - - - - - -
Healthy 1.0
Covid-19(+) 0.0
Hospitalized 0.0
Cured 951.0
Dead 48.0
Name: 53, dtype: float64
我让 python 自动完成所有的工作,制作所有的图表、列表和视频,并以我选择的格式保存。但是请注意,如果您为数量选择了较大的数字,并且以错误的方式更改了一些假设,则可能需要一些模拟运行时间。
例如,模拟 10,000 个人花费了我大约 24 小时,直到第 34 天,您可能会看到下面的模拟结果:
既然你已经开发了自己的样本模型,你可能会发现搜索由专业流行病学家开发的更科学的模型很有趣,或者你可能会在这里看到一个来自华盛顿邮报的。
下面,你可以找到我的 python 代码,在上面的模型中,你可以很容易地改变参数,看看在不同的假设下会发生什么。
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 29 21:57:53 2020[@author](http://twitter.com/author): Sadegh Maghsoudi
"""
# Functions --------------------------------------------------
def point(xlimit,ylimit):
import random
x = random.uniform(0,xlimit)
y = random.uniform(0,ylimit)
return x,ydef Generate(GrupSize,xlimit,ylimit):
import pandas as pd
import math
df = pd.DataFrame(columns='X,Y,Covid-19,Day'.split(','))
for i in range(GrupSize):
df.loc[i,'X'], df.loc[i,'Y'] = point(xlimit,ylimit)
df.loc[i,'Covid-19'] = False
samplesize = math.floor(GrupSize/100)
MoversList = df.sample(n = samplesize).index.values.tolist()
StatofDay = pd.DataFrame(columns='Healthy,Covid-19(+),Hospitalized,Cured,Dead'.split(','))
return df , StatofDay, MoversList
def plt1color(df):
cols=[]
for l in df.index:
if df.loc[l,'Covid-19']==True: #Infected
cols.append('red')
elif df.loc[l,'Covid-19']==666: #Dead
cols.append('black')
elif df.loc[l,'Covid-19']==115: #Hospitalized
cols.append('yellow')
elif df.loc[l,'Covid-19']==7: #Cured
cols.append('green')
else:
cols.append('blue') #Healthy
return colsdef plt2color(Stat):
cols=[]
for i in Stat.columns:
if i=='Covid-19(+)': #Infected
cols.append('red')
elif i=='Dead': #Dead
cols.append('black')
elif i=='Hospitalized': #Hospitalized
cols.append('yellow')
elif i=='Cured': #Cured
cols.append('green')
else:
cols.append('blue') #Healthy
return colsdef Plot():
import matplotlib.pyplot as plt
global df, fig, Stat, Day, Moverslist
cols=plt1color(df)
ld = ['Healthy','Covid-19(+)','Hospitalized','Cured','Death Toll']
axs[0].cla()
axs[0].scatter(df['X'],df['Y'],s=1,c=cols)
for i in MoversList:
axs[0].scatter(df.loc[i,'X'],df.loc[i,'Y'],s=6,facecolors='none', edgecolors='black')
axs[0].text(df.loc[i,'X']+0.02, df.loc[i,'Y']+0.02, str(i), fontsize=5)
cols=plt2color(Stat)
sDay = str(Day)
title = 'Day' + sDay
axs[0].set_title(title,loc='left')
axs[0].set_yticklabels([])
axs[0].set_xticklabels([])
axs[0].tick_params(
# axis='both', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
right=False, # ticks along the right edge are off
left=False, # ticks along the left edge are off
labelbottom=False) # labels along the bottom edge are off
axs[1].cla()
axs[1].plot(Stat.Healthy,label=ld[0],color=cols[0])
axs[1].plot(Stat['Covid-19(+)'],label=ld[1],color=cols[1])
axs[1].plot(Stat.Hospitalized,label=ld[2],color=cols[2])
axs[1].plot(Stat.Cured,label=ld[3],color=cols[3])
axs[1].plot(Stat.Dead,label=ld[4],color=cols[4])
# axs[1].set_prop_cycle(color=cols)
axs[1].legend(bbox_to_anchor=(0, 1), loc='upper left', borderaxespad=0.)
plt.xlabel('Days')
plt.show()
if Day<10 : sDay = '0' + sDay
title = 'Day' + sDay + '.png'
plt.savefig(title)returndef Png_to_gif():
from PIL import Image
import glob
# Create frames
frames = []
imgs = glob.glob("*.png")
for i in imgs:
new_frame = Image.open(i)
frames.append(new_frame)
# Save into GIF
frames[0].save('png_to_gif.gif', format='GIF',
append_images=frames[1:],
save_all=True,
duration=500, loop=0)def infect(Person):
import random
global df,Day
if random.random()>0.25 and Day>3 : return
if df.loc[Person,'Covid-19']==False:
df.loc[Person,'Covid-19'], df.loc[Person,'Day'] = True, Day
def Move(xlimit,ylimit):
"""
Move Movers Randomly
"""
import random
global df, MoversList
for i in MoversList:
if (df.loc[i,'Covid-19']==115) or (df.loc[i,'Covid-19']==666) : MoversList.remove(i)
df.loc[i,'X'], df.loc[i,'Y'] = (df.loc[i,'X']+random.uniform(1,xlimit/3))%xlimit, (df.loc[i,'Y']+random.uniform(1,ylimit/3))%ylimitdef check(i,j):
import math
global df, YesterdayPatients, Distlimit
Dist = math.sqrt((df.loc[i,'X']-df.loc[j,'X'])**2+(df.loc[i,'Y']-df.loc[j,'Y'])**2)
flag = ((YesterdayPatients[i]==True) ^ (YesterdayPatients[j]==True)) and Dist<Distlimit
return flag
def interact():
global Day, df
for i in range(len(df)):
for j in range(i):
if check(i,j):
if (df.loc[i,'Covid-19']==False) :
infect(i)
else:
infect(j)def kill():
import math
global df
samplesize = math.floor(len(df[df['Covid-19']==True])*.005+len(df[df['Covid-19']==115])*.005)
if samplesize>len(df[df['Covid-19']==True]): return
df.loc[df[df['Covid-19']==True].sample(n = samplesize).index.values.tolist(),'Covid-19']=666
returndef hospitilize():
import math
global df
samplesize = math.floor(len(df[df['Covid-19']==True])*0.03)
if samplesize>len(df[df['Covid-19']==True]): return
df.loc[df[df['Covid-19']==True].sample(n = samplesize).index.values.tolist(),'Covid-19']=115
returndef cure():
global df, Day
df.loc[(df['Day']<Day-10) & (df['Covid-19']==True) ,'Covid-19'] = 7
df.loc[(df['Day']<Day-21) & (df['Covid-19']==115) ,'Covid-19'] = 7
return
def Tomorrow(): # To Be checked and Resolved!!!
global df, Day
Day +=1
kill()
hospitilize()
cure()
Move(xlimit,ylimit)
interact()def Count(Day):
global df, Stat
List = list(df['Covid-19'])
Stat.loc[Day,'Healthy'] = List.count(False)
Stat.loc[Day,'Covid-19(+)'] = List.count(True)
Stat.loc[Day,'Hospitalized'] = List.count(115)
Stat.loc[Day,'Cured'] = List.count(7)
Stat.loc[Day,'Dead'] = List.count(666)
return
def write_log(*args):
global log_file
line = ' '.join([str(a) for a in args])
log_file.write(line+'\n')
print(line)
# Main -------------------------------------------------------------------
import matplotlib.pyplot as plt
import random
log_file = open("Log.txt","w+")# -------------------------------------------
# I N P U T V A R I A B L E S H E R E |
# -------------------------------------------
# |
n = 1000 # |
xlimit,ylimit=30,30 # |
Distlimit = 1.5 # |
# |
# -------------------------------------------write_log(31*'-')
write_log("Here's the Input Data:")
write_log(8*'- - ')
write_log('Numper of Sample:',n)
write_log('X & Y limites: ',xlimit,', ',ylimit)
write_log('Distance required for Contamination:', Distlimit)# Day = 0, Generating Model...
Day = 0df, Stat, MoversList = Generate(n,xlimit,ylimit)
infect(random.randrange(n))
fig, axs = plt.subplots(2)
fig.suptitle('Covid-19 Epidemic Sample Model', fontsize=16)
Plot()
Count(Day)
write_log(31*'-')
write_log('Day:',Day)
write_log(8*'- - ')
write_log(Stat.loc[Day])# Day=1
YesterdayPatients = list(df['Covid-19'])
Tomorrow()
Plot()
Count(Day)
write_log(31*'-')
write_log('Day:',Day)
write_log(8*'- - ')
write_log(Stat.loc[Day])
#Main Loop . . .countsames = 0
while Stat.loc[Day, 'Healthy']>0 and Day<100:
log_file = open("Log.txt","a+")
if (list(Stat.loc[Day])==list(Stat.loc[Day-1])):
countsames +=1
if countsames>2 : break
else :
countsames = 0
YesterdayPatients = list(df['Covid-19'])
Tomorrow()
Plot()
Count(Day)
write_log(31*'-')
write_log('Day:',Day)
write_log(8*'- - ')
write_log(Stat.loc[Day])
log_file.close()Png_to_gif()
Stat.to_excel('Stat.xlsx')
Stat.plot(title='Statistical Data Vs. Days Passed')
plt.savefig('Stat')
编者注: 迈向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
构建自己的物体探测器——py torch vs tensor flow 以及如何开始?
-详细的“操作”方法-
由 Unsplash 上 Greg Rakozy 拍摄的照片
在经历了实现用于物体检测的人工智能系统的一些困难和头痛之后,我想分享一些我所获得的关于如何开始的知识。第一步总是最难的,这就是为什么这种非常实用的方法旨在让人们轻松进入 TensorFlow 和 PyTorch 的对象检测框架的世界。
由于我已经是一名经验丰富的数据科学家,并且在过去几年中开发了一些高效的机器学习软件组件,我认为上网应该是一件相当容易的工作,找到一个预先训练的 CNN,并在一个看不见的数据集上进一步训练它,使它能够检测一些以前未知的物体。直到大约一年前,我大部分时间都在做基于树的模型,大量的 scikit-learn 以及 xgboost,当然还有大量的熊猫。和许多人工智能任务一样,我的第一个方法是经典的 a:“不要这么快!”有一些你必须知道的垫脚石,但是似乎没有多少文章和博客提到。在这个主题上花了很多时间并阅读了大量 TensorFlow 源代码后,我知道了如下问题的答案:
“为什么我从官方 GitHub repos 得到的示例代码不能工作?”
所以我想为什么不与他人分享我使用这些工具的经验,并描述我是如何着手解决我所面临的问题的。
简单地说,我的目标是开发自己的对象检测器——一种可以分类和检测图像中对象的神经网络,不仅仅是现成的对象检测算法,而是特别擅长从我自己的数据集中检测图像——这意味着我必须进行迁移学习。
首先,我上网更新了一些关于这些算法在数学上如何工作的知识(我真的可以推荐吴恩达在 coursera 上关于卷积神经网络的 deeplearning.ai 课程。它有整整一周的时间专门用于对象检测,让您了解关键概念并很好地描述每件事情背后的数学。因此,有了这个理论,我看了一些我可以用于我的任务的开源数据集,偶然发现了 experiencor 在 https://github.com/experiencor/raccoon_datasetGitHub上的以下浣熊数据集,然后我决定使用它。它已经将注释和图像整齐地存储在各自的文件夹中,并且只需要检测一个类(浣熊),因此这是一个很好的起点。
完成后,我看了看两个广为人知的深度学习框架,它们让你使用预训练的网络进行迁移学习(进一步训练这些网络以使它们适应你的特定数据集), TensorFlow 的对象检测 API 以及 PyTorch 的 torchvision 包。有一件事我可以马上说:我在 PyTorch 中只用了半天就完成了我的工作,而在 TensorFlow 中我却花了几天时间才完成了我想要的一切!事实上,tf object detection API 是基于 TensorFlow 1.x 构建的,而我们现在已经有了 2.x 版本,这给我带来了很多兼容性问题,如果不仔细查看源代码,几乎不可能完成任何工作,因为他们的报告中的一些示例是基于 2.x 的,而核心培训代码仍然基于 1.x。
我在 Google Colab 上编写代码,因为他们为你提供了整洁的笔记本体验,让你可以访问他们云上的免费 CPU 和 GPU,以及以 google drive 形式提供的免费存储,可以很容易地安装到你的 Colab 空间。
获取数据
获取数据相当容易,因为我只需导航到一个不同的文件夹(在我安装的 google drive 存储中)并运行
! git clone [https://github.com/experiencor/raccoon_dataset.git](https://github.com/experiencor/raccoon_dataset.git)
检查数据很容易,就像这样:
from PIL import Imageimage = Image.open("<your path>/raccoon_dataset/images/raccoon-1.jpg")
image
来自 https://github.com/experiencor/raccoon_dataset的 raccoon-1.jpg
当谈到这个图像的标签时,我们必须查看 annotations 文件夹。在对象检测的情况下,每个对象的一个类(在我们的例子中只是浣熊的一个类)和每个对象的 4 个代表边界框的坐标组成了标签。要快速浏览,只需将浣熊-1.xml 文件下载到您的笔记本电脑上,用编辑器打开它(我用的是 Atom)。然后,您会看到以下内容:
<annotation verified="yes">
<folder>images</folder>
<filename>raccoon-1.jpg</filename>
<path>/Users/datitran/Desktop/raccoon/images/raccoon-1.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>650</width>
<height>417</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>raccoon</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>81</xmin>
<ymin>88</ymin>
<xmax>522</xmax>
<ymax>408</ymax>
</bndbox>
</object>
</annotation>
它告诉你这个注释文件对应于 raccoon-1.jpg 文件,对象的类是“浣熊”,边界框的边由 xmin,xmax,ymin 和 ymax 表示。一个非常自然的反应是首先通过简单地在图像中画出方框来检查这是否正确。
很容易做到:
from PIL import ImageDrawxmin = 81
ymin = 88
xmax = 522
ymax = 408draw = ImageDraw.Draw(image)
draw.rectangle([(xmin, ymin), (xmax, ymax)], outline =”red”)
image
带有来自浣熊-1.xml 的绑定框的 raccoon-1.jpg
因此,我们不必仔细检查文件夹中的每个文件并收集每个图像上的正确标签,因为已经有一个包含所有这些信息的 csv 文件。快速浏览一下可以这样做:
import pandas as pdlabels = pd.read_csv("<your path>/raccoon_dataset/data/raccoon_labels.csv")labels.head()
这是 TensorFlow 和 PyTorch 库的起点,也是两者开始不同的地方。
A 部分:张量流
装置
从 TensorFlow 对象检测开始,基本上应该是这样工作的:你克隆他们的 repo 并根据他们的安装指南安装 API。在实践中,你必须用 Google Colab 做的事情在某些方面更容易,在某些方面更难:
- 安装 TensorFlow 和所有其他提到的库(在 Google Colab 中,选择一个 tf 版本的神奇命令就是你所需要的,其他的都是预装的)
%tensorflow_version 1.x
2.COCO API 安装—已经预装,可以通过
import pycocotools
3.克隆他们的回购协议
! git clone [https://github.com/tensorflow/models.git](https://github.com/tensorflow/models.git)
4.导航到模型/研究文件夹
import os
os.chdir("<your path>/models/research")
5.安装 protobufs
! protoc object_detection/protos/*.proto --python_out=.
6.现在,要测试您的安装,只需运行:
%%bashexport PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
python object_detection/builders/model_builder_test.py
7.超级重要:您在 Colab 中执行的每个 bash 命令都像是启动一个新的终端会话,因此非常重要的是,每次您使用 CLI 进行 tf 的对象检测时,您都必须包括
export “PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
在你的牢房顶上!
因为与 API 的每一次交互都是以命令行方式进行的(为了训练一个您称之为类似的模型):
%% bash
export “PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slimpython”python object_detection/model_main.py \
--pipeline_config_path=${PIPELINE_CONFIG_PATH} \
--model_dir=${MODEL_DIR} \
--num_train_steps=${NUM_TRAIN_STEPS} \
--sample_1_of_n_eval_examples=$SAMPLE_1_OF_N_EVAL_EXAMPLES \
--alsologtostderr
我想深入了解这个 CLI(另外,笔记本环境并不是真正为命令行执行而构建的),我在 Colab 上的安装中添加了一个关键的东西:
8.启用 python 内核来查找 model_main.py 文件中的所有导入(在上面的 CLI 中调用)。
import syssys.path.append("<your path>/models/research/object_detection")sys.path.append("<your path>/models/research/slim/")
9.确保您安装了 numpy==1.17,否则评估脚本将无法工作。
瞧,准备好开始了!
选择一个预先训练好的网络
安装了必要的软件并下载了训练数据后,我们终于可以考虑人工智能了。我们可以使用哪种卷积神经网络架构?它是在哪个数据集上训练的?在 TensorFlow 的对象检测 API 中,我们可以从他们的检测模型 zoo (顺便说一下,喜欢这个名称:)中的各种模型中进行选择,这些模型是在不同的行业和研究标准图像数据集上训练的。也许最著名的是所谓的 COCO 数据集(上下文中的公共对象),它有许多不同的图像,带有标签类、边界框,甚至可以作为注释使用的遮罩。该数据集被用于许多比赛,并被引用为“旨在推动物体检测技术的发展”。很酷的东西,也是我一直在寻找的。我选了一个叫“更快的 R-CNN”的网络。我选择它是因为它在 TensorFlow 模型动物园和火炬视觉套装中都有,这样我可以更容易地比较这两者。更快的 R-CNN 是一个区域提议网络(因此称为 R ),它使用“锚盒”技术来定位物体并预测它们。简而言之,它是两个网络的组合,一个检测图像中很可能包含对象的区域,另一个预测边界框以及这些区域中的类别概率。网上有很多更详细的解释。我个人比较喜欢这个高昊的。
配置模型
1.下载模型文件
一旦您选择了模型,您首先必须下载它,这意味着您下载网络架构和预先训练的权重。我选择的是“更快 _ rcnn _ inception _ v2 _ coco _ 2018 _ 01 _ 28”的模式。这是通过从 models/research 文件夹运行以下命令来完成的:
%%bashwget [http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_v2_coco_2018_01_28.tar.gz](http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_v2_coco_2018_01_28.tar.gz)tar -xvf faster_rcnn_inception_v2_coco_2018_01_28.tar.gz
现在您可以找到一个包含所有模型文件的文件夹:
import os
os.listdir("faster_rcnn_inception_v2_coco_2018_01_28")
看起来像这样:
['model.ckpt.index', 'checkpoint', 'pipeline.config', 'model.ckpt.data-00000-of-00001', 'model.ckpt.meta', 'saved_model', 'frozen_inference_graph.pb']
在那里,您可以找到检查点信息,让您使用预训练的权重重建模型,从而为迁移学习做好准备。您还有一个 saved_model 文件夹,其中包含下载模型的导出版本以及一个 freezed _ inference 图——正如其名称所建议的,您可以使用一个 tf 图进行推理。最后但同样重要的是,您可以找到一个 pipeline.config 文件的示例。在此文件中,您可以准确指定您希望如何训练您的网络,使用什么样的训练数据,您有多少个对象类,等等。在这里,我们可以根据我们的具体需求定制预训练模型。
2.准备数据
在 TensorFlow 的对象检测中,估算器 API 用于处理训练和评估(以及一些类似检查点等的东西。)过程。这个 API 需要您首先创建的 tf.record 格式的数据。
幸运的是,浣熊数据集的创建者已经完成了这项工作。否则我们也可以自己改造它:
!python generate_tfrecord.py --csv_input=data/train_labels.csv --output_path=data/train.record
我们有一个 train.record 和一个 test.record 数据集,它们将用于在训练期间向 tf.estimator 对象成批提供数据。
3.调整 pipeline.config 文件
在 pipeline.config 文件中,我们必须调整 5 个区域。微调检查点、训练配置、有效配置、类数量和第二阶段后处理。其他一切都可以保持原样。fine_tune_checkpoint 是下载的检查点文件中包含的预训练权重的路径。我们在这里所做的就是设置它等于
fine_tune_checkpoint: "<your path >/faster_rcnn_inception_v2_coco_2018_01_28/model.ckpt"
如果您发现没有名为 model.ckpt 的文件,请不要担心,相信我,它确实是这样工作的;)可以重建模型并将权重插入到正确的层中。num_classes 字段被设置为 1(仅 1 个类:浣熊)。
在 train_config 部分,我们可以调整所有关于训练阶段的东西。我保留了所有的默认设置,只修改了必要的部分,比如 train_input_reader,在这里,您必须设置 train.record 训练数据集的输入路径,以及包含标签信息的 pbtxt 文件的 label_map_path。我首先将 label_map 文件更改为
item {
id: 1
name: 'raccoon'
}
然后我将 train_input_reader 设置为
train_input_reader: {
tf_record_input_reader {
input_path: "<your path>/raccoon_dataset/data/train.record"
}
label_map_path: "<your path>/training/raccoon_label_map.pbtxt"
}
接下来,我更改了有效配置部分。这个名字再次解释了这一切。我只是将 eval_input_reader 设置为我的 label_map 文件,并将 test.record 测试数据设置为
eval_input_reader: {
tf_record_input_reader {
input_path: "<your path>/raccoon_dataset/data/test.record"
}
label_map_path: "<your path>/training/raccoon_label_map.pbtxt"
shuffle: false
num_readers: 1
}
最后,我调整了第二阶段后处理。在这里,您可以定义模型如何处理输出。通常,检测模型输出类别概率和边界框坐标的多个可能组合(例如,每个锚一组),其不等于图像中对象的数量。作为用户,我们必须使用非最大值抑制等技术来获得最佳匹配的边界框(上面提到的 Andrew Ngs Coursera 课程对此做了很好的介绍!)到图像中的每个对象。我在这里挑选了以下内容:
second_stage_post_processing {
batch_non_max_suppression {
score_threshold: 0.5
iou_threshold: 0.6
max_detections_per_class: 5
max_total_detections: 5
}
score_converter: SOFTMAX
}
这意味着我将只允许每个图像 5 个检测(理想情况下,如果图像中存在不同的浣熊,5 个不同的检测)。IoU(并集上的交集)阈值以及分数阈值被定制为每个对象只有一个边界框。
训练模型
一旦 pipeline.config 文件准备就绪,我们就可以开始培训了。TensorFlow 建议使用一个命令行作业调用带有各种输入参数的 model_main.py 文件来完成这项工作。然而,当我想深入了解一下时,我跳进了这个文件并自己运行了这些命令。对于模型的训练和评估,对象检测 API 利用 tf 的估计器 API 。它很好地照顾了我们的训练和评估,并且集成了自动检查点和模型导出。它还允许从给定的检查点进行迁移学习(这正是我们正在做的),并在训练期间编写自动摘要,我们可以用 tensorboard 可视化这些摘要,以监控表现。
评估人员将需要培训和评估规范,这些规范包含并定义刚才提到的所有内容,并负责为我们批量处理数据。tf 的对象检测具有预定义的函数来从我们的 pipline.config 文件中实例化这些对象:
在开始之前,我们需要导入所有必需的库(就像在 model_main.py 文件中一样):
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from absl import flags
import tensorflow as tf
from object_detection import model_hparams
from object_detection import model_lib
现在,我们可以从指定模型目录开始:
model_dir = "<your path>/faster_rcnn_inception_v2_coco_2018_01_28/model_dir"
API 将把它的日志文件以及检查点和导出的模型写到这个目录中。然后,在指定运行配置、pipeline.config 文件的路径以及要训练的步骤数(一个步骤是对单批数据的一次运行)之后:
config = tf.estimator.RunConfig(model_dir=model_dir)
pipeline_config_path= "<your path>/training/pipeline.config"
num_train_steps=10000
我们可以实例化所有对象,并最终使用适当的预构建函数创建训练和评估规格。
train_and_eval_dict = model_lib.create_estimator_and_inputs(
run_config=config,
hparams=model_hparams.create_hparams(None),
pipeline_config_path = pipeline_config_path,
train_steps =num_train_steps,
sample_1_of_n_eval_examples = 1)estimator = train_and_eval_dict['estimator']
train_input_fn = train_and_eval_dict['train_input_fn']
eval_input_fns=train_and_eval_dict['eval_input_fns']
eval_on_train_input_fn=train_and_eval_dict['eval_on_train_input_fn']predict_input_fn = train_and_eval_dict['predict_input_fn']
train_steps = train_and_eval_dict['train_steps']
然后使用 Estimator、train_spec 和 eval_spec 进行训练:
tf.estimator.train_and_evaluate(estimator,train_spec,eval_specs[0])
现在发生的一些事情值得一提。首先,使用 pipeline.config 文件中的适当优化器设置来训练模型。每隔config . save _ check points _ secs模型将检查点(一组权重)写入 model_dir。然后每个 eval_specs[0]。我们暂停训练,在测试集上运行评估。为了做到这一点,我们首先需要有一个可用的检查点。eval_spec 配置为使用 COCO challenge 的评估指标(使用 pycocotools 库)。每个config . save _ summary _ stepsestimator API 都会写出事件文件,以便在 tensorboard 中可视化。
我运行了 10.000 步的模型,并在测试集上获得了 0.65 的最终 mAP。当对肉眼进行预测时,这已经输出了一些相当不错的边界框。但是为了看到这一点,我们首先需要弄清楚如何用这个训练过的模型进行推理。
用模型做预测
这可能是整个对象检测流程中最难解决的部分。在 TensorFlow 的对象检测报告中,有一些关于如何在预建模型上进行推理的示例,但是,代码依赖于 TensorFlow 1.x 版。在 TensorFlow 1.x 代码中使用保存的模型或冻结的推理图(相对于 tf 2.x)要复杂得多,因为您必须直接使用 tf 图和会话。
1.导出模型
无论哪种方式,我们首先必须以正确的方式导出模型。我花了一些实验来找出为什么已经在 eval_specs 中的导出器并在 TF . estimator . train _ and _ evaluate 末尾导出一个保存的模型不工作。本质上,这是由于在这个自动导出器中使用的服务功能。它是针对使用 tf.example 类型数据(例如,测试.记录数据)而定制的,然而,我们正在尝试输入表示图像的 3D 张量。这就是为什么我们必须运行一个指定输入类型的导出作业。
包含以下进口:
import tensorflow as tf
from google.protobuf import text_format
from object_detection import exporter
from object_detection.protos import pipeline_pb2
slim = tf.contrib.slim
flags = tf.app.flags
我们必须提供一个输出目录、我们的 pipeline.config 文件、输入类型以及一个我们希望从中导出模型的检查点(只使用最新的一个)
pipeline_config_path = "<your path>/training/pipeline.config"
config_override = ""
input_shape = False
trained_checkpoint_prefix ="<your path>/faster_rcnn_inception_v2_coco_2018_01_28/model_dir/model.ckpt-10000"
output_directory = "<your path>faster_rcnn_inception_v2_coco_2018_01_28/output"
input_type = "image_tensor"
write_inference_graph = False
现在我们可以经营出口商了
tf.reset_default_graph()
pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()
with tf.gfile.GFile(pipeline_config_path, 'r') as f:
text_format.Merge(f.read(), pipeline_config)
text_format.Merge(config_override, pipeline_config)
if input_shape:
input_shape = [
int(dim) if dim != '-1' else None
for dim in input_shape.split(',')
]else:
input_shape = Noneexporter.export_inference_graph(
input_type, pipeline_config, trained_checkpoint_prefix,
output_directory, input_shape=input_shape,
write_inference_graph=write_inference_graph)
2.模型的加载和推理
对于 TensorFlow 2.x,我们只需重新加载运行时并选择 2.x 作为版本
%tensorflow_version 2.x
而且基本上只是跟随他们的例子笔记本。然后,您可以用两行代码加载模型:
model = tf.saved_model.load("<your path>/faster_rcnn_inception_v2_coco_2018_01_28/output/saved_model")
model = model.signatures['serving_default']
我们现在要做的就是从测试集中加载一个图像(例如 raccoon-14.jpg)
from PIL import Image, ImageDraw
import numpy as np
import pandas as pd
filename = "raccoon-14.jpg"img = Image.open("<your path>/raccoon_dataset/images/"+filename)test = pd.read_csv("<your path>/raccoon_dataset/data/test_labels.csv")true_labels = test[test["filename"] == filename][["xmin", "ymin", "xmax","ymax"]]
并运行推理(如 tf 推理脚本所建议的)
image = np.asarray(img)
# The input needs to be a tensor, convert it using `tf.convert_to_tensor`.
input_tensor = tf.convert_to_tensor(image)# The model expects a batch of images, so add an axis with `tf.newaxis`.
input_tensor = input_tensor[tf.newaxis,...]# Run inference
output_dict = model(input_tensor)# All outputs are batches tensors.
# Convert to numpy arrays, and take index [0] to remove the batchdimension.# We're only interested in the first num_detections.
num_detections = int(output_dict.pop('num_detections'))
output_dict = {key:value[0, :num_detections].numpy()
for key,value in output_dict.items()}
output_dict['num_detections'] = num_detections# detection_classes should be ints.
output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64)
3.绘制边界框
现在,我们可以用红色绘制已学习的边界框,用绿色绘制真实标签:
selected_boxes = output_dict["detection_boxes"]
selected_scores = output_dict["detection_scores"]
draw = ImageDraw.Draw(img)#draw predictions:
for i in range(len(selected_scores)):
draw.rectangle([(selected_boxes[i][1]*img.width, selected_boxes[i][0]*img.height), (selected_boxes[i][3]*img.width, selected_boxes[i][2]*img.height)], outline ="red", width = 3)
draw.text((selected_boxes[i][1]*img.width, selected_boxes[i][0]*img.height), text = str(selected_scores[i]))# draw groundtruth:
for i in range(len(true_labels["xmin"].values)):
draw.rectangle([(true_labels["xmin"].values[i], true_labels["ymin"].values[i]), (true_labels["xmax"].values[i], true_labels["ymax"].values[i])], outline ="green", width = 3)img
测试数据集中的 raccoon-14.jpg
我们可以看到一只很酷的小浣熊在做家务。考虑到我们只训练了 10.000 步的网络,包围盒和概率也相当不错。
注意:如果你想在 TF 1 . x 版本中这样做,你可以按照这里的脚本来做。
B 部分:PyTorch
PyTorch 有一个名为 torchvision 的包,包括模型架构、数据集和其他对计算机视觉有用的功能。Torchvision 也有一个关于对象检测的子包,我们将在本节中使用。下面的很多设置和代码都是根据 torchvision 的目标检测教程建模的。
装置
- 我们需要确保安装了 numpy 版。
- 检查 pycocotools 安装
import pycocotools
4.转到您创建的 PyTorch 对象检测目录
import os
os.chdir("<your path>/pytorch object detection")
3.克隆 PyTorch vision repo 并复制一些 python 文件
%%bashgit clone [https://github.com/pytorch/vision.git](https://github.com/pytorch/vision.git)
cd vision
git checkout v0.3.0cp references/detection/utils.py ../
cp references/detection/transforms.py ../
cp references/detection/coco_eval.py ../
cp references/detection/engine.py ../
cp references/detection/coco_utils.py ../
4.现在我们可以做所有必要的进口
import numpy as np
import torch
import torch.utils.data
from PIL import Image
import pandas as pdfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictorfrom engine import train_one_epoch, evaluate
import utils
import transforms as T
配置模型
1.准备数据
与必须为我们的训练数据创建新类型的数据文件(与 TensorFlow 中的 training.record 文件一样)相反,我们只需编写一个数据集 python 类,稍后模型将使用该类来解析图像和相应的注释。该类需要从 torch.utils.data.Dataset 继承并实现 getitem 和 len 方法。由于我们将使用与前面相同的浣熊数据集,并且 repo 中的 data 文件夹已经包含一个包含所有已解析注释的浣熊 _labels.csv 文件,所以我们所要做的就是编写一个小的助手函数:
def parse_one_annot(path_to_data_file, filename):
data = pd.read_csv(path_to_data_file)
boxes_array = data[data["filename"] == filename][["xmin", "ymin",
"xmax", "ymax"]].values
return boxes_array
然后我们可以用它来编写我们的 RaccoonDataset 类:
class RaccoonDataset(torch.utils.data.Dataset):
def __init__(self, root, data_file, transforms=None):
self.root = root
self.transforms = transforms
self.imgs = sorted(os.listdir(os.path.join(root, "images")))
self.path_to_data_file = data_filedef __getitem__(self, idx):
# load images and bounding boxes
img_path = os.path.join(self.root, "images", self.imgs[idx])
img = Image.open(img_path).convert("RGB")
box_list = parse_one_annot(self.path_to_data_file,
self.imgs[idx])
boxes = torch.as_tensor(box_list, dtype=torch.float32)num_objs = len(box_list)
# there is only one class
labels = torch.ones((num_objs,), dtype=torch.int64)
image_id = torch.tensor([idx])
area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:,
0])
# suppose all instances are not crowd
iscrowd = torch.zeros((num_objs,), dtype=torch.int64)
target = {}
target["boxes"] = boxes
target["labels"] = labels
target["image_id"] = image_id
target["area"] = area
target["iscrowd"] = iscrowdif self.transforms is not None:
img, target = self.transforms(img, target)
return img, targetdef __len__(self):
return len(self.imgs)
我们可以运行一个快速检查,看看是否一切都正确实现了。实例化一个 RaccoonDataset 对象并运行 getitem
dataset = RaccoonDataset(root= "<your path>/raccoon_dataset",data_file= "<your path>/raccoon_dataset/data/raccoon_labels.csv")dataset.__getitem__(0)
输出应该是这样的
(<PIL.Image.Image image mode=RGB size=650x417 at 0x7FE20F358908>, {'area': tensor([141120.]),
'boxes': tensor([[ 81., 88., 522., 408.]]),
'image_id': tensor([0]),
'iscrowd': tensor([0]),
'labels': tensor([1])})
2.下载并调整模型
由于我们之前在 TensorFlow 中使用了一个更快的 R-CNN,我们在这里也将使用一个。而且火炬接力也没有给我们太多的选择。在他们的网站上,他们只有两个预先训练好的(在 coco 上)用于物体检测的模型。一个更快的 R-CNN ResNet-50 FPN 和一个面罩 R-CNN ResNet-50 FPN 。
为了下载预训练的更快的 r-cnn,我们可以编写一个小的 get_model 函数来调整模型的最后一层,以输出许多适合我们的浣熊数据集的类:
def get_model(num_classes):
# load an object detection model pre-trained on COCO
model = torchvision.models.detection.
fasterrcnn_resnet50_fpn(pretrained=True)# get the number of input features for the classifier
in_features = model.roi_heads.box_predictor.cls_score.in_features
# replace the pre-trained head with a new on
model.roi_heads.box_predictor = FastRCNNPredictor(in_features,/
num_classes)
return model
我们还可以添加一个小小的 transformer 函数,通过做一些基本的数据扩充(图像的水平翻转)来增强我们的训练集
def get_transform(train):
transforms = []
# converts the image, a PIL image, into a PyTorch Tensor
transforms.append(T.ToTensor())
if train:
# during training, randomly flip the training images
# and ground-truth for data augmentation
transforms.append(T.RandomHorizontalFlip(0.5))
return T.Compose(transforms)
现在,我们可以实例化我们的训练和测试数据类,并将它们分配给 data_loaders,data _ loaders 控制在训练和测试期间如何加载图像(批量大小等)。
# use our dataset and defined transformationsdataset = RaccoonDataset(root= "<your path>/raccoon_dataset",
data_file= "<your
path>/raccoon_dataset/data/raccoon_labels.csv",
transforms = get_transform(train=True))dataset_test = RaccoonDataset(root= "<your path>/raccoon_dataset"
data_file= "<your
path>/raccoon_dataset/data/raccoon_labels.csv",
transforms = get_transform(train=False))# split the dataset in train and test settorch.manual_seed(1)
indices = torch.randperm(len(dataset)).tolist()
dataset = torch.utils.data.Subset(dataset, indices[:-40])
dataset_test = torch.utils.data.Subset(dataset_test, indices[-40:])# define training and validation data loaders
data_loader = torch.utils.data.DataLoader(
dataset, batch_size=2, shuffle=True, num_workers=4,
collate_fn=utils.collate_fn)data_loader_test = torch.utils.data.DataLoader(
dataset_test, batch_size=1, shuffle=False, num_workers=4,
collate_fn=utils.collate_fn)print("We have: {} examples, {} are training and {} testing".format(len(indices), len(dataset), len(dataset_test)))
训练模型
首先,我们可以使用以下命令来检查 GPU 设置是否正确:
torch.cuda.is_available()
如果你在 Google Colab 上运行,只需将运行时间切换到 GPU 即可。
现在我们可以使用我们的 get_model 函数来建立模型。此外,我们还必须指定一个优化器和一个学习率调度器,以便随着时间的推移调整学习率。
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')# our dataset has two classes only - raccoon and not racoon
num_classes = 2
# get the model using our helper function
model = get_model(num_classes)
# move model to the right device
model.to(device)# construct an optimizer
params = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.SGD(params, lr=0.005,
momentum=0.9, weight_decay=0.0005)# and a learning rate scheduler which decreases the learning rate by # 10x every 3 epochslr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
step_size=3,
gamma=0.1)
为了进行训练,我们现在必须编写自己的 for 循环,遍历我们希望训练的历元数,然后调用 PyTorch 的 train_one_epoch 函数,调整学习速率,最后每个历元评估一次。
# let's train it for 10 epochsnum_epochs = 10
for epoch in range(num_epochs):
# train for one epoch, printing every 10 iterations
train_one_epoch(model, optimizer, data_loader, device, epoch,
print_freq=10)# update the learning rate
lr_scheduler.step()
# evaluate on the test dataset
evaluate(model, data_loader_test, device=device)
为了保存训练好的模型(没有自动检查点),我们可以在完成训练后运行以下命令:
os.mkdir("<your path>/pytorch object detection/raccoon/")torch.save(model.state_dict(), "<your path>/pytorch object detection/raccoon/model")
10 个时代后,我得到了 0.66 的地图。
用模型做预测
我们首先必须加载模型,其工作方式是用前面的 get_model 函数实例化同一个“空”模型,然后将保存的权重加载到网络架构中。
loaded_model = get_model(num_classes = 2)loaded_model.load_state_dict(torch.load(“<your path>/pytorch object detection/raccoon/model”))
现在,我们可以使用 dataset_test 类来获取测试图像及其基本事实,并通过预测器运行它们。
idx = 0
img, _ = dataset_test[idx]
label_boxes = np.array(dataset_test[idx][1]["boxes"])#put the model in evaluation mode
loaded_model.eval()with torch.no_grad():
prediction = loaded_model([img])image = Image.fromarray(img.mul(255).permute(1, 2,0).byte().numpy())
draw = ImageDraw.Draw(image)# draw groundtruthfor elem in range(len(label_boxes)):
draw.rectangle([(label_boxes[elem][0], label_boxes[elem][1]),
(label_boxes[elem][2], label_boxes[elem][3])],
outline ="green", width =3)for element in range(len(prediction[0]["boxes"])):
boxes = prediction[0]["boxes"][element].cpu().numpy()
score = np.round(prediction[0]["scores"][element].cpu().numpy(),
decimals= 4)
if score > 0.8:
draw.rectangle([(boxes[0], boxes[1]), (boxes[2], boxes[3])],
outline ="red", width =3)
draw.text((boxes[0], boxes[1]), text = str(score))image
测试集中的 raccoon-45.jpg
简短比较
总而言之,可以肯定地说,对于习惯于命令式编码(代码在编写时执行)并一直使用 scikit-learn 类型 ML 框架的人来说,PyTorch 很可能更容易让他们开始使用(一旦 TensorFlow 将对象检测 API 升级到 2.x 版,这也可能会改变)。在本文中,我只关注“易用性”这一方面,而不关注模型的性能速度、可变性或可移植性。然而,当试图将这样的模型部署到生产性软件环境中时,需要许多这样的特性。在这里,TensorFlow 中使用的带有 config.py 文件的高级 API 从一开始就在框架中融入了更多的灵活性,其中较低级别的 torchvision 更加开放,这意味着更容易看到“幕后”(您不必研究大量 TensorFlow 源代码),但是在其教程中只显示标准。任何不符合标准的内容都必须从头开始编写,而 TensorFlow 可能会在配置文件中有一个部分来解决这个问题。此外,TensorFlow 模型动物园有更多预先训练好的模型可供人们使用。总的来说,我的经验类似于数据科学社区中一个非常典型的观点,即 PyTorche 的对象检测框架可能更适合于研究目的和“理解实现的每个细节”,而 TensorFlow 的 API 是构建生产模型的更好选择。
我希望你们能从中获得一些有价值的信息。现在是时候亲自尝试一下了。快乐编码:)
参考资料:
张量流物体检测:
创建精确的机器学习模型,能够在单个图像中定位和识别多个对象…
github.com](https://github.com/tensorflow/models/tree/master/research/object_detection)
火炬传递:
[## TorchVision 对象检测微调教程— PyTorch 教程 1.5.0 文档
提示为了充分利用本教程,我们建议使用 Colab 版本。这将允许您试验…
pytorch.org](https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html)
卷积神经网络(coursera):
本课程将教你如何建立卷积神经网络,并将其应用于图像数据。感谢深…
www.coursera.org](https://www.coursera.org/learn/convolutional-neural-networks?specialization=deep-learning)
建立你自己的自我关注感
用 MNIST 和西里巴数据集实现 SAGAN 的 PyTorch
来自 imgflip.com 的迷因
GANs ,又称生成对抗网络,是近年来机器学习领域最热门的话题之一。它由两个不同的神经网络模型组成,一个叫做 生成器 ,一个叫做 鉴别器 。这听起来很难理解,但让我试着这样说:假设我们想在没有任何绘画知识的情况下伪造名画,我们应该怎么办?大多数人会说,看看画,学着怎么做就行了。但这不是一个人的工作,在某种程度上,我相信你会在绘画上越来越好。你需要让你的朋友来到一幅真画和一幅你伪造的画面前,让他猜猜哪一幅是真的。一开始他很容易猜到,但是继续猜下去,你最终会把你的朋友弄糊涂。
在 GANs 里,发生器就像你伪造画作,鉴别器就是专门辨别哪幅画是假的朋友。想想这里的目标,你想让你的朋友很难分辨真假。如果你的朋友对每幅画给出一个从 0 到 1 的真实概率,你会希望他对你给他看的任何一幅画给 0.5 分,不管是真实的还是伪造的。这也将是 GANs 的目标,反映在损失函数中。
我们也经常看到 DCGAN ,它代表深度卷积 GAN 。这是一种专门用于图像生成的 GAN 设计,为发生器和鉴别器使用卷积层。它的工作原理就像 CNN 一样。 A 自关注 GAN 是利用自关注层的 DCGAN。自我关注的想法已经存在多年,在一些研究中也被称为非本地。想想卷积是如何工作的:它们对附近的像素进行卷积,并从局部块中提取特征。它们在每一层“本地”工作。相反,自我关注层从远处的街区学习。2017 年,谷歌发表了一篇论文“关注是你所需要的全部”,带来了更多关于该话题的炒作。对于单个图像输入,它是这样工作的:
1.使用一个核大小为 1 的卷积生成查询、键和值层,形状为 (Channels * N) ,其中 N = Width * Height 。
2.由查询和关键字的矩阵点积生成关注图,形状为 (N * N) 。 N * N 注意力图描述的是每个像素在每隔一个像素上的注意力得分,因此得名“自我关注”。这里的像素是指输入矩阵中的数据点。
3.通过价值与注意力地图的矩阵点积得到注意力权重,形状为 (C * N) 。注意力权重描述了所有像素中每个像素的总注意力分数。然后我们将注意力权重重塑为 (C * W * H) 。
4.将注意力权重添加回输入层本身,权重为γ,学习参数初始化为 0。这意味着自我关注模块最初不做任何事情。
综上所述,自我关注 GAN 只是一个具有自我关注层的 DCGAN。2018 年的论文“自我关注生成对抗网络”指出*DCG an 可能无法捕捉多类数据集一致出现的几何或结构模式,例如,画狗时没有单独的脚。*毕竟如何打造一个自我关注的甘?让我们把手弄脏吧!
1.正在准备数据集
我们将使用 MNIST 数字数据集。用 PyTorch 下载后,我们再用 DataLoader 加载数据。
2.构建模型
首先,我们将构建自我关注模块,稍后将在生成器和鉴别器中使用。可以查阅之前的自我关注模块结构,以便更好的理解。
发生器和鉴别器的结构如图所示:
模型结构
谱归一化是在生成对抗网络谱归一化中提出的一种新的权重归一化技术,用于更加稳定的训练过程。借用萨根的 spectra . py。
3.创建培训功能
这通常是最令人困惑的部分。与 CNN 或其他简单的机器学习模型不同,GANs 没有现成的拟合函数。我们需要编写整个训练函数。
我们首先初始化我们的模型和优化器。然后在一个循环中,我们首先从数据加载器读入一批数据。
下一步,我们向我们的鉴别器提供一批真实图像,并计算。然后我们用一组随机数作为潜在变量,用生成器生成一批伪图像,再次送入鉴别器,得到损失。
如前所述,我们的鉴别器的目标是对真实图像给出接近 1 的预测,对虚假图像给出接近 0 的预测。因此,我们希望减少(1-对真实图像的预测)和对虚假图像的预测的总和。借助 PyTorch ,我们可以使用 backward 和 step 实现这一点,并在几行代码内更新鉴别器的所有学习参数。
然后,我们使用来自鉴别器的假图像的输出来更新发生器的参数。瞧,一个训练循环完成了,我们为第一批图像训练了我们的模型。打印出日志信息,并保存图像/模型,如果你想要的。
4.模型性能
训练功能完成后,只需运行该功能即可开始训练。每 100 批从生成器中抽取样本,可以看到我们的模型学习画数字的过程。左边是没有注意的结果,右边是注意的结果。
关于 MNIST 的培训过程
通过对模型结构进行一些细微的更改,我们可以让我们的模型在其他大小的输入上运行。使用与 SAGAN 相同的结构,我们也可以在 CelebA 数据集上运行。具体的模型结构和训练功能可以在我的 GitHub 中找到。
CelebA 上的培训流程
5.你应该使用自我关注甘吗?
正如你可能从上面的 gif 中观察到的,在有和没有自我关注层的模型之间没有明显的视觉差异。此外,自我关注层通过计算多个矩阵点积来工作,这将导致 10% ~ 30%的训练时间延长,具体取决于你的具体模型结构。
然而,在 SAGAN 论文(韩等人 2018)中,作者确实报告了使用自我注意模块获得更好的初始和 FID 分数。我的下一步将是采用这些指标中的任何一个,看看自我关注的甘是否带来了更好的表现。在我的 GitHub 查看所有源代码和演示。
您需要了解的 Jupyter 实验室内置快捷方式和工作流程提示
在我开始从事数据科学之前,我一直在与音频打交道:编辑播客,混合中学乐队成员的 50 首曲目,改编《怪物史莱克》中的“童话”主题,等等。作为一名音频编辑,你 100%绝对需要快捷方式,否则你会在做一个大项目时瘫坐在椅子上。只是没有足够的时间点击所有的东西。因此,当我学习像 Jupyter Lab 这样的新技术时,我做的第一件事就是找到我能找到的每一条捷径,这样我就不会因为点击而提前死去。
图为:我试图不用快捷方式清理一个 Jupyter 笔记本。(图片由 安妮·尼加德 上)
让我们挖掘捷径,好吗?注意,我将提到 Windows 键 Control 和 Alt ,它们分别等同于 Mac 上的 Command 和 Option 。
1.鼠标修饰符:Ctrl(命令)和 Alt(选项)
鼠标修改器是改变鼠标操作的按键。我用过的大多数软件在你control + click
或者alt + click
的时候做一些的事情,是否有用就是另一回事了。
在 Jupyter Lab 中,您可以使用 Control 和 Alt 做一些令人惊讶的事情:
- 按住 control 键并点击可以让你在一个单元格内的多个地方进行编辑。双击也会突出显示一个单词。将这两者结合起来,您可以快速地移除不需要的方法。
按住 Ctrl 键,双击“值”并删除。
- 按住 alt 并拖动可以让你编辑垂直线条。我用它给单元格中的变量添加前缀/后缀。(注意:你也可以按 Ctrl + F 来替换,但是在“全部替换”功能背叛了我之后,我对它产生了信任问题。)
按住 alt 键,垂直向下拖动,给变量名添加前缀
按住 alt,拖动一个框,一次替换多个变量前缀
- 回答你的下一个问题,是的!您可以按住 Alt + Ctrl 突出显示并编辑单元格内的多个位置。但是我只在感觉混乱的时候用这个。
2.细胞操作
单元格可以很好地用数据讲故事,但当你需要更好地组织其中的代码时,它就很烦人了。这里有一些操作,你可以对细胞本身进行清理你的笔记本在一瞬间!
这些操作中的每一个都必须在单元格被选中时执行,所以你不应该编辑单元格。您可以通过单击通常会看到输入/输出数字的单元格左侧区域来选择单元格。
- 复制:按
c
即可 - 粘贴:按下
v
即可 - 切:按
x
即可 - 删除:按
dd
- 移动:点击并拖动单元格
现在看我快速地做这个——哇!我好快啊!哇!印象深刻!哇!我根本没必要练习这个!(…)
合并和拆分单元格
这将帮助我们解决以下问题:
- 您在一个单元格中写了太多内容,希望将其拆分为多个单元格
- 你需要与某人共享代码,但是它跨越了 8 个不同的单元,对你和接收者来说,复制它将是乏味的
- 拆分单元格:**将光标放在后的行的开头,然后按
Ctrl + Shift + -
进行拆分
用 Ctrl + Shift + -拆分单元格
- 合并单元格:按住
Shift
,选择要合并的单元格范围,选择所有要合并的单元格(先点击单元格 1,再点击单元格 8,选择单元格 1-8),然后按Shift + M
,将所有单元格合并为一个单元格
用 Shift + M 合并单元格
- ***撤销最后一个单元格操作:*这是写给那些认为自己因为意外删除了一个复杂函数单元格而毁了整个晚上的数据科学家的。按
z
取消最后一次细胞操作,并降低您的心率。按下Shift + z
也可以重做最后一次单元操作!
3.使用 Ctrl 导航和编辑文本
这是跨越许多程序、文本编辑器和浏览器的东西。我建议每个人都使用它,因为它可以节省你浏览文本行的时间。
- ***通过文字导航:*按住
ctrl
并按向左或向右箭头 - ***删除一整字:*按住
ctrl
,根据你要删除的方向,按delete
或backspace
。如果您想删除从单词中间到单词结尾/开头的内容,也可以这样做。将光标放在中间,使用适当的*delete*
或*backspace*
键 - ***高亮显示一个单词:*按住
ctrl + shift
并按向左或向右箭头高亮显示一个单词。这在 Jupyter Lab 中不是非常有用,但是在文本编辑器中很有用,在那里你可以使用快捷键来加粗、突出显示或给文本加下划线。
除了最初的点击,在制作上面的 gif 时没有使用鼠标。
如果你有一个可编程游戏键盘/鼠标,通过 word 导航的概念是一个完美的工具——我使用ctrl + arrows
的想法来分配快速宏,通过结合上述一些技术,将通过按下按钮自动加粗 markdown 数据字典中每行的第一个单词。
是的,你现在需要一个游戏键盘。我不是罗技赞助的,但我应该是。
最后…平行笔记本标签
当我第一次开始使用 Jupyter Lab 时,最令人沮丧的事情之一是在 markdown 中创建自述文件。我不得不使用第三方平台来查看我的降价编辑。不要害怕!因为我有一个工作流程改进!
- 双击用编辑器打开 README.md 文件。
- 右键点击并转到打开>降价预览
- 单击屏幕顶部的预览选项卡,并将其拖动到屏幕的右侧,将两者并排放置,并查看您的减价的实时更新。
请原谅全屏 gif…
这个的其他用途:
- 调出上下文帮助菜单(在“帮助”下),这样你就可以查看一个函数的文档字符串,而不需要按
Shift + Tab
- 调出一个包含您的自定义函数的
funcs.py
脚本,这样您就可以记住它们是如何工作的,而无需来回翻动。
就这些了,伙计们!
如果您对 Jupyter Lab 有任何其他不满,请留下评论,我会看看我是否能想到用内置功能解决它的方法!也感谢我的同事们在我用“撤销最后一个单元格操作”功能拯救了某人的夜晚后,鼓励我写这篇博文。
Python 快速⚡️中的批量下载
利用 AWS Lambda 和亚马逊 SQS 批量下载外部文件
加布里埃尔·托瓦尔在 Unsplash 上的照片
这篇文章概述了我如何使用 AWS Lambda 和亚马逊 SQS 以比我本地机器快 350 倍的速度将 194,204 个文件(即 CSV 格式)下载到亚马逊 S3!
问题是
最近,我构建了一个 web 应用程序来下载加拿大的历史天气数据。作为应用程序结构的一部分,我需要从第三方服务器下载 8,324 个独立气象站的数据,并将数据存储在数据库中(亚马逊 S3)。
使用 Python、Dash 和 AWS 简化加拿大历史天气数据
towardsdatascience.com](/building-a-dynamic-weather-download-app-1ce64a6c3e61)
看起来很简单,对吧?只需创建一些代码,执行,瞧,你有数据。错了。
每个气象站都有多年的天气数据,第三方服务器将下载限制在 1 年的增量。简而言之,下载所有 8324 个站点的数据集意味着下载 194204 个单独的文件(即一个站点每年的数据一个文件),合并匹配站点的数据,并将数据推送到亚马逊 S3。
下载数据的问题不是文件大小,整个数据集只有 4.4 GB,而是下载速度和网络延迟。在我的本地机器上,下载一年的数据并将其推送到亚马逊 S3 大约需要 1.7 秒。这意味着使用我的本地机器下载所有 194,204 个文件并推送到亚马逊 S3 将花费 3.9 天,假设没有网络中断或下载失败。😲
我们可以做得更好!
解决方案
很明显,在本地机器上下载数据是不切实际的,也是不可靠的,尤其是在云计算如此容易实现的情况下。最终,我决定使用 AWS Lambda 来执行我的 Python 代码,使用亚马逊 SQS 消息队列来触发 Lambda 事件和传达下载任务。
概观
这篇文章并不打算深入概述 AWS Lambda 和 SQS,因为已经有了很好的资源,但是我将提供 Lambda 和 SQS 的基本概述以及我使用的框架。
AWS Lambda 是一种运行代码以响应事件的方式,无需提供或管理服务器。亚马逊 SQS 是一种在不同软件组件之间发送、存储和接收消息的方式(即两个 AWS Lambda 函数之间的消息)。
在我的例子中,我使用一个 Lambda 函数为 8,324 个气象站中的每一个生成包含气象站名称和 ID 等信息的消息。每条消息都被发送并存储在 SQS 消息队列中。同时,另一个 Lambda 函数被设计为响应 SQS 事件(即消息到达队列)而执行。这个 Lambda 函数从 SQS 队列中检索消息,使用消息信息下载数据,并将数据推送到亚马逊 S3 进行存储。
AWS Lambda 和亚马逊 SQS 框架概述
为什么拉姆达和 SQS 很棒
以下是 Lambda 和 SQS 令人惊叹的几个原因,以及它们如何加快执行时间。
- Lambda 函数一次可以从 SQS 消息队列中检索多达 10 条消息。
- Lambda 函数可以并发执行。例如,使用*“for loop”、*执行一个任务 10X,其中每个循环需要 1 秒,而完成这个任务需要 10 秒。使用并发性,您可以“克隆”Lambda 函数并同时执行 10 个相同的函数,只需 1 秒钟即可完成!
- Lambda 函数可以分配特定数量的内存(即 CPU)。这加快了执行时间。
注意:当增加 AWS Lambda 函数的并发性和内存时,你应该小心,因为这会很快导致成本增加。
为什么要做这一切
你可能会问*“为什么要通过 SQS 将相同的信息从一个 Lambda 函数发送到另一个函数,而不是对所有事情都使用一个 Lambda 函数?”。*
问得好。
AWS Lambda 函数的最大执行时间限制为 15 分钟。如果我尝试执行 30 个任务,每个任务花费 1 分钟,我将超过最大执行时间。相反,我需要将 30 个任务分成块,执行时间少于 15 分钟。通过使用 SQS,我可以触发 Lambda 并定义我希望 Lambda 从队列中卸载多少任务(最多 10 个),以确保总任务时间低于执行时间。
代码
第一步:
使用 AWS Lamda 将消息发送到 SQS 消息队列。在我的例子中,我为每个气象站发送了一条消息,其中包含气象站 ID 和数据的开始和结束年份等信息。
AWS Lambda 函数将消息发送到 SQS 消息队列
第二步:
创建一个 AWS Lambda 函数,当消息在 SQS 消息队列中可用时触发(即执行)。在我的例子中,Lambda 函数卸载 SQS 消息,使用消息信息下载气象站数据,并将数据推送到亚马逊 S3 进行存储。
我将 Lambda 函数配置为一次从 SQS 消息队列中读取 10 条消息。这使得总执行时间低于 15 分钟的限制。我还为 Lambda 函数配置了高达 1000 的并发性(即,如果需要,Lambda 可以同时调用 1000 个执行)和 256 MB 的内存。
AWS Lambda 函数从 SQS 消息队列卸载消息,并下载和存储数据
在控制台中将 SQS 设置为 AWS Lambda 的触发器
结果
在我的本地机器上,将 8,324 个气象站的数据下载并推送至亚马逊 S3 需要 3.9 天。
使用 AWS Lambda 和亚马逊 SQS,我能够在大约 16 分钟内完成任务,比我的本地机器快 350 倍!!!💪
为 SQS 消息队列生成消息需要大约 8 分钟(步骤 1),Lambda 同时下载数据并将其推送到亚马逊 S3 需要另外 8 分钟(步骤 2)。
有 AWS 免费层的总成本为 0.00 美元,没有免费层的总成本约为 4.30 美元。
- 我可以在本地机器上免费完成这项工作,但这意味着要确保 3.9 天的持续网络连接。
- 我可以通过旋转一个 EC-2 实例并运行一个 cronjob 来完成它,但是使用 AWS Lambda 的便利性非常值得这 4.30 美元。
总的来说,我很高兴找到了 AWS Lambda 和亚马逊 SQS 组合,并将再次使用它!
使用 Python Pandas 将属性批量映射到数据帧
合并而不是循环遍历大型数据帧如何显著提高程序性能
来源:https://www.pexels.com
当涉及到遍历 Pandas 数据帧中的大量行时,我们中的许多人都不耐烦地等待我们的程序结束循环,有时一行一行地等待很长时间。这是我在将高容量事务性数据作为 Pandas dataframe 加载,然后在单独的字典(从 JSON 文件加载)中根据客户机 ID 匹配丰富记录时遇到的主要困难之一。
两种数据来源:
- 熊猫数据框包含几千行交易数据(待丰富)
- 包含客户端数据的字典(将用于丰富 Pandas 数据帧)
问题:
用来自字典的客户数据丰富交易 Pandas Dataframe
如您所见,最初的方法(如下所示)是在源数据帧中查找 ID,然后遍历参考字典中的另外几千条记录来查找匹配。对每一行重复进行这种操作——想想看。一秒钟是完成这个查找的平均时间,更不用说根据参考数据值更新数据帧需要几个小时的数据处理时间!
源数据是作为来自不同源系统的独立数据帧收集、清理和加载的,因此我的程序遍历这些数据帧的每一行,根据参考字典中的不同属性进行匹配。首先,知道您希望将这两个数据源映射到哪个属性非常重要。在我的例子中,数据帧有 2-3 个不同的属性(基本上是跨数据集的不同映射属性),这就是为什么一开始不可能将它们全部整合到一个更大的数据帧中——这从一开始就会简单得多。在大多数情况下,您无法控制系统和团队如何收集数据,因此在开始繁重的工作之前,可能会花费大量时间来确保您的格式是一致的。
就这一点而言,如果实现一个战略解决方案,与源团队合作并让他们知道您希望他们如何发送数据是值得的——这将节省您未来的时间,也有助于确保一致性。此外,您不希望遇到这样的情况:最终接收到的源数据包含意外的列、缺失的属性或不同的数据类型。
一旦数据帧被清理并重新标记,允许使用相同的属性和数据类型快速组合它们,我很快意识到**循环应该只保留给较小的数据集。**映射或合并更适合有几千条记录的数据帧。这个过程非常类似于 SQL 连接,将多个表(在我们的例子中是数据帧)组合成一个统一的表。
可以想象,使用循环查找匹配对性能没有好处。最初,我的程序要花几个小时来运行,因为它要逐行(针对数千条记录)运行,然后在参考数据字典中找到匹配。我知道,如果我生成的报告从长远来看有效率的话,这个程序必须得到充分的改进。这就是战略问题解决发挥作用的地方!
虽然我在程序中使用了循环,但这只是为了识别惟一的客户机 id,然后从更大的引用数据集中创建一个子集字典。这使我避免了在源数据帧的几千条记录和参考字典的几千个其他值中循环。
这种通过迭代开发的新方法将我的程序的执行时间从 12 小时提高到了 15 分钟。
解决方案:
步骤 1: 在源数据帧中识别惟一的 id,并将它们保存到一个列表中
步骤 2: 查找源数据帧和参考字典之间的匹配
步骤 3: 为较大的参考字典中的所有匹配创建一个子字典&将其转换为数据帧
步骤 4: 将子集参考数据帧与源数据帧合并
希望这种合并而不是循环的发现能够帮助您踏上数据科学之旅!
解决数据不平衡的要点方法!
当绝大多数数据属于一个类(多数类)而少数类的样本很少时,就会出现数据不平衡问题或类不平衡问题。
由 Unsplash 上的 Loic Leray 拍摄的照片
如果:,就不会有数据不平衡的问题
- 你并不真正感兴趣的是,正确地划分少数阶级(很少发生!).
- 你有一个巨大的训练数据集,即使你的类样本比例非常不平衡,你仍然有很多样本在你的少数类。
精确不是你的最佳选择
- 假设你有 1000 个样本(其中 990 个属于 A 类,10 个属于 b 类,你的智能算法决定把所有东西都归为 A 类!你的准确率,在这种情况下,是 99%!
好看!除非你试图开发一个人工智能驱动的疾病识别工具,否则你将走向另一个 Theranos 故事。 - 根据假阳性和假阴性的代价(和后果),你可以决定你应该更关注哪个指标。
- 例如,如果假阳性意味着您将损失 10 万美元,而假阴性意味着您将损失 10 美元,那么您知道您的指标应该更侧重于最小化假阳性!
了解更多!
如何处理问题?
有 3 种方法:
- **关注数据:**使用各种采样、增强技术等。重点是要有一个更平衡的数据集。
- **关注算法:**这些方法大多关注于修改损失函数。
- **混合方法:**抽样和算法变化的结合。
提示:根据假阳性和假阴性的代价(和后果),你可以决定你应该更关注哪个指标。
让我们从不同的方法开始
过采样和欠采样
也许处理数据不平衡最常见的方法之一是对少数类进行过采样或对多数类进行欠采样。请确保仅对定型集进行过采样。
- 非常有用的关于 Python 中过采样的博客文章
- R 中的过采样和欠采样
击杀
过采样的一个有趣的概括是通过创建新的样本来合成少数类中的新数据点,而不仅仅是用替换进行过采样。该方法使用最近邻和随机数来生成新的合成(伪)数据点:
- 随机选择一个数据点,称之为“主”。
- 找出五(k)个最近的邻居。
- 随机选择这 5 个相邻点中的一个。
- 在你的“主要”点和随机选择的邻居之间画一条线。
- 在你画的线上创建一个随机点,并对其进行分类。
主要论文(有 5k+次引用)。如果你是视觉学习者,请看这里!
**Rose,**是另一种使用平滑自举方法的半类似方法。
成本敏感分类
常见的分类算法都试图最小化分类误差(如果你把 A 误分类为 B,就会通过增加代价函数来惩罚算法)。但是对于一个代价敏感的分类器,并不是所有的误分类都是一样的!当算法错误分类少数类(少数类获得更高的权重)时,它们会对算法进行更多的惩罚。
卷积神经网络(CNN)怎么样?
- 上述方法工作良好。但是一些有趣的细微差别出现了,对于“经典的”机器学习技术来说不一定是真的。这是一篇关于的快速阅读实验论文。
焦损失
这种相对较新的方法是我的一个朋友让我注意到的。该方法主要针对一阶段和两阶段目标识别,通过引入聚焦因子对交叉熵损失函数进行了改进。焦点因子给予更“难”的例子更高的权重。读艾的论文。
结论
还有很多,但实际上这些是处理不平衡数据的非常有用的技术。我还想指出,有时将问题重新框定为异常检测问题会更容易!在异常检测中,问题变成了如何定义(和标记)正常行为。在下一篇文章中,我将在几个问题上使用这些技术,看看它们在 python 中的表现。
数据科学中的热点问题
…你应该有自己的看法
艾米丽·莫特在 Unsplash 上的照片
在每一个职业中,社区成员之间都有分歧。大多数时候,争吵的发生要么是因为两种选择都同样可行,要么是很少有证据证明这种或那种选择。有时候,人们不同意只是因为他们有不同的偏好,选择是非常主观的。
对这些分歧有自己的看法是一种巧妙的欺骗,让自己看起来和感觉上像是社区的一部分。无论如何,你迟早会参与到这些讨论中。我只想用这篇文章给你一点小小的推动。
我将列出我多年来在数据科学界听到的一些分歧,并分享我个人对它们的看法。
Python vs R
您可能在开始学习数据科学之前就已经听说过这种讨论。它在互联网上无处不在,每个人都有话要说,有些人对它有非常强烈的意见。
如果你认为如此在意你使用哪种语言是愚蠢的,那么我支持你。但是当你开始工作时,这可能是你的同事问你的第一件事。
我不得不承认,和你的同事讨论所有的利弊很有趣,但这可能弊大于利。我看到许多有抱负的数据科学家在这个问题上困惑到决策瘫痪的地步。他们自然想做出正确的选择,但互联网上的所有讨论都无助于他们。
如果我必须选择一方(我没有,但我仍然会),我会选择 Python。主要是因为我更适应它,我以前已经用过很多了,我可以更快地开始得到结果。这也是我被问到时推荐的语言。我觉得很直观,也很好学。此外,Python 背后有一个伟大的社区,当你陷入困境时,它会为你提供答案和支持。更不用说那些让你的工作变得更容易的神奇的图书馆了。
尽管我遇到过许多强烈偏好 R 的人,他们的理由似乎相似。
但是,让我们往好的方面想。如果两种语言都有铁杆粉丝,这可能意味着两种语言都是非常好的语言!
Matplotlib 与 ggplot2
这最初是 Python 与 R 讨论的延伸。Matplotlib 是使用 Python 时的首选可视化工具,而 ggplot 是人们使用 r 时的首选。人们大多批评 matplotlib 无法创建漂亮的图表。我的一个朋友最近发给我一个关于这个的迷因,我认为它清楚地描述了整个讨论。
让我向您展示每个库生成的图的示例。当然,我同意 ggplot2 图看起来更好看,而不需要付出额外的努力。但与此同时,当你只是在分析时,你需要你的情节看起来有多美?大多数时候,只要他们给你看你需要看的,就没问题。
来源: Pythonspot 和 R-Graph-Gallery
我发现 matplotlib 图和 ggplot2 图一样功能强大,适应性强。一些 R 专家可能不同意我的观点。
matplotlib(或者更一般的 Python)的一个秘密武器是额外的 Seaborn 库,它可以制作非常棒的图形/图表。该你了,r。
来源: Seaborn
保养还是不保养?
我在数据科学界听到的另一个争论是,数据科学家是否应该维护他/她开发的模型?对这个问题的主要反应要么是非常强烈的“是的,当然!”或者“不,当然不是!”。
那么什么是模型维护呢?模型维护仅仅是确保模型在被最终用户部署和使用后仍然能够按照预期的方式工作。这可能是:
- 确保模型跟上现实生活的变化
- 确保模型性能仍然是可接受的,并且不会恶化到某个水平以下
- 当输入数据格式改变时进行必要的更新
- 适应数据质量的变化
- 还有很多其他的东西…
正如您所想象的,关注模型并确保一切正常工作是一项繁重的工作。数据科学界的一些人认为,数据科学家应对他们制作的模型负全责,因为他们最了解模型,他们应该是关注模型的人。而另一些人认为数据科学家的工作在他/她交付一个工作模型以及它的解释/文档时就结束了,应该有受过专门训练的专业人员来做模型维护。
对此我的看法基本是:看情况。如果是资源有限的小公司,期望数据科学家负责模型的维护是很正常的。但是如果它是一个更大的公司,让其他人维护模型更有意义,因为对于一个数据科学家来说,这很容易变成太多的工作要处理。
数据科学是一个垂死的职业,而数据科学才刚刚开始繁荣
关于数据科学泡沫是否正在破裂,有很多争论。有人说,没有人想在 5 年内成为数据科学家,有人说,这项技术才刚刚起步,它将成为下一个大事件。
我认为两种观点都有道理。AI,ML,数据科学绝对是炒作出来的。这就是为什么我认为随着时间的推移和炒作的消退,预计需求会减少是合理的。但与此同时,我们仍然可以用它来实现很多目标。我不是说算法会变得更好,更具可扩展性,我们会实现更大的目标。相反,我相信仍然有一些行业刚刚开始在他们的工作中采用 ML 技术。这就是为什么它有成长的空间,并在更广泛的领域中成为更大的一部分。我想你可以称之为横向扩张,而不是纵向扩张。
专业化与一般化
一些数据科学家认为,最好是非常擅长一种技术或学科,如 NLP 或图像处理。而其他人更喜欢成为数据科学通才,并在理解项目需求和实施各种工具方面训练自己。
很多时候,这种争论源于人们声称在数据科学方面,一种方法比另一种方法更好。我认为这是一个非常个人化的决定,没有什么好或坏的选择。
就目前而言,我更愿意做一个多面手,在需要的时候能够快速学习。我相信这会让我更有效率。我也很喜欢尝试新的工具和方法。
但是,如果我需要实现一个 LSTM 网络,我可能至少需要从该领域的专家那里获得信息,甚至很可能与他们一起工作。
总而言之,我认为,在数据科学中,所需的技术可以有很大不同。归根结底,我们既需要通才,也需要专家。
你听说过数据科学的其他热门话题吗?人们在 Reddit 上发了很长的帖子?评论一下,让我知道!
👉对数据科学领域以及如何开始学习感到困惑? 免费参加数据科学入门迷你课程 !
数据科学家的商业 101
马丁·比约克在 Unsplash 上的照片
为数据科学家量身定制的业务要点
为什么要看这篇文章?
数据科学家通常来自 STEM 课程(科学、技术、工程和数学),非常擅长数字和解决框架清晰的问题。然而,当我们开始处理业务问题时,它可能会变得有点混乱:项目目标并不总是清晰的,问题需要主观输入,因为没有数据可用,执行管理层并不总是热衷于 100%依赖数据来做出决策。
为了处理这些情况,让我们的心态适应这个新环境是一个好主意,最重要的是,通过将“数据行话”翻译成“业务行话”,能够和你的同事说同样的语言。记住这一点,让我们回顾一下商业的基础,以及如何用数据处理商业问题,同时还能以每个人都能理解的方式说出自己的想法。
商务必备
照片由尼基塔·卡恰诺夫斯基在 Unsplash 上拍摄
营销
营销的目标是通过找到你的理想目标市场,选择最佳价格并确定针对这些客户的策略,向尽可能多的人、尽可能多的次数和尽可能高的价格销售尽可能多的产品。
这看起来像一个优化问题,对不对?不完全是。在实践中,有太多的问题需要妥善解决:你如何定义一个理想的目标市场?如何测试不同的价格?你如何确定应对客户的策略?你应该使用哪个时间段?
因此,重要的是使用特定领域的知识来提出特定的问题,并使用数据来指导过程并提出答案。例如,要找到你的理想价格,测试需求对不同价格的反应并找到最佳点是不够的:这也是一个品牌问题,以及与竞争对手相比,你希望你的产品或服务如何被感知。如果你在劳力士工作,即使你注意到对他们手表的需求对价格非常敏感(每次你进行促销和给予特别折扣,需求都会大幅增加),过分降低价格也不一定是一个好策略:你会在一段时间内获得丰厚的利润,然后人们就不会认为劳力士是一个如此高端的奢侈品牌,失去了很多价值。
理解定义价格和目标市场不仅仅是在短期内优化它,而是了解客户如何看待你的产品/服务,以及他们将如何应对营销策略的变化。与竞争对手相比,你希望你的产品被如何看待?这实际上不是一个可以用数据来回答的问题:它需要一个主观的答案,然后决定你将如何使用数据来解决其他问题。
定义营销策略时,你应该熟悉的一个关键营销概念是 4 P:产品、地点、价格、促销。
- 产品是关于你的产品的特性以及潜在客户对它们的看法:品牌名称、外观、特点等。
- 地点是关于你的分销渠道:你的客户将在哪里购买你的产品,谁将出售它,等等。
- 价格是围绕产品价格的一切:你的客户有多看重你的产品?你希望你的产品如何被感知(更贵,更便宜…)?您的客户对价格有多敏感?
- 促销将说明你计划如何接触你的顾客:电视、广播、直接邮寄?联系他们的最佳时间是什么时候?市场有季节性吗?
另一个重要的概念是细分:将你的客户分成具有相似特征的不同群体。例如,根据消费金额,您可以将客户分为新和旧或大和小。一个经典的细分方法是 RFM,它使用 3 个维度对客户进行细分:最近(他们最后一次购买是什么时候?),频率(他们多久买一次?)和货币价值(他们的平均购买金额是多少?).这些通常是主观的概念,但是您也可以使用经典的聚类方法,例如 K-Means,来发现新的细分。然而,重要的是要理解,数据驱动的细分方法不一定比更主观的方法更好,最佳方法将取决于您的目标。
最后,你应该理解角色的概念。通过查看数据,您可以确定客户的平均年龄、收入以及主要的性别。然而,这些数字可能过于抽象,在创建产品功能或营销策略时没有用处。这就是为什么营销人员经常提到角色(角色的复数),这是一种将抽象概念转化为“真实人物”的具体方法。你不用称呼住在乡下、年龄在 50 到 60 岁之间的白人男子,而是创造一个角色:霍华德,55 岁,是住在德克萨斯州海恩斯维尔的退休消防员。当想象我们的市场将如何应对不同的策略时,它帮助我们避开统计抽象。
在试图用数据回答问题之前,这些概念可以帮助你框定你的问题,并将它们视为一个更广泛系统的一部分。
金融
照片由 Fabian Blank 在 Unsplash 上拍摄
财务的核心其实很简单:就是赚的钱比你花的多,理想情况下,能够推迟你的成本并预测你的收入。控制这两种流动的最好方法是记账。会计是一项相当古老的活动,被一些人认为不太性感。不过,在欺诈检测和收入预测等领域,它可以从数据科学中受益匪浅。
收入预测已经存在一段时间了,许多公司仍然使用过时的方法来预测他们明年会赚多少钱。这些信息非常有价值,因为企业用它来决定他们的预算:给每个部门或项目分配多少钱。尽管目前的方法很简单,但它们通常比更复杂的方法效果更好,因此在该领域仍有很大的改进空间。
几个关键概念是利润率、 加价和机会成本。
利润率=(收入-成本)/收入
因此,如果你有 10%的利润率,那么每 100 美元的销售额中,10 美元实际上会变成利润。利润率是你的收入中有多少实际上变成了利润。
加价=(价格-成本)/成本
公司有时使用加价来决定价格:例如,他们采用期望的 30%的加价,并应用于产品成本以得出最终价格。
机会成本是用你本来可以做的事情来衡量做某事的成本。想象一下,你在一家大公司担任经理,正在考虑攻读全日制 MBA 的可能性:这将产生与学费、书籍等相关的直接成本。,但这也会有机会成本,因为你将不得不停止工作一年或更长时间,并且在此期间不会有任何工资(也不会获得专业经验),这也应该在你做决定时加以考虑。企业也是如此:比如,想想持有现金。一家企业的现金越多,它就越能为销售下降或意外成本等困难时期做好准备。然而,当这笔钱作为现金持有时,公司就错过了将其投资于金融产品或企业本身的机会。即使把钱存在银行也有成本,即机会成本,所以公司在决定现金水平时必须考虑这种权衡。
由 Guillaume Bolduc 在 Unsplash 上拍摄的照片
操作
业务运营处理公司向客户交付价值所需的一切,包括优化生产、设备配置、人员配备等。
这里有很多优化,不一定是数据科学,但它肯定可以使用具有数学知识的人。这些部门通常会从流程和系统的角度考虑很多,他们希望确保流程尽可能平稳高效地运行。
这里一个有用的概念是精益方法,它起源于制造业,并以敏捷方法的形式扩展到软件开发。所以,你所知道的关于敏捷软件开发的一切,也可以应用到传统制造业中,不断迭代和改进。
另一种用于流程优化的著名方法是六适马。详细解释这一点超出了本文的范围,但是,一般来说,六适马是一组数据驱动的技术,用于通过减少过程输出的方差来改进过程,从而使过程更加可预测。它在 20 世纪 80 年代和 90 年代非常流行,其根源在于使用基本的统计方法来提高业务流程和运营的质量,因此数据科学家应该有兴趣阅读更多关于它的内容。
最后,从运营角度来看,另一个重要问题是库存水平。大多数企业都有某种库存,而库存通常伴随着一种权衡:你的库存越多,你对意外事件的准备就越充分,比如需求高峰。然而,保持过多的库存有一些成本,如存储成本本身(空间和维护)和机会成本(如上所述),因为用于过多库存的钱可以花在其他地方。
费利克斯·米特迈尔在 Unsplash 上的照片
战略
商业战略是一个高层次、广泛的主题,它包含了许多不同的概念和领域,很难概括。因此,让我们先了解一些关键概念,然后讨论它如何与数据科学相互作用。
商业战略通常被定义为“公司为达到特定目标的高层计划”,这是准确的,但相当模糊。从确定价格策略,到公司将试图征服哪些类型的业务,以及明年将试图进入哪些国家。然而,所有这些决策都应该源于公司的使命和愿景声明及其核心价值观。它的使命陈述是公司自身的存在理由,它陈述了公司为什么存在,它为谁服务,它的目的是什么。例如,看看 IBM 的使命声明:
“在创造、开发和制造行业最先进的信息技术方面处于领先地位,包括计算机系统、软件、网络系统、存储设备和微电子技术。我们遍布全球的 IBM 解决方案和服务专家网络将这些先进技术转化为客户的商业价值。我们通过全球范围内的专业解决方案、服务和咨询业务,将这些先进技术转化为客户价值。”
另一方面,一家公司的愿景声明定义了公司未来的目标,即它期望在未来几年内实现的目标。同样,这是 IBM 的愿景声明:
“成为世界上最成功、最重要的信息技术公司。成功帮助客户应用技术解决他们的问题。成功地向新客户介绍了这项非凡的技术。这很重要,因为我们将继续成为该行业大部分投资的基础资源。”
最后,公司的核心价值观提醒每个人什么对那个公司是重要的,以指导重要的决策。IBM 的价值观如下:
“多样性和包容性,创新,做你自己,关注变化.”
所有这三个概念都是在公司进行战略规划时定义的(通常在执行层面),但小企业也可以定义它们,通常首先在他们的商业计划中定义,这是企业家用来帮助他们在有商业想法时不仅定义他们的战略,还为每个商业领域规划布局,包括财务预测,以检查他们的想法是否实际可行。当一个企业家来要求贷款来开始他们的生意时,商业计划有时被银行要求。
然而,有些人认为商业计划是过时的工具,不能代表现实,尤其是对初创公司而言。对于小型科技公司来说,一个更受欢迎的工具(尽管目标不同)是 商业模型画布 ,它本质上是一个公司如何交付价值、向谁交付价值以及如何在财务上可行的图形表示。
为了做出战略决策,高管们可能需要大量数据,但通常情况下,这些数据并不复杂:他们很大程度上依赖于商业智能和简单的关键绩效指标(KPI),这些指标显示了业务的进展情况、有前景的市场、高绩效部门等。比起执行复杂的统计转换,选择正确的数字以及如何解释它们更重要(尽管这有时可能会导致错误)。
你现在如何应用你刚刚学到的东西?
这里介绍的概念可以帮助你更好地与公司的不同部门沟通,理解他们在说什么,也可以用他们能理解的术语更好地表达你的想法。通过更好地了解整个行业,他们还可以帮助你提出更好的想法。
最后,我希望它能激励你对商业或某些特定的主题做更多的研究。没有多少数据科学家从整体上理解业务,所以理解基础知识可以真正帮助你为公司创造价值。
更进一步
为了帮助你继续研究,这里列出了几本书,可以帮助你更详细地了解这里讨论的一些主题:
- 埃里克·里斯的《精益创业》
- 商业模式生成作者:Alexander Osterwalder 和 Yves Pigneur
- 乔希·考夫曼的个人 MBA 课程
- 迈克尔·波特的竞争战略
- 杰瑞米·大卫·丘鲁苏的《数据驱动:21 世纪管理咨询导论》
- 《商业预测交易:揭露神话,消除不良行为,提供切实可行的解决方案》迈克尔·吉利兰著
- 创业者的财商:你真正需要知道的数字
脑-机接口的商业应用&脑数据的重要性
非侵入性商用脑机接口和脑数据的挑战
Bret Kavanaugh 在 Unsplash 上拍摄的照片
人们经常想知道使用脑机接口能实现什么(BCI)。通过这篇文章,我觉得我可以帮助人们从商业角度更多地了解这项技术,这要归功于我的经验。事实上,在过去的六个月里,我一直在为运动员设计一款非侵入式商业 BCI。
在本文中,我将介绍主要的非侵入性和非医疗商业 BCI 应用,介绍大脑数据在新商业模式中的战略作用,提到该领域的领先公司,并分享我构建 BCI 原型的经验。
有创与无创脑机接口
在开始之前,我必须解释一些关于 BCI 的关键因素。
脑机接口被设计用来读取你的大脑电信号(思想、感觉等等)——有时通过脑电图(存在不同的方法)。
脑电图(EEG): 使用附着在头皮上的小电极检测你大脑中的电活动的监测方法。这项活动在脑电图记录中显示为波浪线。( 1
非侵入性和侵入性 BCIs 的主要区别。
侵入性 BCI“需要通过手术在头皮下植入电极来传递大脑信号”( 2 )。使用侵入式脑机接口,我们通常会得到更准确的结果。
然而,你可能会因手术而遭受副作用。不幸的是,手术后,可能会形成疤痕组织,使大脑信号变弱。而且,身体“可以排斥植入的电极”(3)。
最著名的入侵 BCI 可能是来自 Neuralink 的那个。
部分侵入性 BCI 装置也存在。通常,它们被植入颅骨内,但留在大脑外。从技术角度来看,“它们比非侵入性脑机接口产生更准确的结果,并且比侵入性脑机接口风险更低”( 4 )。
迄今为止,公众可用的大多数 BCI 应用程序都是非侵入性的。
为什么要开发商业脑机接口
首先,你要知道 BCI 并不是什么新鲜事物。事实上,科学家们从 20 世纪 70 年代到现在一直在为医学目的研究脑机接口。由于医疗领域的进步,这项技术“最近”进入了消费领域。
其他技术(人工智能、虚拟现实……)的发展也使公司对商业非侵入性脑机接口的研究具有战略意义(超越了显而易见的医疗领域)。因此,越来越多的初创公司和大型科技公司正试图开发非侵入性脑机接口。
BCIs 被视为战略性的原因各不相同。首先,它们代表了潜在的“下一个硬件接口” ( 5 )。
硬件接口
我们控制设备的方式即将迎来一场重大变革。在未来几年,用我们的大脑控制设备将成为常态。你可以想象,对于大型科技公司来说,开始准备他们的产品生态系统以适应未来的现实是很关键的。
与人工智能的协同
另一个战略要素是将人工智能和 BCI 结合起来,并借助它们创造独特的体验。人工智能已经在一些商业脑机接口中使用。机器学习(ML)可以用于实时分析和分类脑电波。这在“试图测量用户意图”( 6 )时非常有用。
ML 还有助于“将具有高度可变性和非平稳噪声的脑电活动解码成有意义的信号”( 7 )。在构建 BCI 应用程序时,ML 已经被证明是有用的。
此外,“EEG 数据集是高维的,具有大量参数的深度学习模型在直接学习生鸡蛋信号的背景下是有趣的”( 8 )。
结合人工智能和 BCI 可以创造新的机会,让用户体验全新的东西(竞争优势)。例如,BCIs 可以用来利用观众的大脑活动和生成敌对网络来创建新内容。
战略市场
**对于开发 BCI 解决方案的公司来说,一些市场可以迅速盈利。例如,营销/广告领域可以产生大量收入。**甚至尽管目前还没有为营销目的而设计的设备(如果我错了,请写信给我)或应用程序,但研究表明,BCIs 将与它们一起使用。
事实上,一些研究已经指出,BCIs 可以用来评估商业广告产生的注意力水平。可以肯定的是,许多公司都有兴趣为营销专业人士开发一种测量这一关键 KPI 的解决方案。
增强人类
脑机接口也具有战略意义,因为我们可以收集与人体相关的数据。这种收集战略数据的能力非常重要,因为我们已经进入了“人类扩增”的时代。
增强人类: 指提高人类生产力或能力,或以某种方式增加人体的技术。(9)
BCIs 将完善或取代智能手表等现有智能设备,并最终帮助我们实现更多目标。在接下来的几年里,我希望看到越来越多的初创公司参与构建能够分析用户情绪、帮助改善和集中注意力等的 BCI。
我们的项目:我目前正在从事一个项目,通过对大脑数据的分析,帮助运动员提高他们的身体表现。我们使用计算机视觉将这些数据与传感器和过去的表现结合起来。目标是更好地理解运动员对某些情况的反应,并帮助他们更好地管理他们的压力。经过几次测试后,我们已经开始研究一种非侵入式 BCI,它将帮助个人更好地了解他们的运动表现。
走向侵袭性脑机接口
我还认为,公司也有兴趣开发非侵入式 BCI 解决方案,将他们的品牌与这种技术联系起来,并迅速与客户建立信任。一旦入侵性 BCIs 成为主流,这种信任将成为战略。
大脑数据
也许公司投资 BCIs 的最大原因是大脑数据。如你所知,用 BCIs 监测大脑活动会产生大量信息。
的确,你的大脑会产生一种独特的脑电波模式,给你自己的个人神经指纹。你对一些视觉元素的反应方式,你的睡眠和注意力数据等。所有这些都可以被捕获并出售给其他公司。
谁拥有大脑数据,它的用途是什么?
拥有最多大脑数据的公司可能会比其他公司拥有显著的竞争优势。想象一下数据网络效应的影响,但应用于 BCI 和大脑数据…
此外,获得某人的大脑数据可以加强锁定效应。例如,你的大脑数据可以被记录并用于个人识别系统。这个简单的“功能”可以加强您与 BCI 制造商的关系。
谁拥有大脑数据,它的用途是什么?
为商业目的构建 BCIs 的挑战
您可能知道,商业非侵入性 BCI 市场仍处于起步阶段。出于这个原因,公司仍在努力寻找最佳的方法和方法论。
**在我看来,我们还需要 2 到 3 年才能看到 BCIs 变得更加主流。**根据一些行业专家的说法,主要的挑战是“找到仍能从 BCIs 早期迭代中受益的中间市场”( 10 )。
创建易于使用、可访问、直观、安全且具有良好准确性的脑机接口仍然是一个重大挑战。
设备
这种设备本身就是一个重大挑战(昂贵、难以操作、可能很重、不够谨慎等等)。一些公司正在探索开发与监控脑电活动的耳塞耳机整合的传感器的想法。此外,每个人都有大量的校准工作要做…我们距离像智能手机一样直观的设备还很远。
展示有用性
在一些使用案例中,很难说服客户购买 BCI。人们真的会关心用戴着特定设备的大脑来控制设备吗?答案不是那么明显。
例如,在灯光控制的情况下,你也可以只使用遥控器。我希望看到越来越多的初创公司转向寻找最佳用例。由于需要大量的技术开发和资金,这种必要性对 BCI 的初创企业来说是一个重大风险。
也很难为 BCI 解决方案找到合适的价格。对 BCI 公司来说,在生产成本和零售价格之间找到合适的平衡点并非易事。
绕轴旋转
几家 BCI 公司已经考虑转向(从脑机接口转向可穿戴设备)。事实上,睡眠监测等一些商业应用已经代表了一个拥挤的市场。从短期来看,为 BCI 玩家找到相关且独特的中介应用至关重要。
脑电图
BCI 解决方案的另一个值得一提的潜在问题与脑电图数据有关。对于非侵入性脑机接口,“电极和大脑之间的头骨和组织导致信号更弱,信息传递更慢”( 11 )。显然,这限制了用户控制设备的能力。研究人员正试图克服这些限制,以提高脑电图在医疗和非医疗应用中的效用。
在某些情况下,用户基本上必须进入“冥想状态以实现对大脑调制的控制”( 12 ),这可以允许控制设备。最后,目前的非侵入式脑机接口往往需要强化训练。
生态系统
就像 AIoT 战略一样,我认为 BCI 公司面临的主要挑战之一将是整合由其他公司的解决方案组成的生态系统。如果明天,大型科技公司决定建立只适用于某些产品的 BCI,创业公司将很难与之竞争。
最终,BCIs 可以强化锁定效应。
BCIs 将在智能家居行业发挥重要作用,并有可能在长期内取代智能手机。我担心非侵入性的 BCI 产业或多或少会像智能手机产业一样(寡头垄断)。
BCI 在智能环境领域的应用不仅限于家庭。还有为工作场所或汽车行业设计的开发项目。由于这些原因,我担心我们的市场会有一些 BCI 设备和其他公司制造的许多不同的“应用程序”。
规章制度
不知何故,该行业在哪些设备符合 BCI(消费者端)标准方面缺乏清晰度。此外,大脑数据的问题仍然不清楚。我们可以出售大脑数据吗?我们是否必须遵守某些规则,例如 GDPR?如果 BCI 被黑了会怎么样?…
谈到医疗设备,“食品药品监督管理局监管一切——包括一些 BCI。然而,一些 BCI 不被归类为医疗器械,而是直接销售给消费市场”( 13 )。
潜在的非侵入性和非医疗商业 BCI 应用列表
下面,我列出了最常见的非侵入性和非医疗 BCI 应用。
【BCIs 能做什么?
目前,商业脑机接口往往侧重于理解你的情绪状态或你打算做出哪些动作。正如 Jo Best 所提到的那样,“当某人在想‘是’或‘不是’时,BCI 可以感知,但探测更具体的想法仍然超出了大多数商用脑机接口的范围。”( 14 )
而且,“大多数商业 BCI 只能解读你的想法,而不能把任何想法植入用户的头脑。然而,围绕人们如何通过脑机接口进行交流的实验工作已经开始。我们可以想象,很快我们将能够通过分享大脑的神经活动来与远方的人分享经验。
对于 BCI 技术来说,现在还为时尚早,但我们已经看到了有希望的结果。
非侵入式脑机接口的不同应用和研究包括:
- 睡眠模式分析
- 疲劳和脑力负荷分析。
- 情绪检测。例如,“一个监控用户大脑的系统,根据温度、湿度、照明和其他因素相应地调整空间。”( 16 ) 近日,日产与 Bitbrain 合作,展示了首款 脑车接口 原型车。
- 情绪分析
- 控制装置(机械臂等)。)
- 利用脑电波的个人识别系统。
- 利用经颅直接刺激增加身体动作和反应时间。
- **职场分析/生产力最大化。**例如,有项目开发一个应用程序来分析操作员的认知状态,精神疲劳和压力水平。
- **营销领域:**在这个领域,“有研究指出,脑电图可以用来评估不同媒体的商业和政治广告产生的关注度。脑机接口技术还可以提供对这些广告记忆的洞察。( 17 )一般来说,“BCIs 可以用来优化互联网广告或电视插播广告”( 18 )。
- **教育领域:**在这个领域,“BCIs 可以帮助识别每个学生学习信息的清晰程度,允许教师根据结果个性化他们与每个学生的互动”( 19 )。
- 娱乐领域:在这个领域中,脑机接口可以用于视频游戏。例如,玩家可以只用一个 BCI 来控制他们的化身。就电影而言,BCIs 可以利用观众的大脑活动来帮助创作互动电影。”在未来,“未来的观众将能够沉浸其中,并通过他们的联合大脑活动来集体控制一部电影”。
- **军事领域:**在这个领域“在国防高级研究计划局(DARPA),BCI 已经被士兵们用来驾驶一群无人机”( 22 )。
致力于商业非侵入性 BCI 的公司
下面,我试图列出一些目前正在研究非侵入性、非医疗商业脑机接口的公司。如果你知道更多的公司,不要犹豫,联系我,我会把他们加入名单。
脸书
脸书据报道以 10 亿美元收购了 BCI 公司 CTRL-labs。脸书正在进行几个项目。其中一个与翻译思想有关。第二个是关于解释某人想要单独从他们的大脑信号做出的动作。
Neurable Neurable 专注于创造“日常”的脑机接口。
NextMind NextMind,做了一个“非侵入性的神经接口,它坐在一个人的后脑勺上,将脑电波翻译成可以用来控制兼容软件的数据”( 23 )。
其他公司:
- 轨道基
- 顺行学
- Thync
- NeuroSky
- Emotiv
- 交互轴
对于 BCI 技术来说,现在还为时尚早,但结果是有希望的。然而,“这一开创性领域的科学家明确表示,我们甚至还没有触及脑机接口潜在应用的表面(BCI)”(24)。