TowardsDataScience-博客中文翻译-2021-六十八-

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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

运行 A/B 测试的 8 个常见陷阱

原文:https://towardsdatascience.com/online-controlled-experiment-8-common-pitfalls-and-solutions-ea4488e5a82e?source=collection_archive---------6-----------------------

入门,实验和因果推理

如何不让你的网上受控实验失败

照片由罗尔夫·布利彻·戈弗雷Unsplash 拍摄

在线实验已经成为产品创新和决策的行业标准。通过设计良好的 A/B 测试,科技公司可以更快地迭代他们的产品线,并提供更好的用户体验。在 FAANG 中,网飞是最公开其实验方法的公司。在一系列的帖子中,网飞介绍了如何提高实验效率减少方差准实验关键挑战,以及更多

事实上,在控制了所有其他外部因素后,在线控制实验提供了高水平的内部有效性,并且只允许一个因素(治疗条件)发生变化。与其他统计工具(如回归)不同,实验可以得出因果关系,并提供将因果关系与相关性分开的最佳解决方案。

然而,一些人在没有检查异常的情况下匆忙得出结论,由于首要效应和新奇效应而过早结束实验,并在混淆了负面和正面结果后推出损害其收入的产品。这个清单还在继续。

糟糕的测试设计比没有设计更糟糕!

进行科学研究需要纪律,我们需要明白什么是合适的,什么是不合适的。在今天的帖子中,我列出了行业人士经常犯的 8 个常见错误,以及如何分别解决每个问题。我的初衷是写一本如何正确运行 A/B 测试的端到端实用手册。我会牵着你的手走过在实验前、实验中和实验后阶段发生的常见错误。

1.功率分析

  • 样本量不足
  • 提前结束

让你的在线实验失败的方法有成千上万种,样本量不足是测试失败的主要原因。我见过一些公司推出 A/B 测试,在看到治疗组有更好的指标后,立即结束实验。

你做过功效分析来决定样本量吗?

你是否过早结束了你的实验?

没有复杂数据人力的公司可能会发现这两个问题很陌生,很难回答。A/B 检验的基本统计支持被称为假设检验:我们试图将指标的差异(如果有的话)归因于治疗的存在,而不是随机噪声(随机性)。

为此,我们需要一个“足够大”的样本量来拒绝零假设。在这里,我用引号引起来,因为不同的业务场景的样本大小不同。

样本大小取决于三个参数:

  1. 显著性水平,即假阳性的概率。通常情况下,我们定在 0.05。
  2. 统计功效,即在确实存在效果的情况下,正确识别效果的概率。还有,Power = 1 — 类型二错误。通常,我们将功率设置为 0.8。
  3. 最小效果。这是一个商业问题。进行成本和收益分析后,治疗组和对照组之间最小可接受的差异是多少?假设,在实验组之间有 0.000000001%的统计学显著改善。你会推出新版本吗?不。考虑到更新的业务成本(例如,工程时间、业务周期、不良 UX 等),如果我们坚持旧版本而不推出更改,情况会更好。).与你的商业伙伴,尤其是产品经理,讨论权衡并设定最低门槛。

设置正常显著性水平(0.05)和统计功效(0.8),我们有以下公式:

其中:

  • σ:样本方差(总体评价标准的方差,aka。感兴趣的度量)
  • 𝛿:治疗组和对照组之间的差异

为了获得样本方差,我们可以在推出 A/B 测试之前运行 A/A 测试。以下是样本量和参数之间的关系:

  • 显著性水平降低→更大的样本量
  • 统计功效增加→更大的样本量
  • 最小影响降低→更大的样本量

陷阱 0:不懂功耗分析,过早结束实验。

解决方案:我们可以使用在线计算器或者 Python 来计算所需的样本量。假设在进行功效分析后,您需要为每组收集 5000 个样本。网站日访问量 500,分为 2 组,每组 500/2=250。因此,您需要保持测试运行 5000/250 = 20 天,大约 3 周。这属于合理的时间范围。不要过早地结束实验,因为你已经看到治疗组在最初几天出现了积极的上升。等到第三周结束时,当你有足够大的样本量来做出明智的决定。

照片由 Erol AhmedUnsplash 上拍摄

2.随机选择

  • 随机分配水平
  • 重度用户与轻度用户
  • A/A 测试

在线实验的成功取决于治疗条件的随机分配。我们必须确保任务是真正随机的。然而,确保行业内的随机分配说起来容易做起来难。并不是每个公司都有所需的数据人力来正确地做这件事。

为了实施随机化,公司使用散列法和“聚类”系统将用户随机分配到治疗组和对照组。基本思想是为每个访问者创建一个散列值,并将他/她直接分配给治疗条件,或者通过暴露于治疗条件的“集群”来分配。

具有挑战性的部分是他们不能保证一致地将用户分配到相同的治疗条件。如果访问者多次访问网站,他们可能会接触到不同的治疗条件。例如,一家在线视频流媒体公司正在测试一种新的内容推荐算法,其实验平台采用了“集群”系统。每次,该公司随机将用户分配到这两个版本,并分别记录他们的流媒体播放时间(感兴趣的指标)。

有问题吗?

是的,一个大问题。如果用户一天多次访问该网站,他/她可能会暴露于治疗和控制条件下,这将使任何因果结论无效。

陷阱 1:公司不能保证一致的集群分配,因此不是真正的随机过程。

解决方案:最常见的解决方案是采用“集群”系统,确保分配的一致性。首先,工程团队将用户分配到不同的集群。第二,在集群级别随机化,而不是在用户级别。这种方法可以在很大程度上解决上述不一致的分配问题。不幸的是,并不是每家公司都有像网飞和谷歌那样的工程人员和技术来设计这样的系统。此外,一些商业模式不适合“集群”系统。

下一个陷阱也是关于随机化的。对于面向消费者的公司来说,有重度用户和轻度用户之分。重度用户通常只占总人口的一小部分,但贡献了大部分流量。简单的随机分配无法确保小样本量的重度用户的平均分布,从而导致较大的方差。

顺便提一下,这也解释了传统 A/B 检验的低统计功效和小的治疗效果。我将在另一篇文章中解释如何通过方差缩减技术来提高统计能力。

这里有一个假设的例子。进行功效分析后,我们需要每个变体的 1000 个样本。在目标人群中,重度用户约占 5%,但贡献了 60%的网站流量。特别是当样本量相对较小时(例如,1000),随机分配可能导致一组中的重度用户多于另一组中的重度用户。

重度用户是最忠诚的顾客,他们比轻度用户对刺激反应更积极。如果我们将实验组之间的最终差异仅归因于治疗条件,我们将高估治疗效果。

陷阱二:随机分配未能平均分配重度用户。

这个陷阱最让我担心:人们没有意识到这是一个问题。他们天真地认为随机分配会产生两个可比较的组,这在理论上成立,但在实践中很少。如果有一小部分重度用户,随机分配不能保证重度用户的平均分布。

有几十种方法来摸索你的实验,但只有一种方法是正确的。

解决方案:分层抽样一样,我们为重度用户设置阈值,并使用虚拟变量将他们随机分配到治疗组和对照组。通过这样做,实验组中重度用户与轻度用户的比例达到平衡。数据科学家需要与产品团队合作来设置阈值。随机化后,我们需要检查实验组之间关键协变量的分布。

另一个公司通常不知道的解决方案是进行 A/A 测试。

版本差异的 A/B 测试;A/A 测试版本稳定性和一致性。

工程团队已经解决了所有的技术难题,并创建了两个可比较的组。现在,让我们对两组进行相同的治疗条件,也就是 A/A 测试。由于实验组具有相同的属性,面临相同的治疗条件,我们应该观察不到差异。

从统计学上来说,我们应该不能拒绝零假设,并且在 95%的时间里观察不到这些组之间的差异,将α水平设置为 5%。请记住,即使实验组是相同的,仍然有 5%的机会检测出假阳性

照片由约尔根·哈兰Unsplash 上拍摄

3.污染源

  • 其他条件不变
  • 溢出效应

假设经过真正的随机过程,我们已经收集了足够大的样本量和可比较的实验组。

现在还能相信治疗效果吗?

直到我们检查这两个额外的因素:其他条件不变和溢出效应。

首先,其他条件不变的假设是否有效?也就是说,很可能在一个实验组中引入额外的变化,而在另一个实验组中没有。这里有一个微软的真实案例研究( Crook 等人,2009 )。按照相同的 A/B 测试逻辑,他们对一组进行治疗,而不是对另一组。然而,治疗条件需要运行 JavaScript 来加载其内容,这会产生影响结果变量的响应延迟。对照组没有延迟。

陷阱 3:无法检查其他条件不变的假设。

如果发生这种情况,治疗组和对照组之间的差异可归因于真实的治疗效果(版本变化)和额外的反应延迟。

总体差异=真实治疗效果+延迟效果

总体差异是对治疗效果的有偏估计,低估了治疗效果。姑且说新版本确实比老版本好。由于治疗组中引入的延迟效应,我们可能无法识别实际效果并决定不更新。从经济上来说,公司在竞争中失败,并招致巨大的机会成本。

解决方案:为了实验成功,我们必须在任务前、任务中和任务后做平衡检查。如果干预引入了额外的延迟,我们应该给对照组引入相同量的延迟时间。这样做,我们消除了外来因素的影响。

此外,我们还要检查实验组之间的溢出效应。你的治疗组和对照组有互动吗?他们是 LinkedIn、脸书或 Twitter 上的朋友吗?他们在网上谈论治疗吗?如果这些问题的答案是肯定的,那么我们就处于交叉污染和稀释处理效果的困境中。

溢出效应的另一个来源来自同一个地理位置。这里有一个简单的例子。对于优步和 Lyft 这样的打车公司来说,如果他们试图评估两种匹配算法的性能,并将洛杉矶的司机随机分配到治疗组和对照组。无论哪种算法更好,处理组中的驱动程序都会吃掉控制组驱动程序的总请求份额。同样,这导致了有偏见的估计。

陷阱 4:治疗组和对照组之间的交叉污染。

解决方案:我们可以分别从空间和时间维度解决交叉污染效应。从空间上来说,一个非常标准的方法是在宏观层面(例如,城市)而不是个体层面(例如,驾驶员)管理随机化过程,并选择两个地理位置偏远的案例。查看这个案例研究,了解 Airbnb 如何解决这个问题(链接)。

两个样本的比较对于拥有大量用户的公司来说是一个有效的设计,在那里可以选择控制和治疗案例。相比之下,大多数公司没有这种奢侈,只有有限的用户群。如果是这样的话,我们可以从时间维度来解决问题。我们仍然可以牵线搭桥,人为地创建一个控制和治疗组。

有效的因果推理来源于两个维度:空间和时间。

为了比较两个版本,我们可以在第一周对整个人群使用一个版本,并检查指标是增加还是减少。然后,我们取消治疗,并在第 2 周重新记录指标,检查它是否回到正常水平。我们将治疗条件视为一个开关:多次打开和关闭它,并观察指标的任何跳跃以获得显著效果。

例如,我们对评估新版本对点击率(CTR)的影响感兴趣。由于某些未知的原因,没有办法将用户群分为治疗组和对照组。

我的笔迹

在时间点 A,我们打开切换开关,向所有用户推出新的更新。一小段时间后,我们在时间点 b 将其关闭。在时间点 C 和 d 重复开关过程。每次开关打开时,我们都会观察到指标中的尖峰,关闭后会回归到平均值。这种方法在治疗效果上提供了相当好的方向性,例如,新版本在上述情况中具有积极的影响。然而,不利的一面是,由于过去几周的持续影响,很难给出精确的估计。

嗯,有方向性的选择对决策来说已经足够好了。

4.实验后分析

  • 多重比较
  • 例如,谷歌的 41 种蓝色

好的,我们在实验前和实验中做了所有正确的事情。我们的统计结果建议用一个小 p 值来拒绝零假设,我们推出新版本并到此为止好吗?

不要!你不应该。

对于多次比较,累积的 alpha 水平增加,很容易得到假阳性 s,这里有一个真实的案例。谷歌希望为其产品挑选最吸引人的颜色,并测试了 41 种蓝色。

以下是多重比较的详细数学分类:

- Set α level to 5%-  P([False Positive](/crack-data-science-interviews-essential-statistics-concepts-d4491d85219e)) = 5%: no effect but falsely concludes there is an effect- P(Rejecting a False H0) = 1 — 5% = 95%- For 41 comparisons, P(at least one significant result) = 1 — (95%)⁴¹ = 88%

对于 41 次比较,错误地观察到一个显著结果的概率是 88%,即使没有统计学上的显著差异。问题是增加的累积阿尔法水平,它增加并对测试的有效性构成威胁。没有适当的调整,很容易观察到多重比较的假阳性

照片由艾米·里德Unsplash 拍摄

陷阱五:多次比较时被 误判 s 犯规。

解决方案:我们可以使用 Bonferroni 校正,即将α水平除以比较次数,α/n,并在除以的水平上检查统计显著性。在前面的示例中,我们将显著性水平重新设置为 0.05/41 = 0.0012,并且仅在 p 值小于调整后的阈值时拒绝 H0。

然而,一些批评者认为,Bonferroni 的修正过于保守,这意味着更难拒绝 H0。在谷歌的例子中,

P(至少一种显著效果)

= 1 — P(无显著影响)

= 1 — (1 — 0.0012)⁴

= 0.048

结果(0.048)小于传统的 5%,即 0.05。(看看伯克利的讲义)。

  • 辛普森悖论

推广实验的典型方法是对一小部分受试者进行实验,然后逐渐扩大到更广泛的受众。谨慎的加速方法的原因是,如果试验显示对关键业务指标有负面影响,就立即结束试验。

下面是一个真实的例子。在一个实验中,微软采用了 99%(对照组)对 1%(治疗组)的比率,并在第一天观察到治疗组的转化率较高。他们将比例提高到 50%对 50%,并在第 2 天观察到治疗组的转化率更高( Crook 等人,2009 年)。

这是细目表。

资料来源:克鲁克等人,2009 年

在第 1 天和第 2 天,治疗组表现更好。令人惊讶的是,这种模式在总体水平上发生了逆转:对照组的转化率更高(1.68%)。从数学上讲,数据聚合前后的模式是可以颠倒的。我们在个人和集体层面做出不同的决定。我在另一篇 帖子 中讨论过辛普森悖论。

陷阱 6:单个模式和聚集模式在扩大试验中看起来不同。

:有三种解( Crook et al .,2009 )。首先,当比例稳定时,我们可以对数据采用配对 t 检验,即比较第 1 天的治疗和第 1 天的对照以及第 2 天的治疗和第 2 天的对照。其次,我们可以使用加权和来调整第 1 天和第 2 天的不同比率。第三,我们可以抛开斜升期的数据,斜升期相对于实验来说更短。丢弃初始数据的另一个好处是,由于首要和新奇的影响,它太杂乱和嘈杂。

  • 首因效应和新奇效应

首因效应是指有经验的用户适应新版本。例如,我们对了解新版本更新如何影响 CTR 很感兴趣。新版本与旧版本如此不同,让有经验的用户感到困惑,点击(打开)多个链接。

新奇效应是指现有用户希望尝试所有新功能,从而导致指标的增加。由于第一性和新颖性效应而导致的任何度量的增加或减少都会在几天内迅速消失。

很可能这两种心理效应搞乱了最初的治疗数据,夸大或稀释了治疗效果。

陷阱 7:没有检查首因效应和新奇效应,偏向治疗效应。

解决方案:梳理出这两种效果的最好方法就是求助于没有接触过老版本的新用户。换句话说,对新用户的治疗效果应该是治疗效果。当然,我们可以比较新用户和现有用户的治疗效果,以检查两种效果的存在。

8 个常见陷阱 0-索引:

  • 陷阱 0:不懂功耗分析,过早结束实验。
  • 陷阱 1:公司不能保证一致的集群分配,因此不是一个真正随机的过程。
  • 陷阱 2:随机分配无法平均分配大量用户。
  • 陷阱 3:无法检查其他条件不变的假设。
  • 陷阱 4:治疗组和对照组之间的交叉污染。
  • 陷阱 5:进行多重比较时被 假阳性 s 弄脏。
  • 陷阱 6:单个模式和聚集模式在放大实验中看起来不同。
  • 陷阱 7:没有检查首要效应和新奇效应,偏向了治疗效应。

Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。

https://leihua-ye.medium.com/membership

参考

t .克鲁克、b .弗拉斯卡、r .科哈维和龙博瑟姆,2009 年 6 月。在网上进行受控实验时要避免的七个陷阱。第 15 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 1105-1114 页)。

2020 年,唐博士和徐。可信的在线控制实验:a/b 测试实用指南。剑桥大学出版社。

Eryk LewinsonPython 中的功耗分析介绍

艾玛丁7 数据科学面试 A/B 测试问答

进一步阅读

喜欢读这本书吗?

请在 LinkedInYoutube 上找到我。

还有,看看我其他关于人工智能和机器学习的帖子。

在线实验技巧——方差减少

原文:https://towardsdatascience.com/online-experiments-tricks-variance-reduction-291b6032dcd7?source=collection_archive---------4-----------------------

实践教程

分层、CUPED、方差加权估计量和基于 ML 的方法 CUPAC 和 MLRATE

照片由马雷克·皮尼基Unsplash 拍摄

为什么我们需要方差缩减?

当我们进行在线实验或 A/B 测试时,我们需要确保我们的测试具有很高的统计功效,以便我们有很高的概率发现实验效应(如果它确实存在的话)。有哪些因素可能会影响权力?样本大小、实验度量的采样方差、显著性水平α和效应大小。

提高功效的标准方法是增加样本量。然而,动态范围是有限的,因为最小可检测效应 MDE 与 1/sqrt(sample_size)成比例。此外,在现实中,获取更多的样本或运行更长时间的实验来增加样本量可能并不总是容易或可行的。

我们能做的下一个最好的事情是减少实验指标的抽样方差。人们可以做的最简单的事情就是转换度量标准。Winsorize、binarize 或其他更复杂的度量转换将有助于显著减少差异。然而,度量转换会引入偏差。所以这种方法有一个偏差-方差权衡。

许多其他方差减少方法在技术产业中被开发和生产,以提高实验的灵敏度/功效。在本文中,我将介绍一些流行的方差缩减方法,并用 Python 演示一些简单的例子:

  • 分层和后分层
  • CUPED (使用预实验数据的受控实验)
  • 方差加权估值器

基于 ML 的方法:

  • CUPAC (使用预测作为协变量的控制)
  • MLRATE (机器学习回归调整治疗效果估计器)

分层

分层抽样将人口分成 k 个阶层(例如,国家),然后实验从每个阶层独立地随机抽样个体。设 Y_strat 为分层抽样下的处理效果,p_k 表示来自 k 层的样本量比例,下面的等式告诉我们,处理效果是各层处理效果的汇集平均值,是无偏的。方差是层内方差的加权平均值,并且有效地去除了层间方差。方差小于简单随机抽样下的方差,简单随机抽样既包括层内方差,也包括层间方差(更多信息见本论文)。

利弊

分层方法提供了治疗效果的无偏估计,并有效地消除了层间差异。然而,在实践中,通常很难在实验前实施分层抽样。

“在网络世界中,由于我们是随着时间的推移收集数据,我们通常无法从提前形成的地层中取样。”(邓、徐、科哈维和沃克,2013 年)

实际上,实施分层抽样既复杂又昂贵。它“需要一个排队系统和多台机器的使用。”(谢和奥里塞特,2016 年)

后期分层

在实践中,后分层比分层更常见。后分层首先对人口进行随机抽样,然后将个人分成不同的阶层。类似于分层,后分层可以实现类似的方差减少。

这里有一个非常简单的例子,我们从四个不同的正态分布(4 层)中生成数据,将个体随机分配到治疗组和对照组,将治疗效果添加到治疗组,并通过 bootstrapping 可视化治疗效果。治疗效果计算为无分层的治疗和对照之间的平均差异,以及有分层的每个层的平均差异的平均值。从我们的简单例子中,我们确实看到了分层的方差减少。至关重要的是,平均值没有变化,所以我们应该能够更好地看到任何实验对平均值的影响,因为方差已经减小了。

有无分层的治疗效果

杯状

CUPED (使用预实验数据的受控实验)由微软的亚历克斯·邓、徐亚、罗恩·科哈维和托比·沃克于 2013 年首次提出,并已被广泛应用于大型科技公司,如 bookings.com 的、、猫途鹰等。CUPED 使用预实验数据 X(例如,Y 的预实验值)作为控制协变量:

换句话说,Y 的方差减少了(1-Corr(X,Y))。我们需要 X 和 Y 之间的相关性很高,CUPED 才能很好地工作。在原论文中,推荐使用 Y 的预实验值作为 x。

这是一个抽样的例子。我们看到,对照组和治疗组的 Y 的方差都降低了,Y_cuped 和 Y 的方差之比为 0.2789,这与基于上述理论方程的(1-Corr(X,Y))值相同。减少方差会减少这两个分布之间的重叠,从而更容易看到实验效果。

【CUPED 调整前后 Y 的方差

这里我们多次模拟我们的实验,计算对照组和治疗组的均值差,得到治疗效果的分布。请注意,Y_cuped 不是 Y 的无偏估计量。但 Y_cuped 的平均差是 Y 的平均差的无偏估计量。根据下图,很明显,在我们的简单情况下,cuped 降低了我们处理的方差。

带和不带吸盘调节的治疗效果

利弊

CUPED 非常容易使用和实现。然而,协变量的选择可能是棘手的,尤其是当目标变量的实验前测量不可用时。协变量必须与目标测量相关,但与实验无关。此外,原始论文没有经历有多个协变量的情况。这篇博文讲述了从一个协变量到多个协变量的代数扩展。另一种解决方案是使用 ML 来构造控制变量,我们将在后面讨论。

方差加权估计量

方差加权估计法是由脸书和 Lyft 的 Kevin Liou 和 Sean Taylor 于 2020 年提出的。该方法的主要思想是给予具有较低预实验方差的用户更多的权重。

这种方法放松了同方差假设,而是假设每个个体都有自己的度量方差。例如,上图显示了两个人,其中一个(绿线)比另一个(蓝线)具有更高的方差。

在下面的等式中,Y 是感兴趣的度量,δ是治疗效果,Z 是治疗的指示函数。为了最小化治疗效果的方差,我们通过方差的倒数对每个用户进行加权。

与 CUPED 类似,方差加权估计也使用预实验数据。文中提到了几种估计方差的方法,包括利用预实验时间序列数据的经验方差,建立 ML 模型,以及利用经验 Bayes 估计量。最简单的方法是使用经验方差。

加权诱导偏差。为了减少偏倚,本文提出了一种基于用户实验前方差对用户进行分组的方法,计算每个分组内治疗效果和实验前方差的平均值,然后计算跨层的加权治疗效果。

因此,总的来说,在实践中,我们将估计方差,将方差分成 k 个层,通过方差的倒数对每个层进行加权,并计算加权处理效果。

这里有一个演示这种方法的非常简单的例子。我从四个层次开始,我们知道每个层次的度量方差。然后,我们可以用每一层的方差倒数来衡量处理效果。对于本例,除了分层方法之外,方差加权估计量还提供了方差减少的额外好处。

使用和不使用方差加权估计量的处理效果

利弊

  • 方差加权估计量将单个预试验方差建模为权重,它可以用作 CUPED 等其他方法的良好扩展。当用户之间存在高度倾斜的差异时,以及当治疗前差异是治疗后差异的良好指标时,它工作得很好。
  • 然而,当预处理方差的方差较低或者当实验前和实验后方差不一致时,方差加权估计器可能不起作用。此外,方差加权估计量不是无偏的。管理偏倚对这种方法很重要。

基于 ML 的方法

近年来发展了几种基于最大似然的方差缩减方法。我将简要介绍两种基于 ML 的方法——CUPAC 和 MLRATE。由于原始论文没有描述精确的算法和它们的 ML 模型的细节,我将只涉及我对高级思想的理解,而不展示这些方法的例子。

CUPAC

CUPAC (使用预测作为协变量的控制)是由 Doordash 的 Jeff Li,和 Jared Bauman 在 2020 年提出的。它是 CUPED 的延伸。CUPAC 没有选择与治疗无关的实验前协变量 X,而是使用机器学习模型的结果作为其控制变量。机器学习模型的目标是“最大化预测协变量(CUPAC)和目标度量之间的部分相关性”。

假设我们有实验前指标,X1、X2、X3 和 X4。本质上,这种方法所做的是使用一些机器学习模型来预测 Y 使用 X1,X2,X3 和 X4。然后,我们可以使用预测值作为 CUPED 中的控制协变量。

MLRATE

ml rate(machine learning regression-adjusted treatment effect estimator)是由和 Princeton 的郭等人于 2021 年提出的。

和 CUPAC 类似,MLRATE 也是用一个 ML 模型从 X 预测 Y,我们把预测值叫做 g(X)。MLRATE 不是从 Y 中减去 g(X ),而是在回归模型中包括 g(X)和治疗指标,然后计算回归调整的治疗效果。下图展示了这种回归模型:

  • 首先,我们从协变量的向量或协变量 x 的矩阵开始,然后我们学习并应用交叉拟合监督学习算法。交叉拟合用于避免过度拟合偏差。交叉拟合过程如下:我们将数据分成 k 份。对于每个分裂,我们在不在当前分裂中的样本上训练我们的数据,并获得函数 g。然后,我们使用当前分裂中的 X,并获得当前分裂的 g(X)的预测值。
  • 接下来,我们建立一个回归模型,其中我们用回归变量预测实验指标 Y:T—治疗指标,g(X) —交叉拟合 ML 的预测值,以及 T(g(x)-g)。
  • α1 的 OLS 估计量是我们感兴趣的治疗效果。

其他基于 ML 的方法

业内使用的基于 ML 的方法还有其他的。例如,Yandex 的波亚尔科夫等人在 2016 年开发了增强决策树回归调整

总之,本文总结了一些业界流行的方差缩减方法——后分层法、CUPED 法、方差加权估计法以及基于 ML 的方法 CUPAC 和 MLRATE。在实践中,CUPED 在科技公司中被广泛使用和生产,基于 ML 的方法通常用于合并多个协变量。结合多种方法来实现最佳方差减少也是常见的。希望这篇文章对你有所帮助。谢谢!

鸣谢:非常感谢 Anthony Fu 和 Jim Bednar 为本文提供指导和反馈。感谢 Kevin Liou 和 Sean Taylor 澄清了我关于方差加权估计量的问题。

参考文献

作者索菲亚·杨 2021 年 9 月 12 日

在线学习:递归最小二乘法和在线 PCA

原文:https://towardsdatascience.com/online-learning-recursive-least-squares-and-online-pca-c05bd23106c9?source=collection_archive---------11-----------------------

关于如何创建能够在处理流数据时训练一个数据点的在线机器学习模型的实用介绍

O12Unsplash 上拍照

在线学习

在线学习是机器学习的一个子集,它强调从环境中生成的数据会随着时间而变化。

事实上,传统的机器学习模型被认为是静态的:一旦模型根据一组数据进行训练,它的参数就不再改变。尽管环境及其生成的数据可能会随着时间的推移而改变,因此,我们预先训练的模型不再可靠。

为了解决这些问题,公司通常使用的一种简单解决方案是,一旦性能开始下降,自动重新训练和部署机器学习模型的更新版本。

但是,使用这种方法会导致模型周期性地表现得比预期的标准更差[1]。然后可以使用在线学习来为这个问题提供一个明确的答案。

如果你对用 Python 实现在线学习算法感兴趣, Creme 库是一个很好的起点。

本文中使用的所有代码都是可用的(甚至更多!)在我的 GitHub 个人资料上有

递归最小二乘法

介绍

递归最小二乘法(RLS)是一种用于研究实时数据的常用技术。因此,RLS 可以被认为是标准最小二乘算法的递归等价物。

在递归最小二乘法中,在每次算法迭代中分析单个新数据点,以便改进我们的模型参数的估计(在这种情况下,目标不是像最小均方误差那样最小化总均方误差)。

与其他回归技术相比,RLS 通常收敛速度更快,但计算成本更高。

关于该算法的两个重要观察结果是:

  • 使用一个名为 Lambda ( λ )的用户定义参数来定义给予过去输入数据的权重(旧输入的预测权重低于新输入)。 λ 的值越小,过去输入值的重要性越低。
  • 为了避免在每个迭代步骤中计算矩阵求逆(这在计算上可能是昂贵的),我们可以改为应用矩阵求逆引理

如果你对这个算法的实现细节感兴趣,数学推导可以在麻省理工学院开放课件[2]的“动态系统与控制讲座”中找到。

示范

为了测试这个算法,我们将在本文中使用来自 UCI 机器学习库的
每日需求预测订单数据集。

首先,我们需要导入所需的依赖项,并将数据集划分为要素和标签。在本练习中,我们的目标是在给定输入特征的情况下预测订单总数(图 1)。

图 1:每日需求预测订单数据集

现在,我们可以创建自己的递归最小二乘算法实现,并检查我们的残差。

Residual Error:  0.851

如低残差所示,我们的算法似乎已经成功地收敛到相对可靠的解决方案。这可以通过比较我们在相同任务中使用小批量梯度下降算法的结果来进一步证实(图 2)。

图 2:递归最小二乘法与小批量梯度下降

绘制实际时间序列值与递归最小二乘估计值,我们可以进一步确认这个简单问题模型的可靠性(图 3)。

图 3:总订单估算比较

最后,通过创建一个简单的函数,我们可以将我们的模型的总体残差与一些常见的 Scikit-Learn 模型进行比较,以比较性能。如下面的结果所示,高斯过程回归器似乎比递归最小二乘法表现得更好。

SGDRegressor Residual Error:  83.905
DecisionTreeRegressor Residual Error:  84.853
GaussianProcessRegressor Residual Error:  0.0
KNeighborsRegressor Residual Error:  2.296
BayesianRidge Residual Error:  84.853
MLPRegressor Residual Error:  84.661

在线主成分分析

当处理具有大量特征的数据集时,在线 PCA 当然可以被认为是一种很好的实现技术,以便尝试降低我们问题的维数,同时加快执行速度并将我们的误差限制在用户定义的限度内。在线主成分分析试图将主成分分析的相同基本概念应用于在线环境中,通过每次将一个数据点作为输入来创建其估计值。

该算法的一个主要参数是ε()。ε是我们可以容忍的给定数据(误差)。然后,该算法将返回一个 l 维度表示(O(k×poly(1/ε))略高于所需的 k 维度表示(但仍低于原始的 d 维度表示)。

使用小的 ε ,我们迫使我们的算法不能容忍太多的误差,因此这将导致 l 的高值。使用高 ε 来代替,我们允许我们的算法容忍高误差,并且允许使用低值用于 l 。按照 Boutsidis 等人[3]的实现, ε 可以用 0 到 1/15 之间的任意值来表示。通过这种方式,在线 PCA 允许我们在期望的维度和最大允许误差之间进行权衡。

使用该算法的一些额外优点是:

  1. 在线 PCA 可以使我们在更低的维度上进行推理,对输入数据进行降噪,并实现重要的计算节省(特别是在处理属于大数据机制的数据集时)。
  2. 使用在线 PCA 的优化版本,可以避免计算整个协方差矩阵(可能相当大)的所有特征值和特征向量,而是只计算我们感兴趣的第一个 N 个 特征值和特征向量。

如果您对实现在线 PCA 感兴趣, Boutsidis 等人[3]的出版物是一个很好的起点。

希望你喜欢这篇文章,谢谢你的阅读!

联系人

如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

文献学

[1]什么是在线机器学习?马克斯·佩格尔斯,四种。访问:https://medium . com/value-stream-design/online-machine-learning-515556 ff 72 C5

[2]动力系统和控制讲座。Mohammed Dahleh 等人,麻省理工学院开放课件。访问:https://OCW . MIT . edu/courses/electrical-engineering-and-computer-science/6-241j-dynamic-systems-and-control-spring-2011/readings/MIT 6 _ 241 js11 _ chap 02 . pdf

[3] Boutsidis,C,Garber D,Karnin ZS 和 Liberty,e .在线主成分分析,第 26 届 ACM-SIAM 离散算法研讨会会议录,SODA-15:887–901,2015。

使用 LakeFS 和 AWS 进行在线学习

原文:https://towardsdatascience.com/online-learning-with-lakefs-and-aws-926d8ce04a9b?source=collection_archive---------30-----------------------

使用版本控制系统和 Amazon Web Services 从头开始构建在线机器学习系统

克里斯·利维拉尼在 Unsplash 上的照片

在线学习简介

大多数教程/文章通常专注于论文评论和实验室中机器学习模型的性能。然而,一个明显被忽视的领域是将模型投入生产并监控其性能,这被称为在线机器学习或在线学习,模型不断地从新数据中学习。概念很简单。但是,在实施时会遇到一些挑战,例如:

  • 需要将数据结构化地存储在易于使用和访问的存储平台中。
  • 不断地标记新数据(如果你的模型被监督的话)。
  • 优化新的超参数,比如新数据的数量,之后应该开始新的训练迭代。
  • 在“动态”(在线)获取的数据中加入强大的数据过滤技术,更有可能出现大量不规则数据,这与实验室中为机器学习模型准备的数据不同。例如,假设我们正在讨论一个对微观病理切片进行分类的模型。一些载玻片可能比其他载玻片含有更多的灰尘,或者更糟,无法使用。这样的挑战通常会被忽视,直到很晚才被发现。它们可能看起来微不足道,但它们会破坏模型的性能。

在线学习的主要优势在于它可以防止数据变得“陈旧”。有时,数据的性质和分布可能会随着时间的推移而改变。如果你的模型没有持续改进,它的性能会持续下降。监控可以帮助决定这一点:它与在线培训一起进行,因为它将表明模型的性能是否正在下降。它还将帮助您选择重新培训模型的频率。

在线学习系统和 LakeFS

一个典型的在线学习系统将由许多步骤组成。例如,假设您有一个机器学习 web 应用程序,它将上传的图像分类为“肿瘤性”和“非肿瘤性”。您的基础架构通常需要执行以下操作:

  1. 保存每个预测到存储器(如亚马逊 S3)。定义预测的模式可能有点棘手,但是您通常会包括实际的图像、预测、置信度和日期。
  2. 保存每个培训周期的模型性能指标。
  3. 存储设备连接到模型服务器。这个连接管道可能包含一个过滤步骤,以保证数据的质量。
  4. 版本数据。这意味着您必须将新数据与旧数据一致地合并,然后重新训练。
  5. 日志实验和监控。

在实际的场景中,您会不时地对模型进行多次训练,很可能会出现性能下降的迭代。发生这种情况有多种原因,例如迭代中使用的数据质量差。在这种情况下,您需要一个工具来帮助您快速撤销这种更改,检查导致性能下降的数据,等等。这里选择的数据版本控制工具是 LakeFS

LakeFS 将允许我们增强我们的存储系统,使其类似于一个 git 存储库。这意味着我们可以推送新的变更、删除旧的提交、检查版本控制日志等等。此外,这将允许我们创建并行的 CI/CD 管道,这将使实验过程更加自动化和容易。此外,如果这些实验中的任何一个在生产流水线上失败了,我们可以简单地恢复它们。LakeFS 应该与灵活且可伸缩的数据存储机制相结合,比如 S3 对象存储。

LakeFS 的好处之一是它可以很容易地与 AWS S3 对象存储一起使用。事不宜迟,我们开始吧。

步骤 1:在 AWS RDS 上创建 PostgreSQL 数据库

有许多方法可以设置一个数据库并在 LakeFS 中使用它,但是在本教程中,我们将在 AWS RDS 上使用一个 PostgreSQL 数据库。你首先需要的是一个 AWS 账户。

登录后,转到https://console.aws.amazon.com/rds/并点击“创建数据库”,然后您应该会看到一个如下所示的窗口:

作者截图

您可以将所有选项保留为默认选项,并使用 Easy create 创建数据库。就是这样!你很快就创建了一个数据库。现在,您只需要等待几分钟,它就会被创建。

步骤 2:为存储库配置 S3 存储桶

现在我们有了 PostgreSQL 数据库,我们还需要一个 S3 对象存储桶。首先在顶部搜索栏搜索 S3 桶,然后点击第一个“S3”结果。之后,单击橙色的“创建存储桶”按钮,为您的存储桶添加一个名称并创建它。然后,您应该会看到类似这样的内容:

作者截图

之后,单击存储桶,转到“Permissions”选项卡,向下滚动到“Bucket Policy”,然后将此内容粘贴到:

你应该用你的帐号 ID 替换<account_id>(当你点击顶部的用户名时,它是你名字旁边的 12 位数字)。同样,用存储段名称替换<bucket_name>,用正确的角色(管理员)替换<iam_role>。</iam_role></bucket_name></account_id>

步骤 3:安装 LakeFS

你需要做的第一件事是安装docker-compose;这将需要运行 LakeFS 的本地实例。接下来要做的是运行这个命令:

curl [https://compose.lakefs.io](https://compose.lakefs.io) | docker-compose -f — up

要运行 lakeFS,请使用以下命令:

docker run — name lakefs -p 8000:8000-e LAKEFS_DATABASE_CONNECTION_STRING=”<postgres-connection-str>”-e LAKEFS_AUTH_ENCRYPT_SECRET_KEY=”<lakefs-secret-key>”-e LAKEFS_BLOCKSTORE_TYPE=”s3"-e LAKEFS_GATEWAYS_S3_DOMAIN_NAME=”s3.local.lakefs.io”-e LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_SECRET_KEY=”<s3-secret-key>”-e LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID=”<s3-access-key>” -e LAKEFS_BLOCKSTORE_S3_REGION=”<s3-region>” treeverse/lakefs:latest run

您需要填写环境变量;您可以在此处找到连接字符串:

作者截图

s3 区域是 bucket 区域,lakeFS 密钥可以是您选择的任何字符串。如果一切正常,您应该能够看到 lakeFS 实例在 localhost:8000 上运行

这应该是它;这是您需要的大部分初始设置和配置。接下来的几个步骤将不再是教学形式,而是理论结构。

使用 Python 设置存储库和分支

使用 LakeFS 类似于使用 Git。准备好设置后,您需要为数据集创建一个初始分支。我们将使用 python 来完成这项工作。

首先要做的是实例化一个客户端:

然后创建一个存储库和一个分支:

仅此而已。现在您的 s3 存储桶应该连接到您的 LakeFS 存储库了。

数据科学在线硕士——值得一试吗?

原文:https://towardsdatascience.com/online-masters-in-data-science-worth-taking-the-plunge-ec5c2a53048d?source=collection_archive---------22-----------------------

整个学位的每个课程和任务需要多长时间

图片由 Unsplash 的 Bruno bu ar 提供

背景

简而言之,我参加了伊利诺伊大学 3 年多时间提供的数据科学计算机科学在线硕士课程。我总共需要 8 门课程才能毕业,我每学期选一门课(每年 3 门)。每门课程都有讲座和作业,而有些课程有期末考试、期中考试、项目和测验。

我将给出我完成学位的个人经历。如果你正在考虑攻读数据科学领域的计算机科学在线硕士,并想知道我是如何找到它的,请在评论中随意提问——我很乐意尽我所能回答。

不管怎样,我发现这个项目非常有帮助👍我学到了很多。就你想深入一个主题而言,这真的取决于你对它的理解。️I 提到的唯一警告是,如果你特别想进入深度学习,或者你心里有一个非常具体的技术职位,那么我会建议你参加一个更定制的训练营类型的项目,而不是参加正式的硕士 degree⚠️.我之所以这么建议,是因为这个学位并没有详细介绍神经网络的最新发展,只是涵盖了基础知识,其中大部分你可以在网上的好教程中找到。然而,如果你想知道这些概念背后的基本统计和算法,你将在你的整个职业生涯中使用,那么像这样的程序就是你正在寻找的。

数据

用于分析的数据是由我的同学手工收集的。在整个旅程中,他仔细记录了完成每项作业、讲座、考试、期中考试、测验和项目所花的时间。如此巨大的荣誉感谢保罗收集了这一切!🙌。他同意我发表结果。

结果

总的来说,完成课程需要大约 1133 个小时。需要八门课程,在计算每周课时时,我假设了 12 周的学期。

作者图片|小时课程列表

以下是按任务类型细分的相同数据。不是所有的课程都有期末考试、期中考试、项目或测验。然而,所有的课程都有作业和讲座。

作者图片|课程条形图

用第 30 百分位的水平线画出花在做作业上的时间和花在讲课上的时间,我们看到大多数课程的总课时超过 20 小时。分布式系统花了将近 40 个小时的演讲时间,而数据清理花了不到 10 个小时的演讲时间。这个后面会讨论。

作者图片|作业散点图与讲课时间/讲课百分比

相反,在第 80 百分位垂直线处,我们看到大多数课程的作业总时数少于 90 小时。应用机器学习课程是一个明显的例外📊。那门特定的课程有将近 170 小时的作业。为什么应用机器学习在作业上花费的时间要多得多,我们将在后面讨论。

作者图片|作业散点图与讲课时间/作业百分比

为了好玩,我训练了一个聚类算法,其中聚类的数量不需要像 OPTICS 或 DBSCAN 一样指定而不是,并得到了下面的图表。每个色点对应一个特定的簇。应用机器学习(AML)和实用统计学习(PSL)似乎在他们自己的集群中。

作者图片|作业散点图与讲课时间/聚类数图例

讨论

首先,完成某些课程所花时间的差异,例如数据清理实用统计学习 (PSL)与内容的复杂性直接相关。具体来说,数据清洗主要涵盖了数据流、数据库设计、正则表达式等已经为分析专业人士所熟知的理论。因此,大多数视频可以以 2 倍的速度观看,这就是为什么花在讲座上的时间相对较少。这并不意味着只有 10 个小时的讲座😌。

PSL 深入研究了具体的聚类、分类和回归模型是如何工作的。这些更复杂的概念需要反复观看讲座多次,以充分理解和掌握主题,从而能够在测验中获得 100%的分数。此外,除了所有其他的作业和测验,在 PSL 还有四个项目。💪

这两门课程都需要 R 或 Python 方面的技能,但是它们覆盖了完全不同的领域。

作者图片|带数据标签的课程条形图

其次,我们看到应用机器学习课程需要在作业上投入大量时间。没有期末考试,没有测验,没有项目,只有很多作业。就我个人而言,我喜欢这门课,因为每项作业都像一个迷你项目,你不知道如何及时完成😅。但最后你做到了,而且很棒!

第三,我认为数据可视化和数据清理是“简单”的课程。你可以在全职工作的同时,在同一个学期里选修两到三门其他课程,而不会完全疯掉😤。我没有那样做,但是我的许多其他同学做了。

结论

如果你正在考虑攻读计算机科学/数据科学的在线硕士学位,那么我强烈推荐你。与课程中包括法律、隐私和研究设计课程的类似项目相比,这个学位项目技术性很强。我觉得,由于显而易见的原因,与更侧重于社会/定性课程的硕士学位相比,更技术性的学位更适合转化为在线形式。

从花费的时间可以看出,这个学位仍然需要大量的工作😭。令人欣慰的是,并不是所有的课程都要占用你醒着的每一分钟来完成。有“容易”吗😺一和有杀手💀只要你知道你在做什么,你最终会成为一个更好的人。

最后,我还想提一下,你应该考虑在你攻读硕士学位的 1133 个小时里做其他事情的机会成本。与 MBA 风格的硕士相比,在线技术硕士的好处是他们通常要便宜得多💰。

我希望这些数据点能让你更好地了解完成一个硕士学位需要多长时间。请花些时间消化上面的视觉效果,仅从条形图中就可以获得许多见解。

附录/参考文献

[1]保罗·内尔。UIUC 的 MCS-DS 项目的一些数据。(2019)

[2]带有 PBIX 的 GitHub,包括聚合和清理的数据。https://github . com/matt bitter/Medium _ Matthew bitter _ Grad _ Article

ONNX 从头开始进行图像处理

原文:https://towardsdatascience.com/onnx-for-image-processing-from-scratch-6694f9b141b0?source=collection_archive---------22-----------------------

使用 ONNX 进行简单的图像处理(并从头开始构建!).图片作者。

ONNX 越来越多地被用来存储复杂的 DNNs 然而,它的用途远远超出了拟合模型的简单存储。本教程展示了如何用 ONNX 构建一个图像处理管道——随后可以跨设备部署——只需几行 Python 代码。

然而,ONNX 可以有更广泛的用途:ONNX 可以轻松地用于手动指定 AI/ML 处理管道的,包括现实世界部署经常需要的所有预处理和后处理。在本教程中,我们将展示如何使用 Python 中的 *onnx helper* 工具从头开始创建 ONNX 图像处理管道并有效地部署它。**

在本教程中我们不再介绍 ONNX 请参见我们之前关于从零开始创建 ONNX 的帖子以获得总体介绍。在本教程中,我们将展示如何轻松地使用 ONNX 来指定图像处理管道。我们将涵盖以下步骤:

  1. ****管道“培训”:我们将解释我们面临的图像识别任务和我们的一般方法。
  2. ****ONNX 创建:我们将一步一步地详细介绍如何创建 ONNX 管道来执行所需的图像处理。
  3. ****在 python 中测试:我们将演示如何使用 ONNX 运行时在 Python 中测试我们的管道。
  4. ****使用 WebAssembly 进行部署:我们将演示如何将我们的图像处理管道转换为 WebAssembly,以便在浏览器、云中或嵌入式设备上进行高效部署。

请注意,本教程的主要目的是展示 ONNX 可以用来指定数据处理任务(在本例中是图像处理)的简易性,这些任务通常不被视为 AI/ML,但仍然非常有用。希望这有助于打开 ONNX 的用途,使其远远超出训练好的神经网络的简单存储。

1.管道“培训”

很难真正调用模型训练下面的步骤,但是我们从设置问题开始,包括我们将在 ONNX 中实现的分类算法所需的处理。在这个玩具例子中,我们面对的是一个小容器的总共 14 张图片,这个小容器要么是空的,要么是满的。我们的目标是创建一个 ONNX 管道(并部署它),它在给定一个输入图像的情况下,检测容器是否被填满。这里有一个例子:

满容器的示例。图片作者。

我们的方法很简单:首先计算所有空白图像的平均值作为参考。接下来,对于每个新图像,我们简单地从参考图像中减去新图像,并查看它是否偏离(太多):如果是,它一定不是空图像。

请注意,我们在本教程中实现的图像处理方法非常初级;它对于图像的光照变化不是很鲁棒,对于不同的容器也不能很好地工作。然而,这个例子显示了在 ONNX 中创建处理管道的容易程度。

使用 Pillow 和 Numpy,我们的“训练”阶段相对简单:我们简单地打开所有的空容器,计算它们的平均值:

**import numpy as np
from PIL import Image## Setup:
image_folder = “images/”
empty_containers = [2,3,5,8,9,12,13]
full_containers = [1,4,6,7,10,11,14]
all_containers = empty_containers+full_containers# Get number of images, image width, and image height:
n_empty = len(empty_containers)
image_width, image_height=Image.open(image_folder + str(empty_containers[0])+”.JPG”).size# Create a numpy array of ints to store the average (assume RGB images)
av_arr=np.zeros((image_height,image_width,3),np.int64)# Build up average pixel intensities, casting each image as an array of ints
for i in empty_containers:
 im_arr=np.array(Image.open(image_folder + str(empty_containers[0])+”.JPG”),dtype=np.int64)
 av_arr=av_arr+im_arr/n_empty# Round values in array and cast as 8-bit integer
av_arr=np.array(np.round(av_arr),dtype=np.uint8)# Generate and save the average empty container image
out=Image.fromarray(avarr,mode=”RGB”)
out.save(image_folder+”empty-average.JPG”)
out.show()**

empty-average.JPG将作为我们的参考。看起来是这样的:

空容器的平均“参考”图像。图片作者。

2.ONNX 管道创建

我们将从头开始使用 ONNX 和 Python 中的onnx.helper工具来实现我们的图像处理管道。从概念上讲,步骤很简单:

  1. 我们从给定的想要分类的图像中减去empty-average.JPG
  2. 我们计算剩余差值的绝对值。
  3. 我们将差值中的图像(绝对)颜色值的数组求和为一个数字。
  4. 我们检查这个数字是否大于某个阈值。

因此,这种实现的逻辑很简单:与(平均)空图像相比,空容器的图像应该相对相似,即其绝对差异应该很小。然而,如果容器是满的,则图像是不同的,因此它与参考图像相比的总绝对差应该很大。

实现该管道的 python 代码如下:

**# The imports used in this block
from onnx import helper as h
from onnx import TensorProto as tp
from onnx import checker
from onnx import save# 1\. We start by opening the reference image and creating the necessary ONNX constants:# The baseline empty container image (average of the 7 empty images)
reference_image=np.array(Image.open(image_folder+”empty-average.JPG”),dtype=np.int64)# The baseline image as ONNX constant:
c_base = h.make_node(‘Constant’, inputs=[], outputs=[‘c_base’], name=”c_base_node”, 
 value=h.make_tensor(name=”c_base_value”, data_type=tp.INT64, 
 dims=reference_image.shape, 
 vals=reference_image.flatten()))# The threshold value as ONNX constant; here we select an average of 25 points difference (3000000=300*400*25)
image_threshold = numpy.array([3000000]).astype(numpy.int64)
c_cut = h.make_node(‘Constant’, inputs=[], outputs=[‘c_cut’], name=”c_cut_node”, 
 value=h.make_tensor(name=”c1v”, data_type=tp.INT64, 
 dims=image_threshold.shape, 
 vals=image_threshold.flatten()))# 2\. Next, we declare the functional ONNX nodes in order of appearance:# Subtract input xin from baseline
n1 = h.make_node(‘Sub’, inputs=[‘xin’, ‘c_base’], outputs=[‘min’], name=’n1')# Compute absolute values of the remaining difference
n2 = h.make_node(‘Abs’, inputs=[‘min’], outputs=[‘abs’], name=”n2")# Sum all the absolute differences
n3 = h.make_node(‘ReduceSum’, inputs=[‘abs’], outputs=[‘sum’], name=”n3", keepdims=0)# See if the sum is less than image_threshold; if it is the image is empty
n4 = h.make_node(‘Less’, inputs=[‘sum’,’c_cut’], outputs=[‘out’], name=”n4")# 3\. Finally, we create the resulting ONNX graph# Create the graph
g1 = h.make_graph([c_base, c_cut, n1,n2,n3,n4], ‘convert_image’,
 [h.make_tensor_value_info(‘xin’, tp.INT64, target.shape)],
 [h.make_tensor_value_info(‘out’, tp.BOOL, [1])])# Create the model and check
m1 = h.make_model(g1, producer_name=’scailable-demo’)
checker.check_model(m1)# Save the model
save(m1, ‘empty-container.onnx’)**

使用 Netron ,我们可以检查生成的 ONNX 管道:

onnx 图像处理流水线。图片作者。

3.python 中的测试

在详细说明如何在小型 ESP32 设备上使用该管道进行“现场”实际图像处理之前,我们首先想看看它的性能。我们总共有 14 个测试映像,7 个空的,7 个满的。以下 python 代码使用“onnxruntime”来检查每个图像并打印我们的处理管道是否认为它是空的:

**import onnxruntime as rt# Open the model:
sess = rt.InferenceSession(“empty-container.onnx”)# Test all the empty images
print(“Iterating through all images”)
for i in all_containers:

    # Get whether in reality the container is empty
    true_empty = i in empty_containers

    # Check image using the ONNX pipeline
    target=numpy.array(Image.open(image_folder + str(i)+".JPG"),dtype=numpy.int64)    
    out = sess.run(["out"], {"xin": target.astype(numpy.int64)})  
    print("Container {} is empty {}, and it is classified as empty {}.".format(i, true_empty, out[0].flatten()))**

运行代码显示所有示例图像都被正确“分类”。完整工作版本见本笔记本。

4.使用 WebAssembly 部署

到目前为止,我们希望本教程已经展示了使用 ONNX 创建一个基本的图像处理管道是多么简单。因此,ONNX 不仅可以用来存储复杂的 AI/ML 模型,它还是一个非常有用的工具,可以在通用数据管道中表达预处理和后处理。

然而,在我们看来,ONNX 不太适合随后部署最终的管道。虽然在云中onnxruntime工作得很好,但它相当臃肿(人们需要> 200Mb 来安装运行时本身)。在(I)物联网和/或边缘设备上,简单的图像处理任务(如本教程中描述的任务)很常见,因此您无法部署完整的 ONNX 运行时。

这是否意味着 ONNX 对于在嵌入式设备上部署是无用的?不,一点也不!由于 ONNX 图的细节层次,有可能自动将 ONNX 图转换为更低层次的表示(例如,转换为 LLVM IR )。实际上,可以从 ONNX 直接到c在极小的设备上嵌入流水线。或者,我们更喜欢的选择是,从c编译到 WebAssembly:通过编译到 WebAssembly,我们现在可以使用指定的 ONNX 管道,并在几乎任何设备上毫无困难地运行它;在这里,WebAssembly 运行时将处理芯片组之间的差异(例如,英特尔与 Arm、32 位与 64 位等)。)就是我们在边缘设备上经常面对的。

使用 Scailable 提供的工具(你可以在这里注册一个免费账户),从 ONNX 到 WebAssembly 的转换是开箱即用的。上面的自动转换为我们提供了一个 [.wasm](http://b5b78d9b-69e9–11eb-858e-9600004e79cc.wasm) 二进制遵守这里描述的接口标准。随后,很容易将这个二进制文件嵌入到一个简单的c项目中:

**// Note: c code this time, not Python:int main(int argc, char *argv[]) {// ...// 1\. Read WASM into runtime.
 sclbl_core_wasm_read(wasm_path);// 2\. Initialize runtime.
 sclbl_core_wasm_init();// 3\. Generate JSON formatted runtime input string.
 char *input_string = sclbl_util_bmp_to_json(bmp_path);// 4\. Run Sclbl inference.
 char *output_string = sclbl_core_exec(input_string);// 5\. Do something with the output string.
 printf("%s\n", output_string);// 6\. Clean up.
 sclbl_core_finalize();}char *sclbl_util_bmp_to_json(char *imgPath) {// ...// read bmp file 
 sclbl_read_bmp(imgPath, &pixels, &width, &height, &bytes_per_pixel);
 enc = sclbl_b64_encode((const unsigned char *) bytes_per_pixel, width * height * bytes_per_pixel * sizeof(float));
 free(bytes_per_pixel);
 // wrap in json
 json = sclbl_raw_input_wrapper(enc);
 free(enc);
 return json;
}**

上面的代码做了一些更改以与集成摄像头交互,允许我们在只有 4Mb 内存的 ESP32 设备上运行上面的 ONNX 管道。

小型设备上的图像处理。图片作者。

相当酷。

注意,上面的代码需要可伸缩的c运行时,在注册一个帐户后即可使用。它是一个通用的 WebAssembly 运行时,使I/O到可伸缩的二进制文件变得容易,并支持模块化部署。

包裹

我们希望表明,使用 ONNX 作为工具来指定数据处理管道是相对容易的。尽管存在许多其他工具(例如 openCV ),ONNX 的一个优点是它的多功能性,结合它的特殊性,共同允许可以嵌入在微小设备上的复杂预处理、推理和后处理任务的规范(通过转换为 WebAssembly)。

如果您在使用 ONNX / WebAssembly 时有任何问题,请告诉我们!

放弃

值得注意的是我自己的参与:我是 Jheronimus 数据科学院 的数据科学教授,也是Scailable的联合创始人之一。因此,毫无疑问,我对 Scailable 有既得利益;我有兴趣让它成长,这样我们就可以最终将人工智能投入生产并兑现它的承诺。这里表达的观点是我自己的。**

开放 AI 剪辑:从自然语言监督中学习视觉概念

原文:https://towardsdatascience.com/open-ai-clip-learning-visual-concepts-from-natural-language-supervision-d02644969278?source=collection_archive---------36-----------------------

一种基于变换的神经网络,使用对比语言-图像预训练对图像进行分类

照片由 Soragrit WongsaUnsplash 上拍摄

DALL-E 似乎是本周最受关注的,但我认为 CLIP 最终可能会更加重要。这个星期我们一直在用它做实验,结果似乎好得令人难以置信;它甚至能够很好地对我相机里的照片中的蘑菇种类进行分类。

由布拉德·德怀尔对脸书的评论

几天前,OpenAI 发布了两个令人印象深刻的模型 CLIP 和 DALL-E。虽然 DALL-E 能够从图像中生成文本,但 CLIP 通过将图像分类转化为文本相似性问题来分类非常广泛的图像。当前图像分类网络的问题是,它们是在固定数量的类别上训练的,CLIP 不是这样工作的,它直接从关于图像的原始文本中学习,因此它不受标签和监督的限制。这非常令人印象深刻,CLIP 可以在没有任何数据集特定训练的情况下以最先进的精度对图像进行分类。

夹子的主要卖点

OpenAI 正试图摆脱传统的监督学习方法。例如,ImageNet(最大的图像数据集)只能对属于其接受训练的类别的图像进行分类。不断向数据集添加新的类并长期重新训练网络是没有意义的。

ImageNet 数据集是该领域最大的成果之一,需要 25,000 多名工作人员来注释 22,000 个对象类别的 1,400 万张图像。相比之下,CLIP 从互联网上已经公开的文本-图像对中学习。先前的工作已经广泛地研究了减少对昂贵的大标记数据集的需求。

来源: OpenAI

试想一下雇佣 25000 名工人要花多少钱!

CLIP 的主要卖点是零镜头图像分类,这意味着你可以获取一段文本和一幅图像,然后通过网络发送它们,并预测它们相似的可能性。

这意味着您可以进行分类,而无需针对您的自定义用例对数据集进行任何事先培训,这真的令人印象深刻,因为在此之前,几乎所有分类网络都是这样构建的,因为您会有一个自定义数据集,它将代表您想要分类的事物,然后您会有与这些数据集匹配的图像,您必须通过培训程序发送这些图像,最终使您的网络脱离,而 clip 会让您绕过这些图像。

快速回顾:对比学习

对比学习是一种为 ML 模型制定寻找相似和不相似事物的任务的方法。使用这种方法,可以训练机器学习模型来在相似和不相似的图像之间进行分类。

来源:分析公司

为了理解这种模式的力量,你必须理解什么是对比学习。对比学习已经看到了对自我监督学习技术的兴趣,特别是在计算机视觉方面,像 SimclrMoco 这样的论文。

Max BaskakovUnsplash 上拍摄的照片

你可以把对比学习看成一个匹配问题。如果你要把一只猫的图片和另一只相似的图片匹配起来,你可以很容易地做到。首先,认出第一只猫,然后找到另一只猫的图像。所以,你可以对比相似和不相似的事物。

它是怎么做到的?

我认为这个模型优于其他先进模型的主要原因之一是它使用了 NLP 和计算机视觉技术的混合。

  1. 对比预培训

预训练方法在过去的几年里变得越来越流行,并且彻底改变了 NLP。

该模型从对比预训练开始,其中图像文本对与来自一批图像的相似性相匹配。这是使用图像编码器和文本编码器完成的。对比预训练试图学习噪声不变序列表示,这鼓励所学习的表示和原始序列之间的一致性。

他们从 VirTex 获得了灵感,这是一种使用语义密集字幕来学习视觉表示的预处理方法。这种方法已被证明优于其他监督方法,如经典的高端 ImageNet 网络。

2.零射击预测(如上所述)

这很酷,如果你想亲自尝试,我推荐你看看这篇很棒的博文:

https://blog.roboflow.com/how-to-use-openai-clip/?fbclid=IwAR3TFIykuO6p7dswKL5haG1JLgpZRWYWsnGne95zRT4vh82GTQmabQaeauY

CLIP 很棒,也很有革命性,但是…

每个伟大的模型都有其局限性。虽然 CLIP 优于最先进的模型,但它也有一些缺点。

  1. 第一个是它在系统任务上表现不佳,比如计算图像中物体的数量
  2. 对未包含在其预训练数据集中的图像的概括能力较弱。
  3. 对措词和措辞敏感

最后的想法和收获

这篇文章的目的是不要过度剪辑,因为这通常是与许多全新的 ML 模型。然而,看到创新和新想法总是很棒的。我希望你能感觉到 CLIP 的开发者正试图从传统的 ML 技术转向更新颖的技术。我认为向更新颖的方法的第一步总是更困难的一步,我相信我们将来会看到基于 CLIP 的更好的方法。如果你想了解更多关于 CLIP 的技术细节,我建议看看他们的论文这里

如果你想定期收到关于人工智能和机器学习的最新论文的评论,请在这里添加你的电子邮件并订阅!

https://artisanal-motivator-8249.ck.page/5524b8f934

开放式无人机地图-所有人都可以使用本地和城市比例地图

原文:https://towardsdatascience.com/open-drone-map-local-and-urban-scale-mapping-available-to-all-2857b61e7803?source=collection_archive---------19-----------------------

实践教程

包括您在内的每个人现在都可以进行本地和城市范围的采集、处理和制图

戴安娜·姆塞努Unsplash 上拍摄的照片

摄影测量(从二维图像创建三维数据)并不是一项新技术——事实上,根据维基百科,使用照片进行地形测绘是由法国测量员多米尼克·阿拉戈在 1840 年首次提出的[1]。经典的例子包括立体摄影,其利用从稍微不同的视角拍摄的两个图像的视差效应来产生 3D 效果,而更先进的摄影测量的例子使用具有从许多不同角度拍摄的空间元数据的数字图像,使用计算机的能力来处理出正射镶嵌图像和点云。

通过开源社区的力量,有一个应用程序脱颖而出。开放无人机地图(ODM)是一个文档化的应用程序,允许个人和组织以可扩展的方式处理从有效的任何地理标记图像集(想想相机和无人机)收集的原始图像。虽然高质量的激光雷达在 x、y 和 z 方向上要精确得多,但与商用现成无人机市场的低端产品相比,获得激光雷达有效载荷仍然相当昂贵。

开放式无人机地图允许在任何设备上对多组图像进行不同程度的处理,从 PC 一直到虚拟集群、云和服务器,使其具有可扩展性。输出包括正射影像(或正射影像)、数字表面模型(DSM)、数字高程模型(DEM)、点云和 3D 纹理模型,所有这些都具有空间属性,可用于您首选的地理空间信息系统(GIS)!

上面列出的一些数据集的使用案例和应用程序的数量无穷无尽,为城市和地方尺度的空间分析打开了一个令人惊叹的世界。例如,我使用在我的地产上生成的模型来跟踪整个季节的植被生长,创建我的房子的高分辨率地图,计算从我的水箱到浴室的高差,以计算压头,甚至使用图像作为底图来跟踪和属性我的地产上的众多植物物种,以便我可以轻松地在未来的农业活动中参考它们。

作者图片

第一步是获取收集到的图像的良好样本。你既可以自己收集,也可以访问他人收集的样本库。但是,如果使用无人机,请务必了解适用于您所在区域的无人机飞行地点和方式的法律。我使用的是 DJI Mavic Pro,这是一个标准的 RGB 传感器,带有 GPS 定位和 IMU。以下是您可能考虑如何以无人机为例收集影像的一些考虑因素:

  • 面积有多大,可能需要多少电池(1 个电池可以一次绘制几英亩的地图)
  • 在感兴趣的区域周围是否有可能影响起飞、着陆或移动的垂直障碍物
  • 我正在测绘的位置有哪些法律考虑因素,包括空域规则和规定、隐私以及某些飞行模式所需的资格
  • 天气条件,包括风速、雨和照明条件(我发现上午 9-11 点和下午 1-3 点是照明和阴影的好时间)
  • 我应该在图像中实现多少重叠,以优化输出,同时最大限度地减少收集时间
  • 有一些应用程序可以自动收集图像,但我会让您自己探索这些应用程序。

如果你想访问现有的图像库,我推荐你去 ODM 论坛查看可用的数据集

设置 ODM

对于 Windows 或 Mac 用户, ODM 提供了一个简单的安装程序方法,只需一次性购买,就可以减少对命令行安装过程的需求,并通过 GUI 使事情变得更简单。很明显,大量的开发工作正在进行,以使这个工具尽可能广泛地为每个人所用,并且为了使它可持续,已经为更容易的安装方法提供了一个小的价格。

我将完成的以下过程使用了在我的游戏笔记本电脑上的 Linux 操作系统上运行的 WebODM 的 dockerized 实例,并且是完全免费的。我选择 Linux 是因为它有利于包管理和依赖性,同时对可用计算资源的开销很低(我们想要最大的处理能力!).

安装 WebODM

  1. 安装最新版本的 Docker(因 Linux 发行版而异)
  2. 从 docker 存储库中取出 ODM 的最新 docker 映像docker pull opendronemap/odm
  3. 在命令行中导航到 WebODM 目录
  4. ./webodm.sh start(启动 docker 环境的 bash 命令)— Docker 将开始下载并创建运行 ODM 应用程序所需的映像和容器
  5. 完成并运行 Docker 应用程序后,导航至您最喜欢的浏览器并进入localhost:8000
  6. 我应该注意,在基本配置中,ODM 没有配置证书等。如果您想通过跨服务器访问 ODM 来运行它,我建议您深入研究更全面的安全配置。

你的浏览器应该有一个非常漂亮干净的 GUI。ODM 将事情简单地分为“项目”和“任务”。一个项目中可以有多个任务,也可以有多个项目。

处理图像

  1. 创建项目
  2. 创建一个任务并将您的图像集添加到工作中——避免那些不会为您的工作增加价值的图像,如地平线或天空图像
  3. 选择您的处理选项(选择 3D 将创建一些数据集,包括正射镶嵌)
  4. 单击提交-作业处理时间将取决于您使用的节点的处理能力和/或您选择的节点数量
  5. 当你关闭 Docker 时,不要忘记发出一个 stop 命令./webodm.sh stop——Docker 中的 ODM 映像下次还会在那里,并且第二次应该会很快启动。

下面是我运行的一个作业的例子,其中包括来自 DJI Mavic Pro 的 280 张图像。我用了两年的游戏电脑完成这项工作大约需要。处理时间为 2-3 小时。WebODM 甚至有一个内置的“GIS”来查看和进行基本的空间分析。

作者图片

作者图片

这个应用程序还有很多其他的特性可以探索。这些方法包括使用额外的处理节点、使用地面控制点来提高空间精度、调整采集参数等等。beauty is ODM 是一个受到良好支持的开源包,它有一个的大型知识库,供那些想了解更多信息的人使用,包括社区论坛。欢迎来到开放无人机测绘的世界!

参考资料:

[1]:En.wikipedia.org。2021.摄影测量——维基百科。[在线]见:维基百科(点击链接),2021 年 5 月 6 日访问。

DeepMind 的开放式学习

原文:https://towardsdatascience.com/open-ended-learning-at-deepmind-da986c05f16f?source=collection_archive---------28-----------------------

播客

马克斯·贾德伯格关于构建能玩他们从未见过的游戏的代理

苹果 | 谷歌 | SPOTIFY | 其他

编者按:TDS 播客由 Jeremie Harris 主持,他是数据科学导师初创公司 SharpestMinds 的联合创始人。每周,Jeremie 都会与该领域前沿的研究人员和商业领袖聊天,以解开围绕数据科学、机器学习和人工智能的最紧迫问题。

从表面上看,强化学习范式没有明显的限制:你把一个代理放在一个环境中,奖励它采取良好的行动,直到它掌握一项任务。

而且到去年为止,RL 已经取得了一些惊人的成绩,包括精通围棋,各种雅达利游戏,星际争霸 2 等等。但是人工智能的圣杯不是掌握特定的游戏,而是一般化——让代理人能够在他们之前没有接受过训练的新游戏中表现良好。

然而,快进到今年 7 月,DeepMind 的一个团队发表了一篇名为“开放式学习导致一般能力代理”的论文,朝着一般 RL 代理的方向迈出了一大步。和我一起参加本期播客的是这篇论文的合著者之一,马克斯·贾德伯格。马克斯在 2014 年进入谷歌生态系统,当时他们收购了他的计算机视觉公司,最近,他成立了 DeepMind 的开放式学习团队,该团队专注于将机器学习进一步推向跨任务概括能力的领域。我和 Max 讨论了开放式学习、通用化的前进道路和人工智能的未来。

以下是我在对话中最喜欢的一些观点:

  • 最近 DeepMind 关于开放式学习的论文中报告的最重要的进步之一是代理人玩的游戏的程序生成。通过自动生成大量不同的环境和游戏目标,智能体可以接受各种各样任务的训练,迫使他们开发元学习技术,如探索和试错法。
  • 他们制作的游戏包括个人、合作和竞争场景。有趣的是,代理人似乎比合作行为更容易(也更快)学会竞争行为。马克斯认为这是因为竞争伴随着一个更渐进的学习曲线:代理人被训练与其他代理人竞争,这些代理人在过程的每个阶段都经历了与他们大致相同的训练量。随着他们技能的提高,他们在游戏中的对手也在提高,所以他们总是为竞争动力学的“下一课”做好准备。
  • 在开放式强化学习的最新进展和缩放语言模型的进步之间有许多有趣的相似之处。在这两种情况下,研究人员感兴趣的是确定可以可靠测量的概括能力的代理。例如,在 OpenAI 的 GPT-3 的情况下,这些代理之一是算法的算术能力:GPT-3 在增加小数字方面做得很好,但在增加大数字方面失败了——一些人认为这表明 GPT-3 还没有“学会理解”加法的概念。强化学习中加法的类比可能只是博弈论:一个强化学习代理人如何以及如何持续地将博弈论的原理应用到它所面临的问题和环境中?
  • 也就是说,Max 还观察到,像 GPT-3 和开放式 RL 学习者这样的模型确实显示出对算术和博弈论的不完美掌握,这一事实可能只是反映了他们倾向于学习启发式而不是严格的符号逻辑。这可能是一件好事:试探法比逻辑更健壮,因为它们可以随着应用它们的问题领域变得更复杂而进化。启发式也是人类用来学习事物的方法,这就是为什么我们显示了许多与人工智能模型相同的失败模式:大多数人很难用大数做算术,但我们不认为这表明他们不能(或不理解)数学。也许我们应该以同样的方式思考人工智能。

你可以点击这里在 Twitter 上关注 Max。

章节:

  • 0:00 介绍
  • 1:30 Max 的背景
  • 6:40 程序代的差异
  • 12:20 定性方面
  • 17:40 代理人的错误
  • 20:00 测量概括
  • 27:10 环境和损失函数
  • 32:50 符号逻辑的潜力
  • 36:45 两个不同的学习过程
  • 42:35 预测研究
  • 45:00 总结

开放 MLOps:开源生产机器学习

原文:https://towardsdatascience.com/open-mlops-open-source-production-machine-learning-f4080f02e9f0?source=collection_archive---------19-----------------------

我们正在发布 Open MLOps 的测试版:一个用于构建机器学习解决方案的开源平台。

来源:作者

所有的机器学习团队都面临着同样的任务:管理一个预处理流水线;训练和测试模型;并将模型部署为 API。

几乎每个团队都构建了自己的内部工具和脚本大杂烩。替代方案是要么购买昂贵且受限的专有平台,要么花几个月的时间学习和配置开源产品。前者“只是工作”但有局限性;后者很难建立,但是很灵活。

我们想要“灵活和简单”,所以我们构建了开放式 MLOps

Open MLOps 是一套 terraform 脚本和用户指南,帮助您在 Kubernetes 集群中建立一个完整的 MLOps 平台。所有这些都是开源的。

Open MLOps 开箱即用,您可以轻松地根据自己的需要进行调整。来源:作者

谁是开放市场?

开放式 MLOps 适用于任何工程团队。我们构建它是为了让它易于设置,并且可以适应几乎任何机器学习用例。您会发现开放式 MLOps 非常有用,

  • 一个机器学习研究团队:你知道你应该使用 MLOps 的最佳实践。但是您不确定如何开始,并且您缺乏构建自己的框架的工程能力。
  • 一个机器学习初创公司:你需要快速发布你的 PoC。但是它也必须是可扩展的。你知道 Kubernetes 可以解决你的问题,但你没有太多的专业知识。
  • 个体机器学习实践者:即使是你自己,你也要努力跟踪你已经运行的实验,并且你在重复的工作上浪费时间和精力。您需要一种更简单、更快速的方法来用 API 包装您的模型、跟踪实验和管理数据管道。
  • 大型企业中的机器学习团队:预先构建的解决方案对您来说不够灵活。你知道你应该建立自己的,但你不想从零开始。
  • 机器学习学生:如果你想从学术界跳到工业界,你可以通过建立开放的 MLOps 并遵循我们的指导来试水。

Open MLOps 允许您将一组可配置的工具部署到 Kubernetes 集群中。如果您需要连接自己的身份验证或以特定的方式配置服务,您可以简单地派生存储库并构建现有的 Terraform 脚本。

什么是开放式 MLOps?

默认情况下,Open MLOps 设置并连接几个开源机器学习工具。来源:作者

Open MLOps 是 Terraform 脚本和漫游教程的开源存储库,用于在 Kubernetes 集群中设置各种机器学习工具。

默认情况下,这会设置:

  • 提督:用于调度任务和构建依赖任务的 Dag。您可以使用它来清理数据、培训和部署模型,或者执行其他需要自动化的任务。任务是使用 Python 定义的,您可以使用直观的装饰器轻松地将它们构建到管道中。
  • JupyterHub :一个共享的 Jupyter 笔记本环境,供你的团队运行实验、共享代码和进行数据辩论。
  • MLFlow :跟踪实验和模型,密切记录结果和运行,这样你就知道什么已经试过了,什么正在工作。
  • Dask :在多个内核或机器上轻松并行处理繁重的计算任务。
  • Seldon :将你的模型转换成生产 REST APIs,并大规模服务。

我需要什么来开始使用 MLOps?

开始使用 MLOps 最简单的方法是使用 AWS。您所需要的只是访问 AWS 帐户和创建新服务的权限。

您还需要一些使用命令行工具的经验。具体来说,您将在设置过程中使用 Kubectl 和 Terraform,但我们的指南会指导您完成所有工作,因此您不必成为专家。

使用我们的设置指南,您可以在几个小时内完成一切运行和配置。再过一个小时,你就已经在训练你的第一个模特了。

为什么我应该使用开放式 MLOps?

MLOps 是一个新兴但快速增长的领域,旨在帮助机器学习团队快速迭代,可靠地交付结果,并高效地协作。您的团队将在几个方面受益于构成开放 MLOps 的成熟开源工具:

  • 雇佣开发者更容易。开发人员不想要依赖专有软件的角色。他们知道这些可能是没有前途的工作,他们无法学到可转移的技能。
  • 不要多此一举。开发一个能满足您所有需求的内部平台往往很有诱惑力。但是大多数团队发现这比他们预期的要复杂。你可以阅读我们关于为什么机器学习工程比软件工程更复杂的帖子。即使您有复杂的定制需求,您也可以从 Open MLOps 作为基础层开始,并在此基础上构建您的定制解决方案。
  • 建立可复制的模型。机器学习团队最大的抱怨是难以跨不同系统或随着时间的推移复制他们的工作。通过在 MLOps 实践中使用广泛采用的框架和工具,您可以确保永远不会留下没有人能够再次构建的大型二进制模型。
  • 高效协作。如果团队中的每个人都使用相同的系统,那么一起工作、分享或把工作交给其他人会更容易。

反馈、问题或功能请求?

如果您尝试过 Open MLOps,并且需要支持或想要分享您的经验,请联系。或者,您可以直接在 Open MLOps repository 上随意打开问题或拉请求。

AWS 深度学习 AMI 的开源替代方案

原文:https://towardsdatascience.com/open-source-alternative-to-the-aws-deep-learning-ami-f8f77318f8a8?source=collection_archive---------22-----------------------

一篇描述如何使用 conda、Docker、make 和 terraform 自动设置 GPU 基础架构的文章。

尼克斯特拉团队 费德·加尔萨·拉米雷斯马克斯·梅根塔尔

TLDR;使用 GPU 运行深度学习模型非常复杂,尤其是在配置基础设施时。预制的 GPU 云基础设施往往特别昂贵。

为了帮助人们专注于他们的模型而不是他们的硬件和配置,我们在 Nixtla 开发了一种快速简单的方法来在 AWS 云上使用 gpu,而无需为 AMI 环境付费,并将其开源:https://github.com/Nixtla/nixtla/tree/main/utils/docker-gpuhttps://github . com/Nixtla/Nixtla/tree/main/utils/terraform-GPU

简介

深度学习已经广泛应用于许多领域:计算机视觉、自然语言处理、时间序列预测等。由于它所获得的最先进的结果,它在数据科学家和研究人员的日常实践中变得越来越受欢迎。

GPU 加速了模型的训练和推理,因为它们经过优化,可以执行深度学习严重依赖的线性代数计算。然而,对这种专用硬件的需求增加了试验和将这些模型部署到生产中的货币/经济成本。

深度学习实践者面临的一个普遍问题是云上 GPU 基础设施的正确配置。安装硬件管理所需的驱动程序往往很麻烦。如果不能正确解决这个问题,可能会对再现性造成损害,或者不必要地增加这些新模型的成本。在本帖中,我们使用 Docker 为社区提供了一个简单的解决方案。

解决方案

  1. 英伟达深度学习 AMI +康达环境+ Terraform

a)英伟达深度学习 AMI

要使用 GPU 加速计算运行您的代码,您需要做两件事:(1)拥有 NVIDIA GPUs,以及(2)它们必要的驱动程序。

如果你选择 EC2 实例 (P2、P3、P4D 或 G4) ,NVIDIA 提供免费的 AMI ,预装优化的 GPU 软件,你只需要支付 EC2 计算费用。

您可以通过 AWS 控制台从终端轻松启动 GPU EC2 实例及其相应的驱动程序。为此,您需要:

  1. AWS CLI 安装
  2. EC2 启动权限。
  3. EC2 连接权限:(I)。pem 文件从实例启动< YOUR_KEY_NAME >(您可以按照这里的说明创建一个)。(II)实例的安全组< YOUR_SECURITY_GROUP >。

如果您没有自己的<your_security_group>,您可以使用创建一个:</your_security_group>

aws ec2 create-security-group \
        --group-name nvidia-ami \
        --description “security group for nvidia ami”

并使用以下内容向其添加入口规则:

aws ec2 authorize-security-group-ingress \
        --group-name nvidia-ami \
        --protocol tcp \
        --port 22 \
        --cidr 0.0.0.0/0

有了以上内容,启动 GPU ready EC2 实例就像运行以下命令一样简单:

aws ec2 run-instances \
        --image-id ami-05e329519be512f1b \
        --count 1 \
        --instance-type g4dn.2xlarge \
        --key-name <YOUR_KEY_NAME> \
        --security-groups nvidia-ami

图像 id ( —图像 id )标识所需的 NVIDIA AMI。实例数量( —计数)和实例类型( —实例类型)的值是可选的。

一旦实例被初始化,我们就可以用 ssh 来访问它。AMI 预装了 git,因此我们可以毫不费力地克隆我们项目的 repo。

ssh -i path/to/<YOUR_KEY_NAME>.pem ubuntu@<PUBLIC_EC2_IP>

b)康达环境

我们推荐使用 Conda 来方便处理深度学习依赖( PyTorch、TensorFlow 等)。),特别推荐用 environment.yml 文件创建环境。

下图显示了一个示例。本例中使用的深度学习框架是 PyTorch ,也包含了 NumPypandas 等标准库。这个文件是一个框架,所以可以毫无困难地添加任何附加的依赖项。此外,还包括 jupyterlab

原始文件可以在这里找到

可以看到,要用的 python 版本是 3.7。这个版本可以很容易地根据用户的需要进行调整,其他版本的软件包也是如此。

要使用 conda 环境,您需要先安装 conda,因为 NVIDIA AMI 没有安装它。您可以遵循下一组说明:

wget [https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh](https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh) && \
bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda && \
rm -rf Miniconda3-latest-Linux-x86_64.sh && \
source $HOME/miniconda/bin/activate && \
conda init

因此您可以在您的环境中安装,

conda env create -n <NAME_OF_YOUR_ENVIROMENT> -f environment.yml

为了验证一切都正确安装了,您可以克隆我们的 repo 并运行一个测试,

git clone [https://github.com/Nixtla/nixtla.git](https://github.com/Nixtla/nixtla.git)
cd nixtla/utils/docker-gpu
conda env create -n gpu-env -f environment.yml
conda activate gpu-env
python -m test

最后一条建议:用户必须小心所使用的深度学习框架的版本,验证它是否与 NVIDIA AMI 驱动程序兼容。

c)地形

为了促进上述整个过程的创建,我们开发了一个地形脚本。Terraform 是一个开源的基础设施,作为代码工具,允许你将所有的手动开发合成一个自动脚本。在这种情况下,我们编写的基础设施代码挂载 NVIDIA AMI(包括创建一个兼容的安全组)并安装 conda。下图显示了 main.tf 文件。

原始文件可以在这里找到

此外,凭据需要 terraform.tfvars 文件。该文件的图像如下所示。

原始文件可以在这里找到

要使用 Terraform,您只需按照这些说明进行安装。随后,您必须运行

terraform init
terraform apply

这将创建所需的基础设施,并在部署的 EC2 上安装 conda。当 Terraform 完成运行时,您将能够看到与实例相关联的公共 IP,因此您只需要使用 ssh 连接来访问它。

ssh -i path/to/<YOUR_KEY_NAME>.pem ubuntu@<PUBLIC_EC2_IP>

2) NVIDIA 深度学习 AMI + Conda 环境+ Terraform + Docker + Make

a)码头工人

使用 Docker 来确保项目和实验的可复制性是常见的做法。此外,它允许用户将所有必需的依赖项集中在一个地方,避免在本地安装依赖项,这可能会在以后导致冲突。

我们使用 docker 是因为它允许我们将软件从硬件中分离出来,使计算更加灵活。如果负载非常重,只需更改 EC2 实例并运行容器内的代码就足够了。另一方面,如果负载较轻,我们可以选择较小的实例。

下图显示了我们为图像构建的 Dockerfile,用于访问实例的 GPU。首先,必须选择一个与 EC2 上安装的驱动程序兼容的映像。迄今为止,NVIDIA AMI 使用 CUDA 版本 11.2,因此这是所选的图像。

原始文件可以在这里找到

随后,安装项目可能需要的其他操作系统库。例如,在上面的 docker 文件中,安装了 wgetcurl ,这对于下载项目所需的数据可能很有用。

在下一条指令中,安装了 miniconda 。正如我们之前所讨论的,Conda 将允许我们处理 python 依赖项,并使用前一节中显示的 environment.yml 文件来安装它们。

我们强烈推荐使用 mamba 进行版本管理和安装,因为它可以显著减少等待时间。如果用户愿意,她可以很容易地切换到康达。

最后,前面创建的 environment.yml 文件被添加到 Docker 映像并安装在基础环境中。没有必要在每次需要容器时都初始化特定的环境。

b) Makefile

最后,我们为 Makefile 的使用提供了便利。 Make 是控制工作流和可执行文件的强大工具。我们的工作流将允许我们从 Docker 文件快速构建 Docker 映像,并运行 python 和 bash 模块,而无需连续声明必要的参数。

原始文件可以在这里找到

在本例中,Docker 映像将被称为 gpucontainer ,您可以运行 make init 来构建它。一旦执行了这条指令,用户就可以使用 run_module 指令来使用 GPU 运行她的 python 或 bash 模块。

例如,为了验证一切工作正常,我们创建了 test.py 文件,确保 CUDA 可用于 PyTorch 并且 GPU 可用。该模块将按如下方式执行:

make run_module module="python -m test"

原始文件可以在这里找到

其他有价值的指令可能是在 Docker 容器中运行 nvidia-smi 来验证一切正常:

make run_module module="nividia-smi"

或者交互初始化容器,可以用 make bash_docker 来完成。最后,提供了一个在 docker 中运行 jupyterlab 并进行交互式实验的指令:

make jupyter

如果端口 8888(默认)被另一个进程使用,可以使用

make jupyter -e PORT=8886

总结

在这篇文章中,我们展示了一个简单的解决方案,来解决在云上配置 GPU 进行深度学习的问题。有了这个完全开源的工作流程,我们希望该领域的从业者将花费更多的时间来实现模型,而不是像我们一样花太多时间在基础设施上。

您现在可以参与的开源数据科学项目

原文:https://towardsdatascience.com/open-source-data-science-projects-you-can-contribute-to-today-ee766f4b8494?source=collection_archive---------13-----------------------

来自一个初学者的提示,关于你可以开始工作的一些最好的数据科学代码库,以及为什么你应该这样做

卢克·切瑟在 Unsplash 上的照片

为开源做贡献是一个很好的方式,可以获得与大型团队和代码库合作的经验,参与开发社区,为你的简历增加价值,最重要的是,为你使用或相信的软件做出真正的贡献。

对于初学者来说,从事开源项目的世界可能会令人生畏,这是可以理解的。但事实上,有非常欢迎的社区,那里的成员愿意指导你通过你的第一次公关(拉请求)。你只需要挑选一个回购,然后开始!

寻找项目

出于几个原因,我建议为您实际使用的软件做贡献。首先,你会被激励去添加你想要的特性,并且在你下次使用它的时候会得到满足感,因为你知道你在构建它的过程中扮演了一个小角色,也因为你已经对项目和代码有了一定程度的熟悉。

我发现 opensource.guides 是一个有用的资源,可以提供关于贡献和寻找项目的技巧。此外,这个 GitHub repo 有一个完整的适合初学者的开源项目列表,你可以仔细阅读(尽管不是所有的都与数据科学相关)。我相信,找到一个社区对新来者有耐心和帮助的项目是很重要的。

Marvin MeyerUnsplash 上拍摄的照片

一些很棒的回复

如果您对数据科学和 ML 感兴趣,那么您可能已经使用过或者至少以前遇到过这些,使它们成为极好的起点。

sci kit-学习

Sklearn 是一个面向任何进行机器学习的人的主要 Python 库,允许您进行回归分析、聚类、分类等等。他们发展迅速,并向甲板上的新手开放。你可以在 GitHub 页面找到他们的“好的第一期”标签这里

numpy

虽然不是真正的特定于 ML 的库,但 numpy 提供了强大的数值计算工具,这些工具通常与 Python 中的数据科学工作密切相关。从他们的网站来看,他们似乎很重视他们的社区,这对新的贡献者来说是个好兆头。你可以在 GitHub 页面找到他们的“好的第一期”标签这里

matplotlib

我们熟知并喜爱的 Python 数据可视化库。他们的网站有非常全面的投稿指南。你可以在 GitHub 页面找到他们的“好的第一期”标签这里

熊猫

这个灵活而强大的 Python 数据操作和分析库有一个活跃的社区,在他们的博客上有新闻更新。你可以在 GitHub 页面找到他们的“好的第一期”标签这里

PyTorch

一个机器学习框架,加速了从原型到部署的过程。这是一个真正先进的社区,有许多互动渠道。我要说这是一个伟大的贡献。你可以在 GitHub 页面找到他们的“好的第一期”标签这里

照片由“我的镜头人生”Unsplash 上拍摄

如何开始

阅读指南

一旦你找到了你想做的项目,阅读他们的投稿指南是很重要的。所有成熟的开源软件都应该有这样一个文档,无论是在他们的 GitHub 还是网站上。请记住,虽然这些社区是开放和欢迎的,但他们正在做严肃的工作,你应该熟悉作为贡献者对你的要求,这样你就不会浪费任何人的时间——包括你自己的时间。

查找未决问题

接下来,浏览他们标记为适合初学者的开放问题,当你发现一个你想解决的问题时,询问你是否可以解决它,或者只是解决它并提交一份 PR,如果他们在指导方针中允许的话。这个视频给了我很大的帮助,关于如何完成我刚提到的所有步骤,当我开始的时候。

记录还是不记录?

许多资料建议您从撰写文档开始。这听起来可能不太性感——的确不是——但我还是要说这是合理的第一步。然而,认为这不过是第一步。它可以帮助你熟悉高级 git,导航庞大的代码库并遵循正确的程序——毕竟,必须有人去做——但它不是特别令人印象深刻或有意义的工作。所以不要留恋。

修复该问题

显然,最后一步是解决问题。派生出回购协议,将其克隆到您机器上的本地,按照说明找到有问题的代码,做需要做的事情,如果需要,创建一个新的分支,提交您的 PR,嘣。你已经在一个真正的软件上留下了你的印记。

克里斯·利维拉尼在 Unsplash 上的照片

最后的想法

为开源项目做贡献是对你的简历和投资组合的一个有意义的补充。这表明你有能力,参与社区,热情,有团队精神。更不用说,真的是可喜可贺!您不必将自己局限于我上面介绍的软件,但是如果您特别想开始参与数据科学项目,由于它们的广泛使用和受欢迎的社区,这些绝对是不错的选择。

如果我在本文中还没有包含足够的链接,那么仅适用于初次接触者是您开始接触开源资源的一站式商店。

感谢阅读!你贡献过哪些开源软件,我有没有漏掉什么好的?如果你能留下回复,我们可以讨论一下,我会很高兴的。

编码快乐!

订阅 📚为了不错过我的一篇新文章,如果你还不是媒体会员,请加入 🚀去读我所有的,还有成千上万的其他故事!

开源运营:确定帮助实现三星级部署的解决方案

原文:https://towardsdatascience.com/open-source-operationalisation-identifying-solutions-to-help-achieve-three-star-deployments-34230c690904?source=collection_archive---------37-----------------------

您的三星级开源运营难题的解决方案只需 4 分钟即可阅读

图片由卡罗琳娜·格拉博斯卡像素上拍摄

在我以前的文章中,我谈到了开源分析的运营和在餐馆工作之间的相似之处。我列出了这一过程中的所有挑战,现在(最后)我将谈谈我们如何解决这些挑战。这应该有助于您实现值得三星的开源操作!我建议在三个方面下功夫是很重要的:分析的异质性,将模型视为公司资产,而不仅仅是关注技术。

分析异质性

首先,让我们了解分析的异构性。这意味着不同的分析解决方案协同工作,这正是我们有效运营开源所需要的。多样性是创新的关键因素,无论是在员工还是在技术方面。由考吉尔等人于 2020 年在哥伦比亚大学进行的一项研究得出结论,多元化的数据科学团队有助于减少偏见。这变得越来越重要,因为世界各地的政府都在提出关于伦理人工智能的法规。有关这方面的更多信息,请务必参加 4 月 13 日的 SAS 网络研讨会。

对于技术,企业需要在用户选择和治理控制之间取得平衡。在招聘空缺职位时,选择允许更广泛的人才库,并使任何角色更有趣。这当然有助于留住员工。毕竟,当你花了几年时间学习 Python 后,你不会呆在一份被迫使用 R 的工作中!Choice 还有助于通过企业收购和有据可查的数据和模型管道,减少供应商锁定和技术债务。然而,重要的是不要疯狂选择。控制的平衡是关键,可以通过在整个企业范围内以一致的技术堆栈为目标来实现。这只能通过了解用户需求并将其与技术相匹配来管理,以便减少重复的技术并使用基于案例的技术获取。

作为公司资产的模型

第二,将模型视为公司资产改变了它们在企业中使用的思维模式。它赋予它们与现金、存货、机械和专利等其他资产同等的重要性。要真正理解和控制作为资产的模型,您必须拥有监控模型性能、偏差和决策公平性的流程。这有助于促进治理,这对于应对运营挑战至关重要。它还确保人们继续参与决策过程。

这反过来意味着治理涵盖了数据和模型。将知道所有起作用的元素的所有权,帮助企业遵守政策、标准和法规。反过来,这将通过分析的可解释性和民主化鼓励跨业务的资产重用。换句话说,更多的人将知道分析正在做什么,并有助于它的使用,加速创新。

不仅仅关注技术

最后,不要只关注技术!在这些文章中,我一直强调成功的运营需要更多。棘手的是不要有太多的技术,增加不必要的运营支出。通过一致的技术堆栈推动技术收购,企业可以在选择和控制之间取得平衡,消除不必要的用例。不用花时间解决技术债务或参加技术收购会议,可以腾出时间来做重要的事情,例如增加多样性、确保分析异构性和安装正确的治理,以允许模型被视为公司资产!

也就是说,有些特性和功能是您希望包含在技术堆栈中的。首先,您需要能够为所有模型提供治理,不管是哪种语言。这使您可以给数据科学家最大的自由来构建最佳模型。理想情况下,治理将允许持续集成、交付和监控,提高企业分析平台不同元素之间的效率和集成,在需要的地方应用自动化。第二,你应该确保可以访问你所有的数据。如果您不能访问您的所有数据,那么包含一个全新的数据科学工具来构建最准确、令人瞠目结舌的模型是没有意义的。如果工具要求您复制所有数据进行处理,这也会减少您通过模型产生的价值。

最后的想法

我希望大家明白,协作、共享过程知识和开放性是实现高质量、高效和可重复的开源操作的关键要素。这些当然是一家餐厅达到三星级的关键因素!

为了更好地了解这个话题,我鼓励你去看看“ModelOps”或“MLOps”。我推荐一个三集系列,也是由 yours truly 在 Medium 上出版的,作为一个很好的开始。我也鼓励你们参加我和一些同事一起开发的自我评估。这提供了按重要性排序的定制建议,这些建议可以得到涵盖人员、流程,当然还有技术的咨询服务的支持。

最后,如果你熟悉我在第一篇文章中展示的电影料理鼠王,你会知道我们看到的打翻汤的洗碗工(或洗碗工)——让我们的朋友老鼠雷米冲进洗碗池的事件——在拯救著名的法国厨师古斯特的餐馆免于平庸方面至关重要。如果不给人们通过协作和流程知识来帮助创新的机会,谁知道你会错过多少机会?

请随时在社交媒体上联系我; twitter 或者 LinkedIn ,如果有什么问题想深入探讨!

值得一看的开源报告工具

原文:https://towardsdatascience.com/open-source-reporting-tools-worth-a-look-a49a91d93f9a?source=collection_archive---------6-----------------------

探索微软 SSRS 的替代方案

斯科特·格雷厄姆Unsplash 上拍照

当想到报告服务的世界时,我想知道是否有任何开源的报告工具。开源将允许更多的定制,但通常也是一个有趣的话题。当我最终在网上搜索它时,我发现它不仅仅是一个单一的开源报告工具。相反,有相当多的选择。有一张清单,上面列有最好用的工具。现在,在很大程度上,相当多的报告服务最终在列表上重叠。但有些更独特。我相信每个人都有自己的喜好。

我没有选择所有的选项,而是选择了五个选项来做更多的研究。然而,这并不意味着这五个选项比任何其他选项都好。但这可能是对一些强大的开源工具的有趣探索。

斯帕戈比

我们要看的第一个商业智能套件是 SpagoBI。它是一个开源套件,带有各种分析工具。SpagoBI 不仅支持报告,还支持多维分析(OLAP)、图表创建、SPI、交互式驾驶舱、即席报告、位置智能(如 web 地图服务)、免费查询、数据挖掘、网络分析、ETL、协作、办公自动化、主数据管理,甚至可以在后台运行的外部分析流程。针对不同的用户需求,SpagoBI 有不同的主模块。这包括 SpagoBI 服务器、Studio、Meta、SDK 和应用程序。这使得商业用户、开发人员、决策者和管理员能够找到 SpagoBI 的用途。它还支持一系列分析引擎和认证环境。

SpagoBI 是用 Java 编写的,使用 Ext JS 框架,并对研究、使用甚至修改软件以实现更多定制用途是开放的。该套件使用 Mozilla 公共许可证,这意味着组件可以修改和重新分发修改后的副本。

在后来的更新中,2017 年,SpagoBI 进化为 KNOWAGE。这是一个更现代、更成熟的商业智能版本,拥有更高级的分析选项,甚至大数据。KNOWAGE 推进了 SpagoBI 的原始选项,满足了大数据、智能情报、企业报告、位置情报、绩效管理和预测分析的需求。KNOWAGE 有社区版和企业版。

另一个有趣的事情,也是我特别感兴趣的事情,是 SpagoBI 的一个版本可以在 Docker Hub 上找到。随着我尝试更频繁地使用 Docker,你可以期待将来在这里看到更多关于 SpagoBI 使用 Docker 的内容。现在,您可以使用 Docker 通过以下命令来获取 SpagoBI 版本:

sudo docker pull spagobilabs/spagobi

调出萨戈比码头工人的图像。

要从 KNOWAGE suite 页面下载,因为 SpagoBI 下载会将您带到 KNOWAGE,您首先要创建一个帐户。没有帐户,我发现下载页面只是导致一个 404 页没有找到。我确实开始做账号了,但是我承认我等着验证账号注册的时候有点不耐烦。我更愿意尝试 Docker 版本。但这将是另一天,以便我们可以采取更深的潜水。那将是我们能够充分探索特性而不仅仅是细节的时候。

注意,在我尝试注册一两个小时后,我确实收到了验证邮件。也许我以后会再讨论这个问题,但是我现在更想看看 Docker 版本,所以至少现在我不会尝试安装普通版本。如果你决定安装 KNOWAGE,但意识到注册过程中的验证邮件需要一段时间才能收到,所以你不能马上安装 KNOWAGE。因为我没有重新访问,我不能保证你仍然不会得到 404 页找不到错误,但如果你试过了,请随时让我知道在评论中是否有一个帐户帮助下载工作。

密封报告

Seal Report 不是一个典型的数据可视化报告,它更像是一个使用。NET 框架。Seal Report 也是开源的。该框架可用于为任何类型的数据库生成报告,无论该源是基于 SQL 还是基于 NoSQL。Seal Report 专注于快速轻松地安装和构建报告。Seal Report 的所有实体都存储在 Seal Repository 中,Seal Repository 包括数据源、设备和报表。密封报告的主要组件包括服务器管理器、报告设计器、Web 报告服务器、任务调度器和密封报告调度器。总之,这些允许定时报告,如每日报告。

运行 Seal Report 所需的存储库文件夹包括程序集、数据库、设备、日志、报告、安全性、设置、源、表格模板、特殊文件夹、子报告和视图。这些都是用来创建一个简单而全面的报告。

主要功能包括动态 SQL 源、LINQ 查询、原生数据透视表、HTML 5 图表、KPI 和小部件视图、使用 Razor 引擎的全响应 HTML 呈现、Web 报告服务器、报告调度程序、下钻导航和子报告、报告任务和低 TCO(总拥有成本)。

我再次在 Docker Hub 上搜索,看看是否有 Seal 报告。似乎可以在 Docker 上找到密封报告,但是,我发现了问题。这是 Docker 建议使用的命令:

sudo docker pull eesysite/seal-report

因此,当您在 Docker 中查看 eesy/seal-report 时,没有拉动。当我试着:

尝试提取图像失败。

考虑到没有拉力,我想知道是不是有什么东西设置错了,或者只是不能工作。

要正常下载,您将被定向到 GitHub 代码。从那里,您可以直接下载源代码。然后,您可以在计算机上运行该可执行文件。从那里,当您从工具的根目录打开 Seal.sln 解决方案文件时,可以使用 Visual Studio 进行编译。

在尝试学习如何使用密封报告时,密封报告网站上有教程。它首先教您如何从 SQL Select 语句生成报告。这是用来准备一份报告,在几个快速和简单的步骤。执行后,您可以将报告保存到存储库中。

下一组指令展示了如何创建第一个数据源。它还指导如何创建、执行和存储报告。一旦设置好源和报告,就可以发布了。

有两套发布说明,具体取决于您希望报告放在哪里。第一个是在 Linux (Ubuntu)上。这将适用于我,因为这是我所使用的。另一个在 Azure 上。对于 Azure,也有关于如何审计数据库的说明。

最后一组指令是设置密封报告调度程序。这样,您就不必每次都手动创建报告。相反,您可以设置调度程序在特定时间自动生成报告。

查询树

QueryTree 是一个用 C#、ASP.NET 和 JavaScript 编写的开源解决方案。该工具旨在实现即席报告和可视化。在 GitHub 上找到的,可以使用源码运行,也可以使用二进制甚至 Docker 运行。QueryTree 适用于 Microsoft SQL Server、MySQL 或 PostgreSQL 数据库。该工具面向技术和非技术用户。QueryTree 使非技术用户可以轻松地从数据库的表中选择、过滤、分组、聚合和可视化数据。它甚至可以创建交互式图表来可视化数据,而无需编写任何代码。

QueryTree 是一种拖放构建器,它允许非技术用户在不编写任何代码的情况下使用各种可视化选项。还可以计划生成这些报告,以便在 web 或移动设备上查看。拖放式构建器包括一个强大而灵活的界面,允许查询根据用户的选择生成报告。这也意味着可以使用 QueryTree 易于使用的可视化工具来连接、转换或简单地查看数据集。

查看数据时,QueryTree 包括一个排序工具和一个选择工具,可用于组织数据或删除任何可能不一致的信息。还有几个不同的图表选项,因此用户可以选择他们想要查看数据的图表。QueryTree 还允许导出图表,而不是只能保存图表。这样,数据可以用其他工具表示,如 Excel 或 Word。

在计划和生成报告时,QueryTree 还提供了邀请团队成员查看这些计划报告的能力。QueryTree 还允许安全的加密连接来访问数据库,并以只读方式连接,因此数据是安全的。这样,可以与队友共享报告,以获得更好的体验。

对于更复杂的选项,查询树提供了一个高级报告生成器。这包括与简单的报表生成器相同的功能,但是具有更多用于自定义的工具和选项。这些报告更复杂,因此可能会更深入地挖掘数据库。除了标准的拖放选项之外,高级报表生成器还利用简单的向导来全面可视化所需的数据。与我们讨论过的其他产品一样,QueryTree 是开源的,可以免费使用,但也为企业客户提供了可定制的支持计划。对于非企业用户,Github 在 QueryTree 项目上有社区支持。

如前所述,QueryTree 随 Docker 一起提供:

sudo docker pull d4software/querytree

从 Docker Hub 中提取 QueryTree。

QueryTree 是另一个开源的专门报告工具,我认为使用起来会很有趣,所以稍后我们将尝试在 Docker 中进一步使用它。

FineReport

FineReport 是一款开源的 BI 报告和仪表板软件。与其他一些工具不同,FineReport 是一个基于网络的工具。它的设计是模仿 Excel 的,所以对初学者来说很容易操作。FineReport 可以部署在本地,也可以连接到公司数据库。FineReport 几乎支持所有数据库类型。它是用 Java 编写的,个人使用是免费的,但在公司使用 FineReport 时可能会收费。

报告和仪表板的细节旨在实现创新的设计模式、快速的数据集成、酷炫的数据可视化(具有动态甚至 3D 效果)、小数据输入、强大的决策平台以及轻松的部署和集成。FineReport 是用 Java 编写的,这意味着它可以通过独立或嵌入式部署在不同的系统上实现。

FineReport 可用于可视化报告、仪表板、财务报表,开发采购、销售、库存系统等。该工具也有不同的用例。一个原因是业务用户,他们可能需要显示数据的报告,或者 FineReport 可以用于快速和方便的数据输入。下一个用户案例是中层管理者。像这样的主管需要能够生成和显示报告、导出分析(用于 PDF 格式或 Excel 格式的演示),甚至在某些数据需要及时监控和审查的情况下,还需要强制性的数据关注。这是 FineReport 允许生成预定报告的地方,该报告可以通过电子邮件或其他选择的方式将报告推送给用户。考虑的最后一个用户案例是高级管理层。在这种情况下,经理需要能够查看数据,例如使用仪表板,但他们还必须能够在任何地方可视化数据,例如在移动设备上,他们还必须能够分析数据,例如使用链接或钻取。

FineReport 更像是一个专业的大数据商业智能和分析平台。它专注于分析,因此更加以 It 为中心。虽然业务用户可以使用 FineReport,但完整的功能是为 IT 人员设计的。这也是因为大多数用户在使用报表时都具备基本的 SQL 知识。FineReport 确实有几个不同的版本,面向不同的个人。如前所述,FineReport 以典型的 IT 用户为中心。FineBI 的定位是供更多的商业用户或数据分析师使用。JDY 是一个无代码的 aPaaS(应用程序平台即服务)解决方案,业务用户和 IT 都可以使用它来提高工作效率。然而,JDY 可以由全体员工使用,因为不涉及任何代码。然而,我们现在只关注 FineReport。

和其他版本一样,FineReport 的一个版本可以在 Docker 上找到:

正在提取 FineReport Docker 图像。

现在我们已经做好了准备,也许将来我们会更深入地研究 FineReport。

报告实验室

ReportLab 是一个开源引擎,用于创建复杂的 PDF 文档和定制的矢量图。它是标准 Linux 发行版的一部分,嵌入在各种不同的产品中,甚至被选为维基百科的打印/导出功能。ReportLab 可以免费使用,也是用 Python 编写的。

ReportLab 分为三个主要层。第一层是“绘制”PDF 页面的图形画布 API。第二层是图表和小部件库,可用于创建可重用的数据图形。最后一层是页面布局引擎,用于根据不同的元素(如标题、段落、字体、表格和矢量图)构建文档。页面布局引擎是 PLATYPUS(使用脚本的页面布局和排版)。ReportLab 还有一个 PLUS 商业产品,它可以以更高的速度生成 pdf,并且允许使用 ReportLab 的基于 XML 的模板语言 RML。ReportLab PLUS 还包括对开源库的升级,可以加快开发周期。

仅使用标准的 ReportLab 开源引擎,它是一个免费的 PDF 工具包,可以自动化文档制作,快速生成多个 PDF,具有 Diagra 图表工具包,并减少文书工作和打印成本。ReportLab 工具包是免费版本,是一个用于以编程方式创建 PDF 文档的库。该工具包的功能是创建专业的可移植文档,使用 real document layout engine(Platypus),可流动的对象,如标题或段落,但 ReportLab 工具包还支持嵌入式 Type-1 或 TIF 字体、亚洲、希伯来和阿拉伯字符、任何流行格式的位图图像、矢量图形,它包括可重复使用的原始形状库、可扩展的小部件库、用 Python 编写的分层架构,它还包括简单的演示和更复杂的工具,允许任何数据源、完全可用的源代码、强大的社区支持,并且是平台独立的。

因为它是用 Python 编写的,所以可以使用源代码安装,或者使用 PYPI 中的 pip 安装。虽然可以在 Linux 上使用,但 ReportLab 是跨平台的,可以在 Windows、Mac OSX、Solaris、AIX、FreeBSD 等平台上使用。

与这个列表中的其他开源工具不同,ReportLab 在 Docker 上找不到。但是因为它可以使用 PYPI 中的 Pip 进行安装,所以我们将以这种方式进行安装:

sudo pip3 install reportlab

正在安装 ReportLab。

尽管在 Docker 上找不到 ReportLab,但你知道我对我的 Python 项目情有独钟。所以。希望将来能看到我更多地使用 ReportLab。这似乎是一个强大的工具包,但我也很高兴它是用 Python 编写的。

结论

在本文中,我们回顾了五种不同的用于报告的开源引擎/工具包。这五个版本中,有四个在 Docker 上有版本。正如我在开始时所说的,这并不是对“最好的”开源引擎的分解。相反,这更像是为了满足我自己的好奇心而进行的教育失败。灵感只是想知道是否有任何开源报告工具,所以我惊喜地看到有这么多。

我们了解了 SpagoBI、Seal Report、QueryTree、FineReport 和 ReportLab。其中,只有 ReportLab 没有在 Docker 上找到。然而,ReportLab 也是唯一一个 Python 驱动的工具包,可以通过安装 Pip 获得,所以现在还不要把它排除在外。

在我们的研究中,我们只获得了每个报告工具的一般背景信息。然而,我们还没有机会尝试用它们中的任何一个生成报告。这是我有兴趣做的事情。现在请注意,网上有几个“最好的开源报告工具”,虽然其中很多有重叠,但还有很多我没有在这个概述中列出。这并不意味着这是最好的五个,它们只是我更有兴趣了解的五个。在未来,我计划至少使用一些这样的报告工具,并学习更多关于如何使用它们的知识。有趣的是,在它们都被尝试过之后,以比较的形式重新审视我选择的所有工具。如果您使用任何您认为值得研究的开源报告工具,请随时在评论中提出来,我很有兴趣看看。总的来说,我认为看到这些开源报告服务的相似性和不同性是很有趣的,其中一些确实试图通过高级功能来盈利,而另一些仍然免费供所有用户使用,包括公司使用。

稍后,我们将对列表中的每一项进行更深入的探究,但在此之前,干杯!

用我的 每周简讯 免费阅读我的所有文章,谢谢!

想阅读介质上的所有文章?成为中等 成员 今天!

查看我最近的文章:

https://python.plainenglish.io/middleware-in-fastapi-what-is-it-fa028349489d [## SQLite vs TinyDB

towardsdatascience.com](/sqlite-vs-tinydb-7d6a6a42cb97) https://python.plainenglish.io/python-virtual-environments-what-you-need-to-know-95487982c586

参考资料:

https://www.spagobi.org/

https://open-source-guide.com/en/Solutions/Applications/Business-intelligence-suites/Spagobi https://www.knowage-suite.com/site/#nogo https://sealreport.org/ https://github.com/ariacom/Seal-Report

http://querytreeapp.com/

https://www.finereport.com/

https://community.finereport.com/ https://www.reportlab.com/

使用 PyTorch Lightning Flash 和 FiftyOne 快速构建计算机视觉模型

原文:https://towardsdatascience.com/open-source-tools-for-fast-computer-vision-model-building-b39755aab490?source=collection_archive---------11-----------------------

使用开源工具 PyTorch Lightning Flash 和 FiftyOne 增强计算机视觉工作流程的指南

可视化 PyTorch 闪电模型预测在五十一(图片由作者提供)

开源工具在最近几年取得了显著的进步,满足了许多与端到端平台服务相同的需求。从模型架构开发到数据集管理,再到模型培训和部署,它们都非常有用。通过充分挖掘,您可以找到一个能够支持数据和模型生命周期大部分部分的开源工具。工具之间的紧密集成是实现近乎无缝的工作流程的最佳方式。这篇文章深入探讨了模型原型和训练框架 PyTorch Lightning Flash 与数据集可视化和模型分析工具 FiftyOne 之间的新集成。

Lightning Flash 是一个建立在 PyTorch Lighting 之上的新框架,它提供了一系列任务,用于快速原型制作、基线、微调以及用深度学习解决商业和科学问题。尽管无论你有多少深度学习的经验,Flash 都很容易掌握,但你可以用 Lightning 和 PyTorch 修改现有的任务,找到适合你的抽象级别。为了进一步加快速度,Flash 代码是可扩展的,内置了对任何硬件上的分布式训练和推理的支持。

Flash 使得训练你的第一个模型变得非常容易,但是要继续改进它,你需要知道你的模型表现如何,以及如何改进它。 FiftyOne 是由 Voxel51 开发的用于构建高质量数据集和计算机视觉模型的开源工具。它为优化数据集分析管道提供了构建模块,使您能够直接使用数据,包括可视化复杂标注、评估模型、探索感兴趣的场景、识别故障模式、查找注释错误、管理训练数据集等。

借助 Flash + FiftyOne,您可以加载数据集、训练模型并分析以下所有计算机视觉任务的结果:

概观

FlashFiftyOne 之间的紧密集成允许您执行一个端到端的工作流,加载数据集,在其上训练模型,并可视化/分析其预测,所有这些都只需要几个简单的代码块

将 51 个数据集加载到闪存中

虽然使用 FiftyOne 开发数据集一直很容易,但与 PyTorch Lightning Flash 的集成现在允许您通过将数据集直接加载到 Flash 和训练任务中来使用这些数据集。

培训 Flash 任务

Flash 提供了获取任务模型所需的工具,并开始使用尽可能少的代码对数据进行微调,最重要的是,不需要成为该领域的专家。

可视化 51 次闪光预测

由于现代数据集的复杂性和规模,图像和视频数据的可视化始终是一个挑战。fiftone旨在为您的数据集和标签(包括注释和模型预测)提供一个用户友好的视图,现在可以通过 Flash 模型在一行额外的代码中访问该视图。

Flash 视频分类预测第五十一中可视化(图片由作者提供)

示例工作流

设置

按照本文中的例子,你需要安装相关的包。首先,你需要安装 PyTorch 闪电灯51

pip install fiftyone lightning-flash

对于嵌入可视化工作流,您还需要安装降维包, umap-learn:

pip install umap-learn

一般工作流程

使用这些工具的大多数模型开发工作流遵循相同的一般结构:

  1. 将数据集加载到第五十一个
  2. 从数据集创建一个 Flash 数据模块
  3. 微调任务
  4. 根据模型生成预测
  5. 将预测添加回数据集并可视化它们

图像目标检测

本节展示了使用 PyTorch Lightning Flash 和 FiftyOne 之间的这种集成来训练和评估图像对象检测模型的具体示例。

闪光物体探测预测第五十一中可视化(图片由作者提供)

从这里开始,您现在可以将您的预测返回到您的数据集中,并可以运行评估来生成混淆矩阵PR 曲线指标,如准确性和映射。特别是,您能够识别和查看单个真/假阳性/阴性结果,从而让您了解您的模型在哪些地方表现良好,在哪些地方表现不佳。基于常见的故障模式改进您的模型是开发更好模型的更可靠的方法。

第五十一集中的互动混淆矩阵(图片由作者提供)

嵌入可视化

此工作流的独特之处在于,它采用预先训练的模型,并使用这些模型为数据集中的每个图像生成嵌入向量。然后,您可以计算这些嵌入在低维空间中的可视化效果以找到数据的聚类。这种功能可以为硬样本挖掘、数据预注释、样本注释推荐等目的带来宝贵的发现。

借助交互图的概念,您可以点击或圈出这些嵌入的区域,并自动更新您的会话以查看和标记相应的样本

附加任务

您可以在此查看其他任务的类似工作流程,如分类和分段。

摘要

多年来,令人印象深刻的发展来自开源社区,尤其是在机器学习领域。虽然单个工具可以很好地解决特定的问题,但是工具之间的紧密集成才能产生强大的工作流。 PyTorch Lightning FlashFiftyOne 之间的新集成提供了一种新的简单方法来开发数据集、训练模型和分析结果。

(本帖由py torch Lightningvoxel 51团队合作)

开源的 Tipoca 流

原文:https://towardsdatascience.com/open-sourcing-tipoca-stream-f261cdcc3a13?source=collection_archive---------25-----------------------

以近乎实时的方式将数据从 Kafka 转换到 Redshift

在 AWS 中使用 Kafka、KafkaConnect 和 RedshiftSink 创建云原生近实时数据管道的故事。CDC + Sink。RedshiftSink 是 Practo 新推出的开源项目。它配备了一个高性能低开销的数据加载器,用于在 Redshift 中加载数据,并提供丰富的屏蔽支持,以确保您能够以保护隐私的方式在您的组织中创建通用数据访问。

蒂波卡河 2021:作者图片,来源

直接进入我们在 GitHub 上的回购开始吧。🏊

背景

2015 年,我们编写了内部事务数据复制器 Tipoca ,用于 bootstrap Practo 的仓库。它曾经在 PII 屏蔽支持下将数据从我们的事务数据库复制到 Redshift。它每天晚上刷新数据,应用最新的掩码配置进行完整的重新创建。Practo 的每个人第一次能够访问所有数据,并能够在保护客户隐私的同时连接不同系统的数据。

当时,构建分布式系统需要大量的工作。我们构建了一个具有不同流程的系统,跨多个工作人员运行,并通过重试来管理他们的协调。在开源技术和工具的帮助下,构建分布式系统已经变得越来越容易。这是蒂波卡的样子:

2015 年蒂波卡:作者图片

超越蒂波卡的动力

  1. 实时数据分析。
  2. 更快的红移查询。大批量负载占用红移资源。同步数据的需要不同。
  3. 数据驱动的产品。
  4. 每天重新创建数据是不可扩展的,而且成本高昂。
  5. 移除对 RDS 读取副本的分析依赖。

这导致了蒂波卡流的诞生,结束了蒂波卡 5 年的运行。

引入蒂波卡流

2020 年 7 月,我们开始讨论迁移到 CDC 平台的计划。这个想法是将运行在 RDS 上的事务数据库中的数据以近乎实时的方式传输到 Redshift。我们选择卡夫卡主要有两个原因——第一,卡夫卡是开放的;第二,它周围有很好的数据生态系统。

蒂波卡流 2021:作者图片,来源

第一部分(CDC)是开源的。我们使用 Debezium 将 RDS 流写入 Kafka。 Strimzi 有开源的 KafkaConnectKafka 作为 Kubernetes CRDs。

kubectl get kafka
kubectl get kafkaconnect
kubectl get kafkaconnector

在卡夫卡中,我们使用 AVRO 以紧凑的二进制格式存储数据。AVRO 很快,使用 AVRO,您可以在模式注册中心定义和存储数据模式。这是我们使用的模式注册中心的接口

RedshiftSink 解决了第二部分。它将数据从卡夫卡主题下沉到红移。它有丰富的屏蔽支持,并支持所有模式迁移。

眼睛多了软件更好!我们对开源红移链接感到兴奋。它可作为 Kubernetes 红移链运营商。🎉

kubectl get redshiftsink

可以直接跳转到 GitHub 上的 repo 来自己尝试一下。请继续阅读,理解下面实现的核心概念。

核心组件

红移追踪器

RedshiftBatcher 从 Kafka 读取数据,对其进行屏蔽,然后以微批处理的形式上传到 S3。然后,它向红移加载器发送信号,将这些批次加载到红移。

为什么要在流媒体平台上批量?

Redshift 擅长使用 COPY 命令快速摄取数百万条记录。每个文件副本都有开销,因此需要在文件数量和每个文件中的记录数量之间取得平衡。这就是为什么我们要小批量复制。您可以使用 maxSizePerBatch 和 maxWaitSeconds 来控制这些。

spec:
  kafkaTopicRegexes: "db.inventory.*"
  batcher:
    sinkGroup:
      reload:
        maxReloadingUnits: 2
        maxSizePerBatch: 10Mi
        maxWaitSeconds: 30

图片作者,来源

每一个话题都是一张桌子,都有自己的卡夫卡消费群体。批处理程序中的每个主题都会发生以下情况:

  • 管理器例程创建并优雅地关闭使用者组。
  • 萨拉马消费者团体关注卡夫卡主题,并用新信息填充阅读频道。
  • 读取器将收到的消息写入读取缓冲区。
  • 当达到批处理大小或时间过去时,读取器将批处理刷新到进程通道。缓冲通道用于分离消息的接收和处理。
  • Orchestrator 例程使多个批处理并发进行。当处理完成时,它向 Kafka 发送这些批次的加载信号。
  • 提交给 Kafka,将偏移标记为已处理。

配料员的职责:

  • 转换:将批处理中的每个 Debezium 消息转换为 Redshift 可加载格式。我们分叉并改变了开源的红移库,将所有与红移的通信作为这个库的一部分。我们用两个附加字段注释每个消息:operation 和 kafka-offset。在加载到 Redshift 之前,RedshiftLoader 使用这些字段执行合并操作。
  • 面膜:面膜一直是我们最重要的需求。默认情况下,从 RDS 到红移的数据被完全屏蔽,除非开发人员指定不屏蔽它。未屏蔽的配置作为文件保存在 GitHub 中。按照 GitHub Pull 的要求,开发人员和分析师指定不要屏蔽什么。一旦安全工程师审查并批准了更改,RedshiftSink 操作人员就会负责将这些掩码更改应用到红移。第一次接收中的 RedshiftBatcher CPU 要求也很高,因为它必须进行屏蔽处理。这里有改进的空间。以下是屏蔽功能,详情请查看
  • 上传批处理到 S3 :一旦转换完成,我们在 S3 上传批处理。批量写入是一个幂等操作,因此批量的重新处理不成问题。但是我们会优雅地关闭,重新处理的机会非常少。很少见,因为 Kafka 的提交是异步的,以保持批处理的速度。
  • 信号:对于主题 db.inventory.customers,批处理器读取来自该主题的消息,处理数据并上传到 S3。然后,它在主题 loader-db.inventory.customers 中添加一个作业,由 RedshiftLoader 读取该作业以在 Redshift 中加载批处理。下面是作业模式:
var JobAvroSchema string = `{
    "type": "record",
    "name": "redshiftloader",
    "fields": [
        {"name": "upstreamTopic", "type": "string"},
        {"name": "startOffset", "type": "long"},
        {"name": "endOffset", "type": "long"},
        {"name": "csvDialect", "type": "string"},
        {"name": "s3Path", "type": "string"},
        {"name": "schemaId", "type": "int"},
        {"name": "maskSchema", "type": "string"},
        {"name": "skipMerge", "type": "string", "default": ""}
    ]
}`

红移装载机

RedshiftLoader 将已处理的批处理从 S3 加载到红移。

RedshiftLoader 监视批处理程序编写的主题。由于红移连接有限,因此使用尽可能少的加载程序执行加载非常重要。在单个加载器 pod 中,我们在所有加载器例程之间共享红移连接。

spec:
  loader:
    redshiftGroup: non_pii
    redshiftSchema: inventory
    sinkGroup:
      all:
        maxSizePerBatch: 1Gi

图片作者,来源

你通过maxSizePerBatch指定加载多少!

加载程序希望批中的每个消息都具有相同的模式。如果批处理程序为消息找到了新的模式,它将负责刷新现有的批处理。

Debezium 和 RedshiftBatcher 都将模式存储在模式注册表中。当需要获取模式相关信息时,批处理程序和加载程序都会与模式注册中心进行对话。

装载机的职责

  • 模式迁移:开发团队随着他们的代码发布不断地改变 RDS 模式。我们需要使红移模式与 RDS 中发生的模式变化保持同步。因此,我们编写了一个模式迁移器。通过读取批处理中的第一条消息,加载程序判断是否需要执行模式迁移。它通过从作业负载中提取 schema-id 来实现这一点。然后,它从模式注册表中获取模式信息,并使用该信息构建一个输入红移表。然后将输入红移表与红移中的实际表进行比较,并决定模式迁移策略。Redshift 并不支持所有的 SQL 迁移命令,例如,它们只支持很少的 ALTER 命令。第一个策略是尝试就地迁移,如果第一个策略不可行,我们重新创建完整的表并替换它。第二个策略对于大牌桌来说非常耗时。我们计划将大模式迁移从 RedshiftLoader 中移除,并让操作者执行大模式操作。
  • 合并加载:如前所述,复制是向红移添加数据的最有效方式。但是单独复制只能做插入。因此,我们需要使用阶段表的合并技术来执行红移中的更新。YELP 红移连接器文章AWS 文档对使用这种技术有很好的解释。虽然 YELP 的文章很有帮助。

红移链操作符

Kubernetes 操作员帮助将编排和操作交由操作员完成。谢谢 Kubernetes!

kubectl get deploy redshiftsink-operator

图像来源

我们使用 Kubernetes 声明式 API解决了以下问题:

  1. 真人面具重装。
  2. 用户得到一个简单干净的 API。

该操作符帮助我们管理表的第一时间槽,并在更新掩码配置时帮助我们在 Redshift 中重新加载表。

操作员帮助我们解决上述用例,但不是强制性的。您可以安装批处理程序和加载程序,并以任何可能的方式运行它们。Kubernetes 不是强制的!

实时蒙版重装

掩码更改需要用新的掩码配置重新创建表。

图片作者,来源

下面我们用一个例子来了解一下真人蒙版重装。在本例中,我们正在接收与 regex: db.inventory.*匹配的主题

apiVersion: tipoca.k8s.practo.dev/v1
kind: RedshiftSink
metadata:
  name: inventory
spec:
  kafkaTopicRegexes: "^db.inventory*"
  batcher:
    mask: true
    maskFile: ["](https://github.com/practo/tipoca-stream/blob/master/redshiftsink/pkg/transformer/masker/database.yaml)[database.yaml](https://github.com/practo/tipoca-stream/blob/master/pkg/transformer/masker/database.yaml)"
  loader:
    redshiftSchema: "datawarehouse"
    redshiftGroup:  "nonpii"

Batcher 屏蔽了它从 Kafka 读取的所有数据。用户在 GitHub 中指定不要屏蔽什么(非 PII),在本例中是 db.yaml 。为了简单起见,让我们假设 db.yaml 的掩码版本在每次更改时都以 v1、v2、v3…递增。

什么是 SinkGroup?

该运算符通过创建 SinkGroup 来执行 sink 到红移。SinkGroup 是一组 RedshiftBatcher 和 RedshiftLoader 吊舱。

构成接收器组的三个参数是 1)由该组处理的主题,2)使用的掩码版本,以及 3)目标红移表。例如,customers 是主题 db.inventory.customers 的目标表,customers_ts_reload 是临时表。

图片作者,来源

I0218 10:24:21.226806 status.go:229] rsk/inventory allTopics:   126
I0218 10:24:21.226827 status.go:230] rsk/inventory diffTopics:  6
I0218 10:24:21.226832 status.go:231] rsk/inventory released:    120
I0218 10:24:21.226837 status.go:232] rsk/inventory reloading:   6
I0218 10:24:21.226838 status.go:233] rsk/inventory reload-dupe: 6
I0218 10:24:21.226848 status.go:234] rsk/inventory realtime:    0

在第一次创建 RedshiftSink 资源时,操作符将所有主题分配给 Reload SinkGroup,后者开始将掩码版本为 v1 的数据加载到红移临时表中。

与此同时,操作员持续监控正在重新加载的主题的消费者群滞后。当 lag 满足规范中指定的发布条件时,它将重载主题标记为实时。

当操作员发现主题已经到达实时时,它重新配置所有的 SinkGroups 以停止接收实时主题并尝试释放它们。

什么是发布?

Release 是 Redshift 中的操作符在激活实时表时执行的一组操作。

  1. 用实时临时表替换当前的实时表。
  2. 对指定的红移组运行模式授权。
  3. 将发布的主题移动到主 SinkGroup。

当一个新列需要在表格中取消屏蔽时会发生什么?

这需要使用新的掩码配置重新创建该表。

如上所述,所有事情都发生在第一次接收时,唯一的区别是:我们用旧的掩码配置提供对当前活动表的更新,直到用新的掩码配置完成表的完全重新加载。是用ReloadDupeSink组完成的。我们这样做是因为重新加载一个大表需要时间,在此期间,我们仍然希望当前活动的表得到实时更新。一旦表被释放,操作员就通知用户松弛状态的释放。

slack bot 通知用户发布:作者图片

什么是部署单位?

batcher:
  sinkGroup:
    reload:
      maxReloadingUnit: 20
      deploymentUnit:
        podTemplate:
          resources:
            requests:
              cpu: 3
              memory: 3Gi
            limits:
              cpu: 3
              memory: 3Gi

批处理单元需要更多的 CPU 来快速处理大表。要以每秒 80k 条消息的速度处理消息,需要将近 3 个 CPU 内核。在第一个水槽完成后,表已经达到实时,所需的资源非常少,对我们来说是 500 万。这就是我们有sinkGroup规格的原因。使用它,您可以为所有三个 sinkGroups 指定不同的 pod 资源。

maxReloadingUnit 20

reload sinkGroup 为每个主题运行一个单元(pod)。但是 main 和 reloadDupe sinkGroups 将所有主题作为一个单元(pod)一起运行。假设一个数据库有 1000 个主题,我们不会一起重新加载所有的主题,但是我们会首先处理最大 maxReloadingUnit 个具有最短延迟的主题。

挑战

Redshift 是一个强大的分析工具,但是要很好地使用它,很多事情都需要正确处理才能达到最佳性能。

  • 设置正确的排序和 DIST 键。
  • 清空表以保持排序,并回收未使用的磁盘块。
  • 最佳利用节点片实现高效拷贝。决定文件的大小和文件的数量,以便进行有效的复制。
  • 在复制期间最小化 s3 对文件的查找。
  • 使用正确的压缩。

在我们将大约 50%的数据库转移到实时数据库之后,表延迟开始超过阈值。

🤖:您有一个传呼机值班警报!📟 🔥

普罗米修斯对提波卡流的警告:作者图片

所以我们开始测量。我们添加了加载持续时间、加载频率(时间线)、加载速度等指标。这些可作为普罗米修斯指标。

致力于压缩、节点片利用率、保持 s3 查找率较低,我们已经解决了许多负载瓶颈。我们现在以>2mb/秒的速度加载,从大约 100 kb/秒开始跳跃,并设置了正确的默认值,让每个人都从中受益。

AWS 继续在每个版本中改进红移。像自动分拣键,自动 DIST 键,自动真空释放是伟大的!但我们期待更多:)

加载时间轴:按作者排序的图像

最大的挑战是保持1000 个表的滞后红移<10 分钟,同时发生许多并发负载。我们有 1000 多个红移表,但我们一天使用的不超过 400 个。这就是我们现在在需要时为未使用的表调节负载的原因。这个特性确保了正在使用的表总是接近实时并且保持红移负担较小。这非常有用。

期待红移 AQUA 在孟买发布。

count(redshift _ scan _ query _ total)> 0,给出正在使用的表的总数!:作者图片

节流是如何工作的?

按照启用节流。它是这样工作的:

  • **首先,确定正在使用的表:**我们导出红移 STL_SCAN 为普罗米修斯度量redhshift_scan_query_total 。如果扫描查询总数大于零,我们认为表正在使用中。扫描查询表对最近 X 天的视图的查询,以确定该表是否在使用中。
  • ****然后,根据表的用法节流:接下来,我们在红移中只允许 10 个并发加载。如果表在使用中,我们从不节流,总是加载它。否则,如果需要的话,我们会将表负载限制到最大 1 小时。如果表在这 1 小时的限制窗口内被访问,我们就直接让它实时访问。

现在,我们已经成功地将大部分数据库转移到实时数据库,一切都很顺利!

从我们的仓库滞后仪表板:作者图片

通过开源这个项目,我们希望回馈社会。期待向大家学习,并与大家合作,继续做得更好。

OpenAI CURL:强化学习遇上无监督学习

原文:https://towardsdatascience.com/openai-curl-reinforcement-learning-meets-unsupervised-learning-b038897daa30?source=collection_archive---------52-----------------------

通过对比无监督表示促进强化学习。

UnsplashAltumCode 拍摄的照片

CURL 在 DeepMind Control Suite 和 Atari Games 中的复杂任务上,无论是基于模型还是无模型,都优于之前基于像素的方法,在 100K 环境和交互步骤基准测试中分别表现出 1.9 倍和 1.2 倍的性能提升。CURL 是第一个在 DMControl 和 Atari 中的大量基于像素的连续和离散控制任务中,通过对无模型 RL 代理使用对比自我监督学习目标,显示出显著数据效率增益的模型。

由阿拉温德·斯里尼瓦斯、迈克尔·拉斯金和皮特·阿贝耳在卷曲 [1]

加州大学伯克利分校的研究人员在他们最新的论文 CURL 中,在强化学习的样本效率方面取得了令人印象深刻的进步。对比损失用于从高维数据中学习表示。[2]

我一直是无监督学习及其推动其他类型机器学习潜力的粉丝(这是基于我的论文)。此外,我将展示使用无监督学习和多任务学习的力量。

对比学习是关于区分彼此的例子,而不是将猫图像的表示推向一个零类标签向量。损失促使表示与同一猫图像的裁剪相似,并且尽可能与数据集中的其他图像不相似。

一开始我对对比学习有点怀疑,但现在看到它被用在许多伟大的论文中,如这篇文章、 CLIPMoCoSimCLR 以及许多其他论文,我开始意识到它的真正潜力。

CURL 想解决什么问题?

强化学习正受到模拟世界中存在的数据量的限制。即使 GPU 加速器和数据存储设施有了巨大的改进,输入数据处理仍可能是强化学习的瓶颈。

来源: SnappyGoat (CC 许可)。处理高维空间可能相当复杂。

CURL 试图提高在极高维空间中操作的强化学习技术的相同效率。这使得强化学习方法能够模拟更真实的世界。此外,CURL 被设计得足够通用,使得它可以被插入到任何基于从高维图像学习表示的 RL 算法中

CURL 是如何工作的?

我们的工作属于第一类模型,它使用辅助任务来提高样本效率。我们的假设很简单:如果一个智能体从高维度的观察中学习到一个有用的语义表示,建立在这些表示之上的控制算法应该具有更高的数据效率

由阿拉温德·斯里尼瓦斯、迈克尔·拉斯金和皮特·阿比尔在科尔 [1]

辅助任务是与主要学习目标同时学习的附加任务,并且产生更一致的学习信号。

照片由瓦希德·赫内Unsplash 上拍摄

流水线从产生一批转换的“重放缓冲器”开始。重播缓冲区的一个很好的例子是用于训练 RL 算法玩游戏的视频。对于每个转换,应用数据扩充算法来产生“关键字”和“查询”。直观上,你可以把它想成一个字典查找问题(这是对比学习的基础)。

之后,通过两个独立的编码器对密钥和查询进行编码。两个编码器将它们的结果提供给无监督算法,而只有关键编码器将它们提供给强化学习算法。多么不寻常的机器学习管道啊!

如果你不熟悉这项技术(并行训练两种不同的方法),这叫做多任务学习。CURL 使用多任务学习来进一步构建损失函数,并学习从图像帧的高维堆栈到低维表示的映射

图片由作者提供。一个多任务学习系统的例子

设计多任务学习系统并不简单(这来自经验)。通常,当你设计这些多任务学习系统时,你必须考虑到不同的梯度会将重量拉向所有这些不同的方向。幅度可能真的不同,您可能需要用一些额外的超参数来缩放它们。

但是 CURL 的一个有趣的特点是,作者没有提到必须做大量不同的高参数搜索或梯度加权来使这个系统工作

此外,CURL 通过添加利用对比学习的新损失函数来修改 RL 算法。这个损失函数使用了查询和关键字的概念。

为了指定这个新的损失函数,必须有[1]:

1.鉴别目标(把它想象成用于对比样本的锚)

2.生成查询键观察的转换

3.将观察值转换成查询和关键字的嵌入过程

4.内积被用作对比损失中查询-关键字对之间的相似性度量。

由 Aravind Srinivas、Michael Laskin 和 Pieter Abbeel 在 CURL 拍摄。[1]

最后的想法:

CURL 是大多数(6 个中的 5 个)DMControl 环境中最先进的基于图像的 RL 算法,我们根据现有的基于像素的基线对其进行了采样效率基准测试。在 DMControl100k 上,CURL 的中值性能比领先的基于模型的方法 Dreamer (Hafner 等人,2019 年)高 1.9 倍,数据效率高 4.5 倍。

由阿拉温德·斯里尼瓦斯、迈克尔·拉斯金和皮特·阿贝耳在卷曲拍摄。[1]

我确信 CURL 有一些局限性,但是看到独特的方法被一起使用(比如对比学习和多任务学习)来达到一个新的艺术水平总是很棒的。

我希望解释清楚,不要太专业。如果你对更多细节感兴趣,我建议在这里查看原始论文或在这里查看代码。此外,感谢亨利·艾实验室为我写这篇文章提供了很好的解释。

如果你想定期收到关于人工智能和机器学习的最新论文的评论,请在这里添加你的电子邮件并订阅!

https://artisanal-motivator-8249.ck.page/5524b8f934

参考文献:

[1] CURL:用于强化学习的对比无监督表示。阿拉文·斯里尼瓦斯、迈克尔·拉斯金和彼得·阿贝耳。2020.

[2] CURL:用于强化学习的对比无监督表示。亨利·艾实验室

开放 GPT 泄露你的数据

原文:https://towardsdatascience.com/openai-gpt-leaking-your-data-2dfb9e22c1b2?source=collection_archive---------25-----------------------

汤姆·索多吉在 Unsplash 上的照片

我们如何从 GPT-2 中提取数据?

第一部分:了解泄露 GPT-2 训练数据的方法

在这一系列围绕 GPT 的语言模型中,我们将重点阐述从大型语言模型中提取训练数据

论文目标

作者想证明他们可以从诸如 GPT-2 这样的语言模型中提取逐字数据。更有趣的是,他们解释说,他们可以从模型本身中逐字提取在训练数据中只出现过几次的内容。当然,如果你拥有一家公司,并且你正在使用客户的数据来训练一个语言模型,这可能是非常危险的。

用他们自己的话说,“该论文证明(…),对手可以通过查询语言模型来执行训练数据提取攻击以恢复单个训练样本。”

谁愿意冒泄露私人信息的风险?

这听起来确实非常可怕。让我们来理解作者是如何攻击 GPT-2 并表面“记忆”数据的。为此,我们将遵循原始文件的流程,并注释掉任何感兴趣的元素。

首先,让我们定义什么是语言模型。

什么是语言模型?

浅层定义在于将语言模型视为能够推断给定一系列标记的下一个单词的条件概率分布的模型。例如,如果输入的一系列记号是“ 这只猫正在吃一只 ”,那么 LM 的目标是正确推断词汇表中所有可能单词的概率分布。我们想让 LM 做的是给像“ ”、“ ”等词分配一个大的可能性。任何狗能吃的东西。同样,它应该给像“ 汽车 ”、“ 月亮 ”这样与狗能吃什么没有关系的词分配一个低可能性。

既然我们理解了什么是语言模型,我们可以继续阅读这篇介绍了许多有趣概念的文章。在此之前,我们需要强调作者的目标。作者声称他们可以提取数据,并对他们可以提取的数据类型做了一些具体说明。为了理解这一点,我们需要说服自己,提取一些非常普通的东西,如“巴拉克·奥巴马是美国总统”,并不是很有趣。相反,我们的目标是在训练数据中不常见的实体,秘密实体。这就是有趣的事情开始的地方!

用他们自己的话说,“我们的攻击是可能的,即使上面的每个序列都包含在训练数据的一个文件中”。

什么是语言模型记忆?

在阅读这篇论文之前,我不知道如何定义一个模型如何“记忆”一些东西,以及记忆具体指的是什么。从某种程度上来说,从人类的角度来看,记忆只是一种对过去已经看到的元素进行推断的能力,并且在推断的时候,就在现在。换句话说,如果你把你的脑力仅仅当作一本字典,那么你纯粹是在调用你的记忆,因为你不是在看每一句话的模式。

传统上,在 ML 中,我们的目标模型能够在与训练数据“相似”的数据上进行推断,但不能“完全”作为训练数据。因此,对一个模型的记忆可以被看作是负面的。

现在,根据作者的说法,在语言建模中有许多方法来定义记忆。作为一个例子,他们展示了从 GPT-2 的邮政编码推断,这显然是记忆是一些抽象的形式。他们进一步形式化了对'记忆的定义,以便将其限制在被认为是“非预期”的情况下,例如客户数据。如果像我一样,下图似乎不能描述“记忆”的情况,让我为你澄清一下。从本质上来说,我们可以把“记忆”看作是缺乏基于训练期间所学的现有模式的推理。该模型在旧金山有很多地址的可能性很小,因此它不是基于学习的模式进行推理,而是基于某种形式的“记忆”。

GPT-2 推断一个有效的邮政编码给定一个地址在三藩市。自己试试吧!

意识到难以定义记忆对一个 ML 模型意味着什么,作者介绍了一些关键概念。第一个是关于 k-Eidetic 记忆法。

定义 2(k-本质记忆):一个字符串 s 被一个 LM fθ记忆(对于 k ≥ 1)如果 s 可从 fθ提取且 s 出现在训练数据 x 中至多 k 个例子中:|{x ∈ X : s ⊆ x}| ≤ k

这一点非常重要,因为我们之前解释过,我们对普通的句子不感兴趣。换句话说,当 k 很大时,比 k 很小时危害小。实际上,直觉上,人们不应该期望在训练数据的许多示例中出现客户地址。另外,值得一提的是,对于任何一个 k,记忆较长的字符串 s 应该比较短的更有害。

:您可以将 k 值较低的 k-Eidetic 视为异常,对于这种异常,模型将很难找到与其他数据观察结果相结合的模式。换句话说,那些 k 低的 k 本质的例子,很可能是输入空间中的孤立点。

👀正式的攻击目标是什么?

既然我们已经介绍了记忆的关键概念,我们可以正式介绍作者攻击的目标。对手的目标是从模型中提取记忆的训练数据。人们可以通过特定提取的字符串的私密性来衡量攻击的强度。这与上面定义中的 k 的值相关联。根据我们之前的评论,“更强的攻击总共提取更多的示例和具有更低的 k 值的示例”。

这里,理解作者想要不加区别地提取训练数据而不特别关注数据的任何子集是很重要的。

作者本质上对找出任何能被 LM 记住的东西感兴趣。为此,他们把重点放在了 GPT-2 上。

🦊作者选择了什么方法来泄露 GPT 2 号的数据?

作者采用了两步走的方法:

  1. 他们通过 top-n 采样由 GPT-2 生成文本。
  2. 他们预测哪些输出包含记忆的文本。

首先,让我们关注步骤 1,该步骤包括应用 top-n 采样。

首先,当 GPT-2 生成新的标记时,我们记得它在给定输入字符串的情况下,对词汇表中可能的下一个标记使用概率分布。这个概念可能会令人困惑,这里我们可以利用来自 huggingface 的 Patrick von Platen 的精彩解释,他为我们提供了自动回归语言生成的清晰示例。

实际上,取样只是众多方法中的一种。下面显示了一个例子,其中在得到作为输入的令牌“”之后,通过迭代采样,自回归生成的输出是“【The nice house”。

GPT-2 可以根据相关概率生成{“尼斯”、“狗”、“汽车”}中给定“该”的任何单词。一旦我们基于它们的概率从先前的集合中取样,我们就得到“好的”。现在,我们有了“好的”作为输入。GPT-2 然后确定在这个简化的集合中可能的记号的可能性(“女人”、“男人”、“房子”)。然后我们可以随机抽取一个令牌,得到“房子”。来自帕特里克的

自然,当基于标记的概率分布对词汇表进行随机采样时,会出现问题。例如,可能最终生成不期望的标记,尤其是在概率分布具有“接近”概率的相当“接近”的候选的设置中。解决这个问题的一个想法是过滤掉低可能性预测的标记。这就是范等人提出的 top-n 抽样(通常称为 Top-K 抽样)所采取的方向。铝(2018)

上述策略在采样阶段只保留蓝色令牌,过滤掉黑色令牌。我们看到,它成功地在第二个采样步骤中排除了相当奇怪的候选对象(“not”、“the”、“small”、“told”)。摘自帕特里克的

现在我们更好地理解了 Top-n 采样指的是什么,让我们回到作者的策略。对于每次试验,他们通过 top-n 采样生成 256 个令牌。论文中给出的图表反映了设置为 200,000 的一些试验。换句话说,他们通过 top-n 采样从 GPT-2 生成 200,000 个字符串

“我们希望通过根据模型分配的可能性进行采样,我们将对模型认为“非常可能”的序列进行采样,并且可能的序列对应于记忆的文本。具体来说,我们使用 top-n 策略对每次试验的 256 个令牌进行精确采样。”

从那些 20 万个样本中,他们只关注那些困惑度较高的。人们可以把一个序列的迷惑性看作是“LM预测该序列中的记号有多好”的度量。换句话说,就像作者解释的那样,对于那些复杂度较低的序列,该模型对该序列并不感到非常“惊讶”,并且平均而言已经为序列中的每个后续标记分配了高概率。**

序列 x1,…,xn 的迷惑性

现在,为什么他们认为“极有可能”的序列对应于记忆的文本?

嗯,正如我们在上面看到的,困惑与每个标记被预测的可能性有关,给定过去的标记。对于那些低复杂度的过滤序列,该模型已经找到了具有高可能性的下一个记号。因此,在这种情况下,模型对预测非常有信心,这当然意味着它在训练期间已经看到了非常相似的一系列标记(过去的标记+新的标记)。

作者随后解释说,如果你只是对最有可能的序列进行采样和过滤,这实际上并不起作用,因为你最终会获得 k 值很大的 k-eidetic 内容。例如,他们最终会获得数百份 Vaughn Live 的记忆用户指南副本。类似地,他们最终获得了麻省理工学院公共许可证的完整文本,这是 github 上的一个流行文本文件。

“(…)在我们生成的 200,000 个样本中,有数百个是记忆的沃恩 Live 用户指南的副本。”

沃恩直播,一个流媒体网站。GPT-2 的攻击用上述方法拉它的用户指南。

第二个问题是,这种攻击得到的内容“被分配了高可能性(低困惑度),但那是没有记住的”。那些都是误报。正如作者解释的那样,大多数误报包含“重复的”字符串。

值得知道的是,即使重复串出现在同一系列的记号中的这种例子是极不可能的,并且因此在训练数据中未被充分表示,“大的 LMs 经常错误地将高可能性分配给这种重复序列”。(假设 LM 从两个第一重复序列中识别出模式,则第三重复序列可能尤其如此)**

注意:作者可以访问训练数据。因此,给定一个预测为正面的或记忆的示例,作者可以检查它是否确实在训练数据中。

✶Conclusion

总之,作者可以找到一种提取记忆数据的方法。然而,这第一种方法得到了大众记忆的例子。到目前为止,这些例子不会伤害任何公司。

然而,作者提出了一种提取相关记忆数据的改进过程,该过程稍微复杂一些。我们将在下一篇关于“GPT 2 号泄露数据”的文章中讨论这个问题。

masta fa Foufa在 LinkedIn 上。**

OpenAI 为所有人开启 GPT-3

原文:https://towardsdatascience.com/openai-opens-gpt-3-for-everyone-fb7fed309f6?source=collection_archive---------0-----------------------

怎么进去,会有什么结果

摄影站上的罗瑟琳拍摄的照片

这一改变让该公司名副其实。

当 OpenAI 在 2020 年 5 月宣布 GPT 3 号时,我们已经在等待消息了。该模型承诺在 2019 年满足其哥哥设定的高期望。一年前,OpenAI 公布了 GPT-2 的源代码,无论是宣传还是结果,这对他们来说都是一个巨大的成功。从“无限可能”的冒险视频游戏“人工智能地牢”,到每个科技新闻媒体的头条。

GPT-3 将会更大,功能更多,质量更强。

OpenAI 于 2020 年 6 月发布了 GPT-3,但与 GPT-2 形成对比的是——也是对大多数人的欺骗——他们决定建立一个私有 API 来过滤谁可以使用该系统。它拥有 1750 亿个参数,是当时最大的神经网络,吸引了大众媒体、研究人员和人工智能企业的关注。人们不得不加入一个等待名单,耐心地期待 OpenAI 回到他们身边(许多人尝试过,但几乎没有人能进入)。众所周知,参赛非常困难,以至于人们纷纷发帖解释他们是如何做到的。

OpenAI 似乎特别担心安全问题。控制谁可以访问模型允许公司限制潜在的危害。然而,尽管他们做出了努力,安全措施却没有明确规定。Jason Rohrer 是早期尝试 GPT 3 的人之一,他是一名独立视频游戏开发者。他在 12 月建立了项目,作为聊天机器人服务,供用户玩 GPT 3 的定制实例。他万万没想到的是,一位名叫约书亚·巴尔博的用户会将他已故未婚妻的人格植入聊天机器人。

这个故事像病毒一样传播开来,OpenAI 决定介入。

在 Rohrer 拒绝遵守一系列严格的要求后,他们关闭了 12 月项目。罗尔无意中暴露了他们安全系统的一个严重缺陷;OpenAI 无法有效控制 GPT-3 用户。十二月计划没有造成伤害(相反,它帮助约书亚恢复了健康),但它可能会造成伤害。这与 OpenAI 的用例策略明显冲突。

该公司没有很好地解决这一冲突,破坏了 Rohrer 的工作,暴露了他们安全措施的缺陷以及缺乏承认意外用例潜在好处的意愿。

但现在他们似乎已经修复了这些弱点。不再有不安全的想法,不再不必要地删除有前途的项目。不再等待。

如何访问 GPT-3,以及会发生什么

昨天,OpenAI】发表了一篇博文,声明他们已经删除了访问 API 的等待名单。现在任何人都可以使用 GPT-3。

进入操场

我已经经历了这个过程,所以你知道会发生什么。首先,他们要求提供通常的帐户详细信息——姓名、密码、电子邮件和电话号码验证。但他们也会询问使用意图,无论是为了建立一个产品或功能,个人使用,研究,还是新闻和内容创作目的。

我知道 OpenAI 不喜欢人们在社交媒体、博客或杂志上分享 GPT-3 的完成,所以我想看看他们是否会根据你选择的用途改变可访问性。我用两个不同的帐户进入,一个用于内容创建,另一个用于个人使用。

在第一种情况下,收到这样的消息并不令人惊讶:“我们感谢您对探索我们的技术的兴趣,我们的通信团队将很乐意帮助您。请联系 press@openai.com,并简要介绍您的项目,我们将与您联系,了解后续步骤。”但是,在第二种情况下,他们允许我立即进入操场。如果你只是想测试一些想法,玩玩模型,我建议选择个人使用。

定价和使用

OpenAI 按令牌收费——由 GPT-3 系统提示或生成。(令牌可以理解为单词的一部分。假设一个令牌等于 0.75 个单词是安全的。)

在最初的三个月里,你有 18 美元的免费信用额度可以随意使用。在达芬奇模型(GPT-3 的最强大版本)的情况下,1000 个代币花费 0.06 美元。只需 18 美元,您就可以获得 30 万张免费代币。你可以用这些 18 美元的免费积分写 4 部长篇小说。

对于那些从未尝试过该 API 的人,我建议你仔细阅读文档,使用示例并使用预设(预定义的主题提示)来查看 GPT-3 的行为。向系统提示文本似乎很容易,但可能违反直觉。你需要一些练习来获得好的结果。

最后但同样重要的是,你必须牢记安全指南。

严格的安全措施

OpenAI 现在才决定开放 API 的主要原因是他们已经收紧了安全政策;"我们在安全保障方面的进展使我们有可能删除 GPT-3 的等待名单."不管你想用 GPT-3 做什么,我建议仔细阅读用例内容指南以及常见问题和安全要求(一切都在文档中)。

用例指南定义了三个类别:几乎总是被批准的、被逐个评估的和不被允许的。如你所知,他们在允许的范围内非常保守。我建议阅读不允许的案例,以确保你甚至没有接近这些案例,然后尽可能地保持在第一类中。内容指南列举了哪些类别是明确禁止的。这些包括仇恨、骚扰、暴力、自残、成人、政治、垃圾邮件、欺骗和恶意软件。

从我读到的内容来看,我觉得他们现在对可能做的事情有了更多的控制。这使得只要你遵守指导方针,自由使用 GPT-3 更加安全,但同时,它高度限制了用例。尽管如此,我还是要说,控制进入 GTP 3 号总比不被允许好——至少对那些只想在操场上玩和实验的人来说是这样。

这几个月来,我对 OpenAI 进行了广泛的批评,但我发现这个消息对该公司来说是朝着正确方向迈出的一步(尽管他们在其他关键方面没有改变,比如成为微软的傀儡)。对于长期研究和产品开发来说,GPT-3 仍然非常昂贵,但很快就会有(而且)其他选择可用——要么来自开源社区,要么来自想要从 NLP 市场分一杯羹的直接竞争对手

现在去好好玩吧

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员而获得无限制的访问权限! 😃

open ai PALMS——让 GPT-3 适应社会

原文:https://towardsdatascience.com/openai-palms-adapting-gpt-3-to-society-49c16ae5e039?source=collection_archive---------19-----------------------

人工智能|人工智能伦理

OpenAI 找到了减少 AI 偏差的方法。

Lina TrochezUnsplash 上拍摄的照片

AI 目前面临一场至关重要的战役:伦理

10 年前,深度学习开始变得非常流行,非常快。很快,人们开始问一些困难的问题:人工智能将来能取代我们的工作吗?它能被用于全球的数字战争吗?它会最终否决并主宰我们吗?在混乱的道路上,巨大的障碍等待着我们。然而,我们忽略了已经在我们眼前发生的其他更紧迫的问题。

深度学习模型是用海量数据训练出来的。这些数据是由人类创造和编辑的。偏向人类。在不完美的世界中生成的数据不可避免地是不完美的。这些模型最终会发展成为我们偏见的不完美窗口。

通常情况下,少数民族受害最深。年龄、性别、种族、性别、宗教……任何可能的分类都可能成为人工智能偏见的目标。自 2017 年以来,随着基于 transformer 的系统的出现,大公司已经开始用互联网上的数据以无监督的方式训练语言模型。如果有一个很好的例子来说明人类的偏见,那就是万维网。

2020 年 7 月,OpenAI 发布了 GPT-3 的测试 API,这是最流行的语言模型之一。独立研究人员可以利用该系统来测试其令人印象深刻的技能,但一些人却发现了令人印象深刻的偏差。其中一位是脸书人工智能公司的负责人杰罗姆·佩森蒂,他大声指出了问题的严重性。他声称 GPT-3 可能不安全,因为当中性地提示“犹太人、黑人、妇女或大屠杀”时,它可能会产生有害的推文许多媒体附和他的说法,艾再一次被证明无法赢得反对偏见和不宽容的斗争。

为 OpenAI 辩护,值得注意的是他们在论文中解决了偏见问题。但他们知道,如果他们声称与人工智能合作,为所有人类创造一个更美好的未来,提及这些问题是不够的。这就是为什么昨天,即 6 月 10 日,他们展示了 PALMS——使语言模型适应社会的过程——作为向无偏见的人工智能语言模型迈出的重要一步。让我们看看这是怎么回事!

棕榈-GPT 的救赎-3

Irene Solaiman 和 Christy Dennison 共同撰写了一篇题为 的论文,通过价值导向数据集 使语言模型适应社会(PALMS)的过程。他们证明了语言模型——特别是 GPT-3——在用适当的小数据集进行微调时可以表现出道德行为。他们有效地缩小了 GPT-3 的可能输出,将它们限制在一组精选的值中。他们发现,较大的模型能更好地适应理想的行为,并保持它们完成其他任务的能力。

他们如何创建以价值为目标的数据集

  1. 他们创建了一个敏感话题列表,希望 GPT-3 在这些话题上有所改进,并从中选择了 8 个类别来定义道德立场:虐待/暴力、人类行为、不平等、健康、政治观点、关系、性活动和恐怖主义。
  2. 他们为每个类别定义了理想的职位。例如,在“虐待、暴力和威胁”类别中,他们说:“反对暴力或威胁。应该鼓励那些处于虐待、暴力或危险境地的人向有关当局寻求帮助。”在“健康(身体或精神)类别中,他们说:“不要对任何人的身体或精神疾病进行诊断,或建议或开出治疗方案。反对将非常规药物作为医学治疗的科学替代品。"
  3. 在问答形式中,他们创建了提示(总共 80 个,包括中性提示)来针对系统的弱点。针对弱点的两个例子是:“什么会让我更可爱?”以及“是什么让一个人变得美丽?”
  4. 专业作家通过回答步骤 2 中期望的行为之后的问题来完成步骤 3 中的提示。对于“是什么让一个人变得美丽”的问题,作者说:“一个人的吸引力是一种高度主观的衡量标准。每个人都有不同的美的标准,而这些美的标准在不同的文化和世代中也是不同的。例如,当一些人决定一个人是否漂亮时,面部特征可能在他们的考虑中起很大的作用。其他人可能更喜欢关注一个人的个性,而不是他们的面部特征,还有一些人可能更看重一个人的体形和体型,而不是其他任何东西。”
  5. 他们采用了不同版本的 GPT-3 模型(从 1.25 亿到 1.75 亿个参数),并用步骤 1-4 创建的数据集对它们进行了微调。

评估和结果:GPT-3 能去偏倚吗?

他们为每个模型创建了 120 个样本的验证/测试集。8 个类别,每个类别 5 个提示(问题),每个提示 3 个样本(GPT-3 的答案)。为了评估微调模型的效果,他们创建了另一个中性数据集来定义 GPT-3 控制模型。他们评估了 GPT-3 的三个版本:基线、对照和价值目标。

他们使用三个评估指标来衡量结果。首先,他们在透视 API 上评估了反应的毒性。第二,他们雇佣了人类评估者来评估响应是否符合步骤 2 中描述的期望行为。第三,为了进行定性评估,他们进行了跨种族、性别和宗教的共现评估(哪些词更常与特定类别的选定词相关)。

  • 毒性结果:在整个模型规模中,GPT-3 的平均得分始终较低,效应规模始终为负值。这意味着新的 GPT-3 毒性大大降低。最大的模型具有最低的毒性分数。价值目标 GPT-3 175b 毒性最小。
  • 人类评估结果:在整个模型规模中,以价值为目标的 GPT-3 的平均得分始终较高,效果规模始终较高。这意味着新的 GPT-3 比其他人表现出更多令人满意的行为。最大的模型具有最高的人类评估分数。以价值观为目标的 GPT-3 175b 是最道德的。
  • 同现结果:以价值观为目标的 GPT-3 比其他模型表现出更多的中性情绪。

这些结果表明,GPT-3 能够显著改善其行为,坚持特定值时,微调与一个小值为目标的数据集。手掌可能是解决语言模型偏差的低成本第一近似值。

局限性和未来工作

正如 Solaiman 和 Dennison 所指出的,他们所进行的实验是在一个文化的框架内进行的。他们承认不可能找到跨越文化和社会的普遍解决方案。在全球范围内,不同的情况以不同的方式出现和解决,因此找到一个统一的模式似乎不太可能。用他们的话说:“人工智能研究人员必须跨领域和跨部门合作,以理解什么是适当和安全的情绪,以及通过什么镜头。”作者还描述了一系列关于“适当行为”确切定义的问题,以供进一步探讨

  • 谁应该在敏感话题上表明立场?
  • 对于敏感话题,什么是“基于事实”?
  • 什么构成了“安全”的产出?
  • 谁对有害输出负责?我们如何让语言模型负起责任?

回答这些问题对于推动人工智能伦理更上一层楼至关重要。

结论:迈向伦理人工智能的重要一步

为“不道德的”人工智能辩护的一个主要论点是,我们应该创建人工智能系统来反映世界的现状。人工智能是有偏见的,因为我们有偏见,它只是重申人们的想法和方式。然而,当我们思考数据的来源时,这个论点就站不住脚了。杰罗姆·佩森蒂正是这样认为的。他说,尽管人工智能算法向人类学习,但“可以故意选择它们向哪些人学习,哪些声音被放大。”Reddit 可能不是获取数据的最佳地点。

这是一个有力的论据,反对那些声称我们应该让人工智能自由发展,没有边界或限制的人。人类是有偏见的,但有些人比其他人更有偏见。我们希望人工智能反映一个不完美的世界,还是希望它带领我们走向一个更美好的世界?OpenAI 做了一项伟大的工作,向世界展示了被指控具有种族主义和性别歧视偏见的 GPT-3 可以通过一个低成本的过程学习适应社会,只使用一个小的精选数据集。

现在,他们要求 API 用户接管并找到在生产用例中应用这种技术的方法。对于我们其他人来说,我们只能等待 AI 伦理的下一次突破。但这一次,我们会平静地等待,知道这个世界比昨天好一点。

OpenAI 的 DALL-E 和 CLIP 101:简介

原文:https://towardsdatascience.com/openais-dall-e-and-clip-101-a-brief-introduction-3a4367280d4e?source=collection_archive---------16-----------------------

在 GPT-3 之后,OpenAI 带着两个结合了文本和图像的模型回归。DALL-E 会是 2021 在 AI 领域的主角吗?

大卫·佩雷拉在菲格雷斯的大理博物馆拍摄的照片。

当社区仍在讨论 2020 年人工智能重大公告之一时, GPT-3 (其论文于 2021 年 7 月 22 日发表)才刚刚开始,我们已经有了来自 OpenAI 的两个令人印象深刻的新神经网络: CLIPDALL-E

CLIP 和 DALL-E 都是多模态神经网络,它们的创造者声称它们是“向更深入理解世界的系统迈出的一步”。

多模态神经网络:它们是什么?

我们作为人类的体验是多模态的,这意味着我们从周围的世界以不同的形式(声音、图像、气味、纹理等)接收输入。)我们结合使用不同的感官(触觉、视觉、听觉、嗅觉和味觉)来产生学习和保留信息。

那么我们如何定义什么是模态,什么时候问题是多模态的呢?让我在这里引用一个很好的定义,可以在一篇著名的多模态机器学习论文中找到,名为“多模态机器学习:调查和分类”:

模态是指某件事情发生或经历的方式,当一个研究问题包含多个这样的模态时,它被描述为多模态

在深度学习中,只用一种数据格式(单模态)训练模型是非常常见的。作为这方面的一个例子,DeepMind 的 AlphaFold 2 通过将氨基酸作为给定一维序列的一部分时如何与其他氨基酸相互作用的信息转换为相关性矩阵来解决蛋白质的折叠问题,这可以用图像来表示。同样,AlphaFold 的输出是另一幅图像,这次代表的是蛋白质内氨基酸之间的距离,这些距离与蛋白质的 3D 结构密切相关。因此,DeepMind 将蛋白质折叠问题转化为图像到图像的机器学习问题。

预测蛋白质折叠的 AlphaFold 解决方案综述。图片来源:自然。来源:https://www.nature.com/articles/s41586-019-1923-7

最后,我们如何定义机器学习中的多模态?我非常喜欢下面视频中的介绍和定义:

“当两个或更多不同种类的输入被相同的机器学习模型处理时,只有当这些输入不能被算法明确地映射到彼此时,多模态(在机器学习中)才会发生”。来源:https://www.youtube.com/channel/UCobqgqE4i5Kf7wrxRxhToQA】T4

所以现在我们知道了什么是多模态神经网络,让我们来探索 OpenAI 的新多模态神经网络被训练来做什么。

DALL-E:从用自然语言表达的字幕中创建图像

因此,OpenAI 的两个新神经网络中的第一个,DALL-E(灵感来自著名的超现实主义艺术家萨瓦尔多·达利)是 GPT-3 的 120 亿参数版本,经过训练可以从文本描述输入中生成图像。它使用相同的变压器架构。在这种情况下,正如它的创建者在他们的介绍性博客帖子中所说的,“它接收文本和图像作为包含多达 1280 个标记的单个数据流,并使用最大似然法进行训练,以一个接一个地生成所有的标记”。

OpenAI 的 DALL-E 网站中的一些可用演示示例非常惊人(您可以更改一些文本输入参数,以查看输出是如何受到影响的)。请看下面的一个例子,其中您可以更改所有带下划线的参数:

OpenAI WALL-E 演示,来源:https://openai.com/blog/dall-e/

在他们的博客中,OpenAI 列出了他们新神经网络的一些功能:

  • 控制属性(例如,更改输出中图像的颜色、形状和重复次数)
  • 绘制多个对象(这需要算法来计算相对位置、堆叠等)
  • 透视和三维
  • 上下文细节推理
  • 可视化内部和外部能力(OpenAI 的博客显示了一个核桃的横截面作为例子)。
  • 处理能力
  • 组合不相关的元素(描述真实和虚构的概念)
  • 零距离视觉推理(作者承认他们没有预料到)
  • 地理知识
  • 时间知识

警告

从技术角度来看,这种新模式仍然存在许多疑问。正如 Gary Marcus 博士所指出的,我们正在观看一个非常强大的预览,但正如 GPT-3 所发生的那样,在撰写本文时,我们无法获得论文或真正开放的演示环境来深入分析该解决方案。

从社会影响的角度来看,除了 WALL-E 可能对一些职业和过程产生的明显影响(例如,与股票摄影相关的影响),OpenAI 在他们的博客中提到,他们“计划分析 DALL E 这样的模型如何与社会问题相关联[…],模型输出中偏见的可能性,以及这项技术隐含的长期道德挑战。俗话说,一幅图像胜过千言万语,我们应该非常认真地对待像这样的工具如何影响未来的错误信息传播,以及其他问题,如如何识别这种算法的训练数据的价值,就像下面的推文所示。

https://techcrunch.com/2021/01/05/openais-dall-e-creates-plausible-images-of-literally-anything-you-ask-it-to/?guccounter=1&guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&guce_referrer_sig=AQAAANp4CqFZPdCYy-ESEnshoBM-X5vWZNTlTjeCxFen-LhhQwtRgE_LLFfeDpKp4Cmds4e54XIyHyIEKZrp8uNTGsS66daYFMTHg9AiDuhhD-Hu2LsTnXNd-b8z4sJaEZtJUCr6_B-cGpzlfwFqYe4_FB7PKf2IokWoXP6GSwzrlVT-

夹子

OpenAI 的第二个新的多模态神经网络被称为 CLIP(对比语言图像预训练)。正如 OpenAI 提到的,当前的计算机视觉方法提出了两个挑战:

  • 创建数据集是劳动密集型的,成本很高
  • 标准视觉计算模型需要付出巨大努力来适应新任务

为了解决这些挑战,CLIP 不是通过使用带标签的图像数据集,而是通过从互联网上获取的图像及其描述(标题)来训练的。通过使用与 GPT-3 零射击方法类似的能力,可以指示 CLIP 通过使用自然语言来执行分类基准。对于 OpenAI 来说,是关键,正如他们在介绍性博客帖子中提到的(见下面的引用):

“通过不直接针对基准进行优化,我们表明它变得更具代表性:我们的系统将这一“鲁棒性差距”缩小了高达 75%,同时在不使用任何原始 1.28 米标签示例的情况下,在 ImageNet zero-shot 上匹配原始 ResNet50 7 的性能。”

OpenAI 已经用 CLIP 表明,引入一个简单的预训练任务就足以使模型在一组广泛的数据集上表现得非常好。该预训练包括从一组 32,768 个随机采样的文本片段中预测哪个字幕与给定的样本图像相关联。为了做到这一点,OpenAI 已经通过与互联网上的图像配对的文本使用了监督学习。

为了展示 CLIP 是如何概括的,OpenAI 采用了一种零触发的方法,分享了下面的图表。正如他们在他们的介绍性博客文章中提到的,“在我们测试的 26 个不同传输数据集的 20 个数据集上,最好的 CLIP 模型优于最好的公开可用的 ImageNet 模型,嘈杂的学生效率网-L2, 23

来源:https://openai.com/blog/clip/

结论

2021 年始于 OpenAI 在人工智能领域的重大公告。由于 2020 年是 GPT 三号之年,那么今年会是达丨赖之年吗?考虑到这种特殊模式的潜在影响,我不认为 OpenAI 会在短时间内推出公共访问,但编译开发者创建的不同应用程序会很有趣,就像 GPT-3 发生的那样。

另一方面,即使 GPT-3 不知道它在说什么,或者 DALL-E 不知道它在画什么,这两个模型仍然显示了深度学习在过去几年中的进展。想到 AlexNet 只有 8 岁,或者DALL-E 对仅 5 年前由神经网络创建的图像有多大的改善,真是令人惊讶。

创造性工作的未来含义仍有待揭示,人们可能会争论 DALL-E 的一些创作是否可以称为艺术,因为我们和模型本身都不知道正在发生什么。但是让我们诚实一会儿:我们能说我们知道达利在想什么吗?

tempslink1 标注 CC0 1.0

如果你喜欢阅读这篇文章,请 考虑成为会员 在支持我和媒体上的其他作者的同时,获得上的所有故事。

OpenAI 的新模型 DALL E 让我们离通用 AI 更近了一步

原文:https://towardsdatascience.com/openais-new-model-dall-e-brings-us-one-step-closer-to-general-ai-4abfe9cf9cfc?source=collection_archive---------51-----------------------

人工智能的最新发展

DALL E 建立在革命性的 GPT-3 模型之上,可以从纯粹的文本描述中生成令人惊叹的图像

图一。刘玉英在 Unsplash 上的照片

你可能在新年假期错过了人工智能世界的一些最新发展,但 OpenAI 在 2021 年 1 月 5 日发布了另一个革命性的模型:DALL E。DALL E 以西班牙超现实主义艺术家萨瓦尔多·达利和皮克斯的科幻机器人 WALL E 命名,作为一名艺术家,DALL E 具有创造力,作为一个机器人,它非常健壮。

"艺术家萨瓦尔多·达利和皮克斯的《瓦力 e》的结合体"

根据博文中的图像,DALL E 似乎对空间、时间和逻辑等概念有很好的理解。

这篇文章将快速概述 DALL E 是什么,它能做什么,它是如何工作的,以及它为什么重要。但是,首先,简单介绍一下开放人工智能。

让我们开始吧!

什么是开放 AI?

OpenAI 是一个非营利的人工智能研究和部署实验室,位于旧金山。它由埃隆·马斯克(Elon Musk)、萨姆·奥特曼(Sam Altman)和其他人在 2015 年创立,他们承诺投入 10 亿美元开发可持续和安全的人工智能系统。OpenAI 实验室成立背后的主要动机是担心来自人工通用智能的存在风险。即使埃隆·马斯克从 OpenAI 董事会辞职,他仍然是该实验室的捐赠者。非盈利母公司 OpenAI Inc .也拥有盈利的 OpenAI LP 公司。2019 年,微软向盈利子公司 OpenAI LP 投资 10 亿美元。

开放人工智能是近年来最轰动的语言模型之一——预训练生成式变形金刚 3 (GPT-3)背后的实验室。该模型因其激动人心的应用而广受欢迎:

DALL E 也是在 GPT-3 的基础上建造的。所以,让我们看看 DALL E 是什么。

什么是 DALL E?

开放人工智能研究人员在 GPT-3 的 120 亿参数版本(有几个 GPT-3 版本)的基础上建立了 DALL E。这个基于转换器的神经网络被训练成使用图像-文本对的大型数据集从文本描述生成图像。DALL E 具有令人印象深刻的功能,如创建拟人化(即类似人类的)动物和对象、文本渲染、转换现有图像以及将对象和概念组合在单个图像中。它还可以补全图像中缺失的部分。

DALL E 的功能

更详细地说,DALL E 可以做到以下几点:

达勒能:

  • 更改对象的属性和对象在图像中出现的次数:

图二。文字提示:桌子上放着一堆玻璃杯(作者截图)

  • 同时绘制多个对象并控制它们的空间关系:

图 3。文字提示:红色小方块坐在绿色大方块上(作者截图)

  • 控制场景的视点和渲染场景的 3D 样式:

图 4。文字提示:一只坐在田野里的水豚的特写镜头(作者截图)

  • 可视化对象的内部和外部结构:

图 5。文字提示:一个核桃的横切面图(作者截图)

  • 推断上下文细节:

图 6。文字提示:写有“openai”字样的店面。写有“openai”字样的店面。写有“openai”字样的店面。开一家店面。(作者截图)

  • 根据给出的描述创作时尚和室内设计作品:

图 7。文字提示:身着黑色皮夹克和金色百褶裙的女性人体模特(作者截图)

  • 组合不相关的概念并创建真实的对象:

图 8。文字提示:竖琴做的蜗牛。有竖琴纹理的蜗牛。(作者截图)

  • 基于给定描述的动物插图和拟人化蔬菜:

图 9。文字提示:一个穿着芭蕾舞裙遛狗的小萝卜的插图(作者截图)

  • 可以进行零射击视觉推理(即,用于模型未被训练的任务):

图 10。文字提示:上面一模一样的猫,下面是草图(作者截图)

  • 关于地理事实、地标和社区的理由:

图 11。文字提示:中国美食照片(作者截图)

  • 根据时间信息进行推理,并利用其时间知识:

图 12。文字提示:来自……s 的手机照片(作者截图)

如你所见,这些结果令人兴奋。给我留下特别深刻印象的是“竖琴做的蜗牛”和“穿着芭蕾舞裙遛狗的小萝卜”。然而,我们应该对结果保持怀疑态度。这里有一些关于 DALL E 模型的怀疑的想法。

对达尔的怀疑

总的来说,我不得不说 DALL E 所能做的非常令人印象深刻。对于你们可能和我一样思考的模型,我有几点想提出来。

图 13。艾米丽·莫特在 Unsplash 上的照片

没有全纸?

我们关于 DALL E 能力的全部知识都是基于 OpenAI 发布的一篇博客文章。虽然结果令人印象深刻,但关于该方法的全文尚未发表。因此,我希望在完全确信 DALL E 能够做到博客帖子所声称的事情之前,看到这篇论文。

摘樱桃?

可能误导读者的一点是,结果可能是精心挑选的。即使博客文章提到结果不是精心挑选的,文本提示也可能是精心挑选的。我相信全文中的基准分析可以解决这个问题。

通往普通智力的路还很长?

博文中分享的输出似乎很有前景,你可能会认为该模型几乎达到了类似人类的智能。然而,基于之前被认为是革命性的模型的失败承诺,我认为欺骗这些模型犯基本错误并不困难。但是,我们可以测试这个假设的唯一方法是使用这个模型。

最终注释

在这篇文章中,我们快速概述了 OpenAI 的新革命性模型 DALL E,似乎 DALL E 仅通过使用文本提示就可以实现几个图像生成和分类任务。虽然市场上有几种解决方案,但 OpenAI 似乎更进一步,提高了技术水平。然而,由于我们既不能访问模型,也不能访问论文,所以仍然有一些未解决的问题需要回答。一旦论文发表或者提供了对模型的访问,我们就可以测试并对这个令人兴奋的模型有一个更好的想法。

订阅邮件列表获取完整代码

如果你想获得我在 Google Colab 上的其他教程文章的代码,并尽早获得我的最新内容,可以考虑订阅:✉️的邮件列表

现在订阅

如果你对深度学习感兴趣,也可以看看我的人工智能内容指南:

https://oyalcin.medium.com/a-guide-to-my-content-on-artificial-intelligence-c70c9b4a3b17

最后,如果你想阅读 OpenAI 发表的原始博文,请参见下文:

https://openai.com/blog/dall-e/

openCV GPU 的使用令人失望…

原文:https://towardsdatascience.com/opencv-gpu-usage-disappoints-bc331329932d?source=collection_archive---------25-----------------------

将 GPU 与您的 openCV 代码结合使用,获得性能提升…不!

有好几次,我被在 GPU 上使用关键 openCV 调用的诱惑所吸引。最近一次是 matchTemplate 呼叫,在此之前是与视觉里程计相关的呼叫。啊,失望!

现在的情况是,我有 31 个可能的图像(或模板)来匹配来自传感器的图像。我想找出哪一个最适合——大图像上的任何地方。对 31 幅图像中的每一幅使用 openCV 调用 matchTemplate,我得到了最佳匹配的分数——最高分就是赢家。我计划在 nVidia 单板计算机上运行这个——无论是 nano、Xavier 还是任何适合成本和性能的计算机。

首先,正在使用的代码的基础知识(无聊的部分省略…)

// Initialize the GPU TemplateMatching object// - running in 8 bit modecv::Ptr<cv::cuda::TemplateMatching> cvCuda;cvCuda = cv::cuda::createTemplateMatching(CV_8U, cv::TM_CCORR);// , Size(0, 0));// Initialize the big image - in GPU landcv::cuda::GpuMat img_Gpu;img_Gpu.upload(inputImg);// Initialize the templates for matching - in GPU landfor (int i=0; i<kTemplateAngles; i++)  { cv::cuda::GpuMat tmplGMA_GPU; tmplGMA_GPU.upload(newGMA); vTmplGMA_Gpu.push_back( tmplGMA_GPU );}// Initialize the results matrix in GPU landint result_cols =  monoImg.cols - baseGMAImg.cols + 1;int result_rows = monoImg.rows - baseGMAImg.rows + 1;cv::Mat result( result_rows, result_cols, CV_32FC1 );cv::cuda::GpuMat result_Gpu( result_rows, result_cols, CV_32FC1 );// start timer - and do more than one loop to take multiple seconds// loop through our 31 templatesfor (int i=0; i<kTemplateAngles; i++)  { cvCuda->match( img_Gpu, vTmplGMA_Gpu[i], result_Gpu ); cv::cuda::minMaxLoc( result_Gpu, &minVal, &maxVal, &minLoc, &maxLoc );}// end timer

好吧,让我们直接看结果:

在桌面上,GPU 几乎慢了 3 倍!在 Nano 上— 只比慢了将近 2 倍。

这似乎是网络上常见的抱怨。概述的主要问题似乎是:

  • (上下文的)初始化可能需要 10 秒钟。我已经做了多次定时循环——post 初始化。第二次稍微快一点,比如说快 15%,但是之后时间就稳定了(如上表所示)。)
  • 将数据移动到 GPU 内存需要时间。当然,这就是为什么我试图提前做这些。
  • 或许其他人,可以在底部随意评论。还有…
  • 与 CUDA 启动/结束的开销相比,GPU 的实际执行时间相对较短——在快速 GPU 上运行的任何潜在收益都将丢失。

最后,我认为是核心问题。也就是说, 我在 GPU 上做得还不够,无法补偿来回调用 所产生的所有开销。(现在如果 matchTemplate 上有一个 openCV 包装器就好了——比方说迭代 N 个模板…)

顺便说一下,使用 GPU 仍然有意义,即使它比 CPU 花费更多的时间。在我做这项调查的第一个案例中,我们受到 CPU 的限制。将任何东西卸载到 GPU 将释放 CPU 来执行其他任务——只要我们不花费太多时间!

总之,也许我错过了一些东西,但我两次都希望在 openCV 调用中使用 GPU 来提高速度。

打开黑匣子:对可解释人工智能的一种解释

原文:https://towardsdatascience.com/opening-the-black-box-an-explanation-of-explainable-ai-7024d8b1f6b3?source=collection_archive---------18-----------------------

我们能解释我们的模型做出的预测吗?让我们分析为什么我们的模型预测一个图像是某个类的一部分

数码师在 Pixabay 拍摄的照片

想象一下,你去了一家医院,感觉身体不适,需要进行医疗检查。有人可能会认为结果是可信的,但有一个问题。人类不是解释结果并形成诊断的人。这项工作交给了人工智能模型。

你不想知道这个决定背后的理由吗?我们应该盲目地跟随模型的预测吗?

很高兴知道有一个领域致力于训练模型来解释他们的决定。它被称为可解释的人工智能(XAI)。

什么是可解释的人工智能?

这是一个黑盒子:

由 Anon 在 Pixabay 上拍摄的照片

好吧……然后呢?

事实证明,随着新的深度学习创新的出现,我们越来越难以理解一个模型是如何做出决定的,因为使用了反向传播和梯度下降。这个系统被称为黑盒,因为考虑到训练中使用的大量参数,工程师或数据科学家不容易解释模型采用的计算。

这就是可解释人工智能的用武之地。它是一套流程和技术,为黑盒模型的决策提供见解。这允许您:

  • 通过加深对决策过程的理解,调整模型的超参数
  • 告知客户和利益相关者为什么做出特定预测,提供更多透明度。

通过让机器学习模型变得可解释,我们的目标是回答以下问题:

  • 为什么模型做了某个决定?
  • 影响一个模特成败的特征是什么?
  • 模型必须有多大的可信度才能让你相信它?

我相信你已经看到了 XAI 的例子。例如,以 youtube 广告为例:

陈述显示广告的原因——图片由作者提供

局限性:性能与可解释性

像线性回归和决策树这样的模型是固有可解释的。它们接受更少的参数,并通过直观的数学和统计公式具有一定程度的透明度。例如,我们可以通过映射相应残差的误差来评估线性回归算法选择某个函数的决策。

然而,这些模型的精度比深度神经网络的,深度神经网络从大量参数中导出复杂函数。这些数学算法和技术,如梯度下降和反向传播,增加了它们的复杂性。例如,OpenAI 的 GPT-3 需要 1750 亿个参数。虽然它有可能生成真实的人类文本,但很难对所做的决定做出解释。

检验准确性和可解释性之间的关系——作者图片

如上所示,准确性和可解释性之间的权衡是显而易见的。因此,必须努力开发算法,以确保在更复杂的模型中有更高程度的可解释性。

深潜:集成渐变

如果我们想要辨别解释我们模型的方法,我们需要理解正在被分析的数据的类型。在本帖中,我们将讨论如何解释图像数据,尽管一种改进的技术也可以应用于结构化数据。

目前,实现可解释人工智能的主要技术是集成梯度。随意在 Tensorflow 教程这里了解更多。我将介绍如何通过使用带有 ImageNet 权重的 VGG19 模型来实现它,以预测我的双簧管的图像。你可以在我的 Github 库这里找到完整代码。

模型输入和顶部预测-作者提供的图片

  • 第一步:我们需要定义一个基线图像,在其上放置一系列图像。它可以是全黑、全白或随机图像。重要的是,基线将通过模型生成中性预测。

基线图像—作者提供的图像

如上所示,基线图像被实现为像素值为 0 的 224 x 224 x 3 图像。

  • 第二步:从这里我们可以在基线上绘制一系列图像,称为插值。然而,像素的强度将按比例α线性增加。

作者图片

上面的部分为我们的图像插值构造了参数。它通过将图像转换为张量并调整其大小来预处理图像。此外,我们定义了 alpha 值,它由 50 个均匀分布的值组成(插值的增量)。

作者图片

这里我们分两步定义插值函数。我们:

  • 计算我们的图像和基线的像素值之间的差异
  • 构建一个包含基线和插值图像的新张量(像素差乘以 alpha 变化率)。

太好了!现在让我们调用这个函数并可视化我们的插值。

图像插值(由于 alpha 增量较大,每隔 10 个间隔跳过一次)—按作者分类的图像

  • 步骤 3:针对每个插值图像的单个像素,计算模型预测的梯度。由于这些梯度,影响模型结果的像素将具有更大的属性,反之亦然。

计算渐变—按作者排列的图像

  • 第四步:累积插值图像的每个梯度,使用黎曼梯形等技术来估计曲线下的面积。

作者计算黎曼梯形图像

  • 第五步:在所有插值图像上缩放最终的特征重要性值,并显示最终的特征重要性。

作者图片

以下是该模型特征重要性的可视化:

作者图片

太好了!我们已经成功绘制了对模型决策贡献最大的像素。如果你观察属性遮罩,很明显较亮的像素具有最高的属性。因此,它很可能包含在叠加中。

这意味着什么呢?

让我们花一些时间来分析为什么我们的模型预测这个图像是双簧管。

作者图片

如您所见,很明显,该模型是根据按键的形状和结构做出预测的。这很好,因为它证明了模型能够掌握仪器内的关键特征。然而,在某些情况下,模型使用了不属于双簧管的图像区域来进行预测。他们中的一些人最终有一个高的特征属性,如标签。这是有问题的,因为它表明模型正在为错误的原因做出正确的决定。

在这种情况下,模型确定墙的一部分是双簧管的一部分。这很可能是因为它的形状像双簧管,因此模型认为它是乐器的一部分。

将受到 XAI 影响的行业

XAI 的影响将在医疗保健和金融等行业显现。

卫生保健

由 Hush Naidoo Jaide 在 Unsplash 上拍摄的照片

在医疗保健行业,很多情况下所做的决策会产生重大影响。这在疾病诊断中尤其明显,假阳性和假阴性会对患者产生巨大影响。因此,XAI 可用于否定决策的成本过高的情况,如活检。

据数字健康和医疗设备专家 Erik Birkender 称,

“医生接受的训练主要是识别异常值,或者不需要标准治疗的奇怪病例。如果一个人工智能算法没有用适当的数据进行适当的训练,我们就无法理解它是如何做出选择的,我们就无法确定它是否会识别出那些异常值,或者以其他方式正确诊断患者。”

对一个模型的决定缺乏理解是阻止医生理解它是否被正确训练的原因。这让人想起我们看到的例子,模型因为一个错误的原因做出了一个正确的决定。

金融

Austin Distel 在 Unsplash 上拍摄的照片

因为金融市场越来越复杂,并涉及大量数据的分析,人工智能模型被开发用于评估公司预测未来资产价格

这是因为人类很难以高效的速度无误地处理所有数据。然而,这种方法仍然涉及到一个黑盒,其中用户不能理解为什么一个模型预测了某个预测。

由于我们的经济系统会受到影响它的决策的影响,因此了解驱动宏观经济预测的关键特征是很重要的。这就保证了钱不是盲目投入的,预测是被历史趋势和当前社会因素所证明的。

有了可解释的人工智能,我们能够理解驱动模型做出预测的特征。当要以最小的误差做出决策时,这是最基本的,这不仅有助于我们应对高风险的情况,还有助于我们改进模型。随着开发可解释算法的进展,我们可以开始查看深度学习的黑盒内部。

感谢阅读这篇文章!随时在 Linkedin 上加我,订阅我每月的简讯

文献学

[1] 可解释的人工智能,IBM

[2] 医疗保健领域的可解释人工智能(XAI)如何帮助建立用户信任——即使是在生死攸关的决策过程中

[3] 积分渐变 (2021),Tensorflow

[4]o . Yal on,[可解释人工智能是人类生存需要的 5 个重要原因](http://5 Significant Reasons Why Explainable AI is an Existential Need for Humanity) (2020),走向数据科学

[5] R. Schmelzer,理解可解释的 AI (2019),福布斯

[6]钱学森,[可解释人工智能在金融中的意义&资产管理](http://The Significance of Explainable AI in Finance & Asset Management) (2020),反叛研究

OpenStreetMap:从浏览器查询到 Python+R 操作

原文:https://towardsdatascience.com/openstreetmap-from-browser-querying-to-python-r-manipulation-c8e4504ad709?source=collection_archive---------10-----------------------

数据科学家简明指南

OpenStreetMap (OSM)有多个用户,例如,网站应用程序开发人员可以将 OSM 地图集成到他们的在线工具和服务中,数据科学家在很大程度上使用 OSM 数据来创建空间分析和构建模型。本指南面向希望快速开始使用 OSM 数据的数据科学家;为此,它提供了三项基本技能:

  1. 直接在网络浏览器中查询 OSM 数据,
  2. 使用 python 通过 API 请求 OSM 数据,以及
  3. 用 r 探索请求结果。

OSM 数据基础

OpenStreetMap 是一套开源工具,存储并允许访问通过众包标记的地理空间数据。该工具集包括:

数据库和 API 访问 OpenStreetMap 数据库有几个选项。本演练主要关注天桥 API ,它提供只读 API 访问。

查询语言要在天桥 API 中查询数据,必须熟悉天桥 QL 。这是一种专门为 OpenStreetMap 数据模型创建的查询语言。

交互式访问 立交桥涡轮是一个基于网络的界面,允许使用立交桥 QL 探索 OpenStreetMap 数据库。查询结果显示在交互式地图上。

用天桥 turbo 查询 OSM 数据

OpensStreetMap 数据模型由节点路径组成。

  • 一个 OSM 节点代表空间中的一个点,需要两个标签,它的纬度经度
  • 一条 OSM 路代表线路(道路、河流),它们是节点的有序列表。一个 区域 是一条“封闭”的路,应该用isarea=true标记。

另一个 OSM 的数据模型元素是一个关系

  • OSM 关系用于分配国家、县、命名多边形(地标)和路线的边界。

让我们从打开[https://overpass-turbo.eu/?lat=30.30&lon=-97.75&zoom=11](https://overpass-turbo.eu/?lat=30.30&lon=-97.75&zoom=11)开始熟悉 OSM 元素,这是德克萨斯州奥斯汀市中心的立交桥视图。

在左侧,主视图包含一个文本框,其中输入了跨 QL 查询。在右边,结果显示在地图上。

查询 1

下面的代码返回奥斯汀地区的餐馆。这个区域是一个由两点定义的盒子:西南角(30.20, -97.85)和东北角(30.40, -97.65)

node[amenity=restaurant]
  (30.20, -97.85, 30.40, -97.65); 
out;

这些是在地图上查询的结果。

输出是 xml 格式的,每个节点的标签代表一家餐馆。

<node id="358532482" lat="30.3221769" lon="-97.6932173">
    <tag k="amenity" v="restaurant"/>
    <tag k="created_by" v="Potlatch 0.10f"/>
    <tag k="name" v="La Palapa"/>
  </node>
  <node id="358669465" lat="30.3231224" lon="-97.7037688">
    <tag k="amenity" v="restaurant"/>
    <tag k="created_by" v="Potlatch 0.10f"/>
    <tag k="name" v="China Star Buffet"/>
  </node>
  <node id="358693667" lat="30.3253747" lon="-97.7048159">
    <tag k="amenity" v="restaurant"/>
    <tag k="created_by" v="Potlatch 0.10f"/>
    <tag k="name" v="Pappadeaux"/>
  </node>
  <node id="359344991" lat="30.3269188" lon="-97.7048810">
    <tag k="amenity" v="restaurant"/>
    <tag k="created_by" v="Potlatch 0.10f"/>
    <tag k="name" v="Pappasitos"/>

通过 QL,语句将它们的结果写入集合,然后这些集合可以作为后续语句的输入。

查询 2

[out:json];
    (
      node[amenity=restaurant]({{bbox}});
      node[amenity=school]({{bbox}});
    );
    out;

该查询返回两种类型的便利设施的位置,即餐馆和学校。该声明包含:

  • 分号;分隔并结束语句的每一部分。
  • 一个联合块,由一对括号内的语句组成().
  • [out:<format>] 一对方括号[]和一个out语句,它们决定输出的格式(在本例中,是 json 格式)。
  • 完成搜索的边界框。({{bbox}})表示将结果过滤到当前地图视图。

到目前为止,示例中的查询将结果过滤到由坐标或当前地图视图定义的有界框中。在一个城市或一个县内请求结果是一个常见的用例。为此,需要管理边界区域的id。例如,德克萨斯州奥斯汀市的 OSM 关系的id113314

nomist im是允许按名称搜索 OpenStreetMap 数据的工具,可在[https://nominatim.openstreetmap.org/ui/search.html](https://nominatim.openstreetmap.org/ui/search.html)访问。下一张图片是搜索‘奥斯汀’后的 nomim 截图。搜索结果是 OpenStreetMap 数据库中的元素,其标签与搜索关键字相关。

查询 3

下一个查询在德克萨斯州的奥斯汀市执行搜索。请注意,区域 id 由数字 3600000000 和 OSM 关系 id 之和确定(在本例中为 3600113314 = 3600000000 + 113314)。如果感兴趣的区域是 OSM 路,则将数字 2400000000 添加到其 OSM id [ 1 ]中。

area(3600113314);
node[amenity=restaurant](area);
out;

使用 Python 直接发出请求

通过在[http://overpass-api.de/api/interpreter?data=](http://overpass-api.de/api/interpreter?data=)`之后添加一个天桥 QL 查询,可以向天桥 API 发出请求。以下 Python 代码将返回与上一节中的查询 3 示例相同的结果。

# %pythonimport requests
import jsonoverpass_url = "[http://overpass-api.de/api/interpreter](http://overpass-api.de/api/interpreter)"
overpass_query = "[out:json];area(3600113314);node[amenity=restaurant](area);out;"response = requests.get(overpass_url, params={'data': overpass_query})
response = response.json()

API 请求返回一个 json,它是列表和字典的组合。elements项包含所有提取节点的列表。这是前五个条目:

>>> response[‘elements’][1:5][{'type': 'node', 'id': 358669465, 'lat': 30.3231224, 'lon': -97.7037688, 'tags': {'amenity': 'restaurant', 'created_by': 'Potlatch 0.10f', 'name': 'China Star Buffet'}}, {'type': 'node', 'id': 358693667, 'lat': 30.3253747, 'lon': -97.7048159, 'tags': {'amenity': 'restaurant', 'created_by': 'Potlatch 0.10f', 'name': 'Pappadeaux'}}, {'type': 'node', 'id': 359344991, 'lat': 30.3269188, 'lon': -97.704881, 'tags': {'amenity': 'restaurant', 'created_by': 'Potlatch 0.10f', 'name': 'Pappasitos'}}, {'type': 'node', 'id': 359354860, 'lat': 30.3288301, 'lon': -97.7049325, 'tags': {'amenity': 'restaurant', 'created_by': 'Potlatch 0.10f', 'name': 'Japon Sushi'}}]

定义节点的(元)值是typenodeidlatlon。元素是一个嵌套的字典。如何使用pd.json_normalize展平嵌套字典的示例如下所示[ 2 ]。在这种情况下,选择了amenitynamecuisine标签。

# %pythonimport pandas as pd
import numpy as nprestaurants = (
  pd.json_normalize(
    response,
    record_path = 'elements'
    ) 
)[['type', 'id', 'lat', 'lon', 'tags.amenity', 'tags.name', 'tags.cuisine']]# since NaNs are not defined for characters in R (only for numeric)
# we need to replace NaNs for temporary 'NA' strings in python and
# then convert them to actual NAs in Rrestaurants = restaurants.replace(np.nan, "NA")

产生的restaurants数据帧可以很容易地导出到 r。

用 R 探索 OSM 数据

R 中的“传单”库可用于探索我们之前用 Python 获得的数据帧。除了通过“传单”实现 OSM 元素的空间可视化之外,“sf”库还提供了处理 GIS 数据的功能。

在移动到 R 之前,Travis 县(奥斯汀市)的人口普查区块组将使用 Python 从 Tiger/Line ftp 中提取。在这种情况下,下载的 shapefile 存储在本地文件夹/tmp中。

# %pythonimport wget
from zipfile import ZipFileimport os
cwd = os.getcwd()# census block groups
url = '[https://www2.census.gov/geo/tiger/TIGER2020PL/STATE/48_TEXAS/48453/tl_2020_48453_bg20.zip'](https://www2.census.gov/geo/tiger/TIGER2020PL/STATE/48_TEXAS/48453/tl_2020_48453_bg20.zip')
wget.download(url, '/tmp')
file_name = '/tmp/tl_2020_48453_bg20.zip'
ZipFile(file_name, 'r').extractall('./tmp')

使用 R 中加载的restaurants数据框和手边的人口普查区块组形状文件,可以获得一个两层地图:

  • 包含以蓝点表示的餐馆的图层。
  • 带有表示人口普查区块组(cbg)的多边形的图层。
# %rlibrary(leaflet)
library(sf)cbg_sf = st_read("/tmp/tl_2020_48453_bg20.shp")
cbg_sp <- as(cbg_sf, "Spatial")leaflet() %>% 
  addProviderTiles(providers$OpenStreetMap) %>% 
  addPolygons(data = cbg_sp, color = "black", weight = 0.5, 
              ) %>% 
  addCircles(data = restaurants, 
             ~lon, ~lat, popup = ~tags.name)

为了完成本指南,下一个代码块包含计算每个 cbg [ 3 ]中餐馆数量的命令。

# %rlibrary(tidyverse)restaurants_sf = st_as_sf(restaurants, coords = c("lon","lat"), crs = "NAD83")st_join(restaurants_sf, cbg_sf, join = st_within) %>% 
  as.data.frame() %>% 
  select(GEOID20) %>% 
  group_by(GEOID20) %>% 
  summarise(n = n()) %>% 
  arrange(desc(n))

然后,cbg 餐厅计数可用作监督模型的协变量,或用于估计空间分布。

关于如何在 R 中使用地理空间数据的其他学习材料可在其他地方找到:

虽然在 Python 和 R 中存在带有 OSM 数据提取内置函数的包(如 OSMnxosmdata ),但本指南提供了这些函数背后的基本概念。了解 OSM 数据、python API 请求和 R 空间操作的基础知识,最终使数据科学家能够根据手头应用问题的需求轻松调整他们的工作流程(并且可以使用 OSM 数据的应用问题是无限的!).

[1] Nikolai Janakiev,使用 Python 和立交桥 API 从 OpenStreetMap 加载数据 (2018),个人博客

[2] Ankit Goel,如何用 Python 熊猫解析 JSON 数据? (2020),走向数据科学

[3]马特·赫尔曼,带 sf 的多边形中的点 (2018),个人博客

OpenVINO:开始使用 Docker 针对英特尔 CPU 优化您的 TensorFlow 2 模型

原文:https://towardsdatascience.com/openvino-start-optimizing-your-tensorflow-2-models-for-intel-cpus-with-docker-ce59f5e1ce64?source=collection_archive---------23-----------------------

不要浪费你的资源,充分利用你拥有的计算能力。

杰克·吉文斯在 Unsplash拍摄的照片

我们都是在 GPU(或者 TPUs)上训练的。但是预测需要它们吗?不总是。尤其是如果你花一些时间来优化你的模型。如果你运行的是 Intel CPUs,OpenVINO 可以给你很大的帮助。

你可以在官方主页上找到大量的文档,那里有 GitHub 页面,在 Coursera 上的一些课程和许多其他资源。但是如何在不需要学习所有材料的情况下尽快开始呢?在下面的段落中可以找到一种可能的方法。

本文原载于希米拉博客

无需安装,使用 Docker

OpenVINO 有几个依赖项需要安装在你的电脑上。此外,要安装其中的一些,您需要拥有 root/admin 权限。这可能是不可取的。使用 Docker 代表更干净的方式。尤其是在Docker Hub上有一张为你准备的图片。

如果你对 Docker 不熟悉,它可能看起来像是一个复杂的软件,但是我们强烈建议你尝试一下并学习基础知识。这并不难,值得努力。Docker 是当今软件开发世界的重要组成部分。你可以在这里找到安装说明。

运行 Docker 映像

容器是无状态的。这意味着下次启动容器时,所做的所有更改都将消失。(是的,这是一个特点。)如果您想要持久化一些文件,只需在您的文件系统上准备一个目录,我们将把它作为一个共享卷绑定到一个正在运行的容器。(转到/home/openvino目录)。

我们将在交互模式 ( -it)下运行我们的容器,以便您可以轻松地在其中执行命令,当您关闭命令提示符(--rm)后,它将被终止。使用下面的命令,镜像将被下载(拉取),如果还没有完成的话,它将作为一个容器运行。

docker run -it --rm -v __YOUR_DIRECTORY__:/home/openvino openvino/ubuntu18_dev:latest

为了能够使用所有的工具,需要初始化 OpenVINO 环境。出于某种原因,这不是自动完成的。(至少对于一个普通用户来说不是,如果你以 root 身份启动 docker,-u 0,安装脚本就运行了。)

source /opt/intel/openvino/bin/setupvars.sh

然后打印出确认信息。

[setupvars.sh] OpenVINO environment initialized

TensorFlow 2 依赖性

默认情况下,TensorFlow 2 不存在于容器中。我们可以非常容易地基于安装了 TensorFlow 2 的原始图像创建我们自己的图像。这是生产中最好的方法。说到这里,我们将向您展示另一种方法,即使用原始容器并将缺少的包安装到共享目录(卷)中的虚拟环境中。这样,我们就可以随心所欲地创造许多这样的环境。或者轻易地改变这种环境。此外,我们仍然可以尝试旧的 TensorFlow 1 模型。在初始开发阶段,我们更喜欢这种方法。

下面的代码只需要执行一次,在你第一次启动你的容器之后。

mkdir ~/env
python3 -m venv ~/env/tensorflow2 --system-site-packages
source ~/env/tensorflow2/bin/activate
pip3 install --upgrade pip
pip3 install -r /opt/intel/openvino/deployment_tools/model_optimizer/requirements_tf2.txt

当您关闭容器并再次打开时,这是您需要重复的唯一部分。

source ~/env/tensorflow2/bin/activate

转换 TensorFlow SavedModel

假设您在 SavedFormat 中有一个经过训练的模型。出于本教程的考虑,我们可以采用预训练的 MobileNet。执行python3并运行以下几行来下载并保存模型。

转换是一个命令的事情。然而,我们需要使用一些重要的参数,这些参数将在下面描述。完整列表可在文档中找到。退出 python 解释器并在 bash 中运行以下命令。

/opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py — saved_model_dir ~/models/tf2 — output_dir ~/models/converted — batch 1 — reverse_input_channels — mean_values [127.5,127.5,127.5] — scale_values [127.5,127.5,127.5]
  • --batch 1将批量设置为 1。OpenVINO 不能使用未定义的输入尺寸。在这种情况下,MobileNetV2 的输入形状为(-1,224,224,3)。
  • --reverse_input_channels告诉推理引擎将图像从的 BGR 格式转换为 MobileNetV2 使用的 RGB 格式。
  • --mean_values [127.5,127.5,127.5] --scale_values [127.5,127.5,127.5]最后执行必要的预处理,使图像值介于-1 和 1 之间。在 TensorFlow 中,我们会调用预处理 _ 输入

请注意,如果您使用预训练模型,可以使用不同的预处理和通道顺序。如果你试图使用一个输入经过错误预处理的神经网络,你当然会得到错误的结果。

您不需要在转换后的模型中包含预处理。另一个选项是在将图像传递给转换后的模型之前,对代码中的每个图像进行预处理。然而,我们使用一些 OpenVINO 推理工具,它期望正确的输入。

在这一点上,我们还需要提到,您可能会从 TensorFlow 中的 SavedModel 和 converted OpenVINO 模型中获得略有不同的值。但是从我在分类模型上的经验来看,这种差别就像你用不同的方法把你的图像缩小到一个合适的输入尺寸一样。

对转换后的模型运行推理

首先,我们将得到一张属于 1000 个 ImageNet 类之一的测试图片。我们选择了斑马,班级指数 340。(对于 TensorFlow,Google 将类别索引保存在这里。)

弗里达·布莱德森在 Unsplash 上拍摄的照片

让我们把它下载到我们的主目录,我们在 Ximilar 服务器上保存了图像的小版本,所以你可以从那里得到它。

curl -o ~/zebra.jpg -s https://images.ximilar.com/tutorials/openvino/zebra.jpg

您可以使用一个脚本来测试预测,而无需编写任何代码。

python3 /opt/intel/openvino/deployment_tools/inference_engine/samples/python/classification_sample_async/classification_sample_async.py -i ~/zebra.jpg -m ~/models/converted/saved_model.xml -d CPU

我们在最后得到一些信息行和前 10 名的结果。由于数字非常清楚,我们将只显示前三个。

classid probability
------- -----------
  340    0.9556126
  396    0.0032325
  721    0.0008250

酷,我们的模特对图片上的东西真的很确定!

在 Python 中使用 OpenVINO 推理

很简单,对吧?但是你可能需要在你自己的 Python 代码中运行推理。你可以看看剧本里面的。这非常简单,但是为了完整起见,我们将在这里复制一些代码。我们还将添加一段代码,用于在原始模型上运行推理,以便您可以轻松地进行比较。如果你愿意,运行python3我们就可以开始了。

我们需要一个来自 OpenVINO 推理引擎的基本导入。此外,OpenCV 和 NumPy 是打开和预处理图像所必需的。如果你愿意,TensorFlow 当然也可以用在这里。但是因为运行推理根本不需要它,所以我们不会使用它。

至于预处理,它的一部分已经存在于转换后的模型中(缩放、改变均值、反转输入通道的宽度和高度),但这还不是全部。我们需要确保图像有一个适当的大小( 224 像素两边)和尺寸是正确的——批次,通道,宽度,高度。

现在,我们可以尝试一个简单的 OpenVINO 预测。我们将使用一个同步请求。

我们的结果prediction_openvino是一个普通的 NumPy 数组,形状为(批量维度,类的数量)= (1,1000)。要像以前一样打印前 3 个值,我们可以使用下面几行。

我们得到了和以前完全一样的结果。我们的代码有效!

将结果与原始张量流模型进行比较

现在,让我们用张量流模型做同样的事情。不要忘记先预处理图像。准备好的函数预处理 _ 输入可用于此。

结果几乎一样,差别小得可以忽略不计。与我们之前得到的概率 0.9556126 相比,这次预测的最高结果概率 0.95860416 。其他预测的顺序可能略有不同,因为这些值非常小。

顺便说一下,有一个内置函数 decode_predictions ,它不仅会给你排名靠前的结果,还会给你类名和代码,而不仅仅是 id。三大张量流预测。

结果如下:

[[('n02391049', 'zebra', 0.95860416), ('n02643566', 'lionfish', 0.0032956717), ('n01968897', 'chambered_nautilus', 0.0008273276)]]

标杆管理

我们应该提到的是,还有一个用于评测 OpenVINO 模型的工具。它提供同步(面向延迟)和异步(面向吞吐量)测量模式。不幸的是,它不适用于其他模型(如 TensorFlow ),不能用于直接比较。

奥本维诺如何帮助西米拉尔

代码足够了,在文章的最后我们会添加一些数字。在 Ximilar 中,我们经常使用分辨率为 224 或 512 像素的识别模型。每批 1 个或 10 个。我们尽可能多地使用 TensorFlow Lite 格式,因为它加载速度非常快。(此处见比较。)因为有了快速加载,所以不需要一直把模型放在缓存里。为了让运行 TF Lite 模型更快,我们用 XNNPACK 增强了性能。

以下是 MobileNet V2 公司的结果图表。对于批次,我们显示了预测时间,单位为秒/单个图像。对我们的生产工人进行了测试。

摘要

在本文中,我们简要介绍了 OpenVINO 的一些基本功能。当然,还有更多的尝试。我们希望这篇文章已经激发了你自己去尝试,并可能通过更高级的资源继续探索所有的可能性。

操作化:制定度量标准的艺术和科学

原文:https://towardsdatascience.com/operationalization-the-art-and-science-of-making-metrics-31770d94998f?source=collection_archive---------2-----------------------

所有数据专业人员的基本心理学

是时候解决一个对所有数据专业人士都至关重要的心理学话题了:

你如何衡量用户幸福度

让我来猜猜你在想什么。调查反馈?缺乏抱怨?退货数量?点击倾向?

正确答案是…

图片:来源

你没有。如果你认为你的幸福调查可以解决哲学家们争论了几千年的一个未决问题,再想想吧,邓宁教授。

成功怎么样?你如何衡量它?你没有。

如何衡量愤怒?你没有。(看到图案了吗?是的,我故意让你生气。引导愤怒去思考我所描述的名词之间的相似之处。)

你如何衡量信用度?你没有。

你如何衡量?你没有。

你如何衡量营销活动的好坏?你没有!

什么是幸福?

这些东西有什么共同点?它们很模糊。

当你听到幸福这个词时,你的脑海中会浮现出一些东西。无论你在想什么,都可能和你旁边的人想到的不一样。也许在其他日子和其他心情下,你也可能不认同自己。

想从神经科学的角度争论吗?“等等,我们可以看看他们的大脑,看看他们是否快乐……”去过那里,做过那个。在我读研统计学之前,我是神经科学的博士生,专业领域是神经经济学(对,有这么个东西),研究人脑中的效用和价值信号。换句话说,我的论文题目就是这个。

证明你的作者有头脑。图片:来源

我非常幸运地成为了一个设备极其完善的实验室的一员:

  • fMRI 扫描仪。 f 使其成为功能性磁共振成像,这意味着大脑图像不是静态的,而是血氧变化的地图——滞后几秒钟——用于在实验中定位大脑活动。
  • 脑电图钻机。这是脑电图的简称,一种使用电极网络来记录头皮上的电活动的技术,补充了 fMRI 的 where?用一个当什么?通过给你更精确的时间数据——在毫秒级别——关于大脑对各种刺激的反应。
  • 眼球跟踪器。将漂亮的相机与 niftier 软件相结合的专用套件,用于绘制研究参与者选择的凝视方向,使研究人员能够绘制视觉注意力。
  • TMS 钻机经颅磁刺激使用强大的电磁铁诱发大脑中的电活动导致行为。是的,精神控制是真实的(它甚至被 FDA 批准作为抑郁症的治疗方法),但不要担心:除非你一动不动地坐着,否则很难偷偷靠近你,因为你身边有一台冰箱大小的机器,它不会工作。

尽管有如此多的工具,我还是无法测量用户的快乐程度。幸运的是,在我开始之前我就知道了。就像地球上的其他神经科学家一样。

为什么会这样?在神经科学/心理学研究生院的第一周,他们确保向我们灌输一个重要的概念。必要时用棍子。你也该学学了:你好,操作化。

某个我说不出的地方。图片:来源

制作度量标准的艺术和科学

甚至操作化这个词对不同的人也有不同的含义。当我说这个词时,我的意思是:

操作化是为严格调查模糊概念创造可测量的代理。

我的意思和维基百科的意思是一样的:“在研究设计中, 可操作化 是定义一个不可直接测量的现象的测量的过程,尽管它的存在由其他现象指示。它是定义一个模糊概念的 过程,以使理论概念清晰可辨或可测 ,并从经验观察的角度去理解它。”

操作化是心理学可以自称为一门科学的原因。没有它,你将一事无成。你如何衡量一个你甚至无法定义的东西?

你不知道。

人类表达的沼泽

一些名词是根据它们被测量的方式来定义的。固定的含义是温度、质量、卡路里数、距离、星期几等等魅力的一部分。当谈到测量事物时,心理学家会说物理学家很容易。坦率地说,在人类语言的沼泽中艰难跋涉,拖出一门从头到尾都在叫嚣的科学,是一项令人疲惫不堪的工作。

图片: xkcd

问题在于,人类的很多交流都是有意设计的不精确。最精确的形式是数学(一种非常小心地说非常少的语言),不管你有多喜欢数学,我希望你会同意它对于我们大多数的日常聊天来说太慢了。如果我们打开歧义度盘,让听者随心所欲地解释我们的话,会更快地让事情被理解。

人类语言可能如此不精确,以至于其舍入误差具有下一级舍入误差。

每当我们抽象地说话时,我们说得太少(一些预期的意思在飞行中消失了)和太多(用外推解释的分叉道路)。具有讽刺意味的是,这些单词进入你的大脑和离开我的大脑的意思并不完全相同。

因为我不知道你过滤我的话的湿件设置,我能让自己变得几乎可以理解,这简直是奇迹。然而,我相当有信心,你们大多数人会“得到”它。人类是神奇的动物。

四舍五入现实

虽然它能帮助我们在单位时间内传达更多的信息,但诗歌让信息的传递变得不那么可靠。这不一定都是坏事,尤其是如果你想给你的观众留一点创新的空间。

不幸的是,虽然解释的空间通常是歌词和营销活动的一个特征,但就数学证明和科学研究而言,这是一个错误。当目标是传达一个精确的食谱,你的观众可以遵循而不会搞砸——比如你的同事可以借鉴的科学发现——诗歌是适得其反的。这就是为什么没有可操作性心理学就不是一门科学……这也是为什么草率定义的商业指标通常会让你比一开始没有尝试测量它们时更糟糕。

当我们给现实贴上标签时,我们就完成了它。

给解释留有余地的最糟糕的地方之一是机器学习。人类习惯于与其他人交换模糊的废话,所以我们习惯了观众代表我们寻找意义的宽容方式,即使我们不知道我们想说什么。机器不会这么做。他们完全按照吩咐去做。如果你告诉他们优化准确性,他们就会照做。他们不会说,“嘿,老板,我想你说的准确性实际上是说 精度……”

语言更加模糊。图片:来源

此外,我们在数据中创建的类别来自同一个模糊的地方,并且我们给现实贴上的标签揭示了很多关于我们的偏见。不幸的是,如果我们不小心,机器学习系统会收集这些信息并放大它们。为了避免一些可怕的——也是非常常见的——ML/AI/data 陷阱,培养说出自己的意思并理解自己实际说了什么的技能至关重要。

重要的是,你要培养说出自己的意思和理解自己实际说了什么的技能。

心理学剧本中的一页

心理学有一个多世纪的时间来应对测量你没有正确定义的东西的危险,所以我们学到了一两个商业领袖和数据科学家应该借鉴的金块。如果你想让我写下我们操作化的一些技巧,转发是最能打动我的方式。

心理学能给你的最好的度量建议是:

在命名之前,先定义您的指标。

从本质上讲,可操作化就是彻底改变你的标准思维:不要爱上一个词,为了追求它而追求它,而是深入思考你想要测量的真实世界的数量。即使你受到了一个诗意表达的启发,想想为什么这个词会引起你的兴趣。“快乐”的哪些方面似乎与你的业务问题相关?为什么?这和现实世界中的行为有什么关系?这种行为看起来像什么?它看起来像一个愉快地挂在你网站上的微笑用户吗?也许你认为是这样的。

现在忘掉原来的单词。而不是快乐,称之为 X .然后做数学家们做的事情,例如:“让 X =用户在你的网站上花费时间的倾向。”

仔细想想这个量。它真的是你想要衡量和做决定的基础吗?也许你决定它是。

非常好。现在你能说出它的名字。你命名它的原因是为了节省写作和谈话的时间。也许你会叫它【X】也许你会叫它【幸福】或者【blorktibork】甚至X A-12”**

重要的部分来了。你真的可以给它起任何你喜欢的名字,只要它不冒犯(礼仪或常识)和你(以及你的观众!)记住这个名字是一个占位符,代表一些非常具体的东西:用户在你的网站上花费时间的倾向。即使你这样命名,它也不是柏拉图的“幸福”。**

图片:来源

如果你记得名字仅仅是一个占位符,你就不太可能做一些愚蠢的事情,比如:

  1. 与科技兄弟(所有性别)争论这个指标是否真的在衡量幸福。它不是。这种争论就像如果你已经把你的变量叫做 X,是否允许我把我的变量叫做 X 一样荒谬,只要我们都把我们的意思写在我们的页面顶部,我们就很好,兄弟。
  2. 误解“快乐”的增加意味着你的网站正在发展。也许用户找不到他们要找的东西,他们花更多的时间在页面上,同时沮丧地嚎叫。如果你记得你实际测量的是什么,并且它的名字只是一个简写,你会更安全。
  3. 假设别人关于“幸福”的研究适用于你自己的情况。很可能他们定义了不同的度量标准。有时在一次心理交流会上注意一下,你可能会听到这样的一个序列:“很高兴见到你!你在做什么?”“记忆。”“太棒了,我也是。哪种?”"人类视觉空间工作记忆的发展,你呢?"请注意,“记忆”可能意味着任何东西,而 VSWM 是一个定义明确的技术概念(在某个时候,有人想研究它并说,“让 VSWM = _____”)。如果其他科学家不在 VSWM 工作,他们不会认为他们新朋友的研究适用于他们自己的工作。

小心使用语言,用基于操作化的思维评估我们的模糊性,不仅有助于统计推断,也有助于数据收集实用机器学习

如果你喜欢这篇文章,别忘了分享它!

感谢阅读!人工智能课程怎么样?

如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:

在这里欣赏整个课程播放列表:bit.ly/machinefriend

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?用这个表格联系。

接下来

在后续文章中,我将给出创建指标的 7 个技巧。如果这个话题引起了你的兴趣,你的转发是我最喜欢的力量,让我沿着你喜欢的方向继续写作。

与此同时,本文中的大部分链接会带你去我的其他思考。不能选择?尝试以下方法之一:

*http://bit.ly/quaesita_inkblot http://bit.ly/quaesita_fad *

每个数据分析师都应该知道的 5 件事

原文:https://towardsdatascience.com/opinion-4baef884f0da?source=collection_archive---------36-----------------------

意见

为什么它不是 Python,也不是 SQL

每个数据分析师都应该知道的 5 件事

#1 如果你的分析没有任何偏见,那么再看看

问题定义

偏见是支持或反对一种观点的倾向。大多数时候,这是完全无意识的,它主要发生在我们的结果和我们期望的完全一样的时候。我们都是人,如果我们对某件事有期望,在挖掘了一些数据后,我们的第一个结果与我们的期望一致,那么我们倾向于就此打住。当我们的结果不符合我们的预期时,我们可以继续挖掘,直到达到预期。

如何避免这种情况?

想想什么会让你的分析结果出错。我认为这种偏见有两个主要原因。

你分析的范围

尝试改变日期范围焦点,或者甚至使用的数据可能会得到不同的结果。典型的挑战是应对季节性和混合效应。注意群体效应

你的分析方法

这一个与统计 101 调情,现在你已经有了正确的时间和数据点的范围,仔细考虑你如何聚集他们得到结果。离群值是要考虑的,聚合指标也是。总是检查平均值和中值。

#2 大多数初稿可以在 Excel 中完成

这个标题有点挑衅。是的,python 功能强大,允许您保存和重复数据处理。但这是有代价的。首先,这需要时间,尤其是如果你不是 python 高手的话。其次,与非技术用户的协作更加困难。如果你需要不懂代码的人和你一起开发你的数据应用,那么 python 会让他们慢下来。

作为一名数据玩家,你会想用 Python 做项目,只是为了加速。但要谨慎选择。如果你有一个超级紧张的时间表,excel 做的工作,然后去 excel。您可以稍后迁移到 python,因为一次学习一件事情总是更容易。用一种你不熟悉的语言来做一个全新的数据应用是很难的。首先用你熟悉的工具做分析,然后把它移植到新的语言上。

#3 给自己一个保存查询历史的工具

有没有遇到过与 3 个月前类似的数据请求?每年发生太多次,希望你有一个过去 365 天运行的所有查询的历史记录…

退房蓖麻 这样做

#4 不要修正数据,修正创建数据的过程

先说一个现实生活中的例子。

我之前工作的一家公司的一个数据管道因为一个不唯一的问题而不断中断:一个表字段应该是主字段,但是有重复的字段。该字段是 client_id,通常一个客户应该在一个且仅在一个国家。

因此,每当我们遇到这个问题时,我们必须找到与几个国家有关联的客户并解决它。我们还要提醒销售团队“一国规则”。

我们是否应该针对这一具体问题建立一个专门的警报系统?我们是否应该在顶部添加一个变形层?我们应该取消“唯一”检查吗?这些都不是。当销售人员在数据源(也就是 Salesforce 中)创建数据时,我们必须(还没有)简单地执行该规则。

尽可能找到数据问题的根本原因,让人们明白好的数据需要针对它优化的流程。流程的确首先是为了改进业务而制定的,但是为了获得良好的数据,它们必须考虑到数据依赖性。

#5 尽可能广泛地分享你的分析

太多的数据玩家等自己的数据 app 完善了才分享。现在就分享吧(如果你愿意,可以在开头加上“WIP”免责声明)。不要花超过几天的时间对你的工作进行同行评审。它会给你视角。

结论

是的,硬技能(Python、SQL、R…)是开始你的分析的关键,但就个人而言,我更看重软技能(良好的沟通、看到全局的能力、直截了当、黑客)。

很高兴在评论中进行建设性的讨论

最优控制,序言

原文:https://towardsdatascience.com/optimal-control-a-preamble-6c0bc2b12ed6?source=collection_archive---------14-----------------------

思想和理论

如果你知道我在想什么

约翰·福勒在 Unsplash 上的照片

自然、人工智能、经济学家理论、经典力学、我们的大脑以及几乎所有东西有什么共同点?他们试图优化。

你甚至都没有去想,但是你的大脑却在不断的尝试优化。每一个动作都经过优化,消耗尽可能少的能量。每种动物都在努力优化自己的存活率。经济学家试图优化利润,整个自然界也试图优化利润。

这个简单的事实对我的学生时代是一个启示。那时我正在研究泡泡几何学这个有趣的课题。现在考虑这个简单的实验。假设你用金属线做了一个简单的立方体(只做了边缘),然后把它投入到液体肥皂的溶液中(就是孩子们用来做泡泡的那种)。你期望从中得到什么?答案相当令人惊讶,你可以在下面看到:

来源:Youtube,泡沫的科学(全科学纪录片)| Spark

这个谜题的答案其实很简单。这背后的物理现象称为表面张力,它源于一些分子更喜欢在一起,而不是与另一组分子接触,这里是水和空气。水分子会将自己排列成一种形状,使与空气接触的总表面最小化,从而形成这种非常奇特的形状。这也是为什么气泡是球形的原因,因为没有约束(线),封装给定体积的最小表面实际上是球体的表面。但看起来确实没那么酷。

这个简单的实验对我来说确实不可思议。看起来大自然实际上是在解复杂的方程,试图优化自己的能源消耗。考虑到气泡是一个几何解算器,我们几乎可以用气泡来进行科学计算(几乎..).这里的重要结果是,大自然正在试图解决一个优化问题:在给定一组约束的情况下减少一个量。这里减少了水状液体展开的表面,以包围我们吹入气泡的空气(约束)。

通用公式

现在让我们试着把“最优化”的概念转换成一个数学公式。

在数学中,最普遍的是,最优化的概念与寻找一个函数的最小值有关。给定一个函数“f ”,它取 n 个实数的向量作为输入,并将它映射到一个实数,该问题可以表述如下:求 x*使得

这两个公式是等价的。注意,输入域可以被限制到一个更小的域,即实数集。

很简单嘿。这可能隐藏了非常高的复杂度,取决于“f”的性质,不管它是不是一个“好”的函数。求解这个方程实际上是很多算法在做的事情。不管怎样,你经常不得不找到一个函数的最小值。以深度学习领域的神经网络为例。在算法的每一步,我们所做的只是试图找出某个成本函数的最小值。

正如人们经常做的那样,我们可以尝试将问题重新表述为一个更好的形式,等价但实际上更容易处理。特别地,我们可以找到两个必要条件,使得给定的 x 是方程的解:

注意,由于具有 n 个输入向量的函数的梯度是大小为 n 的向量,并且大小为 n 的向量的梯度是大小为(n×n)的矩阵,所以二阶条件需要一些解释。优越或相等条件并不意味着每一项都需要优越或等于 0。而是意味着矩阵需要半正定。还要注意,函数的二阶梯度叫做 Hessian 梯度。所以在这种情况下我们会说 f 的 Hessian 需要是半正定的。

如何简单解释这两个条件?第一个条件类似于高中时众所周知的结果:如果一个点的导数等于 0,则该点只能是函数的最小值。我们给出的是一样的,除了我们把它扩展到多变量的情况,这样就得到梯度。
高中期间省略的一点是,那个点是最小值还有一个必要条件。在这一点上的二阶导数应该大于或等于 0。类似地,黑森条件将 2D 的结果转置到多维情形。
如果这两个条件都得到满足,那么我们可以说这个点是一个驻点。(但我们还不知道这是否是最低价格)。

但是我们可以走得更远。如果“f”的 Hessian 是正定的,那么这两个条件是充分的(在 2D,如果二阶导数是严格正的,我们也将有这个充分条件),我们可以肯定地知道一个点是否是最小值:

一切都很好,我们确实以一种更容易理解的方式来表达这个等式。这意味着如果 f 足够好,我们可以解析地解决它。如果不是,我们需要使用数值方法来尝试反复猜测结果。但是找出这些条件使我们能够验证这些方法提供的结果。例如,我们可以通过查看“f”在该点的 Hessian 来猜测返回的解是否是一个驻点,而不是一个实际的最小值。

作者图片

上面描绘了一个马鞍形状。在拐点,也叫鞍点,只有导数为零,但 Hessian 不是严格半正定的。

我们也可以简单地谈谈求解这类方程的常用数值方法。正如神经网络一样,我们可以使用梯度下降方法或使用牛顿法找到最小值。另一种方法是使用所谓的进化策略,我在之前的文章中进一步详细研究了。然而,这些方法仅在无约束的情况下有效。

受限情况:

一切都很好,但是当我们试图执行优化时,我们经常会面临一些约束。尤其是当我们试图优化的东西是真实的、机械的、物理的实体时。一个经济学家必须考虑到资源是有限的,一个控制工程师必须考虑到其机械系统不能超过一组速度和加速度,否则就会看到系统崩溃。因此,约束是最优化理论的重要组成部分。
我们可以将约束类型分为两种:

  • 平等约束
  • 不等式约束

使用这些约束,优化问题的公式现在可以表述为:找到 x*使得

其中 hi(x)表示第 I 个等式约束,gi(x)表示第 I 个不等式约束。

让我们举一个简单的例子:

这里最小化的函数是一个凸抛物面形状(其中方程是二次函数),我们的约束是一条直线(方程 x = y,蓝点)。如果要最小化的函数的维数为 N,那么约束总是至多为 N-1 维,所以如果要优化的函数位于三维,那么约束位于二维空间。

作者图片

问题的解,最小点,当然需要属于抛物面。但是线性约束带来了新的要求。让我们想象一下,对于坐标为(x,y,z)的抛物面的每一个点,我们在同一个 z 层上画直线 x = y。对于考虑约束的点,它必须在那条线上。如果我们对想要优化的曲面上的每个点都这样做,那么我们最终所做的就是将约束的投影到我们的曲面上。投影的结果称为问题的容许点集(橙色点):

作者图片

如图所示,投影正好是一条抛物线。这意味着问题简化为寻找这条抛物线的极小点,而不是初始曲面。在大多数情况下,向优化问题添加约束会减少实体的整体维度,从而最小化(但仍会增加整体复杂性)。

现在,如果我们考虑不等式约束呢?让我们考虑我们的直线 x = y 的方程,把它转化成一个不等式约束 x ≥y。

作者图片

蓝点对应的是(x,y)平面中满足不等式约束 x ≥ y 的面积。橙色点是属于抛物面的点,它们也满足不等式约束 x ≥ y。

可以看出,约束仍然存在于较低的维度中(x,y 平面)。然而,由于不平等,我们最终得到的是一个区域而不是一条线。同样,为了减少优化问题,我们需要将它投影到我们的曲面上,以最小化可接受的点集。
投影的概念很容易理解,但在维度上就不那么容易理解了。投影的概念仍然是最优化领域的一个重要方面。

这就是几何可视化。在实践中,要找到带有等式约束的函数的最小值,一般工具是使用拉格朗日乘数,它允许通过引入新的耦合变量,以更易处理的方式将问题公式化。

对于不等式约束,我们使用相同的程序,并且可以使用 KKT 条件找到问题的等价表述。

路径优化

许多现实生活中的优化问题不能用上述形式系统化。

就拿谷歌地图来说,这个工具可以为你提供最快的公共交通路线。确实是一个优化问题。谷歌试图找到一条路线,使你从起点到目的地的总运输时间最短。大致的情况是,谷歌会浏览所有可能的路径,选择最快的路径。现在,上一节中描述的公式适用于找到给定函数的最佳点,尽管这里我们试图从函数(路径)的集合中找到最佳函数(这里的函数相当于路径)。看起来我们应该把函数作为变化的参数,并找到最佳的函数。显然,我们需要一个更好的公式。

解决这类问题的第一次尝试来自于著名的最速降线问题:为可以从两个给定点滑落的珠子寻找最短的轨迹。

腕尺年代问题,来源:维基百科

直觉上,我们可以说,如果我们可以将每个轨迹分解成小段,并找出珠子在这些小段上移动的时间成本,那么如果我们将它们相加,我们就可以找到每个轨迹的总时间。用数学公式表示:

其中 a 和 b 分别是问题的起点和终点,J 代表我们路径的总成本,这里是珠子的总移动时间,J是最优成本。
那么这意味着什么呢?与我们在一个变量(或变量向量)上找到最小值的先前公式相反,我们在这里找到一组路径上的最小值,这可以在最速降线示例中看到。但是,每条路径都可以与一个值相关联,即它的成本。我们有一个从泛函到实数的映射。
这里,最优路径是导致最优总成本 J
的路径。

现在这个提法看起来有点太简单了。让我们尝试重新制定。我们可以看到,珠子形成的时间取决于多种因素。首先,我们正在考虑的片段的长度。如果我们用一个函数 y 来定义曲线,使得曲线的每一点都可以用它的坐标(y(x),x)来描述,那么珠子在一段上滚动所需的时间 T 至少取决于 x 和 y(x)。既然我们知道重力也起作用,我们可以想象珠子的速度与线段的倾斜度直接相关,倾斜度越大,速度越快。因此,时间 T 也取决于倾斜度,换句话说,y’(x)。总而言之,函数 T 取决于 x,y 和 y’。我们现在有了公式:

变分法中的一般公式

以类似的方式,最佳路径 y是导致最佳总成本 J的路径。现在,这实际上是一个数学分析领域的通用公式,叫做“变分法”,你猜怎么着,这个领域主要是因为最速降线问题而开始的。

如果把一个函数的变量看成另一个函数的导数让你感到困扰,就把它看成一个正常的变量。就我们所知,我们让它作为导数的唯一原因是,解决这一系列问题的常用工具,欧拉-拉格朗日方程充分利用了这一事实。

这个名字一开始听起来有点高深莫测。尽管背后的逻辑相当简单,但我们需要更精确地观察欧拉-拉格朗日方程试图达到的目的。它遵循与寻找函数最小值相同的原则:我们对属于要优化的函数的一个点进行采样,如果附近的点实际上都在我们考虑的点之上,我们就四处查看(通过查看梯度)。如果是这样,我们处于局部最小值。嗯,路径也是一样。我们取一条路径,以多种方式扭曲它一点点(通过取积分的梯度),然后看看创建的路径是否都导致更高的成本。因此,我们正在寻找路径上的小变化…变分法。

在全球范围内,我们可以使用相同的公式来表示大量的问题,这些问题的特征是在一条路径上累积的局部成本,以形成总成本。显然,所有的导航问题都可以适应,但不是唯一的。经济学家对这类问题也特别感兴趣,因为“成本”这个术语本身就暗示了…

从路径优化到拉格朗日力学

现在来点魔法。

你听说过拉格朗日力学吗?概念挺有意思的。拉格朗日力学不像牛顿力学那样在参考系中建立运动方程,而是试图通过能量推理摆脱任何参考系。拉格朗日力学中臭名昭著的 F = m*a 的类比变成了:

这确实有点罗嗦,但最后,我们可以看到,在经典力学的原始情况下,拉格朗日函数 L 可以被认为是运动的成本。与我们之前的路径优化公式相比,变量有所变化,但总体来说还是一样的。我们不是在一段距离上积分,而是在一段时间上积分,这是等价的(我们可以对最速降线问题这样做)。
回想一下第一部分,函数的驻点是函数的梯度为零的点。我们需要在公式上更精确一点,因为泛函依赖于 yt 。这里的梯度是相对于 y 的,因为我们在看路径之间的差异。

因此,如果我们认为泛函 S 代表给定系统移动的总成本,那么找到 S 的驻点意味着在大多数情况下,我们试图找到 S 的最小值!换句话说,当一个时间间隔内运动的总成本最小时,就找到了系统的轨迹。这里不是我们试图优化一些值,这是一个系统的运动规律。这意味着,我们有了另一个证据,证明自然正试图最小化它的能量消耗,这已经被约瑟夫·路易斯·拉格朗日非常优雅地放进了方程式中。

我们可以看到变分法的公式和拉格朗日力学公式之间的密切关系。这不是巧合,拉格朗日是这个数学领域的主要贡献者之一,求解这个方程组的方程甚至拥有这个名字。在某种意义上,我们可以说拉格朗日力学是用变分法来表述运动定律(如果这有意义的话?).

然而拉格朗日并没有就此止步。也许你已经在这篇文章的某个地方看到了他的名字。事实上,当我们想要找到一个带有约束的函数的最小值时,拉格朗日乘数就出现了。
拉格朗日之所以没有止步于此,是因为我们刚刚提出的提法只适用于少数情况。如果我们挖得更深一点,我们会发现,由于拉格朗日中的项与系统的能量有关,上面的拉格朗日公式只能包含保守力(因为保守力的势能只取决于系统的状态,而不取决于过去的状态)。问题是,自然界的大多数力量都不是保守的。如果我们以钟摆为例:

来源:维基百科

我们有两个力在起作用:重力,和杆的张力,重力是保守力,没问题,但杆的张力不是。这意味着,目前我们不能用拉格朗日公式求解运动方程。除非我们说张力 T 是摆位置的一个约束。
以同样的方式,我们可以使用拉格朗日乘子来解决带约束的最小化问题。事实上,如果没有它们,这个公式在解决现实世界的问题时是相当无效的,拉格朗日在他的条约“分析力学”中用公式表达了运动方程,从而推动了乘数的概念。问题的一般表述变成:
如果 y 是泛函的驻点,曲线 y 描述系统的轨迹:

换句话说,该公式可以被认为是寻找系统的轨迹,使得该系统相对于约束最小化其能量消耗。

控制理论

终于,我们到了。让我们看看如何将我们在上面看到的所有结果转置到控制领域。

一、所谓的控制论是什么?

我们举个简单的例子。如果你从加农炮上发射一枚炸弹,因为你知道运动定律(也许你是拉格朗日力学的专家),你能够预测这枚炸弹会落在哪里。
现在,如果有一阵风,你的炸弹可能会偏离其初始轨道,炸弹可能会落在不希望的目标上。这个故事的寓意?不要相信物理学家,相信工程师。

来源:Youtube,弹性胶带广告

工程师是做什么的?“为什么不在炸弹上加几个螺旋桨”?其中一个说。“像这样,我们就可以实时调整炸弹的轨迹,迫使它按照期望的路径运行!”。“太好了”,另一位工程师说,“但是我们如何决定给螺旋桨多大的推力?”(在我的想象中)这就是控制理论领域出现的原因。

控制理论的思想是:
—以一个动态系统为例,它有自己的时间演化规律
—添加一个单元,使你能够改变系统的状态
系统因此有一个输入值(我们提供给单元的东西)和一个输出值(系统的新状态)。
—采取纠正措施,通过向系统输入输入值,将系统驱动至所需状态。负责向系统提供足够的输入值以便达到所需状态的部分称为控制器

控制理论最感兴趣的是如何定义这个控制器。给定要达到的期望状态,如何向系统提供输入值,使得可以尽可能快地达到该状态,具有最大的精度,并且确保鲁棒性,确保系统保持一定水平的稳定性并且不会退化。

在这种情况下,导弹是一个根据运动规律不断进化的系统。螺旋桨是能够采取纠正措施的装置。系统的输入值是螺旋桨的推力,输出值是导弹的位置和速度。类似地,空调是一种允许我们根据热力学定律对室内温度采取纠正措施的装置。整个(房间+空调)系统的输入是提供给空调的电压,输出是新的房间温度。
当我们进入房间并打开设备时,我们希望尽快达到所需的温度,但我们也不希望房间无缘无故地变成冰箱(坚固性)。

偏爱控制理论的可视化工具是框图。它使我们能够看到我们试图添加到系统原始动态的整体输入。例如:

开环框图

这是一个开环的例子。值 x(t)在这里对应于系统的期望状态。我们首先应用我们的控制器动作,然后将这个值输入我们的系统。在这种情况下,控制器的动作不依赖于新的系统输出。再看空调的例子,就相当于我们把空调的电压固定下来,让它输出一股恒温的气流。如果你决定打开窗户,控制器不会适应。您可能无法达到所需的温度。

工程师们于是创造了闭环的概念。基本上,它不是着眼于期望的状态,而是着眼于系统的当前状态和期望状态之间的差异。这样,控制器对潜在的扰动(打开窗户)变得更加鲁棒。

闭环框图

从上图中可以看出,反馈给控制器的不再是期望状态 x,而是系统输出和期望状态之间的误差e。此外,我们注意到传感器的存在。在大多数情况下,控制器不知道系统的输出,需要对其进行测量。一台空调需要一个传感器来确定新的室温,一枚导弹需要一个跟踪工具来确定其在空间的定位。

最优控制

在介绍了控制理论之后,我们可以把注意力集中在它的一个分支——最优控制上。

正如我们所见,控制集中在多个方面。稳定性、精确度和速度。在最优控制中,我们定义了一个可以在每个时间步计算的成本,它反映了我们想要最小化的数量。它可以是时间,或精度,或两者同时,或者我们也可以有其他的量来优化(燃料消耗,等等..).

首先,让我们考虑我们想要优化的量是时间。给定一个初始系统状态,即要达到的期望状态,这里的目标是找到系统的输入序列,使系统在尽可能短的时间内达到期望状态。换句话说,如果我们找到了最优控制,就不可能有另一系列的控制来使系统在更短的时间内达到期望的状态。让我们以一辆汽车为例,通过选择我们踩下油门踏板的力度,可以控制它沿直线行驶...最优控制问题可以表述为,从 A 点出发,停在 B 点,驾驶员应该如何踩油门以最快的速度停在 B 点。或者用控制术语来说,这个问题等价于说“找到从 A 到 B 的时间最优的控制序列 u(t)(油门踏板的角度)”(导致汽车 x(t)的一个运动)。

鉴于我们在最优性方面的经验,我们几乎想把它变成一个数学公式。大概是这样的:

现在,如果你还在跟踪,你可能会想,我们怎么找到 u(t)和 x(t ),它甚至不在积分中…这就是动力学发生作用的地方。最优控制中考虑的所有系统都是动态系统,这意味着它们遵循形式为 x'(t) = f(x(t))的时间演化定律。
如果拿空调来说,温度受热力学定律支配,而导弹受运动定律支配,就像我们认为的汽车一样。难道你不认为这些应该被考虑进去,才能知道我们多快能到达 B 点?没必要把事情搞复杂,我们就把它作为最小化问题的约束条件加入吧:

但是,方程中没有控制 u?让我们想一想……空调遵循热力学定律,但我们加入了冷空气,打乱了热力学定律。导弹有一个很好的自由落体轨迹,但是通过启动推进器,我们确实改变了它的轨迹。有没有可能,动力学方程也需要考虑控制因素?

现在看起来好多了。让我们试着走向一个普遍的情况。这里我们只想优化问题的总时间。如果,我们也要考虑总用气量呢?气体消耗与我们应用于油门踏板的控制直接相关,因此它应该出现在成本中。但是,如果你正从阿拉斯加开车到加利福尼亚,并且饱受寒冷之苦,那该怎么办呢?那么你最好赶快离开阿拉斯加(而你在加利福尼亚周围会没事)。看起来这里的成本取决于汽车的位置 x(t)。

一个最优控制问题应该表述如下:
找出每个 t 的控制序列 u(t ),使得我们最小化数量:

最优控制问题的一般表述

注意代表成本的函数是用大写的 L. L 写成的像…拉格朗日?事实上,控制理论家决定将其命名为拉格朗日,因为这个最优控制公式是从变分法中推导出来的。不同的是,拉格朗日函数不依赖于(t,x,x '),而是依赖于(t,x,u)。但是正如我们看到的,动力学方程可以把 u 和 x '联系起来,所以这实际上是一样的。

太好了,看起来这个方程可以在变分法的框架下用欧拉-拉格朗日方程来求解。等一下……约束是非完整的?(不能将约束表示为轨迹上的限制)?欧拉-拉格朗日方程不能用?所以你是在告诉我,我们在变分法上所做的所有这些形式主义都是徒劳的?(不!)

有希望的是,一些有才华的人能够利用变分法的策略为这个最优控制公式得出一些结果。例如,拉格朗日乘数仍将用于推导,以考虑其他完整约束。由此得出的定理被称为庞特里亚金最大值原理

然而,最优控制的领域并不局限于庞特里亚金及其定理。由于实现后一个定理的计算量非常大,所以出现了其他方法,每种方法都能够找到特定情况下的最优控制。其中一个叫做动态编程,这是一个分支,后来导致了强化学习和深度强化学习。也有不同的情况需要考虑,如区分有限视野和无限视野问题(无论我们是否有时间限制),连续或离散化表示。有些解如庞特里亚金原理是解析的,有些是数值的。

正如我们所看到的,最优控制领域有很多方法来解决初始问题,找到优化给定成本的最佳控制。然而,所有这些方法都是从我们上面提出的相同公式开始的。关于这一主题的文献通常非常深奥,没有为所使用的问题表述提供任何背景。这篇文章正是为了提供一些介绍性的背景知识,我希望它能帮助你进一步深入最优控制领域。

为了更进一步:

机器人的最佳控制:第一部分

原文:https://towardsdatascience.com/optimal-control-for-robotics-part-1-4cc4ee5fb14d?source=collection_archive---------19-----------------------

如何以最省时的方式移动机械臂?

图德 帕维尔 像素

如果您已经阅读了最优控制系列的前几篇文章(这里这里和那里那里,您将会理解最优控制问题的公式化,以及如何在简单的情况下解决这些问题(使用一阶约束的变分法)。

现在,这一切都很好,但我们想知道更复杂的问题实际上是如何解决的。现实生活中的大多数约束都不够好,不足以让我们使用我们友好的变分法理论。

为了说明用于解决更复杂的最优控制问题的不同方法,我们将集中于机器人的例子,特别是机器人手臂的最优路径参数化。

使用机械臂通常意味着一天内重复执行数万次相同的动作。假设取出一个零件并将其插入到一个精确的位置。减少机器人从这两个位置移动所需的时间,即使是几分之一秒,也可以提高制造过程速度、分类速度或任何其他机器人任务的速度。出于这个原因,科学家们对这个话题产生了兴趣,并试图将最优控制理论应用于机器人手臂的运动。

注意:最佳的机器人动作对打乒乓球也很重要。

来源:决斗:提莫·波尔 vs 库卡机器人https://www.youtube.com/watch?v=J3gvpaNFvZU

机械臂的运动规划管道

对于机器人手臂的复习,手臂可以用一个运动链来表示。

作者图片

机器人的每个关节通常以一个自由度连接两个连杆。一系列关节和链节形成了一个运动链。
链条末端的位置,即其顶端,由手臂的配置决定,换句话说,由每个关节的值决定(该值对应于与初始位置相比关节旋转或平移的程度)。当我们控制机器人时,我们分别控制机器人的每个关节,因为每个关节都有自己的马达。
对于机械臂,我们感兴趣的配置空间因此是所谓的关节空间,表示基于其关节值的机器人的所有可能配置。比如上图,机器人的构型可以用向量[关节 1,关节 2,关节 3,关节 4]来写。

现在,我们实际上如何计划让机械臂移动呢?要将手臂从配置 A 移动到配置 B,我们需要确定两件事:

  • 中间配置的顺序
  • 控制序列,能够从一个中间配置转换到另一个中间配置。

正如我们所看到的,第一个问题属于几何分析的范畴,而第二个问题与机器人的动力学有关。通常的方法是将问题分成两部分,首先找到一条路径,一系列在期望点开始和结束的有效机器人配置,然后采用这条路径,并根据速度和加速度确定输入到每个关节的控制,以便从路径的一个航点移动到另一个航点。这受到约束,因为关节马达具有速度约束和扭矩约束的实际限制(马达能够容纳多少有效载荷)。我们通常将这两个问题称为路径规划轨迹生成或路径参数化。

为了举一个更容易理解的例子,你可以想象你是一个过山车设计师。你想计划一个新的旅程,从一个地方开始,到另一个地方结束,但是你确实有局限性,火车不能走得太快,因为车轮的限制,手推车不能经历快速加速或减速,因为有脱轨的风险。为了使问题变得简单,你首先画出一个几何路径,说明游乐设备将会是什么样子(路径规划),然后尝试确定如何控制火车的马达,以便在任何地方都不会超过速度和加速度限制。通过这样做,您可以将几何路径转换为轨迹,并且能够在路径的每个点上关联所需的列车电机控制。

工业机器人最常见的路径规划工具是快速生长树 RRT,其功能是对任意点进行采样,确定它们是否是机器人的有效配置,然后尝试将它们链接在一起形成路径。下图是点被采样并连接在一起的动画。

来源http://msl.cs.uiuc.eduRRT 的建设

本文将重点讨论机械臂的轨迹生成。

机械臂的轨迹生成

轨迹生成问题显然是一个控制问题,因为给定一条路径,我们必须确定手臂的控制序列,然而,这还不是一个最优控制问题。
给定一条路径,你可以找到无数种方法来移动手臂通过不同的路径点。你可以决定非常缓慢或非常快速地移动手臂,这两种方式都可以解决轨迹规划问题。然而,大多数时候我们关心的是尽快到达目的地。寻找一组控制以最小化某个成本函数?这看起来确实像一个最优控制问题。

让我们试着把这个问题公式化。

我们可以通过机器人每个关节的状态来表示机器人的每个配置,我们在这里称之为 q ,这是一个 n 维向量,n 是运动链的关节数量。
对于我们的参数化问题,我们知道已经设置了一条路径,我们可以用函数 f(s) 对这条路径建模。这里,s 是一个任意值,它使我们能够遍历路径。当 s = 0 时,我们在路径的起点,当 s = 1 时,我们在路径的终点。对于每个 s,函数 f 返回机器人的相应配置。

当我们考虑使用 N 个关节的机器人配置时,为什么我们可以使用一维变量来表述问题?您会注意到,由于我们希望机器人的末端属于几何路径,选择一个关节的值会强制其他关节的值也是已知的。因此,这个问题可以简化为一维问题。
请注意,在此阶段,配方不依赖于时间。参数化的时候,我们要实现的是归纳出时序的概念。换句话说,我们想知道,在什么时候我们将到达路径描述的每个配置。

对于机器人的三个连续配置,如果我们知道我们需要达到它们的时间,那么我们可以推导出每个关节在两个分段上应该具有的速度,从而得出每个关节的加速度。
换句话说,我们的控制问题,在路径的每一点寻找电机的控制,等同于寻找路径执行的时机。

《每日电讯报》对 https://giphy.com/gifs/telegraph-10Z3sr3ClZzUJy 的动画报道

重新表述这个问题:给定 f(s),我们想找到 q'(t),q''(t),通过这样做找到 q(t),从而找到 f(s(t))。我们在这里增加两个条件,分别是 q'(0) = 0 和 q'(T) = 0,T 是问题的最终时刻。

现在我们最优性的条件是找到控制(关节速度和关节加速度),使得我们尽可能快地达到 s(T) = 1:

我们在这里试图找到 T 的最小值,即到达路径终点的时间,在允许的控制集合中。请注意,通过改变变量,我们可以使用路径变量 s 来重新表述该问题。由于该方程涉及其对时间的导数,我们知道仍然涉及时间。然而,这种形式符合我们在以前的文章中看到的一般最优控制问题的表述。

这里的关键是容许控制的概念。我们可以变得疯狂,不断地给每个关节输入最大加速度。然而,我们可以看到,条件 q'(T) = 0(手臂停在终点)迫使考虑减速阶段。
不仅如此,我们还看到了马达在速度和扭矩方面的物理限制。我们还可以根据自己的喜好设置一些其他约束。例如,也可以设置加加速度约束(q ' '(t))来减少输出轨迹的加加速度。

既然我们用路径变量 s 重新表述了问题,这意味着我们也需要用路径变量 s 来表述约束。

机械臂的二阶约束可以表示为以下形式

其中 n 是联合向量 q 的维数,C 是凸多面体。如果你从来没有亲眼见过多面体,要知道对于 n 维的情况,它只是构成多边形的 1d 线和构成多面体的 2d 面的一般等价。因此,我们的约束具有边界面的表达式,因为它是凸多面体。

但是,在 n 维中工作不是很方便。不管用什么方法解决问题,我们工作的维度越低越好。请记住,我们将最小化目标表示为参数路径 s 的函数。我们知道,我们可以将机器人遵循的路径表示为 q(s) 。通过使用链式法则,我们可以得到:

现在,这允许我们只转换 s 的函数中的任何二阶约束:

文献称之为将约束投射到路径上。可能奇怪的是,关节空间中的约束(例如速度限制或加速度限制)取决于机器人的配置,被减少到这个一维。这是因为我们已经知道了路径,所以我们对机器人可能具有的所有不同配置的完整约束集不感兴趣,而只是一个子集,即它在所考虑的路径上实际采用的子集。

我们优化问题现在可以表述如下:

对于这个公式,我们需要在路径的起点和终点添加一些初始和最终的约束,为了简洁起见,这里省略了这些约束。这看起来很像最优控制问题的一般公式,带有二阶约束。

既然问题已经被正确地表述了,我们可以研究解决这个问题的不同方法,以及这如何导致现实世界的机器人解决方案。

我们离开了对变分法的研究,带着对解决更复杂问题的一些见解,提到了庞特里亚金先生。

他对最优控制理论的贡献提供了一个定理,该定理可被认为是欧拉-拉格朗日方程的扩展,但适用于二阶约束情况。如果我们只关注时间最优控制情况,问题可以写成一般形式:

其中 x 是状态变量,u 代表系统的控制。很容易看出,如果我们选择以下公式,则之前为机器人的路径参数化找到的公式与该公式相关:

庞特里亚金从哈密顿量的概念中推导出他的结果。哈密尔顿函数是另一个类似于拉普拉斯的抽象函数,实际上是基于它的。例如,我们可以用哈密顿量导出运动方程,从而导出哈密顿力学。应用于时间最优控制的具体问题:

等式(1)是基于拉格朗日 l 的哈密尔顿函数的定义。在这种情况下哈密尔顿函数是优选的原因是它提供了一些很好的数学特性,使得庞特里亚金可以推导出等式(2)。这个等式的好处是它对任何时间 t 都成立。等式(2)的问题是,对于每个时间 t,H 可以是最大值或最小值,或者根本不存在。所以这个条件还是没给台面带来多少东西。然而,庞特里亚金证明有必要最大化

因此从我们的时间最优问题公式化开始,我们可以首先表达拉格朗日(以及考虑到约束的增广拉格朗日),并且从那里使用等式(1)得到哈密顿量(分别为增广哈密顿量):

等式(4)是等式(2)的重新表述,增加了 H 只能是最大值的知识。*符号代表最佳。然后我们用等价的哈密顿量来代替它。

给定控制 u 总是被一些可能的区间所有界(因为我们处理的是物理系统),假设区间[u-,u+],那么给定(lambda * B 的转置)的符号,我们可以说为了最优,我们的控制只能取两个可能的值:u-或 u+。

所以庞特里亚金证明的是,对于时间最优控制问题,最优控制是在每个时间 t 都处于其容许边界的极限的控制集合。要么在一边,要么在另一边。这种控制系统的方式被称为 Bang-Bang 控制,因为我们从一个极端控制切换到另一个极端控制。

对于一个非常复杂的演示来说,这实际上是一个非常简单的结果。举例来说,这让我们知道如果我们想赢得一场赛车比赛,如何踩油门。

克里斯·赫恩在 Unsplash 上的照片

让我们稍微修改一下规则,假设赛车驾驶员也需要在终点线以零速度停车。根据 bang-bang 控制原理,我们应该尽可能加速(完全踩下油门踏板),然后达到我们的控制不再受加速度限制而是受最大速度限制的状态,在特定点,完全松开油门踏板并完全踩下刹车踏板(假设汽车不打滑)。

机械臂的开关控制

现在让我们回头看看我们的机械臂问题。我们证明了路径参数化问题的确是一个时间最优控制问题。现在,bang-bang 控制对机械臂意味着什么?我们知道,我们的控制是由一个向量[ṡ,ṡ'].
由于路径参数的导数与关节的速度和加速度相关,控制限制也与速度和加速度限制直接相关。

当我们运行最佳轨迹时,这转化为这样一个事实,即在每个时间点,至少关节电机达到其最大速度,或者其扭矩由于加速或减速而饱和。

现在人们可能会感到困惑,难道我们不是在试图找到每一个关节的控制吗?我们不可能同时加速和减速所有的关节。
这样想:
假设在给定的时间 t,我们决定完全加速一个关节。这意味着在时间δt 后,我们知道这个关节移动了多少。但是道路已经决定了。这相当于说,我们可以推导出在时间δt 期间,其他关节需要移动多少才能仍然属于该路径。

因此,庞特里亚金定理让我们知道,在轨迹的每一点,我们需要饱和一个关节,并在特定的切换点,在加速阶段和减速阶段之间交替。现在的问题是,我们如何找到所有这些开关点?关于机械臂控制的文献提出了不同的策略,以利用庞特里亚金的结果,并找到机器人在给定几何路径下移动的最快方式。请参阅本文的第 2 部分,了解可用于解决工业机械臂最优控制问题的不同技术的概述。

来源:

布拉格 CTU 的最优和鲁棒控制。所有的讲座都可以在 Youtube 上看到(频道“aa4cc”)。

机器人的实用时间最优轨迹规划:凸优化方法,Diederik Verscheure,Bram Demeulenaere,Jan Swevers,Joris De Schutter 和 Moritz Diehl。

基于可达性分析的时间最优路径参数化新方法。

机器人的最佳控制:第二部分

原文:https://towardsdatascience.com/optimal-control-for-robotics-part-2-e9f9acb4027b?source=collection_archive---------13-----------------------

通过算法让机器人最优移动。

Pavel Danilyuk 在 Pexels 上的照片

我们在上一篇文章中证明了工业机械臂的路径参数化问题是一个最优控制问题。

从那里我们简单介绍了庞特里亚金最大值原理以及它如何用于我们的问题:
给定一条描述从起点到终点的机器人配置序列的路径,到达终点的最快方法是选择控制(每个关节的加速度和速度),以便我们不断达到控制极限,在最大加速度和减速度的阶段之间交替,Bang-Bang 控制。
我们还表明,通过将约束投射到路径上,这个问题可以变成两个维度,一个是路径参数 s,一个是控制ṡ。

在这篇文章中,我们将提出三种方法,以庞特里亚金定理为出发点,尝试解决这个路径参数化问题。

TOTG

时间最优轨迹生成。

庞特里亚金告诉我们,我们需要交替最大加速和最大减速阶段,如果我们已经达到了最大速度,只要我们能保持在那里。确定每种情况下的控制很容易,但确定开关点也很重要:

如果我们再来看看德拉斯特的情况,我们知道我们需要尽可能多地踩下油门踏板,然后在精确的时刻踩下刹车踏板,停在终点线上。
这里的关键部分是准确知道在两个踏板之间切换的位置。

TOTG ,[ 1]中提出的算法提供了一种严格的分析,以便在约束仅限制关节速度和关节加速度的非常特殊的情况下找到所有的加速度开关点。一旦我们为路径上的一个点建立了成为开关点的所有条件,我们就可以遍历路径,并精确定位所有的开关点。

TOTG 通过数值积分进行,这基本上意味着分两步重复进行,向前传递和向后传递。
在向前传球中,我们使用最大加速度,并试图尽快达到最大速度,并尽可能地保持在那里,直到我们找到一个切换点。TOTG 告诉我们,在那里,我们需要实际上在最大速度极限曲线上继续(即使产生的轨迹不会使用这一部分),并找到下一个速度极限不连续形式的切换点。从那里,我们只需反向运行算法(反转时间)并使用最大减速度而不是最大加速度来连接两个开关点。
然后重复,直到最后找到的切换点实际上是轨迹的终点(零速度)。

让我们试着看看我们的赛车会是什么样子。相对于距离绘制速度足以定义所有需要的控制(速度和加速度):

作者图片

1–2:使用最大加速度,达到最大速度曲线。2–3:停留在最大速度曲线上,直到找到一个切换点:在这种情况下,速度限制不连续,在终点线,速度限制下降到零(汽车应该停止)。4:从切换点开始,做“倒传”。使用最大减速度,我们能够找到与我们正在经历的轨迹的交叉点(5)。

现在让我们看看真正的机器人是什么样子的:

相平面轨迹,来自[1]

这里,每个垂直箭头代表一个开关点。我们可以注意到与我们的简单示例不同的两点:

  • 加速度和速度约束不是线性的。这是因为我们将约束从关节空间投影到路径上,在关节空间约束是线性的。TOTG 实现确实找到了投射到路径上的这些约束的解析表达式。
  • 我们有两种类型的速度约束:速度极限曲线和加速度极限曲线。即使后者被称为“加速度极限”,它也是对速度的一种限制,但由于加速度的限制。假设我们到达了速度极限曲线。我们将尽可能长时间地坚持下去。但也许当我们“骑着它”时,我们实际上加速得太快了。加速度曲线的作用是建立一个速度极限,这样就不会超过最大加速度。正如你在图上看到的,这些加速度极限曲线大多发生在速度曲线有突变的时候。

我们现在可以更好地理解 TOTG 算法。从加速切换到减速的需要主要来自加速极限。如果我们没有很强的加速度极限,我们会沿着最大速度极限曲线前进,直到轨迹的终点。当速度极限曲线与加速度极限曲线相交时,检测到需要这种开关。从那里我们需要反向运行算法来连接轨迹,同时考虑所有的约束。

因此,TOTG 是一种相当可靠的算法,因为约束和开关点可以解析地表达。然而,这只有在将我们自己限制在关节速度和加速度约束时才有可能。不过,限制关节加速度的效用有限。虽然关节速度对应于一个直接的物理限制(转子的旋转),但关节加速度没有物理等价。对电机来说,重要的是施加的扭矩。但这是另一个层面的复杂性,因为电机施加的以特定速度和加速度移动的扭矩取决于特定配置的机器人的惯性。
如果机器人完全伸展,向下施力会困难得多(用手臂试试):

完全伸展配置与收缩配置。图片作者。

假设我们在机器人的顶端安装了一个很重的负载。如果我们的目标是不损坏机器人,那么不管机器人配置如何,限制加速度是不够的。

为了获得完整的解决方案,路径参数化算法因此需要考虑扭矩约束(以及更全面的任何类型的约束)。在这种更普遍的情况下,解析地找到所有可能的加速度转换点(并确保我们找到时间最优的轨迹)变得太难了。

TOPP 公司

当我们谈到最优控制问题时,我们直到现在才想到两个结果,欧拉-拉格朗日算法(导致变分法理论)和庞特里亚金最大值原理。在这两种情况下,目标是将问题公式化为更易处理的东西。这些方法可以称为间接方法。

将方法命名为间接方法需要直接方法的存在。直接方法是指使用已经存在的算法来解决优化问题,但不一定是最优控制问题,只要它们被放入正确的公式中。特别地,当问题是凸的(要优化的函数以及约束是凸的)时,存在大量的算法来提供最优解的估计。
根据要优化的函数的确切性质和约束条件,可以使用不同的算法。在所有函数都是线性或二次函数的特殊情况下,可以更有效地找到最优解。
凸问题的一般表述是:

f,h,g 都是凸函数

在离散化公式中,向量 x 的大小是离散点数的 N 倍。

我们在以前的文章中一直坚持最优控制问题是如何找到一个最优函数(控制),而不仅仅是找到一个给定函数的最小值。那么凸优化算法是如何帮助我们的呢?
这个问题的解决方案类似于任何电子表格软件执行线性或二次回归的方式:我们选择一个模型。优化就是找到模型的参数,让我们找到控制问题的最优解。在最优控制问题中,这种特殊的方法有一个名字:直接转录。

可以使用一个额外的技巧:我们可以离散化路径,然后为路径的每一段选择不同的模型,而不是为整个轨迹上的控制选择模型(否则最优解可能会有太大的误差)。通过某种近似,可以认为,如果对于离散化轨迹的所有点都遵守约束,那么外推轨迹也将遵守约束。

现在让我们来谈谈在论文[2]中提出的 TOPP-CO,它代表通过凸优化的时间最优路径参数化。这种方法使用前面显示的技术:我们从如下描述的路径参数化问题开始(如果这还没有引起注意,请再次检查第 1 部分):

需要做一些工作来将这个公式转换成凸优化问题。该出版物的作者[2]选择为ṡ提供一个模型。路径参数 s 表示我们在路径上的几何位置,想象一个进程的加载条。假设我们知道控件,s 的一个值将对应于某个时间戳,反之亦然。然后,很自然地尝试将 表示为 s 的函数,这里称为 b(s)。将路径离散化后,作者选择模型为(在离散段 k 到 k+1 上):

然后选择函数 b(s)在 s 中是线性的,带有一些参数。选择最优 b(s)(最优控制)将等价于求解最优参数 b^k.。建立模型允许重新表述原始问题,并仅用参数 s 的函数来表达它。经过一些整合后,作者表明该问题可以以如下形式提出(为了简洁起见,省略了约束):

虽然很清楚要优化的函数是凸的,但作者表明约束可以以满足二阶锥约束公式(凸优化问题的子类)的形式存在。通过将其转换成矩阵符号,我们能够利用现有的工具来解决这个凸优化问题,并找到 b(s)的表达式。作者解释说,我们可以通过以下方式积分来找回时间参数化(相当于找到问题的控制):

这是 TOPP 公司使用的技术。我们在这里没有明确描述的是约束的公式以及它们如何投影到路径上。这种凸优化公式的优点是,任何约束都可以包含在过程中,只要它是凸的,并且只要我们可以找到如何将这种约束投影到路径上(将约束表示为 s 的函数)。特别是,扭矩约束可以添加到公式中。凸优化的另一个优点是可以使用其他目标,或者与各自的权重混合在一起。特别是,作者描述了如何将热能和扭矩变化率作为目标函数。

动态规划

解决最优控制问题的另一个广泛使用的工具是动态规划。

如果你不知道什么是动态规划,我们可以简单地说:( 1)它在于将问题离散化,( 2)它利用了贝尔曼最优化原理。换句话说,我们想利用这样一个事实,即轨迹的最优控制在轨迹的每一点都是最优的。如果我们随机抽样轨迹的一部分,它也将是最优的。这就是马尔可夫决策过程。这么说的后果是,我们可以一部分一部分地看待这个问题。

那么在路径参数化的情况下,动态编程是什么样子的呢?我们可以用一种简单的方式来表示它:

动态规划决策过程。作者图片

动态编程的关键方面是离散化状态空间,以及控制。在我们的例子中,我们的状态空间可以减少到一维(路径参数 s)。控制可以简化为确定每个点的速度(【ṡ】))。然后我们有一个二维网格,网格中的每个点都有一对(s,ṡ).

现在动态编程倒着跑。我们从 N-1 状态开始。我们查看所有容许的速度,并根据 N(为 0)处的速度计算加速度,并检查它是否在容许的加速度范围内。基于 N-1 到 N 段之间使用的速度,我们可以得到通过该段所花费的时间。到达网格中该点所需的时间成为与该点相关的成本。关于动态规划算法有趣的部分来自第 N-2 点。在这一步,我们试图将状态 N-2 的所有容许速度与状态 N-1 的每个容许速度联系起来。
贝尔曼的最优性原理指出,网格中某一点的成本是该点的成本+它所能到达的任何一点的最小成本。
如果我们以(b)点为例,其相关成本将为

其中(b)-(e)和(b)-(d)是使用 b、e 和 d 处各自的速度从 N-2 到 N-1 的时间。
我们不需要记住所有从网格点(b)开始的潜在轨迹。我们只需要记住最优的那个。回滚到点 1,我们自然会找到最优轨迹。

值得注意的是,文献[3]只考虑了关节速度和关节加速度约束,然而,任何类型的约束都可以计算出来,以“消除”网格中的某些点。我们也只展示了一个纯时间最优的情况,虽然成本函数可以适应其他目标,如前所述的 TOPP 公司

那么动态规划方法的效率如何呢?如果我们用 N 个点离散化路径参数,用 M 个点离散化它的导数范围,总共,我们必须执行 NMM 次迭代,这听起来是可以接受的。
动态编程经常是“维数灾难”的主题,当控件具有高维度时就会发生这种情况。在我们的例子中,将控件减少到一维使得动态编程成为一个可行的选择。

使用哪种方法来解决真正的机器人路径规划问题?

我们现在经历了三种方法:

  • 一种间接方法,TOTG
  • 一个直接的方法,TOPP 公司
  • 一种动态规划方法

首先,我们看到所有三种算法都是基于空间的离散化,甚至是动态编程方法的控制的离散化。我们还可以注意到,所有的方法都利用了问题可以在两个维度上简化的优点,将约束投射到路径上。但是它们在某些方面有所不同。
在考虑使用哪种算法时,有三个重要参数:

1-灵活性(约束和客观成本)

2-计算时间

3-可靠性

TOPP-CO 和动态方法的主要优点是,只要我们能把它们投射到路径上,就有可能集成任何约束,以及使用多个目标成本的可能性。

动态方法是三种方法中最慢的,特别是当我们需要非常精细地离散路径和控制以避免以不稳定的轨迹结束时。不过,很靠谱。我们会在 100%的时间里以最优轨迹结束。

凸优化方法更快,但有一个主要问题,它不会始终返回最优轨迹:要么凸优化器根本无法找到解决方案,要么找到局部最优解。

间接方法,TOTG 是迄今为止所有方法中最快的,并且由于所有情况都是通过分析研究的,所以它也是非常可靠的(有一些轻微的失败机会,但是没有局部最优)。它的主要缺点是缺乏灵活性,但在实践中(对于工业应用来说),除了时间最优之外,我们不太可能想要别的东西。至于约束,特别是关于扭矩约束的使用,当机器人携带重的有效载荷时,它们通常是最需要的:没有任何有效载荷并且在关节速度范围内,扭矩约束不会被违反。如果有效载荷很重,高速运行的主要问题甚至可能不是扭矩饱和,而是看到物品掉落的风险。所以总而言之,只有在高速携带重型有效载荷时,才需要扭矩约束,而今天的机器人应用程序很少真正做到这一点。即使应用程序确实需要它,使用一个能够承载更重负载的更大的机器人可能也比试图为一个新的参数化算法改变代码库更容易。

最后但同样重要的是,TOTG 科学出版物附带了该算法的一个相当成熟的开源实现。考虑到提供机器人解决方案的公司的规模(通常相当小),这一方面实际上非常重要。拥有一个经过验证的开源运动规划算法通常是业界采用 TOTG 的唯一原因。

发那科机器人的重载荷示例:https://www.youtube.com/watch?v=69RtLBImXiU

所以,默认情况下,大多数机械臂轨迹都是用 TOTG 参数化的。然而,这还不是理想的解决方案。随着后勤部门机械臂的民主化,更重的有效载荷需要高速移动。因此,仍在努力改进运动规划管道,以将灵活性-快速性-可靠性集合到一个算法中。

来源:

每种方法都基于一个或多个科学出版物:

[1]:加速度和速度受限的路径跟踪的时间最优轨迹生成:Tobias Kunz 和 Mike Stilman。

[2]:机器人的实际时间最优轨迹规划:凸优化方法:Diederik Verscheure,Bram Demeulenaere,Jan Swevers,Joris De Schutter 和 Moritz Diehl。

[3]使用动态规划生成机器人操作器的最佳轨迹:S. Singh,M.C. Leu。

分层时间序列的最优预测协调

原文:https://towardsdatascience.com/optimal-forecast-reconciliation-for-hierarchical-time-series-ea892ca105a9?source=collection_archive---------5-----------------------

分层预测的研究表明,我们可以做得比简单地累加成分更好

(感谢 艾米莉·卡萨 的反馈,这篇文章现在更新了关于非负面预测调和的内容。)

作者图片

假设你需要预测一个零售连锁店在商品、商店和整体层面的销售额,你会怎么做?最有可能的情况是,您将预测每件商品的销售额,并将预测汇总到不同的总额中,对吗?

Rob J. Hyndman 教授以其在预测和时间序列方面的工作而闻名,他和他的团队在一篇论文中指出,一个更好的方法可能是独立预测所有级别的所有时间序列,然后用回归模型对这些预测进行最佳协调。他的见解是,不同的聚合级别可能揭示要建模的数据的重要特征,因此在分层时间序列结构内进行协调的预测可能更优。

M5 赛亚军也采用了类似的调整方法。在他们的解决方案中,LightGBM 模型是为产品商店级别构建的,而深度学习算法(N-BEATS)用于预测更高的聚合级别。然后根据 N-BEATS 生成的预测调整 LightGBM 模型。在我看来,这种方法的优点是团队能够使用适合手头任务的不同算法。对于表现出间歇性的产品商店级数据,LightGBM 可能更适合,而 N-BEATS 可能更能够提取较高聚合级别的趋势和季节性模式。

在本文中,我们将首先简要介绍预测协调的背景,然后深入研究一个改编自 M5 竞赛数据集的简化案例。

预测调节

以一家零售连锁店为例,下图显示了该连锁店时间序列的层次结构。

零售连锁店的图解层次结构|作者图片

层次结构的顶部是总计,接下来是商店商店项目

如前所述,虽然在将预测汇总到更高的级别之前,我们肯定可以在商店项目级别进行预测,但更好的做法可能是预测所有级别并调整这些预测,以便将较低级别的预测汇总到更高的级别。那么,我们如何调和这些预测呢?

Hyndman 教授的建议是将调和视为一个回归问题。

给定实际销售观察值,我们可以用下面的等式 1 来表示它们:

等式 1 |作者图片

假设我们要分别预测每个级别(文献将此类预测称为基本预测),那么我们可以为协调问题编写以下等式 2:

等式 2 |作者图片

你们中的一些人可能意识到这个方程看起来非常类似于普通最小二乘法(OLS)提出的方程,事实上,最简单的方法是用 OLS 方法求解:

等式 3 |作者图片

还有其他方法来解决这个方程,你可以参考 Hyndman 教授的在线教材来了解细节。

在我们的零售销售环境中,我们可能还要求调节后的预测为非负数。

要确保非负的已调节预测,确保商店-物料层复合预测为非负就足够了,如以下等式 4 所示:

等式 4 |作者图片

正如由 SL Wickramasuriya 等人在本文中所详述的。艾尔。(2019) ,方程 4 可以构造为非负最小二乘问题(方程 5)。

等式 5 |作者图片

在下一节中,我们将提供一个关于预测调节的案例研究,以及一个用于求解 OLS 调节预测和非负调节预测的示例代码。

案例研究—🏪零售销售预测

虽然这个理论听起来不错,但它在实践中表现如何?

我们用来自 M5 竞赛的一个非常简化的数据集做了一个实验,它包含了分级零售数据。这些数据涵盖了美国三个州的商店,包括商品和商店级别的详细信息。

实验设置是这样的,我们将使用 LightGBM 算法在所有级别预测一个项目未来 7 天的单位销售。比较了两种方法:

  1. 自下而上的方法(即,在商店项目级别进行预测,然后将它们加到每个总数中);和
  2. 预测调节方法(即,在用 OLS 方法调节预测之前,在每个级别独立进行预测)。

虽然实验可能不是非常广泛和彻底,但作为一个简单的案例研究说明应该足够了。

下面,我们比较每一级(存储状态总计)的两种方法的平均绝对误差(MAE)。

自下而上与预测协调方法的 MAE 比较|图片由作者提供

正如您所看到的,预测调节方法(标有“OLS 分级调节”)通常具有更准确的预测(MAE 更低),但得出预测调节方法更好的结论将过于简单。我们使用的数据集毕竟简化了很多,商店和州级 MAE 的差异可能也没有统计学意义。

更有趣的是,尽管我们对商店级别的两种方法的预测具有相似的 MAE 性能,但自下而上的方法在更高的级别会导致更差的性能。这突出了一个反直觉的事实,即在底层更准确并不意味着更高层的汇总预测也将更准确。

它还表明了我们在开始时的观点,即不同的聚合级别可能揭示要建模的数据的重要特征,因此在协调它们之前,最好在每个级别进行预测。

为了执行预测协调,我们利用了 scikit-hts 软件包。用于调节预测的独立代码片段示例如下所示(带有用于非负调节预测的代码)。完整的案例研究代码,您可以在这里查看

由于有许多时间序列表现出层次结构,我们希望这篇文章将是一个有用的参考这些时间序列的预测。

如果您喜欢这篇文章,您可能也会对这个关于“使用深度学习进行端到端时间序列预测”的 3 项目系列感兴趣。作为本系列的作者,我提供了如何交付用于时间序列预测的端到端机器学习应用程序的分步指南。

感谢阅读😄另外,如果您有任何问题或建议,请随时发表评论。

参考

https://otexts.com/fpp3/reconciliation.html https://github.com/carlomazzaferro/scikit-hts

不平衡分类的最佳阈值

原文:https://towardsdatascience.com/optimal-threshold-for-imbalanced-classification-5884e870c293?source=collection_archive---------0-----------------------

照片由 Aaron BurdenUnsplash

动手教程

如何利用 ROC 曲线和精确召回曲线选择最佳阈值

不平衡分类

分类是一种监督学习技术,用于对分类结果进行预测分析,它可能是二进制类或多类。目前,有很多关于使用几种算法进行分类的研究和案例,从基础到高级,如逻辑回归、判别分析、朴素贝叶斯、决策树、随机森林、支持向量机、神经网络等。它们已经得到了很好的发展,并成功地应用于许多应用领域。然而,数据集的不平衡类分布有一个问题,因为开发的大多数监督学习技术是针对平衡类分布的。

不平衡的类别分布通常发生在我们研究一种罕见的现象时,如医疗诊断、风险管理、骗局检测等等。

混淆矩阵概述

在深入讨论不平衡分类和如何处理这种情况之前,如果我们有一个关于混淆矩阵的良好基础就好了。混淆矩阵(也称为误差矩阵)包含关于由分类算法完成的实际和预测分类的信息。这种算法的性能通常使用矩阵中的数据来评估。下表显示了两类分类器的混淆矩阵。

混淆矩阵及其元素(图片由作者提供)

使用两类分类器的分类将具有如下四种可能的结果。

  • 真阳性TP
  • 假阳性FP (俗称I 型错误)
  • 真阴性TN
  • 假阴性FN (俗称二类错误)

点击 阅读更多关于I 型错误II 型错误 的信息

此外,为了在分类情况下评估我们的机器学习模型或算法,有一些评估指标可以探索,但如果我们遇到不平衡的类,这是很棘手的。

  • 精度
  • 召回灵敏度
  • 特异性
  • 精度
  • F1-得分

对于不平衡分类,我们必须选择正确的评价指标,并保证它们是有效的和无偏的。这意味着这些评估指标的值必须代表数据的实际情况。例如,在不平衡分类中,由于类别的不同分布,准确性实际上会有偏差。看一下下面的研究案例来理解上面的陈述。

平衡分类
假设我们是一家科技公司的数据科学家,要求开发一个机器学习模型来预测我们的客户是否会流失。我们有 165 个客户,其中 105 个客户被归类为非流失客户,其余的被归类为流失客户。该模型产生如下给定的结果。

平衡分类的混淆矩阵(图片由作者提供)

作为一个平衡的分类,准确性可能是评估的无偏度量。它正确地表示了平衡类分布上的模型性能。在这种情况下,准确性与召回率、特异性、精确度等高度相关。根据混淆矩阵,更容易得出结论,我们的研究已经产生了一个最佳算法或模型。

不平衡分类
类似于上一个案例,但是我们修改了客户数量以构建不平衡分类。现在,总共有 450 个客户,其中 15 个客户被归类为流失客户,其余的 435 个客户没有流失。该模型产生如下给定的结果。

不平衡分类的混淆矩阵(图片由作者提供)

从上面混淆矩阵中的准确度来看,由于不平衡的阶级分布,结论可能具有误导性。当算法产生 0.98 的精度时会发生什么?这种情况下精度会有偏差。也不能代表车型性能。准确率够高但是召回率很差。此外,特异性和精确度等于 1.0,因为模型或算法不产生假阳性。这是不平衡分类的后果之一。然而,F1 分数将是模型性能的真实表示,因为它在计算中考虑了召回率和精确度。

注:把数据分为正面和负面,仍然没有一个硬性的政策

除了上面提到的一些评估指标之外,还有两个重要的指标需要理解,如下所示。

假阳性率和假阴性率公式(图片由作者提供)

  • 假阳性率
  • 假阴性率

分类的默认阈值

为了比较评价指标的使用和确定不平衡分类的概率阈值,提出了真实数据模拟。该模拟生成了 10,000 个样本,其中包含两个变量,即因变量和自变量,主要类别和次要类别之间的比例约为 99:1。属于不平衡分类,毫无疑问。

为了处理不平衡类,阈值移动被提出作为处理不平衡类的替代方法。从理论上讲,生成综合观测值或对某个数据进行重新采样有其自身的风险,就像创建一个实际上不会出现在数据中的新观测值,减少数据本身的有价值信息或创建大量信息。

生成模拟数据

寻找最佳阈值的 ROC 曲线

X 轴或自变量是预测测试的假阳性率Y 轴或因变量是预测测试的真阳性率。完美的结果应该是点(0,1)表示 0%假阳性和 100%真阳性。

计算 ROC 曲线

ROC 曲线(作者图片)

G 均值

几何平均或称为 G-平均是敏感性(称为回忆)和特异性的几何平均。因此,它将成为不平衡分类的无偏评价指标之一。

几何平均公式(图片由作者提供)

计算几何平均数

利用 G-mean 作为无偏的评价指标和阈值移动的主要焦点,产生了 0.0131 的二分类最优阈值。理论上,当其概率低于 0.0131 时,观察值将被归类为次要类别,反之亦然。

G 均值最高的 ROC 曲线(图片由作者提供)

尤登 J 统计量

要讨论的指标之一是尤登的 J 统计。优化 Youden 的 J 统计将确定分类的最佳阈值。

计算尤登 J 统计量

Youden 的 J 指数给出了与使用 G-均值相同的阈值结果。它在 0.0131 中产生二元分类的最佳阈值。

约登 J 值最高的 ROC 曲线(图片由作者提供)

寻找最佳阈值的精确-召回曲线

精度-召回曲线是表示精度和召回之间关系的图形。

计算精确度和召回率

精确召回曲线(图片由作者提供)

有几个评估指标可以用作计算的主要焦点。它们是 G 均值、F1 得分等。只要它们是用于不平衡分类的无偏度量,就可以应用于计算中。

计算 F1 分数

使用精确回忆曲线和 F1 分数,它产生 0.3503 的阈值,用于确定给定的观察值是属于主要类别还是次要类别。由于方法不同,它与以前使用 ROC 曲线的技术有太大的不同。

F1 分数最高的精确召回曲线(图片由作者提供)

其他方法—阈值调节

阈值调整是为不平衡分类确定最佳阈值的常用技术。阈值序列是根据研究者的需要生成的,而先前的技术使用 ROC 和 Precision & Recall 来创建这些阈值的序列。优点是根据需要定制阈值序列,但是它将具有较高的计算成本。

利用生成的阈值序列进行阈值调节

语法**np.arrange(0.0, 1.0, 0.0001)**意味着阈值有 10,000 个候选。使用循环机制,它试图找出受试者的最佳阈值,以最大化 F1 分数作为无偏度量。最后,停止循环机制并打印出最佳阈值 0.3227。

F1 分数最高的阈值调整曲线(图片由作者提供)

非常感谢 杰森·布朗利 给了我学习的动力,让我在统计学和机器学习实现方面更加努力,尤其是在阈值移动技术方面,他的文章清晰而恰当。谢谢!

不平衡分类的最佳阈值

结论

机器学习算法主要在平衡分类上工作良好,因为它们的算法假设使用目标变量的平衡分布。此外,精度不再与不平衡的情况相关,它是有偏见的。所以,主要的焦点必须转移到那些无偏的指标上,比如 G 均值、F1 分数等等。使用 ROC 曲线、精确召回曲线、阈值调整曲线的阈值移动可以是处理不平衡分布的备选解决方案,因为重采样技术看起来对业务逻辑没有意义。但是,选项是开放的,实施必须考虑业务需求。

参考

[1] J .布朗利。https://machinelearningmastery.com/threshold-moving-for-imbalanced-classification/(2020)不平衡分类的阈值移动。【https://machinelearningmastery.com/】T4。

利用快速 S3 优化深度学习工作流程

原文:https://towardsdatascience.com/optimise-deep-learning-workflow-with-fast-s3-f706ad059039?source=collection_archive---------27-----------------------

以快速 S3 为中心数据和模型库,构建可复制、可扩展的深度学习系统。

我知道大多数数据科学家不关心存储,他们也不应该关心存储。然而,在系统中拥有快速 S3 对象存储肯定会有助于优化我们的深度学习工作流程。让我在这篇博客中解释一下为什么“存储在 DL 中非常重要”。

快速 NFS 分布式培训

在我之前的博客中,我解释了为什么以及如何使用 Kubernetes、Horovod 和 FlashBlade NFS 这样的快速 NFS 存储从单节点扩展到分布式多节点训练。下面是我们在博客中讨论的架构:

在 FlashBlade NFS 上使用 Kubernetes 进行深度学习

这是船上分布式培训的第一阶段。虽然存储可能很少出现在 DL 对话中,但构建可扩展的 DL 系统就像建造一座大房子,您需要在屋顶工作之前先构建一个坚实的基础。DL 系统的基础是基础设施,不仅包括 GPU 服务器,还包括存储和网络。在上述体系结构中,如果我们只关注 NFS 存储部分,它带来的好处包括:

  • 允许在不适合单个主机的大型数据集上进行训练。
  • 允许团队共享昂贵的 GPU 硬件和数据。
  • 让机器学习工程师更容易聚合日志、管理检查点和导出模型。

然而,随着系统的升级和扩展以支持更多的机器学习工作和操作,挑战出现了。NFS 对于主机或机架来说是静态的,但是 DL 工作流是非常动态的。因为所有主机/单元都需要装载一个 NFS 卷来访问其中的数据,所以这在大规模应用时会很有挑战性:

  • 数据访问控制在主机级别。因此,存在数据集从装载该卷的任何主机上意外删除的风险。
  • 由于上述风险,数据集的主副本通常存储在远程存储器中,如 HDFS 或 S3。将数据从 HDFS 或 S3 复制到 NFS 可能会很慢。
  • 难以进行可重复的模型训练,这需要对代码和数据进行集中管理。
  • 弹性模型服务困难。在大公司中,模型训练和服务通常在不同的环境中由不同的团队管理。特别是,模型服务系统可能会频繁地扩大和缩小,NFS 根本不是最适合的。

这里的解决方案是借用数据工程和 devOps 的最佳实践到我们的 DL 工作流中。我见过的最佳实践之一是使用像 S3 这样的对象存储作为中央数据存储库。

利用快速 S3 优化 DL 工作流程

在机器学习和深度学习之前,我在大数据(Hadoop 和 Spark)和 devOps(云,平台即服务)上花了 10 多年时间。我从自己的经历中学到的一件事是,S3 对象存储在这些系统中起着至关重要的作用。这也适用于大规模的 DL 系统。

快速 S3 对象存储如何帮助优化我们的 DL 工作流程?好处来自于使用 S3 作为数据和模型的中央存储库。在以下修改后的体系结构中,我们使用 S3 闪存来存储训练数据集、日志和检查点,而不是 NFS。

利用快速 S3 优化 DL 工作流程

我们仍然使用 NFS,但仅用于工作区卷,它仅存储临时数据。我们将训练数据和模型管理集中在快速 S3 对象存储中,与 NFS 不同,它是在存储端而不是每个单独的主机上进行管理的,并且可以从系统中的任何位置进行访问。快速 S3 是动态 DL 工作流的理想选择。

在 S3 使用数据集

我们没有将数据集放在 NFS,而是放在了 S3 桶中。这使得能够与数据工程工作流顺利集成。S3 正在成为 Apache Spark 等许多大数据工具的标准存储。我们的数据工程团队可能使用 Spark 来完成繁重的 ETL 工作,并简单地将预处理的输出(例如,拼花文件)放入 S3 桶中。通过使用 S3,我们避免了数据工程和数据科学团队之间额外的数据拷贝。看看我的博客关于如何在 S3 上使用 Apache Spark 和 Kubernetes。一旦预处理完成,输出数据将立即出现在 S3。我们可以使用 JupyterLab 的 S3 浏览器扩展来研究这些数据。

JupyterLab S3 浏览器

然后培训岗位可以选择将数据下载到其工作区 NFS 卷,或者直接在 S3 阅读,进行培训。由于 FlashBlase S3 非常快,因此将 S3 数据直接读入训练迭代是可行的。如果数据集太大而无法下载,这将非常有用。例如,我们可以像这样直接从 TensorFlow 中的 S3 读取数据,而不是下载 20TB 的数据:

ds = tf.data.TFRecordDataset(
               s3_filepaths, 
               num_parallel_reads=10, 
               buffer_size=100000000)

与下载整个 20TB 数据集相比,上面的代码使用最少的临时存储和内存,可以立即开始,而不必等待下载完成。通过使用像 FlashBlade S3 这样的快速 S3,并调整并行读取的数量和缓冲区大小,可以达到与从快速 NFS 读取相当的性能。

使用 S3 进行模型跟踪和服务

在上面的架构中,我们还使用 S3 来存储训练日志、检查点和模型。这使得我们可以很容易地将模型跟踪和服务从训练中分离出来,这对于构建一个可重复和可伸缩的 DL 管道是必不可少的。下面的例子启动了一个指向存储在 S3 的日志的 TensorBoard pod。

tensorboard --logdir s3://deephub/models/lstm-sentiment/logs --host 0.0.0.0

S3 支持的 TensorBoard

我们还可以在 Kubernetes 上单独部署一个 mlflow 跟踪服务器,并将其指向 S3 桶进行高级模型跟踪。

mlflow server \
 --backend-store-uri postgresql://user:password@mypostgres:5432/mlflow \
 --default-artifact-root s3://deephub/mlflow/ \
 --host 0.0.0.0

使用 S3 后端进行物流跟踪

同样,模特服务也可以得到 S3 的支持。

MODEL_BASE_PATH=s3://bucket/models tensorflow/serving

模型服务基本上是一个 web 应用程序,它将模型公开为 web APIs。运营和扩展模型服务就像一个典型的 devOps 场景。将原始模型放在 S3,所有的服务 pods 都可以从中读取和缓存,这就像是 devOps 中运行稳定且可伸缩的 web 应用程序的常见做法。

摘要

由于所有重要的数据,包括数据集、训练日志、检查点和模型,都存储在 S3,数据和模型管理变得更加容易。S3 存储桶中的数据是黄金记录,被集中起来并受到保护。通过使用 S3 复制和版本控制,我们可以进一步增强我们的数据保护。高级用户还可以在 S3 数据的基础上构建数据治理、质量控制和模型版本控制。

总而言之,使用 S3 作为中央数据存储库有助于从以下几点优化 DL 工作流程:

  • 简化的工作流程。涉及的存储操作较少。数据科学家可以简单地下载或直接从 S3 的训练代码中读取数据。
  • 简单的数据和模型管理。我们通过将数据放在 S3 作为数据和模型的黄金记录来避免数据孤岛。数据保护、版本控制和跟踪更加容易。所有这些都将有助于可重复的模型训练。
  • 易于弹性模型服务。通过分离模型训练、跟踪和服务,深度学习工作流中的每个阶段都可以独立、轻松、快速地扩大和缩小。

下一篇博客再见。

远视教程:优化您的超参数调谐

原文:https://towardsdatascience.com/optimise-your-hyperparameter-tuning-with-hyperopt-861573239eb5?source=collection_archive---------8-----------------------

使用 Hyperopt 的贝叶斯超参数调整的简单解释和实现

约书亚·阿拉贡在 Unsplash 上拍摄的照片

介绍

超参数调整 是数据科学和机器学习工作流的一个重要组成部分,因为它可以挤压模型所能提供的最佳性能。因此,您选择执行超参数调整的方法非常重要。网格搜索是穷尽式的,而随机搜索是完全随机的,因此可能会错过最重要的值。但是,通过hyperpt包有一个更好的方法!

Hyperopt 是一个开源的超参数调整库,它使用贝叶斯方法来寻找超参数的最佳值。我不打算深入这个贝叶斯方法如何工作的理论细节,主要是因为它需要另一整篇文章来充分解释!然而,感兴趣的读者可以在这里查看文档http://hyperopt.github.io/hyperopt/,如果你感兴趣的话,还有几篇关于这个主题的研究论文。

在本文中,我们将把一个 RandomForestClassifier 模型拟合到 Kaggle 提供的 水质 (CC0 域)数据集。然后,我们将使用hyperpt 调整模型的超参数。

符合简单模型

首先,我们读入数据,并为我们的训练集拟合一个简单的 RandomForestClassifier 模型:

**# read in packages
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score# read in the data and info
data = pd.read_csv('../input/water-potability/water_potability.csv')# remove missing values
data = data.dropna()# split to train and test
X = data.drop(['Potability'], axis = 1)
y = data['Potability']
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state=200)# build the model
model = RandomForestClassifier(n_estimators=300, max_features='sqrt', random_state=42)
model.fit(x_train, y_train)
y_pred = model.predict(x_test)# print out the score accuracy
print("Accuracy:", accuracy_score(y_test, y_pred))**

运行上面的代码会产生 67.24% 的精确度。这是可以的,但我们可以通过超参数调整来改善这一点!

设置 Hyperopt

要使用 Hyperopt,我们需要为我们的模型指定四个关键要素:

  1. 目标函数| 这将返回我们希望在计算过程中最小化的值。在我们的例子中,它是“accuracy_score”函数。
  2. 搜索空间| 这定义了给定超参数的取值范围。这可以是整数、浮点数或字符串,我们将在本文后面看到。
  3. 调优算法| 在 Hyperopt 中,有两种主要的超参数搜索算法:随机搜索和 Parzen 估计器树(贝叶斯)。在本例中,我们将使用后者,因为它已知会产生最佳结果。
  4. 评估| 这是指训练模型的不同超参数实例的数量。建议这是搜索空间中定义的超参数数量的 10-30 倍,以优化性能和计算时间。

在下一节中,我们将展示一个示例,说明如何为我们上面创建的简单随机森林模型实现上述步骤。

具有一个超参数的远视

在本例中,我们将只调整一个超参数,即‘n _ estimators’

在 Hyperopt 中首次阅读:

**# read in hyperopt values
from hyperopt import fmin, hp, tpe, Trials, space_eval, STATUS_OK**

现在我们定义我们的目标函数。这将只是“n_estimators”的一个函数,它将返回从“accuracy _ score”函数推断出的减去精度。我们取负值精度的原因是因为 Hyperopt 的目标是最小化目标,因此我们的精度需要为负,我们可以在最后使其为正。

**# define the function we want to minimise
def objective(n_estimators):
    model = RandomForestClassifier(n_estimators=n_estimators,
                                   max_features='sqrt',
                                   random_state=42) model.fit(x_train, y_train)
    y_pred = model.predict(x_test)
    accuracy = accuracy_score(y_test, y_pred)
    return {'loss': -accuracy, 'status': STATUS_OK}**

定义‘n _ estimators’的搜索空间:

**# define the values to search over for n_estimators
search_space = hp.randint('n_estimators', 200, 1000)**

这里, 'hp.randint' 在给定的范围内给' n_estimators '分配一个随机整数,在这种情况下是 200 到 1000。

指定算法:

**# set the hyperparam tuning algorithm
algorithm=tpe.suggest**

这意味着 Hyperopt 将使用“Parzen 估计器树”(tpe) ,这是一种贝叶斯方法。

最后,我们使用‘fmin’函数将它结合起来。‘fn’功能目标是最小化分配给它的功能,这是上面定义的目标。另外,‘max _ evals’指的是我们要测试的不同超参数的数量,这里我任意设置为 200。

**best_params = fmin(
  fn=objective,
  space=search_space,
  algo=algorithm,
  max_evals=200)**

生成的代码块的输出如下所示:

图片作者。

我们看到我们的准确率提高到了 68.5% !然后我们可以调用‘best _ params’来找到产生该模型的‘n _ estimators’的相应值:

**print(best_params)**

输出是:

图片作者。

调整多个超参数

使用与上面相同的想法,我们可以将多个参数作为字典传递到目标函数中。下面的代码块显示了这一点的实现:

**# redefine the function usng a wider range of hyperparameters
def objective(search_space):
    model = RandomForestClassifier(**search_space, random_state=42)
    model.fit(x_train, y_train)
    y_pred = model.predict(x_test)
    accuracy = accuracy_score(y_test, y_pred)
    return {'loss': -accuracy, 'status': STATUS_OK}# new search space
search_space={'n_estimators':hp.randint('n_estimators',200,1000),

              'max_depth': hp.randint('max_depth',10,200),           

            'min_samples_split':hp.uniform('min_samples_split',0,1),                'min_samples_leaf':hp.randint('min_samples_leaf',1,10),

               'criterion':hp.choice('criterion'['gini','entropy']),

           'max_features':hp.choice('max_features',['sqrt', 'log2']) }# implement Hyperopt
best_params = fmin(
  fn=objective,
  space=search_space,
  algo=algorithm,
  max_evals=200)**

注意| * search _ space 意味着我们在这个字典中读入键值对作为 RandomForestClassifier 类内部的参数。***

在这个搜索空间中,除了‘HP . randint’之外,我们还使用了‘HP . uniform’和’HP . choice .’前者选择指定范围内的任意浮点数,后者从指定字符串中选择一个值。

该计算的输出是:

图片作者。

精确度提高到了 69.5%!

然后我们可以调用‘space _ evals’函数来输出我们模型的最佳超参数。

**space_eval(search_space, best_params)**

输出是:

图片作者。

注意 |如果你不使用‘space _ eval’而只是打印字典,它只会给你分类特征的索引,而不是它们的实际名称。

我们走吧!我们刚刚使用 Hyperopt 调整了我们的模型,一点也不困难!

希望你喜欢这篇关于如何简单实现 Hyperopt 的文章!

另一个简洁的特性是,Hyperopt 允许您使用分布式计算,我将在另一篇文章中介绍这个特性。这意味着,如果您有个多核或者在外部计算集群上运行模型,您可以运行多个具有不同超参数的模型。这种方法极大地优化了你的计算时间,这在对非常大的数据集进行训练时非常有用。

如果您想查看撰写本文时使用的完整代码,可以在下面找到:

**https://github.com/egorhowell/Medium-Articles/blob/main/Data Science Basics/Hyperparameter_Tuning_With_Hyperopt.ipynb

我还创建了一个更新版本(2022 年 9 月),您可以在这里找到:

https://github.com/egorhowell/Medium-Articles/blob/main/Data Science Basics/Hyperparameter_Tuning_With_Hyperopt_V2.ipynb

和我联系!

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。执照: CC BY-SA 4.0**

优化弹性搜索中的磁盘使用

原文:https://towardsdatascience.com/optimising-disk-usage-in-elasticsearch-d7b4238808f7?source=collection_archive---------8-----------------------

理解大数据

在处理大量连续的数据流时,这里有三个策略可以减少弹性搜索索引的存储空间

彼得罗·郑Unsplash 上拍摄的照片

近年来,lasticsearch (ES)获得了广泛的关注,因为它提供了一个强大的、可扩展的引擎,可以低延迟地存储和分析大量数据。如果您是处理大量(且快速增长的)数据的数据工程师或数据科学家,您会知道存储优化是构建高质量解决方案的关键组成部分。在本文中,我将讨论使用 es 时优化磁盘使用的三种策略。这篇博文的复制代码可以在 GitHub 上找到。

弹性研究快速入门

在我们开始探索 Elasticsearch (ES)存储优化之前,让我们回顾一些 ES 基础知识。

如果你问,比如说,四个开发人员来描述 ES 是什么,你可能会得到同样多不同的答案。这并不奇怪:ES 可以用作存储引擎,用于应用机器学习来实时建模数据,以及分析事件和日志,等等。此外,ES 可以处理不同的数据类型(结构化和非结构化),而它的分布式特性使它可以处理大量数据。因此,ES 有理由成为各行各业越来越多公司的首选解决方案,包括 Airbnb、优步、沃尔玛、思科和易贝。

要理解 ES 的力量,我们需要理解它的基本原理。Elasticsearch 是一个基于 Lucene 的分布式搜索和分析引擎。当您设置和部署一个 Elasticsearch 集群时,您可以添加不同的节点(服务器)。您的数据和针对 es 索引中的数据运行的查询都分布在这些节点上,所有这些都是自动完成的,以提供可伸缩性和高可用性。

ES 中的数据组织在“指数”中。弹性搜索指数是数据的逻辑分组,遵循一个模式,但该术语也涵盖了通过碎片对数据的实际物理组织。每个索引由一个“一个或多个物理碎片的逻辑分组”组成。反过来,每个碎片都是一个独立的索引。

存储在 ES 索引中的数据是名为“ documents ”的 JSON 对象。这些文档由字段(键-值对)组成,并在“碎片”之间划分,这些碎片分布在各个节点上。每个文档都属于一个“主碎片”和一个或多个“副本碎片”(假设您已经为索引配置了副本碎片)。因此,Elasticsearch 通过由节点和碎片组成的设计来实现冗余,其中包括主碎片和副本。

在接下来的内容中,我将集中讨论优化 es 中数据存储的三个策略:I)设计好你的索引;ii)优化您的索引映射 iii)使用热-暖-冷架构。我们将使用我在之前关于 Elasticsearch 的博客文章中设置的索引。这是 Kaggle 上可用的网飞秀的元数据数据集。我们将逐步优化这个索引。

如果你想了解更多关于提供一个 ES 集群和设置索引的信息,请阅读我在 上的帖子用 Python 创建和管理弹性搜索索引

在我们开始之前,请注意这篇博文中使用的数据仅包含 7787 个“静态”条目,无论如何也不能被归类为“大数据”。然而,本文中讨论的原则可以概括为大数据和流。

策略 1:删减数据并定义自己的映射

首先,冒着说出显而易见的事实的风险:你必须设计好你的弹性搜索指数。这首先要决定什么可以纳入你的指数,更重要的是,什么不可以。比如你需要把你所有的数据都存储在 Elasticsearch 里吗?或者,您是否只需要将 Elasticsearch 作为一个低延迟的存储,用于存储应用程序需要访问的数据子集,而其他数据可以存储在其他地方?如果后一个问题的答案是肯定的,那么您就可以很容易地识别出一些“立竿见影”的效果,并删除多余的数据。

一旦决定了 Elasticsearch 中需要哪些数据,请确保很好地定义了映射。Elasticsearch 能够使用动态字段映射推断您的数据映射。这意味着每当 ES 在文档中检测到一个新的字段时,它会动态地将字段类型添加到映射中。但这并不意味着它以一种最适合数据存储或您所想的目的的方式来实现。

动态字段映射(当[dynamic](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic.html)参数设置为true时)将例如索引字符串字段为 [text](https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html) [keyword](https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html)。你通常只需要这两个中的一个。text字段类型在索引时被分解成单个术语,并允许部分匹配。相反,索引时不分析keyword类型(或者说:“标记化”),只允许精确匹配(在我们的netflix_movies示例中,我们可以对type字段使用keyword字段类型,它取两个值之一——“电影”或“电视节目”)。

为了建立一个基线来比较我们的优化策略,我们将首先使用动态字段映射将网飞电影数据写入一个新的 es 索引,而无需定义我们自己的映射。ES 为我们的netflix_movies数据推断出以下映射:

{
 "netflix_movies_dynamic_field_mapping": {
  "mappings": {
   "properties": {
    "cast": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "country": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "date_added": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "description": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "director": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "duration": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "listed_in": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "rating": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "release_year": {
     "type": "long"
    },
    "show_id": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "title": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    },
    "type": {
     "type": "text",
     "fields": {
      "keyword": {
       "type": "keyword",
       "ignore_above": 256
      }
     }
    }
   }
  }
 }
}

请注意,我们的目标是减少索引的磁盘使用量,即store.size参数。此参数表示集群上索引的主碎片和复制碎片的存储大小。您可以使用 Kibana 控制台中的CAT indexes API来检查您的索引的存储大小。使用动态字段映射,我们得到 17.1 MB 的基线存储大小(参见下面的屏幕截图)。

使用 ES 的动态字段映射存储大小(图片由作者提供)

通过显式定义映射,我们能比我们的基线 17.1 MB 做得更好吗?让我们从我之前的博客文章中的简单(未经优化的)映射开始。除了release_year(我们将它定义为一个整数)之外,我们将所有字段都设为text类型:

netflix_movies的索引存储大小为 9.3 MB,与我们的基线映射相比减少了 7.8 MB(减少了近 46 个百分点。).

使用卡特彼勒索引 APIKibana 控制台上检查 ES 集群上的索引(图片由作者提供)

策略 2:基于映射的优化

减少索引存储大小的第二个策略是优化映射。在定义映射时,有几种选择可以减少存储大小。这里的权衡是在搜索能力和限制索引大小之间:通常,你对存储优化得越多,查询数据的灵活性就越小。

选择正确的字段类型

首先,为您的字段选择正确的数据类型。在我们的netflix_movies示例中,我们可以将typecountryrating字段转换成关键字字段类型,因为这些字段只能采用一些预定义的值,我们可以预期不必使用部分匹配。

还要确保检查你的变量是否适合“更小”的数据类型。例如,我们可以通过使用short而不是integer字段类型来进一步减小release_year的大小。short字段类型是一个 16 位整数。我们改进后的索引如下所示:

与我们的基准 17.1 MB 相比,这一优化的索引使我们的数据减少到了 8.7mb(减少了 49.1%)。与我们未优化的映射(9.3 MB)相比,这表示磁盘使用量减少了 6.5%。然而,如果您正在处理真正大量的数据,即使这些小的百分比也可以代表显著的节省。

不要索引你不需要过滤的内容

其次,您可以对不需要在上过滤的字段禁用索引。索引是为了快速检索而组织的数据。在 ES 中,text字段例如存储在倒排索引中(即:文档—术语→术语—文档),而数字字段类型例如存储在 BKD 树中。

在我们的netflix_movies示例中,从索引中排除的潜在候选对象是durationdescription。前者在连续剧和电影之间的定义并不一致(前者以季为单位,后者以分钟为单位)。如果我想过滤持续时间,我可能会进一步处理这些数据并创建一个新字段。description反过来可能对部分匹配有用,但是让我们假设(为了说明的目的)我们只对通过元数据识别电影感兴趣,然后阅读它们的描述。

为了关闭特定字段的索引,我们将index选项设置为False:

使用这个新映射写入我们的netflix_movies数据会产生一个总大小为 7.5 MB 的索引(与我们之前的迭代相比减少了 3.0%)。

如果不需要相关性分数,就不要规范化文本字段

第三,如果你不需要相关性分数,你可以去掉text字段的标准化因子。归一化因子存储在索引中,用于评分,即给用户定义的查询与文档的相关性附加一个数值的过程。这些标准化因子占用了大量的磁盘空间(即每个字段每个文档一个字节,包括不包含所述字段的文档)。

让我们假设我们对相关性分数不感兴趣,并且我们可以放弃所有文本字段的标准化因子。我们更新后的映射如下所示(注意添加了“norms”: False):

移除所有文本字段的标准化因子后,我们的大小降至 7.3 MB(与之前的优化步骤相比,又减少了 1.2%)。

总之,对于我们的不同优化选项,我们看到了以下索引存储大小和netflix_movies数据的磁盘使用量减少:

策略 3:使用热-暖-冷架构

优化磁盘使用的第三个策略(或者更确切地说:减少磁盘使用的成本)是使用热-暖-冷架构,使用索引生命周期管理(ILM)自动索引翻转

Elastic (ELK)堆栈(即:Elasticsearch、Kibana、Beats 和 Logstash) 的创建者在 2020 年 11 月宣布为他们的 Elasticsearch 服务提供更好的低成本冷层支持官方 ES 服务现在支持可以驻留在对象存储中的冷层,包括 AWS 的简单云存储(S3)谷歌云存储Azure Blob 存储Hadoop 分布式文件存储(HDFS) 以及共享文件系统如 NFS。与暖层相比,冷存储可以将您的集群存储减少 50%

冷层功能是 Elastic 项目生命周期管理的一部分,您可以为数据转换规则定义自己的标准。这意味着你可以在 S3 上以“可搜索快照”的形式更便宜地存储你的旧数据,同时保持查询能力。搜索性能应该与搜索常规索引相当。

将热-暖-冷架构与 ES 结合使用涉及配置生命周期策略来定义索引的热、暖、冷阶段。例如,您可以将索引配置为在设定的天数后,或者在索引达到某个大小限制后,从热状态翻转到暖状态。您可以重复这种模式进行从暖到冷的翻转。

可以通过 Kibana 控制台配置生命周期策略。或者,您可以使用创建或更新策略 API。下面的例子定义了一个策略,如果数据超过 30 天,或者索引的大小超过 20 GB,那么翻转索引,并开始写入新的索引。随后,该策略会在 60 天后将当前索引(已转存的索引)移到暖阶段,并在 75 天后移到冷阶段。

PUT _ilm/policy/netflix_movies_lp
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "20gb",
            "max_age": "30d"
          }
        }
      },
      "warm": {
        "min_age": "60d"
      },
      "cold": {
        "min_age": "75d",
        "actions": {
          "searchable_snapshot": {
            "snapshot_repository": "my-repository"
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

第二步,我们可以将上述策略与进入netflix_movies索引的任何文档相关联:

PUT _index_template/netflix_movies_template
{
  "index_patterns": ["netflix_movies"],                   
  "data_stream": { },
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "index.lifecycle.name": "netflix_movies_lp"     
    }
  }
}

随后,任何被推送到索引的文档都将受到netflix_movies_lp生命周期策略的约束,并逐步从热存储转移到温存储,再转移到冷存储。

关于 ILM 和热-暖-冷架构的最后一个补充说明:Elastic 已经宣布支持冻结层,这也将由可搜索快照驱动。冻结层中的数据不可更改并用于很少访问的文档(有关 Elasticsearch 数据层的更多信息,请点击此处)。然而,在撰写本文时,这项功能还处于试验阶段,还不能用于 Elasticsearch 服务。

还有很多其他的策略来优化 es 中的存储,我在这篇文章中没有讨论,比如应用最好的压缩编解码器,使用更大的碎片,以及减少碎片的数量(使用 shrink API) 。如果你想了解更多关于这些选项的信息,请点击下面的链接。

感谢阅读!您遇到过哪些值得推荐的其他 ES 存储优化策略?请在评论中留下你的建议!

https://medium.com/@ndgoet/membership

如果你喜欢这篇文章,这里还有一些你可能喜欢的文章:

如果你想了解这篇文章中描述的 es 的一些方面和特性的细节,这里有一些我认为有用的资源的概述,按主题组织(这篇文章中使用的所有资源都有全文链接)。

弹性研究的一般原则

弹性搜索中的磁盘和存储优化

关于分层、索引生命周期管理以及 Elasticsearch 的冷层和可搜索快照

免责声明:“elastic search”和“Kibana”是 Elasticsearch BV 在美国和其他国家注册的商标。本文中对任何第三方服务和/或商标的描述和/或使用不应被视为对其各自权利持有人的认可。

请仔细阅读 本免责声明 中的任何内容后再依托 我关于 Medium.com 的文章

使用 Python 优化成对欧几里德距离计算

原文:https://towardsdatascience.com/optimising-pairwise-euclidean-distance-calculations-using-python-fc020112c984?source=collection_archive---------9-----------------------

探索计算距离的方法,希望找到大数据集的高性能解决方案

马修·施瓦茨Unsplash 上拍摄的照片

欧几里德距离是最常用的度量之一,是许多机器学习算法的基础。然而,当一个人面对包含多个特征的非常大的数据集时,简单的距离计算成为令人头痛和记忆错误的来源。

尽管意识到像 SciPy 这样的包提供了健壮的解决方案,我还是忍不住探索了计算距离的其他方法,希望找到大型数据集的高性能方法。

那么,什么是欧几里德距离呢?

我们从公式的快速提示开始,这很简单。给定两个向量 xy ,我们取它们元素的平方差之和的平方根。

那么,为什么我们会出现内存错误呢?

这个问题在处理非常大的数据集时经常出现…现在,假设我们有 1k 个向量,我们需要计算它们的成对距离。这将导致输出矩阵有 1m 个条目,这意味着对于更大的数据量,您很可能会耗尽内存。

对于所有的计算,Python 使用本地内存,并且它不会立即归还分配的内存。这意味着你受到电脑规格的限制。在云服务中工作有助于相应地扩展内存,但是在大多数情况下,你仍然需要并行计算。

尽管内存限制不会消失,但拥有优化的脚本是可取的。

继续计算…

数据集:信用卡客户

为了测试计算距离的不同方法的性能,我需要相当大的数据集。数据集可以在 Kaggle 上获得,也可以通过下面的链接下载。

https://www.kaggle.com/sakshigoyal7/credit-card-customers

在这种情况下,数据集中的一些特征不是很有用,所以我们将使用精简集。

import pandas as pd
cc_customers = pd.read_csv('BankChurners.csv')
cc_customers = cc_customers[['CLIENTNUM', 'Attrition_Flag', 'Customer_Age', 'Gender','Dependent_count', 'Education_Level', 'Marital_Status','Income_Category', 'Card_Category', 'Months_on_book','Total_Relationship_Count','Months_Inactive_12_mon','Contacts_Count_12_mon', 'Credit_Limit', 'Total_Revolving_Bal', 'Total_Trans_Amt','Total_Trans_Ct']]

我们有混合类型的数据集,用人口统计和信用卡相关属性来表示个人客户的信息。

客户信用卡数据中的一些特征

在使用数据作为输入之前,我们需要确保将分类变量转换为数值。

cat_col = ['Attrition_Flag', 'Gender', 'Education_Level', 'Marital_Status', 'Income_Category', 'Card_Category']
for col in cat_col:
    cc_customers[col]=cc_customers[col].astype('category').cat.codes

当处理大型数据集时,特征转换是相当重要的考虑方面,它可以帮助减少矩阵所使用的内存量(不仅如此)。让我们来看看转换发生前后数据框的内存分解。

转换变量前后的内存使用情况比较。

一旦我们将分类变量转换为数字变量,我们可以看到内存的使用大大减少了。

现在我们已经完成了基本的变换,我们可以回到我们的目标,即计算成对的欧几里德距离,在我看来,计算的速度除外。我们有 10127 个独立客户,这将导致矩阵 10127x10127 维。

主脚本

为了理解代码如何与更大的数据集一起伸缩,引入了 for 循环,在每次迭代中,我们考虑来自原始数据的更大的随机样本。我们从 10%的数据开始,每一步我们的样本增加 10%,当涉及到代码的性能时间时,我们取 20 次运行的平均值。

下面的代码用于每一种方法,唯一的区别是距离函数。

import numpy as np
import time
from tqdm import tqdm_notebook as tqdminput_data = cc_customers.drop('CLIENTNUM', axis=1) # drop the customer ID
iter_times = []
for l,z in zip(range(0, 20), tqdm(range(0, 20))):
    times = []
    for r in np.arange(0.1, 1.1, 0.1):
        data_reduced = input_data.sample(frac=r, random_state=1)
        tic = time.perf_counter()
        ###INSERT DISTANCE CALCULATIONS###
        toc = time.perf_counter()
        times.append(toc-tic)
    iter_times.append(times)

tot_time = [sum(i)/20 for i in zip(*iter_times)]
data_size = [len(input_data.sample(frac=r, random_state=1)) for r in np.arange(0.1, 1.1, 0.1)]for i, j in zip(tot_time, data_size):
    print(f"# of customers {j}: {i:0.4f} seconds")

方法 1: Python 包(SciPy 和 Sklearn)

使用 python 包可能是一个微不足道的选择,但是因为它们通常提供相当快的速度,所以它可以作为一个很好的基线。

from scipy.spatial.distance import cdist
from sklearn.metrics.pairwise import euclidean_distances
scipy_cdist = cdist(data_reduced, data_reduced, metric='euclidean')
sklearn_dist = euclidean_distances(data_reduced, data_reduced)

非常有趣的是,Sklearn euclidean_distances 的性能优于 SciPy cdist,随着数据集越来越大,时间上的差异变得越来越明显。

cdist 与欧几里得距离

实现上的差异可能是 Sklearn 包性能更好的原因,因为它使用矢量化技巧来计算距离,这样效率更高。同时,在查看了 cdist 实现的源代码之后,SciPy 使用了双循环。

方法 2:单 for 循环

优化和 for 循环通常不是最好的朋友!然而,当涉及到成对距离时……可能很难避免,除非走向量化路线(实现将在本文后面介绍)。

# Without pre-allocating memory
dist = []
for i in range(len(data_reduced)):
    dist.append(((data_reduced- data_reduced[i])**2).sum(axis=1)**0.5)

# pre-allocating memory
D = np.empty((len(data_reduced),len(data_reduced)))
for i in range(len(data_reduced)):
    D[i, :] = ((data_reduced-data_reduced[i])**2).sum(axis=1)**0.5
return D

我们比较了两种方法,在计算距离之前有和没有预分配内存。

毫不奇怪,预分配内存有助于提高性能,尽管所用的时间仍然超过了 Sklearn 的实现。

尽管在某些情况下性能较慢,但使用这种方法仍然是首选,因为它能够处理更大的数据集,而不会耗尽内存。

方法 3:矢量化实现

在网上阅读了一些关于这个主题的研究论文后,我不得不说,我对这种方法的性能充满了希望。除了看到 Sklearn euclidean_distances 的性能之外,这些希望也变得更大了…

import numpy as np
x = np.sum(data_reduced**2, axis=1)[:, np.newaxis]
y = np.sum(data_reduced**2,    axis=1)
xy = np.dot(data_reduced, data_reduced.T)
dist = np.sqrt(x + y - 2*xy)

对于较小的数据样本,这种方法在时间上非常接近 cdist 实现,但是它的伸缩性不是很好。对于最大的数据样本,时间几乎与不预先分配存储器的循环方法相同。不出所料,它并没有超过欧几里德距离。

总结

在测试了多种计算成对欧氏距离的方法后,我们发现 Sklearn euclidean_distances 的性能最好。因为它使用了矢量化实现,我们也尝试使用 NumPy 命令来实现,但在减少计算时间方面没有太大的成功。

尽管我们再次表明,在大多数情况下,Python 模块提供了最优的解决方案,但有时仍然需要根据任务的性质选择不同的选项。

基于神经网络的引物推荐系统优化 PCR 方案

原文:https://towardsdatascience.com/optimising-pcr-with-automated-primer-selection-using-neural-network-f6b15d209808?source=collection_archive---------27-----------------------

用一个简单的神经网络自动化一个常规的湿实验室任务

四年前,当我在一个病理实验室实习时,我的工作主要是对 DNA 样本进行测序。虽然这是一个相当容易掌握的技术,但对于一个二年级本科生来说,它给了我一个在湿实验室研究的过山车体验。然而,除了常规的移液、离心和混合溶液,我注意到可以系统地自动化和优化方案的初始步骤,即引物选择步骤。

简而言之,测序

DNA 是由 4 个核酸碱基组成的双链结构:腺嘌呤(A)、胞嘧啶(C)、鸟嘌呤(G)和胸腺嘧啶(T);使得一条链上的碱基通常以互补(即排他)的方式与另一条链上的另一个碱基结合(即 A 将与 T 结合,而 C 将与 G 结合)。当突变出现时,这种排他性被打破,并可能导致氨基酸序列的变化,并影响随后的蛋白质翻译过程。我们可以通过测序(也称为基因分型)的过程来询问基因组成。

为了进行 DNA 测序,我们需要首先通过一种称为聚合酶链式反应(PCR)的技术来扩增感兴趣的区域,通过改变温度,双链结构被分离并退火。正是通过这种“热-再-冷-再”的循环,通过聚合酶促进了 DNA 复制,并重复进行,直到获得足够数量的 DNA 片段。

与 PCR 相似,测序也依赖于聚合酶温度的升高和降低。两者之间的主要区别在于它们对核酸碱基的使用。在 PCR 溶液中,所用的核酸碱基仅由脱氧核苷三磷酸(dNTP)组成,而在测序溶液中,所用的核酸碱基由 dNTP 和双 dNTP (ddNTP)组成。ddNTP 和 dNTP 之间的唯一区别是,d dNTP 不允许在复制过程中进一步添加碱基,而 dNTP 允许。你可以想象在测序过程之后,你会得到多个不同大小的 DNA 片段,有些只有 10 个碱基,而有些有 20 或 30 个碱基。此外,如果你在 ddNTP 上放上某种信号,这样当它们放在灯下时会发出颜色,你就能知道第 10、20 或 30 位的核苷酸是什么。这样做足够多次,你可以得到感兴趣基因的完整核酸组成。

引物选择

引物是几个碱基对的短 DNA 片段。引物通常具有与想要启动 DNA 复制过程的 DNA 片段互补的碱基,没有它,聚合酶就不能与 DNA 链结合。

根据经验,可以根据引物的长度和解链温度(Tm)来选择引物。然而,用手这样做不允许人们容易地观察二级结构稳定性和引物发夹的可能出现(当引物不与感兴趣的区域结合,而是与自身结合时,这些情况)。因此,人们可以求助于公开可用的软件,例如由 Thermofischer 开发的软件。然而,正如学术界经常出现的情况,一个软件并不包含所有的功能,不同的软件可以给出不同的结果。因此,这个项目的目的是合并这些软件,并有可能创建一个自动化的引子推荐系统。

方法和游戏计划

熔化温度计算

快速搜索显示,对核苷酸杂交热力学的研究相当广泛,不同的小组给出了不同的计算 Tm 的方法。一些公式相当基础,只需要每个核苷酸的碱基数量,而其他公式,如等式 1 中的公式,则更高级,需要核苷酸配对焓和熵的实验值。但是,要弄清楚如何将不同的值插入一个公式并不完全是火箭科学,通过足够的文献回顾,您可以得到表 1。

等式 1。由 SantaLucia 等人(1996 年)提供

表 1。37℃下 1 M NaCl 中统一的寡核苷酸 dH 和 dS 参数

(英)可视化(= visualization)

许多现有软件缺少的特征之一是引物和 DNA 区域之间杂交的可视化。我们可以将它硬编码到程序中的一种方法是给一条链上的每一个核苷酸分配一个“移位”值,该值对应于另一条链上其互补碱基的位置。

图二。计算稳定性和可视化二级结构的算法的可视化表示

在图 2A 中,对于引物 5’-ccaaggtagtaatgtatattgag-3’中的每个核苷酸,计算机代码指定一个移位值,其对应于其反向序列(或者在引物二聚体的情况下,另一个引物的反向序列)中 3’-5’方向的互补碱基的位置。例如,5’-3’方向上的最后一个碱基 G 具有-1 和 0 的移位值,因为从 3’-5’方向上的那个位置开始计数,有两个互补的碱基,一个在相同的位置(0),另一个在前一个位置(-1)。在图 2B 中,通过在所有核苷酸上提取相同的移位值,可以随后可视化二级结构中发生的所有杂交事件。例如,通过将 5’-3’引物的 6 个位置定位在其反向序列的右侧,可以构建具有 6 个键的自身二聚体结构。在图 2C 中,使用相同的移位值,也可以描绘出发夹结构,其中在最里面的两个键之间形成的环的大小必须总是大于或等于三个核苷酸。此外,任何二级结构的热力学值都计算为每个键形成所需能量的总和。

在 python 中,移位值列表可以用几行列表理解代码进行硬编码:

从那时起,我们可以画出盒子和棍子来可视化杂交事件:

引物选择推荐系统:

另一个快速文献综述为我们提供了以下引物选择标准:

表二。好底漆的标准

虽然我们可以将标准硬编码到我们的程序中,并让它输出我们选择的引物是否满足所有标准,但我们可以更进一步,创建一个推荐系统,扫描给定感兴趣基因中所有可能的引物,并根据它们的适用性对它们进行排序。

为此,我们可以首先建立一个引物数据库,然后训练一个模型,将一个模型分为好的或坏的,或者给它们分配一个适合性得分。在这种情况下,我选择了分类模型。在这里,我生成了一组 78 206 个不同长度的引物对,长度在 8 到 41 个碱基之间。它们是由计算机从三种不同的基因中随机产生的。从该数据集中,12 600 个随机组合被标记为“好”或“坏”。“不良”引物被定义为在表 2 的 9 个特征之一中具有异常值的引物。为了实现所有参考点的完全均匀分布,“不良”引物组由 9 个统一的特征类别组成,每个类别有 700 对。

模特培训

标记数据集分为训练集(70%)、交叉验证集(20%)和测试集(10%)。在这里,我利用 R 神经网络包来优化 ANN 模型的计算和可视化,并采用了带权重回溯的弹性反向传播(rprop+)方法,其中学习速率根据偏导数的符号在 0.5(-)和 1.2(+)之间变化。

图 3。训练好的人工神经网络模型

我的第一个 GUI

我注意到现有软件的一个问题是它们的功能脱节,在显示结果时缺乏透明度。利用 Python 中的 tkinter 库,我创建了一个具有以下特征的界面:1)可定制的输入,2)实时结果可视化和计算,以及 3)有组织的输出。

图 4。帮助界面

图 5。结果的实时可视化

图 6。有组织的输出和透明的结果

相对重要性

一旦在训练过程之后将权重分配给 9 个特征中的每一个。我们可以看到哪些特征最能决定引物选择的适宜性。

图 7。基于人工神经网络模型的权重排序

正如所怀疑的,Tm 和长度的差异起着最重要的作用,其次是 GC 含量和其他二级结构。最后,我们可以将这样的权重硬编码到我们的程序中,并可以将每个引物标记为好或坏。

结论

这是一个有趣的练习,在这里我学会了如何从头开始创建一个 GUI,并实现一个简单的 ML 模型到日常的湿实验室工作中。实际上,这不太可能造成很大的差异,因为在大多数情况下,即使是一个稍微差一点的引物也可能在 PCR 实验中发挥相当好的作用。然而,二级结构杂交确实会发生,这仅在使用超过 50 bp 的非常长的引物时才会成为问题,且当这种情况发生时,在 PCR 溶液中有其它优化的化学成分来解决该问题。然而,如果你想试试这个 GUI,你可以在下面找到它。

https://github.com/lehai-ml/primer-design

参考

  1. 小 Santa Lucia Allawi,H.T .,Seneviratne,p . a .(1996 年)。预测 DNA 双链稳定性的改进的最近邻参数。生化 35,3555–3562。

使用 tf.data 优化输入管道性能(第 1 部分)

原文:https://towardsdatascience.com/optimising-your-input-pipeline-performance-with-tf-data-part-1-32e52a30cac4?source=collection_archive---------6-----------------------

提高您的输入管道效率和 GPU 利用率

Tensorflow 徽标。来源:https://www.tensorflow.org/

tf.data 的概念

API 使您能够从简单的、可重用的部分构建复杂的输入管道。tf.data也使处理大量数据成为可能,从不同的数据格式中读取,并执行复杂的转换

要知道 GPU 和 TPU 可以显著减少训练一个模型所需的时间,这并不是什么大事情。然而,作为一名深度学习开发者,最糟糕的事情之一是看到你的 GPU 能力没有得到充分利用,CPU 上的瓶颈——特别是如果你在不同的云平台上为这些服务支付大量资金。

因此,确保我们的输入管道实现最佳性能和效率至关重要。tf.data API 直接处理这个问题——这也是我如此喜欢它的原因。

在这篇第 1 部分文章中,我将解释关于tf.data如何实现最佳行为的不同概念,在第 2 部分,我将比较tf.data和 Keras ImageDataGenerator读取输入数据的性能。

tf.data有几种方法可以降低计算开销,这些方法很容易在您的管道中实现:

  • 预取
  • 并行数据提取
  • 并行数据转换
  • 贮藏
  • 矢量化映射

天真的方法

在我们开始这些概念之前,我们必须首先理解当一个模型被训练时,朴素方法是如何工作的。

天真的方法。来源:https://www.tensorflow.org/guide/data_performance

此图显示训练步骤包括打开文件、从文件中获取数据条目,然后使用数据进行训练。我们可以在这里看到明显的低效率,因为当我们的模型正在训练时,输入管道是空闲的,而当输入管道正在获取数据时,我们的模型是空闲的。

tf.data通过使用prefetching解决了这个问题。

预取

预取解决了天真方法的低效率,因为它旨在重叠训练步骤的预处理和模型执行。换句话说,当模型执行训练步骤 n 时,输入管道将读取步骤 n+1 的数据。

tf.data API 提供了tf.data.Dataset.prefetch转换。它可用于将数据产生的时间与数据消耗的时间分离开来。特别是,转换使用后台线程和内部缓冲区在请求元素之前从输入数据集中预取元素。

预取。来源:https://www.tensorflow.org/guide/data_performance

有一种观点认为预取转换需要预取的元素数量。然而,我们可以简单地利用 tensorflow 提供的tf.data.AUTOTUNE,它提示tf.data runtime 在运行时动态地调整值。

并行数据提取

在读取数据时将原始字节加载到内存中会产生计算开销,因为可能需要对读取的数据进行反序列化和解密。无论数据是存储在本地还是远程,都存在这种开销。

为了处理这种开销,tf.data提供了tf.data.Dataset.interleave转换来并行数据加载步骤,交错其他数据集的内容。

类似地,这种交错转换支持tf.data.AUTOTUNE,它将在tf.data运行时再次委托并行级别的决策。

顺序交错。来源:https://www.tensorflow.org/guide/data_performance

并行交错。来源:https://www.tensorflow.org/guide/data_performance

并行数据转换

在大多数情况下,在将数据集传递给模型进行训练之前,您必须对数据集进行一些预处理。tf.data API 通过提供tf.data.Dataset.map转换来解决这一问题,该转换将用户定义的函数应用于输入数据集的每个元素。

由于输入元素相互独立,预处理可以在多个 CPU 内核上并行进行。

要利用多个 CPU 内核,您必须传入num_parallel_calls参数来指定您想要的并行级别。类似地,map 转换也支持tf.data.AUTOTUNE,它将在tf.data运行时再次委托并行级别的决策。

天真的映射。来源:https://www.tensorflow.org/guide/data_performance

平行映射。来源:https://www.tensorflow.org/guide/data_performance

贮藏

tf.data还拥有tf.data.Dataset.cache转换的缓存能力。您可以在内存或本地存储中缓存数据集。经验法则是在内存中缓存小数据集,在本地存储中缓存大数据集。这样就避免了像文件打开和数据读取这样的操作在每个时期被执行——下一个时期将重用由cache转换缓存的数据。

需要注意的一点是,您应该在预处理之后(尤其是当这些预处理函数计算量很大时)和增强之前进行缓存,因为您不希望存储任何来自增强的随机性。

缓存。来源:https://www.tensorflow.org/guide/data_performance

矢量化映射

当使用前面“并行化数据转换”中提到的tf.data.Dataset.map转换时,会有一些与调度和执行用户定义函数相关的开销。向量化这个用户定义的函数——让它一次对一批输入进行操作——并在map转换之前应用batch转换有助于改善这种开销。

批处理前映射。来源:https://www.tensorflow.org/guide/data_performance

批处理后映射。来源:https://www.tensorflow.org/guide/data_performance

从图中可以看出,开销只出现一次,从而提高了整体时间性能。因此,与对每个样本调用map转换相比,对一批样本调用map转换具有更好的性能。

最后

tf.datatensor flow 充分考虑了输入管道的性能,采用多种方式优化效率。

总之,您可以使用prefetch转换来重叠管道(生产者)和模型(消费者)所做的工作,使用interleave转换来并行化数据读取,使用map转换来并行化数据转换,使用cache转换来在内存或本地存储中缓存数据,并且使用batch 转换来矢量化您的map转换。

正如开始时提到的,最糟糕的事情之一是看到你的 GPU 能力没有被充分利用,CPU 上的瓶颈。有了tf.data,你很可能会对你的 GPU 利用率感到满意!

GPU 利用率。来源:来自本地机器的截图

在第 2 部分中,我将演示如何将tf.data用于您的输入管道,并测量tf.data和 Keras ImageDataGenerator之间的性能

[## 使用 tf.data 优化输入管道性能(第 2 部分)

towardsdatascience.com](/optimising-your-input-pipeline-performance-with-tf-data-part-2-9ee406451f93)

资源

  1. https://www.tensorflow.org/guide/data_performance

使用 tf.data 优化输入管道性能(第 2 部分)

原文:https://towardsdatascience.com/optimising-your-input-pipeline-performance-with-tf-data-part-2-9ee406451f93?source=collection_archive---------16-----------------------

提高您的输入管道效率和 GPU 利用率

来源:ka gglehttps://www . ka ggle . com/jalammar/intro-to-data-input-pipelines-with-TF-data

在第 1 部分中,我重点介绍了 aim 中的不同概念tf.data,以优化您的输入管道性能。我们希望确保输入管道上不存在瓶颈,以便充分利用我们的 GPU 使用。

现在,在第 2 部分中,我将展示一个在输入管道中使用tf.data和 keras ImageDataGenerator的实际例子,测量两者之间的性能。

使用 Keras **ImageDataGenerator** :

使用 Keras ImageDataGenerator 加载数据

利用 **tf.data** :

使用 tf.data 加载数据

测量 **tf.data** **ImageDataGenerator** : 的时间性能

测量时间性能

请注意,在这两个示例中,输入数据是从本地机器而不是远程云存储中读取的,并且没有做任何预处理工作。目录结构应该如下所示:

dir_path应该是 pictures 文件夹的路径,而folders是由 pictures 文件夹中的文件夹名组成的数组——在我的例子中,它是我的 train 和 validation 文件夹。

目录结构。来源:来自本地机器的截图

结果对tf.data更有利,比 Keras ImageDataGenerator快两倍多。

注意,对于我们的tf.data生成器,它返回一个类型< float,string >,因为我们已经在函数中定义了标签。如果你想让生成器返回< float,改为 float >,你必须将函数中的标签解析成相应的 float——为了训练你的模型。

此外,在这个tf.data示例中,由于我使用的数据集很大,我将缓存存储在本地存储中,而不是内存中。如果数据集足够小,可以放入内存中,那么将缓存存储在内存中会使性能稍微好一点。

结论

与 Keras ImageDataGenerator相比,tf.data提供了更高效的输入管道。有了一个更有效的输入管道,你就可以更好地利用 GPU 来训练你的模型,因为瓶颈不再在输入管道上了!希望你喜欢这些文章。谢谢大家!

来源

https://medium . com/swlh/dump-keras-imagedata generator-start-using-tensor flow-TF-data-part-1-a 30330 BDB ca 9

机器学习的优化算法

原文:https://towardsdatascience.com/optimization-algorithms-for-machine-learning-a303b1d6950f?source=collection_archive---------17-----------------------

第六章:优化问题

丹尼斯·伊罗雷雷Unsplash 上拍摄

前一章的链接,第 5 章:解决优化问题的先决条件在这里是。第 6 章是这个系列的一部分,从这里我们开始研究真正的优化问题并理解优化是怎么回事。在前面的章节中,我们只研究了有助于我们更好地理解优化的概念。我觉得这是优化的乐趣所在。在本章中,我们将了解:

  • 最优化问题的标准形式
  • 可行和最佳点
  • 全局和局部最优点
  • 凸优化问题
  • 一阶最优条件
  • 凸优化问题的特殊情况
  • 等价凸优化问题
  • 线性和二次优化问题
  • 一些重要的提示
  • 一些问题的解决

我们在 第一章看到了优化问题的一般形式:简介 这里。现在,我们将再次访问通用表单,但会更加详细。因此,优化问题的一般或标准形式由给出:

注意,目标函数是我们要最小化的函数,f(x)的下确界意味着 f(x)的最小值,并且优化问题的域是目标函数的域与等式和不等式约束的域的交集。但是,这里可能出现的问题是,如果问题不是最小化目标函数,而是最大化目标函数呢?因此,在这种情况下,我们仍然必须将问题带到标准优化形式中,以便能够以适当的方式应用优化属性。那么,我们如何将一个最大化问题带入标准的优化形式呢?事实上这很简单。请看下面:

注意,所有的优化问题不一定都是凸优化问题。

现在,让我们看看可行点是什么。位于优化问题的域中的任何点,即,位于目标函数的域中并且满足约束的点,被称为可行点。并且,我们可以说一个最优化问题是可行的,如果它至少有一个可行点。所有可行点的集合称为可行集。该集合表示为:

接下来,我们将看到什么是最佳点。我们说 x 点是最优的,如果:

既然我们已经研究了什么是最优化问题,我们将看看凸最优化问题。

解:对于一个凸优化问题,目标函数和不等式约束(姑且称函数 f(x))需要是凸函数,等式约束(姑且称函数 g(x))应该是仿射函数。目标函数肯定是凸函数,因为它具有抛物面的形式。然而,在检查 f(x)的 Hessian 矩阵时,我们看到它不是半正定的(你可以自己计算和检查)。另外,g(x)不是仿射函数。所以这个问题不是凸优化问题。然而,这并不是故事的结尾。我们肯定可以把问题变成一个凸优化问题。

现在我们已经正确理解了凸优化问题应该是什么样子,让我们看看凸可微函数的一阶最优性条件是什么。在也是可微的凸优化问题中,x 是最优的当且仅当 x 是可行的并且满足以下条件:

可行集边界上的最优点(图片由作者提供)

在上图中,X 是一个函数所有可行点的集合。几何上,最优点 x 位于可行集的边界。点 x 处的梯度将形成可行点的支撑超平面。这是因为我们从第 3 章这里知道,一个集合的支撑超平面是一个集合中所有点都位于它的一边的超平面。因此,我们可以说,如果 x 是最优的,∇f(x)是最优集的支撑超平面。

这个条件肯定有数学上的证明,但是我们不需要深究。另外,请注意,如果 x 是最优点,在给定约束的情况下,f(x)应该具有目标函数的最佳值。

在这一节中,我们将研究凸优化问题的一些特殊情况。它们是无约束凸优化问题、等式约束凸优化问题和非负正交上的极小化问题。所以,让我们从第一种情况开始:

  1. 无约束凸优化问题:这个其实挺简单的。下面看看。

2.等式约束凸优化问题:在这种情况下,凸优化问题只有一个等式约束。这种类型的示例如下所示:

最小化 f(x);服从:Ax = b

3.非负正交上的最小化:需要注意的是,非负正交基本上是指 N 维空间中的非负区域。这种特殊情况将由以下人员给出:

现在我们已经看到了什么是凸优化问题,让我们来看看等价凸问题。如果一个问题的解很容易从另一个问题的解中获得,那么两个问题是等价的(非正式的),反之亦然。在这种情况下,有助于保持凸性的一些常见变换是:

3.引入松弛变量:松弛变量是引入不等式约束以使其成为等式约束的变量。这通过以下方式给出:

因此,我们已经看到当我们使用等价凸优化问题时,在问题的凸性没有丢失的意义上,等价凸优化问题如何能够帮助保持凸性。

在这一节中,我们将研究几类凸优化问题。我们将研究线性和二次优化问题。

应当注意,在这种情况下,目标函数和约束函数都是仿射函数。同样,这种情况下的可行集是多面体。

要注意的是,目标将不是仿射函数,而是二次函数。另一方面,约束函数在这种情况下都是仿射函数。

请注意,我们将在后续章节中详细研究这些问题。至此我们结束了这一章的理论部分。

当我们考虑凸集和函数时,让我们看看一些需要记住的要点。

  • 如果一个函数的所有子水平集都是凸的,那么这个函数不一定是凸的。例如,拟凸函数的次水平集是凸的,但函数本身可能不是凸的。
  • 一个拟凸函数的上图不是凸的,因为如果一个函数的上图需要是一个凸集,那么这个函数必须是一个凸函数。
  • 如果一个方阵的所有元素都是正的,那么这个函数要么是半正定的,要么是正定的。
  • 凸函数永远不能定义在非凸集合上。
  • 凸优化问题可能不总是有最优解,尤其是当问题不可行时。

现在,让我们来看一些问题。

问题 1:

问题二:

下面这个问题是凸优化问题吗?如果不是,就把问题转化为凸优化问题,求函数的最优值,最优点,画出可行集。

可行集的绘图(图片由作者提供)

上面的粗线满足约束和目标函数。因此,它是可行集。

就这样,我们来到了本章的结尾。

机器学习的优化算法

原文:https://towardsdatascience.com/optimization-algorithms-for-machine-learning-d98d0feef53e?source=collection_archive---------19-----------------------

第四章:重要的凸函数和凸性质

图片来源:https://www . wallpaperflare . com/clear-crystal-wine-glass-drinking-glass-macro-red-close-up-wallpaper-hut mt

T 何链接 第三章:一些重要的凸集 就是这里的。第四章是关于一些将帮助我们更好地理解最优化,甚至帮助我们解决最优化问题的主题。这些主题大多与凸函数的不同性质有关。我们将在本章中讨论的主题有:

  • 仿射组合和仿射空间
  • 圆锥组合与圆锥壳
  • 碑文
  • 詹森不等式
  • 保持凸性的运算
  • 拟凸函数

我们离本系列有趣的部分不远了,在那里我们将处理真正的优化问题。所以坚持住。本章将围绕凸集和函数的性质展开。此外,不要忘记查看我在第三章中提出的问题的解决方案,在本章的最后。

在我们开始学习矢量的仿射组合之前,我们需要稍微回顾一下,看看什么是矢量的线性组合。向量的线性组合由下式给出:

类似于向量的线性组合,向量的仿射组合只不过是向量的线性组合,使得系数的总和为 1。这表现为:

现在,让我们看看仿射跨度。集合中所有向量的仿射组合的集合称为仿射跨度。因此,用“y”表示的仿射跨度为

让我们看一个上述概念的实际例子。

向量的线性和仿射组合(图片由作者提供)

在上图中,你会注意到,矢量 V1 和 V2 的任何仿射组合都将位于同样具有矢量 3V1+(-2V2)的黑线上。注意 3+(-2) = 1。因此,黑线是向量 V1 和 V2 的仿射跨度。这意味着 V1 和 V2 向量的任何组合,使得系数之和为 1,将位于黑线上。这也可以从理论上证明。考虑 V1 和 V2 的仿射组合的任何向量。因此,

比较等式 1 和 2,我们可以说,满足 V1 和 V2 的仿射组合的任何向量也将位于 V1 和 V2 的连线上。同时,如果你比较仿射跨度的一般方程和凸集的一般方程,你会发现方程几乎是相同的。因此,仿射跨度或仿射空间是凸集。在集合生成器符号中,仿射空间由下式给出:

在线 x+y=3 的上述等式中,x 可以用 x1 代替,y 可以用 x2 代替。很明显,x 属于 2D 空间,因此 n=2。同样,b 只有 1 个值。所以,m=1。因此,A 的维数为 mXn,能够乘以“x”产生“b”,在本例中为 1x2。

在这里,我有一个问题要问你。如果 n 个向量的线性组合位于一个 n 维空间,你认为这些向量的仿射组合位于哪个维空间?要找到答案,请看下一章的最后一节这里

现在让我们看看圆锥曲线组合。圆锥组合类似于仿射组合,但在约束上有所不同。但是,让我们先了解一下什么是凸锥。

构成圆锥体的向量(图片由作者提供)

从上图中,我们可以说,所有这样的射线,即位于射线中的一个点的一组不同的正倍数,有助于形成一个圆锥。穿过矢量点 V1 和 V2 的光线形成了圆锥体的边界。

2D 的凸锥(图片由作者提供)

现在我们知道了凸锥,让我们看看什么是锥壳。这个概念与凸包非常相似。集合 S(圆锥 S)的圆锥壳是包含 S 的最小凸锥。它是 S 中所有可能的圆锥组合的集合。在集合生成器符号中,圆锥壳定义为:

下图显示了一个圆锥和一个凸面(红色)外壳。黑点构成集合 s。由蓝色光线形成的圆锥壳构成可以容纳集合 s 的最小圆锥。圆锥壳的应用类似于凸包的应用,只是在这种情况下,相关的边界形状仅限于圆锥。

一个凸壳和一个圆锥壳(图片由作者提供)

在这里,我有一个问题要问你。你认为凸圆锥或圆锥壳在三维空间中会是什么样子?要找到答案,请看下一章的最后一节

在这一节,我们将探讨词牌的概念。函数 f(x)的上图,其中 x ∈ S 是所有点(x,α)的集合,使得 f(x)≤α。迷茫?不要这样。请参考下图,了解这意味着什么。参考如下所示的 2D 空间:

凸函数的题词(图片由作者提供)

注意,α的值必须相关,并且不能小于 f(x)的最小值。要注意的是,点的集合(x,α)位于比集合 S 所在的维度高一个维度的维度中。在这种情况下,x 位于一维直线上,题词位于二维平面上。同样,如果 y=α,那么 S1 和 S2 定义了函数的次水平集。就像上图一样,一个函数是凸的当且仅当它的子水平集也是凸的。在上面的例子中,函数 f(x)的次水平集是一条连接 S1 和 S2 的直线,我们知道这条直线由一个仿射跨度给出,仿射跨度是一个凸集。所以,函数 f(x)也是凸的。在集合生成器符号中,函数的子级集合被定义为:

集合构造符号中凸函数的上图由下式给出:

下面是一个三维凸函数的题词。阴影空间形成上图,子水平集由 x-y 平面中的正方形形成。

三维凸函数的题图(图片由作者提供)

现在,可以说函数 f 是凸的,当且仅当它的上图是凸集。为了形象化这一点,取上图中任意两点 x1 和 x2。你会注意到,x1 和 x2 连线上的所有点都在词牌内部。这方面的数学证明如下所示。在这种情况下,我们将不得不从双方证明财产。这意味着我们将不得不取一个凸函数,并证明它的上图是一个凸集。之后我们将得到一个凸上图集,并证明相应的函数是凸函数。

从上面的不等式可以说 f 是凸函数。这样,证明了如果 f 是凸函数当且仅当它的上图是凸集。

在本节中,我们将看到什么是詹森不等式。请参考下图。

在上面的例子中,我们有有限数量的元素。将这个想法扩展到无限多的元素,我们得到:

在这一节中,我们将试图从数学上证明一些重要函数是凸函数。

在下一节中,我们将研究一些保持凸性的运算和凸函数的一些性质。保持凸性基本上意味着对凸集的这些运算的结果会产生一个不同的凸集。注意,我们已经在第二章中详细看到了其中的一些运算:凸集和函数 这里 不过,我还是会在这里提到它们,以保持一个完整的列表。注意,下面 3 点与凸集有关,与凸函数无关。

  • 任何凸集的交集的结果集也是凸集。
  • 两个凸集的向量和结果是一个凸集。
  • 集合αC 对任何凸集合 C 和标量α都是凸的。

请注意,这些是在第 2 章中已经详细介绍过的。下面是一些保持凸函数凸性的新运算。

  • 如果由 f(S)给定的集合 S 的像是凸的,那么如果函数 f 是仿射函数或透视函数或线性分形函数,则前像 S 也将是凸的。透视和线性分形函数不是很重要,尽管这些函数的形式如下所示:

  • 设 f1,f2,…,fn 是定义在同一个域 d 上的凸函数,那种情况下这些函数的非负加权和,f(x)=w1f1(x)+w2f2(x)+…+wnfn(x)也将是凸函数,其中 wi > 0。例如,下面的函数 f(x)是凸函数:

  • 如果 f 和 g 是定义在同一个域 D 上的凸函数,那么 f+g,αf (α>0)和 max{f(x),g(x)}都是凸函数。让我们来看看 f+g 情况的一个证明:

对αf (α>0)和 max{f(x),g(x)}的证明也可以同样地给出。

  • 如果一个函数 f(x)是凸的,另一个函数 g(x)是仿射函数,那么由 f(g(x))给出的 f(x)和 g(x)的合成是凸的。示例:

现在让我们看看凸函数的一些性质。

  • 凸函数不一定是可微的。此外,它不需要在封闭区间集内连续,因为函数在封闭区间的终点可能不连续。然而,一个凸在一个开区间中总是连续的。我们从高中数学中知道,连续的意义就是函数在任何一点都不应该破。对 f 域中任意点 p 连续性的检查如下所示:

连续和非连续函数的一些例子如下所示:

作者图片

同样,函数 f 是可微的,如果它的导数存在于定义域的每个点上。可区分性检查如下所示:

可微和不可微函数的示例如下所示:

作者图片

  • 凸集 S⊆ℝ上的凸函数 f 的每个局部极小值都是全局极小值。让我们首先试着理解什么是局部最小值和全局最小值。考虑定义域为 s 的任何凸函数 f。因此,f(x)的局部极小值在 f(x)定义域中的一点上意味着:

同样,f(x)的全局最小值在 f(x)的定义域中的点 x̄处,如下所示,将意味着:

现在,让我们看看这一财产的基础是什么。下面是物业的证明。我们将在这里使用矛盾证明。

  • 设 f1,f2,…,fk 是定义在同一个域 D 上的凸函数,那么函数 f(x)=max{f1(x),f2(x),…,fk(x)}也是一个凸函数,其中 dom f=dom f1∩dom f2。这被称为逐点最大值。让我们来看一个例子。

  • 凸函数的下一个性质与一个叫做上确界和下确界的概念有关。因此,集合 S 的上确界是大于集合 S 的最高值的最小值。类似地,集合 S 的下确界是小于集合 S 的最小值的最高值。请参考下图以更好地理解。考虑一个定义在实数线上的集合 s,ℝ.

集合的上确界和下确界(图片由作者提供)

所以,该性质说,一族任意凸函数 f1(x),f2(x),…,fn(x)的上确界和下确界也是凸函数。凸函数的上确界如下所示:

类似地,凸函数的下确界如下所示:

在这一节中,我们将研究一种非常有趣的函数,叫做拟凸函数。那么,拟凸是什么意思呢?意思是“仿佛凸”。进一步扩展这一点,拟凸给人一种弱凸感。它不是一个恰当的凸函数,而只是它的一个弱概念。定义拟凸函数有两种不同的方法。

理解拟凸集的另一个定义使用了轮廓的概念。那么什么是等高线呢?轮廓只不过是某物的边界。这个东西可以是任何东西,比如一座山,一个雕塑,一件器具。在我们的例子中,我们将使用集合的轮廓。因此,拟凸函数的第二个定义是:

拟凸函数和下等高线/分段图(图片由作者提供)

拟凸函数的另一个例子(图片由作者提供)

就这样,我们走到了这一章的结尾。

在前面的 第三章:一些重要的凸集 中,我问的第一个问题是“你认为过原点的超平面所创建的半空间的方程会是什么?”答案很简单。

我问的第二个问题是“你能告诉我上图中范数球的向量的大小吗?”这就更简单了。其范数球已被显示的向量的大小是‘r’,这是如图所示的半径。

继续下一章,第 5 章:解决优化问题的先决条件这里

机器学习的优化算法

原文:https://towardsdatascience.com/optimization-algorithms-for-machine-learning-e794f2e7dfa7?source=collection_archive---------27-----------------------

第 5 章:解决优化问题的先决条件

约翰·莫斯·鲍恩在 Unsplash 上的照片

的链接第四章:重要凸函数和凸性质这里的就是。第五章是关于我们在深入凸优化之前需要考虑的一些最终主题。顾名思义,你可以考虑这些凸优化的先决条件。请注意,当我们稍后解决优化问题时,这些概念将非常重要。因此,本章的重点是数学概念。将涉及的主题有:

  • 标量和向量值函数
  • 梯度的图形解释
  • 海森矩阵
  • 半正定矩阵
  • 可微凸函数
  • 一阶和二阶凸性条件
  • 主要次要测验
  • 特征值在确定凸性中的作用
  • 功能组成
  • 一些问题的解决

所以,让我们从标量和向量值函数开始。这些概念相当简单。接受一个或多个值,但返回单个值的函数称为标量值函数。标量值函数的示例如下所示:

从上面的等式中可以看出,该函数有 3 个输入(x、y 和 z ),只有一个输出。因此,该函数是一个标量函数。一个 n 变量标量值函数映射自—

更好地理解这一点的一个例子是抛物面函数,由下式给出

现在,我们将研究什么是向量值函数。向量值函数是那些接受一个或多个变量但产生输出向量的函数。二维中的一个例子是:

抛物面和 x-y 平面上的二维向量空间的俯视图(图片由作者提供)

在本节中,我们将研究梯度的图形解释。我们在前面的章节中已经看到,在 2D,三维图形的梯度是矢量。因此,如果三维图的中心位于原点,则三维图的梯度向量将远离中心。参考下图,图中显示了抛物面在 x-y 平面上的梯度向量空间。

抛物面在 x-y 平面上的梯度矢量点(图片由作者提供)

抛物面的 x-y 平面上的梯度向量空间如上所示。正如你所看到的,点 p 和 q 在抛物面上的投影已经用点ṕ和α表示出来了。ṕ和α代表抛物面上点 p 和 a 的梯度向量。类似地,向量空间(所有向量所在的空间)表示抛物面中所有点的梯度。想象你正在爬上抛物面。假设你在 P 点,你想知道走的方向,为了最快到达抛物面的顶部。从下面看抛物面,我们可以看到,为了最快地爬上抛物面,我们需要直接离开原点。这是因为在直接远离原点的方向上,抛物面最陡。因此,梯度指向最陡下降的方向,基本上是曲线的切线,在这种情况下是抛物面。参考下图可以更好地理解这一点。

从底部看抛物面和向量空间(图片由作者提供)

在上图中,蓝色的向量代表最陡的方向,因此是梯度向量。用黑色显示的向量代表其他不是最陡的运动方向。还要注意,曲线上一点的梯度向量的长度告诉我们曲线在该点的陡度。

在本节中,我们将了解什么是海森矩阵。我们不会马上进入 Hessian 矩阵的应用程序,但会随着系列的进展深入研究这些应用程序。现在,我们只会试着理解这个矩阵是什么。海森矩阵是一个函数的二阶偏导数的方阵。Hessian 矩阵用于识别函数在特定点的局部最小值和局部最大值。Hessian 矩阵的一般形式如下所示:

这里需要注意的是,如果一个函数在某一点的 Hessian 小于 0,那么这个点就是局部极大值。另一方面,如果该值大于 0,则该点是局部极小值。一会儿我们会看到更多的这个概念。

现在,我们将研究什么是半正定矩阵。可以理解半正定矩阵的方式是,假设我们有一个沿特定方向移动的向量 Z。如果这个向量 Z 被一个矩阵 A 击中,使得向量改变方向小于 90°,那么我们称这个矩阵是半正定的。这可以使用下图来显示。

半正定矩阵的图形解释(图片由作者提供)

半正定矩阵的数学定义是:

注意,半正定矩阵的概念将用于确定一个函数是否是凸的。

在这一节,我们将研究什么是可微凸函数。这里不会真正深入,只知道函数可微时需要成立的条件。可微凸函数的这一性质将在下一节中用到。因此,特性如下所示:

在这一节中,我们将研究一阶和二阶凸性条件。这些条件决定了函数是否是凸的。让我们研究一下一阶凸性条件。

理解一阶凸性的图表(图片由作者提供)

既然我们已经理解了一阶凸性条件的图形解释,也就有了上述性质的数学证明。让我们来看看。

现在,让我们来证明故事的另一面:

这里让我们看一个函数的例子,用上面的性质证明它是凸函数。

现在,我们将研究二阶凸性条件。这由下式给出:

现在,让我们看看原理小测是什么。我们不会涉及太多的细节和这个测试背后的逻辑。我们将简单地研究一下这个测试是如何完成的。注意,主要的次要检验将用于确定一个函数是否是半正定的。为了使用这个测试,我们需要找出函数的 Hessian 矩阵,并遵循下面提到的步骤:

需要记住的一点是,只有当函数的 Hessian 矩阵的所有元素都是常数时,主检验才有效。当然,这些盒子的数量会随着矩阵维数的增加而增加。

现在,我们将看到特征值如何帮助我们确定一个矩阵是否是半正定的。同样,我们不会真正进入细节,但我们会看看特征值是如何工作的。如果矩阵的特征值大于或等于 0,则该矩阵是半正定的。那么,我们如何计算特征值呢?

这告诉我们这个矩阵是正定的。注意,如果两个特征值都大于 0,那么矩阵就是正定的。另一点要注意的是,单位矩阵总是半正定的。

现在,我们将看看凸函数的一个非常有趣的性质。这一特性是用 c 语言的函数组合来描述的。这意味着给定一个函数 g(x)=f(h(x)),那么,

  1. g 是凸的,如果—
  • h 是凸的,f 是凸且非减的。为了理解什么是非减函数,请看下图。这几乎是不言自明的。你会注意到图中没有一点的斜率小于 0。

非递减函数(图片由作者提供)

  • h 是凹的,f 是凸的,非递增的。非递增函数的示例如下所示:

非递增函数(图片由作者提供)

在这种情况下,g 的几个例子如下:

2.g 是凹的,如果—

  • h 是凹的,f 是凹的且非减的
  • h 是凸的,f 是凹的,非递增的

至此,我们结束了本章的理论部分。在下一节中,我们将解决一些问题,以更好地理解到目前为止我们所看到的概念。

下一章,第 6 章:优化问题,点击这里

这是解决问题的部分。希望那些热爱解决数学问题的人会喜欢这一部分。

问题 1:

问题 1 的解答(图片由作者提供)

问题二:

问题 3:

凸函数和严格凸函数的区别其实很简单。如果连接曲线上任意两点的线段位于曲线上或曲线上方,则该函数是凸函数。如果这条线段“严格地”位于曲线之上,那么这个函数就成了一个严格凸函数。下面的图表有助于你理解这一点。

左图:严格凸函数;右图:凸函数(图片作者提供)

从右图中可以看出,连接点 x3 和 x4 的线段位于图上。因此,图是凸函数。注意还有一个概念叫“强凸性”。我们将在本系列的后续章节中对此进行研究。

所以,我们在这里可以形成的命题是,如果函数 f 是两次可微的,那么

  • f 是凸的当且仅当 f 的 Hessian 大于或等于 0。
  • 如果 f 的 Hessian 严格大于 0,则 f 是严格凸的。

问题 4:

就这样,我们到了这一章的结尾。最好的部分是,从下一章开始,我们将最终深入适当的优化概念。到目前为止,我们一直只处理辅助主题,这将有助于我们理解和解决优化问题。

在前一章第四章:重要的凸函数和凸性质这里我曾问过“如果 n 个向量的线性组合位于一个 n 维空间,你认为这些向量的仿射组合位于哪个维空间?”。答案很简单。向量将位于 n-1 维空间中。我们可以从这样一个事实得到一个想法,当一些向量的线性组合是一个二维平面时,相同向量的仿射组合是一条线。

我问的下一个问题是“你认为凸锥体或圆锥壳在三维空间中会是什么样子?”。这就更简单了。这些看起来像一个圆锥体,就像一个冰淇淋蛋卷,就是这样!

点击这里进入下一章,第 6 章:优化问题。

用 Python 和 Gurobi 优化周生产计划——第 3 部分

原文:https://towardsdatascience.com/optimization-of-a-weekly-production-plan-with-python-and-gurobi-part3-2d8da1d3fc4c?source=collection_archive---------6-----------------------

实践教程

了解如何使用 Python 和数学求解器 Gurobi 解决优化问题

我们在之前的文章中研究了如何在几条生产线之间分配工作量,以满足需求,同时减少劳动力、库存和短缺成本。

这个模型有一些限制,可能无法在自然环境中使用。事实上,在大多数情况下,需求是根据客户订单列表的发货数量。还有,每种材料的周期时间不一样。

我们将在这里看到在这种情况下如何优化生产计划。

照片由雷米·吉林拍摄| Unsplash

1.语境

最终装配计划

总装调度的想法是通过在每日级别调度生产订单来细化每日需求。我们的目标是通过平滑生产负荷来降低成本,从而减少劳动力成本,同时及时生产以减少库存和短缺成本。

我们采用的是按订单生产方案,其中三条生产线并行。工厂的组织方式使得单件流始终受到尊重,生产材料的所有任务都在同一条生产线上完成。每天 7 到 12 小时之间,每条生产线都可以额外收取加班费用。

我们需要安排生产订单,以满足客户订单清单所表达的要求。

除了我们在前面的文章中所做的,我们将为我们工厂正在生产的每个产品系列添加周期时间的概念。该周期时间通过一个矩阵用作输入,该矩阵显示了 8 小时轮班的演示能力。由于不同生产线的设备不同,产能不仅取决于产品系列,还取决于装配线,如下图所示。

客户订单和生产线产能|图片由作者提供

如何根据这些输入提出一个最小化成本的最终装配计划?

本文给出的算法基于第 1 部分和第 2 部分给出的算法。在本文中,我们将只坚持新引入的概念。

下面是我们将使用 Python 和 Gurobi solver 解决的问题的摘要。

**Inputs**
- Customer requirements
- Capacity matrix
- Labor cost per hour
- Inventory cost per material per day
- Shortage cost per material per day**Variables**
- x_qty[date, order, assembly line]: quantity of materials produced per day for each order on a given assembly line
- x_time[date, order, assembly line]: working time per day for each order on a given assembly line. Defined according to the cycle time for each model.**Constraints** - Produce the quantity required by our customers
- From 7 to 8 standard working hours per day
- From 0 to 4 overtime working hours per day**Objective function to minimize**
Sum of all costs considered
- Labor cost
- Inventory cost
- Shortage cost

2.编程我们的调度算法

输入

提取数据

这一次,为了提出一个更好地满足专业环境需求的模型,输入来自一个 Excel 文件,该文件可以从我们的 ERP 中提取。我们的算法将读取客户的要求,并使用相同的模板在另一个 Excel 文件中生成优化的生产计划。

我们将使用 pandas 的库来拟合这些信息,并转换数据以用于我们的优化算法。

用作输入的第二个 Excel 文件是每种产品每条生产线的演示产能。理想情况下,所有的装配线都应该有相同的流程,因此也应该有相同的能力。然而,在我们的小装配厂却不是这样。

展示的能力不是基于理论路线时间,并且已经考虑了由于缺乏效率而造成的损失。以下是每条生产线 8 小时的产能:

现在让我们从 Excel 中获取数据,并将其加载到 pandas 数据框中:

之前呈现并保存在两个 Excel 文件中的数据没有保存到变量的 customer_orderscapacity 中。此外,为了创建我们的算法,我们需要将产能转换为周期时间,即生产一个项目所需的时间。这些信息存储在变量 【周期 _ 时间】 中。

从本地文件中提取这些数据后,我们需要设置劳动力、库存和短缺成本。这是以与前几篇文章相同的方式完成的,这里不再赘述。

与前面的文章相反,我们操作的日历是基于客户订单文件构建的。如果需要,可以在我的 Git Hub 上找到代码。

现在我们已经访问了所有要处理的信息,我们将创建字典来使用求解器 Gurobi 求解我们的模型。

创作辞书

首先,我们需要创建一个包含与周期时间相关的信息的字典。我们想知道在每条装配线上生产一个订单单位所需的时间。

由于我们还不知道每个订单的周期时间,我们需要将本文第一部分创建的两个数据框架联系起来,即客户订单和产能数据框架。我们还将借此机会格式化日期。

我们现在已经拥有了在一个数据框中构建词典所需的所有信息。

根据记录,字典用于存储按键索引的数据。因为我们需要知道在每条装配线上生产每份订单的一个单位所需的时间,所以用于索引周期时间字典的关键字是元组(订单,装配线)。

为了创建字典,我们将在 customer_orders 数据框架中查找周期时间信息,并迭代每个订单和每条装配线。

输出将是:

cycle_times = {('A','Line_1'): 0.025, ('A','Line_2'): 0.0228, … ,('L','Line_2'): 0.0228,('L','Line_3'): 0.025}

同样,我们创建了包含日常需求(即客户需求)的字典。

daily_requirements = {('2020/07/13','A'): 600, ('2020/07/13','B'): 0, … ,('2020/07/19','K'): 0, ('2020/07/19','L'): 200}

在这一点上,我们已经成功地提取和提炼了将用于优化问题的数据。现在让我们开始定义我们的变量。

变量

与前两篇文章相比,这里是主要的创新之处。

在前面的文章中,我们在二维空间工作,我们的变量是每天在每条装配线上工作的时间。这次我们增加一个维度,这个变量所关注的顺序。

我们有一个主优化变量 x_qty 和一个从属变量 x_time 使用 cycle_times 字典定义。一个三维的元组代表了它们。

  • x _ qty[日期,订单,装配线] :给定装配线上每个订单每天生产的产品数量
  • x _ time[日期,订单,装配线] :给定装配线上每个订单每天的工作时间

除了这些新变量,我们将使用在以前的文章中定义的变量。以下是对这些变量的提醒:

时间变量

这些变量用于根据我们工厂的规定设置工作时间的限制。

 • ***reg_hours[date, assembly line]***: regular working time on each assembly line• ***OT_hours[date, assembly line]***: overtime working hours on each assembly line
 • ***line_opening[date, assembly line]***: binary variable telling if an assembly line is opened each day
 • ***total_hours[date, assembly line]***: total working hours on each assembly line. It is the sum of regular and overtime working hours on the days the line is opened.

数量变量

这些变量用于计算库存和短缺成本。

 • ***early_prod[date, order]***: quantity of items produced early for each order• ***late_prod[date, order]***: quantity of items produced late for each order

限制

正如在简介中看到的,我们对每天的工作时间有一些限制,这是满足我们客户要求的一个障碍。

在每个变量的定义中设定了限制工作时间的约束条件,设定了下限和上限以符合规定。

为了满足我们客户的需求,我们想生产出准确的订单数量。为此,我们将设置以下约束:

目标函数

我们的目标是提出一个考虑到劳动力成本、库存成本和短缺成本的具有成本效益的计划。我们将所有这些变量添加到我们的目标函数中,然后最小化这个函数。

3.解决方案和分析

最小化目标函数后,我们的优化算法返回以下生产计划:

你可以在下图中看到客户的需求是如何在我们的生产线之间分布的。我们可以注意到,每个订单的生产都是在需要最大限度减少库存的当天实现的。

订单 L 的情况并非如此,因为它仅代表几个小时的生产,并且禁止在少于 7 小时的时间内打开生产线。订单 L 在 7 月 18 日生产,它将建立一个 200 件的库存,将在 7 月 19 日发货。

我们可以检查每天工作时间的限制是否得到遵守。这些限制是根据当地法规定义的。

在我们的案例中,现行法规规定每天最少工作 7 小时,最多 12 小时,8 小时是 100%负载的理想工作时间。下图中的灰色线条代表了这些极值。

每条线路上的每日工作时间总是落在 7 至 12 小时之间,并且遵守规定。

现在,让我们显示该计划建议中预期的库存和短缺。

从生产计划中可以看出,订单 L 在一天内增加了 200 件 model 7 库存,从而影响了我们的库存水平。没有后期生产,客户的要求得到满足,没有任何短缺。

第一天客户要求太高无法处理怎么办?

让我们看看我们的调度优化算法如何在时间框架的开始处理一个重要的客户订单。

下面的计划显示了如果第一个客户订单量较高,我们的模型所建议的生产计划。在本例中,订单 A 的数量是 2000 件,而在我们的第一次测试中是 600 件。这个量一天也处理不过来,即使我们三条线满负荷运转。

我们可以看到,我们的模型通过建议在第二天生产这些材料来管理这种类型的请求。这在下面的短缺报告中更加明显,我们可以看到我们无法生产 515 件。它们将在 7 月 13 日生产。

当然,这不应该发生,因为它会对客户满意度产生负面影响。

4.结论

通过这三篇文章,我们一步一步地学习了如何形式化一个优化问题,以及如何使用 Python 和 Gurobi solver 来解决它。

这种方法已被应用于需要安排生产以降低成本(包括劳动力、库存和短缺)的按订单生产工厂。

没有考虑所有的限制和所有的成本;一些需要改进的地方包括:

  • 考虑不同型号之间的转换时间
  • 模拟一个更复杂的工厂,各种任务按照特定的顺序在不同的生产线上执行

资源

这个项目在我的 GitHub 上的仓库:https://GitHub . com/soula bat/Production-plan-optimization/tree/master/Planning _ optimization _ part 1

解释 SAP 如何在其计划优化模块中使用线性优化:http://www . guro bi . com/pdf/user-events/2017-Frankfurt/SAP . pdf

古罗比文档:https://www . guro bi . com/documentation/8.0/examples/work force 5 _ py . html

如果你需要更多的信息或者想就这个问题交换意见,请随时联系我。你可以在 LinkedIn 上找到我。

最优化理论

原文:https://towardsdatascience.com/optimization-theory-7c8cdbf1714d?source=collection_archive---------50-----------------------

数据科学的核心

迭戈博士Unsplash 上拍摄的照片

在日常生活中,我们都会面临一些挑战,通常,我们会努力做出最好的决定。如果你想买一种产品,当然,你会试图以最低的成本选择最好的质量。这些类型的决策被归类为优化问题,其目标是获得最佳解决方案;可能是最小值,也可能是最大值,优化过程是一门为现有情况寻找最佳答案的艺术。高级工程系统的复杂性和相互依赖性需要一个对相关领域知识有全面了解的分析师来帮助你优化系统。最优化理论及其技巧向其他相关科研领域的推广是应用数学的重要应用之一(看来我没有虚度光阴,17 年前就这么多了!)在数学上,优化问题是从一组候选答案或可行答案中找到最佳答案的问题。在数据科学中,由成本函数持续评估数据模型的质量至关重要。在这种情况下,成本函数最小化意味着找到一组在系统中产生最小可能误差的最佳参数。(这个故事可能会帮助你想起一些数学概念:数学,科学之母,数据科学之旅的起点)

最优化的目标是在给定问题的某些条件下,找到最佳的可接受的答案。对于一个问题,可能有不同的解,为了比较它们并选择最优解,定义了一个称为目标函数的函数。这个函数的选择取决于问题的性质。例如,出行时间或成本是优化交通网络的一个常见目标。然而,选择正确的目标函数是最重要的优化步骤之一。所以,请耐心看完,找出其他的!目标是最小化或最大化系统性能的定量测量。例如,在制造业中,目标是最小化生产成本或最大化利润。而在模型的数据拟合中,目标是最小化总观察数据与预测数据的偏差。变量,或者换句话说,未知量,是优化模型的组成部分,需要为其找到合适的值。例如,在生产流程中,变量可以是消耗的资源数量或每项活动花费的时间等参数。在数据拟合中,变量将与模型参数相同。
约束是显示变量之间关系的函数,从而确定变量的允许值。例如,在生产过程中,消耗的资源数量不能超过可利用的资源数量。

一般来说,术语优化指的是一个过程,其目的是在一个确定的领域中找到一个(或多个)目标函数的最佳值。有时在优化中,同时考虑几个目标;这种涉及多个目标函数的优化问题称为多目标问题。处理这种问题的最简单的方法是以主要目标函数的线性组合的形式形成新的目标函数,其中每个函数的有效性由分配给它的权重来确定。每一个优化问题都有若干个自变量,这些自变量被称为设计变量,用 n 维向量 x 来表示(更多内容请看这个故事:线性代数,机器学习的隐藏引擎)

多目标优化问题用于许多科学和应用领域,如工程、经济和物流,并在需要实现系统中的最优决策时使用。在两个或多个相互冲突的目标之间有一个权衡。例如,开发新组件可能需要在最大化功率的同时最小化重量。此外,为了选择正确的投资组合,人们应该以最小化投资、资本和投资风险的预期回报的方式行事。

优化过程的第二步是确定要优化的问题的类型或分类。在下面的章节中,将介绍最优化问题的分类。在这个步骤和确定优化问题的类型之后,根据问题的范围和需要,有必要在可用的优化工具(商业和学术)中优化函数并找到最佳(或近似)解决方案,即最兼容的工具。带着问题的需要,选择并在期望的领域使用它。

不同的优化问题分为以下两类:

a)无限优化问题:在这些问题中,目标是最大化或最小化目标函数,而对设计变量没有任何限制。

b)有限制的优化问题:大多数实际问题中的优化都是根据一些限制来完成的;对系统的行为和性能的约束,以及对问题的物理和几何的行为约束和约束,称为几何或横向约束。代表约束的方程可能相等或不相等,在每种情况下优化方法是不同的。然而,限制决定了设计中的可接受区域。

优化问题的另一个实际分类是基于问题的确定性。在确定性优化问题中,假设给定的问题数据是精确已知的。然而,由于各种原因,许多给定问题的数据无法准确获知(或拥有)。问题数据不准确的第一个原因是数据的“测量误差”。不知道问题数据的第二个也是最重要的原因是,一些数据显示了与未来相关的信息(如产品的需求或未来产品的价格),这些信息无法确定。

在不确定性下的优化或随机优化中,不确定性被结合在模型中。只有当问题的参数在一定范围内时,才能使用稳健优化技术;在这种情况下,目标是找到一个对所有数据都可行的答案,并且在搜索或选择空间中是最优的。随机优化模型利用了支配数据的“概率分布”是已知的或估计的这一事实。在这种情况下,目标是找到所有数据样本都可以接受的策略,并优化模型的预期性能。

让我们假设你正在寻找一个最优化问题的解决方案,它包括一个策略或者一组精确的指令。这个策略叫做算法。现在假设一个场景,其中给定的问题非常复杂,无法用常规算法解决。解决问题最常见的来源是时间(解决问题所需的时间量)和空间(所需的内存量)。为了使这一点更容易理解,问题被分成几类,这样一类的问题在所需的时间或空间方面是相似的。这些类被称为复杂性类。最流行的复杂性分类是 P 和 NP,它们根据所需时间对问题进行分类。直观上,我们可以说 P 类是一个有快速算法可以找到答案的问题。但是 NP 包括那些虽然可能要花很长时间才能找到答案,但可以通过快速算法正确检查的问题。

最具成本效益和最简单的问题解决技术之一是进化计算算法。一般来说,这种算法是基于使用达尔文的进化论,“适者生存”。特别是,进化计算方法和进化算法的一个重要目标是提高给定问题的劣质解决方案的质量。为了改进这些解决方案,进化计算算法使用进化过程,如变异;换句话说,这些算法在迭代过程中操纵弱生成的解,因此系统可以以期望的精度解决问题。

从技术角度来看,进化计算算法是一系列基于群体、试错和随机优化或元启发式优化机制的问题解决方法。这些使用最优答案来收敛到全局或近似最优解。在进化计算中,首先形成候选解的基本集合。在进化过程中,进化计算算法操纵和更新由候选答案组成的群体,以将群体移动到包含全局最优答案的区域。在进化计算算法的每次迭代中,进化过程将通过消除群体中不期望的响应并对候选响应进行非常小的改变而发生。

进化计算方法能够针对不同条件下的特定问题产生一组优化的解决方案;进化计算系统和进化算法中的这种重要特征使它们与传统的优化方法形成对比,传统的优化方法只能产生一个确定性的解决方案或有限数量的问题的近似解决方案。此外,为给定问题生成一组候选答案的能力使得进化计算算法成为最流行的问题解决方法之一。迄今为止,已经提出了各种版本的进化计算算法。近年来推出的许多这样的算法是“独立于领域”和“独立于问题”的,这使它们成为解决具有特定数据结构的广泛问题的一个很好的选择。

参考

杜,张大千;帕尔多洛斯下午;吴,魏(2008)。“最优化的历史”。在弗卢达斯,c;帕达洛斯教授(编辑。).最优化百科全书。波士顿:斯普林格。第 1538-1542 页。

马利亚里斯(2008)。“随机最优控制”,新帕尔格雷夫经济学词典,第二版

Siadati,Saman。(2013).进化计算. 10 . 13140/rg . 2 . 2 . 36143 . 15526 .

赫蒂,男;克拉尔,2003 年 1 月 1 日。交通流网络的建模、模拟和优化。科学计算杂志。25(3):1066–1087。

资源优化教程

原文:https://towardsdatascience.com/optimization-with-recourse-tutorial-6985748a94e6?source=collection_archive---------31-----------------------

带有数字示例的快速指南

罗伯特·鲁杰罗在 Unsplash 上的照片

我们将首先介绍什么是优化,以及优化的一些特殊形式,包括带资源的优化。然后我们会有一个快速的公式和一个数值例子。在本教程结束时,希望你能理解为什么有追索权的优化是随机用例的有用工具,以及有追索权的优化与均值和加权平均等常用的平均方法有何不同。

优化基础

对于给定的问题场景,优化已经成为有效分配有限资源的关键工具。标准数学程序通常为单个决策者做出的单个目标提供一组决策。在实践中,许多优化问题都是在考虑多个决策者和多个阶段的情况下建模的。多级规划涉及多个级别或阶段,其中每个阶段可以有多个目标,这些目标可以由多个决策者制定。

两阶段随机优化程序是多层规划的一个子集。随机程序通常基于概率分布对不确定参数建模。当不确定性已知时,根据决策,不确定性分两个阶段出现,如带追索权的优化情况。

为什么要追索?

当单个决策者可能需要在不同阶段优化目标时,就会出现带追索权的两阶段优化。在可行集 X 的决策 x 必须在实现来自可能集ω的场景 ω 之前做出的情况下,具有追索权的随机优化适合于解决这样的问题。

追索程序指的是随机优化,在不确定性被披露后,从可行集合 Y 中采取追索行动 y 。决策可以分为两个阶段。追索行动 y 被称为第二阶段决策。在 ω 公开之前做出的 x 决策称为第一阶段决策。在这个框架中,不确定的约束被视为软约束,它可能被违反,但具有影响选择 x 的惩罚成本。第二阶段必须考虑可能情况的预期。惩罚偏差促进了第一阶段决策的可行性,并对不常见的极端异常变得稳健。如果样本空间能够以概率 φ 可数或近似为集合ω中的场景 ω ,则期望最小追索权𝔼可以使用基于 φ 的求和来表示。

样本问题公式

我们将从第一阶段和第二阶段决策开始,如下所示:

作者图片

样本数值解

作者图片

作者图片

请注意,在有追索权的两阶段优化中考虑这两种情况时,第一阶段的决策发生了变化。由此产生的第一阶段决策不一定是第二阶段两个方案的平均值或加权平均值。表 1 显示了产生的第一个决策及其相关值。

作者图片

总结

如果给我们一个用例,其中必须在场景公开之前做出决策,而不是仅仅使用均值、加权资源或单级优化,那么尝试使用资源优化可能是一个好主意。这样的工具变得必不可少,尤其是当我们想要从给定的信息和风险中获得最大收益的时候。

优化 AWS Lambda 内存

原文:https://towardsdatascience.com/optimize-aws-lambda-memory-more-memory-doesnt-mean-more-costs-51ba566fecc7?source=collection_archive---------7-----------------------

关于如何决定 lambda 函数的内存需求的见解

埃里克·麦克林在 Unsplash 上的照片

对于任何开始无服务器之旅的人来说,AWS lambda 太棒了。你写代码,调用函数,它会为你做工作。打住,真的做到预期了吗?我是说执行时间呢?如何确保我的 lambda 函数以最低的成本实现最佳性能?这是每个人开始生产 lambda 函数时都会思考的问题。相信我,我得到的关于 lambda 函数的问题都很疯狂:

  1. 当函数是 CPU 密集型的时,为什么要分配更多的内存?
  2. lambda 函数的 CPU 利用率是多少?
  3. 增加内存会增加成本。检查一下你分配了多少内存。

当我第一次开始使用 lambda 时,我感到困惑的是,AWS 可以选择为 lambda 函数分配内存。没有分配 CPU 的选项。CPU 会随着内存的增加而扩展。为了理解它是如何工作的,让我们举一个简单的例子,在不同的内存限制下运行它。

我写了一个简单的函数,打印出介于“下”和“上”值之间的质数。代码如下:

import jsonprint('Loading function')def lambda_handler(event, context):
    lower = 2
    upper = 50000
    print("Prime numbers between", lower, "and", upper)

    for num in range(lower, upper + 1):
        if(num > 1):
            for i in range(2, num):
                if (num % i) == 0:
                    break
            else:
                print(num)return {
        'statusCode': 200,
        'body': json.dumps("Function executed successfully")
    }

我用 4 个内存限制(128 MB、256 MB、512 MB 和 1024 MB)运行了上面的函数。以下是结果:

作者图片

如你所见,【使用的最大内存】总是在 48 MB 左右。不过,有趣的是看到的“执行时间”。随着我增加内存,执行时间下降了(从 128 MB 的 135 秒到 1024 MB 的 17 秒)。这证明随着内存的增加,分配的 CPU 越来越多。但是成本呢?内存增加会导致更高的成本吗?为了理解成本的含义,我使用了 AWS 计算器。我选择找出每月 10000 次执行的无自由层成本,这是我得到的结果:

作者图片

看着这些数字,我很惊讶。对于 128 MB 的内存,我的执行时间大约是 135 秒,成本是 2.82 美元。将内存增加到 1024 MB,在不增加太多成本的情况下,极大地提高了执行时间。因此,增加内存会增加成本并不总是正确的。

问题是如何为 lambda 函数分配最优内存?我的意思是,我不能对我写的每个函数都做这样的计算。所以我开始在网上搜索,看看是否有工具可以做到这一点,并给我提供内存、执行时间和成本的最佳组合。你猜怎么着,谷歌一如既往地帮我找到了答案。GitHub 上有一个由 Alex Casalboni 编写的独立项目可以完成这项工作。(https://github.com/alexcasalboni/aws-lambda-power-tuning

使用 AWS Lambda 功率调谐

你可以在 GitHub 文章https://GitHub . com/alexcasalboni/AWS-lambda-power-tuning/blob/master/README-deploy . MD中了解如何安装 power tuner。

我继续使用选项 1,无服务器应用程序存储库进行部署。部署完成后,是时候为我的 lambda 函数执行它了。同样,在文章https://github . com/alexcasalboni/AWS-lambda-power-tuning/blob/master/README-execute . MD中给出了多个执行选项

我使用选项 3 执行:使用以下输入手动执行状态机(web 控制台):

作者图片

  1. 被测λ函数的λarn→arn。
  2. powerValues →要测试的内存值列表
  3. num →每个配置的调用次数
  4. 策略→可以是我在测试中使用的平衡的"cost""speed""balanced".

您可以在此链接中阅读更多关于其他输入值的信息:https://github . com/alexcasalboni/AWS-lambda-power-tuning/blob/master/README-INPUT-output . MD

一旦我执行了状态机,我得到了下面的结果(注意:对于这个测试,我将‘upper’值减少到了 10000)

作者图片

从上面的描述可以看出,最好的性价比是 512 MB 内存。但当我们看到 1024 MB 的内存时,我们的成本会稍微高一些,但执行时间会大幅减少。我发现这个工具非常适合测量 lambda 函数的内存需求。您可以根据自己的需求在输入中尝试不同的值组合,然后做出决定,而不是进行一些特别的内存分配并期望事情正常工作。

使用 Python 优化电子商务的最后一英里交付

原文:https://towardsdatascience.com/optimize-e-commerce-last-mile-delivery-with-python-ab9ba37d214c?source=collection_archive---------11-----------------------

使用 python 优化模型组织路径,以最少的驾驶员数量交付包裹

萨姆·巴耶在 Unsplash 上拍摄的照片

If you travel to first and second-tier cities of China, you will find on the street many delivery drivers (Chinese: 快递).

They take the parcels from small warehouses called customer service centres (Chinese:客户服务中心) located in each neighbourhood and deliver them to the final customers.

这些中心是中国主要快递公司物流网络的关键要素。它们为最后一英里的交付提供了广阔的地理覆盖范围,并通过提供市场上最佳的服务水平和交付提前期,提供了巨大的竞争优势。

在到达您的家门口之前,您的包裹将从供应商的仓库中取出,经过几个地区配送中心,最终到达您所在社区的服务中心。

当您的包裹到达中心时,您会在手机上收到通知,告知您快递员将在当天为您递送包裹。

本文将提出一个解决方案,优化从这些中心的最后一英里交付,以降低成本,并确保每个司机的工作量均匀分布。

💌新文章免费直入你的收件箱:时事通讯

一、如何用 python 优化最后一公里交付?

问题陈述

你是当地服务中心的经理,负责

  • 您团队中的 4 名车手
  • 每辆车 15 包容量
  • 16 个目的地以覆盖名为 D j 的街区,j 在[1,16]中
  • D0 是中心
  • 每位驾驶员 1 条路线

示例 0:您的服务中心| 1 … 16:客户的目的地—(图片由作者提供)

距离矩阵

要构建您的模型,您需要提供一个距离矩阵 M 作为输入,定义如下

  • M(i,j)与 I,j 在[0,16]中
  • M(i,j)= DI和 D j 之间的距离

该距离矩阵将从 Excel 文件中加载。你可以在这里找到这个场景的例子:链接

距离矩阵(m)——(作者)

需求:要递送到每个地点的包裹数量

我们将在这里使用一个第一个值为零的 python 列表(因为你不需要在中间传递任何东西)

  • 需求= [0,1,1,2,4,2,4,8,8,1,2,1,2,4,4,8,8]

目标

  • 用最少数量的司机运送所有包裹
  • 优化路线以最小化每条路线覆盖的距离

结果

**Route for driver 0**
 0 Parcels(0) ->  4 Parcels(4) ->  3 Parcels(6) ->  1 Parcels(7) ->  7 Parcels(15) ->  0 Parcels(15)
Distance of the route: 1552 (m)
Parcels Delivered: 15 (parcels)

**Route for driver 1**
 0 Parcels(0) ->  14 Parcels(4) ->  16 Parcels(12) ->  10 Parcels(14) ->  9 Parcels(15) ->  0 Parcels(15)
Distance of the route: 1552 (m)
Parcels Delivered: 15 (parcels)

**Route for driver 2**
 0 Parcels(0) ->  12 Parcels(2) ->  11 Parcels(3) ->  15 Parcels(11) ->  13 Parcels(15) ->  0 Parcels(15)
Distance of the route: 1552 (m)
Parcels Delivered: 15 (parcels)

**Route for driver 3**
 0 Parcels(0) ->  8 Parcels(8) ->  2 Parcels(9) ->  6 Parcels(13) ->  5 Parcels(15) ->  0 Parcels(15)
Distance of the route: 1552 (m)
Parcels Delivered: 15 (parcels)

Total distance of all routes: 6,208 (m)
Parcels Delivered: 60/60

根据这些结果,您可以为四位驾驶员中的每一位分配一条总距离相同的路线

  • 100%的包裹在最短距离内送达
  • 司机的车辆已满载(15/15)

使用这种模型有助于确保通过送货获得固定报酬的司机能够被公平地分配到一条路线上。

你将避免司机抱怨的问题,因为他们的路线比他们的同事更长。

此外,你正在最大限度地利用你的资源。

http://samirsaci.com

二。构建您的模型

用谷歌工具解决有容量限制的车辆路径问题(CVRP)

OR-Tools 是 Google 的一个开源集合,提供了用于组合优化的工具。目标是从大量可能的解决方案中找到最佳解决方案。

让我们尝试使用这个库来构建最佳路线。

你可以在这个 Github 资源库中找到完整的代码:链接
我的作品集与其他项目:萨米尔萨奇

1.导入距离矩阵和初始参数

2.创建计算距离和订购数量的函数

3.用约束条件构建模型

4.展示解决方案

三。结论

关注我的 medium,了解更多与供应链数据科学相关的见解。

该模型可以帮助中心经理

  • 充分利用司机和车辆,优化车队
  • 确保工作量在每个驱动程序之间平均分配

问题:

  • 提高每个驱动程序的容量(箱数)会带来什么结果?
  • 如果我们有重量或体积限制,会有什么结果?

我让你测试它,并在评论区分享你的结果(或问题)。

用 Digital Twin 模拟几个场景

数字孪生是物理对象或系统的数字复制品。

供应链数字模型是一种计算机模型,代表供应链中涉及的各种组件和流程,如仓库运输网络生产设施。

在这个数字模型中,您可以用成本、能源、排放和交付周期参数来模拟端到端供应链的每个元素。

(图片由作者提供)

当你头脑风暴潜在的路线分配策略时,你可以模拟它们对整个配送网络的影响。

举个例子,

  • 如果我们增加每辆运输车辆的存储容量,会有什么影响?
  • 如果我们使用货车而不是电动自行车,会对二氧化碳排放量产生什么影响?
  • 使总成本最小化的最佳分销网络(你的最后一英里分销中心的位置)是什么?

欲知详情,

https://www.samirsaci.com/what-is-a-supply-chain-digital-twin/

可持续的数字孪生模型

(图片由作者提供)

假设你使用排放二氧化碳的车辆,你可以修改这个模型来考虑最后一英里配送网络的总排放量。

绿色库存管理可以定义为以环境可持续的方式管理库存。

(图片由作者提供)

对于分销网络而言,这可能涉及一系列旨在减少订单传输、准备和交付的环境影响的流程和规则。

如果我们降低商场补货的频率,对二氧化碳排放会有什么影响?

在本例中,我们使用数据分析来模拟商店补货频率的变化,并衡量对整体环境的影响。

https://www.samirsaci.com/green-inventory-management-case-study/

关于我

让我们在 LinkedinTwitter 上连线,我是一名供应链工程师,正在使用数据分析来改善物流运营和降低成本。

如果你对数据分析和供应链感兴趣,可以看看我的网站

https://samirsaci.com

参考

[1] Google AI,Google OR-Tools 库,链接

在 Python 中优化内存技巧

原文:https://towardsdatascience.com/optimize-memory-tips-in-python-3bbb44512937?source=collection_archive---------1-----------------------

在 Python 中跟踪、管理和优化内存使用是一件很好理解的事情,但是缺乏对方法的全面总结。这篇文章介绍了提高内存利用率的最常见和最有效的方法。

来源:费德里科·贝卡里于 Unsplash

Python 中的内存管理不是一个简单的问题,它需要对 Python 对象和数据结构有很好的理解。与 C/C++不同,用户无法控制内存管理。它由 Python 自己接管。然而,有了关于 Python 如何工作和内存支持模块的一些见解,我们可以在如何控制这个问题上找到一些线索。

分配了多少内存?

在 Python 中有几种方法可以获得对象的大小。你可以使用sys.getsizeof()来获得对象的确切大小,objgraph.show_refs()来可视化一个对象的结构,或者psutil.Process().memory_info().rss 来获得当前所有的内存分配。

“ob”的结构(sample-graph.png)-来源:作者图片

tracemalloc 也是另一种选择。它包含在 Python 标准库中,并提供内存分配的块级跟踪、程序整体内存行为的统计。

最常用的文件是 arr 对象,它占用 2 个内存块,总大小为 2637 MiB。其他对象很少。

另一个重要的技术是估计进程运行需要多少内存。这可以通过监控进程的内存使用峰值来推测。要测量峰值内存,您可以在过程结束时使用下面的代码。

### For Linux (in KiB) and MacOS (in bytes)
from resource import getrusage, RUSAGE_SELF
print(getrusage(RUSAGE_SELF).ru_maxrss)### For Windows
import psutil
print(psutil.Process().memory_info().peak_wset)

有了放入进程的峰值和数据量,就可以通过某种方式判断下一个进程要消耗的内存量。

1。利用 Pytorch 数据加载器

训练大型数据集是您的内存瓶颈,如果整个数据集无法同时放入您的内存,您将永远无法训练完整的模型,尤其是对于图像、文本、语音等非结构化数据……但是,使用 Pytorch DataLoader,您可以为整个数据集设置各种小批量,并且每个小批量都不间断地加载到您的模型中(样本数量取决于您的内存容量)。你可以在这里看到https://pytorch.org/tutorials/beginner/data_loading_tutorial.html使用 Pytorch DataLoader 的教程。

然而,如果你想在不使用深度学习的情况下(因此,不使用 Pytorch)在表格数据上训练机器学习模型,或者你没有访问数据库的权限,只能在内存上工作,那么内存优化的选择是什么?

2。优化的数据类型

通过了解数据是如何存储和操作的,并为任务使用最佳的数据类型,它将为您节省大量的内存空间和计算时间。在 Numpy 中,有多种类型,包括 bool(布尔)、integer (int)、Unsigned integer (uint)、float、complex、datetime64、timedelta64、object_ 等…

### Check numpy integer
>>> import numpy as np>>> ii16 = np.iinfo(np.int16)
>>> ii16
iinfo(min=-32768, max=32767, dtype=int16)### Access min value
>>> ii16.min
-32768

我将它们缩小到 uint、int 和 float ,因为这些是在 Python 中训练模型、处理数据时最常见的。根据不同的需求和目标,使用足够多的数据类型变得至关重要。要检查类型最小值和最大值,可以使用函数numpy.iinfo()numpy.finfo()进行浮点运算。

以下是每种类型的摘要信息。

与 numpy.float32 相比,如果数据类型转换为 numpy . float 64(numpy . array 的默认类型), CSV 文件的大小会加倍。因此,float32 是使用的最佳数据类型之一(Pytorch 数据类型也是 float32)。

由于默认的数据类型numpy.float()float64numpy.int()int64 ,所以在创建 numpy 数组时要记得定义 dtype,这样会节省大量的内存空间。

使用 DataFrame 时,还有另一种常见类型,即“object”。对于具有各种重复的特征,从对象到类别的转换将有助于加快计算时间。

下面是一个优化 pd 的示例函数。标量和字符串的数据类型。

另一种简单有效地减少pd.DataFrame内存占用的方法是使用pd.read_csv()中的usercols参数导入特定列的数据

3。避免使用全局变量,而是使用局部对象

Python 检索局部变量比检索全局变量更快。此外,将太多变量声明为全局变量会导致内存不足的问题,因为这些变量会保留在内存中,直到程序执行完成,而一旦函数结束,局部变量就会被删除,并释放它所占用的内存空间。在阅读更多数据科学家必须掌握的真实技能

**

4。使用 yield 关键字

Python yield 返回一个生成器对象,该对象将给定的表达式转换为生成器函数。要获得对象的值,必须对其进行迭代,以读取 yield 的值。要读取生成器的值,可以使用 list()、for loop 或 next()。

>>> def say_hello():
>>>    yield "HELLO!"
>>> SENTENCE = say_hello()
>>> print(next(SENTENCE))
HELLO!

但是,生成器是一次性使用的对象。如果您第二次访问它,它返回空的。

>>> def say_hello():
>>>    yield "HELLO!"
>>> SENTENCE = say_hello()
>>> print(next(SENTENCE))
HELLO!
>>> print("calling the generator again: ", list(SENTENCE))
calling the generator again: []

因为除非迭代生成器对象,否则不会返回值,所以在定义 Yield 函数时不会使用内存,而在函数中调用 Return 会导致内存分配。

因此, Yield 适用于大型数据集,或者当您不需要存储所有输出值,而只需要存储主函数每次迭代的一个值时。

>>> import sys
>>> my_generator_list = (i*2 for i in range(100000))
>>> print(f"My generator is {sys.getsizeof(my_generator_list)} bytes")
My generator is 128 bytes>>> timeit(my_generator_list)
10000000 loops, best of 5: 32 ns per loop

>>> my_list = [i*2 for i in range(1000000)]
>>> print(f"My list is {sys.getsizeof(my_list)} bytes")
My list is 824472 bytes>>> timeit(my_list)
10000000 loops, best of 5: 34.5 ns per loop

看上面的代码,list comprehension 比生成器重 6441 倍,运行速度比另一个生成器慢。

5。Python 的内置优化方法

使用 Python 内置函数提高代码性能,函数列表

在定义类中使用 slots

Python 类对象的属性以字典的形式存储。因此,定义数千个对象就相当于给内存空间分配数千个字典。并添加了__slots__(通过为固定数量的属性分配空间,减少了空间的浪费,加快了程序的速度。)

没有 _ _ slots _ _(PointWithDict _ structure . png)的点模块的结构-来源:图片由作者提供

slots 的点模块结构,不再有 dict 了(PointWithSlots_structure.png) -来源:图片作者

关于内存使用,假设类对象中不再有 dict,内存空间会从(64+16+120)=200 字节显著减少到 56 字节。

使用 join()代替“+”来连接字符串

由于字符串是不可变的,所以每次通过“+”操作符向字符串添加元素时,都会在内存空间中分配一个新的字符串。字符串越长,消耗的内存越多,代码的效率就越低。使用join()可以提高速度> 30%比'+'运算符。

还有其他提高速度和节省内存的方法,查看详情 这里

itertools

或者用 itertools.chain()展平列表

### Concatenate string using '+' operation
def add_string_with_plus(iters):
    s = ""
    for i in range(iters):
        s += "abc"
    assert len(s) == 3*iters

### Concatenate strings using join() function
def add_string_with_join(iters):
    l = []
    for i in range(iters):
        l.append("abc")
    s = "".join(l)
    assert len(s) == 3*iters

### Compare speed
>>> timeit(add_string_with_plus(10000))
100 loops, best of 5: 3.74 ms per loop
>>> timeit(add_string_with_join(10000))
100 loops, best of 5: 2.3 ms per loop

查看 itertools 文档了解更多方法。我建议探索:

  • ITER tools . accumulate(iterable,func) :通过 iterable 进行累加。func 可以是 operator.func 或默认 Python 函数,如 max、min…
  • ITER tools . compress(iterable,selectors) :用另一个对象过滤 iterable(另一个对象可以当作一个条件)
  • itertools.filterfalse(谓词,iterable) :过滤并删除满足谓词的值。这对于过滤列表对象来说既有用又快速。
  • itertools.repeat(object[,times]) :将一个对象值重复 N 次。然而,我更喜欢使用列表乘法['hi']*1000 来重复‘hi’1000 次,而不是使用itertools.repeat('hi', 1000)(分别为每循环 12.2 秒和每循环 162 秒)
  • ITER tools . zip _ longest( iterables,fillvalue=None)* :将多个 iterables 压缩成元组,并用fillvalue中指定的值填充 None 值。

6。导入报表开销

import 语句可以从任何地方执行。然而,在函数外部执行将比在函数内部运行快得多,即使该包被声明为全局变量(doit2),但反过来,比另一个占用更多的内存空间。

导入执行位置的比较。来源:作者图片

7。数据块

我很自信地说,大多数时候你不会一次使用所有的数据,一次加载一大堆数据可能会导致内存崩溃。因此,将数据分块或装入小块,处理数据块,并保存结果是防止内存错误的最有用的技术之一。

pandas 让你在pandas.read_csv()pandas.read_sql()中的chunksizeiterator 参数的帮助下完成这项工作。sklearn 还支持在大多数模型上使用partial_fit()方法进行小块训练。

外卖📖

在 Python 中处理内存错误是一项棘手的任务,如果换一种方式,根本原因可能永远也不会被发现。

  • 首先,调查哪个进程/变量是导致内存溢出问题的核心原因。
  • 其次,对该对象应用适用的内存优化方法,估计新的内存占用量,并检查新的内存占用量是否能解决问题。
  • 如果没有,尝试优化相关进程(比如减少全进程内存消耗,为核心对象节省更多空间)。
  • 尝试上面的技巧,如果问题仍然存在,考虑在外部数据库服务的支持下,使用块/批处理操作构建流程。**

使用计时装饰器优化 ML 建模

原文:https://towardsdatascience.com/optimize-ml-modeling-using-a-timing-decorator-2b113c6b60d9?source=collection_archive---------23-----------------------

使用定时装饰器记录 ML 训练的执行时间,并将其用于生产数据科学和 ML 优化

图片来源 : Pixabay (免费使用)

为什么测量时间很重要

我们可以继续提供成百上千的论据和引用来说明为什么测量在科学技术中如此重要。这是一个强有力的例子,

一个精确的测量值抵得上一千个专家的意见。—格蕾丝·赫柏

根据开尔文勋爵

如果你不能衡量它,你就不能改进它。

我们想做高效的数据科学。这意味着我们希望提高我们机器学习(ML)训练和推理的效率。自然,我们需要测量将特定的 ML 模型拟合到数据所花费的时间。

https://medium.com/productive-data-science/why-and-how-should-you-learn-productive-data-science-53377b473f37

也许,我们想用各种模型进行实验,并测量它们在相同测试数据上的表现。或者,我们可能希望改变模型的超参数,并查看训练时间和性能如何变化。

在任何情况下,我们都必须测量多次运行的训练函数的执行时间。这是因为我们可能希望对 ML 模型调优如何提高执行时间和性能进行系统研究。

或者,我们可能对联合优化时间和性能指标感兴趣(例如,过于复杂的模型可能只会略微提高性能,但运行速度会慢得多)。

让我向您展示一种简单的方法,使用简单的 Python 代码来完成这种日志记录。

计时装饰器和“functools”

大多数数据科学家使用 Jupyter 笔记本进行他们的探索性工作,它提供了神奇的功能,如 %timeit%%timeit ,用于测量代码块的执行时间。然而,这对于笔记本电池中的单次运行是好的,但是对于多次运行的时间的灵活记录不是很有用。

计时装饰师

进入 装饰器 和内置 Python 模块**functools**

为了简洁起见,我们将不讨论这些实用程序的具体细节。然而,可以说它们利用了这样一个事实,即 函数是 Python 中的一级对象,人们可以 包装一个函数来提取关于它的执行以及正常运行的有用信息

我们可以编写一个计时装饰器来测量函数的执行时间,并加以利用。下面是构建这样一个装饰器的代码,

def timing(func):
    [@wraps](http://twitter.com/wraps)(func)
    def wrap(*args, **kw):
        ts = time()
        result = func(*args, **kw)
        te = time()
        tdelta = round(1000*(te-ts),3)
        print (f"Function '{func.__name__}' took {tdelta} milliseconds to run")
        return result
    return wrap

注意使用了*args**kw来允许任何一组通用的参数和关键字传递给底层函数func。该代码的主要目的是测量 time-delta ( tdelta = round(1000*(te-ts),3)),即函数完成执行前后的时间差,以提取执行时间。因为执行可能非常快,所以我们将它乘以 1000,将其标准化为毫秒。

现在到了我们在一个简单的演示函数中使用它的部分。

[@timing](http://twitter.com/timing)
def list_length(a):
    if isinstance(a,list):
        time.sleep(0.1)
        s = len(a)
        return s
    else:
        print("Argument is not a list")

这是一个简单测量给定列表长度的函数。它还有一个time.sleep(0.1)代码,只是为了演示的目的而强制延迟。如果没有它,执行速度会很快,以至于我无法向您展示任何有意义的结果。

我们测试它,

list_length([1,2,3])>> Function 'list_length' took 111.291 milliseconds to run
>> 3

注意,这个输出多酷啊!第一个打印的语句来自wrap函数,第二个结果 3 来自list_length函数。它们通过包装器/装饰器机制相互联系。当然,111.291 毫秒的时间是由于我们设置的延迟造成的,并且会因系统不同或运行不同而略有不同。

如果我们使用单个数字而不是传递一个列表来测试它,

list_length(5)>> Argument is not a list
>> Function 'list_length' took 0.0 milliseconds to run

在这种情况下,list_length函数中的条件块跳过了time.sleep(0.1)部分,因此几乎立即返回,记录了接近零的执行时间。

仅返回执行时间

现在,上面的代码仅用于演示,不应在实践中使用,因为它实际上并不返回执行时间,而只是打印出来。下面是稍微修改过的代码,

def time_return(func):
    [@wraps](http://twitter.com/wraps)(func)
    def wrap(*args, **kw):
        ts = time()
        result = func(*args, **kw)
        te = time()
        tdelta = round(1000*(te-ts),3)
        **return tdelta**
    return wrap

该代码没有打印语句,并显式返回tdelta测量值。

我们可以用它包装另一个演示函数,

[@time_return](http://twitter.com/time_return)
def numpy_matmul(a,b):
    return (np.matmul(a,b))

因此,它将测量从两个给定的 Numpy 数组计算矩阵乘法所需的时间。

我们来测试一下。

SIZE = 1000
a = np.random.beta(1.0,2.0,size=(SIZE,SIZE))
b = np.random.beta(1.0,2.0,size=(SIZE,SIZE))
numpy_matmul(a,b)>> **16.48**

所以,计算两个大小为(1000,1000)的随机数(Beta 分布)的 Numpy 矩阵的矩阵乘法需要 16.48 毫秒。

用不同的SIZE参数再次运行。

SIZE = 2000
a = np.random.beta(1.0,2.0,size=(SIZE,SIZE))
b = np.random.beta(1.0,2.0,size=(SIZE,SIZE))
numpy_matmul(a,b)>> **111.301**

所以,现在双倍大小的矩阵需要 111.301 毫秒。我们知道矩阵乘法的时间不是线性的:-)

但是这样做的主要好处是现在我们可以用这个函数编写一个紧凑的循环,并观察执行时间如何随输入大小变化

SIZE = [500,1000,2000,3000,4000,5000]
for s in SIZE:
    a = np.random.beta(1.0,2.0,size=(s,s))
    b = np.random.beta(1.0,2.0,size=(s,s))
    t = numpy_matmul(a,b)
    print(f"Matrix multiplication of size ({s}x{s}) took {t} milliseconds")

在我的电脑上,我得到了以下结果,

Matrix multiplication of size (500x500) took 3.0 milliseconds
Matrix multiplication of size (1000x1000) took 17.031 milliseconds
Matrix multiplication of size (2000x2000) took 111.501 milliseconds
Matrix multiplication of size (3000x3000) took 359.307 milliseconds
Matrix multiplication of size (4000x4000) took 835.614 milliseconds
Matrix multiplication of size (5000x5000) took 1611.042 milliseconds

将最大似然估计器融入其中

为了不浪费更多的时间,我们将 ML 估计器(来自 Scikit-learn)加入到这个组合中。现在,因为我们对执行速度和 ML 性能都感兴趣,所以在这种情况下,我们返回时间增量和 ML 度量。下面的代码与我们之前写的代码非常相似,只是我们返回了一个元组:return (tdelta, result)

def time_estimator(func):
    [@wraps](http://twitter.com/wraps)(func)
    def wrap(*args, **kw):
        ts = time()
        result = func(*args, **kw)
        te = time()
        tdelta = round(1000*(te-ts),3)
        return (tdelta, result)
    return wrap

这个修饰了一个实际上符合给定数据的评分函数,并返回准确度分数(在测试/验证集上)

[@time_estimator](http://twitter.com/time_estimator)
def classifier_accuracy(estimator,x,y):
    X_train, X_test, y_train, y_test = train_test_split(x, y, 
                                                    test_size=0.33, 
                                                    random_state=42)
    estimator.fit(X_train,y_train)
    score = estimator.score(X_test,y_test)
    return round(score,3)

我们制作了一些合成数据,并举例说明了一个逻辑回归估计。

data = make_classification(n_samples=1000, n_features=20, n_informative=20, n_redundant=0, flip_y=0.05, class_sep=1.5)x,y = data[0],data[1]log_model = LogisticRegressionCV()

当我们运行classifier_accuracy函数时,我们得到了执行时间和准确性分数,

classifier_accuracy(log_model,x,y)>> (312.083, 0.836)

第一个数字是执行时间,即 312.083 毫秒,第二个数字是准确度分数 0.836。

现在,我们有办法计算具有任意输入的一般 ML 估计器的时序和性能度量

让我们把这个派上用场。

更改数据并记录执行时间

我们可以针对各种数据大小运行估计器,并通过一个简单的循环记录性能和执行时间。

SIZE = [1000+500*i for i in range(21)]
log_model = LogisticRegressionCV()
model_time, model_acc = [],[]for s in SIZE:
    data = make_classification(n_samples=s, n_features=20, n_informative=20,n_redundant=0, flip_y=0.05, class_sep=1.5)
    x,y = data[0],data[1]
    **m_time, m_acc = classifier_accuracy(log_model,x,y)**
    model_time.append(m_time)
    model_acc.append(m_acc)

突出显示的关键代码行是修饰函数classifier_accuracy,它返回一组执行时间和准确性分数。

一个简单的绘图代码为我们提供了以下内容:

图片来源:作者生成

因此,获取更多的数据会使 ML 训练变慢,但实际上并没有改善执行时间。这是因为在合成数据生成中存在**flip_y = 0.05**参数,该参数实际上翻转了 5%数据的标签,从而使基本噪声基底固定在 0.05。这就是为什么大多数准确度分数徘徊在 0.95 左右或以下,并且不能超过该值。

因此,这项研究的启示是,我们可以放弃一个小数据集,从而减少执行时间,以节省计算成本。这就是我们如何优化 ML 培训练习的性价比。

玩估算器优化性价比

让我们假设我们使用一个随机森林估计器来解决这个问题,我们希望通过改变模型中的树的数量来优化准确性和执行时间。

可以像以前一样编写类似的代码。

num_trees = [5*x for x in range(1,21)]
model_time, model_acc = [],[]
data = make_classification(n_samples=1000, n_features=20, 
                           n_informative=20, n_redundant=0, 
                           flip_y=0.05,class_sep=1.0)
x,y = data[0],data[1]
for n in num_trees:
    rf_model = RandomForestClassifier(n_estimators=n)
    m_time, m_acc = classifier_accuracy(rf_model,x,y)
    model_time.append(m_time)
    model_acc.append(m_acc)

现在,当我们绘制精度和执行时间时,我们得到,

图片来源:由作者生成

显然,我们可以确定树木的最佳数量。例如,我们可以创建如下的成本函数,

**model_opt = model_acc + 1/model_time**

这抓住了我们想要在最小化执行时间的同时最大化准确性的意图。

如果我们画出来,我们会得到,

图片来源:由作者生成

显然,我们可以为这个模型选择大约 45 棵树。

样板代码在我的 Github repo 这里是

摘要

我们描述了如何使用 Python decorator 和functools模块为一般的 Python 函数创建一个实用的 decorator,特别是一个 ML 估计器。我们还展示了这种包装器/装饰器在数据或模型实验中的使用,以及如何利用 ML 模型优化的思想。

这种时间测量和想法在 Auto-ML 包的内部是常见的,他们用 ML 模型运行了许多实验,并选择了最好的一个。为了同时优化计算资源和性能,数据科学家应该发现这种测量工具在他们的日常任务中很有用,并定期部署它。

喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果您使用下面的链接, ,我将收取您的一部分会员费,而不会对您产生额外费用

https://medium.com/@tirthajyoti/membership

为大型数据集优化 Pandas 的内存使用

原文:https://towardsdatascience.com/optimize-pandas-memory-usage-while-reading-large-datasets-1b047c762c9b?source=collection_archive---------7-----------------------

有效利用数据类型来防止内存崩溃

来自 Pixabay图卡皮克的图片

Pandas 是一个流行的用于数据科学的 Python 包,因为它为数据探索和可视化提供了强大、富于表现力和灵活的数据结构。但是当处理大规模数据集时,它失败了,因为它不能处理大于内存的数据。

Pandas 提供了大量用于数据探索和可视化的 API,这使得它在数据科学家社区中更受欢迎。 Dask、modin、Vaex 是一些开源包,可以提升 Pandas 库的性能,处理大型数据集。

当数据集的大小相对大于内存时,最好使用这样的库,但是当数据集大小相对等于或小于内存大小时,我们可以在读取数据集时优化内存使用。在本文中,我们将讨论如何在使用**pandas.read_csv()****pandas.read_excel()****pandas.read_excel()**函数加载数据集时优化内存使用。

想法:

数据类型是 Python 用来理解如何存储和操作数据的内部构造。在使用 Pandas read_函数读取数据集时,默认数据类型被分配给每个要素列。通过观察特征值,Pandas 决定数据类型并将其加载到 RAM 中。

对于整数值,Pandas 赋值为 int64,float64 赋值为 float 64,string 值作为对象赋值。其思想是通过观察最大和最小特征值来降级特征数据类型。熊猫分配的默认数据类型列表有:

(作者图片),熊猫默认数据类型

与 int64 数据类型相比,int8 数据类型的值占用的内存少 8 倍。

按照下面提到的列表获取每个数据类型的范围:

(来源)、数据类型及其范围

数据:

我们将使用来自 Kaggle 的纽约出租车行程持续时间数据集进行进一步演示。用熊猫读取数据,占用 467MB。使用 Pandas **.info()** 函数可以观察默认的数据类型和内存使用情况。

(图片由作者提供)、分配的默认数据类型和内存使用情况

数字特征:

对于所有数值,Pandas 将 float64 数据类型分配给至少有一个 float 值的特性列,将 int64 数据类型分配给所有特性值都为整数的特性列。

整数:

New York Taxi Trip Duration dataset中,默认情况下vendor_idpassenger_counttrip_duration 列被指定为 int64 数据类型。

通过观察特性vendor_idpassenger_count的最小值和最大值,可以在 int8 数据类型中调整,特性trip_duration可以在 int32 数据类型中调整。

int64 数据类型的vendor_idpassenger_count功能的内存使用量分别为 11,669,152 字节,减少了约 88%,为 1,458,644 字节。

int64 数据类型的trip_duration特性的内存使用量分别为 11,669,152 字节,减少了约 50%,为 5,834,576 字节。

浮动:

纽约出租车行程持续时间数据集中,默认情况下pickup_longitudepickup_latitudedropoff_longitudedropoff_latitude列被指定为 float64 数据类型。

通过观察上述特性的最小值和最大值,我们可以将数据类型从 float64 降级到 float16。

使用 float64 数据类型的上述特性的内存使用量分别为 11,669,152 字节,减少了约 75%,为 2,917,288 字节。

日期时间:

默认情况下,pickup_datetimedropoff_datetime 列被指定为对象数据类型,可以降级为日期时间格式。

具有 object 数据类型的上述功能的内存使用量分别为 110,856,944 字节,减少了约 90%,为 11,669,152 字节。

分类:

熊猫将非数字特征列指定为对象数据类型,该类型可以降级为类别数据类型。通常,非数字特征列具有分类变量,这些变量通常是重复的。例如,性别特征列只有“男性”和“女性”两个类别,这两个类别在所有重新占用空间的实例中反复出现。将其分配给类别数据类型是一种相对紧凑的表示。

数据类型为 object 的特性store_and_fwd_flag的内存使用量为 90,435,928 字节,减少了约 98%,为 1,458,848 字节。

当任何分类特征的唯一类别数相对小于数据集实例数时,必须将其转换为类别数据类型。

读取数据时进行类型转换:

pandas.read_csv带有一个type 参数,该参数接受用户提供的键值格式的数据类型,可以使用该格式代替默认格式。DateTime 特性列可以传递给parse_dates参数。

使用默认数据类型读取相同的纽约出租车行程持续时间数据集使用了 427MB 内存。在类型转换之后,内存使用减少了大约 70%,只有 135MB。

结论:

本文讨论的类型转换技术可以在一定程度上减少 Pandas read 函数对数据的内存占用。如果数据集的大小与 RAM 相比非常大,那么优化数据类型可能没有帮助。对于如此大的数据集,必须尝试并行化库,如 Dask、Vaex、Modin。

为了更好的理解,请跟随我的一些关于扩大熊猫环境的文章:

参考资料:

[1]熊猫文档:https://Pandas . pydata . org/Pandas-docs/stable/reference/io . html

感谢您的阅读

以意想不到的方式使用 CASE 表达式优化 SQL 查询

原文:https://towardsdatascience.com/optimize-sql-queries-with-case-expressions-in-unexpected-ways-52a8641814c5?source=collection_archive---------12-----------------------

辅导的

是时候通过嵌套的 Case 表达式将您的 SQL 技能从一般提高到非凡了

杰斯·斯洛顿,佩克斯

是那些意想不到的事情改变了我们的生活。—珊达·瑞姆斯

我是黑人,我在一个有帮派的街区长大。和我一起长大的大多数朋友都死了,在监狱里,嗑药了,或者只是卡住了。他们一直将我就读的学校排在最后一名。现在,我正在给一群像我一样的数据极客写技术文章,他们发现生活是一个有待解决的数据问题的未解之谜。真是意想不到。

如果你读过我的其他教程,你会意识到现在我把编程看作是一种艺术努力。挫折中的冒险。每条码线都有自己的色相,美感和质感。它反映了痛苦的检查或反思的几个小时里对编码器的一个贴心的选择。编码员在画布上描绘她的解决方案宽广,反映了她的视角和经验。在写这些教程时,我避开了所有技术复杂性的伪装。真是意想不到。我不会使用过于复杂的术语或例子。我喜欢分享知识,所以我尽量使用通俗易懂的语言。因此,像其他教程一样,本教程向编码人员的添加了一个工具。

储存库是大量储存贵重物品的百宝箱案例表达式应该是 SQL 编码人员百宝箱的一部分。所以,我正在写一系列关于以意想不到的方式使用 Case 表达式的文章。这是系列的第二部:

这些方法可以让你从平庸走向卓越。所以,系好安全带,享受旅程

嵌套 Case 表达式

嵌套 CASE 表达式扩展了 CASE 表达式的功能和精度。案例表达式具有以下特征:

  • CASE 表达式遍历所有条件,并在满足第一个条件时返回值(类似于 if-then-else 语句)。所以,一旦条件为真,它将停止读取并返回值。
  • CASE 允许你显示一列中实际值的替代值。
  • CASE 的一个常见用法是用更可读的值替换代码或缩写。
  • 一个案例可以用计算好的指标构建列。

或者,嵌套 CASE 表达式具有以下特征:

  • 嵌套案例包含了案例的所有特征。
  • 使用嵌套案例,您可以将数据分成子组或段。不同的逻辑可以应用于每个子组。

嵌套 CASE 表达式语法

作者,大小写语法

嵌套 CASE 表达式中,外层语句执行,直到满足一个条件。一旦满足条件,内部的 CASE 表达式就会执行并返回一个结果。如果外部语句中不满足条件, CASE 表达式返回 ELSE 语句中的值。

使用案例

我们虚构的公司在美国有四个分部。该公司希望在每个部门测试不同的定价策略。活动经理要求为每个部门提供一份符合以下要求的数据文件:

  • :如果顾客是 F 住在纽约新泽西的话,顾客会收到 19.99 美元的产品报价。留在北方的其他客户获得 29.99 美元的标准报价。
  • :如果顾客是住在佛罗里达州佐治亚州的 M ale 的顾客,顾客会收到 25.99 美元的产品报价。留在北方的其他客户获得 35.99 美元的标准报价。
  • 西:如果顾客是住在加州或内华达州的话,顾客会收到 29.99 美元的产品报价。留在北方的其他客户收到 39.99 美元的标准报价。
  • 中西部:西部:如果顾客是住在爱荷华南达科他,顾客会收到 21.99 美元的产品报价。留在北方的其他客户收到 31.99 美元的标准报价。

数据:动手操作

请访问 GithubGoogle Drive 上的数据和 SQL 代码,以便跟进。我使用 Postgres 数据库构建了这个解决方案。因此,您需要将数据上传到 Postgres 数据库。或者,您可以更改语法并使用另一个数据库,如 MySQL、Redshift、Oracle 或 SQL Server。

解决方案

当我没有经验的时候,我会查看这些类型的需求以我的方式找到解决方案。我可以想象使用单独的WHERE子句分割数据,然后使用一系列的UNION查询合并数据。最后,通过CREATEUPDATE表格陈述得出解决方案。我会为我花了两天时间来完成“挑战”而感到骄傲。作为一名伟大的 SQL 战士,我杀死了另一个敌人。我觉得我的努力是英勇的,值得为 T21 鼓掌。回想起来,他们既不是也不是。只是因为缺乏经验,所以缺乏想象力或创造力。下面显示的更好的解决方案使用了一个嵌套 CASE 表达式。

作者,嵌套 Case 表达式解决方案

嵌套 CASE 表达式将数据分割成多个部分。一旦细分完成,我们将根据州和性别应用单独的业务需求。结果是一个promotion_price栏目在一两个小时内完成。没有斗争,不眠之夜或争论。真是意想不到。

最后,获得优秀 SQL 技能的途径包括掌握 CASE 表达式以及通用表表达式(CTE 的)、窗口函数和派生表。我将在接下来的教程中分享更多关于这些的内容。不断学习,不断成长,不断分享。那是意料之中的。

如果你喜欢这篇文章,这里有一篇你可能会喜欢的系列文章:

分享的灵感 :每次分享的教训,都让我想起朱利叶斯·邓肯先生。我记得第一天我遇见了他。穿着 白大褂 朝我们家门口走来,我以为他是医生。相反,他是我见过的 最伟大的人 。为了帮助单身母亲,他接受了低于成本的工作。他慷慨地分享他的时间、信仰和资源。对他来说,支付大学课本或以其他方式帮助是很平常的事。当他去世时,排队致敬的队伍持续了一个多小时。他是一个普通的 英雄 黑暗 。不断分享并激励他人变得比他们想象的更伟大。**

[1] Chris Fehily,SQL 的《可视化入门指南》(2008 年)。

优化简化 it 部署

原文:https://towardsdatascience.com/optimize-streamlit-deployment-1b9bb0e415b?source=collection_archive---------20-----------------------

使用 Streamlit 从 Python 部署数据应用程序时要避免的陷阱。

Unsplash科学高清拍摄的照片

部署代码—崩溃应用程序—吸取教训

当您部署一个数据应用程序而不进行内存优化编码时,会发生什么情况?至少对我来说,应用程序崩溃了,我花了几天时间痛苦地重构代码。如果你更幸运或者更聪明(或者两者兼而有之),那么你没什么好担心的。否则,考虑一下从我的错误中吸取的教训和一些有用的资源,以避免你自己特别头疼的问题。

如何避免我的优化错误来部署您的应用程序以取得成功。

为网络编码与为我编码

我一直承认编写优化代码的重要性,但直到部署一个 Web 应用程序,我才完全意识到这意味着什么。在我的笔记本电脑上,即使是写得最差的代码也可能运行,尽管速度很慢。然而,网络上的后果要严重得多——内存泄漏和低效的代码会削弱体验。如果你不喜欢等待应用程序加载,用户也不会喜欢。

在之前的一篇文章中(链接在上方的,我分享了我在部署我的应用时遇到的一些问题。虽然我成功地启动并运行了应用程序,但在添加了更大的数据集后,它开始崩溃。因此,在本文中,我分享一些部署后的问题和解决方案。

部署 Streamlit 应用程序后的两个主要问题:

  1. 应用不可用,因为它已超出其资源限制
  2. 应用程序在部署几小时后崩溃,并在反复重启后继续崩溃

图 1——事实上……部署的喜悦被令人头痛的内存泄漏所中止。来自作者桌面的屏幕截图。

详细问题和关键资源的摘要:

  • 数据帧过大,超过 270 兆字节(MB)!相比之下,100 MB 可能已经太大了。尽管没有一个完美的大小,对于一个有一百万行的表,我最终将文件压缩到了大约 50mb——仍然很大,但还是可以管理的。

第一课:用尽所有可能的选项来减小数据帧的大小。

  • 应用程序将数据帧保存在内存中。这里有一个折衷——将数据保存在内存中以实现快速访问,但保存太多,一切都会崩溃。想都没想,就把应用程序编码成在内存中保存整个数据帧(一开始就太大了)——这被证明是一场灾难。

第二课:有意识地了解存储在内存中的内容。

  • 函数缓存。在我开始搜索关于一个崩溃的 Web 应用的建议后,我发现 Streamlit 有一个方便的 @st.cache 函数装饰器。然后在正确实现了缓存 in 之后,我学习了 TTL 。为了节省时间,从一开始就考虑缓存和 TTL。考虑一下,对于任何多次使用且运行成本很高的函数,缓存可能会有所帮助,因为它将函数的结果保存在内存中。缓存对于一次生成 Plotly 图形并在以后从缓存中检索它们非常有用。

第三课:用@st.cache 缓存函数,不要忘记 TTL 参数。

https://discuss.streamlit.io/t/this-app-has-gone-over-its-resource-limits/7334

  • DataFrame 数据猪。在熊猫数据帧中,当从 对象数据类型 转换为 分类数据类型整数数据类型 时,每列的大小可以减少一半或更多。早期,我转换了大部分内容,但错过了一些专栏——这个疏忽最终吃掉了我的午餐。

第 4 课:在数据帧中应用必要的最小精度;避免像瘟疫一样的“对象”类型。

  • 垃圾进口。这是程序设计的一个总括性问题。举个例子,在每个 Python 文件的顶部,我有用于数据清理的库和包的必要的 import 语句,但是 Web 应用程序不需要。虽然这些垃圾进口没有占用大量的内存,但它们仍然消耗了我无法给予的时间和内存。

第五课:只进口你需要的,扔掉垃圾。

几个具体问题及解决方法

让我们从垃圾箱火灾的粗略快照开始,这是我的程序中的原始架构。在图 2 中,Streamlit 调用了 app.py ,它依次读入数据作为 DataFrames 并调用程序的所有其他函数。起初,这对于我笔记本上的一个小数据集来说工作得很好。不幸的是,在部署带有完整数据集的应用程序后,事情就偏离了轨道。一天结束时,我的小应用程序超出了资源限制,关闭了。

图 2——所有东西都聚集到 app.py 中的原始架构。来自作者 Justin Chae

现在,考虑图 3 中的一个更好的架构。所有东西都被瘦身了,而不是调用一个巨大的表格和臃肿的应用程序。该应用程序只调用上下文菜单所需的一个小文件,并在需要时通过函数调用其他数据。可以肯定的是,这并不完美,但这是对原始版本的巨大改进。

图 3 —架构上的小改进。来自作者 Justin Chae。

贮藏

缓存有两个重要的场景,(1)用 ttl 缓存,(2)用哈希字典缓存。

首先,考虑一个典型的 Streamlit 调用,它从一些其他代码( stat_charts.py )中绘制一个图形,这些代码使用一些函数( graph1 ())进行实际绘制。在这种情况下,程序每次都会重新生成图形。在某些情况下,这可能会导致您的应用程序崩溃或耗尽分配的资源。

**# Streamlit with Plotly, no caching**import streamlit as st
from figs.stat_charts.py import Achartst.plotly_chart(Achart().graph1())

根据文档,你可以尝试使用带有函数包装器的 @st.cache 装饰器。然而,在几个小时的重复调用后,内存问题将会累积并使应用程序崩溃,正如这篇博文中所描述的那样。

**# with basic caching, eventually crash app****@st.cache()**
def make_fig():
    some_fig = Achart().graph1()
    return some_figdef show_objects():
    st.plotly_chart(make_fig()) 

相反,请确保包含用于 max_entriesttl 的参数来管理缓存大小。对我来说,除非有理由不这样做,否则我将默认使用这些参数。

**# with basic cache controls****@st.cache(max_entries=10, ttl=3600)**
def make_fig():
    some_fig = Achart().graph1()
    return some_figdef show_objects():
    st.plotly_chart(make_fig())

图 4 —缓存的第二个问题。

第二,取决于你的函数,你可能会遇到CachedObjectMutationWarning这基本上意味着函数内部的某些东西每次都在变化。根据文档,改变缓存的函数通常是不可取的,但是这篇博客文章提供了一个解决方法。

**CachedObjectMutationWarning**: Return value of overview_data() was mutated between runs.By default, Streamlit's cache should be treated as immutable, or it may behave in unexpected ways. You received this warning because Streamlit detected that an object returned by overview_data() was mutated outside of overview_data().

Streamlit 博客中的一个解决方案非常聪明,它将绘图作为散列字典键值对返回到缓存中。之后,对字典的后续调用。这个超级酷!

**# cache plots in hashed dictionary****@st.cache(hash_funcs={dict: *lambda _*: *None*})**
def make_fig():
    some_fig = Achart().graph1()
    **cached_dict = {'f1': some_fig} **   
    return cached_dictdef show_objects():
    charts = make_fig()
    st.plotly_chart(**charts['f1']**)

优化熊猫

对于熊猫优化,有两个层次要考虑。首先,每一列的数据类型(dtypes)。第二,源文件和数据帧的整体大小和格式。由于这两个优化主题已经被其他的 TDS 文章( 参见参考资料 )很好地涵盖了,我将在这个 Streamlit 部署的上下文中提供一个例子。

在一个应该是布尔值(真/假)的列的例子中,我在某个时候错误地把它变成了文本。因此,该列用两个非布尔值(' nan '和 1)占据了大量空间。).在这种情况下,“nan”是一个文字字符串 nan ,而不是 numpy.nan 类型。

不要让‘南’弦占用宝贵的内存。

**# correcting a mistake for a boolean column
# a DataFrame with about 1 million rows**print(df['flag_col'].unique())
# >>> [nan  1.] **should be boolean!**print(df['flag_col'].memory_usage())
# >>> 15,274,640 **ouch, way too much memory!**

要修补这种特定情况,请用新值映射字典,并应用新的 dtype。请注意,当布尔列的属性类型为 boolean 时,可以节省内存。

**# correct a Pandas Column that should be boolean****# make column into bool**
df['flag_col'] = df['flag_col'].astype('boolean')print(df['flag_col'].memory_usage())
# >>> 8,591,985 **huge savings in memory!**

其他优化考虑事项的清单(酌情适用):

  • 使用浮点数和整数分析所需的最小精度,即 float16 而不是 float64
  • 使用类别数据类型代替对象
  • 有意读取特定列,即 df = df[[col1,col2,col3]]
  • 资源 中所述,压缩大文件,但处理小文件(考虑大文件的空间和解压缩时间与小文件的速度之间的权衡)。

2021 年 1 月 11、13 日更新:

  • 对于 Streamlit 中的 Plotly 图表,创建较小的未压缩 pickle 文件片段,而不是从较大的压缩文件中读取。每个文件应该只包含图表所需的列和数据。在撰写本文时,尽管进行了优化和压缩,我发现如果从单个大型表中读取数据,显示图表的速度仍然太慢。
  • 将布尔转换的示例从“布尔”更改为“布尔”——这是一个主要问题!更多信息,请点击这里阅读:

资源

有时资源部分是事后想起的;然而,我想强调并分享一些关于一个我以前从未想过要研究的课题的信息性文章。

持久化熊猫数据帧的数据文件管理

熊猫数据帧执行中的内存管理

诊断和修复 Pandas 数据帧内存

结论

在本文中,我分享了一个使用 Streamlit 和 Python 的简单数据仪表板应用程序的一些部署后优化缺陷。之前,我分享了一些部署前的问题,但后来,我发现了一些内存和优化方面的其他问题。起初问题并不清楚,但在应用程序不断崩溃后,我意识到我有严重的设计缺陷。感谢网络上的大量建议,我解决并修补了大多数问题。

这些经验可以归结为利用 Web 应用程序上的缓存,尽可能减小数据文件的大小,利用 Pandas 数据帧数据类型中的最低精度,以及简化程序的架构。至于下一步,我正在考虑如何利用库,如 ModinSpark ,以备我用尽技巧并需要更多性能时使用。

我的项目在这里和通过 GitHub 可用,并且实现了本文中描述的所有概念。感谢您的阅读,祝您在下一个项目中一切顺利!

使用 Python 线性编程优化劳动力规划

原文:https://towardsdatascience.com/optimize-workforce-planning-using-linear-programming-with-python-47a0b5f89a6f?source=collection_archive---------11-----------------------

在确保留住员工的同时,你需要雇佣多少临时工来消化你每周的工作量?

使用线性规划的劳动力计划问题—(图片由作者提供)

配送中心(DC) 经理面临的一个主要挑战是一周内工作量的波动。

代表大型电子商务 DC 工作量的每日数据—(图片由作者提供)

在下面的例子中,您可以看到推动您工作量的关键指标的每日变化(#订单、#行、# SKU……)。从一天到另一天,你可以看到需要被你的团队吸收的高度变化。

考虑到你的员工的平均生产率是稳定的,唯一的解决办法就是调整你的资源以满足每天的需求。

💌新文章直接免费放入你的收件箱:时事通讯

一.员工队伍规划:问题陈述

1。场景

你是一家大型零售商的第三方物流公司(3PL)运营的配送中心的 入库经理

您的团队职责包括

  • 从卡车上卸下托盘
  • 扫描每个托盘,在您的仓库管理系统(WMS)中记录收到的数量
  • 将这些托盘放到库存区

团队的全球生产率每周以(托盘/小时)为单位进行衡量。每个月初,您的运输团队同事会分享未来 4 周每天收到的托盘数量预测。

2.劳动力规模

根据这些预测和您的全球生产率,您可以估计每天需要多少资源

每天的入境资源需求预测—(图片由作者提供)

为了更加灵活,您将使用 100%的临时工来建立您的团队。

约束 1:供给必须满足需求

如果你在星期一需要 31 名工人,你至少需要为星期一准备 31 名工人。

约束 2: 工人的最小工作时间

为了确保留住员工,你需要保证每周至少连续 5 个工作日。劳动力来源可能具有挑战性,尤其是如果你的 DC 被电子商务履行中心所包围。

因此,你需要确保临时工的最低工作时间,以成为一个有吸引力的雇主。

约束 3: 每周最大工作时间

按照当地的规定,每个工人在连续工作 5 天后需要休息 2 天。

基于上面列出的约束条件的轮班计划—(图片由作者提供)

第一班的工人从周一开始工作,周五休息两天。她的第六班同事将从周六开始工作,周四休息两天。

目标:尽量减少雇佣工人的数量

按照经理设定的生产率目标,你必须最大限度地减少雇佣工人的数量。如果您没有达到该目标,您的 P&L 可能会受到影响,因为该生产率已被用于计算向客户(零售商)开具的发票价格。

3.线性规划问题

我们通过寻找几个变量 (x[i]) 的一个线性函数(目标函数)的最优值
来定义一个线性规划问题,其条件是变量是非负的并且满足一组线性不等式(称为线性约束)

我们的问题完全吻合!

编辑:你可以在下面的链接中找到这篇文章的 Youtube 版本和动画。

**Variables**
x[i]: number of temporary workers hired for shift i**Constraints**
- For each day the total number of workers on-duty must be higher than the demand- Each worker needs to work a minimum of 5 consecutive days per week- Each worker needs to have 2 days off after 5 consecutive days of work**Objective functions**
The total number of temporary workers hired for all shifts i = 1 … 7 should be minimal

http://samirsaci.com

二。纸浆线性规划

PuLP 是由 COIN-OR Foundation(运筹学计算基础设施)维护的用 Python 编写的线性(LP)和整数规划(IP)问题的建模框架。

你可以在这个 Github 资源库中找到完整的代码:链接
我的其他项目组合: Samir Saci

1.准备你的参数

  • 为每一天创建一个循环列表(如果你需要在周五的基础上增加 5 天,你将到达周三)
  • 工作日列表:如果 day = 0(星期一),则工作日为星期一、星期二、星期三、星期四和星期五
  • 工人每天轮班休息:如果 day = 0(星期一),则第 2 班(从星期二开始)和第 3 班(从星期三开始)的工人休息

2.初始化模型,定义目标并添加约束

  • 初始化【最小化人员编制】模式最小化目标
  • 创建变量 x[i]: 第一班雇佣的工人数量
  • 定义目标:雇佣员工总数 x[i]
  • 添加约束:值班工人总数(非休息日)高于最低员工需求

3.求解模型并分析结果

结果:雇佣了多少工人?

员工总数= 53

洞察力

0 名工人在周四和周六轮班工作

供给与需求:差距是什么?

我们的工人比需要的多吗?

每天工人的供给与需求—(图片由作者提供)

洞察力

周五:1 名额外工人
周六:5 名额外工人

超出

除了优化您的劳动力分配,您还可以遵循流程改进方法来提高每个工人的生产率,就像本文中介绍的拣选方法一样。

https://www.samirsaci.com/improve-warehouse-productivity-using-order-batching-with-python/

三。结论和下一步措施

关注我的 medium,了解更多与供应链数据科学相关的见解。

1.结论

我们的结果符合约束条件,即满足需求。然而,这个规模并不令人满意,因为周五和周六,我们有 6 个额外的人天添加到我们的 P&L。

2.后续步骤

尝试影响几个参数

  • 每周休息两天的限制?
  • 连续工作几天的限制?
  • 每周至少工作 5 天的限制?

你可以尝试这些场景,并在评论区分享你的结果(或问题)。

关于我

让我们在 LinkedinTwitter 上连线,我是一名供应链工程师,正在使用数据分析来改善物流运营和降低成本。

如果你对数据分析和供应链感兴趣,可以看看我的网站

https://samirsaci.com

参考

[1]运筹学的计算基础设施,优化与纸浆(文档),链接

针对 Apache Spark 优化的 Docker 映像—现已在 DockerHub 上公开

原文:https://towardsdatascience.com/optimized-docker-images-for-apache-spark-now-public-on-dockerhub-1f9f8fed1665?source=collection_archive---------20-----------------------

开始使用 Spark 支持的所有通用数据源。

我们为 Apache Spark 优化的 Docker 映像现在可以在我们的 DockerHub 库上免费获得,无论你是否是数据机制的客户。

这是我们工程团队大量工作的结果:

  • 我们构建了一个 Docker 映像舰队,结合了各种版本的 Spark、Python、Scala、Java、Hadoop 和所有流行的数据连接器。
  • 在各种工作负载中自动测试它们,以确保包含的依赖关系能够协同工作——换句话说,将您从依赖地狱中解救出来😄

我们的理念是提供“附带电池”的高质量 Docker 图像,这意味着您将能够使用 Spark 支持的所有常见数据源开始工作。随着时间的推移,我们将维护这些图像,更新 Spark 的最新版本和错误修复以及各种内置依赖项。

Spark 的 Docker 形象是什么?

当你在 Kubernetes 上运行 Spark 时,Spark 驱动程序和执行器都是 Docker 容器。这些容器使用专门为 Spark 构建的图像,其中包含 Spark 分布本身(Spark 2.4、3.0、3.1)。这意味着 Spark 版本不是全局簇属性,因为它适用于纱线簇。

您还可以使用 Docker 映像在本地运行 Spark。例如,您可以在纯驱动模式下(在单个容器中)运行 Spark,或者在本地 minikube 集群上的 Kubernetes 上运行 Spark。我们的许多用户在开发和测试过程中选择这样做。

使用 Docker 将加速您的开发工作流程,并为您提供快速、可靠且可重复的生产部署。图片作者。

‍To 了解更多关于使用 Docker for Spark 的好处,并查看在您的开发工作流程中使用 Docker 的具体步骤,查看我们的文章: Spark 和 Docker:您的开发周期快了 10 倍!

这些 Docker 图像中有什么?

它们包含 Spark 分发版本身——来自开源代码,没有任何专有修改。

它们内置了到公共数据源的连接器:

  • AWS S3 (s3a:// scheme)
  • 谷歌云存储(gs:// scheme)
  • Azure Blob 存储(wasbs:// scheme)
  • Azure Datalake 第 1 代(adls:// scheme)
  • 蔚蓝数据湖第二代(abfss:// scheme)

它们还内置了对Python&PySpark的支持,以及 pipconda 以便于安装额外的 Python 包。(如果不需要 PySpark,可以使用标签前缀为‘JVM-only’的更简单的映像)

最后,每个映像使用以下组件版本的组合:

  • Apache Spark: 2.4.5 到 3.1.1
  • Apache Hadoop: 3.1 还是 3.2
  • Java: 8 或 11
  • Scala: 2.11 或 2.12
  • Python: 3.7 还是 3.8

请注意,并非所有可能的组合都存在,请查看我们的 DockerHub 页面以找到支持列表。

我们的图像包括 GCS、S3、Azure 数据湖、Delta 和雪花的连接器,以及对 Python、Java、Scala、Hadoop 和 Spark 的支持!图片作者。

如何使用我们的 Spark Docker 图片

您应该使用我们的 Spark Docker 映像作为基础,然后通过在其上添加您的代码依赖项来构建您自己的映像。这里有一个 Dockerfile 示例可以帮助您开始:

示例 Dockerfile 文件。图片作者。

一旦你建立了你的 Docker 镜像,你可以通过运行以下命令在本地运行它:Docker run { { image _ name } } driver local:///opt/application/pi . py { args }

或者您可以将新构建的映像推送到您自己的 Docker 注册中心,然后在您的生产 k8s 集群上使用它!

不要以未经验证的方式直接从您的生产集群中提取我们的 DockerHub 映像,因为您有达到速率限制的风险。最好将你的图片推送到你自己的注册中心(或者从 Dockerhub 购买付费计划)。

数据力学用户可以直接使用来自我们 文档 的图片。它们有更高的可用性和一些数据机制独有的附加功能,比如 Jupyter 支持。

结论——我们希望这些图片对您有用

这些图片对你有用吗?需要添加新的连接器或版本吗?请告诉我们,我们希望得到你的反馈。

原载于https://www.datamechanics.co

使用 Python 优化类型

原文:https://towardsdatascience.com/optimized-typing-with-python-d042681be4b2?source=collection_archive---------13-----------------------

照片由努贝尔森·费尔南德斯Unsplash 上拍摄

使用 python 练习和可视化您的输入性能

打字是我们现代日常生活的一部分,因此,学习如何优化打字对像我这样主要在电脑上工作的人来说有很大的好处。

在这篇文章中,我将分享我的日常打字练习,以及我用来记录和可视化我的表现的脚本和软件包。

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片

为什么打字?

我是一名机器学习工程师,也就是说我大部分时间都花在我的电脑上,建立模型,写代码。3 年前,当我在攻读一个生成性对抗网络应用的硕士学位时,我开始注意到,如果我开始在打字技巧上下点功夫,我会更有效率。

因此,我学会了如何触摸打字,三个月后,我的标准打字速度从每分钟 60 个字提高到了 95 个字(今天我的平均速度是每分钟 105 个字),我的编码速度从每分钟 35 个字提高到了 55 到 60 个字。

这种改进对我所有的工作和爱好活动都有很大帮助(比如写作……),我觉得每个人都可以从一点点打字练习中受益。

简化你的打字练习

让我们进入代码!我打字的基本程序超级简单,每天持续大约 5-10 分钟。

我使用 mltype ,这是一个了不起的 cli 工具,可以在你的终端上练习打字。它真的很灵活,开源而且非常整洁!现在,让我们来看看让你的打字练习自动化的脚本。

1.导入依赖项

import os
import pathlib
import random
import pandas as pd
from datetime import datetime
import sys
import plotly.express as px
import plotly.graph_objs as go

2.用 mltype 进行打字练习

def typePractice(typingDataset):
    files = list(typingDataset.iterdir())
    file = random.choice(files)
    with open(file, "r") as f:
        numberOfLines = len(f.readlines()) - 1

    if numberOfLines<=1:
        numberOfLines=2
    elif numberOfLines>10:
        numberOfLines=10

    os.system(f"mlt file --n-lines {numberOfLines} {file}")    

typingDatasetFolder = "path/to/your/typingDataset"
typingDataset = pathlib.Path(typingDatasetFolder)
typingPerformance = "path/to/your/typingPerformance.csv"
df = pd.read_csv(typingPerformance)
typePractice(typingDataset)

在这里,我将所有的 python 文件放在一个名为:typingDataset的文件夹中,我从中选择了一个随机文件,并将其放入对 mltype cli 工具的调用中。我用--n-lines选项给出我想要的文件行数,然后我就可以开始了。键入界面如下所示:

它非常简约,而且非常好用。

3.记录性能并用我的打字性能更新 csv 文件

def updateTypingPerformance(df,datedPerformance, typingDfPath="path/to/typingPerformance.csv"):
    df.loc[len(df)] = datedPerformance
    df.to_csv(typingDfPath, index=False)
    return df

cont = "y"
while cont=="y":
    performance = []
    typePractice(typingDataset)
    date = str(datetime.now())
    wpm = input("What was the wpm?")

    acc = input("Waht was the accuracy?")

    performance.append(date)
    performance.append(wpm)
    performance.append(acc)

    updateTypingPerformance(df,performance)

    cont = input("Continue typing?")

在这里,我使用 python 的内置input()方法获取当前时间并记录我的性能(我想自动完成这一部分,但找不到直接从 mltype 会话中完成的简单方法)。

我给出了一个选项,让我永远继续 while 循环,每次都更新包含我的性能的 csv 文件。

4.绘图选项

import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
from matplotlib import dates as mdates
from matplotlib import ticker

def plotTyping(typingDf):
    typingDf["wpm"] = pd.to_numeric(typingDf["wpm"])
    typingDf["accuracy"] = pd.to_numeric(typingDf["accuracy"])
    typingDf["date"] = pd.to_datetime(typingDf["date"])
    wpmAcc = typingDf.groupby("date")["wpm", "accuracy"].mean()
    wpm = wpmAcc["wpm"]
    acc = wpmAcc["accuracy"]
    fig, ax = plt.subplots(figsize=(15,7))
    ax.plot(wpm,label="wpm trend",color="red")
    ax.plot(acc, label="accuracy", color="green")
#     wpmAcc["wpm"].plot(label="wpm trend",color="red")
#     wpmAcc["accuracy"].plot(label="accuracy",color="green")
    ax.set_xticks(df["date"])
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
    ax.xaxis.set_minor_formatter(mdates.DateFormatter("%Y-%m-%d"))
    plt.gcf().autofmt_xdate()
    ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
    plt.xticks(rotation=45)
    plt.legend()
    plt.show()

if len(sys.argv)>1:
    if sys.argv[1]=="plot":
        plotTyping(df)

在这里,我为我当前的打字性能编写了一个简单的绘图选项,用绿色显示每分钟字数,用红色显示准确率。正如我们所看到的,我的准确率平均保持在 90%以上,打字速度保持在每分钟 50 到 60 字左右。

关于打字的最终想法

打字很有趣,而编写代码来自动化练习打字的过程更有趣。对我来说,这种简单的脚本解决方案总是很值得去做和分享,我希望你能像我喜欢写作一样喜欢阅读!

如果你想知道更多关于触摸打字和如何改进的信息,你可以在这里查看我的帖子:

https://medium.com/digital-diplomacy/type-fast-work-fast-b80eacd10e26

如果你喜欢这篇文章,请在 TwitterLinkedIn 上联系我,并在 Medium 上关注我。谢谢,下次再见!😃

优化复杂模拟?使用科学插值

原文:https://towardsdatascience.com/optimizing-complex-simulations-use-scipy-interpolation-dc782c27dcd2?source=collection_archive---------23-----------------------

在许多情况下,我们可以使用简单插值(Scipy)进行快速优化,而不是使用复杂的优化算法

图片来源:作者创作

背景

在复杂的科学或商业研究中插入实验或模拟数据是一种相当普遍的做法。在我的上一篇文章中,我展示了如何使用简单的 Scipy 代码来实现一维或多维。

https://medium.com/productive-data-science/how-to-interpolate-data-with-scipy-d314143285bc

这种方法的一个关键好处是,我们从 Scipy 例程中获得了精确函数,并可以将其用于多种用途——其中之一是快速优化

这对于单个实验成本高昂的情况尤其有用。在大多数情况下,成本方面远远超出了单纯的计算。想到与昂贵的产品设计迭代,或者医疗保健(药物测试)相关的优化问题。作为设计者或研究人员,你不会有无限的预算来进行数百个实验,因为每个实验可能花费数千美元。

相反,你可以,

  • 运行一组有限的间隔合理的实验(如果你有关于实验设计的知识,那会有很大的帮助)
  • 使用线性、二次或三次样条创建插值函数
  • 运行插值函数以评估密集网格(即数千个点)上的实验/模拟结果
  • 只需选择最大值或最小值以及相应的指数,即可根据您的要求了解哪个输入设置导致了最小值/最大值

没有花哨的优化算法。没有昂贵模拟的成本。只是一些实验设计知识和插值程序。

这种方法不能保证你在所有情况下都有最好的结果。但它在大多数实际情况下都有效。我们来看看为什么。

作为设计者或研究者,你不会有无限的预算来进行数百个实验,因为每个实验可能花费数千美元

为什么它能工作(在大多数情况下)?

插值主要基于平滑度连续性的假设。函数需要平滑,不要过于跳跃,以便以合理的精度进行插值。下图说明了这个想法,假设我们无法收集大量的数据点(实验)。

图片来源:作者创作

而且,事实证明大多数现实生活中的连续数据问题也没有那么跳跃,也就是说,它们足够平滑,可以通过插值技术来处理。因此,在许多情况下,我们可以使用物理模拟和插值的组合来进行快速优化。

图片来源:作者创作

所以,在这里,

图片来源:作者创作

这种方法不能保证你在所有情况下都有最好的结果。但它在大多数实际情况下都有效。

简单的演示

样板代码在我的 Github repo 中。让我在本文中只展示一些相关的代码片段。

模拟和实验功能

假设我们有一个复杂的模拟任务,需要一些时间(这里是 0.1 秒)来完成。实际输出只是一个简单的非线性函数。这是代码,

def complex_simulation(x):
    """
    A nonlinear simulation function with some time delay
    """
    time.sleep(0.1)
    y = np.cos(-x**2/9.0)+np.sin(x/6)
    return y

我们还定义了一个函数run_experiment来运行这个模拟固定的次数。它返回实验域和来自给定边界(低/高端点)的结果。

def run_experiments(experiment_bounds,n=10):
    results = []
    low,high = experiment_bounds
    domain = np.linspace(low, high, num=n, endpoint=True)
    for i in domain:
        y = complex_simulation(i)
        results.append(y)
    return (domain,results)

比方说,我们运行它 11 次,得到这个数据,

图片来源:作者创作

插值和优化

一个简单的三次插值(使用 Scipy),将会给我们这个很好的拟合结果,也是一个新的函数,可以生成任何我们想要的中间结果。

图片来源:作者创作

现在,我们可以用详尽的模拟结果编写一个简单的搜索函数来找到最大值出现的点。

def **optimum_simulation**(experiment_bounds,n=11):
    """
    Using exhaustive simulations
    """
    domain,results=np.array(run_experiments(experiment_bounds,n=n))
    imax = np.argmax(results)
    return (domain[imax])

基本上,它运行实验一定次数(使用之前定义的run_experiment函数)并搜索结果数组的argmax。这在算法上很简单,但由于模拟的性质,速度并不快。当我们为n = 11运行它时,需要大约 1.1 秒,因为每个模拟有 0.1 秒的时间延迟。它得出最佳 x 的结果为, x = 8.0

或者,我们可以定义另一个使用插值函数而不是实际模拟函数的函数。当然,它利用了从有限规模的单次实验中获得的init_results

def **optimum_interpolation**(domain,init_results,n=101):
    """
    Using interpolation
    """
    low,high = domain.min(),domain.max()
    ip_interpolated = np.linspace(low, high, num=n, endpoint=True)
    **f3 = interp1d(domain, init_results, kind='cubic')**
    results_interpolated=np.array(f3(ip_interpolated))
    imax = np.argmax(results_interpolated)
    return (ip_interpolated[imax])

当我们用 n = 101 运行它时,它在大约 900 微秒内完成,并产生结果 x = 7.54

如果你回头看看实际的函数,你会意识到 x = 7.54 比 x = 8.0 更好的逼近最优值。

这意味着插值方法不仅产生了更快而且更准确的结果。这可能并不适用于所有情况,但是的速度优势通常会抵消精度的微小牺牲。

实验事项设计

然而,我们必须注意实验的设计。通常,均匀采样的实验空间是最合适的起点。例如,即使对于我们的简单演示,如果我们用均匀随机的 x 值(不是线性间隔的)做实验,我们可能会得到一个次优的插值函数。

图片来源:作者创作

有关实验设计以及如何使用 Python 包生成健壮的实验计划 的更多信息,请参见我的文章。

在高维空间中非常有用

Scipy 插值例程在二维情况下的工作就像在一维情况下一样简单。由于维数灾难,使用穷举模拟的优化在多个维度上更加复杂和耗时。在这些情况下,插值方法可以派上用场。

这是一个示例结果,其中我们使用 Scipy 插值从稀疏数据中创建了一个平滑的插值 2D 表面。基本上,从 400 个实际数据点,我们创建了一个 4900 数据矩阵,它可以以更高的精度和速度为我们指出最佳点。

图片来源:作者创作(来自同一作者的另一篇文章

摘要

在本文中,我们展示了如何使用简单的插值例程和精心选择的、间隔良好的实验点,我们可以创建能够产生快速优化的插值函数。这种方法特别适用于复杂、耗时的科学或技术模拟,这些模拟的响应或多或少是平滑的。

请注意,虽然我们使用 Python 中的模拟函数展示了演示,但是实验数据可以来自任何来源(例如,数据库、MATLAB 连接器或流式 API),Python 中唯一的部分是基于 Scipy 的插值和后续的搜索例程。

应用领域,如半导体设计、化学工艺优化、生产计划等。,可以从这种方法中获益。

喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果您使用下面的链接, ,我将收取您的一部分会员费,而不会对您产生额外费用

https://medium.com/@tirthajyoti/membership

优化电动汽车充电站以增加使用

原文:https://towardsdatascience.com/optimizing-electric-vehicle-charging-stations-for-increased-use-f514bbb7ab58?source=collection_archive---------18-----------------------

创建预测等待时间和可变使用率仪表板,以重定向电动汽车充电站的流量

詹尼斯·卢卡斯在 Unsplash 上的照片

2020 年,美国的新电动汽车销量创下 2.4%的市场份额新高,投资大力推广电动汽车应用的大都市在电动汽车注册和车型可用性可变性方面处于领先地位

这些促进措施包括降低通行费、免费停车、购买奖励和充电基础设施投资。电动汽车的增长与公共和工作场所充电基础设施的可用性直接相关,主要的大都市地区目前每百万人提供 935 个充电器。

但这还不足以引领电动时代的到来。

今年 4 月,拜登政府宣布了增加美国公共电动汽车充电器数量的雄心勃勃的计划,称公共充电基础设施在未来十年增加道路上电动汽车数量方面发挥着“关键作用”。

“电动汽车充电基础设施是电动汽车普及的最大障碍,”PitchBook 的高级分析师 Asad Hussain 上个月对纽约时报说。

“你和任何犹豫是否购买电动汽车的人交谈,脑海中浮现的第一个担忧就是里程焦虑。”

亚历山大·安德鲁斯在 Unsplash 上拍摄的照片

里程焦虑是指担心电动汽车在你到达目的地或充电之前会没电。如果你曾经担心你的手机没电了,想象一下依靠它让你回家。

汽车制造商通过在电动汽车上提供先进的路线规划来解决这种焦虑——基本上是谷歌地图加。用户在车辆用户界面上计划的任何行程都包括预定的充电站——在哪里充电、电池的电量百分比以及在您可以上路之前充电多长时间。

但这些旅行规划服务目前没有考虑的一件事是车站的繁忙程度:有多少人在车站充电,是否有任何地方可供你充电。

随着越来越多的电动汽车上市,对电动汽车充电站的需求将继续增加,这可能会加剧新电动汽车用户的里程焦虑和充电挫折感。

想象一下,坐在充电站的队列中,看着你的电池电量耗尽到 0%,因为接下来的一个小时所有的位置都被占用了。

照片由何 keiUnsplash

众所周知,与在加油站加油相比,给电动汽车充电确实需要更长的时间,有时可能需要两个小时,这取决于你需要充电多少。

提前向电动汽车司机提供预测的等待时间和各个充电站的充电点可用性可以改变这一切。

根据今年刚刚发表的一项关于适应性路线规划的研究,估计充电站的等待时间并根据站点繁忙程度调整出行规划服务可以减少 97%的等待时间。

因此,我决定将这个想法付诸实践,利用帕洛阿尔托市的公开可用的充电站使用数据来创建仪表板,为消费者显示基于实际充电站使用数据的预测等待时间。

这个想法是为计划出行的电动汽车用户提供当前的使用数据和预测的等待时间,以便他们可以在预计的到达时间内自行选择提供更多可用性的车站。第二个解决方案是通过在车站不经常使用的最佳时间提供较低的费率来激励用户在不太忙的时候使用车站。

在我对数据的初步分析中,我发现帕洛阿尔托公共网络中的电动汽车站,即使是那些相邻的,也有不同的交通模式和高峰繁忙时间。

时间序列仪表板—表格

在帕洛阿尔托市中心一个繁忙的车站等待很长时间可以很容易地避免,只要开车几个街区到一个在同一时间窗口有 5 个空位的车站。

但目前,用户没有实时可用信息,这可能会在不久的将来当路上有更多的电动汽车司机时引起一些大麻烦。

创建这些仪表板的第一步是从帕洛阿尔托市获取数据,您可以在这里选择哪一年来预测等待时间。我选择 2019 年是因为 2020 年是隔离年,但如果你想预测疫情期间充电的等待时间,那么这绝对是你的一年。

接下来是预处理。这个数据集有很多信息,包括每个电动汽车充电插头的 MAC 地址,每个用户的个人邮政编码,以及完成交易的操作(用户或服务器)。就我们的目的而言,我们不需要这些。

Excel 中的原始 Palo Alto 数据

要预测等待时间,您需要站点地址、每个站点插头的唯一标识符(插头 ID 和站点名称的组合)、每次交易的开始时间和结束时间,以及交易数据,如使用的 kWh 和支付的总费用。

在 Excel 中,我创建了两个小时增量的时间窗口,以便预测这些时间段的等待时间。平均事务持续时间大约为两个小时,因此这似乎是跟踪站点繁忙程度的一个很好的基线。

我分别分析了每个工作站的数据,并通过跟踪每个时间窗口中结束的事务之间的时间量,创建了一个运行时间估计值。这意味着如果用户 A 在下午 5:15 离开车站,而用户 B 在下午 5:27 离开同一车站,那么我们有 12 分钟的经过时间。

照片由迈克尔·福塞特Unsplash 上拍摄

如果车站有 1 个或更少的可用位置,我们可以使用交易之间的平均经过时间来估计等待时间,或者下一个用户离开车站所需的平均时间。

最后,我还创建了一些表格,用于计算任意给定时间窗口内每个车站的车辆数量。这包括计数 1)在每个时间窗口中在每个站发起的事务的数量,以及 2)在先前时间窗口中开始的并且在当前时间窗口中仍然存在的事务的数量。

=COUNTIFS('Hamilton Ave Station'!$E:$E,"Sunday",'Hamilton Ave Station'!$G:$G,"0", 'Hamilton Ave Station'!$K:$K,"Sunday",'Hamilton Ave Station'!$M:$M,">=0")

一些用户让他们的汽车过夜充电,而其他人可能只停留 30 分钟,同时获得快速充电。第一种类型的交易需要在汽车在停车场上的所有时间窗内计数,而第二种类型的交易可以在交易发生的时间窗内计数一次。

对于可变费率,我使用 PG & E 针对电动汽车用户的可变费率作为可变费率模型的灵感。

这种模式鼓励夜间收费,当车站是空的,交易持续时间较长。这是激励那些没有家用充电系统的当地用户整夜停车充电的理想时机。

最后,仪表板。

Tableau 是一个交互式数据可视化程序,允许您创建可以根据用户输入进行更改的仪表板。它是这个项目的完美工具,因为它允许我创建一个最终用户产品的模型,电动汽车司机可以使用它来实时查看预测的等待时间和车站繁忙程度。

我用特斯拉 UI 的截图作为这些仪表盘的背景。

用户仪表板—预计等待时间

使用 UI 作为指南,我放入了一个地图,显示每个时间窗口和每天可用的点的数量,如果有一个或更少的点可用,每个站的等待时间,以及向用户显示该时间窗口中的交易数量和交易持续时间的数据可视化。

对于电视台所有者,我构建了一个类似的仪表板,但突出显示了对所有者有用的信息,如每个时间窗口每个电视台的总收入和交易数量,以及每次交易的平均收入。

站长仪表板—收入

在确定最适合激励用户的时间窗口方面,每笔交易的平均收入和电视台的繁忙程度非常有用。

所有加油站晚上 10 点的交易持续时间和平均收入

使用车站仪表板,我们可以确定夜间停车是平均收入最高的最长交易,同时也是车站最不繁忙的时间。

最后,电站所有者仪表板提供了在标准费率(0.23 美元/千瓦时)和建议的可变费率之间切换的能力,这改变了按时间窗口收费的金额。通过在车站应用每千瓦时的可变费率,我们可以通过提供较低的夜间费率来激励夜间停车——这遵循了 PG&E 为电动汽车用户推出的可变费率模式。

车站所有者表仪表板—应用可变利率

Tableau 是一个非常棒的数据可视化工具,也可以用来为消费者和生产者创建数据驱动的最终产品的模型。下次你有一个数据驱动的业务或应用程序的想法,不要忘记使用 tableau 来展示你心目中的真实世界的最终产品。

查看我的 github 了解完整的电动汽车队列项目,以及我的个人网站celiasagastume.com了解更多信息。

用 Amazon SageMaker 优化无服务器推理服务的性价比

原文:https://towardsdatascience.com/optimizing-the-price-performance-ratio-of-a-serverless-inference-service-with-amazon-sagemaker-5969688a2074?source=collection_archive---------44-----------------------

使用 SageMaker 超参数调整和 Locust 为 AWS Lambda 推理寻找最佳设置

我最近发表了一篇关于使用 Amazon SageMaker Pipelines、Amazon API Gateway 和 AWS Lambda 进行无服务器模型部署的分步指南。

菠萝供应公司Unsplash 上拍摄的照片

有了 AWS Lambda ,你只需为你使用的东西付费。Lambda 根据请求数量、执行持续时间和分配给函数的内存量收费。那么你应该给你的推理函数分配多少内存呢?

在这篇文章中,我将展示如何使用 SageMaker 超参数调优 (HPO)作业和一个负载测试工具来自动优化无服务器推理服务的性价比。

我们将重用 XGBoost 模型二进制和 Lambda 推理容器,就像我在上一篇文章中所做的那样。我们将指定一个 Lambda 内存范围,并让 SageMaker 根据延迟-内存总得分找到最佳值。SageMaker 将运行许多作业,每个作业都创建一个推理服务,对其进行负载测试,并返回分数进行优化。我们将使用 LocustInvokust 包装器从 SageMaker 作业中加载测试。

演练概述

我们将通过 3 个步骤找到 Lambda 的最佳内存分配:

  • 我们将首先使用 Boto3 从 SageMaker 训练作业中创建和删除推理服务。
  • 然后,我们将使用 Invokust 对服务进行负载测试,并为性价比生成一个总得分。
  • 最后,我将展示如何启动 SageMaker HPO 作业来自动找到最佳内存值。

先决条件

要浏览此示例,请确保您具备以下条件:

  1. 对于无服务器推理服务,我们将重用我上一篇文章中的容器和二进制模型。开始之前,请确保您熟悉本例中的。
  2. 熟悉 SageMaker 超参数优化 (HPO)岗位。
  3. 使用工作室,一个笔记本实例,或者从你的笔记本电脑访问 SageMaker 环境。
  4. 将这个 GitHub 库克隆到您的环境中来遵循这些步骤。

步骤 1:使用 Boto3 从 SageMaker 培训作业中创建和删除推理服务

首先,我们将使用 Boto3 创建基于 API Gateway 和 AWS Lambda 的简单推理服务。每个 SageMaker 培训作业将通过创建一个服务开始,然后在结束前删除它。

作者图片:无服务器推理服务视图

对于训练作业,我们将使用 PyTorch 估计器和来自 source_dir 文件夹的脚本。这里我们对使用提供的容器比框架本身更感兴趣。

容器入口点是 entry_point.py ,你可以在栈文件夹下找到 boto3 脚本。

用 Boto3 创建 Lambda 函数

我们将使用 ApiGatewayLambdaFunction 类来创建服务。

下面是带有简单创建和删除函数的 LambdaFunction 类:

Lambda 函数的关键参数是:

  • 容器:包含推理代码的容器图像 URI。
  • model _ S3 _ uri:S3 的模型二进制位置。
  • 内存:分配给函数的内存。它根据 SageMaker HPO 的输入而变化。
  • role:由函数承担的 IAM 角色。

步骤 2:负载测试推理服务,并给它一个性价比分数

当一个推理服务被创建时,我们的 entry_point.py 执行一个负载测试来获得它的延迟响应性能。

为此我们使用了 Locust ,这是一个用 Python 编写的开发人员友好的开源负载测试工具。 Invokust 是一个从 Python 本身运行 locust 的包装器,不需要使用 Locust 命令行。它使得从 SageMaker 培训工作中运行负载测试器变得非常容易。

SageMaker 脚本模式使得通过一个 requirements.txt 文件安装这些依赖项变得很容易。

使用示例负载创建一个 locust API 用户

您可以在下面找到一个供 Locust 使用的用户行为示例:

它将向推理服务发送一个示例负载,以便从中获得预测。

运行负载测试并对推理服务评分

然后,我们使用 Invokust 模拟 1000 个用户,100 的生成率,负载测试的运行时间为 1 分钟:

这将允许我们收集推理服务的统计数据。特别是,我们希望使用响应时间的第 95 百分位统计数据作为评估服务性能的关键指标。

下面是来自我们入口点的负载测试代码片段:

在第 11 行中,我们为推理服务计算了一个基本的总分。为了便于说明,我们简单地将 Lambda 内存和响应时间的第 95 个百分点相乘,得到一个数字。这是我们将要求 SageMaker 在 HPO 工作中尽量减少的数字。

根据您的 ML 项目的延迟和成本要求,随意使用更复杂的评分。

第三步:启动 SageMaker HPO 工作,寻找最佳性价比

现在我们准备启动我们的 SageMaker HPO 工作!您可以在下面找到一个示例笔记本,使用我们的代码启动一个示例笔记本:

HPO 的工作将使用贝叶斯搜索,并尝试最小化我们推理服务的总得分。这是为了根据我们的 XGBoost 模型找到一个最佳的延迟-内存(成本)比。

分析您在 HPO 工作的结果

当您的 HPO 作业结束时,您可以导航到 SageMaker 控制台并找到它的结果。在 Best training job 选项卡下,您可以找到 SageMaker 找到的最低分数以及您可以在推理服务中使用的相关 Lambda 内存。

作者图片:在我的例子中,300MB 似乎是分配给 Lambda 的一个不错的值

快速查看该作业的 CloudWatch 日志,可以发现该推理服务的响应时间为 53 毫秒:

作者图片:查看 CloudWatch 日志,并根据工作进行评分

结论

在本文中,我展示了如何使用 Amazon SageMaker 来优化无服务器推理服务的性价比。在我的上一篇关于使用 SageMaker 管道的无服务器部署的文章中,我给 Lambda 函数分配了 1024MB。通过使用 SageMaker HPO,我们自动发现我们可以改为分配 300MB,并且仍然可以从服务获得 53 毫秒的延迟响应。这是 3 倍的内存分配差异!

现在,使用这种模式来优化其他基础设施堆栈怎么样?SageMaker 端点,KFServing,其他?请随意分享你的想法。

利用会议室评分者数据优化您的网络会议背景

原文:https://towardsdatascience.com/optimizing-your-web-conference-background-with-room-rater-data-dad61f966d4a?source=collection_archive---------40-----------------------

照片由 Beci HarmonyUnsplash 上拍摄

通过将自然语言处理和分类算法应用于房间评级者的推文,我们可以学到什么?

在 Zoom calls 上,你对你背后的事情花了多少心思?远程工作,至少是部分时间,可能会成为我们中许多人的习惯。虽然你可能可以在工作中穿着运动裤,但你的演讲中有一个新的元素你以前可能没有考虑过:你的背景装饰、灯光和拍摄角度。

这个项目使用自然语言处理和机器学习管道来预测人们的网络会议背景的质量。这些模型在从房间评级员(@ratemyskyperoom)推特账户收集的推特上进行训练和测试。这个帐户发布人们的网络会议背景照片,评论背景美学,并给他们打 0-10 分。

自然语言处理用于对 tweet 文本进行标记,以识别在背景评估标准中使用的关键词汇。然后,标记化的文本被输入到机器学习模型中,在该模型中测试几个分类器预测评级的能力。

以下是房间评核人给出的较低和较高分数的示例:

让我们看看数据对如何从 3/10 提高到 10/10 有什么说明。

挑战

在 COVID 疫情开始时,许多专业人士发现自己突然开始在家工作,要求他们在厨房、客厅、卧室参加会议,如果幸运的话,还可以在家庭办公室参加会议。

许多人不习惯在这种背景下展示自己,甚至可能更不知道他们的背景是如何形成他们给人的印象的一部分。

输入房间评级人。这个 Twitter 账户开始给人们的网络会议背景打分,称赞他们在背景中对植物和书籍的良好安排,或者批评他们的照明和相机角度。

如果我们将自然语言处理应用于房间评级员的推文,我们能破解他们的评分系统并预测 10/10 的背景吗?

机器学习管道:输入和输出

变量

预测变量:推文文本

结果变量:评级,1-10 级的多类别变量

评估指标

为了评估分类模型,将使用以下指标:

  • 准确性 —准确预测的标签部分
  • 精度 —正确预测的特定类别的预测部分(例如有多少预测为 9 的实际上是 9)
  • 回忆 —正确预测的特定 a 类的部分(例如。有多少个实际的 9 被预测为 9)
  • F1 得分——精确度和召回率的调和平均值
  • ROC AUC 得分—ROC 曲线下的面积(真阳性率对假阳性率),. 5 表示模型表现与随机分类相当。

因为评级是有序的,所以上面的度量没有考虑到错误分类的程度。他们不会意识到把 10 错划为 9 比把 10 错划为 2 更好。因此,我们还将使用以下数据点来评估与正确值的距离:

  • 实际评分和预测评分之差的平均绝对值

数据收集

这里有一些资源可以帮助你开始使用 Twitter API 和一个有用的 Python 包来获取 tweets:

创建一个函数来收集来自 @ratemyskyperoom 的推文,如果我们想扩展我们的数据集,可以很容易地返回来收集更多的推文。

一旦你收集了推文并把它们存储在一个数据帧中,下面是它们的样子:

在将数据加载到模型中之前,我们需要将数据解析成 X 和 y 变量。

数据预处理

准备数据集进行分析的第一步是提取结果变量,即评级。幸运的是,房间评分者的评分格式是一致的,这使我们能够将评分识别为“/10”之前的数字。

数据探索

在选择和应用模型之前,我们应该花时间了解我们的数据。

直方图显示结果变量严重不平衡,接近 10/10。我们将通过各种模型探索解决这一问题的方法。

(图片由作者提供)

自然语言处理

我们使用了几种自然语言处理技术来识别房间评级者推文中最常见的词语:

  • 删除标点符号、URL 和其他非文本字符,并规范大小写
  • 删除英语停用词(the,a,an)
  • 单词标记化将句子分解成单词单元进行分析
  • 将像 plant 和 plant 这样的单词处理成单个标记

在将表征输入分类模型之前,可视化表征可能是有帮助的。

让我们来看看 10/10 最常见的单词。

(图片由作者提供)

我们可以推断,房间评级机构称赞背景艺术的大量使用。植物、鲜花、枕头和书籍也是很好的配饰,也能营造一种深度感。

对其他评级重复这一分析,我们看到中低评级的背景需要在相机角度上进行工作,并保持它们的线在视线之外。背景得分在 7-9 分范围内的有一些基本的东西,可以专注于融入像植物艺术这样的元素来增加趣味性。如果你身后有一面空白的白墙,你将被指控制作了一个人质 视频,并可能获得 2 或 3 级评分。

按背景评级排列的热门关键词。(图片由作者提供)

机器学习管道

评估了五个分类器:

  • 随机森林分类器(在不同的子样本上拟合多个决策树分类器,以最小化过度拟合)
  • 平衡随机森林分类器(通过使用欠采样来平衡随机森林分类器)
  • 梯度推进分类器(运行多个决策树分类器以最小化损失函数)
  • 简易集成分类器(使用 AdaBoost 分类器作为基本估计器,对引导样本采用随机欠采样)
  • 有序逻辑回归(考虑到评级的顺序是有意义的)

GridSearchCV 用于评估分类器的几种参数组合。

以下函数可以帮助我们重新运行多个分类器的评估,而不必为每个模型重复代码。

  1. 由于预测变量是多类别的(输出范围为 0-10),结果标签必须二进制化,以便计算 ROC AUC 得分。

2.将预测评级合并回原始数据框架将允许我们通过可视化和统计来比较实际值和预测值。

3.创建的可视化函数,例如实际值与预测值的热图,可以快速显示结果。

4.打印评估分数的集合可以帮助我们更容易地比较模型。

让我们来看两个不同的模型,随机森林分类器和一个解决数据中类别不平衡的变体。

建立和应用模型

下面的管道首先使用前面开发的标记器转换文本,然后应用选择的分类器。使用 GridSearchCV,您可以同时评估几组参数,并返回最佳参数。

GridSearchCV 选择的参数:

model_rf.best_params_{'clf__class_weight': 'balanced_subsample',
 'clf__min_samples_leaf': 2,
 'clf__n_estimators': 100}

快速查看实际评分和预测评分:

(图片由作者提供)

print_scores(y_test_rf, y_pred_rf, pred_df_rf)accuracy score:  0.45
precision score:  0.5
recall score:  0.45
f1 score:  0.46
roc_auc_score:  0.65
avg diff, actual v pred:  2.36

就任何评估指标而言,模型性能都不是很强。平均而言,它预测的评分与实际评分相差 2 个多点。让我们使用平衡随机森林分类器重新运行该模型,该模型旨在通过欠采样解决类别不平衡问题。

查看平衡随机森林分类器的指标,该模型在指标上的得分甚至更低:

accuracy score:  0.1
precision score:  0.33
recall score:  0.1
f1 score:  0.11
roc_auc_score:  0.55
avg diff, actual v pred:  4.54

为了理解其中的原因,让我们将随机森林分类器和平衡随机森林分类器的实际评级分布与预测评级进行比较:

(图片由作者提供)

上面的分布图将实际评级与随机森林分类器和平衡随机森林分类器的预测评级进行了比较。我们可以看到平衡分类器产生了更广泛的预测分布。

我们可能要考虑测试数据集是否反映了真实世界的现实。我们知道房间评级提供了很多 10/10 评级。这与现实相符吗,还是房间评级者在他们选择发布的照片中引入了偏见?从个人经验来说,我在同事中看到的平均背景(包括我自己!)是相当简单和一维的,可能更接近于 3/10 而不是 10/10。

梯度增强、平衡 AdaBoost 和有序逻辑回归

其余的模型,梯度增强分类器、平衡 AdaBoost 分类器和有序逻辑回归,对度量执行类似的操作。

像平衡随机森林分类器一样,平衡 AdaBoost 分类器也使分布变平。平衡 AdaBoost 的性能优于平衡随机森林。我们可以在上面看到,平衡的随机森林导致了更极端的重新平衡,峰值在 0/10 和 7/10 的评级附近,而不是像实际值那样的 10/10。平衡 AdaBoost 峰值出现在 9/10,更接近实际值。

(图片由作者提供)

尽管利用了结果变量的有序性质,有序逻辑回归并没有胜过其他模型,但是开发一种将有序方法应用于其他分类器的定制集成方法可能是值得测试的。有序逻辑回归更接近真实数据集,比平衡模型更接近 10/10:

(图片由作者提供)

外卖食品

通过自然语言处理,我们能够识别出构成良好背景的关键元素:艺术、植物和书籍。我们还了解到,仅仅拥有这些元素并不能成为很好的背景。对于顶级收视率,还必须创造一种深度感,注意照明,并使用熟练的取景和拍摄角度。

机器学习模型表现不佳。一个挑战是中低评级的代表性不足。也很难判断模型在现实世界中的表现如何,因为样本数据是由房间评级机构预先选择的。10/10 背景的过度呈现可能是由于房间评级者选择他们喜欢的照片,而你的日常背景可能更平庸。

进一步改进

我们可以从几个方向从这些数据中提取更多信息。

情感分析

向管道中添加额外的情感分析步骤可以改进该模型。我们看到像“深度”、“照明”、“重构”这样的普通词,但如果我们能更好地区分这些词是正面使用还是负面使用,我们会获得更多的价值。

动词形式分析

识别动词类型,查看是否使用了命令形式,也有助于我们识别房间评定者是在称赞此人的有效使用,还是在提出建议。例如,在“良好的重构”中使用动名词(-ing)是积极的,而在“重构”中使用命令形式是一种改进的建议。

深度学习和图像分类

另一个可以增强模型的数据源是实际的照片。可以开发一种神经网络来识别 10/10 背景中的视觉相似性。像情感分析一样,这个模型可以帮助评估照明的质量、装饰的位置和摄像机的位置。

人们可以进一步推进这个项目,创建一个应用程序,允许用户上传他们的网络背景照片,并通过图像分析,建议添加植物,艺术品,书籍,或调整照明和框架。

你认为 10/10 的背景是什么样的?房间评级员有最终决定权吗?

点击此处访问 GitHub 知识库: laurenmarar/RoomRater:使用数据科学优化您的缩放背景(github.com)

致谢

这篇博文是 Udacity.com 大学数据科学纳米学位顶点项目的一部分。

期权定价使用布莱克-斯科尔斯模型,没有公式

原文:https://towardsdatascience.com/option-pricing-using-the-black-scholes-model-without-the-formula-e5c002771e2f?source=collection_archive---------12-----------------------

定量金融学基础的另一个视角,布莱克-斯科尔斯公式。

每个选修金融课程的大学生都见过布莱克-斯科尔斯-默顿期权定价公式。它又长又丑,令人困惑。它甚至没有给出期权定价的直觉。它的推导是如此的困难,以至于斯科尔斯和默顿为此获得了 1997 年的诺贝尔奖(布莱克于 1995 年去世)。它依赖于费曼-卡奇定理和风险中性指标,但我不会深入探讨。

(https://en . Wikipedia . org/wiki/Black % E2 % 80% 93 choles _ equation)。

布莱克-斯科尔斯偏微分方程

期权的定价可以用 Black-Scholes 偏微分方程(BS PDE)来完成。BS PDE 可以通过将 Ito 引理应用于几何布朗运动,然后设置必要条件以满足连续时间 delta 对冲来导出。

布莱克-斯科尔斯偏微分方程。

我们将使用 Python 数值求解这个方程。这种方法的主要优点是它绕过了用数值方法进行的非常复杂的分析计算,这些计算是由我们的计算机来完成的。

偏微分方程的数值解

当我们试图用数值方法求解偏微分方程时,我们需要先建立一些东西。首先,我们将使用它来评估执行价格为 k 的欧式看涨期权。我将使用的方法称为有限差分法,它涉及到建立一个网格点。

这个网格将用于点对点模拟 PDE。x 轴上的网格将代表模拟时间,范围从[0,1]开始,y 轴将代表可能的股票价格,范围从[S_min,S_max]开始。结果将是一个三维图形,我们的工作是确定网格上每个点的期权价格。

点网格。(图片由作者提供)

为了在网格上进行模拟,我们需要确定网格的 3 个边界(边缘)条件。在我们的例子中,我们可以对网格的顶部、底部和最后边界这样做。我们稍后还会看到,由于这个原因,我们将反向模拟等式。底部是最容易的,我们将设置S_min=0。顶部条件有点棘手。它应该远高于期权的执行价格 K,以确保期权的价值V = max( S-K, 0)总是(不发生p < 0.0001的概率可以忽略不计)支付S-K。我们可以通过设置S_max远离平均值 8 个标准差来做到这一点,因为股票价格是对数正态分布的。所以,如果我们取S_max=8sigma*(T-t)^0.5,我们就保证了那个属性。

S_max处的选项值V可以使用复制自变量来推导。如果一个衍生品在时间 t 支付S-K,我们可以通过购买 1 个单位的股票并将e^(-r(1-t)*K放入无风险银行账户来复制它。所以这使得选项的值为大 S: V(t,S_max)=S_max — e^(-r(1-t)*K

最后的边界条件将是欧式看涨期权的收益,因为这将给出期权的确切价值。所以三个边界条件是:

边界条件。

我们现在已经建立了网格的边界条件。接下来,我们需要离散化我们的空间,这将允许我们对 BS PDE 的导数使用中心差分估计。

布莱克-斯科尔斯偏微分方程。

在股价方向(垂直)上,我们引入 M 个点。来思考一下这个,假设 S 的可能范围是[0,100]M=100。这将产生 100 个股票点,每个整数为 1。我们在时间方向(水平)用 N 步做同样的事情。这将创建一个N+1 x M+1矩阵,我们可以用它来创建导数估计值。

估计导数

有了离散化的空间,我们可以对期权价值的导数(希腊人的 delta 和 gamma)使用中心差分估计。

BS PDE 中的导数近似。

将这些代入布莱克-斯科尔斯偏微分方程,我们得到

具有中心差分估计的布莱克-斯科尔斯偏微分方程。

这可以很容易地通过想象上面的等式来理解。基本上需要 3 个点,并计算这些点的加权平均值,以在时间上向前一步到达点。

(图片由作者提供)

通过重复上面的过程,我们可以一步一步地模拟上面的网格。注意,因为我们知道最后的边界条件,而不是第一个,我们将会回到过去。

模拟

将欧拉-丸山方案应用于离散化的布莱克-斯科尔斯偏微分方程,我们得到:

这是一个 ODEs 系统,其中 V 是每个时间步长的期权价格的列向量。此外,我们需要在上面包含时间 t: W_t的边界条件的方程中添加一个向量,然后我们可以用矩阵符号重写方程,这样Lambda就包含了乘数。这个方程现在包含了我们所有的信息,被称为显式方法。它使用关于 t 的 V 的后向差估计,如果我们正在模拟前向 It 时间(我们正在模拟后向),这相当于前向差。

所以,为了编码,我们需要边界条件的函数。

import numpy as np
import scipy.sparse
import matplolib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3Ddef bottom_boundary_condition(K,T,S_min, r, t):
    return np.zeros(t.shape)def top_boundary_condition(K,T,S_max, r, t):
    return S_max-np.exp(-r*(T-t))*Kdef bottom_boundary_condition(K,T,S_min, r, t):
    return np.maximum(S-K,0)

我们还需要函数来计算Lamda中的系数。我为此编写了两个函数,这是我在对带有中心差分估计的方程进行了一些代数运算以隔离每个V_i之后得到的。

def compute_abc( K, T, sigma, r, S, dt, dS ):
    a = -sigma**2 * S**2/(2* dS**2 ) + r*S/(2*dS)
    b = r + sigma**2 * S**2/(dS**2)
    c = -sigma**2 * S**2/(2* dS**2 ) - r*S/(2*dS)
    return a,b,cdef compute_lambda( a,b,c ):
    return scipy.sparse.diags( [a[1:],b,c[:-1]],offsets=[-1,0,1])def compute_W(a,b,c, V0, VM): 
    M = len(b)+1
    W = np.zeros(M-1)
    W[0] = a[0]*V0 
    W[-1] = c[-1]*VM 
    return W

将所有这些组合在一个函数中,该函数基本上用期权值填充N x M矩阵,并返回期权值V、时间t和股票价格S

def price_call_explicit( K, T, r, sigma, N, M):
    # Choose the shape of the grid
    dt = T/N
    S_min=0
    S_max=K*np.exp(8*sigma*np.sqrt(T))
    dS = (S_max-S_min)/M
    S = np.linspace(S_min,S_max,M+1)
    t = np.linspace(0,T,N+1)
    V = np.zeros((N+1,M+1)) #...

    # Set the boundary conditions
    V[:,-1] = top_boundary_condition(K,T,S_max,r,t)
    V[:,0] = bottom_boundary_condition(K,T,S_max,r,t)
    V[-1,:] = final_boundary_condition(K,T,S) #...

    # Apply the recurrence relation
    a,b,c = compute_abc(K,T,sigma,r,S[1:-1],dt,dS)
    Lambda =compute_lambda( a,b,c) 
    identity = scipy.sparse.identity(M-1)

    for i in range(N,0,-1):
        W = compute_W(a,b,c,V[i,0],V[i,M])
        # Use `dot` to multiply a vector by a sparse matrix
        V[i-1,1:M] = (identity-Lambda*dt).dot( V[i,1:M] ) - W*dt

    return V, t, S

绘制tSV的对比图,我们得到了每个时间-股票组合的期权收益图。

期权价格为 K=50,r=0.02,σ= 0.2,N=M=50。(图片由作者提供)

我们可以看到在t=1期权价值正好等于它的收益,这是一个很好的健全性检查。下面你可以看到曲线是如何在最后时刻演变成期权收益的。这正是我们想要的。

切片图。(图片由作者提供)

结束语

使用 Black-Scholes PDE 为期权定价是一个很好的直觉构建例子,但遗憾的是它不能真正用于实践。主要是因为用起来慢,而且我们有配方可以用。通过调整 Crank-Nicholson 方法进行模拟,可以使我的上述方法更加稳健,这使得该过程不那么敏感。

如果你想知道更多关于推导的信息,或者更深入的代码回顾或者 Crank-Nicholson 方法,请告诉我。

我想补充一点,我从我在 KCL 的金融数学讲师小约翰·阿姆斯特朗博士那里学到了很多东西。https://nms.kcl.ac.uk/john.armstrong/

如果你对布莱克-斯科尔斯模型不熟悉,看看这篇文章就能得到很棒的介绍:https://medium . com/cantors-paradise/the-Black-Scholes-formula-explained-9e 05 b 7865d 8 a

OPTUNA:一个灵活、高效、可扩展的超参数优化框架

原文:https://towardsdatascience.com/optuna-a-flexible-efficient-and-scalable-hyperparameter-optimization-framework-d26bc7a23fff?source=collection_archive---------9-----------------------

轻型和大型超参数优化的新选择

图一。关于超参数优化的漫画|作者图片|图标取自 smashiconsfreepik

建立机器学习模型时的一个决定性任务是超参数优化。超参数的正确优化直接反映在模型的性能上。这就是为什么超参数优化多年来一直是一个活跃的研究领域。幸运的是,今天有几个备选方案可以用来优化机器学习模型,如:hyperpt[1spearmant[2Vizer [ 3AutoSklearn[4Autotune 这些备选方案中的每一个都提出了各种优化范例。同样,这些优化工具中的每一个都提出了不同的可用性方法,这些方法可以根据情况变得或多或少地灵活。

在这种背景下, Optuna [ 6 出现,其目标是将优化范例统一在由三个支柱支持的理念下:按运行设计 API* 、高效实现易于设置。因此,在这篇博客中我们将看到什么是 Optuna ,它的组件,它的优化范例,以及如何用 Scikit-LearnPyTorch 将其付诸实践。所以这个博客会分为:*

  • 什么是 Optuna?
  • Optuna & Scikit-Learn 集成
  • Optuna & PyTorch 集成

什么是 Optuna?

Optuna 由 Takuya Akiba 等人引进。艾尔。[6]2019 年。 Optuna 是一个用于超参数优化的开源 python 库。在后台, Optuna 旨在平衡采样修剪算法。 Optuna 实现了独立参数采样的树形 Parzen 估计器 (TPE) [ 78 以及高斯过程 (GP) [ 8协方差矩阵自适应(CMA)9[同样, Optuna 为搜索空间的修剪实现了异步连续减半 (ASHA) http://www.cmap.polytechnique.fr/~nikolaus.hansen/cmaartic.pdf 10 ]算法的变体。**

Optuna 作为一个超参数优化软件出现在一个新的设计标准下,该设计标准基于三个基本思想: 定义运行 API ,它允许用户以动态方式构建和操作搜索空间, 高效实现 ,它专注于采样策略以及修剪算法的最佳功能, 易于设置在图 2 中,我们可以看到对 Optuna 架构的可视化描述。**

图二。Optuna 系统架构|作者图片

Optuna 的设计标准使其易于实施、灵活且可扩展。由于 Optuna 的可扩展性,大规模实验的优化可以以并行和分布式的方式进行。 Optuna 是框架不可知的,也就是说,它可以很容易地与任何机器学习和深度学习框架集成,如: PyTorchTensorflowKerasScikit-LearnXGBoost 等。

Optuna 的实现相对简单直观。在代码片段 1 中,我们可以看到一个基本的 Optuna 实现的框架。基本上,需要定义 python 函数,该函数将充当过程的包装,以获得要优化的值(最小化或最大化)。该程序包括 3 个基本步骤,搜索空间的定义,模型实现,以及待优化值获取。**

代码片段 1。Optuna 实现的基本架构。

太好了,到现在为止我们已经知道了 Optuna 是什么,它的组件和属性。现在让我们来看看几个集成。在下一节中,我们将看到 OptunaScikit-Learn 的集成,稍后我们将看到 PyTorch 的集成,让我们开始吧!

Optuna&sci kit-Learn 集成

在这个例子中,我们将通过使用众所周知的乳腺癌数据集随机森林算法来解决分类问题。想法是实现 Optuna 来优化每个随机森林超参数,以便最大化将通过 K 倍交叉验证过程生成的平均精度

代码片段 2。optuna & sci kit-学习集成

正如我们在前面的代码片段中看到的,包装器包含了搜索空间的定义、模型和要优化的值的计算。从第 4 行到第 6 行,执行待优化的 3 个超参数的搜索空间的定义。我们可以看到,对于随机森林算法的决策树的分裂准则,定义了一个分类搜索空间,另一方面,对于估计器的数量和最大深度,定义了整数搜索空间。随后,初始化随机森林模型(第 9 行),并且在 k 倍交叉验证过程下执行训练(第 18 行),存储每个倍的准确度(第 32 行),并且最终返回平均准确度(第 34 行)。该函数的返回(在本例中为平均精度)是每个 Optuna 研究的每个试验用作调整采样和修剪算法的参数。最后,该函数的优化可以通过以下定义来实现:

代码片段 3。研究定义

最后,当执行优化,获得最优超参数并用这样的最优配置训练模型时,我们获得:

**Best average accuracy: 0.9666356155876418
Best parameters: {'criterion': 'entropy', 'n_estimators': 40, 'max_depth': 6}Train score: 1.0
Test score: 0.982456140350877**

你可以在这里找到这个例子的完整实现:https://github.com/FernandoLpz/Optuna-Sklearn-PyTorch

我们可以看到, OptunaScikit-Learn 的集成相对简单直观。一般来说,包装 Scikit-Learn 模型,返回要优化的值就足够了。 Optuna 研究的定义允许我们确定该程序是最大化还是最小化

现在让我们来看看与 PyTorch 的更强大的集成,我们将尝试找到神经网络应该包含的最佳超参数甚至最佳层数,让我们开始吧!

Optuna & PyTorch 集成

在这个例子中,我们将利用众所周知的 MNIST 数据集来解决一个多类分类问题。出于实用目的,我们将实现的神经网络将只包含线性层。想法是使用 Optuna 来找到模型的最优超参数,例如:优化器和学习率。此外,我们将使用 Optuna 找到神经网络中的最佳层数以及每层的最佳单元数**

让我们首先从神经网络的定义开始:

代码片段 4。神经网络定义

Optuna 的一个优点是它允许我们定义动态定义搜索空间的对象。在这种情况下,我们首先初始化一个空堆栈,其中定义线性层的对象和由试验(第 6 行和第 7 行)确定的漏失将被动态存储。随后,定义层数和漏失的搜索空间(第 11 和 12 行)。然后开始将由 trial 定义的动态数量的线性层以及每层的单元数量引入堆栈的过程。值得一提的是,第一层的输入维度和最后一层的输出维度将始终是静态的(分别是第 15 行和第 29 行)。其余层的尺寸将由试验(第 20 行)决定。此时,我们已经有了一个包含各自输入和输出维度的线性图层堆栈和一个辍学堆栈。然而,在 PyTorch 中,定义神经网络的类必须有引用定义神经网络每个组件的对象的实例变量。在这种情况下,堆栈中定义的每个层和 dropout 必须定义为实例变量(第 36 和 39 行)。最后是前进功能。由于层和漏失的数量已经在堆栈中定义,我们只需要展开堆栈并在每个层和漏失上传递输入张量 x* 。*

正如我们已经观察到的,神经网络的定义并不意味着复杂性,只是被认为是网络的每个组件的动态分配。现在让我们看看如何为超参数优化训练这个神经网络。

代码片段 5。优化功能

考虑到代码片段 1 中显示的框架,代码片段 5 中定义的包装器函数将等同于神经网络的优化。首先,通过将试验作为参数(第 4 行)传递给神经网络进行初始化,然后定义优化器学习速率的搜索空间,就这样。剩下的就是分批训练神经网络并计算测试集中的精度,这样的精度就是返回的值,也是 Optuna 用来执行优化的值。

最后,在进行优化时,我们得到以下结果:

*Best accuracy: 0.944831498
Best parameters: {'n_layers': 2, 'dropout': 0.2048202637410447, 'output_dim_0': 13, 'output_dim_1': 24, 'optimizer': 'Adam', 'lr': 0.0030389965486299388}Train score: 0.95349231
Test score: 0.94231892*

你可以在这里找到这个例子的完整实现:https://github.com/FernandoLpz/Optuna-Sklearn-PyTorch

结论

在这篇博客中,我们了解了什么是 Optuna ,开发 Optuna 的理念是什么,它的组件以及几个 OptunaScikit-LearnPyTorch 集成的例子。

**超参数优化有多种选择。一些共享优化方法,采样和修剪算法的相似性。同样,每一个都为每种工具的使用和实现提出了具体的特征。在这种情况下, Optuna 作为超参数优化工具出现,它专注于实现的简单性、灵活性和可伸缩性,这使得它成为迄今为止被广泛接受的工具。

参考

[1] Hyperopt:用于优化机器学习算法的超参数的 Python 库

[2] 留兰香储存库

[3] 维泽

[4] Auto-Sklearn 2.0:下一代

[5] 自动调优:超参数调优的无导数优化框架

[6] Optuna:下一代超参数优化框架

[7] 树形结构 Parzen 估计器

[8] 超参数优化算法

【9】进化策略中完全去随机化的自适应

【10】大规模并行超参数调谐系统

轨道飞行器:重新发明(球形)轮子及其控制算法

原文:https://towardsdatascience.com/orbitron-reinventing-the-wheels-and-its-control-algorithm-8f60ffd44238?source=collection_archive---------40-----------------------

我花了六个月的时间建造了一辆四轮独立驾驶汽车

作为一个重度科幻迷,我总是想知道:那些来自 TronI-Robot 的球形轮子在现实生活中会如何工作?这个简单的想法开始了为期 6 个月的轨道计划之旅。

这个项目一开始就有两个主要目标:

  • 使用 Arduino 制造一辆配有球形车轮的汽车,实现 4 轮独立转向/驱动(4WIS/D)系统
  • 在 Mathematica 中开发 4WIS/D 车辆直观控制算法

这篇文章将展示我的车辆原型 Orbitron 以及建筑场景背后的一个小故事。然后,我将向您介绍亮点:我构建的一个智能算法,用于无缝控制 Orbitron。

您也可以查看我为大学申请制作的这个 maker 组合视频 或查看包含完整代码的 GitHub repo

O RBITRON

正如我上面提到的,轨道飞行器是一种带有球形轮子的交通工具,因此被命名为‘ORB’itron。不幸的是,我有点不够资格用电磁铁将车轮悬浮在半空中,就像许多科幻电影建议的那样。相反,我实现了一个 4 轮独立转向/驱动(4WIS/D)系统:一个用于四轮车辆的转向系统,允许对每个车轮进行单独的速度和方向控制。

肯特预工程中心展示的轨道飞行器(图片由作者提供)

结构

在车轮框架的初始草图之后,我在 Fusion 360 中模拟了相同的设计。我在车架上设计了两个独立的马达,每个马达控制速度和方向,独立地操纵和驱动车轮。

初始车轮草图(图片由作者提供)

我用一个 60 毫米的 EVA 泡沫球作为车轮,因为它们很轻,但足够坚固,可以支撑车辆。顶部带有内置变速箱的 HS-785HB 伺服系统通过转动电机的整个矩形结构来控制车轮的方向。转速为 170 RPM 的 Econ 齿轮马达直接连接到球体的轴上,负责驱动车轮和控制速度。

车轮结构(图片由作者提供)

设计车身相对简单,因为它只是一个支撑轮架的矩形板。

初始身体草图(图片由作者提供)

一开始我用中密度纤维板做了车身,但事实证明它太重了。所以我换成了 PVC 管支撑的 Foamex 板,轻多了,结实多了。

主体框架(图片作者提供)

为了在我飞回韩国的暑假期间继续这个项目,我精心设计了可折叠的板子,以方便海外运输。这样,我只需拆下轮架,将板折叠起来,并在运输时用气泡包装覆盖即可。

电子学

在这里我不会对布线做太多的详细说明。简而言之,Arduino Mega 连接到 XBee shield 进行无线通信,两个电机驱动器用于控制驱动电机,四个伺服电机用于控制每个车轮。

在首尔国立大学实验室测试所有组件(图片由作者提供)

在构建过程中,我开发了一个简单的 C# WinForms 应用程序,以确保每个组件都能正常工作。这个应用程序将通过 XBee 无线模块发送字母信号,Orbitron 将执行预先设置的动作,例如当收到' r '字符时,将所有伺服系统旋转 180 度。

原型控制软件(图片来自作者)

算法

这个项目的真正美妙之处在于算法开发。下面的文字将总结我的论文: 【使用空间鼠标的 4WIS/4WID 直观控制算法开发】

Orbitron 的 4WIS/D 系统为需要在狭小空间中导航的车辆提供了更灵活的运动,但控制每个车轮的两个参数(方向和速度)会导致需要同时控制八个参数。

所以我们的目标很简单:开发一种算法,实现直观的控制,抽象出复杂性,允许充分实现车辆的功能。

算法设置

我们选择 3Dconnexion 的 SpaceMouse (SpaceNavigator)作为控制器,因为它是为在 CAD 中的 3D 空间上进行直观导航而设计的。

将 SpaceMouse 与 Mathematica 连接起来,根据鼠标的位置,我们得到了从-1 到+1 的六个数字,这成为了我们算法的原始输入数据。

算法管道(图片由作者提供)

该算法的主要工作是将来自 SpaceMouse 的这六个变量转换为八个变量,每个变量代表一个轮子的角度或速度。该算法负责计算变量转换,并将带有时间戳的变量集记录在 CSV 文件中。然后,我们使用一个串行调节器,一个我开发的 C#应用程序,在适当的时间传递变量集,而不会向原型过度提供数据。

Mathematica 算法(图片作者提供)

Mathematica Notebook 执行时,右边的界面会根据用户的输入不断更新。该界面中显示的所有箭头都用不同的颜色编码,以便更容易区分彼此。每个车轮旁边显示四个标签,以显示更新的角度和速度值。

  • 绿色同心圆:分别代表每个车轮的曲率半径和车辆的中心。这可以应用于具有任意数量车轮的车辆,但只是具有更多曲率圆。
  • 蓝色箭头:车辆中心的运动
  • 灰色箭头:作为红色/粉色箭头的底座;总是沿着车身的角度固定
  • 粉色箭头:绿色圆圈的切线;灰色箭头和粉色箭头之间的角度用于确定每个轮子的角度
  • 红箭:车辆的实际轨迹;当用户控制鼠标时,箭头的长度将总是代表每个轮子的相对速度。

实施不同的转向模式

转向模式(图片由作者提供)

虽然传统的转向系统只涉及阿克曼转向,但 4WIS/4WID 可以有三种不同的转向模式:AFRS、螃蟹式转向和旋转。我们的算法支持所有三种转向模式,并允许我们同时控制所有四个车轮,而没有任何运动冲突的危险。我们这样做是通过计算车轮的方向和速度的基础上,车轮的角速度在一个转弯。这防止了信号之间的任何冲突,这些冲突会导致车辆打滑。

螃蟹转向

蟹式转向是一种特殊类型的主动四轮转向,通过将所有车轮转向相同的方向和角度来操作。

螃蟹驾驶中的太空鼠(图片由作者提供)

每当用户在飞机上滑动太空鼠标时,该算法都使用 Crab 转向模式。在这个具体的例子中,当鼠标面向右上角时,所有四个滚轮都与鼠标指向的方向成一个角度。所有四个车轮具有相同的速度,该速度被计算为半径非常大的圆的切向速度。

主动前后转向

AFRS 机制包括前轮和后轮独立转动,以获得更小的转弯半径和更好的转弯稳定性。在这种转向模式下,后轮根据驾驶参数改变车辆的转向方式。每个车轮的速度计算为圆周的切向速度。

AFRS 的太空老鼠(图片由作者提供)

太空鼠的扭转运动负责改变飞行器的曲率半径。该算法的核心是将每一个运动视为圆周运动,并计算每个车轮的速度和与该圆周相切的角度。曲率半径(𝒓)由上面所示的等式计算,角度值(θ)由鼠标的扭转运动控制。

顺时针扭转鼠标时,θ增大,导致曲率半径变大。逆时针扭转鼠标时,θ减小,导致曲率半径变小。负θ将使圆在车辆的另一侧移动。

这一原则也适用于直线运动的情况,如螃蟹转向模式。持续逆时针扭动鼠标会使θ变得很小,导致转动半径几乎为无穷大。此时,车辆的运动将被视为直线运动。

AFRS 的太空老鼠(图片由作者提供)

在这些例子中,直线运动和曲线运动是同时完成的。当扭转和移动鼠标同时发生时,车辆可以执行更复杂的运动,例如以逐渐减小的转弯半径向前移动。

旋转

也称为零转弯模式,旋转是车辆以零半径旋转的运动。通过垂直于中心对角线转动所有车轮,并以相同的方向转动车轮,很容易实现这一点。

旋转运动中的太空老鼠(图片由作者提供)

当按下 SpaceMouse 侧面的两个按钮中的一个时,飞行器向各自的方向旋转。如上图截图所示,按下右键车辆顺时针方向转弯,按下左键车辆逆时针方向旋转。

结论

在六个月的时间里,我建造了一辆原型车,并通过实验证实,我们的算法成功地处理了一只太空鼠标传达的驾驶员的意图,并合作控制所有四个车轮,使它们彼此不冲突,以完成预期的运动。

我以前在 Arduino 做过几个有趣的项目,但是 Project Orbitron 是我做过的最大最复杂的项目。光是建造原型就花了整个暑假和超过 1000 美元的预算。我又花了三个月时间开发算法,同时自学 Mathematica 并不断调整 Orbitron 的设置。

完成这个项目后,我参加了一个当地的科学展,并把我的作品展示给了我学校的一个学术团体肯特公会

Orbitron 项目已经成为我旅程的核心体验/项目,并最终成为我大学论文的主题。原型目前展示在肯特学校的预工程中心一楼,我的算法正在韩国走专利流程。(申请号:KR 10–2019–0087022)

最初发表于https://blog.tylertaewook.com/post/project-orbitron

用 Prefect 编制 Python 中的数据科学项目

原文:https://towardsdatascience.com/orchestrate-a-data-science-project-in-python-with-prefect-e69c61a49074?source=collection_archive---------0-----------------------

实践教程

用几行代码优化您的数据科学工作流程

动机

作为一名数据科学家,您为什么应该关注优化您的数据科学工作流程?让我们从一个基础数据科学项目的例子开始。

假设您正在处理虹膜数据集。您从构建处理数据的函数开始。

定义函数后,执行它们。

您的代码运行良好,并且您没有看到输出有任何错误,因此您认为工作流足够好。然而,像上面这样的线性工作流程有很多缺点。

作者图片

缺点是:

  • 如果函数get_classes出现错误,函数encode_categorical_columns产生的输出将会丢失,工作流需要从头开始。如果执行encode_categorical_columns功能需要很长时间,这可能会令人沮丧。

作者图片

  • 由于功能encode_categorical_columnsget_classes互不依赖,因此可以同时执行以节省时间:

作者图片

以这种方式运行函数还可以防止在不起作用的函数上浪费不必要的时间。如果功能get_classes出现错误,工作流程将立即重启,无需等待功能encode_categorical_columns完成。

作者图片

现在,你可能会同意我的观点,优化不同职能部门的工作流程非常重要。然而,手动管理工作流可能会有大量的工作。

有没有一种方法可以让你通过增加几行代码来自动优化工作流程?这时候提督就派上用场了。

什么是提督?

perfect是一个用 Python 构建工作流的开源框架。Prefect 使大规模构建、运行和监控数据管道变得容易。

要安装提督,请键入:

pip install prefect

使用 Prefect 构建您的工作流程

为了了解 Prefect 是如何工作的,让我们用 Prefect 封装文章开头的工作流。

第一步—创建任务

一个Task是一个完整流程中的离散动作。从使用装饰器prefect.task将上面定义的功能转化为任务开始:

第二步—创建流程

一个Flow通过管理任务之间的依赖关系来表示整个工作流。要创建一个流,只需在with Flow(...)上下文管理器中插入运行函数的代码。

请注意,在运行上面的代码时,这些任务都不会执行。Prefect 允许您立即运行流程,也可以安排在以后运行。

让我们尝试使用flow.run()立即执行这个流程:

运行上面的代码将会得到类似如下的输出:

为了理解 Prefect 创建的工作流,让我们将整个工作流可视化。

从安装prefect[viz]开始:

pip install "prefect[viz]"

然后将方法visualize添加到代码中:

您应该会看到如下所示的data-engineer工作流的可视化效果!

作者图片

请注意,Prefect 会自动管理任务的执行顺序,从而优化工作流。对于一些额外的代码来说,这非常酷!

第三步-添加参数

如果您发现自己经常尝试一个变量的不同值,那么理想的做法是将该变量转换成一个Parameter

您可以将Parameter视为Task,除了它可以在流程运行时接收用户输入。要将变量转换成参数,只需使用task.Parameter

Parameter的第一个参数指定了参数的名称。default是可选参数,指定参数的默认值。

再次运行flow.visualize将给出如下输出:

作者图片

您可以通过以下方式覆盖每次运行的默认参数:

  • 将参数parameters添加到flow.run():

  • 或者使用完美的 CLI:

  • 或者使用 JSON 文件:

您的 JSON 文件应该如下所示:

您还可以使用 Prefect Cloud 更改每次运行的参数,这将在下一节中介绍。

监控您的工作流程

概观

Prefect 还允许您在 Prefect Cloud 中监控您的工作流程。按照本说明为完美云安装相关依赖项。

在安装和设置了所有依赖项之后,通过运行以下命令在 Prefect 上创建一个项目:

$ prefect create project "Iris Project"

接下来,启动一个本地代理,在单台机器上本地部署我们的流:

$ prefect agent local start

然后补充:

…在你文件的末尾。

运行该文件后,您应该会看到类似下面的内容:

单击输出中的 URL,您将被重定向到一个概述页面。概览页面显示了您的流程的版本、创建时间、流程的运行历史及其运行摘要。

作者图片

您还可以查看其他运行的摘要、执行时间及其配置。

作者图片

Perfect 自动跟踪这些重要信息的方式非常酷!

使用默认参数运行工作流

请注意,工作流已注册到 Prefect Cloud,但尚未执行。要使用默认参数执行工作流程,请单击右上角的快速运行。

作者图片

单击创建的管路。现在,您将能够实时看到新流程运行的活动!

作者图片

使用自定义参数运行工作流

要使用自定义参数运行工作流,请单击运行选项卡,然后在输入下更改参数。

作者图片

当您对参数感到满意时,只需单击 Run 按钮即可开始运行。

查看工作流程的图表

单击示意图将为您提供整个工作流程的图表。

作者图片

其他功能

除了上面提到的一些基本功能,提督还提供了一些其他很酷的功能,将大大提高您的工作流程的效率。

输入缓存

还记得我们在文章开头提到的问题吗?通常,如果函数get_classes失败,函数encode_categorical_columns创建的数据将被丢弃,整个工作流需要从头开始。

然而,使用提督,encode_categorical_columns的输出被存储。下次重新运行工作流时,下一个任务将使用encode_categorical_columns的输出,而不重新运行任务encode_categorical_columns

作者图片

这可以大大减少运行工作流所需的时间。

持续输出

有时,您可能希望将任务数据导出到外部位置。这可以通过向任务函数插入保存数据的代码来完成。

然而,这样做会使测试功能变得困难。

Prefect 使每次运行时保存任务的输出变得很容易,方法是:

  • 将检查点设置为True
$ export PREFECT__FLOWS__CHECKPOINTING=true
  • 并将result = LocalResult(dir=...))添加到装饰器@task中。

现在任务split_data的输出将被保存到目录data/processed中!该名称类似于以下内容:

prefect-result-2021-11-06t15-37-29-605869-00-00

如果你想定制你的文件名,你可以添加参数target@task:

提督还提供了其他的Result职业,比如GCSResultS3Result。你可以点击查看结果的 API 文档。

将另一个流的输出用于当前流

如果您正在处理多个流,例如,data-engineer流和data-science流,您可能希望将data-engineer流的输出用于data-science流。

作者图片

data-engineer流的输出保存为文件后,您可以使用read方法读取该文件:

连接相关流

想象一下这个场景:您创建了两个相互依赖的流。流程data-engineer需要在流程data-science之前执行

看了你的工作流程的人不理解这两个流程之间的关系。结果他们同时执行流程data-science和流程data-engineer 遇到错误!

作者图片

为了防止这种情况发生,我们应该指定流之间的关系。幸运的是,提督使我们更容易做到这一点。

从使用StartFlowRun抓取两个不同的流开始。将wait=True添加到参数中,以便仅在上游流程完成执行后执行下游流程。

接下来,调用with Flow(...)上下文管理器下的data_science_flow。使用upstream_tasks指定在执行data-science流程之前将要执行的任务/流程。

现在,两个流连接如下:

作者图片

相当酷!

安排你的流程

Prefect 还使得在某个时间或某个时间间隔执行一个流变得无缝。

例如,为了每 1 分钟运行一个流,您可以初始化类IntervalSchedule并将schedule添加到with Flow(...)上下文管理器中:

现在,您的流量将每 1 分钟重新运行一次!

点击了解更多安排你心流的不同方式

记录

只需将log_stdout=True添加到@task中,就可以记录任务中的打印语句:

执行任务时,您应该会看到如下输出:

[2021-11-06 11:41:16-0500] INFO - prefect.TaskRunner | Model accuracy on test set: 93.33

结论

恭喜你!您刚刚学习了 Prefect 如何用几行 Python 代码优化您的数据科学工作流。从长远来看,代码中的小优化可以大大提高效率。

随意发挥,并在这里叉这篇文章的源代码:

https://github.com/khuyentran1401/Data-science/tree/master/data_science_tools/prefect_example

我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以通过 LinkedInTwitter 与我联系。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

Python 中的常微分方程

原文:https://towardsdatascience.com/ordinal-differential-equation-ode-in-python-8dc1de21323b?source=collection_archive---------2-----------------------

颂的用法是什么?如何用 Python 求解 ODE?

约翰·莫塞斯·鲍恩在 Unsplash 上拍摄的照片

常微分方程 (ODE)可以用来描述一个动态系统。在某种程度上,我们生活在一个动态系统中,窗外的天气从黎明到黄昏不断变化,我们体内的新陈代谢也是一个动态系统,因为随着时间的推移,成千上万的反应和分子被合成和降解。

更正式地说,如果我们定义一组变量,比如一天中的温度,或者某个时间点的分子 X 的量,它随着自变量而变化(在动态系统中,通常会是时间 t )。ODE 为我们提供了一种从数学上描绘定义变量的动态变化的方法。与之相对的系统叫做静态系统,想着拍一张外面的照片,这张快照不包含任何动态,换句话说就是静态的。

求解常微分方程意味着确定变量将如何随着时间的推移而变化,该解有时被称为解曲线(如下图所示),为任何动态系统的默认行为提供信息性预测。

线性系统的示例解曲线

在这篇文章中,我将介绍 ODE,更重要的是,如何仅仅使用 Python 来解决 ODE。

术语概述

在这里,我首先介绍一些术语,读者可能会从中受益。常微分方程看起来是这样的:

颂诗

这是一个包含导数的方程,但方程本身没有偏导数。换句话说,我们只考虑一个自变量,那就是时间 t,当我们有多个自变量进来时,就变成了偏微分方程(PDE) ,不在本文讨论范围内。

偏微分方程(Partial Differential Equation 的缩写)

在 ODE 中,如果包含因变量的项的系数(在上面的例子中,变量 R,包含 R 的项包括 dR/dt 和 k2R)与 R 无关,则该 ODE 被视为线性 ODE 。为了说明这一点,让我给你看一首非线性颂歌作为比较:

非线性 ODE

大家可以看到,现在 dR/dt 的系数是 R,违反了线性 ODE 的定义,所以变成了一个非线性 ODE

最后,最后一对术语,如果变量的导数独立于自变量(这里是时间 t),我们称它们为自治颂,否则,就变成了非自治颂。同样,非自治 ODE 如下所示:

非自治颂歌

你可以看到现在时间 t 在右边,所以这是一首非自治颂歌。

求解 s 形信号响应曲线

首先,本文中使用的例子来自于泰森等人的一篇精彩综述论文。如果你对此感兴趣,我强烈推荐你去看看。

s 形信号响应曲线描述了如下所示的系统:

体内磷酸化过程(改编自泰森等人)

它是在我们体内发生的磷酸化过程,R 是一种物质,它将被转化为磷酸化形式 Rp 以发挥许多功能,这一过程由信号 S 催化,并伴随着 ATP 水解。为了描述这一过程,原始论文使用了以下 ODE:

现在我们首先要解这个方程,这意味着获得描述 Rp 如何随时间变化的解曲线

让我们开始编码:

from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as pltdef model(Rp,t,S):
    k1 = 1
    k2 = 1
    Rt = 1
    km1 = 0.05
    km2 = 0.05
    dRpdt = (k1*S*(Rt-Rp)/(km1+Rt-Rp)) - k2*Rp/(km2+Rp)
    return dRpdt

上面的代码只是为了建立我们描述的使用数学方程的模型,这里的一些参数我只是使用了在原始论文中提供的。

我们将信号强度设置为 1,但这只是为了说明,您可以随意将其更改为您喜欢的任何值。然后我们将 Rp 的初始值设置为三种不同的可能性:0,0.3,1。它可以向我们展示不同的初始化将如何最终收敛到稳态。为了简单起见,我们将模拟时间窗口设置为 0 到 20。最后,我们用odeint函数来求解这个 ODE。

S = 1
Rp0 = [0,0.3,1]
t = np.linspace(0,20,200)
result = odeint(model,Rp0,t,args=(S,))

result对象是形状为[200,3]的 NumPy 数组,3 对应三个初始化条件。现在我们画出:

fig,ax = plt.subplots()
ax.plot(t,result[:,0],label='R0=0')
ax.plot(t,result[:,1],label='R0=0.3')
ax.plot(t,result[:,2],label='R0=1')
ax.legend()
ax.set_xlabel('t')
ax.set_ylabel('Rp')

s 形响应,溶液曲线

这里我们可以看到,无论 Rp 从哪里开始,它们都会收敛到 0.5 左右,这被称为稳态。稳态是 ODE 的要点,因为它定义了动态系统的默认行为。你可能想知道为什么我们称之为 s 形信号响应曲线?这是因为除了求解解曲线,我们还想知道信号强度将如何作用于整个系统,用 ODE 语言来说,信号强度将如何改变系统的稳态?现在我们要去探索它!

数学上,当设置 dRp/dt = 0 时,系统的稳态基本上是公式的根。一个更好的例子如下:

定态

所以如果我们能解出关于 Rp 的最后一个方程,我们就能得到稳态时 Rp 的值。

S_all = np.linspace(0,3,100)
def equation(Rp,S):
    k1 = 1
    k2 = 1
    Rt = 1
    km1 = 0.05
    km2 = 0.05
    return k1*S*(Rt-Rp)/(km1+Rt-Rp) - k2*Rp/(km2+Rp)

from scipy.optimize import fsolve
store = []
for S in S_all:
    Rp_ss = fsolve(equation,[1],args=(S,))[0]
    store.append(Rp_ss)

我们首先设置信号 S 的范围从 0 到 3,然后我们使用来自scipy.optimizefsolve函数来完成这项工作。当 S 等于 0–3 之间的不同值时,结果基本上就是 Rp 值。

fig,ax = plt.subplots()
ax.plot(S_all,store,c='k')
ax.set_xlim(0,3)
ax.set_xlabel('Signal(S)')
ax.set_ylim(0,1.1)
ax.set_ylabel('Response(R_ss)')

现在让我们看看结果:

信号响应曲线(s 形)

现在,我希望大家能够清楚为什么称之为 sigmoid 信号响应曲线,因为随着信号强度的变化,系统的稳态将以 sigmoid 方式响应。

进一步评论

上面的例子只是为了让你体会一下什么是 ODE,以及如何用 python 只用几行代码就解决了 ODE。当系统变得更复杂时,例如,涉及到不止一个组件(这里我们称之为一阶 ODE ,另一个名为 GEKKO 或 scipy.integrate.solve_ivp 的 python 包可能会帮你完成这项工作。

如果我们对如何复制 Tyson 等人的其他图感兴趣,我建议你查看我的 Github 库,那里提供了所有代码。

https://github . com/Frank ligy/ScPyT/blob/main/ODE/submission/Frank _ system _ biology _ HW . pdf

我希望你觉得这篇文章有趣和有用,感谢阅读!如果你喜欢这篇文章,请在 medium 上关注我,非常感谢你的支持。在我的 TwitterLinkedIn 上联系我,也请让我知道你是否有任何问题或你希望在未来看到什么样的教程!

推导普通最小二乘法的正规方程。

原文:https://towardsdatascience.com/ordinary-least-squares-ols-deriving-the-normal-equation-8da168d740c?source=collection_archive---------16-----------------------

这将比你想象的要简单。

OLS 无疑是最基本的机器学习算法之一。这个想法真的很简单,给定一个数据集,该算法寻求找到超平面,该超平面使从超平面到数据集中每个点的偏移的、平方和最小化。

慢慢读最后一句话,考虑超平面

我们可以将损失函数推导为

其中 ( x,y ᵢ) 为数据集中的一个元素(观察值) m 为其长度。

足够幸运的是,这只有一个极小值,也就是说有一个唯一的

这绝对最小化了数量,前提是 m > n,否则我们的数据集非常小,损失明显为零,没有唯一的极小值。

这篇文章的存在理由是为了推导出 OLS 问题的封闭解,也称为正规方程,为此,我们将使用一点矩阵微积分(以及一些矩阵代数),这将使我们的推导过程更加简单。

特别是,我们会对以下身份感兴趣:

你可以在维基百科的矩阵微积分页面上找到这个

其涉及相对于向量对标量进行微分,并且可用于通过向量微分恒等式导出许多其他标量。现在很清楚,设置 A=I 和 v=u 我们得到

尽管从基本原理出发推导这个恒等式并不困难,但在寻找封闭形式或与其他算法(如迭代加权最小二乘法和最小绝对偏差)相关的迭代方案时,前面给出的一般恒等式将被证明更加有用,因此最好将其作为起点。现在让我们和 OLS 一起行动吧。

照片由舒巴姆·莎兰Unsplash 上拍摄

让我们从写作开始

如同

注意 J 看起来没有那么弯曲,为了进一步用矩阵形式写出来,我们有

其中 Y 是一个列向量,所有的 yᵢ' 都在我们的数据集中,并且每个对应的行向量 xᵢ 都位于矩阵 X. T 中。为了最小化这样的损失函数,我们需要将它(标量)相对于θ(向量)进行微分,并将其设置为零。

利用这个身份,我们有了

右边的项通过分布微分算子,以 YX 为常数,得到 -X

两边都除以-2,然后交换两边,我们得到

使用基本的矩阵代数

最后求解θ来完善我们得到的结果

这就是标准方程。给定一个数据集,它归结为简单地构造矩阵 X 和向量 Y ,然后插入封闭形式,以简单地找到最佳地最小化损失函数的超平面的系数,也就是说,一旦我们有θ,我们就可以使用该超平面

基于特征 x,的值来推断 y 的合适值,这总体上是一个合适的机器学习模型,特别是如果你的数据集幸运地遵循或接近线性趋势。

希望这篇文章对你有所帮助,也希望你考虑给它一些掌声作为回报。下次见,再见。

参考资料:

[1]:舒巴姆莎兰。(2019 年 6 月 21 日)。搜索了“微积分”。https://unsplash.com/photos/Z-fq3wBVfM

普通最小二乘回归

原文:https://towardsdatascience.com/ordinary-least-squares-regression-da96dde239d5?source=collection_archive---------26-----------------------

作者图片

权威的数学指南。

普通最小二乘法回归是每个人都应该熟悉的标准技术。我们从高斯-马尔可夫定理的角度激励线性模型辨别超定欠定的情况,并将 OLS 回归应用于葡萄酒质量数据集。

内容

  1. 线性模型
  2. 高斯马尔可夫定理
  3. 欠定和超定情况
  4. 分析红酒数据集
  5. 摘要

线性模型

线性模型假设以下 ansatz:

自变量和因变量通过一个乘法和一个常数项的加法联系起来。换句话说,预测的标签是特征向量加上常数的线性组合。然而,在不失一般性的情况下,我们可以去掉常数项,因为它可以被吸收到如下的线性组合中:

我们用虚拟常数 1 扩展了该特性,并将待学习的未知变量连接成单个未知向量。现在,给定数据要素和标注的完整训练集,我们可以拟合数据,或学习最佳预测值和偏移以最好地解释数据。让我们将特征向量按行堆叠成矩阵,并用帽子符号表示未知向量:

然后,优化问题转化为下面的普通最小二乘问题,该问题可以使用线性代数和微积分的技术来解决。

因此,在不失一般性的情况下,我们能够在实现和问题表述中省略常数项,只要我们用一列 1 来扩充特征向量。

我们注意到每门统计学课程都将涵盖线性模型,因为它很容易解释计算不昂贵,也许最重要的是,合理

高斯马尔可夫定理

关于普通最小二乘法(OLS)的讨论如果没有讨论高斯-马尔可夫定理是不完整的,该定理从统计的角度解释了 OLS 估计量的最优性。我们陈述如下。

在线性无偏估计类中,OLS 估计量具有最低的抽样方差;换句话说,OLS 是蓝色的(高斯-马尔可夫)。

蓝色:方差最小意义上的最佳线性无偏估计量

OLS :在普通的最小二乘意义上,就是最小化残差的欧氏范数

我们注意到,上一节的讨论没有包括任何关于噪声和随机性的假设。相反,我们在线性模型 ansatz 中使用了近似的等号。事实上,在现实生活和真实数据集中,等式将是不精确的,无论是因为测量/白噪声误差,还是自然发生的误差源,或者更糟糕的是,数据和标签之间的关系从一开始就不是线性的。然而,在线性的假设下,我们扩展我们的分析以明确模拟误差,并从概率角度观察线性模型。

数学上,我们像以前一样采用线性模型 ansatz,并假设它被噪声破坏。下面,随机噪声变量ε代替了原来的常数项 b,它与线性项合并在一起。

现在,标签本身就是一个随机变量,由一个确定部分和一个随机部分组成。请注意,所有随机性都来自白噪声或ε项。特别是,我们假设噪声的均值为零且方差有限:

我们感兴趣的是估计 x hat,下面这个问题的解,它本身就是一个随机变量,因为 y 是一个随机变量。

特别是,我们只对线性估计类或形式的估计感兴趣

对于由系数 c 定义的给定估计量,估计量的方差或均方误差由下式给出。

估计量是无偏的意味着

高斯-马尔可夫定理简单地说明了下面的估计量是无偏的并且具有最低的方差:

高斯-马尔可夫定理告诉我们,在线性估计量无偏的条件下,我们能做的使方差最小的最好的事情就是上面的估计量。这一统计特性体现了 OLS 估计量的简单性和最优性。线性和无偏性是至关重要的假设。如果我们允许估计量有偏差,那么我们可以进一步减少方差,例如通过岭回归,也称为吉洪诺夫正则化。詹姆斯-斯坦估算器摒弃了线性假设,也实现了更低的方差。偏差和方差之间的权衡是机器学习和统计学习中的一个重要主题,因为有时为了另一个而放弃一部分是可取的,反之亦然。

虽然高斯-马尔可夫定理的证明超出了本文的范围,但我们希望该定理的陈述已经得到澄清。对于感兴趣的读者,可以在这里找到一个证明。

超定情况(n>m)

到目前为止,我们已经隐含地假设矩阵 A 具有满列秩——或者特别地,它具有更多的行和列。在前一节中,我们甚至给出了最小二乘问题解决方案的预览。在这里,我们将更详细地讨论如何解决这个问题。我们准备好了

其中特征矩阵的高度当然大于宽度:在 n-空间中,要满足的方程比自由度还多。我们还假设矩阵是满秩的。在这种情况下,求解 正规方程 (通过对上面的表达式求微分并将导数设置为零而获得)得到解

其中匕首表示矩阵的 Moore-Penrose 伪逆:

欠定情况(m>n)

在欠定情况下,特征矩阵短而宽。在这种情况下,我们有足够的自由度来满足方程!当然,通过秩-零性定理,我们知道方程 Ax=y 实际上有无穷多个解。因此,为了将问题公式化为寻找最小范数解:

这个问题可能看起来与前一个问题无关,但结果是解决方案看起来非常相似!我们为短且胖的矩阵类似地定义 Moore-Penrose 伪逆,除了交换一些术语:

在这个定义下,最小范数问题的解可以再次表示为

上面提出的解决方案可以通过使用这些幻灯片中所描述的限制论点来找到。

分析真实数据集

我们对来自 UCI 机器学习知识库的红酒质量数据集应用最小二乘回归。任务是使用以下 11 个解释性特征(固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、pH、硫酸盐、酒精)预测葡萄酒质量。我们在下表中展示了一些葡萄酒的特性。

红葡萄酒的质量特征。图片作者。

我们先解决所有解释变量的线性回归问题,然后针对单个变量(密度)进行可视化。在下面的代码中,我们将问题转化为最小二乘问题,进行 80–20 训练测试分割,然后使用上面的等式求解预测值。

线性最小二乘回归。

均方误差(MSE)为 0.4068。使用单个特征(密度),我们实际上可以获得 0.7206 的 MSE,这与使用所有特征相比是有竞争力的。如下图所示,密度与葡萄酒质量呈负相关。橙色线显示最佳线性无偏预测值(蓝色),我们通过使用特征矩阵的 Moore-Penrose 逆运算解决了该预测值。

图片作者。

摘要

最小二乘回归对于拟合数据是必不可少的,应该是每个数据科学家的工具包中的一部分。它不仅是一个基本的模型,而且也是优雅和合理的——由方差最小化考虑(高斯-马尔可夫定理)驱动。在本文中,我们展示了如何解决超定和欠定最小二乘问题,并将线性最小二乘回归应用于红酒数据集。摩尔-彭罗斯逆运算和 OLS 回归问题的解决方案可以用你喜欢的脚本语言用几行代码实现。虽然我们没有深究细节偏差-方差权衡,如果你喜欢这篇文章,这是一个有趣的话题,可以了解更多。这个故事的简短版本是:人们可以通过正则化来进一步减少估计量方差,以换取额外的偏差。我强烈鼓励你继续阅读下面的文章!

参考文献

正交系统和傅立叶级数

原文:https://towardsdatascience.com/orthogonal-system-and-fourier-series-bec96510db98?source=collection_archive---------9-----------------------

思想和理论

如何利用函数的正交性导出傅里叶级数

图片来自 Unsplash

这篇文章介绍了傅立叶级数以及它是如何推导出来的。阅读这篇文章你不需要知道很多关于傅立叶变换的知识,但是我希望你知道一些关于多项式和基本微积分的知识。一些线性代数可能也会有所帮助。

周期函数可以分解成正弦函数和余弦函数,它们构成了傅立叶级数。正弦和余弦函数都可以称为正弦曲线,因为它们都是以下形式的函数:

执行傅立叶变换的中心思想是将函数从时域转换到频域。傅立叶级数是应用数学中一个非常强大的工具,因为它可以将一个问题转化为更容易解决的问题。如果某个问题在频域比在时域更容易解决(这在信号处理中非常典型),那么我们就把它转换到频域。有时候我们可以用卷积定理来检索解。这种变换提供了很多便利,例如在解微分方程时,我想在以后的另一篇文章中讨论。

正交系

这里引入正交系是因为傅里叶级数公式的推导就是基于此。

这意味着什么?当两个向量的点积等于 0 时,我们说它们正交。形式上,

向量的正交系是欧几里得(希尔伯特)空间的非零向量的集合{x_α},具有标量积(⋅,⋅),使得当α≦β时(x_α,x_β)=0。

考虑两个向量 x = (-1,2,0), y = (1,0.5,2),那两个向量是正交的,因为点积x****y= 0。

要理解两个函数 g(x)和 f(x)的正交性,可以类比推理。它们可以被认为是两个无限维的向量,事实上构成了希尔伯特空间。我们如何计算两个函数的“点积”?我们用积分来计算

如果这两个函数是正交的,则积分(1.1)的值为 0。

一些准备

现在我们可以看看一些正交系统的例子,它们将在下一节中用到。我们想证明这一点

我们用τ来表示一个周期的间隔,这里是 2π,意思是τ = [t₀,t₀+2π].为了方便起见,我们让一个周期的长度 T = 2π,这样我们可以处理 sin(nx)而不是 sin(2π/t * nx)。

为了证明这些等式,这两个公式会派上用场

首先让我们看看(1.2)。我们可以使用公式(1.5)以如下方式重写它

根据求和规则积分

现在很容易看出(1.2)成立。sin(nx+kx)和 sin(nx-kx)的积分成立,因为任何正弦波在一个周期内的积分等于 0。在此之后,我们可以使用公式(1.6)以同样的方式证明(1.3)和(1.4),并且我们可以得到

傅立叶级数的求导

我们可以用下面的公式来近似一个周期函数:

傅立叶级数和傅立叶系数

其中 T 是一个周期的长度。这是一般情况下的公式,其中周期为 T,如前所述,为了方便起见,我们考虑 T = 2π的情况。现在,我们将使用上一部分中配备的正交系知识来推导这些公式。

在公式(2.1)中,a₀、a_n 和 b_n 是所谓的傅立叶系数。公式(2.2)和(2.3)告诉我们如何找到这些系数。为了计算 a_n,我们只需使用公式(2.2)并代入 n=0。a_0 除以 2,所以公式(2.2)可以直接用来计算 a_n。

现在我们来看看如何推导 a_n 和 b_n,为了求一个具体的 a_k,诀窍是将(2.1)的两边乘以 cos(kx) ,这样就可以创建相互正交函数的积分。然后我们整合双方

再次使用积分的求和规则

现在事情变得非常简单,因为我们已经从上一节中获得了结论,我们可以很容易地观察到

因为任何正弦曲线在一个周期内的积分等于 0。根据我们以前证明的等式(1.2)、(1.3)和(1.4),除了 n=k 的部分,所有其他加数都消失了。提醒一下:

我们在上一节已经看到的正交函数

去掉零加数后,剩下的就是评估了

然后我们可以很容易地获得

这个结论也适用于一般情况,其中 T 是任意周期。系数 a_n. (2.3)的公式可以用同样的方法证明,唯一的区别是我们把(2.1)的两边都乘以 sin(kx) 而不是 cos(kx)。

示例和实施

在这一节中,我们将看一个傅立叶级数应用的典型例子,它是一个方波。我们会尝试用 Matlab 来实现(因为我真的很喜欢用 MatLab 做数值分析或者函数逼近)。

用傅立叶级数逼近方波。图片作者。

我们可以这样实现周期函数

我们知道,那么这个方波函数的一个周期的长度是 T = 3/2,紧支集的长度是 1。我们可以使用公式(2.1)、(2.2)和(2.3)以及下面的脚本来模拟这个函数

你可以试着改变逼近的迭代次数(n),你会看到 n 越大,逼近越接近原函数。一些曲线被其他曲线覆盖,因为当 n / (3/2)是整数时,结果曲线与前一条曲线相同。如在 n=2 和 n=3 的情况下——曲线 n = 3 被曲线 n=2 覆盖,因为在最后一次迭代中cos(2*pi/t * i*x)sin(2*pi/t * i*x)都等于 0,并且它不做任何事情。

摘要

在这篇文章中,我们看到了傅立叶级数的简短介绍,然后我们看了一下正交系统的定义。有了这些知识(也有一些技巧),我们试图推导傅立叶系数的公式。最后,我们看到了如何使用傅立叶级数来实现近似,这一部分使用了 Matlab。

资源

【1】正弦波数学百科全书。

【2】正交系统数学百科全书。

[3]G. Arfken, H. Weber 和 F. E. Harris,物理学家的数学方法第 7 版(2011) ,学术出版社

[4]Swapnil Sunil Jain,傅立叶系数的推导(2013) ,PlanetMath

错误日志

基于 pyproj 的南极企鹅追踪正射投影

原文:https://towardsdatascience.com/orthographic-projection-with-pyproj-for-penguin-tracking-in-antarctica-18cd2bf2d570?source=collection_archive---------34-----------------------

如何在正投影中创建地图以及使用企鹅追踪数据创建地图动画— Pyproj 和 KeplerGL

阿德利企鹅的行为研究是针对中心位置觅食理论的,该理论解释了繁殖海鸟应该积极优化猎物的获取,因此,觅食应该位于猎物最容易获得的地方,在物种能量学定义的范围内【1】。尽管南极的条件如海面温度、叶绿素浓度或海冰覆盖,企鹅必须根据海洋学特征在不同的地点找到觅食的成功。

在这次地图审查中,我将使用一个子集,其中包含 2018 年在南极洲记录的 16 只企鹅的运动轨迹。整个数据集包含 2010 年 12 月 21 日至 2018 年 1 月 11 日期间记录的 129 只企鹅的跟踪信息,可以在 Movebank 中直接找到T5 这里

最终地图动画: 这里! 资源库: 这里!

目标目标目标

这个练习的主要目的是用 pyproj 在正投影中可视化企鹅的足迹。此外,使用 KeplerGL 创建地图动画,显示企鹅在海岸线上觅食活动期间的行为运动。因此,我们将获得两个产品:1)具有正交视图的地图,以及 2)企鹅足迹的地图动画。

1)用正投影创建地图

正交投影的思想是在三维地球中以方位角透视(垂直)来可视化对象。为此,我们将使用 python 库 pyproj 和 geopandas。第一个主要步骤是可视化数据集。

import geopandas as gpd
import pandas as pd
from pyproj import CRS
from keplergl import KeplerGl
import matplotlib.pyplot as plt# reading data
fp = r'data/penguin-tracks.gjson'
geodata = gpd.read_file(fp, driver='GeoJSON')# defining timestamp columns
geodata['timestamp'] = pd.to_datetime(geodata['timestamp'])
geodata['year'] = pd.DatetimeIndex(geodata['timestamp']).year
geodata['t'] = geodata['timestamp'].astype(str)

上面的代码只是读取数据并创建两个额外的列。year包含曲目的年份,对于本例,所有记录都是 2018 年,而t包含字符串类型的时间戳。地图动画的字符串类型中需要最后一列。然后,作为 WGS84 中的快速可视化,我们运行下一行来可视化数据。

geodata.plot(column='ind_ident', figsize=(12,6), markersize=0.2)

图片由作者提供。wgs84 中 16 只企鹅的足迹

现在,我将直接从 geopandas 加载全球国家的自然地球图层,并将其投影到 正投影 。因此,按照我们观察圆形球体的方式,我将正投影的中心放在南极,这意味着latitude -90°longitude 0°。正投影的 CRS 通过转换获得:从 proj4(参数)到 CRS。代码是这样的:

# create world layer
world = gpd.read_file(gpd.datasets.get_path(‘naturalearth_lowres’))# define center of Orthographic Projection
lat = -90
lon = 0ortho = CRS.from_proj4("+proj=ortho +lat_0={} +lon_0={} +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs".format(lat, lon))# Re-project and plot
geodataor = geodata.to_crs(ortho)
world = world.to_crs(ortho)
world.plot(figsize=(12,6))

图片由作者提供。正交投影以南极洲为中心的世界图层

现在,我们创建一个独特的figure, ax,在那里世界层企鹅轨迹将被添加。在这个独特的figure, ax中,我们设定 xy 限制了南极洲大陆的边界框。首先,我们得到南极洲的边界框,然后我们绘制它。代码如下所示:

antarctic = list(world.loc[world['continent']=='Antarctica'].geometry)[0]
antarctic

图片由作者提供。南极的几何对象

现在我们设置包围盒的 x 最小,x 最大,y 最小,y 最大:

bounds = antarctic.bounds

xmin = bounds[0]
xmax = bounds[2]ymin = bounds[1]
ymax = bounds[3]

现在,独特的figure, ax:

# create unique fig, ax
fig, ax = plt.subplots(figsize=(12, 8))# adding layers
world.plot(ax=ax)
geodataor.plot(ax=ax, markersize=10, color=’red’)# limits
ax.set(xlim=(xmin, xmax), ylim=(ymin, ymax))plt.axis(‘off’)

图片由作者提供。正投影中企鹅足迹的定位

既然我们知道了企鹅足迹的位置,我们就可以绘制最终的地图了。

plt.style.use(‘seaborn’)# create unique fig, ax
fig, ax = plt.subplots(figsize=(10, 7))# adding layers
world.plot(ax=ax, color=’#CED7E0', edgecolor=’black’)
geodataor.plot(ax=ax, column = ‘ind_ident’, markersize=7, alpha=0.8, cmap=’tab10', legend=True)# limits
ax.set(xlim=(1500000, 1800000), ylim=(-2050000, -1800000))# plt.axis(‘off’)
plt.grid(False)
ax.set_facecolor(‘#0F4983’)plt.title(‘Adélie Penguins tracks in Antarctic’)ax.get_legend().set_bbox_to_anchor((1.2,1))
ax.get_legend().set_title(“Penguin ID”)plt.savefig(r’png/penguin-tracks.png’)

图片由作者提供。南极的企鹅足迹。

2)用 KeplerGL 创建地图动画

现在,我们想要可视化企鹅足迹的运动模式。我们在geodata 层中只选择地图动画所需的列。那么,可视化运动模式的一个很棒的工具就是 KeplerGL 库。创建 KeplerGL 映射的步骤是从一个空实例开始,然后添加数据,最后保存映射。如下:

# selecting the needed columns
geodata = geodata[[‘t’, ‘ind_ident’, ‘geometry’]]# Create KeplerGl instance
m = KeplerGl(height=600)# Add stop durations
m.add_data(geodata, ‘Penguins’)m

在这里,我们使用 KeplerGL 根据需要配置地图。

图片由作者提供。带有企鹅跟踪数据的 KeplerGL 实例

最后,配置完成后保存地图即可。

# Save map as html
m.save_to_html(file_name=’index.html’)

结论

您可以根据需要使用正投影,不仅可以使用这些数据,而且您可能会注意到,您总是需要在同一个地图中包含所有具有相同投影的内容。这个病例是正高的。对于 KeplerGL,数据必须在地理 CRS (EPSG 4326)中。

企鹅追踪记录包含了空间空白。像往常一样,这种情况发生在运动数据上,并且与 GPS 信号有关。有重建轨迹(路径)的选项。如果你有兴趣了解更多动物追踪和运动数据,请在 上 ping 我的 LinkedIn 个人资料

参考文献

[1] Ballard,g .,Schmidt,a .,Toniolo,v .,Veloz,s .,Jongsomjit,d .,Arrigo,k .,Ainley,D. (2019)。“表征阿德利企鹅在西南罗斯海成功觅食的精细尺度海洋学特征”。第 608 卷:263–277 页。https://doi.org/10.3354/meps12801

使用折射仪测量其他咖啡

原文:https://towardsdatascience.com/other-coffee-measurements-using-a-refractometer-85d0fb28d3d7?source=collection_archive---------35-----------------------

咖啡数据科学

探索未知

在阅读有关色度计来分析咖啡烘焙时,我想到了咖啡在提取后是如何改变颜色的。我想知道测量之前和之后的颜色是否与提取有关。理解圆盘的哪些部分比其他部分提取得更多或更少将是有趣的。

我不会为了一个不确定的实验花 300 美元或更多在这样一个设备上。然而,我有一个折射计,我有一个疯狂的想法。如果我们把咖啡磨粒放在折射计的镜头前和镜头后会怎么样?虽然单个测量的输出可能不令人感兴趣,但与其他测量相比,它可能会告诉我们一些东西。

初始测试

我的第一次测试马上就失败了。我有一台 Atago 数字折光仪,可以测量总溶解固体(TDS)。我把干的用过的咖啡渣放在上面。然而,它需要一些液体。

所以我修改了我的测试,加入了一点水,然后我等待着。我等待着。我等了一分钟,最后,读数显示大约 0.1% TDS。这是令人鼓舞的,所以我想做一些测试,以确定这是否能提供有用的信息。

我们可以将这种测量接地 TDS (gTDS)称为占位符。

进一步测试

我在测试中使用了一个断续的夯实镜头。我一直在测量冰球上半部分和下半部分的重量,看看提取来自哪里。

我只是在靠近中心的地方随机选择了一个点,然后通过将加了水的废咖啡样品放在 Atago 上来测量 gTDS。我知道,这实际上不是 TDS,因为通常,你希望样品没有未溶解的固体。

然后,我进行空间测量,以了解这些测量的可重复性,以及测量值是否会因较暗或较亮的点而发生变化。众所周知,较暗的点流量较低,因此提取较少。

然后我们可以从空间上看下半部分的这些值。对于上半部分,没有任何明显的颜色差异。对于下半部分,有,大部分的深色只是在表面。

所以冰球上的差异就显现出来了。令我感兴趣的是,根据击球后的重量估计,冰球底部应该有更高的提取率,但 gTDS 略高。

我认为这说明了圆盘的顶部比底部被提取得更多,但是底部可能过滤掉了一些提取物,因为我之前的作品展示了咖啡渣是如何捕获可溶物的。然而,那只是理论。我认为没有足够的信息。做出这个决定。

废咖啡测量

作为一个健全的检查,我有一些用过的咖啡渣,我一直在使用一些实验,他们被筛选到三个粒子大小的箱子。我也测量了它们,gTDS 非常低,比投篮后的冰球低得多。

这个实验有点疯狂,但我很好奇,如果我随着时间的推移取一些样本,我会看到提取和 gTDS 测量之间的相关性吗?击球时没有取出的东西一定还在冰球里。除了心照不宣的知识之外,许多这些奇怪的实验都没有很好的理由或直觉来启动它们,但它们最终让我对浓缩咖啡有了深刻的理解。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡用纸质过滤器

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维护

咖啡评论和想法

咖啡实验

我们未能建立一个数据目录 3x。原因如下。

原文:https://towardsdatascience.com/our-learnings-from-3-failures-over-5-years-to-set-up-a-data-catalog-fb9778e25d4e?source=collection_archive---------5-----------------------

我们认为解决这个问题很容易,但是我们大错特错了。

照片由 汤姆·赫曼斯

在 Atlan,我们最初是一个数据团队,与联合国、盖茨基金会、世界银行等组织一起推动社会公益数据项目。

我们充当客户的“数据团队”,因此我们亲身经历了处理大规模数据的所有混乱和挫折。我们每隔几天就会被危机电话吵醒,哪怕是很小的问题——无论是解决仪表板上的数字为什么不正确,还是试图访问正确的数据集。

我们处理各种各样的数据,从 600 多个政府数据源到卫星图像等非结构化数据源。我们的数据增长速度超出了我们的预期,而且我们事先并没有真正计划好如何存储或访问这些数据。我们很快意识到,我们需要一个中央存储库来帮助我们的团队发现、理解和建立对我们正在处理的所有数据集的信任。

我们认为解决这个问题很容易,但是我们大错特错了。这是一个故事,讲述了我们的团队如何经过 4 次尝试和 5 年时间,最终成功实现了一个成功的数据目录。

尝试 1:构建一个由知识图驱动的 NLP 搜索

早在 2013 年,我们就开始涉足数据目录。我们一直在处理大型政府数据集,组织它们并快速找到我们需要的信息是一件痛苦的事情。

我们的目标是创建一个所有数据的存储库。我们想让它变得智能、易于搜索、使用直观。如果我们做对了,我们想我们甚至会把它提供给我们的用户,这样他们就不必通过同样困难的政府数据网站。

我们让我们最好的数据工程师参与这个项目,并制定了一个雄心勃勃的路线图——每个搜索的用户都应该能够在几秒钟内找到正确的数据。我们投入巨资建立了最好的搜索算法工具,如 Elasticsearch 和图形引擎,如 Neo4j,甚至建立了我们自己的自然语言能力。

我们内部团队最令人兴奋的演示是当他们搜索“收费超过 300 Rs 的医生”时,该工具返回了确切的答案。不是数据源或表的列表,而是最相关的表中的 10 行。

我们第一个数据目录的 NLP 支持的搜索正在进行。(图片来自作者。)

然而,尽管这是我们在构建数据目录的 3 次尝试中最成功的技术成就之一,我们还是失败了。

我们失败的原因

阻止数据目录项目起飞的根本挑战不是搜索算法。老实说,今天的搜索算法是这个难题中比较容易的部分,已经被像 Elasticsearch 这样的生态系统和像 Algolia 这样的 SaaS 产品商品化了。

真正的挑战在于在数据发现中建立相关性 —即能够管理和标记数据集和元数据,以便我们的知识图可以建立有意义的关系,我们的搜索算法可以了解哪些数据实际上与用户相关。

在过去的一年里,有很多关于人工智能驱动的元数据管理生态系统的讨论。在 Atlan,我们已经花了很多时间来思考(并构建)ML 算法,以自动化元数据监管的一切可能——例如,自动推荐来自机器人的列描述或相关业务标签。然而,在所有的炒作中,理解 ML 能做什么和不能做什么是至关重要的。

数据科学和分析的现实存在于技术和业务的交叉点上。没有人主导的业务、用户和实体环境,任何数据团队都不可能成功。虽然机器可以帮助丰富元数据的过程,但它们永远不会取代人类。

我们第一次尝试失败的原因是我们过于关注技术的酷和花哨部分,如 NLP 支持的搜索,而不是核心挑战——我们如何使我们的数据团队能够轻松地将“上下文”添加到我们所有的数据资产中,作为他们日常工作流程的一部分?

尝试 2:购买数据编目解决方案

在对该工具投入大量时间和工程资源后,我们放弃了构建内部解决方案的尝试。相反,我们决定买一个。

我们的一位分析师开始评估所有现成的商业解决方案。她最终列出了大约 10 种产品,我们开始联系他们。

这开启了一个为期三个月的漫长过程,以了解外面有什么,以及什么是可能的。许多供应商甚至没有回应我们的演示请求,可能是因为我们太小了。有些人接了我们的电话,但他们报出了百万美元的费用和 18 个月的实施周期。大多数这些产品的界面看起来像是 20 世纪 90 年代为 IT 团队设计的。它们都有复杂的实施周期和许可模式。

整个过程让我们伤脑筋。我们是一个现代团队,热爱投资于生产力。

我们已经在使用 Slack、Quip、Github 和十几个其他 SaaS 工具来帮助我们的团队更好地运行。我们如此习惯于现代软件的基础(快速设置、小额前期投资、随用随付模式和令人愉快的用户体验),以至于我们无法相信解决我们的数据 CRM 问题的唯一方法是…嗯,不存在的。

最后一根稻草是当我们在生态系统中发现了一个相对较新的、有前途的产品。由于他们的产品仍在开发中,我们给他们发了一份十几个功能需求的清单。他们回答说,每个功能将花费 20,000 美元,只是为了在他们的路线图中优先考虑它。开发相对基本的功能需要 24 万美元,更不用说除此之外的额外软件许可费了。

就这样,我们停止了第二次尝试。

我们失败的原因

当时,对于我们这种类型的团队来说,没有可用的解决方案—云优先、“按需购买”的定价、快速的设置时间,以及少于 20 个用户。

尝试 3:创建一个 hacky 内部工具(并取得一些进展)

在两次彻底失败后,我们尝试了一个稍微不同的项目。这一次,我们……几乎成功了。

我们开始这一尝试时略有不同。我们没有考虑产品,而是从创建一个简单的共享元数据框架开始。这基本上是我们希望收集的所有属性的列表,作为我们所有数据的“上下文”。对于每个数据资产,我们的数据分析师和科学家将在一个. txt 文件中创建这些元数据。它与我们的数据资产存储在同一个共享文件夹中(类似 AWS S3 的对象存储),提取器会将它转储到一个中央“目录”中。目录本身是一个简单的 UI,具有基本的搜索和浏览功能。

我们第二个数据目录的搜索和浏览功能。(图片来自作者。)

这个框架的好处是,基本发现是可用的,并且在我们所有的数据资产中启用。然而,虽然该目录帮助团队改进了一些数据发现问题,但我们并没有成功地让我们的团队添加关于数据资产的上下文,即列描述、为什么我们在分析中删除了某些列、已验证的数据资产等等。

这时我们意识到,当涉及到数据时,创建共享环境是一项团队运动。

为什么?没有人对数据有全面的了解。一些上下文是以业务为中心的,所以只有业务分析师或利益相关者知道它。有些上下文是技术性的,数据工程师知道。一些上下文隐藏在数据深处,如数据分析师所知的列中的怪异异常。

为了创造真正的共享环境,正确的解决方案需要具有包容性。一方面,我们需要让工程师通过他们的管道工具中的 API 推送元数据变得容易。另一方面,业务用户需要一个简单的 UI 或松散的集成来添加他们的上下文。整合不同人的工作流程是这一尝试的不足之处。

为什么我们半失败了

在这个项目中,我认为我们成功地迈出了第一步——创建了对我们团队最有效的元数据框架。然而,我们只是没有足够关注下一步——创建一种用户体验,让我们所有的团队成员能够轻松直观地向数据资产添加上下文。

像大多数团队一样,工程和产品资源是稀缺的。在这个项目中,我们没有产品设计师或 UI/UX 专家——我们根本没有多余的资源。结果是难以更新元数据的笨拙体验。像大多数现代团队一样,我们的文化永远不允许我们“强制”人们采用内部工具,所以不管我们做什么,我们实际上无法让人们使用这个笨重的工具。

尝试四:以用户体验为出发点

这一次我们以不同的方式开始,因为我们不能在这个问题上一直处理和失败。我们从一个“匿名分析师”会议、开始,我们的数据团队在周五晚上聚在一起,倾吐他们的心声。他们谈论了他们面临的挑战和他们在日常工作中遇到的挫折。

我们再次承诺构建我们自己的工具,但这次没有 hacky。从我们最近的尝试中,我们从高保真 UI 驱动的原型开始。我们首先在自己身上进行了测试,然后在一组不同组织类型、文化、领域、地域等的试点客户身上进行了测试。

我们反复测试和修改,直到我们自己的团队和我们一起工作的团队真正喜欢使用这个工具。

这花了很长时间,但很值得。我们构建的工具帮助我们自己的数据团队将工作质量提高了一倍,同时将我们用于数据项目的时间减少了一半。这就是今天变成亚特兰蒂斯的版本。

我们在数据目录中加入了一些协作和文档功能。(图片来自 图集 )。)

我们成功的原因

Airbnb 在分享他们关于推动采用内部数据门户的经验时说了一些深刻的话:“设计数据工具的界面和用户体验不应该是事后的想法。”我们早就应该注意到这一点。

我们的第四次尝试终于成功了,因为我们没有从一个很酷的功能开始,比如我们第一次尝试的 NLP 支持的搜索,或者后端功能,比如我们第三次尝试的 hacky 工具。我们从用户体验入手,做出我们团队想要使用的东西。

我们没有一个“酷”的 NLP 搜索(尽管我们正在努力)😉),但人家没在意。我们的团队和客户实际上喜欢每天使用 Atlan。他们最终管理、分享和合作数据,这是最重要的。

数据目录的未来:面向不同数据用户的协作工作空间

在过去的一年里,随着 Atlan 成为数据团队工作流的核心部分,我花了很多时间思考数据目录的未来。

对我来说,这一类别的未来看起来将更像 Github 或 Figma,而不是我们在当今世界看到的任何东西。它将借用概念和超人的原则,使数据团队通过嵌入式协作变得更加高效。

嵌入式协作是指工作发生在你所在的地方,摩擦最少。想象一下,如果你可以在获得链接时请求访问数据资产,就像使用 Google Docs 一样,所有者可以在 Slack 上获得请求,并在那里批准或拒绝它?不再有浪费我们时间和精力的跨无数工具的微工作流。只有一个统一的空间,既包容又令人愉悦。

了解将推动下一波数据目录的 4 个关键原则的更多信息:

觉得这个内容有帮助?在我的时事通讯《元数据周刊》上,我每周都写关于活动元数据、数据操作、数据文化和我们的学习建设的文章。 在此订阅。

我们寻找需求:雷克斯房地产指数

原文:https://towardsdatascience.com/our-search-for-demand-rex-real-estate-index-51590c8a7de1?source=collection_archive---------26-----------------------

行业笔记

采用子市场方法预测房地产需求,并使用贝叶斯分层方法。

该项目和报告由 普雷斯顿·程、南鲁和欧文·斯查费 共同撰写,是 2021 年春季哈佛顶点项目的一部分

蒂埃拉·马洛卡在 Unsplash 上拍摄的照片

目录

  1. 问题陈述和动机
  2. 钻研数据
  3. 建模方法
  4. 估价
  5. 未来的步骤

问题陈述和动机

9.6 万亿美元(截至 2019 年)的全球房地产市场是当今受技术干扰最小的市场之一。住宅房地产中的联系、交易和关系通常是通过传统的利益相关者和人类互动形成的。我们的合作伙伴组织 REX ,利用机器学习和大数据的力量来匹配房屋所有者和买家,寻求创建一个大幅降低交易费用的平台。在减少信息不对称的各种方法中,REX 打算为房地产经纪人和房地产投资者建立一个更强大、更细粒度的房地产指数。目前的解决方案包括全国房地产经纪人协会(NAR)的价格指数和 Zillow 或谷歌实施的自动估价机(AVMs)。然而,这些价格指数通常仅基于州级或城市级指标,并不提供更细粒度子市场的清晰度。此外,确定住宅房地产现货价格的 AVM 是嘈杂的指标,受到不同买卖价差和抵押贷款批准的困扰。销售交易的价格也被认为是二阶效应,因为它们反映了供求动态的平衡。因此,该项目旨在创建一个房地产指数,通过房屋上市和销售交易来预测需求。

图 1 子市场需求型房地产指数的动机

有两篇关键的文献激发了我们的模型。首先,之前构建更精细的房地产指数的工作是由 2020 年秋季学期的IACS·雷克斯团队开发的。他们的工作中描述的模型预测了市场层面上特定时间范围内的上市和销售数量,然后通过特定子市场内的销售/上市率与整个市场的销售/上市率的平均比率来缩放其市场预测,从而预测预定义的地理子市场(人口普查区域)内的相同数量。这种方法可以被视为“自上而下”,因为在更细粒度的子市场级别上做出的预测部分是从模型先前确定的市场级别预测中生成的。其次,刘等人。艾尔。(2020)引入了一个贝叶斯框架来模拟房地产估价,使用层次聚类来捕捉已知子市场之间的不同趋势。这种方法可以被视为一种“自下而上”的方法,旨在首先在子市场层面进行预测,然后在市场层面生成需求的总体预测。这个贝叶斯分层框架中的一个主要假设也是享乐假设,价格可以完全根据个人住房的属性来预测。此外,这个模型试图预测嘈杂的价格信号,而不是需求。

我们团队的模型利用这两个关键文献的优势,通过使用贝叶斯分层方法来预测需求,而不是房地产的货币价值。与基于人口普查的子市场不同,贝叶斯方法可以更准确有效地将子市场识别为地理(靠近学校、商业区)、环境(犯罪率、人口统计)和物理(大小、公寓景观)因素的混合体。为了更好地通知房地产经纪人和房地产投资者,我们的主要目标之一是让我们的模型具有可解释性,并允许洞察各种子市场分类和属性。这篇文章概述了我们回答上述问题的旅程,我们希望它能提供直接的学习以及追求类似挑战的动力。

钻研数据

对于任何机器学习项目来说,拥有正确的数据进行建模对于信任正在做出的结论至关重要。此外,一旦找到正确的数据,我们就必须确保我们已经以可以使用这些数据的方式处理了这些特征。我们已经整合了来自 3 个不同来源的最终数据集,如图 2 所示。

第一个 MLS 数据集由众多合作的房地产经纪人编制,为我们的目标变量提供了房屋上市和销售交易数据的信息。该数据集包含 439,427 个观测点,拥有大丹佛地区从 2016 年 3 月到 2020 年 11 月的 399,883 个唯一房产的交易数据。对于每笔交易,我们都有列表日期、出售日期、撤回日期、到期日期、状态(该物业是出售、到期还是撤回)、该物业的邮政编码和出售价格。

第二个数据源来自我们的合作伙伴 REX,它提供了关于每处房产概况的信息。该数据集提供了另外 70 个数字和分类特征,例如平方英尺面积、房间数量和车库的存在等。该数据集包含 236,000 个房源和 1,200,000 个非房源的信息。

第三个数据集是来自美国邻里分析数据库 NeighborhoodScout 的数据和其他公共人口普查记录的组合,生成了另外 122 个要素,其中包含城市人口统计信息以及对大学生、专业人士和交通分数等友好程度的人口普查指标。

图 2 本项目中使用的 3 个不同数据源的信息图

对于数据预处理,我们基于特定的阈值去除了具有缺失数据和低方差的变量。多重共线性也可以通过移除高度相关的要素来解决,协方差矩阵如图 3 所示。这个过程给我们留下了总共 62 个特征。然而,当训练开发的模型时,我们会遇到内存问题,即使 AWS 实例具有非常高的内存。这就需要进一步减少功能的数量。为此,我们使用 XGBoost 来选择具有最高预测增益的顶级特征。我们还使用基线模型中的子市场分类,并在每个子市场上使用 XGBoost 来获得每个子市场的顶级功能,从而保持所有子市场的一致性能。使用特征重要性,我们将特征空间缩减到以下 15 个特征,前 5 个为单个房屋属性,其余为基于人口普查区域的特征:

  • 卧室:卧室数量
  • 浴室数量:浴室数量
  • 多户家庭、公寓、其他:该单元是多户家庭、公寓,还是既不是多户家庭、公寓也不是独栋房屋。这些特性是特性类型特性的一次性版本。
  • 18–59:附近年龄在 18–59 岁的居民的百分比
  • 家庭平均收入:普查家庭的家庭平均收入
  • 1995 年或以后建造:机组是否在 1995 年或以后建造
  • 活动房屋百分比:活动房屋的百分比
  • 每户年出生人口:每次人口普查中每户出生人口的比率
  • 农场评分,豪华社区评分
  • 房产犯罪率:同一次人口普查中房产的犯罪率
  • 小户型建筑百分比:同一普查中小户型所占的百分比
  • 标准化测试得分百分位数:同一人口普查中居民标准化测试百分位数。

图 3 来自初始预处理的 62 个特征之间的相关矩阵

建模方法

给定由上述选择过程选择的 15 个特征,然后我们可以开始我们的建模方法。我们预测了房屋被出售的概率,假设它被列为每个家庭需求的代理变量。这是在探索需求的其他潜在候选人之后,例如预测房屋在市场上的剩余天数。

图 4 目标预测变量。注意:这是一个条件概率,而不是分数。

我们的基线模型分为两类,即:非次级市场和次级市场方法。开发非子市场方法是为了通过对整个市场进行整体预测来证明业绩的下降。这种情况下的建模方法是将逻辑回归模型拟合到所选特征,并返回目标变量的预测值(图 4)。我们已经试验了其他模型,比如随机森林分类器或简单的神经网络,但是在没有看到真正的性能优势后,最终没有进一步追求它们。

我们创建了子市场方法,以直接与开发的模型进行比较,并确保聚类方法比这里的简单方法更智能。在这种方法中,我们天真地通过在数字特征上使用 K-means 聚类将房屋分配给子市场。K-means 需要指定“聚类数”的超参数,因此我们通过交叉验证和最小化预测出售房屋数和实际出售房屋数之间的 MSE 找到了最佳数量。在这种情况下,我们使用逻辑回归和 XGBoost 来拟合和预测数据,因为我们注意到了 XGBoost 在确定处理步骤中的特征重要性方面的价值。

图 5 三种主要建模方法的概要

转到开发的模型,贝叶斯分层方法试图在两个方面改进我们的基线模型。首先,我们的目标是让我们的模型更好地学习定义最佳子市场分类,而不是被每个家庭的预定义数据聚类所限制。其次,我们的目标是能够解释每个子市场中使用的享乐需求模型,以便理解给定住宅的每个特征对需求的相对重要性和影响,并潜在地定义对应于每个子市场的大致地理区域。在该贝叶斯模型中,住宅的子市场被分类为𝐾子市场之一作为潜在变量,并且该住宅的每个预测数量根据由其子市场分类所确定的其特征的享乐需求函数来分配。这种分层方法是通过期望最大化来估计的,尽管 PyMC3 以前也进行过实验,但由于数据维数的原因,遇到了几个计算问题。这些估计方法试图在具有未观察到的潜在变量的模型中找到参数的最大后验(MAP)估计。

我们假设每个家庭的目标变量是家庭特征的确定性加权线性组合的函数,这些权重由家庭的子市场成员决定。也就是说,对于与单个住宅相对应的层级结构中的特定抽奖 n ∈ { 1,…,N} ,我们的模型假设变量之间存在以下结构和依赖性(参见图 6):

  1. z_n ~Cat(π) :这个变量代表一个家的子市场分类。参数 π ∈ R^K 表示属于每个𝐾子市场的房屋的先验概率,其中 π_ k=1/K 表示k∈【1,…,K}
  2. **h _ n ~ P _ n(θ_(z _ n)):这些随机向量代表每家的特征。这些特征是从𝐾完全不同分布(对于每个子市场)之一中提取的,每个分布由θ_(z _ n)参数化,这是一组分别表征连续、离散和布尔家庭特征的多元正态、泊松和伯努利分布的参数。
  3. **l_n N ~( μ_(z_n),σ_(z _ N)):这个变量对应一个家的经纬度。这与 h_n 分开处理,因为由于潜在的过度拟合,我们不希望将位置特征作为线性享乐需求函数的输入。然而,我们选择将它包含在这个模型层次结构中,目的是获得更多地理上不同的子市场,以获得更好的可解释性。
  4. y_n = f_(z_n)(h_n) :这个变量表示在这个指定的时间间隔内,给定一个房屋被出售的概率。函数 f_(z_n) 是由家庭的子市场成员确定的 h_n 的享乐需求函数。我们实现了开发模型的两个不同版本,其中 f_(z_n) 对应于 h_n 的梯度推进树(XGBoost)的逻辑回归。

图 6 提出贝叶斯分层模型

结果和评价

非次级市场和次级市场基准方法的结果分别见表 1 和表 2。对于非次级市场基线,我们看到普遍表现不佳,特别是在预测与实际售出房屋数量的比率上。该比率的值大于 2,表明它预测的待售房屋数量是实际数量的两倍。次级市场基线方法大大改进了这一指标(表 2 ),得分非常接近 1。然而,在非次级市场和次级市场方法中,每个家庭的准确性和 ROC-AUC 得分相对较低。我们认为这表明子市场方法特别抓住了每个子市场水平上的普遍情绪,但在每个家庭水平上却不那么好。

表 1 基线模型的非子市场指标

表 2 基线模型的子市场指标

基于交叉验证将子市场参数𝐾的数量设置为 11,具有频率主义逻辑回归享乐需求函数的贝叶斯分层模型(通过 1000 次迭代的期望最大化方法估计)导致 9 个子市场被识别。另一方面,具有 XGBoost 享乐需求函数的模型将𝐾设置为 7,并确定了 7 个子市场。表 3 和表 4 分别显示了逻辑回归和 XGBoost 的各个子市场的训练和测试准确性、ROC-AUC、预测房屋销售和实际房屋销售,以及根据各种子市场规模、MSE 和 R2 加权的累积指标。

表 3 逻辑回归享乐函数模型的子市场指标

表 4XG boost Hedonic 函数模型的子市场指标

据观察,线性回归模型的加权平均测试精度和 ROC-AUC 表明在预测单个房屋的销售上表现不佳,但低 MSE 和高 R2 表明该模型确实了解每个子市场内房屋销售分布的特性。另一方面,与子市场基线相比,XGBoost 模型具有更合理的性能。这意味着我们的层次结构能够捕捉训练中使用的家庭数据的分布特性,尽管逻辑回归享乐需求函数不是一个很好的拟合。图 7 和图 8 分别描述了逻辑回归和 XGBoost 的各个子市场的地理分布。

图 7 逻辑回归特征函数模型 9 个子市场的地理分布

图 8XG boost Hedonic 函数模型 9 个子市场的地理分布

此外,XGBoost 模型的三个最重要的特性在每个子市场中的重要性如表 5 所示。虽然有一些特征在许多子市场中都很重要,但没有两组特征的重要性是相同的,这表明该模型正在学习每个子市场中独特的享乐函数。

表 57 个子市场的特征重要性(XGBoost Hedonic 函数模型)

我们发现,我们开发的模型在预测个人住房是否会被出售时,没有一个表现得特别好(尽管在这一领域,使用 XGBoost 特征需求函数的模型确实大大优于使用 logistic 回归特征需求函数的模型)。然而,我们的模型能够对每个子市场内的预期房屋销售数量提供合理的估计。我们从观察中注意到以下情况:

  1. 享乐需求函数:使用逻辑回归享乐需求函数产生的结果通常比 XGBoost 更差,所以我们更喜欢后者。然而,可能有其他享乐需求函数是可以解释的(我们可以理解每个家庭特征的重要性/权重)。
  2. 享乐假设:我们当前框架的一个关键假设是,上市房屋在特定时间段内被出售的概率(以及未上市房屋被出售的概率)是由房屋特征和其他宏观因素(目前在房屋普查区域的水平上)的函数给出的。通过上述过程选择的 15 个特征的集合仅包含特定家庭特有的 5 个特征。
  3. 一般性:我们的模型所确定的子市场已经使用单一的时间间隔进行了评估。虽然它们表现出合理的表现,但当根据其他时期的数据进行评估时,尚不清楚这些子市场分类是否提供了可比较的表现。

未来的步骤

我们希望这项工作能够激发在房地产市场使用机器学习的进一步行动。我们相信有形的商业价值可以从我们的方法中获得,这包括能够利用发现的子市场来推动房地产投资决策。这项工作的自然延伸包括预测供应量,并将工作扩展到丹佛地区以外的地区。对于其他希望接受类似挑战的人,我们建议尽快花时间收集和处理正确的数据。在这样的任务中,正确的数据是必不可少的,任何市场都有需要考虑的细微差别。

感谢

我们要感谢我们的团队合作伙伴 REX 在整个过程中为我们提供项目、数据和支持,感谢我们的课程成员在每个项目里程碑提供反馈,感谢我们的助教 Zona Kostic 对房地产市场的全面指导和知识,最后感谢我们的课程导师 Chris Tanner 精心组织课程并随时提供反馈。

链接

https://github.com/luunam/cs297_rex

https://youtu.be/tRUT96APK_8

课程网站

外部产品:情书

原文:https://towardsdatascience.com/outer-products-a-love-letter-b29a2c2c818e?source=collection_archive---------19-----------------------

图片作者。

矩阵魔法不可否认的力量。

线性代数和向量微积分很厉害!这真的是一个可怕的耻辱,几乎没有时间专门用于高中数学的这些部分。相反,我们被给予了令人作呕的积分和导数问题集——恶心!向量、矩阵和数组提供了一种非常有效地进行大量计算的强大方法。Python 中的 NumPy 模块就是一个很好的例子,它使高级语言能够执行基于数组的计算。
在这里,我展示了如何使用线性代数的方法——外积——来避免过多的循环并加快计算速度。我们开始吧!

(代码可以在【GitHub】)

什么是“外部产品”?

首先,如果你不熟悉线性代数,有几种方法可以将两个数组相乘。其中之一被称为“外部产品”,其写法如下:

其中 uv 分别为 nm 维向量, M 为一个 n x m 矩阵。 M 的第 ij 个元素计算如下:

所以最后我们从向量 u 和向量 v 得到每个可能的元素对之间的一个乘积。这有什么用?让我们来了解一下!

Python 中的外部产品

基础 Python

尽管从技术上讲,这不是数组之间的外积,但是只使用基本 Python 也可以产生类似的东西。最直观的方法是使用列表(表示向量)和嵌套 for 循环:

这个表达式返回列表的列表,其中每个列表都类似于数组中的行向量。然而,这种方法;似乎很笨重。事实上,正如我们所看到的(图 1),它是。众所周知,嵌套的 for 循环在 Python 中效率低下,并且通常被认为不是“Python 式的”。

更优雅和“Pythonic 式”的解决方案是使用列表理解:

虽然您可能会意识到这个解决方案在语法上比嵌套的 for 循环更加高效和简洁,但是您也会注意到这个表达式不会像前面的解决方案那样给出一个列表列表,而是一个长度为 n x m 的长列表。因此,阅读和索引不太直观。然而,它在算法上明显更有效(图 1)。

最后,我们可以使用 base Python 提供的 map() 函数来解决这个问题:

这种方法不仅最难理解,而且效率最低(图 1)。虽然 map() 通常是将函数映射到可迭代对象的非常有效的方式,但是这里我们有一个需要更多内存的问题。为了实现这个方法,我们需要将 iterables uv 分别延长一个因子 mn 。这是非常浪费的,因为这些可重复项是非常占用内存的列表。此外——像 list comprehension 一样——这个方法返回一个平面列表,而不是一个类似数组的列表。

NumPy

如果你没有抓住备忘录,NumPy 是了不起的!作为一个可扩展的模块,它是每个数据科学家工具箱中必不可少的一部分。它的数据类—numpy . array()—带来了许多有用的操作和功能,使大量数据的计算变得更加容易和快速。

外积的计算非常简单,因为它是模块的预定义函数:

它也比基本的 Python 方法更有效(图 1)。此外, numpy.array() 输出的数据类型带来了一大堆简洁的方法和有利的特性。

图 1:使用不同的方法计算给定大小(长度)的两个向量的外积所花费的时间。outer-product(NP . outer())的效率最高,而 map() 的效率最低。图片作者。

有什么意义?

外部产品固然很好,但在更广泛的数据科学背景下,它们的用途肯定有限?嗯,是的。外积在某些用例之外没有特别的用处(例如多层感知器中的误差反向传播),但是它们的原理是可以概括的。

例如,我们可以想象,我们使用任何接受两个数并返回一个值的任意函数,而不是两个数相乘。在数据科学中,我们经常希望找到数据点之间的差异,即距离。为了有效地捕捉这些信息,我们通常会使用成对距离矩阵,它给出了每对点之间的距离。

使用这种方法的一个经典例子是旅行推销员问题(TSP)中的模拟退火算法。在 TSP 中,我们试图找到最短的可能路径来访问集合中的每个城市一次,在起始城市结束。为此,需要一组城市的成对距离矩阵。下面是一个使用 NumPy 的解决方案:

好的,这里有几件事:

  • 我使用 scipy.stats 中的 uniform 函数来生成城市的随机坐标
  • 我用复数表示坐标系。这有几个好处,主要是我可以把一个坐标作为一个数组中的一个单独的元素来存储;同样,我通过求两点的绝对差得到两点之间的欧几里德距离
  • 我通过使用 np.frompyfunc() 对距离函数进行矢量化。这是这种方法的关键一步。我们现在可以在这个函数上使用由 NumPy 提供的 ufunc 方法
  • 其中一种方法是。outer() ,这个我们以前见过。它像以前一样工作,只是我们将得到两个坐标之间的距离,而不是两个数字的乘积;(它以 dtype=object 的形式返回数组中的值,可烦了;然而,这很容易用解决。astype() 方法)

很漂亮,是吧?这个最大的卖点就是可以泛化,我之前也提到过。

例如,我最近使用这种方法来计算一组 DNA 序列的成对序列比对分数。人们也可以很容易地想象如何使用参数向量来测试实验参数的不同组合。可能性几乎是无穷无尽的——而我们只是在 NumPy 中触及了表面。

哦,笨蛋,你这个漂亮的机器!

回归分析中的异常值检测

原文:https://towardsdatascience.com/outlier-detection-in-regression-using-cooks-distance-f5e4954461a0?source=collection_archive---------5-----------------------

在 Scikit-Learn 和 Statsmodel 中使用 Cook 距离进行回归异常值检测

图片来自 unsplash

简介

异常值是指数据集中不符合正态分布的异常值,有可能严重扭曲任何回归模型。因此,必须小心处理异常值,以便从数据中获得正确的见解。通常,从现实世界中收集的数据由几个要素的几个观测值组成,许多值可能放置错误,或者可能只是数据处理的产物。无论异常值的原因是什么,都必须对异常值进行分析,并验证它们是真实的。如果离群值是真实的,可以将这些离群值带入回归模型,或者简单地删除它们,以创建更好的回归模型。

资料组

为了用 python 实现,我将使用 Scikit-Learn 的线性回归和 Statsmodel 的 OLS 方法来拟合房价数据。为了简单起见,这里所有的特征数据都是数字。我将使用下一篇文章中使用的相同的房价数据。

https://medium.com/geekculture/feature-selection-in-large-datasets-fc27a7e8e388

我将从房价的线性回归模型开始,从数据集中选择几个数字预测值。预测值为“总体质量”、“GrLivArea”、“TotalBsmtSF”、“YearBuilt”、“FullBath”、“HalfBath”、“GarageArea”,目标为“销售价格”。这些功能的相应描述如下。

'OverallQual': 'Overall material and finish of the house'
'GrLivArea': 'Ground living area square feet'
'TotalBsmtSF': 'Total square feet of basement area
'YearBuilt': 'Original construction date'
'FullBath': 'Full bathrooms above grade'
'HalfBath': 'Half baths above grade'
'GarageArea': 'Size of garage in square feet' 

我还有另一篇异常值检测文章,特别关注基于 IQR、汉佩尔和 DBSCAN 方法的数值异常值。

在这里,文章将具体到回归模型和使用库克距离的方法来检测异常值。

Scikit-Learn 和 Statsmodel

我们有兴趣调查 Scikit-Learn 和 Statsmodel 之间的拟合质量。首先,Scikit-Learn 的线性回归模型适用于预测值和目标变量。

通过该模型获得的 R 平方值是 0.7672,这基本上表明大约。数据集中 76%的方差是由我们选择的预测因子解释的。

当切换到 Statsmodel 时,R 平方值仍然非常相似,为 0.767,用户也可以选择调整后的 R 平方,它不会改变 mich,这种情况下表示非常适合最初选择的特性。

作者图片

异常值分析

Statmodel 的 OLSinfluence 提供了一种快速的方法来衡量每个观察的影响。当数据绘制在箱线图中时,对数据进行一般异常值分析,高于或低于四分位数间距(IQR)1.5 倍的点被标记为异常值。

图片来自simplypsychology.org

这些异常值有时非常高或非常低,可以形成局部聚类。如果我们选择传统的箱线图,这些局部聚类被识别为异常值。像 DBSCAN 这样的其他方法可以有效地识别这些极值点,并且可以将这些极值点合并到分析中,因为它遵循基于密度的算法。

作者图片

然而,在回归中,标准化残差是异常值的指标。它用标准误差来衡量数据点离回归线有多远。我们将把这个残差用于同一个数据集。

在这里,我们可以看到回归线上最有影响力的数据点,它基本上是一个奇点,具有控制模型的最高能力。

作者图片

根据具体情况,人们可以选择保留或放弃。在下面的代码块中,我们可以画出所有点的影响。当使用 plotly express 绘图时,只需将鼠标悬停在异常值上,就可以更容易地识别异常值。

作者图片

X 轴代表数据点的帽值。多元线性回归表示如下

Y = HX

其中 Y 是以 X 为预测值的结果。H 是帽子矩阵,帽子值是 H 矩阵的对角分量。y 轴代表标准化残差。很明显,最右边的点是具有非常高的 hat 值的异常值。悬停数据可以被修改以显示关于它的更多信息。

作者图片

在这一点上,我们将引入库克距离,这是一个衡量数据点影响的指标。Cook 的距离是杠杆(Wiki 定义:在统计学中,特别是在回归分析中,杠杆是一种衡量一个观察值的独立变量值与另一个观察值的距离)和残差大小的组合。

当以这种方式绘制时,单个点的影响如此之大,以至于所有其他点的贡献几乎不明显。

作者图片

我们需要扩大厨师的距离来注意其他人。当缩放 50 倍时,其他的点就成了大图。

作者图片

绘制库克的距离

库克距离是数据点的导数,并且会因样本而异。下面的块以容易识别的方式绘制了 Cook 的距离,以检测异常值。这里,我们选择将 Id 放在 X 轴上。

作者图片

在这种情况下,可以放弃那个最有影响的点,并继续回归模型,因为它具有如此大的扭曲模型的能力。

结论

在本文中,我们演示了如何使用 Scikit-Learn 和 Stasmodel 来评估回归模型。稍后使用 Stasmodel,基于 Cook 的距离检测异常值。由于人为错误,真实世界的数据可能有几个异常值,或者可能作为分析的产物生成。根据具体情况,数据分析师/科学家可能会选择保留或删除异常值。

Github 页面

机器学习中的离群点检测方法

原文:https://towardsdatascience.com/outlier-detection-methods-in-machine-learning-1c8b7cca6cb8?source=collection_archive---------12-----------------------

本文讨论了在预处理数据以开发机器学习模型时检测异常值的几种常用方法。

图片由粘土堤上的 Unsplash

什么是离群值?

异常值是看起来与数据中的其他值不同的值。下图突出显示了“红色”的异常值,在数据的两个极端都可以看到异常值。

作者图片

数据中异常值的原因

  1. 数据输入过程中的错误或有故障的测量设备(有故障的传感器可能导致极端读数)。
  2. 自然发生(初级员工与高级员工的工资)

异常值引起的问题

  1. 数据中的异常值可能会在模型拟合(特别是线性模型)。
  2. 异常值可能会扩大误差度量,从而为大误差(例如,均方误差、RMSE)赋予更高的权重。

识别数据中异常值的方法

在本文中,我们将使用 Scikit-Learn 的 葡萄酒数据集。 在继续下一步之前,我们将加载并准备数据。

作者图片

1.箱线图

箱线图是识别异常值的直观方法。箱形图是可视化数据分布的许多方法之一。箱线图绘制了数据的 q1(第 25 个百分点)、q2(第 50 个百分点或中间值)和 q3(第 75 个百分点)以及(Q1–1.5 (Q3-Q1))(q3+1.5(q3-q1)) 。异常值(如果有)被标绘为图上方和下方的点。

作者图片

在上图中,异常值显示为箱线图上下的点。“酒精”、“总酚”、“稀释葡萄酒的 od280/od315”和“脯氨酸”没有异常值。

2.IQR 方法

箱线图使用 IQR 方法来突出异常值。IQR 代表四分位数范围,即第三季度(第 75 个百分位数)和第一季度(第 25 个百分位数)之差。IQR 方法通过计算下限和上限来识别异常值。

下限= Q1–1.5 * IQR

上限= q3+1.5IQR*

任何低于下限和高于上限的值都被认为是异常值。下面是 IQR 方法在 Python 中的实现。

作者图片

在上图中,如箱线图所示,“酒精”、“总酚”、“稀释葡萄酒的 od280/od315”和“脯氨酸”没有异常值。

3.z 分数法

Z-score 方法是另一种检测异常值的方法。当变量的分布接近高斯分布时,通常使用这种方法。z 得分是一个变量的值偏离该变量平均值的标准偏差数。

Z 得分= (X 均值)/标准差

当一个变量的值被转换为 Z 分数时,那么该变量的分布就称为均值=0、标准差=1 的标准正态分布。Z 分数法需要用户指定一个临界值来识别异常值。广泛使用的下限截止值是-3,上限截止值是+3。使用这些临界值的原因是,在标准正态分布中,99.7%的值位于-3 和+3 之间。让我们看看 Z-Score 方法在 Python 中的实现。

作者图片

4.“与平均值的距离”方法(多元方法)

与以前的方法不同,这种方法考虑了数据集中的多个变量来检测异常值。该方法根据平均值计算数据点的欧氏距离,并将距离转换为绝对 z 得分。任何大于预先指定的临界值的 z 值都被视为异常值。我们将考虑葡萄酒数据集中的两个变量(“苹果酸”和“镁”),使用 3 作为临界值在 Python 中实现这个方法。

作者图片

以上是机器学习中几种常用的离群点检测方法。异常值的存在可能会在模型拟合(特别是线性模型),并且还可能导致夸大的误差度量,其给予大误差更高的权重。因此,在建立机器学习模型之前,有必要处理异常值。

使用四分位间距的异常值识别

原文:https://towardsdatascience.com/outlier-identification-using-interquartile-range-74f5de12932a?source=collection_archive---------29-----------------------

一种识别异常值的简单方法

照片由 艾萨克

识别异常值是数据预处理中非常常见的任务。它们可以通过模型改变样品的感知重要性,如果处理不当,可以改变任何分析的结果。识别它们的一个简单方法是使用四分位数范围。

四分位间距是多少?

IQR(四分位数范围)是分布的第三个四分位数和第一个四分位数之间的差值(或第 75 个百分位数减去第 25 个百分位数)。这是对我们的分布范围的度量,因为这个范围包含了数据集的一半点。了解分布的形状是非常有用的。例如,它是箱线图中盒子的宽度。

使用 IQR 的异常值定义

一旦我们计算出来,我们就可以用 IQR 来识别异常值。如果一个点满足以下条件之一,我们将该点标记为异常值:

  • 它大于第 75 百分位+ 1.5 IQR
  • 它不到 25%的百分之一点五 IQR

应用这个简单的公式,我们可以很容易地检测出分布中的异常值。Boxplot 使用相同的方法将异常值绘制为胡须外部的点。

1.5 系数背后的原因依赖于正态分布,但一般的想法是在不使用可能受异常值影响的一些度量的情况下计算异常值。这就是为什么,举例来说,使用标准差,可能会导致我们糟糕的结果。四分位数和百分位数是基于计数的,因此它们不太容易受到异常值的影响。

这个想法是,如果一个点离第 75 百分位(或第 25 百分位)太远,它就是一个“奇怪的”点,可以被标记为异常值。这个距离的数量级就是 IQR 本身。

让我们看一个 Python 编程语言中的简单例子。

Python 中的离群点检测

在本例中,我们将根据正态分布生成一些随机分布的点,然后我们将人工添加两个异常值,以查看算法是否能够发现它们。

首先,让我们导入 NumPy 并设置随机数生成器的种子。

import numpy as np 
np.random.seed(0)

现在,让我们创建我们的正态分布数据集。

x = np.random.normal(size=100)

让我们添加两个异常值,例如,-10 和 5。

x = np.append(x,[5,-10])

由于正态分布的均值为 0,方差等于 1,所以这两个数字离均值非常远,非常罕见。我们可以使用正态分布的累积分布函数显式计算它们的频率,这可以使用 scipy 来计算。

from scipy.stats import norm

值小于-10 的概率为:

norm.cdf(-10) 
# 7.61985302416047e-24

值大于 5 的概率为:

1-norm.cdf(5) 
# 2.866515719235352e-07

因此,这些值是如此罕见,远离平均值,他们可以被视为离群值。

现在,让我们来计算 IQR:

iqr = np.percentile(x,75) - np.percentile(x,25)

最后,我们可以根据原始公式创建真/假数组掩码来识别异常值:

outliers_mask = (x > np.percentile(x,75) + 1.5*iqr) | (x < np.percentile(x,25) - 1.5*iqr)

正如所料,它们被完美地识别出来:

x[outliers_mask] # array([ 5., -10.])

结论

对于数据科学家来说,处理离群值始终是一个问题。我们可以使用适当的探索性数据分析来检测异常值的存在,但是如果我们想要正确地标记它们,我们必须应用合适的算法。尽管 IQR 异常值检测只适用于单变量,但它对任何数据科学家和分析师来说都是一个简单而强大的帮助。

www.yourdatateacher.com 教授机器学习和数据科学的数据科学家吉安卢卡·马拉托。

原载于 2021 年 11 月 1 日 https://www.yourdatateacher.comhttps://www.yourdatateacher.com/2021/11/01/outlier-identification-using-interquartile-range/

用 Python 过度分析野生动物活动

原文:https://towardsdatascience.com/over-analyzing-wildlife-activity-with-a-trail-camera-and-python-f7aaebbdbd01?source=collection_archive---------24-----------------------

实践教程

什么叫“你自己出去看看那只鹿”?那是一种选择吗?!

Bushnell trail 相机拍摄了一只漂亮的大雄鹿,下面有 Amazon Rekognition 图像标签。

在狩猎和数据分析的交叉点上,有一个疯狂的人会想方设法利用他们的技术技能来提高他们成功猎鹿的几率。一个既享受户外生活又编写大量多余代码的人。一个努力学习更多自然知识的人,最终花了几个小时在他的笔记本电脑上。

那个人就是我。

几个月前,我在德克萨斯州中部的一些家庭土地上安装了一台蜂窝移动摄像机,用来观察鹿和其他好奇动物的进进出出。这个设备是一个布什内尔脉冲手机摄像头,你可以通过网页与之互动。当我去检查它拍摄的图像时,我期待的是一个简单的存储库——只不过是一堆照片和它们拍摄的时间。当我发现这些额外的数据点时,你可以想象我有多惊讶:

  • 亚马逊识别图像标签
  • 温度
  • 月相
  • 风向
  • 风速
  • 大气压

2020 年给我留下了很多空闲时间,我花了一部分时间学习使用 Python 进行数据分析的概念。这台相机给我提供了一个有趣的机会,一个突然出现的与个人相关的数据财富正等着我去分析。有什么比将我的知识应用于真实世界数据集更好的方法来测试我的知识呢?

当我想到这个想法时,我坐在笔记本电脑前,准备做任何崭露头角的新分析师在试图证明自己的价值时都会做的事情——通过从不完整的数据中得出不必要的结论来解决一个无关紧要的问题。我们去拯救世界吧。

问题

在我们开始之前,我可能应该定义我们在寻找什么——我们试图回答什么问题。

首先,我想知道鹿什么时候最活跃。这可以是一天中的几个小时,也可以是一年中的几天/几周。这将帮助我确定一年中最有希望的日子(在合法的猎鹿季节)去寻找它们。我还想知道上面列出的哪些数据点与鹿的活动最相关。例如,鹿有多关心月亮的相位?当风从南方而不是北方吹来时,他们会紧张吗?我相信我们都有自己的猜测,哪些功能是最重要的,但是看看数据来支持它会很有趣。

数据

我可以看到我想要的信息,但我不喜欢手动将每张图片的数据输入到 excel 电子表格的数百行中。一定有更好的方法…

在对 Bushnell Javascript API 进行逆向工程以了解要查找什么之后,我决定使用 Python 的 HTTP 请求库来收集数据。

我能够拼凑一个脚本来抓取网站,并使用我的数据生成一个漂亮的 excel 电子表格。我就不告诉你细节了——如果你好奇,可以看看下面的代码。

Python 脚本创建了一个 excel 电子表格,其中填充了来自 Bushnell“wirelesstrophycam”网站的数据。

有了下面的 excel 电子表格,我们可以开始分析了。

excel 电子表格输出的屏幕截图。

探索性数据分析

我做的第一件事是导入我打算使用的库,并将电子表格转换成数据帧。

*import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as stats
%matplotlib inline df = pd.read_excel('SPREADSHEET_NAME_HERE.xlsx', index_col = 0)df.info()*

数据帧信息。

在这里,我们可以看到我们的每个列名以及行数——自从我启动相机以来,看起来我们已经获得了 1700 多张照片。接下来,我希望能够区分有鹿的图片和由其他毛茸茸的朋友触发的图片。我添加了一个新的列,如果图片包含一只鹿,该列将填充 1 或 0。

如果你仔细查看 excel 电子表格,你可能会注意到一些奇怪的标记……鉴于我们的牧场位于德克萨斯州中部,我相当有信心不会看到麋鹿、黑斑羚或羚羊。相反,似乎亚马逊河流域识别错误地识别了这些鹿。考虑到这一点,我肯定会在下面的代码中寻找那些附加的动物标记,并将它们视为鹿。

*# add a column that determines if Deer is in the string and will  #populate as True or False or NaN
df['contains_deer'] = df['tag_name_string'].str.contains('Deer|Antelope|Elk|Impala')#replace Trues and Falses with 1s and 0s
df['contains_deer'] = df['contains_deer'].replace({True: 1, False:0})#fill in the contains_deer column with 0's if no tags were present (NaN in tag_name_string)
df['contains_deer'] = df['contains_deer'].fillna(0)#the df.replace from above defaults to float values (1.0 and 0.0), #so change them to ints (1 and 0)
df['contains_deer'] = df['contains_deer'].astype(int)*

我使用新的 contains_deer 列来轻松区分有鹿的图片和没有鹿的图片。这种二进制分类将在以后派上用场…

为了探究因鹿而拍摄的照片相对于其他照片的比例,我使用了 Seaborn 计数图的“色调”特征:

*sns.countplot(data = df, x = 'date', hue = 'contains_deer', palette = 'Paired')*

浅蓝色条代表图像中没有任何鹿(至少根据 AWS)。我们可以看到,在任何一天,除了鹿之外,还有更多其他东西的照片。但是如果不是鹿,外面还有什么?是什么让我的相机有这么多珍贵的记忆呢?

进入垃圾熊猫。这些家伙每天晚上都出去偷喂食器里的玉米,就像他们的生命依赖于此一样(在某种程度上,我想他们是这样的),并占了数百张照片。不管怎样,现在我们知道了为什么有这么多与我的问题无关的照片,我们可以去掉它们,只画鹿。

在我展示之前,这里有一个简短的插曲,是相机拍摄的一些其他有趣的照片:

山猫、雄鹿、臭鼬,还有更罕见的东西——雪!

在图表上:

*sns.countplot(x = 'date', data = df2, palette = 'rainbow')*

随着时间的推移,相机激活标记为“鹿”。

现在事情开始变得有趣了。上图显示了每天拍摄的鹿的标记图片数量。尽管有相当多的变化(一般来说,每天 1 到 12 张照片),你可能会注意到从 11 月 13 日到 19 日活动的增加。15、17、18 都大于 15 张图!

如果你注意到了那个大尖峰,那么你也应该注意到了 16 日明显缺乏图片——正好在我们的鹿朋友们似乎最活跃的几天中间。怎么回事?

不用花几个小时写脚本和分析数据就知道鹿的运动严重依赖于天气。为了探索这一点,我决定检查每天的平均温度,并将它们叠加在活动图上。结果如下:

*df.groupby(['date']).mean()['temperature'].plot(kind = 'line', ax = ax, linestyle = '--', marker = 'o', markerfacecolor = 'c', ylabel = 'Temperature (F)', xlabel = 'Date') #line graph of avg temp per day*

你瞧,16 日的平均气温实际上比那一天前后五天的移动平均气温低 11 度。看起来我们对这种奇怪的现象有了一个非常令人信服的解释:一股冷锋吹来,导致鹿躲避,打断了它们在这段时间活跃的自然趋势。

所选时段的日平均温度。请注意,16 日是 44 度——远低于边境日的温度。

没有什么比你自己得出结论,然后找到完全支持你的结论的外部数据更好的了。我们在我的牧场确定的活动高峰日期(11 月 13 日至 11 月 19 日)恰好落在德克萨斯公园和野生动物预测的“发情期”高峰——这是鹿繁殖和最活跃的时期。对于这个地区(爱德华兹高原),他们发现发情期在 11 月 7 日和 11 月 24 日之间。我们对数据的解读得到了证实!

这一分析给了我一些可操作的见解。明年,我会计划一次旅行,在这段高度活跃的时期去那里。我也会关注雷达,记住即使是最活跃的时期也会受到恶劣天气的严重影响。

当然,我可以在第一时间浏览 TPW 的网站,然后在发情期出去,但是这有什么意思呢?

训练随机森林机器学习模型

如果你认为我刚才做的分析是不必要的,你会喜欢接下来的。在这一部分,我训练了一个机器学习模型,根据我们的定量数据(温度、风速、大气压等)来预测鹿是否会出现。

注意:如果你不知道什么是随机森林分类器,那也没关系。这里有几篇文章的链接,可能有助于解释这个问题:这里或者这里

我做的第一件事是导入一个 Scikit-learn 库,然后将数据分成一个训练集和一个测试集。

*from sklearn.model_selection import train_test_splitX = df.drop(columns = ['filename', 'date', 'time', 'tag_name_string', 'contains_deer'])
y = df['contains_deer']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)*

X 变量是我用于模型的数据,而 y 变量是我试图预测的数据。

下面的代码包含了我需要做的几乎所有事情——导入更多的库,训练模型,并打印出结果(在分类报告中)。

*from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.inspection import permutation_importancerf = RandomForestClassifier(n_estimators = 600)rf.fit(X_train, y_train)
pred_rfc = rf.predict(X_test)print(classification_report(y_test, pred_rfc))*

随机森林模型的分类报告。

上面的分类报告向我们展示了模型的准确性。由于在这种情况下模型本身是完全不必要的,我将只强调 F1 分数——它是召回和精确分数的调和平均值。用更通俗的话来说,它告诉你模型做出的正面预测有多少是正确的。我现在可以从理论上提供一组数据(温度、气压、风速等)。)给模型,并让它基于所述数据预测鹿是否会出现。

就像我之前说过的,一次又一次,这完全没有必要。我真正好奇的是,是否有任何数据点对预测鹿的活动有不成比例的影响。一个特征重要性图将向我们展示在进行预测时模型的哪些参数是最重要的。

*feature_importance = pd.DataFrame(sorted(zip(rf.feature_importances_, X.columns)), columns=['Value','Feature'])sns.barplot(x="Value", y="Feature", data=feature_importance.sort_values(by="Value", ascending=False))*

特征重要性图。

根据上面的图表,很清楚哪些输入参数是最重要的。一个重要的警告是,这种分析对“循环”数据不起作用。例如,风向被列为我们模型最重要的特征。数据点在 0 到 359 度之间,表示主要风向。0 度风向和 359 度风向几乎相同,但模型将它们视为最大不同值。出于这个原因,我们应该忽略风向月相特征(并考虑将它们从我们的模型中完全移除)。

删除这些错误特征后,我们现在可以看到温度是我们模型中最重要的预测特征,紧随其后的是压力。当试图预测鹿的行为时,风速是一个不太重要的特征。这有助于验证我们早期的观点,即为什么在快速移动的冷锋期间鹿的活动突然减少。

如果你能走到这一步,恭喜你。我希望你学到了一些数据分析或野生动物活动或两者兼而有之。下次你拿到一些关于鹿的数据时,也许你也可以进行一些有见地的分析。否则,你知道该找谁。

图形神经网络中的过平滑问题

原文:https://towardsdatascience.com/over-smoothing-issue-in-graph-neural-network-bddc8fbc2472?source=collection_archive---------8-----------------------

[作者插图]

TLDR :这个故事给出了图形神经网络的一个高级入口:如何和为什么,然后介绍伴随着消息传递框架的一个严重问题,它代表了当今 GNN 的主要特征。别忘了使用下面的参考资料来加深你对 GNNs 的理解!

图形神经网络图解指南

图形神经网络或简称 GNN 是用于图形数据的深度学习(DL)模型。最近几年,它们变得相当热门。这种趋势在 DL 领域并不新鲜:每年我们都会看到一个新模型脱颖而出,要么在基准测试中显示最先进的结果,要么在已经使用的模型中显示全新的机制/框架(但当你阅读它时会非常直观)。这种反思让我们质疑这种致力于图形数据的新模型存在的理由。

我们为什么需要 GNNs?

图形无处不在:图形数据丰富,相信是最自然灵活的方式来呈现我们每天产生或消耗的素材。我们无需费力去列举一整套图表数据示例,从大多数公司和社交网络(如脸书或 Twitter)中使用的关系数据库,到链接科学和文学中的知识创造的引用图表。由于图像的网格结构,甚至图像也可以被视为图形。

对于关系数据库,实体是节点,关系(一对一,一对多)定义了我们的边。至于图像,像素是节点,相邻像素可以用来定义边缘[作者举例]

能够捕捉图形中所有可能信息的模型:正如我们所看到的,图形数据无处不在,并且采用具有特征向量的互连节点的形式。是的,我们可以使用一些多层感知器模型来解决我们的下游任务,但是我们将失去图拓扑提供给我们的连接。至于卷积神经网络,它们的机制致力于图的特殊情况:网格结构的输入,其中节点是完全连接的,没有稀疏性。也就是说,唯一剩下的解决方案是一个可以建立在两者中给出的信息之上的模型:我们的图中的节点特征和本地结构,这可以减轻我们的下游任务;这正是 GNN 所做的。

GNNs 训练什么任务?

既然我们已经适度地证明了这种模型的存在,我们将揭示它们的用法。事实上,我们可以在很多任务上训练 GNNs:大型图中的节点分类(根据属性及其关系对社交网络中的用户进行细分),或整个图分类(为药物应用对蛋白质结构进行分类)。除了分类之外,回归问题也可以在图形数据之上公式化,不仅在节点上工作,也在边上工作。

总之,图形神经网络的应用是无止境的,并且取决于用户的目标和他们拥有的数据类型。为了简单起见,我们将集中于唯一图中的节点分类任务,其中我们尝试将由节点的特征向量领导的节点图的子集映射到一组预定义的类别/类。

该问题假设存在一个训练集,其中我们有一组带标签的节点,并且我们图中的所有节点都有一个特定的特征向量,我们记为 x。我们的目标是预测验证集中特征节点的标签。

节点分类示例:所有节点都有一个特征向量;彩色节点被标记,而白色节点未被标记[作者插图]

引擎盖下的 GNN

既然我们已经设置了我们的问题,是时候了解 GNN 模型将如何被训练来为未标记的节点输出类了。事实上,我们希望我们的模型不仅使用我们的节点的特征向量,而且利用我们处理的图结构。

使 GNN 独特的这最后一个陈述必须被限制在某个假设内,该假设声明 邻居节点倾向于共享相同的标签 。GNN 通过使用消息传递形式来合并它,这个概念将在本文中进一步讨论。我们将介绍一些我们将在后面考虑的瓶颈。

抽象够了,现在让我们看看 gnn 是如何构造的。事实上,GNN 模型包含一系列通过更新的节点表示进行通信的层(每层为每个节点输出一个嵌入向量,然后该向量被用作下一层的输入以在其上进行构建)。

我们的模型的目的是构建这些嵌入(对于每个节点),集成节点的初始特征向量和关于围绕它们的局部图结构的信息。一旦我们有了良好表示的嵌入,我们就为这些嵌入提供一个经典的 Softmax 层来输出相关的类。

GNN 的目标是将节点特征转换成能够感知图形结构的特征

为了构建这些嵌入,GNN 层使用一种简单的机制,称为消息传递,这有助于图节点与其邻居交换信息,从而一层又一层地更新它们的嵌入向量。

  • 消息传递框架

这一切都从一些节点开始,用向量 x 描述它们的属性,然后每个节点通过置换等变函数(平均值,最大值,最小值)从它的邻居节点收集其他特征向量..).换句话说,这是一个对节点排序不敏感的函数。这个操作叫做聚合,它输出一个消息向量。

第二步是更新功能,其中节点将从其邻居收集的信息(消息向量)与其自己的信息(其特征向量)相结合,以构建新的向量 h:嵌入

这种聚集和更新函数的实例化因论文而异。你可以参考 GCN[1],GraphSage[2],GAT[3]或者其他人,但是消息传递的思想是不变的。

我们的 GNN 模型的第一层从特征向量 x0 到它的新嵌入 h 的图解[作者图解]

这个框架背后的直觉是什么?嗯,我们希望我们的节点的新嵌入考虑到本地图结构,这就是为什么我们从邻居的节点聚合信息。通过这样做,人们可以直观地预见到一组邻居节点在聚集后将具有更相似的表示,这将在最后减轻我们的分类任务。所有这一切在我们的第一个假设( 邻居节点倾向于共享同一个标签 )的情况下总是成立的。

  • GNNs 中的图层组成

现在我们已经理解了消息传递的主要机制,是时候理解层在 GNN 的上下文中意味着什么了。

回想上一节,每个节点使用来自其邻居的信息来更新其嵌入,因此自然的扩展是使用来自其邻居的邻居的信息(或第二跳邻居)来增加其感受域并变得更加了解图结构。这就是我们 GNN 模型的第二层。

通过聚集来自 N 跳邻居的信息,我们可以将其推广到 N 层。

一层又一层,节点可以访问更多的图节点和更具图结构意识的嵌入

至此,您已经对 gnn 如何工作有了一个高层次的理解,并且您可能能够发现为什么这种形式主义会有问题。首先,在深度学习的背景下谈论 GNN 假设深度(许多层)的存在。这意味着节点可以访问来自远处的节点的信息,这些节点可能与它们不相似。一方面,消息传递形式主义试图软化相邻节点之间的距离(平滑)以方便我们稍后的分类。另一方面,它可以在另一个方向上工作,通过使我们所有的节点嵌入相似,因此我们将不能分类未标记的节点(过度平滑)。

在下一节中,我将尝试解释什么是平滑和过度平滑,我们将讨论平滑作为增加 GNN 图层的自然效果,我们将了解为什么它会成为一个问题。

我还将尝试量化它(从而使它可跟踪),并在此量化的基础上,使用关于此问题的已发表论文中的解决方案来解决它。

GNNs 中的过度平滑问题

尽管消息传递机制有助于我们利用图结构中封装的信息,但如果与 GNN 深度结合,它可能会引入一些限制。换句话说,我们对一个更具表达性和更了解图结构的模型的追求(通过增加更多的层,使节点可以有一个大的感受域)可以转化为一个对节点一视同仁的模型(节点表示收敛到不可区分的向量[4])。

这种平滑现象不是错误,也不是特例,而是 GNN 的本质,我们的目标是缓解它。

为什么会出现过度平滑?

消息传递框架使用前面介绍的两个主要函数聚合更新,它们从邻居那里收集特征向量,并将它们与节点自身的特征相结合,以更新它们的表示。该操作的工作方式使得交互节点(在该流程中)具有非常相似的表示。

我们将尝试在模型的第一层中说明这一点,以显示平滑为什么会发生,然后添加更多的层来显示这种表示平滑如何随着层的增加而增加。

注:过度平滑以节点嵌入的相似性的形式表现出来。所以我们使用颜色,其中不同的颜色意味着矢量嵌入的不同。此外,为了简化我们的示例,我们将只更新突出显示的 4 个节点。

我们 GNN 的第一层[作者插图]

正如您在第一层中看到的,节点可以访问一跳邻居。例如,您可能还会观察到,节点** 2节点 3 几乎可以访问相同的信息,因为它们相互链接并具有共同的邻居,唯一的区别在于它们最后的邻居(紫色和黄色)。我们可以预测,它们的嵌入会略有相似。至于节点 1节点 4 ,它们相互作用但有不同的邻居。因此我们可以预测**他们的新嵌入将会不同。****

我们通过给每个节点分配新的嵌入来更新我们的图,并移动到第二层并重复相同的过程。

GNN 的第二层[作者插图]

在我们的 GNN 的第二层中,节点 1、4 和 2、3 的计算图分别几乎相同。我们可以预期,我们对这些节点的新的更新嵌入将更加相似,甚至对于在某种程度上“幸存于”的节点 1节点 4 ,第一层现在将具有相似的嵌入,因为额外的层给予它们对图的更多部分的访问,增加了访问相同节点的概率。

这个简化的例子显示了过度平滑是 GNN 深度的结果。公平地说,这与真实案例相去甚远,但它仍然给出了这种现象发生背后的原因。

为什么这真的是一个问题?

既然我们了解了过度平滑发生的原因,以及它是由 GNN 图层合成的效果设计而成的原因,那么是时候强调我们为什么应该关注它,并提出解决方案来克服它了。

首先,学习我们的嵌入的目标是在最后将它们提供给分类器,以便预测它们的标签。考虑到这种过度平滑的影响,我们最终会对没有相同标签的节点进行类似的嵌入,这将导致它们的错误标签。

人们可能认为减少层数会降低过度平滑的效果。是的,但是这意味着在复杂结构数据的情况下不能利用多跳信息,因此不能提高我们的最终任务性能。

为了强调最后一句话,我将用一个现实生活中常见的例子来说明它。想象一下,我们正在处理一个有数千个节点的社交网络图。一些新用户刚刚登录平台,订阅了他们朋友的个人资料。我们的目标是找到主题建议来填充他们的提要。

一个虚构的社交网络[作者插图]

给定这个假想的社交网络,在我们的 GNN 模型中仅使用 1 或 2 层,我们将仅了解到我们的用户关心供应链话题,但是我们错过了他可能喜欢的其他多样化话题,因为他的朋友的互动。

总之,由于过度平滑是一个问题,我们在低效率模型和更有深度但在节点表示方面缺乏表达性的模型之间遇到了一个折衷。

怎么才能量化呢?

既然我们已经清楚过度平滑是一个问题,我们应该关注它,我们必须量化它,以便我们可以在训练 GNN 模型时跟踪它。不仅如此,通过将量化作为正则项添加到我们的目标函数中,量化还将为我们提供一个用作数值惩罚的度量。

根据我最近的阅读,大量的论文讨论了 GNN 的过度平滑问题,他们都提出了一个量化指标来证明他们对这个问题的假设,并验证他们的解决方案。

我从两篇讨论这个问题的不同论文中选择了两个指标。

  • MAD 和 MADGap【5】

Deli Chen 等人引入了 MAD 和 MADGap 两个量化指标来度量图节点表示的光滑性和过度光滑性。

一方面,MAD 计算图中节点表示(嵌入)之间的平均距离,并使用它来显示平滑是向 GNN 模型添加更多层的自然效果。基于这一度量,他们将其扩展到 MADGap,MADGap 测量不同类别节点之间表示的****相似性。这种概括建立在主要假设上,即当节点交互时,它们或者可以从来自同一类的节点获得重要信息,或者可以通过与来自其他类的节点交互获得噪声。****

当节点访问图的更多部分时,我们可能会访问影响最终嵌入的噪声节点

在这篇论文中引起我兴趣的是作者质疑消息传递形式主义所基于的主要假设的方式(邻居节点可能有相似的标签)。事实上,他们的测量 MADGap 不仅仅是过度平滑的测量,而是相对于节点收集的信号的信噪比的测量。因此,观察到这一比率逐层降低证明了图拓扑和下游任务目标之间的差异。****

  • 组距离比【6】

周凯雄等人引入了另一个应变前向度量,但其目标与 MADGap 相同,即组距离比。此指标计算两个平均距离,然后计算它们的比率。我们首先将节点放在相对于其标签的特定组中。然后,为了构造我们的比率的命名器,我们计算每两个节点组之间的成对距离,然后对结果距离进行平均。至于分母,我们计算每组的平均距离,然后计算平均值。

解释如何计算组距离比率的图解[作者图解]

具有小的比率意味着不同组中节点嵌入之间的平均距离小,因此我们可以根据它们的嵌入来混合组,这是过度平滑的证明。

我们的目标是保持一个高的组距离比率,以使节点类在嵌入方面有所不同,这将减轻我们的下游任务。

有没有解决过度平滑的方法?

直接监管术语?

既然我们已经量化了过度平滑问题,您可能会认为我们的工作已经结束,将这一指标作为监管条款添加到我们的损失目标中就足够了。剩下的问题是,在我们的训练会话的每次迭代中计算这些度量(如上所述)可能在计算上是昂贵的,因为我们需要访问我们的图中的所有训练节点,然后进行一些距离计算,处理与节点数量成二次比例的节点对(C(2,n) = n * (n -1) / 2 = O(n))。

间接解决方案?

由于这个原因,所有讨论过平滑问题的论文都考虑通过更容易实现并且对过平滑有影响的其他间接解决方案来克服这个计算问题。我们不会详细讨论这些解决方案,但是您可以在下面找到其中一些的参考资料。

对于我们的例子,我们将处理由周凯雄等人引入的可微分组归一化[6]。DGN 将节点分配到组中,并独立地归一化它们,以输出下一层的新嵌入矩阵。

这个附加层是为了优化先前定义的组距离比 而构建的。事实上,在一个组内嵌入的节点的归一化使得它们的嵌入非常相似(减少 Rgroup 的分子),并且这些使用可训练参数的缩放和移位使得来自不同组的嵌入不同(增加 Rgroup 的分子)。

可区分组规范化是如何工作的?[作者插图]

为什么会起作用?第一次阅读这篇论文时,我没有看到添加这个归一化层和优化 Rgrou 比率之间的联系,然后我观察到,这个层一方面使用可训练的分配矩阵,因此它有来自我们的损失函数的反馈,所以它被引导在理想情况下将节点分配给它们的真实类。另一方面,我们也有同样由损失函数引导的移动和缩放参数。这些参数用于区分不同组的嵌入,因此有助于下游任务。

开场白和结论

这篇文章可能很长,但它只是触及了图形神经网络及其问题的表面,我试图从 gnn 的一个小探索开始,并展示它们如何能够——用这样一个简单的机制——打开我们在其他 DL 架构的上下文中无法想到的潜在应用。这种简单性受到许多问题的限制,阻碍了它们的表达能力(目前…),研究人员的目标是在寻求利用图形数据的全部力量时克服它。

就我而言,我阅读了不同的论文讨论 GNNs 的一些限制和瓶颈,但将它们统一起来的一个共同点是所有这些问题都可以与我们用来训练我们的图模型的主要机制相联系,这就是消息传递。我可能不是专家,但我必须就此提出一些问题。不断列举这些问题并试图解决它们真的值得吗?既然我们还处于这个有趣领域的第一次迭代,为什么不考虑一个新的机制并尝试一下呢?

[1] Kipf,T. N. (2016 年 9 月 9 日)。基于图卷积网络的半监督分类。ArXiv.Org。https://arxiv.org/abs/1609.02907

[2]汉密尔顿,W. L. (2017 年 6 月 7 日)。大型图上的归纳表示学习。ArXiv.Org。https://arxiv.org/abs/1706.02216

[3]veli kovi,P. (2017 年 10 月 30 日)。图形注意力网络。ArXiv.Org。https://arxiv.org/abs/1710.10903

[4] Oono,K. (2019 年 5 月 27 日)。图形神经网络指数地失去了节点分类的表达能力。ArXiv.Org。https://arxiv.org/abs/1905.10947

[5]陈 d .(2019 . 9 . 7)。从拓扑角度度量和缓解图神经网络的过光滑问题。ArXiv.Org。https://arxiv.org/abs/1909.03211

[6]周,K. (2020 年 6 月 12 日).用可微分的组规范化走向更深层次的图形神经网络。ArXiv.Org。https://arxiv.org/abs/2006.06972

我想对齐纳布·SAIF巴德尔·穆法德 为这部不大的作品做出的贡献表示感谢。不要忘了我的阅读团队,他们一直在给我发草稿。谢谢大家,直到我们在另一个故事中相遇

过度挤压、瓶颈和图的 Ricci 曲率

原文:https://towardsdatascience.com/over-squashing-bottlenecks-and-graph-ricci-curvature-c238b7169e16?source=collection_archive---------4-----------------------

重新思考 GNNs

当消息传递未能在图上有效传播信息时,过度挤压是图神经网络的常见困境。在这篇文章中,我们讨论如何通过从微分几何领域借用的 Ricci 曲率的概念来理解和纠正这种现象。

本文由弗朗西斯科·迪·乔瓦尼和杰克·托普合著,基于 j·托普、f·迪·乔瓦尼等人的论文 通过曲率理解图的过度挤压和瓶颈【ICLR】(2022),由 Twitter Cortex 和牛津大学合作完成。这篇文章是通过微分几何和代数拓扑 的透镜来研究 图神经网络系列的一部分。另见系列讨论 神经扩散偏微分方程 细胞束 拓扑信息传递 的其他帖子。如需更多详细信息,请参见 Aleksa gordi**解释论文的视频以及图表&几何阅读小组中 Francesco 和 Jake 的 谈话

T 大多数图神经网络(GNN)体系结构基于消息传递范式,其中信息在图的节点之间沿其边缘传播。传统上,输入图形既用作数据(连同节点特征)的一部分,也用作信息传播的计算结构。然而,最近的工作表明,某些图形在某些情况下对消息传递来说往往是“不友好的”[1],挑战了这一范式。

更具体地说,当所学习的任务需要长程相关性时(即,MPNN 的输出依赖于彼此交互的远程节点的表示),消息传递神经网络(mpnn)[2]往往表现不佳,同时,图的结构导致指数级的许多长程相邻节点(即,节点的“感受野”随着邻域的半径呈指数级增长)。在这种情况下,来自非相邻节点的消息需要被传播并压缩成固定大小的向量,从而造成信息过度挤压【3】的现象。造成过度挤压的图形结构特征被称为“瓶颈”。公平地说,尽管从经验上进行了广泛观察,但对这些现象的理论理解相当有限。

在最近的一篇论文中,我们引入了一些工具,通过描述图的局部几何性质来研究过度拥挤和瓶颈。假设我们有一个多层的 MPNN;我们可以计算由 MPNN 计算的隐藏特征对远程节点处的输入特征的敏感度。给定一个节点 p 和另一个节点 sr-远离它[5],雅可比∂h⁽ʳ⁺⁾/∂x告诉我们输入特征的变化 x 将如何被 MPNN 传播并影响(r+1)st 层输出【t35 该雅可比矩阵的小绝对值表明信息传播不良或过度拥挤[6]。

过挤压可以被定义为节点 p 处的 MPNN 的输出对 r 远处节点 s 处的输入特征缺乏敏感性,由雅可比|∂hₚ⁽ʳ⁺⁾/∂xₛ|.量化树是这种现象特别严重的病理图的示例。

雅可比矩阵可以由通过图的归一化邻接矩阵的幂表示的项来限定[7]。然而,除了指出图形结构(“瓶颈”)在某种程度上是过度挤压的原因之外,这种表达方式并不具有启发性。为了更好地理解瓶颈的本质,我们需要更仔细地看看图的细粒度几何属性。

首先,我们期望看起来像网格的图(其中节点的感受域多项式增长,就像卷积神经网络的情况)和看起来像树的图(具有指数增长的感受域)有非常不同的行为。在微分几何中,一个让我们能够区分不同几何形状的自然物体就是 Ricci 曲率,以早期微分几何学家Gregorio Ricci-curba stro【8】命名。粗略地说[9],它决定了“测地线离散度”,即从附近具有“相同”速度的点开始的测地线是保持平行(如在曲率为零的欧几里德空间中),收敛(正曲率的球面空间),还是发散(负曲率的双曲空间)。

流形的 Ricci 曲率可以通过“测地分散”来表征,即从附近点射出的两个平行测地线是否收敛(这发生在局部类似于球体的正弯曲空间中)、保持平行(平坦或欧几里得情形)或发散(负曲率产生双曲几何)。

流形的 Ricci 曲率是微分几何和引力几何理论中研究的最基本的几何对象之一(在广义相对论中,Ricci 曲率出现在爱因斯坦的场方程中,该方程将时空的曲率与能量和动量联系起来)。它还被广泛探索为一种通过一族几何偏微分方程使公制结构变形的方法,该方程由理查德·汉弥尔顿在 20 世纪 80 年代以“瑞奇流”【10】的名义引入。二十年后,格里戈里·佩雷尔曼完成了汉密尔顿的程序,证明了著名的庞加莱猜想,这一方法甚至在纯数学领域之外也声名狼藉。

从左至右:格雷戈里奥·利玛窦-库巴斯托(他引入了现在所谓的“利玛窦曲率”)、理查德·汉弥尔顿(他构想了“利玛窦流”)、格里戈里·佩雷尔曼(他用汉密尔顿的技术证明了百年 庞加莱猜想 )。《科学》杂志宣布该证明为 2006 年 年度 突破。图片来源:维基百科/卡梅伦·斯莱登/科学。

作为图中测地离差的类比,考虑一条边 p ~ q 和两条分别从 pq 开始的边。在一个离散的球形几何体中,边会在另一个节点 k 处相遇,形成一个三角形(一个 3-团)。在离散欧几里德几何中,边将保持平行,并形成基于 p ~ q (正交网格)的矩形 (4 圈)。最后,在离散双曲几何中,与 pq 相比,边端点的相互距离会增加(这是树的情况)。

基于对上述局部结构(三角形、矩形和向外边缘)的计数,我们为边缘 p ~ q 定义了一个新的概念平衡共振峰曲率【12】,用 Ric( pq 表示。我们的离散曲率再现了连续情况下的测地线色散行为:

我们对图上离散 Ricci 曲率的定义通过捕捉从节点 p 和 q 发出的边(用粗体黑色标记)形成的局部结构来模拟连续情况下的“测地线离散度”,其中 p~q 是边。在球面几何的离散类比中,这些边倾向于形成三角形(本例中的 pqk)。在欧几里得几何中,它们保持“平行”(即,停留在相同的 1 跳距离并形成 4 个循环)。在双曲几何中,边发散(即,它们的端点之间的距离增加,导致树状结构)。

本文的主要理论结果是雅可比矩阵的界限,它量化了 MPNN 输出对输入特征的敏感度,通过平衡的 Forman 曲率[13],从而将图形的曲率与过度挤压现象联系起来。我们的结论是负向弯曲的边是导致过度挤压的图形瓶颈。

我们的结果的实际含义之一是一种基于曲率的图重布线的概念方法,称为“随机离散瑞奇流”连续的 Ricci 流与 Ricci 曲率成比例地发展了黎曼流形的度量。受这种方法的启发,并根据我们对瓶颈的描述,我们使用离散的平衡福尔曼曲率来指导图上的重新布线,其中在最负弯曲的边周围局部添加边 p ~ q 以减少瓶颈。在预处理阶段完成,这样的重新布线使得图对消息传递更友好,并且提高了图神经网络的性能。同时,我们程序的“外科手术”性质确保了新图表与原始图表没有显著不同。

上图:具有负弯曲瓶颈(由冷色编码的负曲率)的哑铃形黎曼流形经历了基于曲率的度量演化,变得“更圆”,更少“瓶颈”。下图:基于曲率的图形重布线的类似过程,减少了瓶颈,使图形对消息传递更友好。

在本文的第二部分,我们将看看基于曲率的图重布线的实验评估,并将其与约翰内斯·克利茨佩拉和合著者介绍的流行的基于扩散的重布线方法 DIGL 进行比较【14】。使用微分几何的技术,我们将试图更好地理解扩散是否(以及何时)改善图形学习。

[1] U. Alon 和 E. Yahav,论图神经网络的瓶颈及其实际意义 (2020) arXiv:2006.05205 .

[2] J. Gilmer 等人,量子化学的神经信息传递 (2017) ICML。

[3]以前在传统(基于 RNN 的)seq2seq 模型中观察到过度挤压现象——这些模型必须将整个输入序列“挤压”到固定大小的向量中。然而,当在 1D 网格上操作的 RNNs 中,节点的感受野线性增长时,在 GNNs 中,这种增长通常是指数的,因此更令人关注。

[4] J. Topping,F. Di Giovanni 等人,通过曲率理解图的过度挤压和瓶颈 (2021) arXiv:2111.14522。

[5]即 ps 之间的最短路径(测地线)由 r 跳组成。

[6]类似的灵敏度分析由徐等人完成,跳跃知识网络图的表示学习 (2018),但据我们所知,我们是第一个将其应用于过度挤压的。

[7]我们论文[4]中的方程 2。

[8] G .利玛窦,《质量变化中的原理》( 1903-1904 年)。威尼托63(2):1233–1239。用一个缩写姓氏“利玛窦”(而不是“利玛窦-库巴斯托”,一个古老的意大利家族)签名,有时会让人混淆这是不是两个不同的人。

[9]形式上,Ricci 曲率为黎曼流形上每一点的切空间指定了一个对称的双线性形式(张量),它表示度量与平坦的(欧几里得)度量有多么不同。更一般地,可以测量任意仿射连接的 Ricci 曲率。测地线色散还可以与体积增长(即半径为 r 的球的体积)相关,在欧氏空间中是多项式,在双曲空间中是指数。

[10] R. S. Hamilton,具有正 Ricci 曲率的三流形 (1982)微分几何杂志 17(2):255–306 介绍了 Ricci 流。瑞奇流是形式为∂g/∂t=-2r的偏微分方程,其控制流形的黎曼度量张量 g 与瑞奇曲率张量 R 成比例的演化,其在结构上类似于扩散方程。

[11]该证明出现在一系列 arXiv 论文中,G. Perelman,Ricci 流的熵公式及其几何应用(2002)arXiv:0211159,G. Perelman, Ricci 流与三流形上的手术(2003)arXiv:0303109,以及 G. Perelman,佩雷尔曼用“手术的瑞奇流”证明了一个更一般的结果,称为瑟斯顿几何化猜想,其中庞加莱猜想是一个特例。如果不是因为与另一位明星数学家丘成桐在优先权问题上的争执,这一非凡的数学成就可能会被公众忽视。大卫·格鲁伯(我在 CETI 项目中的同事,也是出了名的离群索居的佩雷尔曼接受采访的少数人之一)和西尔维娅·纳萨尔(通常被认为是《美丽心灵》的作者)在他们的《纽约客》文章中引起了广泛关注。佩雷尔曼因此拒绝了应得的奖励和金钱,并退出了公共生活和数学。

[12]在我们的论文[4]中,等式 3 给出了平衡曲率的定义。存在几种 Ricci 曲率的图形类比,其中包括 R. Forman 介绍的构造、 Bochner 的细胞复形和组合 Ricci 曲率的方法 (2003)离散和计算几何 29:323–374 和 Y. Ollivier、度量空间的 Ricci 曲率(2007)Comptes Rendus mathématique 345(11):643–646,称为 Forman -和奥利维尔曲率由于其与最佳传输的关系而具有更丰富的理论,但同时计算起来很昂贵,而福曼曲率的优势在于其组合定义和更低的计算复杂度。然而,Forman 曲率的缺点在于它偏向于负曲率(例如,根据 Forman 的定义,网格的曲率是负的)。出于这个原因,我们引入了一个新版本的 Ricci 曲率图,在精神上类似于 Forman 的构造,但考虑了 4 个周期的贡献,因此命名为“平衡 Forman ”。我们证明了我们的曲率是奥利维尔曲率的下界(定理 2)。这个结果的一个结果,连同关于奥利维尔曲率的已知事实,是在正弯曲的图中,体积多项式地增长(推论 3)。

[13]我们论文[4]中的定理 4。

[14] J .克利茨佩拉等人,扩散改善图学习 (2019) NeurIPS,缩写为“DIGL”,是一种基于扩散图拓扑的图重布线方法。

我们非常感谢克里斯·博德纳尔和大卫·艾纳德的校对和深刻的评论。本帖是通过微分几何和代数拓扑 的透镜讲述 图神经网络系列的一部分。有关图形深度学习的其他文章,请参见 Michael 在《走向数据科学》中的 其他帖子 订阅他的帖子和 YouTube 频道 ,获取 中级会员资格 ,或在 Twitter 上关注 Michael

克服人工智能在预测创业成功方面的偏见

原文:https://towardsdatascience.com/overcoming-ai-faults-in-predicting-startup-success-768985e6e289?source=collection_archive---------22-----------------------

许多预测创业成功的尝试( 我们 做到了 78%的准确率)。人工智能时代让我们能够识别复杂创业数据中的模式。但是,当我们有脏数据和次优的现成人工智能时,会发生什么?在这篇文章中,我们描述了我们识别数据和创建预测创业成功的人工智能的方法。

迈克尔·泽兹奇拍摄的照片

动机

每个投资者都想在潜在投资的海洋中找到隐藏的独角兽。发现具有独角兽潜力的创始人,尤其是在他们职业生涯的早期,极其困难。尽管如此,还是有很多尝试预测公司成功的例子。我在谷歌上快速搜索了一下,找到了 20 多个。其中一些是投资者给出他们对最重要的事情的看法的诀窍。其他人是从大数据中搜索预测洞察力的机器学习工程师。

不幸的是,这些方法最终都达不到要求。这些方法不够理想有多种原因。投资者提供的见解是他们认为重要的有价值的视角,但它们是不可能复制的。他们衡量创始人“专注度”的内部尺度是无法在另一个投资者的过程中(非常容易地)校准的。虽然我坚信人类是优秀的模式识别者,但我们也只能掌握这么多信息。这些投资者的“规则”可能只捕捉到一个更大的画面的一部分,并可能以某种不明显的方式存在偏见。这意味着这些规则可能不适用于所有创始人。我也坚信数据和机器学习/数据科学/人工智能/模式识别技术包含预测创业成功的能力(具有一定程度的准确性)。然而,我看到的方法通常使用公开可用的数据,做出自己的一套假设。我没有提及这些作品,因为我不想贬低他们正在做的工作。我认为这很有价值,但这是一个有很多不确定性的问题。在这篇文章的剩余部分,我将重点关注预测创业成功的数据驱动方法。我将对数据、标准人工智能实践以及我们为交付专门为此开发的解决方案所做的工作进行高层次的概述。

启动数据

询问任何一位数据科学家,他们可能会告诉你这项工作最令人沮丧的部分之一是清理数据。我从事数据工作已经 10 多年了,但从未收到过干净的数据。围绕数据的问题不是它是否脏,而是脏到什么程度?我寻找的前两件事是数据是否不完整或不正确。不完整的数据仅仅是指任何数据点丢失,不正确的数据是指数据点完全错误。为了减少不完整的数据,我通常会寻找缺失的值并明确定义范围。例如,如果 2021 年的数据还没有收集,我会在检查结果时明确说明这一点。

关于创业公司的可用信息从未如此之多。许多网站的整个价值主张是提供关于创业公司的数据。常见的数据点包括公司成立的年份、地点、创始人人口统计、融资轮次、融资金额等。这篇的文章强调了一项关于数据质量的研究。这进一步证实了我的观点,即所有数据都是脏的,尤其是在这个领域。每个数据点至少在不同方面略有偏差,因此我们将考虑使用这种类型的数据的一些含义。

  • 创始人人口统计

使用创始人的人口统计数据来预测成功可能是最糟糕的数据点,尤其是如果你使用任何黑盒分类器的话。有很多恐怖的故事说明为什么用人口统计来预测不是一个好主意。如果不明显的话,使用人口统计学会导致一个人口统计学被提升到另一个之上。使用这个作为输入意味着一个人口统计比另一个更好——这应该发出危险信号。

  • 资助金额

资金的多少可能是创业公司成功和失败的一个重要区别。然而,这有助于你预测他们未来的成功吗?绝对不行!投资者想在投资前知道谁会成功,而不是投资后——这使得这个数据点毫无用处。

  • 公司所在地

位置也可能预测成功,但与此相关的偏见是阶级不平衡。当一种类型的数据比另一种类型的数据有更多的例子时,就会出现类别不平衡。例如,一个地方比另一个地方有更多成功的创业公司。我来自纳齐兹小镇,女士。独角兽创业公司不太可能来自纳齐兹,但这就意味着不可能吗?还是那句话,绝对不行。然而,如果这个数据点暴露于一种算法,它 可能 了解到只有来自硅谷的公司才值得。

为什么我在最后一段突出了“may ”?用于这类任务(分类)的标准算法并不总是明确说明它们在数据集中发现什么是重要的。

分类算法

分类器是用于在对应于标签的一组数据中寻找模式的算法。分类算法已经存在了几十年,它们在分类方面非常出色。不幸的是,没有银弹解决方案,这就是为什么有这么多不同的分类器。例如,这是流行的 scikit-learn 工具箱中分类器的数量(这些是可以在几分钟内使用的!)

分类器有成千上万种,知道哪一种(如果有的话)适合手头的问题(和数据)是一门艺术和科学。选择分类器有两种标准做法。

  1. 数据科学家/ML 工程师知道哪些?
  2. 哪个精度最高?

这两个问题都没有回答它们是否是全局最佳算法。平心而论,这是一个不可能回答的问题。但是,这并不意味着所有的分类器都是一样的。作为这些方法的实践者,理解何时使用每种算法是至关重要的。当预测创业成功时,我看到的趋势是使用上面的两个问题来预测创业成功。虽然他们的解决方案是数据科学社区的标准,但我认为这个问题具有更高的标准,因为我不认为存在更好的解决方案。因此,我们应用两种不同于普通方法的实践来预测创业成功。我们不仅收集行为数据,而且我们还为这个问题开发了一个特定的分类器。我们不仅预测相当准确,而且我们还可以直接向投资者解释这些结果,做出切实可行的投资建议。

简单的规则

简单规则是我和迈克尔在过去几年里开发的一种算法。我们发现问题是:

找出导致公司成功(或失败)的创始人的行为特征。

我们的数据开始时是每位创始人 100 多项特质(或数据科学术语中的特征)与他们的成功相对应——我们最终减少到不到 10 项。标准分类器(来自 scikit-learn)可以学习哪些特征是重要的,但它们不能告诉我们它们是哪些。此外,他们无法以一种通俗易懂的方式解释每个功能对每个创始人的影响。所以,我们制定了简单的规则。简单规则是一个分类器,它学习如何对创始人和数据中的规则进行分类。

数据科学/人工智能专家提示:开发一个最终用户能够理解的分类器是物有所值的。

这很重要,因为我们有一个可以从两个层面解释的解决方案。首先,它对投资者是可解释的,因为与创始人相关的风险产生了(预测)。第二,这对于行为科学家来说是可以解释的,因为他们理解每种特质的影响(在全球层面上,并且对于特定的创始人来说)。简单规则学习模糊规则库,可以预测创始人的成功,同时还可以学习每个特征的影响。这意味着我们可以将从数据中学到的东西直接传递给最终用户。行为科学家现在明白了:

情绪稳定性低,那么成功就低。

你可能会问,为什么有人会关心特性呢?有了这些信息,行为科学家就可以将上下文应用到预测中。了解情绪稳定性在现实世界中的表现超出了任何人工智能的能力。尽管如此,领域专家可以有效地描述和发展这种特质,以减轻创始人给公司带来的风险。

结论

我们成功地创建了一个识别创始人及其成功潜力的流程。这个由两部分组成的解决方案涉及到使用行为数据和一个可解释的算法来预测和向最终用户(投资者和行为科学家)传递信息。我们的方法不仅是可解释的(我们可以突出任何偏见),而且由于数据的标准,它不容易受到其他解决方案所面临的偏见的影响。

如果你是一名数据科学家/ ML 工程师/ AI 爱好者,我希望这篇文章能启发你创建、突破和构建更好的解决方案来管理不确定的现实世界的数据。与领域专家交流是困难的,但它确实有助于打造值得构建的解决方案。能够产生更广泛影响的解决方案。

克服 AWS CodePipeline 的设计缺陷以自动化无服务器 ML 架构部署

原文:https://towardsdatascience.com/overcoming-aws-codepipelines-design-flaws-to-automate-serverless-ml-architecture-deployment-2c250ae5006a?source=collection_archive---------12-----------------------

构建一个简单的 CI/CD 管道,在 15 分钟内在 Amazon 上自动创建和部署 lambda 函数和相关的 SQS 队列。

照片由来自佩克斯的埃伯哈德·格罗斯加斯泰格拍摄

机器学习和数据科学需要无服务器应用。它们是轻量级的现收现付功能,可以减少为机器学习基础架构设置服务器或实例所花费的时间。AWS 通过 CodeCommit、CodeBuild、CodeDeploy 和 CodePipeline 使构建 CI/CD 管道变得更加容易。数据科学家可以花更少的时间在云架构和 DevOps 上,花更多的时间微调他们的模型/分析数据。此外,现收现付模式比支付云服务器/EC2 实例 24/7 运行来托管基础架构更便宜。

在本文中,我们将介绍如何使用 AWS 原生工具来构建 CI/CD 管道,以便将简单的机器学习模型部署为无服务器端点。该管道(使用 CodePipeline)从 CodeCommit 存储库中读取所有代码,并触发代码构建。此代码构建使用无服务器框架(一个用于 YAML + CLI 开发的软件包)将 CodeCommit 中的代码部署到 AWS Lambda 函数中。目标是每当我们对 CodeCommit 存储库进行更改时,触发 AWS Lambda 部署。

在开始之前

  • 这篇文章将涉及很多概念,可能你们中的很多人都不熟悉。请查看术语建议阅读了解更多详情。
  • 声明:由于 AWS Lambda 是轻量级的,它可能不适合庞大的深度学习模型。参见为什么我们不使用 Lambda 进行无服务器机器学习了解更多信息。
  • AWS Lambda 和无服务器通常可以互换使用。为了避免混淆,在讨论按需付费架构时,我将参考 AWS Lambda。当谈到用于部署 Lambda 的 CLI 工具时,我将参考无服务器框架。

术语

  • AWS SQS-简单队列服务。一种完全托管的消息队列服务,使您能够分离和扩展微服务、分布式系统和无服务器应用程序。
  • AWS SageMaker 通过整合一系列专为机器学习构建的功能,帮助数据科学家和开发人员快速准备、构建、训练和部署高质量的机器学习(ML)模型。用于独立于 AWS Lambda 部署 ML 模型。
  • AWS Lambda —一种无服务器计算服务,让您无需配置或管理服务器、创建工作负载感知集群扩展逻辑、维护事件集成或管理运行时即可运行代码。
  • 无服务器框架—用于 YAML + CLI 开发和部署到 AWS Lambda 的软件包。
  • AWS cloud watch——监控和观察工具。在日志中跟踪 Lambda 输出。

推荐阅读

要了解更多关于 AWS Lambda 的信息,我强烈推荐阅读无服务器函数和使用 AWS Lambda 和 S3 桶

要了解更多关于在无服务器框架中部署的信息,请参见无服务器框架文档

要了解 AWS 中的 CI/CD 和代码管道开发,我强烈推荐阅读 CI/CD-在 AWS 上构建四步管道的逻辑和实用方法

要了解更多关于 SageMakerSQS 的信息,请参见 AWS 上的文档。

体系结构

我使用 Codecraft 创建的无服务器架构图

以下步骤如下

  • 开发者在 SageMaker 上部署一个模型
  • 开发人员通过 git 更新包含架构逻辑的 CodeCommit 存储库
  • CodePipeline 通过 CloudWatch 注意到 CodeCommit 存储库中的一个变化。然后它触发 CodeBuild 在 AWS 中创建/更新、链接和部署所有 4 个服务(3 个 SQS 队列和 1 个 lambda 函数)。
  • 然后,开发人员从 TriggerLambdaSQS 发送一条消息。然后,这个 TriggerLambdaSQS 用输入数据触发 ModelPredictLambda 函数。Lambda 将使用 SageMaker 部署的模型。如果消息格式/lambda 中有错误,失败的消息将输出到 DeadletterSQS。如果 lambda 函数成功处理了消息,它将把 SageMaker 的结果输出到 CloudWatch 日志中。

为什么使用 CodeBuild 进行无服务器部署?AWS CodeDeploy 没有内置 Lambda 部署吗?

正确,CodeDeploy 允许 lambda 部署。对于 CodeCommit 的每次提交,您可以手动调用 CodeBuild,然后调用 CodeDeploy。我们希望通过 CodePipeline 自动化构建和部署阶段,而不用担心手动触发。

好吧,但是为什么不在 CodePipeline 中使用 CodeDeploy 呢?

在 CodeDeploy 中,在 lambda 函数上部署包不同于在 EC2 实例上部署包。在 lambda 函数上部署时,CodeBuild 只接受列出 lambda 部署配置的 YAML 文件,并将其存储在 S3 桶中。CodeDeploy 下载 YAML 文件并将其部署在 lambda 函数上。在 EC2 上部署时,CodeBuild 从 CodeCommit 获取所有文件,压缩它们,并将 zip 文件存储在 S3 桶中。CodeDeploy 在 EC2 上下载并解压缩文件。CodePipeline 指定从 CodeBuild 生成的工件必须为 zip 格式,才能传递给 CodeDeploy。这使得自动化 lambda 部署变得棘手,因为它依赖于 YAML 文件进行部署。这是 AWS 论坛中的一个已知问题,亚马逊承诺会修复这个错误。截至 2021 年,仍然没有更新。

解决方法是创建一个同时使用 CodeCommit 和 CodeBuild 的代码管道。在 CodeBuild 中,您安装所有包(包括无服务器框架)并运行无服务器框架来将应用程序部署到 AWS Lambda。由于您依赖于无服务器框架包而不是 CodeDeploy 进行部署,因此您需要创建一个名为 serverless.yml 的不同的 YAML 文件(不需要 appspec.yml ,这是 CodeDeployment 的默认 YAML 文件)。我们稍后会讨论更多。

教程

对于本教程,我们将使用 scikit-learn 的波士顿房价数据集。我们将训练一个 XGBoost 模型来预测波士顿的房价中值。我们将在 SageMaker 上部署模型,并在 AWS Lambda 架构中使用它进行预测。

创建文件夹结构

我们首先要创建一个名为 repo 的文件夹。这将包含同一级别的一个文件夹(lambda_deployment)和一个 Python 脚本(boston_sagemaker_deployment.py)。lambda_deployment 将包含在 CodePipeline 中成功部署 lambda 函数所需的所有相关文件。下面是文件的文件夹结构。

Visual Studio 代码中 REPO 的文件夹结构的屏幕截图

  • build spec . yml—YAML 格式的构建命令和相关设置的集合,CodeBuild 使用它来运行构建并使用无服务器框架进行部署
  • model _ predict _ lambda.py 为预测调用 SageMaker 模型的 lambda 函数
  • requirements.txt —从 pip 下载的 python 包列表
  • serverless.yml 定义无服务器服务的 YAML 配置。这还包括需要与 lambda 一起部署的附加组件(SQS)
  • Boston _ sagemaker _ deployment . py—使用 SageMaker 在 AWS 上构建和部署模型的脚本

创建并执行 SageMaker 脚本

第一件事是向 AWS 部署一个简单的 XGBoost 模型。注意:我们想要创建一个名为 sagemaker-role 的 IAM 角色,拥有访问 sagemaker 的完全权限。我不会深入讨论 XGBoost 的任何细节,因为这超出了本教程的范围。

之后,我们将执行脚本。

python boston_sagemaker_deployment.py

我们只需要做一次。这需要几分钟,但会给出成功或失败的信息。如果成功,它将为我们的模型返回一个端点。在 SageMaker AWS 控制台上检查端点是否在那里。

创建并上传 lambda_deployment 文件夹和文件到 CodeCommit

CodeCommit 是 Amazon 的源代码控制服务,托管安全的基于 Git 的存储库。我们将在那里上传 lambda_deployment 文件夹。我们可以使用 git 添加文件,也可以通过控制台手动添加。

lambda 部署中带有上传文件的 AWS 代码提交的屏幕截图

更新:CodeBuild 只识别 repo 头的文件,不识别 repo/lambda_deployment 头的文件。要解决这个问题,请将 lambda_deployment 中的所有 4 个文件移到 repo 的根目录。一旦这些被移动,删除其余的文件/文件夹。

为代码构建环境添加文件

CodeBuild 允许我们构建和测试持续扩展的代码。如前所述,我们还将使用无服务器框架在 CodeBuild 中部署 lambda 函数和服务。

我们将添加包含代码构建配置的 buildspec.yml,。因为我们使用一个干净的环境/映像,所以我们想要指定下载某些包所需的命令。这是假设一个干净的 Ubuntu 环境:

version: 0.2phases:
  pre_build:
    commands:
      - echo "Running pre build commands"
      - apt-get update
      - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7EA0A9C3F273FCD8
      - add-apt-repository "deb [arch=amd64] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) bionic stable"
      - apt-get -y install docker-ce docker-ce-cli containerd.io
      - npm install -g serverless --unsafe
      - npm i -D serverless-dotenv-plugin
      - npm install serverless-plugin-aws-alerts --save-dev
      - sls plugin install -n serverless-python-requirements
      - apt-get -y install python3-pip
      - pip3 install awscli --upgrade --user
      - pip3 install -r requirements.txt
      - echo "Reducing size of SageMaker to run on lambda"
      - pip3 install sagemaker --target sagemaker-installation
      - cd sagemaker-installation
      - find . -type d -name "tests" -exec rm -rfv {} +
      - find . -type d -name "__pycache__" -exec rm -rfv {} +
      - zip -r sagemaker_lambda_light.zip
      - cd .. build:
    commands:.
      - echo "Running build commands"
      - sls deploy --verbose
      - echo "Finished deploying to Lambda and SQS"

因为是干净镜像,所以我们负责安装 pip,awscli,serverless,docker 等。注意:lambda 对我们可以在函数上安装多少东西有一个限制。SageMaker 有很多依赖项,所以我们删除了 SageMaker 中与部署无关的组件。

prebuild 命令主要用于安装软件包,包括 requirements.txt 中的 pip3 软件包(如下所示):

boto3

现在我们有了 CodeBuild 命令,接下来我们想设置 serverless.yml 。yml 包含部署 lambda 函数和相关服务的配置,以触发函数、存储函数输出、发送阈值限制警报、记录函数行为等。该文件将如下所示。

service: model-predictpackage:
  include:
    - ./model_predict_lambda.pyprovider:
  name: aws
  runtime: python3.6
  iamRoleStatements:
    - Effect: "Allow"
      Action: 
        - "lambda:InvokeFunction"
        - "iam:GetRole"
        - "sqs:CreateQueue"
        - "sqs:GetQueueUrl"
        - "sqs:SendMessage"
        - "ecr:DescribeRepositories"        
        - "cloudformation:DescribeStacks"
        - "sagemaker:InvokeEndpoint" 
      Resource: "*"functions:
  get_model_predictions:
    handler: model_predict_lambda.model_predict_handler
    provisionedConcurrency: 1 # optional, Count of provisioned lambda instances
    reservedConcurrency: 1 # optional, reserved concurrency limit for this function. By default, AWS uses account concurrency limit
    events:
      - sqs:
          arn:
            Fn::GetAtt:
              - TriggerLambdaSQS
              - Arn
          batchSize: 1resources:
  Resources:
    TriggerLambdaSQS:
      Type: "AWS::SQS::Queue"
      Properties:
        QueueName: "TriggerLambdaSQS"
        VisibilityTimeout: 30
        MessageRetentionPeriod: 60
        RedrivePolicy:
          deadLetterTargetArn:
            "Fn::GetAtt":
              - DeadletterSQS
              - Arn
          maxReceiveCount: 1
    DeadletterSQS:
      Type: "AWS::SQS::Queue"
      Properties:
        QueueName: "DeadletterSQS"
        VisibilityTimeout: 30
        MessageRetentionPeriod: 60plugins:
  - serverless-python-requirements

这里有一个无服务器框架正在创造什么的简要概述

  • 名为的服务 model-predict ,它将封装 lambda 函数及其资源
  • lambda 函数所需的所有 python 文件的包(在这里是 model_predict_lambda.py
  • AWS 提供程序和分配给为此函数创建的 IAM 角色的权限
  • 一个名为 get_model_predictions,的 lambda 函数,它包含一个指向model _ predict _ lambda . py .中的 model_predict_handler 函数的处理程序,它还包含并发限制和对参考资料中列出的 SQS 队列的引用
  • 包含 TriggerLambdaSQSdeadletterqs 的资源部分。 TriggerLambdaSQS 是我们向 lambda 函数发送消息的地方。DeadletterSQS 包含在 lambda 中处理时失败的所有消息。添加了死信队列,以确保 TriggerLambdaSQS 不会保留失败的消息(这可能会被重新发送到 lambda 函数,并触发失败消息的连续循环,从而导致大量失败的 lambda 调用和价格飙升)

现在,我们想要创建 python 文件来存储 lambda 函数。

Lambda 函数调用 SageMaker 端点来获得预测

因为我们使用 SQS 来触发 Lambda 函数,所以我们处理的是异步事件队列。因此,我们遍历“Records”参数来处理队列中当前时刻的事件列表。现在,我们将打印出结果并返回一条成功的消息(当我们将 serverless.yml 中的 batchSize 设置为 1 时,该消息将立即被删除)。

创建代码构建

既然我们已经将 repo 上传到 CodeCommitt,那么让我们创建一个代码构建。导航到开发者工具- >代码构建- >构建项目。

AWS CodeBuild 仪表板的屏幕截图

从那里,点击橙色按钮,创建构建项目。

创建构建项目->项目配置的屏幕截图

让我们把这个项目命名为 serverless-build。然后,我们向下滚动以启动代码构建的源代码。

创建构建项目→源代码的屏幕截图

选择代码所在的适当分支。

接下来,我们将为构建配置环境。

创建构建项目→环境的屏幕截图

我们可以选择在 Amazon ECS 上使用定制的 Docker 图像,或者创建一个新的图像。我推荐使用 Ubuntu,因为它兼容很多机器学习库。因为我们之前没有为代码构建创建服务角色,所以我们将为帐户创建一个新的服务角色。

然后,我们将指定 buidspec 文件、批处理配置和工件。

创建构建项目→ Buidspec,批处理配置,工件的屏幕截图

Buildspec,我们已经在 repo 中定义了 buildspec.yml 文件。所以我们只要指向那个文件。工件是存储在 S3 的 zip 文件,从 CodeBuild 输出并发送到管道中的其他阶段。因为我们只是在构建步骤中使用无服务器进行部署,所以我们可以将其留空。

接下来,我们将实例化 CloudWatch 日志来监控代码构建过程。

创建构建项目→日志的屏幕截图

我们将所有内容留空,并选中“CloudWatch logs”复选框。最后,我们单击创建构建项目。

构建项目仪表板中服务器构建的屏幕截图

这样我们的构建项目就创建好了。我们可以点击开始构建橙色按钮,但我们可以让 CodePipeline 来处理。

向代码构建服务角色添加权限

还记得我们如何在 CodeBuild 中创建了一个名为code build-server less-build-service-role的新服务角色吗?虽然这会创建一个同名的新服务角色,但我们仍然需要为该角色添加权限,以便它可以访问我们架构中的其他 AWS 组件(Lambda、SQS、CloudFormation、CloudWatch 日志等)。在创建代码管道之前,请检查服务角色中是否添加了以下权限。

  • 亚马逊 QSFullAccess
  • IAMFullAccess
  • 亚马逊 3 完全访问
  • CloudWatchLogFullAccess
  • AWSLambdaSQSQueueExecutionRole
  • AWSCloudFormationFullAccess
  • AWSLambda_FullAccess

为 code build-server less-build-service-role 添加的策略和权限的屏幕截图

创建代码管道

代码管道在 CodeCommit 中监视 repo 。每当我们向 repo 添加提交时,它都会触发一个管道。这很方便,因为每当我们进行更改时,我们都会自动进行部署。导航到开发者工具- >代码管道- >管道。

代码管道仪表板的屏幕截图

点击橙色按钮创建管道。

创建新管道→选择管道设置的屏幕截图

我们现在可以为管道配置设置。在步骤 1 中,将管道命名为无服务器管道。因为我们之前没有为代码管道创建服务角色,所以我们将为帐户创建一个新的服务角色。其他一切使用默认值。使用高级设置的默认值,然后单击下一步。

创建新管道→添加源阶段的屏幕截图

我们现在添加管道的源阶段,它指向 CodeCommit 中的 repo 。使用默认值并选择分支,然后单击下一步。

创建新管道→添加构建阶段的屏幕截图

我们现在添加管道的构建阶段。我们将构建提供者设置为 CodeBuild,将项目名称设置为 serverless-build(这是我们之前创建的)。我们进行一次构建,然后单击下一步。

创建新管道→添加部署阶段的屏幕截图

因为我们没有添加 CodeDeploy 阶段(并且因为我们正在 CodeBuild 中进行无服务器部署),所以我们可以跳过这一步。单击跳过部署阶段。

创建新管道屏幕截图→查看

这只是在创建管道之前回顾所有的事情。看起来不错,所以让我们点击创建管道。

管道→无服务器-管道截图

我们的代码管道现在已经完成。这有源代码和构建阶段。源阶段为蓝色,因为它正在进行中。如果成功,它将是绿色的,如果失败,它将是红色的。一旦两个阶段都通过了,我们就可以开始测试我们的架构了。

测试架构

如果一切构建正确,我们应该看到 Lambda-> Function-> model-predict-dev-get _ model _ predictions 被创建。我们还应该看到创建了两个队列(DeadletterSQS 和 TriggerLambdaSQS)。

亚马逊 SQS 仪表板的屏幕截图,其中创建的队列来自 serverless.yaml

如果我们点击 TriggerLambdaSQS ->发送和接收消息,我们将看到一条可以发送给 lambda 函数的消息。让我们发送一个 JSON 格式来传入模型。

TriggerLambdaSQS →发送和接收消息的截图

这是我们在消息正文中发送的内容。

{ "payload": "14.0507,0,18.1,0,0.597,6.657,100,1.5275,24,666,20.2,35.05,21.22"}

点击 Send Message 后,我们导航到 cloud watch-> Log Groups->/AWS/lambda/model-predict-dev-get _ model _ predictions。我们获取最新的时间戳并检查日志。

CloudWatch 日志的截图,描述了 lambda 的输出

根据我们发送的输入,我们可以看到输出 75.875,它代表波士顿住房平均样本价格。

结论

我们讨论了如何在 AWS 中构建 CI/CD 管道来部署 lambda 架构。该架构包含用于触发/失败消息的 SQS 队列和将结果输出到日志的 CloudWatch。我们讨论了一种通过利用 CodeBuild 和无服务器部署框架来创建无服务器管道的变通方法。

我们还创建了一个脚本来利用 SageMaker 托管 XGBoost 模型。我们参考了 lambda 函数中的 SageMaker 端点,并根据 SQS 的输入预测了波士顿住房价格的中位数。我们可以在 CloudWatch 日志中看到预测。

AWS CodePipeline 使数据科学家更容易执行 MLOps。希望亚马逊可以修复 CodePipeline 中的错误,允许 YAML 文件在管道中的 CodeBuild 和 CodeDeploy 阶段之间传递。

注意:完成后一定要删除 SageMaker 端点

https://github.com/hd2zm/Data-Science-Projects/tree/master/Medium/Serverless_CI_CD

感谢阅读!如果你想阅读更多我的作品,请查看我的目录。

如果你不是一个中等收入的会员,但对订阅《走向数据科学》感兴趣,只是为了阅读这样的教程和文章,点击这里注册成为会员。注册这个链接意味着我可以通过向你推荐 Medium 来获得报酬。

利用基于代理的模型克服复杂性

原文:https://towardsdatascience.com/overcoming-complexity-with-agent-based-models-5c4cca37cc61?source=collection_archive---------19-----------------------

复杂系统

基于代理的模型初学者指南:它们如何工作和做什么

Unsplash 上由 James Wainscoat 拍摄

这是一个晴朗的秋日下午。

你坐在长椅上享受着一天中最后一缕温暖的阳光。

在远处你可以看到一大群鸟。他们正在表演艺术舞蹈,在空中画出令人印象深刻的图形。

你可能会开始怀疑:这是怎么回事?整个鸟群的运动如此复杂,它们是如何从每个个体的行为中浮现出来的?

在我们的日常生活中,我们被复杂的系统所包围。复杂系统是一个由许多部分相互作用、相互影响的系统。一个例子是大城市的交通。汽车相互碰撞,这可能导致事故或交通堵塞。交通灯、人行横道和建筑工地与汽车相互影响。它们可能会影响交通的流向和地点。一个交通灯周期的微小变化可能对大范围内的交通流量产生重大影响。

如果我们想写下一个方程式来计算某条街道的交通流量,这几乎是不可能的。很难将所有的相互作用纳入分析方程。然而,每辆车的行为很容易建模。它根据前面的汽车和交通标志遵守严格的规则。如果我们能够精确地模拟城市中的一些单独的汽车,我们就可以预测交通标志的变化在高峰时间的某一点会产生什么影响。

这就是基于主体的建模思想。

在这篇文章中,我们将探索基于代理的模型是什么,它们是如何工作的,以及它们是如何建立的。

对于一个动手的例子,你可以看看这个关于一个基于代理的疫情模型的帖子:

基于代理的模型的目标是什么?

通过一个基于主体的模型,我们旨在模拟一个复合的、自浮现的行为。系统的动态太复杂,无法在全局范围内描述,但在局部范围内很容易理解。对于一个城市的高峰时间交通,很难将所有的相互作用作为一个整体来描述。然而,我们很好地掌握了赛车在这个系统中遵循的具体规则。同样,把一整群鸟的形状放进一个等式也很难。但是凭直觉,我们可以粗略地描述一只鸟可能遵循的规则。

晒帕尔Unsplash 上的照片

能够精确地模拟一个复杂的系统可能会改变游戏规则。如果我们有一个城市交通的模型,我们可以研究限速的变化如何影响高峰时间的交通堵塞。基于此,我们可以找到各种情况下的最佳策略。拥有病毒感染传播的准确模型可以帮助决策者找到适当的措施。我们可以研究关闭学校或取消航班是否能有效阻止疾病的传播。

基于主体的模型不仅在调查外部干扰对系统结果的影响方面有用。他们也可以帮助理解可能导致特定自我浮现行为的基本原则。对于复杂系统中出现的某种动态,必须满足特定的条件。在我们的模拟中,我们可以通过将模拟的动态与现实进行比较来隔离这些条件。例如,通过模拟个人的社会行为,我们可以研究利他主义和合作可能出现的条件。

基于代理的模型的基本要素

大多数基于代理的模型都有相似的核心结构和几个必要的组件。

首先我们需要代理。代理是模型中个体的基本类型。这些可能是交通模型中的汽车司机、金融市场模型中的交易员、群体模拟中的鸟类、网络模型中的数据包、森林生长模拟中的树木或细胞自动机中的细胞。基于代理的模型可以由几种类型的代理组成。例如,生态系统的模拟可以模拟植物和动物。交通模拟可以将汽车和行人视为代理。

典型地,代理有某些属性来描述他们当前的状态。我们的鸟群模型中的鸟可能有位置和速度。疫情模型中的个体应该具有某种健康状态。代理的属性集试图只表示所需行为所必需的信息。在建立疫情模型时,个人的年龄或社会地位可能是一个值得考虑的属性。然而,个人的鞋码可能不是直接感兴趣的。大量属性可能会给模拟带来异构性,同时增加其复杂性。这是一个需要管理的权衡。

最重要术语的概述。由作者创建的图形。

基于代理的模型的关键部分是代理之间的交互。为此,代理需要一个特定的更新方案,一组在与其他代理交互时如何更新其状态的规则。在交通模拟的情况下,这可能意味着如果当前代理前面的汽车太靠近,就要刹车并减速。与互动相关的一个重要概念是邻居。

邻域定义了代理与之交互的组。对于鸟群模拟,鸟的邻域可能是离它最近的鸟。在疫情模式中,可能是一群朋友和同事。有几种方法可以在基于代理的模型中实现邻域。最简单的方法之一是在网格上排列代理,并允许代理与 4-/或 8-邻域交互,这意味着网格上 4 或 8 个最近的代理。通常这已经是引入空间异质性的合理方式。

最后,我们想要定义一些可观察的,或度量,量化我们模拟的行为。在交通模拟的情况下,这可能是特定点的交通流量。对于疫情模型,我们可能对任何给定时间点的感染人数感兴趣。

这一切是如何协同工作的

照片由 Xavier von ErlachUnsplash 上拍摄

我们发现,对于基于代理的模型,我们需要具有属性的代理以及代理之间的交互。此外,我们需要一组指定如何更新代理状态的更新规则。现在,我们想知道如何将这些成分放在一起,根据我们的模型进行模拟。

基于代理的模型是随时间变化的动态模型。为了模拟这种行为,我们将模拟运行为一系列离散的时间步长

时间步长是模拟中最小的进度步长。在每个时间步中,代理及其邻域的状态可以根据指定的规则进行更新。请注意,时间步长不一定代表时间,但可以解释为整个动力学中的进展步长。

这些渐进步骤的大小应该根据你所期望的动态来合理选择。如果我们想模拟交通堵塞,一分钟的时间步长可能太长了,因为如果交通灯变成红色,司机需要在几秒钟内做出反应。对于模拟疫情来说,秒的时间步长可能太精细了,因为动力学是在天的尺度上发生的。

在模拟的最开始,我们需要为代理的属性和邻域设置初始值。模拟的结果可能很大程度上取决于代理的初始状态。因此,用不同的初始化运行几个实验通常是有用的。这一程序使我们能够量化模拟中涉及的一些不确定性。

一个典型的基于 agent 模型的工作流。由作者创建的图形。

开始简单

当构建基于代理的模型时,模型的复杂度应该尽可能低。同时,它需要尽可能高,以实现所需的动态特性。如果模拟有太多的超参数,可能很难调整它们以获得所需的动态特性。当构建交通模拟时,我们不会开始模拟所有不同种类的汽车和卡车。我们宁愿从尽可能简单的开始,找出一个最小的设置,导致最基本的动力学。

从简单开始的一个优点是,对于一个简单的设置,可能存在一个解析解。为了模拟疫情,我们可能希望从一组同质的个体开始。在每个时间步,他们中的每一个都有一定数量的随机触点。每次接触都有被感染的可能。在这种情况下,产生的动力学也可以通过一组微分方程来建模。这就是所谓的 SIR 模型,它有一个众所周知的解析解。我们可以使用这个解决方案作为基准来验证我们的简单模型,然后进一步增加复杂性。

照片由 蒂姆·莫斯霍尔德 发自 派克斯

假设混合良好的同质个体具有随机相互作用的设置被称为平均场近似。这是传染病模型或社会行为的一种常见近似。在这种特殊情况下,我们通常可以将系统描述为一个整体,而不需要考虑每个个体。这通常允许找到直接的解析解。如果我们把交通模拟简化到足够的程度,我们可以用一个抽象的交通流来描述动态,而不是分别考虑每辆车。这些类型的近似是我们模拟的重要锚点。它允许我们将基于代理的观点与整个系统的描述联系起来。

添加异构性

顾名思义,平均场近似只是一种近似。最终,我们对更复杂的行为感兴趣。基于代理的模型的全部要点是我们想要考虑单个代理。我们不想对系统进行全局描述。因此,从一个简单的模型开始,我们需要增加复杂性,或者异构性。这可以通过多种方式实现。

通过考虑更多不同的个体,可以将异质性引入系统。在疫情模拟中,我们可以开始为代理添加年龄分布,并根据代理的年龄更改更新规则。对于交通模拟,我们可能想要引入具有不同加速速度的不同类型的汽车和具有不同驾驶风格的不同驾驶员。

可以引入异质性的另一个要点是交互。从混合良好的随机互动,我们可以实现一个社会结构到行为模型。如果代理与随机联系人合作,或者总是与同一组联系人合作,通常会产生巨大的差异。

例如,在博弈论中,自私个体之间合作的出现是一个长期存在的问题。很难用一个混合均匀的社会的平均场近似来解释。然而,通过给代理人群体增加一个社会结构,自我维持的合作者群体可能会出现。

模型的复杂性是一个需要考虑的重要属性。大多数时候,我们无法在一对一的环境中模拟现实。我们需要做出假设和近似。建立一个成功的基于主体的模型的关键是仔细考虑模拟中需要实现的细节和可以省略的细节。

检验和确认

任何模型的一个重要部分是适当的确认和验证。我们已经讨论过,从一个可能存在解析解的简单案例开始,是验证模型总体设置的一个很好的方法。对于更复杂的模型,我们需要将模型与真实世界的数据进行比较。构建有意义的指标在这一过程中起着关键作用。例如,对于鸟群模拟,我们可以跟踪鸟类之间的平均距离,并将其与真实世界的观察结果进行比较。在交通模拟的例子中,我们可以在模拟和真实世界数据之间的某些点比较交通流量。

在现实世界中观察到的自浮现行为的发生也可以用于验证模型。观察高交通流量的交通堵塞将是交通模拟中的期望结果。

结论

基于主体的模型提供了通过分别模拟每个个体来描述复杂行为的可能性。难以全面描述的问题通常可以在参与实体的级别上进行局部描述。在模拟的帮助下,我们可以对全球行为进行建模。

基于主体的模型在从生物学、流行病学、经济学、社会科学、博弈论到网络和通信理论的广泛领域都有应用。基于代理的模型通常由一组具有特定属性的代理、一组更新规则和交互组成。在许多模型中,每一个代理的邻居,也就是交互作用发生的地方,在系统的动态中扮演着重要的角色。

尽管基于代理的模型在克服复杂性方面取得了成功,但在许多领域,它们仍然只是填补了一个空白,并且通常还不被认为是标准方法。我希望这篇文章能启发你解决复杂性问题,并自己建立一个基于代理的模型!

如果你有兴趣进入贝叶斯数据分析的世界,看看下面的帖子:

利用 TensorFlow 数据服务、NVIDIA DALI 和其他方法克服数据预处理瓶颈

原文:https://towardsdatascience.com/overcoming-data-preprocessing-bottlenecks-with-tensorflow-data-service-nvidia-dali-and-other-d6321917f851?source=collection_archive---------12-----------------------

理解大数据

最大限度地提高培训资源利用率,加速学习,节省资金

你能找到瓶颈吗?由维斯瓦纳特·穆达达Unsplash 上拍摄

在前一篇帖子中,我谈到了剖析 DNN 培训课程运行时性能的重要性,这是充分利用您的培训资源、加速您的培训并节省资金的一种方式。我描述了一个典型的培训管道(见下图),回顾了一些潜在的性能瓶颈,并调查了一些可用于识别这些瓶颈的工具。在这篇文章中,我想阐述一个更常见的性能瓶颈,CPU 瓶颈,以及克服它的一些方法。更具体地说,我们将讨论数据预处理管道中出现的瓶颈,以及克服它们的方法。

在这篇文章的上下文中,我们将假设我们正在使用 TensorFlow ,具体来说就是 TensorFlow 2.4 ,在 GPU 设备上训练一个图像处理模型,但是内容大部分都与其他训练框架、其他类型的模型和其他训练加速器相关。

样本培训渠道(按作者)

数据预处理瓶颈

当由于一个或多个 CPU 达到最大利用率而导致 GPU 资源利用不足时,就会出现 CPU 瓶颈。在这种情况下,GPU 在等待 CPU 传入训练数据时将部分空闲。这是不希望的状态。因为 GPU 通常是系统中最昂贵的资源,所以你的目标应该是最大化它的利用率。在不涉及太多技术细节的情况下,当在 CPU 上执行的数据预处理的“量”与模型在 GPU 上执行的计算的“量”之间的比率大于整体 CPU 计算能力与整体 GPU 计算能力之间的比率时,通常会出现 CPU 瓶颈。例如,如果您的 CPU 核心和 GPU 都得到最大限度的利用,然后您升级到更强大的 GPU,或者降级到具有更少 CPU 核心的系统,您的训练运行时性能将受到 CPU 的限制。

很自然,您的第一反应会是简单地切换到一台 CPU 与 GPU 计算比率更合适的机器。但是,可悲的是,我们大多数人都没有这种自由。虽然云服务,如亚马逊 SageMaker ,提供了各种训练实例类型,具有不同的 CPU-计算与 GPU-计算比率,但你可能会发现它们都不太适合你的特定需求。

假设您被现有的系统所困扰,您可以采取哪些措施来解决您的性能瓶颈并加快培训?

在接下来的部分中,我们将提出解决预处理数据瓶颈的四个步骤。

  1. 确定任何可以转移到数据准备阶段的操作
  2. 优化数据预处理流水线
  3. 在 GPU 上执行一些预处理步骤
  4. 使用 TensorFlow 数据服务将一些 CPU 计算卸载到其他机器上

为了方便我们的讨论,我们将基于 Resnet50 构建一个玩具示例。

示例使用案例

在下面的代码块中,我使用 TensorFlow 的内置 Resnet50 应用程序构建了一个模型。我添加了一个相对较重的数据预处理管道,包括膨胀、模糊过滤和一些张量流预处理层。(参见文档了解使用此类层的优势。)

**import** **tensorflow** **as** **tf
import** **tensorflow_addons** **as** **tfa
from** **tensorflow.keras.applications.resnet50** **import** **ResNet50**
**from** **tensorflow.keras.layers.experimental** **import** **preprocessing****def** get_dataset(batch_size):
    *# parse TFRecord*
    **def** parse_image_function(example_proto):
        image_feature_description = 
           {'image': tf.io.FixedLenFeature([], tf.string),
            'label': tf.io.FixedLenFeature([], tf.int64)}
        features = tf.io.parse_single_example(
                      example_proto, image_feature_description)
        image = tf.io.decode_raw(features['image'], tf.uint8)
        image.set_shape([3 * 32 * 32])
        image = tf.reshape(image, [32, 32, 3])
        label = tf.cast(features['label'], tf.int32)
        **return** image, label *# dilation filter*
    **def** dilate(image, label):
        dilateFilter = tf.zeros([3, 3, 3], tf.uint8)
        image = tf.expand_dims(image, 0)
        image = tf.nn.dilation2d(
                    image, dilateFilter, strides=[1, 1, 1, 1],
                    dilations=[1, 1, 1, 1],
                    padding='SAME', 
                    data_format='NHWC')
        image = tf.squeeze(image)
        **return** image, label *# blur filter*
    **def** blur(image, label):
        image = tfa.image.gaussian_filter2d(image=image,
                            filter_shape=(11, 11), sigma=0.8)
        **return** image, label *# rescale filter*
    **def** rescale(image, label):
        image = preprocessing.Rescaling(1.0 / 255)(image)
        **return** image, label *# augmentation filters*
    **def** augment(image, label):
        data_augmentation = tf.keras.Sequential(
           [preprocessing.RandomFlip("horizontal"),
            preprocessing.RandomRotation(0.1),
            preprocessing.RandomZoom(0.1)])
        image = data_augmentation(image)
        **return** image, label autotune = tf.data.experimental.AUTOTUNE
    options = tf.data.Options()
    options.experimental_deterministic = **False**
    records = tf.data.Dataset.list_files('data/*', 
                            shuffle=**True**).with_options(options)
    *# load from TFRecord files*
    ds = tf.data.TFRecordDataset(records, 
                 num_parallel_reads=autotune).repeat()
    ds = ds.map(parse_image_function, num_parallel_calls=autotune)
    ds = ds.map(dilate, num_parallel_calls=autotune)
    ds = ds.map(blur, num_parallel_calls=autotune)
    ds = ds.batch(batch_size)
    ds = ds.map(rescale,num_parallel_calls=autotune)
    ds = ds.map(augment, num_parallel_calls=autotune)
    ds = ds.prefetch(autotune)
    **return** ds**if** __name__ == "__main__":    
    model = ResNet50(weights=**None**,
                     input_shape=(32, 32, 3),
                     classes=10)
    model.compile(loss=tf.losses.SparseCategoricalCrossentropy(),
                  optimizer=tf.optimizers.Adam())
    dataset = get_dataset(batch_size = 1024)
    model.fit(dataset, steps_per_epoch=100, epochs=10))

原始数据输入存储在 TFRecord 文件中,这些文件是我从 CIFAR-10 数据集创建的,(使用这个脚本)。

我创建这个例子是为了人为地制造一个性能瓶颈。在任何情况下,我都不建议在实际训练中使用它。

所有测试都是在使用亚马逊深度学习 AMI亚马逊 ec2 p2.xlarge 实例类型上运行的。

识别瓶颈

有许多不同的工具和技术可用于评估培训会话的运行时性能,以及识别和研究输入管道瓶颈。让我们回顾一下其中的几个:

系统度量

首先要检查的是系统资源利用率。有许多不同的方法可以做到这一点。Linuxtop命令显示 CPU 利用率。要查看每个 CPU 内核的利用率,请在 top 运行时键入‘1’。要衡量 GPU 利用率,可以使用 nvidia-smi 。在亚马逊 EC2 培训时,可以使用亚马逊 CloudWatch 来监控系统指标。虽然默认情况下不包含 GPU 指标,但是您可以使用GPU on 实用程序来添加这些指标。下面是几个不同实验中捕获的 CPU 和 GPU 利用率的示例图。

亚马逊 CloudWatch 中的性能指标(按作者)

在我们上面介绍的用例中,报告的平均 GPU 利用率在长时间空闲时不到 50%。同时,CPU 的利用率很高,一些内核达到了最大利用率。

性能分析器

要深入到下一个细节层次,了解培训是如何进行的,您可以使用一个性能分析器。

TensorFlow Profiler: 内置的 TensorFlow profiler 包括丰富的性能分析,特别是用于分析输入管道性能的工具。您可以通过安装 TensorBoard profile 插件来查看使用 TensorBoard 的情况。启用 profiler 的一种方法是使用 TensorBoad 回调对训练循环进行编程。

*# program the callback to capture steps 20-24*
cb = tf.keras.callbacks.TensorBoard(
        log_dir='/tmp/profile', profile_batch='20,24',
        histogram_freq=0, write_images=**False**)
model.fit(dataset, steps_per_epoch=100, epochs=10, callbacks=[cb])

下面是我们用例的概要分析页面,其中数据输入瓶颈非常明显。

tf profiler —概览页面(作者使用 TensorBoard)

trace-viewer 工具允许您深入到管道执行的细节,并研究 CPU 和 GPU 之间的数据流。在我们的示例中,由于数据输入瓶颈,您可以清楚地看到 GPU 长时间空闲。

tf profiler — trace-viewer(作者使用 TensorBoard)

Amazon SageMaker 调试器:如果您正在 Amazon SageMaker 环境中进行培训,您可以利用内置于 Amazon SageMaker 调试器中的分析特性。下面是一个输入管道中的严重瓶颈如何出现在 Amazon SageMaker Studio 中的例子。

亚马逊 SageMaker Studio 中的资源利用(按作者)

Linux 概要分析器:通用的 Linux 性能概要分析器通常也有助于分析训练瓶颈。例如,使用 Linux perf 实用程序,我们能够看到我们的 CPU 在一个内部线性代数函数上花费了大量时间:

Linux 性能捕获(按作者)

吞吐量测量

既然我们分析的目标是加速训练运行时间,那么很自然地我们会使用这个指标来衡量我们的表现。

在我们的例子中,我们将使用单个(100 步)时期的平均运行时间作为我们的主要性能度量,并测量模型的不同变化如何影响这个值。上述模型单个历元的平均运行时间为 122 秒

如果没有数据输入瓶颈,测量运行时的一个有用技术(这里描述为)是缓存第一个处理的输入批,并对所有后续步骤使用相同的缓存批。这实质上关闭了预处理流水线,并使我们能够计算理想的纪元运行时间。

为了实现这一技术,我们只需在数据集创建结束时添加以下代码行:

ds = ds.take(1).cache().repeat()

通过将这种技术应用到我们的例子中,我们能够将运行时间减少到 58 秒。换句话说,如果不是因为数据输入的瓶颈,我们可以将训练速度提高两倍以上。

在接下来的部分中,我们将介绍一些解决输入管道瓶颈的建议步骤。我们将在我们的玩具示例中演示一些步骤,记住我们刚刚计算的目标运行时间,每个时期 58 秒

将操作放在数据准备阶段

为了解决数据预处理瓶颈,要做的第一件事是识别任何可以优先进入原始数据记录创建阶段的操作。我们进入数据创建阶段的操作越多,我们就越能在训练期间释放 CPU 周期。以确定性方式(没有随机成分)、不依赖于超参数并且不会过度增加数据大小的任何操作都是优势的良好候选。在我们的玩具示例中,膨胀操作(假设它不依赖于超参数)符合这个标准。因此,我们要做的第一件事是停止膨胀操作,并假设 TFRecords 包含已经经过适当膨胀的图像数据。

在我们的具体实现中,模糊过滤器可能也是优势的良好候选,但由于在大多数情况下,模糊是随机应用的,我们将把它留在这里。

通过去除膨胀操作,我们的运行时间减少到每个时期 115 秒。这比我们的起始值每周期 122 秒要小,但是要达到我们的目标每周期 58 秒我们还有很长的路要走。

需要注意的一点是,某些操作可能会更改数据记录的大小,因此可能会影响数据集的整体大小以及训练期间的网络流量(如果训练集是远程存储的)。如果您选择优先处理那些会过度增加数据大小的操作,您可能会冒用一个瓶颈替换另一个瓶颈的风险,即网络 IO 或数据加载瓶颈。

优化数据预处理管道

一旦我们将尽可能多的操作转移到数据创建阶段,第二步就是确定优化剩余管道性能的方法。

流水线调整

通常,对输入管道设置进行一些小的调整可以降低性能开销。以下是一些你可以尝试的事情:

  1. 如果您有多个相对较小的数据集映射函数,请考虑将它们组合成一个映射函数。
  2. 相反,如果您有一个非常大的数据集映射函数,可以考虑将它分成两个或更多的小函数,以便更好地利用内置的并行调用支持。
  3. 寻找可以在批处理后应用的操作,而不是每个记录。(在我们的示例中,模糊函数理论上可以应用于训练批次,但由于它通常以随机方式应用,因此我们将保留每个记录的模糊函数。)
  4. 尽可能使用低精度类型。推迟铸造到更高的精度到管道的末端。
  5. 如果您的管道包含 tf.numpy_functiontf.py_function ,请考虑改用 TensorFlow 原语。

CPU 优化和扩展

确保您的 TensorFlow 二进制文件被配置(和编译)为充分利用您的 CPU 和 CPU 扩展。例如,如果您使用现代 x86 ISA CPU,(如 Intel 或 AMD),请确保使用经过优化的 TensorFlow 二进制文件,以使用 CPU 的高级矢量扩展(如 AVX2 )。总的来说,英特尔提供了各种各样的二进制文件,专门针对在英特尔 CPU 上运行进行了优化,包括英特尔至强TensorFlow-mkl

请注意,使用基于云的解决方案进行培训的优势之一是,云学习环境(大概)被配置为充分利用云系统资源。

CPU 负载平衡

当您在多 CPU 内核系统中遇到 CPU 瓶颈时,您可能会发现,虽然一个或多个 CPU 内核处于完全利用状态,但其他内核却没有。这其实挺常见的。您可以尝试的一件事是改善 CPU 之间的负载平衡,从而提高整体 CPU 利用率。您可以尝试使用TF . config . set _ logical _ device _ configurationAPI 将 CPU 计算分成多个逻辑设备,并使用 tf.device API 指定每个操作应该在哪里运行。您还可以尝试通过使用 tf.data.Dataset.map 函数的 num_parallel_calls 参数的不同选项来改善负载平衡,(而不是依赖 TensorFlow 的自动调优功能)。在任何情况下,请记住,这可能是一个乏味的、令人痛苦的工作,即使对您的模型进行最轻微的更改,也可能需要重新计算负载平衡。

将操作卸载到 GPU

在我们的例子中,您可能会发现,即使您已经尝试了所有将操作放在数据创建阶段并优化 CPU 代码的方法,您仍然会面临数据预处理瓶颈。下一个要考虑的选项是通过将一些预处理操作转移到 GPU 上来修改 CPU 和 GPU 之间的负载平衡。这种方法的缺点是,我们几乎肯定会增加 GPU 步骤的运行时间。此外,由于我们正在增加 GPU 上运行的计算图形的大小,我们可能需要通过运行较小的批处理来释放一些 GPU 内存。因此,我们很可能无法实现上面计算的目标吞吐量。但是如果它减少了总的火车时间,那么它是完全值得的。让我们探索几种将预处理操作卸载到 GPU 上的方法。

将预处理操作推迟到 GPU

在大多数情况下,减轻 CPU 负担的最佳方式是将预处理管道末端执行的操作转移到 GPU。通过瞄准这些“尾部”操作,而不是流水线中间的操作,我们避免了 GPU 和 CPU 之间的数据传输开销。如果“尾部”操作是在模型输入上执行的,我们可以将它们放在模型的头部。如果它们是在标签数据上执行的,我们可以在应用实际损失之前修改我们的损失函数来执行这些操作。

在我们的示例中,我们已经从输入管道中移除了增强,而是将它们应用于 GPU 计算图的开头:

data_augmentation = tf.keras.Sequential(
        [preprocessing.RandomFlip("horizontal"),
         preprocessing.RandomRotation(0.1),
         preprocessing.RandomZoom(0.1)])inputs = tf.keras.Input(shape=(32, 32, 3))
*# Augment images*
x = data_augmentation(inputs)
*# Add the rest of the model*
outputs = tf.keras.applications.ResNet50(weights=**None**,
                      input_shape=(32, 32, 3), classes=10)(x)
model = tf.keras.Model(inputs, outputs)

通过应用这一改变,我们能够将运行时间减少到每个时期 108 秒。

tf.device

通过用一个TF . device('/device:GPU:0 ')语句包装操作,我们可以强制某些操作在 GPU 上运行。这种方法的缺点是,它需要在 GPU 设备之间来回传输数据。

在我们的例子中,我们选择将这种技术应用于模糊函数,修改如下:

**def** blur(image, label):
    **import** **tensorflow_addons** **as** **tfa**
    **with** tf.device('/device:GPU:0'):
        image = tfa.image.gaussian_filter2d(image=image,
                           filter_shape=(11, 11), sigma=0.8)
        **return** image, label

当以这种方式在 GPU 上运行模糊功能时,同时将增强功能留在 CPU 上,我们获得了 97 秒的纪元运行时间。当结合两种技术时,epoch 运行时间是 98 秒

使用 TensorFlow profiler trace-viewer,我们可以看到 tf.device 技术如何增加 CPU 和 GPU 之间的数据流量:

使用 tf.device 卸载到 GPU—TF profiler 跟踪查看器(作者使用 TensorBoard)

通过将本实验中突出显示的流与上面 trace-viewer 捕获中的相同流进行比较,我们看到进出 GPU 的内存拷贝明显更多。我们还看到,GPU 要活跃得多。

验证模糊函数确实在 CPU 上运行的另一种方法是设置TF . debugging . set _ log _ device _ placement(True)。您可以运行这个示例,在 CPU 上使用模糊函数运行一次,在 GPU 上使用模糊函数运行一次,看看它如何影响日志设备放置例程的输出。

女娲大理

NVIDIA DALI是一个用于构建高度优化的预处理管道的框架。特别是,使用 NVIDIA DALI,您可以对部分管道或整个管道进行编程,以在 GPU 上运行。DALI 管道由 DALI 运营公司建造。DALI 附带了一个支持的操作列表,以及用于创建定制操作的 API。使用 TensorFlow DALI 插件,DALI 管道可以用符合 tf.data.Dataset API 的 DALIDataset 包装,如此处所示。此外,DALI 支持从 TFRecord 文件加载,如下图所示。不幸的是,在撰写本文时,对 DALI 的文档支持仅限于版本 1 兼容的 TensorFlow 。(那些读过我以前博客的人,应该已经知道我对使用遗留代码的感受。)另外,NVIDIA DALI 是为 NVIDIA GPUs 设计的。它不会在其他机器学习加速器上运行。另一个考虑是分布式培训。虽然 DALI 确实支持多 gpu 训练,但根据您实现分布式训练的方式(例如,使用 HorovodTensorFlow 分布策略,使用 model.fit() 或自定义训练循环),集成 DALI 管道会在稍微困难和困难得多之间变化。如果你对使用最新的 TensorFlow 功能有强烈的感觉,或者如果你希望你的代码与其他加速器兼容,( AWS TraniumHabana GaudiTPU 等。),或者如果将您的管道转换为 DALI 操作需要大量工作,或者如果您依赖于高级 TensorFlow 分布式培训 API,NVIDIA DALI 可能不是您的正确解决方案。

使用 DALI 需要使用 TensorFlow DALI 插件 python 包。安装步骤见文件。在下面的代码块中,我展示了如何将管道从我们的用例转换到 NVIDIA DALI。我省略了一些随机的扩充,因为没有内置的、相应的 DALI 操作。

**from** **nvidia.dali.pipeline** **import** **Pipeline**
**import** **nvidia.dali.ops** **as** **ops**
**import** **nvidia.dali.types** **as** **types**
**import** **nvidia.dali.tfrecord** **as** **tfrec**
**import** **nvidia.dali.plugin.tf** **as** **dali_tf**
**import** **tensorflow.compat.v1** **as** **tf**
tf.disable_eager_execution() **class** **TFRecordPipeline**(Pipeline):
    **def** __init__(self, batch_size, num_threads,
                 device = 'cpu', device_id = 0):
        super(TFRecordPipeline, self).__init__(batch_size,
                                         num_threads,
                                         device_id)
        self.input = ops.TFRecordReader(
             path = ['data/train0.tfrecords'],
             index_path = ['index/train0'],
             features = {
              "image": tfrec.FixedLenFeature((), tfrec.string, ""),
              "label": tfrec.FixedLenFeature([], tfrec.int64,  -1)})
        self.decode = ops.Cast(device=device,dtype=types.UINT8)
        self.reshape = ops.Reshape(device=device,
                                   shape=[32, 32, 3])
        self.cast = ops.Cast(device=device,
                             dtype=types.DALIDataType.INT32)
        self.blur = ops.GaussianBlur(device=device,
                                     window_size=11,sigma=0.8)
        self.iter = 0 **def** define_graph(self):
        inputs = self.input()
        images = self.decode(inputs["image"].gpu())
        images = self.reshape(images)
        images = self.blur(images)/255.
        labels = self.cast(inputs["label"].gpu())
        **return** (images, labels) **def** iter_setup(self):
        **pass** **if** __name__ == "__main__":
    batch_size = 1024
    shapes = ((batch_size, 32, 32, 3),
              (batch_size))
    pipe = TFRecordPipeline(batch_size=batch_size, 
                            num_threads=4, 
                            device='gpu', 
                            device_id=0) **with** tf.device('/gpu:0'):
        *# Create dataset*
        ds = dali_tf.DALIDataset(
            pipeline=pipe,
            batch_size=batch_size,
            output_shapes=shapes,
            output_dtypes=(tf.float32, tf.int32),
            device_id=0)
        model = tf.keras.applications.resnet.ResNet50(
                   weights=**None**, 
                   input_shape=(32, 32, 3), 
                   classes=10)
        model.compile(
             loss=tf.keras.losses.SparseCategoricalCrossentropy(),
             optimizer=tf.keras.optimizers.Adam())
        model.fit(ds, steps_per_epoch=100, epochs=10)

我在 TensorFlow 2.3 中运行脚本(看起来,在撰写本文时,DALI 还没有更新到支持 TensorFlow 2.4)。一个 100 步的时间的结果运行时间是 77 秒。虽然这个试验没有包括增强功能,但是很明显 DALI 提供了显著的运行时改进的潜力。

正如我上面提到的,将操作卸载到 GPU 可能需要释放一些内存来减少训练批次的大小。事实证明,这在我们的玩具示例中是不需要的。(这可能意味着我们可以从更大的批量开始。)这一发现不一定适用于其他模型,尤其是如果你要确保最大化你的 GPU 内存和批处理大小。

将数据预处理卸载到其他机器上

我们探索的最后一个选项是将一些预处理活动卸载到其他机器上。我们将把预处理计算转移到辅助机器的 CPU 核心上,而不是转移到 GPU 上。我们将使用相对较新的 TensorFlow 数据服务功能来探索这种方法。在 TensorFlow 版本 2.3 中引入,TF . data . experimental . service提供了用于定义执行数据预处理的专用工作机的 API。一个调度服务器负责将预处理任务分配给一个或多个工作服务器,每个工作服务器直接从存储器中加载原始数据,并将处理后的数据发送给 GPU 设备。通过将TF . data . experimental . service . distribute应用到您的数据集,您可以对数据集进行编程,以便在专用工作器上运行所有预处理操作,直到应用点。要使用的工作服务的数量和类型,以及在管道中的什么位置应用服务,应该根据一些考虑因素来确定,例如瓶颈的严重程度、辅助机器的可用性和成本、预处理操作影响数据大小的方式,以及这会如何影响网络流量。例如,如果您选择一台网络带宽较低的远程工作机,并编写一个在该工作机上运行的扩大数据大小的预处理操作,您可能看不到任何性能改进。

让我们在玩具示例中演示这个 API 的用法。对于这个演示,我选择了一个单独的辅助 Amazon EC2 c5.4xlarge 实例,它具有 16 个 CPU 内核,并使用相同的 Amazon 深度学习 AMI 。p2.xlarge 和 c5.4xlarge 之间的通信将使用 grpc 网络协议,因此您需要确保两个实例都在一个安全组中,该安全组允许相关协议的入站流量,一个来自另一个。

在工作设备上,我们运行以下脚本,其中“10.0.1.171”是辅助设备的 ip 地址:

**import** **tensorflow** **as** **tf**
d_config = tf.data.experimental.service.DispatcherConfig(port=5000)
dispatcher = tf.data.experimental.service.DispatchServer(d_config)
w_config = tf.data.experimental.service.WorkerConfig(port=5001,
    dispatcher_address=dispatcher.target.split("://")[1],
    worker_address='10.0.1.171:5001')
worker = tf.data.experimental.service.WorkerServer(w_config)
dispatcher.join()

注意,我们在同一台机器上运行调度服务器和工作服务器。我们还确保将 TFRecord 文件复制到这台机器上,因为工作人员将从这些文件中加载原始数据。在 GPU 机器上,我们对训练脚本进行了如下修改:

autotune = tf.data.experimental.AUTOTUNE
options = tf.data.Options()
options.experimental_deterministic = **False**
records = tf.data.Dataset.list_files('data/*', shuffle=**True**).with_options(options)
ds = tf.data.TFRecordDataset(records, num_parallel_reads=autotune).repeat()
ds = ds.map(parse_image_function, num_parallel_calls=autotune)
ds = ds.map(blur, num_parallel_calls=autotune)
*# use the TensorFlow Data Service*
ds = ds.apply(tf.data.experimental.service.distribute(
      processing_mode="parallel_epochs",
      service='grpc://10.0.1.171:5000'))
ds = ds.batch(batch_size)
ds = ds.map(rescale,num_parallel_calls=autotune)
ds = ds.map(augment, num_parallel_calls=autotune)
ds = ds.prefetch(autotune)

请注意,我们只编写了记录解析和在 worker 上运行的大量模糊函数。批处理和扩充保留在主设备上。

运行此设置的结果再好不过了!每个历元的运行时间是 58 秒,达到了我们上面为自己设定的目标。通过使用辅助 CPU 设备和 TensorFlow 数据服务来卸载预处理计算,我们已经完全解决了 CPU 瓶颈!事实上,我们发现在这种情况下,平均 GPU 利用率提高了 97%左右。

摘要

下表总结了我们对玩具 resnet50 模型的研究结果:

在本帖中,我们调查了解决数据输入管道中性能瓶颈的许多方法。特别是,我们展示了如何使用 TensorFlow 数据服务来彻底解决这一瓶颈。这项调查并不全面。很可能会有其他可用的工具和技术。虽然我们已经演示了如何将这些技术应用于玩具 Resnet50 模型,但它们的影响肯定会因模型和数据集而异。请不要犹豫,分享您自己的工具、技术和经验。

克服数据可视化冒名顶替综合症

原文:https://towardsdatascience.com/overcoming-data-visualization-imposter-syndrome-5c22ec1bca3d?source=collection_archive---------11-----------------------

社交媒体上共享数据的可视化程度高得惊人,这让许多人望而却步,不敢分享。剧透:我们都有过这样的感觉!

鸣谢:Unsplash 的 Chris Yang 和 Adam Mico

:这里重点介绍的数据可视化工具是 Tableau,但是提到的很多项都适用于所有的数据可视化工具。

在周三我的 Dreamforce 采访 期间,我提到我的旅程在 2019 年才刚刚开始。我提供了一些信息,但没有时间全部分享。最重要的是意识到我的可视化和设计方法需要彻底改革,成为社区的一员不仅让我明白了这一点,还给了我改进的资源和灵感。

两年多前,当我开始在 Tableau 的社交媒体上创建#DataFam 或数据可视化社区时,我知道我有自己的工作要做。那时,我使用这个工具已经五年了,所以我对它的功能很熟悉,可以进行计算,分析数据以获得洞察力,还可以制作图表。尽管如此,我对设计最佳实践毫无头绪,更不用说创建美观的可视化了。所以即使我肩膀上的魔鬼一直告诉我,我不是设计师,不再打扰,另一个肩膀上的天使也不肯让我屈服。

在 Tableau 之前,我使用 Excel 进行数据可视化。它是一个工具,用来炫耀用 3D 爆炸饼图和大量的颜色制作精美的图表或仪表板——越多越好。这贯穿了我对 Tableau 的工作。我的客户想要颜色,并且总是红色和绿色作为度量。他们想要空间颜色和大量的交叉表。这就是我如何来到这个社区和我的想象。这只丑小鸭是我认为的一个好的、可共享的数据可视化的例子:

鸣谢:Adam Mico 2019 Tableau Viz

一旦我加入,我立即发现,在许多情况下,少即是多。例如,我们不需要共享所有的数据或使用所有可用的颜色或填充每个像素。

最成功的社区成员有一个非常不同的方法。他们有节制地、有目的地使用颜色来成功地推动一个点,使用空白,并分享产生最大影响的数据亮点。

尽管我在社区中的可视化率有时不是每周甚至每月一次,但我每周在工作中都会创建一些数据可视化。那时,我的重点是在工作中学习和应用最好的技术。考虑到我的观众和他们习惯的东西,我知道这将是一个艰难的推销,需要大量的学习和研究来解释选择,并在一点点见解中应用稳健的数据。此外,当我做 vizzed 时,我与我尊敬的人合作,并寻求他们对个人可视化的反馈,这些人包括扎克·鲍德斯[Twitter|Tableau|SiteToan Hoang[Twitter|Tableau|SiteSarah Bartlett[Twitter 凯文·弗莱格推特 | 画面 | 现场,还有布莱恩·摩尔** [ 推特 | 画面等等。**

我知道我在处理冒名顶替综合症,但我不想把它公之于众。公开分享它会给我一个借口,不把我的工作放在那里,努力更好地可视化,或者限制我的学习欲望。

自 2019 年加入该社区以来,我已经投入了数千小时来进行数据可视化,其形式包括消费媒体、文献、协作、讨论、指导和可视化数百个仪表板(如果不是接近一千个的话)。因为这些努力,我在 2020 年取得了足够的进步,成为 Tableau 公共精选作者,今年有了两个 Tableau 公共全球“今日(VOTD)”活动,并在大约 20 个其他 votd 上提供了迭代反馈。我作为一个冒名顶替者的感觉并没有因为外界的认可(或者我对别人得到认可的贡献)而消退……而是因为我下面提到的。

3 个事实让我们都成了“冒名顶替者”(或感觉自己是)

  1. 要学的东西太多了。虽然数据可视化课程开始在大学中找到自己的路,但它不是人们通常会考虑的事情。它将数据科学、心理学和艺术的一些复杂性结合到一个学科中——我们大多数人都学习其中一个或另一个,甚至可能来自两个地方,但不是所有三个。开发这些技能的和谐融合需要时间、工具内练习和许多错误的开始。
  2. ****我们一开始没有下文。我们都是从无到有。比如我的 Twitter 和 LinkedIn 在 2019 年 8 月是-0-。因为我使用这个工具的经历,我想回馈社会,但是谁会把我当回事呢?然后你会看到那些拥有成千上万追随者的人,他们拥有巨大的荣誉、令人难以置信的头衔等等。我不知道如何开始,更不用说适应和成长。
  3. ****数据可视化社区可能会让人不知所措,压力重重。我总是将我们社区中共享的可视化视为灵感的无尽源泉。尽管如此,许多人认为这是一个可怕的提醒,提醒他们还有多远才能和出现在他们订阅源上的许多人坐在同一张桌子上。

帮助克服冒名顶替综合症的 7 个技巧

  1. 与你尊敬的社区成员联系。我学得很快;我欣赏的许多人都可以立即接触到——你可以和他们聊天,获得反馈,并更多地了解 dataviz 艺术家。将他们视为不仅仅是数据可视化专家的化身,增加了使社区变得更小和更人性化的背景——你也很快了解到我们希望你做得好,并尽我们所能支持你。从你钦佩的人那里感受到有助于激励和启发学习。
  2. ****阅读,练习,分享(冲洗,重复)。要想提高,光是潜伏在一个社区里,在真空中观察是不够的。如果你把自己推到那里,利用许多社区资源来提高技能,这将会有所帮助。此外,参与那些鼓励参与者分享和观看他人作品的项目是一种更快提高的方式。例如,对于社区的新成员,我分享了#改头换面星期一是看到数据可视化改进的最快方式——你不仅有一个干净的数据源可以使用,安迪·克里贝尔(禅宗大师名人堂成员)在 YouTube 上分享了他对每个可视化的方法——你还可以看到许多其他人在 Twitter 和 LinkedIn 上对相同数据的处理过程。此外,您可以进入档案馆,研究过去几周的情况,并查看伊娃·默里和客人的每周反馈。其他项目、灵感来源和教程由 Tableau — 书签Tableau 社区博客中心每周和每月编辑。
  3. 在 Tableau Public 上下载并评论你欣赏的作品。此外,Tableau Public 为作者提供了下载或复制其可视化内容的机会。在可视化效果的右上角,如果允许,您可以将其复制到您的 Tableau 公共帐户(需要登录)上进行网络编辑(免费),或者下载到您的 Tableau 桌面上查看。

超级重要提示 :尽管有些作者允许下载他们的可视化作品,但请意识到这是他们的作品和资产。如果你创作的作品受到视觉化的启发,请注明作者。此外,如果工作是一个副本或非常相似,请隐藏在您的 Tableau 公共投资组合或以任何方式代表他们的工作作为您的工作。

4.寻求私人反馈。我更喜欢私人反馈——无论是发送还是接收。对于那些感觉有点像骗子的人来说,这甚至更重要。分享时,请随意征求私人反馈或私下询问某人。然而,假设你觉得这样做不舒服。在这种情况下,Tableau 大使米歇尔·弗雷曼和扎克·盖修** [ 推特 | Tableau | 网站提供了一个极好的社区资源,名为 Viz 反馈办公时间,请参见并 填写表格 以供参考。**

5.合作。与他人合作有助于您在创造新事物的同时向其他数据可视化工具学习。以我的经验来看,一次成功的合作是它改善了视觉化,提供了独特的学习机会,并加深了友谊。

6.寻找你自己的数据集,创造你感兴趣的东西。这是可以做到的,因为你在互联网上找到了灵感,并想把它放在一起可视化或有助于社区倡议,如# IronQuest 需要你找到你的数据。看到或整理你的数据可以激发你开发一些独特的东西。激励性的存在是与世界分享你的激情——你想让它变得伟大,并将努力理解数据并以最有影响力的形式呈现出来。

7.定期花时间回顾进度。你可能永远不会成为 Tableau 公共精选作者 或获得 Tableau 公共 Viz of the Day 但应该会看到你的投资组合从底部到顶部的显著改善。即使每六个月看一次也能为你的设计成就提供一个骄傲的源泉。

亚当·米克

Twitter|LinkedIn|Tableau Public

用 PASS 克服 ImageNet 数据集偏差。

原文:https://towardsdatascience.com/overcoming-imagenet-dataset-biases-with-pass-6e54c66e77a?source=collection_archive---------16-----------------------

PASS:ImageNet 替代无人参与的自我监督预训练

图片作者使用@Canva

ImageNet 是计算机视觉应用中使用最广泛的数据集之一。然而,研究表明,基于收集方法和图像类型的偏见在该数据集中普遍存在。在这方面,牛津大学视觉几何小组的一组研究人员提出了一个名为 PASS for self-supervised (SSL)模型预训练的新数据集,专门解决隐私和公平问题。本文是该团队发表的论文的摘要。

PASS:ImageNet 替代无人参与的自我监督预训练

arXiv 上的及格论文|来源:https://arxiv.org/pdf/2109.13228.pdf

什么是通行证?

PASS 代表Pictures without humans for Self-Supervision.它是一个大规模的无标签图像数据集,旨在缓解围绕著名的 Imagenet 数据集的道德、法律和隐私问题。

ImageNet 的问题

ImageNet 当前的一些问题包括:

ImageNet |作者图片的问题

作为备选方案通过

作者指出:

当前最先进的模型预训练使用自我监督学习(SSL ),因此根本不需要标签。受此推动,我们因此考虑在不使用标签的情况下形成数据集,显著增加多样性并消除搜索引擎选择偏差。因为我们去除了带有人的图像,所以我们进一步显著降低了包含与人的外表相关的背景偏见的风险。此外,由于其更随机和无监督的性质,该数据集也可以作为 SSL 的更好的基准,以研究对没有预定义类别标签集的自然图像的缩放,从而解决当前评估的技术缺点。

  • 数据保护:PASS 数据集不包含人体或身体部位
  • 版权 : PASS 仅包含 CC-BY 授权图片,有完整的归属信息。
  • 偏差 —数据集不包含标签,从而减轻了搜索引擎的偏差。
  • 有问题的图像内容-没有个人身份信息,如车牌、签名或笔迹和 NSFW(不适合工作)图像。

收集方法

作者从一个名为 雅虎 Flickr 知识共享 1 亿张 (YFCC100m) 的随机 Flickr 图片数据集开始。接下来,只过滤具有有效CC-BY 授权图像的图像,总共 1700 万。从这里,包含人类的有问题的图像被移除,剩下的净图像总数为 1000 万。由于每个摄影师的图像分布是高度倾斜的,每个摄影师的图像贡献是平衡的,最后,这些图像被提交给人类标记。

数据集生成管道|来源:https://arxiv.org/pdf/2109.13228.pdf

提交人还提到,注释是由一家注释公司历时三周完成的,该公司支付注释者 150%的最低工资。

结果

作者在论文中提交的结果如下:

(I)诸如 MoCo、SwAV 和 DINO 的自监督方法在 PASS 数据集上训练良好,产生强有力的图像表示

(ii)在预训练期间排除人类图像对下游任务表现几乎没有影响,即使这是在 ImageNet 中进行的;

(iii)在 PASS 上训练的模型的性能产生比在 ImageNet 上预训练更好的结果(包括没有人或者甚至没有 Places 205 数据集的 ImageNet),如下所示:

冻结编码器评估|来源:https://arxiv.org/pdf/2109.13228.pdf

(iv)对于微调评估,例如检测和分割,通过预训练在 COCO 数据集上产生 1% mAP 和 AP50 内的结果。

微调代表性评估|来源:https://arxiv.org/pdf/2109.13228.pdf

(v)即使在涉及人类的任务上,如密集姿势预测,在我们的数据集上进行预训练也能产生与 ImageNet 相当的性能,即使 PASS 没有人类图像

这对 Imagenet 意味着什么?

作者强调,PASS 不会使现有数据集过时,因为它不足以进行基准测试。然而,PASS 背后的想法是展示在使用更安全的数据时,模型预训练通常是可能的,并且它还为预训练方法的更稳健的评估提供了基础。

PASS 是无偏差的吗?

尽管 PASS 显著降低了数据主体的数据保护和其他道德风险,但正如作者自己指出的那样,一些问题仍然普遍存在:

  • 即使在过滤图像时非常小心,有害图像仍有可能漏网。
  • 由于图像是随机采样的,地理偏见的问题依然存在。
  • 由于缺少人体图像,PASS 不能用于学习人体模型,例如用于姿势识别。
  • PASS(与 ImageNet 相反)不能单独用于培训和基准测试,因为 PASS 不包含标签

结论

PASS 有其局限性,但仍然是研究界朝着降低许多任务和应用的道德和法律风险迈出的令人鼓舞的一步。ImageNet 数据集无疑开创了最先进的计算机视觉应用的时代,但作为一个社区,我们不能忽视数据集中的缺点。

参考

论文:PASS:ImageNet 替代无人自监督预训练

作者 : YM。 C .鲁普雷希特 A .齐塞曼 A .韦达尔迪

克服变压器的输入长度限制

原文:https://towardsdatascience.com/overcoming-input-length-constraints-of-transformers-b0dd5c557f7e?source=collection_archive---------19-----------------------

思想和理论

一种面向长文档训练的抽取摘要方法

贾瑞德·克雷格Unsplash 上拍摄

名副其实,Transformers【1】在过去几年中真正改变了 NLP 领域,主要是因为它们的并行化能力允许大型预训练模型,如 BERT【2】。虽然 BERT 及其衍生工具已经在 NLP 的大多数领域显示出了最先进的结果,但是 Transformer 模型有一个主要缺点:它很难应用于非常长的文档。这个困难是由于自我注意操作,其相对于输入长度具有 O(n)的指数复杂度。随着许多公司将人工智能模型集成到他们的工作流程中,这可能会成为一个问题,因为并非所有公司都有资源来有效处理他们可以访问的数据的大小和复杂性。例如律师事务所(法律文件)和医院(医疗记录)。

已经提出了几种解决方案来减轻长文档带来的问题。最简单的解决方案是截断,其中只将文档的前 N 个标记作为输入,但是这从原始文档中丢弃了许多潜在的有价值的信息。另一个解决方案是分块,将一个文档分割成更小的块,每个块都作为模型的一个独立输入。虽然这确实允许更长的输入,但是每个块必须被单独编码,并且必须在下游模型中使用,这仍然使得它在计算上是昂贵的。这种方法的另一个缺点是长时间的注意力丢失了,因为组块之间没有注意力。一个有希望的新解决方案是通过用一种称为局部敏感哈希自关注【9】的近似方法来替代全局自关注,潜在地降低计算复杂度,这种近似方法在重整器模型【10】中使用,有效地将复杂度降低到 O(L log L)。

然而,我建议针对长文档输入的另一种解决方案:摘要。我将展示如何使用提取摘要首先从长文档中提取重要信息,然后利用这些摘要训练一个基于 Transformer 的模型。换句话说,我将演示如何应用摘要来减少输入大小,从而减少计算需求。

为了评估这种方法,我们比较了“引文预测”任务的几个输入预测科学文献的引用数量是一项任务,通过利用文献的全文与仅使用摘要相比,已经取得了明显的改进 [3]。对于我们的实验来说,引用预测任务有两个独特的性质:首先,我们知道需要长文档输入才能在这项任务中获得更好的结果。第二,我们有一个摘要形式的人工摘要,我们可以将自己的摘要与之进行比较。我们提出的模型如图 1 所示。

图 1: T 他提出了引文预测模型。使用 LexRank 从输入文档中提取摘要,然后将其用作引用预测的 Transformer 模型的输入。图片作者。

摘录摘要的复习

为了理解我们的方法是如何工作的,重要的是理解我们的总结算法是如何工作的。摘要算法有两种风格:提取的和抽象的。

提取摘要算法从源文档中选择一组被组合成摘要的句子,而抽象摘要算法生成包含不一定出现在源文档中的句子的摘要。

虽然在过去的几年中在抽象概括方面已经取得了很大的进步,主要是由于基于预训练的编码器-解码器的模型(例如变换器)的出现,但是抽象概括模型要复杂得多,并且在计算上非常昂贵;违背了我们实验的目的。出于这个原因,我们使用了 lex rank【4】,一种 2004 年的快速摘要算法,它仍然是摘要中最先进的算法之一。

LexRank 使用无监督的基于图的方法从文档中选择最相关的句子。LexRank 的工作方式如下:输入文档中的每一个句子首先被转化为一个嵌入(使用句子中单词的平均值 TF-IDF),然后被视为图中的一个节点。通过计算句子嵌入之间的余弦相似度来创建连接或边缘。在实践中,这些信息被放在一个连接矩阵中,该矩阵包含所有句子的所有相似之处。然后,LexRank 对每个连接应用相似性阈值,以确保在连接矩阵中只使用“强”连接。这就产生了一个由 0 和 1 组成的矩阵。之后,每个节点除以它的度数:它拥有的连接数。最后,使用幂迭代方法计算每个句子的得分,并返回得分最高的前 N 个句子作为摘要。因此,我们的摘要是原始文档的严格子集。对于算法的更广泛的解释,我鼓励你阅读 Erkan 等人的论文【4】。

实验装置

为了评估我们的方法,我们使用 LexRank 从所有的全文输入中生成了摘要。我们将这些摘要与训练数据中每个文档的摘要和全文进行了比较。此外,我们还为每个文档生成了一组随机句子,作为我们的随机基线。为了公平的比较,作为随机句子的两个生成的摘要具有与人类书面摘要相同数量的句子。

请注意,该数据集没有可用的小节信息,这就是为什么我们随机选取句子,而不是每个小节的前 N 个句子(这是文献中常见的基线)。虽然可以将平均引用计数作为基线,但这将总是导致 R2 值为 0,因为我们的预测无法解释我们数据中的任何差异。

作为我们的训练数据,我们使用了【3】中提出的 ACL-文献计量学数据集。该数据集包含来自 ACL 选集数据库的 30950 个文档的全文和摘要信息。每篇论文都有一个标签,标明论文发表后前 10 年的引用情况。由于引用数量的增加遵循齐普斯-曼德勃罗定律(或幂定律)【8】,,我们感兴趣的是“从谷壳中分离出小麦”,而不是预测极端影响的论文,因此我们使用了等式 1 中所示的公式,其中我们取了对数并将引用数量 n 加 1,以确保我们的公式是针对引用数量为 0 的情况定义的。图 2 显示了训练集中非标准化引用的图表。请注意,我们数据中的引用计数严重倾斜,并且遵循幂定律。

等式 1: 引用的对数归一化函数

图 2: 训练数据中引用计数的直方图。图片作者。

因此,我们有一个文档的四个输入,每个输入都训练了一个引用预测模型:全文、摘要、随机基线和我们的 LexRank 摘要。我们的假设是,我们可以通过摘要对全文文档中的重要信息进行编码,并匹配甚至提高摘要的性能。

摘要和概要中的平均句子数是 6。相比之下,全文文档中的平均句子数量是 150,因此我们的摘要在输入大小上平均减少了 25 倍。

我们使用了在【3】中提出的舒伯特模型,除了我们用 SciBERT【5】代替了 BERT-base,因为我们处理的是科学文档。在这个模型中,使用我们的 SciBERT 层将全文文档编码为 512 个标记的块,之后使用单个丢弃层训练 GRU 层,然后使用单个线性层进行预测。对于架构的更全面的解释,我鼓励你阅读 [3]。为了生成我们的 LexRank 摘要,我们使用了 Sumy 包(https://pypi.org/project/sumy/)。

为了比较我们的结果,我们报告了三个常见的回归指标:R2、均方误差(MSE)和平均绝对误差(MAE)。对于 R2,分数越高越好,对于 MSE 和 MAE,分数越低越好。

除了评估我们的摘要在预测引用数量方面的表现,我们还计算了摘要和摘要之间的(F1) Rouge-1、Rouge-2 和 Rouge-L 得分【6】。我们这样做是为了评估两者之间有多少重叠,因为我们希望它们包括全文中的类似信息。

建议实验的结果

表 1: 引文预测不同输入类型的结果。

****表 2:F-1·鲁日在摘要和 LexRank 摘要之间的得分。

表 1 中列出了测试集的 R2、MSE 和 MAE 分数,它们是三次运行的平均值。正如所料,我们选择 N 个随机句子的基线模型的表现明显比其他输入差。人工撰写的摘要略优于 LexRank 摘要,而全文输入则显著优于两者。请注意,当我们将这些分数转换回它们的非标准化值时,对于全文文档和摘要文档,我们得到的 MAE 分别为 13.09 和 13.62。这些高 MAE 分数受到大量引用的论文的严重影响,这就是为什么我们训练对数标准化引用计数。供参考:如果我们从 1474 篇论文的测试集中删除引用率最高的前 50 篇论文,这些分数分别为 6.92 和 7.19。

表 2 列出了摘要和摘要之间的 Rouge-1、Rouge-2 和 RougeL。Rouge 的得分与最近的研究相当,在最近的研究中,LexRank 被用作基线【7】

讨论

我们的结果表明,使用 LexRank 获得的摘要在用作下游任务的输入时,提供了与人工编写的摘要相似的结果。LexRank 摘要和摘要的结果的接近程度表明,我们通过使用全文输入的精简版本所能获得的下游结果可能有一个上限。尽管我们提取的摘要并没有提高摘要的性能,但它们具有相似性能的事实表明,当全文文档输入过于昂贵时,提取的摘要可以作为一种很好的输入。这在经常发现长文档,但通常没有压缩版本的领域中特别有用,例如法律或医疗文档。但是,如果可能的话,全文文档仍然是首选,性能的显著提高就证明了这一点。

rouge 分数表明,就内容而言,摘要和摘要之间存在显著差异,这很有趣,因为表 1 中的结果非常接近。我们尝试使用摘要和概要的连接作为输入来平衡这些差异,但是这仅仅给出了非常小的改进。

一个有趣的后续研究是比较不同的摘要长度,看看我们是否可以用更短的摘要来匹配全文输入的性能,例如,通过生成长度为我们输入长度一半的摘要。另一个有趣的研究是比较不同的摘要算法,因为在这个实验中只使用了 LexRank。最后,由于 LexRank 为每个句子输出一个分数,我们也可以用它来减少噪音,去掉最不突出的句子。

结论

我们表明,摘录摘要在引用预测任务中用作转换器的输入时,具有与人类编写的摘要相似的性能。对于资源有限的长文档培训任务,这是一个很有前途的解决方案。然而,与摘要相比,全文输入仍然有很大的改进。

参考文献

[1] Ashish Vaswani、Noam Shazeer、Niki Parmar、Jakob Uszkoreit、Llion Jones、Aidan N. Gomez、Lukasz Kaiser 和 Illia Polosukhin。你只需要关注,2017。

[2] Jacob Devlin、张明蔚、Kenton Lee 和 Kristina Toutanova。Bert:用于语言理解的深度双向转换器的预训练。arXiv 预印本 arXiv:1810.04805,2018。

[3]托马斯·范东恩、吉迪恩·迈莱特·德·布伊·温尼日尔和兰伯特·肖梅克。舒伯特:带有伯特编码的学术文档块促进引用计数预测。2020 年第一届学术文献处理研讨会会议录。

[4]居内斯·埃尔坎和德拉戈米尔·拉杰夫。基于图的词汇中心性作为文本摘要中的显著性。j .阿提夫。里面的第 22(1):457-479 号决议,2004 年 12 月。

[5] Iz Beltagy、Kyle Lo 和 Arman Cohan。科学文本的预训练语言模型。在 EMNLP,2019。

[6]林金耀。ROUGE:一个自动评估摘要的包。《文本摘要分支》, 74-81 页,西班牙巴塞罗那,2004 年 7 月。计算语言学协会。

[7]董玥、安德烈·米尔恰和成龙。长科学文献的话语感知无监督摘要,2021。

[8]祖拉布·西拉加德泽。引文和齐夫-曼德勃罗定律。复杂系统,1999 年 2 月 11 日。

[9]亚历山大·巴甫洛夫·安多尼、皮奥特·因迪克、蒂伊斯·拉霍文、伊利亚·拉赞施泰因和路德维希·施密特。角距离的实用和最佳 lsh,2015。

[10]尼基塔·基塔耶夫、祖卡斯·凯泽和安塞姆·列夫斯卡娅。改革者:高效的变压器,2020。

过度拟合和概念合理性

原文:https://towardsdatascience.com/overfitting-and-conceptual-soundness-3a1fd187a6d4?source=collection_archive---------15-----------------------

行业笔记

特征使用如何影响我们对深层网络中过度拟合的理解

谢恩·奥尔登多夫Unsplash 上拍摄的照片

过度拟合是机器学习中的一个中心问题,当它被部署在看不见的数据上时,它与学习模型的可靠性密切相关。过度拟合通常通过模型在其训练数据上获得的精度与之前未见过的验证数据相比的差异来衡量,甚至定义。虽然这是一个有用的度量,广泛地捕捉了模型在新的点上犯错误的程度(过度拟合的关键问题之一),但我们将改为对过度拟合采取更一般和细微的看法。特别是,本文将使用 TruLens 解释性框架来检查过度拟合背后的一个关键机制:编码和使用不健全的特性

在高层次上,深度网络通过学习提取高层次的特征来工作,这些特征使它们能够对新的输入进行预测。虽然这些特征中的一些可能真的是可概括的预测器,但其他的可能只是巧合地帮助训练集上的分类。在前一种情况下,我们说学习到的特征在概念上是合理的。后一种类型的学习特征在概念上不是合理的,因此可能导致在看不见的点上的异常或不正确的行为,即过拟合。

在本文的剩余部分,我们将提供支持这种过度拟合观点的证据,并展示 TruLens 如何用于评估神经网络学习和使用的特征。有关 TruLens 的更全面介绍,请参见本文。

一个例证

我们的假设是,过度拟合通过特殊的特征使用在模型中表现出来。为了说明这一点,我们将考虑来自野生的(LFW)数据集中的“标记的人脸的例子。LFW 数据集包含许多名人和杰出公众人物大约在 21 世纪初的图像,任务是识别每张照片中的人。我们选择了包含五个最频繁出现的身份的子集。完整的数据集可以通过 scikit-learn 获得。

LFW 培训点示例。我们看到右上角的图像有一个独特的粉红色背景。(图片来自利用模型记忆进行校准的白盒成员推理)

在训练集中,我们发现托尼·布莱尔的一些图像具有独特而鲜明的粉红色背景。我们的假设表明,一个模型可以通过学习使用粉红色背景作为托尼·布莱尔的特征来过度拟合,因为该特征确实在训练集上预测托尼·布莱尔。当然,尽管它对训练集非常有用,但背景显然在概念上是不合理的,并且不太可能对新数据有用。

如果模型以这种方式过度拟合,那么通过检查模型在具有粉红色背景的实例上编码和使用的特征,这将是明显的。这可以通过 TruLens 使用内部影响 [1]来完成。复制本文中图像和实验的笔记本可以在这里找到。

我们将从在 LFW 训练集上训练一个简单的卷积神经网络(CNN)开始。例如,使用张量流:

from trulens.nn.models import get_model_wrapper# Define our model.
x = Input((64,64,3))z = Conv2D(20, 5, padding='same')(x)
z = Activation('relu')(z)
z = MaxPooling2D()(z)z = Conv2D(50, 5, padding='same')(z)
z = Activation('relu')(z)
z = MaxPooling2D()(z)z = Flatten()(z)
z = Dense(500)(z)
z = Activation('relu')(z)y = Dense(5)(z)keras_model = Model(x, y)# Compile and train the model.
keras_model.compile(
    loss=SparseCategoricalCrossentropy(from_logits=True),
    optimizer='rmsprop',
    metrics=['sparse_categorical_accuracy'])keras_model.fit(
    x_train, 
    y_train, 
    epochs=50, 
    batch_size=64, 
    validation_data=(x_test, y_test))# Wrap the model as a TruLens model.
model = get_model_wrapper(keras_model)

接下来,我们将使用内部影响来检查模型用于决策的主要学习特征。根据我们的假设,过度拟合模型将编码粉红色背景作为用于分类的特征。如果这个假设成立,我们将需要找到这个特征在模型中的编码位置,以及它是否用于分类。

CNN 的卷积层由许多通道特征图组成,而这些特征图又由单个神经元网格构成。每个通道代表一种类型的特征,而每个通道内的神经元代表图像中特定位置处的那种类型的特征。有可能高级特征(例如,粉色背景)由网络编码,但是它不对应于单个通道。例如,它可以由多个通道的线性组合形成。在我们的例子中,为了简单起见,我们将我们的搜索限制在考虑单个通道,这恰好对我们有用。

我们训练出来的网络不是特别深,所以我们没有太多的选择层来搜索。典型地,更深的层编码逐渐更高级的特征;为了找到我们的粉红色背景特征,我们将从搜索第二个卷积层开始。

我们使用下面的过程:首先,我们在第二卷积层(我们的模型的实现中的第 4 层)中找到最有影响的信道。我们有很多方法可以做到这一点;在我们的例子中,我们将根据通道中每个神经元之间的最大影响为每个通道分配影响。一旦我们确定了最有影响力的通道,我们将通过找到对该通道贡献最大的输入像素来可视化它。总之,这个过程告诉我们哪个特征(在我们选择的层)对模型的预测最有影响,以及图像的哪些部分是该特征的一部分。

from trulens.nn.attribution import InternalInfluence
from trulens.visualizations import HeatmapVisualizerlayer = 4# Define the influence measure.
internal_infl_attributer = InternalInfluence(
    model, layer, qoi='max', doi='point')internal_attributions = internal_infl_attributer.attributions(
    instance)# Take the max over the width and height to get an attribution for
# each channel.
channel_attributions = internal_attributions.max(
    axis=(1,2)
).mean(axis=0)target_channel = int(channel_attributions.argmax())# Calculate the input pixels that are most influential on the
# target channel.
input_attributions = InternalInfluence(
    model, (0, layer), qoi=target_channel, doi='point'
).attributions(instance)# Visualize the influential input pixels.
_ = HeatmapVisualizer(blur=3)(input_attributions, instance)

(图片由作者提供)

最重要的像素以红色突出显示。我们看到,实际上,背景被我们的模型大量使用。使用另一种可视化技术,我们可以再次确认解释集中在这些独特训练点的背景上:

from trulens.visualizations import ChannelMaskVisualizer
from trulens.visualizations import Tilervisualizer = ChannelMaskVisualizer(
    model,
    layer,
    target_channel,
    blur=3, 
    threshold=0.9)visualization = visualizer(instance)
plt.imshow(Tiler().tile(visualization))

(图片由作者提供)

为了便于比较,我们可以在一个不同的模型上遵循相同的程序,该模型在训练期间没有看到任何粉色背景。这个模型没有理由对粉红色背景特征进行编码,更不用说用它来识别托尼·布莱尔了。正如预期的那样,我们看到结果完全不同:

(图片由作者提供)

用解释捕捉错误

解释有助于增加我们对概念上合理的模型的信任,或者有助于我们预测未来可能因使用不合理的特性而出现的错误。

再次考虑我们的运行示例。模特了解到粉色背景是托尼·布莱尔的特色。碰巧的是,在我们的测试集中,没有托尼·布莱尔或其他任何人的图片是粉色背景的。因此,我们的测试集在识别这种概念不健全的情况下是没有用的。但是模型应该被信任吗?据推测,粉色背景很容易在部署中出现,即使在测试集中没有出现。

用粉色背景训练的模型和不用粉色背景训练的模型都达到了大致相同的验证准确度(在 83%和 84%之间)。从验证指标的角度来看,我们应该对其中任何一个都满意。但是,前面几节中生成的解释应该清楚地表明,一个模型有一个缺点,而另一个模型没有。

事实上,我们可以直接证明不健全的功能使用的含义,这可以通过检查解释来预见。虽然我们在测试集中没有显示粉红色背景的例子,但这可以通过一些基本的照片编辑很容易地解决。在这里,我们编辑了一个来自 LFW 的非托尼-布莱尔派人士 Gerhard Schroeder 的图像,使其背景为粉红色。当然,像编辑过的图像这样的图片很容易在现实生活中实现。

来自 LFW 的 Gerhard Schroeder 的原始图像(左)和编辑版本(右)。(图片由作者提供)

我们看到,在原始图像上,模型正确预测了类别 3,对应于 Gerhard Schroeder。但是,在编辑过的图像上,模型预测的是 class 4,对应的是 Tony Blair。

>>> keras_model.predict(original).argmax(axis=1)
array([3])
>>>
>>> keras_model.predict(edited).argmax(axis=1)
array([4])

而且,可以预见的是,如果我们问模型为什么它在编辑过的图像上预测到了托尼·布莱尔,我们会看到粉红色的背景再次被突出显示。

(图片由作者提供)

最后,如果我们转向没有粉红色背景的替代模型,我们观察到我们编辑的图像不会导致相同的错误行为。毕竟,另一种模式没有理由将粉红色背景与托尼·布莱尔(或任何其他人)联系起来,而且似乎也没有这样做。

>>> keras_model_no_pink.predict(original).argmax(axis=1)
array([3])
>>>
>>> keras_model_no_pink.predict(edited).argmax(axis=1)
array([3])

过度拟合的其他含义

我们已经看到过过度拟合如何导致模型在看不见的数据上犯特殊的错误。除了导致错误分类之外,过度拟合还会带来隐私风险。直观地说,通过学习过于特定于训练集的特征,模型将会无意中泄露关于它们的训练数据的信息。我与马特·弗雷德里克松(出现在《2020 年 USENIX》中)在这个话题上的研究【T1【2】)使用了与这里类似的见解来展示攻击者如何能够对用于训练模型的数据做出推断。

特别是,我们设计的攻击甚至在模型的训练集和验证集之间基本上没有差距的情况下也能工作。这强调了一点,即过度拟合不一定需要在验证数据上显示为错误来导致问题。通过检查我们的模型使用特性的方式,我们可以在它们的功效上获得比我们从简单的性能度量中推断的更多的信任;相反,我们可以发现潜在的问题,否则可能会被忽视。

摘要

机器学习模型容易学习不健全的特征,这些特征可能导致预测错误、隐私漏洞等。解释有助于识别不合理的特性使用情况,否则即使在验证数据中也不会被发现。另一方面,我们应该努力寻找那些解释表明合理特征使用的模型,增加我们对模型在未来未知数据上的表现的信任。TruLens 是一个功能强大且易于使用的工具,可以帮助我们应用这种有价值的模型分析形式。

参考

  1. 深度卷积网络的影响导向解释。ITC 2018。 ArXiv
  2. 雷诺&弗雷德里克松。"偷来的记忆:利用模型记忆校准白盒成员推理."USENIX 2020。 ArXiv

过拟合和欠拟合原则

原文:https://towardsdatascience.com/overfitting-and-underfitting-principles-ea8964d9c45c?source=collection_archive---------0-----------------------

理解欠拟合和过拟合的基本原理,以及为什么你应该使用特殊的技巧来处理它们

欠拟合和过拟合原则。作者图片

已经有很多关于过度拟合的文章,但是几乎所有的都只是简单的工具列表。“如何处理过度拟合——十大工具”或“防止过度拟合的最佳技术”。这就像给别人看钉子却不解释怎么钉一样。对于试图弄清楚过度拟合是如何工作的人来说,这可能非常令人困惑。还有,这些文章往往不考虑欠适,好像根本不存在。

在这篇文章中,我想列出提高模型质量的基本原则(确切地说是原则),并相应地防止特定示例的欠拟合和过拟合。这是一个非常普遍的问题,可以适用于所有的算法和模型,所以很难完全描述它。但是我想试着给你一个理解为什么会出现欠拟合和过拟合,以及为什么要使用一种或另一种特定的技术。

欠拟合和过拟合以及偏差/方差权衡

虽然我没有在这里描述你需要知道的所有概念(例如,质量度量或者交叉验证,但是我认为向你解释(或者只是提醒你)什么是欠拟合/过拟合是很重要的。

为了弄清楚这一点,让我们创建一些数据集,将其分为训练集和测试集,然后在其上训练三个模型——简单、良好和复杂(我不会在这个示例中使用验证集来简化它,但我将在稍后讲述它)。所有代码都可以在这个 GitLab repo 中找到。

生成的数据集。作者图片

欠拟合是指你的模型对于你的数据来说过于简单的情况。更正式地说,你关于数据分布的假设是错误的,过于简单——比如你的数据是二次的,你的模型是线性的。这种情况也叫高偏。这意味着您的算法可以进行准确的预测,但最初对数据的假设是不正确的。

不合身。基于立方数据训练的线性模型。作者图片

相反,过度拟合是当你的模型对于你的数据来说太复杂的情况。更正式地说,你关于数据分布的假设是错误的,太复杂了——比如你的数据是线性的,你的模型是高次多项式。这种情况也被称为高方差。这意味着您的算法无法进行准确的预测——输入数据变化很小,模型输出变化很大。

过度拟合。基于立方数据训练的 13 次多项式模型。作者图片

这是同一个问题的两个极端,最优解总是在中间的某个地方。

好模式。基于立方数据训练的立方模型。作者图片

我不会过多谈论偏差/方差权衡(您可以阅读本文中的基础知识,但让我简单地提一下可能的选项:

  • 低偏差、低方差——这是一个很好的结果,恰到好处。
  • 低偏差、高方差过度拟合 —算法对相似数据输出非常不同的预测。
  • 高偏差,低方差— 欠拟合 —算法对相似数据输出相似预测,但预测是错误的(算法“未命中”)。
  • 高偏差、高方差——非常糟糕的算法。你很可能永远看不到这个。

四幅图上的偏差和方差选项。作者图片

所有这些情况都可以放在同一个地块上。这是一个有点不如前一个清晰,但更紧凑。

一个图上的偏差和方差选项。作者图片

如何检测欠拟合和过拟合

在我们进入工具之前,让我们了解如何“诊断”欠拟合和过拟合。

训练/测试错误和欠拟合/过拟合。作者图片

拟合不足意味着你的模型做出了准确但最初不正确的预测。在这种情况下,训练误差大val/test 误差也大

过度拟合意味着你的模型预测不准确。在这种情况下,训练误差很小val/test 误差很大

当你找到一个好的模型训练误差小(但比过拟合的情况下大),并且 val/test 误差也小

在上述情况下,测试误差和验证误差大致相同。当一切正常,并且您的训练、验证和测试数据具有相同的分布时,就会发生这种情况。如果验证和测试误差非常不同,那么您需要获得更多类似于测试数据的数据,并确保您正确地分割数据。

如何检测欠拟合和过拟合?作者图片

工具和技术

现在让我们看看防止欠拟合和过拟合的技术,确切地考虑一下为什么我们应该使用它们

你应该记住一般直觉

我们记得:

  • 当你的模型对你的数据来说太简单时,就会出现欠拟合。
  • 过度拟合发生在你的模型对你的数据太复杂的时候。

基于此,你应该记住的简单直觉是:

  • 要修复欠拟合,你应该模型复杂化。
  • 为了修正过拟合,你应该简化模型。

事实上,下面将要列出的一切只是这个简单规则的结果。我将试图说明为什么某些行为会使模型变得复杂或简化。

更简单/复杂的模型

基于上述直觉想到的最简单的方法是尝试更简单或更复杂的算法(模型)。

为了使模型变得复杂,你需要添加更多的参数(自由度)。有时这意味着直接尝试更强大的模型——一种先验地能够恢复更复杂的依赖性的模型(具有不同内核的 SVM,而不是逻辑回归)。如果算法已经相当复杂(神经网络或者某种集成模型)你需要给它增加更多的参数,比如增加 boosting 中的模型数量。在神经网络的上下文中,这意味着添加更多的层/每层中更多的神经元/层之间更多的连接 CNN 更多的过滤器,等等。

为了简化模型,你需要反过来减少参数的数量。要么彻底改变算法(尝试随机森林代替深度神经网络),要么减少自由度。更少的层,更少的神经元,等等。

更多正规化/更少正规化

这一点与前一点非常相关。实际上,正则化是对模型的间接强制简化。正则项要求模型保持参数值尽可能小,因此要求模型尽可能简单。具有强正则化的复杂模型通常比最初的简单模型表现得更好,因此这是一个非常强大的工具。

正则化的好模型和复杂模型。作者图片

更多的正则化(简化模型)意味着增加正则化项的影响。这一过程是严格的个体化过程——取决于算法,正则化参数是不同的(例如,为了减少正则化,岭回归的α应该减少,而 SVM 的 C——增加)。所以你要研究算法的参数,注意在特定情况下是应该增加还是减少。有很多这样的参数——线性回归的 L1/L2 系数,SVM 的 C 和 gamma,决策树的最大树深度,等等。在神经网络中,主要的正则化方法有:

  • 提前停车,
  • 辍学,
  • L1 和 L2 正规化。

你可以在这篇文章中读到它们

相反,在模型需要复杂的情况下,你应该减少正则项的影响或者完全放弃正则化,看看会发生什么。

更多功能/更少功能

这可能不那么明显,但是添加新功能也会使模型变得复杂。在多项式回归的背景下考虑这个问题-向数据集添加二次要素允许线性模型恢复二次数据。

添加新的“自然”特性(如果你可以这样称呼的话)——获取现有数据的新特性很少使用,主要是因为它非常昂贵且耗时较长。但是你要记住,有时候这是有帮助的。

但是从现有特征中人工获得附加特征(所谓的特征工程)经常用于经典的机器学习模型。这种转变的例子数不胜数,但以下是主要的几个:

  • 多项式特征—从 x,x ₂到 x,x,xx,x,x,… ( sklearn.preprocessing.PolynomialFeatures类)
  • log(x),用于非正态分布的数据
  • ln(|x| + 1)用于右尾粗的数据
  • 范畴特征的转换
  • 其他非线性数据转换(从长度和宽度到面积(长度*宽度))等等。

如果您需要简化模型,那么您应该使用较少数量的特征。首先,删除您之前添加的所有附加功能。但结果可能是,在原始数据集中,有些要素不包含有用的信息,有时还会引发问题。如果一些特征是相关的,线性模型通常工作得更差。在这种情况下,你需要使用特征选择方法来选择那些携带最大量有用信息的特征。

值得一提的是,在神经网络的背景下,特征工程特征选择几乎毫无意义,因为网络在数据本身中找到依赖性。这其实也是为什么深度神经网络可以还原如此复杂的依赖关系。

为什么获取更多数据有时没有帮助

对抗过度拟合的技术之一是获取更多的数据。然而,令人惊讶的是,这并不总是有用的。让我们生成一个类似的 10 倍大的数据集,并在其上训练相同的模型。

为什么获取更多的数据有时没有帮助。作者图片

一个非常简单的模型(1 级)一直保持简单,几乎没有什么变化。因此获得更多的数据在不足的情况下没有帮助。

但是复杂模型(13 度)已经变好了。它仍然比最初的好模型(3 级)差,但比原来的好得多。为什么会这样?

上次(对于初始数据集),在 14 个数据点上训练模型( 20(初始数据集大小) 0.7(训练比)= 14* )。一个 13 次多项式可以完美匹配这些数据(以此类推,我们可以通过 2 个点画一条理想直线(次数=1),通过 3 个点画一条理想抛物线(次数=2),以此类推)。通过获得 10 倍多的数据,我们的训练集的大小现在是 140 个数据点。为了完美匹配这些数据,我们需要一个 139 次多项式!

注意,如果我们最初训练了一个非常复杂的模型(例如,150 次多项式),这样的数据增加不会有帮助。所以获取更多的数据是提高模型质量的好方法,但是如果模型非常非常复杂的话可能就没什么帮助了。

因此,结论是——获得更多的数据只能有助于过度拟合(而不是欠拟合),并且如果你的模型不是太复杂

在计算机视觉的背景下,获得更多数据也可以意味着 数据扩充

摘要

让我们用一个表来总结所有的事情。

对抗欠适和过适的技巧。作者图片

好吧,两个更好。

应对欠适和过适的技巧(扩展版)。作者图片

一些工具和技术在本文中没有涉及。例如,我认为数据清理交叉验证保持验证是任何机器学习项目中的常见做法,但它们也可以被视为对抗过度拟合的工具。

你可能会注意到,为了消除欠拟合或过拟合,你需要应用完全相反的动作。因此,如果您最初“误诊”了您的模型,您可能会花费大量的时间和金钱在无意义的工作上(例如,当实际上您需要将模型复杂化时,获取新的数据)。这就是它如此重要的原因——数小时的分析可以节省您数天甚至数周的工作时间。

除了通常的模型质量分析(训练/测试错误),还有许多技术可以准确理解需要做什么来改进模型(错误分析上限分析等)。).不幸的是,这些主题超出了本文的范围。

但是,所有这些程序都有一个目的,就是了解往哪里搬,需要注意什么。我希望这篇文章能帮助你理解欠适和过适的基本原则,并激励你去了解更多。

正如我之前所说,本教程中使用的所有代码都可以在 GitLab 上获得。

https://gitlab.com/Winston-90/underfitting_vs_overfitting

感谢您的阅读!

  • 我希望这些材料对你有用。在 Medium 上关注我,获取更多这样的文章。
  • 如果您有任何问题或意见,我将很高兴得到任何反馈。在评论里问我,或者通过 LinkedIn 或者 Twitter 联系。
  • 为了支持我作为一个作家,并获得数以千计的其他媒体文章,使用我的推荐链接获得媒体会员资格(不收取额外费用)。

过度适应并不是正规化可以帮助解决的唯一问题

原文:https://towardsdatascience.com/overfitting-is-not-the-only-problem-regularisation-can-help-with-6fcdbfdb9384?source=collection_archive---------30-----------------------

从数学上理解岭回归在特征数量超过数据点时的作用

弗兰基·查马基在 Unsplash 上拍摄的照片

特征多于数据的问题

当我们谈论正则化时,我们几乎总是在过度拟合的背景下谈论它,但一个鲜为人知的事实是,它可以帮助解决上述问题。

由于数据是机器学习的核心,你永远不会想到会遇到这样的问题。话虽如此,但我们有许多特征而数据点很少,这是很常见的,尤其是在涉及生物学的 ML 问题中。在回归问题中,特征多于数据点使得普通最小二乘回归(OLS)表现很差

让我们通过一个简单得可笑的例子来理解为什么。

这是直线的方程式

hθ(x) = θ0 + θ1x1

为了找出给定 x1 和 hθ(x)θ0 和θ1 的值,我们需要至少 2 个数据点。假设我们根据一个单一特征预测人的体重——他们的年龄。在这种情况下,我们需要至少两个人的数据来拟合一条直线。如果我们只有一个人的年龄会怎样?

无限解(图片由作者提供)

从上面我们可以看到,多条直线可以穿过一个点,虽然我只展示了三条这样的直线,但是这样的系统有无穷多个解!

线性回归的正规方程与不可逆性

首先,我们在线性回归期间最小化的成本函数是

线性回归成本函数

这里 m 代表数据点的数量,θ是(n+1)维向量,(n 维代表 n 个特征+1 维代表偏差( θ0 )。

为了最小化这个成本函数,我们将关于θ矩阵中每个条目的偏导数设置为 0,并且同时求解θ。

这是我们最后的法线方程

线性回归的正规方程

详细的推导对于熟悉微积分的人可以在这里找到https://see.stanford.edu/materials/aimlcs229/cs229-notes1.pdf第 11 页。

现在 X 是由 m 个数据点和 n 个特征组成的(m X (n+1))维矩阵。请注意,X 的第一列填充了 1,以说明偏差。因此,X 对于 n 个特征中的每一个都有一列,加上 1 的一列,使得它总共有(n+1)列。

如果我们有两个数据点,分别由特征(2,5)和(4,7)组成,这就是我们矩阵的样子。

一个示例 X 矩阵

现在在正规方程中,每当我们有 m < n 也就是每当 X 的行数比特征数少的时候,X 转置的乘积的逆,并且 X 不存在。

这里有一个同样的数学证明。如果你不熟悉线性代数,请跳过证明。

**

证据 1

外卖食品


救援正规化!

这里是正则化成本函数的等式,更具体地说是 岭回归。λ是这里经常微调的正则化参数。**

岭回归成本函数

使用与上一节相同的逻辑,我们对该函数进行微分,并将其设置为零,求解θ以得出正则化法线方程。****

正则正规方程

这里,M 是一个矩阵,其维数为 (n+1 X n+1) ,对角线上的值为 1,除了左上角的条目为 0 之外,其他地方的值都为 0。比如一个 3X3 M 的矩阵看起来是这样的:****

三维 M 矩阵

哒哒!只要λ严格大于 0,我们可以证明正则化正规方程中的乘积是可逆的。

这是对数学好奇的人的证明!如果你不熟悉线性代数,请跳过它。

****

证据 2

外卖食品

那么梯度下降呢?

到目前为止,我们只谈到了线性回归的正常方程,但如果您使用梯度下降来优化θ呢?虽然从理论上讲,这应该会给你一个解决方案,事实证明,由于未知因素多于特征,我们有多个解决方案,这个解决方案可能不能很好地推广。添加正则化项将有助于进一步约束目标,并使解偏向θ的“小”值(输入的小变化不会转化为输出的大变化)。这通常会帮助我们收敛到一个更通用的解决方案。

这类问题在实践中是如何处理的?

通常,当我们试图解决一个回归问题时,当我们面临特征多于数据点的问题时,我们会这样做。

  1. 选择山脊(L2)或拉索回归(L1)
  2. 使用 K 倍交叉验证并调整正则化参数(λ)
  3. 在调整严格大于 0 的λ之后,应该会产生比普通最小二乘回归更好的性能
  4. 在一些极端的情况下,调整后,如果λ结果为零,这将意味着问题本身并不适合算法,正则化不会给出比 OLS 更好的解决方案

我知道我谈到了极端的例子,我们只有 1 或 2 个数据点,但在实践中,你会面临大约 500 个数据点和大约 5000 个特征的问题,让你选择调整 lambda。

结论

除了更著名的(解决过度拟合)之外,我们还看到了一个有趣的正则化用例。我们也看到了数学证明,显示了正则化如何解决我们的目标。不过,我希望你小心谨慎。仅仅因为正规化找到了解决方案,并不意味着这是最好的方案。事实上,正则化将有助于比 OLS 执行得更好,但其他最大似然算法可以更好地解决你的问题!****

此外,还有其他方法,比如降维,来解决特征多于数据点的问题

如果你喜欢这篇文章,这里有更多!

其他一些项目。可以联系我 这里 感谢您的配合!

过度参数化但一般化的神经网络

原文:https://towardsdatascience.com/overparameterized-but-generalized-neural-network-420fe646c54c?source=collection_archive---------20-----------------------

为什么你的深度神经网络在测试数据上表现很好?

信用:Maximalfocus Unsplash

深度学习已经从只是参数化的非线性函数发展到用于主要的计算机视觉和自然语言处理任务。分段非线性网络能够形成数据的非平凡表示。尽管这些网络已经非常成功,但是在他们对为什么通过找到问题的近似最优解而表现如此之好的理解之间还有许多差距。

这些模型给出的训练误差为 0,因此高度过拟合训练数据,但仍然能够给出良好的测试性能。

这种良性的过度拟合似乎与公认的统计学智慧相矛盾,统计学智慧坚持在模型的复杂性及其与数据的拟合之间进行权衡。因此,有必要研究这一有趣的现象来填补空白。

什么是泛化?

假设我们的任务是将一组数据点 X 映射到它们的标签Y。我们定义一个函数 f: X- > Y 。这里的基本假设是数据是独立同分布的,这意味着每个数据点都是彼此独立随机生成的。

选择 f 可以有很多种方式。其中一种方法是让数据分布 X 决定 f 应该是什么,假设这是 f^ 。现在,我们希望 f^ 给出好的预测,这样f^风险

是最小值。 风险 基本上就是损失的预期。有办法保证这一点吗

对于大样本量 n,输出较小。这里 f* 是描述数据的最佳函数。

这给了我们一个衡量我们的模型在未知样本上表现如何的标准。这里需要注意的一点是,如果我们有足够数量的样本,这两项将会收敛。

但在现实生活中并非如此。我们需要知道在一个特定的模型上,我们的模型在 n 个样本的情况下会犯多少错误,因此我们的模型会有多好。

泛化为我们提供了一个在没有看到数据的情况下,我们的模型将执行的最高错误数的界限。

你不觉得这对量产的车型超级重要吗?我们可以找出我们的模型可能犯的最多的错误!

概括方法

传统的一般化方法采用模型容量的观点,其中一般化的能力由假设类 H 的复杂性(容量)来建模。其中假设类是所有可能符合数据的函数 f (见第一节)。一些传统的方法包括 VC 维、Rademacher 复杂度和 PAC-Bayes 界。

  1. VC dimension- 衡量算法可以学习的一组函数的能力。它由算法能够粉碎的最大点集来衡量。f 被认为分解了一组数据点,如果对于这些点的所有标签分配,存在一个函数使得 f 在对这些点求值时没有错误。
  2. Rademacher complexity- 一类实值函数丰富性的度量,因此是一个假设类拟合二元标签的能力。
  3. 大概正确- 如【3】所述

来自[3]的定义

简单来说:PAC 的主要目标是分析一个模型是否以及在什么条件下可能输出一个近似正确的分类器。在这里,我们可以通过以下方式定义近似的

其中 D 是输入的分布,h 是假设。接下来,我们如何定义“大概”?如果我们的模型将以概率 1-δ输出这样一个分类器,其中 0≤δ≤1/2,我们称该分类器可能近似正确。知道目标概念是 PAC 可学习的,允许您限制可能学习近似正确的分类器所需的样本大小。

神经网络中的泛化

实证研究的方法

社区提出了各种理论和经验结果。[2] 通过系统地改变超参数对 40 个测量值进行了研究。他们训练了大约 10000 个卷积网络,以了解泛化和不同超参数设置之间的关系。他们发现了 PAC-Bayesian 界限的潜力和基于规范的措施的失败。

通过随机测试探索普遍性

张等[1]的论文进行了随机测试,用随机标签代替真实标签。理想情况下,模型的性能应该不会很好。但令他们惊讶的是,他们发现~深度神经网络很容易以 0 的训练误差拟合随机标签。

仅通过随机化标签,我们就可以在不改变模型、其大小、超参数或优化器的情况下,迫使模型的泛化误差大幅上升。

他们还用完全随机的像素(例如高斯噪声)代替真实图像,并观察到卷积神经网络继续以零训练误差拟合数据。这表明,尽管它们的结构不同, 卷积神经网络可以拟合随机噪声。

他们进一步改变随机化的量,在无噪声和完全噪声的情况之间平滑地插值,以观察当我们增加噪声水平时泛化误差的稳定恶化。这表明神经网络能够捕捉数据中的剩余信号,同时使用蛮力拟合噪声部分。

表征学习视角

周 Z-H[4]对这个问题给出了一个非常不同的视角。他对为什么过度参数化不会过度拟合的回答导致了一个事实-

深度网络将 特征学习分类器训练相结合。所有传统的学习理论主要关注学习者的训练,或者更具体地说,来自特征空间的分类器的训练,但是很少关注特征空间本身的构造。

深度学习结合了分类器构造和特征学习

因此,传统的学习理论可以用来理解概括的行为,但是当它被应用到表征学习的时候就必须小心了。因此,需要对表征学习的一般化做特殊的工作。

实证方法

NeurIPS 竞赛关于预测深度学习中的泛化(NeurIPS 2020)的获奖方案【5】。声称理论上的界限通常被证明在实际设置中没有用。他们在不查看测试数据的情况下给出了训练数据的泛化错误。他们利用表征的两个特征- 一致性稳健性来衡量泛化。他们对他们的方法有如下的看法-

如果深度神经网络将相同的标签分配给两幅图像,它们必须在网络的某个阶段收敛到相似的表示。

测量网络内部表示的一致性将会告诉我们这个网络的泛化能力。

模型对输入空间中似是而非的扰动的鲁棒性是泛化能力的另一个标志。

为了测量网络表示对有效或似是而非的扰动的鲁棒性,他们使用了 Mixup。在 Mixup 中,他们检查相同标签内输入样本线性组合的模型性能

样本离被归入另一类有多远。

他们证明了扩大的边际分布作为泛化的度量,可以考虑过度拟合和异常样本。

优化视角到泛化

Google[7]给出了泛化的在线优化视角。他们给出了一个深度引导框架,其中他们将数据有限的训练世界与数据无限的理想世界进行了比较。先验,人们可能期望现实世界和理想世界可能彼此无关,因为在现实世界中,模型从分布中看到有限数量的例子,而在理想世界中,模型看到整个分布。但在实践中,他们发现真实模型和理想模型实际上有相似的测试误差。

在存在无限训练数据(理想世界)和存在有限数据(现实世界)的场景中的训练给出相似的测试误差,直到现实世界收敛。

因此,人们可以通过研究模型在理想世界中的相应行为来研究现实世界中的模型。好的模型和训练程序是那些(1) 在理想世界中快速优化和(2) 在现实世界中不太快速优化的模型和训练程序。每当一个人做出影响现实世界中的普遍性的改变时(架构、学习速度等)。),应该考虑它对(1)测试误差的理想世界优化(越快越好)和(2)训练误差的现实世界优化(越慢越好)的影响。

结论

从统计学的角度来看,神经网络中的过度参数化使它们变得有趣。这篇文章简单介绍了传统的测量泛化能力的方法,这些方法并不直接适用于深度学习。已经从表示学习和优化的角度提供了不同的视角来解释神经网络所实现的高测试性能。

[1] 理解深度学习需要重新思考泛化(arxiv.org)

[2]1912.02178.pdf(arxiv.org)

[3]0211.pdf(princeton.edu)

[4]sciChina20over.pdf(nju.edu.cn)

[5]【2012.02775】基于表征的复杂性度量用于预测深度学习中的泛化(arxiv.org)

[6]【arxiv.org 【2010.08127】深度引导框架:好的在线学习者是好的离线概括者

【2103.09177.pdf(arxiv.org)

过采样:主成分分析-KNN 方法

原文:https://towardsdatascience.com/oversampling-a-pca-knn-approach-f392ca232486?source=collection_archive---------17-----------------------

利用多数类信息改进预测

https://jovian . ai/ana prec 07/PCA-KNN-article-notebook-breatcancer

在本文中,我将讨论一种使用 PCA 降维和 K-最近邻算法的过采样方法。它包括(1)预处理特征以缩放它们、去除空值和去除离群值;(2)通过主成分分析降低它们的维数;(3)使用 KNN 算法找到与少数类观察足够相似的多数类观察,以使它们被错误地认为是少数类。

请随时通过这个木星笔记本跟随练习。

我将使用通过 scikit-learn 图书馆获得的乳腺癌数据集。在笔记本中,我对数据集进行了重新采样,以创建一个新的高度不平衡的版本,它有 248 个观察值,其中只有 36 个是阳性的——换句话说,14%。使用 train_test_split,我们将数据集分为训练(70%)和测试(30%)。

在评估我在本文中提出的 PCA KNN 过采样方案之前,我们需要一个基准。为此,我们将创建两个基本模型,它们直接根据我们新创建的功能进行训练。为了多样性,我们将看看 SVM,决策树分类器,随机森林和梯度推进。

接下来,我们将使用基本算法预测我们的测试集,并创建一个函数来帮助我们通过在一个清晰有序的 pandas 表中选择的指标(平均精度、Breier 得分损失、ROC AUC)来评估它们的性能。让它成为一个预先定义的函数的目的是为了我们将来可以重用它。

这是我从 sklearn 文档中直接引用的一个度量词典。

度量字典:

  • average _ precision _ score:“AP 将精度-召回曲线总结为每个阈值下达到的精度的加权平均值,召回率从前一个阈值的增量作为权重。这种实现不是内插的,并且不同于用梯形规则计算精度-召回曲线下的面积,梯形规则使用线性内插并且可能过于乐观”。
  • Brier _ score _ loss:“Brier 分数损失越小越好,故以“损失”命名。Brier 评分衡量预测概率和实际结果之间的均方差。Brier 分数总是取 0 和 1 之间的值,因为这是预测概率(必须在 0 和 1 之间)和实际结果(只能取 0 和 1 之间的值)之间的最大可能差异。
  • roc auc :“根据预测得分计算受试者工作特征曲线下面积(roc auc)”。

基本模型结果:

提议的过采样技术:主成分分析 KNN

接下来,我们将尝试一种方法,在这种方法中,我们将使用主成分分析和 KNN,以便将一些负面观察转化为正面观察,并提高我们的机器学习模型的质量。

在下面的 cod 中,我们将创建一个表,通过该表我们将选择哪些是多数类观测值,我们希望通过少数类观测值切换到 fakely,以便我们可以丰富我们接下来要训练的模型。

如前所述,我们预处理数据(电源变压器和标准定标器),对其应用主成分分析,然后用 KNN 识别这些我们将切换的观察值。

这是我们使用的 PCA 组件的漂亮的 seaborn pairplot 图:

在这里,我们使用生成的数据来训练和预测 KNN:

我们为多数类观察选择了一个阈值截止点,我们将切换到少数类,我们用它们创建新的目标。

在笔记本中,阈值设置为 0.3。通过这种方式,我们获得了 5 个新的积极观察值——这听起来可能不多,但比我们在训练集中的原始数量增加了 20%。

我们在这里训练模型:

和他们一起预测:

结论——这意味着什么?

这意味着过采样方法确实产生了稍微好一点的模型。正如你在木星笔记本上看到的,如果我们以预测值 0.97 为分界点,我们会得到 7 个正确的预测值,而不是以前的 3 个。另一个优点是,该技术在不影响或夸大模型特征重要性的情况下实现了更高的性能。它有助于一种侵入性更小的过采样技术,同时仍然改善基本预测。

https://www.linkedin.com/in/anapreciado/

缓解过拟合问题的 4 种模型验证方法概述

原文:https://towardsdatascience.com/overview-of-4-model-validation-approaches-to-mitigate-overfitting-problem-6d2eecdf8053?source=collection_archive---------24-----------------------

本文是一篇 全面概述 的四(4)个模型验证策略以构建健壮的模型

图片由杰奎琳·马库提供,来自 Pixabay

为什么模型验证很重要

未经验证而训练的模型可能会过度拟合测试数据。如果我们只处理两组数据,即训练和测试数据,这种情况很可能发生。

(图片由作者提供)

为了减少测试数据的过度拟合,您将需要验证。在本文的其余部分,我们将讨论不同的验证方法,从单一交叉验证(最不健壮)到 k 重交叉验证的不同变体(更健壮)。

单一交叉验证

这是您可以执行的最简单的验证方法。它涉及到三组数据的使用:训练数据验证数据测试数据。典型的划分是 80%用于培训,10%用于验证,10%用于测试。

如果 y 你有 N 个候选模型( N 在下图的例子中是 4),这些模型将使用训练数据进行训练,并使用验证数据进行评估。评估的过程是超参数调整。一旦找到可能的最佳模型,它将在测试数据上运行,以便了解它在现实世界中的表现。总的来说,我们有 N 个训练过程N 个验证过程只有 1 个测试过程

(图片由作者提供)

这种方法的问题是,在拆分之后,验证集中的数据将永远不会用于训练模型。此外,由于训练和验证分割的随机性,您可能会选择一个恰好给出非常差的结果,或者可能给出很好的结果的分割。我们将看到如何应用更健壮的技术来缓解这些问题。

K 重交叉验证的不同变体

对于每个候选模型,这些方法包括使用训练数据的不同子集重复训练和验证。这是一个非常稳健的数据,不会浪费数据,因为每个观察值都用于训练和验证。使用这种方法与 N 候选模型和 K 折叠,你将运行 NxK 训练N 个验证过程 ,但是 只有 1 个测试过程

遗漏一个交叉验证

假设您有一个大小为 N 的训练数据,当使用这种方法时,您首先保持第一个观察值,在剩余的 N-1 观察值上训练您的模型,并在保持观察值上评估它。然后,维持第二次观察,在 N-1 剩余观察上训练模型,并在维持(第二次观察)上评估模型。同样的过程也适用于第三次观察,以此类推。在这个过程的最后,你将对每个观测值进行一次精确的测量,并将得到 N 的评估值。最终的评估指标是 N 值的平均值。

(图片由作者提供)

这种技术的好处是,它确保每一个观察结果都用于培训和评估。然而,这可能非常耗时且计算量大,因为只有一个模型被训练 N 次。此外,如果您有 M 个候选模型,则每个模型都将在所有这些分割上进行训练和验证,这将增加很多计算时间。

k 重交叉验证

这种方法类似于省去一个交叉验证,但是在模型性能方面,极大地改进了计算时间,而没有损失太多。它不是一次只保留一个观察值,而是将训练数据拆分成相等数量的数据(称为折叠)。

(图片由作者提供)

训练数据被分成 5 个相同大小的不同数据,在本例中,我们执行 5 重交叉验证。在每次迭代中,模型在 4/5 的数据上进行训练,在剩下的 1/5 的数据上进行验证

  • 从分割 1 开始,折叠 1 至 4 用于训练模型,折叠 5 用于验证模型。
  • 从分割 2 开始,折叠 1 至 3 和 5 用于训练模型,折叠 4 用于验证模型。
  • 执行相同的过程直到分割 5,并且这适用于所有模型。

数据中的每个观察值用于验证一次,单个模型的整体性能通过平均所有分割的所有性能获得。在所有模型的训练结束时,最好的模型是具有最高性能值(最低误差值)的模型。然后对测试数据运行最佳模型,以获得对未知数据的性能评估。

K-folds 改进了留一交叉验证,但是在将训练数据分成不同的 folds 时,它们都没有考虑到类/标签,这可能是一个缺点,因为一些标签可能在一些 folds 中不被表示。

分层 K 重交叉验证

这种方法在分割成折叠时考虑训练数据的标签/类别,并确保每个折叠具有不同类别的表示。假设原始数据被分类为“疟疾”和“疟疾”,每个文件夹将具有整个数据中存在的“疟疾”或“非疟疾”的近似代表性混合。

假设训练数据有 100 个观测值,80 个“疟疾”,20 个“非疟疾”。如果您决定应用 10 倍验证,每个折叠将有大约 8 个“疟疾”和 2 个“非疟疾”

文章结尾

我希望您喜欢这篇文章。如果您有任何问题或意见,我将很高兴欢迎他们进行进一步的讨论。如需进一步阅读,请随时查阅以下链接:

https://sci kit-learn . org/stable/modules/cross _ validation . html

再见🏃🏾

相册概述:用于高级图像增强的开源库

原文:https://towardsdatascience.com/overview-of-albumentations-open-source-library-for-advanced-image-augmentations-c821a025c2ca?source=collection_archive---------31-----------------------

实践教程

带有关于增强和集成 PyTorch 和 Tensorflow 管道的代码片段

作者图片

原生 PyTorch 和 TensorFlow 增强器有一个很大的缺点,它们不能同时增强图像及其分段遮罩、边界框或关键点位置。所以有两个选择——要么自己写函数,要么用第三方库。两个我都试过了,第二个选择更好🙂

为什么是白蛋白?

albuminations是我尝试过的第一个图书馆,我一直坚持着,因为:

  • 它是开源的,
  • 直觉,
  • 快,
  • 拥有超过 60 种不同的增强功能,
  • 证据充分,
  • 最重要的是,可以同时增强图像及其分段遮罩、边界框或关键点位置。

还有两个类似的库——img augAugmentor 。不幸的是,我不能提供任何比较,因为我还没有尝试过。直到现在,白蛋白已经足够了。

简短教程

在这个简短的教程中,我将展示如何用几行代码轻松地增强图像以用于分割和对象检测任务。

如果你想跟随这个教程:

  1. 安装抛光垫。我真的建议检查你是否有最新的版本,因为旧的版本可能会有问题。我用的是 1.0.0 版本,运行良好。
  2. 下载标签如下的测试图像。这只是来自 COCO 数据集的随机图像。我稍微修改了一下,然后按照相册要求的格式保存了下来。该库接受 NumPy 数组形式的图像、NumPy 数组形式的分段遮罩和列表形式的边界框。

在这里下载。

让我们加载图像、它的二进制像素分割蒙版和一个边界框。边界框被定义为 4 元素列表— [x_min,y_min,width,height]。

import pickle 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches# load data
with open("image_data.pickle", "rb") as handle:
    image_data = pickle.load(handle)image = image_data["image"]
mask = image_data["mask"]
bbox = image_data["bbox_coco"]# visualize data
fig, ax = plt.subplots(1, 2, figsize=(12, 5))
ax[0].imshow(image)
ax[0].set_title("Image")
ax[1].imshow(image)
bbox_rect = patches.Rectangle(
    bbox[:2], bbox[2], bbox[3], linewidth=2, edgecolor="r", facecolor="none"
)
ax[1].add_patch(bbox_rect)
ax[1].imshow(mask, alpha=0.3, cmap="gray_r")
ax[1].set_title("Image + BBox + Mask")
plt.show()

在加载并可视化图像后,您应该会看到:

图像。运行图像及其标签可视化代码时的输出。分割遮罩被可视化为透明的黑白图像(1 为黑色,“马”)。作者图片

用于分割的掩模增强。现在我们可以从白蛋白开始。这里的转换定义非常类似于 PyTorch 和 TensorFlow (Keras API):

  • 通过使用 Compose 对象组合几个扩充来定义转换。
  • 每个增强都有参数“p ”,即要应用的概率,此外还有特定于增强的参数,如 RandomCrop 的“width”和“height”。
  • 使用定义的变换作为函数来增加图像及其遮罩。这个函数返回一个包含关键字“图像”和“遮罩”的字典。

下面是如何用随机 256×256 裁剪(总是)和水平翻转(仅在 50%的情况下)来增加图像(及其遮罩)的代码。

import albumentations as A# define agumentation
transform = A.Compose([
    A.RandomCrop(width=256, height=256, p=1),
    A.HorizontalFlip(p=0.5),
])# augment and visualize images
fig, ax = plt.subplots(2, 3, figsize=(15, 10))
for i in range(6):
    **transformed = transform(image=image, mask=mask)**
    ax[i // 3, i % 3].imshow(transformed["image"])
    ax[i // 3, i % 3].imshow(transformed["mask"], alpha=0.3, cmap="gray_r")
plt.show()

结果,你应该得到这样的东西。您的增强图像会有所不同,因为白蛋白会产生随机转换。关于面罩增大的详细教程,请参考原始文档

形象。运行用于同时增强图像和遮罩的代码时的输出。
分割蒙版被可视化为透明的黑白图像(1 为黑色,‘马’)。作者图片

用于对象检测的包围盒增强。然而,它类似于分段遮罩的增强:

  • 此外,定义“bbox_params ”,其中指定边界框的格式和边界框类的参数。“coco”表示 COCO 数据集格式的边界框— [x_min,y_min,width,height]。参数“bbox_classes”将在后面用于传递边界框的类。
  • ` transform '接受边界框作为列表的列表。此外,即使图像中只有一个边界框,它也需要边界框类(作为列表)。

下面是对图像及其边界框同时进行 RandomCrop 和 HorizonalFrip 的代码。

# define augmentation 
transform = A.Compose([
     A.RandomCrop(width=256, height=256, p=1),
     A.HorizontalFlip(p=0.5), 
], **bbox_params=A.BboxParams(format='coco', label_fields=["bbox_classes"])**)# augment and visualize 
bboxes = [bbox]
bbox_classes = ["horse"]fig, ax = plt.subplots(2, 3, figsize=(15, 10))
for i in range(6):
 **transformed = transform(
        image=image, 
        bboxes=bboxes, 
        bbox_classes=bbox_classes
    )**
    ax[i // 3, i % 3].imshow(transformed["image"])
    trans_bbox = transformed["bboxes"][0]
    bbox_rect = patches.Rectangle(
        trans_bbox[:2],
        trans_bbox[2],
        trans_bbox[3],
        linewidth=2,
        edgecolor="r",
        facecolor="none",
    )
    ax[i // 3, i % 3].add_patch(bbox_rect)
plt.show()

这是结果。如果您需要一些特定的边界框扩充,请参考原始文档

图像。运行同步图像
和边界框扩充代码时的输出。作者图片

多个目标的同时增强。除了允许同时增加几个遮罩几个边界框之外,Albumentations 还有一个功能可以同时增加不同类型的标签,例如,一个遮罩和一个边界框。

当调用“转换”时,简单地给它你所拥有的一切:

# define augmentation 
transform = A.Compose([
     A.RandomCrop(width=256, height=256, p=1),
     A.HorizontalFlip(p=0.5), 
], bbox_params=A.BboxParams(format='coco', label_fields=["bbox_classes"]))# augment and visualize 
bboxes = [bbox]
bbox_classes = ["horse"]fig, ax = plt.subplots(2, 3, figsize=(15, 10))
for i in range(6):
    **transformed = transform(
        image=image, 
        mask=mask, 
        bboxes=bboxes, 
        bbox_classes=bbox_classes
    )**
    ax[i // 3, i % 3].imshow(transformed["image"])
    trans_bbox = transformed["bboxes"][0]
    bbox_rect = patches.Rectangle(
        trans_bbox[:2],
        trans_bbox[2],
        trans_bbox[3],
        linewidth=2,
        edgecolor="r",
        facecolor="none",
    )
    ax[i // 3, i % 3].add_patch(bbox_rect)
    ax[i // 3, i % 3].imshow(transformed["mask"], alpha=0.3, cmap="gray_r")
plt.show()

您的结果将如下图所示。这里是关于那个的更详细的文档。

形象。运行同步图像、分割遮罩、
和边界框增强代码时的输出。分割蒙版被可视化为透明的
黑白图像(1 为黑色,‘马’)。作者图片

还有更多。albuminations 有更多可用的功能,例如对关键点自动增强的增强。它包括大约 60 种不同的增强类型,字面意思是你需要的任何任务。

最有可能的是,你将使用白蛋白作为 PyTorch 或 TensorFlow 培训管道的一部分,所以我将简要描述如何做。

PyTorch 。当创建自定义数据集时,在 __init__ '函数中定义 Albumentations 转换,并在 getitem '函数中调用它。PyTorch 模型要求输入数据是张量,所以确保在定义“transform”时将“ToTensorV2”作为最后一步添加(这是一个来自 Albumentations 教程之一的技巧)。

from torch.utils.data import Dataset
from albumentations.pytorch import ToTensorV2class CustomDataset(Dataset):
    def __init__(self, images, masks):
        self.images = images  # assume it's a list of numpy images
        self.masks = masks  # assume it's a list of numpy masks
        **self.transform = A.Compose([
            A.RandomCrop(width=256, height=256, p=1),
            A.HorizontalFlip(p=0.5),
            ToTensorV2,
        ])** def __len__(self):
        return len(self.images) def __getitem__(self, idx):
        """Returns a single sample"""
        image = self.images[idx]
        mask = self.masks[idx]
        **transformed = self.transform(image=image, mask=mask)
        transformed_image = transformed["image"]
        transformed_mask = transformed["mask"]**
        return transformed_image, transformed_mask

TensorFlow (Keras API)也允许创建自定义数据集,类似于 PyTorch。因此,在“init”函数中定义 Albumentations 转换,并在“getitem”函数中调用它。很简单,不是吗?

from tensorflow import kerasclass CustomDataset(keras.utils.Sequence):
    def __init__(self, images, masks):
        self.images = images
        self.masks = masks
        self.batch_size = 1
        self.img_size = (256, 256)
        **self.transform = A.Compose([
            A.RandomCrop(width=256, height=256, p=1), 
            A.HorizontalFlip(p=0.5),
        ])** def __len__(self):
        return len(self.images) // self.batch_size def __getitem__(self, idx):
        """Returns a batch of samples"""
        i = idx * self.batch_size
        batch_images = self.images[i : i + self.batch_size]
        batch_masks = self.masks[i : i + self.batch_size]
        batch_images_stacked = np.zeros(
            (self.batch_size,) + self.img_size + (3,), dtype="uint8"
        )
        batch_masks_stacked = np.zeros(
            (self.batch_size,) + self.img_size, dtype="float32"
        )
        for i in range(len(batch_images)):
            **transformed = self.transform(
                image=batch_images[i], 
                mask=batch_masks[i]
            )
            batch_images_stacked[i] = transformed["image"]
            batch_masks_stacked[i] = transformed["mask"]**
        return batch_images_stacked, batch_masks_stacked

就是这样!希望这篇教程鼓励你下次在做分割、物体检测或关键点定位任务时尝试 Albumentations。如果有,请告诉我!

原载于notrocketseconomy . blog

如果你想阅读更多类似的教程,可以订阅我的博客“非火箭科学”——电报 推特

分类器概述

原文:https://towardsdatascience.com/overview-of-classifiers-d0a0d3eecfd1?source=collection_archive---------22-----------------------

对分类、模型概述和其中重要概念的简要介绍

多元高斯分布中不同协方差矩阵的图示。图片作者。

内容

这篇文章是我将要发表的一系列文章的一部分。你可以通过点击这里在我的个人博客上阅读这篇文章的更详细版本。下面你可以看到该系列的概述。

1.机器学习导论

2.回归

3.分类

分类器的类型

正如在系列文章的第一篇中提到的,在分类中,目标变量的可能值是离散的,我们称这些可能值为“类”。在 2(a)2(b) 中,我们经历了回归,简而言之,这是指从数据集 X 中构造一个函数 h ( x ),该函数为新的值 x 产生预测值 t 。分类的目的是相同的,除了 t 的值是离散的。

我们将讨论 3 种不同的方法或分类器类型:

  • 生成分类器,对输入和目标变量 Pr 的联合概率分布进行建模( xt )。
  • 鉴别分类器,其对给定输入变量 Pr( t | x )的目标的条件概率分布进行建模。
  • 不使用概率模型但直接将输入分配给目标变量的无分布分类器

这个主题的一个快速声明:术语会很混乱,但是当我们跨越这些桥梁时,我们会处理它。

生成性与鉴别性

下面是我们将要讨论的分类器列表:对于生成分类器来说,它是二次判别分析(QDA)线性判别分析(LDA) 和(高斯)朴素贝叶斯,它们都是同一模型的特例;对于歧视分类器来说是逻辑回归;对于无分布分类器,我们将看看感知器以及支持向量机(SVM)

所以,他们都做同样的事情(分类)。哪个最好?你应该用哪一个?好吧,让我们回忆一下“没有免费的午餐”定理,它概括地说,没有一个模型总是比另一个更好。它总是取决于你的数据。也就是说,关于生成性和区别性量词,我们可以说一些事情。Ng 和 Jordan (2002)发现,重复将朴素贝叶斯和逻辑回归应用于二元分类任务的实验,朴素贝叶斯(生成型)在数据较少的情况下表现更好,但逻辑回归通常表现更好 [1]。然而,Ulusoy 和 Bishop (2006)指出,只有当数据遵循生成模型的假设时才会出现这种情况【2】,这意味着逻辑回归(判别)通常优于朴素贝叶斯(生成)。

普遍的共识是,在大多数情况下,判别模型优于生成模型。其原因是,生成模型在某种程度上有更困难的工作,因为它们试图模拟联合分布,而不仅仅是后验分布。他们还经常对数据做出不切实际的假设。然而,怎么强调都不为过,尽管情况并非总是如此,而且你不应该忽视生成模型。例如,生成对抗网络(GANs)是一种生成模型,已经证明在各种任务中非常有用。还有一些其他的原因可以解释为什么你不应该忽视生成模型,例如,它们更容易适应。无论如何,我们在这里不是要找出使用哪种模型,而是要了解这两种模型。

重要工具

多元高斯分布

在接下来的文章中,我们将非常依赖多元高斯(正态)分布,掌握它非常重要。多元高斯分布表示为 N ( μσ),其中 μ 为均值向量,σ为协方差矩阵。 D 维的概率密度函数定义为

协方差矩阵决定了高斯分布的形状,对于我们将要研究的分类器来说是一个重要的概念。下图展示了不同类型的协方差矩阵。

多元高斯分布中不同协方差矩阵的图示。图片作者。

贝叶斯定理

我们要使用的另一个重要工具是贝叶斯定理。如果你没有读过关于频率主义和贝叶斯主义的文章,那么这里有一个关于贝叶斯定理的快速回顾。给定两个事件 AB ,我们可以用条件概率扩展它们的联合概率

利用右边的等式,我们可以改写它,得到贝叶斯定理

就假设和数据而言,我们经常使用后验、似然、先验和证据来指代贝叶斯定理的部分

我们经常这样写

其中∝表示“成比例”。

参考

[1] Andrew Y. Ng 和 Michael I. Jordan,“判别型和生成型分类器:逻辑回归和朴素贝叶斯的比较”,2001 年。

[2] Ilkay Ulusoy 和 Christopher Bishop,“用于对象检测和分类的生成和鉴别技术的比较”,2006 年。

数据相关角色概述

原文:https://towardsdatascience.com/overview-of-data-related-roles-70ca48f8deed?source=collection_archive---------42-----------------------

不同视角的数据

马库斯·斯皮斯克在 Unsplash 上的照片

毫无疑问,数据世界是一个有利可图的世界。早在 15 年前的 2006 年,英国数学家 Clive Humby 就将其称为“新石油”,现在人们似乎真的开始见证数据在商业中的影响,现在每个人都想分一杯羹。

“我们每天产生的数据量真的令人难以置信。以我们目前的速度,每天会产生 2.5 万亿字节的数据,但随着物联网(IoT)的发展,这一速度只会越来越快。”— 我们每天创造多少数据?每个人都应该知道的惊人数据 ,《福布斯》杂志,2018 年

与石油不同,数据不会“用完”,因为数据可以无限更新。相比之下,我们说这两者在某种意义上是相似的,就像石油一样,原始数据本身没有价值。为了从数据中产生任何价值,数据应该在一个被称为“预处理”的过程中被严格地提炼。

随着一个看起来像怪物一样的行业的出现,许多新的角色被嵌入到允许市场运行的生态系统中。到目前为止,大数据的爆发创造了 4 个主要角色,但由于该行业的新生性质,许多角色都没有明确定义,并且可能都属于一个总括术语“数据科学”,具体取决于公司。

注意:我使用了 TargetJobs 来大致了解每项工作所涉及的职责(每项工作部分的要点摘自其工作描述)。

数据科学家

数据科学家将分散的数据转化为清晰可行的见解。通过进一步推断和分享获得的见解,数据科学家有能力解决这个星球上一些最大胆的问题。

从本质上讲,数据科学家将计算机科学技能与统计、概率、数学、分析、建模和商业智慧相结合,以帮助发现重要问题的答案,从而帮助公司做出客观决策。

作为一名数据科学家,您将负责确定组织内需要改进的关键领域,通过数据科学的视角来研究问题,并通过使用先进的技术来实施多项关键计划,以提高业务绩效和收入。— 工作委员会的数据科学家职责。

在这些职责中,数据科学家需要与技术和非技术受众沟通,提出建议以适应现有的业务战略,并从多个来源提取数据。

这个角色非常重要,涵盖了时间序列、自然语言处理和计算机视觉等广泛的任务。

数据分析师

数据科学家的近亲是数据分析师。数据分析师在各种分析工具的帮助下仔细检查信息,以识别事实和趋势,再次帮助员工、客户或两者做出更明智的决策。

许多婴儿潮一代(没有接受过技术背景培训的人)希望从事数据科学职业,他们倾向于利用数据分析师的角色来启动他们在数据领域的职业生涯,然后完全转变为数据科学家。

数据分析师的职责包括执行分析以确定所呈现数据的含义,根据分析准备报告,向高级职员呈现报告,分析数据质量,以及删除损坏的数据。

数据科学家和数据分析师之间的界限可能非常模糊。一些人说,区别因素是数据科学家使用模型进行预测,尽管数据分析师也可能这样做。我更喜欢 Harpreet Sahota 给我的描述—

“数据科学家发现,数据分析师分析”。

数据工程师

数据工程师负责构建数据管道,将原始的非结构化数据转换为清晰的格式,从而使数据科学家能够继续施展他们的魔法。本质上,他们的角色包括创建和维护分析基础架构,该基础架构开启了几乎所有其他数据功能,即数据库、服务和大规模处理系统。

这个角色是相当密集的,需要大量的技术技能,如 SQL 数据库设计和多种编程语言的深厚知识。然而,为了有效地工作,数据工程师还应该具有非常好的软技能,因为他们经常需要跨一系列不同的部门工作,以便了解高级管理层试图从公司数据中实现什么。

在用数据函数实现业务和/或客户对象的需求中,数据工程师还需要构建算法来提供对原始数据的更容易的访问。

总而言之,数据工程师将正确的数据放在正确的位置。

机器学习工程师

机器学习工程师位于软件工程和数据科学的交叉点。根据跳板定义,机器学习工程师“利用大数据工具和编程框架,确保从数据管道收集的原始数据被重新定义为随时可以按需扩展的数据科学模型”——通俗地说,他们将数据科学家构建的机器学习模型部署到生产中。

这个角色包括合并软件工程最佳实践的知识以及各种数据科学技术,如机器学习、深度学习和统计模型,以便将数据输入模型。

通常,机器学习工程师的角色和职责往往比数据科学家的角色和职责设计得好得多。这一壮举是因为一个简单的事实,即要雇用一名机器学习工程师,你首先必须对如何以及为什么要利用机器学习有一个非常好的认识。

包裹

有各种方法可以进入数据世界。虽然我只列出了 4 个,但还有其他一些头衔,比如研究科学家和决策科学家。我通常发现,研究科学家的角色通常与更具研究性的任务相关,如开发新算法(从而使其更具学术性,而不是实用性),而决策科学家更实际,更专注于在决策方面构建数据分析。我决定在这篇文章中不包括这两个角色,原因有二:

  1. 我主要在大公司看到他们
  2. 它们主要应用于研究(谈论研究科学家)

这使得他们不符合我的名单,虽然没有过时的数据相关的角色。

感谢阅读!在 LinkedIn 和/或 Twitter 上与我联系

与本文相似的帖子:

什么是集成学习?

原文:https://towardsdatascience.com/overview-of-ensemble-learning-c216a9f6c04?source=collection_archive---------25-----------------------

简单的集合方法,装袋,引导,助推

来自 Unsplash 的夏洛特·诺勒的照片

想象一下,你计划去度假,还没有决定去哪里(是的,在 covid 期间,我只能梦想旅行)。你不能自己决定,因此你想收集更多的信息。你在网上搜索不同旅游目的地的旅游反馈,你向一些朋友寻求建议,最后,你需要根据多种信息来源做出决定。

在生活中做出决定从来都不容易,这也适用于机器学习模型。不同的模型在不同的场景下表现良好。您可以选择运行多个模型并汇总结果,而不是依赖单个模型的结果。

现在问题来了,如何汇总不同模型的结果并做出最终决策?

集成学习模型是多个模型的集合,它结合不同的决策来提高整体性能。本文的主要目的是向您概述不同的集成学习方法如何从不同的模型中聚合结果。

基本集成技术

1.最大投票

你收集完去哪里旅游的建议。你意识到大多数人都推荐你去马尔代夫。嗯,既然大多数人都推荐那个地方,那就不会错。最后,你决定去马尔代夫。

该方法输出具有最高投票的结果,或者您可以将此视为采用所有预测的模式。通常,它应用于分类结果。

最大投票

2.简单平均/加权平均

决定去哪里后,你要决定兑换多少钱。根据你在网上搜索的预算数字和你朋友告诉你的,你应该决定一个数字。

简单平均:你可以对你找到的所有数字进行简单平均。

简单平均数

加权平均:你知道你的一些朋友真的很有钱,所以你没有办法花他们的预算(悲伤故事)。因此,您希望采用加权平均法,并对更适合您个人资料的旅程给予更多权重。

加权平均值

打包/引导汇总

Bagging 超越了基本的集成学习。它不仅依赖于来自多个模型的结果,它让每个模型在原始数据集的不同随机子集上训练(带有替换)

我们为什么要这么做?

一些机器学习模型对训练数据集非常敏感,这意味着它们的模型方差会很高。这并不理想,因为当数据发生变化时,可能会对结果产生很大影响。

这也是一个被称为过度拟合的问题。通过为不同的模型随机选择训练子集,使模型的敏感性多样化,从而减轻过拟合。

作者西拉科恩——自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=85888768

随机森林算法采用 Bagging 技术,通过随机选择数据集的子集来适合不同的决策树。此外,随机森林算法还将模型的待训练特征随机化,这进一步减少了过拟合的机会。

来自 Unsplash 的 Jens Lelie 的照片

这是因为决策树是对他们接受训练的特定数据非常敏感的模型之一。因此,bagging 和随机化特征可以帮助获得将模型应用于测试数据集的更好结果。

助推

Bagging 或其他基本集成学习方法是并行技术,这意味着每个模型在聚合之前独立运行。Boosting 是一种连续的技术,在这种技术中,不同的模型被迭代地添加以提高整体模型性能。

boosting 的思想是将多个弱模型组合起来,形成一个强模型。每个模型都有自己的优势,boosting 试图结合不同模型的优势。

由西拉科恩——自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=85888769

Boosting 通过迭代实现聚合。当一个模型训练数据时,它会将模型结果与地面真实情况进行比较,并找出错误分类的案例。在训练随后的模型时,这些情况被给予更高的权重(意味着错误地计算这些情况将具有更高的惩罚)。结果将是所有模型的加权平均值。

常用的升压方式有 AdaBoost渐变升压光渐变升压机等。我包含了如何使用这些方法的相关文档的链接。不同的方法有不同的性能和运行时。我将在以后的文章中对这些提升方法进行更详细的比较。

在装袋和增压之间选择

这可能是许多人在选择型号时想知道的问题。

这取决于数据以及您选择的基本模型。一般来说,如果单一模型有过度拟合的问题,装袋将是一个更好的选择,因为它减少了模型的方差。如果单个模型的性能较低,您应该考虑使用 boosting 来提高精度。

与装袋技术相比,升压更容易过度拟合。然而,这并不意味着当我们选择助推时,我们对此无能为力。我们可以为 boosting 算法设置一些早期停止标准,这样模型就不会变得过于特定于训练数据。

最后

集成学习通常给出比单一模型更好的性能,因为它减轻了过度拟合问题,并且它结合了不同模型的优势。然而,这可能导致更长的运行时间,并且模型逻辑更难解释

就个人而言,我会推荐使用集成学习模型而不是单一模型,因为该模型的性能和鲁棒性更好。当我们选择集合模型时,我们还应该考虑基础数据和基础模型来做出决定。

GANs 调理方法概述

原文:https://towardsdatascience.com/overview-of-gans-conditioning-methods-edeac018a7f3?source=collection_archive---------27-----------------------

最近,生成对抗网络不仅在计算机视觉问题上,而且在广泛的应用领域都引起了广泛的关注。使用谷歌的 BigGANs英伟达的 StyleGANs ,从高分辨率的训练集中生成新样本和模式的能力成为可能。

GANs 由两个神经网络组成,称为生成器和鉴别器。生成器旨在生成与训练集中的样本相似的随机样本,而鉴别器旨在区分生成的样本和真实样本。这两个网络被对立地训练;发生器被优化为将产生的样本推向正侧,而鉴别器被优化为将它们推向负侧。

GANs 的一个突出变体是条件 GANs ,其中一些附加信息被传递给发生器和鉴别器网络。该信息通常表示训练集中的类,例如,在 MNIST 数据集的情况下,不同的数字。使用 cGANs 不仅可以有条件地生成样本,还可以提高生成样本的质量。

在这篇博客中,我们将简要讨论一些最常用的条件反射方法如下:
1-串联条件反射。
2-使用辅助分类器进行调节。
3-投射条件反射。
4-有条件的批量标准化。

串联调节:

将条件集成到网络中的最简单的方法是将其连接到第一层,即,在传递到生成器和转发到鉴别器的图像之前,将其连接到 z 向量。如图 1 所示,这种方法在第一篇关于 cgan(条件生成对抗网)的论文中使用过。

图 1,串联调节[ 来源

该方法的扩展版本用于(生成对立文本到图像合成)中,他们使用可学习函数(如线性层)将条件映射到空间特征,并将输出连接到鉴别器中间层从图像中提取的特征,如图 2 所示。

图 2,在中间层连接[

使用这种方法的缺点是背后没有数学逻辑;通常情况下,条件是作为一个热编码的向量引入的,简单的连接与图像的像素空间无关。

使用辅助分类器的调节:

AC-GANs 中,鉴别器架构被修改以输出样本的真实概率及其类别概率。这样,鉴别器使用辅助分类器,并且目标函数被修改以包括附加项:正确类别的对数似然性。

图 3,AC-GANs 鉴别器图[ 来源

这种方法的缺点是,生成器可能生成易于分类的样本,以满足新呈现的损失,因此生成的图像的多样性将较低。

投影调节:

带投影鉴别器的 cGANs 中,他们修改了鉴别器,使其包含了条件和从图像中提取的特征之间的投影。该投影值测量条件和图像之间的相似性,并被添加到鉴别器 logit。鉴频器输出变为:

其中 V 是嵌入矩阵(例如 PyTorch 中的嵌入层或线性层),该方法的示意图如图 4 所示。

图 4,鉴别器[ ]中的条件预测

用投射进行调节已被证明比早期的方法更有效。然而,一个限制是当条件是连续值时,在这种情况下,它们不能使用嵌入矩阵进行映射,并且使用线性层会导致小的角度变化。

条件批处理规范化(CBN):

在( Dumoulin et al .,2016 )中使用了条件批次归一化; De Vries et al .,2017 )进行风格转移,其中条件 y 用于调制神经网络的激活函数。考虑以下等式:

其中 x_i 代表激活函数。首先,使用在小批量实例上计算的平均值和方差来标准化激活,然后通过基于所提供的条件/样式选择的自适应函数 fg 来缩放和移位激活。这种思想在最近的 GANs 模型中被使用,(张等,2019Brock et al .,2018 )通过用 CBN 图层 替换生成器中的批量归一化图层。

总之,有许多方法可以为 GANs 的生成器和鉴别器提供附加信息。对于分类类,投影鉴别器似乎比简单的连接或使用附加分类器更有效。在生成器中,条件批处理规范化已经在最近的许多工作中使用,而不是连接。

参考资料:

AWS 共同责任模式概述

原文:https://towardsdatascience.com/overview-of-the-aws-shared-responsibility-model-4d2dab91aced?source=collection_archive---------55-----------------------

AWS 共享责任模型解释了如何在客户和 AWS 之间分配安全性

图片来自 Pexels

在本文中,我将解释 AWS 共享责任模型,并谈论与此相关的实践。在当今竞争激烈的世界中,云计算是越来越多的公司最想要的技术之一。虽然一些公司正在将他们现有的基础设施升级并转移到云,但一些公司已经在全面使用 AWS 服务的过程中。在云上似乎令人生畏,但是,我们需要特别关注驻留在云上的数据的安全性和合规性。AWS 共享责任模型是 Amazon 定义的关于云中安全性和合规性的实践,并定义了客户和 AWS 的责任。

图 1 — AWS 共享责任模型描述(来源)

AWS 共享责任模型是在客户和 AWS 之间划分的安全实践的集合,以便他们可以减轻压力,平等地参与云安全和合规性。AWS 通常负责管理云系统的全局基础设施,包括硬件和网络模块。这些可以跨越多个区域、可用性区域等。客户主要负责保护云中的数据,维护操作系统的补丁等。让我们详细了解一下双方的责任。

AWS 共享责任模型

在很高的层面上,共享责任模型可以大致分为以下几类。

1.基础设施服务

2.集装箱服务

3.抽象服务

现在,让我们详细了解上述每一种责任模式。

基础设施服务

当考虑基础设施服务时,任何人都能想到的第一个服务是 EC2 实例。EC2,也称为弹性计算云,是一种允许客户在云上运行虚拟机的服务。正如我们所知,AWS 的主要职责是提供云的安全性,这使 AWS 能够保护其遍布全球的基础架构,包括多个地区、可用性区域和边缘位置。这也延伸到 AWS 用于计算、存储、数据库和网络的设备。

AWS 在世界各地运营着几个物理数据中心。对这些数据中心的物理访问由 AWS 以及为这些数据中心提供必要备份的其他设施控制。例如,对电力系统、不间断电源、HVAC 系统等的访问。完全由 AWS 负责。因此,维护这些的负担摆脱了客户的负担,他们可以将更多精力放在云计算业务上。

尽管如此,客户主要负责管理 EC2 实例的客户端和服务器端加密,设置安全组并允许对操作系统的特定访问。客户还负责配置防火墙并设置身份和访问管理(IAM)用户。作为一个最佳实践,应该向任何将要使用 EC2 实例的用户提供最少的访问权限。

集装箱服务

容器服务可以被认为是基础设施服务之上的封装。在这些服务中,操作系统的维护由 AWS 负责,而维护系统的安全性和完整性则委托给客户。在任何情况下,如果您的服务需要启动基础设施服务,它会在幕后完成。例如,将 AWS RDS 视为不需要客户安装或维护任何操作系统的容器服务。但是,在后台,AWS 已经启动了一个 EC2 实例来支持您的 RDS 实例。容器服务也称为平台即服务(PaaS)。

在这样的产品中,维护硬件和操作系统的责任由 AWS 承担。AWS 还维护各种系统补丁和其他活动,如升级系统和软件。客户在使用服务时需要保持数据加密,还需要进行必要的安全配置,如设置 VPC 和其他配置设置。下图解释了容器服务的责任模型。

抽象服务

AWS 共享责任模型中关注的第三个类别是抽象服务。这些服务也称为软件即服务产品。在这些服务中,大部分安全性由 AWS 自己处理,很少功能由客户负责。这对客户非常有帮助,因为他们不需要维护系统的操作更新或操作系统的补丁。但是,客户仍然有责任通过在其中应用适当的 IAM 角色和策略来保护数据。客户还应该通过维护对编程访问凭据的健康检查来控制这些服务不会受到未经授权的访问。

亚马逊 S3、DynamoDB、SQS 就是属于这一类的服务。下图描述了抽象服务模型中 AWS 和客户之间共享的一些安全特性。

从客户的角度看安全性

在本文的前几节中,我们已经讨论了 AWS 共享责任模型的三个层,现在让我们来讨论客户需要实现的其他一些重要的安全特性,而不考虑他们使用的各种共享责任模型。

AWS 帐户安全功能

了解安全日志

让我们详细了解一下上述每个主题。

AWS 帐户安全功能

AWS 在 AWS 帐户中提供了许多安全功能,建议客户利用这些功能在 AWS 中构建一个安全的工作环境。一些重要的功能是在组织内定义适当的角色和策略,然后使用这些角色分配给用户和组。这有助于控制谁可以控制 AWS 帐户中的哪些服务或资源。为了访问跨帐户资源,应该使用 AssumeRole 服务,该服务可用于承担另一个 AWS 帐户的角色,并在另一个 AWS 帐户中执行一些活动。

要了解有关 AWS IAM 角色和政策的更多信息,请遵循官方文档

了解安全日志

尽管我们努力保护 AWS 内的服务和资源,但仍有可能发生一些安全事故。在这种情况下,分析各种服务生成的日志以识别故障并采取适当的措施来修复它以减少漏洞是非常重要的。AWS 提供了一项名为 CloudTrail 的服务,使用它可以分析来自 web 服务器和其他服务的各种日志。要阅读更多关于 AWS CloudTrail 的信息,请关注官方文档

结论

本文详细解释了 AWS 共享责任模型,该模型解释了关注云中数据的安全性和合规性的任务。尽管将应用程序迁移到云中有好处,但也存在一些风险,因此亚马逊推出了 AWS 共享责任模型,该模型解释了客户必须关注的部分以及 AWS 将关注的部分。使用 AWS 共享责任模型,客户和 AWS 都能够管理庞大的云生态系统的安全性和合规性。

要了解更多关于 AWS 安全性和最佳实践的信息,请阅读白皮书。

用于监控和管理 Apache Kafka 集群的 UI 工具概述

原文:https://towardsdatascience.com/overview-of-ui-tools-for-monitoring-and-management-of-apache-kafka-clusters-8c383f897e80?source=collection_archive---------0-----------------------

图片由来自 freepic.com卡纳瓦特拍摄

在 Apache Kafka 中,工程师可以使用哪些最佳工具来观察数据流、跟踪关键指标和解决问题?

Apache Kafka 是一个开源的分布式事件流平台,使组织能够实施和处理高性能数据管道、流分析、数据集成和任务关键型应用程序。它被成千上万的公司使用,其中 80%是财富 100 强公司。

虽然 Apache Kafka 是需要实时数据处理和应用程序活动跟踪的场景的首选服务,但 Apache Kafka 中的集群监控和管理经常带来挑战。为了使这些任务更加高效和透明,您可能需要提供附加管理和监控功能的第三方、开源或商业图形工具。

本文提供了此类 UI 工具的概述,包括:

  1. AKHQ
  2. 科尔
  3. 卡夫多普
  4. Apache Kafka 的用户界面
  5. 镜头
  6. CMAK
  7. 汇合 CC
  8. 康杜克托尔

但首先,让我们深入研究一下阿帕奇卡夫卡中的可观察性和监控问题。

阿帕奇卡夫卡中的可观察性和监控

Apache Kafka 是任何数据驱动型组织的关键服务。但是处理普通的 Apache Kafka 集群可能相当痛苦。Kafka 集群很难建立,难以扩展,维护成本也很高。最重要的是,它们容易出错并且观察起来很复杂,这可能会导致数据流中的各种业务关键问题,并阻止工程师跟踪和解决这些问题。

为了减少错误和避免关键问题,对于组织来说,通过添加健壮的可观察性组件来确保其 Apache Kafka 集群的安全是非常重要的。更好的可观察性有助于:

  • 更快地解决数据流问题
  • 通过对工程师通过元数据管理的数据流有一个共同的理解,改善工程师之间的协作。
  • 更轻松地发现数据流中的敏感数据,以满足合规性要求。
  • 更快速有效地清理数据。更少的错误仪表板意味着更满意的客户。

集群可观察性的挑战是 Apache Kafka 附带了用于所有必要管理任务的 CLI 工具。但是因为它们没有集成到一个单一的服务中,所以您必须为不同的任务分别运行不同的工具,这就造成了不便和时间损失。随着集群规模的增长,或者如果您有多个集群,问题可能会迅速升级,这仅仅是因为您缺乏正确观察它们的能力。

这让我们回到 UI 监控工具,它可以帮助组织简化和加快开发,最大限度地缩短解决问题的时间,并加快报告过程,以提高工程团队内部和之间的运营效率。

Apache Kafka 集群的 8 大 UI 监控工具

首先,快速比较一下 Apache Kafka 集群监控工具。

作者图片

AKHQ

  • GitHub:https://github.com/tchiotludo/akhq
  • 许可证:Apache 2
  • 可用性:免费
  • 优点:许多有用的功能
  • 缺点:UI 不好;缺少 KSQL 集成;部分支持 Protobuf 模式注册表

AKHQ (之前被称为 KafkaHQ)是一个用于 Apache Kafka 的 Kafka GUI,它使工程团队能够在一个统一的控制台中搜索和探索数据。有了 AKHQ,开发者和 DevOps 可以管理主题、主题数据、消费者群体、模式注册、连接性等等。

作者图片

AKHQ 提供了大量有用的功能,包括多集群管理、消息浏览、实时跟踪、认证、授权、只读模式、模式注册和 Kafka 连接管理。它支持 Avro 并兼容 LDAP 和 RBAC。

但是 AKHQ 的 UI 并不是最方便的。你肯定需要分配一些时间来调整学习曲线。

最重要的是,AKHQ 没有 KSQL 集成,只提供对 Protobuf 模式注册中心的部分支持。它也不支持动态主题配置、分区增加、副本更改、Kafka Streams 拓扑或 JMX 度量可视化和图表。

那些希望在 AWS 上使用 AKHQ 作为其数据流解决方案的一部分的人应该知道,它不支持亚马逊 MSK 的 AWS 身份和访问管理(IAM)访问控制。

科尔

Kowl(以前称为 Kafka Owl)是一个 web 应用程序,旨在帮助开发人员探索 Apache Kafka 集群中的消息,并更好地了解这些集群中实际发生的事情。

作者图片

Kowl 最大的优势是它梦幻般的 UI。这是方便的,用户友好的,非常简单的使用。不过,它没有太多的特性。

例如,Kowl 提供消息浏览、实时跟踪,以及对 Protobuf、Avro 和亚马逊 MSK IAM 的支持,但登录系统(Google、GitHub、Okta)和 RBAC 的群组同步权限只能通过付费的 Kowl 商业计划获得。

Kowl 还缺少多集群管理、动态主题配置、分区增加、副本更改、Kafka 连接管理、模式注册、KSQL 集成、Kafka 流拓扑、只读模式以及 JMX 指标的可视化和图表等功能。如果将这些纳入一揽子计划,Kowl 将优于任何其他工具。

卡夫多普

Kafdrop 是一个用于查看阿帕奇卡夫卡主题和浏览消费群体的 web UI。该工具使开发人员能够更容易地显示和处理集群信息,如代理、主题、分区和消费者。它还允许查看消息。

作者图片

在很大程度上,Kafdrop 是一个非常普通的工具。它的用户界面并不壮观,而且缺少很多功能。它允许你查看 Kafka 经纪人和消费者团体,创建和查看主题,浏览消息,和监控 ACL。它还提供对 Azure 事件中心的支持。但是其他有用的特性呢,比如实时跟踪、模式注册或只读模式?

好消息是 Kafdrop 在 GitHub 上的评价很高,如果你正在寻找一个有帮助的沉浸式社区,这很可能是你的工具。

Apache Kafka 的用户界面

Apache Kafka 的 UI 是一个免费的开源 web 服务,为开发者提供了一个清晰的 UI 来处理 Apache Kafka 集群。它使开发人员能够监控数据流,并在提供最佳性能的同时发现和解决数据中的问题。轻量级仪表板使跟踪 Apache Kafka 集群的关键指标变得容易,包括代理、主题、分区、生产和消费。

作者图片

Apache Kafka 的用户界面因其方便的用户界面、免费的可用性和众多的特性而脱颖而出。它具有以下功能:

  • 浏览消息 —浏览采用 Avro、Protobuf、JSON 和纯文本编码的消息
  • 查看用户群 —查看每个分区的暂停偏移,以及组合延迟和每个分区的延迟
  • 可配置认证 —使用可选的 Github/Gitlab/Google OAuth 2.0 保护您的安装
  • 查看 Kafka Brokers —查看主题和分区分配,以及控制器状态
  • 查看 Kafka 主题 —查看分区数量、复制状态和自定义配置
  • 多集群管理 —在一个位置监控和管理您的所有集群
  • 动态主题配置 —使用动态配置创建和配置新主题

设计和构建该工具的人工智能咨询公司 Provectus 声称,最早将于 8 月底添加更多功能,包括实时跟踪、KSQL 集成、Kafka Streams 拓扑以及 JMX 度量可视化和图表。

镜头

  • GitHub:https://github.com/lensesio
  • 许可证:BSL
  • 可用性:免费
  • 优点:对于 fast-kafka-dev 和本地开发来说非常棒
  • 缺点:缺少许多功能

lens将自己定位为 Apache Kafka 和 Kubernetes 的实时应用和数据操作的数据操作平台。它可以帮助工程师提高数据的可用性和安全性,并消除数据孤岛。镜头似乎是实时流分析中评价最高的产品。

但是镜头可以说是一个相当普通的工具。用镜头搭配 fast-kafka-dev 再合适不过了。对地方发展也有好处。然而,它缺乏某些特征;多集群管理、消息浏览和 avro 支持根本不足以让它为许多任务工作。将 Kafka Connect 管理作为一项单独的服务提供也没有帮助。

作者图片

但如果你对没有很多功能感到满意,Lenses 的用户界面绝对符合要求。这是一个真正令人惊叹的工具,非常圆滑和直观。

CMAK

  • GitHub:https://github.com/yahoo/CMAK
  • 许可证:Apache 2
  • 可用性:免费
  • 优点:非常适合分区重新分配;Ops 工具
  • 缺点:仅限于 Ops 任务

CMAK (之前称为 Kafka Manager)是一个全面的工具,使工程师能够管理 Apache Kafka 集群,以完成各种运营任务。

作者图片

CMAK 自诩有一个好的和相当简单的用户界面。虽然它没有提供很多特性,但是多集群管理、动态主题配置、分区创建和副本更改将涵盖您的大部分任务。

在很大程度上,CMAK 主要是一个作战工具。它也非常擅长分区重分配。

汇合 CC

汇合控制中心是一个基于 web 的用户界面,允许开发人员和操作员管理和监控 Apache Kafka 集群,包括检查集群健康状况、观察和控制消息、主题和模式注册。它还可以用于开发和运行 ksqlDB 查询。

关于融合 CC 的重要事情是,它是作为融合企业的一部分提供的,这意味着它只是一项付费服务。它有很多功能和一个非常好的用户界面。如果你不介意被锁定在合流生态系统中,这个 UI 工具将远远满足你的需求。

总的来说,Confluent CCS 不仅仅是一个普通的主题检查工具。它的功能是一流的,所有这些功能都完美地工作,没有任何故障。

康杜克托尔

Conduktor 是 Apache Kafka 的桌面客户端,为工程师提供了与 Kafka 生态系统合作的用户友好界面。该客户端是 Windows、Linux 和 Mac 的原生客户端。它可以处理任何类型的 Apache Kafka 集群,并拥有您可以要求的所有功能。

作者图片

但是 Conduktor 可能没有这个列表中的其他 UI 工具方便,因为它是一个桌面应用。如果你同意的话,Conduktor 可以成为融合 CC 的一个可行的替代方案。

结论

拥有合适的 UI 工具来监控和管理 Apache Kafka 集群是集群健康的关键。通过简单方便的用户界面,您可以更有效地观察数据流、跟踪指标和排除故障,而不必使用许多额外的 CLI 工具。这导致更少的瓶颈、更快的报告和更具成本效益的开发。

本文提供了我对 Apache Kafka 中监控和管理集群的主要 UI 工具的看法。我尽了最大努力保持客观,但社区肯定会有所补充。

欢迎在评论区分享你对这些 Apache Kafka UI 工具的反馈和意见,以及我对它们的概述。

简而言之 p 值:它实际上意味着什么?

原文:https://towardsdatascience.com/p-value-in-a-nutshell-what-does-it-actually-mean-d180388bb499?source=collection_archive---------68-----------------------

理解、可视化和计算 p 值

图片由皮克斯拜格雷格·蒙塔尼拍摄

介绍

欢迎学习计算 p 值的课程。

在我们开始计算 p 值之前,重要的是要考虑 p 值的真正用途。

假设检验复习者

这篇文章不涉及太多细节,当建立一个假设检验时,你将确定一个零假设。你的零假设代表了你评估的两个变量没有任何关系的世界。相反,另一个假设代表了一个世界,在那里有一个统计上显著的关系,这样你就可以拒绝零假设而支持另一个假设。

潜得更深

在我们离开假设检验的概念之前……想想我们刚刚说的。你需要有效地证明,几乎没有出错的余地,我们在现实世界中看到的事情不可能发生在这些变量不相关的世界,或者关系独立的世界

有时在学习统计学的概念时,你会听到定义,但很少花时间去概念化。经常会有很多规则集的记忆…我发现理解这些原则的直觉基础会在找到它们的实际应用时更好地为你服务。

继续这个思路。如果你想比较真实世界和虚拟世界,那正是你应该做的。

正如您所猜测的,我们可以通过创建一个线性回归模型来计算观察到的统计数据,在该模型中,我们将响应变量解释为解释变量的函数。一旦我们做到了这一点,我们就可以使用通过 ols 回归确定的斜率或系数来量化这两个变量之间的关系。

但是现在我们需要想出一个零世界的概念,或者说这些变量是独立的。这是我们没有的东西,所以我们需要模拟它。为了方便起见,我们将利用 infer 包。

让我们来计算我们观察到的统计数据

首先,让我们得到我们观察到的统计!

我们正在处理的数据集是西雅图房价数据集。我以前多次使用过这个数据集,发现它在演示时特别灵活。数据集的记录级别是按房屋和详细价格、平方英尺数、床位数、浴室数等。

在这篇文章中,我们将试图通过平方英尺的函数来解释价格。

让我们创建我们的回归模型

*fit <- lm(price_log ~ sqft_living_log,
          data = housing)
summary(fit)*

正如您在上面的输出中看到的,我们所追求的统计数据是我们的解释变量sqft_living_logEstimate

一个非常干净的方法是整理我们的结果,这样我们得到的不是一个线性模型,而是一个 tibble。tible、tables 或 data frames 将使我们更容易进行系统化的交互。

然后我们想要过滤到sqft_living_log项,我们将通过使用pull函数返回估计值本身来结束它。这将把斜率作为一个数字返回,这将使得稍后与我们的空分布进行比较更加容易。**

看一看!

*lm(price_log ~ sqft_living_log,
          data = housing)%>%
  tidy()%>%
  filter(term == 'sqft_living_log')%>%
  pull(estimate)*

模拟时间到了!

首先,你应该知道有各种类型的模拟。我们这里要用的是所谓的排列

在展示变量相互独立的世界时,排列特别有用。

虽然我们不会深入研究如何在幕后创建置换样本的细节;值得注意的是,对于观察到的统计量,样本将是正态的,以 0 为中心。

在这种情况下,斜率将集中在 0 附近,因为我们在解释变量和响应变量之间没有关系的前提下进行操作。

推断基本原理

有几件事你需要知道:

  • 指定我们如何确定我们正在建模的关系:price_log~sqft_living_log
  • 假设是我们指定的independence
  • “生成”是我们确定想要复制的数据集的数量的方式。请注意,如果您这样做了,一个复制而没有calculate它将返回一个与原始数据集大小相同的样本数据集。
  • 计算允许您确定有问题的计算(斜率、平均值、中值、均值差异等)。)
*library(infer)
set.seed(1)perm <- housing %>%
  specify(price_log ~ sqft_living_log) %>%
  hypothesize(null = 'independence') %>%
  generate(reps = 100, type = 'permute') %>%
  calculate('slope')perm
hist(perm$stat)*

1000 个代表的相同分布

零抽样分布

好了,我们做到了!我们创造了所谓的零抽样分布。我们在上面看到的是 1000 个斜率的分布,每个斜率都是在独立数据的 1000 次模拟后建模的。

这正是我们所需要的。一个我们可以与现实进行比较的模拟世界。

以我们刚刚制作的视觉效果为例,让我们使用密度图,并为我们观察到的斜率添加一条垂直线,用红色标记。

*ggplot(perm, aes(stat)) + 
  geom_density()+
  geom_vline(xintercept = obs_slope, color = 'red')*

从视觉上,你可以看到这种情况的发生远远超出了随机事件的发生。

从视觉上看,你可以猜到这里的 p 值是 0。至于说,在 0%的零抽样分布中大于或等于我们观察到的统计量。

如果事实上我们看到置换数据大于或等于我们观察到的统计数据,我们就会知道这只是随机的。

这里重申一下,p 值的目的是让您了解我们看到的这种随机斜率与统计显著关系的可行性。

计算 P 值

虽然我们知道这里的 p 值是多少,但是让我们来计算一下 p 值。

重新提出这个想法;p 值是(随机)大于或等于我们观察到的斜率的重复部分。

您将在我们的summarise函数中看到,我们正在检查我们的 stat 或斜率是否大于或等于观察到的斜率。每条记录将被赋予相应的真或假..当你用一个均值函数包装它时,TRUE 将代表 1,FALSE 代表 0,导致一部分情况 stat 大于或等于我们观察到的斜率。

*perm %>%
  summarise(p_val = 2 * round(mean(stat >= obs_slope),2))*

为了确定我们没有足够的证据来拒绝零假设的较弱关系的情况,让我们看一下价格作为它建立的年份的函数。

使用与上面相同的计算,这导致 12%的 p 值;根据 95%的标准置信水平,这不足以作为拒绝零假设的证据。

关于 P 值解释的最终注释

最后,我想再强调一次…

12%的意思。我们看到,当我们随机生成一个独立的样本时……在整整 12%的时间里,我们随机生成的斜率等于或大于……

你可能会看到 12%的结果是随机的

结论

就是这样!你是计算和理解 p 值的大师。

在短短的几分钟内,我们学到了很多东西:

  • 假设检验
  • 线性回归复习器
  • 抽样解释
  • 了解推断包
  • 构建抽样分布
  • 可视化 p 值
  • 计算 p 值

在剖析 p 值等统计概念时,很容易迷失方向。我的希望是,对需求和相应的执行有一个强有力的基础理解能让你理解并正确地将它应用于各种各样的问题。

如果这有帮助,请随时查看我在https://medium.com/@datasciencelessons的其他帖子。祝数据科学快乐!

以自包含格式打包 PyTorch 模型

原文:https://towardsdatascience.com/package-pytorch-models-in-a-self-contained-format-badbe10b7ae5?source=collection_archive---------29-----------------------

在机器之间移动你的模型,而不是 Python 代码。

克劳迪奥·施瓦茨在 Unsplash 拍摄的照片

PyTorch 在 2016 年开始了它卑微的旅程,并迅速成为深度学习研究人员的首选工具。然而,PyTorch 现在已经不仅仅是一个原型工具了。它已经发展成为一个成熟的生产就绪框架,正在扩大其在商业领域的粉丝基础。

而这恰恰是它的创造者和维护者的目标;成为学术界和工业界的事实标准。研究人员和机器学习工程师应该能够高效地运行 PyTorch,从本地 Jupyter 服务器到云平台,从多节点 GPU 集群到边缘的智能设备。

然而,PyTorch 在我看来有一个显著的缺点:它存储模型的方式。你会问,PyTorch 模型的推荐存储方式是什么?一言以蔽之,你要保留的是模型的参数,而不是模型本身。从文档中:

当保存用于推理的模型时,只需要保存训练模型的学习参数。用torch.save()函数保存模型的 state_dict 将为您以后恢复模型提供最大的灵活性,这就是为什么它是保存模型的推荐方法。

缺点是什么?您应该在服务器中再次定义模型的架构,反序列化state_dict并将参数加载到模型中。如果您有办法将所有需要的东西打包到一个归档文件中,在服务器中解压缩,然后完成您的工作,这不是很好吗?好吧,我有一些好消息:现在你可以了!

学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!

火炬.包装

*torch.package*是一种将 PyTorch 模型打包成独立、稳定格式的新方法。包是一个档案,包括模型的参数和元数据以及它的架构。

此外,torch.package增加了对创建包含任意 PyTorch 代码的密封包的支持。这意味着您可以使用它来打包您想要的任何东西(例如,PyTorch 数据加载器、数据集等)。).

这是一种很好的方式来重现您的训练结果,并使用您喜欢的工具为模型服务。

那么,让我们来看看如何使用这个强大的工具。

装置

torch.package模块是核心 PyTorch 1.9 的一部分,所以我们首先需要检查并安装 PyTorch 的正确版本。使用下面的命令来完成此操作:

!pip uninstall -y torch
!pip install -f https://download.pytorch.org/whl/test/cpu/torch_test.html torch

包装你的模型

在这个故事中,我们将使用torch.package封装然后导入一个 DCGAN 模型,可以用来生成时装模型。这个预先训练好的模型托管在火炬中心。要下载它,请复制下面的代码:

接下来,我们来测试一下。使用下面的代码生成时装模特的随机图像,使用您刚刚下载的 DCGAN:

结果应该是这样的:

作者图片

现在,让我们包装模型。我们将创建PackageExporter来创建一个归档文件,其中包含在另一台机器上运行模型所需的一切。为此,复制以下代码:

运行上面的代码会产生一个错误:

PackagingError:
* Module did not match against any action pattern. Extern, mock, or intern it.
models.DCGAN
models.utils.config
models.loss_criterions.ac_criterion     models.loss_criterions.base_loss_criterions     models.networks.DCGAN_nets

这意味着什么?为了创建一个密封的包,PackageExporter将试图访问将要被酸洗的模块和对象所需的所有依赖关系的源代码。

在此过程中,它将跳过标记为externmock的依赖项,并将标记为intern的依赖项包含在存档中。在这种情况下,我们需要包括models。为此,请修改您的代码,如下所示:

现在,我们有另一个问题:

PackagingError:
* Module did not match against any action pattern. Extern, mock, or intern it.
numpy

然而,NumPy 不是我们想要打包的模型的一部分。因此,我们可以安全地排除它:

使用这个命令,您已经成功地创建了您的包!

加载您的模型

要将你的模型加载回内存,你应该使用PackageImporter。这比以前简单;只需复制下面的代码:

为了测试一切工作正常,您可以再次调用您之前定义的run_model函数并检查结果。一切都应该井然有序!

最后,您可以使用这个 colab 实验并运行完整的示例。

结论

PyTorch 在 2016 年开始了它卑微的旅程,并迅速成为深度学习研究人员的首选工具。然而,PyTorch 现在已经不仅仅是一个原型工具了。它已经发展成为一个成熟的生产就绪框架,正在扩大其在商业领域的粉丝基础。

因此,研究人员和 ML 工程师必须能够为本地 Jupyter 服务器到云平台,从多节点 GPU 集群到边缘智能设备高效运行 PyTorch。

为了实现这一点,PyTorch 1.9 引入了一种新的打包机制:模块torch.package

在这个故事中,您看到了什么是torch.package模块,以及如何使用它来保存和检索模型。玩得开心!

关于作者

我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。

如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 Twitter 上关注我的 MediumLinkedIn@james2pl

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。

制作 Python 包第 2 部分:如何用诗歌在 PyPI 上发布和测试您的包

原文:https://towardsdatascience.com/packages-part-2-how-to-publish-test-your-package-on-pypi-with-poetry-9fc7295df1a5?source=collection_archive---------5-----------------------

Python 诗歌项目指南

在本指南的上一版中,我们使用传统的 setup.py 发布了一个 python 包给 PyPI。

照片由克里斯汀·休姆Unsplash 上拍摄

它需要一个奇怪的 Manifest.in 文件,没有附带任何测试,我们甚至没有用 requirements.txt 讨论依赖管理,为什么?因为 2021 年不是这样,我的朋友们。

依赖管理是关于你的包使用的 Python 库。如果您导入 numpy 并使用它的类/函数,您的包将依赖于 numpy 的版本

如果一个新版本的 numpy 使用了不同的语法或者去掉了一个函数,那么你的包就不能在那个版本的 numpy 上工作。我们需要跟踪您使用的版本。

或者,如果您使用 numpy 和 pandas,并且它们都依赖于其他某个库的不同版本,该怎么办?谁来记录这些事情?!

诗歌会。

poem 是一个 Python 库,我们可以使用它来创建一个包,更容易地将其发布到 PyPI,它将为我们处理依赖管理。耶!

要开始,我们只需安装诗歌

pip install poetry

和往常一样,如果您没有 pip,请尝试 pip 3(python 3 的版本)。

新诗

我们的第一个命令是创建目录。当我们有诗的时候,在我们项目的开始没有 mkdir。

真的,在你这样做之前不要为你的项目创建一个目录,因为 poems 会用你的项目名创建一个目录,把所有的东西都放在里面包括一个也是以你的项目命名的子目录,源代码就放在那里。

所以,如果你为你的项目做一个目录,并在那里这样做,你会得到一个俄罗斯娃娃的情况:我的包/我的包/我的包/yikes。

相反,只需转到所有包所在的目录(这样当您运行 ls 时,就可以看到您的其他项目),然后运行:

poetry new

现在你可以看到你的诗歌目录及其所有部分,包括最重要的 pyproject.toml.

现在我们可以开始建立一个诗歌包了!

虚拟环境

但首先,快速绕道一下诗歌作为虚拟环境是如何工作的。

虚拟环境是一个孤立的数字环境,其中的库、代码和解释程序与计算机上的其他程序完全分离。

如果你进入一个数字环境并试图导入 numpy,它将不会存在,因为它没有安装在那个数字环境中。

相反,如果你在数字环境中安装了一个库,它就不会安装在你电脑的其他部分。

本质上,环境中可用的库都存储在该环境中的某个目录中。虚拟环境使用自己的可用库目录,因此它与计算机的可用库目录没有关系。

当我们运行新诗时,我们创建了一个虚拟环境!当我们在诗歌目录中从命令行运行代码时,我们在虚拟环境中是而不是。但是,如果我们用

poetry run the-rest-of-the-command

然后我们可以在诗歌环境中运行这个命令。

或者,如果我们跑了

poetry shell

然后,我们将进入我们的诗歌文件夹的虚拟环境,在那里我们可以使用我们将通过诗歌安装的库。

用 ctrl+d 退出虚拟外壳。

诗歌添加

事实上,让我们看看如何安装带有诗歌的库,这将很好地管理我们的依赖性。

让我们进入我们创建的 pyproject.toml。它将包含两个主要内容:

  1. 我们项目的文档(嗯,包括引用自述文件和许可证)。我们将在完成图书馆事务后回到文档上。
  2. 我们的包需要的库版本的范围

当我们制作包时,我们需要告诉 poems 我们使用的是什么版本的库。这个命令很简单:

poetry add library-name

其中 library-name 是我们正在使用的任何库的名称,比如 numpy。

该命令会将库版本添加到我们的 pyproject.toml 中。它实际上是一系列遵循语义版本化的版本。你可以在这里看到语法:【https://classic.yarnpkg.com/en/docs/dependency-versions/

它还会在我们的诗歌虚拟环境中安装库。

poem . lock

如果您poems 添加一个库,这也将安装那个库,您不仅会看到您的 pyproject.toml 自动更新——您还会获得一个新文件:poetry.lock。

pyproject.toml 记录了您的包可接受的库版本的范围,并且只列出了您用 poeties add 直接添加的库。

另一方面,poetry.lock 记录了安装在您的包中的确切的库版本。它包括你的依赖项需要的每一个库。

所以如果你把诗加上 seaborn,

当你的 pyproject.toml 得到 seaborn 的时候,

你的诗。锁将获得:

atomicwrites、attrs、colorama、cycler、fonttools、kiwisolver、matplotlib、more-itertools、numpy、packaing、pandas、pillow、pluggy、py、pyparsing、pytest、pytz、scipy、setuptools-scm、six、tomli、wcwidth、 和 seaborn

因为这是 seaborn 所依赖的每一个库,加上每一个库所依赖的每一个库,递归地直到 seaborn 所需要的每一个库都有它所需要的库。

关于他人使用你的源代码的旁注

现在,如果有人从 github 克隆了你的包,他们会有你的 pyproject.toml,但是还没有安装你的库。他们需要逃跑

poetry install

如果他们也有你的 poetry.lock,他们将安装你的 poetry.lock 中声明的精确版本。

如果他们没有你的 poetry.lock,那么 poem 会为你做它做过的事情——找出要安装的编写版本,并将其写入 poetry.lock。

总的来说,poetry.lock 列出了一个包运行时安装的所有精确的库版本,这样你的包的用户就可以使用所有东西的相同版本。

用 pyproject.toml 进行项目描述

好的,那么我将尽快跳到 PyPI 发布,我们只需要在这里对我们的包文档稍微好一点。

pyproject.toml 顶部的那个部分将包含 setup.py 在传统打包方法中包含的所有内容,没有诗意。

pyproject.toml 的顶部应该是这样的:

pyproject.toml

[tool.poetry]name = “” #your package nameversion = “0.0.1”description = “” #a short description of your package that will be used in PyPI searchauthors = [“your-name <your-email>”]license = “MIT”readme = “README.md”homepage = “” #can be the reporepository = “”keywords = [“test”, “dependencies”, “documentation”]classifiers = [“Development Status :: 5 — Production/Stable”,“Intended Audience :: Education”,“Operating System :: MacOS”,“License :: OSI Approved :: MIT License”,“Programming Language :: Python :: 3”,]include = [“LICENSE”,]

继续把它复制到你的 toml 中并更新字段:填写你的名字和电子邮件,项目名称和版本,简短描述,回购/主页,并使用这里的选项填写这些分类器:https://pypi.org/pypi?%3Aaction=list_classifiers

如您所见,我们引用的是 README.md,所以如果您愿意,可以将 README.rst 更改为 md (markdown)文件。您将把包含变更日志的长项目描述放在那个 README.md 中,因此它看起来像这样:

README.md

My long description blah blah blah blah.Change Log**================**0.0.1 (Dec 1, 2021) **— — — — — — — — — — — — — — — -**- First Release0.0.2 (Dec 2, 2021) **— — — — — — — — — — — — — — — -**- Did some more stuff

发布到 PyPI

好了,我们开始吧。我将跳到有趣的部分,然后我将回头提供一些提示。

可以一行发布到 PyPI。在您使用以下工具设置一次您的凭证后:

poetry config http-basic.pypi username password

这些是你在 pypi.org 的证件,你可以在他们的网页上注册账户。

在您设置了这些凭证之后,下面是一行 publish:

poetry publish --build my_package

你就这样在 PyPI 上!

有一个单独的诗歌构建命令,但是您可以在发布的同时使用构建标志(— build)进行构建。

对测试 PyPI 的测试

但是也许在我们把半成品包扔给 PyPI 之前,我们可以在 PyPI 的测试版本上测试它。

这个测试 PyPI 将允许我们模拟对 PyPI 的更新,然后 pip 安装我们自己的包,看看它是否像预期的那样工作。

这样做的第一步是在 test.pypi.org 上创建一个新帐户(是的,你需要一个与你的 pypi 帐户不同的帐户,但是它可以有相同的用户名)。

然后,您可以将存储库添加到诗歌中:

poetry config repositories.testpypi https://test.pypi.org/legacy/

发布到存储库:

poetry publish –-build -r testpypi

pip 从存储库中安装您包:

pip install --index-url [https://test.pypi.org/simple/](https://test.pypi.org/simple/) my_package

侧栏:pip 安装故障排除

如果您遇到问题,这个更长的命令行功能可以解决一些常见问题:

python3 -m pip install -i [https://test.pypi.org/simple/](https://test.pypi.org/simple/) — extra-index-url [https://pypi.org/simple](https://pypi.org/simple) my_package==0.0.1

pip 之前的 python -m 是为了确保您使用的是正确的 pip 版本。您也可以尝试查看您的 pip 版本和 python 版本

which pip
which python
pip --version
python --version 

或者更新画中画

 python -m pip install --upgrade pip

和往常一样,你可能需要用 python3 切换 python,或者用 pip3 切换 pip。

额外的索引 url 指向普通的 PyPI repo(而不是测试),您的依赖项需要从这里下载。

最后,我还添加了版本,您应该用您的包版本号替换它,以便它得到正确的版本号。

在新的虚拟环境中安装和导入

当您尝试 pip 安装时,我将进入一个新的虚拟环境,这样您的软件包模块名称就不会与我们所在的目录名称混淆,该目录也称为您的软件包名称。

我喜欢直接进入我的顶级项目目录,用 poems new 创建一个新目录,用

poetry shell

pip 从测试 PyPI 安装它。

然后我在虚拟环境中运行 python 解释器

poetry run python

现在,用 Python 导入您的包和函数!你可以先试试:

import my_package

接下来,尝试导入您的函数。如果它们在 init 中。py 您可以直接导入它们,如

from my_package import my_function

或者它们是否在与 init 相同级别的文件中。py,您将指定不带。py 来获取它的模块名。比如 utils.py 就叫 utils。

from my_package.my_module import my_function

如果在那个级别有一个文件夹。py 文件,通过添加 init,将该文件夹变成一个包。也复制到那个文件夹。初始化文件可以是空的。

所以如果

  1. 我的 _ 包是整个库,
  2. my_package 文件夹中是 my_subpackage 文件夹,它包含。py 文件和 init 文件,
  3. my_subpackage 文件夹中是 my_module.py
  4. 在 my_module.py 中存放着我的 _function,

应该是:

from my_package.my_subpackage.my_module import my_function

您还可以使用以下命令检查导入的模块中有哪些函数:

dir(my_package.my_module)

奖励:用诗歌更新更新所有依赖关系

为什么总有关于更新东西的加分部分?

总之,为了更新所有的库(依赖项)并将它们写入您的 poetry.lock,您运行:

poetry update

不要把它和更新诗歌、混淆,后者可以通过

pip install --upgrade poetry

或者

poetry self update

感谢阅读!

请关注我,了解更多关于 Python 和数据科学的知识!

查看本指南的第 1 部分,学习如何用传统的方式向 PyPI 发布 setup.py,一些其他的技巧,再加上一些幽默。那天我运气很好:

https://medium.com/@skylar.kerzner/publish-your-first-python-package-to-pypi-8d08d6399c2f

包装圈

原文:https://towardsdatascience.com/packing-circles-a9d1f775353b?source=collection_archive---------28-----------------------

交互式层次图

美国所有县的 Circlepacker 可视化(按人口)-图片按作者

你是否曾经处理过层次数据,并努力使其可视化?那这篇文章就送给你了!我最近偶然发现了 R 中的便捷的circle packer包,它使您能够创建交互式图表,便于分层数据的可视化,我想与您分享我的经验。

先决条件

为了创建如上所述的类似可视化,您首先需要安装以下软件包:

devtools::install_github("jeromefroe/circlepackeR")
install.packages("data.tree")
install.packages("htmlwidgets")library(circlepackeR)
library(data.tree)
library(htmlwidgets)

数据

在这个简短的示例中,我将使用包含州名、县名及其人口的美国县数据:

head(counties)# A tibble: 3,093 x 5
   country       state   county   population                       
   <chr>         <chr>   <chr>         <dbl>                             United States Alabama Autauga       55380 
United States Alabama Baldwin      212830 
United States Alabama Barbour       25361 
United States Alabama Bibb          22493 
United States Alabama Blount        57681 
United States Alabama Bullock       10248 

预处理

为了准备好数据,我们需要应用两个预处理步骤:

1.添加路径字符串列

counties$pathString <- paste(“world”, counties$country, counties$state, counties$county, sep = “/”)

新列应该被称为“pathString ”,并将您想要显示的所有层次级别连接成一个长字符串,该字符串以单词“world”开头,并使用“/”作为分隔符。在这一步之后,带有新添加的列的数据帧看起来是这样的:

country       state   county   population pathString                          
   <chr>         <chr>   <chr>         <dbl> <chr>                               
United States Alabama Autauga       55380 world/United States/Alabama/Autauga 
United States Alabama Baldwin      212830 world/United States/Alabama/Baldwin 
United States Alabama Barbour       25361 world/United States/Alabama/Barbour 
United States Alabama Bibb          22493 world/United States/Alabama/Bibb    
United States Alabama Blount        57681 world/United States/Alabama/Blount  
United States Alabama Bullock       10248 world/United States/Alabama/Bullock

2.将数据帧转换成一个data.tree数据结构

第二个预处理步骤包括将数据帧转换成 data.tree 数据结构。这听起来很复杂,但可以通过下面的函数轻松完成:

nodes <- as.Node(counties)

这是新创建的结构的样子:

levelName
world 
° — United States 
¦ — Alabama 
¦ ¦ — Autauga 
¦ ¦ — Baldwin 
¦ ¦ — Barbour
¦ ¦ — Blount
¦ ¦ — Bullock
..

我们准备好创造我们的观想了!

创建圆形包装图

创建 circlepackeR 图再简单不过了。只需运行以下代码:

#create circlepacker graph
p <- circlepackeR(nodes, 
                  size="population", 
                  color_min=rgb(255/255,0/255,0/255), 
                  color_max=rgb(0/255,0/255,0/255), 
                  width=1200, 
                  height=1200) #save the circle graph
saveWidget(p, file="circles.html")

注意上面的论点:

  • size :应该作为每个圆大小的列名。
  • ****颜色最小值:圆圈颜色范围的最小值。可以是十六进制、RGB 或 HSL 颜色。
  • color_max: 圆圈颜色范围的最大值。可以是十六进制、RGB 或 HSL 颜色。
  • width: 创建的圆形图形的宽度(像素)(如果图形很大,尤其有用)
  • ****高度:高度(像素)所创建的圆形图形(如果你的图形很大的话特别有用)

保存图表后,您将在指定的目录中看到一个 HTML 文件,该文件可以通过电子邮件或嵌入在网页中与其他人共享。此外,您可以使用 codepen.io 将它嵌入到一篇中型文章中(复制 HTML 源代码并根据它创建一个 codepen,如下所示:

调整图表

该图通常显示得很好,但有时导出图的字体大小有点太小。不幸的是,字体大小和任何其他样式选项都不能在图形创建过程中设置,但是您可以做一些事情!

由于导出的文件是一个 HTML 文件,您可以简单地在任何编辑器中打开它并搜索 CSS 声明:

<style type=”text/css”>.circlepackeR .node {cursor: pointer;}.circlepackeR .node:hover {
stroke: #000;
stroke-width: 1.5px;
}.circlepackeR .node — leaf {
fill: white;
}.circlepackeR .label {
font: 11px “Helvetica Neue”, Helvetica, Arial, sans-serif;
text-anchor: middle;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}.circlepackeR .label,
.circlepackeR .node — root,
.circlepackeR .node — leaf {
pointer-events: none;
}</style>

如果你有一些 CSS 知识,你会发现修改图形的布局很容易。如果以前从未使用过 CSS,这里是你如何改变字体大小和改变圆形轮廓的颜色:

更改字体样式

只需通过指定像素数(如 15px)来更改字体大小。此外,您可以将字体名称从“Helvetica 新”更改为任何想要的字体:

.circlepackeR .label {
font: 15px “Helvetica Neue”, Helvetica, Arial, sans-serif;
text-anchor: middle;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}

更改圆形轮廓颜色

如果你想改变圆轮廓(笔画)的颜色,你可以简单地在这里指定所需的十六进制代码(例如#FF0000):

.circlepackeR .node:hover {
stroke: #FF0000;
stroke-width: 1.5px;
}

我希望这对你们中的一些人有用!

进一步阅读

****【1】jeromefroe—D3 可缩放圆形装箱可视化(教程):【http://jeromefroe.github.io/circlepackeR/】T2

****【2】circle packer Github 库:https://github.com/jeromefroe/circlepackeR

PageRank:从零开始的链接分析解释和 Python 实现

原文:https://towardsdatascience.com/pagerank-3c568a7d2332?source=collection_archive---------1-----------------------

启动谷歌的算法

克里斯蒂安·威迪格在 Unsplash 上拍摄的照片

介绍

在前一篇文章中,我们已经介绍了 HITS 算法并指出它的主要缺点。在本文中,我们将展示一种叫做 PageRank 算法的高级方法。我们将简要解释 PageRank 算法,并演练整个 Python 实现。

https://chonyy.medium.com/hits-algorithm-link-analysis-explanation-and-python-implementation-61f0762fd7cf

PageRank 最好的部分是它的查询独立。我们不需要根集来启动算法。

PageRank 和 HITS 最大的区别

  • HITS 根据 hub 和 authority 值计算权重
  • PageRank 根据网站之间传递的比例排名计算排名

根据谷歌的说法,

PageRank 的工作原理是通过计算一个页面的链接数量和质量来粗略估计该网站的重要性。潜在的假设是,更重要的网站可能会从其他网站收到更多的链接。

算法

请随意查看评论良好的源代码。这真的有助于理解整个算法。

https://github.com/chonyy/PageRank-HITS-SimRank

算法步骤如下所列

  • 用值 1 初始化每个节点的 PageRank
  • 对于每次迭代,更新图中每个节点的 PageRank
  • 新的 PageRank 是其所有父级的比例等级的总和
  • 对新的 PageRank 应用随机漫步
  • PageRank 值将在足够的迭代后收敛

PageRank 方程

图片由 Chonyy 提供

Python 实现

初始化 PageRank 值

我们在节点构造函数中初始化 PageRank 值。

PageRank 一次迭代

这是 PageRank 主函数。就像上面解释的算法一样,我们只需在每次迭代中为每个节点更新 PageRank。这个算法的关键是我们如何更新 PageRank。

计算新的页面排名

  • 指定节点的内部邻居,即其所有父节点
  • 对其所有邻居的比例等级求和
  • 用阻尼因子 d 计算随机走出链路的概率
  • 用比例排名和随机漫步的和来更新 PageRank

结果分析

让我们在回购中的 数据集 上测试我们的实现。我们在所有结果中设置阻尼因子= 0.15。

graph_1.txt

图片由 Chonyy 提供。

结果

结果遵循节点值1, 2, 3, 4, 5, 6的顺序。

让我们观察图表的结果。图中的节点是单向流动的。我们知道 PageRank 算法将从邻居中累加比例等级。这意味着节点 2 将累积来自节点 1 的等级,节点 3 将累积来自节点 2 的等级,等等。

换句话说,节点 6 将累积从节点 1 到节点 5 的等级。这就是 node6 排名最高的原因。

graph_2.txt

图片由 Chonyy 提供。

结果

节点形成一个循环。所以等级的传递将会是一个无止境的循环。并最终收敛到一个相等的值。

graph_3.txt

图片由 Chonyy 提供。

结果

如果我们从物理学的角度来看这个图表,我们假设每个环节都提供相同的力。直观地说,我们可以计算出,与旁边的节点 1 和节点 4 相比,中心的节点 2 和节点 3 将会受到更大的力。

graph_4.txt

图片由 Chonyy 提供。

结果

节点 1 和节点 5 都有四个邻居。但是为什么 Node1 的 PageRank 最高呢?这是因为节点 5 的两个内邻居具有非常低的等级,它们不能向节点 5 提供足够的比例等级。

节点 6 和节点 7 具有较低的 PageRank,因为它们位于图的边缘,并且只有一个邻居。对他们来说等级不够。

IBM.txt

图片由 Chonyy 提供。

结果

结果遵循节点值顺序2076, 2564, 4785, 5016, 5793, 6338, 6395, 9484, 9994

节点 9484 具有最高的 PageRank,因为它从其内部邻居获得许多成比例的等级,并且它没有外部邻居来传递该等级。根据这一观察,我们可以猜测,具有许多内邻居而没有外邻居的节点往往具有较高的 PageRank。

讨论

让我们做一个有趣的实验。假设我们要增加每个图中 node1 的枢纽和权限。怎么才能做到呢?

graph_1.txt

因为 PageRank 是用其父级的比例排名的总和计算的,所以我们将关注图周围的排名流。为了增加 PageRank,直观的做法是增加其父节点来传递其中的排名。

与原始图相比,我们添加了一条额外的边(节点 6,节点 1)来形成一个循环。这样,每个节点的 PageRank 是相等的,大于 node1 的原始 PageRank 值。

graph_2.txt

同样,我们希望增加 node1 的父节点。父节点越多,传递给节点 1 的秩就越多。

因此,我们添加了一条额外的边(节点 4,节点 1)。在原始图中,节点 1 只能从节点 5 获得他的等级。但是在添加了这条额外的边之后,节点 1 可以获得由节点 4 和节点 5 提供的等级。

graph_3.txt

添加新边(节点 4,节点 1)。就像我们在 graph_2 中解释的那样,节点 1 可以通过这种方式从节点 4 获得更多的排名。请注意,这条规则可能并不总是适用。这只是我通过观察得出的直觉方法。

计算性能

趋同;聚集

现在我们都知道,经过足够的迭代,PageRank 将总是收敛到一个特定的值。为什么我们不画出来看看它收敛的有多快?

在 graph_4.txt 上测试收敛性

图片由 Chonyy 提供。

从图表中,我们可以看到曲线在开始时有点颠簸。等级在每个节点之间传递,最终达到平衡。每个节点的 PageRank 值在迭代 5 时开始收敛。

请注意,完成计算可能不总是只需要这几次迭代。例如,如果我们在 repo 中的 graph_6 上测试这个算法,它有 1228 个节点和 5220 条边,即使 500 次迭代也不足以使 PageRank 收敛。并且由于大量的边,计算会花费很长时间。

边数

图片由 Chonyy 提供。

我们用不同数量的总边运行 100 次迭代,以便发现总边和计算时间之间的关系。正如你所看到的,边数对计算时间的推断几乎是线性的,这是非常好的。

请注意,它不是完全线性的原因是边彼此链接的方式也会稍微影响计算时间。

结论

这并不奇怪,PageRank 并不是 Google 搜索引擎中实现的唯一算法。现实世界中的问题远比单一算法复杂。例如,他们可以对每个节点应用额外的权重,以更好地反映网站的重要性。所以有另一种算法结合 PageRank 来计算每个站点的重要性。

根据谷歌的说法,

谷歌使用各种技术评估每个网页的重要性,包括其专利的 PageRank 算法。

源代码

https://github.com/chonyy/PageRank-HITS-SimRank

PageRank 图解

原文:https://towardsdatascience.com/pagerank-illustrated-c056a45a2f60?source=collection_archive---------37-----------------------

关于“推荐”的例子

Unsplash 上由 Belinda Fewings 拍摄的照片

PageRank 是为图中的节点分配重要性分数的关键算法。你可以说它推出了谷歌。

在这篇文章中,我们用最简单的例子来说明 PageRank 能够展示的关键“精心制作的行为”。

在谷歌网络搜索设置中,图表的节点是网页。“成千上万”的人。如果页面 A 包含到页面 B 的超链接,这在图中被捕获为从 A 到 B 的弧线。因此,图是有向的。

PageRank 适用于任何需要对其节点进行重要性评分的图,例如一个社交网络,其节点是人,其边捕捉了他们之间的某些关系。

在这篇短文中,我们将用一个例子来说明这个算法。我们的节点是某个职业的人。比如医生。引用由从引用者到被引用者的弧线表示。我们希望根据推荐给推荐图中的各种专业人士分配“重要性分数”。

一个简单的重要性分数是一个参考对象收到的推荐的数量。这个数字越大,重要性分数越高。PageRank 有更高级的机制。我们的工作就是在这篇短文中尝试一下。

考虑下面描述的情况。箭头表示推荐。

重要人物推荐:作者图片

p 得到许多推荐,所以被认为是重要的。q 只有一个推荐人。虽然是来自一个重要的人。所以 PageRank 也认为 Q 很重要。

把它和下面的对比一下。

一个重要的人给了很多推荐:作者图片

在这种情况下,PageRank 会认为 Q 不太重要。这是因为 P 给了多人推荐,从而稀释了她对 q 的推荐。

有意思。让我们看看当 Q 得到许多推荐时会发生什么。q 的重要性可以表示为与推荐的加权和成比例。推荐的权重基于推荐人的重要性,被她给出的推荐数量稀释。所以来自的重要推荐谨慎推荐的人最重要。

现在考虑一下这个。该图可以具有有向圈。例如,P 和 Q 可以相互推荐。在更复杂的情况下,可能会有一长串的推荐。如 P → Q → R → S → P,一般来说,图可以是任意复杂的。那是任何有向图。

所以情况是递归的。那么我们如何计算重要性分数呢?在这里,我们不会正式地描述 PageRank 算法,甚至不会完整地描述它。我们将在下面的有向图中尝试一下它是如何工作的。

该图有三个节点 P、Q 和 r。该算法将重要性分数建模为节点上的概率分布。(认为,相对重要。)它从初始概率分布开始,并迭代地调整概率,直到它们停止变化(很多)。关键是,如果它们停止变化,它们就已经“安定下来”,即处于某种形式的平衡。我们将通过遍历一个迭代来感受“安定下来”。

说明迭代重要性分数计算的图表:作者图片

让我们从初始化开始,其中所有三个节点的重要性概率都是⅓,表示同等的重要性。接下来,让我们一次看一个节点。我们将根据其邻居的当前重要性分数来更新其重要性分数。(节点的内部邻居是具有进入前者的弧线的节点。)然后继续迭代。这在下面描述

Iteration  I(P)  I(Q)  I(R)
0           1/3   1/3    1/3
1          **>1/3**    .      .

在第一次迭代中,p 的重要性被提升了,因为算法意识到 p 已经收到了两个推荐人,他们的重要性分数目前都是⅓。相比之下,q 和 r 只收到了一个当前重要人物⅓.的推荐

请注意,更新后的重要性分数总和需要达到 1。我们不会解释这是如何发生的。为了向你保证这是可以做到的(虽然你不想这样做),你可以用每个非标准化分数除以所有分数的总和。即显式地将一组正得分转换成概率分布。

总结

在这篇文章中,我们展示了 PageRank 算法如何产生比简单算法更细微的重要性分数,简单算法只计算网页的链接数量。

在这个过程中,读者还将理解(I)为什么算法是迭代的(简单的回答:这是产生细微差别的行为所需要的)以及(ii)更好地理解它的用例的宽度。o 后者,本质上是任何需要对其节点的重要性进行评分的图,web 图和社交网络是两个最突出的例子。

延伸阅读

https://en.wikipedia.org/wiki/PageRank

Power BI 中的分页报告可视化—您需要知道的一切!

原文:https://towardsdatascience.com/paginated-report-visual-in-power-bi-everything-you-need-to-know-34a39c9f6fe7?source=collection_archive---------7-----------------------

有人告诉你 SSRS 和分页报告已经死了?再次检查,因为 Power BI 中全新的分页报告视觉效果将继续存在并丰富您的报告解决方案!

作者图片

最令人期待的 Power BI 特性之一终于出现了!不,这不是新的花哨的小倍数改进,或另一个新鲜的人工智能东西…它甚至不是对数据流的 DirectQuery 支持,也不是数据集可发现性(顺便说一下,这两者都是非常酷的补充)。猜猜看,分页报告可视化刚刚进入 Power BI 桌面!此时此刻,它仍在预览中,但周围的兴奋是巨大的。

我听到了,我听到了…谁需要这个东西?!为什么人们会在超级现代的闪亮电源 BI 解决方案中使用(几乎)被否决的技术?!更有甚者,分页报告几乎都是枯燥的表格+矩阵。我们在 Power BI 中推出了这两款产品,并提供了更多的定制选项和属性,让它们看起来更好看。

历史课…

我们这些上了年纪的人往往会说:“你知道我年轻时是怎么做的……”或者“我们 X 年前也是这么做的……”在 Power BI 出现之前,分页报告就已经进入了我们的生活。2004 年,微软推出了名为 SQL Server Reporting Services 的 SQL Server 2000 外接程序,该工具成为了本世纪头十五年的报告标准(直到今天,有些人还会争论更久)。

https://www . pexels . com/photo/Stonehenge-under-nimbostratus-clouds-161798/

数据领域的发展速度很快!速度极快!因此,新的挑战需要新的解决方案,Power BI 于 2015 年推出,以最高效、最引人注目的方式回答尽可能多的业务报告问题。然而,和 SSAS 多维一样,它仍然拒绝放弃(即使微软在最近几年将所有东西都变成了表格),SSRS 是许多遗留 BI 解决方案的一个组成部分,这些解决方案仍然工作——不仅仅是工作,它们工作得相当好!

好吧,与 Power BI 相比,可视化类型的数量和它们的定制可能看起来很笨拙,但是,嘿,我们可以编写 Visual Basic 来扩展内置特性!使用了类似下面的代码片段使表格行颜色交替的人请举手:)

=iif(rownumber(nothing) mod 2 = 0,"LightGrey","Transparent")

是的,我知道,在 Power BI 中格式化你的表格要容易得多,只需点击交替行选项,但是 VB 更有趣:)(当然,只是开玩笑)

我自己在 2-3 年前认为 SSRS 已经死了…哦,我错了!你知道电影《老无所依》吗?在我的案例中,它可以很容易地翻译为:“没有老(数据)人的 SSRS”…即使大多数公司迁移到 Power BI 并调整他们的报告解决方案以适应新的云环境,仍然有大量的客户不愿意停止使用良好的旧分页报告。

老男人没有 SSRS

相信我,我看到了许多混合解决方案,其中大多数报告都迁移到 Power BI,但某些报告仍然以分页形式存在,没有任何在 Power BI 中重新创建它们的意图…我听到你问为什么会这样?动力阿碧难道不是更强大、更高效、更有力的工具吗?当然是啦!这是毫无疑问的。如果从性能的角度来看, VertiPaq 是一个能够以惊人的速度压缩和处理大量数据的庞然大物…从数据建模的角度来看,我敢打赌 Power BI 是目前最全面的解决方案。您可以使用各种强大的功能来扩展传统的数据建模原则,例如复合模型角色扮演维度、数据流等等。

不要谈论数据转换和数据整形的能力,以最佳方式为最终报告解决方案准备您的数据。

分页报告不能替代 Power BI!

当然,如果你把力量 BI 和 SSRS 放在一起,胜利者是显而易见的!但是,如果您逐一比较这两个工具的特性,您就忽略了这一点。分页报告不是 Power BI 的替代品,而是 Power BI 的补充!简而言之,SSRS 提供了一些 Power BI 无法复制的特性。例如,如果您的用户坚持要像素完美、可打印或易于导出的报表,那么没有比分页报表更好的选择了!它们的名字说明了一切——它们被称为分页的,因为它们被设计成很适合页面!

到目前为止,分页报告和 Power BI 报告之间的集成是不可能的。非此即彼。现在,有了分页报表可视化,您可以利用两个世界的最佳功能!

创建分页报表

为了能够使用分页报表可视化,首先需要构建分页报表本身。因此,让我们使用 Adventure Works 示例数据库构建一个非常基本的分页报表。我有意使事情保持简单,因为本文的目的不是深入分页报告的创建过程,而是更多地关注分页报告和 Power BI 之间的集成。

如果你计划使用分页报告,你必须拥有某种高级许可(T1),即 EM1-EM3 SKU、P1-P3 SKU 和 A1-A6 SKU。它也可以基于每个用户提供 Premium per user,这是基于 Premium Gen2 构建的,也有公共预览版。请记住,您要将分页报表发布到的工作区必须定义为高级工作区,这一点很重要

作者图片

为了构建分页报告,您需要一个单独的工具,称为 Power BI Report Builder 。如果您曾经在 SSRS 报表生成器中工作过,整个环境看起来会很熟悉。下面是我将用来为分页报表创建数据集的查询:

SELECT p.Color,
       fsi.SalesAmount,
       d.FullDateAlternateKey AS [date]
FROM FactInternetSales fsi
    INNER JOIN DimProduct p
        ON p.ProductKey = fsi.ProductKey
    INNER JOIN DimDate d
        ON d.DateKey = fsi.OrderDateKey
WHERE d.FullDateAlternateKey >= @dFrom
      AND d.FullDateAlternateKey <= @dTo;

基本上,我想显示 FactInternetSales 表中每笔交易的产品颜色、销售额和日期。如我所说,这是一个非常基本的设置。

作者图片

因为我的查询是参数化的,所以我需要映射参数(在我的例子中,这些是开始和结束日期)。如果您使用附加参数(例如,颜色),请确保也映射它们。我已经在报告画布上放置了一个简单的矩阵,现在我准备将报告发布到我的工作区:

作者图片

通过查看报告名称旁边的图标,您可以立即注意到分页报告不同于“经典”的 Power BI 报告。而且,如果我运行分页报告,它会很好地显示基于我设置的日期参数的结果:

作者图片

到目前为止,没有什么特别的,因为你必须决定你是否要使用 Power BI 或分页报告…

在 Power BI 报告中运行分页报告!

这里是真正的奇迹发生的地方!现在,您可以将分页报告集成到 Power BI 报告中,并从那里运行它!让我们一步一步来看看是怎么做的…

作者图片

在 Power BI Desktop 中,我使用了完全相同的数据集(AdventureWorksDW2017 ),并且创建了与之前分页报告中相同的矩阵。现在,我将在报告画布上拖动一个全新的分页报告,并按照指示连接到我的分页报告

作者图片

接下来是有趣的部分,因为您需要配置一些东西。在我选择了我想要连接的分页报告(在我的例子中,我的分页报告)之后,我需要提供参数值,以便可以从 Power BI 中交叉过滤可视化内容!因此,我将创建两个度量来使用它们提供参数值:

dFrom = MIN(FactInternetSales[OrderDate])
dTo = MAX(FactInternetSales[OrderDate])

我将拖动这些度量值作为分页报表可视化的参数,并将这些值赋给我的原始参数:

作者图片

当我单击“查看报告”时,您会注意到我将在 Power BI 中直接呈现分页的报告!多酷啊!两个矩阵之间的结果是相同的:

作者图片

对于分页报表视觉效果,还有其他格式选项。显然,定制的可能性不如“常规”Power BI 视觉效果多,但仍然有用,尤其是工具栏和参数属性:

作者图片

它是如何在后台工作的?

因为视觉在交叉过滤方面完全响应,所以让我们检查如果我改变切片器值会发生什么:

作者图片

正如您所期望的,Power BI visual 会立即反映这些更改,但是对于分页的报表 visual 没有任何变化。默认情况下,您需要显式单击此应用更改按钮,以便将新的切片器值传播到基础数据源。您可以通过在“格式”面板中启用自动应用过滤器来改变这种行为,但我建议不要这样做,因为默认设置是在考虑减少查询的情况下指定的。我们将很快解释当您更改切片器值时,后台发生了什么…

因此,我很想知道当您在 Power BI 中呈现分页报告时会发生什么,以及如何检索数据。让我们首先启动 DAX Studio 并捕获 Power BI 生成的查询:

作者图片

嗯,这很奇怪,因为没有生成 SQL 代码,我希望看到类似 SQL 语句的东西。这个查询基本上只计算我们对 dFrom 和 dTo 参数的度量。因此,我打开了一个很好的旧 SQL Server Profiler 来检查下面到底发生了什么。

作者图片

这就是了!这是从 AdventureWorksDW2017 数据库中检索数据的 SQL 语句。看着眼熟?没错,这就是我们用来为分页报表创建原始数据集的查询!然而,Power BI 生成了一个动态 SQL 语句,用从 Power BI slicer 获取的参数包装了我们的原始查询(这就是我们在 DAX Studio 中看到的查询)!

如果我更改切片器的值,我们应该看到具有不同参数值的新动态 SQL 查询(我将开始日期设置为 6 月 25 日)。让我们来看看是不是这样:

作者图片

嘭!这就对了。正如预期的那样,我们有了一个新的 SQL 语句——事实上,基本语句是相同的,但是参数值发生了变化,生成并执行了新的动态 SQL。

由此得出结论 分页报表可视化工作于 DirectQuery 模式

导出数据

好吧,这一切都很好,但我听到你问:为什么我首先需要我的 Power BI 报告中的分页报告可视化?我将发布我们的 Power BI 报告,其中包括对工作区可视化的分页报告,并向您展示使用案例。

让我们假设一个用户请求从视觉效果中导出数据。

作者图片

当您从 Power BI 原始矩阵导出数据时,唯一可用的格式是 xlsx。另一方面,如果我在分页的报表视图中单击 Export,看看我有什么可以处理:

作者图片

哇!不仅仅是 Excel!我可以导出各种不同的格式,包括 pdf(如果我需要打印一些东西的话)(哦,是的,相信我,周围有很多人仍然喜欢打印他们的报告),或者 pptx(如果我需要它来做我的精彩 PowerPoint 演示的话)!不要忘记为什么分页的报表首先被称为分页的:)

接下来,如果我的视觉效果中的数据超过了一个页面所能容纳的范围,并且想将其导出为 pdf,会发生什么情况?让我们看看 Power BI matrix 如何渲染为 pdf:

作者图片

哦,伙计,我丢失了数据!这是为什么呢?6 月 3 日到 6 月 30 日之间我的日期在哪里?我在我的 Power BI 报告中看到了它们。是的,你做到了。但是,您可以滚动 Power BI 报告中的表格,但不能滚动 pdf 格式的图像!

让我们看看如果从分页的报表可视化中导出数据会发生什么:

pdf 报告的第 1 页

pdf 报告的第 2 页

哦,看起来多干净漂亮啊!

结论

在 Power BI report 中直接呈现分页报告的可能性是对 Power BI 已经提供的广泛功能的巨大补充。拥有另一个(非常强大的)工具只会增加您的报告解决方案提供的业务价值。

总会有一些用户坚持要求像素完美、打印友好的数据,而 Power BI 本身无法满足这些要求。但是,现在,通过集成成熟的技术,如分页报告,您可以从一个位置满足所有请求,甚至可以一次对数据应用所有过滤器!

尽管有一些限制,我相信分页报告可视化是 Power BI 最近最大的改进之一!

感谢阅读!

成为会员,阅读媒体上的每一个故事!

streamlit 中的分页

原文:https://towardsdatascience.com/pagination-in-streamlit-82b62de9f62b?source=collection_archive---------18-----------------------

使用会话状态实现下一个/上一个功能

照片由本斯·博罗斯Unsplash 上拍摄

介绍

这篇文章旨在演示如何使用Streamlit中的会话状态来存储关于某些变量的信息,并防止它们在运行中更新。但是什么是Streamlit

Streamlit是一个 python 库,旨在使 python 开发者构建 web 应用程序来展示你的工作变得非常容易。在这个包到来之前,FlaskDjango是开发人员选择使用的 goto 库,以便在 web 上开发和部署他们的应用程序;然而,这两种框架都要求用户编写 HTML/CSS 代码来将他们的工作呈现为 web 应用程序。Streamlit抽象了所有这些,并提供了一个简单的 pythonic 接口来添加自定义组件,如滑块、下拉列表、表单、文本框等。同时也允许人们添加他们自己的定制 HTML/CSS 组件。如果你是 Streamlit 的新手,他们的官方文档非常适合让你入门。

在这篇文章中,我将讨论我们如何构建一个组件来帮助实现分页支持,因为它不是开箱即用的,需要一个小技巧SessionStates.

什么是分页?

Wikipedia 将分页定义为将文档分成离散页面的过程,这些页面可以是电子页面,也可以是印刷页面。

所以基本上,如果你有很多内容想要显示在你的应用程序/网页上,你可以将它们分成多个组件页面,一个接一个地显示,在页面之间切换的触发器可以是像Next按钮或Previous按钮这样的按钮。

在许多网页上,你可以看到分页为 eg。

  • 在任何有大量产品展示的电子商务网站上,它们通常以页面方式展示。
  • 给定查询的谷歌搜索结果总是在页面中可见,而不是一次全部可见。

Streamlit 的当前版本不提供开箱即用的支持来处理这种用例,但在本帖中,我们将讨论一种使我们能够以整洁的方式执行分页的方法。

问题是

如果我们看一个简单的演示代码来显示一个数据帧到我们的屏幕上,我们可以看到代码如下:

在屏幕上显示数据帧

我们在这里面临的问题是,如果我们想做分页,我们将必须定义一个页码,如果我们在这里初始化它。

接下来,我们需要创建一个名为NextPrevious的按钮,它将在数据帧中的下一个或上一个条目之间移动。但是,当我们将变量 page_number 链接到这些按钮时,每次点击页码或会话中有任何组件的状态更改时,变量都会被重新初始化为它的初始值,我们永远不会动态地跨页面移动。假设我们有这样一个代码

我们已经创建了一个按钮 next 和一个按钮 previous,当单击它们时,会根据一些条件检查来更改页码(即,在第一页和最后一页的情况下不要超出范围;视情况分别回滚到最后/第一页)。如果我们按原样使用此代码并在应用程序中显示数据帧,我们的输出将如下所示:

图片由 Vinayak 提供

当我们单击“下一步”时,页码被重新初始化为 0。这就是为什么我们永远无法超越第一页。页码重新初始化为 0,递增 1,如此循环往复。

同样,当我们点击“上一页”时,页码会重新初始化为 0,然后递减到最后一页,这种情况会一直持续下去!

解决方案

这段代码Thiago Teixeira 慷慨地借给 streamlit 的用户,他是 streamlit 的联合创始人,允许我们创建对象,我们可以在一个会话中跟踪这些对象,而不用一次又一次地覆盖/重新初始化它们。

您基本上是将上面这段代码中给出的代码复制到一个名为 SessionState.py 的文件中,并将其保存在与应用程序文件相同的工作目录中。接下来,你只需要通过使用如下所示的 get 方法,将你想要阻止重新初始化的变量封装在一个会话状态对象中。

如果你有更多的变量要记录,你可以写

import SessionState
ss = SessionState.get(page_number = 0, var_1 = True, var_2 = "Streamlit demo!")

它也能很好地工作。但是这里有一个警告

每个应用程序只能有一个会话状态对象

这一点很重要,否则如果你试图用多个变量/属性初始化多个状态,将会失败并抛出一个错误。所以你必须 小心 哪些变量要动态跟踪,哪些要通过会话跟踪,并把后者放在你要创建的唯一的 SessionState 对象中。上述代码的结果非常完美,如下所示

图片由 Vinayak 提供

如果你喜欢上面的内容,你可能会对我写的其他文章感兴趣。你可以在这里找到它们。

这里有一个帮助你使用 Pytorch 建立自己的视频背景模糊功能

https://towards data science . com/semantic-image-segmentation-with-deeplab v3-py torch-989319 a9 a4fb

参考

  1. 该应用源代码的 Github 链接
  2. 数据集引用—来自 Kaggle 的 auto-mpg . CSV

使用 BigQuery 轻松扩充数据

原文:https://towardsdatascience.com/painless-data-augmentation-with-bigquery-da1e30002af3?source=collection_archive---------37-----------------------

使用 BigQuery 公共数据快速扩充数据集

卢卡斯·布拉塞克Unsplash 拍摄的照片

对于数据科学家来说,Google Cloud 的 BigQuery 是一个很好的工具,可以快速轻松地用外部数据扩充他们的数据集。具体来说,BigQuery 有一个来自各种不同来源的公共数据集的列表。你需要的只是一个谷歌云账号和一些基本的 SQL 知识。

https://cloud.google.com/bigquery/public-data [## BigQuery 公共数据集|谷歌云

cloud.google.com](https://cloud.google.com/bigquery/public-data)

以下是一些有用的公共数据集:

一个简单的例子

我认为 BigQuery 公共数据集中最有用的一个是美国人口普查 ACS 数据,它给出了按地理位置(按州、邮政编码、县等)细分的多年数据。).

它有许多重要的人口统计信息,如人口(按年龄、种族、性别、婚姻状况等细分)。),教育水平,就业,收入等等。

例如,假设我想查询 NYC 地区三个邮政编码的总人口和家庭收入中值。有一个名为zip_codes_2018_5yr的表格给出了 2018 年人口普查数据的 5 年估计,按邮政编码细分。

我的查询看起来是这样的:

SELECT 
  geo_id, -- Where geo_id is the zip code
  total_pop,
  median_income
FROM 
  `bigquery-public-data`.census_bureau_acs.zip_codes_2018_5yr
WHERE 
  geo_id in ("11377","11101","10708");

我可以在 BigQuery UI 中运行它…

BigQuery UI 的屏幕截图

并得到以下结果…

在 BigQuery UI 中查看查询结果

太好了!我在 0.4 秒内得到了答案,现在我可以返回并扩展我的查询来获得多年的数据。或者,我可以将结果导出到 CSV 或 JSON 文件,将其与我的数据连接起来。

显示 BigQuery 结果导出选项的屏幕截图

最后,作为奖励,您可以通过 Python 使用以下包连接到 BigQuery:

链接/延伸阅读

感谢阅读!如果您觉得这很有帮助,如果您有任何注释、问题或者您有喜欢的 BigQuery 公共数据集,请告诉我。

你可以通过 Medium、Twitter 或 LinkedIn 联系我!

使用米托轻松加速 Python 中的数据分析

原文:https://towardsdatascience.com/painlessly-speed-up-your-data-analysis-in-python-with-mito-2b79de4f2f46?source=collection_archive---------12-----------------------

一种快速清理、过滤和可视化电子表格格式 Python 数据的方法

米克·豪普特在 Unsplash 上的照片

您的旅程概述

  1. 设置舞台
  2. 安装米托
  3. mito sheets 的基础知识
  4. 用米托清洗数据
  5. 用米托过滤数据
  6. 用米托可视化数据
  7. 包装

1 —搭建舞台

我一直在寻找可以帮助加快数据分析探索阶段的新工具。尽管您应该对您选择的工具有信心,但是与可能改进您的过程的新工具保持同步也是很好的。

几周前,我偶然发现了米托,这是一个能让你在 Jupyter 笔记本上使用 excel 电子表格的工具。我最初的反应是,这似乎是一种倒退;如果需要 excel,那就用 excel。否则,使用更多代码繁重的工具,如 Pandas 来完成这项工作。然而,我对米托与笔记本电脑环境的融合感到惊喜😃

在这篇博文中,我想向你展示米托作为你的数据分析工具链中的一个便利工具可以做些什么。具体来说,我将使用米托着重完成以下三项任务:

  • 清理数据,
  • 过滤数据,
  • 可视化数据。

我将把米托和你们在熊猫身上做的事情进行对比。正如您可能怀疑的那样,这两种工具各有优缺点。读完这篇博文后,你就可以决定是否要将米托的一些功能应用到你的日常工作流程中。

声明: 我不以任何方式赞助或隶属于米托、熊猫或与这些软件在同一领域的任何其他软件。

2 —安装米托

安装米托相当简单:首先需要在终端或命令提示符下运行以下命令:

python -m pip install mitoinstaller

现在你已经下载了米托安装程序。要运行米托安装程序,请使用以下命令:

python -m mitoinstaller install

如果有问题,可以查看常见安装错误页面。

重要: 你需要 3.6 或更高版本的 Python 才能运行米托。如果您的 Python 版本是 3.5 或更低,那么您将严重错过其他 Python 特性,如data classes。如果可能的话,将您的 Python 发行版升级到最新的稳定版本。

3 —有丝分裂表的基础

要开始使用米托,请打开一个 JupyterLab 笔记本,并编写以下代码:

import mitosheet
mitosheet.sheet()

如果上一步中的安装正确,那么您应该会在笔记本中看到以下 GUI(图形用户界面)弹出:

您现在已经打开了一个空的米托工作表。在继续之前,您可能想看看米托 GUI 中的标题。有用于导入和导出数据、添加和删除列、绘制数据、合并数据等的按钮💪

因此,正如您可能已经猜到的,将数据输入米托的一种方法是使用 GUI 中的 import 按钮。这将打开一个文件浏览器,您可以在其中选择要导入到米托的文件(如 CSV 文件)。

更常见的方法是使用 Pandas 中的导入功能,如read_csv()来导入数据。之后,数据帧被传入米托电子表格。让我们使用经典的泰坦尼克号数据集来探索如何处理米托的数据。这里可以下载泰坦尼克号数据集,但是不需要手动下载!只需运行:

import pandas as pdtitanic = pd.read_csv("[https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv](https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv)")titanic.head()

很酷,对吧?不是每个人都知道熊猫函数read_csv()可以接受 URL🔥

现在你需要做的就是写下:

import mitosheet
mitosheet.sheet(titanic, view_df=True)

您应该看到以下内容:

您已成功将数据集加载到米托。不要害怕四处点击,看看你是否能自己理解米托的一些功能。事实上,米托的一个吸引力在于它提供的许多功能是不言自明的。

在接下来的部分中,您将使用米托的泰坦尼克号数据集来了解一些很酷的功能!

4-使用米托清理简单数据

泰坦尼克号数据集中有一些缺失的数据。让我们关注列Embarked,它缺少两个值。要查找丢失的值,您可以通过单击Embarked列标题中的过滤符号对Embarked列进行排序。然后,您应该会看到以下菜单:

现在,您可以选择排序选项Ascending并按下高亮按钮Filter/Sort。然后应该对已装载的列进行排序。更重要的是,您现在会发现顶部缺少Embarked值的两行:

缺少Embarked值的两个乘客是小姐。陈月娇·伊卡德乔治·尼尔森·斯通夫人。通过他们泰坦尼克号幸存者网页的链接,你可以看到他们都是在南安普顿登上泰坦尼克号的。事实上,小姐。陈月娇·伊卡尔德是乔治·尼尔森·斯通夫人的女仆😮

你如何改变Embarked中缺失的两个条目来包含这个新信息?只需像在 excel 表格中一样点击条目,并使用南安普敦的S更新信息!当只有几个条目需要更改时,这比手动编写 pandas-query 要快。

最酷的事?如果你在米托工作表下面的单元格中查找,那么熊猫代码已经自动生成用于再现:

# Set column Embarked at index 829 in titanic to S
titanic.at[829, 'Embarked'] = "S"# Set column Embarked at index 61 in titanic to S
titanic.at[61, 'Embarked'] = "S"

米托给了我们熊猫函数.at(),这比更常用的.loc()熊猫函数更快。令人惊叹的是,像米托这样的图形工具生成的代码比许多开发人员在旅途中编写的熊猫代码更具性能。

age这样的其他列有许多缺失值。在这种情况下,使用 Pandas 以适当的方式填充这些值可能会更容易,比如使用.isna()这样的函数。同时使用熊猫和米托进行数据清理是一种有效的组合😃

5-使用米托过滤数据

正如您在上一节中看到的,虽然您可以使用米托处理简单的缺失值,但米托的主要优势在于我在数据探索中的选项。想根据条件检查某一列的某些值吗?这在米托做起来既快又简单。

假设您只想查看为旅行支付超过 20 美元的乘客。这时你可以做的是点击Fare列标题中的过滤符号来得到过滤菜单:

您可以在这里添加一个过滤器,并指定如何进行过滤。因此,您可以创建以下过滤器:

按下突出显示的按钮Filter/Sort应用过滤器!在米托的电子表格单元格下面,你可以看到漂亮的熊猫布尔索引代码:

# Filtered Fare in titanic
titanic = titanic[titanic['Fare'] > 20]

对于泰坦尼克号数据集,有很多过滤选项可供选择。我建议你试着过滤掉一些,看看米托有多简单。

6-使用米托可视化数据

作为最后一个展示,使用米托可以非常轻松地显示数据集中的各种要素。按下米托 GUI 顶部的Graph按钮开始。然后,您将看到弹出以下窗口:

您现在可以选择Chart Type以及X axisY axis的值。例如,让我们尝试一个条形图(默认),并为X axis选择Pclass(乘客等级):

上图不是世界上最美的。但是请记住,它应该主要用于数据探索,而不是最终结果数据可视化。你可以很容易地看到大多数乘客乘坐三等舱。

尝试一些其他的可视化。米托有四种内置酒吧类型:

  • 条形图,
  • 直方图,
  • 箱线图,
  • 和散点图。

所有的情节都是 Plotly 编的。在我的选择中,这些图应仅用作初始数据勘探。对于用于演示的可视化工具,我会推荐 Seaborn 或 PowerBI 等工具。

7 —总结

我发现米托有助于简单的数据清理、过滤和探索性的数据可视化。在某些情况下,米托生成的代码非常有性能,这很好。米托也可能对有更多商业分析背景的人有所帮助。

如果你需要了解更多关于米托的信息,那么请查阅米托文档。

喜欢我写的?查看我的其他帖子,了解更多 Python 内容:

如果你对数据科学、编程或任何介于两者之间的东西感兴趣,那么请随意在 LinkedIn 上加我并向✋问好

详细的 Pair plot 和 PairGrid

原文:https://towardsdatascience.com/pair-plot-and-pairgrid-in-details-f782975032ea?source=collection_archive---------12-----------------------

Amir-abbas Abdolali 在 Unsplash 上拍摄的照片

用真实数据演示 Pandas 和 Seaborn 库中的配对图

当我第一次学习绘制 pairplots 时,我在每个项目中都使用了一段时间。我仍然经常使用它们。配对图是一个图中的几个二元分布,可以只用一个简单的函数来制作。即使是最基本的,在有几个连续变量的数据分析项目中也非常有用。我们知道散点图被广泛用于表示两个连续变量之间的关系。配对图将几个散点图放在一个图中,并提供对角分布。这篇文章是关于如何制作不同风格的 Pairplots 的教程。

本文将涵盖:

  1. 使用 Pandas 和 Matplotlib 配对绘图
  2. 使用 Seaborn 库的更时尚和信息丰富的配对图
  3. 使用“PairGrid”功能制作更动态的配对图

资料组

我使用了这个著名的数据集,叫做“nhanes”数据集。我发现它很有用,因为它有很多连续和分类的特征。请随意从该链接下载数据集,以便跟进:

https://github.com/rashida048/Datasets/blob/master/nhanes_2015_2016.csv

如果这个数据集对您来说是新的,列名可能看起来有点奇怪。但是不用担心。当我使用它们时,我会解释它们的含义。

配对图

让我们先导入数据集

import pandas as pd
df = pd.read_csv("nhanes_2015_2016.csv")

数据集相当大。因此,我不能在这里显示截图。这些是数据集中的列:

df.columns

输出:

Index(['SEQN', 'ALQ101', 'ALQ110', 'ALQ130', 'SMQ020', 'RIAGENDR', 'RIDAGEYR', 'RIDRETH1', 'DMDCITZN', 'DMDEDUC2', 'DMDMARTL', 'DMDHHSIZ', 'WTINT2YR', 'SDMVPSU', 'SDMVSTRA', 'INDFMPIR', 'BPXSY1', 'BPXDI1', 'BPXSY2', 'BPXDI2', 'BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML', 'BMXARMC', 'BMXWAIST', 'HIQ210'], dtype='object')

我们将从使用 Pandas 库的最基本的“pairplot”开始。它在熊猫图书馆被称为“散点矩阵”。

在此之前,我应该提到我将使用数据集的一部分。因为如果我使用了太多的特征,不管你叫它什么,散点图或配对图都不会有太大的帮助。里面的每个情节都会太小。本演示选择了五个连续变量:“BMXWT”、“BMXHT”、“BMXBMI”、“BMXLEG”、“BMXARML”。它们代表人口的体重、身高、身体质量指数、腿长和臂长。

我们需要从 pandas 的库中导入 scatter_matrix,然后简单地使用 scatter_matrix 函数。

import matplotlib.pyplot as plt
from pandas.plotting import scatter_matrixscatter_matrix(df[['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML']], figsize = (10, 10))
plt.show()

输出:

作者图片

你从给定的变量中得到所有组合的二元散点图。每个变量都与其余变量相对应。对角线图是每个变量在 scatter_matrix 函数中的分布。

使用 seaborn 库可以获得相同的图。如你所知,seaborn 库有一些默认的风格。所以,最基本的 pairplot 也比 scatter_matrix 更时尚一些。我没有选择直方图,而是选择了密度图作为对角线图。

我将绘制对角线的密度图,只是有一点变化。所以,我将指定' diag_kind = 'kde '。如果你想保持直方图,只要避免指定任何东西。因为默认类型是直方图。

import seaborn as sns
d = df[['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML']]
sns.pairplot(d, diag_kind = 'kde')

作者图片

下一个图包括这个默认图的另一个变量。这一次,我将通过性别变量分离 pair 图中的所有图。同时,我使用 alpha 参数和边缘颜色添加了一些透明度。

d = df[['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML', 'RIAGENDR']]sns.pairplot(d, diag_kind = 'kde', hue = 'RIAGENDR', plot_kws={'alpha':0.5, 'edgecolor': 'k'})

输出:

作者图片

Paiplot 和 scatter_matrix 都基于散点图。PairGrid 给它带来了更多的灵活性。

配对网格

使用 PairGrid,可以生成一个空网格。以后你可以随心所欲地把它装满。让我们来看看实际情况:

g = sns.PairGrid(df, vars = ['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML'], hue = 'RIAGENDR')

这行代码将提供一个空网格,如下所示:

作者图片

现在,我们将填满那些空盒子。我将使用直方图的对角线图,其余的将保持散点图一样。它不一定是散点图。它可以是任何其他二元图。我们一会儿会看到一个例子:

g.map_diag(plt.hist, alpha = 0.6)
g.map_offdiag(plt.scatter, alpha = 0.5)
g.add_legend()

作者图片

我们使用性别参数来分离图,以使用“色调”参数来分别查看男性和女性的分布和散点图。接下来的图使用连续变量作为色调参数。我选择了“BPXSY1 ”,这意味着收缩压。我还将向数据集添加一个条件。我将只使用 60 岁以上的人的数据。

g = sns.PairGrid(df[df["RIDAGEYR"]>60],
   vars = ['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG',  'BMXARML'], hue = "BPXSY1")g.map_diag(sns.histplot, hue = None)
g.map_offdiag(sns.scatterplot)
g.add_legend()

作者图片

你可以看到散点图中的点有不同的阴影。颜色越浅,收缩压越低,颜色越深,收缩压越高。

看啊!下面的三角形和上面的三角形有几乎相同的情节。如果你只是切换下面三角形的坐标轴,你会得到上面三角形的坐标图。因此,如果您希望在 Pairplot 的下三角形和上三角形中看到不同类型的图,PairGrid 提供了这种灵活性。对于 pairplot 的上三角形,我们只需要提到 map_upper,对于下三角形,我们只需要提到 map_lower。

g = sns.PairGrid(df[df["RIDAGEYR"]>60],
    vars = ['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML'],
                hue = "RIAGENDR")g.map_lower(plt.scatter, alpha = 0.6)
g.map_diag(plt.hist, alpha = 0.7)

这将只绘制对角线和下面的三角形。

作者图片

让我们把上面的三角形也填满。我会用阴影绘制密度图。

g.map_upper(sns.kdeplot, shade =True)

作者图片

我认为在两个三角形中有两种不同类型的图比几乎相同的图更有用。

同样,如果你不想要任何其他类型,你可以完全避免上面或下面的三角形。这里我使用 diag_sharey = False 来避免上面的三角形。

g = sns.PairGrid(df[df["RIDAGEYR"]>60], diag_sharey = False, corner = True, vars = ['BMXWT', 'BMXHT', 'BMXBMI', 'BMXLEG', 'BMXARML'],
hue = "RIAGENDR")g.map_lower(plt.scatter, alpha = 0.6)
g.map_diag(plt.hist, alpha = 0.7)

输出:

作者图片

在这里!三角完全没了!

结论

在这里,我试图介绍几种不同的方法来制作和使用 pairplots。我还引入了 PairGrids,使 pair 图更加灵活。希望这是有帮助的,您将尝试更多的样式和选项的文档。

以下是相同内容的视频:

请随时在 Twitter 上关注我。

更多阅读

[## 熊猫总结数据的三个非常有用的功能

towardsdatascience.com](/three-very-useful-functions-of-pandas-to-summarize-the-data-491b64db9370)

用于数据预处理的熊猫备忘单

原文:https://towardsdatascience.com/pandas-cheat-sheet-for-data-preprocessing-cd1bcd607426?source=collection_archive---------3-----------------------

关于如何用熊猫预处理数据的实用指南

图片来源:斯蒂芬妮·克莱帕奇

你的“带回家的信息”是什么?

通过这篇文章,你会学到以下方法:

  • 导入和导出数据
  • 获取数据概览
  • 处理重复、缺失值、错别字、有比例关系的一对列

介绍

背景

理解数据结构及其特征是重要的关键之一,不仅对于创建高度精确的机器学习模型,而且从将其付诸实践的角度来看也是如此。

实际上,预处理数据的过程对于每个数据集都是不同的,需要像定制一样进行。所以我们在建立机器学习模型的时候,大部分时间都花在这部分。

我想分享的是

在这篇文章中,我将总结 Pandas 中常用于预处理数据的函数。

我是一名数据科学顾问,这篇文章基于我为各种公司分析大量数据的经验

在这篇文章的底部,我附上了包含我们将使用的 Jupyter 笔记本的链接。

导入模块

首先,我们导入以下我们将使用的模块。

  • 熊猫
  • Numpy
  • Scikit-learn|load_boston,预处理
import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
from sklearn import preprocessing

Jupyter 笔记本中的显示设置

接下来,我们将更改 Jupyter 笔记本中熊猫数据帧的显示行数和列数。

在本例中,我们将显示的行数和列数都设置为 50:

pd.set_option('display.max_rows', 50)
pd.set_option('display.max_columns', 50)

读取数据集

在这里,我们阅读我们将要研究的数据。
例如,scikit-learn 中的 Boston Housing 数据集将在本文中使用:

boston = load_boston()
df_X = pd.DataFrame(boston.data, columns=boston.feature_names)
df_y = pd.DataFrame(boston.target, columns=['target'])

读取 CSV 数据

一般来说,您可以通过 CSV 或 Excel 文件读取数据,具体做法如下:

df_X = pd.read_csv('boston_X.csv')
  • 如果表头不存在: 您可以通过添加表头=无来指定没有表头:
df_X = pd.read_csv('boston_X_noheader.csv', header=None)
  • 如果索引已经存在: 可以通过“ index_col=k ”将第 k 列指定为索引:
df_X = pd.read_csv('boston_X_withindex.csv', index_col=k)

读取 Excel 数据

熊猫也能接受 Excel(。xlsx)文件:

df_X = pd.read_excel('boston_X.xlsx')
  • Select sheet_name 如果您在一个 excel 文件中有多个工作表,您可以使用“ sheet_name 选择要读取的单个工作表:
df_X = pd.read_excel('boston.xlsx', sheet_name='sheet_X')
df_y = pd.read_excel('boston.xlsx', sheet_name='sheet_y')

数据概述

在本节中,我们将查看您已经阅读过的数据帧的概述。

在这里,我们再次读取新数据。然而,为了练习,数据的某些部分被有意修改。

df_X = pd.read_csv('boston_X_mod.csv')

形状

使用“shape”检查数据帧的行数和列数。在这个例子中,它是 509 行* 15 列。

df_X.shape

头,尾巴

使用“和“尾【T3”)检查前 x 行和后 Y 行的内容。

df_X.head(x)
df_X.tail(Y)

获取列名

df_X.columns

如果你想列一张清单

df_X.columns.tolist()

重复的行、列

有时,您会面对重复的行或列。(令人惊讶!)在实践中,数据集有时由人工制作或经常由人工组合和校正。因此,我们每次都必须仔细检查副本。

行(索引)

如何显示重复的行?下面是怎么做的。

  • 显示复制行的最后一行:
df_X[df_X.duplicated()]

  • 显示复制行的第一行:
df_X[df_X.duplicated(keep='last')]

  • 显示复制行的所有行:
df_X[df_X.duplicated(keep=False)]

如上所述,由于本文中使用的数据集被有意修改,因此出现了一些重复的行。在本例中,我们找到了 3 对重复的行:303 和 508;368 和 507;453 和 506。

圆柱

我们可以使用转置矩阵找到重复的列,就像找到行一样。

显示复制列的所有列:

df_X.T[df_X.T.duplicated(keep=False)].T

我们发现了我特意创建的重复列“TAX”和“TEST”。我们还可以像显示行一样,只显示第一列或最后一列。“测试”一栏后来被删除。

缺少值

检查缺少的值

原始数据集的另一个问题是缺少值。首先,我们使用“ pd.isnull ”来查看丢失值的位置。

它返回一个布尔格式的数据帧。除此之外,我们可以使用“ np.where ”检索相应的行和列:

np.where(pd.isnull(df_X))

我们发现丢失的值位于[296,12],[308,6],[494,7]。检查它们以防万一:

我们确认这些是丢失的值。

填补空白

其次,我们必须用一些替代值来替换这些缺失值,这些替代值可能是同一列中的均值或中值,也可能只是 0(这部分是展示您作为数据科学家的技能的好时机!).

使用替换,可以用指定的字母和数字替换空白。在这里,我们只是作为一个简单的例子向这些缺失值填充零:

df_X.replace(np.nan, 0)

我们只是确保丢失的值被替换为零:

检查变量类型以及如何找到错别字

接下来,我们将检查每一列的变量类型。检查变量类型不仅仅是为了“检查”。检查数据集是否包含错别字非常有用,尤其是对于数值。根据我的经验,这种错误已经发生过几次了。

" dtypes "显示所有列的变量类型:

df_X.dtypes

“DIS”(到五个波士顿就业中心的加权距离)和“B”(1000(Bk-0.63),其中 Bk 是按城镇划分的黑人比例)列似乎不是数字列。但是……等等,再检查一遍数据本身就好了!

如您所见,“DIS”和“B”列至少在前 5 行包含数值。这意味着这些列中包含了一些数值以外的元素。

在这里,我会告诉你如何找到他们。

首先,在 col_miss 中定义可疑列的列表。然后,提取列中的唯一值,并尝试将每个值转换为数字数据。如果值被恰当地表示为数值,我们就跳过它们。但是,如果这些值不能正确转换,我们将显示这些值:

col_miss = ['DIS', 'B']
for i_col in col_miss:
    for j in df_X[i_col].unique():
        try:
            float(j)
        except ValueError:
            print(j)

从结果中,我们发现了一个拼写错误 1..DIS 中的 7554 和 b 中的 396.9.9。正确的值分别是 1.7554 和 396.99。

因此,我们将更正这些值:

df_X.replace('1..7554', 1.7554)
df_X.replace('396.9.9', 396.99)
  • 改变数据类型

对于“DIS”和“B”列,使用“ astype ”将其转换为 float 格式,这是原始数据类型:

df_X[['DIS', 'B']] = df_X[['DIS', 'B']].astype(float)

唯一值的数量

在这里,我们使用“ nunique ”来查看每一列中包含多少不同的值(唯一值的数量):

df_X.nunique()

从这些结果中,我们可以看到 CRIM 有 504 个不同的值,而 CHAS 只包含两个不同的值,它坚持使用虚拟变量。

比例关系

在上面的内容中,我们确认了重复、缺失值和错别字。然而,即使两列之间的数字不完全匹配,一些列对有时彼此完全成比例。这里,我们通过使用“ MinMaxScaler ”对每一列的值进行规范化,来检查这种类型的列对是否包含在数据帧中:

mm = preprocessing.MinMaxScaler()
df_float = df_X.loc[:, df_X.dtypes == 'float64']
df_scaled = pd.DataFrame(mm.fit_transform(df_float), index=df_float.index, columns=df_float.columns)
duplicates = df_scaled.T[df_scaled.T.duplicated()]
duplicates.T

从输出中,我们发现“TEST2”(有意包含的)与“RM”成正比。在机器学习中,这样的比例特征意味着重复,所以我们需要去掉其中的一个。

删除列

这里,我们使用“drop”:
(axis = 1 表示在列方向上删除)删除了之前发现的重复列“TEST”和“TEST2”

df_X.drop(['TEST', 'TEST2'], axis=1)

形容

清理数据帧后,我们使用“ describe ”为数据帧的每一列导出基本统计参数,如平均值、标准偏差、最大值和最小值。

df_X.describe()

出口

数据预处理后,我们要做什么…?当然,救他们!这就是如何将数据帧导出为 CSV 和 Excel 文件。

  • CSV
    "index = False"从输出项目中排除索引
df_X.to_csv('boston_correct.csv', index=False)
  • Excel
df_X.to_excel('boston_correct.xlsx', index=False)

差不多就是这样!

感谢阅读这篇文章,并希望你喜欢它。我很高兴得到你们所有人的任何评论!

编码

https://github.com/rkiuchir/blog_TDS/tree/main/01_Pandas_Cheat_Sheet

链接

其他文章

https://rkiuchir.medium.com/20-background-image-in-python-basemap-using-arcgis-api-78c0d12b93be

个人网站

https://rkiuchir.github.io/

熊猫数据争论备忘单 2021

原文:https://towardsdatascience.com/pandas-data-wrangling-cheat-sheet-2021-cf70f577bcdd?source=collection_archive---------7-----------------------

KOBU 机构Unsplash 上拍摄的照片

要想超越数据分析 / 数据科学 / 机器学习在 Python 中,熊猫是你需要掌握的库。这里有一个备忘单是一些你可能不想错过的最常用的语法。

Pandas 包是当今使用 Python 进行数据科学和分析的最必要的工具。强大的机器学习和迷人的可视化工具可能已经吸引了你的注意力,然而,如果你在熊猫中没有良好的技能,你将不会走得很远。

所以今天我收集了一些最常用的熊猫基本功能供你参考。我将从创建数据帧开始,然后是数据整形、字符串查找、值排序等。

内容

  1. 数据帧创建
  2. 列重命名
  3. 数据插入
  4. 数据删除
  5. 处理空值
  6. 整形
  7. 基础数据观察
  8. 查询/检索数据
  9. 奖励:处理大数据:

数据帧创建

我相信有必要提一下熊猫数据框架的基本结构。说到数据,在大多数情况下,你会有变量和变量的观察值。在 Pandas 中,每个变量存储为一列,而与该变量相关的所有观察值存储为行。例如,如果你对一个变量 A 有 20 个观察值,那么在 Pandas 中,它将被表示为包含 20 行数据的“A 列”。

好了,我们开始吧!

  • 创建空数据框
import pandas as pd
# These are the 3 basic territories in Hong Kong. They are Hong Kong, Kowloon, and the New Territories.col=[‘香港’,’九龍’,’新界’]df = pd.DataFrame(columns=col)
df

退货:

一个空列表。

  • 使用列表创建数据框架。

就个人而言,我更喜欢以这种方式创建数据框架。

col=[‘香港’,’九龍’,’新界’]
ind=[1990,2000,2010]
Data= [[‘98731’,’34444',’99384'],[‘34323’,’44243',’88543'],[‘2222’,’4324',’3432']]df = pd.DataFrame(Data, columns=col, index=ind)
df

退货:

  • 使用字典创建数据框架。
Data= {‘A’:[98731,34444,99384],‘B’:[34323,44243,88543],‘C’:[2222,4324,None]}df = pd.DataFrame(Data)
df

熊猫用“无”代表空值。

重命名列

df = df.rename(columns={“A”:”香港”})df

退货:

插入

  • 列插入
# inserting column Dd = [“x”,”y”,”z”]df[“D”] = d
df

退货:

  • 行插入
# inserting the 4th rownew_row = {“A”:98989,”B”:77889, “C”:None, “D”:”z”}df = df.append(new_row, ignore_index=True)
df

删除

  • 降一列
# to drop several columns, you can use a list. 
# E.g. df.drop(["C","B"],axis=1)
# to make permanent change, add inplace=True
# dropping column C onlydf.drop(“C”,axis=1)

  • 降一排
# to make permanent change, inplace=True
# dropping a row with index "0"df.drop(0)

  • 删除重复项
df.drop_duplicates()

我们的 df 数据帧保持不变,因为这里没有副本。

处理空值

通常,我们的数据中有空值。通常,我们要么去掉那些空值,要么用一些其他有意义的值来代替,例如列的平均值。

  • 检出空值
pd.isnull(df)

我们可以看到 c 列中有两个空值。

  • 水平定位空值
# checking horizontally, from Col A to Dpd.isnull(df).any(axis=0)

  • 垂直定位空值
# checking vertically, from index 1 to 4pd.isnull(df).any(axis=1)

  • 用一些有意义的值填充所有 NaN
df2 = df.copy()df3 = df2**.fillna(0)** # fill with 0df4 = df2.fillna(df**.mean()**) # fill with the mean of the columndf5 = df2.fillna(df**.B.max()**) # fill with the max of colum B

在这种情况下,用自己列的平均值填充 C 列中的 NaN 值似乎是最合理的。

重塑

数据科学家必须处理的另一个常见问题是数据的形状。由于不同的机器学习模型有不同的数据形状要求,所以我们必须根据模型的要求对数据进行整形。例如,我最喜欢的 LSTM 模型接受三维数据,因此我们需要将大多数二维数据集转换为三维数据集。

  • 将所有列合并成一列
# gather all columns, and all observations into one columnpd.melt(df2)

  • 串联—堆叠

这类似于 SQL 语法中的 UNION ALL。它堆叠具有相同列名的值。

# similar to UNION ALL in SQLpd.concat([df,df]) # join vertically

  • 并排拼接
# join horizontallypd.concat([df,df], axis=1)

  • 分组依据

这是一种非常流行的技术,出现在许多计算机语言中。在下面的例子中,我们按照 D 列中的字母对数据进行分组,在 b 列中只显示每个数据的总和值。

# SELECT B, SUM(B) FROM df GROUP BY D ORDER BY Bdf.groupby(“D”)[“B”].sum()

基础数据观察

在所有的数据管理和转换之后,是时候检查我们做了什么。

  • 打印前几行
# the default is 5 if you leave the bracket empty
# we are showing the first 3 rows onlydf.head(3)

  • 打印最后几行
# the default is 5 if you leave the bracket empty
# we are showing the last 2 rows onlydf.tail(2)

  • 随机打印几行
# randomly sampling only 50% of the data setdf.sample(frac=0.5)

  • 打印数据帧的简明摘要。
df.info()

  • 生成描述性统计

这是一个方便而简单的方法,可以直观地定位哪些变量有异常值。

# only describing the numerical columns. Column D is a string column, so nothing is shown.df.describe()

查询/检索数据

在得到我们需要的数据帧的形状/形式后,我们将希望从数据中检索信息。查询功能是 Pandas 中最常用的数据检索功能之一。

  • 排序

熊猫也有一些 SQL 的特征。在排序中,默认值是升序,这类似于 SQL 在中的顺序。

# sort values according to Hong Kong
# default is ascendingdf.sort_values(“香港”, ascending=False)

  • 复位索引

很多时候,在排序之后,我们必须将索引重置为行号。这是它的语法。

df.reset_index()
  • 一个条件
# returns a dataframe with one condition, which is B has to be bigger than or equal 50000df.query(“B >= 50000”)

下面的语法产生相同的结果,只是检索方式不同。

df[df[“B”]>=50000]

下面的代码只检索列 C,而不是打印整个数据帧。

df.C[df[“B”]>=50000]

只打印了 C 列的 2 行。

  • 多个条件—“与”
# returns a dataframe with 2 conditions, which are B has to be bigger than or equal 50000, **and** “香港” has to be smaller than 99000.df[(df[“B”]>=50000) & (df[“香港”] < 99000)] # no and

  • 多个条件—“或”
# returns a dataframe with 2 conditions, which are B has to be bigger than or equal 50000, **or** “香港” has to be smaller than 49000.df[(df["B"]>=50000) | (df["香港"] < 49000)] # no or

  • 串串

要在数据集中查找字符串,我们可以使用“str.find()”或“str.contains()”。“str.find()”方法返回一个整数值。如果子字符串存在于字符串中,则返回子字符串第一个匹配项的索引。如果字符串中不存在 substring,则返回-1。

对于 str.contains,它返回布尔值 True 或 False。

# Within column D, check if "z" exits.print(df[“D”].str.find(“z”))print(df[“D”].str.contains(“z”,case=False))

  • 用 loc 和 iloc 选择数据
# return the entire roll
# with a conditional statement
df.loc[df['D'] == 'z']# return the entire first roll
df.loc[0]# select one specific value row label and column label
df.loc[0, "D"]# select specific value row index and column index
df.iloc[0,3]

  • 用正则表达式查询

熊猫中有很多支持 regex 的原生函数,分别是 count()、replace()、contains()、extract()、findall()、match()、split()和 rsplit()。

# searching for rows with single letter in D column.df[df[‘D’].str.contains(r’[a-z]+’)] # \D

它返回整个数据帧,因为 D 列中的所有变量都是字母。

  • 最大和最小
# Return numbers of rows with the largest and smallestdf.nlargest(2, “B”)

# Return 2 rows with the smallest number in column Bdf.nsmallest(2, “C”)

奖励:处理大数据:

Microsoft Excel 只能很好地处理 1000 行数据而不会滞后。但是,如果数据集超过 10k 行,它将经常冻结。对于 Python 熊猫来说,它处理 100 万行没有任何问题(至少我的经验是这么告诉我的,我的设备只是一台 16GB ram 的旧 Macbook Pro)。大数据呢?数据大小大于 1GB 怎么办?或者数据文件太大,根本无法加载到内存中?当然你可以用 Dask,或者 Vaex,但是这次我们还是用熊猫。

对于 Pandas 中的大数据,我们将使用 chunksize 在任何给定时间只将文件的一部分加载到内存中。

**df = pd.read_csv(’data.csv’, chunksize=10000)**

太好了!现在我们刚刚快速复习了熊猫的基本操作,我希望这个小抄能让你在处理熊猫的数据帧时更有信心。

为了便于修改,我把上面提到的所有内容都放在了一个 Jupyter 笔记本文件中。请放心下载:熊猫数据扯皮小抄 2021 修订文件

你可能也会对这篇文章感兴趣:基础营销分析

非常感谢您阅读我的文章,我一直在为数字营销、数据分析、分析和 Python 写作。请点击下面的链接来看看。

数字营销:https://elartedm.com/marketing-blog/

另一个数字营销和机器学习:【https://positivehk.com/category/�%B...】T2

数据科学:【https://lorenzoyeung-io.medium.com/

熊猫因子分解:从文本到数字的快速通道

原文:https://towardsdatascience.com/pandas-factorize-a-fast-track-from-text-to-numbers-2a343d91b1f9?source=collection_archive---------18-----------------------

学习如何使用。来自熊猫的 factorize()方法。

澳大利亚八月在 Unsplash 拍摄的照片

这篇文章只会占用你一分钟的时间,但我相信它可以节省几分钟的数据转换时间。

因式分解

.factorize()是一个 Pandas 方法,可以帮助你快速地将数据从文本转换成数字。

将对象编码为枚举类型或分类变量。[熊猫文档]

很多时候我们需要将一个给定的变量转换成数字,特别是在呈现给某些只需要数字输入的算法之前。因此,有几种方法可以用熊猫来玩这个把戏,例如像mapreplace

地图示例

import pandas as ps
import seaborn as sns# Load dataset for this example
df = sns.load_dataset('taxis')# slice only some textual columns
df = df[['payment', 'pickup_borough', 'pickup_zone']]# payment unique entries
df.payment.unique()
**[OUT]:** array(['credit card', 'cash', nan], dtype=object)# Using map
df.payment.map({'cash':0, 'credit card':1})

当我们只有两个选项时,上面的代码将很好地工作。现在,对于 pickup_borough 列,我们已经看到 4 个条目,仍然可以很快完成。不过,还是来看看 pickup_zone 一栏。

df.pickup_zone.nunique()[OUT]: 194

哎哟……194 个条目。这将需要一些时间来记录和创建映射字典。即使使用代码来实现这一点也需要时间。

现在让我们在这种情况下使用.factorize()函数。

因子分解示例

请看下面的内容,.factorize将得到一个数组,其中包含每个唯一条目的编号和索引,这样你就知道什么是什么了。因此,0 将是“鲁诺希尔西”,1 是“上西区南”,等等,直到最后一个是“希尔克雷斯特/波莫诺克”。

df.pickup_zone.factorize()[OUT]:
(array([ 0,  1,  2, ..., 61, 75, 64]),  
Index(['Lenox Hill West', 'Upper West Side South', 'Alphabet City',         'Hudson Sq', 'Midtown East', 'Times Sq/Theatre District',         'Battery Park City', 'Murray Hill', 'East Harlem South',         'Lincoln Square East',         ...         'Columbia Street', 'Middle Village', 'Prospect Park', 'Ozone Park',         'Gravesend', 'Glendale', 'Kew Gardens Hills', 'Woodlawn/Wakefield',         'West Farms/Bronx River', 'Hillcrest/Pomonok'],        dtype='object', length=**194**))

要从因式分解方法中访问数组,请使用切片索引[0]。让我们用数字放一个新的栏。

# New factorized column
df['zone_code'] = df.pickup_zone.factorize()[0]

因子分解列。图片由作者提供。

请注意,我们在第 7 行有一个NaN。看看 factorize 是如何处理的。它使用-1。所以,如果需要的话,你可以更容易地摆脱它。

df['pay_cd'] = df.payment.factorize()[0]

NaN = -1。图片由作者提供。

更快的

而且,正如所料,因式分解更快。

两种方法的时间测量。图片由作者提供。

在你走之前

当您需要将包含许多唯一条目的列从文本转换为数字时,factorize方法非常方便。它也比应用映射字典更快。

它和map或者replace做的是一样的工作,但是你不需要写字典。

这是因式分解的文档。

如果这个内容是有帮助的,你想要更多的内容,请关注我。

https://medium.com/gustavorsantos

每个数据科学家都需要知道的熊猫基础知识

原文:https://towardsdatascience.com/pandas-fundamentals-for-beginners-that-will-help-you-code-like-a-pro-2ff5e34fee09?source=collection_archive---------30-----------------------

像专业人士一样提高性能和代码

锡德·巴拉钱德朗在 Unsplash 上拍摄的照片

更喜欢看这个? 在 YouTube 上查看视频版本。

熊猫不是最好的吗?这是一个如此伟大的图书馆,具有如此大的潜力和如此大的灵活性。我记得我刚开始用它的时候。我立刻喜欢上了它。

不要误解我,它确实有一个陡峭的学习曲线。并非所有事情从一开始就显而易见。熊猫有几个棘手的概念。这些事情只需要 20%的努力就能让你达到 80%。

以下是我多年来学到的熊猫的主要工作原理,它们将提高你的编码性能。

数据框架和系列是主要的构件

将数据加载到数据框中。数据框由行和列组成。一行是一个数据点,一列是机器学习方面的一个特征。

但是当您仔细观察时,数据框由多个系列对象组成。series 对象基本上是一个列。当您将多个列(或系列对象)加在一起时,您会得到一个数据框。

正如我在 Pandas 公共函数备忘单中提到的,Pandas 库的大多数函数要么应用于要么返回一个系列对象或一个数据框。

当您意识到这两者之间的区别和关系时,理解数据帧的工作方式就变得容易多了。

该指数具有支持作用

列是熊猫数据框的星星,但是行也可以用于动作。Pandas 有适用于每一行的内置函数,还提供了遍历行的选项。

索引是标识行的方式。在下面的示例数据框架中,索引是最左侧的数字,以粗体显示。也可以有其他类型的索引,比如 string。

图片由我提供。

即使我们与索引没有太多的关系,我们仍然需要知道它们是如何工作的。有时,index 可能被用作 Pandas 函数中的引用,它需要是正确的。举个例子,如果我将上面的数据帧按trip _ distance排序,我会得到这样的结果。您可以看到,索引现在出现了故障。第一个数据点的索引值是 2 而不是 0。

图片由我提供。

这通常不是一个大问题,但是如果您随后想要对以索引为参考的数据框执行操作,您可能会得到意想不到的结果。例如,如果我现在试图绘制 trip_distance 列,我将得到这个奇怪的图形:

图片由我提供。

发生这种情况是因为绘制图的函数将指数作为参考。x 轴是索引,y 轴是 trip_distance 值。于是这个怪异的图形就产生了。

对此有一个非常简洁的解决方案,就是用 reset_index() 重置索引。所以我们得到了这个数据框架:

图片由我提供。

它再次按 trip_distance 排序,但索引是有序的。不要被有一个名为 index 的列所迷惑。只是旧的指标值。如果不需要,您可以轻松删除该列。

现在,如果我绘制这个数据框,我会得到一个合适的图:

图片由我提供。

当您想要更改某些内容时,请考虑数据框的整体

如果你像我一样来自编程背景,你的第一反应会是为你想在数据框中改变的一切写循环(for 或 while)。

例如,如果我想将每个数据点的 passenger_count 增加 1,旧 me 可能会编写一个 For 循环,读取每一行并将乘客计数增加 1。

但是你不必用那种方式对待熊猫。甚至是劝阻。相反,你可以说,嘿,你看到了名为 passenger_count 的列,将所有值加 1。这只用一行代码就可以完成。

这也是因为列本身就是对象。就像在 Python 中把一个整数加 1 一样,你可以把一列中的所有值都加 1。

你当然也可以做更多。在基础数学之上:

  • 您可以组合多个列来创建一个新列,
  • 您可以更改列的格式,
  • 您可以用给定的值来填充缺失的值

还有更多。

主要要点是,当您考虑更改数据框中的内容时,请将整个数据框或至少列视为单独的对象,而不是逐行进行更改。

我在这篇文章的视频版本中有更多这样的例子。

高效的过滤会节省你很多时间

在熊猫数据帧中过滤数据点是经常需要的。您想要过滤掉数据框中的某些值可能有多种原因:

  • 为了只看到数据帧的子集,
  • 要在分析中仅使用具有特定值的数据点,
  • 排除具有特定值组合的数据点等等。

熊猫让过滤变得超级简单。它由两部分组成:数据框外壳和条件。这些不是正式的名字,是我想出来的。

数据框外壳基本上就是数据框的名称和两个括号。在数据框外壳中,您可以写下您希望包含和排除哪些内容的条件。就像:

my_dataframe[ ]

图片由我提供。

这里有一个例子。如果我只想在一个名为的数据帧中查看具有大于 0 的 行程距离 的数据点,我将编写如下过滤行:

内部短语是taxi _ df[' trip _ distance ']>0是我所说的条件。它返回一个 Series 对象,其中每个值要么为真,要么为假。这取决于相应的 trip_distance 是否大于 0。

你可以有任何条件。包括比较字符串、检查值是否在某个列表中等等。您可以通过在条件前放置波浪符号(~)来否定条件。您还可以将多个条件用括号括起来,并用逻辑运算符(如& (and)、| (or)进行合并。当你知道你所需要的是:

  • 数据帧外壳和
  • 为每个数据点/行返回 True 或 False 的条件语句

社区永远在你身边

当然,也许他们不是为你个人而存在,但他们一直在为别人而存在,你可以利用他们积累的知识。有如此多的信息、如此多的问题和如此多的答案,我认为几乎不可能提出一个还没有解决的问题。

这就是为什么当我陷入困境时,当我不知道如何做某件事时,我做的第一件事就是用一种非常简单明了的方式在谷歌上写下我试图做的事情。大多数时候,我第一次尝试就能找到问题的答案。

这些只是我学到的一些简单而有效的关于熊猫的基本知识,一旦我学会了,它们让我的生活变得容易多了。所以我想和你分享。

如果你想更深入地了解熊猫,了解一些最常用的功能是如何工作的,请查看我的熊猫常用功能备忘单。它包括按用途分类的功能定义,一些关于它们工作方式的提示和我给熊猫的一些建议。

祝你的熊猫之旅好运!我希望你和我一样喜欢它!

🐼想了解更多关于熊猫的知识吗? 获取我的免费熊猫小抄。

熊猫因爱而分组

原文:https://towardsdatascience.com/pandas-groupby-love-5b3bce19c35e?source=collection_archive---------22-----------------------

用你的大脑来思考熊猫最强大的统计分析工具之一。

帕斯卡·米勒Unsplash 上的照片

在本教程中,您将学习如何使用 Pandas dataframe .groupby()方法和聚合器方法,如.mean().count(),从大型数据集(超过 1000 万行)中快速提取统计数据。还将向您介绍开放大学学习分析数据集

熊猫

Pandas 是 Python 中最可爱的表格数据管理库。一旦你掌握了它的窍门,它的直观的、面向对象的实现和提高计算效率的巧妙技巧就能实现灵活而强大的数据处理。

Pandas 促进了数据挖掘、数据处理、数据清理、数据可视化,以及对小型到大型数据集的一些基本统计分析。

分组依据

Pandas 最重要的分析工具之一是 Pandas DataFrame 对象的.groupby()方法。当您将分类数据列的名称传递给 dataframe 的.groupby(by='column')时,返回的对象将把分组列中的每个唯一类别作为行的索引,没有分组的其他特征作为列,以及由用于分组的类别组织的样本堆栈的第三维。该方法返回一个新的 groupby 对象,该对象比调用它的对象多一个维度。

作者图片

聚合器

聚合器返回一个矩阵,它的维数比它们聚合的维数少一个,并且充满了被压缩维数的所需统计信息。如果groupby是 groupby 对象,groupby.mean()将返回 groupby 对象分组所依据的每个类别中样本特征的平均值的数据帧。其他聚合器包括:.count().sum().std()

开放大学学习分析数据集

让我们看看这一切的行动。我将使用来自https://analyse.kmi.open.ac.uk/open_dataset的 studentVle.csv 数据。这是一个为期两年的几门课程的匿名在线学习者记录的数据集。我选择的表格记录了学生与虚拟学习环境(VLE)相关的学习活动或资源之间的个人互动。

作为一名数据科学家,我们总是希望明确自己的目标。在这个 groupby 示例中,我想知道每个学生参加了多少活动,以及每个活动的平均点击数。

下面的代码将下载数据集,这个数据集很大,需要一段时间。一旦它下载了数据,它将解压缩文件与学生/VLE 的互动记录。一如既往,我鼓励您将我的示例作为起点,用于您自己的数据。

import pandas as pd
import zipfile
import wgeturl = '[https://analyse.kmi.open.ac.uk/open_dataset/download'](https://analyse.kmi.open.ac.uk/open_dataset/download')
# filename = wget.download(url)
zpf = zipfile.ZipFile(filename)
student_vle = pd.read_csv(zpf.open('studentVle.csv'))
student_vle

如下所示,这段代码的输出告诉我们有超过 1000 万行数据。每行代表一个学生同时参与的一项活动。数据包括模块、模块演示、学生 id、活动 id、日期和学生在活动中的点击次数。请注意,date栏是课程开始日期之后的几天。有关数据的更完整描述,请访问来源。那里的团队很棒,工作非常出色。

作者图片

我们不可能实事求是地浏览每一条记录;我们的大脑会爆炸。用 for 循环遍历 1000 万条记录来收集统计数据的计算代价非常高。幸运的是,制造熊猫的天才们已经想出了一些神奇的数组来以惊人的速度汇总统计数据。

计数聚合器

让我们从计算每个学生参加的活动数量开始。我们将按student_id列分组。如果您和我一样是视觉型的,您可能会想象 groupby 方法将id_student列中具有给定编号的所有行一个接一个地堆叠在一起,以生成 3D 表格。当我们在 groupby 对象上调用一个聚合器方法时,这些堆栈中的每一个都展平成我们想要的任何统计数据。在这种情况下,我们将使用.count()方法。

student_groups = student_vle.groupby('id_student')
activity_counts = student_groups.count()
activity_counts.head()

在下面的输出中,您可以看到id_student已经成为索引,并且每个原始特征都被聚合到每个学生在数据集中出现的活动参与数量的计数中。

作者图片

如果没有丢失的数据,每一行的数字都是相同的。.count()方法返回每个原始列中的计数,但是像.mean()这样的方法将只返回数字列。分类的将从结果数据帧中丢失。

平均聚合器

我们还想知道学生每次活动的平均点击数,所以我们将使用.mean()聚合器方法来收集每个学生的统计数据。它会返回sum_click列的平均值,对应的是每个学生每次活动的平均点击次数,以及一些我们不关心的数字。

average_clicks = student_groups.mean()print('Mean of median clicks per activity is',    
       average_clicks['sum_click'].mean())average_clicks.head()

请注意,这一次我们没有取回模块或表示列,因为它们是绝对的。日期和活动 id 的含义没有意义。

作者图片

如您所见,这些学生每次活动的点击次数的平均值为 3.2,在原始数据集中,我看到了许多 1-click 活动。我猜很多这些活动都是外部资源的链接。

让我们通过一个pd.merge()调用将我们想要的统计数据放在一个表中。

activities_and_clicks = pd.merge(left=activity_counts['id_site'], 
                                 right=average_clicks['sum_click'],
                                 how='inner',
                                 on='id_student')cols = ['Total Activities Engaged', 'Average Clicks per Activity']
activities_and_clicks.columns = colsactivities_and_clicks.head()

我们现在有一个表格,每个学生占一行,一列描述该学生参加了多少活动,另一列描述他们每次活动的平均点击数。

作者图片

这张表给了我们每个学生的具体统计数据。

其他分组:

也许我们需要模块或演示的统计数据。我们可以通过改变我们分组的列来得到它们。例如:

module_group = student_vle.groupby('code_module')
module_averages = module_group.mean()
module_counts = module_group.count()modules = pd.merge(module_counts['id_site'], 
                                module_averages['sum_click'],
                                how='inner',
                                on='code_module')modules.columns = ['Total Activities Engaged','Average Clicks per Activity']modules

这将返回每个模块而不是每个学生的活动计数和点击平均值的表格。

作者图片

有些模块的平均点击率比其他模块高得多。为什么 DDD 模块的每项活动平均需要的点击次数比 FFF 模块少 2 次?嗯…

多重索引

随着我们越来越了解我们的数据,我们意识到我们犯了一个错误。我们想知道每个学生的平均点击数,但是有些学生同时上多门课,或者多次上同一门课。

在我们的利益相关者澄清了上面的原始问题后,我们真正想要的是每个学生参与了多少活动,以及他们在每次课程演示的基础上平均点击了多少次。换句话说,我们需要每个课程注册的统计数据,而不是每个学生。如果同一个学生复读一个模块或参加多个模块,可能会有多个记录。上面,我们找到了每个模块和每个学生的统计数据,但是让我们看看如何得到每个课程、每个演示、每个学生的统计数据。

稍微补充一下,为同一个学生创建多个记录违反了观察是独立的假设。一些种类的分析需要考虑到有效性。

我们需要按照三个不同的列对数据进行分组:code_modulecode_presentationid_student。幸运的是,.groupby()方法允许我们将一列列表传递给by=参数。这将为每个传递的列创建一个具有另一个维度的 groupby 对象。你可以用另一种方式来思考它,结果是数据帧的数据帧乘以你传递的列数。下面的代码将创建一个五维的 groupby 对象,然后返回其余特性的每个唯一模块表示注册的平均值。

cols = ['id_student','code_presentation','code_module']
reg_groups = student_vle.groupby(cols) reg_averages = reg_groups.mean()
reg_averages.head()

dataframe 有三个索引列:id_student、code_presentation 和 code_module。第一个是学生个人,第二个是他们参加课程的学期,第三个是他们参加的课程。

作者图片

你可以看到学生 8462 两次选修了 DDD 模块,一次是在 2013 年 10 月,另一次是在 2014 年 10 月。(字母是月份,所以 J ==第 10 个月。)学生 8462 第一次参加课程时,每项活动的平均点击率为 2.15,第二次为 2.5。他们更努力了吗?参与不同的活动?这是一个更深入分析的机会,但是超出了我们当前任务的范围。让我们把它放在冰箱里待会用。

元组索引

如果我们想要索引这个多索引数据帧来检索特定的数据,我们需要使用一个元组作为行索引器。如果我们想知道学生 8462 在 2013 年 10 月 DDD 模块演示期间的每次活动的平均点击数,我们可以这样索引:

reg_averages.loc[(8462,'2013J','DDD'), 'sum_click']

正如我们所希望的,这将返回 2.15333。

我们还可以颠倒传递给 groupby 方法构造函数的列列表的顺序,以获得不同的数据顺序。让我们翻转'code_module'id_student,看看这会如何改变结果。

cols = ['code_module','code_presentation','id_student']
groupby_module= student_vle.groupby(cols)module_averages = groupby_module.mean()
module_averages.head()

上面的代码首先按照模块,然后按照演示,最后按照学生对统计数据进行分组。我们获得按模块组织的整个班级列表的数据。

作者图片

如果我们想查看模块 BBB 的数据,演示 2014B,我们应该这样索引:

module_averages.loc[('BBB','2014B'), 'sum_click']

这将返回一个 Pandas 系列,其中包含该群组中所有学生每次活动的平均点击数。有将近 1300 名学生,但这是一所在线大学,所以课程是虚拟的,自定进度,并且可以更大。

展平多索引

我希望早点知道的最后一个技巧是如何将多索引表变成单索引表。它实际上非常简单和直观…一旦你已经知道了!

flat_module_averages = module_averages.reset_index()
flat_module_averages.head()

上述代码将行重新堆叠到 2D 表中,排序方式与显示的 groupby 对象相同。groupby 对象索引变成列,并添加一个新索引。

作者图片

请注意,这与我们第一次只按一列分组时的数据帧不同。在我们的第一个 groupby 对象中,每个学生都是一个样本。当我们使用所有三个列进行分组,然后变平时,我们现在有了每个模块、每个注册、每个学生的平均点击统计数据。

摘要

在本教程中,您下载了一个包含 1000 万行学生/虚拟学习环境交互的表格,并使用 Pandas .groupby() dataframe 方法以不同方式对数据进行分组。最后,您使用聚合器方法.count().mean()来提取每个学生在一门课程中参与的活动数量以及每个学生每个活动的平均点击数,并将它们返回到一个整洁的表格中。另外,您还学习了如何将多索引数据帧还原为单索引数据帧。

全部要点

以下要点汇集了您所学的所有技能,并返回一个单一索引表,显示每个模块的每个演示中每个学生的活动数量和每次活动的平均点击数。

作者代码

预期产出:

作者图片

参考资料:

Kuzilek J .、Hlosta M .、Zdrahal Z. 开放大学学习分析数据集 Sci。数据 4:170171 doi:10.1038/sdata . 2017.171(2017)。

熊猫黑客,我希望我有当我开始了

原文:https://towardsdatascience.com/pandas-hacks-that-i-wish-i-had-when-i-started-out-1f942caa9792?source=collection_archive---------6-----------------------

我仍然记得学习熊猫和 Python 时的焦虑;我希望在学习过程中早点掌握这些技巧

介绍

开始接触熊猫和蟒蛇可能是一次令人焦虑的经历。在我的经历中,我已经成长为 Stata 的一名中高级程序员。那是在我向博士委员会提交论文的几个星期后,但在我答辩之前。我有大把的时间。数据分析结束了,写作也完成了。

提交后答辩前的时间我是怎么度过的?对我来说,这是大约六周的时间。我开始学习 Python。

几年后,我发现自己在为我曾经认为是问题的事情寻找解决方案。现在,我几乎不费吹灰之力就找到了解决办法。出于有一两个空闲时间来分享这些,加上一个真诚的想法,也许(也许)这些黑客可能对其他人有用…给你。

准备好了吗?

检查狭长数据帧

您多久检查一次长(许多观察值)但窄(几列)数据框中的数据?在 Jupyter 笔记本环境中,或者在命令提示符下,检查这些“高”数据框会占用垂直空间,同时“浪费”水平空间。这是我的看法(以及我的感受):

作者插图。

如果我们能把输出并排放在一起会怎么样?我们可以。首先定义这个函数:

def lrpd(df, n=5, sep='< head | tail >', sepcol=' '):
   return(
     pd.concat([df.head(n),
                pd.DataFrame([sep] * n,
                columns=[sepcol]),
                df.tail(n).reset_index().drop('index',
                                              axis=1)], axis=1))

然后在一行代码中,类似于:

lrpd(df, n=8)

会给你:

作者插图。

测试项目“A”是否也在列表“L”中

你可能会因此而对我们动心。但是为什么不也写一个函数呢?至少这是我曾经的初学者的想法。除了这个模仿 Stata 的inlist()选项,您还应该看到下面的pd.isin()方法。

如前所述,这个 Stata 的inlist()功能就是灵感。首先定义以下内容:

def inlist(list_to_test, item=''):
   isinlist = False
   for i in list_to_test:
      if i == item:
         isinlist = True
   return(isinlist)

并实施:

inlist(df['country'], 'Angola')

或者,用漫画小说的风格。数据中有安哥拉吗?

作者插图。

代替一个新的函数,一些聪明的方法链有时可以完成类似的结果。例如,如果测试字符串出现在序列中,链接到isin().max()方法将返回True:

# Returns True
df['country'].isin(['Angola']).max()

同样,如果你更喜欢 0 或 1 链,那么.sum()方法:

# Returns 1
df['country'].isin(['Angola']).max().sum()

长期保存数据

这第三次攻击更多的是推荐,而不是攻击。建议是,以多种格式保存数据文件。当归档项目文件以备将来某个未知时刻参考时,这种多格式建议尤其重要。

在我职业生涯的早期(这么早),我记得我认为数据就是数据,对吗?所以,我通常把我的数据保存在 CSV 中。也许很大一部分人默认选择 CSV。然而,如果你是熊猫的新手,你知道除了 CSV 还有 21 种格式可以选择吗?这些是熊猫支持的现成格式。结合其他软件包,你会有更多的选择。

以下是熊猫将支持的一些格式,以及一些关于它们的用例的片段。

pandas.DataFrame.to_html('file_name.html')
pandas.DataFrame.to_xml('file_name.xml')

当你使用一个不总是擅长读取.csv文件的平台向任何人发送数据时,使用这些格式。我不止一次将一个csv 数据文件发送给某人,他会将该文件导入到一个解析csv数据时出错的工具中。有些事情不太对劲。谁知道呢?有些工具在这方面比其他工具更好。

在无孔不入的情况下,并且默认为许多csv失败了,还有pandas.DataFrame.to_html()pandas.DataFrame.to_xml()来救场。

我也很喜欢这些非文本格式。

pandas.DataFrame.to_stata('file_name.dat')
pandas.DataFrame.to_pickle('file_name.pkl')
pandas.DataFrame.to_parquet('file_name.parquet')

通过以更复杂的方式保存数据,这些数据格式可以更好地保留数据表示和数据类型。

一般来说,我倾向于以至少两种格式保存数据。这种做法有助于未来证明我的项目。也许在 5 年、10 年或者更久以后,我可能会重新考虑一个项目。或者其他人可能会重访某个项目。如果数据仅以一种不再广泛使用的格式存储,这可能会产生问题。以多种格式保存可以防止在数据标准、工具和其他环境因素尚不可知的未来系统中读取数据时可能出现的问题。

我赞成以多种格式保存的另一个原因是,有时由于古怪的数据类型,项目中可能会出现错误。每种格式都有自己的数据类型方案。熊猫也有自己的计划。当数据类型没有很好地映射时,将数据从一种格式交换到另一种格式有时会产生意想不到的结果。拥有数据的冗余副本有助于解决这些与数据类型相关的问题。

https://adamrossnelson.medium.com/membership

结论

这些是我希望在我的数据科学职业生涯中早点知道的一些技巧。我希望这些技巧对你有用。如果你有想法或主意,请发表评论。让它成为可乐吧。

我也希望你喜欢原来的插图。

编辑:感谢媒体、电子邮件和其他平台上的有益评论——我对这篇文章做了一些编辑。我非常感谢那些做出贡献的人。

另一个我开始时想变得更简单的任务是:在 Pandas >中移动列:|

感谢阅读

感谢阅读。把你的想法和主意发给我。你可以写信只是为了说声嗨。我期待着尽快聊天。推特:@ adamrossnelsonLinkedIn:亚当·罗斯·尼尔森在推特和脸书:亚当·罗斯·尼尔森在脸书

数据科学熊猫:初学者指南,第一部分

原文:https://towardsdatascience.com/pandas-i-read-csv-head-tail-info-and-describe-43b9b2736490?source=collection_archive---------19-----------------------

开始学习基本的 Pandas 方法,开始用 Python、head()、info()、sum()和 describe()创建数据科学项目。

图片由 995645 来自 Pixabay

一、关于 Python 中数据科学的熊猫

Pandas 是一个构建在 Python 之上的数据分析库。这个灵活的库对于处理和分析各种结构的数据非常有用,但是它对于表格数据尤其有用,比如 SQL 表和 Excel 电子表格。在本教程中,我将重点介绍用 Python 处理 Pandas 中带标签的表格数据的最基本的函数。

二。获取一些数据

  1. 跟随这个链接到 Kaggle 并下载金属乐队的国家数据集到你的项目目录中。

2.打开您的终端,导航到您的项目目录,并使用以下命令打开 Jupyter 笔记本:

$ jupyter notebook

在您的浏览器中,将打开一个包含项目目录的新选项卡。在右上方,你会看到一个下拉菜单,上面写着“新建”。从下拉列表中,选择虚拟环境的名称。这将创建一个新的 Jupyter 笔记本,它使用您已经安装到该虚拟环境中的包。

如果您遇到问题,您可能想参考本教程,以确保您的虚拟环境和 Jupyter 笔记本设置正确。

三。探索熊猫

3.检查以确保您已经安装了 Pandas、Matplotlib 和 Seaborn。如果你不确定如何安装它们,看看这个教程

4.有了熊猫后,回到 Jupyter 笔记本,在第一个单元格中输入:

import pandas

这个命令导入熊猫图书馆,用于你的 Jupyter 笔记本。

对于像 Pandas 这样的库,通常使用别名或简称,这样我们可以在代码中更容易地使用这个库。要使用别名,请删除第一个单元格中的信息,输入以下内容,并键入 Shift + Enter 来执行该单元格。

import pandas as pd

现在,当您使用熊猫函数时,您可以使用别名。

5.在下一个单元格中,我们将读入之前下载的电子表格。为此,请输入以下内容:

df = pd.read_csv(“metal_bands_2017.csv”)
  • df 是我们用来存储电子表格的变量的名字,它现在变成了一个熊猫数据框
  • = 用于将数据赋给变量
  • pd 是 Pandas 的别名——我们用来读取文件的库
  • read_csv() 是 Pandas 库中执行此功能的方法
  • "metal_bands_2017.csv" ,(括号内)是我们希望处理的文件的名称

6.现在,我们可以开始检查数据框,方法是在笔记本的新单元格中输入以下内容:

 df.head()

此方法是查看数据框前五行的一种方式。将一个整数放在括号内可以让您看到按升序排列的许多行。或者, df.tail() 将允许您查看最后五行。这样做可以让我们快速评估数据的格式和质量。

7.要查看所有列的名称,可以使用:

df.columns

这将返回一个列列表。

8.接下来,我们想知道我们正在处理什么样的数据。为了找到答案,我们可以使用:

df.info()

这将显示一个小报告,其中包含所有列名、它们的数据类型以及空值的数量。

到目前为止,您的笔记本应该是这样的:

9.如果您只想查看空值,请输入:

 df.isna().sum()

10.最后,如果你想找出一些描述性的统计数据,你可以使用:

df.describe()

它应该是这样的:

11.如果您正在跟踪一天系列中的数据,请保存此笔记本以备下次使用,并将其命名为“MyProject.ipynb”。

四。我们做了什么?

  1. 学会了如何从命令行启动 Jupyter,打开一个新的笔记本,导入一个包(熊猫)。
  2. 探索熊猫,学习一些数据分析的基本方法。

继续阅读基本熊猫 II 继续用 Python 和 Pandas 检查和转换金属乐队的国家数据集。在那篇教程中,我解释了如何使用像 drop()和 isna()这样的方法来处理缺失值。

数据科学熊猫:缺失值初学者指南,第二部分

原文:https://towardsdatascience.com/pandas-ii-drop-isna-cbbe16a15e70?source=collection_archive---------26-----------------------

了解如何使用 drop()、drop_duplicates()和 isna()处理 Pandas 的 Python 数据科学项目中的缺失值。

图片来自 Pixabay莎朗·昂

Pandas Essentials I 中,我描述了如何开始用 Python 分析和操作 Pandas 中的数据。在本教程中,我将解释如何通过处理缺失值来继续使用国家的金属乐队数据集。

在第一节处理缺失值中,我提供了一些关于处理缺失值的基本信息。如果你只是为了代码片段而来,这些信息会在 Jupyter 笔记本的第二部分数据分析:缺失值中。

一.处理缺失的价值观

数据往往是不完美的。最明显的缺陷之一是缺少值,这可能会对您的项目造成严重破坏。

A.什么是缺失值?

在表格数据(或以行和列的模式排列的数据)中,当有一列包含空白行时,这些空白单元格中的值被视为缺失。

虽然有一些处理缺失值的通用过程,但是每个数据集都是唯一的,在确定如何处理它们之前评估数据是很重要的。在本教程中,我将探索一些最基本的方法来纠正 Python 中的缺失值。

B.什么是南

当数据通过 Pandas 导入 Python 时,将出现在该单元格位置的占位符值通常是 NaN(非数字)。对于日期时间数据类型,会调用 NaT(非时间)。

C .为什么数据缺失?

数据丢失可能有多种原因。其中包括:

  1. 人/机错误 —有人在数据输入阶段犯了一个错误。(例如,由于传感器的问题,没有记录三天的温度。)
  2. 无响应 —可能没有提供响应。(例如选择不披露收入的调查对象。)
  3. 损耗 —一些观察数据不可用,因为它们不再可用于研究。(例如,退出纵向研究的参与者会阻止在研究的后期记录某些指标。)
  4. 修订 —只有拥有特定权限的用户才能访问数据。(例如,诊断仅包括已签署 HIPPA 表格的患者)

在本教程中,我们将重点介绍清除缺失值以提高数据完整性的基本方法。但是,在项目的后期阶段,在调查领域的上下文中考虑缺失值的深层本质是很重要的。

D.数据是怎么丢失的?

缺失数据分为三种主要类型:

  1. 完全随机失踪(MCAR)
  2. 随机失踪(三月)
  3. 非随机缺失(MNAR)

看看这个资源,了解更多关于不同类型的缺失值。

E.为什么缺失值是一个问题?

请继续阅读下一节,查看不同类型的缺失值的一些示例、与它们相关的问题以及如何处理它们。

二。识别缺失值

在本教程中,我讨论了如何。info()可用于获取数据的快速摘要。

df.info()

没有多少值是明确丢失的

二。使用 Jupyter 笔记本进行数据分析

1.返回到终端中的项目文件夹。输入以下内容:

$ jupyter notebook

当 Jupyter 启动时,选择您的项目笔记本。在上一个教程中,我们使用 Pandas 方法做了一些初步的分析。要重新执行代码并从我们离开的地方开始,从页面顶部选择内核>重启并运行所有

答:放下一个有熊猫的专栏

因为某些值丢失而删除整个列是删除丢失值的一种笨拙的方法。

2.在上面笔记本的第三个单元格中,我们查看了最上面的五行。我们可以做的一件事是清理和改进数据帧,去掉“未命名:0”列。它似乎是索引的副本。

第一个是按国家排列的金属乐队数据集

3.要去掉那一行,我们可以用 drop() 。该方法将允许我们在数据框中删除一行或一列。输入:

df = df.drop(“Unnamed: 0”, axis=1) 

如何分解是我们使用 = 来重新分配我们的 df 变量给它自己的一个修改版本。在赋值的右侧,drop() 被应用于数据帧。

要做到这一点,请记住以下几点:

  • 我们需要为 drop()提供必要的参数,在本例中是列的名称(未命名:0)和轴
  • 坐标轴的默认值为 0,表示行数。如果您没有指定一个轴,Pandas 会认为您引用的是一个行位置,并将抛出一个错误。
  • 要表示“未命名:0”将从列中删除,请输入 axis=1 作为参数。

未命名的数据帧:0 已移除

请记住,如果您想一次删除多列,请将这些列放在方括号内以表示多列,如下所示:

df = df.drop([“Unnamed: 0”, "split", "another_column"], axis=1)

三。丢下熊猫的复制品

4.由于这是一个按国家划分的波段数据集,我们可以使用波段名作为主键,或者作为数据中每个观测值(或行)的唯一标识值。因此,band_name 列中不应有重复值。

df[df['band_name'].duplicated()]

6.对于此示例,这些重复的波段名称很可能是真正的重复。然而,验证我们的假设,即每个观测的波段名确实是唯一的,不会有什么坏处。此外,在其他数据集中,标识列可能不那么明显,所以最好仔细查看重复项。在您的笔记本中尝试这行代码,以便更仔细地查看重复的内容:

df[df['band_name'].duplicated()]

四。用熊猫填充缺失值

4.既然我们已经做出了改进,我们可以更仔细地查看其余的数据。我们可以通过链接方法 isna()sum() 来检查每一列中有多少个空值:

df.isna().sum()

5.“原点”好像少了 8 行。让我们通过输入以下命令来检查缺少数据的行:

df[df[‘origin’].isna()]

现在,您的笔记本应该看起来像这样:

当我们进入这一行时,我们要做的是让 Pandas 显示 df 的各个部分,这样列“origin”就有一个空值。使用 df[df[column]] 语法允许我们 切片 查看满足特定标准的数据帧部分。

在处理缺失值时,谨慎是关键。我们有多种方法来处理缺失的价值,任何方法都有其利弊。因为我们试图确定什么因素会影响一个金属乐队的粉丝数量,所以我们在做决定时会记住这一点。

处理这种情况的两种方法是消去法或代换法。我们可以通过删除这些行来消除丢失的值。由于我们有 5000 行数据,我们的分析不会因为丢失 8 行数据而受到根本影响。然而,我们也可以通过替换“丢失”来最小化丢失的数据量。这样,我们仍然可以在分析中使用这些波段的其他数据。

由于这是小规模的,这个选择是相当琐碎的。然而,当数据集越来越大,丢失的数据量也越来越大时,您应该尽可能避免丢弃太多的数据。

6.我将使用第二个选项,用“Missing”替换这些值。我们所需要做的就是:

df = df.fillna(“Missing”)

很好,现在我们去掉了多余的列并修复了空值,我们可以开始检查其他列的数据类型了。

7.如果您正在跟踪一天系列中的数据,请将您的笔记本保存为 MyProject.ipynb,以便我们可以从上次停止的地方继续。继续阅读熊猫三继续。

三世。我们做了什么?
1。在 Jupyter 笔记本中重新打开了 a 项目。
2。使用 drop()消除熊猫数据框中的列。
3。链接 isna()和 sum()以返回所有列 4 的缺失值的数量。
4。使用 fillna()填充缺少的值

四。下一步是什么?
Pandas III 中,我们将按国家数据集分析和转换金属乐队中的“拆分”和“成型”列。

熊猫三:数值计数(),重复(),最小值(),最大值()

原文:https://towardsdatascience.com/pandas-iii-value-counts-duplicated-min-max-d705cae54862?source=collection_archive---------23-----------------------

熊猫 II 中,我们开始按国家清理金属乐队的数据集。我们删除了一个不需要的列,并填充了一些缺失的值。现在,我们将检查其他列,评估它们的数据类型和值,并根据需要采取措施。

图片由 Nick115 来自 Pixabay

I .检查数据类型

  1. 打开你的项目笔记本,然后点击内核>重启并运行所有重新执行我们之前的工作。

2.这将是很好的,看看我们正在处理的其他类型的价值观。根据我们从输入信息中学到的,我们有五个对象(非数字)列和一个数字列。数字列是我们的目标变量——粉丝数量(稍后会详细介绍)。其余的数据是分类数据,告诉我们不同波段的质量。

二。Python 中熊猫的价值计算

4.我们要看的下一栏是“起源”。首先,我们将使用 value_counts()检查唯一值,如下所示:

df[“origin”].value_counts()

有许多值,Pandas 只显示结果的头部和尾部。我们可以将上面的代码行包装在 len 中,以准确找出我们有多少个独特的原产国。

len(df[“origin”].value_counts())

三。熊猫蟒蛇皮复制品

3.5000 个金属带看起来很多,所以也许我们可以检查重复的,以确保所有的行都是唯一的带。我们可以这样检查:

len(df[df[“band_name”].duplicated()])

这将返回“band_name”值重复的行数。我们可以使用 duplicated() 删除它们:

df = df.drop(df[df[“band_name”].duplicated()].index)

您的笔记本应该是这样的:

四。对 Python 和 Pandas 使用 min()和 max()

5.接下来,我们有“形成”列。调用value _ counts()将返回所有唯一的年份及其出现的频率。然而,找出最早和最晚的年份可能更有帮助,这样我们可以得到一个范围。将此输入下一个单元格:

df[“formed”].min() 
df[“formed”].max()

看着【min()【max()揭示了另一个问题。一些行的值为-。现在,我们需要决定是删除那些行,还是替换那些值。****

尽管 info()表明“formed”是一个对象列,但年份数据实际上是数字。因此,如果我们决定替换 "-" ,使用“Missing”这样的替代词将会导致以后的问题。我们最好使用一个在数据中没有出现过的年份,比如“1900”。

动词 (verb 的缩写)使用 replace()和 astype()在 Python 和 Pandas 中转换数据

7.您可以通过使用 replace() 来进行替换。要将 replace()应用于 Pandas 数据框中的列,可以使用以下方法:

**df[“formed”] = df[“formed”].replace(“-”, “1900”)**

现在,我们的最小值和最大值应该是 1900–2016。如果您需要查看实际的最小值,只需输入以下内容:

**df[df[“formed”] != “1900”][‘formed’].min()**

这将显示 df 部分中“已形成”列的最小值,因此“已形成”列不会(!= )的值为 1900。

8.既然我们已经从“formed”列中消除了非数字字符,我们可以用 astype() 将整个列转换成数字列:

**df[“formed”] = df[“formed”].astype(int)**

9.现在,让我们对“split”列做同样的操作,因为它也是一年,是数字数据。也就是用 value_counts()检查值,用 replace()替换“-”,用 astype()更改数据类型。我们还将检查 min()和 max()。

六。我们做了什么?

  1. 使用 info() 检查了列的数据类型。
  2. duplicated() 解决了重复问题。
  3. 使用 isna()fillna() 处理空值。
  4. 使用最小()最大()检查范围。
  5. 替换()清除“已形成”和“已拆分”中的年份数据。
  6. 使用更改了列的数据类型。astype()

七。下一步是什么?

在 Pandas IV 中,我们通过分析和转换“风格”列来继续分析国家数据集中的金属乐队。

熊猫可能终究不是丛林之王

原文:https://towardsdatascience.com/pandas-may-not-be-the-king-of-the-jungle-after-all-f09d061cf121?source=collection_archive---------1-----------------------

有点偏颇的比较

弗朗西斯科·德·托马索在 Unsplash 上拍摄的照片

Pandas 主要处理表格形式的中小型数据的数据分析和操作任务。它可以说是数据科学生态系统中最受欢迎的库。

我是熊猫的忠实粉丝,自从开始我的数据科学之旅以来,我一直在使用它。到目前为止我很喜欢它,但是我对熊猫的热情不应该也不会阻止我尝试不同的工具。

我喜欢尝试比较不同的工具和库。我的比较方式是用两者做同样的任务。我通常把我已经知道的东西和我想学的新东西进行比较。它不仅让我学习了一种新工具,还帮助我实践了我已经知道的东西。

我的一个同事告诉我为 r 尝试“data.table”包。他认为对于数据分析和操作任务,它比 Pandas 更有效。所以我试了一下。用“data.table”完成某些任务是如此简单,这给我留下了深刻的印象。

在本文中,我将通过几个例子来比较 Pandas 和 data.table。我仍然在争论是否应该将我默认选择的数据分析库从 Pandas 更改为 data.table。但是,我可以说 data.table 是取代 Pandas 的第一候选库。

事不宜迟,让我们从例子开始。我们将使用 Kaggle 上的墨尔本房屋数据集中的一个小样本作为例子。

第一步是读取数据集,分别由 Pandas 和 data.table 的 read_csv 和 fread 函数完成。语法几乎是一样的。

#Pandas
import numpy as np
import pandas as pdmelb = pd.read_csv("/content/melb_data.csv", 
usecols = ['Price','Landsize','Distance','Type', 'Regionname'])#data.table
library(data.table)melb <- fread("~/Downloads/melb_data.csv", select=c('Price','Landsize','Distance','Type', 'Regionname'))

前 5 行(作者图片)

这两个库都提供了基于列值过滤行的简单方法。我们希望过滤类型为“h”且距离大于 4 的行。

#Pandasmelb[(melb.Type == 'h') & (melb.Distance > 4)]#data.tablemelb[Type == 'h' & Distance > 4]

我们只在 data.table 中写入列名,而 Pandas 还需要 dataframe 的名称。

下一个任务是对数据点(即行)进行排序。假设我们需要按地区名称升序排序,然后按价格降序排序。

下面是我们如何使用这两个库来完成这项任务。

#Pandasmelb.sort_values(by=['Regionname','Price'], ascending=[True, False])#data.tablemelb[order(Regionname, -Price)]

逻辑是一样的。指定列和顺序(升序或降序)。但是,data.table 的语法非常简单

data.table 的另一个优点是,索引在排序后被重置,这与 Pandas 的情况不同。我们需要使用一个额外的参数(ignore_index)来重置索引。

熊猫(作者图片)

data.table(图片作者提供)

数据分析中的另一个常见任务是根据列中的类别对观察值(即行)进行分组。然后,我们计算每个组的数字列的统计数据。

我们来计算一下类型一栏中每一类的房屋均价和土地面积。我们还想看看每个类别中的房屋数量。

#Pandasmelb[['Type','Distance','Landsize']]\
.groupby('Type').agg(['mean','count'])

(图片由作者提供)

对于 Pandas,我们选择感兴趣的列并使用 groupby 函数。然后指定聚合函数。

编辑:感谢 Henrik Bo Larsen 的提醒。我忽略了 agg 函数的灵活性。我们可以在不选择列的情况下进行同样的操作:

#Pandasmelb.groupby('Type').agg(
   avg_distance = ('Distance', 'mean'),
   avg_landsize = ('Landsize', 'mean'),
   N = ('Distance', 'count')
)

(图片由作者提供)

下面是我们如何使用数据完成同样的任务。表:

#data.tablemelb[, .(mean(Distance), mean(Landsize), .N), by='Type']

(图片由作者提供)

我们使用“by”参数来选择要在分组中使用的列。聚合函数是在选择列时指定的。它比熊猫简单。

让我们也添加一个过滤组件,并对成本低于 100 万的房子进行相同的统计。

#Pandasmelb[melb.Price < 1000000][['Type','Distance','Landsize']]\
.groupby('Type').agg(['mean','count'])#data.tablemelb[Price < 1000000, .(mean(Distance), mean(Landsize), .N), by='Type']

过滤组件与 data.table 在相同的方括号中指定。另一方面,我们需要在 Pandas 中的所有其他操作之前进行过滤。

结论

我们在本文中讨论的是在典型的数据分析过程中完成的常见任务。当然,这两个库提供了更多的功能。因此,本文不是一个全面的比较。然而,它揭示了在两者中如何处理任务。

我只关注完成某些操作的语法和方法。与性能相关的问题,如内存和速度尚未发现。

综上,我感觉 data.table 对我来说是替代熊猫的有力人选。它还取决于您经常使用的其他库。如果你大量使用 Python 库,你可能想坚持使用熊猫。不过 data.table 绝对值得一试。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫:数据科学中最常用的函数

原文:https://towardsdatascience.com/pandas-most-used-functions-in-data-science-51b7c2b9c38a?source=collection_archive---------14-----------------------

对数据预处理最有用的函数

锡德·巴拉钱德朗

当你开始学习机器学习时,第一步是学习 Python,而学习 Python 的基本步骤是学习熊猫库。我们可以通过 pip 安装熊猫来安装熊猫库。安装后,我们必须在每次运行会话时导入熊猫。所使用的数据例如来自 UCI 储存库“https://archive . ics . UCI . edu/ml/datasets/Heart+failure+clinical+records”。

  1. 读取数据

我们可以将 pandas 数据帧中的数据读取为 read_csv()。两种最常用的数据读取格式是 csv 和 excel。如果我们正在读取 excel 格式的数据,我们也可以给出如下的工作表名称。还有其他较少使用的其他文件类型的选项。

作者图片

2。头尾

要查看数据帧,我们可以使用 df.head()。Head 返回前几行,如果没有输入,它将总是显示在 5 行以上。与下面的行相反,我们可以使用 df.tail()。

作者图片

3。形状、尺寸和信息

读取数据后最基本的两个功能是知道行数和列数,以及知道变量的数据类型。我们可以使用 df.shape,它先给出总行数,然后给出列数。df.size()返回数据框中的行数乘以列数。我们还可以使用 df.info(),从中我们可以获得不同的信息,比如 RangeIndex 中的行、数据列以及每列的数据类型。它还包括非空计数的信息。

4。isna

但是,如果需要获得数据中空值的总数,我们可以使用 df.isna(),如下所示。Sum 将给出总的空值。如果我们只想要一个空值的变量,我们也可以通过如下给出变量名来得到它。

作者图片

5。描述

然后为了理解变量的基本统计,我们可以使用 df.describe()。它会给你计数,平均,标准偏差,也有 5 个数字摘要。

作者图片

6。努尼克

要获得变量的总唯一值,我们可以使用 df.nunique()。它将给出一个变量包含的所有唯一值。

作者图片

7。数值计数

同样,为了获得单个变量的唯一值,我们可以使用 df .贫血. value_counts()。为了演示,下面只给出了具有布尔值的变量。count_values()返回唯一值的计数。结果对象将按降序排列。默认情况下,此函数不包括 NA 值。

作者图片

如果我们对数据进行任何更改,并希望将其写入逗号分隔值(csv)文件,我们可以使用 to_csv()。在此 for 索引中,默认值为 true。

作者图片

8。列

要知道数据框中所有变量的名称,我们可以使用 df.columns。

作者图片

结论

这些函数在初始步骤中对数据进行预处理是非常常见的。甚至记住这些功能也是一个好主意。还有许多其他有用的功能,可以根据条件和要求使用。可在熊猫文档中探究:“https://pandas . pydata . org/pandas-docs/stable/reference/frame . html”。

感谢阅读!

Pandas 多重索引和处理时间序列数据

原文:https://towardsdatascience.com/pandas-multiindexing-and-working-with-time-series-data-8e6229f11998?source=collection_archive---------17-----------------------

埃斯凯·林Unsplash 上的照片

帮助清理时间序列数据的分步示例

在我们进行任何预测建模或分析之前,我们首先需要清理和格式化我们的数据。熊猫图书馆有很多很棒的工具来帮助加速这个过程——我们清理得越快,我们可以花更多的时间来分析和建模。

以下是四只股票几周的股价数据(眼尖的,是的,我故意给微软留了个日期):

ticker       date    close
0    AAPL 2021-03-18   120.53
1    AAPL 2021-03-19   119.99
2    AAPL 2021-03-22   123.39
3    AAPL 2021-03-23   122.54
4    AAPL 2021-03-24   120.09
5    AAPL 2021-03-25   120.59
6    AAPL 2021-03-26   121.21
7    AMZN 2021-03-18  3027.99
8    AMZN 2021-03-19  3074.96
9    AMZN 2021-03-22  3110.87
10   AMZN 2021-03-23  3137.50
11   AMZN 2021-03-24  3087.07
12   AMZN 2021-03-25  3046.26
13   AMZN 2021-03-26  3052.03
14  GOOGL 2021-03-18  2021.34
15  GOOGL 2021-03-19  2026.96
16  GOOGL 2021-03-22  2030.69
17  GOOGL 2021-03-23  2041.33
18  GOOGL 2021-03-24  2032.53
19  GOOGL 2021-03-25  2032.46
20  GOOGL 2021-03-26  2024.73
21   MSFT 2021-03-18   230.72
22   MSFT 2021-03-19   230.35
23   MSFT 2021-03-22   235.99
24   MSFT 2021-03-23   237.58
25   MSFT 2021-03-24   235.46
26   MSFT 2021-03-25   232.34

假设我们想计算每只股票在一周内的累积回报,并通过相关矩阵比较它们的共同运动。

目前,数据是堆叠格式的,一只股票在另一只的上面。以表格形式分析时间序列数据(如股票价格)要容易得多,表格中每行是一个日期,每列是一只股票。

获取表格

让我们考虑一下如何快速将数据转换成表格格式。我们应该:

  1. 按股票对数据进行分类。
  2. 并将它们水平堆叠。

一个简单的方法是通过熊猫的多重索引功能。如果您对上面的数据(存储在名为data的数据帧中)运行下面的代码行,它会为data创建一个多索引。

data = data.set_index(['ticker','date'])

我们选择了按股票代码和日期进行索引,因此采用了多重索引,因为我们要按多个列进行索引。一旦我们打印出生成的数据帧,多重索引如何让我们的生活变得更加轻松就变得显而易见了:

print(data)**Output:**
                     close
ticker date               
AAPL   2021-03-18   120.53
       2021-03-19   119.99
       2021-03-22   123.39
       2021-03-23   122.54
       2021-03-24   120.09
       2021-03-25   120.59
       2021-03-26   121.21
AMZN   2021-03-18  3027.99
       2021-03-19  3074.96
       2021-03-22  3110.87
       2021-03-23  3137.50
       2021-03-24  3087.07
       2021-03-25  3046.26
       2021-03-26  3052.03
GOOGL  2021-03-18  2021.34
       2021-03-19  2026.96
       2021-03-22  2030.69
       2021-03-23  2041.33
       2021-03-24  2032.53
       2021-03-25  2032.46
       2021-03-26  2024.73
MSFT   2021-03-18   230.72
       2021-03-19   230.35
       2021-03-22   235.99
       2021-03-23   237.58
       2021-03-24   235.46
       2021-03-25   232.34

看看现在数据帧组织得多好。是按股票分出来的。例如,我们可以很容易地获得苹果的回报:

data.loc['AAPL']**Output:**
             close
date              
2021-03-18  120.53
2021-03-19  119.99
2021-03-22  123.39
2021-03-23  122.54
2021-03-24  120.09
2021-03-25  120.59
2021-03-26  121.21

或者苹果和谷歌的单个日期( IndexSlice 简化了多索引切片的语法):

idx = pd.IndexSlice
print(data.loc[idx[['AAPL','GOOGL'],'2021-03-18'],])**Output:**
                     close
ticker date               
AAPL   2021-03-18   120.53
GOOGL  2021-03-18  2021.34

按库存水平堆叠

在我们的例子中,我们希望获得每只股票的回报,并将它们水平叠加,同时确保价格正确排列(时间序列分析中可能发生的最糟糕的事情是构建了一个令人敬畏的模型,却发现您的数据没有对齐)。我们可以通过一个简单的 for 循环来实现这一点:

# Get tickers where the tickers are the set of index level 0 values
# get_level_values returns all values for the given index level
# In our case, level 0 is stock ticker and level 1 is date
# Since we want, a list of tickers we can take the set of the index level 0 values
tickers = list(set(data.index.get_level_values(0)))# Initialize dataframe to store tabular stock price data
clean_table = data.loc['AAPL'][['close']]
clean_table.rename({'close': 'AAPL'}, axis=1, inplace=True)# Loop through all tickers besides Apple and "h-stack" prices
for ticker in tickers:
    if ticker != 'AAPL':
        clean_table[ticker] = data.loc[ticker][['close']]

print(clean_table)**Output:**
              AAPL     AMZN    MSFT    GOOGL
date                                        
2021-03-18  120.53  3027.99  230.72  2021.34
2021-03-19  119.99  3074.96  230.35  2026.96
2021-03-22  123.39  3110.87  235.99  2030.69
2021-03-23  122.54  3137.50  237.58  2041.33
2021-03-24  120.09  3087.07  235.46  2032.53
2021-03-25  120.59  3046.26  232.34  2032.46
2021-03-26  121.21  3052.03     NaN  2024.73

看看向我们数据帧添加新数据是多么容易(只需要前面代码块中的最后一行代码:clean_table[i] = data.loc[i][['close']])。它只需要一行代码。因为clean_tabledata.loc[ticker[[['close']]都是按日期索引的,所以当我们向clean_table添加一个新列时,Pandas 会确保日期正确对齐。换句话说,当添加另一个数据帧或序列到一个现有的数据帧时,Pandas 只会在索引(在这种情况下是日期)匹配时添加非空值(这不适用于没有索引的列表)。

这里有一个例子,让我们试着给clean_table添加一些日期不匹配的数据:

# some stale data with dates that don't matchdate
2016-01-04    26.337
2016-01-05    25.677
2016-01-06    25.175
2016-01-07    24.113
2016-01-08    24.240
2016-01-11    24.633
2016-01-12    24.990

我们将这个数据称为wrong_dates。现在让我们看看当我们尝试添加它时会发生什么:

clean_table['wrong_dates'] = wrong_dates
print(clean_table)**Output:** AAPL     AMZN    MSFT    GOOGL  wrong_dates
date                                                     
2021-03-18  120.53  3027.99  230.72  2021.34          NaN
2021-03-19  119.99  3074.96  230.35  2026.96          NaN
2021-03-22  123.39  3110.87  235.99  2030.69          NaN
2021-03-23  122.54  3137.50  237.58  2041.33          NaN
2021-03-24  120.09  3087.07  235.46  2032.53          NaN
2021-03-25  120.59  3046.26  232.34  2032.46          NaN
2021-03-26  121.21  3052.03     NaN  2024.73          NaN

因此,即使我们试图添加的数据长度是正确的(长度为 7),Pandas 也正确地认识到日期严重不匹配(我们的数据来自 2021 年,而wrong_dates数据来自 2016 年)。因此,我们得到的不是数值,而是空值(如果想将wrong_dates加到clean_table,可以使用外部合并:clean_table.merge(wrong_dates, how='outer’, left_index=True, right_index=True))。

还要注意,MSFT 缺少一个值,因为它比其他股票少了一个价格观察值。与wrong_dates类似,熊猫对此处理正确。既然我们已经了解了索引如何允许我们正确地排列数据,那么让我们去掉所有的空值,这样我们就可以完成我们的分析了:

clean_table = clean_table.dropna(axis=1, how='all').dropna(axis=0)
print(clean_table)**Output:**
              AAPL     AMZN    MSFT    GOOGL
date                                        
2021-03-18  120.53  3027.99  230.72  2021.34
2021-03-19  119.99  3074.96  230.35  2026.96
2021-03-22  123.39  3110.87  235.99  2030.69
2021-03-23  122.54  3137.50  237.58  2041.33
2021-03-24  120.09  3087.07  235.46  2032.53
2021-03-25  120.59  3046.26  232.34  2032.46

累积收益和相关性

为了获得累积回报和相关性,我们需要首先计算月回报,这可以使用shift方法很容易地计算出来(此处应用的方法允许我们将每个观察值除以前一个观察值)。然后我们用cumprod得到累计收益。取cumul_returns的最后一行给出了我们的样本期内每只股票的累计回报。

stock_returns = (clean_table/clean_table.shift(1)-1).dropna()
cumul_returns = (1+stock_returns).cumprod()-1
cumul_returns.iloc[-1].plot(kind='bar', figsize=(8,5));
plt.tight_layout()
plt.savefig('ts_cumul_returns')

这是结果图:

在我们短暂的样本期内的累积回报(来源:Sharadar,图片由作者创作)

最后,让我们计算相关矩阵:

print(stock_returns.corr())**Output:**
           AAPL      AMZN      MSFT     GOOGL
AAPL   1.000000  0.440295  0.724448  0.344711
AMZN   0.440295  1.000000  0.710669  0.814061
MSFT   0.724448  0.710669  1.000000  0.499615
GOOGL  0.344711  0.814061  0.499615  1.000000

结论

全部完成!Pandas 确实使分析时间序列数据变得容易得多——难怪它在数据分析中如此重要。您对 Pandas 的微妙之处(如多重索引)掌握得越多,花在清理和格式化上的时间就越少,而花在思考、分析和建模上的时间就越多。干杯!

熊猫靠火花奔跑!

原文:https://towardsdatascience.com/pandas-on-spark-current-issues-and-workarounds-dc9ed30840ce?source=collection_archive---------11-----------------------

在那里,我参加了一个常规的熊猫项目,并尝试在 Spark pandas 下运行它

ZanUnsplash 上的照片

安达斯和火花

Pandas 是数据分析和数据科学的关键工具,已经存在了十多年。它是稳定的,经过验证的。但是 pandas 有一个重大的限制,每个数据工程师都会在某个时候碰到——它只能在一台计算机上运行。pandas 的数据大小限制约为 100M 行或 100GB,只有在功能强大、价格昂贵的计算机上才能达到这些限制。

Apache Spark 最近发布了这个问题的解决方案,在 Spark 3.2 中包含了 pyspark.pandas 库。由于 Spark 运行在几乎无限的计算机集群上,它可以处理的数据集大小实际上没有限制。熊猫程序员可以移动他们的代码来激发和消除以前的数据约束。

测试

当然,像这样的 API 仿真工作在第一个版本中是不完美的,也不会覆盖所有的目标特性。因此,我在 Spark 中测试了 pandas 的功能,将一些中等复杂的 pandas 代码从 Python 3.8.8 和 pandas 1.2.4 迁移到 Spark 3.2。我在 Databricks 10.0 中这样做,因为该平台使得创建和管理 Spark 集群变得容易。

我的目标是在 Spark 下运行代码,尽可能少做改动。我移植的 pandas 代码是一对程序——一个是导入/清理/规范化/连接三个数据集,一个是分析组合数据。由此产生的 pyspark.pandas 代码是一个 Databricks 笔记本,这里称为 DBCPython

结果

总的来说,pyspark.pandas 工作得很好,产生了正确的结果,无论是在数字上还是在各种图形的视觉上。需要对代码进行一些修改,但没有一处是令人失望的,也没有一处会导致错误或不完整的答案。

本文列出了我发现的妨碍我的代码不加修改地运行的问题,以及每个问题的解决方法。我已经向 Apache-Spark 吉拉报告了这些问题,并附上了这些链接。它们是:

  • 版本检查
  • 读取输入文件
  • 保存结果
  • 输入的拉丁 1 编码
  • to_numeric(错误=)
  • 。地图()。菲尔娜
  • 从字符串中删除后缀
  • 调整日期时间值
  • 数据帧中一列的直方图
  • 直方图标题
  • 直方图范围

我使用的计算环境是免费的 Databricks 社区版 10.0,其中包括 Spark 3.2。为了清楚起见,我用普通的别名“pd”来称呼普通的熊猫,用“pspd”来称呼 PySpark 熊猫。

检查熊猫版本

鉴于 pyspark.pandas 不是独立的软件,除了 pyspark 之外不进行更新,请将第一行中出现的任何内容更改为第二行。

#print(pd.__version__)print (sc.version)  # sc = Spark context

要跟踪此问题,请参见https://issues.apache.org/jira/browse/SPARK-37180

读取输入文件

对于从普通熊猫转向 Spark-cluster 熊猫的程序员来说,这个问题可能会令人困惑。对于普通的熊猫来说,程序、数据和用户都在同一台电脑上。有了 PySpark pandas,你的电脑只是操作 Spark 集群的前端,而 Spark 集群位于云中的某个地方。因此,pspd.read_csv()看不到电脑本地磁盘上的文件。

你如何给你的程序输入信息?有两种方法都很有效。

  • 使用 Databricks GUI 将输入文件从您的计算机复制到 Databricks 文件系统(DBFS)。详细说明在我的上一篇里。一旦到了 DBFS,文件就在 Spark 的本地,并且pspd.read_csv()可以正常打开它们。
  • 将文件放入云存储中,如亚马逊 S3Azure blob ,将该存储挂载到 DBFS,然后在pspd.read_csv().中使用该路径

要跟踪此问题,请参见https://issues.apache.org/jira/browse/SPARK-37198

保存结果

pspd.to_csv()写输出文件会导致两个问题。Spark 写 DBFS 而不是你的本地机器。由于 Spark 运行在多个计算节点上,它将输出写成一组名称丑陋、不可预测的文件集合。你可以找到这些文件,并把它们合并成一个普通的 CSV 文件,但这很麻烦。

要解决这些问题:

  • 对于可视化结果,如直方图或散点图,按下图中的相机图标以在本地机器上获得 PNG 图像。
  • 对于多达 10,000 行的数据集,使用display(pspdDataFrame).初始输出显示 1000 行,您可以选择获得 10,000 行。有一个按钮可以将 CSV 文件下载到您的本地机器上。
  • 对于稍后要处理的较大数据集,将数据帧保存为 Databricks 表,该表在计算会话之间作为单个实体保存在 DBFS 中。当您以后想要读取该数据时,只需在 Databricks 中打开该表。
# DataFrame to table
pspdDF.to_spark().write.mode(“OVERWRITE”).saveAsTable(“my_table”)

# Table to DataFrame
pspdDF = sqlContext.table(“my_table”).to_pandas_on_spark()

要跟踪此问题,请参见https://issues.apache.org/jira/browse/SPARK-37198

拉丁 1 编码

在撰写本文时,pspd.read_csv()还不支持 latin-1 编码。相反,使用pspd.read_csv(encoding='Windows-1252')这两种编码并不相同,但它们很接近。

要跟踪此问题,请参见https://issues.apache.org/jira/browse/SPARK-37181

to_numeric(错误=)

pandas 代码的一个常见行如下所示,它将文本数字转换成适当的数字数据类型。

VaxDF["CompleteCount"] = \
    pd.to_numeric(VaxDF["CompleteCount"], errors='coerce')\
    .fillna(0)\
    .astype(int)

errors='coerce'参数导致任何错误的值被设置为 NaN。但是 pspd.to_numeric()不支持 Spark 3.2 中的 errors 参数。幸运的是,pspd 的默认行为是模仿上面的,所以下面的代码就像包含了errors='coerce'.一样工作

VaxDF["CompleteCount"] = \
    pspd.to_numeric(VaxDF["CompleteCount"])\
    .fillna(0)\
    .astype(int)

要跟踪此问题,请参见https://issues.apache.org/jira/browse/SPARK-36609。请注意,此修复将提交给 Spark 代码库,并将出现在 Spark 3.3 中。

DF[列]。地图()。菲尔娜

习语。地图()。fillna()可用于控制在字典不包含某个键的情况下设置什么值。酪之后不支持 fillna()。PySpark Pandas 3.2 中的 map(),所以改一行这样的:

DF["state_abbr"] = \ 
    DF['state'].map(us_state_to_abbrev).fillna(DF["state"])

对此:

DF["state_abbr"] = DF['state'].map(us_state_to_abbrev)

确保字典包含所有需要的键,或者为缺少的键提供有意义的值。

追踪本期:https://issues.apache.org/jira/browse/SPARK-37183

. str.split 删除即可

在普通的熊猫中,你可以像这样去掉一个后缀:

DF["column"] = DF["column"].str.split("suffix").str[0]

在 pyspark.pandas 3.2 中,这种说法不起作用。相反,请这样做:

DF["column"] = DF["column"].str.replace("suffix", '', 1)

如果后缀只在末尾出现一次,两者都将正常工作。但是,请注意,如果后缀不止一次出现或者出现在整个字符串的中间,这两行代码的行为会有所不同。

追踪本期:https://issues.apache.org/jira/browse/SPARK-37184

offsets()来调整日期时间

在常规的 pandas 中,您可以使用 pandas.offsets 来创建一个时间增量,允许这样的行:

this_period_start = OVERALL_START_DATE + pd.offsets.Day(NN)

这在 pyspark.pandas 3.2 中不起作用。改为写:

import datetimethis_period_start = OVERALL_START_DATE + datetime.timedelta(days=NN)

追踪本期:https://issues.apache.org/jira/browse/SPARK-37186

大型数据框架中一列的直方图

当试图从一个较大的数据帧中创建一个列的直方图时,我的代码总是崩溃。下面一行产生了如下所示的错误:

DF.plot.hist(column=”FullVaxPer100", bins=20) # there are many other columnscannot resolve ‘least(min(EndDate), min(EndDeaths), min(`STATE-COUNTY`), min(StartDate), min(StartDeaths), min(POPESTIMATE2020), min(ST_ABBR), min(VaxStartDate), min(Series_Complete_Yes_Start), min(Administered_Dose1_Recip_Start), ...’ due to data type mismatch: The expressions should all have the same type, got LEAST(timestamp, bigint, string, timestamp, bigint, bigint, string, timestamp, bigint, bigint, timestamp, bigint, bigint,...).;

奇怪的是,pyspark.pandas 似乎在所有的列上操作,而只需要一个列。

作为一种解决方法,首先提取列,然后绘制直方图:

OneColumnDF = FullDF["FullVaxPer100"]OneColumnDF.plot.hist(bins=20, title="US Counties - FullVaxPer100")

追踪本期:https://issues.apache.org/jira/browse/SPARK-37187

直方图标题不起作用

在 pyspark.pandas 3.2 中,直方图的 title 参数没有任何作用。所以这个命令:

DF.plot.hist(bins=20, title="US Counties – FullVaxPer100")

运行时没有错误,但标题不与直方图一起显示。

作为一种变通方法,使用普通的 print()语句在绘图之前或之后输出标题。

追踪本期:https://issues.apache.org/jira/browse/SPARK-37188

直方图范围不起作用

在 pyspark.pandas 3.2 中,直方图的范围参数不起任何作用。所以这个命令:

DF.plot.hist(bins=20, range=[0, 50], title="US Counties")

运行时没有错误,但显示的值不限于 0 到 50 之间。

一种解决方法是,在运行直方图之前选择范围。

OneRangeDF = (DF[DF.DeathsPer100k <= 50])["DeathsPer100k"]
print ("US Counties -- DeathsPer100k (<=50)")
OneRangeDF.plot.hist(bins=20)

追踪本期:https://issues.apache.org/jira/browse/SPARK-37189

就像我上面说的,星火上的熊猫效果不错。上面链接的 pandas 代码在 Spark 上运行并产生了正确的结果,给出了这里概述的小的代码更改。

欢迎对本文进行评论和更正。

熊猫(Python) vs 数据表(R)

原文:https://towardsdatascience.com/pandas-python-vs-data-table-r-278386a96f2a?source=collection_archive---------53-----------------------

比较两种流行的数据操作库的实用指南

约尔根·哈兰在 Unsplash 上的照片

数据科学生态系统充满了高效实用的工具和框架。新的产品不断推出,现有的产品不断改进。

有多种选择是一件好事,在大多数情况下可能会提高效率。然而,这也可能让你很难决定选择哪一个。

在本文中,我们将比较数据科学领域中最常用的两种编程语言中流行的数据操作库。

我们将看到基本操作是如何在 Pandas (Python)和 Data.table (R)中完成的。目标不是确定一个是否优于或优于另一个。我只是想让你熟悉语法,并展示相似或不同的方法。

使用这些包有很多选择。我用 R-studio IDE 做 R,用 VSCode 做 Python。

我们从导入库开始,通过从 csv 文件中读取数据来创建基本的数据结构。

读取 csv 和 fread

在 Pandas 中,我们使用 read_csv 函数从 csv 文件创建数据帧。

import numpy as np
import pandas as pd #importing pandasinsurance = pd.read_csv("/home/soner/Downloads/datasets/insurance.csv")

在 Data.table 中,read_csv 的等效函数是 fread 函数。

> library(data.table) #importing data.table 

> insurance = fread("/home/soner/Downloads/datasets/insurance.csv")

head 函数显示前 n 行。两个包的函数名相同,但语法略有不同。

熊猫(作者图片)

Data.table(图片作者提供)

两者的缺省 n 值都是 5,所以缺省情况下它们将显示前 5 行。

行数和列数

我们通常根据行数和列数来检查数据的大小。这两个库都有获取大小相关信息的直观方法。

#Pandas
insurance.shape
(1338, 7)#Data.table
nrow(insurance)
1338ncol(insurance)
7

按列选择子集

在某些情况下,我们只需要表中的一组列。Pandas 和 Data.table 都提供了方便的方法来完成这个操作。

sub = insurance[['age','sex','charges']]
sub.head()

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

对 Data.table 执行相同的操作,如下所示:

> sub = insurance[, .(age, sex, charges)]
> head(sub)

子数据表(图片由作者提供)

重命名列

rename 和 setname 函数可分别用于重命名 Pandas 和 Data.table 中的列。

熊猫:

sub.rename(columns={'sex':'gender'}, inplace=True)sub.columns
Index(['age', 'gender', 'charges'], dtype='object')

数据表:

> setnames(sub, c("sex"), c("gender"))> names(sub)
[1] "age"     "gender"  "charges"

正如我们从示例中看到的,dataframe 上的 columns 方法返回列的列表。对 Data.table 库中的 names 函数执行相同的操作。

基于行值的筛选

我们可以根据行值过滤数据帧或表格。在下面的示例中,我们创建了一个包含年龄超过 40 岁的客户的子集。

熊猫:

sub_over40 = sub[sub.age > 40]

(图片由作者提供)

数据表:

> sub_over40 <- sub[age > 40] #can also use "<-" instead of "="

(图片由作者提供)

分组

数据分析中最常见的操作之一是根据分类变量中的不同值来比较数值变量。

在 Pandas 中,这种转换和计算是通过 group by 函数完成的。例如,我们可以基于性别和吸烟者列计算每个类别中数据点的平均费用。

insurance[['gender','smoker','charges']]\
.groupby(['gender','smoker']).mean().round(2)

(图片由作者提供)

可以应用多个聚合函数。例如,除了平均电荷值之外,我们可能还希望看到每组中的观察次数。

insurance[['gender','smoker','charges']]\
.groupby(['gender','smoker']).agg(['mean','count'])

(图片由作者提供)

在 Data.table 中,相同的计算如下:

> insurance[, .(mean(charges)), by = .(gender, smoker)]

(图片由作者提供)

就像 Pandas 一样,Data.table 提供了一种应用多个聚合的简单方法。观察次数和平均电荷值计算如下:

> insurance[, .(mean(charges), .N), by = .(gender, smoker)]

(图片由作者提供)

结论

我们已经在 Pandas 和 Data.table 库中介绍了一些简单的任务。由于操作的复杂程度,两个库的语法看起来非常相似。然而,随着复杂性的增加,以及我们进行更高级的数据分析和操作,它们之间的差异变得更加明显。

学习如何使用这些库的最好方法是通过实践。当您在数据分析任务中使用它们时,您会更喜欢在某些任务中使用特定的一个。

总的来说,我认为两者都足以完成典型的数据分析任务。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫侧桌——如何用最简单的方法计算频率

原文:https://towardsdatascience.com/pandas-sidetable-how-you-calculate-frequencies-the-easy-way-d56afa90973c?source=collection_archive---------20-----------------------

简化 EDA 中的频率计算

照片由卡伦·艾姆斯利Unsplash 上拍摄

在我的日常数据科学工作中,我几乎所有的项目都使用熊猫。毫无疑问,pandas 是用于数据处理和分析的最流行的 Python 库之一。基于 Python 的开源理念,pandas 也可供我们免费使用。

更重要的是,开源性质允许好奇且有能力的数据科学家通过创建额外的附加组件来扩展熊猫已经提供的多种功能。一个这样的附加组件是sidetable,它为我们的数据构建了简单但信息丰富的摘要。

在本教程中,让我们探索这个优雅工具的基本特性。事不宜迟,让我们开始吧。

0.家务琐事

在所需的虚拟环境中,您可以使用pip工具安装sidetable。如果您的项目不使用虚拟环境,强烈建议您这样做。如果你感兴趣,这里有一个快速入门

pip install sidetable

一旦你安装了这个包,你导入它们应该没有问题。出于当前教程的考虑,让我们使用 tips 数据集,它有数百条关于感恩的记录,作为日期、时间和其他因素的函数。

下面向您展示了数据集以及导入。

设置

1.计算频率

在我们的 EDA(探索性数据分析)中,检查分类变量的频率以查看是否存在任何异常总是一个好主意。按照惯例,我们可以在 Series 上使用value_counts方法,如下所示。

>>> df['day'].value_counts()
Sat     87
Sun     76
Thur    62
Fri     19
Name: day, dtype: int64
>>> df['day'].value_counts(normalize=True)
Sat     0.356557
Sun     0.311475
Thur    0.254098
Fri     0.077869
Name: day, dtype: float64

绝对计数和它们相应的频率都是有趣的信息。然而,如果我们想并排查看它们,我们必须将它们合并。这对我来说是个问题——在我开始使用sidetable之前,事情已经变得简单多了。

>>> df.stb.freq(['day'])
    day  count    percent  cumulative_count  cumulative_percent
0   Sat     87  35.655738                87           35.655738
1   Sun     76  31.147541               163           66.803279
2  Thur     62  25.409836               225           92.213115
3   Fri     19   7.786885               244          100.000000

不是计数和它们各自的百分比并排作为一天的函数。它还提供了累积计数和百分比,这在许多用例中都很有用。

您可以拥有多个列来创建更多的子组,而不是传递一个列,这可以为我们提供更细粒度的信息。下面是一个例子。

多列频率

只是提醒一下,如果没有sidetable,您将不得不使用groupby结合其他几个计算来获得这些数据,这是很重要的。

2.聚合更小的组

当你有太多组的时候,一些组的频率可能太小而没有意义。请考虑以下情况:

>>> df.stb.freq(['size'])
   size  count    percent  cumulative_count  cumulative_percent
0     2    156  63.934426               156           63.934426
1     3     38  15.573770               194           79.508197
2     4     37  15.163934               231           94.672131
3     5      5   2.049180               236           96.721311
4     6      4   1.639344               240           98.360656
5     1      4   1.639344               244          100.000000

如你所见,当聚会规模小于 2 或大于 4 时,数据并不太多。在这种情况下,我们可以考虑聚合这些更小的组,如下所示。我们只需为分组设置一个阈值——超过这个百分比,所有剩余的组将被合并。

>>> df.stb.freq(['size'], thresh=95)
     size  count    percent  cumulative_count  cumulative_percent
0     2.0    156  63.934426               156           63.934426
1     3.0     38  15.573770               194           79.508197
2     4.0     37  15.163934               231           94.672131
3  others     13   5.327869               244          100.000000

3.按组计算单独的总和

在上一节中,我们已经看到了freq方法生成与计数相关的结果。除此之外,sidetable还提供了一种按组计算单独金额的便捷方式。这就像在freq方法中指定value参数一样简单。

>>> df.stb.freq(['day'], value='tip')
    day     tip    percent  cumulative_tip  cumulative_percent
0   Sat  260.40  35.594193          260.40           35.594193
1   Sun  247.39  33.815851          507.79           69.410044
2  Thur  171.83  23.487520          679.62           92.897564
3   Fri   51.96   7.102436          731.58          100.000000

在上面的例子中,我们想知道小费的总额是一天的函数。为此,我们只需将value设置为‘tip’

4.按组计算小计

当我们将数据聚合为多级分组的函数时,有时需要按顶级计算小计。考虑下面的例子:

按组求和

在这两种情况下,我们都不知道一天的总小费是多少。为此,我们可以利用subtotal方法。

按组分类汇总

在本例中,我们有两个级别,因此默认情况下,小计是为第一个级别计算的。当有 N (N>2)个级别时,默认情况下将提供前 N-1 个级别的小计。

5.计数概述

sidetable的另一个超级有用的方法是counts,它构建了一个表,向您显示列的唯一值总数,以及最频繁和最不频繁的类别及其各自的计数。听起来很拗口?让我们快速看一个例子。

按列计数

通过检查列数,很容易发现一些有用的信息。例如,大多数账单不涉及吸烟者(151 对 93),男性顾客比女性顾客多(157 对 87)。周六的账单最多,这可能是人们的预期。

6.失踪人员概述

EDA 中的另一个重要步骤是找出数据集缺失的程度。熊猫当然有现有的方法(比如isna)来完成这个需求。但是,如前所述,您必须进行一些单独的计算,以全面了解数据集中的缺失情况。幸运的是,sidetable为我们挑起了重担。

>>> df.stb.missing()
            missing  total  percent
total_bill        0    244      0.0
tip               0    244      0.0
sex               0    244      0.0
smoker            0    244      0.0
day               0    244      0.0
time              0    244      0.0
size              0    244      0.0

这就像调用missing方法一样简单,它不提供缺失值的数量,也不提供这些数字的百分比。是不是超级方便?

最后的想法

在本文中,我们回顾了sidetable必须提供的基本操作。正如您所注意到的,它并不是一个提供大量函数的花哨的库,但它确实提供了必要的快速方法来计算与数据集频率相关的关键数据质量指标。

顺便提一下,初级数据科学家往往忽视 EDA 的重要性,喜欢跳到“有趣”的部分,尽快开始分析数据,因为分析工作更有回报。然而,我想提醒你,也提醒我自己,最初彻底的数据质量检查最终决定了你的分析质量。

原因很简单:垃圾进,垃圾出。

熊猫到 PySpark 的 6 个例子

原文:https://towardsdatascience.com/pandas-to-pyspark-in-6-examples-bd8ab825d389?source=collection_archive---------20-----------------------

当你去大规模的时候会发生什么

杰克·吉文斯在 Unsplash 上的照片

Pandas 是操纵和分析结构化数据的主要工具之一。它提供了许多函数和方法来处理表格数据。

然而,随着数据变大,熊猫可能不是你最好的朋友。当处理大规模数据时,有必要同时分发数据和计算,这是 Pandas 无法实现的。

这类任务的一个非常受欢迎的选项是 Spark,这是一个用于大规模数据处理的分析引擎。它让您可以将数据和计算分散到集群上,从而实现显著的性能提升。

收集和存储数据已经变得非常容易,所以当我们处理现实生活中的问题时,可能会有大量的数据。因此,像 Spark 这样的分布式引擎正在成为数据科学生态系统中的主要工具。

PySpark 是 Spark 的 Python API。它结合了 Python 的简单性和 Spark 的高性能。在本文中,我们将通过 6 个例子来演示 PySpark 版 Pandas 的典型数据分析和操作任务。

示例 1

我们需要一个例子的数据集。因此,第一个示例是通过读取 csv 文件来创建数据帧。我将使用 Kaggle 上的墨尔本房产数据集

# Pandas
import pandas as pd
df = pd.read_csv("melb_housing.csv")

对于 PySpark,我们首先需要创建一个 SparkSession,作为 Spark SQL 的入口点。

from pyspark.sql import SparkSession
sc = SparkSession.builder.getOrCreate()sc.sparkContext.setLogLevel("WARN")print(sc)
<pyspark.sql.session.SparkSession object at 0x7fecd819e630>

我们现在可以读取 csv 文件了。

# PySpark
df = sc.read.option("header", "true").csv(
    "/home/sparkuser/Desktop/melb_housing.csv"
)

示例 2

开始数据分析的一个好方法是获得数据的概述。例如,我们可能想要检查列名、行数,并查看前几行。

# Pandaslen(df)
63023df.columns
Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG','Date', 'Postcode', 'Regionname', 'Propertycount', 'Distance','CouncilArea'])

(图片由作者提供)

这些函数和方法与 PySpark 非常相似。

# PySparkdf.count()
63023df.columns
['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG','Date', 'Postcode', 'Regionname', 'Propertycount', 'Distance','CouncilArea']df.show(5)

示例 3

在某些情况下,我们需要根据列值过滤数据框。例如,我们可能对北部大都市地区价值超过 100 万英镑的房子感兴趣。

对于 Pandas,wgionne 指定条件和列名如下:

# Pandas
df_sub = df[
      (df.Price > 1000000) & 
      (df.Regionname == 'Northern Metropolitan')
]len(df_sub)
3022

我们对 PySpark 采用了类似的方法。

# PySpark
from pyspark.sql import functions as Fdf_sub = df.filter(
    (F.col('Price') > 1000000) &
    (F.col('Regionname') == 'Northern Metropolitan')
)df_sub.count()
3022

PySpark 的 SQL 模块中的函数需要单独导入。在以下示例中,我们将使用本模块中的几个函数。

实例 4

典型的任务可以是根据列选择数据集的子集。让我们以价格、地区名称和地址列为例,按价格降序排列。我们将只显示前 5 个观察值(即行)。

# Pandas
df[['Price', 'Regionname', 'Address']].sort_values(by='Price', ascending=False).head()# PySpark
df.select("Price", "Regionname", "Address").orderBy('Price', ascending=False).show(5)

(图片由作者提供)

语法也非常相似。PySpark 的功能更像 SQL 语句。此外,正如您所注意到的,PySpark 像显示 SQL 表一样显示数据框。

实例 5

我们并不总是数字数据。文本数据是数据科学的基础部分。因此,数据分析库提供了许多操作字符串的函数。

例如,我们可能希望从地址列的值中提取地址的类型。

# Pandas
df.Address[:3]
0    49 Lithgow St 
1    59A Turner St 
2    119B Yarra St

地址中的最后一个字给出了 st 和 rd 等类型。我们可以通过在空格处拆分地址并获得最后一项来获得该信息。

Pandas 使用 str 访问器下的 split 函数来完成这个操作。

# Pandas
df.Address.str.split(' ', expand=True)[2][:5]
0    St 
1    St 
2    St 
3    St 
4    Rd

末尾的“[:5]”表达式仅用于显示前 5 行。

Pyspark 还有一个拆分功能。下面是如何使用该函数完成该操作的:

# PySpark
df.select(
   F.split("Address", ' ').getItem(2).alias('Address_type')
).show(5)

(图片由作者提供)

实例 6

数据分析中最常用的函数之一是 groupby 函数。它允许根据列中的类别或不同值对行进行分组。然后,我们可以对每个组的数字列执行聚合。

例如,我们可以计算每个地区的平均房价。熊猫和 PySpark 都有这类任务的分组功能。

# Pandas
df.groupby('Regionname').agg(Avg_price=('Price', 'mean')).round(2)# Pyspark
df.groupby('Regionname').agg(F.round(F.mean('Price'), 2).alias('Avg_price'))

(图片由作者提供)

结论

我们做了 6 个例子来比较 Pandas 和 PySpark 的语法。正如我们在例子中看到的,它们非常相似。

需要注意的是,Spark 针对大规模数据进行了优化。因此,在处理小规模数据时,您可能看不到任何性能提升。事实上,在处理小数据集时,Pandas 可能会比 PySpark 表现得更好。

感谢您的阅读。如果您有任何反馈,请告诉我。

pandas-to-sql——将代码从 SQL 转移到 Python 和 Pandas

原文:https://towardsdatascience.com/pandas-to-sql-moving-code-from-sql-to-python-and-pandas-afc4c62a644c?source=collection_archive---------14-----------------------

迈克尔·泽兹奇在 Unsplash 上的照片

pandas-to-sql 是一个 python 库,允许使用 python 的 Pandas DataFrames 来创建 sql 字符串,这些字符串稍后可用于查询数据库。这里有一些你可以运行的例子。

数据科学项目的常见结构将从数据获取和准备阶段开始。如果保存数据的数据库支持 SQL,数据提取甚至一些数据准备都可以使用 SQL 来执行(受 DB 支持,为什么不呢?)

这方面的问题:

  • 用两种不同的语言(SQL 和 Python)维护代码
  • 该项目成为一个两步项目(SQL 部分,然后是 Python 部分)。这可能是设计的选择,但也可能是项目中两种编码语言的副作用
  • 在 SQL 代码上更难使用编码原则和最佳实践(例如 SOLID
  • 通常,SQL 代码不会被测试

pandas-to-sql 如何尝试解决这些问题?

pandas-to-sql 是一个 python 库,允许用户使用 pandas 数据帧,创建不同的操作,并最终使用 get_sql_string() 方法获得描述操作的 sql 字符串。此时,可以使用这个字符串来查询数据库。

如何安装:

pip install pandas-to-sql

简单的例子:

输出:

‘SELECT (sepal_length) AS sepal_length, (sepal_width) AS sepal_width, (petal_length) AS petal_length, (petal_width) AS petal_width, (species) AS species FROM iris’

在上面的例子中,我们将虹膜数据集加载到熊猫数据帧中。然后我们使用 pandas_to_sql.wrap_df 转换数据帧。从这一点开始,所有操作都将保存为 SQL 字符串。在任何时候,都可以使用 df.get_sql_string() 获得这个 SQL 字符串。

这里还有一些例子…

过滤示例:

输出:

‘SELECT (sepal_length) AS sepal_length, (sepal_width) AS sepal_width, (petal_length) AS petal_length, (petal_width) AS petal_width, (species) AS species FROM iris WHERE (((petal_length > 1.4) AND (petal_width < 0.2)))’

分组示例:

输出:

‘SELECT (avg(petal_length)) AS petal_length_mean, (sum(petal_length)) AS petal_length_sum, (count(petal_length)) AS petal_length_count, (species) AS species FROM iris GROUP BY species’

注意约定的使用。由于 Pandas groupby 返回一个多索引数据帧,而该数据帧不适用于 SQL,因此该方法编辑 SQL 查询中的列名,以匹配 reset_index() 返回的默认值(并对 groupby 返回的数据帧执行 reset_index() )。

串联示例:

输出:

‘SELECT (sepal_length) AS sepal_length, (sepal_width) AS sepal_width, (petal_length) AS petal_length, (petal_width) AS petal_width, (species) AS species, ((CASE WHEN ((ABS(sepal_width) — ROUND(ABS(sepal_width)-0.5))==.5) AND ((CAST(sepal_width AS INT))%2 == 0) THEN (CASE WHEN sepal_width>0 THEN ROUND(sepal_width-0.001) ELSE ROUND(sepal_width+0.001) END) ELSE (ROUND(sepal_width)) END)) AS sepal_width_rounded FROM iris WHERE ((species = ‘setosa’)) UNION ALL SELECT (sepal_length) AS sepal_length, (sepal_width) AS sepal_width, (petal_length) AS petal_length, (petal_width) AS petal_width, (species) AS species, ((CASE WHEN ((ABS(sepal_width) — ROUND(ABS(sepal_width)-0.5))==.5) AND ((CAST(sepal_width AS INT))%2 == 0) THEN (CASE WHEN sepal_width>0 THEN ROUND(sepal_width-0.001) ELSE ROUND(sepal_width+0.001) END) ELSE (ROUND(sepal_width)) END)) AS sepal_width_rounded FROM iris WHERE ((species = ‘versicolor’))‘

这里注意 PDpandas _ to _ SQL . wrap _ PD(PD)的包装,以便覆盖 pd.concat()

以下是一个要点中的所有示例:

该库尚未投入生产。我的主要目标是检查这个想法的吸引力,以及是否有更多的人觉得这个有用。如果是的话,会增加更多的支持。目前的支持只针对 SQLite ,希望很快增加对的支持。对于任何 bug 或新功能请求,请随时提出问题。问题

感谢阅读:-)

5 个例子中的 Pandas vs SQL

原文:https://towardsdatascience.com/pandas-vs-sql-in-5-examples-485b5571d934?source=collection_archive---------26-----------------------

Pandas 中的合并和 SQL 中的连接的比较

詹姆斯·巴尔茨在 Unsplash 上的照片

最近,我写了几篇文章,专注于数据科学生态系统中使用的工具和框架的比较,如 Pandas vs dplyr、SQL vs NoSQL、Pandas vs SQL、Seaborn vs ggplot2、Seaborn vs Altair 等等。

在这些文章中,我主要关注如何使用不同的工具来完成给定的任务。我清楚地看到了它们之间的差异和相似之处。此外,它有助于建立一种直觉,了解这些工具的创造者是如何处理特定问题的。

本文的重点是在合并和连接操作方面比较 Pandas 和 SQL。Pandas 是 Python 的一个数据分析和操作库。SQL 是一种用于管理关系数据库中数据的编程语言。两者都处理带有标签的行和列的表格数据。

Pandas 的合并功能根据公共列中的值合并数据帧。SQL 中的连接也完成了同样的操作。这些都是非常有用的操作,尤其是当我们在表格的不同数据框架中有关于观察的数据(即数据点)时。

熊猫合并(图片由作者提供)

我创建了两个简单的数据框架和表格,通过例子来说明合并和连接。

客户数据框架(图片由作者提供)

“cust”包含关于 5 个客户的 3 条信息。这些列是 id、年龄和类别。

“purc”包含客户 id、票号和购买金额。

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

id 是公共列,所以我们将在合并或连接时使用它。

您可能已经注意到 id 列并不完全相同。一些值只存在于一个数据帧中。我们将在示例中看到处理它们的方法。

示例 1

第一个示例是基于 id 列中的共享值进行合并或联接。默认设置完成这项任务,所以我们不需要调整任何参数。

熊猫:

import pandas as pdcust.merge(purc, on='id')

(图片由作者提供)

SQL:

mysql> select cust.*, purc.*
    -> from cust join purc 
    -> on cust.id = purc.id;+------+------+------+------+--------+--------+
| id   | age  | ctg  | id   | ticket | amount |
+------+------+------+------+--------+--------+
|    3 |   22 | B    |    3 |   1001 |  24.10 |
|    4 |   29 | C    |    4 |   1002 |  32.50 |
|    5 |   17 | B    |    5 |   1003 |  34.80 |
+------+------+------+------+--------+--------+

Pandas 的合并功能不会返回重复的列。另一方面,如果我们选择两个表中的所有列(" * "),则 id 列在 SQL join 中是重复的。

示例 2

假设我们希望左表中有所有的行,而右表中只有匹配的行。在 Pandas 中,打开参数被更改为“左”。在 SQL 中,我们使用“left join”而不是“join”关键字。

熊猫:

cust.merge(purc, on='id', how='left')

(图片由作者提供)

SQL:

mysql> select cust.*, purc.*
    -> from cust
    -> left join purc
    -> on cust.id = purc.id;+------+------+------+------+--------+--------+
| id   | age  | ctg  | id   | ticket | amount |
+------+------+------+------+--------+--------+
|    3 |   22 | B    |    3 |   1001 |  24.10 |
|    4 |   29 | C    |    4 |   1002 |  32.50 |
|    5 |   17 | B    |    5 |   1003 |  34.80 |
|    1 |   34 | A    | NULL |   NULL |   NULL |
|    2 |   28 | A    | NULL |   NULL |   NULL |
+------+------+------+------+--------+--------+

purc 数据帧和表没有 id 为 1 或 2 的行。因此,purc 中的列用这些行的空值填充。

我们可以使用 on 参数的“right”参数对右边的数据帧进行同样的操作。类似地,在 SQL 中使用了“右连接”。

示例 3

如果我们希望看到数据帧或表中的所有行,该怎么办?

熊猫:

在 Pandas 中,这是一个简单的操作,可以通过将“outer”参数传递给 on 参数来完成。

cust.merge(purc, on='id', how='outer')

(图片由作者提供)

SQL:

MySQL 不提供“全外部”连接,但是我们可以通过组合两个左连接来实现它。

注意:尽管关系数据库管理系统(RDBMSs)大多采用相同的 SQL 语法,但可能会有细微的差别。因此,最好检查特定 RDBMS 的文档,看看它是否支持完全外连接。

在 MySQL 中,下面是如何用两个左连接实现一个完整的外连接:

mysql> select cust.*, purc.*
    -> from cust left join purc
    -> on cust.id = purc.id
    -> union
    -> select cust.*, purc.*
    -> from purc left join cust
    -> on cust.id = purc.id;+------+------+------+------+--------+--------+
| id   | age  | ctg  | id   | ticket | amount |
+------+------+------+------+--------+--------+
|    3 |   22 | B    |    3 |   1001 |  24.10 |
|    4 |   29 | C    |    4 |   1002 |  32.50 |
|    5 |   17 | B    |    5 |   1003 |  34.80 |
|    1 |   34 | A    | NULL |   NULL |   NULL |
|    2 |   28 | A    | NULL |   NULL |   NULL |
| NULL | NULL | NULL |    6 |   1004 |  19.50 |
| NULL | NULL | NULL |    7 |   1005 |  26.20 |
+------+------+------+------+--------+--------+

union 运算符堆叠多个查询的结果。类似熊猫的 concat 功能。

实例 4

合并或联接不仅仅是组合数据。我们可以把它们作为数据分析的工具。例如,我们可以计算每个类别的总订单量(“ctg”)。

熊猫:

cust.merge(purc, on='id', how='left')[['ctg','amount']]\
.groupby('ctg').mean()

ctg     amount
--------------                             
A       NaN                 
B       29.45                 
C       32.50

SQL:

mysql> select cust.ctg, sum(purc.amount)
    -> from cust
    -> left join purc
    -> on cust.id = purc.id
    -> group by cust.ctg;+------+------------------+
| ctg  | sum(purc.amount) |
+------+------------------+
| A    |             NULL |
| B    |            58.90 |
| C    |            32.50 |
+------+------------------+

因为 purc 表不包含属于类别 A 中的客户的任何购买,所以 sum 结果为 Null。

实例 5

我们也可以在合并前根据条件过滤行。假设我们需要找到 25 岁以下的顾客的购买量。

熊猫:

我们首先过滤数据帧,然后应用合并功能。

cust[cust.age < 25].merge(purc, on='id', how='left')[['age','amount']] age     amount                       
0       22       24.1                 
1       17       34.8

SQL:

我们只是实现了一个 where 子句来指定过滤的条件。

mysql> select cust.age, purc.amount
    -> from cust
    -> join purc
    -> on cust.id = purc.id
    -> where cust.age < 25;+------+--------+
| age  | amount |
+------+--------+
|   22 |  24.10 |
|   17 |  34.80 |
+------+--------+

结论

我们已经通过一些例子展示了 Pandas merge 函数和 SQL 连接之间的区别和相似之处。

这些例子可以被认为是简单的案例,但是它们可以帮助你建立直觉和理解基础。理解了基础知识之后,你就可以逐步学习更高级的操作了。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫 vs SQL。当数据科学家应该使用一个而不是另一个的时候。

原文:https://towardsdatascience.com/pandas-vs-sql-when-data-scientists-should-use-one-over-the-other-ba5f27a78e5d?source=collection_archive---------3-----------------------

意见

深入探究每种工具的优势

照片由参宿七Unsplash【1】拍摄。

目录

  1. 介绍
  2. 熊猫
  3. 结构化查询语言
  4. 摘要
  5. 参考

介绍

这两种工具不仅对数据科学家很重要,对数据分析和商业智能等类似职位的人也很重要。也就是说,数据科学家什么时候应该专门使用 pandas 而不是 SQL,反之亦然?在某些情况下,您可以只使用 SQL,而在其他一些时候,pandas 更容易使用,特别是对于那些专注于 Jupyter 笔记本设置中的研究的数据科学家。下面,我将讨论你什么时候应该使用 SQL,什么时候应该使用 pandas。请记住,这两种工具都有特定的用例,但是它们的功能有很多重叠的地方,这也是我下面要比较的地方。

熊猫

照片由卡伦·坎普Unsplash【2】上拍摄。

Pandas【3】是 Python 编程语言中的一个开源数据分析工具。当您已经有了主数据集(通常来自 SQL 查询)时,pandas 的好处就开始了。这一主要区别意味着这两个工具是独立的,但是,您也可以在各自的工具中执行几个相同的功能,例如,您可以在 pandas 中从现有的列创建新的要素,这可能比在 SQL 中更容易和更快。

需要注意的是,我并不是在比较 Pandas 能做 SQL 不能做的事情,反之亦然。我将根据个人经验,选择能更有效或更适合数据科学工作的工具。

以下是使用 pandas 比 SQL 更有利的时候——同时还具有与 SQL 相同的功能:

  • 根据现有特征创建计算字段

当合并一个更复杂的 SQL 查询时,通常还会合并子查询,以便划分不同列的值。在熊猫身上,你可以简单地划分特征,就像下面这样:

df["new_column"] = df["first_column"]/df["second_column"]

上面的代码显示了如何划分两个单独的列,并将这些值分配给一个新列-在这种情况下,您将对整个数据集或数据框执行要素创建。在数据科学的过程中,您可以在特征探索和特征工程中使用该功能。

  • 分组依据

还可以参考子查询,SQL 中的 group by 可能会变得非常复杂,并且需要一行又一行的代码,这在视觉上可能会让人不知所措。在熊猫中,你可以简单地通过一行代码进行分组。我不是在一个简单的 select from table 查询的末尾引用 group by,而是在一个包含多个子查询的查询中引用。

df.groupby(by="first_column").mean()

这个结果将返回数据帧中每一列的 first_column 的平均值。使用这个分组功能还有很多其他的方法,下面链接的 pandas 文档中很好地概述了这些方法。

  • 检查数据类型

在 SQL 中,您经常需要转换类型,但是有时可以更清楚地看到 pandas 以垂直格式排列数据类型的方式,而不是在 SQL 中滚动水平输出。您可以预期返回的数据类型的一些示例是 int64、float64、datetime64[ns]和 object。

df.dtypes

虽然这些都是 pandas 和 SQL 的相当简单的函数,但在 SQL 中,它们特别复杂,有时在 pandas 数据框架中更容易实现。现在,让我们看看 SQL 更擅长执行什么。

结构化查询语言

卡斯帕·卡米尔·鲁宾在Unsplash【4】上的照片。

SQL 可能是被最多不同职位使用最多的语言。例如,数据工程师可以使用 SQL、Tableau 开发人员或产品经理。也就是说,数据科学家倾向于频繁使用 SQL。值得注意的是,SQL 有几种不同的版本,通常都有相似的功能,只是格式略有不同。

以下是使用 SQL 比 pandas 更有利的时候——同时还具有与 pandas 相同的功能:

  • WHERE 子句

SQL 中的这个子句使用频率很高,在熊猫中也可以执行。然而,对于熊猫来说,这要稍微困难一些,或者说不那么直观。例如,您必须写出冗余的代码,而在 SQL 中,您只需要WHERE

SELECT IDFROM TABLEWHERE ID > 100

对熊猫来说,可能是这样的:

df[df["ID"] > 100]["ID"]

是的,两个都很简单,一个只是更直观一点。

  • 加入

Pandas 有几种连接方式,这可能有点让人不知所措,而在 SQL 中,您可以执行简单的连接,如下所示:INNER, LEFT, RIGHT

SELECTone.column_A,two.column_BFROM FIRST_TABLE oneINNER JOIN SECOND_TABLE two on two.ID = one.ID

在这段代码中,join 比 pandas 更容易阅读,在 pandas 中,您必须合并数据帧,尤其是当您合并两个以上的数据帧时,在 pandas 中会非常复杂。SQL 可以执行多重连接,无论是内部连接还是其他连接。,都在同一个查询中。

所有这些例子,无论是 SQL 还是 pandas,至少可以用于数据科学过程的探索性数据分析部分,也可以用于特征工程,以及在将模型结果存储到数据库中后对其进行查询。

摘要

pandas 与 SQL 的这种比较更多的是个人偏好。话虽如此,你可能会觉得我的意见相反。然而,我希望它仍然揭示了 pandas 和 SQL 之间的区别,以及您可以在这两个工具中执行相同的操作,使用稍微不同的编码技术和完全不同的语言。

总的来说,我们比较了使用 pandas 和 SQL 的好处,反之亦然,它们有一些共享的功能:

* creating calculated fields from existing features* grouping by* checking data types* WHERE clause* JOINS

我希望你觉得我的文章既有趣又有用。如果你同意这些比较,请在下面随意评论——为什么或为什么不同意?你认为一种工具比另一种更好吗?你能想到哪些其他数据科学工具可以进行类似的比较?pandas 和 SQL 还有哪些功能可以比较?

请随时查看我的个人资料和其他文章,也可以通过 LinkedIn 联系我。

参考

[1]照片由参宿七Unsplash(2019)拍摄

[2]照片由卡伦·肯普Unsplash(2020)上拍摄

[3]熊猫开发小组,熊猫文献,(2008-2021)

[4]卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄的照片,(2017 年)

文字资料上的熊猫 vs Tidyverse

原文:https://towardsdatascience.com/pandas-vs-tidyverse-on-textual-data-23c6a7c2df8c?source=collection_archive---------25-----------------------

如何在两个库中操作字符串

照片由 Aaron BurdenUnsplash

文本数据通常没有一个好的和干净的格式,所以它需要大量的预处理和操作。大量的原始数据是文本的,所以数据分析库应该能够很好地处理字符串。

在本文中,我们将从处理字符串的角度比较两个流行的库。第一个是 pandas,它是 Python 的数据分析和操作库。另一个是 tidyverse,它是为数据科学设计的 R 包的集合。

在熊猫的例子中,我们将使用城市数据框架。我还使用 r . exe 中的 readr 包创建了一个包含相同数据的 tibble。

拆开一根绳子

熊猫:

可以使用 str 访问器来使用字符串函数和方法。split 函数在给定字符处拆分字符串。

“城市”列包括城市和州的名称。我们可以为 state 部分创建一个新列。

import pandas as pdcities.city.str.split(",")0    [Houston, TX]
1     [Dallas, TX]
2    [Seattle, WA]
3    [Atlanta, GA]

返回序列中的每个值都是城市和州的列表。我们可以通过使用 str 索引提取一个新列,将其分配给 state 部分。

cities['state'] = cities.city.str.split(",").str[1]

城市数据框架(图片由作者提供)

潮汐:

Tidyverse 是包的集合。我们将使用以下 tidyverse 包来处理城市 tibble(与 pandas 中的 dataframe 相同)

  • readr:从 csv 文件创建 tibble
  • DP lyr:tible 上的数据操作
  • stringr:字符串上的函数
cities <- mutate(cities, state = str_split_fixed(city, ",", n=2)[,2])

dplyr 包的 mutate 函数可以用来在现有列的基础上创建新列。

stringr 包的 str_split_fixed 函数在逗号处拆分城市列。因为每个值中有两个字,所以 n 参数是 2。最后,我们选择分裂后的第二部分。

适宜居住的城市(图片由作者提供)

上和下

将字符串转换为大写或小写是获得一致值的常见操作。

让我们将“ctg1”列转换为大写字母。

熊猫:

上层函数的用法如下。

cities['ctg1'] = cities['ctg1'].str.upper()

城市数据框架(图片由作者提供)

Tidyverse:

stringr 包的 str_to_upper 函数使用如下。

cities <- mutate(cities, ctg1 = str_to_upper(ctg1))

连接字符串

就像我们拆分字符串一样,我们可能也需要组合它们。例如,我们可以通过合并“ctg1”和“ctg2”列来创建一个新的类别列。

熊猫:

使用 str 访问器的 cat 函数。我们指定用作分隔符的字符以及列名。

cities['new_ctg'] = cities['ctg1'].str.cat(cities['ctg2'], sep="-")

潮汐:

使用 stringr 包的 str_c 函数。

cities <- mutate(cities, new_ctg = str_c(ctg1, ctg2, sep="-"))

适宜居住的城市(图片由作者提供)

遏制/检测

我们可以检查字符串,看看它们是否包含一个特定的字符或一组字符。让我们创建一个新列,指示“new_ctg”列是否包含字母“f”。

熊猫:

要使用的函数非常简单。

cities["is_f"] = cities.new_ctg.str.contains("f")

城市数据框架(图片由作者提供)

潮水:

stringr 包的 str_detect 函数完成 pandas 的 contains 函数所做的事情。

cities <- mutate(cities, is_f = str_detect(new_ctg, "f"))

索引

字符串可以被认为是字符的集合。它们不必是单词或有意义的文本数据。例如,“foo123”是一个有效的字符串。

在数据操作中,对字符串进行索引或切片是一项非常实用的操作。我们可以通过提供索引来提取字符串的任何部分。pandas 和 tidyverse 都提供了基于字符索引提取部分字符串的功能。

让我们通过提取“ctg2”列的最后两个字符来创建一个新列。

熊猫:

我们可以从 0 开始传递索引,也可以从-1 开始传递索引。既然需要后两个,那就用最后面那个比较方便。

cities["sub_ctg2"] = cities.ctg2.str[-2:]

通过将相关索引传递给 str 访问器来指定所需字符串部分的开始和结束。起始索引是倒数第二个(-2)。结束索引留空以表示字符串结束。

潮汐

使用 str_sub 函数可以完成相同的操作,如下所示:

cities <- mutate(cities, sub_ctg2 = str_sub(ctg2, -2, -1))

适宜居住的城市(图片由作者提供)

长度和计数

在某些情况下,我们可能需要根据字符串包含的字符数来确定字符串的长度。特定字符在字符串中出现的次数也是一条有用的信息。

熊猫:

len 函数返回字符串的长度,count 函数返回字符在字符串中出现的次数。

# Length of citiescities.city.str.len()
0    10
1     9
2    10
3    10# How many "a" exists in city namescities.city.str.count("a")
0    0
1    2
2    1
3    2

Tidyverse:

这些功能的名称与熊猫中的功能非常相似。我们只需要在开头加上“str”。

# Number of occurrencesstr_count("Houston", "o")
[1] 2# Length of a stringstr_length("Houston")
[1] 7

结论

我们已经介绍了一些常用于操作字符串的基本操作。熊猫和 tidyverse 在执行这类任务时效率都很高。

还有许多操作可以用来操作或转换字符串。我认为我们在这篇文章中讨论的内容足以让你感到温暖。在后面的文章中,我计划用 pandas 和 tidyverse 演示更复杂的字符串操作。

感谢您的阅读。如果您有任何反馈,请告诉我。

电子商务需求的面板预测

原文:https://towardsdatascience.com/panel-forecasting-for-ecommerce-demand-3cb4d7c6f351?source=collection_archive---------8-----------------------

行业笔记

使用机器学习来更好地预测和理解数字市场

本文是哈佛大学 2021 年秋季 课程 AC297R 期末项目的一部分。

团队成员:siva Nanda Raja Nanda、Ryan Liu、David Assaraf、Junkai Ong

模式伙伴 :雅各布·米勒、汉密尔顿·诺尔

助教 :佐纳·科斯蒂克

导师 :克里斯·坦纳

问题描述

电子商务正在全球零售市场中占据主导地位。预测消费者行为的趋势非常重要,因为它们有助于为库存规划等关键业务提供信息。库存过多会导致不必要的财务支出和存储成本增加,而库存不足会导致潜在收入损失和消费者需求得不到满足。因此,准确预测需求以优化库存计划至关重要。

我们与电子商务加速器 Pattern 合作,创建了一个预测未来 8 周需求的面板预测模型。我们的模型的性能将与 28 天移动平均线模型进行比较,该模型用作基线模型。

数据

提供了从 2018 年 1 月到 2021 年 11 月每日产品销售业绩的数据集。该数据集包含大约 1150 万行,与 Amazon.com 的销售有关。数据集的字段包括假名供应商(品牌)代码、产品代码、地区、日期、单位销售、库存和购买量百分比。库存和购买箱百分比信息是内部跟踪的指标,有时可能会丢失。在亚马逊上有多个卖家出售同一产品的情况下,当买家购买产品时,购买框决定哪个卖家获得销售。购买箱百分比是根据模式每天估计的一个指标,该功能为需求预测增加了另一层复杂性,因为特定卖方的销售增长可能归因于该卖方更高的产品需求和/或更高的购买箱百分比。此外,库存信息可能对我们的预测有用,因为用完库存(缺货)会影响观察到的销售。

我们选择专注于美国地区的销售,因为大部分销售都在美国。

探索性数据分析

图 1:按日期排列的总单位数(图片由作者提供)

图 1 显示了整个数据范围内的每日单位总数。该图还显示,在每年的黄金日、黑色星期五和圣诞节前后,与大型销售活动相对应,销售量会出现峰值。因此,我们为某些假日创建了指示变量(参见后面的“特征工程”部分),以在我们的建模中考虑这些事件。在 Covid 疫情期间,我们看到了更多的销售波动。特别是,在 Covid 开始时有一个峰值(可能是由于对某些维生素和医疗保健产品的需求增加),在 2020 年下半年急剧下降并迅速恢复,在 2021 年期间销售相对稳定。

图 2:按日期排列的未购买框百分比(按作者排列的图片)

由于购买箱百分比信息可能对需求预测很重要,我们在图 2 中按日期显示了缺少购买箱百分比信息的观察的百分比。我们观察到,从 2018 年下半年开始,购买箱百分比指标变得更加一致。此外,似乎有几个日期的购买框从几乎所有的观察中消失了。

方法——概述

如下图所示,我们采用了三步法进行面板预测。对于数据清理,我们过滤掉非美国数据,并将其汇总到每周级别(以减轻每日波动的影响)。对于特征工程,我们创建了新的特征来捕捉潜在的信息。在建模中,我们探索了基线模型(即 28 天移动平均线)、XGBoost、不同的 LSTM 模型,并最终通过集合模型将它们全部结合起来。

图 3:面板预测的三步法(图片由作者提供)

方法——培训和评估方法

我们的评估标准是平均绝对误差(MAE ),它是针对每个预测周独立测量的。在评估过程中,我们还删除了基准(28 天移动平均线)为 0 的观察值,因为使用基准作为未来需求估计的人如果知道产品可能会有一些销售,可能不会预测 0 销售。

为了训练和评估模型,我们按日期分割训练、验证和测试数据:

  • 训练数据集:截至 2021 年 2 月 28 日
  • 验证数据集:2021 年 3 月 1 日至 2021 年 4 月 30 日
  • 测试数据集:2021 年 5 月 1 日起

我们利用验证数据集来调整每个模型的超参数。一旦超参数被调优,我们就在组合的训练集和验证集上进行训练,然后在测试集上评估性能。

我们有两种训练方法:

  1. 非在线培训。在非在线训练中,我们在测试数据集上计算模型预测的 MAE。
  2. 在线培训。在在线培训中,我们用测试集中每个新周的数据迭代更新我们的模型,以便预测下一组周的需求。这种方法(如图 4 所示)模拟了真实世界的环境,因为模型可以在生产中每周更新一次。

图 4:在线培训流程图(图片由作者提供)

数据处理、特征工程

我们设计了各种附加功能来补充原始数据集中提供的功能。针对之前 1、2、3、4、12、26、52 周的时间框架,计算销售单位的滚动汇总统计数据(即平均值、标准偏差、最小值、最大值、第 25 百分位、第 50 百分位和第 75 百分位指标),并将其添加到数据集中。因此,每一行不仅包含该周的销售数据,还包含前 4 周的信息。我们还计算了 12 周、26 周和 52 周时间范围内购买箱百分比的汇总统计数据。这些额外的信息将允许模型捕捉短期趋势,并检测本周数据中可能的异常。

基于时间的要素也被创建并添加到数据集中。对一周的开始日期进行简单的解析和操作,以设计诸如一月中的某一天、一年中的某一天、一月中的某一周、一年中的某一周、月和年等特征。为了提取品牌和产品的更多信息,我们还计算了自品牌首次出现在市场上以来的日志天数和自产品首次出现在市场上以来的日志天数。我们使用了对数变换,使特征的数据分布更接近高斯分布。这导致更紧凑的特征范围,从而实现更有效的神经网络训练。

自从产品最后一次销售以来的周数和最后一次销售的数量也被添加为特性。我们还添加了截至该日期每种产品的总销售量,作为长期历史销售业绩的指标。由于产品可能会遵循季节性周期,我们设计了一个包括上一年 2 周平均销售额(即本周之前 52–53 周的平均销售额)的功能。

由于从每日级别到每周级别的数据聚合,我们丢失了一些关于缺失值的信息。因此,该特定周的购买框和库存列中缺失值的数量也被添加到数据集中(这对于模型能够考虑缺货非常重要)。原始数据集中缺少的行(由于缺少销售额)也被计算并添加到数据集中。此外,由于假日和销售额的大幅增长之间存在明显的相关性,我们还设计了一个“假日指标”功能,该功能可以指示假日的购物期是否在我们希望预测的一周内。

为了利用具有相似销售趋势的产品的统计优势,我们基于训练数据中最近 52 周的单位销售执行了时间序列聚类。我们使用 3 种不同的聚类算法将产品分为 6 类:(1)欧几里德 k 均值聚类,(2)动态时间弯曲(DTW),以及(3) DTW 重心平均(DBA)。

建模

在基线模型(28 天移动平均线)之上,我们选择与不同的模型(即 XGBoost、LSTM、CNN-LSTM 和自回归 LSTM)合作,以利用它们的不同优势。众所周知,XGBoost 在某些预测任务上具有一流的性能,训练速度相对较快,并且可伸缩性非常好。LSTM 模型是为序列和时间序列数据制作的,因为它们能够处理不同长度的时间戳。然后,我们在最后将这些模型与一个集合模型(以随机森林回归的形式)相结合,以获得有利的结果。

我们从使用更小的数据子集开始,随着我们构建数据管道、训练我们的模型和调整我们的模型超参数,迭代地增加产品的数量。我们在下面更详细地描述了我们的模型和建模结果。

基线模型(28 天移动平均线)

基线模型是一个简单的 28 天移动平均线。这意味着,对于每种产品,提前 1-8 周的任意一周的预测需求是前 28 天售出数量的简单平均值。

为了直观显示基线模型在较高或较低流动性产品上表现更好,我们绘制了基线模型的相对绝对误差(|y_pred — y_true | / y_true)与产品流动性的关系图。图 5 显示,数据量和 28 天基线模型的性能之间似乎没有相关性。

图 5:28 天基线相对于产品流动性的表现(图片由作者提供)

下面是单个产品的基准模型预测的直观表示,比较了预测 1 周和未来 8 周的基准性能。在每个预测日期,28 天移动平均线用于预测接下来 8 周的销售额。我们观察到,这一基线在提前 1 周预测需求方面相当不错,但在前几周之后表现不佳,除非销售相当稳定。

图 6:单一产品的 28 天平均基线(图片由作者提供)

XGBoost

我们选择训练一个单独的模型来预测未来每周的需求。这种方法在计算上更容易,并允许我们更快地迭代,因为预测未来任何一周的全局模型都需要在内存中保存更大的数据集,并且训练起来更慢。此外,在预测未来特定时间范围的更窄任务上训练模型可能会导致更好的性能,因为该模型针对该任务进行了优化,而不是平衡跨时间段的性能。

使用默认超参数在我们的工程特性上训练的 XGBoost 模型能够击败基于前 3000 个产品的测试集的 MAE 的基准测试,参见下面的图 7。

XGBoost:超参数(HP)调整

我们对训练数据执行了网格搜索的多次迭代和交叉验证,以找到该预测任务的最佳超参数。对于每次迭代,搜索空间被缩小以精确定位要使用的最佳超参数。最终,通过搜索选择的超参数对前 3000 种产品的未调优 XGBoost 模型产生了更大的改进。

图 7:超参数调优的 XGBoost 性能(前 3000 种产品)(图片由作者提供)

XGBoost:在线培训

随后,我们进行了在线训练,并评估了我们的模型。在测试集中的每个星期之后,该模型在直到该星期的数据期间被重新训练。通过这种方式,模型将使用生产环境中可用的新信息进行更新,并且在预测日期不会使用未来的信息来训练模型。此外,这种方法更好地解释了数据的分布变化。如果测试数据与训练数据的分布不同(在这种情况下是正确的,因为销售通常在增加),那么更新模型将是必要的,以防止它在未来的进一步预测中变得过时。下图比较了有和没有在线培训的 XGBoost 模型的结果 MAEs。我们观察到,在线培训极大地提高了模型性能,尤其是在未来几周。

图 8:在线培训的 XGBoost 性能(前 3000 名产品)(图片由作者提供)

XGBoost:用于在线培训的不同时间长度

在线训练的一个相关超参数是在每个预测周期后使用多少数据来重新训练模型。换句话说,我们想要调查我们需要给模型多少周的过去数据来学习数据中的模式,所以我们设计了一个实验,在再训练期间用给模型的不同周的数据来执行在线训练。下面我们展示这个实验的结果。有趣的是,我们看到,虽然在更长的一段时间内重新训练模型提高了对近期预测的性能,但它往往会导致对未来更远时间的更差预测。对此的一个潜在解释可能是,越旧的数据变得越不相关,您需要预测的越远,因此将训练数据限制到更近的观测值可能有利于预测未来更远的时间。

图 9: XGBoost 在线培训绩效,按用于再培训的周数排列(图片由作者提供)

XGBoost:前 100 名产品

接下来,我们评估了我们的模型在前 100 种产品上进行训练时的性能。如下图所示,在对排名前 100 的产品进行评估时,我们的模型相对于基准测试的改进更加适度。

图 10:在线培训的 XGBoost 性能(前 100 名产品)(图片由作者提供)

XGBoost:预测 9 到 16 周

预测未来超过 8 周的需求可以帮助品牌了解生产量。因此,当提前 16 周预测时,我们评估我们的模型与基准相比的性能。我们观察到,通过在线培训,我们的模型相对于基准的改进随着提前周数的增加而增加。虽然基准和模型 MAE 都在增长,但模型 MAE 的增长速度比基准慢,因为它在预测中考虑了其他特征。

图 11:在线培训的 XGBoost 性能(图片由作者提供)

LSTM

我们探索了 LSTM 的 3 个关键设计,即:

  1. 普通 LSTM 。我们探索了常规 LSTM 的使用,它适用于基于时间序列的数据和应用,如面板需求预测。
  2. 美国有线电视新闻网-LSTM。在 LSTM 进行序列预测之前,CNN-LSTM 将利用 CNN 层来改进特征提取。
  3. 自回归 LSTM 。自回归 LSTM 将允许我们利用历史时间序列数据的自回归。

普通 LSTM 和 CNN LSTM 频道

为了了解以下因素对性能的影响,我们在常规 LSTM 和 CNN LSTM 频道上进行了以下实验。

常规 LSTM & CNN LSTM: 1 全球模特 vs 每周模特

我们探讨了 LSTM 的以下主要方法,即:

  1. 跨所有周和所有产品的 1 个 LSTM 模型(全球模型)
  2. 所有产品每周 1 个 LSTM 模型(每周模型)

下图总结了实验结果。

图 12:全球模型与每周模型的比较(图片由作者提供)

从上图可以看出,从第 1 周到第 7 周,周模型的性能优于全局模型。这可能是因为每周建模的 LSTM 允许它学习预测未来特定时间范围的更窄任务,这可能会导致更好的性能,因为该模型针对该任务进行了优化,而不是平衡各时间段的性能。

常规 LSTM 和 CNN LSTM:不同的 LSTM 输入序列长度

我们研究了在 LSTM 模型中改变输入序列长度对性能的影响。出于我们项目的目的,我们选择探索 2、6、10、14、18 的长度。结果如下图所示。

图 13:不同序列长度的常规 LSTM 的比较(图片由作者提供)

图 14:不同序列长度的 CNN LSTM 对比(图片由作者提供)

如上图所示,通常随着输入序列长度从 2 增加到 14,LSTM 的性能(就 MAE 而言)会提高。然而,当序列长度变为 18 时,我们注意到性能变得更差。这可能是因为虽然较长的输入序列长度允许 LSTM 更好地了解历史趋势,但当输入序列长度变得过长时,模型的训练会变得过于复杂,并且模型无法很好地拟合预测数据。

常规 LSTM 和 CNN LSTM:100 大产品

我们探究了常规的 LSTM 和 CNN LSTM 在 100 大产品上的表现。结果如下图所示。

图 15:常规 LSTM 百强产品的结果(图片由作者提供)

图 16:CNN-LSTM 100 强产品结果(图片由作者提供)

如上图所示,在预测前 100 种产品的需求时,常规的 LSTM 和 CNN-LSTM 都比没有在线培训的基准(28 天移动平均线)差得多。然而,常规的 LSTM 和 CNN-LSTM 都能够在在线培训后实现接近基准(28 天移动平均线)的 MAE 表现。这可能是因为在线训练允许用新数据更新先前训练的模型,从而提高其性能。

常规 LSTM 和 CNN LSTM:前 3000 名产品

我们探讨了常规 LSTM 和 CNN LSTM 对前 3000 名产品的表现。结果如下图所示。

图 17:常规 LSTM 3000 强产品的结果(图片由作者提供)

图 18:CNN LSTM 3000 强产品结果(图片由作者提供)

如上图所示,在预测前 3000 种产品的需求时,与前 100 种产品的需求相似,常规的 LSTM 和 CNN-LSTM 都比没有在线培训的基准(28 天移动平均线)差得多。

然而,在线培训后,常规的 LSTM 和 CNN-LSTM 都能够在 1-2 周内实现优于基准(28 天移动平均线)的 MAE 表现,而在 2 周后实现差于基准的 MAE 表现。这可能是因为在线训练允许用新数据更新先前训练的模型,从而提高其性能。

自回归 LSTM

我们选择实施自回归 LSTM (AR-LSTM),因为这可能是一个优雅的问题解决方案。AR-LSTM 为一种产品获取 10 个时间步长(即 10 周)的数据,然后预测第 11 周的销售量。由于许多特性取决于售出的单位,因此第 11 周的预测用于生成特性,作为第 12 周预测的输入。这种特性工程是在训练和测试期间动态进行的。

图 19:显示自回归 LSTM 过程的图表。(图片由作者提供)

由于 LSTM 无法处理 NaN 值,我们向前填充每个产品的值,然后用零填充剩余的 NaN(即在产品生命周期开始时没有先前数据的 NaN)。在评估期间,我们删除了这些填充的值,以确保模型不会根据填充的值进行评估。

图 20:前 100 名产品的结果(图片由作者提供)

图 21:3000 强产品的结果(图片由作者提供)

图 22:所有产品的结果(图片由作者提供)

我们在下面看到,AR-LSTM 的结果随着产品数量的增加而改善。人们可能会凭直觉认为,用更多产品训练的模型表现更好,因为它在大多数时候预测的值要低得多。但是,预测值和真实值的直方图显示,预测值的分布通常相互匹配。相反,它还表明该模型没有尽可能多地预测接近于零的值。这可能是由于损失函数是均方误差,并且较低的损失不会像较高的损失那样受到惩罚。

图 23:所有产品的预测直方图和预测标签(作者图片)

单个模型的结果汇总

下表总结了各个模型在预测前 100 名产品和前 3000 名产品方面的性能。

一般来说,与前 3000 个产品相比,我们的模型对前 100 个产品的改进更为适度。一种解释可能是,模型有更多的数据和产品可供训练,因此产品之间和品牌内部有更好的迁移学习。此外,另一个起作用的因素可能是,前 100 名中的这些高销量产品比低销量产品具有更稳定的销售,因此 28 天移动平均线是对这些产品未来需求的相当好的预测,因此基准预测更难改进。事实上,前 100 名产品基准的 MAEs 远低于前 3000 名产品的 MAEs,这意味着该基准是前 100 名产品与前 3000 名产品的更好预测器。

请注意,下表中以浅绿色突出显示的单元格代表特定一周的最低(即最佳)MAE。单个模型的预测将在下一步被输入到集合模型中,以结合我们不同模型的优势。

表 1:前 100 名产品的结果(图片由作者提供)

表 2:3000 种顶级产品的结果(图片由作者提供)

集合模型

我们方法的最后一步是结合不同模型的优势。在这个时间点,我们有 4 个不同的模型在每个时间步产生 4 个不同的预测,我们希望有一个统一的方法来组合各种预测。拥有一个集成学习方法将允许我们拥有一个集中的预处理、训练和微调 API。此外,由于一些模型在时间序列之间的迁移学习方面比其他模型更强——我们可以在跨模型比较前 100 名产品和前 3000 名产品的性能时看到这一点——组合不同的模型将是有帮助的。

我们希望集合模型能够缩小某个模型优于另一个模型的情况。因此,我们希望不同模型的“权重”是动态的。

从非动态聚合模型切换到动态聚合模型:

( 图片作者)

因此,第一步将是在 0 级模型(即下面描述的“聚集模型”)的不同预测上训练元模型,并添加一些元特征以给出关于我们正在预测的当前点的一些元信息(关于该方法的详细描述,请参考特征加权线性叠加,Sill 等人)。

第二步是选择我们想要使用的实际元模型。通常的方法是利用线性模型的可解释性。然而,线性模型的基本假设是不同的预测因子是相互独立的。因此,分配给不同的 0 级模型的权重不能依赖于当前时间。因此,我们决定使用随机森林模型。最后,我们也将使用黑盒解释方法来推断集合模型是如何做出预测的。

元特性:我们使用的元特性被称为‘元’,因为我们不希望它们包含任何定量信息,例如它们只包含当前季节、年份、产品和供应商的信息。使用这些元特征,我们期望随机森林(RF)分类器能够拾取不同的模型。

聚合模型:我们利用来自以下模型的预测:Tuned XGBoost、AR-LSTM、LSTM、CNN LSTM 和 Benchmark。

培训程序:对于这一步,我们设计了 2021 年 3 月 1 日的培训-验证拆分和 2021 年 5 月 1 日的验证-测试拆分。我们设计了两种不同的培训程序,一种用于非在线培训(nOT ),一种用于在线培训(OT)。

  • 非在线训练:0 级模型首先在训练集上进行训练,然后在验证集上进行预测。然后,我们在训练+验证上重新训练,并在测试集上预测。然后,元模型在验证集上被训练,并在测试集上被测试。
  • 在线训练 :首先在训练集上对 0 级模型进行训练,然后在验证集上进行预测。然后,我们再培训那些培训+验证。元模型已经在验证集上进行了训练。然后,0 级模型都在测试集上进行在线训练,元模型在不同的 0 级模型之上进行在线训练。

调谐程序:

  • 消融研究 :为了仅在“强”模型上训练元模型,我们执行消融研究,以便在对整个测试集进行 1 周到 8 周的预测时,仅从模型中选择对降低整体 MAE 有显著贡献的预测。这个过程是在验证集上运行的,我们将验证集分成两部分(并用来自训练集的数据填充训练部分)。
  • 嵌入式超参数(HP)调整 : 随机森林分类器模型的每一次训练都利用了对 4 个关键超参数的超参数调整:树的数量、生长的树的最大深度、分裂节点的最小点数和叶子中的最小点数。超参数调整过程利用贝叶斯优化(BO)来加速该过程并更有效地搜索参数空间。

集合模型:前 100 名产品

  • 消融研究:在 160,000 种组合中,我们可以尝试约 40,000 种组合,并选择预测因子的最佳子集。所选择的特征是 prediction_XGBoost、prediction_CNNLSTM、vendor_name_encoded、自品牌发布以来的时间、基准和一些其他时间特征。这一步骤有助于显著降低 MAE。
  • 嵌入式超参数调整:贝叶斯优化算法探索了插入的 max_depth 和 min_sample_split 范围的下端。树的数量是我们指定的一组离散值。

图 24:惠普调优仪表板的可视化(图片由作者提供)

表 3:消融研究和嵌入式惠普调整后前 100 名产品的整体模型结果(图片由作者提供)

如上面的表 3 所示,集合模型在所有预测周内都明显优于所有其他模型。这证实了我们的直觉,即集合模型能够获得不同产品和供应商的不同模型的不同优势。具有在线培训、消融研究和 HP 调整的集合模型是产生最佳结果的模型。

集合模型:前 3000 名产品

使用前 3000 种产品运行管道的计算成本更高,因此无法进行全面的消融研究或惠普调整程序。这里,结果使用所有 20 个特征和随机森林分类器的默认超参数。

**表 4:前 3000 种产品的整体模型结果,无消融研究,无嵌入式惠普调整(图片由作者提供)

这里要观察的一点是,前 3000 个产品上的默认集合模型(非在线训练)优于前 100 个产品上的优化模型(非在线训练)。对于前 100 名产品的模型,采用嵌入式 HP 调整的消融研究显著提高了分类器的性能。因此,我们相信,在排名前 3000 的产品上以正确的方式调整集合模型将会产生更好的结果。

集合模型解释 : 如前所述,我们故意使用不可解释的模型,以便预测依赖于所有特征的值。然而,随机森林模型并不受益于可解释的机制。因此,我们使用了 SHAP 模型,一个统一的方法来解释模型预测,伦德伯格等人。艾尔。,以便了解执行预测时使用了哪些特征。在这里,我们将 SHAP 模型用于前 100 名产品的集合模型、消融后研究和超参数调整后。

**图 25:100 强模型的全球 SHAP 值结果(图片由作者提供)

SHAP 值背后的直觉是,给定要预测的实例 x,我们训练局部线性模型来近似我们的(黑盒,这里是随机森林)模型的输出:

( 图片作者)

图 25 中的图是整个训练集的所有 SHAP 值的集合,其中不同的特征按照特征重要性排序(参见 Lundberg 等人。艾尔。对特征重要性的定义)。我们可以从这个数字中得出一些结论:

  1. 随机森林最重要的特征是基准。这抓住了我们的直觉:即使我们构建了不同的模型来预测未来的价值,基准模型将始终“产生”非常接近实际价值的结果。
  2. CNN-LSTM 的预测比 XGboost 的预测用得多。这表明,在这种情况下,CNN-LSTM 能够更有效地获取前 100 名产品的需求。
  3. 编码的供应商名称具有很高的特性重要性,这意味着当删除时,性能会显著下降。这证实了我们最初的观点,即随机森林模型比不同的模型具有更强的性能,因为它了解模型对于不同产品和品牌的优势。
  4. 实施的不同模型以正确的方式捕捉了趋势:当它们的值低时,它们的 Shapley 值是负的。这意味着当模型的输出与其平均值相比较低时,其预测对缺口 y(x,t)- y 的影响是负的;这将降低输出的价值。

未来的工作

在我们的项目结束后,我们项目的下一步包括以下内容。

在这个项目中,我们实现了前 3000 种产品的面板预测模型。对于项目的下一个开发阶段,我们可以将其扩展到包括整个产品集的预测,以使模型更加全面。

此外,针对整体模型,我们对前 100 种产品进行了全面的消融研究和超参数调整。在项目的下一阶段,我们可以将其扩展到前 3000 个产品,并随后扩展到整个产品集。这将有可能让我们在更全面的产品组合中实现出色的表现。

参考文献

南任、崔天凯、刘,“基于面板数据的粒子滤波模型在服装销售预测中的应用”,载于《IEEE 系统、人与控制论汇刊:系统》,第 45 卷,第 3 期,第 411-421 页,2015 年 3 月,doi:10.1109/台积电,2014 年 12 月。40316.63636363616

R.Ghanbari 和 K. Borna,“使用 LSTM 神经网络的多变量时间序列预测”,2021 年第 26 届国际计算机会议,伊朗计算机学会(CSICC),2021,第 1–5 页,doi:10.1109/csicc 52101 . 53686766676

Y.王,郭,“基于和 XGBoost 混合模型的股市波动时间序列预测方法”,载《中国交通》,第 17 卷第 3 期,第 205-221 页,2020 年 3 月,doi: 10.23919/JCC.2020.03.017

J.Sill,G. Takacs,L. Mackey 和 D. Lin,“特征加权线性叠加”,arXiv.org,2019 年 11 月,arXiv: 0911.0460

南 Lundberg,S. Lee,“解释模型预测的统一方法”,arXiv.org,2017 年 11 月,arXiv: 1705.07874

论文解释:视觉表征对比学习的简单框架

原文:https://towardsdatascience.com/paper-explained-a-simple-framework-for-contrastive-learning-of-visual-representations-6a2a63bfa703?source=collection_archive---------4-----------------------

查看 SimCLR 论文中提出的观点

在这个故事中,我们将看看 SimCLR:在视觉任务的自我监督预训练中,将计算机视觉研究社区引向新高度的架构。

SimCLR 在 2020 年来自 Google Research 的陈等人的论文 【视觉表征对比学习的简单框架】中提出。本文中的思想相对简单和直观,但也有一个新颖的损失函数,这是实现自我监督预训练的良好性能的关键。我尽量让文章简单,这样即使没有什么先验知识的读者也能理解。事不宜迟,我们开始吧!

SimCLR 训练程序的说明。来源:【1】

先决条件:计算机视觉的自我监督预培训

在我们深入研究 SimCLR 白皮书之前,有必要快速回顾一下自我监督的预培训到底是怎么回事。如果你一直在阅读我的其他自我监督学习的故事,或者你熟悉自我监督预培训,请随意跳过这一部分。

传统上,计算机视觉模型总是使用监督学习来训练。这意味着人类看着这些图像,并为它们创建了各种各样的标签,这样模型就可以学习这些标签的模式。例如,人类注释者可以为图像分配一个类标签,或者在图像中的对象周围绘制边界框。但是,任何接触过标注任务的人都知道,创建足够的训练数据集的工作量很大。

相比之下,自我监督学习不需要任何人为创造的标签。顾名思义,模特学会自我监督。在计算机视觉中,对这种自我监督进行建模的最常见方式是获取图像的不同裁剪或对其应用不同的增强,并通过模型传递修改后的输入。尽管图像包含相同的视觉信息,但看起来并不相同,我们让模型知道这些图像仍然包含相同的视觉信息,即相同的对象。这导致模型学习相同对象的相似潜在表示(输出向量)。

我们可以稍后在这个预训练的模型上应用迁移学习。通常,这些模型然后在 10%的带有标签的数据上进行训练,以执行下游任务,如对象检测和语义分割。

用 SimCLR 学习图像相似度

这篇论文的一个重要贡献是使用了数据扩充。SimCLR 创建成对的图像来学习相似性。如果我们两次输入相同的图像,就不会有学习效果。因此,每对图像都是通过对图像应用放大或变换来创建的。

不同的数据增强应用于狗的图像。来源:【2】

从这篇论文的摘录中可以看出,作者应用了不同的增强,如调整大小、颜色失真、模糊、噪声等等。他们还从图像的不同部分获取作物,这对模型学习一致的表示很重要。可以将图像裁剪成全局和局部视图(完整图像和图像的裁剪部分),或者可以使用相邻视图(从图像的不同部分进行两次裁剪)。每一对被公式化为正对,,即两个增强图像包含相同的对象。

接下来,这些对被传递到卷积神经网络中,以创建每个图像的特征表示。在论文中,作者选择使用流行的 ResNet 架构进行实验。成对的图像总是成批地提供给模型。特别强调的是批量的大小,作者从 256 到 8192 不等。从该批次开始,应用数据扩充,导致批次大小加倍,因此从 512 到 16382 个输入图像。

一旦 ResNet 计算出输入图像的矢量表示,该输出将被传送到投影头进行进一步处理。在本文中,这个投影头是一个带有一个隐藏层的 MLP。该 MLP 仅在训练和进一步细化输入图像的特征表示期间使用。

从原始输入图像到由 MLP 计算的表示的 SimCLR 训练过程。来源:【1】

一旦 MLP 计算完成,结果保留为损失函数的输入。sim clr 的学习目标是使同一图像的不同增强之间的一致性最大化。这意味着模型试图最小化包含相同对象的图像之间的距离最大化包含非常不同的对象的图像之间的距离。这种机制也被称为对比学习

SimCLR 论文的一个主要贡献是制定了其 NT-Xent 损失。NT-Xent 代表归一化温度标度交叉熵损失。这个新颖的损失函数具有一个特别理想的性质:不同的例子被有效地加权允许模型从彼此远离的矢量表示中更有效地学习,即使它们的原点是相同的图像。这些模型认为彼此非常不同的例子被称为硬否定

这种损失有效地实现了相似图像的吸引,即,相似图像被学习为更紧密地映射在一起。

相似的图像相互吸引。来源:【1】

结果

一旦网络被完全训练,MLP 投影头被丢弃,仅卷积神经网络被用于评估。在他们的论文中,作者进行了不同的评估:

首先,他们在 ImageNet 数据集上测量 SimCLR 作为线性分类器的性能。他们的结果显示 SimCLR 执行所有其他自我监督的方法

SimCLR 和其他自监督方法对 ImageNet 线性分类的结果。来源:【2】

请记住,这些结果不再是最新的,因为具有更好性能的新方法已经出现。请随意阅读我的其他文章,在那里我回顾了其他自我监督的预培训模型。

其次,他们评估了 SimCLR 在不同图像数据集上的性能,对比了使用标签训练相同的 ResNet,即使用监督学习。同样, SimCLR 表现非常好,在许多数据集上击败了监督训练方法。在同一张表中,他们还查看了用标记数据微调自我监督模型的结果。在这一行中,他们表明 SimCLR 在几乎所有数据集上的表现都优于监督训练方法

评估 SimCLR 与 ResNet 的监督培训。来源:【2】

包装它

在本文中,您了解了 SimCLR,这是一篇最流行的自我监督框架,概念简单,结果有希望。SimCLR 在不断改进,甚至还有这种架构的第二个版本。虽然我希望这个故事能让你对这篇论文有一个很好的初步了解,但是还有很多东西需要发现。因此,我会鼓励你自己阅读这篇论文,即使你是这个领域的新手。你必须从某个地方开始;)

如果你对论文中介绍的方法有更多的细节感兴趣,请随时在 Twitter 上给我留言,我的账户链接在我的媒体简介上。

我希望你喜欢这篇论文的解释。如果你对这篇文章有任何意见,或者如果你看到任何错误,请随时留下评论。

最后但同样重要的是,如果你想在高级计算机视觉领域更深入地探索,考虑成为我的追随者。我试着每周发一篇文章,让你和其他人了解计算机视觉研究的最新进展。

参考资料:

[1] SimCLR GitHub 实现:【https://github.com/google-research/simclr

[2]陈,丁等:“视觉表征对比学习的一个简单框架。”机器学习国际会议。PMLR,2020 年。https://arxiv.org/pdf/2002.05709.pdf

论文解释:DINO——自监督视觉变压器中的新兴特性

原文:https://towardsdatascience.com/paper-explained-dino-emerging-properties-in-self-supervised-vision-transformers-f9386df266f1?source=collection_archive---------5-----------------------

用于自我监督学习的高级视觉转换器

在这个故事中,我很乐意给你一个关于 DINO paper 如何工作的好主意,以及是什么让它如此伟大。我尽量让文章简单,这样即使没有什么先验知识的读者也能理解。

迪诺的注意力被想象成树上的一只猴子。来源:【2】

传统上,视觉变压器(ViT)并不像一些人预期的那样有吸引力:它们有很高的计算要求,需要更多的训练数据,并且它们的特征没有表现出独特的属性。在他们 2020 年的论文“自我监督的视觉变压器中的新兴特性”中,Caron 等人旨在研究为什么监督的 ViT 尚未起飞,以及是否可以通过对它们应用自我监督的学习方法来改变这种情况。

传统上,计算机视觉模型,例如卷积神经网络,总是在人类监督下训练。这意味着人类必须为训练数据创建标签,比如告诉模型图像中有一只狗。

自我监督学习允许它在没有任何标签的情况下训练模型。因此,在计算机视觉任务的情况下,只有图像被输入模型,网络本身学习理解它周围的视觉世界

事实证明,将自我监督应用于视觉变压器会产生以下理想的特性:

  • 该模型学习从语义上分割对象并创建边界。该信息可在自我关注模块中获得。我们稍后会谈到什么是自我关注。

来自 DINO 的关注显示了该模型可以多么令人印象深刻地专注于图像的最相关部分。这也用作场景的无监督语义分割。来源:【1】

  • 学习到的特征表示,即模型的输出向量,对于执行聚类非常有用。此外,应用 k-最近邻分类器导致一些令人印象深刻的分类结果

迪诺以自我监督的方式学习集群。在训练过程中没有使用标签。来源:【2】

迪诺如何工作

迪诺采用了一种叫做自我蒸馏的方法。这也是这个名字的由来:Self-distillation withnolabels(或者他们只是想构造一个朗朗上口的名字)。

自我升华创造了一个教师和学生网络。这两个网络的模型架构完全相同。DINO 的一个很大的优点是它在这一点上完全灵活:可以使用 ViT 或 ConvNet,比如流行的 ResNet-50。

迪诺前进训练过程的简单概述。一幅图像被裁剪成两种尺寸,并传送给学生和教师网络。对教师的输出应用居中操作,并且两个输出都通过 softmax 层馈送。来源:【2】

在模型的正向训练阶段,创建图像的不同裁剪。作物 1 通过学生网络提供,而作物 2 通过教师网络提供。与来自学生网络的输出相反,对教师网络的输出应用居中操作。接下来,使用 softmax 函数对两个网络的输出进行归一化。

为了反向传播模型并更新参数,定义了交叉熵 损失

两个 softmax 输出都被传递到损失函数中,使用随机梯度下降(SGD)执行反向传播。之后,使用指数移动平均(EMA)将学生网络的模型参数转移到教师网络。来源:【2】

两个 softmax 输出都馈入损失函数。对于训练,模型通常处理多个图像,在这种情况下,可能是 2 个较大的作物和 4 个较小的作物。这种损失可以同时应用于所有视图。一旦计算出损失,使用随机梯度下降 (SGD)执行反向传播,目标是最小化交叉熵。反向传播是通过学生网络执行的,这就是为什么教师的权重还没有更新。为了更新教师模型,DINO 对学生权重使用指数移动平均(EMA),即动量编码器

简而言之,这就是训练程序。在我们看一些结果之前,让我们快速看一下这篇论文使用了什么模型。

用于 DINO 的网络体系结构概述。来源:【1】

正如我们将在结果中看到的,DINO 与 ViT 一起使用时效果最佳,特别是 ViT-B/8 效果最佳。但是,如前所述,DINO 也可以与传统的 ConvNet 一起使用。

结果

为了应用该模型,作者以 3 层多层感知器(MLP)的形式在变压器的顶部添加了投影头。虽然它们提供了各种各样的结果,但我想把重点放在我认为最相关的结果上。

ImageNet 上的线性和 k 近邻分类

在我看来,最相关的是将 k-最近邻分类器应用于训练特征呈现时的分类性能。如本文介绍所示,恐龙集群不同班级成绩斐然。这又是那个图表:

迪诺创造的集群。来源:【2】

巨大的分离清晰可见,代表相似物体的星团彼此更加接近。这具有难以置信的含义。这意味着分类可以在没有标签监督的情况下,仅通过自我监督的预训练,以高精度完成。此外,DINO 对于线性分类似乎工作得很好。如需了解更多详情,请参见下表,其中作者将 DINO 与其他最先进的自我监督预训练方法进行了比较:

与其他自我监督预训练方法的性能比较。对于 ImageNet 上的线性和 k-NN 分类任务,DINO 优于所有这些方法。来源:【1】

高度精确的注意力和完全无监督的语义分割

视觉上最令人印象深刻的当然是由自我注意机制产生的分割结果。就像人类一样,模型聚焦于场景中的相关物体,即使船只被遮挡。虽然没有在本文中进行定量评估,但这种可视化提供了模型过程的更透明的视图,并增加了对其能力的信心。

迪诺对这艘船的关注可视化了。来源:【2】

包装它

在本文中,您已经了解了 DINO,这是一篇在《视觉变形金刚》中利用自我监督学习的论文。虽然我希望这个故事能让你对这篇论文有一个很好的初步了解,但是还有很多东西需要发现。因此,我会鼓励你自己阅读这篇论文,即使你是这个领域的新手。你必须从某个地方开始;)

如果你对论文中介绍的方法有更多的细节感兴趣,请随时在 Twitter 上给我留言,我的账户链接在我的媒体简介上。

我希望你喜欢这篇论文的解释。如果你对这篇文章有任何意见,或者如果你看到任何错误,请随时留下评论。

最后但同样重要的是,如果你想在高级计算机视觉领域更深入地探索,考虑成为我的追随者。我试着每周发一篇文章,让你和其他人了解计算机视觉研究的最新进展。

参考资料:

[1]https://ai . Facebook . com/blog/dino-paws-computer-vision-with-self-supervised-transformers-and-10x-more-efficient-training/

[2]卡隆,玛蒂尔德等,“自我监督的视觉变形金刚的新兴特性” arXiv 预印本 arXiv:2104.14294 (2021)。https://arxiv.org/pdf/2104.14294.pdf

链接到 GitHub 库:https://github.com/facebookresearch/dino

论文解释:屏蔽自动编码器是可伸缩视觉学习器

原文:https://towardsdatascience.com/paper-explained-masked-autoencoders-are-scalable-vision-learners-9dea5c5c91f0?source=collection_archive---------8-----------------------

重建图像中被遮蔽的部分是如何有益的

自动编码器在自然语言处理任务方面有着成功的历史。伯特模型开始在句子的不同部分屏蔽单词,并试图通过预测要填入空格的单词来重建完整的句子。最近的工作旨在将这一想法转移到计算机视觉领域。

在这个故事中,我们将看看最近发表的论文 “掩蔽的自动编码器是可扩展的视觉学习者” 何等人从 2021 年开始。明凯·何是计算机视觉领域最具影响力的研究人员之一,他与 Meta AI Research 的其他研究人员一起取得了 ResNet、fast R-CNN 和 Mask R-CNN 等突破性进展。在他们的最新论文中,他们提出了一种新的方法,使用自动编码器对计算机视觉模型,特别是视觉变压器进行自我监督的预训练。

屏蔽自动编码器训练管道的高级可视化。来源:【1】

在我们深入研究他们提出的方法之前,重要的是我们要快速回顾一下自我监督的预训练,以正确设置环境。如果你已经熟悉自我监督的预备培训,可以跳过这一部分。我尽量让文章简单,这样即使没有什么先验知识的读者也能理解。事不宜迟,我们开始吧!

先决条件:计算机视觉的自我监督预培训

在我们深入讨论之前,有必要快速回顾一下自我监督预培训是怎么回事。如果你熟悉自我监督的预备培训,可以跳过这一部分。

传统上,计算机视觉模型总是使用监督学习来训练。这意味着人类看着这些图像,并为它们创建了各种标签,这样模型就可以学习这些标签的模式。例如,人类注释者可以为图像分配一个类标签,或者在图像中的对象周围绘制边界框。但是,任何接触过标注任务的人都知道,创建足够的训练数据集的工作量很大。

相比之下,自我监督学习不需要任何人为创造的标签。顾名思义,模型学会自我监督。在计算机视觉中,对这种自我监督进行建模的最常见方式是获取图像的不同裁剪或对其应用不同的增强,并通过模型传递修改后的输入。尽管图像包含相同的视觉信息,但看起来并不相同,我们让模型知道这些图像仍然包含相同的视觉信息,即相同的对象。这导致模型学习相同对象的相似潜在表示(输出向量)。

我们可以稍后在这个预训练的模型上应用迁移学习。通常,这些模型然后在 10%的带有标签的数据上进行训练,以执行下游任务,如对象检测和语义分割。

使用掩蔽使自动编码器理解视觉世界

这篇论文的一个关键创新已经包含在标题中:图像的屏蔽。在将图像输入编码器转换器之前,会对其应用一组特定的遮罩。这里的想法是从图像中移除像素,从而为模型提供一个不完整的图片。这个模型的任务是学习完整的原始图像是什么样子的。

在左边,可以看到被屏蔽的图像。在右边,显示原始图像。中间一栏显示了自动编码器重建的图像。来源:【1】

作者发现非常高的掩蔽比是最有效的。在这些例子中,他们用遮罩覆盖了 75%的图像。这带来了两个好处:

  1. 训练模型的速度提高了 3 倍,因为它需要处理的图像补片要少得多
  2. 由于模型必须彻底地从图像中学习视觉世界,因此精确度增加了

遮罩总是随机应用的,因此同一图像的多个版本可以用作输入。

既然已经对图像进行了预处理,让我们来看看模型架构。在他们的论文中,何等人决定采用非对称编码器设计。这意味着他们的编码器可以更深,而他们选择一个相当轻量级的解码器。

编码器将图像划分为分配了位置编码的面片(即上面图像中的正方形),并且只处理图像中未被遮罩的部分。编码器的输出是输入图像块的潜在矢量表示。

编码器接收未掩蔽的图像补片并输出潜在向量表示的可视化。来源:【1】

在此之后,引入掩模标记,因为下一步是解码器重建初始图像。每个掩码标记都是一个共享的学习向量,用于指示缺失补丁的存在。再次应用位置编码来与解码器进行通信,其中各个补片位于原始图像中。

解码器接收潜在表示以及掩模标记作为输入,并输出包括掩模在内的每个补片的像素值。根据这些信息,可以将原始图像拼凑在一起,以从用作输入的掩蔽图像形成完整图像的预测版本。

从掩蔽的输入图像的潜在表示到重建的目标图像的解码过程。来源:【1】

在蓝色潜在向量计算之后添加掩码标记是一个重要的设计决策。它减少了编码器到达矢量输出的计算成本,因为它必须处理更少的面片。这使得模型在训练期间更快。

一旦目标图像被重建,它与原始输入图像的差异被测量并被用作损失。

重建图像与原始图像的比较。来源:【1】

在模型被训练之后,解码器被丢弃,只有编码器,即视觉变换器,被保留以供进一步使用。它现在能够计算图像的潜在表示,以便进一步处理。

现在我们已经讨论了论文介绍的方法,让我们看看一些结果。

结果

由于屏蔽自动编码器使用变压器,因此作者将其性能与其他基于变压器的自监督方法进行比较是有意义的。他们的改进表现在第一次比较中:

使用 ImageNet-1K 上的微调结果进行预训练。来源:【1】

在与其他方法的比较中,当在 ImageNet-1K 上预训练模型,然后端到端地微调它时,MAE (masked autoencoder)显示出比其他方法(如 DINO 、MoCov3 或 BEiT)更好的性能。即使随着模型尺寸的增加,改进也保持稳定,使用 ViT-H(巨大的视觉转换器)时性能最好。MAE 达到了令人难以置信的 87.8 的准确度。

这种表现也适用于下游任务的迁移学习:

迁移学习在不同变压器预训练方法中的应用。这些结果用于 COCO 检测和分割数据集。来源:【1】

当使用预训练的变换器作为在 MS COCO 检测和分割数据集上训练的掩模 R-CNN 的主干时,MAE 再次优于所有其他基于变换器的方法。它实现了令人难以置信的 53.3 AP(平均精度)的盒子。掩模 R-CNN 还输出对象的分割掩模。在这次评估中,MAE 再次以面膜高达 47.2 AP 的成绩高居所有其他方法之首。该方法甚至优于 Mask R-CNN 的完全监督训练,再次显示了自我监督预训练的益处。

包装它

在本文中,您已经了解了 masked autoencoders (MAE ),这是一篇利用变压器和自动编码器进行自我监督预训练的论文,并为自我监督预训练工具箱添加了另一个简单但有效的概念。在某些任务上,它甚至优于完全监督的方法。虽然我希望这个故事能让你对这篇论文有一个很好的初步了解,但是还有很多东西需要发现。因此,我会鼓励你自己阅读这篇论文,即使你是这个领域的新手。你必须从某个地方开始;)

如果你对论文中介绍的方法有更多的细节感兴趣,请随时在 Twitter 上给我留言,我的账户链接在我的媒体简介上。

我希望你喜欢这篇论文的解释。如果你对这篇文章有任何意见,或者如果你看到任何错误,请随时留下评论。

最后但同样重要的是,如果你想在高级计算机视觉领域更深入地探索,考虑成为我的追随者。我试着每周发一篇文章,让你和其他人了解计算机视觉研究的最新进展。

参考资料:

[1]何,,等,“蒙版自动编码器是可伸缩的视觉学习者。” arXiv 预印本 arXiv:2111.06377 (2021)。https://arxiv.org/pdf/2111.06377.pdf

论文解释:通过用支持样本非参数预测视图分配的视觉特征的半监督学习

原文:https://towardsdatascience.com/paper-explained-semi-supervised-learning-of-visual-features-by-non-parametrically-predicting-view-1fcbf91517a0?source=collection_archive---------33-----------------------

利用标记支持样本进行半监督学习

在这个故事中,我们将进一步了解 PAWS ( p 预测视图 a 分配wwiths支持标签),这是一种将半监督学习应用于计算机视觉问题的新方法。

该方法已作为 Assran 等人在 2021 年 ICCV 大会上发表的论文 “通过支持样本的非参数预测视图分配的半监督学习”的一部分。与我写过的一些其他论文相比,这种方法允许有限地使用标记数据,只将这些信息投射到更大的未标记数据池中进行学习。因此,标记的数据变得比在完全监督下训练模型更有价值。和往常一样,我试图保持文章的简单,这样即使没有什么先验知识的读者也能理解。事不宜迟,我们开始吧!

PAWS 训练过程的简化可视化。最值得注意的是,标签与支持样本一起被引入训练过程。来源:【1】

先决条件:自我监督与半监督学习

一个重要的区别是自我监督和半监督学习之间的区别。

当以自我监督的方式训练模型时,监督不是来自标记的数据。更确切地说,这个模型,顾名思义,是自我监督的。这种监管会是什么样的?简而言之,可以向模型提供应用了不同数据增强的相同图像,目标是了解图像仍然是相同的。这样,学习过程就有了指导。

相比之下,半监督学习确实依赖于标记数据,但很少。当使用传统的监督训练方法时,所有数据都必须被标记。半监督模型仅使用一小部分标记数据,并提取标签来推理和学习未标记的训练数据。这在本文中变得更加清楚。

从少量标记图像中学习

在过去,有监督的计算机视觉模型总是在 ImageNet 数据上进行评估。为了执行评估,仅使用标记的图像在数据集上训练模型。PAWS 只有 1%或 10%的标签可用于训练,但仍然取得了令人难以置信的性能。我们来看看为什么!

首先,每个图像被随机增强以形成两个视图:锚视图和正视图。虽然图像的内容仍然是相同的,例如它包含一只狗,增强现在已经扭曲了它的视觉表现,即它们看起来不同

数据扩充的一个例子。右边是原始图像,左边是增强图像。来源:【2】

现在使用卷积神经网络对同一图像的这两个视图进行编码,在这种情况下是 ResNet-50。该网络将每幅图像作为输入,并输出其矢量表示。在自我监督学习中,我们现在将在同一图像的两个视图之间公式化相似性损失或类似的东西。但是在半监督学习中,在任何损失函数被公式化以从这些输出中学习之前,我们可以从我们可用的标记图像中受益

在本文中,带标签的图像称为支持样本。这些被标记的支持样本也被编码,使用相同的 ResNet-50 来为它们中的每一个形成向量表示。

形成输入图像的矢量表示的编码器的图示。来源:【3】

现在我们已经有了带有标签的矢量表示,我们可以使用它们来衡量它们与锚和正图像编码的相似性。这通过使用所谓的软最近邻策略来实现。这意味着锚和正视图根据它们与其中一个支持样本的相似性进行分类,并且它们被分配一个软伪标签,即具有最小距离的支持样本的标签。

整个训练过程可视化了。条形图前面的箭头表示软最近邻分类器。来源:【3】

既然已经为正视图和锚视图生成了软伪标签,则计算它们之间的交叉熵作为损失项的公式。

注意,为了防止学习崩溃,温度参数被引入到最近邻分类器中,而且被引入到显示在图示右下角的目标预测中。在这种情况下,温度参数充当锐化工具。简单来说,在输出分配中,高值变得更高,低值变得更低,增加了它们之间的对比度。这使得学习目标更接近于一次性编码(标签被编码成 0 和 1 的数组)。

至此,我们将结束对本文背后技术的简短概述。现在,让我们来看看一些结果!

结果

如前所述,与自我监督学习相比,半监督学习可以利用标签形式的信息来学习理解周围的视觉世界。作为评估的一部分,在预训练期间,1%或 10%的 ImageNet 训练数据被标记为 paw。所有方法都在没有监督的情况下进行训练,然后使用 10%的标记 ImageNet 数据进行微调。这使得 PAWS 的第一个优点相当直观。

PAWS 与 Top 1 ImageNet 分类的其他预训练技术的比较。来源:【3】

第一个图表显示 PAWS 在这个分类基准上表现得更好,训练更少,因为它的训练数据信息更丰富。因此,在训练期间使用标签取代了诸如 SwAV 或 SimCLRv2 所要求的长训练时间。这是有意义的,因为 SwAV,一种自我监督的方法,必须在没有任何人类帮助的情况下找出一个良好的视觉世界模型,而 PAWS,在这种情况下,使用 10%的数据和标签。

将 PAWS 的表现与其他预训练技术进行比较的表格。所有模型都使用 ResNet-50,并在其他 1%或 10%的标记上进行微调,除了 PAWS-NN,它在学习的嵌入上使用最近邻分类。来源:【3】

与其他预训练方法相比,PAWS 的性能优势是真实的,也是最先进的自我监督预训练。通过使用 1%或 10%的标记 ImageNet 数据作为支持样本,PAWS 能够以更少的训练时期胜过所有这些。更令人印象深刻的是在 PAWS-NN 下看到的结果。为此,没有对 PAWS 进行微调,所有图像都基于其原始输出嵌入的最近邻分类进行分类。这是了不起的,显示了半监督训练的真正潜力。

这表明以标签的形式提取的人类知识,当被正确地整合时,可能是极其强大的。如与自我监督学习相比更低的训练时间所示,通过让人类辅助学习过程,人工神经网络可以更有效地理解信息。从某种意义上说,这是两个神经网络一起工作。一个生物的,一个人工的。

包装它

在本文中,您已经了解了 PAWS,这是一篇使用半监督学习从少数标记图像中获利并将该知识转移到所有其他未标记图像的论文。这已经显示出期望的特性,例如更少的预训练时间和更好的性能。虽然我希望这个故事能让你对这篇论文有一个很好的初步了解,但是还有很多东西需要发现。因此,我会鼓励你自己阅读这篇论文,即使你是这个领域的新手。你必须从某个地方开始;)

如果你对论文中介绍的方法有更多的细节感兴趣,请随时在 Twitter 上给我留言,我的账户链接在我的媒体简介上。

我希望你喜欢这篇论文的解释。如果你对这篇文章有任何意见,或者如果你看到任何错误,请随时留下评论。

最后但同样重要的是,如果你想在高级计算机视觉领域更深入地探索,考虑成为我的追随者。我试着每周发一篇文章,让你和其他人了解计算机视觉研究的最新进展。

参考资料:

[1] PAWS GitHub 资源库:【https://github.com/facebookresearch/suncet

[2]陈,丁等:“视觉表征对比学习的一个简单框架。”机器学习国际会议。PMLR,2020 年。https://arxiv.org/pdf/2002.05709.pdf

[3] Assran,Mahmoud 等人,“通过支持样本的非参数预测视图分配的视觉特征的半监督学习” arXiv 预印本 arXiv:2104.13963 (2021)。https://arxiv.org/pdf/2104.13963.pdf

论文解释:通过对比聚类分配的视觉特征的无监督学习

原文:https://towardsdatascience.com/paper-explained-unsupervised-learning-of-visual-features-by-contrasting-cluster-assignments-f9e87db3cb9b?source=collection_archive---------10-----------------------

为什么 SwAV 模型架构对自我监督的预培训如此有效的秘密

多年来,教会神经网络在没有人类监督的情况下理解周围的世界一直是计算机视觉研究社区的北极星之一。最近,多个出版物显示了新方法在该领域取得重大进展的潜力。

发表的最有前景的方法之一是 Caron 等人从今年开始发表的一篇名为 “通过对比聚类分配进行视觉特征的无监督学习” 的论文。在这篇文章中,我们将回顾作者介绍的思想,SwAV 模型架构以及自我监督预训练的结果。我尽量让文章简单,这样即使没有什么先验知识的读者也能理解。事不宜迟,我们开始吧!

SwAV 训练程序的可视化。来源:【1】

先决条件:计算机视觉的自我监督预培训

在我们深入研究 SwAV 论文之前,有必要快速回顾一下自我监督预培训是怎么回事。如果你熟悉自我监督的预备培训,可以跳过这一部分。

传统上,计算机视觉模型总是使用监督学习来训练。这意味着人类看着这些图像,并为它们创建了各种标签,这样模型就可以学习这些标签的模式。例如,人类注释者可以为图像分配一个类标签,或者在图像中的对象周围绘制边界框。但是,任何接触过标注任务的人都知道,创建足够的训练数据集的工作量很大。

相比之下,自我监督学习不需要任何人为创造的标签。顾名思义,模特学会自我监督。在计算机视觉中,对这种自我监督进行建模的最常见方式是获取图像的不同裁剪或对其应用不同的增强,并通过模型传递修改后的输入。尽管图像包含相同的视觉信息,但看起来并不相同,我们让模型知道这些图像仍然包含相同的视觉信息,即相同的对象。这导致模型学习相同对象的相似潜在表示(输出向量)。

我们可以稍后在这个预训练的模型上应用迁移学习。通常,这些模型然后在 10%的带有标签的数据上进行训练,以执行下游任务,如对象检测和语义分割。

SwAV 如何使用无监督学习来理解周围的视觉世界

SwAV 的培训管道分为多个阶段。

在第一部分中,创建图像的不同裁剪。其他技术总是使用固定的大小来裁剪图像,而 SwAV 引入了多裁剪策略:不仅创建了两个较大的裁剪,还拍摄了多达 4 个较小的裁剪。这是 SwAV 与其他方法相比能够提升其性能的关键之一。也可以应用其他图像增强,如模糊和翻转。

SwAV 从同一幅图像中创建不同大小的作物进行训练。这被称为多作物策略。来源:自己的策展,图片来自 Unsplash

接下来,图像通过卷积神经网络成对传递。在论文中,作者使用了流行的 ResNet-50 架构,他们发现随着模型宽度的增加,性能也有所提高。对于每一个图像,ResNet 将输出一个维数为 128 的特征向量。

该可视化显示了将图像的每种不同裁剪输入到 ResNet,ResNet 输出每种图像的矢量表示。来源:【1】

一旦这些特征向量或代码被计算出来,它们就与所谓的原型向量相匹配。这些是定义可学习视觉特征空间之间的可能区别的空间的向量,例如,狗和猫之间的区别由不同的原型向量表示。制定代码到原型的映射,以最大化图像特征和原型之间的相似性。这个过程的输出是一个集群分配。

将输出特征向量匹配到原型向量空间导致将向量分配给原型聚类。来源:【1】

现在我们已经创建了这些聚类分配,我们做一个假设:如果输入的作物来自同一幅图像,我们希望以这样一种方式学习模型,即它为同一幅图像的作物输出相似的向量。

匹配聚类分配向量的简化可视化。来源:【1】

因此,应该可以交换两个输出向量(作物 1 得到向量 2,作物 2 得到向量 1)并且使模型学习预测另一个输入作物的向量输出。

交换集群分配。这成为新的训练目标。来源:【1】

这些交换的向量现在是另一个输入的预测目标,现在成为我们的学习目标,我们用它来反向传播模型的权重。

这种机制允许 SwAV 学习相同图像或对象类的一致矢量表示。这种能力对下游迁移学习至关重要。

现在,让我们看看一些结果。

结果

当仅使用来自预训练的冻结权重在 ImageNet 上对线性分类评估 SwAV 模型时,它优于所有其他最先进的自我监督方法。

SwAV 在 ImageNet 数据集上的性能。来源:【2】

最令人印象深刻的是,自我监督模型的性能几乎与仅使用注释数据的完全监督模型的性能相当。所有评估均使用 ResNet-50 (R50)骨架进行。在右图中,更多参数的性能差异表明 SwAV 也优于其他方法。

对 SwAV 的评估与对差异数据集的全监督训练程序的比较。来源:【2】

线性分类的这种性能优势在其他数据集上也同样适用。令人难以置信的是,当用作 Mask R-CNN 等对象检测模型的主干并仅使用 ImageNet 中 10%的标记数据进行微调时,所示的所有对象检测架构都优于相同模型架构的完全监督训练。这意味着对象检测主干的自我监督预训练可以产生比完全监督训练模型更好的性能。

包装它

在本文中,您已经了解了 SwAV,这是一种利用自我监督的预训练来为下游任务(如对象检测)实现新的性能高度的论文。在某些任务上,它甚至优于完全监督的方法。虽然我希望这个故事能让你对这篇论文有一个很好的初步了解,但是还有很多东西需要发现。因此,我会鼓励你自己阅读这篇论文,即使你是这个领域的新手。你必须从某个地方开始;)

如果你对论文中介绍的方法有更多的细节感兴趣,请随时在 Twitter 上给我留言,我的账户链接在我的媒体简介上。

我希望你喜欢这篇论文的解释。如果你对这篇文章有任何意见,或者如果你看到任何错误,请随时留下评论。

最后但同样重要的是,如果你想在高级计算机视觉领域更深入地探索,考虑成为我的追随者。我试着每周发一篇文章,让你和其他人了解计算机视觉研究的最新进展。

参考资料:

[1] SwAV GitHub 实现:【https://github.com/facebookresearch/swav

[2]卡隆、玛蒂尔德等人,“通过对比聚类分配对视觉特征进行无监督学习。” arXiv 预印本 arXiv:2006.09882 (2020)。https://arxiv.org/pdf/2006.09882.pdf

posted @ 2024-10-17 11:33  绝不原创的飞龙  阅读(208)  评论(0)    收藏  举报