TowardsDataScience-博客中文翻译-2021-七十六-
TowardsDataScience 博客中文翻译 2021(七十六)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
负责任的人工智能在行动
原文:https://towardsdatascience.com/responsible-ai-in-action-2099be088321?source=collection_archive---------27-----------------------
人工智能校准和安全,值得信赖的人工智能
负责任的人工智能的市场驱动因素、框架和实用建议

谨慎前进——图片来源:奥利维尔·佩内尔
随着人工智能(AI)在社会各个方面的兴起,伦理被证明是技术的新前沿。公众意识、媒体审查和即将出台的法规正在要求组织和数据科学界将道德原则嵌入到他们的人工智能计划中。Gartner 将“更智能、负责任和可扩展的人工智能”确定为 2021 年数据和分析的 #1 市场趋势。你可能也知道欧盟委员会在 2021 年 4 月发布的法规提案。这不仅仅是欧盟监管狂热的又一个例子。世界各地的许多政府都在努力为人工智能制定类似的监管框架。
问题应该是用于训练机器学习模型的数据的适用性,放大人类偏见和歧视的风险,用算法做出的预测和决策的可解释性,以及人工智能应用程序的公平性和透明度的人类监督。除了更大的利益和社会责任,利害攸关的是人工智能技术的成功采用,否则,这些技术有可能为组织和整个社会带来巨大的价值。
在本文中,我将介绍:
- 推动对负责任的人工智能的需求的市场力量,
- 负责任的人工智能原则框架,
- 将负责任的人工智能付诸实践的 5 条建议。
负责任人工智能的市场力量
在我最近与 EMEA 各地组织的互动中,我观察到所提问题类型的转变。人们一直非常关注实验,探索新技术,并试图定义创新的用例。随着意识和成熟度的提高,问题现在变成了:“我如何有效地、大规模地、负责任地使用人工智能来实现切实的业务成果?”。
我今天在市场上看到的是 3 股力量的汇聚:加速、委托和放大。

在 Unsplash 上由 Patrick 拍摄的照片
加速
可用数据、存储和计算能力的指数级增长使得加速成为可能。在过去的 18 个月里,COVID 危机加剧了这种加速。来自麦肯锡的最近的一项调查显示,对新冠肺炎危机的回应已经将数字技术的采用速度加快了几年,而且这些变化中的许多可能会长期存在。这不仅仅是能够在家工作。组织已经意识到,他们需要能够依靠他们的分析和数字服务来建立弹性、竞争力并在不确定的时代生存下来。
这种加速也是由我称之为“即时暴政”和消费者对即时访问在线服务的需求所驱动的。就像孩子一样,我们什么都想要,现在就想要!消费者有一个明确的期望,那就是产品、服务、信息,所有的一切,都应该可以在网上即时获得。我不得不承认我自己也有同感。在一天结束的时候,谁想回到买东西的时候,你不得不货比三家。谁想回到获得贷款的时候,你必须去你的银行的一个分支机构,与一个人交谈,填写一些表格,然后等待 3 周(如果你幸运的话)得到答复?
人工智能被广泛视为一种竞争优势。如果 A 银行不能立即批准我的贷款,我就直接问 b 银行。如果我想买的产品明天不能通过网上零售商 X 发货,我就从网上零售商 y 那里买。

照片由奥斯汀·尼尔在 Unsplash 上拍摄
委托
令我印象深刻的第二个方面是,我们准备将多少决策委托给机器人或算法。
让我们以股票市场交易为例。今天,股票市场上大约 85%的交易是由算法自动完成的,没有人类的干预。当这对交易员、投资银行和对冲基金来说既方便又有利可图时,我们知道,事实上,这可能会加剧股市崩盘,给个人的生活和财富带来现实后果。这就提出了自动交易算法的责任和可解释性的问题。
这是一个极端的例子,但我们现在期望计算机为我们做出如此多的决定:当我们在网上搜索某些东西时获得的信息,从 A 到 B 的方向,交通灯、飞机和核反应堆的操作,保护我们的银行账户免受欺诈者的侵害,等等。
我们似乎盲目相信算法做出正确决定的能力。在某种程度上,算法在某些事情上比人类好得多,比如处理大量数据以识别模式并做出预测。但是他们缺乏常识、文化和背景。他们只是从提供给他们的数据中学习。它们可能非常有效,但也非常狭隘,导致人工智能系统做出技术上正确但社会上不可接受的预测或决定。
我们看到人工智能应用不断扩展,有时会取代人类代表我们做决定,这提出了一些问题,例如:
- 我们能信任他们吗?
- 什么样的标准和道德规范被用来做这些决定?
- 谁对所做的决定负责?错误的决定会有什么后果?
- 为什么算法不应该分享类似的道德准则和标准,并像人类一样面对错误决策的后果?(对于算法而言,这将导致重新训练、重建或退役)。

桑迪·卡瓦德卡尔在 Unsplash 上拍摄的照片
扩大
放大 AI 应用能实现多少,眨眼之间能做多少决定。问题是…我们知道算法有时会做出糟糕的预测,而这些糟糕的预测会导致糟糕的决策,对现实世界产生真正的影响。
个人做出糟糕或不公平的决定是一回事。但是算法是大规模实时决策的,所以错误决策的后果会很快变得更严重。实际上,人工智能就像一个放大器或者是一个回音室。人工智能系统的覆盖范围要大数百万倍。因此,无论我们是否意识到,我们大脑中存在的偏见,以及现实世界中存在的歧视,无论我们喜欢与否,都被人工智能应用放大了。

马特·切辛在 Unsplash 上的照片
反应过度?
这些担忧是完全合理的,但无助于失败的人工智能系统在媒体上的铺天盖地的报道。新闻上到处都是。这些备受瞩目的案件没有一天不成为头条新闻。杀手机器人的幻想对记者来说是非常好的材料,但它加剧了公众和决策者的恐惧,他们不想犯这些错误,损害他们的品牌。
某种程度上,这是可以理解的。公众意识和监管者正在赶上一段时间以来未受抑制的技术创新。有些人已经决定亲自解决这个问题,并采取一些措施。有无数的倡议和团体决心解决这一问题,提高对这一问题的认识,制定指导方针和最佳做法,并向立法者提出挑战。
我最近看了一部名为“编码偏见的纪录片,揭示了面部识别等人工智能技术的某些使用中的歧视和缺乏透明度。尽管这部纪录片为围绕人工智能使用的伦理问题提供了一个颇具启发性的视角,但它完全错过了人工智能对社会也有好处的反驳论点。让我们不要忘记人工智能能够并确实为个人、社会和环境带来的巨大好处,例如,通过帮助保护亚马逊雨林或濒危物种,提供更多见解以帮助医生更早地做出正确的诊断,解决虐待儿童、无家可归和精神卫生保健等问题。
问题是:所有这些美好都被像这个故事这样高度宣传的案例所掩盖,你可能听说过:微软 2016 年在 Twitter 上发布的 Tay chatter bot。在短短 16 个小时内,聊天机器人从说“人类超级酷”到发布种族主义、性攻击和各种非常冒犯的评论。事实是,Tay 正在从 Twitter 上与它互动的人那里学习,他们显然很喜欢向它扔可怕的东西。当 Tay 回应某人说“你是一台愚蠢的机器”时,他说“好吧,我向最好的人学习,如果你不明白,让我给你解释一下:我向你学习,你也是愚蠢的”。这只是人工智能出错的一个有趣例子,但对于微软和其他公司的数据科学家来说,这也是一次很好的学习经历,了解了对机器学习算法的数据进行监督的必要性,以及人工智能应用程序输出的问责制问题。
创新的障碍?
这些被高度宣传的案例产生了积极的影响,提高了人们对事情可能出错的认识,但它们也引起了决策者的担忧。这些担忧甚至减缓了人工智能技术的采用和推广。根据德勤最近的一项研究,95%的受访高管表示,他们担心人工智能采用中的道德风险——担心损害他们的品牌,担心降低客户、合作伙伴和员工对品牌的信任。以至于其中 56%的人放慢了他们采用人工智能的速度。
尽管如此,人工智能仍然是加速数字化转型、发展市场差异化和竞争优势的关键。这是一场比赛,成功主要是通过力量和速度来衡量的,这意味着道德考虑往往是事后的想法,被视为监管或责任问题。

劳拉·古德塞尔在 Unsplash 上的照片
业务需求
是时候平衡这两个看似对立的世界了。一方面,我们有道德和更大的利益。另一边:创新和利润。
道德和商业之间的这种紧张关系只是表面现象。负责任的 AI 其实对商业是有好处的。负责任的人工智能是关于信任的,它正在成为一种商业需求,是数字化转型的一个关键成功因素。
组织关心负责任的人工智能有各种原因:
- 在大多数情况下,它是关于建立用户采用人工智能应用程序所需的信任,从而确保这些应用程序的预期价值。例如,我最近与一个组织合作,该组织开发了一个预测模型,帮助销售团队将精力集中在最有可能成功的销售机会上,从而用同样的资源增加收入。但是由于模型的内部工作缺乏透明度,因此对正在做出的预测缺乏信任,大多数销售人员倾向于忽略它,而只是利用他们的直觉来优先考虑他们的工作。结果,被数据科学和 IT 团队设计成黑匣子的 AI 系统从未被业务采用,价值从未实现。
- 组织也使用负责任的人工智能作为将自己与竞争对手区分开来的一种方式。就像咖啡品牌宣传公平贸易商业行为一样,负责任的人工智能正在成为一种营销标签,旨在为品牌带来积极的影响。因为大多数消费者热衷于做正确的事情,他们将倾向于更好地信任那些能够展示其道德价值观和负责任地使用人工智能的公司,并与之做生意。有些人甚至把负责任的 AI 称为“新绿”。以同样的方式,每个人都想拯救地球,每个人也想实施并被视为实施负责任的人工智能。
- 风险缓解也是负责任人工智能的重要驱动力。降低负面宣传的风险,例如当使用人工智能应用程序导致歧视时,或者愤怒的客户询问他们的数据是如何使用的,为什么他们的贷款申请被拒绝,或者为什么他们的保险单得到不同的报价。
- 最后是关于合规。符合利益相关者对道德商业实践的要求。符合现有和未来的法规。这将成为组织做好准备和避免高额罚款的首要任务。
负责任的人工智能框架

查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
可靠的计算器
那么,什么是负责任的人工智能呢?我先说,没有“负责任的 AI ”这种东西。同样,也不存在负责任的计算器这种东西。如果我在纳税申报表中错误地申报了比我应该申报的少的收入,我们能责怪我为此使用的计算器吗?我们能说它的行为不负责吗?我希望我们可以,但是不行。这是我使用计算器的过错。这就是为什么我认为我们应该谈论“负责任地使用人工智能”而不是“负责任的人工智能”。公平地说,这个计算器和一个典型的人工智能系统的不同之处在于,有了这个计算器,我就可以根据我输入的数字和我选择的操作提供明确的指令。我没有要求计算器从以前的计算中学习并预测一个结果。
负责任的人工智能原则
那么负责任地开发和使用一个 AI 系统意味着什么呢?在过去的几年中,已经开发了许多原则和框架,在我看来,它们都或多或少是相同的。所以,这是我对这些原则的看法:

作者图片
以人为中心
- 提供与用户有意义的互动,例如使用自然语言来理解人工智能系统,即使是非专业人士也能理解。
- 建立一些人工监督,通过清晰的流程来审查人工智能系统的影响,或者对个人决定提出上诉。
负责
- 一个具有明确角色和责任的治理框架,提供了关于谁对人工智能系统所做的预测和决策负责的清晰性。
- 为所有参与充分培训的人员提供安全措施和指导原则。
公平&公正
- 人工智能系统不应该区分不同类别的人。应该主动监控用于训练模型的数据中的偏差、对不同人群评分的模型输出中的偏差,以及使用这些模型做出的决策的公平性。
- 毫无疑问,所有数据集都有偏差,但这是可以检测和缓解的。数据应该代表模型将要应用的人群。
- 如果你想赢得一场足球比赛,你不想雇佣一个 11 个守门员的团队。技能和背景的多样性将确保你设计的人工智能系统不仅有效,而且对每个人都公平。
透明&可解释
您应该能够回答简单的问题,例如:
- 用什么数据来训练一个模型?
- 模型的内部工作、属性和相互关系是如何被了解和记录的?
- 什么变量对特定的预测产生了积极或消极的影响?
- 什么样的规则/逻辑与预测一起被用来推动特定的决策?
稳健&可靠
- 你的人工智能系统应该产生一致和可靠的输出。
- 您的模型的部署应该是自动化的,以避免容易出错的手动活动。
- 生产中的模型应该被主动监控,不仅是为了准确性,也是为了公平性,而且应该有一些适当的流程,以便在需要时重新培训、重建或淘汰模型。
安全&安全
您的人工智能系统应该受到保护,免受可能导致物理或数字伤害的潜在风险(包括网络威胁)。
顺从
它应符合关键法规,尤其是隐私方面的法规(欧盟 GDPR),即个人能够决定是否共享其数据,不使用超出其预期和声明用途的客户数据等。
伦理
最后,它应该是道德的。道德对不同的人或在不同的国家可能有不同的含义。所以我所说的道德人工智能是指遵守特定道德准则的能力,这取决于负责人工智能系统的组织的价值,人工智能系统使用的国家和行业。它通常包括人权、社会福祉和可持续性。
5 将负责任的人工智能付诸行动的考虑
很难论证负责任的人工智能原则的好处。把它们转化为行动是另一回事。当你希望在你的组织中实施负责任的人工智能原则时,我想提出以下五条建议。

照片由 Gia Oris 在 Unsplash 上拍摄
1.将原则融入语境
一旦你定义了自己版本的负责任的人工智能原则,符合你的组织的价值观和优先事项,第一个挑战将是把这些原则转化为实际的指导方针,可以传达给所有参与开发和部署人工智能解决方案的人。之所以需要将这些原则放在上下文中,是因为单一的原则可能不会以相同的方式应用,这取决于您所在的行业、部署解决方案的国家、您自己组织的文化以及人工智能应用程序的预期用途。例如:
- 在医疗保健中使用性别变量可能对支持医疗状况的分析和诊断至关重要,但使用性别来批准贷款通常是不可接受的。
- 在网站上提出下一个最佳报价所需的透明度与其他事情所需的透明度不同,例如在招聘过程中筛选简历,或在社会福利申请中标记潜在的欺诈行为,或计算已定罪罪犯再次犯罪的可能性。
- 用于天气预报的人工智能系统所需的安全级别与处理高度敏感或个人数据或军事应用不同。
原则需要转化为具体的指导方针,并且需要建立一些方法来评估道德影响和所涉及的风险。
2.将负责任的人工智能嵌入到您的数据和分析战略中
第二个建议是避免将负责任的人工智能单独作为一个话题来处理。负责任的人工智能不能脱离你的数据和分析战略,你应该寻求将负责任的人工智能原则嵌入到你现有的数字化转型计划中。
谁应该拥有负责任的人工智能?目前有一个新的职业被称为“人工智能伦理学家”的炒作,在纸面上,这是某种独角兽,能够掌握大量的人工智能工具和技术,有足够的经验来了解业务和行业,能够识别其中存在的特定人工智能道德陷阱,具有出色的沟通技巧和跨组织边界工作的能力,拥有广泛的监管,法律和政策知识等...
实际上,你几乎肯定找不到。
好消息是,你并不真的需要一个团队,因为在团队中,不同的人可以发挥他们的特殊技能,多元化可以防止个人偏见。
虽然你可能不需要人工智能伦理学家,但你可能应该考虑任命一个小团队来领导这项工作,在人工智能生命周期的每个阶段跨部门协调负责任的人工智能原则的可操作性。
我还建议这个团队应该尽可能向贵组织业务部门的最高层汇报。IT 和分析团队都有一定程度的利益冲突,可能不适合承担这一职责。
一些你绝对要避免的陷阱:
- 在法律部门建立所有权,这将使负责任的 AI 成为纯粹的合规和责任问题。
- 让数据科学家成为负责任的人工智能需求的唯一守护者或管理者。数据科学家在设计和开发透明、可解释和可部署的预测模型方面发挥着作用,但他们只拥有端到端人工智能生命周期的一小部分。
一些人认为数据科学应该成为一个受监管的职业,或者数据科学家应该做出某种誓言,类似于医生的希波克拉底誓言。虽然我可以看到这背后的合理意图,但我不确定这是否可行,我认为这是通过数据科学的唯一镜头来看待负责任的人工智能,而事实上这是一个更广泛的问题。
3.在人工智能生命周期的每个阶段注入负责任的人工智能原则
正如我刚才讨论的那样,数据科学只是端到端人工智能生命周期的一部分,你应该在每一步都注入负责任的人工智能原则,从一开始一直到最后,都要有适当的清单和保障措施。
从你的人工智能系统的初始和设计开始。应该评估伦理风险。应定义缓解措施和成功标准。
在数据收集期间,应收集个人的明确同意以使用其数据,并且应保护敏感属性。您仍然希望收集一些个人和/或敏感数据,以便稍后可以测量和减轻与这些变量相关的偏差。
在存储数据时,应标记敏感变量,并将同意信息与数据一起存储。
在数据准备和分析期间,应评估偏差,训练数据应适合工作,即代表算法设计用于的人群。您可能希望考虑使用合成数据来保护隐私,并使数据集更加多样化,以减少训练数据中的偏差。
在建模和测试期间,有一些明显的事情要围绕代码文档做,并使用可解释性算法技术,如 PD、ICE、LIME 和 SHAP,但我的主要建议是尽可能保持事情简单。机器学习不是一切的答案,你需要平衡一方面对准确性的需求,另一方面对透明性/可解释性的需求。使用机器学习的增量优势有时不值得努力构建和部署这些模型,也不值得在可解释性方面进行权衡。所以,当一个简单的线性回归足够好的时候,就去做吧!
在您的分析模型和 AI 应用程序的部署期间,关键是使用自动化、可预测和可重复的流程,例如使用 CI/CD(持续集成/持续交付)管道。在整个过程中还必须捕获血统信息,这样您就能够跟踪哪些数据用于训练模型,哪些模型用于进行预测,预测如何与一些业务逻辑一起用于决策,以及该决策的结果和影响是什么。
一旦一个人工智能应用程序投入生产,就假设它是有偏见的,然后试图证明它是错误的。您需要主动监控模型输出和决策中的偏差,建立一个 KPI 系统,并以利益相关者能够理解的方式传达给他们,并建立一些偏差和公平性仪表板。
4.利用您的模型操作框架
根据您在分析方面的进步程度,您可能已经达到了这样一个点,即挑战不再是探索可能性领域和试验新技术,而是现在要操作您的分析,将分析洞察力或预测模型的输出带入生产,在业务的第一线采取行动、做出决策和实现业务成果。
为了有效地做到这一点,您需要将端到端生命周期工业化,加快部署流程,并在一个受治理的环境中产生可靠和一致的输出,以最终将分析驱动的决策扩展为您数字化转型的一部分。实现这一点的方法被称为 ModelOps(或 MLOps),它涉及到为人工智能实现一个正式的治理模型,以及自动化部署和监控流程。
有趣的是,相同的治理框架及其底层功能也有可能支持负责任的人工智能的许多要求。实际上,有了 ModelOps,你可以一石三鸟,如果你允许我这样表达的话。你可以扩展你的分析,你可以操作你的分析,你可以负责任地做。
5.不要等待,从今天开始!
我最后的建议是不要等待。不要等法规生效。实施负责任的人工智能原则不能事后才想到。将它们改造成现有的人工智能应用程序将比从一开始就将它们嵌入其中花费更多,因为你可能需要重建一切,并面临一场改变行为和流程的艰苦战斗。
总结…
我希望到现在为止,你已经很好地理解了什么是负责任的人工智能,以及它为什么重要,不仅是为了做正确的事情,也是为了确保业务成果。这是关于建立成功采用人工智能系统并实现预期价值所需的信任。
负责任的人工智能的原则是众所周知的,但你需要将它们融入到你的行业和具体的道德要求中,将这些原则嵌入到你的数据和分析战略中,利用现有的治理框架,如 ModelOps,并在你的人工智能生命周期的每个阶段注入负责任的人工智能要求。
在我的下一篇文章中,我将更详细地介绍实现负责任的人工智能原则的实际方面,以及你应该考虑的能力,以使你自己获得负责任的人工智能的最佳成功机会。
感谢您的阅读。期待大家的评论!
具有错误分析的负责任的机器学习
原文:https://towardsdatascience.com/responsible-machine-learning-with-error-analysis-a7553f649915?source=collection_archive---------8-----------------------
了解如何识别和诊断机器学习中的错误

(图片作者)
概观
网址: ErrorAnalysis.ai
Github 资源库:https://github.com/microsoft/responsible-ai-widgets/
在现实世界中部署模型的机器学习(ML)团队经常面临对 ML 模型进行严格的性能评估和测试的挑战。我们有多频繁地读到诸如“模型 X 在给定的基准上有 90%”的断言,并且想知道,这个断言对于模型的实际使用意味着什么?在实践中,团队很清楚模型的准确性在数据的子组之间可能不一致,并且可能存在模型更经常失败的输入条件。通常,这种失败可能会导致与缺乏可靠性和安全性、不公平或更广泛地对机器学习缺乏信任相关的直接后果。例如,当交通标志检测器在某些日光条件下或对于意外输入运行不良时,即使模型的整体精度可能很高,开发团队提前了解模型在这种情况下可能不可靠的事实仍然很重要。

图 1 — 错误分析脱离了总体准确性指标,以透明的方式向开发人员公开了错误的分布,使他们能够有效地识别&诊断错误。(图片作者)
虽然当前的模型评估实践存在几个问题,但是最明显的一个问题是在整个基准上使用聚合度量来对模型进行评分。很难用一个单一的数字来传达一个关于模特行为的详细故事,然而大多数研究和排行榜都是基于单一的分数。同时,可能存在输入特征空间的几个维度,从业者可能有兴趣深入研究并提出诸如“当外面黑暗并下雪时,自动驾驶汽车中的识别模型的准确性会发生什么变化?"或"贷款审批模型在不同种族、性别、年龄和教育背景的人群中表现相似吗?”。沿着如上所述的多个潜在维度在失败的领域中导航是具有挑战性的。此外,从长远来看,当模型根据新的数据证据或科学进步频繁更新和重新部署时,团队还需要持续跟踪和监控模型行为,以便更新不会引入新的错误,从而破坏用户信任。
为了解决这些问题,从业者通常不得不创建定制的基础设施,这既繁琐又耗时。为了加速严格的 ML 开发,在这篇博客中,你将学习如何使用错误分析工具来:
1)深入了解模型的故障分布情况。
2)用主动数据探索和可解释性技术调试 ML 错误。
错误分析工具包集成在负责任的 AI 部件 OSS 库中,这是我们向开源社区和 ML 从业者提供一套集成工具的起点。不仅是对 OSS RAI 社区的贡献,从业者还可以在 Azure 机器学习中利用这些评估工具,包括fair learn&interpret ml和 2021 年年中的 now Error Analysis。
如果您有兴趣了解更多关于通过最小化回归和新错误来保持向后兼容先前自我的训练模型更新,您也可以查看我们最新的开源库和工具 BackwardCompatibilityML 。
先决条件
要安装负责任的 AI Widgets“raiwidgets”包,只需在您的 python 环境中运行以下命令,从 pypi 安装 rai Widgets 包。如果您还没有安装 interpret-community,您还需要安装它来支持模型解释的生成。
pip install interpret-community
pip install raiwidgets
或者,您也可以克隆开源存储库并从头开始构建代码:
git clone https://github.com/microsoft/responsible-ai-widgets.git
您需要安装 yarn 和 node 来构建可视化代码,然后您可以运行:
yarn install
yarn buildall
并从 raiwidgets 文件夹本地安装:
cd raiwidgets
pip install –e .
更多信息请参见投稿指南。
如果您打算运行存储库测试,在存储库的 raiwidgets 文件夹中运行:
pip install -r requirements.txt
入门指南
本文通过对收入预测(> 50K,<50K). The model under inspection will be trained using the tabular UCI 人口普查收入数据集)使用二元分类任务来说明错误分析工具,该数据集包含数字和分类特征,如年龄、教育程度、工作时间、种族等。
我们可以使用下面的 API 调用错误分析仪表板,它接收由来自解释社区存储库、模型或管道、数据集和相应标签(true_y 参数)的解释器之一计算的解释对象:
ErrorAnalysisDashboard(global_explanation, model, dataset=x_test, true_y=y_test)
对于较大的数据集,我们可以将解释下采样到较少的行,但对整个数据集运行误差分析。我们可以提供缩减采样解释、模型或管道、完整数据集,然后提供采样解释和完整数据集的标签,以及(可选)分类特征的名称:
ErrorAnalysisDashboard(global_explanation, model, dataset=X_test_original_full,true_y=y_test, categorical_features=categorical_features, true_y_dataset=y_test_full)
下面所有的截图都是使用 LGBMClassifier 和三个估值器生成的。您可以使用我们库中的 jupyter 笔记本直接运行这个例子。
错误分析如何工作
1.识别
错误分析从识别与总体基准错误率相比具有较高错误率的数据群组开始。仪表板允许通过使用错误热图或由错误引导的决策树来进行错误探索。
用于错误识别的错误热图
该视图基于输入要素的一维或二维格网对数据进行切片。用户可以选择感兴趣的输入要素进行分析。热图以较暗的红色显示误差较大的单元格,以将用户的注意力吸引到误差差异较大的区域。这是有益的,尤其是当不同分区中的错误主题不同时,这在实践中经常发生。在这个错误识别视图中,分析主要由用户和他们的知识或假设来指导,这些知识或假设是理解失败最重要的特征。

图 2 — 虽然数据集的总体错误率为 23.65%,但热图显示,对于受过高等教育的个人,错误率明显更高,高达 83%。男性的错误率也高于女性。 ( 图片作者)
错误识别决策树
通常,错误模式可能很复杂,涉及不止一个或两个特征。因此,开发人员可能很难探索所有可能的功能组合,以发现具有严重故障的隐藏数据袋。为了减轻负担,二叉树可视化自动将基准数据划分为可解释的子组,这些子组具有出乎意料的高或低的错误率。换句话说,该树利用输入特征最大限度地将模型错误与成功分开。对于定义数据子组的每个节点,用户可以调查以下信息:
- 错误率 —模型不正确的节点中的一部分实例。这通过红色的强度显示出来。
- 错误覆盖范围 —落入节点的所有错误的一部分。这通过节点的填充率来显示。
- 数据表示 —节点中实例的数量。这通过节点的传入边的厚度以及节点中实例的实际总数来显示。

图 3 —旨在通过分离数据中的错误实例和成功实例来发现失败模式的决策树。这里的分层误差模式表明,尽管数据集的总体误差率为 23.65%,但对于已婚、资本收益高于 4401 英镑、受教育年限高于 12 年的个人,误差率可能高达 96.77%。 ( 图片作者)
群组定义和操作
为了使分析专门化并允许深入研究,可以为任何数据群组而不仅仅是整个基准生成两个错误识别视图。群组是数据的子群组,如果用户希望回到那些群组用于将来的调查,他们可以选择保存这些子群组以供以后使用。可以从热图或树中交互式地定义和操作它们。它们也可以被带到下一个关于数据探索和模型解释的诊断视图中。

图 4——创建一个新的队列进行进一步调查,重点关注已婚且资本利得低于 4401 的个人。 ( 图片作者)
2.诊断
在识别具有较高错误率的群组之后,错误分析使得能够进一步调试和探索这些群组。然后,通过数据探索和模型可解释性,就有可能获得关于模型或数据的更深入的见解。
调试数据
数据浏览器:用户可以通过沿着数据浏览器的两个轴选择不同的特性和估计器来探索数据集的统计和分布。他们可以进一步将子组数据统计与其他子组或整体基准数据进行比较。例如,该视图可以揭示某些群组是否代表性不足,或者它们的特征分布是否与总体数据显著不同,从而暗示可能存在异常值或异常协变量偏移。

图 5 — 在图 1 和图 2 中,我们发现,对于受教育年限越长的个体,该模型的失败率越高。当我们查看数据在特征“education_num”中的分布时,我们可以看到 a)受教育超过 12 年的个人的实例较少,b)对于该群组,低收入( 蓝色 )和高收入( 橙色 )之间的分布与其他群组非常不同。事实上,对于这个群体来说,收入高于 5 万英镑的人更多,这与总体数据不符。 ( 图片作者)
实例视图:除了数据统计之外,有时仅仅观察原始数据以及表格或平铺形式的标签是有用的。实例视图提供此功能,并将实例分为正确和不正确的选项卡。通过目测数据,开发人员可以识别与缺失特征或标签噪声相关的潜在问题。
调试模型
模型可解释性是提取关于模型如何工作的知识的强大手段。为了提取这些知识,错误分析依赖于微软的 InterpretML 仪表板和库。该库是 Rich Caruana、Paul Koch、Harsha Nori 和 Sam Jenkins 在 ML 可解释性方面的突出贡献。
全球解说
特征重要性:用户可以探索影响所选数据子组或群组的整体模型预测(也称为全局解释)的前 K 个重要特征。他们还可以并排比较不同群组的特征重要性值。关于特征重要性或排序的信息有助于理解模型是利用预测所必需的特征,还是依赖虚假的相关性。通过将特定于该群组的解释与针对整个基准的解释进行对比,可以了解该模型对于所选群组的表现是否不同或异常。
依赖图:用户可以看到所选特性的值与其对应的特性重要性值之间的关系。这向他们展示了所选特征的值如何影响模型预测。

图 6 —收入预测模型的全局特征解释表明,婚姻状况和受教育年限是全局最重要的特征。通过单击每个特性,可以观察到更细粒度的依赖关系。例如,“离婚”、“从未结婚”、“分居”或“丧偶”等婚姻状态有助于模型预测较低的收入(< 50K)。“民事配偶”的婚姻状况反而有助于模型预测更高的收入(> 50K)。 ( 图片作者)
本地解释
全局解释近似于整体模型行为。为了将调试过程集中在给定的数据实例上,用户可以从表格实例视图中选择任何单独的数据点(具有正确或不正确的预测),以探索它们的局部特征重要性值(局部解释)和单独的条件期望(ICE)图。
局部特征重要性:用户可以调查单个预测的前 K 个(可配置的 K 个)重要特征。帮助说明基础模型在特定数据点上的局部行为。
个体条件期望****【ICE】:用户可以调查特征值从最小值到最大值的变化如何影响对所选数据实例的预测。
扰动探索(假设分析):用户可以对所选数据点的特征值进行更改,并观察预测的结果变化。他们可以保存假设的假设数据点,以便进一步与其他假设数据点或原始数据点进行比较。

图 7 —对于这个个体,模型输出一个错误的预测,预测这个个体的收入不到 50K,反之亦然。有了假设解释,就有可能理解如果其中一个特征值发生变化,模型将如何表现。例如,在这里我们可以看到,如果这个人老了 10 岁(年龄从 32 岁变到 42 岁),这个模型就会做出正确的预测。虽然在现实世界中,许多这些特性是不可变的,但是这种敏感性分析旨在进一步支持具有模型理解能力的从业者。 ( 图片作者)
其他相关工具
错误分析使从业者能够识别和诊断错误模式。与模型可解释性技术的集成证明了将这些工具作为同一个平台的一部分一起提供的联合力量。我们正在积极地将更多的考虑整合到模型评估体验中,例如公平性和包容性(通过 FairLearn )以及更新期间的向后兼容性(通过backward compatibility ml)。
我们的团队
错误分析的最初工作始于对深入理解和解释机器学习失败的方法的研究调查。微软研究院的贝斯米拉·努什、 Ece Kamar 和埃里克·霍维茨正在领导这些努力,并继续用新技术创新用于调试 ML 模型。在过去的两年里,我们的团队通过与 Azure 机器学习小组中的 RAI 工具团队以及微软混合现实中的分析平台团队的合作得到了扩展。分析平台团队在构建内部基础设施方面投入了数年的工程工作,现在我们正在将这些工作作为 Azure 机器学习生态系统的一部分开源提供给社区。RAI 工装团队由伊利亚·马蒂亚赫、梅赫努什·萨梅克、罗曼·卢茨、理查德·埃德加、惠美·宋、敏素·思格彭和阿努普·希尔冈卡组成。他们对负责任的人工智能的民主化充满热情,并在为社区提供此类工具方面有多年的经验,以前有 FairLearn、InterpretML Dashboard 等例子。在这个过程中,我们也得到了微软以太委员会和微软混合现实的合作伙伴的慷慨帮助和专业知识:帕勒姆·莫哈杰尔、保罗·科赫、泽维尔·费尔南德斯和胡安·马乐。所有的营销活动,包括这个博客的展示,都是由 Thuy Nguyen 协调的。
非常感谢所有让这一切成为可能的人!
相关研究
走向负责任的人工智能:用于表征系统故障的混合人机分析。贝斯米拉·努希、埃切·卡马尔、埃里克·霍维茨;HCOMP 2018。 pdf
机器学习的软件工程:案例研究。Saleema Amershi、Andrew Begel、Christian Bird、Rob DeLine、Harald Gall、Ece Kamar、Nachiappan Nagappan、Besmira Nushi、Thomas ZimmermannICSE 2019。 pdf
人类-人工智能团队的更新:理解并解决性能/兼容性权衡。Gagan Bansal、Besmira Nushi、Ece Kamar、Daniel S Weld、Walter S Lasecki、Eric HorvitzAAAI 2019。 pdf
机器学习系统向后兼容性的实证分析。梅加·斯里瓦斯塔瓦、贝斯米拉·努什、埃切·卡马尔、什塔尔·沙阿、埃里克·霍维茨;KDD 2020。 pdf
通过稳健的特征提取了解深度网络的故障。萨希尔辛拉,贝斯米拉努什,什塔尔沙阿,欧洲经委会卡马尔,埃里克霍维茨。CVPR 2021(即将亮相)。 pdf
用于特征提取的受限玻尔兹曼机器,解释
原文:https://towardsdatascience.com/restricted-boltzmann-machines-for-feature-extraction-explained-90cc433c2556?source=collection_archive---------18-----------------------
它们易于编码,并与神经网络相连。受限玻尔兹曼机器会卷土重来吗?
受限玻尔兹曼机(简称 RBM)是一种通用的特征提取方法。它拥有坚实的理论基础,但实现和运行它所需的实际步骤相当简单明了。它可以与其他类型的机器学习模型相结合,最值得注意的是,RBM 可以与深度学习模型无缝集成。当我在学习欣赏这种算法时,我意识到我错过了一个好的解释,没有用公式和技术术语来攻击我。这篇文章是对受限玻尔兹曼机器的日常语言介绍——在需要的地方有一点数学知识。所以,如果你想知道更多关于受限玻尔兹曼机器在特征提取中的应用,这篇文章就是为你准备的。

照片由维姆·范因德在 Unsplash 拍摄
但是首先:关于特征提取说几句话
受限玻尔兹曼机是一种特征提取过程。执行要素提取时,数据集中的现有要素将被合并并转换为一组更简洁的要素,然后可用于聚类、分类和其他任务。我们为什么要这样做,这有什么帮助?主要有两个原因。两个都提吧。
特征提取减少过拟合。当输入要素的数量很大时,这可能意味着用于有效分类的信息“分散”在大量要素中。它还增加了数据中“机会模式”的可能性,这可能导致分类算法过拟合。图像和语音到文本数据是两个例子,其中特征的原始数量往往非常大,并且特征提取有助于随后的分类。
特征提取允许更好的结果,更快。因为我们使用的是更小的向量,所以聚类、离群点检测和可视化等操作可以在更少的特征上更快地执行。更重要的是,当特征提取算法适用于数据时,它将影响比原始集合更少相互依赖的特征。这使得分类结果更加可靠,也更容易训练和调整。
现在我们理解了动机,让我们回顾一下几乎任何特征提取算法的最突出的超参数背后的直觉:输出维数。
决定输出维度的数量
当执行特征提取时,我们减少了特征的数量,这导致我们的数据集中每个样本的一些信息丢失。自然,我们希望避免不必要的损失,因此特征提取算法通常被设计为在给定输出特征数量的情况下,保留尽可能多的信息。显然,我们选择输出的特征越多,可以保留的信息就越多——但同时,使用特征提取算法的全部意义在于减少维度的数量。因此,在开发包含特征提取阶段的模型时,我们应该尝试不同的输出维度选择,直到找到正确的平衡。特征提取算法的工作的一个关键部分是最小化所选输出大小的信息损失,以便我们可以获得该大小的最佳折衷。
但是我们如何知道丢失了多少信息呢?我们通过逆转提取过程来做到这一点——这被称为重建——并观察原始样本与其重建样本之间的差异。RBM 为我们提供了特征提取(称为编码)和重建(称为解码)的公式。这些公式将在下一节中介绍。
在此之前,我们来看一个检查不同输出维度的例子。下图是 MNIST 手写数字数据集中的一些 28 x 28 像素的图像样本(实际上是测试集中的前几个图像)。原始图像在左手边。它们由在 MNIST 的训练集上训练的 RBM 编码和解码,输出节点的数量有两种不同的选择。
重建示例

受限玻尔兹曼机:重构实例。作者图片
标有重建(1)的列显示从 128 隐藏特征重建的图像,而下一列显示缩小到 64 尺寸然后重建的图像。现在,仔细观察并比较图像:第一次重建通常更好,只有一些局部伪影。在第二次重建中,数字 4 变得与 9 非常相似,这有点令人担忧。右手边的最后一栏显示了基本的特征提取算法(一种标准的重采样程序,将图像减少到 64 像素)如何对相同的数据执行。重采样过程产生的质量比同等维数的 RBM 差得多,因为与 RBM 相比,它没有利用原始图像中的结构和重复模式。
现在我们已经理解了有效特征提取背后的思想,让我们看看 RBMs 中用于数据编码和解码的公式。
是时候来点公式了
在这一节中,我们将深入探讨并解释对 RBM 实现至关重要的两个过程的公式,即编码(提取)和解码(重建)公式。这些几乎是实践中唯一需要的公式。如果你想明智地使用 RBMs,熟悉并理解它们是很重要的。
第一个公式显示了如何将数据编码到一个较低的维度中:

受限玻尔兹曼机编码公式。作者图片
让我们回顾一下每个符号代表的含义:
- h 代表隐藏。 h 是输出,一个低维向量,它表示特征提取过程后的数据点。
- 适马象征着 s 形函数。如果你需要复习什么是乙状结肠,请查看 Jimmy Shen 的文章或维基百科页面。
- v 代表可见。它是表示我们想要对其执行特征提取的数据点的输入向量。它被渲染为一个行向量,然后乘以矩阵 W 。
- W 是一个 m- by- n 权重矩阵,其中 m 是输入尺寸 v 的长度】, n 是输出尺寸 h 的长度)。 W 的条目是训练时学习到的参数。
- b 是偏置参数的向量,长度为 n
因此,要计算低维特征向量,需要将输入向量乘以一个矩阵,添加一个偏差向量,然后对每个元素应用 sigmoid 函数。 W 和 b 的条目需要针对特定数据集的重建进行优化。这是通过 RBM 的专门训练算法实现的,称为对比发散。您可能已经注意到,这个公式与具有 sigmoid 激活的密集神经网络层的公式非常吻合,这意味着一旦您单独训练它并将其插入深度神经网络模型,您就可以使用端到端反向传播来进一步微调参数。
但是,现在应该清楚的是,RBM 不仅仅是标准神经网络层的一个花哨名称。下一个公式是解码(重建)公式,它将低维的 h 作为输入,并检索高维的 v:

受限玻尔兹曼机解码(重构)公式。作者图片
我非常喜欢这个公式,因为它与编码公式的形式几乎完全相同,甚至使用了相同的变换矩阵 W 。第一个公式中的偏置向量 b 在这里不能重复使用(它甚至没有正确的长度),所以它在公式中被替换为不同的偏置向量 a 。
现在,您可能已经注意到,我们计算的 v 的条目被限制在某个范围内:由于我们在应用公式时执行的最后一个操作是应用 sigmoid,因此结果 v 的所有条目都被限制在 0 和 1 之间。这不是巧合,它引导我们讨论 RBM 及其假设的一个重要方面,特别是那些适用于输入向量的假设。
受限玻尔兹曼机和伯努利随机变量向量
受限玻尔兹曼机器在其基本形式中,假设其输入是伯努利变量的向量(参见参考文献中放宽这一假设的扩展示例)。每个伯努利变量只有两种可能的状态,标记为 0 和 1,因此 RBM 输入向量中只允许 0 和 1。单个伯努利变量的随机行为可以用单个参数 p 来概括,该参数表示变量取值为 1 的概率。两个伯努利随机变量的行为要求,在两个变量各自的概率 p( v₁ 和 p( v₂ )之上,它们的条件概率 p( v₂ | v₁ =1)和 p( v₂ | v₁ =0)(等价地,我们可以指定它们的联合概率 p( v₁对于三个伯努利变量,潜在相互作用项的数量增加到 5(8–3),对于四个变量,增加到 12(16–4),依此类推。换句话说,考虑到涉及两个、三个或更多变量的潜在相互作用,即使这些看似简单的变量的行为也很难建模。
为了更好地理解“交互”意味着什么,让我们再次考虑 MNIST 数据集。例如,如果我们将图像中心像素为白色的图像子集与整组图像进行比较,我们会发现,在第一种情况下,围绕该像素的八个像素也为白色的概率更高。这意味着中间像素的亮度值在统计上依赖于其相邻像素的值。我们从中抽取样本的概率分布模型需要包括相互作用项(在本例中,用于相邻像素)
RBM 旨在模拟数据集中最显著的交互作用。他们通过学习参数 W 、 a 和 b 的适当值来做到这一点。 W 的列表示输入变量之间的不同交互模式,这些模式中的每一个都可以存在或不存在,输出向量 h 表示特定模式在给定示例中存在的概率。
幸运的是,将输入表示为 0 和 1 的向量实际上不是一个严重的限制,因为我们可以根据数据类型对每个特征应用适当的预处理技术:
- 分类(也称为名义)变量,如汽车的品牌,可以使用一键编码进行编码,这是机器学习中编码名义值的标准方法。
- 整数值——如售出商品的数量——可以使用一键编码和变体进行编码,如格雷码。
- 连续值(如每英里的运营成本)必须进行分类,然后作为整数值处理。
对于 MNIST 数据集,输入影像中的像素值是 0 到 255 之间的整数。但是,中间值很少出现,因此对于这个特定的数据集,最好只分入两个容器,一个用于暗(黑)像素,一个用于亮(白)像素。
使用图像作为输入,可以可视化 W 的列。每一列代表像素之间相互作用的一种模式,其中相同色调(黑色或白色)的像素被 RBM 识别为在该模式下串联出现。此示例显示了只有 12 个隐藏单元的 RBM 的权重矩阵 W 的列:

训练后变换矩阵 W 的列值的可视化。有些补丁明确表示特定的数字,如 0、1、2、6、7 和 9。
在这个例子中,RBM 探测到的一些交互模式类似于特定的数字。因为我们知道数据集实际上包含不同的数字,这有力地证明了该算法能够检测其输入向量中的重复模式,同时分离不同的向量。
如何开始使用 RBMs
如果你想在自己的数据和建模问题上尝试 RBM 过程,那么我建议你使用发布到 github 的这个实现。这是我的回购 与笔记本,我在这里生成了这篇文章中使用的例子。
摘要
在这篇文章中,我介绍了受限玻尔兹曼机器和特征提取的原理。受限玻尔兹曼机是一种易于实现的二进制数据向量的特征提取过程。可以研究 RBM 的权重矩阵以进一步了解结果,因为它的列表示特定输入要素的权重。虽然成果管理制植根于一些深刻的理论概念,但实施和调整它们并不需要广泛的理论背景。
如果你对从数据科学家到机器学习专家的旅程感兴趣,或者只是想扩大你对经典机器学习的理解,那么受限玻尔兹曼机器是更彻底研究的好模型。RBM 背后的许多理论概念与其他主要模型是相同的——仅举两个例子,高斯混合模型和隐马尔可夫模型。在下面的链接中,你可以找到一些资源来帮助你扩展对受限玻尔兹曼机器背后的理论和相关机器学习概念的理解。我发现这个博客条目比 RBMs 上的维基百科页面更有帮助。如果您找到了其他好的资源,请告诉我:)
参考
[1]|《乙状结肠和坦的区别》作者 Jimmy Shen,2020 年 4 月。
[2]罗伯特·w·哈里森 2018。连续受限玻尔兹曼机器。无线网络。https://doi.org/10.1007/s11276-018-01903-6。
[3] Youtube。com | 深度学习讲座 10.3 受限玻尔兹曼机器,作者 Frank Noe,2020 年 10 月。
[4]Wikipedia.com |受限玻尔兹曼机
[5]Github.com |受限-玻尔兹曼-机作者易先生,2020 年 8 月。
[6]Github.com |火车-可视化-rbm-mnist 由基什卡什,2021 年 10 月。
[7]AI 梦想(【www.theaidream.com】)|受限玻尔兹曼机器简介,2020 年 11 月
零售数据分析
原文:https://towardsdatascience.com/retail-data-analytics-1391284ec7b8?source=collection_archive---------29-----------------------
使用 AWS 的数据科学组合项目

卢卡斯·布拉塞克在 Unsplash 上的照片
介绍
在本文中,我想向您展示一个完整的数据科学组合项目。在这个项目中,我想使用亚马逊网络服务和不同的机器学习算法来执行零售数据分析。包括项目建议书和最终项目报告的完整代码可以在我的 Github 资源库中找到。
定义
如今,商店使用零售数据分析(RDA)来更好地预测可能售出的商品数量,从而更好地估计应该生产多少商品。这一点非常重要,因为一年中售出商品的数量会有很大变化。例如,人们倾向于在圣诞节前购买比平时多的东西,而不是在节假日。这可以很容易地从亚马逊统计数据的季度收入中看出。亚马逊的季度收入在第四季度总是最大的,这表明人们在第四季度比其他季度消费更多。这是显而易见的,因为圣诞节在第四季度,也是黑色星期五,这也导致了全球范围内的大量消费。如果一家商店在圣诞节前商品太少,潜在的收入就会流失。但是如果一个商店有太多的产品,就需要太多的存储空间,而存储又要花钱,所以公司又会浪费钱。因此,可以使用 RDA 来优化产品的生产,从而总是有一个最佳的可用量。
问题陈述
这个项目的目标是预测商店的部门范围内的每周销售额。这将有助于优化生产流程,从而在降低成本的同时增加收入。应该可以从一个部门输入过去的销售数据,并获得预测的每周销售额。
韵律学
目标数据是数值数据。因此,可以使用均方根误差(RMSE)来获得最佳性能的机器学习技术。等式 1 显示了计算 RMSE 的公式。为了更好地理解 RMSE 的规模,可以使用归一化的 RMSE。归一化 RMSE 的计算方法是将 RMSE 除以目标变量的标准偏差。此外,可以使用 R 平方分数。R 平方得分代表模型可以代表的方差的百分比。R 平方得分计算每个点的平方误差除以“虚拟”估计误差,该误差仅预测所有目标变量的平均值。等式 2 显示了计算 R 平方的公式。

等式 1:均方根误差等式

等式 2: R 平方等式
数据探索
这个项目使用了来自 Kaggle 的 RDA 数据集。该数据集包含位于不同地区的 45 家商店的历史销售数据。每个商店又进一步分成几个部门。数据本身存储在 excel 表中。excel 表包含三个选项卡。第一个选项卡包含来自商店的数据。第二个包含特性,第三个包含销售数据。
商店
总共有 45 家店的数据。每个商店都有自己的类型和大小,这也包括在 excel 表中。excel 表中包含的信息是匿名的。图 1 显示了商店大小的统计数据。总共有三种不同类型的商店(A、B 和 C)。

图 1:商店规模统计
特征
这些特征与商店相关。图 2 包含所有可用的特性和每个特性的简短描述,而图 3 包含一些特性的统计数据。降价 1-降价 5 的数据非常不完整,必须删除,或者必须应用不同的方法来处理丢失的数据。

图 2:数据集的特性

图 3:特性的统计
销售
每个商店还将历史销售数据存储在数据集中。销售数据收集自 2010 年 2 月 5 日至 2012 年 11 月 1 日。图 4 包含与销售数据相关的所有特性,图 5 包含每周销售的一些统计数据。

图 4:销售数据的特征

图 5:销售数据统计
探索性可视化

图 6:特性的历史数据
本章更详细地介绍了数据和所有功能。图 6 显示了一些特征的时间序列分析。第一行包含温度图。气温一年一年地变化,最高值出现在七月左右,最低值出现在一月。气温本身似乎对周销量没有任何影响。该图的第二行包含燃料价格。从 2011 年 1 月到 2011 年 7 月,燃油价格大幅上涨。之后,燃油价格上下波动。图中的第三行包含消费者价格指数,自时间序列开始以来,该指数稳步上升。下一行可以看到失业率,自时间序列开始以来,失业率稳步下降。CPI 和失业率的作用完全有道理,因为当人们有更多的工作时,他们有更多的钱去买东西,因此 CPI 上升,因为需求越多,价格越高。该图的第五行包含是否是假日周的布尔数据。最后一行包含每周销售数据。可以看出,如果一周是假日周,则每周销售数据不会自动变大。每周销售的高峰在 11 月和 12 月。11 月的高峰可能是由于黑色星期五,而 12 月的高峰可能是由于圣诞节。一月份的周销售额最低。
图 7 显示了商店分析。左边的图显示了每种类型有多少商店。“A”类商店最常见,而“C”类商店最不常见。中间的图显示了每种商店类型的每周销售额的箱线图。商店类型“A”的周销售额中值最高,而类型“C”的周销售额中值最低。如果看一下右边的图,这是完全有意义的,它显示了每种商店类型的商店大小的方框图。在这里,可以看到商店类型“A”最大,商店类型“B”第二大,商店类型“C”最小。所以商店的规模与每周的销售额直接相关。

图 7:商店分析
算法和技术
为了解决这个问题,应该应用机器学习。应该应用不同状态的机器学习技术,并且最好的性能应该用于最终应用。在最终的应用程序中,用户应该能够输入一周和感兴趣的商店,并获得预测的每周销售额作为输出。作为机器学习算法,应应用和评估以下算法:
1 .线性回归
2。决策树回归器
3。随机森林回归变量
4。XGBoost 回归器
最终的模型应该能够遵循每周销售的模式。它应该能够检测到黑色星期五和圣诞节前后的峰值和一月份的低值。
线性回归
线性回归是一种机器学习技术,它试图找到一个结合所有输入特征的线性函数,以获得目标值。因此,假设输入要素和目标值之间的关系是线性的。
决策树回归器
决策树可以表示线性和非线性函数,并试图构建规则树。树中的每个节点包含一个条件,每个分支包含一个结果。它可以被认为是一个简单的“如果条件则分支 1 否则分支 2”结构。决策树算法试图以能够优化结果性能的方式构建这些规则。当应该创建预测时,对决策树的节点和分支进行“遍历”,并且最终节点包含该树的预测。决策树非常流行,因为它们易于解释。树的结构可以容易地可视化,并且用户可以直接看到节点条件和分支,因此可以容易地遵循策略,决策树模型如何创建预测。
随机森林回归量
随机森林在训练时创建更多的决策树,以防止过度适应。在推理期间,随机森林输出所有决策树预测的平均值,以获得最终预测。
XGBoost 回归器
XGBoost 回归器算法是随机森林的优化版本。它使用梯度推进技术来提高训练速度和预测性能。
基准
线性回归模型被用作基准模型。它是使用 scikit-learn 库训练的。它的 RMSE 为 21469.1 周销售额,这是一个非常大的值,它告诉我们,周销售额与输入要素不是线性相关的。图 8 显示了 100 个预测和它们的真实标签。可以看出,基准模型不能遵循周销售额的结构。图 11 显示了训练基准模型、部署它并获得评估结果的代码。

图 8:线性回归模型的结果
履行
在这一章中,我想解释预处理数据和训练所有估算者的主要程序。为了更加清晰,我附上了代码片段。
数据预处理
笔记本"2 _ Create _ Train _ and _ Test _ data . ipynb"包含数据预处理和创建训练、测试和验证数据的代码。作为第一个预处理步骤,列“IsHoliday”从布尔值转换为整数。其次,商店类型被转换为分类列。商店类型“A”转换为 0,“B”转换为 1,“C”转换为 2。下一步,日期列被转换成两个独立的特性。第一个是年份,第二个是一年中的星期。应使用一年中的某一周,因为要预测每周的销售额。之后,应解决降价列中大量缺失值的问题。为了消除缺失值,使用了 sklearn 库中的迭代估算器。迭代插补器将每个缺失值建模为其他特征的函数,并使用该估计值进行插补。降价列的特征和可用值用于训练回归模型。然后使用训练好的回归模型预测缺失值。迭代估算器仅根据训练数据进行训练,以避免数据泄漏到拒绝测试和验证数据中。图 9 显示了训练一个迭代估算器,然后输入缺失值的代码。
最后,训练、测试和验证数据集被创建并存储在单独的 csv 文件中。测试集大小占所有数据的 10%,而验证集大小占其余数据的 30%。
图 9:迭代估算代码
培养
笔记本“3 _ Training _ and _ deployment . ipynb”包含所有训练代码。我开始将训练、验证和测试数据加载到 S3(图 10)。
图 10:向 S3 上传数据的代码
然后我训练了基准模型。使用 sklearn 库创建和训练线性回归基准模型。用于训练的代码位于源文件夹中的“train_linear_regression.py”脚本中,该脚本也用作笔记本中 sagemaker sklearn 估计器对象的入口点。之后,部署并评估了基准模型。在评估中,我计算了归一化 RMSE、R 平方得分,并创建了一个包含前 100 个测试预测的图(图 11)。此外,我使用 matplotlib 库绘制了前 100 个预测值与实际值的关系。
图 11:训练和部署线性回归模型的代码
之后,我训练了决策树回归器和随机森林回归器。对于两者,我都使用了 sklearn 库,并且在源文件夹中有单独的训练脚本作为入口点。决策树和随机森林有很多不同的超参数。为了找到最佳匹配,我使用 skopt 库来创建贝叶斯优化器。贝叶斯优化器将 sklearn 估计器对象作为输入,这是一个字典,其中超参数名称作为键,它们的值范围作为值,一个整数指示应该执行多少次迭代以及用于交叉验证的折叠数。图 12 包含了寻找最优决策树回归器的代码。我使用交叉验证折叠大小为 5,贝叶斯优化器运行了 7 次迭代。
图 12:为决策树回归器训练贝叶斯优化器的代码
图 13 包含寻找最优随机森林回归量的代码。交叉验证折叠大小再次为 5,贝叶斯优化器运行 10 次迭代。随机森林回归器另外使用所有四个 cpu 核心,以便加速训练。
图 13:为随机森林回归器训练贝叶斯优化器的代码
对于这两个训练好的模型,我计算了归一化 RMSE 和 R 平方得分。作为最后一个估计者,我训练了 XGBoost 回归器。XGBoost 回归器使用 Sagemaker 中已经创建的容器进行训练。同样,XGBoost 估计量有很多超参数。为了找到最佳组合,我使用了 Sagemaker 的“HyperparameterTuner”库。图 14 包含查找最佳 XGBoost 回归器并对其进行评估的代码。我训练了 20 种不同的 XGBoost 估计器,并提取和部署了性能最好的估计器。部署后,我再次计算了标准化的 RMSE 和 R 平方得分,加上前 100 个测试预测的可视化。
图 14:为 XGBoost 模型加评估训练贝叶斯优化器
结果

图 15:最终结果
图 16 显示了经过训练的决策树回归器的前 100 个预测与基本事实标签的比较。可以看出,决策树回归器已经能够跟踪每周销售的模式。图 15 包含 RMSE 和 R 平方得分。

图 16:决策树模型的结果
图 17 显示了经过训练的随机森林模型的前 100 个预测。随机森林同样能够遵循周销售额的结构,但是随机森林回归器具有稍大的归一化 RMSE,同时具有与决策树模型相同的 R 平方。

图 17:随机森林模型的结果
图 18 显示了根据贝叶斯优化具有最佳超参数组合的训练 XGBoost 模型的前 100 个预测。XGBoost 模型还具有最低的归一化 RMSE 和最高的 R 平方得分,因此是所有训练模型中性能最好的估计器。

图 18:XG boost 模型的结果
XGBoost 模型的 R 平方值是基准模型的十倍以上。归一化 RMSE 比基准模型的 RMSE 小五倍。R 平方得分为 0.96,这意味着最终模型可以代表测试数据集中给定方差的 96%。RMSE 仍然在每周销售标准偏差的 19%。但周销量的幅度也很大,最低周销量为-4989,最高周销量为 693099.4(参见图 5)。当查看图 18 时,可以看到最终模型已经学习了底层结构,因此可以用作预测器,但是仍然需要考虑预测中的潜在异常值。
利用事件建模驱动的干预时间留住客户
原文:https://towardsdatascience.com/retain-customers-with-time-to-event-modeling-driven-intervention-de517a39c6e3?source=collection_archive---------8-----------------------
实践教程
使用 XGBoost 在正确的时间精确定位客户流失
由查尔斯·弗伦泽 l、百川孙和宋寅
获得一个客户通常比留住一个客户花费更多。
关注客户维系使公司能够在客户生命周期中最大化客户收入。
这篇博文将向你展示如何训练一个模型,使用 XGBoost 来预测客户流失事件的风险 和 时间。
结合生产级端到端机器学习管道,如 AWS 上的客户流失管道,有时间进行事件流失建模,这允许及时干预以停止客户流失。

作者图片
客户流失或简称为流失是指客户在实现最大收益之前“离开”。停止这些活动以保持收入是如此确定,以至于基于流失的模型是首批投入生产的机器学习解决方案之一。
然而,这些模型很少被优化,因为它们依赖于二进制分类标志(是或否)。客户流失分类模型不会告诉客户什么时候可能会离开,而只是表明这将在几天或几个月内发生。
这篇博文将介绍如何在客户的生命周期中衡量流失风险,以找到需要进行流失干预的 时间点 。
范式转变:从仅事件到及时干预
流失模型可能更好的一个很好的理由是,许多模型是根据固定的二元结果的任意时间阈值设置的。这意味着时间保持不变!例如,设置一个任意的阈值,在 40 天的不活动之后,客户就会翻盘。
基于这样的启发标记客户会导致滑点,主要是:
- 顾客在门槛前翻腾。
- 离门槛很远很远的客户。
- 忽略客户一生的差异
将 40 天后可能离开的客户与 100 天后离开的客户同等对待可能是错误的。传统的客户流失建模没有进行这种区分。
例如,在下面的图表中,模型准确地捕获了客户 B,因为他们在设置阈值的确切时间点(40 天)离开。客户 A 实际上在阈值之后搅动,并且他们丢失了,因为模型不能解释他们。客户 C 做了相反的事情,停留的时间远远超过数据时间窗口。他们很可能会流失,但我们无法用分类模型来模拟何时流失。

作者图片
这里唯一的时间点是“40 天内”阈值。由于它没有考虑时间,我们不清楚在什么时候需要营销干预,它会导致可预防的客户流失。
当知道时,重新构建问题
我们不使用二元分类器,而是将问题重新构建为依赖于时间的问题。这使我们能够在适当的时候进行干预,在客户流失发生之前阻止它。不再依赖于阈值,我们现在将流失设置为连续的时间条件事件。如下图所示,我们现在知道损耗风险最有可能发生的时间。

作者图片
时间不再保持不变,我们现在随着时间的推移跟踪风险以确定何时需要营销干预来留住客户。如果我们为时间和事件建模,干预和防止损耗的正确时机是显而易见的。一种叫做生存分析的建模技术允许我们这样做,随着现代机器学习的出现,这现在是一项微不足道的任务。对生存分析及其背后的数学原理的深入探究超出了我们的范围,我们鼓励你查看所有关于 Medium 的关于数据科学的好文章,以获得更多信息。
对数据的快速浏览
在本例中,您将使用一个虚构的电信公司的合成客户流失数据集,结果为“客户流失?”标记为真(已搅动)或假(未搅动)。功能包括客户详细信息,如计划和使用信息。客户流失数据集是公开的,在丹尼尔·t·拉罗斯的《T2 发现数据中的知识》一书中有所提及。作者将其归功于加州大学欧文分校的机器学习数据集仓库。所有代码的笔记本位于这里。
df = pd.read_csv("../../data/churn.txt")
# denoting churn and duration
df["event"] = np.where(df["churn?"] == "False.", 0, 1)
df = df.rename(columns={"account_length": "duration"})
del df['churn?']
df = df.dropna()
df = df.drop_duplicates()df.head()

作者图片
进一步检查我们的目标会发现,总共有 5,000 条记录,其中 49.9%的记录最终被淘汰。数据集在目标上是平衡的。在真实世界的数据中,情况并非总是如此,流失事件可能是数百万条记录中的 1%。有补救的策略,但这超出了这篇博文的范围。
查看持续时间,表示为账户长度(我们的时间部分),它显示中位数时间为 102 天,接近 101 天的平均值。
print("Total Records:",df.shape[0],"\n")
print("Percent Churn Rate:",df.event.mean())
print("")
print("Duration Intervals")
print(df['duration'].describe())Total Records: 5000
Percent Churn Rate: 0.4996
Duration Intervals
count 5000.0000
mean 101.6758
std 57.5968
min 1.0000
25% 52.0000
50% 102.0000
75% 151.0000
max 200.0000
对于生存模型,数据不同于传统的分类问题,需要:
- 审查员——对我们来说,这些是尚未流失的客户。在这里阅读关于权利审查的内容。
- 持续时间——客户活动的持续时间。在这种情况下,是以天为单位的
Account Length。 - Event —二进制目标,在这种情况下,如果他们终止了标记为
Churn?的电话计划。
我们可以绘制时间线上的前 10 个客户,以了解右删数据是如何工作的,以及问题是如何形成的。
ax = plot_lifetimes(df.head(10)['duration'], df.head(10)['event'])
_=ax.set_xlabel("Duration: Account Length (days)")
_=ax.set_ylabel("Customer Number")
_=ax.set_title("Observed Customer Attrition")

作者图片
在上图中,红线表示客户离开的时间,圆点表示具体的时间点。蓝线表示在 x 轴上测量的持续时间内仍处于活动状态的客户。
在这里,我们看到客户号 8 直到第 195 天才流失,客户号 0 和 4 分别在第 163 天和第 146 天离开。所有其他客户仍然活跃。
请注意所有客户是如何被设置在相同的时间尺度上的,因为数据是分析对齐的。每个顾客可能在不同的时间来,但是我们把日子定得一样。这让我们能够正确审查客户流失事件的数据。在建模开始之前,真实世界的数据需要审查和校准。
流失的风险
一个更有用的方法可能是估计生存函数或客户流失前的天数。为此,我们将使用卡普兰·迈耶估算器来计算流失发生前的时间。估计量定义为:

来源:生命线
其中,𝑑𝑖是𝑡时间点的客户流失事件数量,𝑛𝑖是𝑡.时间点之前面临客户流失风险的客户数量
我们将使用伟大的 python 包 lifelines 来绘制生存函数,因为该函数是最终流失模型的一个组件。
kmf = KaplanMeierFitter()
kmf.fit(df['duration'], event_observed=df['event'])
kmf.plot_survival_function()
_=plt.title('Survival Function for Telco Churn');
_=plt.xlabel("Duration: Account Length (days)")
_=plt.ylabel("Churn Risk (Percent Churned)")
_=plt.axvline(x=kmf.median_survival_time_, color='r',linestyle='--')

作者图片
我们来看看中位存活时间。这是一半的顾客产生的原因。根据这张图,用红色虚线标记的地方,大约 152 天,一半的客户流失。这是有帮助的,因为当需要干预时,它给整体基线。然而,对于每个客户来说,这是没有意义的。
缺少的是每个客户流失风险最高的时间点。
为此,我们将使用考克斯比例风险创建一个模型,该模型使用对数风险函数 h(x) 。风险函数以客户在时间 t 或更晚之前的剩余率为条件,这允许估计随着时间推移的流失风险。这将使我们能够对每个客户进行评分,并预测何时需要营销干预。然而,在此之前,我们需要对数据进行预处理。
数据分割和预处理
首先,我们将数据分为训练和测试。我们将使用测试集作为例子的验证。在实践中,您需要所有这三个拆分,这样您就不会调整到验证集。
接下来,我们获取数字特征和分类特征,然后对它们进行预处理以用于下游建模。在类别的情况下,我们将首先用常量进行估算,然后简单地对它们进行一次性编码。在数字的情况下,我们将填充中间值,然后将它们标准化为 0 和 1 之间的值。为了简单起见,这些都包含在 Sklearn 的管道和列变换器中。
作为搅动管道的一部分,所有这些步骤都包含在最终的预处理器中,保存起来供推断时使用。
df_train, df_test = train_test_split(df , test_size=0.20, random_state=SEED)numerical_idx = (
df_train.select_dtypes(exclude=["object", "category"])
.drop(['event','duration'],1)
.columns.tolist()
)
categorical_idx = df_train.select_dtypes(exclude=["float", "int"]).columns.tolist()
numeric_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler()),
]
)
categorical_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="constant", fill_value="missing")),
("onehot", OneHotEncoder(sparse=False, handle_unknown="ignore")),
]
)
preprocessor = ColumnTransformer(
[
("numerical", numeric_transformer, numerical_idx),
("categorical", categorical_transformer, categorical_idx),
],
remainder="passthrough",
)
train_features = preprocessor.fit_transform(df_train.drop(['event','duration'],1))
test_features = preprocessor.transform(df_test.drop(['event','duration'],1))
转换 XGBoost 的目标
我们将使用 XGBoost 的 DMatrix 格式来运行常规的非 scikit API。对于生存函数,这需要一个转换,将持续时间设置为目标,然后使其对于事件为正,对于非事件为负。这不是一个事件和持续时间或二元结果的元组,而是一个正/负的单一连续变量作为目标。更多关于 XGBoost 中生存是如何工作的,请看这个教程。
def survival_y_cox(dframe:pd.DataFrame) -> np.array:
"""Returns array of outcome encoded for XGB"""
y_survival = []
for idx, row in dframe[["duration", "event"]].iterrows():
if row["event"]:
# uncensored
y_survival.append(int(row["duration"]))
else:
# right censored
y_survival.append(-int(row["duration"]))
return np.array(y_survival)
dm_train = xgb.DMatrix(
train_features, label=survival_y_cox(df_train), feature_names=feature_names
)
dm_test = xgb.DMatrix(
test_features, label=survival_y_cox(df_test), feature_names=feature_names
)
关于危险函数的更多信息
风险功能提供客户流失风险——告诉我们客户流失最有可能发生的时间。
生存函数 S(t) 返回超过某个时间点的客户流失概率 S(t) = P(T > t) ,而风险函数 h(t) 给出客户停留到时间 T 的近似概率,使得:

来源:生命线
另一方面,利用危险函数,也可以得到生存函数,因为:

来源:生命线文档
梯度推进和 Cox 的部分似然
在梯度增强的情况下,多个基本学习器被组合以获得增强的整体学习器集合,其被定义为以下的加法模型:

来源:sci kit-生存文档
对于生存分析情况,目标是最大化对数部分似然函数,但是用加法模型代替传统的线性模型 f(x) :

资料来源:sci kit-生存文件
关于这方面的更多信息,请参见这个优秀的 python 库 Scikit-Survival 教程。
正常的参数在这里都适用,除了我们已经把objective改为surivial:cox这将允许训练一个增强的生存树。
params = {
"eta": 0.1,
"max_depth": 3,
"objective": "survival:cox",
"tree_method": "hist",
"subsample": 0.8,
"seed": 123
}
bst = xgb.train(
params,
dm_train,
num_boost_round=300,
evals=[(dm_train, "train"), (dm_test, "test")],
verbose_eval=int(1e1),
early_stopping_rounds=10
)[0] train-cox-nloglik:7.25501 test-cox-nloglik:5.86755
...
[151] train-cox-nloglik:6.67063 test-cox-nloglik:5.39344
关于预测的一个注记
该模型的预测以风险比的形式返回(即,比例风险函数 h(t) = h0(t) * HR 中的 HR = exp(marginal_prediction)。这意味着输出可以是指数边际预测,也可以是非指数边际预测。为了预测客户流失最有可能发生的时间,我们需要指数化的版本,因为它直观地反映了一种概率(即使从技术上讲,这并不是真正的概率)。更多信息见输出如何发生见。
检查全球预测
然后,我们可以根据时间 t (在这种情况下为账户长度)来计算风险分数或流失概率,并查看何时最有可能发生流失。

分桶流失风险(作者图片)
将这些值分成时间段显示,最高流失风险发生在第 53 天到第 62 天。在这段时间之后,最可能的损耗时间是在第 80 到 102 天。实际上,您应该忽略从第 191 天到第 200 天的最后一根棒线,因为这是截断点。
评估绩效
在生存模型的情况下哈勒尔和谐指数和布里埃分数通常用于评估生存模型。
哈勒尔索引(哈勒尔等人,1982 年)
一致性指数或 C 指数是 ROC 曲线(AUC) 下区域的概括,可以考虑删失数据。
它应该被认为是模型的拟合优度度量,该度量确定了模型基于个体风险评分正确提供可靠生存时间排序的能力。
C = 0.5的值表明风险分值不比抛硬币好多少。
这表示为一致对的数量/(“一致对”的数量+“不一致对”的数量)或:

资料来源:PySurvival 文件
布赖尔乐谱(布赖尔 1950)
Brier 评分用于评估给定时间 t 的预测生存函数的准确性。它代表观察到的生存状态和预测的生存概率之间的平均平方距离,并且总是 0 到 1 之间的数字,0 是最佳可能值。

资料来源:Pysurvival 文件
然而,如果数据集包含被右删截的样本,则有必要通过加权来调整分数。这就是 Scikit-Survival 的 Brier 评分标准的用处。如他们的文件中所述,依赖于时间的 Brier 分数是在时间点 t 的均方误差

来源:sci kit-生存文档
这意味着测量现在根据右删失数据进行了调整,因此更加准确。
让我们给模型打分!
*print("CIC")
print(
surv_metrics.concordance_index_ipcw(
y_train,
y_test,
df_test['preds'],
tau=100 # within 100 days
)
)
print("Brier Score")
times, score = surv_metrics.brier_score(
y_train,y_test, df_test['preds'], df_test['duration'].max() - 1
)
print(score)**CIC
(0.7514910949902487, 177342, 58706, 0, 1218)
Brier Score
[0.37630957]*
这些结果是可以接受的,因为这些数据并没有考虑到生存分析。一致性指数达到 0.75,优于简单随机概率。欧石南的分数是 0.376,不算很高。理想情况下,我们希望它是 0.25 或更低,正如 Pysurvival 文档指出的。
还有其他方法来进一步评估这一点。例如, Scikit-survival 软件包提供了多种评估指标,如 ROC 下的时间相关区域等。
模型可解释性与 SHAP
好消息是SHAP(SHapley Additive exPlanations为基于树的集成提供了一种高速精确算法,以帮助解释模型中的特征重要性。具体来说,它将允许用户了解哪些因素会增加和降低客户流失风险。
*explainer = shap.TreeExplainer(bst, feature_names=feature_names)
shap_values = explainer.shap_values(test_features)
shap.summary_plot(shap_values, pd.DataFrame(test_features, columns=feature_names))*

作者图片
此外,我们现在在客户层面解释了如何计算每个流失风险分值。这有助于为干预策略的选择提供信息。例如,夜间收费、夜间通话和夜间通话时间都会导致客户流失。加上每天的通话时间(作为一个积极的预测因素)表明,显然在晚上或夜间打电话的客户面临更高的风险。这可以进入干预策略,通过设置干预通信在晚上和傍晚向处于危险中的客户发出。
这提供了易于向业务用户展示的细节,并提供了进一步分析哪些功能会导致客户流失的方法。
*idx_sample = 128
shap.force_plot(
explainer.expected_value,
shap_values[idx_sample, :],
pd.DataFrame(test_features, columns=feature_names).iloc[idx_sample, :],
matplotlib=True,
)
print(f"The real label is Churn={y_test[idx_sample][0]}")*

一个非搅动者是如何计算出来的,图片由作者提供
*The real label is Churn=False*
最后,由于这是一个基于树的模型,我们也可以画出树的样子。虽然我们设置了 100 棵树来训练,但是很早就停止了,这次运行的最佳迭代是 67 棵树。让我们只看第一棵树,看看它的分裂来判断理解推理是如何运行的。
*xgb.plot_tree(bst, rankdir="LR", num_trees=0)
fig = plt.gcf()
fig.set_size_inches(150, 100)*

第一棵树,作者图片
不出所料,最具预测性的特征是它首先分裂的特征。在这种情况下,这意味着夜间费用,夜间通话,白天和晚上分钟分裂。显然,这个树也是向业务用户展示您的模型正在做什么的好方法。
最终检查
在我们的最后检查中,我们将把问题作为一个分类器来处理,因为我们可以这样做。由于模型本身是以时间为条件的,所以这些并不是评估它在技术上做得如何的真正好的指标。我们只是为反对者运行这个,并表明它是可行的。
*from sklearn import metrics
y_preds = df_test.preds.apply(lambda x : np.exp(x))
y_pred = np.where(y_preds > 0.5, 1, 0)
print(f"Accuracy score: {metrics.accuracy_score(df_test.event, y_pred)}")
print(f"Area Under the Curve {metrics.roc_auc_score(df_test.event, y_pred)}")
print("")
print(metrics.classification_report(df_test.event, y_pred))**Accuracy score: 0.932
Area Under the Curve 0.9339674490815218
precision recall f1-score support
0 0.97 0.90 0.93 527
1 0.89 0.97 0.93 473
accuracy 0.93 1000
macro avg 0.93 0.93 0.93 1000
weighted avg 0.94 0.93 0.93 1000*
令人惊讶的是,该模型获得的结果优于 2017 年该数据集首次出现在博客世界时报告的 86%的准确率。我们不仅有准确性,还能在时识别出。这使得及时的营销干预能够留住客户。
结论
这篇博文展示了如何用时间组件来训练客户流失模型。使用带有 Cox 比例风险的生存分析,我们可以通过确定客户流失风险最高的时间来防止客户流失。这允许主动、及时的干预来阻止客户离开。
现在你有了一个模型,是时候生产它了,就像 AWS 上的客户流失管道,它包括一个流失时间事件建模的模板。一旦配置了管道,您就可以对记录运行推理,通过批量推理来累积分数,从而做出干预决策。

按天间隔划分的客户风险(图片由作者提供)
(上面显示了一个表格,显示了客户在几天内批处理作业的累积结果。现在有了客户流失风险历史记录,可以监控并标记何时进行干预。)
使用机器学习进行生存分析是一种解决客户流失等问题的好方法。我们鼓励您查看下面的参考链接,了解所有可用的不同技术。
参考文献
生命线,卡梅隆戴维森-皮隆 2014
XGBoost:一个可扩展的树提升系统,陈& Guestrin 2016
PySurvival:生存分析建模开源包,Fotso 2019
scikit-survival:基于 scikit-learn 构建的时间-事件分析库,Sebastian Polsterl 2020
SHAP(沙普利补充解释),伦德伯格 2017
留存和日活跃用户解释。
原文:https://towardsdatascience.com/retention-and-daily-active-users-explained-79c5dab1bf84?source=collection_archive---------10-----------------------
针对 Firebase 用户、机器学习爱好者和营销人员的完整 Data Studio 指南和 BigQuery 教程。你想知道的。包括数据工作室模板。

Data Studio 模板。作者图片
你有没有想过如何减少用户流失,节省用户获取的费用?这篇文章是关于如何统计那些在你的应用中停留在 T1 的用户,以便让 T2 了解是什么让他们停留在 T3。
这篇文章是写给谁的?
- 负责创建自定义用户留存仪表板的营销人员。
- 可能想要创建更好报告的分析师。
- 人工智能和人工智能专家肯定想预测用户流失。
- 可能想质疑其保留数字的 Firebase 用户。
先决条件
- SQL 的基础知识
- 谷歌开发者账户。它是免费的。
- BigQuery access。它是免费的。
- 数据工作室访问。它是免费的。
如果你喜欢这个模板,你可以从这里下载。它是免费的。所有数据集都包含在此模板中。在本文最后阅读如何复制。
基础
我将使用 BigQuery (BQ)和 Data Studio (DS)来处理数据。
我们需要的所有数据都将包含在下面的 SQL 中。所以这是一个非常小的数据集,运行它不需要任何成本。
SQL 可以很容易地适应任何其他数据仓库,但在 BQ 中运行它并在 DS 中可视化更容易。所以不要犹豫,尝试一下吧。
我们来看一些用户活动示例(复制粘贴后在 BQ 中运行即可):
这将给我们一个模拟出来的用户活动表:

示例用户活动表。BigQuery。作者图片
如果你使用 Firebase 或 Google Analytics 你可以提取数据并上传到 BigQuery 中做进一步分析。我在之前的一篇文章中写道:
现在,当我们有数据时,我们需要一个视图来查看用户在注册后的每一天是否活跃,然后统计活跃的用户。

保留表示例(作者图片)
要计算 BigQuery 中每天的活跃用户数,可以使用下面的 SQL。有点难看,但像这样的东西应该工作:
用户保留表
对于许多营销人员来说,代表最大兴趣的指标将是 30 天留存,因为如果用户在第 30 天活跃,这意味着它已经使用应用程序 30 天了。如果用户在过去 30 天内至少活跃一次,则该用户将成为月活跃用户 ( MAU )。
然而,这个用户不一定是一个活跃的用户。
我们需要区分可测量的用户活动(例如,你的用户群的 K-means 聚类)和简单地活跃为 MAU 。
例如,如果一个用户打开了你的应用程序,然后卸载了它,这是一个活跃的用户吗?是的,它是。
在这篇文章中,我将讨论如何计算用户登录次数,并生成 DAU/MAU 指标。
新活跃用户是指在指定时间段内,首次与你的 app 互动的用户。(例如创建一个帐户)然后开始每天、每周或每月使用它。这些用户通常会受到他们所经历的用户入职流程的严重影响。
返回活跃用户是指经过一段时间的不活跃后,继续回到你的应用的用户,与你的业务的留存率和经常性收入指标密切相关。
现在让我们创建一个新的数据源,并在 Data Studio 中可视化我们的数字。
我们并不真的需要在 SQL 中使用聚合并将它物化,因为我们的数据集相对较小,Data Studio 可以为我们做聚合。
数据源:
你可以看到我创建了一个名为user_pseudo_id_percent的新领域。稍后我们将使用它来显示保留用户的百分比。
现在,让我们添加一个新列week_,我们将使用它来计算每周的保留时间。尝试运行这段 SQL,看看会发生什么:
select ceil(DATE_DIFF('2020-10-25', '2020-10-10', DAY)/7) AS week_diff

周差异
例如,在 Firebase 中,我们有一个类似的东西叫做每周保留群组。

Firebase 新用户保留示例(图片由作者提供)
让我们将这个新字段添加到我们的数据源:
将每周分组添加到保留中
为了准确报告留存率,您的分析工具需要能够识别同一用户,即使他们在六个月后使用不同的浏览器或设备登录。这可能会成为一个真正的挑战,因为
…在现实生活中,当用户拥有不同的帐户和多台设备时,事情会变得更加复杂。
什么是“活跃用户”
让我们假设每个客户端应用程序在运行时每天都会登录几次。每个登录事件都可以与用户 id 和设备 id 一起记录到您的数据湖/数据仓库中。
这差不多就是 Firebase 记录用户的方式。默认情况下,您将拥有user_pseudo_id,并且可以像这样启用user_id:
https://firebase.google.com/docs/analytics/userid
您可以做很多事情来监听这些事件,甚至在将它们发送到数据仓库之前对它们进行预处理,以得到您需要的数据。像 Kinesis 或 Kafka 这样的东西可以很容易地从你的微服务中传输事件数据。
—那么什么是活跃用户呢?
—这取决于您希望应用于数据集和报表的业务逻辑。
活跃用户通常被报告为每月活跃用户(MAU) 、每周(WAU) 和每天(DAU) 。让我们用一个可视化的例子来进一步说明活跃用户:

DAU、WAU 和每月活跃用户。作者图片
在上图中,您可以看到用户注册后每天登录。每一个彩色圆圈都暗示着用户在那天很活跃。用户'J'(‘J’代表约翰纳斯)在第 1-6 周都很活跃。不过还是算 1 MAU ( 月活跃用户)。因此,我们可以看到该月有 2 个活动用户,因为所有用户在该月都至少活动过一次。你可能注意到用户 id ' E01 ' ('E '是 Emma 的)有 2 个设备( user_pseudo_id 2001 和 2000 )。
我们计算了用户,这就是为什么它是 2(不是 3) MAU。所以你可以看到,这完全取决于方法论。
在这种情况下,活跃用户数可能会轻松增加一倍或两倍。想象一下,约翰用他的一台设备创建了多个账户。
我们稍后将更好地研究如何解决这个问题。
如果我们将范围缩小到周 (WAU) 我们可以看到在周1–3 期间有 2 个活动 用户,而在周 4 期间只有个 1 个。我看到人们在分析不同时间段(每月、每周、每天)的用户活动数据时,经常会质疑这些数据,并认为这些数据有问题,而事实并非如此。
如果一个用户在一个月的每一天都访问你的应用程序,那就是单个用户。 不是 30 个不同的用户。
如果你喜欢上面的模板,你可以简单地从 复制到这里 。
数据集:

Data Studio 保留模板。第二页。作者图片
保留
我们可能想要回答以下问题:
在第天 1,2,…,n,有多少新用户是活跃的?
这是日常的滞留队列。这是用户注册后的天数(不是日期)。一些帐户可能在不同的日期注册。
在第周 1,2,…,n,有多少新用户是活跃的?
这是每周保留队列(注册日期后的周数)。
在月 1,2,…,n 有多少新用户是活跃的?
月度留存群组(登记日之后的月份编号)。
让我们为我们的保留群组创建一个数据集。
每日、每周和每月保留组
要回答第一个问题
在日 1,2,…,n,所有新用户中有多少是活跃的?
我将使用 Data Studio 和上面的数据集,默认聚合设置为 MAX。
我将使用 day_number 、 week_diff 和 month_diff 作为数据透视表中的维度、行和列。
我将使用user_pseudo_id ( device_id )来统计独立用户,因为这几乎是 Firebase 中的标准。
结果:

每日保留队列
在第周 1,2,…,n,有多少新用户是活跃的?

保留周刊
还记得那个看起来很熟悉的 Firebase 保留视图吗?它简单地倒退 5 周,并将first_seen_week添加到行中:

我们可以在 Data Studio 中通过将first_seen添加到我们的数据集来实现这一点:

Data Studio 中的每周保留。作者图片
或者我们可以添加first_seen_week:
*EXTRACT(WEEK FROM first_seen) AS first_seen_week*
我已经添加了另一个 device_id ,它将在 11 月 1 日与在第一次看到,新的数据集将是(记住现在我们需要在分区中使用first_seen进行行分组):
如何更好地可视化以留住人才?
如果我们能以日历的形式显示我们的保留率会怎么样?
日历图表
我们通常使用数据透视表来可视化保留群组的数据,但在日历上查看相同的数据通常会更有见地。

在下一个例子中,我将假设每 30 天的保留期等于一个月。因此,它实际上不是一个日历月,但没有什么可以阻止您显示日历月的保留率,而不是保留组。只要记住它会有完全不同的意义。
事实上,在许多情况下,您可能希望简化显示保留时间,如下所示:

按活动日期保留
使用活动日期而不是每天、每周或每月分组是有意义的,因为这样更直观,更容易理解。
我们还能对保留做些什么?
- 我们可以在之前的问题中添加日期。例如,在 DS_START_DATE 和 DS_END_DATE 之间注册的新用户中有多少人在 day 1,2,…,n 是活跃的?
- 我们也可以将
first_seen或registration_date放在 X 轴上,用线图显示 3、7、30 天的留存。 - 在现实生活场景中,我们通常会有
registration_date而不是 first_seen,所以我们的数据集可能需要一点调整。 - 我们可以使用日历月作为保留群组。只要记住它和第一、第二等等不一样。注册后一个月。对于在
2020–11–03的2020–10–01活动日期注册的用户,将被月 2 日保留。然而,如果我们使用日历日期,那就是一个月。 - 添加用户属性(例如来自 Google Analytics 的活动、来源、媒体)并在行分组中使用它来查看不同活动的留存率可能是非常有见地的。
- 确定真正的唯一用户并分别计算他们的留存率。这可能会对保留数字产生巨大影响。拥有多台设备的用户或者和拥有多个用户账号的用户一样重新安装 App 的用户或者垃圾邮件发送者真的很难统计。毫无疑问,他们可能会歪曲你的保留数字。
- 如果我们使用自定义保留组,例如第 7 天+-1 天或第 30 天+-1 天,看看会发生什么可能会很有趣。
还记得 30 天保留期以及它对营销人员如此重要的原因吗?
- 您还可以计算不同用户群的留存率。例如,对于那些符合特定标准的人。或者,执行一个快速的 K 均值分析来对你的用户进行聚类,然后计算留存率,这可能非常有用。
结论
这就把我带到了这篇文章的结尾。使用这个漂亮的模板,你可以轻松模拟用户活动数据,并对你的留存报告进行单元测试。
我们刚刚在 BigQuery 和 Data Studio 中使用了 5 种不同的方法来显示用户留存率,并且您可以使用 Firebase、Google Analytics 数据和这个小报告做更多的事情。
只需在 Data Studio 中进行一些简单的调整,这个模板就可以变成一个漂亮的实时分析仪表板,用来更好地了解你的用户行为。
保留率是一个非常重要的指标,因为能够了解用户离开的原因、时间和地点可能有助于您了解他们这样做的原因。
保留分析是一个非常强大的工具,旨在解释用户流失。利用这些知识,营销人员可以通过修复应用程序错误、改进应用程序功能和建立更成功的营销渠道来提高保留率。
众所周知,获得新用户的成本高于留住现有用户的成本。
因为流失的用户可以转化为收入的直接损失,预测可能流失的用户可以帮助公司挽回这一损失。这就是为什么对保留的不同观点、解释保留数字的方法以及解释用户流失的原因在建立机器学习模型(例如,流失预测)中变得越来越重要。
感谢阅读!
如何复制此模板
- 点击此链接并点击使用模板

复制模板。作者图片
2.单击复制包含数据集的报告:

3.有些部件会显示为损坏,但单击一个部件,然后单击编辑

4.选择您的计费项目,点击重新连接:

成功了!

在datastudioguides.com上有更多的模板和教程
推荐阅读:
https://datastudioguides.com/data-visuals-with-data-studio/ https://firebase.google.com/docs/analytics/userid https://support.google.com/firebase/answer/6317510?hl=en https://stackoverflow.com/questions/60782636/firebase-retention-ratescohort https://cloud.google.com/bigquery/docs https://firebase.google.com/
反思我们如何处理人工智能问题
原文:https://towardsdatascience.com/rethinking-how-we-approach-ai-problems-909dad4a7f3d?source=collection_archive---------38-----------------------
让我们关注数据

图片通过 Canva 在 下一次设计使用许可 给作者。
当我们谈论机器学习和人工智能时,在大多数情况下,我们会谈论我们用来处理分类或回归任务的模型:一些专家承诺他们对集成模型的忠诚,如梯度增强决策树。其他人则通过微调高度复杂的神经网络架构来试试运气。有些人甚至更进一步,试图两全其美,将各种模型堆在一个巨大的黑盒子里,以获得尽可能高的准确度。
但是为什么从来没有人谈论数据呢?

图片通过 Canva 在 下一次设计使用许可 给作者。
很长一段时间以来,我们经历了一个研究、文献和在线人工智能教程专注于算法和模型的时代,并建议为了成为更好的机器学习专家并取得更好的结果,我们应该使用更复杂的模型,调整超参数,堆叠它们,如果我们目睹过度拟合,那么简单地执行一些正则化。然而,为什么大多数教科书和教程几乎完全忽略了实际进入模型的数据的重要性?我相信是时候进行范式转换了!
人工智能的移动部件

图片 via Canva 根据 一个设计使用许可 给作者。
在一个非常抽象的层面上,可以说人工智能有两个组成部分:经过训练的模型及其代码(例如神经网络)输出一些预测,以及用于训练模型的数据。如上所述,我们目前生活在一个最关注改进模型的时代,例如通过微调参数。来自深度学习的吴恩达。AI 称之为以模型为中心的观点,并将其与他称之为以数据为中心的另一种新方法区别开来。
以模型为中心
在已经讨论过的以模型为中心的观点中,我们首先下载并收集我们可能得到的所有数据,然后开发一个性能良好的模型。基于该基线,数据被固定,并且模型和代码被迭代改进(例如,通过改变模型架构或调整参数),直到达到令人满意的精度水平。
以数据为中心
在以数据为中心的方法中,焦点放在数据上,而不是模型上:在为任务找到一个非常合适的模型后,模型的代码被固定下来,而的数据质量被迭代地提高。这里的主要转变是,处理数据不再是预处理步骤!处理数据不是我们只做一次的事情,而是我们反复改进的核心部分。使用这种方法,数据的一致性至关重要。
“在机器学习生命周期中,没有任何其他活动比改善模型可以访问的数据具有更高的投资回报。”— 戈杰克
变得更加以数据为中心

图片通过 Canva 在 下一次设计使用许可 给作者。
本文的目的不是让你完全忽略你的模型,而是激励你花一些时间处理数据,而不是把所有的东西都投入到模型中。因为毕竟 AI 有两个运动的部分,模型和代码,为什么只专注一个呢?如果你想更多地了解如何变得更加以数据为中心,这里有一些来自吴恩达的指导方针,可以帮助你开始——然而它们中的大多数都有一个共同点:一致性。
一致的 y 标签
数据以多种形式出现,但是监督学习任务的每个数据集的共同点是 y 标签。这些 y 标签或者是自动收集的,或者是在(半)人工注释过程中添加的。然而,它们经常不一致或没有错误,并且模型最终学习到阻碍性能的矛盾信号。
下图描述了大象检测器图像识别任务的不一致标签。为了训练这个检测器,大象的图像被手动标注了边界框。但是哪个选择更正确呢——左派还是右派?如果任务不是数大象,而是简单地判断图像中是否包含动物,那么这两个版本都完全没问题。然而,重要的是如何在训练图像上绘制边界框的方式是一致的,否则,分类器将不能正确地学习。

大象不一致的包围盒注释— 图片由作者拍摄
如何发现不一致?
寻找这些不一致的地方,尤其是当你的数据集很大的时候,是非常耗时的。根据经验,吴恩达指出,如果数据集不超过 10.000 个观察值,寻找不一致之处并专注于数据效果最好。在这种数据集规模下,通过正确的工作流程,可以在合理的时间内发现并手动修复不一致之处,并且与专注于模型相比,可能会在准确性方面产生更大的性能提升。
“从以数据为中心的角度来看,< 10,000 examples” — Andrew Ng
的问题有很大的改进空间。例如:量化改进
如果你有 500 个观察值,其中 12%的观察值被不一致或不正确地标记,下面的方法证明是同样有效的:
- 修复不一致(重新标记数据)
- 收集另外 500 个新观察值(训练集加倍)
来自https://www . deep learning . ai
发现标签不一致的一种方法是使用多个标签,并观察它们如何解释和注释数据。例如,如果你从事一项语音识别任务,你雇用五个人来转录音频序列,以便能够训练你的分类器,不要简单地把你的数据分成五部分,然后看着标签员做他们的工作!最好从一小部分数据开始,向多个贴标机显示相同的观察结果。很有可能你会发现标签员转录音频序列的不同之处,不是因为有些人懒惰或者做得不好,而是因为最初没有建立标准!想象一下同一个句子的这两种转录:

图片经由 Canva 在下一个设计使用许可给作者。
- 转录 1: “嗯……明天要下雨了”
- 转录 2:****明天会下雨
然而,两种转写都没问题,因为对于如何转写填充词(如“uhm ”)没有一致同意的标准,标签中出现了不一致。这些不一致很可能会降低语音识别模型的性能。因此,就如何处理这些歧义做出决定并就标准达成一致是非常重要的。可以想象,您将无法在注释过程之前定义所有必要的标准,并且在注释过程中可能会出现新的不一致。因此,将此视为迭代方法非常重要!
如何修复不一致?
如上所述,修复不一致是一个迭代的方法。一旦您知道数据标签中的不一致,您应该考虑以下步骤作为蓝图:
- 找出 与这些歧义和不一致的例子
- 就标准达成一致,决定如何对其进行标记/处理(例如,在上面的例子中,是否应该转录或省略“uhm”)
- 在专用标签说明手册中记录新标准
只有当标准是可复制的并且用有意义的例子很好地记录下来,你才能确保被雇佣的贴标员或者如果你雇佣其他人来做这项工作,在不确定的情况下知道该怎么做。因此,重要的是,标签说明应包括边界情况、未遂事件和混淆的例子,而不仅仅是明确的假例子。

图片 via Canva 下 一个设计使用许可 给作者。
如果重新标记和修复不一致不是一个选项呢?
有时,例如由于预算或时间原因,不可能修复整个数据集中的不一致。但是,如果您希望充分利用您的数据并坚持以数据为中心的观点,您可以考虑以下选项:
- 收集更多数据(也不总是可行的)
- 使用数据扩充(给现有的观察增加一些噪音和变化)
- 扔掉不一致的和包含太多噪音的例子
- 专注于最有改进潜力的数据子集——使用错误分析
随后,将更详细地讨论最后两个选项。
抛弃观察—从大数据到好数据

**图片经由 Canva 在下一个设计使用许可给作者。
这个选项可能非常违反直觉。但是数据越多并不总是越好!拥有大型数据集只有在它是“好”数据的情况下才有帮助,但是如何定义“好”数据集呢?一般来说,您可以看出高质量数据集的四个特征:
- 一致且不含糊的标签
- 观察涵盖了最重要的案例
- 训练数据有来自生产数据的及时反馈。特别是在数据漂移方面)
- 数据集大小合适(不要太小)
如果你的数据不符合上述标准,你可能要考虑花费一些来改善它,或者如上所述,删除糟糕的观察!“良好”数据和模型性能的关系示例性地(简化)显示在下图中:

图像灵感来自吴恩达,由作者重新绘制和改编
如果你有一个很小的数据集,只有很少的噪声观测值,那么拟合一个稳健的函数(红线)是很困难的(左)。如果您有一个包含大量噪声的大型数据集,那么拟合一个稳健的函数是可能的,并且可能会产生良好的结果(中间)。如果数据质量非常高的观测值很少,在本例中可以拟合最佳函数。
执行错误分析,重点关注要改进的数据子集
如上所述,有时改进整个数据集会非常耗时,尤其是在处理大数据时。此外,正确地确定优先级通常是很重要的,这样可以避免在问题上浪费时间,一旦这些问题得到解决,可能不会真正显著地提高模型的性能。因此,专注于数据子集通常似乎是正确的做法。这里有一些实用的指导方针和选项,您可以在执行错误分析时遵循:
- 在进行分类时,使用混淆矩阵作为工具,首先了解哪个类别表现最差。通常这是更深入调查的良好起点。
- 如果您对人类的表现水平(人类专家如何完成相同或相似的任务)有任何了解,请尝试在错误分析中包含此信息:寻找估计的人类表现水平与您的模型表现之间的最大准确度差距。这个类有最大的改进潜力——因此从修复这个类的数据开始是最好的选择!通常不可能获得对人类性能水平的估计,在这种情况下,尝试寻找相关领域的研究或调查过去制作的机器学习模型的性能!
- 仔细看看错误分类的观察结果,试着看看你是否能找到一个模式。例如,如果您从事图像分析工作,您可以调查错误分类的图像是否显示出某种类型的噪声,例如变化的光照条件、不清晰,或者它们是否可能被错误标注。如果有多种模式的噪音,集中在出现频率最高的一种。
你如何处理噪声是高度依赖于具体情况的。如果在生产中不希望出现噪声(例如,由被替换的旧传感器采集的图像),则可能值得移除或重新标记错误分类的图像。但是,如果生产中会出现噪声(例如,改变照明条件),您可以尝试向数据集中添加更多包含相同噪声信号的图像。第二种选择是人为地增加数据集,例如,使一些现有的图像变亮或变暗。在这两种情况下,您都将为模型提供更多的示例,从中学习,最终提高性能。

图片通过 Canva 在 下一次设计使用许可 给作者。
最后,重要的是要说,误差分析不是一步到位的方法,而是必须是迭代的:训练你的模型,执行误差分析,改进你的数据(子集)和重新训练你的模型。重复此操作,不断提高模型的准确性。
最后的想法和限制
本文向您展示了为什么专注于改进数据而不是模型可能会有回报。此外,还讨论了如何变得更加以数据为中心的准则。但是,任何东西都有一些限制,在这里列出一些限制是很重要的:
- 对于图像、视频或音频序列等非结构化数据,拥有以数据为中心的视图通常更容易。在处理结构化表格数据时,在数据中寻找模式和修复标签通常要困难得多。
- 数据集越大,就越难确保数据集的一致性。在数据集的改进上花费的时间最大,数据集的大小< 10,000 个观察值
尽管本文的重点是建立数据集中的一致性,但这里也必须强调数据科学和要素工程的重要性。使用具有数千个参数的复杂模型不应被用作不执行适当的数据科学和获得对您的数据的真正理解的借口。通常,与忽略数据和使用非常复杂的模型(如神经网络)相比,花更多的时间结合简单的模型分析和修复数据集可以获得更好的性能。最近可以看到的一个趋势是,机器学习专家认为适当的特征工程并不重要,因为神经网络被认为是强大的学习器,不需要这些耗时的步骤。最近,这种趋势已被证明是有问题的,因为预测来自几乎没有可解释性的黑盒模型,机器学习专家通常无法解释为什么模型会预测一些东西。
更多材料
【2021】吴恩达 — MLOps:从以模型为中心到以数据为中心的 AI[PDF]:https://www . deep learning . AI/WP-content/uploads/2021/06/MLOps-From-Model-centric-to-Data-centric-AI . PDF
【2】吴恩达**—与安德鲁关于 MLOps 的对话:Youtube 上从以模型为中心到以数据为中心的人工智能:https://www.youtube.com/watch?v=06-AZXmwHjo&t
【3】深度学习。人工智能**——以数据为中心的人工智能:Youtube 上的真实世界方法:https://www.youtube.com/watch?v=Yqj7Kyjznh4
反思我们如何对抗多重假设检验
原文:https://towardsdatascience.com/rethinking-how-we-combat-multiple-hypothesis-testing-16c4eb912690?source=collection_archive---------19-----------------------
入门
更强大的“在线”方法

由大卫·特拉维斯在 Unsplash 上拍摄的照片
前言
这篇文章不是一篇技术文章,也不是一篇关于控制 I 型和 II 型错误率的所有不同方法的综合文章。这篇文章将假设一些背景知识,并主要集中在激发一个新的范式,以打击多重假设检验问题,并介绍一套工具,在 R and R 闪亮,你可以使用。
背景
如果你以前做过统计或读过关于某项发现的研究论文,那么数字 0.05 应该会让你想起。指的是 0.05 的显著性阈值。这意味着,如果零假设为真,结果有 5%的可能性是“令人惊讶的”。在假设检验中,我们将我们的 p 值与显著性阈值进行比较。p 值是观察结果的概率或更极端的概率,假设零假设是正确的。0.05 这个神圣的数值据说起源于剑桥统计学家 RA Fisher,他在 1926 年提出了当时新颖的统计学意义的概念。他任意选择了这个值,我们可以从他的论文中引用:
就个人而言,作者倾向于将显著性的低标准设定在 5%
点,并完全忽略所有未能达到这一水平的结果。
从那时起,世界各地的科学家基本上都坚持 5%的门槛。如果假设检验返回的 p 值低于 0.05,您拒绝零假设,并得出结论,您有一些证据来支持您的替代假设。如果它高于 0.05,你不能拒绝零假设。
这很好,但是如果你要做很多很多假设测试呢?考虑这样一个场景,我们已经进行了少量假设检验,比如说 20 次,所有这些检验都是真的无效(这在现实生活中我们永远不会知道)。如果我们问自己,由于偶然,观察到至少一个重要假设检验的概率是多少,我们可以计算:

64%是一个相当高的概率,因为在仅仅 20 次测试中,至少有一个重要结果是偶然观察到的,所以你可以想象当我们有 1000 次假设测试时,这个概率会发生什么。一万次测试。一百万次测试。即使进行了 100 次假设检验,正如您在下图中看到的,观察到至少一个重要结果的概率接近 1,或 100%确定性。那我们该怎么办?

传统方法:Bonferroni 和 Benjamini-Hochberg
在统计推断中,我们有两个(通常是相互竞争的)目标。第一是尽量减少犯第一类错误的概率,或者在我们不应该拒绝零假设的时候拒绝零假设。这就是我用上面的玩具例子演示的。过去和现在都有很多关于如何控制 I 型错误率的研究,但在本文中,我将主要关注控制错误发现率和家庭错误率。
区分这两者是最重要的。家庭式错误率(FWER) 是使产生任何类型 I 错误的概率。 Bonferroni 校正通过将每个单独测试的显著性水平降低到 0.05/n 来保证 FWER 将小于我们选择的显著性阈值(让我们使用 0.05),其中 n 是假设测试的总数。
现在是告诉你统计推断的第二个目标的好时机。即最大化功效,或者最小化第二类错误(在应该拒绝零假设的时候没有拒绝)。管理这两个目标是一个持续的平衡行为。众所周知,Bonferroni 的修正非常保守,这意味着我们可能会错过潜在的发现,因为我们设置的显著性阈值太严格了。
因此,我们可能要考虑控制一个不同的指标——错误发现率(FDR) ,或者错误拒绝占所有拒绝的预期比例。它必然不那么严格,因为现在我们可以接受一些假阳性的数量,而通过控制 FWER,我们不希望有任何假阳性。这种思维方式的转变是可以接受的,尤其是在基因组学等领域,我们在数百万个基因中进行测试。通过控制 FDR,我们拥有了更高的统计能力,或发现重大发现的能力。一切都好,对吧?
这个引导性问题的答案是其实不是。在我们现代的数据密集型时代,有两个主要挑战。
- 随着时间的推移,对相关数据进行假设检验的次数是未知的,并且可能非常多
- 数据存储库被越来越多地使用,并随着时间的推移而增长。
这两个挑战都是由于当前的科学研究范式而表现出来的——通常,不同地方的许多团队都在研究同一个问题。这意味着对于任何给定的团队,没有人知道有多少假设被测试。约翰·约安尼迪斯在他的著名论文“为什么大多数发表的研究结果是错误的”中陈述了这一点。
一项研究发现不太可能是真的……当更多的团队参与到一个科学领域来追求统计意义时。
事实证明,许多研究人员很可能仍然在一个离线设置中控制多重假设检验。它指的是多重假设检验程序(比如 Bonferroni)一次考虑所有 p 值的设置(还记得在 Bonferroni 中我们除以总假设检验的次数吗)?那么,谁知道假设检验总数是多少呢?这是你的研究小组做的所有测试吗?是大纽约地区的所有测试吗?怎么会有人知道?如果不考虑之前的发现,我们到底在控制什么?在某些研究领域将其结果存放在公开可用的数据存储库中的情况下,固定的显著性阈值无法适应不断增长的假设数量。
新方法:在线控制
我们现在已经达到了我们的主要动机——在现代数据时代,假设检验已经采取了一种不同的形式,我们称之为在线设置。它的定义为:
假设连续不断地出现。在每一步,研究者必须决定是否拒绝当前的无效假设,而不需要知道假设的数量(可能是无限的)或未来的 p 值,而仅仅基于以前的决定。

到达数据流的假设示意图
一个不断发展的研究领域已经出现来解决这个问题,我有极好的机会加入这个跨越美国和英国的不断发展的社区并做出贡献。我帮助开发了一个 R 包,其中包含各种在线控制 FDR 和 FWER 的算法以及一个闪亮的应用程序,使非编码人员可以轻松使用这个包。

标志
这些算法背后的数学是非常技术性的,所以请记住以下好处:
- 你可以利用你的领域知识对假设进行排序,以增加统计能力(通过首先拒绝某些假设),同时仍然控制你的 I 型错误。这样你就能更好地实现上述两个目标!
- 这些算法使用显著性阈值,比如说 0.05,作为一种支出预算,其中你花费 0.05 的一部分来执行假设检验,如果你有所发现(拒绝零假设),你就可以拿回一些“财富”!
- 最后,如果你在我们当前的科学时代坚持传统的方法,你很可能会得出错误的结论。

阿尔法财富如何运作的高级示意图
在 R 中做
如果你已经做到了这一步,并对亲眼目睹这一奇迹感到兴奋/好奇,这里有一份如何开始的清单。
- 阅读我们的快速入门指南
- 让你自己熟悉一些我们的算法,它们有什么不同,以及在什么情况下你应该使用它们
- 下载包或者打开我闪亮的应用,这样你就可以开始在线控制了
- 如果你想了解更多关于这个包的信息,请看这篇文章。如果你对所有血淋淋的数学细节感兴趣,请参阅我们的插图中的参考文献部分。

onlineFDR 探索闪亮应用截图
作为这些算法的一个例子,让我们看看 SAFFRON 算法在模拟假设测试的样本数据集上做了什么。
请注意 Bonferroni(技术上是 Bonferroni 的一个版本,说明了无限假设测试,这就是为什么你会看到它是非常数)如何随着测试的增加而变得越来越保守,但 SAFFRON 处理信息的方式要聪明得多,当它有所发现时,可以获得一些“预算”。这样,我们能够保持我们的力量,同时也最大限度地减少我们犯的第一类错误。
总结想法
多重假设检验是统计推断的核心问题之一。可重复性、出版偏见和“p-hacking”是阻碍良好研究和科学进步的障碍。在我们的大数据时代,随着世界各地的研究小组进行越来越多的假设测试,所有研究人员开始转向更准确和有效的错误测试框架变得越来越重要。所以,我希望你们仔细考虑一下 0.05,更仔细地考虑一下如何控制它。
重新思考我们如何教 tidyverse
原文:https://towardsdatascience.com/rethinking-how-we-teach-the-tidyverse-da09a3a23934?source=collection_archive---------29-----------------------
从一个 tidyverse 粉丝的角度尝试“不偏不倚”的观点

由 Kelly Sikkema 在 Unsplash 上拍摄的照片
我最近参加了一个相对流行的堆栈溢出“竞赛”(“流行”在堆栈溢出上到底意味着什么??),其中的提示是为所呈现的解决方案编写一个更“优雅”的dplyr或tidyverse解决方案。
问题陈述要执行两个回归:1) dep ~ cov_a + cont_a + cont_b和 2) dep ~ cov_b + cont_a + cont_b。
这是最初发布的代码:
map(.x = names(df)[grepl("cov_", names(df))],
~ df %>%
nest() %>%
mutate(res = map(data, function(y) tidy(lm(dep ~ cont_a + cont_b + !!sym(.x), data = y)))) %>%
unnest(res))
这是提供的样本数据集:
set.seed(123)
df <- data.frame(cov_a = rbinom(100, 1, prob = 0.5),
cov_b = rbinom(100, 1, prob = 0.5),
cont_a = runif(100),
cont_b = runif(100),
dep = runif(100))
如果你愿意,可以在这里暂停一下,试着想出一个有趣的解决方案!
如果你对tidyverse一点都不熟悉,那么我建议你跳到下一节,在那里我会对它做一个更全面的概述。但是请原谅我,因为我想用这个例子来说明我从tidyverse中意识到的一个基本问题。
我发布了一个初步的解决方案。然后有人贴了 3 个解决方案。然后又提出了 4 个独特的tidyverse解决方案。那就是一共有 9 种不同的方法来解决函数化生成两个回归模型的问题(包括最初发布的解决方案)。
这是什么意思?8 个方案是不是太多了?有这么多方法来解决一件事是好现象吗?让我们深入研究一下。
什么是潮汐?
看待tidyverse的一种方式是将其视为哈德利·威克姆的创意。tidyverse是一组不断进化的 R 包(如dplyr、purrr等)。)旨在提供一个统一界面,允许“整洁”的工作流。这个“整洁”的概念建立在整洁数据原则的基础上,我已经包含了一个链接。简而言之,整齐的数据有三个特征:
- 每个变量形成一列
- 每个观察值形成一行
- 每种类型的观测单位形成一张表
“整洁”的工作流程背后的渴望更难定义。哈德利目前将其概念化为四个主要原则:
- 重用现有的数据结构
- 用
%>%又称“管道”来组合函数 - 使用函数式编程
- 为了使代码更易于阅读
要阅读更多关于他对每个原则的想法,请查看他的宣言。
那么,有争论吗?
是的,外面有持不同政见者。我个人不是其中之一,但我想我明白他们来自哪里。一个受欢迎的异议者是诺姆·马特罗夫,他写了一篇马丁·路德式的 95 篇论文,阐述为什么推广 T2 是倒退。他引用的最大原因是可教性——T3 让 R 变得更难学,并且阻碍了基本的 R 知识。
我不认为我完全同意这一点。
Matloff 列举了教授tidyverse困难的两个主要原因。
- 它的认知超载了
- 它掩盖了传统的编程技巧,并且是反直觉的(后来我有机会与 Norm 交谈,他澄清了第二点,意思是 tidyverse 哲学强调“函数式编程”)
以下是我对他第一点的看法。
以我前面提到的堆栈溢出为例。有九种不同的基于 T5 的方法来做某事。因为tidyverse是由系列包组成的,解决一个数据争论问题更像是建造一个乐高房子,而不是修理一个堵塞的水槽。在后者中,可能有一个标准的最佳方式,而在前者中,有一些更深层次的东西——有一种创造力、艺术的感觉。你不仅仅是在建造一所房子,你还想让它尽可能的稳定,尽可能的漂亮。也许你想尽快建立它。你可以实现很多不同的目标,而tidyverse试图给用户提供这些构建模块。
但是我明白,如果你有大量各种各样的积木,很难建造一个乐高房子——你需要说明书。不幸的是,因为tidyverse在不断发展,所以很难编写说明书。例如,*_at()和*_if()功能被across()取代。代替gather或reshape包,我们现在打算使用pivot_*()函数。可能很难跟上。你的代码可能会在几个月内迅速过时——它仍然可以工作,但会过时。
以下是我对他第二点的看法。
有趣的是,几乎我所有在大学学习计算机科学的朋友,学习 C 或 Java 之类的语言,都抱怨 r。它绝对是一种奇怪的编程语言。但是,R 仍然保持了许多与其他编程语言相同的逻辑和语法。
然而,在tidyverse中我们有类似%>%的东西。对于门外汉,这是一个 WTF 时刻。
突然,像这样的事情:
c(1,2,3) %>% mean()
工作,尽管它完全不同于任何其他类型的“传统”编程。但是,Matloff 的观点是,这对于完全的编码初学者来说很难理解。(编辑:Norm Matloff 已经阐明了他对管道的观点,即“对于一个变量的函数来说,管道很好(尽管不是有益的),如果有多个变量,就非常混乱了”,并强调函数式编程很难掌握(我同意这一点),因此对于初学者来说,将此作为“他们学习的关键”是不合理的,这一点我理解)。有大量的证据围绕着所谓的歧义容忍度和语言学习。基本上,适度的歧义容忍度与提高学习第二语言的能力相关。我认为我们应该更加相信学生对歧义的容忍度,并且相信一个完全的新手不会被tidyverse语法完全弄糊涂。当然,我并不是说学生根本不应该学习基本的 R 语法。我认为$操作符,索引一个向量,写循环,等等。是非常有用的技能,我全心全意地支持它作为学生 R 教育的核心部分。但是,我想说的是,我认为我们应该容忍tidyverse带来的看似陌生的东西。
那么我们该怎么教呢?
我认为堆栈溢出问题让我意识到没有一种通用的编码方法。人类可读是什么意思?我们在乎速度吗?我们应该只使用最常用的功能吗?然而,这些可能是以后在学习 r 的层次中要问的问题。记住,初学者的基本需求通常是从输入到输出。我认为教tidyverse的一种支持方式是:
- 设置标准课程,教授基本的核心 R 概念,并在此基础上构建
tidyverse词汇来处理数据(毕竟,R 是一种统计编程语言)。比如,使用这本网络教材。 - 强调一些功能可能已经过时,但是学生需要一个基础词汇来开始做事情
- 强调很少有完美的解决方案。使用
tidyverse就像说一种语言,它不仅有功能,而且是一种交流方式。学生应该可以很好地学习交流,非常基础,但流利,并建立他们的技能,更漂亮,更流利地表达代码
编辑:最终由学生个人决定他们的教育旅程。我在这篇文章中公开表明了自己的立场,我和 Norm Matloff 以及其他人就不同的观点进行了精彩的富有启发性的对话。我鼓励学生以对他们有意义的方式塑造他们的学习方法(无论是否通过 tidyverse!)
重新思考数据科学家、工程师和架构师的角色
原文:https://towardsdatascience.com/rethinking-the-roles-of-data-scientists-engineers-and-architects-9da1ca06e203?source=collection_archive---------32-----------------------
这些措辞说明了什么角色,以及为什么一些公司应该重新思考他们的方法和对数据项目的期望

在 Unsplash 上拍摄的 ThisisEngineering RAEng
“数据科学家”的角色已经存在了大约 10 年,不久之后,人们认识到需要一个“数据工程师”的额外角色来支持稳定的进步。最后,“数据架构师”需要编排多个团队和系统之间的交互。但是这些角色都是关于什么的,他们之间的区别是什么?实际上,这些角色并没有标准化的定义,对它们的解释几乎总是取决于需求、技术以及最终每个公司的文化。但是当你开始思考这些术语,这些词语本身,对这些角色的一个坚实的解释变得几乎立即可见。
在本文中,我们将深入分析这些角色,并为每个角色的可交付成果设定明确的预期——其中一些可能会让一些公司(或更具体地说,他们的经理)感到惊讶。这将有助于加强经理和候选人的理解和期望。
一句话里有什么
让我们暂时忘记我们正在谈论的数据业务中的角色(即“数据科学家”),让我们专注于每个角色的第二个词:科学家、工程师和架构师。这些角色已经存在了几个世纪,回到它们的基本定义并将它们应用到软件和数据产品中确实是值得的。
1.科学家
科学家在几乎每一项技术进步开始的地方工作。从本质上来说,科学家的工作就是用他的创造力来产生和探索新的想法。他在实验室里度过他的工作日(无论是化学或生物学的真实实验室,还是数学或社会科学的虚拟思想实验室)。
科学家任务
基本上,一个科学家有两个重要的使命:第一,他从各种来源系统地收集信息和知识,第二,他结合信息和扩展知识以产生新的想法。
典型的科学家利用他的创造力在给定的环境中探索新的概念和想法,或者达到一个特定的目标,有时只有一个粗略的方向可以遵循。这取决于研究的目标:它应该用于在短时间内推动公司向前发展所急需的新产品,还是作为更具战略性的长远计划的一部分?
例如,在移动领域,一位科学家可能致力于改进明年汽车模型中使用的电动机的细节。在这种情况下,环境是由管理层设置的,以便实现一些短期的改进。另一位科学家可能会考虑慢慢改变习惯(例如,由于家庭办公的增加)以及这些习惯如何影响未来对移动性的总体要求。
科学家方法论
科学家收集和扩展知识以及研究新思想的特殊责任需要一种适当的方法。在科学家的定义中,科学委员会已经给出了如何完成这项任务的强有力的提示:“科学家是系统地收集和使用研究和证据,提出假设并进行检验,获得并分享理解和知识的人
这个定义本质上总结了科学方法,它是建立在观察、假设推断和使用合理的方法如统计测试来测试这些假设的基础上的。这种方法是由“试错法”主导的,但相对于软件开发来说,这是一种非常积极的方式。研究总是探索,而探索(根据定义)总是意味着尝试新事物,而事先不知道结果。这种方法的一个重要结果是,科学家总是准备好他建立在一系列假设基础上的理论被证明是错误的。从商业的角度来看,这意味着“做科学”总是包含着不可忽视的失败风险。
除了产生新的想法和理论,每个科学家的一项重要活动是与其他研究人员交流想法。这可以在会议上完成,但即使阅读一篇论文也已经说明了这种活动。这种类型的交流(无论是双向的会议还是单向的阅读)也有助于获得和培养形成和测试新假设所需的理论知识。
科学家的责任
科学家的主要职责是探索和发现。科学家的主要目标是为未来铺平道路,例如通过分析社会趋势的影响或通过探索新技术来满足新要求。
在这一点上,特别重要的是要明白,科学家并不负责把一个想法变成一个产品,相反,他正在进行他的研究,作为下一步的理论基础。当然,他应该参与将他的想法产品化,但只能以专家和顾问的角色。
科学家教育与人格
科学家的目标和方法都需要适当的教育,但也需要一定的个性。科学家应该有很强的学术背景(即他应该拥有硕士学位或博士学位),以确保他在系统研究和应用科学方法方面经验丰富。这意味着他可能(这可能取决于领域)也需要扎实的统计学教育作为假设检验的主要工具。
一个科学家需要强大的毅力,加上几乎无止境的好奇心和很大一部分创造力。每当他经历研究固有的许多失败之一时,这些特性帮助他再次摆脱困境。
最后,每个科学家还需要成为一个强有力的沟通者:一方面,他需要说服其他人相信并支持他的想法,以确保他正在进行的工作的资金基础。另一方面,一个科学家也需要知道如何简化他的新的可能复杂的发现,以便向广大非专业观众解释它们和它们的影响。
2.工程师
科学家发现新的见解后,工程师会将想法转化为实际产品。一般来说,工程师可能会使用同一家公司的科学家的成果,或者他甚至会对给定的任务进行一些文献研究,并从其他科学家那里获得想法。
工程师任务
工程师的主要职责是为一个特定的问题创造一个解决方案设计。在软件领域,工程师通常也负责实现,而在其他领域,这可能是其他技术人员的责任。解决方案设计应该提供适当级别的抽象和概括,这样它就可以在类似的案例中重复使用,并为科学家未来的工作提供可靠的基础和工具。
为了创建解决方案设计,工程师要么基于科学家的成果,要么(当没有科学家时)对类似问题的解决方案进行研究。这些结果可能只构成解决方案设计和最终产品的一小部分,但却很重要。许多重要的部分将从科学家的结果中消失,因为所有这些细节已经被很好地理解,不需要科学家做任何额外的研究。但是工程师必须包括所有这些部分。
例如,科学家可能已经实现了一种新的算法(无论是用于机器学习还是其他完全不同的东西),但它可能不是尽可能高效(就所需的能量或时间而言),并且它可能根本无法扩展到集群中的多台机器。这些都是工程师必须注意的重要方面。最终,工程师将不得不构建一个应用或产品,其中包括一个用户界面或 API,可能还有监控或日志等等。所有这些额外的部分都很容易理解,以库的形式存在,所以不需要科学探索。
工程师方法论
科学家和工程师的任务有一些不可否认的重叠(例如文学研究),但他们的方法不同。科学家遵循“科学方法”进行探索和发现,工程师遵循“工程设计流程进行解决方案设计。措辞已经暗示了工程师遵循一个过程,而不是科学家,他们主要使用单一的方法。
工程设计过程从解决类似问题的基础研究开始——这可能需要包括比科学家所关注的更多的方面。在软件领域,这可能包括研究合适的编程语言、库、设计模式等等。找到合适的设计模式的一个关键部分是对给定问题进行抽象和概括,以检测其基本结构。同时,一个工程师还需要从产品专家那里收集所有的需求:解决方案到底应该包括什么,谁会是它的用户,应该如何使用它?
当这两个步骤完成后,工程师将验证可行性,以确保给定的问题可以用现有技术解决。如果在这一点上有差距,科学家可能会帮助弥补。
最后,通过将现有构建模块与定制实施相结合来准备解决方案设计。根据领域的不同,实现也是工程师的职责,但在大多数情况下,熟练的工匠和工匠会接手(在软件开发中通常不是这样,尽管有“软件工程师”和“程序员”的角色)。
工程师的职责
工程师的主要职责有两个方面:首先,他需要构建工具和基础设施来支持科学家的工作。这些工具需要足够通用,以便科学家能够以新颖的方式组合不同的工具进行创新。
工程师还负责从科学家那里获得结果,并设计出目标受众可用的工作产品。产品不仅应该包含和实现科学家的想法,还应该满足许多非功能性的需求。例如,它不应该因为错误的使用而立即损坏,它应该是最终用户使用的一种乐趣。
对于软件世界来说,这意味着产品应该有一个用户友好的用户界面,当出现问题时,它不应该崩溃,而是呈现有意义的错误信息。
工程师教育与个性
为了能够承担他的责任,工程师也需要足够的教育和适当的知识。具体来说,他应该有好奇心去学习新的东西,并且精通应用他领域的最新技术。一个工程师需要理解和处理所有的需求——包括功能性的需求(“产品应该做什么?”)和非功能性的()“用户应该如何与产品互动?”、“产品将用于何种环境?”等)。因此,工程师需要非常彻底地工作,他应该(至少有一点点)痴迷于细节,以构建稳定和令人愉快的产品。
与科学家相比
显然,科学和工程在方法论上有重叠。但是有一些关键的区别:工程学是在阐述一个可以通过设计解决的问题,而科学是在阐述一个可以通过研究解决的问题。根据维基百科,“工程过程和科学过程的关键区别在于,工程过程侧重于设计、创造和创新,而科学过程强调发现(观察)。”
3.建筑师
最后,我们有一个建筑师的角色。根据维基百科的经典含义是“规划、设计和监督建筑施工的人”。当然,我们在这里不仅对建筑物的建造感兴趣,更感兴趣的是建造物品或产品的总体任务。我认为,任何涉及许多不同学科的足够复杂的任务都可以从本文所描述的架构师角色中受益。
架构师任务
我们可以简单地将传统建筑师定义中的任务概括为一个通用的概念:建筑师计划、设计并监督产品的建造。并不是所有的产品都需要这个角色,在许多不同的领域中,这些职责由一些(项目)经理来承担——这完全没问题。我认为,即使是古典建筑设计师也是某种形式的管理者,因为他是监督施工的人。
正如定义所暗示的,建筑师有三项重要任务:设计、规划和控制。在第一阶段,架构师必须收集最终产品的所有需求,并创建一个技术设计来满足这些需求。这个设计是一个相当高层次的设计,它将整体结构描述为一个解决方案设计,包括许多关于使用的技术和材料的基本决策。架构师必须决定所有在项目进行过程中很难改变的东西——这可能是他与工程师不同的一个重要方面(稍后将详细介绍不同之处)。虽然工程师应该能够采用他的组件设计来适应变化的需求,但是架构设计更多的是关于需要哪些组件以及如何组合在一起。在工作开始一段时间后,如果不拆除已经构建的部分,这些架构决策通常很难改变。
在第二阶段,架构师必须计划如何实现设计。这并不意味着他现在将开始研究所有的技术细节,相反,他应该关心构建最终产品所需的技能以及组件的构建顺序。这一阶段的结果是一个粗略的计划,说明需要在什么时候做什么,需要多少人力和物力。
最后,在第三个也是最关键的阶段,建筑师必须监督施工。虽然实现和构建本身是由工程师和额外的工作人员执行的,但是架构师必须验证所有的工件都是根据他的高级设计构建的,并且所有的组件最终都能够装配在一起。在许多情况下,原来设计的一些细节并不像预期的那样,所以微小的设计调整是必要的,但是整体结构不应该有太大的变化。
建筑师方法论
建筑师也要遵循工程师的工程设计流程,只是层次更高。架构师不应该像科学家一样遵循试错法(记住,架构的改变是困难的,因此非常昂贵)。相反,他应该创建一个支持预先收集的所有需求的设计。
建筑师的责任
架构师肩负着非常重大的责任,因为他的基本设计决策对产品是否可以构建以及是否可以在计划的范围和时间内完成具有最大的影响。架构设计的结构和技术通常也会对包括工程师在内的施工团队的形成产生直接影响。改变设计结构可能需要建立新的团队——这是每个公司都试图避免的代价高昂的一步。
在最初的设计和规划阶段完成后,建筑师还直接负责施工过程中的设计。他负责构建质量符合他的期望,并且适合于满足给定的要求。架构师可能必须为团队设定技术规则,说明需要如何构建各个组件。
建筑师教育与个性
一方面,建筑师负责创建整体设计,另一方面,他需要监督施工。这两项义务也要求非常扎实的教育。架构师需要了解广泛的技术,以便能够选择合适的技术。他需要知道他为设计考虑的每一种选择的优点和局限性。
由于可用技术的数量随着时间呈指数增长,没有人能指望一个人知道所有这些技术的所有细节。对于建筑师来说也是如此。因此,即使他密切关注市场的新趋势和新技术,他也需要咨询真正了解所有重要细节、优势和局限性的专家。
为了履行监督施工的义务,建筑师还需要提供技术领导,他经常发现自己扮演着导师的角色,不仅要解释“是什么”,更重要的是解释他的设计决策的“为什么”。因此,除了适当的教育,沟通和学习是成为一名成功的建筑师的关键。
与工程师的比较
工程师关心的是一个可实现的解决方案设计,包括所有讨厌的技术细节,而架构师的角色是更高层次的。架构师还需要了解许多技术和框架的能力和属性,但是他不需要知道如何在这些技术之上构建产品。架构师的职责是展望全局,重点关注多个系统和技术之间的交互,这些系统和技术是整个公司的基础。他将做出最基本的决定,决定使用哪种技术堆栈以及数据应该如何在它们之间流动。他与工程师一起构思宏伟的计划,工程师是他的具体技术顾问。
将角色映射到数据域
到目前为止,我们探索了“科学家”、“工程师”和“架构师”这些角色在任何特定领域之外的一般含义。现在,让我们尝试将获得的见解应用到数据领域,在这里,我们有几个由这些基本个性组成的不同角色:
- 数据科学家
- 数据工程师/机器学习工程师
- 数据架构师
其中一些角色的职责重叠,并非所有的数据公司都有或者甚至不需要为每个角色配备专门的人员。
有趣的是,在过去的几年中,我们可以看到“数据科学”和“机器学习”之间更明显的区别,这变得很有必要,因为所需的技能集重叠但不同。虽然数据科学家应该具有非常广泛的知识,包括概率论和统计学,但机器学习科学家应该具有不太广泛但更深入的知识,特别是在深度学习领域,这是数据科学中越来越重要且发展非常迅速的子领域。因此,也许今天甚至有一个“机器学习科学家”,尽管我从未明确看到过这个角色。
数据科学家
交给数据科学家的任务确实应该要求科学方法取得进展。这意味着数据科学家的大部分工作是对给定数据的特定属性提出假设,并通过实验接受或拒绝它们。此外,数据科学家也可能参与探索从数据中提取相关信息的新算法。这意味着数据科学家可能会忙于分析客户数据,以获得对他们行为的新见解,或者他可能会研究下一个用于识别猫和狗的深度学习架构。
由于这项工作在很大程度上依赖于实验和探索,数据科学家将更喜欢在 Jupyter 和 R Studio 这样的交互式笔记本上工作,它们比传统的编程环境更好地支持试错法。出于同样的原因,科学家会更喜欢像 Python 和 R 这样的解释型语言,而不是编译型语言,以便最大限度地减少周转时间,如果每次修改都需要一个编译步骤,然后重新启动程序,那么周转时间会大得多。
数据科学家将严重依赖统计包来测试关于数据分布的假设,但他也将使用库和应用程序来进行数据可视化。最终,他可能还会使用机器学习和深度学习库来研究预测和推理任务的强大模型。
数据工程师
数据工程师是专门研究数据主题的软件工程师。典型的数据工程师有两项重要的工作:第一,他必须为数据科学家建立一个可靠和愉快的工作环境。该任务包括通过构建适当的数据管道来提供所有需要的数据,还可能包括构建适用于典型分析任务的集成模型(应该想到术语“https://en.wikipedia.org/wiki/Star_schema”【宽表】)。可能大多数人在想到数据工程师时都会想到这个方面,但是这个角色不仅仅是构建数据管道和为数据科学家提供环境。数据工程师还负责提供工具和其他构建模块,以支持和简化数据科学家的工作。
数据工程师的另一项重要工作是(或者应该是)将数据科学家的任何成果转化为工作产品。当数据科学家使用科学方法探索可能性时,数据工程师将获得科学家的结果,并应用工程设计流程来提出一个可靠的应用程序,该应用程序从本质上实现并嵌入科学家的想法到更大的应用程序中。也许不是所有的人都会同意这个责任,但是因为工程师是技术和设计方面的专家,派一个科学家去做这项工作是粗心的。
数据科学家和数据工程师在方法论上的差异也反映在工具上。当科学家花大部分时间在交互式笔记本上时,数据工程师使用成熟的 ide 并遵循软件开发的最佳实践,如创建可靠的软件设计、使用类型安全的编译语言、实现单元测试和集成测试等等。
由于数据工程师的职责是构建一个生产就绪的应用程序,所以他也熟悉相应的技术:Spark、Scala、Java 是他实现数据管道的最好朋友,但他也知道关于 Hadoop、Docker、Kubernetes 以及可能作为典型部署目标平台的云服务的许多细节。
机器学习工程师
机器学习工程师的角色是相当新的,它的职责以前是数据工程师工作的一部分。但由于大规模机器学习在数据管理和模型部署方面有其自身的挑战,需要特殊的工具和框架来解决,因此将这一角色从数据工程师中分离出来是有意义的。
与数据工程师类似,机器学习工程师是专门研究机器学习主题的软件工程师。主要职责是为机器学习科学家提供适当的研究环境,这是简单数据科学家所需的超集。像“训练数据的版本控制”和“模型部署”这样的主题更具体地针对机器学习,而不是通用数据科学。因此,机器学习工程师主要需要解决这些主题,而数据工程师则提供输入数据。
为了履行这些义务,机器学习工程师应该了解为数据科学家提供环境的基础设施主题,包括数据版本控制和简单模型部署。具体到第二部分,机器学习工程师也应该是软件开发人员,能够从数据科学家模型构建生产就绪的应用程序(可能是 REST 服务),这需要数据科学家的语言和框架知识,如 Python、R、Keras、Tensorflow。他可能还需要了解 Kubernetes 作为模型部署的目标环境。
数据架构师
最后,数据架构师必须设想数据应该如何在公司中流动。他需要决定划分不同数据域的切入点,以及应该组建哪些团队来构建每个域中的应用程序和服务。
为了满足这些义务,数据架构师需要对业务模型及其需求有非常详细的理解。他对可用应用程序、平台、服务和库的广泛了解使他能够将这些需求映射到合适的技术。他工作的第一个成果是一个粗略的设计,确定了所需的数据域以及适当的技术堆栈。这一基本决策在以后将很难改变——即使有人可以替换一些单独的组件,由单独的团队划分到不同的数据域在以后将很难克服。
一旦数据架构师完成了他的设计,并且团队开始了它的实现,他需要监督进度,并对设计进行小的调整,以防某些东西不能如预期的那样工作。具体来说,他需要通过与其他团队的互动来支持所有团队,以构建一个工作可靠的数据和服务网络。架构师将执行域内通信的规则,包括规定数据传输的类型,如基于 FTP 的文件或基于 Kafka 的消息,以及如何在全球注册中心发布和记录接口。
结论
这篇文章对科学、工程和架构的观点可能与“数据科学家”和“数据工程师”的常见理解有所不同,但我强烈建议通过查看科学家和工程师的更一般定义来理解这些术语。我感觉很多找数据科学家的公司其实是在找数据工程师(他们有技术设计可以解决的问题,而不是探索)。然而,即使有这种观点,ETL 仍然是数据工程师的责任,因为它是一个设计问题。同样,寻找客户行为的新见解也是数据科学的责任,因为这是一个研究问题。
机器学习的事情变得非常有趣,这可能是两者兼而有之:简单且容易理解的问题可以通过设计过程来解决,而文献较少的更困难的问题可能需要发现过程。但即使在后一种情况下,工程师也应该负责为生产建立一个完整的机器学习管道,这也需要涵盖许多非功能性需求,如缩放、监控、日志记录等。
你现在也应该明白,所有的角色都同样重要,但在知识和方法上需要不同的关注点和深度。哪种角色最适合你完全取决于你的技能和个性。只有科学、工程和建筑的结合,才能创造出包含新奇想法的令人兴奋和愉快的产品。
我希望这篇文章能帮助你决定你是想成为一名科学家,一名工程师,一名建筑师,还是介于两者之间。根据角色的期望,方法和工具会有很大的不同,你可能会觉得在一个角色中比在另一个角色中更舒服。但好的一面是,在一个领域内的所有角色都有很多所需的知识,所以当你找到最适合你的技能和偏好时,应该很容易转换到不同的角色。
RetinaNet:失焦之美
原文:https://towardsdatascience.com/retinanet-the-beauty-of-focal-loss-e9ab132f2981?source=collection_archive---------22-----------------------
改变游戏的一阶段物体检测模型!

Unsplash 上 Arteum.ro 拍摄的照片
对象检测已经成为众多领域应用的福音。因此,可以肯定地说,它比其他一些领域更值得研究。多年来,研究人员不懈地致力于改进对象检测算法,并成功地做到了这一点,以至于我无法将 5 年前的对象检测算法的性能指标与今天的进行比较。所以为了更全面的观点,我想建立一个我们如何到达这里的前提。
目标检测

图 1 —目标检测示例(照片由莎伦·麦卡琴从像素拍摄)
对象检测开始时是一个两阶段的实现,在第一阶段检测图像中的对象(定位),在第二阶段对其进行分类(分类)。该过程的早期先驱是 RCNN 及其后续改进(快速 RCNN,更快 RCNN)。它们的实现是基于区域提议机制的,正是这种机制在后来的版本中得到了主要的改进。还有另一种物体检测方法,其中定位和分类在单个步骤中执行。尽管一些网络在早期阶段执行单级对象检测,例如 SSD(单次检测器),但 YOLO 在 2016 年彻底改变了该领域。YOLO 能够用边界框定位物体,并立刻计算出它们的等级分数。由于其令人难以置信的速度,YOLO 是大多数实时应用程序的首选模型。沿着同样的思路,宗-林逸等人发表了一篇论文,“密集物体探测的焦点损失”,其中介绍了一种称为 RetinaNet 的探测器。它胜过当时市场上的所有其他型号。在深入 RetinaNet 的本质之前,我将讨论焦点丢失的概念。
焦点损失
焦点损失被设计为在密集检测器训练期间通过交叉熵损失观察到的类别不平衡的补救措施。我说的类别不平衡是指(或作者指的是)前景和背景类别的差异,通常是 1:1000 的比例。

图 2-交叉熵和焦损失之间的比较
暂且忽略公式吧。考虑γ = 0 的情况,对应交叉熵。如果你观察曲线,你会发现即使对于分类良好的例子,损失也不是微不足道的。现在,如果我加入阶级不平衡的问题,那里有大量的容易否定的东西,它倾向于压倒前景阶级。
为了解决这个问题,作者增加了一个可调聚焦参数的调制因子。因此,焦点损失的公式变为:

图 3 —焦点丢失(作者提供的图片)
如果你注意到,负项和对数项构成了交叉熵损失,γ代表可调参数。如果我考虑一个具有低概率 p_t 的错误分类样本,调制因子实际上是不变的,而如果概率 p_t 很高(容易分类),那么损失函数将趋向于 0。从而降低容易分类的样本的权重。这就是聚焦损失如何区分易分类和难分类样本的。
最后,损失函数还有一个附加项,即平衡因子α。α对应于一个权重因子,该权重因子或者用反向类别频率计算,或者作为交叉验证优化变量。焦点损失公式现在变为:

图 4 —修改后的焦损失(作者提供的图片)
作者(通过实验)注意到焦点损失形式不需要精确。相反,有几种形式可以整合样本之间的差异。
RetinaNet
RetinaNet 实际上是由一个主干网和两个特定任务子网组成的网络组合。主干网络是一个纯卷积网络,负责计算整个图像的卷积特征图。第一个子网对主干网的输出执行卷积分类,第二个子网对主干网的输出执行卷积包围盒回归。总体架构看起来非常简单,但作者调整了每个组件以改善结果。
特征金字塔网络主干
作者实现了由 T. Y. Lin 等人提出的特征金字塔网络(FPN)作为主干网络。FPN 通过横向连接实施自上而下的方法,提供了丰富的多尺度要素金字塔。对于 RetinaNet 来说,FPN 是建立在 ResNet 架构之上的。金字塔有 5 个等级,从 P₃到 P₇,其中分辨率可以计算为 2ˡ,其中 l 对应于金字塔等级,在本例中为 3 到 7。

图 5 —包含单个组件的 RetinaNet 架构
锚
RetinaNet 使用平移不变的锚盒,分别在 P₃到 P₇级别上具有从 32 到 512 的区域。为了加强更密集的覆盖范围,锚增加了{2⁰,2(1/3),2(2/3)}.的大小所以,每个金字塔等级有 9 个锚。每个锚被分配一个分类目标 K 的独热向量和一个盒回归目标的 4 向量。
分类子网
分类子网是附加到每个金字塔等级的 FCN,其参数在所有等级之间共享。考虑通道的数量 C 为 256,锚 A 为 9,分类目标的数量 K,特征图通过具有 C 滤波器的四个 3×3 conv 层馈送。这是继 ReLU 激活和另一个 3×3 conv 层,但与 K×A 过滤器的应用。最后,sigmoid 激活被附加到每个空间位置的 K×A 二元预测的输出。所以,最终输出变成(W,H,K×A),其中 W 和 H 分别代表特征图的宽度和高度。为了获得更好的结果,作者在分类子网的参数不与回归子网共享的地方做了一点修改。
箱式回归子网
如果参考图 5,可以看到分类子网和回归子网同时接收到特征映射。因此,它们并行运行。对于回归,将另一个小 FCN 附加到每个金字塔等级,以回归从每个锚定框到附近地面实况对象(如果存在)的偏移。整个结构类似于分类子网,但区别在于输出不是 K×A,而是 4×A。具体数字“4”代表用于确定偏移量的参数,即中心坐标以及宽度和高度。对象分类子网和盒回归子网虽然共享一个公共结构,但使用不同的参数。
模型的整体流程
让我们取一个样本图像,并将其馈送给网络。第一站,FPN。在这里,图像将在不同的尺度(4 个级别)上进行处理,在每个级别上,它将输出一个特征图。每个级别的特征图将被提供给下一个组件包,即分类子网和回归子网。FPN 输出的每个特征图然后由分类子网处理,并且它输出具有形状(W,H,K×A)的张量。同样的,回归子网会处理特征图,会输出 a (W,H,4×A)。这两个输出被同时处理,并发送给损失函数。RetinaNet 中的多任务损失函数由用于分类的修正聚焦损失和基于回归子网产生的 4×A 通道向量计算的平滑 L1 损失组成。然后损失被反向传播。这就是模型的整体流程。接下来,让我们看看该模型与其他对象检测模型相比表现如何。
情况如何?

图 6 —结果对比
从上表可以明显看出,采用 ResNeXt-101 主干的 RetinaNet 优于之前提出的所有其他两级和一级模型。唯一有 0.9 错误的类别是大型对象的 AP。
我想实现 RetinaNet,我应该注意什么?
当然,每个问题陈述都是不同的,作者建议的一些参数可能不适合你。但是作者进行了严格的研究来获得这些最佳结果。所以,我觉得它们可以很好地解决一般问题,或者至少,它们可以作为一个基本参数集,用户可以进一步调整它们。
- γ = 2 在实践中工作良好,RetinaNet 对γ ∈ [0.5,5]相对鲁棒。分配给稀有类的权重α也有一个稳定的范围,但它与γ相互作用,因此必须同时选择两者。一般来说,当γ增加时,α应该稍微减少。对作者来说,最合适的构型是γ = 2,α = 0.25。
- 使用 0.5 的交集(IoU)阈值将锚点分配给地面实况对象框;并且如果它们的 IoU 在[0,0.4]中,则返回到背景。由于每个锚点被分配给至多一个对象框,所以其长度 K 标签向量中的相应条目被设置为 1,而所有其他条目被设置为 0。如果锚点未被赋值(这可能发生在[0.4,0.5]中的重叠),则它在训练期间被忽略。
- 为了提高速度,在阈值检测器置信度为 0.05 之后,每个 FPN 级别仅解码来自至多 1k 最高得分预测的盒预测。来自所有级别的顶部预测被合并,并且应用阈值为 0.5 的非最大值抑制来产生最终检测。
- 除了 RetinaNet 子网中的最后一个图层之外,所有新的 conv 图层都使用偏差 b = 0 和σ = 0.01 的高斯权重填充进行初始化。对于分类子网的最终 conv 层,偏置初始化被设置为 b = log((1π)/π),其中π指定训练每个锚的开始应该被标记为置信度为τπ的前景。π的值在所有实验中都是 0.01。
摘要
总之,RetinaNet 在推出时对物体探测领域进行了重大改进。一级检测器优于两级检测器的想法是非常不现实的,但 RetinaNet 使其成为现实。从那时起,有许多新的算法被设计来进一步改进这些结果,随着我不断发现它们,我肯定会将它们记录到新的文章中。所以,敬请期待下一期!
我希望你喜欢我的文章,如果你想联系我:
- 我的网站:https://preeyonujboruah.tech/
- Github 简介:【https://github.com/preeyonuj
- 上一篇媒体文章:https://towards data science . com/the-implications-of-information-theory-in-machine-learning-707132 a 750 e 7
- 领英简介:【www.linkedin.com/in/pb1807
参考
[1]密集目标检测的焦损失—https://open access . the CVF . com/content _ ICCV _ 2017/papers/Lin _ Focal _ Loss _ for _ ICCV _ 2017 _ paper . pdf
使用深度学习检索相似的电子商务图像
原文:https://towardsdatascience.com/retrieving-similar-e-commerce-images-using-deep-learning-6d43ed05f46b?source=collection_archive---------21-----------------------
基于从多尺度卷积神经网络学习的嵌入生成图像推荐
目录
1。简介
2。商务问题
3。映射到深度学习问题
4。使用的数据集
5。模型架构
6。损失函数
7。实施概述
8。构建数据管道
9。定义模型架构
10。定义损失和精度功能
11。定义步进功能
12。最终流程
13。验证结果
14。了解部署
15。未来工作&结论
16。参考
- 简介: 视觉推荐对于任何电子商务平台来说都是至关重要的功能。它赋予平台即时推荐与用户正在浏览的产品相似的产品的能力,从而抓住他/她的即时意图,这可能导致更高的客户参与度(CTR ),从而提高转化率。在这个案例研究中,我们试图实现一个研究工作,使用暹罗网络为核心检索类似的电子商务图像。为此,我们将按照下面的论文重复所做的工作。我们将尽量只涵盖有助于我们理解和实现工作的重要部分。如果你不能把这些点联系起来,请随意阅读这篇论文。
- 商业问题: 找到看起来与特定产品相似的产品是现代电子商务平台的重要特征。如果正确利用这些信息,可以提升用户体验和购买转化率。检索给定查询图像的相似电子商务图像可以用于各种场景。一个这样的场景可以是推荐相似的产品,相似性可以是在形状、颜色、图案等方面。所以,我们想建立一个系统,如果用户寻找一个特定类型的产品,得到类似产品的推荐。
- 映射到深度学习问题: 如上所述,我们正在尝试使用从一幅图像中提取的特征来获取(推荐)与那幅图像相似的产品。我们可以通过多种方式来解决这个用例。一种这样的方法是使用多尺度连体网络来识别相似的图像。下图显示了一个简单的连体网络:

作者图片
在暹罗网络中,我们基本上传递 2 对图像,一对属于相似的图像,另一对属于不相似的图像。核心思想是模型基于图像的相似性和不相似性来学习权重。如果我们可以通过使用这样的架构生成嵌入来捕获细粒度的视觉细节。我们其实可以利用这些嵌入来推荐类似的产品。这项工作的主要贡献是一个由多尺度深度 CNN 组成的连体网络,它学习图像的 4096 维嵌入,以捕捉视觉相似性的概念。此外,我们需要确定损失函数,我们将使用对比损失来实现。给定一幅图像,我们将如何处理,首先我们将识别一幅相似的图像,然后是一幅不相似的图像。一旦我们有了这些图像。我们将把这些图像传递给我们的模型进行嵌入。那么这些嵌入将用于计算损失。基于损失值,我们将学习权重,直到我们达到收敛。模型性能将使用精确度来衡量。
4。使用的数据集: 对于这项工作,我们使用了三元组数据进行训练和验证。三元组数据由查询图像、正图像(类似于查询图像)和负图像(相对不同于作为正图像的查询图像)组成。查询图像可以是野生图像(人们在日常不受控制的设置中穿着衣服)或目录图像(模特在受控制的设置中穿着衣服,如电子商务应用程序中所示)。而正图像和负图像可以是类别内的(与查询图像相同的产品类别)或类别外的(不同于查询图像的其他产品类别)。本案例研究中使用的数据由论文作者在下面的链接中提供。他们通过编程从 4 个不同的数据集生成了这些三元组。样本数据如下所示:

作者图片
5。模型架构: 实现了以下架构:

Img 资料来源:https://arxiv.org/pdf/1901.03546.pdf
如已经示出的,暹罗网络包括两个具有共享权重的卷积神经网络,其在训练期间通过最小化损失函数而被优化。其工作原理是,网络将两幅图像作为输入,但我们有 2 对图像,第一对图像相似,第二对图像不相似。因此,对于任何一个查询(锚)图像,我们将有两个以上的图像与之相关联。一个是正像(相似),另一个是负像(不相似)。一旦这些图像对被识别,我们通过网络将这些输入图像映射到嵌入空间。如果相似图像的嵌入距离很近,而不相似图像的嵌入距离很远,那么网络已经学习到了一个好的嵌入。
了解架构的各个组成部分:模型架构有多个部分。第一部分是深度 CNN。深度 CNN 在训练过程中很容易学会将强方差编码到它们的结构中,这使得它们在图像分类中取得了很好的性能。因此,对于这一部分,我们使用类似于 VGG19 的卷积神经网络的架构。该 CNN 用于编码强方差并捕获图像中存在的语义,因为它有 19 个卷积层。在 19 层中,顶层擅长编码图像特征的复杂表示。类似 CNN 的 VGG19 具有高的全向容量,因为它的 4096 维最终层允许网络有效地将信息编码到子空间中。
另外两个 CNN 使用较浅的网络架构来捕捉下采样图像。由于较浅的架构,这些 CNN 的方差较小,用于捕捉更简单的方面,如形状、图案和颜色,从而形成图像的视觉外观。
因此,使用三个不同的卷积神经网络代替单个 CNN,并使它们共享较低的层,使得每个 CNN 独立于其他两个。最后,来自三个卷积神经网络的嵌入被归一化并与 4096 维线性嵌入层组合,该嵌入层将输入图像编码并表示为 4096 维向量。为了防止过拟合,使用了 L2 归一化。
- 损失函数: 对比损失函数是基于距离的损失函数,与基于预测误差的损失函数相反。像任何其他基于距离的损失函数一样,它试图确保语义相似的例子紧密地嵌入在一起。
当相似图像对(标号 Y = 0)被输入网络时,下图的右侧加法部分无效,损失等于包含两个相似图像嵌入之间的正对距离的部分。因此,如果两个图像在视觉上相似,梯度下降减少了它们之间的距离,这是由网络学习的。
另一方面,当两个不同的图像(标签 Y = 1)被馈送到网络时,左边的加法部分消失,等式的剩余加法部分基本上作为铰链损失函数工作。如果图像对完全不相似,并且网络输出其接近度大于 m 的一对嵌入,则损失函数值最大化到零,否则如果图像有些相似,则当存在误差时,我们通过优化权重来触发接近度最小化。
m 值是阴性和阳性样本之间的分离界限,由经验决定。当 m 较大时,它会将不同的和相似的图像推得更远,从而充当边距。在这项工作中,我们使用 m = 1。

对比损失函数
-
实施概述: 研究工作的实际实施可以在这里找到。我们不会复制相同的代码,相反,我们将使用 TensorFlow 2 来实现这项工作,其中我们将使用 tf.data 创建输入管道,并且为了进行训练,我们将创建自定义的训练循环。
-
构建数据管道: 为了构建我们的输入管道,我们将使用 tf.data。数据集 API 允许您构建一个异步的、高度优化的数据管道,以防止您的 GPU 数据匮乏。它从磁盘加载数据(图像或文本),应用优化的转换,创建批处理并将其发送到 GPU。以前的数据管道让 GPU 等待 CPU 加载数据,导致性能问题。部分官方资料来源: API 文档、数据集快速入门、程序员指南、官方博客文章、来自 tf.data 创建者的幻灯片、 Origin github 发布、Datasets API 的 Stackoverflow 标签。
我们的第一个管道方法是获取图像路径,我们从读取输入文件(train/val/test)开始,这些文件包含我们的三元组信息,附加图像存在的实际路径,最后返回包含每个三元组图像完整路径的最终列表。
获取图像路径函数
然后,我们定义两个函数来处理完整的输入管道。这些功能是:
图像解析功能
输入管道
上面的函数使用 tf.data 来定义输入管道。在上面的实现中,我们从一个数组中读取输入文件名,该数组包含每个图像的输入文件路径的细节。然后我们把内容打乱读。然后,我们使用 input_parser 映射读取内容,以获得每个图像的特征向量,然后返回作为数据集对象的最终张量,该张量将在建模期间使用。
- 定义模型架构: 我们已经了解了什么是架构,所讨论的架构的代码实现是:
体系结构
- 定义损失和精度函数: 我们已经讨论过损失函数,下面代码是对比损失函数的损失实现。该函数计算一批图像的损失。对于一个批次,首先计算每对的损失值。一旦我们有了这个值,这个值就被加到最终损失上,然后损失通过除以 batch_size 的 2 倍来归一化。在损失等式中,标签 Y = 1 被分配给不同的或负的图像对,而 Y = 0 被分配给相似的或正的图像对。
损失实现
对于精确度函数,计算一个批次的精确度。如果 neg_dist > pos_dist,它通过批处理获取每个图像、batch_size 和迭代器的嵌入张量,给出值 1,否则给出值 0。它最终返回一个批次的最终精度。
- 定义阶跃函数: 到现在我们已经看到了数据管道函数、模型架构、损耗定义,现在是时候定义封装了网络前向和后向通路的阶跃函数了。为此,我们将使用梯度胶带。tf。GradientTape 允许我们跟踪张量流计算,并根据给定变量计算梯度。GradientTape 是 TensorFlow 2.0 中的一个全新功能,可用于 自动微分 和 编写自定义训练循环 。 GradientTape 可以用来编写定制的训练循环。
在我们的实现中,我们将使用两步功能,一步是训练步骤,另一步是验证步骤。训练步骤是进行实际训练的地方。在我们的例子中,由于我们正在处理三元组,对于一个批次,我们首先找到该批次中每个图像的嵌入,这样我们得到查询、正面和负面图像的嵌入。这种嵌入是使用已定义的模型架构生成的。有了这些数据后,我们将计算该批次的损耗和准确度,然后根据损耗,使用梯度带计算梯度。一旦我们有了这些梯度,我们就使用优化器对象来更新权重。代码实现:
训练步骤
tf.function decorator 用于使 TensorFlow 自动签名工作,并加速其内部操作的执行。当我们第一次调用@tf.function decorator 时,TensorFlow 会首先将它转换成图形,然后执行它,之后,当我们再次调用该函数时,它只会执行图形。验证步骤负责给出一个时期内每一步验证数据的验证损失和准确性。该函数使用模型(用更新的权重训练)来生成嵌入,并且基于这些嵌入,我们计算损失和准确度。
val 步骤
- 最终流程: 一旦定义了所有的帮助器函数,下一步就是定义最终的流程方法,它将负责创建定制训练,它有多个部分,我们将分解这些部分。
我们首先定义训练和验证 csv 文件的路径。完成后,我们生成两个列表,一个包含训练路径,另一个包含验证集路径。这个列表是通过调用 get_image_path()函数生成的。最后,我们使用 tf.metrics.Mean 测量训练丢失和训练准确性
train_csv_file = '/content/drive/My Drive/data/tops_train.csv'
cv_csv_file = '/content/drive/My Drive/data/tops_val.csv'
train_data_path = get_image_path(train_csv_file)
validation_data_path = get_image_path(cv_csv_file)
train_loss = tf.metrics.Mean(name="train_loss")
train_accuracy = tf.metrics.Mean(name="train_acc")
然后,我们将启用 GPU 的使用,然后开始我们的每个时代的流程。在 epoch 循环中,我们首先调用返回数据集对象的 input_pipeline()函数,然后将迭代器链接到这个函数。最后,我们开始逐步训练,步长等于数据点数// batch_size。完成后,我们将调用 step 函数进行训练,我们继续记录在一个时期内每一步训练中获得的分数,最后,当完成后,我们使用验证集来计算损失和准确性,并打印训练和验证的最终结果。模型权重也在每个历元后保存。我们还将分数写入 tensorboard,这可以使用以下代码完成:
with tf.name_scope("per_epoch_params"):
with wtrain.as_default():
tf.summary.scalar("loss", train_loss.result().numpy(), step=epoch)
tf.summary.scalar("acc", train_accuracy.result().numpy(), step=epoch)
wtrain.flush()
with wval.as_default():
tf.summary.scalar("loss", round(np.mean(np.array(val_loss)), 6), step=epoch)
tf.summary.scalar("acc", round(np.mean(np.array(val_accuracy)), 2), step=epoch)
wval.flush()
流程功能的全面实施:
流量函数
一旦我们所有的步骤都定义好了,我们就可以使用下面的代码调用整个流程:
主要功能
在运行 10 个时期后,在第 4 个时期看到了最好的结果,来自该时期的权重然后被用于在验证和测试集上检查模型性能。

培训结果
结果:我们在验证集上得到了 94.19 的准确率。
- 验证结果: 我们已经在验证集本身上定义了一个验证块,它取一批 128 张图像并返回一个分数。它进行 5 次迭代,图像随机取自验证集。除此之外,我们还采用了 5 组不同的三元组,看看模型是否能够正确识别相似的图像和不同的图像。代码实现:
验证块
这可以通过以下方式调用:
执行验证块
上述单元格的结果:

验证结果
- 了解部署: 整个架构可以使用以下流程进行部署:

作者图片
基础模型训练:这是我们在之前的笔记本中看到的部分,我们在那里建立一个管道,并根据可用的训练集进行全面训练,一旦完成,我们将最好的模型重量保存到一个存储桶中(例如:S3)。
在进行增量训练之后,更新的模型权重再次存储在存储桶中。
生成嵌入:一旦我们的训练完成,我们就可以生成我们数据存储库中所有图像的嵌入,为此我们需要首先从数据存储库中加载所有图像,并加载模型权重,然后基于此生成最终嵌入。
colab 中使用了以下函数来描述部署:
对于任何查询图像,调用该函数来生成对应于该图像的嵌入…
输入管道函数使用此函数来映射图像路径,并将它们转换为表示图像的张量
这是我们的输入管道函数,它实际上读取所有图像路径,并用于最终为图像库中已经存在的所有图像生成嵌入
在上面的单元格中,我们首先定义图像出现的路径,然后生成 2 个列表,一个用于查询,其余的用于图像。一旦完成,我们正在加载最佳模型的重量。然后,由于内存问题,我们通过批量大小为 128 个图像的数据集进行迭代,以生成大小为 28,4096 的张量。最后,我们将所有这些张量连接起来,以嵌入图像库中的所有图像。
以上代码是余弦相似性的简单实现,当给定两幅图像的嵌入时,这将返回这些图像有多相似,值越高,图像越相似。
上述函数用于查找查询图像的前 n 个相似图像。给定一个基于余弦相似性的图像,它会给出该图像的索引和它与该查询图像的得分,最后根据 k 的值,它会返回与基于图像嵌入之间余弦相似性的查询图像相似的前 k 个图像。
在上面所有图像的单元格中,我们实际上找到了前 10 个 NN,并将结果存储在最终列表中。测试样品上看到的结果:

作者图片

作者图片
-
未来作品& 结论: 以上结果是在亚马逊一些报废的 16k 图片上。这些建议似乎不错,我们可以通过增强图像来进一步提高性能。整个实现分为 3 个部分。一个简单的 EDA 上的数据,我们有,培训实施和推理(部署步骤)。你可以在这里找到完整的代码。
-
参考文献:
https://www.appliedaicourse.com/https://arxiv.org/pdf/1901.03546v1.pdf
https://medium . com/predict/face-recognition-from-scratch-using-siamese-networks-and-tensor flow-df 03 e 32 F8 CD 0
https://cs230.stanford.edu/blog/datapipeline/
https://www . Sri Jan . net/blog/building-a-high-performance-data-pipeline-with-tensor flow
你也可以在Linkedin和Github上找到并与我联系。 作品到此结束,感谢阅读!**
自然语言查询中的返回子句
原文:https://towardsdatascience.com/return-clauses-in-natural-language-queries-74a4a2fd53e6?source=collection_archive---------26-----------------------
将 openCypher 的元素整合到 FEQL (FactEngine 查询语言)中

包含 RETURN 子句的 FEQL 查询。图片作者。
FactEngine 是一个从根本上重新思考如何从概念上定义、查看和查询数据库的计划。重点是利用对象-角色建模主干在知识图上提供自然语言查询。典型的 FactEngine 查询如下所示:

典型的事实引擎查询。图片作者。
为了实现查询编写的相对简单性, FactEngine 架构首先要求数据库模式(或者是图形,或者是物理层的关系)被定义为对象-角色模型。
为了证明这一点,我通常会查看一个影院预订数据库的概念模型:

点击放大。ORM 图表示例。电影院预订模式。图片作者。
在的一篇早期文章中,我描述了同一个模式如何被视为一个图表或关系模式,对于外行来说,这看起来像是意大利面条出错了:

属性图和实体关系图之间的态射。图片作者。
论文的关键在于,当使用对象-角色模型覆盖时,关系数据库可以像图形数据库一样用自然语言查询;这是通过尊重图形和关系数据库之间的形态来实现的。
但是有一个小问题
自然语言查询是理想化的,但是处理自然语言查询的软件可能非常难以编写,有时需要使用机器学习的黑魔法式编程来解释自然语言。
机器学习类型安排的问题是,它们没有覆盖超出其训练范围的大量可感知的用例,并且需要就如何处理它们覆盖的用例进行训练。
相比之下,像 SQL 和 openCypher 这样的数据库查询语言,它们的语法可以清晰地表达几乎任何您想对数据库提出的查询。
在我看来,需要使用机器学习来处理自然语言查询是不对的,所以 FactEngine 没有使用任何机器学习,只是一种受控的自然语言,凭借模式本身来适应所研究的模式。在这种程度上,查询语言更接近于新兴的图形查询语言标准。
FEQL(事实引擎查询语言)中的返回类型查询
作为所面临问题的一个例子,最明显的莫过于对我们的影院预订模式提出以下问题:
"每个电影院的每个区域有多少个座位?"
所有形式的机器学习和复杂的试探法都需要将该查询转换为对我们的影院预订模式的机器可解释的查询。
FactEngine 摒弃了令人费解的试探法,而是提供了一种受控的自然语言。
为了获得这个示例的结果,FactEngine 借鉴了新兴的图形查询标准,将 RETURN 子句放在查询的自然语言部分下面…首先询问每个电影院的每个区域有哪些座位,然后返回所需的信息和数量,如下所示:

这感觉有点像作弊,将 SQL 和标准化图形查询语言的元素合并到基于自然语言的查询语言中,但这足够直观,对于熟悉 SQL 和一般图形查询语言的人来说会很自然。
两全其美
为什么要对数据库进行自然语言查询?嗯,因为我甚至不能用 Cypher、 openCypher 或 GQL 编写上面的查询……我懒得学习语法。受控自然语言查询非常容易编写和理解,以至于用自然语言编写的图形查询的好处远远超过了编程工作,最终结果是易于使用和理解……依我看。
在我看来,到目前为止,在数据库上引入自然语言查询的努力是如此复杂和做作,以至于它们似乎永远也不会推向市场,也不会迷失在研究的好奇世界中。我更希望有一门容易理解和实际可用的语言,而不是沉溺于假设和可能的世界。虽然我为研究努力喝彩,但我最深切的感受是,需要有一个分界点,在这里你可以说,“已经够了。我们可以尝试解决世界上的所有问题,或者用一种不那么理想化的方法,推出一些在现实世界中实际可用的东西”。
因此,FEQL 现在包含了一个 RETURN 子句,非常像您所熟悉的图形查询语言,同时尽可能地保留了自然语言查询的理想主义。"每个电影院的每个区域有多少个座位?"可以等到机器学习的努力赶上来。
感谢阅读。如果时间允许,我会写更多关于自然语言查询、对象-角色建模、图形查询和概念建模的文章。
【https://github.com/cjheath/activefacts】NB 本文中表达的模型是 DataConstellation 的原始版权的衍生,正如之前在 GitHub 上的 ActiveFacts 项目下分享的:https://github.com/cjheath/activefacts
— — — — — —结束— — —
带有空间规则匹配器的可重用术语
原文:https://towardsdatascience.com/reusable-terms-with-spacy-rule-matcher-5d60ae5697fe?source=collection_archive---------30-----------------------
匹配者的一个简单技巧

Sheri Hooley 在 Unsplash 上拍摄的照片
我不想撒谎,我真的很喜欢空间。它基于复杂的自然语言处理(NLP ),但使用起来非常简单。这是一个 ML 工程师的梦想(尽管这是一个多么奇怪的梦想)。另外,这也是数据科学家的梦想,因为如何增强底层的 NLP(仍然是一个怪异的梦想)!我几乎每天都要使用它,在这一过程中,我学到了一些技巧,您可能会发现这些技巧很有帮助,第一个技巧涉及到可重用术语。
规则匹配器基础
spaCy(实际上是 NLP)的核心思想之一是单词被分解成记号,这些记号可以被识别(例如,词性)或以各种方式使用。使用令牌的一种特定方式是根据显式标准对它们进行匹配。spaCy 使用 Python 来实现这一点,可以创建模式,将其添加到 spaCy Matcher 对象中,然后对照文本来查找匹配。
例如,假设我想找到“爱吃披萨”这几个词,通过研究我知道人们经常使用这个确切的短语,但是“爱披萨”、“爱披萨”、“挖披萨”、“吞食披萨”和“吃披萨”都表示爱披萨(因为每个吃披萨的人都爱披萨,对吗?).
要为某样东西创建一个匹配模式,比如说“爱吃比萨饼”,我将编写以下代码:
pattern只是 Python 字典条目的列表(尽管字典条目非常特定于空间)。在我的代码中,TEXT指定了我要查找的内容,然后那个键的值就是字面的、区分大小写的文本。列表中字典元素的顺序很重要——换句话说,我不能用这种模式匹配“pizza loves”。然后我将这个模式添加到matcher对象(类型为spacy.matcher.Matcher)中,并给它一个标签(PIZZA_RULE)。然后在我的代码中,我展示了如何使用匹配器从一些文本中输出匹配。
PIZZA_RULE loves pizza
前缀的问题是
这里的问题是,我有一堆非常相关的短语要匹配——实际上只有第一个单词发生了变化,即前缀和。现在我可以为每一个写一个匹配器:
注意,这些模式只改变了第一个单词。这很管用。但是想象一下,我在许多应用程序中使用了这些模式,然后我意识到人们也经常说“崇拜比萨饼”?我可以继续添加更多的模式,但真的有更好的方法。
确实有。
可重用性第一部分
首先,spaCy 中有一种机制,允许您在创建模式时使用IN属性从一个术语列表中进行选择。对于比萨饼模式,看起来像这样:
IN属性允许一个术语列表,这意味着列表中的任何一个单词以及单词“pizza”都是匹配的。非常酷,非常灵活。
可重用性第二部分
现在想象一下,我有另外一系列前缀,它们是单词“order”的变体,表示短语“orders from Amazon”、“order Amazon”、“get from Amazon”、“procure from Amazon”(等等)。).现在想象我在“Amazon”之外的许多上下文中使用这个前缀(例如,“订购比萨饼”)。这种机制不够灵活,因为它是嵌入式模式的一部分。我需要一种方法将这些前缀从内嵌模式中去掉。
这里真正好的消息是,我可以依靠基本的 Python 来解决这个问题。鉴于IN属性只是一个 Python 列表,并且我可以在外部定义一个 Python 列表,整个事情变得非常简单。
首先,我创建了一个名为reusable.py的文件,其中包含了我所有“order”前缀的列表。它只有一行字:
order_prefixes = [‘buy’, ‘get’, ‘order’, ‘orders’, ‘ordering’, ‘procure’, ‘procuring’, ‘purchase’, ‘purchases’]
接下来,我将新的reusable.py文件导入到我的主代码中,代码行如下:
import reusable as terms
最后,我将模式中的列表替换为从reusable.py:导入的名为orders_prefices的列表的引用
pattern = [{‘TEXT’: {‘IN’: terms.order_prefixes}}, {‘TEXT’: ‘from’}, {‘TEXT’: ‘Amazon’}]
最后,我修改了我最初的“pizza”代码,以处理来自 Amazon 的订单,因此我的最终代码如下所示:
以下是输出结果:
简单但强大
这种可重用性“技巧”实现起来非常简单,但是对于在整个组织中创建匹配关键字来说却非常强大。我用 Amazon 显示了“order”前缀,但是我可以用它来处理任何东西,比如 Nick 和 Vito's (pizza)。有了一个集中的术语库,添加/更改/删除它们以及在多种上下文中使用它们就容易多了。
还有谁不喜欢亚马逊和披萨?嘿…我可以从亚马逊买披萨吗?
关于 spaCy 的更多基本设置,请访问 spaCy 网站。
参考
[1]空间,基于规则的匹配(未标明),空间. io
重复使用纸质过滤器冲浓缩咖啡
原文:https://towardsdatascience.com/reusing-paper-filters-for-espresso-ef1899ae2b35?source=collection_archive---------41-----------------------
咖啡数据科学
高级滤纸理论第三部分
之前,我已经讨论过纸质过滤器如何影响流量以及将它们切割成合适的尺寸对它们的效率有多重要。在这篇文章中,我将回答今天的重要问题:我能有多懒?对于浓缩咖啡,我可以使用任意一款纸质过滤器多少次?

我将在几个月的时间里从统计的角度来看这个问题,以及一些与底部过滤器相关的精确例子。
在顶部使用纸质过滤器可以重复使用很多次,但我的机器在顶部使用过滤器时表现更差。对于底部过滤器,一次性使用是最好的,或者在正确的清洗后使用。在这种情况下,第二次使用是非常引人注目的。对于中间的过滤器,似乎在 4 到 6 之间的某处使用它是最佳的。这在进行断续捣固或断续浓缩时使用。
镜头性能指标
我将这些定义放在这里,因为在这一节之后,我将使用这些指标评估不同数量的纸质过滤器。
我使用了两个指标来评估镜头之间的差异:最终得分和咖啡萃取。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难,会影响最终得分。
使用折射仪测量总溶解固体(TDS ),该数字用于确定提取到杯中的咖啡的百分比,并结合一杯咖啡的输出重量和咖啡的输入重量,称为提取率(EY)。
纸时代
我重复使用我的过滤器,因为切割它们需要时间,如果没有必要,我也不喜欢浪费。我还记录了每个过滤器的使用时间(即使用了多少次)。所以年龄 1 是一个新的过滤器。然后我看了一些标准的性能指标。
从最终得分来看,味道似乎略有下降。对于 EY 和 TDS,在使用 6 次左右后有明显的下降。

所有图片由作者提供
年龄并不影响纸张重量,所以剩余的固体量很少,但它们有影响。

对覆盖过滤器的时间(TCF)和总时间也有影响。 TCF 是一个很好的流量指标,但在这个图表中,这个变量并没有完全与烘焙时间分开。

我将 TDS 和 EY 在控制图中与所有数据进行了比较,然后是新的、有点新的和旧的数据。

在这些图表中似乎没有太多的分离。所以我用平均值来总结数据。

可以对这些数据进行总结,从平均值来看,趋势似乎很明显。

首选是使用新的过滤器或适当清洁的过滤器。
不要重复使用底部过滤器
底部过滤器只能使用一次。不管什么原因,都清理不干净不堵。我开始用一个是因为一些高难度的烘焙,一旦发现这个事实,我就改只用新鲜的。在这个测试中,我使用了一次过滤器,冲洗它,让它干燥,并再次使用它与所有其他拍摄参数相同。


左是第一次使用,右是第二次使用
这种差异在球后分析中尤其明显。较暗的点表示由于其他地方的通道流动缓慢。冰球的上半部分是一个轻得多的夯实,所以如果它均匀地分崩离析,这通常表明更均匀和更好的提取。在这种情况下,这是第一次使用过滤器。第二次,顶层有更大的团块,特别是在中间,这表明没有发生足够的提取。





左图是第一次使用底部的纸质过滤器,右图是第二次使用相同的纸质过滤器。
我们可以看看镜头的流速,很明显曾经用过的新 vs 差别很大。流速慢了很多。作为参考,预注入为 45 秒,流量的抖动是由于压力脉动造成的。

当我们观察平滑流速时,预输注期间的峰值较低,然后变得更加恒定。输液也是如此。蓝线更能代表真正好的照片的样子。

新的过滤器具有更高的 TDS、EY 和味道。这表明一些咖啡残留在过滤器中,甚至在冲洗后仍然限制流动。

这让我想知道当过滤器用肥皂清洗并重复使用时会发生什么。
清洁纸质过滤器
我想看看我是否能清洁纸质过滤器,尽管许多人建议我使用新的。我不重复使用纸质过滤器的问题归结于成本、浪费和时间。通过清洗它们,我可以在这三个方面节省自己,因为批量清洗比单独切割更快。

以前,我只冲洗过过滤器。然后我试着用肥皂和水,这比重复使用过滤器要好。然而,它没有使用新的过滤器好。

然后我试了异丙醇。那似乎起了作用!结果与新过滤器如此相似,以至于很难区分味道和提取率。

这项研究极大地影响了我的行为,因为它把数字放到了一个不太为人理解的技术上。我现在已经改用新的纸质过滤器或异丙基水洗过滤器,它帮助我保持了一致性,拍出了优秀的照片。
此外,在撰写这一系列文章时,我决定再看看布料过滤器,我已经在一个断续的夯实镜头中将中间的过滤器切换为布料过滤器。这极大地改变了流动和拍摄,所以我也决定看看其他材料的咖啡中间或底部的这一层。我对更好的投篮和技术感兴趣,但更重要的是,我很想更好地了解冰球内部的一切是如何运作的。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。
我的进一步阅读:
使用模式识别比较咖啡
咖啡数据回顾:等级和口味
按地区、工艺、等级和价格分类的咖啡
家庭烘焙咖啡的经济学
咖啡豆脱气
解构咖啡:分割烘焙、研磨和分层以获得更好的浓缩咖啡
浓缩咖啡的预浸:更好的浓缩咖啡的视觉提示
咖啡的形状
搅拌还是旋转:更好的浓缩咖啡体验
香辣意式浓缩咖啡:热磨,冷捣以获得更好的咖啡
断续浓缩咖啡:提升浓缩咖啡
用纸质过滤器改进浓缩咖啡
浓缩咖啡中咖啡的溶解度:初步研究
断奏捣固:不用筛子改进浓缩咖啡
浓缩咖啡模拟:计算机模型的第一步
更好的浓缩咖啡压力脉动
咖啡数据表
揭示:一种简单得可笑的将 Azure Cosmos DB 与 Azure Databricks 集成的方法
原文:https://towardsdatascience.com/revealed-a-ridiculously-easy-way-to-integrate-azure-cosmos-db-with-azure-databricks-4314cce0259b?source=collection_archive---------10-----------------------
Azure Cosmos DB 的简单 3 步数据块教程

由 Unsplash 上 Greg Rakozy 拍摄的照片
巴迪,我们的数据工程师新手,最近发现了在 Databricks 中读写文件的终极备忘单,现在正在 Azure 世界中升级。
在本文中,您将发现如何无缝集成 Azure Cosmos DB 和 Azure Databricks 。Azure Cosmos DB 是 Azure 云平台中的一项关键服务,它为现代应用程序提供了一个类似 NoSQL 的数据库。
作为一名数据工程师或数据科学家,您可能希望使用 Azure Cosmos DB 来提供使用 Azure Databricks 建模和准备的数据,或者您可能希望使用 Databricks 来分析 Azure Cosmos DB 中已经存在的数据。无论你的目的是什么,只要遵循这个 3 步指南就可以开始了。
Azure Cosmos DB 是什么?
对于外行人来说, Azure Cosmos DB 是名副其实的微软多模型数据库,可以在全球范围内管理数据。它和它的对手 AWS DynamoDB 一样属于“NoSQL 数据库即服务”栈。
在 Cosmos DB 中,每一项数据都存储在与模式无关的容器中,这意味着您不需要遵循任何特定的数据模式。
Cosmos DB 支持多模型 API,如 MongoDB、Cassandra API、Gremlin API 和默认的核心 SQL API。
核心 SQL API 为您提供了类似 JSON 的 NoSQL 文档库,您可以使用类似 SQL 的语言轻松查询它。
尽管 Cosmos DB 有着花哨的名字和强大的功能,但它基本上是一个数据存储,一个我们可以读写的数据存储。
通过与大量 Azure 服务的无缝集成, Azure Databricks 正是这项工作的合适工具。
为了执行这个练习,您必须拥有一个运行着 Cosmos DB 和 Databricks 服务的 Azure 订阅。如果您没有,请按照下面的步骤获得它并免费创建服务!
如果您已经有 Azure 订阅,请跳到下一部分。
如果你没有 Azure 订阅在这里获得一个免费试用版,这很容易,不到两分钟。(您需要提供您的信用卡信息,但不要担心您不会被收取任何费用)
现在,我们只需要一个 Cosmos DB 帐户和一个 Databricks 工作区。
如何创建 Azure Cosmos DB?
微软使用快速入门模板让在 Azure 上部署服务变得越来越容易。
按照快速入门模板的链接到部署 Azure Cosmos DB ,点击部署到 Azure,这将在浏览器上打开 Azure 门户。查看步骤并创建您的服务。在你喝下一杯咖啡之前,Cosmos DB 帐户就会准备好
创建帐户后,您需要创建一个数据库和一个容器来存储您的数据。按照下面的示例创建一个名为 AdventureWorks 的数据库和一个名为 ratings 的容器。
导航到您部署的 Cosmos DB 帐户,点击数据浏览器 → 新容器 →命名您的数据库AdventureWorks→您的容器评级 →分区键为/评级→ 选择吞吐量手册并将其设置为 1000。

来自微软文档的插图
最后一步是从 Keys 部分复制 Azure-Cosmos DB 读写密钥,如下所示。您将需要这个来验证您的 Databricks 工作空间,以访问 Cosmos DB 帐户。

来自微软文档的插图
如何创建 Azure Databricks workspace?
类似地,通过下面的链接部署 Azure Databricks workspace 。一旦部署了工作空间,您需要做的就是创建一个集群。
导航到您的 Databricks 工作区,在左侧选择 Clusters,并创建一个新集群(选择 Scala 2.11 版本,这是支持我们接下来将安装的 cosmosdb 库的版本)。选择集群模式作为标准模式(如果标准集群出现任何问题,请尝试单节点)。
哇,这比超速罚单还快!
简单的 3 步指南
- 在你的 Databricks 集群上安装最新的 azure-cosmosdb-spark 库。
- 使用 Spark 连接器将数据写入 Cosmos DB。
- 使用 Spark 连接器从 Cosmos DB 读取数据。

Cosmos DB Azure Databricks 模式(图片由作者提供)
如何安装 cosmosdb 库?
步骤 1:初始设置和安装。
在左侧导航中,转到您的集群,并选择您创建的集群。如果它没有运行,现在就启动它。
选择库选项卡,并选择安装新的。在安装对话框下,选择 Maven 并插入以下内容:
坐标:com.databricks.training:databricks-cosmosdb-spark2.2.0-scala2.11:1.0.0
知识库:https://files.training.databricks.com/repo
注意:目前支持带有 Scala 2.11 的 Databricks 运行时版本,因此请确保您的集群运行的是 Scala 2.11 版本。

来自微软文档的插图
如何向 Azure Cosmos DB 写入/发布数据?
步骤 2:将数据写入 Azure Cosmos DB
为了将数据写入 Azure Cosmos DB,我们需要准备一个配置,告诉 Spark 如何连接和验证 Cosmos 容器。
URI = "cosmos-db-uri"
PrimaryKey = "your-cosmos-db-key"CosmosDatabase = "AdventureWorks"
CosmosCollection = "ratings"writeConfig = {
"Endpoint": URI,
"Masterkey": PrimaryKey,
"Database": CosmosDatabase,
"Collection": CosmosCollection,
"writingBatchSize":"1000",
"Upsert": "true"
}
在新笔记本中,创建上述配置变量。 URI 和 PrimaryKey 是我们之前从你的 Azure Cosmos DB 帐户的 Keys 部分复制的值。
现在我们只需要一些数据。将评级样本 csv 文件(从 GitHub 这里下载)上传到您的 Databricks 工作区。
ratingsDF = spark.read.format("csv")\
.option("header","true")\
.load("/FileStore/tables/ratings.csv")
上述命令将一个包含 100 行的示例 ratings csv 文件读入 dataframe。
(ratingsDF.write
.mode("overwrite")
.format("com.microsoft.azure.cosmosdb.spark")
.options(**writeConfig)
.save())
最后,上面的命令使用 Spark DataFrame writer 将数据推入我们的 Cosmos DB 容器。
通过进入 Cosmos DB 帐户→ 数据浏览器→AdventureWorks→ratings,验证数据确实在您的 Cosmos DB 容器中。

那是轻而易举的事!
如何从 Azure Cosmos DB 读取数据?
步骤 3:从 Databricks 中查询 Azure Cosmos DB 中的数据
在这一步中,我们将读取刚刚推入评级容器的数据。我们首先需要创建一个名为 readConfig 的新配置设置,它将包含一个读取 10 行数据的自定义查询。
URI = "cosmos-db-uri"
PrimaryKey = "your-cosmos-db-key"CosmosDatabase = "AdventureWorks"
CosmosCollection = "ratings"
query = "Select top 10 * from ratings"readConfig = {
"Endpoint": URI,
"Masterkey": PrimaryKey,
"Database": CosmosDatabase,
"Collection": CosmosCollection,
"query_custom": query
}
定制查询是一个简单的 SQL 查询,将在 Cosmos DB 容器上执行。您还可以编写包含 where 条件的复杂查询。对于这个练习,一个简单的选择就足够了。
最后的启示是,一旦 readConfig 设置完毕,我们只需使用 Spark DataFrame writer 将数据从 Cosmos DB 读入 dataframe。
readDF = (spark.read
.format("com.microsoft.azure.cosmosdb.spark")
.options(**readConfig)
.load())
像读写数据一样,您也可以遵循类似的模式来更新 Cosmos DB 容器中的记录。只需将您想要更新的数据读入数据帧,并使用您的更新操作该数据帧。完成后,只需使用 writeConfig 推送更新的数据帧。你可以在这个 GitHub 链接中找到完整源代码的例子。
结论
Azure Cosmos DB 和 Azure Databricks 是微软的旗舰服务,结合在一起,它们变得更加强大,知道如何做将使你足智多谋。
这篇文章的要点是:
- 什么是 Azure Cosmos DB,如何创建 Cosmos DB 帐户?
- 如何创建 Azure Databricks 工作区?
- 如何将数据写入 Azure Cosmos DB?
- 如何从 Azure Cosmos DB 读取数据?
所有这些都不花一美元,完全免费!
你对 Azure Cosmos DB 有什么看法?分享你的经验,如果文章很有见地,与你的同行分享。
链接到 Github 源代码:
如需方便的 Spark 备忘单,请查看:
有关 SQL 的基本介绍,请参阅:
https://medium.com/better-programming/absolute-beginners-guide-to-sql-601aad53f6c9
参考
- https://docs . Microsoft . com/en-us/learn/modules/integrate-azure-data bricks-other-azure-services/1-简介
- https://docs . Microsoft . com/en-GB/azure/cosmos-db/spark-connector # bk _ working _ with _ connector
- https://docs . data bricks . com/data/data-sources/azure/cosmos db-connector . html
用卫星图像揭示运动
原文:https://towardsdatascience.com/revealing-motion-with-satellite-imagery-b101c83fd1c6?source=collection_archive---------29-----------------------
使用行星图像观察云的移动、飞机的起飞等等

从 PlanetScope 图像中看到的云运动(图片由作者提供)
这篇文章概述了我的行星运动项目,演示了如何寻找和处理成对的行星图像来突出快速变化。参见 此处的 项目代码。
卫星图像被广泛用于监测地球上任何地方正在发生的变化。从观察整个季节作物的健康状况,到跟踪十年来冰川的融化,这些图像可以用来记录地球上的物体如何随着时间的推移而变化。

谷歌定时界面(图片由作者提供)
谷歌最近发布了时间推移,这是一个互动工具,展示了从多年卫星图像中捕捉到的一些长期变化。
卫星在地球上同一地点连续拍摄图像的时间长度被称为“重访率”。从历史上看,对于地球上的大多数地方来说,这个速率大约是几天到几周,这是由单个成像卫星的周期轨道决定的。这种长度的重访率对于跟踪长期变化很有用,但会错过捕捉在较短时间内发生的任何动作。
较新的商业图像提供商,如 Planet ,正转而使用小卫星星座,这些小卫星协同工作,在更短的时间尺度上收集图像。他们的 PlanetScope 星座每天拍摄整个地球的图像,他们的 SkySat 卫星可以在不到一小时的时间内拍摄地球上同一地点的图像。这些缩短的重访率为更快速变化的事件提供了新的见解。
尽管如此,地球上仍有一些事件发生得太快,即使以这样的速度也无法捕捉到。然而,一个在更短的时间尺度上探测变化的机会存在于行星已经收集的图像中。
“2 秒”重访率
Planet 的 PlanetScope 图像在线性飞行扫描中收集,当一颗卫星沿着其轨道运行时,每隔几秒钟就会周期性地收集一张新图像。由于拍摄每幅图像的时间以及卫星的飞行距离,扫描中的每幅背靠背图像之间都有少量的地理重叠。
下图显示了一个这样的例子。左边和中间显示了相隔几秒钟的飞行扫描中捕捉到的两幅图像,它们的地理足迹以红色突出显示。右图显示了两幅图像的叠加,并以绿色突出显示了它们之间的重叠部分。

一对行星镜图像,重叠部分用绿色突出显示(图片由作者提供)
这个重叠区域,在大约 2 秒的时间内被拍摄了两次,基本上为地球的这一部分提供了“2 秒”的重访率。在捕捉到这种重叠的地方,有机会看到更快的变化。
寻找图像对
在给定的飞行扫描中出现这种重叠完全是偶然的。没有行星计划这些重叠发生在哪里,所以让它们发生在感兴趣的特定区域只是运气,而不是保证。
为了帮助寻找和处理显示这种重叠的图像对,我开发了行星运动项目。它包含 Python 脚本,这些脚本包含用于过滤 Planet API 搜索结果以识别图像对的函数,以及用于将图像处理成可视化输出的函数。
此代码可用于搜索特定的地理空间区域,以查找那里是否存在任何重叠对,并在从 Planet 下载图像后,通过裁剪重叠区域并创建两幅图像之间的 GIF 动画来处理它们。
动画输出有助于轻松解释可视化,当图像来回闪烁时,我们的眼睛会自然地感知到两个图像之间的变化。
观看飞机起飞
以下是此流程可以捕获的事件类型的示例。这里的 GIF 动画显示了地面上物体的运动,这在使用遥感影像时通常是看不到的。
这第一对图像是在旧金山机场上空拍摄的,揭示了多架飞机的运动。一架飞机起飞中,另一架在跑道上滑行。

旧金山机场的飞机起飞(图片作者提供)
同一机场上空的另一对图像显示了两架飞机以不同的速度滑行,以及附近高速公路上的汽车运动。

旧金山的飞机滑行和汽车运动(图片由作者提供)
这张照片是在一个风力农场上空拍摄的。在这里,涡轮机叶片的阴影揭示了它们在图像之间的几秒钟内旋转。还可以观察到云及其阴影的运动。

云的移动和涡轮阴影(图片由作者提供)
在旧金山湾上空的这两幅图像中,你可以看到高速公路上两艘船和汽车的运动。

旧金山的船和汽车运动(图片由作者提供)
这些图像对中的每一个都展示了一种不同的物体运动,这种运动在仅仅观看静态卫星图像时通常是观察不到的。这一运动提供的额外背景可以让我们更深入地了解在被监测的地方到底发生了什么。
在不久的将来,从太空提供视频的卫星将变得更加普遍,并更好地提供这里看到的好处。然而,由于这一过程与行星的行星镜图像一起工作,这些图像仍然是例行收集的,它将仍然是分析这种运动的一种选择。
使用 Python 中的蒙特卡罗模拟揭示线性优化问题的鲁棒性
原文:https://towardsdatascience.com/revealing-robustness-in-linear-optimization-problems-using-monte-carlo-simulation-in-python-c999c836aa02?source=collection_archive---------35-----------------------
线性规划是在给定一组约束的情况下确定最小化和最大化问题的最优解的一个很好的工具。通过将蒙特卡罗模拟应用于这样的程序,我们可以看到最优解是如何随着随机冲击而变化的。

由 Unsplash 上的 Edge2Edge 媒体拍摄
我们将做以下工作:
使用纸浆构建一个确定性线性规划问题
对该问题应用蒙特卡罗模拟
使用数据可视化解释结果
我们要解决的线性规划问题如下:
一家专业工业窗户制造商的产品线中有三种产品,分别称为“小型”、“中型”和“大型”。我们得到以下数据:
1。 关联营业利润 pr。积分别是 12,12.5,12。 2。 所需工时请购单。产品分别是 2.5、3 和 8,总共有 1000 小时可用于生产。 3。 所需 pr 的平方英尺。产品分别为 18、18 和 19,在工厂 共有 1500 平方英尺。 一份交货合同强制生产至少 8 扇大窗户
使用上述数据,确定制造商的利润最大化生产计划:
让我们用 python 实现这个线性编程包,PuLP。通过在 cmd 行中写入以下文本,可以轻松安装 PuLP:
pip install pulp
线性程序的实现如下:
优化的目标函数和决策变量给出了以下内容:
目标函数 = 1021.00
生产大型 = 8 生产中型 = 74 生产小型 = 0
因此,没有任何其他生产计划能比这一精确组合带来更高的利润。看起来“中等”是有利可图的,也不会消耗太多的约束条件,因此对该产品的大量分配似乎是有效的。然而,如果对中等尺寸窗户的需求非常不稳定,该怎么办呢?我们仍然冒着产量高达 74 辆的风险吗?
让我们假设“中等”窗口的利润遵循基于历史数据的 N(0,2)正态分布。
我们对目标函数进行这些修改,并设置一个选择的种子。这些变化可以在第 3、6、7 和 18 行找到。所有其他因素保持不变:
稍作修改的优化程序现在给我们提供了以下结果:
目标函数= 984.00
生产‘大型’=8 生产‘中型’=0 生产‘小型’=74
请注意,新的优化生产计划将中等尺寸窗户的产量设置为零!正如我们可以清楚地看到的,将确定性模型暴露于随机性可以真实地揭示生产计划的稳健性。当进一步检查目标函数时,我们可以看到,对于这个特定的模拟实验,“中等”的利润被设置为 10.5(这可以通过打印模型 v 变量来完成)。这显然有利于小尺寸窗户的更多生产,因为利润相对于“中型”窗户更高,而且消耗的工时也更少。
然而,我们不应该满足于仅仅一个实验。因此,让我们对这个优化问题进行 1000 次蒙特卡罗模拟,并以直方图解释结果:
上面的代码生成以下优化决策变量的直方图:



从 1000 次模拟运行中,有几个有趣的见解。首先,显然不令人吃惊的是,大窗户的产量将永远保持在 8。这是由于 8 小时 pr 的工作时间消耗。单位明显多于其他两个。其次,我们看到“小”和“中”的最佳选择在 0 和 74 之间移动,中间没有观测值。由于“中型”最初的利润比“小型”高 0.5 倍,因此最好在 600 次模拟运行中最大限度地提高产品产量。同样,74 个小窗口的生产在 40%的模拟运行中是最优的。作为生产计划员,这是非常有价值的信息,应该制定策略来降低执行错误生产计划的风险。看起来,相信像最初那种确定性模型可能会产生戏剧性的后果。
总之,应该非常小心地跟踪确定性优化模型的输出。运行模拟并将其暴露于随机性(即使是最轻微的)应该会揭示出最优命题在一开始是多么好。
我喜欢用的一个很好的比喻是:
一个士兵正在努力寻找他的最佳射击位置,以便保持稳定的瞄准。当中士经过并试图稍微打扰士兵时,我们很好地了解了士兵们的瞄准和射击姿势。在这里,瞄准是优化,受到干扰是模拟。
揭示神经网络看到和学到什么:PytorchRevelio
原文:https://towardsdatascience.com/reveling-what-neural-networks-see-and-learn-pytorchrevelio-a218ef5fc61f?source=collection_archive---------20-----------------------

图片来自[0]
介绍
线性和经典的学习模型,如逻辑回归[1],SVM[2],决策树,…很容易理解和分析。另一方面,深度神经网络很难理解,所以人们将其称为黑盒。幸运的是,已经发明了很多方法,让我们在某种程度上了解这些网络。在这篇文章中,我们将介绍其中的一些方法,同时我们也推荐 PytorchRevelio [0】,一个包含这些方法的工具包。
为什么理解深度神经网络看到的东西很重要?
深度神经网络,特别是卷积神经网络,在大数据集和新的训练方法的帮助下,避免了梯度消失等问题,达到了高性能。因此,它们取代了许多计算机视觉任务中的旧方法,如分类、检测、语义分割、跟踪、场景重建等。
Grad-CAM[3]论文为理解神经网络所见的重要性提供了以下理由:
可解释性很重要。为了建立对智能
系统的信任,并推动它们有意义地融入我们的日常生活,很明显,我们必须建立“透明的”
模型,这些模型能够解释为什么它们预测它们所预测的
。
通过理解为什么模型对输入的预测是错误的,我们可以想出解决模型问题的方法。
当一个模型在给定的任务中表现得比人更好时,我们可以通过理解它为什么做出那个决定来学习新的东西。

图片来自[3]。
上面的图像的第一行包含四个图像给 VGG-16 在 ImageNet 上训练[4]。这些图像被分类到错误的类别中。在第三行中,在理解神经网络的方法的帮助下,描绘了激发错误类别变得活跃的像素。例如,第四个图像是一个线圈。然而,它被归类为藤蔓蛇。原因是第三行显示的绿色曲线。

图片来自[0]
PytorchRevelio 工具包通过使用两种不同的方法来获得上面的图像。这些图像是在 ImageNet 上训练的 VGG11[4]的分类标签 691-氧气面罩的表示。在这些图像中,不仅氧气面罩的图案可见,而且它们还包含噪声和眼睛形状。这就提出了一个问题,这个模型是否对这个阶层有偏见。它能够正确分类不在人脸上的氧气面罩图像吗?

图片来自[0]
红色像素显示了在 ImageNet 上训练的 ResNet-50 [5]集中对动物图像进行分类的部分图像,如巨嘴鸟、狐狸、鹰和孔雀。这些红色像素是通过使用 PytorchRevelio 获得的。例如,在对巨嘴鸟进行分类时,ResNet-50 主要考虑它的喙,而其他部分则不太重要。为了将图像分类为孔雀类,网络主要使用其羽毛上的眼睛图案。如果巨嘴鸟的喙被遮挡,网络能正确分类吗?
以上图像是通过激活最大化、显著图、Grad_CAM 等不同方法创建的。通过使用这些方法,回答了许多问题,并提出了新的重要问题。
激活最大化
激活最大化是一种为神经网络中的神经元/过滤器已经学习的特征寻找表示的方法。激活最大化可以在本文中找到:“可视化深层网络的更高层特征”[6]。在这种方法中,通过从诸如高斯分布的分布中随机抽取像素来创建图像。然后这个图像被传送到网络。计算神经元/滤波器的输出相对于图像的梯度。将梯度添加到图像中,以找到为神经元创建更大输出的更好的图像(梯度上升法,用于最大化)。新图像经历相同的过程,这种情况会发生几次。在每一步中获得一个新的图像,该图像比前一步更多地激活目标神经元/滤波器。

图片来自[0]

图片来自[0]
上面这两幅图像代表了 AlexNet[7]中名为“features.0”和“features.6”的图层中的一些学习过的过滤器。第一张图片中的滤镜属于 AlexNet 的第一层;他们已经学会了简单的特征,例如不同方向的边。第二个图像中的滤镜位于深度较高的图层中。如图所示,他们已经学会了更复杂的功能。然而,这种方法有一些缺点。例如,如果我们举例说明最后一层(输出层)的特征,我们将看到获得的表示非常模糊。接下来的两种方法将解决这个问题。
高斯模糊激活最大化
如果我们用激活最大化方法产生类的表示,我们不能容易地在学习特征的表示中找到想要的对象。会有很多高频图案降低它们的清晰度。有几种方法可以解决这些问题。最简单的方法之一是使用低通滤波器,如高斯模糊[8]。在每一步中,高斯滤波器应该应用于计算的梯度或获得的图像。其他一切都将与激活最大化方法相同。这种差异在下面的图片中是显而易见的。

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]
这些图像是通过使用高斯模糊方法的激活最大化获得的,该方法在 PytorchRevelio 中实现。这些代表了在 ImageNet 上训练的 VGG11 [4]的神经元/过滤器的一些习得特征。如图片所示,第一层的要素较为简单,在后面的层中逐渐变得更加复杂和抽象。
在之下,通过进入更深的层,可以在所获得的特征的抽象中观察到顺序:
1-边缘/拐角
2-纹理
三模式
4-对象的部件
5-整个对象
双边模糊激活最大化
该方法[9]类似于具有高斯模糊的激活最大化,但是双边滤波器被用作低通滤波器。虽然它像高斯滤波器一样模糊图像,但它保留了边缘。因此,获得了更好的表示。
显著图
显著图[10]是示出输入图像的每个像素在计算输出类别分数中的重要性的图。为了计算显著图,需要输入图像和目标类别。为了找到每个像素的重要性,我们计算 softmax 之前的最后一层网络的目标神经元的输出。然后将目标类的渐变设置为 1,其他输出设置为零。之后,计算输出相对于输入图像的梯度。梯度值越大,表示相应的像素越重要。计算显著图很快,因为它只需要一次向前和向后的传递。不幸的是,这种方法的输出不够好,但接下来的两种获得显著图的方法获得了令人印象深刻的结果。

图片来自[0]
具有引导梯度的显著图
具有引导梯度的显著图与前面的方法相同。然而,它使用引导梯度[11]而不是梯度。
我们称这种方法为引导反向传播,因为它将来自更高层的额外引导信号添加到通常的反向传播中。这防止了负梯度的反向流动,对应于减少我们旨在可视化的更高层单元的激活的神经元。[11]
使用引导梯度极大地提高了所获得的显著图的质量。下面您可以看到 PytorchRevelio 计算的几个输出。差异是显而易见的。

图片来自[0]

图片来自[0]

图片来自[0]
与前一种方法相比,这种方法产生的图像质量较高。然而,如果我们试图为给定的图像和包含几个不同对象的目标类绘制显著图,我们将观察到其他对象的部分也被标记。下图是这个问题的一个例子。虽然秃鹰是这幅图的目标职业,但是狮子的某些部位也有标记。下一个方法解决了这个问题。

图片来自[0]
制导摄像机
Guided Grad-CAM [3]方法首先使用先前的方法获得输入图像和目标类别的显著图:“具有引导梯度的显著图”然而,它计算得到的显著图的逐元素乘积和矩阵 L,以消除显著图中不想要的像素。为了获得矩阵 L,它使用网络的最后一个卷积层的输出特征图。他们的理由如下:
此外,卷积层自然保留了全连接层中丢失的空间信息,因此我们可以预期最后的卷积层在高级语义和详细的空间信息之间具有最佳的折衷。[3]
和
Grad-CAM 使用流入 CNN 最后一个卷积层的梯度信息,为每个神经元分配重要值,以做出感兴趣的特定决策。[3]
它使目标类的梯度等于 21,然后相对于最后一个卷积层的输出特征图计算目标类得分的梯度。现在,为了找到每个特征图的重要性,计算该特征图的相应梯度的平均值。为了获得矩阵 L,借助于计算的重要性,计算输出特征图的加权平均值,加权平均值的负元素被设置为零。如上所述,通过在矩阵 L 和引导梯度显著图之间执行逐元素乘积,获得最终的显著图。
在下图中,您可以看到在 ImageNet 上训练的 ResNet-50 [5]的该方法的一些输出。此外,为了进行比较,还提供了前面方法的输出。

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]

图片来自[0]
在上面的图像中,图像中有不止一个对象。与引导梯度显著图不同,在引导梯度 CAM 方法中,只有属于输入目标类别的对象部分被突出显示。
到目前为止 PytorchRevelio 中实现的方法

图片来自[0]
哪种方法性能更好?
- 列表中较高的方法在特征可视化方面表现更好:
- 激活最大化双边模糊
- 激活最大化高斯模糊
- 激活 _ 最大化
- 列表中较高的方法对显著图执行得更好:
- grad_cam
- 显著性 _ 地图 _ 导向
- 显著性 _ 地图
更多细节以及如何使用 PytorchRevelio,请访问其 GitHub 页面:https://github.com/farhad-dalirani/PytorchRevelio
参考
[0] PytorchRevelio,【https://github.com/farhad-dalirani/PytorchRevelio】T2
[1]托勒斯·J·默雷尔·WJ。逻辑回归:将患者特征与结果联系起来。 JAMA。2016;316(5):533–534.doi:10.1001/jama
[2]科尔特斯,科琳娜和弗拉基米尔·瓦普尼克。"支持向量网络。"机器学习 20.3(1995):273–297。
[3] Selvaraju,Ramprasaath R .等人,“Grad-cam:通过基于梯度的定位从深度网络中进行可视化解释”IEEE 计算机视觉国际会议论文集。2017.
[4]西蒙扬、卡伦和安德鲁·齐泽曼。“用于大规模图像识别的非常深的卷积网络。” arXiv 预印本 arXiv:1409.1556 (2014)。
[5]何,,等.“用于图像识别的深度残差学习”IEEE 计算机视觉和模式识别会议论文集。2016.
[6] Erhan,Dumitru,等,“深层网络的高层特征可视化”蒙特利尔大学(2009 年)
[7]克里热夫斯基、亚历克斯、伊利亚·苏茨基弗和杰弗里·e·辛顿。"使用深度卷积神经网络的图像网络分类."神经信息处理系统进展25(2012):1097–1105。
[8]au dun m . ygard,https://www . au duno . com/2015/07/29/visualizing-Google net-classes/,2015 年。
[9]迈克·泰卡,https://mtyka . github . io/deep dream/2016/02/05/bias-class-vis . html,2016。
[10] Simonyan,Karen,Andrea Vedaldi 和 Andrew Zisserman。"深入卷积网络内部:可视化图像分类模型和显著图." arXiv 预印本 arXiv:1312.6034 (2013)。
[11]斯普林根伯格,乔斯特·托拜厄斯,等,“力求简单:全卷积网络。” arXiv 预印本 arXiv:1412.6806 (2014)。
利用机器学习对水的属性进行逆向工程
原文:https://towardsdatascience.com/reverse-engineering-water-properties-with-machine-learning-38315590f0d7?source=collection_archive---------28-----------------------

由 Unsplash 上的 mrjn 摄影拍摄
考虑到水的特性,以下是如何理解水的来源。只有几行代码。
机器学习在日常生活中帮了我们很多,而且有时我们甚至没有完全意识到。主要原则(也是我们使用机器学习的主要原因)是,当一些事情真的很难理解时,我们仍然有机会用数据解决它。
虽然 ML 通常被用来解决问题,
另一个强大的选择是使用机器学习来进行逆向工程。
但它实际上是什么意思呢? 好吧,假设你创建了一个新的社交媒体,每次有人发布带有某个单词的内容(假设 " 愚蠢 " )时,你决定删除该内容,因为这违反了你的政策。想象一下,你的朋友决定使用你的社交媒体,而他们不知道这条规则。如果他们想知道为什么他们的帖子被删除了,他们必须对你的社交媒体进行逆向工程。这基本上就是逆向工程的意思。
在这篇博文中,我将向您展示如何使用机器学习、以及几行代码对某个数据集进行逆向工程。
特别是,我们会有一个数据集,解释某个地方某个水的所有水属性。鉴于这些属性,我们希望对它们进行逆向工程,并使用机器学习来实际检索原产国。
我们开始吧!
0.图书馆:
出于我们的目的,我们将使用 Python 。我们将使用一些著名的库,如 sklearn、pandas、matplotlib 和 numpy。以下是您可以复制粘贴到笔记本中的完整列表:
1.数据探索:
很好,我们差不多准备好了。不过,我们需要一个重要的东西:数据。你可以在这里下载数据集,好消息是,这是一个相对较小的数据集。
正如我们想要得到这个国家一样,我们不想用一个代理这个国家本身作为一种财产。出于这个原因,我们将从数据中删除代理列。以下是最终结果:
我们得到了许多属性,许多非数字特征,以及国家列,这就是我们想要了解的。通过这样做,我们可以理解列的类型:
所以我们有一个数字特征列表和一个非数字特征列表:
这样我们就可以了解每个非数字特征有多少个条目;
这样我们可以检查数字特征的相关性:
现在让我们看看我们的目标栏,看看我们有多少个国家。

好吧,所以…这是一个烂摊子。让我们通过选择最频繁的类来使它更有序,并将其他类分组在一起。
注意:这完全没有必要!只是为了让事情更清晰易懂。请随意跳过这一部分。

办法更好。
2.机器学习:
当你在逆向工程一些东西时,可解释性是至关重要的。一个众所周知且可解释的机器学习模型被称为决策树。 但是它是如何工作的呢?好吧,让我们简单点。你玩过“猜猜是谁?”?这是一个著名的经典游戏,你必须通过向对手提问来了解某个角色。假设你必须猜艾德·希兰。它可能是这样的:
Is he an actor? **No** Is he a singer? **Yes** Is he a pop singer? **Yes** Is he from Canada? **No** Has he ginger hairs? **Yes
It’s Ed Sheeran!**
这正是决策树对我们的特征所做的,以了解国家。很简单,对吧?让我们成功吧!使用这些代码行,您可以准备数据集并查看与目标列的关联。

有了这几行代码,你可以真正地训练你的模型,并检查它的性能(训练/测试分割:80%/20%):

是一个逆向工程任务,所以应该是这样的!我们想要了解一个精确的模式,我们不想有任何错误。
这是逆向工程的结果:

那解释了一切!如果水超过一定的金属百分比属于某一类,同样的还有玻璃和干旱 _ 洪水 _ 温度。
3.结束语
由于机器学习,能够理解新的东西是令人惊讶和鼓舞的。我真的希望你喜欢这篇文章,并且像我写这篇文章和开发代码一样开心。
如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:
A.在 Linkedin 上关注我,我在那里发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于现有最新技术的文章。
非常感谢,祝你有美好的一天!
使用纽约自行车共享数据进行反向地理编码
原文:https://towardsdatascience.com/reverse-geocoding-with-nyc-bike-share-data-cdef427987f8?source=collection_archive---------27-----------------------
实践教程
使用 Pandas 合并来增强来自 Nominatum 的区和邻居的城市自行车出行数据
纽约市自行车共享系统 Citi Bike 提供出行数据文件,因此任何感兴趣的人都可以分析该系统的使用情况。在本文中,我将展示如何通过反向地理编码自行车站点坐标来添加每个站点所在的区、社区和邮政编码,从而增强 Citi 自行车出行数据。

作者照片
在我之前的文章探索纽约自行车共享数据中,我展示了如何通过数据准备让花旗自行车出行数据变得更有用。关于如何安装所用工具的说明,请参阅那篇文章:Jupyter Notebook、Pandas、Seaborn 和 Pyarrow。
本文中使用的所有 Python 代码及其生成的输出可以在 Jupyter 笔记本 locations.ipynb 中的 github 上找到。
下载花旗自行车旅行数据
花旗自行车系统数据页面描述了所提供的信息,并提供了一个可下载数据的页面链接。在这篇文章中,我使用了 2020 年 9 月的数据。
在 Windows 上找到 202009 年的 NYC 文件,下载,解压到一个bikeshare目录。
在 Linux 上,从命令提示符发出命令:
mkdir bikeshare && cd bikeshare
wget [https://s3.amazonaws.com/tripdata/202009-citibike-tripdata.csv.zip](https://s3.amazonaws.com/tripdata/202003-citibike-tripdata.csv.zip)
unzip 202009-citibike-tripdata.csv.zip
rm 2020009-citibike-tripdata.csv.zip
导入库和数据
启动 Jupyter,然后从浏览器窗口在您的bikeshare目录中创建一个新笔记本。
导入这些库。
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
然后将数据文件读入熊猫数据框并检查其形状。
df = pd.read_csv('202009-citibike-tripdata.csv')
df.shape(2488225, 22)
shape 属性告诉我们有多少行(和列)被读取,因此 9 月份有将近 200 万次访问。
计算行程
我以前看过最受欢迎的车站,但我也对最受欢迎的行程感兴趣。有多少种不同的行程,即始发站和终点站的组合?理论最大值是起点站的数量乘以终点站的数量:
counts = df[['start station id','end station id']].nunique()
counts
start station id 1087
end station id 1112
dtype: int64counts.agg('product')1208744
一位读者注意到有 25 个不同的终点站比起点站多,并问这是怎么回事?嗯,泽西城也有花旗自行车系统,所以有可能在那里的一个车站放下自行车。虽然从曼哈顿到乔治·华盛顿大桥很容易,但距离泽西城还有 13 英里,所以这不太可能。骑手也可以乘坐纽约水路轮渡,但实际上更合理的做法是在一个终点站放下自行车,过了河再去取另一辆。虽然我能解释清楚,但这样的旅行只有 60 次,这是一个微不足道的数字,所以我选择忽略它们。
因此,有 1000 多个车站,就有超过 120 万次可能的旅行。但是有多少是在 9 月份被骑过的呢?
df[['start station name','end station name']].\
value_counts().count()317636
这显示了超过 30 万次或者大约三分之一的可能行程实际上有乘客。那么最受欢迎的旅行是什么?
我使用value_counts创建了一个系列trips来查找前二十个旅行。
然后trip_names用斜线将 s 起点站名和 e 终点站名连接起来,为这些旅程创建一个名称。
然后我可以使用barplot来显示旅行次数。
trips=df.value_counts(['start station name','end station name'])[:20]
trip_names=[trips.index[t][0] + ' / ' + trips.index[t][1] for t in range(len(trips))]plt.figure(figsize=(12,10))
sns.barplot( x= list(trips.values), y = trip_names, orient="h") ;
我注意到的第一件事是,许多旅程都有相同的起点和终点。我认出了许多中央公园附近的车站。所以看起来很多人都去公园兜风了。

乘坐次数排名前 20 的旅行
我可以重新创建trips,省略起点站 id 和终点站 id 相同的“循环”或行程。
trips = df[df['start station id'] != df['end station id']].\
value_counts(['start station name','end station name'])[:20]
然后重新创建trip_names并重新运行图表。

按乘坐次数排名的前 20 次旅行——省略循环
现在我注意到最热门的旅行是在名字像野餐点,Soissons Landing 和 Yankee Ferry Terminal 的车站之间。这些听起来不像是纽约市的地点!他们听起来像是在某个小岛上。事实证明,的确如此。
车站位置
关于站点在行程数据文件中的位置的唯一信息是其名称和 GPS 坐标。虽然坐标对于绘图来说是必要的,但是对于人类读者来说并没有太大的意义。但是,可以使用反向地理编码将它们转换成完整的地址。
有许多可用的地理编码 API,包括来自谷歌、ESRI、here、Mapquest 等的 API。有些是商业性的,大多数有免费等级或免费试用。
以前我用 ESRI,但免费试用后,你必须付费。因此,在本文中,我将使用使用 OpenStreetMap 数据的nomim。它是免费的,但是每秒钟有一个请求的限制。要使用它,请导入这些库:
from geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter
为了符合他们的要求,将user_agent设置为您的应用程序名称或电子邮件地址。然后创建一个reverse函数,使用RateLimiter将查询次数限制为每秒一次。
geolocator = Nominatim(user_agent="bikeshare")
reverse = RateLimiter(geolocator.reverse, min_delay_seconds=1, max_retries=0)
默认情况下,reverse函数返回一个简单的值列表,这个列表很难解释,但是它提供了一个raw属性,这个属性以字典的形式返回这些值。从结果中,我可以提取出address元素,它也是一个字典。
举个例子,这里我传递了我之前工作的坐标。
reverse("40.75029943702441, -73.99221868612786").raw['address']
结果是一个包含该位置信息的字典。
{'building': 'Pennsylvania Station',
'road': 'West 36th Street',
'neighbourhood': 'Garment District',
'suburb': 'Manhattan',
'county': 'New York County',
'city': 'New York',
'state': 'New York',
'postcode': '10018',
'country': 'United States',
'country_code': 'us'}
现在,我只需要对行程数据文件中所有唯一的站点进行这样的操作。首先,我将创建一个具有起点桩号 id、名称、纬度和经度的新数据框,并将其限制为桩号 id 的唯一值。
dfs=df[['start station id','start station name',\
'start station latitude','start station longitude']]\
.drop_duplicates(subset = ['start station id'])
然后重命名列,并将index设置为stationid。
dfs.columns=['stationid','station name','latitude','longitude']
dfs.set_index('stationid', inplace=True)
dfs

电台表
反向地理编码
现在我要给每个站打reverse。我看到这个月有 1087 个站点被使用。首先创建一个空列表。然后遍历元素,将数字纬度和经度转换成格式化的文本字符串。每个结果都被附加到列表中。
完成后,以数据框的形式查看列表,显示前十行。
注意:由于我们被限制为每秒一次通话,这意味着这将需要十八分钟才能完成。稍后我会将结果保存在一个文件中,这样我就不需要再次运行它。
locations=[]
for index, row in dfs.iterrows():
locations.append(reverse("{}, {}".format(row['latitude'],\
row['longitude'])).raw['address'])pd.DataFrame(locations[:10])

显示站点位置反向地理编码的表
这确实提供了关于空间站位置的有用信息。然而,我注意到一些差异。我看到城市总是纽约,这对于曼哈顿来说是正确的,但是对于布鲁克林的地址,它应该是布鲁克林,而在皇后区,它们应该有一个实际的城市名称,如阿斯托里亚或福雷斯特山。布鲁克林和皇后区的县名称不出现在 county 中,而是出现在 city_district 中。然而,郊区列实际上包含了纽约市的区名,所以这更有用,因为社区也是如此。
我使用原始数据帧中的站点 id index创建了一个数据帧。然后,我只选择我感兴趣的三个列,我将把它们重命名为对纽约人有意义的名称。
dfstations = pd.DataFrame(index=dfs.index, data=locations,\
columns=['neighbourhood','suburb','postcode'])dfstations.rename(columns={"neighbourhood":"neighborhood",\
"suburb": "boro", "postcode": "zipcode"}\
,inplace=True )
因为只有五个区,所以我可以通过将boro从字符串转换为类别来节省空间并获得更好的性能。我可以为neighborhood和zipcode做同样的事情,因为它们的数量也有限。对于一个类别,每个名称只存储一次,指向名称的指针存储在单独的行中。
我注意到至少有一个邮政编码使用了 ZIP+4 格式,这是我不想要的,所以将它们都剥离为五个字符,并将其转换为一个类别。
dfstations['neighborhood'] = dfstations['neighborhood'].astype('category')
dfstations['boro'] = dfstations['boro'].astype('category')dfstations['zipcode'] = dfstations['zipcode'].str[:5].astype('category')
cols = ['neighborhood', 'boro']
然后我会将station name、longitude和latitude也添加到表格中。
dfstations[['station name','latitude','longitude']] =\
dfs[['station name','latitude','longitude']]
然后检查创建的表。
dfstations.head(10)

带有街区、行政区和邮政编码的车站
最后,我将这个表保存到磁盘上,这样以后就可以再次使用它,而不必重新创建它。我使用的是 Parquet column store 格式,它比 CSV 文件更节省空间,并且维护我创建的索引和数据类型。
dfstations.to_parquet('202009-stations.parquet')
我还在 github 上将这个文件保存为202009-stations . parquet,这样你就可以将它下载到你的系统中,而不是自己创建。
dfstations = pd.read_parquet('202009-stations.parquet')
或者,你可以直接从 github 读取文件。
dfstations = pd.read_parquet('[https://github.com/ckran/bikeshare/raw/main/202009-stations.parquet'](https://github.com/ckran/bikeshare/raw/main/202009-stations.parquet'))
使用位置数据
现在,我可以查看上面提到的三个站点的位置数据,提供一个站点名称列表,以便使用isin方法。
dfstations.loc[dfstations['station name'].isin\
(['Yankee Ferry Terminal','Picnic Point','Soissons Landing'])]

“诺兰公园”车站的位置详情
在这里,我看到所有三个车站都在诺兰公园,我不得不在谷歌上搜索,发现这是纽约港的一个岛屿上的公园。
探索站数据
现在我有了一个包含位置的车站表,我可以进一步研究这些数据。例如,我可以用 Seaborn countplot按区统计站点,并轻松创建一个图表。
sns.countplot(data=dfstations, x="boro") ;

按行政区统计车站数量
我看到花旗自行车仍然主要服务于曼哈顿和布鲁克林。我还可以看到曼哈顿哪些街区的电视台最多。首先创建一个系列,包括曼哈顿拥有最多电视台的 25 个社区。然后用barplot给他们看。
nabes = dfstations['neighborhood'].loc[dfstations['boro']== 'Manhattan'].value_counts()[:25]plt.figure(figsize=(12,10))
sns.barplot( x=nabes.values , y=list(nabes.index), orient="h" ) ;

曼哈顿排名前 25 的社区
将车站位置与行程数据相结合
真正有用的是,您可以执行 SQL 所称的从带有站点的表到原始旅行数据文件的连接。熊猫把这个操作叫做merge。
前两个参数是数据框的名称(对于 stations 表,我使用了一个子集),然后是可选的连接类型,可以是 inner(默认)、left、right 和 outer,其含义与 SQL 中的含义相同。因为车站表是从行程数据文件中的起始车站导出的,所以我知道它们都匹配。
因为匹配列在两个表中有不同的名称,所以我将它们明确指定为最后两个参数。
dfa=pd.merge(df, dfstations[['boro','neighborhood','zipcode']],\
how = 'inner',left_on='start station id', right_on='stationid')
仅使用车站表,我就可以计算每个区的车站数量。有了合并的表格,我可以做一个图表,显示从每个区开始的次行程的次数。在这里,我看到了花旗自行车使用率对曼哈顿的重要性。
sns.countplot(data=dfa, x="boro") ;

按行政区的行程计数
我可以做另一个连接来添加和站的位置细节。对于这个合并,我使用 left(外部连接),因为一些旅程在新泽西结束,所以它们不会被发现。
dfa=pd.merge(dfa, dfstations[['boro','neighborhood','zipcode']],\
how='left',left_on='end station id', right_on='stationid')
它会产生带有 _x 或 _y 后缀的列名。我可以用 boro 代替 station 做和本文第一个一样的图表。
trips=dfa.value_counts(['boro_x','boro_y'])[:10]
trip_names=[trips.index[t][0] + ' / ' + trips.index[t][1] for t in range(len(trips)) ]plt.figure(figsize=(12,10))
sns.barplot( x= list(trips.values), y = trip_names, orient="h") ;
图表显示,花旗自行车的“跨区”使用非常少。

按起始区和结束区统计乘车次数
又一张图表,用街区代替自治市。在这里,我看到大多数花旗自行车的使用是在一个街区内,有时是在相邻的街区。

通过开始和结束邻域进行乘车计数
所以我可以看到更多的游乐设施在 UWS 开始和结束,比其他任何社区。切尔西对切尔西第二。但是我想看看其他经常去的地方,比如说切尔西。从这张图表中很难看出这一点。有没有更好的方法来可视化这些数据?事实上,期待我的下一篇文章用和弦图可视化纽约自行车共享出行。
结论
通过使用反向地理编码增加 Citi Bike trip 数据文件,为每次骑行的起点和终点添加行政区和社区信息,我可以对该系统的使用方式有更多的了解。
事实上,数据显示,花旗自行车在曼哈顿的使用率仍然高于其他行政区,几乎所有的行程都在同一个行政区开始和结束,而且大多数行程都在同一个或相邻的社区。尽管花旗自行车是为运输而设计的,但它也用于娱乐,这可以从返回出发地的旅行次数和完全在港口的一个岛上的旅行次数中得到证明。
一位前 SageMaker 项目经理关于 re:Invent 2021 AI/ML 发布的评论
原文:https://towardsdatascience.com/review-of-re-invent-2021-ai-ml-releases-by-a-former-sagemaker-pm-cc416ed32d94?source=collection_archive---------16-----------------------
意见
AWS 对所有新 MLOps 工具的深入分析
每年 12 月,亚马逊网络服务(AWS)都会为客户发布新的机器学习(ML)功能。这是拉斯维加斯的一项激动人心的活动,门票通常会销售一空。有很多新闻,我将为数据科学社区提炼出来。

来自 Unsplash 的会议图像
我之前在《走向数据科学》上写过云 MLOps 平台,目前我正在创建一家应用 ML stealth 初创公司。我之前是 AWS SageMaker 的高级产品经理,脸书的计算机视觉(AR/VR)数据、工具和运营主管,以及投资新兴市场债券的 applied ML 对冲基金的创始人。欢迎发微博或在 LinkedIn 上给我发信息你的评论。
在过去的两年里,我观察到有一个简单的框架来应用 ML 产品:应用 AI/ML 服务、MLOps 平台和 ML 框架。最底层是 框架 ,跨越 ML 库(PyTorch、Jax、XGBoost)到编译器和计算芯片(GPU、ARM、TPU、ASICs)。中间是 MLOps 平台 SDK像训练、推理系统、元数据管理、数据处理、工作流引擎和笔记本环境。最后在最顶层的是 AI/ML 服务 ,它抽象了下面的层。AWS 很乐意通过 understand of Textract 向您销售人工智能服务,但我采访的几乎每个企业都喜欢拥有自己的 ML 团队来管理复杂性并将正确的工具粘合在一起。我的框架分解实际上在一个标准的 AWS AI/ML 营销幻灯片中使用。

图片来自 Unsplash
SageMaker 产品从底层框架到 AI 服务都有。他们的产品定位旨在成为万金油,这在 Gartner 魔力象限中得分很高,但仍受到首席信息官和 ML 团队经理对功效的广泛争论。然而,在 2021 re:Invent 上,SageMaker 模糊了 MLOps 平台和人工智能服务之间的界限,同时还在框架上发布了新的深度学习工具。
毫无疑问,SageMaker 今年非常重视深度学习(DL)能力。早在 7 月份,他们的领导层做了一件前所未有的事情,与拥抱脸合作,进行直接的培训和推理产品合作。与其他云提供商相比,AWS 与开源初创公司合作的记录参差不齐,但 HuggingFace 在自然语言处理(NLP)库中的主导地位使得这种协同作用非常值得期待。
训练编译器 —该产品旨在通过使用不同的 AWS 专有库运行张量运算,减少 DL 模型的训练时间。DL 模型由一个多维矩阵组成,神经网络的每一层都在训练过程中运行一系列数学运算。每种运算(加、减等)都可以归类为一个运算符。在 Numpy,有超过 1000 个运营商,你可以从我的朋友芯片那里了解更多这个话题。AWS 选择强调 NLP 模型,这是在打赌客户对文本深度学习的使用最多。在我自己的 CIO 电话中,我看到了类似的趋势。然而,为一系列 NLP 客户提供一个普遍可用的产品有几个挑战,我怀疑这些挑战已经被克服了。
首先,SageMaker 有自己的运行培训作业所需的容器。如果缺少操作员,您将无法运行培训作业,直到库支持优化版本。后备机制引入了会降低工作速度的巨大瓶颈。培训产品的常见问题强调了这些问题,“使用 SageMaker Training Compiler,我总能获得更快的培训工作吗?不,不一定”。其次,如果你需要完全控制容器和它安装的东西,你需要 AWS 团队的白手套服务。第三,如果你在实验阶段对模型进行多次迭代,这将增加你培训工作的开始时间,从而降低开发速度。我很难向任何一个 ML 团队推荐这个。对于大多数深度学习用例来说,即使运行 POC 也不太可能值得付出努力。
Ground Truth Plus—Ground Truth Plus 允许公司提交项目请求,SageMaker 项目经理会将项目与他们管理的一组工人进行匹配。Plus 和 standard Ground Truth 之间的唯一区别是工人管理。在大多数深度学习数据需求中,如音频转录、分割、分类,甚至 3D 点云标签,许多创业公司都有多年提供这些服务的经验。例子包括私人创业规模。AI、社会责任数据标注厂商 Samasource、加拿大 Telus(通过收购 Lionbridge)。
SageMaker 还为他们的工作室笔记本发布了一些新功能。
sage maker Studio Lab——类似谷歌 Colab 的运行笔记本的免费服务。该产品非常适合希望了解更多关于 ML 和免费计算的爱好者社区。然而,这并不能帮助大多数企业客户。我在使用该产品的等待名单上,所以我会保留更深入的评论,直到我使用它之后。
sage maker Canvas——如果你使用过 SageMaker Autopilot,Canvas 用更多的工作室图形工具包装该产品,以最大限度地减少组织中没有 Python 数据科学经验的业务分析师的编码,他们希望进行快速的 ML 实验,我可以看到向他们展示该功能的明显好处。换句话说,任何拥有大量雪花和红移用户群的公司都有可能优化 TCO,方法是让他们的数据分析师先用 Canvas 运行 POCs,然后再让数据科学家提供支持。这里的挑战仍然是,这些千篇一律的模型可以解决的问题的类型很窄,并且基于表格数据的 ML 的大部分问题在数据处理中。截至发稿时,Canvas 在 US-West-1 上还不可用,我可以在体验后分享更多细节。
sage maker Studio Spark Connector—Spark 可能是有史以来使用最广泛的分布式数据处理系统之一。对于 ML 之前的数据预处理,这是简化开发人员体验的起点。大多数财富 500 强公司都在 Spark 上有一些部署,部署从 on instance(裸机)、Kubernetes (Spark 运营商)、Databricks 到 AWS 的 EMR 都有。虽然我看到的数据块比 EMR 客户多,但非 EMR Spark 支持可能会出现。值得注意的是,这是开发人员体验的增强,对性能没有好处。当数据和计算位于同一位置时,大规模分布式处理作业通常运行得最好。然而,用于数据处理的 EMR 和用于 ML 模型训练的 SageMaker 是在两个完全独立的计算环境中运行的。
最后,还有一个 SageMaker 推理推荐器。SageMaker 和大多数 AWS 产品依赖于实例的概念。SageMaker 计算作业本质上是在标准 EC2 节点池上运行的,带有一个定制的运行时、AMI 和容器。因为实例是离散的,但是流量和工作负载是连续分布的,所以我工作过的许多企业都使用 Kubernetes 运行 ML 工作负载。Kubernetes 上有像 knative 这样的工具,它们可以从零开始弹性地扩展持久性服务,通过资源配置文件使用 spot 实例。像 Seldon Core 和 KServe 这样的库将这些特性和其他特性一起打包在一个可安装的 Kubernetes 清单中。
SageMaker 推理推荐器试图通过提供每种实例类型的延迟和吞吐量指标来缩小这一差距。您必须支付实例计算成本。SageMaker 选择了创可贴,而不是进行更大的投资来制造无服务器或绑定到公司现有计算集群的模型服务。如果客户真的需要这个特性,那么编写一个脚本来实现这个推理推荐器所提供的功能是非常简单的。事实上,它的主要客户 Intuit 就是这么做的,你可以在今年早些时候在 Github 上看到他们的开源代码。
托管服务仍然为公司提供巨大的价值。它们通过卸载普通的配置和设置,降低了 IT 组织的总拥有成本。然而,该领域变化太快,在这一点上只有一个真正的 SageMaker 和其他主要 MLOps 平台的最终游戏。他们需要在 Kubernetes 上运行他们的工具和计算引擎。微软 Azure 和 GCP 已经在他们的 ML 平台中提供了这种形式。
Kubernetes 开源工具中的 MLOps 工具生态系统发展迅速。一些大品牌,如 Kubeflow Pipelines,已经成为企业中非常受欢迎的产品。SageMaker 可以在 MLOps 馅饼中占有很大份额,但今天他们已经采取了一种几乎是围墙花园的方法。不幸的是,这意味着 ML 团队将不得不继续混合和匹配开源、自主开发和多个供应商的服务,以使端到端的 ML 工作流运行良好。
简而言之,至少可以说,2021 年人工智能/人工智能领域的公告乏善可陈。这也不是因为缺乏客户需求——摩根士丹利首席信息官调查显示,分析(AI/ML)仍然是每个季度的前五大考虑因素。企业应该继续投资于他们自己的 MLOps 团队,该团队可以有选择地挑选出对他们的公司有意义的解决方案。所有拥有超过 25 名数据科学家的企业将无法单独在 AWS SageMaker 这样的工具上运行。查看我之前的帖子,深入了解工具选项和生态系统的状态。
尽管如此,作为一个与 SageMaker 的许多工程师一起工作过的人,我相信他们正在为这个行业进行改变游戏规则的长期投资。然而,似乎他们中的许多人还没有为 2021 年的重新发明做好准备。
少镜头目标检测综述
原文:https://towardsdatascience.com/review-on-few-shot-object-detection-185965e0e6a2?source=collection_archive---------6-----------------------
少镜头目标检测的介绍和综述

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
用于分类和对象检测的深度学习解决方案是计算机视觉的最先进技术,这已经不是新闻了。尽管最近的 SOTA 算法具有很高的精度和速度,但有一个大问题:对于一个性能良好的解决方案,我们需要大量的数据。此外,必须对数据进行注释,这需要大量的手工工作。这就是一些新模式发展的原因,如自我监督学习和少量学习。
少镜头分类的最新进展有助于显著提高分类中“学会学习”问题的性能,然而少镜头目标检测(FSOD)具有很大的发展和改进潜力。围绕这一主题已经进行了大量的研究。然而,与经典的对象检测或少量镜头分类相比,存在巨大的性能差距。
现在让我们更深入地了解 FSOD:
- 少镜头目标检测的问题定义
- 基准 3 最近的 SOTA 算法
- 回顾并比较上述 3 篇论文。
少数拍摄对象检测
少镜头对象检测旨在使用有限的监督和带注释的样本来概括新的对象。设(S1,… Sn)是一组支持类,Q 是一个有多个实例和背景的查询图像。对于给定的(S1,… Sn)和 Q 模型,目标是从 Q 中找到的支持集中检测和定位所有对象。在训练期间,大多数 FSOD 应用程序将类分成两个不重叠的部分:基本类和新类。训练数据集包括用于训练基线模型的基类。然后,在使用基类和新类的组合数据集的情况下,对模型进行微调。最后一个阶段包括在仅由新类组成的数据集上进行测试
这是最流行的少数镜头对象检测问题定义。它可能因纸张不同而略有不同。然而,每个研究的主要思想都是相同的:创建一个模型,它能够以一种类不可知的方式在新的、从未见过的类上找到对象。
基准
两个流行的少数镜头对象检测任务被用于基准测试:MS-COCO 10 镜头和 MS-COCO 30 镜头。让我们来看看每项任务的前 3 种模式:

两个不同任务的 3 个模型的基准。按作者分类的图表
根据不同的任务,这 3 种算法优于其他算法,然而,在经典的目标检测任务和少量拍摄的目标检测之间存在巨大的差距。让我们深入其中的每一项,了解每一项的结构和差异。
DeFRCN:解耦的快速 R-CNN,用于少量拍摄的物体检测
顾名思义,该模型改进了快速 R-CNN,用于少量拍摄的目标检测。更快的 R-CNN 由 3 个模块组成:“用于提取广义特征的共享卷积骨干,用于生成类别不可知建议的区域建议网络(RPN),以及用于执行类别相关分类和定位的特定任务 RCNN 头”[1]。

图 1:更快的 R-CNN 和去耦更快的 R_CNN 架构。图片来源于论文1
为了修改更快的 R-CNN 以在少数镜头设置上工作,作者试图解决两个问题:
- 多任务学习的问题 : R-CNN 头的模型负责分类,换句话说就是看什么,而 RPN 头的目的是理解看哪里,它解决的是本地化问题。“第一个头部需要平移不变特征,而定位头部需要平移共变特征”[1]。在 FSOD 的情况下,当我们有单独的小任务时,这两个头的联合优化会导致更差的结果。
- 共享骨干的问题。正如我们在上面的图片中看到的,更快的 R-CNN 有一个 2 头共享主干。它在对象检测方面工作得非常好,但是在一些镜头设置中,当针对新类别进行微调时,准确性会有所下降。前景-背景混淆可能出现,这意味着基础训练中的背景可能在新的微调阶段变成前景。这就是为什么来自 RPN 的梯度导致共享主干的过度拟合和模型不能收敛。
为了解决这些问题,作者建议通过添加两个模块来改变该模型:梯度解耦层(GDL) 和原型校准块(PCB) ,以改善少数镜头设置中的对象检测。让我们仔细看看这些模块。

图 2: DeFRCN 架构。图片来源于论文1
正如我们在图 2 中看到的,两个梯度去耦层(GDL)放置在主干后面。GDL 进行仿射变换,该仿射变换由可学习的通道权重来参数化。在前向传播期间,来自共享主干的特征通过 Aᵣₚₙ和 Aᵣ𝒸ₙₙ"[1].被变换到不同的特征空间
定义了常数λ ∈ [0,1],这有助于在反向传播期间设置主干、RPN 和 RCNN 的去耦度。解耦程度可以通过λᵣₚₙ和λᵣ𝒸ₙₙ来调整,粗略地说,这决定了梯度将对前一层产生多大的影响。要停止来自 RPN 或 RCNN 的更新,我们可以设置λ = 0。否则,我们可以通过设置λ大于 0 来缩放梯度。换句话说,λᵣₚₙ和λᵣ𝒸ₙₙ决定了共享主干上每个 RPN 和 RCNN 的各自贡献。这解决了共享主干的第二个问题。
论文的下一个输入是原型校准块。分类需要翻译不变特征,而定位需要翻译共变特征。因此,本地化分支可能迫使主干逐渐学习翻译协变属性,这潜在地降低了分类器的性能。PCB 包括来自 ImageNet 预训练模型的强分类器、RoIAlign 层和原型库”[1]。
首先,它从支持集计算原型。我们来定义一个 M 路 K 拍设置的几拍问题。PCB 从支持集图像中提取特征图。使用 RoIAlign 将这些特征地图与地面实况框对齐后,它会生成 MK 实例表示。然后,它将表示缩小为一个原型银行。
对于来自微调的少镜头检测器的对象提议,PCB 首先在预测的盒子上执行滚动,并生成对象特征。然后计算该目标特征和支持集原型之间的余弦相似性 sᵢᶜᵒˢ。这种相似性被用作预测类别的得分。为了计算最终的分类分数,模型在 PCB ( sᵢᶜᵒˢ)给出的分数和微调的少发探测器(sᵢ)给出的分数之间进行加权聚合。

在少触发检测器和 PCB 模块之间没有共享的参数,使得 PCB 不仅可以保持分类目标平移不变性特征的质量,而且可以更好地分离 RCNN 内的分类任务和回归任务。此外,由于 PCB 模块是离线的,无需任何进一步的培训,它可以即插即用,很容易装备到任何其他架构,以建立更强大的少击探测器”[1]。
https://arxiv.org/pdf/2102.12152v3.pdf双感知注意少拍物体检测
本文作者提出了另外两个问题:
- 支持特性的质量问题:在 FSOD 期间,我们关于新对象的支持信息有限,因此我们需要高质量的特性以获得更好的结果。为了解决这个问题,作者们正试图削弱噪音的影响。
- 相关性问题:同样,由于示例数量有限,很难获得支持集和查询集之间的高度相关性。这里的目标是提高对象间的相关性。
作者提出了一种称为双意识注意(DAnA)的新机制,它结合了两个新模块,称为背景衰减(BA)和跨图像空间注意(CISA)。
为了削弱噪声影响背景衰减块(BA)** 被提出。下图显示了该模块的结构。首先,通过线性可学习矩阵 Wₑ.对支持特征图进行整形和变换**

图 3:背景衰减块。图片来源于论文2
使用支持特征图的每个像素和 Wₑ.来计算注意力图接下来,他们将注意力地图与支持特征相结合,给出最重要的特征。最后,leaky relu 被用于一种更柔和的注意力策略。这种变换有助于获得更具区分性的支持特征。
本文提出的下一个区块称为跨图像空间注意区块(CISA)** 。该块的目标是帮助模型关注对象的最有代表性的部分,以确定类内相似性。**

图像 4:跨图像空间注意块。图片来源于论文2
“跨图像空间注意(CISA)的核心思想是自适应地将每个支持特征图转换成表示支持图像的特定信息的查询位置感知(QPA)支持向量”[2]。
设 Z 表示在 BA 块中处理支持特征映射,X 表示查询特征映射。CISA 使用 W𝓺和 Wₖ权重矩阵将 x 和 z 转换成查询和密钥嵌入𝑸和𝓚。
然后,它计算查询和支持之间的相似性得分:

其中𝑸和𝓚是所有像素的平均嵌入值。
对于下一步,添加了自我关注,因为作者假设关注不仅应该基于查询-支持相关性,还应该基于支持图像本身。

𝛽是一个常数系数。
最后的变换是通过将上述结果乘以位置感知支持特征图 z 来计算查询位置感知向量。该结果准备好被传递给对象检测。
DAnA 可以与对象检测框架相结合。因此,CISA 输出可以与查询要素地图相结合,并发送到区域建议网络等模块。作者在 fast-RCNN 和 RetinaNet 上进行了实验。
元 DETR:利用类间相关性的图像级少镜头物体检测
大多数少镜头对象检测框架结合了元学习技术和对象检测模型。Meta-DETR 也是如此。大多数方法基于更快的 R-CNN 或类似的对象检测算法。尽管这些模型取得了成就,但本文的研究人员发现了两个主要问题,并试图通过他们的解决方案来改善这些问题。

图 5:相似类之间分类不良的问题。图片来源于论文3
- 区域提议的问题:这可能在大量图像上工作得很好,但是在少量拍摄的情况下,我们每个类只有有限数量的例子。此外,我们试图在新颖的类上进行概括,这使得更难获得高质量的区域提议。
- 元学习任务定义不清的问题。每个支持类都被单独处理,这导致了很好地区分类似类的问题,如自行车和摩托车、牛和羊等(图 5)。
图 6 描述了整个元 DETR 算法。首先,具有共享权重的特征提取器被用于查询和支持图像。

图 6:元 DETR 算法架构。图片来源于论文3
为了解决相似类之间高度相关的问题,作者提出了一种新的模块,称为相关聚集模块(CAM)。它将查询特性与支持类聚合在一起,以进行与类无关的预测。与其他方法的主要区别在于,它可以同时聚合多个支持类,这有助于捕捉类间相关性并减少误分类。CAM 首先将查询特征与一组支持类进行匹配。然后,它将一组支持类映射到一组预定义的任务编码,这些编码以类不可知的方式区分这些支持类。
CAM 输出支持聚合的查询特征,然后这些特征成为用于对象检测的基于转换器的模型的输入。最近提出的可变形 DETR 用于物体检测。DETR 使用变换技术进行一阶段目标检测,因此在算法中没有区域建议。这解决了论文中提出的下一个问题:低质量区域建议。
匈牙利损失用于模型,与可变形 DETR 相同。此外,在 CAM 之后使用余弦相似交叉熵来分类类原型。
该算法的训练过程与上述相同。首先,使用基本数据集进行全面训练,然后使用新类和基本类进行微调。
结论
每篇论文的作者都试图用一种新的创造性方法来解决少镜头目标检测问题。如上所述,经典物体检测和 FSOD 的精确度之间存在巨大差距。然而,这种模式有巨大的潜力,希望有一天我们可以拥有像经典物体检测一样有效的 FSOD 算法。
参考
[1]乔,李,赵,杨,李,赵,邱,徐,吴,张,解耦快速 R-CNN 用于少镜头目标检测 (2021)。| Github
[2]陈,陈,刘,杨,苏,洪,常,杨,林,杨,叶俊杰,徐文辉(2021)。| Github
[3]张刚,罗,z,崔,k,陆,s,【元】:利用类间相关性的图像级少镜头目标检测 (2021)。| Github
自我监督对比学习述评
原文:https://towardsdatascience.com/review-on-self-supervised-contrastive-learning-93171f695140?source=collection_archive---------9-----------------------
自我监督对比学习简介与综述
在过去的几年里,对比学习和自我监督技术成为计算机视觉领域的一个热门话题。来自不同人工智能研究实验室的许多研究人员正在致力于创建新的架构,并探索这些技术的有效性。
在本文中,我们将讨论自我监督对比学习的优点和缺点,概述最近的进展,然后回顾最近两个最流行的算法:SwAV 和 SimCLR。让我们深入了解一下!
为什么自我监督学习的想法对许多专业人士如此有吸引力?作为数据科学家,我们几乎总是面临缺乏有标签的干净数据的问题。为了进行目标检测或分割,我们需要大量的标记数据。有时候注释那么多数据是很昂贵的,在某些情况下,我们甚至不能从特定领域获得足够的数据。这就是自我监督技术派上用场的地方!
自我监督学习和对比学习
自我监督学习是非监督学习的一个子集。与监督学习不同,它不需要任何标记数据。相反,它创建自定义的伪标签作为监督并学习表示,然后在下游任务中使用。
自我监督学习主要用于两个方向:GANs 和对比学习。对比学习的目的是将相似的样本分组,而将不同的样本分组。
对比学习的主要动机来自人类的学习模式。人类在不记得所有小细节的情况下识别物体。例如,我们很容易根据颜色、形状和某些其他特征来查看图像并在其中找到表格。粗略地说,我们在头脑中创建某种表征,然后用它来识别新的物体。自我监督学习和对比学习的主要目标分别是创建和概括这些表征。
自我监督的任务被称为借口任务,它们旨在自动生成伪标签。有很多不同的方法可以自动创建任务,比如
- 颜色增强
- 图像旋转和裁剪
- 其他几何变换。



例子 a .几何变换,b .颜色变换,c .拼图游戏:图片来源[1]
有许多新的方法和技术来进行自我监督的对比学习。这些技术的三个最重要的组成部分是托词任务的定义、主干和对比损失。为了找到这些组件的最佳组合,进行了许多研究。
这一领域最受欢迎的两部作品是:
- SimCLR [3]:由 Google Research 创建的算法
- SwAV [2]:由脸书研究所发布的最新算法
视觉表征对比学习的简单框架(SimCLR)

图片来源:【https://amitness.com/2020/03/illustrated-simclr/
为了创建 SimCLR 的架构,Google 研究团队通过比较自我监督学习算法的不同组件做了大量的工作,最终,他们找到了最佳架构,该架构在论文发表时是对比学习中的 SoTA。他们的架构由四个主要组件组成:
- 数据扩充
- 基本编码器
- 投影头
- 对比损失
为了创建托辞任务,SimCLR 使用数据扩充。作者尝试了许多不同的增强构图,并通过随机裁剪、调整大小、颜色失真和高斯模糊获得了最佳效果。他们表明,随着扩充变得越来越复杂,模型开始表现得更好。
第二个组件是基本编码器。他们评估了许多不同的主干,因此他们使用了不同深度的 ResNet。他们的研究表明,更深层次的网络能显著提高训练效果。
下一个实验是选择投影头。具有投影头的架构在下游任务上显示出比没有投影头的架构好得多的结果。进行了许多实验来选择模型的最终结构。因此,选择 Danse-Relu-Dense 结构作为投影头。
最后但同样重要的是:损失函数。归一化温度尺度交叉熵损失(NT-Xnet)被用作对比损失,其目的是拉近表征并推开不同表征。

(1)标准化温度标度交叉熵损失(NT-Xnet)
首先,计算一个正表示和所有其他负表示之间的相似性。余弦相似性被用作距离度量。接下来,用负交叉熵损失(1)来计算正的一对示例(I,j)的损失函数。计算所有正对的最终损耗。
如上所述,进行了大量的实验,最终,研究团队展示了导致他们成功的主要结果:即扩大规模显著提高性能。缩放意味着使用更大的批量(对于模型,训练批量从 256 到 8192 不等)、更大的主干以及更长时期的训练(即使在 800 个时期的训练之后,SimCLR 也可以继续其改进)。
在多个视图之间交换任务(SwAV)
最近的 SoTA 在自我监督学习是由脸书研究所提出的。像 SimCLR 一样,SwAV 架构也是基于对自我监督学习技术的不同组件的实验而创建的。然而,他们的成功是基于他们在架构上做出的两大改变:增强类型和集群而不是投影头。这是他们建筑的最终结构:
- 多作物种植
- 基本编码器
- 使聚集
- 损失与“交换”预测问题。

SwAV 架构:图片来源[2]
对于数据扩充,SwAV 再次使用几何和颜色变换,然而,作者提出了一种新的独特而有效的技术来创建托词任务。这项技术被称为多作物种植。这种类型的增强创建了相同图像的多个视图,而不增加计算成本。在增强之后,我们得到标准高分辨率(224X224)图像的两个变体,以及同一图像的许多采样低分辨率(96x96)视图。这些视图是从主样本图像裁剪和颜色增强的。使用低分辨率视图有助于在不增加太多计算的情况下获得更好的图像样本。
对于基本编码器,再次使用具有不同深度的 ResNets。
该模型的主要区别之一是第三个组件:集群分配。聚类算法的主要问题是它们离线工作,这意味着我们需要将整个数据集提供给算法来获得分配。这在自我监督的环境下是行不通的。SwAV 作者将聚类视为在线任务,并向聚类算法提供小批量数据。Sinkhorn Knopp 算法用于聚类。
为了计算 SwAV 的损失,作者使用了交换问题技术。

(2)交换损失
这里,l(z,q)表示交叉熵,其中 q 被称为代码(聚类的输出),z 是图像特征和所有原型之间的点积的 softmax。法典可以被认为是基本真理。假设同一图像的两个不同视图的表示应该包含相似的信息,因此应该可以从另一个视图的表示中预测一个视图的代码。
基准测试结果

自监督模型的基准结果:图像源[2]
结论
对下游任务的基准测试结果表明,自我监督技术目前还不能超过监督学习技术,但这些都是强大的方法,可以用于不同的领域,其中数据注释稀缺或难以标记数据是具有挑战性的。
文学
[1]https://arxiv.org/pdf/2011.00362.pdf
[2]https://arxiv.org/pdf/2006.09882.pdf
[3]https://arxiv.org/pdf/2002.05709.pdf
通过构建一副牌来回顾 GitHub Copilot
原文:https://towardsdatascience.com/reviewing-github-copilot-by-building-a-deck-of-cards-3c25c63b63e0?source=collection_archive---------20-----------------------
通过在 Go 中构建一副牌来测试副驾驶

亚历山大·奈特在 Unsplash 上拍照
不久前 GitHub Copilot 发布了测试版。你必须在他们的 GitHub 注册进入。我报名了,没想到会收到邀请。结果我很幸运得到了一个。几个月来,我一直在项目开发过程中积极使用它,并希望分享我对它的见解。
什么是 GitHub Copilot?
Copilot 是编辑器的一个插件,它使人工智能训练的模型能够帮助你提供代码建议、代码生成和提示。人工智能由 OpenAI Codex 提供支持。目前支持的编辑器有 VS Code、Jetbrains 和 NeoVim。
围绕 Copilot 有很多争论,因为 GitHub(微软)在授权代码上训练了这个模型。这一事实引发了许多关于生成的代码是否因违反许可而被非法使用的讨论。一些许可证声明您可以自由使用代码,但不能重新分发。
很多文章都说不要用它,但是我要逆流而上。这可能是我见过的最酷的扩展之一。这将大大加快开发速度,在开发过程中也有很大的帮助。你应该一有机会就尝试一下。
它不仅很好,而且速度很快,能够提出与当前代码库相匹配的建议。它分析你的代码,似乎神奇地知道你想编码什么,并匹配你当前的代码库。
你会问这是怎么回事?接下来,你的代码被发送到模型(讨论的主题之一),这样它就可以分析你的代码的上下文。这是提出相关的好建议所必需的。
这也是我还没有开始在工作中使用它的原因之一,我不希望公司代码到处乱飞,我还不清楚代码的哪些部分是共享的,哪些部分不是。
在他们的网站上,copilot 的工作原理通过流程图图片得到了很好的解释。
为了复习 Copilot,我们将编写一副扑克牌,同时逐一介绍 Copilot 的功能。
代码建议
副驾驶的一个主要特点是能够给出代码建议。大多数 ide 可以建议变量或函数的使用,但是这里不同的是 Copilot 实际上可以建议完整的代码块。
代码建议有两种方式,内联建议,当您编码时,它在您的当前位置后显示为灰色代码。Copilot 不仅像大多数 ide 一样建议完成您的单词,它还可以根据您的上下文建议新的字段。下面的片段展示了我如何使用 Copilot 内嵌建议来为我们的游戏创建Deck。你按下标签接受建议。
GitHub Copilot —内联建议
看看我们是如何创建Deck和Card类型的,几乎完全是通过按 Tab 键来接受建议。
如果你不喜欢一个内嵌的建议,你可以跳到下一个建议,这取决于你的操作系统。
通过按下alt + ],或者在我的情况下(瑞典语),我按下alt + å来切换下一个解决方案。
GitHub Copilot —在内嵌建议之间切换
有时建议可能不正确,您可能需要更高级的牌组。您可以通过按下ctrl + enter让 Copilot 向您展示 10 种不同的建议,这将显示完整的代码建议。这将建议多行解决方案,而不是逐行建议。并非所有的建议都是你想要的,但我发现它们是找到解决问题的灵感的有用方法。
GitHub Copilot —为我们生成一副卡片
现在,我们在几秒钟内就有了一个完整的Deck,以及洗牌、弃牌和抽牌的功能。
让我们给我们的main函数添加一些逻辑,看看这是否如我们所愿。让我们看看是否可以洗牌,从牌堆里抓几张牌印出来。这是一个非常简单的任务,但即使是现在,我们也可以从副驾驶那里获得帮助。看看我是如何简单地通过 tab 键浏览主函数的。副驾驶可以建议这些事情,因为它一直在使用你当前的代码库上下文。
请注意我是如何接受 gif 中的大多数更改的,但有时我会手动键入第一个字母,以便让副驾驶知道我想要什么。当你发现与副驾驶的合作时,你会意识到这个名字很棒。它不是一个你可以纯粹依赖的自动化代码编写器,但它确实和你一起编码。你按下标签几次,然后意识到它在错误的轨道上,轻轻推它一下,回到标签页。
GitHub 副驾驶——为我们生成一个打印手的主函数
现在运行该程序将打印 5 张卡片,然而,它将总是打印相同的 5 张卡片,我们遇到了一个小问题,过于依赖生成的代码。虽然这是一个很好的例子,但我们不能依靠它来解决问题。
[{Spades Six} {Spades King} {Spades Nine} {Clubs Ace} {Hearts Two}]
单元测试
现在我们有一副牌可以玩了,对吧?老实说,在生成代码时,你可能会变得懒惰,快速浏览一下,然后想Looks good!
我总是向我的团队强调的一件重要的事情是单元测试,尤其是现在在这个例子中,当我们有已经生成的代码时。
让我们写一些单元测试,以确保甲板工作如预期,让我们确保让副驾驶帮助我们这样做。编写单元测试是我注意到的许多开发人员由于时间紧迫而放入技术债务部分的事情之一。这是一个很大的风险,因为它往往会留下错误的代码,并且做出改变会变得更加困难,因为你不知道在应用修复时会破坏什么。
我将首先确保shuffle正常工作,并且Deck尺寸正确。因此,让我们创建一个main_test.go并确保。
我首先验证我的Deck尺寸是否合适,注意在找到符合我需求的建议之前,我不得不在不同的建议之间切换。然而,仍然节省时间。
GitHub Copilot——为我的甲板长度生成单元测试
由于运行主函数并看到相同的输出,我怀疑Shuffle不是随机的。所以让我们也为它生成测试。
让我们来看看它,看看它是如何工作的,然后编写一个简单的测试。
Copilot —生成随机播放方法
它遍历整副牌,使用math/rand包用一个随机生成的数字交换当前索引的位置。让我们看看 Copilot 能否帮助我们创建一个测试。
GitHub Copilot —随机播放功能的生成单元测试
两个测试都通过,正确的长度和两副牌是不一样的。但是运行 main 函数总会触发同样的输出,一定是 draw 函数?让我们回顾一下这个函数。
func (d Deck) Draw(n int) []Card {
return d[:n]
}
那里不会有太多问题。
我写下这个调试过程,因为它非常重要。Copilot 非常棒,帮助我们很快就有了一个游戏平台,但它也是一把双刃剑。对于有使用math/rand包经验的开发人员来说,这个 bug 是非常明显的。乍一看,我们拥有的代码看起来像是在做我们想要的事情,但是如果开发人员没有多少经验,就很容易被愚弄。
math/rand包使用一个全局源来管理生成什么随机数,如果这个源不是使用Seed设置的,我们将总是得到相同的“随机”生成的数字,使得Deck总是洗牌并发给我们相同的牌。
是的,为洗牌阶段创建的单元测试,因为第一副牌和第二副牌是不一样的,但是,如果我们多次运行测试并打印它们,你会看到牌总是一样的。
为了修复这个错误,我们可以改变种子,以防止人们能够预测抽什么牌,如果你正在创建一个在线赌场,这是非常重要的。
copilot——修正了生成的函数不能随机产生相同的数字
评论建议
关于副驾驶的另一个很酷的事情是,你可以根据你的评论得到建议。写下你想做的事情,副驾驶会遵从。例如,我更喜欢表格驱动的单元测试,所以让我们把这个告诉副驾驶员进行Draw功能测试。
GitHub CO-Pilot——从注释中生成表驱动的单元测试
看到这有多简单了吗?出于某种原因,Copilot 把它变成了一个注释,但是除了删除它之外,我还做了一个完整的表驱动单元测试,从一个小注释中抽取了 5 张卡作为例子。
当然,它并不完美,我把它修改成了下面的要点,但是 95%的测试都生成了。
GitHub Copilot —生成单元测试
同样,一切似乎都在按预期运行。但是回顾为抽奖生成的代码,我们将再次看到一个小错误。
func (d Deck) Draw(n int) []Card {
return d[:n]
}
抽一张牌只是返回最新的索引,它不会丢弃抽中的牌。这意味着我们会一次又一次地得到同样的卡片,这不是我们想要的。
让我们转到该功能,看看 Copilot 是否可以修复自己的错误。
GitHub Copilot —修复函数内部的逻辑
嗯,那很简单。另一种方法是使用注释告诉副驾驶我们想做什么。
GitHub Copilot —使用注释生成代码
结论和评论
Copilot 是一个令人惊叹的产品,它将非常有帮助。然而,有一个很大的但是,你不能依靠它来解决你的问题。正如上面的例子所示,您仍然需要了解正在发生的事情并审查代码。
不要忘记为生成的代码编写测试(Copilot 会在这方面帮助你),因为它看起来像是在做你想做的事情,但包含单元测试一章中看到的问题。
我最大的优点如下
- Copilot 非常适合帮助解决“样板”代码。在编码时看到这些建议是非常有帮助的,它们可能并不总是与你想要的一致,但是大部分仍然是有用的。
- 这也是一个伟大的指路明灯,当你穿越你不熟悉的主题,需要灵感,通常,我谷歌,但很多谷歌搜索可以被副驾驶取代。
- Copilot 还加快了开发速度,很多时候,当我创建测试和新功能时,我可以通过 tab 键来查看不需要的代码。内联建议神奇地知道我想要什么函数,我需要什么输入参数和输出,这本身就是一个障碍。
然而也有一些缺点,正如我之前提到的,它是一把双刃剑。
- 除非开发人员意识到发生了什么,并花时间去理解 Copilot 为您创造了什么,否则代码错误的可能性很高。
Shuffle函数是一个很好的例子,它看起来是正确的,但是一直存在一个隐藏的大缺陷。 - 如果有太多的代码是由副驾驶生成的,你可能会失去对代码库的了解
- 尽管如此,对我来说,很多开发时间都花在了架构和找出解决方案上,而不是输入代码。
- 过于信任它的风险很高,它会做出非常好的假设,大多数时候它会做正确的事情。这可能会让开发人员思维迟钝,并“跳”出错误的代码。
我还没有尝试过的事情如下
- 公司代码——我不知道代码是如何被完全处理的,所以我不想公开它。也不确定合法性。在一个更大的代码库上尝试一下,看看它是如何处理上下文检测的,这会很有趣。
今天就到这里,一定要报名参加副驾驶并试驾一下。如果你想了解更多关于 Visual Studio 代码的技巧,我建议阅读我之前的文章。
保重,感谢阅读!
</7-vs-code-tricks-every-developer-needs-to-know-cc8b3dad50e4>
使用 Amazon CodeGuru Reviewer 检查 Python 脚本
原文:https://towardsdatascience.com/reviewing-python-scripts-using-amazon-codeguru-reviewer-36927f213d01?source=collection_archive---------36-----------------------
了解 Amazon CodeGuru Reviewer 和自动化代码评审的方法

图片来自 Unsplash
2020 年的某个时候,AWS 推出了一项名为亚马逊代码大师的新服务。
CodeGuru 主要有两种服务:CodeGuru Profiler和 CodeGuru Reviewer 。
对于本文,我们将更多地关注 CodeGuru 评审员。
什么是 Codeguru 评审员?
根据 AWS 用户指南,亚马逊 CodeGuru Reviewer 是一项使用程序分析和机器学习来检测开发者难以发现的潜在缺陷的服务,并提供改进你的 Java 和 Python 代码的建议。
通俗地说,它审查您的代码,并在检测到潜在缺陷时给出建议。
不幸的是,这些建议并不详尽。它有九个方面
- AWS 最佳实践
- 并发
- 资源泄漏预防
- 防止敏感信息泄露
- 常见的编码最佳实践
- 重构
- 输入验证
- 证券分析
- 代码质量
你可以在这里 找到更多关于以上九个方面的信息 。知道该服务目前只支持 Java 和 Python 语言也很好。
让我们使用 Amazon CodeGuru Reviewer 进行一次简单的代码审查。
在开始之前,请确定以下事项。
- 您已经有了要使用的测试存储库。在这里随意克隆我在这个演示中使用的测试库。
- 您知道如何运行简单的 git 任务,比如创建一个新的分支,提交和推送变更等。这里的是这方面的一篇复习文章。
- 您知道如何在 GitHub 上创建 Pull 请求。这里是这方面的复习文章。
- 您拥有 AWS 管理帐户,可以使用 AWS 控制台查找服务。您可以在这里创建一个免费的等级帐户,并使用这个来帮助您快速使用 AWS 管理控制台。
如前所述,我特别为这个演示创建了一个简单的存储库。这里可以找到。
存储库包含一个.py文件。我们会用这份文件来进行审查。
让自己熟悉这项服务
Gif 来自 Giphy
- 前往 AWS 管理控制台,搜索亚马逊代码大师或代码大师。一旦你选择了搜索,你就会被带到 Amazon CodeGuru 控制台。在那里,您将看到两个可用的主要服务:剖析器和评审器。

作者截图
- 点击显示 Codeguru associate repository(在红色框突出显示的下面)的部分按钮。通过这种方式,CodeGuru Reviewer 可以访问您选择的存储库。
您会看到一个类似这样的页面表单。

作者截图
在这一页上,有四件重要的事情要做
- 指定要使用的源提供程序。由于演示资源库目前存储在 GitHub 中,所以我们选择 GitHub。
- 因为我们选择了 Github,所以我们需要通过点击 Connect to Github 按钮将服务连接到我们的 GitHub,并允许服务访问您的 Github (注意,选项根据您选择的源提供者而变化)。
- 选择特定的演示存储库。在我的例子中,我会选择名为与亚马逊代码大师一起实验的存储库。
- 点击按钮:关联仓库。
点击按钮后,您将被重定向到如下所示的页面。

作者截图
您会注意到状态 s 字段(在突出显示的红色区域内) 在一段时间后从关联变为关联。
导航到上面蓝色突出显示的菜单部分中的代码审查页面。
它会带你到一个像这样的页面

作者截图
在 code reviews 页面上,您会注意到两个选项卡(突出显示的红色和蓝色):
- 完整存储库分析:审查特定 Git 分支存储库中的所有代码,并在必要时返回建议。
- 增量代码评审:只评审更新的代码行,它由拉请求(PR)触发。
点击此处了解更多关于两种点评类型的信息。
演示 1:完整的存储库分析
要获得完整的存储库分析,请点击完整存储库分析选项卡并选择创建完整存储库分析。您将被重定向到下面的页面。

作者截图
您需要在这里指定
- 您想要查看哪个关联存储库(在本例中:)Experimenting-with-Amazon-CodeGuru)
- 而分支代码是在(在本例中,分支是 主 分支)。
- 你可以选择给出一个代码评审名。然而,这位代码权威评审者会自动生成一个名字。但是,可以随意修改。
在上面的表单页面中点击创建完整的存储库分析按钮之后,您将被重定向到显示评审状态的上一个页面。
它看起来像这样。

作者截图
一旦完成,状态从未决变为完成

作者截图
(状态也可以更改为失败。大多数情况下,这是由于表单页面中的输入不正确,例如,用于查找代码脚本的错误分支名称等。)
从上面可以立即看到它输出了多少条建议
您可以通过点击(突出显示的红色)上方的名称字段下的链接找到建议。你会看到下面的页面。

作者截图
所有建议都可以在该页面上阅读。您也可以直接在您的 GitHub 存储库上查看这些建议。
演示 2:增量代码评审
请记住:
增量代码评审只有在关联的存储库上进行 PR 时才会被触发。
我继续添加了一个修改,通过在下面的代码中取消对return命令上面的print语句的注释,使.py文件生效。
通过共享 Deepnote
接下来,我做了下面一系列的事情
- 创建名为 trigger_pr,的分支
- 添加、提交所做的更改并将其推送到该分支。
- 最后,我在 Github 中创建了一个 Pull 请求,将 trigger_pr 分支合并到主分支。
我一创建 PR,就会触发增量代码评审,自动开始增量代码评审。
您可以通过返回到代码评审页面来确认这一点,并且您将会在增量代码评审选项卡下看到正在进行的评审,就像这样。

作者截图
像完整存储库分析过程一样,当完成时,状态从待定变为完成。您还可以查看输出了多少条建议(如果有,即建议可能为零),并按照您在上面查看的方式查看这些建议。
一个优秀的宠物项目应该是弄清楚如何使这个过程成为一个工作流程,而不是每次你需要审查某个东西时手动点击按钮或填写表格。
在 GitHub 的这里找到代码演示。
亚马逊 CodeGuru Reviewer 的潜在应用有
- 面试带回家测试的自动化代码审查。
- 当没有人审查 PR 时,自动进行 PR 审查。它还可以帮助人类评审者基于建议关注哪里,从而缩短评审过程时间。
回顾最近发布的拥抱脸🤗课程
原文:https://towardsdatascience.com/reviewing-the-recently-released-huggingface-course-a6b4ace16167?source=collection_archive---------10-----------------------
课程内容的概述和浏览

该上另一门课了|作者图片
大规模开放在线课程(mooc)是自学成才的数据科学家生活中不可或缺的一部分。如果你在一个满是想要成为数据科学家的房间里,有可能他们中的百分之五十都上过著名的吴恩达的机器学习课程。然而,问题就在这里。尽管我们中的许多人注册了各种在线课程,但只有少数人完成了这些课程。事实上,一项名为为什么 MOOCs 不起作用的研究在 3 个数据点中声称,在线课程的完成率和保留率是最低的。虽然有些人可能会说,学生必须有足够的动力来完成一门课程,但责任也落在内容创作者身上。

一个伟大的 MOOC 的食谱|作者的图片
我和很多人交流过,并听取了他们对发布内容的反馈。如果一门课程检查了以上五点,我相信它会成为一次很好的学习经历。
那么,为什么突然深入在线课程呢?这是因为最近,团队在 抱紧脸 🤗用抱脸库 在 NLP 上发布了他们的 免费课程。这门课程将让许多人不仅了解他们的图书馆,而且了解如何在 NLP 中完成最先进的任务。拥抱脸是自然语言处理生态系统中一个非常著名的名字。除了有一个很酷的标志,他们还被认为是 NLP 领域的民主化。
在这篇文章中,我们将走过,并得到一个课程的游览。然后,我们将查看课程内容、课程设置,以及它是否符合我们的需求。所以让我们开始吧。
🔖抱脸课程链接:https://huggingface.co/course/chapter1
关于❓的课程是什么
本课程的重点是使用 HuggingFace 生态系统教授自然语言处理的细节。尽管该课程是针对初学者的,但在某种程度上,它对中间用户和专家都有帮助。本课程的主要目标是强调四个重要的拥抱面部库的内部工作原理和用法:

拥抱脸库|作者图片
- 变形金刚 是一个库,提供了数千个像 BERT、GPT-2、RoBERTa、XLM、DistilBert、XLNet 等预先训练好的模型。,对文本执行任务,如分类、信息提取、问题回答、摘要、翻译、文本生成等。
- 分词器 将文本输入转换成数值数据。
- Datasets 是一个轻量级的可扩展库,可以轻松共享和访问数据集以及自然语言处理(NLP)的评估指标。
- 加速 库支持在多个 GPU 或 TPU 上分布式训练 Pytorch 模型,只需少量调整
除此之外,课程还会教你如何使用抱脸毂。整个课程以短视频片段的形式,并配有文字解释和可重复使用的代码。
什么是 pre-requisites❓
这门课程有几个先决条件,所以你可以充分利用它。它要求你对 Python 有很好的理解,并具备一定水平的基础深度学习知识。此外,在 Pytorch 或 Tensorflow 方面有一些经验将会有所帮助。

课程的先修课程|作者图片
这门课包括❓的哪些内容
课程分为三个主要模块,每个模块又分为章节或小节。随着您的进步,这些模块会越来越先进。主要模块如下:

课程的三个模块|作者图片
目前,只发布了第一个模块。其余两个模块将在未来几个月内推出。
模块 1

第一模块的内容(内容取自课程页面)|作者图片
第一个模块介绍了变压器库的概念以及如何使用它。此外,它还教授如何使用来自拥抱面部中枢的模型,在数据集上对其进行微调,然后在中枢上共享结果。
该模块进一步分为四章:
- 第 1 章
本章介绍了 NLP,以及为什么文本处理对机器学习从业者提出了挑战。然后解释了管道的概念— 管道是🤗变形金刚图书馆。
它将模型与其必要的预处理和后处理步骤联系起来,允许我们直接输入任何文本并获得可理解的答案——来源【HuggingFace 课程】
您可以将管道方法应用于几个 NLP 任务,如文本生成、文本分类、问题回答和许多其他任务。然后,您将深入了解变压器模型以及编码器、解码器和序列到序列模型的架构和工作原理。最后,您将了解编码器、解码器和编码器-解码器模型。
- 第二章
现在你知道变压器是什么,管道是如何工作的,你会看到它是如何工作的。您将使用 Transformer 模型和 tokenizers 来复制pipeline API 的行为。您还将了解到记号赋予器以及它们如何将文本转换成模型可以理解的输入。
- 第三章
事情现在开始有点进展了。本章重点介绍定制数据集的预训练 NLP 模型。您将学习如何利用高级的**Trainer** API 来微调模型,然后使用🤗加速库在多个 GPU 和 TPU 上训练你的 Pytorch 模型。
- 第四章
最后一章集中在拥抱脸生态系统的社区方面。它将教你如何浏览模型中心,这样你不仅可以使用社区培训的模型,还可以贡献你自己的模型。
模块 2

第二模块的内容(内容取自课程页面)|图片由作者提供
第二个模块深入到 Huggingface 数据集和记号化器中。一旦你对第一个和第二个模块有了相当好的理解,你将能够运用所学的知识来处理最常见的 NLP 任务。
模块 3

第三模块的内容(内容取自课程页面)|图片由作者提供
如果你想学习如何为特定用例编写自定义对象或者理解专用架构,这个模块不会让你失望。在本模块结束时,您应该了解 HuggingFace 生态系统,并以有意义的方式解决复杂的 NLP 问题。
单元 2 和单元 3 的章节发布后,文章将会更新
course❓使用哪些框架

该课程在 Pytorch 和 Tensorflow 都有。因此,如果您对这两个图书馆中的任何一个都感到满意,您应该可以开始了。此外,该课程可以很容易地跟随谷歌 Colab 笔记本电脑。
有奖问答🏅

每章的末尾都提供了补充测验来测试你的理解程度。然而,了解你是否真正掌握了材料的一个很好的方法是在你自己的项目中或通过与社区合作来利用所学的知识。
结束语🌟
那么,回到我们的问题,这个 MOOC 是否符合正确的标准?绝对的。课程内容是有意义的,有趣的,是很长一段时间所需要的。每个模块都经过精心策划,从简单到系统地推进。这可以防止初学者一开始就失去兴趣。该课程还鼓励参与者使用自己的例子或数据进行实验,这是一个好主意。MOOCs 缺乏互动性,包括测验和“尝试自己”练习可以帮助克服这一点。
👉有兴趣看我写的其他文章。这个 回购 包含了我分类写的所有文章。
查看 TensorFlow 决策森林库
原文:https://towardsdatascience.com/reviewing-the-tensorflow-decision-forests-library-1ecf50ae00c3?source=collection_archive---------17-----------------------
使用 Tensorflow 和 Keras 构建基于树的模型的库

感谢https://undraw.co/illustrations提供免费插图
在他们的论文 表格数据:深度学习不是你需要的全部 中,作者认为,尽管深度学习方法在图像和文本领域取得了巨大成功,但传统的基于树的方法如 XGBoost 在表格数据方面仍然大放异彩。作者检查了 Tabnet 、神经不经意决策集成(节点)、 DNF 网和 1D-CNN 深度学习模型,并使用 XGBoost 比较了它们在 11 个数据集上的性能。

表格数据:深度学习不是你需要的全部|来源:https://arxiv.org/pdf/2106.03253.pdf
这是一篇重要的论文,因为它重申了一个事实,即深度学习可能不是解决所有机器学习问题的银弹。另一方面,对于表格数据,基于树的算法已经显示出与神经网络性能相当,甚至优于神经网络,同时易于使用和理解。
对于喜欢使用基于树的模型的人来说,这是一个好消息。几个月前, TensorFlow Decision Forests,又名 TF-DF 库被谷歌开源。在本文中,我们将了解什么是 TF-DF,以及它如何对我们有所帮助。
目标
许多优秀的资源和代码示例已经作为文档的一部分提供(参考下面的参考部分)。因此,我不会重新发明轮子。本文不是入门指南,而是对该库的快速概述,展示其主要思想和特性。为了深入了解,推荐由 Eryk Lewinson 撰写的关于使用 TensorFlow 决策森林使用口袋妖怪数据集的文章。
张量流决策森林
决策森林(DF)是一类由多个决策树组成的机器学习算法。随机森林和梯度提升决策树是两种最流行的测向训练算法。tensor flow 决策森林是为训练、服务、推理和解释这些决策森林模型而创建的库。TF-DF 基本上是 c++Yggdrasil Decision Forests(YDF)库的包装器,使其在 TensorFlow 中可用。
TF-DF 为基于树的模型和神经网络提供了统一的 API。这对用户来说非常方便,因为他们现在可以对神经网络和基于树的模型使用统一的 API。
实施概述
TF-DF 库可以很容易地用 pip安装。但是,它仍然不能与 Mac 或 Windows 兼容。对于非 Linux 用户来说,通过 Google Colab 使用它可能是一种变通方法。
让我们看看在帕尔默企鹅数据集上使用 TF-DF 的基本实现示例。该数据集是 iris 数据集的替代物,目标是根据给定的特征预测企鹅物种。

brgfx-www.freepik.com 创造的水矢量

数据集的前五行
如您所见,数据集是数字和分类特征的混合,是分类机器学习问题的经典示例。TensorFlow 中的训练决策森林非常直观,如下例所示。该代码取自官方文件。

训练张量流决策森林|作者图片
很多事情都很突出。值得注意的是,不需要像一键编码和标准化这样的预处理。我们将在下一节谈到它们。
应用程序
我们已经看到了一个分类示例。TF 决策森林还可以用于回归甚至排名这样的任务。


使用 TF 决策森林的回归和排序示例|作者图片
突出
TF-Decision 森林在几个方面表现突出。让我们简要讨论其中的几个:

TF 决策森林的亮点|作者图片
易用性
- 相同的 Keras API 可以用于神经网络以及基于树的算法。将决策森林和神经网络结合起来创建新型混合模型是可能的。
- 无需指定输入特征。TensorFlow 决策森林可以自动检测数据集中的输入要素。

通过 TF 决策树自动检测输入特征|图片由作者提供
最小预处理
- 不需要像分类编码、归一化和缺失值插补这样的预处理。
- 不需要验证数据集。如果提供,验证数据集将仅用于显示指标。
TensorFlow 服务的简单部署选项
- 模型训练完成后,您可以使用
model.evalute()在测试数据集上对其进行评估,或者使用model.predict()进行预测。最后,您可以使用 TensorFlow Serving 将模型保存为SavedModel格式,就像任何 TensorFlow 模型一样。

通过 TensorFlow 发球 |作者图片
可解释性
- 有时候,对于高风险的决策,我们必须理解模型是如何工作的。TensorFlow 决策树有内置的绘图方法来绘制和帮助理解树结构。
这是我们的随机森林模型的第一棵树的图。
tfdf.model_plotter.plot_model_in_colab(model_1, tree_idx=0, max_depth=3)

交互式可视化|作者图片
此外,用户还可以访问模型结构和特征重要性以及训练日志。
改进的余地
TF 决策树打包了许多有用的特性,但也有一些需要改进的地方。
- 不直接支持 Windows 或 macOS(直到日期)。
- 到目前为止,TF DF 模块中只有三种算法可用:随机森林、梯度提升树和 CART 模型。

TF 决策森林库中所有可用的学习算法|作者图片
- 目前,也不支持在 GPU/TPU 基础设施上运行模型。
最后一句话&入门资源
总的来说,TF 决策树为使用 Tensorflow 和 Keras 构建基于树的模型提供了一个很好的选择。对于那些已经有 TensorFlow 管道的人来说,这尤其方便。这个库还在不断的开发中,所以很快就会有更多的特性出现。如果您想查看代码示例并使用该库作为您的用例,这里有一些适合所有级别的优秀资源。
- TensorFlow 决策森林教程
- GitHub 上的 TensorFlow Decision Forests 项目。
- 官方博客
重温 DCT 域深度学习
原文:https://towardsdatascience.com/revisiting-dct-domain-deep-learning-51458fe2e6e4?source=collection_archive---------17-----------------------
意见
对 JPEG 和 DCT 域数据的深度学习代表了一个有前途的新研究方向。
在进行我的学位论文提案时,我有机会重温了我在 ICCV 2019 年的论文“JPEG 变换域中的深度剩余学习”。大约一年后回顾它,看看这个领域从那时起是如何发展的,这是一次有趣的经历。在这篇文章中,我将给出我们在论文中提出的方法的一些细节,然后谈一谈 DCT 域深度学习的最新进展。

JPEG 与空间吞吐量的比较,稍后会详细介绍。图片作者。
概观
我预计许多读者将熟悉深度学习,这是现代机器学习中无处不在的技术。然而,很少有人熟悉 DCT 域技术及其在这里的应用。这些想法在 20 世纪 80 年代末和 90 年代初非常流行,当时解压缩 JPEG 对计算机来说是一个非常耗时的过程。这个想法很简单:重新定义你想要执行的操作,这样它们就可以在压缩数据上完成,而不是在像素本身上完成。这是可能的,因为 JPEG 转换(大部分)是线性的。我们通常将这些技术称为 JPEG、DCT 或压缩域操作。
虽然随着计算能力的增加,这些想法已经过时,但在我看来,它们仍然非常适用于计算机视觉,从长远来看,每幅图像节省几毫秒可以节省大量时间(例如:训练卷积神经网络),这正是我想在 ICCV 论文中展示的内容[1]。2019 年是该领域研究的一个极其活跃的领域,回顾进展令人兴奋,四种正交技术最终成为基础。
首先,这里是一些附加资源:
- 论文本身可以在 arxiv 上免费获得
- 我在开发这项技术时做了大量的笔记,你可以在这里阅读这些笔记也可以作为可运行 Jupyter 笔记本获得
- 文中使用的代码是公开的,你可以从我的 gitlab 获得
JPEG 和 DCT
有很多关于 JPEG 如何工作和离散余弦变换(DCT)的文章,所以我只简单介绍一下。JPEG 编码大致由以下步骤组成,从 RGB 图像开始:
- 转换图像 YCbCr 色彩空间,将亮度(灰度或 Y)数据与色彩数据(Cb 和 Cr)分开。
- 填充并居中图像。大多数编码器会进行色度子采样(4:2:0 是最常见的),这意味着颜色通道在每个维度上减半。由于 DCT 将在 8 乘 8 的块中进行,这意味着图像需要被填充到 16 的倍数,以便在对颜色通道进行二次采样之后,大小可以被 8 整除。然后通过从每个像素中减去 128 来使像素居中。
- 计算每个块的 2D 第二类离散余弦变换(通常称为 DCT)。这是 JPEG 算法的真正核心,压缩域运算中的大部分工作是处理 DCT 和算法的其他步骤,这些步骤对于导出运算来说通常是微不足道的。
- 上述变换的结果称为 DCT 系数,然后使用预先计算的量化表对其进行量化。只是每个 8 乘 8 模块的元素级除法,并对结果进行舍入。这是 JPEG 中主要的有损步骤,所有复杂的 JPEG 伪像都是由 DCT 系数上这个相对简单的操作引起的。
- 系数按之字形顺序矢量化,低频放在开头,高频放在结尾。这是因为量子化倾向于将我们大脑无论如何都无法清晰感知的高频归零。通过将零集中在向量的末尾,可以有效地对它们进行游程编码。
- RLE 向量然后被熵编码
JPEG 解码本质上是相反的过程。请注意,我们说第 4 步是有损耗的,因为它实际上无法撤消。我们知道用来划分系数的量化矩阵是什么,但是因为系数是四舍五入的,所以当我们相乘时,我们只能得到原始系数的近似值。
作为参考,DCT 由下式给出:

对于像素块 P,块偏移 m,n 和空间频率 α,β 。函数 V() 计算使变换正交的比例因子。这里有两个重要的结果需要注意。第一个是,每个系数是所有块中像素的函数,第二个是,第一个频率( α = β = 0):

换句话说,它是像素的未加权和,与块的平均值成比例。
JPEG 的线性度
正如我上面提到的,模拟 JPEG 压缩的一种方法是线性映射。我们可以对 JPEG 编码这样做,只要我们忽略上一节第 4 步中的舍入,它完全适用于 JPEG 解码。这很有用,因为任何其他线性地图都可以乘以 JPEG 线性地图,以创建一个新的地图,对 JPEG 数据进行操作。为了简单说明这一点,考虑以下两个实数的线性函数:

如果我想将 f 然后 g 应用于相同的输入,我可以简单地计算 f(x) 然后 g(x) ,这需要两次乘法,或者我可以计算

它只需要一次乘法。这是压缩域技术背后的思想:如果 f 是 JPEG, g 是对像素的一些操作,那么你可以将它们相乘来对 JPEG 数据进行操作。
那么这到底是什么样子的呢?布莱恩·史密斯在 1993 年发现了这一点[2],我试图用多元线性代数的思想将它形式化。如果你不知道什么是多元线性代数,它只是线性代数对任意形状张量的扩展(注:张量形状的恰当数学术语是它的型)。警告一下,这有点复杂。**
首先,让我们复习一些符号。本节中的所有方程都将采用所谓的“爱因斯坦符号”(他在研究广义相对论时开发的)。这本质上是一种写和的简写方式,它使得张量积更具可读性。在爱因斯坦符号中,有上指数和下指数,重要的是要记住,如果你看到一个上标,它是一个上指数而不是幂。不出所料,一个下标被称为下下标*。每当一个指数在表达式中作为一个张量的上指数出现,而作为另一个张量的下指数出现时,元素就会相乘并相加。每当一个指数出现在两个张量的相同(上或下)位置时,元素相乘但不相加。任何未加总的指数都会结转到结果中。这里有一个矩阵向量乘积的例子,关于矩阵 Q 和向量 x:***

因此,我们乘以索引 i ,因为它出现在 Q 的顶部和 x 的底部,然后求和,我们让 j 单独产生索引为 j 的向量 q 。
接下来,我们需要定义在这个模型下图像是什么样子。我们说单平面图像(例如,灰度图像)是类型(0,2)张量,这意味着它没有上索引和两个下索引(本质上它是一个矩阵)。我们将此表示为:**

被圈起来的次数有一个张量积(有时称为外积),其中的 H 和 W 是向量空间,表示一个对偶空间,对于我们的目的来说只是意味着张量积的结果有较低的指标。*
最后,我们可以导出 JPEG 压缩和解压缩张量。为了简洁,我不会把推导放在这里(它相当长),但你可以在论文的 3.2 节找到它。推导的结果是两个线性图,第一个是:

J 执行 JPEG 压缩,注意这里的 H,W 没有号,这意味着它们是较高的索引,因此当我们将其应用于 I 时,它们会被相乘。还要注意,X 和 Y 索引图像中的一个块,K 索引存储的系数(每个块有 64 个)。第二张地图是:*

它执行 JPEG 解压缩。有了这两张图,我们可以得到一张新的线性图,它计算像素的线性函数,如下所示:

并且计算相应的 JPEG 域映射为:

阅读最后一个等式的右边,我们可以看到新地图做了什么。它解压缩图像,应用 C ,然后压缩结果。但是因为我们事先将所有这些相乘,所以它在一个步骤中完成所有这三个步骤。
在继续之前,我将展示另一个重要的张量,我们将在下一节使用它:DCT 张量。这可用于执行正向和反向 DCT:

如前一节中的 DCT 方程一样, m,n 索引像素块,α,β索引空间频率。 V 是用于使变换正交的常数。注意缺失的求和:这由张量积来处理。
JPEG 领域深度学习
事实证明,这让我们在 JPEG 领域深度学习方面取得了很大进展。对于 ICCV 的论文,我们有一个简单的目标:使用前一节中的分析来制作一个 ResNet [3],它对 JPEG 域数据进行操作,但尽可能接近相同的结果,就好像它对像素进行操作一样。ResNet 有几个操作,我们需要定义每个操作。
卷积这个非常简单,直接来自上一节。卷积是像素上的线性映射,所以它们本质上是我们之前讨论过的 C 。使用同样的技术,我们可以将ξ定义为压缩域卷积。这里我们还可以做一些小技巧,如果你感兴趣的话,请看第 4.1 节。
批量规格化这个也很简单。批次范数定义了可学习的仿射参数γ和β,并测量批次的运行均值和方差。然后使用以下公式应用这些值:

正如我们之前所讨论的,0,0 系数与块的平均值成比例,这使得它易于提取,并且比计算像素平均值快得多(无条件读取与 64 次求和)。计算方差也很容易,事实证明,如果像素的均值为零,则 DCT 系数的均值等于像素的方差。类似地,应用β就像将它加到 0,0 系数上一样简单,应用γ就像将每个系数乘以它一样简单。有关该程序的更多详细信息,请参见第 4.3 节。
全局平均池这是批量标准化的一个延续。其思想是只取每个特征图的每个通道的平均值。这就像读取每个已经包含平均值的块的 0,0 系数一样简单。参见下图和论文的第 4.5 节。请注意,从这一点来看,ResNet 使用完全连接的层,而 GAP 输出正是这些完全连接的层所期望的输入,因此不需要导出进一步的压缩域操作。

DCT 域全局平均池。图片作者。
模型转换本节最后要提到的是,我们的公式中没有任何东西依赖于从随机权重开始,从预先训练的模型开始并从中导出 JPEG 域模型同样有效。我们称之为模型转换,它基本上意味着你可以得到一个模型,在 JPEG 域数据上操作,而不需要重新训练任何东西。
虽然这让我们对 JPEG 域 ResNet 了如指掌,但仍然缺少一大块:ReLU [4]。
ReLU 问题
CNN 本质上是非线性的,这使得它们能够学习如此复杂的映射。在现代架构中,ReLU 几乎专门用于引入非线性。前面的分析只适用于线性函数,所以我们需要依靠一种近似技术。
回想一下,ReLU 被定义为

将所有负值设置为零。这可以用二进制掩码来实现,定义如下

然后与原始特征图相乘。这样做的好处是近似遮罩比近似 ReLU 本身要容易得多(见下图)。

我们近似技术的示例模块。绿色表示负值,红色表示正值,蓝色表示零值。图片作者。
我们使用来自每个 JPEG 块的 DCT 系数的子集来计算近似掩模。通过仅使用系数的子集,我们仍然具有比完全解压缩更高的吞吐量。
到目前为止,最有趣的部分是我们提出的对 DCT 系数应用蒙版(像素蒙版)的方法,这是我们在上一节中讨论的 JPEG 线性的直接结果。对于这一部分,我们可以使用 DCT 张量 D ,因为我们不必担心跨块的相互作用。我们将用一个 DCT 块 F 来操作它的像素域块 I、和掩码 G.
如果我们天真地这样做,我们会:
- 解压缩图像
- 逐像素倍增蒙版
- 重新压缩图像
所有这些都是线性或双线性映射:

因此,我们可以将这些步骤相乘,得到一个包含所有三个步骤的双线性映射:

然后我们可以做出如下定义:

并且 H 是将像素掩模应用于 DCT 系数的双线性映射。这个操作比前几个稍微复杂一点,完整的细节在论文的第 4.2 节。
结果
那么所有这些是如何工作的呢?实际上相当好。我们在 MNIST [5]和 CIFAR [6]上测试了这项技术。这是我们使用的玩具网络:

玩具网络结构。图片作者。
这基本上是一个微小的 ResNet [3]。
第一件有趣的事情是近似值的精确度。首先,我们可以注意到,如果根本不进行近似(例如,通过使用所有空间频率来计算掩模,这相当慢),我们将像素域网络匹配到浮点误差内。当我们开始逼近 ReLU 时,通过比较朴素方法(APX)和我们的方法(ASM ),我们得到了以下精度:

左: RMSE 个人 8 乘 8 街区。中:模型转换后的网络精度。右:带再训练的网络精度。图片作者。**
即使用于重建的频率更少,我们的方法也做得很好,尤其是在再训练时。
接下来要看的是吞吐量。我们的目标是建立一个运行速度更快的网络,因为它不需要解压,我们成功了吗?算是吧:

吞吐量结果。图片作者。
我们可以看到 JPEG 训练稍微快了一点,而 JPEG 推理几乎快了 4 倍,这是一个很大的改进。那么为什么训练比较慢呢?推理不仅允许我们离线预计算一些我们需要的地图,而且 JPEG 训练的反向传递要复杂得多,因为它需要 JPEG 压缩和解压缩张量的梯度。
进一步的进展
虽然我的论文很整洁,但这类工作在 2019 年取得了一些其他重大进展。首先,我们应该谈谈我的方法的主要缺点:权重明显大于传统的 CNN。以至于基本上不可能将其应用于“真正的”架构或像 ImageNet 这样的数据集。这里提出的方法的权重大小为 O(HW ),而传统 CNN 的权重大小为 O(1)。我确实提出了这个工作的一个扩展,它的权重为 O(1 ),但是这个还没有发表,仍然有很大的内存开销。这种方法的目标之一是尽可能接近像素域操作,这就是为什么我们只使用一种近似。如果你放松这种约束,你可以做一些真正有趣的事情。现在在这一领域已经开发了另外三种基本技术。
什么都不做可能最著名的是 Gueguen 等人的【7】,其基本内容是“在不修改网络结构的情况下传递 ResNet DCT 系数”。事实证明,这只能以轻微的精度损失为代价,并且您可以从 ResNet 中移除初始层以获得高吞吐量,但是它似乎不能在整个图像分类之外工作(例如,检测、分割等不能很好地工作)。
块表示下一项技术通过为每个 DCT 块定义一个“块表示”【8】来利用 DCT 块结构。他们通过使用 8x8 步距-8 卷积来实现这一点。这给出了每个维度上八分之一大小的图像。他们将这一想法用于物体检测。
频率系数重排最后的技术利用了系数【9】的频率结构。他们通过重新安排频道来做到这一点。所以,再一次,你最终得到的图像是每个维度的八分之一大小,这次是 64 个通道。他们把这个想法用于语义分割。
总的来说,看到这个领域的发展是令人兴奋的。我认为这真的很重要,也很有趣,所以我总是鼓励人们参与进来。JPEG 文件无处不在,因此这类数学应用程序并不缺乏。作为另一个例子,在 ECCV 2020 上,我使用了后两种技术来实现 JPEG 伪像校正的艺术水平[10]。
参考
- 米(meter 的缩写))Ehrlich 和 L. Davis,JPEG 变换域中的深度残差学习 (2019),载于:计算机视觉国际会议论文集。
- B.Smith,运动 JPEG 视频的快速软件处理 (1994),载于:第二届 ACM 多媒体国际会议论文集。
- K.何等,【图像识别的深度残差学习】 (2016),载于:IEEE 计算机视觉与模式识别会议论文集。
- 动词 (verb 的缩写)Nair 和 G. Hinton,整流线性单元改进受限玻尔兹曼机器 (2010),机器学习国际会议。
- Y.LeCun,MNIST 手写数字数据库
- A.Krizhevsky 和 G. Hinton,从微小图像中学习多层特征 (2009)
- 长度 Gueguen 等人,直接来自 jpeg 的更快的神经网络 (2018)神经信息处理系统的进展。
- B.Deguerre 等,压缩 jpeg 图像中的快速物体检测 (2019),IEEE 智能交通系统会议。
- 赛。Lo 和 H. Hsueh-Ming,探索 DCT 表示的语义分割(2019)ACM 多媒体亚洲会议录。
- 米(meter 的缩写))Ehrlich 等人,量化引导的 JPEG 伪像校正 (2020)欧洲计算机视觉会议论文集。
重访我的元编程绘图库!
原文:https://towardsdatascience.com/revisiting-my-meta-programmed-plotting-library-c6802d0171c0?source=collection_archive---------32-----------------------
Hone.jl
回顾一下我过去做过的一个非常酷的项目!
介绍
一年多以前,我开始用 Julia 编程语言开发一个新项目。该项目旨在作为主要的实践,以及证明语言中的一些概念和想法,同时也用 Julia 的范式和方法进行一些实验。该项目名为 Hone.jl,Hone.jl 是一个面向对象的图形库,使用高级声明性调用来创建元代码。这有一些缺点,主要是 Julia 在一定数量的重复代码后中断了解释。如果您想阅读我写的介绍该软件的文章,您可以在这里查看:
不管这些问题,我认为这是一个超级酷的项目!不仅如此,编程真的很有趣!本着这个包已经正式推出一年的精神,我决定回去看看这个包是如何工作的,以及它能够产生什么样的结果。如果您想尝试使用 Hone.jl,或者查看我将在本文中使用的代码,您可以在 Github 上查看它,或者查看我用来生成本文中的结果的笔记本:
笔记本
https://github.com/emmettgb/Hone.jl
高级接口
为了使用 Hone.jl,我们需要添加这个包。它不在 Julia General 注册表中,所以我们必须通过 git 添加它:
julia> ]
pkg> add [https://github.com/emmettgb/Hone.jl.git](https://github.com/emmettgb/Hone.jl.git)
现在,在我的笔记本中,我将使用 DataFrames.jl 创建一个新的数据框:
using DataFrames
df = DataFrame(:A => randn(20), :B => randn(20), :C => randn(20))
现在我们可以使用 Hone:
using Hone
包中的所有内容都被导出,所以我们现在可以使用?()方法。Hone.jl 非常酷的一点是它是模块化的。这意味着我们可以单独创建散点图的各个部分,甚至可以随心所欲地添加新的形状。记住这一点,让我们来看看这个圆形:
?(Circle)

作者图片
我们现在将使用这些参数做一个圆。
shape1 = Circle(.5, .5, .08, :orange)
我们可以使用 show()函数显示圆:
shape1.show()

作者图片
由于我们的数据框具有多个要素,我们应该制作另一个形状以便绘制其他要素。我还会把这个做得小一点:
shape1 = Circle(.5, .5, .02, :orange)
shape2 = Circle(.5, .5, .04, :red)
shape2.show()

作者图片
现在我们将把这两个形状放入一个数组中,我们可以将它作为参数传递到散点图中:
shapes = [shape1, shape2]
现在看看我们的形状还需要什么,我们将使用相同的?()我们的散点类型方法:
?(Scatter)

作者图片
所有这些参数都是位置性的,对于某些参数,我们需要输入一些空值。回过头来看,这是一个糟糕的想法,但我并不介意,因为除了我之外,这个包并不打算由任何人添加,因为与 Julia 可用的其他包竞争并不一定在 Hone.jl 的目标列表中。因此,我们将 X 作为数据帧,y 作为数组,并创建一个散点图。不过,我们需要做的第一件事是准备要通过这个函数传递的 x 数据帧和 y 数组。为此,我们将首先从我们的数据帧中提取我们的:C 数组:
y = df[!, :C]
现在我们需要在 X 数据帧中去掉这一列。我们将使用 select()和 Not()方法来实现这一点。
x = select(df, Not(:C))
现在我们可以做散点图了!
plot = Scatter(x, y, shapes)

作者图片
哎呀。
看起来这个调用实际上将使用一个符号而不是一个数组,这个符号将调用数据帧上的列。这可能会产生问题,因为该包使用 DataFrames.jl 的旧版本,该版本可能支持对列进行索引,如下所示:
df[:A]
但是现在的语法应该是:
df[!, :A]
所以希望我们不会遇到这个问题。如果我们这样做了,我会简单地提供很长时间以来的第一次更新…
事实证明这个包有相当多的问题,为了解决一些问题,我们可能需要深入研究一下。幸运的是,我们完全有能力做到这一点!
代码内部
在我们开始修复这个包之前,我们应该看看里面的实际代码,这些代码实际上已经相当过时了。我知道这使用了装箱类型,这是一种在 Julia 中使用未知类型创建类型的过时方法,所以我们可能应该使用内部和外部构造函数将其更新为较新的方法。如果你想了解更多关于 Julia 中构造函数的知识,我也写了一篇文章,你可以点击这里:
git clone [https://github.com/emmettgb/Hone.jl.git](https://github.com/emmettgb/Hone.jl.git) --branch Unstable
这个包的排列方式有两个函数,_arrayscatter 和 _dfscatter。这两个方法与 Scatter()方法一起被分派来处理不同的类型。使用内部构造函数可以更有效地做到这一点,但是这也是包装在一个完全不同的对象中的,这个对象叫做 Frame。因此,我们不将散点图作为一种类型,而是保留分派,只改变框架的类型。举个例子,下面是一个新函数,用于创建包含两个数组的散点图:
function Scatter(x::Array, y::Array; shape = Circle(.5,.5,25),
grid = Grid(4),
features = [Axis(:X), Axis(:Y)],
frame=Frame(1280,720,0mm,0mm),
)
points = Points(x, y, frame, shape)
frame.add(points)
glabels = GridLabels(x,y, grid)
frame.add(grid)
frame.add(glabels)
for feature in features
frame.add(feature);
end
return(frame)
end
我更改的另一件事是更新 DataFrames.jl 调用,以反映最新版本的语法。由于 DataFrames.jl 没有 compat 绑定,所以可以假设它将使用最新版本。我还从 Frame 类型中删除了一些参数,我们现在要重构它。以下是现成的代码:
function Frame(width::Int64, height::Int64, lm, bm)
base = string("compose(context(units=UnitBox(0,0,",
width, ",",
height, ",",
lm, ",", rm,",",
tm, ",", bm,
")),")
objects = []
tag = base
composition = nothing
add(object) = composition,objects,tag = _frameup(base,objects,object)
show() = composition
tree() = introspect(composition)
save(name) = draw(SVG(name), composition)
(var)->(add;show;tag;base;objects;composition;save;tree;width;height;lm;bm;rm;tm)
end
我要做的第一件事是从底部去掉上边距和右边距,因为我想我不会再用这个方法了。我将用 0 替换它们。现在我们需要将它包装在一个可变结构中,并用 new()方法传递我们的类型。我们将从在我们的函数上面添加这个开始:
mutable struct Frame{A, S, T, SA}
add::A
show::S
tree::T
save::SA
tag::String
objects::Array
然后,我们将更改用于创建类型的最后一部分,并将其恢复为:
A, S, T, SA = typeof(add), typeof(show), typeof(tree), typeof(save)
new{A, S, T, SA}(add, show, tree, save, tag, objects)
我们也可以用它来创建一个完整的类型层次结构,并进行更多的转换——比如在 objects 类型中。我们可以将数组{Any}改为类似数组{HoneShape}的形式。现在我要更新并再次尝试使用该软件包!
julia> ]
pkg> update
结论
现在我们终于可以创建一个散点图,如下所示:
plot = Scatter(df[!, :A], df[!, :B], shape = shapes[1], grid = Grid(4),
frame = frame)

作者图片
我认为这是一个非常酷和有趣的项目,有很大的潜力。做了一点工作后,我真的很好奇我能在这个包中实现多长时间的功能!我很想知道是否有人认为我应该继续在这个方案上工作,或者我应该让它保持原样并继续前进。你怎么想呢?我想把事情进一步与互动和可能的动画,以及更多的图形功能。我在 Twitter 上发起了一个投票,你可以提供你的答案!您可以在此查看投票结果并进行投票:
感谢您的阅读!
重访 Numpy 和 ndarray
原文:https://towardsdatascience.com/revisiting-numpy-and-ndarray-e1e5f9a69791?source=collection_archive---------24-----------------------
ScPyT
关于 ndarray 对象和 Numpy 包的鲜为人知但有用的知识和技巧

在 Unsplash 上由 Faris Mohammed 拍摄的照片
我最近开始了一项艰巨的任务— —阅读整个 Numpy 文档,特别是最新发布的 Numpy 模块(1.19)的 API 参考。这么做的原因很简单,我是一名生物信息学博士生,我的研究重点是在广泛的生物学问题中开发计算工具。随着项目的进展,我发现对 Numpy 知识的缺乏极大地阻碍了我快速准确地找到最优解的能力,并且我浪费了大量的时间来搜索 Stackoverflow 上的某些命令。为了让我的生活更轻松,我问自己,为什么不直接钻研 Numpy 官方文档,这样可以很大程度上填补我的知识空白,节省我很多时间。
所以我确实阅读了文档,并且完全诚实地告诉你,我从阅读那篇中学到了很多。现在,我只想分享我在过去几周学到的技巧和诀窍,希望它最终会对你有用。
我决定将这个系列命名为:Python 中的科学计算,因为我将涵盖线性代数和统计建模。这是一个很大的话题,所以我必须把它分成几个部分:
- 重访 Numpy 包和 ndarray 对象(本文)
- Python 中的线性代数
- Python 中的统计建模(敬请关注)
我在这里总结的所有内容都来自于 Numpy 的官方 API 参考,但是我认为使这篇文章有价值的关键部分是因为我根据自己的工作经验提炼了它们,并且以我认为容易理解的方式组织了它们。你可以在我的 Github 页面找到所有的代码库:
https://github.com/frankligy/ScPyT
现在,让我们开始旅程吧!
ndarray 是如何存储在内存中的?
让我们创建一个 n 阵列:
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
ndarray 的一个您可能不知道的属性:
a.strides
# (24, 8)
当你访问strides属性时,它返回一个元组为(24,8),什么意思?为了理解它,我们必须知道 ndarray 是如何存储在我们的内存中的。
在底层,数据必须存储在平面 1D 阵列中,我们认为理所当然并每天使用的 2D 3D 阵列实际上需要复杂的内存分配过程。让我们以这个a数组为例。

内存和步幅属性中的数组
这个 2D 数组必须以上述方式展平并存储在内存中,正如你注意到的,数组中的每一项都是一个整数,默认占用 8 个字节,因此是 64 位,现在你知道np.int64是什么意思了吧?这意味着这个整数将占用 64 位内存空间。
现在我们回过头来看看我们的a.strides输出,它是(24,8),它表示沿着axis=0(行方向),跳跃一个单位需要跨越 24 步,它是从每整数倍 8 字节得到的,每行有三个元素。具体来说,从 1 跳到 4 需要 24 步的记忆。第二个8表示列方向,跳过 1 个单位需要 8 步,因为它们基本上是相邻的。
你理解 Numpy 中的 dtype 对象吗?
创建 ndarray 时,将自动推断出一个 dtype 对象并将其与该数组相关联。举个例子,
d = np.array([1,2,3])
d.dtype
# dtype('int64')
它的 dtype 是一个“int64”对象,也就是说,数组中的元素是均匀整数,每个整数占用 8 个字节或 64 位内存。有一种更正式的方式来表示这一点:
d.dtype == np.dtype('<i8')
# True
- ‘的意思是字节的顺序,为了简单起见,对于大多数情况它并不影响我们如何理解
dtype对象。它表示我们如何在底层存储字节。 - “I”表示整数,还有一些其他常用的符号值得记忆:'?'表示布尔值,“U”表示无符号整数,“f”表示浮点,“O”表示 python 对象,“U”表示 Unicode 字符串。
- “8”表示它在内存中占用多少字节。概括一下,' < f8 '应该是' float64 '吧?唯一需要特别注意的地方是,对于 Unicode 字符串,第三位不是表示字节数,而是表示字符串的长度。例如,' < U8 '表示长度为 8 的 Unicode 字符串。
为了进一步理解dtype,让我们再次使用'< U8 '的例子,
d_type = np.dtype('<U8')
d_type.byteorder
# '='
d_type.itemsize
# 32
d_type.name
# 'str256'
因此,为了方便起见,dtype对象将有三个易于访问的属性与其字节顺序、项目大小和快捷方式名称相关联。让我们仔细看看,U8表示 8 个字符的字符串,每个字符用 UTF8 编码,这是一种变长编码(每个字符会占用 1–4 个字节)。让我们取最大值,因此一个字符占用 4 个字节,8 个字符将占用 32 个字节。str256表示该字符串占用 256 位。作为扩展,如果使用 ASCII 编码,每个字符将由 1 个字节编码,例如,字母 A 将是 ASCII 表中的数字 65,它能够用 1 个字节(8 个二进制位)来表示。
结构数组和记录数组
顺便说一下,我选择这些例子是因为它们都是我日常生活中经常使用的东西。所以,请不要仅仅把它看作是我试图让你大吃一惊的一些有趣/奇特的用法,它们实际上在许多现实世界的例子中是超级有用的命令。
让我们创建一个结构化数组:
sa = np.array([('John',[88,95,100]),('Mary',[77,88,68])],
dtype=[('student','<U8'),('grades','<i4',(3,))])
想想我们要用一个数组来形象化下面的情况,有两个学生“约翰”和“玛丽”,约翰的数学、英语和生物成绩分别是 88、95、100,玛丽的是 77、88、68。我们可以用表格来说明这种结构:

一个结构数组代表什么?
这里我们有两个元字段,“学生”和“成绩”,对于字段“成绩”,它实际上是一个(3,)1D 数组,分别对应于“数学”、“英语”和“生物”。在结构数组sa中,我们定义了每个列的字段名(列名)和 dtype,以及一个可选的 shape 参数来指定 ndarray shape。然后我们把每一行/观察作为一个元组,形成一个结构数组。
结构化数组的好处不仅在于以节省成本的方式组织数据,而且允许您通过简单地键入以下内容来访问每个字段:
sa['student']
# array(['John', 'Mary'], dtype='<U8')
还有一个类似于结构数组的对象叫做记录数组,我们先把结构数组sa转换成记录数组ra。
ra = sa.view(np.recarray)
type(ra)
# numpy.recarray
使用记录数组的额外好处是,您可以使用以下方式访问每个字段:
ra.student
# array(['John', 'Mary'], dtype='<U8')
除此之外,结构数组和记录数组看起来非常相似。
切片和索引
根据官方文档,有三种方法可以对 ndarray 进行索引和切片,它们是:
- 基本索引
- 高级切片(数值型、布尔型)
- 现场访问
我已经在我的structural array and record array部分中介绍了字段访问。对于剩下的两个,基本索引是指我们使用整数或切片对象来切片 ndarray:
b = np.array([[1,2,3,4,5,6,7,8,9,10],
[4,5,6,7,8,9,20,11,12,13],
[1,2,3,4,5,6,7,8,9,9]])
b0 = b[1:3,4:7]. # basic indexing
这里(1:3)是一个 python slice对象,它相当于slice(1,3,1)。如果使用 1 或 3 这样的单个整数,这也是基本的索引。需要注意的是:基本的索引只会在原始的 **b** 数组上创建一个视图,它不会为此创建一个副本。为了说明这一点,我们更改切片b0数组上的一个值:
b0[0,1] = 99
那么让我们看看在原来的b阵列上会发生什么:

修改“视图”会改变原来的数组
你看到明显的“99”了吗?我们不小心改变了原始数组b的值,这可能会有不利影响,所以请确保您意识到这一点。无论何时使用基本索引,您都是在创建一个“视图”而不是一个完整的“副本”。
相比之下,什么是高级切片呢?高级切片允许您在想要提取元素的每个维度上传递索引。
b1 = b[:,(4,7)]. # (4,7) is advanced slicing
为了突出差异,(4,7)属于高级切片,但 4:7 是基本索引,因为它是一个slice对象。
高级切片总是会创建一个“副本”,因此您不必担心“基本索引”可能会引发的有害问题。
高级切片也可以接受布尔值,这是 Numpy 包中非常方便的方法。Python 原语list对象不支持布尔索引。
你需要知道的许多有用的功能
在我通读文档后,这里有一个我标记为“需要知道”的函数列表,因为我以前看到它们在现实世界的任务中使用过,或者我认为知道这些可以给你带来很多方便。
- 创建数组:(空、1、0、满和相关的 full_like)
- 身份数组:(眼,身份)
- 数值范围:(排列,linspace,logspace,meshgrid)
- 建筑矩阵 : (diag,tri,tril,triu,vander)
- 整形:(整形、对换、转置、展平、散开、新轴、挤压、扩展 _ 变暗、平铺、重复)
- 连接和拆分:(连接,堆栈,列 _ 堆栈,拆分,数组 _ 拆分)
- 功能编程:(沿轴应用)
- 分度:(在哪里)
- 逻辑:(逻辑异或)
- 数学 : (deg2rad,hypot,sinh,trunc,round,lcm,gcd 等)
- 随机 : (rand,randn,randint,choice,shuffle,beta 等)
- 统计 : (corrcoef、cov、直方图、分位数、var 等)
我建议在 Numpy 文档中检查它们的例子,并内化它们的用法。
结论:
下一次,我将带您浏览 python 中的线性代数模块,然后是统计建模。感谢阅读!如果你喜欢这篇文章,请在 medium 上关注我,非常感谢你的支持。在我的 Twitter 或 LinkedIn 上联系我,也请让我知道你是否有任何问题或你希望在未来看到什么样的 NumPy 教程!
Github 资源库:
https://github.com/frankligy/ScPyT
改革公共服务
原文:https://towardsdatascience.com/revolutionising-the-public-service-71d90ef88c08?source=collection_archive---------40-----------------------
以人为中心的人工智能如何改变公民互动

潘晓珍在 Unsplash 上的照片
几周前,我们庆祝了公共服务周。这是献给那些每天为我们提供各种基本服务的人们的一段时间。从清洁我们的城镇到维持我们的卫生基础设施。所有这些对一个国家的发展都很重要。在疫情战争期间,人们特别感受到了他们的工作,这些无名英雄不顾挑战,每天醒来,保持我们国家的各个方面正常运转。就这一点,他们值得我们感谢。
但是公共服务周并不是为了追忆过去。它更多的是描绘未来。公共服务转型所依赖的三大支柱是人、服务和技术。

照片由岩田良治在 Unsplash 上拍摄
公共服务是为公民服务的,因为他们是任何政府的核心。官员需要帮助他们的客户在尽可能短的时间内获得最好的服务。当然,我们必须记住每天与这些部门打交道的人的分布情况——老年人、年轻人、有文化的人、文盲、外国人、精通数字的人等等。这个清单实际上是无穷无尽的。这就是为什么这些部门每天都面临着一项艰巨的任务。

照片由 QuickOrder 在 Unsplash 上拍摄
这一挑战将我们引向第二个支柱,即服务。政府已经提供了数以千计的申请,一些通过办公室,另一些在网上。但对于任何大型组织来说,当它开始增长时,事情往往会变得难以控制。用户不可能了解政府提供的所有机会,即使个别部门竭尽全力告知其公民。人们需要指导来浏览网上申请的迷宫,评估他们的资格并最终申请。不幸的是,在某些情况下,道路并不那么清晰。他们只能偶然或通过别人的介绍找到一项服务。
此外,这些部门与具有不同期望和需求的人互动,如需要帮助的数字文盲。但他们也遇到了那些在网上迁移的人,他们的房子钥匙、汽车钥匙、驾照、信用卡,以及几乎大部分生活资料都存储在手机里。这些人的期望很高,他们无法理解为什么一些政府服务仍然处于离线状态。

马文·迈耶在 Unsplash 上的照片
这就是最后一个支柱发挥作用的地方,因为技术将是公共服务和客户之间新契约的基石。新开发的系统不仅能为客户提供超越现有线下服务的数字糖。但是新的服务将给客户带来许多实实在在的好处。让我给你举几个例子。
在任何大型组织中,人们往往会发现已经存在了几十年的遗留系统。由于所涉及的巨大投资和它们所具有的依赖性,很难取代它们。一个解决方案是采用机器人流程自动化(RPA)。这项技术使得构建、部署和管理模拟人类行为的自动化过程变得容易。想象一下你正在申请执照。尽管流程保持不变,但 RPA 系统正在处理这一事实使得它比人工处理要快得多,也更不容易出错。这样的系统将在短期内为市民提供优质服务。
但这只是冰山一角。一个更加雄心勃勃和重要的项目是一次性原则,这是一个电子政府概念,旨在确保公民、机构和公司只提供一次标准信息。访问一个部门并重复政府已经拥有的相同信息将成为过去。
毫无疑问,当人工智能(AI)增强政府服务时,所有这些转变的顶点将会到来。想象一下你的婚姻状况发生了变化。主要的公共服务应用程序为您提供相关信息和建议,而不是挠头试图找出从哪里开始。它意识到你的变化,并通知你需要通知各个部门。但它甚至更进一步。只需点击一个按钮,它就会代表你提交所有需要的信息。它还建议了您有资格享受的新福利。再一次,这个应用程序不是填写无止境的表格,而是请求你的许可来代表你申请。只需点击一个按钮,你就可以走了。
预想的好处相当可观;他们将永远改变公共服务,使其与人们对私营公司的期望持平。当然,有人可能会质疑这种系统的危险性,尤其是在隐私方面。然而,在这种转变中有一个词很有特色,那就是“技术的道德使用”。原因很简单。数字化转型的第一支柱是公民。如果我们想让公民使用这些系统,公共服务必须获得他们的信任,只有承诺以合乎道德的方式使用他们的数据,才能赢得他们的信任。

弗雷德里克·科贝尔在 Unsplash 上的照片
有了这个愿景,公共服务的未来看起来一片光明。与任何转型一样,将会面临许多挑战。但是在公共服务部门工作的人们心中装着公民,我确信他们将克服他们将面临的所有困难。最终,我坚信公共服务会更强更好。市民将对高质量的服务和技术感到满意,这些服务和技术将改善他们的生活。
如果你喜欢这篇文章并想联系我,请在🖊️ 媒体上联系我,🐦推特,🔗 LinkedIn ,📷 Instagram ,😊脸书或者🌐 网站
https://medium.com/dataseries/the-future-of-governments-267476e790a8 </10-questions-you-always-wanted-to-ask-an-ai-disruptor-but-never-did-5203a6d31aa4>
Alexiei Dingli 教授是马耳他大学人工智能教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他出版了几本同行评审的出版物,并成为马耳他的一部分。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。
奖励最大化对于完全智能是不够的
原文:https://towardsdatascience.com/reward-maximization-is-not-enough-for-complete-intelligence-d1afecde097a?source=collection_archive---------27-----------------------
多代理场景使得报酬最大化成为一种风险。讨论何时,而不是是否,我们应该相信奖励假说。
多巴胺 (下图)是人类体验的核心。众所周知,它与感受当前的快乐有关——那是你正在经历和享受的事情。多巴胺在预测未来方面也起着至关重要的作用——这是在计划中完成的,当你计划做你喜欢的事情时,释放出同样的快乐感。人体有一个超级复杂的基础设施,围绕着享受、愉悦、目标设定、生殖等等,所有这些都与这个分子有关。

来源,维基百科。
试图模拟多巴胺的作用可能是理解人类如何学习的一条途径。这个信号是我个人对强化学习如何与神经科学和生化系统联系起来的评论的中心(博客 TBD)。声称我们可以通过“求解”多巴胺来理解人类意图的目标,与我们可以从一个测量信号中优化任何复杂系统的目标非常相似(古德哈特定律源于人性)。
我们可以将我们需要的所有指标封装在一个单一的奖励函数中的想法是深度学习的当前技术应用所特有的。特别是在强化学习中,有一种理论认为,任何智能体都可以通过合适的标量奖励函数来学习解决其可达空间中的任何任务。这个 奖励假设 ( 链接)是在说,对于任何强化学习主体(通常被视为个体),我们都可以将多目标优化归结为标量优化。奖励假说,或者这篇文章中的假说,是由一些“创始人”或 RL 提出的,所以它是有分量的。
最初是在 Rich Sutton 的博客上说的:
我们所说的目标和目的都可以被认为是接收到的标量信号(奖励)的累积和的期望值的最大化。
在将这种方法应用于更复杂的互联网系统时,所有可以采取的行动(跨许多用户)都包含在同一个代理下,这扩展了最初想法的范围,并导致其有效性受到质疑。这篇文章旨在梳理奖励假说背后的一些关键思想,并指出我们应该在这个假说的适用性上划一条线。
在理解可以由标量奖励函数合理定义的行为时,有哪些限制?可能有一个精确的函数来描述任何尺度下的人类意图,但它可能对扰动过于敏感,试图找到它会弊大于利。
假设
由于实数和表达式的无限性,奖励假说有了很好的基础。该理论的支持者说,对于一个智能体来说,必然有一个高度精确的函数来满足它的需求。我并不否认这种函数的存在,而是我们是否应该费心去寻找它们。
下面是对假设的两个低层次的批评(即假设在任何情况下都是合理的主张)。首先,我们应该考虑这些标量奖励函数是否可能永远不会是静态的,因此,如果它们存在,我们在事后发现的那个将永远是错误的。此外,由于存在无限可能的奖励函数,所以也可能无限难以找到代理的奖励规格。如果我们知道我们不太可能找到正确的表示,那么将每一个可能的回报都包含在标量函数中又有什么意义呢?
对于提供分数和排行榜的游戏,奖励函数很直观:最大化分数。对于具有多个优先级的代理,例如健康和事业,通过关系优化找到奖励函数变得更具挑战性。我假设对个人来说,这样做更合理,但不值得,因为我们可以扩展状态-行动空间,以轻松解释多模态行为。这就是说,当阅读或锻炼时,人类可能采取非常不同的行动,并且他们可能以相关的方式对奖励函数做出贡献(奖励函数通常被定义为当前状态和行动的函数)。
奖励假说的真正挑战在于更多的存在性问题:
- 这对关系回报有用吗:标量函数能代表不同的人对不同的东西的价值吗,特别是当这些人相互作用或者系统必须决定一个人更想要它的时候?
- 控制和政治经济:让一家公司或一些机器理解、支配和执行特别调整的报酬,值得吗?考虑到以上所有因素,可以说,像营利性公司这样的公司正通过努力学习并根据你的奖励偏好和你最亲密朋友的偏好采取行动而使你受益。
学习别人的价值观并不一定是对我们某种形式的社会目标的侵犯。知道这样的近似是由设置将有错误,并采取行动,好像学习奖励无论如何是真的可能是。当公司超越基于点击的指标时,理解用户目标是参与度和价值最大化的合乎逻辑的下一步。
大卫·西尔弗、萨汀德·辛格、多伊娜·普雷科普和理查德·萨顿最近发表的论文、奖励就够了,通过大卫·西尔弗(领导了许多 DeepMind 的游戏研发工作;迄今为止 ML 的一些最引人注目的成功)和 Richard Sutton(80 年代 RL 领域的创始人)。在我看来,在这些系统上工作的人需要有一个更加多样化的话语,来说明 RL 被大规模使用的意义。是的,回报最大化可能在所有这些应用中都有用,但是人们需要考虑界限、红线、最终目标、价值等等。
论文中的许多观点都是合理的,但是那些认为回报最大化是建模和理解“社会智力、语言、概括”的唯一视角的观点就很难得到支持了。遵循这些对设计这样的关系系统有用的回报最大化和优化框架的主张,是对什么样的结构应该控制我们的生活的强有力的陈述。
(生物)逻辑代理和标量最大化
多巴胺在人类主观体验中起着核心作用的假设被创造为快感缺失假说 (1982):
快感缺失假说——大脑多巴胺在与积极奖励相关的主观快乐中起着关键作用——旨在吸引精神病学家的注意,越来越多的证据表明,多巴胺在与食物和水、大脑刺激奖励、精神运动兴奋剂和鸦片奖励相关的客观强化和激励动机中起着关键作用。
多巴胺现在稍微为人所知:
在学习和记忆的细胞模型中,大脑多巴胺在强化反应习惯、条件偏好和突触可塑性方面起着非常重要的作用。多巴胺在强化中起主导作用的概念是成瘾的精神运动兴奋剂理论、大多数成瘾的神经适应理论以及当前条件强化和奖励预测理论的基础。正确理解的话,它也是最近的激励理论的基础。
这种激励动机渗透在许多学习代理中,作为预期回报的升华,转化为控制行动的参数:

一个强有力的论点是,个人的行为就好像生命是一个精细调整的奖励系统,优先考虑繁衍后代。一个人的遗传和环境决定了某种条件,这种条件会重新权衡多巴胺回路中不同的优先级。
我们的大脑可能会在其已知行为范围内非常迅速地适应它在社交媒体中面临的变化,并通过进化慢得难以想象。如果社交媒体处于泡沫中,我们与它的互动不会相互影响,那可能没问题。当我们在社会的尺度上研究它,并试图比较不同群体的动机时,多巴胺预测和代理的标量优化的原则就失效了。
将优化应用于现实决策
这篇文章真正开始的地方是思考,更现实地希望,基于注意力的度量最大化时代的结束。基于注意力的指标优化是:技术公司如何使用一些简单的指标来推动他们平台上的参与度(短期内,持续地)。目标是考虑系统如何更好地平衡和共同优化用户的长期利益。
通过在伯克利举行的关于人工智能未来影响的会议,我听到了多个关于用户计量跟踪的大规模改革不太可能在短期内发生的第一手报道。
对这些公司来说高利润的东西暂时还会起作用,至少在任何监管通过之前。最终,我怀疑大型社交媒体公司会希望过渡到一种模式,使其平台的行为与用户的目标相匹配。
大多数认识到他们或者他们亲近的人沉迷于他们的手机的人不喜欢它,因此优化的改变是应该的。不再有点击率,犹豫时间,像数数等。!虽然,可能的结果是公司将当前的方法转变为不同的奖励功能,优化长期计划,但如果社交媒体应用的奖励功能旨在激励某些类型的生活方式,优化可能是不适定的。
看过去的短期指标使这些算法在屏幕上的行为(计算秒、分、小时)和生活方式结构(天、周、年)之间取得平衡。多目标优化领域非常清楚地说明了为什么这很难做到:
对于一个非平凡的多目标优化问题,不存在同时优化每个目标的单一解决方案。在这种情况下,目标函数被认为是冲突的,并且存在(可能无限)个 Pareto 最优解。如果没有一个目标函数的值可以在不降低其他一些目标值的情况下得到提高,那么一个解决方案被称为非支配、帕累托最优、帕累托有效或非劣解。如果没有额外的主观偏好信息,所有的帕累托最优解都被认为是同样好的……目标可能是找到一组有代表性的帕累托最优解,和/或量化满足不同目标的权衡,和/或找到满足人类决策者(DM)主观偏好的单一解决方案。
有无限多种解决方案。帕累托最优看起来不像是人类可以实际追求的东西。 我不希望我的应用程序在帕累托方案之间做出选择。
任何用户都应该有能力说明他们的目标是什么,并让算法调整他们的行为以匹配这一点。无论有多少反思,公司在不告诉我们的情况下定期在我们生活的幕后改变优化问题的事实是家长式的,不可取的。
由于盈利能力存在问题,用户的选择可能会受到限制。在这些系统的规模下,任何用户都可能看起来更像噪音,而不是公司优化的真实信号。用户之间的交互,以及他们经常使用的列举的应用程序,将在很大程度上决定这些系统的轨迹。
作为多目标优化的社会和系统
任何在社会中定义奖励功能的尝试都会侵犯我们认为不可剥夺的权利。人类社会作为一种新出现的进化行为,其稳定性还没有得到很好的研究。很快,将会对我们最重要的进化技能应用更多的测试案例。
如上所述,比较动机将转化为根据手头的权重对某些用户进行优先排序。考虑一个不祥的场景,某些应用程序可以准确预测我们的多巴胺水平,并利用它来调整个人及其最亲密朋友的行动。多巴胺峰值水平较高的人会优先于基线水平较低的人吗?反驳这一论点可以揭示更多的缺点,比如社交媒体永远不知道你的过去,不知道某人被某种形式的创伤所阻碍的巅峰幸福。
如果所有个体代理都同意这个目标,那么类似奖励假设的系统运行大型系统可能是有意义的,但事实并非如此。在大规模推荐的情况下(例如 YouTube、脸书……),从工程的角度来看问题有很多方法。这些系统设计中的每一个在高层次上都是合理的,但对下游的影响却大相径庭:
- 部署一个全局策略(累积推荐器是随着用户数量增长而拥有巨大行动空间的代理),人是环境。
- 改变奖励机制,使人们在包含推荐的环境中行动(可能是一种反向 RL)。
- 坚持一对一优化,其中用户查询一组权重,并且他们的体验对其他用户的数字选择封闭(交互仍然存在于现实世界中,在这种方法的预期抽象之外)。
许多观点和几个令人信服的答案都集中在人类排列上,特别是从个人的角度,这让我担心。更加集成和先进的数据驱动系统正在将我们推向那个方向,目前还不清楚我们何时会通过重新安排我们的偏好和目标而达到某个重要社会结构的临界点。
这些奖励不够的情况可能没有一个工具可以最优解决。有些问题最好不要优化。
这个原本出现在我的自由子栈 民主化自动化 。请查看或关注我的 推特 !
用 Dplyr 改写熊猫
原文:https://towardsdatascience.com/rewriting-pandas-with-dplyr-5927b856f87d?source=collection_archive---------29-----------------------
Python 和 R 在数据操作上的比较

尼提什·米娜在 Unsplash 上的照片
Python 和 R 是数据科学生态系统中的主流编程语言。两者都提供了大量的包和框架来执行有效的数据分析和操作。
在本文中,我们将从数据操作和转换任务方面比较两个非常流行的库。
- pandas:Python 的数据分析和操作库
- dplyr:R 的数据操作包
下面的例子由熊猫和 dplyr 解决的一些简单任务组成。使用这些包有很多选择。我用 R-studio IDE 做 R,用 Google Colab 做 Python。
第一步是安装依赖项和读取数据。
#Python
import numpy as np
import pandas as pd
marketing = pd.read_csv("/content/DirectMarketing.csv")#R
> library(readr)
> library(dplyr)
> marketing <- read_csv("/home/soner/Downloads/datasets/DirectMarketing.csv")
我们有一个关于营销活动的数据集存储在一个 csv 文件中。我们将这个数据集读入熊猫的数据帧和熊猫的数据帧,

营销数据框架(图片由作者提供)

营销 tibble(图片由作者提供)
我们现在可以开始工作了。
基于条件的筛选
任务:过滤花费金额大于 2000 的行。
下面的代码根据给定的条件创建一个新的数据帧或表。
#pandas
high_amount = marketing[marketing.AmountSpent > 2000]#dplyr
high_amount <- filter(marketing, AmountSpent > 2000)
对于熊猫,我们在数据帧上应用过滤条件,就像我们正在索引一样。对于 dplyr,我们将数据帧和条件都传递给过滤函数。
根据多个条件过滤
任务:筛选消费金额大于 2000 且历史高的行。
#pandas
new = marketing[(marketing.AmountSpent > 2000) & (marketing.History == 'High')]#dplyr
new <- filter(marketing, AmountSpent > 2000 & History == 'High')
对于这两个库,我们可以使用逻辑运算符组合多个条件。
我们将为下面的两个示例创建一个示例 dataframe 和 tibble。
#pandas
df = pd.DataFrame({
'cola':[1,3,2,4,6],
'colb':[12, 9, 16, 7, 5],
'colc':['a','b','a','a','b']
})#dplyr
df <- tibble(cola = c(1,3,2,4,6),
colb = c(12, 9, 16, 7, 5),
colc = c('a','b','a','a','b')
)

df(作者图片)
基于列排序
任务:根据可乐对 df 中的行进行排序。
#pandas
df.sort_values('cola')#dplyr
arrange(df, cola)
我们在 pandas 中使用 sort_values 函数,在 dplyr 中使用 arrange 函数。默认情况下,它们都是按升序对值进行排序。

分类 df(按作者分类的图像)
基于多列排序
任务:首先根据 colc 以降序对行进行排序,然后根据 cola 以升序对行进行排序。
这比上一个例子更复杂,但逻辑是相同的。我们还需要改变升序排序的默认行为。
#pandas
df.sort_values(['colc','cola'], ascending=[False, True])#dplyr
arrange(df, desc(colc), cola)

分类 df(按作者分类的图像)
对于熊猫,这些值根据给定列表中的列进行排序。列表中列的顺序很重要。如果我们想改变默认的行为,我们也传递一个列表给 ascending 参数。
对于 dplyr,语法稍微简单一点。我们可以通过使用 desc 关键字来改变默认行为。
选择列的子集
我们可能只需要数据集中的一些列。pandas 和 dplyr 都提供了选择一列或一列列表的简单方法。
任务:通过选择“地点”、“薪金”、“花费金额”列来创建数据集的子集。
#pandas
subset = marketing[['Location','Salary','AmountSpent']]#dplyr
subset = select(marketing, Location, Salary, AmountSpent)

子集(作者图片)
逻辑是一样的,语法也非常相似。
基于现有列创建新列
在某些情况下,我们需要将列与转换相结合来创建一个新列。
任务:创建一个名为 spent _ ratio 的新列,它是支出金额与工资的比率。
#pandas
subset['spent_ratio'] = subset['AmountSpent'] / subset['Salary']#dplyr
mutate(subset, spent_ratio = AmountSpent / Salary)
我们使用 dplyr 的 mutate 函数,而我们可以直接对带有 pandas 的列应用简单的数学运算。

(图片由作者提供)
结论
我们比较了 pandas 和 dplyr 如何完成简单的数据操作任务。这些只是基本操作,但对于理解更复杂和高级的操作是必不可少的。
这些库提供了更多的函数和方法。事实上,两者都是非常通用和强大的数据分析工具。
在下面的文章中,我将基于复杂的数据操作和转换任务来比较这两个库。
敬请关注后续文章!
感谢您的阅读。如果您有任何反馈,请告诉我。
用熊猫重写 SQL 查询
原文:https://towardsdatascience.com/rewriting-sql-queries-with-pandas-ac08d9f054ec?source=collection_archive---------27-----------------------
SQL 和熊猫实用指南

咖啡极客在 Unsplash 上的照片
Pandas 是一个用于数据分析和操作的 Python 库。SQL 是一种用于处理关系数据库的编程语言。它们的共同点是 Pandas 和 SQL 都操作表格数据(即表格由行和列组成)。
因为 Pandas 和 SQL 都处理表格数据,所以类似的操作或查询可以使用其中任何一种来完成。在本文中,我们将使用 Pandas 语法重写 SQL 查询。因此,这将是他们两人的实际指南。
我有一个 SQL 表和一个包含 15 行 4 列的 Pandas 数据框架。让我们从显示前 5 行开始。
mysql> select * from items limit 5;
+---------+--------------+-------+----------+
| item_id | description | price | store_id |
+---------+--------------+-------+----------+
| 1 | apple | 2.45 | 1 |
| 2 | banana | 3.45 | 1 |
| 3 | cereal | 4.20 | 2 |
| 4 | milk 1 liter | 3.80 | 2 |
| 5 | lettuce | 1.80 | 1 |
+---------+--------------+-------+----------+

(图片由作者提供)
我们有一些关于在不同零售店出售的商品的数据。在下面的例子中,我将写下一个查询任务,并用 SQL 和 Pandas 完成它。
示例 1
任务:找出每个商店商品的平均价格。
我们需要根据商店 id 列对价格进行分组,并计算每个商店的平均值。
mysql> select avg(price), store_id
-> from items
-> group by store_id;+------------+----------+
| avg(price) | store_id |
+------------+----------+
| 1.833333 | 1 |
| 3.820000 | 2 |
| 3.650000 | 3 |
+------------+----------+
在 SQL 中,我们在选择列时应用聚合函数(avg)。group by 子句根据商店 id 列中的类别对价格进行分组。
items[['price', 'store_id']].groupby('store_id').mean()

(图片由作者提供)
在 Pandas 中,我们首先使用 groupby 函数,然后应用聚合。
示例 2
任务:通过将 price 列重命名为“average_price ”,并根据平均价格对商店进行排序,来修改前面示例中的结果。
在 SQL 中,我们将使用 AS 关键字进行重命名,并在末尾添加 order by 子句对结果进行排序。
mysql> select store_id, avg(price) as average_price
-> from items
-> group by store_id
-> order by average_price;+----------+---------------+
| store_id | average_price |
+----------+---------------+
| 1 | 1.833333 |
| 3 | 3.650000 |
| 2 | 3.820000 |
+----------+---------------+
在 Pandas 中,重命名价格列有许多选项。我将使用命名的 agg 方法。sort_values 函数用于对结果进行排序。
items[['price', 'store_id']].groupby('store_id')\
.agg(average_price = pd.NamedAgg('price','mean'))\
.sort_values(by='average_price')

(图片由作者提供)
示例 3
任务:找到商店 id 为 3 的所有商品。
我们只需要根据商店 id 列过滤行。在 SQL 中,这是通过使用 where 子句来完成的。
mysql> select * from items
-> where store_id = 3;+---------+----------------+-------+----------+
| item_id | description | price | store_id |
+---------+----------------+-------+----------+
| 7 | water 2 liters | 1.10 | 3 |
| 9 | egg 15 | 4.40 | 3 |
| 10 | sprite 1 liter | 1.60 | 3 |
| 11 | egg 30 | 7.50 | 3 |
+---------+----------------+-------+----------+
对熊猫来说,这也是一个非常简单的操作。
items[items.store_id == 3]

(图片由作者提供)
实例 4
任务:找出每家商店出售的最贵的商品。
此任务涉及分组依据和聚合。在 SQL 中,max 函数应用于 price 列,值按商店 id 分组。
mysql> select description, max(price), store_id
-> from items
-> group by store_id;+----------------+------------+----------+
| description | max(price) | store_id |
+----------------+------------+----------+
| apple | 3.45 | 1 |
| cereal | 6.10 | 2 |
| water 2 liters | 7.50 | 3 |
+----------------+------------+----------+
在 Pandas 中,我们首先按照商店 id 对所选的列进行分组,然后应用 max 函数。
items[['description','price','store_id']].groupby('store_id').max()

(图片由作者提供)
实例 5
任务:找到所有包含单词“egg”的项目。
该任务涉及过滤,但与我们在前面的示例中所做的不同。在 SQL 中,我们将在 where 子句中使用 like 关键字。
mysql> select * from items
-> where description like '%egg%';+---------+-------------+-------+----------+
| item_id | description | price | store_id |
+---------+-------------+-------+----------+
| 9 | egg 15 | 4.40 | 3 |
| 11 | egg 30 | 7.50 | 3 |
+---------+-------------+-------+----------+
' %egg% '符号表示我们希望每个描述中都包含' egg '字符序列。
在 Pandas 中,我们将使用 str 访问器的 contains 函数。
items[items.description.str.contains('egg')]

(图片由作者提供)
实例 6
任务:找出所有在描述中包含“升”这个词并且比 2 美元贵的物品。
它类似于上一个示例中的任务,但有一个附加条件。
在 SQL 中,我们可以在 where 子句中放置多个条件。
mysql> select * from items
-> where description like '%liter%' and price > 2;+---------+--------------+-------+----------+
| item_id | description | price | store_id |
+---------+--------------+-------+----------+
| 4 | milk 1 liter | 3.80 | 2 |
+---------+--------------+-------+----------+
在 Pandas 中,我们可以应用如下多个过滤条件:
items[(items.description.str.contains('liter')) & (items.price > 2)] item_id description price store_id 3 4 milk 1 liter 3.8 2
例 7
任务:找到所有描述以“冰”开头的物品。
这是另一种基于文本的过滤。在 SQL 中,我们可以使用 like 运算符或 left 函数将描述的前三个字符与' ice '进行比较。
mysql> select * from items
-> where left(description, 3) = 'ice';+---------+-------------+-------+----------+
| item_id | description | price | store_id |
+---------+-------------+-------+----------+
| 6 | icecream | 6.10 | 2 |
| 14 | iced tea | 2.10 | 2 |
+---------+-------------+-------+----------+mysql> select * from items where description like 'ice%';+---------+-------------+-------+----------+
| item_id | description | price | store_id |
+---------+-------------+-------+----------+
| 6 | icecream | 6.10 | 2 |
| 14 | iced tea | 2.10 | 2 |
+---------+-------------+-------+----------+
在 Pandas 中,我们可以使用 str 访问器的 startswith 函数。
items[items.description.str.startswith('ice')]

(图片由作者提供)
结论
Pandas 和 SQL 都是在数据科学领域使用的流行工具。它们被证明是有效和实用的。如果你正在或计划从事数据科学领域的工作,我强烈建议两者都学。
我们已经使用 Pandas 和 SQL 做了一些基本的查询来检索数据。通过执行相同的操作来比较它们是一种很好的做法。它将提高你的实践技能以及对语法的理解。
感谢您的阅读。如果您有任何反馈,请告诉我。
电子商务中的 RFM 细分
原文:https://towardsdatascience.com/rfm-segmentation-in-e-commerce-e0209ce8fcf6?source=collection_archive---------13-----------------------

照片来自pixabay.com
实用的 RFM 教程,包含详细的数据预处理步骤和业务操作项
如果你是一名对无监督学习的商业应用——尤其是聚类——感兴趣的数据从业者,你应该熟悉 RFM 分割。
RFM 细分是一种众所周知的基于三个用户特征的用户细分策略:
- Recency (R):用户最近一次交易是什么时候?
- 频率(F):客户多久交易一次?
- 货币(M):用户的交易规模是多少?
我们可以使用这种技术来更深入地了解我们的用户群,让我们能够提出(更重要的是,回答)以下重要问题:
- 我们为用户提供了多少种不同的 RFM 细分市场?每个细分市场有哪些独特的高级特征?(通过回答这些问题,我们可以确定可用于最大化每个细分市场收入的业务杠杆)
- 每个 RFM 片段的百分比是多少?(回答这个问题有助于判断机会)
鉴于这种方法明显的潜在好处,在互联网上有大量关于 RFM 分割的资源也就不足为奇了。也就是说,我似乎找不到一个关于如何创建 RFM 分割的好教程。我的结果表明,教程要么
- 提供的数据预处理措施不充分,无法真正适用于真实的业务环境。
- 或者,没有对收集的细分市场进行适当的业务分析,导致没有可操作的步骤来跟进这项工作(我认为这应该是构建 RFM 细分市场的首要目标)
考虑到这一点,我决定写这篇教程。将涵盖以下主题:
- 具有现实(商业)考虑的详细数据预处理
- 进行 K-均值聚类(RFM 分段的引擎)的最佳实践,包括特征标准化和确定最佳 K(聚类/分段的数量)。
- 对收集的 RFM 细分市场进行实际分析,以便我们能够采取适当的业务行动,以及后续行动的机会大小。
让我们开始旅行吧,别再废话了!
数据
本文中使用的数据是一个电子商务数据集,可通过这个链接在 Kaggle 获得。数据集是交易数据,包含一家英国零售商在 2011 年的交易。
数据预处理
导入数据
我们的旅程从导入数据开始。
# import data
import pandas as pdraw_data = pd.read_csv('data.csv')
raw_data.head()

raw_data.head()
我们可以看到数据有八列,但是我们在后面的练习中将只使用其中的一个子集。
基础数据清理
原来,数据在某些列上包含空行,以及重复的行。在这一步,我们想摆脱他们。
# check NA/NULL
raw_data.isna().sum()

我们确实在一些列上有空行
# remove NULL
raw_data = raw_data.dropna(axis = 0, how = 'any')# check duplicates
raw_data.duplicated().sum() # 5225 duplicated rows detected# drop duplicates
raw_data = raw_data.drop_duplicates(ignore_index = True)
特征工程
这一步至关重要,因为我们开始将原始数据转换为具有适当格式的数据,以供即将到来的聚类算法使用。为此,我们将采取以下措施:
- 将
InvoiceDate列转换为方便的日期时间格式 - 通过将
Quantity和Unitprice相乘来创建trx_amount列 - 将
CustomerID列转换为整数格式
# convert datetime column format
raw_data.InvoiceDate = pd.to_datetime(raw_data.InvoiceDate)# create trx_amount col
raw_data['TrxAmount'] = raw_data.Quantity * raw_data.UnitPrice# include only positive TrxAmount values(exclude credit)
raw_data = raw_data[raw_data['TrxAmount'] > 0]# cast CustomerID column to integer
raw_data.CustomerID = raw_data.CustomerID.astype('int')
有了从上面的代码片段中获得的最新的raw_data数据帧格式,我们就可以为 RFM 分割构建一个新的数据帧了。dataframe 的关键字是CustomerID,有三列特性:最近、频率和货币。
首先,我们讨论第一个特性:最近性,我认为就所需的预处理而言,这是三个特性中最复杂的。我们将从下面的代码开始。
# recency (r) df
data_r = raw_data[['InvoiceDate','CustomerID']].groupby('CustomerID')['InvoiceDate'].agg('max').reset_index()data_r.head()

初始最近数据帧:data_r.head()
我们将用户最近度定义为自从用户进行最后一次交易已经过去了多长时间(以月为单位)。在这点上,我们首先需要确定我们用于向后计算月份的当前时间参考:我们将它设置为InvoiceData列的最近值。
# current time reference
cur_time = data_r.InvoiceDate.max()# month diff function
def month_diff(cur_time, datetime_val):
return 12 * (cur_time.year - datetime_val.year) + (cur_time.month - datetime_val.month)# recency month
data_r['Recency'] = data_r.InvoiceDate.apply(lambda datetime_val: month_diff(cur_time, datetime_val))
其次,如果客户最近一次交易发生在 6 个月或更久之前,我们会认为他/她绝对是被激怒了,因此,如果交易时间超过 6 个月,我们就没有兴趣对最近交易值进行编码,因为我们不再拥有有意义的额外信息。换句话说,最近值必须限制在最长 6 个月。
# clip max at 6 months backward
data_r.Recency = data_r.Recency.clip(lower = None, upper = 6)# drop InvoiceDate column
data_r = data_r.drop('InvoiceDate', axis = 1)# head
data_r.head()

已处理的最近数据帧:data_r.head()
我们结束了最近的事。现在我们将创建频率和货币特征。因为我们只想要最有意义(非过时)的信息,所以在构建频率和货币特征时,我们只考虑过去 6 个月的交易:
- 频率:用户在前六个月完成的交易次数。
- 货币:用户在过去六个月的平均交易规模
值得注意的是,从计算的角度来看,这个时间段约束也是有利的。假设你在亚马逊工作,创建 RFM 细分市场。如果您不限制时间窗口,您将最终使用他们超过二十年的事务日志数据(这在大小上可能太大了)。
# frequency & monetary(fm) df only w.r.t. last 6 months data
EARLIEST_DATE = pd.to_datetime('2011-06-09')
data_fm = raw_data[raw_data.InvoiceDate >= EARLIEST_DATE]
data_fm = data_fm[['InvoiceNo','CustomerID','TrxAmount']]data_fm = data_fm.groupby('CustomerID')[['InvoiceNo','TrxAmount']].agg({'InvoiceNo':'nunique', 'TrxAmount':'mean'}).reset_index()
data_fm = data_fm.rename(columns = {'InvoiceNo':'Frequency', 'TrxAmount':'Monetary'})
data_fm.Monetary = data_fm.Monetary.round(2)
data_fm.head()

频率-货币数据框架:data_fm.head()
最后,我们将近期数据框架(data_r)与频率&货币数据框架(data_fm)结合起来,得到我们的最终数据!
# join to have the final data df
data = data_r.merge(data_fm, on = 'CustomerID', how = 'left')
data = data.fillna(0)
data.head()

最终数据:data.head()
基于 K 均值聚类的 RFM 分割
标准化栏目
这一步在很多教程中经常被跳过。然而,最佳实践是标准化 R-F-M 特征,特别是因为货币函数具有货币的度量,这意味着标度与其他特征有很大不同。通过将其标准化,我们确保 K-means 算法不会高估这个货币函数(即,将它视为比其他特征更重要的特征)。
from sklearn.preprocessing import StandardScaler# feature columns
feature_cols = ['Recency','Frequency','Monetary']# standardized df for training
standardized_data = data.copy()# standardization
scaler = StandardScaler()
scaler.fit(data[feature_cols])
standardized_features = scaler.transform(data[feature_cols])
standardized_data[feature_cols] = standardized_features
肘法
如你所知,K-means 算法中的 K(聚类数)是一个超参数。因此,我们必须提前仔细选择它。肘法是最佳选择 K 的一种常用方法:我们绘制各种 K 值的误差平方和(SSE ),并选择 SSE 下降斜率在该值前后显著变化的 K 值。
对于那些不熟悉 SSE 的人来说,术语“误差”指的是数据点与其质心之间的偏差/距离。因此 SSE 是所有数据点的这种平方误差的数量。同样值得注意的是,SSE 值总是随着 K 的增加而减小。
为了继续,我们用十个不同的 K(1,2,…,10)拟合 K-means 算法十次,并保存每个收敛模型的 SSE(注意 SSE 存储在inertia_属性中)。
# fit K-means clustering on various Ks
from sklearn.cluster import KMeanskmeans_kwargs = {
"init" : "random",
"n_init" : 10
}sse = []
for k in range(1,11):
kmeans = KMeans(n_clusters=k, **kmeans_kwargs)
kmeans.fit(standardized_data[feature_cols])
sse.append(kmeans.inertia_)
让我们把肘法形象化!
# Elbow method plot
import matplotlib.pyplot as pltplt.figure(figsize = (12,8))
plt.plot(range(1,11), sse)
plt.xticks(range(1,11))
plt.xlabel("Number of Clusters")
plt.ylabel("Sum of Squared Error")
plt.show()

不同数量聚类的误差平方和
看上面的图,很明显我们可以选择 K= 3:观察在这个特定的 K 值之前和之后斜率的巨大差异。
拟合 K-表示使用最优 K
在知道最佳 K 是 3 之后,我们使用这个 K 值再次拟合算法。
kmeans_kwargs = {
"init" : "random",
"n_init" : 10
}# run kmeans with the optimal k
kmeans = KMeans(n_clusters=3, **kmeans_kwargs)
kmeans.fit(standardized_data[feature_cols])
data['cluster'] = kmeans.labels_
data.head()

具有从 K-means 算法获得的聚类数的数据
结果分析
我们的工作还没有结束。我们必须在群集被收集后对其进行解释。为此,我们可以通过显示 R-F-M 形心值以及每个集群中的用户数量来总结所获得的集群。
为什么是质心值?因为我们可以认为这些值是每个获得的聚类的代表。因此,我们可以使用这些值从相应的用户方面(R/F/M)来解释属于特定集群的用户的整体行为/特征。
# look at the centroids per cluster
centroid_df = data.groupby('cluster')[['Recency', 'Frequency', 'Monetary','CustomerID']].agg({'Recency': 'mean', 'Frequency': 'mean', 'Monetary':'mean','CustomerID':'nunique'}).reset_index()
centroid_df = centroid_df.rename(columns = {'CustomerID':'NumBuyers'})
centroid_df

获得的聚类:质心细节和聚类大小
根据上表,我们有三个用户群/细分市场:
- 集群 0:我们的顶级用户群。此类别的用户是最近/当前的定期购买者(最近购买率低,频率高)。他们最近的一次交易也就在几天前,之前半年的交易频率是 26 次。不幸的是,他们为数不多(66 个用户,相当于所有用户群的 1.5%)。
- 第一类:我们被搅动的用户群。这一类别的用户是我们选择退出的客户(最近率高【注意这是一件坏事】,频率低)。他们上一次交易是五个多月前,之前半年只有 0 或 1 次交易!不幸的是,他们也很多(1364 个用户,相当于所有用户群的 31.5%)。
- 集群 2:我们的休闲用户群。这一类别的用户是我们的常客(无论是最近的还是频繁的)。他们最近的交易发生在最近两个月内,在之前的六个月内交易频率高达三次。众所周知,他们是我们用户群中最大的一部分(2908 个用户,相当于所有用户群的 67%)
# give high-level name for each cluster
centroid_df.pop('cluster')cluster_names = ['Top Buyers','Churned Buyers','Casual Buyers']
centroid_df['ClusterName'] = cluster_namescentroid_df

获得了具有高级名称的集群
可操作的步骤
我们将根据对上述集群的了解,为每个集群创建一个定制的推广策略,如下所示:
- 顶级买家:没有必要用优惠券/促销活动来压倒他们(这为我们省钱),但我们可以优化/利用某种忠诚度积分来留住他们。
- 临时买家:我们需要提高这一细分市场的频率和货币价值。我们可以通过提供返现形式的优惠券来实现这一点(以实现重复购买),并具有较高的资格门槛(例如,优惠券仅对至少 50 英镑的交易金额有效)。
- 被搅动的买家:我们的首要任务是让他们在被搅动一段时间后再次与我们交易。为了鼓励他们这样做,我们可以提供一两张大额福利券。这与持续不断的推送通知密切相关。
总结和结论
祝贺你读到这里!👏
在这篇博客中,我们通过一步一步的 Python 教程,以端到端的方式在电子商务环境中执行了 RFM 分割!我们首先执行彻底的数据预处理,然后适当地拟合 K-means 算法(结合特征标准化和肘方法)。最后,我们解释了由此产生的细分市场,以便为每个细分市场制定个性化的推广计划。
啊,对了,对于那些喜欢 GitHub 界面的人来说,完整的笔记本可以在我的 GitHub repo 这里找到。
我希望这篇文章对你即将到来的 RFM 细分项目/任务有所帮助!总而言之,感谢阅读,大家在 LinkedIn 上和我连线吧!👋
Rfviz:一个交互式可视化包,用于解释 R
原文:https://towardsdatascience.com/rfviz-an-interactive-visualization-package-for-random-forests-in-r-8fb71709c8bf?source=collection_archive---------11-----------------------
实践教程
从随机森林算法的最初创建者和他们在 Java 中的最初实现开始,他们的工作被翻译成 R 包 Rfviz。
背景故事
首先,我想说的是,我不应该因为这个计划而得到任何荣誉。这应归功于 Leo Breiman 博士和 Adele Cutler 博士,他们是这一广受欢迎的成功算法的最初创造者。我只是一个幸运的学生,在我的研究生项目中与卡特勒博士一起工作。
Breiman 博士和 Cutler 博士最初用 Java 创建了允许你可视化和解释随机森林的图。你可以在这里看看原著的剧情和风格:
https://www.stat.berkeley.edu/~breiman/RandomForests/cc_graphics.htm
我有幸从 2017 年开始去了犹他州立大学,卡特勒博士是那里统计系的教授。我想做机器学习方面的研究生工作,并请她做我的研究生导师。她同意了,并向我展示了潜在的项目。在这个时候,我不知道她帮助创建了随机森林算法。事实上,直到我的项目进行到一半的时候,我才从另一个教员那里得知。当我走近她,问她为什么不告诉我时,她回答说,“哦,我真的不喜欢自吹自擂。”我希望这能告诉你她是多么脚踏实地,是一个怎样的人。
总之,她向我展示的一个潜在项目是将一些用于交互式可视化和随机森林解释的 Java plots 翻译成 R。我选择了这个项目,并在 2018 年完成了 R 的翻译,并将包作为 Rfviz 发布到 CRAN。
最近,我一直在工作中使用它,在我看来,能够获得比通过 Shapley 方法或整体变量重要性图等方法更深入的见解。我认为其他人应该更多地了解我从布雷曼博士和卡特勒博士的工作中获得的益处。这是这篇文章的灵感来源。
理论背景
随机森林
随机森林(Breiman (2001))使许多树木(通常 500 或更多)适合回归或分类数据。每棵树都适合数据的引导样本,因此一些观察值不包括在每棵树的拟合中(这些被称为树的出袋观察值)。在每棵树的每个节点上独立地随机选择相对较少数量的预测变量(称为 mtry ),这些变量用于寻找最佳分割。树长得很深,没有修剪。为了预测一个新的观察值,观察值被传递到所有的树上,预测值被平均(回归)或投票(分类)。
可变重要性
对于每个变量,为数据集中的每个观察值获得局部重要性分数。为了获得观察值 i 和变量 j 的局部重要性分数,对观察值 i 超出范围的每棵树随机置换变量 j ,并将变量 j 置换数据的误差与实际误差进行比较。观察值 i 超出范围的所有树的平均误差差是其局部重要性分数。
变量 j 的(总体)变量重要性分数是所有观测值的局部重要性分数的平均值。
邻近
邻近度是当两个观测值都超出范围时,两个观测值在同一终端节点结束的时间比例。获得所有观察对组合的接近度分数,给出对称的接近度矩阵。
注意:在处理近似时,建议使用 9 或 10 倍的树,因为这是两个观测值都超出范围的概率。这是为了确保每个观察结果能够与后续观察结果进行比较。
平行坐标图
平行坐标图用于绘制一些变量的观察值。变量可以是离散的或连续的,甚至是分类的。每个变量都有自己的轴,这些轴用等间距的平行垂直线表示。通常,轴从观察数据值的最小值延伸到最大值,尽管其他定义也是可能的。通过使用分段线性函数连接每个变量的观察值,绘制出给定的观察值。
静态平行坐标图不太适合发现变量之间的关系,因为显示很大程度上取决于图中变量的顺序。此外,对于大型数据集来说,它们承受着过度绘制的痛苦。然而,通过刷图(用对比色突出显示观察值的子集)平行坐标图可用于调查不寻常的观察值组,并将观察值组与变量的高/低值相关联。
Rfviz 制作的图
输入数据的平行坐标图。
预测变量绘制在平行坐标图中。观察值根据其响应变量的值进行着色。刷这个图允许研究者交互地检查输入数据,寻找不寻常的观察,异常值,或预测和反应之间的任何明显的模式。该图通常与局部重要性图结合使用,这使得用户可以更专注于对给定观察组重要的预测值。
局部重要性分数的平行坐标图。
每个观察值的局部重要性分数绘制在平行坐标图中。具有高局部重要性的刷牙观察可允许用户查看原始输入平行坐标图上的相应变量,并观察该变量是否具有高值或低值,从而允许诸如“对于该组,最重要的变量是变量j’”的解释。
邻近度的旋转散点图。
该图允许用户选择看起来相似的观察值组,并刷过它们,相应的观察值显示在两个平行的坐标图中。例如,在分类中,如果用户刷一组来自类 1 的观察值,那么他们可以检查局部重要性平行坐标图。对于正确分类该组很重要的变量将被突出显示,然后可以在原始输入平行坐标图中研究任何具有高重要性的变量,以查看重要变量的高值或低值是否与该组相关联。
使用案例:
这里使用的数据是来自图书馆 OneR 的乳腺癌数据集。它最初来自 UCI 机器学习资源库这里。
library(OneR)
library(rfviz)
library(tidyverse)
data(breastcancer)
bc[is.na(bc)] <- -3
data_x <- bc[,-10]
data_y <- bc$Class
head(breastcancer)

截图 1
#The prep function. This runs default randomForest() and prepares it for the plotting function.rfprep <- rf_prep(data_x, data_y)
我们的用例:假设我们查看随机森林中的可变重要性图。
varImpPlot(rfprep$rf)

截图 2
查看一些最重要的变量,我们可以看到,根据基尼系数的平均下降,“细胞大小的均匀性”和“细胞形状的均匀性”是两个最重要的预测指标。但是,这些价值观中哪些是最重要的,对哪个阶层最重要?让我们打开可视化工具,深入研究其中一个。
#Pull up the visualization toolbcrf <- rf_viz(rfprep, input=TRUE, imp=TRUE, cmd=TRUE)

截图三
我们可以看到这里有三个情节,还有一个“loon inspector”与情节进行交互。对于每列数据,每个平行坐标图都有单独的刻度,这就是为什么没有 y 轴刻度或标签的原因。刻度与该列的最大值和最小值相关。邻近图是一个 XYZ 散点图。主要是在空间上显示不同的类在树中是如何分组的。
首先,让我们看看什么颜色与每个类相关。在右侧的“loon inspector”中的“select”部分,单击“by color”子部分下的一种颜色。我们先点蓝色。在屏幕截图 5 中,您可以看到结果。

截图 4

截图 5
我们可以看到,所有与蓝色类相关的数据现在都突出显示了。这与哪一类相关?回到休息状态,运行:
bc[bcrf$imp['selected'],'Class']

截图 6
我知道这是最基本的,但这是我目前为止能快速简单地识别类的所有方法。我还没想好怎么在检查员身上标注颜色。现在我们知道蓝色是恶性或 1 级,灰色是良性或 0 级。现在单击可视化工具上的任意位置,将会取消选择。

截图 7
我们现在知道,蓝色是 1 类或患有恶性癌症的人。现在,让我们关注“细胞形状的一致性”列,这是基尼系数总体重要性图中平均下降的第二个最重要的变量。看一下局部重要性分数图,以及截图 7 中的“细胞形状的一致性”栏。从视觉上看,1 级/恶性肿瘤的局部重要性分值似乎倾向于高于 0 级/良性肿瘤。
现在,这里是深入解释和理解的地方。在局部重要性分数图上,用鼠标单击并向上拖动“细胞形状一致性”栏,靠近您认为两类或两种颜色的线会发生分离的位置。以下是我在截图 8 中选择的内容。

截图 8
在 R 中,运行:
bc[bcrf$imp['selected'],'Uniformity of Cell Shape']
c1 <- bc[bcrf$imp['selected'],]
summary(c1$`Uniformity of Cell Shape`)
table(c1$Class)

截图 9
现在对我们没有在局部重要性分数图上的“细胞形状的一致性”列中选择的数据部分做同样的操作。以下是我在截图 10 中选择的内容。

截图 10
再次在 R 中运行:
bc[bcrf$imp['selected'],'Uniformity of Cell Shape']
c2 <- bc[bcrf$imp['selected'],]
summary(c2$`Uniformity of Cell Shape`)
table(c2$Class)

截图 11
现在让我们看看结果。在我们最初选择的患者中,198/236 (~84%)来自 1 级/恶性肿瘤。“细胞形状均匀度”值的第一个四分位数为 4,中位数为 6,第三个四分位数为 9。
对于第二组,423/466 (91%)来自 0 级/良性。“细胞形状均匀度”值的第一个四分位数为 1,中位数为 1,第三个四分位数为 2。
由此,我们可以得出结论,对于预测的第二个最重要的变量,第一个四分位数为 4,中位数为 6,第三个四分位数为 9 的较高“细胞形状均匀性”值通常对随机森林的 1 类/恶性分类很重要。我说“一般”是因为我们选择数据中包括了一些 0 级/良性的。
另一方面,第一个四分位数为 1、中位数为 1、第三个四分位数为 2 的较低值“细胞形状的均匀性”通常对随机森林的 0 级很重要。更重要的是,我们可以查看确切的数据,并将其保存为 R 中的对象,以便进行更多的操作。
例如,假设我们不希望其他类的任何值出现在每个数据选择的“细胞形状一致性”的汇总数据中。
summary(c1$`Uniformity of Cell Shape`[c1$Class!='benign'])
summary(c2$`Uniformity of Cell Shape`[c2$Class!='benign'])

截图 12
那么 Rfviz 允许我们做什么呢?Rfviz 允许我们对随机森林进行更深入的交互和解释。我们可以可视化数据并与之交互,快速查看类别之间的差异,并查看总体重要变量对每个类别的局部重要性。
关于如何与工具交互的更深入的教程,请看这里。
我希望你喜欢这篇文章,并祝你在随机森林的解释和推断中好运。
参考资料:
布雷曼,2001 年。“随机森林。”机器学习。http://www.springerlink.com/index/u0p06167n6173512.pdf。
布雷曼,我,和一个卡特勒。2004.随机森林。https://www . stat . Berkeley . edu/~ brei man/random forests/cc _ graphics . htm。
C Beckett,Rfviz:R 中随机森林的交互式可视化包,2018,https://chrisbeckett8.github.io/Rfviz.
Rich:用 Python 在终端生成丰富美观的文本
原文:https://towardsdatascience.com/rich-generate-rich-and-beautiful-text-in-the-terminal-with-python-541f39abf32e?source=collection_archive---------7-----------------------
用几行代码调试和创建很酷的 Python 包
动机
在开发了一个有用的 Python 包或函数之后,您可能希望您的队友或其他用户使用您的代码。然而,您的代码在终端中的输出有点令人厌烦,并且很难理解。
有没有一种方法可以让输出像下面这样更清晰更漂亮?

作者 Gif
这就是 Rich 派上用场的时候。除了漂亮的印刷,Rich 还允许您:
- 生成关于任何 Python 对象的漂亮报告
- 调试函数的输出
- 创建一个树来显示文件结构
- 创建进度条和状态
- 创建漂亮的列
在本教程中,我将向您展示如何用几行 Python 代码完成上面提到的所有事情。
开始
要安装 Rich,请键入
pip install rich
要快速总结 Rich 的功能,请键入
python -m rich

作者图片
输出很漂亮!但是怎样才能重现上面这样的输出呢?
创建漂亮的打印输出
Rich 使用 pretty print 函数使调试变得容易。虽然 icecream 允许您查看产生输出的代码,但是 Rich 会根据数据类型突出显示输出。

作者图片
在上面的输出中,不同的输出基于它们的数据类型用不同的颜色突出显示。这个输出不仅漂亮,而且当有许多不同数据类型的输出时,对于调试也很有用。
生成关于任何 Python 对象的漂亮报告
场景:你不确定你正在使用的 Python 对象的功能。您不想在 Google 上搜索,而是想在终端中快速浏览 Python 对象。这可以使用help()来完成
但是,输出相当长,难以阅读。

作者图片
幸运的是,Rich 提供了inspect,这使得在终端中查看 Python 对象的文档更加容易。

作者图片
现在你知道sklearn.datasets提供了哪些数据集以及如何使用它们了!
调试函数的输出
Scenerio:您想知道函数中的哪些元素创建了特定的输出。所以你打印了函数中的每个变量。
解决方案:您可以简单地使用Console对象来打印输出和函数中的所有变量。

作者图片
您可以通过简单地使用console.log来查看产生函数输出的相关细节!这将使您更容易发现代码中的任何错误,并相应地修复它们。
创建目录的树形结构
如果我们想知道一个目录的结构,查看目录树结构会很有帮助。Rich 允许我们使用Tree对象来这样做。
例如,如果我们的数据目录包含两种类型的数据:data1和data2,我们可以使用tree.add方法将这两个文件添加到父目录中

作者图片
在data2下,我们有另外 3 个文件。我们可以使用与上面相同的方法将它们添加到data2。但是为了使它更有趣,我们还将使用['color_name]your_text'给我们的字符串添加颜色

作者图片
现在我们有了一个整洁的树结构,不同的叶子有不同的颜色!
创建进度条和状态
了解代码的进度或状态通常很有用。Rich 允许我们使用progress.track方法创建一个进度条。

作者 Gif
如果我们想记录一个特定任务完成执行的时间,我们可以使用console.status来代替

作者 Gif
是不是很酷?如果您不喜欢当前的微调器,可以使用以下命令搜索其他微调器选项:
python -m rich.spinner
然后通过为console.status方法中的spinner参数指定不同的值来更改默认微调器。

作者 Gif
创建漂亮的列
您可能只想比较两个不同要素之间的关系,而不是一次查看数据集中的许多要素。Rich 允许您使用等宽的整齐列一次查看多行数据。
我们将下载 Open ML 的速配数据集,查看两人年龄差距与匹配与否的关系。

作者图片
结论
恭喜你!您刚刚学习了如何使用几行 Python 代码生成漂亮的终端输出。我们都喜欢 Python 包,当我们等待它工作的时候,它们在终端上看起来很酷。
我希望这篇文章能给你一些想法,让你的工作流程更有效率,并开发一个有很酷的用户界面的包。我鼓励您探索 Rich,了解我在本文中没有提到的其他特性。
随意在这里叉玩这篇文章的源代码。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。
星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:
脊线、套索和弹性网回归
原文:https://towardsdatascience.com/ridge-lasso-and-elasticnet-regression-b1f9c00ea3a3?source=collection_archive---------2-----------------------
正则化的持续冒险和防止模型过度拟合的永恒追求!

套索、山脊和弹性网回归|照片由 Daniele Levis Pulusi 拍摄
这篇文章是上周介绍使用线性回归的正则化的延续。莴苣那边回到本质上,用更先进的技术简化我们的模型,使最好的数据科学/机器学习模型成为可能。我们如何简化我们的模型?通过移除尽可能多的特征。我为什么要这么做?我想要一个更简单的模型。为什么我想要一个更简单的模型?因为一个简单的模型概括得更好。泛化是什么意思?这意味着你可以在现实世界中使用它。该模型不仅解释了训练数据,而且也有更好的机会解释我们以前没有见过的数据。
正规化
正则化试图通过添加调谐参数λ或α来控制方差:
套索(L1 正则化)
- 正则项惩罚系数的绝对值
- 将不相关的值设置为 0
- 可能会移除模型中的过多特征
岭回归( L2 正则化)
- 惩罚回归系数的大小(大小的平方)
- 强制降低 B (斜率/部分斜率)系数,但不是 0
- 不会删除不相关的功能,但会最小化它们的影响
现在不要担心λ。现在假设λ是 1。对于岭回归,我们惩罚回归系数的大小。因此,较大的回归系数是较大的惩罚。

b 和 c 是回归系数
所以在这个岭回归中,我会取 b 的平方,并把它加到 c 的平方上。这就是我的惩罚。现在比这稍微复杂一点,因为有时我想让惩罚变强或变弱,我现在引入这个λ,这个调谐参数。所以我的惩罚现在变成了:

也称为 L2 或欧几里德范数
这就是岭回归的作用。通过在我的成本函数中加入这个惩罚,在训练过程中,它将保持这些 b 和这些 c 很小。这样做可以简化模型。这意味着任何给定的列都不会有那么大的功率。
套索做了几乎相同的事情。除了正则化罚函数没有平方:

也称为 L1 或曼哈顿/出租车规范
请注意,因为这里可能有负值,所以需要在部分斜率的系数上加上绝对值。
上例中的系数 b 和 c 由您使用的算法调整。我们通过引入一个不为 1 的 lambda 罚值给它添加了另一个怪癖——它一直在幕后,但为了简单起见,我们将其保持为 1。当需要评估你的模型的好坏时,通过成本函数,我们将把一个我们称为λ的惩罚乘以你的系数(或系数的平方),这将是一个额外的惩罚。
我们仍然有我们的一般成本函数。这只是对成本函数增加。我们的一般成本函数总是相同的,它是这样的,我们有 y——预测的 y,取它的平方,然后把所有这些加起来。这是我们的成本函数,基线。现在,为了正则化的附加惩罚是使用所谓的 L2 范数的岭回归,或者使用所谓的 L1 范数的 LASSO(最小绝对收缩和选择算子)回归。
对于这两种类型的回归,较大的系数对模型不利。对于岭,由于平方的原因,损失不成比例地更大,但是一般来说,较大的系数会降低模型性能,较大的系数会降低拟合优度。
名词(noun 的缩写)b:L符号是对闵可夫斯基规范和 Lp 空格的引用。这些只是将出租车和欧几里德距离的概念推广到以下表达式中的 p > 0p > 0 :

对于那些还记得线性代数的人
里脊回归
再次重申,岭回归是一种限制回归中独立变量(列/特征/属性)数量的方法。正则最小二乘准则最小化误差的最小平方加上正则项,正则项是常数和系数平方之和的乘积:

岭回归成本函数,以另一种方式表达|在某些文献中,有时使用α代替λ
本质上,这是为了防止部分斜率项变得过大。
这里我称这个惩罚系数为α,而不是λ。这有点令人困惑,因为在这个行话中,alpha 有几个非常相关的意思。所以我想提醒你,一般来说,你可能会有一些问题,lambda 是一个安全的赌注。α至少有两个非常接近但仍然不同的含义。
这里,我们有这个β的平方。什么是贝塔?β是系数的向量。所以β是一个向量,在我之前的例子中是 b 和 c。记住,我有 y = a +bX1 + cX2,b 和 c 是两个系数。β是一个向量,这里由两个数字组成。在我的例子中,这两个数字是 b 和 c;a 是截距,有时容易混淆地称为 b。
所以β的平方和上面的等式完全一样。什么是偏坡?部分斜率的另一个词是系数。为什么我们称之为偏坡?如果你记得,我们有一个斜率,当我们有一个线性回归时,y = a + bX,b 是斜率。如果你有多个 x,那么 y = a + bX1 + cX2 + dX3 等等。然后,在我刚才提到的例子中,b,c 和 d 都是部分斜率,这是因为它们乘以了列。列的输入值随变量的变化而变化的方式会影响输出。如果系数或部分斜率越大,影响就越大。当我说更大,我的意思是在数量上。
所以脊目标**是残差平方和(RSS)+λ(系数的平方和)**。*
- 使用 lambda 来平衡最小化 RSS 和最小化系数
- 当 lambda = 0 时,结果与常规线性回归相同:您已经移除了岭回归损失
- 随着λ增加到无穷大,系数变得更接近于 0
- 任何非零λ值都会将系数缩小到小于非正则化回归的系数
- 随着 lambda (alpha)的增加,模型复杂度降低
Lambda 只是一个标量,应该使用交叉验证(调整)从您的数据中学习。所以λ总是正的,介于零和无穷大之间。给你一个范围的基本概念,它很少比 1 大很多,可能是 2 或 3,通常是 1 的一小部分。这是为什么呢?嗯,事情就是这样解决的。我刚才说的有反例,但是作为一个普遍的启发,你通常会发现λ在 0 和之间,一个小值,让我们说大约 2。
如果模型的复杂度随着 lambda 的增加而降低,你怎么能看出这一点?

我们的回归线与蓝点吻合得很好
在上面的例子中,我近似了某种形式的回归,在这种情况下,可能不是线性回归。这种回归非常有效。然后我们添加了 lambda 参数。希望事情有所好转。如果我在这里看这个,我可能会想要右边的那个。我的理由是,我看到这些蓝点,它们到处飞,它们在那条黑线的上下。我预计这些蓝点会有更多的变化,会有很多变化。所以我认为,试图找到一个模型,试图最小化这些蓝点的残差,会试图最小化它太多,会发生的是,它会变得太复杂,它会过度拟合。然后,当新的数据出现时,模型从未见过的数据,这些新数据不会出现在模型适合的地方。

红色圆圈很可能过度拟合残差
例如,这个用红色圈起来的小怪癖,看起来很不错。但我猜测这只是因为一两个数据点有相对高的 y 值。我认为这只是一个怪癖。也许这应该直接过去,就像它在最右边的图像上一样。因为如果我看一下这些蓝点上升和下降的总量,我真的无法证明创建一个试图下降以最小化这一个蓝点的残余然后再上升的模型是正确的。因此,小的λ值可能是过度拟合的,我相信右边的 1/100λ值实际上更好地拟合了数据,并且将更好地概括。
套索
套索回归做了几乎相同的事情;这是限制回归中自变量数量的另一种方法。唯一的区别是,它使用绝对值。现在的问题是,因为数学,它不只是减少系数,拉索实际上删除了系数。许多人喜欢 LASSO 的原因是:系数实际上可以变为零,而在岭回归中,它们不会变为零,它们会变小,但永远不会消失。
现在,你可以用最后一种方法,如果你看到系数变得很小,你可以说,“好吧,我把这一列扔掉,因为它的系数很小。”LASSO 的好处在于它实际上会以一种智能的方式为你做到这一点。

y 是 j 点的预测值,有 I 项具有β系数—λ限制β
系数的向量。你只需要取绝对值,而不是平方它们。
线性代数
接下来是线性代数的快速回顾。为什么我们要快速复习线性代数?嗯,因为机器学习是大量的线性代数,你对机器学习算法理解得越多,通常你就能更好地应用它们。在研究数据科学时,你不是在研究机器学习,你是在研究如何使用机器学习算法。
矩阵的代数性质;
- 加/减矩阵:必须具有相同的维数(m * n)
- 对于矩阵乘法:内部尺寸必须匹配
- 记住矩阵乘法是不可交换的:A x B!= B x A
- 矩阵乘以它的逆矩阵得到单位矩阵
- 矩阵除法未定义
矩阵线性回归
考虑线性回归公式:

写成矩阵:

可以改写为:

对于矩阵的线性回归,如果你有,比方说 10 个案例,这意味着 10 个点,你将有 10 列,那么将有一个精确的,最好的解决方案。对此会有一个简单的解决方案。然而,并不是在每种情况下,都有共线性的情况,这意味着一列与另一列基本相同,或者与其他一些列的组合相同。当这种情况发生时,你通常有无限多的解决方案。我们不喜欢这样,因为有无限多的解,意味着你没有任何有用的解。如果有这样的情况,根本没有解决办法。但是一般情况下,或者你希望的情况是,你有一个好的解决方案。
大多数时候,当我们做机器学习或数据科学时,我们的案例比变量多得多;我们的数据点比列多得多;我们的行数比列数多得多——我只是用稍微不同的词一遍又一遍地重复同样的事情。这将给我们带来一个问题,首先,这意味着我们的 x 矩阵不是一个方阵。
所以当我们想要反转它的时候,我会告诉你们我们想要这样做,这会给我们带来一些问题,伴随着共线性之类的问题。

*简洁地说:y = X β+ε
这些概念在代码中得到最好的展示。
Python 示例:奇异值分解
在前面的中,我提到逐步回归是一种正则化的方法,通过向前或向后的方法,一次找到一个有意义的特征。我现在引入奇异值分解(SVD)作为另一种有意义的寻找特征的方法。
正则化方法稳定了模型矩阵的逆。我们将使用奇异值分解方法来稳定模型矩阵。
名词(noun 的缩写)b:逐步回归是一个计算密集型过程,因为我们必须多次重新计算模型。存在允许计算更新模型的方法,但是对于大量的特征,存在许多排列。我们需要能够处理数百、数千甚至数百万个特征的方法。考虑一个只有 20 个特征的小数据集。没有交互项的可能线性模型的数量由下式给出:

也就是帕斯卡三角形第 21 行的和。结果是:

虽然根据我们的算法,这将是要计算的模型的最大数量,但是当天真地考虑逐步回归时,你可以看到这在计算上变得多么困难。
为了理解特征选择/转换的动机和方法,我会复习一些线性代数。
线性代数评论
*import numpy as npa_list = [2]*3
print(a_list)
print(type(a_list))
a = np.array([2]*3)
print(a)
print(type(a))
b = np.arange(1, 4)
print(b)
print(type(b))*

Jupyter 类似地显示列表和数组
矩阵乘法和加法
*a2d = np.array([[2]*3, [3]*3])
print(‘a: \n{} \n a-size: {}’.format(a2d, a2d.shape))
b2d = np.reshape(np.arange(1,7), newshape=(2, 3))
print(‘\nb: \n{} \n b-size: {}’.format(b2d, b2d.shape))# Addition
print(‘\nAddition: \n {}’.format(a2d + b2d))
# Multiplication
print(‘\nMultiplication: \n {}’.format(a2d * b2d))*

矩阵转置
我们也可以通过翻转行和列来转置一个二维矩阵。我们使用numpy方法np.transpose。
*print(‘Try transposing on a vector…’)
print(np.transpose(a))
# Transposition on a vector does not workprint(‘Now reshape a into 2D and then transpose:’)
print(np.transpose(np.reshape(a, newshape=(1,3))))
print(‘Now transpose a 2d matrix:’)
print(np.transpose(a2d))*

矩阵点积
我们需要知道如何计算两个等长向量的点积,也称为标量积或内积,通过逐元素乘法,然后将它们相加:

*print(‘np.dot(a, b) = np.dot({}, {})’.format(a, b))
np.dot(a, b)*

向量与其自身的内积的平方根是向量的长度或 L2 范数:

我们也可以把内积写成:



注意正交向量的内积是 0
*aa = np.array([1, 0, 0])
bb = np.array([0, 1, 1])
print(inner_prod(aa, bb))*

线性无关的向量是完全正交的
下面是一些关于矩阵的运算。设 A 和 B 是 m=4 行乘以 n=3 列的矩阵:
*A = np.array([[4]*3]*4)
print(A)
B = np.array(np.reshape(np.arange(1, 13), newshape = (4, 3)))
print(B)
C = np.array(np.reshape(np.arange(1, 9), newshape = (4, 2)))
print(C)
np.dot(np.transpose(A), C)*

单位矩阵
这个特殊的正方形矩阵在对角线上有 1,在其他地方有 0:

1 的矩阵等价物
乘以任何矩阵的恒等式给出了那个矩阵。如果 AB 是一个矩形矩阵,那么:

在numpy中,单位矩阵被称为np.eye,并以行数/列数作为自变量:
*I3 = np.eye(3)
I4 = np.eye(4)print(‘I (3X3) = \n{}’.format(I3))
print(np.dot(I3, AtB))print(‘I (4x4) = \n{}’.format(I4))
print(np.dot(I4, ABt))*

矩阵的逆
定义并计算矩阵的逆矩阵,使得:



用numpy中的线性代数方法,用np.linalg.inv求矩阵 M 的逆
*M = np.array([[1., 4.], [-3., 2.]])
M_inverse = np.linalg.inv(M)print(‘M: \n{}’.format(M))
print(‘\nM_inv = \n{}’.format(M_inverse))
print(‘\nM_inv * M = \n{}’.format(np.dot(M_inverse, M)))
print(‘\nM * M_inv = \n{}’.format(np.dot(M, M_inverse)))*

抛开这个简短的回顾,我们现在可以开始用 SVD 正则化模型了。
奇异值分解
在机器学习中,我们经常会遇到不能直接求逆的矩阵。相反,我们需要对 a 进行分解,以便计算 A^−1,这可以通过 SVD 来实现:

- u 是正交单位范数左奇异向量
- V 是正交单位范数右奇异向量,V∫是共轭转置;对于实值 A,这只是 VT
- d 是奇异值的对角矩阵,据说定义了一个谱
- a 由奇异值缩放的奇异向量的线性组合组成
要计算矩阵的 SVD 并查看结果,请执行下面单元格中的代码。我们使用称为np.linalg.svd的numpy方法,使用s获得奇异值:
*U, s, V = np.linalg.svd(B, full_matrices=False)
print(‘B: {}’.format(B)) # ESHx
print(‘U: {}’.format(U))
print(‘s: {}’.format(s))
print(‘V: {}’.format(V))*

岭和套索回归正则化
到目前为止,我们已经研究了两种处理过度参数化模型的方法;基于逐步回归和奇异值分解的特征选择。在本节中,我们将探索基于优化的机器学习模型最广泛使用的正则化方法,岭回归。
让我们从研究线性回归问题的矩阵方程公式开始。目标是在给定数据𝑥x 向量和模型矩阵 A 的情况下,计算最小化均方残差的模型系数或权重的向量。我们可以将我们的模型表示为:

执行下面单元格中的代码,它计算λ值为0.1的𝐴^𝑇 * 𝐴+𝜆 )^-1 * A^T 矩阵
*U, s, V = np.linalg.svd(M, full_matrices=False)# Calculate the inverse singular value matrix from SVD
lambda_val = 1.0
d = np.diag(1\. / (s + lambda_val))print(‘Inverse Singular Value Matrix:’)
print(d)# Compute pseudo-inverse
mInv = np.dot(np.transpose(V), np.dot(d, np.transpose(U)))print(‘M Inverse’)
print(mInv)*

偏差-方差权衡
偏差-方差权衡是机器学习模型的一个基本属性。为了理解这种权衡,让我们将模型的均方误差分解如下:

正则化会减少方差,但会增加偏差。选择正则化参数以最小化 delta_X。在许多情况下,这一过程证明是具有挑战性的,涉及大量耗时的反复试验。
不可约误差是模型精度的极限。即使你有一个完美的模型,没有偏差或方差,不可减少的误差是数据和模型中固有的。你不能做得更好。
statsmodels包允许我们计算一系列岭回归解。实现这一点的函数使用了一种叫做“Elasticnet”的方法,我们知道岭回归是 elastic-net 的一个特例,稍后我会详细介绍这一点。
注意:这是我之前在高尔顿家族数据集上工作的延续。
下面单元格中的代码计算 20 个 lambda 值的解:
*# Ridge regression with various penalties in Statsmodels
# sequence of lambdas
log_lambda_seq = np.linspace(-6, 2, 50)
lambda_seq = np.exp(log_lambda_seq)coeffs_array = []
rsq_array = []
formula = ‘childHeight ~ mother + father + mother_sqr + father_sqr + 1’for lamb in lambda_seq:
ridge_model = sm.ols(formula, data=male_df).fit_regularized(method=’elastic_net’, alpha=lamb, L1_wt=0)
coeffs_array.append(list(ridge_model.params))
predictions = ridge_model.fittedvalues
residuals = [x — y for x, y in zip(np.squeeze(predictions), childHeight)]SSR = np.sum(np.square(residuals))
SST = np.sum(np.square(childHeight — np.mean(childHeight)))rsq = 1 — (SSR / SST)
rsq_array.append(rsq)# pull out partial slopes (drop intercept version)
beta_coeffs = [x[1:] for x in coeffs_array]
plt.plot(log_lambda_seq, beta_coeffs)
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.ylabel(‘Partial Slope Values’)
plt.xlabel(‘Log-Lambda’)
plt.show()*

绘制局部斜率与 R 的关系:
*# % deviance explained
plt.plot(rsq_array, beta_coeffs)
plt.xlim([0.0, 0.25])
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.xlabel(‘R-squared’)
plt.ylabel(‘Partial Slopes’)
plt.show()*

注意,随着 lambda 的增加,4 个模型系数的值向零减小。当所有系数都为零时,模型预测标签的所有值都为零!换句话说,λ的高值给出了高度偏向的解,但是方差非常低。
对于较小的λ值,情况正好相反。该解决方案具有较低的偏差,但相当不稳定,具有最大方差。这个偏差-方差权衡是机器学习中的一个关键概念。
套索回归
我们也可以使用其他规范进行正则化。LASSO 或 L1 正则化限制了模型系数绝对值的总和。L1 范数有时被称为曼哈顿范数,因为距离的测量就像你在一个矩形的街道网格上行进一样。
您也可以将 LASSO 回归视为限制模型系数向量值的 L1 范数。λ的值决定了系数向量的范数对解的约束程度。
执行与之前相同的计算,但是使用不同的正则化范数和相关联的惩罚:
*# LASSO regression with a sequence of lambdas
# sequence of lambdas
log_lambda_seq = np.linspace(-6, 2, 50)
lambda_seq = np.exp(log_lambda_seq)coeffs_array = []
rsq_array = []
formula = ‘childHeight ~ mother + father + mother_sqr + father_sqr + 1’for lamb in lambda_seq:
ridge_model = sm.ols(formula, data=male_df).fit_regularized(method=’elastic_net’, alpha=lamb, L1_wt=1)
coeffs_array.append(list(ridge_model.params))
predictions = ridge_model.fittedvalues
residuals = [x — y for x, y in zip(np.squeeze(predictions), childHeight)]SSR = np.sum(np.square(residuals))
SST = np.sum(np.square(childHeight — np.mean(childHeight)))rsq = 1 — (SSR / SST)
rsq_array.append(rsq)# drop intercept version
beta_coeffs = [x[1:] for x in coeffs_array]
plt.plot(log_lambda_seq, beta_coeffs)
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.ylabel(‘Partial Slope Values’)
plt.xlabel(‘Log-Lambda’)
plt.show()*

*# plot partial slopes vs R squared (% deviance explained)
plt.plot(rsq_array, beta_coeffs)
plt.xlim([0.0, 0.25])
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.xlabel(‘R-squared’)
plt.ylabel(‘Partial Slopes’)
plt.show()*

注意,模型系数比 L2 正则化受到更严格的约束。事实上,可能的模型系数中只有两个具有非零值!这是典型的 L1 或拉索回归。
弹性净回归
弹性网算法使用 L1 和 L2 正则化的加权组合。正如您可能看到的,LASSO 和 Ridge regression 使用了相同的函数,只有L1_wt参数发生了变化。这个论点决定了偏斜率的 L1 范数的权重。如果正则化是纯 L2(山脊),如果正则化是纯 L1(拉索)。
下面单元格中的代码对每种回归方法给予同等的权重。执行这段代码并检查结果:
*# ElasticNet Regression with a sequence of lambdas
# sequence of lambdas
log_lambda_seq = np.linspace(-6, 0, 50)
lambda_seq = np.exp(log_lambda_seq)coeffs_array = []
rsq_array = []
formula = ‘childHeight ~ mother + father + mother_sqr + father_sqr + 1’for lamb in lambda_seq:
ridge_model = sm.ols(formula, data=male_df).fit_regularized(method=’elastic_net’, alpha=lamb, L1_wt=0.75)
coeffs_array.append(list(ridge_model.params))
predictions = ridge_model.fittedvalues
residuals = [x — y for x, y in zip(np.squeeze(predictions), childHeight)]SSR = np.sum(np.square(residuals))
SST = np.sum(np.square(childHeight — np.mean(childHeight)))rsq = 1 — (SSR / SST)
rsq_array.append(rsq)# pull out partial slopes (drop intercept version)
beta_coeffs = [x[1:] for x in coeffs_array]
plt.plot(log_lambda_seq, beta_coeffs)
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.ylabel(‘Partial Slope Values’)
plt.xlabel(‘Log-Lambda’)
plt.show()*

*# plot partial slopes vs R squared (% deviance explained)
plt.plot(rsq_array, beta_coeffs)
plt.xlim([0.0, 0.25])
plt.title(‘Partial Slopes vs Log-Lambda’)
plt.xlabel(‘R-squared’)
plt.ylabel(‘Partial Slopes’)
plt.show()*

请注意,弹性网络模型结合了 L2 和 L1 正则化的一些行为。
结论
在这篇文章和上周的文章中,我研究了 3 种方法来解决过度拟合模型的问题:
- 逐步回归,一次消除一个要素
- 奇异值分解寻找有意义的特征
- 套索、脊和弹性网正则化以稳定过度参数化模型
重要术语包括:
- AIC-根据模型参数数量调整的模型对数似然
- 偏差——模型相对可能性的度量(方差的推广)
- 奇异值分解将矩阵描述为一系列向量 U,V,D 的线性组合
- 奇异值 s-用作比例项的奇异值对角矩阵
- λ—添加到奇异值上的小偏差项,用于稳定逆奇异值矩阵
- PCA 主成分分析,通过使用函数和奇异值分解来确定可以从彼此独立的线性组合中获得哪些新特征
- PCR 主成分回归使用 PCA 来执行“正则化”回归
- L1 正则化-使用“曼哈顿”规范的套索正则化
- L2 范数正则化-限制模型系数向量值的“欧几里德”范数的岭正则化
- 弹性网算法——L1 和 L2 正则化的加权组合
我简要回顾了线性代数运算:
- 添加向量和矩阵
- 向量和矩阵相乘
- 用
np.transpose转置矩阵 - 用
np.dot点积或标量积或内积 - 向量的 L2 范数
- 带
np.eye的单位矩阵 - 用
np.linalg.inv求矩阵的逆 - 用
np.linalg.svd进行奇异值分解 - 用
np.diag创建对角矩阵
到目前为止,我一直严格地使用线性回归模型。接下来,我将看看线性模型上广泛使用的变体,称为 逻辑回归 !
在 Linkedin 上找到我
物理学家兼数据科学家——可用于新机遇| SaaS |体育|初创企业|扩大规模
适合工作的型号
原文:https://towardsdatascience.com/right-model-for-the-job-243b0009d84e?source=collection_archive---------5-----------------------
环境如何决定数据科学中的模型选择
为商业用例选择正确的机器学习模型可能很棘手。作为免费可用库的一部分,有如此多的模型可以方便地访问,并且每天都有更多的模型被添加进来,所以花一些时间考虑一下应该将精力集中在哪个模型子集上是非常重要的。许多因素决定了这一选择,如手头的问题陈述、可用数据量、生产限制。
在决定正确的模型时,要考虑的最基本的问题是问题的性质,是分类任务还是回归任务。这一点从问题陈述中应该是清楚的。
比方说,我们正在研究一个回归问题。可用于训练的数据量是选择模型的另一个重要考虑因素。然而,要考虑的更好的一点是模型的目的,也就是说,模型是用于预测还是用于绘制推理。
预言;预测;预告
预测产量所需的模型必须将准确性置于其他考虑因素之上。当然,这种情况下的准确性是指对看不见的数据(“测试误差”)的预测准确性,而不是对经过训练的数据模型的预测准确性(“训练误差”)。
例如,如果我们要预测股票价格,我们会希望关注预测的准确性。
在这种情况下,最佳模型将是具有最佳预测误差的模型。通常,这种模型将更加复杂和非线性,以捕捉目标变量的变化。然而,随着模型复杂性的增加,解释所有的变化以及每个因素如何影响输出以及影响到什么程度变得越来越困难。
例如,在二维空间中可视化数据点是非常容易的,而随着维数的增加,在 n 维空间中可视化数据点变得越来越困难。
推论
除了预测之外,该模型还可用于近似目标变量和一组特征之间的关系。例如,了解影响预期寿命的因素,如教育和生活水平,可能是有用的。对于政策制定者来说,理解额外两年的教育能在多大程度上提高预期寿命是很重要的。
当推理是分析的主要目的时,最好有一个比更复杂的模型更容易解释的模型,有更好的预测准确性。对于这些情景,更重要的是理解因素之间的相互作用以及每个因素在目标变量的最终值中的权重。简单、易于解释的模型(如线性回归)更可取,因为直接查看线性回归模型的系数可以让我们了解特征的重要性以及预测随特征值的变化而发生的变化。
鱼与熊掌不可兼得
可能会出现预测和推理都很重要的情况。例如,预测房价的模型不仅可以提供对房产价值的估计,还可以提供对影响房产价格的因素以及影响程度的想法。
通常在业务中,具有最佳预测准确性的复杂模型需要与一些可解释性框架相结合,以方便业务采用。
根据问题,如果我们有一个具有良好预测准确性的可解释模型,那么我们可以直接使用该模型。此外,还有一些模型可解释性技术,如莱姆和 SHAP,它们可以增强模型的可解释性。
复杂性问题
模型架构的选择不仅取决于用例,还取决于其他因素,比如可用的数据量。更复杂的模型需要更大量的数据来提供类似的预测精度。
在模型准确性和模型可解释性之间有一个折衷。随着模型变得更加复杂,它可以更好地遵循数据中的模式,但它也变得更难解释。但是,如果一个复杂的模型是基于有限的数据训练的,那么这个模型可能会过拟合。它将更加 【灵活】 即它将过于紧密地适应目标特征的变化,但它也将噪声结合到图案中。

常见的机器学习模型——可解释性-准确性谱(图片来自这篇论文)
结论
选择正确的机器学习模型不仅取决于业务用例,还取决于可用的数据量。如今,行业中可能存在对预测准确性的过度依赖,但预测和推断在分析工作流中都有价值。两者都提供了更好地理解数据的不同视角,并且是互补的方法。
将来,当开始一个新的分析并决定模型架构时,最终用例以及可用的数据量是重要的因素。
相关阅读
- 博客推理与预测的比较
- 可解释的 ML 书
风险、相对风险和几率
原文:https://towardsdatascience.com/risk-relative-risk-and-odds-2837915fede8?source=collection_archive---------33-----------------------
统计数字
了解相对风险和优势比
根据维基百科中对风险的定义;风险是坏事发生的可能性。因此,在使用风险这一术语时,应考虑阴性病例的数量。换句话说,风险取决于负面案例比正面案例多多少。那么,相对风险和优势比是多少呢?在这篇文章中,你将得到以下问题的答案;
- 什么是风险和相对风险?
- 如何找到相对风险?
- 风险、相对风险、比值比有什么区别?
- 如何决定我们应该使用哪种风险度量?

洛伊克·莱雷在 Unsplash 上拍摄的照片
风险和相对风险
最好通过一个例子来简单地理解风险和相对风险。假设有一个电子商务网站,人们可以购买手表。让我们假设,这个电子商务网站已经决定将产品传送带移到页面顶部。他们正在考虑将这个转盘放在页面的右边,而不是放在顶部。在这种情况下,风险在于客户(用户)发现这种重新定位不可用,或者他们无法习惯。考虑到每天平均有 1 万用户的网站流量,做出这样的用户界面更改会对购买数量产生负面影响。如果用户习惯了旧的布局,让他们习惯新的是一个巨大的挑战。因此,电子商务网站决定在做出这一改变之前只检查两个不同的组(样本)。第一组将看到电子商务网站的新布局,在右边栏中有一个产品转盘。第二组将看到它是旧布局,顶部有一个产品转盘。因此,第一组将是实验组,第二组将是对照组。
他们决定每个组 1000 个用户,他们不想要很少登录网站的用户。这些用户的数据可能会误导搜索结果。因此,他们选择了平均每周至少登录两次网站的用户。这些用户在产品传送带上的行为将被跟踪。如果用户在某周首次登录时点击产品传送带上的任何项目,该用户将被确认为“已点击”。如果用户在第一次登录时没有进行任何点击,该用户将被确认为“未点击”。那么,现在让我们来检查产品转盘点击。

实验组和对照组的点击量—图片由作者提供
实验组中的 434 名用户在第一次登录时点击了产品传送带中的项目。566 名在侧边栏中看到产品轮播的用户从未点击或在首次登录时点击。现在,让我们检查一下控制组的用户,他们像以前一样看到了布局(没有产品传送带位置的变化)。1000 个用户中有 708 个在第一次登录时点击了产品转盘中的项目。剩下的 292 名用户从未点击或没有点击他们的初始登录。基于这些结果,可以说新的布局对于点击来说效率不高。不过还是要深挖一点,计算风险和相对风险。
计算
如前所述,风险是坏事发生的可能性。这种情况下不好的地方是“没有被点击”,因为我们希望用户点击产品。所以,要找到实验组中“未被点击”的风险,我们应该得到属于实验组的“未被点击”的数量,并除以实验组中的用户总数。这是实验组的风险。同样,也可以获得对照组的风险值。

风险计算-作者图片
对照组“未点击”的风险为 0.292。实验组是 0.566。根据这些结果,实验组的风险高于对照组。可以得出结论,将产品轮播放置在右侧边栏具有较高的风险。相对风险 (RR)可以用来定义这个风险有多高。实验组的风险除以对照组的风险,得到了在改变产品传送带的布局后被“不点击”的相对风险。

相对风险的计算——作者图片
相对风险为 1.938。这意味着改变产品传送带的位置的风险是不改变的 1.938 倍。
让步比
还有一种测量方法叫做优势比。这个比率经常与相对风险混淆。但是,它们在逻辑上是不同的。相对风险取决于两组的风险,优势比取决于对照病例(表中单元格)。可以说,赔率有两种情况,预期和意外。在本例中,电子商务网站决定更改布局,因此预计这将对用户点击产生积极影响。令人意想不到的是,这些变化将对用户的点击量产生负面影响。

比值比-作者图片
这个比值比表明,位于右侧边栏的产品轮播被点击的可能性是位于顶部的产品轮播被点击的可能性的 0.316 倍。0.316 小于 1。多 0.316 倍的意义在于,对照组的点击次数会多得多。所以,当取 0.316 的-1 次方时((0.316)^-1 = 2.97),2.97 将是不点击情况下的“赔率”。意义;点击位于顶部的产品传送带的可能性(控制)是点击位于侧边栏的产品传送带的可能性(实验)的 2.97 倍。
请阅读我之前的文章,了解更多关于比值比的信息;
结论
解释可能性的术语总是一个挑战。因此,在解释风险、相对风险和优势比时,定义问题或研究的逻辑是至关重要的。不应该忘记风险有负面意义。在获得相对风险和比值比之前,将病例分为预期和非预期两类会更好理解。这些类别也可以被命名为积极或消极。
River:在线机器学习的最佳 Python 库
原文:https://towardsdatascience.com/river-the-best-python-library-for-online-machine-learning-56bf6f71a403?source=collection_archive---------11-----------------------
意见
流数据机器学习的“sklearn”

图片由 UnboxScience 在 Pixabay 拍摄
传统的机器学习算法,如线性回归和 xgboost,以“批处理”模式运行。也就是说,它们一次性使用完整的数据集来拟合模型。用新数据更新该模型需要使用新数据和旧数据从头开始拟合一个全新的模型。
在许多应用中,这可能是困难的或不可能的!它要求所有的数据都适合内存,这并不总是可能的。模型本身的重新训练可能会很慢。为模型检索旧数据可能是一个很大的挑战,尤其是在数据不断生成的应用程序中。存储历史数据要求数据存储基础设施能够快速返回完整的数据历史。
或者,模型可以“在线”或以“流”模式训练。在这种情况下,数据被视为一个流或一系列项目,一个接一个地传递给模型。
增量学习、持续学习 和 连续学习 是“在线学习”的首选术语,因为对“在线学习”的搜索主要指向教育网站。
增量学习是许多用例的理想选择,例如在大型数据集上拟合模型、垃圾邮件过滤、推荐系统和物联网应用。
介绍河流
[River](https://riverml.xyz/latest/getting-started/getting-started/)是一个新的 python 库,用于在流设置中增量训练机器学习模型。它为不同的在线学习任务提供了最先进的学习算法、数据转换方法和性能指标。它是合并了creme和scikit-multiflow库的最好部分的产物,这两个库都是为了相同的目标而构建的:
“为社区提供工具来提升流式机器学习的状态,并促进其在现实世界应用中的使用。”
River 是一个由从业者和研究人员组成的大型社区维护的开源包。源代码可在 Github 上获得。
River 中的算法类型
river为回归、分类和聚类任务提供了一系列增量学习算法。可用的模型类型包括朴素贝叶斯、树集成模型、因式分解机、线性模型等等。有关已实现算法的完整列表,请参见 API 参考。
River 还提供漂移检测算法。概念漂移发生在输入数据和目标变量之间的关系改变时。
River 提供了处理不平衡数据集和异常检测的方法。
最后,river提供了模型度量和数据预处理方法,它们已经被重构以处理增量更新。
增量学习算法有什么不同?
为了增量地转换数据和训练模型,必须重构大多数学习算法和数据转换方法来处理更新。
首先,考虑如何缩放特征以获得零均值和单位方差。在批量设置中,这很简单:计算平均值和标准差,从每个值中减去平均值,结果除以标准差。这种方法需要完整的数据集,并且不能随着新数据的到来而更新。在流设置中,使用运行统计完成特征缩放,这是一种数据结构,允许平均值和标准偏差增量更新。
对于增量式训练模型,常见的学习算法是 随机梯度下降 (SGD)。 SGD 是一种用于训练神经网络的流行算法,有多种变体。它还可以用于训练其他模型,如线性回归。SGD 的核心思想是在每个训练步骤中,模型参数权重在梯度的相反方向上进行调整,该梯度是使用该步骤中的模型预测误差来计算的。
API 河
所有模型都能够从数据中学习并做出预测。river的模型具有从单一实例中学习的灵活性。每当新数据到达时,模型可以快速更新。
learn_one(x, y)更新模型的内部状态,给出一个包含输入特征x和目标值y的新观察值。predict_one(分类、回归、聚类)返回单个观察值的模型预测值predict_proba_one(分类)返回单次观察的模型预测概率score_one(异常检测)返回单个观察值的异常值transform_one转换一个输入观察值
要演示 API 的用法,请参见下面的示例。在该示例中,实例化了线性LogisticRegression模型和ROCAUC模型评分对象。然后,对于数据集中的每个观察值,模型使用predict_proba_one进行预测,并通过将观察值x和标签y传递给learn_one方法来更新其权重。最后,用真实值y和预测值y_pred更新模型评分对象metric.update。
字典数据结构
River 希望数据观察能够以 python 字典的形式呈现。代表功能名称的字典关键字。
字典数据结构有几个优点:
- 词典是灵活的,不是打字的。因此,它们可以处理稀疏数据和可能出现在数据流中的新功能。
- 字典数据是轻量级的,不需要复杂数据结构(如
numpy.ndarray或pandas.DataFrame)所需的开销。这使得在流式环境中快速处理单个观察更容易。
River 扩展了原生 python 字典结构,以支持更高效的数据操作。
river中的stream模块提供了几个用于处理流数据的实用程序,包括将数据加载到预期的字典格式中。
例如,stream.iter_csv方法允许您将 CSV 文件加载到流数据结构中。在下面的例子中,“loaded”data_stream实际上是一个 python 生成器,它遍历 CSV 文件并解析每个值。整个数据集不是一次从磁盘中读取,而是一次读取一个样本。
典例出自 河文献 。
以上stream.iter_csv示例中使用的一些附加参数:
converters参数指定非字符串列的数据类型。如果在加载时没有指定数据类型,stream.iter_csv假设所有数据都是字符串。parse_dates表示解析日期的预期格式。target指定哪个变量是目标,或y列。如果排除,y返回为None。
在像 web 应用程序这样的应用程序中,字典数据结构非常直观。您可以简单地将一个 JSON 结构的有效负载传递给一个模型,以进行预测或更新模型。
代码示例来自 河流文档 。
河流管道
管道是river的核心组成部分。与scikit-learn类似,管道将模型的各个步骤,包括数据转换和预处理,链接到一个序列中。
河流用户指南中的代码示例(管道—河流(riverml.xyz) )
如使用管道的艺术教程所示,当特征预处理步骤变得复杂时,管道简化了模型拟合代码。它使代码可读性更强,更不容易出错。
需要注意的重要行为:当在管道上调用 **predict_one** 或 **predict_proba_one** 方法时,模型的非监督部分被更新!无监督部分包括特征缩放和其他变换。这和批量机器学习有很大不同。像要素缩放这样的变换不依赖于地面实况标签,因此可以在没有地面实况标签的情况下进行更新。当然,除了转换方法之外,管道的learn_one方法还会更新受监控的组件。
简单的例子
以下示例演示了如何在乳腺癌数据集上拟合逻辑回归模型。
首先,实例化标准数据缩放器和逻辑回归模型。给逻辑回归模型一个学习率为 0.01 的随机梯度下降优化器进行训练。然后,初始化真实值和预测值的列表。
然后,代码遍历数据集;每个xi都是一个字典对象。在 for 循环的每一步中,代码需要 4 个步骤:
- 用新的观测值更新定标器,并对观测值进行定标。
- 该模型使用缩放后的观察值进行预测。
- 模型将使用新的观察和标签进行更新。
- 真实标签和预测标签存储在一个列表中。
当 for 循环结束时,计算总 ROC AUC。
改编自河(riverml.xyz) 文档的代码示例
这段代码可以改进和简化。在下面的示例中,为相同的任务训练了逻辑回归模型,但是使用管道和运行度量来减少步骤数量并增强可读性。
结论
river是增量学习和持续学习的首选库。它提供了一系列数据转换方法、学习算法和优化算法。其独特的数据结构非常适合流数据和 web 应用程序的设置。
参考资料和进一步阅读
如何使用 River 的例子:【https://riverml.xyz/latest/examples/batch-to-online/】T4
用户指南:https://riverml.xyz/latest/user-guide/reading-data/
河纸:https://arxiv.org/abs/2012.04740
RMSE:扭曲对结果的评估
原文:https://towardsdatascience.com/rmse-the-poor-and-distorting-evaluation-of-the-results-for-multi-class-classification-and-efebbf0492a2?source=collection_archive---------15-----------------------
RMSE 评估较弱,不应用于多分类以及具有分散结果的回归。

RMSE 评价(图片由作者提供)
为了教授分类和回归的基本概念,“RMSE 评价”通常被用作一种常用的评价方法。从一开始,人们就对这种评价方法持肯定态度。但是如果将这种评估方法用于全面的多类分类挑战或回归挑战,则可以容易地识别出最终结果的弱点。
在这些挑战中,每个人都在争取更好的分数,参与者尝试不同的分类和回归方法是很自然的。但是,如果这些挑战是在 RMSE 的基础上评估的,所有分类和回归方法的结果都将被“RMSE 笼子”捕获。换句话说,结果将很少分散,并且所有结果都是错误获得的,仅在正确值的平均值附近。
请注意,例如,如果多类别分类挑战的评估仅基于 based 在基于 RMSE 计算参与者的最终分数之前,首先参与者自己基于 RMSE 设置他们所有的方法和算法(XGBoost,CATBoost,…),以便在评估期间获得最佳分数。这正是所有方法试图最小化 RMSE 方程的原因。但是最小化这个等式并不总是能让我们更接近正确的答案。也就是说,结果将具有很小的分散性,并且将仅围绕一个数 (mean(y_train)) 。换句话说,一些类通常在我们的结果中没有代表性,仅仅是因为它们不接近那个数字。
对此的数学证明不是我们文章的主题。在这篇文章中;我们回顾了 Kaggle 挑战赛的最佳结果(其中甚至包括该挑战赛的一些获胜者),并表明由于使用了 RMSE 评估,提交给该挑战赛的所有结果的分散性非常低。因此,我们在任何预测中都看不到一些正确的值。我们也建议一些方法,这样你可以通过增加你的结果的分散性来提高你在这种类型的挑战中的分数。这篇文章写于 2021 年 12 月作者: 索马耶赫·戈拉米 和 麦赫兰卡泽米尼亚 。
表格游乐场系列—2021 年 8 月

表格游乐场系列—2021 年 8 月(图片由作者提供)
2021 年,每月将在 Kaggle 举办“表格游乐场系列”挑战赛。这些挑战对于练习来说非常棒,每个人都可以从别人的笔记本和现场评论中学习。在其中一些挑战中(如八月),RMSE 被用于评估。接下来,我们将回顾八月挑战,以及本月提交的结果。
在这个挑战中,为每个样本提供 100 个特征。“火车”组包含 250,000 个样本,而“test”组包含 150,000 个样本。“训练”组中的答案(损失栏)是数字 0 到 42。这意味着“test”集合中的 150,000 个样本中的每一个也必须被分配一个 0 到 42 之间的数字。最终,这项挑战的获胜者将是其结果能够最小化 RMSE 方程的人。
在这些挑战中,“训练”集和“测试”集总是随机的(所谓的混洗),除了在时间序列挑战或类似挑战的情况下。这意味着“测试”集合中“损失”栏中的数字必须介于 0 和 42 之间,并且这些数字的直方图必须与“训练”集合中“损失”栏中的直方图相似。例如,如果在“train”集合中大约 25%的“loss”列为零,那么在“test”集合中大约 25%的“loss”列也应该为零。
不能在“中等平台”运行代码,但我们已经在 Kaggle 上发布了以下四个挑战的笔记本。您可以在这些笔记本中找到本文剩余部分中呈现的所有结果的代码,并自己运行它:
【1】TPS 8 月 21 日—XGBoost&CatBoost
2】TPS 8—智能组装
【3】TPS 8 月 21 日—结果& RMSE 评测
https://www.kaggle.com/somayyehgholami/4-tps-aug-21-guide-point-snap-to-curve
By:Somayyeh&Mehran Kazeminia**
挑战数据的概况
“train”集合的“loss”列的值包括 0 到 42 之间的 250,000 个数字。另外,根据下面的图表,其中 0.240576 是 0 号,0.088276 是 1 号,0.088900 是 2 号,…其中 0.000012 是 42 号。如前所述;在这个挑战中,必须为“测试”集的“丢失”列预测 150,000 个数字。预测的数字应该是大约 0.24 其中 0,0.08 其中 1,以此类推。

data_train'loss'
令人惊讶的是,没有一个预测值接近正确值。你会看到所有方法预测的数字都在 3 到 12 之间。例如,没有一个预测接近于零。但我们知道,总预测数的 24%左右一定是零(或接近零)。
换句话说,“train”集合中“loss”列的直方图如下图。所以正确的预测直方图应该是这样的。

(图片由作者提供)
但是如果你看看这次挑战的不同预测,所有预测的直方图如下图所示。这意味着所有的分类和回归方法只能使 RMSE方程最小化,不幸的是不能接近正确的预测。

(图片由作者提供)
我们在我们的第第一和第第二笔记本中使用 XGBoost 和 CatBoost,然后将我们的结果与其他几个公共笔记本的结果“组合”起来以提高我们的分数。但是所有笔记本结果的直方图与上图相似,这意味着所有的结果都在“RMSE 笼子”里。在第三和第四笔记本中,我们看了同样的问题,并提供了一些提高分数的近似方法。
我们在这次挑战中挑选了七款优秀的笔记本,每一款的成绩都非常不错。这些笔记本使用了以下方法:
1- 投票(CB/XGB/LGBM) > > >得分:7.86780 2-表格去噪+残差网络> > >得分:7.86595 3-LightAutoML>>>得分:7.86259 4-【4】
下图包含了这七个笔记本的结果直方图。正如你所看到的,它们都装在一个盒子里,我们称之为“RMSE 笼”。

(图片由作者提供)
所有直方图的纵轴近似为“np.mean(y)=6.81392”。如你所见,所有的预测都围绕这个数字。如果我们在一张图中画出这七个笔记本的 y 直方图和预测直方图,那么正确值和预测值之间的差异就变得相当清楚了。

(图片由作者提供)
那怎么办呢?
RMSE 评估较弱,不应用于多分类以及具有分散结果的回归。因为所有方法的结果都会在“RMSE 笼子”里面。当然,如前所述,这在数学上是可以证明的。然而,如果你运行一个使用“RMSE 评估”的挑战;有几件事要记住:
- “组合”方法也许能提高你的笔记本分数,但你的成绩的分散性不会增加,实际上对这个问题没有帮助(RMSE·凯奇)。
- 笔记本预测的数字顺序和排名并不准确。这意味着,只要有一丝可能,RMSE 方程就可能脱离最优状态。而在实践中,我们不能简单地增加数字的离散度。
- 在我们的第三本笔记中,我们介绍了一种近似方法,叫做“常值坐标”。这种方法是基于将一个固定值加到一些结果上,并从一些其他结果中减去另一个固定值。要成功做到这一点,你必须“试错”很多次。

(图片由作者提供)
- 在我们的第四本笔记本中,我们介绍了另一种叫做“曲线拟合”的方法。我们的想法是基于“引导点”来“捕捉到曲线”。最佳“引导点”是基于评估方程“RMSE”来确定的。值“np.mean(yy)”在这里是合适的,但是我们不知道这个数字是多少。所以我们首先考虑“np.mean(y)”,然后用数字“R”修改它的值。

(图片由作者提供)
好运。
索马耶赫&梅兰
RNA 速度:细胞的内部指南针
原文:https://towardsdatascience.com/rna-velocity-the-cells-internal-compass-cf8d75bb2f89?source=collection_archive---------12-----------------------
思想和理论
在单细胞 RNA 测序数据中寻找方向

绝对视觉在 Unsplash 上拍摄的照片
单细胞 RNA 测序(scRNA-seq)在过去十年中彻底改变了我们研究细胞生物学的方式,开创了单细胞基因组学的快速发展领域。scRNA-seq 允许我们描绘单个细胞的转录组,获得对它们的功能和身份的全面了解。转录组是细胞中所有信使核糖核酸(mRNA)分子的集合。在过去的一年里,你可能经常听说 mRNA,许多新冠肺炎疫苗都依赖于这种分子。mRNA 代表一个基因的读数或转录本。这些分子携带有关感兴趣的基因的信息,细胞的机器用这些信息来构建蛋白质。在基于 mRNA 的新冠肺炎疫苗中,它们携带着如何制造针对 SARS-CoV2 病毒的良性蛋白质的信息,有效地教会我们的身体如何抵抗感染。这些 mRNA 分子的产生被称为转录,这些分子有时也被相应地称为转录物。你会经常听到生物学家将 mRNA 丰度更宽泛地称为基因表达。你可以把它想象成建造宜家家具:指令就是转录的 mRNA 分子,对应的蛋白质就是家具。然而,在 mRNA 被翻译之前,它必须经历一个额外的步骤。mRNA 分子中有不编码蛋白质的片段,称为内含子。这些在蛋白质翻译之前通过称为剪接的过程被去除。剩下的片段被称为外显子。很快知道这一点很重要。

作者图片
您可以将转录组视为细胞的指纹,用于识别它并将其与其他细胞区分开来(例如,红细胞与神经元)。通过对成千上万个细胞的转录组进行测序,我们可以构建一个整体的、高维的细胞状态图,这些细胞状态是干细胞在转变为更专业化的细胞(如神经元)时所经历的,可以表征癌症肿瘤,并区分患者的健康组织和患病组织。这些测序协议因此产生了数千兆字节的数据进行分析和理解,这可能会因为我们的数据集中有如此多的维度而变得复杂,每个维度对应一个基因(见我的第一篇文章关于解决这个难题的一种方法)。看起来很酷,对吧?然而,这种方法有一个主要缺点。这些测序实验在过程中杀死细胞,阻止我们在以后的时间点再次对这些细胞重新测序。因此,我们只剩下一个细胞 mRNA 丰度的静态快照,这使得推断其未来的基因表达具有挑战性。我们如何解决这个问题?
这就是 RNA 速度发挥作用的地方。RNA 速度是一种简单而强大的方法,它使我们能够预测细胞未来的基因表达。回想一下,我提到过 mRNA 可以通过剪接和未剪接的转录物来区分。虽然剪接的转录物是大多数 scRNA-seq 方案的主要读数,但也测量未剪接的表达。利用这些补充信息,我们可以建立一个简单的数学模型来预测未来的剪接表达。


作者图片
其中 u 为未剪接的 mRNA 分子数, s 为剪接的 mRNA 分子数, α 为转录速率, β 为从未剪接到剪接的剪接速率, γ 为剪接的 mRNA 产物的降解速率。
取给定细胞的特定基因的未来 mRNA 表达和当前 mRNA 表达之间的差异,我们可以得到基因表达变化的度量。对于给定细胞的所有基因,这些基因可以聚合起来,以创建细胞未来转录组的载体,代表所述细胞变化的速度和方向——因此出现了术语 RNA 速度。一种常见的可视化方法是在嵌入中将一个向量场叠加到单元格上,如下所示:

La Manno 等,Nature560:494–498(2018)PCA 包埋中经历神经发生的细胞的 RNA 速度
这是经历神经发生的细胞的 PCA 图——大脑中神经元(红色)的产生来自称为放射状胶质细胞(蓝色)的干细胞样细胞。每个点代表一个叠加了 RNA 速度向量的细胞,预测细胞转变。注意这些箭头如何在中间阶段(成神经细胞和未成熟神经元)变长——这表明基因表达的动态变化,因为神经元的基因打开,而放射状胶质细胞的基因关闭。随着这些细胞成功转化为神经元,载体迅速缩短,反映了这些细胞基因表达的“减速”。你可以把这些向量想象成类似于细胞的指南针:一个内部 GPS,如果细胞想要成为神经元,它可以精确地指出细胞需要去的方向。
RNA 速度主要有两种模型:稳态模型和动态模型。稳态模型是发表在 Nature 上的原始模型,上图使用了它的实现。这个模型假设了一个通用的、转录组范围的剪接率,并且基因表达遵循一个稳态:即,当 ds/dt=0 由 u = γs 给出时,速度被估计为与剪接和未剪接分子的 γ 拟合比率的偏差。下面我举个例子:

作者图片
该图根据从 SOX2 基因转录的剪接与未剪接的分子计数,绘制了来自先前显示的神经发生 PCA 的单个细胞,so x2 基因是放射状神经胶质细胞的标记(蓝色)。实线是从广义线性回归模型中得到的对 u = γs 的拟合(参见我的上一篇文章对这个统计模型的介绍)。这条线以上的细胞( u > γs )被认为具有正速度。这意味着未剪接的 SOX2 mRNA 分子的产量超过了它的剪接对应物的降解:我们有 SOX2 mRNA 的净产量。相比之下,线( u < γs )以下的细胞具有负速度:被降解的 SOX2 比产生的多,导致净损失。直接在线上的细胞具有零速度,因为它们没有偏离这个 γ 拟合的未剪接与剪接 mRNA 分子的比率。
相比之下,动态模型直接求解每个基因的完整转录动力学,而不是做出转录组范围的假设。它不是试图将数据拟合到回归模型中,而是使用期望最大化算法 (E-M)来估计参数,该算法使用最大似然来迭代逼近 α 、 β 和 γ ,并学习给定基因的拼接/未拼接轨迹。这为每个基因分配了如下可能性:

在哪里

其分别代表细胞 i 中特定基因观察到的未剪切和剪切的 mRNA 分子,而 xₜᵢ 代表基于推断的参数集 θ = ( α , β , γ )在时间 tᵢ 的未剪切/剪切的分子。具有高可能性的基因被认为是感兴趣的生物现象中动态变化的主要贡献者——在我们的情况下,是神经发生。但是足够的数学,让我们看看这在行动中!
要亲自尝试 RNA velocity,请使用以下任一 pip 安装 scvelo 包:
pip install -U scvelo
如果您喜欢 conda,您可以通过 bioconda 渠道进行安装,如下所示:
conda install -c bioconda scvelo
您还需要 scanpy,可以从 conda-forge 安装。这是 Python 中一个流行的单细胞分析库。
conda install -c conda-forge scanpy
我们将使用上面描述的人类神经发生数据集作为例子,在这里我将说明和比较稳态和动态模型。该数据集有 1720 个细胞,代表神经发生中的四种主要细胞类型:放射状胶质细胞、成神经细胞、未成熟神经元和神经元。
首先,我们将从互联网上加载数据集:
接下来,让我们导入我们的包
我们将把数据集读入一个带注释的数据 (anndata)对象。这是存储用于 Python 分析的单细胞数据的一种流行方式:

Anndata 概述,来自 Wolf 等人,SCANPY:大规模单细胞基因表达数据分析。 Genome Biol 19、 15 (2018)和https://anndata.readthedocs.io/en/latest/
现在我们来计算 RNA 的速度。scvelo 为此使用了两个函数:scv.tl.velocity()计算每个基因的速度,scv.tl.velocity_graph()基于速度和潜在细胞状态转换之间的余弦相似性输出速度图。换句话说,它测量细胞基因表达的变化与其预测速度向量的匹配程度,预测速度向量可用于推导转移概率。我们还会将数据中的数字聚类标签更改为论文中定义的单元格类型。
这为我们提供了以下 PCA 图,类似于论文中的图:

作者图片
正如你所看到的,每个细胞都有一个箭头叠加在上面,预测其未来的转录组。这些箭头给了我们一种全局方向性的感觉,显示了从放射状胶质细胞到神经元的线性进展。然而,你可能已经注意到,一些绿色的神经母细胞似乎正在回复成放射状胶质细胞。在一些神经元中也有类似的现象,尽管程度较轻。这些回流可归因于两个主要原因:1)如前所述,原始 RNA 速度模型的稳态假设不能准确反映更多的瞬时细胞群体,如神经母细胞;2) scRNA-seq 非常稀疏。基因容易逃避测序平台的检测,导致“退出”,这些 mRNA 测量值被错误地记录为零。一种避免这种情况的方法是使用插补,我们通过计算推断缺失值。一种类似的方法是通过数据平滑来消除固有稀疏性产生的噪声,原始论文的作者通过 k-最近邻池做到了这一点。这些方法中的每一种都有缺点,以及关于是否应该将它们用于 scRNA-seq 分析的争论,因为结果可能是误导的。出于本文的目的,我将继续以原始形式呈现数据集。
我们可以通过生成相位图来进一步探索细胞的基因特异性速度:

最左边是 SOX2 表达的拼接 v .未拼接图,so x2 表达是放射状胶质细胞的标志。每个点是根据其细胞类型着色的细胞(蓝色代表放射状胶质细胞,绿色代表成神经细胞,暗金色代表未成熟神经元,红色代表神经元)。如前所述,确定性模型通过假设稳态模型来求解未来表达式。线条代表 ds/dt 稳态解的回归拟合,用 u = γs 表示。这条线以上的细胞被认为具有正速度:SOX2 正被上调,这些细胞中产生的净产物多于其被降解的产物。我们看到一些放射状胶质细胞似乎显示了这种现象,如右侧的表达图所示,其中上面 PCA 图中的细胞根据它们的 SOX2 表达水平进行着色。然而,大多数细胞在开始分化时关闭 SOX2 活性(由中间图中的负速度指示),正如 SOX2 在其他细胞类型中的零速度所证明的那样:它们不再转录也不再降解其 mRNA 分子,这解释了这些细胞类型中的最低表达水平。
如上所述,稳态模型虽然强大,但也有局限性,因为它假设了稳态表达水平和恒定的剪接速率。在更复杂的系统中,具有多种最终状态(即,一个干细胞可以最终分化成不同的细胞)和异质亚群,这种假设可能失败并产生错误的解释。这就是前面提到的动态模型的用武之地。我们可以使用以下代码实现动态模型:

在这里,我们观察到相邻细胞之间的方向更加一致(尽管神经母细胞之间的方向仍然存在分歧,这可以通过数据平滑来解决),神经元具有明显的主导趋势。使用每个基因的可能性估计,我们可以提取出表现出最显著动态行为的基因:
NPAS3 0.994760
CREB5 0.896914
FOS 0.882965
SLC1A3 0.806150
SYT1 0.749349
MYT1L 0.737498
MAPT 0.687999
GLI3 0.663777
DOK5 0.656130
LINC01158 0.651856
RBFOX1 0.608533
TCF4 0.592459
FRMD4B 0.580061
HMGN3 0.577301
ZBTB20 0.575223
Name: fit_likelihood, dtype: float64

该图显示了基因 RBFOX1 的未剪接/剪接轨迹,根据细胞类型用点着色(蓝色代表放射状胶质细胞,绿色代表成神经细胞,暗金色代表未成熟神经元,红色代表神经元),用 E-M 算法得到的紫色拟合动力学曲线。你可以看到实线曲线如何给出比虚线稳态模型更好的拟合,随着细胞从放射状胶质细胞到神经元,未剪接 mRNA 相对于剪接 mRNA 的转录迅速增加,表明该基因在神经元中被激活,而在放射状胶质细胞中不活跃。我们可以观察到几个基因在神经发生的不同部分被上调和下调的类似动态,如下所示:

最后的想法
scRNA-seq 的一个主要缺点是它只能产生细胞转录组的快照;您不能重新访问您的样本进行后续测序。RNA velocity 是一种规避这种限制的有效方法,它利用 RNA 生物学来推断未来的基因表达,绘制出细胞固有的转录指南针,并为您的数据提供方向性。这可以用来说明细胞到达给定终点可能采取的不同途径,基因表达变化有多快,构建干细胞如何变得更加特化的整体轨迹,还有很多。但是,它也不是没有自己的局限性。如前所述,scRNA-seq 常常是稀疏的和嘈杂的。从描述良好的生物学过程的基本事实来看,速度随后可能是不直观的或完全不正确的。虽然插补和数据平滑等方法有助于纠正这些问题,但应小心使用,因为它们易于消除实际的生物噪声,从而提供有价值的见解,例如向我们数据集中不存在的细胞的潜在转变。尽管如此,这是一种强大的方法,为理解高维生物数据提供了很多清晰度,并且随着数据科学领域的不断发展,这种方法将继续进一步完善。单细胞基因组学这十年的目标之一是有效整合测量细胞不同属性(如 RNA、蛋白质、表观遗传学等)的高维数据集。像 RNA velocity 这样的方法可以扩展来学习这些不同模态之间的关系,从而对细胞间的转换做出强有力的推断,并因此微调细胞的指南针。
参考资料:
[1] G .拉·曼诺、r .索尔达托夫、a .蔡塞尔、e .布劳恩、h .霍赫格纳、v .佩图霍夫、k .李德施赖伯、M. E .卡斯特里蒂、p .伦纳伯格、a .弗尔兰、j .范、L. E .博尔姆、z .刘、d .范·布鲁根、j .郭、x .何、r .巴克、e .松德斯特伦、g .卡斯特洛-布兰科、p .克拉默、I .阿达梅科
[2] V. Bergen,M. Lange,S. Peidli,F. Alexander Wolf 和 F. J. Theis,通过动力学建模将 RNA 速度推广到瞬时细胞状态,(2020),自然生物技术
[3] V. Bergen,R. Soldatov,P. V. Kharchenko,F. J. Theis, RNA 速度——当前挑战和未来展望,(2021),分子系统生物学
从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
原文:https://towardsdatascience.com/road-map-from-naive-bayes-theorem-to-naive-bayes-classifier-6395fc6d5d2a?source=collection_archive---------11-----------------------
朴素贝叶斯分类器的完整指南,从头开始实现

约翰·汤纳在 Unsplash 上拍摄的照片
朴素贝叶斯这个名字本身就表达了算法的含义。但是怎么会!我们来分析一下算法的名字,朴素贝叶斯。我们找到两个术语,一个是朴素的,另一个是贝叶斯。在这里,Naive 意味着算法中使用的所有特征都是相互独立的;而且之所以叫贝叶斯,是因为它依赖于贝叶斯定理。朴素贝叶斯分类器是分类器算法的集合,其中所有算法共享一个共同的原则,因为每个特征对都是彼此独立分类的。它基于一个对象进行预测。为了理解该算法,我们必须从一些基本术语开始,如生成模型、贝叶斯定理。有两种机器学习模型。
- 生成模型
- 判别模型
朴素贝叶斯分类器是生成模型的用例之一。因此,在一开始,我们将讨论生成模型。
注意:如果你想了解概率的概念,在阅读这篇文章之前,我建议你先浏览一下下面这篇文章。]
✪生成模型
生成模型主要关注数据的分布,并考虑分布的密度来计算类。
生成模型的一些示例:
- naïve·贝叶斯
- 贝叶斯网络
- 马尔可夫随机场
- Hidden 马尔可夫模型
- 潜在狄利克雷分配
- 生成对抗网络
- 自回归模型
✪贝叶斯定理
以英国数学家托马斯·贝叶斯命名的贝叶斯定理被用来寻找条件概率。条件概率用于根据前一个事件找到事件概率。贝叶斯定理产生后验概率来分解先验概率。
先验概率是在获取新数据点之前事件的相似性。
后验概率是在获取新数据点后对事件的推测。决定性地,贝叶斯定理试图在新的数据或信息被添加到数据集之后找到事件的可能性。贝叶斯定理的公式:
P(A|B) = P(A) * P(B|A)/P(B)
在哪里,
P(A)表示事件 A 发生的概率
P(B)表示事件 B 发生的概率
P(A|B)表示给定 B 时发生 A 的概率
P(B|A)表示给定 A 时发生 B 的概率
◉朴素贝叶斯算法是如何工作的
一个分类问题可能有一个、两个或多个类别标签。假设我们有 m 个类别标签 y1,y2,…,ym,和 n 输入变量 X1,X2,…,Xn。从这些数据中,我们可以计算出给定输入变量的概率。数据的公式如下
P(yi | x1,x2,…,xm) = P(x1,x2,…,xn | yi) * P(yi) / P(x1,x2,…,xm)。
我们必须确定值 yi 其中 i =1,2,…,m. 最后将这些概率值与对应的 yi 值进行比较。最大概率值表示输出标注。
让我们用下面的例子简化一下。假设我们有一个由三个输入变量组成的‘天气状况’数据集,前景、温度和湿度、和相应的目标值‘播放’。我们试图根据输入变量找出某一天比赛的概率。假设我们要计算天气条件下打球的概率:前景=晴朗,温度=凉爽,湿度=正常。
开始时,我们必须为特定输入变量转换频率表中的数据集,并计算可能性:
➣ 为 Outlook 输入变量

温度输入变量的➣

湿度输入变量的➣

这里, P(播放=是)= 0.5,P(播放=否)= 0.5
现在,我们的配方准备应用贝叶斯定理来找出在那个雨天玩家是否会玩的输出。
P(是|晴,......高)=P(晴|是)P(凉|是)P(正常|是)P(是)/(P(晴)P(凉)*P(正常)
从上表
P(晴|是)= 1/4 = 0.25
P(酷|是)=2/4 = 0.5
P(正常|是)=2/4 = 0.5
P(晴天)= 0.375
P(酷)= 0.375
P(正常)= 0.375
P(是)=4/8 = 0.375
**所以 P(是|晴,…..高)=(0.25 * 0.5 * 0.5 * 0.375)/(0.375 * 0.375)=0.444
P(无|晴……高)= P(晴|无)P(凉|无)P(正常|无)P(无)/(P(晴)P(凉)*P(正常))
根据上表
P(晴|否)= 1/4 = 0.25
P(cool|No)=2/4 = 0.5
P(正常|否)=2/4 = 0.5
P(晴天)= 0.375
P(冷)= 0.375
P(正常)= 0.375
P(否)=4/8 = 0.625
*所以 P(不|晴,…..高)=(0.25 * 0.5 * 0.5 * 0.625)/(0.375 * 0.375) =0.740740
所以,我们从上面的计算中发现。
***P(No|sunny,…..high) > P(No|sunny,…..high)***
因此,在雨天,玩家无法玩游戏。
朴素贝叶斯模型的✪类型
朴素贝叶斯模型的类型基于它们的分布。诸如
◉ 伯努利朴素贝叶斯
伯努利朴素贝叶斯是一种重要的朴素贝叶斯算法。这个模型以文档分类任务而闻名,它决定一个特定的单词是否留在文档中。在这些情况下,频率的计算就不那么重要了。这是最简化的算法。该算法对于小数据集最有效。伯努利朴素贝叶斯的决策规则是

例如,您想知道文档中是否包含特定的单词。在这类二元分类中如真或假、成功或失败、0 或 1、玩或不玩等。,使用伯努利朴素贝叶斯分类。
◉ 多项式朴素贝叶斯
当我们研究术语“多项式”时,它的意思与多类分类密切相关。假设你对特定输出的频率感兴趣;多项式朴素贝叶斯算法是解决这一问题的合适算法。另一个例子是,您给了一个文本文档来查找文档中某个特定单词的出现次数。在这种情况下,您必须应用多项式朴素贝叶斯算法。对于多项式朴素贝叶斯算法,使用多项式分布函数。多项式分布函数:

在这里,我们将展示方程,并用下面的一个实例来找出 P 的过程。例如,我们从城市人口 (孟加拉达卡的拉杰巴里) 中收集了血型样本。此外,计算样本中每个血型的概率。

作者图片
现在,你出了一道题,随机取 9 个人,计算一下。
这里,n1 = O+的频率值,
n2 =频率值 A,
n3 =频率值 B,
n4 =频率值 AB
这里,n=9,随机样本的总数。
另外,p1 = 0.44 =样本中 O+血型的概率,
p2 = 0.42 =样本中 A 血型的概率,
P3 = 0.10 =样本中 B 血型的概率,
P3 = 0.04 =样本中 AB 血型的概率
现在,只要把上面的值代入方程,就会得到多项式朴素贝叶斯的概率。
◉ 高斯朴素贝叶斯
伯努利朴素贝叶斯和多项式朴素贝叶斯用于离散类型数据集。但是我们将使用真实世界的连续数据。在这种情况下,我们需要使用高斯朴素贝叶斯定理。高斯分布或正态分布函数看起来如下:

朴素贝叶斯算法的✪从头实现
为了从零开始实现朴素贝叶斯,我们将一步一步地接近:
**#importing necessary libraries
import numpy as np
import pandas as pd**
➣从头开始创建用于实现朴素贝叶斯算法的数据集。
**from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()data = pd.DataFrame(data=cancer.data, columns=cancer.feature_names)
data['diagnosis'] = cancer.targetdata = data[["mean radius", "mean texture", "mean smoothness", "diagnosis"]]
data.head(10)**

作者图片
➣:首先,我们要计算先验概率。我们已经创建了一个函数calculate _ prior _ probability,其中您将数据帧、df 和 Y 作为输入,并返回先验概率值。如P(Y =是)** 或P(Y =否)。****
➣当我们创建函数 cal_likelihood_gau 时,我们必须计算条件概率。我们将输入必要的数据,计算给定 Y 标签时输入变量 X 的概率,这意味着概率 X 给定 Y 。该函数返回将被进一步使用的 pro_x_given_y,。
➣最后,你必须建立模型,并使用前面的两个函数calculate _ prior _ probability和 cal_likelihood_gau 计算后验概率。
➣从上面的naive_bayes_gaussian() function.中预测最终产量
输出
**[[36 4]
[ 0 74]]
0.9736842105263158**
使用 Sckit-learn 的朴素贝叶斯算法的✪Implementation
➣使用 Sckit-learn 导入实现朴素贝叶斯算法所需的库。这里,我们将实现伯努利、高斯和多项式朴素贝叶斯算法。
**from sklearn import metrics
import urllib
from sklearn.naive_bayes import BernoulliNB,GaussianNB, MultinomialNB
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split**
➣拆分数据集,用于训练、测试和转换数据以适应模型。
**train, test = train_test_split(data, test_size=.2, random_state=41)
X_train=train.iloc[:,:-1].values
y_train=train.iloc[:,-1].values
X_test = test.iloc[:,:-1].values
y_test = test.iloc[:,-1].values**
➣最后,训练模型,测试准确性,并显示混淆度量。
输出
**0.6491228070175439
0.7368421052631579
0.9649122807017544
0.9736842105263158
[[36 4]
[ 0 74]]**
上述结果清楚地表明,当数据集包含连续值时,高斯朴素贝叶斯算法优于其他朴素贝叶斯算法。

来源:https://upload . wikimedia . org/Wikipedia/commons/b/B4/Naive _ Bayes _ classifier . gif
上面的 gif 演示了朴素贝叶斯分类器是如何工作的。
结论
朴素贝叶斯分类器是监督学习中一种简单易行但功能强大的分类算法。如果我们考虑数据集的分布,它在分类提供有效结果的情况下表现良好。更准确地说,当存在对事件的先前发生的依赖性时。在自然语言处理中,有时算法显示出有希望的结果。
参考文献
1.https://www . analyticsvidhya . com/blog/2017/09/naive-Bayes-explained/
2 . https://www . Java point . com/machine-learning-naive-Bayes-classifier
关于数据科学统计学的完整系列文章
- 少即是多;采样的‘艺术’(Stat-01)
- 熟悉数据科学最重要的武器~变量(Stat-02)
- 要提高数据分析能力,您必须了解频率分布(Stat-03)
- 通过可视化频率分布找到数据集的模式(Stat-04)
- 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
- 通过简短的讨论消除你对 Mean 的误解(Stat-06)
- 通过规范化提高您的数据科学模型效率(Stat-07)
- 数据科学的基本概率概念(Stat-08)
- 从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
- 数据科学爱好者需要知道的假设检验(Stat-10)
- 多组间统计比较用 ANOVA (Stat-11)
- 用卡方检验比较分类变量的相关性(Stat-12)
路标让你疯狂?
原文:https://towardsdatascience.com/road-signs-driving-you-crazy-e686d97f2480?source=collection_archive---------16-----------------------
以下是我如何建立一个程序来为你阅读它们

罗西·斯蒂格尔斯在 Unsplash 上的照片
路标。一大堆不同颜色的符号,它们的形状你应该能够推断出它们的意思。奇怪的符号,你必须谷歌甚至模糊地认识。路标令人困惑,很难记住它们的意思。这就是为什么我建立了这个程序来为你阅读它们!给定一张足够清晰、裁剪得当的图像,我的 CNN 可以读取路标中的图案,并使用数字分类系统对它们进行分类。我将向你展示它是如何工作的!
目录
因为这是一篇有点长的文章,我想我应该给你一个简短的目录,以便能够快速导航到我的文章的特定部分。
- 为什么这个其实有用?
- CNN
- 入门
- 准备数据
- 创建神经网络
- 定义功能
- 训练神经网络
- 测试型号
为什么这实际上是有用的?
你可能想知道这一切有什么意义。当我们可以自己看路标时,为什么我们需要一台计算机来对它们进行分类?
答案:自动驾驶汽车。
无人驾驶汽车每天都变得越来越真实。谷歌的姐妹公司 Waymo 已经在亚利桑那州的凤凰城建立了完整的系统。城市特定区域的市民可以像订购优步一样订购无人驾驶汽车!但是,为了让自动驾驶汽车与你今天可能驾驶的汽车无缝集成,它们需要能够像人类一样遵守道路规则。这包括阅读路标!
CNN
你可能也想知道这些 CNN 的东西是什么。别担心,我可以解释😉
CNN 是一种特别擅长图像分类的神经网络(阅读我的其他文章来了解基础知识)。CNN 用于计算机视觉,因为它们擅长检测图像中的图案,如线条、圆形和其他形状和图案。CNN 使用卷积层,它本质上学习可以检测图像模式的过滤器。例如,过滤器可以检测垂直线,也可以检测水平线。

信用:塔拉普罗尔
这些滤波器在图像上“卷积”,以小的 3x3(或任何大小的滤波器)块来获得所述 3x3 块的点积。过滤器首先检查输入图像的第一个 3x3 区域,并找到该块的点积。它记录下来,并成为下一层输入的一部分。对于整个图片中的每一个 3×3 的块,都会发生这种情况,并且创建一个用点积和过滤器简化的新图片。

图片由 Kjell Magne Fauske 在公共领域发布
正如你所看到的,这个过滤器把一个更大的图像变成更容易管理和计算机可读的东西。过滤器通常检测图像中最相关和最突出的特征——它们可以非常简单,如检测线条和形状,也可以非常复杂,如面部识别——或者就我而言,是路标。
如果你想看看这些卷积层是如何工作的,请查看瑞尔森大学的资源:
[## 卷积神经网络的三维可视化
www.cs.ryerson.ca](https://www.cs.ryerson.ca/~aharley/vis/conv/)
这里有一段来自 DeepLizard 的视频,让你了解更多关于 CNN 的信息:
CNN 上的深蜥蜴
入门指南
为了创建我自己的 CNN,我使用了一个叫做 PyTorch 的 Python 库。PyTorch 是一个开源的机器学习框架,允许你从头到尾创建神经网络。首先,我通过 Kaggle 创建了一个 Jupyter 笔记本,这是一个非常有用的网站,允许你使用免费的 GPU 来运行你的机器学习模型。我强烈建议将您的代码移到那里——一旦您掌握了窍门,它非常直观且易于使用。
神经网络在大型数据集上训练。在我的神经网络中,我使用德国交通标志识别基准(GTSRB)数据集来训练和测试神经网络。我的神经网络对一组 39,209 个带标签的图像进行了训练,以学习用于确定路标模式的过滤器。然后,它在一组 12,630 张带标签的测试图像上进行测试,以了解它在真实世界数据上的准确性。
为了将数据加载到我的程序中,我前往 GTSRB 数据集的 Kaggle 页面,并创建了一个新的笔记本。
import torch as t
import torchvision
from torchvision import transforms
import torch.utils.data as data
import torch.optim as optim
import torch.nn as nn
import time
import numpy as np
import os
import matplotlib.pyplot as plt
下面是我导入的库的列表,它们是什么,以及它们各自文档的链接。
- PyTorch
- 火炬视觉【PyTorch 内部的计算机视觉库
- Transforms -允许转换输入数据,在这种情况下是从图像到张量。还能够对输入数据进行大小调整、裁剪和其他转换。
- torch.utils.data -处理数据的工具
- torch.optim -优化算法,使网络达到最佳状态
- torch.nn -神经网络工具,专门为训练神经网络而制作
- 时间 -用于计时测试和培训所需的时间
- NumPy——用于制作和使用数据数组
- os -用于管理我们程序中的文件
- matplotlib.pyplot -用于显示整个程序的图形和图像
准备数据
*#Defining the transformation*
data_transforms = transforms.Compose([transforms.Resize([112, 112]), transforms.ToTensor()])
接下来,我为数据定义了转换。该转换将输入图像的大小调整为 112x112,并将这些图像转换为张量。
*#Defining hyperparameters*
BATCH_SIZE = 256
learning_rate = 0.001
EPOCHS = 7
numClasses = 43
然后我定义了模型的超参数,比如批量大小、学习速率和时期数。批量大小是指一次处理的图像数量。学习率是神经网络每次出错时调整的程度。历元是计算机检查整个训练集的次数(它查看每个图像 7 次)。
*#path of training data*
train_data_path = '../input/gtsrb-german-traffic-sign/Train'
train_data = torchvision.datasets.ImageFolder(root = train_data_path, transform = data_transforms)
*#Divide data into training and validation (0.8 and 0.2)*
ratio = 0.8
n_train_examples = int(len(train_data) * ratio)
n_val_examples = len(train_data) - n_train_examples
train_data, val_data = data.random_split(train_data, [n_train_examples, n_val_examples])
print(f"Number of training samples = **{**len(train_data)**}**")
print(f"Number of validation samples = **{**len(val_data)**}**")
接下来,我开始创建我的数据集!首先,我定义了训练数据的文件路径。Kaggle 使复制和粘贴数据路径在您的程序中使用变得很容易——只需前往界面的右侧,将鼠标悬停在包含您的列车数据的文件夹上,然后单击复制按钮。然后,我使用 torchvision 的 ImageFolder 数据集类型,使用 Kaggle 文件路径和我之前定义的转换,创建了我的训练集。
然后,我将训练集分为训练集和验证集。训练是程序实际训练的内容——这些是它将学习识别的图像。验证集基本上是为了在训练时进行测试——它让您实时看到您的模型在没有训练的数据上的表现。
*#create data loader for training and validation*
trainloader = data.DataLoader(train_data, shuffle=True, batch_size=BATCH_SIZE)
valloader = data.DataLoader(val_data, shuffle=True, batch_size=BATCH_SIZE)
准备训练数据的最后一步是创建数据加载器。这基本上是一种让程序轻松访问和遍历你定义的数据集的方法。我已经将这些加载器的批处理大小设置为 256(我之前设置的变量),它们每次都会洗牌。
*# Plot histogram for training and validation data*
train_hist = [0]*numClasses
for i **in** train_data.indices:
tar = train_data.dataset.targets[i]
train_hist[tar] += 1
val_hist = [0]*numClasses
for i **in** val_data.indices:
tar = val_data.dataset.targets[i]
val_hist[tar] += 1
plt.bar(range(numClasses), train_hist, label="train")
plt.bar(range(numClasses), val_hist, label="val")
legend = plt.legend(loc='upper right', shadow=True)
plt.title("Distribution Plot")
plt.xlabel("Class ID")
plt.ylabel("# of examples")
plt.savefig("train_val_split.png", bbox_inches = 'tight', pad_inches=0.5)
不过,在开始实际训练网络之前,我画了一个数据分布图。我设置它来显示总共有多少个例子,以及训练和验证之间的差异。

信用:塔拉普罗尔
创建神经网络
class **NeuralNet**(nn.Module):
def __init__(self, output_dim):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=2, padding=1),
nn.MaxPool2d(kernel_size=2),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=64, out_channels=192, kernel_size=3, padding=1),
nn.MaxPool2d(kernel_size=2),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=192, out_channels=384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
nn.BatchNorm2d(256),
nn.MaxPool2d(kernel_size=2),
nn.ReLU(inplace=True),
)
self.classifier = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(256*7*7, 1000),
nn.ReLU(inplace=True),
nn.Dropout(0.5),
nn.Linear(in_features=1000, out_features=256),
nn.ReLU(inplace=True),
nn.Linear(256, output_dim)
)
def forward(self, x):
x = self.features(x)
h = x.view(x.shape[0], -1)
x = self.classifier(h)
return x, h
有趣的事情从这里开始!这是我定义我的神经网络的代码块。这个网络非常类似于 AlexNet 框架,使用 5 个卷积层,然后是 3 个全连接(线性)层。每个卷积层使用最大池。这里有一个来自 DeepLizard 的关于 max pooling layers 的视频,我觉得它很好地解释了这个主题。
最大池层数上的深蜥蜴
我还使用了退出方法来减少我的模型中的过度拟合(网络学习特定的图像而不是模式)——这是使用 nn 定义的。辍学(0.5)。
*# define optimiser and criterion functions*
optimiser = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=0.01)
criterion = nn.CrossEntropyLoss()
这里我定义了优化器和损失函数。优化器是在每个训练时期之后返回并固定模型的参数。我还在优化器中设置了权重衰减,这意味着权重每次都会减少一点。这也有助于减少过度拟合。
定义函数
*# Function to perform training of the model*
def train(model, loader, opt, criterion):
epoch_loss = 0
epoch_acc = 0
*# Train the model*
model.train()
for (images, labels) **in** loader:
images = images.cuda()
labels = labels.cuda()
output, _ = model(images)
loss = criterion(output, labels)
*# Training pass*
opt.zero_grad()
*# Backpropagation*
loss.backward()
*# Calculate accuracy*
acc = calculate_accuracy(output, labels)
*# Optimizing weights*
opt.step()
epoch_loss += loss.item()
epoch_acc += acc.item()
return epoch_loss / len(loader), epoch_acc / len(loader)
接下来,定义一个函数来训练模型。基本上,该函数迭代通过训练/验证加载器并训练网络。需要注意的几件重要事情是优化和反向传播。该函数还返回它所使用的每个历元的损失和精度(一个历元是程序循环通过所有训练数据的次数)。
def evaluate(model, loader, opt, criterion):
epoch_loss = 0
epoch_acc = 0
*#evaluate the model*
model.eval()
with t.no_grad():
for (images, labels) **in** loader:
images = images.cuda()
labels = labels.cuda()
output, _ = model(images)
loss = criterion(output, labels)
acc = calculate_accuracy(output, labels)
epoch_loss += loss.item()
epoch_acc += acc.item()
return epoch_loss / len(loader), epoch_acc / len(loader)
我还定义了一个函数来评估模型。不使用梯度下降,它测试网络的表现如何。像训练函数一样,它评估网络的损耗和准确性。
训练神经网络
*#TRAINING*
train_loss_list = [0]*EPOCHS
train_acc_list = [0]*EPOCHS
val_loss_list = [0]*EPOCHS
val_acc_list = [0]*EPOCHS
for epoch **in** range(EPOCHS):
print("Epoch **{}**: ".format(epoch))
train_start_time=time.monotonic()
train_loss, train_acc= train(model, trainloader, optimiser, criterion)
train_end_time = time.monotonic()
val_start_time = time.monotonic()
val_loss, val_acc = evaluate(model, valloader, optimiser, criterion)
val_end_time = time.monotonic()
train_loss_list[epoch] = train_loss
train_acc_list[epoch] = train_acc
val_loss_list[epoch] = val_loss
val_acc_list[epoch] = val_acc
print("Training: Loss = **%.4f**, Accuracy = **%.4f**, Time = **%.2f** seconds" %(train_loss, train_acc, train_end_time-train_start_time))
print("Validation: Loss = **{}**, Accuracy = **{}**, Time = **{}** seconds".format(val_loss, val_acc, val_end_time - val_start_time))
print("")
这就是:我的代码中最重要的部分!这个模块是所有神经网络训练发生的地方。它首先打印出纪元编号,然后使用训练集加载器训练模型。它还使用 time.monotonic()函数计算训练模型所需的时间。然后它对验证集做同样的事情,除了它使用 evaluate 函数(这里没有训练)。
在这一切结束时,它打印出损耗、精度和训练网络所用的时间。我看到了损失的减少和精确度的提高——这非常令人满意😁

前一个块的输出——看着损耗减少,精度增加!
顺便说一下,你可以访问项目的 Kaggle 页面来查看这些块的所有输出。
*# Saving the model*
*# Create folder to save model*
MODEL_FOLDER = "../Model"
if **not** os.path.isdir(MODEL_FOLDER):
os.mkdir(MODEL_FOLDER)
PATH_TO_MODEL = MODEL_FOLDER + "/pytorch_classification_alexnetTS.pth"
if os.path.exists(PATH_TO_MODEL):
os.remove(PATH_TO_MODEL)
t.save(model.state_dict(), PATH_TO_MODEL)
print("Model saved at **%s**" %(PATH_TO_MODEL))
当训练完成时,程序保存模型,以便我可以在以后加载和使用它。
*# Plot loss and accuracies for training and validation data*
_, axs = plt.subplots(1, 2, figsize=(15, 5))
*# Loss plot*
axs[0].plot(train_loss_list, label="train")
axs[0].plot(val_loss_list, label="val")
axs[0].set_title("Plot - Loss")
axs[0].set_xlabel("Epochs")
axs[0].set_ylabel("Loss")
legend = axs[0].legend(loc='upper right', shadow=False)
*# Accuracy plot*
axs[1].plot(train_acc_list, label="train")
axs[1].plot(val_acc_list, label="val")
axs[1].set_title("Plot - Accuracy")
axs[1].set_xlabel("Epochs")
axs[1].set_ylabel("Accuracy")
legend = axs[1].legend(loc='center right', shadow=True)
测试过程之前的最后一点代码是绘制网络的损耗和准确性。这使用 matplotlib 库来创建两个简单的线图,显示每个时期的损耗和每个时期的精度。每个图表将这些元素中的一个与训练集和验证集进行比较。训练集的线条是蓝色的,验证集的线条是橙色的。看到网络如何随着时代的发展而进步真的很有趣。

信用:塔拉普罗尔
测试模型
现在我已经训练了神经网络,是时候看看它在一些它从未见过的测试数据上的表现了。这是因为在现实世界中,并非所有的路标都处于相同的角度,相同的旋转,相同的背景-计算机通过训练集学习了许多变化,我们需要看看它是否可以应用于一些新的例子。
*#Define transformations*
test_transforms = transforms.Compose([
transforms.Resize([112, 112]),
transforms.ToTensor()
])
首先,我为测试数据定义了转换。这种转换将测试图像转换为 112 x 112 的图片,然后转换为 PyTorch 可以读取的张量。
*# Define path of test data*
test_data_path = "../input/gtsrb-test-images/GTSRB/Final_Test"
test_data = torchvision.datasets.ImageFolder(root = test_data_path, transform = test_transforms)
test_loader = data.DataLoader(test_data, batch_size=1, shuffle=False)
numClasses = 43
然后我定义了测试数据的路径,再次使用 Kaggle 数据集中的复制粘贴函数。对于测试数据,我在数据输入方面有一些问题。我使用的 CSV 文件中的 png 格式,图像是。ppm 文件。我选择从 GTSRB 网站单独下载测试图片,并上传到 Kaggle 作为自定义数据集。
import pandas as pd
*# Read the image labels from the csv file*
*# Note: The labels provided are all numbers, whereas the labels assigned by PyTorch dataloader are strings*
df = pd.read_csv("../input/gtsrb-german-traffic-sign/Test.csv")
numExamples = len(df)
labels_list = list(df.iloc[:,6])
print(numExamples)
为了让计算机读取每个图像,使用 CSV 文件来获取文件路径和它们各自的类。为了实现这一点,我导入了 Pandas 库。我用它来读取 CSV 文件,获取示例数量,并使用 iloc 函数创建标签列表。这得到了整个列(列 7,按照 Python 语法索引为 6 ),并将它转换成一个列表,我可以用它来标记测试图像。
*#Perform classification*
y_pred_list = []
corr_classified = 0
with t.no_grad():
model.eval()
i = 0
for image, _ **in** test_loader:
image = image.cuda()
y_test_pred = model(image)
y_pred_softmax = t.log_softmax(y_test_pred[0], dim=1)
_, y_pred_tags = t.max(y_pred_softmax, dim=1)
y_pred_tags = y_pred_tags.cpu().numpy()
y_pred = y_pred_tags[0]
y_pred = labels[y_pred]
y_pred_list.append(y_pred)
if labels_list[i] == y_pred:
corr_classified += 1
i += 1
print("Correctly classified: **{}**".format(corr_classified))
print("Incorrectly classified: **{}**".format(numExamples - corr_classified))
print("Final accuracy: **{}**".format(corr_classified / numExamples))
这是一大段代码🤣总的来说,这个模块为模型对测试数据的预测创建了一个空列表。在没有梯度下降(没有训练)的情况下,代码循环通过测试加载器中的每个图像,并在模型中运行它。它使用 softmax 和 max 函数来预测给定图像将具有哪个标签,然后将该标签添加到之前创建的列表中。
最后,它打印出正确分类的数量,错误分类的数量,然后将两者相除得到最终的准确度。
*# Display first 30 images, along with the actual and predicted classes*
from PIL import Image
fig, axs = plt.subplots(6,5,figsize=(50,75))
*#fig.tight_layout(h_pad = 50)*
for i **in** range(30):
row = i // 5
col = i % 5
imgName = '../input/gtsrb-test-images/GTSRB/Final_Test/' + df.iloc[i,7]
wrongFolder = str(imgName).replace('/Test', '/Images')
wrongExtension = wrongFolder.replace('.png', '.ppm')
img = Image.open(wrongExtension)
axs[row, col].imshow(img)
title = "Pred: **%d**, Actual: **%d**" % (y_pred_list[i], labels_list[i])
axs[row, col].set_title(title, fontsize=50)
plt.savefig("predictions.png", bbox_inches = 'tight', pad_inches=0.5)
最后,是时候看看一些真实的数据和随之而来的预测了!这段代码显示了 30 个测试图像,预测和实际标签显示在每个图像的上方。

信用:塔拉普罗尔
正如你所看到的,该模型只预测了一些错误的图像,并且在对一些硬路标进行分类方面做了非常出色的工作。
这个项目来自 Suraj Krishnamurthy 的 GTSRB 分类程序。这里看 Github 项目原文:【https://github.com/surajmurthy/TSR_PyTorch
https://www.linkedin.com/in/taraprole/
如果你有兴趣看更多我的作品,我有一份每周时事通讯,请在下面订阅!
https://taraprole.substack.com/subscribe
参考
GTSRB 数据集
- Johannes Stallkamp、Marc Schlipsing、Jan Salmen 和 Christian Igel
人与计算机:交通标志识别的基准机器学习算法。神经网络 32,第 323–332 页,2012 年 - Johannes Stallkamp、Marc Schlipsing、Jan Salmen 和 Christian Igel
德国交通标志识别基准:多类别分类竞赛。神经网络国际联合会议(IJCNN 2011),第 1453–1460 页,IEEE 出版社
用人工智能将咖啡烘焙到极致
原文:https://towardsdatascience.com/roasting-coffee-to-perfection-using-ai-33ff249377e4?source=collection_archive---------33-----------------------
真实世界人工智能
多亏了人工智能,完善你最喜欢的一杯咖啡变得更容易了

照片由🇸🇮·扬科·菲利在 Unsplash 上拍摄
如果你是一个咖啡爱好者,你可能想知道你最喜欢的一杯早茶是如何变得如此美味的。
当然,还有咖啡师的技巧,以及浓缩咖啡机器的质量。
但是还有咖啡豆的烘焙——做好这一点会让你的早餐味道大不相同。
咖啡烘焙是一个复杂的过程,需要相当程度的技巧。
在繁忙的咖啡烘焙场所里,想要获得持续的好结果并不容易。
这就是为什么挪威咖啡烘焙专家— 罗斯特 —一直求助于人工智能 (AI)来获得最佳效果。
在这篇文章中,我们将看看人工智能的有趣应用——特别是tinyML——如何烘焙出始终如一的好咖啡。
味道在棕色中
你听说过美拉德反应吗?(显然,它的发音是我的 - YAR )
一般来说,这是烹饪的一个重要部分,指的是食物开始变成褐色的阶段。例如,想想烤洋葱、茄子、牛排和土豆。
如果你和很多人一样,现在你可能会想“好吃!”——正是这种变褐的过程给我们喜爱的许多菜肴增添了许多风味。
那么,MR 和咖啡烘焙有什么关系呢?
倾听第一次破裂
碰巧的是,管理 MR 过程需要多长时间是咖啡烘焙最重要的方面之一。
根据 Rounton Coffee 的 Guy Snead 的说法,将 MR 延长一点时间,你会得到“更重的口感和丰富的焦糖味道”。或者,如果你喜欢“内在水果味”和“明显酸味”的咖啡,你就需要一个短点的 MR。
因此,追踪 MR 对咖啡烘焙至关重要。
MR 进展如何的一个关键指标是烘焙咖啡豆的第一次破裂发生的时间。
当豆子里的水变成蒸汽时,会听到第一声爆裂声,结果,豆子开始“爆”开,就像爆米花一样。
听第一次破裂是由专业烘焙师手动完成的,需要持续关注以帮助确定破裂的准确时间。
由于这是一个手动过程,不同烘焙者的一致性各不相同。
它还占用了烘焙师繁忙日程中的宝贵时间——因为它需要专注的注意力——并且限制了烘焙师处理其他任务的能力。
自动化对第一条裂纹的一致而准确的识别将对咖啡烘焙师大有裨益。这就是人工智能可以帮助的地方。
完美烘焙咖啡的样品
Roest 专门从事样品烘焙— 烘焙少量生咖啡豆以确定其特殊品质的实践。
样品烘焙是咖啡供应链的重要组成部分。它为出口商、进口商和咖啡烘焙商提供了做出合理采购决策所需的信息。
鉴于样品烘焙的重要性,仔细管理烘焙过程对于确定咖啡样品批次的质量至关重要。
Roest 是一家屡获殊荣的样品烘焙机制造商。他们的机器以质量和精度著称,这两者对于样品烘焙来说都很重要,甚至比日常食用烘焙更重要。
Roest 已经转向人工智能,将他们的样品烘焙机提升到一个新的水平。
人工智能如何帮助烘焙咖啡
如前所述,识别第一个裂缝是咖啡烘焙过程的重要部分。
通过与另一家挪威公司 Soundsensing 合作,音频和机器学习专家 Roest 和 Soundsensing 开发了一种自动化解决方案,以高精度识别第一个裂缝。
它是这样工作的:
- 使用一个 tinyML 实现,即。在微型设备上运行机器学习在物联网(internet-of-things)框架中,一个小型微控制器被放置在每台咖啡烘焙机内
- 微控制器包括一个小型麦克风,以及相关的声音感应固件,在烘焙过程中监听咖啡豆
- 一个已经过预训练的机器学习算法(神经网络)以高精度识别和鉴别咖啡豆的第一个裂纹是嵌入在微控制器中的
- 在识别出第一条裂纹后的预设时间,烘烤机自动关闭并停止烘烤过程
这种 tinyML 解决方案使烘焙过程完全自动化,并具有以下优势:
- 腾出焙烧操作工做其他工作
- 提高焙烧过程的一致性
- 保持标准,无论个体烘焙操作员的技能水平如何
- 使得烘焙过程的放大更容易
自 2020 年以来,Roest 一直在他们的烤箱中使用这种 tinyML 解决方案。
未来召唤着 tinyML 声学解决方案
这种类型的人工智能应用——使用 tinyML 和声学技术来识别咖啡烘焙中的第一个裂缝——是世界上第一个此类应用。
未来应用的可能性是多种多样的。
通过使用声音,声音传感已经涉及工业机器监控的许多领域。借助 AI 和 IoT-tinyML 技术,这种智能监控的能力和部署可能性可能会显著增加。
概括起来
- 咖啡烘焙是一个复杂的过程,其中一个关键部分是检测烘焙咖啡豆的第一个裂纹
- 样品烘焙是咖啡供应链中至关重要的一环,在这一过程中,宝贵的时间和资源被用于检测第一个裂缝
- 两家挪威公司 Roest 和sound sensing 开发了一种自动化人工智能解决方案,利用 tinyML 和声学技术来识别咖啡烘焙过程中的第一个裂缝,这在世界上尚属首次
- 这种人工智能解决方案将烘焙操作员解放出来从事其他工作,并提高了咖啡烘焙过程的一致性和准确性
- 自 2020 年以来,Roest 一直在运输其获奖的咖啡烘焙机,其中包括人工智能解决方案
- 鉴于能够部署在人工智能驱动的物联网设备上的能力, tinyML-acoustic 解决方案的未来可能性非常大
机器人记者——如何应对重复
原文:https://towardsdatascience.com/robojournalism-how-to-tackle-the-repetition-693fcc25cac4?source=collection_archive---------23-----------------------
在基于模板的自动新闻 NLG 中改进语言多样性

汉娜·格蕾丝在 Unsplash 上的照片
在这篇博文中,我描述了我 2020 年在赫尔辛基大学进行的数据科学领域硕士论文研究的一部分。2021 年 4 月,一篇关于新闻媒体内容分析和自动报告生成的论文随后发表在《EACL 黑客工作室学报》上。特别感谢我的硕士论文导师和合著者 Leo Leppä nen。
为了服务于更广泛的受众,我将很快解释一些关键概念。然而,理解这篇文章需要对计算机科学有一些基本的了解。
自然语言生成(NLG)——在 NLG,目标是从一些潜在的非语言数据(如时间序列数据或图像)中创建可以用英语或其他人类语言生成流利文本的系统。
基于模板的 NLG —经典的 NLG 方法,通过将数据插入模板来构造最终文本,如“In【where】,最高温度为【period】【temperature】【C”。由此产生的句子可能是“在 芬兰 ,2020 年夏季的最高温度是 33.5 摄氏度”。**
词性(POS)标签 —用于表示单词在文本中的作用的标签,例如名词和副词。
单词嵌入 —用数字向量表示的自然语言单词,以便计算机能够理解它们。这些从文本集合中学习的向量形成了向量空间,其中向量的距离是那些单词的语义距离的近似值。一个经典的例子是,你可以做这样的计算,“如果你从国王的向量中减去男人的向量,然后加上女人的向量,你就会得到王后的向量”。
上下文单词嵌入 —单词嵌入最初是非上下文的,这意味着不管原始上下文如何,拼写相同的两个单词将具有相同的向量表示。让我们以银行这个词为例,它可以指一家银行或一家金融机构。上下文单词嵌入将学习不同上下文的不同向量表示。**
在基于模板的自动新闻 NLG 中使用上下文单词嵌入来改进语言的多样性
基于模板的自然语言生成(NLG)方法仍然广泛用于新闻行业的自动化新闻报道,即使已经引入了新的和令人兴奋的 NLG 统计方法。为什么?基于模板的方法精确地表示底层数据,并且它们的过程是透明的。****
开发一个简单的基于模板的 NLG 系统很容易,但是当引入更多的模板来增加语言的多样性时,所需的工作量就会迅速增加。并且当为特定领域编写大量模板时,如果不进行大量修改,它们就不能转移到新的领域。
对于我的硕士论文研究,我们提出了一个想法:如果我们依靠少量的简单模板,并允许上下文单词嵌入模型在输出中插入新的和替换现有的单词,会怎么样?
由于保留意义和控制输出对于新闻的上下文至关重要,我们将方法缩小到只插入预定义的词类和用同义词替换。
方法
在我的论文研究中,我开发了两个算法,一个用于单词的添加,一个用于单词的替换。我的方法需要上下文单词嵌入,带有一个屏蔽语言模型头( BERT )、一个同义词词典( Wordnet )和一个词性标注工具( NLTK ),可用于所讨论的语言(英语)。我的研究中使用的具体工具和语言在括号中提到。
作为示例使用的系统从欧盟统计局(欧盟统计局)提供的时间序列数据中生成新闻报道。
基于上下文添加新单词
为了添加新词,将带有词性标签定义的空槽引入到中间领域模板中。然后,在过程结束时处理这些空槽,因为上下文单词嵌入需要上下文,即句子中的周围单词来操作。
在澳大利亚,2018 年 75 岁或以上的女性 {empty,pos=RB} 的平均等值净收入为 22234 €。
然后,使用上下文单词嵌入来为该空槽找到一组合适的单词。如果单词从上下文单词嵌入中得到高于给定阈值的分数,则该单词被认为是合适的。然后通过我们选择的词类来缩小单词列表,在这个例子中,词类是副词 RB。
在澳大利亚,2018 年 75 岁以上的女性仍然获得 22234 €的平均等值净收入。
简而言之的插入算法(硕士论文中有完整的伪代码):
输入:句子、词性、k、最小掩码标记数、最大掩码标记数
输出:拟合词列表
- 初始化空列表 WordsAndScores 。
- 从 min [MASK] tokens 到 max [MASK] tokens
2.1 范围内的 n 循环。在句子中插入 n [MASK]标记,代替空槽
2.2。针对 2.1 中的屏蔽句子,从屏蔽语言模型中获取 top k 预测(单词和分数)。
2.3。将单词及其分数插入到步骤 1 中初始化的列表中。 - 返回列表单词和分数的子集,其中单词词性等于输入词性,分数大于或等于确定的阈值。**
基于上下文替换现有单词
为了替换单词,单词在中间模板中被标记为“要被替换”。
在芬兰,2016 年家庭在医疗保健上的总支出为 20.35 %。
在生成过程结束时,向同义词词典查询要替换的那些单词的同义词。这些同义词随后用带有屏蔽语言模型头的上下文单词嵌入来评分,并且那些分数高于给定阈值的被认为是合适的候选。然后从这个列表中随机选择一个单词。
在芬兰,2016 年家庭在医疗保健上的总支出为 20.35 %。
替换算法简称(硕士论文有完整伪代码):
输入:原单词,句子
输出:拟合单词列表
- 初始化一个空列表字和分数**
- 从同义词词典中获取原单词的同义词列表
- 循环同义词列表
3.1。用句子
3.2 中的同义词替换原词。使用掩蔽语言模型,给句子
3.3 中的单词打分。将同义词和分数添加到步骤 1 中初始化的单词和分数列表中。 - 返回列表中得分大于或等于给定阈值的子集 WordsAndScores
结果呢
我们的方法由通过在线平台招募的人类法官进行评估。法官被问及关于原句和修改后的句子的问题 1-3,以及关于合适和不合适单词的问题 4 和 5。
- 原句是目标语言中质量好的句子。
- 修饰句是目标语言中质量好的句子。
- 原文和修改后的句子意思基本相同。
- 有多少被评估为合适的单词可以用在第一句中标记的地方,这样意思基本上保持不变?
- 有多少被评价为不合适的词可以用在第一句中有标记的地方,使意思基本保持不变?
问题 1 和 2 被要求评估修改是否改变了句子质量,问题 3 被要求评估句子含义是否基本上保持与定义为新闻生成系统的要求相同。
问题 4 和 5 用来检查我们将单词分为合适和不合适的单词是否有意义。事实并非如此。有合适的词被排除在第一组词之外,类似地,一些明显不合适的词也被包括在第一组词中。
然而,根据我们的评估,修改并没有降低句子的质量,句子的含义基本上与用李克特量表评估句子 1-3 时相同,李克特量表的范围从 1(“强烈不同意”)到 4(“既不同意也不反对”)到 7(“强烈同意”),Q1 和 Q2 的得分大致相同,Q3 的得分也在同意一方。我们认为这些结果是成功的。

插入法句子的质量和句子意义的保持。

英语中高资源替换句子的质量和句子意义的保持。
插入和替换方法的人工评估结果。主要数字是在 7 点李克特量表上给出的分数,括号中的数字是标准偏差。
关键要点
- 在一个案例研究的上下文中使用这篇博文中提出的算法确实创造了语言的多样性,同时保持了句子的质量和意义。
- 加法:将加法缩小到一个特定的词类,使过程处于控制之中。我预计,要添加的词性“安全”在很大程度上取决于文本的类型。例如,对于新闻报道,添加形容词可能会添加错误信息,从而改变意思,但对于虚构的故事,这可能是一个有趣的选择。
- 替换方法:同义词词典的使用减少了自然语言生成所需的模板变体的数量,而语言模型的使用允许对提议的变体进行上下文评分,从而选择更高质量的结果。例如,人们可以找出某个词类“安全”地在自己的领域中进行替换,并允许替换模板中该词类的所有出现。
限制
- 在替换法中,我设法避免了用英语处理词法形式。我预计开发一个单独的词法处理将允许成功地替换单词,例如,复数形式。
- 这些结果是在局部(句子)而不是全球(完整的新闻报道)水平上进行评估的。我们预计,例如,当在一个句子中插入一个像“still”这样的词时(如关于加法方法的部分中的示例所示),当在全局级别上进行评估时,结果可能会有所不同。
其余硕士论文研究
在我的论文工作中,我还为低资源语言开发了本文中提出的算法的变体,这些语言没有同义词词典或词性标注工具。这些变体利用成对对齐的跨语言单词嵌入将低资源语言单词“翻译”成高资源语言,然后利用可用的同义词词典和词性标注工具。这些变体的结果明显低于这篇博文中的结果。然而,已经确定了一些明显的改进点。
感谢您的阅读!如果你学到了新的东西或者喜欢这篇文章,在 Medium 上跟随我。我目前正在撰写关于 NLP 和数据工程的未来文章。你也可以在 LinkedIn 上找到我。你可以从以下链接找到原始论文和研讨会论文:
硕士论文 : 【语境和跨语言嵌入的自动撰写新闻的(再)词汇化
研讨会论文 : 使用上下文和跨语言的单词嵌入来提高基于模板的自动杂志 NLG 的多样性
机器人农场、人工生命和二阶工程
原文:https://towardsdatascience.com/robot-farms-artificial-life-and-second-order-engineering-an-in-depth-interview-with-professor-a524c92ee455?source=collection_archive---------25-----------------------

布雷特·乔丹在 Unsplash 上的照片
思想与理论
古兹提·艾本教授深度访谈
1991 年,Guszti Eiben 在埃因霍温理工大学获得了计算机科学博士学位。他在布达佩斯的 etvs loránd 大学攻读数学硕士学位期间,第一次接触到了人工智能。在当时,AI 非常深奥,Guszti Eiben 只能做白日梦来想象它的可能性。现在,作为阿姆斯特丹自由大学的人工智能教授和约克大学的特别客座教授,他拥有实现所有科幻梦想的工具。艾本教授是进化计算的先驱;他编写了现在许多大学都在使用的教科书,是世界上第一个让两个机器人生孩子的人,并不断推动该领域超越现状。
2018 年,一个由他的英国同事组成的财团获得了 200 万欧元的资助,用于研究自主机器人进化。ARE 项目正在建造 EvoSphere,这是一个进化机器人栖息地,作为研究进化和智能出现的工具。对于生物学家和计算机科学家来说,基本的进化问题现在可以得到解答了。但是 EvoSphere 也有望推动工程学的发展;应用包括自主机器人殖民太空和清理地球上的核反应堆。艾本教授假设,如果进化可以创造智能,那么人工进化也可以创造人工智能。
艾本教授,继续你的类比:上帝创造了后代,而你创造了人造后代。说你是人造神公平吗?
肯定不是,而且我不同意你第一部分的说法‘上帝创造了后代’,因为进化创造了后代。这是一个很大的起点差异。简单来说,一开始,物理变成了化学,化学变成了生物。与最后一次转变同时,进化出现了。我们仍处于进化的伟大过程中,这是地球上最伟大的表演。我只能改变基质,在这个过程中起次要作用。我们所知道和分析的唯一进化形式是碳基的,也就是地球上的生命。像我这样的人不会引入新的原则;我们只是在新的媒介上引入进化原理。
顺序如下:19 世纪,达尔文用湿件描述了进化。在 20 世纪,软件进化是由计算机科学家发明的。现在,在 21 世纪,我们正致力于硬件的发展。因此,有两个重大转变:
1.湿件到软件
2.软件到硬件。
结果是硬件的进化,这不同于我们所知的碳基生命。
“未来的人工智能将由自主过程产生,而不是由人类开发人员编码解决方案。我把这种现象称为“二阶工程”。"
你被认为是进化计算的先驱;你的主要贡献是什么?
在 20 世纪后期,出现了一个社区,它使用基于达尔文原理、选择和繁殖的搜索算法来解决问题,并开发了现在称为进化计算的东西。然而,在早期,没有人知道如何精确调整进化算法。首先,我对方法论做出了贡献。我烧死了三个研究和优化进化过程中超参数的博士生。我展示了进化过程的质量如何依赖于这些超参数,并把它放在了研究议程上。此外,我优化了优化器,以改善进化过程的结果。
其次,在等待一本好教材很长时间之后,我自己写了一本(和吉姆·史密斯,一位来自英国的朋友兼同事)。我们的教科书现在可能是进化计算的教科书,在许多大学使用,最近,它已经被翻译成中文。
第三,我研究了基于生殖机制的基本问题。例如,我调查了如果我们有两个以上的父母会发生什么。在生物学中,我们知道两种繁殖方式:有性繁殖和无性繁殖。无性繁殖只包括突变,而有性繁殖需要双亲,被更高级的生命形式如智人和鱼类所使用。
作为一名数学家,我认为父母的数量只是一个繁殖参数。它不必限于两个,理论上,它可以是三个、四个或更多。我研究了如果更多的亲本繁殖,进化会发生什么,并证明了在交叉算子中有两个以上的亲本会加速进化。根据交叉算子的种类,最佳数量在 2 到 10 之间。
最后,也许是我最重要的贡献;我提倡主动对象的优化,而不是被动对象的优化。在经典的进化计算中,像旅行推销员的路线或工业对象的设计这样的对象会被优化。我开始优化与代理的事情。在那个领域中,我研究和进化活跃的人工制品、代理、有机体或模拟机器人。在某种程度上,这些都是相同类型的实体;他们有身体和大脑。两者兼而有之使它们更难进化,但研究起来也更有趣。
在我们深入细节之前,你能简单介绍一下吗?什么是进化计算?
它是一个有自己风格的搜索算法集合;进化的风格。这种风格采用了生物进化中的繁殖/变异和选择原则。
有人可能会说所有的搜索算法都有相同的属性,即:生成和测试。“生成”步骤相当于复制/变异,“测试”步骤用于选择。进化算法在搜索算法的大家庭中是独特的,因为它们使用解的群体和交叉作为搜索算子,组合两个或多个解。这是独一无二的,因为所有其他搜索方法只迭代一个解,应用扰动(突变)产生新的解。此外,群体中选择和繁殖的随机性是一个重要的特征。
总之,进化算法是基于群体的随机搜索方法。进化计算受进化原理的激励,搜索步骤可以使用搜索空间中更多的点来生成新点。我们并不完全模拟或仿效进化(碳基)机制,但我们使用进化原则。
进化计算是人工智能的一种形式吗?
绝对的。为了更进一步,粗略地说,人工智能可以分为符号/自上而下和子符号/自下而上的方法。在符号人工智能中,算法设计者在制定规则方面最为突出,而设计者在子符号方法方面则不那么突出。在 20 世纪,自上而下的方法是占主导地位的方法,而次符号方法在 21 世纪成为主导。通过子符号人工智能,算法可以根据预定义的方法找到解决方案。然而,产生输出的结果规则有时非常不透明和不可解释。进化计算是一种亚符号、自下而上的 21 世纪人工智能。
你的作品有很多应用;你最感兴趣的应用是什么?
所有这些都非常有趣,但它们的可见性可以区分一些比另一些。
请允许我先解释一件事;进化不一定是不受控制的。进化可以被人类监督和控制;我们称之为‘繁殖’。农民可以培育作物和动物等物种。从进化的两个主要操作,繁殖和选择,人类可以控制选择已经几千年了。例如,农民可以决定哪头公牛和母牛可以交配生小牛。影响进化的选择部分几代人是有效地引导进化走向理想的结果。
在这种背景下,我工作中最明显的应用是“机器人饲养场”,进化在人类的监督下进行。人类可以帮助、指导和加速进化过程,以达到期望的结果。如果有足够的资源(理解为资金),我们可以在五年内拥有机器人养殖场。这种养殖场将采用进化作为设计方法,在监督下运行许多代,一旦出现好的解决方案,就停止进化。这种方法不会取代传统的机器人设计方法,但它有一个补充通常应用的利基。
一个很好的应用例子是用于监测雨林的机器人。这个问题非常复杂,因为我们不知道哪种机器人最适合那种环境;机器人应该有轮子、腿还是两者都有?它应该小一点,以便偷偷穿过植被中的洞,还是应该大一点,以便它可以压倒障碍?通过经典工程方法设计的机器人只能在静态、可预测和结构化的环境中工作(例如仓库)。但是如果环境是复杂的,动态的,事先不知道,找到一个好的设计是非常困难的,进化是你的朋友。我对我的学生说:当事情变得艰难时,进化就开始了。
基于这个想法,我们可以使用机器人饲养场来获得设计良好的身体和大脑,并在我们的原型森林中良好地运行。在那之后,我们创造出许多最佳机器人的复制品,并把它们送出去监测真实的环境。这是我最喜欢的应用之一,因为我们可以很快地做到这一点,而且它与社会相关。
从长远来看,我们可能拥有不受人类直接监督的进化过程。这意味着一个不用手,几乎开放的进化过程。然而,这个过程引发了失控进化的伦理和安全问题。同时,这种方法具有非常有用的应用。例如,它可以用于空间研究。我们可以把一个进化机器人群体送到另一个星球,让他们做地球上的生物所做的事情。首先,它们需要进化并适应环境,以便长期生存和运作。一旦它们能够存活下来,它们就可以启动与人类相关的任务,比如建造房屋或让地球适合人类居住。这是一种不同于养殖场的方法,因为它不受指导和控制。
假设许多机器人被派出去执行一项任务。机器人如何在执行任务和寻找配偶之间做出选择?
分时系统是最符合逻辑的。例如,任务执行可以(几乎)是永久的,而交配可以是偶然的,可能由时间(例如交配季节)或事件(例如遇到另一个机器人)触发。
这些是实际的应用,还是一个关于可能性的假设性讨论?
这个育种场是一个实际应用,涉及到约克大学、布里斯托尔机器人实验室、爱丁堡纳皮尔大学和阿姆斯特丹自由大学之间的合作。我们的目标是开发能够清理核电站的机器人。这种有远见的项目通常是我们不会成功的。然而,我们学到了很多东西,知道如果我们再获得四年的资助,该如何让它发挥作用。
免提自主机器人的空间应用是未来的事,还需要 10 到 15 年。然而,这些应用不仅仅是钱和工程的问题。首先需要解决一些基本的技术、科学和伦理问题;怎样才能建立一个系统来运作,做我们想做的事,没有坏处?
你对哪些基本问题最感兴趣?
我最喜欢的两个是',智力是如何从非智力起点进化而来的?和‘在(进化的)智能行为背后,身体和大脑之间的相互作用是什么?前提是智力不仅在大脑中,也在身体中。我们所知道的所有现存的智慧形式都存在于一个身体中,我们不知道有任何不需要身体的智慧。这表明智力既需要大脑,也需要身体。更具体地说,行为总是由身体、大脑和环境决定的。
人类可以很好地在坚实的地面上用两条腿走路。但是如果你把它们放入水中,它们会下沉。如果身体没有改变,但是环境改变了,那么行为需要改变,例如,游泳而不是走路。从基础和实践的角度来看,这都很有趣。
例如,我们调查的一个有趣的问题是:‘什么对智能行为更重要;好的身体,还是好的大脑?“我们是如何通过进化得到这些的?”。回答这个问题有很多注意事项,因为答案可能取决于实验设置、给定的机器人设计和环境细节。然而,我已经量化了这个问题,通过实验回答了它,并与一名学生和一名同事在年度人工生命会议上发表了结果。在我们进化的机器人系统中,对于智能行为来说,身体比大脑更重要。
你的实验装置是什么?
我们设计了一个具有本质属性的系统;所有可能的身体和大脑可以组合成一个工作机器人,我们测量了每种组合的行为。简而言之,我们找到了一种技术解决方案,即使是鱼的大脑也可以放在人体上工作。
我们生成了 25 个身体和 25 个大脑,形成了 625 种排列在表格中的组合,并对每一种进行了评估。然后,我们查看了列的标准偏差和行的标准偏差。如果标准差较低,则该部分更重要。为了理解为什么,想象这些行是物体。在这种情况下,你会得到一个有 25 种不同大脑组合的身体,从而得到 25 个适应值。如果这些健康值在一个很小的范围内,你用什么大脑都没关系;你总是得到大致相同的情报。但是,如果你有一个更大的健身值传播,那么智力在更大程度上取决于大脑。
这就是我们如何将我们的天真问题量化为科学问题。公式化问题后,我们“只”需要运行模拟并填写身体-大脑矩阵。最后我们发现,在身体固定的情况下,价差总是更小。在这个系统中,身体对行为质量更具决定性。
对于这个问题,我感兴趣的不仅仅是工程学。我特别着迷于基本的,甚至是哲学的方面,身体和大脑之间的相互作用,以及它们如何通过进化同时发展。
所以,身体对智力最重要。然而,人类有一套固定的身体部位。父母的最佳数量大于两个。然而,人类只有双亲。人类陷入局部最优了吗?
不会,最优的父母数量也是由实用性决定的。更多的父母不太实际,需要更多的努力和运气来交配。
Evosphere 和机器人养殖场一样吗?
不,不一定;进化球是一个通用的概念,而养殖场是一个特定的亚型。在后者中,人类处于循环中,并在“机器人托儿所”中监督选择和婴儿学习过程。
与饲养场相反,Evosphere 还允许开放式机器人进化,无需人类直接监督。Evosphere 是一个通用的系统架构,由三个组件组成。第一个是机器人制造商或“生育诊所”,生产机器人后代。从进化的角度来说,一个基因型(机器人的 DNA)被转换成一个表现型,一个真正的机器人。第二个是训练中心或“托儿所”,是“新生”机器人学习最佳身体控制的地方。这个阶段被称为“婴儿时期”。在此期间,机器人学习新技能,不能生育。在婴儿时期之后,机器人变得有生育能力,并进入“竞技场”,在那里它们操作和生产孩子。这是一个通用的系统架构,适用于所有机器人进化系统,不管细节是如何实现的。
你更喜欢使用 Evosphere 的哪个组件?
在过去的几年里,我对婴儿期更感兴趣,也更有挑战性,婴儿期类似于机器学习,但也完全不同。解释这种差异的最佳方式是将“机器学习”一词颠倒为“学习机器”。这里的意思是,对于“学习机器”,你是在讨论能够学习的机器,无论是模拟的还是物理的。值得注意的是,学习机通过执行动作来生成其训练数据,而在机器学习中,用户向算法提供预定义的训练数据集。
在我的研究背景下,学习机器形成了一个很大的挑战;每个新机器人都有不同的身体(例如,更多的腿,更少的轮子,不同的传感器,相机在另一边),需要依赖于身体的控制器。因此,每个机器人代表一个新的学习问题:如何最佳地控制给定的身体,并确保机器人能够操作,例如行走、执行任务、生存和繁殖。
人类婴儿花一年时间学习走路和抓握物体。进化型机器人也必须在出生后迅速发展他们的“手眼协调能力”。机器人的问题更具挑战性,因为人类婴儿的身体总是和他们的父母一样(例如两只手,每只手上有五个手指)。相比之下,机器人后代可以拥有与父母完全不同的身体。我们正在使用机器学习中的一些学习技术,如强化学习和神经网络。因此,尽管许多机器学习算法有潜在的帮助,但我们事先对机器人的形态(身体规划)一无所知,也无法做出任何假设。因此,我们需要在我们的设计空间中对所有可能的机器人都有效的学习方法。进化产生的每一个新机器人都相当于传统机器学习中的一个新数据集。
这个学习问题只是真正大挑战的敲门砖;发现进化和学习是如何相互影响的。这个问题已经讨论了一百多年,产生于生物学界。他们发明了像、或鲍德温效应这样的概念,早期的人工智能社区开始采用。四十年前的论文研究了在我现在称之为人工生命系统的环境中学习和进化的结合。这对进化中的机器人来说是一个突出的问题,因为婴儿期的学习是必不可少的。这就把进化和学习之间相互作用的理论问题变成了一个实际问题:如何将机器人的进化和学习结合起来,以最大限度地提高效率和效能?
最终,我对进化和学习在一个系统中的结合感兴趣;这将是实现人工智能新水平的重要途径。我相信未来的人工智能将由自主过程产生,而不是由人类开发人员编码解决方案。我把这种现象叫做‘二阶工程’或者‘二阶发展’。开发人工智能系统(机器人或其他)的标准方法是基于开发人员分析问题,进行文献搜索,并设计和实现目标系统。这是典型的‘一阶工程’。用二阶工程,我们开发一个进化系统,它为我们开发一个解决方案,而不是我们直接构建一个 AI 或机器人系统。我深信,二阶工程在未来的人工智能中将变得更加突出。
人类在二阶工程中的作用是什么?
人类应该指定进化系统的组成部分。例如,定义基因型中使用的遗传语言,指定适当的变异和交叉算子,制定适应度函数,并确定繁殖条件。如果应用了学习,那么也需要定义学习方法。
这里有两个关键问题:样品效率和安全性。生物进化是非常浪费的。它创造了许多解决方案,其中大部分在变得肥沃之前就夭折了。人工进化系统不能太浪费,因为时间尺度是几周或几个月,而不是几百万年。此外,我们需要确保在真实世界中生产真实机器人的固有随机和自适应系统的安全性。显而易见的危险是失控的进化和不必要的或危险的机器人属性的出现。安全和道德至关重要。然而,我们对这些问题知之甚少,因为我们才刚刚开始了解它们。然而,我们需要从一开始就意识到道德和安全问题。
在早期的媒体采访中,你讨论了集中复制。这是你提议的一种安全措施吗?
是的,因为它有助于防止进化失控。我的解决方案是拒绝分布式生殖系统,如产卵、怀孕或细胞分裂,因为这些生殖系统将允许机器人在任何地方以任何方式繁殖,而没有阻止它们的选项。相反,我坚持认为,我们只能建立一个用于机器人(再)生产的集中单元的进化系统,这是 EvoSphere 的第一个组成部分。该装置用作安全开关;一旦关闭,繁殖就停止了,不会再有机器人后代。现有的机器人可能不会立即‘死亡’,但至少它们不会进一步繁殖。
自主机器人的适应度函数是如何定义的?
研究团体的标准方法是有一个任务,并且将适应性等同于任务性能(例如,对于应该很快的机器人;快机器人会生很多孩子,慢机器人不会)。这保证了进化会创造出擅长完成这项任务的机器人。我试图推动研究界走得更远,做更复杂的有实际意义的任务,同时考虑多项任务。为了生存,机器人需要擅长许多任务。
让我们假设我们正在发送一个机器人殖民地到一个遥远的星球。有多项任务要执行。你如何定义适应度函数?
这里要区分技能和任务。完成复杂任务所需的可组合的基本技能相对较少,不到 10 项。采取运动;机器人必须行走。然后,运动应该是目标;机器人应该学会如何移动到特定的目标并避开障碍物。随后,机器人需要学习操纵物体。这套基本技能可以用作垫脚石,这样机器人也可以执行更复杂的任务。机器人将在“机器人学校”学习这些技能,使他们能够执行更复杂的任务。
让我们把重点放在事物的进化和二阶工程上。你能想象机器人会发展出意识、道德或情感来执行任务的场景吗?
让我先给“事物的进化”下定义。之前,我描述了从湿件到软件,从软件到硬件的转变。同样,这样的序列也可能与进化有关:从生命体的进化到代码的进化(进化计算),再到事物的进化(机器人)。
关于意识的问题很难回答;它更具有根本性和哲理性。我不能说他们是否会或可能有意识。下面的类比是简单的解决方法:如果它走路像鸭子,看起来像鸭子,叫起来像鸭子,那么它很可能是一只鸭子。如果机器人的行为符合我们的道德标准,我们可以称它们为道德机器人,不管驱动这种行为的机制是什么。道德行为是可设计的和可取的;他们需要遵守我们的标准。
但是这也可能是进化过程的结果吗?
有进化或任何其他适应性的、突现的过程在起作用并不意味着我们不能控制它。我们必须发展技术和科学来控制这些突发过程,并确保它们尊重我们的约束,我们可以称之为道德或伦理边界。然而,设置这样的约束归结为自底向上、子符号人工智能中最大的问题之一;如何在不禁用进化过程的情况下限制它们?因此,如何将进化保持在我们的伦理边界内,而不过度“限制”它们的行为。我没有答案,只能强调需要进一步关注。
假设你有一个机器人,可以在两个机器人中选择繁殖后代。这两个机器人在功能上是一样的。机器人基于美学做出决定,这种说法可信吗?
基于我们基于工程的认知,我们倾向于根据功能性和实用性来选择机器人。但是生活不是那样的。你提出的想法很好,我们正在研究。这种方法不同于通常的进化算法。首先,选择不是集中进行的,而几乎所有的人工进化系统都有一个集中的协议,“经理”(技术上来说是主要的进化循环),来决定哪些机器人与哪些其他机器人交配。该决定基于每个群体成员的完整信息。这是算法学家想要的属性,但不是人工生命社区。因此,第一个变化是使机器人能够自己选择交配对象。其次,择偶标准应该改变。目前,两个机器人可以相遇,并纯粹基于效用(任务表现)决定是否想要一个“宝宝”。在新的方法中,我们用另一个与机器人形态相关的标准来扩展或取代这个标准——美,如果你愿意的话。通常,效用与行为相关联;‘告诉我你在森林里采集了多少土壤样本,我就告诉你我要不要和你生个孩子’。或者,您可以将其更改为;‘我看着你,我会告诉你我是否想和你生个孩子’。所以,是的,基于审美的选择是可能的,非常令人兴奋,我们刚刚开始研究它。
这种基于美学的方法对工程师也有意思吗,还是主要对人工生命的人有意思?
对于工程师来说,这没什么意思,因为他们是以实用为导向的。它主要对人工生命、理论生物学或哲学感兴趣。一个有趣的问题是:如果你有形态驱动的选择,你会得到什么样的身体/形态?孔雀是我脑海中的一个典型例子。孔雀有奇异的形态特征;它们巨大的尾巴。虽然尾巴很漂亮,但是它们完全没有用,甚至很危险。尾巴使孔雀更容易被捕食者捕获,并且它们需要孔雀吃更多的食物。然而,这种形态特征严重影响了孔雀是否会繁殖。我很好奇我们是否会在机器人系统中看到这种现象。如果我们的进化机制捕捉到了基本属性,我们就可以创造一个人工进化系统,它具有与碳基进化相同的吸引子。碳基进化经历了数百万年的发展,非常复杂。人工进化仅仅发展了几十年,而且远没有那么复杂,所以这种可能性并不是板上钉钉的事。
然而,它是极其令人兴奋的;发现这样的效应表明我们理解了进化系统的本质。不管我们能捕捉到的基质是什么,进化本身就有一些基本的东西。这也将暗示其他星球上的生命。如果所有的进化系统都是相似的,那么其他星球上的进化也可能是相似的。
你说,随着人工智能改变了我们对智能的看法,人工生命很可能也会改变我们对生命的看法。你认为人工生命会给我们的生活带来怎样的改变?
生命的概念将不再局限于碳基生命,这是我们目前知道的唯一一种生命。如果许多科学家同意进化的机器人系统构成了生命,那将承认生命可以有不同的基础。其他生命形式可以是数字化的、机电一体化的,或者基于具有新的驱动和传感形式的新材料。这意味着判断一个东西是否有生命的标准会发生变化;他们需要更多地关注功能,而不是“具体化”或实例化。一个更宽泛的生命定义将使对生命的研究更具普遍性。作为一名科学家,你不希望只根据一个样本就得出结论。然而,目前我们只有一个生命样本。更多的样本会带来更好的结论,也能更好地洞察生命的意义。
为此,重要的是我们所知的生命是适度可观察的,难以控制的,并且不是真正可编程的,这使得实验研究变得困难。但是机器人和人造生物是可观察、可控制和可编程的。例如,可以通过注册 wifi 信号来检索机器人通信,内部进程可以记录在机器人内部的黑匣子中。原则上,这可以涵盖一切:所有的感官输入,机器人大脑中的所有信息处理,所有的控制命令,电池电量,等等。这种数据可以离线存储和分析,或者在控制回路中使用,以在线方式在系统运行期间探测系统。这为我们研究和理解生命和智能提供了一套扩展的工具。
最终,进化机器人系统代表了一种全新的研究工具,可以帮助理解智能的出现。这里关键的未决问题是:‘智慧是如何出现的?’时至今日,甚至连最简单的答案都没有。比如获取智力的过程是线性的、阶梯式的,还是曲棍球棒曲线?进化中的人工生命系统允许我们研究这些问题,这将是我们所知的人工智能的丰富。
采访到此结束,艾本教授。你有什么遗言吗?
突现智能和二阶工程有非常重大的风险。在开发此类系统时,必须从一开始就彻底解决这些风险。如果我们只是在它们发生时才试图减轻它们,那就太晚了。
- 基因操作发明后,直接干预生殖成为可能。这在伦理上有争议,但在技术上是可能的。
这次采访是代表比荷卢经济联盟人工智能协会进行的。我们汇集了来自比利时、荷兰和卢森堡的人工智能研究人员。
机器人公司 2.0:横向模块化
原文:https://towardsdatascience.com/robotic-companies-2-0-horizontal-modularity-4a920fa34c9?source=collection_archive---------46-----------------------
如何表现为一个数字平台而不是制造商,将是下一代机器人公司的最佳选择
过去十年,数据和深度学习一直在改变世界。大多数机器人公司还没有进入数据革命,机器人技术的主流愿景还远未实现。机器人公司的现状不会实现机器人在任何场景下帮助我们完成任何任务的梦想(或至少试图取得某种程度的成功),但它将创造出一些解决一个问题的昂贵玩具(提示,我们已经有 已经有一些)。
如今最受欢迎的机器人初创公司是波士顿动力公司、特斯拉汽车公司,甚至可能是 SpaceX。所有这些公司都在竞争前年垂直整合一种具有最佳自主性的产品,以创造出极具价值的产品。最终,竞争会赶上来,我感兴趣的是在一项任务中获得 90%或 99%相同能力,但同时解决多种类似问题的新公司。通过在物理上不同的平台上查看试探性地相同的问题陈述(避免崩溃,定位对象),可以同时解决其他问题。
我对成功的机器人公司的下一个时代的看法是水平模块化,其中跨系统的数据共享使得能够使用新的技术集,并消除了多次解决同一类问题的需要。
在这篇文章中,我强调了我如何看待机器人开发中的两个大玩家: Boston Dynamics 和 Covariant.ai (自我报告偏差,因为这是伯克利分校的副产品)及其未来。未来几年将会有更多的例子可供借鉴。

照片由 Ann H 从 Pexels 拍摄。
首先,在讲述我们如何从垂直硬件优化转向水平模块化机器人平台之前,先了解一下这些公司及其开发流程的背景。
波士顿动力公司
Boston Dynamics 通过最大化特定硬件组件的性能,在移动性的狭窄终端产生了惊人的工作(计划很快就他们和他们使用的系统发表一篇文章),但它不是为通用性和可扩展性而建立的。他们让工程师研究每一个子问题,以获得更高的可靠性。从入门读物来看,Boston Dynamics 利用非常精确的模拟器和机器人模型,通过流行的最优控制变量(如模型预测控制)来计算最佳动作。这种方法过度专注于他们的平台,没有简单的将权重或模块转移到新问题的方法(一些来源:波士顿动力公司在真实世界 RL 研讨会上讨论了他们的 MPC和来自 IEEE 的体面总结)。
协变. ai
与此同时,协变专注于收集正确的数据,以解决一类问题,例如机器人对拾取和放置的感知。在一次采访中,联合创始人 Pieter Abbeel 非常肯定地说他们的开发过程是(凭记忆回忆):
我们把我们能想到的一切都扔给了实验室里的机器人。
从数据而非控制的角度来看,这听起来像是一种极限开发。一个例子是,我们如何解决机器人的感知问题,使它能够看到和操纵半透明的物体。如果感知堆栈可以看到并识别半透明物体在空间中的位置,这些知识就可以用于操纵和移动。在数据驱动的感知机制之外,协变并不试图重新发明轮子,而是使用 PID、LQR、MPC 等控制中屡试不爽的方法。
从垂直转向水平机器人开发
我们从机器人在过去是如何发展的开始。这可以被描述为硬件和软件之间的专业舞蹈。最好的机器人专家对他们有一种文艺复兴时期的感觉,在小团队中,他们会连续迭代和优化系统。这里的限制因素是时间、专业知识和资源。

机器人迭代优化,速度慢。
为了了解行业如何超越这种方法,我们需要理解机器人系统是由重叠的原语集组成的。
机器人原型
每个机器人都需要具备某些技能才能作为产品存在。每个机器人都需要:与世界互动(操纵、移动等)并看到世界,这通常被称为感知。运动和控制可以使用许多不同的模块,包括不同的执行器和不同的算法来决定和规划。感知使用许多不同的形式,类似于不同的感觉。
如果我们放大多个机器人公司汇聚的地方,它们有许多不同的能力,并且几乎总是与相关系统有一些重叠。在相似类型的数据和动作中利用这些水平连接是机会所在。

一些机器人系统如何在模块中重叠的可视化。
当然,我不会说这很容易做到:将另一个项目的数据插入到您自己的项目中,反之亦然,通常会导致两者都不工作。利用等级制度是有希望的。
层级和模块化
[分级控制](https://en.wikipedia.org/wiki/Hierarchical_control_system#:~:text=A hierarchical control system (HCS,form of networked control system.)和分级学习是在系统中显式或自动创建抽象以改善其行为的领域。拥有一个动态的层级结构对这一愿景的发展至关重要。如果系统的各个部分不能相互分离,机器人使用来自多个一流供应商的解决方案的希望就很小(幸运的是,正在成为下一代机器人专家的计算机科学家确实最擅长抽象)。
最佳层级的效果是机器人不可知论,一些研究表明,数据和方法可以在经过集中训练的独立机器人上工作。您可以查看这两篇论文以了解更多信息(这两篇论文都非常受欢迎,我非常倾向于继续这一研究方向):通过分层集成模型进行多机器人深度强化学习或 Sim-to-(Multi)-Real:将低级鲁棒控制策略转移到多个四旋翼飞行器。随着许多机器人专家被困在他们的机器人之外,共享数据的能力变得越来越迫切,而不仅仅是有趣。
数据和缩放
回到开头,我是这样看待我重点提到的两家公司的:

比较垂直和水平。波士顿动力公司和协变公司在方法上采取不同的方向。
随着机器人种类的减少和少量机器人将数据传输到云端,这种方式的影响会更小。然而,有一个明显的趋势是增加在线设备的数量,当许多系统试图解决许多场景时,协变开始看起来像一个完全不同的命题。

横向模块化的终极游戏和关键收获。横向是 Covarint,纵向是 Boston Dynamics。
这并不是说协变将解决感知和控制堆栈中的所有问题,而是说,通过成为其中一个问题的最佳解决方案,它们的影响和价值将会聚合。
加倍努力,这种方法可以让新的机器人公司更快地发展和部署。例如,一家公司需要解决一个新的执行器和场景(总是有新的机器人应用程序,只是有时没有足够的创造力),可以使用其他公司的 API 等感知和控制堆栈的可插拔部分。新玩家不需要收集大量数据来在他们的新环境中使用 vision,这将有助于改善他们为任何组件购买的播放器。该公司需要解决以前缺失的子组件,而不是从头构建一个全新的系统。
水平的模块化公司将获得大部分价值(数字媒体总是如此),但快速发展的新垂直公司将迅速部署,并带回机器人令人兴奋的未来:我们可以制造任何东西来解决你的问题。
我已经花了很多时间来建立一个新的网站,这将是我关于机器学习和更广泛的生活的许多知识和思想的家园。正是这里。
如果你想支持这个:喜欢,评论,或者伸出!这第一次出现在我的子堆栈上。
**https://robotic.substack.com/ 
现在为博客的“漂亮部分”寻找外部照片。谢谢爸爸。**
机器人服务员,请给我账单!
原文:https://towardsdatascience.com/robotic-waiter-my-bill-please-7a4988f572b7?source=collection_archive---------40-----------------------
人工智能对餐饮服务业的影响

照片由 Lefteris kallergis 在 Unsplash 拍摄
在发达国家似乎有一种趋势,公民更喜欢白领职位,而不是体力密集型工作。原因是多方面的;这类人渴望更高的工资,在舒适的环境中工作,提高自己的社会地位。虽然这些选择是可以理解的,但这种情况造成了全国就业供应的缺口,从而对依赖这些工人的行业产生了负面影响。受到严重影响的一个部门是食品服务业。在对旅游业依赖程度相对较高的国家,这个问题更加突出。在某些情况下,这些国家甚至不得不从国外引进工人来维持该部门的需求。但是当这个问题正在酝酿的时候,一些组织提出了一个新的想法,用机器人代替人类工人。
有些人觉得这很荒谬。这确实涉及到资本成本,因为机器人并不便宜,但我们不要忘记,机器人不会累,不需要假期,没有报酬,而且它们做的事情相当精确。但在现实中,如果我们不得不这样做,会带来什么?
当我们提到机器人时,我们的脑海中往往会浮现出著名的好莱坞电影,在电影中,人形的数字生物会满足我们的每一个要求。这种机器人是存在的。现代公司波士顿动力公司创造了世界上最先进的机器人。他们可以像我们一样走路,像袋鼠一样跳跃,像猎豹一样奔跑,像大象一样负重。当然,如果我们让这些机器人为一家餐厅服务,这将是一种过度的杀戮,除了它会塞住你口袋里的一个洞,这个洞有几百万欧元深。但是机器人只不过是一个隐藏着人工智能(AI)程序的外壳,人工智能程序本质上完成了大部分魔法。它可以分析形势,自主决策并采取具体行动。

照片由克里斯·斯皮格尔在 Unsplash 上拍摄
人工智能程序仍然可以做许多事情,而不需要人形机器人的外壳。让我举几个例子:
- 它可以轻松地从任何渠道全天候接受预订,无论是通过社交媒体还是传统电话。
- 人工智能对预订进行分析,预测需求并建议需要购买的物品。这样的过程有助于减少浪费,并有助于厨师的计划。
- 当顾客到达餐厅时,一个电子主持人会迎接他们,并把他们带到他们的餐桌。
- 一旦他们坐下,一个位于他们桌子顶部屏幕上的聊天机器人会向他们打招呼。然后,它会突出显示每日特色菜,并帮助他们下单,同时注意任何特定的饮食要求。提供的可能性是多种多样的。顾客不再局限于菜单中的项目,而是可以按照成分(以防过敏)甚至热量值进行分类,从而帮助他们做出明智的决定。
- 当厨师准备订单时,顾客可以用个性化的灯光、视觉效果或音乐定制他们餐桌的氛围,这只会影响他们的空间。这种定制也可以在他们预订时提供,从而确保他们到达时发现这个地方已经准备好了。他们还可以选择多种娱乐形式,如预先录制的乐队,甚至现场足球比赛。
- 食物一准备好,自动推车就把盘子拿到顾客面前。这样的系统已经在许多地方运行。其中一个叫“Aglio Kim”,他的工作是为韩国的餐馆服务。它可以携带最大 30 公斤,同时为四张桌子服务。由于 Aglio Kim 的数字大脑包含餐厅地图,它可以在避开障碍的同时导航餐厅。手推车还可以说英语,与客户的互动有限。
- 在用餐快结束时,顾客要求位于他们桌子上的聊天机器人付款,他们使用非接触式卡转账。
- 该系统还可以提供额外的服务,如出售附近景点的门票或他们可以在饭后观看的表演。它也可以召唤出租车送他们回家。可能性实际上是无限的。
从上面的例子可以看出,我们不是在谈论火箭科学,这些解决方案也不再局限于好莱坞电影。技术就在这里,任何人都可以使用。甚至不需要财大气粗。即使一个人仍然不确定,为什么不尝试其中之一,而不是去寻找一个成熟的人工智能系统。在大多数情况下,这些系统投资回报快,从而帮助餐馆业主投资于更全面的解决方案,从而节省大量资金。多年来,我们一直试图用同样的心态来解决我们的问题。现在是大胆创新、跳出框框思考、利用现有技术并从今天开始从中受益的时候了。
如果你喜欢这篇文章并想联系我,请通过 🖊️Medium 、联系我🐦推特,🔗领英,📷Instagram ,😊脸书还是🌐网站
阿列克谢丁立教授 是马耳他大学的艾教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他出版了几本同行评审的出版物,并成为马耳他的一部分。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。
机器学习时代的稳健决策
原文:https://towardsdatascience.com/robust-decision-making-in-the-era-of-machine-learning-2dc43fd571a6?source=collection_archive---------12-----------------------
公平和偏见
我们如何确保 ML 避免人类决策中的陷阱
(与约瑟夫·莫里斯合著@LLNL。)
过去十年中最重要的技术进步之一是机器学习(ML)[1]的成熟和广泛采用。许多过去由传统的以算法为中心的编程难以完成的任务突然变得触手可及。大多数此类任务的核心是根据提供给决策者的信息做出决策。例如,决定走哪一步棋是决策;驾驶或刹车是一个决策过程;从 CT 图像诊断癌症是决策;评估在不引起地震的情况下,我们可以向地下注入多少废水或二氧化碳也是一个决策过程。决策者曾经要么是一个人,要么是一群人;现在它可以是一个使用 ML 和传统算法编程的不同组合的人工智能(AI)。

(照片由 iStock 授权)
如何最大化机器学习对我们社会的好处,不仅仅是一个计算机科学的问题。人工智能可以变得越来越聪明,但历史告诉我们,聪明的实体可能会做出愚蠢、不道德甚至灾难性的决定。一旦人们对基于多元智能或多元智能增强决策的潜力有了初步了解,相关的伦理和法律含义就成了讨论的重要话题[2,3]。一个奇怪的观察是,大多数利益相关者似乎没有认识到决策研究本身是心理学和认知科学中一个卓有成效的研究领域。将 ML 置于认知科学的框架中使我们能够理解它的力量和局限性,从而使我们能够以更聪明和更安全的方式利用 ML。
对两个认知过程的理解,在卡尼曼的书思考快与慢【4】中被命名为系统 1 和系统 2,可以揭示人工智能在决策中的许多作用。系统 1 是大脑自动的、很大程度上无意识的思维模式。经过充分的训练,系统 1 " 执行熟练的反应并产生熟练的直觉 " [4]。系统 1 负责我们大部分的日常决策。它需要很少的精力或注意力,但往往容易产生偏见。系统 2 缓慢、费力,并受分析推理的支配。考虑所有的选择需要努力和注意力。大多数时候,系统 2 认可系统 1 产生的连贯的,或者至少看起来连贯的故事。当系统 1 挣扎时,系统 2 被调用来进行更努力的推理。
一个简单的、有启发性的事实是,大多数 ML 方法模拟人类系统 1 的操作。卷积神经网络的训练非常类似于人类系统 1 的训练,直观术语“训练”生动地证明了这一点。ML 通过训练建立“经验”关联。当给定类似于训练场景的应用场景时,ML 以一种快速的、看起来毫不费力的方式产生结果。如果培训材料没有涵盖应用场景,或者培训不充分,那么当前的 ML 方法将举步维艰。ML 和人类系统 1 之间的这种相似性提供了许多基于从人类决策科学中学习的有用见解。
一个强大的系统 2 需要与 m1 协同工作。在人类决策中,当懒惰的系统 2 因为被系统 1 创造的明显连贯的画面所愚弄而未能干预时,我们往往会犯错误。因此,指望曼梯·里独自做所有的决定是愚蠢的。如果在决策中使用 ML,则检测困难或危险情况并随后触发系统 2 干预的能力应该是强制性的。提到一个在基于 ML 的决策中有意识地包括系统 2 组件的例子是有用的:当前汽车中的自动驾驶系统要求人类驾驶员将手放在方向盘上并准备干预。这个例子中一个有趣的事实是,这里的系统 2 很可能是驾驶员的系统 1 和系统 2 的组合,但作为一个整体,它在这个决策(即驾驶)过程中扮演系统 2 的角色。
多元化带来稳健的决策。在人类社会中,重要的决策通常都是经过严格的辩论做出的。当放射科医师阅读 CT 图像时,他/她首先依赖于他/她的系统 1。这种判断通常很快,不需要很大的精神努力,但这种系统 1 只是通过多年的训练才获得这种能力。当放射科医师的系统 1 检测到异常时,系统 2 被调用来进行调查。很多时候会咨询一群不同专业的医生的意见。在这里,多样性是实现可靠诊断的关键。当人工智能取代放射科医生时,我们可以有多个人工智能,它们可以基于不同的数学原理,用不同的数据进行训练,共同完成这项工作。幸运的是,雇佣多个人工智能的成本会更低,因为有一组医生来检查彼此的工作。以这种方式,在过去由单个人系统 1 处理的事情中引入了多样性。
视觉化比以往任何时候都更重要。历史上,可视化一直是算法驱动的决策制定工作流的主要组成部分。人类系统 1 严重依赖视觉输入;因此,卡尼曼创造了“所见即所得”这个表达方式。既然 ML 可以直接“看到”比特,那么可视化还有必要吗?根据上面的讨论,我们看到人类不能完全脱离决策过程。人类评审员、检查员和专家小组仍然是决策制定中“系统 2”不可或缺的部分。因此,鉴于可视化是与人类联系的最直接的方式,可视化的质量直接决定了系统 2 在防止错误和偏见方面的有效性;有效和引人注目的可视化变得比以往任何时候都更重要,以允许人类为决策过程提供及时的输入。
心理学关于决策的研究有一个深刻的发现,那就是大多数人的决策都是不理性的,尽管我们坚信自己是理性的。重要的是要认识到,使用最大似然法来部分取代人类系统 1 并不会使决策制定更加合理。虽然表面上人们倾向于相信机器比人更理性,但基于人工智能的人工智能具有人类系统 1 的所有缺点。无论人工智能变得多么先进,这一点都不会改变。从根本上说,它们的工作方式是一样的。承认局限性是避免陷阱的第一步。更好的未来在于对决策是如何制定的、错误是如何产生的、ML 的局限性以及如何有效地将人类纳入决策过程的充分理解。
(本文由美国能源部的 SMART 倡议支持。)
参考:
1.M.I. Jordan,T.M. Mitchell,《机器学习:趋势、观点和前景》。科学:349:6345,255–260。DOI:10.1126/science . AAA 8415(2015)。
2.C. Coglianese,D. Lehr,“机器人监管:机器学习时代的行政决策”宾夕法尼亚大学法学院教师奖学金,1734 年。https://scholarship.law.upenn.edu/faculty_scholarship/1734。(2017)
3.E. Vayena,A. Blasimme A,I.G. Cohen,。医学中的机器学习:应对伦理挑战。 PLoS Med 。15(11):e1002689。DOI:10.1371/journal . pmed . 1002689。
4.d .卡尼曼,思考,快与慢(法勒,斯特劳斯和吉鲁;2011 年第一版)。
稳健实验设计
原文:https://towardsdatascience.com/robust-experiment-design-244f835c6874?source=collection_archive---------6-----------------------
行业笔记
实验很容易,对吗?本文将实验设计中的常见陷阱与 t 检验背后的基本统计假设联系起来。
想象一下,你将一小部分用户分成两组。一组人享受新的功能,另一组人则没有。您观察到变体组中某个用户的平均收入更高,这似乎具有统计学意义:因此该功能很好,让我们推出它吧!瞧,实验很容易。嗯,也许…

由亚历克斯·康德拉蒂耶夫在 Unsplash 上拍摄的照片
顺便说一下,实验应该很容易:这是强大的因果推理的作弊代码。但是,如果没有给予应有的关心和重视,就会得出错误的结论。花点时间让你的实验变得强大,对你的公司来说,这是做出正确或错误决定的关键。
以下是实验背后的一些重要提示,将实验与基本原则联系起来,以帮助确保你的结论是可靠的。
根据基本原则评估你的实验设计
在我们的实验中,我们收集了一些小样本,希望它们能反映我们想要比较的两个平行宇宙(比如一个宇宙引入了某个特性,另一个宇宙没有引入)。因此,实验设计的目的是将测试组和对照组之间的差异归结为两件事:
- 您的新特性 X 带来的真正差异
- 抽样误差(因为我们只收集了一小部分样本:我们将很快讨论这个问题)
实验经常使用 t 检验。t 检验估计变异组的平均值可能来自与对照组的平均值相同的抽样分布的概率。换句话说,我们正在测试零假设,即对照均值和变异均值之间没有差异(即使有一些差异,也只是由于收集中的噪声)。
如果测试一个测试组和控制组之间的平均度量的差异,并且每个组有超过 30 个样本,那么韦尔奇的 t-test 很可能是您选择的测试。
确保 Welch 测试背后的假设得到满足将有助于将组之间的任何测量差异分离到这两个因素。为了实现这一点,在收集样本时需要考虑两个关键假设:
- 组间抽样的独立性
- 组内抽样的独立性和同分布(iid)

纳赛尔·塔米米在 Unsplash 上的照片
那么什么是群体间的独立性,我为什么要关心?
网络效应
侵犯两个群体之间的独立性可能意味着一个群体的结果也会影响另一个群体。举一个社交媒体平台的例子:你向你的变体组中的用户发布了一个新的分享功能,而控制组看不到它。您的变体组中的用户使用新的共享功能,并且比他们使用旧功能更频繁。这增加了他们的平均参与度(目前看起来不错!).但你的控制组中的用户看不到这些新的共享,事实上他们现在看到的比以前少,这反过来意味着他们与内容的互动比他们原本应该的少。这降低了他们的平均参与度:组间的差异被过分夸大了。这是违反独立性假设的网络效应的一个例子。类似地,如果用户可以看到两个版本,在用户级别而不是访问级别将样本分配给组可以确保组之间没有效果的交叉污染。
可观察的混杂因素
混杂变量是影响样本分配到试验组或对照组以及感兴趣的指标的因素。因此,违反独立性可能意味着收集的样本可能不会受到相同潜在因素的同等影响。例如,我们为你的网站运行一个新的颜色主题的实验,测量新用户注册率:控制组样本在周一到周三收集,而变体样本在周四到周六收集。但是用户更有可能在周末加入,所以在其他条件相同的情况下,我们预计周六的用户数量会更多。每个组的用户分配并不独立于一周中的某一天。同时进行实验有助于解决这个问题,所以这是一个简单的解决办法…
隐藏的混杂因素!
但现在让我们说,巧合的是,在你的变体组中有更多的色盲者:这是影响你的度量的一个因素,但你没有收集关于它的数据——那么你如何防止这干扰你的测量?随机化是你的朋友。将您的用户群随机分配到测试组和控制组(有足够的样本量)有助于平衡您没有收集数据的特性。这也有助于确保您的样本也能代表您的人群。确切地说,随机化不会保证组间的平均分布,只是趋向于平均分布:但是无论如何在测试时,不平均分布的可能性应该被考虑到 p 值中。
那么什么是群体内部的身份识别,我为什么要关心?
检查指标的稳定性
独立性确保一个样本的收集不会影响另一个样本的收集。相同分布也意味着样本所采集的分布充分模拟了我们希望它所代表的总体。换句话说,这意味着没有潜在趋势影响我们观察的样本:如果样本的收集影响总体,那么就没有“真实”值(它随着样本的收集而变化)。相反,我们应该期待指标在收集时趋向真实平均值(根据大数定律),而不是趋势向上或向下,或者其方差随时间变化(这意味着指标不是静止的)。然而,数据的“外部知识”很可能是决定数据是否是身份识别数据所必需的
但是为什么这有帮助呢?
如果满足独立性和同分布的假设,那么(假设样本量足够大)我们可以确信每个样本的均值服从近似正态分布:均值趋向于总体均值,方差与样本量有关。简而言之,这是中心极限定理(CLT)最常见的版本。

照片由 Unsplash 上的水晶贴图拍摄
为了说明这一点:想象投掷一枚公平的硬币。每次抛硬币都不会影响下一次(独立性),使用相同的硬币可以确保正面的概率保持不变(相同的分布)。如果你把硬币抛 10 次,记录下人头的数量,你可能会得到 5。但实际上,你只有 25%的机会得到 5 分!这是抽样误差:尽管真实概率是 50%,但你更有可能在只翻转 10 次时得不到 5 个头。例如,有大约 38%的机会你得到四个或更少。
现在想象一个热心的抛硬币者重复了这个测试——但是他们做了 100 次。现在他们观察到 40 个头的概率只有~3%。相比之下,当我们只做了 10 次翻转时,观察到 4 次翻转或更少是 38%!这表明我们采集的样本越多,我们对结果就越有信心。。标准误差是对这些平均值的标准偏差的测量,随着收集的样本越来越多,标准误差也越来越小:

标准误差,即样本平均值的估计标准偏差,随着样本量的增加而减小
现在想象一个完全古怪的抛硬币者重复 100 次抛硬币实验数千次,记录下每次抛硬币的平均头数。他们不仅会发现每个程序的平均头数为 50,而且这些程序平均值的分布将遵循近似正态分布,约 68%(这些平均值的一个标准偏差)的程序具有 45-55 个头,约 95%(两个标准偏差)的程序具有 40-60 个头。CLT 的意思是,即使抛硬币的基本分布是二项式的(观察人头是二进制的,零或一),人头平均数的分布是正态的。
因为 CLT 确保平均值的分布是正态的,这意味着我们可以估计抽样误差方差(标准误差),我们可以开始确定我们在变异样本中观察到的平均值是从与对照样本相同的分布中产生的可能性。如果这个概率足够低,我们确定两组之间有统计学上的显著差异。批判性地思考是否满足独立性和同分布的假设,从而有助于确保这些测试的结论是稳健的。
参考消息——这些古怪的实验者是“常客”统计学家。重复这个过程很多很多次,最终会给你正确的答案(旁注:这也是考虑置信区间的正确方式:它们与概率无关,因为真实均值要么落在估计的置信区间内,要么不在;但是,如果您多次重复样本收集和“置信区间估计”过程,95%的 ci 将包含真实值)。

庞余浩在上拍照
还有一点需要注意:作为测试的一部分,我们需要从我们收集的较小样本中估计总体均值的真实均值和标准差。这也只有在所收集的基础样本是独立且同分布的(样本量足够大)时才有效。
将这些联系在一起:统计能力
假设存在真正的差异,检验的统计功效是我们检测到两组之间有统计学显著差异的概率。
假设我们有两个硬币,我们想确定它们翻转头部的概率是否有差异。所以我们把每个翻转 100 次。从这些样本中,我们估计真实总体的平均值为 X1 和 X2。我们将标准误差(这些平均值的标准偏差)估计为样本的标准偏差除以样本大小的平方根。
在这种情况下,Welch t-test 统计量按以下方式指定:

检验统计量的绝对值越大,结果越有可能具有统计学意义。这意味着我们更有可能检测到变异组和对照组之间的真正差异,如果:
- 平均值(X1-X2)的差异更大
- 样本量更大(所以 N_i 更大)
- 度量的方差(噪声,s_i)较低
这说明了良好的度量选择的重要性。如果选择的度量是快速抽动且噪声较少,则差异会更大,方差会更低:因此,对于相同的样本大小,绝对 t-stat 会更大。我们将很快讨论这个问题。

照片由卡姆兰·乔德里在 Unsplash 拍摄
(旁注:从公式中可以看出,韦尔奇检验不要求两个样本的方差相等——这是学生 t 检验必须满足的一个附加假设。我总是进行韦尔奇 t 检验,而不是学生检验:即使方差不同,它也有效,如果方差相同,它几乎等同于学生 t 检验。)
关于运行有效实验的一些进一步的提示
被假设引导
数据科学家经常会遇到一个模糊的问题,比如“我们应该发布特性 X 吗?”。第一步是将这个问题转换成一个可测试的问题陈述,这个问题陈述要么有一个正确的答案,要么有一个错误的答案。例如,“特性 X 将增加每个用户的平均参与次数。”t 检验统计是比较组均值差异的一个很好的选择。假设引导确保你的测试是有目的的,集中在回答“为什么”,也是设计一个有效指标的支柱。

艾米丽·莫特在 Unsplash 上的照片
为测试制定快速抽动指标
设计一个好的指标通常是让实验有效的秘方——所以有意识地花时间评估你的指标。最重要的是,你设计的指标必须与你公司关心的目标高度相关。但另一方面,这些公司层面的数字往往太慢:增加平台上的收入或用户数量是一个令人钦佩的目标,但在你的小实验中,你真的不太可能有意义地移动它。相反,关注“快速抽动”指标,比如那些衡量转化率或用户参与度的指标:这可能是你可以有意义地衡量的两个群体之间的差异(你知道从长远来看,这与推动更多收入或更多用户相关)。
此外,值得查看任何指标的历史变动,以了解它有多嘈杂,是否受到季节性等因素的影响。这将提高你的统计能力。
指定护栏规格
花时间思考你的度量标准的缺陷也是值得的,这样它就不会被“欺骗”。例如,你可以开展一个误导性的广告活动来提高点击率,但是当用户访问你的网站时,这将是一个糟糕的体验,并降低新用户的保留率。如果您的指标很差,指定有效的护栏指标可能是一种补救措施—这些指标您不会测试其统计显著性,但您可以确保它们不会在您的实验中下降。护栏指标通常也有助于检测看似无关的问题,比如更高的 CPU 使用率。然而,尽管护栏指标很重要,应该总是包括在内,但通常你也可以在第一时间提出一个更好的指标(例如,转化率而不是点击率)。

艾萨克·史密斯在 Unsplash 上拍摄的照片
另一个潜在的陷阱:小心除数指标。例如,每个活跃用户的每日参与。您可能会看到变体组中每个活跃用户的平均每日参与度上升,但如果变体组中实际活跃的用户数量在测试期间因为不喜欢该功能而下降,您就有了一种偏见,即您只测量了继续保持活跃的用户的改善。
对度量标准要有选择性(否则家族错误会咬人!)
测量数百个指标的统计意义可能很诱人:但是这样做是危险的!每当我们测试一个指标时,我们都会接受一定程度的误报率(有时称为 1 类错误),通常设置为 5%。假设两组之间没有真正的差异:如果我们在两组之间测试 20 个指标,我们会期望观察到其中一个具有统计显著性!这可以通过诸如 bonferroni 之类的家族校正来解释,但是这降低了实验的功效。实验的力量是检测两组之间真正差异的可能性,这是实验的全部目的——所以要高度选择你测试的指标。
Winzorization
样本的平均值和标准偏差受极值的影响很大。在实践中,数据科学家倾向于使用 winsorization 来处理极值:例如将极值调整到第 1 和第 99 百分位值。这可以使你的实验更有效率(更快地达到较低样本量的统计显著性),但注意这将引入偏差,因为极值实际上不是异常值。

由 Peter Beukema 在 Unsplash 上拍摄
新奇效果
最后,谨防新奇效应。当一个特性刚刚发布时,用户群可能会大量使用它,推动你的兴趣指标上升,但这是暂时的:随着时间的推移,它们的使用可能会变得不那么新奇。长期抵制(在很长一段时间内保持一个小的控制组)是帮助在更长一段时间内实现这一点的一种方式。
让这更上一层楼
有时,我们希望稳健地达到统计显著性,但要更快(用较低的样本量),并且我们不能改变感兴趣的度量。在这种情况下,方差减少会有所帮助!我将很快写一篇关于如何通过方差减少来增强实验的文章。

Yusuf Evli 在 Unsplash 上的照片
参考资料和进一步阅读:
http://daniellakens.blogspot.com/2015/01/always-use-welchs-t-test-instead-of.html https://bloomingtontutors.com/blog/when-to-use-the-z-test-versus-t-test https://www.analytics-toolkit.com/glossary/randomization/
基于 MTCNN 的鲁棒人脸检测
原文:https://towardsdatascience.com/robust-face-detection-with-mtcnn-400fa81adc2e?source=collection_archive---------9-----------------------
从旧的 Viola-Jones 检测器升级
简介
人脸检测是在给定图像上检测所有人脸的任务。这通常是通过提取边界框的列表来完成的,即面部周围最小可能矩形的坐标。完美的探测器应该是:
- 快速—理想情况下是实时的(至少 1 FPS 以上)
- 准确—它应该只检测人脸(无误报)和检测所有人脸(无误报)
- 鲁棒—应该在不同的姿势、旋转、光照条件等情况下检测人脸。
- 利用所有可用资源——如果可能,使用 GPU,使用彩色(RGB)输入等。
如果你已经知道 Viola-Jones 检波器是如何工作的,你可以跳过下一部分,直接进入 MTCNN 部分。
维奥拉-琼斯探测器
最古老的方法之一是 Viola-Jones 探测器(论文)。它适用于灰度图像,因为它将图像解释为一组 Haar 特征,即较亮和较暗的矩形。有许多类型的 Haar 特征,在矩形中具有不同的亮区和暗区位置。通过使用一种叫做积分图像的技术,可以非常快速地计算出它们。

哈尔特征(来源)
这些特征然后被馈送到 AdaBoost 分类器的级联。它们是按照一定顺序排列的决策树的增强集合。每个特征被馈送到第一个分类器——如果它拒绝它(即认为这个地方没有人脸),它立即被拒绝;如果它接受(即认为它是面部的一部分),它将作为下一个分类器的输入。通过这种方式,Viola-Jones 检测器将检测人脸的任务转变为拒绝非人脸的任务。事实证明,我们可以用 cascade 快速过滤掉非人脸,从而实现快速检测。

维奥拉-琼斯级联(来源)
然而,它也有自己的问题。如果人脸大小不同,则调整图像的大小,并对每张图像运行分类器。这种情况下的准确性不是很高,在非常令人惊讶的情况下也可能失败(见下图)。主要缺点是缺乏鲁棒性。Viola-Jones 分类器假设人脸直视摄像机(或几乎直视),光照均匀,人脸清晰可见。这种情况经常出现,例如当智能手机摄像头检测人脸进行过滤时,但并不总是如此。主要的例子是安全(它们被放置在天花板附近)和团体照片(在光线条件变化的地方)。
美国有线电视新闻网前来救援
多任务级联卷积神经网络(论文)是一种现代的人脸检测工具,利用了 3 级神经网络检测器。

MTCNN 工作可视化(来源)
首先,多次调整图像大小,以检测不同大小的人脸。然后,P 网络(建议)扫描图像,执行第一次检测。它的检测阈值很低,因此即使在 NMS(非最大抑制)之后也能检测到许多误报,但它是故意这样工作的。
建议的区域(包含许多假阳性)被输入到第二个网络,R-网络(Refine ),顾名思义,它过滤检测(也用 NMS)以获得相当精确的边界框。最后阶段,O-网络(输出)执行边界框的最终细化。这种方式不仅可以检测到人脸,而且边界框也非常正确和精确。
MTCNN 的可选特征是检测面部标志,即眼睛、鼻子和嘴角。它几乎没有成本,因为它们无论如何都被用于过程中的面部检测,这是一个额外的优势,如果你需要这些(例如,面部对齐)。
MTCNN 的官方 TensorFlow 实现效果不错,但是 PyTorch one 更快(链接)。它在全高清视频上达到了大约 13 FPS,甚至在重新缩放时达到了 45 FPS,使用了一些技巧(见文档)。它还非常容易安装和使用。我还在全高清的 CPU 上实现了 6-8 FPS,因此使用 MTCNN 进行实时处理是非常可能的。
MTCNN 非常准确和健壮。即使在不同大小、光照和强烈旋转的情况下,它也能正确检测人脸。它比 Viola-Jones 检测器慢一点,但是用 GPU 也不慢太多。它还使用颜色信息,因为 CNN 获得 RGB 图像作为输入。
比较

Viola-Jones 和 MTCNN 探测器的比较(图片由作者提供)
代码和示例
为了查看这两个检测器在真实数据上的比较,我使用了下面的代码和一些流行的图片。
Viola-Jones 代码基于这个 OpenCV 教程。人脸检测的预训练权重可以在这里找到。
第一张图片(来源)是一张典型的家庭照片。人脸检测经常用于这类图像,例如用于 iPhones 上的自动图库管理。

左:维奥拉-琼斯,右:MTCNN ( 原始图片来源)
Viola-Jones 检测的典型用例,一张全家福。很棒的条件,脸几乎正对着镜头,效果真的很好。由于默认情况下更敏感,MTCNN 会检测到假阴性。对于这种情况,我们可以使用 thresholds 属性轻松地更改 MTCNN 的阈值,这非常有用,但这里我们坚持使用默认值。
第二张图片更具挑战性,一张著名的苏威会议合影(来源)。这类似于大型家庭团体照片,也是社交媒体中人脸检测的热门目标。

上图:维奥拉-琼斯,下图:MTCNN ( 原始图片来源)
两个探测器都工作良好。Viola-Jones 唯一没有检测到的是旋转的那张脸。这里 MTCNN 展示了它的鲁棒性——它检测到了这张脸。如你所见,“琐碎”的照片对于简单的探测器来说也是有问题的。
最后一张照片是典型的街拍(来源)。这种情况更类似于安全摄像机照片,其中 ML 用于面部检测,例如加速监控视频分析。

上图:维奥拉-琼斯,下图:MTCNN ( 原始图片来源)
像这样的图像有许多不同的光线水平,所以 Viola-Jones 检测器不能很好地工作,它会产生很多假阳性,并且不能检测较小、旋转或部分遮挡的面部。另一方面,MTCNN 具有完美的检测能力,即使对于严重遮挡的人脸也是如此。
总结
您已经了解了 MTCNN,它是 Viola-Jones 检波器的一种强大而精确的替代产品。在现实生活条件下,Viola-Jones 框架的假设经常失败,但巧妙构建的神经网络可以轻松完成这些任务。
如果你想了解更多关于 MTCNN 和它的技术细节,请看优秀的文档(那里有教程和笔记本链接)。
NumPy 中从头开始的 ROC 曲线和 AUC(可视化!)
原文:https://towardsdatascience.com/roc-curve-and-auc-from-scratch-in-numpy-visualized-2612bb9459ab?source=collection_archive---------6-----------------------
因为在你建造它之前,你不会学到它

妮娜·摄影实验室在 Unsplash 上拍摄的照片
从引用开始怎么样?。
“过去,我曾试图使用[…]种不同的编程语言[…]来教授机器学习,我发现,使用 Octave 等相对高级的语言,学生能够最有效地学习[…]。”,吴天俊。
从零开始构建东西是 Andrew NG 教授他著名的 Coursera 的机器学习课程时使用的方法😂),拥有平台上最棒的收视率之一。像安德鲁一样,我真的相信建造东西是最好的学习方式,因为它迫使我们理解算法的每一步。与 Andrew 不同,我更喜欢使用 Python 和 Numpy😎因为它们简单且被广泛采用。直接反对他的建议听起来有点疯狂,但时代在变,我们也能变。
评估机器学习模型可能是一项具有挑战性的任务。有大量的指标,仅仅看着它们,你可能会感到不知所措。通常的第一种方法是检查准确度、精确度和召回率。但是当你再深究一点,你很可能会碰到一个 ROC 图。问题是它不像其他的那样容易理解。
那怎么办呢?从头开始构建!。
接收操作特性(ROC) 图试图解释二进制分类器的表现如何。一个简单的混淆矩阵不足以测试你的模型有几个原因。尽管如此,ROC 表示非常好地解决了以下问题:在一个可视化中设置多个阈值的可能性。
在我们继续之前,下面的一个场景是真的:第一个是你理解了我在最后一段所说的一切,所以我可以继续下去,开始构建 ROC 曲线。第二是你没懂多少。如果是这样的话,我不想显得粗鲁。因此,我有东西给你。
如果你对自己的知识有信心,你可以跳过下一部分。但是如果你不知道(或者你需要复习一下),我鼓励你去读一读。理解以下概念是必要的,因为 ROC 曲线是建立在这些概念之上的。
基础
注:以下术语将浅显处理。如果你想要更详细的指南,看这里的或这里的。
- 混淆矩阵 :预测二分类问题时,通常将正例标为 1,负例标为 0。当预测值与实际值相等时,为真情况;否则就是负面的。该矩阵旨在揭示这些场景组合的比例信息,包括真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)。在下图中,你可以看到一个例子。

作者创建的图像。

作者创建的图像。
- 真阳性率: 根据以下公式,使用真阳性和假阴性计算此指标。

作者创建的图像。
- 假阳性率: 根据以下公式,使用假阳性和真阴性来计算此指标。

作者创建的图像。
- Predict _ proba:对于大多数模型,您可以检索预测的概率。概率显示所选类别上模型的置信度是否存在差异。predict_proba 越高,表示输出的可信度越高。
- 阈值: 该值定义了模型何时改变对输出的看法,从正面到负面,反之亦然。默认情况下,模型的阈值为 0.5。如果该值高于 0.5,模型会将样本预测为阳性,但如果该值低于 0.5,模型会将其预测为阴性。
ROC 曲线从零开始
ROC 图在 y 轴上具有真阳性率,在 x 轴上具有假阳性率。正如您可能猜测的那样,这意味着我们需要一种方法来不止一次地创建这些指标,以使图表具有自然的形状。我们需要一种算法来迭代计算这些值。
尽管 scikit-learn(我们稍后将访问)中有这个指标的实现,但如果您已经在这里,这强烈表明您有足够的勇气来构建而不是仅仅复制粘贴一些代码。为了了解我们实际要做的事情,我为你准备了以下步骤,以及视觉化…享受吧!。
第一步,选择一个阈值 :正如我们之前讨论的,ROC 曲线的整个思路就是检验出不同的阈值,但是怎么做呢?这是我们工作的一部分。做这件事有不同的方法,但我们将采用最简单的方法。只需将阈值设置为距离相等的分区,我们就可以解决第一个难题。

作者创建的图像。
我们需要查看的阈值等于我们设置的分区数量加 1。我们将迭代这个步骤中定义的每个阈值。
第二步,阈值比较: 在每次迭代中,我们都要将预测概率与当前阈值进行比较。如果阈值高于预测概率,我们将样本标记为 0,反之标记为 1。如果你还不清楚这一点,我相信下一个例子会有所帮助。

作者创建的图像。
在可视化中,有两个不同迭代的例子。高阈值的阳性预测病例数总是低于或等于较小阈值的阳性预测病例数。
第三步,计算 TPR 和 FPR: 我们差不多完成了我们的算法。最后一部分是在每次迭代中计算 TPR 和 FPR。方法简单。这与我们在上一节中看到的完全相同。唯一的区别是,在进行下一次迭代之前,我们需要将 TPR 和 FPR 保存在一个列表中。TPRs 和 FPRs 对的列表是 ROC 曲线中的线。所以,我们正式结束了!
我知道你想再看一次。你可以看到不同的阈值如何改变我们的 TPR 和 FPR 的值。

作者创建的图像。
既然你是算法方面的专家,是时候开始构建了!开始之前的第一步是要有一些概率和一些预测。为了快速解决这个问题,我们将使用 scikit-learn 收集它(这不是作弊,因为它只是算法的输入)。
注意:因为我没有在“make_classification”上设置 random_state 参数,所以您的案例的结果可能会有细微的变化。
首先,我们需要一个方法来复制步骤 3,它是通过下面的方法完成的。
该算法的核心是迭代步骤 1 中定义的阈值。我们通过步骤 2 和 3,在每次迭代中将 TPR 和 FPR 对添加到列表中。
你认为这行得通吗?🤞

作者创建的图像。
显然,这是可行的🤣。使用 10 个分区,我们获得了第一个 ROC 图。但是你可以看到增加分区的数量是如何给我们一个更好的曲线近似值的。

作者创建的图像。
但是让我们将我们的结果与 scikit-learn 的实现进行比较。

作者创建的图像。
差不多一样😎。但是我们还没有结束。ROC 曲线带有一个度量标准:“曲线下的面积”。
从头开始 AUC
ROC 图中曲线下的面积是确定分类器是否运行良好的主要指标。该值越高,模型性能越高。这个指标的最大理论值是 1,但通常比这个值小一点。
可以使用函数在 0 和 1 之间的积分来计算函数的 AUC。
但是在这种情况下,创建一个函数就没那么简单了。尽管如此,一个好的近似方法是计算面积,将其分成更小的块(矩形和三角形)。

作者创建的图像。
随着数字的增加,三角形下面的面积变得更加可以忽略,所以我们可以忽略它。不过,我们还有最后一个挑战:计算 AUC 值。我们要做的是把我们刚刚画的矩形的每一个面积加起来。尽管不是最佳实现,我们将使用 for 循环来使您更容易理解。

作者创建的图像。
同样,我们将它与 scikit-learn 的实现进行比较

作者创建的图像。
由于点的位置不同,差异很小,但值几乎相同。
我们完了!🙌
该算法还有待改进,但这只是为了教学目的。我真的希望看到每一步,帮助你更好地解释指标。
再见
现在是你做决定的时候了。Octave 和 Python 哪个最适合你?我在评论里等你的回答!。我真的希望这个博客能让你感兴趣。

我还上了 Linkedin 和 Twitter 。我很乐意与你交谈!
如果你想多读一点,看看我最近的一些帖子:
ROC 曲线解释
原文:https://towardsdatascience.com/roc-curve-explained-50acab4f7bd8?source=collection_archive---------13-----------------------
数据科学基础
学习用 Python 可视化 ROC 曲线
ROC 曲线下面积是评估监督分类模型的最有用的度量之一。这一指标通常被称为 ROC-AUC。这里,ROC 代表受试者操作特征,AUC 代表曲线下面积。在我看来,AUROCC 是一个更准确的缩写,但听起来可能不太好听。在正确的上下文中,AUC 也可以暗示 ROC-AUC,即使它可以指任何曲线下的面积。

乔尔·菲利普在 Unsplash 上的照片
在这篇文章中,我们将了解 ROC 曲线是如何从概念上构建的,并以 Python 中的静态和交互式格式来可视化该曲线。
理解曲线
ROC 曲线向我们展示了不同阈值下假阳性率和真阳性率(TPR) 之间的关系。让我们来理解这三个术语的含义。
首先,让我们回顾一下混淆矩阵的样子:

作者图片
刷新了我们对混淆矩阵的记忆后,让我们看看术语。
假阳性率
我们可以使用下面的简单公式找到 FPR:

FPR 告诉我们不正确预测的负面记录的百分比。

作者图片
真实阳性率
我们可以使用下面的简单公式找到 TPR:

TPR 告诉我们正确预测的正面记录的百分比。这也被称为回忆或敏感性。

作者图片
阈值
通常,分类模型可以预测给定记录成为某个类别的概率。通过将概率值与我们设置的阈值进行比较,我们可以将记录分类。换句话说,您需要定义一个类似如下的规则:
如果为正的概率大于或等于阈值,则记录被分类为正预测;否则,一个负面的预测。
在下面的小例子中,我们可以看到三个记录的概率得分。使用两个不同的阈值(0.5 和 0.6),我们将每个记录分类到一个类中。正如您所看到的,预测的类根据我们选择的阈值而变化。

作者图片
当构建混淆矩阵和计算 FPR 和 TPR 等比率时,我们需要预测的类别,而不是概率得分。
受试者工作特征曲线
既然我们知道了什么是 FPR、TPR 和阈值,就很容易理解 ROC 曲线显示了什么。当构建曲线时,我们首先跨多个阈值计算 FPR 和 TPR。一旦我们有了阈值的 FPR 和 TPR,我们就可以在 x 轴上绘制 FPR,在 y 轴上绘制 TPR,从而得到 ROC 曲线。就是这样!✨

作者图片
ROC 曲线下的面积范围从 0 到 1。完全随机模型的 AUROCC 为 0.5,由下面的蓝色三角形对角线虚线表示。ROC 曲线离这条线越远,模型的预测性越强。

作者图片
现在,是时候看看一些代码示例来巩固我们的知识了。
在 Python 中构建静态 ROC 曲线
让我们首先导入本文剩余部分所需的库:
import numpy as np
import pandas as pd
pd.options.display.float_format = "{:.4f}".formatfrom sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, plot_roc_curveimport matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
sns.set(palette='rainbow', context='talk')
现在,我们将构建一个函数,在给定正确类别、预测为阳性类别的概率和阈值的情况下,该函数将找到假阳性和真阳性的数量:
def get_fp_tp(y, proba, threshold):
"""Return the number of false positives and true positives."""
# Classify into classes
pred = pd.Series(np.where(proba>=threshold, 1, 0),
dtype='category')
pred.cat.set_categories([0,1], inplace=True)
# Create confusion matrix
confusion_matrix = pred.groupby([y, pred]).size().unstack()\
.rename(columns={0: 'pred_0',
1: 'pred_1'},
index={0: 'actual_0',
1: 'actual_1'})
false_positives = confusion_matrix.loc['actual_0', 'pred_1']
true_positives = confusion_matrix.loc['actual_1', 'pred_1']
return false_positives, true_positives
请注意,您将在现实中使用分区数据集(例如,培训、测试)。但是为了简单起见,我们不会在本文中对数据进行划分。
我们将在玩具数据集上构建一个简单的模型,并获得这些记录为正的概率(用值 1 表示):
# Load sample data
X = load_breast_cancer()['data'][:,:2] # first two columns only
y = load_breast_cancer()['target']# Train a model
log = LogisticRegression()
log.fit(X, y)# Predict probability
proba = log.predict_proba(X)[:,1]
我们将使用 0 到 1 之间的 1001 个不同的阈值,增量为 0.001。换句话说,阈值看起来像 0,0.001,0.002,… 0.998,0.999,1。让我们找到阈值的 FPR 和 TPR。
# Find fpr & tpr for thresholds
negatives = np.sum(y==0)
positives = np.sum(y==1)columns = ['threshold', 'false_positive_rate', 'true_positive_rate']
inputs = pd.DataFrame(columns=columns, dtype=np.number)
thresholds = np.linspace(0, 1, 1001)for i, threshold in enumerate(thresholds):
inputs.loc[i, 'threshold'] = threshold
false_positives, true_positives = get_fp_tp(y, proba, threshold)
inputs.loc[i, 'false_positive_rate'] = false_positives/negatives
inputs.loc[i, 'true_positive_rate'] = true_positives/positives
inputs

该地块的数据已准备好。让我们画出来:
def plot_static_roc_curve(fpr, tpr):
plt.figure(figsize=[7,7])
plt.fill_between(fpr, tpr, alpha=.5)
# Add dashed line with a slope of 1
plt.plot([0,1], [0,1], linestyle=(0, (5, 5)), linewidth=2)
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC curve");
plot_static_roc_curve(inputs['false_positive_rate'],
inputs['true_positive_rate'])

虽然构建自定义函数有助于我们理解曲线及其输入,并更好地控制它们,但我们也可以利用 sklearn 的功能进行更好的优化。例如,我们可以用一个roc_curve()函数得到 FPR、TPR 和阈值。我们可以使用自定义绘图功能以同样的方式绘制数据:
fpr, tpr, thresholds = roc_curve(y, proba)
plot_static_roc_curve(fpr, tpr)

Sklearn 还提供了一个plot_roc_curve()函数,为我们完成所有的工作。您只需要一行代码(添加标题是可选的):
plot_roc_curve(log, X, y)
plt.title("ROC curve"); # Add a title for clarity

用 Python 绘制交互式 ROC 曲线
使用静态图时,很难看到曲线上不同点的相应阈值。一种选择是检查我们创建的inputs 数据框架。另一个选项是创建图形的交互式版本,这样当我们将鼠标悬停在图形上时,可以看到 FPR 和 TPR 以及相应的阈值:
def plot_interactive_roc_curve(df, fpr, tpr, thresholds):
fig = px.area(
data_frame=df,
x=fpr,
y=tpr,
hover_data=thresholds,
title='ROC Curve'
)
fig.update_layout(
autosize=False,
width=500,
height=500,
margin=dict(l=30, r=30, b=30, t=30, pad=4),
title_x=.5, # Centre title
hovermode = 'closest',
xaxis=dict(hoverformat='.4f'),
yaxis=dict(hoverformat='.4f')
)
hovertemplate = 'False Positive Rate=%{x}<br>True Positive Rate=%{y}<br>Threshold=%{customdata[0]:.4f}<extra></extra>'
fig.update_traces(hovertemplate=hovertemplate)
# Add dashed line with a slope of 1
fig.add_shape(type='line', line=dict(dash='dash'), x0=0, x1=1, y0=0, y1=1)
fig.show()plot_interactive_roc_curve(df=inputs,
fpr='false_positive_rate',
tpr='true_positive_rate',
thresholds=['threshold'])

互动性挺有用的吧?
希望你喜欢学习如何建立和可视化 ROC 曲线。一旦理解了这条曲线,就很容易理解另一条相关曲线: 精准召回曲线 。

由 Mael Pavageau 在 Unsplash 上拍摄的照片
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️ 在 Python 中使用标点符号的有趣方法
◼️ 从零开始学习 Python 的 5 个技巧
◼️python 虚拟环境数据科学简介
◼️git 数据科学简介
◼️ 用这些技巧整理你的 Jupyter 笔记本
◼️ 6 个简单技巧让你在 Seaborn (Python)中的情节更漂亮、更定制
◼️️
再见🏃💨
Rock 容器化 GPU 机器学习开发用 VS 代码
原文:https://towardsdatascience.com/rock-containerized-gpu-machine-learning-development-with-vs-code-34940ff25509?source=collection_archive---------18-----------------------
再也不用为破损的基础设施而烦恼了

由 Fab Lentz 在 Unsplash 上拍摄的照片
在 GPU 上运行机器学习算法是一种常见的做法。虽然有像 Paperspace 和 Colab 这样的云 ML 服务,但是最方便/灵活的原型化方式仍然是本地机器。
别闹了,用集装箱🦺
自从机器学习库(例如 TensorFlow、Torch 和 Caffe)出现以来,处理 Nvidia 库一直是许多数据科学家头疼的问题:
- Nvidia 驱动程序/库和硬件/操作系统可能不兼容,这在面向消费者的笔记本电脑/台式机上经常发生。
- Nvidia 库可能与 ML 库版本不匹配,这意味着您不能让系统自动更新库。
- ML 进程和其他进程可以竞争资源。例如,如果您在训练模型时筛选记录,则两者都有可能崩溃,因为编解码器和模型训练都需要锁定 GPU 资源。
- 更多奇怪的问题…
总之,建立一个 GPU ML 环境会不断弄乱现有的基础设施,通常需要重新安装操作系统来恢复。
更好的方法是在支持 CUDA 的容器中进行开发,其中开发环境与主机和其他项目相隔离。
VS 代码远程容器=在容器中开发
在容器内开发通常效率很低,因为很难想象 VM 内发生了什么。
然而,VS 代码通过在 IDE 前端和后端之间定义一组通用的 API 使它变得简单,这使得在两个系统中运行它们对用户来说是无缝的。
下面是来自 VS 代码文档网站的图表,展示了它是如何工作的:

鸣谢: Visual Studio 代码文档网站
关于它如何工作的更多细节,参见官方文档。
逐步安装说明
让我们一步一步来看看如何用 VS 代码建立一个容器化的 GPU ML 开发环境。
步骤 1:定义容器
基于容器的开发中最基本的组件是容器。我们需要用 Dockerfile 文件定义容器。
下面是张量流的一个例子:
这个 Dockerfile 告诉 VS 代码以官方的 TensorFlow 图像为基线构建一个容器,此外,使用 BASH 作为默认终端,而不是不太用户友好的 SH(IMO)。
步骤 2:定义 VS 代码应该如何使用 VM
现在我们有了一个可以利用 GPU 能力的容器,我们需要告诉 VS 代码使用之前定义的容器并且将 GPU 能力传递给它:
步骤 3(可选):在虚拟机中添加用户
理论上,我们已经可以使用这个环境进行开发,但是,由于我们还没有定义任何用户,所以所有的操作都将在 root 下进行,这是可以的,但是不太安全。
我们可以通过在 docker 文件中添加以下代码来定义用户:
此外,我们需要告诉 VS 代码以这个远程用户的身份登录:
步骤 4:启动虚拟机开发环境
最后,我们已经准备好运行远程开发会话的一切,让我们试一试:

要了解更多细节,请查看这个库,这是我试验这个设置的库。更多后续提示和技巧(我仍在努力),请在 GitHub 上关注我。
以下是如何在 GPU 的支持下进行 ML 开发,但又不会经常搞乱你的基础设施。快乐黑客🚀🚀🚀
石头、剪刀、布和股票市场
原文:https://towardsdatascience.com/rock-paper-scissors-and-the-stock-market-f1ad81785a76?source=collection_archive---------22-----------------------
讲述我在石头、剪子、布游戏中的经历,以及游戏结构与股票市场的相似之处。

法迪拉·n·伊玛尼在 Unsplash 上拍摄的照片
你通常不会把石头、剪刀、布(简称 RPS)和股票市场联系起来。这样做实际上似乎很荒谬。当然,一个 RPS 游戏,或者一系列的一千个 RPS 游戏和股票市场没有任何关系。
但是,当 RPS 被置于一种竞争形式中,各种算法为了排行榜上的分数而相互争斗时,我的理论是,它与股票市场有一些显著的相似之处。
更准确地说,Kaggle 最近在 RPS 上的比赛从 2020 年 11 月开始,到 2021 年 2 月结束,似乎具有我们通常的股票市场的一些特征,我个人通过使用投资组合优化理论来利用这种相似性,达到了第 32 位(前 2%)。
请注意,本文的大部分内容都是基于直觉;没有统计数据支持我的论点。但是,对于那些对市场效率、卡格尔竞争、投资组合优化理论等感兴趣的人来说,这篇文章应该是信息丰富的。
石头、布、剪刀背景下的数据科学
Kaggle 的 RPS 比赛
四个月前,大概是 2020 年 11 月初,Kaggle 发起了 RPS 竞赛。下面是比赛描述页面的节选节选。
石头、剪子、布(有时称为 roshambo)一直是解决操场上的分歧或决定谁在公路旅行中坐在前排的主要手段…
研究表明,石头、剪刀、布人工智能可以持续击败人类对手。以以前的游戏作为输入,它研究模式以了解玩家的倾向。但是,当我们将简单的“三局两胜”游戏扩展为“一千局三胜”游戏时,会发生什么呢?人工智能的表现能有多好?
在这个模拟比赛中,你将创建一个人工智能在这个经典游戏的许多回合中与他人比赛…当比赛涉及非随机代理时,有可能大大胜过随机玩家。一个强大的人工智能可以持续击败可预测的人工智能…
如上所述,比赛中每个参与者的目标是提交一个与另一个机器人(由其他一些参与者提交)进行 1000 次连续 RPS 匹配的算法。如果一个算法赢了超过 20 分,它就赢得了那一集(= 1000 场比赛),赢了奖励 1 分,平了奖励 0 分,输了奖励-1 分。对于一集的每一场胜利,该算法都会根据比赛的评估标准获得 learderboard 积分。
乍一看,这似乎毫无意义。在 RPS 游戏中,直觉的理性举动是随机游戏,没有争论。如果我们要和任何机器人对战一集,我们一定要随机播放。
但竞赛的重点在于这部分描述:
当比赛涉及到非随机代理时,有可能远远胜过随机玩家。
如果比赛中甚至有几十个非随机机器人,那么只要有足够数量的匹配,另一个可以利用这种非随机性的机器人将有更高的机会胜过所有其他随机机器人。这是因为高级非随机算法可能会与其他随机机器人打成平手,但会战胜低级非随机算法,在排行榜上获得随机机器人无法获得的额外分数。
因此,尽管纳什均衡表明,在假设所有其他机器人都理性行事的情况下,人们应该随机行事,但并非所有机器人都理性的事实使得非随机代理在排行榜上表现出色。
我们已经看到了与股票市场的相似之处。如果所有的市场参与者都在给定的信息下理性地行动,那么股票市场将是极其有效的。正是市场参与者存在的非理性导致了可利用的市场无效率以获取超额收益(尽管这部分在各种风险调整后仍有争议)。
以前的 RPS 比赛
信不信由你,在 Kaggle 之前已经有过几次 RPS 比赛了。最近的一个是 RPSC T4 在线考试网站。尽管每月获胜者没有奖品,但人们积极参与了竞赛,这导致了一些真正了不起的算法的诞生。
在 Kaggle 的讨论中,还有其他经常提到的算法,比如格林伯格和 Iocaine 粉。这些算法甚至在 2001 年及之前的 RPSContest 之前就已经在比赛中使用过。对这些算法最好的详细描述可以在这里找到,但简单地把逻辑放在上下文中,这些非常成功的算法利用了多层元策略的内存搜索算法,这些元策略决定是否做出击败过去历史预测移动的移动,或者击败移动的移动,或者击败移动的移动,击败移动的移动,等等。
将这些算法的强度放在上下文中, Iocaine Powder 和 Greenberg 可以轻松击败基于机器学习的算法,如决策树和多层感知器(前馈神经网络)。事实上,使用机器学习算法需要格外小心,以避免过度拟合,因为其他内存搜索算法和统计模型对对手策略的变化反应更快,这对于确保+20 分的胜利至关重要。
股票市场中的市场效率和数据科学
有效市场?
好了,现在我们已经讨论了 RPS 在传统数据科学社区中的位置,让我们来看看拥有一个有效市场意味着什么。
一个完全有效的市场会立即将所有相关信息纳入其市场价格。这意味着,由于市场价格已经反映了资产的真实价值,因此没有机会找到“低估”或“高估”的资产。根据这一定义,持续跑赢市场是不可能的——所有那些拥有长期优异表现记录的人只是幸运而已。
有不同程度的建议市场效率。疲软的形式表明,过去的价格变动在预测未来回报时是无关紧要的。换句话说,基于趋势的交易或基于价格变动的技术分析不足以持续跑赢市场。这是最近学术界对加密货币市场效率研究的焦点之一,阅读相关论文可能会很有趣。
半强式市场效率是指市场价格对所有公开信息做出快速反应。从这个角度来看,即使是基本面分析也被认为是过时的。以这种方式战胜市场的唯一方法将是获得非公开信息,这种信息危险地挂在非法内幕交易的线上。
强式认为,市场会立即反映所有信息,包括公开的和未公开的,这意味着跑赢市场几乎是不可能的。
然而,也有某些类别的股票似乎跑赢了市场。为了将这些异常纳入有效市场环境,我们可以利用 Fama 的三因素模型,该模型表明,当根据某些因素对各种风险进行调整时,看似优越的股票回报可以得到解释(Fama 后来扩展了该模型,纳入了另外两个因素,但这些因素本身就可以解释预期回报中的大多数异常)。
似乎除了学术界之外,人们普遍认为,虽然市场总体上是有效的,但它仍然表现出低效率,特别是在短时间内——因此 Lasse Heje Pedersen 关于对冲基金和积极投资的著名入门书采用了有效无效率作为书名。
那么数据科学在战胜市场中的地位如何呢?
作为这个领域的新生,我可能没有资格回答上面的问题,但无论如何我会试一试。
使用机器学习算法预测股市的棘手之处在于,它非常容易过度拟合。媒体上的证据几乎无处不在。“预测股市”的比较老的文章,有一半以上落入这个陷阱。最容易发现的是那些使用最近价格数据的 LSTMs 来预测下一个价格的,这只是一个时滞预测(基本上,每天的价格预测都是前一天的价格;有趣的是,这与鞅属性一致,但是你不需要 LSTMs 来利用这个属性。
诚然,顶级量化对冲基金可能正在使用 ML 算法,通过额外小心避免过度拟合来充分受益于战胜市场,但对于普通散户投资者来说,采取这种额外小心的成本可能超过了收益。事实是,一个简单的统计模型与足够的,真正的多样化显示出惊人的强劲表现。虽然使用额外的数据科学技术,如情绪分析、谷歌趋势分析和深度神经网络可以提供一点优势,但这种努力最好用于最小化市场摩擦,提供额外的多样化,降低服务器成本等。
当然,也有一些例外,比如最近吸引了很多注意力的韩国初创公司 QRAFT ,但即使在这里,你也应该注意到,这家初创公司最有价值的资产不仅是其基于深度强化学习的 ETF,还有 AXE(基于 ML 的订单执行系统)和麒麟 API(自动数据清理模块)。
总而言之,数据科学在活跃的投资世界中确实有一席之地,但尽管它对股票回报预测的影响尚不清楚,但它对交易的其他方面(如订单执行)的积极影响似乎非常明显。
非随机 RPS 竞争与无效率市场
打个比方
你现在可能想知道上面所有的信息是如何结合在一起形成 Kaggle 的 RPS 竞赛类似于股票市场的结论的。
好吧,让我们考虑一下市场效率的半强形式。这里的论点是,每当有一个被披露的事件改变了资产的价值,市场价格就立即反映了这一信息,这是由抓住机会获利的市场参与者推动的。
理解这一点的一种方法是,考虑如果保证市场效率成立,会发生什么。如果是这样的话,那么任何市场参与者都没有动力通过积极交易来承担损失交易成本的风险。最好的办法是通过投资被动型 ETF 来承担系统性风险。
然而,通常情况并非如此。投资者,无论是机构投资者还是个人投资者,都在假设存在某些低效率以供利用的情况下积极交易。如果存在任何低效率,那么这种积极的运动将这种低效率从市场中消除,因为投资者贪婪地从错误的定价中抓住机会,迅速将价格恢复到正确的价值。投资者从这种活动中获得的回报可以被认为是对市场重新注入效率的回报。
有趣的是,这种恢复效率的积极投资也是低效的根源。
现在让我们回到 Kaggle 的 RPS 比赛。在纳什均衡下,人们应该只提交随机的代理人,并希望获胜。然而,在这种情况下,我们知道一个事实,有非随机,非理性的代理人参与竞争。在这种新的信息下,最好的办法是引入类似的非随机(低效)代理,它们有望击败所有其他非随机代理。如果你成功地想出了这样的算法,那么你将把其他非随机代理的表现恢复到随机平均值(恢复效率),并在排行榜中获得分数作为奖励。同时,因为你提交了一个非随机的代理,你也有给市场带来低效率的风险,除非出现另一个更好的 bot。
在 Kaggle 的 RPS 比赛中,过去像 Iocaine 粉和格林伯格这样的算法表现非常差。为什么?一个显而易见的原因是,几乎所有其他表现出色的代理都有这种算法的镜像版本,可以在 100%的时间里击败他们,另一个原因是,因为已经提交了如此多的这种过去成功但公开可用的算法的副本,可能会输给这种算法的机器人已经在排行榜上排名太低了。换句话说,奥卡因粉或格林伯格可以赖以生存的竞争中的所有低效都已经被集体解决了。
这与成功的交易策略在投资界广为人知的情况非常相似。在最初利用布莱克-斯科尔斯模型的期权定价时,像配对交易和反向策略这样的套利机会都非常有利可图,因为只有少数市场参与者使用它们。然而,到了 2000 年代的市场崩盘时,为了获得类似的回报水平,极端的杠杆变得至关重要。
我可能会因为在没有任何真实数据支持的情况下起草这些结论而遭到批评。毕竟,实际提取数据并得出具体结论是 Kaggle 和数据科学社区的精神。但是这里的类比确实带来了一个关于竞争本质的有趣观点。
作为整体方法论的投资组合优化
离比赛截止日期还有不到几周的时间,越来越明显的是,合奏可能是取得成功的途径。虽然是一个简单的非集成代理表现出了卓越的性能,但大多数讨论倾向于提出一种可靠的集成方法。
就我个人而言,由于我被竞争与股票市场的相似性所吸引,我迫切希望利用过去一年一直在努力学习的量化金融领域的知识。
我的想法的详细记录在这里有很好的证明,但是为了补充链接主题中所说的内容,让我具体解释一下我是如何设置问题的。
不管你是在每集的每一步做出确定性的选择还是随机的选择,事实是,当试图整合来自多个算法的信息时,你要为最终的决定权衡那些算法的决定。如果算法 A 对当前的对手产生了极好的结果,那么最有可能的是你应该坚持算法 A 推荐的走法;如果算法 A 推荐剪刀,你应该挑剪刀。在这种情况下,权重映射看起来像:{0 : 0.02,1 : 0.18,2 : 0.80},其中 0,1,2 分别对应于石头,剪刀,布。由于 80%的重量集中在 2 上,全体成员下一步会选择剪刀。
因此,在某些方面,为算法选择用于当前步骤的权重类似于在重新平衡期间为不同资产选择投资组合权重。如果一个算法最近表现良好,你可能会给它更多的权重。然后,我们可以将这一集中的每一步视为重新平衡我们投资组合的自然时间步骤。
现在,大多数公开可用的 RPS 算法使用相同的核心逻辑;在竞赛线程中经常讨论的是,为了提高集合的性能,移除冗余代理是必不可少的。嗯,如果我们要激励与其他算法相关性低的算法,那么就没有必要手工挑选。
幸运的是,我们著名的均值-方差投资组合优化理论给了我们这样做的方法。我不想太深入投资组合优化理论,因为有些模糊的领域我仍然不太确定,但重要的一点是,只要目标资产的预期回报是优秀的,最终的投资组合在风险调整后的回报方面也将是优秀的:投资组合很少会亏损。
令人遗憾的是,Kaggle 只允许最多 1 秒钟来决定下一步行动,所以我无法获得一个集合模型来检查有效边界,以找到最大夏普点。如果可能的话,我敢说我可能会在排行榜上名列前茅。
不过,等等。我怎么知道这个合奏方法在比赛中确实成功了?毕竟,由于 RPS 的性质,一个幸运的随机代理可以在排行榜上排名很高。我的辩护是,在比赛结束时,我在奖牌区有 8 个这样的组合整体代理,这种整体方法在本地测试中(和在排行榜中)证明比具有 beta 分布的多臂 bandit 更成功。
最后
一旦你登记了所有的事实,RPS 竞赛在某些方面类似于股票市场就不足为奇了。从长期来看,两者都可以被描述为完全随机的系统,但从短期来看,它们多少是可以预测的。
然而,RPS 竞赛真正向我展示的是,使用 LSTMs 这样的复杂方法来打击所有随机噪声通常是毫无意义的。事实是,在过去的分数趋势中,并不存在任何能提供未来有意义信息的如此强烈的信号。与其担心调整超参数,不如把更多的精力花在减少算法的执行时间上?)或者想出并添加更有效的算法(=添加多样化)。
还有,数学才是王道。我真的推荐看看这个帖子。它显示了一个简单的数学解决方案是多么有效。
感谢 Kaggle 工作人员举办了这次有趣的比赛,非常感谢像 Stas Sl、Taaha Khan、SuperAnt、托尼·罗宾逊等人,他们为社区做出了如此多有意义的智力贡献。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
通过 PyMC3 在 Python 中实现滚动回归
原文:https://towardsdatascience.com/rockin-rolling-regression-in-python-via-pymc3-e4722b6118cd?source=collection_archive---------4-----------------------
贝叶斯统计
学习如何处理变化的参数

由本杰明·沃罗斯在 Unsplash 上拍摄的照片
答假设您想要训练一个参数模型,如线性模型或神经网络。在线性回归的情况下,首先,你指定模型的形状,我们说 y = ax + b. 其次,你估计参数 a 和 b 。对你这样的专家来说没什么难的。
我想指出的是你在这样做的时候所做的一个隐含的假设:
来自数据集的所有观测值都服从具有相同固定参数的相同模型。
在线性模型的情况下,这意味着 a 和 b 的相同固定值适用于所有观测值。这个假设是否合理,取决于你手头的数据集。虽然它经常成立,但在这篇文章中,我想给你看一个简单的例子,它是完全错误的。在你读完之后,你将能够自己发现这些有问题的例子,并且知道如何以一种好的方式对待它们。我们将考虑一个天真的以及不错的贝叶斯治疗。
随时间变化的参数
一个参数可能变化的明显场景是在处理时间序列时。随着时间的推移,数据的输入和输出之间的依赖关系可能会改变,这意味着模型及其参数也必须随着时间的推移而改变。
作为一个假设的例子,让我们假设我们有一个数据集 D = ( t , x , y ),其中 t 是某个时间戳。 D 的时间上的第一个条目可能表现得像y≈3x+2,而最近的条目表现得更像y≈-x+1,这只是因为事情随着时间而改变。如果我们能够检测并量化这样的变化,那就太好了,例如通过找到一些满足y≈atx+b的时间相关函数 a ( t )和 b ( t )
为了了解我们如何做到这一点,让我们看一个具体的例子。
抽样资料
首先,让我们加载数据集:
*import pandas as pd
data = pd.read_csv(
'https://raw.githubusercontent.com/Garve/datasets/3b6b1e6fadc04e2444905db0a0b2ed222daeaa28/rolling_data.csv',
index_col='t'
)*
然后,我们可以看一看它:

图片由作者提供。
我们的目标是找到一个线性模型,在给定 x,即 y = ax + b 的情况下预测 y 。然而,仅从图中我们可以看出,由于以下观察结果,固定值对于 a 和 b 是不够的:
- 在 300 和 670 左右的时间内,蓝色和红色时间序列都增加,然后又同步下降。这表明它们是正相关的,这暗示着a0。
- 在时间 720 和 950 期间,蓝色时间序列先增加然后下降,而红色时间序列正好相反。这暗示着这些时间序列是负相关的,意味着a0。
这两点都表明斜率 a 必须随时间变化,这意味着我们更愿意处理一个依赖于时间的函数 a ( t ),而不仅仅是一个固定的 a 。
我们也可以在散点图中以不同的方式显示上面的图片,这样我们可以更好地理解实际数据集的样子:

图片由作者提供。
在这个表示中,您还可以看到回归线做了次优的工作。做线性回归
*from sklearn.linear_model import LinearRegression
X = data[['x']]
y = data['y']
lr = LinearRegression().fit(X, y)
print(f'intercept = {lr.intercept_:.5f}, slope = {lr.coef_[0]:.3f}')
# Output: intercept = 18.45587, slope = 0.593*
生产

图片由作者提供。
不是很合适。那么,怎样做才能更精确地描述 x 和 y 之间的联系呢?
可怜人的滚动回归
一个简单的解决方法是在一个连续的滑动窗口上进行几次较小的回归。听起来不错吧?它的意思如下:
- 您创建了第一个 w 观察值的较小子集,即从时间 0 到 w -1 。即第一次迭代中的滑动窗口。你在这个子数据集上做普通的最小二乘法,写下直线的斜率和截距。
- 你移动窗口一步,意味着它现在从时间 **1 到达w。在这个子数据集上使用普通最小二乘法。**
- 您将窗口移动一步,这意味着它现在从时间 2 到达 w+1 。在这个子数据集上使用普通最小二乘法。
- 你移动窗口一步,意味着它现在从时间 3 到达 w+2 。在这个子数据集上使用普通最小二乘法。
- …
你明白了:每个小数据集由 w 个连续元素组成,其中 w 也被称为(窗口* ) 长度。这是一个你可以随意摆弄的超参数。从图形上看是这样的( w = 3):*

数据集上长度为 3 的滑动窗口(蓝色),有 9 个时间步长,图片由作者提供。
编写这种滚动回归方法的简单方法如下:
*w = 30 # sliding window of length 30
slopes = []
intercepts = []
for i in range(len(data) - w):
X = data.loc[i:i+w, ['x']]
y = data.loc[i:i+w, 'y']
lr = LinearRegression()
lr.fit(X, y)
intercepts.append(lr.intercept_)
slopes.append(lr.coef_[0])*
绘制我们得到的斜率和截距
**
作者图片。
我们可以看到,斜率从正变到负再变回来是非常不规则的。截距似乎随着时间增加了一点。这很有趣,但是它可能取决于窗口长度吗?我们将它设置为 30 是相当武断的,那么为什么不尝试其他值,比如 200,看看故事是否会发生变化?
一般来说,以下情况成立:
窗口长度越大,图形越平滑。
这是因为窗口长度越大,每两个相邻的子数据集就越相似。如果窗口长度是 200,那么每两个相邻子数据集(至少)有 199 行是相同的。几乎相同的数据集意味着训练后几乎相同的模型,至少对于线性回归这样的确定性方法来说是如此。如果窗口长度仅为 2,那么每两个相邻的子数据集只有至少 50%是相同的,因此在这些数据集上训练的模型可以显著不同。让我们看看长度为 200 的滑动窗口的结果是什么样的。
**
作者图片。
我们可以看到,图形更加平滑,故事大致保持不变:斜率在零附近波动,截距随着时间的推移而增加。然而,曲线图差别很大,所以很难说斜率和截距实际上如何随时间演变。
总之,这种滚动回归方法在很大程度上取决于窗口长度,我不知道有什么好的方法来正确选择这个超参数,以获得真相。
因此,让我们研究一种更好的方法来处理变化的参数。像往常一样,贝叶斯挽救了局面。
贝叶斯滚动回归
首先,让我们回顾一下简单的贝叶斯线性回归是什么样子的。您可以在此了解更多信息:
***
第一次尝试
假设您知道该练习,请检查代码:
import pymc3 as pm
with pm.Model() as linear_model:
slope = pm.Normal('slope', sigma=1) # a
intercept = pm.Normal('intercept', sigma=1) # b
noise = pm.Exponential('noise', lam=1)
y = pm.Normal(
'y',
mu=slope*data['x'] + intercept, # the linear model equation
sigma=noise,
observed=data['y']
)
linear_trace = pm.sample(return_inferencedata=True)
这里应该没有什么惊喜。我们定义了一个斜率、截距和一个具有先验知识的噪声参数,并通过均值为 ax + b 的正态分布直接对输出 y 进行建模。
不幸的是,这个模型就像简单的线性回归一样糟糕,只是带有不确定性界限。那么,我们如何对随时间变化的事物建模呢?引入变化斜率的简单方法如下:
import pymc3 as pm
with pm.Model() as linear_model_2:
slopes = pm.Normal('slopes', sigma=1, shape=len(data))
intercepts = pm.Normal('intercepts', sigma=1, shape=len(data))
noise = pm.Exponential('noise', lam=1)
y = pm.Normal(
'y',
mu=slopes*data['x'] + intercepts,
sigma=noise,
observed=data['y']
)
linear_trace_2 = pm.sample(return_inferencedata=True)
使用这段代码,我们给每个时间步长赋予它自己的斜率和截距,因为我们定义的斜率和截距与数据集中的观测值一样多。
我希望你明白这是个糟糕的主意。
该模型定义,即使用shape=len(data),意味着所有参数相互独立。所有的斜率都是相同且独立的 N (0,1)分布(正态),这意味着两个相邻的斜率可能相距很远。例如,假设在一个时间步长中斜率为 2.41,而在下一个时间步长中斜率急剧变化为-2.8。由于随着时间的推移变化通常更平稳,这不是我们从现实世界的时间序列中所期望的。当然,拦截也是如此。
查看当前行为的另一种方式是,它相当于使用一个长度为1 的滑动窗口。每个斜率和截距都必须用单个数据点来估计,而且没有合理的方法来做到这一点。
高斯随机游动
解决方案是使两个相邻滚动窗口的参数以某种方式相关。如果某一时刻 t 的斜率为 a ( t ),那么下一时间步 t + 1 的斜率也不应远离 a ( t )。表达这一点的一种方式是通过对所有时间的标准偏差σ进行建模a(t+1)~N(a(t),σ**),对第一个斜率使用一些初始值,如a(0 用语言来说:
下一个斜率是旧斜率加上一些误差。
这就是所谓的高斯随机游走。您可以通过 NumPy 自己模拟一个
np.random.seed(0)
steps = 20 # length of the random walk
a = [0] # the initial slope, can be anything
sigma = 1 # the error
for t in range(steps):
a.append(np.random.normal(a[-1], sigma))
绘图a导致

图片由作者提供。
如果你稍微摆弄一下sigma,你会发现值越大,a内的跳跃越大,这是有道理的。你还可以看到的是,对于所有的 t 来说, a ( t+1 )总是接近 a ( t )。
PyMC3 模型
虽然在 PyMC3 中实现同样的逻辑并不太难,但是开发人员通过实现一个GaussianRandomWalk发行版让我们变得很容易。有了它,我们现在可以用 PyMC3 写下最终的模型了。整体造型和之前挺像的。我们只需要
- 引入两个高斯随机游走,一个用于斜率,一个用于截距,以及
- 这些高斯随机游走的两个噪声参数
以下是建议书范本:
with pm.Model() as rolling_linear_model:
# noise parameters
sigma_slope = pm.Exponential('sigma_slope', lam=1)
sigma_intercept = pm.Exponential('sigma_intercept', lam=1)
sigma = pm.Exponential('sigma', lam=1)
# Gaussian random walks
slopes = pm.GaussianRandomWalk(
'slopes',
sigma=sigma_slope,
shape=len(data)
)
intercepts = pm.GaussianRandomWalk(
'intercepts',
sigma=sigma_intercept,
shape=len(data)
)
# putting it together
y = pm.Normal(
'y',
slopes*data['x'] + intercepts,
sigma,
observed=data['y']
)
rolling_linear_trace = pm.sample(return_inferencedata=True)
与之前的简单线性回归相比,运行该模型需要一些时间,因为有许多参数也随机地相互依赖。不过,在你的机器上,这应该不到 15 分钟。
我们可以运行一个后验预测检查,看看这个模型是否通过
import arviz as az
with rolling_linear_model:
posterior = pm.sample_posterior_predictive(rolling_linear_trace)
az.plot_ppc(az.from_pymc3(posterior_predictive=posterior))
这输出

图片由作者提供。
这意味着该模型非常好地捕捉了观察到的数据,因为黑色的观察到的线正好在蓝色的后验预测管内。这辆 r 也表现不错:
az.r2_score(data['y'].values, rolling_posterior['y'])
# Output:
# r2 0.981449
# r2_std 0.000920
但是,请注意,这是培训绩效。该模型可能会也可能不会过拟合,但这不是我们在这里要讨论的内容。
总的来说,挺好看的。是时候提取模型对斜率和截距的了解了。
结果
由于这个提取过程不是完全显而易见的,所以让我向您展示一下我是如何做到的。
import matplotlib.pyplot as plt
# extract the means and standard deviations of the slopes
posteriors = rolling_linear_trace.posterior.slopes.values
slopes_means = posteriors.reshape(4000, len(data)).mean(0)
slopes_stds = posteriors.reshape(4000, len(data)).std(0)
# plot
plt.figure(figsize=(16, 8))
plt.fill_between(
range(len(data)),
slopes_means - 2*slopes_stds,
slopes_means + 2*slopes_stds,
alpha=0.33,
label='$\mu \pm 2\sigma$'
)
plt.plot(slopes_means, linewidth=1, label='$\mu$')
plt.title('Slope over time')
plt.xlabel('Time')
plt.legend()
您会收到以下内容:

图片由作者提供。
这看起来比以前好多了,对吧?它非常平滑,并且有很好的图案,当然这并不表示结果是正确的。但在这种情况下,我可以告诉你,结果是相当准确的,因为我自己创建了地面真相和数据集。让我把随时间变化的真实斜率也放入图中:

图片由作者提供。
这是拦截的结果。正如您在这里看到的,它们也是正确的:

图片由作者提供。
因此,使用高斯随机游走的贝叶斯滚动回归方法(多么好的一个词,嗯)在这种情况下工作得很好,在您的情况下也可能如此。每当您觉得参数可能会随时间或跨任何其他维度发生变化时,您都可以尝试一下!
结论
在本文中,我们已经看到,将参数模型中的参数视为固定参数有时是没有目的的。由于输入和输出数据之间的关系会随着时间的推移而变化,因此模型也必须能够调整其参数。否则,它可能会惨败。
我们已经讨论了一种简单的滚动窗口方法,这种方法易于理解和实现,但是非常不稳定,因为它取决于超参数窗口长度,而我们不知道如何正确设置。
作为补救措施,我们定义了一个贝叶斯滚动回归模型使用高斯随机游走。它运行良好,非常灵活。您可以扩展这个模型来包含更多的特性,但是您也可以固定一些参数,只让其中的一些发生变化。无论何时,当您想要可视化随时间的变化时,在您的清单中有这个模型是非常好的。
但是,请注意,该模型仅用于推理,即确定参数。预测未来是很困难的,因为随机行走的随机性会给你未来更大的不确定性。要创建预测,您可以尝试找到斜率、截距和所有其他参数随时间变化的公式,并在您的模型中使用该公式。在示例中,我们有a(t)= sin(t/20)/3 和 b ( t ) = √ t,,因此最终的模型方程为y= sin(t/20)/3 *x+√t .

图片由作者提供。***
我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!
作为最后一点,如果你
- 想支持我多写点机器学习和
- 无论如何,计划获得一个中等订阅量,
为什么不做 通过这个环节 ?这将对我帮助很大!😊
透明地说,给你的价格不变,但大约一半的订阅费直接归我。
非常感谢,如果你考虑支持我的话!
如有问题,在LinkedIn上写我!**
Rok 打败小众?磨咖啡的另一个角度
原文:https://towardsdatascience.com/rok-beats-niche-another-angle-to-grind-coffee-645e46102891?source=collection_archive---------21-----------------------
咖啡数据科学
给这些研磨看看从正确的角度,第 4 部分
之前的,我展示了韩国在口味和提取方面击败了小众。我以为我已经捕捉到了所有的变量,但是有一个我错过了。壁龛毛刺位于 15 度角,而毛刺位于 0 度角。这可以是另一个角度吗?


所有图片由作者提供
我做了一个快速的比较,将小生境设为 0,然后将韩国设为 20。我拥有的最简单的稳定平台是拿着一台电脑,因为手工研磨会使研磨机移动更多。我比较了研磨分布,一些样本镜头,然后几对镜头。

分布
在查看研磨分布时,我很惊讶利基在一个角度匹配韩国,反之亦然。有角度的毛刺会导致研磨分布的差异,但我没有考虑到会有多大的差异。


我们可以使用 LBP 和 K-means 聚类来查看粒子形状的相似程度。与 Rok 法线相比,生态位角度比 Rok 法线与角度以及生态位法线与角度更相似。

按颗粒大小划分,垂直与倾斜生态位差别很大,而 Rok 倾斜生态位更接近大于 500 微米的垂直生态位。这意味着较粗的颗粒在形状上更相似,这是之前发现的主要差异是韩国击败利基的根本原因。

绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**
第一组样本
我为每一个有角度和没有角度的研磨机拍了两张照片。当研磨机具有相同的角度时,它们具有相似的味道分数(最终分数)以及 EY/TDS。生态位(15 度)的 TDS 较高,但 EY 较低,因为它比其他生态位稍短。
****
就拍摄时间而言,没有什么特别的。TCF 是时候盖上过滤器了。

成对拍摄
我拍了 9 对照片,我把生态位角度设置为 0。每张图比较了某一角度的毛刺(壁龛通常是如何设置的)和台面上的毛刺(壁龛向后推 15 度)。
这个数据没有显示出这两个角度之间的趋势差异,所以它是不确定的。我本以为平行于桌面的毛刺会有更高的 EY 和更好的口感,但它们非常相似。

我真的很喜欢这两个研磨机,而且我没有考虑到研磨机角度是一个可能影响研磨分布的变量。似乎关于两个研磨机中的毛刺组,它们似乎仅在角度偏移上有所不同。这些数据确实存在于研磨机毛刺角度与性能的研究中,希望有一天,这些数据能够让普通人更好地理解研磨这一过程。
如果你愿意,可以在 Twitter 、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。
我的进一步阅读:
我未来的书
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改进浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡滤纸
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维修
咖啡评论和想法
咖啡实验
韩国击败利基零:第一部分
原文:https://towardsdatascience.com/rok-beats-niche-zero-part-1-7957ec49840d?source=collection_archive---------10-----------------------
咖啡数据科学
咖啡研磨机摊牌
早在一月份,我买了一个小生零。虽然我热爱我的 Rok 手动研磨机,但用它进行了 5 年的多次拍摄和咖啡实验已经让我精疲力尽了。我想要一个电动研磨机,希望能升级。出于某种原因,我当时没有费心做一个并排的比较,我把韩国磨床存放起来,直到我的夏季旅行。

所有图片由作者提供
我带着韩国磨床去了我的亲家,在那里我有另一台像我家一样的 Kim Express 机器。我立即注意到我正在拉更高的提取镜头。我本来打算把韩国磨床留在那里,但我改变了主意,这样我就可以进行并排比较。
我把这个比较分成三个部分,因为我想更深入地了解为什么研磨机的性能如此不同。
- 第 1 部分包括使用两个研磨机的 19 对镜头的配对比较,以及每对镜头的相同镜头参数。
- 第 2 部分检查粒子分布,看看是否有更好的理解发生了什么。
- 第 3 部分甚至更深入,使用 K-means 聚类对性能差异进行理论化,然后用一个 sifter 进行一个简短的实验来帮助验证该理论。
绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
使用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**
在利基市场拨号
一开始,我认为我可能需要磨得更细,所以我花时间拨入。通常,我发现设置 13 是最好的,这也不例外。设置 13 韩元的味道和提取。场景 14 是一个美味的镜头,但就提取而言,它并不令人印象深刻。
****
设定为 13 时,总时间稍长,但没关系。

我没有在韩国拨号。我去过一个比 0 更好的地方,在过去的三年里我一直呆在那里。它在那个设置上已经太久了,拧入的部分需要更换。

螺丝孔右上方带有螺丝凹痕的底部毛刺块。
比较
我使用散点图来比较性能。很容易看出这些点是在线上还是线下。如果是在线上,两者表现差不多。
****
我根据咖啡烘焙分解了这些数据,结果是相似的。韩国击败了纸,我的意思是,利基。
****
对于一般的统计,我有这个小表。我计划做 30 双,但是我在韩国弄坏了传动齿轮。

对于口味(最终得分),结果几乎没有统计学意义。更多的数据可能会显示出统计学意义。我观察了两个异常值,p 值下降到 0.05 以上。
****
在工作流程方面,我更喜欢小众,因为电动研磨机部分。我很兴奋,韩国声称是一个更昂贵的电动磨床相同质量的磨床是真的。这项研究也有助于巩固我想继续使用我的韩国研磨机,特别是最好的烘烤。
当我探索其中的原因时,我真的开始更深入地理解咖啡研磨机。在我看来,研磨机之间的客观比较很少,部分原因是比较它们很困难。在接下来的两个部分中,我将深入探究原因和条件。
如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在媒和订阅关注我。
我的进一步阅读:
我的未来之书
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改进浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡滤纸
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维修
咖啡评论和想法
咖啡实验
韩国击败利基零:第二部分
原文:https://towardsdatascience.com/rok-defeats-niche-zero-part-2-acdbae134018?source=collection_archive---------16-----------------------
咖啡数据科学
咖啡研磨机摊牌,粒子分布
在第一部分中,我们发现 Rok grinder 比 Niche 更适合制作浓缩咖啡。我想知道为什么,所以我收集了一些地面粒子分布来寻找线索。我看了一些烘烤以及有和没有流量控制盘的壁龛。
对于所有这些烘焙,来自韩国的研磨粉比来自利基市场的研磨粉提取率更高。
2021 年 5 月 24 日烧烤


与壁龛相比,这种烘烤对韩国来说向右移动了,所以韩国给出了更粗糙的研磨。我试着在壁龛上变得粗糙,但是提取率下降了。
5/18/2021
这种烘烤有非常相似的分布,但韩国仍然拉得更高。

6/3/2021
故事和以前一样。我在第 1 部分中扫了一些研磨参数,这仍然是最好的。没有一个明确的答案来解释为什么韩国会胜过利基市场。

控制盘
韩国没有控制盘,所以我想我会检查一下。流量控制盘也没有显著改变分布。在这种情况下,Rok 要粗糙得多,但当我试图将粗糙度与小生境相匹配时,我的提取产量下降了。

我还检查了另一次烘烤的分布,无论有没有控制盘,它们几乎是一样的。

不幸的是,这些发行版最让我困惑。这意味着粒子分布只是故事的一部分。也许,粒子本身有不同的形状,这是我在第三部中探索的。
如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。
我的进一步阅读:
我未来的书
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改进浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡滤纸
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维修
咖啡评论和想法
咖啡实验
韩国击败利基零第 3 部分
原文:https://towardsdatascience.com/rok-defeats-niche-zero-part-3-2fbcc18397af?source=collection_archive---------18-----------------------
咖啡数据科学
咖啡研磨机摊牌,根源
之前我发现 Rok grinder 在口感和提取上都比小众 Zero 好。然而,当调查研磨分布时,我没有看到可以解释口味和提取差异的巨大差异。所以我想深入挖掘,我转向了模式识别。

我用线性二元模式(LBP)来描述粒子,然后我用 K-means 聚类对它们进行分类。我观察了不同大小的颗粒,以了解大小相似的不同颗粒之间的差异。
粒子分布的 LBP + K 均值聚类
我按颗粒直径分解了每种研磨分布,然后比较了这些颗粒聚集的直方图。从一些初始数据来看,大于 500 微米的颗粒差异似乎很大,所以我将大于 500 微米和小于 500 微米的颗粒分成两部分。


对于小于 500um 的粒子,它们非常相似,并结合成相似的簇。对于大于 500 微米的颗粒,小生境仅分为 8 个簇,而 Rok 则更分散,表明颗粒形状更为多样。
理论:韩国研磨机生产的 500 微米以上的研磨料比利基零研磨料更好。
筛
为了验证这个理论,我用一个 500 微米的筛子从每个研磨机中筛出咖啡。然后我将 Rok 的粗颗粒和小生境的细颗粒重新混合,反之亦然。


以下是每台研磨机的分布情况,使用筛分重量作为成像颗粒重量的参考。

以下是<500um particle distributions:

Here are the >500 微米的颗粒分布:

混合
通过混合这些筛过的粉末,我能够分离出作为潜在问题的粗颗粒。



我做了这些混合镜头的最终分布,分布非常相似。

绩效指标
我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。
最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**
表演
使用韩国粗磨和利基细磨的结果是在味道和提取相似的镜头作为韩国地面自己。反其道而行之会导致比单独的小生境更差的味道,但是这一次的产出与投入的比率略高,为 1.5:1。其他镜头的比例是 1.3:1。
****
将最终数字放入网格中,以帮助显示与汇总水平的差异。

就总时间而言,时间似乎更多地与韩国的罚款联系在一起,而不是任何其他变量。

这个调查对我来说是最有趣的,因为我还没有找到比较研磨机的好方法。通常,人们使用分布曲线,但当它们匹配时,如何量化差异?我对应用这项技术来帮助区分高端研磨机非常感兴趣。
编辑:在这篇文章中,我最后看了磨床角度。
如果你愿意,请在 Twitter 、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。也可以在 LinkedIn 上找到我。也可以在中和订阅关注我。
我的进一步阅读:
我未来的书
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事首页
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡滤纸
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维修
咖啡评论和想法
咖啡实验
人工智能在实现可持续发展目标中的作用
原文:https://towardsdatascience.com/role-of-ai-in-achieving-sustainable-development-goals-7b7556ee0efa?source=collection_archive---------9-----------------------
人工智能如何用于推进可持续发展目标的总结
PS。这是一篇观点文章。所有观点都是我自己的。
目录:
- 什么是可持续发展目标
- 人工智能和环境成果
- 人工智能和社会结果
- 人工智能和经济成果
- 结论

由若奥·维托尔·马尔西利奥在 Unsplash 拍摄的照片
什么是可持续发展目标
可持续发展目标是 17 个相互关联的全球目标的集合,旨在作为“为所有人实现更美好、更可持续的未来的蓝图”。可持续发展目标于 2015 年由联合国正式确定,预计将于 2030 年实现。
那么,人工智能是如何帮助或阻碍这些目标的呢?让我们考虑一下人工智能对环境、社会和经济结果的潜在好处和风险。
人工智能和环境成果
人工智能在环境领域的应用越来越多,包括能源(如智能电网)、农业和监控领域。物联网硬件的最新进展以及随之而来的视觉和传感器融合中的人工智能算法使这成为可能。

照片由埃里克·穆尔在 Unsplash 上拍摄
例如,在智能城市背景下,引入和潜在采用电动汽车和智能电器可以提高发电的效率和可靠性。此外,人工智能可以通过敏锐地管理风险和有效地弥合供需差距,将可再生能源纳入智能电网。
然而,这些人工智能技术中的一些在计算上可能是昂贵的。在那些仍然用脏煤发电的国家,效率的提高可能会被过度的污染所掩盖。据估计,到 2030 年,仅信息和通信技术(ICT)的总电力需求就可能占到全球能源的 20%,而目前仅为 1% [1]。
因此,绿色增长是必不可少的,它需要建立一个更高效、基于可再生能源的数据中心,并通过先验知识将人类知识嵌入到现有模型中。这是因为人类大脑消耗的能量比当前的人工智能模型少得多(并且效率也更高),并且在这种集成上的创新(例如,基于物理学的深度学习[2])不仅对环境有益,而且对那些特别容易受到基于人工智能系统的过度污染影响的社区也有益。
人工智能和社会结果
不幸的是,复杂的人工智能系统仍然很昂贵,低收入家庭和弱势群体可能无法获得。如果政府未能监管人工智能的好处如何在不同的利益相关者之间分配,不平等加剧的风险将越来越大。例如,大生产商可能会受益,而小农户可能会被甩在后面,因为后者可能负担不起任何可以提高产量和生产率的昂贵的人工智能系统[3]。

亚辛·优素福在 Unsplash 上的照片
此外,如果没有足够的透明度和多样性,现有的各种种族主义、性别陈规定型观念、仇外倾向和仇恨犯罪可能会加剧[4]。一些研究[4,5]表明,我们的大多数人工智能系统,特别是在 NLP 和计算机视觉领域,仍然显示出系统的种族主义和偏见的迹象。这是因为用于训练的数据已经受到现有社会偏见的污染,并且在数据工程期间没有明确的去偏见程序,曾经客观的机器可能会采用我们主观的和不相关的偏见。
因此,透明度和多样性是保持我们的模型尽可能客观的关键。一种方法是权力下放程序,在这种程序中,人工智能技术的实施可以在不同文化、民族、种族和性别背景的团队中进行。
人工智能和经济成果
人工智能补充了一个人的工作,这样一个人可以获得更大的产出,提高自己的生产力水平。从让农民知道何时、何地以及如何种植的智能农业技术,到可以监控罪犯和潜在入侵者的智能安全算法。

rupixen.com 在 Unsplash 上拍照
然而,如果目前的轨迹继续下去,未来的市场仍然严重依赖于数据相关的经济,那么收入差距可能会大大增加,特别是在低收入和中等收入国家,那里升级人力资本的资源有限[5]。例如,自 20 世纪 70 年代以来,美国拥有研究生学位的人的工资上涨了约 25%,而由于自动化和有利于前者的新工作的创造,普通高中辍学者的工资下降了 30%。
虽然有些人可能会认为创造性破坏的过程会自然地造成这种隔离,但政府肯定可以加强努力,尽量减少这种影响。再培训和再技能培训将是弥合不平等差距的关键,正如新加坡通过其职业未来计划以及许多其他政府举措所做的那样。
结论
总之,识别风险是确保人工智能进步的收益是公平和可持续的第一步。只有承认这些缺点,我们才有力量和意识来创新更友好、更可持续的下一代人工智能技术。
参考资料和进一步阅读
[1] Jones,n.《如何阻止数据中心吞噬世界电力》.性质 561 ,163–166(2018)。
[2] Raissi,m .,Perdikaris,P. & Karniadakis,G. E .物理学通知深度学习(第一部分):非线性偏微分方程的数据驱动解。 arXiv:1711.10561 (2017)。
[3] Wegren,S. K,“掉队的”:当代俄罗斯农业中的小农。j .阿格拉。昌。 18 ,913–925(2018)。
[4]t . Bolukbasi,Chang,k . w .,邹,j .,Saligrama,v .和 Kalai,a .男人对于计算机程序设计员就象女人对于家庭主妇一样?去偏置词嵌入。神经 Inf。过程。系统。 29 ,4349–4357(2016)。
[5]比西奥,《希望的载体,恐惧的来源》。聚光灯持续。开发。77–86 (2018).
[6] Brynjolfsson,E. & McAfee,A. 第二个机器时代:辉煌技术时代的工作、进步和繁荣 (W. W. Norton &公司,2014 年)。
数据在隐式正则化中的作用
原文:https://towardsdatascience.com/role-of-data-in-implicit-regularization-a37cdd6cce2e?source=collection_archive---------40-----------------------
实践教程
使用勒让德多项式作为特征可以显著提高收敛性

照片由德鲁·格拉汉姆在 Unsplash 上拍摄
TL;速度三角形定位法(dead reckoning)
在本文中,我们重温了基于梯度下降的优化算法的一个明显的隐式正则化效应。我们认为这是教科书上的过度拟合的例子,你可以在 scikit-learn 网站上找到。我们证明,当我们使用先验不相关多项式作为新特征时,隐式正则化效应消失。
过度拟合和正则化
在机器学习中,过度拟合是指一个经过训练的模型非常适合数据,但对看不见的数据不能很好地概括。一个相关的概念是不适定问题,当训练数据的微小变化导致模型参数的巨大变化时,不适定问题导致模型不稳定【1】。这种情况会阻止模型对来自与训练数据相同分布的数据进行归纳。这个问题可以通过正则化来解决,这是一组帮助创建模型的技术,不仅适用于训练数据,也适用于相同分布的未知数据。但是,请注意,一般来说,正则化并不能保证泛化。
文章中给出了一个过拟合的好例子:
https://scikit-learn.org/stable/auto_examples/model_selection/plot_underfitting_overfitting.html
这是一个回归问题,用一个简单的函数来描述基本事实
添加了高斯噪声。我们正试图用不同次数的多项式来逼近它。我们观察到,对于较低次数的多项式,该模型不太适合数据。这也被称为欠配合。相反,如果我们使用高次多项式来近似函数,则模型很好地拟合数据,但是曲线并不平滑,并且与我们试图学习的地面真实函数非常不同。下面是不同程度参数值的三个图。

在本例中,我们看到一次多项式对数据拟合不足,15 次多项式对数据拟合过度,而 4 次多项式似乎效果最好。
隐式正则化
然而,请注意,在这个例子中,我们使用线性回归的封闭形式的解决方案。如果我们决定通过改变solver 参数采用基于梯度下降的方法:
对于 15 次多项式,我们得到一个非常不同的图像:

在这个图中,我们尝试了四个不同的精度值(这决定了优化算法进行多少次迭代)。我们可以看到,几乎所有的预测曲线都非常接近真实函数,即使我们使用了更高次的多项式。诸如此类的例子让一些人(包括本文作者)相信基于梯度下降的优化过程具有正则化效果。隐式正则化是一个活跃的研究领域,其对泛化的影响尚未完全确定[2]。
然而,如果我们从另一个角度来看待这一现象,我们可以将我们的观察视为优化算法未能达到全局最小值。这是学习算法的问题(或特征)吗?不一定。原因可能在数据上。为了证明这一点,让我们考虑特征之间的相关性:

我们看到生成的特征高度相关。为了去相关特征,许多人使用像 PCA 这样的方法。然而,我们更喜欢先验不相关的特征。我们将使用勒让德多项式,而不是使用 x 的幂作为附加特征。
构建勒让德多项式
为简单起见,考虑区间[-1,1]中定义的函数。我们将使用与所有低次多项式不相关的多项式。设 f(x)是自变量 x 的先验分布的概率密度函数,那么两个函数 a(x)和 b(x)是不相关的,如果:
因此,我们的计划是选择与分布 f(x)不相关的多项式:
为简单起见,假设独立变量 x 的均匀先验分布。在贝叶斯术语中,它被称为无信息先验,通常在我们对变量没有任何先验信念时使用。那么等式就变得简单了:
我们将从零阶多项式开始,通过选择与所有其他低阶多项式正交的多项式来逐步提高。无需实际计算,我可以给你前 10 个多项式的结果:

来源:https://en.wikipedia.org/wiki/Legendre_polynomials
这些多项式被称为勒让德多项式,用于数学和物理的许多领域。以下是前六次勒让德多项式的曲线图,供您参考:

来源:https://en.wikipedia.org/wiki/Legendre_polynomials
然而,请注意,这不是多项式的归一化形式,因为按照惯例,P_n(1) = 1。
在numpy和scipy Python 库中都有一种计算勒让德多项式的有效方法。在我们的示例中,我们将添加基于勒让德多项式的特征,并将解决我们的回归问题:
在上面的代码中,我们将输入转换到区间[-1,1]中,然后基于直到指定次数的所有次数的勒让德多项式创建要素。结果真的很惊人:

仅用 13 次迭代,该模型就能达到全局最小值并匹配封闭形式的解。
结论
在本文中,我们考虑了高度相关的特性阻止优化算法找到全局最小值的情况。我们使用先验不相关的勒让德多项式构建特征,而不是使用 PCA 去相关。实验表明,优化算法能较快地收敛到封闭解。这表明所谓的隐式正则化可以是数据的特征,而不是优化算法,并且它可以随着适当的数据预处理而消失。本文的代码可以在我的 github 库中找到。
参考
[1]弗拉基米尔·瓦普尼克..统计学习理论的本质。:斯普林格,2000 年。
[2]阿罗拉、桑吉夫、科恩、纳达夫、胡、魏、罗、俞平。"深度矩阵分解中的隐式正则化." arXiv:1905.13655 ,2019。
Java 全栈开发人员的角色和职责
原文:https://towardsdatascience.com/roles-and-responsibilities-of-a-java-full-stack-developer-d365e8ae2e08?source=collection_archive---------13-----------------------
正在寻找 Java 全栈开发的职业?在你选择它之前,请阅读这篇文章!

照片由 olia danilevich 发自 Pexels
概述
这篇博客将带您了解 Java 全栈开发的完整过程。你将深入了解什么是 java 全栈,成为一名 Java 全栈的要求是什么,以及这个角色的期望薪资。
先说全栈开发,有两个部分,一个是前端开发,一个是后端开发。谈到全栈开发,它包含了开发人员将要处理的应用程序栈,并且他将处理完整的端到端应用程序栈。
前端应用:
当涉及到应用程序的前端模块时,开发人员必须掌握 HTML、CSS 和 Javascript。除了了解这些基本技术,大多数公司都在寻找 React、Vue 和 Angular 这样的框架来处理他们的前端模块。
前端应用的使用:
- 以提供其前端模块的结构良好的视图。
- 将页面分割成不同的部分,并尽可能重用这些部分。
- 利用样板代码来执行更快的开发。
- 拥有标准的用户界面外观。
- 高效地维护代码。
后端应用
后端应用模块通常用 Java 编写。要构建后端模块,您需要了解核心 java,Jakarta Enterprise Edition 以前的 j2ee,其中涉及 servlets、Rest、JSON API、异步、来自服务器的事件。
有了这些框架,您将需要 spring framework,这是一个事实上的 java 框架,用于企业应用程序的开发,因为它有广泛的特性集。Spring 最初是作为 MVC 出现的,但是现在它已经发展成为一个完整的生态系统。
Spring 在编写单片、无服务器应用、微服务、事件驱动和反应式应用时非常有用。它将一切都包含在一个框架中。
后端应用的使用:
- 更快的开发过程和更短的营销时间。
- 创建无错误和更好的应用程序。
- 应用程序的克隆和运行测试环境。
- 维护安全。
数据库的使用
有许多数据库支持不同的数据模型,它们是:
- 关系数据库
- 图形数据库
- 面向文档的数据库
- 键值数据库
- 宽列数据库
每个数据库都有自己的特点,并根据应用程序的要求加以利用。一个全栈开发者需要一个数据库来满足开发应用的需求。MongoDB 和 MySQL 是应用程序开发中使用的重要数据库。数据库的选择不是基于受欢迎程度,而是基于特定用例的需求。
使用网络应用架构
在 web 应用程序和软件架构开发中,你将设计 web 应用程序架构中涉及的组件。您应该了解不同的架构风格,如对等分散、客户端-服务器、数据流基础、高可用性、微观基础、负载平衡和高可伸缩性。
版本控制
版本控制系统帮助您管理项目文件,并让您跟踪用户工作的所有历史。一些流行的版本控制系统有 Git、Subversion 和 Github。这些有助于管理项目文件,并且用户将具有查找其他代码、发现错误和建议更改的功能。
敏捷的利用
如果你是个新手,还没有从事过敏捷方法论的工作,那么你可以跳过它。敏捷是一种项目管理方法,你可以在处理项目时与项目管理团队一起学习。
作为个人贡献者的角色
作为一名全栈开发人员,你将被要求在大型应用程序的开发中作为唯一的贡献者,而不依赖于团队中的任何其他程序员。要构建一个大型应用程序,你需要有从头开发应用程序的经验。
全栈开发者的职责:
- 使用不同的前端技术构建交互式用户界面。
- 应该能够设计使用不同技术从服务器检索数据的健壮的后端架构。
- 创建能够抵御中断并持续工作的数据库和服务器。
- 通过创建在不同平台上工作的应用程序来确保跨平台兼容性。
- 基于应用程序的类型,开发人员负责 API 的创建。
- 开发人员负责构建满足消费者需求的灵活应用程序。
全栈开发者工资:
每个人都知道,全栈开发人员的工资因地区而异,也因他被分配的职位而异。根据薪级表,美国全栈开发人员的平均基本工资为每年 75057 美元。在印度,平均基本工资为每年 593,295 印度卢比。
结论
全栈开发人员的职业生涯充满挑战,不可能一蹴而就,需要大量的努力和耐心来掌握不同的技术。
在期货曲线上滚动——连续期货价格
原文:https://towardsdatascience.com/rolling-on-the-futures-curve-continuous-futures-prices-99382ee4bb4e?source=collection_archive---------9-----------------------
使用 Python 创建自定义的连续期货价格时间序列,用于回溯测试和交易。

M. B. M. 在 Unsplash 上拍摄的照片
放弃
本文不提供投资建议,其中的任何内容都不应被理解为投资建议。它为那些不需要建议就能做出投资决定的个人提供信息和教育。
本文包含的信息不是也不应被解读为购买或出售任何证券的要约或建议,或征求购买或出售任何证券的要约或建议。它不是,也不应该被视为使用任何特定投资策略的建议。
在今天的资本市场上,期货提供了一种最具资本效率的交易各种资产类别的方式。它们的用途广泛,从对冲未来汇率风险,到直接持有大宗商品头寸,再到做空股指波动。
从历史上看,尽管期货的资本效率非常高,而且相对于名义保证金而言,要求的保证金相对较低,但这些名义保证金的绝对规模意味着它们不适合账户规模较小的散户投资者。
近年来,多个小型期货合约(小型和微型)的开发和上市极大地改变了这一局面。股票指数、波动性、石油、玉米和其他大宗商品甚至比特币的期货合约规模较小。这使得散户投资者对这一资产类别很感兴趣,尤其是从系统投资的角度来看。
https://www.investopedia.com/terms/f/futures.asp
挑战
系统地回测和交易期货策略有其自身的挑战,主要的困难是从基础期货创建一个连续的时间序列。不同到期的合约很少以相同的价格交易,如果它们的价格只是缝合在一起,就会导致时间序列的跳跃。
举个例子,让我们看看 2021 年 6 月和 7 月到期的 VIX 期货合约。6 月合约于 6 月 16 日到期。
如果我们只是在滚动日期从一个期货切换到下一个期货,并将价格时间序列拼接在一起,下图中 6 月 16 日的跳跃(用红色标记)完全是两个不同水平的合约交易的产物,并不代表市场的实际行为。
缝合时间序列显示,从 6 月 15 日的 17.1 跃升至 6 月 16 日的 19.625,涨幅为 14.8%,而 7 月期货合约的变化实际上仅为 0.3%!

VIX 期货 6 月和 7 月 21 日的时间序列

VIX 期货价格快照(作者图片)
很明显,引入这样的人为跳跃可以完全改变任何形式的数据分析或对这一时间序列进行的回溯测试。
解决方案
有各种各样的方法可以用来解决这个问题,以便获得适合于回溯测试和分析的时间序列。最常见的是巴拿马调整、比例调整和使用永久展期。这些方法各有利弊。让我们看看它们中的每一个以及它们使用 python 的实现。
巴拿马调整
这种方法通过在滚动日期将每个以前的合同移动期货价格的差异来消除不同期货合同之间的差距。在我们上面的例子中,7 月期货在滚动日期的价格是 19.625,6 月期货的价格是 16.38,这意味着滚动前的所有价格都向上移动了 3.245。
执行巴拿马校正的简单 python 函数如下所示:
应用巴拿马调整的结果是这个价格时间序列。

使用巴拿马调整后的期货时间序列
与缝合的时间系列完全不同!
这是一个非常简单的方法,但有一些缺点。主要问题是,它引入了趋势偏差,这可能导致价格大幅波动。在某些情况下,这可能导致旧合同的负价格。时间序列中的相对价格信息也有损失,因为这种变化是绝对的。
然而,这是最常用的方法之一。
比例调整
与巴拿马法使用的绝对偏移不同,比例调整法使用旧价格的相对调整。这提供了一个连续的时间序列,不会引入任何偏差。
然而,这种方法的问题是,任何依赖于绝对价格水平的策略都需要以类似于时间序列的方式进行调整,这需要非常小心,因为使用这种方法非常容易引入错误。

使用比例调整后的期货时间序列(作者图片)
永久展期
这种方法使用两种期货的线性组合来进行 x 天的滚动。例如,如果您将滚动 5 天,在第 1 天,您将从旧合同滚动 20%到新合同,旧合同的风险敞口为 80%,新合同的风险敞口为 20%。第二天,旧的有 60%,新的有 40%,以此类推。到第 5 天,你将完成你的滚动。
虽然这种方法提供了非常平滑的过渡,但其主要缺点是在实际交易中,人们需要在所有这些天进行交易,并可能导致更高的交易成本。

使用永久展期后的期货时间序列(图片由作者提供)
结论
在这篇文章中,我介绍了三种不同的方法来创建一个连续的期货时间序列,用于回溯测试和分析。所有这些方法都有各自的优缺点,最终取决于您的具体应用,哪种方法效果最好。然而,这应该给你一个好的起点。
如果你想了解更多期货回溯测试和交易的复杂性,请查看 Quantra 的 12 小时综合课程,学习如何用 python 实现期货交易自动化。
https://quantra.quantinsti.com/course/futures-trading/?ref=stefanharing
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
基于深度学习的罗马图书馆读者评论分析
原文:https://towardsdatascience.com/romes-libraries-readers-comments-analysis-with-deep-learning-989d72bb680c?source=collection_archive---------29-----------------------
实践教程
主题建模、情感分析和读者聚类,以获得对用户偏好的洞察并执行量身定制的推荐

照片由尼古拉斯·帕丁在 Unsplash 上拍摄
简介
这篇文章描述了对罗马图书馆的读者评论开放数据集的分析,该数据集由Istituzione Biblioteche di Roma公开发布。
该分析利用主题建模技术在读者的评论中寻找重复出现的主题,从而通过推理确定所借书籍的主题和读者的兴趣。此外,执行情感分析以确定客户评论是正面还是负面的。最后,使用读者数据(年龄和职业)通过聚类技术实现客户细分。
这提供了关于借阅书籍的主题、读者情绪和不同读者群的见解。除此之外,这些信息将用于在两种不同的场景中执行建议 :
- 按题目推荐:
1.1。在中找到书名最相似的题目**
1.2。返回按降序排序的书名**评论情感评分**** - 推荐由用户(当我们没有偏好的主题,但仍有一些关于读者的信息时):
2.1。对读者数据(年龄和职业)执行聚类
2.2。为新用户
2.3 找到所属的集群。返回按评论情绪得分降序排列的书名。****
数据准备和探索性数据分析
我们从导入所需的库开始:
然后我们加载数据集(2021 年 11 月更新):

图片作者。
我们主要对以下栏目感兴趣:
- " Descrizione commento ":将用于主题建模和情感分析的完整用户评论。
- " Titolo ":素材的标题(书,电影,..)由客户借用,也是审查的主题。
- " Età utente ":客户的年龄,以年为单位。
- " Tipo utente ":客户的职业。
值得注意的是,数据集中的一列收集了用户给产品的一个分数,从 1 到 5。然而,在 15636 条总评论、中,只有 5.2%** 显示该分数,因此该信息将不被使用:**

图片作者。
正在审核的产品为图书占 78.7% ,音像(如电影)占 12.44% ,电子资源占 8.86% :

图片作者。
通过观察客户,我们注意到他们的平均年龄为 49 岁(只有 25%的总体评论是由 38 岁以下的读者撰写的),并且几乎没有缺失值:

图片作者。
大多数客户都有职业,最常见的类型是雇员(" impiegato ",31.58%),而学生(" studente ")仅占客户群的 19.49%;

图片作者。
根据职业类型的年龄分布,我们还可以观察到学生的年龄(平均标准:26±8,Q1–Q3:25-32)低于雇员(平均标准:51±8,Q1–Q3:44–57)或工人(平均标准:50±9,Q1–Q3:47–56)和退休人员(平均标准:68±5,Q1–Q3:62–71)。

图片作者。
主题建模
读者评论不与任何标签相关联,因此它们需要用无监督的方法来分析。
为了在评论中找到语义相似的结构,我们将使用 BERTopic,这是 Maarten Grootendorst 的主题建模技术。
正如 author⁴所解释的,算法的主要步骤包括嵌入的文档,其中利用了 bert⁵;然后 UMAP⁶到降低嵌入维数,否则将导致较差的聚类性能;用于聚类的 HDBSCAN⁷,以及最后,通过将 TF-IDF 应用于主题内的所有文档(而不是应用于单个文档)来定义主题表示,基本上将主题视为文档本身(因此得名,基于类的 TF-IDF):通过这种方式,得到的重要单词(以及相关分数)提供了有意义的、可解释的主题描述。****

使用 UMAP 在 2D 空间上投影的基于类别的 TF-IDF 主题表示可以被动态地探索。图片作者。
我们现在观察读者评论中最常出现的 25 个话题。根据基于类别的 TF-IDF 得分,主题名称由最具代表性的单词组成,通过查看它们的频率,我们可以获得关于客户阅读内容的见解:

客户评论中最常出现的 25 个话题。图片作者。

图片作者。
例如,如果我们从顶部观察表格,我们会注意到所有评论中的 5.27% 与电影(主题 1)相关,随后是 3% 与儿童书籍(主题 2)相关的评论,以及 1.8% 与社会经济学读物(主题 3)相关的评论。
我们还可以推断关于外国文学或国家的趋势或偏好,其中日本是所有评论的 0.85% (主题 7)的对象,而俄罗斯是 0.57% (主题 14)的对象。
我们还可以看到大量关于罗马历史和建筑的评论( 0.84% ,话题 8)。或许,这可能与我们观察的地点有关(罗马图书馆的读者评论)。
最经常出现的主题所涵盖的评论比例较低,这背后的原因可能会引起问题。直觉上,我们可能期望最经常出现的主题能够解释大多数评论(帕累托原则)。这一发现至少有两个主要原因:
- 大量检测到的主题**:在数据集上的重复实验总是产生数量一致的主题,在 130 到 145 之间变化。如果这种对语义差异的高度敏感性产生了过于分散而难以解释的结果,则可以减少主题的数量。减少话题有不同的方法。我们可以通过它们的层次结构来观察主题的相似性,以及它们如何相互关联,例如通过topic _ model . visualize _ topic():

尽管由于主题标签之间的重叠而在该图中不太明显,但是可以观察到关于音乐的主题(“musica_orchestra_compositori_…”)非常类似于关于爵士乐的主题(“jazz_blues_melodie_…”)。或者,它们可以被认为是一个不同的或一个单独的主题(从某种角度来看,主题建模是相当主观的)。根据我们观察树状图的层次级别,可以随意调整主题的数量来调整输出。图片作者。
- ****离群值的存在:ber topic 中使用的聚类算法 HDBSCAN 并不强制将观察值划分到聚类中,从而导致在主题 index -1 中收集离群值。
我们最后将主题保存到一个新的 dataframe 列中:
情绪分析
我们对读者的评论进行情感分析,通过使用 HuggingFace⁹.上的feel-it-italian-sentiment⁸模型来确定评论是正面的还是负面的
该模型在一个新的数据集上对翁贝托·⁰模型进行了微调: FEEL-IT ,这是一个新颖的意大利 Twitter 帖子基准语料库。
我们可以用几个句子来测试模型输出:

并预测评论的情绪。这保存在新的 dataframe 列中:
值得注意的是,我们通过变量 max_w 限制了每个评论的情感分析所考虑的字数。
我们还可以观察读者职业的平均情绪,证实工人(年龄:50±9 岁)和学生(年龄:26±8 岁)表达了最积极的情绪,而家庭主妇(年龄:57±6 岁)、管理人员(年龄:62±3 岁)和退休人员(年龄:68±5 岁)在产品评论中表达了最不积极的情绪:

图片作者。
读者聚类
到目前为止,我们利用自然语言处理技术对读者评论进行了主题建模和情感分析。
我们现在根据客户的特征(年龄和职业)对他们进行聚类,以便以后在没有偏好主题或兴趣的情况下实施推荐。
由于观察值包含数字(年龄)和分类(职业)变量,我们将使用 k-prototypes 算法。
****注意:当我们通过用平均值替换缺失的年龄值来估算它们时,我们不执行进一步的预处理(年龄是我们使用的唯一数字变量),但是我们也可以对其进行缩放或应用变换以使其更像高斯,例如 Yeo-Johnson 变换。

图片作者。
我们通过夏皮罗检验来检验年龄是否呈正态分布:
我们使用肘方法来确定集群的数量:

图片作者。
我们根据对图上肘部的观察,用 4 个聚类拟合模型,然后将信息保存在新的 dataframe 列中:
我们现在可以通过观察年龄分布和每个聚类中最常见的职业来检查所获得的聚类:

图片作者。
我们可以将集群总结如下:
- ****n0:60 岁以上退休:年龄在 64.6±5.4 岁之间,最经常从事的职业“退休人员”(28.5%)和“雇员”(24.5%)。
- n 1 : 三十多岁的学生和员工:年龄在 31.6±3.9 岁之间,最经常出现的职业“学生”(65.8%)和“员工”(10.6%)。
- n 2 : 四五十岁的工人:年龄在 48.2±4 岁之间,最经常从事的职业是“雇员”(55.2%)和“闲人”(13.3%)。
- n 3 : 青年学生:年龄在 13.8-4.9 岁之间,最经常出现的职业“学生”(93.1%)。
还可以直观地检查职业按类别的分布:

图片作者。
****年轻学生(第 3 组)在评论中表现出最积极的情绪(0.82±0.37),而 60 岁以上的退休人员或在职人员(第 0 组)表现出最不积极的情绪(0.62±0.4):

图片作者。
推荐
按主题推荐
让我们考虑一位顾客问图书管理员:
你能推荐一些关于旅行的东西吗?
或者让我们想象一下,同一个客户在一个在线图书馆目录上进行类似的查询。
由于对客户评论进行主题建模,我们可以找到与感兴趣的论点最相似的主题,然后在该主题中推荐最受好评的标题。
因此,我们定义了一个推荐类,它将主题模型和搜索查询作为输入,并提供方法来:
- 确定最相似的主题,
- 通过单词云图表显示其表现形式(基于类别的 TF-IDF 单词得分),以及
- 根据话题相似度和情感评分推荐前 n 个标题:
例 1: vacanza(休假)
搜索度假( vacanza )会有什么推荐?

图片作者。
最接近的主题具有 id 53 和 0.83 的相似性,我们可以观察主题表示(基于类别的 TF-IDF 单词分数)作为相似性度量的验证:

图片作者。
与“度假最接近的话题,用“游记”、“导游”、“旅游”、“行程”、“旅行者”、“徒步旅行】等词来表示。
该主题中情感得分最高的 5 个标题是:

图片作者。
书名包括旅游指南(特别是针对那不勒斯、阿马尔菲海岸和日本的),建议度假的门户目的地,以及深入研究旅行概念的小说(阿兰·德波顿的“旅行的艺术”,伊塔洛·卡尔维诺的“看不见的城市”)。
第二个例子:贾洛(黄色/犯罪小说)
“ Giallo ”是一个有趣的查询术语:在意大利语中,这个词既代表黄色,也代表犯罪小说叙事的类型。
步骤:

图片作者。

图片作者。
尽管输入的单词有歧义,但所有结果都属于犯罪小说类型。
不出所料,阿加莎·克里斯蒂的“然后就没有了”出现在这个主题的首选推荐中(在两个不同的版本中)。
例 3:爵士乐
为简单起见,代码不再重复(可以应用前面示例中的相同步骤):

图片作者。

图片作者。
虽然我个人认为所有推荐的结果都很有趣,但我想提请注意第五个结果:“Abbiamo tutti un blues da piangere”,这是一张来自 Perigeo 的精彩专辑,这是一个 70 年代的爵士/进步摇滚意大利乐队,我直到现在才知道它的存在。我真诚地感谢发现了这颗隐藏的宝石(的确,推荐似乎很管用)。
值得注意的是,检索不同的产品类型(书籍、电影、相册)。这种行为可以通过在建模阶段或推荐阶段(例如作为过滤器)考虑产品类型来修改。
按客户特征推荐
在用户没有偏好的主题或特定的兴趣,并且没有搜索/贷款历史可用的情况下,推荐仍然可以通过利用由聚类产生的客户群来实现。
给定用户的年龄和职业,我们可以找到其归属的聚类,并返回该聚类中最受好评的标题作为推荐:
假设我们需要向一名 32 岁的员工提供建议:

图片作者。
正如我们所料,用户属于集群 n 1,其元素是 30 多岁的学生和员工。我们现在可以在同一个群集中检索最受好评的书目:

图片作者。
有什么推荐给 12 岁的学生?

图片作者。
结论
我们分析了由“Istituzione Biblioteche di Roma”拥有并公开的罗马图书馆评论数据集。
主题建模和情感分析让我们能够深入了解图书馆借阅和用户偏好。聚类技术提供了客户群的附加信息。
我们利用这些见解,通过使用主题和情感信息来实施推荐策略(“你能就旅行提出一些建议吗?)”),或者在没有查询或兴趣表达的情况下,客户群和情感(用户所属的群中最受好评的标题)。
可以通过将不同的产品性质(书籍、电影、专辑)作为过滤器来考虑,并将感兴趣的主题与客户细分相结合来进行改进。主题的数量也可能是进一步调整的主题,尽管显示的最经常出现的主题在不同的实验中被一致地识别。
参考
[1]https://www . bibliotechediroma . it/it/open-data-commenti-lettori
[2]https://maartengr.github.io/BERTopic/index.html
[3]https://medium.com/@maartengrootendorst
[4]https://towards data science . com/topic-modeling-with-Bert-779 F7 db 187 e 6
[5] Jacob Devlin,张明蔚,Kenton Lee,Kristina Toutanova,“ BERT:用于语言理解的深度双向变压器的预训练”,2019, arXiv:1810.04805v2
[6]利兰·麦金尼斯,约翰·希利,詹姆斯·梅尔维尔, UMAP:一致流形逼近与降维投影,2020, arXiv:1802.03426v3
[7] Claudia Malzer,Marcus Baum,“一种基于分层密度的混合聚类选择方法”,2020, arXiv:1911.02282v4
[8] Federico Bianchi,Debora Nozza,Dirk Hovy,“ FEEL-IT:意大利语的情感和情绪分类”,2021 年,第 11 届主观性、情绪和社交媒体分析计算方法研讨会会议录,第 76–83 页(链接)
https://huggingface.co/MilaNLProc/feel-it-italian-sentiment
[10]https://hugging face . co/musix match/umberto-common crawl-cased-v1
[11]黄哲学,“使用混合数值和分类值对大型数据集进行聚类”, 1997 年,第一届亚太知识发现和数据挖掘会议,第 21–34 页(链接)
[12]桑福德·魏斯伯格,“Yeo-Johnson 电力转换”,2001 年(链接)
数据工程师的根本原因分析
原文:https://towardsdatascience.com/root-cause-analysis-for-data-engineers-782c02351697?source=collection_archive---------13-----------------------
权威指南
排除管道中数据质量问题的 5 个基本步骤

图片由蒙特卡洛提供。
这篇客座博文的作者是 弗朗西斯科·阿尔贝里尼*蒙特卡洛 的产品经理和前细分市场产品经理。*
数据管道可能因为一百万种不同的原因而中断,没有一种通用的方法来理解如何中断或为什么中断。以下是数据工程师在进行数据质量问题的根本原因分析时必须采取的五个关键步骤。
虽然我不能确定,但我相信我们很多人都经历过。
我说的是下午晚些时候疯狂的 Slack 消息,看起来像是:

在我的职业生涯中,这种情况在我身上发生过很多次。作为协议的项目经理,我们的数据治理工具,我花了很多时间思考和构建仪表板,以评估我们的客户发送给细分市场的数据的质量。
作为这个产品的所有者,任何关于这些仪表板的问题都直接找我。我解决这些问题的方法可以归结为两步:
- 疯狂地向一位在我们团队工作了 4 年多的数据工程师寻求紧急帮助。
- 如果她不在,花几个小时通过抽查 1000 个 1:1 的表来调试这个管道。
你明白了。
多年来,在与数十个数据工程团队交谈和合作后,我了解到对数据质量问题进行根本原因分析 (RCA)既可以像查看气流日志一样简单,也可以像检查 5+系统一样复杂,以确定上游数据供应商是否在少数记录值中添加了一些尾随空白字符。
在这篇文章中,我将总结我的经验,并通过一个五步骤的方法来使这个过程更快,更少痛苦,并且在下次你遇到这种情况时更有效。
什么是成功的根本原因分析?
当 数据宕机 来袭时,第一步(嗯,在暂停您的管道之后)是确定是什么出了问题。

图片由蒙特卡洛提供。
理论上,根本原因听起来就像运行几个 SQL 查询来分割数据一样简单,但在实践中,这个过程可能相当具有挑战性。事件可能以不明显的方式出现在整个管道中,并影响多个(有时是数百个)表。
例如,数据停机的一个常见原因是数据的新鲜度,即数据异常过时。这种事件可能是由多种原因造成的,包括作业卡在队列中、超时、合作伙伴未及时提供其数据集、错误或意外的计划更改从 DAG 中删除了作业。
根据我的经验,我发现大多数数据问题都可以归因于以下一个或多个事件:
- 输入作业、管道或系统的数据发生意外变化
- 逻辑(ETL、SQL、Spark 作业等)的变化。)转换数据
- 操作问题,如运行时错误、权限问题、基础设施故障、计划变更等。
快速确定手头的问题不仅需要适当的工具,还需要考虑这三个来源如何以及为什么会中断的整体方法。
你应该这么做。
第一步。看看你的血统

图片由蒙特卡洛提供。
你知道顾客仪表板坏了。您还知道这个仪表板是建立在一长串转换之上的,由几个(或者几十个……)数据源提供数据。
要了解什么出了问题,您需要找到系统中出现问题的最上游节点——这是事情开始的地方,也是答案所在……如果您幸运的话,所有罪恶的根源都出现在有问题的仪表板中,您将很快发现问题所在。
在糟糕的一天,问题发生在系统的最上游来源之一,距离损坏的仪表板有许多转换步骤,这将需要一整天的时间来跟踪 DAG 上的问题,然后回填所有损坏的数据。
外卖。确保对数据问题进行故障排除的每个人(数据工程师、数据分析师、分析工程师和数据科学家)都能访问最新的血统。你的血统应该包括像 BI 报告、ML 模型或反向 ETL 接收器这样有用的数据产品。外地级血统是一个加号。
第二步。看看代码

图片由蒙特卡洛提供。
您找到了遇到问题的最上游的表。恭喜你,你离理解根本原因又近了一步。现在,您需要理解这个特定的表是如何由您的 ETL 过程生成的。
浏览一下创建该表的逻辑,甚至是影响事件的特定字段,将有助于您对问题所在提出合理的假设。问问你自己:
- 什么代码最近更新了该表?什么时候?
- 相关字段是如何计算的?按照这种逻辑,什么可能会产生“错误”的数据呢?
- 逻辑最近是否有任何变化,潜在地引入了一个问题?
- 是否有对该表的临时写入?最近回填了吗?

图片由蒙特卡洛提供。
外卖。确保每个对数据问题进行故障排除的人都能快速追溯到创建表的逻辑(SQL、Spark 或其他)。为了弄清事情的真相,您不仅需要知道代码当前的样子,还需要知道表最后一次更新时的样子,理想情况下是什么时候更新的。虽然我们都试图避免它们,但回填和临时写入应该考虑在内。
第三步。看看你的数据

图片由蒙特卡洛提供。
您现在知道了数据是如何计算的,以及它可能如何导致了事故的发生。如果您仍然没有发现根本原因,那么是时候更仔细地查看表中的数据,寻找可能出错的线索了。
问问你自己:
- 所有记录的数据都是错误的吗?为了一些记录?
- 特定时间段的数据是否有误?
- 特定数据子集或数据段的数据是错误的吗,例如,只有您的 android 用户还是只有来自法国的订单?
- 是否有新的数据段(您的代码还没有考虑到…)或缺失的数据段(您的代码依赖于…)?
- 模式最近是否发生了变化,从而可能解释了这个问题?
- 你的数字从美元变成美分了吗?你从太平洋标准时间到东部时间的时间戳?
这样的例子不胜枚举。

图片由蒙特卡洛提供。
这里有一种很有前途的方法,那就是研究表中有异常记录的其他字段如何提供线索,说明数据异常发生在哪里。例如,我的团队最近发现,我们的一个客户的一个重要的用户表中的 user_interests 字段的空率突然增加。我们查看了源领域(Twitter、FB、Google ),看看关系模式是否能为我们指出正确的方向。
这种类型的分析提供了两个关键的见解,这两个见解都可以解释空记录的增加,但最终会驱动非常不同的操作。
- 与 source="Twitter "相关联的记录的比例显著增加,这通常比其他来源具有更多 user_interests="null "的记录
- 对于 source =“Twitter”的记录,user _ interests =“null”的记录比例增加,而 source =“Twitter”的记录比例没有变化
对于 insight 1,我们可能只是遇到了季节性问题或有效营销活动的结果。对于 insight 2,我们可能会遇到来自 Twitter 源的用户数据的数据处理问题,可以将我们的调查重点放在来自 Twitter 的数据上
外卖。确保对数据问题进行故障排除的每个人都可以方便地对数据进行切片和切块,以找出问题与数据的各个部分、时间段和其他切片之间的关系。对数据或其模式的最新更改的可见性是救命稻草。请记住,虽然这些统计方法是有帮助的,但它们只是更大的 RCA 过程的一部分。
第四步。看看您的运营环境

图片由蒙特卡洛提供。
好了,数据核实了。现在怎么办?许多数据问题是运行您的 ETL/ELT 作业的操作环境的直接结果。
查看 ETL 引擎的日志和错误跟踪有助于回答以下一些问题:
- 相关工作有没有失误?
- 开始工作时有异常的延迟吗?
- 是否有任何长时间运行的查询或低性能作业导致延迟?
- 是否存在任何影响执行的权限、网络或基础设施问题?最近这些有什么变化吗?
- 是否对作业计划进行了任何更改,导致意外删除作业或将其误放在依赖关系树中?

图片由蒙特卡洛提供。
外卖。确保每个解决数据问题的人都了解 ETL 工作是如何执行的,并且能够访问相关的日志和调度配置。了解基础设施、安全性和网络也会有所帮助。
第五步。利用你的同事

你已经做了你能做的一切(或者你正在寻找捷径)——下一步是什么?您需要从您的数据团队获得指导。在你开始用问题轰炸 Slack 之前,问问你自己:
- 这个数据集过去发生过什么类似的问题?团队做了什么来调查并解决这些问题?
- 谁拥有现在遇到问题的数据集?我可以向谁寻求更多信息?
- 谁在使用现在遇到问题的数据集?我可以向谁寻求更多信息?
外卖。确保每个解决数据问题的人都可以访问关于数据集所有权和使用的元数据,这样他们就知道应该向谁询问。包含有用文档的数据事件历史也会有所帮助。
把一切都包起来

在一天结束的时候,你的目标是展示你需要的每一个细节,以尽可能少的点击次数快速完成你的 RCA。基于世系、历史记录和元数据自动生成见解的方法可以使这一过程变得简单而快速。图片由蒙特卡洛提供。
在近乎实时地解决和预防数据质量问题时,根本原因分析可能是一个强大的工具,但重要的是要记住,管道破裂很少能追溯到一个特定的问题。与任何分布式架构一样,您的数据生态系统由一系列复杂的逻辑、事件以及管道组成,就像科学实验一样,这些管道会以多种方式做出反应。
也就是说,我们希望这个框架能够帮助您实现更好的数据质量,从而获得更值得信赖和可靠的管道。通过利用这种方法,您也可以将 RCA 从一个引发压力的警钟转变为整个数据组织的可扩展和可持续的实践。
在这个过程中,你会给那个数据工程师(你知道,人类数据管道百科全书)一点喘息的机会…
有兴趣了解如何对您的数据管道进行 RCA 的更多信息吗?伸出手去 巴尔藩 ,还有 其余的蒙特卡洛团队 。**
如何预测 IT 事件
原文:https://towardsdatascience.com/root-cause-analysis-of-it-incidents-based-on-correlations-between-time-series-of-it-infrastructure-cd7a116a334a?source=collection_archive---------18-----------------------
根据 IT 基础设施指标时间序列之间的相关性分析 IT 事故的根本原因
简介
IT 监控系统的任务之一是收集、存储和分析表征 IT 基础设施的各种元素(CPU 负载、空闲 RAM、空闲磁盘空间等)的状态的各种度量。),以及各种业务流程的状态。为了应用统计分析的广泛的数学工具,以相应变量的有序时间序列的形式呈现这些数据通常更方便。Python 中处理时间序列的一个好工具是三个模块的组合:pandas、scipy 和 stats models(【pandas.pydata.org】、 scipy.stats 、statsmodels.org),它们为构建时间序列、估计各种统计模型以及进行统计测试和分析统计数据提供了广泛的类和函数。具体来说,在本文中,我们将描述这些模块中包含的所有大量数学工具算法,这些算法用于 AIOps 平台 monq 中的根本原因分析,特别是 IT 基础设施指标时间序列的相关性分析。

包含 MLOps 数据的 Monq IT 服务运行状况图。图片作者。
在数学上,相关性是两个或多个变量的值的一致变化,当一个变量发生任何变化时,另一个变量也会发生相对变化(减少或增加),相关系数是两个变量的这种匹配可变性的定量度量。相关分析是数理统计的方法之一,通过计算变量之间的相关系数,可以确定变量之间是否存在相关性以及相关性有多强。应当记住,相关系数是一种描述性统计,变量之间存在相关性并不一定意味着它们之间存在因果关系,也就是说,正相关或负相关并不一定意味着一个变量的变化会引起另一个变量的变化(“相关性并不意味着因果关系”)。
如果在相关分析中考虑三个或更多变量的时间序列,则相关矩阵由成对相关系数构成,在该矩阵中,相应变量之间的相关系数位于相应行和列的交点处。关于 IT 基础设施的监控系统,各种度量的时间序列的关联矩阵可用于两种主要场景(用例):寻找系统中事件的根本原因(根本原因分析)和寻找系统元素之间隐藏的基础设施连接(以某种方式,“绘制”资源服务模型)。最终,度量之间的时间相关性可以插入到各种算法中,用于进一步的数据分析,如预测或建模工具。
构建度量的时间序列
相关性分析过程中的第一步是以规则(等间距)时间序列的形式呈现描述 IT 基础架构元素状态的度量值集,即描述每个特定时刻(每 5 分钟、每半小时等)的度量值的行。).在一般情况下,度量值的测量和它们在数据存储器中的记录以不同的间隔和不同的频率异步发生,因为这些度量通常来自外部源,并且监控系统对它们没有控制:存在这样的情况,当几个度量值在 5 分钟间隔内出现,然后在半小时内没有一个度量值出现。在这方面,需要一个用于正则化各种度量的时间序列的程序,为此,有必要对不同的时间间隔使用数据内插和外插的方法。时间序列正则化过程如图 1 所示,在熊猫模块中,这是在一行中完成的——在下面的代码示例中,这是最后一行,其中方法重采样(‘5min’)。mean 对每个 5 分钟时间间隔内的测量值进行平均,方法 fillna(method='ffill') 将前一个度量值外推至空(无测量值)时间间隔:
import pandas as pd
data=pd.read_csv(‘TimeSeriesExample.txt’,parsedates=[0])
timeSeries=pd.Series(data[‘KEHealth’].values, index=data[‘Timestamp’])
timeSeriesReg=timeSeries.resample(‘5min’).mean().fillna(method=’ffill’)
tsCollection.append(timeSeriesReg)

图一。度量值时间序列的正则化。图片作者。
Monq 使用资源服务模型,根据相关触发器的状态以及第三方系统和组件对给定配置单元的相互影响,计算硬件和服务的健康指标。在上面的示例中,使用了关于特定健康指标的数据,该数据是根据某些规则为监控系统的每个元素计算的。图 2 显示了我们的一个拥有几千个配置单元的客户的系统中的一些 Cu 的健康指标的时间序列的典型视图,时间跨度大约为一年。

图二。监控系统不同元素的运行状况指标的时间序列。图片作者。
相关矩阵的计算
在获得正则化的度量时间序列之后,计算它们的相关矩阵是一项相当简单的任务。在 pandas 模块中,最简单的方法是将时间序列合并到一个表(dataframe)中,并对其应用 corr() 方法,该方法计算每对指标在其联合定义的时间间隔内(不一定是连续的)的皮尔逊相关系数:
import matplotlib.pyplot as plt
allKeDF=pd.concat(tsCollection, axis=1)
corrMatrix=allKeDF.corr()
pallet=plt.getcmap(‘jet’)
img=plt.imshow(corrMatrix, cmap=pallet, vmin=-1, vmax=1, aspect=’auto’)
plt.colorbar(img)

图三。系统中 150 个最不稳定的 Cu 的运行状况指标的时间序列的相关矩阵。图片作者。
图 3 显示了来自我们的一个客户的监控系统的 150 个配置单元的健康状况度量的时间序列的相关矩阵,其中度量值变化最频繁。如您所见,该矩阵基本上是一个“绿色区域”,这意味着绝大多数 Cu 之间不存在任何相关性,或者存在非常弱的相关性。对于那些算法未能计算相关系数的 CU 对,图片中出现白色像素——它们的时间序列在时间上不相交(为了进一步处理的方便,所有的 nan 值被置零)。这是很有可能的,因为监控系统是活的——新的配置元素可以出现在其中,旧的配置元素可以消失。图片中的红色和蓝色像素对应于那些 CU 对,它们的时间序列是相关的,因此是反相关的。这样的 CU 对并不多:相关系数 r > 0.7 (占总对数的 0.29%)的相关对只有 65 个, r < -0.7 (0.02%)的反相关对只有 4 个。这从好的方面描述了监控系统的特征:没有许多重复的元件监控相同的参数,每个人都忙于自己的事情。重复彼此功能的配置单元应该正好属于相关系数为 r > 0.95 的强相关对组。

图 4。度量时间序列不同正则化间隔的相关矩阵— 5 分钟和 10 分钟。图片作者。
图 4 显示了为一组相同的 Cu 计算的相关矩阵,但是对时间序列的度量使用了不同的正则化间隔——5 分钟和 10 分钟。乍一看,两张图片看起来相当相似,但如果你计算一下它们之间的差异,你会得到图 5 所示的直方图,其中平均值接近于零μ = 0,标准差σ = 0.11。5 分钟和 20 分钟时间序列的相关性差异的相同直方图具有标准偏差σ = 0.16,由此得出结论,随着正则化的改变,显著数量的 KE 对可以从相关组移动到非相关组,反之亦然。可以看出,时间序列的正则化间隔的选择对相关矩阵的值有显著影响,并且应该在计算相关性的期望精度、所需的计算机资源和计算时间之间进行一定的折衷。

图 5。5 分钟和 10 分钟正则化时间序列的相同相关系数值之间差异的直方图。图片作者。

图六。CU 对的运行状况度量的相关时间序列的典型视图。图片作者。
图 6 显示了几对相关的 CU 健康指标时间序列的概况,图 7 显示了反相关时间序列的概况。最后一幅图清楚地表明,相关系数的高模数值可能是由于时间序列的非常特殊的行为,它们的联合可变性的时间间隔的特征交叉。在这种情况下,为了检查所计算的相关系数的显著性,可以使用(有些夸张地)学生的 t 测试,为此,使用公式 t=|r|√(n-2)/(1-r2) ,计算 t 统计量 tobs ,并与给定显著性水平和自由度数量 k=n-2 的表格值 tcrit(α,k) 进行比较作为 n,应该取在定义两者的时间间隔上度量(来自 CU 对)的时间序列中值变化的最小数量。对于图 7 中的时间序列对,在 α = 0.05 的情况下计算学生的 t 测试的结果显示在红色方块中。由于对于前两对tobs<t crit,相关系数的测量值被认为不重要,可能是随机巧合的结果。对于最后一对tobs>t crit,这意味着反相关的测量值具有统计学意义。在 scipy 模块中很容易获得 tcrit 值:
import scipy as sp
tCrit=sp.stats.t.ppf(1-alpha/2, ndf)

图 7。CU 对健康度量的反相关时间序列的典型视图。图片作者。
相关矩阵的使用
如引言中所述,在 IT 基础设施的监控系统中使用度量的时间序列的关联矩阵有几种情况,其中两种似乎是主要的:1)搜索 IT 系统中事件的根本原因(根本原因分析),以及 2)搜索资源服务模型中不存在的系统元素之间的隐藏基础设施链接。应该记住,在这两种情况下,相关性分析的信息性和有用性直接取决于给定 IT 系统可用的资源服务模型(RSM)的质量和完整性:如果系统的配置单元之间存在的所有连接和影响程度都显示在 RSM 图上,那么相关性矩阵不可能包含 RSM 中已经注册的任何附加信息。很明显,完整的 RSM 给出了系统中所有因果关系的完整图像,在这种情况下,相关矩阵只是 RSM 图的某种简化表示。然而,建立一个完整的 IT 系统资源服务模型是一个非常耗时的过程,并且在实践中并不总是可行的,因此,分析系统元素行为的相关性可以帮助揭示它们之间的一些隐藏的(RSM 中不存在的)联系,或者建立一个元素对另一个元素影响程度的定量表达,即在某种程度上补充 RSM 图。在系统没有 RSM 的情况下,相关性矩阵可以找到另一个应用:3)相关性的分级聚类分析,用于将系统元素组合成组,并以树状图的形式可视化其 PCM 结构。
寻找事故的根本原因
一般而言,IT 系统中的事故是导致或可能导致服务标准流程失败、服务中断或服务质量下降的任何事件。与此同时,许多事件可能只是基础设施层面一些更深层次问题的症状,通常一个问题(根本原因)会引发一整组事件。找到这些事件的根本原因是 IT 监控系统最重要的功能之一。
原则上,如果系统的成熟且可靠的资源服务模型存在,则特定 CU 的操作失败的根本原因可以通过沿着所有连接链顺序检查有问题 CU 的存在以及对原始 CU 的影响来在 RSM 图中追踪。通过分析 CU 状态时间序列之间的相关矩阵,可以在一定程度上弥补在搜索事件根本原因时缺乏完整的 RSM 图的问题。由于数据库查询类型的不同,关联矩阵比 RSM 图更快地确定事件的根本原因也是可能的。
在 monq 中,CUs 的健康度量的时间序列的相关性分析的功能被委托给单独的微服务,该微服务在后台不断更新相关性矩阵。对于整个矩阵,更新不是同时发生的,而是部分发生的(由于计算资源的限制),对于更不稳定的时间序列,相关系数的计算要比稍微不稳定的时间序列更频繁。因此,当前相关矩阵包含在不同时刻计算的相关系数,但是由于上述用于更新它的方法,其中的所有值都是相关的。
当某个 CU 发生事故时,微服务在收到相应的请求后,会发布一个与原始 CU 相关系数的值高于某个阈值(通常为 r > 0.7 )的 CU 的排序列表,如图 8 所示。该信息可以直接在前端用于检查相关 Cu 的状态,也可以传递给组合根本原因搜索算法,该算法除了时间相关性之外,还使用事件的语义聚类。

图 8。与 CU-38374 相关的 CU 列表,由微服务生成,用于计算相关矩阵。图片作者。
搜索隐藏的基础设施链接
如上所述,CU 状态的时间序列的相关性分析可以揭示 IT 系统的元素之间的新的联系,这些联系在其资源服务模型中没有被考虑。这可能是系统本身中某种隐藏的基础设施链接(例如,使用公共电源电路、公共冷却系统等。)或对某种外部服务的普遍依赖。由于在这种情况下,在系统的元件之间寻求相当严格的连接,用于选择 CU 对的相关系数的阈值应该取得相当高: r > 0.95 。
图 9 显示了我们主要客户的 IT 系统的 CU 健康指标的时间序列关联矩阵,它由 3200 个配置项组成。相关系数大于 0.95 的 CU 对的数量是 7470,其中,在检查 RSM 图中的对元素之间的连接之后,剩余 2310。一些剩余 CU 对的时间序列的典型视图如图 10 所示,其中学生的 t 测试结果以红色方块给出(为了更高的可靠性, α=0.001 )。从图中可以看出,对于大多数对来说, t 统计值小于临界统计值,所以最终只有 3 对相关 CU 通过了这个 t 测试。对于参数值为 α=0.01 的t-标准,剩余 CU 对的数量为 27。尽管原则上自动添加也是可能的,但是下一步如何处理在 IT 系统的元素之间发现的新连接,是否将它们添加到 RSM,由其操作员决定。

图 9。我们主要客户的 IT 系统的 CU 健康指标的时间序列的全相关矩阵。图片作者。

图 10。RSM 图中未连接的一些高度相关的 Cu 对的典型时间序列视图。图片作者。
相关性的层次聚类分析
层次聚类用于识别一组变量中相对同质的组,使用的算法首先将每个变量视为一个单独的聚类,然后根据变量之间的某种定量度量接近度,依次将这些聚类相互组合成更大的聚类,直到只剩下一个聚类。作为该过程的输出,获得了一个树状图——一个从相似性(差异)度量矩阵构建的树状图形,它可视化了给定集合中变量之间的相互距离。在相关的情况下,差分矩阵通常取为 Mdist=||1||-Mcorr ,其中||1||是与相关矩阵 Mcorr 大小相同的单位矩阵。在 scipy 模块中,您可以用几行代码从相关矩阵构建一个树状图:
import scipy.cluster.hierarchy as hac
z = hac.linkage(1-corrMatrix, method=’complete’)
hac.dendrogram(z, colorthreshold=3, leaf_rotation=90., labels=allKeDF.columns)
plt.title(‘Dendrogram of hierarchical cluster analysis based on correlation matrix of CU health’, fontsize=12)
plt.ylabel(‘Distance’,fontsize=10)
plt.xlabel(‘Cu Id’,fontsize=10)
plt.show()
图 11 显示了从图 3 中 150 个配置单元的运行状况度量的时间序列的相关矩阵中获得的树状图,其中,分层聚类算法以不同的颜色突出显示了具有其度量的相关行为的 CU 簇,并有效地将整个系统 CU 集划分为相关的组(子系统)。在没有系统 RSM 的情况下,这样的划分已经揭示了系统的一些结构,并且可能是有用的,例如,当搜索事件的根本原因时。

图 11。系统中 150 个最不稳定的 Cu 的运行状况指标时间序列的相关矩阵的树状图。图片作者。
使用快速探索随机树的 ROS 自主 SLAM(RRT)
原文:https://towardsdatascience.com/ros-autonomous-slam-using-randomly-exploring-random-tree-rrt-37186f6e3568?source=collection_archive---------3-----------------------
移动机器人 Turtlebot3 在 ROS 的导航栈和 Gazebo 模拟器的帮助下实现未知环境探索的 RRT 算法

使用 RRT 探索 Turtlebot3 图片由作者提供
机器人操作系统(ROS)已经成为现代机器人领域的游戏规则改变者,在这个领域具有极高的潜力,有待于下一代更熟练的开源机器人社区来探索。ROS 的最大优势之一是它允许机器人系统中不同流程(即节点)的无缝集成,在开源社区的支持下,这些流程也可以在其他系统中重用。
ROS 和 SLAM
ROS 最受欢迎的应用之一是 SLAM(同步定位和地图绘制)。移动机器人中 SLAM 的目标是在将用于探索的机器人上附着的可用传感器的帮助下,构建和更新未探索环境的地图。
在这个演示中,我们将看到预构建的 ROS 包的实现,即导航堆栈和 Gmapping,使用 SLAM 自主地使用随机探索随机树(RRT)算法来绘制未探索的房子,使机器人覆盖未知环境的所有区域。
RRT 算法
快速探索随机树(RRT)是一种数据结构和算法,旨在有效地搜索非凸高维空间。RRT 是以一种快速减少随机选择的点到树的预期距离的方式递增构建的。RRT 特别适合于涉及障碍和微分约束(非完整或动力学)的路径规划问题。来源

RRT 算法动画|图片由作者提供,使用源代码生成
SLAM 应用的 RRT
我们将使用 RRT 算法为机器人制定路径计划,以到达传感器附近所有可到达的远程端点,也称为前沿点,这反过来使机器人在试图到达其新的远程端点时,使用 SLAM 连续绘制新的区域。以这种方式将 RRT 应用于移动机器人,使我们能够创建一个无需人类干预的自我探索自主机器人。该算法的本质倾向于偏向于未探索的区域,这对于环境探索任务变得非常有益。更深入的信息和该策略的流程可以在本出版物中找到:基于多个快速探索随机树的自主机器人探索。

探索未知空间的 RRT 算法的推广|图片作者
露台模拟器
Gazebo Simulator 是一个设计良好的独立机器人模拟器,可用于快速测试算法、设计机器人、执行回归测试以及使用真实场景训练 AI 系统。我们将使用带有房屋模型的露台环境,让我们的机器人探索并制作房屋地图。

露台模拟器中的房屋模型|图片由作者提供
让我们开始和 ROS 一起工作吧
对于这个演示,请随意从我的Github资源库下载我预建的 ROS 包ROS _ autonomous _ slam。
这个存储库由一个 ROS 包组成,它使用导航栈在 GMAPPING 的帮助下自主探索未知环境,并构建所探索环境的地图。最后,在新生成的地图中使用导航堆栈中的路径规划算法来达到目标。Gazebo 模拟器用于 Turtlebot3 华夫饼 Pi 机器人的模拟。集成了各种算法,用于在 360 度激光雷达传感器的帮助下自主探索该区域并构建地图。不同的环境可以在启动文件中交换,以生成所需的环境图。当前用于自主探索的最有效的算法是快速探索随机树(RRT)算法。RRT 算法是使用来自 rrt_exploration 的包实现的,它是为了支持 Kobuki 机器人而创建的,我进一步修改了源文件,并在这个包中为 Turtlebot3 机器人构建了它。
在这个项目中有三个主要步骤要执行。
- 步骤 1:将机器人放置在露台内的环境中
- 步骤 2:执行环境的自主探索并生成地图
- 步骤 3:执行路径规划并在环境中到达目标
项目的先决条件和设置
在开始执行这些步骤之前,请确保您已经成功完成了本项目演示的先决条件和设置。有三个安装部分(Gazebo ROS 安装、Turtlebot3 包和导航栈安装)。
ROS 安装
我用的是 Ubuntu 18 OS 配合 ROS 旋律版。检查 ROS 安装的官方文件 ROS 安装
露台 ROS 安装
主露台模拟器是一个独立的应用程序,必须安装。办理文件凉亭安装。测试 Gazebo 及其版本的工作情况
*gazebo
which gzserver
which gzclient*
安装 Gazebo 后,必须单独安装 Gazebo ROS 软件包
*sudo apt-get install ros-melodic-gazebo-ros-pkgs ros-melodic-gazebo-ros-control*
在本教程中,将melodic替换成你的 ROS 版本。
Turtlebot3 包
Turtlebot3 ROS 包可以从工作区的源文件下载并构建,也可以直接从 Linux 终端安装。无论哪种方式都可以,我建议两者都做,因为它会自动安装所有缺少的依赖项。

Turtlebot3 Waffle Pi 凉亭内的房屋模型|图片由作者提供
直接安装
*source /opt/ros/melodic/setup.bash
sudo apt-get install ros-melodic-turtlebot3-msgs
sudo apt-get install ros-melodic-turtlebot3*
构建包
*cd catkin_ws/src
git clone -b melodic-devel https://github.com/ROBOTIS-GIT/turtlebot3
git clone -b melodic-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations
cd ..
catkin_make
source /devel/setup.bash*
导航堆栈
导航栈也可以作为源文件下载到您的工作区并进行构建。
*sudo apt-get install ros-melodic-navigation
cd catkin_ws/src
git clone -b melodic-devel https://github.com/ros-planning/navigation
cd ..
catkin_make
source /devel/setup.bash*
自主 SLAM 演示的主要执行
步骤 1:将机器人放置在露台内的环境中
将您的环境变量设置为要使用的模型机器人。
*export TURTLEBOT3_MODEL=waffle_pi
source ~/.bashrc*
使用给定的世界文件执行给定的启动以打开 Gazebo,并将机器人 Turtlebot3 Waffle pi 模型放入其中。
*roslaunch ros_autonomous_slam turtlebot3_world.launch*
保持此过程始终运行,并在不同的终端中执行其他命令。
步骤 2:执行环境的自主探索并生成地图
*roslaunch ros_autonomous_slam autonomous_explorer.launch*
运行 Autonomous Explorer 启动文件,它同时为我们执行两个任务。
- 它使用定制的修改后的 RVIZ 文件启动导航堆栈中的 SLAM 节点,以监控环境的映射。
- 它同时启动自主浏览器,这是一个基于 Python 的控制器,在机器人周围移动,掠过所有区域,帮助 SLAM 节点完成映射。用于探索的默认算法是 RRT 算法。我还创建了一个 explorer 方法,该方法使用 Bug Wall following 算法进行探索,可以通过将参数
explorer添加到采用[RRT,BUG_WALLFOLLOW]的 launch 来进行测试。
在 RVIZ 窗口中设置 RRT 的探测区域(更多详情
RRT 探测需要在 RVIZ 窗口中定义机器人周围的矩形区域,使用四个点和机器人已知区域内探测的起点。必须使用 RVIZ 发布点选项,按照下面给出的确切顺序定义总共五个点。

发布点序列|作者图片,更多细节来自 rrt_exploration 教程
在 RVIZ 窗口中监控映射过程,并坐下来放松,直到我们的机器人完成 XD 映射。

使用 RRT 算法的机器人地图|图片由作者提供
对构建的地图感到满意后,保存地图。
*rosrun map_server map_saver -f my_map*
my_map.pgm 和 my_map.yaml 保存在您的主目录中。将这些文件移动到包的 maps 文件夹中(chunk _ ws \ src \ ROS _ autonomous _ slam \ maps)。现在你的新地图基本上是一个占用网格构建!

由作者构建的地图|图像
在自主失败的情况下你可以使用键盘手动控制环境中的机器人,下面给出一个单独的启动执行。您也可以像玩游戏一样手动探索和构建地图。
*roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch*

手动机器人制图|图片由作者提供
步骤 3:执行路径规划并在环境中到达目标
我们将使用 ROS 的导航栈来执行路径规划,并使用/move_base/goal 操作到达目标。执行给定的打击发射会打开一个 RVIZ 窗口,显示机器人在先前构建的地图中的位置。
*roslaunch ros_autonomous_slam turtlebot3_navigation.launch*
RVIZ 窗口显示机器人使用其激光传感器构建的局部地图,相对于之前在步骤 2 中借助成本地图构建的全局地图。
在 RVIZ 窗口中设置目标
- 首先,估计初始姿态,即相对于地图定位真实的机器人位置。这可以在 RVIZ 窗口中设置,使用 2D 姿态估计,并在当前机器人的位置和方向上指向和拖动箭头。

2D 估价标签
- 可使用 2D 导航目标选项在 RVIZ 窗口中设置目标点,该选项可在顶部窗口选项卡中找到。这允许您在 RVIZ 环境中的地图上设置一个目标点,然后机器人自动执行路径规划并开始沿其路径移动。

2D 导航目标选项卡
Ros 导航堆栈调整指南
ROS 导航堆栈需要调整其参数,这些参数对于不同的环境类型有不同的作用,以获得最佳的 SLAM 和路径规划性能。下面是 ROS 针对 Turtlebot3 的导航栈参数调优指南。 Turtlebot3 导航参数整定指南

机器人局部路径和全局路径规划|图片由作者提供

机器人向目标移动动作|作者图片
太好了!!!现在我们已经在 ROS 工具的帮助下完成了 SLAM 任务。
人工智能艺术:玫瑰色人工智能
原文:https://towardsdatascience.com/rosy-ai-5897b1e1b5be?source=collection_archive---------28-----------------------
令人震惊的细节,错过了“大画面”——由外星人
在这项工作中,我们从主要的旅程中绕了一个小弯,以利于短暂的丰富多彩的反思。我们忠实于我们的使命,使用“人工智能”生成数字艺术作品,尽管不是在预期的意义上。

灵感
那是 2020 年的夏天,我们正在讨论新的人工智能和艺术项目的想法,我们周围的世界正在螺旋上升。这种不和谐是不可能被忽略的。在我们封闭的墙内,我们被广阔而快速发展的人工智能世界所包围。价值数十亿美元的数据集和 TPU 年,以及研究论文中捕获的数千人类年。都是打着对科学、健康、农业、能源管理、交通、信息消费、人机交互等更美好未来的或隐或显的承诺的旗号。然而,这一切似乎与外部世界的现实如此脱节。
这些科学和技术的奇迹,这些机器奥林匹克——令人着迷于它们捕捉细节和模式的非人类能力。然而,他们没有人性,既看不到问题,也看不到大局。
但不仅仅是机器。此外,人工智能的人性一面似乎陷入了某个孤立的人造宇宙的无限循环中。研究论文的无数次迭代,每一次都引入了另一项改进,每一次都推动了某个综合基准上的另一个 SOTA。然而,在非常基本的人类层面上,尽管取得了所有这些进步,但作为一个社会,我们似乎最终还是在同一个地方。我们想以某种方式在一件人工智能艺术品中捕捉这种感觉。
我们希望拥有所有的技术烟火:一个大的数据集和丰富的功能使用,机器控制的流程,随机性,算法和启发式多样性,以及一点视觉浮夸。但我们不希望它是常规意义上的 ML。我们希望使用所有这些,特别是数据集中捕获的信息,以一种街上普通人(抗议)更容易理解的方式。
对我们来说,抓住细节上的独创性和宏观上的盲目之间的矛盾也很重要。最后,我们想将这一切包裹在一个神奇的无限循环中,通过奇妙而独特的技术路径滚动,最终到达完全相同的地方。
玫瑰色艾
Rosy AI 是一个 Python 程序,它应用人类工程算法来解决马赛克难题,覆盖了一个人工智能模型,该模型试图使用最先进的对象检测技术来“理解”正在出现的图像。镶嵌图由 32K 的花朵图像块组成,这些图像块最初被编译为数据集,用于训练人工智能模型对花朵进行分类。它似乎充分代表了人工智能的 rosey 图像,就像它的受限宇宙的墙壁所反映的那样。

32,000 张美丽的花图像(小样本)
从随机分布或初始图像开始,如果切换代表有利于最终图像的帕累托改进,则通过某个最佳拟合算法替换瓦片,或者为潜在的切换随机选择瓦片。人类观众是人工智能试图识别马赛克中出现的形状的见证人,并且由于他/她的本性,也是解决谜题竞赛中的竞争者。
根据作品展示的地理位置,最终的图像可能对当地观众来说非常熟悉(或者不太熟悉)。那些在媒体上见过照片无数次的人,可以在识别场景中的物体方面轻松击败人工智能。它们是否也能够比人工智能更好地处理和理解大局,这是 Rosy 人工智能的一个核心问题。
最终的艺术作品以数字视频的形式在屏幕上展示。它不是一个预先录制的视频文件,而是一个在无限循环中实时运行的计算机程序,在显示器上呈现实时视频。每次循环大约 10 分钟,它捕捉照片马赛克的形成。当它完成镶嵌时,它又重新开始。
循环不会简单地重复自己。每次迭代都是独一无二的,机器可以决定它的细节:起始状态、目标图像(来自专用文件夹中的候选图像集合),以及它将用来构建最终图像的方法(最佳拟合、切换等)。强烈建议观众连续观看多次,以获得对作品的完整印象。
戏弄者
我们录了几个例子给你欣赏。正如你所看到的,它们看起来很有趣,并且产生不同的结果。不过有一个小注意:实际的艺术作品可用于 1800p 和 4K 显示器,并且是为大屏幕设计的,允许观众探索从花卉瓷砖的细节到整体图像的整个光谱。因此,如果你正在手机上阅读这篇文章,你可能想稍后在更大的屏幕上重新观看这些视频:)
示例运行 1:使用另一个马赛克初始化,使用最佳匹配-从最暗/最亮开始
示例运行 2 ( Gezi ):随机初始化,帕累托开关方法
示例运行 3:随机初始化,最佳拟合垂直线
示例运行 4a(熟悉的图像…):图像初始化,灰色第一最佳拟合算法
示例运行 4b:相同的图像,随机初始化,完全相反的最佳拟合算法(最亮/最暗优先)
老实说,即使不谦虚,我们对结果也很满意。盯着那个无限循环看了一会儿后,我们认为我们成功地捕捉到了我们想要的那种感觉…
将您的实验路由到文件
原文:https://towardsdatascience.com/route-your-experiments-to-files-11a65be823d2?source=collection_archive---------39-----------------------
提高深度学习体验的小技巧

汤姆·赫尔曼斯在 Unsplash 上拍摄的照片
运行深度学习实验可能是一项令人生畏的任务。您安排了一批实验通宵运行,结果前几天发现几乎所有的实验都失败了——并且任何堆栈跟踪都被其他测试遗忘了很久。多好的开始一天的方式:x .如果你和我一样,看到这种事情发生的次数比你愿意承认的多,这里有一个纯 Python 的方法来防止丢失控制台消息:
自动控制台到文件记录器
将任何控制台输出镜像到备份日志文件的小 Python 代码片段。
总的来说,在调用mirror_console_to_file(file)之后,任何发送到stdout 和stderr 流的消息都将被拦截,路由到一个文件,然后像往常一样打印出来。这模仿了 Linux 中使用纯 Python 的‘tee’命令。这具有跨所有平台工作的优势,并且它给了您对过程的编程控制。
在这个实现中,stdout 和stderr 都指向同一个文件,并且有一个带有系统时间戳的开始和结束消息,这对于检查测试完成/失败花费了多长时间很有用。更进一步,可以通过手动检查消息中的\n字符来添加每条消息的时间戳。
需要注意的是,使用\r字符的消息不会像往常一样被处理。相反,日志将按顺序包含每条消息,而不是每条消息覆盖前一条消息。这让我很恼火,所以我在开发和测试时分别打开和关闭路由代码。
如果你是那种把一堆旧测试结果放在身边的人,我强烈推荐你下载 GitPython 。使用它,您可以获取当前的提交摘要/散列,并在日志的开头打印出来。这将极大地帮助您解析旧的日志,因为它将准确地告诉您在项目时间表的哪个点进行了这个测试。下面是一个片段:
import git
head = git.Repo(search_parent_directories=True).head.object
summary, sha = head.summary, head.hexsha
最后一点,您可能想知道:为什么手动将标准输出发送到一个文件,而不是使用日志库?有几个理由支持手动方法:
- 大多数人的代码都是基于基本的 print,所以将其转换成 logger 实现可能会花费太多的时间和精力。
- 实际上,(非库)深度学习代码并不长,也不复杂,无法保证日志记录级别或分布式日志记录等功能。
- 有用的调试信息通常来自库警告,而不是您自己的消息。
有关训练深度学习模型的更多提示,请考虑阅读:
如果您对本文有任何问题,请随时发表评论或与我联系。如果你刚接触媒体,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。
感谢阅读:)
获取 Pandas 中具有特定列值的行的索引
原文:https://towardsdatascience.com/rows-index-with-certain-column-value-pandas-1b25d382f0cb?source=collection_archive---------12-----------------------
了解如何在 pandas 数据帧中检索其列与特定值匹配的行的索引

davisuko 在 Unsplash 上拍摄的照片
介绍
有时,我们可能需要检索其列匹配特定值的数据帧行的索引。在今天的简短指南中,我们将探索如何在熊猫身上做到这一点。
具体来说,我们将展示如何使用
- 熊猫数据框的
index属性 - 和 NumPy 的
where()方法
此外,我们还将讨论如何使用检索到的索引来执行常见任务。
首先,让我们创建一个示例数据框架,我们将在本文中引用它,以便围绕感兴趣的主题演示一些概念。
import pandas as pd df = pd.DataFrame(
[
(1, 100, 10.5, True),
(2, 500, 25.6, False),
(3, 150, 12.3, False),
(4, 100, 76.1, True),
(5, 220, 32.1, True),
(6, 100, 10.0, True),
],
columns=['colA', 'colB', 'colC', 'colD']
)print(df)
*colA colB colC colD
0 1 100 10.5 True
1 2 500 25.6 False
2 3 150 12.3 False
3 4 100 76.1 True
4 5 220 32.1 True
5 6 100 10.0 True*
使用索引属性
访问索引的第一个选项是[pandas.DataFrame.index](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.index.html)属性返回熊猫数据帧的索引(即行标签)。
例如,假设我们想要检索所有行的索引,这些行在colD中的列值是True。下面的方法可以解决这个问题:
**idx = df.index[df['colD']]**print(idx)
*Int64Index([0, 3, 4, 5], dtype='int64')*
现在,如果你想将索引存储到一个列表中,你可以简单地使用tolist()方法:
**indices = df.index[df['colD']].tolist()**print(indices)
*[0, 3, 4, 5]*
使用 NumPy 的 where()方法
或者,您可以使用 NumPy 的[where()](https://numpy.org/doc/stable/reference/generated/numpy.where.html)方法,该方法返回一个包含基于指定条件选择的元素的ndarray。
例如,为了获得列值在colB中等于100的所有行的索引,下面的表达式将完成这个任务:
import numpy as np**indices = np.where(df['colB'] == 100)**print(indices)
*(array([0, 3, 5]),)*
利用检索到的索引
现在我们知道了如何获取特定行的索引,这些行的列匹配特定的值,您可能希望以某种方式利用这些索引。
例如,为了使用检索到的索引从 pandas DataFrame 中选择行,您可以使用loc属性和Index:
**idx = df.index[df['colD']]** **df_colD_is_true = df.loc[idx]** print(df_colD_is_true)
*colA colB colC colD
0 1 100 10.5 True
3 4 100 76.1 True
4 5 220 32.1 True
5 6 100 10.0 True*
或者,如果您有一些存储在列表中的索引,并且您想要直接使用它们来获取相应的行,您可以使用iloc属性:
**indices = df.index[df['colD']].tolist()** **df_colD_is_true =** **df.iloc[indices]**print(df_colD_is_true)
*colA colB colC colD
0 1 100 10.5 True
3 4 100 76.1 True
4 5 220 32.1 True
5 6 100 10.0 True*
最后的想法
在今天的简短指南中,我们讨论了如何检索其列与指定值匹配的行的索引。具体来说,我们展示了如何使用 pandas DataFrames 的index属性以及 NumPy 库的where()方法来获取索引。
此外,我们还探索了如何使用检索到的索引从 pandas 数据帧中获取实际的行。
成为会员 阅读媒体上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
r 的层次聚类图解——小菜一碟!
原文:https://towardsdatascience.com/rs-hierarchical-clustering-illustration-a-piece-of-cake-a2406f48cbf9?source=collection_archive---------43-----------------------
聚类分析中的一个常见问题是:“现在怎么办?”。您有很多方法可以让混乱的数据变得有序,而不需要在头脑中有一个预先定义的假设。您可以使用传统的 kMeans,一些基于密度的方法,如 dbscan 或层次聚类,这可以让您对数据集中的聚类层次有一个印象。然而,你最感兴趣的不仅仅是你的哪些样本聚集在一起,还有,为什么它们会聚集在一起。只有当能够区分哪些样本特征将它们聚集在一起,哪些将它们分开时,您才能从分析中获得值。你超越了单纯的描述,走向了诠释和洞见。
然而,你要确保你的分析本身就能说明问题。不要抢镜头。只要提供正确的数字,见解就会显而易见。最近,我偶然发现了 R 中的一个新包,它使吸引人的层次集群变得轻而易举。它也有一个很棒的文档在这里,所以我仅仅提供一个开胃菜。你可以自己去探索所有的基本细节。
因此,首先我们获取一些数据(mtcars 数据集)并运行层次聚类分析。标准图看起来是这样的:

作者图片
现在,我们加载 Tal Galili 的出色的 dendextend 包,将 hclust 对象转换成一个树状图。您可以给树叶标签和树状图线着色(这里是根据引擎类型),根据某个向量(这里是根据气缸数量)设置标签的大小,并对节点进行处理。

作者图片
但最重要的是,您可以添加彩色条,代表您给定样本的特征级别。我将连续变量按其四分位数分割,以分配离散的颜色,因此您很快就能对给定聚类的特征级别有一个印象。因此,我们可以很快看出,与 Merc450 系列处于中间位置的那一组拥有共同的重量等级(wt)、后轮轴比(drat)、相同数量的齿轮和气缸、相同类型的变速器和发动机(am、vs),但这两款车的排量和马力不同(disp、hp)。有趣的是,本田思域的后轮轴比率和 mpg 组合远远落后于 Mercedes450 组,它与丰田和菲亚特归为一类,尽管它的其他参数与 Merc450 相当。我想知道如果有一天数据集被更新,特斯拉会被分组到哪里。
下面是获取这些数字的代码:
library(dendextend)
library(colorspace) #to translate factors to colors
library(plotrix) #to translate hex to color#run cluster analysis:
hccomplete <- hclust(dist(mtcars), method ="complete")
#standard plot
plot(hccomplete)
#transform the hclust object to a dendrogram
dend <- hccomplete %>% as.dendrogram
#get colors for factors. Continuous variables are cut by their quartiles, to which the colors are assigned
the_bars <- cbind(unname(sapply(rainbow_hcl(length(levels(as.factor(mtcars$cyl))))[c(as.factor(mtcars$cyl))], color.id)),
unname(sapply(rainbow_hcl(length(levels(as.factor(mtcars$vs))))[c(as.factor(mtcars$vs))], color.id)),
unname(sapply(rainbow_hcl(length(levels(as.factor(mtcars$am))))[c(as.factor(mtcars$am))], color.id)),
unname(sapply(rainbow_hcl(length(levels(as.factor(mtcars$gear))))[c(as.factor(mtcars$gear))], color.id)),
unname(sapply(rainbow_hcl(length(levels(as.factor(mtcars$carb))))[c(as.factor(mtcars$carb))], color.id)),
sapply(cut(mtcars$mpg,breaks=c(0,unname(quantile(mtcars$mpg))), labels=heat_hcl(5)), color.id),
sapply(cut(mtcars$disp,breaks=c(0,unname(quantile(mtcars$disp))), labels=heat_hcl(5)), color.id),
sapply(cut(mtcars$hp,breaks=c(0,unname(quantile(mtcars$hp))), labels=heat_hcl(5)), color.id),
sapply(cut(mtcars$drat,breaks=c(0,unname(quantile(mtcars$drat))), labels=heat_hcl(5)), color.id),
sapply(cut(mtcars$wt,breaks=c(0,unname(quantile(mtcars$wt))), labels=heat_hcl(5)), color.id),
sapply(cut(mtcars$qsec,breaks=c(0,unname(quantile(mtcars$qsec))), labels=heat_hcl(5)), color.id))#plot awesomely
par(mar = c(17,3,2,2))
dend %>% set("branches_col", ifelse(mtcars$vs ==0, "red", "blue")) %>% # change color of branches
set("labels_col", ifelse(mtcars$vs ==0, "red", "blue"))%>% # change color of labels
set("labels_cex", mtcars$cyl/10+0.2 ) %>% # Change size by number of cylinder
set("nodes_pch", 19) %>% set("nodes_cex", 0.8) %>% set("nodes_col", 3) %>% #add nodes
plot(main = "Hierarchical cluster dendrogramm colored by engine (vs) \nFont size by cylinder") # plot
colored_bars(colors = the_bars, dend = dend, rowLabels = c("cyl","vs","am","gear","carb","mpg","disp","hp","drat","wt","qsec"), sort_by_labels_order = FALSE) #sort_by_labels_order = FALSE is very important, otherways you get the colors sorted by their appearance in the dataset rather than in the dendrogram
AWS EMR 中的 RStudio 服务器简单、可重复且快速
原文:https://towardsdatascience.com/rstudio-server-in-aws-emr-easy-reproducible-and-fast-f066aa6135d?source=collection_archive---------33-----------------------
理解大数据

由马克·佩津在 Unsplash 上拍摄的照片
在我之前写的一篇文章(可以在这里找到)中,我分享了我对使用基础设施作为代码工具的看法,如 Packer 和 Terraform,以创建 Amazon 机器映像(AMI),为数据科学家和数据分析师创建一个可复制的环境,以利用机器中预装的许多工具(Jupyterhub 和 RStudio Server)探索云资源。
我不会在这篇文章中扩展自己,因为已经讨论过了,但是与另一篇博客文章相关的存储库使用 Ansible playbooks 来安装所需的包和库,以便使用 R 和 Python 来开发分析和模型,然而,我探索创建自定义 ami 的可能性的主要原因是在 AWS EMR 集群的部署中使用它们作为基础映像。
推理
许多过去部署过 EMR 集群的人已经知道,集群的部署可以与引导脚本相关联,引导脚本将提供数据科学家、分析师或工程师在工作中使用的必要工具,尽管这是一个重要的解决方案,但它增加了服务器部署的时间代价(与集群初始化相关联的包和库越多,集群部署的时间就越长)。
EMR 的默认部署允许配置 Jupyter 笔记本或 Zeppelin 笔记本以及集群的初始化,但是,R 和 RStudio 用户落后了,因为这两种解决方案在 EMR 集群中都不可用,所以我觉得有必要探索其他既可扩展又快速的解决方案,允许每个分析师/科学家/工程师部署他们自己的集群,以最适合他们需求的语言完成他们的工作,然后在完成后关闭集群。
经过一番挖掘,我发现在 EMR 5.7(以及更高版本)发布后,可以使用定制的 Amazon 机器映像来部署集群,只需遵循一些建议和最佳实践,如这里建议的这里的,比如为高于 EMR 5.30 和 6.x 的 EMR 版本使用 Amazon Linux 2。 使用 Packer 和 Ansible 创建一个定制的 Amazon 机器映像(以确保 RStudio 服务器的安装和配置),然后使用这个映像部署一个 EMR 集群,再做一些配置以确保 RStudio 用户能够访问 Spark 环境、Hadoop 和其他通过使用 EMR 集群可用的特性。
操作方法
和我的另一篇博文一样,这篇博文与一个库相关联,它帮助用户:
- 使用 Terraform 和自定义 AMI 部署 EMR 集群
- 配置默认的 RStudio 服务器用户来访问 Hadoop 文件系统和 Spark 环境
- 将 AWS Glue Metastore 与 Spark 集群一起使用,以便 EMR 集群可以访问 Glue 中已经存在的数据目录
请注意,这个部署是以 AWS 为中心的,我现在没有在其他云中开发这个相同项目的计划,尽管我知道通过使用 Google 云平台和 Azure 上可用的工具这是可能的。
使用 Terraform 部署 EMR 集群
在项目仓库中,我们有一个堆栈来使用模块化的 Terraform 脚本部署 EMR 集群,因此任何满足您的基础设施需求的必要调整(如创建密钥或角色许可)都可以单独实现。到目前为止,Terraform 希望变量如下所述,以允许创建集群主服务器和核心节点。
该实现还支持在主节点和核心节点中使用现场实例,但是,在任何生产环境中,建议至少将主节点部署为按需实例,因为如果主节点关闭,整个集群将被终止。
我的地形配置中可用的变量如下:
# EMR general configurations
name = "" *# Name of the EMR Cluster*
region = "us-east-1" *# Region of the cluster, must be the same region that the AMI was built*
key_name = "" *# The name of the key pair that can be used to SSH into the cluster*
ingress_cidr_blocks = "" *# Your IP address to connect to the cluster*
release_label = "emr-6.1.0" *# The release of EMR of your choice*
applications = ["Hadoop", "Spark", "Hive"] *# The applications to be available as the cluster starts up*
# Master node configurations
master_instance_type = "m5.xlarge" *# EC2 instance type of the master node* *The underlying architecture of the machine must be compatible with the one used to build the custom AMI*
master_ebs_size = "50" *# Size in GiB of the EBS disk allocated to master instance*
master_ami = "" *# ID of the AMI created with the custom installation of R and RStudio*
# If the user chooses to set a bid price, it will implicitly create a SPOT Request
*# If left empty, it will default to On-Demand instances*master_bid_price = ""
# Core nodes configurations
core_instance_type = "m5.xlarge" *# EC2 instance type of each core node* *The underlying architecture of the machine must be compatible with the one used to build the custom AMI*
core_ebs_size = "50" *# Size in GiB of the EBS disk allocated to each core instance*
core_instance_count = 1 *# Number of core instances that the cluster can scale*
# If the user chooses to set a bid price, it will implicitly create a SPOT Request
*# If left empty, it will default to On-Demand instances*core_bid_price = "0.10"
这些配置应该足以让您启动并运行一个定制的 EMR 集群。
允许 AWS EMR 中的自定义端口
自 2020 年 12 月以来,增加了一些增强安全性的更改,要求用户手动允许端口公开可用,可在此处找到。如果不是这种情况,您可以跳到下一个会话,但是,如果您希望通过 internet 公开您的 RStudio 服务器实例,您必须遵循下述步骤:
- 进入 AWS 控制台> EMR
- 选择阻止公共访问(应被激活)
- 编辑端口间隔,以允许 RStudio 服务器公开使用端口 8787
如果您希望部署只对少数 ip 地址可用的自定义服务器,您可以跳过这一步,将 ingress_cidr_blocks 设置为您的个人 IP 地址。
配置 RStudio 服务器以使用全部 AWS EMR 资源
下面描述的步骤已经嵌入到部署集群的 Terraform 脚本中,如果有人希望对其进行调整和定制,这里只是为了提供信息。
在部署服务器之后,添加了配置环境变量的进一步步骤,这使得 RStudio 更容易找到必要的文件,以便与 Spark、Hive、Hadoop 和集群中可用的其他工具一起顺利运行。此外,该步骤将 RStudio 用户添加到 Hadoop 组,并允许它修改 HDFS。
这个步骤可以在这个项目中找到。
AWS 将 metastore 作为 JSON 配置粘附在 Terraform 模块中
随着现成工具(如 AWS Glue)的出现,允许以一种简单的方式转换数据和存储数据及其元数据,需要将 EMR 集群与该堆栈集成。这也已经在 Terraform 堆栈中完成,因此如果用户希望使用 Hive Metastore 而不是托管 AWS Glue Metastore,则需要删除这部分代码。
这个步骤由 EMR main Terraform 中的 configurations_json 完成,它接收关于应该如何配置集群的多个输入,更改 spark-defaults(例如,允许不同的 SQL 目录实现),配置单元站点配置使用 AWS Glue Metastore 作为默认配置单元站点,等等。要配置的可能性列表可在这里找到。
结束语
该项目的部署旨在缩小数据科学相关堆栈的供应之间的差距,试图确保无论数据科学家/分析师/工程师打算使用什么工具,他们都有机会使用它。在部署结束时,人们应该能够在不到 10 分钟的时间内访问功能完整的 EMR 集群,在 EMR 的主节点上安装和配置 R 和 RStudio 服务器。
任何与这个项目相关的问题,包括建议,都可以添加到 Github 资源库中。
RTFQ:让洞察力变得简单和可持续
原文:https://towardsdatascience.com/rtfq-making-insights-simple-and-sustainable-5cff24ac8e66?source=collection_archive---------47-----------------------
行业笔记
带来更多成功结果的商业分析原则

由乔治亚·德·洛茨在 Unsplash 上拍摄的照片
数据是一个飞速发展的领域。似乎每天都有新的发展和令人兴奋的新技术发布,准备改变世界。作为一名数据科学家、分析师或工程师,使用前沿技术的诱惑是巨大的!
然而,正如发生在我身上不止一次的那样,这通常会导致比更简单、更老的方法好不了多少的输出。或者更糟的是,最终产品根本没有落到非数据同事的手里,导致您所有的努力都付之东流。这可能是由多种原因造成的,例如难以向同事解释黑箱是如何做出决定的,或者使用过于复杂的解决方案来解决简单的业务问题,或者没有花足够的时间来使得出的见解简单明了。
在我看来,解决的办法是专注于问题,做足够的事情来解决问题。把节省下来的时间花在尽可能好的展示和交流上。
这篇文章的其余部分描述了一个我在工作中陷入这个陷阱的例子,其中高级管理人员希望快速自助一些关键指标。旅程从自然语言到 SQL 翻译的梦想开始,集成到 Slack bot 中,在 BERT、GPT-3 和 4 以及 TAPAS 中漫游,然后意识到有许多更简单的方法来解决业务问题。最终的解决方案在几秒钟内提供答案,其格式已经被所有人使用,具有 100%的准确性、精确度、召回率或任何您喜欢的评估指标…
开始的时候…
…有业务需求。尽管拥有广泛的 Tableau 和 Data Studio 仪表盘,但高级管理层需要能够了解特定的数字,如注册率、在特定日期范围内使用特定平台上的特定服务,而无需搜索仪表盘。首先想到的是 SQL 查询,然后是如何让不懂 SQL 的人也能使用 SQL 查询。
数据科学的魔力
像翻译这样的自然语言处理任务是我们在开始时谈到的发展非常迅速的领域之一。就在几年前,谷歌翻译还能翻译单个单词,但在翻译较长的文本时,它对 YouTube 上的笑话视频更有用。进入变压器和神经网络,计算机语言翻译性能爆炸。像 DeepL 这样的网站现在可以准确地翻译整本书。
考虑到这一点,我花了整整一周的时间来研究它,我最初的想法是使用类似 BERT 的东西来设计一个英语到 SQL 的翻译器。我的研究表明,令人震惊的是,我并不是第一个有这种想法的人,整个社区都在 WikiSQL 上做这件事。最先进的测试精度也令人印象深刻,弱监督方法的准确率为 83.7%,监督方法的准确率为 87.5%。然而,试验这些方法很快就暴露了问题。WikiSQL 数据比工作时更干净、更小。这些方法很复杂(维护风险),很难用通俗易懂的语言解释。这意味着实际 SQL 表的准确性低得令人无法接受,而且实现速度很慢。
揭开小吃
对更简单、更轻便、更精确的解决方案的探索仍在继续。在进入 GPT 4 的恐怖和惊人的世界后,我发现了另一个类似于 SQL 解决方案的文本, Google 的 TAPAS 。

TAPAS 是谷歌一长串有趣的 NLP 开发中的又一个。图片来自 Github
TAPAS 直接处理表格数据,而不是将文本翻译成 SQL,并让 SQL 处理数据。这使得事情变得更快,更简单,更容易处理和解释,同时它保持了与其他 WikiSQL 模型相同的精确度。像大多数谷歌产品一样,文档非常棒,对于我们这些只有硕士学位的人来说,这是一个很大的不同!
不幸的是,有缺点。表格的大小是有限的(我尝试的时候是 512 个单元格),这意味着我不能使用原始的数据库数据。我编写了一些脚本来按照日期、服务和平台(根据业务需要)聚合数据,但是表仍然太大。当我准备开始拆分表和多次运行模型的工作时,突然想到了解决方案。
为什么要用大锤敲碎坚果?
伯特和它的许多形式是惊人的,塔帕斯是惊人的,GPT-5 可能会杀了我们所有人!但是他们的神奇会让像我这样的人误入歧途。被激动人心的技术蒙蔽了双眼,我忘记了最重要的是产出,问题的解决方案。
回到问题,查看高级管理人员过去的请求,他们只可能问大约 10 个具体指标,按日期、平台和服务划分。除此之外,虽然他们使用 Slack 给同事发消息,但他们并不像组织中的其他人那样将它用作监控工具。相反,人们喜欢以谷歌表单的形式获得他们的度量和分析。
考虑到所有这些,解决方案很简单。使用上面提到的聚合脚本,可以从数据库中提取数据,聚合并加载到一个隐藏的中央 Google sheet 中,充当一个粗略的临时数据仓库。然后,每个人都可以有自己的链接表,只有 3 个下拉菜单和一个日期范围选择器(比输入完整格式的问题更快)和一个带有公制答案的大盒子。任何人都可以使用,熟悉的格式,在几秒钟内回答,100%的准确性和完全解决业务问题的东西。
事实上,它没有使用花哨的技术,只有几行代码使用 Lambda 自动生成的 Pandas,并使用像 Google Sheets 这样的基本工具,这可能会导致尴尬和担心人们会认为你是某种业余爱好者。但是数字不会说谎。这个自助服务系统是迄今为止最受同事欢迎的产品,拥有比其他任何产品多 700%的独立用户,好评如潮。
最后…
以下仅是我的看法,但我的经历似乎越来越表明,这些原则会带来更成功的结果。
原则一:商业问题为王。确保你花时间确保你理解它,并计划最简单的解决方案。在某些情况下,这可能是强化学习和深度神经网络的结合,但在其他情况下可能不是。
原则二:关注输出是如何呈现的。解决方案可能是完美的,但如果以完全不熟悉和技术上不合适的方式呈现,可能需要很长时间才能被广泛接受,或者可能根本不被接受。
原则 3: 确保它易于解释、维护和记录。没有人会永远做他们的工作。你的解决方案通常会比你持久。如果你的替代者来了,但不能掌握你所建立的东西,它可能不会比你活得久。通过从一开始就确保事情只像它们需要的那样复杂,并且有很好的文档记录,那么留下受尊敬的数据遗产的机会会提高许多倍。
今天,免费举办一场机器学习竞赛。
原文:https://towardsdatascience.com/run-a-machine-learning-competition-for-free-today-9e87a9f5c00?source=collection_archive---------28-----------------------
使用 DSLE:设计数据科学竞赛的智能平台。

由卢卡斯·布拉塞克在 Unsplash 拍摄的照片
什么是 DSLE?
DSLE 是一个用于构建机器学习竞赛的 API,内置于 python (Flask)中。这是都灵理工大学(意大利都灵)一篇研究论文的成果。其目的是为设计和监控机器学习竞赛提供一个开源平台,该平台易于使用且高度可定制。[1]
我应该期待什么?
使用 DSLE,你应该能够建立任何类型的私人或公共比赛。您可以利用 API 本身提供的极简界面,或者将其嵌入到您的 web 应用程序中。考虑到代码【2】带有知识共享署名 4.0 国际公共许可证【3】,你对使用 DSLE 代码所能构建的东西的期望主要受限于你作为软件开发人员的技能。
本文将探讨如何仅使用 API 及其内置接口来建立竞赛。我们还将做一些小的编辑来增加它的健壮性:
- 将申请归档
- 添加需求依赖版本
最后,您将能够通过上传您的解决方案的 csv 文件来举办比赛,还可以创建自定义 API 密钥来与您的朋友共享,以便他们可以上传他们的结果。
先决条件
要在本教程后面使用 Docker 和 Docker compose,您需要在您的计算机上安装它们。访问这里了解更多关于如何安装它们的细节:https://www.docker.com
我们开始吧
首先,我们要从这里下载 https://zenodo.org/record/3666486#.YW6WYy8w30o 代码:
截至今天,最新版本的代码是0.1.0,上传于 2020 年 2 月 13 日。根据您访问存储库的时间,您的最新版本可能与我的不同。下载后,你可以用你选择的代码编辑器打开代码文件夹:我使用 Visual Studio 代码,但是其他的也可以。
提示:你也可以在文末找到我的 GitHub 公开回购的链接。
将申请归档
如果你已经看过原始回购中提供的README.md文件,你可能会注意到它并不包含如何运行该应用程序的最彻底的说明。但是,它建议您创建一个虚拟环境来本地运行它。另一方面,我发现 dockerised 环境比传统的虚拟环境更容易管理,并且添加了更好的“容器层”。
如果你不熟悉 docker,我写了一篇文章在这里关于如何使用 flask 和 Docker 自动化 pandas workflow,它提供了一种在没有任何 Docker 或 Flask 知识的情况下建立 Flask 应用程序的简单方法:https://medium . com/analytics-vid hya/automate-your-pandas-workflow-with-Flask-Docker-28e 5 ab 461288
因此,让我们创建一个Dockerfile和docker-compose.yml,并将除了requirements.txt和README.md之外的所有其他文件移动到一个名为app的子文件夹中。
此时,您应该有这样的文件夹结构:

最终文件夹结构
打开您刚刚创建的Dockerfile,复制粘贴下面的代码:
现在打开docker-compose.yml并粘贴以下内容:
如果你需要更多关于Dockerfile和docker-compose.yml代码的信息,你可以在我上面链接的文章中读到。
注意:在我们构建并运行我们的应用程序之前,如果您已经使用了上述的
Dockerfile,请确保将文件app.py重命名为main.py并修改文件WSGI.py第 3 行:来自:
from app import app as flask_app至:至:
from main import app as flask_app
构建并运行应用程序
打开你的终端,进入Dockerfile所在的应用目录。如果最后一条指令对你来说很奇怪,不要担心,它实际上很简单:
- 打开您的终端,键入
cd(带空格)、,不要按回车键 - 将应用程序文件夹拖放到终端窗口中(这将自动生成文件夹路径)
- 按回车键
现在您可以键入docker-compose build来构建您的 docker 映像。一旦完成,输入docker-compose up运行 docker 容器。
注意:如果您有一个关于名为greenlet的依赖项版本的错误,您可以通过在您的requirements.txt上添加下面一行来解决它:greenlet == 0.4.17。然后保存需求文件并重新构建容器映像。
最后,要检查应用程序是否运行良好,请在您最喜欢的浏览器上访问127.0.0.1或 localhost,您应该会看到类似这样的内容:

PS。不要担心有效期;我们稍后会改变这一点。
更新需求文件
您可能已经注意到了,requirements.txt文件包含一个依赖项名称列表,但是缺少版本号。这意味着每次构建容器映像时,安装的依赖项都是最新的版本。
截至今天,2021 年 10 月 19 日,除了上面描述的greenlet问题之外,没有太多变化,所有依赖项在其最新版本上都运行良好。但是,将来这种情况可能会改变,所以如果您遇到依赖问题,这里是我的requirements.txt文件的快照,您可以用作参考:
为比赛做准备
现在,应用程序正在运行,我们可以花时间来设置我们的竞争数据。
DSLE 应用程序通过将提供的解决方案与参与者上传的数据集进行比较来工作。[1]默认情况下,解决方案和参与者提交的内容都必须采用csv格式。
要为比赛格式化数据,您应该以这样的方式分割数据集:将一部分数据发送给参与者进行培训和测试,另一部分作为隐藏解决方案,应用程序将使用该解决方案进行验证并对提交的数据进行评分。
如何在熊猫身上做到这一点的一个例子是:
添加解决方案文件:
导航到app/static/test_solution并用您的solution文件替换文件test_solution.csv;然后重命名您的文件test_solution.csv。
定制比赛配置:
打开文件config.py。在这里你可以改变比赛的某些方面,比如开始和结束的时间以及比赛的管理,以适应你的需要。
在配置选项中,您还会看到API_FILE_PATH引用了一个名为mappings.dummy.json的文件。在这里,您可以找到一个用户“字典”,其中已经映射了相关的 API 键。您可以随意更改它们,也可以添加更多内容与单身参与者分享。在提交或检查结果时,他们将使用您提供的 API 密钥进行身份验证。
定制评估指标
在开展竞赛之前,您需要设置评估指标,用于对参与者提交的内容进行评分。你可以在evaluation_functions.py文件中找到这个选项。默认情况下,使用的度量是准确性;你可以在这里找到所有可用函数的列表:https://sci kit-learn . org/stable/modules/model _ evaluation . html
或者,如果您需要包含多个指标和更复杂的评估,您可以创建自己的函数。
主持比赛
现在一切就绪,您只需要在服务器或本地网络上部署 docker,并与您的参与者共享 API 密钥和公共数据集。每次有人提交,公共排行榜上的分数就会自动生成。
我希望您喜欢这个简短的指南,并且能够顺利地运行您的应用程序。如果你想查看 dockerised app 的最终代码,可以在这里找到我的公共 GitHub repo:https://github.com/fabiom91/DSLE_dockerised
参考文献:
1。 G. Attanasio 等人。,“DSLE:设计数据科学竞赛的智能平台”, 2020 IEEE 第 44 届计算机、软件和应用年会(COMPSAC) ,2020,第 133–142 页,doi:10.1109/COMPSAC 48688 . 2020 . 00026
2。 DSLE:设计数据科学竞赛的智能平台。0.1.0,芝诺多,2020 年 2 月 13 日,p,doi:10.5281/芝诺多. 3666486。
3 。【https://creativecommons.org/licenses/by/4.0/legalcode】
在谷歌联合实验室上运行 Jupyter 实验室
原文:https://towardsdatascience.com/run-jupyter-lab-on-google-colaboratory-7b02075f61c?source=collection_archive---------45-----------------------
简单使用一个反向 SSH 隧道来大大提高可用性。

这不是 SSH 隧道,但仍然是一个反向隧道。2019 年葡萄牙辛特拉。(作者供图)。
介绍
我们已经很久没有写过任何“类似工程”的话题了。因为我们都想保持高效和多产,所以这是一个重温谷歌联合实验室的好时机。
总的来说,谷歌合作实验室(Google Colaboratory,简称 Colab)一直是数据科学家或机器学习爱好者的一个伟大平台。它在有限的时间内提供了一个免费的 GPU 和 TPU 实例,此外它还提供了一个美化版的 Jupyter 笔记本。这是各种小型或中型项目的绝佳组合。
不幸的是,它有一定的局限性。最大的问题是缺乏存储持久性,以及局限于单个文档。这两个限制使开发变得复杂,并使处理多个文件变得不那么简单。
虽然社区已经开发了一些好的解决方案(包括我之前的工作这里和这里,我们中的许多人仍然在寻找类似“数据工作室”的东西,也就是 Jupyter Lab 。
在本文中,我们将展示如何通过 Colab 在 Google 机器上安装和运行 Jupyter Lab 实例,将其转变为一个免费的带有 Jupyter Lab 前端和 GPU/TPU 后端的定制解决方案。更重要的是,这里介绍的方法是通用的,也允许你使用其他服务,比如 Flask。它不同于这里的这里的或者这里的,因为它们显示了如何将 Jupyter Colab 前端连接到本地实例。在这里,我们将做完全相反的,所以继续!
大意
主要想法是利用驻留在 Colab 笔记本后面的服务器,并使用其后端功能,但取代前端。要使其工作,步骤如下:
- 点击笔记本后面的服务器。
- 安装我们需要的所有软件包(例如 Jupyter Lab)。
- 建立沟通渠道。
- 连接到它,玩得开心。
入门指南
转到 https://colab.research.google.com 的来启动一个新实例,连接到它,并等待资源被分配。如果你愿意,现在是时候将后端切换到 GPU 或 TPU(除非你想重复所有步骤)。

图一。我们已经连接到谷歌后端的证据。(作者供图)。
准备工作区
第一次“黑”
现在,我们需要更深入地与笔记本背后的机器对话,而不是与笔记本本身对话。与底层 shell 交互的标准方式是在 bash 命令前面加上!(例如!ls -la)。但是,它可能会在以后产生一些问题,所以最好使用一种替代方式,主要是执行
eval "$SHELL"
在一个细胞中,这将让我们与后面的控制台直接沟通。
安装 Jupyter 实验室
接下来,我们安装 Jupyter 实验室或任何其他东西。Colab 本身没有安装它,您可以通过执行以下命令来确认:
pip list | egrep jupyter
# output
jupyter 1.0.0
jupyter-client 5.3.5
jupyter-console 5.2.0
jupyter-core 4.7.0
jupyterlab-pygments 0.1.2
jupyterlab-widgets 1.0.0pip install jupyterlab
pip list | egrep jupyter
# output
jupyter 1.0.0
jupyter-client 6.1.11
jupyter-console 5.2.0
jupyter-core 4.7.0
jupyter-server 1.2.2
jupyterlab 3.0.5
jupyterlab-pygments 0.1.2
jupyterlab-server 2.1.2
jupyterlab-widgets 1.0.0
所以现在,我们已经拥有了 Python 环境所需要的一切,但是我们仍然需要在笔记本之外公开它。为此,我们将做所谓的反向 ssh 隧道。
反向 SSH 隧道
反向 SSH 隧道允许使用两台机器之间的现有连接来建立从本地机器到远程机器的新连接通道。正如这篇文章所解释的:
因为最初的连接是从远程计算机到您的,使用它去另一个方向就是“反向”使用它因为 SSH 是安全的,所以您将安全连接放在了现有的安全连接中。这意味着您到远程计算机的连接充当原始连接内部的专用隧道。
现在,按照本文使用的词汇,本地机器实际上是运行 Colab 的 Google 服务器。我们想向外界公开的就是这台机器的端口。然而,由于我们不知道本地机器的外部地址(或者按照本文的词汇表,是“远程”机器),我们使用第三方服务,即http://localhost.run/。
这个解决方案是由 haqpl 建议的,他是一个专业的 pentester,也是我的一个朋友。
它既是反向 SSH 隧道的终端,也是普通的 HTTP 服务器,允许我们将其用作通信的桥梁。换句话说,该服务在一端完成 SSH 隧道,在另一端完成 HTTP 服务器,将我们的本地 PC 连接到我们在 Colab 上运行的任何服务。
生成公钥
在我们开始之前,有一件事我们需要注意。我们需要一个密钥对来保护没有密码的 SSH 通道。
这是容易的部分。详细说明可以在 GitHub 上找到。对我们来说,执行以下命令就足够了。不要担心密码短语。只要按下回车键。
ssh-keygen -t ed25519 -C "your_email@example.com"
默认情况下,密钥存储在/root/.ssh/id_ed25519.pub下。接下来,确认我们有ssh-agent并注册密钥。
eval "$(ssh-agent -s)"
ssh-add
# expected response
Identity added: /root/.ssh/id_ed25519 (your_email@example.com)
此时,我们准备测试隧道。
测试连接
为了初始化连接,我们需要选择一个不太可能被系统使用的端口。比如 9999。这是一个很好的数字,不是吗?然后,要执行的命令将把这个端口映射到端口 HTTP 连接的标准端口)。此外,我们需要让系统对宿主是谁视而不见。因此有了-o旗。
ssh -o StrictHostKeyChecking=no -R 80:localhost:9999 ssh.localhost.run
如果一切顺利,响应的最后一行应该会给出指向本地机器的 URL。

图二。SSH 反向隧道已经建立。在我们的例子中,URL 是 root-3e42408d.localhost.run。
然而,当您将它复制粘贴到您的浏览器时,您最有可能得到的响应是Something went wrong opening the port forward, check your SSH command output for clues!。这没问题,因为这个端口上确实没有运行任何服务(还没有)。
让我们在这个端口下启动一个小的 python 服务器(或者如果你以前用过的话就换一个)。
python -m http.server 9999 & ssh -o StrictHostKeyChecking=no -R 80:localhost:9999 ssh.localhost.run
当连接建立后,您应该能够在浏览器中浏览 Colab 上的文件,看到这样的行:
====================================================================
root-be893e68.localhost.run tunneled with tls termination
127.0.0.1 - - [14/Jan/2021 22:39:21] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [14/Jan/2021 22:39:22] code 404, message File not found
127.0.0.1 - - [14/Jan/2021 22:39:22] "GET /favicon.ico HTTP/1.1" 404 -
在笔记本上打印出来。
这是一个非常好的迹象!这意味着如果我们可以运行python -m http.server,我们也可以用 Flask 或 Jupyter Lab 来代替它,这正是我们将要做的!
最后一击
现在,让我们更改端口,开始实验。要运行的命令有点长,原因是我们必须传递必要的参数:
--ip=0.0.0.0强调这是一台本地机器(本地到 Colab)。--port=8989当然,--allow-root,否则 Lab 将启动但拒绝与您通信。
jupyter lab --ip=0.0.0.0 --port=8989 --allow-root & ssh -o StrictHostKeyChecking=no -R 80:localhost:8989 ssh.localhost.run
同样,如果一切正常,那么借助 SSH 隧道,我们应该使用前面发布的 URL 从外部访问 Jupyter 实验室。唯一的附加组件是您可以从响应中读取的参数和令牌。

图 3。Jupyter 实验室实例正在运行的确认。(作者供图)。
将给出的 URL 复制粘贴到浏览器的另一个标签中。记得用之前收到的 URL 替换localhost:8989。

此处图 4。Jupyter 实验室确实连接到 Colab 后端的确认。(作者供图)。
结论
就是这个!我们通过反向 SSH 隧道(和 haqpl )创建的 Jupyter Lab 和 Google Colaboratory 的组合,可能会提供最终的自由,因为现在您可以简化文件的上传/下载,方便地跨多个文件组织您的项目,并为您的计算提供真正强大的硬件支持……免费。
一句话,在我们走之前…记住,尽管 SSH 通道是安全的,但会话对任何知道你的 URL 的人都是开放的。如果作为工作的一部分,你决定在机器上安装 Google Drive,那么即使你不知道,也有可能有人访问你的文件。所以,请小心使用这个“黑客”。或者,您可以考虑使用虚拟专用服务器(VPS)来取代localhost.run,并给予端点独占所有权。
感谢阅读!请在评论中告诉我,以防你遇到问题或有任何建议。祝你好运,玩得开心!
还会有更多…
我计划把文章带到下一个层次,并提供简短的视频教程。
如果您想获得关于视频和未来文章的更新,订阅我的 简讯 。你也可以通过填写表格让我知道你的期望。回头见!
原载于https://zerowithdot.com/jupyter-lab-colab/。
使用 PecanPy 以更少的内存运行 node2vec ultrafast
原文:https://towardsdatascience.com/run-node2vec-faster-with-less-memory-using-pecanpy-1bdf31f136de?source=collection_archive---------26-----------------------
理解大数据
一种流行的图形嵌入方法的简单实现

来自 Pixabay 的大卫·马克的图片
Node2vec 是一种节点嵌入方法,它生成图中节点的数字表示(或嵌入)[1]。然后,这些嵌入被用于各种下游任务,例如节点分类和链路预测。如果你对 node2vec 不熟悉,可以看看我的另一篇文章来解释它的直觉。
TL;速度三角形定位法(dead reckoning)
- Node2vec 是一种非常流行的嵌入方法,用于生成图(也称为网络)中节点的数字表示,然而最初的实现是慢和内存低效。
- PecanPy 是 node2vec 的超快速和内存高效的实现,可以通过 pip 轻松安装,并且可以从命令行或在您的 Python 脚本中使用。
- 作为一个使用字符串网络的例子,PecanPy 将运行时间从 5 小时减少到略超过一分钟,并将内存使用量从 100GB 减少到 < 1GB 。
node2vec 的原始 Python 实现速度慢且内存效率低
最初的实现(在 C++ 和 Python 中实现)非常慢,内存效率也很低。在这篇博客文章中,我将介绍 PecanPy [2],一个 p 并行化的,内存 e ffi c ient 和aacceleratednode 2 vec inPython,我们将看到运行时间和内存使用都比最初的实现有了显著的改进。

图 1。两个生物网络 BioGRID 和 STRING 上 node2vec 的运行时和内存使用情况。
让我们来看两个嵌入生物网络 BioGRID 和 STRING 的例子。两个网络都有大约 20k 个节点,STRING 的密度稍大。使用原始 Python 实现完全嵌入字符串花费了超过 5 个小时和 100GB 的内存,并为 BioGRID 使用了超过 1GB 的内存,即使整个网络的文件大小只有 2.5 MB。惯坏警告:使用 pec 嵌入字符串只花费了略超过 一分钟 ,内存不到1GB
node2vec 最初实现的三个主要问题
以下问题专门针对最初的 Python 实现。尽管 C++实现在某些方面更有效,但我们将在下一节中看到,它仍然受到内存问题的困扰,并且运行速度比 PecanPy 慢。
并行性问题:转移概率预处理和随机游走生成没有并行化,尽管这两个过程具有令人尴尬的并行性,即每个游走生成都是独立的任务,不依赖于任何其他的游走。
图形数据结构问题:Python 原始实现使用 networkx 存储图形,对于大规模计算效率相当低。受 Matt Ranger 的这篇博客文章的启发,PecanPy 对稀疏图使用紧凑稀疏行(CSR)格式,这种格式更紧凑地存储在内存中,最重要的是,运行速度更快,因为它可以更好地利用缓存。然而,CSR 有一个问题,如果图是密集的(比如完全连接,这在生物学中很常见,如基因共表达网络),那么由于显式存储索引,在 CSR 中存储需要比所需更多的内存。为了处理密集网络,我们还添加了另一个选项来存储为 2D numpy 数组。
内存问题:内存使用量远远超过网络文件大小的原因是二阶转移概率的预处理和存储。为了解决这个问题,我们可以简单地删除预处理步骤,并根据需要计算转移概率,而无需保存。然而,对于仍然可以保存所有二阶转移概率的小型稀疏网络,建议包括预处理步骤,因为它可以更快地生成随机游走,而无需在每个步骤中重新计算转移概率。

图 2。PecanPy 执行模式概述。
PecanPy 解决了上述所有问题,并提供了三种执行模式,包括 PreComp 、 SparseOTF 和 DenseOTF ,每种模式都针对不同大小和密度的图形进行了更优化。简而言之,两种 OTF (代表 On The Fly)模式通过即时计算转移概率来解决内存问题,而 PreComp 模式保留了在较小网络上的原始实现中的预处理步骤,以实现更快的遍历生成。最后,稀疏和密集表示是用 CSR 还是 numpy 数组来存储图形。
基准测试结果

图 3。node2ec 在 8 个不同网络上的不同实现的运行时和内存使用情况
图 3 显示了原始实现和 PecanPy 之间的运行时和内存使用比较,使用了不同规模和密度的网络,包括 node2vec 论文[1]中测试的网络。首先,请注意,与最初的 Python 和 C++实现相比,PecanPy 的所有三种模式都实现了更快的运行时。特别是,嵌入字符串网络仅用了一分多钟。其次, OTF 策略显著降低了内存使用量。再看 STRING, SparseOTF 能够用不到 1GB 的内存完全嵌入网络,而两个原始实现都需要~100GB 的内存。此外,由于内存限制(使用 200GB 资源配置进行测试),GIANT-TN 网络(26k 节点,完全连接)不能使用任何原始实现进行嵌入。
最后,PecanPy 生成的嵌入质量被证实与原始 Python 实现生成的嵌入质量相同。查看[2]了解更多信息。
PecanPy 入门
你可以在 GitHub 上查看最新(未发布)的 PecanPy。也可以通过 pip : pip install pecanpy轻松安装,安装最新发布的 PecanPy 版本。使用由基准库提供的工作流脚本,所有基准都是可再现的(您也可以使用它来基准测试您自己的 node2vec 实现)。
PecanPy 既可以从命令行使用,也可以作为 Python 脚本中的模块加载。例如,下面的命令行脚本嵌入了带有 SparseOTF 模式的空手道网络:
*pecanpy --input karate.edg --output karate.emb --mode SparseOTF*
或者换句话说,您可以将 PecanPy 作为一个模块加载,并从图中生成随机遍历,然后可以用它来生成嵌入:
*from pecanpy import pecanpy# load graph object using SparseOTF mode
g = pecanpy.SparseOTF(p=1, q=1, workers=1, verbose=False)
g.read_edg("karate.edg", weighted=False, directed=False)# generate random walks
walks = g.simulate_walks(num_walks=10, walk_length=80)# use random walks to train embeddings
w2v_model = Word2Vec(walks, vector_size=8, window=3, min_count=0, sg=1, workers=1, epochs=1)*
与 ndoe2vec 的现有实现相比
尽管 node2vec 有许多其他现有的实现,包括由 Matt Ranger开发的 nodevectors 和由 Elior Cohen 开发的 Python3 node2vec ,但是它们都没有提供一个系统化的基准来显示到底加速了多少,并且很少处理内存问题。此外,现有的实现都没有显示嵌入的质量控制,尽管在优化代码时容易出错并引入错误,例如在随机漫步生成中,从而降低了所得嵌入的质量。PecanPy 提供了嵌入的系统性能基准和质量控制,使用基准库中设置的工作流程可以完全重现。
参考
[1] Grover A .,Leskovec J. (2016) node2vec:网络的可扩展特征学习。在:第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,KDD 2016 年,第 855–864 页。美国纽约州纽约市计算机协会。
[2]刘,Arjun Krishnan,pecan py:node 2 vec,生物信息学*的快速高效并行 Python 实现,2021;,btab202,【https://doi.org/10.1093/bioinformatics/btab202 *
跑熊猫像火花一样快
原文:https://towardsdatascience.com/run-pandas-as-fast-as-spark-f5eefe780c45?source=collection_archive---------1-----------------------
为什么 Spark 上的熊猫 API 完全改变了游戏规则

克莱顿·霍尔姆斯在 Unsplash 上拍摄的照片
就是这样。它出来了。Spark 现在有一个熊猫 API。
似乎每次你想使用数据框架时,你都必须打开一个放着所有工具的杂乱抽屉,并仔细寻找合适的工具。
如果你处理结构化数据,你需要 SQL 。熊猫也总是在那里。Spark 是大数据不可或缺的。工具箱里有满足各种需求的工具。但是你再也不需要工具箱了,因为 Spark 已经成为了终极的瑞士军刀。
这一切都始于 2019 Spark + AI 峰会。考拉,一个开源项目,使熊猫能够在 Spark 上使用,已经启动。起初,它只涵盖了熊猫功能的一小部分,但它逐渐成长。两年过去了,现在,在新的 Spark 3.2 版本中,考拉已经并入 PySpark。结果很棒。
Spark 现在集成了 Pandas API,所以你可以在 Spark 上运行 Pandas。你只需要修改一行代码:
import pyspark.pandas as ps
是不是很棒?
由于这一点,我们可以获得广泛的好处:
- 如果你用熊猫但是不熟悉 Spark,马上就可以用 Spark 工作,没有学习曲线。
- 你可以有一个单一的代码库来处理所有事情:小数据和大数据。单机和分布式机器。
- 你可以更快地运行你的熊猫代码。
这最后一点尤其值得注意。
一方面,您可以在 Pandas 中将分布式计算应用到您的代码中。但好处不止于此。多亏了 Spark 引擎,你的代码会更快甚至在单机上!
如果你想知道,是的,看起来熊猫星火也比 Dask 快。
我对这一突破感到非常兴奋,那么,我们为什么不进入正题呢?让我们用 Spark 上的熊猫 API 做一些代码吧!
在熊猫、熊猫火花和火花之间切换
我们需要知道的第一件事是我们到底在做什么。当与熊猫一起工作时,我们使用类pandas.core.frame.DataFrame。当在 Spark 中使用 pandas API 时,我们使用类pyspark.pandas.frame.DataFrame。两者相似,但不相同。主要区别是前者在一台机器上,而后者是分布式的。
我们可以创建一个熊猫在火花上的数据帧,并将其转换为熊猫,反之亦然:
# import Pandas-on-Spark
import pyspark.pandas as ps# Create a DataFrame with Pandas-on-Spark
ps_df = ps.DataFrame(range(10))# Convert a Pandas-on-Spark Dataframe into a Pandas Dataframe
pd_df = ps_df.to_pandas()# Convert a Pandas Dataframe into a Pandas-on-Spark Dataframe
ps_df = ps.from_pandas(pd_df)
请注意,如果您使用多台机器,当将 Pandas-on-Spark 数据帧转换为 Pandas 数据帧时,数据会从多台机器传输到一台机器,反之亦然(参见 PySpark 指南)。
我们还可以将 Pandas-on-Spark 数据帧转换为 Spark 数据帧,反之亦然:
# Create a DataFrame with Pandas-on-Spark
ps_df = ps.DataFrame(range(10))# Convert a Pandas-on-Spark Dataframe into a Spark Dataframe
spark_df = ps_df.to_spark()# Convert a Spark Dataframe into a Pandas-on-Spark Dataframe
ps_df_new = spark_df.to_pandas_on_spark()
数据类型会发生什么?
当使用 Pandas-on-Spark 和 Pandas 时,数据类型基本相同。当将 Pandas-on-Spark 数据帧转换为 Spark 数据帧时,数据类型会自动转换为适当的类型(参见 PySpark 指南)
用熊猫火花复制火花功能
本节的目的是提供一个备忘单,其中包含管理 Spark 中的数据帧以及 Pandas-on-Spark 中类似数据帧的最常用函数。注意,Pandas-on-Spark 和 Pandas 在语法上的唯一区别只是import pyspark.pandas as ps行。
您将看到,即使您不熟悉 Spark,也可以通过 Pandas API 轻松使用它。
导入库
# For running Spark
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("Spark").getOrCreate()# For running Pandas on top of Spark
import pyspark.pandas as ps
读取数据
让我们以老狗虹膜数据集为例。
# SPARK
sdf = spark.read.options(inferSchema='True',
header='True').csv('iris.csv')# PANDAS-ON-SPARK
pdf = ps.read_csv('iris.csv')
选择
# SPARK
sdf.select("sepal_length","sepal_width").show()# PANDAS-ON-SPARK
pdf[["sepal_length","sepal_width"]].head()
删除列
# SPARK
sdf.drop('sepal_length').show()# PANDAS-ON-SPARK
pdf.drop('sepal_length').head()
删除重复项
# SPARK
sdf.dropDuplicates(["sepal_length","sepal_width"]).show()# PANDAS-ON-SPARK
pdf[["sepal_length", "sepal_width"]].drop_duplicates()
滤镜
# SPARK
sdf.filter( (sdf.flower_type == "Iris-setosa") & (sdf.petal_length > 1.5) ).show()# PANDAS-ON-SPARK
pdf.loc[ (pdf.flower_type == "Iris-setosa") & (pdf.petal_length > 1.5) ].head()
计数
# SPARK
sdf.filter(sdf.flower_type == "Iris-virginica").count()# PANDAS-ON-SPARK
pdf.loc[pdf.flower_type == "Iris-virginica"].count()
截然不同的
# SPARK
sdf.select("flower_type").distinct().show()# PANDAS-ON-SPARK
pdf["flower_type"].unique()
排序
# SPARK
sdf.sort("sepal_length", "sepal_width").show()# PANDAS-ON-SPARK
pdf.sort_values(["sepal_length", "sepal_width"]).head()
分组依据
# SPARK
sdf.groupBy("flower_type").count().show()# PANDAS-ON-SPARK
pdf.groupby("flower_type").count()
更换
# SPARK
sdf.replace("Iris-setosa", "setosa").show()# PANDAS-ON-SPARK
pdf.replace("Iris-setosa", "setosa").head()
加入
# SPARK
sdf.union(sdf)# PANDAS-ON-SPARK
pdf.append(pdf)
结论
从现在开始,你将可以在 Spark 中使用熊猫。这导致了 Pandas 速度的提高,迁移到 Spark 时学习曲线的减少,以及单机计算和分布式计算在同一代码库中的合并。
我想留给读者几个问题:
- 你认为 Spark 会成为管理数据框架的终极瑞士军刀吗?
- 熊猫会像 Dask 或者 Vaex 一样杀光其他库吗?
- 熊猫用户会逐渐迁移到 Spark 吗?
- 我们将来会看到
import pandas as pd吗?
参考
- Spark 用户指南:Spark 上的熊猫 API
- 即将发布的 Apache Spark 3.2 的熊猫 API
运行 Jupyter 笔记本上的零碎代码,没有任何问题
原文:https://towardsdatascience.com/run-scrapy-code-from-jupyter-notebook-without-issues-69b7cb79530c?source=collection_archive---------6-----------------------
Scrapy 是一个开源框架,用于从网站中提取数据。它快速、简单且可扩展。每个数据科学家都应该熟悉这一点,因为他们经常需要以这种方式收集数据。数据科学家通常更喜欢使用某种计算笔记本来管理他们的工作流程。Jupyter 笔记本在数据科学家中非常受欢迎,其他选项包括【py charm】zeppelinVS Codeinteract、Google Colab、和spyder等等。
使用 Scrapy 的刮擦通常是用一个.py文件完成的。它也可以从笔记本电脑初始化。问题是,当代码块第二次运行时,它抛出一个错误“ReactorNotRestartable:”。

由 Clément Hélardot 在 Unsplash 上拍摄
使用[crochet](https://pypi.org/project/crochet/)包可以解决这个错误。ReactorNotRestartable使用该软件包可以减少错误。在这篇博文中,我展示了我从 Jupyter Notebook 运行 scrapy 代码而不出错的步骤。
先决条件:
刺儿头:
pip install scrapy钩针 :
pip install crochet任何适合 python 的笔记本,我用的是 Jupyter 笔记本:
pip install notebook
演示项目:
为了演示这些步骤,我从 wikiquote 中搜集了美国摇滚歌手梅纳德·詹姆斯·基南的引语,并将这些信息保存为. csv 文件,每次运行脚本时都会被覆盖,这对项目的重新开始很有用。这是通过使用自定义设置并传递一个以FEEDS为键的嵌套字典和一个以输出文件的名称为键的字典以及包含提要的不同设置的值来实现的。
为了初始化这个过程,我运行下面的代码:
process = CrawlerProcess()
process.crawl(QuotesToCsv)
process.start()
它第一次运行时没有问题,并将 csv 文件保存在根目录下,但是从下一次开始会抛出以下错误。

` ReactorNotRestartable '错误,图片由作者提供。
要再次运行代码而不出现问题,必须重启内核。现在随着钩针的使用,这个代码可以在一个 Jupyter 笔记本上使用,没有问题。
现在,我调用这个函数来运行代码,没有任何问题。
run_spider()
现在让我来看看这两种方法之间的区别:
- 用
CrawlerRunner代替CrawlerProcess。 - 从
*crochet*导入setup和wait_for,并使用setup()初始化。 - 在从 scrapy 运行蜘蛛的函数上使用
@wait_for(10)decorator。@wait_for用于阻塞进入扭曲反应器线程的调用。点击此处了解更多信息。
瞧啊。不再有错误。脚本运行并将输出保存为quotes.csv。
如果文件包含脚本,这也可以使用!python scrape_webpage.py从 Jupyter 笔记本的. py 中完成。话虽如此,从笔记本上开发代码还是很方便的。此外,这种方法的一个警告是,如果使用CrawlerRunner而不是CrawlerProcess,日志会少得多。

由 Roman Synkevych 在 Unsplash 上拍摄的照片
这里的是我用来测试我的工作流程的所有代码和笔记本的 GitHub repo。
下次见!!!
在 python 的 Vespa 中运行搜索引擎实验
原文:https://towardsdatascience.com/run-search-engine-experiments-in-vespa-from-python-522142ceb4fb?source=collection_archive---------47-----------------------
pyvespa 的三种入门方式
pyvespa 给 vespa 提供了一个 python API。该库的主要目标是允许更快的原型开发,并促进 Vespa 应用程序的机器学习实验。

克里斯汀·希勒里在 Unsplash 上的照片
有三种方法可以让你从pyvespa中获得价值:
- 您可以连接到正在运行的 Vespa 应用程序。
- 您可以使用 pyvespa API 构建和部署 Vespa 应用程序。
- 您可以从存储在磁盘上的 Vespa 配置文件部署应用程序。
我们将逐一回顾这些方法。
连接到正在运行的 Vespa 应用程序
如果您已经在某个地方运行了一个 Vespa 应用程序,您可以使用适当的端点直接实例化 Vespa 类。以下示例连接到 cord19.vespa.ai 应用程序:
from vespa.application import Vespa
app = Vespa(url = "https://api.cord19.vespa.ai")
然后我们准备好通过pyvespa与应用程序交互:
app.query(body = {
'yql': 'select title from sources * where userQuery();',
'hits': 1,
'summary': 'short',
'timeout': '1.0s',
'query': 'coronavirus temperature sensitivity',
'type': 'all',
'ranking': 'default'
}).hits[{'id': 'index:content/1/ad8f0a6204288c0d497399a2',
'relevance': 0.36920467353113595,
'source': 'content',
'fields': {'title': '<hi>Temperature</hi> <hi>Sensitivity</hi>: A Potential Method for the Generation of Vaccines against the Avian <hi>Coronavirus</hi> Infectious Bronchitis Virus'}}]
使用 pyvespa API 进行构建和部署
您还可以使用 pyvespa API 从头开始构建您的 Vespa 应用程序。这里有一个简单的例子:
from vespa.package import ApplicationPackage, Field, RankProfile
app_package = ApplicationPackage(name = "sampleapp")
app_package.schema.add_fields(
Field(
name="title",
type="string",
indexing=["index", "summary"],
index="enable-bm25")
)
app_package.schema.add_rank_profile(
RankProfile(
name="bm25",
inherits="default",
first_phase="bm25(title)"
)
)
然后我们可以将app_package部署到 Docker 容器(或者直接部署到 VespaCloud ):
from vespa.package import VespaDocker
vespa_docker = VespaDocker(
disk_folder="/Users/username/sample_app", # absolute folder
container_memory="8G",
port=8080
)
app = vespa_docker.deploy(application_package=app_package)Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
app保存了一个 Vespa 类的实例,就像我们的第一个例子一样,我们可以用它来提供和查询刚刚部署的应用程序。我们还可以访问存储在disk_folder中的 Vespa 配置文件,修改它们,并使用下一节讨论的方法直接从磁盘部署它们。当我们想要根据通过pyvespa API 无法获得的 Vespa 特性来微调我们的应用程序时,这是非常有用的。
还可以通过export_application_package方法将app_package显式导出到 Vespa 配置文件(无需部署它们):
vespa_docker.export_application_package(
application_package=app_package
)
从 Vespa 配置文件部署
pyvespa API 提供了Vespa中可用功能的子集。原因是pyvespa旨在用作信息检索(IR)的实验工具,而不是用于构建生产就绪的应用程序。因此,python API 基于我们复制经常需要 IR 实验的常见用例的需求而扩展。
如果您的应用需要pyvespa中没有的功能或微调,您可以直接通过 Vespa 配置文件来构建,如 Vespa 文档中的许多示例所示。但是即使在这种情况下,您仍然可以通过基于存储在磁盘上的 Vespa 配置文件从 python 部署pyvespa来获得价值。为了说明这一点,我们可以复制并部署本 Vespa 教程中介绍的新闻搜索应用程序:
!git clone [https://github.com/vespa-engine/sample-apps.git](https://github.com/vespa-engine/sample-apps.git)
新闻搜索应用程序的 Vespa 配置文件存储在sample-apps/news/app-3-searching/文件夹中:
!tree sample-apps/news/app-3-searching/[01;34msample-apps/news/app-3-searching/[00m
├── hosts.xml
├── [01;34mschemas[00m
│ └── news.sd
└── services.xml
1 directory, 3 files
然后,我们可以从磁盘部署到 Docker 容器:
from vespa.package import VespaDocker
vespa_docker_news = VespaDocker(
disk_folder="/Users/username/sample-apps/news/app-3-searching/",
container_memory="8G",
port=8081
)
app = vespa_docker_news.deploy_from_disk(application_name="news")Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for configuration server.
Waiting for application status.
Waiting for application status.
Finished deployment.
同样,app保存了一个 Vespa 类的实例,就像我们的第一个例子一样,我们可以用它来提供和查询刚刚部署的应用程序。
最后的想法
我们讨论了使用pyvespa库从 python 连接到Vespa应用程序的三种不同方式。这些方法提供了极大的工作流灵活性。它们允许您快速开始 pyvespa 试验,同时允许您修改 vespa 配置文件以包括 pyvespa API 中不可用的功能,而不会失去试验添加功能的能力。
定制 SageMaker Studio
原文:https://towardsdatascience.com/run-setup-scripts-automatically-on-sagemaker-studio-15222b9d2f8c?source=collection_archive---------7-----------------------
管理您团队的 SageMaker 笔记本的技巧,以及通过 Jupyter APIs 对自动化的深入探讨

安装了“自动关机”扩展的 Amazon SageMaker Studio 的屏幕截图
更新 2021–11–02:好消息— SageMaker Studio 现在支持生命周期配置脚本!更多信息请参见发布博客、开发者指南和公开样本。定制映像仍然是管理内核定制的首选,但配置脚本可以帮助完成一系列任务,包括本文中最初解决的使用扩展安装案例。
通过亚马逊 SageMaker Studio ,AWS 提供了一种完全托管的云笔记本体验,被称为“第一个完全集成的机器学习开发环境”:基于流行的开源 JupyterLab ,但具有一系列扩展和集成,以加速云中的数据科学。
但是有经验的环境管理员会知道(尤其是在数据科学领域!),了解托管服务有哪些选项可用于集中定制用户环境的配置或设置,而不会限制实验或工作效率,这一点很重要。
作为一名 ML 专家解决方案架构师,我在 AWS 工作时亲眼目睹了不同企业在这一领域的需求可能非常多样化:从实施合规性控制,到围绕特定的专用网络架构工作,甚至只是推出定制以改善用户体验。
在这篇文章中,我将:
- 首先简要回顾一下 SageMaker 架构的一些相关要点
- 然后回顾一些可用的标准配置选项,以及新 SageMaker Studio 与之前的 SageMaker 笔记本实例之间需要注意的一些重要差异
- 最后,介绍一种新颖的方法,您可以在 SageMaker Studio 用户配置文件上自动运行任意设置代码,以防您需要更多的灵活性!
引擎盖下:SageMaker 笔记本电脑的登录和存储
对于基本的访问控制,Studio 和 SageMaker 笔记本实例(nbi)都使用 AWS IAM 中的角色进行基于角色的访问控制。NBI 或工作室的“用户配置文件”与特定的执行角色相关联,用户在登录笔记本时承担该角色及其权限。
当第一次设置 SageMaker Studio 时,管理员选择 Studio“域”是否也通过 IAM 处理登录,或者通过 AWS SSO 代替。
对于一个 IAM 域,任何识别出的 IAM 用户或身份,只要具有特定域&用户配置文件的sage maker:CreatePresignedDomainUrl 权限,就可以生成一个预签名的 Url 来登录到该域&用户配置文件。这是在 SageMaker 的 AWS 控制台中单击“打开工作室”按钮时发生的事情——这也是 SageMaker 笔记本实例使用的相同过程(与sagemaker:CreatePresignedNotebookInstanceUrl权限略有不同)。

SageMaker 的 AWS 控制台中的 Studio 用户配置文件
对于配置了 SSO 身份验证的 Studio 域,用户改为通过 SSO 门户登录(甚至可能没有 AWS 控制台访问权限),但在笔记本本身中运行代码时,仍将承担其用户配置文件的关联 IAM 角色的权限。
对于重启之间的持久存储,NBIs 在/home/ec2-user-SageMaker(Jupyter 根目录)挂载一个 Amazon 弹性块存储 (EBS)卷。在 SageMaker Studio 中,为工作室“域”创建了一个单独的 Amazon 弹性文件系统 (EFS)。每个 Studio 用户配置文件在创建时都被分配了一个单独的 EFS 用户 ID,EFS 包含每个用户一个单独的顶级文件夹(命名为 EFS UID),如 SageMaker 开发人员指南中的概述图所示。
因此,虽然 Studio 在文件存储方面带来了一些架构上的差异,并在经典的 SageMaker 笔记本实例上添加了一个新的身份验证选项;两者都允许我们使用执行角色对登录用户在笔记本中的操作进行细粒度控制,包括对以下内容的控制:
- 他们可以读取哪些源数据(比如通过 s3:* IAM 动作读取不同的亚马逊 S3 存储桶或路径)
- 他们在 SageMaker 或其他服务上有什么能力(比如拒绝
sagemaker:DeleteFeatureGroup保护共享资源) - 他们可以启动哪些实例类型,以控制成本(使用 IAM 上的
sagemaker:InstanceTypes条件动作,如sagemaker:CreateTrainingJob或sagemaker:CreateApp - 特定的标签或 VPC 设置是否在创建的资源上是强制性的
- …还有许多其他的
自定义 SageMaker 笔记本实例设置
在经典情况下,管理员可以将 SageMaker 笔记本实例链接到一个生命周期配置:它定义了在 NBI 首次创建和/或重新启动时执行的定制 shell 脚本。

官方在线示例展示了广泛的使用案例,包括:
- 启动一个监视进程,以便在 NBI 空闲了配置的时间后自动关闭它
- 将有用的 conda 或 pip 包安装到 SageMaker 提供的一个或多个内核环境中
- 在 EBS 装载上创建一个持久的基于 conda 的环境,以在重新启动之间保持库配置
- 安装 JupyterServer/JupyterLab 扩展或自定义其设置
…很明显这是一个非常灵活的工具,但仍然有一些限制:一个重要的限制是生命周期配置脚本必须在 5 分钟内完成,否则实例将无法启动——这可以通过使用 nohup 作为后台进程启动长期运行的任务来解决。
由于笔记本实例与独立的基于 EBS 的存储是分开的,所以跨团队共享内核配置也是一个挑战:要求用户重启他们的实例来使用新的更新。
在 SageMaker 工作室,事情有点不同
SageMaker Studio 将运行笔记本内核从 JupyterServer 基础设施中分离出来,将两个进程容器化,并将运行容器称为“应用”。用户配置文件的“默认”或“JupyterServer”应用程序运行 Jupyter UI,而笔记本内核环境(或其他 UI 功能,如 SageMaker Data Wrangler )运行在单独的应用程序中,这些应用程序可以独立启动和停止,或分配给不同的计算资源。
每次重新启动(或者用 Studio 的术语来说是“创建”)应用程序时,应用程序都会从受管容器映像中重新初始化,通常良好的做法是定期删除和重新创建应用程序,以获取更新的容器映像并使用安全补丁或功能更新。

AWS 控制台中的 SageMaker Studio 用户详细信息屏幕,显示用户正在运行的“应用程序”
利用这种容器化的设置,定制映像功能为 Studio 带来了比 NBIs 更广泛的工具,用于管理和共享定制内核环境:管理员将内核注册为容器映像并进行版本控制,并在一个中心位置配置用户对它们的访问。
当然(就像在 SageMaker 笔记本实例上一样),用户可以临时将额外的包安装到他们的内核,直到应用程序重启恢复默认环境——使用笔记本命令,如:
!pip install ***
# Or...
!conda install ***
由于域上的存储由集中的 EFS 文件系统支持,我们还可以构建集中的自动化来初始化或强制执行用户工作室环境中的某些内容:比如复制初始项目模板,或者强制同步一些共享的实用程序代码。例如,可以在 Amazon EventBridge 中设置一个规则,用 EFS root 访问权限触发一个 Lambda 函数,将 starter 内容复制到新加入的用户的主文件夹中。
最后也是最重要的一点是:
【更新:2021–09 年不再真实,见 发布帖 】至少截至今天,SageMaker Studio 还没有直接相当于 的笔记本实例生命周期配置 内置。
“默认的”JupyterServer UI 应用程序的容器由 SageMaker 维护,并在每次重新启动应用程序时刷新。因此,尽管管理员可以说已经改进了在 Studio 中管理内核环境(使用自定义映像)和控制用户内容(使用 EFS 集成)的选项,但我们仍然需要一种方法来在 JupyterServer 本身上运行自定义设置命令然后再将其公开给用户。这将允许集中管理,例如:
- 安装 JupyterLab 扩展
- 禁用文件下载选项(如本文中针对 NBIs 的所述)
- 配置定制 git 或工件存储库设置
一种选择是将一个 shell 脚本加载到用户的主文件夹中(通过 EFS ),每次重启 JupyterServer 应用程序时,用户可以在“系统终端”中运行该脚本……当然,这取决于用户采取的行动。
(2021–11 年更新)自从在 Studio 中启动生命周期配置脚本以来,这些是为您的用户自动运行此类设置脚本的最简单和首选的方式。您可以找到一系列用例的官方示例,并为您的域中的哪些用户配置默认运行的脚本。在接下来的部分中,我将讨论一个比这个功能更复杂的解决方法,它可能在一些自动化边缘情况下仍然有意义,但是对于更直接的需求来说就不再需要了。
在 SageMaker Studio 上自动执行代码
利用 3 个关键组件,即使不使用生命周期脚本,我们也可以在 SageMaker Studio 中设置自动执行的脚本:
- Studio 基于 JupyterLab,这意味着经过认证的客户端可以利用公开记录的 JupyterServer REST API 和Jupyter Client web socket API来连接和运行命令——就像 UI web 客户端一样。
- 对于仅 IAM 认证的域,SageMakerCreatePresignedDomainUrl API可以允许脚本登录到 Jupyter,假设客户端环境有权限。
- 我们可以为“默认”/JupyterServer 应用程序捕获
sagemaker:CreateApp事件,并使用这些事件来触发我们的客户端登录并运行设置命令。
虽然这种解决方案:
- 在脚本完成之前,无法显式阻止对环境的访问(请记住,NBI 生命周期配置脚本只能在 5 分钟内做到这一点),并且
- 目前仅涵盖 IAM 认证的域(支持生成预先指定的 URL)
…它当然可以帮助我们自动运行设置代码,并为运行命令提供比静态脚本更具交互性、类似机器人流程自动化的界面。
作为一个具体的例子,我们将自动安装 SageMaker Studio 自动关机扩展——一个用于成本管理的 JupyterLab 扩展。
我最初为这个扩展贡献了自动安装程序解决方案,基于同样的方法:所以我们将在这篇文章中浏览代码片段,但是你可以参考 GitHub 中的自动安装程序来获得完整的上下文(以及任何更新!).对于在生产中安装扩展的更简单的方法,您现在可以参考为它发布的特定的 Studio 生命周期配置示例。
步骤 1:登录 Jupyter
许多编程语言支持 HTTP、WebSockets 和一个AWS SDK;但是我们将用 Python 演示一个客户机,因为它可能为许多 Jupyter/SageMaker 用户所熟悉。
客户端代码将在某种可以访问 AWS API 的环境中运行:无论是 Lambda 函数(通过函数的执行角色),在本地笔记本电脑上测试(通过您的 AWS CLI 登录),还是在其他地方。
只要您的环境拥有 sagemaker:CreatePresignedDomainUrl IAM 权限,我们就能够调用这个 API(通过 Boto3 ,Python 的 AWS SDK)来请求一个预签名的 Url,以作为目标用户进行身份验证:
smclient = boto3.client("sagemaker")
sagemaker_login_url = smclient.create_presigned_domain_url(
DomainId=domain_id,
UserProfileName=user_profile_name,
)["AuthorizedUrl"]
…然后我们可以简单地获取预先签名的 URL 来登录——注意将我们的请求链接到一个会话,这样任何需要的 cookies 都会为将来的请求保存下来。
import requests
reqsess = requests.Session()
login_resp = reqsess.get(sagemaker_login_url)
简单!这个过程与在浏览器中从 AWS 控制台单击“Open Studio”按钮是一样的:如果您的控制台用户有足够的权限,您的浏览器将被重定向到一个预先签名的 URL,该 URL 设置 cookies 和本地存储来初始化 Jupyter 会话。
然而,有可能 JupyterServer 应用程序之前没有运行或者还没有准备好。我们可以实施一个轮询检查,看看我们是否真的被重定向到 Jupyter,或者只是一个加载屏幕——如果需要,轮询“默认”应用程序的状态,直到它启动:
base_url = sagemaker_login_url.partition("?")[0].rpartition("/")[0]
api_base_url = base_url + "/jupyter/default"# Using XSRF as a proxy for "was Jupyter ready":
if "_xsrf" not in reqsess.cookies:
app_status = "Unknown"
while app_status not in {"InService", "Terminated"}:
time.sleep(2)
app_status = reqsess.get(
f"{base_url}/app?appType=JupyterServer&appName=default"
).text
ready_resp = reqsess.get(api_base_url)
步骤 2:打开系统终端
Jupyter 既使用 REST APIs(用于请求/响应类型的操作,比如与正在运行的内核列表或工作区中的内容进行交互),也使用 WebSocket APIs(用于流式连接,比如终端窗口或笔记本内核本身)。
在我们的例子中,我们希望在系统终端中运行一些命令——所以首先需要通过下面的 REST API 创建终端。注意,遵循一个通用的模式来防止跨站点请求伪造 (CSRF/XSRF),API 要求我们在任何状态改变请求(比如 POST、PUT、DELETE)中传递一个来自会话 cookies 的令牌,而不是只读请求(比如 GET):
terminal = reqsess.post(
f"{api_base_url}/api/terminals",
params={ "_xsrf": reqsess.cookies["_xsrf"] },
).json()terminal_name = terminal["name"]
我们的终端会话现在已经创建好了,可以通过 WebSocket API 进行连接了。在本例中,我们将为此使用单独的web socket-clientPython 库,因此需要从基于请求的 REST 会话中复制 cookies:
import websocketws_base_url = \
f"wss://{api_base_url.partition('://')[2]}/terminals/websocket"
cookies = reqsess.cookies.get_dict()ws = websocket.create_connection(
f"{ws_base_url}/{terminal_name}",
cookie="; ".join(["%s=%s" %(i, j) for i, j in cookies.items()]),
)
步骤 3:运行命令
Jupyter 用于终端的 WebSocket API 比用于笔记本内核的更简单:消息是 JSON 编码的 2-list(类型,内容)。接收初始“设置”消息;此后,该连接类似于标准终端流。客户端接收类型为stdout或stderr的文本消息,并可以发送作为stdin的文本输入。
重要的是要认识到,我们在这里做的是通过终端交互式地运行命令——这与在脚本中执行命令不太一样(尽管我们可以通过 /contents REST API 将脚本文件作为文本发布,然后通过终端执行该文件来获得这种效果)。
对于每个命令,终端没有“成功或失败”的内置概念(比如退出代码)…甚至当一个命令完成时:只是在屏幕上输出文本,用户通过stdin输入。
对于一个基本的开始,我们可以通过stdin发送一个命令(带有一个尾随的换行符,就好像用户在输入之后按了 enter 然后继续监听终端输出,直到我们看到类似于下一个命令提示符的内容(使用正则表达式)。这样,客户端可以等到系统准备就绪后再发出下一个命令:
COMMAND_SCRIPT = [
"git clone https://github.com/aws-samples/sagemaker-studio-auto-shutdown-extension.git",
"pwd && ls",
"cd sagemaker-studio-auto-shutdown-extension && ./install_tarball.sh",
]
prompt_exp = re.compile(r"bash-[\d\.]+\$ $", re.MULTILINE)for ix, c in enumerate(COMMAND_SCRIPT):
ws.send(json.dumps(["stdin", c + "\n"])) while True:
res = json.loads(ws.recv())
if res[0] == "stdout" and prompt_exp.search(res[1]):
# Ready for next command
break
time.sleep(0.1)
您可以使用其他检查来扩展这一点,根据特定命令的预期结果,从控制台输出中确定命令是“成功”还是“失败”。
第四步:自动执行
一旦我们有了工作的基本程序,最后一步就是打包客户端代码,并在我们希望它运行时自动触发它。对于启动 Studio Jupyter 容器的自动化设置,这将意味着在 SageMakercreate appAPI 事件上运行应用类型JupyterServer。
在撰写本文时,应用程序状态的变化没有反映在直接 SageMaker EventBridge 集成中。相反,您可以启用 AWS CloudTrail 审计日志来捕获事件,然后使用 EventBridge 规则来触发相应的 SageMaker CloudTrail 事件。

显示由 SageMaker CreateApp 上的 EventBridge 和 CloudTrail 触发的 Lambda 函数的架构
在上面显示的简单示例中,我们将上面的客户端代码作为 Python Lambda 函数运行——尽管也有其他选项。
这引入了所有命令必须在 15 分钟最大 Lambda 函数超时内发送的约束,这将也包括等待应用/容器启动所花费的任何时间。这是因为 CreateApp API 调用是在完成时记录的,而不是在请求的应用程序变为“正在运行”时记录的。
实际上,这个时间限制可能不成问题:
- 长期运行的设置总是可以作为脚本上传,并使用 nohup 运行,就像经典的笔记本实例生命周期配置脚本一样。
- 有了这个解决方案,人类用户已经可以在客户端开始运行命令的同时访问环境——所以我们无论如何都需要保持最关键的设置动作快速。
回顾
虽然亚马逊 SageMaker classic Notebook 实例中的配置定制主要限于“生命周期配置”外壳脚本,但 SageMaker Studio 有一些更广泛的选项可用于共享和管理内核环境(使用自定义映像功能)和集中管理用户内容(通过 root 访问挂载共享的 EFS 文件系统,并操纵用户的个人文件夹)。
Studio 现在也支持生命周期配置脚本,这些对于需要定制核心 JupyterLab 平台本身的设置用例特别有用。尽管这些脚本可以为一系列任务提供简单的解决方案,但是记住管理用户内核和文件系统内容的其他选项是很有用的。
在本演练和开源 SageMaker Studio 自动关机扩展的原始自动安装功能中,我们展示了一种替代方法,您可以在新启动的 SageMaker Studio“默认”(UI)应用程序上自动运行安装命令:使用 Jupyter 的底层 API。
类似的触发器可以应用于运行外壳代码以响应不同的事件,相应的笔记本内核 API同样可以用于自动和交互地运行笔记本(或内核环境中的其他代码)。
正如解决方案所展示的,SageMakerCreatePresignedDomainUrl或CreatePresignedNotebookInstanceUrlAPI 上的权限足以授予在这些环境上登录和代码执行的权限:因此,在授予这些权限时,一定要应用最小权限原则!出于同样的原因,如果考虑参数化 Lambda 函数运行的命令序列,您应该仔细评估您的信任架构。
要了解更多信息,您可能还想查看:
- SageMaker 开发者指南,了解关于设置 SageMaker Studio 和其他 SageMaker 特性的详细信息
- 定制图像样本库,用于打包定制内核环境以在 Studio 中使用的示例
- 安全数据科学参考架构示例,了解更多参考模式——其中一些更面向 SageMaker 笔记本实例,但在许多情况下也可转移到 Studio
- …以及新的 Amazon SageMaker 节约计划,该计划提供灵活的节约,可将您的成本降低高达 64%,以换取一年或三年的使用承诺(以美元/小时计)——即使您使用不同的实例类型和 AWS 区域,也具有灵活性!
我希望你发现这些想法有用,并觉得更好地解决自己的 SageMaker 笔记本管理需求!
在浏览器中运行张量流模型
原文:https://towardsdatascience.com/run-tensorflow-models-in-the-browser-84280b3c71ad?source=collection_archive---------26-----------------------
如何用 TFJS 和亚马逊 S3 无服务器托管机器学习模型

图片由作者使用wordclouds.com生成。
目录
- 介绍
- 用 TensorFlow 训练数字识别模型
- 在 S3 用 TensorFlow.js 托管模型
- 结论
- 参考
介绍
要让您的客户可以使用机器学习模型,需要通过应用程序编程接口(API)或图形界面(如 Web 应用程序(Web App))来访问它。
API 和 Web 应用程序都需要服务器来提供运行它们的计算需求。对于大多数用例,这个服务器是由开发人员配置和维护的,但在某些情况下,它不需要这样做。
无服务器架构允许开发人员从架构和维护中抽象出来,这样他们就可以真正专注于开发和改进他们的模型。与传统服务器相比,无服务器计算具有更多优势,例如:
- 如果您的应用程序不经常使用(客户数量少,或频率低),则成本较低。
- 自动将模型从几个用户扩展到几千个用户。
- 提高可重用性,因为无服务器通常采用模块化方法。
在本帖中,我们将介绍如何训练 Tensorflow 模型进行数字识别,并使其以无服务器的方式可用。
关于 Tensorflow 建模的简要介绍,请查看我之前的帖子“tensor flow 入门”。如果你想找一份关于 S3 无服务器托管的简介,看看这篇“用亚马逊 S3 和 53 号公路建立一个无服务器网站”。
用 TensorFlow 训练数字识别模型
在本节中,我们将使用通过 TensorFlow 库提供的 MNIST 数据集来训练一个简单的数字识别模型。
要加载数据集,请在笔记本的第一个单元格中键入以下内容。
这将显示训练数据输入(tx)和目标(ty)以及验证数据输入(vx)和目标(vy)的形状。
tx:(60000, 28, 28, 1), ty:(60000,)
vx:(10000, 28, 28, 1), vy:(10000,)
现在,让我们为每个数字显示一组 10 个样本图像,以了解数据的样子。
这将生成下面的图像网格。请注意,该图像具有黑色背景和白色前景。这将与稍后定义我们的画布来绘制数字相关。

通过 TensorFlow 库提供的 MNIST 数据集中每个数字的图像样本集。图片由作者提供。
对于视觉模型,让我们从定义卷积构建模块开始。该模块将包括卷积、批量标准化、relu 激活、最大汇集和漏失层。
我们的完整网络将由 2 个“normConvBlock”组成,随后是一个扁平化层,最后是一个 softmax 激活的致密层。
为了训练模型,我们可以使用“亚当”优化器和分类交叉熵损失。在这个例子中,我们将使用“稀疏分类交叉熵”,因为我们的目标数据是顺序编码的。
将显示以下模型结构。

提议的模型架构。该模型由两个“normConvBlock”层组(b1,b2)组成,后面是平坦层和致密层。图片由作者提供。
我们现在准备训练我们的模型。为此,我们可以简单地用上面定义的处理过的数据调用“model.fit”。为了确保我们得到最佳的模型迭代,让我们如下定义一个早期停止回调。
令人惊讶的是,我们刚刚训练了一个模型来识别个位数!对于这个例子来说,模型的精确度已经足够好了(验证集的精确度约为 99%)。如果您需要更精确的模型,请更改模型结构或执行某种类型的数据扩充。
Epoch 11/20 59/59 [==============================] - 3s 50ms/step - loss: 0.0317 - acc: 0.9906 - val_loss: 0.0338 - **val_acc: 0.9899** Epoch 12/20 59/59 [==============================] - 3s 50ms/step - loss: 0.0292 - acc: 0.9913 - val_loss: 0.0496 - val_acc: 0.9823 Epoch 13/20 59/59 [==============================] - 3s 50ms/step - loss: 0.0275 - acc: 0.9918 - val_loss: 0.0422 - val_acc: 0.9866
完整脚本
如需完整的脚本,请点击以下链接进入我的 Github 页面:
https://github.com/andreRibeiro1989/medium/blob/main/tensorflowjs/digit_recognition/tensorflow_js_training.ipynb
或者通过以下链接直接访问 Google Colab 笔记本:
https://colab.research.google.com/github/andreRibeiro1989/medium/blob/main/tensorflowjs/digit_recognition/tensorflow_js_training.ipynb
在 S3 用 TensorFlow.js 托管模型
在这一节中,我们将开发最简单的 HTML + Javascript 组件来与 TensorFlow.js 模型接口。
TensorFlow.js 是一个完全在浏览器中训练和运行机器学习模型的开源库,通过高级 API 使用 Javascript。
将模型从 TensorFlow 转换为 TensorFlow.js
要在浏览器中托管 TensorFlow 模型,我们需要执行的第一步是将其转换为 TensorFlow.js 模型。为此,我们只需从 tensorflowjs 库中调用' tensorflowjs . converters . save _ keras _ model'。
如果使用 Colab 将文件下载到您的本地机器以备后用。
使用 HTML 和 JavaScript 创建 web 界面
让我们首先为我们的 web 应用程序创建文件夹结构。首先创建一个名为“digit_recognition”的主文件夹,并在其中创建两个名为“index.html”和“script.js”的文件。
此外,在“digit_recognition”中创建一个名为“tensorflow”的文件夹。将我们从 Colab 笔记本下载的两个文件“group1-shard1of1.bin”和“model.json”复制到这个新文件夹中。
您的文件夹结构应该如下所示:
- digit_recognition/
- index.html
- script.js
- tensorflow/
- group1-shard1of1.bin
- model.json
T3【Index.html】T5
用任何代码编辑工具打开 index.html 文件,并将以下代码复制到其中。这个脚本定义了绘制一个数字并使用训练好的模型识别它的基本组件。
现在让我们来剖析上面的代码。
-
第 3 行到第 11 行定义了 html 文件的头。在这里,我们加载必要的 TensorFlow.js 库。
-
第 23 行创建了一个按钮,我们将使用它来调用模型推理函数(' predictModel ')。当按钮被按下时,模型将被触发,预测结果显示在
标签中。
-
第 26 行创建了一个清除画布的按钮(“erase”)。
-
第 31 行定义了一个 canvas 对象,它将允许我们绘制一个数字,供我们训练过的模型稍后识别。
-
第 35 行来源于“script.js”文件,该文件包含 JavaScript 逻辑,用于将画布中的数据转换为张量,并对其应用模型。
script . js
使用任何代码编辑工具打开 script.js 文件,并开始添加以下代码片段。
- 定义我们在这个脚本中需要的主要变量。
2.为不同的用户操作定义画布触发器。
在“鼠标按下”(点击并按住)时,脚本被触发以启动绘图过程并记录当前的鼠标/触摸位置。在“鼠标移动”时,脚本开始在画布上绘制。在“mouseup”(释放点击)时,脚本被触发以停止绘图过程。
3.检查设备是否支持触摸。这是在“设置位置”功能中选择正确事件所必需的。
4.设置接合(开始绘制)和分离(停止绘制)标志。
5.记录鼠标/触摸位置。请注意,我们需要知道设备是否支持触摸。
6.定义要在画布上绘制的主函数。
“拖动”标志定义了用户是“参与”还是“脱离”(第 8 行)。如果接通,在通过“设置位置”获得的过去记录的位置和当前位置之间画一条线(第 18 至 21 行)。
7.定义清除画布的函数。
8.定义加载张量流模型的函数。
“tf.loadLayersModel”函数从 url 或本地目录加载模型(第 5 行)。因为对于第一次预测,模型必须初始化权重,所以通常建议预热模型以防止第一次预测期间的延迟(第 8 行)。
9.定义从画布中获取当前数据的函数。
10.定义模型推理的函数。
“getData”从画布中加载数据(第 5 行)。' tf.browser.fromPixels '将画布数据转换为张量(第 8 行)。' tf.image.resizeBilinear '将图像从画布大小调整到模型大小(第 11 行)。' model.predict '获取模型预测(第 14 行)。第 17 行将概率最高的数字‘y . arg max(1)’设置到
标签中。
在本地测试模型
出于安全原因,浏览器限制从脚本发起的跨来源 HTTP 请求。这意味着 web 应用程序只能从加载应用程序的同一来源请求资源,除非来自其他来源的响应包含正确的跨来源资源共享(CORS)标头。
要在 Chrome / Chromium 中实现这一点,您可以安装“Moesif CORS”扩展。然而,这仍然会限制本地资源的加载。在本教程中,我们将使用火狐代替。
要在 Firefox 中允许 CORS,在 Firefox 搜索栏中键入“about:config ”,在新的搜索栏中键入“privacy.file_unique_origin ”,并将默认值更改为“false”。

火狐配置界面。图片由作者提供。
现在在 Firefox 中打开“index.html”文件,方法是双击文件名并选择“用 Firefox 打开”,或者将文件拖到 Firefox 窗口中。您将看到以下登录页面。

我们 web 应用程序的登录页面。图片由作者提供。
到目前为止,这不是最漂亮的网络应用,但它确实有用。现在,让我们通过绘制一个数字并单击预测按钮来测试该模型。

模型预测。图片作者。
太好了。我们的模型在本地有效!下一步是将网络应用推向像亚马逊 S3 这样的无服务器平台。
在亚马逊 S3 托管 web 应用程序
要托管我们的 web 应用程序,您首先需要创建一个亚马逊 S3 桶,并将其设置为静态 web 托管。如果你想快速了解如何做到这一点,请查看我之前的帖子“使用亚马逊 S3 和 53 号公路建立一个无服务器的网站”。
为了使我们新的无服务器 web 应用程序可用,我们只需要将文件推送到 S3。确保您推送整个项目文件夹“digit_recognition”。

上传网络应用到 S3。图片由作者提供。
我们现在可以在任何设备上使用任何浏览器测试应用程序(因为所有资源现在都在同一个来源,我们不需要激活 CORS 请求)。
为此,如果您有与您的 S3 桶相关联的域,请访问http://DOMAIN/projects/digit _ recognition/index . html,如果没有,请访问https://S3 . eu-west-1 . amazonaws . com/DOMAIN/projects/digit _ recognition/index . html。

使用移动触摸设备的模型预测。图片由作者提供。
完成脚本
完整的“index.html”和“script.js”脚本请点击下面的链接。在这次回购中,我还包括了一个使用 bootstrap 4 的更好看的应用程序(“index_mobile.html”和“script_mobile.js”)。
https://github.com/andreRibeiro1989/medium/tree/main/tensorflowjs/digit_recognition
有关原始和引导 web 应用程序的演示,请点击以下链接:
http://portfolio . dataisawesome . com/projects/digit _ recognition/index . html(桌面、移动)
http://portfolio . dataisawesome . com/projects/digit _ recognition/index _ mobile . html(手机)
结论
使用无服务器计算允许您在不管理 web 服务器的情况下扩展应用程序,同时保持低成本。
在本教程中,我们探讨了如何使用 TensorFlow.js 和亚马逊 S3 以无服务器方式托管 TensorFlow 模型。要了解如何使用 TensorFlow.js 的更多信息,请确保查看 TensorFlow.js 官方页面中提供的教程。
参考
[1]no nica Fee,"什么是无服务器架构?主要优势和限制(2020 年 8 月)
https://new relic . com/blog/best-practices/what-is-server less-architecture
[2]https://www.tensorflow.org/datasets/catalog/mnist
[3]乔什·戈登和萨拉·罗宾逊,《TensorFlow.js 简介:Javascript 中的机器学习》(2018 年 3 月)
https://medium . com/tensor flow/Introducing-tensor flow-js-Machine-Learning-in-Javascript-BF 3 eab 376 db
像 C 语言一样快速运行您的 Python 代码
原文:https://towardsdatascience.com/run-your-python-code-as-fast-as-c-4ae49935a826?source=collection_archive---------0-----------------------
如何在不做任何改变的情况下提高 python 代码的性能。

图片由来自 Pixabay 的 Onur mer Yavuz 提供
作为一名博士研究员,我的工作至关重要的一点是快速编写一个想法,看看它是否可行。 Python 是实现这一点的优秀工具。它允许专注于想法本身,而不是被样板代码和其他乏味的事情所困扰。
然而, Python 有一个很大的缺点:它比像 C 或者 C++ 这样的编译语言要慢很多。那么,在我们通过构建一个 Python 原型测试了一个想法之后,现在我们想把它变成一个快速且高性能的工具,我们该怎么做呢?大多数情况下,我们最终会做两倍的工作,手动将 Python 代码转换成 C 。如果我们的 Python 原型本身能够运行得更快,那不是很好吗?所有花在实现每件事情两次上的时间可以用来做更有意义和有趣的事情。
幸运的是,我偶然发现了问题的解决方案: PyPy ,这是 Python 的快速替代方案。


为了说明 PyPy 可以提供多大的加速,我在下面的例子中运行了默认的 Python 解释器和PyPy py:
基本上,该脚本在一个循环中将 0 到 100,000,000 之间的所有整数相加,并在完成时打印一条消息和脚本的运行时。
尽管这不是一个科学的评价,但这个生动的例子仍然令人振奋。与默认的 Python 解释器(大约需要 10 秒)相比, PyPy 在 0.22 秒后就完成了它的执行!另外,请注意,我们可以直接将我们的 Python 代码输入到pypypy中,不做任何修改。当你把它与速度大师 C 相比时,这个结果会更加令人印象深刻。在我的电脑上, C 中的等效实现需要 0.32 秒。虽然总体来说 C 依然是速度大师, PyPy 在某些情况下也能打败 C。
"如果你想让你的代码神奇地运行得更快,你也许应该使用 PyPy . "
—吉多·范·罗苏姆(Python 的创造者)
来源:youtu.be/2wDvzy6Hgxg?t=1012
当我们的程序无论如何都很快时,或者当大部分运行时间用于调用非 python 库时,PyPy 就不那么有效了。然而,如果我们有一个很慢的程序,大部分时间花在执行 Python 代码上, PyPy 可以创造奇迹。
PyPy 为什么这么快?
这是你可能会问自己的问题,如果你是第一次被 PyPy 绊倒,这是理所当然的。开始时,这看起来像是魔法。我们运行完全相同的代码,用 PyPy 获得了看似免费的巨大加速。
虽然代码完全相同,但是代码的执行方式却有天壤之别。 PyPy 的性能提升背后的秘密是实时编译,简称 JIT 编译。
但是让我们慢慢来。
超前编译
像 C、C++这样的编程语言,还有 Swift、Haskell、Rust 等等都是提前编译的。这意味着在你用那些语言写了一些代码之后,你点击一个按钮,编译器将源代码转换成机器可读的代码,可以被一个特定的计算机架构读取。每当程序执行的时候,你的原始源代码早就没了。执行的只是机器码。

提前编译将源文件转换为机器码。
语言解释
Python , JavaScript , PHP ,类似的语言则采取了不同的方式。它们被解释。与将源代码转换成机器码相比,源代码保持不变。每次程序运行时,解释器逐行“查看”代码并为我们运行。

解释器逐行运行程序。
在 JavaScript 的例子中,每个网络浏览器都内置了一个解释器。标准的 Python 解释器叫做 CPython。然而,区分语言 Python 和运行我们代码的东西 CPython 是非常重要的。这是因为我们可以拥有完全不同的工具,都具有运行 Python 代码的能力。这就是 PyPy 进入画面的地方。
即时编译
PyPy 是利用即时编译的 Python 的替代实现。正在发生的是 PyPy 像解释器一样直接从源文件中运行我们的 Python 代码。然而, PyPy 并不是一行一行地运行代码,而是在执行代码之前将部分代码编译成机器码,可以说只是在时间上。

JIT 编译结合了提前编译和解释。
从这个意义上说,JIT 编译是解释和提前编译的结合。我们获得了提前编译的性能提升,以及解释语言的灵活性和跨平台可用性。
你如何从 PyPy 中获益?
既然我们已经理解了 PyPy 是如何实现惊人的性能提升的,我们就想使用它。 PyPy 在pypy.org免费提供,安装简单。除了工具本身之外,该网站还包含大量关于微调 python 程序以进一步提高性能的提示和技巧。由于 PyPy 只是 Python 的替代实现,大多数时候它只是开箱即用,无需对您的 Python 项目做任何更改。它完全兼容 web 框架 Django ,科学计算包 Numpy 和众多其他包。它节省了我无数的用 C 重新实现原型的时间,我不想在我的编程工具包中错过它。
觉得这个故事有趣?你可以在这里成为灵媒会员来支持我的写作:medium.com/@mmsbrggr/membership。你将获得所有媒体的访问权,你的部分会员费将直接支持我的写作。
欢迎在 LinkedIn 上向我提出私人问题和评论。如果你喜欢这篇文章,让我告诉你我的时事通讯:marcelmoos.com/newsletter。
在 Mac 上运行 dockerized CKAN 地理空间开放数据门户
原文:https://towardsdatascience.com/running-a-dockerized-ckan-geospatial-open-data-portal-on-a-mac-347a0346729d?source=collection_archive---------14-----------------------
实践教程
关于如何利用 docker-compose 充分利用 OSX 世界领先的操作系统数据门户的实践指南
CKAN 很棒。它不仅是全球开放数据门户最受欢迎的系统之一:大量可用的插件和蓬勃发展的社区使它成为一个非常灵活和强大的工具,用于不同类型的数据和可视化,包括地理空间。

Docker 让运行 CKAN 实例变得简单多了,不需要运行 Ubuntu 机器
说到地理空间数据门户,其他工具可能更为人们所知。ESRI 无疑在说服顶级玩家(如全球的联合国和地方政府使用ArcGIS Enterprise方面做得很好,但是这种设置会花费你几千美元。OSGEO 社区在开发 GeoNode 和 GeoNetwork 方面做得很好,但这将占用你的机器上的大量空间,因为这两者都需要 Postgres 数据库和 Geoserver 实例来存储数据和地理服务。
如果你正在寻找一些例子来说服自己,请查看 CKAN 网站上的展示页面。许多国家政府,如美国和加拿大,正在使用它作为他们的开放数据门户。我最喜欢的一个是联合国 OCHA 办事处的人道主义数据交换门户网站。

人道主义数据交换门户,您可以在其中按类别和位置搜索数据,并在嵌入式 web 地图中预先可视化空间数据。图片由作者提供。
因此,如果您正在寻找一个免费的轻量级解决方案来存储地理空间元数据,CKAN 会支持您。在本教程中,我们将设置一个基本的 CKAN 安装在 Mac 与 Docker,设置一些基本的插件,并使其地理空间友好。
让我们从头开始——一个非常好的起点
让我们开门见山吧:您可能最终阅读了这篇文章,因为您正试图在 Mac 上运行 CKAN 门户,而关于如何操作的文档并不理想。坏消息是 CKAN 被开发成主要在 Linux 上运行(尽管你可以在 OSX 上运行源码安装),所以你不能运行包安装。好消息是 CKAN 也作为 docker-compose recipe 发布,所以你可以在 Mac 的 docker 容器中运行它。
- 在我们开始之前,确保您的机器上安装了 Docker 和 Docker-compose。在 mac 上,这意味着你只需下载并安装 Docker-compose 自带的 Docker 桌面应用。
如果你不熟悉 Docker 的工作方式,也许值得研究一下。您需要知道的最起码的事情是,Docker 文件包含一个构建映像的方法,该映像作为一个容器中的卷依次执行。docker-compose 方法指向 docker 文件的集合,因此您可以在一个容器中有多个卷运行您的设置的不同部分,如数据库、web 服务器和应用程序。所有这一切都不需要建立一个虚拟机:您只需运行这些服务工作所需的部分。
2.现在打开您的终端,直接从 Github 获取 CKAN 的源代码:
$ git clone https://github.com/ckan/ckan.git
3.进入下载目录,并导航至 docker-compose 配方的存储目录:
$ cd ckan/contrib/docker
4.在为 CKAN 实例构建映像时,Docker 将被告知寻找。env 文件,它包含一些环境变量。我们将创造我们的。env 文件,方法是通过运行以下命令复制 CKAN 提供的模板(. env.template):
$ cp .env.template .env
5.这些变量没有太多需要改变的地方。有一件事是绝对必须的,那就是更改变量 CKAN_SITE_URL。为此,请打开新创建的。env 文件用你最喜欢的文本编辑器(由于这个文件以点开始,你的 Mac 会隐藏它;点击CMD+SHIFT+.使隐藏文件在 Finder 中可见)。该变量应该如下所示:
CKAN_SITE_URL = http://docker.for.mac.localhost:5000
6.现在我们已经准备好构建我们的 Docker 映像了!让我们调用 docker-compose,告诉它构建必要的图像,并在容器中将它们作为卷运行。
$ docker-compose up -d --build

如果一切顺利,您应该会在 Docker 桌面应用程序中看到一个正在运行的容器。ckan 的每个部分都有一个实例,比如数据库、web 服务器和 ckan 本身。图片由作者提供。
7.如果您遇到任何问题,运行以下命令来修剪 Docker 可能是值得的:
$ docker container prune $ docker volume prune $ docker network prune $ docker system prune
8.在你的浏览器上检查http://docker.for.mac.localhost:5000/,你应该会看到 CKAN 网站正在运行!

它还活着!图片由作者提供。
就这些吗?
好的,很好。我们设法很快完成了基础安装,这将作为 CKAN 最初设定的元数据门户。不过,您可能会有兴趣将 CKAN 作为一个 数据 门户来运行。为此,您需要设置数据存储扩展,同时让我们也设置管理员用户名。
在本节中,我们将使用production . ini文件。这基本上是 CKAN 存储所有相关选项的地方,比如语言、用户和扩展。但是请注意,根据您使用的 CKAN 版本,这可能会被命名为 ckan.ini 。
- 预先为数据存储设置用户:
$ docker exec ckan ckan -c /etc/ckan/production.ini datastore set-permissions | docker exec -i db psql -U ckan
docker exec 命令意味着我们可以在任何特定的运行容器中运行命令——在本例中,我们已经访问了 ckan 分区。
2.访问 Docker Linux 虚拟机:
$ docker run -it --privileged --pid=host justincormack/nsenter1
3.现在您已经进入了 Linux 机器,让我们使用 UNIX vi 编辑器对 production.ini 文件(或 ckan.ini 取决于 ckan 的版本)进行修改,CKAN 的大多数规则:
$ vi var/lib/docker/volumes/docker_ckan_config/_data/production.ini都在这个文件中
a.将datastore datapusher添加到ckan.plugins b。取消ckan.datapusher.formats c。将ckan.locale_default更改为您偏好的语言
要编辑 production.ini 文件,键入 i 进行插入。然后 ESC ,然后 :x 保存时退出 vi,或者 :q!不保存退出。要退出虚拟机,请键入 exit 。
4.一旦您退出了 VM,让我们重新启动容器来实现更改:
$ docker-compose restart ckan
5.要检查一切是否顺利,请访问http://docker . for . MAC . localhost:5000/API/3/action/datastore _ search?resource _ id = _ table _ metadata
您应该会看到一个带有“success: true”属性的 JSON 对象。
6.现在让我们为 CKAN 创建超级用户:
$ docker exec -it ckan ckan -c/etc/ckan/production.ini sysadmin add yourname
你现在应该可以用yourname登录 CKAN 了。
7.作为将来的参考,如果您想让停止容器,只需访问存储和运行原始 docker-compose 文件的文件夹: $ docker-compose down
要重新激活它,只需运行
$ docker-compose up
让我们用我们的用户登录并上传一个数据集,看看它会是什么样子。我将上传一些存储在压缩 shapefile 中的行政边界,看看它是什么样子的。

图片由作者提供。
我以为你提到了地理空间?
为了让 CKAN 具有空间感知能力,我们需要安装两个扩展: geoview 和 spatial 。请记住,有许多扩展可能非常有用,比如地图小部件。
在 CKAN 的 dockerized 实例中安装扩展的方法不止一种。您可以将这些步骤包含在菜谱中,并从一开始就安装它们。在这里,我们将把扩展直接安装在这个特定的运行容器上,因此这不会对我们用来构建这些映像的 docker 文件产生任何影响。
地理视图
Ckanext-geoview 是一个扩展,能够以网络地图的形式预可视化空间数据。那些可以是 shapefiles,geojson 甚至是 WMS。
- 进入正在运行的 ckan 容器:
$ docker exec -it ckan /bin/bash -c "export TERM=xterm; exec bash"
2.在运行容器内,激活 virtualenv:
$ source $CKAN_VENV/bin/activate && cd $CKAN_VENV/src $ git clone [https://github.com/ckan/ckanext-geoview.git](https://github.com/ckan/ckanext-geoview.git) $ cd ckanext-geoview $ pip install -r pip-requirements.txt $ python setup.py install $ python setup.py develop $ cd .. $ exit
3.访问 Docker Linux 虚拟机:
$ docker run -it --privileged --pid=host justincormack/nsenter1
4.从虚拟机内部:
$ vi var/lib/docker/volumes/docker_ckan_config/_data/production.ini
5.在ckan.plugins中增加resource_proxy geo_view geojson_view shp_view
6.将geo_view geojson_view shp_view添加到ckan.views.default_views
同样,要用 vi 编辑器编辑 production.ini 文件,键入 i 进行插入。然后 ESC ,然后 :x 保存时退出 vi,或者 :q!退出而不保存。要退出虚拟机,请键入 exit 。
7.通过运行
$ docker-compose restart ckan重新启动容器
安装 Geoview 后,我们现在可以通过点击 Explore 按钮,直接在 CKAN 的网络地图中显示我们之前上传的数据。

图片由作者提供。
空间的
Spatial 是一个扩展,可将空间字段用于 CKAN 中存储的所有元数据。所以基本上,它将在底层 PostgreSQL 数据库中安装 PostGIS,并在我们的门户中启用空间索引和搜索。安装它会比 geoview 稍微复杂一点,但是我们会做到的。
- 进入正在运行的 ckan 容器:
$ docker exec -it ckan /bin/bash -c "export TERM=xterm; exec bash"
2.在运行容器中,激活 virtualenv,获取扩展的源代码并安装:
$ source $CKAN_VENV/bin/activate && cd $CKAN_VENV/src/ $ git clone [https://github.com/ckan/ckanext-spatial.git](https://github.com/ckan/ckanext-spatial.git) $ cd ckanext-spatial $ pip install -r pip-requirements.txt $ python setup.py install $ python setup.py develop $ cd .. $ exit
3.这就是棘手的地方。我们将从主机容器中更新 postgis 的权限:
$ docker exec -it db psql -U ckan -f /docker-entrypoint-initdb.d/20_postgis_permissions.sql
4.访问 Docker Linux 虚拟机:
$ docker run -it --privileged--pid=host justincormack/nsenter1
5.从虚拟机内部:
$ vi var/lib/docker/volumes/docker_ckan_config/_data/production.ini
将spatial_metadata spatial_query添加到ckan.plugins
添加ckanext.spatial.search_backend = solr
6.重启容器:
$ docker-compose restart ckan
7.重新进入正在运行的 ckan 容器并重新激活 virtualenv:
$ docker exec -it ckan /bin/bash -c "export TERM=xterm; exec bash" $ source $CKAN_VENV/bin/activate && cd $CKAN_VENV/src/
8.从虚拟机内部,运行空间 initdb 命令:
$ ckan--config=/etc/ckan/production.ini spatial initdb
9.通过访问http://docker . for . MAC . localhost:5000/API/3/action/status _ show再次重启容器并检查它是否工作
安装 Spatial 后,我们现在可以对数据集进行地理索引,并按空间范围进行搜索!
这是所有的乡亲
这一块就到此为止!我们已经成功地在 Mac 上运行了 CKAN 的 dockerized 实例,它具有两个重要的地理空间数据扩展!如果你有问题或建议,不要犹豫,随时给我写信!
如果你喜欢这篇文章,考虑给我买杯咖啡,这样我就可以继续写更多的文章了!
https://www.buymeacoffee.com/guilhermeiablo
使用 Docker 在 EC2 + CI/CD 上运行气流,使用 GitLab
原文:https://towardsdatascience.com/running-airflow-with-docker-on-ec2-ci-cd-with-gitlab-72326d4baeb4?source=collection_archive---------2-----------------------
使用基本命令创建简单的数据管道,并运行您自己的基于云的管道!

约书亚·阿拉贡在 Unsplash 上拍摄的照片
我已经学习数据科学一年了,但直到几周前,我仍然发现自己对工程方面完全一无所知。数据分析和人工智能是金字塔顶端的东西,需要强大的数据管道基础。在这篇文章中,我将分享我在尝试使用开源编排工具 Airflow 构建简单数据管道时学到的经验。这个 orchestrator 部署在 Amazon EC2 之上,利用 GitLab 的 CI/CD 来简化开发过程。好的,一个接一个,我们来谈谈每个术语的定义。
气流
基于其网站,Airflow 是一个由社区创建的“平台,用于以编程方式创作、安排和监控工作流数据工程师通常使用气流来协调工作流程和管道。假设一名数据工程师每天需要将数据从一个源移动到另一个目的地四次(例如,为了保持数据的新鲜)。他们可以使用 Airflow 自动运行脚本,按照特定的时间表运行,而不是手动完成该任务。Airflow 还可以用于管理依赖关系、监控工作流执行和可视化工作流。
气流需要安装在机器上。与其使用本地电脑,不如安装在基于云的主机上,提高可靠性。
亚马逊 EC2
Amazon EC2(代表弹性计算云)是由 Amazon Web Services 提供的基于云的租用计算机。EC2 将充当主机,气流将在其上部署。EC2 只是一台计算机,就像我们本地的笔记本电脑一样,但是这台计算机 99%的时间都是运行的,由 AWS 团队管理。我们可以通过使用 SSH 在 EC2 机器的命令行界面中“挖隧道”。稍后,我们将学习如何使用 SSH 和 git 将代码从远程存储库部署到 EC2。
码头工人
Airflow 不会直接安装在 EC2 本地机器上,而是安装在 Docker 容器内部。Docker 是一组创建虚拟操作系统(称为容器)的平台。我们使用 Docker 来减少设置,因为所有设置都将由 Docker 映像的维护者(在本例中是气流贡献者)来管理。Docker 映像包含应用程序代码、库、工具、依赖项和其他运行应用程序所需的文件。我们将从 Docker image registry 中提取一个图像,构建它,启动容器,并在里面运行 Airflow。
GitLab
GitLab 将被用作我们的存储库和 DevOps 生命周期工具。实际上,在 GitLab 中有无数种方法可以利用 CI/CD,但为了简单起见,我们将只使用“CD”部分。每次用户将任何分支合并到主分支时,都会触发部署脚本。部署管道由进入我们的 EC2 的 SSH 隧道组成,将主分支从 GitLab 存储库拉入 EC2,将几个变量写入一个文件,并重建+重启 Docker 容器。
在深入细节之前,请查看这个库,它包含了完整的代码库和我们将成功创建一个持续的气流部署管道的步骤摘要。好了,我们开始吧!
安装
EC2
访问 AWS 控制台,然后准备一个 EC2 实例。我推荐在 ubuntu OS 上使用 instance,性能中等偏下。下载 EC2 实例的 SSH 密钥(通常以.pem后缀结尾),并记下实例的 IP 地址。然后,将您的实例配置为打开所有端口(至少打开端口 8080 以访问 Airflow 服务器)。最后,通过使用 SSH 键从命令行界面安装 Docker 和 docker-compose 来访问 EC2。
ssh -i ssh-key.pem ubuntu@EC2_ADDRESS
【https://www.youtube.com/watch?v=YB_qanudIzA】EC2 条款指南:
GitLab
在 git lab(https://gitlab.com)上注册并创建一个新项目。将内容从 github 仓库克隆到我们新的 GitLab 仓库。在用代码填充存储库之后,我们需要配置 GitLab runner 并设置存储库变量。GitLab runner 用于执行我们在gitlab-ci.yml中定义的 CI/CD 脚本。存储库变量用于存储敏感信息(如用户名、密码、EC2 的 IP 地址和 EC2 的 SSH 密钥)。存储库变量作为环境变量加载到 CI/CD 管道中,在那里它可以作为变量/文件部署到服务器。

GitLab 知识库的接口。图片作者。
按照 GitLab 转轮配置指南中的说明配置我们的转轮。对于我来说,我使用 EC2 实例和 ubuntu OS 来安装我的 runner。如果您通过提供您的信用卡信息激活 GitLab 的免费试用,您就不必配置自己的跑步者,因为 GitLab 会为您提供一个共享的跑步者。
GitLab 储存库变量

存储库变量—按作者分类的图像。
我们需要设置六个存储库变量。进入设置> CI/CD >变量,点击展开,开始添加变量。
前两个是 _AIRFLOW_WWW_USER_PASSWORD 和 _AIRFLOW_WWW_USER_USERNAME,它们将用于在部署 AIRFLOW 服务器后登录到该服务器。为这两个变量选择任意值。
第二对是 EC2_ADDRESS(您的 EC2 实例的 IP 地址)和 SSH_KEY_EC2(您的 EC2 实例的 SSH key,通常以.pem后缀结尾)。这些值将用于访问您的 EC2 机器。将 SSH_KEY_EC2 设置为文件而不是变量。
最后一对是 GITLAB_PASSWORD 和 GITLAB_USERNAME,用于从 GITLAB 存储库中提取提交的凭证。
代码解释
从下面的目录结构开始。

这个项目的目录结构-作者图片。
三个目录(Dag、日志和插件)是基本的气流目录。我们让日志和插件(几乎)为空,因为这些文件夹将在部署后被填满。我们希望自动化的脚本写在 Dag 内部,我们将在后面介绍。
在对 GitLab 的回购进行任何推送的过程中,都会触发.gitlab-ci.yml(定义 CI/CD 管道)中的脚本。该脚本执行一系列命令来将存储库部署到 EC2。在 EC2 内部,我们将通过在docker-compose.yaml上使用docker-compose up来构建包含气流的 Docker 容器。
CI/CD 管道
在变得更复杂之前,请先参考本指南了解什么是 GitLab 的 CI/CD。
CI/CD 管道在.gitlab-ci.yml中定义。
因为我使用的 GitLab runner 使用 Docker 执行管道,所以默认图像在顶部指定。我使用ubuntu:latest作为我的默认 Docker 图像。
如前所述,我们不会利用 CI/CD 的持续集成方面。我们只使用仅在主分支中触发的部署。这意味着所有推送到 main 之外的其他分支不会导致部署。
deploy-prod:
only:
- main
stage: deploy
before_script: ...
script: ...
deploy-prod是我们管道的名称,它将只在主分支中运行。这个管道的阶段是部署阶段(与测试或构建等其他阶段不同)。命令在before_script和script中指定。
before_script:
- ls -la
- pwd
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- cat $SSH_KEY_EC2
- echo "$(cat $SSH_KEY_EC2)" >> ~/.ssh/ssh-key.pem
- chmod 400 ~/.ssh/ssh-key.pem
- cat ~/.ssh/ssh-key.pem
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- apt-get update -y
- apt-get -y install rsync
before_script由几个命令组成,这些命令让我们的跑步者为部署做好准备。这些命令用于安装 open-ssh、评估 ssh-agent、将 ssh 密钥从存储库变量转储到文件、更改 ssh 密钥的权限、设置 SSH 配置以及安装 rsync。
ssh -i ~/.ssh/ssh-key.pem ubuntu@$EC2_ADDRESS \
'git config --global --replace-all user.name "Full Name"
&& git config --global --replace-all user.email "email@email.com"
'
script部分分为三个部分。每个部分都是从进入 EC2 的 ssh 隧道开始的。第一部分用于设置 git config,使用您的全名和电子邮件作为全局配置。
ssh -i ~/.ssh/ssh-key.pem ubuntu@$EC2_ADDRESS \
'
if [ -d airflow-pipeline ];
then cd airflow-pipeline
&& git status
&& git restore .env
&& git pull --rebase
&& git status
&& sed -i s:%AIRFLOW_UID%:'"$(id -u)"':g .env
&& sed -i s:%AIRFLOW_GID%:0:g .env
&& sed -i s:%_AIRFLOW_WWW_USER_USERNAME%:'"$_AIRFLOW_WWW_USER_USERNAME"':g .env
&& sed -i s:%_AIRFLOW_WWW_USER_PASSWORD%:'"$_AIRFLOW_WWW_USER_PASSWORD"':g .env
else git clone https://'"$GITLAB_USERNAME"':'"$GITLAB_PASSWORD"'@gitlab.com/gitlab-group/gitlab-project.git
&& cd airflow-pipeline
&& ls -la
&& chmod 777 logs
&& sed -i s:%AIRFLOW_UID%:'"$(id -u)"':g .env
&& sed -i s:%AIRFLOW_GID%:0:g .env
&& sed -i s:%_AIRFLOW_WWW_USER_USERNAME%:'"$_AIRFLOW_WWW_USER_USERNAME"':g .env
&& sed -i s:%_AIRFLOW_WWW_USER_PASSWORD%:'"$_AIRFLOW_WWW_USER_PASSWORD"':g .env
&& docker-compose up airflow-init;
fi'
第二部分用于从 GitLab 存储库中的主分支提取变更,并将环境变量写入.env文件。这里我们使用基于 EC2 主目录上目录存在的条件。如果我们之前已经克隆了 GitLab 存储库,我们只执行了:从.env文件中恢复所有更改,从远程 GitLab 存储库中提取更改,并将环境变量写入.env。如果还没有,我们首先克隆存储库,然后将环境变量写入.env文件,并启动 Docker 容器。
ssh -i ~/.ssh/ssh-key.pem ubuntu@$EC2_ADDRESS \
'cd airflow-pipeline &&
if [ docker ps | grep -q keyword ];
then docker-compose down && docker-compose up -d --build;
else docker-compose up -d --build;
fi;'
最新的部分用于重新启动 Docker 以合并新的更改。
可以在 GitLab 的 CI/CD >管道上监控 CI/CD 管道。

GitLab CI/CD 管道—图片由作者提供。
如果一切顺利,你的气流网络服务器将准备就绪。在浏览器上点击https://{EC2_ADDRESS}:8080进入用户界面。使用之前在存储库变量上设置的 Airflow 用户名和密码登录。

Airflow webserver 登录页面—作者图片。

Airflow webserver 的界面—图片由作者提供。
稍后,您希望自动化的任何脚本都可以写在 DAG(或有向无环图,没有有向循环的有向图)中。DAG 内的任务被框定为图的节点,其中可以定义依赖性。存储库中的任何更改都可以通过将更改推送到 GitLab 存储库、合并到主分支(或直接推送到主分支)并等待 CI/CD 管道成功来部署。
您可以在 DAG 中定义许多东西,例如数据接收任务、数据查询任务、发送自动电子邮件、抓取数据、进行 API 调用等。

DAG 中的依赖关系可视化—按作者排序的图像

DAG 中的任务监控—按作者排列的图像
为什么指定。gitignore?
不建议在本地记录气流活动。然而,由于时间和成本的限制,我在本地记录所有的活动,尤其是在/logs目录下。除了日志,DAG 执行还会在/dags/__pycache__/中创建缓存。因此,我通过使用.gitignore忽略了那些文件,以安全地提取更改,而不会导致冲突。
EC2 检验
如果出现任何问题,您总是可以通过使用 SSH 键来检查 EC2 内部发生了什么。
ssh -i ssh-key.pem ubuntu@EC2_ADDRESS
删除未使用的文件,未使用的 Docker 图像,或从内部进行任何调整!
参考文献
[1]https://airflow.apache.org/
【2】https://aws.amazon.com/ec2/
【3】https://www.docker.com/
【4】https://about.gitlab.com/
【5】https://air flow . Apache . org/docs/Apache-air flow/stable/start/docker . html
【6】Bunga Amalia K 关于设置 GitLab runner 的代码参考
大规模运行 Apache 超集
原文:https://towardsdatascience.com/running-apache-superset-at-scale-1539e3945093?source=collection_archive---------23-----------------------
大规模高效运行超集的一组建议和起点

样本超集仪表板(来源:https://superset.apache.org/gallery/
W 谈到商业智能(BI)生态系统,专有工具在很长一段时间内都是标准。Tableau、Power BI 和最近的 Looker 是企业 BI 用例的首选解决方案。但是后来,Apache 超集发生了。
由于对依赖专有 BI 解决方案的诸多不便感到失望(如缺乏与某些查询执行引擎和供应商锁定的兼容性),Maxime Beauchemin 使用 Airbnb 内部黑客马拉松从头开始构建 BI 工具。
该项目于 2016 年开源(最初为 Caravel ),并在过去五年中成为今天的 Apache 超集,作为开源项目为全球开发者提供专有 BI 工具(及更多)的功能。因此,毫不奇怪,它很快被数十家公司采用。
在最初发布五年后,当谈到大规模运行超集时,文档仍然有限,尽管该工具本身是云原生的,并且是为大规模运行而设计的。本文旨在提供一些起点和建议,可以在这方面帮助新的采用者。
都是关于容器的
无论您希望在哪个平台或云上运行超集,如果您正在计划可伸缩性,那么第一个构建块应该是准备您的定制容器映像。这将允许您拥有与您的用例相匹配的超集容器,并且可以部署到各种编排平台(如 ECS 或 Kubernetes)。
起点应该是官方的超集映像(DockerHub 上的),然后在 DockerHub 文件中,您可以为您的用例添加额外的依赖项(如数据库驱动程序)。例如,如果我们想使用 Redis,docker 文件应该是这样的:
FROM apache/superset:1.0.1
# We switch to root
USER root
# We install the Python interface for Redis
RUN pip install redis
# We switch back to the `superset` user
USER superset
此外,您应该创建一个包含您的定制配置的 superset_config.py 文件。多亏了它,你可以覆盖超集的主配置文件中的值,比如认证方法或查询超时。
最后,我们可以通过添加以下命令来更新 Dockerfile 文件:
# We add the superset_config.py file to the container
COPY superset_config.py /app/
# We tell Superset where to find it
ENV SUPERSET_CONFIG_PATH /app/superset_config.py
这将确保我们的定制配置被加载到容器中,并被超集识别。然后,您可以简单地在 docker 文件中添加一个 CMD 步骤来实际运行超集。
缓存,缓存,缓存
无论您想将超集连接到哪个(哪些)数据库,如果您计划大规模运行它,那么您肯定不希望它在每次有人打开仪表板时运行多个查询。
该工具提供了不应被忽视的多种缓存可能性。至少,您应该尝试缓存超集自己的元数据和不同图表的数据。这样,在我们创建图表后,超集将把它的数据保存到我们配置的缓存中。之后,下次有人试图查看图表时(例如,通过仪表板),超集将立即从缓存中检索数据,而不是在实际的数据库上运行查询。
基本上是一个 Flask 应用程序(它使用 Flask-AppBuilder 框架),出于缓存的目的,Superset 使用Flask-Cache——这反过来支持多个缓存后端,如 Redis 和 Memcached。
如果您还想将超集用于长时间运行的分析查询,那么您可以使用 Celery 配置一个异步后端,这样您就可以拥有一个查询结果的专用缓存机制。
设置身份验证
不出所料,Superset 也依赖 Flask AppBuilder 进行认证。它提供了多种身份验证选项,如 OAuth 和 LDAP,可以轻松激活和配置。
对于可伸缩的设计,您可能希望激活一种身份验证方法,然后让用户在平台上执行自我注册。为此,您可以将下面两行添加到您的 superset_config.py 中:
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "a_custom_default_role"
权限很乱,不过没关系
关于 Superset 的一个不太理想的方面是它的权限管理,在它的存储库上有一个公开的问题(大约两年前公开的),详细说明了当前实现的不同问题,并提出了一个更好的替代方案。
幸运的是,数据访问权限很容易配置,这个问题与 Flask AppBuilder 生成的特性相关的权限有关。
为了避免管理长长的权限列表,一种有效的方法是克隆现有角色中的一个,并根据您的用例对其进行定制,这样您就可以在默认情况下为您的用户提供这个新的定制角色。
结论
得益于其庞大的社区,Superset 迅速成为一个成熟且非常完整的项目(最近发布了 1.0 版本)。考虑到这一点,当您设计大规模 BI 平台时,它绝对应该被视为一个可行的选择。
当我们考虑到它的一长串特性和功能时,它大规模工作所需的不同配置步骤只是一个小小的代价。Airbnb 的设置以及他们如何利用其不同的功能(通过该公司博客上的一篇文章详细讨论了这一点)是其强大的最好例子。
最后,值得一提的是,Superset 的创造者 Maxime Beauchemin 最近成立了预置——一家为 Apache Superset 提供托管云服务的公司。如果您希望最大限度地减少必要的配置工作,那么选择预置会更方便。
要了解更多数据工程内容,您可以订阅我的双周刊时事通讯 Data Espresso,在其中我将讨论与数据工程和技术相关的各种主题:
https://dataespresso.substack.com/
用 K-均值聚类进行竞选活动。
原文:https://towardsdatascience.com/running-election-campaigns-with-k-means-clustering-ecc40a91135a?source=collection_archive---------15-----------------------
实用 ML
K-均值聚类实用介绍。

照片由来自 Pexels 的 Andre Taissin 拍摄
假设你是下届总统选举的首席竞选策划人。由于疫情推动的技术采用,这次活动将在网上进行。因为它有助于覆盖整个国家,无需任何旅行,您的政党决定采取创新的方法。
你的任务是找到有相似兴趣(或需求)的人群。他们每个人都将有一个单独的在线活动。如果你的国家的未来取决于你,你会怎么做?
数据科学家使用聚类算法来帮助解决这个问题。K-means 是使用各种属性对大型数据集进行分组的最简单而有效的算法。这是一种在数据集中查找非重叠组的迭代方法。在你的情况下,找到有着相似需求和兴趣的不同的选民群体。每个人都成为一个且只有一个群体的成员。
k 是您希望拥有的集群数量。但是,你怎么知道正确的数字是多少呢?通读一遍,找出答案。
这篇文章将带你经历解决这个难题的步骤,并回答你在途中必须做出的一些关键决定。在本文中,我使用 python 实现了我们讨论的例子。
如果你感到迷茫,可以参考 GitHub 资源库。我在这个插图中使用的数据集不是原始的。如果你还想练习,那也在知识库里。
寻找具有两个变量的聚类。
让我们假设你可以访问你的国家的个人年龄年收入(和债务)水平(在一个电子表格中,如下图所示)。

作者图片
当然,你可以根据你以前的知识来创建小组。例如,高收入的千禧一代将是其中一个群体。但是,您决定深入研究,看看是否有其他方法来聚集它们。因此,你决定用这两个变量进行 K-means。
使用 python 来做是毫不费力的。您只需要几行代码来读取数据并执行 K-means 聚类。
你现在知道要考虑哪两个更突出的群体,以及他们的平均年龄和收入。你也知道每个人属于哪一组。
真是难以置信。但是,我们需要亲眼看到它才能更好地理解它,不是吗?同样,这很简单,只需要几行代码。

作者图片
想象有帮助。我们可以看到这些簇被很好地分开,并且它们的簇质心是有代表性的。
此时要问的一个有趣问题是,我们如何知道只有两个集群?还会有更多吗?让我们重复同样的步骤,假设数据集有三组。

作者图片
只有两个变量的聚类使可视化变得简单。但是,如果只需要考虑两个特性,您甚至可以创建逻辑组。我们能增加更多的功能吗?
此外,我们可以将集群的数量增加到任意值。但是什么是最佳数量呢?
我们将在接下来的章节中回答这些问题。但是在我们开始之前,让我们试着理解 K-means 算法是如何工作的。
引擎盖下发生了什么?
K-means 使用数据点之间的距离。因此,彼此靠近的数据点很可能落入同一聚类中。
开始时,K-means 随机选择 K 个数据点作为它的聚类中心。这里,K 是我们定义的任意数。在我们的例子中,这个可以是年龄 25 岁,收入 20k(集群 A) 和年龄 50 岁,收入 100k(集群 B) 。
然后,它会计算数据集中所有数据点与这些质心之间的距离。并且该算法将每个数据点分配给最近的质心。因此,这意味着一个收入为 30k 的 20 岁的人将在群集 A 中,而一个收入为 80k 的 60 岁的人可能在群集 b 中。
K-means 通过平均每个聚类的所有数据点来计算一组新的质心。因此,聚类 A 的新聚类质心可以是年龄 22 和 25k 收入。星团 B 的质心可能也发生了变化。这些将是下一次迭代的质心。
这个过程一直持续到聚类质心没有显著变化。
如果要考虑更多的特性呢?
根据年龄和收入寻找聚类似乎很简单。你可能不需要机器学习来做这件事。但是,在现实中,你将有一堆其他的变量要处理。这可能包括他们的教育水平、健康状况和财务状况。
然而,这两个维度帮助我们理解了算法。此外,只用两个变量也很容易想象。但是,让我们添加一个新的变量,使它更加现实。
假设你也有每个人的债务水平。这难道不是政治竞选的重要信息吗?
您无需对已经编写的代码做太多修改就可以做到这一点。只需将“债务”添加到要传递的变量列表中。
找到 k 的正确值。
K-means 查找聚类,但是它不确定集合的数量;你得自己定义。
如果你使用了一个较小的 K 值,你可能无法解决投票者的正确问题。你的承诺可能看起来很肤浅,因为有不同需求的人现在在同一个集群里。
另一方面,如果你使用了大量的 K,那么广告活动将会很昂贵。结果,你的派对可能会以取悦每一个毫无价值的利基市场而告终。
但是你怎么知道你得出的任意数字是合适的呢?
肘法可以帮你找到这个。
在这种方法中,我们使用数据点和它们的聚类质心之间的距离平方和(SSE)来确定 K 值。我们称这个值为惯性。随着聚类越多(K 越大),惯性将总是随着到最近聚类的距离的减小而减小。
然而,在某种程度上,这种减少变得微不足道。因此,我们得出结论,此时的簇数是 k 的正确值。
下面是实现这一点的 python 代码片段。
我们用不同的 K 值拟合 K 均值,并将惯性值收集在一个列表中。然后,我们使用这些信息绘制下图。

作者图片
在这张图上,很明显,经过三个集群后,惯性的下降并不明显。
这一信息意味着,如果你将选民分成三组,属于同一聚类的人具有相似的特征。你可以策划三种不同的策略来解决它们。
相反,四个集群会让你的营销活动变得昂贵,因为每个集群需要不同的策略。两个群体可能会让选民觉得他们的需求没有得到满足。
K-均值聚类的缺点。
你可能对 K 均值的初始聚类质心有疑问。如果它是随机选择的,那么每次算法运行时,聚类不会不同吗?
当然,陷入局部最小值是 K-means 算法的一个问题。
要解决这个问题,您可能需要多次运行该算法,然后选择最合适的算法。聚类质心和它们的成员之间的距离平方和可以帮助我们找到正确的拟合。这个数字越低越好。
K-means 算法对异常值很敏感。由于该算法在每次迭代时都会计算新的质心,离群值可能会扭曲它。在开始之前,请确保移除所有异常值。
但是,这些缺点更容易控制。一些让 K-means 不适合的严肃问题怎么办?
K-means 对于不同大小或密度的聚类表现不佳。因此,如果数据集的高收入老年人多于中年低收入者,K 均值可能会以无意义的聚类结束。
k 表示对于线性可分的簇表现良好。但是其他类型的数据呢?K-means 不能聚类不同的几何形状,如椭圆形和圆形。
然而,K-means 一直是数据科学家的最爱。
总而言之,
K-means 是一种简单而流行的聚类算法。它将数据点分组到不重叠的群集中。
在本文中,我们讨论了如何使用 python 执行 K-means 聚类。我们从两个变量开始。然后我们谈到增加更多的变量,为 k 找到一个正确的数。
在这篇文章中,我们一直遵循一个假设的政治竞选场景。虽然,在现实中,你可能有无数的其他变量,但基本步骤是相同的。此外,您可以在无数其他应用程序中使用 K-means 算法。例如,你可以用它来压缩图像以及对你电脑上的文件进行分类。
但这并不意味着它永远是最好的。我们已经讨论了 K-means 算法的几个缺点。例如,K-means 在复杂的几何形状上做得不好。DBSCAN 等算法可以更好地解决这个问题。但那是后话了。
感谢阅读,朋友!看来你和我有许多共同的兴趣。我很乐意通过 LinkedIn、T2、Twitter 和 Medium 与你联系。
使用 Google Cloud BigQuery ML 运行 Kedro 机器学习管道
原文:https://towardsdatascience.com/running-kedro-machine-learning-pipelines-with-google-cloud-bigquery-ml-47cfe2e7c943?source=collection_archive---------19-----------------------
理解大数据
Kedro 是一个面向数据科学家和数据工程师的流行开源框架。在这篇文章中,我们将展示如何通过在 Google Cloud 笔记本中部署 Kedro 管道来简化它们,将主数据保存在 BigQuery 中,并利用其使用标准 SQL 查询创建和执行机器学习模型的能力。

照片由弗洛里安·威特在 Unsplash 拍摄
介绍
Kedro 是一个用于数据管道的开源框架。它实现了行业最佳实践。它通常由日期科学和数据工程团队使用。看看下面这个来自他们的创作者的介绍视频, QuantumBlack 。
我们将使用原始太空飞行教程。我们身处 2160 年,Spaceflights 是一家带游客往返月球的公司。在本例中,我们将创建一个模型来预测旅行价格。这篇文章中的两个步骤:
- 在谷歌云笔记本中部署 Spaceflights 原始教程
- 通过以下更改修改管线:
- 使用 Google 云存储(GCS)存储原始数据和中间结果
- 将主数据保存在 BigQuery 表中
- 用 BigQuery ML 创建 ML 模型
为了运行本教程,您需要:
- 谷歌云账户
- 浏览器
在谷歌云笔记本中部署太空飞行教程
我们首先需要的是一个谷歌云项目。打开一个云控制台,点击右上角的“激活云壳”图标。这将部署一个可通过浏览器访问的开发和操作环境。
记下您的项目 ID 并选择一个离您的位置较近的地区和区域来部署您的资源。
有了这些信息,我们可以从云 Shell 命令行创建一个笔记本(用您自己的值替换粗体中的文本):
PROJECT_ID=**mh-kedro**
REGION=**europe-west1**
ZONE=**europe-west1-b**gcloud config set project $PROJECT_ID
gcloud services enable notebooks.googleapis.comgcloud beta notebooks instances create "kedro-spaceflight-nb" \
--vm-image-project="deeplearning-platform-release" \
--vm-image-family="common-cpu" \
--machine-type=n1-standard-4 \
--location=$ZONE
从云外壳的第一次执行将弹出一个授权确认。几秒钟后,实例将被创建。在云控制台的左侧主菜单中,选择 AI 平台>笔记本,查看您的笔记本实例:

单击“打开 JUPITERLAB”访问您的 JupyterLab 会话。

打开一个终端。我们将在这里工作。要安装 kedro,只需输入
pip install kedro
下一步是安装 spaceflights 教程。原始文档详细解释了如何做。为了简洁起见,我们将使用“太空飞行”开头。
kedro new --starter=spaceflights
选择“spaceflights”作为项目名称,保留其他默认值

现在,让我们安装所需的库并运行项目:
cd spaceflights
git init
pip install -r src/requirements.txt
kedro run
这是输出:

spacefligths 项目运行输出
注意每个节点的执行。我们在 data/02_intermediate 创建中间文件,并生成主数据文件data/03 _ primary/master _ table . CSV。
然后,我们使用该文件创建一个价格预测模型,作为对某些特性的线性回归。模型存储在文件data/06 _ models/regressor . pickle中。最后,我们显示了模型的 R^2 系数值:0.456。
在这一点上,可视化管道是很有趣的。Kedro 为此提供了 viz 工具。从您的终端运行:
pip install kedro-viz
kedro viz
这将打开一个监听 localhost:4141 服务器。

为了从我们的浏览器访问,我们需要通过键入以下命令从云外壳打开一个隧道:
gcloud compute ssh --project $PROJECT_ID --zone $ZONE "kedro-spaceflight-nb" -- -L 4141:localhost:4141
然后点击右上角菜单中的“网络预览”图标。将端口更改为 4141。

此时,会打开一个新选项卡,我们可以看到我们的管道:

航天管道可视化
我们已经在一个 Google Cloud 笔记本实例中成功运行了我们的 kedro 管道。
到目前为止,管道是在本地运行的,使用本地文件系统存储中间数据、主数据、模式等。现在想象一个非常大的数据集。在某个时候,我们当地的环境会耗尽资源。我们如何扩展?
答案是在外部系统之间分配负载,并从 kedro 管道进行编排。特别是在这个例子中,我们将使用:
- 用于原始和中间文件的谷歌云存储
- BigQuery 作为保存主数据的数据库
- BigQuery ML 用于机器学习模型的创建和执行
创建 Google 云存储和 BigTable 资源
第一步是资源创建。转到您的云外壳,退出您的 ssh 隧道会话并键入:
gsutil mb -l $REGION gs://$PROJECT_IDbq --location=$REGION mk spaceflightsbq mk \
-t \
--description “Kedro tutorial master table” \
spaceflights.master \
id_x:INTEGER,shuttle_location:STRING,shuttle_type:STRING,engine_type:STRING,engine_vendor:STRING,engines:NUMERIC,passenger_capacity:INTEGER,cancellation_policy:STRING,crew:NUMERIC,d_check_complete:BOOLEAN,moon_clearance_complete:BOOLEAN,price:NUMERIC,review_scores_rating:NUMERIC,review_scores_comfort:NUMERIC,review_scores_amenities:NUMERIC,review_scores_trip:NUMERIC,review_scores_crew:NUMERIC,review_scores_location:NUMERIC,review_scores_price:NUMERIC,number_of_reviews:INTEGER,reviews_per_month:NUMERIC,id_y:INTEGER,company_rating:NUMERIC,company_location:STRING,total_fleet_count:NUMERIC,iata_approved:BOOLEAN
第一行创建一个 GCS bucket,第二行创建一个 BigQuery 数据集,最后一行创建一个表来保存主数据。
回到笔记本,安装额外的 python 依赖项来与 BigQuery 交互。接下来,我们必须将原始数据文件从 data/01_raw 复制到 GCS。我们可以在笔记本中直接使用 gsutil(用您的 PROJECT_ID 值替换 mh-kedro )。
pip install pandas-gbq google-cloud-bigquery
gsutil cp data/01_raw/* gs://mh-kedro/raw/

检查站
您可以从云控制台检查 GCS 上的文件:

检查站
改变太空飞行管道:谷歌云存储
【查看本回购中的完整新文件】
这个真的很简单。Kedro 包括许多用于外部集成的数据集,以及使用gcsf的直接 GCS 支持。Kedro 在数据目录中定义其数据源。
我们只需更改我们的项目目录文件中的文件名,指向我们的 GCS 存储桶:
在这里使用您自己的存储桶名称。
改变太空飞行管道:大查询
kedro 还通过 pandas-gbq 包含了一个直接的 BigQuery 集成。不需要更改代码,只需更改目录条目,如下所示:
请注意数据集和表的名称值。参数 if_exist 可以取两个值,这里使用 replace 在每次执行时创建新数据和删除旧数据。使用 append 在每次执行时写入额外的数据,或者如果表已经存在,如果想要给出一个错误,使用 fail 。
更改 spaceflights 管道:BigQuery ML
现在是时候创建和执行我们的机器学习模型了。使用 BigQuery ML,可以直接用 SQL 代码创建模型。这一次我们必须对原始的 spaceflights 教程代码进行一些修改。
首先,我们向数据目录添加两个新条目。这将用于在我们的新节点之间传递数据。在这种情况下,我们使用数据类型 MemoryDataSet ,它不链接到文件,而是直接指向内存。
然后,我们向参数文件添加两个新值:
在最初的数据工程管道中,只有很小的改变来创建我们的 MemoryDataSet。查看节点和管道源文件中的详细信息。
在数据科学管道中是奇迹发生的地方。在管道源代码中,我们删除了原始的“分割数据”节点,因为我们在模型创建期间直接进行数据分割。
主逻辑在节点源文件中实现。相关部分是:
- 模型创建和培训
这里,我们从保存主数据的表中创建一个模型。一些细节需要评论:
- 使用的模型类型是线性回归。还有很多其他型号可供选择。
- 标签列是价格。这就是我们用模型预测的结果。
- 在这种情况下,拆分方法是随机的。随机拆分是确定性的:如果基础培训数据保持不变,则不同的培训运行会产生相同的拆分结果。
- 测试和训练数据集由参数子样本控制。0.2 表示 20%测试,80%训练。
2.模型评估
我们可以使用以下 SQL 代码评估模型:
运行修改后的 kedro 项目
现在是时候运行我们的模型了。从您的笔记本终端键入:
kedro run
输出是这样的:

现在 R^2 系数是 0.454。是的,改进这种模式还有很多工作要做。
让我们来看看我们的新渠道:
kedro viz

现在是在 BigQuery 中查看数据的好时机。转到云控制台,用您的数据进行实验

…还有你的模型。

打扫
完成后不要忘记清理您的资源,这样您就不会产生费用。
这是我们的月球之旅的结束,我们回到了地球,我希望你喜欢这次旅行!
使用 Cygwin 运行 Keras
原文:https://towardsdatascience.com/running-keras-using-cygwin-shell-987d211f3899?source=collection_archive---------34-----------------------
如何让你的运营团队骄傲

来源
目的
几个星期前,我们的一个业务部门成员告诉我,如果他们能够在他们的服务器上运行我们的 DL 引擎,“生活会更方便”。“服务器”这一概念意味着运行在 Cygwin 引擎上,在那里 python 并不总是被安装,如果是,版本是未知的,显然没有像 Keras 或 Pytorch 这样的包可以被安装(由于内部约束)。从他的角度来说,理想的情况是拥有一个执行 DL 任务的 shell 工具。那时我很清楚当我在我的电脑上使用 Torch 或 Keras 时它们是如何工作的,但是拿一个模型并把它们“Cygwin ”?我对此一无所知。可能有些读者现在会说,“这是小事”,他们是对的。然而,当我开始工作时,我发现有许多网站讨论了许多行动,但没有什么是端到端的描述。这就是这个帖子的动机。
早期步骤
当我开始工作时,我渴望在 Cygwin 上开发整个解决方案(梦想总是推动你前进)。因此,我采取的早期步骤贯穿于整个 Cygwin 安装程序,并且只是通过使用它。我路上的第一个“站”是选择套餐屏幕。

为了添加包,必须将该屏幕设置为满而不是未决。I安装 Openssh git 和 curl ( 安装如下图所示)


选择这些包并继续安装过程后,可以打开 Cygwin 屏幕并看到以下内容:

我们可以验证我们的装置运行良好

可以看出 curl 和 git 位于 Cygwin 内。Python?Cygwin 识别了我的 PC 上的 Python(事实上,我假设如果你读了这篇文章,你的 PC 上很可能有一个 Python)。由于这个项目是为不一定安装 Python 的环境开发的,所以我希望整个工作都在 Cygwin 上完成。因此,我返回到安装过程,并在选择包屏幕中添加了 Python(显然,Cygwin 提供了许多版本..我没有最喜欢的)

安装后“哪个 python 输出这个答案

我们甚至可以验证 Python 可以在 Cygwin 中工作,如下图所示:


正如我在开始时提到的,目标是让 shell 文件从 Cygwin 屏幕上运行。因此,是时候检查 Cygwin 是否允许这样做了(非常琐碎,但需要测试)。我写了一个小小的玩具文件( uu1.py ,我对名字很在行)保存在 Cygwin 下的 home/username 里。
if __name__==**"__main__"**:
a=2
b=a+3
print(**"gggg "**, a, b)
在运行之前,在文件的开头写入:
#!/usr/bin/python3
该文件夹是从 python3 的获得的文件夹
在 Cygwin 屏幕中,您可以编写
chmod a+x 文件名(在我的例子中是 chmod a+x uu1.py)
然后干脆。/uu1.py. 我们得到了:

好吧,Python 是管用的。现在我们需要引入一些额外的库(例如 numpy,matplotlib 等。)
显然,我们需要返回到 Cygwin 安装程序。选择包允许安装 numpy 和 matplotlib。这个安装非常慢,因为它添加了几个包。。安装完成后,我给 uu1.py: 添加了一些代码
if __name__==**"__main__"**:
a=2
b=a+3
xx=[1,1,8]
plt.plot(xx, **'r'**, label=**"trial Cyg"**)
plt.savefig(**"mygraph2.png"**)
print(xx)
x = np.array([1, 2, 5.])
print(x)
print(**"gggg "**, a, b)
print(np.random.randn(3, 4))
他的输出是:

毫无疑问 numpy 起作用了。那么 matplotlib 呢?
检查文件夹( home/natank/ )我得到了所需的带有正确图形的文件。对我来说,这就足够了。那些希望从 plt.show()获得屏幕上的图形的人可以在这里阅读
SciPy 怎么样?
你可能注意到了,直到现在,我们根本没有使用 pip 。
对于 Scipy 来说是需要的。在前进之前,验证您使用的是正确的 pip ,即位于 Cygwin 内的 pip

在上面的屏幕中,我们需要使用下面的 pip (pip3)。鞋面与另一种蟒蛇有关
如果你在 Cygwin 中没有 pip ,你可以从选择包屏幕安装它。
安装 Scipy 很简单:简单地使用 pip3 安装 Scipy。然而,这部分可能会消耗大量时间。尽管已经安装了一些必需的包(可能是在早期安装 numpy 和 matplotlib 的时候),我仍然需要返回到sleeded Packages并安装额外的包。这里读,这里读,这里读,受益匪浅:。我需要添加整个列表:
**liblapack-devel****libopenblas****wget****python37-devel****python37-paramiko****python37-crypto****gcc-fortran****python-gtk2**- tcl-tk
**libpng**- pkg-config
- l ibffi - devel
- zlib-devel
在某些情况下,您可能需要添加 python37-wheel
现在我设法安装了 Scipy。我甚至问过 uu1.py 的同意
*#!/usr/bin/python3* import numpy as np
import matplotlib.pyplot as plt
import scipy as sc
import os
from scipy.special import cbrt
if __name__==**"__main__"**:
a=2
b=a+3
xx=[1,2,8]
plt.plot(xx, **'r'**, label=**"trial Cyg"**)
plt.savefig(**"mygraph2.png"**)
print (xx )
x = np.array([1, 2, 5.])
print (x)
cb = cbrt([27, 64])
print(**"scipy "**,cb)
print (**"gggg "**,a,b)
print (np.random.randn(3,4))

所以一切正常。我现在确信使用 Cygwin 运行 Keras 只需两分钟。但是,正如你可能知道的,一分钟的长度取决于观察者,两分钟可能会变成两天,大部分时间花在与 Tensorflow 拒绝错误的斗争上
我必须找到另一个框架。这里提供了一种选择。我决定尝试使用我自己的 Python 创建 exe 文件,并验证 Cygwin 是否支持它
在 Anaconda 中创建 Exe
PyInstaller
据网上说,有几种方法可以创造。Python 中的 exe 文件。我决定测试的包是使用常规 pip 安装的 Pyinstaller 。
它实际上是如何工作的?
我就用下面这个玩具例子 test_dl.py :
import numpy as np
from keras.layers import Input,Dense,Dropout,concatenate
from keras.models import Model
import sys
if __name__ ==**'__main__'**:
print (sys.argv)
inp_dim =int(sys.argv[1])
batch_size=int(sys.argv[2])
r0 = np.random.randn(10,2*inp_dim)
tt = Input(shape=(inp_dim,))
tt1= Input(shape=(inp_dim,))
xx=Dense(256,activation=**"relu"**)(tt)
xx1 = Dense(256)(tt1)
xx= concatenate([xx,xx1],axis=1)
xx = Dropout(0.1)(xx)
xx = Dense(256,activation=**"relu"**)(xx)
xx = Dropout(0.1)(xx)
xx= Dense(100,activation=**"relu"**)(xx)
xx = Dropout(0.1)(xx)
xx =Dense(1,activation=**"sigmoid"**)(xx)
model = Model(inputs=[tt,tt1], outputs=xx)
model.compile(loss=**'binary_crossentropy'**, optimizer=**'adam'**)
print (model.summary())
zz = model.predict([r0[:,:inp_dim],r0[:,inp_dim:]])
print (zz)
print (sys.argv[3])
我们将 CMD 屏幕(或 anaconda 提示符)设置为包含我们的源代码的文件夹,并键入下面的“py installer—one file file _ name . py

当这个过程结束时,您将在项目查看器中看到两个新文件夹 build 和 dist 以及一个名为 file_name.spec 的文件

在区内你会发现。exe 文件

有两种方法可以运行它:
使用 cd dist 进入 dist 文件夹并运行(带有 sys.argv 的参数)

或者复制到 Cygwin 文件夹(home/user/)并如下运行:

Sys.argv
我假设你们大多数人都熟悉 sys.argv. 对于那些不熟悉的人来说, sys.argv 是一个包含 exe 文件外部参数(如果有的话)的列表。第一个单元格总是文件的名称。
最终外壳文件
目标是:创造一个外壳。这是我们玩具例子中的一个:

test_dl.sh
我们如下运行它:

希望这篇帖子对部分读者有所裨益(假设读者的存在)
承认
我希望感谢 Yuval Shachaf 花费了大量的时间做这个项目和一些校对工作(剩下的错误是因为我没有听)
来源
https://yourcfriend . com/WP-content/uploads/2019/05/Launching-and-use-Cygwin . png(图片)
https://towards data science . com/tensor flow-is-in-a-relationship-with-keras-introducing-TF-2-0-DCF 1228 f 73 AE
https://upload . wikimedia . org/Wikipedia/commons/thumb/2/29/Cygwin _ logo . SVG/1200 px-Cygwin _ logo . SVG . png
运行机器学习项目:需要知道的事情
原文:https://towardsdatascience.com/running-machine-learning-projects-things-to-know-316775338eab?source=collection_archive---------22-----------------------
行业笔记
机器学习和数据科学项目的生命周期
根据我的经验,ML 项目有各种各样的形状和大小,并且在复杂性上有很大的不同。在最初的 2000/10 年,重点是以模型为中心的方法,我总是觉得有点奇怪,因为我听到无数次关于更好的模型而不是结果(嗯,这是一个不同的时代,人们习惯于在听到 ML、AI、DS 等时感到敬畏);慢慢地,焦点逐渐转移到以结果为中心的方法上,也就是说,使用你能使用的任何模型,但是要利用数据并产生有方向性的、适用的和一致的结果。
尽管重心转移,该领域的知识水平不断提高,但 ML 方面的努力往往以失败告终。没有成功的蓝图,但有一些步骤可以确保你走在正确的方向上。
下面的文章只不过是我过去 10 年在埃森哲、Evalueserve、BCG、Intent HQ 和 Quantplex 领导 ML 团队并解决一些有趣问题的经历的一个简要要点。

图片来源: Unsplash
先决条件
- 在你迈出这一步之前,你应该清楚你试图解决的问题陈述是什么,解决方案的界限是什么,即什么可以解决,什么不能解决,什么数据可用,你将与什么团队打交道,你的工作时间表是什么。
- 一个好主意是在会议室坐 2 个小时,在白板上列出所有内容,尝试向您的团队成员解释问题陈述(此外,与客户的 SOW/合同应该包含所有信息,否则会造成很大的麻烦,至少问题陈述、解决问题所需的时间以及财务状况应该在合同中有所体现)。请你的团队列出 100%解决问题所需的所有数据和因素(在理想情况下),然后找出你有哪些数据和信息来解决问题。是否足以解决问题?你能进行二次调查以补充数据来源吗?你能向客户询问相关信息吗?
- 你能把问题陈述模块化,并对模块进行优先排序,首先处理最重要的模块吗?你能使用帕累托原则吗,即什么样的模块可以解决 80%的问题?
- 根据团队规模和时间表,花 2-4 天时间研究重要模块的可能解决方案。阅读研究论文或寻找对他人有效的解决方案。在你使用的任何平台上保持一些沟通渠道 Slack,teams 等,请保持无意识的聊天一分钟(为这种恶作剧保持一个单独的渠道)。
- 你团队中的每个人都应该清楚正在解决的问题,以及可能的解决方法。选择一个简单且能产生最大影响的方法。
从头算
- 你知道项目的目标,你能量化它吗?如果你正在处理多个目标,那么你能根据重要性将它们堆叠起来吗?
- 验收标准或成功标准是什么?(为此,你必须与客户或利益相关者合作,这是一项咨询工作)。
- 您能定义用于衡量项目目标/成功的指标吗?就像正指标一样,你应该创造一个负指标,你的结果应该同时满足正指标和负指标,例如,在设计推荐系统时,正指标可以是你推荐的购买产品的百分比,负指标可以是你没有推荐给用户的购买产品的百分比。这里负指标的百分比应该很小。
- 您在上述步骤中定义的指标应该与现实世界相关,而不仅仅是满足数据团队的欲望。是的,模型应该具有统计显著性结果,您应该使用 R、似然性、对数似然性、敏感性、特异性、混淆矩阵变量、准确性、MAPE、MSE 等,但只能用于评估模型的性能,而不能用于向有业务利益相关者和非技术人员的受众传达结果。确保你使用的东西对他们的世界有意义。如果你找不到其他任何东西,就创建更有现实内涵的代理指标。
- 你会做什么来不让你的模型误入歧途,并继承世界的偏见,如种族,文化,亚文化,性别,年龄,地理等)?你能给你的微观世界带来平衡吗?
下文
基础架构往往被搁置一旁,被忽视,成为一个瓶颈。如果您的机器无法运行繁重的解决方案,那么就寻找替代方案或基于云的解决方案。
- 您的团队或您是否可以访问以不同于您的模型可能需要的格式存储的数据?很多时候,数据馈送被推送到 HDFS 生态系统中的 S3 桶,用户必须运行 apache spark 查询来访问相关的片。不要给你的团队配备过多的数据科学家,确保你也有数据工程师,他们是紧急情况下上帝派来的,让你的团队多才多艺。
- 你的产品在现实生活中不会是一个 jupyter 内核,它将是一组文件,这些文件将通过一个 cron 作业通过一个调度程序运行,该作业将结果发布在一个仪表板上或将结果推送到另一个 S3 桶中。如果你认为所有这些都是胡言乱语,那么确保你有可以帮助你的人(工程师)。ML 项目通常不是个人的追求,需要广泛的技能才能成功。
- 后端基础架构设计将限制您可以开发的模型和支持的输出,以及您刷新模型和更新结果的频率。在团队开始开发一个结果无法使用的笨重复杂的模型之前,应该先弄清楚后端基础设施。
数据
- 您已经有了数据,但是您需要进行数据完整性检查。它将检查提供给你的数据的完整性。
- 数据有多新鲜,使用它有意义吗?它能捕捉到你希望用模型捕捉到的情感吗?
- 刷新率是多少?多久会变味?它符合 GDPR 标准吗?它有固有的偏见吗?
- 为数据中的所有要素准备一个术语表和定义。数据的来源是什么?是否依赖于上游数据?如果是,那么刷新率是多少?SLA 是什么?是谁定义的?
- 最重要的部分之一是你有你想要的格式的信息吗?最常见的是 int 类型转换为 object,DateTime 对象转换为 strings。您需要对这些特性进行预处理,以减少后期的痛苦。
基线狼
我假设你已经进行了一次令人满意的探索性数据分析,不要花费数周时间试图对每一个可能的特性进行各种统计测试;在重要的事情上运用你的常识。异常值分析是一项重要的任务。当您拥有增量模型,并且正在评估模型的性能并试图证明某些错误分类时,离群点分析会有所帮助。
重要的是要确定一个你在未来几天要努力超越的底线。
- 花一周时间想出一个基线模型,最好是不太复杂的东西,只是使用基于语义的方法来解决问题,而不是涉及任何机器学习。基线模型还将帮助您测试模型的健全性,并测试一些简单的情况,例如,如果您正在设计一个贷款审批系统,信用评分低于 400 的每个人都应该被标记出来。这种简单的初始设计有助于您从一开始就测试严格性。
- 确保基线模型能够产生与您在上面的步骤中定义的相同的指标。记录下你离目标有多远,以及你需要做些什么来一点点接近你定义的成功标准或目标。
- 尽快部署/发布您的第一批模型,以便进行一些准备工作,并测试端到端系统。拥有 Streamlit/Heroku 技能是一件好事,这样你就可以向更多的观众展示间歇甚至最终的结果。
增量备份
一旦你有了一个基线集,你需要通过各种特征工程、数据建模努力来改进系统。
- 您的后续迭代应该是增量的,使用您的经验、客户和业务人员的输入,以及您从二次研究中收集的信息来衡量增量模型中应该使用什么信号和特性。构建您的模型,并尝试超越基线。
- 确保你的取样方法没有偏差。他们不应该在你的增量模型的结果中带来偏见,并弄脏图片。
- 总是回到基础,看看你是否能在模型的可解释性和复杂性之间找到平衡。如果你的模型越来越复杂,那么你会在解释上失败。主成分分析是一种很好的降维方法,也是一种很好的可视化数据的方式,但尝试向 100 个人解释它,你会得到冷眼旁观。
- 假设您创建了一些复杂的特征或选择了一个神经网络的隐藏层,并在您的模型中使用它,基本上这样做是可以的,但这些特征通常是非凸的,这意味着您的模型的内部优化引擎将很难收敛,因此您很可能会陷入局部最大值或最小值,因此每次运行的结果可能会有所不同。如果您正在使用这样的特性,那么在引入它们之后测试系统的健壮性。
- 借助你创造的积极和消极的度量标准,不断检查你的增量模型做得如何。
大脑和机器——最后一英里
ML 模型不会孤立地工作(至少在它们通过图灵测试和我们得到 AGI 之前),所以人类方面暂时是最重要的。
- 制定一个体面的策略,在数据失败时帮助你,例如,你如何对那些在贷款审批系统中没有信用评分的用户进行分类,或者在后端系统出现故障时,你会给出什么建议。
- 你的模型会有目标函数和损失函数。如果你认为有一个令人毛骨悚然的特征是一个麻烦制造者,那么把它推进损失函数。那是它的归属。
- 你能对你的产品/系统进行用户试用吗?如果是,那么接受这个结果,因为你和你的团队已经很好地融入了 ML 的世界,并且理解了系统的本质,但是最终用户可能会有不同的想法。你知道西红柿是一种水果,但最终用户认为它是一种蔬菜,那就这样吧。不要固执地改变世界的看法。
- 根据你制定的标准来衡量你的系统的表现。你的系统离他们太远了吗?是否需要重新定义指标?
- 通常被掩盖的一个重要因素是模型更新和模型老化。刷新模型将是一项艰巨的任务吗?它会像皮诺葡萄酿造的葡萄酒一样老化吗?还是会像一个摔倒在楼梯上的稻草人一样无法控制?
更大的计划
在机器学习项目的整个生命周期中,你需要不断地问一些问题。
- 系统或产品是随着时间变好还是停滞不前?
- 你能做些什么来简化系统,降低复杂性吗?
- 你有信心回答你开始要回答的问题吗?
端到端咨询
- 从结果中抽取一部分进行 A/B 测试总是一个好主意;关注你(或企业)认为相关的用户群、地理位置、产品。不要运行测试太长时间,因为 A/B 测试运行起来很昂贵;这就是为什么你应该仔细选择你的项目/产品会产生影响的群体。如果结果没有开始向有利于你的方向倾斜,这可能意味着很多事情——不要突然下结论。寻找线索。完全有可能这个模型很糟糕,但也有可能它从来没有到达它应该到达的最终用户那里。
根据最终用户的结果,看看你是否能吸收反馈并改进模型。
收场白
我故意没有涉及一些部分,例如选择工具集、IDE 等,还有一些部分我可能没有意识到。因此,如果你碰巧看到这篇文章,请提供你的想法,以及你如何组织你的 ML 团队和项目。
享受:)
使用 Slurm 和 Pytorch Lightning 运行多个 GPU ImageNet 实验
原文:https://towardsdatascience.com/running-multiple-gpu-imagenet-experiments-using-slurm-with-pytorch-lightning-ac90f3db5cf9?source=collection_archive---------21-----------------------

照片由 imgix 在 Unsplash 上拍摄
理解大数据
从 MNIST 和 CIFAR 的沙坑梦幻世界毕业后,是时候转向 ImageNet 实验了。也许你也站在那里盯着那百万以上的数据集,问自己应该从哪个方向接近这头野兽。在这里,我将给出我采取的一步一步的方法,希望它能帮助你与怪物搏斗。
首先,警告:
不要低估运行 ImageNet 实验所需的计算: 经常需要多个 GPU 每个实验需要几个小时。
如果你正在读这一行,那么你已经决定你有足够的计算和耐心继续,让我们看看我们需要采取的核心步骤。我的方法在使用 SLURM(我的大学集群)、Pytorch 和 Lightning 的计算集群上使用多个 GPU。本教程假设一个基本的能力,导航他们所有的❤
关键步骤
1.在 Lightning 中设置 DDP
2.访问 ImageNet 数据集
3.Bash 脚本指令 Slurm
在 Lightning 中设置 DDP
等等,DDP 是什么?
问得好,DDP 代表分布式数据并行,是一种允许不同 GPU 和集群中不同节点之间进行通信的方法。有很多方法可以做到这一点,但是我们只讨论 DDP,因为它是推荐的,并且是用 Lightning 实现的。
DDP 在每个可用的 GPU 上训练模型的副本,并为每个 GPU 将一个小批量分成独占的片。向前传球非常简单。每个 GPU 在其子小批量上进行预测,并且预测被合并。简单。

DDP 的前传。小批量与相同的模型参数一起在每个 GPU 之间平均分配。然后,每个 GPU 计算正向传递,并汇总输出预测
向后传球有点棘手。DDP 的非分布式版本(叫做,你猜对了,DP)要求你有一个“主节点”,它收集所有的输出,计算梯度,然后将这个传递给所有的模型。
但是,DDP 对中央集权的官僚体制说不。相反,每个 GPU 负责将模型权重梯度(使用其子小批量计算)发送到其他每个 GPU。收到完整的梯度集后,每个 GPU 都会汇总结果。结果如何?每个 GPU 上的每个模型副本都有相同的更新。这种操作的名称是全归约操作。

用于更新每个 GPU 上的模型的 all-reduce 操作。所有的 GPU 都向所有其他的 GPU 发送它们自己的梯度(记住它们是在一个子小批量上训练的),然后它们各自聚合。
好吧,告诉我闪电帮我设置了这个?
是的,确实如此。我假设你有一点闪电经验的读者,所以将只专注于关键的事情去做:
同步记录
就像确保梯度更新是相同的一样,您还需要更新您必须考虑到通信需求的任何度量记录。如果不这样做,您的准确性将取决于 GPU,仅基于 GPU 看到的数据子集。
为多个 GPU 进行转换非常简单。只需在所有日志中添加“sync_dist = True”即可。
设置 GPU 设备和 DDP 后端
现在我们需要更新我们的训练器,以匹配我们正在使用的 GPU 数量。或者,您可以让 Lightning 计算出您有多少个 GPU,并将 GPU 的数量设置为-1。
如前所述,我使用 DDP 作为我的分布式后端,因此设置我的加速器。这里没什么可做的>>
trainer = Trainer(gpus=-1, accelerator='ddp')
这就是 Python 代码。根据您设置模型的方式,您可能还需要删除任何。到()或。cuda()调用——这会导致问题。
如果遇到什么困难:https://py torch-lightning . readthedocs . io/en/stable/advanced/multi _ GPU . html
ImageNet
闪电代码准备好了,是时候抓 ImageNet 了。通过 torchvision 下载数据集不再像以前那么简单。相反,我将给出我发现有效的两个选项
长版
http://image-net.org/download
点击上面的并请求访问。这可能需要几天时间才能被批准用于非商业用途。
短版
https://www.kaggle.com/c/imagenet-object-localization-challenge/data
转到 Kaggle,加入 comp 并使用下面的 bash 命令下载数据。
kaggle competitions download -c imagenet-object-localization-challenge
在这两种情况下,当下载到您的集群实例时,您可能希望下载到 scratch 而不是您的主文件空间,因为,嗯,ImageNet 是一头野兽,很快就会超出最大的存储空间。
创建您的 lightning 数据模块
您可以像连接其他模块一样连接该数据模块,这样培训就可以按照以下方式进行:
data = ImageNet_Module()
model = YourModel()
trainer = Trainer(gpus=-1, accelerator='ddp', max_epochs=90)
trainer.fit(model, data)
trainer.test()
当然,您会希望将它放入一个漂亮的 Python 文件中,其中包含您希望 bash 脚本调用的所有铃声、哨声和定制模型。好了,我想我们已经准备好了最后一块胶水,SLURM 脚本。
SLURM 脚本
至此,所有艰难的工作都完成了。下面我将给出我在我的大学集群上运行的示例脚本作为示例:
当然,你会受到分配的资源和限制的约束,但这应该有助于给你一个基本的轮廓来开始。要使用这个大纲,您需要设置 conda 环境,并在集群上安装所需的库。
这是所有的乡亲
好了,就这样了。
如果一切按计划进行,你现在应该在训练过程中。
对于我的设置,一个使用 4x RTX 8000 的现成 ResNet18 模型每个时期大约需要 30 分钟,批量大小为 128。
这是一个 n=1 的例子,说明如何使用 SLURM 和 Lightning 进行 ImageNet 实验,所以我确信在资源、库和版本略有不同的情况下会出现障碍和问题,但希望这将有助于您开始驯服野兽。
感谢您阅读❤
使用的工具
- Pytorch (1.7)
- Pytorch 闪电(1.2)
- SLURM 管理器(Uni 计算集群)
- 4 辆原始的夸德罗 RTX 8000
在 AWS EC2 上运行 MySQL 数据库——初学者教程
原文:https://towardsdatascience.com/running-mysql-databases-on-aws-ec2-a-tutorial-for-beginners-4301faa0c247?source=collection_archive---------2-----------------------
数据科学
远程运行和管理 MySQL 数据库

图片由作者提供(使用 Canva)。
在本地计算机上运行数据库很容易,有时在开发阶段就足够了。但是,部署大多数应用程序需要在远程服务器上运行数据库。远程部署数据库的解决方案有成千上万种。本文向您展示了如何在 AWS EC2 服务上创建一个简单的数据库并远程管理它。
本文是为没有云数据库部署经验的初学者编写的。此外,如上所述,有许多基于云和非基于云的解决方案来部署数据库。例如,AWS 有一个名为 AWS RDS 的专用服务,用于在云上部署数据库。我们将在以后讨论其中的一些解决方案,并对它们进行比较。今天,让我们在 AWS EC2 实例上部署一个 MySQL 数据库。
步骤 A:启动一个 AWS EC2 实例。
首先,我们需要一个 AWS 帐户。您可以在几分钟内免费设置一个 AWS 帐户。
https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc
本文更详细地解释了这些步骤。
https://dan852.medium.com/how-to-create-an-amazon-aws-free-tier-account-e4cc099a8e94
创建您的免费 AWS 帐户并登录后,单击服务(在 AWS 徽标旁边),并从列表中选择“EC2”(即代表亚马逊弹性计算云,这是一种对云计算机的花哨说法)。

从加载的页面/仪表板中,选择“启动实例”

AWS 向您展示了启动 EC2 实例必须遵循的 7 个步骤。

步骤 A1:选择一个 Amazon 机器映像(AMI)
首先,让我们为我们的项目选择一个操作系统。为此,最好的免费选择是 Ubuntu Server 20.04,它符合免费层的条件。

步骤 A2:选择实例类型
我们不需要大型机器来测试这个想法。让我们使用一个简单但免费的选项,如 t2.micro。如果我们愿意,以后可以升级它。

单击“下一步”配置实例详细信息
步骤 A3:配置实例详细信息
这是至关重要的一步,但是对于这个演示来说,这里没有什么需要真正改变的。你把它压碎了!!!
步骤 A4:添加存储
在这里,您必须设置您的存储大小。要获得免费层定价资格,请选择 8GB(默认值)。当处理更大的数据库时,您可能需要增加它(当然,您必须为此付费)。

步骤 A5:添加标签
你也可以忽略这部分,直接跳到下一步。
另外,为了将来,请看一下这个链接,了解 AWS 标记的最佳实践。
步骤 A6:配置安全组
在这一步,我们应该配置 EC2 实例上的哪些端口应该向外界公开(包括您和您的本地计算机)。目前,我们只开放端口 22,用于通过 SSH(一种通过互联网或网络在计算机之间进行交互和数据传输的安全协议)连接到我们的系统。您可以根据需要打开不同的端口,如 HTTP 或许多其他端口。出于演示的目的,我们只需要打开 SSH 端口(即 22)。
警告:对于这个演示,您不需要打开 MySQL 端口(默认为 3306)来与 MySQL 数据库进行交互。在没有适当的认证和安全措施的情况下对外开放这个端口是非常危险的。稍后我将向您展示如何通过更安全的连接与您的数据库进行通信。

步骤 A7:检查实例启动
仔细检查一切,然后点击启动按钮。一秒钟后,会弹出一个窗口,要求您选择一对密钥。密钥对使您能够通过互联网安全地连接到 EC2 系统。密钥是一个.pem文件,您必须将它存储在一个安全的地方。
警告:任何有权访问此文件的人都可以连接到您的 EC2 机器并使用它。
你有两个选择。首先,如果您已经有一个密钥对,您可以使用现有的密钥。第二种选择是选择一个新的密钥对。在这里,我为这个演示生成一个新的密钥对。我给它一个名字,并在一个安全的文件夹中“下载密钥对”。

您的新 EC2 实例需要几秒钟(有时几分钟)就可以使用了。要检查 EC2 实例的状态,请单击 Services(也在 AWS 徽标旁边)> > > EC2 >>> Instances。
您将看到您的实例列表(或者一个实例,如果它是您的第一个实例)。确保您的实例已准备好(见下图)。

警告:请记住在您完成测试后停止或终止您的实例(除非您决定保留它)。一个正在运行的实例在试用期内可能是免费的,但是如果您忘记停止或终止它,您将在试用期后收到来自 AWS 的账单。
步骤 A8:连接到 EC2 实例
如果您的 EC2 系统正在运行,现在您可以选择您的实例,并从顶部菜单中选择 Actions >>> Connect。

从打开的页面中选择“SSH client ”,您应该会看到关于如何连接到您的实例的完整说明。在这里,我遵循同样的指示。
基本上,您需要一个名为 SSH Client 的工具来安全地连接到 EC2 机器。如果你的系统安装了 Linux、Mac 或 Windows 10(或更高版本),你必须安装“SSH 客户端”并准备好运行。一些 Windows 用户应该在开始使用 SSH 客户端之前在他们的计算机上启用/安装它。这里有一个链接展示了如何做。
打开终端并转到包含 AWS 密钥文件的文件夹(。pem 文件)。对我来说,我将我的密钥文件(my_test_key.pem)保存在一个名为test_mysql_aws的文件夹中。
cd test_mysql_aws
chmod 400 my_test_key.pem
ssh -i “my_test_key.pem” ubuntu@ec2SSSSSS214.us-east-2.compute.amazonaws.com
同样,当您在 EC2 仪表板中单击 Connect 时,您可以找到完整的说明。
步骤 B:在 AWS EC2 实例上安装 MySQL。
如果您成功地构建并连接到 EC2 实例,那么是时候在您的实例上安装 MySQL 服务器了。我的首选方法是使用 APT 包库管理工具。
sudo apt updatesudo apt install mysql-server
安装完成后,MySQL 服务器应该会自动运行。您可以使用下面的命令来检查它。
sudo systemctl status mysql
它必须返回一些关于 MySQL 服务器的信息,比如Active: active (running)。让我们以 root 用户身份登录。
sudo mysql
您现在必须为您的 root 用户设置密码。用强密码替换your_password_here。
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password_here';mysql> FLUSH PRIVILEGES;
现在,让我们退出并使用 root 凭据登录。
mysql> exit$ sudo mysql -u root -p
输入您的 root 密码,希望您能回到 MySQL 命令行。
步骤 C:创建一个虚拟数据库
虽然这不是本节所必需的,但是我假设您熟悉 SQL 命令。如果您不熟悉 SQL,我强烈推荐您学习这三门课程,但是您现在可以继续学习。
课程一:https://academy.vertabelo.com/course/sql-queries
课程二:https://academy . vert abelo . com/course/SQL-insert-update-delete
课程三:https://academy.vertabelo.com/course/creating-tables-in-sql
首先,让我们在数据库中创建一个虚拟数据库(mysql_test)和一个虚拟表(test_table1)。
CREATE DATABASE mysql_test;USE mysql_test;CREATE TABLE test_table1 (id INT, name VARCHAR(45));
让我们也在数据库中插入一些虚拟数据。
INSERT INTO test_table1 VALUES(1, 'Joe'), (2, 'Jane'), (3, 'Jack'), (4, 'Jessica');
最后,让我们显示表中的所有数据,以确保没有出错。
SELECT * FROM test_table1;
在您的 MySQL 应用程序中,您一定会看到如下所示的小表。
+------+---------+
| id | name |
+------+---------+
| 1 | Joe |
| 2 | Jane |
| 3 | Jack |
| 4 | Jessica |
+------+---------+
4 rows in set (0.00 sec)
步骤 D:安装 MySQL Workbench 以简化管理
MySQL Workbench 是一个可视化的数据库管理工具。它帮助您在短时间内完成复杂的数据库管理任务,而不牺牲任何灵活性。我们可以在本地计算机上安装这个应用程序,并管理任何本地或远程数据库。
让我们使用这个强大的工具来访问和管理我们刚刚构建的 AWS EC2 实例上的 MySQL 数据库。你可以从这里下载并安装该应用。安装简单明了,只需点击几下鼠标。这个链接也可以帮你完成安装。
记住:对于这个演示,我们将 MySQL Workbench 安装在本地计算机上,而不是 EC2 实例上。
在本地系统上安装 MySQL Workbench 后,您应该会看到如下图所示的第一个页面。

图片由作者提供。
点击 MySQL 连接旁边的+。

图片由作者提供。
给你的连接起一个任意的名字(例如AWS SQL test)。从连接方法下拉菜单中,选择“SSH 上的标准 TCP/IP”SSH 主机名是您的 EC2 实例公共 IPv4 DNS 地址。您可以在 EC2 仪表板上找到这个地址,方法是单击您的实例并从选项卡菜单中选择 details。
此外,将 SSH 用户名改为ubuntu并找到您的 SSH 密钥文件(即。pem 文件,以便通过 SSH 进行连接)。最后,确保你的用户名是root。单击 OK,您的连接应该出现在第一页上。

点击新的连接,它会询问你的 MySQL 根密码。输入密码后,您可以在 Schema 选项卡下看到您的数据库和表(参见下图)。

在查询区域,您可以编写和运行 SQL 命令。键入以下命令,突出显示它们,然后单击 Execute 按钮(如下图中的红色箭头所示)。
USE mysql_test;SELECT * FROM test_table1;

如您所见,它显示了 AWS EC2 上的mysql_test表的内容。MySQL Workbench 可以帮助您方便安全地管理 AWS 上的数据库(通过 SSH 隧道)。
摘要
在本文中,您将开始在 AWS EC2 实例上部署 MySQL 数据库。您将学习如何设置 EC2 实例,连接到它,安装 MySQL Server,配置您的服务器,创建一些数据库和表,最后用 MySQL Workbench 管理它们。
在 Kubernetes 上运行 Spark:方法和工作流程
原文:https://towardsdatascience.com/running-spark-on-kubernetes-approaches-and-workflow-75f0485a4333?source=collection_archive---------10-----------------------
在 Kubernetes 上为开发、数据探索和生产运行 Spark 作业的最佳方式

拉扎勒斯库·亚历山德拉在 Unsplash 上的照片
在从事 Apache Spark 应用程序工作的这些年里,我一直在开发和生产环境之间切换。我会使用 Visual Studio 代码之类的 IDE 来编写 Scala 或 PySpark 代码,针对一小部分数据进行本地测试,将 Spark 作业提交给 Hadoop YARN 以在生产中运行,希望它只适用于真正的大数据。我会花大量时间处理本地和生产环境的 Spark 依赖关系,并确保它们同步。对于机器学习应用程序来说,这个工作流变得更加痛苦,因为需要 PySpark、Python 库和 Jupyter notebook 环境的组合。即使对于拥有许多工程师的企业来说,为 Spark 应用程序开发、数据探索和生产运行建立和维护环境仍然是一项挑战。
在 Kubernetes 上输入 Spark。有了 Kubernetes 上的 Spark,以及理想情况下像 FlashBlade S3 这样的快速对象存储,我们可以使用单一环境轻松运行所有这些不同的 Spark 任务。
- 由多个 Spark pods 支持的 Jupyter 笔记本电脑,可用于小型和大型数据的快速原型制作和数据探索。
- 在 yaml 文件中声明一个 Spark 应用程序,并提交它以在生产中运行。
- Apache Airflow 来协调和调度具有多个作业的管道。
与以前的工作流程相比,这个新的工作流程更令人愉快。我的所有任务都利用相同的 Kubernetes 环境。在容器映像中管理依赖关系,以便它们在开发和生产中保持一致。性能问题可以在开发阶段检测出来,因为大规模测试变得更加容易。最重要的是,不再需要管理 Hadoop 集群。
我在之前的博客中解释了如何设置 Spark 在 Kubernetes 上运行并访问 S3。这一次,我将描述我在 Kubernetes 上运行 Spark 进行开发、数据探索和生产的新工作流。
超级充电 Jupyter 笔记本,带 Kubernetes 上的 PySpark
Jupyter Notebook 对于快速原型开发和数据探索非常方便,因为开发人员和数据科学家可以在其基于 web 的交互式开发环境中直接开始编码。然而,由于它运行在单个 Python 内核中,处理大数据可能会很慢。另一方面,PySpark 允许我们用 Python 编写 Spark 代码并在 Spark 集群中运行,但它与 Jupyter 的集成并不存在,直到最近的 Spark 3.1 版本,它允许 Spark 作业在 Kubernetes 集群中本地运行。这使得从 Jupyter 笔记本电脑处理大数据成为可能。
通过几行代码配置,我们现在可以在 Jupyter 笔记本中编写 PySpark 代码,提交代码在 Kubernetes 集群中作为 Spark 作业运行。

在 Jupyter 的 Kubernetes 会议上发起火花
在示例笔记本 blow 中,我的 PySpark 代码从存储在 FlashBlade S3 的 CSV 文件中读取了 112M 条记录,然后执行了一些功能工程任务。由于记录数量巨大,如果在单个进程上运行,这可能会非常慢。

将 1.12 亿张 S3 唱片读入 PySpark

PySpark 中的特征工程
然而,在这种情况下,在后端,繁重的处理由 Kubernetes 中运行的 Spark 作业来处理。下面是笔记本推出的 Kubernetes 中的 Spark pods。

Jupyter 笔记本推出的 Kubernetes 中的 Spark pods
因为后端是完全分布式的 Spark 作业,所以速度很快。我们现在可以从浏览器处理和浏览 Juypyter 笔记本中的大量记录。
简化生产中的 Spark 提交
工作流程的下一步是将 Spark 代码提交给生产部门。曾经讨论过是否应该将笔记本视为生产代码。一些公司如网飞已经在做这个 T2,但是我认为大多数公司还没有做到。在我的工作流程中,我会将笔记本代码复制并提炼为一个 Python 文件,将其放在 S3,在 yaml 文件中声明一个 PySpark 作业,并使用 Spark on k8s 操作符将其提交给 Kubernetes。你可以在我的以前的博客中找到细节。
在 Spark 3.x 中,向 Kubernetes 提交 Spark 作业有两种方法:
- 使用传统的 spark 提交脚本
- 在 k8s 操作器上使用 Spark
我选择在 k8s 上使用 Spark 操作符,因为它是 Kubernetes 的原生操作符,因此可以从任何有 Kubernetes 客户端的地方提交。使用这种方法,提交 Spark 作业是一个标准的 Kubernetes 命令:kubectl apply -f nyc-taxi.yaml。这有助于简化 Spark 提交。它也更加灵活,因为在节点上不需要 Spark 客户机。
你可能已经注意到了,这与我在上面部分中从 Jupyter 在 Kubernetes 会话上启动 Spark 的方式不同,在那里使用了传统的 spark-submit。这是真的,因为我想让 Spark 驱动程序运行在 Jupyter 内核中进行交互式开发。而在生产中,我们需要再现性、灵活性和便携性。
协调和安排管道
虽然在 k8s 上的 Spark operator 很适合提交一个 Spark 作业在 Kubernetes 上运行,但我们经常希望将多个 Spark 和其他类型的作业链接到一个管道中,并安排管道定期运行。对此,Apache Airflow 是一个流行的解决方案。
Apache Airflow 是一个以编程方式创作、调度和监控工作流的开源平台。它可以在 Kubernetes 上运行。它还可以与 Kubernetes 很好地集成。我将跳过如何在 Kubernetes 上运行 Airflow 的细节,以及从 Airflow 如何编排 Spark 作业在 Kubernetes 上运行。现在,让我们关注它带来的行为和价值。
在示例 blow 中,我定义了一个简单的管道(在 Airflow 中称为 DAG ),其中包含两个顺序执行的任务。第一个任务使用 Spark on k8s 操作符向 Kubernetes 提交一个名为 nyc-taxi 的 Spark 作业,第二个任务检查在第一个状态中提交的 Spark 作业的最终状态。我还将 DAG 设置为每天运行。

气流中定义的简单管道
在 Airflow UI 上,DAG 看起来是这样的:

气流界面上的纽约市出租车分析 DAG
运行时,DAG 中的第一个任务将在 Kubernetes 上通过 Spark on k8s 操作符启动多个 Spark pods,如nyc-taxi.yaml文件中所定义的,就像kubectl apply命令一样。

火花舱被气流旋转起来
Airflow 有助于管理多任务工作流的依赖性和计划。因为它重用作业并在相同的 Kubernetes 环境中运行,所以引入气流的开销是最小的。
结论
有了 Kubernetes 上的 Spark 和用于数据的外部 S3 对象存储,我的数据工程过程大大简化了。我会打开浏览器,开始快速原型制作和数据探索。感谢 Kubernetes 上 Spark 的强大功能,我不必将我的原型开发和探索局限于一小组样本数据。一旦我熟悉了原型,我就把代码放到 Python 文件中,用一个 Kubenetes 命令修改并提交它,以便在生产中运行。对于复杂的管道,我会用气流来编排作业,以帮助管理依赖性和调度。
这是我的数据工程工作流程。我喜欢我只需要一个单一的环境来实现所有这些。
对 SQL 数据大规模运行时间序列异常检测
原文:https://towardsdatascience.com/running-timeseries-anomaly-detection-at-scale-on-sql-data-4407eb3d3bd3?source=collection_archive---------12-----------------------
多维数据、SQL、熊猫和先知

从展开的插图
时间可能是衡量标准最重要的维度。
在商业世界中,业务主管、分析师和产品经理会随着时间的推移跟踪指标。
在创业领域,风投希望指标周环比增长 5%。
在公开股票市场,长期投资者按季度评估指标,以做出买入/卖出决定。短线交易者以小得多的时间粒度——几分钟或几小时——监控股价,以做出同样的决定。
在系统监控领域,团队以秒或分钟为基础跟踪指标。
在数据科学领域,时间序列分析是工作的重要组成部分。
尽管时间可能是数据中最重要的维度,但数据确实有许多其他维度。这些维度具有不同的基数。一些高基数维度可能有数千个唯一的维度值。
手动监控数千个维度值及其组合的指标几乎是不可能的。这就是时间序列分析,尤其是时间序列异常检测派上用场的地方。
对业务数据运行异常检测的挑战
- 大多数业务数据都在 SQL 数据库中
时间序列分析需要时间序列数据作为输入。但是大多数业务数据是表格形式的,存放在关系数据仓库和数据库中。分析师通常使用 SQL 来查询这些数据库。我们如何使用 SQL 来生成时间序列数据?
2。如何按维度拆分指标?
一些尺寸可以有数千个唯一的尺寸值。对所有维度值运行异常检测将是昂贵且嘈杂的。我们如何只为我们的分析选择重要的维度值?
3。大规模异常检测成本高昂
假设你为一家在线零售商工作。你的商店销售 1000 种产品。您希望对这 1000 种产品中的每一种产品的每日订单运行异常检测。这意味着:
指标数= 1(订单)
维值数= 1000 (1000 件产品)
指标组合数= 1000 (1 个指标 1000 个维值)*
这意味着异常检测过程每天必须运行 1000 次,每个指标组合一次。
假设您想要通过另一个维度—州(50 个唯一值)来监控订单。您还希望通过这两个维度的组合来监控指标。这意味着异常检测过程现在每天必须运行 51,050 次。
51,050 = (1 个指标 1000 个产品)+ (1 个指标* 50 个州)+ (1 个指标* 1000 个产品* 50 个州)*
为了了解基础设施的定价,我们来看看 AWS 异常检测服务的定价。AWS 将向您收取每月 638 美元的费用,用于每天跟踪 51K 个指标组合。
这就是你运行异常检测程序所要支付的费用。在流程每次运行之前,您需要运行一个查询来从数据仓库中提取数据。51K 指标组合意味着每天对您的数据仓库进行 51K 次查询,这是额外的成本。
这还只是云基础设施的成本。
4。大规模异常检测有噪音
这 51K 个度量组合中的每一个都有可能成为异常。即使这些组合中有 0.1%被证明是异常,对于一个指标,您每天都会看到 51 个异常。
您或您的团队每天有足够的带宽对如此多的异常情况采取行动吗?大概不会。
如果你不对这些异常采取行动,这些异常不会增加任何商业价值。相反,它们只会增加你的成本。
5。当检测到异常时,如何深入挖掘并进行根本原因分析?
假设您有以下异常情况:
昨天状态= CA** 的订单**减少了 15%
这可能会引发如下问题:
- 该州所有城市的订单都减少了吗?如果不是,是哪些城市?
- 所有产品的订单减少了,还是特定的几个产品的订单减少了?
怎样才能快速回答这些问题?
面对这些挑战,我们开始构建cue observe。下面是我们如何解决这些问题。
1.创建虚拟数据集
数据集类似于数据的聚合 SQL 视图。我们使用聚合函数编写 SQL GROUP BY query 来汇总数据,将其列映射为维度和指标,并将其保存为虚拟数据集。
以下是 BigQuery 的 GROUP BY 查询示例:
2.定义异常
我们现在可以在数据集上定义一个或多个异常检测作业。异常检测作业可以在聚合级别监控指标,也可以按维度拆分指标。
当我们按维度分割指标时,我们限制了唯一维度值的数量。我们使用三种方法之一来限制:
- 前 N 名:基于尺寸值对度量的贡献的限制。
- 最小百分比贡献:基于尺寸值对度量贡献的限制。
- 最小平均值:基于指标平均值的限制。

作者图片
3.执行数据集 SQL
作为异常检测过程的第一步,我们执行数据集的 SQL 查询,并以 Pandas 数据帧的形式获取结果。该数据帧充当识别维度值和异常检测过程的源数据。
4.生成子数据帧
接下来,我们创建新的数据帧,实际的异常检测过程将在这些数据帧上运行。在此过程中,我们通过对维度进行过滤来查找维度值并创建子数据框架。需要创建子数据框的维度值由上述 3 个维度分割规则之一决定。例如,如果维拆分规则是 Top N,则内部方法会确定前 N 个维值并返回一个字典列表,每个字典都包含维值字符串、其百分比贡献和子数据框架。
提到的子数据帧只是在过滤了特定的维值并删除了除时间戳列和度量列之外的所有其他列之后的数据帧。
datasetDf[datasetDf[dimensionCol] == dimVal][[timestampCol, metricCol]]
5.聚集子数据帧
准备子数据帧的一个重要步骤是聚合时间戳,这可以在前面的代码片段中看到。
"df": aggregateDf(tempDf, timestampCol)
这种聚合包括在时间戳列上对过滤后的子数据帧进行分组,并在度量列上对其求和。我们还将时间戳列重命名为“ds ”,将指标列重命名为“y ”,因为 Prophet 要求 dataframe 列也这样命名。
6.生成时间序列预测
我们现在将时间序列数据帧输入到 Prophet 中。每个数据框架都在 Prophet 上单独训练,并生成预测。在聚集之后,每个数据帧必须具有至少 20 个数据点,因为少于 20 个数据点将是太少的训练数据,不能获得合理的好结果。关于数据帧的粒度,还需要考虑其他一些因素,如 Prophet 做出的预测数量以及训练数据间隔。对于每小时的粒度,我们只在最近 7 天的数据上训练 Prophet。
我们用预定的参数和区间宽度初始化 Prophet,以获得合理的宽置信区间。稍后,我们计划让这些设置也可以配置。在获得未来的置信区间和预测值后,我们将所有大于零的预测值裁剪掉,并从 Prophet 的输出中删除所有多余的列。
7.检测异常
接下来,我们将实际数据与 Prophet 的预测数据以及不确定性区间带结合起来。这些波段估计数据的趋势,并将用作确定数据点异常的阈值。对于原始数据帧中的每个数据点,我们检查它是否位于预测带内,并相应地将其分类为异常。
最后,我们将流程的所有单个结果与元数据一起存储在一种易于可视化表示的格式中。下面是一个异常可视化的例子。

作者图片
结论
为了对多维业务数据运行异常检测,我们通过查询编写一个 SQL 组,将其列映射为维度和度量,并将其保存为虚拟数据集。然后,我们在数据集上定义一个或多个异常检测作业。我们限制尺寸值的数量,以最大限度地减少噪音并降低基础设施成本。
当异常检测作业运行时,我们执行数据集 SQL 并将结果存储为 Pandas 数据帧。我们从数据帧中生成一个或多个时间序列。然后,我们使用 Prophet 为每个时间序列生成一个预测。最后,我们为每个时间序列创建一个可视卡片。
俄罗斯桥、欧拉回路和基因组组装?
原文:https://towardsdatascience.com/russian-bridges-eulerian-circuits-and-genome-assembly-9fd1d84832e9?source=collection_archive---------26-----------------------

这是我试图更好地解释数学、生物和计算机科学的交集。文章中用于理解的最严格的例子都在 Pavel Pevzner 和 Phillip Compeau 的书中,但是由我进行了格式化和扩展。
数学和生物学的交叉确实是一件值得思考的美好事情。当然,我们的 DNA 遵循的基本原则与世界上几乎所有的东西都一样是有道理的(数学),但是这些点以这样一种方式连接起来,使得一切都变得非常清楚。
当我继续在生物学和工程学的交叉领域工作的时候,像这样的想法几乎是我理解和欣赏生物学的核心,也是我为什么喜欢它的首要原因。
一个非常重要的例子是图论与一个关键过程的独特交叉,这个关键过程是生物学中每一个重大发现的先驱:基因组组装。
我写这篇文章的目的不仅是为了帮助你了解更多关于计算生物学的知识,也是为了解释为什么我认为每个人都应该为计算生物学而疯狂,并通过一个简单明了的例子来说明它的潜力。
好吧,我谈了很多关于数学和科学的诗意,但是技术层面呢?为什么理解图论和再造我们的基因组如此重要?
这一切都始于对人类基因组的整体理解。
我将让麻省理工学院的大卫·吉福德来解释为什么基因组组装是令人着迷的,因为他总结得很好。
“(基因组组装)是所有现代生物学的基石。在研究进化、观察基因结构方面,我们几乎所有的事情都依赖基因组参考……这真的是一个非常基本的概念。
基因组组装指的是组织 DNA 的子成分以获得可以描述整个生物体的遗传信息的表示的过程。
例如,人类基因组只是我们身体使用的每一个 DNA 序列的目录。把它想象成人类的字典。如果你上过高中生物课,你会知道人类有 23 对染色体(染色体是几个 DNA 分子的浓缩版本)。
当然,每条染色体都由一个与这些 DNA 分子结合的组蛋白骨架组成,当我们对每个基因组中每一个独特的 DNA 序列进行测序时,我们得到了一个非常长的序列字典,几乎有30 亿个碱基对长的 DNA。
持怀疑态度的科学家或工程师可能会看到这种情况,并说“30 亿个碱基对太长了。我们究竟如何一次读取这么多数据?”
你没有错。对 30 亿个碱基对进行测序不仅在计算上很困难,而且我们的技术仍然无法一次性对一个基因组进行测序,主要是因为提取超长序列带来的信息损失。
如果你还记得[人类基因组计划,](https://en.wikipedia.org/wiki/Human_Genome_Project#:~:text=The Human Genome Project (HGP,physical and a functional standpoint.)正是因为这个原因,绘制整个人类基因组的比赛非常艰难。
实验室中的生产挑战,如获得足够的样本、防止污染、获得实际序列的准确表示和绘制其功能图,都是我们正在慢慢克服的一些主要障碍(我们今年刚刚完成了整个基因组的测序)。
这些都是基因组组装中的基本问题。为了测序或读取你的基因组,你首先需要找到一种方法来获得你的基因组的较小代表,然后将它们放在一起启动测序。
现在,我们能够对“人类基因组”进行测序,是的,但是地球上的数十亿人和我们能够对其基因组进行测序的其他生物呢?如果我们能找到更好更准确的方法来组装我们的基因组,我们能对自己和周围的世界了解多少?
这是前提。为了首先对你的基因组进行测序和解释,你首先需要能够组装它。
我们如何最有效地组装生物体的基因组?
基本原理是,我们希望从几个 DNA 副本或重叠群中收集一组片段,这些片段包含中心但不相关的信息,然后将它们组合起来,以找到这些片段的正确顺序。
重叠群或连续序列通过鉴定特定重叠群之间重叠区域的支架进行组合。我们可以以阅读对的形式将某些重叠群重叠在一起。这可以被认为是一个单词的前缀和后缀,我们可以用它们来排列单词,使我们的字典按照字母排列。
另一种思考方式是,我们的序列中有一些缺口,因为我们最初可能丢失了一些读数。
如果你知道这些重叠群的最后部分和第一部分是什么,你可以用在它们各自的开始和结束处包含这两部分的重叠群来桥接它们。
在此之后,你可以使用许多不同的管道来排列和排序这些支架,例如序列标签位点,它可以帮助在实际的染色体中排序某些支架。最终,这些可以被推断和解释,以产生最终的基因组图谱或我们类比中的字典。
这个过程被称为 从头全基因组鸟枪组装 ,看似简单,实则不然。初始扩增或变性引起的突变或无序阅读等问题都使这一过程复杂化,更不用说让我们难以找到这些重叠群应该排列的确切顺序。
一些问题和关键障碍包括但不限于:
- 由于 DNA 是双链的,没有办法知道给定的读数来自哪条链,这意味着我们不知道对于特定方向(3 '或 5 ')的给定重建是使用读数还是其反向互补。
- 从左到右阅读基因组不是很有用,因为当你向序列中引入新的核苷酸时,大多数算法的复杂程度会增加。你不仅不确定你在寻找什么样的片段、模式或统计异常,而且随着长度的增加,缩小这个范围变得更加困难。
- 现代测序机器经常出现错误,这使得很难具体地“读取”完整的基因组。→测序错误使基因组组装变得复杂,因为它们通常会阻止我们识别重叠的读数
- 由于缺乏知识,基因组的一些区域可能没有被任何读数覆盖,使得不可能重建整个基因组。这些往往是我们自己理解中的盲点,而计算测序方法和基因组图谱可以帮助预防。

WG 鸟枪测序->我们从一组 DNA 拷贝中随机选择不同的重叠群。
这被称为从头组装,我们需要在没有任何先验知识或参考的情况下,从零开始组装一组读数。
一个快速的 迂回 : S/O 到麻省理工学院开放课件:我们可以根据我们所拥有的覆盖率,设计一个特定于基因组的算法。覆盖率是我们在所有读数中总共有多少核苷酸以及它们占整个基因组长度的百分比的另一个名称。

M =以核苷酸计的基因组大小| p = pair_end 长度| r = read 长度| Sgb =基因组大小
我们可以使用泊松分布来模拟碱基在我们的读数中是否被覆盖的概率,因为我们拥有的数据本质上是随机和独立的。 覆盖率 可以认为是分布的 or 均值,因此在这种情况下方差也等于覆盖率。请注意,覆盖率是相对于整个基因组而言的。

因此,如果我们试图找到一个基数未被覆盖的概率,它将构成图的一部分,直到平均值或(因此是 x 的阶乘!)因为我们在努力求每个概率的和。

泊松分布公式-> k 是给定指数下核苷酸的频率
这为什么有用?嗯,你可以用概率来找到关键的重叠点,尤其是你阅读中的重复部分。
恢复正常: TLDR: DNA 组装很重要,很有挑战性,但解决起来也很有趣。我只讨论了 DNA 组装,但是我们如何把它变成一个计算问题呢?
从随机字符串到方法的框架问题。
我们需要马上认识到我们的问题中的一些事情。首先,我们可以假设覆盖率几乎是完美的(这实际上是不现实的),但确实有助于在早期建立直觉。我们还知道这些读数大部分长度相同,这样可以很容易地帮助我们识别重叠。

长度为随机构型或 3 聚体-> 3 个核苷酸
鉴于我们对组装所述基因组的初始方法的了解,很明显,我们可以通过观察它们的重叠区域 (前缀和后缀)来建立顺序,从而组装这些配置。

我们知道 GCC 与 CCA 重叠,那么 CAT 与 CCA 重叠,以此类推。
基于它们的前缀或后缀是否与集合中的任何其他 k-mer 重叠,可以使用相同的系统来找到排列中的第一个和最后一个 k-mer 。在我们这里,这是 TAA 的 TA 和 GTT 的 TT 。

这些读数可以基于它们的重叠按如下顺序排列。

根据上面的顺序和一系列步骤,很明显这种方法对于找到最终的输出并不那么有用,因为我们可能会陷入局部最小值 ( 低深度排序)。尽管如此,还是有可能在几次随机迭代后得到最终输出。

天真的方法->找到任何重叠的读取
但是正如我上面所说的,这对于基于试错法的更小的读取集合来说可以很好地工作,但是由于重复的 k-mers 或重叠区域,它仍然会变得有问题。
虽然一些重叠区域在给定的一组读数中可能更常见,但其他的不太可能,因此您可能有几个潜在的选项和路径,可能会导致您出现不正确的排列(注意,这甚至没有考虑潜在的突变和错误)。
有效计算重叠的概率几乎是不可能的,因为这种概率仅仅取决于重叠的种类和整个读取集。
取序列atttatatttat和 2 读取 TT 和 AT。TTA 出现在序列中的概率是 5/14,等于 AT,但实际上,TT 出现的概率比 AT 高得多,因为 TT 可以与自己重叠。同样,这是一个简化的例子,但是重复确实使得找到正确的重叠更加困难。
基于这个简化的例子,我已经清楚地表明随机迭代和猜测检查是一个非常低效的想法。这就是我们的数据表示变得非常有用的地方,不仅可以删除冗余的读取,还可以找到客观上正确的快速简单的路径。
图论、循环和符号的快速介绍。
首先,要知道图表实际上只是可视化数据之间联系的一种奇特方式。数据是图中的节点,连接是边。


图的节点和边->这是一个有向循环图,其中每个节点指向另一个节点
以下面这个为例。这就是所谓的 有向图 ,它展示了一对一或一对多的关系。
这里,我们看到一组标为 V 的节点和一组标为 e 的边或关系,利用这些,我们可以画出连接来描述这些相邻的对是如何相互连接的。
现在,假设我想让你找到 a,b,c 作为一个字符串的所有可能的组合,以字母 a 开始。有了这个可视化,很明显你可以通过在图上走两个不同的步来创建两个表示: (a - > b - > c) 和 (a - > c - > b) 。注意因为图是有向的,所以我们不能做 (a- > b- > a) 之类的。
在我们的例子中,这对于查找订单和安排非常有用,从而大大降低了图形的复杂性。这为我们的问题提供了约束,可以用图论来表达和解决。
还有其他图形,如加权有向无环图(神经网络)、无向图、树和有根树的树状部分、二分图等等。




无向、加权、完全和有向非循环(从左到右、从上到下)
如果你已经注意到了,图通常通过方向、它们的边/连接的性质( u 和 v) 以及循环的数量来区分。
在我们的可视化中,有很多问题包含图论,从最短路径问题(您的 GPS 路线),测量连通性和平衡(是否所有节点都以某种方式在某些限制下相互连接),以及找到自包含、强连接的组件。
有向图和字符串图重叠布局共识
为了更容易地表示我们的阅读和重叠,我们可以回到符号的前缀和后缀。假设一些前缀连接到其他后缀,并且有几个重复,我们可以构建一个图,特别是一个有向图,它的节点代表实际的读数,边代表前缀或后缀。

有向连接图->节点是读数,边代表重叠前缀/后缀
这种方法正式称为重叠–布局–一致性方法,其中每个读数映射到图中序列中的每个其他读数,重叠由边决定。
注意这是一个平衡的、强连接的图,其中通过一些路径,每个节点或配置连接到另一个。我还生成了下面的一些代码示例,以帮助您处理和试验这一点
下面是我们的图的字典和距离矩阵表示。你在这里真正要解决的是给定的事实,即每个阅读是相同的长度和相同的重叠,你实际上是试图从一组阅读中找到最短的字符串序列,通过最大化每个阅读与另一个阅读的重叠程度(增加覆盖率-> 1)。

功能输出
给定这个图表,我们怎样才能找到最终组装基因组的正确顺序和方向呢?
如果我们从一个图来看,我们知道可以通过访问每个节点或只读取一次来找到最优解,而到达那里的唯一方法是找到我们应该访问的读取的理想顺序。这比看起来要困难得多,因为大多数图都可以是循环的,或者因为重叠部分的重复而具有独立的组成部分。
这种行走被称为哈密尔顿路径。
哈密尔顿路径 是一种特殊的图的行走,其中图中的每个节点被恰好访问一次,而不管它是如何到达那里的。如果在我们的行走过程中,我们到达了我们开始的同一个节点,这就是所谓的哈密顿回路。

橙色路径突出显示了连续连接每个节点的哈密顿路径
同样,这似乎很容易解决,但事实是,这个问题被认为是 NP 完全的。为什么?因为求解哈密顿回路的唯一方法,是我们最初尝试过的蛮力方法。
你可以从 CSC 463:http://www.cs.toronto.edu/~ashe/ham-path-notes.pdf这里看到这个证明
我撒了个谎,我们这个具体例子的图示。强力算法被认为具有 O(N)的时间复杂度。虽然蛮力算法可以最小化路径上的总成本,或者简单地说,找到由所有读取组成的最短公共超串,但这不适用于数亿次读取。
那我们现在怎么办?让我们稍微重新组织一下这个问题。
我认为一个计算机科学专业的学生可能不会选择使用贪婪的字符串算法,这很好,因为在一个典型的基因组中有重复的阅读。
因此,我们可以尝试最大化重叠,这样当两个重复设置在一起时,您会被卡住。这越来越令人困惑了。让我们再细分一下。
我们知道,我们的重叠群的图形表示的属性需要是这样的,即路径必须能够连接所有可能的重叠群而不重复。
我们想补充的另一点是,我们想要图的简化表示,或者说图应该是解开的。
在这种情况下,我们不能将 k-mers 表示为节点,因为有向边仅表示与下一个节点的前缀重叠的后缀。相反,如果我们想要最大化重叠和覆盖,您会想要实际的前缀和后缀作为图中的节点,而 k-mers 作为连接每个节点的边或胶水。


对于真实世界的数据,大多数收集的重叠群将具有来自多个拷贝的重复,它们可能具有潜在的突变,或就此而言的漏读。如果我们使用哈密顿量来绘制路径和序列,它会限制稍后使用特定超参数重建基因组的能力,例如错误阈值(称为汉明距离)或消除重复(我们将在稍后讨论)。

德布鲁因图和方法
请注意,如果我们决定改变前缀和后缀的实际长度,同时保留实际读取的边内容,这种表示会如何变化。
这也允许我们减少图中的总边数。对于传统的哈密尔顿函数,从一个节点到另一个节点可能有几个连接,而在这里,每个前缀仅通过由它们的重叠产生的读数连接到特定的后缀,而没有其他。
例如,如果我们有重复的读取,如上述示例中的 ATG,则哈密尔顿函数将不得不为这些读取指定单个节点,因为要使哈密尔顿路径工作,每个节点都必须被访问一次。因此,您不能重叠任何节点来简化图形。
这在具有哈密尔顿步行的重叠图的正式定义中被清楚地概述:
一个图是一个重叠图,如果它的顶点可以与直线上的区间一一对应,使得两个顶点相邻当且仅当区间部分重叠,也就是说,它们有非空交集,但都不包含另一个。
在这个新的图中,由于我们的新表示将读数存储为图中的边而不是节点,我们现在可以将路径的新标准定义为任何恰好通过图中每条边一次的行走。
我们的循环将会是同样的事情,但是在我们开始的节点结束。
这张图被称为德布鲁因图,非常有用。
De Bruijn 图也是有向图,但是具有欧拉图的性质。这是什么意思呢?
嗯,你听说过哥尼斯堡七桥吗?
哥尼斯堡市有七座桥,让游客可以跨越普雷格河的不同河段。

这座城市想要找到一条道路,这样游客可以从任何一座桥开始,穿过城市中的每一座桥回到同一座桥。本质上,这被称为我们的哈密尔顿路径,但这是不可能的。
这是因为对于为真的哈密尔顿路径,每个节点必须有偶数度,而在这里,每个节点有奇数度。
然而,莱昂哈德·欧拉提出的解决方案满足了一部分约束条件。他指出,该图有一条 欧拉路径 ,在这条路径上,每个游客都有能力恰好穿过每座桥一次,但永远不会回到他们出发的地方。
所以让我们介绍一下欧拉图、路径以及它们之间的一切。
如果有一条路(欧拉路)恰好访问图中的每条边一次,则该图可以是欧拉图。然而,不是每个图都有欧拉路径,也不是每个有欧拉路径的图都有欧拉环。
这些属性对基因组组装有些用处,但是让我们来确定欧拉图的一些属性。一个有向图只能是欧拉图,如果每个顶点与其中两个顶点的距离相等,其中一个顶点的进出度为 1,另一个顶点的进出度也为 1。

欧拉循环和路径
为什么这很重要?好吧,我们先定义一下学位是什么意思。一个节点的度由连接到该节点的边数与该节点连接到其他节点的边数之差决定。

节点的度是其入度和出度之差
为了让我们能够开始一条欧拉路径,起始顶点只需要有一条回到节点的路,因为那会让路径终止。

原图鸣谢:欧拉路径- > BBADCDEBC |节点 A 的偶数度 D(A)= 1–1 或 D(A) = i(A)-o(A)
在这种情况下,B 是起始节点,因为它只有 1 条输入边和 2 条输出边。因此,节点 B 的 o(B)为 2,i(B)为 1。这个的度是|o(B) — i(B)| = 1。以类似的方式,C 是端节点,因为它有 2 条输入边和 1 条输出边。因此,节点 C 的 o(C)为 1,i(C)为 2。
所有其他节点都有偶数度,它们的 o(v)和 i(v)之差总是偶数,不管 i(v)和 o(v)是什么。

所以回到我们的 De Bruijn 图,如果基因组是线性的,起始前缀将总是图中只有 1 条输出边的节点,如果基因组是圆形的,则度为 1。
我们的欧拉路径是有用的,有几个原因,主要是它有助于防止数据中序列和重复的丢失。
对于哈密尔顿图,一些行走可以访问每个节点,但是不能以正确的顺序接受所有可能的重复。此外,随着基因组长度的增加,求解哈密尔顿路径变得更加困难。
我们现在已经把我们的问题重新定义为欧拉路径寻找问题。然而,为了找到所述路径,我们需要能够构建所述德布鲁因图,该图可以帮助我们可视化该路径。

请注意我们的距离矩阵的大小是如何从重叠图的 16×16 变为德布鲁因图的 11×11 的。
给定一组重叠群,您可以使用一个简单的脚本构建 De Bruijn 图:
它的输出以字典格式表示了 De Bruijn 图。

现在困难的部分来了,在我们的德布鲁因图中找到一条欧拉路径。如果你要创建一个强力方法来检查每条边是否被使用过一次,对于一个更大的图来说是无效的,主要是因为你可能会在一个给定的行走中陷入许多局部欧拉循环。
我们可以利用这一点,而不是创建几个随机的遍历,你可以随机遍历图形,直到你到达一个停止点。这可能是当你在你开始的同一个节点结束,或者如果没有其他边可以走。
一旦你走进死胡同,这可以帮助你快速识别出图的尽头,然后回溯穿过图的每一条边。
演示这一点的一种流行方法是将图分成几个单向图,其中每个节点的 o(v)和 i(v)均为 1。这类似于图的随机游走,如果图是真正的欧拉图,那么除了 2 之外的每个节点都有一条未使用的边。

学分:生物信息学第 1 卷
一旦你到达一个循环或路径的末端,你可以回溯直到你读取一个有未使用边的节点。现在,这可以成为您下一次步行的起点,您可以消除您在上一次步行中访问过的边缘。

这个下一个循环在具有未使用的边的另一个节点处结束,并且这个过程继续,直到遍历了所有的边。由于图是平衡的,所以该算法对于循环很有效,并且类似的过程对于欧拉路径也有效,在欧拉路径中,唯一的约束是网络的最后一个节点将在第一次行走中被确定,因为该图将总是几乎不平衡的。
这就是众所周知的 Hierholzer 算法,这个很棒的视频教程对此做了很好的解释,你应该看看它来获得一些直觉。
这是一个实现欧拉循环行走的简单脚本:
使用这个例子数据集,你可以在这里检查你的欧拉周期的答案。
对于欧拉路径,我们可以为德布鲁因图实现类似的算法(就像欧拉圈一样),如下所示。
使用这个示例数据集,您可以使用下面的格式化函数来验证您的答案。
我们已经研究了基因组组装的一些更基础的部分,但现在我们需要研究实用的部分。
当我学习基因组组装时,最初困扰我的一件事是,我们解决方案的较小部分,如重叠长度为 k-1 或只有一个可能的解决方案的假设,是否怀疑我正在做的很多事情。
嗯,没那么多。这个过程的目的是更好地了解基因组组装是如何利用真实世界的数据完成的,拥有理想的例子只会加强我们的基础。

人类基因组组装示例:微光索引+最小化误差+最大化重叠
话虽如此,让我们进入阅读,特别是他们的长度。需要注意的一个关键点是,阅读长度越长,最终序列就越准确。
较长的读数具有较大重叠覆盖的优势,因此与重叠长度的误差空间有限的较短序列相比,对重叠更加严格。

可变阅读长度对图谱覆盖范围的影响:对于消化不足(处理环境温和)和消化过度(处理环境极端),核小体图谱的覆盖范围分布随着阅读时间的延长而增加。
这也有助于在管道中早期发现突变或错误,并消除基因组某些部分比其他部分拷贝数更多的扩增偏差(如上面的比较所示)。
到目前为止,大多数推荐的阅读长度(k)约为 300 个核苷酸长。这是有意义的,因为阅读长度变得越长,我们的图表就变得越不混乱,并且从一开始就越接近原始基因组。
然而,对于 30 亿长的基因组来说,300 聚体重叠群几乎不算什么。这不仅提出了几个精度问题,而且使计算更加困难。
为了突出这一点,让我们以 TAATGCCATGGGATGTT 为例。如果我们按字典顺序看它的 k-mer 组成,你会得到
['AAT ',' ATG ',' ATG ',' ATG ',' CAT ',' CCA ',' GAT ',' GCC ',' GGA ',' GGG ',' GTT ',' TAA ',' TGC ',' TGG ',' TGT']。
注意这适用于任何指定的 k-mer 。
如果你还记得最初激发决策路径想法的强力方法,你会知道初始序列的另一个可能的重构是 TAATGGGATGCCATGTT。
如果你观察这个序列的 k-mer 组成,它也恰好是
['AAT ',' ATG ',' ATG ',' ATG ',' CAT ',' CCA ',' GAT ',' GCC ',' GGA ',' GGG ',' GTT ',' TAA ',' TGC ',' TGG ',' TGT']
这是与前一个序列相同的 k-mer 组成,但两者有很大不同。这意味着一些图可能有多条欧拉路径,这使得我们的整个过程变得复杂。
但是,如果我们将 k-length 从 3 增加到 5,你可以很容易地看到,这个问题对于 5-mer 来说是可以避免的。
['AATGC ',' ATGCC ',' ATGGG ',' ATGTT ','CATGG【T17]',' CCATG ',' GATGT ',' GCCAT ',' GGATG ',' GGGAT ',' TAATG ',' TGCCA ',' TGGGA']
['AATGG ',' ATGCC ',' ATGGG ',' ATGTT ','cat gt【T19]',' CCATG ',' GATGC ',' GCCAT ',' GGATG ',' GGGAT ',' TAATG ',' TGCCA ',' TGGGA']
CATGG 和 CATGT 不匹配,因为读取长度越长,重复的空间就越小。现在,在 30 亿长基因组和 300 长核苷酸上限的背景下,这个问题会变得非常复杂。
如果我要传递上面显示的重叠群的 De Bruijn 表示,我将得到 2 个不同的欧拉路径作为问题的解决方案。
就这一个例子来说,我们很容易认为我们的测序出现了错误,导致仅 1 个核苷酸出错。这是一个完全合理的假设,但最终结果可能会大相径庭。
幸运的是,有一种方法可以解决这个难题,它来自于我们最初的测序过程。
当我们对我们的初始基因组进行多次鸟枪法测序时,你会得到更长的随机重叠区域,这些区域在几个拷贝中是不同的。

在我们最初的方法中,我们只能组装单个序列,而不能组装重叠的序列。我们希望得到洋红色和蓝绿色重叠序列,以及它们的重叠群集合。给定一系列 k-mers 来表示跨序列的重叠区域,我们如何做到这一点?
让我们跳到所谓的成对合成图。
成对合成图实质上是由设定距离分隔的几对读数。

(k,d) = (3,1)的 3-mer 配对表示
这是一个 (3,1)成对阅读组合 ,因为每个阅读之间有 1 个核苷酸的距离。你用这种表示法所做的是,你现在已经在阅读和缺口之间画出了联系,以这种方式,这些对的重叠只能对应于一个特定的序列,而不是别的。

成对读取 DeBruijn 图表示
您仍然可以在 De Bruijn 图中将其表示为一组节点和边,但现在每个边是一对读取,节点是该对中每个读取的成对前缀和后缀。要了解为什么这种表示更有用,我们可以看看之前的 De Bruijn 图。

德布鲁因图和方法
假设我们有 CCA 和 AAT,在成对表示中,你有一个由长度为 5 的路径拼写的唯一字符串(这是最终的重叠),但不是有多余的额外序列, 你可以写 AAT-CCA,这表明有一个 2k + d 的更长路径。
如果您确实重叠了它,您将得到 AATGCCA,其中现在您已经将 AAT、ATG、TGC、GCC 和 CCA 编码在 5 长度 mer 中,而不是 3 * (k=3) mer 中。
这也消除了不必要的重复,并允许你简化你的潜在路径,而不必通过消除 ATG 的重复来大幅增加你的阅读长度。
使用该系统的目的是利用覆盖范围,因为您现在可以拥有两条覆盖范围较大的特定路径,它们需要无任何误差地匹配。
为了说明这一点,我们可以看看相同的例子,我们有相同的 k-mer 集,现在使用我们的成对组合来比较两个 TAATGCCATGGGATGTT 和 TAATGGGATGCCATGTT 。
['TAA| GCC ',' AAT| CCA ',' ATG| CAT ',' TGC |ATG ','GCC|TGG',' CCA
['TAA| GGG' ,' AAT| GGA ,' ATG| GAT' ,' TGG |ATG ','GGG|
线对之间的差异非常明显,这有助于区分不同的路径,同时优化单个解决方案。
关于配对的另一点是它们很有用,因为它们代表了我们所关注的阅读的前缀和后缀。
对于字符串 AGCAGCTGCTGCA,可以用路径AG-AG→GC-GC→CA-CT→AG-TG→GC-GC→CT-CT→TG-TG→GC-GC→CT-CA 来拼写。

通过重叠,您将得到匹配的 AGCAGCTGCTGCA。
但是如果我们转换到另一个潜在的欧拉路径,成对读取的顺序将是 AG-AG→GC-GC→CT-CT→TG-TG→GC-GC→CA-CT→AG-TG→GC-GC→CT-CA。
然而,这种重叠不会起作用,因为现在你会得到不同的核苷酸: AGC?GC?GCTGCA。

我们可以使用类似的方法来公式化给定的一组读对的德布鲁因图,其中如果当前节点的后缀=下一个节点的前缀 (因此显示重叠),则节点(两对的前缀或后缀)仅连接到另一个。
以下代码可用于将一组对读转换为 De Bruijn。
从那里,我们可以使用与之前完全相同的欧拉路径算法。
为了组装最终的基因组,我们使用上面演示的方法,其中我们可以使用以下函数找到重叠区域:
给定下面的例子:
***4 2
GAGA|TTGA
TCGT|GATG
CGTG|ATGT
TGGT|TGAG
GTGA|TGTT
GTGG|GTGA
TGAG|GTTG
GGTC|GAGA
GTCG|AGAT***
你最终的重构将是 GTGGTCGTGAGATGTTGA 其中 k=4,d=2。
好了,现在是时候解决基因组组装的一些实际问题了。
你可能已经注意到这里有很多假设。首先,覆盖率总是被认为对每个基因组都是完美的,但这通常是不正确的。
事实上,覆盖总是不完美的。Illumina 的测序技术被认为是世界上最好的,能够对 300 聚体进行测序,但错过了几个关键的重叠群。而那些被它选中的往往总是有错误。
尽管如此,该公司已经在他们的白皮书中概述了几项改进。
为了真正解决覆盖率和准确性问题,大多数现代汇编程序使用读中断方法,即采用几个长重叠序列,并使用 FM 索引将它们分成读对。之后,使用基因组上重叠群的索引,您可以交叉阅读对以实现完美的覆盖。****
因此,您可以使用我们当前的过程来处理组装阅读对的模糊性,然后使用基因组中重叠群的索引位置来对齐阅读中断方法中的 k-mers ,复杂度为 O(logN)。
索引重叠群不仅移除了图中的可传递边,还压缩了我们的表示以解开我们的图。当我们用它和我们的阅读对一起寻找支架中的缺口并填补它们时。**
与此同时,读取的大小是至关重要的,就像我们之前概述的那样,在给定足够多的 DNA 拷贝和重叠区域的情况下,较小的 k-mer 将增加总覆盖率,但也会使我们的图表在计算上更加昂贵。
我们通常可以用其他超参数来模拟 De Bruijn 图,例如最小或最大重叠长度,其可以为重叠段和实际读数之间的最小汉明距离的理想欧拉路径解决方案创建几个分支和路径。
汉明距离和熵是一组序列之间变化的度量。 海明距离为 0 意味着集合中的所有序列都是相同的,高于 0 意味着存在多个碱基对差异。
熵可以认为是对一组序列之间的错配变异进行建模的概率分布。

熵越低,分布中的不确定性和变化就越少,或者说该链就越保守。
主题熵通常适用于 加权图建模,在这种情况下,我们可以使用较低的熵作为两次或多次读取之间的重叠更有可能准确的标志 。
***[[0.2 0.2 0\. 0\. 0\. 0\. 0.9 0.1 0.1 0.1 0.3 0\. ]
[0.1 0.6 0\. 0\. 0\. 0\. 0\. 0.4 0.1 0.2 0.4 0.6]
[0\. 0\. 1\. 1\. 0.9 0.9 0.1 0\. 0\. 0\. 0\. 0\. ]
[0.7 0.2 0\. 0\. 0.1 0.1 0\. 0.5 0.8 0.7 0.3 0.4] ]***
第一个输出是计数矩阵,它模拟序列中给定位置的核苷酸的概率分布。例如,矩阵的第一列 T 为 0.7,表示最佳重叠区域将从核苷酸 T 开始
结果,熵是每个单独行的熵之和,因此在9.916556772。****
你可以用类似的方法找到基因组中出现多次的碱基不匹配的部分。 你可以用熵来计算一个使用守恒重叠 的最优覆盖,之后你可以修剪节点中的不匹配并移除气泡(我们稍后会谈到)。**
通常情况下,大多数基因组无法从头到尾组装起来,因此这是一个关键步骤,不仅因为这很昂贵或者现代技术无法对更长的链进行测序,而且同时对整个基因组进行测序容易出现几个错误,尤其是从头开始。
大多数测序应用基于全基因组测序,其中您使用组装构建整个生物体的基因组,这种方法是准确的,因为通过多年的研究,大多数生物体都有参考材料。
对于与完全外来的生物体相关的从头方法,它变得更加困难。然而,rread-break 方法允许个人在一定范围内分析关键变量,因为大多数读数通常都有不可告人的功能。****
这些可以是转录因子结合位点、复制起点、转座因子、核糖体 rRNA 基因和卫星 DNA。碱基信息有助于识别突变,通过组装映射功能,每次都能更好地改进流程。**
我们基因组的多样性经常会带来组装方面的问题,但它也有助于创建准确的参考材料,这些材料在医疗系统的每个主要部分都发挥着重要作用,从临床护理、罕见疾病的诊断,到制定个性化的疗法和治疗。****
无论如何,如果有一个无法解释的单核苷酸错误,我们最初的德布鲁因图将会有一个缺失的边,使得不可能找到欧拉路径。
从基因组的角度考虑重叠群的一个好方法是看德布鲁因图中的无分支图。
如果您能从我们的欧拉循环部分重新计数,这只是您将进行的第一次随机行走,其中该图中的节点对于除开始和结束之外的每个中间节点都具有 1 的 in(v)和 out(v ),因为它们不会分别具有 in()或 out()。
对于我们图中的重叠群,你可以把它想象成路径,当一个节点有不止一条边或选择时,这条路径就结束了,因此这有助于产生几条无分支路径。****
我们正在寻找的是最大无分支图,它不同于无分支路径,因为它们可以通过任何一组节点,非常类似于初始随机行走。**
一个最大的非分支图实际上是任何一个路径,一旦有一个以上的可能路径(度> 1)可以选择,它就结束了。
TAATGCCATGGGATGTT ,有九个最大无分支路径,拼出了重叠群* TAAT、TGTT、TGCCAT、ATG、ATG、ATG、TGG、GGG 和 GGAT →由于重复,不使用读取对就很难推断出唯一的欧拉路径,因为它们只在完全覆盖的情况下工作,并且通常很少得到所述读取对。***
单点或核苷酸改变的易错读数是测序的主要障碍。多个长度的多个误差会产生与原始路径的几个偏差。
这被称为气泡,其由潜在读取排列的发散然后会聚路径定义。**

在人类基因组测序的情况下,您可以通过基线基因组识别大多数气泡,并识别 DNA 序列中的潜在错误,但如果您的目标是捕捉所说的突变呢?
模拟整个基因组的 De Bruijn 图通常有数百万个气泡,这些气泡具有不同类型的误差,可以创建一个非常误导的图片。例如,不精确的重复序列困扰着人类基因组计划,因为与其他重复序列相比,1 个重复序列中的单个点突变将产生相同的气泡,这使得选择正确的重复序列更加困难。**
然而,在大多数情况下,您可以修剪掉气泡,因为它们的覆盖率很低,但是没有任何关于消除错误的具体内容,这在大多数汇编器中都是精简的。
使用所有这些策略,大多数工业字符串图汇编器通常平均获得 94%以上的覆盖率,对于人类来说接近 99%,这对于获得患者的准确图像来说非常好。
基因组组装可以被认为是理解构成所有生命的语言的第一个基础步骤。
组装可能是流水线中简单的一部分,但它是推进生物信息学和计算生物学领域的重要组成部分。
为了对汇编器的实际用例进行更多的评论,大多数服务都是基于映射汇编器的,它利用了已知基因组的参考引导重建。一些开源的工具包括 AMOS (一个模块化的开源汇编器 ) ,其中包括用于从头汇编的工具和不同的工具,如生成支架和重叠图,Illumina 的用于小基因组的铲,以及 IDBA-UD ,虽然更老,但也是开源的。**
重要的是要认识到,计算的作用大大加快了我们在 4GB 内存上组装整个基因组的能力。建立在终止和焦磷酸测序基础上的早期技术继续帮助随着时间和成本提高阅读长度。
从测序到组装,我们本质上是在用线索和特征破译基因之谜。通过这一过程,我们对几种生物和我们自己的了解比以往任何时候都多,并且能够根据某些基因的位置和表达方式来利用它们的独特性质来解决一些基本问题。
我们现在正处于这样一个阶段,测序技术似乎是改进组装计算方法的最大障碍,然而通过我在本文中概述的一些过程,生物信息学家已经能够开拓从比较基因组学到个性化医学的新领域和新方法。
从头组装仍然是该领域的一个重要问题,如廖等人所述,
第一个挑战是测序误差,这可能会在组装结果中引入伪像 Illumina 等平台中的测序偏差具有碱基组成偏差,这通常会导致测序深度不均匀。第三个是重复基因组的拓扑复杂性(重复占整个哺乳动物基因组的 25-50%)…最后一个挑战是巨大的计算资源消耗。尽管小基因组(如细菌基因组)的从头组装只需要几分钟,但是大基因组(如哺乳动物基因组)的组装通常需要几天到几周,并且需要超过几十到几百 GB 的峰值 RAM 存储器
通过这一过程,我学到了很多东西,这使我不仅能够在理解行业的许多关键问题的同时,考虑到基因组学作为一个领域的实际障碍,而且我也很高兴能够了解更多信息,并致力于组装和分析中一些更有问题的方面。
我希望你们现在和我一样对生物和工程领域抱有同样的热情。
更 打造 即将到来。
感谢你花时间阅读这篇文章,我希望你从中有所收获。如果你想获得更多的技术或者只是联系我,你可以在LinkedIn,Email,或者GitHub上找到我。还有* 网站 【在作品中因为没有作品:)】。也可以在这里 订阅我的简讯 。***
我将在 CS/DL/CB 列车上呆更长的时间,所以如果你有任何我应该知道/谈论的很酷的论文、想法、技术或人,我将非常感激。
我咨询了一些你应该看看的资源(尤其是。5、1 和 8)。
1。https://www.bioinformaticsalgorithms.org/
2。https://link . springer . com/content/pdf/10.1007/s 40484-019-0166-9 . pdf3 .https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3072823/4。http://www.cs.toronto.edu/~ashe/ham-path-notes.pdf5。https://www.youtube.com/watch?v=xR4sGgwtR2I6
。https://www.youtube.com/watch?v=otOipgZF0ag
7。https://www.youtube.com/watch?v=5wvGapmA5zM8。【https://www.youtube.com/watch?v=ZYW2AeDE6wU9。https://www.youtube.com/watch?v=KASvlXYPCBI
萨拉米咖啡研磨
原文:https://towardsdatascience.com/salami-coffee-grinding-fb9ebd489cbd?source=collection_archive---------13-----------------------
咖啡数据科学
在时间中切割研磨
一杯意大利香肠浓缩咖啡是指你使用多个杯子,同时抽取一杯来检验味道和/或萃取的差异。这是一个有助于理解镜头如何随时间变化的实验。我决定将同样的概念应用于研磨,因为我注意到一些咖啡豆的研磨分布与 20 克咖啡有很大不同。
这些结果显示了从研磨开始到结束的颗粒分布差异,这可能解释了为什么垂直分布方法(如 WDT )比水平分布技术(如 OCD )能提高提取率。

所有图片由作者提供
我用了一个冰块托盘,效果很好,在整个研磨过程中我收集了 13 个样本。然后我测量了每个样品的研磨分布。第一组显示了前两个样本,第 8 个样本(研磨中间)和第 13 个样本(最后一个样本)。


我发现前几个样品比其余的更粗糙。以下是前四个样本:

然后研磨开始稳定,这样到最后,样本之间不会有太大的时间差异。以下是最后四个样本:

我们可以使用累积条形图以另一种方式查看这些数据:


那么如果把重点放在几个点的累积分布上,前几个样本的粗糙程度就更清晰了。

我想知道这是否是因为研磨机在达到稳定状态之前就装满了研磨物。
应用模式识别
查看这些数据的另一种方法是使用模式识别。我想看看每个样本中产生的粒子形状是否有很大不同,所以我使用线性二进制模式(LBP)对每个粒子进行分类,然后我对这些粒子进行 K-means 聚类,并进行相互比较。
有了这些,我可以根据每个粒子所属的簇来判断不同样本有多相似:

这表明第一个样本实际上是样本 2 和 3 的异常值。样品 4、5 和 6 似乎像样品 10、11 和 12 一样聚集得很好。
我们可以用细小的(<400um) and coarse (>400 微米)颗粒来分割它。<400um similarity matrix is very similar to all the particles because 70% of particles are on the fine size.

What is interesting in the > 400um 矩阵就是样品 1 和其余样品还是有这样的差别。最后一个样本在这方面是相似的。
我们可以将这些进一步分解成几个颗粒大小:

300um 似乎在样品 3 后显示出稳定性。这些休息没有告诉一个故事有很大不同于前。
更多的数据点
在我的一些其他实验中,我一直在探索增加烘焙咖啡豆储存的湿度,在六天中,我测量了 1 克和 20 克的研磨分布,每天研磨新鲜的咖啡豆。所以我可以比较第一部分和其他部分。


从 1 克样品到 20 克样品,总体上趋向于更细的研磨。我用另一种方式绘制了它:


这些样品有助于强化萨拉米香肠研磨样品不仅仅是一次性的,而是研磨机功能的一部分。
这个实验对我来说既简洁又有益。我不认为研磨是同质的,但这绝对不是我所期望的。
我想知道直接在篮子里研磨是否会导致底部的粉末分布过于粗糙。我怀疑这就是为什么像 WDT 或某种分布的方法可以帮助拍摄,因为实际研磨分布在不同的层是不同的。
让我们在断奏镜头的背景下思考这个信息。最基本的断奏镜头在底部有一个较精细的图层,在顶部有一个较粗糙的图层。如果你直接在过滤篮中研磨,底部的粉末会比顶部的更粗糙,就像一个倒置的断奏。
我通常把它磨成一个杯子,在把它放进过滤篮之前稍微混合一下。通常情况下,我最后会把地面的顶部放在过滤器的底部。
这些测量也可以解释为什么咖啡师 Hustle 的实验没有显示出体重的差异。他们没有测量颗粒分布,但研磨分布的真正差异是一个垂直函数。
这些结果更有力地说明了夯实前需要分配地面,无论是在研磨机中还是在过滤篮中。我不知道咖啡结块在多大程度上影响了拍摄后分配地面的需要(因为我生活在干燥的气候中,很少出现结块问题),但肯定研磨分配指向了分配的需要。
第一个示例解释
家庭浓缩咖啡爱好者脸书小组的托德·戴维斯指出,第一个样本可能是异常值,因为它是研磨机中残留的咖啡渣。在进行这个测试之前,我没有清理研磨机,不是故意的,而是因为忘记了。所以第一个样品可能是不同的烘焙或者不同的研磨环境。无论如何,这是最合理和简单的解释,所以谢谢你托德!
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影飞溅页
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡用纸质过滤器
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维护
咖啡评论和想法
咖啡实验
顶级数据科学职位的薪资明细
原文:https://towardsdatascience.com/salary-breakdown-of-the-top-data-science-jobs-cf83c6464a59?source=collection_archive---------4-----------------------
意见
机器学习 vs NLP vs 数据工程师 vs 数据科学家,以及在每个角色中意味着什么

照片由思想目录在Unsplash【1】上拍摄。
目录
- 介绍
- 机器学习工程师
- 自然语言处理工程师
- 数据工程师
- 数据科学家
- 摘要
- 参考
介绍
当看数据科学家的工资和数据科学角色时,很明显数据科学中有不同的、更具体的方面。这些方面与独特的工作岗位相关,特别是机器学习操作、NLP、数据工程和数据科学本身。当然,还有比这些更具体的职位,但是这些可以给你一个大概的概括,如果你在这些职位中的一个找到工作,你会有什么期望。我也想挑选这四个角色,因为它们可以很好地分开,就好像有一个聚类算法可以找到彼此最不同但也在同一人群中的工作。下面,我将讨论低范围和高范围的平均基本工资,以及各自的资历水平、用于确定这些数字的估计数,以及每个角色的预期技能和经验。
机器学习工程师

照片由附身摄影在Unsplash【2】上拍摄。
机器学习工程师倾向于将已经研究和构建的数据科学模型应用到生产环境中,通常包括软件工程,当然还有机器学习算法知识。话虽这么说,可想而知薪水相当不错。这个特别的估计来自于glass door【3】。
根据大约
1,900提交的工资,有以下广泛的范围:
- 低——约 86,000 美元
- 平均——约 12.8 万美元
- 高——约 19 万美元
正如你所看到的,任何职位都有一个范围,你的经验越多,薪水越高也就不足为奇了。除了多年的经验之外,你工作的州、你所运用的技能以及公司也会决定最终的薪水数额——所有这些职位都是如此。为了获得更多的粒度,我们可以查看各种资历级别,以便了解级别的增加与薪金金额之间的关系:
- 机器学习工程师 L2~ 12.8 万美元
- 高级机器学习员 L3~ 15.3 万美元
- 机器学习领袖 L4~ 16.6 万美元
这里有一些来自个人经验的技能,你可以期望在机器学习职位上使用:
- SQL/Python/Java ( 有时)
- 算法知识 —无监督和有监督分类的区别,时间序列,回归,以及打包它们的流行库
- 部署平台和工具 — AWS、Google Cloud、Azure、Docker、Flask、MLFlow 和 Airflow —部署模型并与数据科学家合作构建自动化流程
自然语言处理工程师

帕特里克·托马索在Unsplash【4】上拍摄的照片。
这个角色通常被称为 NLP 工程师,通常专注于将数据科学模型或机器学习算法应用于文本数据。NLP 工作的一些例子是大量文本的主题建模、语义分析和聊天机器人代理。话虽如此,你也可以想象一份相当不错的薪水——然而,这份薪水细目将低于机器学习工程师,很可能是因为这个角色的包容性更低,更专注于数据科学中的一个特定主题。这个特别的估计也来自glass door【5】。
根据大约
*20*提交的工资,有以下广泛的范围:
值得注意的是,报告的工资数额相当低,所以对这一范围持保留态度,但尽管如此,对这一工资仍有很高的信心。
- 低——约 8 万美元
- 平均——11.5 万美元左右
- 高——约 16.6 万美元
所有这些数量都低于机器学习,但是,与大多数其他角色相比,它们仍然相当高。
以下是一些来自个人经验的技能,你可以期望在自然语言处理工程师的职位上使用:
- NLTK —自然语言工具包库
- 文本 Blob
- 宽大的
- 文本清理和处理(r 删除标点符号、删除停用词、分离词根、词干化和词条化
- 语义分析 —一个例子是分析来自客户的正面和负面评论
- 主题建模 —一个例子是在大量文本中发现共同的主题,就像客户评论一样,但不仅仅是好的或坏的评论,还可以分析评论的主题以改进产品:“质量差”与 90%的负面评论有关。
- 分类 —使用类似 Random Forest 的算法将传统的数字特征和文字特征(如描述)结合起来,创建一个将数据分组的模型,如客户细分
数据工程师

卡斯帕·卡米尔·鲁宾在Unsplash【6】上拍摄的照片。
也许一个更常见的角色是数据工程,它与数据科学的关系比数据科学更密切。然而,这个角色对于数据科学工作来说 仍然 至关重要,有时,数据科学家可能会知道数据工程师会知道的大部分内容,这就是我将它包括在本分析中的原因。数据工程的一些例子包括创建存储最终用于数据科学模型的数据的 ETL 作业,以及自动存储模型结果和执行查询优化。这个特别的估计也来自 T21 的玻璃门。
基于大约~
6,800提交的薪水,有以下广泛的范围:
- 低——大约 76000 美元
- 平均工资为 111,000 美元左右
- 高——约 16.4 万美元
这个范围更类似于自然语言处理工程师的角色,然而,它可能是日常工作中离实际工作角色最远的。还需要注意的是,这个职位涉及到更多的评估。
以下是一些来自个人经验的技能,你可以在数据工程师的职位上运用到:
- ETL —提取、转换和加载
- ELT —提取、加载和转换
- 获取将存储在数据库或数据湖中的数据,这些数据可用于数据分析查询、机器学习算法训练查询以及用于存储数据科学模型结果
- SQL 查询的优化 —节省公司的时间和金钱
数据科学家

照片由达里娅·内布里亚希娜在Unsplash【8】上拍摄。
最后但同样重要的是,数据科学家的角色。虽然这个角色看起来是最普通的,但它实际上也可以是具体的,通常主要由模型构建过程组成——有时需要数据工程和机器学习工程师的操作,但可能性较小——但仍然可能涉及自然语言处理方面的专业知识(通常,如果重点是 NLP,那么数据科学家将拥有这个头衔——但并不总是如此)。这个角色还可以有更多的变化,所以我们可以期待一个广泛的范围。这个特别的估计也来自于glass door【9】。
根据大约~
*16,200*提交的薪水,有以下广泛的范围:
- 低——约 81,000 美元
- 平均——约 11.5 万美元
- 高——约 16.4 万美元
出乎意料地低于预期,在这个分析中,这个角色与大多数其他角色差不多。也就是说,它可能是最真实、最稳健的离群值,因为迄今为止,它提交了最多的薪金来构成这些薪金金额。
以下是一些来自个人经验的技能,你可以在数据科学职位上运用到:
- SQL,Python,R
- Jupyter 笔记本
- 可视化 — Tableau、库和包、Google Data Studio、Looker 等等…
- 定义问题陈述、获取数据集、特征工程、模型比较、模型部署和结果讨论
- 示例项目 —创建一个分类器,根据几个特性对公司产品进行分组,使用 SQL 和 Python 从各种来源获取数据,部署模型,解释结果及其对公司的影响
摘要
虽然这些角色可能有一些相似之处和不同之处,但他们的工资范围也是如此。四份薪水中有近三份相似,有一份很突出。这个角色就是机器学习工程师— 为什么呢?我的理解是,这个职位需要了解大多数数据科学概念,尤其是它们的输出,以及围绕部署所涉及的软件工程——这需要了解和使用很多东西,因此,为什么一个由软件工程和数据科学组成的职位报酬如此之高是有道理的。除了每个数据科学职位(或在某些方面类似于数据科学的职位)的薪资明细之外,还有您可以预期使用的技能,以便您可以更好地了解该职位以及它与薪资金额的关系。
总而言之,我们分析了以下四个职位,以及他们的技能:
* Machine Learning Engineer* Natural Language Processing Engineer* Data Engineer* Data Scientist
我希望你觉得我的文章既有趣又有用。如果你同意这些数字和范围,请在下面随意评论——为什么或为什么不同意?有没有觉得某个角色,特别离现实那么远?你还能想到哪些其他数据科学职位会有不同的薪资明细?关于一个角色还有哪些因素会影响薪水?
这些薪资在美国报告,因此以美元金额表示。我与这些公司都没有关系。
请随时查看我的个人资料和其他文章,也可以通过 LinkedIn 联系我。
参考
[1]照片由思想目录在Unsplash(2018)上拍摄
[2]照片由附身摄影在Unsplash(2018)上拍摄
[3] Glassdoor,Inc .,机器学习工程师工资,(2008–2021)
[4]帕特里克·托马索在 Unsplash 上拍摄的照片,(2016)
[5] Glassdoor,Inc .自然语言处理工程师薪资,(2008–2021)
[6]照片由卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄,(2017)
[7] Glassdoor,Inc .数据工程师工资,(2008–2021)
[8]照片由 Daria Nepriakhina 在Unsplash(2017)上拍摄
[9] Glassdoor 公司,数据科学家的工资,(2008 年至 2021 年)
工资、工作满意度、数据工作趋势
原文:https://towardsdatascience.com/salary-satisfaction-trend-of-data-jobs-f47bdf72afa3?source=collection_archive---------25-----------------------
从堆栈溢出调查数据中我们能学到什么

图片来自 unsplash.com
我们现在处于数据时代,在过去的几年里,就业市场见证了对数据相关工作的持续需求。数据科学家、数据分析师和数据工程师是数据相关工作的三大主流。对于任何有兴趣进入该领域或已经进入该领域的人来说,了解数据就业市场的现状将是有益的。当你在数据职业道路上迈出下一步时,工作要求、工资和满意度等信息可以给你更多的洞察力。在这篇文章中,我使用了一个特殊的数据集, Stack Overflow 年度开发者调查,来探索一些有趣的问题。这篇文章将涉及一些数据分析和建模,有三个主要部分:
第一部分:工资
- 什么数据角色工资最高?
- 不同国家数据角色的薪酬;
- 不同工作年限的工资;
- 数据领域不同性别的薪酬;
- 薪水与工作满意度。
第二部分:数据工作的变化,比较 2020 年和 2019 年的数据
- 数据角色数量的变化;
- 工资变动;
- 工作满意度的变化。
第三部分:工作满意度
- 基于 XGBoost 的多类分类预测工作满意度:
- 来自建模的洞察力。
数据注释:
在展示分析结果之前,有必要解释一些重要的数据处理步骤。但是您可以随意跳过这一部分,并在需要时返回。
该调查主要针对具有一般开发背景的人,包括软件开发和数据分析。2020 年的调查数据包含 64,461 份回复。我利用了问题“DevType ”,并对数据进行了预处理,以便只分析拥有数据相关角色的响应者。问卷中的问题如下。
以下哪一项描述了您?请选择所有适用的选项。
[]学术研究员
[]数据或业务分析师(名为 DA)
[]数据科学家或机器学习专家(名为 DS)
[]数据库管理员
[]设计师
[]开发者、后端
[]开发者、桌面或企业应用
[]开发者、嵌入式应用或设备
[]开发者、前端
[]开发者、全栈
[]开发者、游戏或图形开发者、移动
[]开发者、 QA 或测试
[] DevOps 专员
[]教育家
[]工程师、数据(名为 DE)
[]工程师、现场可靠性工程经理
[]营销或销售专业产品经理
[]科学家
[]高管(C Suite、VP 等。 )学生
[]系统管理员
[]其他
请注意,一个响应者可以有多个 DevType 选项,甚至可以选择多个数据角色(即 DA、DS、DE)。我只保留与数据角色相关联的数据条目,并按不同类型的数据角色将它们分开。因此,两个新创建的实例可能来自具有多个数据角色的同一个数据实例。
为了使分析结果更加一致,我还过滤了“雇佣状态”,只保留当前被雇佣的响应者。有了这样的数据准备,我们对数据角色的分析有 11,186 个实例。对 2019 年的调查数据进行了相同的数据准备,创建了 17370 个实例,用于与第 2 部分中的 2020 年数据进行对比。
第一部分:关于工资的事实
我们先来看看这三个数据作业的分布情况。这里我们可以看到它们的数字非常接近,DA 排在第一位,然后是 DS,DE(图 1a)。就平均工资(以美元计)而言,我们可以看到 DS 和 DE 几乎相同,而 DA 的工资略低(图 1b)。

图 1 .(a)2020 年调查的数据角色分布。(b)数据工作的工资。图片作者。
当进一步显示不同国家(回答最多的前 9 个国家)的工资时,我们可以在图 2 中看到一些有趣的细节:
- 美国的数据工作收入最高。美国的平均工资大大高于其他国家,甚至高于西方世界的其他发达国家(即德国、英国、加拿大)。
- 与 DA 相比,DS(和 DE)不一定是收入更高的工作。事实上,我们看到在加拿大和法国,DA 的工资比 DS 高得多。这可能会让你想起一句谚语:数据科学家是 21 世纪最性感的工作。它可能没有你想象的那么性感,至少从调查数据告诉我们的薪水来看是这样的。然而,堆栈溢出调查数据不一定代表真实世界的人口。

图二。不同国家数据工作的薪水。图片作者。
与工资相关的一个重要因素是工作经验的年限。在调查数据中,我们以「专业编码年数」作为工作经验的代理,以「专业编码年数」将受访者分为四组。在图 3 中,从“0-3 岁”到“6-13 岁”,我们可以看到工资逐渐缓慢增加,而在“13 岁以上”群体中,工资有了大幅提高。

图 3。不同「专业编码年」组别的数据工作薪酬。这些组以这样的方式分类,使得大小尽可能相等。图片作者。
另一个有趣且重要的检查点是该领域的性别分布。开发人员领域的性别差异是一个长期关注的问题。在这里,我们在数据字段中也看到了这个问题(图 4)。

图 4 数据工作的性别分布。为了绘图的简单,所有非二元性别都被认为是“其他”组。图片作者。
就工资而言,我们可以看到男女之间没有实质性差异(图 5a),但女性的工资差距较大(差异较大,图 5b)。

图 5。按性别分列的数据工作工资。(a)条形图。(b)小提琴情节。图片作者。
最后,我们来看看工作满意度和薪资的关系。正如你所料,工作满意度并不总是与工资正相关,这也是图 6a 中的数据所显示的。这也可能表明,有一群数据工程师对他们的工作非常不满意,尽管他们的工资很高(见图 6b 中最右边的高绿色条)。当然,在现实世界中,还有许多其他因素会影响我们的工作满意度。而在 Part 3 中,我会应用机器学习建模来预测工作满意度,找到更多洞察。

图 6。薪水和工作满意度。图片作者。
第 2 部分:数据工作的变化,比较 2020 年和 2019 年的数据
在这一部分,我们来看看数据领域的一些趋势。因为我们的分析依赖于堆栈溢出调查数据,并且 2018 年的调查表格与 2019 年和 2020 年的有很大不同,所以我们将仅使用 2019 年和 2020 年的数据进行比较。我们首先注意到,2020 年从原始数据中筛选出的有效调查回复总数为 53,159,15.69%的回复者从事与数据相关的工作。相比之下,2019 年的调查数据有 77,420 份有效调查回复,16.71%的回复者有与数据相关的工作。

图 7。数据角色和分布的数量,2019 对 2020。请注意,由于我们创建数据实例的方式,总数大于调查响应的数量。图片作者。
首先,数据显示,数据角色的分布在这三个角色之间几乎没有变化(图 7)。2019 年的统计数据更大,因为 2019 年的调查中有更多的回复,这并不一定意味着 2020 年数据相关工作的数量有所减少。

图 8。2019 年和 2020 年薪资对比。图片作者。
说到工资的变化,可能是我遇到的最意外的结果了。我们可以看到所有三种数据工作的工资都有所下降,总体降幅约为 16,000 美元(图 8)。

图 9。2019 年和 2020 年薪资对比,仅美国数据。图片作者。
为了进一步验证这种变化,我只用美国的数据做了这个图。并且观察到工资的类似下降(图 9)。这一次,我们看到 DS 的工资仅略有下降,而 DA 和 DE 的工资下降幅度更大。使用其他数据来源来交叉检查就业市场中数据工作的下降是否属实将是有趣的。如果是这样,原因是什么?我们在这里能得到什么启示?顺便提一句,我最初认为薪水的下降可能是由于新冠肺炎以及市场的低迷。但 2020 年的调查数据实际上是在 2020 年 2 月收集的,因此疫情还没有发挥作用。
最后,让我们看看工作满意度,这是帮助洞察就业市场的另一个重要因素。问卷中关于工作满意度的问题如下:
你对目前的工作有多满意?(如果你做多份工作,请回答你花时间最多的那一份。)
o 非常不满意(-2)
o 稍微不满意(-1)
o 既不满意也不满意(0)
o 稍微满意(1)
o 非常满意(2)
我把不同等级的满意度转换成从-2 到 2 的值。平均分数在图 10 中给出。我们可以观察到,在 2019 年和 2020 年,DS 的满意度最高,其次是 DE 和 DA。此外,从 2019 年到 2020 年,所有三种数据工作的满意度都有所下降,与工资的变化方向相同。

图 10。2019 年和 2020 年工作满意度对比。图片作者。
第三部分:工作满意度预测
在这篇文章的最后一部分,我对建立一个预测工作满意度的机器学习模型感兴趣。正如我们之前看到的,工作满意度问题有五种可能的答案。因此,预测将是一个多分类问题。
为了避免不同年份的数据分布不一致,将只使用 2020 年的调查数据进行建模。另外,请注意数据是不平衡的。“非常满意”和“稍微满意”占总数据的 60%以上,而“非常不满意”不到 10%。

图片作者。
一些重要的数据处理步骤包括:1)数据清洗;2)缺失数据插补;3)分类数据编码;4)特征选择/工程师。我将在这里跳过这些技术细节,你可以参考笔记本和 GitHub 库中的代码了解更多细节。对于建模,我使用 XGBoost 算法和 oneVsRest 方法来处理这个多分类问题。
3.1.探索性数据分析
在展示建模结果之前,我将展示一些 EDA 作为数据科学项目的常规,让您快速了解工作满意度。如第一部分所示,薪酬和工作满意度并不一定相互关联(图 6)。其他潜在影响工作满意度的重要因素呢?
如图 11 所示,公司规模和工作满意度之间确实存在某种模式,但是很难得出一个普遍的结论。很有可能,在小公司中,“非常满意”的比例往往高于“稍微满意”。

图 11。不同规模公司的工作满意度分布。图片作者。
加班是另一个与一般意义上的工作满意度相关的因素。然而,如果有的话,模式是模糊的(图 12)。的确,在从不过劳的群体中,“非常满意”阶层并不是最有反响的。

图 12。不同加班时间群体的工作满意度分布。图片作者。
最后,我们来看看不同国家的工作满意度分布情况。有一个现象很突出:在印度和巴西等发展中国家,“非常满意”的比例相对较低。然而,现在就断定这是数据领域的一个特殊现象还为时过早。相反,无论在哪个领域,发展中国家“非常满意”的比例较低可能是一个普遍现象。

图 13。不同国家的工作满意度分布。注意,为了简单起见,我们在建模步骤中没有使用 Country 作为特征。国家是一个高基数特性,应该使用更高级的编码技术,而不是简单的一次性编码。图片作者。
3.2.使用 XGBoost 的多分类
这里我们通过检查混淆矩阵跳到模型性能。我们的模型有两个观察结果:
- 尽管在建模步骤中已经应用了几种技术来解决过拟合问题,但是模型仍然存在过拟合问题;
- 该模型可以在合理的水平上正确地预测辅修课,尽管将实例预测为“非常满意”和“稍微满意”会产生许多错误。
- 该模型被“非常满意”和“稍微满意”所混淆(图 14,右)。

图 14。用混淆矩阵模拟性能。左图:训练数据的混淆矩阵。右图:测试数据的混淆矩阵。图片作者。
当然,该模型还有改进的空间,但是与使用朴素贝叶斯的基线模型相比,该模型的性能相当好,我在这里没有展示。此外,数据集本身可能具有挑战性,因此无论如何难以学习一般模式(即,过拟合问题)。
3.3.模型可解释性和洞察力
为了理解模型并获得更多的洞察力,让我们检查在树构建过程中计算的顶部特征(图 15)。
一位热编码的使用给解释带来了一些不便,因为原始特征现在被分解成多个二进制特征。最重要的两个特征是关于“NEWOnboardGood”的:“NEWOnboardGood_1”表示“是”回答“你认为你的公司有好的入职流程吗”的问题,“NEWOnboardGood_2”表示“否”。显而易见,良好的入职流程通常与高工作满意度相关。
我们也把“本科生专业”剧看作是继“NEWOnboardGood”之后的一个重要特色。事实上,模型从数据中学到的是:
- 如果应答者有自然科学本科专业(如生物、化学、物理等。),更有可能是他们“非常满意”;
- 对于本科专业为其他工程学科(如土木、电气、机械等)的响应者也是如此。)
“Bash/Shell/PowerShell”这个特性很有趣,使用“Bash/Shell/PowerShell”作为编程语言之一的应答者比不使用它的应答者更有可能“非常满意”。至少这是模型从数据中学到的。

图 16。在 XGBoost 的树构建过程中通过 gain 计算的特征重要性。图片作者。
我们可以使用 SHAP ,一个非常通用的模型解释工具,来更好地理解模型行为。鼓励您在笔记本中探索更多内容。在这里,我将向您展示基于 SHAP 价值观的主要特征,并发布两个工资和公司规模相关性图的示例。
首先,我们将看到由 SHAP 值给出的顶部特征(图 17)不同于从节点分裂期间的信息增益计算的那些(图 16)。SHAP 值方法被认为更符合评估特征重要性(见 SHAP 论文参考)。在这里,最靠前的特征是“薪水”、“NEWOnboardGood_1”、“年龄”、“YeasCode”、“OrgSize”,在我看来比较符合常识。

图 17。与图 16 中来自信息增益的特征相比,来自 SHAP 值的顶部特征。从 0 到 4 级:“既不满意也不不满意”、“稍微不满意”、“T2”、“稍微满意”、“非常不满意”、“非常满意”。图片作者。

图 18。工资的 SHAP 依赖图。图片作者。

图 19。公司规模的 SHAP 依赖图。OrgSize 的映射是:{1:'只有我—我是自由职业者、个体经营者等。',2: '2 到 9 名员工',3: '10 到 19 名员工',4: '20 到 99 名员工',5: '100 到 499 名员工',6: '500 到 999 名员工',7:' 1000 到 4999 名员工',8:' 5000 到 9999 名员工',9:' 10000 或以上员工',-1:'缺少' }。图片作者。
图 18 中的 SHAP 依赖图告诉我们,如果一个实例“非常满意”,工资将如何有助于预测。我们可以看到,总的来说,更高的工资将有助于预测实例更有可能“非常满意”,因为增加的趋势表明。
对于公司规模而言,较小的规模往往对预测“非常满意”做出积极贡献(图 19)。
结论
在本文中,我们使用堆栈溢出调查数据做了一些探索性分析,并对数据领域有了一些了解。
- 我们分析了不同数据角色的薪酬分布,并考虑了其他因素,如国家、经验年限、性别。
- 我们对比了 2019 年的调查数据和 2020 年的数据。令人惊讶的是,数据相关工作的薪水和工作满意度都有所下降。
- 最后,我们建立了一个 XGBoost 多分类模型来预测工作满意度,并通过检查特征的重要性和依赖关系来提取对工作满意度的一些见解。
本文中的分析和建模更多的是出于实践目的,没有进一步的研究就不能得出可靠的结论。最重要的是,堆栈溢出调查数据本身可能有偏差,不一定代表真实世界的人口。我希望你能从这篇文章中找到乐趣。要查看更多技术细节,请参考 GitHub 库。
Salesforce 数据科学家编写面试问题
原文:https://towardsdatascience.com/salesforce-data-scientist-coding-interview-questions-6dad64c4a85f?source=collection_archive---------27-----------------------
在本文中,我们将涵盖您可能会在 Salesforce 上被问到的最重要的数据科学家编码面试问题。如果你准备去面试一个数据科学家的职位,你必须知道这些问题。

由塞巴斯蒂安·赫尔曼在 Unsplash 上拍摄的照片
Salesforce 是一家软件公司,也是客户关系管理(CRM)平台的提供商。它提供了广泛的基于云的解决方案,以改善和简化公司及其客户之间的合作。Salesforce 是一家全球性公司,总部位于旧金山,在全球 29 个国家设有办事处。2021 年,根据员工完成的调查,Salesforce 在《财富》杂志的“100 家最适合工作的公司”中排名第二。
Salesforce 的数据科学家角色
Salesforce 雇佣了许多数据科学家和数据工程师,分布在许多地点和团队,每个人通常负责一个产品。虽然每个职位的具体情况因团队而异,但许多数据专家都致力于解决一些问题,如预测业务指标、为客户群和参与度建模,以及通过对结构化和非结构化数据执行分类和聚类来创造有意义的客户体验。此外,他们可能开发端到端的数据产品,审查和更新现有数据,或者建立和维护机器学习管道。
Salesforce 的数据科学家或数据工程师通常期望的堆栈包括 SQL(通过 PostgreSQL)、Python(带有 Pandas 和 Sklearn)和 Spark。此外,候选人应该具备机器学习、项目生命周期、性能监控和软件测试方面的知识。Salesforce 还广泛使用 Docker、AWS 或 Airflow 等技术。
在 Salesforce 数据科学家编码面试问题中测试的技术概念

作者在 Canva 创建的图像
本文讨论了最近 Salesforce Data Scientist 面试中候选人被问到的一些 SQL 问题。传统上,Salesforce 的 SQL 面试问题相当多样化,涵盖的主题包括将单个数据点与平均值进行比较(AVG)、计算每个时间段的出现次数(计数、提取)、根据标准查找数据(HAVING、MAX/MIN、greater/low than 等)。)、排序(ORDER BY)、查找重复项(DISTINCT)或连接表(JOIN)。
然而,最近大多数候选人面临着基于同一张简单表格的各种面试问题。Salesforce 数据科学家面试问题与及时分析用户参与度的变化有关。在本文中,我们将分析这个最近的数据集,并讨论您可能会被问到的问题的解决方案。
Salesforce 数据科学家面试问题 1:用户增长率
我们被要求找出每个账户从 2020 年 12 月到 2021 年 1 月的活跃用户增长率。我们获悉,增长率定义为 2021 年 1 月的用户数除以 2020 年 12 月的用户数。我们应该编写一个 SQL 查询,只输出 account_id 和增长率。

截图来自 StrataScratch
可以在这里看到这个 Salesforce 数据科学家面试问题,自己练习解答:https://platform . stratascratch . com/coding/2052-user-growth-rate?python=
为了回答这个问题,我们提供了一个简单的数据表“sf_events”。
以下是数据的一个示例:

截图来自 StrataScratch
如我们所见,只有 3 列。列“date”的类型为“datetime ”,它表示某个用户处于活动状态的时间。其他列“account_id”和“user_id”的类型为“varchar ”,允许唯一标识某个帐户的用户。在本例中,有 3 个帐户(A1、A2 和 A3),每个帐户可能有几个用户。
要回答这个 Salesforce 数据科学家访谈问题,我们需要处理此表中的数据,最终目标是计算每个客户的增长率。该解决方案有 3 个主要步骤:
- 对于每个月,创建一个新表,其中包含给定月份中每个帐户的活动用户数;
- 使用内部联接合并所有月份的表;
- 对于每个帐户,用 1 月的用户数除以 12 月的用户数(增长率)。
在这个例子中,我们感兴趣的是两个月:2020 年 12 月和 2021 年 1 月。让我们从 2020 年 12 月开始,只看用户参与度来解决这个问题。我们希望返回每个帐户在本月活跃的用户数量。因此,我们可以从写:
SELECT account_id,
count(DISTINCT user_id) AS dec_count
FROM sf_events
GROUP BY account_id
这将返回两列:“account_id”和该帐户中处于活动状态的用户数,我们称之为“dec_count”。由于 GROUP BY 语句,每行将包含一个不同的“account_id”。此外,在 COUNT 语句中使用 DISTINCT 语句非常重要,因为我们只对活动用户的数量感兴趣,而不是他们活动的次数。然而,上面的查询将返回所有月份的用户总数,另一方面,我们只对 2020 年 12 月感兴趣。因此,有必要使用 WHERE 添加一个约束,并利用列“date”的类型为“datetime”这一事实:
WHERE EXTRACT(MONTH
FROM date) = 12
AND EXTRACT(YEAR
FROM date) = 2020
包含上面的代码将成功地按日期过滤用户参与度,并将返回 2020 年 12 月的相关值。为了能够在以后重用该查询,我们可以将其视为子查询,并将其命名为' dec_2020 '。此外,我们可以编写一个类似的代码来计算从 2021 年 1 月开始的用户数量,并将其命名为' jan_2021 '。关键的区别在于 WHERE 语句——需要替换代表月份和年份的数字。
dec_2020 AS
(SELECT account_id,
count(DISTINCT user_id) AS dec_count
FROM sf_events
WHERE EXTRACT(MONTH
FROM date) = 12
AND EXTRACT(YEAR
FROM date) = 2020
GROUP BY account_id),
jan_2021 AS
(SELECT account_id,
count(DISTINCT user_id) AS jan_count
FROM sf_events
WHERE EXTRACT(MONTH
FROM date) = 1
AND EXTRACT(YEAR
FROM date) = 2021
GROUP BY account_id)
有了这个,我们就能计算增长率了。为此,我们首先需要组合子查询‘dec _ 2020’和‘Jan _ 2021’产生的表。我们将使用 INNER JOIN 来仅包括在两个月中有任何用户活动的帐户,否则没有增长率可计算。
再次查看面试问题以了解结果应该以什么格式返回也很重要,在本例中为:“输出 account_id 和增长率”。因此,我们将选择“account_id ”,然后按如下方式计算增长率:jan_count / dec_count。由于使用了内部连接,我们可以从两个子查询中的任何一个中选择列‘account _ id’。至于增长率,我们还是确保以浮点数的形式返回吧。使用 AS 语句为这个新列命名也是一个好习惯。
SELECT jan_2021.account_id,
jan_count / dec_count::float AS growth_rate
FROM jan_2021
INNER JOIN dec_2020 ON jan_2021.account_id = dec_2020.account_id
我们现在已经涵盖了构建 Salesforce 的这个数据科学编码面试问题的解决方案所需的所有步骤。仍然需要将这些步骤结合起来,以创建产生预期输出的最终查询。将两个子查询“dec_2020”和“jan_2021”与上面的查询组合起来的一个简单方法是使用 with 语句。最终的解决方案如下所示:
WITH dec_2020 AS
(SELECT account_id,
count(DISTINCT user_id) AS dec_count
FROM sf_events
WHERE EXTRACT(MONTH
FROM date) = 12
AND EXTRACT(YEAR
FROM date) = 2020
GROUP BY account_id),
jan_2021 AS
(SELECT account_id,
count(DISTINCT user_id) AS jan_count
FROM sf_events
WHERE EXTRACT(MONTH
FROM date) = 1
AND EXTRACT(YEAR
FROM date) = 2021
GROUP BY account_id)
SELECT jan_2021.account_id,
jan_count / dec_count::float AS growth_rate
FROM jan_2021
INNER JOIN dec_2020 ON jan_2021.account_id = dec_2020.account_id

截图来自 StrataScratch
注意,有多种方法可以编写这个查询。现在,您可以想出自己的代码,并提交到我们的平台上,以接收其他用户的反馈。请务必查看其他人提交的解决方案,以获得更多灵感。
Salesforce 数据科学家面试问题 2:连续几天
让我们看看另一个 Salesforce 数据科学家面试问题,它使用了相同的数据集,但提出了不同的挑战。在这种情况下,我们被要求查找所有连续 3 天或更长时间处于活动状态的用户。我们得到了与问题 1 中完全相同的数据表。

截图来自 StrataScratch
链接到此 Salesforce 数据科学家面试问题:https://platform . stratascratch . com/coding/2054-连续-天?python=
尽管这个面试问题很短,但实际上,这个任务比前一个案例更棘手。虽然可以使用一个相当短的查询来解决这个问题,但是困难的部分是如何从一个排序的表中提取连续的日期。仅这项任务就需要更高级的 SQL 函数和语句的知识。解决方案应遵循以下一般步骤:
- 仅查询“user_id”和“date”列,并按升序排序;
- 使用 ROW_NUMBER()函数按日期分别对每个用户的数据进行排序
- 通过从事件日期中减去等级,只留下连续的日期来过滤结果;
- 仅选择这些在过滤结果中至少出现 3 次的不同用户 id。
Salesforce 数据科学家面试问题 3:保留率
这是另一个问题,我们得到了与问题#1 和问题#2 相同的数据集。然而,这一次我们被要求分别找出 2020 年 12 月至 2021 年 1 月每个账户的逐月用户保留率。我们被告知,保留率是一个企业在给定时间内保留用户的百分比。我们可以假设,如果用户在未来几个月继续使用该应用程序,他就会被保留下来。此外,我们给出了一个例子:如果用户在 2020 年 12 月是活跃的,并且在接下来的一个月(2021 年 1 月)或未来的任何其他月份也是活跃的,则他被保留到 2020 年 12 月。最后,我们被告知输出应该包含 account_id 和 2021 年 1 月的保留率除以 2020 年 12 月的保留率。

截图来自 StrataScratch
链接到这个 Salesforce 数据科学家面试问题:https://platform . stratascratch . com/coding/2053-retention-rate?python=
这个问题的解决方案不需要很高的 SQL 水平,但是,它需要使用 CASE 语句的知识。在这种情况下,最终查询也会相对较长,因为在输出最终结果之前需要执行多个子查询。以下是解决方案应该遵循的步骤:
- 对于每个月,查询给定月份中活动的用户及其帐户;这与问题 1 的第一步非常相似;
- 对于每个用户,检查他们活动的最后日期;
- 计算每个月的保留率:计算每个帐户在给定月份中活跃的用户数,以及他们活跃的最后日期发生在本月之后的用户数;
- 将月留存率表示为百分比,即留存用户数除以一个账户中的所有用户数,再乘以 100;
- 按照问题:对于每个客户,将 2021 年 1 月的留存率除以 2020 年 12 月的留存率来调整输出。
Salesforce 数据科学家面试问题 4:不同货币的总销售额
尽管 Salesforce 的大多数最新数据科学家面试问题都集中在我们在之前的问题中看到的简单数据表上,但我们已经收到了用于构建面试任务的另一个数据集的报告。
让我们来考虑一下这个问题,假设你在一家跨国公司工作,该公司希望计算他们开展业务的所有国家的总销售额。有两个表,一个是公司处理的所有国家和货币的销售记录,另一个保存货币汇率信息。任务是计算 2020 年前两个季度每季度的总销售额,并以美元货币报告销售额。

截图来自 StrataScratch
此问题链接:https://platform . stratascratch . com/coding/2041-不同币种总销售额?python=
问题中提到,这次有两个表有数据。保存货币汇率信息的表名为“sf_echange_rate ”,有 4 列,而包含销售记录的表名为“sf_sales_amount ”,有 3 列。查看数据类型和数据示例:
顺丰 _ 汇率

截图来自 StrataScratch
顺丰 _ 销售 _ 金额

截图来自 StrataScratch
虽然这个问题的解决方案并不特别困难,但以汇率日期和销售日期相匹配的方式正确连接这两个表是至关重要的。要实现这一点,并报告每个季度的值,了解 DATE_PART()函数是很有用的,它可以很容易地从 datetime 类型中提取重要信息。该解决方案应遵循以下步骤:
- 联接两个表,使“source_currency”与“currency”匹配,并且“date”中的月和年与“sales_date”中的月和年匹配;
- 按季度对日期进行分组,并对每个日期进行求和,得出“销售额”乘以正确的汇率。
- 通过仅保留 2020 年的前两个季度来过滤结果。
结论
我们希望这篇文章通过关注 Salesforce 使用的最新数据科学家面试问题对准备面试有所帮助。如果您在解决这些任务时遇到困难,请在我们的平台上随意浏览 Salesforce 访谈中的所有 SQL 问题。使用“方法提示”功能来显示解决问题的一般步骤,并与其他用户讨论您的代码,以获得更多的见解和反馈。您还可以找到本文中描述的所有问题的完整查询。在练习使用来自 Salesforce 的真正的 SQL 问题后,您应该有适当的准备来面对面试中的技术问题!
最初发表于T5【https://www.stratascratch.com】。
使用 PyTorch 可视化深度学习模型的显著图
原文:https://towardsdatascience.com/saliency-map-using-pytorch-68270fe45e80?source=collection_archive---------7-----------------------
通过查看深度学习模型的梯度来解释深度学习模型的结果。

丹尼·米勒在 Unsplash 上的照片
动机
当我们使用逻辑回归或决策树等机器学习模型时,我们可以解释哪些变量对预测结果有贡献。但是,当我们使用深度学习模型时,这一步会很困难。
深度学习模型是一个黑箱模型。这意味着我们无法分析模型如何根据数据预测结果。随着模型变得越来越复杂,模型的可解释性会降低。
但这并不意味着模型不可解读。我们可以推断深度学习模型,但我们必须研究它的复杂性。
在本文中,我将向您展示如何基于梯度可视化深度学习模型结果。我们称这种方法为显著图。我们将使用一个名为 PyTorch 的框架来实现这个方法。
事不宜迟,我们开始吧!
显著图
在进入显著图之前,先说一下图像分类。给定这个等式,

在哪里,
- Sc(I)是 c 类的分数
- I 对应于图像(在一维向量上)。
- w 和 b 对应于 c 类的重量和偏差。
从等式中可以看出,我们将图像向量(I)与权重向量(w)相乘。我们可以推断,权重(w)可以定义图像上的每个像素对类(c)的重要性。
那么,我们如何得到对应于给图像(I)的分数(S)的权重(w)?我们可以通过看梯度得到那些变量之间的关系!
但是等等,梯度到底是什么?我不想在上面解释那么多微积分,但我会告诉你这个。
梯度描述了一个变量(比如 x)对另一个变量(比如 y)的影响程度。
当我们使用该类比时,我们可以说梯度描述了图像(I)的每个像素对预测结果的贡献有多强。寻找权重(w)的等式看起来像这样,

通过知道每个像素的权重(w ),我们可以将其可视化为显著图,其中每个像素描述了该像素影响预测结果的能力。
现在,让我们开始实施吧!
实施
在本节中,我们将使用 PyTorch 实现显著图。我们将使用的深度学习模型已经为名为“植物病理学 2020”的 Kaggle 竞赛进行了训练。要下载数据集,您可以通过链接访问此处。

这是我们必须要做的步骤,
- 建立深度学习模型
- 打开图像
- 预处理图像
- 检索梯度
- 想象结果
现在,我们要做的第一件事是建立模型。在这种情况下,我将使用 ResNet-18 架构使用我的预训练模型权重。此外,我已经建立了模型,所以我们可以使用 GPU 来获得结果。代码看起来像这样,
在我们建立模型之后,现在我们可以建立图像。为此,我们将使用 PIL 和 torchvision 库来转换图像。代码看起来像这样,
在我们转换图像后,我们必须对其进行整形,因为我们的模型读取 4 维形状(批量大小、通道、宽度、高度)上的张量。代码看起来像这样,
**# Reshape the image (because the model use
# 4-dimensional tensor (batch_size, channel, width, height))**
image = image.reshape(1, 3, 224, 224)
在我们重塑图像之后,现在我们将图像设置为在 GPU 上运行。代码看起来像这样,
**# Set the device for the image**
image = image.to(device)
然后,我们必须设置图像捕捉梯度时,我们做反向传播。代码看起来像这样,
**# Set the requires_grad_ to the image for retrieving gradients**
image.requires_grad_()
之后,我们可以通过将图像放在模型上并进行反向传播来捕捉梯度。代码看起来像这样,
现在,我们可以使用 matplotlib 可视化梯度。但是有一项任务我们必须完成。该图像有三个通道。因此,我们必须在每个像素位置上从这些通道中取最大值。最后,我们可以使用如下所示的代码来可视化结果,
这是可视化的样子,

从上图可以看出,左边是图像,右边大小是显著图。回想一下它的定义,显著图将显示每个像素对最终输出贡献的强度。
在这种情况下,这张图片上的叶子有一种叫做锈病的疾病,你可以在它上面的黄色斑点上看到。如果你仔细观察,有些像素的颜色比其他任何图像都要亮。说明那些像素对最终结果的贡献巨大,就是铁锈本身。
因此,我们可以自信地说,通过查看模型的正确信息,模型已经预测了结果。
结论
干得好!现在,您必须实现自己的显著图来解释您的深度学习模型。希望大家能针对自己的案例实现显著图,别忘了关注我 Medium!
如果你想和我讨论数据科学或机器学习,你可以在 LinkedIn 上联系我。谢谢你看我的文章!
参考
[1] Simonyan K,Vedaldi A,Zisserman A. 2014。卷积网络深处:可视化图像分类模型和显著图。arXiv:1312.6034v2 [ cs。简历
【2】拉斯托吉 A. 2020。使用 PyTorch 中的显著图可视化神经网络。数据驱动投资者。
【3】https://github . com/sijoonlee/deep _ learning/blob/master/cs 231n/network visualization-py torch . ipynb
SambaNova 的 6 . 76 亿美元融资
原文:https://towardsdatascience.com/sambanova-lands-676m-funding-eaa7c0571592?source=collection_archive---------20-----------------------
数据流架构及其如何影响您的 it 策略

SambaNova 是数据流架构的一个例子,它在架构上与人脑有许多相似之处。这个数字是我自己对硬件、知识图和人脑之间相似性得分的直观衡量。请注意,我将数据流与人脑的相似度评分定为 0.9。作者的作品。
本周,一家新的人工智能初创公司 SambaNova 获得了 6.76 亿美元的 D 轮融资,使其成为世界上获得资金最多的人工智能初创公司https://www.businesswire.com/news/home/20210413005263/en/SambaNova-Systems-Raises-676M-in-Series-D-Surpasses-5B-Valuation-and-Becomes-World’s-Best-Funded-AI-Startup。我的许多研究企业知识图和大规模机器学习的同事可能对资金的规模有点困惑。的确,一开始,连我都为这么小的公司获得这么大的资金而感到惊讶。然而,在研究了 SambaNova 的 40B 晶体管数据流芯片架构后,我现在明白了为什么他们的系统值得这种程度的关注。
这个博客将回顾什么是数据流架构,SambaNova 如何实现这个架构,为什么这个投资有意义,以及你需要做什么来将这个新的开发集成到你的整体 IT 策略中。
NLP 和 EKG
让我们首先回忆一下,组织中 80%以上的知识都与非结构化数据相关联。企业知识图(EKG)架构师需要像伯特和 GPT 这样的高质量定制自然语言过程(NLP)模型来:
- 从大型文档中提取统一的概念,
- 对要搜索的文档进行分类,
- 并提取特定的事实,我们可以很快整合到我们的心电图。
你的客户发来的每封电子邮件都应该在几分钟内(而不是几天内)进入你的 EKG,并直接影响他们的嵌入。这不仅是电子邮件分类,而是针对产品评论、评论,甚至社交媒体帖子。对于许多公司来说,构建高质量机器学习 NLP 模型的成本一直是首要问题。像生命科学和医疗保健这样的行业也需要专门的词汇,这些词汇不包括在 Huggingface 上托管的数千个标准 NLP 模型中。
随着上周 SambaNova 基金的宣布,这些成本障碍可能最终会变得不那么令人担忧。
声称 NLP 模型训练性能提高了一个数量级

SambaNova 图来自他们的网站这里。经 SambaNova 许可使用的图像。
让我们从 SambaNova 的说法开始:对于训练像 BERT 和 GPT 这样的大型语言模型,他们 1/4 机架的硬件比 1024 个 NVIDIA V100 GPUs 具有数量级的性能优势。当然,他们提供的网页在细节上还是有点粗略。尚不清楚他们关于“性能提高一个数量级”的说法是否与构建大型 NLP 模型(如伯特或 GPT)的时间有关,或者与购买价格或 ROI 等其他指标有关。
请注意,本页没有提到价格比较。SambaNova 可以将他们的硬件定价为$2M 克雷图形引擎级别!这仍然可以为一些需要快速模型训练时间的公司提供价值。然而,我认为这个价格会让大多数公司负担不起他们的硬件,所以让我们期待他们更好的定价吧。
让我们假设这不仅仅是营销炒作,最终,SambaNova 用独立第三方支持的可复制基准和定价来支持他们的说法。我们希望他们能让许多小公司买得起硬件。
现在让我们来看看这是如何实现的。当英伟达是全球最有价值的芯片制造商并拥有近 20,000 名员工时,一家新的创业公司(LinkedIn 上不到 200 名员工)如何创建一个具有“压倒 GPU”性能的系统?为了理解他们的说法可能是有效的,我们需要理解数据流硬件与串行 CPU 和 [SIMD](https://en.wikipedia.org/wiki/SIMD#:~:text=Single instruction%2C multiple data (SIMD,on multiple data points simultaneously.) GPU 芯片的设计有什么根本不同。回想一下,GPU 最初是为了加速视频游戏而设计的,而不是在海量深度学习数据集上执行训练。
了解异步数据流硬件

图 2:左边的全局时钟(同步)感知器电路与右边的异步数据流(未锁定)电路的比较。图片由作者提供。
20 世纪 80 年代,当我还是贝尔实验室(Bell Labs)的 VLSI 电路设计师时,我对芯片设计师为高速电信系统构建高度专业化定制芯片的不同方法非常着迷。其中一种方法是构建接收数据输入并立即将数据转换为输出的电路,而无需时钟。这些电路被称为异步数据流架构,因为它们连续不断地从输入流向输出,从不使用时钟来通知电路何时可以开始计算。
在数据流电路领域,我们使用术语“内核功能”或简称“内核”来描述诸如加法、乘法、求和或平均等功能的原子库。我们在标量、向量或多维数组上执行这些功能。
尽管数据流电路具有出色的性能特征,但它们也面临着一些设计挑战:
- 您无法确定地预测给定函数(内核单元)的输出何时有效。两个零的乘法可能很快就能完成,但两个大数的乘法可能需要更长的时间。
- 让本地化的数据流彼此协同工作并与复杂的总线逻辑协同工作是一项挑战。
因此,根据输入数据和内核之间的时序,相同输入的输出可能会有所不同。可测试性也是一个挑战。整个会议都致力于解决这些问题。这两种架构之间的差异如图 2 所示。
以下是一些关于数据流架构的事实:
- 它们没有一个单独的程序计数器——它们不是典型的冯·诺依曼架构。
- 通常不太需要中央“全局时钟”来同步电路。仍然需要全局时钟来将数据移入和移出通信总线,但它们的总体作用较小。
- 任何电路块的输出都仅取决于输入数据的可用性。这应该会提醒您纯粹的函数式编程单元。
- 当正确的结果出现在输出信号上时的精确定时是复杂的。确定这一点的电路可能会加倍复杂。
- 如果设计者能够找出同步逻辑的方法,数据流电路可以比传统 CPU 更快地实现并行数据转换。设计一个电路在结果完成时发出信号是一个不小的问题。
- 只有一小部分电路设计者接受过设计异步数据流逻辑电路的培训。
虽然同步电路已经主导了几乎所有的芯片设计,但当执行快速、有时不精确的计算时,数据流架构仍有其一席之地。问题是,它们只在需要高速并行计算性能的专业环境中更具成本效益。设计一个可以用作通用计算系统的数据流芯片并不容易。
即使你可以设计一种新的数据流芯片架构,其性能是 CPU 的 100 倍,另一个挑战是如何训练开发人员停止考虑编写过程化的 IF/THEN/ELSE 代码,并让他们考虑使用数据流解决问题。许多新创公司的商业计划不会因为缺乏硬件性能而失败。他们未能招募到足够多知道如何为芯片编程的开发人员。即使在今天,只有不到 1%的数据科学家和 Python 开发人员能够开始理解如何将超快速并行处理 FPGA 集成到他们的生产代码中。尽管 FPGAs 是一项已经存在了 30 年的成熟技术。
如果你有兴趣听最近关于数据流架构的播客,这里有一个播客,Kunle Olukotun 谈论数据流架构。奥卢科通是桑巴诺瓦的创始人之一。在这个播客中,Olukotun 谈到了在传统的冯·诺依曼“软件 1.0”解决问题的方法中,仅仅是移动数据就花费了多少能量。
深入桑巴诺瓦建筑

SambaNova 芯片架构将数据流计算单元放置在内存单元旁边,并通过高速交换机连接它们。经 SambaNova 许可使用的图像。
我可以用整个博客来深入研究 SambaNova 如何将他们的 400 亿晶体管 7 纳米 TSMC 制造的芯片划分成数据流块。简而言之,他们将内核逻辑划分为数据流内核电路,这些电路被设计成称为可重新配置数据流单元(rdu)的逻辑块。和 RDU 可以使用片上网络交换机快速重新配置。
总而言之,他们将数据流内核电路(PCU)与内存交错,并使用高速片上开关在这些单元之间移动数据。他们通过分析深度学习神经网络的静态结构,将核心功能放在 PCU 中。然后,软件将 PCU 和内存连接在一起,以最大限度地减少芯片周围的数据移动。这听起来编程起来非常复杂。幸运的是,如果你使用的是 TensorFlow 的 PyTorch,你只需要修改几行代码。
入口点:挂钩 Python 代码

SambaNova 系统的主要入口直接通过 PyTorch 和 TensorFlow。经 SambaNova 许可使用的图像。
SambaNova 系统的关键是他们如何整合所有这些数据流内核来训练你的神经网络。当你编写大多数训练神经网络的深度学习算法时,你指定了数据流的有向图的拓扑。SambaNova 截取这段代码,在其硬件中构建数据流图,并产生与使用 CPU 或 GPU 相同的结果。困难的部分是由数据流图分析器完成的,它将图转换成可以编译成硬件连接的格式。
这类似于 FPGAs 编程的相同过程。但与 FPGA 不同的是,它改变芯片中的布线,使布线在芯片上电时永久不变,SambaNova 在交换机中动态路由数据,不需要两秒钟;交换机可以在几毫秒内重新路由 RDU 的输入和输出。
进入深度神经网络的机器学习
尽管同步 von-Naumann 架构在过去 40 年中占据主导地位,但一些芯片架构师仍然认为设计数据流架构的极端挑战是可以克服的。这些工程师中的许多人都隶属于斯坦福电子工程和计算机科学系,以及由 Kunle Olukotun 领导的斯坦福普适并行实验室。
在 2018 年左右,人们也清楚地看到,对以训练深度神经网络为中心的计算有着强烈的需求。公司每年花费数百万美元训练这些网络,他们选择的工具围绕两个 Python 库:TensorFlow 和 PyTorch。这为数据流开发人员提供了一种方式来轻松中断 python 库调用并使用他们的硬件,而无需从头重写算法。现在,新的硬件开发人员只需将“钩子”构建到 Python 库中,就可以使用他们的硬件来训练神经网络。
人工智能的未来:低成本的专用 BERT 盒
当 OpenAI 宣布他们的 175B 参数 GPT-3 时,它在整个 AI 社区发出了冲击波。虽然他们没有表明他们在 GPU 上花了多少时间来训练这些庞大的模型,但我们可以推断出在 500 万美元到 1000 万美元之间。这使得使用伯特和 GPT 建立新的深度学习模型超出了大多数学术研究机构的预算范围。它还向硬件社区发出信号,表明对专门从事深度神经网络训练的硬件的需求正在增长。
现在,构建深度学习模型的大部分成本都集中在 NLP 和图形领域。BERT 和数以百计的 BERT 变体现在是最流行的需要扩展的语言模型。标准的 BERT 受到进程中输入令牌数量的限制,并且 BERT 训练成本随着输入令牌数量的增加而呈指数增长。许多公司和开源项目都关注 BERT 大型基准测试,以及在分布式 GPU 上扩展这些模型所需的巧妙技巧。
我们需要记住,SambaNova 不是第一家声称他们的硬件比传统 GPU 快一个数量级、成本低得多的公司。Graphcore 和 T2 Cerebras 已经提出这些声明好几年了。他们在公共数据集上公开发布他们的性能基准,您甚至可以尝试复制(如果您有能力购买评估硬件的话)。这就把我们带到了下一个话题:我们如何知道供应商说的是不是真话?
对客观机器学习基准的需求
任何客观的采购流程的首要规则之一是以适度的怀疑态度对待供应商发布的任何性能基准。我记得在 20 世纪 80 年代打开我的《计算机世界》杂志,看到甲骨文和赛贝斯都在整版的背靠背广告中宣称他们各自的速度比对方快十倍。他们所要做的就是调整配置文件中的几个参数来减慢对手的速度。这让我很早就认识到供应商基准是不可信的。
当你仔细阅读许多软件供应商的软件许可协议时,这个问题变得更加困难。未经书面批准发布基准测试违反了您的许可协议。一些供应商甚至拒绝给你许可证密钥来运行你自己的内部基准,我个人认为这是一种不道德的做法。
MLCommons 和 MLPerf
在机器学习领域,现在有一些小的努力来标准化机器学习基准,如 MLCommons 项目。但即使是这些“客观”的网站,有时也很容易被大型行业参与者资助的所谓独立顾问所吸收。
如果您决定尝试了解类似于 MLPerf 基准测试的基准测试,请确保了解训练和推理基准测试之间的差异,密集和稀疏数据表示之间的差异,以及 SIMD 硬件非常适合密集矩阵问题(如图像)但可能不适合稀疏问题(如 NLP、BERT 和图形卷积)的事实。
获得原始执行速度来训练大型深度神经网络只是第一步。下一步是了解进行这种计算的长期成本和投资回报率。许多软件优化可以降低训练成本和推理成本。知道您的组织中有多少人将来会需要这种类型的硬件也是很难预测的。尽管云服务提供商都很乐意向你出售 GPU 时间,但他们可能不会对你探索创新的新机器学习硬件感兴趣。
带回家的点数
你真的不需要知道数据流架构是如何工作的。但你确实需要知道,它们可能会完全颠覆机器学习市场和现有 GPU 硬件的价值。这里有几点可以带回家:
- 如果你每月花费超过 5 万美元来训练你的机器学习模型,请考虑这些新的硬件选项。
- 如果你还在用“R”和 SAS 做数据科学,考虑到新一代硬件厂商只会支持 TensorFlow 和 PyTorch 这样的 Python 库。现在可能是重新培训你的员工的好时机。
- 如果你正准备购买大量的 GPU 来进行深度学习,可以考虑租赁它们,这样一年后你就可以升级到专门的深度计算机硬件。
- 如果您目前拥有大量 GPU,请考虑在它们过时之前将其出售。GPU 可能很快就会成为数据中心中贬值最快的组件之一。
- 如果您正在使用云服务提供商(CSP ),请询问您的 CPS 是否有计划来帮助您评估低成本的 BERT boxes 及其同类产品。
- 如果你想要更快和更低成本的推理,考虑低成本的硬件选项,比如可以在两秒钟内重新编程的 FPGAs。正如奥卡姆剃刀教导我们的那样,有时最简单的解决方案就是最好的解决方案。
- 不要盲目相信供应商的基准。在您自己的数据中心对您自己的数据进行基准测试。在进行基准测试时,要考虑所有因素,包括网卡和交换机的成本。
- 如果您看到您的供应商做出不公平的声明,在 Twitter 上发布您的内部基准测试结果之前,请检查您的许可协议。
- 拒绝与不允许你客观评估他们的主张的供应商合作。请他们将代码发布在 GitHub 等公共源代码库上。
- 支持开放透明的机器学习基准。
摘要
SambaNova 的资助声明并不孤立。许多新公司正在构建定制的硅硬件,以帮助降低计算成本。从 Raspberry Pi 的 RS2040 到英特尔 PIUMA 图形加速器,每个人都在行动,半导体行业颠覆的时机已经成熟。我们期待在这些新系统上运行客观的基准测试!
样本高效人工智能
原文:https://towardsdatascience.com/sample-efficient-ai-4380739eda7c?source=collection_archive---------28-----------------------
播客
高阳关于制造学习速度和人类一样快的人工智能
苹果 | 谷歌 | SPOTIFY | 其他
编者按:TDS 播客由杰雷米·哈里斯主持,他是人工智能安全初创公司墨丘利的联合创始人。每周,Jeremie 都会与该领域前沿的研究人员和商业领袖聊天,以解开围绕数据科学、机器学习和人工智能的最紧迫问题。
从历史上看,人工智能系统学习速度很慢。例如,计算机视觉模型通常需要看到数万个手写数字,才能区分 1 和 3。即使是玩游戏的人工智能,如 DeepMind 的 AlphaGo,或其最近的后代 MuZero,也需要比人类更多的经验来掌握特定的游戏。
因此,当有人开发出一种算法,可以像人类一样快地达到人类水平的性能时,这是一件大事。这就是为什么我邀请高阳和我一起参加本期播客的原因。杨是伯克利大学和清华大学的人工智能研究人员,他最近与人合著了一篇论文,介绍了 EfficientZero:一种强化学习系统,在短短两个小时的游戏体验后,就学会了在人类层面上玩雅达利游戏。这是采样效率的巨大突破,也是开发更通用、更灵活的人工智能系统的重要里程碑。
以下是我在对话中最喜欢的一些观点:
- 自 AlphaGo 以来,人工智能研究人员已经认识到将强化学习与搜索方法相结合的前景,这涉及到考虑许多潜在的下一步行动,并在选择一个行动之前模拟它们的结果。通过明确地将“规划”的元素引入 RL 范式,这开始更紧密地模仿人类的思考。杨将 AlphaGo、AlphaZero 和 MuZero 的巨大性能提升归功于这一搜索过程。
- RL 中的另一个重要区别是基于模型的系统和无模型系统之间的区别,前者构建环境的显式模型,后者不构建。在 AlphaGo 之前,几乎所有领先的 RL 工作都是在无模型系统上完成的(例如,PPO 和深度 Q 学习)。基于模型的系统是不实际的,因为学习环境建模是困难的,并且在更简单的动作选择任务之上增加了一个重要的复杂性层,而无模型系统可以专门关注该任务。但现在,计算资源和一些新的算法技巧已经可用,基于模型的系统正迅速成为更灵活、能力越来越强的选择。
- DeepMind 的 MuZero 是迈向实用的基于模型的 RL 的重要一步。MuZero 被设计用来玩各种视频游戏,使用屏幕上的像素作为输入。然而,与它的前辈不同,它构建的游戏环境模型并没有试图预测每个游戏中的像素在未来的时间步骤中会如何变化。相反,它将游戏环境映射到一个潜在的空间,压缩游戏的表示,使其只包含相关信息。这种更低维度的表示方式使得预测未来时间步骤中游戏环境的显著特征变得更加容易,也更加符合人类学习玩游戏的方式:例如,当我们踢足球时,我们不会跟踪球场上的每一片草,或者每个球员脸上的表情——我们维护着一个非常精简的竞技场心理模型,其中包括一些细节,如球员的位置、球的位置和速度等。
- EffcientZero 在很多方面对 MuZero 进行了改进。首先,它能够考虑假设的形式,“如果我执行动作 X,未来会是什么样子?”这种能力是通过自我监督的学习过程开发的,在这个过程中,EfficientZero 利用其过去关于环境对类似行为的反应方式的经验。
- 其次,EfficientZero 还提出了所谓的“混淆问题”(aliasing problem),这是强化学习中一个众所周知的问题,因为 RL 代理的环境模型通常被设计为预测关键事件将发生的准确时间步长(例如,足球将飞入球门的精确视频帧)。但这种精确度并不是必需的,事实上是适得其反的,因为它会导致过度敏感的学习信号:即使一个智能体的环境模型几乎一切都正确,但它的预测却差了几分之一秒,它最终也不会得到任何奖励!EfficientZero 通过粗粒度化时间维度来纠正这一点,确保模型因预测“足够接近实际目的”而得到奖励。再一次,这背后有一个与人类学习的强大类比:好的老师会给学生一个问题的大部分正确的部分分数,而不是提供二进制的 100%/0%分数。这给了学生更多的信号去抓住,也避免了过度适应没有实际意义的细节层次。
- 如何将 EfficentZero 的样本效率与人类的样本效率进行比较还不是很明显。EfficientZero 论文中分享的方法是让一群人玩一系列不同的 Atari 游戏,两小时后查看他们的中值或平均分数,并将其与 EfficientZero 在相同的游戏时间内训练后的表现进行比较。虽然这种策略确实使 EfficientZero 优于人类,但它几乎肯定低估了 EfficientZero 的实际样本效率。杨认为,从某种意义上来说,一个第一次玩雅达利游戏的 8 岁儿童,一生都在为这个游戏做准备(训练)——掌握因果关系,甚至是帮助他们在游戏中导航的文化线索,即使他们以前没有见过这个游戏。另一方面,EfficientZero 每次推出新游戏时,都必须从头开始学习。
你可以在推特上关注杨。

章节:
- 0:00 介绍
- 杨背景 1:50
- 6 点穆泽罗的活动
- 13:25 穆泽罗到效率零点
- 19:00 样品效率比较
- 23:40 利用算法调整
- 27:10 进化对人脑和人工智能系统的重要性
- 35:10 的人工采样效率
- 38:28 AI 在中国的生存风险
- 进化和语言
- 49:40 总结
样本群体—对象-角色建模
原文:https://towardsdatascience.com/sample-populations-object-role-modeling-870f964e6a94?source=collection_archive---------38-----------------------
人口抽样变得容易
对象-角色建模(ORM)是一种图形概念建模技术,主要用于数据库分析和设计,但也可用于任何你想记录或定义数据结构的情况。
下面是一个典型的对象-角色模型:

对象-角色模型。图片作者。
上面的 ORM 模型表明,在我们的话语世界 (UoD)中,每个人都由他们的 Person_Id 唯一标识,具有唯一的名和姓组合以及唯一的昵称。
事实类型下的方框是样本总体。在我们的 UoD 中,凯莉·斯隆有一个人名为 1 ,名为凯莉,姓为斯隆,昵称为凯尔。
这是否使对象-角色建模,或者使你能够绘制 ORM 模型的软件,成为一个数据库?
不一定。样本总体被引入 ORM,以允许建模者测试模型,看它是否适合目的。例如,如果我们将一个名字为 Steven 但是名字为 并且 personId 为 1 的人引入到我们的模型中,我们的内部唯一性约束表明每个人只有一个名字(在事实类型中,Person 有名字),那么就违反了唯一性约束。现在请注意,在我们的软件中,事实类型以红色突出显示(即包含错误),错误通过样本总体中 PersonId,1 的两个实例也以红色突出显示来指示。

样本总体中包含错误的对象-角色模型。图片作者。
乍一看,这似乎很简单,但这就是样本总体的全部意义……它们可以用来表明一个观点,并在创建数据模型时帮助解决问题。
例如,以下面的对象角色模型为例。它为库存管理解决方案对存储在仓库箱柜中的零件进行建模:

库存管理解决方案的对象-角色模型。图片作者。
StockedItem 事实类型中的唯一性约束是针对 Part 和 warehouse 所扮演的角色的,这表明在我们的 UoD 中,Part 只存储在 Warehouse 中的一个 bin 中。
为了帮助设想模型,下面的图片显示了一名员工在仓库的一个箱子里伸手拿零件:

一名仓库保管员在仓库的箱子里寻找零件。图像通过 Dreamstime.com 授权给维克多摩根特。ID 102810076 七十四张图片| Dreamstime.com
但是,如果箱柜不够大,无法存储仓库中一种零件类型的所有库存,该怎么办?在这种情况下,我们可以选择将相同的零件存放在同一仓库的多个箱子中。
我们的模型不支持这一点,所以当我们创建一个表达我们的新需求的样本群体时,错误显示在我们的对象-角色建模软件中:

对象-角色模型中样本总体的错误。图片作者。
为了解决这个问题,我们将内部唯一性约束扩展到 cover、Part、Warehouse 和 Bin,消除了样本总体中的错误。

解决样本总体错误的对象-角色模型。图片作者。
对象-角色建模中的样本总体就是这么简单。它们是帮助你分析和解决概念模型的工具。
感谢您的阅读,如果时间允许,我会写更多关于对象-角色建模和概念建模的内容。
— — — — — — — — — — — — — — — — — — — — — — — — -
使用 Python 对分布进行采样
原文:https://towardsdatascience.com/sampling-distributions-with-python-f5a5f268f636?source=collection_archive---------2-----------------------
用 Python 实现大学统计
介绍
在一系列的每周文章中,我将涉及一些重要的统计学主题。
目标是使用 Python 来帮助我们获得对复杂概念的直觉,从经验上测试理论证明,或者从零开始构建算法。在本系列中,您将会看到涵盖随机变量、抽样分布、置信区间、显著性检验等主题的文章。
在每篇文章的最后,你可以找到练习来测试你的知识。解决方案将在下周的文章中分享。
迄今发表的文章:
- 伯努利和二项随机变量与 Python
- 用 Python 从二项式到几何和泊松随机变量
- 用 Python 实现样本比例的抽样分布
- Python 的置信区间
- 使用 Python 进行显著性测试
- 用 Python 进行组间差异的双样本推断
- 分类数据的推断
- 高级回归
- 方差分析— ANOVA
像往常一样,代码可以在我的 GitHub 上找到。
抽样分布
我们经常发现自己想要估计一个总体的参数,例如,它的均值或标准差。通常,我们无法从总体人群中收集数据。在这种情况下,我们估计总体参数的唯一方法是从总体中随机抽样。我们定义样本的大小 n 并计算每个样本的统计量。这个统计量是我们用来计算总体参数的。请注意,我们为每个随机样本计算的统计数据可能与总体值相差很远,因为它是一个随机样本。这就是为什么我们要多次执行这个过程,我们称之为试验。
让我们定义一个简单的例子。我们有 100 名运动员,他们的球衣号码从 0 到 99 不等。首先,我们计算总体、和σ的参数。
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import bernoulli, norm, poisson
from scipy import stats
from scipy.stats import kurtosis, skew
import seaborn as snsX = np.random.choice(np.arange(0, 100), 100, replace=False)
print(f'μ={X.mean()}')
print(f'σ={X.std()}')μ=49.5
σ=28.86607004772212
我们随机抽取 100 个大小为 5 的样本。
rs = []
for i in range(100):
rs.append(np.random.choice(X, 5))
rs = np.array(rs)# 5 examples of our random samples
rs[:5]array([[87, 73, 61, 91, 99],
[10, 5, 46, 72, 92],
[ 1, 3, 7, 59, 88],
[ 1, 42, 87, 21, 42],
[65, 9, 54, 88, 67]])
对于每一个,我们计算一些统计数据;在这种情况下,样本意味着 x̄.因此,x̄是 100 个值的数组(每个样本的平均值)。让我们打印前 5 个值,然后绘制一个直方图,以便更好地理解抽样分布的形状。事实上,这是样本量等于 5 时样本均值的采样分布。
x_bar = rs.mean(axis=1)
print(x_bar[:5])
plt.hist(x_bar, bins=100);[82.2 45\. 31.6 38.6 56.6]

图 1:样本大小为 5 时样本均值的抽样分布直方图。
样本比例的抽样分布
我们将通过创建两个随机变量(RV)来开始这一部分,一个伯努利 RV 和一个二项式 RV(如果您不熟悉细节,请参见本系列中我以前的文章)。

图 2:《瑞克和莫蒂》是一部动画系列片,讲述了一位超级科学家和他不太聪明的孙子的故事。
手头的问题如下,有 20,000 个不同的宇宙,里克和莫蒂生活在其中,我们想计算如果我们访问一个随机的宇宙,我们可以找到莫蒂的比例。设 X 为如下伯努利 RV:

我们已经在过去的文章中看到

和

现在,我们定义一个新的 RV,它等于 X 的 10 次独立试验的总和。这是一个二项式 RV

现在是时候访问一些宇宙,并在那里随机寻找莫迪了。想象一下,我们每次访问 10 个宇宙,这确实是我们从宇宙总体中抽取的样本。请注意,我们可以认为这些样本是独立的,即使我们为 10 个样本选择了不同的宇宙。这是因为与总体相比,样本数量非常少。事实上,有一个 10%的规则,假设在没有从一定规模的人口中替换的随机抽样中的独立性。
该去找莫蒂了。
p = 0.6
n = 10
X = bernoulli(p)
Y = [X.rvs(n) for i in range(10000)]plt.hist(np.sum(Y, axis=1));

图 Morty 搜索的抽样比例的抽样分布直方图。
这就是抽样比例的抽样分布。如何计算它的均值和标准差?您的样本比例的期望值是我们在访问中发现的死亡比例,显示了总体参数的无偏估计。同理,样本比例的标准差就是我们的二项随机变量 Y 除以 n 的标准差。

print('Empirically calculated expected value: {}'.format(np.mean(np.mean(Y, axis=1))))
print('Theoretical expected value: {}'.format(p))Empirically calculated expected value: 0.5977399999999999
Theoretical expected value: 0.6print('Empirically calculated standard deviation: {}'.format(np.std(np.mean(Y, axis=1))))
print('Theoretical standard deviation: {}'.format(np.sqrt(p*(1-p)/n)))Empirically calculated standard deviation: 0.15472844728749785
Theoretical standard deviation: 0.15491933384829668
给你。我们得出了非常相似的值。首先,通过对随机宇宙进行 10 次参观旅行的大量试验。其次,通过计算这个采样分布的理论值。在本文中,我们将确切地理解为什么这两种方法会产生相似的结果。
样本比例抽样分布的正态性
有两种情况可以认为抽样分布的形状近似正态。

让我们试一个例子。你经营一家音乐商店,每周收到 100 张新 CD(把这些看作是随机样本)。您的供应商表示,他们交付了大约 10%的摇滚 CD。你计算每周样本中摇滚 CD 的每周比例。
n = 100
p = 0.1
print(n*p)
print(n*(1-p))10.0
90.0
条件满足。让我们画出来,看看最终的分布。
X = bernoulli(p)
Y = [X.rvs(100) for i in range(10000)]normal = np.random.normal(p*n, np.sqrt(n*p*(1-p)), (1000, ))
density = stats.gaussian_kde(normal)
n_, x, _ = plt.hist(normal, bins=np.linspace(0, 20, 50),
histtype=u'step', density=True)
plt.close()
plt.hist(np.sum(Y, axis=1), density=True)
plt.plot(x, density(x));

图 4:摇滚 CD 每周抽样比例的抽样分布。
看起来不错,基本正常。如果收到摇滚 CD 的概率不是 10%,而是变成了 3%,会怎么样?
n = 100
p_ = 0.03
print(n*p_)
print(n*(1-p_))3.0
97.0
第一个条件不满足。
X = bernoulli(p_)
Y_ = [X.rvs(100) for i in range(10000)]normal = np.random.normal(p_*n, np.sqrt(n*p_*(1-p_)), (1000, ))
density = stats.gaussian_kde(normal)
n_, x, _ = plt.hist(normal, bins=np.linspace(0, 20, 50),
histtype=u'step', density=True)
plt.close()
plt.hist(np.sum(Y_, axis=1), density=True)
plt.plot(x, density(x));

图 5:概率为 3%的 Rock CDs 每周抽样比例的抽样分布。
事实上,我们的分布是向右倾斜的。
为什么这些条件很重要?当我们需要回答关于抽样比例概率的问题时,这些是相关的。比如回到我们的例子,考虑 10%概率收到摇滚 CD 的初始信息。假设您在第一次试用时发现 12%的 CD 是摇滚 CD。假设真实比例是由您的供应商提供的,您搜索的样本中超过 12%是摇滚 CD 的概率是多少?
我们已经知道抽样分布是近似正态的。所以我们需要建立我们的正态分布,计算 P(p>0.12)。
print('Empirically calculated expected value: {}'.format(np.mean(np.mean(Y, axis=1))))
print('Theoretical expected value: {}'.format(p))Empirically calculated expected value: 0.09973800000000001
Theoretical expected value: 0.1print('Empirically calculated standard deviation: {}'.format(np.std(np.mean(Y, axis=1))))
print('Theoretical standard deviation: {}'.format(np.sqrt(p*(1-p)/n)))Empirically calculated standard deviation: 0.029996189024607777
Theoretical standard deviation: 0.030000000000000002n = 100
p = 0.10
p_ = 0.12
print(f'P(p>0.12)={1-norm.cdf(p_, p, np.sqrt(p*(1-p)/n))}')P(p>0.12)=0.252492537546923
推断人口平均数
在第一部分中,我们用两种不同的方法计算了在宇宙样本中发现的死亡数。第一种方法是推导出抽样比例的抽样分布的理论性质。第二种是通过使用抽样分布的统计来估计参数。在本节中,我们将更好地理解第二种方法。
让我们从定义总体均值开始:

其中 N 代表 20,000 个宇宙的人口规模。样本均值ȳ可以定义为,

其中 n 代表样本大小,或者我们从总体中抽取的一个简单随机样本,大小为 10。
p = 0.6
n = 10
X = bernoulli(p)
Y = [X.rvs(n) for i in range(10000)]# One random sample
y_bar = np.mean(Y[0])
y_bar0.9
请注意,ȳ是我们用来推断总体参数的统计数据。然而,这些可能是不同的,因为我们是从人群中随机抽取样本。
中心极限定理
我们想得到关于中心极限定理(CLT)的直觉,然后我们将得到它的兴趣和应用。但是,首先,让我们定义一个明显的非正态分布。
elements = np.arange(6)
probabilities = [0.3, 0., 0.05, 0.05, 0.2, 0.4]
X = np.random.choice(elements, 100, p=probabilities)sns.histplot(X, stat='probability');

图 6:样本的非正态原始分布。
现在,我们可以从中提取样本。我们将抽取大小为 4 的样本,并计算其平均值。
s_1 = np.random.choice(elements, 4, p=probabilities)
print(s_1)
x_bar_1 = np.mean(s_1)
print(x_bar_1)[0 5 4 0]
2.25
让我们做同样的程序一万次。
s = []
n=4
for i in range(10000):
s.append(np.random.choice(elements, n, p=probabilities))
s = np.mean(np.asarray(s), axis=1)print('Kurtosis: ' + str(np.round(kurtosis(s),2)))
print('Skew: ' + str(np.round(skew(s),2)))
print('---')
print('μ=' + str(np.round(np.mean(s), 2)))
print('σ=' + str(np.round(np.std(s), 2)))
sns.histplot(s, stat='probability');Kurtosis: -0.36
Skew: -0.27
---
μ=3.06
σ=1.06

图 7:样本大小为 4 的样本均值的抽样分布。
上面的发行版看起来不再像我们最初的发行版了。CTL 告诉我们,当你取更多的样本并计算它们的平均值时,得到的分布将接近正态分布。我们可以通过偏度和峰度的值来衡量它,对于正态分布来说,这个值应该为零。正偏态分布的尾巴在右边,而负偏态分布的尾巴在左边。如果分布有正峰度,它比正态分布有更厚的尾部;相反,在消极的情况下,尾巴会更细。
CLT 还告诉我们,随着样本量的增加,近似值会变得更好。因此,让我们通过将样本量从 4 增加到 20,然后增加到 100 来测试它。
s = []
n=20
for i in range(10000):
s.append(np.random.choice(elements, n, p=probabilities))
s = np.mean(np.asarray(s), axis=1)print('Kurtosis: ' + str(np.round(kurtosis(s),2)))
print('Skew: ' + str(np.round(skew(s),2)))
print('---')
print('μ=' + str(np.round(np.mean(s), 2)))
print('σ=' + str(np.round(np.std(s), 2)))
sns.histplot(s, stat='probability');Kurtosis: -0.1
Skew: -0.09
---
μ=3.06
σ=0.47

图 8:样本大小为 20 的样本均值的抽样分布。
s = []
n=100
for i in range(10000):
s.append(np.random.choice(elements, n, p=probabilities))
s = np.mean(np.asarray(s), axis=1)print('Kurtosis: ' + str(np.round(kurtosis(s),2)))
print('Skew: ' + str(np.round(skew(s),2)))
print('---')
print('μ=' + str(np.round(np.mean(s), 2)))
print('σ=' + str(np.round(np.std(s), 2)))
sns.histplot(s, stat='probability');Kurtosis: -0.08
Skew: -0.03
---
μ=3.05
σ=0.22

图 9:样本量为 100 的样本均值的抽样分布。
注意最后一个图是如何类似于正态分布的。有一个惯例,即大于 30 的样本量足以近似正态分布。此外,请注意我们为不同样本量绘制的抽样分布的平均值和标准偏差值。毫不奇怪,均值与原始分布相同。但是标准差的值确实很奇怪,因为它一直在缩小。事实上,这是一个需要注意的重要性质:我们对样本均值的抽样分布的标准差是原始总体标准差除以样本容量的平方根。因此,我们可以把它写成:

print("Theoretical value: " + str(np.sqrt(X.var()/n)))
print("Empirically computed: " + str(s.std()))Theoretical value: 0.20789179878003847
Empirically computed: 0.2151977077573086
这个过程并不特定于样本均值;例如,我们可以计算样本和。
s = []
for i in range(10000):
s.append(np.random.choice(elements, 100, p=probabilities))
s = np.sum(np.asarray(s), axis=1)print('Kurtosis: ' + str(np.round(kurtosis(s),2)))
print('Skew: ' + str(np.round(skew(s),2)))
sns.histplot(s, stat='probability');Kurtosis: -0.04
Skew: -0.02

图 9:样本总数为 100 的样本的抽样分布。
我希望现在你明白为什么正态分布经常被用来模拟不同的过程。即使您不知道您想要以统计方式描述的过程的分布,如果您添加或取您的测量值的平均值(假设它们都具有相同的分布),您会突然得到一个正态分布。
结论
我们在这篇文章中面临的问题是总体参数的估计。通常我们不能收集足够的数据来代表整个人口,因此,我们需要找到另一种方法来估计其参数。我们探索的方法是从人群中随机抽取样本。从随机样本中,我们计算统计量,然后用它来推断总体的参数。我们研究了抽样比例的抽样分布和样本均值的抽样分布。
我们还探索了 CLT。它告诉我们,独立于我们想要统计描述的过程的原始分布的形状,对于大于 30 的样本大小,从该原始分布获得的样本的平均值或总和将接近正态分布。
保持联系: LinkedIn
练习
你将在下周的文章中找到答案。
- 里克在一个遥远的星球上对 75 名公民进行了 SRS 调查,以了解抽样调查的公民中有多少人对自己的生活水平感到满意。假设生活在这个星球上的 10 亿公民中有 60%对自己的生活水平感到满意。对自己的生活水平感到满意的公民比例的抽样分布的均值和标准差是多少?
- 某个拥有超过 1,000,000 个家庭的星球的平均家庭收入为 1,000,000 美元,标准差为 150,000 美元。Rick 计划随机抽取 700 个家庭样本,计算样本平均收入。然后,计算样本均值的抽样分布的均值和标准差。
- Rick 正在对不同的入口枪进行质量控制测试,因为在制造过程中存在一些可变性。比如某枪,目标厚度 5mm。厚度分布向右倾斜,平均值为 5 毫米,标准偏差为 1 毫米。该零件的质量控制检查包括随机抽取 35 个点,并计算这些点的平均厚度。样本平均厚度的抽样分布是什么形状?样品中的平均厚度在目标值 0.2 毫米以内的概率是多少?
上周的答案
def geomcdf_1(p, x):
# implementing first approach
prob = 0
for i in range(x-1):
prob+=p*(1-p)**i
return probdef geomcdf_2(p, x):
# implementing second approach
prob = 1-(1-p)**(x-1)
return prob
- 你有一副标准的牌,你在挑选牌,直到你得到一张女王(如果他们不是女王,你替换他们)。你需要挑 5 张牌的概率是多少?而不到 10?而且超过 12 个?
# Exactly 5
p = 4/52
p**1*(1-p)**40.055848076855744666# Less than 10
geomcdf_2(p, 10)0.5134348005963145# More than 12
1 - geomcdf_2(p, 13)0.3826967066770909
2.Jorge 对冰柜进行检查。他发现 94%的冰柜成功通过了检查。设 C 为 Jorge 检查的冷冻箱数量,直到一个冷冻箱未通过检查。假设每次检查的结果都是独立的。
# Our probability of success is actually the probability of failing the inspection
p=1-0.94
p**1*(1-p)**40.04684493760000003
3.佩德罗罚球命中率为 25%。作为热身,佩德罗喜欢罚任意球,直到他罚进为止。设 M 为佩德罗第一次任意球射门的次数。假设每个镜头的结果是独立的。找出佩德罗第一次投篮不到 4 次的概率。
p=0.25
# We can use our two functions
geomcdf_2(p, 4)0.578125geomcdf_1(p, 4)0.578125# which are computing
1-0.75**30.578125# and
0.25+0.25*0.75+0.25*0.75**20.578125
4.构建一个计算泊松 PMF 的函数,除了使用来自numpy的np.exp之外,不使用任何来自外部包的函数。选择一些参数,并将您的结果与scipy中的pmf函数进行比较。
def fact(k):
k_ = 1
for i in range(1, k+1):
k_ *= i
return k_def poisson_pmf(k, λ):
return np.exp(-λ)*λ**k/fact(k)poisson_pmf(1, 2)0.2706705664732254poisson.pmf(1, 2)0.2706705664732254
5.构建一个计算泊松 CDF 的函数,而不使用任何外部包。选择一些参数,并将您的结果与scipy中的cdf函数进行比较。
def poisson_cdf(x, λ):
p = []
for i in range(x+1):
p.append(poisson_pmf(i, λ))
return sum(p)poisson_cdf(2, 2)0.6766764161830635poisson.cdf(2, 2)0.6766764161830634
统计学中的抽样技术
原文:https://towardsdatascience.com/sampling-techniques-in-statistics-9c77a39e0948?source=collection_archive---------7-----------------------
统计学中不同抽样技术的简单介绍

图片由良治在 Unsplash 上拍摄
每当我们遇到任何统计研究时,我们都会听到许多不同的统计术语。😳我们最常听到的一个术语是抽样。在本文中,我们将尝试理解什么是采样,然后深入研究不同采样技术的细节。
抽样
抽样,简单来说,就是从人群中选择一个群体(样本),我们将从中收集数据用于我们的研究。取样是研究的一个重要方面,因为研究的结果主要取决于所用的取样技术。因此,为了得到准确的结果或能很好地估计总体的结果,应该明智地选择抽样技术。
现在让我们先了解一下统计学上的样本和总体究竟是什么。
总体是指我们从中抽取用于研究的统计样本的元素或个体的集合。这是我们想要得出结论的整个群体。群体中元素或个体的数量称为群体规模。
注: 在统计学研究中,人口并不总是刻画人。它可以是任何东西,印度的羊的数量;美国小学生的总人数;互联网上所有博客网站的数量。
另一方面,样本是总体的子集。它是您从中收集数据的特定组。样本中元素或个体的数量称为样本容量。选择样本的过程称为取样。比如印度拉贾斯坦邦的羊的样本;美国纽约小学生样本;互联网上的数据科学博客网站样本。
注: 样本的大小总是小于总体的大小。
但是,我们为什么需要样本呢?🤔这是一个很好的问题。👏让我们先了解这一点。
我们为什么需要样本?
答案简单明了。从人口中的每个个体(或元素)收集数据几乎是不可能的。因此,抽样有助于我们获得整个人口的信息。很明显,这些结果不可能完全准确,但却是总体的最接近的近似值。此外,重要的是,选定的群体应具有人口代表性,并且不以任何方式带有偏见。
这是一个简单的人口说明和从中抽取的样本。

作者图片
有许多抽样技术,但我们将只讨论统计学中几种常见的抽样技术。请注意,我们不会深入比较这些技术。
取样技术
简单随机抽样(SRS):
假设我们有一个 20 人的群体,我们需要从这个群体中得到一个 7 人的样本。为了便于理解,让我们给这些人编号。现在,我们将在 1 到 20 之间随机选择 7 个数字,反对这些数字的人将成为我们样本的一部分。如果与所选数字相对的人已经在我们的样本中,我们将跳过该数字,选择另一个数字。

作者图片
假设我们选择 4,然后 7,然后 11,然后 20,然后 1,然后 12,然后 20。既然已经选了 20,我们就再选一个数字,假设这次是 19。为了便于理解,我们将选出的人划掉。

作者图片
注:
- 我们跳过了重复的数字,因为我们不会对同一个人进行两次调查或采访。
- 随机数有不同的生成方式。您可以通过编程或通过将所有这些数字放入一个包中并每次选择一个来实现。
这种类型的抽样称为简单随机抽样。当总体是同质的时,这种抽样是最合适的。我们可以注意到,这个样本中的每个成员都有平等的机会(概率)被选中。在这种情况下,选择的概率是 1/20。
分层抽样:
让我们取和上面一样的样品。假设我们这次想要 9 号的样品。让我们把这些人分成不同的组,让这些组基于这些人穿的衣服的颜色。

作者图片
根据颜色,我们将这 20 个人分成 4 组。这些更小的群体中的每一个都被称为一个阶层,每个阶层都可以由一个特征来定义,在这种情况下,这个特征就是衣服的颜色。因此,基于关于样本成员的先验信息来创建阶层。一个阶层中的成员是同质的,而一个阶层的成员与另一个阶层的成员是异质的。因此,当群体本身是异质的,并且可以从中分离出同质层时,就使用这种方法。
现在,从这些层中的每一层中选出成员,也就是说,从每一层中抽取一个样本。当我们对有许多不同阶层的人口进行抽样时,我们一般要求样本中各阶层的比例应与人口中的比例相同。
一个玩具例子,只是为了理解这个概念。
黑人比例
=(黑数/总数)样本量= (9/20)8 = 3.6
红色的比例= (4/20) * 8 = 1.6
蓝色的比例= (4/20) * 8 = 1.6
绿色的比例= (3/20) * 8 = 1.2
如果我们近似这些数字,我们可以选择 4 个黑色,2 个红色,2 个蓝色和 1 个绿色来很好地代表人口。
注: 可采用随机抽样或其他任何抽样技术从各层中抽取成员。
整群抽样:
整群抽样经常与分层抽样混淆,但这两种抽样技术互不相同。主要的区别在于,使用整群抽样,你可以用自然群体来区分你的人群。比如像城市街区、学区、年龄、性别等聚类。
让我们再次考虑我们的人口,假设第一排的人住在第 36 街,第二排的人住在第 11 街。每一个都是一个集群。

作者图片
现在,我们可以从这两个集群中选择一个集群(这可以通过简单的随机抽样来完成)。假设我们选择第 11 街,那么我们现在将调查住在第 11 街的每一个人。
注: 我们可以选择任意多的集群。
整群抽样有两种方式:
单阶段整群抽样,我们随机选择整群并调查整群的每个成员;或者两阶段整群抽样,我们首先随机选择整群,然后从这些整群中随机选择成员。
系统取样:
在这种抽样技术中,我们系统地选择成员。特别是,通过先将所有成员按顺序排列,在群体的规则间隔中选择成员。
让我们考虑一下 20 人的样本人口。假设我们要选择 5 个人,我们的系统是从第三个人开始,每四个人选一个。我们将继续这样做,直到我们得到 5 人的样本。(勾号表示选中的人。)

作者图片
注:
- 为了让每个成员都有平等的入选机会,建议采用随机抽样的方式选出第一个(起始)成员。
- 系统抽样会导致偏倚。
方便取样:
这是最简单的采样技术之一,但也是最危险的采样技术之一,因为样本是根据可用性选择的。例如,调查你办公室的每一个人,研究当地的每一只猫。这样的样本不能代表总体。
注: 应使用随机化,以便我们的样本能很好地代表我们的总体,并能使我们接近关于我们总体的准确结果。
抽样技术——简单抽样、聚类抽样、分层抽样和系统抽样都是概率抽样技术,并涉及随机化。然而,便利抽样是一种非概率(或非随机)抽样技术,因为它依赖于研究人员选择样本的能力。非概率抽样技术可能导致有偏差的样本和结果。
还有其他的采样技术。比如立意、配额、转诊/滚雪球抽样都是非概率抽样技术。多阶段抽样是一种概率抽样技术。然而,涵盖所有的采样技术超出了本文的范围。😐
注: 我这里用的是人作为例子。为了简单起见,我给不同的人涂了不同的颜色,但是这些颜色并不代表什么。
我希望这篇文章能帮助你理解这些采样技术背后的基本概念。😀
参考文献:
这篇文章的灵感来自于 Steve Mays 在 YouTube 上的一些很棒的视频。🙏此外,请查看这个名为 StatQuest 的精彩频道。
谢谢大家阅读这篇文章。请分享您宝贵的反馈或建议。快乐阅读!📗 🖌
领英
圣诞老人今年应该密切关注他的需求预测模型
原文:https://towardsdatascience.com/santa-should-monitor-his-demand-forecasting-models-closely-this-year-7014f63cb27c?source=collection_archive---------20-----------------------

图片作者(鸣谢:阿里泽艾)
需求预测模型的 ML 监控和可观察性的最佳实践正好赶上混乱的供应链、暴躁的客户和突然的雪橇漂移(哦,哦,哦,不)
需求预测是一门经过时间考验的学科,它使用历史数据(传统上是购买数据)来预测给定时间段内的客户需求。对于运营和定价策略至关重要的是,几乎每个类别的企业都以某种形式使用需求预测来优化一切,从商店货架上的食品分配到数据中心的硬件计算能力,甚至(假设)是一个快乐的老精灵在树下递送的礼物。
半个多世纪以来,企业一直使用统计和计量经济学方法来预测需求,而人工智能和机器学习的出现正在帮助自动化这一过程,并使预测变得更加复杂和精确。在这些进步的推动下,企业通常依赖需求预测模型的准确性来确保一致的客户体验和卓越的运营。然而,最近的事件让人质疑这些车型的表现是否可以想当然。
为什么在需求预测中使用模型监控和 ML 可观察性?
与大多数处理未来事件的预测建模问题一样,需求预测在理论上和实践中被广泛认为是困难的,因为在做出预测时模型中有许多不确定性未被考虑。
在后 COVID 时代尤其如此,曾经的异常事件变得更加常见。今天的企业不仅要适应不断变化的消费者口味和记录需求,还要适应复杂的供应链,在这个供应链中,通货膨胀、延迟、短缺和其他不可预见的因素越来越常见。总之,近一半的 (44%)企业首席财务官报告称,2021 年第三季度供应链上的延迟和短缺增加了成本,32%的人报告称因此导致销售额下降。
由于需求预测模型的输出通常用于规划环境中,这些变化带来的性能下降的连锁影响可能不会立即显现出来。然而,每次性能下降或模型或概念漂移都会给带来重大的财务损失。
ML 监控和可观察性对于在这些事件发生时提醒团队、量化它们对模型的影响程度以及产生对根本原因的洞察以快速补救问题是至关重要的。简而言之,拥有一个 ML 可观察性策略可能是零售商拥有足够的库存来满足假日需求,还是因为缺货而失去数百万的销售机会的区别。
需求预测中的常见方法和挑战
需求预测 ML 模型一般分为两类:时间序列模型和回归模型。
时间序列模型适用于历史数据,用于预测一段时间内的销售量(即销售额)。根据行业的不同,时间序列模型通常不需要特征——只需要实际数据,如激光打印机上的历史销售数据来预测未来的销售——因此没有特征漂移的风险。有了可控的参数和坚实的统计学基础,时间序列模型通常也很容易解释。
时间序列模型的一个缺点是,它们通常需要数年的数据才能做出准确的预测,这限制了它们的可用性。例如,一家消费电子公司可能会推出一种新的可穿戴设备或一款更好的智能手机,但由于这是一种新产品类别或发明,它们本身缺乏可比的历史销售数据。
即使有这种数据,专门根据历史数据拟合的时间序列模型的总体准确性可能不如根据特征建立的模型高。尽管漂移不是一个大问题,但现实世界中的表现仍然会下降,因为历史数据通常不会编码未来事件的信息(例如,新冠肺炎导致了 2020 年股市的下跌)。
另一方面,回归预测模型不需要相同级别的历史数据。用于预测固定时间段(即未来七天)的需求量,或预测未来“n”天的需求量,以未来天数(n)为特征,回归预测可以利用更复杂的模型来生成更准确的预测。考虑到相同的模式可以用于其他部分,它们也相对更容易升级和重新培训。
出于这些原因,回归预测模型在各行各业都非常普遍——从航空公司如何对冲燃油价格飙升,到零售商在假期期间为过道端盖和其他高流量区域定价的策略,这些模型无所不包。然而,它们也不是没有缺点,因为复杂性和偏差-方差权衡会使这些模型更容易发生漂移(更多内容见下文)。
当然,这不必是一个非此即彼的选择。许多组织发现回归模型和时间序列模型在不同的情况下都很有用。例如,我们的一个与大型食品零售商合作以防止浪费的合作伙伴在同一个仪表板中监控时间序列预测和回归预测以及销售数据(实际值),按生产、位置和商店细分模型。

优化零售需求预测中的业务成果|图片由 Arize AI 提供
在实践中,预测不足或预测过高可能会很快发生,并且很难排除故障,从而导致成本超支或客户不满意,从而降低盈利能力。管理需求预测模型的团队面临的常见挑战包括:
- 回归模型对漂移的敏感性很高。虽然复杂性和更多的特征可以提高模型的准确性,但随之而来的噪声源和概念漂移(潜在变量的属性发生意外变化)的增加可能会导致模型失败。例如,一个利用数百个特征来预测房价的复杂模型可能会很快受到不断变化的购房行为或监管变化的挑战。
- 像新冠肺炎这样的事件会放大并加速漂移。在新冠肺炎飓风过后不久,很少有模型能够预测到美国的大规模移民浪潮,这一浪潮是由该国很大一部分劳动力突然并可能永久在家工作引起的。在像这样的异常事件中,漂移对回归模型的影响可能是如此之大,以至于一个更简单的时间序列模型可能值得换成一个过渡时期。
- 有限的功能多样性使故障排除变得困难。构建需求预测模型的 ML 团队通常依赖于缺乏特异性的特性,这使得故障排除更加困难。一般来说,对于他们试图解决的问题(例如,平均房价、司机延迟、评级等)而言,高度具体(通常是数字)的特征往往是理想的,因为你可以转换它们、规范化它们、删除条目或将其限制在某个值。这与 location_id 等分类要素(离散,无顺序)或顺序要素(离散,但通常是任意顺序)形成对比。例如,在零售业,像“中号”的“packet_size”这样的序数特征可能意味着一个中号的背包或一件中号的青年 t 恤——这使得它在计算(比如)棉花价格的突然上涨可能对单位成本造成的影响时用处不大。
需求预测模型的监控和可观察性的最佳实践
考虑到这些挑战和大多数组织中需求预测的高风险,我们如何才能确保令人满意的绩效,了解预测何时以及为何偏离目标,并确定如何应对?
绩效指标:需要一个可视化的村庄
回归模型预测中的偏差和误差度量是发现性能问题和优化业务目标的关键。
常见指标包括:
- 平均误差(ME): 平均历史误差(偏差);正值表示预测过高,负值表示预测过低。虽然平均误差通常不是模型在训练中优化的损失函数,但它测量偏差的事实对于监控业务影响通常是有价值的。
- 【MAE】:模型预测值与真实值之间的绝对值差,在整个数据集中取平均值。对模型性能的“第一印象”,因为它没有被一些预测的极端误差所扭曲。
- 平均绝对百分比误差****【MAPE】:衡量一个模型产生的误差的平均大小;模型预测准确性的一个更常见的度量标准。
- 均方误差(MSE) :模型的预测值和地面真实值之间的差值,经过数据集的平方和平均。MSE 用于检查预测值与实际值的接近程度。与均方根误差(RMSE) 一样,这种方法对较大的误差给予较高的权重,因此在企业可能希望严重惩罚较大的误差或异常值的情况下可能很有用。
应该注意的是,平均误差不足以说明偏差。在特征漂移事件中,在给定的时间周期中存在过预测和欠预测,平均误差可以被相反的度量值抵消。这就是并排显示平均误差和平均绝对误差的大小和方向很有帮助的原因,两者都可以用于确定模型在给定时间段内的性能何时低于标准。

作者图片(阿里泽·艾)
所有的指标都有权衡,额外的背景对于理解一个模型是否表现不佳有很大的影响。在选择需要密切关注的最有用的指标时,了解您正在优化的业务成果是至关重要的。一家希望避免大幅低估的公司——比如,一家零售商正在为占其年度销售额大部分的假日期间做准备——可能会围绕均方根误差或均方差进行优化,并密切跟踪它和均方差的图表,以揭示预测偏差的问题。在实践中,观察上述所有指标会产生切实的影响。
识别性能问题
一旦根据偏差和误差指标确定需求预测偏离目标,团队就可以识别导致性能下降的部分(或特性和价值的组合)。例如,如果一家包装食品制造商在给定时间段内具有较高的平均绝对误差和较高的平均误差,这可能是因为模型的训练数据包含了比现实世界中常见的更多的品牌忠诚者的购买。从那里,ML 团队可能会从更喜欢购买通用产品的人那里采集更多的销售数据,以重新训练模型——或者为识别出的表现较差的部分训练一个单独的模型,并在生产中分割这两个模型。
漂移检测、诊断的重要性
如前所述,监控漂移或分布变化并排除故障至关重要,特别是考虑到回归需求预测的复杂性。测量种群稳定性指数作为分布检查,ML 团队可以检测分布中的变化,这些变化可能会使某个要素作为模型的输入变得不那么有效。
例如,如果一家大型零售商的平均绝对误差很高,但平均误差为负,那么它很可能低估了需求。深入调查,零售商的 ML 团队可能会发现这是由消费者偏好的变化引起的——比如,比过去几年更早购买节日礼物,而且尺寸更大。有了这种洞察力,他们可以相应地重新训练模型。通过拥有一个 ML 可观察性平台,组织可以快速可视化并找出这些问题的根源。这在异常事件中变得更加重要。
结论
鉴于新冠肺炎事件后各行业产品开发和全球运营的性质不断变化,我们可能会见证需求预测模型应用的一代一次的重置。例如,零售商可能比过去几年更愿意接受额外的库存——认为预测不足比预测过度成本更高,因为有可能失去客户。
ML 可观察性可以帮助团队优化这些结果,避免代价高昂的错误,并保持在快速变化的顶端。通过识别导致高估或低估的特征,并快速找到问题的根源,团队可以确保未来的预测既准确又乐观。作为额外的参考,这里的是一个 ML 可观察性平台如何帮助客户处理需求预测。
联系我们
如果这个博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性和模型监控,请查看我们其他的博客和 ML 监控上的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队,帮助模型成功生产,请随时联系我们,并在此处找到我们的空缺职位!
谷歌云中的 SAP 数据分析
原文:https://towardsdatascience.com/sap-data-analytics-in-the-google-cloud-3a08b10dc0a6?source=collection_archive---------44-----------------------
如何将 SAP 与谷歌云平台相结合

克里斯蒂安·卢在 Unsplash 上的照片
如何将 SAP 与谷歌云平台(BigQuery、Data Studio 或 recently looker 等强大数据分析工具的提供商)相结合,以获得强大的数据分析平台和宝贵的见解。如果您对 SAP 数据的实用数据分析方法感兴趣,这篇文章可能也会让您感兴趣。
建造一座建筑
SAP HANA 已经内置了 SAP 数据服务,因此您可以轻松地将数据从 SAP 应用程序或其底层数据库导出到 BigQuery[1]。然而,GCP 和思爱普的结合对于那些仍然生活在 ERP 世界中的公司来说也是可能的。
以下几点显示了将数据从 SAP 加载到 Google Services 的可能性:
- 使用 talend/Google data flow/等数据集成工具,通过 RFC(远程函数调用)接口提取数据。
- 编写 ABAP 程序
- fivetran 等第三方连接器
- 使用 SAP 复制服务器
因此,可能的解决方案如下所示:

SAP 到大型查询—图片来自 Google [2]
实现增量负载
获取数据是第一步。之后,您将处理如何实现一个 delta 逻辑的问题,因为您可能不想通过满载定期加载所有数据。这只会带来加载时间长、没有历史数据等缺点。尤其是控制、内部审计等部门。通常基于历史数据视图构建他们的数据分析。
虽然 SAP 数据服务已经内置在 CDC 向导中,但其他数据集成方法可能需要一些额外的工作。要实现这一步,非常了解 SAP 表和表结构是很重要的。在自己的逻辑上实现增量加载尤其可以借助两个表来实现: CDHDR (改变标题)和 CDPOS (改变位置)。这些表跟踪主数据或事务数据的变化。
数据转换
随着基于列的数据仓库工具(如 BigQuery)的出现,由于性能以及源系统和目标系统之间不同的表结构或数据类型,数据转换通常是必要的。
一个例子是,在 SAP 中,你有 BKPF(会计凭证标题)和 BSEG(会计凭证段)表。由于其基于列的结构,对 BigQuery 中的数据进行反规范化是有意义的。解决方案可以是连接 BKPF 和 BSEG,如果需要的话,还可以连接其他主数据和参考表——例如借助 BigQuery DTS ( 数据传输服务)的帮助。因此,您可以得到一个非规范化的数据对象体系结构,如下图所示:

插图:从原始表格到非规范化数据对象-作者图片
嵌套数据
另一个获得性能和成本效率的转换是使用嵌套数据结构。BigQuery 或 Amazon 的 Redshift 等较新的数据仓库技术确实能更好地处理这种数据结构。使用嵌套数据的用例有,例如标题/段表,如 BKPF 和 BSEG,或者如果一个表包含的列变化不大,如:
namelastname
结合历史上经常变化的栏目,如[3]:
address(一个嵌套重复的字段及其后续嵌套字段):address.addressaddress.city
如果你问自己什么是嵌套数据——简而言之:BigQuery 支持从支持基于对象的模式的源格式(例如 JSON)加载和查询嵌套和循环数据。这些列可以保持关系,而不会像关系模式或规范化模式那样降低性能[4]。

嵌套和重复数据的图示-按作者分类的图像
地址列包含一个值数组。数组中的不同地址是重复出现的数据。每个地址中的不同字段是嵌套数据。点击阅读更多相关信息。
实施(自助)报告
最后一部分将实现报告和数据分析的可能性。有了 BigQuery,数据分析师已经有了一个很好的分析工具。数据科学家可以使用数据实验室或 GCP 内众多 ML 服务之一。Data Studio 可能是业务用户共享 KPI、仪表板等的合适解决方案。为了在 BigQuery 中实现角色/用户访问模型,通常使用 BUKRS 属性(公司代码),这样用户就只能看到分配给他的公司代码的数据,这也是 SAP 处理用户权限的方式。
摘要
SAP 和 GCP 的结合将为贵公司带来巨大的数据分析能力和可能性。SAP 系统托管了大量想要分析的有趣数据,而 GCP 提供了许多数据分析/科学家工具和服务,可以实现这一点。谷歌云和较新的 SAP-HANA-Cloud 架构本质上很容易相互结合,但旧系统也可以集成。因此,稳固的 SAP 财务系统符合专为数据分析而设计的敏捷的 Google world 一个非常有用的组合。
资料来源和进一步阅读:
[1] SAP 社区,HANA SDA—Google big query(2018)
[2]谷歌,https://cloud . Google . com/solutions/sap/docs/big query-replication-from-sap-apps?hl=de (2021)
[3]谷歌,【https://cloud.google.com/bigquery/docs/nested-repeated】T4(2021)
[4] Google,指定嵌套和重复的列 (2021)
SAP KPI:效率(制造)
原文:https://towardsdatascience.com/sap-kpi-efficiency-manufacturing-1a4b2fbf14ab?source=collection_archive---------29-----------------------
连接哪些 SAP 表来分析效率

一切都是为了效率(法国岩石,作者图片)
动机:
即使是最好的制造工艺,其效率也会有所不同。随着时间的推移分析效率,将 ERP 中的数据存储在数据仓库中,这难道不是很有趣吗?下面的 SQL 从 SAP BI 的角度向您展示了如何实现这一目标。请注意,由于所有 SAP ERP 都是公司独有的,因此没有 100%正确和完整的解决方案。但它肯定会指引你正确的方向。
解决:
如果您希望提高效率,表 AFVV(工序数量、价值和日期)、AFVC(订单内的工序)和 CRHD(工作中心标题)是我们感兴趣的中央 SAP 表:

与生产计划 PP 模块相关的 SAP 表格(图片由作者提供)
truncate table [etl].[Efficiency]
insert into [etl].[Efficiency]
(AUFNR, LMNGA, XMNGA, RMNGA, VGW01, VGW02, VGW03, ISM01, ISM02, ISM03, TSTP_DT ,
AfvvErdat, AfvvAufpl, AfvvAplzl,AfvvMeinh, AfvcArbid,
arbpl, BEGDA, ENDDA, CrhdWerks, CrhdObjty, iedd,efficiency, abteil, team, vornr)
select distinct
a.AUFNR, a.LMNGA, a.XMNGA, a.RMNGA, a.VGW01, a.VGW02, a.VGW03, a.ISM01, a.ISM02, a.ISM03, a.TSTP_DT ,
a.ERDAT as AfvvErdat, a.aufpl as AfvvAufpl, a.aplzl as AfvvAplzl,a.MEINH as AfvvMeinh, b.arbid as AfvcArbid,
c.arbpl, c.BEGDA, c.ENDDA, c.werks as CrhdWerks, c.OBJTY as CrhdObjty, a.iedd, 0 as efficiency, null as abteil, null as team, b.vornr
from [AFVV] as a
inner join [AFVC] as b
on a.aufpl=b.AUFPL and a.APLZL=b.APLZL
inner join [crhd] as c
on b.arbid=c.OBJID
如果您只想分析特定状态,请使用表 JEST 进行映射:
update [etl].[Efficiency]
set JestStatActive= ‘WhatEverYourCompany’
from [etl].[Efficiency] as j
inner join [JEST] as jest
on concat(‘WhatEverYourCompany’, j.aufnr) = jest.OBJNR
where jest.inact<>’X’ and jest.stat =’WhatEverYourCompany'
我们已经可以计算效率:标准值存储在 vgw 中,而先前确认的活动来自 ism、总确认产量(lmnga)、总确认返工数量(rmnga)和总确认报废数量(xmnga):
update [etl].[Efficiency]
set EfficiencyTotal =
( case
when (ism03 = 0) then (vgw01 + vgw02 * (lmnga + rmnga + xmnga))
else (vgw01 + vgw03 * (lmnga + rmnga + xmnga))
end)
也许你还想加上预订日期:
update [etl].[Efficiency]
set BookingDate= i.iedd
FROM [etl].[Efficiency] as j
Inner join [afvv] as i
On j.AfvvAplzl = i.APLZL and j.AfvvAufpl=i.AUFPL
要检查测量单位(UoM),请从 AFVV 转到 vge:
update [etl].[Efficiency]
set AfvvVge01 = i.vge01
from [etl].[Efficiency] as j
inner join [AFVV] as i
on j.AUFNR = i.aufnrupdate [etl].[Efficiency]
set AfvvVge02 = i.vge02
from [etl].[Efficiency] as j
inner join [AFVV] as i
on j.AUFNR = i.aufnrupdate [etl].[Efficiency]
set AfvvVge03 = i.vge03
from [etl].[Efficiency] as j
inner join [AFVV] as i
on j.AUFNR = i.aufnr
恭喜:
我们刚刚计算了 ERP 系统 SAP 的效率。非常感谢阅读,希望这是支持!有任何问题,请告诉我。你可以在 LinkedIn 或者 Twitter 上和我联系。
最初发表在我的网站 DAR-Analytics 。
SAP KPI:最终产量(制造)
原文:https://towardsdatascience.com/sap-kpi-final-yield-manufacturing-1f2cfb374940?source=collection_archive---------40-----------------------
连接哪些 SAP 表来分析最终产量和首次通过率

与生产计划 PP 模块相关的 SAP 表格(图片由作者提供)
动机:
即使是最好的制造工艺也会产生废料,至少时不时会有一点。分析一段时间内的最终产量,并将 ERP 中的数据存储在数据仓库中,这难道不是很有趣吗?下面的 SQL 从 SAP BI 的角度向您展示了如何实现这一目标。请注意,由于所有 SAP ERP 都是公司独有的,因此对于此请求没有 100%正确和完整的解决方案。但它肯定会指引你正确的方向。
解决方案:
如果您在最终产量之后,AFKO 是感兴趣的中央 SAP 表。AFKO(德语为 Auftragskopf)代表订单标题数据 PP 订单。
truncate table [etl].[Yield]
select * into [etl].[Yield] from [Afko]
QMFE 是关于质量通知的,我们将使用该表来接收与生产相关的中断(字段 Fmgeig 代表缺陷数量)。字段 Fegrp、Fecod 和 Fekat 都存储问题信息。我们在生产订单(Fertanr 和 Aufnr)和 Qmnum(通知信息)级别加入这些信息:
update [etl].[Yield]
set ProductionRelatedOutage=
(
select sum(fmgeig)
from [qmfe] as a, [qmel] as b
where b.FERTANR=[etl].[Yield].AUFNR and a.qmnum in
(
select b.qmnum
FROM [qmel]
)
and fegrp=’WhatEverYourCompany’ and FEKAT=’WhatEverYourCompany' and FECOD=’WhatEverYourCompany'
)
然后,通过交付数量(Igmng)除以订单接收量(Gamng)来计算产量:
update [etl].[Yield]
set Yield =[IGMNG] / nullif([GAMNG],0)
或者有时甚至更具体地,您将通过交付数量除以交付数量+确认的废料信息(Iasmg)来计算产量-与生产相关的停机:
update [etl].[Yield]
set YieldMoreSpecific =[IGMNG]/nullif(([IGMNG]+[IASMG]-isnull([ProductionRelatedOutage],0)),0)
为了接收生产订单状态,我们必须加入 Jest(单个对象状态)表。我们将只考虑非不活跃的(<> X):
update [etl].[Yield]
set Status = b.stat
from [etl].[Yield] as a
inner join [aufk] as c
on a.aufnr = c.AUFNR
inner join [JEST] as b
on b.objnr = c.objnr
where b.inact <>’X’
作为补充,我们还可以使用每个内部连接的确认数量信息(Igmng)来增加返工的产量:
update [etl].[Yield]
set YieldFromRework= QuantityFromRework
from [etl].[Yield] as a
inner join (select sum(igmng) as QuantityFromRework, maufnr
from [etl].[Yield]
group by maufnr) as b
on b.maufnr= a.aufnr
我们最终可以用它来计算首次通过率,即数量(来自 MSEG)-返工产量除以 Gamng:
update [etl].[Yield]
set FirstComeThroughRate =( MSEGMenge -isnull(YieldFromRework,0))/GAMNG
恭喜:
我们刚刚计算了 ERP 系统 SAP 的最终产量和首次通过率。非常感谢阅读,希望这是支持!有任何问题,请告诉我。你可以在 LinkedIn 或者 Twitter 上和我联系。
最初发布于我的网站 DAR-Analytics 。
SAP KPI:废料成本(质量管理系统)
原文:https://towardsdatascience.com/sap-kpi-scrap-costs-quality-7562b9ceea75?source=collection_archive---------32-----------------------
连接哪些 SAP 表来分析报废成本

人无完人(Fondor,经马蒂亚斯·伯乐许可)
动机:
即使是最好的制造工艺也会产生废料,至少时不时会有一点。使用将 ERP 中的数据存储在数据仓库中来分析这些报废成本,这难道不有趣吗?下面的 SQL 从 SAP BI 的角度向您展示了如何实现这一目标。请注意,由于所有 SAP ERP 都是公司独有的,因此对于此请求没有 100%正确和完整的解决方案。但它肯定会指引你正确的方向。
解决方案:
如果您正在寻找废料成本,QMFE 是感兴趣的中央 SAP 表。QMEL 保存总体质量通知,而 QMFE 存储每个项目的误差。制裁可在 QMSM 中找到,根本原因可在 QMUR 中找到,活动可在 QMMA 中找到:

质量相关交易为 QM10、13 和 15(图片由作者提供)
首先,我们将加载表 QMFE:
select * into [etl].[qmfe] from [qmfe]
我们将只考虑 QMSM 中那些没有被取消的数据行(kzloesc <> x)。使用窗口函数 row_number 和 partition by,我们只将每个 qmnm 和 fenum 的第一个数据行选择到新表 qmsm_decision 中:
drop table [etl].[qmsm_decision]
select * into [etl].[qmsm_decision]
from
(select a.*,
Row_number() over (partition by qmnum, fenum order by manum desc) rn
from [qmsm] as a
Where mngrp =’WhatEverYourCompany' and kzloesc <>’X’
)src
Where rn =’1'
Order by qmnum;
我们想为代码组任务(mngrp)和任务代码(mncod)丰富我们的 etl.qmfe,这是我们从表 QMSM 中收到的:
Update [etl].[qmfe]
set QmsmMngrp= qmsm.mngrp, QmsmMncod=qmsm.mncod
FROM [etl].[qmfe] as qmfe
left outer join [etl].[qmsm_decision] as qmsm
on qmfe.QMNUM=qmsm.QMNUM and qmfe.FENUM=qmsm.FENUM
现在有趣的部分来了:我们将更具体地更新那些 QmsmMngrp 当前为 null 并且 QMSM 中的 fenum 为零的数据行:
Update [etl].[qmfe]
set QmsmMngrp= qmsm.mngrp, QmsmMncod=qmsm.mncod
FROM [etl].[qmfe] as qmfe
left outer join [etl].[qmsm_decision] as qmsm
on qmfe.QMNUM=qmsm.QMNUM
where QmsmMngrp is null and qmsm.FENUM=0
我们从表 QMEL 中获得项目编号:
Update [etl].[qmfe]
Set qmelMatnr=qmel.matnr
From [etl].[qmfe] as qmfe
inner join [QMEL] as qmel
On qmfe.qmnum=qmel.qmnum
这也是我们从以下地址获取消息类型(qmart)和
工作中心工厂(arbplwe)、简短文本(qmtxt)和通知完成日期(qmdab)的地方:
Update [etl].[qmfe]
Set QmelQmart =qmel.qmart, QmelQmtext= qmel.qmtxt, qmelqmdab=qmel.qmdab , qmelWerk=qmel.ARBPLWE
From [etl].[qmfe] as qmfe
inner join [QMEL] as qmel
On qmfe.qmnum=qmel.qmnum
让我们进入狮穴,最终开始计算废料成本:
Update [etl].[qmfe]
Set scrap=qmsm.mngrp
From [etl].[qmfe] as qmfe
inner join [QMSM] as qmsm
On qmfe.qmnum=qmsm.qmnum
Where qmsm.mngrp=’WhatEverYourCompany' and qmsm.mncod=’WhatEverYourCompany' and qmsm.kzloesc <>’x’
我们来谈谈过度消费:
Update [etl].[qmfe]
Set OverConsumption=qmsm.mngrp
From [etl].[qmfe] as qmfe
inner join [QMSM] as qmsm
On qmfe.qmnum=qmsm.qmnum
Where qmsm.mngrp=’WhatEverYourCompany' and qmsm.mncod=’WhatEverYourCompany' and qmsm.kzloesc <>’x’
不要再拐弯抹角了:我们因废品损失了多少?标准价格(stprs)来自 MBEW 表(材料估价)。乘以物料的缺陷数量,包括外部(fmgfrd)和内部(fmgeig ),并考虑价格单位(peinh ),得出报废成本:
Update [etl].[qmfe]
Set ScrapCosts=(FMGFRD+FMGEIG)*(STPRS/nullif(Peinh,0))
From [etl].[qmfe] as qmfe
真的有那么糟糕吗?像往常一样,这要看情况。您可能需要详细考虑特殊情况:例如,仅将特定的 qmtext、mngrp 和 mncod 组合视为真正的废料。但这确实取决于你的 ERP 设置。
如果只有一些状态与您废料分析相关:
update [etl].[qmfe]
set JestStatus = c.stat
from [etl].[qmfe] a
inner join [JEST] c
on (‘WhateverYourCompany’+ a.QMNUM ) = c.objnr
where c.inact <>’X’
通常,需求会随着时间而变化。因此,将来您可能需要从您的分析中移除一些特定的植物、OTRGRP 和 OTEIL:
delete from
[etl].[qmfe]
where qmelwerk=’WhatEverYourCompany' and otgrp= ‘WhatEverYourCompany’ and oteil=’WhatEverYourCompany' and jeststatus =’WhatEverYourCompany'
QPCT(代码文本)是另一个关于废料成本的有趣表格。例如,我们可以通过加入 codegruppe 和 code 来提取部门详细信息:
update [etl].[qmfe]
set Department= [Kurztext]
from [bi].[F_ScrapCosts]
left outer join [qpct]
on OTGRP=Codegruppe and OTEIL=Code
where [catalog]=’WhatEverYourCompany’
恭喜:
我们刚刚从 ERP 系统 SAP 中计算了废料成本。非常感谢阅读,希望这是支持!有任何问题,请告诉我。你可以通过 LinkedIn 或 Twitter 与我联系。
最初发表在我的网站 DAR-Analytics 。
SAP KPI:吞吐量/提前期(制造)
原文:https://towardsdatascience.com/sap-kpi-throughput-lead-time-manufacturing-b74d1e4c21b8?source=collection_archive---------36-----------------------
连接哪些 SAP 表来分析吞吐量时间

与生产计划 PP 模块相关的 SAP 表格(图片由作者提供)
动机:
即使是最稳定的制造流程也会因每次生产的产品数量而有所不同。随着时间的推移分析您的吞吐量,将 ERP 中的数据存储在数据仓库中,这难道不是很有趣吗?下面的 SQL 从 SAP BI 的角度向您展示了如何实现这一目标。请注意,由于所有 SAP ERP 都是公司独有的,因此对于此请求没有 100%正确和完整的解决方案。但它肯定会指引你正确的方向。
解决方案:
如果您正在寻找吞吐量时间,AFKO 是感兴趣的中央 SAP 表。AFKO(德语为 Auftragskopf)代表订单标题数据 PP 订单。订单详情存储在 AFPO,我们从那里获取位置编号(posnr)、计划订单的开始日期(strmp)、计划订单的交付日期(ltrmp)、项目(matnr)和工厂(werks ),这些信息来自:
drop table [etl].[Throughput]
Select distinct a.aufnr, a.gstri, a.getri, a.dispo, a.fevor, a.gsuzi, a.geuzi, b.posnr, b.strmp, b.ltrmp, b.matnr, b.werks, a.gltri
into [etl].[Throughput]
From [AFKO] as a
inner join [afpo] as b
on a.aufnr=b.aufnr
为了计算净实际吞吐量,我们必须测量实际开始日期(gstri)和确认订单完成日期(getri)之间的距离。下面你会看到一个只考虑周一到周五工作日的例子:
update [etl].[Throughput]
set ActThroughputNet= DATEDIFF(dd,gstri,getri) — (DATEDIFF(wk,gstri,getri) * 2) -
case when datepart(dw, gstri) = 1 then 1 else 0 end +
case when datepart(dw, getri) = 1 then 1 else 0 end
作为基准,我们再次使用相同的逻辑,但是这次是 strmp(计划开始)和 ltrmp(计划交付日期)。这样我们可以在以后比较实际和计划:
update [etl].[Throughput]
set PlanThroughput =DATEDIFF(dd,strmp,ltrmp) — (DATEDIFF(wk, strmp,ltrmp) * 2) -
case when datepart(dw, strmp) = 1 then 1 else 0 end +
case when datepart(dw, ltrmp) = 1 then 1 else 0 end
到目前为止,我们只计算了以天为单位的日期差异(不包括周六和周日)。我们现在也要考虑时差。字段 gsuzi 代表实际开始时间。确认的订单完成时间存储在字段 geuzi 中。如果我们把这个时间差加到我们已经计算的日期差(ActThroughputNet)上,我们就完成了。其余的只是通常的时间格式,例如以分钟或小时显示时差:
update [etl].[Throughput]
set
gsuzitime= (select left(gsuzi,2) + ‘:’ + substring(gsuzi,3,2) + ‘:’ + right(gsuzi,2)),
geuzitime= (select left(geuzi,2) + ‘:’ + substring(geuzi,3,2) + ‘:’ + right(geuzi,2))update [etl].[Throughput]
set ThroughputNetTimeMinutes =(
case
when
— (gsuzitime>geuzitime) then 1440+datediff (mi,gsuzitime,geuzitime)
(geuzitime> gsuzitime) then datediff (HOUR,gsuzitime,geuzitime)
else datediff (HOUR, geuzitime, gsuzitime)
end
)update [etl].[Throughput]
set ActThroughputNetMeasureHours= (case when gsuzitime > geuzitime then ActThroughputNet *24 — ThroughputNetTimeMinutes else ActThroughputNet *24 + ThroughputNetTimeMinutes end)
此外,我们现在可以映射生产订单状态。由于我们不想考虑取消的生产订单,我们将只从 JEST 表中提取那些活动的行(inact <> 'X '):
update [etl].[Throughput]
set JestStatActive= ‘WhatEverYourCompany’
from [etl].[Throughput] as a
inner join [JEST] as b
on concat(‘OR’, a.aufnr) = b.OBJNR
where b.inact<>’X’ and stat =’WhatEverYourCompany'
生产主管(fevor)是从 T024F 的 fevtxt 中加入部门详情的关键:
update [etl].[Throughput]
set Bereich = b.FEVTXT
from [etl].[Throughput] as a
Inner join [T024F] as b
On a.fevor=b.fevor
最后,我们可以随心所欲地进行所有吞吐量计算,例如:
drop table [etl].[ThroughputTop]
select matnr, avg(ActThroughputNetMeasureHours)/24 as AvgDurationPerItem
into [etl].[ThroughputTop]
from [etl].[Throughput] as a
group by matnr
order by AvgDurationPerProdOrder
恭喜:
我们刚刚计算了 ERP 系统 SAP 的吞吐量(或交付周期)。非常感谢阅读,希望这是支持!有任何问题,请告诉我。你可以在 LinkedIn 或者 Twitter 上和我联系。
最初发布于我的网站 DAR-Analytics 。
Sara Metwalli 谈 NLP、公共写作和开启数据科学生涯
原文:https://towardsdatascience.com/sara-metwalli-on-nlp-public-writing-and-launching-a-data-science-career-dca64e26103c?source=collection_archive---------28-----------------------
作者聚焦
“我开始寻找一种方法来记录我的学习历程并帮助他人。”
在 Author Spotlight 系列中,TDS 编辑与我们社区的成员谈论他们在数据科学领域的职业道路、他们的写作以及他们的灵感来源。我们很激动地呈现我们在这个系列中的第一次对话,与 萨拉 a .梅特沃利 。

照片由 Sara A. Metwalli 提供
Sara a . Metwalli 原籍埃及,获得亚历山大大学工程学院电子与通信工程学士学位。她随后前往东京继续攻读研究生课程:她于 2018 年获得了东京工业大学计算机和通信工程硕士学位。
完成硕士学位后,萨拉休学一年研究和学习量子力学和量子物理学,并在庆应义塾大学兼职做讲师,在东京编码俱乐部做讲师。最后,在 2020 年 4 月,她成为了庆应义塾大学的一名博士生,她是庆应义塾/IBM 量子计算中心的成员。在她的许多其他活动中,去年 Sara 还加入了 TDS 的编辑助理的行列,同时确立了自己作为一名多产和迷人的作家的地位。综上所述,当她同意和我们聊她的工作时,我们很感激。
人们进入数据科学的途径千差万别,你的经历是怎样的?
数据科学最先吸引我的是 NLP(自然语言处理 ) 。我总是着迷于语言,它们是如何演变的,以及作者如何用它们来讲述一个令人难忘的故事。
我对了解人们如何使用语言的好奇心让我试图理解我们如何教会计算机理解语言。因为如果我能理解这一点,我就能更好地了解我们是如何理解语言的。
在你的工作中,有没有哪个方面比其他方面更困难?
当任何人加入一个技术领域,尤其是自学的时候,最具挑战性的事情之一就是孤独感。你觉得你在独自经历这段旅程。作为一名从事科技行业的女性,加剧了这种孤独感。
对我有帮助的是加入了编写代码的女性 Slack 小组,并成为 Python 全球分会的领导。这让我能够与和我有着相同经历的志趣相投的人交流。我们可以互相提供支持和见解。
自去年以来,你一直定期在 Medium,特别是 TDS 上发表文章,是什么激励你为更广泛的受众撰写关于数据科学、机器学习和其他主题的文章?
正如我之前提到的,我一直热衷于语言和写作。但是由于我的工作是一名教师和一名博士生,我发现自己必须一次学这么多东西。和其他人一样,我发现我也忘记了很多我学过的东西。因此,我开始寻找一种方法来记录我的学习历程并帮助他人。
答案是写文章:这就像同时达到多个目标。在我开始写作之前,我已经阅读 TDS 文章很多年了,在那里拥有我的许多文章简直是梦想成真。
关于这种公开写作,你最喜欢的是什么?
我一直在与“冒名顶替综合症”做斗争——我总觉得自己不够好,我的知识永远不会像同龄人一样好。写作给了我一个目标,一种被认可的感觉,让我觉得自己不那么像个骗子。此外,它还帮助我提高了写作和沟通技巧,让我结识了新朋友。
作为一个前瞻性的总结,你对未来几年的数据科学社区有什么希望?
我真的希望在接下来的几年里,数据科学社区仍然支持和欢迎新来者。这个支持我的社区鼓励了我,让我成为今天的我,无论是在媒体上还是在非媒体上。
想了解更多关于 Sara 的工作吗?她的帖子可能涵盖各种各样的主题,但它们都专注于清晰和同情,并着眼于教别人如何提高技能。这里有一些我们最喜欢的 TDS 档案以及其他出版物;无论你是长期粉丝还是刚刚发现莎拉的作品,你都会想读一读。
- 成为数据科学家的学习之路 ( TDS ,2020 年 10 月)
在 Sara 最早的病毒式成功中,这是一个初学者友好的路线图,用于在数据科学和机器学习的广阔(和狂野)世界中获得立足点。 - 写作帮助我克服冒名顶替综合症的 5 种方法(独一无二,2020 年 8 月) 萨拉作品中最引人注目的元素之一是她对所面临挑战的透明性;在这篇文章中,她分享了为广大读者写作如何让她在学术和专业领域感到更加自在。
- 6 种 NLP 技术每个数据科学家都应该知道 ( TDS ,2021 年 1 月) 正如她在我们的 Q & A 中提到的,NLP 是 Sara 非常关心的一个话题,在这篇文章中,她强调了这个广阔领域中数据科学家(尤其是职业生涯早期的数据科学家)应该投入时间的一些领域。
- 数据库 101:如何选择 Python 数据库库 ( TDS ,2020 年 10 月) 教学和解释是 Sara 的帖子做得最好的两件事,这一篇也不例外,考察了 SQL 和 NoSQL Python 库这两个领域。(你可以看看 Sara 的其他 101 篇文章:例如,关于有效可视化或选择正确的算法。)
- 我是如何停止欺负自己的 ( 看不见的病,2020 年 8 月) 关于心理健康和自我接纳的几篇文章的一部分,萨拉的帖子邀请人们像对待别人一样对待自己——带着尊重和同理心。
敬请期待我们的下一位特色作者,即将推出!(如果您对希望在此空间看到的人有任何建议,请给我们留言。)
Python 中基于空间的讽刺文本分类
原文:https://towardsdatascience.com/sarcasm-text-classification-using-spacy-in-python-7cd39074f32e?source=collection_archive---------6-----------------------
实践教程
训练自己的自定义 TextCat 组件,并将其打包为 Python 模块

照片由 Unsplash 上的 capnsnap 拍摄
通过阅读本文,您将学会训练一个讽刺文本分类模型,并将其部署到您的 Python 应用程序中。检测文本中讽刺的存在是一项有趣但具有挑战性的自然语言处理任务。
本教程主要关注于训练一个自定义多分类空间的TextCat组件。如果您刚刚开始或者有自己的用例,您需要做的就是用您喜欢的数据集替换掉数据集。设置和培训过程大致相同,只是对配置做了一些小的改动。
为了保持简单和简短,这部分的培训架构将基于以下内容的叠加组合:
- 线性词袋模型和
- 建立在 Tok2Vec 层上并使用注意力的神经网络模型。
在内部,spaCy 支持任何具有预训练权重和来自 HuggingFace 的 PyTorch 实现的变压器模型。如果您喜欢使用最新的变压器模型,如 BERT、ALBERT、RoBERTa 等,请随意修改模型架构。
事不宜迟,让我们进入下一节,开始安装必要的模块
设置
强烈建议您在继续之前设置一个虚拟环境。
宽大的
根据您的喜好,有多种方式安装空间。
通过pip的安装可以通过以下命令完成(仅限 CPU):
pip install -U spacy
对于 GPU 支持,请使用以下命令:
pip install -U spacy[cuda102]
或者,您可以通过conda安装,如下所示:
# CPU
conda install -c conda-forge spacy# GPU
conda install -c conda-forge spacy
conda install -c conda-forge cupy
资料组
本教程在 Kaggle 的 Reddit 数据集上使用了讽刺。如果您在访问它时遇到问题,请查看存放数据的原始链接..请根据您的用例随意更改数据集。
下载以下文件:
- 测试平衡. csv
- train-balanced.csv
下图展示了数据集的内容及其相应的标题。最重要的数据点是:
label:表示文本是讽刺性的(1)还是非讽刺性的(0)comment:代表文本

作者图片
您需要处理数据集并将其转换为两个 JSONL 文件,如下所示:
{"text": "Certainly not number of recruiting stars.", "cats": {"sarcasm": 0.0, "other": 1.0}}
{"text": "actually Mercedes parts are quite cheap.", "cats": {"sarcasm": 0.0, "other": 1.0}}
{"text": "Because four days really makes all the difference!", "cats": {"sarcasm": 1.0, "other": 0.0}}
每行代表一个具有以下属性的字典:
- 文本
- 猫
cats表示相应文本的标签。将相应的目标标签标记为1.0,其余标记为0.0。在这种情况下,讽刺被标记为1.0,而其他被标记为0.0。将assets文件夹中的 JSONL 文件另存为:
- data.train.jsonl
- data.valid.jsonl
转换器脚本
此外,您将需要一个额外的转换器脚本,以便在训练期间将新创建的 JSONL 数据转换为 spaCy 二进制格式。创建一个名为scripts的新文件夹。然后,创建一个名为convert.py的 Python 文件,其中包含以下代码:
配置文件
接下来,在您的工作目录中创建一个名为configs的新文件夹。在该文件夹中,创建一个名为config.conf的新文件,并在其中添加以下配置:
它表示在 spaCy 中训练模型时使用的自定义管道。这表示将使用空间对textcat组件进行培训。TextCatEnsemble.v2 架构。您可以根据自己的喜好随意修改配置。
例如,您可以将patience值更改为更高的值,以防止过早停止。如果 1000 步后分数没有提高,当前设置将停止训练。
[training]
...
patience = 1000
max_epochs = 1
max_steps = 0
eval_frequency = 100
...
请注意,对于用于多分类任务的textcat组件,应始终使用exclusive_classes = true。另一方面,在训练多标签分类模型时,你应该使用exclusive_classes = false。
[components.textcat.model.linear_model] @architectures = "spacy.TextCatBOW.v1" exclusive_classes = true
ngram_size = 1
no_output_layer = false
nO = null
项目文件
让我们通过在您的工作目录中创建一个名为project.yml的新文件来结束设置。在其中添加以下代码:
它包含以下内容:
- 与项目相关的元数据
- 命令
- 工作流程
您可以在vars部分修改与现有项目相关的所有元数据。例如,如果您打算使用本地机器的第一个 GPU 进行训练,可以将gpu_id更改为 0。通过在每次训练中指定不同的version,spaCy 会通过version将你的模型打包到不同的文件夹后缀中。
vars:
name: "textcat_multilabel_emotion"
# Supported languages: all except ja, ko, th, vi, and zh, which would require
# custom tokenizer settings in config.cfg
lang: "en"
# Set your GPU ID, -1 is CPU
gpu_id: -1
version: "0.0.0"
train: "data.train.jsonl"
dev: "data.valid.jsonl"
config: "config.cfg"
命令是预定义的操作,可以通过以下方式触发:
spacy project run [command]
假设您已经定义了以下命令:
...
commands:
- name: "convert"
help: "Convert the data to spaCy's binary format"
script:
- "python scripts/convert.py ${vars.lang} assets/${vars.train} corpus/train.spacy"
- "python scripts/convert.py ${vars.lang} assets/${vars.dev} corpus/dev.spacy"
deps:
- "assets/${vars.train}"
- "assets/${vars.dev}"
- "scripts/convert.py"
outputs:
- "corpus/train.spacy"
- "corpus/dev.spacy"
...
您可以通过在命令行中运行以下命令来触发它。
spacy project run convert
或者,您可以将所有命令捆绑到一个工作流中,如下所示:
workflows:
all:
- convert
- train
- evaluate
- package
然后,您可以运行以下命令来按顺序执行所有命令:
spacy project run all
您已经完成了初始设置。前往下一部分训练你的模型。
履行
在本节中,您将学习训练模型并将其部署到 Python 应用程序中。在您之前创建的project.yml脚本中,它包含以下命令:
convert—将数据转换为 spaCy 的二进制格式train—训练 textcat 模型evaluate—评估模型并导出指标package—将训练好的模型打包成 pip 包visualize-model-使用 Streamlit 交互式可视化模型输出
如果您打算运行visualize-model命令,请转到下面的链接并将代码保存为visualize_model.py在scripts文件夹中。除此之外,您还需要通过以下命令安装spacy-streamlit。
pip install spacy-streamlit --pre
使用工作流
让我们利用以下工作流,而不是逐个运行命令:
- 转换数据
- 训练模型
- 评估模型
- 打包训练好的模型
运行以下命令:
spacy project run all
检查文件夹
它将首先检查您的工作目录,并生成其中不存在的文件夹。您应该有以下文件夹:
- 资产
- 文集
- 配置
- 培养
- 剧本
- 包装
转换数据集
之后,它将加载您的 JSONL 数据集,并在corpus文件夹中将其转换为二进制格式:
- 火车空间
- 开发空间
训练模型
一旦转换完成,它将初始化管道组件并开始训练模型。您应该会在控制台中看到以下输出:
ℹ Pipeline: ['textcat_sarcasm']
ℹ Initial learn rate: 0.001
E # LOSS TEXTC... CATS_SCORE SCORE
--- ------ ------------- ---------- ------
0 0 0.06 48.55 0.49
0 100 1.90 52.71 0.53
0 200 1.41 57.34 0.57
0 300 1.07 60.73 0.61
0 400 0.83 63.55 0.64
E—表示已经完成的历元数。#—表示当前的总训练步数。您可以通过配置文件中的eval_frequency更改频率。LOSS TEXTCAT—损失值。CATS_SCORE—评估分数,从 0 到 100。SCORE—评价得分从 0.0 到 1.0,小数点后两位(四舍五入)。
训练将持续进行,直到满足以下任一条件:
- 达到了定义的
max_epochs - 达到了定义的
max_steps - 达到定义的
patience(分数没有任何提高的步数)
它会将最佳模型和最后模型保存在training文件夹中。
模型评估
下一步是模型评估。它将使用最佳模型计算指标,并将结果作为training文件夹中的metrics.json导出。
{
"token_acc":1.0,
"cats_score":0.728515388,
"speed":36132.1250494927,
"cats_f_per_type":{
"sarcasm":{
"p":0.7550697085,
"r":0.6728651527,
"f":0.7116012201
},
"other":{
"p":0.709381495,
"r":0.7853374063,
"f":0.7454295559
}
},
"cats_auc_per_type":{
"sarcasm":0.8028807945,
"other":0.8028807993
}
}
p—表示精度值r—代表召回值f—f1 值
打包模型
工作流程的最后一步是将最佳模型作为 pip 包打包在packages文件夹中。确保在每次培训期间修改project.yml中的版本。它将相应地输出一个新文件夹,如下所示:
en_textcat_sarcasm-0.0.0
en_textcat_sarcasm-0.0.1
en_textcat_sarcasm-0.0.2
在每个包中,它包含以下文件和文件夹:
- 距离
- en _ textcat _ 讽刺
- en _ textcat _ 讥讽. egg-信息
- 清单. in
- meta.json
- setup.py
部署包
您可以在文件夹中运行以下命令,将它安装到您的虚拟环境中:
python setup.py
或者,您可以复制出底层的en_textcat_sarcasm文件夹,并将其直接放入 Python 应用程序的同一文件夹中。它将被视为另一个 Python 模块。因此,您可以在 Python 应用程序中正常调用包,如下所示:
import en_textcat_sarcasm nlp = en_textcat_sarcasm.load()
一旦加载了模型,就可以按如下方式处理单个文本:
doc = nlp("This is a text")
它将返回一个空间的 Doc 对象。您可以通过以下方式获得基础cats分数:
doc.cats
处理大量文本时,您应该使用pipe成批处理:
texts = ["This is a text", "These are lots of texts", "..."]# bad
docs = [nlp(text) for text in texts]# good
docs = list(nlp.pipe(texts))
以下是打印所有文本及其相应分数的示例脚本:
您应该在命令行中获得以下输出:
yea right, so funny
{'sarcasm': 0.9599524736404419, 'other': 0.040047552436590195}You forgot "Am I a joke to you" guy
{'sarcasm': 0.3846711814403534, 'other': 0.615328848361969}Pretty ballsey for Ted to mouth off to his bosses like that.
{'sarcasm': 0.2167516052722931, 'other': 0.7832483649253845}I’m sure she is going to make an absolutely stellar cop, with no power trip agenda whatsoever
{'sarcasm': 0.878804087638855, 'other': 0.12119589745998383}Shut up, college boy!!
{'sarcasm': 0.6504116654396057, 'other': 0.3495883643627167}
结论
让我们回顾一下你今天所学的内容。
本文首先简要介绍了 spaCy 的 TextCat 组件和一个构建讽刺分类器模型的用例。
然后,它继续通过pip或conda安装 spaCy。除此之外,还介绍了使用 Kaggle 中的数据集进行数据准备以及创建相关的配置文件。
接下来,介绍了整个实现过程,包括将数据集转换为 spaCy 的二进制格式、训练模型、模型评估以及将最佳模型打包为 pip 包。
最后,本文提供了一个示例,说明如何在 Python 应用程序中部署它并获得相应的分类器结果。
感谢你阅读这篇文章。希望在我的下一篇文章中再次见到你!
参考
- 安装空间——文件
- 空间项目:演示文本猫
- Reddit 上的嘲讽——Kaggle
基于支持向量机和拉曼光谱的新型冠状病毒疾病状态分类
原文:https://towardsdatascience.com/sars-cov-2-disease-state-classification-by-support-vector-machines-and-raman-spectroscopy-690c307a01cd?source=collection_archive---------29-----------------------
随着各国开始重新开放,大流行后世界的新挑战显露出来。最近,当我去国外参加一个会议时,我遇到了这种类型的挑战。在我在上述会议上的演讲结束后,我被安排乘飞机回家。为了登上国际航班的飞机,人们需要出示在 72 小时内进行的阴性新型冠状病毒(Covid)测试。实时逆转录聚合酶链反应(rRT-PCR)测试的周转时间通常为 24 小时或更长。我在起飞前 48 分钟做了一次测试,不幸的是,我没有及时收到测试结果。这导致了严重的时间延误、购买新机票的费用以及不必要的压力。
通过 rRT-PCR 的新型冠状病毒检测需要时间、专业人员和一定程度上集中的实验室、昂贵的试剂,并且是一个受操作者误差强烈影响的过程。抗原测试是分散的、快速的,并且是护理点诊断工具。护理点检测允许医生和医务人员在几分钟内而不是几小时内准确获得实验室质量的诊断结果。护理点对于测试航空旅行者是至关重要的,这种性质的测试本来可以解决我的问题。不幸的是,与 rRT‐PCR 相比,在 80%的灵敏度下,抗原测试遗漏受感染个体的概率比 rRT‐PCR 高 20%。这种较大的假阴性率降低了抗原测试的有效性,也是政府机构仍然使用阴性 rRT-聚合酶链式反应测试结果作为国际旅行的金标准 Covid 测试的原因。具有较低假阴性率的快速现场护理诊断解决方案将是国际机场的高度需求,并且可能具有优于 rRT-PCR 测试及其 3 天有效性的其他优势。新型冠状病毒的中位潜伏期为 5-6 天,因此,一个人完全有可能在 72 小时内被感染并被允许旅行。问题是:我们能否建立一个更好的快速测试来帮助国际旅游业尽快恢复元气?
类似拉曼光谱(RS)的振动光谱是用于诊断的有前途的分析技术。拉曼光谱已经证明了其在感染的护理点诊断中的适用性,并可能显示出疾病早期诊断的前景。拉曼光谱的工作原理是用单色光源(激光)照射样品,然后读取光与样品分子键相互作用引起的光波长变化。不同类型的键在波长上产生不同的变化,允许一个人产生一个“化学指纹”,理论上对每一个分子都是独一无二的。
通过抗原测试检测的分子是刺突蛋白,通过 rRT‐PCR 检测 RNA。拉曼是否可以看到新型冠状病毒感染的这些和其他分子标记,并区分个体/样本是否会检测出 covid 感染阳性或阴性?为了测试这个假设,我下载了一个血清拉曼光谱的数据集,这些血清来自 Covid 测试呈阳性和阴性的个体。血清测试对国际旅行的筛查不起作用,但是有的研究已经成功使用唾液样本的拉曼光谱。
这篇文章旨在实现两个目标。第一:看看我们能否用 Kaggle 免费提供的数据有效地检验之前陈述的假设。二:提供在高维数据上构建支持向量机分类器的教程。有了这两个目标,我们开始吧!
在 csv 文件中提供了光谱数据,每行对应于一个新的光谱/样品,每列对应于以拉曼位移(cm-1)为单位的光波长。转换成拉曼位移使 x 轴标准化,以说明入射激光的波长。为了构建一个基于光谱预测疾病状态的模型,我们将使用 python 并导入以下模块。
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import savgol_filter
import csv
from sklearn.decomposition import PCA
from math import sqrt
from sklearn.metrics import mean_squared_error
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn import svm
import seaborn as sns
我们将首先加载 csv 文件并获取每个光谱的类别信息。
vector = np.vectorize(np.float)
trainSetFile = r"Data/covid_and_healthy_spectra.csv"
labels = r"Data/covid_and_healthy_spectra.csv"with open(labels, newline='') as labelcsvfile:
labelcsvfile = csv.reader(labelcsvfile, delimiter=',', quotechar='|')
labelHeader = next(labelcsvfile)
classData = [0] for row in labelcsvfile:
classData.append(row[-1])
classData.pop(0)
接下来,我们将对类别信息进行编码,这些信息是表示“健康”或“新型冠状病毒”的字符串。我们将把这些转换成健康的 0 和新型冠状病毒的 1
def encode(x):
uniqueClasses = set(x)
encodedArray = np.array(x)
for count, word in enumerate(uniqueClasses):
indices = [i for i, y in enumerate(x) if y == word]
encodedArray[indices] = count
return encodedArrayencodeClassdata = encode(classData)
从这里,我们将从 csv 文件中读取光谱,并绘制每个光谱以进行可视化。

根据相关疾病状态着色的原始光谱(蓝色=健康,红色=新型冠状病毒)(图片由作者提供)
光谱根据其类别进行着色,红色代表 Covid 阳性,蓝色代表 Covid 阴性。数据需要清理,因为信号在某些光谱和区域有噪声。我将用 15 点三阶多项式 Savitzky-Golay 平滑处理数据,并用标准正态变量对数据进行标准化。我不会执行任何基线修正,因为上升的基线可能包含有助于我们的模型预测的诊断信息。我还将删除超过 1750 cm-1 的数据,因为那里存在的正弦信号可能来自标准具,这是一种由背反射引起的降低薄型背照式 CCD 性能的现象。我将展示我用来读取光谱、执行预处理和绘图的代码。
# Standard normal variate normalizationdef snv(y):
average = np.mean(y)
standardDev = np.std(y)
for count, element in enumerate(y):
y[count] = (element - average) / standardDev
return y with open(trainSetFile, newline='') as csvfile:
csvfile = csv.reader(csvfile, delimiter=',', quotechar='|')
header = next(csvfile)
for count, element in enumerate(header[1:]):
header[count] = header[count].split("cm-1")[0]
xvals = vector(header[1:-1])# indexes find the array position for the beginning and end of the
idx1 = (np.abs(xvals - 400)).argmin()
idx2 = (np.abs(xvals - 1750)).argmin()
xvals = xvals[idx1:idx2]
dataMatrix = np.zeros(len(xvals))
plot1 = plt.figure()
for count, row in enumerate(csvfile):
spectrum = np.asarray(row[idx1:idx2])
spectrum = vector(spectrum)
# Savitzky-golay smoothing, 15 point
spectrum = savgol_filter(spectrum, 15, 3, deriv=0)
# Standard Normal Variate
spectrum = snv(spectrum)
plt.plot(xvals, spectrum)
dataMatrix = np.vstack((dataMatrix, spectrum))
if row[-1] == "Healthy":
plt.plot(xvals, spectrum, color='blue', label='Healthy')
elif row[-1] == "SARS-CoV-2":
plt.plot(xvals, spectrum, color='red',label='SARS-CoV-2')
dataMatrix = np.delete(dataMatrix, (0), axis=0)
plt.xlabel("Raman Shifts ($cm^{-1}$)")
plt.title("Spectra of healthy and infected subjects")
plt.ylabel("Counts")
# Below gets unique series names to reduce size of the legend
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.show()

预处理和转换后的光谱由相关疾病状态着色(蓝色=健康,红色=新型冠状病毒)(图片由作者提供)
数据现在被平滑和归一化。我已经做了这种类型的预处理,因为我知道拉曼光谱是由我最喜欢的科学定律之一,比尔定律来辅助的。这是我最喜欢的,一部分是因为我喜欢啤酒,一部分是因为它非常有用。本质上,只要路径长度保持不变,来自样品中分子浓度的拉曼光子响应将是线性的。此外,如果被测物质相同,每列(波数)应遵循正态分布。然而,这仍然是高维数据,最好避免一些与维数灾难相关的陷阱。幸运的是,我们有主成分分析(PCA)来帮助解决这个问题。
PCA 是一种用于减少这种数据集的维度、增加可解释性并同时最小化信息损失的技术。它通过创建新的不相关变量来实现方差的连续最大化。在我们可以将 PCA 应用于数据之前,我们首先需要将数据集中,并将数据分成训练集和测试集。
dataMatrixTrans = dataMatrix.T
for col in dataMatrixTrans:
meanVal = np.mean(col)
for count, i in enumerate(col):
col[count] = col[count] – meanValPCAmat = dataMatrixTrans.T
X_train, X_test, y_train, y_test = train_test_split(PCAmat, encodeClassdata,test_size=0.33, random_state=42)
pca = PCA(n_components=5)
pca.fit(X_train)
PCAmat = pca.transform(X_train)plt.figure(figsize=(10,10))
plt.plot(np.arange(1, len(pca.explained_variance_ratio_)+1, 1), np.cumsum(pca.explained_variance_ratio_), 'ro-')
plt.xlabel("Component #")
plt.ylabel("% Variance Explained")
plt.grid()

总和方差图展示了随着每个连续成分的增加,我们的数据中解释了多少方差(图片由作者提供)
有了 5 个成分,我们能够解释数据集中超过 95%的差异。PCA 提取了 900 个预测变量,并将其转换为 5 个变量。更棒的是,我们可以画出这些新的变量,叫做载荷,来看看它们是什么样子的!
loadings = plt.figure()
for count, row in enumerate(pca.components_):
plt.plot(xvals, np.transpose(pca.components_[count]), label="PC " + str(count+1))
plt.title("Loadings")
plt.ylabel("Counts")
plt.xlabel("Raman Shifts ($cm^{-1}$)")
plt.legend()
plt.show()

来自 PCA 的载荷。负载代表我们变量的线性组合,以创建我们新的“潜在变量”(图片由作者提供)
加载目前看起来像一团乱麻,但其中包含有价值的信息,我们可以用它来帮助推断我们的模型的属性。我们可以以后再谈这个。
目标是在对数据集应用主成分分析后,查看是否出现了任何模式。将这些电脑的分数彼此对照,一个在 x 轴上,一个在 y 轴上,这就是我们将如何看到组件空间中是否出现了任何模式。将组件得分的组合相对于彼此作图,似乎 PC 4 与 PC 5 显示出最有趣的结果。

PC4 对 PC5 的观察分数(图片由作者提供)
PC 4 很好地将两个组分开。PC 5 有助于进一步分层,并表明 PCA 可以看到健康样本的 2 个亚群。没有更多关于这项研究的信息,我们只能推测亚组的有效性。回到负荷,PC 4 似乎在 800 cm-1 附近具有两个峰的结构,可能是从 400-600cm-1 上升的基线。上升的基线可能是由于荧光,这可能表明样品中存在更多的蛋白质或更多的细胞副产物。有必要进行更多的正交分析测试和测量,以确认从五氯苯甲醚中得出的任何推论,但这些推论可能对指导有用。
接下来,我们将使用我们的训练集数据来构建支持向量机(SVM)分类器,并在测试集上评估模型的性能。我们还不会调整分类器的超参数,但将简单地测量以三阶多项式为核心的简单 SVM 的性能。
# SVM classifier
SVMdataMatrix = PCAmat[:, 3:5]
SVMmodel = svm.SVC(kernel='poly', degree=3)#, C=1, gamma=1)
SVMmodel.fit(SVMdataMatrix, y_train)
# Testing Set
test_PCAmat = pca.transform(X_test)
test_SVMdataMatrix = test_PCAmat[:, 3:5]
test_preds = SVMmodel.predict(test_SVMdataMatrix)
print("test accuracy score: " + str(SVMmodel.score(test_SVMdataMatrix, y_test)))
测试准确度得分:0.931
看来我们在测试中取得了相当不错的准确度。然而,我们知道需要解决的更紧迫的问题是假阳性和假阴性读数的比率。我们将在混淆矩阵中绘制这些指标。
cfMat = metrics.confusion_matrix(y_test, test_preds)
disp = metrics.plot_confusion_matrix(SVMmodel, test_SVMdataMatrix, y_test, cmap=plt.cm.Blues, normalize='true', display_labels=classData)
plt.show()

混淆矩阵显示 15%的假阳性率(图片由作者提供)
好像我们的假阳性率是 15%,假阴性率是 0%。我可以想象在机场的旅客会因为一个假阳性结果而被禁止登机而感到非常沮丧!让我们调整模型的超参数,看看我们能否降低假阳性率。
from sklearn.model_selection import GridSearchCV
# parameter range
param_grid = {'C': [0.1, 1, 10, 100, 1000],
'gamma': [1, 0.1, 0.01, 0.001, 0.0001],
'kernel': ['poly'],
'degree':[0, 1, 2, 3, 4]}
grid = GridSearchCV(svm.SVC(), param_grid, refit=True, verbose=3)
# fitting the model for grid search
grid.fit(SVMdataMatrix, y_train)
print(grid.best_params_)
print(grid.best_estimator_) plt.show()
{'C': 0.1,'度数':1,' gamma': 1,'内核':' poly'}
SVC(C=0.1,度数=1,伽玛=1,内核='poly ')
看起来使用 gridsearch 来调整超参数已经为 SVM 分类器确定了我们的最佳参数,该分类器是具有 C=0.1 和γ= 1 的一阶多项式核。让我们绘制应用于我们的测试集的这个模型的新混淆矩阵。

混淆矩阵显示 12%的假阳性率(图片由作者提供)
现在我们可以看到,我们能够将假阳性率从 15%降低到 12%。这并不激烈,但却是朝着正确方向迈出的一步。让我们通过绘制决策边界来看看我们的模型是如何对数据进行分类的。
# Create color maps
cmap_light = ListedColormap(['orange', 'cyan'])
cmap_bold = ['darkorange', 'darkblue']
# Plotting the decision boundary
x_min, x_max = test_SVMdataMatrix[:, 0].min() - 1, test_SVMdataMatrix[:, 0].max() + 1
y_min, y_max = test_SVMdataMatrix[:, 1].min() - 1, test_SVMdataMatrix[:, 1].max() + 1
h = 0.02
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
zMat = np.c_[xx.flatten(), yy.flatten()]
Z = grid.predict(zMat[:, 0:2])
# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=cmap_light, alpha=0.8)
sns.scatterplot(test_SVMdataMatrix[:, 0], test_SVMdataMatrix[:, 1], hue=nocode_y_test, palette=cmap_bold, alpha=1.0, edgecolor="black")plt.xlabel('PC 4')
plt.ylabel('PC 5')

PC4 与 PC5 得分由疾病状态着色,背景由 SVM 决策边界着色(图片由作者提供)
看起来这个模型是通过 PC 4 用一条直线分割这些组。
这个模型仅仅基于使用 PC 4 和 PC 5,但是我们可以包括更多的组件。一开始使用两个更容易演示和绘制决策边界。让我们看看是否可以通过添加组件 1 到 5 来进一步改进模型。

混淆矩阵显示 10%的假阳性率(图片由作者提供)
现在,我们使用线性 SVM 分类器(C=0.1,gamma=1)将假阳性率降至 10%,这与我们之前训练的模型完全相同!使用更多组件似乎有助于进一步降低我们的假阳性率!
摘要
我们已经提供了一个快速概述如何拉曼光谱可能有潜力作为一个点的护理工具检测新型冠状病毒。我们能够证明,我们可以使用 PCA 维数缩减和支持向量机分类器,基于 Covid 感染和未感染个体的血清的拉曼光谱,实现对 Covid 感染和未感染个体的分类。这是一个很好的潜力演示,但当我们试图将该数据集应用和扩展到现实世界的诊断工具时,我们必须仔细考虑。
首先,数据集是血清的,从航空旅客身上提取血液是不可行的。你需要多名训练有素的护士,然后瓶颈就变成了抽血。唾液是一种更好的方法,Carlomagno 等人已经证明了这一点。唾液样本可能会有更复杂的问题,因为食物或饮料的物质身份最终可能会掩盖冠状病毒的信号,甚至导致假阳性。
拉曼光谱也可能被证明不够敏感,无法检测低浓度的病毒和生物标志物,因此其他分析仪器可能更适合,如质谱分析,它已经在世界各地的机场广泛存在,用于检测各种违禁物质。
最后,我们没有关于样品是如何被物理处理的良好信息。两类样本在储存、化学或物理处理方面的差异可能会导致我们的模型基于这些影响进行分类,并且无法准确预测真实世界的样本。
尽管存在假设和潜在的缺点,但我们能够证明,我们可以使用 PCA 维数缩减和支持向量机分类器,基于 Covid 感染和未感染个体的血清拉曼光谱,实现对他们的分类。需要更快和更准确的护理点 Covid 诊断测试,尽管拉曼可能显示出潜力,但应继续寻找更好的分析测试。
SAS 到 Python —函数式与逐行翻译
原文:https://towardsdatascience.com/sas-to-python-r-functional-vs-line-by-line-code-refactoring-4288e9f11eb0?source=collection_archive---------19-----------------------
数据帧结构和方法消除了在旧的过程语言中必要的迂回逻辑和额外的数据结构

Unsplash.com
在最近重构了使用医疗保险/医疗补助服务中心的公共数据计算医院评级的代码后(原始代码和数据可以在https://quality net . CMS . gov/inhibitory/public-reporting/overall-ratings/SAS找到),我想我可以在这里获得我的关键见解。
从这种转换中可以观察到,数据帧的力量已经完全改变了可读性和交付速度的标准。由于 SAS 是从早期的过程语言世界演变而来的,早期的过程语言世界包括 FORTRAN 和 COBOL,具有统一数据类型和元素式操作的数组类型数据结构,抽象级别可通过异构数据数组来实现,这些数据数组逐个元素地循环,以执行通常需要并行数组进行后续处理的算术或比较。
这里有一个例子。在下面的 SAS 代码中,目标是识别具有少于 100 个观察值的评级类别,并从数据集中删除这些列:
PROC SQL;
select measure_in_name into: measure_in separated by '' notrim
from include_measure0;
QUIT;
%put &measure_in;/* &measure_cnt: number of included measure */
PROC SQL;
select count(measure_in_name)
into: measure_cnt
from include_measure0;
QUIT;
%put &measure_cnt;/*COUNT # HOSPITALS PER MEASURE FOR ALL MEASURES*/
PROC TABULATE DATA=All_data_&year.&quarter out=measure_volume;
var &measure_all;table n*(&measure_all);
RUN;PROC TRANSPOSE data=Measure_volume out=measure_volume_t;
RUN;/* IDENTIFY MEASURES WITH VOLUMN <=100 */
DATA less100_measure (drop=_NAME_ _LABEL_ rename = (COL1=freq));
SET measure_volume_t (where = (col1<=100));if _name_ ^= '_PAGE_' and _name_^='_TABLE_';
measure_name = tranwrd(_NAME_, '_N', '');RUN;
DATA R.less100_measure;SET less100_measure;run;*OP-2;/* CREATE a measure list for count<=100 */
PROC SQL;
select measure_Name
into: measure_exclude separated by '' notrim
from Less100_measure;
QUIT;/* REMOVE MEASURES WHICH HAVE HOSPITAL COUNTS <=100*/
DATA initial_data_&year.&quarter;
SET All_data_&year.&quarter;/* measure volume <=100*/
drop &measure_exclude ;
RUN;
代码首先创建一个结构来保存列名,然后创建一个结构来填充每个指定列中的观察计数。接下来,它确定哪些列的观察值少于 100 个,并创建一个结构来保存这些列名,最后,使用这些名称将它们从主数据数组中删除。
下面是使用相同初始数据的 pandas 数据框架的等效 python:
# grab all columns with hospital counts>100
dfObs100=df[df.columns.intersection(df.columns[df.notna().sum()>=100])]
没有创建显式的数据结构,也没有执行基于元素的计算循环。一切都发生在 pandas 函数内部,这意味着您可以获得由包开发人员创建的用于循环行和列的最先进的内部方法的好处。
另一个例子是程序包中程序 1 的代码,它由一个 SAS 程序文件和另一个文件中的宏组成,用于计算标准化的组分数。以下是程序 1 的 SAS 代码:
******************************************
* Outcomes - Mortality *
******************************************;
*option mprint;
/* count number of measures in Outcome Mortality Group */
PROC SQL;
select count(measure_in_name)
into: measure_OM_cnt /*number of measures in this domain*/
from Outcomes_mortality;/*Outcomes_mortality is generated from the SAS program '0 - Data and Measure Standardization_2021Apr'*/
QUIT;/*OM is used to define the data name for mortality Group;
&measure_OM is the measures in Mortality Group;
&measure_OM_cnt is the number of measures in this Group;*/
/*output group score in R.Outcome_mortality*/
%grp_score(&MEASURE_ANALYSIS, OM, &measure_OM, &measure_OM_cnt,R.Outcome_mortality);***************************************
* Outcomes - Safety of Care *
***************************************;/* count number of measures in Outcome Safety Group */
PROC SQL;
select count(measure_in_name)
into: measure_OS_cnt
from Outcomes_safety;/*Outcomes_safety is generated from the SAS program '0 - Data and Measure Standardization_2021Apr'*/
QUIT;/*OS is used to define the data name for Safety Group;
&measure_OS is the measures in Safety Group;
&measure_OS_cnt is the number of measures in Safety Group;*/
/*output group score in R.Outcome_safety */
%grp_score(&MEASURE_ANALYSIS, OS, &measure_OS, &measure_OS_cnt, R.Outcome_safety);********************************************
* Outcomes - Readmission *
********************************************;/* count number of measures in Outcome Readmission Group */
PROC SQL;
select count(measure_in_name)
into: measure_OR_cnt
from Outcomes_readmission;/*Outcomes_readmission is generated from the SAS program '0 - Data and Measure Standardization_2021Apr'*/
QUIT;/*OR is used to define the data name for Readmission Group;
&measure_OR is the measures in Readmission Group;
&measure_OR_cnt is the number of measures in Readmission Group;*/
/*output group score in R.Outcome_readmission*/
%grp_score(&MEASURE_ANALYSIS, OR, &measure_OR, &measure_OR_cnt, R.Outcome_readmission);************;******************************************
* Patient Experience *
******************************************;/* count number of measures in Patient Experience Group */
PROC SQL;
select count(measure_in_name)
into: measure_PtExp_cnt
from Ptexp;/*Ptexp is generated from the SAS program '0 - Data and Measure Standardization_2021Apr'*/
QUIT;/*PtExp is used to define the data name for Patient Experience Group;
&measure_PtExp is the measures in Patient Experience Group;
&measure_PtExp_cnt is the number of measures in Patient Experience Group;*/
/*output group score in R.PtExp*/
%grp_score(&MEASURE_ANALYSIS, PtExp, &measure_PtExp, &measure_PtExp_cnt,R.PtExp);**********************************************
* Timely and Effective Care *
**********************************************;/* count number of measures in Timely and Effective Care */
PROC SQL;
select count(measure_in_name)
into: measure_Process_cnt
from Process;/*Process is generated from the SAS program '0 - Data and Measure Standardization_2021Apr'*/
QUIT;
下面是程序 1 中使用的附带宏:
**********************************************************
* macro for calcuating group score for each measure group*
**********************************************************;%macro grp_score(indsn, gp, varlist, nmeasure, Out_avg);
data dat0 (keep=provider_id &varlist. c1-c&nmeasure. total_cnt measure_wt avg );
set &indsn.;array M(1:&nmeasure.) &varlist.;
array C (1:&nmeasure.) C1-C&nmeasure.;DO k =1 TO &nmeasure.;
if m[k] ^=. then C[k]=1;
else C[k]=0;
END;
total_cnt=sum(of c1-c&nmeasure.);
if total_cnt>0 then do;
measure_wt=1/total_cnt;
avg=sum(of &varlist.)*measure_wt;
end;
run;
*standardization of group score;
PROC STANDARD data=dat0 mean=0 std=1 out=dat1;var avg;run;*add mean and stddev into the data;
ods output summary=new(drop=variable);
proc means data=dat0 stackodsoutput mean std ;
var avg;
run;proc sql;
create table dat2 as
select *
from dat0, new;
quit;data &out_avg;merge dat2(rename=avg=score_before_std) dat1(keep=provider_ID avg rename=avg=grp_score);by provider_ID;run;
%mend;
下面是我用 python 编写的等价程序 1 代码:
# mortality scores
mortality=getScores(dfAllStd,df,mortalityFields)
# safety scores
safety=getScores(dfAllStd,df,safetyFields)
# readmission scores
readmit=getScores(dfAllStd,df,readmitFields)
# patient care scores
patient=getScores(dfAllStd,df,pxFields)
# process scores
process=getScores(dfAllStd,df,processFields)
使用支持 python 的函数 getScores(),大致相当于 SAS 宏:
def getScores(dfStd,dfAll,fields):
# get fields counts and weights
cnt=dfStd[dfStd.columns.intersection(fields)].count(axis=1,numeric_only=True)
wt=(1/cnt).replace(np.inf,np.nan)#get raw scores
scoreB4=dfStd[dfAll.columns.intersection(fields)].mean(axis=1)
# standardize scores
sMean=np.nanmean(scoreB4)
sStddev=np.nanstd(scoreB4)
score=(scoreB4-sMean)/sStddev
#generate table of values
table5=pd.DataFrame({'id':df['PROVIDER_ID'],'count':dfAllStd[dfAllStd.columns.intersection(fields)].count(axis=1,numeric_only=True),
'measure_wt':wt,'score_before':scoreB4,'score_std':score})
return table5
正如您再次看到的,python 代码更小,并且使用隐式熊猫循环更容易阅读。
通过在 R 中使用数据帧可以获得类似的紧凑结果。事实上,隐式“应用”函数循环对于 R 计算性能至关重要。
另一个教训是,由于自动化重构工具只会逐行重建原始 SAS 代码的结构,所以典型的翻译人员只会复制旧结构及其原始设计问题。对于输入和输出的数据结构不太可能改变的操作,这可能是有意义的,但是,随着数据可用性的增长,很可能会越来越需要和可能输入更多的并行字段。具有新输出的新模型将更加常见,这使得代码很可能需要适应来自新建模技术的新输出。
如果语言转换的目的是使代码现代化并适应新的数据通道和建模能力,那么自动化代码重构将是一个障碍。因此,在开始重构旧的数据科学代码之前,重要的是确定您想要利用代码的哪些部分,并计划使用目标语言中可用的灵活功能,然后使用旧代码作为参考的功能规范进行重构。
总之,主要的收获是
- 逐行转换锁定了旧的程序结构,与新的语言功能相比,这可能是次优的
- 数据帧加上对其进行操作的函数可以创建更好、可读性更强的代码,从而更易于维护
- 进行逐行翻译的简单翻译器可能能够访问新的方法和模型,但是将关键的程序领域锁定在低级的数据和逻辑范例中
- 在 pandas 和其他包中使用嵌入式函数为列和行操作上的循环提供了一流的性能
最后,对于使用相似数据结构和循环的 FORTRAN 和 COBOL 的翻译,也存在同样的问题。现代语言的真正力量在于数据框架和功能,释放它需要超越简单机器翻译的非线性连接。
使用 Python 进行卫星影像分析
原文:https://towardsdatascience.com/satellite-imagery-analysis-using-python-9f389569862c?source=collection_archive---------2-----------------------
遥感|数据分析| Python
使用 Python 对 Sundarbans 的卫星图像进行数据分析的详细说明

美国地质勘探局在 Unsplash 上拍摄的照片
本文帮助读者更好地理解卫星数据以及使用 Python 探索和分析 Sundarbans 卫星数据的不同方法。
目录
- 孙德尔本斯卫星图像
- 数据分析
- 植被和土壤指数
- 水指数
- 地质指标
- 结论
- 参考文献
让我们开始吧✨
孙德尔本斯卫星图像
孙德尔本斯是孟加拉湾恒河、布拉马普特拉河和梅克纳河汇合形成的三角洲中最大的红树林区之一。孙德尔本斯森林横跨印度和孟加拉国,面积约为 10,000 平方公里,其中 40%位于印度,是许多珍稀和全球濒危野生物种的家园。下面的谷歌地图显示了孙德尔本斯地区。
来源:谷歌地图
在本文中,我们将使用 2020 年 1 月 27 日使用 Sentinel-2 卫星获得的 Sundarbans 卫星数据的一小部分。saidSundarbans 数据的优化自然色图像如下所示:

孙德尔本斯数据的优化自然彩色图像—作者提供的图像
卫星数据有 954 * 298 像素,12 个波段,光谱分辨率从 10 — 60 米不等。可以使用下面的链接下载数据。
https://github.com/syamkakarla98/Satellite_Imagery_Analysis/tree/main/Data/sundarbans_data
数据分析
为了对 Sundarbans 数据执行不同的操作,我们将使用 EarthPy、RasterIO、Matplotlib、Plotly 等库进行数据可视化和分析。
让我们从导入必要的包开始编码,
读出数据
让我们使用 rasterio 读取 12 个波段,并使用 numpy.stack()方法将它们堆叠成一个 n 维数组。堆叠后的结果数据具有形状(12,954,298)。
可视化波段
正如我们所讨论的,数据包含 12 个波段。让我们用 EarhPy 包来可视化每个波段。plot_bands()方法采用带和图的堆栈以及自定义标题,这可以通过使用title=参数将每个图像的唯一标题作为标题列表传递来完成。

乐队的可视化-作者提供的图像
RGB 合成图像
这些 Sundarbans 数据有多个波段,包含从可见光到红外的数据。所以对人类来说很难将数据可视化。通过创建 RGB 合成图像,可以更容易有效地理解数据。要绘制 RGB 合成图像,您将绘制红色、绿色和蓝色波段,分别为波段 4、3 和 2。由于 Python 使用从零开始的索引系统,所以需要从每个索引中减去值 1。因此,红色波段的指数为 3,绿色为 2,蓝色为 1。
如果像素亮度值偏向零值,我们创建的合成图像有时会很暗。这种类型的问题可以通过拉伸图像中的像素亮度值来解决,使用参数stretch=True将这些值扩展到潜在值的整个 0-255 范围,以增加图像的视觉对比度。此外,str_clip参数允许您指定想要截取多少数据尾部。数字越大,数据将被拉伸或变亮的越多。
让我们看看绘制 RGB 合成图像以及应用拉伸的代码。

孙德尔本斯数据的 RGB 合成图像-作者提供的图像
上图显示了应用拉伸前后 Sundarbans 数据的 RGB 合成图像。
直方图
可视化高光谱图像数据集的波段有助于我们理解波段的像素/值的分布。来自earhtpy.plot的hist方法通过为我们之前创建的数据集/堆栈的条带绘制直方图来完成工作。我们还可以修改各个直方图的列大小,标题,颜色。让我们看看绘制直方图的代码。

波段直方图-按作者分类的图像
植被和土壤指数
归一化卫星指数是根据多光谱卫星图像计算的图像。这些图像强调了存在的特定现象,同时减轻了降低图像效果的其他因素。例如,植被指数将健康植被显示为指数图像中的亮色,而不健康植被的值较低,贫瘠地形为暗色。由于地形变化(丘陵和山谷)的阴影会影响图像的强度,因此创建索引时会强调对象的颜色,而不是对象的强度或亮度。
归一化差异植被指数(NDVI)
为了确定一块土地上的绿色密度,研究人员必须观察植物反射的可见光(VIS)和近红外(NIR)阳光的不同颜色(波长)。归一化差异植被指数(NDVI)通过测量植被强烈反射的近红外和植被吸收的红光之间的差异来量化植被。NDVI 的范围总是从-1 到+1。
NDVI = ((NIR - Red)/(NIR + Red))
例如,当你有负值时,很可能是水。另一方面,如果 NDVI 值接近+1,则很有可能是浓密的绿叶。但是当 NDVI 接近零度时,就没有绿叶,甚至可能成为城市化地区。
让我们看看在 Sundarbans 卫星数据上实现 NDVI 的代码。

孙德尔本斯的 NDVI 数据—图片由作者提供
土壤调整植被指数(SAVI)
土壤调整植被指数(SAVI)是一种植被指数,它试图使用土壤亮度校正因子来最小化土壤亮度的影响。这通常用于植被覆盖率低的干旱地区。
SAVI = ((NIR - Red) / (NIR + Red + L)) x (1 + L)
L 值根据绿色植被覆盖的数量而变化。一般在没有绿色植被覆盖的地区,L = 1;在中度绿色植被覆盖区,L = 0.5 在植被覆盖非常高的地区,L=0(相当于 NDVI 方法)。该指数输出介于-1.0 和 1.0 之间的值。让我们看看 SAVI 的实现代码。

孙德尔本斯的 SAVI 数据—图片由作者提供
可见大气阻力指数(VARI)
可见大气阻力指数(VARI)旨在强调光谱可见部分的植被,同时减轻光照差异和大气影响。非常适合 RGB 或彩色图像;它利用了所有三种颜色波段。
VARI = (Green - Red)/ (Green + Red - Blue)

孙德尔本斯的 VARI 数据—图片由作者提供
水指数
地表水变化是环境、气候和人类活动的一个非常重要的指标。sentinel-2、Landsat 等遥感器在过去四十年里一直在提供数据,这对于提取森林和水等土地覆盖类型很有用。研究人员提出了许多地表水提取技术,其中基于指数的方法因其简单和成本效益高而受到欢迎。
修正的归一化差异水指数
修正的归一化差异水体指数(MNDWI)使用绿色和 SWIR 波段来增强开放水体的特征。它还减少了在其他指数中经常与开放水域相关的建成区特征。
MNDWI = (Green - SWIR) / (Green + SWIR)
下面的代码用于实现 MNDWI,输出如下所示。

孙德尔本斯数据的 MNDWI 图片由作者提供
归一化差异湿度指数(NDMI)
归一化差异湿度指数(NDMI)对植被中的湿度水平很敏感。它被用来监测干旱以及火灾多发地区的燃料水平。它使用近红外和 SWIR 波段来创建一个比率,旨在减轻照明和大气的影响。
NDMI = (NIR - SWIR1)/(NIR + SWIR1)
让我们看看实现和输出:

孙德尔本斯的 NDMI 数据—图片由作者提供
地质指数
事实证明,卫星图像和航空摄影是支持矿产勘探项目的重要工具。它们可以以多种方式使用。首先,它们为地质学家和野外工作人员提供了轨迹、道路、栅栏和居住区的位置。
粘土矿物
粘土比率是 SWIR1 和 SWIR2 带的比率。这一比率利用了粘土、明矾石等含水矿物吸收光谱中 2.0-2.3 微米部分的辐射这一事实。由于该指数是一个比率,因此可以减轻由于地形造成的光照变化。
Clay Minerals Ratio = SWIR1 / SWIR2

孙德尔本斯数据的 CMR 由作者提供的图像
含铁矿物
含铁矿物比例突出了含铁材料。它使用 SWIR 波段和近红外波段之间的比率。
Ferrous Minerals Ratio = SWIR / NIR

孙德尔本斯的 FMR 数据—图片由作者提供
结论
本文介绍了使用 python 分析孙德尔本斯卫星数据的不同方法,如数据可视化和归一化植被、水和地质指数。
文章中使用的卫星数据和详细代码可以通过下面的 GitHub 链接获得。
快乐学习!
https://github.com/syamkakarla98/Satellite_Imagery_Analysis
更多来自作者
参考
https://www.usgs.gov/centers/eros/science/usgs-eros-archive-sentinel-2?qt-science_center_objects=0#qt-science_center_objects https://www.sentinel-hub.com/
饱和模型、偏差和平方和的求导
原文:https://towardsdatascience.com/saturated-models-deviance-and-the-derivation-of-sum-of-squares-ee6fa040f52?source=collection_archive---------8-----------------------
利用饱和模型和偏差探讨平方和误差的来源

罗伯特·斯汤普在 Unsplash 上拍摄的照片
在我之前的帖子中,我已经讨论过广义线性模型(GLMs) 。这些是线性回归模型的概括,其中目标的变量分布是非正态。使用确定问题的损失函数的最大似然估计求解 GLMs。这就是分别用于线性和逻辑回归的平方和和对数损失的来源。然后,我们使用这些损失函数来拟合数据的模型。然而,我们如何确定我们的拟合模型捕捉到的数据有多好?这就是离经叛道的原因。
什么是空模型、建议模型和饱和模型?
在我们讨论偏差之前,我们首先需要了解什么是饱和模型、建议模型和无效模型。
饱和模型是指参数/系数的数量等于数据点的数量。这就像一个‘连接点’模型,其中直线或曲线通过每个点。这被认为是完美模型,因为它考虑了数据中的所有方差,并具有最大可实现可能性。
零模型与相反,只有一个参数,即截距。这实质上是所有数据点的平均值。对于一个双变量模型,这是一条水平线,每一点都有相同的预测。
提议的模型被认为是最佳拟合,并且在零模型和饱和模型之间有个参数。这是我们适合数据科学和机器学习问题的模型。
下面的脚本是 Python 中的一段代码,它从随机生成的数据集中绘制了一个空的、建议的和饱和的模型。这段代码利用了‘NP . poly fit’方法,允许我们绘制不同的指定次数多项式。
# import packages
import numpy as np
import matplotlib.pyplot as plt# generate data and sort it
x = np.random.randn(10)
y = np.random.randn(10)
x.sort()
y.sort()# calculate the null, proposed and saturated models
null_coeff = np.polyfit(x, y, 0)
null_model = np.poly1d(null_coeff)
null_x = np.linspace(x[0], x[-1])
null_y = null_model(null_x)saturated_coeff = np.polyfit(x, y, len(x))
saturated_model = np.poly1d(saturated_coeff)
saturated_x = np.linspace(x[0], x[-1])
saturated_y = saturated_model(saturated_x)proposed_coeff = np.polyfit(x, y, 3)
proposed_model = np.poly1d(proposed_coeff)
proposed_x = np.linspace(x[0], x[-1])
proposed_y = proposed_model(proposed_x)# plot the models
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(22,7))ax1.plot(null_x, null_y, color="blue")
ax1.scatter(x,y,s=70, color="blue")
ax1.set_title('Null Model', fontsize=22)
ax1.axes.xaxis.set_visible(False)
ax1.axes.yaxis.set_visible(False)ax2.plot(proposed_x, proposed_y, color="red")
ax2.scatter(x,y,s=70, color="red")
ax2.set_title('Proposed Model', fontsize=22)
ax2.axes.xaxis.set_visible(False)
ax2.axes.yaxis.set_visible(False)ax3.plot(saturated_x, saturated_y, color="green")
ax3.scatter(x,y,s=70, color="green")
ax3.set_title('Saturated Model', fontsize=22)
ax3.axes.xaxis.set_visible(False)
ax3.axes.yaxis.set_visible(False)
此代码的输出产生以下图形:

从左到右显示零模型、建议模型和饱和模型的图。作者制作的图像。
我们观察到零模型不擅长对数据进行分类,然而另一方面,饱和模型过度分类。在数据科学术语中,这是过拟合,并且模型具有高方差。然而,提出的模型最好地概括了数据。
完整的代码可以在我的 GitHub 这里找到。
异常
偏差是统计模型的拟合优度度量,尤其用于 GLMs。它被定义为饱和模型和建议模型之间的差异,并且可以被认为是我们建议的模型说明了数据中的多少变化。因此,偏差越低,模型越好。
数学上,总偏差, D ,定义为:

作者的总偏差公式
其中 L_s 和 L_p 分别为饱和模型和建议模型。 μ 值是输入值的矩阵点积、 x 及其系数 β 的预测值:

作者的线性模型预测
这些系数负责拟合最佳模型,可以通过分析或迭代方法梯度下降找到。感兴趣的读者可以在我之前的文章中更好地理解如何拟合这些系数。
线性回归偏差
我们现在将推导线性回归的偏差,显示误差平方和(SSE) 的来源。在线性回归中,目标变量有一个正态分布,因此概率密度函数为单一预测,μ,而 y ,为:

正态分布的概率密度函数,作者
上述函数的对数似然为:

按作者列出的正态分布的对数似然性
这是我们提出的模型的对数似然。需要重申的是,这只是针对单一的预测和观察。这被定义为单元偏差,而总偏差是所有单元偏差的总和。
通过设置 μ=y ,我们得到最大可达对数似然,这就是饱和模型:

饱和模型可能性,作者
因此,单位偏差, d ,是:

按作者列出的正态分布的单位偏差
总偏差是:

按作者列出的正态分布的总偏差
这就是总平方和误差!
因此,我们可以看到,偏差是线性回归的(比例)平方和误差的通用公式。我们可以对其他概率分布进行类似的推导,如泊松、伽马和二项式 l 分布,使用它们的 pdf 来计算它们的偏差。例如,如果你的目标是二项分布,偏差就是对数损失公式!
总结想法
在本文中,我们已经了解了饱和模型以及它们如何与称为偏差的拟合优度度量相联系。该值描述了建议的模型考虑了多少数据变化。如果饱和的和建议的模型符合正态分布,偏差等于我们在这里推导出的普遍存在的平方和。
我希望你喜欢这篇文章,并学到一些新的东西!请随意阅读我的其他帖子,进一步探索 GLMs!
和我联系!
- 要在媒体上阅读无限的故事,请务必在这里注册! 💜
- /subscribe/@egorhowell😀
- LinkedIn👔
- 推特 🖊
- github🖥**
- https://www.kaggle.com/egorphysics🏅****
(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。执照: CC BY-SA 4.0
土星云 vs 谷歌 Colab 的数据科学和机器学习
原文:https://towardsdatascience.com/saturn-cloud-vs-google-colab-for-data-science-and-machine-learning-ea3a02165c5?source=collection_archive---------10-----------------------
哪种工具更适合可扩展数据科学?

没有 GPU、并行编程和 DevOps 团队的端到端数据科学管道的图示。在 Unsplash 上由 amirali mirhashemian 拍摄的照片
向任何数据科学家询问他们在工作中最常用的工具。很有可能,你会听到很多关于 Jupyter notebook 或者 Google Colab 的消息。这并不奇怪,因为数据科学家经常需要一个交互式环境来编码-以立即看到我们数据争论的结果,从可视化中提取见解,并密切监控机器学习模型的性能。就我个人而言,我希望我的代码执行得非常快,如果不是立即执行的话。这通常在 GPU 和并行编程的帮助下完成。
在之后,一个机器学习模型被开发并在本地环境中测试,它必须上线并被部署。不幸的是,部署过程非常复杂。这项工作涵盖了从创建服务器到建立安全协议的所有领域。完成这些工作通常需要一名专门的 DevOps 工程师,他是云服务、操作系统和网络方面的专家。
现在,数据科学家如何大幅加快我们的数据科学发展进程?像我们这样的数据科学家如何绕过 DevOps 工程师的需求,部署我们的模型?
这就是土星云能为数据从业者做的事情。 土星用分布式系统和 GPU 帮助团队训练和部署模型。
好奇?在这篇博文中,我将展示 Saturn Cloud 与 Google Colab 的相似之处(但也有很大不同),以及如何使用 Saturn Cloud 来优化您的数据科学工作流。
以下是土星云和 Colab Pro 的六大区别。
- 定价
- 编码界面的外观
- 易于部署和共享仪表板
- 运行时的可定制性
- 并行计算的代码效率
- 支持水平
定价
土星云和谷歌 Colab 都提供免费和付费服务。下表比较了这两种服务。
谷歌 Colab 和土星云价格对照表。来源于 a Colab 笔记本和 Stackoverflow 。
对于许多初学者来说,Google Colab 免费提供的服务已经足够了。那些想要比谷歌免费 Colab 更多资源的人可以选择 9.99 美元的低价 Colab Pro。然而,那些寻求更大灵活性和易于部署的人会发现土星云是 Google Colab 的一个有吸引力的替代方案。
请注意,虽然本文中讨论的所有功能都适用于自由层 Saturn Cloud,但 Saturn Cloud 的全部功能在 Pro 版本中是不可用的。
编码界面的外观
Google Colab 的界面类似于 Jupyter 笔记本,只是它包含一些独特的功能。这些功能包括显示文件夹目录的左窗格和右上角提醒您资源使用情况的两个栏。

谷歌 Colab 屏幕。作者截图。
另一方面,土星云编码环境和 JupyterLab 的完全一样。事实上,土星是建立在木星实验室上的。JupyterLab 为数据科学家提供了在 Jupyter 笔记本中编码、访问 shell 终端和在 GUI 环境中移动文件的界面。
如果你喜欢在 Jupyter 笔记本上运行你的代码,你也可以在 Saturn Cloud 上运行。

木星实验室的屏幕,位于土星云上。
易于部署和共享交互式控制面板
许多 python 包允许我们构建用户可以与之交互的交互式仪表盘。这些软件包包括 Plotly Dash、Voila 和 Bokeh。这种交互式仪表盘可以在 Google Colab 和 Saturn Cloud 上构建。在这个例子中,我将使用 Google Colab 和 Saturn Cloud 从的 Voila Gallery 复制一个交互式仪表盘。

瞧,交互式仪表板。作者截屏。由画廊制作的仪表板。
为了与访问者共享仪表板,用户需要将仪表板部署到服务器,以便用户可以与可视化交互。易于部署是谷歌 Colab 和土星云的关键区别。
在 Google Colab 上,用户可能需要依赖第三方解决方案 Heroku 或 Ngrok 进行部署,这有些繁琐。另一方面,在 Saturn Cloud 上部署仪表板相对简单,只需要五次点击,因为 Saturn Cloud 已经处理了与部署相关的繁重工作。

在土星上部署仪表板只需几步之遥。作者截屏。
简而言之,虽然可以在 Google Colab 和 Saturn Cloud 上部署交互式可视化,但后者可以为您节省宝贵的时间。
运行时的可定制性

在设置运行时被宠坏了…照片由叶戈尔·迈兹尼克在 Unsplash 上拍摄
Google Colab 最吸引人的额外津贴之一是它的免费运行时,包括 CPU、GPU、TPU 和大约 12GB 的内存(在撰写本文时)。像谷歌 Colab 这样的基于云的笔记本的出现,以及免费的资源,确实使深度学习民主化了。如今,任何拥有谷歌账户的人都可以获得一些 GPU 来训练他们的神经网络。

你可以通过进入菜单>运行时>更改运行时,在 Google Colab 上选择 CPU、GPU 或 TPU 运行时。
然而,为了让 Colab 对所有人免费,Colab 中可用的 GPU 类型会随着时间的推移而变化,并且没有办法选择一个人在任何给定时间可以连接的 GPU 类型,即使你是 Colab Pro 用户。
此外,如果你是一个广泛使用谷歌 Colab 的极客,你一定遇到过这些毁灭性的屏幕之一…



向你们死去的内核致以最深切的哀悼…作者截图。
- 您的 Google Drive 空间不足,无法存储您的数据或模型
- 你的 GPU 内存使用被切断
- 您的会话因内存不足而崩溃
- 您的会话在 1 小时不活动或运行笔记本 12 小时后超时
这些屏幕可能非常具有破坏性。如果 GPU 内存使用被切断,您的模型可能没有得到足够的训练。如果你在训练一个模型的时候运行时崩溃了,你基本上失去了所有的进展。当然,有一些技巧可以确保解决每种情况。然而,我们不能确定这样的黑客攻击会无限期地有效。一个人可以注册 Colab Pro 来获得对这些资源的优先访问权,但是他们不能得到保证。
这就是 Saturn Cloud 的硬件可定制性派上用场的地方。
在土星云上运行笔记本之前,必须创建一个工作空间。用户可以自由定制工作空间,包括所需的磁盘空间(从 10 GB 到 1000 GB)、硬件(CPU/GPU)、大小要求(从 2 核 4GB 到 64 核 512GB)以及关闭持续时间(从 1 小时到从不关闭)。因为您是这个工作区的老板,所以您不需要担心空间、GPU 访问、内存或运行时的不足。
额外的好处是能够用现有的 Docker 图像建立一个工作空间。这意味着工作空间将由 Docker 映像指定的某些包来设置,允许您复制其他人编写的代码。

在土星云上设置可定制的工作空间
并行计算的代码效率
并行计算是同时使用多个计算资源来解决一个计算问题。与顺序解决大问题的非并行(或串行)编程不同,并行编程将一个问题分解成更小的部分,同时解决这些小问题。
并行编程可以加速计算繁重的任务。例如,并行编程允许程序员加载和处理大型数据集(尤其是当它们太大而无法保存在内存中时)。它还允许超参数调整过程更快。
python 中有很多并行编程的包。其中最著名的是 Dask。它被设计为在单机设置和多机集群上工作良好,并且可以与 pandas、NumPy、scikit-learn 和其他 Python 库一起使用。想了解更多关于 Dask 的信息,你可以参考 Saturn Cloud 关于 Dask 的文档。

并行计算分解了一个大问题,因此可以由许多工作人员同时解决。照片由 Salmen Bejaoui 在 Unsplash 上拍摄
你可以在 Google Colab 和 Saturn Cloud 上使用 Dask。然而,一个人在 Saturn Cloud 上比在 Google Colab 上有更大的潜力来加速他们的代码。
这是因为并行化您的代码所能获得的加速量取决于工作空间的规格。直观地说,如果一个 CPU 有更多的核心,那么就有工人来处理这些小问题。这意味着并行编程有更大的加速潜力。
由于用户可以在 Saturn Cloud 中定制工作空间的规范,但不能在 Google Colab 上定制,因此 Saturn Cloud 的用户可以根据需要多少加速来决定运行时的内核数量,而 Google Colab 的用户则不能。
此外,还可以利用 Saturn Cloud 上的 Dask 集群来进一步提高 Dask 命令的速度。这增加了解决问题的工人数量。(免费土星云用户每个月有 3 个小时使用 3 个工作者的黄昏集群。)谷歌 Colab 上没有这个功能。
让我们用一个玩具例子来想象一下。我们首先创建一个 10,000 行的方阵,用随机数填充它,然后是它本身和它的转置的和,然后沿着其中一个轴寻找一个平均值。
下面是说明这一点的三个代码块。
- 写在 NumPy 数组中的代码块在 Google Colab 上免费
- 在 Google Colab 免费上的 Dask 数组中编写的代码块
- 用 Dask 集群写在土星云 Dask 数组中的代码块。
当我们从 NumPy 阵列切换到 Dask 阵列时,速度提高了 56%,当我们从 Google Colab Free 切换到 Saturn Cloud 时,速度又提高了 97%。
代码块 1: NumPy 数组上 Google Colab 免费
>>> import numpy as np >>> def test():>>> x = np.random.random((10000, 10000))>>> y = x + x.T>>> z = y[::2, 5000:].mean(axis=1)>>> return>>> %timeit test()1 loop, best of 5: 2.14 s per loop
代码块 2: Dask 数组上 Google Colab 免费
>>> import dask.array as da>>> def test():>>> x = da.random.random((10000, 10000), chunks=(1000, 1000))>>> y = x + x.T>>> z = y[::2, 5000:].mean(axis=1)>>> return z>>> %timeit test().persist()1 loop, best of 5: 866 ms per loop
代码块 3: 土星云上的 Dask 阵列和土星云上的 Dask 集群
>>> from dask.distributed import Client>>> from dask_saturn import SaturnCluster>>> import dask.array as da >>> cluster = SaturnCluster(n_workers=3)>>> client = Client(cluster)>>> def test():>>> x = da.random.random((10000, 10000), chunks=(1000, 1000))>>> y = x + x.T>>> z = y[::2, 5000:].mean(axis=1)>>> return z >>> %timeit test().persist()26.7 ms ± 2.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
支持的程度
Google Colab 不提供个性化支持,所以解决问题的最佳方法是堆栈溢出。另一方面,土星云有一个松散的社区和一个支持团队,你可以为你的问题寻求帮助。
结论
虽然 Google Colab 是一个令人惊叹的数据科学工具,但它在可定制性、资源可靠性、效率和易于部署方面存在局限性。对于正在起步的数据科学初学者来说,Google Colab 是您的最佳选择。对于正在寻找完整解决方案来高效部署数据科学解决方案的中高级数据科学从业者来说,值得考虑土星云。当然,您可能需要在 Saturn Cloud 上投入一点时间和金钱,但是采用它的效率收益可能会超过它的成本。
总之,Google Colab 非常适合个人小规模数据科学项目,而 Saturn Cloud 是可扩展数据科学的赢家。如果你想尝试一下,可以开始尝试土星云。
使用这个库,只需几行代码就可以完成一个完整的 EDA,节省大量时间
原文:https://towardsdatascience.com/save-hours-of-work-doing-a-complete-eda-with-a-few-lines-of-code-45de2e60f257?source=collection_archive---------14-----------------------
大蟒
学习如何为你的下一个项目使用 QuickDA 并节省工作时间

照片由新数据服务。资料来源:联合国人类住区规划署
无论你是数据分析师还是数据科学家,你都听过专业人士花 80%的时间做数据清理,只有 20%的时间做建模。的确,数据清理和探索性数据分析需要多个步骤来执行,记住所有的代码都需要大量的实践。例如,一个简单的数据可视化需要至少三行代码才能最少地呈现。然而,如果我告诉你有一种方法可以大幅减少花在 EDA 上的时间呢?这时候 QuickDA 就可以派上用场了。

来源:pypi.org
QuickDA 是一个易于使用、直观的低代码库,允许您用几行代码执行数据清理、数据探索和数据可视化。事实上,大多数时候我们将只使用一行代码。我创建了一个小项目来展示 QuickDa 有多强大。你可以在这里找到笔记本。
入门
安装 QuickDA 最简单的方法是在你的终端中键入pip3 install quickda,差不多就是这样。您可以通过将git clone [https://github.com/sid-the-coder/QuickDA.git](https://github.com/sid-the-coder/QuickDA.git)复制并粘贴到您的终端来使用git close。现在,让我们探索这个神奇的图书馆。
对于这个项目,我只会用我们的老朋友熊猫和 QuickDA。NumPy,Matplotlib,Seaborn 都没必要。对于 QuickDA,我将使用以下库:
**# Importing libraries**
import pandas as pd
from quickda.explore_data import *
from quickda.clean_data import *
from quickda.explore_numeric import *
from quickda.explore_categoric import *
from quickda.explore_numeric_categoric import *
from quickda.explore_time_series import *
我将使用loans.csv。你可以在我的 GitHub 里找到数据集。我无法找到原始来源,所以如果你找到了,请让我知道,这样我就可以添加学分。
**# Importing dataset**
df = pd.read_csv(‘loans.csv’)

作者图片
汇总数据集
现在我们将开始看到 QuickDA 的所有功能。首先,我们可以使用代码explore(df)汇总我们的数据集,并获得数据类型、计数、空值、唯一值的数量以及描述性统计数据,如最小值、最大值、平均值和中值。请注意,QuickDA 还可以汇总分类数据的统计信息。常规的df.describe()功能无法做到这一点。让我们来看看这个功能,因为它很强大。

作者图片
那很容易。在我看来,只有这个汇总表才值得一试图书馆。还有一个斜列。该列显示了特征偏斜度。我从未在我的数据分析中使用它,因为我通过数据可视化来检查它。不过,有也挺好的。正如我们所看到的,explore(df)可以返回很多重要的信息,让我们不用再键入诸如df.dtypes、df.info、df.isnull.sum()、df.nunique()、df.skew()、df.describe()之类的东西。最棒的是,一切都被组织在一个数据框中。厉害!
还不信服?别担心!QuickDA 能提供更多。
我们也可以更直观的得到数据汇总。添加参数method = profile,QuickDA 将生成一个 HTML 文件,该文件汇总了所有列,并为我们提供了对数据集的深入了解。您可以通过添加report_name = 'Name of the Report'为您的报告添加一个名称。我们来探讨一下这个函数。
**# Summarize dataset**
explore(df, method=’profile’, report_name=’Loan Dataset Report’)

作者图片
这是大量的信息。您可以通过点击Toggle details获得关于该功能的更多信息。它将打开关于数据集、公共值甚至要素可视化的描述性统计信息。在下面的例子中,我们可以看到一个直方图,但这将取决于你的数据类型。让我们继续使用这个神奇的函数,因为这里有很多值得探索的地方。您也可以使用顶部的导航栏来浏览表格。

作者图片
正如我提到的,您可以获得大量的描述性统计信息和更好的特性概述。它显示要素中包含不同值、缺失值和无穷大值的百分比。无穷大的值不适用于大多数建模算法。例如,分位数统计信息就在那里,包括范围。下表至少有十行代码。

作者图片
点击Histogram,您将看到该功能的可视化效果。它看起来足够好,可以在专业报告中呈现。

作者图片
另一件很酷的事情是你可以看到数据集警告。例如,它显示高基数、高相关性、缺失值、均匀分布值以及数据集中零的百分比。这将对你做出与项目相关的决定有很大帮助。太棒了,对吧?

作者图片
稍后我们将进一步探讨这些数据可视化,但我想说的是,您可以获得一个漂亮的关联可视化。你可以看到 xticks 被编辑过——非常好的处理。

作者图片
数据清理
让我们稍微改变一下思路,检查一下 QuickDA 的数据清理功能。熊猫可以很快完成其中的一些功能。但是,我也想展示 QuickDA 的解决方案。
标准化列名
每个做过一些探索性数据分析的人都见过具有不同格式的列名的数据集。有时名字是大写的或带有空格。我们可以很容易地解决这个打字问题。这一行代码将小写列名,并在有空格时添加下划线(_)。代码如下所示:
**# Standardize column names**
df_name = clean(data, method='standardize')

作者图片
删除列
您也可以删除列。与普通的熊猫.drop()功能相比,我看不出有什么优势。但是,如果您想只使用 QuickDA 来标准化您的代码,您还有一个选择。
**# Drop columns**
df_name = clean(data, method='dropcols', columns=[column_names])
删除重复值
该数据集没有重复的值。因此,当应用这一行代码时,我们不会看到任何差异。
**# Removing duplicates**
df_name = clean(data, method='duplicates')

作者图片
重命名值
我们也可以很容易地用 QuickDA 替换列中的值。熊猫确实有同样好用的.replace()功能。不过 QuickDA 也很好用。在这种情况下,我将把值Source Verified替换为Verified。
clean(**data**, **method**="replaceval",
columns=[], to_replace="value to be replaced", value="new value")

作者图片
填充缺失值
缺少值?没问题,QuickDA 也能够通过插值来处理。插值是对值序列中两个已知值之间的值的估计。为此,您可以使用以下代码:
df_name = clean(data, method='fillmissing')
移除异常值
我们什么时候应该剔除异常值是有争议的。有时数据是不正确的,有时离群值对于理解所有场景是重要的。然而,如果您认为异常值不重要,可以用下面的代码删除它们:
df_name = clean(data, method='outliers', columns=[column_names])

作者图片
您可以选择要删除异常值的列。如果不选择列,QuickDA 将删除所有列中的异常值。
待续
我们刚刚看到了许多激动人心的信息,还有更多信息要向您展示。然而,这个博客变得有点太长了。出于这个原因,我将写第二部分,在那里我将向您展示更多令人兴奋的东西,我们可以用 QuickDA 来做。例如,如何用它创建数据可视化。敬请期待,过几天我会发表。
更新:正如我承诺的,我已经写了第二篇关于数据可视化的博客。你可以在这里找到: 如何用一行代码用 Python 创建数据可视化
最后的想法
QuickDA 是我见过的最不可思议的 Python 库之一。通常,当我尝试新的库时,会有起伏。然而,我只对 QuickDA 有过正面的体验。就是管用,百分百值得一试。我强烈建议您用自己的数据集尝试一下,感受一下它的神奇之处。我向你保证,你会节省时间。你可以在这个博客和这个笔记本中找到更多的代码。
您的反馈对我很重要。让我知道进展如何。我可以等着看你将如何使用这个神奇的图书馆。编码快乐!
省钱并防止偏斜:Sagemaker 和 Lambda 的一个容器
原文:https://towardsdatascience.com/save-money-and-prevent-skew-one-container-for-sagemaker-and-lambda-75d1bc6f4925?source=collection_archive---------22-----------------------
关于为这两种服务构建容器的教程

照片由费边布兰克在 Unsplash 上拍摄
答这篇文章写完后,AWS 发布了 Sagemaker 无服务器推断,你可以直接用它来代替。
P 产品生命周期通常需要不频繁的机器学习推理。例如,测试版可能只会收到少量的流量。在这些场景中,托管模型推理可能是昂贵的:即使没有推理请求正在被处理,模型推理服务器也总是开启的。
解决利用不足的一个好办法是无服务器产品,如 AWS Lambda 。这些允许您按需运行代码,但只为您使用的 CPU 时间付费。对于不频繁的推理来说,这是一个很有吸引力的环境,但是通常需要不同的软件栈和打包限制。因此,当需要扩展到无服务器范围之外时(即,当一个功能进入 GA 或我们需要 GPU 进行大批量处理时),工程师需要为实时端点重写推理代码。
重写推理代码耗费了工程师的时间,并且引入了环境偏斜的风险。与培训/服务偏斜一样,环境偏斜是由于软件依赖性或输入数据处理方式的差异而导致的模型性能变化。换句话说,重写推理代码可能会意外地导致模型性能下降。
在本教程中,我将展示如何为 AWS Lambda 和 Sagemaker 端点创建一个 docker 容器。使用这种方法,您可以在不经常访问的模型的无服务器上开始运行推理,然后在需要时转移到始终在线的 Sagemaker 端点。因此,您可以在最初保持低成本,并有效地扩展,而没有环境偏差或重写推理代码的风险。
github 上有完整的代码。
你容器里的叉子
Sagemaker 和 Lambda 都支持自带容器。Sagemaker 需要 HTTP 服务器,而 Lambda 使用运行时作为入口点。这个项目背后的关键思想是根据容器运行的环境来派生容器逻辑,但是使用相同的推理代码:

作者图片
在entry.sh中分叉实际上相当容易:Sagemaker 在启动时向容器传递一个serve参数,而 Lambda 传递函数处理程序名。因此,我们的entry.sh脚本只需要检查命令行参数就可以知道它是在 Sagemaker 还是 Lambda 中运行:
#!/bin/bashif [ "${1:-}" = "serve" ] ; then
# Start an http server for Sagemaker endpoints..
exec /usr/local/bin/python serve.py
else
# run the Lambda runtime environment
exec /usr/local/bin/python -m awslambdaric ${1:-}
fi
(我省略了用于本地测试的 Lambda 仿真器,,但它在 github repo 中)
推理代码
这种方法的一个关键好处是您可以在两种环境中使用相同的推理代码。在这个例子中,我将使用来自 gluoncv 模型动物园的模型对图像进行分类,但是基本概念应该可以扩展到您自己的模型。
使您的推理代码模块化是这里的关键:文件serve.py和lambda.py应该只有最少的逻辑来验证输入。为此,inference.py有两个主要功能:
load_model-将模型加载到内存中infer—接受输入和模型,返回推理结果。
加载模型需要一些小心,因为 Sagemaker 可以部署来自模型注册中心的模型,而 Lambda 不能。当这种情况发生时,工件被安装到容器中的/opt/ml/model,我们将通过变量model_path来标识它:
def load_model(model_path = None):
"""
Loads a model from model_path, if found, or a pretrained model
specified in the MODEL_NAME environment variable.
""" # Try to load from model_path if we are running on sagemaker.
if model_path and os.path.exists(model_path):
symbol_file = glob(join(model_path, '*symbol.json'))[0]
params_file = glob(join(model_path, '*.params'))[0]
return SymbolBlock.imports(symbol_file, 'data', params_file)
else:
# running in lambda, so load the network from the model zoo
model_name = os.environ['MODEL_NAME']
return gluoncv.model_zoo.get_model(model_name,
pretrained=True, root='/tmp/')
在 Lambda 示例中,上面的代码让用户在MODEL_NAME环境变量中指定模型,并从模型动物园中加载模型。或者,您可以将模型打包在容器中,或者从 S3 装载。
infer函数是一个简单明了的例子,说明了如何使用 gluon API 进行推理:
def infer(uri, net):
"""
Performs inference on the image pointed to in `uri.`
""" # Download and decompress the image
img = open_image(uri) # Preprocess the image
transformed_img = imagenet.transform_eval(img) # Perform the inference
pred = net(transformed_img)
prob = mxnet.nd.softmax(pred)[0].asnumpy()
ind = mxnet.nd.topk(pred, k=5 [0].astype('int').asnumpy().tolist() # accumulate the results
if hasattr(net, 'classes'):
results = [{
'label': net.classes[i],
'prob': str(prob[i])
} for i in ind]
else:
results = [{'label': i, 'prob': str(prob[i])} for i in ind] # Compose the results
return {'uri': uri, 'results': results}
Sagemaker 代码
当容器在 Sagemaker 端点中启动时,它启动一个在serve.py中指定的 HTTP 服务器。服务器在POST /invocations端点上处理推断请求。我在这个例子中使用了 flask ,但是任何 HTTP 框架都应该可以工作:
# HTTP Server
app = Flask(__name__)# The neural network
net = None[@app](http://twitter.com/app).route("/ping", methods=["GET"])
def ping():
return Response(response="\n", status=200)[@app](http://twitter.com/app).route("/invocations", methods=["POST"])
def predict():
global net
# do prediction
try:
lines = request.data.decode()
data = json.loads(lines)
results = inference.infer(data['uri'], net)
except ValueError as e:
error_message = f"Prediction failed with error '{e}'"
return Response(response=error_message, status=400)
output = json.dumps(results)
return Response(response=output, status=200)
invocations端点简单地解码请求并将输入传递给上面指定的inference.infer函数。这使事情变得简单:所有的逻辑都在推理文件中指定。
网络本身应该在启动服务器之前加载 main 函数,这也为一些句柄命令行参数提供了可能性:
def parse_args(args=None):
parser = argparse.ArgumentParser(
description='Server for inference on an image.'
)
parser.add_argument(
"--model-path", type=str, default='/opt/ml/model',
help="The model artifact to run inference on."
)
parser.add_argument(
"--port", type=int, default=8080,
help="Port to run the server on."
)
parser.add_argument(
"--host", type=str, default="0.0.0.0",
help="Host to run the server on."
)
return parser.parse_args(args)if __name__ == "__main__":
# parse command line arguments
args = parse_args()
# load the model
net = inference.load_model(args.model_path)
# start the server
app.run(host=args.host, port=args.port)
您会注意到model_path被设置为/opt/ml/model,这是 Sagemaker 从模型注册中心提供工件的默认位置。
拉姆达代码
Lambda 代码甚至更简单:您需要的只是一个处理请求的函数:
# Loads the model when the lambda starts up
net = inference.load_model()def handler(event, context):
global net
try:
return inference.infer(event['uri'], net)
except Exception as e:
logging.error(f'Could not perform inference on {event}', e)
return json.dumps({'error': 'Unable to perform inference!'})
第一次调用 Lambda 时加载模型,这会增加一些冷启动延迟,但只要 Lambda 处于活动状态,它就会留在内存中。
保持精益
AWS Lambda 是减少不经常使用的模型的推理成本的一个很好的方法,但是如果由于功能发布或产品流行而导致调用次数增加,成本会更高。切换到始终在线的 Sagemaker 端点降低了成本,但是可能需要重写推理代码,这需要时间,并且可能引入环境偏差。这里描述的容器可以在两种环境中工作,这使得在两种环境之间切换变得容易和快速,并获得最大的收益。
完整的代码可以在 github 上找到。
我们使用我在这里描述的技术来节省 Bazaarvoice 的推理成本。如果这种工作吸引了你,看看我们的职位空缺。
如果你喜欢这个故事,请考虑支持我,请给我买一杯咖啡或者通过我的推荐注册媒体。
用数据拯救动物的生命
原文:https://towardsdatascience.com/saving-animal-lives-with-data-d815c6e854eb?source=collection_archive---------18-----------------------
变更数据
动物收容所分析介绍

由路易斯·罗伯特在 Unsplash 上拍摄的照片
据估计,目前世界上大约有 5000 家独立经营的动物收容所。我个人觉得可能会更多。这些收容所的运营效率很大程度上取决于它们满足其主要目标的能力,通常是优化选择指标。为了计算这些指标,需要收集、维护和分析数据。
但是,我们在动物收容所遇到过多少次数据的使用呢?我从来没有这样做过,直到我决定带着一份投机性的申请去当地的一家动物收容所,希望被聘为数据分析师实习生。我如何获得这个机会的细节已经在之前的一篇文章中详细讨论过了。
本文总结了不同的实践,这些实践可以付诸行动,以帮助庇护所在数据驱动的帮助下更好地发挥作用。或者我喜欢称之为动物收容所分析。
什么是动物收容所?
对动物收容所最常见的描述围绕着为动物提供一个栖身之所的想法,尤其是当它们被遗弃或受伤时。从更基本的意义上说,动物收容所为有需要的动物提供康复和住所。大多数情况下,经营这些机构的组织都是非盈利性的,它们的运作严重依赖于它们收到的捐款。
第一个动物收容所并不完全是人们所说的“动物友好型”。无家可归或“不受欢迎”的动物被收容所杀死,这是常态。然而,随着时间的推移,庇护系统开始看到一个向他们所保护的生物的利益的范式转变。这种变化甚至可以在所用术语的演变中看到。例如,“动物福利”被创造出来,从而反映了一种更人道的庇护方式。
看待庇护系统的另一种方式是将其视为“控制”流浪动物数量的一种手段。虽然有必要保护动物,但同样重要的是确保人类生活不受不受监督的动物种群的妨碍或威胁。这种观点的一些例子包括对流浪狗进行绝育以控制它们的数量。
通常,动物庇护所是指那些收容家畜或宠物如狗和猫的庇护所。然而,也有像我工作过的组织致力于保护城市野生动物。
城市野生动物指(通常)在城市化地区与人类共存的非驯化物种。例如,松鼠、蛇、风筝等。属于这一类。
数据在动物收容所扮演什么角色?
一个非常大的角色!数据可能是经营动物收容所最重要的部分。需要收集关于动物、手术成本、可用资金等的数据。正是这些数据可以用来在收容所执行几项重要的操作,包括拯救更多的生命、优化运营成本以及将动物与潜在的捐赠者联系起来。
现在,让我们后退一步,确定为什么需要将数据驱动的实践整合到庇护所的运营中。首先,数据帮助验证事实和数字的真实性。这反过来给庇护所带来了透明度。鉴于大多数庇护所都是慈善信托机构或非盈利机构,这种透明感是所有需求中的重中之重。
数据至关重要的另一个原因是,良好的数据收集有助于对进展进行精确评估。一个好的庇护所几乎总是有一个关于它想要达到的目标的强有力的计划。为了了解庇护所的成功程度,它需要能够客观地量化其贡献。
第三个原因是数据为提供了消息灵通的行动计划。例如,考虑庇护所 X 在一周的时间内接收 20 台起重机进行处理的情况。如果没有关于这些动物的数据,庇护所唯一能做的就是尽力拯救这 20 只鹤。然而,如果收集了关于这些起重机的数据,并且如果注意到所有的起重机都是从同一个地方运来的,庇护所就可以派出一个小组来审查在给起重机带来麻烦的地方发生了什么。这是解决问题的根本原因,比解决根本原因的个别结果更有效。
动物收容所数据收集的演变
在这个精彩的演讲中,玛蒂基金会的负责人克里斯汀·哈森和她的同事对收容所收集数据的软件进行了历史评估。
根据他们的观察,shelter 软件已经经历了 3 次浪潮才达到目前的水平。第一波的软件仅仅是用来执行记录动物数量的任务。基本上,它将动物视为“库存”,不支持收养。自然,我们可以想象这种软件运行的原始程度。
第二次浪潮比第一次浪潮要好,因为庇护所软件制造商现在开始认识到收养的重要性。软件变得更加以“拯救生命”的概念为中心。在此期间,收容所软件的另一个受欢迎的变化是,它变得更加用户友好,并提供了存储动物病史和行为模式的机会。
第三次浪潮,即当代,集中在社区。软件帮助跟踪数据,形成动物和人之间的桥梁。“避难所”现在有能力使用他们的数据来量化他们的影响和解决根本原因。
我对第三波略有不同。我相信第三次浪潮对于像印度这样的发展中国家的大多数动物收容所来说仍然是奢侈的。我工作的收容所有一个非常敬业、充满热情的团队收集所有动物的数据,但是他们使用电子表格和手动输入,从而避免使用任何类型的收容所软件。
第三次浪潮也可以被认为是以更严肃的态度将指标纳入庇护所运营的浪潮。度量是可以量化流程状态的量度。
在题为神奇的指标和令人眼花缭乱的数据的演讲中,康奈尔大学收容所医学项目的创始人 Janet Scarlett 博士提供了一个关于指标如何用于改善动物收容所的条件、跟踪疫情和监控收容所动物健康的视角。
在另一个名为更好地利用收容所数据的演讲中,Scarlett 博士强调了动物收容所的指标通常是未充分利用的资源,并介绍了使用平均停留时间(ALOS)来估计住房容量的想法。
动物收容所最常用的一些指标是
- 摄入量:进入收容所的动物数量
- 结果:有多少动物被收养、归还、安乐死、死亡、转移?
- 拯救率:活着离开收容所的动物的百分比
- 实时发布率:(总实时结果/总结果)
- 停留时间:特定的动物在收容所停留了多长时间?
迈向动物收容所分析理论
现在你已经了解了动物收容所的领域,是时候向你介绍动物收容所分析的概念了。这不是一个普遍定义的学科,但是我相信根据我在庇护所的经验,这个名字是合适的。
一切数据驱动的事情都始于识别利益相关者
数据驱动实践的核心任务是确保相关的利益相关者对解决方案感到满意。为此,首先要确定利益相关者。在动物收容所,基本上有 5 种利益相关者,如下所述。

动物收容所的利益相关者(鸣谢:作者)
根据费尔南德斯等人的说法。为了在动物福利领域做出更好的决策并实现持久的改善,鼓励利益相关者之间的合作的需求日益增长。然而,要做到这一点,必须有清晰的、令人信服的叙述和观点,与上述五类利益相关者中的每一类都有共鸣。
原始数据通常由避难所工作人员在行政层面进行处理。虽然这是庇护所工作人员活动的一个重要部分,但如果他们能够将原始数据可视化,并以有意义的图表和图片的形式查看,也会有所帮助。
实习生/受训人员和志愿者将根据工作人员提供的见解,更好地了解对他们的期望以及他们需要采取的行动。
咨询委员会将能够通过观察可视化来评估避难所影响的深度,他们将能够在很短的时间内做到这一点。
最后,在 PFA 这样的动物收容所中,公众无疑是最重要的利益相关者。让社区了解庇护所的工作和努力是至关重要的,为此,该组织必须通过精心设计的叙述与更广泛的公众沟通。
数据驱动的决策之所以重要,一个关键原因是因为它是的目标。它为庇护所的活动创造了可量化的视图,因此像一个共同的点,供相关各方讨论。
定义动物收容所分析
用学术的方式下定义并不完全是我的优点之一。因此,我将利用一个图表来定义这个动物收容所分析的想法。这个图表非常简单明了。

动物收容所分析的 3 个主要组成部分(鸣谢:作者)
使用动物收容所分析
动物收容所收集数据,如动物信息、救援次数、救援地点等。这些数据集包含的模式可以让我们更深入地了解庇护所的运作。领域专家和数据团队可以坐在一起,讨论关键焦点,分析以获得见解,使用指标来量化庇护所的进展,甚至决定新的指标来定义庇护所的功效,并将这些纳入庇护所的实践中。
以下是我能想到的动物收容所分析有益的广泛使用案例:
了解庇护所的运作
细节,如多少救助,多少志愿者,不同种类的物种,收养和捐赠者的数据等。
了解特定物种的脆弱性
关于某一特定物种的救援和状况的细节
救援热点地理测绘
地理可视化的位置,从那里给定物种的大部分救援发生
建立公共关系,提高社区参与度
引导数据分析,以规划更好的推广计划,并将潜在的捐赠者与受伤的动物联系起来
动物收容所分析的当前挑战
了解了数据分析如何帮助避难所改善运营后,现在是时候讨论一些使这一想法不那么容易实施的关键挑战了。
这里提到的所有挑战都是我在收容所实习时直接面对的。其中一些可能是其他庇护所共有的,而一些可能不是。
挑战 1:数据质量不令人满意
没有坏数据,只有收集或维护得不令人满意的数据。这是我上班第一天学到的一课。该收容所有一些令人印象深刻的记录,记录了它在过去 6 年中救助的动物,然而,仔细观察后发现,它的维护方式存在一些问题。
首先,每年收集数据的方式不一致。每年,栏目都要重新命名或推出新栏目;但是这些列很少被填充,因此导致了丢失数据的问题。这些不一致反映了在收集动物记录时缺乏框架。
另一个突出的问题是数据输入不一致。庇护所数据中发现的不一致之处包括
- 拼写错误:同一物种的名字每次都有不同的拼写
- 大小写错误:随意使用大写和小写
- 学名混淆:一些物种的学名并不是该物种的实际学名
- 日期的不规则格式
如果组织必须做出数据驱动的决策,这些数据问题会导致数据的质量低于应有的水平。质量差的数据可能导致错误见解的上游传播,进而导致错误决策。没人想这样。
清理所有这些数据花了我几天时间。尤其是学名混淆的部分,因为这需要我谷歌每个物种的名字,并检查其记录的学名是否正确。我所遵循的数据清理过程是另一篇文章的主题!
挑战 2:缺乏庇护软件
我不认为自己是这方面的专家,但印度的大多数动物收容所还没有明确的收容所软件。电子表格是这些组织用来存储数据的。
现在,在我的职业生涯中,评论电子表格与其他软件的争论还为时过早。但是,我从实习中学到的一件事是,使用电子表格存储数据比使用专门构建的软件存储数据需要更仔细的考虑。
为数据收集而构建的软件可以强制执行内置的特定标准,从而帮助从源头解决数据质量差的问题。虽然像 MS-Excel 这样的电子表格确实允许你使用约束条件来确保输入数据时的质量水平,但所涉及的复杂程度低于定制软件。
挑战 3:采用数据驱动文化的惰性
再说一次,我不是专家。但是,我坚信动物收容所没有采用数据驱动文化的一个原因是因为这样做太不容易了。从我在收容所的经验来看,他们做的工作是惊人的,而且非常耗时。由于这是一个非营利组织,他们几乎总是在资源方面受到挤压,但每天都设法挽救如此多的生命。
有这么多事情正在进行,整合新的优先级总是一个挑战。而且,总有一个的问题“这值得我们花时间吗?”。回答这个问题总是有点困难,因为任何答案都无法说服利益相关者,除非他们愿意在游戏中加入一些内容。
如何解决这些挑战?
识别挑战是一项相对容易的任务。真正的价值在于产生解决方案的能力。在庇护所面临上述三大挑战的背景下,我在最终报告中向利益相关者提出了一些建议,我将在此讨论其中几项。
解决方案 1:创建数据录入规则手册
这个想法是在输入数据时有一套固定的、特定于组织的指导原则。这将确保数据的统一结构,从而简化以后的分析过程。
解决方案 2:倡导数据驱动的文化
如挑战 3 所述,这并不容易。然而,如果收容所能做到这一点,更多的生命将被拯救。动物收容所发展这种数据驱动文化的几种方式是
- 提高志愿者和员工的数据素养。如果他们知道数据的重要性,他们在处理数据时肯定会更加小心。
- 包括在庇护所进行技术实习,熟悉计算和分析的学生可以提供服务,帮助庇护所的运营。
- 联系那些愿意帮助建立数据库或为庇护所开发 CRM 软件的公司,作为其 CSR 活动的一部分。
- 维护关于数据的相关文档并收集元数据,即关于数据的数据。
- 确保庇护所的每个人都对数据驱动的流程负责。每个员工都必须认识到,任何在 T 时刻乱糟糟的数据,除非被打断,否则在 T+1 时刻只会变得更糟!
结论
动物收容所的数据有很大的潜力,可以积极地平衡人与动物之间的互动。一些避难所已经意识到了这一点,而更多的避难所还没有挖掘出隐藏在电子表格中的大量数据。
如果要帮助更多的动物,现在是所有动物收容所采用数据驱动的做法的时候了。拥有清晰的数据驱动实践也有助于收容所衡量其作为一个组织的进展。正如彼得·德鲁克(Peter Drucker)曾经说过的一句名言“被衡量的,被管理的”。
这篇文章最初发表在我的个人博客上。
如果你对这篇文章的内容有任何疑问,请随时联系我。你可以在 Linkedin 和 Twitter 上找到我。
