TowardsDataScience-博客中文翻译-2020-八十八-

TowardsDataScience 博客中文翻译 2020(八十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

具有局部异常因子的新奇检测

原文:https://towardsdatascience.com/novelty-detection-with-local-outlier-factor-4867e89e4f91?source=collection_archive---------25-----------------------

检测新数据是否是异常值

兰迪·法特在 Unsplash 上的照片

异常检测相比,新奇检测可能是一些人更难听到的术语。如果离群点检测旨在发现数据集中的异常或显著不同的数据,则新颖性检测旨在确定新的或未知的数据是否是离群点。

新颖性检测是一种半监督分析,因为我们将训练未被异常值污染的训练数据,并且我们感兴趣的是通过使用训练的模型来检测观察值是否是异常值。在这种情况下,离群值也称为新奇值。

在这篇文章中,我将解释如何使用局部异常因子(LOF)进行新颖性检测。让我们开始吧。不过,如果你想跳过所有的理论,只是想接触编码部分,就跳过下一节吧。

本地异常因素(LOF)

局部异常因子或 LOF 是由 Breunig 等人提出的一种算法。(2000 年)。概念很简单;该算法试图通过测量给定数据点相对于其邻居的局部偏差来发现异常数据点。在这个算法中,LOF 会给出一个分数,告诉我们的数据是否是异常值。

LOF(k)~1 意味着作为邻居的相似密度。

LOF(k) < 1 means 密度高于邻居(内/非外值)。

LOF(k) > 1 意味着密度低于邻居(离群值)

在上式中,我已经给你介绍了一个 k 参数。在 LOF 算法中,局部性由 k 个最近邻给出,其距离用于估计局部密度。然后,该距离将用于测量局部偏差并查明异常。

k 参数是我们为获取一个 k 距离而设置的参数。k 距离是一个点到它的第 k 个邻居的距离。如果 k 为 4,k-距离将是一个点到第四个最近点的距离。距离本身是我们可以选择的距离计算的度量。通常它是“欧几里得”,但你可以选择其他距离。

k = 4,该点到达第四个最近的点(由作者创建的图像)

如果您想知道,我们的数据集中的每个数据点都将被测量 k 距离,以便测量下一步。

距离现在被用来定义我们所说的可达性距离。这个距离度量是两点距离的最大值或第二点的 k 距离。形式上,可达性距离的度量如下。

可达性距离 k(A,B)= max

其中 A 和 B 是数据点,A 和 B 之间的可达性距离要么是 k-距离 B 的最大值,要么是 A 和 B 之间的距离。如果 A 点在 B 点的 k-邻居内,那么可达性距离 k(A,B)将是 B 的 k-距离。否则,它将是 A 和 B 之间的距离

接下来,我们将通过使用可达性距离来测量局部可达性密度 (lrd)。测量 lrd 的公式估计如下。

lrd(A) = 1/(sum(可到达距离(A,i))/k)

其中 I 是点 A 的邻居(从其邻居可以“到达A**的点),为了获得点 A 的 lrd,我们计算 A 到其所有 k 个最近邻居的可达性距离之和,并取其平均值。lrd 是平均值的倒数。LOF 概念完全是关于密度的,因此,如果到下一个邻居的距离较长,则特定点位于较稀疏的区域。因此,密度越低——反之亦然。

这里,lrd 表示该点要移动多远才能到达下一个点或点簇。lrd 越低意味着点必须走得越长,并且组越不密集。

中心点的 lrd 是到其最近邻居的平均可达性距离,这些最近邻居是除(1,1)点之外的左下角的点。但是,这些邻居有其他 lrd,因为它们的最近邻居不包括中心点。(图片由作者创建)

然后,使用以下公式将本地可达性密度与其他邻居的可达性密度进行比较。

将每个点的 lrd 与其 k 个邻居的 lrd 进行比较。LOF 是 A 的相邻点的 lrd 与 A 的 lrd 的平均比率。如果该比率大于 1,则点 A 的密度小于其相邻点的密度。这意味着,从点 A 到下一个点或点簇需要比从 A 的邻居到下一个邻居的距离长得多的距离。

LOF 表示该点相对于其相邻点的密度。如果一个点的密度小于其相邻点的密度(LOF 大于 1),则该点被视为异常值,因为该点比密集区域更远。

LOF 算法的优点是,即使在异常样本具有不同基础密度的数据集上,它也能很好地执行。这是因为 LOF 不是样本有多孤立,而是样本与周围邻居相比有多孤立。

通过 LOF 进行新颖性检测

我们将使用由 scikit-learn 提供的 LOF 来帮助我们训练我们的模型。

#Importing the moduleimport pandas as pd
import seaborn as sns
from sklearn.neighbors import LocalOutlierFactor#Importing the dataset. Here I use the mpg dataset as an example
mpg = sns.load_dataset('mpg')

作为介绍,在使用模型进行新颖性检测之前,让我们尝试使用 LOF 作为离群点检测模型。

#Setting up the model. K is set by passing the n_neighbors parameter with integer. 20 is often considered good already to detect an outlier. By default the distance metric is Euclidean distance.lof = LocalOutlierFactor(n_neighbors = 20)#Training the model, I drop few columns that was not a continuous variablempg['lof'] = lof.fit_predict(mpg.drop(['cylinders', 'model_year', 'origin', 'name'], axis = 1))#Getting the negative LOF scorempg['negative_outlier_factor'] = lof.negative_outlier_factor_mpg

下面是结果,我们得到了 LOF 分类和负 LOF 分数。如果 lof 等于 1,那么它被认为是一个 inlier 如果它是-1,那么它是一个离群值。让我们试着得到所有的离群数据。

mpg[mpg['lof'] == -1]

污染或异常值取决于 LOF 分数。默认情况下,如果 negative_outlier_score 的分数小于-1.5,它将被视为异常值。

现在,让我们尝试使用模型进行新颖性检测。我们需要再次训练模型,因为我们需要传递一个额外的参数。

#For novelty detection, we need to pass novelty parameter as Truelof = LocalOutlierFactor(n_neighbors = 20, novelty = True)
lof.fit(mpg.drop(['cylinders', 'model_year', 'origin', 'name'], axis = 1))

我们只训练模型,我们根本不会使用训练数据来预测数据。在这里,我们将尝试预测新的看不见的数据。

#Predict a new random unseen data, the dimension must match the training datalof.predict(np.array([109, 310, 190, 3411, 15]).reshape(1,-1))Out: array([1])

输出可能是 1 或-1,这取决于它是否是一个异常值。如果你想得到负的 LOF 分数,我们也可以用下面的代码来实现。

lof.score_samples(np.array([109, 310, 190, 3411, 15]).reshape(1,-1))Out: array([-1.34887042])

输出将是数组形式的分数。就是这样,我已经向你们展示了如何用 LOF 做一个简单的新奇感检测。

结论

新奇性检测是检测新的看不见的数据是否是异常值的活动。局部异常因子是一种用于异常检测和新奇检测的算法。这取决于我们传递的 k 参数。通常情况下,k = 20 是可行的,但是如果您觉得数据中有大量的异常值,您可以增加这个数值。

希望有帮助。

如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。

如果您没有订阅为中等会员,请考虑通过我的推荐订阅。

11 月版:深度学习的力量

原文:https://towardsdatascience.com/november-edition-the-power-of-deep-learning-74e8182ee4f1?source=collection_archive---------34-----------------------

月刊

构建受生物启发的算法

岩田良治Unsplash 上拍摄的照片

当我刚刚开始研究数据科学时,我从未想过我需要解决深度学习问题。深度学习不是新手才有的概念!我天真的以为可以避免。突然,在我的旅程开始几个月后,我试图通过构建一个推荐系统来优化一项任务,并需要了解哪种 NLP 模型适合我的问题以及原因。是时候面对现实了。

当我开始深入主题时,我意识到建立深度学习模型很像是在不看盒子上的图片的情况下将拼图拼在一起。首先,我们根据形状挑选出我们认为是边缘的部分。接下来,我们按颜色将剩余的拼图块分开。根据边缘块的颜色,我们也许能够猜出每个颜色组的大概位置。之后,我们从一组颜色中挑选出我们容易识别的相关部分,并开始将它们放在一起。一点一点,我们意识到这是梵高的夜店。

就像这个类比一样,深度学习模型是由许多更简单的概念和函数组成的杰作。这种想法使得深度学习成为一种强大而广泛使用的技术。无论你是新手、科技领域的博士还是任何关心社会的人,你都会比你想象的更快地遇到深度学习的话题。为了帮助你了解更多,我们在这个话题上收集了一些我们最喜欢的精选,从介绍性的想法到最先进的技术。我们希望它们能让你对当前的理解有新的认识,并帮助你在这个旅程中导航。

《走向数据科学》的编辑琳达·陈。

深度学习的数学路线图

从头开始理解神经网络的内部运作

由蒂瓦达·卡丹 — 19 分钟阅读

用 CIFAR-10 进行深度学习

基于 CNN 的图像分类

阿雅婆罗门 — 10 分钟阅读

利用深度学习&人工智能解决现实世界的问题

不是你通常的物体检测博客

通过 Vaishnavi Dwivedi — 6 分钟读取

深度学习真的需要 GPU 吗?

获得一个 GPU 是深度学习的必备条件吗?了解 GPU 及其优势,并探索替代方案

通过bharat K—7 分钟读取

我的 3 年历程:从零 Python 到深度学习竞赛高手

自从 2017 年开始学习 Python 以来,我一直遵循的道路是在 2019 年年中成为一名 Kaggle 竞赛大师,并获得一枚单人金牌。一个激励你追求目标,永不放弃的故事。

由米格尔·平托 — 6 分钟读完

图形深度学习:成功、挑战和后续步骤

这是系列帖子中的第一篇,在这里我将讨论图形深度学习领域的演变和未来趋势。

迈克尔·布朗斯坦——7 分钟阅读

深度学习不再困难

至少,用深度学习构建软件不是

凯泽 — 6 分钟阅读

用于深度学习的 MacBook Pro?让我们试试。

它与英伟达 GPU 驱动的笔记本电脑相比如何?

达里奥·拉德契奇 — 4 分钟阅读

新播客

我们也感谢最近加入我们的所有伟大的新作家费德里科·乌雷纳贾森·吴永林瓦伊什纳维·德维迪尼古拉斯·路易斯安佳丽·巴德瓦吉克里斯·麦考密克阿米尔·阿菲安胡希德·加福尔应元(瓦莱丽)张提莫·博恩施泰特亚历山大·科尔科维洛斯薇琪·于达斯·维耶桑德拉泰勒·哈里斯加布里埃尔·卢西亚诺·彼得拉费萨艾琳·p阿里雷扎·库查里米黑尔-尤利安·pleșa我们邀请你看看他们的简介,看看他们的工作。

“现在,我该怎么做呢?”

原文:https://towardsdatascience.com/now-how-am-i-actually-going-to-do-this-b2c6a3e2379a?source=collection_archive---------78-----------------------

你已经有了伟大的项目想法,现在做什么?

Med Badr ChemmaouiUnsplash 上拍摄的照片

我的上一篇文章中,我谈到了我是如何为我的类似的针织图案探测器想出一个项目创意的。这个星期,我将谈论在你有了一个可靠的项目想法后的下一步。

太好了,你现在有了你的项目想法!对很多人来说,这可能是一个非常艰难的步骤,所以要鼓励自己。现在,你必须考虑你将如何回答你的问题或者构建你的程序。

研究

第一步是研究。你没有必要去重新发明轮子。如果有人已经写了一篇关于如何做一件具体事情的文章,你最好现在就找到它,而不是花几个星期做你的项目,只是发现有人写了一篇你可以直接跟随的漂亮、整洁的教程。就我而言,我从阅读协作式和基于内容的推荐系统以及它们是如何工作的开始。我还开始查看 Ravelry API 文档,看看我可以通过 API 访问哪些数据。

说了这么多,我需要指出一点:

不要在这一步花太多时间

我们都去过维基百科虫洞,浪费时间阅读语言学中所有未解决的问题。虽然你肯定不想盲目地一头扎进去,但是你也不想躲在你的研究后面,所以你从来没有真正开始编码。理想情况下,您希望处于可以完成下一步的位置:

创建路线图

在您提出项目想法后,您的项目路线图可能看起来像这样:

  1. 查找数据
  2. 干净的数据
  3. 尝试模型
  4. ????
  5. 利润

如果那是你开始的地方,那是可以的,但是如果你真的想越过想法阶段,你肯定需要做得更好。当你在研究阶段,你的目标应该是找出如何使这些步骤更加具体。例如,这个步骤可能会变成“发出这些 API 请求”,或者“从这些网站收集数据”,而不是“查找数据”你每一步做得越具体,你的情况就越好。

也就是说,你不需要想清楚一路上的每一步。如果您在收集数据的同时还在考虑如何清理数据,那也没关系。只要你对接下来的步骤有一个具体的想法,对你想要的结果有一个清晰的画面,你就有足够的东西可以开始工作了。路线图的目标是集中你的工作(这样你就不会花两周的时间在你最终扔掉的东西上),并使一个潜在的令人生畏的任务变得不那么令人生畏。

虽然有一个项目路线图很重要,但是步骤列表不能是一个僵化、不灵活的列表。出现了意想不到的错误,当您开始收集数据时,有一些您不知道的奇怪的数据特性,您正在收集的数据没有您最初想要的所有特性,项目有太多的方式可以偏离轨道并可能脱轨。对于你完成的每一步,肯定会有至少三个你必须解决的问题。这就是为什么你必须有一个适应性强的路线图。即使出现了这些问题,你仍然需要有这样的地图,这样你才不会迷失在细节中,看不到你的项目目标。

我已经有了路线图,现在做什么?

现在您已经有了项目路线图,并且至少对如何完成项目有了一个大致的想法,您必须做最难的事情之一:

实际跟进并完成你的项目

在我们的回购协议中,我们都有被放弃的附带项目,下周我将谈论我如何确保这个项目不会成为其中之一。

在欧洲,现在是成为数据科学家或数据管家的最佳时机

原文:https://towardsdatascience.com/now-is-the-best-time-to-be-a-data-scientist-or-a-data-steward-in-europe-618143a80dd0?source=collection_archive---------33-----------------------

为什么欧盟计划培训 50 多万数据科学家和数据管理员

【Pexels.com 的 皮沙贝拍摄的照片

内容

  1. 简介
  2. 什么是公平数据?
  3. 在科学和研究领域,对数据科学家的期望是什么?
  4. 数据管家是做什么的?
  5. 两个角色如何比较和交集?
  6. 结论

介绍

2016 年,一组欧盟高级专家估计,欧洲将需要在十年内使开放科学成为可能 超过 50 万“核心数据专家”

在他们看来,这些“核心数据专家”将在整个研究生命周期中支持 170 万研究人员和 7000 万科学技术专业人员,确保良好的数据管理,帮助数据捕获(格式、元数据、标准、出处、发布),以及数据分析。

两年后,在 2018 年,这一想法得到了加强,并且“核心数据专家”被确定为数据科学家和数据管家 ( 将公平变为现实最终报告和行动计划),他们除了技术专业知识外,还需要拥有他们将从事的研究和创新领域的领域知识。

在研究的背景下,这两种技能组合定义如下:

  • 数据科学“处理、加工和分析数据,从中得出真知灼见的能力”;所需技能包括:计算机科学、软件开发、统计学、数据可视化、机器学习以及计算基础设施。
  • 数据管理“一套确保数据在整个研究生命周期和长期保存过程中得到正确管理、共享和保存的技能”。提到的技能的一些例子是:信息管理、数据清理、数据管理。

鉴于这些确定的需求,该报告呼吁制定新的正式或不太正式的教育和培训计划,帮助培养实现公平数据所需的大量数据科学家和数据管理员。

有趣的是,该报告还呼吁研究人员精通数据,以便他们能够更好地利用现有的数据和技术。

什么是公平数据?

从哲学的角度来看,公平数据的原则,以及整个开放科学运动,都与科学和研究数据一样可以被视为全球公共产品的理念有关。尤其是当它们是由公共资金资助的时候。

关于开放数据作为公共产品的更多信息,以及关于免费开放数据来源的信息可以在我之前的文章中找到:

[## 用于社会公益的数据科学:免费开放数据的最佳来源

类型、优势以及在哪里可以找到它们

towardsdatascience.com](/data-science-for-social-good-best-sources-for-free-open-data-5120070caf02)

每年,科学和其他领域产生的数据量都呈指数级增长。这为我们如何在科学中使用这些数据、制定商业决策或制定基于证据的政策带来了巨大的机遇。但在利用产生的数据方面也存在巨大挑战,比如数据的质量及其长期保存。

按照这种逻辑,我们必须能够将数据转化为知识,然后付诸行动。

那么,公平代表什么?(公平数据原则

  • 可查找的 —人类和计算机都应该能够很容易地找到数据及其元数据。为此,元数据应该是机器可读的,允许自动发现数据集和服务。
  • 可访问 —数据应该带有关于如何访问的明确信息,即使这涉及认证或授权。此外,即使数据不再可用,也应该可以访问相应的元数据。
  • 可互操作 —数据需要与应用程序(如 API)或工作流互操作,以便进行分析、存储和处理。
  • 可重用 —该原则指的是 FAIR 的主要目标,即优化和促进数据的重用。为此,元数据和数据需要被很好地描述,以包括关于使用许可的信息,以及出处。

公平数据不等于开放数据。例如,从可访问性原则中可以注意到,有时它可能涉及授权或认证。

据欧盟委员会公平数据专家组主席西蒙·哈德森(Simon Hudson)称,没有“数据科学和数据管理技能的显著和广泛提高”,公平就不可能实现。在数字技能方面,欧洲并不是真正的最佳实践范例,平均 42%的人口缺乏这方面的技能。

数字经济与社会指数 2 0 2 0

在科学和研究领域,对数据科学家的期望是什么?

与数据管家一起,数据科学家将被要求在整个研究生命周期中支持研究人员,并将被嵌入机构层面的研究项目或每个领域的专业服务中。

在许多情况下,数据科学职位由已经有研究背景或受过信息专业培训的人担任。前者尤其重要,因为数据科学家在这一领域的大部分工作都是特定学科的,需要对监管和研究有深刻的理解。

在查看了一些由研究执行组织提供的数据科学家的工作描述后,我注意到,除了与机器学习、统计学、Python、数据可视化、有时高性能计算或云计算相关的常见要求之外,一些未来的员工还应该了解与研究学科相关的软件工具,为科学期刊文章和博客撰写内容,或者参加国家和国际会议并在会上发言。在教育方面,该领域的数据科学家需要拥有天文学、物理学、统计学或计算机科学等领域的硕士或博士学位(根据研究学科的不同而不同)。

对于那些来自计算机科学或其他相关学科,而不是来自特定研究领域的人来说,一个潜在的缺点是要求至少是第一阶段的研究人员(R1)。在这种情况下,最好先成为该领域的研究人员,然后再学习数据科学技能。然而,并非在所有情况下都是如此。

另一方面,在研究执行组织中担任数据科学家的一个优势可能是,它可能会对社会影响做出贡献。例如,该领域的一些工作需要将数据科学应用于社会技术主题,如流行病、假新闻、公民参与或可再生能源。

[## 造福社会的数据科学

超越我们想看什么类型的电影,到我们想生活在什么类型的世界。资源、示例和…

towardsdatascience.com](/data-science-for-social-good-a88838bc8ed0)

数据管家是做什么的?

在业务领域,数据管理与提高数据质量、处理敏感和机密数据、数据清理、定义政策和监控系统、定义标准、添加元数据以及数据生命周期中的整个数据管理流程(从监管到废弃)相关联。

数据仓库信息图

Adobe 的数据治理角色

在 Adobe,数据管理员特别负责解释法规、任何合同限制和政策,并将其应用于数据。因此,他们的职责包括:创建数据策略并将其应用于数据集;审查数据、数据集和数据样本,以应用和管理元数据使用标记等。

从 Adobe 的例子和其他例子中我们可以看出,在某些情况下,数据管理更多地与数据策略和处理敏感和机密数据相关。接下来我们将会看到,在欧洲开放科学的背景下,数据管理是如何围绕实施公平原则展开的。

在研究的背景下,数据管理员可以负责数据清理、消除不一致、组织和构建数据、处理元数据、确保数据的可重用性、可访问性和长期保存(即使在技术发生变化时),以及其他数据管理操作。根据他们的经验和专业水平,在某些情况下,数据管理员可能还需要处理定义标准、最佳实践和互操作性框架。

然而,无论是公共部门还是私营部门,数据管理不仅仅是数据管理,因为它还包括数据收集或捕获、处理、长期保存及其再利用。

在代尔夫特理工大学 关于 数据管理的演示中,提到数据管理人员应该能够回答特定研究领域中所有与数据相关的问题。一些问题可能涉及数据存储、数据恢复和备份、如何处理机密和敏感数据、在申请专利的情况下共享数据、帮助制定数据管理计划和跟踪数据、确保数据的长期保存。

此外,在代尔夫特大学,数据管理员的工作规范包括数据管理员预期工作的研究领域的核心要求知识。

数据管理员与工作相关的职责示例(摘自 EURAXESS )包括:在整个研究生命周期中支持研究人员和管理人员,开发研究数据管理工作流程和最佳实践,研究项目的数据管理规划,研究数据监管,为研究人员开发和举办培训和研讨会,数据管理,确保数据有效性、保护和安全性,确保符合有关格式、元数据的国际标准,监控数据管理,维护词汇表,实施公平数据原则,开发特定领域的词汇、本体和元数据模式,参与研究活动和编写出版物。

这两个角色是如何相互比较和交叉的?

2020 年美国平均年薪:

热门技能(按此顺序,在 Payscale.com 上):

  • 数据管家:数据分析、数据管理、数据质量、Microsoft Excel、SQL
  • 数据科学家:机器学习,Python,数据分析,统计分析,R

欧洲研究人员专用平台EURAXESS上的工作列表数量:

  • 数据管家:只有 3 个,在荷兰、德国和卢森堡
  • 数据科学家:488 人,但这个数字并不完全准确,因为这个名单还包括其他类型的工作,比如 UI/UX 设计师、软件开发员

当谈到研究执行组织的工作职责时,两者在一定程度上是重叠的。数据科学家角色还包括与数据管理或处理公平数据原则相关的任务。

将公平变为现实报告的作者认为,数据科学和数据管理通常可以在同一个人身上结合,但最好是在这两个领域推动更大的专业化。在某些情况下,这可能取决于可用的预算和研究机构的数据导向程度。对于许多这样的组织来说,在这方面可能很难有两种不同的立场。

下面是一个与欧洲开放科学云相关的试点项目如何详细描述数据管理技能和能力框架的示例。在这种情况下,数据科学是更大的数据管理概念的一部分。整个框架请见报告

EOSC 飞行员技能和能力框架

其他定义数据科学和数据管理的欧洲计划可在以下页面查阅:

  • 爱迪生计划 —数据科学专业的加速和创造
  • 数字策展的课程框架

结论

鉴于目前数据管事没有太多的职位空缺,这似乎可能不是最好的职业。然而,空缺数量少也可能是因为该角色有时被整合在数据科学家的角色中,因为后者还涉及处理研究数据管理和数据的公平原则(至少在欧洲)。

当这两个角色分开时,数据管家对于数据的重用可能是极其重要的,即使它与私有或公共部门有关。数据具有更大的价值,当它可以被重用和构建时,可以产生更好的结果和影响。为了完成他们的工作,数据科学家需要获得良好、可靠的数据,并且,随着时间的推移,数据管理员可以在这方面提供帮助。

数据管理可以解决数据科学中的垃圾入、垃圾出(GIGO)问题。如果你一开始就没有高质量的数据,那么一个数据科学家再好也没用。正如我的一个朋友曾经说过的,我们需要从如何和收集什么类型的数据开始,然后转移到处理和从中提取洞察力

无论如何,欧洲对数据专家的需求很高,预计还会增加,因为欧盟机构希望在创新和技术竞赛中赶上美国和中国。如果不拥抱新技术,不在人力资源方面加强竞争,这是不可能的。

如果您希望尝试开放的研究数据集,请查看以下存储库:

[## 芝诺多——研究。分享。

2020 年 8 月 12 日(1.0 版)数据集开放存取 Bardi,Alessia 库奇马、伊里纳;波波罗夫、叶夫根尼;伊万娜·特鲁科洛;蒙泰罗…

zenodo.org](https://zenodo.org/) [## 领域知识在数据科学中到底有多重要?

看看来自美国的招聘信息,不仅仅是。

towardsdatascience.com](/how-important-domain-knowledge-really-is-in-data-science-19d833d98698)

现在,使用惰性计算在一秒钟内加载巨大的数据集😴用 Python?

原文:https://towardsdatascience.com/now-load-huge-datasets-within-a-second-using-lazy-computation-in-python-2698bdb02250?source=collection_archive---------51-----------------------

厌倦了用 pandas 加载数据集…了解 Vaex 如何通过 Python 实现在几秒钟内加载大量数据。

来源:https://vaex.readthedocs.io/en/latest/tutorial.html

本文简要介绍了如何使用 Vaex 将大数据集加载到 Python 内核中,并给出了实际的实现。让我们开始吧。在深入真正的实现之前,让我们了解一下什么是 Vaex。

Vaex 是什么?

  1. Vaex 是一个高性能的 Python 库,用于懒惰的核外数据帧(类似于 Pandas),以可视化和探索大型表格数据集。
  2. 它在一个 n 维网格上每秒计算超过 10 亿(10⁹)个样本/行的统计数据,如平均值、总和、计数、标准偏差等。
  3. 可视化是使用直方图、密度图和 3d 体绘制完成的,允许对大数据进行交互式探索。Vaex 使用内存映射、零内存复制策略和惰性计算来获得最佳性能(不浪费内存)。

看完这篇文章,我建议你去这里 看看 VaexT3 的文档

下载和安装包

第一步是使用任何包管理器如 pipconda 下载并安装 vaex 库。

pip install vaex

或者

conda install -c conda-forge vaex

记得用“!”如果您直接将它输入到 iPython 环境中,请在命令之前。

导入包

现在,我们需要使用下面的命令将这个库导入到我们的工作环境中。我们将导入 pandas 来计算两个库的执行时间。

import vaex
import pandas as pd

资料组

现在,在本演示中,让我们创建一个包含 100 万行 100 列的大型数据集,这确实是一个大型数据集。

n_rows = 100000
n_cols = 10
df = pd.DataFrame(np.random.randint(0, 100, size=(n_rows, n_cols)), columns=['c**%d**' % i **for** i **in** range(n_cols)]) 

现在,让我们检查一些关于加载的数据集的信息。

df.info(memory_usage='deep')

创造。csv 文件

我们将把上面创建的演示数据帧保存为的形式。csv 文件实现加载。

file_path = 'main_dataset.csv'
df.to_csv(file_path, index=**False**)

创建 Hdf5 文件

我们需要以 hdf5 格式存储数据集,作为 vaex 负载的输入。

请注意,所有这些过程只是为了创建演示数据集,用于演示目的,在实际项目中,我们会有一些数据,而实现基于 vaex 的数据加载只是一行代码。

vaex_df = vaex.from_csv(file_path, 
                        convert=**True**, 
                        chunk_size=5_000_000)

在检查我们得到的这个数据帧的类型时,

type(vaex_df)

使用 Vaex 库读取 Hdf5 文件

现在,我们终于到了演示中最重要的一步,所以请注意。使用 Vaex 加载 Hdf5 格式的数据集。

vaex_df = vaex.open('main_dataset.csv.hdf5')
vaex_df.head()

表达系统

现在让我们看看 Vaex 的计算速度有多快。我们实现了两列的乘法,并将它们存储在数据帧中的一个新列中,并估计了这个过程所花费的时间。结果可以忽略不计。

%%time
vaex_df['multiplication_col13']=vaex_df.c1*vaex_df.c3

看到这一列中的内容,我们得到一个 vaex 定义的表达式类似于熊猫数据框中的一列。

vaex_df['multiplication_col13']

核外数据帧

坚持 Vaex 开发背后的主要概念,我们需要记住以下注意事项,

"筛选和计算表达式不会因为复制而浪费内存;数据在磁盘上保持不变,仅在需要时进行流式传输。在需要集群之前延迟时间。”

比如…

vaex_df[vaex_df.c2>70]

所有的算法都在内核之外工作,极限是你的硬盘驱动器的大小

比如…

dff.c2.minmax(progress='widget')

Vaex 实现了并行、高性能的 groupby 操作,尤其是在使用类别(> 10 亿/秒)时。

实现为…

%%time
vaex_df_group = vaex_df.groupby(vaex_df.c1,
                                agg = vaex.agg.mean(vaex_df.c4))
vaex_df_group

%%time
vaex_df.groupby(vaex_df.c1,agg='count')

参考

https://vaex.readthedocs.io/en/latest

关于这次演示的完整代码,请从我的 Github 中获取 Jupyter 笔记本

谢谢!

Numba: JIT 编译,但是用于 Python

原文:https://towardsdatascience.com/numba-jit-compilation-but-for-python-373fc2f848d6?source=collection_archive---------31-----------------------

快速浏览一下 2020 年让 Python 变得更好的神奇工具。

介绍

对于程序员和计算机科学家来说,统计计算一直是一个非常困难的学科。程序员不仅在统计编程语言中寻找某些属性和特征,在通用编程语言中也是如此。随着机器学习和数据科学应用的普及,统计计算的兴起也加剧了“完美语言”发展中的这些关键问题。

回到十年前,没有人能预料到 Python 中机器学习的兴起会是什么样子。大多数科学家使用 R 编程语言进行统计分析和类似的事情。MATLAB 当然也是统计计算领域非常流行的选择,Scala 也是如此。Python 最近在这方面变得非常流行,因为它具有强大的统计能力

当然,Python 是用 c 解释的,这意味着 Python 没有它的竞争对手那么快,也不适合大数据解决方案。Python 本质上并不是一种为满足现代科学计算需求而构建的编译器语言。虽然 Python 对于大多数统计应用程序来说是一个很好的应用程序,但 Python 的主要缺点通常是在处理大量数据和递归训练机器学习模型时的速度。

为什么要用 Python?

如果 Python 在处理大量数据方面有问题,并且本质上是一种解释型的高级语言,那么为什么今天许多科学家喜欢这种语言呢?答案很简单,目前,Python 是最好的解决方案。虽然 Python 与许多其他语言相比相对较慢,但与其他语言相比,它也是非常高级的语言,并且在过去几年中一直在变得更快和更优化。

除此之外,Python 拥有当今最强大的统计计算生态系统之一。这些包中的大部分也是用 C 语言编写的,这使得 Python 经常成为非常快速的代码的简单接口。然而,无论生态系统有多强大,它都无法帮助处理海量数据和编写 Pythonic 算法来清理和编辑数据。

吉特舞乐

除非你一直生活在编程的龟壳下,否则你可能熟悉——或者至少听说过一个叫做 JIT 的编译器概念。JIT 或即时编译是一种编译器特性,它允许在运行时而不是在执行时解释和编译语言。这意味着 JIT 编译器在编译代码之前执行逻辑,而不是准备所有的代码来工作,决定代码要做什么,然后再去做。

这种编译器的好处当然是速度。花费在初始编译上的时间更少意味着代码可以更快地被解释。打个比方,假设你有一份晚餐要做的东西的清单。你可以采取一种多任务的方法,在同一时间做多件事情,而不是单独做所有的事情。

数字概述

Numba JIT 编译器类似于 Julia JIT 编译器,使用标准的 LLVM 编译器库。虽然它在这方面确实有一些缺点,因为 LLVM 的重点不一定是 JIT,但它确实意味着编译器非常快和精确。Numba 编译的 Pythonic 算法可以达到 c 等低级语言中常见的速度。

这听起来可能很复杂,确实如此——但这并不意味着 Numba 很难使用。事实上,Numba 非常容易使用!为了试用它,你当然需要用 Python 的包管理器 PIP 来添加它。

sudo pip3 install numba

安装 Numba 后,您可以通过 jit 函数访问它:

from numba import jit
import random

@jit(nopython=True)
def monte_carlo_pi(nsamples):
    acc = 0
    for i in range(nsamples):
        x = random.random()
        y = random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

对于大多数代码,Numba 在优化 Python 代码方面做得非常出色。然而,正如 Julia 开发者在 JuliaCon 上讨论的那样,在当前版本中,Numba 仍有很长的路要走,并存在[某些代码的问题。一些问题无法通过简单的 Python 调用来解决,尽管 Numba 在创建可以轻松导入的 Python 优化编译器方面做得很好,但仍有一些改进需要做。

结论

不管 Python 是否会一直成为科学目的和统计计算的首选编程语言,很明显 Python 现在肯定是这样。虽然 Python 不是最快的编程语言,并且在科学计算方面也有一些小问题,但对于那些希望进行统计或机器学习的人来说,它仍然是一个很好的选择。这主要是由于它的生态系统和整体受欢迎程度。

幸运的是,Python 的许多缺陷正被有才华、有干劲的开发人员直接瞄准。随着时间的推移,这项技术很有可能会发展到当使用 Python 进行数据科学时,这些问题中的许多可能都不会再被感觉到。

Python 最大的问题之一是速度。Numba 是一系列令人敬畏的工具之一,有助于解决这个问题,并使 Python 达到对抗其他统计语言的标准,特别是像 Julia 这样的新语言。Numba 令人兴奋的地方在于它使用起来非常简单,就像一个电灯开关,可以让你的代码运行得更快。反过来,这可以用来为应用程序注入新的活力,否则这些应用程序甚至可能无法运行。

Numba:“大规模优化的武器”

原文:https://towardsdatascience.com/numba-weapon-of-mass-optimization-43cdeb76c7da?source=collection_archive---------9-----------------------

Numba 如何节省您的时间并加速您的代码

Numba 是一个 Python 编译器,专门针对数字函数,允许您使用直接用 Python 编写的高性能函数来加速应用程序。

Numba 使用 LLVM 生成从纯 Python 代码优化的机器码。通过几处简单的修改,我们的 Python 代码(面向函数的)可以“实时”优化,获得类似于 C、C++的性能,而不必改变语言。

你可以在我的 GitHub 中找到完整的代码!😃

索引

  1. 什么是 Numba?
  2. 第一步:为 CPU 编译
  3. GPU 的 Numba
  4. 结论

什么是 Numba?

Numba 是一个编译器,允许您为 CPU 和 GPU 加速 Python 代码(数值函数):

  1. 函数编译器: Numba 编译 Python 函数,而不是整个应用或部分应用。基本上,Numba 是另一个提高函数性能的 Python 模块。
  2. Just-in-time: (动态翻译)Numba 将字节码(比机器码更抽象的中间代码)在其执行前立即翻译成机器码,以提高执行速度。
  3. 数值型: Numba 关注的是数值型数据,比如intfloatcomplex。目前,对字符串数据使用它有一些限制。

Numba 不是 CUDA 唯一的编程方式,通常是直接用 C/C ++为它编程。但是 Numba 允许你直接用 Python 编程,并对 CPU 和 GPU 进行优化,只需对我们的代码做很少的修改。关于 Python,还有其他替代方案,如 pyCUDA,下面是它们之间的比较:

CUDA C/C++:

  1. 这是 CUDA 中最常见和最灵活的编程方式
  2. 加速 C、C ++中的应用程序。

pyCUDA

  1. 这是 Python 最有效的 CUDA 形式
  2. 它需要用我们的 Python 代码进行 C 编程,一般来说,还需要许多代码修改。

PyCUDA 示例

数字巴

  1. 效率不如 pyCUDA
  2. 它允许您用 Python 编写代码,并通过少量修改对其进行优化
  3. 它还为 CPU 优化了 Python 代码

目标

本次会谈的目标如下:

  • 使用 Numba 在 CPU 上编译函数
  • 了解 Numba 是如何工作的
  • 在 GPU 中加速 Numpy ufuncs
  • 使用 Numba 编写内核(下一个教程)

第一步:为 CPU 编译

Numba 除了能够加速 GPU 中的函数之外,还可以用来优化 CPU 中的函数。为此,使用了 Python decorators(函数修饰符)。

首先我们要开始评估函数hypot来试试 Numba 是怎么工作的。我们需要在函数中使用装饰器@jit

>>> # Numba function
>>> hypot(3.0, 4.0)
**5.0**>>> # Python function
>>> hypot.py_func(3.0, 4.0)
**5.0**

Numba 中的结果与 Python 函数中的结果相同,因为 Numba 将函数的原始实现保存在.py_func中。

标杆管理

自然,测量我们代码的性能,检查 Numba 是否真的工作良好,并观察 Python 实现和 Numba 实现之间的差异是很重要的。此外,库math已经包含了hypot函数,我们也可以对其进行评估。

>>> # Python function
>>> %timeit hypot.py_func(3.0, 4.0)**The slowest run took 17.62 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 260 ns per loop**>>> # Numba function
>>> %timeit hypot(3.0, 4.0)**The slowest run took 33.89 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 216 ns per loop**>>> # math function
>>> %timeit math.hypot(3.0, 4.0)**The slowest run took 105.55 times longer than the fastest. This could mean that an intermediate result is being cached. 10000000 loops, best of 3: 133 ns per loop**

math.hypot功能甚至比 Numba 还快!!这是因为 Numba 为每个函数调用引入了一定的开销,这比 Python 函数调用的开销要大,非常快的函数(就像上一个)会受此影响。

(但是,如果从另一个函数调用 Numba 函数,开销很小,如果编译器将该函数集成到另一个函数中,开销有时甚至为零。总之用 Numba 检查一下功能是不是真的在加速)。

**[## 1.14.性能提示-Numba 0 . 48 . 0 . dev 0+134 . g 709967 b-py 3.7-Linux-x86 _ 64 . egg 文档

这是一个简短的指南,介绍 Numba 中的一些特性,这些特性有助于从代码中获得最佳性能。二…

numba.pydata.org](https://numba.pydata.org/numba-doc/dev/user/performance-tips.html#performance-tips)**

Numba 是如何工作的?

当我们初始化hypot函数时:

Numba 如何工作

  • 中间表示法
  • ****字节码分析中间代码比机器码更抽象
  • LLVM 低级虚拟机,开发编译器的基础设施
  • NVVM 是一个基于 LLVM 的 IR 编译器,它被设计用来表示 GPU 内核

python 的每一行前面都有几行 Numba IR 代码。最有用的是查看向我们展示 Numba 如何处理变量的类型注释,例如,在“pyobject”中,它表明 Numba 不知道np.sin函数,他应该从 Python 中调用它。我们可以使用.inspect_types()检查hypot的过程。

>>> @jit
>>> def foo_np(x):
>>>     return np.sin(x)>>> foo_np(2)
>>> foo_np.inspect_types()**foo_np (int64,)
----------------------------
# File: <ipython-input-18-02574ac7ba04> 
# --- LINE 1 ---  
# label 0** **@jit** **# --- LINE 2 ---   
def foo_np(x):    
# --- LINE 3 ---    
#   x = arg(0, name=x)  :: int64   
#   $0.1 = global(np: <module 'numpy' from '/usr/local/lib/python3.6/dist-packages/numpy/__init__.py'>)  :: Module(<module 'numpy' from '/usr/local/lib/python3.6/dist-packages/numpy/__init__.py'>)  

#   $0.2 = getattr(value=$0.1, attr=sin)  :: Function(<ufunc 'sin'>)   #   del $0.1   
#   $0.4 = call $0.2(x, func=$0.2, args=[Var(x, <ipython-input-18-02574ac7ba04> (3))], kws=(), vararg=None)  :: (int64,) -> float64** **#   del x   
#   del $0.2   
#   $0.5 = cast(value=$0.4)  :: float64   
#   del $0.4   
#   return $0.5    return np.sin(x)   ==============================================**

示例:创建分形

我们将使用 Mandelbrot 集合来测量创建分形的性能,我们将看到 Numba 如何帮助我们提高性能。

**1 loop, best of 3: 4.62 s per loop
<matplotlib.image.AxesImage at 0x7f986ce23780>**

使用 Mandelbrot 集合生成一个分形大约需要 4.62 秒,现在我们将使用 Numba 来提高性能,我们只需添加@jit装饰器。

**The slowest run took 4.17 times longer than the fastest. This could mean that an intermediate result is being cached. 1 loop, best of 3: 52.4 ms per loop**

我们可以观察到我们是如何实现将构建分形的时间从 4.62 秒减少到 52.4 毫秒… 并且这是通过添加装饰器实现的!!****

一些常见错误

我们说过 Numba 只对数字函数有效,虽然 Numba 可以编译和运行任何 Python 代码,但是有些类型的数据它还不能编译(比如字典),而且编译它们也没有意义。

>>> @jit
>>> def dictionary(dict_test):
>>>    return dict_test['house']dictionary({'house': 2, 'car': 35})
**2**

****但它并没有失败!!我们说过 Numba 不编译字典…这里的重点是 Numba 创建了两个函数,一个用 Python,另一个用 Numba。这里我们看到的是 python 解决方案,我们可以通过做nopython = True来验证这一点。

*jit(nopython = True)*相当于njit

>>> @jit(nopython = True)
>>> def dictionary(dict_test):
>>>    return dict_test['house']dictionary({'house': 2, 'car': 35})**-----------------------------------------
TypingError                Traceback (most recent call last)****<ipython-input-31-14d1c8683c01> in <module>()
      3   return dict_test['house']
      4 
----> 5 dictionary({'house': 245, 'car': 350})2 frames****/usr/local/lib/python3.6/dist-packages/numba/six.py in reraise(tp, value, tb)
    656             value = tp()
    657         if value.__traceback__ is not tb:
--> 658             raise value.with_traceback(tb)
    659         raise value
    660****TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Internal error at <numba.typeinfer.ArgConstraint object at 0x7f986c1bed68>:
--%<-----------------------------------------**

GPU 的 Numba

使用 Numba 在 GPU 中编程有两种方式:

1。 ufuncs/gufuncs__

2。 CUDA Python 内核(下一个教程)**

函数 ufunc

****GPU 的主要设计特性之一是并行处理数据的能力,因此 numpy (ufunc)的通用函数是在 GPU 编程中实现它们的理想候选。

: ufunc 是对 numpy 数组的每个元素执行相同操作的函数。例如:

实践:为 GPU 创建函数

正如我们之前说过的,ufunc 函数是将它们与 GPU 一起使用的理想选择,因为它们具有并行性。因此,Numba 有能力在不使用 c 的情况下创建编译的 ufunc 函数,要做到这一点,我们必须使用 decorator @vectorize

让我们从一个使用@vectorize编译和优化 CPU ufunc 的例子开始。

**array([ 24, 343,  15,   9])**

我们将在 GPU 中使用 CUDA,而不是使用 CPU 来编译和执行前面的函数,为此我们必须使用“目标属性”。我们将指出每个变量的类型(参数和返回值)。

return_value_type(argument1_value_type, argument2_value_type, ...)

为此,我们将使用前面的函数,该函数需要 2 个 int64 值并返回另一个 int64 值。我们将指定target = 'cuda'能够在 GPU 中执行它。

**array([ 24, 343,  15,   9])**

我们可以检查它在 CPU 或 GPU 上运行的速度:

>>> %timeit np.add(a, b)   # Numpy en CPU**The slowest run took 38.66 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 511 ns per loop**>>> %timeit add_ufunc_gpu(a, b)   # Numpy en GPU**The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached. 1000 loops, best of 3: 755 µs per loop**

GPU 比 CPU 慢!!!安静,这有一个解释…但是首先让我们看看当我们调用那个函数时会发生什么…

当我们执行这个函数时,Numba 产生:

  1. 编译 CUDA 内核,对输入数组 的所有元素并行执行 ufunc 函数
  2. 将输入和输出分配给 GPU 内存
  3. 将输入复制到 GPU
  4. 运行 CUDA 内核
  5. 将结果从 GPU 复制回 CPU
  6. 以 numpy 数组的形式返回结果

与 C 中的实现相比,Numba 允许您以更简洁的方式执行这些类型的任务。

为什么 GPU 比 CPU 慢?

  • 我们的输入太小:GPU 使用并行性一次对数千个值进行操作来实现更好的性能。我们的输入是 4 或 64 维,我们需要更大的阵列来保持 GPU 被占用。
  • 非常简单的计算:与调用 CPU 函数相比,将计算结果发送到 GPU 需要很多“努力”。如果我们的函数不需要过多的数学计算(这通常被称为算术强度),那么 GPU 可能会比 CPU 花费更长的时间。
  • Numba 将数据复制到 GPU。
  • 我们输入的变量类型比需要的大:我们的例子使用 int64,我们可能不需要它们。实际上,在 CPU 中,32 位和 64 位具有相同的计算速度,但在 GPU 中,64 位的计算速度略有增加(它可以分别比 32 位慢 24 倍)。因此,在 GPU 中执行函数时,记住这一点非常重要。

****考虑到这一点,我们将尝试应用前面几点学到的东西,看看在 GPU 上运行是否真的比 CPU 快。我们将计算一个密度函数,对于较大的数组,这是一个稍微复杂一点的操作。

给定平均值和 sigma,让我们计算x中高斯密度函数的值:

>>> %timeit norm_pdf.pdf(x, loc=mean, scale=sigma)  # CPU function
**10 loops, best of 3: 60.8 ms per loop**>>> %timeit gaussian_dens_gpu(x, mean, sigma) # GPU function
**100 loops, best of 3: 6.88 ms per loop**

耶啊!

我们甚至可以使用 Numba 定义在 CPU 中执行的函数。

>>> %timeit gaussian_dens_cpu(x, mean, sigma) # CPU
**10 loops, best of 3: 23.6 ms per loop**

它甚至比用 Python 编写的函数还要快,但比在 GPU 中执行的函数要慢。

不幸的是,有几个函数不在 ufunc 的定义范围内,因此,为了在 GPU 中执行不满足该要求的函数,我们使用cuda.jit。我们可以使用运行在 GPU 上的“设备功能”。

:“设备函数”是只能从内核或另一个“设备”函数调用的函数。

>>> %timeit polar_distance(rho1, theta1, rho2, theta2)
**The slowest run took 23.16 times longer than the fastest. This could mean that an intermediate result is being cached. 1 loop, best of 3: 10.2 ms per loop**

结论

总而言之,Numba 是一个 Python 编译器,专门针对数值函数,允许您使用直接用 Python 编写的高性能函数来加速应用程序。

它是一个稳定的工具,允许您优化面向数组操作的代码。感谢它的易用性(只是一个装修工!!)为我们提供了一个非常强大的工具来提高我们代码的性能。

欢迎建议和评论。关注我,感谢你的阅读!😃

前馈神经网络中的参数数量

原文:https://towardsdatascience.com/number-of-parameters-in-a-feed-forward-neural-network-4e4e33a53655?source=collection_archive---------3-----------------------

手动计算前馈神经网络中可训练参数的总数

今天,机器学习正在解决如此大量的复杂问题,看起来就像魔术一样。但是机器学习没有任何魔力,相反它有很强的数学和统计基础。

在试图理解机器学习的重要且有些困难的概念时,我们有时甚至不会考虑一些琐碎的概念。也许你会想到这些,但是我知道我经常忽略很多简单的事情。原因是令人惊叹的机器学习和深度学习库,它们具有为我们快速做到这一点的功能和方法。😍

一个这样的小问题是手动找出前馈神经网络中可训练参数的总数。我在一次考试中遇到的一个问题,它让我对所提供的选项感到困惑。这个问题也被很多机器学习的从业者在很多不同的论坛上问过。🙋🏻

照片由普里西拉Unsplash 上拍摄

本帖讨论的问题是:

如何求一个前馈神经网络中可训练参数的总数?

你一定想知道为什么这是一个需要讨论的重要问题。的确是!训练一个模型所需的时间取决于要训练的参数的数量,因此这些知识有时真的可以帮助我们。

通过查看一个简单的网络,您可以很容易地计算并说出参数的数量。最坏的情况,你可以画出图,说出参数个数。但是当你遇到一个问题,一个神经网络有 7 层,每层的神经元数量不同,比如说 8,10,12,15,15,12,6,会怎么样呢?你怎么知道总共有多少个参数?

让我们一起找到一个数学公式来得到计数。但是在开始计算之前,让我们先了解一下什么是前馈神经网络,它具有什么特征。这将帮助我们找到参数的总数。

前馈神经网络是最简单的人工神经网络,其中感知机之间的连接不形成循环。

尽管是最简单的神经网络,但它们对机器学习实践者来说极其重要,因为它们构成了当今使用的许多重要和高级应用的基础。🤘

前馈神经网络的特性;

  1. 感知器是分层排列的。第一层接收输入,最后一层给出输出。中间层被称为隐藏层,因为它们对外部世界是隐藏的。
  2. 一层中的每个感知器都连接到下一层的每个感知器。这就是信息不断从一层流向下一层的原因,因此得名前馈神经网络。
  3. 同一层的感知器之间没有联系。
  4. 从当前层到前一层没有向后连接(称为反馈连接)。

注: 感知器是计算输入值加权和的神经网络的基本单元。

数学上,前馈神经网络定义了映射y = f(x;θ) 并学习有助于找到最佳函数近似的参数 θ 的值。

注: 前馈神经网络中除输出层外的所有层中也有一个偏置单元。通过将激活功能向左或向右移动,偏差对成功学习非常有帮助。迷茫?🤔简单来说,bias 类似于直线的线性方程 y = mx + c 中的截距(常数),有助于预测线更好地拟合数据,而不是一条总是经过原点(0,0)的线(y = mx 的情况)。

现在让我们利用这一知识来找出参数的个数。

场景一: 一个只有一个隐层的前馈神经网络。输入层、隐藏层和输出层中的单元数分别为 3、4 和 2。

一个前馈神经网络(图片由作者提供)

假设:

i =输入层的神经元数量

h =隐含层神经元的数量

o =输出层神经元数

从图中,我们有 i = 3, h = 4, o = 2。请注意,红色神经元是该层的偏差。一层的每一个偏置都连接到下一层除了下一层偏置以外的所有神经元。

数学上:

  1. 第一层和第二层的连接数:3 × 4 = 12,无非是 ih 的乘积。
  2. 第二层和第三层的连接数:4 × 2 = 8,无非是 ho 的乘积。
  3. 层与层之间也有通过偏置的连接。第一层的 bias 和第二层的神经元之间的连接数(第二层的 bias 除外):1 × 4,无非就是 h
  4. 第二层偏置与第三层神经元的连接个数:1 × 2,无非是 o

总结所有:

3 × 4 + 4 × 2 + 1 × 4 + 1 × 2

= 12 + 8 + 4 + 2

= 26

因此,这个前馈神经网络总共有 26 个连接,因此将有 26 个可训练参数。

让我们试着用这个等式来概括,找出一个公式。

3 × 4 + 4 × 2 + 1 × 4 + 1 × 2

= 3 × 4 + 4 × 2 + 4 + 2

=I×h+h×o+h+o

因此,具有一个隐藏层的前馈神经网络中的参数总数由下式给出:

(I×h+h×o)+h+o**

由于该网络是一个小型网络,因此也可以通过计算图中的连接数来得出总数。但是,如果层数更多呢?让我们再研究一个场景,看看这个公式是否有效,或者我们需要对它进行扩展。

场景一: 一个具有三个隐层的前馈神经网络。输入层、第一隐藏层、第二隐藏层、第三隐藏层和输出层中的单元数分别为 3、5、6、4 和 2。

假设:

i =输入层的神经元数

h1 =第一个隐藏层的神经元数量

h2 =第二个隐藏层的神经元数量

h3 =第三隐藏层的神经元数量

o =输出层的神经元数量

  1. 第一层和第二层的连接数:3 × 5 = 15,无非是 ih1 的乘积。
  2. 第二层和第三层的连接数:5 × 6 = 30,无非是 h1h2 的乘积。
  3. 第三层和第四层的连接数:6 × 4 = 24,无非是 h2 和 h3 的乘积。
  4. 第四层和第五层的连接数:4 × 2= 8,无非是 h3o 的乘积。
  5. 第一层的 bias 和第二层的神经元(第二层的 bias 除外)的连接个数:1 × 5 = 5,无非就是 h1
  6. 第二层偏置与第三层神经元的连接个数:1 × 6 = 6,无非是 h2
  7. 第三层偏置与第四层神经元的连接个数:1 × 4 = 4,无非是 h3
  8. 第四层偏置与第五层神经元的连接个数:1 × 2 = 2,无非是 o

总结所有:

3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 1 × 5 + 1 × 6 + 1 × 4 + 1 × 2

= 15 + 30 + 24 + 8 + 5 + 6 + 4 + 2

= 94

因此,这个前馈神经网络总共有 94 个连接,因此有 94 个可训练参数。

让我们试着用这个等式来概括,找出一个公式。

3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 1 × 5 + 1 × 6 + 1 × 4 + 1 × 2

= 3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 5 + 6 + 4 + 2

= I×h1+h1×H2+H2×H3+H3×o+h1+H2+H3+o

因此,具有三个隐藏层的前馈神经网络中的参数总数由下式给出:

(I×h1+h1×H2+H2×H3+H3×o+h1+H2+H3+o****

T 因此,找到具有 n 个隐藏层的前馈神经网络中可训练参数总数的公式由下式给出:

计算前馈神经网络中参数总数的公式(图片由作者提供)

如果这个公式听起来有点让人不知所措😳,别担心,没必要背这个公式🙅。请记住,为了找到参数的总数,我们需要总结以下内容:

  1. 输入层和第一个隐藏层中神经元数量的乘积
  2. 两个连续隐藏层之间神经元数量的乘积之和
  3. 最后一个隐藏层和输出层中神经元数量的乘积
  4. 所有隐藏层和输出层中神经元数量的总和

现在,我希望你可以应用这种方法,即使不使用库,也可以找到具有任意数量的隐藏层和神经元的前馈神经网络中的参数总数。🙃

参考:

https://cs . Stanford . edu/people/eroberts/courses/soco/projects/neural-networks/Architecture/前馈. html

谢谢大家!如果你对这篇文章有任何反馈或建议,请留下你的评论!

领英

数字会说谎

原文:https://towardsdatascience.com/numbers-can-lie-3474e0efa1e1?source=collection_archive---------35-----------------------

分析的常见陷阱:它们如何误导决策者以及如何避免它们。

由于技术的进步,分析和统计几乎已经成为业务各个方面不可或缺的一部分。这对数据科学家和分析师来说很好,但也会产生一些非常现实的问题。

主要问题是由分析融入业务流程的速度引起的,因为事实上大多数人没有受过多少统计教育,即使受过教育,也往往从学生时代起就没有重温过这些主题。这给组织带来了一个非常现实的问题。

盲目相信决策是基于那些实际上站不住脚的指标和数字,这种现象正在蔓延。

如果你是一名数据科学家或分析师,记住我们的工作不会凭空出现是至关重要的。我们的分析是共享的,并将影响决策的方式,因此在构建报告、仪表板等时记住这一点很重要。以确保它们不会无意中误导最终用户。

简单地说,如果你不能证实你的数字,为什么会有人相信你的分析?或者更糟糕的是,如果你的分析是无意的误导,它会造成严重的伤害。

在这篇文章中,我将探讨一些可能导致决策者被误导的不同因素,以及如何在您的工作中避免这种情况。

照片由 @thisisengineeringUnsplash 上拍摄

模糊平均值

首先要思考的是:术语“平均”是什么意思。

有三种:均值、中值、众数。

当你看到“平均”这个词时,你可能指的是他们中的任何一个。最常见的是,提到的平均值是均值,但并不总是如此,在我的工作中,我选择称之为“均值平均值”,除非客户特别要求。

我将更深入地研究平均值,因为它们可能会非常容易误导,因为不同的数据集可能会以多种方式产生相同的平均值。例如,三个值“1,2,3”可以具有与“2,2,2”相同的含义。

均值可能误导的主要原因是异常数据,相对非常大或非常小的值对均值有很大的影响。

一个真实的例子:一家公司的月平均销售额为 25000 英镑。高管们看到了这一点,并对公司的状况感到满意。
实际上,平均销售额会因为一个每月 50,000 的客户被竞争对手收购而出现偏差。这位客户的即将流失实际上降低了 15,000 英镑的均值,这对公司来说是一个非常危险的现金头寸。在这种情况下,查看分布或另一种类型的平均值可以帮助管理人员预见这些事件并做好准备。

我倾向于“越多越好”的方法,并在我自己不展示结果的任何场景中包含其他描述,这几乎没有出错的余地。永远记住考虑最终用户的需求,而不是你的需求,我可以保证他们没有像你一样花几个小时扫描原始数据,所以不要假设他们了解数据集。

这是具有相同平均值的不同数据集的示例

第一个数据集

第二数据集

第三个数据集

上述分析显示了三个完全不同的数据集,它们都具有相同的平均值、计数和总和,然而,它们都具有非常不同的分布(我保持了相似的标度以强调这一点)。这种情况在分析中经常发生,并且经常被完全掩盖。

说到分析,描述性统计是必须的。仅仅制作漂亮的度量标准和图表而没有适当的背景会导致弊大于利。如果您计划使用平均值作为报告和仪表板的一部分,那么我建议至少用它们来显示分布,这样平均值背后的上下文是可以理解的,并且请记住将其标记为“均值、众数、中等”。如果您不确定最适合您数据集的平均值,我建议您事先详细研究每个平均值。

失踪的小字

统计数据经常被引用,而没有任何原始数据的参考,以及遗漏某些可能违背创造者假设的数字。

向自己展示调查结果时,要问自己的一个重要问题是“此图中谁的利益是正确的”?这并不是说这些数字不正确。只是没有办法确切知道。
因此,不应该仅仅依赖这些数字。

如果你要展示数据,一定要注明来源、方法和其他相关信息。如果你遗漏了什么,问问自己为什么,如果答案是防御性的,不要遗漏。我们不再需要那么多虚假的事实。

虚假陈述的一个常见例子是调查数据,其中遗漏了关于方法或样本大小的信息。这通常包括总下载量等数据,这是营销人员喜欢的,但却忽略了活跃用户等其他指标。

这在以下两个陈述中清楚地显示出来,两个陈述都是准确的。

中国的 GDP 比卢森堡高。
卢森堡的 GDP 比中国高。

GDP /人均 GDP |来源世界银行(2018 年)

这两种说法都是正确的,因为中国的 GDP 总量要大得多。但是,人均来说,卢森堡要高很多。在这种情况下,你可以说两个经济体的表现都比另一个好。

大假设,小暗示。

统计数字经常被用来证明一个观点或巩固一种观点。尽管事实上他们经常两者都不成功。

想出一个令人心酸的陈述并以准复杂的统计数据为依据是很容易的,但当你深入挖掘表面之下时,它们就会被推翻。

其中一种说法是“首席执行官的收入比以往任何时候都高”。这种说法得到了一些数据的支持,比如“首席执行官现在的平均收入为 25 万英镑。与 1950 年相比,他们只赚了 5 万英镑。这本身似乎是一个强有力的证明,但实际上,1950 年的 5 万英镑相当于今天的 48 万英镑。因此,尽管初看起来,这种说法是荒谬的。我知道这似乎是显而易见的,但还有很多不那么明显的。

我个人看到的另一个常见例子是,一家大型人力资源分析软件公司在其网站上声明:“我们的客户实现了高达 80%的投资回报率。”

这种说法有两个主要问题。

首先,从数学的角度来看,短语“高达”在这个场景中实际上可以表示任何东西,即公司的大多数客户可能获得零投资回报,而一个客户可能获得 80%。因此,这种说法是正确的,但具有误导性。

这种说法的另一个问题是方法中的假设。假设在这个场景中,公司销售的产品是销售软件。他们计算出,与前一年相比,使用第一年的销售额增加导致 80%的投资回报率。他们很方便地忽略了一个事实,即在软件推出之前,销售额每年增长 50%。因此,声称这种增长是由软件引起的是没有根据的,因为这种增长已经在客户的正常操作趋势之内。

避免这种情况的一个简单的方法就是避免一般化,因为这给错误留下了太多的空间。请记住,你试图用你的数据来讲述一个故事,这个故事需要包括细节。

相关性而不是因果关系。

这可能是查看统计数据时最常犯的错误,这样做的后果可能是巨大的。

假设您想要了解工作场所敬业度和员工服务年限之间的关系,因此您进行了一项调查并获得了结果。

你会发现时间长度和参与度之间存在正相关关系。由此你可以得出结论,一个人在组织中工作的时间越长,他们就会越投入。我们怎么能确定这是真的呢?首先,您需要访问服务年限的分布。这是接近正态分布的水平,还是分布有很大的偏差?记住,拿苹果和桔子做比较没有什么价值。

值得庆幸的是,有一个有用的方法可以理解相关性有多重要,那就是 P 值。该计算用于显示如果相关系数为零,则具有相同结果的概率。如果 P 值小于 5%,(0.05),则认为相关性具有统计学意义。

这并不意味着这种相关性是一种因果关系,只是值得进一步研究,以确定这种相关性实际上是否是由于因果关系。

由于对 P 值含义的无知或仅仅依靠相关系数,看似相关的事物通常被认为是因果关系。如果你发现两件事是相关的,并希望进一步了解这种关系,那么贝叶斯统计将是一个有助于更深入地了解数据的工具。

关于相关性,需要考虑一些简单的事情:
通常的相关性分为四类(这些可以是积极的或消极的关系):

不相关:不言自明。
相关,但不一定:有时候事情在统计上是相关的,但实际上并没有关系,只是偶然发生的。避免这种情况的两种方法是获得更多的数据或进行实验,在受控条件下检验这种关系。
实际相关:这些输入有关系,但如果影响条件改变,它们可能会改变或破坏这种关系。记住数据不存在于虚空中,事物是变化的,不要假设 其他条件不变
因果:输入直接支配输出,考虑关系的顺序 eg 是 X 引起 Y 变化,还是相反,还是关系是双向的?这当然取决于你的数据的性质。

相关性是数据科学的一个重要组成部分,但是当你得到你想要的结果时,很容易被冲昏头脑。真正挖掘,直到你完全明白发生了什么,你会惊讶你的发现。

结论

这些问题中的大多数可能看起来很明显,但在快节奏的商业环境中,它们很容易悄悄进入您的分析中而没有人注意到,尤其是您正在使用现成的分析工具,这些工具不允许您检查原始数据或运行自定义查询和公式。

一般来说,为了更好地实践,如果你不理解或不知道漂亮的图表或先进的机器学习模型背后发生了什么,那么当涉及到决策时,你不应该依赖他们的输出,总是提供上下文。

令人欣慰的是,网上有很多阅读统计、数据科学和机器学习的好地方,让每个人都能提高自己的数据素养。

美国人纠结于图表

原文:https://towardsdatascience.com/numeracy-and-graph-literacy-in-the-united-states-ea2a11251739?source=collection_archive---------56-----------------------

新的研究显示对数标度的 y 轴混淆。但是当与“公众”交流数据时,需要有多简单呢?人们能处理多少复杂性?

(图片来自作者+ VectorStock )

上个月,亚历山德罗·罗马诺、基亚拉·索蒂斯、戈兰·多米尼奥尼和塞巴斯蒂安·圭迪对 2000 人进行了调查,证明“公众不理解用来描绘新冠肺炎的对数图。

他们发现,只有 41%的参与者能够正确回答关于对数标度图的基本问题(线性标度的准确率为 84%)。

但是这个问题比对数秤更难。正如您将在下面看到的,许多“公众”甚至连最基本的图表都难以理解,更不用说复杂的可视化了。

知识的诅咒

评论中有一条引起了我的注意:

“作为一家大报的前信息图表编辑,我一直认为我的优势之一是缺乏数学技能。如果我能理解图表,也许读者也能。是的,我从来没有用过对数图表。”——罗伯特·b

这引发了更多的问题:有多少数据记者像罗伯特·b 一样思考?或者,正如 Romano & friends 建议的那样,大众媒体中的人们是否“习惯性地”假设对数标度轴是广泛可理解的?如果是后者,他们高估了世界的量化能力,那么普通观众会忽略多少其他重要的数据故事?

我从个人经验中知道,这是一个容易犯的错误。如果您一天中的大部分时间都花在 python 笔记本上,或者您的午餐谈话经常转向 arXiv 上的新内容,那么您可能也是如此。

斯坦福/杜克大学的教授丹/奇普·希斯称之为“知识的诅咒”。

“一旦我们知道了一些事情,我们很难想象不知道它是什么样子。我们的知识“诅咒”了我们。我们很难与他人分享我们的知识,因为我们不能轻易地重现听众的心理状态。”—奇普&丹希斯,制成贴

也就是说,如果你有很高的计算能力,通常很难和没有计算能力的人交流。

为了治愈“诅咒定量知识”,并通过更典型、更不了解的观众的眼睛来看待数据世界,我们将关注三项不同的研究,这些研究大规模地测量了计算能力和图形读写能力。

他们的一般发现是有帮助的,但为了使其具体化,我们还将看看这些研究中的 10 个具体问题,我将提供 1)一个典型用户可能解释它们的准确程度,以及 2)我们成年人能够正确可靠地解释它们的百分比。

有了这些基准,希望你能有一个更直观的感觉,一个故事需要简化到什么程度,才能被更广泛的读者所理解。

当用数据讲故事时,如果你想让你的(来之不易的)见解变得平易近人,没有太简单这一说。

tldr/外卖:

  • 美国的基线计算能力不是很好。
  • 图形理解依赖于计算能力和“阅读”的复杂性。
  • 有一些令人惊讶的基本解释让许多人纠结。

算术问题

计算能力不是天生的。

显然,婴儿和啮齿动物天生就能区分简单的数量。如果在两堆饼干中做出选择,婴儿知道要选择较大的那一个( src )。老鼠可以学会按 8 次或 16 次杆来接收零食( src )。

但这大概是我们与生俱来的数字能力的极限。剩下的,包括比率、负数等基本概念都是学的。

PIAAC 研究 38 个国家的“计算能力”。

每隔几年,经济合作与发展组织都会进行一项名为“国际成人能力评估项目”的大型研究。它考察了世界各地成年人的基本技能,其中之一是计算能力。

研究人员与来自 38 个国家的约 24.5 万人坐下来,每人约一小时,并对他们进行测试。他们在 1-500 的范围内计算自己的分数,其中 500 是满分。然后将这些分数分成 5 个等级,其中 1 级最不熟练,5 级最熟练。

3 级似乎是一个重要的门槛。典型的“3 级”人员得分在 276-326 分之间( src ,第 71 页)。他们可以在 67%的情况下回答“3 级”问题。我们稍后将探讨示例问题,但 PIAAC 将 3 级问题描述为:

这一级别的任务要求回答者理解可能不太明确的数学信息,嵌入在不总是熟悉的上下文中,并以更复杂的方式表示。任务需要几个步骤,可能涉及解决问题的策略和相关过程的选择。任务倾向于要求数感和空间感的应用;认识并运用以口头或数字形式表达的数学关系、模式和比例;以及对文本、表格、图表中的数据和统计数据的解读和基本分析。( src ,第 71 页)

根据 PIAAC,我们成年人的计算能力如何?

在接受调查的 38 个国家中,美国在 3 级或 3 级以上的成人比例方面排名第 28 位。(转载自技能很重要:美国成人技能调查的额外结果2017 年美国 PIAAC 结果网络报告的亮点)

美国在接受调查的 38 个国家中排名第 28 位。美国成年人的平均分数为 255 分( src ),这让他们稳稳地处于 2 级范围(226-276 分)( src ,第 71 页)。只有 37%的美国成年人达到 3 级或以上,日本为 63%,芬兰为 58%。

因此,如果 10 个美国成年人中只有 4 个表现在 3 级以上,那么 10 个中就有 6 个会努力“识别和运用以口头或数字形式表达的数学关系、模式和比例;并能对文本、表格和图表中的数据和统计数字进行解释和基本分析

“这些结果是另一个信号,表明许多美国人在最基本的数学技能上挣扎,”NCES 副专员佩吉·卡尔说。

“但我的观众很聪明”

这是一个很好的实践,坦率地说,假设一个聪明的、善意的观众是值得尊敬的,但是仅仅因为某人受过良好的教育,并不意味着他们精通数量。

计算能力和教育之间有很大的关系,但也有例外。例如,即使在高中以上学历的人群中,47%的人在 PIAAC ( src )中的表现仍为 2 级或以下。

2008 年,莎拉·霍利(& friends)发现,即使在至少拥有学士学位的参与者中,也有 33%的人被归类为低算术水平( src )。在 2001 年对“高学历者”的一项研究中,艾萨克·利普库斯(&朋友)发现,16-20%的参与者错误地回答了与风险大小相关的非常基本的问题(例如“哪一个代表更大的风险:1%、5%还是 10%?” ) ( src )。

Goutham Rao 在 2008 年的评论表明,即使是医生也在挣扎。一项对家庭医生的调查显示,尽管 95%的参与者肯定了理解生物统计学的重要性,但只有 25%的人表示对该学科有信心。根据他们的测试结果,缺乏信心是有根据的:他们平均只有 41%的正确答案。诚然,生物统计学是一个更高的门槛,但希望这表明,即使是先进的观众也不总是像他们希望的那样先进。

图形理解

算术和交流数据有什么关系?

Mirta Galesic 和 Rocio Garcia-Retamero 表明,低计算能力不仅限制了一个人的数学能力,还与他们的“图形素养”或解释图表的能力密切相关。

根据 Galesic 和 Garcia-Retamero 的说法:“导致高计算分数的相同的元认知能力也培养良好的图形读写技能。”反之亦然:在 261 名“低计算能力”的美国成年参与者中,只有 89 人(34%)表现出高图形读写能力。

用户将如何“读取”数据?

Galesic 和 Garcia-Retamero 的另一个聪明见解是:图形理解不仅仅基于读者的能力,它还取决于他们需要如何解释数据。他们提出了三种人们“阅读”图表的方式。用户可以:

  1. “读取数据”——识别图表上的特定值
  2. “在数据之间读取”——识别图表数据中的关系
  3. “阅读数据之外的内容”——从图表数据中做出推论

这些水平中的每一个都越来越难,这反映在他们的结果中。美国参与者可以在 86%的回答中正确“阅读数据”,在 67%的回答中正确“阅读之间”,在 63%的回答中正确“阅读之外”。

请注意,这些结果似乎比 PIAAC 建议的更积极。为了更好地理解数据读者实际能处理什么,让我们来看看这两项研究中的一些潜在问题。

人们能处理多少复杂性?

为了说明这一点,让我们看看一些图形理解问题&来自 PIAAC、国家成人识字调查问题和 Galesic/Garcia-Retamero 的“图形识字”研究的结果。

PIAAC 样题

我们将从第三级开始,即“中等难度”

一个“3 级”问题。只有 37%的美国成年人会定期正确回答这个问题。(图片来自 NCES, src )

级别 3:对于时间序列折线图:“在哪个(些)时期出生人数有所下降?”

美国成年人 PIAAC 计算能力的平均分数是 255/500。因此,美国成年人平均有大约 26%的机会正确回答 3 级问题。一个得分在 276-326 分之间的“3 级”的人,在 50-80%的时间里回答正确。由于 37%的美国成年人得分在 3 级以上,我们可以说,只有十分之四的美国成年人能够可靠地回答这样的问题。

一个“1 级”问题。92%的美国成年人会定期正确回答这个问题。(图片来自 NCES, src )。

对于刻度盘温度计:

  • 级别 1: “温度计上显示的温度是多少华氏度(F)?”
  • 级别 2: “如果显示的温度降低了 30 摄氏度,那么温度是多少摄氏度?”

这些似乎是 1 级和 2 级问题。一个典型的美国成年人在 89%的情况下会正确回答 1 级问题(92%的美国成年人是 1 级,并且在大多数情况下会正确回答)。他们会在 66%的情况下正确回答第二级问题(70%的美国成年人是第二级,大多数情况下会正确回答)。

(注:NCES 网站将这些问题列为 3 级,但读者指南将类似的问题列为“低难度”或 1/2 级)

一个“二级”问题。70%的美国成年人会正确回答这个问题(通过国家教育研究中心)

对于表格和条形图:“哪两个条形是不正确的?”

这是一个“二级”问题。一个典型的美国成年人在 66%的情况下会正确回答这个问题(70%的美国成年人在大多数情况下会正确回答这个问题)。

全国成人识字调查问题

美国的一项早期研究“全国成人识字调查”表明,普通美国成年人只能在大约 50%的时间里“从描述能源和年份的条形图中识别信息”。他们只能在大约 25%的时间里“使用信息表来确定多年的石油出口模式”( src )。

提示“2 级”问题。(图片来自 NCES, src )

第 2 级:“你是一家小型制造公司的营销经理。这张图表显示了贵公司过去三年的销售额。根据图中所示的季节模式,在图上画一个“x”来预测 1985 年春季的销售额(以千计)

一个普通的美国成年人在 60-80%的时间里回答正确。( src ,第 102 页)

提示 3 级问题。(图片来自 NCES, src )

第三级:“假设你在一个周六乘坐下午 12:45 的公交车从 U.A.L.R .学生会到第 17 大街。按照时间表,大巴要坐几分钟?”

一个普通的美国成年人在 35-65%的时间里回答正确。

“图形素养:跨文化比较”问题

在《图形素养:跨文化比较》中,Galesic 和 Garcia-Retamero 告诉我们“即使是最简单的图形对许多人来说也可能难以理解”( src )。

3 个不同的图表,提示了以下来自 Galesic 和 Garcia-Retamero“图形素养”研究的问题。(转载自 src )

一些示例问题和预期结果:

  • 读出柱状图上的一个点(左图):“化疗后痊愈的患者比例是多少?”——85%的美国成年人回答正确。
  • 确定两个条形图之间的差异(中图):“手术后康复的患者百分比与放射治疗后康复的患者百分比之间的差异是什么?” — 70%的美国成年人回答正确。
  • 比较一条线的两个区间的斜率(中图):“什么时候患支气管炎的人的百分比增加得更高?(1)从 1975 年到 1980 年,(2)从 2000 年到 2005 年,(3)在这两个时间间隔内的增长是相同的,(4)不知道“——62%的美国成年人回答正确。
  • 确定两组图标之间的差异(右图):“100 名 X 病患者中,男性比女性多多少?” — 59%的美国成年人回答正确。

一个也许会计算的伐木工人考虑简单的木材分配。

外卖:

在交流数据时,上述问题提供了有用的基准,用于根据可视化或数据故事的复杂性确定您的目标受众规模:

  • 如果它大致像识别和减去两个值一样复杂(例如,“手术后康复的患者百分比和放射治疗后康复的患者百分比之间的差异是什么?”),你在和 10 个人中的 7 个人说话。
  • 如果它和识别线图上的趋势一样复杂(例如,“在哪个(些)时期出生人数下降了?”),你只能和 10 个人中的 4 个人说话

基于这些,您可以相应地调整数据的显示。如果你知道你只是在和一群高级观众说话,你就可以开始了。但是如果你想获得更广泛的受众,想办法简化。

我们能做得更好吗?

记住我们的观众比以往任何时候都重要。新冠肺炎是一场数字概念和条件的龙卷风,人们在与之斗争(例如,大数、指数曲线、政治/情感等)。此外,受病毒影响最严重的社区在算术教育方面也是最缺乏服务的。这两者都提高了传播者的门槛,使他们的见解更容易被人接受。

那么,我们能做些什么来解决“[定量]知识的诅咒?”

  • 不要假设普遍的计算能力。意识到你的观众对复杂性的偏好。
  • 在真人身上测试你的作品。没有什么比用户对表面区域的反馈更简单的了。
  • 当大多数人(至少是我们成年人)需要访问数据时,问问自己:这比在条形图上减去 2 个值复杂还是不复杂?
  • 注释一切。只要有可能,就提供如何解释你的视觉化图像的书面说明,并用关键要点的叙述性描述来补充视觉化图像。
  • 如果你知道像对数标度轴这样的东西不会被广泛理解,无论如何都要去做。许多人认为,接触更难的图形实际上有助于提高图形素养,所以也许团队需要一个?

我是谁?不,不,你是谁?!

我是伊莱。我的数据可视化咨询公司帮助客户使用数据(可视化)创造积极的变化,不仅通过理性地吸引受众,还通过情感和文化吸引受众。变化发生在头脑心里。

如果你对用户测试数据感兴趣,或者如果你是在数据、设计和用户心理学的交叉领域工作的创始人、制造者、讲故事者或商业领袖,我很乐意联系和交换故事。

你可以给我发电子邮件,地址是eli@3iap.co或者关注我的推特

参考

数字锦标赛:融合传统量化方法和现代机器学习

原文:https://towardsdatascience.com/numerai-tournament-blending-traditional-quantitative-approach-modern-machine-learning-67ebbb69e00c?source=collection_archive---------17-----------------------

如何提高金融机器学习的智能

Erol Ahmed 在 Unsplash 上拍摄的照片

介绍

数字锦标赛

Numerai 是一个众包基金,一个对冲基金,它根据不特定数量的人做出的股价预测结果进行操作。Numerai 举办比赛,参与者为预测业绩而竞争。锦标赛参与者将根据 Numerai 提供的加密数据集建立一个预测模型,然后使用它来创建一个提交。参与者将根据他们的预测表现进行排名并获得报酬(有时会被封杀)。Numerai 的支持者包括复兴科技的联合创始人霍华德·摩根(Howard Morgan)、保罗·都铎-琼斯(Paul Tudor-Jones)、联合广场风险投资公司(Union Square Ventures)和其他知名风险投资家以及具有丰富对冲基金经验的人士。数字数据集由专门从事金融机器学习的顾问监督。迄今为止,支付给参与者的奖金总额已超过 3400 万美元,该项目可能进展良好。

图片由numeri提供

关于作者

作者使用市场中性方法投资日本股票市场。市场中性旨在通过结合买入和卖出(多头和空头),预测宇宙(要投资的一组股票)中股票价格的相对涨跌,获得独立于市场价格运动的绝对回报。在传统的定量方法和统计学的基础上,作者通过机器学习建立了该预测模型。结果一直不错,收益率在 40%左右。

本文的目的

在这篇文章中,我将分享在建立作者模型的过程中获得的见解。我首先解释了传统定量方法的概念,并讨论了如何将其与机器学习相结合,以建立一个现代预测模型。

笔记

Numerai 的数据集是加密的,作者对此一无所知。这篇文章仅仅是作者投资和建模经验的观点。

传统定量方法

预测股票收益的研究由来已久。让我们从解释什么是传统的定量方法及其起源开始。

巴拉风险模型

现在的 quants 的原型很可能就是 Barr Rosenberg 提出的风险模型[1]。关于这一点有很多理论,但是对于华尔街这方面的历史,你绝对应该读一读彼得·伯恩斯坦的书《资本理念》[2]。

在 20 世纪 60 年代,基于 Markowitz 的协方差模型,Rosenberg 设计了一种方法,使用各种因素来解释单个公司的风险。他还发现这些风险因素与股票价格的超额收益(风险溢价)相关。1975 年,罗森博格成立了一家咨询公司,Barr Rosenberg Associates,Inc .这家公司被全世界的管理公司称为 BARRA。

目前,BARRA 模型是最知名的风险模型,MSCI 作为供应商提供。其他风险模型包括公理。虽然有各种类型的 BARRA 模型,但 BARRA 全球股票模型(GEM)是全球主要股票市场股票的风险模型[3]。该模型将股票收益分解为国家因素、行业因素、风险因素和个人因素,如下所示。

这可以用多元回归模型描述如下。Rn 是股票 n 的超额收益(相对于无风险利率),x 是股票 n 对每个因子(k,j,I)的因子敞口,f 是因子收益,en 是具体收益。这里的关键是要素收益的概念。

因子回报

为简单起见,我将用单因素模型而不是多因素模型来解释。我还将把数字数据集结构作为一个具体的例子。因子收益是以下横截面回归中的回归系数 f。这里 r 是 eraX 中的目标向量,x 是 eraX 中 featureA 的向量。

因子回报是通过对宇宙中的风险因子下注来衡量预期的回报。因子暴露是股票暴露于该风险因子的程度,暴露越大,因子回报的收益越大。从上面的等式可以看出,回归模型是一个特定时间段(eraX)的横截面模型,在实际测试过程中,我们在一段时间内(如每月)对其进行累积,并观察其特征。

以下是 BARRA GEM 文档中的因子回报示例。如果一个因子收益明显向右,说明只要赌上那个因子,就能获得稳定的收益。如果价格明显下跌,那么你可以赌这个因素无效(转换多头和空头)。在当前的 2020 年,很少有一个方向的要素回报是显著的。因此,我们应该考虑每只股票的因素敞口,构建一个分散于各种因素的投资组合。

各种风险因子的因子收益。来源:[3]

因素回报和相关性

由于因子收益是回归系数,因此可以使用目标变量和解释变量的波动性将它们转换为相关性。在下面的等式中,b 是解释变量 x 对目标变量 y 的回归系数,σxy 是 x 和 y 的协方差,σx 和σy 分别是 x 和 y 的标准差。相关性,可以这么说,是标准化在-1 和 1 之间的因子收益,用波动性修正。

相关性在风险模型中是一个非常重要的指标,因此在主动投资组合管理理论中也是如此。在主动投资组合管理理论中,相关性被称为信息系数,它是基金经理技能的一个指标。我将不详细解释这一领域。有兴趣可以参考最著名的主动管理理论的书[4]。

在这里,我描述了每个数字特征的因子回报(通过相关性计算)。计算简单地通过单因素模型来完成。从这个图中,我们可以一目了然的看出哪些特征有哪些特点,它们本身有多大的解释力。

数字特征的因子收益。来源:作者

应该注意的是,这些因素回报包括由于随机性引起的变化。以下是相关性=0.0 和相关性=0.005 (100 次试验)情况下的蒙特卡罗模拟。我们应该始终记住,这种程度的可变性可能是由于随机性而产生的。在 120 左右的样本期内确定统计显著性是一个非常困难的问题。我们可以看到最重要的因素回报是由敏捷 4 和 7 获得的。

随机因子回报。来源:作者

相关性评估

当我们这样想的时候,我们就能明白为什么 Numerai 使用相关性来评估。每个锦标赛参与者提交的预测本身就是一个丰富的超级因子——一个包含比典型因子更多信息的信号。Numerai 随后从这些由参与者独立产生的超级因素中寻求高额回报。如果因子回报很好,Numerai 可以简单地通过组合它们来操作,或者在某些情况下,可以从收集的单个因子中实现进一步的学习,以提高它们的性能。

风险因素作为一个特征

在这一章中,我们讨论如何将传统的风险因素作为机器学习的特征。首先,国别特征和行业特征很重要。

国家特色

Numerai 被认为在全球所有主要市场都有股票。在数字锦标赛的数据集中,个股的 id 是加密的,我们无从得知。不过,由于 Numerai Signals 公布了一份目标股票清单,我整理了一下。从股票总数来看,我怀疑它与当前的数字锦标赛相同。在数字信号列表中有 41 个国家,美国拥有最多的股票,其次是日本、韩国和英国。

这些可能不是简单地按国家合并,而是按地区(北美、南美、太平洋等)合并。).

每个市场的股票数量。来源:作者

在通常的风险模型中,国家特征被作为 0/1 分类变量引入。然而,数字数据集基本上是一个 5 分位数,并且每个分位数的数量在大多数特征中是相同的。因此,如果我以这种方式创建一个特性,我将对每个国家(或每个地区)的指数进行多元回归,然后使用 beta 作为该特性的分位数。

例如,如果我们这样做,日本股票相对于东京市场指数将具有更高的 beta,并且将被聚集在该特征的更大(或更小,取决于分类符号)分位数中。然后,如果 Numerai 中有一个国家特征,最大的分位数只提供信息,其余的没有信息。Numerai 的 analysis_and_tips 报道了某些特征在特征值为 0 或 1 时具有显著的特征,我认为可能就是这种情况。

作为参考,我展示了自 2010 年以来每个国家的相对回报率趋势。

每个国家的累积相对收益。来源:作者

行业特征

其次,行业特色很重要。在《股市奇才》中,史蒂夫·科恩指出,40%的股票价格变动是由市场决定的,30%是由行业决定的,剩下的 30%是由个人原因决定的。没有理由不包含这一行业特征。行业的定义各不相同,但 BARRA GEM 定义了 38 个行业。此外,GICS 定义了 60 个部门,FactSet 的 RBICS 定义了 12 个经济体、31 个部门和 89 个子部门。作为参考,美国市场按经济体划分的股票数量如下所示。

美国市场各行业股票数量。来源:作者

行业特征也可以用行业指数上的多元回归贝塔进行量化,就像国家特征的情况一样。同样在这种情况下,只有最大的分位数是有信息的,其余的没有信息。

作为参考,我展示了自 2010 年以来美国市场各行业的相对回报率趋势。

各行业累计相对收益。来源:作者

风险指数特征

风险指数很可能包含 BARRA 中使用的那些指标。它们是规模、价值、成功(势头)和波动性。这些可以简单地合并,但考虑到国家和行业的偏差,通常按类别进行标准化。

对于规模指数,可以考虑诸如销售额、总资产和雇员人数以及市场资本总额等因素。对于价值指数,可以考虑市净率、市盈率、现金流比。其他风险指数包括流动性、增长、股息和财务杠杆。除了这些传统的风险指数之外,还可以纳入其他变量,如从新闻中提取的分析师修正值和情绪指数。

作为参考,我展示了 2010 年以来美国市场各风险指数的相对收益趋势。

每个风险因素的累积相对回报。来源:作者

融合传统定量方法和现代机器学习

在这一章中,我们将讨论如何使用机器学习来提高传统量化指标的性能。

树形模型

BARRA 模型只是单个风险因素的加权组合。有一种简单易行的方法可以改善这种情况。即考虑个体风险因素之间的相互作用。

举个简单的例子,有些行业更有可能是价值导向的,有些则不是。如果我们看股票的大小,有一个因素最适合大盘股,也有一个因素最适合小盘股。此外,不同的行业在不同的国家表现出色。

为了考虑这种相互作用,线性模型是不够的。在线性模型中,交互变量必须由人指定并设置为特征。在基于树的模型的情况下,模型可以在没有任何特定意图的情况下自己学习交互。另一方面,基于树的模型不善于理解原始 BARRA 模型的风险溢价,因为由于网格状划分,它们不善于线性分类。

对此的解决方案是线性和树模型的集合或堆叠。事实上,在 Kaggle 举行的两次适马金融竞赛中,岭回归和 ExtraTrees 的组合获得了好奖[5]。

在 Kaggle 举行的双西格玛金融挑战赛中获得第五名。来源:[5]

深层因素模型

另一方面,也有在模型中使用深度学习的情况。这是一种叫做深度因子模型的技术[6]。在常规的量化管理中,基金经理根据他或她的经验创建和选择因素,但深度因素模型旨在通过用深度学习取代人类判断来消除人类判断,从而捕捉单个因素的非线性。

该方法使用 80 个因素来预测月度回报,并已被证实能够优于线性模型和其他机器学习方法(SVR 和随机森林)做出的预测。

深度因子模型。来源:[6]

我认为,通过这种方式混合机器学习,相对容易胜过传统的量化模型。但另一方面,模型的复杂性可能会降低其可解释性,可能存在过学习和窥探偏差等陷阱,因此机器学习模型的构建需要金融领域特有的知识和直觉。关于这方面的更多技术技巧,我们应该参考 Numerai 首席科学顾问 Prado 的《金融机器学习》一书[7]。

结论

在本文中,我解释了传统定量方法的概念,然后描述了一种将传统风险因素作为一种特征的方法,并展示了如何将传统定量方法和现代机器学习融合在一起。这样,显著提高预测性能是可行的。

我也希望读者通过了解如何在传统的量化方法的基础上观察市场,对实际的市场更感兴趣,这将使对数字的分析更加愉快。

希望这篇文章能激发读者的好奇心,启发读者的预测模型。谢谢你看完。

UKI

参考

[1]巴尔·罗森博格、马拉泰·维奈,《投资风险的预测:系统性和剩余风险》,1975 年
[2]彼得·伯恩斯坦,《资本理念:现代华尔街的不可思议的起源》,1992 年
[3]巴拉全球股票模型手册
[4]理查德·格林诺德、罗纳德·卡恩,《主动投资组合管理》,1995 年
[5]团队最佳拟合,《两次适马金融建模代码竞赛,第 5 名获奖者访谈》,2017 年
[6]中川圭佑

数字阵列—您想知道的一切

原文:https://towardsdatascience.com/numpy-array-all-you-want-to-know-d3f8503a2f8f?source=collection_archive---------49-----------------------

如果您对 NumPy 数组有问题,请从阅读本文开始。

对于任何数据科学家来说,最具挑战性的步骤之一是理解如何使用和修改 NumPy 数组。今天,您将从库的角度学习关于数组的核心概念。我们一起潜水吧!

图片由 Pixabay — Pexels 提供

目录

  • 什么是 NumPy 数组
  • 关于异次元
  • 如何创建 NumPy 数组?
  • 用整形修改
  • 使用 NumPy 的操作
  • 转置你的数组
  • 带 NumPy 的条件
  • 额外的

什么是 NumPy 数组?

相同类型的数字表,由非负整数元组索引,也称为多维数组。

NumPy 的数组和标准数组的主要区别是后者只处理一维数组,提供的功能较少。

关于不同的维度

在我们开始讨论 NumPy 数组之前,有必要知道我们有哪些类型的维度。是的,他们有不同的名字,以后会引起一些误解。首先,让我们从标量开始。

图片由雷南·洛里科拍摄——中号

1.数量

也称为零阶张量;例如,它可以是任何有/没有单位、数量的数字,甚至是向量的函数。有量,无维度。

2.矢量

一阶张量;通常是单个数字的有序数组,表示为矩阵的一行(或一列)。只需要一个尺寸

  • 从向量及其以外,都将有大小和维度

3.[数]矩阵

二阶张量;就是一个由多行(或多列)数字组成的矩形数组。为了简单起见,矩阵是由几个向量组成的。

4.张量

封装标量、向量和矩阵。它们可以代表从零到 N 维的任何东西,这使得它们在深度学习中非常有用。张量可以是不同阶的,但通常我们用三阶或四阶;最后一个更复杂。

如何创建 NumPy 数组?

有几种方法可以创建数组。您可以从头开始生成数据,并使用生成的数据填充您的列,或者使用您已经拥有的数据,并将其转换为 NumPy 数组。让我们逐一讨论。

当你已经有了数据

这非常简单:只需将数据转换成一个数组。对于这个例子,我将创建一个熊猫系列。让我们检查一下。

图片由雷南·洛里科拍摄——中号

多好啊!我们把我们的系列变成了 ndarray!现在我们可以开始将我们的数学工具应用于这些数据了!还有一点:如果你不知道什么是系列, 点击这里 学习。

从头开始生成数据

当您需要处理操作、条件和循环时,创建新数据非常有用。不用生成完整的数字列表,只需将开始、停止和步进参数传递给 NumPy 数组。有些函数甚至不需要这些参数!我们去看看。

1) np.arange()

你想用生成一个具有均匀间隔值的元素数组吗?所以试试 np.arange()函数。当你需要创建快速列表时,这是非常有用的。让我们检查代码。

来自 NumPy 文档:

  • 对于整数参数,该函数相当于 Python 内置的 range 函数,但是返回的是 ndarray 而不是 list
  • 当使用非整数步长时,如 0.1,结果通常不一致。这些情况最好使用 numpy.linspace。

2) np.linspace()

这与上面描述的非常相似,但有一个具体的区别:当在这里处理非常小的数字时,你不会受到影响,有更多的参数要定义,并且你不需要定义任何步骤,只需要在你的数组上有多少个数字,让我们看看。

3) np.random()

这是一个非常大的模块,每个案例都有许多特定的功能;当需要随机创建数字时,它被广泛使用。我将集中讨论最常用的方法。

numpy.random.randint()

从“半开”区间[ ]中指定数据类型的“离散均匀”分布中返回随机整数。如果为 None(缺省),那么结果是从【0,】低)”。来自文档

图片由雷南·洛里科拍摄——中号

纪念

  • 如果尺寸参数大于高值,将重复输出。

numpy.random.random()

“返回半开区间[0.0,1.0]内的随机浮点数”。来自文档

图片由雷南·洛里科拍摄——中号

纪念

  • 值的范围从 0.0 到小于 1.0。

numpy.random .指数()

“从指数分布中抽取样本”。来自文档

图片由雷南·洛里科拍摄——中号

还有更多值得探索的地方!想看看吗? 点击这里 查看随机模块。

4 ) np.ones()和 np.zeros()

在你的任务中,可能需要创建只有 1 或 0 的 n 维数组,谁知道呢?NumPy 有这方面的函数,我们来看看. np.eye()

输出将是只有 1 或 0 的数组,如下所示。

图片由雷南·洛里科拍摄——中号

5) np.eye()

创建一个 0 和 1 的数组(数字 1 创建一条对角线);您可以毫不费力地找到该函数的实用程序。

图片由雷南·洛里科拍摄——中号

用整形修改 NumPy 数组

这是任何使用 NumPy 的人都必须知道的。在使用神经网络和深度学习时,重塑我们的阵列是一个至关重要的过程。

在调整形状期间,您可以修改阵列的格式,即行数、列数和维数。让我们用代码试试。

随着整形改变了数组的形状,我们将检查输出。

图片由雷南·洛里科拍摄——中号

别忘了

如果乘法产生的元素数量与之前不同,则不能修改尺寸。如果你有 20 个元素,你可以改造成(4,5),(5,4),(2,2,5),等等。

使用 NumPy 的操作

看看你的学习变得多么优秀!我们现在学到了很多东西,但是还有更多隐藏的东西!我们需要学习如何使用一些数字操作功能。

例如,因为你是数据科学家,所以没有理由解释 sum 函数是做什么的。因此,我将创建一个包含一些非常重要的操作的代码片段,并讨论输出。

图片由雷南·洛里科拍摄——中号

我们有两个每 5 列 2 行的矩阵。上面,你可以查看每个操作的输出。这里没有什么玄机,但是如果你是新手,我会解释元素式乘法和点积的区别。

元素式产品

图片来自维基百科— 哈达玛产品

也称为哈达玛乘积,是一种二元运算,它采用两个维数相同的矩阵,并生成另一个维数相同的矩阵作为操作数。每个元素都是原始两个矩阵元素的乘积。看看下面的例子。

图像通过矩阵乘法

点积

简单来说,点积就是两个数列对应项的乘积之和。没有比这更简单的方法了。用一个数字来理解吧。

图片由可汗学院

当我们需要直接处理数组时,点积广泛用于机器学习;通常当我们使用梯度下降法时。由于是高级内容,我推荐你去看看 这篇可汗学院关于矩阵乘法的文章

转置你的数组

转置矩阵是使用点积非常必要的功能,但它并不止于此:

  • 熊猫图书馆允许你的数据框架使用转置;
  • 您可以使用它来快速反转您的数组的列和行,用于任何您想要的目的;

因此,您将翻转您的行与列!

图片由雷南·洛里科拍摄——中号

有条件带 NumPy

最后,我想和大家分享两个用 NumPy 进行条件选择的有用函数:np.where()和 np.select()。两者都广泛用于熊猫,是本馆必备。

np.where()

np.where (条件,真则返回,假则返回)

首先,您传递您的布尔条件;然后,需要加上条件结果为真时要返回的值;最后,相反(如果假)。通过代码你会更好地理解它。

图片由雷南·洛里科拍摄——中号

别忘了:np.where()只有在需要用条件返回一两个值的时候才有用。如果有更多的值,请使用 np.select()。

np.select()

NP . select(cond list,choicelist,default)

选择功能可以处理两个以上的条件,例如,当您需要应用 数据宁滨 时,它非常有用。在这里,您将一个条件列表传递给选项列表;两者将一起填充新列表。默认参数是不满足条件时使用的值。

图片由雷南·洛里科拍摄——中号

额外的

如果不先教你如何洗牌,我还是无法完成这篇文章。在训练机器学习算法时,这是一个非常重要的过程,以避免过度调整。还可以找到其他很棒的资源!

numpy.random.shuffle()

"通过混洗其内容来就地修改序列。这个函数只沿着多维数组的第一个轴打乱数组。子数组的顺序改变了,但它们的内容保持不变”。来自文档

图片由雷南·洛里科拍摄——中号

纪念

  • shuffle 函数返回 None,它只是打乱原始数组,给值分配一个新的顺序。

就这样,伙计们!

我希望你喜欢这个内容,并能熟练运用你的新知识!如果你想每天学习有趣的东西,我很乐意与你分享精彩内容!

另外,你可以在 Github 上查看我的个人资料。我从事一些数据科学项目已经有一段时间了。所有的关键概念都可以学习和重用!

[## 雷南·洛利科-吉图布

在 GitHub 上注册你自己的个人资料,这是托管代码、管理项目和构建软件的最佳地方…

github.com](https://github.com/renfelo)

文献学

Numpy 数组指南:在 Python 中生成和操作数组

原文:https://towardsdatascience.com/numpy-array-cookbook-generating-and-manipulating-arrays-in-python-2195c3988b09?source=collection_archive---------10-----------------------

我的 numpy 数组清单

我曾经作为一名数据科学家毫无准备地走进一家公司。虽然我期望成为训练模型,但我的角色却是软件工程,这个应用程序使用了我所见过的最大量的 numpy。

虽然我已经多次使用np.array()将一个列表转换成一个数组,但我并没有为一行又一行的linspacemeshgridvsplit做好准备。

如果我想能够读写代码,我需要尽快熟悉 numpy。

这是我为自己构建的 numpy 数组函数和示例的精选列表。

我们将在第一部分介绍数组的背景信息,然后讨论一些高级函数,这些函数将帮助您更快地处理数据。

目录:1。阵列概述
2。生成数组
3。操纵数组

1)阵列概述

什么是数组?

数组是存储同类数据的数据结构。这意味着所有的元素都是同一类型。

Numpy 的数组类是ndarray,意思是“N 维数组”。

import numpy as nparr = np.array([[1,2],[3,4]])
type(arr)#=> numpy.ndarray

它是 n 维的,因为它允许根据初始化时传递的形状创建几乎无限维的数组。

例如: np.zeros((2))生成一个 1D 数组。np.zeros((2,2))生成一个 2D 数组。np.zeros((2,2,2))生成一个 3D 数组。np.zeros((2,2,2,2))生成一个 4D 数组。诸如此类…

**np.zeros((2))**
#=> array([0., 0.])**np.zeros((2,2))**
#=> array([[0., 0.],
#=>        [0., 0.]])**np.zeros((2,2,2))**
#=> array([[[0., 0.],
#=>         [0., 0.]],
#=> 
#=>        [[0., 0.],
#=>         [0., 0.]]])
...

数组与列表

  • 数组比列表使用更少的内存
  • 阵列有更多的功能
  • 数组要求数据是同质的;列表不
  • 数组上的算术运算类似于矩阵乘法

重要参数

shape: 表示数组维数的元组。形状为(2,3,2)的数组是一个 2×3×2 的数组。看起来像下面。

np.zeros((2,3,2))#=> array([[[0., 0.],
#=>         [0., 0.],
#=>         [0., 0.]],
#=> 
#=>        [[0., 0.],
#=>         [0., 0.],
#=>         [0., 0.]]])

dtype: 存储在数组中的值的类型。数组是同质的,所以我们不能混合多种数据类型,如字符串和整数。dtype的值可以是np.float64np.int8intstr几种其他类型中的一种。

2)生成数组

零点

生成具有指定形状的零数组。

当您希望在开始训练之前将 ML 模型中的权重初始化为 0 时,这很有用。这也常用于初始化一个具有特定形状的数组,然后用您自己的值覆盖它。

np.zeros((2,3))
#=> array([[0., 0., 0.],
#=>        [0., 0., 0.]])

一念之差

生成具有指定形状的一个数组。

如果您需要在增量相减之前将值初始化为 1,这很有用。

np.ones((2,3))
#=> array([[1., 1., 1.],
#=>        [1., 1., 1.]])

空的

np.empty()与 0 和 1 略有不同,因为它没有在数组中预设任何值。有些人说初始化稍微快一点,但这可以忽略不计。

为了代码可读,在用数据填充数组之前初始化数组时,有时会用到这种方法。

arr = np.empty((2,2))
arr
#=> array([[1.00000000e+000, 1.49166815e-154],
#=>        [4.44659081e-323, 0.00000000e+000]])

全部

用给定值初始化数组。

下面我们用10初始化一个数组。然后是另一个有['a','b']对的数组。

**np.full((3,2), 10)**
#=> array([[10, 10],
#=>        [10, 10],
#=>        [10, 10]])**np.full((3,2), ['a','b'])**
#=> array([['a', 'b'],
#=>        ['a', 'b'],
#=>        ['a', 'b']], dtype='<U1')

排列

这可能是你在现实生活中见过最多的。它从一个“类数组”对象初始化一个数组。

如果您将数据存储在另一种数据结构中,但需要将其转换为 numpy 对象以便传递给 sklearn,这将非常有用。

li = ['a','b','c']
np.array(li)#=> array(['a', 'b', 'c'], dtype='<U1')

注意: *np.array* 还有一个参数叫做 *copy* ,可以设置为 *True* 来保证生成一个新的数组对象,而不是指向一个已有的对象。

_ 喜欢

有几个_like函数对应于我们已经讨论过的函数:empty_likeones_likezeros_likefull_like

它们生成的数组与传入的数组形状相同,但具有自己的值。所以ones_like生成一个 1 的数组,但是你传递给它一个现有的数组,它取那个数组的形状,而不是你直接指定形状。

a1 = np.array([[1,2],[3,4]])
#=> array([[1, 2],
#=>        [3, 4]])np.ones_like(a1)
#=> array([[1, 1],
#=>        [1, 1]])

请注意第二个 1 的数组是如何呈现第一个数组的形状的。

边缘

用随机值生成一个数组。

当您希望将模型中预先训练的权重初始化为随机值时,这很有用,这可能比将它们初始化为零更常见。

np.random.rand(3,2)
#=> array([[0.94664048, 0.76616114],
#=>        [0.395549  , 0.84680126],
#=>        [0.42873   , 0.77736086]])

阿萨瑞

np.asarraynp.array的包装器,设置参数copy=False。参见上面的np.array

阿兰格

生成一个值数组,其间隔设置在上限和下限之间。这是 numpy 版本的list(range(50,60,2))列表。

下面我们生成一个 50 到 60 之间的每秒值的数组。

np.arange(50,60,2)
#=> array([50, 52, 54, 56, 58])

林空间

生成两个其他数字之间间隔相等的数字数组。我们不是像arange那样直接指定区间,而是指定在上限和下限之间生成多少个数。

下面我们返回一个由 10 到 20 之间的 6 个数字和 0 到 2 之间的 5 个数字组成的数组。

np.linspace(10, 20, 6)
#=> array([10., 12., 14., 16., 18., 20.])np.linspace(0, 2, 5)
#=> array([0\. , 0.5, 1\. , 1.5, 2\. ])

请注意,我们是如何指定数组中元素的数量,而不是指定区间本身的。

网格

基于两个输入数组生成坐标矩阵。

这可能有点棘手。让我们看一个例子。生成 2 个数组并将它们传递给np.meshgrid

x = np.array([1,2,3])
y = np.array([-3,-2,-1])

xcors, ycors = np.meshgrid(x, y) xcors
#=> [[1 2 3]
#=> [1 2 3]
#=> [1 2 3]]ycors
#=> [[-3 -3 -3]
#=> [-2 -2 -2]
#=> [-1 -1 -1]]

在这里,我们可以看到两个不同的矩阵输出,基于输入数组的值和形状。

但是不要把它想象成两个独立的矩阵。这些实际上是一对(x,y)坐标,代表平面上的点。下面我把它们组合起来了。

[[(1, -3), (2, -3), (3, -3)]
 [(1, -2), (2, -2), (3, -2)],
 [(1, -1), (2, -1), (3, -1)]]

3)操纵数组

复制

制作现有阵列的副本。

将一个数组赋给一个新的变量名将会指向原来的数组。你需要小心这种行为,这样你就不会无意中修改现有的变量。

考虑这个例子。虽然我们修改了a2,但是a1的值也会改变。

a1 = np.array([1,2,3])
a2 = a1a2[0] = 10
a1
#=> array([10,  2,  3])

现在比较一下这个。我们修改了a2但是a1没有改变…因为我们做了一个拷贝!

a1 = np.array([1,2,3])
a2 = a1.copy()a2[0] = 10
a1
#=> array([1, 2, 3])

形状

获取数组的形状。

在处理大规模多维数组时非常有用,因为无法观察维度。

a = np.array([[1,2],[3,4],[5,6]])
a.shape
#=> (3, 2)

使再成形

重塑数组。

这非常有用,我无法想象没有它会使用像 Keras 这样的库。让我们看一个创建和整形数组的例子。

生成一个数组。

a = np.array([[1,2],[3,4],[5,6]])
a
#=> array([[1, 2],
#=>        [3, 4],
#=>        [5, 6]])

检查它的形状。

a.shape
#=> (3, 2)

将阵列从 3x3 调整为 2x3。

a.reshape(2,3)
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])

将数组展平为一维。

a.reshape(6)
#=> array([1, 2, 3, 4, 5, 6])

将阵列重新整形为 6x1 矩阵。

a.reshape(6,1)
#=>array([[1],
#=>       [2],
#=>       [3],
#=>       [4],
#=>       [5],
#=>       [6]])

将数组重塑为 3 维,2x3x1。

a.reshape(2,3,1)
#=> array([[[1],
#=>         [2],
#=>         [3]],
#=> 
#=>        [[4],
#=>         [5],
#=>         [6]]])

调整大小

类似于reshape但是它改变了原来的数组。

a = np.array([['a','b'],['c','d']])
a
#=>array([['a', 'b'],
#=>       ['c', 'd']], dtype='<U1')a.reshape(1,4)
#=> array([['a', 'b', 'c', 'd']], dtype='<U1')a
#=>array([['a', 'b'],
#=>       ['c', 'd']], dtype='<U1')a.resize(1,4)
a
#=> array([['a', 'b', 'c', 'd']], dtype='<U1')

注意调用reshape并没有改变a,但是调用resize却永久地改变了它的形状。

移项

转置一个数组。

在生成 pandas 数据框或进行计数或求和等聚合计算之前,我们可以交换行和列吗?

a = np.array([['s','t','u'],['x','y','z']])
a
#=> array([['s', 't', 'u'],
#=>        ['x', 'y', 'z']], dtype='<U1')a.T
#=> array([['s', 'x'],
#=>        ['t', 'y'],
#=>        ['u', 'z']], dtype='<U1')

注意所有的东西是如何在sz之间的对角线上翻转的。

变平

将数组展平为一维并返回一个副本。

这实现了与下面的reshape(6)相同的结果。但是当您事先不知道数组的大小时,flatten会很有用。

a = np.array([[1,2,3],['a','b','c']])
a.flatten()
#=> array(['1', '2', '3', 'a', 'b', 'c'], dtype='<U21')a.reshape(6)
#=> array(['1', '2', '3', 'a', 'b', 'c'], dtype='<U21')

解开…的纠结

将类似数组的对象展平为一维。类似于flatten,但是它返回数组的视图而不是副本。

最大的好处是它可以用在非数组上,比如列表,而在列表中flatten会失败。

np.ravel([[1,2,3],[4,5,6]])
#=> array([1, 2, 3, 4, 5, 6])np.flatten([[1,2,3],[4,5,6]])
#=> AttributeError: module 'numpy' has no attribute 'flatten'

hsplit

将数组水平分割成子数组。

您可以将这想象成将矩阵中的每一列拆分成自己的数组。

如果每一列描述一个对象,每一行是这些对象的一个时间段,则在 ML 中用于拆分时间序列数据。

a = np.array(
    [[1,2,3],
     [4,5,6]])
a
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])np.hsplit(a,3)# #=> [array([[1],[4]]), 
# #=>  array([[2],[5]]), 
# #=>  array([[3],[6]])]

vsplit

将数组垂直拆分成子数组。

您可以将这想象成将每一行拆分成自己的列。

如果每一行代表一个对象,每一列是这些对象的一个不同的特性,那么在 ML 中就很有用。

a = np.array(
    [[1,2,3],
     [4,5,6]])
a
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])np.vsplit(a,2)#=> [array([[1, 2, 3]]), 
#=> array([[4, 5, 6]])]

连接轴上的数组。

这本质上与vsplithsplit相反,它将独立的数组组合成一个数组。

沿着axis=0

a = np.array(['a', 'b', 'c'])
b = np.array(['d', 'e', 'f'])np.stack((a, b), axis=0)
#=> array([['a', 'b', 'c'],
#=>       ['d', 'e', 'f']], dtype='<U1')

沿着axis=1

a = np.array(['a', 'b', 'c'])
b = np.array(['d', 'e', 'f'])np.stack((a, b), axis=1)
#=> array([['a', 'd'],
#=>        ['b', 'e'],
#=>        ['c', 'f']], dtype='<U1')

结论

我认为这是 numpy 的基础。当您在工作中阅读现有代码或在线学习教程时,您会反复遇到这些函数。

熟悉以上内容意味着你不会陷入理解如何使用meshgrid来生成 matplotlib 图表的困境。或者如何快速添加维度,使您的数据符合 Keras 模型的输入要求。

有哪些你离不开的 numpy 函数?

NumPy 数组操作

原文:https://towardsdatascience.com/numpy-array-manipulation-5d2b42354688?source=collection_archive---------26-----------------------

修改数组形状的实用指南

数据科学的一切都始于数据,数据有多种格式。数字、图像、文本、x 光、声音和视频记录只是数据源的一些例子。无论数据以何种格式传入,都需要转换成数字数组进行分析。复杂的计算机视觉模型无法像人类一样看到或处理图像。在分析之前,图像被转换成一组数字。因此,在数据科学中有效地存储和修改数字数组是至关重要的。NumPy(数字 Python)是一个科学计算包,它提供了非常实用的方法来创建和操作数字数组。

阿里·耶尔马兹Unsplash 拍摄的照片

在这篇文章中,我将介绍在 NumPy 中使用以下操作来操作数组形状的方法:

  • 使再成形
  • 扩展 _ 变暗
  • 散开并弄平

如果你想了解 NumPy 的基础知识,你可以访问下面的帖子:

[## 数据科学中最被低估的工具:NumPy

NumPy 的强大功能以及如何有效地使用它

towardsdatascience.com](/the-most-underrated-tool-in-data-science-numpy-68d8fcbde524)

让我们从导入 NumPy 开始:

import numpy as np

提示:就存储和处理而言,NumPy 数组比列表有效得多。

重塑

Numpy 提供了灵活的工具来改变数组的维数。在更改维度之前,最好记住数组的维度是什么意思,以及不同维度的数组是什么样子:

a = np.random.randint(10, size=5)
a
array([9, 7, 3, 7, 5])a.ndim
1a.shape
(5,0)

我们还可以用 numpy 创建多维数组:

# 2-dimensional
b = np.zeros((3,4))b
array([[0., 0., 0., 0.],        
       [0., 0., 0., 0.],        
       [0., 0., 0., 0.]])b.ndim
2# 3-dimensional
c = np.ones((2,2,2))c
array([[[1., 1.],         
        [1., 1.]],

        [[1., 1.],         
         [1., 1.]]])c.ndim
3

有不同的方法来改变数组的维数。 Reshape 函数通常用于修改数组的形状和维度。我们只需要将新形状作为参数传递给 shape 函数:

提示:举例来说,我在创建数组时使用了不同的方法,这样您也可以熟悉如何创建数组。

np.arange(6)
array([0, 1, 2, 3, 4, 5])np.arange(6).reshape(2,3)
array([[0, 1, 2],        
       [3, 4, 5]])

shape (2,3)返回一个 2 行 3 列的二维新数组。因此,我们应用 reshape(2,3)的数组必须是 6 个元素。

让我们也使用 reshape 创建一个三维数组:

np.arange(8).reshape(2,2,2)array([[[0, 1],         
        [2, 3]],                 [[4, 5],         
         [6, 7]]])

reshape 函数的一个非常有用的特性是,如果不知道原始数组中元素的数量,可以将其中一个维度指定为“-1”。

因为我们几乎总是使用非常大的数组,所以键入(-1,1)而不是(100000,1)也很方便。

提示:调整数组形状时,新形状需要与原始形状兼容。

np.arange(6).reshape(-1,2)
array([[0, 1],        
       [2, 3],        
       [4, 5]])np.arange(6).reshape(-1,3)
array([[0, 1, 2],        
       [3, 4, 5]])

也可以在不改变元素顺序的情况下增加维度。我们可以通过整形(-1,1)或(1,-1)来实现:

np.random.normal(0,1,3)
array([-0.14788456,  0.01909406,  0.88659889])np.random.normal(0,1,3).reshape(-1,1)
array([[-0.14588167],        
       [ 0.06871804],        
       [ 2.32699261]])np.random.normal(0,1,3).reshape(1,-1)
array([[ 1.46812451,  0.48818206, -0.80228877]])

Expand_dims

顾名思义, expand_dims 扩展一个数组的形状。

a = np.array([1,2,3])np.expand_dims(a, axis=0)
array([[1, 2, 3]])np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])

轴参数允许选择通过哪个轴进行扩展。

axis=1 的 expand_dims 等效于 shape(-1,1)。

np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])

拆卷压平

Ravel 返回一个扁平数组。如果你熟悉卷积神经网络(CNN),汇集的特征映射在馈送到完全连接的层之前被展平。该操作将二维数组转换为一维数组。

a = np.random.randint(10, size=(2,3))
aarray([[6, 8, 2],        
       [5, 1, 8]])np.ravel(a)
array([6, 8, 2, 5, 1, 8])

第二行连接在第一行的末尾。Ravel 函数还允许使用顺序参数进行列级连接:

np.ravel(a, order='F')
array([6, 5, 8, 1, 2, 8])

展平也执行相同的操作:

array([[3, 5, 2],        
       [6, 7, 8]])a.flatten()
array([3, 5, 2, 6, 7, 8])

松散和展平的区别:

  • Ravel:尽可能返回原始数组的视图。
  • Flatten:总是返回原始数组的副本。

因此,您在 flatten 返回的数组上所做的更改将永远不会在原始数组上进行。但是,如果通过 ravel 修改返回的数组,也可能会改变原始数组。让我们看一个例子来说明这一点:

array([[3, 5, 2],        
       [6, 7, 8]])a.flatten()[0] = 10
a
array([[3, 5, 2],        
       [6, 7, 8]])np.ravel(a)[0] = 10
a
array([[**10**,  5,  2],        
       [ 6,  7,  8]])

如你所见,我们在 ravel 上所做的改变也改变了原始数组。

感谢您的阅读。如果您有任何反馈,请告诉我。

采用 Cython 的 NumPy 阵列处理:速度提高 5000 倍

原文:https://towardsdatascience.com/numpy-array-processing-with-cython-1250x-faster-a80f8b3caa52?source=collection_archive---------14-----------------------

本教程将向您展示如何使用 Cython 加速 NumPy 数组的处理。通过在 Python 中显式指定变量的数据类型,Cython 可以在运行时大幅提高速度。

茱莉亚·乔皮恩:【https://unsplash.com/photos/IojCPQ2rWe8】T2

本教程涵盖的部分如下:

  • 遍历 NumPy 数组
  • NumPy 数组的 Cython 类型
  • NumPy 数组元素的数据类型
  • NumPy 数组作为函数参数
  • 对 NumPy 数组进行索引,而不是迭代
  • 禁用边界检查和负索引
  • 摘要

关于 Cython 及其使用方法的介绍,请查看我在上发表的关于使用 Cython 提升 Python 脚本的帖子。要不,我们开始吧!

[## 使用 Cython | Paperspace 博客提升 Python 脚本

Python 可能是当今最流行的编程语言之一,但它肯定不是最高效的。在…

blog.paperspace.com](https://blog.paperspace.com/boosting-python-scripts-cython/)

遍历 NumPy 数组

我们将从与上一教程相同的代码开始,除了这里我们将遍历一个 NumPy 数组而不是一个列表。NumPy 数组是使用 arrange()函数在 arr 变量中创建的,该函数从 0 开始以 1 为步长返回 10 亿个数字。

import time
import numpytotal = 0
arr = numpy.arange(1000000000)t1 = time.time()
for k in arr:
    total = total + k
t2 = time.time()print("Total = ", total)
t = t2 - t1
print("%.20f" % t)

我在一台配备 Core i7–6500 u CPU @ 2.5 GHz 和 16 GB DDR3 RAM 的机器上运行这个程序。Python 代码在 458 秒(7.63 分钟)内完成。太长了。

让我们看看在编辑了在之前的教程中创建的 Cython 脚本后,需要多长时间才能完成,如下所示。唯一的变化是在 for 循环中包含了 NumPy 数组。请注意,在使用 Cython 脚本之前,您必须使用下面的命令来重新构建它。

python setup.py build_ext --inplace

当前形式的 Cython 脚本在 128 秒(2.13 分钟)内完成。仍然很长,但这是一个开始。让我们看看如何让它更快。

NumPy 数组的 Cython 类型

之前我们看到,在为所使用的变量显式定义 C 类型后,Cython 代码运行得非常快。NumPy 数组也是这种情况。如果我们保留 NumPy 数组的当前形式,Cython 的工作方式与常规 Python 完全一样,为数组中的每个数字创建一个对象。为了让事情运行得更快,我们还需要为 NumPy 数组定义一个 C 数据类型,就像为任何其他变量一样。

NumPy 数组的数据类型为 ndarray ,代表 n 维数组。如果您使用关键字 int 来创建整数类型的变量,那么您可以使用 ndarray 来创建 NumPy 数组的变量。注意n array必须使用 NumPy 调用,因为n array在 NumPy 内部。因此,创建 NumPy 数组变量的语法是 numpy.ndarray 。下面列出的代码创建了一个名为 arr 的变量,数据类型为 NumPy ndarray

首先要注意的是,NumPy 是使用第二行中的常规关键字 import 导入的。在第三行,您可能会注意到 NumPy 也是使用关键字 cimport 导入的。

现在我们来看看 Cython 文件可以分为两类:

  1. 定义文件(。pxd)
  2. 实现文件(。pyx)

定义文件的扩展名为。pxd,用于保存 C 声明,例如要导入并在其他 Cython 文件中使用的数据类型。另一个文件是带有扩展名的实现文件。pyx,我们目前用它来编写 Cython 代码。在这个文件中,我们可以导入一个定义文件来使用其中声明的内容。

下面的代码将被写入扩展名为. pyx 的实现文件中。 cimport numpy 语句在 Cython 中导入一个名为“numpy”的定义文件。这样做是因为 cy thon“numpy”文件具有处理 NumPy 数组的数据类型。

下面的代码定义了前面讨论的变量,分别是 maxvaltotalkt1t2t 。有一个名为 arr 的新变量保存数组,数据类型numpy.ndarray。之前使用了两个导入语句,即import numpycimport numpy。这里哪一个是相关的?这里我们将使用需要的cimport numpy,而不是常规的import。这让我们可以访问在 Cython numpy 定义文件中声明的 numpy.ndarray 类型,因此我们可以将 arr 变量的类型定义为 numpy.ndarray。

maxval 变量被设置为等于 NumPy 数组的长度。我们可以从创建一个长度为 10,000 的数组开始,并在以后增加这个数字,以比较 Cython 相对于 Python 的改进。

import time
import numpy
cimport numpycdef unsigned long long int maxval
cdef unsigned long long int total
cdef int k
cdef double t1, t2, t
cdef numpy.ndarray arrmaxval = 10000
arr = numpy.arange(maxval)t1 = time.time()for k in arr:
    total = total + k
print "Total =", totalt2 = time.time()
t = t2 - t1
print("%.20f" % t)

在创建了一个类型为numpy.ndarray的变量并定义了它的长度之后,接下来是使用numpy.arange()函数创建数组。注意,这里我们使用的是 Python NumPy,它是使用import numpy语句导入的。

通过运行上面的代码,Cython 只用了 0.001 秒就完成了。对于 Python,代码耗时 0.003 秒。在这种情况下,Cython 比 Python 快近 3 倍。

maxsize变量设置为 100 万时,Cython 代码运行 0.096 秒,而 Python 需要 0.293 秒(Cython 也快了 3 倍)。当处理 1 亿个时,Cython 需要 10.220 秒,而 Python 需要 37.173 秒。对于 10 亿,Cython 需要 120 秒,而 Python 需要 458 秒。尽管如此,Cython 可以做得更好。让我们看看怎么做。

NumPy 数组元素的数据类型

第一个改进与数组的数据类型有关。NumPy 数组arr的数据类型根据下一行定义。注意,我们所做的只是定义数组的类型,但是我们可以给 Cython 更多的信息来简化事情。

请注意,没有任何东西可以警告您有一部分代码需要优化。一切都会起作用;你必须调查你的代码,找出可以优化的部分,以便运行得更快。

cdef numpy.ndarray arr

除了定义数组的数据类型,我们还可以定义两条信息:

  1. 数组元素的数据类型
  2. 维度数量

数组元素的数据类型是int,根据下面的代码行定义。使用 cimport 导入的 numpy 有一个对应于 NumPy 中每种类型的类型,但在末尾有 _t 。比如常规 NumPy 中的 int 对应 Cython 中的 int_t

参数是ndim,它指定了数组中的维数。这里设置为 1。请注意,它的默认值也是 1,因此可以从我们的示例中省略。如果使用了更多的维度,我们必须指定它。

cdef numpy.ndarray[numpy.int_t, ndim=1] arr

不幸的是,只有当 NumPy 数组是函数中的一个参数或者函数中的一个局部变量时——而不是在脚本体中——才允许这样定义 NumPy 数组的类型。我希望 Cython 尽快解决这个问题。我们现在需要编辑前面的代码,将其添加到下一节将要创建的函数中。现在,让我们在定义数组之后创建它。

注意,我们将变量arr的类型定义为numpy.ndarray,但是不要忘记这是容器的类型。该容器包含元素,如果没有指定其他内容,这些元素将被转换为对象。为了强制这些元素为整数,根据下一行将dtype参数设置为numpy.int

arr = numpy.arange(maxval, dtype=numpy.int)

这里使用的 numpy 是使用cimport 关键字导入的。一般来说,无论何时发现用于定义变量的关键字 numpy,都要确保它是使用cimport关键字从 Cython 导入的。

NumPy 数组作为函数参数

准备好数组后,下一步是创建一个函数,它接受下面列出的类型为numpy.ndarray的变量。这个函数被命名为do_calc()

import time
import numpy
cimport numpyctypedef numpy.int_t DTYPE_t
def do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t

    t1 = time.time() for k in arr:
        total = total + k
    print "Total = ", total

    t2 = time.time()
    t = t2 - t1
    print("%.20f" % t)

构建完 Cython 脚本后,接下来我们根据下面的代码调用函数do_calc()

import test_cython
import numpy
arr = numpy.arange(1000000000, dtype=numpy.int)
test_cython.do_calc(arr)

这种情况下的计算时间从 120 秒减少到 98 秒。这使得 Cython 在对 10 亿个数字求和时比 Python 快 5 倍。正如你现在所期望的,对我来说这仍然不够快。我们将在下一节看到另一个加速计算的技巧。

NumPy 数组上的索引与迭代

Cython 只是将计算时间减少了 5 倍,这并不鼓励我使用 Cython。但这不是 Cython 的问题,而是使用的问题。问题在于循环是如何产生的。让我们仔细看看下面给出的循环。

在之前的教程中,提到了非常重要的一点,那就是 Python 只是一个接口。界面只是让用户觉得事情更简单。请注意,简单的方法并不总是做某事的有效方法。

Python 有一种特殊的方法来迭代数组,这在下面的循环中实现。循环变量 k 循环遍历 arr NumPy 数组,从数组中一个元素一个元素地取出。变量 k 被分配给这样的返回元素。以这种方式循环遍历数组是 Python 中引入的一种风格,但它不是 C 用于循环遍历数组的方式。

for k in arr:
    total = total + k

对于编程语言来说,循环遍历数组的通常方式是从 0(有时从 1)开始创建索引,直到到达数组中的最后一个索引。每个索引用于索引数组以返回相应的元素。这是循环遍历数组的正常方式。因为 C 不知道如何以 Python 风格遍历数组,所以上面的循环是以 Python 风格执行的,因此执行起来要花很多时间。

为了克服这个问题,我们需要创建一个普通样式的循环,使用索引for访问数组元素。新的循环实现如下。

首先,有一个名为arr _ shape的新变量用于存储数组中元素的数量。在我们的示例中,只有一个维度,其长度通过使用索引 0 索引 arr.shape 的结果来返回。

然后 arr_shape 变量被提供给range()函数,该函数返回访问数组元素的索引。在这种情况下,变量 k 代表一个索引,而不是一个数组值。

在循环内部,通过索引 k 对变量 arr 进行索引来返回元素。

cdef int arr_shape = arr.shape[0]
for k in range(arr_shape):
    total = total + arr[k]

让我们编辑 Cython 脚本来包含上面的循环。下面列出了新脚本。旧循环被注释掉了。

import time
import numpy
cimport numpyctypedef numpy.int_t DTYPE_tdef do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t
    cdef int arr_shape = arr.shape[0] t1=time.time()#    for k in arr:
#        total = total + k for k in range(arr_shape):
        total = total + arr[k]
    print "Total =", total

    t2=time.time()
    t = t2-t1
    print("%.20f" % t)

通过构建 Cython 脚本,在将循环改为使用索引后,对 10 亿个数字求和的计算时间现在大约只有一秒钟。所以,时间从 120 秒减少到仅仅 1 秒。这是我们对 Cython 的期望。

请注意,当我们使用 Python 风格遍历数组时,不会发生任何错误。没有迹象可以帮助我们找出代码没有优化的原因。因此,我们必须仔细寻找代码的每一部分,寻找优化的可能性。

注意,普通 Python 执行上述代码需要 500 多秒,而 Cython 只需要 1 秒左右。因此,对于 10 亿个数的求和,Cython 比 Python 快 500 倍。超级棒。记住,为了减少计算时间,我们牺牲了 Python 的简单性。在我看来,将时间减少 500 倍,值得使用 Cython 优化代码。

代码速度提高 500 倍固然很好,但还有一个改进,这将在下一节讨论。

禁用边界检查和负索引

Cython 文档中所述,导致代码变慢的因素有以下几个:

  1. 边界检查,以确保索引在数组的范围内。
  2. 使用负索引访问数组元素。

当 Cython 执行代码时,这两个特性是活动的。可以使用负索引(如-1)来访问数组中的最后一个元素。Cython 还确保没有索引超出范围,如果出现这种情况,代码不会崩溃。如果您不需要这些功能,您可以禁用它以节省更多时间。这是通过添加以下行来实现的。

cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)

禁用这些功能后的新代码如下:

import time
import numpy
cimport numpy
cimport cythonctypedef numpy.int_t DTYPE_t@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function
def do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t
    cdef int arr_shape = arr.shape[0] t1=time.time()#    for k in arr:
#        total = total + k for k in range(arr_shape):
        total = total + arr[k]
    print "Total =", total t2=time.time()
    t = t2-t1
    print("%.20f" % t)

构建并运行 Cython 脚本后,对 0 到 100000000 的数字求和的时间大约为 0.09 秒。与 Python 脚本大约 500 秒的计算时间相比,Cython 比 Python 快 5000 多倍。

在下一段代码中使用numpy.sum()函数的情况下,时间大约为 0.38 秒。那就是 Cython 快了 4 倍。

import numpy
import timearr = numpy.arange(100000000)t1 = time.time()
result = numpy.sum(arr)
t2 = time.time()
t = t2 - t1
print("%.20f" % t)

摘要

本教程使用 Cython 来提高 NumPy 数组处理的性能。我们通过四种不同的方式实现了这一目标:

1.定义 NumPy 数组数据类型

我们首先使用numpy.ndarray指定 NumPy 数组的数据类型。我们看到这个类型在使用cimport关键字导入的定义文件中是可用的。

2.指定数组元素的数据类型+维数

仅仅将numpy.ndarray类型赋给一个变量是一个开始——但这还不够。仍然需要提供两条信息:数组元素的数据类型和数组的维数。两者都对处理时间有很大影响。

只有当 NumPy 数组被定义为函数参数或函数内部的局部变量时,这些细节才会被接受。因此,我们在这些点上添加了 Cython 代码。您还可以指定函数的返回数据类型。

3.使用索引遍历 NumPy 数组

减少处理时间的第三种方法是避免 Pythonic 循环,在这种循环中,一个变量由数组中的值逐个赋值。相反,只需使用索引遍历数组。这导致时间的大量减少。

4.禁用不必要的功能

最后,您可以通过禁用 Cython 中为每个函数默认完成的一些检查来减少一些额外的毫秒数。这些包括“边界检查”和“回绕”禁用这些功能取决于您的具体需求。例如,如果使用负索引,则需要启用回绕功能。

本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码

结论

本教程讨论了使用 Cython 操作 NumPy 数组,其速度是 Python 单独处理的 5000 倍以上。减少计算时间的关键是指定变量的数据类型,并对数组进行索引而不是迭代。

在下一篇教程中,我们将通过使用 Cython 来减少遗传算法的 Python 实现的计算时间,从而总结和推进我们迄今为止的知识。

Numpy 备忘单

原文:https://towardsdatascience.com/numpy-cheat-sheet-4e3858d0ff0e?source=collection_archive---------9-----------------------

Python Numpy 库基础的快速指南,包括代码示例。

查尔斯·德鲁维奥在 Unsplash 上的照片

NumPy 是一个库,它赋予 Python 快速处理数据的能力。与数据清理和操作相比,Numpy 有几个优点。它允许对机器学习中经常使用的数据结构进行有效的操作:向量、矩阵和张量。

当我第一次学习 NumPy 时,我很难记住所有需要的函数和方法。所以我把最常用的 Numpy 操作放在一起。我有时会回过头来看看这张便条,以唤起我的记忆。如果这对你的旅程有所帮助,我也很高兴。

这张纸条的结构是:

  1. n 维数组
  2. 阵列形状操作
  3. 数组上的数值运算
  4. 数组操作例程(选择和分割)
  5. 统计操作

这是一封长信,给自己泡杯茶,我们开始吧!

和往常一样,我们需要导入 NumPy 库:

import numpy as np

来源: me.me

1.n 维数组

什么是数组?

数组是存储相同类型元素的数据结构。存储在数组中的每一项称为一个元素。数组中元素的每个位置都有一个数字索引,用于标识元素。

1D vs 2D 阵列

1D 数组(即一维数组)存储同一数据类型的变量列表。使用索引可以访问每个变量。

1D 阵列

2D 数组(即多维数组)以由行和列组成的格式存储数据。

2D 阵列

数组与列表

  • 数组比列表使用更少的内存
  • 阵列有更多的功能
  • 数组要求数据是同质的;列表不
  • 数组上的算术运算类似于矩阵乘法

NumPy 用于处理数组。NumPy 中的数组对象叫做ndarray

创建一个向量

要创建一个向量,我们只需创建一个一维数组。就像向量一样,这些数组可以水平(即行)或垂直(即列)表示。

# Create 1 dimensional array (vector)
vector_row = np.array([1,2,3]) # Create vector as a row
>>> array([1, 2, 3])vector_column = np.array([[1],[2],[3]]) #Create vector as a column
>>> array([[1],
           [2],  
           [3]])

创建矩阵

为了创建一个矩阵,我们可以使用一个 NumPy 二维数组。在我们的解决方案中,矩阵包含三行和两列。

matrix = np.array([(1,2,3),(4,5,6)]) # Two dimensional array
>>> array([[1, 2, 3],
          [4, 5, 6]])

创建稀疏矩阵

稀疏矩阵是大部分元素为零的矩阵。稀疏矩阵只存储非零元素,并假设所有其他值为零,从而节省大量计算资源。

想象一个矩阵,其中列是媒体上的每篇文章,行是每个媒体读者,值是一个人阅读该特定文章的时间(分钟)。这个矩阵会有数万列和数百万行!然而,由于大多数读者不会阅读所有文章,因此绝大多数元素都是零。

比方说,我们想创建一个有两个非零值的 NumPy 数组,然后把它转换成一个稀疏矩阵。如果我们查看稀疏矩阵,我们可以看到只有非零值被存储:

from scipy import sparse
matrix_large = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                         [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                         [3, 0, 0, 0, 0, 0, 0, 0, 0, 0]])# Create compressed sparse row (CSR) matrix
matrix_large_sparse = sparse.csr_matrix(matrix_large)
print(matrix_large_sparse)
>>>   (1, 1)	1
      (2, 0)	3

在上面的例子中,(1, 1)(2, 0)分别代表非零值13的索引。例如,元素1位于第二行第二列。

创建特殊数组

**np.zeros()**函数返回给定形状和类型的新数组,用零填充。

# Create  1d array of zeros, length 3
np.zeros(3) 
>>> array([0., 0., 0.])# 2x3 array of zeros
np.zeros((2,3))
>>>array([[0., 0., 0.],
         [0., 0., 0.]])

函数返回一个给定形状和类型的新数组,用 1 填充。

# Create 3x4 array of ones
np.ones((3,4)) 
>>> array([[1., 1., 1., 1.],
           [1., 1., 1., 1.],
           [1., 1., 1., 1.]])

**np.eye()**函数返回对角线上有 1 而其他地方有 0 的矩阵。

# Create 5x5 array of 0 with 1 on diagonal (Identity matrix)
np.eye(5) 
>>> array([[1., 0., 0., 0., 0.],
           [0., 1., 0., 0., 0.],
           [0., 0., 1., 0., 0.],
           [0., 0., 0., 1., 0.],
           [0., 0., 0., 0., 1.]])

**np.linspace()**函数返回指定间隔内均匀分布的序列。

# Create an array of 6 evenly divided values from 0 to 100
np.linspace(0,100,6) 
>>> array([  0.,  20.,  40.,  60.,  80., 100.])

**np.arange(start, stop, step)**函数返回在给定范围内包含均匀间隔值的ndarray对象。

这些参数决定了值的范围:

  1. start定义数组中的第一个值。
  2. stop定义数组的结尾,不包含在数组中。
  3. step是定义数组中每两个连续值之间的间距(差)的数字,默认为1

N 注:step不能为零。否则我们会得到一个ZeroDivisionError。如果增量或减量是0,我们就不能离开start任何地方。

# Array of values from 0 to less than 10 with step 3 
np.arange(0,10,3)
>>> array([0, 3, 6, 9])

**np.full(shape, fill_value)**函数返回一个指定形状的新数组,用fill_value填充。

# 2x3 array with all values 5
np.full((2,3),5)
>>> array([[5, 5, 5],
           [5, 5, 5]])

**np.random.rand()**函数返回指定形状的数组,并用随机值填充。

# 2x3 array of random floats between 0–1
np.random.rand(2,3)
>>> array([[0.37174775, 0.59954596, 0.50488967],
           [0.22703386, 0.59914441, 0.68547572]])# 2x3 array of random floats between 0–100
np.random.rand(2,3)*100
>>> array([[23.17345972, 98.62743214, 21.40831291],
           [87.08603104, 84.23376262, 63.90231179]])# 2x3 array with random ints between 0–4
np.random.randint(5,size=(2,3))
>>> array([[2, 3, 4],
           [4, 4, 0]])

2.阵列形状操作

形状

检查一个数组的形状和大小对于进一步的计算和简单地在一些操作后进行检查是有价值的。

NumPy 数组有一个名为shape的属性,它返回一个元组,每个索引都有相应元素的数量。

arr = np.array([(1,2,3),(4,5,6)])
arr.shape # Returns dimensions of arr (rows,columns)
>>> (2, 3)

在上面的例子中,(2, 3)表示数组有 2 个维度,每个维度有 3 个元素。

使再成形

了解如何重塑 NumPy 数组很重要,这样我们的数据才能满足特定 Python 库的期望。例如,Scikit- learn 要求输出变量y的一维数组的形状像一个二维数组,其中一列和每行的结果。

一些算法,如 Keras 中的长短期记忆递归神经网络,需要将输入指定为由样本、时间步长和特征组成的三维数组。

reshape()允许我们重新构建一个数组,这样我们可以维护相同的数据,但是它被组织成不同数量的行和列。

N 注:原矩阵和新矩阵的形状包含相同数量的元素(即相同的大小)

arr1 = np.arange(1, 11)  # numbers 1 to 10
>>> array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])print(arr1.shape) # Prints a tuple for the one dimension.
>>> (10,)

我们可以使用reshape()方法将我们的数组整形为一个 2 乘 5 维的数组。

arr1_2d = arr1.reshape(2, 5)print(arr1_2d)
>>> array([[ 1,  2,  3,  4,  5],
           [ 6,  7,  8,  9, 10]])

如果我们希望 NumPy 自动确定特定维度的大小/长度,那么将维度指定为-1,这实际上意味着“需要多少就有多少”例如,reshape(2, -1)表示两行和任意多列。

arr1.reshape(2, 5)
arr1.reshape(-1, 5)  # same as above: arr1.reshape(2, 5)
arr1.reshape(2, -1)  # same as above: arr1.reshape(2, 5)

移项

转置是线性代数中的常见操作,其中每个元素的列和行索引被交换。

在最后一个例子中,arr1_2d是一个 2×5 维的数组,我们希望用它的列来交换它的行。

arr1_2d.T
>>> array([[ 1,  6],
          [ 2,  7],
          [ 3,  8],
          [ 4,  9],
          [ 5, 10]])

展平矩阵

flatten()是将一个矩阵转换成一维数组的简单方法。

arr1_2d.flatten()
>>> array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

调整矩阵大小

**resize(arr, new_shape)**函数返回指定形状的新数组。
如果新数组比原数组大,那么新数组用arr的重复副本填充。

# Resize arr1_2d to 3 rows, 4 columns 
resize_arr = np.resize(arr1_2d, (3,4))
resize_arr
>>> array([[ 1,  2,  3,  4],
           [ 5,  6,  7,  8],
           [ 9, 10,  1,  2]])

矩阵求逆

矩阵 A 的是这样一个矩阵,当乘以 A 时得到恒等式。一个很好的例子是在线性回归中寻找系数值的向量。

使用 NumPy 的线性代数inv方法:

matrix = np.array([[1, 2],
                   [3, 4]])# Calculate inverse of matrix
np.linalg.inv(matrix)
>>> array([[-2\. ,  1\. ],
          [ 1.5, -0.5]])

将数组转换为列表,反之亦然

当我第一次学习 Python 时,我经常遇到的一个错误——有时现在仍然会遇到——是这样的:

数组需要声明,而列表不需要声明,因为它们是 Python 语法的一部分。这就是列表比数组更常用的原因。但是在对我们的列表执行一些算术函数的情况下,我们应该用数组来代替。

如果我们想要存储大量数据,我们应该考虑数组,因为它们可以非常紧凑和高效地存储数据。

arr = np.array([(1,2,3),(4,5,6)])
>>> array([[1, 2, 3],
          [4, 5, 6]])arr_to_list = arr.tolist() # Convert arr to a Python list
>>> [[1, 2, 3], [4, 5, 6]]np.array(arr_to_list) # Convert list to array 
>>> array([[1, 2, 3],
          [4, 5, 6]])

描述阵列的其他有用函数:

arr.size # Return number of elements in arr
len(arr) #Length of arrayarr.ndim # Number of array dimension
arr.dtype # Return type of elements in arr
arr.dtype.name # Name of data type
arr.astype(int) # Convert an array to a different type
arr.astype(dtype) # Convert arr elements to type dtype
np.info(np.eye) # View documentation for np.eye

3.数组上的数值运算

迹(线性代数)

轨迹是一个方阵的所有对角元素的总和。

arr = np.array([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
np.trace(arr)
>>> 6

决定因素

行列式矩阵是一种特殊的数,可以从方阵中计算出来。计算矩阵的行列式有时会很有用。NumPy 用det()让这变得简单。

matrix = np.array([[1, 2, 3],
                   [2, 4, 6],
                   [3, 8, 9]])# Return determinant of matrix
np.linalg.det(matrix)
>>> 0.0

求矩阵的秩

矩阵的秩是矩阵中线性无关的行或列的数量的估计。知道矩阵的秩很重要。在解线性方程组时,秩可以告诉我们Ax = 0是有一个解还是多个解。

matrix = np.array([[1, 1, 3],
                   [1, 2, 4],
                   [1, 3, 0]])# Return matrix rank
np.linalg.matrix_rank(matrix)
>>> 3

求特征值和特征向量

许多机器学习问题可以用线性代数建模,其解来自特征值和特征向量

特征值和特征向量

在 NumPy 的线性代数工具集中,eig让我们计算任何方阵的特征值和特征向量。

matrix = np.array([[0, 1, 2],
                   [3, 4, 5],
                   [6, 7, 8]])# Calculate eigenvalues and eigenvectors
eigenvalues, eigenvectors = np.linalg.eig(matrix)
eigenvalues
>>> array([ 1.33484692e+01, -1.34846923e+00, -2.48477279e-16])
eigenvectors
>>> array([[ 0.16476382,  0.79969966,  0.40824829],
           [ 0.50577448,  0.10420579, -0.81649658],
           [ 0.84678513, -0.59128809,  0.40824829]])

标量运算

当我们对一个矩阵加、减、乘或除一个数时,这就叫做标量运算。在标量操作期间,标量值应用于数组中的每个元素,因此,该函数返回一个具有相同行数和列数的新矩阵。

new_arr = np.arange(1,10)
>>> array([1, 2, 3, 4, 5, 6, 7, 8, 9])# Add 1 to each array element
np.add(new_arr,1)
>>> array([ 2,  3,  4,  5,  6,  7,  8,  9, 10])

同样,我们可以使用下面的函数对矩阵进行减法、乘法或除法运算:

np.subtract(arr,2) # Subtract 2 from each array element
np.multiply(arr,3) # Multiply each array element by 3
np.divide(arr,4) # Divide each array element by 4 (returns np.nan for division by zero)
np.power(arr,5) # Raise each array element to the 5th power

矩阵运算

如果两个矩阵具有相同的维数,即它们必须具有相同的行数和列数,则只能将一个矩阵与另一个矩阵相加(或相减)。

矩阵相乘时,我们取第一个矩阵的行,乘以第二个矩阵对应的列。

注意:记住“行优先,列第二”

乘法矩阵

了解矩阵的形状是很重要的。然后矩阵操作使用 NumPy 库是简单的。

np.add(arr1,arr2) # Elementwise add arr2 to arr1
np.subtract(arr1,arr2) # Elementwise subtract arr2 from arr1
np.multiply(arr1,arr2) # Elementwise multiply arr1 by arr2
np.divide(arr1,arr2) # Elementwise divide arr1 by arr2
np.power(arr1,arr2) # Elementwise raise arr1 raised to the power of arr2
np.array_equal(arr1,arr2) # Returns True if the arrays have the same elements and shape

其他数学运算:

np.sqrt(arr) # Square root of each element in the array
np.sin(arr) # Sine of each element in the array
np.log(arr) # Natural log of each element in the array
np.abs(arr) # Absolute value of each element in the array
np.ceil(arr) # Rounds up to the nearest int
np.floor(arr) # Rounds down to the nearest int
np.round(arr) # Rounds to the nearest int

4.数组操作例程

添加/删除元素

**append()**函数用于将值追加到给定数组的末尾。

np.append ([0, 1, 2], [[3, 4, 5], [6, 7, 8]])
>>> array([0, 1, 2, 3, 4, 5, 6, 7, 8])np.append([[0, 1, 2], [3, 4, 5]],[[6, 7, 8]], axis=0)
>>> array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])

沿其追加值的轴。如果没有给定轴,数组和值在使用前都被展平。

**insert()**:用于在数组的给定索引前插入元素。

arr = np.arange(1,6)
np.insert(arr,2,10) # Inserts 10 into arr before index 2
>>>array([ 1,  2, 10,  3,  4,  5])

**delete()**我们可以从ndarray中删除任何行和列

arr = np.arange(12).reshape(3, 4)
>>> [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]]np.delete(arr,2,axis=0) # Deletes row on index 2 of arr
>>> array([[0, 1, 2, 3],
           [4, 5, 6, 7]])np.delete(arr,3,axis=1) # Deletes column on index 3 of arr
>>> array([[ 0,  1,  2],
           [ 4,  5,  6],
           [ 8,  9, 10]])

**sort()**函数可以用来对列表进行升序和降序排序。

oned_arr = np.array([3,8,5,1])
np.sort(oned_arr)
>>> array([1, 3, 5, 8])arr = np.array([[5, 4, 6, 8],
                [1, 2, 4, 8],
                [1, 5, 2, 4]])# sort each column of arr
np.sort(arr, axis=0)
>>> array([[1, 2, 2, 4],
           [1, 4, 4, 8],
          [5, 5, 6, 8]])# sort each row of X
np.sort(arr, axis=1)
>>> array([[4, 5, 6, 8],
          [1, 2, 4, 8],
          [1, 2, 4, 5]])

加入 NumPy 数组

连接意味着将两个或多个数组的内容放在一个数组中。在 NumPy 中,我们通过轴连接数组。我们传递一系列我们想要加入到concatenate()函数中的数组,以及轴。如果没有显式传递该轴,则该轴被视为 0。

# Adds arr2 as rows to the end of arr1
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.concatenate((arr1, arr2), axis=0)
>>> array([1, 2, 3, 4, 5, 6])# Adds arr2 as columns to end of arr1
arr1 = np.array([[1, 2, 3],[4, 5, 6]])
arr2 = np.array([[7, 8, 9],[10, 11, 12]])
arr = np.concatenate((arr1,arr2),axis=1)
>>> array([[ 1,  2,  3,  7,  8,  9],
           [ 4,  5,  6, 10, 11, 12]])

拆分 NumPy 数组

酷,现在我们知道如何将多个阵列合并成一个。如何把一个数组拆成多个?我们使用array_split()来分割数组,我们传递给它我们想要分割的数组和分割的数目。

N 注意:如果数组的元素比要求的少,它将从末尾进行相应的调整。

# Splits arr into 4 sub-arrays
arr = np.array([1, 2, 3, 4, 5, 6])
new_arr = np.array_split(arr, 4) 
>>> [array([1, 2]), array([3, 4]), array([5]), array([6])]# Splits arr horizontally on the 2nd index
arr = np.array([1, 2, 3, 4, 5, 6])
new_arr = np.hsplit(arr, 2)
>>> [array([1, 2, 3]), array([4, 5, 6])]

选择元素

NumPy 为索引和分割数组中的元素或元素组提供了多种方法。

注意:NumPy 数组是零索引的,这意味着第一个元素的索引是 0,而不是 1。

假设我们有两个数组,一个包含 user_name,另一个存储这个人阅读的文章数量。

user_name = np.array(['Katie','Bob','Scott','Liz','Sam'])
articles = np.array([100, 38, 91, 7, 25])user_name[4] # Return the element at index 4
>>> 'Sam'articles[3] = 17 # Assign array element on index 1 the value 4
>>>array([100,  38,  91,  17,  25])user_name[0:3] # Return the elements at indices 0,1,2
>>> array(['Katie', 'Bob', 'Scott'], dtype='<U5')user_name[:2] # Return the elements at indices 0,1
>>> array(['Katie', 'Bob'], dtype='<U5')articles<50 # Return an array with boolean values
>>> array([False,  True, False,  True,  True])articles[articles < 50] # Return the element values
array([38,  7, 25])# Return the user_name that read more than 50 articles but less than 100 articles
user_name[(articles < 100 ) & (articles >50)]
>>> array(['Scott'], dtype='<U5')

我们使用类似的方法来选择多维数组中的元素:

arr[2,5] # Returns the 2D array element on index [2][5]
arr[1,3]=10 # Assigns array element on index [1][3] the value 10
arr[0:3] # Returns rows 0,1,2
arr[0:3,4] # Returns the elements on rows 0,1,2 at column 4
arr[:2] # Returns returns rows 0,1
arr[:,1] # Returns the elements at index 1 on all rows

5.统计操作

求最大值和最小值

通常我们想知道数组或数组子集的最大值和最小值。这可以通过maxmin方法完成。使用axis参数,我们也可以沿某个轴进行操作:

假设我们将一个人每月的文章数量存储在一个数组中。

articles = np.array([[10, 23, 17],
                   [41, 54, 65],
                   [71, 18, 89]])# Return maximum element
np.max(articles)
>>> 89
np.max(articles, axis=0) *# Find maximum element in each column
>>>* array([71, 54, 89])
np.max(articles, axis=1) # Find maximum element in each row
>>> array([23, 65, 89])

我们可以用类似的方法找到最小元素:

np.min(arr) # Return minimum element
np.min(arr,exis=0)# Find minimum element in each column
np.min(arr,axis=1)# Find minimum element in each row

计算平均值、方差和标准差

就像使用max()min()一样,我们可以很容易地获得整个矩阵的描述性统计数据,或者沿着单个轴进行计算。

np.mean(arr,axis=0) # Return mean along specific axis
arr.sum() # Return sum of arr
b.cumsum(axis=1) # Cumulative sum of the elements
np.var(arr) # Return the variance of array
np.std(arr,axis=1) # Return the standard deviation of specific axis
arr.corrcoef() # Return correlation coefficient of array

本笔记中的代码可在 Github 上获得。

就是这样!

我认为这个音符是 NumPy 的基础。在工作中阅读现有代码或在线学习教程时,您可能会反复遇到这些函数。当我发现更多有用的 Numpy 函数时,我会不断更新它。

所有的学习活动都是在时间和经历中进行的。在几个小时内学会 Python 是不可能的。记住,任何努力最困难的部分是开始,你已经度过了,继续努力,继续努力!!!

来源:模因

资源

Numpy 是一个非常重要的库,几乎每个数据科学或机器学习 Python 包(如 SciPy、Matplotlib、Scikit-learn)都在一定程度上依赖于它。对基本面有很强的理解是很重要的。方便的是,有一些很棒的资源可以帮助完成这项任务。下面我列出了一些我最喜欢的,其中一些深入到线性代数的各个方面;如果您渴望了解更多信息,请查看它们!

  1. 线性代数,麻省理工
  2. 深度学习的基础线性代数
  3. 【NumPy 数组和 matrics 的区别
  4. 稀疏矩阵,SciPy 文档
  5. NP . shape()一步一步来
  6. 机器学习—特征值和特征向量

NumPy 的备忘单:基本功能和鲜为人知的功能

原文:https://towardsdatascience.com/numpy-cheatsheet-for-essential-functions-python-2e7d8618d688?source=collection_archive---------40-----------------------

(照片由克里斯·利维拉尼Unsplash 上拍摄)

终极指南

学习你可能不知道的 NumPy 的各种基本功能(用代码)

Numpy ( 代表数值 Python )是 Python 编程语言中可用的库,支持矩阵数据结构和多维数组对象。这是我们需要学习的最基本的科学计算库,以开始我们在数据科学领域的旅程。

Numpy 可以计算基本数学计算以使创建高级机器学习和人工智能应用程序的过程更容易(通过使用库中可用的综合数学函数)。Numpy 允许我们毫不费力地进行各种复杂的数学计算以及几个补充库(如 matplotlib、pandas、scikit-learn 等)。)建在它上面。

这个库是每个数据科学专业人员高效处理和分析数据的一个很好的工具。此外,与 python 的 list 相比,使用 numpy 数组执行数学运算要容易得多。

Numpy 库中有各种可用的函数。在本文中,我们将学习本库的一些基本鲜为人知的函数,以及如何高效地实现它们。

注意:在本文中,我们将使用 谷歌合作实验室 来执行我们的代码。

导入数字

Numpy 可以通过使用以下代码简单地导入到笔记本中:

import **numpy** as **np**

在这里,numpy 写成 np 是为了节省编码时的时间,也是数据科学界的事实。

现在,让我们从 numpy 函数开始吧!

使用 numpy 创建 n 维数组

数组是 numpy 库中的一种数据结构,它就像一个可以存储值的列表,但不同之处在于,我们可以指定数组元素的数据类型(dtype函数),数组速度更快,存储数据占用的内存更少,允许代码进一步优化。

要创建一个一维数组我们可以使用下面的代码:

import numpy as np
array = **np.array(**[1,2,3,4,5]**)**

创建多维数组的过程类似,我们只需在[]括号中添加更多的值:

array = **np.array(**[[1.1,2.2,3.0,4.6,5.0],[6.4,7.3,8.5,9.1,10.2]**)**

numpy.linsapce()函数

这个numpy.linspace()函数用于在给定的区间内创建一个均匀分布的数组。我们还可以确定我们想要生成的样本数(但是,它是一个可选参数,缺省值设置为五十个样本)。我们可以添加到该函数的另一个可选参数是restep,如果True将返回space,即样本与列表之间的间距。功能是:numpy.linspace(start, stop)。让我们在一个例子中应用这个函数:

import numpy as np
import matplotlib.pyplot as plt
x = **np.linspace(0,10,10,dtype = int, retstep=True)**
print(x)
x = np.linspace(0,10,100)
y = np.sin(x)
plt.plot(x,y,color = 'orange')
plt.show()

正如我们在这里看到的,即使是计算数学函数,我们也在使用numpy库。我们使用linspace()函数生成等距值,并使用该数组绘制sine函数图。

(图片由作者 ) 正弦函数图使用 linspace()函数生成数值

随机抽样函数

在这里,numpy.random函数帮助我们以各种方式计算随机值,比如以给定的形状生成随机值,通过从给定的 1D 数组中随机选择值来生成数组,或者随机置换给定数组或范围的序列。

  • numpy . rand():使用此函数,我们可以在给定的输入形状上创建一个均匀分布的值数组,范围为0,1。例如:
**np.random.rand**(3,4)

正如我们在本例中所看到的,shape (3,4)的数组是用范围在[0,1]内的所有值生成的。

(图片由作者 ) 生成随机值

  • numpy.random.choice(): 这个随机函数从给定的输入数组中返回一个随机样本数组。我们可以定义的其他可选参数是- size即数组的输出形状,replace即我们是否希望输出数组中有重复值,以及p即输入数组的每个给定样本的概率。看看下面的例子:
**np.random.choice**([1,2,3,4],(1,2,3),replace=True,p=[0.2,0.1,0.4,0.3])

这里,我们已经给函数提供了以下输入参数——一个具有四个元素的输入数组,输出数组的形状(上面代码中的1是我们想要作为输出的数组的编号,2,3是输出形状),值的重复是True和每个样本的概率(其中值的总和应该等于 1)。

(图片由作者 ) 随机抽样使用 numpy.random.choice()

  • NP . random . permutation():此函数返回一个随机排列的序列(对于输入数组)或排列的范围(对于单输入)。
arr = np.random.permutation(5)
print('Permutation of a range: ' + str(arr))
arr_ = np.random.permutation([1,2,3,4,5,6,7,8,9])
print('Permutation of elements of input array: ' + str(arr_))

在第一种情况下,我们返回了一个输入范围内的置换数组,在第二种情况下,我们返回了一个输入数组内的置换数组。

(图片由作者 ) 使用 numpy 随机排列

***numpy.random***中可用的功能不仅仅限于这些,您还可以在这里找到完整详尽的功能列表: numpy 文档页面

数组的索引和切片

为了访问和修改数组的对象,我们使用索引和切片方法。长度为**n**的数组中第一个元素的索引值,从**0**值开始,数组最后一个元素的索引将为**n-1**

a = [1,2,3,4,5,6]
b = a[3]
#output = 4

在上面的例子中,这个索引方法将返回数组的第四个元素a.

对于数组的基本切片(即,简单地说,拆分数组),我们使用**[start:stop:step_size]**符号。

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
**arr[1:7:2]**
#output array([1, 3, 5])

高级索引和切片:对于多维数组,我们可以通过输入特定的行和列值(以**[rows,column]**格式)来索引和切片数组。为了更好地理解,请看下面的例子:

x = np.array([[ 0,  1,  2],
[ 3,  4,  5],
[ 6,  7,  8]])
**x[0:2,1:2]**

这里,我们选择了前两行的索引(即代码中的0:2)和索引为1(即代码中的1:2)的单列。

(图片由作者 ) 高级索引和切片

numpy.ravel()和 numpy.flatten()函数

这些函数返回输入数组的 1D 展平形式。

arr = np.array([[1,2], [3,4],[5,6]])
x = arr.flatten()
print(x)
y = arr.ravel()
print(y)

(图片由作者 ) 输出上面的代码

您可能会观察到两个函数的输出是相同的!现在你可能想知道这两个函数有什么不同,因为它们的输出结果是一样的。很简单,在numpy.flatten()中创建原始数组的副本,而在numpy.ravel()中改变原始数组。此外,numpy.ravel()功能比numpy.flatten()快,因为它不占用任何内存。

numpy.isclose()函数

此函数用于检查两个数组在容差范围内的元素是否相等,并返回一个布尔数组。.isclose函数数组可以用来assert(验证)你的代码。

def inv(arr):
  arr = np.array(arr)
  inverse = **np.linalg.inv**(arr)
  return inverse**assert** np.all(**np.isclose**(inv(np.array([[6, 1, 1], [4, -2, 5], [2, 8, 7]])).tolist(),np.array([[0.17647058823529413,-0.0032679738562091526, -0.02287581699346405],[0.05882352941176469, -0.130718954248366, 0.0849673202614379],[-0.1176470588235294, 0.1503267973856209, 0.0522875816993464]])))print("Sample Tests passed", '\U0001F44D')

在上面的例子中,我们正在使用另一个 numpy 函数numpy.linalg.inv()寻找给定矩阵的逆矩阵。之后,我们使用assert函数验证结果,并使用numpy.isclose()函数检查输出值是否接近真实值。只有当所有的值都是Trueassert 函数才会起作用,否则它会给出一个断言错误。

(图片由作者 ) 实施。isclose()函数

numpy 中的堆栈数组

numpy 中有两个函数可用于堆叠不同的数组。

  • numpy.hstack(): 此函数按列(即水平)堆叠数组,类似于沿第二个轴串联数组(除了 1D 数组,它沿第一个轴串联)。对于这个函数,输入数组应该是相同的形状(1D 数组除外,它可以是任意长度)。
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[7,8],[9,10],[11,12]])
**np.hstack**((a,b))

(图片由作者 ) 水平堆叠的数组使用。hstack()函数

numpy.vstack(): 这个函数按行(即垂直)堆叠数组,类似于 shape (N,)的一维数组被重新整形为(1,N)后沿第一个轴的数组的串联。对于这个函数,输入数组应该具有相同的形状(1D 数组必须具有相同的长度)。

a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[7,8],[9,10],[11,12]])
**np.vstack**((a,b))

(图片由作者 ) 垂直堆叠的数组使用。vstack()函数

numpy 的统计功能

Numpy 库有一些有用的功能,可以用来发现见解和统计分析数据。我们可以计算平均值、中值、方差、标准差,计算一组数据的直方图,等等。

  • numpy.mean(): 使用这个函数,我们可以计算给定数组的算术平均值,我们还可以指定轴。
arr = a = np.array([[1, 2], [3, 4]])
np.mean(a,axis=1)
**#output:** 
array([1.5, 3.5])
  • 这个函数帮助我们计算一组数据的直方图。这里,我们必须输入一个我们想要计算直方图的数据的展平数组,我们还可以定义bins的数量(即给定范围内等宽面元的数量(可选)),以及面元上限和限制的range(可选)。
arr = np.array([1,2,3,2,2,3,4,5])
np.histogram(arr, bins= [1,2,3,4,5])

(图片由作者 ) 使用 numpy 计算直方图

您也可以使用 matplotlib 库在绘图上显示直方图值。

你可以在这里找到其他的 numpy 统计函数: numpy 文档页面

结论

我希望通过这篇文章,您一定已经了解了这个库的一些基本的和新的功能。为了更好地理解,我建议您尝试自己实现这些功能。

在日常使用中贯彻这些技巧,作为数据科学专业人士,一定会让你受益匪浅!

如果你有任何问题或意见,请发表在评论区。

如果你想了解如何可视化数据,并从中找到直观的见解,那么看看我们的另一篇文章:

[## 用 Python 实现数据可视化

Master python 的数据可视化库

towardsdatascience.com](/data-visualization-with-python-8bc988e44f22)

最初发表于:

*Resources:
[https://numpy.org/](https://numpy.org/)
[https://numpy.org/doc/stable/](https://numpy.org/doc/stable/)*

NumPy 速成班

原文:https://towardsdatascience.com/numpy-crash-course-6e2906feb175?source=collection_archive---------52-----------------------

关于 NumPy 你需要知道的一切

你好,

今天我们就来看看 NumPy Python 库 。NumPy 用于数值处理。请记住,需要一些基本的 Python 知识。我建议您跟随 jupyter 笔记本,这样您可以看到代码的输出,也可以使用不同的输入进行实验。

照片由 Kolleen GladdenUnsplash 拍摄

在本文中,您将学习如何:

  • 创建 numpy 数组。
  • 生成随机数,以及如何设置种子。
  • 使用数组执行操作。
  • 如何重塑一个数组?

如何从 N 维数组中:

  • 获取单个元素。
  • 获取行/列。
  • 切片。
  • 做蒙版。

在这个过程中,我们将看到一些技巧窍门,你可以用它们来使编码更加高效和简单。

我希望你会喜欢它🙂

首先进行 pip 安装 numpy ,然后将其导入您的笔记本电脑:

import numpy as np

快速注意:在每个代码块中,您都可以看到代码和输出。如果你想下载 Jupiter-notebook,你也可以查看我的 GitHub 库这里

创建 numpy 数组

可以使用列表或内置函数来创建数组。让我们看看它们各自是如何工作的。

A.使用列表创建 numpy 数组

我们可以用一个列表创建一个数组。

我们首先创建一个列表,

my_list = [0,1,2,3]
my_list [0, 1, 2, 3]

然后将其转换为 numpy 数组。

my_array = np.array(my_list)
my_array array([0, 1, 2, 3])

B.使用内置函数创建 numpy 数组

Numpy 有许多内置函数,提供了一种快速有效的方法来创建数组。

窍门:

要查看所有可用的函数,请键入阵列的名称,然后按 tab 键。

my_array.  # press tab

1.Arange 内置函数。

假设您想要创建一个大小为 5 的数组,数组中的数字从 0 到 4。我们可以这样做:

np.array([0,1,2,3,4]) array([0, 1, 2, 3, 4])

但是假设我们需要创建一个大小为 100 的数组,其中包含从 0 到 99 的所有数字。如果使用以前的方法,可能会非常痛苦。这就是阿朗奇拯救世界的地方。

这里我们只需要指定起点和终点(注意,终点不会包含在数组中)。

np.arange(0, 100) array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
       51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
       68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
       85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])

我们还可以指定步长。假设我们想要这个数组的每一个元素,我们可以简单地通过在 arange 函数中增加步长来实现:

np.arange(0, 100, 2) array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
       34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66,
       68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98])

2.Linspace 内置函数,用于创建线性间隔的数组

Linspace 将一个起点、一个终点和它们之间均匀分布的点数作为输入,这些点数也表示数组的长度。

让我们看一个例子:

# From 1 to 10, 5 elements, evenly spaced between them.
np.linspace(1, 10, 5) array([ 1\.  ,  3.25,  5.5 ,  7.75, 10\.  ])

这里起点是 1,终点是 10。Linspace 创建一个数组,在开始和结束点之间有 5 个均匀分布的数字。

3.随机内置函数创建随机数组

如果我们不关心我们的数组会有什么数字呢?嗯,我们简单地把随机数放在那里,对吗?random.randint 函数就是这样做的。

它将一个起点、一个终点(不包含在数组中)和一个形状的大小(不用担心,我们稍后会研究它)作为输入。

np.random.randint(0, 4, (2,2)) array([[2, 0],
       [0, 2]])

好吧,但现在我想和你产生相同的随机数!怎么才能做到呢?

简单,我们用一颗种子!如果您在一个单元格中键入:

np.random.seed(12)

我们将得到相同的随机数!

*np.random.seed(12)
same_arr = np.random.randint(0, 10, 20)
same_arr array([6, 1, 2, 3, 3, 0, 6, 1, 4, 5, 9, 2, 6, 0, 5, 8, 2, 9, 3, 4])*

4.正态(高斯)分布的样本

如果我们需要一个大小为 100 的样本,均值为 0,标准差为 1,该怎么办?嗯,我们再次使用。随机但这里不是。我们用 randint。正常!

*np.random.seed(101)
norm_arr = np.random.normal(0, 1, 100)
norm_arr array([ 2.70684984e+00,  6.28132709e-01,  9.07969446e-01,  5.03825754e-01,
        6.51117948e-01, -3.19318045e-01, -8.48076983e-01,  6.05965349e-01,
       -2.01816824e+00,  7.40122057e-01,  5.28813494e-01, -5.89000533e-01,
        1.88695309e-01, -7.58872056e-01, -9.33237216e-01,  9.55056509e-01,
        1.90794322e-01,  1.97875732e+00,  2.60596728e+00,  6.83508886e-01,
        3.02665449e-01,  1.69372293e+00, -1.70608593e+00, -1.15911942e+00,
       -1.34840721e-01,  3.90527843e-01,  1.66904636e-01,  1.84501859e-01,
        8.07705914e-01,  7.29596753e-02,  6.38787013e-01,  3.29646299e-01,
       -4.97104023e-01, -7.54069701e-01, -9.43406403e-01,  4.84751647e-01,
       -1.16773316e-01,  1.90175480e+00,  2.38126959e-01,  1.99665229e+00,
       -9.93263500e-01,  1.96799505e-01, -1.13664459e+00,  3.66479606e-04,
        1.02598415e+00, -1.56597904e-01, -3.15791439e-02,  6.49825833e-01,
        2.15484644e+00, -6.10258856e-01, -7.55325340e-01, -3.46418504e-01,
        1.47026771e-01, -4.79448039e-01,  5.58769406e-01,  1.02481028e+00,
       -9.25874259e-01,  1.86286414e+00, -1.13381716e+00,  6.10477908e-01,
        3.86030312e-01,  2.08401853e+00, -3.76518675e-01,  2.30336344e-01,
        6.81209293e-01,  1.03512507e+00, -3.11604815e-02,  1.93993231e+00,
       -1.00518692e+00, -7.41789705e-01,  1.87124522e-01, -7.32845148e-01,
       -1.38292010e+00,  1.48249550e+00,  9.61458156e-01, -2.14121229e+00,
        9.92573453e-01,  1.19224064e+00, -1.04677954e+00,  1.29276458e+00,
       -1.46751402e+00, -4.94095358e-01, -1.62534735e-01,  4.85808737e-01,
        3.92488811e-01,  2.21490685e-01, -8.55196041e-01,  1.54199041e+00,
        6.66319321e-01, -5.38234626e-01, -5.68581361e-01,  1.40733825e+00,
        6.41805511e-01, -9.05099902e-01, -3.91156627e-01,  1.02829316e+00,
       -1.97260510e+00, -8.66885035e-01,  7.20787599e-01, -1.22308204e+00])*

诡计!

类型?你会得到如何使用这个功能的信息。如果您不想记住每个函数需要什么输入以及函数返回什么,这很有帮助。

*?np.random.normal*

让我们检查一下 norm_arr 数组的均值是否接近 0,标准差是否接近 1。

*norm_arr.mean()0.166369880423112 norm_arr.std()1.0338189430873386*

如果增加样本量,这些数字将分别越来越接近 0 和 1。

让我们从 norm_arr 数组中找出最小和最大的数字,以及它们分别在哪个索引处!

*norm_arr.min() # minimun value-2.1412122910809264 norm_arr.max() # maximun value2.706849839399938 norm_arr.argmin() # index of the minimun value75 norm_arr.argmax() # index of the maximun value0*

最后一步是把所有东西整理好。我们来排序一下 norm_arr 数组!

*np.sort(norm_arr) array([-2.14121229e+00, -2.01816824e+00, -1.97260510e+00, -1.70608593e+00,
       -1.46751402e+00, -1.38292010e+00, -1.22308204e+00, -1.15911942e+00,
       -1.13664459e+00, -1.13381716e+00, -1.04677954e+00, -1.00518692e+00,
       -9.93263500e-01, -9.43406403e-01, -9.33237216e-01, -9.25874259e-01,
       -9.05099902e-01, -8.66885035e-01, -8.55196041e-01, -8.48076983e-01,
       -7.58872056e-01, -7.55325340e-01, -7.54069701e-01, -7.41789705e-01,
       -7.32845148e-01, -6.10258856e-01, -5.89000533e-01, -5.68581361e-01,
       -5.38234626e-01, -4.97104023e-01, -4.94095358e-01, -4.79448039e-01,
       -3.91156627e-01, -3.76518675e-01, -3.46418504e-01, -3.19318045e-01,
       -1.62534735e-01, -1.56597904e-01, -1.34840721e-01, -1.16773316e-01,
       -3.15791439e-02, -3.11604815e-02,  3.66479606e-04,  7.29596753e-02,
        1.47026771e-01,  1.66904636e-01,  1.84501859e-01,  1.87124522e-01,
        1.88695309e-01,  1.90794322e-01,  1.96799505e-01,  2.21490685e-01,
        2.30336344e-01,  2.38126959e-01,  3.02665449e-01,  3.29646299e-01,
        3.86030312e-01,  3.90527843e-01,  3.92488811e-01,  4.84751647e-01,
        4.85808737e-01,  5.03825754e-01,  5.28813494e-01,  5.58769406e-01,
        6.05965349e-01,  6.10477908e-01,  6.28132709e-01,  6.38787013e-01,
        6.41805511e-01,  6.49825833e-01,  6.51117948e-01,  6.66319321e-01,
        6.81209293e-01,  6.83508886e-01,  7.20787599e-01,  7.40122057e-01,
        8.07705914e-01,  9.07969446e-01,  9.55056509e-01,  9.61458156e-01,
        9.92573453e-01,  1.02481028e+00,  1.02598415e+00,  1.02829316e+00,
        1.03512507e+00,  1.19224064e+00,  1.29276458e+00,  1.40733825e+00,
        1.48249550e+00,  1.54199041e+00,  1.69372293e+00,  1.86286414e+00,
        1.90175480e+00,  1.93993231e+00,  1.97875732e+00,  1.99665229e+00,
        2.08401853e+00,  2.15484644e+00,  2.60596728e+00,  2.70684984e+00])*

现在我们有了一个从最小值开始一直到最大值的数组。

提示:

  1. 若要检查数组的维数,请使用数组的名称,然后。ndim
  2. 若要检查数组的形状,请使用数组的名称,然后。形状

但是数组的维度和形状是什么呢?

让我们看一个例子。

想象一下,你有一个如下所示的嵌套列表:

[ [1,2], [3,4], [5,6], [7,8] ]

这里,你有一个列表,在这个列表里面,你有另外 4 个列表,每个列表有 2 个元素。太好了。现在想象一下有一个更大的列表,包含前一个列表的 3 倍!我们把所有这些列表转换成 numpy 数组。

*small_array  = np.array([1,2])
small_arrayarray([1, 2]) medium_array = np.array([[1,2],[3,4],[5,6],[7,8]])
medium_arrayarray([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]]) big_array = np.array([ [[1,2],[3,4],[5,6],[7,8]] , [[1,2],[3,4],[5,6],[7,8]], [[1,2],[3,4],[5,6],[7,8]] ])
big_arrayarray([[[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]],

       [[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]],

       [[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]]])*

我们知道要从数组中获取维数。ndim,所以我们来试试吧!

*small_array.ndim1 medium_array.ndim2 big_array.ndim3*

要查看数组形状,请使用。形状

*small_array.shape(2,) medium_array.shape(4, 2) big_array.shape(3, 4, 2)*

我们在这里看到的是,维度与列表的嵌套程度有关!

数组的形状是用来创建数组的列表的长度。在 big_array 中,我们有 3 个列表,每个列表中嵌套了 4 个列表,这 4 个列表的长度都是 2。所以形状是:(3,4,2)。

5.零数组

要创建一个每个索引都为零的数组,我们需要指定:

  1. 数组的长度。
  2. 形状(作为元组)。如果未指定形状,则默认值为(数组的长度)。

输出是一个浮点数为 0 的数组。

*# (3,) shape numpy array with 3 zeros
array1 = np.zeros(3)
array1array([0., 0., 0.]) # (2,3) shape numpy array with 6 zeros
array2 = np.zeros((2,3))
array2array([[0., 0., 0.],
       [0., 0., 0.]])*

6.一的数组

就像。零点函数,同样的事情也适用于这里。要创建一个每个索引都有一个的数组,我们需要指定:

  1. 数组的长度。
  2. 形状(作为元组)。如果未指定形状,则默认值为(数组的长度)。

输出是一个浮点数为 1 的数组。

*# (3,) shape array with 3 ones
np.ones(3)array([1., 1., 1.]) # (2,3) shape array with 6 ones
np.ones((2,3))array([[1., 1., 1.],
       [1., 1., 1.]])*

7.完全内置功能

0 和 1 可能不是我们唯一想用的数字。如果我们想创建一个数组,它的每个索引都是数字 4 呢?我们可以充分利用内置功能。

首先,我们指定数组的形状,然后在每个索引处指定我们想要的数字。

*all_4 = np.full((2, 3), 4)
all_4 array([[4, 4, 4],
       [4, 4, 4]])*

至此,您知道了创建 numpy 数组的两种方法。

第一种方法是使用列表,第二种方法是使用内置函数。现在是时候了解我们可以利用这些阵列做些什么了!首先,我们将看看如何执行操作,然后如何重塑数组,最后如何访问数组中的特定元素。

操作

假设我们有两个形状和长度相同的数组,分别叫做 ab

我们可以:

  • 取相应指数之和。
  • 在每个索引处添加元素值。

同样的事情也适用于减法、乘法和除法。

*# Array with 3 random numbers. a = np.random.randint(0, 10, 3)aarray([1, 9, 9])b = np.random.randint(0, 10, 3) 
barray([2, 0, 2]) a + b # addition of two arraysarray([ 3,  9, 11]) a + 1 # adding 1 to each element of aarray([ 2, 10, 10])*

使再成形

假设我们有一个长度为 9 的数组。

*first_arr = np.arange(0,9)
print(first_arr)
first_arr.shape [0 1 2 3 4 5 6 7 8]

(9,)*

这里的目标是创建一个新的数组,包含相同的数据,但具有新的形状!让我们选择(3,3)形状。我们可以使用 shape 内置函数。

*sec_arr = first_arr.reshape(3,3)
print(sec_arr)
sec_arr.shape [[0 1 2]
 [3 4 5]
 [6 7 8]]

(3, 3)*

所以现在我们已经把第一个数组分成了 3 部分,创建了一个(3,3)形状的数组!你能猜出第二个数组的维数吗?你看到数组中嵌套了多少东西?让我们检查一下:

*sec_arr.ndim 2*

这就像我们之前看到的 medium_array。

访问数组中的特定元素

我们创造了不同尺寸和形状的阵列。但是我们如何访问我们想要的元素呢?

首先,想象一个二维数组,有 5 个嵌套数组,每个数组有 5 个元素。你可以把这个数组想象成一个矩阵。

*mat = np.arange(0, 25).reshape(5, 5)
mat array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])*

获取矩阵的第一个数组。

我们有一个嵌套的数组,所以当我们键入 mat[0]时,这代表第一个维度和第一个数组(因为 0)。

注意 python 中的索引从 0 开始!

*mat[0] array([0, 1, 2, 3, 4])*

获取矩阵的最后一个数组。

你可以用-1 来代替计算你的数组有多长。

*mat[-1] array([20, 21, 22, 23, 24])*

获取单个元素

现在假设我们想从这个矩阵中得到值 0。有了 mat[0]我们就有了来自第一维的第一个数组。现在用 mat[0,0]表示第二维度和矩阵中的元素 0。

*mat[0,0] 0*

去第三排

当我们想要访问所有的元素时,我们可以使用符号:。所以我们在这里说,从第一个维度我想要一切,从第二个维度我只想要第三个元素。

*mat[:,2] array([ 2,  7, 12, 17, 22])*

获取第二列

否则:从第一个维度,第二个数组,从第二个维度,一切。将这两列结合起来,我们就剩下第二列了。

*mat[1,:] array([5, 6, 7, 8, 9])*

限幅

这里我们想得到一片或一片矩阵。假设我们想要一个 3x3 的矩阵,其左上角的值来自原始矩阵。我们可以这样做:

*mat[0:3, 0:3] array([[ 0,  1,  2],
       [ 5,  6,  7],
       [10, 11, 12]])*

掩饰

如果我们想要指定一些限制,屏蔽是有用的。假设我们只想从矩阵中得到小于 5 的值。

*mat < 5 # matrix with boolean valuesarray([[ True,  True,  True,  True,  True],
       [False, False, False, False, False],
       [False, False, False, False, False],
       [False, False, False, False, False],
       [False, False, False, False, False]])*

获取实际值

要获得实际值而不是布尔值数组,我们可以这样做:

*my_filer = mat < 5
mat[my_filer] array([0, 1, 2, 3, 4])*

或者只是

*mat[mat<5] array([0, 1, 2, 3, 4])*

万岁!

这样,你实际上完成了 numpy 速成班!为你做到了而自豪吧!我希望这对你有用,你可以使用不同的输入来玩它,我期待着在熊猫速成班见到你。

感谢阅读,保持安全,并快乐。

关于我:

我对机器学习和人工智能充满热情。我是 Clarify 的一名数据科学家,我们正在那里建造 Clarify !Clarify 是团队探索时间序列数据和共享知识的工具。

NumPy 速成班:阵列基础

原文:https://towardsdatascience.com/numpy-crash-course-array-basics-35c83ea147f5?source=collection_archive---------35-----------------------

几乎所有数据科学工具的核心数据结构。

亨利&公司在 Unsplash 上拍摄的照片

列表与数组

我们都熟悉标准的 Python list——一个可变的对象,它具有很大的灵活性,因为不是列表中的所有元素都需要是同质的数据类型。也就是说,您可以拥有一个包含整数、字符串、浮点甚至其他对象的列表。

my_list = [2, {'dog': ['Rex', 3]}, 'John', 3.14]

上面是一个包含多种数据类型作为元素的完美有效的列表——甚至是一个包含另一个列表的字典!

然而,为了支持所有这些并发数据类型,每个 Python 列表元素都必须包含自己的唯一信息。每个元素都充当指向唯一 Python 对象的指针。由于这种低效率,随着列表变得越来越大,使用列表变得更加费力。

>>>for element in my_list:
    print(type(element))<class 'int'>
<class 'dict'>
<class 'str'>
<class 'float'>

有了数组,我们摆脱了列表的灵活性,取而代之的是一个由相同数据类型(通常是整数)的元素组成的多维表。
这使得大型数据集的存储和操作更加高效。

数组的属性

NumPy 数组的每个维度称为一个轴。例如,如果我们如下声明一个数组,我们有一个 2 轴数组:

>>> import numpy as np
>>> a = np.arange(10).reshape(2,5)
>>> a
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

上面的代码使用 arrange()函数创建一个范围为 10 的数组,并将其重塑为一个 2 x 5 的数组。这个方法只是标准 range()函数的数组版本。

你可以看到你的数组属性使用了内置的数组属性 shape、ndim、dtype、itemsize 和 size。

**>>> # Returns a tuple of the size of each dimension**
>>> a.shape
(2, 5)**>>> # Returns the number of axes of the array**
>>> a.ndim
2**>>> # Returns the description of the data type of the array**
>>> a.dtype
dtype('int32')**>>> # Returns the byte size of each element in the array**
>>> a.itemsize
4**>>> # Returns the total number of elements in the array**
>>> a.size
10

创建数组

从头开始创建 NumPy 数组的方法有很多——这通常取决于您的应用程序使用哪种方法,但是下面列出了一些更常用的技术。

注意:如果要显式指定类型,dtype 参数是可选的,否则它将默认为最适合您在创建时传递的数据的类型。

**>>> # Create an array of specified size filled with 0's**
>>> np.zeros((3,3), dtype=int)
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])**>>> # Create an array of specified size filled with the given value**
>>> np.full((4,2), 1.23)
array([[1.23, 1.23],
       [1.23, 1.23],
       [1.23, 1.23],
       [1.23, 1.23]])**>>> # Create a linear array with values from the arange() function**
>>> np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])**>>> # Create an array of N evenly spaced values between x and y**
>>> # np.linspace(x, y, N)
array([0\.        , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
       0.55555556, 0.66666667, 0.77777778, 0.88888889, 1\.        ])**>>> # Create an array of random values between 0 and 1**
>>> np.random.random((2,2))
array([[0.90416154, 0.56633881],
       [0.09384551, 0.23539769]])**>>> # Create an array of random integers between a given range**
>>> np.random.randint(0, 5, (2,2))
array([[4, 3],
       [3, 3]])

重塑数组

你已经看到我们使用了 shape()方法,它对操纵你的数组非常有用。对于 arange()和 linspace()这样的函数,可以使用 shape()创建任意大小的数组。
然而,非常重要的一点是要注意,为了能够重塑数组,新数组的大小必须与原始数组的大小相匹配。例如,以下内容不是有效的整形:

>>> b = np.arange(0, 6)
>>> b
array([0, 1, 2, 3, 4, 5])
>>> b.reshape((3,3))Traceback (most recent call last):
  File "<pyshell#40>", line 1, in <module>
    b.reshape((3,3))
ValueError: cannot reshape array of size 6 into shape (3,3)

我们有 6 个元素,但正试图改造成一个 3 x 3,这将需要 9 个元素。然而,我们可以把它改造成 3 x 2:

>>> b.reshape((3,2))
array([[0, 1],
       [2, 3],
       [4, 5]])

我们还可以通过使用 ravel()方法将多维数组“展平”成一维:

>>> b.ravel()
array([0, 1, 2, 3, 4, 5])

索引/切片数组

数组索引的工作方式非常类似于列表索引和切片,我们只需要注意数据的维度。

例如,假设我们正在使用如下所示的阵列:

>>> x = np.arange(12).reshape((4,3))
>>> x
array([[ 0, 1, 2],
       [ 3, 4, 5],
       [ 6, 7, 8],
       [ 9, 10, 11]])

我们有一个总共包含 12 个元素的 4 x 3。要访问一个元素,我们需要使用一个元组。因此,如果我们想在多维数组中返回值,我们可以这样做:

**>>> # Return an entire axis**
>>> x[0]
array([0, 1, 2])**>>> # Return a specific element**
>>> x[3][1]
10

我们也可以用它来修改数组中的值。
请注意,如果您尝试将该值修改为与您的数组不同的数据类型,您可能会遇到问题!当我们试图修改一个 int 类型的数组时,我们的 float 被转换为 int。

**>>> # Modify a value using a correct data type**
>>> x[1][1] = 30
>>> x
array([[ 0,  1,  2],
       [ 3, 30,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])**>>> # Modify a value using an incorrect data type**
>>> x[0][1] = 3.14
>>> x
array([[ 0,  **3**,  2],
       [ 3, 30,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])

对于切片,我们再次使用熟悉的列表切片符号,但是当我们处理一维以上的数组时,需要用逗号分隔每个维度。
我们使用通常的 x【开始:停止:步骤】格式访问行和列。

**>>> x**
array([[ 0,  3,  2],
       [ 3, 30,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])**>>> # Return a slice of the first 2 rows and all columns**
>>> x[:2, :]
array([[ 0,  3,  2],
       [ 3, 30,  5]])**>>> # Return a slice of all rows up to the first column**
>>> x[:, :1]
array([[0],
       [3],
       [6],
       [9]])**>>> # Return every other row, every column**
>>> x[::2, :]
array([[0, 3, 2],
       [6, 7, 8]])

既然您已经掌握了数组的基础知识,那么您就可以理解 Python 中最强大的数据结构之一了!

接下来,我们将研究对数组的基本操作,因此,随着本系列的进展,请务必遵循本系列。
未来故事的链接将会随着它们的发布而增加——以及一个索引页。

照片由 Gaelle MarcelUnsplash 上拍摄

NumPy 速成班——从零到英雄

原文:https://towardsdatascience.com/numpy-crash-course-zero-to-hero-c1788a8a48ac?source=collection_archive---------41-----------------------

对于那些有 Python 经验但想学习 NumPy 的人来说,这是你必须去的地方

尼克·希利尔在 Unsplash 上的照片

本文的目的是向任何具有 Python 知识的人提供一个关于 numPy 功能的快速速成课程,以及他们应该根据自己的用例详细阅读的内容。

什么?怎么会?为什么?

在我们开始探索 numPy 之前,让我们回答任何人都会想到的 3 个基本问题:

  • 什么是 numPy?
  • 人们为什么使用 numPy?
  • numPy 是怎么写的?

什么是 numPy?

numPy 或 numerical Python 是一个库,用于高级数学计算,同时保持高水平的性能。根据维基百科,“NumPy 是 Python 编程语言的库,增加了对大型多维数组和矩阵的支持,以及对这些数组进行操作的大量高级数学函数”

人们为什么使用 numPy?

数字有很多不同的用途。让我们列出其中的一些:

  • 与 Python 列表相比,它有一个高效的存储机制
  • 能够指定 numPy 数组的数据类型
  • 更快的操作 numPy 数组上的操作比 Python 列表上的操作更快,主要是因为它的同质性
  • n 维数组的创建和操作——Python 列表在多维中是非常原始的,而 numPy 使这方面的工作变得非常容易
  • 随机数据的创建——numPy 可以创建几乎符合所能想到的规范的随机数据,这在许多不同的情况下都非常有用

numPy 是怎么写的?

  • numPy 是用 C 编写的,是 SciPy 项目的一部分,但后来被分离出来,因为用户不希望仅仅为了 numPy 提供的数组操作而安装庞大的 SciPy 包

设置 numPy

>> import numpy as np

numpy 作为 np 进口的唯一原因是惯例。你可以自由地使用另一个别名,但不推荐使用,因为这是你在任何地方都能找到的别名,最好坚持使用标准

>> np.__version__'1.18.1'

钕阵列

numpy 速度快的主要原因是它使用 nd-array 类型来存储和操作数据

ndarray 是同构数据的通用多维容器。它提供了矢量化的算术运算和复杂的广播功能。每个 ndarray 都有两个属性:shape 和 dtype。shape 是一个元组,提供数组的维度,dtype 提供数组的数据类型。

在定义数组时,也可以显式指定数组的 dtype,从而对数组进行微调控制。

让我们从一个数组创建一个 numpy 数组。这可以通过将数组作为输入传递给函数 np.array 来实现

>> nparray = np.array([1,2,3])array([1, 2, 3])

numpy 数组有许多属性,这些属性提供了关于它们的更多信息。

数组的数据类型

>> nparray.dtypedtype('int32')

数组的大小

>> nparray.size3

阵列的形状

>> nparray.shape(3,)

下面两个单元的代码保证了详细的解释。 itemsize 参数返回数组中单个项目的大小。在这种情况下,我们有一个整数数组,它为单个项目占用 32 位空间,这相当于 4 个字节(1 字节= 8 位)。下面的单元格展示了 nbytes 参数,该参数返回整个数组的字节大小,从而提供了一个 12 字节的值(4 字节* 3 项)。

简而言之: itemsize 提供数组中单个项目的大小,而 nbytes 返回整个数组的大小。

>> nparray.itemsize4>> nparray.nbytes12

numpy 的 nd-array 比 Python 的原生 list 快是有原因的。让我们在下面的单元格中深入了解这一点

>> %timeit pythonList = [i for i in range(10000)]545 µs ± 24 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)>> %timeit npList = np.arange(10000)7.82 µs ± 256 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

numpy 数组是同构的,在内存中处理速度更快。现在将它与 Python 列表进行比较,在 Python 列表中可以放入任何东西;Python 列表中的每个条目都是一个 Python 对象,这导致了计算开销。这是 numpy 数组比传统 Python 列表快得多的主要原因

现在让我们看看使 numpy 成为一个灵活方便的库的一些函数。

使用 numpy 生成数据

arange 生成所传递数字范围内的数字列表

>> np.arange(10)array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

linspace 返回作为输入传递的范围内的一组线性间隔的项目。在 linspace 中,起始位、结束位以及作为输入传递的所需位数。基本上,它返回一个数组,该数组具有指定间隔内所需的位数

>> np.linspace(0, 10, 5)array([ 0\. ,  2.5,  5\. ,  7.5, 10\. ])

T21 创建了一个充满 1 的数组。作为输入传递的参数是所需数组的大小

>> np.ones(5)array([1., 1., 1., 1., 1.])

创建一个用零填充的数组。作为输入传递的参数是所需数组的大小

>> np.zeros(5)array([0., 0., 0., 0., 0.])

zeros_like 创建一个与作为输入传递的数组大小相同的数组。生成的数组将以零作为元素

>> np.zeros_like(np.arange(5))array([0, 0, 0, 0, 0])

创建一个单位矩阵。生成的矩阵将是作为输入传递的整数的维数

>> np.eye(5)array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])

创建一个用垃圾值填充的数组,通常是零。作为输入传递的参数是所需数组的大小

>> np.empty(5) array([1., 1., 1., 1., 1.])

索引

在索引和切片方面,numpy 遵循 Python 的常规规则。我在下面列出了几个例子,你可以尝试一下:

>> nparray[1]2>> nparray[-1]3

限幅

>> nparray[1:2]array([2])>> nparray[:2]array([1, 2])>> nparray[:]array([1, 2, 3])>> nparray[1:]array([2, 3])>> largeArray = np.arange(100)>> largeArray[::20]array([ 0, 20, 40, 60, 80])>> largeArray[1:10:2]array([1, 3, 5, 7, 9])>> largeArray[::-20]array([99, 79, 59, 39, 19])>> largeArray[10:1:-2]array([10,  8,  6,  4,  2])

在 numpy 中使用切片时要记住的一件重要事情是,切片本质上是引用(视图),因此,您对切片数据所做的任何更改都会反映在父数据中。让我们看一个例子

>> smallArray = largeArray[:10]>> smallArrayarray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>> largeArray[:10]array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>> smallArray[0] = 666>> smallArrayarray([666,   1,   2,   3,   4,   5,   6,   7,   8,   9])>> largeArray[:10]array([666,   1,   2,   3,   4,   5,   6,   7,   8,   9])

copy()方法可以用来创建副本,而不是这样的视图

轴线

numpy 数组可以是多维的。它还使您能够将现有数组更改为您喜欢的形状,前提是它满足多个约束

重塑让你完全按照名字说的去做。它允许您将数组调整为作为输入传递的维度。如果您没有传递一个可以对数组进行整形的维度,那么该函数将返回一个错误。比方说,该数组有 10 个元素,您试图将其整形为形状为 3x5 的数组,那么整形将返回一个错误

>> np.arange(1, 7).reshape((2, 3))array([[1, 2, 3],
       [4, 5, 6]])>> np.arange(1, 4)array([1, 2, 3])>> np.arange(1, 4).reshape(1,3)array([[1, 2, 3]])

newaxis 用于在数据中创建新轴。它通常在研究建模技术时使用,因为模型要求数据以某种方式成形。如下图所示,如果 newaxis 参数位于第一个位置,那么将会生成一个新的行向量。如果在第二个位置,那么将创建一个列,每个元素是一个单独的向量。

>> np.arange(1, 4)[np.newaxis, :]array([[1, 2, 3]])>> np.arange(1, 4)[:, np.newaxis]array([[1],
       [2],
       [3]])

数组串联

可以使用 concatenate 方法在 numpy 中连接数组。要连接的数组列表将作为输入传递给 concatenate 函数。

>> np.concatenate([smallArray, largeArray])array([666,   1,   2,   3,   4,   5,   6,   7,   8,   9, 666,   1,   2,
         3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
        16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
        29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
        42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
        55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
        68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,
        81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,
        94,  95,  96,  97,  98,  99])>> np.concatenate([smallArray, largeArray, [888, 999]])array([666,   1,   2,   3,   4,   5,   6,   7,   8,   9, 666,   1,   2,
         3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
        16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
        29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
        42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
        55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
        68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,
        81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,
        94,  95,  96,  97,  98,  99, 888, 999])

数字函数

Ufunc 的主要目的是能够加速对 numpy 数组中的值的重复操作。它既可以在一个标量值和一个数组之间工作,也可以在两个数组之间工作

>> 3 * np.arange(0, 10)array([ 0,  3,  6,  9, 12, 15, 18, 21, 24, 27])>> np.arange(0, 10) + np.arange(20, 30)array([20, 22, 24, 26, 28, 30, 32, 34, 36, 38])

这不仅在语法上更好更直观,而且速度更快。让我们在下面尝试一下

>> %timeit 3 * smallArray1.22 µs ± 61.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)>> %%timeit

>> for i in range(len(smallArray)):
       3 * smallArray[i]7.15 µs ± 182 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

从上面可以看出,ufunc 比循环版本的代码快很多倍。随着所涉及的计算逻辑变得越来越复杂,这种差异变得越来越明显

聚合

在这一节中,我们将探索 numpy 提供的各种聚合函数。numpy 附带了一个标准的 sum() 函数,该函数返回数组中所有元素的总和。你可能会问,原生 Python 函数和 numpy 函数有什么区别!毕竟他们做的是同样的功能;提供元素的总和。下面就来看看吧

>> np.sum(smallArray)711>> sum(smallArray)711>> hugeArray = np.random.randint(100000, size=1000000)
>> %timeit np.sum(hugeArray)
>> %timeit sum(hugeArray)526 µs ± 9.48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
271 ms ± 11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

从上面的代码块可以明显看出,与原生函数相比,numpy 的速度有多快。这适用于 numpy 中可用的大多数(如果不是全部)聚合函数

>> np.min(smallArray)1>> np.max(smallArray)666>> np.std(smallArray)198.31512801599376>> np.mean(smallArray)71.1np.median(smallArray)5.5

使用聚合函数时需要注意的一点是,在您使用它们时,这些函数容易出现 NaN 值,也就是说,如果您的数组中有 NaN 值,这些聚合函数将会失败。在这种情况下,您可以使用它们的 NaN 安全替代方案。给你一个例子:nansum()是 sum 函数的 NaN-safe 替代

>> np.nanmean(np.array([1, 2, np.nan]))1.5>> np.mean(np.array([1, 2, np.nan]))nan

广播

我们现在要看一个你可能经常使用但没有概念上的理解的操作。在广播中,对具有不同形状/尺寸的实体执行操作。

一个简单的例子是向 numpy 数组添加一个标量。基本上,您可以认为复制的值是为了匹配数组的维数,然后是要执行的操作。

广播是一个可以详细阐述的操作,但这不是我这篇文章的目标

>> a = np.arange(1, 7)
>> aarray([1, 2, 3, 4, 5, 6])>> a + 1array([2, 3, 4, 5, 6, 7])

逻辑运算

有时候,您会希望对一段数据执行逻辑检查。numpy 提供了您所期望的所有常规逻辑操作:大于、小于和等于检查。逻辑函数返回一组布尔值结果,表明它们是否满足条件

>> x = np.array([1, 2, 3, 4])>> x > 2array([False, False,  True,  True])>> x == 2array([False,  True, False, False])

numpy 还提供了一些有用的函数,比如 any()和 all(),用于执行以下检查:是否有任何元素满足条件,或者是否所有元素都满足条件。它们提供一个布尔值作为输出来指示结果

>> np.any(x == 2)True>> np.all(x == 2)False

从以上两个代码块中;可以理解以下内容:

  • any(x == 2):检查数组中的元素是否满足传递的条件
  • all(x == 2):它检查数组中的所有元素是否满足传递的条件

假设我们需要满足这个特定条件的值的计数,您可以使用 sum()方法,如下所示。它计算数组中真值的数量

>> np.sum(x == 2)1

这也可以组合起来检查多种情况。对于的任何的所有功能,也可以进行同样的操作

>> np.sum((x == 2) | (x == 3))2>> np.any((x == 2) | (x == 3))True

掩饰

您可能已经看到了上面的以布尔数组形式提供值的数组,并且想知道这有什么帮助,因为您仍然需要提供进一步的操作来理解输出。这就是掩蔽的用武之地;真/假数组可以通过传入数组,只提供那些满足条件的值

>> x[x == 2]array([2])>> x[x > 2]array([3, 4])

花式索引

花哨的索引不过是一次访问数组中多个元素的能力

>> xarray([1, 2, 3, 4])>> x[[0, 2, 3]]array([1, 3, 4])

您可能已经猜到了,我们也可以将一个数组作为索引列表传入

>> indexList = [0, 2, 3]
>> x[indexList]array([1, 3, 4])

当它与切片、索引和广播等技术相结合时,花式索引的真正威力就显现出来了

整理

numpy 提供的排序算法非常高效。有两种方法可以对 numpy 数组进行排序;并通过调用返回排序数组的 numpy 排序函数

让我们首先打乱我们的数组,以便我们可以对它进行排序和处理

>> np.random.shuffle(x)
>> xarray([1, 3, 4, 2])

在数组上调用 np.sort 将返回一个已排序的数组副本,但不会对数组进行排序,如下所示

>> np.sort(x)array([1, 2, 3, 4])>> xarray([1, 3, 4, 2])

如果你在数组上调用 sort ,那么数组将被就地排序,没有必要保存到另一个数组。这两种方法执行相同的功能,并且根据所需的用例来使用

>> x.sort()
>> xarray([1, 2, 3, 4])

结束语

numPy 有更多的功能,尤其是在高维数据方面。numPy 可以轻松地处理和操作更高维度的数据。我还没有决定进入这样的细节,因为这将挫败这个职位的目的。

我已经用这个博客的全部内容编辑了一个笔记本。

有很多事情我没有涉及,因为它超出了本博客的范围,但是,如果你有兴趣阅读更多关于 numpy 的内容,我强烈推荐以下资源:

  • Python 数据科学手册——《数据科学手册》是 Dat 科学领域非常受欢迎的书籍,其电子书版本免费提供。它会让你更详细地了解 numpy,如果你感兴趣,还有 pandas,matplotlib & scikit-learn
  • 用于数据分析的 Python——由熊猫的创造者撰写,你可以通过这本书深入了解 numpy 的用法示例
  • 当然, numpy 文档 —如果你是一个经验丰富的开发人员,并且确切地知道你在寻找什么,你可以直接去 numpy 文档,因为它有许多用户指南和教程,而不仅仅是一个托管参考文档的网站

数据科学的数字基础

原文:https://towardsdatascience.com/numpy-essentials-for-data-science-25dc39fae39?source=collection_archive---------26-----------------------

帮助您掌握正确的 Numpy 主题以开始数据科学的参考指南

https://images.app.goo.gl/zdDB2fSETvpprWok8

这是关于 NumPy 的两部分系列,第二部分将于 5 月 5 日出版。

数据科学爱好者最常见也是最重要的问题之一是关于数学先决条件以及如何对涉及矩阵和向量的方程进行编码。

嗯,我们有幸拥有一个核心科学计算 python 库,它消除了这种开销— NumPy 是一个强大的开源科学包,它为我们提供了:

  • 方法来处理 N 维数组和矩阵数据结构。
  • 执行复杂数学运算的方法,包括统计、三角和代数函数。
  • 测试线性代数、傅立叶级数和随机数生成能力的类和函数。

Numpy 为什么这么重要?

下一个问题是,如果我们已经掌握了 python 中的列表,那么为什么还要使用 NumPy 呢?NumPy 在计算矩阵上的复杂数学方程时脱颖而出有几个原因:

  • NumPy 在 Python 中集成了 C/C++和 Fortran 代码,与 Python 相比执行速度更快。
  • Python list 是元素的异构集合,而 Numpy 数组是存储在连续内存位置的元素的同构集合,这导致了更快的访问和执行。
  • 与 python 列表相比,使用 Numpy 数组执行简单的算术运算要容易得多。
  • 对大型任务的子任务进行并行处理,从而以超快的速度执行大型数据阵列。

他的帖子涵盖了作为数据科学家/分析师应该练习的数字基础知识,让你的生活变得更轻松。

涵盖的主题:

  • 安装和导入
  • Numpy 数组创建(1D 或多维)
  • 索引和切片
  • NumPy 数组的属性
  • 基本数学运算
  • 数组操作函数

安装和导入

在我们开始讨论具体概念之前,请确保您已经将软件包安装在您的环境中,她:

conda install numpy

或者可以用pip install numpy

一旦包在虚拟环境中可用,我们必须使用以下语句将其导入我们的工作区(这里是 jupyter notebook ):

import numpy as np

Numpy 数组创建(N 维)

我们有许多数据类型可以作为 NumPy 对象使用,但主要关注点可能是:

一维数组

在关于 Python 数据科学基础的博客中,我们已经了解了 Python 列表是如何工作的,现在我们可以将我们的学习扩展到 NumPy 数组。我们可以选择创建称为ndarray的 N 维数组。

现在,与列表不同,numpy 数组只能有一种数据类型(int、float、strings 等)。这就是如何使用np.array()函数将 python 列表转换成 NumPy 数组。

arr = np.array([1,3,5.5,6,7])

检查这个数组arr的类型会给我们numpy.ndarray类对象。

多维数组

类似地,我们也可以使用下面的代码片段将 2D 列表转换为 2D numpy 数组:

md_arr = np.array([[1,2,3],[4,5,6]])

或者,您可以使用列表理解,并根据您的需要自动完成这一过程:

md_arr = np.array([[2*i +j **for** j **in** range(4)] **for** i **in** range(3)]) # creates the following md_arr array:
array([[0, 1, 2, 3],
       [2, 3, 4, 5],
       [4, 5, 6, 7]])

除了使用列表,我们还有一些内置的占位符函数,包括:

  • np.zeros((3,4)) —创建一个形状为 3×4 的 2D 零数组
  • d = np.arange(5, 20, 4 —创建一个等间距值的数组(步长值)
  • np.linspace(0,2,9) —创建一个等间距值(样本数)的数组
  • np.full((2,2),7) —创建一个 2 × 2 形状的 7 的常量数组
  • np.eye(2) —创建一个 2×2 单位矩阵
  • np.random.random((2,2)) —用形状为 2×2 的随机值创建一个数组。
  • np.empty((2,4)) —创建形状为 2×4 的空数组。

索引和切片

创建之后,您需要以不同的形式访问数组的元素。NumPy 数组从 0 开始遵循相同的索引样式。

https://images.app.goo.gl/8qVFZULxw7HLRejs7

要访问数组的第 n 个元素,必须使用第(n-1)个索引。

arr = np.array([1,3,5,6,7])# to access the 3rd element i.e. 5, you writearr[2]

切片的工作方式也和 Python 列表中的一样。

arr = np.array([1,3,5,6,7])arr[1:3]
# this would return [3,5]

公共属性

有一个属性列表可用于检查您的阵列并了解其形状、大小、长度和其他方面。以下是您应该尝试的常见属性列表:

  • shape —告诉我们数组的形状。

  • len() —返回数组的长度

  • ndim —返回数组维数

  • astype() —将值的数据类型转换为指定的类型

  • dtype —告诉我们数组中值的数据类型

  • size —给出数组中元素的数量。

基本数学运算

为了计算数据列上的各种数学方程,这种操作非常方便。这里有几个非常重要的方法来计算 N-D 数组上的表达式

  • 矢量加法:

  • 向数组中添加一个标量将反映在所有元素中,如下所示:

  • 两个数组的乘积将两个数组的对应元素相乘:

  • 使用dot()功能的两个矢量的点积:

同样,您应该尝试其他算术运算,如/通用函数,如np.add()np.subtractnp.divide()等。

NumPy 还提供了创建一个数学序列的方法,该序列通常用于用遵循特定模式的随机数来测试一个假设。例如,如果我们需要遵循对数函数的一系列数字,我们可以使用np.log()方法:

我们可以利用的其他功能:

  • np.cos() —返回数组的余弦值。
  • np.sqrt() —返回数组中每个元素的平方根
  • np.exp —取幂函数

以及这里的许多其他人。

统计聚合函数:

  • a.sum() —数组中所有元素的总和。
  • a.min() —数组的最小值。
  • b.max(axis=0) —数组行的最大值
  • b.cumsum(axis=1) —元素的累积和
  • a.mean() —数组的均值。
  • b.median() —数组的中间值。

数组操作函数

在处理 N 维数组时,您经常需要处理矩阵或数组中的数据。您可能需要追加、删除、整形或拆分数组。NumPy 提供了以下功能,您一定要练习和理解:

  • 使用resize()reshape()方法改变阵列的形状:

使用 resize 方法更改原始数组

使用 reshape 不会改变原始数组 a1

  • 使用append()insert()delete()方法追加和删除数组元素:

  • 转置数组

转置被定义为通过选择用矩阵或 2D 阵列的列交换行来改变矩阵的形状。

这是一种重要的操作方法,当我们编写数学方程来寻找各种算法方程的解时,这种方法会派上用场。

我们可以使用返回输入数组转置的transpose()函数或者快捷方式T 属性方法。

你可以在我的 GitHub 资源库中学习和实践笔记本中的所有概念。

摘要

你应该从这篇文章中得到的要点是:

  • 什么是 NumPy,在您的数据科学项目中轻松使用它是否重要?
  • 为什么 NumPy 比使用简单的 python 列表更好。
  • 编码机器学习算法和复杂分析项目中常用的重要数据结构、属性、运算和数学函数。
  • 使用拆分、整形和转置函数操作多维数组的不同方式。

Harshit 的数据科学

通过这个渠道,我计划推出几个涵盖整个数据科学领域的系列。以下是您应该订阅频道的原因:

  • 该系列将涵盖每个主题和副主题的所有必需/要求的高质量教程。
  • 解释了为什么我们在 ML 和深度学习中做这些事情的数学和推导。
  • 与谷歌、微软、亚马逊等公司的数据科学家和工程师以及大数据驱动型公司的首席执行官的播客。
  • 项目和说明,以实现迄今为止所学的主题。

你可以在 LinkedInTwitterInstagram 上与我联系(在那里我谈论健康和福祉。)

数据科学的 NumPy:第 1 部分

原文:https://towardsdatascience.com/numpy-for-data-science-part-1-21e2c5ddbbd3?source=collection_archive---------25-----------------------

NumPy 基础和数组创建

作者图片

NumPy 代表数字 Python 是 Python 中最重要的库(=包或模块)之一。本教程解释了 NumPy 的基础知识和数组创建的各种方法。它是为那些想学习 NumPy 的基础知识和各种功能的人编写的。为了充分利用本教程,您应该熟悉 Python 编程语言和面向对象编程(OOP)的概念。

话题讨论

  • NumPy 基础:导入 NumPy,ndarray,轴,秩,Ndarray 类的属性
  • 数组创建: array() 函数,1d 数组,2d 数组,3d 数组, arange() 函数, ones() 函数, zeros() 函数, identity() 函数, eye() 函数, full() 函数,randn()函数
  • 创建向量:行向量,列向量

导入 NumPy 库

为了使用 NumPy 库,您需要在您的程序中导入它,如下所示:

或者,您可以使用以下语法导入 NumPy 库。

按照惯例,NumPy 库以别名 np 导入。通过这样做,您可以使用 np.namespace 访问 NumPy 库中的函数、类和子程序包。【例: np.array()NP . random . randn()]

恩达雷

NumPy 的主要对象是 ndarray (代表 N 维数组)。这个对象是同质数据的多维数组。 同构 是指数组中的所有元素都具有相同的数据类型。

n array 对象是从n array 类中创建的,后者有许多属性和方法。

斧头和等级

在 NumPy 中,一个数组的维数称为 ,维数称为

NumPy ndarray 类的基本属性(特性)

下面的列表显示了 ndarray 类的基本属性。ndarray docstring 中提供了带有描述的完整属性列表,可通过在 Python 解释器中调用help(NP . ndarray)来访问。

在 NumPy 库中获得关于 ndarray 类的帮助(图片由作者提供)

性能

  • ndarray.ndim: 数组的维数(轴数)。
  • ndarray . shape:N 个正整数的元组,指定每个维度的大小(元素个数)。对于具有 m 行和 n 列的矩阵,形状将为 (m,n) 。因此,形状元组的长度就是维数 ndim
  • ndarray.size: 数组中元素的总数。这等于形状的元素的乘积。
  • ndarray.dtype: 数组中元素的数据类型。

要获得 NumPy 中n array 类的特定属性的帮助,可以执行以下类型的命令。

获取 NumPy 中 ndarray 类的 shape 属性的帮助(图片由作者提供)

使用 NumPy 的 Array()函数创建数组

您可以使用 NumPy 的 array() 函数从 Python 列表或 tuple 创建一个数组(ndarray 类的一个实例)。这个 array() 函数返回一个 ndarray 对象。

作者图片

要获得关于 NumPy array() 函数的帮助,可以执行以下命令。

获取 NumPy array()函数的帮助(图片由作者提供)

注意:使用 NumPy 时,ndarray 中的数据被简单地称为数组

创建 1D 数组

顾名思义,1D 数组是一维的。

1D 数组的示例(图片由作者提供)

我们可以通过向 NumPy 的 array() 函数传递一个列表来创建一个 1D 数组。一维数组作为行返回。

我们可以得到这个 ndarray 对象的属性:

创建 2D 数组

顾名思义,2D 数组是二维的。

2D 数组的示例(图片由作者提供)

我们可以通过向 NumPy 的 array() 函数传递一个列表来创建一个 2D 数组。注意,这一次,列表的元素也是列表。二维数组作为矩阵返回

我们可以得到这个 ndarray 对象的属性:

创建 3D 阵列

顾名思义,3D 阵列有三个维度。

3D 数组示例(图片由作者提供)

我们可以通过向 NumPy 的 array() 函数传递一个列表来创建一个 3D 数组。三维数组作为矩阵列表返回。

我们可以得到这个 ndarray 对象的属性:

注:array()函数将序列转换为一维数组,将序列的序列转换为二维数组,将序列的序列转换为三维数组,以此类推。

其他数组创建函数

除了 NumPy array() 函数之外,还有许多其他函数用于创建新数组。例如,0()1()分别创建具有给定长度或形状的 0 或 1 的数组。

arange()函数

arange() 是内置 Python 范围函数的数组值版本。

获取 NumPy arange()函数的帮助(图片由作者提供)

参数

  • 开始:这是可选的,表示间隔的开始。间隔包括该值。默认值为 0。
  • 停止:这是强制性的,表示间隔结束。间隔不包括该值。
  • 步骤:这是可选的,表示值之间的间距。默认步长为 1。如果步骤被指定为位置参数,则开始也必须给出。

ones()函数

返回一个给定形状和类型的数组,用 1 填充。默认情况下,创建的数组的 dtypenp.float64 。要创建一个一维数组,只需为形状参数传递一个正整数。要用 ones() 创建一个高维数组,可以为形状传递一个元组。

获取 NumPy ones()函数的帮助(图片由作者提供)

zeros()函数

这与 ones() 完全相同,但创建了一个充满零的数组。

identity()函数

identity() 返回一个主对角线上为 1,其他位置为 0 的正方形数组。 dtype 参数默认为浮点型。

获取关于 NumPy identity()函数的帮助(图片由作者提供)

eye()函数

eye() 返回一个 2D 数组,其中所有元素都等于零,除了第 k 条对角线的值等于一。 N 是行数。 M 是列数。如果不指定 M ,则默认为 Nk 是对角线的指数。 0 (默认)指主对角线。正值表示上对角线,负值表示下对角线。

获取 NumPy eye()函数的帮助(图片由作者提供)

完整的()函数

full() 函数返回一个给定形状和类型的数组,用 fill_value 填充。对于一维数组, shape 只是一个整数。要用 ful l () 创建一个高维数组,可以为 shape 传递一个 tuple。

获取关于 NumPy full()函数的帮助(图片由作者提供)

random.randn()函数

NumPy random 子包的 randn() 函数返回一个数组,数组中的元素来自标准正态分布。返回数组的维数应该都是正数。如果没有给定参数,则返回一个 Python 浮点数。

获得关于 NumPy 随机子包的 randn()函数的帮助(图片由作者提供)

创建向量

单行矩阵

要创建行向量,我们只需创建一个包含一行的一维数组。

列向量

为了创建一个列向量,我们需要创建一个只有一列的二维数组。

注意:列向量是二维的,不是一维的。我们可以使用 ndarray.ndim 和 ndarray.shape 属性对此进行检查。

本教程由Rukshan Pramoditha数据科学 365 博客作者设计创作。

本教程中使用的技术

  • 计算机编程语言
  • NumPy
  • Jupyter 笔记本

2020–05–03

数字中的数字

原文:https://towardsdatascience.com/numpy-in-numbers-1d235138e177?source=collection_archive---------38-----------------------

马库斯·斯皮斯克在 Unsplash 上的照片

关于最常用的 Python 库之一的统计数据

从计算机科学毕业生到数学专业学生,从数据科学家到软件工程师,从机械工程师到建筑学学生,Numpy 是典型的 Python 库。几乎每个人都知道这件事。我们都知道它很有名。但是在谷歌上搜索了几天后,我发现很难了解 Numpy 社区有多大。

所以,这里尝试用数字来捕获 Numpy。

Numpy 是一个 Python 包,存储在 PyPi 上。PyPi 通常被称为奶酪店,代表 Python 包索引。它是 Python 编程语言的软件仓库(还记得吗:Dockerhub,Maven?)

估计项目影响范围的一个好方法是去它的源头,知道有多少人下载了它。现在,有很多其他方法来计算社区(活跃用户数)。查看 PyPi 下载也有缺点(并不是所有的 PyPi 下载都转化为“用户”)。但是考虑到我能够收集的数据,这似乎是一个公平的评估。

30 天下载次数最多的 PyPi 包

排名 15: numpy(过去 30 天下载 45000 次)

30 天按类别付费下载

在过去的 30 天里,哪个类别对 numpy 下载量的贡献最大。

下面的 SQL 查询就是这样做的!

  • Pip 是 Numpy PyPi 下载使用最多的项目(43M)
  • 家酿软件以 2.5 万的下载量屈居第 11 位
  • 直到今天,我知道班德纳斯奇是

谷歌搜索

  • 今天,我发现 bandersnatch 也是一个 PyPi 镜像客户端。

pip install bandersnatch

带有热图的表格(左)|树形图(右)

Python 版本每周 Numpy 下载量

Python2 于 2019 年 12 月达到其 EOL(生命周期结束)时正式停产。更多信息—https://www.python.org/doc/sunset-python-2/

话虽如此,在过去的 4 周里,我们将继续跟踪 python 3+的其他版本。令人惊讶的是,2020 年 1 月仍有大量 py2.7 numpy(每周 400 万以上)。

  • Python 2.7 仍在使用中(徘徊在 450 万左右)
  • Python 3.6 是 Python 3 版本的标准。

堆积柱形图

Numpy 下载的地理分布

为了了解各个国家的 Numpy 下载量,使用了这个查询。它揭示了有趣的事情

  • 美国下载量为 3200 万次,其次是 IE(爱尔兰)300 万次。日德(各 1M)封顶 Numpy 国家独角兽。
  • 澳大利亚、中国、印度、新加坡(亚太地区)在 50 万到 100 万之间。

我不得不承认,我很惊讶地看到爱尔兰排在第二,而中国和印度只有 50 万,远远低于美国的 3200 万。

地理地图|数字地图

谷歌数据工作室的积极方面是它能够使用国家代码检测国家,并将其转换为地理地图的值。然而,谷歌数据工作室的一个很大的限制是有限的功能和对阴影的限制。另一方面,Tableau 功能更强大,有很多定制和增强功能。

Numpy 下载的时间分布

为了捕获随时间分布的 numpy 下载,使用了 SQL 的 group by 构造。

  • 截至 1 月 19 日的数据显示,12 月是 Numpy 下载量最高的月份,下载量为 4600 万次。
  • 由于一月份只有 19 天,它有望打破 12 月份的数字,因为目前它已经达到 3000 万(还差 1600 万)。
  • 过去 6 个月的数据显示出积极(增长)的趋势

条形图(左)|圆环图(右)

感谢 Google 的 BigQuery,Data Studio & 分析 PyPi 包下载文章。

NumPy 索引解释

原文:https://towardsdatascience.com/numpy-indexing-explained-c376abb2440d?source=collection_archive---------15-----------------------

数字索引及其方法综合指南

让-路易·波林在 Unsplash 上拍摄的照片

NumPy 是在 Py thon 中处理NumEric 数据的通用标准。多维 NumPy 数组广泛用于 Pandas、SciPy、Scikit-Learn、scikit-image,它们是一些主要的数据科学和科学 Python 包。因此,如果我们使用这些工具,那么很好地理解 NumPy 是至关重要的!因此,要理解它的索引方法,我们将在本帖中讨论。

请注意,使用 NumPy 的一个关键方面或动机是,它能够以一种向量化的方式操作大量的数字数据,也就是说,避免使用低效的 python 循环。向量化你的代码的巨大优势是你把所有的循环都推到了 C 级,这要快得多。

现在让我们进入文章的主题,即索引 NumPy 数组。如果没有很好地理解 NumPy 的基本规则,那么使用 NumPy 进行索引可能会有点困难,而且有悖常理。在这里,我们将深入探讨可以使用的不同索引方法,它们是:

在这里 找到这篇文章的笔记本版本以及所有解释

基本切片

NumPy 的基本切片是 Python 的基本切片概念扩展到 N 维的延伸。

它基本上允许你使用基本的切片符号,即 start:stop:step,沿着数组的维度对数组进行切片如果你不太熟悉 Python 的基本切片符号,你可以查看这个在堆栈溢出中的帖子,这就很清楚了。让我们看一个例子:

array([['A', 'B', 'C', 'D', 'E'],
       ['F', 'G', 'H', 'I', 'J'],
       ['K', 'L', 'M', 'N', 'O'],
       ['P', 'Q', 'R', 'S', 'T'],
       ['U', 'V', 'W', 'X', 'Y']])

是的,我知道 z 这个示例数组有一个形状为 (5,5),的二维数组。我们可以沿着它的维度(我将使用等价术语)进行切片,例如:

a[:2, 1:4]array([['B', 'C', 'D'],
       ['G', 'H', 'I']])

到目前为止一切顺利。我们基本上已经沿着第一个轴对数组进行了切片,直到从索引 0 开始的第二行(注意停止索引不包括在内!),并沿第二条得到第一到第三列。把坐标轴想象成矩阵的维度( x,y,z )。其中第三维可以简单地认为是将多个 2D 阵列堆叠在一起:

好了,现在我们知道我们可以使用 python 的切片符号对 n 维数组进行切片。但是,如果您必须使用一个索引列表从给定的轴中获取值,该怎么办呢?

这就是高级索引发挥作用的地方↓

高级索引

让我们举一个直观的例子:

a_indexed = a[[4,3,1], [2,4,0]]

好的,按照与基本切片相同的逻辑,我们可以得到沿着 ndarray 的不同轴落入上述索引中的所有值。即第 2、4、0 列的第 4、3、1 行的所有值,所以下面突出显示的相交值:

是这样吗?让我们检查一下:

print(a_indexed)
array(['W', 'T', 'F'])

显然不是…(这个例子来自海梅·费尔南德斯的非常有启发性的演讲:)那里发生了什么?为什么我们得到的是一维的结果?

这是因为高级步进遵循一套不同的规则。考虑这个问题的一个好方法是,当使用基本切片时,我们在一个网格上建立索引,该网格由我们在每个维度上获取的切片定义。而使用高级索引可以被认为是指定一组我们想要检索的值的( x,y ) 坐标

在上述情况下,使用[4,3,1],[2,4,0]进行步进,将分别在(4,2)(3,4)(1,0)上进行步进。因此,我们在每个维度中指定的每个索引都将与其他维度中的相应索引相结合。

更一般地说,当使用高级索引时,我们必须考虑这两个主要方面(来自文档):

  • 索引数组表示该维度中的多个索引

这基本上意味着我们将从一个给定的轴中检索与索引数组中指定的索引一样多的元素。在上面的例子中,我们已经检索了长度为 3 的索引数组指定的 3 个元素。

  • 结果形状与(广播)步进阵列形状 相同

为了理解以上内容,我们需要深入了解一下广播

深入广播很容易导致另一个完整的博客帖子,所以我将试图涵盖非常重要的内容…来自文档:

广播被定义为一个描述 NumPy 在算术运算过程中如何处理不同形状的数组的术语。受某些约束,较小的阵列在较大的阵列上“广播”,以便它们具有兼容的形状

所以基本上,当一些涉及不同形状的数组的操作被执行时,NumPy 试图在操作发生之前使它们的形状兼容。让我们来看一些直观的例子:

图源

例如,在第一种情况下,一维 NumPy 数组被添加到一个整数上。因此,在添加发生之前,NumPy 将在较大的数组中广播较小形状的数组,也就是说,它将复制其值,直到其形状与较大数组的形状兼容。

我们如何知道两种形状是否兼容?

我们可以在文档中找到通用广播规则。据说两个维度在下列情况下是相容的

  • 它们相等,或者说
  • 其中一个是 1

好的,那么所有这些和高级索引有什么关系呢?提醒第二点,高级索引产生的形状与(广播)索引数组形状相同。这基本上意味着在执行索引操作之前,NumPy 将尝试使索引数组中的图形兼容。检查结果形状的一个简单方法是使用np.broadcast(在数组可以广播的情况下)。让我们看看与上面相同的例子:

a = array([['A', 'B', 'C', 'D', 'E'],
           ['F', 'G', 'H', 'I', 'J'],
           ['K', 'L', 'M', 'N', 'O'],
           ['P', 'Q', 'R', 'S', 'T'],
           ['U', 'V', 'W', 'X', 'Y']])

假设我们现在想用以下内容索引数组:

rows = np.array([0,2,1])
cols = np.array([2])

因此,使用上面的索引,我们将得到一个形状如下的数组:

ix = np.broadcast(rows, cols)print(ix.shape)
(3,)

我们可以看到,上图中第一种情况下的广播正在发生。该阵列将在以下 (x,y) 坐标上进行索引:

print(*ix)
(0, 2), (2, 2), (1, 2)

因此我们得到:

a[rows, cols]
array(['C', 'M', 'H'])

其中,由于两个数组都被广播,所以上述内容相当于:

a[[0, 2, 1], [2, 2, 2]]
array(['C', 'M', 'H'])

因此,为了索引整数数组,我们只需确保它们的形状可以一起广播,然后让 NumPy 处理剩下的事情。

好了,现在我们知道了如何使用整数索引来索引一个数组…

giff 来自 giphy

所以随之而来的问题是…

如果我想让索引像基本切片那样运行,该怎么办?也就是说,我们如何获得我们在第一种情况下所期望的,而不是array(['W', 'T', 'F'])

让我们回到那个例子…我们使用了索引:

rows = np.array([4,3,1])
cols = np.array([2,4,0])

在这种情况下,正如我们之前所验证的,我们得到了一个一维数组,结果是:

ix = np.broadcast(rows, cols)print(*ix)
(4, 2) (3, 4) (1, 0)

所以我们必须找到一种方法让 NumPy 明白我们想要检索一个包含所有值的网格。如何做到这一点…?

giff 来自 giphy

答案是……要用广播!!

考虑到广播正在做的是拉伸较小的阵列,以便所有阵列形状都兼容,我们可以利用这个想法来获得我们预期的结果。

我们可以做的是给其中一个数组添加一个轴,这样 NumPy 就可以传播较小的数组来适应较大数组的大小(这里是指较小的数组)。这可以通过以下方式实现:

rows[:,np.newaxis]
array([[4],
       [3],
       [1]])

或者我们可以等效地使用rows[:,None]。现在,两个索引数组可以一起广播,并可用于索引数组:

ix = np.broadcast(rows[:,None], cols)
print(*ix)
(4, 2) (4, 4) (4, 0) (3, 2) (3, 4) (3, 0) (1, 2) (1, 4) (1, 0)

我们可以认为这是生成索引列表的 笛卡尔积 ,以便从数组中检索所有的索引。我们实际上可以用[itertools.product](https://docs.python.org/3/library/itertools.html#itertools.product)来复制这个:

print(*product(rows, cols))
(4, 2) (4, 4) (4, 0) (3, 2) (3, 4) (3, 0) (1, 2) (1, 4) (1, 0)

因此,现在通过用广播索引来索引数组,我们得到:

a[rows[:,None], cols]array([['W', 'Y', 'U'],
       ['R', 'T', 'P'],
       ['H', 'J', 'F']])

该广播也可以使用功能np.ix_ : 来实现

a[np.ix_(rows, cols)]array([['W', 'Y', 'U'],
       ['R', 'T', 'P'],
       ['H', 'J', 'F']])

因此,正如我们所见,整数索引是一个非常有用的工具,我们只需要了解它是如何工作的。一个非常常见的应用是当我们有一个数组或嵌套的索引列表时,例如:

cols = [[3,4], [0,2], [0,1], [1,2], [3,3]]

我们想沿着第一轴分别取这些列,所以第一行的第 3 列和第 4 列,第二行的第 0 列和第 2 列,依此类推。我们如何做到这一点?你为什么不试一试…?

【giphy 的 gif

如前所述,在整数索引中,维度上的索引通过广播规则进行组合。因此,利用广播,我们想要获得一组索引,其组合形状是可广播的到期望的输出形状。这在本例中非常简单,因为每行都有一个子列表。因此,很明显,我们需要一个包含与第一个轴上索引的行数一样多的值的范围。

所以一个显而易见的方法是:

rows = np.arange(a.shape[0])
a[rows, cols]

然而,这将产生:

IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (5,) (5,2)

正如我们所看到的,错误是显而易见的,索引数组不能一起广播。这是因为沿相应轴的形状不兼容,因为我们有:

cols (2d array): 5 x 2
rows (1d array):     5 

从上面的草图可以清楚地看出,为了使形状兼容,我们必须向rows添加一个新轴,这样两个数组上的第二个轴具有相同的形状,并且行的第一个轴是 1,这满足广播的第二个规则:

cols         (2d array): 5 x 2
rows[:,None] (1d array): 5 x 1

现在我们会得到预期的结果:

a[rows[:,None], cols]array([['D', 'E'],
       ['F', 'H'],
       ['K', 'L'],
       ['Q', 'R'],
       ['X', 'X']])

现在,对于最后一部分… 是否有可能结合两种类型的索引

警告…!(这最后一部分变得有点复杂,并且您已经浏览了最相关和最有用的内容,所以可以休息一下,或者如果您认为现在已经看够了,就把它留在这里:)

【GIPHY 的 gif

结合高级索引和基本切片

也可以将基本切片和高级索引结合起来。这将导致整数数组索引以与我们之前看到的相同方式一起广播,并且切片的行为与我们在基本切片部分看到的一样。然而,在某些情况下,这可能会导致意想不到的结果。

让我们以下面的例子作为参考来更好地解释这一点:

a = np.arange(60).reshape(3,4,5)print(a)
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34],
        [35, 36, 37, 38, 39]],

       [[40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49],
        [50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59]]])

对于组合索引,我们需要考虑以下指导规则:

  • 整数数组索引规则仅在引入两个或更多非切片对象时适用

这意味着如果我们只使用一个整数数组来索引,比如:

a_s = a[:2, [0, 1]]a_s.shape
(2, 2, 5)print(a_s)
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9]],

       [[20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29]]])

因此,因为基本切片规则在这里适用,所以上述规则将等同于a[:2,:2]

然而,一旦我们有了一个以上的索引数组,高级索引规则将适用:

a_s = a[:2, [0, 1], [2, 4]]a_s.shape
(2, 2)print(a_s)
array([[ 2,  9],
       [22, 29]])

我们可以看到,为最后一个轴添加一个索引数组,导致输出的形状取决于两个索引数组的广播形状,即(2,2)。

  • 数组索引引入的结果轴在前面,除非它们是连续的

让我们看一些例子来更清楚地了解这一点。以下面的索引对为例:

ix1 = np.array([0,1])
ix2 = np.array([1,3])

例如,我们可以分别使用ix1ix2沿着前两个轴进行索引,并沿着最后一个轴进行完整的切片。在这种情况下,我们将得到 2D 数组 0 和1,分别为第 1 行和第 3 行,并且对于这两种情况都得到沿着最后一个轴的完整切片:

a_s = a[ix1, ix2, :]a_s.shape
(2, 5)print(a_s)
array([[ 5,  6,  7,  8,  9],
       [35, 36, 37, 38, 39]])

所以我们选择了这些元素:

注意,如前所述,这里两个不同方法的规则按预期工作并被组合。沿着最后一个轴的基本切片遵循第一节中提到的基本切片的规则,所以如果你用一个数组代替索引,你会得到:

ix3 = np.array([1,2])a[ix1, ix2, ix3]
array([ 6, 37])

我们也可以用以下方式索引:

a_s = a[:, ix1, ix2]a_s.shape
(3, 2)print(a_s)
array([[ 1,  8],
       [21, 28],
       [41, 48]])

所以在第一个轴上选择所有 2D 阵列的完整切片,然后分别选择行 0 和 1 以及列 1 和 3,所以:

因此,最后如果我们使用索引数组在第一个和最后一个轴上建立索引,如a[ix1, :, ix2],我们将期望在前两个 2D - 数组上建立索引,在第二个轴(所有行)上取一个完整的切片,分别在第 1 列和第 3 列上。所以:

有了(4,2) 的最终形状,让我们检查一下:

a_s = a[ix1, :, ix2]s_s.shape
(2,4)print(a_s)
array([[ 1,  6, 11, 16],
       [23, 28, 33, 38]])

为什么这个案例不一样… ??

回到第二个规则:由数组索引引入的结果轴在前面,除非它们是连续的。因此,因为这里的索引数组不是连续的,所以使用它们的结果轴将在前面,切片维度在后面。

虽然用一维数组做索引看起来很奇怪,但是要考虑到也可以用任意维数的数组做索引。假设我们用 3d 数组在第一个和最后一个轴上索引同一个示例数组,两个数组的形状都是(3,4,2)。所以我们知道最终的数组在某个地方也会有形状(3,4,2),因为两个索引数组传播到同一个形状。现在的问题是,我们在第一个轴和最后一个轴之间取一个完整的切片放在哪里?

鉴于不再清楚是否应该放在中间,在这些情况下有一个惯例,即切片维度放在最后

因此,在这种情况下,我们的任务是重新排列数组的维数,以匹配我们的预期输出。在上面的例子中,我们可以交换最后两个轴,得到我们期望的结果:

a[ix1, :, ix2].swapaxes(0,1)array([[ 1, 23],
       [ 6, 28],
       [11, 33],
       [16, 38]])

这种情况下基本和移调一样,a[ix1, :, ix2].T

因此,作为最后一节的收获,我们在组合两种索引方法时必须小心,因为我们可能不总是得到我们期望的。最安全的方法是牢记组合索引的注意事项,以确保它的行为符合我们的预期。

非常感谢你花时间阅读这篇文章,希望你喜欢:)

NumPy——Python 的科学计算之王

原文:https://towardsdatascience.com/numpy-the-king-of-scientific-computing-with-python-d1de680b811d?source=collection_archive---------50-----------------------

用于数据科学和机器学习的 Python

NumPy 入门综合指南

Dilyara Garifullina 在 Unsplash 上拍摄的照片

ython 是我最喜欢的编程语言之一(我也喜欢 cpp)。由于其对初学者友好的语法,它非常容易学习。使它从其他编程语言中脱颖而出的是它令人敬畏的开发者社区。它预装了如此多的工具&库。并且是数据科学&机器学习领域最首选的语言之一。

在本文中,我将向您介绍 Python 中一个如此强大的库,名为 NumPy。

享受旅程!!

内容:

  1. 什么是 NumPy?
  2. 数字对比列表
  3. 安装
  4. 让我们从 NumPy 数组开始
  5. 下面我们来盘点一下 NumPy
    a)arange
    b)零和一
    c)linspace
    d)eye
    e)Random
  6. 数组属性和方法
    a) 整形
    b) max,min,argmax,argmin
    c) 形状
    d)d 类型
  7. 数字索引和选择
  8. 广播
  9. 索引 2D 阵列(矩阵)
  10. 选择
  11. NumPy 运算
    a) 算术
    b) 通用数组函数
  12. 矢量化
  13. 结论
  14. Github 资源库
  15. 参考文献
  16. 建议阅读

1.什么是 NumPy

来源:https://giphy.com/gifs/maths-DHqth0hVQoIzS

NumPy 是 python 的线性代数库。

  1. 它是 python 中科学计算的核心库。
  2. 它非常快,因为它绑定到 C 库。
  3. 它提供了一个高性能的多维数组对象和工具来处理这些数组。

多维数组(来源:https://ipython-books.github.io/)

2.数字与列表

谁是赢家?

图片来自 PixabayGraphicMama-team

让我们看看不同之处

  • NumPy 有固定的自然类型。NumPy 用于创建同构 n 维数组。列举了可以是自然界中的异类。
  • 在遍历 NumPy 数组时,我们不需要进行类型检查。另一方面,列表中的对象可以是类型 intbooleanstring 等。

如果我们明确地提到 dtype,这段代码会给出一个错误:

#heterogenous 1D array 
#gives an error in numpy
np_arr = np.array([1,2,"a",3,"b"], dtype=np.int32)

这是一个有效的 python 代码列表:

#heterogenous 1D array
arr = [1,2,"a",3,"b"]

数学运算不能在异构数据上执行。这就是为什么建议使用同构 NumPy 阵列的原因

让我们再举一个例子:

这段代码会在 python 列表中给出一个错误:

x = [1,2,3]
y = [4,5,6]#this will give an error,
#not possible in Lists
x*y

但是这一个有效的代码为 NumPy:

x = np.array([1,2,3])
y = np.array([4,5,6])x*y#Output
np.array([4,10,18])

在接下来的章节中,我们将了解更多关于 NumPy 的一些令人敬畏的特性。

假设我们有一个矩阵:

[[1,2,3],
 [4,5,6],
 [7,8,9]]

我们将分析矩阵中的数字7

计算机读取二进制信息。

默认情况下 Numpy7存储在 4 字节的总存储空间中。

另一方面在列表中,需要为整数7存储大量信息。

列表使用 python 内置的int类型。

内置的int型由四种不同的东西组成:

大小

描述该特定整数值的大小。

引用计数

它告诉我们这个特定的整数(这里是7)被指向了多少次。

Python 中的每个变量都只是一个对象的引用(指针)。不是实际值本身。

因此,为了跟踪引用,每个对象(偶数)都有一个额外的字段,称为引用计数,当创建或删除指向该对象的指针时,引用计数会增加或减少。

对象类型

它告诉对象是否是 int,boolean,string 等。

目标值

它有自己的二进制表示

高达 64 位……..000000000000000111(8 字节)

像这样,我们也有二进制表示的大小引用计数对象类型。

所以基本上读取更少字节的内存会更快。

我们可以清楚地看到,对于单个整数存储,Numpy 比 Lists 占用更少的内存!!

请看这幅插图

作者图片

我们清单上的数据将分散在计算机的内存中。它没有连续的内存块。该列表将只包含指向这 8 个内存块的指针。

作者图片

另一方面,NumPy 数组在计算机中有连续的内存块。所有 8 个街区都紧挨着。

作者图片

所以从上面的分析中可以看出,列表非常慢,而 NumPy 非常快!!

NumPy 拥有猎豹般的速度;)

资料来源:https://giphy.com/gifs/animal-running-7lz6nPd56aHh6

3.装置

我将推荐您使用 Anaconda 发行版安装 Python,以确保所有底层依赖项(如线性代数库)与 conda install 的使用同步。

请参考此链接了解更多关于 anaconda 安装的信息:

安装— Anaconda 文档

如果您有 Anaconda,请在您的终端或命令提示符下安装 NumPy,并开始键入:

conda install numpy

如果您没有 Anaconda 发行版,也可以使用:

pip install numpy

4.让我们从 NumPy 数组开始:

我们将讨论向量和矩阵。

向量是严格的一维数组,矩阵是二维数组

注意:矩阵仍然只能有一行或一列

首次进口数量

import numpy as np

让我们使用 python 列表创建 NumPy 数组

代码 1:

#define
just_a_list = [1,2,3]#show
just_a_list

输出:

[1, 2, 3]

现在我们将把上面的代码 1 片段变量just_a_list转换成 NumPy 数组。

代码 2:

np.array(just_a_list)

输出:

array([1, 2, 3])

代码 3:

#define
just_a_matrix = [[1,2,3],[4,5,6],[7,8,9]]#show
just_a_matrix

输出:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

现在我们将把上面的代码 3 片段变量just_a_matrix转换成 NumPy 2d 数组

代码 4:

np.array(just_a_matrix)

输出:

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

5。我们来看看 NumPy 的一些内置方法:

a)范围

它返回给定间隔内均匀分布的值。

这和 Python 自己内置的 range 函数非常相似。

输出中排除了上限。

代码 1:

np.arange(0,20)

输出:

array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])

代码 2:

#step size of 2
np.arange(0,10,2)

输出:

array([0, 2, 4, 6, 8])

在上面的代码片段中,2 是步长。正如您在输出中所看到的,该系列以差值 2 递增。

b)零和一

让我们生成 0 或 1 的数组

代码 1:

np.zeros(4)

输出:

array([0., 0., 0., 0.])

所以基本上np.zeros(4)返回一个填充了 4 个零的新数组。

代码 2:

np.zeros((3,3))

输出:

array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

np.zeros((3,3)) 返回用零填充的 shape (3,3)矩阵。Shape (3,3)是指 3 行& 3 列。

代码 3:

np.ones(4)

输出:

array([1., 1., 1., 1.])

在上面的代码片段中,np.ones(4)返回一个填充了 4 个 1 的新数组。

代码 4:

np.ones((3,3))

输出:输出:

array([[ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 1.,  1.,  1.]])

c) linspace

返回指定间隔内等间距的数字。

代码 1:

#generates three numbers
#between range 0 to 10
np.linspace(0,10,3)

输出:输出:

array([0., 5., 10.])

代码 2:

np.linspace(0,10,20)

输出:

array([ 0.,  0.52631579,  1.05263158,  1.57894737,  2.10526316,         2.63157895,  3.15789474,  3.68421053,  4.21052632,  4.73684211,         5.26315789,  5.78947368,  6.31578947,  6.84210526,  7.36842105,         7.89473684,  8.42105263,  8.94736842,  9.47368421,  10\.        ])

d)眼睛

创建一个单位矩阵。

代码:

np.eye(3)

输出:

array([[1., 0., 0.],
       [0., 1., 0.],       
       [0., 0., 1.]])

e)随机

Numpy 也有很多方法来创建随机数数组

一)兰特

创建一个给定形状的数组,并用来自[0,1]上的均匀分布的随机样本填充它。

代码 1:

np.random.rand(2)

输出:

array([0.01231767, 0.24372946])

代码 2:

np.random.rand(3,3)

输出:

array([[0.75250092, 0.7582111 , 0.16155648],        
       [0.11020177, 0.51819124, 0.29267394],        
       [0.70052998, 0.58651773, 0.80589757]])

二)randn

标准正态高斯分布中返回一个(或多个)样本。不像np.random.rand返回一个均匀的分布。

代码 1:

np.random.randn(2)

输出:

array([ 1.5868519 , -2.72817085])

代码 2:

np.random.randn(4,4)

输出:

array([[ 0.24602617, -2.39464955, -0.1382286 ,  1.47872422],    
       [ 0.70466341, -0.17408009, -2.22898345,  0.28018941],        
       [ 0.57969196,  0.00664889,  1.20221044,  0.47452959],        
       [ 0.93939176, -0.07719476, -0.08907384,  1.26465443]])

三)随机

返回从(含)到(不含)的随机整数。

代码 1:

np.random.randint(1,100)

输出:

84

代码 2:

#generates 10 random 
#integers between 1 to 100
np.random.randint(1,100,10)

输出:输出:

array([85, 30,  2, 72, 40, 86, 18, 46,  3, 24])

6.数组属性和方法

a)重塑

对数组使用的最有用的方法之一是 reshape 方法。

它返回一个数组,该数组包含具有新形状的相同数据。

代码 1:

#define
arr = np.arange(16)#show
arr

输出:

array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])

现在让我们重塑上面的代码 1 片段变量arr

代码 2:

arr.reshape(4,4)

输出:

array([[ 0,  1,  2,  3],        
       [ 4,  5,  6,  7],        
       [ 8,  9, 10, 11],        
       [12, 13, 14, 15]])

b)最大值、最小值、argmax、argmin

这些是寻找最大值或最小值的有用方法。我们还可以使用 argmin 或 argmax 找到它们的索引位置!!

让我们生成一个由 10 个整数组成的随机数组

代码 1:

#define
random_arr = np.random.randint(0,50,10)#show
random_arr

输出:

array([16,  8, 40,  7, 15, 39,  0, 15, 20, 35])

代码 2:

random_arr.max()

输出:

40

代码 3:

random_arr.argmax()

输出:输出:

2

代码 4:

random_arr.min()

输出:

0

代码 5:

random_arr.argmin()

输出:

6

c)形状

形状是数组具有的属性(不是方法)

我们已经在整形部分的 代码 1 片段 下定义了变量arr

代码 1:

arr.shape

输出:

(16,)

上面的形状表明arr只是一个秩为 1 的一维向量。

代码 2:

arr.reshape(1,16)

输出:

array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]])

注意输出中的两组括号。它指示二维 NumPy 数组。

代码 3:

arr.reshape(1,16).shape

输出:

(1, 16)

重塑后的arr包含1 row & 16 columns

代码 4:

arr.reshape(16,1)

输出:

array([[ 0], 
       [ 1], 
       [ 2], 
       [ 3], 
       [ 4], 
       [ 5], 
       [ 6], 
       [ 7], 
       [ 8], 
       [ 9], 
       [10], 
       [11], 
       [12], 
       [13], 
       [14], 
       [15]])

代码 5:

arr.reshape(16,1).shape

输出:

(16, 1)

重塑后的arr包含16 rows & 1 column

d)数据类型

使用 dtype 我们可以得到数组中对象的数据类型。

代码 1:

arr.dtype

输出:

dtype(‘int64’)

7.数字索引和选择

现在我们将学习如何从数组中选择元素或元素组。从数组中挑选一个或多个元素的最简单方法看起来非常类似于 python 列表

我们已经在整形部分的 代码 1 片段 下定义了变量*arr*

代码 1:

#Get a value 
#at an index
arr[5]

输出:输出:

5

代码 2:

#Get values 
#in a range
arr[1:5]

输出:

array([1, 2, 3, 4])

8.广播

术语广播描述了 Numpy 在算术运算中如何处理不同形状的数组。

Numpy 数组不同于普通的 Python 列表,因为它们具有广播的能力。

代码 1:

#Setting a value with
#index range
arr[0:5]=100#Show
arr

输出:

array([100, 100, 100, 100, 100, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])

代码 2:

#Reset array, we'll 
#see the reason behind it soon
arr = np.arange(0,11)#Show
arr

输出:输出:

array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

代码 3:

slice_of_arr = arr[0:6]#Show slice
slice_of_arr

输出:

array([0, 1, 2, 3, 4, 5])

代码 4:

#Change Slice
slice_of_arr[:]=99#Show Slice again
slice_of_arr

输出:输出:

array([99, 99, 99, 99, 99, 99])

代码 5:

arr

输出:

array([99, 99, 99, 99, 99, 99, 6, 7, 8, 9, 10])

正如您在上面的输出中所看到的,在我们的原始数组中也发生了变化!!

发生这种情况是因为*slice_of_arr*只是对*arr*的前五行的引用。赋值操作不会单独复制数据。

要复制数据,我们需要使用复制的方法!!

代码 6:

arr_copy = arr.copy()arr_copy

输出:

array([99, 99, 99, 99, 99, 99,  6,  7,  8,  9, 10])

让我们看另一个广播的例子

代码 7:

a = [[1,2,3],[4,5,6]]#Converting to 
#numpy 2d array
np_a = np.array(a)#show
np_a

输出:

array([[1, 2, 3],        
       [4, 5, 6]])

代码 8:

#2 rows, 3 columns
np_a.shape

输出:

(2, 3)

代码 9:

b = [100,200,300]#converting to 
#numpy array
np_b = np.array(b)#show
np_b

输出:

array([100, 200, 300])

代码 10:

np_b.shape

输出:

(3,)

代码 11:

np_b_reshaped = np_b.reshape(1,3)#show
np_b_reshaped

输出:

array([[100, 200, 300]])

代码 12:

#1 row, 3 columns
np_b_reshaped.shape

输出:

(1, 3)

看看广播的魔力

代码 13:

np_a + np_b_reshaped

输出:输出:

array([[101, 202, 303],        
       [104, 205, 306]])

所以基本上第二行&的np_b_reshaped复制了自己,它的形状变成了(2,3)

代码 14:

np.array([[100,200,300],[100,200,300]])

输出:

array([[100, 200, 300],        
       [100, 200, 300]])

9.索引 2D 数组(矩阵)

一般格式为arr_2d[row][col]arr_2d[row,col]

代码 1 :

arr_2d = np.array(([1,2,3],[4,5,6],[7,8,9]))#Show
arr_2d

输出:

array([[1, 2, 3],        
       [4, 5, 6],        
       [7, 8, 9]])

代码 2:

#Indexing row
arr_2d[1]

输出:

array([4, 5, 6])

代码 3:

#Getting individual element value
arr_2d[1][0]

输出:输出:

4

代码 4:

#another way
arr_2d[1,0]

输出:

4

代码 5:

#2D array slicing
#Shape (2,2) from
#top right cornerarr_2d[:2,1:]

输出:

array([[2, 3],        
       [5, 6]])

代码 6:

#Shape of the 
#bottom row
arr_2d[2]

输出:

array([7, 8, 9])

10.选择

让我们简单地看一下如何使用括号进行基于比较运算符的选择。

代码 1:

arr1 = np.arange(1,11)#show
arr1

输出:

array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

代码 2:

arr1 > 5

输出:

array([False, False, False, False, False,  True,  True,  True, True,          True])

代码 3:

bool_arr = arr1 > 5#show
bool_arr

输出:

array([False, False, False, False, False,  True,  True,  True, True, True])

代码 4:

arr1[bool_arr]

输出:

array([ 6,  7,  8,  9, 10])

代码 5:

arr1[arr1 > 2]

输出:

array([ 3,  4,  5,  6,  7,  8,  9, 10])

11.数字运算

a)算术

您可以轻松地用数组算法执行数组运算,或者用数组算法执行标量运算。让我们看一些例子。

代码 1:

arr2 = np.arange(0,10)

代码 2:

arr2 + arr2

输出:

array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

代码 3:

arr2 * arr2

输出:

array([ 0,  1,  4,  9, 16, 25, 36, 49, 64, 81])

代码 4:

arr2 - arr2

输出:

array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

被零除的警告,但不是错误!

Numpy 会用 nan 代替它

代码 5:

arr2 / arr2

输出:

/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:3: RuntimeWarning: invalid value encountered in true_divide
  This is separate from the ipykernel package so we can avoid doing imports untilarray([nan,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.])

另一个警告,但不是错误。值将被替换为无穷大。

代码 6:

1 / arr2

输出:

/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:2: RuntimeWarning: divide by zero encountered in true_dividearray([inf, 1., 0.5, 0.33333333, 0.25, 0.2, 0.16666667, 0.14285714, 0.125, 0.11111111])

数字的立方

代码 7:

arr2 ** 3

输出:

array([0, 1, 8, 27, 64, 125, 216, 343, 512, 729])

b)通用数组函数

Numpy 预装了许多通用数组函数,这些函数本质上只是数学运算,您可以使用它们来执行跨数组的运算。来看几个常见的。

求平方根

代码 1:

np.sqrt(arr2)

输出:

array([0\. , 1., 1.41421356, 1.73205081, 2., 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.])

计算指数(e^x)

代码 2:

np.exp(arr2)

输出:

array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,        5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,        2.98095799e+03, 8.10308393e+03])

与 arr.max()相同

代码 3:

np.max(arr2)

输出:

9

计算正弦值

代码 4:

np.sin(arr2)

输出:输出:

array([ 0.,  0.84147098,  0.90929743,  0.14112001, -0.7568025 ,        -0.95892427, -0.2794155 ,  0.6569866 ,  0.98935825,  0.41211849])

计算日志

代码 5:

np.log(arr2)

输出:输出:

usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in log
  """Entry point for launching an IPython kernel.array([ -inf, 0., 0.69314718, 1.09861229, 1.38629436, 1.60943791,  1.79175947, 1.94591015, 2.07944154, 2.19722458])

12.…向量化…

矢量化用于在不使用循环的情况下加速 Python 代码。

可以对向量和矩阵执行各种操作,如点积、元素积等。

点积的矢量化版本

代号:

import timea = np.random.rand(1000000)b = np.random.rand(1000000)tic= time.time()c = np.dot(a,b) #dot product of two vectorstoc = time.time()print("Time taken in vectorized version: "+str(1000 * (toc - tic))+" ms")

输出:

Time taken in vectorized version: 1.483917236328125 ms

让我们检查 for loop 版本的点积

代码:

c = 0tic = time.time()for i in range(1000000):
  c += a[i] * b[i]toc = time.time()print("Time taken in for loop version: "+str(1000 *(toc - tic)) + " ms")

输出:

Time taken in for loop version: 579.4703960418701 ms

因此,从上述分析中得出的基本结论是向量化比简单的循环更加强大和高效。它花费很少的时间。所以尽可能避免显式的 for 循环。

13.结论

我已经尽力给你全面介绍了 NumPy。

有了这个软件包,线性代数变得轻而易举。

NumPy 是 python 中科学计算和数学运算的基础包。

NumPy 比列表更强大。

14.Github 知识库

请继续查看我的 GitHub 库,获取完整的代码。

以下是我的中型文章 GitHub 资源库的链接:

[## shubhanshu 1995/My-Medium-文章

在 GitHub 上创建一个帐户,为 shubhanshu 1995/My-Medium-Articles 的开发做出贡献。

github.com](https://github.com/shubhanshu1995/My-Medium-Articles)

这里是我的 NumPy Jupyter 笔记本的直接链接,其中包含了本文中使用的所有代码片段

[## shubhanshu 1995/My-Medium-文章

github.com](https://github.com/shubhanshu1995/My-Medium-Articles/blob/master/A_Comprehensive_Guide_to_NumPy.ipynb)

15.参考

[## 快速入门教程- NumPy v1.20.dev0 手册

在阅读本教程之前,你应该了解一点 Python。如果你想刷新你的记忆,看看…

numpy.org](https://numpy.org/devdocs/user/quickstart.html)

16.推荐阅读

如果你对学习 CS 基础感兴趣。如果你对学习数据结构和算法感兴趣,那么看看我的第一篇关于堆排序算法的博客。

[## 用 C++实现解释堆排序

你好世界。欢迎来到我的第一个关于媒体的博客。

medium.com](https://medium.com/@shubhanshu1995/heap-sort-explained-with-c-implementation-85e4fe3f5279)

感谢您阅读这篇文章。

如果你有任何问题,请在下面留言。

新冠肺炎时间养老院:为什么有这么多护理和保护失败的例子?

原文:https://towardsdatascience.com/nursing-homes-in-covid-19-time-why-so-many-examples-of-failure-to-care-and-protect-e0ea38f6fd2c?source=collection_archive---------68-----------------------

走向数据科学

数据显示,许多发达国家的护理院在保护和拯救弱势人群免受冠状病毒感染方面存在无名的失败

黄之锋Unsplash 上的照片

疗养院:不仅是一个沉重的打击,而且也是卫生保健系统的失败!

养老院(NH)和长期护理(LTC)部门普遍受到新冠肺炎疫情的重创。本说明通过观察和数据分析,研究了疫情在世界各国和各地区的 NH 经验的相似性和差异性。以下是在第一次分析中得出的一些发现,这些发现导致之前的一篇文章触及了魁北克的这个主题,在加拿大新冠肺炎疫情的第一周,魁北克的养老院情况最糟糕:

[## 魁北克对新冠肺炎的不同反应

就在许多地区的商业和学校重新开放之前,加拿大的这个省出现在了前 10 名最高的…

medium.com](https://medium.com/swlh/quebecs-distinct-response-to-covid-19-6caf65543574)

今年 5 月观察到的情况,以及前一篇文章中报道的情况,在美国病例上升、欧洲一些地区重新出现的情况下,目前甚至更有意义。根据最近纽约时报6 月 27 日发布的分析,现在,在美国 130,000 多例冠状病毒死亡中,超过 40%与疗养院有关。事实上,《纽约时报》的数字(即 43%)包括了新冠肺炎确诊死亡病例和疑似病例。

正如雅虎财经上周五所指出的,专家将这一失败归咎于全国各地养老院面临的资源缺乏,以及他们特别脆弱的人群。

[## 冠状病毒如何肆虐一个已经“陷入危机”的养老院行业

冠状病毒疫情已经影响了所有种族和年龄的人,尤其是破坏了养老院和…

finance.yahoo.com](https://finance.yahoo.com/news/coronavirus-nursing-homes-162629862.html)

6 月 13 日,《每日邮报》报道称,冠状病毒已经杀死了 16 名护理院居民中的 1 人。

疫情期间,英国政府因其对护理院的处理受到广泛批评,自 3 月份首次发病以来,病毒传播的数字迅速上升。

[## 在英格兰和威尔士,Covid 已经杀死了 1/16 的养老院居民

新的研究表明,冠状病毒现在已经导致英格兰和威尔士 16 个护理院居民中的一个死亡。的…

www.dailymail.co.uk](https://www.dailymail.co.uk/news/article-8404653/Coronavirus-killed-1-16-care-home-residents-England-Wales-analysis-reveals.html)

他们是对的:数据显示,自疫情爆发以来,护理院已有 26211 人超额死亡。在一个对它们有特殊保护的国家,这是世界上最高的。只有一个国家,比利时,在养老院死亡的绝对数字上有更高的份额。值得注意的是,比利时是少数几个将疗养院中疑似冠状病毒导致的 T2 死亡作为官方病例统计的司法管辖区之一。

一些州和较小的管辖区也有类似的失败趋势

截至 5 月 24 日,美国有类似数量的人死于疗养院,即根据 CMS(医疗保险和医疗补助服务中心)的计算,超过 26000 人,并于 6 月初在 MSN 上报道。在美国的许多州和县,这个数字每天都在增长。值得注意的是,在目前增长最快的 NH 死亡人数(人均)中,亚利桑那州 Puma 县 6 月 30 日的报告显示,该县 50%的死亡人数是 LTC 居民(在那一周,总共 263 人中有 136 人死亡)。这一趋势与前 3 周相似,并且与一个月前相比有所增长。

因此,使用最新完成的 CMS 数据(6 月 21 日)绘制美国疗养院的死亡地图是很重要的。它显示了新冠肺炎死亡人数最多的地区。注意:该图仅考虑了“确认”的测试死亡人数,该数字使用根据 CMS 图的“每百万居民”比率。例如,在马萨诸塞州,“38472”意味着 3.8%的居民死亡。值得注意的是,截至 6 月 21 日,该州有 3012 例死亡,新冠肺炎 NH 病例中有 20.1%的死亡,而在新泽西,NH 居民中有 3416 例死亡,死亡率为 3.3%,占 NH 病例的 11.9%。

来源: CMS 数据集;介词截至 2020 年 6 月 21 日,美国比洛多——养老院居民每百万人死亡地图【SB】data.cms.gov

一些州和国家的养老院似乎特别容易受到高传染性病毒的影响,因为它们的设置,年老体弱的居民经常住在共用的房间里,与工作人员密切接触,这些工作人员可能在没有症状的情况下被感染。

这就是为什么我们将疗养院(NH)的工作扩展到更广泛的领域,拥有新的权限和更全面的数据集。简而言之,这项分析包括超过 23 个国家、省、州和地区,这些国家、省、州和地区有足够的数据可供报告。

请注意,由于 NH 和 LTC 的不同定义以及新冠肺炎测试和报告实践中不同国家之间的差异,必须极其谨慎地解释比较结果。值得注意的是,开始报告或包括(如比利时和魁北克)或不包括(如其他)新冠肺炎“疑似”死亡的日期。然而,任何比较都提供了另一个视角,让我们从不同的经历中学习。在这样一个不可思议的时代,不应该回避任何信息来源、比较或学习。每个生命都值得。

这需要的不仅仅是“自由放任”

虽然此处报告的正在进行的研究集中于疗养院和/或长期护理中心的新冠肺炎死亡,但它也触及了解决疫情的政策响应。

在 6 月 9 日的一篇 Medium 文章中,Tomas Pueyo 对群体免疫策略(所谓的“自由放任”方法)和锤子&舞蹈(“碾压曲线”)策略进行了比较。

来源:to MAS PUE yomedium . com/coronavirus-we-should-aim-for-herd-immunity-like-Sweden

Pueyo 报告说,瑞典为保护养老院采取的第一项措施是实际禁止探访,但未能保护其老年人。即使这种措施仍然限制了传染,也不足以控制护理院环境中的感染传播。瑞典首席流行病学家安德斯·泰格内尔承认:

我们很难理解一级防范禁闭将如何阻止疾病进入养老院。(……)这不是总体战略的失败,而是保护老年人的失败。

但是,尽管看起来很糟糕,瑞典的例子还远不是保护弱势群体失败的最糟糕例子,特别是在长期护理(LTC)环境中。

截至 2020 年 6 月 25 日,养老院和长期护理中心居民中报告的新冠肺炎死亡人数差异很大,从斯洛文尼亚的 10 人或澳大利亚的 28 人到美国的 33,500 人,比利时和加拿大的超过 5,000 人,到法国、意大利、西班牙和英国的超过 10,000 人

五月底,英国出现了一个关于疗养院的错误策略的例子。即使 3 月 19 日英国国家医疗服务体系(NHS)和政府发给医疗服务提供者的一封信(旨在释放医院容量)命令“那些不再需要躺在病床上的人安全快速地出院,新的默认将是今天出院回家”。这种“出院”与英国公共卫生部的第一个(也是正确的)反应相反。英国(PHE)在二月份警告说,如果存在传播病毒的严重风险,老年人不应该从医院出院到护理院。

[## 英格兰超过一半的冠状病毒相关死亡将是来自护理院的人

护理院居民将占冠状病毒直接或间接导致的死亡人数的一半以上…

www.theguardian.com](https://www.theguardian.com/society/2020/jun/07/more-than-half-of-englands-coronavirus-related-deaths-will-be-people-from-care-homes)

许多国家都犯了和英国一样的错误。事实上,在养老院死亡人数超过 5000 人的国家中,我们可以在大多数主要的新冠肺炎地区找到同样的痕迹。保护主要卫生机构(即医院)可能会损害长期护理院的利益。

许多“所谓的”发达国家做出了错误的选择

OECD 国家/地区,平均有超过 5500 名长期护理住院患者死亡,其中许多国家/地区的长期护理死亡比例很高。值得注意的是,养老院居民占加拿大所有报告的新冠肺炎死亡人数的 68%(占加拿大所有 LTC 的 81%),西班牙的 66%和比利时的 64%,而其他经合组织国家的平均水平超过 42%(斯洛文尼亚和匈牙利的一些国家不到 10%,奥地利和荷兰不到 20%)。

数据:卫生当局;介词 S.BilodeauDatawrapper 创建;注:只有比利时和魁北克(加拿大)在报告中包括疑似新冠肺炎疗养院死亡病例(在这两种情况下,分别占病例的 22%和 20%)

各地区、州或省之间的差异大于经合组织国家之间的总体差异。在这方面,加拿大各省之间的差异尤其明显。截至 6 月 25 日,纽芬兰省和拉布拉多半岛、爱德华王子岛省、新不伦瑞克省和其他地区没有养老院和长期护理机构的死亡报告,而在魁北克省、安大略省和阿尔伯塔省,NH 死亡人数占新冠肺炎死亡人数的 65%以上。在新斯科舍省,97%的死亡发生在 LTC。

在美国,我们也看到各州之间的重要差异。马萨诸塞州、康涅狄格州和新泽西州每百万人口中养老院的死亡人数最少,而宾夕法尼亚州是 NH 死亡人数与新冠肺炎总死亡人数之比最大的州。虽然没有前几个州高,但亚利桑那州现在显示出死亡率的最大周增长率。

一般来说,社区中新冠肺炎感染率较低的管辖区报告的 NH 病例和死亡人数较少。但是有很多种情况。作为新冠肺炎病例总数的一部分,疗养院中的病例比例从澳大利亚的不到 1%到加拿大的 18%,到法国的 51%和英国的 73%

感染 NH 的居民死于该疾病的比例在不同国家也有很大差异,从斯洛文尼亚的 4%到挪威的 83%。在加拿大,截至 6 月 25 日,NH 中感染新冠肺炎病毒的死亡率约为 36%。

成功是可能的

许多国家报告了卫生保健工作者的高感染率,导致缺勤和人员短缺。

CIHI(加拿大健康信息研究所)6 月发布的新报告:“长期护理领域的疫情”证实了我们过去几周的发现。他们强调了一个有趣的观点:“在限制和关闭公共场所的同时,实施了专门针对 LTC 部门的强制性预防措施的国家(澳大利亚、奥地利、荷兰、匈牙利和斯洛文尼亚)在 SLD 中的新冠肺炎感染率和疾病相关死亡率较低。”这些是需要在失败的(疗养院)卫生系统中复制的成功故事。

资料来源:cihi.ca/en在该国出现第 1000 例新冠肺炎病例时宣布或实施的新冠肺炎政策干预的影响 o 截至 2020 年 5 月 25 日的长期死亡/总死亡和病例比率

为使疗养院的成功机会最大化,包括一些预防措施,如即时感染控制措施、访客限制、急性护理和个人防护设备资助、LTC 设施中的招募、培训和普遍筛查、建立隔离单位以管理病例群、广泛的 LTC 检测、感染控制培训和审计、快速反应控制、预防团队和对员工的额外支持。LTC,如增加人员配备、创建专业团队和分发个人防护设备(PPE)。

工作人员管理和保护,一个明确的问题来源

在“不那么”受控制的疫情,试图通过探视限制来限制疗养院的感染将需要持续数月,甚至数年,直到出现治疗或疫苗。这是因为即使许多人已经克服了感染,病毒仍然存在。

根据英国国家统计局的数据,英国那些雇佣更多机构员工或不提供病假工资的养老院,其居民中新冠肺炎感染率更高。

周五发表的 Vivaldi 研究基于英国 5126 家护理院的回应,发现大多数时间或每天使用银行或机构护士或护工的护理院居民比那些不使用这些工作人员的护理院居民新冠肺炎病毒检测呈阳性的可能性高 1.58 倍。

资料来源:【ons.gov.uk 图 1:按工作人员感染、地区、使用银行或机构护理人员以及在其他地点工作的工作人员分类的养老院居民新冠肺炎感染几率

[## 冠状病毒对英格兰养老院的影响——国家统计局

2020 年 5 月 26 日至 6 月 20 日,作为维瓦尔第项目的一部分,英格兰的 9,081 家护理院(全部由……

www.ons.gov.uk](https://www.ons.gov.uk/peoplepopulationandcommunity/healthandsocialcare/conditionsanddiseases/articles/impactofcoronavirusincarehomesinenglandvivaldi/26mayto19june2020)

简而言之,在英格兰和威尔士护理院冠状病毒相关死亡人数升至 19394 人之际,英国国家统计局的调查结果突显出合同制员工(通常是低薪和“零时工”合同)可能无意中助长了病毒的传播。另一方面,在工作人员领取病假工资的护理院,与工作人员领取病假工资的护理院相比,住院病人检测呈阳性的几率估计在 0.82 到 0.93 之间。

托马斯·普约在 6 月 9 日的文章中指出:

老人还是需要工人照顾的。这些被称为 shielders 的工人会怎么样?他们也会被隔离吗?好几年了?他们的伴侣呢,也会被隔离吗?他们会失业吗?他们的孩子呢,他们也应该被隔离吗?不上学了?如果不是,那么其他孩子和他们的父母呢?他们应该被隔离吗?所有这些都是不可能的,所以我们必须假设许多护理之家的工作人员会被感染。如何保护老年人免受其害?

绿化疗养院

在这段时间里,只要疗养院里有一个人被感染,病毒就会像野火一样在里面蔓延。因此,这意味着如果我们不能在普通人群中用“绿区”方法或“零感染”策略来控制病毒,那么多年内都不能就诊。

[## 绿色区域——EndCoronavirus.org

严格的旅行限制,在抵达时进行检测和隔离,将有助于减少进口…

www.endcoronavirus.org](https://www.endcoronavirus.org/green-zones)

一些“失败的养老院”政府试图采取适当的方式,并建立良好的做法,如在后续国家。周五,魁北克公共卫生主任 Horacio Arruda 博士宣布,养老院和长期护理中心的所有工作人员,特别是在大都市地区,将每周接受一次检测,以检测出病毒携带者但没有症状的人。虽然这还是一小步,但这是重要的一步,因为无症状人群是疫情的重要隐形载体。比利时有超过 61 509 例严重急性呼吸综合征新型冠状病毒感染确诊病例和 9754 例相关死亡病例。4 月,卫生部决定在长期护理设施中开展大规模检测活动。《柳叶刀》发表的一项新研究揭示了 2020 年 4 月 8 日至 5 月 18 日期间从实验室收到的数据的横截面分析。对在长期 CFs 中进行的大量测试的分析显示,无症状病例的比例很高(见下面的“附录 2”图表)。这证实了之前在欧洲和中国进行的研究,评估无症状新型冠状病毒感染的比例在受试人群的 20%至 88%之间。

来源:安娜·霍查克洛伊·温德姆-托马斯索菲克·克拉默多米尼克·杜伯格梅丽莎·维穆伦马奈·哈玛米等人 Thelancet . com/journals/laninf/article/piis 1473–3099(20)30560–0

因此,比利时的布鲁塞尔地区与红十字会合作,为养老院的所有护理人员制定了指南和特殊的新冠肺炎课程,以确保无症状者不会传播更多的感染。

英格兰和鲸鱼还参与了一项名为“冠状病毒对护理院的影响”的大型研究,该研究旨在更好地了解并纠正该领域的严峻形势。

资料来源:国家统计局——涉及新冠肺炎护理部门的死亡

所有这些都提出了许多国家社会保健系统的状况问题,这些国家多年来迫切需要改革。它经常资金不足,而护理人员的工资却很低。在我们的新冠肺炎养老院死亡人数与总死亡人数图表中,许多国家的养老院死亡人数没有那些“前 12 名”管辖区高,我们经常可以看到一个成功的模式。对于同一图表中排名倒数 10 位的许多国家来说尤其如此(如德国、葡萄牙、挪威、以色列或斯洛文尼亚)。值得注意的是,我们将会看到一个由训练有素、受人尊敬的护理人员组成的不同体系,他们的艰苦工作会得到更合理的回报,而不是依赖多个机构的工作来谋生,从而导致病毒从一个机构迅速传播到另一个机构。

现在还需要改进

现在比以往任何时候都更需要纠正这种情况。上世纪中叶,玛格丽特·米德博士定义了人类文明的一个特征。Ira Byock 博士在他关于姑息医学的书中报道了这一点【最好的护理:一位医生对临终关怀的探索】 (Avery,2012)。

几年前,一个学生问人类学家玛格丽特·米德,她认为什么是一种文化中文明的第一个标志。这个学生以为米德会谈论鱼钩、陶罐或磨石。但不是。米德说,古代文化中文明的第一个标志是一根被折断然后愈合的股骨。

米德解释说,在动物王国里,如果你摔断腿,你就会死去。你不能逃避危险,去河边喝水或寻找食物。你是觅食野兽的肉。没有动物能在断腿后存活到骨头愈合。愈合的股骨骨折证明有人花时间陪伴跌倒的人,包扎伤口,把他带到安全的地方,并照顾他康复。米德说,帮助他人渡过难关是文明的起点。当我们为他人服务时,我们处于最佳状态。要文明。

来源:britannica.com/biography/Margaret-Mead

从失败中吸取教训并扩大成功不仅仅是我们政府的责任。是让所有的领导都站出来。社区、城市或地区、养老院或家庭的领导者。比如一个月前《经济学人》的一篇文章中强调的,

新冠肺炎已经证明了繁荣的基础是不稳固的。人们谈论了很久,却忽视了很久的灾难会毫无征兆地降临到你身上,颠覆生活,动摇一切看似稳定的事物。

[## 政客们忽视了远在天边的风险:他们需要提高自己的水平

1993 年,这份报纸告诉全世界要观察天空。当时,人类对小行星的了解可能…

www.economist.com](https://www.economist.com/leaders/2020/06/25/politicians-ignore-far-out-risks-they-need-to-up-their-game)

米德博士的这一见解在《疫情时报》上仍然很有价值。2020 年,那些忽视照顾弱势群体的人,那些拒绝社会距离,戴着面具,禁闭来拯救生命的人,应该思考一下。

因此,我们所有人都应该参与到拯救最脆弱人群的生命和痛苦的行动中来。在这样一个关键时刻,每个人都可以做出贡献。我们都可以在各自的社区、家人和朋友中成为领导者。我们的卫生系统,尤其是照顾最弱势群体的部门,以及我们每个人都需要做好准备,以避免另一次失败。我们需要在第一波结束前准备好。第二波可能很快会在混乱中出现。我们应该让弱势群体做好准备。

让我们文明一点!

eberhard grossgasteiger 在 Unsplash 上的照片

本文由夏羽·比洛多,ing 准备。工程博士,对外经济合作中心。创始人&首席技术官,Smart Phases ( Novacab ),加拿大工程师协会会员。他的文章涉及能源问题、可持续发展、创新、人工智能、数据科学和分析,以及新冠肺炎;他是能源中心创业DDI & 迈向媒介数据科学的专家贡献者。他也为EndCoronavirus.orgSTIM-科维德做贡献

.

Nvidia 3000 GPUs:数据科学家、游戏玩家和黄牛的碰撞

原文:https://towardsdatascience.com/nvidia-3000-gpus-where-data-scientists-gamers-and-scalpers-collide-7a9a6f34f81f?source=collection_archive---------19-----------------------

新 Nvidia Ampere 系列概述;不同的 GPU 基准、规格、传言和制造问题;以及我自己尝试购买 3000 系列 GPU 的经历

图片来源:克里斯蒂安·魏迪格

在这篇博客中,我将解释围绕新的 Nvidia Ampere 3000 系列 GPU 的宣传,它们与图灵 2000 系列卡的比较,以及当前每一代 RTX 可用的基准。我还会查看即将推出的 3080 变种的传言,以及来自用户的报告,称他们收到的卡有缺陷。在文章的最后,我将回顾一下我的观点和我对任何试图获得它们的人的建议,不管是针对游戏、数据科学还是后两者。

英伟达为什么这么受欢迎?

Nvidia 一直是 GPU 领域的赢家,但这是出于多种原因,而不仅仅是他们的“能力”。当你想比较 Nvidia 和 AMD GPUs 之间的计算能力或万亿次浮点运算量(TF)时,实际上没有太大的差异——而且往往 AMD 在这方面名列前茅。例如,当比较 AMD 镭龙 RX Vega 64(~ 400 美元)和 Nvidia 2080(~ 700 美元)时,你会看到 Nvidia 是最强大的这一论点的裂缝。当比较这些卡之间的万亿次浮点运算性能时,AMD 镭龙 64 在各个方面都名列前茅(FP16、FP32 和 FP64)。那么如果 AMD 以低得多的成本提供更强大(就 TF 而言)的卡,那么为什么 Nvidia 会被认为是最好的 GPU 制造商呢?真正的答案来自于 Nvidia 提供的花哨功能,以及它们如何针对多种不同类型的客户,从图形设计师、数据科学家,最重要的是,游戏玩家。说到游戏,TF 的数量并不等同于它们提供的游戏体验。看看织女星 64 和 RTX 2080,RTX 2080 在每一项游戏基准测试中都击败了织女星,平均每秒帧数(FPS)增加了 20%-50%[织女星 64 对 2080 基准测试 ]。我知道有些人可能会想,你到底为什么用 Vega64 和 RX 2080 做比较?我知道这些卡的用法完全不同,但我想说明的是,仅仅说“更强大”只是故事的一半。Nvidia 在 GPU 方面优于 AMD 的原因有很多,其中只有一部分原因是针对您计划使用硬件的方式的。我将在这篇博文的其余部分更详细地阐述我的意思。

图片来源:弗洛里安·奥利佛( Unsplash

RTX GPU 在现代游戏中如此强大的原因是由于他们的光线跟踪技术和 Nvidia 所谓的 CUDA 核心的实现。CUDA 核心是为游戏而创造的,但对 Nvidia 来说,锦上添花的是,它们在深度学习和人工智能方面也令人印象深刻——让这项技术拥有更广泛的目标受众。拥有更多 CUDA 内核不仅可以提高您实现神经网络和高级算法的能力,而且当应用于游戏时,它们可以创建更逼真的图形和更高的 FPS 率。

RTX 2000 系列(图灵架构)

为了充分理解为什么 3000 系列受到如此多的关注,了解上一代 Nvidia 卡以及 3000 系列在性能上的巨大飞跃是很重要的。为了保持一致,我将坚持使用这些卡:Nvidia 2060、2060S、2070、2070S、2080、2080S、2080ti 和泰坦 RTX。

英伟达图灵 2000 系列(作者供图)

上面我们可以看到 2000 系列产品中每个 GPU 的性能差异。我想指出的是,在这一代人之前,没有超级卡。Super 的实施被认为是对 AMD 激进定价策略的回应,因为 Nvidia 填补了每个型号之间的价格差距,使他们的产品比 AMD 更便宜的卡更具吸引力。我还想指出,上面列出的价格不是发布价格,而是亚马逊和新蛋的当前价格。这些卡刚上市时,每张卡的零售价格要高出 20%-40%。从这个系列到 3000 系列的一个主要飞跃是核心时钟、位带宽,以及最重要的 CUDA 核心数量。正如我们在上面看到的,2000 系列中的旗舰卡有 4606 个 CUDA 内核,384 位的位带宽,1350–1770 MHz 的时钟速度;上市时定价高达 2500 美元。这一性能令人印象深刻,但与新的 3000 系列产品相比,这些规格就显得微不足道了。

Nvidia 3000 系列(安培架构)

在这一代 GPU 中,Nvidia 真的超越了自己。他们不仅创造了一个击败他们最后一个的阵容,而且他们增加了一个新的定价策略,作为一个硬件公司,这是非传统的。下面你可以看到新系列的规格。每张标有***的卡都被认为是谣言,价格和规格都不确定。

英伟达安培 3000 系列 vs 图灵 2000 系列(作者供图)

正如你在上面看到的,价格不仅仅是上一代的一半,而且低端 3000 系列卡比他们的旗舰产品更快?我在这里加了个问号是因为和你一样,我就是不明白。看看售价约为 700 美元的 3080,我们可以看到它的 CUDA 内核几乎增加了 50%,时钟速度也高于之前的旗舰产品 RTX Titan——我知道,这很疯狂,对吧...通过创建这些卡并像这样定价,Nvidia 使他们自己的上一代产品完全无关紧要——也就是说,对于游戏玩家来说。这就引出了我的下一个话题, 记忆。2000 系列和 3000 系列的内存带宽略有不同,因为 3080 仅包含 10GB,比上一代 2080ti 少 1GB,后者包含 11GB。对于游戏玩家来说,1GB 的损失并不重要,只要 FPS 速率和光线跟踪内核增加,他们确实增加了。然而,对于深度学习和图形设计师来说,这有点令人失望。显卡中可用的内存带宽对于使用最先进的(SOTA)技术至关重要。这里是一篇解释内存带宽如何重要,以及某些深度学习技术需要哪些 GPU 的文章。在这篇文章中,作者 Tim Dettmers 解释如下:

  • 追求最高分数的研究:> =11 GB
  • 寻找有趣架构的研究:> =8 GB
  • 任何其他研究:8 GB
  • ka ggle:4–8 GB
  • 初创公司:8 GB(但检查型号大小的具体应用领域)
  • 公司:8 GB 用于原型开发,> =11 GB 用于培训

考虑到这一点,尽管 3080 缺乏内存带宽令人失望,但包含一个巨大的 24gb 3090 模型弥补了一些人感到的痛苦。看看新的 3090 系列,它不仅包含更多的 CUDA 内核,而且比 RTX Titan 多 2GB 的内存——别忘了它便宜 1000 美元!

3080 20GB 谣言

如果你是少数有机会在发布日购买 3080 GPU 的人之一,你可能会恐慌地看着图表。虽然还不确定,但有无数可靠的消息来源透露,将会有 3080 20GB 的变体。就我个人而言,当我读到这些时,我感到非常欣慰,因为我自己也在试图购买 3080。这个版本背后的想法是,Nvidia 将在 AMD 的大 Navi 发布的同一周内发布这个变种。AMD 宣布了他们下一代 6000 系列卡的一些规格,显示他们的旗舰将包含总共 16GB 的内存,并将比 3080 更快。这一增长也令人印象深刻,但 Nvidia 坚持 20GB 的型号是天才,因为它将比大 Navi 版本更有吸引力。Carly Page 的这篇文章概述了泄露的规格以及它们与 Nvidia 3000 系列的比较。如果 AMD 真的创造了一种比 3080 更快的卡,那么 3080 拥有更多内存将把客户推向 Nvidia,而不是 AMD。

第一次泄露来自技嘉网站。正如你在这里看到的,他们公布了 3000 系列发布的各种兑换代码,包括尚未公布的卡。当我看到这些时,我已经确信这是真的,尤其是 Nvidia 还没有纠正这些谣言,并保持沉默。

在这次泄露几天后,另一家 GPU 制造商 Galax 又泄露了一次。在这次泄露的中,一份内部演示中的路线图显示了 3080 20GB 的变体。考虑到这两个泄漏发生在同一个星期,而 Nvidia 对此只字未提,在我看来,很明显这个版本可能真的会发布。

从机器学习的角度来看,推出价格低于 1000 美元的 20GB 卡将是一个游戏规则改变者——尤其是对我来说,因为我目前使用的是 RX 580 8GB 卡。然而,从游戏的角度来看,这些内存的增加对大多数人来说并不重要。我将谈谈我对 3090 年前后大规模炒作的看法,以及为什么有些人不应该因为他们计划将它用于游戏而感到兴奋。

损坏/缺陷卡的报告

当用户开始实际收到他们的卡时,已经有许多报告说卡不能如预期的那样工作,或者他们的卡在装运时没有盒子,导致卡弯曲和美观损坏。前一个没有盒子的贺卡问题在本文中有所概述,作者解释说这是像新蛋这样的分销合作伙伴的错。另一方面,要完全理解卡崩溃和不能正常工作的原因,你还必须知道卡的分发和制造是如何工作的。当 Nvidia 创建一个 GPU 时,市场上会有不同的版本。例如,每个创始人版卡都是 Nvidia 自己创建的,被认为具有最好的硅胶质量和规格,以便创建卡设计的完整体验。另一方面,Nvidia 也将其设计授权给第三方制造商,如 EVGA 和华硕,这些公司被给予这些卡工作所需的最低规格。许多人遇到的问题是由于这些最低要求以及这些卡上的电容布局。如下图所示,左图是一张方正版卡片,包含两排大电容和一排非常小的电容(中间一排)。看一下中间的卡,我们看到每行只有小电容,这使得该卡的制造成本更高。最后,Zotac 卡是报告问题的卡之一,它只有更大、更便宜的电容器。从这些卡有缺陷的意义上来说,这些问题不是问题,而是它们不能提升到它们想要的时钟速度。电容的作用是实现安全稳定的能量传输。只有大电容会使卡不稳定,并在卡试图自我增强时导致崩溃。在由 JayzTwoCents 制作的视频中,他解释了为什么会发生这种情况,以及对那些有这个问题的人可能的解决方法。

左(创始人版)、中(华硕 TUF)、右(Zotac)[图片鸣谢: JayzTwoCents & 伊戈尔的实验室 ]

图片来源: Giphy

我的看法

在我进入之前,我想指出的是,人们有购买他们想要的东西的自由,仅此而已。这些意见只是表达了如何以更好的方式花钱,以及 GPU 硬件的整个倒票时代是如何毫无意义,因为我相信人们会在尝试这样做时被严重烧伤。

虽然新推出的 3000 GPU 在性能升级方面令人难以置信,但如果你只是将这些 GPU 用于游戏,就必须考虑一些事情。作为一个狂热的游戏玩家,我觉得我可以为为什么某些型号不应该这么快售罄提供意见,因为花那种钱去看 最低限度的 性能提升是没有意义的。对比 3090 和 3080,Youtube 上有大量基准视频显示,尽管价格差距为 700 美元,但 FPS 性能并没有太大差异。在本文中,作者展示了基准性能,并显示 3080 和 3090 的性能仅提高了 10%。此外,考虑到 CUDA 内核,3090 中当然有更多,但由于它们都远高于上一代旗舰机型,额外的 2000 个 CUDA 内核对游戏几乎没有影响。我可能有偏见,因为我是一名痴迷于神经网络的数据科学家,但我相信 3090 最适合数据科学和机器学习。额外的 14GB 内存乍一看似乎很性感,但它真正改变您游戏体验的唯一情况是您在 8K 显示器上玩游戏,我敢肯定只有非常少的一部分游戏玩家会这样做。是的,有些人可能会说,“好吧,山姆!它的未来证明”。虽然这是正确的,但所有关于现在得到它的宣传对我来说毫无意义。你不仅需要一个高端处理器,比如 i9 或锐龙 9(价格在 700-1000 美元之间),而且你肯定还需要升级你的电源。因此,如果你是一个购买了 3090 的狂热游戏玩家,你不仅在卡上花了 1500 美元,在 PSU 上花了 200 美元,而且除非你有可以处理 GPU 的 CPU,否则你在体验上看不到任何差异(除非你是从 GTX 900 系列卡或更低版本升级)。

头皮

转向我的下一点,黄牛们!我自己从来没有当过球鞋头,但现在我理解了他们每次发射时应对的痛苦。你可能会认为这些大公司,特别是像英伟达这样在机器学习方面有如此大影响力的公司,应该已经预料到这一点或开发出检测黄牛的算法。当然,这是对创建这种算法的难度的过度简化,然而,我仍然相信 Nvidia 从现在到 10 月下旬的下一次发布有足够的时间来修复它。

图片来源:内里诺( Memedroid

在我看来,人们看到了购买一个被大肆宣传的产品的机会。但是,与运动鞋不同的是,显卡并不局限于生产。是的,这个版本的库存有限,但不是因为 Nvidia 希望它这样,而是因为由于新冠肺炎产量下降。例如,像耐克这样的大型运动鞋公司会宣布他们将发布一款鞋,但他们只生产了几百款。在这种情况下,Nvidia 每周都会不断生产更多产品,并计划在未来几个月内恢复正常生产。黄牛认为他们可以购买一张卡,并以高于零售成本 1000 美元的价格出售,这是令人惊讶的愚蠢。是的,也许有些人在易贝成功地推销了他们的产品,但我敢打赌,那是极少数人。仅仅因为易贝上有数百种售价 1000-2000 美元的新卡上市,并不意味着人们会购买它们。

图片来源:吉菲

我想买 3090 的经历

为了充分了解情况的严重性,让我向您介绍一下 我的经历 在发布日试图在我当地的 Micro Center 购买 3090。我醒得特别早,因为我知道商店开门前外面会排起长队。老实说,因为我没有计划露营前一天晚上,我知道我能够得到一个 3090 的机会很渺茫,考虑到 3080 一周前推出,但我仍然想尝试,并看到自己的混乱。我终于在他们开门后大约 20 分钟到达了微中心,不出所料,有几十个人在商店外面露营。当我走到门口时,我看到两个人拿着他们全新的 3090 走出商店。商店外面的露营者一看到他们,就有两个人冲到幸运的购买者面前,问他们是否可以以比他们刚刚在里面支付的价格多 500 美元的价格从他们那里购买卡片。我听到的答案让我很失望。当这些人被问及是否愿意出售这些卡片时,他们的回答是这样的:“嗯,我打算在易贝以 4000 美元的价格出售这张卡片”。我心想…多傻啊… $4000??!?!?考虑到你可以花不到 4000 美元买一台内置 3090 的预装电脑,这种逻辑是如此荒谬。因此,如果有人非常渴望这张卡,他们可以购买预建的卡,取出卡,出售其他部分,花掉卡的价值。当然,我不希望任何人倒霉,考虑到当今的经济形势,挣 1000 美元的机会对一些人来说非常重要;然而,我只是希望吸取一个教训,鞋子和 GPU 是完全不同的东西。

图片来源:吉菲

我的建议

我的建议很简单。如果你目前还没有显卡,而你一直在等待这个版本,那么尽一切办法去尝试获得一个。我去过那里,我知道建造一台电脑并在你自己的游戏上尝试的兴奋,所以我一点也不轻视它。然而,如果你不能得到卡,我建议得到一个临时卡,如 1660 或 RX 580。你可以在易贝以低于 200 美元的价格买到这些卡片,它们非常好用。目前,我有一台 125 美元买的 RX 580 8GB。在每一个游戏中,(堡垒之夜,英雄联盟,鳕鱼战争区)我都在 1080p 获得了惊人的画面。这些卡片的美妙之处在于它们买起来很便宜,而且当你用完它们时,总会有转售的市场。如果你急着要买一台游戏电脑,就买一张这样的卡,一直用到你觉得买新一代 3000 卡没那么麻烦为止。例如,假设你花 150 美元买了一台 RX 580。一旦你觉得 3000 系列卡很容易得到,就以 100 美元的价格出售 RX 580,以保证快速销售。这样做之后,你只花了 50 美元买了一张临时卡,就能拥有你想要的游戏体验,而不是什么都不等。

如果你是一名数据科学家,我的建议会更悲观(这就是我现在正在经历的)。目前,我正在做几个不同的项目,这些项目让我很头疼如何使用我的显卡,所以能够升级的想法真的很令人兴奋。因为这些发射是一场灾难,唯一能做的就是等待。对我来说,我计划等到 10 月下旬 AMD/Nvidia 发布新卡,也许我会在商店露营-我还不确定。在我看来,卡的稀缺性将开始减少,因为 Nvidia 会像过去一样增加生产和销售。

图片来源: Giphy

我希望我能提出一些好的建议。如果你和我处于相似的位置,不要担心,我们是一起的:)

再过几个月,库存就会得到补充,黄牛党就会明白,这是一个糟糕的商业决策。

NVIDIA DALI:加速 PyTorch

原文:https://towardsdatascience.com/nvidia-dali-speeding-up-pytorch-876c80182440?source=collection_archive---------10-----------------------

提高 DALI 资源利用率的一些技术&创建一个完全基于 CPU 的管道。PyTorch 培训速度提升高达 4 倍

TL;DR:我展示了一些提高 DALI 资源利用率的技术&创建一个完全基于 CPU 的管道。与 DALI 包提供的示例 CPU 和 GPU 管道相比,这些技术稳定了长期内存使用,并允许大约 50%的大批量。使用 Tesla V100 加速器进行的测试表明,PyTorch+DALI 可以达到近 4000 张图像/秒的处理速度,比原生 PyTorch 快约 4 倍。

更新 20/3/2019: DALI 0.19 改进了内存管理,消除了内存使用量的逐渐上升( 278 )。我仍然建议在使用 GPU 管道时重新导入 DALI,以减少 GPU 内存的使用。

介绍

过去几年,深度学习硬件领域取得了巨大进步。Nvidia 的最新产品 Tesla V100 & Geforce RTX 系列包含专用张量内核,用于加速神经网络中常用的操作。特别是 V100,它有足够的能力以每秒数千张图像的速度训练神经网络,将 ImageNet 数据集上的单 GPU 训练缩短到仅几个小时的小模型。这与 2012 年在 ImageNet 上训练 AlexNet 模型所需的 5 天时间相去甚远!

如此强大的 GPU 使数据预处理管道不堪重负。为了解决这个问题,Tensorflow 发布了一个新的数据加载器:tf.data.Dataset。该管道用 C++编写,并使用基于图形的方法,从而将多个预处理操作链接在一起形成一个管道。另一方面,PyTorch 在 PIL 库的基础上使用 Python 编写的数据加载器——在易用性和灵活性方面很棒,但在速度方面不太好。尽管 PIL-SIMD 图书馆确实改善了这种情况。

进入 NVIDIA 数据加载库(DALI):旨在消除数据预处理瓶颈,允许训练和推理全速运行。DALI 主要设计用于在 GPU 上进行预处理,但大多数操作也有快速的 CPU 实现。本文关注 PyTorch,但是 DALI 也支持 Tensorflow、MXNet 和 TensorRT。尤其是 TensorRT 的支持,非常棒。它允许训练和推理步骤使用完全相同的预处理代码。Tensorflow 和 PyTorch 等不同的框架通常在数据加载器之间有细微的差别,这可能最终会影响准确性。

以下是开始使用 DALI 的一些重要资源:

大理家园

用 NVIDIA DALI 快速 AI 数据预处理

大理开发者指南

入门

在本文的剩余部分,我将假设对 ImageNet 预处理和 DALI ImageNet 示例有基本的了解。我将讨论我在使用 DALI 时遇到的一些问题,以及我是如何解决它们的。我们将研究 CPU 和 GPU 管道。

DALI 长期记忆使用

更新 20/3/2019:此问题已在 DALI 0.19 中修复

我在 DALI 中遇到的第一个问题是,RAM 的使用随着每个训练时期而增加,导致 OOM 错误(即使在具有 78GB RAM 的 VM 上)。这已被标记( 278344486 ),但尚未修复。

我能找到的唯一解决方案并不漂亮——重新导入 DALI 并在每个时期重建培训和验证管道:

del self.train_loader, self.val_loader, self.train_pipe, self.val_pipe
torch.cuda.synchronize()
torch.cuda.empty_cache()
gc.collect()importlib.reload(dali)
from dali import HybridTrainPipe, HybridValPipe, DaliIteratorCPU, DaliIteratorGPU<rebuild DALI pipeline>

注意,使用这种解决方法,DALI 仍然需要大量 RAM 来获得最佳结果。考虑到现在 RAM 有多便宜(至少相对于 Nvidia GPUs 来说),这不是什么大问题;相反,GPU 内存是一个更大的问题。从下表中可以看出,使用 DALI 时可能的最大批量比 TorchVision 低 50%:

在接下来的几节中,我将介绍一些减少 GPU 内存使用的方法。

构建完全基于 CPU 的管道

我们先来看例子 CPU 流水线。当不需要峰值吞吐量时,基于 CPU 的管道非常有用(例如,当处理 ResNet50 这样的中型&大型模型时)。然而,CPU 训练管道仅在 CPU 上执行解码&调整大小操作,而 CropMirrorNormalize 操作在 GPU 上运行。这意义重大。我发现,即使只是用 DALI 将输出传输到 GPU,也使用了大量的 GPU 内存。为了避免这一点,我修改了示例 CPU 管道以完全在 CPU 上运行:

class HybridTrainPipe(Pipeline):
    def __init__(self, batch_size, num_threads, device_id, data_dir, crop,
                 mean, std, local_rank=0, world_size=1, dali_cpu=False, shuffle=True, fp16=False,
                 min_crop_size=0.08):

        # As we're recreating the Pipeline at every epoch, the seed must be -1 (random seed)
        super(HybridTrainPipe, self).__init__(batch_size, num_threads, device_id, seed=-1)

        # Enabling read_ahead slowed down processing ~40%
        self.input = ops.FileReader(file_root=data_dir, shard_id=local_rank, num_shards=world_size,
                                    random_shuffle=shuffle)

        # Let user decide which pipeline works best with the chosen model
        if dali_cpu:
            decode_device = "cpu"
            self.dali_device = "cpu"
            self.flip = ops.Flip(device=self.dali_device)
        else:
            decode_device = "mixed"
            self.dali_device = "gpu"

            output_dtype = types.FLOAT
            if self.dali_device == "gpu" and fp16:
                output_dtype = types.FLOAT16

            self.cmn = ops.CropMirrorNormalize(device="gpu",
                                               output_dtype=output_dtype,
                                               output_layout=types.NCHW,
                                               crop=(crop, crop),
                                               image_type=types.RGB,
                                               mean=mean,
                                               std=std,)

        # To be able to handle all images from full-sized ImageNet, this padding sets the size of the internal nvJPEG buffers without additional reallocations
        device_memory_padding = 211025920 if decode_device == 'mixed' else 0
        host_memory_padding = 140544512 if decode_device == 'mixed' else 0
        self.decode = ops.ImageDecoderRandomCrop(device=decode_device, output_type=types.RGB,
                                                 device_memory_padding=device_memory_padding,
                                                 host_memory_padding=host_memory_padding,
                                                 random_aspect_ratio=[0.8, 1.25],
                                                 random_area=[min_crop_size, 1.0],
                                                 num_attempts=100)

        # Resize as desired.  To match torchvision data loader, use triangular interpolation.
        self.res = ops.Resize(device=self.dali_device, resize_x=crop, resize_y=crop,
                              interp_type=types.INTERP_TRIANGULAR)

        self.coin = ops.CoinFlip(probability=0.5)
        print('DALI "{0}" variant'.format(self.dali_device))

    def define_graph(self):
        rng = self.coin()
        self.jpegs, self.labels = self.input(name="Reader")

        # Combined decode & random crop
        images = self.decode(self.jpegs)

        # Resize as desired
        images = self.res(images)

        if self.dali_device == "gpu":
            output = self.cmn(images, mirror=rng)
        else:
            # CPU backend uses torch to apply mean & std
            output = self.flip(images, horizontal=rng)

        self.labels = self.labels.gpu()
        return [output, self.labels]

DALI 管道现在在 CPU 上输出 8 位张量。我们需要使用 PyTorch 来完成 CPU-> GPU 传输、浮点数转换和规范化。这最后两个操作是在 GPU 上完成的,实际上,它们非常快,并且降低了 CPU -> GPU 内存带宽要求。我试图在转移到 GPU 之前锁定张量,但这样做并没有获得任何性能提升。用预取器把它放在一起:

def _preproc_worker(dali_iterator, cuda_stream, fp16, mean, std, output_queue, proc_next_input, done_event, pin_memory):
    """
    Worker function to parse DALI output & apply final preprocessing steps
    """

    while not done_event.is_set():
        # Wait until main thread signals to proc_next_input -- normally once it has taken the last processed input
        proc_next_input.wait()
        proc_next_input.clear()

        if done_event.is_set():
            print('Shutting down preproc thread')
            break

        try:
            data = next(dali_iterator)

            # Decode the data output
            input_orig = data[0]['data']
            target = data[0]['label'].squeeze().long()  # DALI should already output target on device

            # Copy to GPU and apply final processing in separate CUDA stream
            with torch.cuda.stream(cuda_stream):
                input = input_orig
                if pin_memory:
                    input = input.pin_memory()
                    del input_orig  # Save memory
                input = input.cuda(non_blocking=True)

                input = input.permute(0, 3, 1, 2)

                # Input tensor is kept as 8-bit integer for transfer to GPU, to save bandwidth
                if fp16:
                    input = input.half()
                else:
                    input = input.float()

                input = input.sub_(mean).div_(std)

            # Put the result on the queue
            output_queue.put((input, target))

        except StopIteration:
            print('Resetting DALI loader')
            dali_iterator.reset()
            output_queue.put(None)

class DaliIteratorCPU(DaliIterator):
    """
    Wrapper class to decode the DALI iterator output & provide iterator that functions in the same way as TorchVision.
    Note that permutation to channels first, converting from 8-bit integer to float & normalization are all performed on GPU

    pipelines (Pipeline): DALI pipelines
    size (int): Number of examples in set
    fp16 (bool): Use fp16 as output format, f32 otherwise
    mean (tuple): Image mean value for each channel
    std (tuple): Image standard deviation value for each channel
    pin_memory (bool): Transfer input tensor to pinned memory, before moving to GPU
    """
    def __init__(self, fp16=False, mean=(0., 0., 0.), std=(1., 1., 1.), pin_memory=True, **kwargs):
        super().__init__(**kwargs)
        print('Using DALI CPU iterator')
        self.stream = torch.cuda.Stream()

        self.fp16 = fp16
        self.mean = torch.tensor(mean).cuda().view(1, 3, 1, 1)
        self.std = torch.tensor(std).cuda().view(1, 3, 1, 1)
        self.pin_memory = pin_memory

        if self.fp16:
            self.mean = self.mean.half()
            self.std = self.std.half()

        self.proc_next_input = Event()
        self.done_event = Event()
        self.output_queue = queue.Queue(maxsize=5)
        self.preproc_thread = threading.Thread(
            target=_preproc_worker,
            kwargs={'dali_iterator': self._dali_iterator, 'cuda_stream': self.stream, 'fp16': self.fp16, 'mean': self.mean, 'std': self.std, 'proc_next_input': self.proc_next_input, 'done_event': self.done_event, 'output_queue': self.output_queue, 'pin_memory': self.pin_memory})
        self.preproc_thread.daemon = True
        self.preproc_thread.start()

        self.proc_next_input.set()

    def __next__(self):
        torch.cuda.current_stream().wait_stream(self.stream)
        data = self.output_queue.get()
        self.proc_next_input.set()
        if data is None:
            raise StopIteration
        return data

    def __del__(self):
        self.done_event.set()
        self.proc_next_input.set()
        torch.cuda.current_stream().wait_stream(self.stream)
        self.preproc_thread.join()

基于 GPU 的流水线

在我的测试中,上面详细介绍的新的完整 CPU 流水线大约是 TorchVision 的数据加载器的两倍,同时达到几乎相同的最大批量。CPU 管道对于像 ResNet50 这样的大型模型非常有用;然而,当使用 AlexNet 或 ResNet18 这样的小模型时,CPU 流水线仍然无法跟上 GPU。对于这些情况,示例 GPU 流水线工作得最好。问题是 GPU 管道将最大可能的批处理大小减少了近 50%,限制了吞吐量。

一种显著减少 GPU 内存使用的方法是让验证管道远离 GPU,直到一个时期结束时真正需要它。这很容易做到,因为我们已经重新导入了 DALI 库并在每个时期重新创建了数据加载器。

更多提示

使用 DALI 的更多提示:

*对于验证,平均划分数据集大小的批次大小效果最佳,例如,对于 50000 的验证集大小,500 而不是 512,这样可以避免在验证数据集结束时出现部分批次。

*与 Tensorflow 和 PyTorch 数据加载器类似,TorchVision 和 DALI 管道不会产生位相同的输出,您会看到验证精度略有不同。我发现这是由于不同的 JPEG 图像解码器。以前有一个调整大小的问题,但现在已经修复。另一方面,DALI 支持 TensorRT,允许将完全相同的预处理用于训练和推理。

*对于峰值吞吐量,请尝试将数据加载器工作线程的数量设置为虚拟 CPU 内核的数量。2 提供最佳性能(2 个虚拟内核= 1 个物理内核)

*如果您想要绝对最佳的性能,并且不在乎输出类似于 TorchVision,请尝试在调整 DALI 图像大小时关闭三角形插值

*不要忘记磁盘 IO。确保您有足够的内存来缓存数据集和/或真正快速的 SSD。DALI 最高可以从磁盘拉 400Mb/s!

把它放在一起

为了帮助轻松集成这些修改,我用这里描述的所有修改创建了一个数据加载器类,包括 DALI 和 TorchVision 后端。用法很简单。实例化数据加载器:

dataset = Dataset(data_dir, 
                  batch_size,
                  val_batch_size
                  workers,
                  use_dali,
                  dali_cpu,
                  fp16)

然后获取训练和验证数据加载器:

train_loader = dataset.get_train_loader()
val_loader = dataset.get_val_loader()

在每个训练时段结束时重置数据加载器:

dataset.reset()

或者,在模型验证之前,可以在 GPU 上重新创建验证管道:

dataset.prep_for_val()

基准

以下是我在 ResNet18 中能够使用的最大批量:

因此,通过应用这些修改,DALI 可以在 CPU 和 GPU 模式下使用的最大批处理大小增加了大约 50%!

以下是 Shufflenet V2 0.5 和批量 512 的吞吐量数据:

以下是使用 DALI GPU 管道训练 TorchVision 中包含的各种网络的一些结果:

所有测试都是在 Google Cloud V100 实例上运行的,该实例具有 12 个 vCPUs 个物理内核)、78GB RAM &使用 Apex FP16 培训。若要重现这些结果,请使用以下参数:
— fp16 —批量大小 512—workers 10—arch " shuffle net _ v2 _ x0 _ 5 或 resnet 18)—prof—use-Dali

所以,有了 DALI,单个特斯拉 V100 就可以达到将近 4000 图像/秒的速度!这只是英伟达超级昂贵的 8 V100 GPU DGX-1 的一半多一点(尽管使用的是小型号)。对我来说,能够在几个小时内在单个 GPU 上运行 ImageNet 培训是生产力游戏规则的改变者。希望对你也一样。感谢反馈!

本文给出的代码是这里的

承认

非常感谢 Patricia Thaine 对本文早期草稿的反馈。

封面图片由亚采克·阿布拉莫维奇拍摄

Nvidia 给了我一个价值 15000 美元的数据科学工作站——以下是我用它做的事情

原文:https://towardsdatascience.com/nvidia-gave-me-a-15k-data-science-workstation-heres-what-i-did-with-it-70cfb069fc35?source=collection_archive---------2-----------------------

视频教程

在几个小时而不是几个星期内,在数据科学 WhisperStation 上重建一个大规模的 Pubmed 文献搜索项目

在 YouTube 上观看并查看相关的 git 回购

当 NVIDIA 问我是否想试试最新的数据科学工作站时,我很兴奋。然而,一个发人深省的想法伴随着兴奋而来:我到底应该用它来做什么?

作为一名机器学习工程师,我做了很多深度学习,但我绝对不是谷歌大脑研究员。我可以运行基准测试,时间工作等…但我不在英伟达工作,老实说,这听起来不太有趣。

该死的 —基于 NVIDIA 的数据科学工作站

我不断推销自己的想法,并开始思考强大计算对数据科学家的真正价值。精心设计的 GPU 计算可以节省成本,降低服务延迟,简化大型模型的训练,但我最感兴趣的是快速迭代。

数据科学是一个以实验为基础的领域。对于大数据或大模型,如果没有大量资源,科学家尝试新配置或参数的次数是有限的。每个人都知道启动一个计算密集型进程的痛苦,只是在运行它的几个小时内被一个不可预见的错误弄得措手不及。然后你要改正,重新开始。

我回想起我的第一个数据科学项目:一个大规模、多语言的医学文献搜索引擎。如果我在 2020 年回到 2017 年,能够访问我现在拥有的计算和 GPU 库,我可能已经能够完成什么?我能以多快的速度完成它?

因此,我试图通过构建一个仅使用 GPU 资源的 Pubmed 搜索引擎来回答这个问题。

该项目

最初的项目来自中国的一个团队,那里的制药公司有责任向医疗保健从业者(hcp)提供非品牌医疗信息。该团队希望构建一个新颖的搜索工具,它需要:

  • 多语言(中文/中文)
  • 可通过多种渠道(网络/微信)获得
  • 可定制(能够调整算法以获得最佳结果)
  • 低延迟(快速搜索结果)
  • 大数据(所有的 Pubmed 摘要—这里我以过去 10 年为试点)
  • 准确(比 Pubmed 搜索结果更好)

我的工作是设计一个能够满足并支持所有这些需求的解决方案。此外,这个解决方案需要通过迭代相对快速地周转,以便我们能够基于来自主题专家(SME)的输入快速地测试、评估和更新系统。

然而,作为一名数据科学家,我有一个大问题…

数据

对于那些不知道的人来说,Pubmed 是一个包含超过 3000 万次引用的生物医学文献数据库。虽然不是所有的全文文章都是开源的,但是每个引用都有摘要。所有这些信息都可以通过 API 获得,或者以 XML 文件的形式从批量下载,不幸的是,对我来说,大约 300GB 分布在一千个文件中。

这张照片体现了“搜索”吗?

在解析每个 XML 以提取有用的字段(标题、摘要、出版年份等)之后,数据大小减少到接近 25GB。然而,这仍然不是超级本地可管理的。就像我之前说过的,数据科学是关于实验的——我需要做很多实验。作为一个有点新的数据科学家(和糟糕的工程师),我基本上只有一个资源:Python。没有 20 个节点的 Spark 或 Elasticsearch 集群来救我。

但是,如果我有一两个 GPU 呢?

工作站

我通过 Microway &获得访问权限的数据科学耳语站Nvidia 具有以下特性:

  • 双英特尔至强 10 核 CPU
  • 192GB 内存
  • 高速 1TB 暂存驱动器
  • 带 NVLink 的双 NVIDIA Quadro RTX 6000 GPU
  • 预装和配置 Python,Docker,RAPIDs 和我这个项目需要的所有机器学习库

我们真正关心的是最后两颗子弹。你可能知道,GPU 计算在数据科学中非常流行。使用 GPU 库运行工作流可以将代码速度提高几个数量级,这意味着每次实验运行只需几个小时,而不是几周。

此外,如果您曾经从零开始建立过数据科学环境,您会知道这真的很糟糕。安装和配置 Docker、RAPIDs、tensorflow、pytorch 和其他所有现成的软件节省了安装时间。

直到最近,GPU 主要用于数据科学中的深度学习。然而,不久前 Nvidia 发布了RAPIDS——一个针对 GPU 的通用数据科学库。急流由以下部分组成:

  • cudf (基本是熊猫)
  • cuml (基本上是 scikit-learn)
  • cugraph (基本是网络-X)

这些通用数据科学库为传统的 CPU 处理(数据加载、清理、特征工程、线性模型等)提供了大量的计算增强,为数据科学的全新前沿铺平了道路。

熊猫到急流城

在现代,简单的搜索是一个相当简单的过程。单词可以用数字向量来表示,然后计算这些向量之间的距离,就可以看出段落有多“相似”。最简单的方法是使用 TF-IDF 字向量的余弦相似度。

急流

然而,为了“矢量化”我们的文本,我们首先需要实际读入并预处理它。假设 XML → csv 预处理已经完成,现在我们只需要将它们作为数据帧读入并执行相关的预处理。

现在,我们有大约 23GB 的数据,只有两个 GPU。我并不幻想能够用 Python 将所有这些都放入 GPU 内存中。幸运的是,就像科学文献一样,只有最近的文章才是相关的。为了评估专家搜索的准确性,我真的只需要 Pubmed 最近 10 年的数据——根据我的数据集,大约有 800 万篇文章。

使用受 CPU 限制的进程会很费力,但是用 cuda 加速会有很大的不同。我想:

  1. 读入数据帧
  2. 清除“摘要”列中的字符串
  3. 仅保留≥ 2009 年的年份
  4. 重写为 csv

这就是 cudf 的用武之地。我真的写了熊猫代码,做了查找/替换,我还有 GPU 加速代码!

这比在本地处理数据帧要快得多。以下是使用 pandas 的本地输出示例:

Processed 13783 abstracts in 0.84604811668396 seconds
Processed 21714 abstracts in 1.2190630435943604 seconds
Processed 20259 abstracts in 1.1971170902252197 seconds

下面是使用 cudf 的工作站上的流程输出:

Processed 23818 abstracts in 0.3909769058227539 seconds
Processed 23609 abstracts in 0.5951714515686035 seconds
Processed 23929 abstracts in 0.3672349452972412 seconds

每个文件的处理速度提高了一倍以上,而代码只需要一个 GPU!更好的是,我们可以通过创建 cuda 集群和使用 dask 来使用两个 GPU 中的所有内存。

如果我只是想阅读所有的摘要,然后用它们做些别的事情,dask 用最少的代码行就能做到非常高效。

上面的代码在我的 Pubmed 数据子集上产生了以下输出(所有的 Pubmed 都会抛出一个内存错误——这并不奇怪)。

Read 7141779 abstract in 64.332682 seconds

使用watch -n 0.5 nvidia-smi在单独的窗口中检查 GPU 使用的输出,您可以观察您的进程运行并监控内存使用。

监控工作站上的 GPU 使用情况

GPU 加速余弦相似度

既然我现在知道我可以将过去十年的 Pubmed 数据加载到 GPU 内存中,我就可以进入有趣的部分了:实际的 TF-IDF 矢量化。在 scikit 中——了解这一点相当容易,请在这里查看我的完整 CPU 实现。使用 cuml,我们应该能够像对熊猫那样找到并替换,但不幸的是…

失败:(

根据这期 Github的消息,在撰写本文时,cuml 的文本特征提取库仍在工作中(但一旦完成,我会用代码更新!).这意味着我们的矢量器仍然需要用 scikit-learn 来实现,我们还不能在这个 TF-IDF 任务上获得 GPU 加速。这只是针对训练步骤,但这意味着我们的 TF-IDF 矢量器将仍然受到 CPU 的限制,因此效率低下。

然而,这还没有结束。即使训练本身是低效的,那一步真的只需要发生一次。幸运的是,sklearn 的 TF-IDF 矢量器的输出只是一个稀疏矩阵——当我们回到处理矩阵时,我们可以从一些经典的张量库中获得帮助。我决定用 tensorflow。

正如所料,矩阵乘法是任何张量库的隐含部分。在 sklearn 中训练了我的矢量器之后,我可以用 tensorflow 将实际的矢量移植回 GPU 来执行矩阵乘法。

现在,从理论上讲,这对于 Pubmed 的一小部分非常有效——但是它没有伸缩性。在所有的 Pubmed(甚至我们的子集)中,有相当多的独特的单词。由于 2009 年以后 Pubmed 中的每一个引用都有一个向量,我们的稀疏矩阵变得庞大。我想大概是 800 万 T4 乘以 100 万 T5。

是的,大惊喜,凯尔,干得好,伙计

受到阻碍的不是硬件,而是软件。试图在 sklearn 和 tensorflow 之间来回切换导致了一系列问题。意识到这种方法需要更多的时间和技能,这是我继续前进或者成为一名更好的工程师的时候了。是时候转向深度学习表示了。

创建 GPU 加速的 BERT 索引

使用 BERT 向量化 Pubmed

NLP 中的变压器的最新进展已经在各种任务中显示出巨大的改进。虽然此后出现了许多模型,但这场革命的起源是谷歌的 BERT。像其他一些基于 DL 的模型一样,BERT 为句子生成一个上下文向量。维数(向量的长度)等于隐藏层的大小,在最新推荐的 BERT-large 模型中是 1024。

这是巨大的。即使我们不能再使用稀疏矩阵,我们向量的大小也从几百万 x 几百万→几百万 x 几千。在空间有限的 GPU 上,这一点非常重要。

通常 BERT 用于分类任务,但是在我们的例子中,我们只是想用它来提取 Pubmed 摘要的矢量化表示,这样它们就可以被索引和搜索。感谢腾讯研究院,我们已经有了一个设计良好且支持 GPU 的库: BERT as a service

您可以按照 repo 中的说明来实际安装该服务。一旦您的环境中有了它,您所要做的就是下载您喜欢的 BERT 模型并启动它。

下载模型并启动服务

现在您已经运行了服务,可以调用简单的 Python 来获取您想要 BERT 表示的任何文本的向量。

使用 bert-as-service 对文本进行矢量化

很简单。通过使用工作站上两个 GPU 的 BERT 服务,大量摘要以惊人的速度通过模型。下面是我为每个 csv 计时时的输出:

Vectorized 23727 abstracts in 53.800883 seconds
Vectorized 25402 abstracts in 56.999314 seconds
Vectorized 25402 abstracts in 57.235494 seconds
Vectorized 23575 abstracts in 50.786675 seconds
Vectorized 17773 abstracts in 33.936309 seconds
Vectorized 24190 abstracts in 53.914434 seconds

即使有了工作站,这个过程也需要一段时间——这让你知道没有它需要多长时间。同样值得注意的是,这次包括用 cudf 读入数据。为了说明 GPU 加速和本地计算之间的差距有多大,下面是使用我的个人笔记本电脑的相同过程:

Vectorized 13172 abstracts in 2048.069033 seconds

30 分钟。我花了将近 30 分钟在工作站上对< 60 秒处理的一半的摘要进行矢量化处理。即使只是从如此大的模型中获取向量,GPU 计算也让我在代码运行时不用整天摆弄手指。

使用 Faiss 索引

这一次,我将把它交给一个设计良好的快速索引库,而不是自己做矩阵乘法。脸书的 faiss 易于使用,GPU 能力使其成为索引伯特矢量的完美工具。要在 faiss 中创建一个基于 GPU 的平面,我们只需要大约 10 行代码。

一旦你有了索引,你要做的就是把向量放进去。为了节省 GPU 内存,我建议先单独使用 BERT 服务对文本进行矢量化,然后保存到磁盘。然后,您可以加载和索引向量,而不需要服务在后台运行。但是,如果您愿意,也可以一次性完成。

创建索引本身后,可以在一行中完成搜索。但是这个规模会大吗?如果我想使用这段代码来检索结果,或者甚至将一个模型投入生产,我想确保搜索尽可能快地运行。我对大约 300 万份摘要进行了基准搜索,搜索结果仍然花费了不到 0.1 秒。

即使是 250 万份摘要,在工作站上使用 faiss 的搜索查询时间仍然不到 10 毫秒

终于?健全检查。我一直在假设 SME 能够评估搜索的准确性的情况下进行搜索。然而,如果搜索结果如此糟糕,那就毫无意义了,我将不得不从头开始,或者彻底重构我的方法。幸运的是,情况并非如此。

>>> search_term = "parkinsons disease" # search parkinsons
>>> search_vector = bc.encode([search_term]) # encode term
>>> distances,indicies = index.search( # get top 3 results
    search_vector.astype('float32'), 
    k=3)
>>>for i in indicies[0]:
...    print(text[i][0:500], sep = "\n") # print first 500 charDeep brain stimulation (DBS) improves motor symptoms in Parkinson's disease (PD), but questions remain regarding neuropsychological decrements sometimes associated with this treatment, including rates of statistically and clinically meaningful change, and whether there are differences in outcome related to surgical target.Neuropsychological functioning was assessed in patients with Parkinson's disease (PD) at baseline and after 6 months in a prospective, randomised, controlled study comparingKennedy's disease (KD) is a progressive degenerative disorder affecting lower motor neurons. We investigated the correlation between disease severity and whole brain white matter microstructure, including upper motor neuron tracts, by using diffusion-tensor imaging (DTI) in eight patients with KD in whom disease severity was evaluated using the Amyotrophic Lateral Sclerosis Functional Rating Scale (ALSFRS).From DTI acquisitions we obtained maps of fractional anisotropy (FA), mean diffusivity (Autophagy is associated with the pathogenesis of Lewy body disease, including Parkinson's disease (PD) and dementia with Lewy bodies (DLB). It is known that several downstream autophagosomal proteins are incorporated into Lewy bodies (LBs). We performed immunostaining and Western blot analysis using a cellular model of PD and human brain samples to investigate the involvement of upstream autophagosomal proteins (ULK1, ULK2, Beclin1, VPS34 and AMBRA1), which initiate autophagy and form autophago

快速浏览显示,aa 上下文搜索“帕金森病”会返回该领域的相关摘要(以我外行的评价)。

因此,让我们回顾一下需求,看看这种方法是否解决了该项目的所有需求:

多语言(en/zh) ✅: BERT 支持 104 种语言!

多渠道(网络/微信)✅:用 API 包好,端上桌。

可定制(能够调整算法以获得最佳结果) ✅: 我使用的是 BERT base,但这里也可以使用 Bio-BERT 或任何其他微调过的 BERT。此外,我们可以在这些结果上叠加轻量级分类算法或启发式算法,以进一步提高准确性。

低延迟(快速搜索结果) ✅: 使用 Pubmed abstracts 的近 1/3,延迟仍为< 0.1 秒,看起来比例合理。

支持大数据(所有 Pubmed 摘要等) ✅: 我们只使用 2009 年的引文进行验证,但是有了更多的 GPU 和更好的工程师,你可以很容易地将其扩展到整个 Pubmed。

准确(比 Pubmed 更好的搜索结果)🤔:有待观察。中小企业必须用 Pubmed search 对搜索结果进行评级和比较,并随着时间的推移调整算法。然而,由于大约 700 万份摘要的短期周转,工作站使得这种周转相对较快的方法非常可行。此外,虽然健全性检查缺乏规模,但它至少表明这种方法可能值得探索。

结论

在充斥着杂乱无章的文档的大公司中,信息检索非常重要。检索这些文档的智能解决方案非常受欢迎。虽然许多供应商都提供了强大的企业级解决方案,但要在如此短的时间内组织如此大规模的信息,现在只有通过 2010 年代后期的硬件和软件进步才有可能。

在几周的空闲时间里,我创造、重复和修改了我解决这个问题的方法。多亏了工作站和开源的力量,我在那段时间里成功地完成了我的目标。我没有等待几个星期来运行代码,而是不断收到反馈,并尽早解决错误。结果,我的代码和这个个人项目以指数级的速度进步。

我太喜欢这个小家伙了,他们帮我解决了几个小时的头痛问题

因为我基本上已经在一个生产环境中工作,所以也很容易过渡到更多托管的云主机进行部署。虽然我的代码与生产代码相去甚远,但使用 Docker 使我能够确保我构建的所有东西都可以被预打包,并被发送到我喜欢的任何映像注册中心和部署方案。

显然,15000 美元对于某些硬件来说是一笔不小的数目。但是,如果你是一个寻求快速试验和周转的企业组织,这是有意义的。作为对比,这里有一个专用 AWS p3.8x large (4 特斯拉 V100s)的报价。一年 75,000 美元,以及自己安装所有库和工具的麻烦。

专用 GPU 资源的 AWS 定价

这个问题有不涉及 GPU 的解决方案。由于 elasticsearch 现在有了对向量评分的支持,您可以非常容易地在一个 20 节点的集群上部署相同的解决方案,比我在这里使用的大约 30 行代码多得多。

英伟达 DGX

然而,这里仅在两个 dgx 上实现的效率和规模应该显示了使用 GPU 的工作情况。通过高级 Python APIs 的可访问性现在使普通数据科学家能够以最小的努力执行高度优化的任务。感谢您的阅读,请务必改进这些解决方案!

不要脸塞:正在制作 我的 Twitter 游戏 并随时连接上LinkedIn

NVIDIA Jetson Nano vs Google Coral vs Intel NCS:比较

原文:https://towardsdatascience.com/nvidia-jetson-nano-vs-google-coral-vs-intel-ncs-a-comparison-9f950ee88f0d?source=collection_archive---------5-----------------------

用于计算机视觉和机器学习的边缘人工智能硬件加速器

Edge AI 硬件:谷歌珊瑚、英特尔 Movidius NCS、英伟达 Jetson Nano、树莓 Pi

在人工智能培训框架达到一定程度的成熟后,dge 人工智能已经获得了发展势头;Tensorflow,Pytorch,Caffe,Keras,OpenVINO 等。然而,从数据采集到模型部署和推理的完整工具链仍不清晰,因为这项工作仍处于研究阶段,发展非常迅速。然而,这并没有阻碍该领域一些令人兴奋的解决方案的开发。例子包括从计算机视觉的物体识别和从自然语言处理角度的语音识别

传统人工智能,机器学习方法

许多现有的人工智能解决方案都将云计算或存储作为架构的重要组成部分。由于隐私、延迟、可靠性和带宽方面的问题,这使得某些部门很难将该技术用于实际应用。虽然资源有限,但边缘计算可以在一定程度上缓解这些问题。争论的焦点不是边缘和云计算的相互排斥,而是边缘计算对云计算的补充。

边缘人工智能未来提案

Gartner 炒作周期 2019 年和 2018 年[ 1 ]显示的新兴技术趋势表明,边缘人工智能和边缘分析具有过高的预期。然而,由于该领域仍处于起步阶段,软件框架和硬件平台将随着时间的推移而发展,以经济高效的方式创造价值。

谁在竞争:英伟达、谷歌和英特尔

人工智能领域的三个主要参与者;英特尔、谷歌和英伟达通过提供小型硬件平台/加速器来支持边缘人工智能。虽然这三者各有优缺点,但这完全取决于应用程序、预算和技能组合的可用性。

在这篇博客中,我将提供三个 edge AI 硬件加速器的简要比较;英特尔 Movidius NCS 棒,谷歌 Coral 盘,英伟达 Jetson Nano。

测试设置

为了执行检测比较,考虑了相同的环境设置。测试对象包括一个人、一辆公共汽车和一辆汽车。确保相同的照明条件。讨论的最后给出了设置每个实验的入门教程的链接。在实验中,硬件组件包括 NVIDIA Jetson Nano 开发者套件、32GB Scandisk Ultra SDcard、微软 USB LifeCam 1080p HD(网络摄像头)、树莓 Pi 官方通用电源 2.5A、树莓 Pi 摄像头、谷歌 Coral USB 和英特尔 NCS。

图片由作者提供。测试设置

性能和资源利用率

使用 Linux 的top命令测量资源利用率。推理时间是在单个帧中检测到对象的时间,CPU 使用率表示协处理器的利用率。英特尔 NCS 的帧率较低,但第二代英特尔 NCS2 据称可提供高达 8 倍的性能[ 2 ]。检测结果代表检测的置信度得分。

图 01 描绘了 Nvidia Jetson Nano 的检测结果,图 02 代表 Google Coral,图 03 显示了来自 Intel NCS 的检测结果。可以看出,NVIDIA 和 Intel NCS 提供了更好的置信度得分,而 Google Coral 的置信度得分相对较低。原因之一是谷歌珊瑚使用的是红外摄像头,因此由于摄像头传感器的不匹配,检测性能并不完全科学。但是,这提供了一个指示,表明有多少对象用于估计处理负载、内存使用和推理时间计算。

图片由作者提供。图 01,Nvidia Jetson Nano 的检测结果

图片由作者提供。图 02,Google Coral 的检测结果

图片由作者提供。图 03,英特尔 Movidius NCS 的检测结果

费用

下表列出了硬件加速器以及所需组件的成本。值得一提的是,Nvidia Jetson Nano 是一个开发板,作为一个独立的设备工作。然而,Google Coral USB 和 Intel NCS 需要一台主机来处理数据流。主计算机可以是单板计算机,例如 Raspberry Pi 或任何其他具有 Windows 或 Linux 操作系统的 x86 计算机。下表中的费用是用树莓 Pi 3 B+计算的。

单板计算机的边缘人工智能设置。

成本是针对原型系统估算的,每个加速器提供商都有生产就绪的硬件。生产就绪型加速器的成本将取决于批量和第三方产品,因为这些模块需要集成到主机中。

生产就绪的硬件加速器:杰特森纳米谷歌珊瑚英特尔 NCS

你应该买什么

答案取决于最终目标。

  • 如果目标是最终产品,最好使用生产就绪的硬件加速器( Jetson nanoGoogle CoralIntel NCS ),它们具有更好的温度额定值。
  • 如果目标是开发概念验证(PoC),最好使用开发板(NVIDIA、Google coral)或 USB 接口加速器(Intel NCS、google Coral)。

对于 PoC,成本相对相同,并且完全取决于应用程序要求、选择三个选项中任何一个的技能的可用性。尽管如此,还是建议评估不同的模型,并评估加速器是否支持特定的模型。下一段将简要讨论每个硬件加速器的灵活性。

大部分

通用性可以从硬件和软件两个角度来理解。从硬件角度来看,灵活性可能是;在片上系统或主机中集成/利用特定加速器有多容易。这完全取决于应用程序和接口的可用性。
从软件角度来看,灵活性可以从特定加速器支持多少检测和分类模型的角度来定义。这里列出了三个加速器的模型动物园

  • 英特尔 NCS 模型动物园和应用[ 3
  • Nvidia Jetson Nano 型号[ 4
  • 谷歌珊瑚动物园[ 5

结论

从延迟角度来看,Nvidia Jetson Nano 的性能明显优于 google coral 的约 9 fps 和 Intel NCS 的约 4 fps,前者约为 25 fps。对于某些应用,考虑到成本差异,超过 4 fps 也可能是一个不错的性能指标。Nvidia Jetson Nano 是一款评估板,而英特尔 NCS 和谷歌 Coral 则是可以连接到现有硬件的附加设备。使用上述硬件可以快速开发 PoC。还值得一提的是,这三款产品都具有可生产的硬件加速器,具有更好的额定温度和性能模式,例如 google coral 具有动态频率缩放,并根据加速器的温度调整负载。
这些原型硬件加速器的成本相对较小,且在同一范围内,适用于不同的低成本应用。

入门教程

[## 入门:Nvidia Jetson Nano,对象检测和分类

边缘计算的未来

towardsdatascience.com](/getting-started-nvidia-jetson-nano-object-detection-and-classification-161ad566d594) [## 开始使用英特尔神经计算棒 2

按照下面的逐步说明来设置您的英特尔神经计算棒 2(英特尔 NCS 2)或原始…

software.intel.com](https://software.intel.com/content/www/us/en/develop/articles/get-started-with-neural-compute-stick.html) [## 开始使用 USB 加速器| Coral

Coral USB 加速器是一种 USB 设备,可为您的计算机提供 Edge TPU 作为协处理器。它会加速…

coral.ai](https://coral.ai/docs/accelerator/get-started/)

参考文献:

  1. https://www . Gartner . com/en/documents/3956015/hype-cycle-for-emerging-technologies-2019
  2. https://software . Intel . com/content/dam/develop/public/us/en/documents/NCS 2-product-brief . pdf
  3. https://github . com/m ovidius/ncappzoo/blob/master/apps/readme . MD
  4. https://github.com/NVIDIA-AI-IOT/tf_trt_models
  5. https://coral.ai/models/

相关文章

[## 在 Windows 上使用 GStreamer 和 QT 的 OpenCV

使用 OpenCV 的 GStreamer 管道的分步指南和实例

towardsdatascience.com](/opencv-with-gstreamer-and-qt-on-windows-6f0fdb075993)

NVIDIA NeMo —构建自定义语音识别模型

原文:https://towardsdatascience.com/nvidia-nemo-building-custom-speech-recognition-model-d614289f0277?source=collection_archive---------42-----------------------

https://www . pexels . com/photo/aluminum-audio-battery-broadcast-270288/

介绍

NVIDIA NeMo 是一个对话式人工智能工具包。该工具包是一个加速器,它帮助研究人员和从业人员对复杂的神经网络架构进行实验。语音处理(识别和合成)和自然语言处理是该平台的重要功能。因为它来自 NVIDIA,所以完全支持 GPU。该框架依赖 PyTorch 作为深度学习框架。

在本笔记本中,我们将尝试如何创建自动语音识别(ASR)。在本教程中,我们将使用 LibriSpeech 数据集。

设置

对于这个实验,以下软件:Ubuntu 16.04 Anaconda 4 . 7 . 11 NeMo—【https://github.com/NVIDIA/NeMo】T2 卡拉迪—https://github.com/kaldi-asr/kaldi按照软件自述文件中的说明运行代码。确保您安装的 PyTorch 支持 GPU。硬件规格至少需要 6g 的 GPU RAM。

数据

LibriSpeech 是一个开放域语音识别数据集。我们可以从这里下载数据http://www.openslr.org/12.对于本教程,我们使用的是 dev-clean 数据集—http://www.openslr.org/resources/12/dev-clean.tar.gz。为了在一个非常小的 GPU 占用空间中轻松进行培训,我们从文件夹“dev-clean/84/121123/84”和“dev-clean/84/121550/”中选择数据。

语音文件存储在。flac 格式,应该转换成。' wav '格式的 NeMo 工作。NeMo 培训需要一个“清单”文件。“清单”文件包含“”的路径。wav '(演讲录音),演讲持续时间,以及每个录音的抄本。

为了让生活变得简单,我们创建了一个实用程序来转换。flac' to '。“wav”和元数据文件。

from wavconvert import create_nemo_manifest

创建培训清单文件

flac_path = "/home/jaganadhg/AI_RND/nvidianemo/LibriSpeech/dev-clean/84/121550/"
meta_apth = "meta_train.json"

create_nemo_manifest(flac_path,
    meta_apth)flac_path = "/home/jaganadhg/AI_RND/nvidianemo/LibriSpeech/dev-clean/84/121123/"
meta_apth = "meta_val.json"

create_nemo_manifest(flac_path,
    meta_apth)

模型训练

让我们跳到建立一个模型。我们稍后将讨论 FFT、频谱和语言模型。创建一个实用程序脚本来抽象该过程。QuartzNet15x5 型号用作基础型号。语音识别结果用单词错误率(WER)来评估。实用程序脚本实现了一个 WER 计算器。

注意-相应地调整历元值以得到一个合适的模型。

from asrtrainer import (train_model,
        computer_wer)
from ruamel.yaml import YAMLconfig_path = 'quartznet_15x5.yaml'
train_manfest = "metadata.json"
val_manifest = "metadata_validation.json"

yaml = YAML(typ='safe')
with open(config_path) as f:
    model_params = yaml.load(f)

my_asr_model = train_model(model_params,
                            train_manfest,
                            val_manifest,
                            5,
                            False)

wer = computer_wer(model_params,
                    my_asr_model)

保存的模型可以保存到。nemo 的格式。

my_asr_model.save_to("tutorial.nemo")

后续步骤

在本教程中,我们创建了一个非常简单的模型,它的性能可能并不好。我们可以尝试构建一个更大的数据集,也许是整个 LibriSpeech dev-clean。时代的增加(我尝试了 1000 个时代,转录看起来不错!).

如果您有兴趣进一步了解,可以在“quartznet_13x5.yaml”文件中找到模型配置。

该代码可在 https://github.com/jaganadhg/nemoexamples 获得。

通过纽约市开放数据门户支付平价

原文:https://towardsdatascience.com/nyc-opendata-hackathon-pay-parity-4423ac691307?source=collection_archive---------27-----------------------

这个周末,我有幸参加了“像姐姐一样爱你”黑客马拉松,这是纽约开放数据周的一部分。与 DataKind 的 DataDeepDive 周末活动类似,我们得到了一个由不同专家组成的团队,一个特定的问题,以及大约 8 个小时来解决它。

虽然我们的 Github repo 和更具体的工作流将很快上传,但这篇文章将是对可用数据资源的简短探索,以解决我的团队面临的问题。

挑战:

纽约市性别平等委员会(CGE 纽约市)制定了消除性别薪酬差距的政策,包括企业在“平衡薪酬领域”的最佳做法为企业开发一个解决方案来理解和实现这些实践。

随着我们深入杂草,并咨询我们的主题专家,很明显纽约市 CGE 区面临的障碍与最新信息流有关,就像与雇主合规信息流有关一样。企业——特别是需要适应的基础架构较少的小型企业——没有提供关于其策略合规性的反馈,也没有在策略强化方面加倍努力。因此,我开始梳理纽约市的 OpenData 门户网站,试图找到可以作为政策合规性代理的数据集,为向雇主通报政策提供基础,或者为我们的挑战提供一些其他见解。

下面我提供了 4 个相关数据集的链接,以及它们的:

  • 描述(来自 OpenData 门户)
  • 可能的用途
  • 相关栏目
  • 主键(在可能与其他数据集合并时使用)

相关数据集:

合法经营的企业

描述:该数据集以持有 DCA(消费者事务部)执照的企业/个人为特征,因此他们可以在纽约市合法经营。

照片由迈克·彼得鲁奇Unsplash 上拍摄

用途:这个数据集可以为 CGE 想要联系的企业生成一个初始模式。通过提供关于预先存在的许可的基本信息,它可以用于减少雇主初始登录的负荷,提供更安全的登录协议以确保雇主连接到其验证的企业,或者为特定行政区的企业预先填充其他位置相关的政策信息。

相关栏目 : DCA 牌照号、牌照类型、牌照类别、企业名称、地址区

主键 : DCA 牌照号

WBE、LBE 和 EBE 认证企业列表

照片由阿里·叶海亚Unsplash 上拍摄

描述:该市的认证计划,包括少数族裔和妇女所有的商业企业(M/WBE)计划、新兴商业企业(EBE)计划和本地商业企业(LBE)计划,认证、促进和扶持该市少数族裔和妇女所有的企业以及符合条件的小型建筑和建筑相关企业的发展。该列表包含认证公司的详细信息,包括其工作历史的简要描述、联系信息以及公司销售的详细信息。

用途:该数据集将帮助 CGE 瞄准并为拥有这些认证类型的企业提供额外的支持/信息,或者为这些公司创建一个比上述 LOB 数据库中提供的更具体的方案。

相关栏目:成立日期、供应商正式名称、建设类型、项目、货物、材料、供应商

主键:供应商 _ 正式 _ 名称

市议会立法项目

照片由迈克尔Unsplash 上拍摄

说明:此清单载有由立法会提出及制定的立法项目的资料。

用途:这些项目可以通知相关立法项目的运行列表,以填充站点内的“资源”选项卡,以及连接到关于相关法律对企业的期望的外部文献。“标题”栏将需要清理和关键字的功能工程,以便有更多的功能,CGE 可能有一个更新的相关立法项目的数据库。

相关栏目:最终行动(日期/时间)、标题(包含法律本身的信息)

主键 : File_#

【2018 财年收到的问询

evUnsplash 上拍摄的照片

说明:该数据集包含上一财政年度公众成员向委员会提出的关于歧视事件和涉嫌违反《城市人权法》的[总]次数。

用途:虽然这个数据集有点稀疏,但它可以提供一个基础,为指称的基于性别的歧视侵权行为的频率建模,帮助收集这些侵权行为的模式,以防止它们在未来几年发生。

相关栏目:类别、就业、公共住宿、总计

主键:类别

未来数据集

虽然我们仍在使这个项目的 MVP 成为现实,但在未来,包含更广泛的信息可能是有用的。更全面的解决方案包括为雇主、雇员以及负责执法的政府机构提供一个平台。这些利益相关者的一些潜在数据源包括:

对于机构:

商业位置数据:这有助于为信息组织或执法机构创建一个地理信息系统地图。

商业解决方案:这种位置信息有助于确定市场拓展的目标,也有助于鼓励特定行政区更积极的雇主提供支持。

许可证申请:这将有助于从外部监控许可证申请流程。随着城市了解许可证申请的发展趋势,他们可以调整他们的执法或教育工作。

对于员工:

纽约市妇女资源网络数据库:这将是一个很好的资源,可以将员工与该市的组织联系起来,帮助他们了解并倡导自己的权利。

2014 年纽约市工作和家庭假期调查(WFLS):通过监测在职父母带薪家庭假期的可用性和可获得性的变化,员工可以了解劳动力中性别平等的关键问题,以及它如何随着新政策而变化。

Rebecca Rosen是 Flatiron 的数据科学 Immersive 的应届毕业生,具有认知科学和非营利管理的背景。她目前居住在纽约,在业余时间制作音乐。想看更多她的作品,或者打个招呼,搜索 Medium,Instagram 或者标签为@ rebeccahhrosen的脸书。

基于梯度推进算法的纽约出租车费用预测

原文:https://towardsdatascience.com/nyc-taxi-fare-prediction-with-gradient-boosting-algorithm-9ff7a1eded1e?source=collection_archive---------66-----------------------

基于决策树的预测模型构建方法

卢克·斯塔克波尔在 Unsplash 上拍摄的照片

纽约市的出租车展示了一幅清晰的城市生活画面。每个月,出租车机构收集的数百万数据使他们能够深入了解需求密度、出行模式和交通拥堵情况。通过利用这些每天积累的数据,出租车公司可以提供更好的定价,旨在为乘客提供具有竞争力的乘车费用。

在这个实验中,我们将实现一个梯度推进的学习算法来预测出租车费用。

梯度推进(GBM) 是一种学习技术,它将许多简单预测器的输出结合起来,构建一个强大的预测器,其性能优于基础学习器树。新树是先前树的增强版本,因此这种技术被称为 boosting,其中新树提高了原始版本的性能(Biau 等人,2019)。

作者插画的大树

GBM 算法可以如上图所示。GBM 使用由固定规模的多层决策树组成的基本学习器。已经强调了梯度增强具有几个优点。GBM 提供了训练模型的易用性,并提高了效率和有效性,如下所示:

  • 与其他模型相比,预测准确性更高
  • 提供优化各种损失函数的灵活性,并提供多种超参数调谐选项
  • 不需要预处理数据,因为 GBM 可以很好地处理数字和分类变量
  • 不需要处理丢失的数据

数据集

这项实验利用了纽约市出租车和豪华轿车委员会(TLC)的数据,特别是 2019 年 6 月的黄色出租车数据。点击查看数据集。数据集由包括上下客区、行程距离、上客时间、乘客数量、拥堵附加费等要素组成。这些变量将被用作独立变量。另一方面, fare_amount 变量将被用作目标变量,其定义为出租车费的总额。此外,出于模型开发和评估的目的,大约 1000 个观察值的随机子集将被分割成 8:2 的比例。

最后,RStudio 将用于执行模型开发的所有实验,均方根误差(RMSE)将用作评估指标。

梯度增强实现

GBM 提供各种调谐参数,非常灵活。然而,在寻找超参数的最佳组合时会出现挑战,因为它可能很费时控制。

毫无疑问,GBM 通过消除所有错误,过分强调离群值,并导致它们过度拟合来继续发展。因此,有必要进行交叉验证以推广该模型。第一步,用默认的【收缩】 为 0.00110 重交叉验证建立 GBM 模型。此外,GBM 使用默认的数量 interaction.depth 作为 1 来定义用于学习的树的级别。最后, n.trees 将被设置为 10000。

输出:

交叉验证估计

从上图可以看出,0.001 收缩率是一个非常小的学习率,通常需要大量的树才能达到最小 MSE。此外,许多树木也导致一个漫长的训练过程。

这个设置似乎不足以进行更好的预测。因此,需要通过网格搜索来调整几个参数。为了在不过度拟合的情况下找到具有较低 RMSE 速率的参数的正确拟合,执行网格搜索。在此步骤中,调整几个参数,包括:

  • 缩水:指 GBM 学习率
  • 树的深度(层次)增长
  • n.minobsinnode: 树终止时的观察次数
  • bag.fraction: 随机选择的训练集分数观察值比率,用于提出扩展中的下一棵树

以下是各参数的网格搜索设置。参数范围设置为适合数据集特征。在这种情况下,给定的数据仅仅是 1000 个观察值,非常小。

然后,网格搜索设置被适配到模型训练循环中,如下所示。

因此,以下是输出 RMSE 的 10 个最低比率的几个参数集。在这种情况下,第一行设置将用于拟合最终模型。

RMSE 税率最低的 10 个州的产量

以下是为最终模型设置的参数:

  • 收缩率: 0.10
  • 互动深度: 1
  • 微小牛肝菌
  • 袋.分数: 0.80

该配置将用于获得最佳模型。然后用 gbm ()函数将这些参数拟合到最终模型,以训练模型。

最终列车 RMSE 是 0.1148923,测试 RMSE 是 0.3030436,这表明它是一个好模型,其中列车 RMSE 和测试 RMSE 之间的差距相当小。

结论

在整个模型开发过程中,微调和优化程序在寻找最佳参数以建立更好的模型和降低错误率方面发挥着重要作用。在所有模型被训练之后,执行验证以在测试数据集上评估训练的模型是必要的任务。该验证过程验证模型是否按预期执行。不仅如此,这一过程还有助于已经训练和调整的模型的泛化能力。

讨论:随机森林和梯度推进的比较

在速度性能方面,以前的研究人员揭示了梯度推进学习技术比其他基于树的学习(如随机森林)执行得更快。在随机森林的训练过程中,该模型利用完全生长的树,通过投票的方式将所有的树结合起来进行预测。然而,梯度提升利用弱学习器的组合来做出更好的预测。

参考文献

  1. Biau,g,“干部”, b .和 Rouvière,l,“加速梯度推进”。《机器学习》(2019),第 108 卷,第 971–992 页。
  2. 纽约市出租车和豪华轿车委员会, TLC 旅行记录数据( 2020 ),【在线】
    可从以下网址获得:https://www1 . NYC . gov/site/TLC/about/TLC-Trip-Record-Data . page

服从试验山羊!在你有测试之前什么都不要做

原文:https://towardsdatascience.com/obey-the-testing-goat-do-nothing-until-you-have-a-test-5f17c714c0f9?source=collection_archive---------58-----------------------

图片作者。

测试驱动的开发周期是 Django 应用程序向生产环境迁移的重要部分。在这篇简介中学习 TDD 的基础知识。

我经历了惨痛的教训,比如数据库操作、登录或注册等功能部件在您没有注意到的情况下发生了故障。然而,你的用户会注意到。测试是的生产过程中至关重要的一部分,在这个故事中,我们将简要介绍如何测试您的 Django 应用程序。

这个故事包括:

  • 测试驱动的开发周期
  • 单元测试简介
  • 用 Django 的TestCase进行单元测试
  • 功能测试简介
  • 功能测试登录页面

测试驱动的开发周期

TDD 周期

首先我们编写测试;然后我们运行它,检查它是否如预期的那样失败。只有这样,我们才能继续开发我们的应用程序。

TDD 由单元测试组成,这是一种软件测试方法,通过这种方法,单个单元的源代码和功能测试功能测试使用 Selenium,让我们驱动一个真正的 web 浏览器,这样我们就可以从用户的角度与应用程序的功能进行交互!功能测试的其他术语有验收测试端到端测试、黑盒测试

一些有用的 TDD 概念是用户故事预期失败

  • 用户故事:应用程序如何为用户工作的描述。用于构建功能测试。
  • 预期失败:当一个测试以我们预期的方式失败。我们不打算明确地涵盖这一点,但是在传统的 TDD 周期中,你编写一个测试期望它失败,然后只重构它以便它不会失败。这样,您就知道当它失败时会发生什么,比如返回哪个错误消息,以及您是否希望对其进行更改以提供更多信息。

我们将在一个单独的文件test.py中编写单元测试,在一个单独的文件functional_tests.py中编写功能测试,我们将把它们放在我们的项目结构中,如下所示。

[projectname]/
├── [projectname]/
│   ├── __init__.py
│   ├── forms.py
│   ├── models.py
│   ├── settings.py
│   ├── templates/
│   │   ├── home_page.html
│   ├── **tests.py** │   ├── urls.py
│   ├── views.py
│   ├── wsgi.py
└── manage.py
└── **functional_tests.py**

然后,我们可以使用以下命令行命令运行我们的测试:

-- unit tests --
$ cd projectname
$ python3 manage.py test-- functional tests --
$ cd projectname/projectname
$ python3 functional_tests.py

单元测试简介

对于我们的第一个单元测试,我们将尝试解析home_page视图 URL,并检查它是否映射到正确的视图函数。我们应用程序的home_page的网址是'/'home_page()必须是我们的视图中的一个函数,在我们的urls.py中有一个这样的 URL 映射

url(r'^$', views.home_page, name='home_page')  # Windows
url('', views.home_page, name='home_page')  # Macintosh/Linux

现在我们希望在运行命令$ python3 manage.py test时能够正确解决这个问题,事实也确实如此!

单元测试

用 Django 的TestCase进行单元测试

对于我们的下一个单元测试,我们将尝试检查主页是否返回正确的 HTML 模板。

然而,我们在这里做的事情非常幼稚。我们通过检查 HTML 代码和文本来检查 HTML 模板的内容。然而,如果我们改变<title>文本会发生什么?我们的测试会失败,因为文本现在不同了。

一般来说,单元测试的一个规则就是 不要测试常量 ,测试 HTML 为文本很像测试常量。单元测试实际上是关于测试逻辑、流程控制和配置的。断言 HTML 字符串中的字符序列并不能做到这一点。

我们可以使用 Django 的内置TestCase工具assertTemplateUsed来检查我们的模板,而不用检查常量!Django 模板放在我们项目的templates文件夹中(参见项目结构),我们可以自动检查home_page的渲染模板。

另外,test_root_url_resolves_to_home_page_view(self)功能隐含在assertTemplateUsed功能中。重构我们的单元测试现在只需要两行代码!

功能测试简介

既然我们已经断言一些视图和功能的独立单元工作,我们将使用一个用户故事来构建一个使用 Selenium 的功能测试。

Selenium 是一个使用 Selenium WebDriver 编写功能/验收测试的简单 API。它所做的是打开一个网络浏览器并阅读其内容来测试模拟用户体验。Selenium 的其他用例是 web 抓取动态网站。

使用 Selenium,您可以访问用于形成网页的源代码,并找到您想要访问的元素。这使我们能够自动填写数据库操作、登录用户或注册的表单。

为了在本地运行功能测试,我们需要两个终端。一个是用$ python3 manage.py runserver运行应用,一个是用$ python3 functional_tests.py运行应用。

在下面的功能测试中,我们模拟了一个用户体验:用户将如何看到主页并声明它的信息。用户故事在评论中有详细描述。

setUp()tearDown()是打开网络驱动程序,然后关闭的功能。我们使用的是 Chrome webdriver,但是 Firefox 也可以使用,一旦安装,就可以在虚拟 Python 环境的 bin 路径中访问。

功能测试登录页面

登录页面的功能测试

正如你所看到的,这是一个非常简单的例子,用户检查了title文本和header文本。但是我们也可以使用 Selenium 来自动化表单提交。对于我们的下一个用户故事,我们将检查登录页面,看看它是否如我们预期的那样工作。

我们使用Keys在登录表单中输入用户名和密码。由于该应用程序已经用 Google 的 RECAPTCHA 保护了表单提交,我们无法登录,但确实收到了一条错误消息,我们可以对其进行测试。

注意在我们的功能测试中,我们测试常量,比如标题文本,或者错误消息文本,更好的做法是包含一个元素属性,比如id="recaptcha_error"并验证它。

这个故事的灵感来自《用 Python 进行测试驱动的开发》一书。如果你想通过 Django 和 Selenium 了解更多关于 TDD 的信息,请查看!相信我,这只是冰山一角:还有很多东西要学。

用 Python 进行测试驱动开发

基于对象的 Python 土地覆盖分类

原文:https://towardsdatascience.com/object-based-land-cover-classification-with-python-cbe54e9c9e24?source=collection_archive---------22-----------------------

eCognition 和 ERDAS Imagine 的免费开源替代品

国家农业图像项目(NAIP)的航空图像

航空图像以不同的空间和时间分辨率覆盖全球。从航空图像中及时提取信息需要自动分析,以训练计算机识别人眼立即识别的内容。基于对象的图像分析(OBIA)通过实施图像分割算法将像素组组合成对象(片段)来减少图像中的信息量,从而提高处理效率。本文描述了如何使用开源 Python 包来执行航空影像的影像分割和土地覆盖分类。具体来说,我将演示基于地理对象的影像分析(GeOBIA)过程,通过 5 个步骤执行监督土地覆盖分类。

  1. 图像分割
  2. 量化分段光谱特性
  3. 真实数据
  4. 土地覆盖分类
  5. 精度评估

1.图象分割法

上图是美国农业部(USDA)在国家农业图像计划(NAIP)下收集的航拍照片的一部分。水平图像分辨率为 1 米。我们的第一个任务是将相似的像素分组为片段。分割有效地减少了图像中需要分类的元素的数量。这可能会将 1 百万像素的图像减少到 50,000 个片段,这更易于管理。

有许多分割算法可供使用。本文中我们就不详细赘述了。我将向您展示两种不同算法的结果,以及如何使用skimage在 Python 中实现它们。

下面的代码演示了使用 SLIC(简单线性迭代聚类)和 quickshift 算法的分段(分别是第 23 行和第 24 行)。首先,来自 NAIP 图像的 4 个波段(红、蓝、绿、近红外)中的每一个都被读取为带有gdalnumpy阵列。波段数据被重新调整为亮度值(范围从 0 到 1)。然后创建段。用gdal将线段保存到新的光栅。

下图演示了分割算法和参数如何影响图像片段的大小和形状。第一幅图像中的片段(快速移位)不能很好地捕捉图像中的特征。您会看到路段与道路、田地和森林区域重叠。在第二幅图像中,来自 SLIC 算法的片段沿着图像特征的边界做得更好。本文的其余部分使用 SLIC 结果。图像中的特征可能由不同的算法或不同的算法参数来最好地表示。在继续分类之前,请务必评估您的细分市场。

快速移位分段(作者提供照片)

SLIC 分段(作者提供照片)

2.图像片段的光谱特性

一旦图像被分割,每个部分的光谱特性必须被定量描述。给定一定数量的像素,下面的函数计算每个波段的描述性统计数据(例如,平均值、最大值、最小值、方差)。随机森林算法将使用这些值来将这些部分分类为土地覆盖类型。

现在,我们遍历每个片段,将每个片段的像素发送到segment_features函数,并将结果保存在一个列表中。这段代码可能会成为处理时间的瓶颈。它可以通过并行化来改进,但这里不讨论。

3.真实(训练和测试)数据

这是一个监督分类工作流,因此您需要一些真实数据来描述分类中表示的土地覆盖类型。我在 QGIS 中快速生成了下面的点来表示七种不同的土地覆盖类别。这些数据只是一个例子。理想情况下,您应该以一种更有组织和统计上更严格的方式收集数据。

描述土地覆被类型的真相(作者照片)

土地覆盖真实数据需要分成训练数据集和测试数据集。训练数据集将训练随机森林分类算法。我们将把分类结果与测试数据集进行比较,以评估分类的准确性。

我的土地覆盖数据是 shapefile 格式的。以下代码使用geopandas将真实数据作为地理数据框架读取。随机地,70%的真实观察值被分配给训练数据集,剩余的 30%被分配给测试数据集。训练和测试数据集分别保存到新的 shapefile 中。在此过程中,我还使用了一个我创建的查找表,为每个土地覆盖类别命名(第 8-11 行)。这不是必需的,但是可以更容易地看出每个类代表什么。

现在,将训练数据转换为栅格格式,以便每个观测点都可以与一个图像片段相关联。

将每个训练观察与相应的图像片段相关联。第 13–19 行确保每个训练观察只与一个片段相关联。由于区段包含多个像素,因此区段可能代表多种土地覆被类型。这就是为什么正确调整分段算法很重要。

4.土地覆盖分类

这是分析的核心。分类算法。首先,识别并标记培训对象(第 1-20 行)。这一过程包括将一个标签(土地覆盖类型)与描述图像段内每个光谱带的统计数据相关联。

现在,一切都设置好了,可以训练一个分类器,并使用它来预测图像中的所有片段。这里我使用随机森林,一种流行的分类算法。训练(适应)算法和进行预测的代码非常简单(第 22–24 行)。只需将训练对象(包含光谱属性)和相关的土地覆盖标签传递给分类器。一旦训练(拟合)了分类器,就可以基于它们的光谱特性对非训练片段进行预测。做出预测后,将其保存到栅格中,以便在 GIS 中显示(第 26–43 行)。

最终土地覆盖分类(作者提供照片)

5.用混淆矩阵进行精度评估

准确性评估是任何分类的一个重要方面。如果你的分类不能代表它应该代表的东西,它就没什么价值。因为本文的重点是描述 GeOBIA 工作流,所以我不展示我自己的准确性结果。相反,我将展示如何为准确性评估生成一个基本的混淆矩阵。

加载之前创建的测试数据集,并将其转换为栅格格式,以便与生成的预测兼容。然后简单地从测试数据存在的位置查询预测值。最后,从相应的值生成混淆矩阵。

注意:我们对片段进行了分类,但是这种精度评估比较的是像素。我们将每个测试片段中的所有像素与相应预测片段中的所有像素进行比较。如果某些土地覆被类别比其他类别更经常出现在较小(或较大)的部分,这可能会导致一些偏差。同样,如果您已经对图像分割进行了尽职调查,这应该不成问题。

结论

在 Python 中将图像模块与地理空间模块结合起来为 GeOBIA 创造了令人兴奋的机会。数据操作(将光栅转换为矢量,再转换为数组等。)对于这个应用程序来说是相当繁重和乏味的,但这就是为什么它被称为数据科学。

具有小训练数据集的对象分类

原文:https://towardsdatascience.com/object-classification-with-small-training-datasets-c6bd1e90dfc8?source=collection_archive---------16-----------------------

实践教程

Boris DunandUnsplash 上拍摄的照片

在一次机器学习实习期间,我的任务是为“空货架综合症”创建一个解决方案。在某些情况下,空货架综合症是零售业中的一个常见问题,在这种情况下,零售商仅仅因为没有意识到货架已经空了而无法用他们库存的物品补充货架。这导致消费者认为该商品不可用,从而导致零售商失去销售机会。

最初,对象检测模型似乎是解决当前问题的理想方案。然而,在最初的设计阶段,我遇到了相当多的警告,使得一个简单的对象检测方法不可行。

我必须注意的一些关键业务警告是:

  • 零售店中各种商品的数量
  • 缺乏每个单项的综合数据集

该解决方案是对象检测的流水线和图像分类模型,用于最初检测项目的宽泛分类,然后进一步识别准确的类别标签。

管道:

  1. 捕捉图像:使用 OpenCV 构建的简单模块用于以 2 分钟的间隔捕捉货架的图像。为 POC 选择 2 分钟的时间间隔主要是为了提供充足的提醒时间,同时考虑到所需物品的重新进货。
  2. 对象检测:捕获的图像通过对象检测模型运行。该模型确定了图像中存在的项目的大致分类。在当前的用例中,广泛的分类包括瓶子、盒子、包、书等。
  3. 图像裁剪:一旦对象检测模型已经识别了对象的宽泛分类,每个对象被从左上到右下单独裁剪,并存储在对应于其宽泛分类标签的文件夹中。例如,图像中的所有瓶子将保存在名为“瓶子”的文件夹中。
  4. 图像分类:文件夹中的所有图像被分组,然后通过相应的图像分类模型运行(为每个宽泛的分类标签开发了一个单独的模型)
  5. 对象计数:分类模型的结果用于计数,图像的顺序用于映射货架上的物品位置。
  6. 仪表板:项目的数量显示在仪表板上,并对任何位置不当的项目发出警告。

物体检测

对于对象检测模型,我利用了 Tensorflow 对象检测 API(https://github . com/tensor flow/models/tree/master/research/Object _ Detection)。来自 COCO 数据集的预训练权重被用于在基本分类标签上训练模型。

一旦模型检测到相关的对象,OpenCV 就被用来裁剪图像中的边界框。这些图像随后被存储在相关的文件夹中。

该模型是使用 Tensorflow 对象检测 API 创建的。将更快的 RCNN 初始 resnet 权重用作初始权重,然后在 COCO 数据集上进一步训练该模型,该数据集具有广泛分类类所需的标签。

MODEL_NAME = 'object_detection/Models/faster_rcnn_inception_resnet_v2_atrous_oid_v4_2018_12_12'
PATH_TO_FROZEN_GRAPH = MODEL_NAME + '/frozen_inference_graph.pb'

MODEL_NAME 在这里指定要下载的模型,而 PATH_TO_FROZEN_GRAPH 是模型将实际用来执行对象检测的冻结图。

有关 Tensorflow 对象检测 API 使用的全面教程,请参考以下链接。

[## 安装- TensorFlow 2 对象检测 API 教程文档

虽然安装和使用 TensorFlow 并不一定要有 Anaconda,但我建议这样做,因为它…

tensor flow-object-detection-API-tutorial . readthedocs . io](https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/install.html)

图像裁剪

基于边界框裁剪图像是下一个关键步骤。

在上面的要点中,output _ dict[' detection _ Scores ']包含了模型创建的每个包围盒的分数。出于 POC 的目的,并且为了考虑部分可见的项目,阈值被设置为 50%(即,模型超过 50%确信所创建的边界框已经检测到相关项目)。50%可能看起来是一个相当低的数字,但它允许在不适当的位置考虑更广泛的项目。

然后存储每个边界框的 4 个端点,并用于确定图像的位置和要裁剪的原始图像的区域,并随后输入图像分类模型。

图像分类

对于图像分类模型,只有稀疏训练集是可用的。用户拍摄物品的图像(大约 5-10 张图像),然后进行复制和转换。这些图像随后被用来以很高的精确度训练模型。在创建这个概念验证时(2019 年 5 月),我使用了 ImageAI 库(https://github.com/OlafenwaMoses/ImageAI)作为图像分类模型。

一旦模型被分类到广泛的分类标签中,它们都被存储在“裁剪图像”目录下的单独文件夹中。然后,该模型将依次考虑目录中出现的文件夹,并为每个文件夹创建一个预测列表。

例如,让我们考虑标签瓶。

duck 将包含瓶子文件夹中所有图像的列表,然后对图像进行排序。(图像正在排序,因为在裁剪过程中,图像的命名顺序与它们在原始图像中出现的顺序相同)。这些图像被分组,然后进行分类。每个分类的预测和概率随后被存储,并且列表 img 被所有预测的标签填充。

输入图像(作者提供的图像)

带有边框的图像(作者提供的图像)

结果

带有项目计数和位置提醒的仪表板(图片由作者提供)

仪表板根据项目的广义分类标签显示项目的数量。如果发现任何放错地方的物品,就会发出警报。

未来范围

这个项目是我在计算机视觉领域起步时创建的一个有趣的概念验证。将对该项目的进一步改进,以充实功能和优化管道。当处理小数据集时,一种简单而有效的方法来处理对象检测。

Github 链接:https://github . com/abhinav 2301/Object _ Detection-Empty-Shelf-Issue

通过 Tensorflow 1.x 进行物体检测

原文:https://towardsdatascience.com/object-detection-by-tensorflow-1-x-5a8cb72c1c4b?source=collection_archive---------18-----------------------

自动驾驶汽车的交通灯检测——如何应用 Tensorflow 对象检测 API 的分步指南

计算机视觉是增长最快的领域之一,基于深度学习的方法现在被广泛应用于解决现实世界的问题,如人脸识别、癌症检测等。

其中最有效的工具是 Tensorflow 对象检测 API 并使用它们预先训练好的模型,取代最后一层针对特定问题试图解决和微调的模型。

现在 Tensorflow 2.x 采用了 API。但是,运行时环境有时不允许使用最新版本,仍然需要使用 Tensorflow 1.x。这篇博客文章演示了如何在这种情况下使用 API。如果你能使用 Tensorflow 2.x 进行推理,最好使用它——参见另一篇解释如何使用的帖子。

作者图片

在这里,我以自动驾驶汽车的交通灯检测为例,由于依赖性,即使在汽车上的小型计算资源上,也必须以高频率(~10fps)检测红色、黄色或绿色交通灯。

请注意,这篇文章只描述了机器学习方法的对象检测。实际的自动驾驶汽车使用激光雷达、雷达、GPS 和地图,并应用各种滤波器进行定位、对象检测、轨迹规划等,然后应用致动器来加速、减速或转弯,这超出了本文的范围。

在训练数据方面,kitti(【http://www.cvlibs.net/datasets/kitti/index.php】)为自动驾驶汽车提供了全面的数据集。

下面用 Google Colab。如果您在当地环境下训练,请参考报告中的自述文件。

第 1 部分:在本地 PC 上准备

1。克隆项目 回购 或创建新项目

如果您创建了新的 repo,请创建以下目录

创建新的 repo 时,复制脚本目录中的所有脚本。

2。选择要使用的预训练模型

到 github 中的 Tensorflow 1 检测模型 Zoo 下载适合该用途的。由 coco 数据集训练的模型在大多数情况下工作良好。速度和精度(地图)是权衡的。我选择 SSD Mobilenet v2 是为了获得更快的推理速度,但人们可以选择更大的模型和更好的精度,如更快的 RCNN Resnet101,它大约是模型大小的 100 倍,比我的机器慢 10 倍,但具有很高的精度。

一旦决定了模型,解压并复制 pipeline.config。或者,您可以从 tensorflow 模型报告中复制示例管道配置。

3。准备培训数据

正如监督学习的情况一样,您需要花费几个小时来手动标记输入数据。将训练图像保存在 images 目录下,我在模拟器中提供了交通灯检测图像,并在我的报告中使用 Pascal VOC 进行了标记。有许多可用的工具,labelImg 是最简单的盒型经典工具之一。确保你有 python 3 并简单地从 PyPI 安装,或者参考安装指南

将 xml 文件保存在同一目录中。好消息是,不需要准备成千上万的标签,因为这是一个迁移学习,每个类别 100 个标签将产生良好的微调结果。

4。创建标签图

这只是一个标签列表。名称应该与上一步中的注释标签相匹配。将文件另存为 annotations/label_map.pbtxt

训练集准备的下一步是将图像分离为训练集和测试集,然后生成。每个 xml 文件的 TFRecord。这可以在本地完成,但是我在 Colab 上包含了这个步骤,这样任何附加的标签都不会在 TFRecord 中丢失。

5。编辑 pipeline.config

有些更改是强制性的,有些是可选的,但更适合培训数据。

将回购推给 github—一切就绪!

第 2 部分:Google Colab

接下来,转到 Google Colab,创建一个新的笔记本。红绿灯检测-tf1.ipynb 是我 repo 里的一个样本。

1。安装 Tensorflow 1.14 和所需的库

2。设置变量

3。克隆 Tensorflow 模型回购

将 tensorflow 模型 repo 下载到 Colab env,编译协议缓冲区,设置 PYTHONPATH,安装 COCO API 进行评估。

4。下载预先训练好的模型

将预先训练的模型下载到 Colab 环境中。

5。克隆项目回购

确保本地更改在 master 分支中提交,并提前推送到 github。

6。过程输入图像(训练数据集)

  1. 首先,将图像和标签分割成训练集和测试集
  2. 接下来,将 xml 文件转换成 csv 文件
  3. 然后,将 csv 转换为 TFRecord

7。设置张量板

启动 tensorboard 监控训练进度非常有用。要访问 tensorboard 进程,请在此处使用 ngrok 隧道。

8。火车!最后:)

这需要一段时间,取决于型号和参数,可能需要几分钟到几小时甚至更长时间。喝两杯茶,甚至吃顿饭,洗个澡,看看电视,然后睡觉…

在 TF1 中,评估在 pipeline.config 中指定的训练期间在检查点运行。如果损失没有减少,准确性/召回率没有提高或学习曲线没有达到预期,则检查 Tensorboard 上的进度并调整 pipeline.config 中的参数很好。目标总损失低于 2。

在每个评估步骤中,它也提供了地面真实和图像检测之间的良好比较。

9。输出输出

不要忘记导出并下载训练好的模型,它将用于推理。

下载后,将文件解压缩到 exported_models/[model name]目录。

10。预测!(可选)

Tensorboard 已经提供了预测图像,所以这里只是演示如何使用训练好的模型进行推理并绘制图像。

以下是一些示例输出。

第 3 部分:将训练好的模型转换为 tensoflow 运行时的旧版本(可选)

如果您的推理运行时受到 tensorflow 版本的限制,导出的模型可能会出现错误,因为引用了旧版本中不存在的参数。这可以通过在匹配运行时版本的环境中转换导出的模型来避免。

这里,我的运行时是 tensorflow v1.3。最老的可用对象检测 API 是在 v1.4 上,但幸运的是,它似乎与 v1.3 兼容,所以使用这个版本。

1。创建一个 env 并安装库

我使用康达,但你可以使用任何一个虚拟环境管理工具。

2。克隆 tensorflow 模型回购,复制兼容版本

3。下载协议并编译协议缓冲区

兼容的协议版本是 v3.4.0,可以从这里下载。下载后,编译协议缓冲区。

4。转换型号

如果您启动一个新的控制台,请确保设置 PYTHONPATH,它也可以被保存以在每次切换虚拟环境时自动运行——例如,对于 conda,请参考保存环境变量

这篇文章解释了如何使用 Tensorflow 对象检测 API 进行训练,以及如何使用旧版本的 Tensorflow 1.x 对微调后的模型进行推理,如果你没有这样的限制,请参见另一篇文章,其中解释了如何使用最新的 Tensorflow 2.x 对象检测 API 。样本代码和图片可以在我的 github repo 中找到。

通过 Tensorflow 2.x 进行物体检测

原文:https://towardsdatascience.com/object-detection-by-tensorflow-2-x-e1199558abc?source=collection_archive---------10-----------------------

自动驾驶汽车的交通灯检测—如何应用 Tensorflow 对象检测 API 的分步指南

计算机视觉是增长最快的领域之一,基于深度学习的方法现在被广泛应用于解决现实世界的问题,如人脸识别、癌症检测等。

其中最有效的工具是 Tensorflow 对象检测 API 并使用它们预先训练好的模型,取代最后一层针对特定问题试图解决和微调的模型。

现在,API 支持 Tensorflow 2.x。有很好的理由使用 TF2 而不是 TF1——例如,渴望执行,它在 TF1.5 中引入以使编码更简单和调试更容易,并且新的艺术(SOTA)模型如 CenterNetExtremeNetEfficientDet 可用。撰写本文时的最新版本是 Tensorflow 2.3。

这个 API 是向后兼容的,但是如果你的运行时不能升级,使用 TF1 会让你的生活更容易。这里是 TF1 版的分步指南。

作者提供的自动驾驶汽车图片

在这里,我以自动驾驶汽车的交通灯检测为例,由于依赖性,即使在汽车上的小型计算资源上,也必须以高频率(~10fps)检测红色、黄色或绿色交通灯。

请注意,这篇文章只描述了机器学习方法的对象检测。实际的自动驾驶汽车使用激光雷达、雷达、GPS 和地图,并应用各种滤波器进行定位、对象检测、轨迹规划等,然后应用致动器来加速、减速或转弯,这超出了本文的范围。

使用的预训练模型是 Centernet Resnet50,它通过级联角池和中心池架构实现了极高的效率和相当好的准确性,使用 Resnet50 作为主干网络,适合此使用案例。

Centernet Resnet50 架构的高级图像,基于 Centernet paper:https://arxiv.org/abs/1904.08189和 Resnet paper:https://arxiv.org/abs/1512.03385

在训练数据方面,kitti(http://www.cvlibs.net/datasets/kitti/index.php)为自动驾驶汽车提供了全面的数据集。

下面用 Google Colab。如果你在当地环境下训练,请参考报告中的自述。

第 1 部分:在本地 PC 上准备

1。克隆项目 回购 或创建新项目

如果您创建了新的 repo,请创建以下目录

创建新的 repo 时,复制脚本目录中的所有脚本

2。选择要使用的预训练模型

去 github 的 Tensorflow 2 检测模型动物园下载适合的。这里的所有模型都是在撰写本文时由 coco 数据集训练出来的,在大多数情况下效果很好。速度和精度(地图)是权衡的。我选择了 CenterNet Resnet50 V1 FPN 512x512,其速度为 27,mAP 为 31.2——事实上这比 TF1 中的 SSD Mobilenet v2 更快更准确,速度为 31,mAP 为 21,我在这里使用了!

如果环境允许更大的模型规模和更慢的推理时间,当然可以选择更复杂的模型。

模型确定后,解压缩并复制 pipeline.config。该配置用于他们的培训,需要稍后进行修改,因为我们使用它进行微调。或者,您可以从 tensorflow 模型报告中复制示例管道配置,因为在使用 Colab 环境时,您实际上不需要下载模型本身。

3。准备培训数据

正如监督学习的情况一样,您需要花费几个小时来手动标记输入数据。将训练图像保存在 images 目录下,我在模拟器中提供了交通灯检测图像,并在我的报告中使用 Pascal VOC 进行了标记。有许多可用的工具,labelImg 是最简单的盒型经典工具之一。确保你有 python 3 并简单地从 PyPI 安装它,或者参考安装指南

将 xml 文件保存在同一目录中。好消息是,不需要准备成千上万的标签,因为这是一个迁移学习,每个类别 100 个标签将产生良好的微调结果。

4。创建标签地图

这只是一个标签列表。名称应该与上一步中的注释标签相匹配。将文件另存为 annotations/label_map.pbtxt

训练集准备的下一步是将图像分离为训练集和测试集,然后生成。每个 xml 文件的 TFRecord。这可以在本地完成,但我包括在 Colab 的步骤中。

5。编辑 pipeline.config

有些更改是强制性的,有些是可选的,但更适合培训数据。

将更改推送到 github——一切就绪!

第 2 部分:Google Colab

接下来,转到 Google Colab,创建一个新的笔记本。红绿灯检测-tf2.ipynb 是我 repo 中的一个样本。

1。安装所需的库

2。设置变量

3。克隆张量流模型回购

克隆、编译协议缓冲区、设置 PTTHONPATH 并安装。

然后,安装 COCO API 进行评估

4。下载预训练模型

5。克隆项目回购

确保本地更改在 master 分支中提交,并提前推送到 github。

6。处理输入图像(训练数据集)

首先,将图像分为训练集和测试集。

然后,将 xml 文件转换为 csv 文件

最后,将 csv 文件转换为 TFRecord 格式

7。建立 Tensorboard

启动 tensorboard 监控训练进度非常有用。在 TF1 版本中,我们使用 ngrok 隧道,但现在有一个神奇的命令可以在笔记本中启动 tensorboard!

8。火车!最后:)

只需执行 model_main_tf2.py,注意 TF1 使用的 model_main.py 的参数略有不同。

这需要一段时间,取决于型号和参数,可能需要几分钟到几小时甚至更长时间。喝两杯茶,甚至吃顿饭,洗个澡,看看电视,然后睡觉…

9。评估(可选但必须)

在 TF1 中,它是在训练过程中完成的,但不知何故它被分开了。它在本地运行时很有用,但在 Colab 中没那么有用…无论如何,您可以在训练后通过指定 checkpoint_dir 来运行它,它运行评估模式。设置 eval_timeout 或在评估完成后终止进程,因为它会无限期等待输入。

如果损失没有减少,准确率/召回率没有提高,或者学习曲线没有达到预期,请调整 pipeline.config 中的参数。目标总损失低于 2。

在每个评估步骤中,它也提供了地面真实和图像检测之间的良好比较。

9。输出输出

不要忘记导出并下载训练好的模型,它将用于推理。这里再次使用 exporter_main_v2.py,而不是 TF1 中的 exporter_main.py。

成功导出后,将其存档并下载。

10。预测!(可选)

当然,训练模型的全部目的是使用训练好的模型进行推理。在这里,我使用测试图像进行演示,但这可以是任何新的图像,你想检测的对象。

首先配置图像路径:

然后,加载训练好的模型:

现在,对图像路径中的每个图像进行推理。

以下是一些示例输出。它可以在所有情况下以良好的置信度检测和分类交通灯,甚至具有更快的推理速度。

这篇文章解释了如何使用 Tensorflow 对象检测 API 2.x 进行训练,并在微调后的模型上执行推理。如果你用 Tensorflow 1.x,请看这篇帖子。样本代码和图片可以在我的 github repo 中找到。

使用探测器 2 分 6 步进行物体探测

原文:https://towardsdatascience.com/object-detection-in-6-steps-using-detectron2-705b92575578?source=collection_archive---------2-----------------------

让我们看看如何使用 FAIR(脸书人工智能研究所)的 Detectron 2 对涉及文本识别的自定义数据集进行实例检测。

使用 Canva 设计

你有没有尝试过使用自己选择的自定义数据集从头开始训练一个对象检测模型?

如果是的话,你就知道这个过程有多乏味了。如果我们选择基于区域建议的方法,如更快的 R-CNN,或者我们也可以使用一次性检测器算法,如 SSD 和 YOLO,我们需要从使用特征金字塔网络结合区域建议网络构建模型开始。

如果我们想从头开始实现它,这两种方法都有点复杂。我们需要一个框架,在这个框架中,我们可以轻松地使用最先进的模型,如 Fast、Faster 和 Mask R-CNN。然而,重要的是至少尝试一次从头构建模型,以理解其背后的数学原理。

如果我们想用自定义数据集快速训练一个对象检测模型,Detectron 2 就能帮上忙。Detectron 2 库的模型动物园中的所有模型都在 COCO 数据集上进行了预训练。我们只需要在预训练的模型上微调我们的自定义数据集。

Detectron 2 是对 2018 年发布的第一款 Detectron 的完全重写。前任是在 Caffe2 上写的,这是一个深度学习框架,也是由脸书支持的。Caffe2 和 Detectron 现在都被弃用了。Caffe2 现在是 PyTorch 的一部分,后继者 Detectron 2 完全写在 PyTorch 上。

Detectron2 旨在通过提供快速培训和解决公司从研究走向生产时面临的问题来推进机器学习。

这些是 Detectron 2 提供的各种类型的对象检测模型。

https://research.fb.com/wp-content/uploads/2019/12/4. -detectron2.pdf

让我们直接进入实例检测

实例检测是指对周围有边界框的对象进行分类和定位。在本文中,我们将使用 Detectron 2 的模型动物园中更快的 RCNN 模型来处理从图像中识别文本语言的问题。

请注意,我们将把我们的语言限制为 2。

我们标识了印度语文本和英语文本,并为其他语言添加了一个标记为其他的类。

Colab 的最终结果

我们将实现一个输出如下的模型。

我们开始吧!

使用 Detectron 2,可以使用七个步骤对任何自定义数据集执行对象检测。所有的步骤都在这个 Google Colab 笔记本中,你可以直接运行它!

使用 Google Colab 将是一项简单的任务,因为我们可以使用 GPU 进行更快的训练。

步骤 1:安装 Detectron 2

从安装一些依赖项开始,比如 Torch Vision 和 COCO API,然后检查 CUDA 是否可用。CUDA 帮助跟踪当前选择的 GPU 。然后安装 Detectron2。

# install dependencies: 
!pip install -U torch==1.5 torchvision==0.6 -f [https://download.pytorch.org/whl/cu101/torch_stable.html](https://download.pytorch.org/whl/cu101/torch_stable.html)
!pip install cython pyyaml==5.1
!pip install -U 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'import torch, torchvision
print(torch.__version__, torch.cuda.is_available())
!gcc --version# install detectron2:
!pip install detectron2==0.1.3 -f https://dl.fbaipublicfiles.com/detectron2/wheels/cu101/torch1.5/index.html

步骤 2:准备和注册数据集

导入一些必要的包。

在 detectron2 中有内置支持的数据集在内置数据集中列出。如果您想在重用 detectron2 的数据加载器的同时使用自定义数据集,您将需要注册您的数据集(即,告诉 detectron2 如何获取您的数据集)。

我们使用我们的文本检测数据集,它有三个类:

  1. 英语
  2. 印地语
  3. 其他人

我们将从现有的在 COCO 数据集上预训练的模型中训练一个文本检测模型,该数据集可在 detectron2 的模型动物园中获得。

如果您有兴趣了解从数据集的原始格式到 Detectron 2 接受的格式的转换,请查看这个 Colab 笔记本

数据输入模型的方式有一定的格式,如 YOLO 格式、PASCAL VOC 格式、COCO 格式等。Detectron2 接受数据集的 COCO 格式。数据集的 COCO 格式由 JSON 文件组成,该文件包括图像的所有细节,例如大小、注释(即,边界框坐标)、对应于其边界框的标签等。举个例子,

Detectron 2 的数据集格式

这是一张图片的 JSON 外观。边界框表示有不同类型的格式。它必须是结构的成员。探测器 2 的 BoxMode 。有 5 种这样的格式。但目前支持 BoxMode。XYXY_ABS,BoxMode。XYWH_ABS 。我们使用第二种格式。(X,Y)表示边界框的一个坐标,W,H 表示该框的宽度和高度。category_id 是指盒子所属的类别。

然后,我们需要注册我们的数据集。

为了验证数据加载是否正确,让我们可视化训练集中随机选择的样本的注释。

步骤 3:可视化训练集

我们将从数据集的 train 文件夹中随机选取 3 张图片,看看边界框是什么样子的。

输出是这样的,

Colab 的结果

步骤 4:训练模型

大步。在这一步,我们给出配置,并设置模型以准备接受训练。从技术上讲,我们只是在数据集上微调我们的模型,因为该模型已经在 COCO 数据集上进行了预训练。

在 Detectron2 的模型动物园中有大量模型可用于对象检测。在这里,我们使用 faster_rcnn_R_50_FPN_3x 模型,从这个角度来看,它是一个高水平的模型。

来源

将有一个主干网络(在这种情况下为 Resnet ),用于从图像中提取特征,然后是一个区域建议网络,用于提出区域建议,还有一个框头,用于收紧边界框。

你可以在我的上一篇文章中读到更多关于 R-CNN 如何更快工作的信息。

让我们为培训设置配置。

我不会说这是最好的配置。当然,其他配置的精度也可能会提高。毕竟,这取决于选择正确的超参数。

培训过程(来自 Colab 的结果)

注意,这里我们还计算了验证集上每 500 次迭代的精确度。

步骤 5:使用训练好的模型进行推理

是时候通过在验证集上测试模型来推断结果了。

成功完成存储最终权重的训练后,输出文件夹会保存在本地存储中。您可以保存此文件夹,以便将来根据此模型进行推理。

结果:

步骤 6:评估训练好的模型

通常,模型按照 COCO 评估标准进行评估。平均精度(mAP)用于评估模型的性能。这里有一篇文章精确地给出了地图上的一个概念。

评估指标(来自 Colab 的结果)

对于 0.5 的 IoU,我们可以获得大约 79.4%的准确率,这还不算太差。当然可以通过调整参数和增加迭代次数来增加。但是要密切关注广泛的训练,因为模型可能会超出训练集。

如果您需要从保存的模型中进行推断,请浏览本 Colab 笔记本

结论

在本文中,我强调了使用 detectron 2 使用自定义数据集进行异议检测的过程,而不是关注获得更高的准确性。

虽然这似乎是一个非常简单的过程,但在 Detectron 2 的库中还有很多东西需要探索。我们有大量的优化参数,可以进一步调整以获得更高的精度,这完全取决于一个人的自定义数据集。

希望你今天学到了新东西。

你可以从我的 Github 库下载笔记本,并尝试在 Google Colab 或 Jupyter 笔记本上运行。

你可以在我的上一篇文章中读到更多关于物体探测和传统 R-CNN 的内容。

如果你想联系我,请在 LinkedIn 上联系我。

基于 YoloV3 的报纸图像目标检测

原文:https://towardsdatascience.com/object-detection-on-newspaper-images-using-yolov3-85acfa563080?source=collection_archive---------16-----------------------

为更好的 OCR 制作自定义 YoloV3 模型

当我在报纸图像上尝试光学字符识别时,我意识到大多数文档都有章节,并且文本不一定跨越页面的整个水平空间。

即使宇宙魔方能够辨认出文本,它也是乱糟糟的。为了解决这个问题,该模型应该能够识别文档中的部分,并在其周围绘制一个边界框,并执行 OCR。就在这个时候,我想到了在这样的图像上应用 Yolo 物体检测。

YoloV3 简介

YOLOv3 速度极快,精度极高。在 mAP 中,测得 5 IOU YOLOv3 与焦点损耗相当,但速度快 4 倍左右。此外,你可以简单地通过改变模型的大小在速度和准确性之间进行权衡,不需要重新训练!

创建数据集

首先,我需要一个标记图像的数据集来训练 Yolo 模型,但没有可用的数据集,所以我决定自己制作一个。找到了一个用 Python 写的优秀工具,按照 Yolo 格式链接 给图片加标签。经过几个小时的鼠标点击、绘制边框和手工标记报纸图片,我最终得到了一个包含 4 个类的图片数据集

  • 头条新闻
  • 标志;徽标
  • 图像
  • 文本

我已经将数据集上传到 Kaggle 和 Github 上,供任何人进一步使用。(下面的链接)

数据集文件结构

.
├── custom.names
├── detector.data
├── images
│   ├── 001.jpg
│   ├── 002.jpg
│   ├── 003.jpeg
│   ├── 100.jpg 
|   .....
│   ├── 101.JPG
├── labels
│   ├── 001.txt
│   ├── 002.txt
│   ├── 101.txt
├── newspaper-yolo.cfg
├── test.txt
└── train.txt

培养

我们将使用的模型架构被称为 YOLOv3,或者你只看一次,由 Joseph Redmon 编写。这种特定的模型是一次性学习器,这意味着每幅图像只通过网络一次来进行预测,这使得该架构的性能非常高,在预测视频馈送时每秒可查看高达 60 帧。从根本上说,YOLO 把一幅图像分成几个子部分,并对每个子部分进行卷积,然后汇集起来进行预测。这里有一个关于 YOLO 的深度潜水推荐

现在,即使我们在自定义数据集上训练我们的模型,使用另一个已经训练好的模型的权重作为起点仍然是有利的。想象一下,我们想要尽可能快地爬上一座山,而不是完全从零开始创建我们自己的路径,我们将从假设别人的路径比我们随机尝试猜测曲折路径更快开始。

为了给我们的模型计算提供动力,我们将使用 Google Colab,它提供免费的 GPU 计算资源(在浏览器打开的情况下长达 24 小时)。

从克隆约瑟夫·雷德蒙的 Github 回购开始。这提供了动态训练对象检测模型所需的大部分工具。

git clone [https://github.com/pjreddie/darkne](https://github.com/pjreddie/darknet)t

编辑 yolo-v3.cfg 文件,根据您的要求进行配置

你需要在第一行输入你的班级号,train.txttest.txt路径在第二和第三行,object.names路径在第四行。

现在你需要编辑***.cfg**文件。默认情况下,每个 YOLO 层有 255 个输出:每个锚点 85 个输出[4 个框坐标+ 1 个对象置信度+ 80 个类别置信度],乘以 3 个锚点。

在我们的例子中,我们只使用了四个类,然后我们需要编辑过滤器。您可以将过滤器减少到filters=[4 + 1 + n] * 3,其中n是您的类计数。这种修改应该在三个 YOLO 层的每一层之前进行。此外,修改classes=80classes=n在每个 YOLO 层,其中n是你的类计数。

我更改了第 67 行中的批量和细分。然后是行号 610 (类=4)和 603 (过滤器=27),然后是行号 689 & 696 ,最后是行号776&783。如果您使用 tiny-yolo,行号会有所不同。

[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=4
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

将 num classes 更改为您想要检测的类的数量,我们就可以开始训练了。

# Start Training ./darknet detector train custom_data/detector.data custom_data/newspaper-yolo.cfg -dont_show

在数千行控制台输出和几个小时后…

结果

在图像增强的帮助下,经过 2 小时训练的 32 幅图像的小数据集能够产生 98%以上置信度的结果。考虑到报纸是非常复杂的文档,需要适应大量的内容,这个模型表现得非常好。类似的模型可以被训练用于各种任务,如验证 Id,验证物理表单,转换手写笔记等等!

如果你喜欢我做的,请随意鼓掌!(你可以顺便做 50 次)

源代码和数据集链接

[## imvab/news-yolo

报纸图像中的目标检测。在 GitHub 上创建一个帐户,为 imvab/news-yolo 的发展做出贡献。

github.com](https://github.com/imvab/news-yolo) [## 文档对象检测

用于文本图像上目标检测的标记图像。

www.kaggle.com](https://www.kaggle.com/immvab/document-object-detection)

在 LinkedIn 和 Github 上与我联系

[## vaibhav Birla-Techno India Salt Lake-Kolkata,西孟加拉邦,印度| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Vaibhav Birla 的个人资料。Vaibhav 的教育列在…

in.linkedin.com](https://in.linkedin.com/in/vaibhav-birla-960412b7) [## imvab -概述

在 GitHub 上注册你自己的个人资料,这是托管代码、管理项目和构建软件的最佳地方…

github.com](https://github.com/imvab)

基于模板匹配的 Python 对象检测

原文:https://towardsdatascience.com/object-detection-on-python-using-template-matching-ab4243a0ca62?source=collection_archive---------7-----------------------

了解如何在没有机器学习或任何框架的情况下在 Python 上进行对象检测

雅各布·欧文斯在 Unsplash 上的照片

每当我们听到“对象检测”时,我们脑海中就会浮现出机器学习以及不同的框架。但我们实际上可以在不使用机器学习或任何其他框架的情况下进行对象检测。在本文中,我将向您展示如何只用 Python 来实现这一点。

我们将从定义一个模板图像(对象)开始,系统将在源图像中找到与我们选择的模板匹配的所有其他对象。让我解释一下我给你们看一个例子的意思。下面有两张图片,左边是飞机的源图像,右边是飞机作为物体的模板照片。

左—源图像,右—模板图像

我要做的是写一个 python 代码来显示这个模板图像实际上适合我的源图像的所有区域。

首先,让我们从检测一个对象开始,其次,我们可以调整代码来检测多个对象。

检测一个对象—最精确的对象

为此,我们需要一个源图像和一个模板图像。模板图像在源图像上滑动(像 2D 卷积一样),程序将试图找到最准确的匹配。

开始编码吧。

import cv2
import numpy as np
from matplotlib import pyplot as pltimg_rgb = cv2.imread('SourceIMG.jpeg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('TemplateIMG.jpeg', 0)

在上面的部分代码中,我们使用 OpenCV 来读取我们的SourceIMG.jpegTemplateIMG.jpeg

height, width = template.shape[::]

当模板图像滑过源图像时,它会寻找整个区域。(左上角为参考帧)。在模板图像与源图像匹配后,我们要注意左上角的位置,然后在实际匹配的区域周围画一个方框。为了做到这一点,我们需要找到这个模板图像的高度和宽度。所以我们可以画矩形。

res = cv2.matchTemplate(img_gray, template, cv2.TM_SQDIFF)

模板匹配是 OpenCV 的一部分,它获取我们的灰度源图像和带有我们需要使用的统计指标的模板图像。在这种情况下,我使用的是最小方差 ( TM_SQDIFF),因为我们在寻找模板图像和源图像之间的最小差异。

plt.imshow(res, cmap='gray')

如果你画出我们到目前为止所做的,我们会看到一个概率图。正如你从下图中看到的,这些小点就是模板实际匹配的地方。

概率图

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

使用上面的代码,我们可以找到概率图中微小点的位置。使用minMaxLoc(res)我们可以提取最小值、最大值、最小位置和最大位置。

top_left = min_loc 
bottom_right = (top_left[0] + width, top_left[1] + height)
cv2.rectangle(img_rgb, top_left, bottom_right, (255, 0, 0), 2)

为了在模板图像匹配的源图像上绘制一个蓝色矩形,我们需要得到最小位置,min_loc(匹配实际开始的位置)作为我们的左上角。同样的,我们可以通过top_left[0] + widthtop_left[1] + height得到我们的底部。有了这些尺寸,我们可以使用cv2.rectangle绘制蓝色矩形。
这就是我们需要设置的所有内容,让我们继续想象一下。

cv2.imshow("Matched image", img_rgb)
cv2.waitKey()
cv2.destroyAllWindows()

匹配图像—一个对象

完整代码:

在给定阈值下检测多个对象

我们已经通过选择源图像和模板图像之间的最小差异检测了一个对象。通过定义一个阈值,我们可以检测所有与模板图像相似的对象。

为此,我将使用相同的源图像和模板图像来检测一个概率阈值高于 0.5 的对象(您可以通过参考res数组来决定阈值)。我们只需要修改几行代码来检测多个对象。

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)

这里我使用TM_CCOEFF_NORMED是因为我们需要得到最大值,而不是最小值。这意味着我们需要寻找多个物体而不是一个。

threshold = 0.5 #For TM_CCOEFF_NORMED, larger values means good fitloc = np.where( res >= threshold)

我们试图找到所有大于阈值的位置值。loc将接收 2 个输出数组,组合这些数组我们可以得到 x,y 坐标。

for pt in zip(*loc[::-1]):
   cv2.rectangle(img_rgb, pt, (pt[0] + width, pt[1] + height), (255, 0, 0), 1)

我现在要做的是,我们有多个位置,而不是一个。因此,对于所有这些位置,我们需要绘制蓝色矩形。这就是我们需要设置的所有内容,让我们继续想象一下。

匹配图像—多个对象

完整代码:

看起来很简单,对吗?但如果我们使用机器学习或框架,我们可以更准确地做到这一点。

感谢您的阅读,我希望这篇文章是有帮助的。

资源

[## Sreeni 为显微镜专家开发的 Python

本频道将带您了解学习 Python 编码的整个过程;从基础到高级…

www.youtube.com](https://www.youtube.com/channel/UC34rW-HtPJulxr5wp2Xa04w)

对象检测-张量流

原文:https://towardsdatascience.com/object-detection-tensorflow-854c7eb65fa?source=collection_archive---------33-----------------------

使用 Tensorflow 对象检测 API 为 Pascal VOC 数据集训练对象检测模型

Pascal VOC 数据集中图像的目标检测

T 使用 Tensorflow 对象检测 API 训练该模型,用于在 Pascal VOC 2012 数据集上训练 20 个类的模型。

自从机器学习和深度神经网络被搁置了几年后,它们的受欢迎程度又恢复了,人们对此议论纷纷。最近,世界各地的社区已经开始为机器学习领域做出贡献。自从其发展以来,对象检测和对象识别已经获得了巨大的普及,并且世界各地的研究人员已经贡献了各种最先进的架构。

谷歌的 Tensorflow 贡献了一个专用的 API(对象检测 API ),它提供了一堆在大型语料库上训练过的模型。这些模型是免费提供的,也允许用户贡献。在这篇文章中,我将使用预训练的模型来训练一个模型,以检测 PASCAL VOC 数据集中的对象。

本博客使用的数据集可在此免费获取(2012 版)。但是,服务器大部分时间都是关闭的,所以您可以在这里找到数据集。

关于数据集

我们使用的数据集代表 XML 文件和相应图像中的数据。数据中的每个 XML 文件都包含所有边界框的信息。对象检测 API 使用这些 XML 文件,并将它们转换为 csv 格式,CSV 格式可以进一步转换为训练模型所需的 tf 记录格式。在我们的例子中,我们使用的是 PASCAL VOC 数据集,tensorflow 已经为其提供了各种实用工具,使我们的生活变得更加轻松。我们将继续讨论细节。

所以,现在是时候开始一些真正的编码了……

API 为我们抽象了所有棘手的东西。但是,在使用 API 之前,用户需要满足一些要求。

API 使用 tf 记录格式的数据集。它是表示数据的二进制格式。API 使用这种格式来加速训练过程。Tf record 在内部以允许并行处理的格式表示数据。

让我们从克隆 tensorflow 模型开始,它是正在研究的模型和正式发布的模型的集合。

现在我们需要在 models/research 的 object detection 文件夹中安装协议缓冲文件。此外,我们需要安装研究文件夹中的所有模型。让我们开始吧…

在研究文件夹中安装了所有的模型之后,我们就可以将数据转换成 tf 记录格式了。现在,在我们使用 PASCAL VOC 数据集的情况下,tensorflow 为我们提供了一个脚本,我们可以用它来转换 tf 记录格式的数据。我们还需要标签数据,该数据包含要为其训练模型的类的数量。标签文件看起来像这样…

item {
  id: 0
  name: 'businesscard'
} 

这里,每个 id 映射到一个从开始的唯一数字,名称是类名。在我们的例子中,我们有 20 个类,并且在同一个文件中有 20 个唯一的项目 JSON 对象。出于我们的目的,tensorflow 为我们的数据集提供了一个标签文件,该文件可以在您的 colab 笔记本/content/models/research/object _ detection/data/Pascal _ label _ map . Pb txt中的以下路径找到

实际调用脚本将数据转换成 Tf-record 格式的时间。

这将节省。列车数据的记录文件。

同样,您需要运行 create _ Pascal _ TF _ record _ test . py 来将测试数据转换成所需的格式。

现在该训练模型了…

在处理 API 时,有各种各样的兼容性问题需要处理。这是由于 API 的初始版本。我花了大约 3 天时间解决了我们大多数人都面临的一个主要问题,那就是超薄模块。即使在提供了正确的路径和阅读了大量的博客和评论后,我最初也无法解决这个问题。但是,我会指导你的步骤,以帮助你按照目前的版本。运行培训流程时,需要使用瘦模块。要导入 slim 模块,您首先需要制作一个新的笔记本,导入并下载所有的库,并在其中克隆模型。

在 colab 笔记本开始时,您必须首先使用以下命令% tensorflow _ version 1.x将 tensor flow 版本转换为 1 . x

出于我们的培训目的,我们将使用SSD _ mobilenet _ v1 _ coco模型。我也尝试使用其他模型,但不知何故,在遵循相同的过程后,我无法摆脱那里的错误。但是对于SSD _ mobilenet _ v1型号来说一切都很好。它是在 COCO 数据集上训练的模型,因此可以检测 90 个类别。但是出于我们的目的,我们只需要为 VOC 数据集中的 20 个类训练它。

首先从 tensorflow 官网下载模型(此处)。现在,我们将提取模型 tar 文件。

现在,我将为您提供一些命令,您可以运行这些命令来解决 slim 问题。将以下命令复制并粘贴到您的笔记本中,以安装 slim 库,一次在 research/slim 文件夹中,第二次,复制 object_detection 文件夹中的所有 slim 文件,并将它们也安装在那里。

有时,使用 pip install tf-slim 直接安装 tf-slim 包也是可行的(大多数情况下是 kaggle 笔记本)

接下来,您需要从models/research/object _ detection/samples/configs/文件夹中下载模型的 config 文件,并将输入 tf 记录文件、标签映射文件、测试 tf 记录文件的路径和目录更改为现在,运行命令开始训练过程。

注意:在 colab 笔记本中,即使修改了 fine_tune_checkpoint 路径,检查点也会保存在 colab 笔记本根目录下的 tmp 文件夹中。如果这种情况仍然存在,一定要考虑一下。此外,如果训练中出现错误,则通过重新启动会话切换到 tensorflow 2.x。这样现在就不会出现小错误了。

推理

在为 20 个类训练好模型之后,我们需要将检查点文件转换成可重用的格式。为了将模型转换成所需的格式,tensorflow 提供了一个可以使用的脚本。

在 trained_checkpoint_prefix 中提供最新的检查点路径,但最多不超过您看到的最大检查点数量。

注意:如果 export_inference_graph.py 脚本抛出一个错误,指出必须使用 output_file 提供路径,那么您需要用另一个可以下载的脚本替换这个脚本,在这里找到,然后运行上面的命令

获得预测

为了获得预测,我们将使用 tensorflow 工具来获得概率和边界框值,然后在图片上显示边界框。预测的全部代码非常简单,遵循相同的结构。你可以在下面找到代码…

您可以在我的 github repo 上找到完整的工作笔记本:

** [## sahilgupta 001/Object _ Recognition _ Pascal _ VOC

GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码、管理项目和构建…

github.com](https://github.com/sahilgupta001/Object_Recognition_Pascal_VOC)

我希望本教程能在培训和测试的各个方面帮助你。如果你有任何疑问,你可以在评论区提问。

谢谢!**

使用 GluonCV 的目标检测

原文:https://towardsdatascience.com/object-detection-using-gluoncv-b7940670ba54?source=collection_archive---------38-----------------------

在本文中,我们将演示如何使用 GluonCV 使用预训练模型进行对象检测。

  1. 导入库

我们将从导入所需的库开始。我们需要导入 MXNet、GluonCV 和 Pyplot。

import mxnet as mx
import gluoncv as gcv
import matplotlib.pyplot as plt

2。测试图像

我们将使用下面的图像进行对象检测。该图像有几个明显的对象。在前景中,我们有一只在自行车前面的狗。在背景中,我们有一棵树和一辆车。我们想要一个模型来探测这些物体。

3。加载图像

因此,让我们使用 imread()加载图像。

image = mx.image.imread(image_path)
print('data type: ', image.dtype)
print('shape: ', image.shape)
print('type: ', type(image))
plt.imshow(image.asnumpy())
plt.show()

4。变换图像

如上所示,该图像具有 HWC 的数据布局。我们的图像高度为 576 像素,宽度为 768 像素。这是一个有三个通道的彩色图像。因此,让我们将图像转换成所需的格式。

CV 提供了一个为 yolo 网络应用所有必要的预处理步骤的函数。我们用我们的图像调用 yolo.transform_test ,并用 short 参数提供输出图像的短长度。我们输入的图像是高度小于宽度的风景。使用此功能,高度将被调整为 512 像素,同时保持图像的纵横比。

image, chw_image = gcv.data.transforms.presets.yolo.transform_test(image, short=512)

print('data type: ', image.dtype)
print('shape: ', image.shape)
print('minimum value: ', image.min().asscalar())
print('maximum value: ', image.max().asscalar())

转换测试函数返回两个对象。我们的第一个对象是准备好提供给网络的转换图像。我们的第二个对象只是调整了大小的图像,我们使用这个图像来绘制结果。

调整大小后的图像是一批单幅图像。这是 NCHW 格式,而不是 NHWC 格式,并且是 32 位浮点数组,而不是 8 位整数。最后,返回的 resize 图像是一个规范化的图像。

我们可以绘制调整后的 CHW 图像。

我们可以看到调整大小的效果。我们的短边现在是 512 像素而不是 576 像素,而宽度仍然是高度的三分之一。

5。负载预训练模型

我们可以使用 get_model() 函数从 CV 模型动物园加载我们的预训练模型。我们将使用带有 darknet53 主干网的 yolo3 网络,该主干网已经在 coco 数据集上进行了训练。

不要忘记将 pretrained 参数设置为 true。

6。做出预测

我们可以再次像函数一样调用网络。给网络和图像和一个预测将被返回。当使用检测模型时,我们可以预期返回三个 MXNet ndarrays。我们可以遍历元组并打印出这些数组的形状。

  1. 第一个数组包含对象类索引。
  2. 第二个数组包含对象类别概率。
  3. 最后一个数组包含了物体边界框的坐标。

请注意,这些数组的形状都是从 1,100 开始的。这是因为我们的模型可以预测单个图像中多达 100 个对象。因此,对于第一个数组,形状为 1,100,1,这意味着我们有 1 个图像,100 个潜在对象,每个对象有 1 个类别索引。

对于最后一个数组,形状为 1,100,4,我们有 1 个图像,100 个潜在的对象。和 4 个值来定义其边界框。

因为我们只对一个图像执行对象检测,所以我们可以删除所有数组的额外批处理维度,然后解包元组。我们将赋予每个数组自己的变量。

7 .。对象类别

让我们仔细看看对象 class_indexes 。虽然我们的模型可以潜在地检测每幅图像中的 100 个对象,但是让我们来看看前十个对象的类索引。

我们检测到的第一个对象的预测类别为 16,我们看到了更多类别为 1、7、2、13 和 0 的对象。在这之后,我们有许多类索引为-1 的对象。

-1 是一个特殊的类索引,用于指示没有检测到对象。

因此,我们总共有六个检测到的对象,剩下的 94 个潜在对象用-1 值填充。我们可以使用网络的类别属性来查找类别标签。顶部的对象是 class 16,在查看 class 标签时,我们可以看到 dog 的索引是 16。

8。物体概率

类似于对象 class_indexes ,我们可以得到相关的对象类概率。我们可以把这理解为我们相信类索引是正确的。

如果我们使用 50%的置信度阈值,我们可以看到已经检测到三个对象。我们的模型对它的两个检测非常有信心,概率得分在 90%以上。这可能是两个前景物体。我们还会看到-1。我们没有填充物体的置信度。

9。包围盒坐标

四个值用于定义每个对象的边界框。给出了边界框左上角和右下角的坐标,总共有四个值。

10。可视化

让我们来做可视化,而不是解释表格中的边界框。CV 带有边界框绘图功能。我们可以提供之前调整过大小的图像( chw_image )。以及每个网络输出。可选地,我们可以提供类标签来为我们的绘图添加注释。

预训练的网络在检测图像中的对象方面做得很好。它成功地检测到了一只狗、一辆自行车和一辆卡车(置信区间为 50%)。预训练的网络错过了背景中的树,因为它是在 coco 上预训练的,而 coco 没有树的对象类。

总之,我们从预处理输入图像开始。然后,我们从模型动物园加载一个对象检测模型,并使用它来生成预测。最后,我们解释了网络输出并可视化了检测到的目标。

在下一篇文章的中,我们将讨论使用 GluonCV 的图像分类问题。

在这里成为媒体会员,支持独立写作,每月 5 美元,可以在媒体上看到所有的故事。

使用 YOLOv3 的对象检测

原文:https://towardsdatascience.com/object-detection-using-yolov3-9112006d1c73?source=collection_archive---------23-----------------------

使用 YOLOv3 和 OpenCV 实时检测物体的旅程

深度学习彻底改变了计算机视觉领域。神经网络被广泛应用于几乎所有的尖端技术,如特斯拉的自动驾驶功能。他们表现得太好了,有时会导致道德问题和冲突。我们今天不会深入讨论这些。让我们来关注一下计算机视觉的一个子类,叫做“检测”。

探测一个物体是什么意思?当我们看到一个物体时,我们可以准确地指出它在哪里,并轻松地确定它是什么。然而对于计算机来说,任务并不简单。多年来,这一直是一个活跃的研究领域,今天仍然如此。在过去的十年里,随着深度学习的出现(而不是复兴),我们能够取得良好的结果,在一定程度上已经可以在实时场景中使用它。

图片来自维基百科

概观

有几种用于检测的神经网络结构

  • R-CNN 系列架构
  • 单发探测器
  • YOLO——你只能看一次

我们今天将看到 YOLOv3 的实现(最初 YOLO 架构的一个变种),但不会详细介绍它是如何工作的。之所以选择 Python(❤语,是因为它得到了 OpenCV 等库的大力支持。值得一提的另一个要点是,YOLO 模型不如 R-CNN 模型准确,但它们很快,很容易适用于实时应用。

履行

让我们从导入必要的库开始。OpenCV 库将是我们在本教程中最好的朋友,因为它有几个用于操作图像的有用函数,以及一些有用的模块,比如‘dnn’。

由于我们将使用预先训练好的模型,我们必须下载某些文件。“权重”文件、“配置”文件和“可可名”文件。权重和配置文件可以在链接中找到,coco-names 文件可以从这里下载/复制。有几种预先训练好的模型可用,我们将使用“yolov 3–416”模型。在 MS COCO 数据集上训练模型,该数据集上存在 80 类对象。

下载完所有文件后,就该创建和加载我们的模型了。正如您在下面看到的,dnn 模块有几个内置的函数在这方面帮助我们。我们的模型被训练识别的对象的名称在“coco.names”文件中给出,我们将该文件存储在一个名为 classes 的列表中。我们还在 getLayerNames()getUnconnectedOutLayers()函数的帮助下检索输出层的名称,并将它们存储在 output_layers 列表中。

我们现在必须通过模型传入图像。但是,我们不能直接这样做,因为我们的模型期望我们的图像具有特定的形状。这就是 cv2.dnn.blobFromImage() 函数派上用场的地方。它帮助我们重塑我们的形象,同时也使它们正常化,并以适当的顺序重新排列颜色通道。

然后将图像提供给模型,并执行向前传递。其输出为我们提供了一个检测列表。从该列表中,获得每个检测到的对象的一组边界框坐标,如下所示。我们使用置信度阈值来过滤掉弱检测。我使用的置信度阈值的默认值是“0.5”。所有的包围盒坐标、它们的类别 id 和它们相应的置信度值分别存储在列表“盒子”、“类别 id”和“置信度”中。

现在我们已经获得了图像中物体的位置,是时候画出它们的边界框并标记它们了。函数 draw_boxes() 为我们做了这件事。我们在旅途中可能会遇到的一个问题是,这些物体有时可能会被探测到不止一次。为了避免这种情况,我们将采用非最大值抑制(也称为非最大值抑制)。我使用的 NMS 阈值的默认值是“0.4”。这是下面的 cv2.dnn.NMSBoxes() 函数所执行的。我们最后使用 cv2.imshow() 函数显示输出图像。

既然我们已经看到了所有需要的组件,现在让我们把它们粘在一起,在一个图像文件中执行对象检测。

我们可以从文件和网络摄像头的视频中执行相同的任务,如下所示。

右图显示了同一个人周围的多个边界框。在使用 NMS 之后,我们获得了左边的图像作为输出。重复的包围盒已经被处理。

样本输出—从http://cocodataset.org/获得的测试图像

通过下面的链接,可以在我的 GitHub 库中找到这篇文章的全部代码以及一个清晰的界面。

https://github.com/GSNCodes/YOLOv3_Object_Detection_OpenCV

深度学习的最新进展为研究和探索开辟了许多途径。如果你想深入研究这个问题,我鼓励你这样做。创造和创新新技术,但要合乎道德。我希望这篇文章对你有所帮助,我很高兴成为你旅程的一部分:)

G.SowmiyaNarayanan

附言:——

这是我关于媒介的第一篇文章,我欢迎任何批评来改进我的工作,以便我能更好地满足未来像你这样的探险家的需要。欢迎评论,让我知道你的想法。你也可以在 LinkedIn 上和我联系。

内存字节:-

“若无变化,则无变化。”

使用 YoloV3 和 OpenCV 进行目标检测

原文:https://towardsdatascience.com/object-detection-using-yolov3-and-opencv-19ee0792a420?source=collection_archive---------6-----------------------

面向初学者的 YoloV3 物体检测介绍

使用 YoloV3 和 OpenCV 进行目标检测

计算机视觉一直是我着迷的话题。通俗地说,计算机视觉就是复制人类视觉的复杂性和他对周围环境的理解。它正在成为人工智能最强有力的应用领域之一。由于每天都会产生大量的数据。

目标检测

当我们观看图像或视频时,我们可以很容易地在瞬间定位和识别我们感兴趣的对象。将这种智能传递给计算机只不过是物体检测——定位物体并识别它。目标检测在很多领域都有应用,比如视频监控、图像检索系统、自动驾驶汽车等等。各种算法可用于对象检测,但我们将集中于 YoloV3 算法。

YoloV3 算法

你只看一次或者更通俗的说法是,与 R-CNN 家族(R-CNN,Fast R-CNN,Faster R-CNN 等)相比,YOLO 是最快的实时物体检测算法之一(每秒 45 帧)。)

R-CNN 系列算法使用区域来定位图像中的对象,这意味着该模型被应用于多个区域,并且图像的高得分区域被认为是检测到的对象。但是 YOLO 遵循一种完全不同的方法。它不是选择一些区域,而是对整个图像应用神经网络来预测边界框及其概率。

我们有两个选项来开始对象检测:

  1. 使用预先训练的模型
  2. 从头开始训练自定义对象检测器

在本文中,我们将着眼于使用图像、视频和实时网络摄像头的预训练模型来创建对象检测器。如果你想训练一个自定义的 YOLO 物体探测器,我建议你前往 与 YOLO 物体探测:动手教程 。作者介绍了从定制对象检测器的数据注释到处理数据并最终训练模型的所有步骤。

让我们深入研究代码。

让我们从导入该程序所需的模块开始。

模块

您还需要下载几个重要文件,包括 YoloV3 的预训练权重、配置文件和名称文件。

重量和 cfg(或配置)文件可以从https://pjreddie.com/darknet/yolo下载。您将看到几个不同的选项。该模型已针对不同大小的图像进行了训练:320 x 320(高速,精度较低)、416 x 416(中速,精度中等)和 608 x 608(低速,精度较高)。我们现在将下载 yolov 3–320 的重量和 cfg 文件。

名字文件可以从https://github . com/pjreddie/darknet/blob/master/data/coco . names下载。

现在我们已经下载并准备好了所有这些文件,我们可以开始编写 python 脚本了。就像我之前提到的,我们的输入有三种形式:

  1. 图象档案
  2. 网络摄像头馈送
  3. 可见文件

首先,我们将创建一个名为 load_yolo() 的函数。

装载重量

在上面的函数中,你可以看到,我在 OpenCV 的 dnn 模块的帮助下加载 YoloV3 权重和配置文件。 coco.names 文件包含我们的模型被训练识别的不同对象的名称。我们将它们存储在一个名为 的列表中。现在要使用 cv2.dnn 模块运行一个正向传递,我们需要传递要计算输出的层的名称。net . getunconnectedoutlayers()返回网络输出层的指数。

为了接受图像文件,我们将需要另一个名为 load_image() 的函数,它将接受一个图像路径作为参数,读取图像,调整其大小并返回它。

加载图像

为了正确预测具有深度神经网络的对象,我们需要对我们的数据进行预处理, cv2.dnn 模块为此提供了两个函数:blobFromImageblobFromImages。 这些功能执行缩放、均值减法和可选的通道交换。我们将在一个名为 detect_objects() 的函数中使用blobFromImage,该函数接受来自视频或网络摄像头流的图像/帧、模型和输出层作为参数。

正如你在上面的代码片段中看到的,我们使用了 0.00392比例因子,也可以写成 1/255 。因此,我们将图像像素缩放到 0 到 1 的范围。不需要均值减法,这就是为什么我们将它设置为【0,0,0】值。

cv2.dnn 模块的 forward() 函数返回一个嵌套列表,其中包含所有检测到的对象的信息,包括检测到的对象中心的 x 和 y 坐标、边界框的高度和宽度、coco.names 中列出的所有对象类别的置信度和得分。得分最高的类别被视为预测类别。

get_box_dimensions() 函数中,创建了一个名为 scores 的列表,其中存储了对应于每个对象的置信度。然后,我们使用 np.argmax() 来识别具有最高置信度/得分的类的索引。我们可以从我们在 load_yolo() 中创建的 classes 列表中获得对应于索引的类名。

我选择了所有置信度超过 30 %的预测边界框。您可以随意使用这个值。

现在我们有了预测边界框的顶点和 class_id(预测对象类的索引),我们需要绘制边界框并向其添加一个对象标签。我们将借助 draw_labels() 函数来完成。

现在,你一定在想, cv2.dnn.NMSBoxes() 是干什么用的?我们只是应该添加绘制边界框,并添加一个标签,对不对?

尽管我们移除了低置信度边界框,但仍有可能在对象周围出现重复检测。例如,请看下图。

具有多个包围盒的对象检测

您可能会注意到,有些对象已经被检测了多次,我们有一个以上的边界框。为了解决这种情况,我们需要应用非最大值抑制(NMS) ,也称为非最大值抑制。我们传入置信度阈值和 NMS 阈值作为参数来选择一个包围盒。从 0 到 1 的范围内,我们应该选择一个中间值,如 0.4 或 0.5,以确保我们检测到重叠的对象,但最终不会为同一个对象获得多个边界框。

因此,最终输出如下所示:

最终输出

我们看到的所有函数都可以在另一个名为 image_detect() 的函数中流水线化,用于检测图像文件中的对象。

同样,对于视频文件和网络摄像头输入,我们可以创建两个不同的函数,分别叫做 start_video()webcam_detect()

完整的工作脚本可以在https://github . com/nandinib 1999/object-detection-yolo-opencv找到。

更新 2021/11/05

加载 YOLO-V3 砝码时,代码可能会中断,您可能会得到如下所示的错误。

错误截图

如果发生这种情况,您可以使用 load_yolo()的以下代码片段:

错误修复

解决这个问题后,我遇到了另一个问题:

这就像一个警告。它不会中断代码的功能,但是在代码运行时,这个警告会一直出现在命令行上。我试图寻找一个解决方案,发现这是由于 OpenCV 和 PyQt 库之间的一些依赖问题。您可能需要升级/降级这些库,以使它们再次兼容。

一个有用的问题线索是 THIS 来了解更多关于警告和修复它的信息。此外,如果你们中的任何一个人能够找到这个警告的永久解决方法,也请与我们分享。

这都是为了这篇文章。希望你觉得有用。如果有,请鼓掌。如有任何问题和建议,请随时通过 LinkedIn 与我联系。

感谢阅读!

~南迪尼

使用 Colab 上的 YOLOv3 进行对象检测,并为面试准备问题

原文:https://towardsdatascience.com/object-detection-using-yolov3-on-colab-5d7d9eef02b3?source=collection_archive---------13-----------------------

来源:来自 Unsplash.com 的迈克·格吕贝尔

训练一个模型来识别你拍摄的图像中的不同物体。

这个博客将帮助你训练一个可以识别图像中不同物体的模型。观察模型如何在特定条件下比人类表现得更好,这既有趣又令人兴奋。它可以区分汽车和皮卡,即使卡车的尾部在图像中不清晰,就我个人而言,我无法做出这种区别。如果你已经把 YOLO 作为一个黑箱,这个博客将帮助你理解这个模型及其细微差别。最后,有一些问题可以帮助你衡量你对模型的理解。尽量在评论区回答问题,如果需要答案,尽管问我。

要求:有互联网连接和谷歌账户的 pc。

学习:使用 YOLOv3 进行物体检测的亲身体验,加深对 YOLO 算法的理解。

设置: 通过你的 google drive 设置一个 Colab 笔记本账号(我的 Drive >新>更多>连接更多 app>Colab)。要对您电脑中的图像执行对象检测,请安装“驱动器备份和同步”。允许您电脑上的一个文件夹同步到 google drive。该文件夹中的文件(图像或视频)将由 Colab 访问(通过 google drive)。

物体检测

物体检测部分分为 9 个简单的步骤。它将允许您对您点击的图像应用对象检测。所以让我们先开始物体检测,稍后我会解释它背后的算法(YOLO)。

第一步:用 google drive 连接你的 Colab 笔记本。一旦您导入并安装了驱动器,您需要点击出现在您的代码下面的链接。您需要通过允许来允许 Colab 访问驱动器。

from google.colab import drivedrive.mount('/content.gdrive')

第二步:将硬件加速器改为 GPU(运行时>更改运行时类型>硬件加速器= GPU)。要确保您已连接到 GPU,请键入!nvidia-smi,如果你连接了你应该得到你连接的 GPU 的详细信息(如下所示)。

!nvidia-smi

检查与 GPU 的连接

Step3: Darknet 是由 Joseph Redmon 编写的开源神经网络。是用 C 和 CUDA 写的。它同时支持 CPU 和 GPU 计算。暗网的官方实现可在:https://pjreddie.com/darknet/获得。我们将使用 AlexyAB/darknet 上的 darknet 的稍微修改版本。该神经网络框架可以用于使用 YOLO 的对象检测。

#clone darknet repositoryimport osos.environ['PATH'] += ':/usr/local/cuda/bin'!rm -fr darknet!git clone https://github.com/AlexeyAB/darknet

步骤 4: 使用!pwd。我们应该在/content/darknet 文件夹中。或者转到 darknet 文件夹(%cd /darknet)。在这个文件夹中,我们使用流编辑器(sed)编辑 GPU 和 OpenCV 的 make 文件(在就地模式下,即 sed -i)。我们把 GPU=0 到 GPU =1 的所有实例都改成,启用 GPU 和 OpenCV。

#go to the darknet folder, edit and remake Makefiles of GPU and OPENCV!sed -i 's/GPU=0/GPU=1/g' Makefile!sed -i 's/OPENCV=0/OPENCV=1/g' Makefile!make

第五步:加载预先训练好的 YOLO 物体检测权值。我们从 pjreddie.com 得到 YOLOv3 的预训练重量。这个网站属于约瑟夫·雷德蒙,他是 YOLO 和黑暗网的幕后黑手。

# get yolov3 weights!wget https://pjreddie.com/media/files/yolov3.weights!chmod a+x ./darknet

第六步:确保你在正确的目录下(/content/darknet)使用!pwd。如果是,则安装所需的软件包。关于完整的列表,我鼓励你看看 github 上我的 jupyter 文件。

!apt install ffmpeg libopencv-dev libgtk-3-dev python-numpy python3-numpy libdc1394-22 libdc1394-22-dev libjpeg-dev libtiff5-dev libavcodec-dev libavformat-dev libswscale-dev libxine2-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libv4l-dev libtbb-dev qtbase5-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils unzip

第七步:将镜像从你的硬盘加载到 Colab,并在上面运行 YOLO。您可以将 pc 中的任何图像传输到您在步骤 1 中与 google drive 共享的文件夹中。该图像将出现在驱动器的同一文件夹中。在我的例子中,我将文件夹命名为“darknet”,图像的名称为“test2.jpg”。文件夹的地址将是:/content . g Drive/My Drive/darknet/test 2 . jpg,但是由于地址路径中不允许有空格,所以您可以使用:/content . g Drive/My \ Drive/darknet/test 2 . jpg。

!./darknet detect cfg/yolov3.cfg yolov3.weights /content.gdrive/My\ Drive/darknet/test2.jpg

你需要 OpenCV 和 matplotlib 来查看你的结果。如果你正在进行这一步,首先祝贺你已经使用你的图像运行了你的第一个 YOLO 物体探测。

import cv2import matplotlib.pyplot as pltimport os.pathfig,ax = plt.subplots()ax.tick_params(labelbottom="off",bottom="off")ax.tick_params(labelleft="off",left="off")ax.set_xticklabels([])ax.axis('off')file = './predictions.jpg'if os.path.exists(file):img = cv2.imread(file)show_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#show_img(show_img)plt.imshow(show_img)plt.show()#cv2.imshow(img)

第九步:结果分析。在这里,你可以看到算法可以正确地检测出婴儿是人、手机还是发刷(牙刷)。而其他几件物品(吹风机、小钱包、化妆品)无法被检测到。你能猜到原因吗?也许你应该检查一下我们所用的重物是在哪个物体上训练的。

结果分析(来源:作者照片)

在这里,我已经提出了一个练习,以帮助新用户开始使用他们的电脑对象检测。此外,用户可以使用他们的图像,这将进一步增加他们的乐趣。一旦你完成了这个有趣的部分,了解 YOLO 如何探测到这些物体将会很有趣。

关于 YOLOv3 的信息

让我们试着了解算法是如何工作的。

YOLO ( 原文链接 ): 你只看一次是物体探测网。它对物体进行定位和分类。它在一个步骤中完成这两项任务。darknet-53 神经网络中 YOLO 的主干,网络中有 53 个卷积层用于特征提取。

YOLO 把输入图像分成 m×m 的网格。网格的每个单元包含一些(B)定位框来定位对象。对于一个物体,物体中心所在的细胞负责检测物体。

让我们试着去理解输出向量,它将给出这个算法不同方面的见解。输出向量将由 B * (5 + C)个元素组成。b 是每个单元中存在的锚盒的数量。每个框将给出一个概率元素,显示对象出现在单元中的概率,4 个元素描述边界框(2 个用于中心坐标 bx,by,另外两个用于描述框的高度和宽度 bh 和 bw)。c 是类的数量。如果有 6 个类,那么每个盒子将有 11 个元素,如果有 3 个盒子,那么在输出中总共将有 33 个元素。

YOLOv3 是目前最快的对象检测算法之一。速度是以准确性为代价的。与快速 R-CNN 相比,它在对象定位中产生较高的误差,但是与后者相比,它产生较小的背景误差。

为了检测每个单元中的多个对象,它在每个单元中使用多个锚定框。当然,这些锚会有不同的尺寸。假设一个是更宽的矩形(纵向),另一个是更长的矩形(横向)。要提到的另一个方面是使用标准的非最大抑制来消除每个对象的多个边界框。

面试问题

你可以在评论区评论你的答案,或者问我,如果你想让我回答这些问题的话。如果你能回答你知道答案的问题,我将非常感激,其他读者肯定会因为你的评论而受益。

Q1。一个 n×n 的图像与一个 f×f 大小的滤波器、p 的填充和 s 的步幅进行卷积,输出的大小是多少?一定要检查如果没有填充并且 f & s 都等于 2 会发生什么。

Q2。为什么在对象检测神经网络中需要完全连接的层?

Q3。列出数据扩充的策略/方法。

Q4。在 YOLO,定位框和边框有什么区别?

Q5。如何计算平均精度?

Q6。解释 NMS 或非最大值抑制的概念?

Q7。YOLO 损失函数的不同组成部分是什么?

要访问完整的 jupyter 文件:点击这里

我希望这个博客给你全面的 YOLO 实践,并帮助你开始你的目标探测之旅。如果你想讨论更多,请随意评论。

Python 中 Haar 级联的目标检测

原文:https://towardsdatascience.com/object-detection-with-haar-cascades-in-python-ad9e70ed50aa?source=collection_archive---------11-----------------------

计算机视觉演示

OpenCV for Python 在一个易于使用的包中附带了一些高级工具,使用 Haar 级联的对象检测就是其中之一。我将大致解释它是什么,并介绍如何识别图像和视频中的面部特征。

理论课

我们将使用基于 Haar 特征的级联分类器来检测人脸、眼睛、微笑以及眼镜。该方法由 P. Viola 和 M. Jones 于 2001 年提出[1]。简而言之,它是一种机器学习方法,其中在大量的正负图像上训练所谓的级联函数(正的意思是它包括期望的对象,负的图像缺少它),反过来可以用于对象检测。

为了实际解释它,我们引入了 Haar 特征的概念,它们是由下面充当卷积核的黑盒子和白盒子获得的。更具体地说,这些特征是通过从黑色矩形下的像素总和中减去白色矩形下的像素总和而接收的单个值。[2]

哈尔的特点[2]

如果你对卷积这个词感到不安,让我借助维基百科的一幅图片来简化它。它本质上是两种功能相互影响的结果。因此,在我们的例子中,它表示盒子的白色和黑色部分的像素的总和如何相互作用,即被区分以产生单个值。当然,还有一种算法可以有效地计算一个区域内像素的总和,它被称为总面积表,由 F. Crow 于 1984 年发表[3]。它后来在图像处理领域得到推广,并被命名为 integral image,但我在这里不会深入研究它。

卷积(来自维基百科的 Cmglee)

接下来,功能选择会像您想象的那样发生。您尝试不同的 Haar 特性,并查看哪一个特性能够产生黑白矩形之间像素总和的最大差值。我们下面有一个例子,其中发现了最佳的哈尔特征。眼睛通常有点暗,而下面的区域可能比较亮,因此一个上黑下白的水平矩形是合适的。第二,鼻梁通常比眼睛亮,因此中间有一个垂直的白色方框的哈尔特征是合适的。

图像的最佳哈尔特征[2]

Haar features 这个名字听起来有点奇怪,但它实际上源于与 Haar 小波的直观相似性,Haar 小波就是这些坏男孩:

它们没有被直接使用,但是这些特征(黑盒子和白盒子)是我们可以称之为 Haar-like 的东西,在这个意义上,你现在已经明白了。许多这些类似 Haar 的特征可以应用于图像,并使用 Adaboost 算法,该算法找到用于正确分类训练图像的最佳阈值。但是将其中的一个放在某个地方,即使放在可能的最佳位置,仍然会导致一些误差,因为正集和负集中的所有图像彼此不同。最后,选择错误率最小的哈尔特征作为分类器。

尽管采取了这些措施,但最终的特征数量可能相当大,因此发明人引入了分类器级联的概念(现在我们已经得到了基于特征的级联分类器的全称)。这在进行检测时使用,因为用大量特征进行检测会很慢,相反,在检测时分类器由级联的特征组成。因此,最初的哈尔特征可能只是检查图像是否可能是人脸(在人脸检测的情况下),然后接下来的阶段具有更多最基本的哈尔特征。这是一种有利的方法,因为早期不包含所需对象的图像被丢弃并且不再被处理。将这与一次将所有特征扔向图像进行比较,你会看到增益。[2]**

履行

到了我们用 Python 实现它的部分。如果你想在自己的机器上跟随或尝试任何酷的东西,它可以在 GitHub 仓库Google Colab 中公开获得,尽管不幸的是,后者不能在视频中进行对象检测……无论如何,我们从做一些导入开始,所以我们都准备好了。

接下来,我们加载容易训练的对象分类器。我从 OpenCV 自己的仓库下载了它们,在这篇文章的底部还有一个链接,告诉你如何训练你自己的分类器来分类你家里的任何东西。

所以我想这是有趣的部分。首先,在灰度模式下进行分类,然后我们可以看看 detectMultiScale,它执行对象检测,并以矩形列表的形式返回它们。该方法可以接受一些参数,这些参数可以根据个人喜好进行调整。

  • scaleFactor: 指定在每个图像比例下图像尺寸缩小多少的参数。增加它会导致更快的检测,但有丢失一些对象的风险,而较小的值有时可能会太彻底。
  • minNeighbors: 参数,指定每个候选矩形应该有多少个邻居来保留它。较高的值导致较少的检测,但质量较高。
  • ****最小尺寸:可能的最小物体尺寸。小于该值的对象将被忽略。
  • maxSize: 最大可能的对象大小。大于该值的对象将被忽略。

我篡改了代码中的比例因子和最小邻居。例如,眼镜很难被检测到,可能是因为我使用的图片中的人是向上看的,这不像输入级联被训练的目的。因此,为了更精确,我降低了比例因子和最小邻居。除此之外,我发现了太多的微笑——所以我增加了这两个参数。

请注意,OpenCV 使用图像通道的 BGR 排序,而不是 RGB,所以如果你绘制任何东西,并以一些有趣的东西结束,你知道为什么。

当你的颜色通道顺序错误时(原始的,由 Pexels 的 fauxels 拍摄的更好的照片)

我们使用 cv2 来考虑这一点。COLOR_BGR2RGB 并绘制我们的对象检测结果。

脸部、眼睛和微笑现在都可以被检测到了

整洁不是吗?你可以看到眼镜检测远非理想。我们还注意到,正如理论课所预期的那样,分类器不适用于半张脸。为此,我们需要一个单独的分类器。

现在,继续我发现的更令人兴奋的事情。我们可以修改图像检测代码中的几行代码来对视频进行对象检测。我的意思是调用 cap = cv2。VideoCapture(0) 指的是网络摄像头。我们通过按 ESC 键退出视频,作为键码键码。KEY _ ESCAPE = 27forOpenCV 的 cv2.waitKey() 这是一个将显示一帧的毫秒数作为输入的函数。不要忘记用 cap.release()cv2 . destroyallwindows()释放并关闭最后的窗口。

如前所述,你可以通过克隆我的 GitHub 库或者在 Google Colab 上尝试我所说的东西。然而, Colab 笔记本不支持网络摄像头流式视频,但我确实找到了一种在 Colab 内部拍摄自己照片的方法,面部检测可以在上面进行。这仍然是它在运行时的样子。

我们可以看到,它确实很好地检测到了我的脸和眼睛,而且笑容应该很大,就像这个:D,这样它才能工作。否则可能会被误认为是眼睛。

最后,如果您想为自己唯一的对象训练一个分类文件,该怎么办?这相当简单,我们需要一组正匹配以及大量负匹配,其中不包括您的对象。这里是我发现的一个逐步操作指南:

** [## 将数据集训练为 XML 文件,用于级联分类器 OpenCV

查找列车图像:

medium.com](https://medium.com/@toshyraf/train-dataset-to-xml-file-for-cascade-classifier-opencv-43a692b74bfe)

现在一切都结束了,如果你愿意,在领英上和我联系,链接在我的个人资料里。祝你有愉快的一天!**

[1]: P. Viola 和 M. Jones,使用增强级联简单特征的快速目标检测(2001)

[2]:使用 Haar Cascades 进行人脸检测,https://docs . opencv . org/3.4/D2/d99/tutorial _ js _ Face _ Detection . html

[3]: F. Crow,纹理映射的总面积表(1984)

物体(无人机)探测:掩模 R-CNN 的逐步指南

原文:https://towardsdatascience.com/object-drones-detection-step-by-step-guide-on-mask-r-cnn-7bec0fb09a1?source=collection_archive---------13-----------------------

米格尔·Á·安赫尔·埃尔南德斯在 Unsplash 上拍摄的照片

对象检测是一类计算机视觉,用于识别和定位图像中的对象。存在许多检测算法,这里的是对它们的一个很好的总结。

掩模 R-CNN 是对象检测的扩展,因为它为图像中检测到的每个对象生成边界框和分段掩模。我最近不得不训练一个 Mask R-CNN 模型,并在尝试在我的自定义数据集上训练时遇到了一些障碍。即使有来自 matterport 的样品笔记本,由于兼容性和数据问题,实现也不是那么简单。因此,我决定写这篇关于使用 Mask R-CNN 训练自定义数据集的指南,并希望它能帮助你们简化这个过程。

https://github.com/matterport/Mask_RCNN

对于本指南,我选择使用无人机数据集,您可以在这里下载。

首先—库和包

该算法的主要软件包是 mrcnn。从下载并导入库到您的环境中开始。

!pip install mrcnnfrom mrcnn.config import Config
from mrcnn import utils
import mrcnn.model as modellib
from mrcnn import visualize
from mrcnn.model import log

当我们到达那里时,我将解释每个导入的类。现在,只需要知道这些是我们需要的导入语句。

至于 TensorFlow,mrcnn 尚未与 TensorFlow 2.0 兼容,所以请确保您恢复到 TensorFlow 1.x。因为我是在 Colab 上开发的,所以我将使用 magic 函数恢复到 TensorFlow 1.x。

%tensorflow_version 1.x
import tensorflow as tf

如果我没看错,在 TensorFlow 2.0 中 tf.random_shuffle 被重命名为 tf.random.shuffle,导致了不兼容问题。通过更改 mrcnn 代码中的 shuffle 函数,您可能能够使用 TensorFlow 2.0。

我也不得不把我的 Keras 恢复到以前的版本,但是我不记得原因了。只是把它放在那里,以防你遇到一些错误,由于 Keras。

!pip install keras==2.2.5

预处理

mrcnn 包在其接受的数据格式方面相当灵活。因此,由于它的简单性,我将处理成 NumPy 数组。

在此之前,我意识到视频 17_295 和视频 19_1900 不能被 cv2 正常读取。因此,我过滤掉这些图像,并创建了一个文件名列表。

dir = "Database1/"# filter out image that cant be read
prob_list = ['video17_295','video19_1900'] # cant read format
txt_list = [f for f in os.listdir(dir) if f.endswith(".txt") and f[:-4] not in prob_list]
file_list = set([re.match("\w+(?=.)",f)[0] for f in txt_list])# create data list as tuple of (jpeg,txt)
data_list = []
for f in file_list:
    data_list.append((f+".JPEG",f+".txt"))

接下来要做的事情很少;

  1. 检查标签是否存在(一些图像不包含无人机)
  2. 读取和处理图像
  3. 读取并处理边界框的坐标
  4. 出于可视化目的,绘制边界框
X,y = [], []
img_box = []
DIMENSION = 128 # set low resolution to decrease training timefor i in range(len(data_list)):
    # get bounding box and check if label exist
    with open(dir+data_list[i][1],"rb") as f:
    box = f.read().split()
    if len(box) != 5: 
        continue # skip data if does not contain labelbox = [float(s) for s in box[1:]]# read imageimg = cv2.imread(dir+data_list[i][0])
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)# resize img to 128 x 128
    img = cv2.resize(img, (DIMENSION,DIMENSION), interpolation= cv2.INTER_LINEAR)# draw bounding box (for visualization purposes)
    resize1, resize2 = img.shape[0]/DIMENSION, img.shape[1]/DIMENSION
    p1,p2,p3,p4 = int(box[0]*img.shape[1]*resize2), int(box[1]*img.shape[0]*resize1) ,int(box[2]*img.shape[1]*resize2) ,int(box[3]*img.shape[0]*resize1)ymin, ymax, xmin, xmax = p2-p4//2, p2+p4//2, p1-p3//2, p1+p3//2draw = cv2.rectangle(img.copy(),(xmax,ymax),(xmin,ymin),color=(255,255,0),thickness =1)# store data if range of y is at least 20 pixels (remove data with small drones)
    if ymax - ymin >=20:
        X.append(img)
        y.append([ymin, ymax, xmin, xmax])
        img_box.append(draw)# convert to numpy arraysX = np.array(X).astype(np.uint8)
y = np.array(y)
img_box = np.array(img_box)

在转换为 NumPy 数组之前,我获取了数据集的一个子群体,以减少训练时间。如果你有计算能力,可以忽略它。

这里有一些样本图像。

MRCNN —处理

现在来看看 mrcnn 本身,我们需要在训练过程之前定义一个 mrcnn 数据集类。这个数据集类提供图像的信息,例如图像所属的类以及图像中对象的位置。我们之前导入的 mrcnn.utils 包含这个数据集类。

这就是事情变得有点棘手的地方,需要对源代码进行一些解读。

这些是你需要修改的函数;

  1. add_class,它决定了模型的类的数量
  2. add_image,您可以在其中定义 image_id 和图像路径(如果适用)
  3. load_image,加载图像数据的地方
  4. load_mask,它获取关于图像的遮罩/边界框的信息
# define drones dataset using mrcnn utils classclass DronesDataset(utils.Dataset):
    def __init__(self,X,y): # init with numpy X,y
        self.X = X
        self.y = y
        super().__init__()def load_dataset(self):
        self.add_class("dataset",1,"drones") # only 1 class, drones
        for i in range(len(self.X)):
            self.add_image("dataset",i,path=None)def load_image(self,image_id):
        image = self.X[image_id] # where image_id is index of X
        return imagedef load_mask(self,image_id):
    # get details of image
    info = self.image_info[image_id]
    #create one array for all masks, each on a different channel
    masks = np.zeros([128, 128, len(self.X)], dtype='uint8')class_ids = []
    for i in range(len(self.y)):
        box = self.y[info["id"]]
        row_s, row_e = box[0], box[1]
        col_s, col_e = box[2], box[3]
        masks[row_s:row_e, col_s:col_e, i] = 1 # create mask with similar boundaries as bounding box
        class_ids.append(1)return masks, np.array(class_ids).astype(np.uint8)

因为我们努力将图像格式化成 NumPy 数组,所以我们可以简单地用数组初始化 Dataset 类,并通过索引数组来加载图像和边界框。

接下来做一个传统方式的火车测试,

# train test split 80:20np.random.seed(42) # for reproducibility
p = np.random.permutation(len(X))
X = X[p].copy()
y = y[p].copy()split = int(0.8 * len(X))X_train = X[:split]
y_train = y[:split]X_val = X[split:]
y_val = y[split:]

现在将数据加载到数据集类中。

# load dataset into mrcnn dataset classtrain_dataset = DronesDataset(X_train,y_train)
train_dataset.load_dataset()
train_dataset.prepare()val_dataset = DronesDataset(X_val,y_val)
val_dataset.load_dataset()
val_dataset.prepare()

prepare()函数使用 image_ids 和 class_ids 信息为 mrcnn 模型准备数据,

接下来是我们从 mrcnn 导入的 config 类的修改。Config 类决定了训练中使用的变量,应该根据数据集进行调整。以下这些变量并不详尽,您可以参考文档获得完整列表。

class DronesConfig(Config):
    # Give the configuration a recognizable name
    NAME = "drones"# Train on 1 GPU and 2 images per GPU.
    GPU_COUNT = 1
    IMAGES_PER_GPU = 2# Number of classes (including background)
    NUM_CLASSES = 1+1  # background + drones# Use small images for faster training. 
    IMAGE_MIN_DIM = 128
    IMAGE_MAX_DIM = 128# Reduce training ROIs per image because the images are small and have few objects.
    TRAIN_ROIS_PER_IMAGE = 20# Use smaller anchors because our image and objects are small
    RPN_ANCHOR_SCALES = (8, 16, 32, 64, 128)  # anchor side in pixels# set appropriate step per epoch and validation step
    STEPS_PER_EPOCH = len(X_train)//(GPU_COUNT*IMAGES_PER_GPU)
    VALIDATION_STEPS = len(X_val)//(GPU_COUNT*IMAGES_PER_GPU)# Skip detections with < 70% confidence
    DETECTION_MIN_CONFIDENCE = 0.7config = DronesConfig()
config.display()

根据您的计算能力,您可能需要相应地调整这些变量。否则,你将面临卡在“Epoch 1”而没有给出错误信息的问题。甚至有一个 GitHub 问题针对这个问题提出,并提出了许多解决方案。如果这种情况发生在你身上,一定要检查一下,并测试其中的一些建议。

MRCNN —培训

mrcnn 已经在 COCO 和 I mageNet 数据集上进行了训练。为了将这些预先训练好的权重用于迁移学习,我们需要将其下载到我们的环境中(记得首先定义您的 ROOT_DIR)。

*# Local path to trained weights file*
COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5")*# Download COCO trained weights from Releases if needed*
**if** **not** os.path.exists(COCO_MODEL_PATH):
    utils.download_trained_weights(COCO_MODEL_PATH)

创建模型并以预训练的权重开始。

# Create model in training mode using gpuwith tf.device("/gpu:0"):
    model = modellib.MaskRCNN(mode="training", config=config,model_dir=MODEL_DIR)*# Which weights to start with?*
init_with = "imagenet"  *# imagenet, coco***if** init_with == "imagenet":
    model.load_weights(model.get_imagenet_weights(), by_name=**True**)
**elif** init_with == "coco":
    *# Load weights trained on MS COCO, but skip layers that*
    *# are different due to the different number of classes*
    *# See README for instructions to download the COCO weights*
    model.load_weights(COCO_MODEL_PATH, by_name=**True**,exclude=["mrcnn_class_logits", "mrcnn_bbox_fc", "mrcnn_bbox", "mrcnn_mask"])

最后,我们可以开始实际训练了。

model.train(train_dataset, val_dataset,learning_rate=config.LEARNING_RATE,epochs=5,layers='heads') # unfreeze head and just train on last layer

对于本练习,我将只训练最后一层来检测我们数据集中的无人机。如果时间允许,您还应该通过训练所有前面的层来微调您的模型。

model.train(train_dataset, val_dataset, 
            learning_rate=config.LEARNING_RATE / 10,
            epochs=2, 
            layers="all")

你已经完成了 mrcnn 模型的训练。您可以用这两行代码保存模型的权重。

# save weights
model_path = os.path.join(MODEL_DIR, "mask_rcnn_drones.h5")
model.keras_model.save_weights(model_path)

MRCNN —推理

要对其他图像进行推理,您需要创建一个带有自定义配置的新推理模型。

# make inferenceclass InferenceConfig(DronesConfig):
    GPU_COUNT = 1
    IMAGES_PER_GPU = 1inference_config = InferenceConfig()# Recreate the model in inference mode
model = modellib.MaskRCNN(mode="inference",config=inference_config, model_dir=MODEL_DIR)# Load trained weightsmodel_path = os.path.join(MODEL_DIR, "mask_rcnn_drones.h5")
model.load_weights(model_path, by_name=True)

mrcnn 的 visualize 类在这里派上了用场。

def get_ax(rows=1, cols=1, size=8):
    _, ax = plt.subplots(rows, cols, figsize=(size*cols, size*rows))return ax# Test on a random image
image_id = random.choice(val_dataset.image_ids)
original_image, image_meta, gt_class_id, gt_bbox, gt_mask =\
modellib.load_image_gt(val_dataset, inference_config,image_id, use_mini_mask=False)results = model.detect([original_image], verbose=1)
r = results[0]visualize.display_instances(original_image, r['rois'], r['masks'], r['class_ids'],val_dataset.class_names, r['scores'], ax=get_ax())

恭喜你,你已经用自定义数据集训练了一个 mrcnn 模型。拍拍自己的背,因为这不是一件容易的事。如您所见,掩蔽对我们的数据集来说并不完美,因为我们没有掩蔽数据。在这样的模型上测试一下,你会得到更好的结果。

快乐学习。

使用 Python 进行面向对象编程——您需要知道的一切

原文:https://towardsdatascience.com/object-orientated-programming-with-python-everything-you-need-to-know-cb0ada963756?source=collection_archive---------27-----------------------

在 10 分钟内掌握最流行的编程范式的概念。

面向对象编程并不是一个新概念。它由 Alan Kay 在 20 世纪 60 年代引入,但直到 20 世纪 90 年代才成为主流(感谢 C++)。今天我们将通过 Python 编程语言来了解 OOP 的基础知识。

照片由丹金Unsplash 上拍摄

不想看书?看看我关于这个主题的视频:

在一篇文章中不可能涵盖 OOP 的所有内容。整本书都是关于这个主题的,但是我们将使用 80:20 原则来涵盖你每天在 20%的时间里使用的 80%的东西。

这篇文章的结构如下:

  • OOP 是什么?
  • 类别和对象
  • 构造器
  • 类方法
  • 遗产
  • 结论

OOP 是什么?

面向对象编程不是特定于语言的。它是许多语言中使用的编程范式,比如 PythonJavaC# 等等。OOP 技能是可以转移的——所以学习 Python 中的概念会让你在其他语言中变得熟练,如果我们不考虑语法差异的话。

OOP 就是从类中创建对象。一个类包含许多以某种方式相关的字段和方法。类被用作创建对象的蓝图。

例如,您可以声明一个客户类,并使用它来创建许多客户对象。在这种情况下, Customer 类是创建单个客户的蓝图。并非所有的客户都是平等的,但是都可以用相同的字段来描述,比如年龄、性别、成员类型等等。

OOP 的目标是在代码中实现真实世界的实体。你可以用 OOP 来建模你生活中的任何东西。比如你每天都和人打交道。即使人与人不同,但他们仍然只是人。用面向对象的术语来说,你可以用一个类来建模人,并用不同的属性创建尽可能多的实例。

但是这个例子对于今天来说太复杂了。相反,我们将用汽车来探索 OOP 概念。接下来让我们看看类和对象在实践中是如何工作的。

类别和对象

把类想象成你自己的数据类型。Python 中有内置的数据类型,比如列表和字符串,但这些对于更高级的用例来说还不够。

在 Python 中,类是通过在关键字class后面加上类名和冒号来定义的。类名是任意的,但是将它写在一个标题案例中是一个好的实践。比如写MyPythonClass而不是myPythonClass或者my_python_class

一旦声明了类,就可以根据需要创建任意多个实例。让我们来看一个例子:

在上面的例子中,我们创建了一个空的Car类。下面,我们制作了它的一个实例(存储在变量car中)并打印结果。默认情况下,只有内存地址被打印到控制台:<__main__.Car object at 0x7fda5cefb3d0>

这个空类几乎没有用,所以让我们开始向它添加东西。我们将从构造函数开始。

构造器

类构造函数只有一个目标:在创建对象时给类变量赋值。

我们在这里研究汽车,所以花点时间想想每辆车的共同点是个好主意。对于我们的例子,三个属性就足够了——汽车品牌颜色车牌

汽车的属性必须在__init__()方法内部。这个方法也被称为初始化器构造器——所以请记住这些是同义词。每当创建一个对象时,就会立即调用__init__()方法。

构造函数的第一个参数必须是self。它是一个关键字,负责将传递的值分配给类变量。在 Java 等其他编程语言中,它被命名为this

现在让我们看看如何添加具有上述三个属性的构造函数,以及如何创建一个实例:

这就是你要记住的一般语法。在创建实例时,您可以看到现在需要三个参数,不提供它们会导致错误。print 语句仍然输出一个内存地址,但这是意料之中的。

我们的课还是很无聊。幸运的是,我们有办法增加趣味。接下来就让我们来探究一下。

类方法

最简单地说,方法是用来描述对象行为的函数。至少,涵盖您可以用方法做的所有事情需要一整篇文章,所以让我们坚持 80:20 原则。

本节涵盖常规、静态、私有和特殊方法。术语 private 在 Python 中是有争议的,因为没有相应的关键字,就像 Java 一样。

您可以像声明任何其他函数一样声明常规方法,用一个def关键字后跟方法名和参数列表。常规方法必须包含self作为第一个参数。

另一方面,静态方法不会。它和常规方法完全一样,但是我们需要在声明上面放一个@staticmethod装饰器。

私有方法和常规方法非常相似。惯例是在方法名前使用下划线。这不会使方法成为私有的,因为您仍然可以从外部访问它。下划线是告诉其他开发人员不应该显式使用该方法,也不应该修改其功能的一种方式。

最后但同样重要的是,我们有特殊方法。这些修改了类的原始行为。例如,我们可以用__str__方法修改输出(注意双下划线),而不是每次打印实例时都输出内存地址。当处理一个对象数组时,用__repr__方法修改打印行为。还有很多,但这两个将让你开始。

下面的代码片段演示了每种类型的方法以及如何调用它:

下面是相应的输出:

图片 Car 类方法的探索(图片由作者提供)

接下来,让我们讨论继承。

遗产

继承是 OOP 的一个重要支柱。因此,一个类可以继承另一个类的属性和方法。其属性和方法被继承的类称为父类。类似地,继承的类被称为子类

打个车的比方,你可以这样想:每辆奥迪都是车,但不是所有的车都是奥迪。Audi 是一个子类,继承了 car 类的基本属性和方法。

为了使继承有效,您必须将您继承的类的名称放在子类名称后面的括号中。让我们来看一个例子:

以下是输出结果:

图 2——继承在行动(作者图片)

describe方法是新的,并且特定于Audi类。我们已经覆盖了__str__方法,正如您在前两条 print 语句中看到的。由于继承的原因,我们可以在Audi类内部使用Car类中的stop方法。

像这样构建类是有限的。我们还需要别的东西。例如,在Audi类中,我们不能访问start方法,因为它需要Audi类没有的字段。super()关键词来拯救。

在构造函数中调用super()调用父类的构造函数,让我们可以访问里面的一切。让我们来看一个例子:

以下是输出结果:

图 3-继承和超级关键字(作者图片)

如您所见,BMW类没有任何方法,但可以从其父类访问任何内容。

离别赠言

这就是你所拥有的 Python 面向对象编程的基础。这是一个相对简短的指南,介绍了基本的 OOP 概念,并附有示例。我希望你已经理解了,并且现在概念已经很清楚了。

你今天学到的一切足以让你开始。OOP 范例可以用于所有类型的项目。我喜欢以这种方式进行机器学习,并扩展内置预测算法的功能。

感谢阅读。

加入我的私人邮件列表,获取更多有用的见解。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

原载于 2020 年 11 月 16 日https://betterdatascience.comT22。

面向对象编程:实用介绍(第一部分)

原文:https://towardsdatascience.com/object-oriented-programming-a-practical-introduction-part-1-a6755b9cee72?source=collection_archive---------55-----------------------

凯利·麦克林托克在 Unsplash

面向对象的力量

如果你已经编程至少有一段时间了,你可能会遇到(也许使用过)面向对象编程(OOP)的概念和语言特性。自 90 年代中期以来,这种编程范式一直是软件工程中的核心概念,可以为程序员提供一些非常强大的功能——尤其是在小心使用时。

然而,对于许多程序员来说,围绕着 OOP 这样的概念打转很多年并不罕见——也许在这里或那里获得了一点点洞察力——但是没有将这种理解整合成一组清晰的想法。对于初学者来说,OOP 的概念可能有点令人困惑,一些指南利用特定语言的 OOP 实现来说明思想,许多指南使用微妙不同的重载语言,所有这些反过来有时会在更一般的意义上混淆 OOP 概念。

这篇文章旨在对 OOP 的核心概念进行一次简短而实用的浏览。它会给你一些例子和用 Python 写的比较,比较你可能已经在写的代码类型和 OOP 简化的代码类型。它的目标是那些熟悉编程,但对 OOP 的正式理解有限,并且希望加深对这一领域的理解的人。它不会深入探讨 OOP 的具体方面和应用,也不会深入探讨你在不同语言实现中可能遇到的 OOP 的各种“风格”——它会尽可能保持一般性。如果这听起来不错,请继续阅读!

初学者的方法

让我们开始吧。假设您正在编写一个程序来计算一组形状的总面积。也许你正在开发一个绘图工具,或者一个边界框类型的计算机视觉问题。你知道你需要计算一组矩形和圆形的总面积。很简单,对吧?你设置并编写两个函数:

import math def area_of_rectangle(length, width): 
    return length * width def area_of_circle(radius): 
    return math.pi * radius ** 2

太好了。一个美好的全新开始。现在,要计算一组特定形状的面积,您可以写:

area_of_rectangle(10, 5) + area_of_circle(5) + area_of_circle(10)

如果你只需要计算这三个特定的形状,那么恭喜你,你已经完成了!但是如果你需要计算任意的圆和矩形集合呢?也许你会这样做:

circles = [5, 10, 25] # each element is a radius of a given circle. rectangles = [(10, 5), (6, 8)] # each element is (length, width) pair for a given rectangle. # calculate area of rectangles 
area_rectangles = 0 
for (l, w) in rectangles: 
    area_rectangles += area_of_rectangle(l, w) # calculate area of circles
area_circles = 0 
for r in circles: 
    area_circles += area_of_circles(r) # get total area total_area = area_circles + area_rectangles

同样,简单明了,和以前一样:也许你需要做的就是。但是您可能已经能够看到一些问题悄悄进入这段代码:每个形状都需要自己的for循环,并且每个循环在结构上非常相似,这导致了一定程度的代码重复。然而,如果你完全确定你只会被要求计算一组圆和矩形的总面积,那么这是很棒的。

也就是说,如果你在混乱的商业软件世界中工作,你也许能够预测到将要发生什么。你的“上游”有人发布了一个新功能,将三角形引入到形状的混合中,他们也需要你计算这些三角形的面积。现在,在上面的代码中,您可以添加如下内容:

def area_of_triangle(base, height): 
    return (base * height) / 2.0

然后,您可以添加另一个 for循环,另一个triangles列表,并更新total_area以反映您的需求。很简单,但是你的代码可能开始看起来重复和有点冗长。也许这还可以忍受,在这种情况下,很公平。

然而,你现在得到一个请求,让你的程序计算每个形状的面积和周长。你是做什么的?您可以添加以下内容:

def perimeter_of_rectangle(length, width): 
    return 2*length + 2*width

对于每个新的形状,你必须复制(甚至复制粘贴!😱)更多的代码行来支持每个新的形状或操作。

此外,计算面积(和周长)的核心问题由于周围的逻辑变得有点混乱。更糟糕的是,随着代码的增长,出现错误变得越来越容易,调试这类问题变得越来越困难,新人也更难学会和改变。虽然这个具体的例子有点做作,但总的来说,这种方法不太具有可扩展性,相当冗长,并且有很多代码重复。当事情开始变得越来越复杂时,所有这些都会使您的代码变得有点可怕——在专业环境中,这是不可避免的。

走向面向对象

这就是(谨慎应用)OOP 的好处所在。又到了从头开始计算形状面积的时候了。一眼看去,很明显你上面的小程序有很多结构上的相似性——你有一组形状,每个形状都可以说有一个面积。改变的是定义每个形状所需的信息:圆形的radius、矩形的lengthwidth,以及这些信息如何用于计算面积。如何以编程方式捕捉这种观察?这就是classes能派上用场的地方。这里有一个新的Shape类:

class Shape: 
    def area(self) -> float: ...

这告诉你什么?它说有一个名为Shape的结构,它附带了一个方法 area。换句话说:所有的Shape都有一个与之相关的区域。您可能认为area看起来很像一个标准的 Python 函数,您是对的。作为类的成员的函数通常称为方法

重要的是,这个特定的片段可以说是定义了一个抽象类:你对Shape有一个完全抽象的“概念”。它很抽象,因为它没有定义如何计算 area,只是说所有的Shape都有一个你可以访问的区域。为什么这个有帮助?现在你可以定义的子类 -抽象Shape的特定变体,为的特定形状实现这些信息。下面是一个RectangleCircle可能使用的样子:

class Rectangle(Shape): def __init__(self, length: float, width: float) -> None:
        self.length = length 
        self.width = width def area(self) -> float: 
        return self.length * self.width 
class Circle(Shape): 
    def __init__(self, radius: float) -> None: 
        self.radius = radius     def area(self) -> float: 
        return math.pi * self.radius ** 2

让我们打开包装。您会看到每个子类都是按照class Circle(Shape)的思路定义的。你可以这样理解“a CircleShape的一种”。从技术上讲,这反过来意味着Circle将立即从Shape继承area方法。逻辑上:所有的Circle也都有一个area。这里你可以看到,对于每个形状,现在已经针对所讨论的形状实施了area方法。

你还会看到现在这些类上也有一个奇怪的方法__init__。在 Python 中,这在技术上被称为“初始化器”。然而,它在功能上非常类似于更广为人知的构造函数方法,出于一般性考虑,本文将这样称呼它(两者之间的区别将在稍后讨论)。

一个构造器是一个特殊的方法,它提供了如何构造一个给定类的新实例的指令。在上面的例子中,你可以看到两种形状之间的“可见”差异在构造函数中被捕捉到:a Rectangle需要lengthwidth,而Circle需要radius。这意味着所有其他的区别(例如area是如何计算的)对代码的其余部分是隐藏的。看看这对您的初始示例意味着什么:

shapes = [Circle(5), Rectangle(10, 5), Circle(10), Rectangle(6, 8), Circle(25)] area = 0 
for shape in shapes: 
    area += shape.area()

如您所见,核心代码本身并不冗长,而且可以说更容易理解:给定一组形状,迭代这些形状并求和它们的面积。您甚至可以选择使用一个生成器表达式来代替:

area = sum(shape.area() for shape in shapes)

更加简洁的和明确的。显然,area的实现对于这个逻辑来说是不重要的(并且是不可见的)。

扩展您的代码

现在,回到在代码中引入新特性的问题。在最初的例子中,您需要添加对计算三角形面积的支持。使用你所看到的,你可以创建一个新的形状类型Triangle,如下所示:

class Triangle(Shape): 
    def __init__(self, base: float, height: float) -> None:
        self.base = base 
        self.height = height     def area(self) -> float: 
        return (self.base * self.height) / 2.0

同样,area的实现是特定于类的,但是使用类的实例对代码隐藏。因此,代码的核心逻辑(在某种意义上是“有趣的部分”)保持不变。你所需要做的就是在你的Shape列表中添加一个Triangle,这个想法更进一步:一个类的任何实例,只要是一个‘有效的’Shape就可以用在任何一个可以使用Shape的地方,而不需要其他的改变。您可以将抽象* Shape类视为定义了一个契约,所有使用Shape的代码都可以依赖它来提供所需的功能(在本例中,是形状的area)。具体来说,您的shapes列表现在应该是这样的:*

shapes = [Circle(5), Rectangle(10, 5), Circle(10), Rectangle(6, 8), Circle(25), Triangle(10, 5)]

您可能会看到,随着一些基本 OOP 概念的引入,代码变得更具可扩展性。您可以添加任意数量的形状变体,并且不需要做任何工作来改变您的“核心”逻辑。您可能会注意到,这也将您的“业务逻辑”(一组形状的总面积)与实现细节(Shape本身)隔离开来。

但是等等——还有一个要求:然后要求你也计算每个形状的周长。你是怎么做到的?

class Shape: 
    def area(self) -> float: ... 
    def perimeter(self) -> float: ... class Rectangle(Shape): 
    ... 
    def perimeter(self) -> float: 
        return (self.length + self.width) * 2.0

在这种情况下,您可以看到一个新的方法 perimeter被添加到了Shape类中。如你所料,这通知程序所有有效的Shape类都应该实现perimeter方法。回到你的Rectangle类,你现在可以实现如代码片段所示的perimeter方法。你们也可以为彼此做同样的事情Shape。注意,为了简洁起见,这里的省略号被用作上面定义的__init__area方法的简写。

然而,你可能在这里先占另一个问题:通过baseheight单独计算三角形的perimeter不同于三角形的类型,但是area保持不变。在这种情况下,使成为Triangle : RightTriangleEquilateralTriangle的子类可能是有意义的:

class RightTriangle(Triangle):    
    def perimeter(self) -> float:        
    	return self.base + self.height + math.sqrt(self.base**2 + self.height ** 2)

class EquilateralTriangle(Triangle):    
    def __init__(self, base: float) -> None:        
    	super().__init__(base, base)

    def area(self):
    	return (math.sqrt(3) * self.base ** 2) / 2.0

    def perimeter(self) -> float:        
    	return 3.0 * self.base

这个是什么意思?您会注意到,在这两种情况下,现在都有了一个特定类型的perimeter方法实现。您可能还注意到RightTriangle没有使用Triangle上定义的构造函数方法。这是因为这种类型的Triangle的构造函数与父类相同,并且通过不覆盖子类RightTriangle中的这个方法将告诉该类使用默认的构造函数。

相比之下,EquilateralTriangle 不会覆盖__init__方法。显然,对于一个等边三角形,你只需要一条边的长度就可以完全确定它的形状。这里,构造函数被修改为只需要base来反映这一点。您将会看到实现执行了第super().__init__(base, base)行。这一行调用父类* Triangle的构造函数,参数位置参数baselength被映射到base。*

把这些放在一起,你会有:

shapes = [Circle(5), Rectangle(10, 5), Circle(10), Rectangle(6, 8), Circle(25), RightTriangle(10, 5), EquilateralTriangle(5)] area = 0 
for shape in shapes: 
    area += shape.perimeter()

希望您可以看到对“核心”逻辑的更改是最小的,这个小程序现在比最初的例子更具可扩展性。您已经创建了一个由您的类层次结构捕获的本体。这允许你通过扩展你的类层次或者更新你的核心业务逻辑来给你的代码添加新的特性。您可能会看到,这(在很大程度上)分离了这些任务,使得新用户更容易专注于一个或另一个。你会问,这在实践中有什么用?

让我们暂时撇开形状不谈。想象一下,你正在为一家类似于 Stripe 的公司工作(一家数字支付公司)。您有一些代码来处理平台上发生的每个事务。您已经定义了一个简单的Transaction类来捕获关于事务的信息。然后,您的业务逻辑管道获取该类的实例,检查欺诈迹象,更新您的内部交易记录,向您的客户发送推送通知,然后将交易元数据归档到某个地方。

这个流程可能非常复杂,显然性能和可靠性对您的服务至关重要。您可能会有一组测试套件围绕这个管道,也许还有一个特别健壮的代码审查过程。基本上:你不想对你的代码做虚假的修改。然而,商业世界喜欢虚假的变化。在本例中,可能法规发生了变化,或者您需要在一个新的区域运营,这需要您处理额外的数据。实际上,你仍然想要一个设计良好的渠道——你不想为每一个小的业务变化或每一个新的领域更新整个渠道。

通过这个例子,你可能会明白如何应用本文中的概念。通过使用 OOP 技术的组合将变化的东西(即事务信息)从管道实现中隔离出来,您可以减少您遇到的每个新的特定于业务的用例需要更改的代码量,同时保持您的业务关键代码坚如磐石。酷吧。

直到下次

第 1 部分到此为止。您已经看到了 OOP 在玩具问题上的一些实际能力,以及它们如何改变您对设计和构建软件的看法。您还看到了一个简单的例子,说明了 OOP 对于更“真实”的应用程序的好处。希望你已经发现它有用。

然而,到目前为止,您已经避开了对支撑 OOP 的语言和概念的更技术性的研究。此外,你可能也看到了对 OOP 应用过于乐观的看法:在使用 OOP 时有相当多的理由要谨慎,在将它应用到你的项目之前理解这些理由是很重要的。

幸运的是,这是您将从第 2 部分中得到的!下次请继续收听!

如果您有任何问题或反馈,通过 Twitter 与我联系。

原载于 2020 年 9 月 14 日https://mark . douthwaite . io

面向对象编程:实用介绍(第二部分)

原文:https://towardsdatascience.com/object-oriented-programming-a-practical-introduction-part-2-f376bc25f839?source=collection_archive---------53-----------------------

凯利·麦克林托克

在本系列的第 1 部分中,您看到了一些如何使用面向对象编程(OOP)来帮助您解决一些代码设计问题的实际例子。如果你错过了,就在这里:

[## 面向对象编程:实用介绍(第一部分)

面向对象编程是现代软件工程工具箱中的一个主要部分。这篇文章给出了一个温柔的…

towardsdatascience.com](/object-oriented-programming-a-practical-introduction-part-1-a6755b9cee72)

好吧,我们开始吧。

变得技术化

面向对象的语言看起来令人生畏。您已经在第 1 部分的示例中看到了一些这种语言,但是让我们把它变得更具体一些。首先,让我们从最基本的问题开始:一个class和一个object之间有什么区别?

  • —给定结构可用的数据和程序的定义。换句话说,一个类定义了它引用什么数据,以及什么过程(方法)可以用在这些数据上。
  • 对象 —类的具体实例。例如,在上面的例子中,你定义了Rectangle,并实例化了这个类以产生一个Rectangle对象(例如Rectangle(10, 5))。

class方法和变量与instance方法和变量之间也有一些重要的区别,它们会对代码的行为产生影响:

  • 实例变量— 这些是“属于”一个类的每个实例的数据元素(即对象,例如Rectangle类上的lengthwidth变量)。
  • 类变量——这些是“属于”一个类的所有实例的数据元素——该类的所有实例都有一个副本。

为了澄清这一点,我们来看看两者之间的区别:

class NewCircle(Shape): 
    pi = math.pi     def __init__(self, radius: float) -> None: 
        self.radius = radius     def area(self) -> float: 
        return self.pi * self.radius ** 2

在这种情况下,pi是一个类变量,而radius是一个实例变量。实际上,pi是由所有类共享的,所以如果你这样做:

a, b = NewCircle(1), NewCircle(1) 
print(a.area(), b.area()) # 3.141592653589793 3.141592653589793 NewCircle.pi = 3.14 # this changes `pi` on both `a` and `b`. print(a.area(), b.area()) # 3.14 3.14

你会看到用NewCircle.pi更新类变量改变了两个圆的面积,而:

a, b = NewCircle(1), NewCircle(1) 
print(a.area(), b.area()) # 3.141592653589793 3.141592653589793 
a.pi = 3 # update only the copy of `pi` on the instance `a`. print(a.area(), b.area()) # 3 3.141592653589793

只会在属于这个类的a实例的pi的副本上修改pi

对数据操作方法—* 事物*怎么样?正如你在第 1 部分中看到的,方法可以被认为是一个类的成员(即“属于”)的函数。有两个特别重要的例子反映了上面的变量定义:**

  • 实例方法 —很像实例变量,实例方法‘属于’个别对象。这些方法可以访问封装的数据和方法成为对象,包括其他方法、实例变量和类变量。
  • 类方法— 相比之下,类方法是对一个类的所有实例都可用的方法,但是只能访问该类的其他类方法和类实例。

Python 支持类方法(以及一些其他种类的方法),但是理解它们在 Python 中的使用需要对一些中级 Python 语言特性(包括 装饰器 )有扎实的理解,所以关于这些的示例和讨论将留到以后的文章中。

现在正式介绍 OOP 的一些更大的概念。

包装

在第 1 部分的例子中,你看到了Rectangle类的定义。概括来说,您有:

*class Rectangle(Shape): 
    def __init__(self, length: float, width: float) -> None: 
        self.length = length 
        self.width = width     def area(self) -> float: 
        return self.length * self.width     def perimeter(self) -> float: 
        return (self.length + self.width) * 2.0*

在 OOP 中,封装指的是将数据和函数(方法)捆绑成一个单一的结构(一个类)。实际上,封装用于隐藏对象的状态。这种信息隐藏的一部分包括定义如何访问特定的变量和方法,以限制误用并确保稳定性。这就是某些语言中使用的公共受保护私有‘访问修饰符’概念的由来。让我们来看看这意味着什么。

在这里的例子中,Rectangle中的所有实例变量和方法都可以描述为 public - 它们对于与任何Rectangle实例交互的任何代码都是“可见的”(可访问的)。然而,如果您决定不希望您的用户在实例化了一个Rectangle之后干扰lengthwidth实例变量,会发生什么呢?一种方法是将你的变量和方法保护起来或者私有。这将防止(或者在 Python 中某些情况下阻止直接使用Rectangle的人访问lengthwidth。具体地说,您可以将一个类的成员定义为具有三种访问级别之一:**

  • Public —对任何使用该类的代码可见。
  • Protected —仅对定义该成员的类以及该类的所有子类可见。
  • 私有— 仅对定义成员的类可见。

同样,其他语言也可以有额外的访问(或非访问)修饰符。这在 Python 中是如何工作的?下面是上述Rectangle片段的修改版本:

*class Rectangle(Shape): 
    def __init__(self, length: float, width: float) -> None: 
         self._length = length 
         self.__width = width     def area(self) -> float: 
         return self._length * self.__width 

    def perimeter(self) -> float: 
         return (self._length + self.__width) * 2.0*

这个代码片段遵循 Python 约定,现在表明_length实例变量是一个受保护的成员(即可以被子类访问)并且__width是一个私有成员(即只能被Rectangle访问)。这表明如果您要创建class Square(Rectangle),这个新类根本不能使用width变量。

另外,你不应该在Rectangle的实例上访问变量_length(例如Rectangle(10, 5)._length)。如果你正在使用棉绒,你会注意到如果你试图违反这些规则,它会给你警告。此外,虽然 Python 不以传统方式强制保护的私有的成员,但是许多语言都这样做,并且控制对所述成员的访问的能力(即使在 Python 的更有限的方法中)可能是一个有用的设计特性。

例如,将计算中的中间步骤分解成不同的受保护的方法是有用的,但是只公开一个公共方法供用户使用。换句话说:隐藏终端用户不应该访问的实现细节,只暴露那些他们应该访问的细节。

因此,只让方法的最小子集成为公共方法通常是个好主意(或者相反,你应该默认让变量和方法成为受保护的,除非你有特定的理由让它们成为公共的)。这有助于保持用户与类交互的方式尽可能的窄,这反过来减少了您向他们展示的 API 的“表面区域”,这通常会减少支持和维护该 API 所需的开发工作。

多态性

让我们再一次回顾第 1 部分中重构的Shape示例:

*class Shape: 
    def area(self) -> float: ... class Rectangle(Shape): 
    def __init__(self, length: float, width: float) -> None: ... def area(self) -> float: ... class Triangle(Shape): 
    def __init__(self, base: float, height: float) -> None: ... def area(self) -> float: ... shapes = [Rectangle(5, 10), Triangle(1, 2)] area = 0 for shape in shapes: 
    area += shape.area()*

这个片段捕获了与多态性概念相关的一些关键思想。技术上,多态是指不同类型的对象可以公开一个单个接口的概念。在这里的示例代码中,RectangleTriangle都公开了相同的方法,因此调用这些方法的代码可以与它所操作的对象的类型无关。换句话说,你在列表shapes上的循环只需要保证它所操作的对象实现了Shape接口,如果它们实现了,那么它总是工作得很好。**

这是一个非常强大的概念。如果使用得当,它允许您构建干净的、可扩展的 API,这些 API 易于使用且易于调试。这个特定的概念被用作许多流行框架的基础:公开的接口捕获一个领域或问题的模型,然后您可以与它交互或扩展它。

具体来说,以一个流行的机器学习(ML)库为例,比如 Scikit-Learn 。如果你曾经使用过这个库,你无疑会熟悉描述库中模型特征的经典fitpredict方法(以及其他方法)。这个接口简单明了——如果有时有限制(通过定义什么东西,你也最终定义了什么东西不是),并且允许用户构建利用它的 ML 管道,而不用担心管道使用的特定模型变量(事实上,这正是 Scikit-Learn Pipelines 所做的!).

…通过定义什么东西 ,你也经常最终定义什么东西 不是,毕竟*。*

因此,其他提供者可以实现他们自己的符合该接口的模型版本,这些版本又可以立即用于任何使用 Scikit-Learn 模型的管道设置中。您可能还记得其他流行的库,如 LightGBMXGBoostTensorflow 提供了 Scikit-Learn 兼容的接口。这是为什么存在如此活跃的 Scikit-Learn 兼容工具生态系统的部分原因,也是为什么从工程角度来看这个事实如此有用(和重要):它帮助您将您实际使用 a 模型所做的事情的逻辑与特定模型变体的实现细节分开。这(部分)是通过多态性实现的。

如果你对更正式地理解各种形式的多态性背后的思想感兴趣,你可能会发现阅读与相关的思想,包括利斯科夫替代原理,会很有帮助。此外,多态性有时会被误认为是 OOP 本身的一个特定方面。相反,它是一个更通用的编程概念,并且可以在各种形式的许多不同范例中找到变体,包括函数式编程(另一个杰出的编程范例)。

遗产

OOP 的第三个主要特征是继承。这里的关键思想是继承允许你表达类之间的“是一种类型”的关系。例如,在第 1 部分中看到的Shape示例中,您可以将关系class Triangle(Shape)表达为:Triangle Shape的一种类型。同样,你可以把class RightTriangle(Triangle)表达为:RightTriangle Triangle的一种。然后,您可能会开始看到您正在构建一个类的层次结构。在这个简单的例子中,您会看到这样的内容:

这种层次结构中的“根节点”(即本例中的Shape)通常被称为基类。这些类是抽象的也是很常见的:它们不指定自己的实现,而是定义一个接口(也许是部分实现)。抽象类不是设计来直接实例化的:它是设计来子类化的。许多语言积极地强调这一事实,并阻止你试图直接实例化一个抽象类。这种行为也可以在 Python 中实现。在这些类上定义的不提供实现的方法(如示例中的area)被称为抽象方法(或者在某些语言/上下文中等同于虚拟方法)。**

为了更具体一点,抽象类可以定义为:

  • 抽象类 —具有一个或多个抽象方法的类。

那么为什么这个有用呢?继承(理论上)使您能够轻松地扩展和修改类,从而可以更容易地向代码中添加特性和功能。以上面的例子为例:你看到了Triangle类是如何被扩展的,在两种新类型的Triangle上快速方便地实现一个新方法perimeter,而不需要“接触”父Triangle类。

您可能会看到如何在业务环境中使用它:您可以选择捕获不同类型的客户、交易或其他业务实体作为一个类层次结构,然后使用您在多态中看到的思想创建一些好的通用业务逻辑来操作这些不同类型的对象。你当然应该探索这个想法,但要谨慎行事。

深入挖掘

这篇文章实际上只是触及了 OOP 的皮毛:它是一个很大的领域,有大量的工具、思想和实现来支撑它在现代软件项目中的使用。如果你选择深入 OOP 的世界,你会发现某些血统的语言(例如 C++,Java)之间有很多相似之处,也有一些区别。一些语言和工具有意采用了这里讨论的特性的特定子集,而其他语言和工具也实现了更复杂的版本。如果你花时间学习这些思想——特别是跨语言的来帮助你比较和对比思想和方法——你会发现 OOP 是你编程工具箱中的一个无价工具。然而…

一句警告

到目前为止,你已经看到了 OOP 如何被用来帮助你构建和解决问题。在有经验的人看来,这是一个强有力的工具。然而,当不加选择地使用时,OOP 可能会成为的问题。不恰当/过度地使用 OOP 概念和能力很容易对你不利。正如在学习新知识和新技能时的情况一样,对于不熟悉 OOP 概念的人来说,落入“锤子定律”设置的陷阱是很常见的:当你有一把锤子时,一切看起来都像钉子。

…对于不熟悉 OOP 概念的人来说,落入“锤子定律”的陷阱是很常见的:当你有一把锤子时,一切看起来都像钉子。

实际上,你在上面看到的封装、多态和继承的完全相同的特性会增加复杂性,并且阻碍你的代码的调试、性能和维护,如果你不小心和没有预先考虑就使用它们的话。例如,过度复杂和/或设计不良的类层次结构是开发团队最终陷入困境的常见方式——他们的类层次结构可能会变成难以推理和技术上难以扩展的大型复杂结构。

与任何技能一样,理解何时以及如何应用 OOP 概念来自实践,坦率地说,来自偶尔的失败。您将使一些代码变得不必要的复杂和笨拙。你很可能会打碎东西。最终,你需要将 OOP 的思想应用到你自己的问题中几次,然后你才能感觉到什么可行,什么不可行。此外,对概念的“纯粹”技术理解是不够的:当你开始一个新项目(或加入一个现有项目)时,你需要记住后退一步,思考更大的图景,以及如何最好地使用可用的工具。

结束语

正如您所看到的,OOP 提供的概念和 OO 语言特性的具体实现可以帮助您设计和实现代码,以非常优雅的方式运行。然而,从某种意义上来说,它们并没有增加任何“新”东西:你可以编写代码来解决你可能面临的任何问题,而不需要去使用 OOP 提供的工具。也就是说,明智地使用面向对象的思想可能会让你成为一个更加高效的程序员,并且可能会让别人更容易采用重用你的代码。此外,很好地掌握 OOP 还将帮助你更好地理解和推理许多流行软件框架的行为和设计。

很好地掌握 OOP 也将帮助你更好地理解和推理许多流行软件框架的行为和设计。

和往常一样,知道何时使用特定的工具(并准备好工具等待使用)是一项需要培养的宝贵技能。重要的是,你要尝试和思考如何以及在哪里将面向对象的思想应用到你自己的工作中。例如,如果您确定您正在编写一个一次性问题的解决方案,那么创建一个复杂的类层次结构很可能会过度设计您的解决方案,产生比它解决的问题更多的问题。然而,如果你开始一个你知道会被广泛使用和扩展的项目,它可能真的会有回报。

进一步阅读

* [## 电气工程和计算机科学

麻省理工学院的电子工程和计算机科学系的毕业生工作在不同的行业和进行…

ocw.mit.edu](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/) [## PEP 8 风格的 Python 代码指南

Python 编程语言的官方主页

www.python.org](https://www.python.org/dev/peps/pep-0008/#designing-for-inheritance)

原载于 2020 年 10 月 9 日https://mark . douthwaite . io*。**

面向对象编程已经死了。等等,真的吗?

原文:https://towardsdatascience.com/object-oriented-programming-is-dead-wait-really-db1f1f05cc44?source=collection_archive---------0-----------------------

函数式编程的鼓吹者们,你们把枪口对准了错误的敌人

如果这么多人讨厌面向对象编程,为什么它仍然占主导地位?Vale Zmeykov 在 Unsplash 上的照片

20 世纪 60 年代的编程有一个很大的问题:计算机还没有那么强大,它们需要在数据结构和过程之间进行分割。

这意味着,如果你有一大堆数据,如果不把计算机推到极限,你就不能做那么多。另一方面,如果你需要做很多事情,你不能使用太多的数据,否则计算机会永远运行不完。

然后,艾伦·凯在 1966 年或 1967 年提出理论,认为人们可以使用封装的微型计算机,这些计算机不共享数据,而是通过消息传递进行通信。通过这种方式,可以更加经济地使用计算资源。

尽管这个想法很巧妙,但直到 1981 年,面向对象编程才成为主流。然而,从那时起,它就没有停止吸引新的和经验丰富的软件开发人员。面向对象程序员的市场和以前一样繁忙。

但是最近几年,这种有十年历史的模式受到了越来越多的批评。有没有可能,在面向对象编程风靡大众四十年后,技术正在超越这种范式?

[## 为什么开发人员会爱上函数式编程

从 Python 到 Haskell,这种趋势不会很快消失

towardsdatascience.com](/why-developers-are-falling-in-love-with-functional-programming-13514df4048e)

函数和数据耦合有那么蠢吗?

面向对象编程背后的主要思想非常简单:你试图把一个程序分解成和整体一样强大的部分。接下来,您将数据片段和那些只在相关数据上使用的函数结合起来。

请注意,这仅包括封装的概念,也就是说,位于对象内部的数据和函数对外部是不可见的。人们只能通过消息与对象的内容进行交互,通常称为 getter 和 setter 函数。

最初的想法中没有包含的,但被认为是今天面向对象编程所必需的,是继承和多态。继承基本上意味着开发人员可以定义拥有其父类所有属性的子类。直到 1976 年,在它的概念提出十年之后,它才被引入面向对象编程。

多态性在另一个十年后来到了面向对象编程。基本上,这意味着一个方法或一个对象可以作为其他方法或对象的模板。从某种意义上说,这是继承的一般化,因为并不是原始方法或对象的所有属性都需要传递给新实体;相反,您可以选择覆盖属性。

多态的特别之处在于,即使两个实体在源代码中相互依赖,被调用的实体更像是一个插件。这使得开发人员的生活更加轻松,因为他们不必担心运行时的依赖性。

值得一提的是,继承和多态并不是面向对象编程所独有的。真正的区别在于封装了数据片段和属于它们的方法。在计算资源比今天稀缺得多时候,这是一个天才的想法。

面向对象编程不是一个愚蠢的想法。这使得编码变得容易多了。由 Unsplash 上的窗口拍摄的照片

面向对象编程中的五大问题

一旦面向对象编程风靡大众,它就改变了开发人员看待代码的方式。20 世纪 80 年代以前流行的过程编程是非常面向机器的。开发人员需要对计算机如何工作有相当多的了解,才能写出好的代码。

通过封装数据和方法,面向对象编程使得软件开发更加以人为中心。方法drive()属于数据组car,但不属于数据组teddybear,这符合人的直觉。

当遗传出现时,那也是直觉。很有意义的是,Hyundaicar的子群并且共享相同的属性,但是PooTheBear不是。

这听起来像是一台强大的机器。然而问题是,只懂面向对象代码的程序员会把这种思维方式强加到他们做的每一件事情上。这就像人们看到到处都是钉子,因为他们只有一把锤子。正如我们将在下面看到的,当你的工具箱里只有一把锤子时,这会导致致命的问题。

香蕉大猩猩丛林问题

想象你正在建立一个新的程序,你正在考虑设计一个新的类。然后,您回想起您为另一个项目创建的一个整洁的小类,您意识到它非常适合您当前正在尝试做的事情。

没问题!您可以在新项目中重用旧项目中的类。

除了这个类实际上可能是另一个类的子类,所以现在你也需要包含父类。然后,您意识到父类也依赖于其他类,您最终会包含大量代码。

二郎的创造者,乔·阿姆斯特朗,著名的宣称:

面向对象语言的问题是,它们拥有所有这些隐含的环境。你想要一个香蕉,但你得到的是一只大猩猩拿着香蕉和整个丛林。

这几乎说明了一切。重用类没问题;事实上,这可能是面向对象编程的一个主要优点。

但是不要走极端。有时你最好写一个新的类,而不是为了枯燥而包含大量的依赖项(不要重复)。

要聪明,不要像宗教一样遵循一种范式。车窗挡泥板上拍照

脆弱的基础类问题

假设您已经成功地为新代码重用了另一个项目中的一个类。如果基类改变了会怎样?

它会破坏您的整个代码。你可能都没碰过它。但是某一天你的项目运行得很好,第二天就不行了,因为有人改变了基类中的一个小细节,而这个小细节对你的项目来说是至关重要的。

使用继承越多,可能需要做的维护就越多。因此,即使重用代码在短期内看起来非常有效,但从长远来看,它可能会变得非常昂贵。

钻石问题

继承是一个可爱的小东西,我们可以把一个类的属性转移给其他类。但是如果你想混合两个不同类的属性呢?

你做不到。至少不是以优雅的方式。以类Copier为例。(我从 Charles Scalfani 的病毒故事 再见,面向对象编程中借用了这个例子,以及关于这里提出的问题的一些信息。)复印机扫描文件内容,然后打印在一张空白纸上。那么它应该是Scanner的子类,还是Printer的子类呢?

根本没有好的答案。尽管这个问题不会破坏您的代码,但它经常出现,足以令人沮丧。

等级问题

在钻石问题中,问题是哪个类Copier是。但是我骗了你——有一个简单的解决方案。让Copier作为父类,ScannerPrinter作为子类,它们只继承属性的一个子集。问题已解决!

很好。但是如果你的Copier只是黑白的,而你的Printer也能处理彩色的,那该怎么办呢?这个意义上的Printer不就是Copier的一个概括吗?如果Printer连接了 WiFi,而Copier没有呢?

在一个类上堆积的属性越多,建立适当的层次结构就越困难。实际上,您正在处理属性集群,其中Copier共享Printer的一些属性,但不是所有属性,反之亦然。如果你试图把它固定在层级结构中,并且你有一个大的复杂项目,这可能会把你引向一场混乱的灾难。

不要混淆层次结构,否则你可能会陷入混乱。艾玛·道在 Unsplash 上的照片

参考问题

你可能会说,好吧,那我们就只做没有层次结构的面向对象编程。相反,我们可以使用属性集群,并根据需要继承、扩展或覆盖属性。当然,这可能有点乱,但这将是手头问题的准确表示。

只有一个问题。封装的全部目的是保护数据块之间的安全,从而提高计算效率。没有严格的等级制度,这是行不通的。

考虑如果一个对象A通过与另一个对象B交互来覆盖层次结构会发生什么。AB有什么关系并不重要,只不过B不是直接的父类。那么A必须包含一个对B的私有引用,因为否则,它不能交互。

但是如果A包含了B的孩子也拥有的信息,那么这个信息可以在多个地方被修改。因此,关于B的信息不再安全,封装被破坏。

尽管许多面向对象的程序员用这种架构来构建程序,但这不是面向对象编程。就是一团乱。

单一范式的危险

这五个问题的共同点是,它们在不是最佳解决方案的地方实现了继承。因为继承甚至没有包含在面向对象编程的原始形式中,所以我不认为这些问题是面向对象所固有的。它们只是教条走得太远的例子。

然而,不仅仅是面向对象编程可能会过头。在纯粹的函数式编程中,处理用户输入或在屏幕上打印消息极其困难。面向对象或过程式编程更适合这些目的。

尽管如此,仍有一些开发人员试图将这些东西作为纯函数来实现,并将他们的代码扩充到几十行,没有人能够理解。使用另一种范式,他们可以很容易地将代码减少到几行可读的代码。

范式有点像宗教。他们善于中庸——可以说,耶稣、穆罕默德和佛陀说了一些很酷的东西。但是如果你遵循它们到最后的小细节,你可能会让你自己和你周围的人的生活变得非常痛苦。

编程范例也是如此。毫无疑问,函数式编程正在获得越来越多的关注,而面向对象编程在过去几年中已经受到了一些严厉的批评。

了解新的编程范例并在适当的时候使用它们是有意义的。如果说面向对象编程是让开发者走到哪里都看到钉子的锤子,那这是把锤子扔出窗外的理由吗?不。你在工具箱里放一把螺丝刀,也许一把小刀或一把剪刀,然后根据手头的问题选择工具。

函数式和面向对象的程序员都一样,不要把你的范例当成宗教。它们是工具,在某个地方都有用途。你用什么应该只取决于你在解决什么问题。

[## 函数式编程和面向对象哪个更好?

你可能问错了问题

medium.com](https://medium.com/madhash/what-is-better-functional-programming-or-object-oriented-9a116c704420)

最大的问题是:我们正处于一场新革命的风口浪尖吗?

最终,函数式编程与面向对象编程之间的争论——诚然相当激烈——可以归结为:我们是否正在走向面向对象编程时代的终结?

越来越多的问题出现了,而函数式编程通常是更有效的选择。想想数据分析、机器学习和并行编程。你越深入这些领域,你就会越喜欢函数式编程。

但是如果你看看现状,有十几个面向对象的程序员和一个函数式程序员。这并不意味着如果你更喜欢后者,你就找不到工作;如今功能性开发人员仍然非常缺乏。

最有可能的情况是,面向对象编程将在未来十年左右继续存在。当然,前卫是实用的,但这并不意味着你应该抛弃面向对象。在你的节目中有这样的表演还是非常好的。

所以在未来几年内,不要把面向对象编程扔出你的工具箱。但是要确保这不是你唯一的工具。

基于对象的强化学习

原文:https://towardsdatascience.com/object-oriented-reinforcement-learning-95c284427ea?source=collection_archive---------17-----------------------

对世界物体的认知能提高强化学习算法的有效性和效率吗?

有一天,强化学习可能会提供正确的工具来建立完全自主的代理。在 Unsplash 上由 Franck V. 拍摄的照片

强化学习为建模行为构成了一种强大的形式主义,它允许我们解决多种类型的复杂决策问题,例如游戏自主机器人自动股票交易;我们曾经认为用经典的(甚至基于人工智能的)算法方法几乎不可能有效地解决这些问题。

在这篇文章中,我们将探索一个名为面向对象强化学习【1】的强化学习形式,其主要特点是在更高的抽象层次上进行推理,即在世界/环境的对象及其关系的层次上进行推理。这种形式保证了优越的性能以及采样效率的显著提高。

内容

这篇文章的结构如下:

  • 强化学习简介,
  • RL 的基本限制,
  • 面向对象的强化学习,
  • 结论和参考文献。

RL 的非正式介绍

强化学习提供了一套工具来训练一个 代理环境 (一个真实或模拟的世界)中,通过试错(即执行一个动作,然后体验它的效果),仅在 奖励 的指导下,采取最优动作。奖励是一个标量反馈信号,告诉代理人所采取的行动有多好。代理人收集奖励是为了学习在给定的情况或状态下执行哪种动作是最好的。

RL 位于许多知名领域的交汇点。[ 来源 ]

简而言之,代理学习如何解决一个任务即决策问题。Atask 被正式定义为根据环境和奖励函数描述的马尔可夫决策过程** (MDP)。环境决定了世界的动态,即当一个动作在特定情况下被执行时接下来会发生什么(称为状态),而奖励函数告诉代理在给定世界的当前情况(其状态)下,它通过执行一个动作赚了(或赔了)多少。**

在每个时间步,代理通过执行一个动作来改变环境的状态。行动的效果是由环境提供的,作为下一个状态和奖励。代理使用奖励或两者的反馈来改善其行为。[ 来源 ]

MDP 的解决方案是确定代理行为的策略** 𝛑。最佳策略是"最大化(预期)回报的(贴现)总和",也称为 RL 目标😗*

RL 目标。最佳代理人是能获得最高回报的人。当从随机策略中抽取行动样本时,我们通过行动概率对累积回报进行加权。

请注意,这是一个通用公式,因为该策略可以用多种方式表示:作为一个手工设计功能的线性或浅层组合,或者作为一个深度神经网络。此外,策略可以是随机的或确定的。随机策略是行动的概率分布,在这种情况下,RL 目标是最大化预期奖励总和。相反,一个确定性策略是状态 s 的确定性函数,其中只有一个动作具有非零概率。

深度 RL 支持深度神经网络策略,因为它们既有表达性(我们可以轻松增加模型容量),又在空间和时间上计算高效,因为计算神经网络的正向传递通常是廉价的。用这些术语来表达,RL 目标旨在找到政策的参数θ,该参数产生最高的可能(贴现)累积回报总和:**

当策略是具有参数θ的神经网络时的 RL 目标。注意,期望是在轨迹𝜏上,即状态和动作对(s,a ),通过与环境交互并根据具有参数θ的策略行动而获得。

请注意,在这两个目标中都有一个𝛄折现因子,即一个介于 0 和 1 之间的实数,用于“衡量”未来的奖励。当时间范围 T 为无穷大时,贴现因子是强制性的,因为它防止了报酬总和的发散。一般来说,我们总是想用 0.9、0.95 或 0.99 的系数来贴现奖励。**

为了计算最优策略,我们需要一种比较策略的方法。直觉告诉我们,一项更好的政策会惠及“更有价值”的州,也会挑选出“更有回报”的行动:

  • 状态值函数 V(s) ,量化了我们从状态 s 采取最优行动平均可以获得多少回报。如果 s初始状态其值衡量当前策略从开始时平均会得到多少奖励。因此,最佳策略是实现最高价值的策略。同样的,
  • 动作值函数 Q(s,a) 表示当处于状态 s 时采取动作 a 有多好。action-value 函数有助于理解在状态 s 时采取哪个特定动作是最好的。我们知道最优策略只执行最优动作,即面对给定状态时 Q 值最大的动作。

这两个函数是寻找最优策略的贝尔曼最优方程的基本成分。对于小问题,这个方程可以用动态规划很容易地解决。相反,对于高维度和连续的 MDP,我们通常使用神经网络来近似由无模型方法(例如 Q 学习、TD 学习、策略梯度、参与者-批评家)和基于模型的方法(例如 Dyna)使用的 V 和/或 Q,以找到给定任务的最佳策略。**

深度强化学习有什么问题?

Deep RL 正在实现几个突破性的人工智能,它非常有前途,但并不完美,因为它继承了深度学习和经典强化学习的问题。主要缺陷是:

  • 样本效率:深度神经网络(DNNs)需要具有大量示例的数据集(想想 ImageNet)才能实现良好的性能。对于作为 dnn 实现的代理策略也是如此,需要来自其环境的数百万个经验样本。减少样本数量是减少训练时间的基础。
  • 概括:在训练期间很少或根本没有样本的区域中,DNNs 的输出不一致。因此,在大而多样化的数据集上训练网络对于在输入空间的大范围内实现低概化误差非常重要。对于 RL 来说,情况要复杂得多:如果一个代理学习做某事(例如驾驶),它应该能够重用调整它的技能,以便当它被要求解决与它被训练的任务相关的任务时“概括它的行为”。元强化学习旨在训练代理人能够快速调整他们的行为以适应新的任务。**
  • 安全:物理媒介(如机器人)在接受训练前后都可能是危险的。在学习时,物理代理与真实环境(如果没有经过模拟训练)进行交互,以学习什么动作是好的。如果这种相互作用没有受到约束,该制剂可能会损坏自身(例如过热、撞击物体、破坏致动器)以及由于随意尝试动作而导致的人身伤害。在学习了最佳行为之后,由于错误的预测(例如,对象的错误分类),代理仍然可能是危险的。因此,有必要对动作实施两种 安全约束 ,以了解执行哪些动作是安全的,并对预测中的不确定性建模,以考虑次优(悲观)行为。****
  • 合规:**智能体在与人类互动时,应该能够根据用户偏好非语言提示法律和社会规范调整自己的行为。****
  • 可解释性:为了理解和调试整个代理决策过程,代理的策略应该可以由人来解释,即,为了输出特定的动作,输入的哪些元素与代理相关。

这五个问题是现代强化学习算法的一般局限性。克服这些限制是在生产系统中实现 RL 的基础。要进一步理解,请参考启发本节的这两篇论文[2]和[3]。

基于对象的表示

面向对象的 RL 依赖于对象及其交互来为给定的任务设计最佳策略。对象和交互形成了任务环境的表示。

在这个上下文中, 对象 是出现在任务环境中的任何相关实体,其特征在于一些属性集。当两个对象 以某种方式交互 时,交互对象之一或两者中的一个或多个属性的值会发生变化,这被称为 效应

将任务的环境表示为一组相互作用的对象可以促进先前知识的重用,并且提供重要的机会来:

  • 一般化:如果一个智能体学会了如何在一个环境中对某些类别的对象做出最佳行为,它可能会将其行为一般化到包含相同类别对象的任何环境中。假设这些对象以相同或相似的方式运行。
  • 更低的样本复杂度:从基于对象的世界表示中学习智能体的行为可以加快学习过程。原因可能是这种表示提供了比原始像素观察(通常在深度 RL 中进行)更多的先验知识,这可以减少无模型方法训练竞争代理所需的样本数量。
  • 可解释:对象和交互很容易被人类理解,因此调试代理的决策过程应该更容易。理想情况下,我们想知道哪些对象会影响代理的决策,所以我们可以想象代理会给我们一种“对象上的注意力向量”,让我们了解哪些对象与其决策更相关。此外,通过监视对象的属性如何随时间变化,应该可以理解代理本身如何影响其他对象。请注意,在像素级推理时,这两种分析都很难执行。
  • 确保安全:安全约束可直接应用于对象。例如,我们可以限制某些对象类的某些属性的值(例如,惩罚汽车类的速度属性)。更重要的是,甚至对象之间的交互也可以被约束。这样,我们可以,理想地,在我们选择的一些对象类中防止非法行为。

因此,对象可以帮助减轻 RL 的一些基本问题,但实际上,在这种方法中,我们需要克服一些重要的问题,以便实现这样的框架。

首先,我们必须检测对象,以便能够对它们进行推理。这应该以一种无人监督的方式来完成,因为我们不想手工设计东西,也不想引入特定问题的先验知识;我们希望使用尽可能广泛适用的无监督对象检测/场景理解方法。**

两个最近的场景理解算法,空间和 SPAIR。[ 来源

其次,我们应该能够预测被检测对象的一些属性,以便出于安全目的最终约束它们。最后,也是更重要的,我们需要一些方法来推断它们之间的相互作用。这是最大的问题,因为不完全清楚如何在没有先验知识的情况下,以无人监督的方式估计这种相互作用。

让我们假设我们能够检测对象、属性并估计交互。我们如何代表他们?还有,我们如何更新它们?嗯,交互可以自然地将对象排列成类似图形的结构。因此,一种可能的方法是将两者都建模为图形神经网络!****

一般来说,图网络有三种更新规则:一种用于节点,一种用于边,另一种用于全局属性集。[ 来源 ]

图形神经网络(或图形网络)由节点(即对象的属性)(即对象对之间的交互)和一组可选的全局属性组成。图网络(GN)将图作为输入,并将图作为输出返回。结果输出图的结构可以不同于输入图的结构。****

GN 非常适合处理基于对象的表示,因为它们可以被构造为图形。因此,GN 可以理想地替代密集的、卷积的或递归的神经网络来表示代理的策略。

基于 OO-RL 的两个有前途的工作,(1)战略面向对象强化学习[8]和(2) COBRA [9],展示了本节讨论的一些思想的有效性。需要进一步的研究来充分利用 RL 方法中的对象。

结论

有很多东西要讨论,甚至有更多的东西要发现!面向对象的 RL 是 RL 的一个相当未开发的子领域,在我看来,它应该得到研究社区更多的关注。此外,无监督计算机视觉方法的进一步改进,如对象检测和场景理解,对于 OO-RL 的成功可能是至关重要的。

理想情况下,OO-RL 有可能帮助减轻现代深层 RL 方法的基本限制。解决这些问题将推动基于 RL 的人工智能应用向大规模采用迈进一步。

希望这篇文章对你来说足够有趣。请评论任何疑问或澄清。这几个字里面有很多概念要解包,所以一开始可能会比较混乱。下次见!

参考资料和进一步阅读

RL 理论

  • 大卫·西尔弗 2015 年在 UCL 的强化学习课程(链接)。
  • Sergey Levine 在加州大学伯克利分校的深度强化学习课程,2019 ( 链接)。

引用论文

[1]迪尤克,c .,科恩,a .,&利特曼,M. L. (2008 年 7 月)。有效强化学习的面向对象表示。

[2] McAllister,Rowan 等人,“自动驾驶汽车安全的具体问题:贝叶斯深度学习的优势。”2017 年国际人工智能联合会议。

[3] Dulac-Arnold、Gabriel、Daniel Mankowitz 和 Todd Hester。“现实世界强化学习的挑战。” arXiv 预印本 arXiv:1904.12901 (2019)。

[4] Keramati,Ramtin,等人,“面向战略对象的强化学习” arXiv 预印本 arXiv:1806.00175 (2018)。

[5] Watters,Nicholas 等,“Cobra:通过无监督的对象发现和好奇心驱动的探索,基于数据高效模型的 rl。” arXiv 预印本 arXiv:1905.09275 (2019)。

元学习、图形网络等。

  • 芬恩,切尔西,彼得·阿贝耳和谢尔盖·莱文。“用于深度网络快速适应的模型不可知元学习。”第 34 届机器学习国际会议论文集——第 70 卷。JMLR。org,2017。**
  • 强化学习的无监督元学习。 arXiv 预印本 arXiv:1806.04640 (2018)。
  • 彼得·w·巴塔格利亚等人,《关系归纳偏差、深度学习和图形网络》 arXiv 预印本 arXiv:1806.01261 (2018)。
  • 林,等,〈空间:经由空间注意与分解的无监督物件导向场景表现〉arXiv 预印本 arXiv:2001.02407 (2020)。

SPOT 机器人系统的目标识别和空间感知

原文:https://towardsdatascience.com/object-recognition-and-spacial-awareness-for-a-spot-robotics-system-2ba33152bf65?source=collection_archive---------47-----------------------

荷兰 TNO 研究机构的 SPOT 机器人。经许可使用。

本月早些时候,TNO 的首席科学家 Joris Sijs 加入了我们对 T2 Grakn 轨道 T3 的第二系列研究。

TNO 是荷兰的国家研究协会,乔里斯和他的团队希望在这里结合机器人和人工智能。

大约两年前,他们开始与 Grakn 合作。到那时为止,还没有一个适合机器人学的数据库能够准确地代表真实世界。这在需要在真实世界环境中执行任务和做出决策的自治系统中是必不可少的。机器人项目经常在精心策划的环境中运行,在 TNO 的案例中,他们希望尽可能接近真实世界的场景。

搜索和救援——雪计划

TNO 正在进行的项目叫做 SNOW,专注于自主系统。该团队将自主系统定义为机器人技术与人工智能的结合。

在实践中,这意味着机器人被赋予了更多的自主权,从用户的角度来看,人类的干预更少。这使得机器人能够在更复杂的环境中工作。

雪计划目标。经许可使用的幻灯片

传统上,在机器人领域,你会有远程控制系统。然而,对于雪,TNO 正试图尽可能减少人为干预,尤其是当环境的复杂性增加时。

从事 SNOW 项目的团队由 15 名科学家组成,主要关注 3 个挑战:

情境意识——机器人知道它在哪里操作吗

自我意识——在给定的环境下,机器人此时能做什么

情景规划——基于机器人所知道的,它应该如何完成任务

TNO 为这个项目选择的用例是半真实的。通常,他们的客户只会要求一个狭窄的人工智能任务来探索。然而,通过创建他们自己的案例,他们能够测试全套的技术情况并集成所有的技术解决方案。

SPOT 将在什么样的环境和情况下运营?

雪地项目设置。经许可使用的幻灯片

TNO 使用的是一栋内部别墅,由四个房间、一个大厅和一个门廊组成。现场有四名受害者和一名消防员。斯波特被派去获取关于遇难者下落的准确信息,以及对搜救有用的任何其他信息。

这个机器人来自波士顿动力公司,然后被送进别墅去寻找或定位受害者。

然后,SPOT 被赋予一系列目标:

  • 找到家庭成员
  • 对他们进行医学评估

例如,机器人可能会报告女儿在去厨房的走廊上,并且她有反应。接下来的行动、将是继续搜寻其他受害者

过了一段时间,机器人报告说它在客厅的椅子旁边找到了父亲,但没有反应。在这种情况下,动作原地不动,为救援队制造噪音。

SPOT 在现实环境中运行时面临一些挑战:

  • 斑点不应该被玩具狗弄糊涂——它应该区分真正的狗和玩具
  • SPOT 应该评估什么时候情况太危险——根据房间里的条件,搜索和定位能力是如何减弱的
  • SPOT 应该能够根据受害者的情况或其他变量,如位置或危险的接近程度等,权衡救援对象。

斯诺的机器人系统

SPOT 是如何观察和收集数据的——雪地里用的是什么硬件?

  • PTZ 摄像机—安装在聚光灯顶部的全景倾斜变焦摄像机
  • 用于语音交互的语音阵列和扬声器

这些组件安装在迷你电脑的顶部。这种迷你电脑拥有强大的计算能力,因为大部分计算都是在设备本身上完成的,以确保机器人尽可能多的自主权。

TNO 的典型机器人系统是什么样的?

例如 TNO 机器人系统。经许可使用的幻灯片

首先,从 PTZ 摄像机中捕捉到一幅图像,然后将它传送到图像识别模块,该模块用于进行一些房间特征描述,这样机器人就可以在房间内确定自己的位置。

关联模块从摄像机获取所有检测,并将它们关联起来,以便它们可以创建更好的轨迹,而不是单独的检测。

Grakn 被用作数据库,以协调他们系统中的所有数据和知识。

传统上,在机器人学中,ROS 和 Python 用于实现系统中模块之间的通信。如果你用 Python 创建一个模块或软件组件,ROS 会在 Python 代码中添加另一层,以便与系统的其他部分进行通信。

因此,他们还需要为 Grakn 创建一个专用的 ROS 客户端,并使用原生 Python 客户端。

Joris 注意到他们的数据库虽然相对较小,但在处理管理负担和向数据库中添加新知识方面非常动态。

Grakn ROS 客户端

什么是 ROS ?ROS 在这个过程中扮演了什么角色?

ROS 客户端。经许可使用的幻灯片

ROS(机器人状态发布器)是一种发布/订阅机制。设置包括:摄像机、图像识别、关联层、规划器和控制器。ROS 便于将输入的数据合并到数据库中。让我们来看看这个识别狗的例子:

  • PTZ 照相机发布了一幅图像
  • Grakn 客户端订阅图像,以便将其反馈给数据库
  • 图像然后被传递到识别模块
  • 检测到一只狗
  • 然后狗被发布在 ROS 总线上
  • Grakn 客户机再次订阅这个输出(dog ),以便将它发送并写回数据库
  • 同样的情况也发生在关联模块中,狗的速度和位置被写入数据库
  • 那么计划者可能需要一些信息
  • Grakn 客户端也将订阅来自规划器(对象速度)的这些请求,反之亦然

您如何着手构建 ROS Grakn 客户端?

着手构建这个 ROS 客户端的团队将它分成了两部分:ROS 包装器和 Grakn 客户端会话。

构建一个 ROS 客户端。经许可使用的幻灯片

ROS 包装器处理发布/订阅机制, Grakn 客户端会话作为抽象层构建在 Grakn 客户端之上。

各有什么要求?

  • ROS 包装器初始化客户端和要发布或订阅的主题。
  • Grakn 客户端应该自动启动 Grakn 并删除任何现有的密钥空间。删除键空间是必要的,因为在机器人学中,我们希望从一个空的键空间开始。我们希望有一个新的场景来描述机器人所处的动态变化的环境。
  • Grakn 客户端会话还应该加载已知的模式和实例。

过一会儿,当事情可能已经运行了一段时间时,新的 ROS 消息进来(例如,对 object_velocity 的请求)。

在这里,他们使用基于 Grakn Python 客户端的 Grakn 实用程序。

Joris 和他的团队目前正在寻找一个可以自动生成查询的工具。这被记为未来的工作。

经许可使用的幻灯片

这张幻灯片向我们展示了 read 函数在幕后的样子。函数request_all_humans获取数据库中已知的所有人类。他们使用 Grakn 实用程序从数据库中读取查询。

然后数据被检索,并以一种良好的格式提供给 ROS 包装器,由它作为 ROS 主题再次发布。

这是一个创建起来相当简单的函数。然而,当我们考虑为机器人观察添加额外的变量时,情况变得有点复杂。

在我们到达那里之前,让我们看一下他们的模式——Joris 在下面的幻灯片中以模式图的形式浏览了其中的一部分。

架构图的部分。经许可使用的幻灯片

这里我们看到他们定义了一个living_being,它是一个human或者一个animal的父实体。这两个实体是:adultchild的父实体;还有dogcat

SPOT 需要报告living_being s 的状态,包括physical状态和mental状态。具体来说,SPOT 的任务是识别已识别的living_beingmental-responsiveness

让我们看看他们是如何在这个模式片段中建模关系的。

define
## relation 1: mental responsiveness of a discovered (by SPOT) living-being ##
well-being sub relation,
	relates health,
	relates being;
mental-responsiveness sub attribute,
	plays health;
living-being sub entity,
	plays being;

## relation 2: family of living-beings ##
family sub relation,
	relates father,
	relates mother,
	relates son,
	relates daughter,
	relates pet; 
human sub living-being;
adult sub human;
child sub human;
man sub adult,
	plays father;
woman sub adult,
	plays mother;
boy sub child,
	plays son;
girl sub child,
	plays daughter;
animal sub living-being,
	plays pet;

参考上面幻灯片的下半部分,我们还可以看到该模型的一个实例。

首先,他们用truefalse实例化mental概念。他们有一些人和一只狗,毛毛。注意,在这个例子中有两个成年人,man(名字是 Sam)和man(名字是 George)。山姆是消防员,乔治是一家之主。

我们可以看到,萨姆是精神上有反应的,而乔治不是精神上有反应的。我们如何在代码中创造心理反应?

假设母亲在精神上有反应:

经许可使用的幻灯片

在这里,您可以看到代码增长很快,以及希望探索自动查询生成的原因。

小但有活力

还记得我们说过数据库很小但却是动态的吗?在这里,我们将看到 SPOT 在现实世界中的运行情况。

把场景设在现实世界中,我们有一个家庭,一个消防队,一个有一个大厅和一组房间的房子。

这差不多是 SNOW 项目的完整模式图。

完整的架构图。经许可使用的幻灯片

您可以看到绿色的所有关系和深蓝色的所有属性。所有的概念或实体都是淡蓝色的,并被组织成一个类型层次结构。

乍一看,它没有看起来那么大或复杂,但正如 Joris 继续描述的那样,一旦机器人在一个房间里,复杂性就会迅速增长,因为机器人需要确定自己的方向。

他们能够通过在数据库中表示多边形来对此建模。

看下面的幻灯片,我们看到厨房、厨房门和四面墙被映射为多边形的点和边。

多边形是一个数学概念,可以用来描述房间的边界,比如厨房。写为多边形,你有一组点和边或线。这些边缘对应于墙壁或厨房门。

多边形由直线构成,直线由两点定义。如果您将此多边形建模为 Grakn,则该多边形与一组线相关,每条线与两个点和一个结构部分相关。

在 Grakn 中为空间感知建模多边形。经许可使用的幻灯片。

在 Grakn 中对此建模,我们得到实体:mathematical-conceptpolygonline s、point s,以及实体point的两个子类型:local-originglobal-origin

这些线条也可以采取某种物理形式,如结构部件:墙或门。

为什么知道这些有用的信息?

如果斑点在厨房里,它应该能够在那个房间里定位自己。

如果它在厨房,需要通过厨房门离开房间,它必须知道厨房门的位置。使用激光雷达系统,SPOT 能够测量到墙壁的距离,从而将阵列映射到多边形。接下来,它应该通过检索门的端点来定位门。最后,向门口走去,它会找到一个出口。

这样,如果你根据平面布置图使用机器人和真实环境,使用多边形是很方便的。

推理如何从一个房间移动到另一个房间

我们看到了乔里斯如何模拟一个特定的房间,以便点点在里面移动;但是在整栋楼里移动呢?我们应该如何建立一个建筑模型,使得斑点可以在房间和大厅之间自由移动?

首先,Joris 需要在模式中对建筑物的组成进行建模——我们可以看到他的图表在 Graql 中的样子:

define
building sub entity,
plays composition; 

office-building sub building;
res-house sub building;	
space sub entity,
	plays partition;	
open-space sub space;
closed-space sub space;
real-estate sub closed-space,
	plays composition;
room sub real-estate;
	composing sub relation,
	relates composition,
	relates partition;
structural-part sub entity,
	plays partition;
window sub structural-part;
wall sub structural-part;
door sub structural-part;

这意味着当我们有一个res-house的实例时,比如这个例子中的别墅,它由房间组成:kitchen hall living。这些房间由structural-part s: kitchen-wallkitchen-doorhall-wallliving-wallliving-door组成。

正如 Joris 解释的那样,我们可以利用 Grakn 的超图和基于规则的推理,根据通常关联的structural-parts来创建房间连接(关系)。

如果我们知道kitchen-door是与房间kitchen以及房间living有关系的角色扮演者(上图中的c#2);然后我们可以通过kitchen-door推断出房间kitchenliving之间的关系。

这让 SPOT 知道它可以通过厨房门从厨房移动到大厅。正如你自己可能推断的那样,我们可以通过kitchen-doorliving-door在房间:kitchenliving之间建立联系。这是 Grakn 中传递关系的一个例子。

传统上,机器人团队可能会使用 SLAM 或其他导航技术来实现这种穿越空间的机动性。在 Grakn 中,这变得相当简单。

您可以在 Grakn work base(Grakn 的 IDE)中看到这种情况:

模拟否定

当机器人进入建筑物时,我们如何处理点点还不知道living-being在哪里的事实?我们如何在数据库中模拟这种知识的缺乏?

在 Grakn 中,我们使用一个带有两个子关系的locating关系:possibly-locatingnot-possibly-locatingactually-locating。这些让我们能够解决负面问题;一旦搜索到一个空间,在数据库中捕获一个living_being不在该房间中。我们不需要现场复查房间和浪费宝贵的时间。这需要在主动搜索期间频繁更新数据库。

向数据库中添加新知识怎么样?

在真实世界的场景中,在积极的搜索和救援过程中会出现新的事实。想象一下,一名消防指挥官发现其中一间卧室有一台弹球机,这些数据目前可能不在数据库中。

您应该更新基础知识,而不是将这些新知识作为实例添加到数据库中。您希望将这一点添加到模式中,以便可以对知识进行推理并用于帮助 SPOT 实现其目标。

Joris 指出,这种情况可能会定期发生。以一种合适的、自动化的方式来做这件事是很重要的。Grakn 的动态模式——能够在任何时候更新,而不需要进行任何迁移——使这变得非常简单。

摘要

对我来说,机器人技术非常酷。还有,知识图比较热。所以综合这些,在我看来,让我发烧。你可以在这里看到我的一些发烧症状。

只是一些额外的“狂热”打动了乔里斯和他的团队。

在结束讲话时,Joris 谈到了他对使用知识图上的机器学习来通过对象识别定位自己的兴趣。例如,如果我们认识到两个物体:一个烤箱和一个水槽,我们应该能够知道我们在厨房里。

Joris 和他的团队目前正在与 Grakn 实验室的首席科学家 James Fletcher 合作,该项目利用了他对知识图卷积网络(KGCN)的研究。

特别感谢 Joris 和他在 TNO 的团队,感谢他们的热情、启发和透彻的解释。

你可以在 Grakn Labs YouTube 频道点击找到完整的演示文稿。

软件风险和人工智能的未来

原文:https://towardsdatascience.com/observation-on-software-risks-and-artificial-intelligence-future-473a1bd55fb9?source=collection_archive---------47-----------------------

在机器学习时代,我们应该害怕什么,不应该害怕什么

人类一直生活在有史以来最受机器支配的时代。在大多数人注意到这一点之前,他们已经将世俗的决定留给了网飞推荐、特斯拉自动驾驶仪或《纽约时报》上的机器人撰写的评论,通常没有考虑到这些由人类编码的机器也可能容易出现意想不到的结果,如审查或假新闻。虽然不可否认的是,许多行业的机器智能改善了大多数人的生活质量,但越来越多的与数据隐私和人工智能有关的新闻,例如剑桥分析公司丑闻,或参与地区战争的杀手无人机,都给公众带来了一些担忧。让我们承认:作为整个人类物种,我们偶尔会失去对信息和算法的控制。然而,当公众人物谈论人工智能时,绝大多数人只是谈论它的前景,这让一些人对人类过度依赖机器决策感到紧张。这些担心是可以理解的:人们害怕他们不确定的事情,甚至专家也不知道人工智能研究最终将走向何方。在这些恐惧中,哪些是合理的,哪些显然是不必要的?

恐惧是真实的吗?

如果我们列举新闻和科幻电影中人们出现的有害的人工智能应用,杀手无人机和人工智能战斗机器人通常位于列表的首位。人们担心这些实体会超出发明者的控制,从而危及人类。虽然不幸的是,美国军方已经在任务中使用杀手无人机,但仍然足以说,人工智能杀手机器人将在几十年内仍然是一个幻想。谷歌大脑集团前总裁吴恩达表示,自 20 世纪 50 年代以来,人类一再遭受对人工智能的过度期望,即使在人工智能掌握围棋和星际争霸 2 之后,当前的研究仍然远远没有产生一个可以征服人类的全能人工智能。

在解决更多的恐惧之前,有必要知道现在的人工智能能够做什么。假设我们将一个人工智能定义为如果它的表现可以与人类相媲美。2016 年和 2019 年,AlphaGo 和 AlphaStar 的胜利表明,人工智能能够"在合理的步骤数内做出好的决定,即使在没有完整信息的情况下。(如传统象棋 AI 一步考虑 1000000 步,而 AlphaZero 考虑 10000 步)。在过去的十年里,计算机也变得非常擅长合成逼真的图像、玩策略游戏和辅助诊断。

来源:DeepMind 官方在 AlphaZero 上的博文。

也就是说,其他一些恐惧是有根据的吗?在我看来,是的,但是认识到 AI 还不能做的事情也同样重要。当前的人工智能无法 概括任务 ,这意味着它无法将其训练的模型概括为新的但类似的任务,例如,识别猫的模型在识别狗时表现不佳。《麻省理工技术评论》称,“机器学习系统可能会被它们以前从未见过的情况搞糊涂”。

艾也患 辨因果 。无法“推断”的结果来自于人工智能算法对相关性而不是因果关系的狭隘关注。“这就好像你知道云更有可能下雨,但你不知道云会下雨,”哥伦比亚大学的研究员 Elias Bareinboim 说。当人工智能必须回答“如果……会怎样”的问题时,这种无知是至关重要的。比如一个病人在临床试验中死亡;是实验医学的错还是别的什么?这样的推理远远超出了目前人工智能的熟练程度。虽然研究人员已经提供了可能的解决方案,如因果贝叶斯网络-一种可以检测哪些变量对其他变量影响最大的架构,但这种方法仍然没有在人工智能领域取得多少进展。

短期恐惧:算法偏差

当机器被用来确定公平性时,识别因果关系的不恰当可能是有问题的,这导致了对当前人工智能的似是而非的担忧——算法偏差。这种争议出现在 2016 年,当时司法辅助系统 COMPAS 被指控对黑人被告有偏见。新闻调查集团 ProPublica 声称,就累犯率而言,“在最终没有再犯的被告中,黑人被归类为中等或高风险的可能性是白人的两倍多”。

要理解这场争论,人们必须仔细思考一个系统的“公平”意味着什么?请记住,COMPAS 基于 100 多个因素来分配分数,包括年龄、性别、犯罪史,特别是种族“不”包括在内。《华盛顿邮报》重新分析了 ProPublica 收集的被告 COMPAS 评分数据,发现了以下情况:

  • 在每个风险类别中,无论种族如何,重新犯罪的被告比例大致相同。这是发明者对公平的定义。
  • 黑人被告的总体累犯率高于白人(52%比 39%)。

然而,这两个特征导致以下两个观察结果:

  • 黑人被告更有可能被归类为中等或高风险(58%对 33%)
  • 最终“没有”再次犯罪的黑人被告被预测比没有再次犯罪的白人被告更危险。这是 ProPublica 对算法的批评。

这里的一个重要认识是:

双方对公平的定义是互斥的,因此结果的差异在数学上是有保证的。

请记住,虽然系统不考虑个人决策的种族,但“训练数据”确实包括一个全面的特征列表,其中可能包括种族。因此,很可能是输入系统的真实数据导致了系统偏差。我们应该简单地接受这个不幸的结果吗?这可能不是大多数人想听到的答案。然而,如果我们手动调整算法,有条件地降低对黑人的风险预测,根据发明者的定义,我们也对白人被告有偏见。

算法偏见的另一个例子如下:美国政府的测试发现,2019 年,即使是性能最高的面部识别系统对黑人的错误识别率也比白人高 5 至 10 倍。反复出现的有问题的机器决策留下了一个尚未解决的问题:这种道德困境对于机器决策来说是不可避免的吗?鉴于算法有可能提高后续决策的有效性,我认为公平性应该是人们在不久的将来应该应对的重要恐惧之一。

机器知道公平问题吗?图像来源

长期恐惧:所有人工智能都是有益的吗

从 2015 年开始,特斯拉首席执行官埃隆·马斯克(Elon Musk)一直在敦促美国对所有高级人工智能研究进行监管。“人工智能比核武器更危险,”马斯克解释道。“狭隘的人工智能将导致混乱、失业和更好的武器,但这不是我所说的物种层面的风险。”不管拟议的法规是否可行,马斯克的言论让人工智能乐观主义社会陷入混乱,特别是当马克·扎克伯格和谷歌人工智能首席执行官约翰·詹南德雷亚以及许多研究人员公开反驳他的说法时。

不过,对话特别有意思。想想这个:埃隆·马斯克绝不是技术悲观主义者。他敢于冒险,将他所有的 1.8 亿 PayPal 收入投资到 SpaceX、特斯拉和太阳能城市。他还负责人类历史上第一个“可重复使用的火箭”项目。马斯克在这里关注的不是 Siri 等公司人工智能,而是人工通用智能——一些前所未有的、有意识的超级智能实体。虽然我之前对这些“人工智能启示录”的说法表示了怀疑,但马斯克的回答提出了一个“人类控制机器”的关键问题。

加州大学伯克利分校教授斯图尔特·拉塞尔(Stuart Russell)是有史以来最有影响力的人工智能研究人员之一,他曾表示,他认为一个有益的人工智能必须“可证明地符合”人类价值观,当我们谈论“一般智能”时,最终的问题是我们是否能控制人工智能的决定,而不是它能做什么。

失控恐惧实际上是理性的。从历史上来说,艾伦·图灵发明的计算机时代仅仅是 70 年前,但我们已经看到机器从努力解决井字游戏发展到在棋盘游戏上超越人类知识,只需 30 个小时的训练,甚至可以解决生物医学研究中人类无法克服的障碍。从技术角度来看,强化学习模型对环境变量的敏锐度和即时生成训练数据的能力比新生儿强得多。一个实体如此快的学习速度,无疑是人类在发明之前无法理解的。因此,推测机器智能将在一个世纪或更短的时间内超越人类是公平的。但是,我们准备好了吗?

不确定性有利于机器决策

有时,人们害怕深入谈论人工智能的阴暗面,因为我们几个世纪以来一直信奉的科学实践并不是为有益的技术追求而设计的:在统计学和机器学习中,你会最小化外部指定的损失函数;在运筹学中,你最大化一个奖励函数。在许多学科中, 我们构思问题的方式是基于这些任意选定的方向来解释自然界中某个特定的、可以说是歪斜的镜头 。“这是一个错误的问题,”斯图尔特·罗素在 2019 年接受采访时说。

“我们需要机器具有不确定性,也就是说对人类的任务持合理的怀疑态度,这样在它朝着指定的方向起飞后,我们就不会失去对它的控制。”他补充道,“机器永远不应该把输入目标当成真理。”的确,现代人工智能训练方法包括人类指定一个固定的目标,而这个目标实际上可能是错误的。有时这些目标存在于我们内心,但我们要么不知道如何解释它,要么不知道我们想要什么样的未来。如果一个人工智能盲目地追求最小化一个数字,而没有考虑到它的目标,数值最优,在人类逻辑中可能没有意义,结果可能会彻底脱轨。

我们需要机器具有不确定性,这样在它按照指定的方向起飞后,我们才不会失去对它的控制。

这一愿景也许是理想的。如果我们真的希望我们的机器是不确定的,所有传统的决策过程,如马尔可夫决策,标准博弈树搜索,都变得不适用。此外,这产生了一个更复杂的问题,因为人的交互现在是机器决策问题的一部分。就金钱主宰一切因素的行业而言,这种人性化的考量往往超出了任何企业愿意投入的成本。

结束思绪

为了确保一个有益的人工智能未来,需要在实验中保持耐心,并大胆挑战一些旧的科学方法。甚至一些专家关于有益的人工智能的说法也仍然模糊不清:例如,如果人类的价值观不断进化,人工智能如何才能“可证明地与价值观保持一致”?然而,我的观点认为,只有考虑到人工智能在未来十年能做什么和不能做什么,对人工智能的恐惧才是合理的。“具有不确定性的人工智能”的说法目前似乎难以置信,但随着我们在使我们的机器智能更“意识到”人类价值方面取得进展,如因果关系,更多的线索可能会被揭示,或许将人类互动纳入决策的人工智能将不再是幻想。

参考

  1. " IBM 研究员:对人工智能的担忧被夸大了."时间2016 年 3 月 12 日https://Time . com/4281476/IBM-人工智能-沃森-2016/
  2. "埃隆·马斯克表示,所有先进的人工智能开发都应该受到监管,包括特斯拉."TechCrunch2020 年 2 月 18 日https://TechCrunch . com/2020/02/18/elon-musk-says-all-advanced-ai-development-should-be-regulated-including-at-Tesla/
  3. “这位人工智能先驱有一些担忧”, Wired,2015 年 5 月 23 日,https://www . Wired . com/2015/05/Artificial-Intelligence-Pioneer-Concerns/
  4. “AlphaZero:为象棋、松木和围棋带来新的启示”, DeepMind ,2018 年 12 月 96 日,https://deep mind . com/blog/article/alpha zero-Shedding-new-light-grand-games-chess-shogi-and-Go
  5. “Stuart Russell:超级智能 AI | AI 播客剪辑的控制问题”,2019 年 10 月 13 日,https://youtu.be/bHPeGhbSVpw
  6. 萨姆·科比特-戴维斯、艾玛·皮尔森、阿维·费勒和沙拉德·戈埃尔。一个用于保释和判决的电脑程序被贴上了对黑人有偏见的标签。其实也没那么清楚。”、《华盛顿邮报》、2016 年 10 月 17 日、https://www . Washington Post . com/news/monkey-cage/WP/2016/10/17/can-an-algorithm-be-racistic-our-analysis-is-more-谨慎于 propublicas/#评论
  7. 布莱恩·伯格斯坦,“人工智能还不能做什么”,麻省理工科技评论,2020 年 2 月 19 日,https://www . Technology Review . com/s/615189/What-AI-still-cant-do/
  8. “最好的算法努力平等地识别黑人面孔”,2019 年 7 月 22 日,https://www . wired . com/story/Best-Algorithms-fight-Recognize-Black-Faces-Equally/
  9. 凯瑟琳·克利福德,“埃隆·马斯克:‘记住我的话——人工智能远比核武器更危险’”,2018 年 3 月 13 日,美国消费者新闻与商业频道https://www . CNBC . com/2018/03/13/Elon-Musk-at-sxsw-a-I-is-more-dangerous-than-nuclear-weapons . html

获取和分析 Fitbit 睡眠分数

原文:https://towardsdatascience.com/obtaining-and-analysing-fitbit-sleep-scores-d2715aebd18e?source=collection_archive---------62-----------------------

凯利·西克玛在 Unsplash 上的照片

如何获取和分析 Fitbit 睡眠评分

乔纳斯·班纳 — 9 分钟阅读

智能手表和其他可穿戴设备在过去几年里越来越受欢迎,并催生了“量化自我”的文化现象。Apple Watch 或 Fitbit 等设备让任何人都有可能轻松地自我跟踪,从而以某种方式量化他们的生活。

图片由来自 Pixabay 的洛伦佐·卡法罗提供

估计收入增长的贝叶斯方法

通过 Vinai Oddiraju — 14 分钟读取

也许你是一个投资者,正试图决定一只股票是否值得投资。也许你最近才听说贝叶斯推理,并想了解它在现实世界中的应用。也许您是一位经验丰富的分析师,偶然发现了这篇文章,并觉得标题很有趣。

作者图片[Marc Kelechava]

使用 Librosa 的城市声音分类—复杂的交叉验证

Marc Kelechava — 13 分钟阅读

我将展示一个实现一篇有趣的研究论文的结果的例子,该论文基于音频片段的声音内容对它们进行分类。这将包括 librosa 库的应用,librosa 库是一个用于音乐和音频分析的 Python 包。

MachineRay 的输出示例

MachineRay:利用人工智能创造抽象艺术

罗伯特·a·贡萨尔维斯 — 12 分钟阅读

在过去的三个月里,我一直在探索人工智能(AI)和机器学习(ML)领域的最新技术来创作抽象艺术,在我的调查过程中,我了解到创作抽象绘画需要三样东西:(A)源图像,(B)ML 模型,以及 C 在高端 GPU 上训练模型的大量时间。在我讨论我的工作之前,让我们先来看看一些先前的研究。

我们的每日精选将于周一回归!如果你想在周五收到我们的 每周文摘 ,很简单!跟随 我们的出版物 ,然后进入你的设置,打开“接收信件”您可以在此 了解有关如何充分利用数据科学 的更多信息。

Swift 编程语言中类和结构之间的(明显)相似性

原文:https://towardsdatascience.com/obvious-similarities-between-classes-and-structures-in-swift-7a9c4ba2c994?source=collection_archive---------75-----------------------

技术的

在 Swift 编程语言中,结构和类是不同的对象类型,但它们确实有一些相似之处。本文探讨了其中的一些相似之处。

克里斯托夫·高尔在 Unsplash 上拍摄的照片

介绍

本文旨在展示 Swift 编程语言中两种不同的对象类型——类和结构之间的相似性。

您不需要具备丰富的 Swift 使用经验就能理解本文中的示例和相似之处。

本文中的内容可用作 Swift 中的类和结构对象的复习或介绍。

但是为什么还要麻烦斯威夫特呢?

Swift 是一种通用的编程语言,用于 iOS 应用程序开发和机器学习等任务。它可能是一种需要掌握的自然语言,尤其是对于那些有 C 或 Python 等语言经验的开发人员来说。

下面是一些相似之处的快速总结,然后是深入的探索。

1.创造

在 Swift 中创建结构或类别的过程几乎完全相同。

对于结构的定义,您只需键入'struct '(Swift 中识别的关键字语法),然后是所需的结构名称,最后是相应的左花括号和右花括号。

struct NewCustomStructure {
  // Properties, methods...
}

类遵循与结构相似的定义模式。只需输入可识别的关键字' class' ,然后输入所需的类名,最后输入花括号。

class NewCustomClass {
  // Properties, methods...
}

结构和类命名通常遵循相同的命名模式,即upper case模式(每个新单词的第一个字母大写)。

2.例子

熟悉面向对象编程语言(如 Java、Python 或 JavaScript)的有经验的程序员将熟悉创建类实例的概念。

对于那些不是这样的人来说,创建类的实例可以被描述为将类视为蓝图,而类的实例是从蓝图(类)构建的对象。

在 Swift 中,您可以创建一个类实例,也可以创建一个结构实例。

类/结构实例的创建遵循类似的模式。我们将创建先前创建的结构' NewCustomStructure' 和类' NewCustomClass' 的新实例。

将创建结构实例,如下所示:

let structureInstance = NewCustomStructure()

和类实例的创建如下所示:

let classInstance = NewCustomClass()

3.创建、定义和访问类属性

类和结构都可以定义属性。

属性可以被认为是可区分的数据容器/占位符,它们与创建它们的类或结构直接相关。变量和常量是类和结构的属性。

当一个类或结构的实例被创建时,我们可以在它们的属性中定义数据。

属性在类和结构中以相同的方式创建。

为了说明我们如何在类和结构中创建、定义和访问属性,我们将使用结构来定义房子,使用类来定义人。

struct House {
  var noOfDoors: Int
  var noOfWindows: Int
  let noOfRooms: Int
  let noOfFloors = 2
}

上面是一个结构定义,它代表了一个具有一些在实际住宅中可以找到的明显属性的房子。

下面的代码片段显示了 house 结构的一个实例,该实例是用该实例的预期属性值创建和初始化的。

let smallHouse = House(noOfDoors:2, noOfWindows:3, noOfRooms: 6)
print(smallHouse)>> House(noOfDoors: 2, noOfWindows: 3, noOfRooms: 6, noOfFloors: 2)

可以使用点标记法访问 struct 实例的已定义属性。

print(smallHouse.noOfDoors)
print(smallHouse.noOfWindows)
print(smallHouse.noOfRooms)

为了说明类中的属性是以类似于结构的方法来访问的,我们将创建一个类并使用点符号来访问它的属性。

class Person {
    var firstName: String
    var lastName: String
    var age: Intinit(firstName:String, lastName:String, age:Int) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
    }
}let kindPerson = Person(firstName: "James", lastName: "John", age:23)print(kindPerson.firstName)
print(kindPerson.lastName)
print(kindPerson.age)

这篇短文介绍了这两种对象类型、类和结构之间的主要相似之处。

我还介绍了这两种对象类型之间的区别。有关主要差异的信息可通过下面的链接获得。

[## Swift 中类别和结构之间的差异

虽然类和结构有一些明显的相似之处,但本文列出了结构之间的差异…

medium.com。](https://medium.com/swlh/differences-between-classes-and-structures-in-swift-ab2e27956665)

光学字符识别和文字搜索求解人工智能

原文:https://towardsdatascience.com/ocr-and-the-wordsearch-solver-ai-515aeb816bdf?source=collection_archive---------22-----------------------

实践教程

使用自定义 OCR 模型、Pytesseract 和数组操作来自动解决单词搜索

作者原创。单词搜索解决程序在运行

介绍

最近看到很多关于数独求解器的帖子。它的算法非常简单,通常是一个回溯递归算法,只有几行 Python 代码。我最喜欢的视频来自计算机爱好者和 Thorsten Altenkirch 教授,我可以看他一整天。如果使用计算机视觉方法,你只需要一个已经在 MNIST 上训练过的简单模型,或者类似的东西。解释所有步骤的非常棒的视频可以在这里找到。

那么,这给我们留下了文字搜索。嗯,我已经厌倦了看到数独解谜的多种版本和视频。所以我想看看是否有人做过文字搜索解决方案。令我惊讶的是,并没有我想要的东西。现在,这并不是说人们没有这样做,但我觉得这将是一个很好的实践项目,所以决定不深入研究,因为我想自己解决这个问题。为此我使用了 WordSearch.com 的

完成这个项目后,我偶然发现了马丁查尔斯的一个不错的帖子,这是我见过的大多数需要手工输入文本的地方的典型。

这是一个很好的项目,因为它涉及以下主题:

*定制 OCR —在处理少量不平衡数据时进行培训(包括获取图像),测试,部署
*图像处理—查找网格等。
*寻路——大脑。这让我走上了一条漫长而有趣的道路,尽管我最终坚持使用我最初的简单解决方案
*自动控制——让计算机解决这个难题

为了简洁起见,我将不再讨论 OCR、路径寻找和自动控制。毕竟,找到网格很容易,Sodoku 解算器中使用的相同条件也可以使用,Sodoku 解算器有很多。这是图像处理的结果,它找到了网格框(红色轮廓)、单词框(黄色轮廓)和绿色轮廓的每个字母边框。

图像处理后的结果,显示网格、字符和单词搜索边界框的轮廓

眼睛

源图像

在训练我自己的模型之前,第一个选择是使用 Pytesseract。然而,不幸的是,即使在裁剪了网格之后,也没有立即找到可用的字母。如果我改为裁剪每个字母,它仍然不是超级准确,而且非常慢。但是,我确实使用 Pytesseract 通过传递单词框(上面用黄色标出)来获取要搜索的单词。这给我留下了一个相对简单的任务,即进行单个字母的 OCR。

我首先通过收集单个字母的图像来创建数据集,并手动创建我的数据集。我使用了一个简单的脚本来收集每个字母包围盒,显示在屏幕上,并输入一个字母来标记我的训练数据。因为我使用了特定的字体和从截图中获得的图像,所以我可以用少量的训练数据就可以了。然而,这是令人难以置信的不平衡。在浏览了大约 5 个格子,也就是大约 1000 个字母之后,我只看到了大约 3 个 Q,3 个 Z,3 个 F,以及令人惊讶的其他一些少量的字母。另一方面,我有相当多的 a,e,o 等。以至于我开始跳过它们。

词搜索中字母的训练数据分布

为了解决这个问题,在应用数据扩充时,我使用了一个平衡的数据生成器,这样每个字母就总是有相同数量的例子。这使用了 imblearn 来生成随机过采样器,并结合 Tensorflow Keras 中的增强。这是我从另一个中帖这里找到的。这意味着,将对 Q/N 应用更多的增量,以平衡数据。这些扩充很简单;轻微的旋转,移动,缩放,最终获得了高精度的验证数据,基本上完美的测试数据,这是每一个新的搜索。当然,这只在我的电脑上测试过。但目前它确实有用。

来自生成器的示例扩充和训练数据

对于模型本身,我只使用了一个简单的 LeNet 架构。这被证明是准确和充分的,所以嘿,不要修复没有坏的东西。在我的 GTX 1060 GPU 上,这并不是实时快速的,它花了大约 10 秒钟来分类所有 196 个字母。我不确定瓶颈是什么;如果是图像处理得到每个字母或分类本身。我确实对经典的 28x28 图像进行了尺寸调整。我也许可以用一个小一点的图像,也许会更快。我不太关心时间,但如果你想把它作为一个实时应用程序,这可能是一个考虑因素。这是一个最终的结果,显示了使用 OpenCV 的字母边界框和作为字符串写在图像上的代表字母。

对单词搜索网格中的每个字母进行分类的结果

然后,网格被表示为 2D 数字字母数组,就像您自己输入一样。此外,要查找的每个单词都被保存为一个列表。现在我们知道要找什么了,我们只需要找到它。

大脑

源图像

正如我提到的,这让我走上了一条有趣的研究道路,我可能在这里学到了最多。我开始使用网络来查找每个单词的第一个和最后一个字母的起点和终点。然后,我将这些结果解析成有效的移动(向上/向下、对角线、水平)。然而,当我进行全尺寸测试时,从许多许多可能的组合来看,速度非常慢。我后退一步,取而代之的是一个非常简单的解决方案,简单地检查每个单词第一个字母的每个位置的邻居。然后是下一个字母的相邻字母,然后检查该方向的每个字母的单词长度。如果它符合这个词,我们有一个解决方案,如果不是,我们继续寻找。我发现一种更通用的方法是再次使用递归,只保留单词中后续字母的相邻字母。这也允许无效移动,是一个更通用的路径查找器。正如我所说的,我坚持使用我的第一个可用的解决方案。这是我使用的算法的示意图。它既简单又快捷。

在字母网格中查找单词的简单算法

如果你有兴趣看到一个非常好的通用解决方案,我在 reddit 上发起了一个讨论,有人在里面发布了一个非常棒的解决方案。这是到它的链接

我还添加了一些解析器来删除像“.”这样的东西或'-'有时出现在单词中。

身体

源图像

为此,我们可以感谢我们的好朋友 PyAutoGui。“困难的部分”只是从我们用来定义网格的 numpy 字母数组中获取屏幕像素坐标。我创建了另一个数组,在对每个字母进行 OCR 之前,当我们第一次定义边界框时,它存储了字母的质心位置。我还保留了截图中的网格位置偏移。在考虑了 OpenCV 坐标和 numpy 数组位置之间的差异后,简单的数学将告诉我们位置。单个字典可以用于每个字母和相应的像素位置,而不是两个单独的数组,但我的意思是,无论哪种方式……为了简化 wordsearch.com 的自动化,你可以选择“拖动”动作来查找单词,或者你可以在单词的开头和结尾使用“点击”。这更简单,尽管事实上是一样的。所以,如果你想自己尝试一下,我确实实现了‘敲击’单词选择方法。这是在文字搜索页面的设置中。我故意在每个单词之间增加了 1 秒的延迟和 0.2 秒的睡眠时间,以确保任何互联网连接延迟或其他不会导致它变得疯狂。

单词搜索游戏中使用的设置

结论

总而言之,看到所有的单词都被找到,这是一个非常令人满意的结果。我确实学到了很多东西,并练习了一些有用的技术。我对表演很满意。

我最近在 neptune.ai 上找到了另一篇关于 OCR 的文章,这篇文章更加详细地介绍了如何构建自己的 OCR 引擎以及这个过程的每一步。如果你有兴趣了解更多,我鼓励你去看看。

如果这篇文章的任何部分提供了一些有用的信息或一点灵感,请关注我。

你可以在我的 github 上找到源代码。

您可能还喜欢:

网络图中可视化的所有字母相邻连接

octave——科学编程语言速成班

原文:https://towardsdatascience.com/octave-scientific-programming-language-crash-course-2ab8d864a01d?source=collection_archive---------17-----------------------

免费 Matlab 替代品

八度(作者截图)。

GNU Octave 是一种免费的科学编程语言。它提供了丰富的数学工具简洁的语法、以及内置的可视化工具 [1]。整套真的是得心应手。它有图形用户界面(GUI)和命令行界面版本。感觉像是 Java 或 Python 的标准集成开发环境 (IDE)。

Octave 可用于解决各种数学问题、构建模拟或从事数据科学项目。如果你熟悉Matlab【2】,或者你正在寻找一种快速原型化你的科学相关想法的方法,你绝对应该试试 Octave。让我们来看一些实际的例子,这些例子将帮助你用这个工具开始你的旅程。

装置

Debian 操作系统(例如 Ubuntu)上,你可以使用内置的包管理器来安装 Octave:

Debian 系统上的 Octave 安装。

如果系统提示您缺少软件包,请检查此处的 [3】命令,其中包含您的操作系统版本所需软件包的完整列表。对于 ubuntu 20.4,它看起来是这样的:

Ubuntu 20.4 需要的 Octave 包(作者要点)。

如果你使用的是 Windows 系统,只需下载安装程序的可执行文件或压缩文件,然后解压。当前版本 5.2,以及 macOS 和 BSD 系统的说明,可从这里【4】获得。

GUI 指南

八度 GUI(作者截图)。

Octave GUI 由 4 个主要部分组成。最重要的是右边覆盖面积最大的面板。默认情况下,它是一个 命令窗口 。在这里,你可以在交互模式下输入任何 Octave 命令,它们会立即执行,并显示结果。

命令窗口的底部,你可以找到另外 3 个选项卡。第二个是 文档 。这是 Octave docs 的一个非常方便的离线版本。它由主题部分组成,您可以在主题部分阅读数据类型或语句等主题。它还包含一个单独的 函数索引 与示例:

Octave 内置文档(作者截图)。

右侧主区域下的最后两个选项卡是 编辑器变量编辑器 。编辑器选项卡只是一个文本编辑器,您可以在其中键入您的 Octave 代码。它有一个语法补全特性,但是一般来说,非常简单。在变量编辑器中,您可以选择一个变量并更改其值。它在处理多维变量时很有用,所以当您需要手动编辑它们时不会感到困惑。根据我的经验,这是很少使用的功能。

在主窗口的左侧,有 3 个面板。在顶部,有一个 文件浏览器 ,在这里你可以选择你的项目目录并可以操作它的文件。下面你会发现一个 工作区 ,其中包含所有活动变量及其简短描述(类型、尺寸、值、属性)。最后一个面板包含 命令历史 。它允许您搜索和过滤您过去使用过的命令:

Octave 命令历史面板(作者截图)。

使用数据

数据和变量是任何计算机程序的核心部分。看看如何在 Octave 中定义不同类型的变量和加载文件。

Octave 中的变量定义(作者截图)。

在截图中,你可以看到定义变量是非常直观的。您需要提供一个变量名,使用赋值运算符" = " ,并输入一个您想要放在变量下的值。您可以使用标量值,如整数、浮点数、文本(用引号定义,如“我是一个示例文本”)。如果你只是输入一个没有名字的值,Octave 会创建一个 ans 变量,并保存你在命令窗口中直接输入的最后一个值。您可以将用作任何其他变量。

如果你仔细看了截图,你会注意到一个的诡计。当你用分号“结束你的一行;***该命令不打印任何输出。但是,命令末尾没有分号**会将结果打印到控制台。*

定义向量

向量是由多个值组成的变量。你可以把它想象成一个元素数组。要在 Octave 中定义一个向量,你需要提供一个向量名和用空格分隔的向量值。所有语句都应该用方括号括起来:

Octave 中的矢量定义(作者截图)。

要定义列向量,应该用分号分隔向量值。

定义矩阵

矩阵定义和向量定义一样简单。主要规则是:

  1. 用空格分隔矩阵行值。
  2. 用分号分隔矩阵列。

看一下图片:

Octave 中的矩阵定义(作者截图)。

定义变量时有用的函数

如果你想生成一个由 0 或 1 组成的变量,有两个方便的函数可以使用。 零点(m,n,k,..) 生成全零变量, m,n,k 是定义尺寸大小的整数。以此类推,你可以使用 个 1(m,n,k,…) 来获得一个填充有 1 的变量:

zeros 函数示例(作者截图)。

另一种生成值的有用方法是使用给定的 离散步长 生成矢量。假设你需要一个从 0 到 10 的向量,步长等于 0.5。在 Octave 中,您可以这样定义它:

使用离散步骤生成的向量(作者截图)。

你只需要从向量的初值,步长值,最后一个值开始。这三个值应该用冒号分隔。在我们的例子中,vector 有 21 个元素。

访问元素

访问变量时要记住的最重要的事情之一是 Octave 从 1 开始索引,而不是像我们大多数人习惯的那样从 0 开始。要获取特定元素,您需要在括号内指定其索引:

访问 Octave 中的变量元素(作者截图)。

加载数据

加载数据最简单的方法是使用 【加载(filename . m)】功能。它需要一个包含逗号分隔的值和列的文件。看一下这个例子:

样本数据文件(作者截图)。

有了这样一个文件,姑且称之为 myData.m ,你只需选择一个变量来赋值数据,并像这样调用 load 函数:

加载数据示例(作者截图)。

在图中,你可以看到我们加载了一个矩阵变量,它有 63 行,每行 2 个值。使用 尺寸(变量) 功能检查变量尺寸。加载后,我们检查第一行的第一个元素,它等于 2000。

Octave 还支持更高级的加载功能,如二进制文件或在文件中定义分隔符。要了解更多信息,请查看文档中的加载函数描述。

基本线性代数运算

Octave 最强大的部分是一个内置的数学仪器。简单方便的语法使它变得更好。

加法和减法矩阵

加减矩阵需要使用 "+" 或者 "-" 减运算符。当您添加两个相同大小的矩阵时,将使用相应单元格中的值进行运算(例如,矩阵 A 中第一行和第一列的值加上矩阵 B 中第一行和第一列的值)。

加减矩阵示例(作者截图)。

然而,你需要小心。也可以加上或减去一个矢量。为了清楚起见,我们来看几个不同的例子:

矩阵和向量的运算(作者截图)。

矩阵乘法

让我们回忆一下矩阵相乘的先决条件。

矩阵乘法法则(图片由作者提供)。

要将大小为 m x n 的矩阵 A 乘以矩阵 B ,矩阵 B 中的行数必须等于矩阵 A 中的列数。假设矩阵 B 的大小为 n x k,乘法运算的结果是矩阵 C 的大小为 m x k. 使用 "" 运算符来乘矩阵。*

让我们来看看这个例子:

矩阵乘法示例(作者截图)。

为什么我们会得到这样的结果?检查每个矩阵单元是如何根据矩阵乘法规则计算的:

矩阵乘法示例详情(图片由作者提供)。

我们可以将相同的规则应用于向量,因为它们是矩阵的一种特殊情况(大小为 1 x n ,或者列向量的大小为 n x 1)。如果我们对以下大小的多个向量进行乘法运算,我们将得到一个值:

产生单一值的特殊情况(图片由作者提供)。

为了形象化这种情况,让我们定义向量 A 和列向量 B 并将它们相乘:

向量乘法示例(图片由作者提供)。

两个向量都由 1,2,3,4 组成。将它们相乘等于将来自 AB 的第一个元素相乘,并将它们的第二个元素相乘的结果相加,依此类推,直到我们得到所有的元素。这意味着我们得到了:

向量一步一步相乘(图片由作者提供)。

标量矩阵乘法

有时候你需要把矩阵的对应元素相乘。当然不是按线性代数定义的矩阵乘法,所以不能用运算符。相反,Octave 有一个额外的 点“.” 乘法运算符前的运算符。让我们看看使用它时会发生什么:*

标量矩阵乘法示例(作者截图)。

矩阵转置

转置一个矩阵,意味着我们把行改成列,把列改成行。因此,矩阵的大小根据以下公式变化:

矩阵换位公式(图片由作者提供)。

在 Octave 中,您可以使用“”运算符转置一个矩阵:

矩阵转置的例子(作者截图)。

解线性方程组

最后,让我们解一个简单的线性方程组:

线性方程组(图片作者提供)。

这样的系统可以用两个矩阵来表示,这两个矩阵在变量之前映射系数。第一个代表系统的左侧:

方程组的左侧—矩阵表示(图片由作者提供)。

右边看起来像这样:

方程组右侧—矩阵表示(图片由作者提供)。

整个系统用以下公式表示,其中矩阵 x 由变量 x 和 y 组成:

线性方程组(图片作者提供)。

为了解决这个问题,我们可以对矩阵 A 求逆,并将其乘以矩阵 b。在 Octave 中,这相当于使用左侧除法运算符“\”【5】。结果 x = A \ b:

线性方程组求解(作者截图)。

最后,我们得到变量 x 等于 2,变量 y 等于 3。这是正确答案,太好了!

可视化工具

我们知道图像胜过千言万语,它有助于理解我们试图解决的问题。幸运的是,绘图也是 Octave 的内置功能。

绘图点

要绘制 2D 数据点可以使用功能绘制。它将点的 xy 坐标作为自变量和附加的样式相关参数。**

让我们假设你有一个文件,其中每一行包含一个点。下面的代码将文件加载到数据变量中,提取每个点的 xy 坐标(使用“ : ”运算符),并绘制蓝色点( b. )、大小为 30 的点(marker size“参数):

代码绘制 2D 点(作者要点)。

结果,我们得到一个网格点:

剧情结果(作者截图)。

要更改颜色和样式,您可以尝试不同的字母,例如,【g】代表绿色,【r】代表红色,点样式字符如“ + ”或“ ******* ”。例如"" plot(x,y,' r+',' markersize ',30);** “看起来是这样的:**

使用 r+风格的剧情(作者截图)。

绘图功能

可以用同样的作图方法画出函数图。首先,你需要准备离散坐标向量,然后准备每个坐标的函数值向量。重要的是这些向量应该大小相等。

作为一个例子,让我们画一个下列函数的图:

样本线性函数(图片由作者提供)。

看一下代码片段:

功能图代码(作者要点)。

在第一行中,向量 x 从-10 开始填充,直到值达到 10(步长等于 0.1)。所以包含了-10,-9.9,-9,8 … 10。那么向量 y 包含每个 x 坐标的函数值。最后,我们绘制我们的函数,并将其线宽设置为 10:

线性函数图(作者截图)。

更多奇特的功能

当然,也可以画出更复杂的函数。Octave 提供了非常好的文档,所以我鼓励您检查并使用 plot3meshgridsurfsombrero 函数。这是很好的锻炼。

对于上面提到的一些函数,Octave 也提供了一些测试 plot 函数,你可以不用任何参数调用它们就可以很快看到结果。以下是一些例子:

****

峰值和 surf 函数(作者截图)。

有用的诡计

在这个速成课程的最后一点,我将分享在过滤您的数据时非常有用的功能。您可以将它用于来自机器学习分类器的预测向量或矩阵,并决定给定对象的标签。另一个例子是对数据应用给定的阈值,或者移除和提取异常。

假设我们有一个包含 0 和 1 的预测向量,作为不同对象的标签。要查找给定标签的索引,您可以使用 查找 功能,并定义一个条件作为其参数。为了更好地理解它,让我们来看看下面的例子:

find 函数示例(作者截图)。

它是如何工作的?传递给 find 函数的条件用于返回所有大于 0 的元素索引。然后,我们可以使用这些索引从预测向量中提取元素。就是这样!

摘要

在完成这个简短的教程后,你已经掌握了一些知识,这些知识会让你对 Octave 环境有一个良好的开端。您知道如何定义和加载数据,如何对向量和矩阵执行操作,以及如何可视化您的工作。

我鼓励您在有想法时使用 Octave,并且您需要一个丰富而简单的环境来实现它,而您的成熟 Python 设置是遥不可及的。

参考书目:

  1. https://www.gnu.org/software/octave/
  2. https://en.wikipedia.org/wiki/MATLAB
  3. **【https://wiki.octave.org/Octave_for_Debian_systems **
  4. https://www.gnu.org/software/octave/download.html
  5. https://octave.org/doc/v4.0.1/Simple-Examples.html

十月 AI——值得一试的五个项目

原文:https://towardsdatascience.com/october-ai-five-projects-worth-checking-out-99a00d2c7c19?source=collection_archive---------40-----------------------

每月一次的网络广播,在这里我分享了五个值得花时间去做的很酷的项目!

人工智能和数据科学的世界正在以惊人的速度加速发展。对于人工智能爱好者和学习者来说,跟上该领域有意义的进展变得非常困难。应用、研发、单个项目、专有软件——每个部门都在以自己独特的方式应用 DS 和 AI。

我开始这个每月一次的人工智能网络研讨会有两个主要原因:

  1. 这种方法帮助我发现了这个广阔的人工智能领域的趋势,这让我对自己前进的方向感到放心。所以,为什么不和别人分享呢!
  2. 这让我充满活力和感激,因为我是这个社区的一部分。这也意味着我对那些努力向更广泛的观众展示他们的才华和努力的人负有责任。

但是为什么只有五个项目,你会问…

嗯,我想保持它的简洁、有用和多样化,这样我们就可以涵盖所有重要的领域,而不会被一大堆项目淹没。

这些有什么用?鉴于该项目是公开的而非专有的,我将尽力给你列表中每个项目的行动项目。

所以,这里列出了我认为值得一试的五个很酷的项目:

Python 3.9 的稳定发布

在过去的一年里,来自世界各地的开源爱好者一直致力于开发新的、增强的和不推荐的特性。尽管测试版已经推出了很长时间,Python 3.9.0 的正式发布是在 2020 年 10 月 5 日。

官方文档包含了最新特性和变更日志的所有细节。下面列出了可能对我们的日常编程任务有用的功能:

  • 类型提示泛型以及灵活的函数和变量注释——Python 3.9 增加了 PEP 593 引入了一种机制,扩展了PEP 484的类型注释,提供了注释的标准语义,并建议将注释用于类型提示。
  • ****字典中的联合操作符—Python 3.9 最酷、最有用的特性之一是添加到内置dict类中的合并(|)和更新(|=)操作符。
    PEP 584 为字典引入了两个新的运算符:
    (|) union — 合并两个字典。它保留了原始词典。
    (|=)更新— 这是用于字典的就地合并。
  • **zoneinfo** —访问和计算时区— 到目前为止,我们已经有了像dateutil这样的第三方库来实现这种时区特定的规则,但是现在 Python 3.9 让 Paul Ganssle 加入核心团队来添加一个新的**zoneinfo**模块,该模块提供整个互联网数字地址分配机构(IANA)时区数据库供访问和使用。
  • **去除前缀和后缀的字符串方法——**PEP 616推出了从字符串中去除前缀和后缀的新方法。新方法有:
    1。 removeprefix() 2。 removesuffix()

围绕lstrip()rstrip()方法,所有主要论坛(如 StackOverflow)都有许多重复出现的问题。

  • 其他发布亮点— 1。CPython 现在使用一个基于 PEG
    2 的新解析器。CPython 现在采用新的年度发布周期。 PEP 614 ,放松了对装饰者的语法限制,提供了更灵活的语法。

我还在我的博客中详细介绍了所有重大更新:

** [## Python 3.9 —最新更新的实际操作

浏览新发布的 Python 3.9 中的最新更新

towardsdatascience.com](/python-3-9-hands-on-with-the-latest-updates-8137e2246119)

CNN 解说

图片来源:https://poloclub.github.io/cnn-explainer/

CNN Explainer 是一个基于浏览器的卷积神经网络的可视化说明。令人感兴趣的是,我们如何使用 Keras 或 fastai 等库,在几行代码中创建一个对对象进行分类的最先进的 CNN,但理解 CNN 如何处理图像以获得最终输出的机制是至关重要的。这就是 CNN 解释者的用武之地。如果你曾经努力完全理解 CNN 发生了什么,或者如果你只是需要一个更清晰的复习,从数学和视觉的角度来看,这个工具对你来说是完美的。

该项目使用浏览器内 GPU 加速的深度学习库 TensorFlow.js 加载预先训练好的模型进行可视化。整个交互系统是用 Javascript 编写的,使用作为框架,使用 D3.js 进行可视化。你只需要一个网络浏览器就可以开始学习 CNN 了!

这是由王杰罗伯特·图尔科奥马尔·谢赫海丘公园尼拉克什·达斯弗雷德·霍曼明苏克·康波罗洲创造的,是佐治亚理工学院和俄勒冈州立大学合作研究的成果。

先决条件要完全理解这个工具:

  1. 对 CNN 理论的基本了解或
  2. 一定是用深度学习框架编写了 CNN

如果以上两种你都没有做过,建议在使用工具之前先学习一下神经网络和卷积神经网络的基础知识。

CNN Explainer 使用一个非常简单的 CNN 称为 TinyVGG,它只包含三个卷积层,两个 max-pool 层和一个 flatten 层,将图像分为 10 个类别——救生艇,瓢虫,披萨和 7 个其他类别。

您可以使用他们的一个图像或上传您自己的图像来查看图像如何穿过神经网络,以及神经网络如何捕捉图像的某些特征。

但是可视化图像如何出现在不同的层只是冰山一角。通过使用该工具,您还可以了解以下内容在 CNN 中的作用:

  • 卷积层的核权重偏差**
  • 需要最大池层和展平
  • 超参数 ( 输入大小、填充、内核大小步距*)如何影响卷积运算*
  • ReLU 激活功能的需要和工作
  • Softmax 激活功能的需要和工作

行动/学习项目:

试着回答这些问题来测试你对项目中演示的 CNN 的理解

  1. 对于给定的卷积层,存在多少个核权重和偏置权重(或者需要在训练阶段进行训练)?
  2. 最大池层的需求是什么,为什么它没有任何内核/偏差权重?
  3. 如果你上传的图片不属于这 10 类中的任何一类,会发生什么?

张量传感器

它是一个 python 库(pip install tensor-sensor),创建的目的是在使用 NumPyTensorflowPyTorch 构建神经网络(甚至只是简单的基于矩阵的计算,如点积)时处理异常。通常当使用这三个库时,如果我们在计算矩阵乘法时犯了一个错误,比如说矩阵的维数,解释器会抛出一个错误,而没有说明更多的细节,这使得调试更加困难——通常导致编码者编写一些显式的打印语句来查看哪里出错了。TensorSenor 的目标是通过做两件事来解决这个问题

  1. 提供更好的异常消息。
  2. 提供与异常消息相关的张量(或矩阵)的可视化表示,以了解哪里出错了。

在 TensorSensor 中,主要使用两种类型的上下文管理器:

  1. **with tsensor.clarify():**

这仅用于处理异常。它可以用于预构建的 Keras 对象,甚至用于我们自己定制的定义。

例如:

图片来源:https://explained.ai/tensor-sensor/index.html

  1. **with tsensor.explain():**

为了更清楚地理解,我们可能只想观察矩阵的维数,而不是处理异常。

举例:

*图片来源:【https://explained.ai/tensor-sensor/index.html *

我们还可以为 3D 张量扩展这些上下文管理器,其中第一维可以是批量甚至是 4D 张量。

*图片来源:【https://explained.ai/tensor-sensor/index.html *

还有一个函数 tsensor.astviz(),用于创建抽象树语法,如下所示:

T sensor . astviz(" h _ = torch . tanh(Whh _ @(r * h)+Uxh _ @ X . T+BH _)")

图片来源:https://explained.ai/tensor-sensor/index.html

Nvidia Maxine 视频通话

图片来源:https://blogs . NVIDIA . com/blog/2020/10/05/gan-video-conferencing-Maxine/

这是清单上的专有项目。因此,Nvidia 最近宣布,他们的人工智能专家正在研究这个云人工智能视频流平台,该平台将使用 GANs 来提高带宽性能。

该平台使用神经网络代替称为视频编解码器的标准软件,视频编解码器通常用于压缩和解压缩视频,以便在互联网上传输。

他们的工作使得视频通话只需要用户通常所需网络带宽的十分之一。

它是如何工作的

发送者首先发送呼叫者的参考图像。然后,它发送用户眼睛、鼻子和嘴巴周围几个关键点的位置数据,而不是发送大量像素打包的图像。

接收方的生成对抗网络使用初始图像和面部关键点在本地 GPU 上重建后续图像。因此,通过网络发送的数据要少得多

即使打电话的人戴着帽子、眼镜、耳机或口罩,这项技术仍然有效。

这项工作中更重要的功能是使用神经网络来调整用户面部的位置,以获得更自然的体验。来电者观看他们的视频,但他们似乎直接看着他们的摄像机,增强了面对面交流的感觉。

洋红色调转印

https://sites.research.google/tonetransfer

Tone Transfer 是谷歌的一个研究项目,将日常声音转化为乐器。

Tone Transfer 诞生于 Google Research 的两个团队之间的合作:Magenta 和 AIUX

色调转换是建立在今年早些时候一项名为可微分数字信号处理或 DDSP 的 Magenta 开源技术之上的。

在这个项目的开始,团队使用这个 Colab 笔记本来展示他们的工作。经过多次反复的设计探索和用户研究,AIUX 团队开发出了这个平台,使得在应用程序层面上使用 DDSP 模型变得非常有趣。

他们通过训练机器学习模型来提取是什么让一种乐器听起来像那种特定的乐器。它拾取音高、八度、响度以及许多其他特征,并将日常声音重塑为乐器。

为了从音频中提取音高,使用了 Google Research 开发的另一个模型 SPICE

即将发布的版本将使您能够轻松训练自己的 DDSP 模型,并将其部署在任何地方:手机、音频插件或网站。**

如果你想看我回顾所有这些项目,这里是这个博客的视频版本,有演练和编码截屏。

数据科学与 Harshit

通过这个渠道,我计划推出几个涵盖整个数据科学领域的系列。以下是你应该订阅频道的原因:

请随时在 TwitterLinkedIn 上与我联系。

十月版:在数据科学领域就业

原文:https://towardsdatascience.com/october-edition-getting-hired-in-data-science-e76235ae9eb2?source=collection_archive---------32-----------------------

月刊

我们最好的职业建议

优 X 创投Unsplash 上的照片

在主持“走向数据科学”播客和在sharpes minds辅导数据科学学员期间,我意识到试图成为一名数据科学家就像从两条消防水管喝水一样。第一条消防水管是技术性的。你必须浏览博客帖子、在线课程、Kaggle 比赛和训练营,了解从 AUC 分数和超参数调整到聚类算法和深度神经网络的一切。这是一个很难处理的问题,但它得到了很多关注,我们有很好的资源来帮助大多数人理解它,只要他们花时间。

但第二点同样重要。这是职业建议消防水带——一组信息可以帮助你决定你应该以什么工作为目标进入数据科学领域,以及如何在其他申请者中脱颖而出。

大多数人从技术消防水带开始,然后通过寻找与他们的技术技能相匹配的工作,转向职业消防水带,而不是相反。我认为这是一个错误。

在你知道你需要学习什么技术技能之前,你需要知道你想做什么。否则,你可能会学到一大堆通用的、不相关的、千篇一律的数据科学知识,这些知识无法构成一个连贯的角色,或者更糟糕的是,它们让你承担了一个你后来意识到自己从未想要的角色。

因此,对于这篇时事通讯,我们决定本末倒置,强调 TDS 作者希望你了解的一些最佳职业建议。无论你是一名有抱负的数据科学家,还是正处于数据科学职业生涯的中期,我都建议借此机会思考一下你未来的职业道路。享受阅读吧!

《走向数据科学》的播客主持人 Jeremie Harris。

被解雇,在新冠肺炎中部被聘为数据科学家

由 Dhruvil Karani — 8 分钟

困难时期找工作的心得。

我在数据科学家的职业生涯中学到了什么

罗马 Orac — 5 分钟

如果时光可以倒流,我会给自己什么职业建议?我做对了什么,哪里做错了?

让你在数据科学职业生涯中不可或缺的 4 种超能力

Ganes Kesari — 6 分钟

了解数据科学行业的这些最大挑战,以避免职业生涯停滞不前

如何写一份获奖的数据科学简历

由 Matt Przybyla 制作— 10 分钟

…吸引脸书、谷歌、苹果和微软等公司。

给年轻自己的数据科学职业建议

肖恩·惠勒 — 11 分钟

我不知道这些想法是否会让年轻的我受益。我想他们会的。

数据科学入门终极指南

安妮·邦纳 — 16 分钟

我是如何在不到 6 个月的时间里获得数据科学工作机会的

为什么你还不是一个可以胜任工作的数据科学家

由杰瑞米·哈里斯——6 分钟

如果说我从我工作的数据科学导师初创公司学到了什么,那就是:在你的数据科学工作申请或面试中获得反馈几乎是不可能的

想要一份数据科学的工作?利用周末项目原理搞定

丹尼尔·伯克 — 4 分钟

在线课程证书很棒。但是自己的项目更好。

能让你得到工作的数据科学项目

由纳塔莎·塞尔瓦拉吉 — 6 分钟

我是如何在自学数据科学四个月后获得实习机会的

新视频

新播客

我们也感谢最近加入我们的所有伟大的新作家沙伊拉·马奎斯史华靖约书亚·茨马诺夫斯基蒂格兰·哈查特里安玛蒂娜·波恰里尤瓦尔·布劳张博·杜托伊特丹尼尔·L·J·托马斯卡罗·莱斯科瓦尔 埃利奥特·特拉巴克拉德·恩耶希奇扎卡里·托马斯塞巴斯蒂安·波利亚克帕里迪·帕拉朱莉以及许多其他人。 我们邀请你看看他们的简介,看看他们的工作。

基于卷积神经网络的眼部疾病识别

原文:https://towardsdatascience.com/ocular-disease-recognition-using-convolutional-neural-networks-c04d63a7a2da?source=collection_archive---------9-----------------------

变更数据

为眼疾识别构建深度学习模型。

Unsplash卡莉娅·杰丽勒的照片

关于这个项目

这个项目是米兰大学组织的海量数据算法课程的一部分,我最近有机会参加了这个课程。任务是开发能够使用 TensorFlow 库从眼底图像识别眼病的深度学习模型。一个重要的要求是使训练过程可伸缩,因此创建一个能够处理大量数据点的数据管道。在本文中,我总结了我在卷积神经网络和使用 Tensorflow dataset 对象构建高效数据管道的方法方面的发现。在我的 Github 库上有完整的可重复实验代码:https://github.com/GrzegorzMeller/AlgorithmsForMassiveData

介绍

早期眼部疾病检测是预防由糖尿病、青光眼、白内障、年龄相关性黄斑变性(AMD)和许多其他疾病引起的失明的经济有效的方法。据世界卫生组织(世卫组织)统计,目前全球至少有 22 亿人有视力障碍,其中至少有 10 亿人的视力障碍是可以预防的[1]。疾病的快速和自动检测在减少眼科医生的工作量和防止患者视力损伤方面是关键和迫切的。计算机视觉和深度学习可以在提供高质量的医学眼底图像后,自动检测眼部疾病。在本文中,我展示了使用 TensorFlow 库编写的卷积神经网络构建高级分类模型的不同实验和方法。

资料组

眼部疾病智能识别(ODIR)是一个结构化的眼科数据库,包含 5000 名患者的年龄、左眼和右眼的彩色眼底照片以及来自医生的医生诊断关键词。该数据集旨在代表上工医疗科技有限公司从中国不同医院/医疗中心收集的“真实生活”患者信息集。在这些机构中,眼底图像由市场上的各种相机拍摄,例如佳能、蔡司和 Kowa,导致图像分辨率各不相同。注释由受过质量控制管理训练的人类读者进行标记[2]。他们将患者分为八个标签,包括正常(N)、糖尿病(D)、青光眼(G)、白内障(C)、AMD (A)、高血压(H)、近视(M)和其他疾病/异常(O)。

经过初步的数据探索,我发现 ODIR 数据集面临以下主要挑战:

高度不平衡的数据。大多数图像被分类为正常(1140 个实例),而特定疾病,例如高血压,在数据集中仅出现 100 次。

数据集包含多标签疾病,因为每只眼睛可能不仅患有一种疾病,还可能患有多种疾病的组合。

标记为“其他疾病/异常”(O)的图像包含与超过 10 种不同疾病相关的图像,将可变性扩展到更大程度。

非常大和不同的图像分辨率。大多数图像的大小约为 2976x2976 或 2592x1728 像素。

所有这些问题都会对准确性和其他指标产生重大影响。

数据预处理

首先,调整所有图像的大小。一开始,我想使用 TensorFlow 数据集对象“动态”调整图像大小。训练模型时调整了图像的大小。我认为它可以防止耗时的图像尺寸调整一次。不幸的是,这不是一个好的决定,一个历元的执行甚至可能需要 15 分钟,所以我在创建 TensorFlow dataset 对象之前创建了另一个函数来调整图像的大小。因此,数据只需调整一次大小,并保存到不同的目录中,这样我就可以使用更快的训练执行来试验不同的训练方法。最初,所有图像的大小都被调整为 32x32 像素,但我很快意识到,压缩到如此低的大小,即使它大大加快了训练过程,也会丢失许多重要的图像信息,因此准确性非常低。经过几次实验后,我发现 250x250 像素的大小在折衷训练速度和准确性指标方面是最好的,因此我在所有进一步的实验中在所有图像上都保持这个大小。

其次,图像被标记。data.csv 文件中的图像注释存在问题,因为标签同时与两只眼睛(左眼和右眼)相关,而每只眼睛可能患有不同的疾病。例如,如果左眼患有白内障而右眼眼底正常,则标签将是白内障,而不是指示右眼的诊断。幸运的是,诊断关键字与一只眼睛相关。创建数据集的方式是将左眼和右眼图像作为输入提供给模型,并返回总体(对于双眼)累积诊断,忽略了一只眼睛可能是健康的这一事实。在我看来,从这种模型的最终用户的角度来看,这是没有意义的,最好是对每只眼睛分别进行预测,以了解例如应该治疗哪只眼睛。因此,我通过创建诊断关键词与疾病标签之间的映射来丰富数据集。这样,每只眼睛都被分配到一个适当的标签。该映射的片段以字典的形式呈现在图 1 中。通过重命名图像名称,更具体地说,通过向图像文件名添加对应于特定疾病的一个或多个字母来添加标签信息。我应用了这个解决方案,因为这样我不需要存储任何带有所有标签的额外数据帧。重命名文件是一个非常快速的操作,在正式的 TensorFlow 文档中,TensorFlow 数据集是简单地从文件中创建的,标签信息是从文件名中检索的[3]。此外,一些图像的注释与特定疾病本身无关,而是与图像的低质量有关,如“镜头灰尘”或“照片上不可见的视盘”,这些图像被从数据集中删除,因为它们在确定患者的疾病中不起决定性作用。

图 1:用疾病标签映射特定诊断关键词的字典片段

第三,通过随机选择所有可用图像的 30%来创建验证集。我选择 30%是因为这个数据集相对较小(总共只有 7000 个图像),但是我想使我的验证足够有代表性,而不是在评估模型时有偏见,因为事实上许多图像变体或类在验证集中没有它们的表示。ODIR 数据集提供了测试图像,但不幸的是,data.csv 文件中没有为它们提供标注信息,因此我无法使用可用的测试图像来评估模型。

接下来,在训练集上应用少数类的数据扩充以平衡数据集。应用了随机缩放、随机旋转、左右翻转、上下翻转。一开始,我使用 TensorFlow dataset 对象在训练模型[4]时“动态地”应用数据扩充,以尽可能保持我的解决方案的可伸缩性。不幸的是,它缺乏许多功能,如随机旋转,因此我在创建 TensorFlow 数据集对象之前,使用 OpenCV 等其他图像处理库进行了数据扩充。一开始,我还考虑过通过应用对比度受限的自适应直方图均衡化(CLAHE)来增强所有图像,以增加图像局部细节的可见性,但由于这给图像增加了许多额外的噪声(尤其是背景,最初是黑色的),我决定不遵循这个方向。使用 PIL 和 OpenCV 库编写的 my 函数进行数据扩充的例子如图 2 所示。

图 2:示例性数据扩充结果

最后,创建 TensorFlow 数据集对象。它的开发与 TensorFlow 官方文档中用于加载图像的开发非常相似[5]。由于这个库很复杂,对于 TensorFlow 初学者来说不容易使用,所以我想在这里分享一下我在构建可伸缩的快速输入管道方面的发现。 tf.data API 使您能够从简单的、可重用的部分构建复杂的输入管道。例如,图像模型的管道可能从分布式文件系统中的文件聚合数据。 tf.data API 引入了一个 tf.data.Dataset 抽象,表示一系列元素,其中每个元素由一个或多个组件组成。例如,在我的图像管道中,一个元素是一个单一的训练示例,用一对张量分量表示图像及其标签[6]。TensorFlow 引入了所谓的迭代学习过程,即向模型输入一部分数据(而非整个数据集),训练并重复另一部分数据(称为批次)。批量大小定义了在每个训练步骤中要抽取多少个样本。在每一步之后,权重被更新。我选择的批量大小等于 32,以避免过度拟合的问题。由于批量较小,权重会定期频繁更新。小批量的缺点是训练时间比大批量长得多。tf.data 的一个重要元素是混洗数据集的能力。在混洗中,数据集用元素填充缓冲区,然后从该缓冲区随机采样元素,用新元素替换所选元素[7]。它防止了将相同类别的图像重复填充到批中的情况,这不利于训练模型。

构建卷积神经网络

在深度学习中,卷积神经网络(CNN)是一类深度神经网络,最常用于分析视觉图像[8]。输入图层采用 250x250 RGB 图像。第一 2D 卷积层使用大小为 5×5 像素的窗口在输入图像上移动,以提取特征并将它们保存在多维阵列上,在我的示例中,第一层的滤波器数量等于 32,因此为(250,250,32)大小的立方体。

在每个卷积层之后,应用校正的线性激活函数(ReLU)。激活具有决定神经元是否需要被激活或者不测量加权和的权力。ReLU 直接返回作为输入提供的值,如果输入等于或小于 0.0,则返回值 0.0。由于校正后的线性单元几乎是线性的,因此它们保留了许多使线性模型易于使用基于梯度的方法进行优化的属性。它们还保留了许多使线性模型能够很好地推广的特性[9]。

为了逐步减小输入表示的空间大小并最大限度地减少网络中的参数和计算数量,添加了最大池层。简而言之,对于由特定大小的过滤器表示的每个区域,在我的示例中是(5,5),它将获取该区域的最大值并创建新的输出矩阵,其中每个元素都是原始输入中该区域的最大值。

为了避免过度拟合问题,增加了两个 45%层的漏失。模型中添加了几个批量标准化图层。批处理规范化是一种提高人工神经网络的速度、性能和稳定性的技术[10]。它改变了神经元输出的分布,所以它更适合激活函数。

最后,将“立方体”展平。没有实现完全连接的层,以保持网络的简单性和快速训练。最后一层的密度为 8,因为 8 是数据集中存在的标签(疾病)的数量。由于我们面临多标签分类(数据样本可以属于多个实例),sigmoid 激活函数被应用于最后一层。sigmoid 函数将每个分数转换为 0 到 1 之间的最终节点,与其他分数无关(与 softmax 等其他函数相反),这就是 sigmoid 最适合多标签分类问题的原因。由于我们使用的是 sigmoid 激活函数,我们必须使用二进制交叉熵损失。所选的优化器是 Adam,学习率很低,为 0.0001,因为我在培训期间面临过拟合问题。我的 CNN 的整个架构如图 3 所示

图 3:模型总结

实验和结果

为了简单起见,我想从简单的概念验证实验开始我的研究,在挑战性较小的数据集上,测试之前的假设是否正确。因此,我开始训练一个简单的模型来检测一只眼睛是否有正常的眼底或白内障,只对标记为 N(正常)或 C(白内障)的图像进行训练。结果非常令人满意,使用一个相对简单的网络在 12 个时期内我的模型得到了 93%的验证准确率。这已经表明,使用 CNN 可以自动检测眼睛白内障!在接下来的每个实验中,我都向数据集添加另一个类的图像。第四个实验是在整个 ODIR 数据集上进行的,达到了几乎 50%的验证准确率。实验结果列于表 1。我们可以清楚地看到,整个模型的结果很低,因为很难训练它正确地检测糖尿病,因为患有糖尿病的眼睛看起来几乎与眼底正常的眼睛一样。检测近视或白内障是一项容易得多的任务,因为这些图像彼此之间以及与正常眼底之间有很大差异。图 4 显示了不同的选定疾病。

表 1:实验结果。图例:N-正常,C-白内障,M-近视,A-AMD,D-糖尿病,所有-在整个 ODIR 数据集上训练的模型

图 4:不同眼病的图示。显然,糖尿病似乎是最难检测的,而白内障是最容易检测的,因为它与正常眼底变化最大。

对于所有实验,使用相同的神经网络结构。唯一的区别是每个实验达到所呈现的结果所需的时期数(有些需要提前停止,有些需要更多的时期来学习)。此外,对于不包括整个数据集的实验,使用 softmax 激活函数和分类交叉熵损失,因为它们是多类而不是多标签分类问题。

关于模型可伸缩性的最后考虑

如今,在大数据世界中,根据可扩展性和可重复性评估每个 it 项目至关重要。从这个项目实施的一开始,我就非常强调这个想法,即使这是一个研究项目,也许在未来随着更多眼部疾病的数据点,模型可以被重新训练,并且肯定会取得更好的结果,有更多的图像来训练。因此,主要目标是建立一个通用的数据管道,能够处理更多的数据点。这个目标主要是通过使用高级 TensorFlow 库实现的,特别是 dataset 对象,它支持大型数据集上的 ETL 过程(提取、转换、加载)。不幸的是,在创建 TensorFlow 数据集对象之前需要进行一些转换,包括调整图像大小和扩充少数类。也许在未来,可以更快地“动态”调整图像大小,并且会添加更多的增强功能,如之前已经提到的随机旋转。但是,如果我们考虑将来有更多的数据点,可能就没有必要进行任何扩充,因为将提供足够多的图像变化。从深度学习项目中使用的其他流行数据集的角度来看,ODIR 将被视为一个小数据集。这就是为什么必须增加和过采样数据点以获得合理结果的原因。

摘要

在这个项目中,我证明了使用卷积神经网络检测各种眼部疾病是可能的。最令人满意的结果是以 93%的准确率检测白内障。一次性检查所有疾病,结果明显偏低ODIR 数据集为训练模型提供特定疾病的所有重要变化并不总是可能的,这会影响最终指标。尽管如此,我确信拥有一个更大的数据集将会提高预测的准确性,并最终使检测眼部疾病的过程自动化。

参考

[1]世卫组织:世界视力报告。世界卫生组织(2019):https://www . who . int/publications-detail/world-report-on-vision

[2] Kaggle 眼病识别数据集描述:https://www . ka ggle . com/Andrew MVD/Ocular-Disease-Recognition-odir5k

[3]将图像加载到 TensorFlow 数据集对象:https://www.tensorflow.org/tutorials/load_data/images

[4]tensor flow 中的数据增强:https://www . tensor flow . org/tutorials/images/Data _ augmentation

[5]将图像加载到 TensorFlow 数据集对象:【https://www.tensorflow.org/tutorials/load_data/images

[6]https://www.tensorflow.org/guide/data

[7]https://www . tensor flow . org/API _ docs/python/TF/data/Dataset # shuffle

https://en.wikipedia.org/wiki/Convolutional_neural_network

[9]深度学习,伊恩·古德菲勒,约舒阿·本吉奥,亚伦·库维尔。

https://en.wikipedia.org/wiki/Batch_normalization

[11]使用神经网络从眼底图像进行独立于源和相机的眼科疾病识别。医学博士塔里克·伊斯兰,谢赫阿西夫伊姆兰,阿西夫阿雷费恩,马哈茂德哈桑,西莉亚沙赫纳兹。孟加拉工程技术大学。

[12]用于视网膜图像分析的完全连接的层和类的数量之间的关系。阿贾纳·拉姆和康斯坦丁诺·卡洛斯·雷耶斯-阿尔达索罗。伦敦大学

天文学,恒星和数据

原文:https://towardsdatascience.com/of-astronomy-stars-and-data-6fb347045a4a?source=collection_archive---------32-----------------------

H-R 图上恒星分布的数据驱动解释

女性电脑

天文学是最古老的、数据驱动的科学之一。19 世纪后期出现了“天体照相术”,这是一种用来捕捉和创建天体、天体事件和夜空区域的照相底片数据库的摄影技术。

早在 1875 年,哈佛大学天文台就开始雇佣越来越多的女性助手(尽管这一决定更多的是从经济角度而非伦理角度)来研究玻璃盘子。这些女性每周工作六天,对这些盘子上的数据进行分类、计算和解释,从而绘制出宇宙地图。

来源:https://commons . wikimedia . org/wiki/File:天文学家 _ Edward _ Charles _ Pickering % 27s _ 哈佛 _ 计算机. jpg

随着使用现代仪器产生大量数据,天文学变得比以往任何时候都更受数据驱动。在处理来自 R 的“dslabs”包的“恒星”数据集时,我遇到了一个有趣的练习,分析一组真实的天文数据,以检查恒星的属性,它们所属的不同类别,它们的表观和绝对星等,光谱类型和表面温度。

一点恒星演化的背景知识和对恒星进行研究和分类的基本属性将进一步帮助理解这项工作。

视在和绝对星等(亮度)

考虑两种光源——手里的手电筒和远处某个点的街灯。从表面上看,人们会得出这样的结论:我们手中的手电筒比远处的路灯更亮。本质上,这个问题转化为恒星亮度。随意看一眼星星并不能帮助揭示这颗星星是附近发光的灰烬还是远处的大灯塔。为了区分一颗恒星看起来有多亮和它实际上有多亮,天文学家使用了表观星等和绝对星等的测量方法。

顾名思义,视亮度是地球上的观测者看到的一颗恒星的相对亮度,而绝对亮度是所有恒星都神奇地放置在相同的标准距离时观测者看到的亮度。

测量表观亮度的一种方法是以每秒的照片数为单位。一个更方便的方法是用一颗突出的亮星与实际恒星的比率来表示。天狼星是最亮的恒星,视星等为-1.46,而肉眼可见的最暗的恒星的星等约为 6。

恒星的表观亮度主要取决于两个因素:

1.实际亮度

2.离地球的距离

另一方面,绝对星等反映了恒星发出的真实光量。因此,我们把这个值表示为恒星的光度。

光谱等级和表面温度

亨利·德雷珀在 1872 年第一个拍摄了恒星光谱。哈佛大学的“女性电脑”随后实现了他拍摄并记录天空中所有明亮星星的梦想。光谱等级很快就根据温度进行了排列,并按照从热到冷的顺序用字母命名——O、B、A、F、G、K 和 M。O 型恒星的最高表面温度可高达 30,000 开尔文,M 型恒星的温度可高达 3,000 开尔文。

让我们用星形来给数据集中的点着色。这种分类描述了恒星光谱的特性,即不同波长产生的光量。

stars %>%
    ggplot(aes(log10(temp), magnitude, col=type)) +
    geom_point() +
    geom_text(aes(label = star)) +
    scale_x_reverse() +
    scale_y_reverse()

温度的密度图显示大多数恒星的温度都很低。

stars %>%
    ggplot(aes(temp)) +
    geom_density()

下面给出的是数据的散点图,x 轴是温度,y 轴是幅度。大多数恒星都遵循递减的指数趋势。这些也被称为主序星,我们稍后会谈到。

stars %>%
    ggplot(aes(temp, magnitude)) +
    geom_point()

由于各种原因,科学家在绘图时并不总是遵循直接的约定,天文学家通常在绘图前转换恒星光度和温度的值。我们将翻转 y 轴,使较低的量值向轴的顶部移动。

stars %>%
    ggplot(aes(log10(temp), magnitude)) +
    geom_point() +
    scale_x_reverse() +
    scale_y_reverse()

赫兹普朗-罗素图

从斯蒂芬-玻尔兹曼定律,我们知道:

像黑体一样,恒星也发出辐射。因此,我们可以利用上述三个性质(光度、半径和温度)来比较和分类恒星。埃希纳·赫茨普龙和亨利·罗素绘制了现在著名的 H-R 图,它成为现代天文学的基本工具。根据绝对星等绘制光谱分类图,他们发现大多数恒星位于图表中的特定区域。

来源:https://Chandra . Harvard . edu/edu/formal/variable _ stars/BG _ info . html

明显的空白区域引发了一个问题:恒星是一定会出现在整个图表中,还是只有在特定的温度和光度组合下才会出现?事实证明,除了上面突出显示的四个区域之外,其他区域的恒星很少或根本不存在。

四个主要的起始序列如下:

主程序

从左上角到左下角的狭窄的恒星带形成了主序。这些恒星反映了太阳内核中的聚变反应。这个序列中较大的恒星(高光度、高温)经历了快速的聚变反应。因此,恒星在这个序列中的位置越高,它的寿命就越短。而且位置越低,寿命越长。

巨人

位于主星序列右上角的星团被称为巨行星。这些恒星大多呈现红色,因为它们的半径大,表面温度低。将所有的氢燃烧成氦后,这些恒星进入了它们生命的最后阶段。

超级巨人

超级巨星的半径比红巨星的半径大,散布在主序和巨星的上方。由于它们的质量,氦碳融合过程在这些恒星中发生得更快,因此它们永远不会成为巨星。超级巨星可以把碳融合成氧,氧融合成氖,氖融合成镁,镁融合成硅,最后,硅融合成铁。有了铁核,超级巨星最终会死于超新星爆炸。根据恒星的原始质量,结果可能是中子星或黑洞。

白矮星

在主序星左下角发现的几颗星星。这些恒星的聚变反应随着碳停止,核心最终开始收缩。外层消散了,剩下的只是恒星的小而冷的核心。白矮星的温度导致黄白色到蓝白色。

由于我们现在可以识别特定的恒星是主序星、红巨星还是白矮星,现在让我们标记我们数据集中的所有恒星,以定位一些特定的恒星。

stars %>%
    ggplot(aes(log10(temp), magnitude)) +
    geom_point() +
    geom_text(aes(label = star)) +
    scale_x_reverse() +
    scale_y_reverse()

我们知道,超级巨星是温度最低、光度最高的恒星。看上面的图,我们看到参宿四和心宿二是这个数据集中的超级巨星。而范玛宁是样本中最不亮的恒星。

如果你仔细观察这幅图,你会看到太阳出现在主恒星序列中。半人马座阿尔法星也是。

恒星演化

在 H-R 图中有一个地方,恒星正在耗尽它们的核燃料。这被天文学家称为“主序关闭”区域。这组星不包含主序列 O 型星。星团越老,越多的主序星会消失。它们会变成巨人、白矮星或超级巨人。这里可以得出的一个重要结论是

H-R 图可以作为测定一起形成的恒星群的工具。

这是一个极其重要的应用,使天文学家能够进一步探测星系中恒星的年龄。

仪表板和深入地图

原文:https://towardsdatascience.com/of-dashcards-and-drill-down-maps-d892d145b10d?source=collection_archive---------56-----------------------

语境为王

为什么,在数据可视化的世界里,上下文才是王道。

几个月来,我们都接触到不断更新的可怕记录,疫情冠状病毒已经并继续在世界各地传播。病例数上升,死亡率上升,感染率上升,一些曲线达到峰值,另一些曲线变平。无论你如何分割,或者如何呈现,这幅画面都相当严峻。然而,在建立我们对新型冠状病毒在世界各个角落的影响的理解时,重要的是要记住,在数据可视化的世界中,上下文是王道。上下文有助于建立理解。

我第一次读到“语境为王”这句话是在的博客文章中,作者是道尔顿·二如,又名qlikkodor。然后找到了其他 消息来源详细阐述了这个想法。在任何情况下,它都是仪表板设计的重要组成部分,但今天我打算展示一个例子,说明在视觉效果中添加上下文如何有助于更准确地描述被测绩效。了解我们每天关注的数字背后的含义,无论是在社会问题上还是在商业领域,是什么推动了特定的绩效指标,以及它如何随着时间的推移而发展,将有助于我们做出更好的决策。

我们可以围绕绩效指标提供的上下文类型通常是以下一种或多种:

  • 时间背景。与之前的可比期间相比如何(即周与周、月与月、工作日与前一周的同一天等)。有时,为了理解当前的数字,了解结果的趋势也很重要。这种趋势可以基于绝对数字,也可以基于一段时间内的变化率。或者两者都有。
  • 可能通过因果关系或相关性与主要 KPI 相关的绩效驱动因素和/或衍生指标。通常,我们正在监控的指标可能是多个事件发生的结果。例如,由于较高的客流量,商店位置的销售额可能会增加,或者由于高点击率的广告活动,网站流量可能会增加,这又会导致更高的在线销售额。或者,由于更积极的检测,确诊的冠状病毒病例增加,但同时阳性率更高。
  • 位置上下文。有时,性能也可能与地理位置相关,因此让用户能够在地理环境中探索数据可能有助于更好地理解结果。这是通过使用地图可视化来实现的。
  • 比例语境。在许多情况下,清楚地了解一个指标相对于另一个指标的比例,可以使其更容易理解,并提供一种方法来执行跨分类维度的比较,如果没有比例性,这些维度可能无法直接进行比较。一个明显的例子是人均国内生产总值,它允许不同国家的国内生产总值进行比较,否则可能会提供一个误导性的数据。

将上述所有内容添加到一个仪表板中似乎是一项令人生畏的任务,但事实并非如此。我们不必将所有类型的上下文提示添加到我们正在监控的所有指标中,只需添加与我们试图传达的内容最相关的信息,这将帮助用户建立对数据的理解,而不会弄乱仪表板和分散对其主要目的的注意力。当有效使用时,上下文将帮助用户避免心算来理解屏幕上的数字,并防止他们对呈现的数据得出错误的结论。

上下文仪表板示例

在过去的几周里,我一直致力于构建一个 Dashcard 可视化对象,以便于可视化某个 KPI 的上下文,并且是一个易于理解的精简视图。为了建立一个概念证明,我决定使用墨西哥卫生部提供的与冠状病毒疫情相关的数据,这导致了下图所示的交互式仪表板。

下面显示的仪表板显示了两个仪表板,一个显示了确诊病例的数量,另一个显示了观察到的死亡人数。除了显示主要指标(总数)之外,每个仪表板还提供以下上下文提示:

  • 指标在过去 14 天内的趋势,包括所述时间段内的最高点和最低点
  • 单日最高纪录,以及该纪录出现的日期
  • 与前一天相比的变化百分比
  • 过去 14 天内某一天到下一天的变化率的历史视图(红/绿条)
  • 前一天发生的事故数量
  • 到前一天为止累积的事件总数
  • 衍生指标(分别为阳性率和死亡率)

仪表盘还有一个向下钻取的 choropleth 地图,用于显示位置环境,并直观地显示各个区域之间的比较情况。当点击一个州时,地图会提供特定于该州的更细粒度的上下文,显示按自治市的细分,以及它们的地理上下文。

地图顶部的按钮允许用户通过更改用于比较地图上各区域的测量值(左侧的按钮组)与仪表板进行交互,还可以通过切换视图在绝对数字和以人口(每 10 万人的发病率)显示的数字之间切换,以及由标记为“Ver por Tasa”的按钮控制的比例环境。您可以看到打开和关闭这种上下文如何描绘出一幅非常不同的画面,从而产生对数据的更好理解。这种切换也会影响显示在两个仪表板对象上的主要 KPI。

最后,底部有一个趋势视图,允许用户查看所选度量的总体趋势,同时还允许他们放大到特定的时间段。

我已经将下面的仪表板作为截图包含在内。如果你喜欢观看互动版本,你可以在这里打开这个演示的主视图

附加上下文提示

上面的概念验证可能仍然受益于我没有机会实现的额外功能,至少现在是这样。例如,我们可能需要在地图上添加一个图例来显示计算区域颜色的比例。此外,地图上的工具提示也可能受益于重新设计,仪表盘中的迷你图也可能受益于一些工具提示。这些功能将很快添加。

关于仪表板

Dashcard 对象是我创建的定制设计,使用 D3.js 库在服务器端预先呈现,并在用户导航仪表板时在客户端更新。它可通过使用描述可视化元素的声明性语言进行配置,类似于 Vega-Lite ,并且元素基于此配置自动对齐,以创建数据的像素完美视图。

它的优点是可以适应任何屏幕大小,以保持元素位置和大小的几何精度,还可以动态地重新调整它们,以适应用户与数据交互时显示的新值。

希望你已经发现这信息。欢迎在下面发表评论,并在 TwitterLinkedIn 上与我联系。

原载于 2020 年 7 月 23 日 https://aftersync.com*。***

模型偏移—实现的逻辑

原文:https://towardsdatascience.com/offsetting-the-model-logic-to-implementation-7e333bc25798?source=collection_archive---------4-----------------------

偏移项对 GLMs 和机器学习中建模速率和提升其他模型的重要性

背景

在我们的财产和意外险领域,我们经常使用一个称为“补偿”的术语,它广泛用于建模费率(计数/风险),如每个风险单位的索赔数量。这有助于模型通过使用简单的代数将响应变量从速率转换为计数保持系数为 1。

但是,我们需要偏移来做这个转换吗?

这个术语可能会让初学者感到困惑,当我第一次介绍这种方法时,我就有这个问题。为什么我们不能通过简单地将计数除以其各自的暴露量来手动导出新的响应变量,而不是使用偏移项?

这两种方法的区别是什么?

我将带您浏览两个版本的对数似然函数,有和没有偏移以显示差异,并突出该方法中遵循的任何差异。

需要注意的重要一点是,偏移应包含在与线性预测值相同的“标度”中。在对数链接模型的情况下,这要求在将偏移变量包括在模型中之前记录偏移变量。

使用偏移项的模型

这是原始形式的回归模型,其中偏移变量(Si)、响应变量 Y、xi 作为独立变量,一组参数θ可通过最大似然法进行估计。这是通过将曝光变量乘以原始形式来实现的。

此外,我们可以通过对两边取自然对数来简化这个方程

现在,这个等式可以改写为θ的似然函数,如下所示

最后,我们得到第一个版本的对数似然方程(有偏移),只有依赖于θ的项将保留在方程中,其他项在微分过程中被忽略:

无补偿项的模型(使用转换的响应变量)

让我们看看另一种情况,当我们将速率(Yi /si )建模为响应变量时,这是我们的新模型方程。

同样,我们得出了与第一种情况相同的等式。

那么,有什么区别呢?两个方程看起来一样。

在第一种情况下,我们假设 yi(计数响应)遵循泊松分布,而在第二种情况下,我们假设(yi/si)具有泊松分布,这第二种假设不合适,这使得我们的模型不正确。

让我们来看看新的可能性函数:

微分时只保留θ相关项后的新方程

现在,我们可以比较对数似然函数(1)和(2),并观察其差异,这两种方法将产生不同的结果。同样,我们已经看到,第二个方程是基于一个关于泊松分布的错误假设,数据不再是整数。 因此,我们可以得出结论,使用一个转换后的速率变量作为响应而没有一个偏移量是不正确的方法

然而,我们仍然可以通过对每个观察值应用相当于暴露量(si)的权重来修正后一种方法。我们可以看到下面的等式与等式(1)等价。

下面我们通过下面的 R 代码例子来了解一下实现上的区别。类似地,这些也可以在其他建模包中实现,两种方法将给出相同的输出。

#Implementation of equation (1) in R
poi_r <- glm(numclaims ~ x1+x2+x3,data=train, family = "poisson", offset=log(exposure))#Implementation of equation (3) in R
poi_r <- glm(numclaims/exposure ~ x1+x2+x3,data=train, family = "poisson", weight = exposure)

offset 的另一种用法

有些情况下,我们已经知道解释变量的影响,与其估计该变量的参数β,不如利用现有信息。

另一种情况是,使用现有的模型输出来提升新模型,例如,您为一个模型训练了 200 次迭代,后来想要从那里重新开始以完成另一个 300 次迭代,而不是从零开始重新开始该过程,您可以提供以前的模型输出作为基本余量或偏移量。

各种统计和机器学习包中的偏移实现

这种实现在 R、SAS、徽记(Willis Tower Watson 的特定于保险行业的 GLM 软件)和 stats models(python 中 sci-kit learn 的统计建模对应物)中非常简单和直接,而在机器学习模型中则不太受欢迎。相反,他们在训练新模型之前使用一些函数来设置基础分数,这个基础分数可以从现有模型或任何已知的变量效应中使用。

或者,ML 算法的这一功能可以帮助我们在建模速率时实现偏移。这种实现在所有情况下都是可能的,其中泊松、伽马和特威迪损失函数已经与 log-link 一起使用。

各种算法中的实现示例

对于 R 中的 GLM,可以使用 Offset()函数来实现偏移,对于 pscl、GBM 和 glmnet 封装,类似的实现也是可能的。

poi_r <- glm(numclaims ~ x1+x2+x3,data=train, family = "poisson", offset=log(exposure))

Python 中 GLM(stats models)的偏移可以使用 exposure()函数实现,这里需要注意的一点是,这不需要记录变量,函数本身会处理并记录变量。

poi_py = sm.GLM(y_train, X_train, exposure = df_train.exposure, family=sm.families.Poisson()).fit()

Python 中 XGBOOST 的偏移可以使用 set_base_margin()函数来实现,这需要一个日志变量。在 lightgbm 中,我们可以在训练前使用set_init_score()。

#Convert training data into DMatrix
dtrain_offset = xgb.DMatrix(data=X_train.iloc[:,2:29],label=y_train)#Before training the model set a base margin into DMatrix  
dtrain_offset.set_base_margin(np.log(X_train['exposure']))

结论

我们讨论了如何使用偏移变量将泊松回归用于速率建模,以及如何在机器学习模型中实现该功能。这里给出的算法示例并不是一个详尽的列表,读者可以探索其他算法,如基于模型的决策树和神经网络。

感谢阅读!我希望这篇文章对你有所帮助。

参考

[## [1] XGBoost 文档—XGBoost 1 . 1 . 0—快照文档

XGBoost 是一个优化的分布式梯度增强库,旨在高效、灵活和可移植…

xgboost.readthedocs.io](https://xgboost.readthedocs.io/en/latest/) [## [2]欢迎阅读 LightGBM 的文档!— LightGBM 2.3.2 文档

LightGBM 是一个梯度推进框架,使用基于树的学习算法。它被设计成分布式的…

lightgbm.readthedocs.io](https://lightgbm.readthedocs.io/en/latest/)

[3]邓肯·安德森及其团队,2007 年,广义线性模型实践指南

[4]https://www.statsmodels.org/

https://en.wikipedia.org/wiki/Poisson_regression

哦,你会去垄断的地方

原文:https://towardsdatascience.com/oh-the-places-youll-go-in-monopoly-96abf70cdbd7?source=collection_archive---------33-----------------------

(照片由来自 PxHere苏西·黑兹尔伍德拍摄)

用马尔可夫链探索稳态概率

桌游概率分析— 有没有更具标志性的二人组?我认为我的想法是如此新颖,将这两种兴趣结合到一个小的研究中,但是一个简单的网络搜索“马尔科夫垄断”显示了这个主题已经被覆盖的广泛程度。然而,有各种不同的方法可以产生不同的结果,这就是美妙之处。这一个更倾向于理论而不是实践,但是也许有一天我会在兔子洞的更深处寻找一个更深的范围。

在上个世纪的大部分时间里,“大富翁”是世界上玩得最广泛的棋盘游戏之一,要成为一名成功的玩家,需要在谈判和资源管理方面深思熟虑的策略。虽然这种人类控制的技能至关重要,但由于游戏是由掷骰子和经常抽牌来控制的,因此对机会的依赖很大。大富翁因在游戏中激起残酷的竞争而臭名昭著,所以关于棋盘上最有可能着陆区域的知识使玩家能够做出更明智的决定,如何实现令人垂涎的最终目标让他们的朋友和家人破产

在垄断游戏中,财务是玩家进步的主要指标,玩家做出的每一个决定都应该最终提高他们的相对净值。话虽如此,分析游戏的财务方面已经超出了本次调查的范围,它只关注玩家在棋盘上的移动。这里的目标是当掷骰数接近无穷大时,确定落在棋盘上 40 个空格中任何一个的概率。这些被称为稳态概率,将通过采用全概率法则和执行马尔可夫链来计算。

游戏概述和分析假设

今天有数百个从最初的垄断衍生出来的游戏,每个都有自己的主题和游戏变化。这项调查是参照游戏的原始版本标准规则进行的,目前由 Hasbro Inc .制作。

图一。棋盘的指定编号规则。

游戏板

大富翁棋盘是正方形的,它的边上排列着 40 个游戏位置,我们称之为空格。游戏从棋盘右下角的空格开始,称为围棋。大多数空间代表玩家可以选择购买的财产,尽管一些空间有其他功能,稍后讨论。如前所述,这项调查只涉及棋盘上标记的移动,因此不考虑游戏的货币含义的任何细节。上面的图 1 显示了游戏棋盘的轮廓,其空格用数字从#0 到#39 标记。该编号惯例将在整个调查中使用。

制图卡

三个空间标记为“公益金”(#2、#17、#33,从这里分别称为 CC1、CC2 和 CC3),三个标记为“机会”(分别为#7、#22、#36 或 CH1、CH2 和 CH3)。落在任何一个上面都会提示玩家从棋盘中央相应的牌组中取出一张抽牌,并按照其指示进行货币交易,或者将代币移动到其他空间;如前所述,这项调查只涉及后者。官方规则要求将抽中的牌放回牌组底部(即抽中的牌的顺序在整个游戏中保持不变),但在本次调查中,我们将把抽中的牌重新洗牌放回牌组,以确保所有的抽牌事件都是随机统计独立的。

监狱

监狱空间(#10)有两个功能。如果一个玩家仅仅通过推进骰子显示的数字而入狱,他们被称为拜访。所有其他的进入监狱的方式都需要逮捕,比如被抽牌指示,或者进入坐牢 (#30)空间(我们称之为 GTJ)。要被释放,玩家必须支付罚款,使用“免费出狱”卡,或者在他们的回合中掷出双倍,否则他们将被拘留。如前所述,我们忽略了游戏中关于滚动双打的方面,所以我们可以假设玩家在被捕后立即支付罚款并在下一轮离开;为了这次调查的目的,在监狱里作为一个访问者和被拘留者是没有区别的。

分析

使用上面建立的约定,我们可以开始计算占据每个板空间的稳态概率的过程。

掷骰子事件

mn表示掷出的两个骰子上显示的数值,其中[m, n∈ 1,6]。由于骰子是公平的,并且它们的结果在统计上是独立的,所以掷出mn的每个组合的概率是1/6 ∙ 1/6 = 1/36。设r表示一次掷骰的总值,即r = m + n(因此[r∈ 2,12]),而q表示产生rmn的组合数。比如r = 12 就是由q = 1组合产生的(其中m = 6n = 6),而 r = 3是由q = 2组合产生的(其中m = 2n = 1,或者m = 1n = 2)。P(R)的概率分布如下图 2 所示。

图二。从两个骰子中掷出总值 r 的概率。

活动和非活动空间

偶尔,在六个 CH 或 CC 格(#2、#7、#17、#22、#33、#36)中的任何一个格落地时抽一张牌,或者 GTJ (#30)来命令移动。这七个空格是棋盘上唯一的空格,如果落在上面,可能会将玩家作为同一掷骰子的一部分发送到其他空格,所以我们将它们称为活动空格。剩余的 33 个空格在任何涉及它们的掷骰中完全肯定是最终目的地,因此被称为非活动 空格

当登陆 CH3 (#36)的玩家抽取指示他们“后退 3 格”从而登陆 CC3 (#33)的牌时,出现了一个值得注意的现象。这在 CH3 内为可能由 CC3 指引的目的地创建了嵌套概率分布。我已经将这些合并到下面表 1 中呈现的总概率分布中,该表显示了被每个活动空间移动到空间j的个体概率。

表 1。被七个活动空间中的每一个移动空间 j 的概率。[如果您看到的是 502 错误而不是表格,几分钟后刷新页面通常可以解决问题]

注意进监狱 (#30)有一个非常简单的分布:被转移到监狱 (#10)的概率为 1,在其他地方的概率为 0。在这里着陆,你肯定会被送进监狱。

在任意两个空间之间移动的概率

M_{i,j}表示令牌将从空间i移动到空间j的事件。为了计算其概率,必须考虑移动的每个潜在因素,包括除了被七个活动空间中的每一个移动之外,仅被骰子的滚动移动的概率。这八个事件总共是互斥的,并且集合起来是穷举的,如根据全概率定律的以下等式所示,其中[a∈ CC1 CC2 CC3 CH1 CH2 CH3 GTJ]。将这些活动空间描述符替换为它们相应的索引号,就得到[a∈ 2 7 17 22 30 33 36]

[等式可能被夹在手机上。别担心——没那么重要:)]

这是一个好的开始,但它有一些漏洞;我们需要做一些调整来解释活动空间的行为。如果j是活动空间,则等式中的第一项必须从计算中排除,以避免重复计算概率。在这种情况下,P(M)成为七个概率的和,而不是八个。

否则,当j为非活动空间时,掷骰子事件肯定是运动的唯一发起者。数学上,这被描述为“从i移动到j的概率,假设掷骰子是j-i,是 100%”,或者P(M|R) = 1

考虑到这些因素后,我们能够更新初始公式,并根据作为活动空间的j的状态将其拆分成不同的情况。

[等式可能被夹在手机上。]

这个更新的等式完全描述了在棋盘上任意两个空格之间移动的概率,很容易求解,因为P(R)P(M|R)的所有项都已经在前面确定了(如图 2 和表 1 所示)。

跃迁矩阵

对于任何给定的空间i,总共有 40 个不同的目的地j,理论上一次滚动可以在这里结束。由于i也可以取 40 个值,所以ij总共有 1600 种不同的组合,因此P(M)的 1600 个值完全描述了在任意两个空间之间移动的概率。通过一点单元格引用的魔力,我在 Excel 电子表格中将它们枚举成一个 40x40 的数组。这被称为转移矩阵,因为它代表了跨越状态对的转移概率。然后,通过一点点条件格式的魔力,我将它们可视化为下面的图 3,其中ij的每个组合的P(M)基于最低非零概率(0.001532)和最高概率(0.173611)之间的从浅到深的线性梯度进行着色;零概率的情况用白色表示。

图三。转换矩阵,说明在空格' i '(行)和' j '(列)之间移动的概率

注意,转移矩阵描述了着陆在j上的概率,假设滚转从i开始,不管它最初是如何到达i的。这就是为什么第 30 行(描述了一个从 GTJ 开始的转折)包含了所有的概率,即使我们知道一个玩家如果没有被立即送进监狱,他根本不可能真正到达那个地方。

稳态概率

T表示上面计算的 40×40 转换矩阵。由于给定i的所有概率P(M)的总和为 1,因此T的每一行的总和为 1。

O_j表示空间j被占据的事件,设U_i表示 1x40 初始状态向量,包含游戏开始时(即第一次掷骰子之前)占据棋盘上每个空间的概率。规则规定每个玩家在 Go 开始游戏,因此U_i的第一个条目(即索引#0)为 1,所有其他条目为 0。

当掷骰子的数量接近无穷大时,O_j的概率分布应该收敛到一个恒定的 40 个值的集合,该集合包括占据棋盘上每个空间的稳态概率。

所有这些都是通过应用马尔可夫链理论联系在一起的。我们首先将初始状态向量设置为当前状态向量 U_c,然后将其乘以转移矩阵T以获得更新后的当前状态向量 U_cu。这个过程一直持续到当前状态向量停止改变值,此时它被称为稳态向量。将当前状态向量乘以转移矩阵的每一次迭代模拟一次掷骰子事件。下面的 Python 脚本遵循这个过程,通过从我存储在“Monopoly.xlsx”中的转移矩阵中提取概率来计算稳态向量。

剧本 1。用于计算稳态向量的 Python 输入。“Monopoly.xlsx”的表 3 包含转换矩阵。

得到的向量就是O_j的稳态概率分布。根据该程序,总共进行了 284 次马尔可夫链迭代(即 284 次理论掷骰子)以使解收敛。

结果

让我们绘制新的稳态分布图,按照概率从高到低排序。

图 4。占据垄断板上任何空间的稳态概率分布

监狱(排名第 10)是最常见的着陆空间,稳态概率为 0.0587。这意味着当掷骰数接近无穷大时,或者更确切地说,当迭代次数达到 284 时,玩家有 5.87%的机会出现在那里。考虑到所有活跃空间送代币坐牢的综合影响,这么高的相对概率并不奇怪。

这种现象的结果是,监狱在某种程度上充当了代币的磁铁,从而增加了代币落在紧随其后的空间中的概率。我们从以下事实中看到了这一点:在监狱之后的 12 个最常去的地方中,有 7 个就在一次掷骰子之内。

概率最高的属性是 Illinois Ave. (#24),它比 Jail 领先 14 个空格,因此相当于两次掷出 7,这当然是骰子显示的最有可能的值(根据图 2)。这一事实,除了 CH2 (#22)给出“前进到伊利诺伊大道”的指令的可能性之外,还使其具有甚至比 Go 更高的稳态概率,其受到 7 个活动空间中的 6 个的影响。

稳态概率的含义

因此,我们知道我们在董事会的最终位置,但这对我们改进战略有多大帮助呢?不提出一些新的问题很难说。首先,什么大富翁游戏持续 284 轮?!我是说,世界上有没有足够多的桌子可以在游戏中翻转到那么远?

由于一个典型的游戏只持续大约每个玩家 30 回合,所以在更少的迭代之后,知道我们的稳态分布有多可靠是很重要的。量 284 本身有些随意,因为它取决于程序用来确定浮点值之间相等的容差。让我们通过向脚本 1 中的 Python 代码添加一个函数来进一步探讨这个问题,该函数将一组迭代次数i_max作为参数。

剧本 2。添加到脚本 1 的 Python 函数,用于计算指定次数迭代后当前状态向量和稳态向量之间的最大差值列表。

不停地提到“稳态向量和当前状态向量中相应元素之间观察到的概率的最大差异”是相当拗口的,所以让单词 tolerance 在这里定义它。上面的函数计算 1 和i_max = 30之间每次迭代次数的公差。还是满嘴?那就尽情享受这个吧:

图五。计算的迭代次数和矢量公差之间的关系。

从图中可以清楚地看到,在大约 11 次滚动后,公差下降到 1%以下,并且在大约 25 次滚动后几乎完全检测不到。因此,我们可以确信,没有必要等待荒谬的大量掷骰来相信稳态概率,但也应该记住,它们直到游戏中的几次掷骰才真正开始成形。

利用群体优化财产所有权

虽然游戏的财务方面超出了本次调查的范围,但还是有必要看一看我们的稳态结果如何进行有意义的聚集。“大富翁”奖励在棋盘上预先定义的类别中拥有和开发 28 个地产空间的玩家,无论是通过铁路公用事业还是八个颜色组中的房地产。下面显示了它们的组合概率。

图 6。群体占有财产的组合稳态概率。

从高层次来看,铁路是赢家。这是很直观的,因为他们的团体比任何其他团体都有更多的成员——董事会上 40 个铁路空间中的 4 个等于 10%,加上一些变化以说明活跃空间的影响。亚军是橙色/红色组,这也与我们之前观察到的距离监狱几个高概率骰子滚动的空间一致。

我们现在去哪里?

我们可以整天继续挑选这样的观察,但这些不是特别有用,因为它们忽略了并非所有的属性都是一样的。

我们现在去哪里?嗯,5.87%的人说坐牢……(照片由伊万·蒙卡达Unsplash 上拍摄)

如果不考虑房地产的成本和预期回报率,只有部分情况是由它们的稳态概率描绘的。毕竟,游戏的目标是货币目标,所以我们不能制定一个稳健的战略计划,除非我们将货币纳入我们的分析。

其他人也对这些财务影响进行了广泛的探索,虽然我现在对垄断有点厌倦,但我完全希望在未来的某个时候尝试一下。不过,就目前而言,我对迄今为止从调查中得到的主要收获感到满意:分析这个游戏比实际玩这个游戏有趣得多。

基于 YoloV3 卫星影像的储油罐容积占有率研究

原文:https://towardsdatascience.com/oil-storage-tanks-volume-occupancy-on-satellite-imagery-using-yolov3-3cf251362d9d?source=collection_archive---------27-----------------------

使用 Tensorflow 2.x 从零开始使用 Yolov3 物体检测模型识别卫星图像中的储油罐,并借助浮头罐产生的阴影计算其所占体积。

来源

在 1957 年之前,我们的地球只有一颗天然卫星:月球。1957 年 10 月 4 日,苏联发射了世界上第一颗人造卫星。自那时以来,来自 40 多个国家的大约 8900 颗卫星已经发射。

美国宇航局在 Unsplash 拍摄的照片

这些卫星帮助我们进行监测、通信、导航等等。这些国家还利用卫星来监视另一个国家的土地及其动向,以评估他们的经济和实力。然而,所有的国家都互相隐瞒他们的信息。

同样,全球石油市场也不完全透明。几乎所有产油国都在努力隐瞒其总的生产、消费和储存量。各国这样做是为了间接地向外界隐瞒他们的实际经济状况,并增强他们的防御系统。这种做法可能导致对其他国家的威胁。

出于这个原因,许多初创公司,如 PlanetOrbital Insight 都出来通过卫星图像来关注各国的此类活动。Thye 收集储油罐的卫星图像并估计储量。

但问题是,人们如何仅仅通过卫星图像来估计坦克的体积?嗯,只有当油储存在浮顶/高位槽时,这才有可能。这种特殊类型的储罐是专为储存大量石油产品,如原油或凝析油而设计的。它由直接位于油顶部的顶盖组成,顶盖随着油箱中油的体积而上升或下降,并在其周围形成两个阴影。正如你所看到的下图,阴影在北面

来源

储罐的(外部阴影)是指储罐的总高度,而储罐内的阴影(内部阴影)显示了浮头/浮顶的深度(即储罐有多少空)。并且体积将被估计为 1-(内部阴影面积/外部阴影面积)。

在这篇博客中,我们将使用 Tensorflow2.x 框架,在 python 语言的卫星图像的帮助下,从头开始实现完整的模型来估计坦克的占用体积。

GitHub 回购

本文的所有内容和全部代码都可以在 this github 资源库中找到

以下是该博客关注的内容列表。我们会一个一个地探索。

目录

  1. 问题陈述、数据集和评估指标
  2. 现有方法
  3. 相关研究著作
  4. 有用的博客和研究论文
  5. 我们的贡献
  6. 探索性数据分析(EDA)
  7. 第一次切割方法
  8. 数据预处理、扩充和 TFRecords
  9. 使用 YoloV3 进行物体检测
  10. 预留量估算
  11. 结果
  12. 结论
  13. 未来工作
  14. 参考文献

1.问题陈述、数据集和评估指标。

问题陈述:

检测浮头罐并估计其中的油的储备/占用体积。随后将图像补片重新组合成增加了体积估计的全尺寸图像。

数据集:

数据集链接:https://www.kaggle.com/towardsentropy/oil-storage-tanks

该数据集包含一个带注释的边界框,卫星图像取自谷歌地球上包含世界各地工业区的储罐。数据集中有 2 个文件夹和 3 个文件。让我们一个一个来看。

  • large_images: 这是一个文件夹/目录,包含 100 张大小为 4800x4800 的卫星原始图像。所有图片均以 id_large.jpg 格式命名。
  • Image _ patches:Image _ patches 目录包含从大图像生成的 512x512 个补丁。每个大图像被分割成 100,512x512 个小块,在两个轴上的小块之间有 37 个像素的重叠。图像补丁按照 id_row_column.jpg 格式命名
  • labels.json: 它包含了所有图片的标签。标签存储为字典列表,每个图像一个。不包含任何浮头罐的图像被标注为“跳过”。边界框标签采用边界框四个角的(x,y)坐标对的格式。
  • labels_coco.json: 包含了与之前文件相同的标签,转换成 coco 标签格式。这里边界框被格式化为[x_min,y_min,width,height]。
  • large_image_data.csv: 包含大图像文件的元数据,包括每张图像的中心坐标和高度。

评估指标:

对于坦克的检测,我们将对每种类型的坦克使用平均精度(AP) ,对所有类型的坦克使用图(平均平均精度)。浮头式水箱的估计容积没有度量标准。

地图是对象检测模型的标准评估度量。地图的详细解释可以在下面的 youtube 播放列表中找到

来源

2.现有方法

卡尔·基耶在他的仓库里使用 RetinaNet 来完成坦克探测任务。他从头开始制作模型,并从这个数据集应用生成的锚盒。这导致浮头罐的平均精度(AP)得分为 76.3%。然后他应用阴影增强和像素阈值来计算它的体积。

据我所知,这是互联网上唯一可用的方法。

3.相关研究工作

基于高分辨率遥感图像估算油罐容积【2】:

提出了基于卫星图像估计油罐容量/体积的解决方案。为了计算坦克的总体积,他们需要坦克的高度和半径。为了计算高度,他们使用了投影长度的几何关系。但是计算影子的长度并不容易。为了突出阴影,使用 HSV(即色调饱和度值)颜色空间,因为通常,阴影在 HSV 颜色空间中具有高饱和度和增加的色调。然后采用基于亚像素细分定位的中值法计算阴影长度。最后,通过霍夫变换算法得到油罐的半径。

在本文的相关工作中,提出了基于卫星图像计算建筑物高度的解决方案。

4.有用的博客和研究论文

借助卫星图像计算储油罐容积的初学者指南【3】:

[## 借助卫星图像计算储油罐容积的初学者指南

在 TankerTrackers.com,我们的使命是借助……展示石油现货市场的鸟瞰图

medium.com](https://medium.com/planet-stories/a-beginners-guide-to-calculating-oil-storage-tank-occupancy-with-help-of-satellite-imagery-e8f387200178)

这个博客是 TankerTracker.com 自己写的。其中一项服务是利用卫星图像追踪几个地理和地缘政治景点的原油储存情况。在这篇博客中,他们详细描述了油罐的外部和内部阴影如何帮助我们估计油罐中的油量。还比较了卫星在特定时间和一个月后拍摄的图像,显示了一个月内储油罐的变化。这个博客给了我们一个直观的知识,那就是体积的估算是如何进行的。

用深度学习温柔介绍物体识别【4】:

本文涵盖了对象检测初学者头脑中出现的最令人困惑的概念。首先,描述物体分类、物体定位、物体识别和物体检测之间的区别。然后讨论了一些主要的先进的深度学习算法,以开展对象识别任务。

对象分类是指将标签分配给包含单个对象的图像。而对象定位意味着围绕图像中的一个或多个对象绘制边界框。目标检测任务结合了目标分类和定位。这意味着这是一项更具挑战性/更复杂的任务,首先通过定位技术在感兴趣对象(OI)周围绘制一个边界框,然后在分类的帮助下为每个 OI 分配一个标签。目标识别不过是上述所有任务的集合(即分类、定位和检测)。

来源

最后,讨论了两大类目标检测算法/模型,它们是基于区域的卷积神经网络(R-CNN)和你只看一次(YOLO)。

对象识别的选择性搜索【T6【5】:

在目标检测任务中,最关键的部分是目标定位,因为目标分类在此之后。分类取决于本地化建议的感兴趣区域(简称区域建议)。更完美的定位将导致更完美的对象检测。选择性搜索是最先进的算法之一,在一些物体识别模型中用于物体
定位,如 R-CNN 和 Fast R-CNN

该算法首先使用有效的基于图的图像分割生成输入图像的子片段,然后使用贪婪算法将较小的相似区域组合成较大的区域。片段相似性基于四个属性,即颜色、纹理、大小和填充。

信号源

区域提案网—详细视图【6】:

RPN(区域建议网络)因其比传统的选择性搜索算法更快而被广泛用于目标定位。它从特征图中学习感兴趣对象的最佳位置,就像 CNN 从特征图中学习分类一样。它负责三个主要任务,首先生成锚框(从每个特征地图点生成 9 个不同形状的锚框),其次,将每个锚框分类为前景或背景(即,它是否包含对象),最后,学习锚框的形状偏移以使它们适合对象。

更快的 R-CNN:利用区域提议网络实现实时目标检测【7】:

更快的 R-CNN 模型解决了前两个相对模型(R-CNN 和快速 R-CNN)的所有问题,并使用 RPN 作为区域提议生成器。其架构与快速 R-CNN 完全相同,只是它使用 RPN 而不是选择性搜索,这使得它比快速 R-CNN 快 34 倍。

来源

使用 YOLO、YOLOv2 和现在的 YOLOv3 进行实时对象检测【8】:

在介绍 Yolo(你只看一次)系列模型之前,我们先来看看它的首席研究员 Joseph Redmon 在 Ted Talks 上的演示。

该模型位于对象检测模型列表的顶部有许多原因。但是,最主要的原因还是它的牢度。它的推断时间非常少,这是它容易匹配视频的正常速度(即 25 FPS)并应用于实时数据的原因。下面是 Yolo 网站提供的 YoloV3 在 COCO 数据集上的精度和速度对比。

来源

与其他物体检测模型不同,Yolo 模型具有以下特征。

  • 单个神经网络模型(即分类和定位任务将从同一模型执行):将照片作为输入,并直接预测边界框和每个边界框的类别标签,这意味着它只看图像一次。
  • 由于它对整个图像而不是图像的一部分执行卷积,因此它产生非常少的背景错误。
  • YOLO 学习物体的概括表示。当在自然图像上训练和在艺术品上测试时,YOLO 远远胜过 DPM 和 R-CNN 等顶级检测方法。由于 YOLO 是高度概括的,当应用于新的领域或意想不到的输入时,它不太可能崩溃。

是什么让 YoloV3 比 Yolov2 优秀。

  • 如果你仔细看了 yolov2 论文的标题,那就是“YOLO9000:更好、更快、更强”。是 yolov3 比 yolov2 好很多吗?好吧,答案是肯定的,它更好但不是更快更强,因为暗网架构的复杂性增加了。
  • Yolov2 使用 19 层暗网架构,没有任何残留块、跳过连接和上采样,因此它很难检测到小对象。但是,在 Yolov3 中添加了这些功能,并使用了在 Imagenet 上训练的 53 层 DarkNet 网络。除此之外,还堆叠了 53 层卷积层,形成了 106 层完全卷积层架构。

来源

  • Yolov3 在三个不同的尺度上进行预测,首先是在 13X13 网格中预测大型物体,其次是在 26X26 网格中预测中型物体,最后是在 52X52 网格中预测小型物体。
  • YoloV3 总共使用 9 个锚盒,每个音阶 3 个。使用 K-均值聚类来选择最佳锚盒。
  • Yolov3 现在对图像中检测到的对象执行多标签分类。通过逻辑回归预测对象置信度和类别预测。

5.我们的贡献

我们的问题陈述包括两个任务,第一个是浮头罐的检测,另一个是阴影的提取和被识别的罐的体积的估计。第一项任务基于目标检测,第二项任务基于计算机视觉技术。让我们描述一下解决每项任务的方法。

储罐检测:

我们的目标是估计浮头罐的容积。我们可以为单个类建立目标检测模型,但是,为了减少模型与另一种坦克(即坦克/固定头坦克和坦克群)的混淆,并且为了使其稳健,我们提出了三个类目标检测模型。 YoloV3 具有用于物体检测的转移学习,因为它易于在不太特定的机器上训练。此外,为了增加度量值,还应用了数据增强

阴影提取和体积估计;

阴影提取涉及许多计算机视觉技术。由于 RGB 颜色方案对阴影不敏感,我们必须先将其转换为 HSV 和 LAB 颜色空间。我们已经使用-(l1+l3)/(V+1)(其中 l1 是 LAB 颜色空间的第一个通道值)比率图像来增强阴影部分。之后,通过阈值化 0.5t1 + 0.4t2(其中 t1 是最小像素值,t2 是平均值)对增强的图像进行滤波。然后用形态学操作(即,清晰的噪声、清晰的轮廓等)处理阈值图像。最后,提取两个坦克阴影轮廓,然后通过上述公式估计所占体积。这些想法摘自下面的笔记本。

[## 油罐容积估算

使用 Kaggle 笔记本探索和运行机器学习代码|使用储油罐中的数据

www.kaggle.com](https://www.kaggle.com/towardsentropy/oil-tank-volume-estimation)

遵循整个管道来解决此案例研究,如下所示。

让我们从数据集的探索性数据分析开始吧!!

6.探索性数据分析

探索 Labels.json 文件:

作者代码

作者图片

所有的标签都存储在字典列表中。总共有 10K 的图像。不包含任何坦克的图像标记为跳过,包含坦克的图像标记为坦克坦克群浮头坦克。每个坦克对象都有字典格式的四个角点的边界框坐标。

计数对象:

作者图片

在 10K 图像中,8187 幅图像没有标签(即它们不包含任何坦克物体)。此外,至少包含一个坦克群对象的图像有 81 个,至少包含一个浮头坦克的图像有 1595 个。

在条形图中,可以观察到包含图像的 1595 个浮头罐中的 26.45%的图像仅包含一个浮罐对象。单个图像中浮动头坦克对象的最大数量是 34。

探索 labels_coco.json 文件:

作者代码

作者图片

该文件仅包含浮头罐的边界框以及字典格式列表中的图像 id

绘制边界框:

作者图片

有三种坦克:

1.坦克(吨)

2.坦克集群,

3.浮头罐(FHT)

7.首次切割方法

在 EDA 中,已经观察到 10000 个图像中的 8171 个是无用的,因为它们不包含任何对象。此外,1595 个图像包含至少一个浮头坦克对象。我们知道,所有的深度学习模型都渴望数据,如果没有足够的数据,性能就会很差。

因此,我们的第一种方法是数据扩充,然后将获得的扩充数据拟合到 Yolov3 对象检测模型中。

8.数据预处理、扩充和 TFRecords

数据预处理:

观察到对象的注释以具有 4 个角点的 Jason 格式给出。首先,从这些角点中提取左上和右下点。接下来,属于单个图像的所有注释及其相应的标签都保存在 CSV 文件的单行列表中。

从角点提取左上角和右下角点的代码

作者代码

CSV 文件将如下所示

作者图片

为了评估该模型,我们将保留 10%的图像作为测试集。

作者代码

数据扩充:

正如我们所知,物体检测需要大量的数据,但我们只有 1645 张图像用于训练,这非常少。为了增加数据,我们必须进行数据扩充。在这个过程中,通过翻转和旋转原始图像来生成新图像。所有的功劳都归入下面的 GitHub 库,代码就是从这里提取的。

[## 边界框的数据扩充:翻转

当谈到从深度学习任务中获得良好的表现时,数据越多越好。然而,我们可能只会…

blog.paperspace.com](https://blog.paperspace.com/data-augmentation-for-bounding-boxes/)

通过执行以下动作,从单个原始图像生成 7 个新图像:

  1. 水平翻转
  2. 旋转 90 度
  3. 旋转 180 度
  4. 旋转 270 度
  5. 水平翻转和 90 度旋转
  6. 水平翻转和 180 度旋转
  7. 水平翻转和 270 度旋转

下面显示了一个示例

作者图片

TFRecords 文件:

TFRecords 是 TensorFlow 自己的二进制存储格式。当数据集太大时,这通常是有用的。它以二进制格式存储数据,会对定型模型的性能产生重大影响。复制二进制数据需要的时间更少,而且占用的空间也更少,因为在训练时只加载一批数据。你可以在下面的博客中找到它的详细描述。

[## Tensorflow 记录?它们是什么以及如何使用它们

自 2015 年 11 月推出以来,对 Tensorflow 的兴趣稳步增长。一个鲜为人知的组成部分…

medium.com](https://medium.com/mostly-ai/tensorflow-records-what-they-are-and-how-to-use-them-c46bc4bbb564)

你也可以查看下面的 Tensorflow 文档。

[## TFRecord 和 tf.train.Example | TensorFlow 核心

为了有效地读取数据,将数据序列化并存储在一组文件(每个文件 100-200MB)中会很有帮助,这些文件…

www.tensorflow.org](https://www.tensorflow.org/tutorials/load_data/tfrecord)

我们的数据集已经被转换成 RFRecords 格式。这个任务没有必要,因为我们的数据集并不庞大。然而,这样做是为了获取知识。如果感兴趣,您可以在我的 GitHub 资源库中找到代码。

9.使用 YoloV3 的对象检测

培训:

为了训练 yolov3 模型,使用了迁移学习。第一步包括加载暗网网络的权重,并冻结它以在训练期间保持权重不变。

我们已经使用 adam optimizer(初始学习率=0.001)来训练我们的模型,并应用余弦衰减来降低学习率与历元数的关系。训练过程中使用模型检查点保存最佳权重,训练完成后保存最后一个权重。

损失图:

作者图片

Yolo 损失函数:

用于 Yolov3 模型训练的损失函数相当复杂。Yolo 在三个不同的尺度上计算了三个不同的损失,并求和用于反向传播(正如您在上面的代码单元格中所看到的,最终损失是三个不同损失的列表)。每个损失借助 4 个子函数计算定位和分类损失。

  1. 中心(x,y)的均方差(MSE)。
  2. 边界框的宽度和高度的均方误差(MSE)。
  3. 包围盒的二元交叉熵客观分数和无客观分数
  4. 包围盒的多类预测的二元交叉熵或稀疏分类交叉熵。

让我们看看 Yolov2 中使用的损失公式,并检查不同的来源

来源

Yolov2 中的最后三项是平方误差,而在 Yolov3 中,它们被交叉熵误差项所取代。换句话说,Yolov3 中的对象置信度和类预测现在是通过逻辑回归来预测的。

看看 Yolov3 损失函数的实现

分数:

为了评估我们的模型,我们使用了测试和训练数据的 AP 和 mAP

测试分数

作者代码

作者图片

训练成绩

作者代码

作者图片

推论:

让我们看看模型是如何表演的!!

作者图片

作者图片

10.保留体积估算

体积的估算是本案例研究的最终结果。没有度量标准来评估储罐的估计容积。然而,我们已经尝试提出图像的最佳阈值像素值,以便可以在很大程度上检测阴影区域(通过计算像素数量)。

我们将使用由卫星捕获的形状为 4800X4800 的大图像,并将其分成 100 个 512x512 的小块,在两个轴上的小块之间有 37 个像素的重叠。图像补丁按照 id_row_column.jpg 格式命名。

每个生成的预测补丁将被存储在一个 CSV 文件中。我们只储存了一个浮头水箱的包围盒。接下来,估计每个浮头罐的体积(代码和解释可以在我的 GitHub 存储库中以笔记本格式获得)。最后,所有的图像块以及边界框与标签合并,作为大图像的估计体积。你可以看看下面给出的例子:

作者图片

11.结果

浮头式水箱在试验装置上的 AP 分数为 0.874,在列车装置上的 AP 分数为 0.942。

12.结论

  • 仅用有限数量的图像就获得了相当好的结果。
  • 数据扩充工作做得很好。
  • 在这种情况下,与 RetinaNet 模型的现有方法相比,yolov3 表现良好。

13.未来的工作

  • 对于浮头罐,获得了 87.4%的 AP,这是很好的分数。然而,我们可以尝试在某种程度上增加分数。
  • 我们将尝试用增强生成的更多数据来训练这个模型。
  • 我们将尝试训练另一个更准确的模型,如 yolov4、yolov5(非官方)。

14.参考

[1] 油罐容积估算,作者:Karl Heyer,2019 年 11 月。

[2] 根据高分辨率遥感图像估算油罐容积王童,,俞胜涛,,2019 年 4 月。

[3]TankerTrackers.com2017 年 9 月借助卫星图像计算储油罐容积的初学者指南。

[4] 深度学习物体识别温柔介绍作者https://machinelearningmastery.com/,2019 年 5 月。

[5] 由 el 的 J.R.R. Uijlings 进行的对象识别的选择性搜索。2012

[6] 地区提案网 Sambasivarao 的详细观点。k,2019 年 12 月

[7] 更快的 R-CNN:通过区域提议网络实现实时对象检测 Ross Girshick 等人,2016 年 1 月。

[8]Joseph Redmon 于 2015 年至 2018 年利用 YOLO约洛夫 2 和现在的约洛夫 3 进行实时物体检测

申请课程:https://www.appliedaicourse.com/

感谢您的阅读!这是我的 LinkedIn 和 Kaggle 简介

旧的健康行为正在塑造我们的“新常态”

原文:https://towardsdatascience.com/old-health-behaviors-are-shaping-our-new-normal-fbe6b6c072dd?source=collection_archive---------58-----------------------

利用 CDC 普查数据了解人口健康史如何影响新冠肺炎传播

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

  • COVID 死亡数据基于该市出现首例确诊病例后的第 100 天。

2020 年已经过去 200 天了,“新常态”仍然每天都在制造恐慌。曲线仍然没有变平,我们开始问自己:什么是新常态?更重要的是,我们能做些什么来帮助自己和他人度过难关?

在新冠肺炎有成百上千的谣言:仅仅是流感吗?年轻人对它免疫吗?是不是只对有潜在病症的人有危险?简答:没有,没有,也没有。然而,从公共卫生数据中,我们也许能够了解谁更容易受到病毒的攻击,以及社区应该做些什么来保护你和你所爱的人。

数据概述

为了了解人口健康历史如何影响新冠肺炎的传播,我们结合了来自 data.world500 个城市:改善健康的本地数据、来自 CDC 的 2018 年发布以及来自 simplemaps 的制图数据的每日 COVID 活动数据。

COVID 措施:由于首例确诊病例日期在 2 月至 4 月,我们使用该地区首例病例发生后第100 天的数据,以减少病毒传播时间造成的差异。

按城市分列的首例确诊 COVID 病例的日期

  • 死亡人数 100 万——各县每 100 万人的死亡人数

人口健康指标:该数据包括与美国 500 个城市的不健康行为、健康结果和预防服务使用情况相关的 27 项慢性病指标。这些值以百分比显示。更多详情,请访问 CDC 项目页面

按类别衡量

市/县制图:市/县制图数据用于合并上述两个数据集。如果一个县包括多个城市,我们假设所有城市的 COVID 死亡率相同。

在合并和清理数据后,我们有 497 个城市的 COVID 指标、27 个健康指标和人口密度。

数据摘要—直方图

什么因素影响着一个地区的 COVID 死亡人数?

我们知道什么:

  • 早期首次确诊新冠肺炎病例的地区更有可能一开始准备不足,遭受更严重的打击。
  • 如果没有疫苗,从长远来看,确诊病例总数可能就不那么重要了。合理安排资源以降低死亡率对“新常态”至关重要。

假设 100 天对于大多数地区来说足以稳定局势并宣布安全条例,我们将从分析我们的健康措施和自第一例病例以来第 100 天死亡 1 百万人之间的系数开始。

让 a̶w̶a̶y̶医生保持亲密

这张图表可能会压倒我们所有的措施,但快速看一下下面 0 的部分:根据皮尔逊系数,与死亡病例负相关的 6 项措施中有 5 项是预防服务*。这可能表明更好的健康意识,以及更好的医疗保健系统体验

哪些群体更容易受到新冠肺炎病毒的攻击?

为了更好地理解这个问题,我们使用 OLS 回归模型来调查在某一地区哪些措施对新冠肺炎的死亡率有更强的影响。

从拟合的模型中,我们在训练集上获得了一个 0.508 的调整后 r 平方得分,这意味着我们在模型中使用的健康指标解释了一个地区50.8%的 COVID 死亡率。如果我们使用这个模型来预测测试数据,r 平方得分是 0.236 ,这是合理的,因为病毒造成的损害还受到许多其他因素的影响,例如采取了哪些安全法规,人们在社交距离方面做得如何,以及我们对病毒本身还不了解的其他 100 件事情。

现在来看看模型中具有统计显著性(p ≤ 0.05)的测量值:

在 27 项措施中,6 项健康状况、3 项预防服务和 1 项不健康行为对每百万人的 COVID 死亡率有显著影响。关节炎、哮喘、高胆固醇和缺乏闲暇时间的体力活动与 COVID 死亡病例有很强的正相关性。

等等,看起来有些不对劲

看看这个结果,它是否告诉我癌症和糖尿病降低了 COVID 死亡风险,而做牙科和常规检查使我们更容易受到伤害?

这些“奇怪的结果”背后有很多潜在的原因。例如,在我们的数据中,成年人的癌症发病率在 4%到 7%之间,这比大多数其他指标低得多。在这种情况下,即使在人群中患癌症和 COVID 死亡之间没有因果关系,如果某些地区碰巧有高癌症率和高 COVID 死亡,它也可能导致模型中的强正相关。

另一个例子是常规检查。如果我们绘制死亡率和常规检查,我们可以看到:

  • 东海岸和西海岸的常规体检率差别很大
  • 大多数既有高体检率又有高 COVID 死亡率的地区都来自少数几个州(马萨诸塞州、新泽西州。纽约)

每 100 万人中常规检查和 COVID 死亡的百分比

在美国 COVID 爆发的开始阶段,所有这些州都受到了严重打击,这可能是巧合吗?这么高的死亡人数会不会是医院在第一次增兵时压力过大的结果?根据我们有限的数据,很难得出进一步的结论。但随着病毒传播速度继续稳定,我们预计会有更清晰的前景。

结论

  1. 高关节炎、哮喘、高胆固醇和缺乏闲暇时间体育活动率与高新冠肺炎死亡率密切相关。
  2. 而人口健康指标可以解释 50%的新冠肺炎死亡率。目前还不足以预测病毒的传播,因为有太多的不确定因素。
  3. 从长远来看,卫生措施将更有价值,有助于社区采取行动保护更易受病毒感染的人。

你是如何适应“新常态”的?你有什么想法可以让这项研究更好吗?在下面留下评论,让我知道你的想法!所有数据和模型都可以在项目 git repo 中找到。

资源:

Git Repo:https://github . com/Estella-zzz/data-science-projects/tree/master/covid 19 _ vs _ Population _ Health

把它形象化成画面:【https://public.tableau.com/profile/estella.zhang#! /viz home/covid 19 vspopulationhealth/CovidPopulationHealth

*所有健康措施列表:

OLS 回归、高斯-马尔可夫、蓝色和理解数学

原文:https://towardsdatascience.com/ols-linear-regression-gauss-markov-blue-and-understanding-the-math-453d7cc630a5?source=collection_archive---------2-----------------------

弄清楚 OLS 假设(它们可能不是你想的那样……)

照片来自researchgate.net

背景和动机

对于任何从事统计学或机器学习研究的人来说,普通最小二乘(OLS)线性回归是第一个也是最“简单”的方法之一。虽然我已经注意到,在这个领域,在这个平台上,对 OLS 估计量有很多困惑。对有效的 OLS 估计“需要”什么样的假设,以及它与其他估计量的关系的困惑。我写这篇文章是为了从数学角度对 OLS、高斯-马尔科夫定理以及满足不同条件所需的假设进行深入的解释。请注意,在本文中,我是从频率主义范式(与贝叶斯范式相反)出发的,主要是为了方便起见。所以,让我们开始吧:

你可能在某个时候被问过以下问题:

我现在要做一个评论,有些人(起初)可能会觉得有争议或违背直觉。我的评论是:

这个问题无法回答,主要有两个原因:

  1. 术语“线性回归”没有很好的定义,并且没有指定唯一的目标函数。诚然,我通常让这个问题滑一点;当人们通俗地说“线性回归”时,我想他们指的是 OLS 线性回归。然而,为了在我们的语言中更加明确,我们应该明确提到 OLS 的名字。
  2. “OLS 线性回归需要什么假设”这个问题仍然是一个不适定且无法回答的问题。为什么?因为我们还没有明确说明我们要用 OLS 线性回归做什么,也没有明确说明我们对它有什么要求?例如:

上述期望的属性都是不同的,并且需要不同的假设来满足它们。这些只是我们可能感兴趣的一些期望的属性和场景,当然还有更多。因此,当指定一个统计模型并问自己“需要什么假设”时,我们需要首先回答“我们要用这个统计模型做什么,我需要从中获得什么?”。在没有这种背景的情况下,质疑统计模型的“必要假设”将永远是一个根本不适定的问题。

我们将花大量时间深入研究 OLS 估计量,了解它在不同条件下的性质,以及它与其他估计量的关系。大纲如下:

  1. 高斯-马尔可夫定理和“标准”假设
  2. 恢复 OLS 估计量
  3. OLS 估计量在什么条件下是无偏的证明
  4. 不同条件下 OLS 估计量的无偏和一致方差估计
  5. 标准 GM 假设下的证明 OLS 估计量是蓝估计量
  6. 与最大似然估计的联系
  7. 总结和最后的想法

1.高斯-马尔可夫定理和“标准”假设

在开始恢复 OLS 估计量本身之前,让我们先谈谈高斯-马尔可夫定理。

高斯-马尔可夫(GM)定理指出,对于一个加性线性模型,在“标准”GM 假设误差不相关且同方差且期望值为零的情况下,普通最小二乘(OLS)估计器在线性无偏估计器类中具有最低的抽样方差。这似乎有点拗口。下面开始更具体地梳理一下上面的内容。

关于符号的快速迂回:

关于记谱法,我想做两点说明:

到目前为止,我们已经使用的符号,以及除了这一小段之外,将在本文的其余部分使用的符号,是来自概率论和数理统计领域的“经典”符号。然而,关于 OLS 估计的相同材料通常在计算机科学系的机器学习(ML)入门课程中讲授,并且通常使用上面注#2 中直接显示的替代符号来呈现。对这种替代符号的仔细研究揭示,与“经典”符号相比,矩阵和向量的几个维度被调换,截距项位于参数向量之外,并且参数向量和数据矩阵按照它们的内积的顺序被交换。

作为一名训练有素的统计学家,我并不特别喜欢这种替代符号,也从来没有完全理解它为什么存在?检查这种材料的历史,我不清楚为什么 ML 社区的计算机科学分支建立了一种“镜像的”和稍微向后的符号,这种符号已经在统计社区中存在了几十年了?在 ML 成为一个领域之前,已经有大量的工作(证明、定理等)用“经典”符号解决了;在人工智能和人工智能中非常有用和有价值的定理。转换所述证明和定理以匹配上面的替代符号是(我觉得)很多额外的工作和不必要的混乱。

总之,我的咆哮到此为止。我希望读者至少意识到这种替代符号,因为那些对人工智能和 ML 感兴趣的人肯定会遇到它。但是,在本文的其余部分,我们将使用“经典”符号。

2.恢复 OLS 估计量

既然我们已经讨论了高斯-马尔可夫定理,让我们恢复 OLS 估计量。

关于恢复 OLS 估计量的方法的说明:

请注意,我们解析地求解了上述 OLS 估计量,假设 OLS 估计量恰好具有封闭形式的解。然而,当将我们的模型拟合到实际数据时,我们可以使用迭代数值技术(如梯度下降或牛顿-拉夫森)来恢复我们指定的模型参数的经验估计值。如果我们正确地实现这些数值技术并使它们收敛,它们将恢复与我们上面求解的闭合形式解相同的参数估计。在未来的一篇文章中,我将深入概述拟合统计模型的迭代数值技术,敬请关注。

3.OLS 估计量在什么条件下是无偏的证明

接下来让我们证明在什么条件下 OLS 估计量是无偏估计量:

正如我们在上面看到的,OLS 估计量要成为无偏估计量,并不需要所有的“标准”高斯-马尔可夫假设。误差项不必是同方差的,也不必是不相关的。现在,在所有无偏线性估计量中,OLS 估计量会是方差最小的无偏估计量吗?不一定。这是我们在第 5 节讨论的内容。

4.不同条件下 OLS 估计量方差的无偏和一致估计

接下来,让我们在“标准”GM 假设下恢复 OLS 估计量的方差:

现在,如果不是所有标准的 GM 假设都成立呢?如果唯一成立的假设是所有误差项的期望值为零,那会怎样?

5.标准 GM 假设下的证明 OLS 估计量是蓝估计量

在 GM 假设下,OLS 估计量是 BLUE(最佳线性无偏估计量)。这意味着,如果标准的 GM 假设成立,在所有可能的线性无偏估计量中,OLS 估计量是方差最小的,因此是最有效的。让我们证明这一点:

6.OLS 和最大似然估计之间的联系

在许多统计学入门课程中,经常(很少)教授 OLS 线性回归所需的硬性假设是误差项必须是正态分布且同分布和独立分布。然而,正如我们在本文的大部分内容中所看到的,我们设法为 OLS 推导出了相当多的理论和证明,而没有做出任何明确的正态性或同分布假设?那么这些额外的假设在哪里发挥作用呢?

这些正态性和独立同分布假设是 OLS 和最大似然估计(MLE)之间的“桥梁”。如果我们有一个线性加性模型,并且我们的 n 误差项都是正态分布的并且是同分布的,那么最大似然估计在数学上就简化为 OLS 估计。换句话说,这些是最大似然估计和 OLS 成为同一事物的唯一条件。我不打算在这里给出证明,但是在以后的文章中,我计划深入研究最大似然估计,所以请继续关注。

7.总结和最后的想法

作为一个快速总结,下表提供了我们在本文中讨论的关于可加线性估计的一些内容的概述(期望的性质,以及满足它们的必要要求)。

关于放松一些经典高斯-马尔科夫假设的方法和分析的入门,请参见我的文章

我希望这篇文章有助于澄清关于 OLS 线性回归的误解,并在更高的层次上,为为什么在进入“必需的假设”之前,考虑您正在处理的问题的背景以及您需要模型的什么类型的属性是至关重要的提供背景。总是问自己“所需假设 做什么?”。如果你不能清楚地回答“ 做什么 ”部分的问题,那么你就没有准备好列出任何所需的假设。

希望以上有见地。正如我在以前的一些文章中提到的,我认为没有足够的人花时间去做这些类型的练习。对我来说,这种基于理论的洞察力让我在实践中更容易使用方法。我个人的目标是鼓励该领域的其他人采取类似的方法。我打算在未来写一些基础作品,所以请随时在 LinkedIn 上与我联系,并在 上关注我在 上的更新!

全渠道营销:我们如何评估其影响?

原文:https://towardsdatascience.com/omni-channel-marketing-how-can-we-evaluate-its-impact-922949458682?source=collection_archive---------57-----------------------

亚伦·塞巴斯蒂安在 Unsplash 上拍摄的照片

应用向量自回归(VAR)模型,利用 R

营销不像过去那么简单了。在这个数字时代,我们接触到许多不同的渠道和媒体平台,典型的客户旅程不再遵循简单的线性路线。对于营销人员来说,这是一个问题。我们如何知道哪种营销媒介是销售的结果?每种营销媒介的效果如何?这些营销媒体是如何相互作用的?

我们可以通过使用向量自回归(VAR)模型来回答上述问题,该模型可以捕捉时间序列中不同营销支出之间的不同相互依赖关系。下面可以看到一个例子。

使用的数据集是一个时间序列,包含 14 个属性和 191 周的数据,涵盖营销媒体的每周营销支出、根据在线和离线营销漏斗阶段的指标以及收入。但是,出于此目的,我们将只使用营销支出属性和收入。

要使用时间序列和 VAR 模型,我们需要安装下面的库。

library(tseries)
library(vars)

然后我们读取数据。

*# View data*
data <- read_excel("dataset_var.xls")
kable(head(data))%>%
  kable_styling()

作者图片

首先,我们将数据设置为时间序列对象。因为有 191 周,这将超过 3.5 年的数据。因此,我将频率设置为 52,代表一年中的 52 周。

*# Time series for all attributes*

flyer <- ts(data[,2], frequency=52)
catalog <- ts(data[,3], frequency=52)
adwords <- ts(data[,4], frequency=52)
email <- ts(data[,5], frequency=52)
rev <- ts(data[,14], frequency=52)

在我们可以估计和运行风险值模型之前,重要的是序列是平稳的。这里不包括时间序列的准备和检验,因此下面假设该序列没有季节性和趋势性。

构建风险值模型

我们用传单、目录、广告词、电子邮件和收入作为变量来估计模型。在此之前,传单、目录、电子邮件和收入系列已经进行了日志转换,而 adwords、电子邮件和收入系列则首次实现了差异化。

现在我们的时间序列是平稳的,我们从所有的序列中构建一个数据框架,并估计 VAR 模型。

*# Build a data frame*
data.ts <- window(cbind( log_flyer, log_catalog, adwords.diff1, log_email.diff1, log_rev.diff1))# Remove rows with nulls
data.ts1 <- na.omit(data.ts)# Estimate VAR model
var.m1 <- VAR(data.ts1, ic="AIC", lag.max=1, type="const")

df <- var.m1$varresult# Display using stargazer
stargazer(df$log_flyer, df$log_catalog, df$adwords.diff1,
          df$log_email.diff1, df$log_rev.diff1,
          column.labels = c('flyer', 'catalog', 'adwords', 'email',
                            'rev'),
          type = "text", 
          dep.var.labels.include = FALSE)

作者图片

解释结果

下面的示例说明了读取结果的简化方法:

作者图片

示例:

结转效应:电视过去一段时间的支出有 1%被结转到未来。

交叉效应:广告词每增加 1%,电视消费效应增加 d%

对销售的直接影响:电视支出每增加 1%,收入就会增加 c%

反馈效应:过去销售增长 1%会对下一期电视产生 g%的影响。

请注意,这些是弹性,所以如果变量是对数转换,他们解释为百分比(%)。否则,其值保持原样。另一方面,如果变量已经差分,那么它们可以用增长来解释。

现在回到我们的结果表。

结转效应 :
一般来说,所有过去的营销支出都不会结转到未来。事实上,所有这些都产生了负面影响,其中传单增长了 0.18%,目录增长了 0.038%,广告词增长了 0.043%,电子邮件增长了 0.473%。

交叉效应 :
传单对目录有积极的交叉效应,传单支出每增加 1%,目录的支出效应就会增加 0.032%。但是,flyer 对 Adwords 和 email 没有正面作用。传单支出每增加 1%,Adwords 支出效应就会减少 3.97 美元,电子邮件增长支出效应就会减少 0.11%。

另一方面,目录对传单、Adwords 和电子邮件没有正面的支出效应,目录支出每增加 1%,传单的支出效应就会降低 0.166%,Adwords 的支出效应会降低 6.185 美元,电子邮件的增长支出效应会降低 0.236%。

Adwords 仅对目录有正面影响,但几乎可以忽略不计。在 Adwords 上增加 1 美元的支出,会对目录产生 0.04%的正支出效应。对传单的支出效应和对电子邮件增长的支出效应受到负面影响,但也可以忽略不计,均为-0.2%。

电子邮件增长的支出效应对目录和 adwords 有积极的支出效应,但对传单有消极的支出效应。发出的电子邮件数量增加 1%会使传单支出的有效性降低 0.01%,目录支出的有效性增加 0.042%。然而,对于 Adwords 而言,电子邮件增长支出每增加 1%,Adwords 支出的有效性就会增加 0.04 美元。

反馈效应 :
除了 Adwords 之外,营收通常对所有业务都有正反馈效应。过去销售增长 1%会对下一期 Adwords 产生 0.29 美元的负面影响,而对传单、目录和电子邮件增长产生 0.656%、0.867%和 0.029%的正面影响。

对销售的直接影响 :
传单、目录和广告词对销售有积极影响。传单支出增加 10%会影响销售增长 0.01%,目录支出增加 10%会增加销售增长 0.01%,Adwords 支出增加 1 美元会增加销售增长 0.02%。然而,发送的电子邮件数量增长 10%会使收入增长降低 0.001%。

然而,值得注意的是,这些系数中没有多少是重要的。根据该表,只有传单和电子邮件的遗留效应、传单对电子邮件的交叉效应、目录的反馈效应和购买强化效应(-0.339)具有统计显著性。表中的星号(*)表示重要性。

剩余检查

最后,我们应该检查模型的残差,以确保它没有被错误指定。这可以通过确保平均残差为零且没有异常值来实现。

*# Check mean residuals of Sales*
rev.residuals <- data.frame(residuals(var.m1))$log_rev.diff1
rev.residuals <- ts(rev.residuals, frequency = 52, start = c(1, 1))
round(mean(rev.residuals),52)

给定的值是-2.272712e-17,实际上是 0。我们也可以画出残差图来直观地检查它。残差应围绕值为 0 的 y 轴均匀“反弹”。

*# check residual plots*
autoplot(rev.residuals)

作者图片

从残差检验中,我们看到该模型是合适的,因此可以接受。

营销人员的关键点

当计划营销组合策略时,从估计的风险值模型中解释的影响可以是有用的信息来源。媒体之间以及与销售之间的互动现在可以很容易地被隔离。

通过对销售效果的直接影响,营销人员可以将销售归因于每种媒体,同时消除每种媒体可能从其他媒体建立的影响。

另一方面,交叉效应可以让营销人员一瞥哪种媒体互相影响,哪种媒体不影响,哪种媒体互相蚕食。

因此,下次营销主管、首席财务官甚至首席执行官询问上个季度的活动对正常销售之外的销售额有多大贡献时,请尝试使用 VAR 模型!

亚兹林 YR

创新|战略|分析|设计思维

LinkedIn 上关注我

OmniNet:如果本的 Omnitrix 内置了更好的机器学习/人工智能系统?

原文:https://towardsdatascience.com/omninet-if-bens-omnitrix-had-a-better-machine-learning-artificial-intelligence-inbuilt-70dcb321be79?source=collection_archive---------45-----------------------

OmniNet:如果本的 Omnitrix 内置了更好的机器学习/人工智能系统?

我是 Ben 10 系列的忠实粉丝,我一直想知道为什么 Ben 的 Omnitrix 没有变成 Ben 选择成为的外星人(这很大程度上是因为手表中已经内置了一个弱人工智能系统)。为了帮助本,我们将设计“OmniNet”,一种能够根据给定情况预测合适外星人的神经网络。

正如节目中所讨论的,Omnitrix 基本上是一个连接到行星 Primus 的服务器,用来控制大约 10000 个外星人的 DNA!如果我是这款设备的工程师,我肯定会给手表增加一个或多个功能。

普里默斯位于太空深处。(https://unsplash.com/photos/E0AHdsENmDg)

为什么和如何?

Why:Omnitrix/ulti matrix 是一个特例,因为它不知道周围的环境。根据 Azmuth 和其他人的说法,Omnitrix 有时会给出错误的转换,因为它自己的人工智能系统会得到错误的分类。让我们想象一下,造物主阿兹慕雇佣我们来建造一个新的人工智能/ML 系统。

H ow:为了建立我们的系统,我们需要某种形式的初始数据,感谢我们的地球同胞,我们有了 Kaggle 的 Ben 10 数据集。

要求

对于任何项目,我们都需要一个良好的需求列表,对于这个项目,我们需要:

  • Python 3.8:编程语言
  • Scikit-Learn:通用机器学习
  • 熊猫:用于数据分析
  • Numpy:用于数值计算
  • 张量流:构建我们的深层神经网络
  • Matplotlib:绘制我们的进度

数据预处理

T21 的数据集由 3 列 97 行组成。这些列是不言自明的,在分析数据时,我们立即将所有的分类表示转化为数字表示。

  • 角色:本 10 系列角色
  • 异能等级:角色的异能等级
  • 本 10 系列:与角色相关的系列

资料组

lr = LabelEncoder()def convert_id_to_category(index, mapping=None):
    """
        Convert the id into the label
        Arguments:
            mappping: The Mapping built by the LabelEncoder
            id: id corresponding to the label
        Returns:
            str: the label
    """
    return mapping.get(index, False)def convert_to_mapping(lr:LabelEncoder):
    """
        Extract the mapping from the LabelEncoder

        Returns:
            Dict: key/value for the label encoded
    """
    mapping = dict(list(zip(lr.transform(lr.classes_),lr.classes_)))
    return mappingdef get_power_level_mapping(df=None):
    mapping = {}
    for i in range(0, len(df)):
        mapping[df.loc[i].Character] = df.loc[i].Power_Level
    vtok = {}
    for i,j in enumerate(mapping):
        vtok[mapping[j]] = j
    return mapping, vtok# Ben_10_Series
df['Ben_10_Series'] = lr.fit_transform(df['Ben_10_Series'])
mapping_ben_10_series = convert_to_mapping(lr)
df['Character'] = lr.fit_transform(df['Character'])
mapping_character = convert_to_mapping(lr)print ("Length [Ben_10_Series]: {}".format(len(mapping_ben_10_series)))
print ("Length [Character]: {}".format(len(mapping_character)))def remove_string_powerlevel(df=None):
    """
        Replaces the string format of power level into an integer. (Manually checked the data)

        Arguments:
            df: Pandas DataFrame
        Returns
            None
    """

    # lowe bound
    df.loc[28, "Power_Level"] = "265"
    df.loc[93, "Power_Level"] = "12.5"
    df.loc[51, "Power_Level"] = "195"
    df.loc[52, "Power_Level"] = "160"
    df.loc[62, "Power_Level"] = "140"
    df.loc[67, "Power_Level"] = "20"
    df['Power_Level'] = df['Power_Level'].str.replace(",","")

    # converting power_level to float
    df['Power_Level'] = df['Power_Level'].astype(float)
    df['Character'] = df['Character'].astype(int)remove_string_powerlevel(df)

在中,除了更改分类表示,我们还清理了数据(列:Power_Level ),因为它包含一些文本级别。该列还包含逗号,因此我们也对其进行了清理。

特征转换

在上检查进一步的数据,我们可以清楚地看到一些异常值。(原子 X 和外星人 X)。如果你熟悉本 10,你应该知道这些外星人非常强大!

除了要素转换,我们将创建一个能够处理多类分类问题的新数据集。

为了查看我们可以在哪里应用特征变换,我们将首先检查任何异常值。

下面给出的散点图展示了这两个 Power_Level 的偏差程度。

极端值

我们可以清楚地看到有两个异常值,检查异常值的明显方法是分析它们的 zscores 并设置一个阈值。

values = df['Power_Level'].values
zscore(values, 0) > zscore(values, 0).mean() # All the True values are outliers.values[96] = np.mean(values)
values[36] = np.mean(values)
# changing the outliers to mean value
# handpicking abnormal values and setting it a justified value.
  • 如果我们将阈值设置为 zscore 值的平均值,我们可以清楚地看到所有为真的异常值。
  • 现在我们不想删除这些值,因为每个字符都很重要

但是,由于我们知道数据集,我们不想删除任何外国人,我们将手动改变离群指数的平均功率水平。

我们修改过的 Power_Level 列

新数据集的创建

制定一个新的问题不是一件容易的事情,但是因为我们是 Ben 10 系列的狂热粉丝,我们可以很容易地制定一个新的数据集。

由于缺乏信息(特征),我们将首先根据一个因子拆分修改后的 Power_Level。为了任务的简洁,我们将把整数分成另外三列。

1。沙之力:陆地上人物的力量

2。空气力量:角色在空气中的力量

3。水力:水中人物的力量

def split_powerlevel(df, factor=3):
    """
        Split the power level by the specified factor
        Arguments:
            df:DataFrame
            factor: int
        Returns:
            data: dict[str] = list[str]

    """
    data = {'air_power1':[], 'sand_power1':[], 'water_power1':[], "air_power2":[], "sand_power2":[], "water_power2":[]}
    for i in df['power_level1']:
        t = i/factor # float
        data['air_power1'].append(t)
        data['sand_power1'].append(t)
        data['water_power1'].append(t)
    for i in df['power_level2']:
        t = i/factor # float
        data['air_power2'].append(t)
        data['sand_power2'].append(t)
        data['water_power2'].append(t)
    return datadef return_individual_data(th = .5, winner='c1'):
        """
            Returns a row in our dataset.

            Arguments:
                th: threshold
                winner: The winning character

            Returns:
                (str,str, float, float, str)
        """
        characters = np.array(list(mapping_character.keys()))
        mapping_ch_to_pl, mapping_pl_to_ch = get_power_level_mapping(df)
        random_character1 = np.random.choice(characters)
        random_character2 = np.random.choice(characters)
        p1 = mapping_ch_to_pl[random_character1]
        p2 = mapping_ch_to_pl[random_character2]
        power_diff = np.abs(mapping_ch_to_pl[random_character1] - mapping_ch_to_pl[random_character2])
        if winner == 'c1':
            return random_character1, random_character2,p1, p2, random_character1
        else:
            return random_character1, random_character2,p1, p2, random_character2

对于每个字符,我们在最终的数据帧中增加了 3 列

F 对于我们数据集中的每一行,我们随机选择角色,并以 50:50 的比例将其分配给集合(角色 1 赢得 50 %的决斗,角色 2 赢得 50%的决斗)

调用 return_individual_data

有了这条信息,功率水平除以因子 3 以创建一组 10 个特征。

为了总结所有内容,我们将每一行合并并调用它 n 次,每次将功率级分成 3 列。

def create_data(df, split_size=0.2, size=1000):
    """
        Create Data for Multiclass classification problem
        Arguments:
            df: Pandas DataFrame
        Returns:
            data: Pandas DataFrame
    """
    def return_individual_data(th = .5, winner='c1'):
        """
            Returns a row in our dataset.

            Arguments:
                th: threshold
                winner: The winning character

            Returns:
                (str,str, float, float, str)
        """
        characters = np.array(list(mapping_character.keys()))
        mapping_ch_to_pl, mapping_pl_to_ch = get_power_level_mapping(df)
        random_character1 = np.random.choice(characters)
        random_character2 = np.random.choice(characters)
        p1 = mapping_ch_to_pl[random_character1]
        p2 = mapping_ch_to_pl[random_character2]
        power_diff = np.abs(mapping_ch_to_pl[random_character1] - mapping_ch_to_pl[random_character2])
        if winner == 'c1':
            return random_character1, random_character2,p1, p2, random_character1
        else:
            return random_character1, random_character2,p1, p2, random_character2# win is by character1 (by default)
    data = {'character1':[], 'character2':[], 'power_level1':[],'power_level1':[],'power_level2':[], 'win':[]}

    # first half
    for i in range(0, size//2):
        c1, c2, p1, p2, c1 = return_individual_data(winner='c1')
        data['character1'].append(c1)
        data['character2'].append(c2)
        data['power_level1'].append(p1)
        data['power_level2'].append(p2)
        data['win'].append(c1)

    # second half
    for i in range(0, size//2):
        c1, c2, p1, p2, c2 = return_individual_data(winner='c2')
        data['character1'].append(c1)
        data['character2'].append(c2)
        data['power_level1'].append(p1)
        data['power_level2'].append(p2)
        data['win'].append(c2)

    data_df = pd.DataFrame(data=data, columns=['character1', 'character2', 'power_level1', 'power_level2', 'win'])
    data_df = shuffle(data_df)

    toadd = split_powerlevel(data_df)
    for k,v in enumerate(toadd):
        data_df[v] = toadd[v]

    features, labels = data_df.drop(columns=['win']).values, data_df.win.values

    x_train, x_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)
    x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.25, random_state=42)

    print ("Generated data of size:{}".format(size))return features, labels,x_train, x_test, y_train, y_test,x_val, y_val, data_df

我们计算获胜的次数来检查班级的不平衡。

def count_wins(df=None):
    """ Count number of character wins. # to check for class imbalance
        Returns: 
            c1_wins: Character 1 wins
            c2_wins: Character 2 wins
    """
    for i in range(0, len(df)):
        if df.loc[i].character1 == df.loc[i].win:
            c1_wins.append(i)
        else:
            c2_wins.append(i)
    print("Character 1 wins: {}, Character 2 wins: {}".format(len(c1_wins), len(c2_wins)))       

features, labels,x_train, x_test, y_train, y_test,x_val, y_val,data = create_data(df, size=5000)

我们的最终数据集(其中大小= 5000)

模型创建

O ur 神经网络是一个简单的前馈网络,具有一组隐藏层,随后是一组丢弃层(减少过拟合的最佳方式,因为该数据集很容易过拟合),最后是一个具有 90(唯一字符总数)个单元的 softmax 层。

我们的模型架构

我们的数据已经在 create_data()方法中被分割成 x_train、x_test、y_train、y_test、x_val、y_val。

我们用 Adam 优化器训练模型(学习率= 3e-4,损失= 300 个历元的交叉熵)。

300 是一个实验数字,因为在 300 个时期之后,模型倾向于过度拟合。

model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=3e-4), loss=tf.keras.losses.sparse_categorical_crossentropy, metrics=['acc'])history = model.fit(x_train, y_train, epochs=300, validation_data=(x_val, y_val), callbacks=[tensorboard])

结果和预测

答经过大约 300 个历元的训练,我们能够在验证数据上达到 2.6692 的损失和 2.6995 的验证损失以及 26% 的准确率。这个结果是用 5000 行假生成的数据得到的。

低精度模型是比过度拟合模型更好的选择。

如果我们增加我们的数据,然后训练我们的模型,我们肯定会得到更好的结果。

我们模型的损失和价值损失

为了测试我们的模型,我们进行了一次评估,得到了 26%的准确率。为了清楚起见,我们开发了一个测试函数,为 90 个字符中的每一个生成概率。

def test():
    for i, j in enumerate(model.predict(x_test[0].reshape(1,-1))[0]):
        print ("{} -> {}".format(mapping_character[i], j))test()

预言

结论

总而言之,我们开发了一个网络,能够预测 90 个角色中每个角色的获胜概率。我们对来自 Kaggle 的初始数据集进行预处理,得到一个新的能够进行多类分类的数据集。我们的模型没有达到很高的精度,但也没有过度拟合。在尝试了书中的每一种技术来应对过度拟合后,我们得出了生成更多数据来训练我们的模型的结论。

最后,我们能够开发 OmniNet,这使得 Azmuth,创造者,授予我们开发 Omnitrix 软件的终身合同。

Github 链接:https://github.com/aaditkapoor/OmniNet

在 A/A 测试中,p 值、显著性和均匀分布

原文:https://towardsdatascience.com/on-a-a-tests-p-values-significance-and-the-uniform-distribution-95d6e9a2afb1?source=collection_archive---------36-----------------------

模拟 1,000 次 A/A 测试,了解 p 值的分布情况

几周前,我在为我的同事 Andrew 模拟一些 A/A 测试数据。我们想为他那周做的关于 A/B 测试和偷看的危险的全公司演示制作一个如下的图表:

作者图片

我们的目标是展示 p 值如何变动,以及即使在零假设肯定为真的 A/A 测试中,我们如何看到 p 值< 0.05 at some point.

Hence, I went on to simulate 1,000 A/A tests in order to calculate how many of them reached significance (p-value < 0.05) at some point. Each test ran for 16 days. With this simulation, I got that ~23% 变动。

然而,如果我做一个简单得多的模拟,我只要:
1。从一个均匀(0,1)——中抽取 16 个随机数,因为空值下的 p 值是均匀分布的
2。注意是否至少有一个数字< 0.05 和
3。这样重复了很多次,得到了 16 个数数组中的 ~56% 至少有一个数<为 0.05。

作者图片

我很困惑。对于 A/A 测试数据,尽管我看到 p 值是均匀分布的,但我发现 23%的测试在 16 天的某个时间点达到显著性。相比之下,当做一个简单得多的模拟,从一个制服(0,1)中随机抽取 16 次时,我得到的比例要高得多,为 56%。

第二天我醒来时脑子里有了一个理论:有没有可能 A/A 测试中的 p 值在这 16 天的每个测试中都不是真正独立的?也就是说,如果一项测试在第一天随机获得了非常高的 p 值,那么它在第二天也更有可能获得高 p 值,这是可能的吗?毕竟,我们不是每天都使用完全不同的数据,而是将新数据累积到用于计算之前 p 值的旧数据中。

于是,我:
1。根据首日 p 值是高(≥ 0.9)还是低(≤ 0.1)对 A/A 测试进行分组,以及
2。观察各组第二天 p 值的分布

这是我看到的:

作者图片

这非常强烈地表明,我发现了一些东西。在第一天碰巧有很高 p 值的 A/A 测试很可能在第二天也有很高的 p 值,反之亦然。这就是看完整个 16 天期间(而不仅仅是第二天)分布的不同之处:

作者图片

同样的故事。更有力的证据。

当我弄清楚这一切的时候,我也问了西蒙(我们的数据科学顾问和 Coppelia 背后的大脑),因为我对他的想法以及他对我的无独立性假设的认可很感兴趣。

当按天分组时,他也看到了大约 5%的 A/A 测试在任何一点上都是显著的,正如我们所预料的那样。然而,当按测试分组时,情况就完全不同了——依赖关系是这样的,如果我们在第d天有假阳性,那么我们在第d+1天仍然有假阳性的可能性就大得多。对于真正的否定也是如此。因此,按试验分组的总比率差异很大。

在他发给我的这个图中,这一点非常清楚,它显示了当假阳性(白色方块)发生时,它可能会持续到后续日期:

作者图片

哦,好吧,谜底解开了!今天到此为止。我知道我在这篇博文中没有详细介绍一些统计学概念,但是如果你感兴趣,我鼓励你去了解更多:

感谢阅读!

执行人工智能任务

原文:https://towardsdatascience.com/on-an-ai-mission-949290e80aa?source=collection_archive---------52-----------------------

一所大学如何将一个国家转变为人工智能强国的故事

乔恩·泰森在 Unsplash 上的照片

几个月前,马耳他政府推出了马耳他号。AI 国家战略 。这是一项雄心勃勃的努力,旨在使 马耳他成为世界上人工智能(AI)方面排名前 10 的国家之一。然而,这只是旅程的开始,真正的工作从现在开始!

人工智能不仅仅是另一个我们几个月后会忘记的时髦词。它是自第二次世界大战以来一直在发展的不同技术的集合。它们的成熟度极高,数十亿人最终受益于它们的使用。以至于人们把人工智能称为千年新电。

马耳他大学在这一战略中扮演着至关重要的角色,对国家的成败至关重要。我们不要忘记,该大学已经进行了近四十年的人工智能研究。它的专业知识宝库是无与伦比的,在马耳他和许多其他国家都是如此。但由于马耳他需要加快人工智能的吸收,唯一能够做到这一点的实体无疑是马耳他大学。

正因为如此,马耳他。人工智能战略声明大学将建立一个新的应用人工智能中心(CAAI)。该中心将负责四项主要任务,其中两项是内部任务,另外两项是外部任务。

应用人工智能中心的拟议结构(来源:作者)

第一项内部任务是服务ICT(FICT)学院。让我们不要忘记,FICT 已经拥有我们所需要的所有专业知识。该中心背后的理念不是要重新发明轮子或复制学院的职能,而是帮助学院及其部门扩大规模。由于人工智能研究人员在学院的五个部门工作,CAAI 将帮助他们走到一起,促进跨部门合作。它还将积极寻求国家&和欧盟的资金,从而帮助研究人员探索新的项目。

第二项内部任务涉及与其他院系、研究所、中心的互动。这个想法是聚集所有对人工智能感兴趣的学院的学者,和 FICT 的研究人员一起,创建一个人工智能社区。通过这样做,他们可以共同努力为公众开设短期课程,为所有非信通技术学生提供学分,促进合作,并为联合项目寻求外部资金。

第三项任务聚焦于外部学术利益相关者,如学校、私立教育机构和其他教育组织。大学应该设法让这些实体加入进来,以获得更广泛的影响。因此,CAAI 将协调外联举措,组织人工智能宣传活动,提供进修课程以帮助这些实体跟上形势,并与它们合作开展最终旨在提高国家能力的项目。让我们不要忘记,如果我们想让马耳他成为人工智能的领导者,我们必须放眼大学环路之外,创造一个当地的生态系统。

第四项任务涉及其他利益相关者。对该大学的一个常见批评是,它没有满足行业需求。这种说法是不真实的,这些联系今天比以往任何时候都更加紧密。然而,我们总是可以做得更多。CAAI 将专注于这项任务,并将帮助进一步加强这些联系。该中心将协调外联活动,传播人工智能,为行业推出短期课程,领导转换硕士,并促进研究合作。

在这个阶段,一个相关的问题是,是否会与现有的结构有任何重叠。CAAI 的范围不在于涉足任何人的领域,也不在于建造其他象牙塔。它旨在促进资源共享,提高效率。大学中没有任何实体优先考虑大学内外的外联和合作。原因是每个人都被工作压得喘不过气来,不幸的是,这些合作往往被抛到了脑后。因此,我们需要 CAAI 来支持和领导这些举措。

这样一个雄心勃勃的项目不容易实现。这需要大量的努力、耐心和奉献。但如果我们想认真对待 AI,我们没有其他选择,除了大学,马耳他没有其他实体可以完成这项任务。正因为如此,我坚信我们大学的使命是帮助我们的国家发展成为一个人工智能强国,公司可以在全球范围内推出他们的人工智能项目。

本文原载于 Newspoint 。请在下面留下你的想法评论。如果你喜欢这篇文章,请跟我来🐦推特,🔗 LinkedIn 或者😊脸书

[## 一个全新的人工智能世界

疫情之后人工智能的兴起

towardsdatascience.com](/a-whole-new-ai-world-6a5e9e49aa12) [## 失业的人工智能专家

失业的人工智能专家就像喜马拉雅山的雪人一样难以捉摸。事实上,在…

towardsdatascience.com](/the-unemployed-ai-expert-de5528e0443b)

Alexei DingliProf 是马耳他大学的 AI 教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他已经出版了几本同行评审的出版物,并且是马耳他的成员。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。

平均而言,我们更喜欢使用分销

原文:https://towardsdatascience.com/on-average-we-will-prefer-using-distribution-3c479ba387c8?source=collection_archive---------47-----------------------

或者在黑色数字的世界中引入灰色阴影。

“平均”一词来自阿拉伯语“awar”,意思是“缺陷”或“部分损坏的东西”。

大约在 12 世纪,地中海世界首次在海上贸易中使用这个术语。它用于描述损害、损失或非正常费用,这是我们今天在法语单词“avarie”中找到的含义。

当前含义的根源来自中世纪末期的商船法契约。在一场恶劣的风暴中,海军陆战队不得不将一些货物扔出船外,以使船更轻更安全。所有的商人都要按比例遭受损失,更一般地说,任何损失都要按比例分配。

从那时起,这个词被英国的保险公司、债权人和商人采用,用来表示他们的损失分散在他们的整个资产组合中,并有一个平均的比例。今天的意思是从那发展而来的,始于 18 世纪中期的英语。

平均的众所周知的缺点

平均值很可能是理解数据的第一个指标。我们在任何地方都能看到和使用它:销售报告、电视新闻、运行应用程序、车载仪器等等。这是非常方便的,因为它将大量数据恢复到一个图形中。

但是从设计上来说,它有一定的局限性:将许多观察结果汇总成一个数字资产会浪费很多重要信息。

让我们用一个简单的例子来看看平均是如何不够的。

考虑到这两个系列: 2,4,6,8,16,17,322,4,6,8,16,17,92

第一个系列的平均值为 12.1,而第二个系列的平均值为 20.7。正如我们所看到的,两个系列之间只有一个元素发生了变化。

我们现在来看看中位数。你可能听说过。它有时接近平均值,但代表另一个统计属性。

简单来说,中位数是一组数字的“中间”。在我们的示例中,两个系列的中位数都是 8。

这是一个非常简单的例子,但它强调了如果我们不仔细观察我们的数据,特别是异常值,平均值会产生误导。

更普遍的说法是:平均值、中间值或其他任何一个数字的汇总都有潜在的危险,并且常常隐藏了数据必须提供的所有模式。因为它们是有意隐藏的,所以如果我们完全依赖它们,就有出错的风险。

更精细的视图

我们必须爬得更高。转向更精细的视图。

当数据达到一定数量时,我们的大脑无法处理信息:数据太多了。因此,我们通常不看原始数据,而是通过相似的值来聚合它们:这就是我们通常所说的分布。

分布是一个函数,它显示变量的可能值以及它们出现的频率。

有许多方法可以可视化数据分布,以下是一些方法:

直方图

它们可能是绘制分布图最简单的方法。直方图显示数据的整体形状,并告知样本大小。条形图有什么区别?通常,直方图处理连续数据,而条形图用于处理分类数据。

箱线图

虽然没有“数据素养”的人很难读懂它们,但是盒状图收集了许多有趣的信息。它们表达基本的统计数据,如中位数、最小值、最大值甚至四分位数。将它与几个组(通常是数据的一个定性属性)一起使用,以减轻这些组之间的差异,这通常是很有趣的。

小提琴图

小提琴图结合了箱线图和密度图。它们增加了关于数据分布的完整形状的信息,比箱线图更直观、更有吸引力。

如果你喜欢小提琴图表,你可能会珍惜强调个体数据点的蜂群图

还有很多其他方式来看待分布。上面的三个非常容易制作,并且提供了比单一指标更多的细节。

我们经常被我们理解得非常快的简单的黑色数字所吸引。然而,花一点额外的时间来看看数据分布是值得的。你不会失望,而且会更好:你会很好奇,想了解更多关于你的数据。

同型图上的一个字

早在 20 世纪,许多政府信息程序都通过称为“同型”的离散图形元素来显示数据元素。Isotype 代表国际印刷图片教育系统。这种设计是由奥图·纽拉特、玛丽·纽拉特和格尔德·阿恩茨发起的,目的是创造一种视觉语言,让尽可能多的受众能够理解统计元素。

它们不仅可以简化信息,还可以快速显示分布中的巨大差距。插图和图片比行号或传统的直方图更容易记住。

同型图突出分布。拍摄自第二次世界大战信息图

到处发行

当我在火车上写下这篇文章时,我的目光迷失在乡村,我正眯着眼看着一个由人手做成的长长的栅栏。与机器制造的现代栅栏不同,这种栅栏非常不规则。

然后出现正态分布。

这里没看到正态分布吗?

几个世纪以来,科学家们发现许多观测数据都遵循相同的数学分布。

每小时到达商店收银台的人数服从泊松分布,人的大小服从正态分布,一个学生考试及格或不及格服从伯努利分布,等等。数学分布在自然界中无处不在。

看着柱子之间的空隙,我可以注意到一种模式。事实上,柱子之间的间距遵循正态分布。

正态分布。你已经看过这个形状了。

在这些发行版背后还有很多技术资产,我们在这里不做介绍。但是,当您听到和看到发行版时,请记住这些名称:您会惊讶地发现它们是多么自然地出现。

正如 RJ·安德鲁斯在他的优秀著作《我们信任的信息》中写道:“数据通常不会显示出开箱即用的有趣模式。”。

所以,下次你看到一位数的统计数据时,先问问自己数据分布的形状是什么。

希望这不是一般的作品。

成为一名数据科学家

原文:https://towardsdatascience.com/on-being-and-becoming-a-data-scientist-880fb4c81607?source=collection_archive---------27-----------------------

关于我如何成为一名数据科学家,我借鉴了自己 20 年职业生涯中的经验(其中大部分是在金融领域(更具体地说是最近的金融科技领域)获得的)。

这张照片是大约 20 年前拍的。在这张摄于纽约的照片中,我一直向左看街道。

工作给数据科学家带来了一系列新的不同的挑战,无论是新手还是更有经验的人,大多数人要么没有意识到,要么一开始准备不足以应对。通常破解ー的不是算法或代码库,而是其他东西。不管成为数据科学家的途径是什么,这或多或少都是正确的:无论是研究生院还是新兵训练营,自学还是其他方式。事实上,作为一名数据科学家,与数据无关的部分可能会在职业生涯中带来挑战和机遇。

在许多组织中,数据科学团队是独立的,有时会自行其是,被视为工程或技术职能。这种分离强化了数据科学家与世隔绝的自然倾向。无论是社交还是工作,我们可能会选择一起做,创造一个回音室,在那里我们可以听到自己最响亮的声音。

所有这一切的负面影响是,许多人真的不完全理解我们在做什么(也可以说他们可能不想理解)。公平地说,我们帮不上忙。沟通不一定是大多数数据科学家的强项,这个领域本身可能充满术语,充斥着外行难以解释的技术概念。我们有可能成为自己最大的敌人。

关键是,除了最初让我们兴奋并引领我们进入数据科学的技术技能之外,数据科学家还需要培养许多其他技能才能在工作中取得成功。

以下是对该领域中那些希望管理自己的职业生涯、获得个人和专业发展,并在作为数据科学家的工作中变得更加有效的人的一系列建议。这些建议很大程度上是基于我在数据科学领域 20 年职业生涯的经验,其中大部分时间是在金融领域(最近几年更具体地说是在金融科技领域)。

擅长一件事

数据科学学科包括一系列具有广泛应用的技术技能,随着“大数据”的出现,这些技能的需求不断增长。数据科学现在有太多的用例无法计数:流行病学、制药、金融和银行、媒体和广告。甚至是‘钱球’。哪里都最需要我们。

然而,申请的数量是福也是祸。

作为数据科学家,我们可能从技术角度理解工作中的挑战,但缺乏对以有意义、实用的方式理解和解决问题的更广泛背景的理解。

在建立和发展数据科学家的职业生涯时,领域很重要。除非你是一名行业专家,并在此过程中成为一名数据科学家,否则你需要时间才能发挥作用。我们时不时地学习,而不仅仅是在堆栈方面,在数据中寻找出路。

在某种程度上,你必须弄清楚,除了数据科学之外,你是否对你所在的行业感兴趣(除非它选中了你)。这是一个重大而基本的问题。

对我来说,这个行业就是金融,尽管我一开始并不知道,也没有做好准备。我对它既感兴趣又感到害怕。在我第一份数据科学家的工作结束几年后,我才找到了进入银行的路。

从统计学研究生院毕业后,我在营销和广告领域做了几年数据分析师,先是在麦迪逊大街的一家广告公司,然后在一家旅游公司和一家大型杂志和图书出版商工作。我从分析调查数据开始,这些调查数据被计划者用来通知广告,然后演变成直接营销和反应模型的发展。虽然我发现这项工作的技术挑战很吸引人,我的角色的影响也很明显,但我工作过的行业并不引人注目。

在那段时间快结束的时候,我在出版社的新业务开发组找到了一个角色,我为出版社找到了一个机会,向其杂志读者推销我之前工作过的旅游公司的旅游产品。当我向老板提起这个想法时,她建议我去找旅游公司的营销主管,看看他是否有兴趣——当然,他有兴趣!然后,我的老板把我介绍给了出版商的业务发展主管,然后我安排他和旅游公司的营销主管会面。几周之内,我就转入了这个小组。

我的工作是使用我们的数据建立统计模型,以便营销其他公司提供的金融服务,从保险单到退休计划的一切。我意识到我是多么喜欢商业发展和模型识别机会的能力。我还学到了一点金融知识,这最终导致了我在银行业的第一份工作,我在这个行业已经工作了大约 15 年。

从外面看,金融可能会让人望而生畏。它有自己的行话,也因此有了不抓俘虏的名声,这种名声通常是实至名归的。虽然我一开始就有足够的技术技能,但我必须了解这个行业,它是如何运作的,存在哪些问题和挑战,以及如何应对和解决这些问题。

量化金融(通常被称为“金融工程”)可能会吸引许多具有数学背景的数据科学家。然而,从事金融工作需要对金融工具和市场的理解远远超出数据科学的范畴。对我来说,这意味着理解和学习应用信用利差和违约模型,比如 Hull-White 和 Vasicek 的模型。对于其他人,这也将包括期权定价模型(即布莱克-斯科尔斯)。

从事金融工作也需要一定程度的毅力。这是一个高风险、难以预测的世界,事情可能会很快变糟。这个行业是由一群自信的,通常是自大的人经营的,他们从外面看起来很吓人。你必须做好准备,在一个经常要求很高的环境中努力工作,加快步伐,这是我喜欢的,在我加入银行时就已经准备好了,但并不适合所有人。最终,我在信贷领域找到了自己的位置,这是一个更具可预测性的金融领域。例如,债券支付固定的息票。抵押贷款利率通常在一段时间内保持不变。风险可以分散和集中,现金流变得更加可靠。

理解和欣赏背景很重要。以下是一些关于如何跟上你所在行业的想法:

  • 提问:询问和你一起工作的人他们是做什么的,他们是如何融入组织的大环境中的。许多人在同一个行业的其他地方工作过,对其他地方的工作方式有非常宝贵的看法。尽管他们可能无法用技术术语表达问题或挑战(那是你的工作),但他们会对业务或领域有更好的理解。当我在纽约四大咨询集团之一(隶属于德勤、普华永道和毕马威等大型会计公司)工作时,我能够分享我作为金融监管者和软件供应商的工作经验,但依赖于我的同事来更好地了解这些大型咨询组织是如何运作的。
  • 保持学习:学习是终身的;你永远也吃不够。如果你是一名在商界工作的数据科学家,MBA 可能是一份不错的证书,可以帮助你完善职业生涯,填补一些空白。我没有这样做,但回想起来,我会考虑一下。以我为例,我在一家银行工作,第一次从事金融工作,周围都是经济学家,我决定(在获得统计学学位五年后,在银行工作不到一年)再获得一个研究生学位,这是经济学学位,它帮助我说与我一起工作的经济学家的语言,理解他们如何思考和处理问题。在这个过程中,我学到了相当多的数学知识,有助于巩固我对统计学和金融市场的理解。

还有其他一些不太耗时的方法来了解你所在的行业或领域,其中包括以下几种:

  • 参加会议,不仅是数据科学会议,还有行业会议。我在金融风险管理领域工作了很多年,仍然坚持每年参加一两次活动。数据科学和金融科技也是如此。
  • 看行业期刊。加入社团。听播客,读奇怪的博客(我喜欢 DataCamp 的 Hugo Bowne-Anderson 创建的播客。哥伦比亚大学统计学教授 Andrew Gelman 有很多有趣的事情要说——无论是在 Twitter 上还是在他的博客上。你明白了。了解财务报表,了解你工作的公司(和你工作的行业)。我是这类事情的忠实粉丝。

追寻你想要的

有时候事情会阻碍你的发展。星星排成一行,你的事业开始腾飞。

在某个时候,这种事情发生在我身上。我被一家大型金融服务公司的咨询团队聘为数据科学家。该公司向市场出售软件,我所在的团队对其进行了定制。随着时间的推移,我从做工作升级到管理团队。

然而,事情并不是这样开始的。

回到大型金融服务公司的工作。我接手的项目严重落后于计划,而且有成为真正问题的危险。该项目经理要搬到欧洲,因此时间有限。那时他在中西部,比我在纽约时更接近客户。我飞了出去,和他在一起呆了一周,之后我被介绍给了客户,并被授予了控制权。

代码库一片混乱,团队士气低落,乌合之众在寻找方向。

尽管面临各种挑战,我们还是按时完成了项目,并且没有超出预算。九个月后,我申请并获得了晋升,接替了我的老板,他自己也获得了晋升。

我的客户称我为“球员教练”,这给了我一个想法。项目结束后,我发现自己在想下一步该做什么。我鼓起勇气和老板安排了一次会面来讨论这个问题,并发现自己获得了管理团队的晋升。我进入了角色,这是我应得的。

结果比我预料的要困难得多。真的没有管理他人的手册。你通过做来学习,这意味着摸索。我想到了我自己的导师,遵循黄金法则,全力以赴。

我的一个朋友是纽约一家大型金融科技公司的软件工程师,这家公司与我获得第一份管理工作的公司类似。他现在年近 20,从我们第一次在一次聚会上相遇开始,他的职业生涯已经走了很长一段路,当时我正在一次聚会上做演讲。他现在正在考虑一项人事管理措施。我认为这是个好主意。作为朝这个方向迈出的一步,他已经开始用一个专门的团队来管理一个项目。他学会了项目管理技能,掌握了敏捷过程,并且有效地拥有了一个更大项目的一部分开发。我要说,他正在朝着更长久地管理人的方向前进。

这并不适合所有人。人际交往能力很重要,对于我们这些在技术领域工作的人来说,这可能不是天生的。回想我自己的经历,我现在遵循并期待给别人的建议包括以下几点:

  • 先试后买:在全职从事这项工作之前,先测试一下管理人员和对可交付成果负责的感觉。希望与跨职能团队一起运行项目。或者考虑一些与工作无关的工作机会,比如团队午餐或其他课外活动。组织郊游和活动。尽你所能展现领导力。
  • 理解后果:管理人员意味着远离工作,以及一定程度的分离。它也为其他人的工作带来了更大的责任。更不用说激励人们的挑战了。在你承担这些额外的责任之前,这些都是需要知道的。
  • 寻求一个机会:留意做出有意义贡献的方式,承担更多的责任。如果你做得好,认可就会随之而来。但是不要害怕要求通过改变头衔来正式增加责任。
  • 原地成长:在去其他地方升职之前,考虑一下在你目前的公司里争取更大的职位。一个好的经理知道增加责任可以激励他们的员工。寻找更好的环境可能是一种诱惑。在跳船之前,四处看看。问问你自己,是不是这个组织没有吸引力。还是行业。或者只是你的老板。有时换换环境会有帮助。你总是想保持成长。

一路走来,我最终做了许多我没有预料到的事情,也没有任何迹象表明我有能力做到。随着时间的推移,你学会了不要说“我不是被雇来做那件事的”。是的,保持自己的优势很重要(这是比较优势)。然而,如果没有其他人可以做这项工作,那就加入进来。

保持谦逊

在我的职业生涯中,我有幸与许多聪明的人共事过,通常是作为老板,但也经常是作为同事或同事。与聪明人一起工作可能会令人生畏:他们推动我们,告诉我们如何做我们可能不知道自己能做的事情,并在这个过程中让我们变得更好。

有几次,这些人以深刻的方式帮助了我。

我早期的一位导师是宾夕法尼亚大学的经济学博士,他是一名移民,当最终成为他论文导师的教授休假访问印度时,他加入了这个项目。他是我见过的最谦逊的人之一。这并不是说他不会让ㅡ失望,不是因为他缺乏智慧,而是因为他以无知冒充智慧。可以理解。

Sarma 帮助我学会了编码。当我开始攻读经济学研究生学位时,我们会一起推导公式(9/11 时,我无法从我们都工作的城市之外的威彻斯特办公室回到曼哈顿,他也让我住了下来)。

我和 Sarma 的经历与我和其他人一起工作的经历形成了鲜明的对比。随着数据科学家的角色成为一种“东西”,一些数据科学家变得傲慢,并开始像半神一样行事。

在一天结束的时候,没有人喜欢一个无所不知的人,那种以他们的存在来给我们增光的人。一位数据科学家告诉我,一位客户有兴趣与我们合作,以便成为“书呆子邻居”。嗯。好吧,好吧。眼花缭乱的冲动,做脚尖旋转,大喊“看我,我会用 scikit!”需要被关注。在努力给人留下深刻印象的过程中,我们可能会忽略这变得多么令人生畏和令人不快。检查你自己。

不要太炫耀。你可能有一两个名牌大学的学位,写过软件或书,在大型会议上讲过话,或者是‘某个人’。随便啦。一点点谦逊会有很大帮助。

最后,数据科学不仅仅是编码或建模。多得多。不仅仅是数据工程,还有这个工作的其他方面,通常是非技术性的,在研究生院或者ーor 的训练营里是不会教的,实际上,除了工作。同样关注这些技能,你会以你从未想象过的方式获得成功。

艺术和数据科学中的废话

原文:https://towardsdatascience.com/on-bullshit-in-art-and-data-science-2c68c9ae17db?source=collection_archive---------28-----------------------

思想开放的几个理由

是的,完全正确。你读了。既不是 BS 也不是 公牛t** 。简单来说就是: 扯淡 ,或者更准确的说是“伪深奥的扯淡”。这已经不是一句脏话了,而是一个科学术语,至少在论文“ 扯淡让艺术变得更深刻 ”之后( PDF ,以下简称 BSS )于去年 11 月问世(载于判决与决策第 14 卷第 6 期 2019 年 11 月)

这是怎么回事?

研究的主旨是关于意为艺术 中的作用:

先前关于审美偏好的研究表明,人们普遍不喜欢他们认为毫无意义的艺术( BSS )。

根据这项研究,在数字时代,人工智能生成(抽象)图像的趋势正在出现,以及对观众的欺骗。给抽象画加上标题使它们显得深刻。对于人工智能生成的标题,它们会引发所谓的“伪深奥的废话”,尤其是在艺术家(=自己的人工智能生成的艺术品的策展人)试图获得“社会优势”的情况下。他们在愚弄无辜的观众,他们深信不疑地希望,一切都是有意的:

与没有标题时相比,随机生成的伪深奥的废话标题增加了计算机生成的抽象艺术的可感知的深度( BSS )。

这项研究不仅旨在提高人们对艺术欺诈的认识(低成本人工智能艺术作品在艺术市场获得高估价),而且还仔细审查抽象艺术家的责任。

一些抽象艺术家对艺术抱着一种极端主观的观点,也就是说对于美或意义没有可能的客观标准。这些艺术家的目标是给人留下深刻或美感的印象,而不仅仅是不关心真理,而是否认任何客观真理可能存在 ( BSS )。

如果抽象艺术的世界事实上代表了扯淡的理想环境被部署作为获得声望的有效低成本策略,那么人们会期望扯淡在这个领域广泛存在。( BSS )。

因此,本研究遵循以下几个目标:

  1. 关于标题让无意义的艺术变得深刻的心理学证据(特别是使用人工智能技术,如甘和自然语言处理)
  2. 社会学,然而对抽象艺术家的刑事调查艺术炫目(“给别人留下深刻印象的快速有效的方法】 )
  3. 质疑抽象艺术形式本身,据称它们没有以可理解的方式描绘现实。

伪高深的学问?

在我看来,这项研究在对艺术理论的无知和伪心理策略之间如履薄冰。

让我们从四个方面来分析这项研究。

#1.反学术方法

每一项心理学研究都需要人体统计学。他们应该是负责任和可靠的。如果我们看看这项研究的先证者(一篇论文中有几项研究),我们会看到一些有趣的细节:

“扯淡让艺术变得更深刻”研究的先证者

我们有什么?

  • 他们是这所大学的本科生,显然他们正处于学术旅程的开端。对于一般的心理学研究来说,教育状态确实只在特定的案例中起作用。关于艺术感知的心理学研究,教育状况、文化能力和背景知识是相关的(多样性计数)。
  • 先证者(想必)不是艺术史学家
    为什么对研究来说必不可少,我以后会参考。
  • 他们参与的动机是“课程学分”。
    还是那句话,没有记录在案,但是志在必得这个可悲的目标可能会引起偏见。这是给先证者的文件— 测试“深度”

该研究评估了真实的抽象艺术品(MoMA 作为来源)和人工智能生成的图像,结合人工智能生成的(“伪深奥的废话”)和人类创建的(“世俗”)标题。

摘自《扯淡让艺术变得更深刻》

人工智能生成的标题倾向于形而上学的想法(“病理内部”),世俗的标题是对艺术作品的视觉描述(“颜色混合”)。

检验的重点在于,如果给定标题(“人工智能生成的” vs “平凡的”),先证者是否以不同的方式接受抽象的未理解的艺术。这项研究的设置令人惊讶地反学术(缺乏互文性,只是指主观接受代替)。

**Titles. Short excourse.**Indeed, **titles are a relatively new phenomenon** in art history. Before the XVIIIth century, most pictures didn't have titles (see also [***NewRepublic***](https://newrepublic.com/article/125621/art-no-name)). ***Art historian E.H.Gombrich*** has observed, title “*is a by-product of the mobility of images*”, this textual attachment emerges parallelly with art market developments (~> mobility of images). Initially, titles were used **not for making art "profound", but rather for raising *motives recognition* among public**, who weren't limited to patrons and educated artwork owners in times of Renaissance anymore. One of the title-proponents, ***abbé Du Bos,*** writes 1719: “*most spectators… are not learned enough to guess the subject of a picture*”. Here titles have rather **educational, explanational task** than valorization of artwork.Along with the evolution of art, also the significance of titles changed. Titles enhance and augment the visual artwork in a psychological way of perception. In a study **"**[**The Influence of Titles on How Paintings Are Seen**](https://www.jstor.org/stable/1575894)**"** (*Leonardo*, vol. 26, no. 2, 1993, pp. 103–108.), Margery B. Franklin (at all) highlights, that "***titles function as guides to interpretation, not simply as identifying tags***". According to this study, titles influence the perception in psychological and even physiological ways. By applying various titles to the same images, researchers observed different viewing tracks by their probands:

出自: 头衔对画是如何被看出来的影响

本研究( BSS )试图用所谓的标题欺骗的论证来为抽象艺术家定罪。

#2 混淆艺术和艺术市场

社会优势、意义、艺术价值的不断具体化——所有属于艺术市场领域的成分。没有一个字提到这种可能性,即一个艺术家可能通过他的艺术作品来表达自己,而没有任何商业化的意图。

艺术品 ( 作为艺术家个人的表达 ) **与艺术市场** ( 作为艺术品货币化的平台)之间的区别,甚至**的并置,不仅是显著的,而且在 20 世纪关于艺术权威被废除的批判性话语中是不可避免的****

主要的反传统艺术颠覆者是达达主义者、超现实主义者和抽象主义者——这正是我们当前研究的目标群体。

这使我们进入…

#3 忽视艺术史

具有讽刺意味的是,如果在这项研究中,旁观者的主观观点得到了尊重,艺术家的主观动机却没有得到尊重。

平原说,这项研究想要证明给抽象绘画命名是一个伪深奥的废话(特别是如果所有组件都是人工智能生成的话)——进一步怀疑抽象艺术本身的相关性。

让我们看看曝光群体的一些作品和标题。

超现实主义:勒内·马格里特

"摔跤手之墓** " (" 摔跤手之墓")——多么伪深奥的 BS 标题!乍一看。在这个标题中,马格里特引用了法国象征主义者莱昂-阿尔比恩·克拉德尔的小说《Ompadrailles,le tombeau des lutteurs》(1879)。在这个标题的背后,是一个复杂的文化和社会政治故事,基于与纽约人 Lawer 和诗人 Harry Torczyner 关于苏联“塔奇斯特”画家、20 世纪 60 年代欧洲形势等的信件往来**

马格里特是怪异标题的大师——除了对于不知情的观众来说,“怪异只是“怪异。(#文化能力)****

达达主义:库尔特·施威特斯

K.Schwitters,“色情苦难大教堂”(重建,照片由 Merzmensch)

这是达达主义者和默茨艺术家库尔特·施威特斯的默茨-鲍尔装置作品。他的跨媒体空间装置占据了他在汉诺威公寓的几个房间。当他从纳粹德国流亡到挪威时,他一直在他居住的每个地方建造 Merz-Baus,没有任何希望(也没有意图)让这个作品出名,将其货币化,或获得任何社会优势。他这样做只是因为他无法停止创作。这是他的生活。

《性爱苦难大教堂》这个标题是高度叙事性的:关于他的曲折,关于他那个时代的文化话语,关于二战前的政治崩溃,关于他的个人处境。这个标题被取消,并被重新命名为 Merz-Bau,因为 Schwitters ' uvre 是由纳粹在他们讽刺性的展览“ Entartete Kunst ”中提出的(堕落艺术展,1937)。本次展览的主要任务是将抽象主义者和先锋派与他们的(对于同胞来说难以理解和近乎深奥的)叙事和视觉效果,与“纯粹的”、政治上认可的和有用的现实主义以及纳粹政权委托的艺术进行对比。

抽象艺术:保罗·克利。

页(page 的缩写)克利,“理性的极限”

****理性的限度(《格伦森·德·韦尔斯坦德斯》)。现在,这是一个完美的伪深奥的废话,不是吗?

不,不是的。在这部抽象作品中,保罗·克利以讽刺的方式探索了包豪斯的哲学。最初,克利是 T4 包豪斯学院的讲师,但它对技术倾向和功利主义的日益关注让保罗·克利对这个艺术学校和运动持怀疑态度。在这幅抽象画中,艺术家表达了包豪斯对实用主义可悲的崇拜。

正如你所看到的,在这些第一眼看上去“伪深奥”的标题背后,总是一个庞大的叙事,只有了解背景的观众才能完全理解。在这里,情感艺术变成了智力艺术。

但是…

“嗯”,你会说,“但是那些用 StyleGAN 和其他 GANs 生成艺术,并使用像 thisthis 这样的标题生成器来应用随机的形而上学标题的炫目者和模仿者呢?然后在苏富比上卖大钱?是不是伪深奥的屁话?****

嗯,可以,但是只有不买(有意双关)。

  1. 其实并不是这样:艺术市场仍然对人工智能生成的艺术持怀疑态度(人工智能生成的艺术泡沫已经破灭了吗?《艺术网上的》
  2. 不跟艺人玩同一游戏才是 BS。

因为 AI 生成的内容创造了新的叙事。新流派。新的深刻。

****新的讲故事方式

结论

根据牛津词典,术语扯淡的意思是

你认为愚蠢或不真实的想法、陈述或信念。

****信不信由你。用艺术家的频率说话或者拒绝。你不需要为此进行研究,尤其是如果这项研究带有偏见和刻板的概括。

毕竟,即使是人工智能生成的艺术(使用 art breader)和标题(使用 TitleGen )的随机组合也可以建立一个新的叙事(如果你打开思维并遵循你的想象力)。

和平的诗歌

如果你把艺术——和生活——看得太重,你只会声称被“伪深奥的废话”愚弄了。

智者指点,驾驶的 GPT-2 型给了我,就在我问它关于生命的意义是什么:

TalkToTransformer.com生成

幸运的是,我不是唯一有这种观点的人:

朋友们,你们觉得怎么样?

按需物化视图:图形、分析或机器学习的可扩展解决方案

原文:https://towardsdatascience.com/on-demand-materialized-views-a-scalable-solution-for-graphs-analysis-or-machine-learning-w-d3816af28f1?source=collection_archive---------19-----------------------

作者使用 Chart.js 提供的图片

为图表、分析、投资组合甚至机器学习聚集数据可能是一项艰巨的任务,难以扩展。在本文中,我将详细介绍 MongoDB 的新(ish) \(merge* 管道,我认为它解决了许多这样的伸缩问题,并自动化了某些以前需要大量定制开发才能完成的设计实践,然而,Mongo 的文档未能提供推断的示例或多个用例。本文将深入探讨 MongoDB 的聚合操作。它将假设您已经了解如何聚合数据,并将主要关注涵盖可伸缩性、缓存和数据增长的*\)合并管道

**Table of Contents** *Basic Usage
Incrementing New Subsets of Data
Incrementing or Replacing a Field based off a conditional* Aggregating Data from Multiple Collections
*Creating a Basic Graph or Machine Learning Data Set*

让我们用一些模拟数据创建一个简单的例子。在这个例子中,我们将聚集一般职位,并确定每个配置文件有多少职位,然后我们将聚集评论。如果您使用代码片段来阅读本文,您将希望按照下面的风格创建一些数据点。但是,这种解决方案很容易扩展到具有大量数据点的数据库

db.posts.insert({profileId: "1", title: "title", body: "body", createdAt: new Date()})db.comments.insert({profileId: "1", body: "body", createdAt: new Date()})

接下来,我们将通过简单的分组来聚合数据

db.posts.aggregate([{
  “$group”: {
    “_id”: “$profileId”,
    “totalPostCount”: {“$sum”: 1}
}}])

这将为我们提供一系列类似这样的文档

[
{_id: “1”, totalPostCount: 5}, 
{_id: “2”, totalPostCount: 4}, 
{_id: “3”, totalPostCount: 9}
]

为了避免定期运行集合扫描,即扫描整个集合而不是集合子集的操作,我们可以将此信息存储在概要文件中,并偶尔使用 cronjob 更新它,或者我们可以将内容缓存在某个地方,并重新运行整个聚合来重新同步计数。当有数百万的个人资料和数百万的帖子时,这个问题变得更加明显。突然之间,聚合将占用大量的计算资源和时间,从而推高成本和服务器负载。如果我们显示某种投资组合视图,或者终端用户正在物理地等待这些计数,并且它们需要 100%最新,这将变得更糟;更糟糕的是,许多用户可能同时发出这个请求,使我们的服务器和数据库过载,并使我们的应用程序崩溃。

按需物化视图

这就引入了对 MongoDB 的按需物化视图的需求。

在计算机科学中,物化视图是与原始数据集分开存储的先前运行的数据查询的结果。在本例中,它描述了$merge 操作,以及如何将结果直接输出到另一个集合中,而不是输出到一个游标中以立即返回到应用程序。Mongo 的文档页面描述了每次运行时都会更新内容——即按需更新。然而,它没有正确解释当扫描更小、更新的数据子集时,如何显示数据的增量表示。在本文的剩余部分,我将展示几个例子和用例来说明如何做到这一点

这种方法将*\(合并管道*添加到聚合操作的末尾。它可以将聚合操作的内容输出到为此目的创建的特定集合中,并替换或合并与之匹配的文档。内容将作为返回数组中每个元素的一个文档输出,允许对新的聚合集合进行进一步的聚合和计算。这是对以前的\)out 管道操作符的巨大升级,它将覆盖所有匹配的条目。$merge 添加以前不存在的数据,并替换已经存在的数据。这个链接展示了一个非常清晰的例子。

基本用法

 db.posts.aggregate([
{
  “$group”: {
    “_id”: “$profileId”,
    “totalPostCount”: {“$sum”: 1}
  }
},
{
  “$merge”: {
      “into”: “metricAggregates”
  }
}])

现在,我们可以使用 metricAggregates 集合的普通查询来收集数据

db.metricAggregates.find()
->
[{_id: “1”, totalPostCount: 5}, 
{_id: “2”, totalPostCount: 4}, 
{_id: “3”, totalPostCount: 9}]

这个例子没有涵盖更复杂的用例。它只包括添加新的概要文件,但是在我们的例子中,现有概要文件的新帖子呢?我们如何避免重复扫描之前聚集的数据?拥有数百万的个人资料和数百万的帖子,我们无法承担如此繁重的工作。

增加新的数据子集

当处理数百万个文档时,我们需要找到一种方法,只聚合最近的数据,并且只聚合我们还没有聚合的数据。我们不想替换已经存在的字段,我们想增加它们。解决方案隐藏在可选的“匹配时”字段底部的$merge 的文档中

用于更新集合中文档的聚合管道。
[ <第一阶段>,<第二阶段> … ]

管道只能由以下阶段组成:
\(addFields](https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/#pipe._S_addFields) 及其别名 [\)set
\(project](https://docs.mongodb.com/manual/reference/operator/aggregation/project/#pipe._S_project) 及其别名[\) unset
$ replace root及其别名 $replaceWith

通过应用 whenMatched 选项,我们可以应用一个 $project 管道操作符,允许我们增加字段

db.posts.aggregate([
{ "$match": {"createdAt": {"$gt": aggregationLastUpdatedAt}}},
{
  "$group": {
    "_id": "$profileId",
    "totalPostCount": {"$sum": 1}
  }
},
{
  "$merge": {
    "into": "metricAggregates",
    "whenMatched": [{
      "$project": {
        "_id": "$_id",
        updatedAt: new Date,
        totalPostCount: {
          "$sum": ["$totalPostCount", "$$new.totalPostCount"]
        }
      }
    }]
  }
}])

我们在这次行动中增加了两件事。首先是 \(match* 。现在我们需要查询最近的 *updatedAt* 字段,并将其从集合中取出。之后,我们可以将它包含在匹配中,所以我们只拉**自上次调用操作**以来创建的帖子。在 *\)merge 管道中,我们添加了一个 \(project* 操作,因此每次在 *_id* 字段上出现匹配时, *updatedAt* 将被刷新, *totalCount* 将被*递增*而不是被替换。语法 *\)$new 是一个与我们刚刚执行的聚合操作中的数据相关的关键字

这些数据只需要查看一次,而且是以很小的增量查看

基于条件递增或替换字段

但是如果更复杂呢?如果我们还需要显示本周发布的帖子的数量呢?其中我们需要根据时间戳或其他信息有条件地增加或替换字段

let aggregationLastUpdatedAt = //retrieve most recent timestamp in the metricAggregates collectionlet startOfWeekDate = //new Date representing the beginning of the weekdb.posts.aggregate([
{
  "$match": {"createdAt": {"$gt": aggregationLastUpdatedAt}}
},
{
  "$group": {
    "_id": "$profileId",
    "totalPostCount": {"$sum": 1},
    "postsThisWeek": {"$sum": {
       "$cond": {
          "if": {"$gte": ["$createdAt", startOfWeekDate]},
          "then": 1, "else": 0}}},
  }
},
{
  "$merge": {
    "into": "metricAggregates",
    "whenMatched": [{
      "$project": {
        "_id": "$_id",
        "updatedAt": new Date,
        "weekStartedAt": startOfWeekDate,
        "totalPostCount": {
          "$sum": ["$totalPostCount", "$$new.totalPostCount"]
         },
        "postsThisWeek": {
          "$cond": {
            "if": {"$eq": ["$weekStartedAt", startOfWeekDate]},
            "then": {
              "$sum": ["$postsThisWeek", "$$new.postsThisWeek"]
            }, 
            "else": "$$new.postsThisWeek"
          }
        }
      }
    }]
  }
}
])

现在我们有条件地增加 postsThisWeek 如果它匹配 weekStartedAt date,或者替换它如果它不匹配

聚合来自多个集合的数据

如果我们需要从其他集合中聚合数据呢?以前我们可能必须使用一个 \(lookUp* 操作符*、*,但是**、 *\)lookUp 失败了,因为它只与基本集合**匹配。例如,如果我们需要从我们的评论集合中收集指标,该怎么办?一个 \(lookup* 将跳过所有从未发表过帖子的个人资料,导致那些只发表过评论的个人资料从聚合结果中完全消失。 *\)merge 很容易解决这个问题,它允许我们在不同的时间、地点或服务上聚合不同的集合,并将所有输出到同一个集合和文档中

db.comments.aggregate([
{
  "$match": {"createdAt": {"$gt": commentsAggregationLastUpdatedAt}}
},
{
  "$group": {
    "_id": "$profileId",
    "totalComments": {"$sum": 1},
    "commentsThisWeek": {
      "$sum": {"$cond": {
         "if": {"$gte": ["$createdAt", startOfWeekDate]},
         "then": 1, "else": 0}}},
  }
},
{
  "$project": {
    "_id": "$_id",
    "totalComments": 1,
    "commentsThisWeek": 1,
    "weekStartedAt": startOfWeekDate,
    "postsThisWeek": {"$literal": 0}, // explained below
  }
},
{
  "$merge": {
    "into": "metricAggregates",
    "whenMatched": [{
      "$project": {
        "_id": "$_id",
        "commentsUpdatedAt": new Date(),
        "weekStartedAt": startOfWeekDate,
        "totalComments": {
          "$sum": ["$totalComments", "$$new.totalComments"]
        },
        "commentsThisWeek": {"$cond": {
          "if": {"$eq": ["$weekStartedAt", startOfWeekDate]},
          "then": {
            "$sum": ["$commentsThisWeek", "$$new.commentsThisWeek"]
          },
          "else": "$$new.commentsThisWeek"
         }},
         //explained below
        "postsThisWeek": {"$cond": {
          "if": {"$eq": ["$weekStartedAt", startOfWeekDate]},
          "then": {"$sum": ["$thisWeek", "$$new.thisWeek"]}, 
          "else": "$$new.thisWeek"
        }},
      }
    }]
  }
}])

现在在 comments 集合中,我们很快遵循相同的聚合原则,集合将自动按照我们想要的方式进行合并。您可能已经注意到了一个额外的 \(project* 操作,以及仍然在 *\)merge pipeline 中的 postsThisWeek 字段。这样做的原因是,如果评论聚合操作发生在新的一周,则总评论将被准确重置,并且周开始日期将被正确更新。但是,如果稍后发生 post 聚合,则不会触发周开始替换,因为 weekStartedAt 已经匹配,导致 post 字段在应该重置时错误地递增。通过包含这些字段并将该字段设置为{$ literal 0 }$ literal将该字段设置为文字整数值 0,而不是解释为排除。代码翻译成“如果是新的一周,将该字段设置为 0,否则递增 0”

注意,我们还在 $merge 中设置了一个唯一的日期字段。我们需要将评论最后一次汇总的时间和帖子分开,否则可能会丢失数据

当最终用户请求数据时,他们只需像任何普通的 mongoDB 操作一样从输出集合中提取数据。即使数据是多个聚合查询和集合的集合,也可以轻松地对其进行排序、分页、过滤和索引。

这种方法保证了即使对于复杂的计算,我们也只需要扫描一次数据,而且只需要一点点。可以在每次查看页面时额外聚合数据,也可以由 cronjob 管理数据。它可以跨越任意数量的集合,而不需要 $lookup ,并且复杂度可以根据用例的不同而增加。

最后,新的输出集合还可以被聚合,以得出不同的有趣度量,这可以极大地帮助各种机器学习应用程序或投资组合视图。

创建基本图形或机器学习数据集

作为最后一个例子,我将包含一个聚合操作,该操作按周对总计数进行排序,这对于创建可视化图形或机器学习数据集非常有用

db.posts.aggregate([
{"$match": {"createdAt": {"$gt": aggregationLastUpdatedAt}}},
{
  "$project": {
    "createdAt": 1,
    "week": {"$trunc": 
      {"$divide": [
        {"$divide": [{"$subtract": ["$createdAt", startDate]}, 86400000]},
        7
      ]}
    }
  }
},
{
  "$group": {
    "_id": "$week",
    "week": {"$first": "$week"},
    "totalPostCount": {"$sum": 1}
  }
},
{
  "$merge": {
    "into": "metricsByWeek",
    "on": ["week"], // this requires a unique index on the metricsByWeek collection
    "whenMatched": [{
      "$project": {
        "week": 1,
        "updatedAt": new Date,
        "totalPostCount": {
          "$sum": ["$totalPostCount", "$$new.totalPostCount"]
        }
      }
    }]
  }
}])

如果您正在实时跟踪代码示例,您将需要在运行上述代码之前复制并粘贴以下代码片段

db.metricsByWeek.createIndex({week:1}, {unique:true})

这是因为当您定制 $merge 操作符寻找匹配的字段时,该字段(或字段组合)必须有一个惟一的索引,这样才能保证 mongo 只找到一个单个匹配

这样就创建了一个这样的文档集合,可以插入到图形库或任何其他应用程序中

{
  week: 0,
  totalCount: 3
}
{
  week: 1,
  totalCount: 9,
}
{
  week:2,
  totalCount: 25
}

Z 在 VAE 的分布

原文:https://towardsdatascience.com/on-distribution-of-zs-in-vae-bb9a05b530c6?source=collection_archive---------25-----------------------

我们是否正确地使用了创成部分

https://unsplash.com/photos/Hba7In7vnoM

动机

这个帖子的动机是在学习 VAE 的理论和遵循它的一般实现时提出的。正如我们所知,VAE 由两个网络构成:一个(编码器)被训练成将真实数据映射成高斯分布,旨在优化其与给定分布(通常为标准正态分布)的 KL 距离。)和另一个(解码器)来将该高斯分布的样本(Zs)映射成实数据。也就是说,最终目标是解码器将能够从通用分布中生成数据,但是它具有双重目标

  • 越来越接近标准的正常距离。
  • 由解码器生成良好的数据样本

VAE 通常使用 ELBO 作为损失函数。该函数用于解决变分推理 ( VI )问题和早期热力学。它旨在研究给定观测数据的潜在变量的分布。

虽然 ELBO 看起来是用于生成给定现有真实数据的数据的正确函数(这实际上是 VI 的经典定义),但是不清楚为什么会期望 ELBO 收敛到 normal dist。

为了开始分析性的讨论,让我们先介绍一下埃尔伯公式。

我们的目标是找到潜在变量(Zs)的最优分布 Q ,使其与 P(Z|X)的 KL 距离最小,其中 X 是真实数据

我们可以这样写 KL:

这导致了以下情况:

P(Z)是 Z 的先验分布,并假设为标准正态分布

爱尔博是第二任。最大化 ELBO 等价于最小化 KL 散度。

考虑到 VAE 的双重目标和爱尔波公式的代数结构,有两个问题:

  • ELBO 的 KL 项(在 Q 和之前的 P 之间)是否收敛到标准正常距离?
  • 假设第一个问题的答案是肯定的,那么整个 ELBO 呢?

在接下来的部分中,我将研究这两个问题并给出一些数值实验

KL 收敛

为了证明一个函数收敛到某一点,我们必须证明这个点是一个极值,并且存在一个时间动力学,在这个时间动力学中这个点是稳定的。我们将证明对于 ELBO (0,1)的 KL 项满足这些条件。由于计算损失函数的常用方法是蒙特卡罗估算法,我们将在下一节中说明(0,1)是解析解和蒙特卡罗的最小值。在下一节中,我们将展示这一点的稳定性。

高斯解析公式

假设我们对寻找两个高斯分布之间的 KL 距离感兴趣,一个由 P 表示,另一个是标准正态分布( S )。

对于一个 K 维高斯,KL 散度遵循以下公式:

(备注:在 VAE 我们总是假设协方差矩阵是对角的。因为协方差矩阵类似于对角矩阵,并且类似的矩阵共享它们的迹和行列式,所以我们可以知道对角假设是充分的

为了简单起见,我们可以用不同的方式来写这个公式:

F 和 G 是在 0 (F)和 1 (G)处具有唯一零点的非负函数。为了说明,我们提出平面空间,σ****

KL 图具有这种形式

我们可以看到,当我们遵循分析方法时,标准正态分布是一个唯一的最小值。

然而,这是 KL 术语的最小值,而不是 ELBO 术语的最小值

通常我们不用解析形式而是用蒙特卡罗估计来求解 VAE。我们将在下一节讨论这一点。

蒙特卡洛

让我们来表示

我们如前所述

****P(Z)-先验分布(标准正态分布)

X -数据

我们有爱尔波公式

因为我们对 KL 的收敛性感兴趣,所以我们关注、σ** 。很明显,解码器对 Z 的依赖性是难以控制的。因为它是通过解码器的隐藏层获得的。我们将遵守 KL 项。**

计算 KL 散度的常用方法是假设高斯分布并使用蒙特卡罗估计量

如果我们为每个数据项显式地编写这些术语,我们将得到

当我们对批量和 Z 的样本进行平均时,我们得到

回忆

我们得到了与解析解相同的结果。很明显,如果 KL 散度收敛到一个点(高斯分布),它将是标准的正态分布。仍然不清楚为什么会发生这种趋同。

动力系统方法

**以便在学习过程中产生对过程进行重新分级的直觉。我们来考虑一下平原 **- σ。潜在的学习过程可能遵循红色或蓝色曲线(抱歉,螺旋形更酷)。

为了了解为什么唯一的最小值是稳定的不动点,我们必须观察 Kl 散度。给定一个分布函数 KL 是一个非负函数,只有相同的函数才会得到 0。这使得它成为 李雅普诺夫函数 的良好候选

现在我们有以下内容:

如果我们考虑一个有争议的时间

现在我们可以计算 KL 散度的时间导数

因此 KL 是非负且向内的,即(0,1)是稳定的不动点。

中间总结

我们已经看到使用两种方法论,0,1 是 ELBO 的 KL 项的稳定不动点。如果我们假设整个 ELBO 都需要用于训练,那么就有两种可能的选择:

  • 我们需要整个 ELBO,因为它的条件概率项(P(X|Z)达到最小值(0,1)并改善了整个系统
  • ELBO 在(0,1)上没有得到它的最小值,但是仍然提高了 VAE

另一方面,如果我们可以在没有解码器的情况下解释到(0,1)的收敛,并保持整体结果,也许我们不需要条件分布项

实验

平均场定理

在这一节中,我展示了我所做的一些试验,以回答我在上一节中提出的问题。我用这个平均场算法

该图显示了四个框架工程的衰减:

蓝色当前使用的方法

绿色-蒙特卡罗估算器,仅在编码器上进行训练

红色-仅在编码器上训练的两个高斯分布的解析公式

黑色-从 troch.randn 采样的随机样本的 KL 散度(可以认为是 GAN 的一种输入。)

可以看出 Z 的分布比我们使用整个 ELBO 时的分布更接近标准正态分布。该图与我们在后面章节中的分析计算一致。此外,我们的 KL-only 培训比简单的 torch.randn 样品获得了更好的分布

然而,这些结果没有提供关于解码器的信息。我们可以看到,我们的编码器被训练成具有在 KL 方向上接近标准高斯分布的分布 Q ,但是解码器的工作情况如何呢?我们可以使用以下方法之一:

  • 训练编码器和比解码器(分开)
  • 训练他们俩(同时)
  • 遵循当前方法(一起训练整个系统)

第一种和第二种方法将提供相同的 KL。然而,解码器的性能相似并不明显,第三种选择将提供较低的 KL (Z 的距离与(0,1)高斯的距离较大)

我们将使用两个“KPI”来评估解码器的性能

  • 可能性分数
  • 生成的图像

以下两幅图像是由当前算法创建的

********

我们使用第一种方法(即训练编码器,然后才训练解码器)。以下图像是使用此方法创建的,但有分析损失

这张图片是由随机取样的 z 创建的

我们可以在分离的方法中观察解码器分数

通过分数和图像可以看出,对于当前方法,解码器工作得稍微好一些。

下图比较了同时学习和分别学习的区别

给出了使用同时分析法和蒙特卡罗损失法创建的图像

********

总结

  • 我们看到,正如数学直觉所暗示的,在 VAE 独立地训练编码器提供了更好的 KL 结果(即所获得的 Z 更接近于标准的正态分布。
  • 以“串联方式”训练 VAE:首先,编码器和解码器类似地同时训练它们(即,用编码器进行 KL 步骤,然后用解码器和 z 进行 BCE 步骤)
  • 另一方面,当我们将解码器从编码器训练中移除时,会扭曲其性能。这使得整个训练在数学上不太一致,因为它揭示了好的z(好的-closer to standard normal dist)对于好的解码器是不够的。

推论

回想一下,VAE 使用 ELBO 来实现两个目标:

  • 训练将数据映射成接近正态分布 KL-wise 的高斯分布(编码器的目标)
  • 使用该分布的采样来训练解码器生成数据(解码器的目标)

我们看到 ELBO 确实为解码器的目标提供了最佳结果,而当我们仅使用 KL 散度时,编码器的目标获得了更好的结果

一,可以声称,本质部分是生成数据的质量。既然 ELBO 在这方面做得很好,我们也没问题。然而,由于我们希望解码器扮演图像生成器的角色,这一主张遇到了一些障碍,因为我们看到最佳图像是由从非标准分布中抽取的 Z 获得的。

理论

VAE 是一个变分推理问题:我们有一个使用潜在变量创建的观测数据,我们希望找到生成这些潜在变量的最佳分布。在推理阶段,我们使用这个函数来生成新数据。我们看到的是,这个函数不能假设为标准的正态分布。

我们可以假设对于每一个数据 X 和一类潜在变量的分布 P 存在一个分布 q

这优化了解码器。然而,如果希望使用这种分布生成图像,他必须使用编码器进行处理,或者测量 q 的参数,并根据这些参数对解码器的输入进行采样。我们不能假设解码器使用的是通用分布

这项研究的代码可以在这里找到,基于 Altosaar 教授的代码,你可以在这里找到

承认

我要感谢 Uri Itai 和 Shlomo Kashani 在工作期间的审阅和协助

文献学

https://Mr-easy . github . io/2020-04-16-KL-divergence-between-2-Gaussian-distributions/

https://jaan . io/what-is-variable-auto encoder-vae-tutorial/

https://www . cs . Princeton . edu/courses/archive/fall 11/cos 597 c/lessons/variation-inference-I . pdf

https://arxiv.org/pdf/1312.6114.pdf

https://www.math24.net/method-lyapunov-functions/

http://www . wisdom . Weizmann . AC . il/~ vered/courseds 2019/tu t8-李亚普诺夫%20functions.pdf 【利亚波诺夫】

https://stanford.edu/class/ee363/lectures/lyap.pdf

https://chrisorm.github.io/VI-ELBO.html

图片链接

https://unsplash.com/photos/Hba7In7VnM

Python 代码

https://github.com/lyeoni/pytorch-mnist-VAE

https://github.com/altosaar/variational-autoencoder

https://github.com/lyeoni/pytorch-mnist-VAE

性别、技术和开放合作

原文:https://towardsdatascience.com/on-gender-technology-and-open-collaboration-d396bd730caf?source=collection_archive---------46-----------------------

维基百科引文研究

一年多前,维基媒体基金会发布了一份长长的列表,列出了所有维基百科引用的出版物(说英语的人通常只想到英文维基百科,但现在有 306 个不同语言的维基百科在 T2)。引文目录包含超过 1500 万条记录,但只是整体的一个子集;没有唯一标识符(例如,书籍使用的 ISBN 或学术论文的 DOI)的源不会出现。不过,这本集子似乎是一个寻找我一直想知道的问题答案的好地方:性别平衡是什么——不是维基百科传记或维基百科编辑的性别平衡,这两者都以 80%以上是男性而闻名——而是维基百科上引用的作者的性别平衡?

维基百科的链接引用为页面上的声明提供了可验证性,并为引用的来源提供了可见性——潜在的大量可见性。我想更好地了解那里有什么。

对于我的引文查询,我从英文维基百科的数学引文开始,既是因为我喜欢数学,也是因为我在之前已经查看了的数学群组,并且知道像数学谱系项目这样的工具在识别数学家时非常有帮助。维基百科数学文章列表包含超过 28,000 页——25,000 篇主题文章和 3,000 篇传记。我决定不使用基于姓名的预测工具来识别性别,因为这项工作可能很耗时,所以我不得不限制我的范围。这就是为什么从数学项目中,我首先只选择了那些被社区认为是“ top priorit y”(即“文章/主题对其领域极其重要,甚至至关重要”)的页面。

我收集了 239 页最重要的数学页上的引文——总共超过 4000 条引文,其中大约 2750 条有 ISBN。我选择了有一个主要作者或编辑的书,我列出了 1753 个名字(不全是独一无二的;一些作者在不同的书中出现多次和/或同一本书的多次引用)。

我最初认为性别是最难识别的,但我很快发现确定一本书是否有第一作者/编辑是更大的挑战。维基媒体基金会发布的引用数据集不包含作者或书名,只包含参考编号(ISBNs、DOIs 等),尽管我可以查询 Google Books、Open Library 或 ISBNdb 等服务来返回这些信息,但我对不同服务的结果差异如此之大感到震惊,特别是在确定的名称数量方面。

有一次,我试图自己做一致的评估,比较从不同服务返回的元数据,追踪封面看有多少名字出现,翻阅数字化文本看我在标题页上找到了什么。我花了很多时间做这件事,然后决定这是愚蠢的。

为了这次分析,我选择查看马特·米勒分享的数据集中找到的作者,他使用 OCLC 元数据 API收集的英文维基百科上引用的作者和书名记录。如果元数据包含两个或更多的名字——编辑、作者、译者等等——我不认为这本书有第一作者。我不知道返回的信息和维基百科页面上指定的信息有多大差异。数据集不捕获在编辑过的卷中找到的单个作者的姓名,例如,仅捕获编辑的姓名,有时仅捕获几个编辑中的一个编辑(或作者)。

在顶级数学页面的名字中,我将大约 1200 名作者与维基数据中的记录进行了匹配,这是一种以机器可读的形式存储信息(例如在维基百科页面上找到的信息)的服务。为此,我使用了 OpenRefine ,一个用于“处理杂乱数据”的开源工具。

虽然不是每个匹配的人都有维基百科页面,但维基百科的记录几乎总是包括性别。这些匹配中的一小部分可能是我所谓的“Weedon matches”,由谷歌将女权主义学者克里斯·威登(Chris Weedon)与废水系统安装人员克里斯·威登(Chris Weedon)的混搭来说明(见信息框),但我相信大多数是正确的。

我在网上找到了一些简历或提及(一本书或评价我的教授的评论或虚拟国际权威文件 ( VIAF ))证实了大约 400 个不匹配名字的性别——剩下的作者(大约 140 个),我通过名字和照片来识别,或者在没有照片的情况下,简单地根据名字来识别。我经常依靠代词(“他”或“她”,通常出现在简历中)来识别性别;只使用两种性别会排斥和错误识别那些认同二元之外的人。

更难找到年长的作者——退休的学者,他们不再在他们的机构或个人网页上有网页。那些不属于大学的人更难找到。我从讣告上认出了许多老作品的作者,过去和现在在网上存在的不平衡令人难以忘怀。

在我为只有一个第一作者的书所做的数学引文中,我发现了 1661 个男性和 77 个女性,以及一些我无法合理确定性别的作者(大约十几个)。查看一段时间内累积的引用,可以发现有几年,集合中的女性作者根本不存在。

我还查看了第二层数学页面,那些被视为“高”但不是“最高”优先级的页面:863 个维基百科页面包含 4068 个 ISBN 引用(总共 7384 个引用)。在这些书中,我找到了大约 2500 本书的第一作者:2377 名男性和 125 名女性作者——或者约 5%的女性——还有一些我无法确定的名字。

我翻到英文维基百科文学项目中优先级最高的页面,看看这种平衡是否更好。我收集了被指定为“最重要”的 108 页文献中的图书引文(仅超过 850 条引文)。从这个集合中,我确定了大约 600 个第一作者引用,性别划分为 507 个男性和 88 个女性(15%为女性)。

我看了看文献项目中的第二层页面——那些被认为“高”但不是“最高”重要性的页面。在 1167 次图书引用中,我确定了 644 名男性和 185 名女性主要作者(其余的书目——约 330 本——有两个或更多作者,或我无法确定的作者)。在这组页面中,女性作者占所有单人著作的 22%,其中包括几名女性作为页面主题(顶层页面的页面主题中没有女性)。在第三层“中等重要性”中,女性作者约占单作者引文的 27%。

我很好奇我是否能在诗歌项目中找到同样的模式。尽管一些维基百科页面与文学和诗歌都相关,但重要性水平根据每个页面对特定领域的重要性而有所不同。对于诗歌,在最重要的一层,我发现 300 个男性作者和 67 个女性作者的引用(18%)。在第二层,我发现了 578 名男性和 156 名女性(21%)。在第三层,我找到了 1272 名男性和 390 名女性作者(23%)。不同层次之间的差异较小,但这种模式——随着页面重要性的降低,女性作者的比例越来越高——与我在文学作品中看到的一致。

维基百科在传播知识方面发挥着巨大的作用,任何偏见都同样具有破坏性。谁的作品被引用、被引用的频率以及被引用的显著程度,会对我们认为谁是专家以及我们根本看不到谁(尽管他们的工作非常出色)产生重大影响。如果这些数字是社会偏见的一面镜子,那么在平等地听到女性的声音之前,我们还有很长的路要走。

延伸阅读:

米勒、马特《分析英文维基百科引用的书籍》https://medium . com/@ thisismatmiller/Analyzing-Books-Cited-in-English-Wikipedia-d 7520 b 7838 f 3

米丽娅姆·热地;Taraborelli,Dario (2018):维基百科中带有标识符的引文的可访问性和主题。figshare。数据集。https://doi.org/10.6084/m9.figshare.6819710.v1

如果我的电子表格有用或有趣,我会把它们放在这里。这些表格包含来自维基媒体引用数据集的引用,马特·米勒收集的相关作者/书名书籍元数据,以及我自己关于作者性别的笔记和我用来确定作者性别的来源。

关于 IBM 离开面部识别行业

原文:https://towardsdatascience.com/on-ibm-leaving-the-facial-recognition-industry-3b76ef108b91?source=collection_archive---------58-----------------------

它会信守承诺吗?

根据NBC 新闻的一篇文章报道,在对抗议警察暴行和制度性种族主义的回应中,IBM“周一呼吁国会颁布改革以推进种族公正和打击制度性种族主义”。此外,IBM 首席执行官 Arvind Krishna 表示,在多年来备受关注后,该公司将从面部识别技术业务中退出。

第一台便携式计算机 IBM 5100 的图像。(桑德斯坦/ CC BY-SA )

Krishna 发布了以下关于使用 IBM 技术的声明:

"IBM 坚决反对并且不会宽恕将任何技术(包括其他供应商提供的面部识别技术)用于大规模监控、种族定性、侵犯基本人权和自由,或者用于任何与我们的价值观以及信任和透明原则不一致的目的"

虽然这绝对是朝着正确方向迈出的一步,但它并没有消除 IBM 在面部识别技术的利用和发展方面令人担忧的过去。

IBM 与 NYPD 有着非常紧密的联系和历史,特别是在警察局希望在纽约全城安装监控摄像头方面。

NYPD 对监视普通纽约居民活动的着迷导致了与 IBM 的合作,共同开发允许 NYPD 根据肤色对个人进行分类的技术。这一切都是通过秘密合作进行的,只是通过截取者获得了机密公司文件才公之于众。

卡森·马斯特森在 Unsplash 上的照片

鉴于美国国内种族关系紧张和系统性种族主义的状况,这种类型的伙伴关系对有色人种尤其具有破坏性。英国最大的警察部队——伦敦警察厅(Metropolitan Police)进行了一项面部识别技术测试。独立发现产生的98%的警报都是误报,根据报告

英国的另一支警察部队南威尔士警察使用这种技术也产生了非常相似的结果。根据 The Independent 的同一篇文章,自 2017 年 6 月以来,系统“在 15 次部署中返回了超过 2400 个误报,并且在发布时仅发现“ 234 个警报——不到 10%”实际上是正确的。

根据电子前沿基金会(EFF) 通过爱荷华州交通部,针对欺诈性驾驶执照,通过以下步骤进行生物特征数据提取:

  1. 图像被捕获
  2. 确定眼睛位置
  3. 图像被转换为灰度并被裁剪
  4. 图像被转换成搜索引擎用于面部比较结果的模板
  5. 使用复杂的算法搜索和匹配图像,将模板与文件上的其他模板进行比较
  6. 重复证照被查造假

多年来,面部识别技术一直因缺乏实用性和产生真正肯定的能力而受到批评。如前所述,IBM 放弃该行业的转变是一个积极的举措,但这并不表明这是一个永久的举措,这为该公司在获得批准的情况下公开回归敞开了大门。

关于象征性的姿态,这当然是一个积极的发展。然而,警察和国家组织的错误仍然存在,几乎没有什么可以阻止 NYPD 等警察部门寻求其他类似于 IBM 的公司的支持,以生产面部识别和人工智能技术。根据卡耐基国际和平基金会 (CEIP)的一篇论文,截至 2019 年 9 月发表时,“最大的非中国人工智能监控技术供应商是日本 NEC 公司

照片由亚历山大·奈特Unsplash 上拍摄

Clearview AI 是一家利润丰厚的公司,负责开发面部识别应用程序,并处于潜在消除隐私的最前沿"正如我们所知"据纽约时报最近报道了新冠肺炎·疫情和美国反对制度种族主义的抗议活动。在过去几年中,Clearview AI 一直在向外国政府国内执法部门等出售面部识别技术,这引发了人们的担忧。

面部识别技术功能的缺乏应该足以使其不能在公共场合使用,但在过去几周席卷全国的抗议活动之后,看到它成为更常用的工具也就不足为奇了。

虽然 IBM 已经正式停止了这些技术的生产,但 NYPD 等部门仍然可以通过与 IBM 在过去 15 年左右的时间里的合作来获得开发成果,如果 IBM 最终决定在未来重返该行业,这也不足为奇。

用 Python 从零开始实现深度学习库

原文:https://towardsdatascience.com/on-implementing-deep-learning-library-from-scratch-in-python-c93c942710a8?source=collection_archive---------9-----------------------

理解深度学习平台基本构件的初学者指南

深度学习已经在很短的时间内从简单的神经网络发展到相当复杂的架构。为了支持这种快速扩张,许多不同的深度学习平台和库被开发出来。这些库的主要目标之一是为构建和训练深度学习模型提供易于使用的界面,这将允许用户更多地关注手头的任务。为了实现这一点,可能需要将核心实现单元隐藏在几个抽象层之后,这使得难以理解深度学习库所基于的基本底层原则。因此,本文的目标是提供关于深度学习库的构建模块的见解。我们首先浏览深度学习的一些背景知识,以了解功能需求,然后使用 NumPy 浏览 python 中一个简单而完整的库,该库能够对神经网络模型(非常简单的类型)进行端到端训练。在这个过程中,我们将学习深度学习框架的各个组件。这个库只有不到 100 行代码,因此应该很容易理解。完整的源代码可以在 https://github.com/parmeet/dll_numpy 找到

背景

通常,深度学习计算库(如 TensorFlow 和 PyTorch)由下图所示的组件组成。

深度学习框架的组件

经营者

也可与层互换使用,它们是任何神经网络的基本构建块。运算符是转换数据的向量值函数。一些常用的操作符是线性、卷积和池化等图层,以及 ReLU 和 Sigmoid 等激活函数。

优化者

他们是任何深度学习图书馆的骨干。它们提供了必要的配方,使用它们相对于优化目标的梯度来更新模型参数。一些著名的优化器有 SGD、RMSProp 和 Adam。

损失函数

它们是封闭形式且可微分的数学表达式,用作手头问题的优化目标的替代。例如,交叉熵损失和铰链损失是分类任务常用的损失函数。

初始值设定项

它们在训练开始时提供模型参数的初始值。初始化在训练深度神经网络中起着重要的作用,因为不好的参数初始化会导致收敛缓慢或不收敛。有许多方法可以初始化网络权重,比如从正态分布中抽取小的随机权重。你可以看看 https://keras.io/initializers/的综合名单。

正则化子

它们提供了必要的控制机制来避免过度拟合和促进泛化。人们可以通过显性或隐性措施来调节过度拟合。显式方法对权重施加结构约束,例如,最小化它们的 L1 范数和 L2 范数,分别使权重更稀疏和均匀。隐式度量是对中间表示进行转换的专用运算符,或者通过显式规范化(例如 BatchNorm),或者通过更改网络连接(例如 DropOut 和 DropConnect)来进行转换。

上述组件基本属于库的前端部分。对于前端,我指的是向用户公开的组件,以便他们有效地设计神经网络架构。在后端,这些库为自动计算损失函数相对于模型中各种参数的梯度提供支持。这种技术通常被称为自动微分(AD)。

自动微分

每个深度学习库都提供了一种 AD 风格,以便用户可以专注于定义模型结构(计算图)并将梯度计算的任务委托给 AD 模块。让我们通过一个例子来看看它是如何工作的。假设我们想要计算以下函数相对于其输入变量 X₁X₂ 的偏导数:

***Y =* sin(*x₁*)*+X₁*X₂***

下图是我从https://en.wikipedia.org/wiki/Automatic_differentiation那里借来的,展示了它的计算图和用链式法则计算导数。

计算图和用链式法则计算导数

你在上图中看到的是一种逆向模式自动微分(AD)的味道。众所周知的反向传播算法是上述算法的特例,其中顶部的函数是损失函数。AD 利用了这样一个事实,即每个复合函数都由初等算术运算和初等函数组成,因此导数可以通过递归地将链规则应用于这些运算来计算。

履行

在前面的部分中,我们已经检查了所有必要的组件,以提出我们的第一个可以进行端到端训练的深度学习库。为了简单起见,我将模仿Caffe库的设计模式。这里我们定义了两个抽象类:一个“函数”类和一个“优化器”类。此外,还有一个“Tensor”类,它是一个简单的结构,包含两个 NumPy 多维数组,一个用于保存参数值,另一个用于保存它们的梯度。各种层/操作符中的所有参数都是“张量”类型。在我们深入探讨之前,下图提供了该库的高级概述。

图书馆的 UML 图

在撰写本文时,该库附带了线性层、ReLU 激活和 SoftMaxLoss 层以及 SGD 优化器的实现。因此,该库可用于训练包括全连接层和 ReLU 非线性的分类模型。现在让我们来看看两个抽象类的一些细节。

“Function”抽象类为操作者提供了一个接口,定义如下:

抽象函数类

所有操作符都是通过继承“Function”抽象类来实现的。每个操作符必须提供一个 forward(…)backward(…) 方法的实现,并可选地实现 getParams 函数以提供对其参数的访问(如果有的话)。 forward(…) 方法接收输入,并通过操作符返回其转换。它还将执行计算梯度所需的任何内务处理。 backward(…) 方法接收损失函数相对于算子输出的偏导数,并实现损失相对于算子输入和参数(如果有)的偏导数。注意 backward(…) 函数本质上为我们的库提供了执行自动微分的能力。

为了使事情具体化,让我们看看线性函数的实现,如下面的代码片段所示:

线性函数的实现

forward(…) 函数实现形式 **Y = XW+b 的转换并返回。它还存储输入 X,因为这是计算后向函数中 W 的梯度所需要的。 backward(…) 函数接收损耗对输出 Y 的偏导数 dY ,并实现对输入 X 和参数 Wb 的偏导数。此外,它返回关于输入 X 的偏导数,该偏导数将被传递到前一层。***

抽象的“优化器”类为优化器提供了一个接口,定义如下:

抽象优化器类

所有优化器都是通过继承“Optimizer”基类来实现的。具体的优化类必须提供步骤()函数的实现。该方法使用模型参数相对于我们正在优化的损失的偏导数来更新模型参数。在 init(…) 函数中提供了对各种模型参数的引用。注意重置渐变的常用功能是在基类本身实现的。

为了使事情具体化,让我们看看动量和重量衰减的随机梯度下降(SGD)的实现。

开始真正的东西

为此,我们拥有使用我们的库来训练(深度)神经网络模型的所有成分。为此,我们需要以下内容:

  • 这是我们的计算图
  • 数据和目标:这是我们的训练数据
  • 损失函数:我们优化目标的替代
  • 优化器:更新模型参数

下面的伪代码描述了一个典型的训练周期:

****model** *#computation graph*
**data,target** #*training data*
**loss_fn** *#optimization objective*
**optim** *#optimizer to update model parameters to minimize loss***Repeat:**#until convergence or for predefined number of epochs
   **optim.zeroGrad()** *#set all gradients  to zero*
   **output = model.forward(data)** *#get output from  model*
   **loss   = loss_fn(output,target)** *#calculate loss*
   **grad   = loss.backward()** *#calculate gradient of loss w.r.t output*
   **model.backward(grad)** *#calculate gradients for all the parameters*
   **optim.step()** *#update model parameters***

虽然不是深度学习库的必要成分,但将上述功能封装在一个类中可能是一个好主意,这样我们就不必在每次需要训练新模型时重复自己(这符合像 Keras 这样的高级抽象框架的哲学)。为此,让我们定义一个类“模型”,如下面的代码片段所示:

该类提供以下功能:

  • 计算图:通过 add(…) 功能,可以定义一个顺序模型。在内部,该类将简单地将所有操作符存储在一个名为calculation _ graph的列表中。****
  • 参数初始化:在训练开始时,该类将使用从均匀分布中抽取的小随机值自动初始化模型参数。
  • 模型训练:通过 fit(…) 函数,该类提供了一个训练模型的通用接口。这个函数需要训练数据、优化器和损失函数。
  • 模型推断:通过 predict(…) 函数,该类提供了一个通用接口,用于使用经过训练的模型进行预测。

由于这个类不是深度学习的基础构建块,我在一个名为 utilities.py 的单独模块中实现了它。注意, fit(…) 函数使用了 DataGenerator 类,其实现也在 utilities.py 模块中提供。这个类只是我们训练数据的包装器,为每次训练迭代生成小批量数据。

训练我们的第一个模型

现在让我们来看最后一段代码,它使用建议的库来训练神经网络模型。受 Andrej Karapathy博文的启发,我打算在螺旋数据上训练一个隐层神经网络模型。utilities.py 文件中提供了生成数据及其可视化的代码。

三类螺旋数据

一个三级螺旋数据如上图所示。数据是非线性可分的。因此,我们希望我们的单隐层神经网络能够学习非线性决策边界。综上所述,下面的代码片段将训练我们的模型。

用于训练神经网络模型的端到端代码

下图显示了相同的螺旋数据以及训练模型的决策边界。

螺旋数据与训练模型的相应决策边界

结束语

随着深度学习模型的复杂性不断增加,这些库在功能和底层实现方面都倾向于以指数速度增长。也就是说,非常核心的功能仍然可以在相对较少的代码行中实现。尽管该库可用于训练端到端神经网络模型(非常简单的类型),但它仍在许多方面受到限制,这些方面使深度学习框架可用于各种领域,包括(但不限于)视觉、语音和文本。也就是说,我认为这也是一个派生基本实现和添加缺失功能的机会,以获得您的实践经验。您可以尝试实现的一些事情有:

  • 运算符:卷积池等。
  • 优化者:亚当 RMSProp 等。
  • 调整人员:批次正常退出等。

我希望这篇文章能让你一窥当你使用任何深度学习库来训练你的模型时,在引擎盖下会发生什么。感谢您的关注,我期待着您的评论或评论区的任何问题。

具有工作示例的对象检测度量

原文:https://towardsdatascience.com/on-object-detection-metrics-with-worked-example-216f173ed31e?source=collection_archive---------2-----------------------

AP、mAP 和 AP50 以及其他度量都通过一个示例进行了说明。

照片由 XPSUnsplash 上拍摄

平均精度(AP)和平均平均精度(mAP)是用于评估对象检测模型的最流行的度量,例如更快的 R_CNN、掩模 R-CNN 和 YOLO 等等。相同的指标也用于评估 COCO 和 PASCAL VOC 挑战赛等比赛中的提交材料。

我们可以从 AP 中导出其他度量。例如,mAP、AP50、AP75 和 AP[.5:.5:.

在本文中,我们将仔细阅读这些概念,以便在一天结束时,您能够清楚地理解它们。下图(图 1 和图 2)显示了这些指标在一些最新(SOTA)模型中的使用情况。

图 1:分别在掩码 RCNN ( )和 YOLOv3 ( )中使用的度量。

图 COCO 挑战赛中使用的一些指标(来源

在低层次上,评估对象检测器的性能归结为确定检测是否正确。

术语定义:

  • 真阳性(TP) —模型做出的正确检测。
  • 假阳性(FP) —检测器的错误检测。
  • 假阴性(FN) —物体检测器遗漏(未检测到)的基本事实。
  • 真阴性(TN)—这是模型正确检测不到的背景区域。在对象检测中不使用该度量,因为在准备注释时没有明确地注释这些区域。

我们需要另一个名为 T22 交集/并集(IoU)的辅助指标来以更可量化的方式定义这些术语。

并集上的交集

对象检测中的 IoU 度量评估地面 ( *gt* ) 真实与预测 ( *pd* ) 之间的重叠程度。基本事实和预测可以是任何形状-矩形盒、圆形或不规则形状)。其计算方法如下:

用图解法,IoU 定义如下(相交面积除以地面实况和预测框之间的联合面积。

图 3:欠条(来源:作者)

IoU 的范围在 0 和 1 之间,其中 0 表示没有重叠,1 表示*gt**pd*之间完全重叠。IoU 度量通过阈值处理是有用的;也就是说,我们需要一个阈值(比如说α)来确定检测是否正确。

对于α处的 IoU 阈值,真阳性(TP)是对IoU(*gt,pd)*≥ α的检测,假阳性是对IoU(*gt,pd)*< α的检测。假阴性是与IoU(*gt,pd)*< α.一起错过的*gt* 地面真相

清楚了吗?如果不是,下图应该会使定义更清楚。

考虑 IoU 阈值,α = 0.5,则 TP、FP 和 FNs 可以如下图 4 所示确定。

图 4:通过 IoU 阈值识别 TP、FP 和 FN。

注意:如果我们把 IoU 阈值提高到 0.86 以上,第一个实例就是 FP;如果我们将 IoU 阈值降低到 0.24 以下,第二个实例就变成了 TP。

备注:将检测标记为 TP 或 FP 以及将地面实况标记为 FN 的决定完全取决于 IoU 阈值α的选择。例如,在上图中,如果我们将阈值降低到 0.24 以下,那么第二个图像中的检测将变为 TP,如果 IoU 阈值升高到 0.86 以上,则第一个图像上的检测将为 FP。

精确度和召回率

精度是模型仅识别相关对象的精确程度。它是 TPs 与模型进行的所有检测的比率。

回忆测量模型检测所有基本事实的能力——所有基本事实中的 TPs 命题。

等式 1:精确度和召回率

一个模型如果精度高,召回率高,就说是好的。一个完美的模型有零 FNs 和零 FPs(精度=1,召回=1)。通常,获得一个完美的模型是不可行的。

精确 x 召回曲线(PR 曲线)

注意:在继续之前,请看这个图并阅读它的标题。

这是使用屏蔽 R-CNN 进行的检测。它显示了一个边界框(虚线)、分割遮罩、类(水果)和置信度得分(0.999)。对象检测模型通常输出边界框、置信度得分和类别。置信度值是模型在检测中的置信度,其范围在 0 和 1 之间。

就像前面 IoU 描述的一样,置信度评分也依赖于阈值。提高置信度得分阈值意味着模型将错过更多的对象(更多的 fn,因此低召回和高精度),而低置信度得分将意味着模型获得更多的 FPs(因此低精度和高召回)。这意味着我们需要在精确度和召回率之间进行权衡。

精确度-召回率(PR)曲线是不同置信度下精确度和召回率的曲线图。对于一个好的模型来说,即使置信度变化,精确度和召回率仍然很高。

平均精度

AP@α是在α IoU 阈值下评估的精确召回曲线(AUC-PR)下的面积。形式上定义如下。

等式 2:平均精度的定义

符号: AP@α或 APα表示 AP 精度在α IoU 阈值处评估。如果您看到 AP50 和 A75 这样的指标,它们分别表示在 IoU=0.5 和 IoU=0.75 时计算的 AP。

PR 曲线下的高面积意味着高召回率和高精度。自然,PR 曲线是一个锯齿形的曲线。这意味着它不是单调递减的。我们可以使用插值方法消除这一特性。我们将在下面讨论其中的两种插值方法:

  1. 11 点插值法
  2. 全点插补方法

11 点插值法

11 点 AP 是在 11 个等间隔的标准回忆水平,即 0.0,0.1,0.2,.。。1.0.它被定义为

等式 3: 11 点插值公式

其中,R = {0.0,0.1,0.2,.。。1.0}和

等式 4:支持等式 3

召回值处的插值精度,r — 它是任何召回值 r'≥ r 的最高精度,如果这个没有意义,我向你保证,一旦我们通过一个例子,它就完全有意义了。

所有点插值法
在这种情况下,对所有位置(回忆值)进行插值,即,

等式 5:所有点插值方法

平均精度

备注(AP 和班级数): AP 是针对每个班级单独计算的。这意味着 AP 值和类的数量一样多(不严格)。这些 AP 值被平均以获得平均精度(mAP) 度量。

定义:平均精度(mAP)是所有类的 AP 值的平均值。

备注(AP 和 IoU) :如前所述,AP 是在给定的 IoU 阈值α下计算的。通过这种推理,可以在一个阈值范围内计算 AP。微软 COCO 计算了给定类别/类在 10 个不同 IoU 下的 AP,范围从 50%到 95%,步长为 5%,通常表示为 AP@[.50:.5:.95]。 Mask R-CNN 报道 AP@[.50:.5:.上面写着

“我们报告了标准 COCO 指标,包括 AP(IoU 阈值的平均值)、AP50、AP75 以及 APS、APM、APL(不同规模的 AP)”—摘自 Mask R-CNN 论文

为了使所有这些事情更清楚,让我们来看一个例子。

例子

考虑下面图 5 中显示的 3 个图像。它们包含 12 个检测(红色方框)和 9 个基本事实(绿色)。每个检测都有一个由字母和模型置信度标记的类别。在本例中,假设所有检测都属于同一对象类别,IoU 阈值设置为α= 50%。IoU 值如下表 1 所示。

图 5:检测同类对象的模型。有 12 个检测和 9 个地面真相。

备注(多次检测):例如图像 1 中的 c,d,图像 2 中的 g,f,图像 3 中的 i,k。对于类似的多个检测,置信度最高的检测标记为 TP,所有其他检测标记为 FPs,前提是该检测具有 IoU≥阈值的真值框。这意味着:

  • c 和 d 成为 FPs 是因为它们都不满足阈值要求。 cd 分别有 47%和 42%的欠条,而要求的是 50%。
  • g 是 TP,f 是 FP 。两者的 iou 都大于 50%,但 g 的信心为 97%,而 f 的信心为 96%。
  • ik 呢?

图像中同一物体的多次检测被视为错误检测,例如,单个物体的 5 次检测被视为 1 次正确检测和 4 次错误检测— 来源:PASCAL VOC 2012 论文

一些检测器可以输出与单个地面实况重叠的多个检测。对于这些情况,具有最高置信度的检测被认为是 TP,而其他的被认为是 FP,如 PASCAL VOC 2012 挑战所应用的。-来源:对象检测算法性能指标调查论文。

表 1: IoU 阈值,α = 50%。cumTP 和 cumFP 分别是 TP 和 FP 列的累积值。all _ detections = cumTP+cumFP。

重要提示:在填写 cumTP、cumFP、all_detection、precision 和 recall 之前,您需要按照置信度降序对表格值进行排序。精度是累计/所有检测,召回是累计/实际数量。我们有九个基本事实。

11 点插补

为了使用 11 点插值计算 AP@0.5 的近似值,我们需要对 R 中召回值的精度值求平均值(见等式 3),即召回值 0.0、0.1、0.2、.。。1.0.如下图 6 所示。

图 6:左:所有精确召回值的图表。右图:匹配以下召回值的 11 个精度值:0.0,0.1,…,1.0。

所有点插值

根据等式 5 中的定义,我们可以使用以下所有点插值法计算 AP@50。

图 7:左:覆盖原始 PR 曲线的所有点插值曲线(红色)。右图:所有点插值的区域

简而言之,所有点插值包括计算和求和图 1.3b 中四个区域(R1、R2、R3 和 R4)的面积值,也就是说,

仅此而已!

备注:回想一下,我们说过 AP 是为每个类计算的。我们的计算是针对一门课的。对于几个类别,我们可以通过简单地取不同类别的结果 AP 值的平均值来计算 mAP。

这是另一篇关于对象检测指标的文章

[## 混淆矩阵和目标检测

一种评估实例分割模型性能的度量

towardsdatascience.com](/confusion-matrix-and-object-detection-f0cbcb634157)

结论

看完这篇文章,希望你很好的理解 AP,mAP,PR 曲线。您还注意到 IoU 是一个重要的概念,因为如果不基于 IoU 定义阈值,我们就无法定义这些指标。我们还了解到,AP 是按类计算的,得到的 AP 值的平均值就是地图。对于不同的 IoU 阈值,也可以计算 AP。

同样重要的是要注意,预测掩码不一定是矩形框。它可以是任何形状,特别是被检测物体的形状。下图显示了形状不规则的检测示例。

图 8:基本事实(蓝色圆圈)和检测(红色遮罩)。预测不是规则形状的面具。

如果你觉得这篇文章很有帮助,并且想了解 Python 的实现,请给我写信。我个人资料上的电子邮件。

更多文章

[## 7 个月的关系,WhatsApp 消息分析

使用 Python 分析 WhatsApp 数据。如此简单。任何人都可以跟随。

towardsdatascience.com](/7-months-of-a-relationship-whatsapp-messages-analyzed-e5c34b8aaa63) [## 使用 Selenium 的 Web 抓取电子商务网站

抓取网上书店的一个简单例子。

towardsdatascience.com](/web-scraping-e-commerce-website-using-selenium-1088131c8541)

参考

https://medium.com/@kiprono_65591/membership加入 medium可以全面了解 Medium 上的每个故事。

你也可以在我发文章的时候通过这个链接把文章发到你的邮箱里:【https://medium.com/subscribe/@kiprono_65591

一如既往地感谢您的阅读:-)

F. Chollet (2019)的《论智力的衡量》

原文:https://towardsdatascience.com/on-on-the-measure-of-intelligence-by-f-chollet-2019-9c78f8546dc4?source=collection_archive---------32-----------------------

走向心理测量&智能系统基于能力的评估

上周 Kaggle 宣布了一项新的挑战。这是一个在许多方面都不同的挑战。它基于抽象和推理语料库&,并附有一篇由 Francois Chollet 撰写的近期论文。在这项工作中,Chollet 强调了当前人工智能研究议程的几个缺点&主张对智能系统进行心理测量&能力评估,这允许标准化&可靠的比较。更重要的是,它引入了一个可操作的类人一般智力的定义,该定义基于先验、经验和推广难度的概念。这个定义可以被研究团体用来衡量进展和为一个共同的目标而共同努力。读完论文后,在我们的阅读小组中讨论(你可以在这里查看海纳·斯皮斯的演讲)以及重读,我的头脑仍然在整理知识内容。所以请继续关注我&让我给你一个 64 页的金矿的自以为是的总结。我还稍微探索了一下抽象的&推理语料库基准,所以如果你想开始处理智能,请留下来!

机器学习研究的进展绝对不是为了寻找下一个性感的技能或游戏。但这种感觉时常如此。DeepBlue、AlphaGo、OpenAI 的 Five、AlphaStar 都是大规模公关活动的例子,它们在“成功”宣布后不久就被批评缺乏普遍性。每一次“技能球”被推得更远…到下一个挑战性的游戏(也许是为了某种心智理论合作多智能体学习的 Hanabi?).但是我们最终会在哪里?解决每个游戏的独立算法不一定能推广到更广泛的类似人类的挑战。游戏只是一个人工子集,并不代表我们物种生态位的全部(这允许快速的数据生成)。简而言之:智力不仅仅是学习技能的集合。因此,人工智能研究社区必须确定一个共同的目标——一个一致的智能目标定义。

从历史上看,有许多测量智力的尝试——或多或少有些重叠。Chollet 的论文首先回顾了两个主要支柱:基于技能和基于能力的智力评估。他认为,虽然技能是智能系统的重要输出,但它们仅仅是人工制品。另一方面,能力允许我们扩大可能的技能输出空间。通过学习的魔力(例如,基于进化/梯度、基于可塑性、基于神经动力学),智能系统能够将先前的知识和经验与新的情况相结合。这种适应性的&面向任务的和非常有条件的过程可能最终受到智力的症结的影响。

对我来说,显而易见的是,学习和相关的特定领域归纳偏差的出现(比如我们的身体和神经系统)必定是智力的核心。它跨越了所有的时间尺度,并与杰夫·克伦大卫·哈以及布莱斯·阿格拉在 NeurIPS 2019 期间推广的想法产生了很大的共鸣。我们的机器学习基准也应该反映这个高层次的目标。这并不是说已经有了相当多的尝试,包括以下内容:

尽管如此,社区中的大多数人仍然致力于解决类似的利基问题,这些问题远离一般化和类似人类的一般智力。那么我们能做些什么呢?

AI & ML 社区一直梦想着一个前所未有的通用智能概念。人类的认知和大脑提供了一个自然的第一个起点。但神经科学的发现似乎缓慢/模糊,如何将低水平的细胞灵感转化为归纳偏差的算法版本往往不明显。另一方面,心理学和心理测量学——心理测量的学科(根据维基百科)——提供了不同层次分析的见解。Chollet 建议不要再忽视来自已经开发了人类智力测试几十年的社区的见解。

他的一个主要论点是反对通用的 g 因子。相反,所有已知的智能系统都以它们的环境和任务规范为条件。人类的智慧是为人类的问题而优化的。因此在解决可能在火星上遇到的问题上表现不佳。这就是所谓的‘智力没有免费的午餐定理’。因此,我们对智力的所有定义也只在人类参照系中有效。我们不应该忽视拟人化但可操作的智力评估,而是应该接受它。心理测量的视角可以让我们清楚地了解我们的开发者偏见和我们构建到人工系统中的先验知识。Chollet 建议开发以人为中心的智力测试,它结合了人类认知先验&核心知识的发展心理学概念。这些包括不同层次的描述(例如低层次的感觉运动反射、学习如何学习的能力以及高层次的知识)以及先天能力(例如初等几何、算术、物理&机构)。因此,情报的可操作定义如下:

“一个系统的智能是对它在一个任务范围内的技能获取效率的度量,包括先验知识、经验和概括难度。”—Chollet(2019;第 27 页)

此外,Chollet 还提供了一种基于算法信息论的人工系统智能测量方法:

简而言之:智力的度量可以解释为当前信息状态和在不确定的未来表现良好的能力之间的转换率。它考虑了任务的概括难度、先验知识和经验&考虑了任务的主观权重以及我们关心的任务的主观结构。这项措施与提出的任务范围(生态位)相联系,将技能仅仅视为产出的人工制品属性,并以课程优化为基础。在高层次上,这个度量可以用来定义一个自顶向下的优化目标。这将允许应用一些链式法则/自动微分魔法(如果生命是平滑可微分的),最重要的是量化进展。它损害了先前的知识和经验,从而遵循了上述原则。

显而易见的下一个问题是:那么我们如何才能真正按照这样的衡量标准行事呢?

抽象和推理语料库通过引入一种旨在评估和提供人工智能可重复测试的新基准来解决这个问题。它让人想起经典的瑞文渐进矩阵,有时甚至对人类来说也很棘手。每个任务(见上面的例子)为系统提供一组示例输入-输出对,并查询测试输入的输出。系统最多可以提交 3 个解决方案,并接收一个二元奖励信号(对/错)。上述任务的具体解决方案需要对重力的概念有一个大致的了解。输出只是将对象“放下”到图像数组的底部。但这只是一个解决方案示例。基准要宽泛得多,需要不同的核心知识概念。整个数据集由 400 个训练任务、400 个评估任务和另外 200 个坚持测试任务组成。很刺激,对吧?

在过去的几天里,我一直在用基准测试来弄脏我的手。当试图使用即插即用深度(强化)学习时,有几个基本问题。最初,问题在于不规则的输入/输出形状。如果您训练您最喜欢的 MNIST-CNN,输入和输出层形状都是固定的(即 32x32 和 10 个输出数字标签)。从这个意义上说,ARC 基准并不规则。有时有两个不同形状的例子&输出查询有一个不同的例子。因此,不可能训练具有单一输入/输出层的网络。此外,示例的数量也有所不同(见下图),并且不清楚如何利用这 3 次尝试。我最初的想法是对给定的例子进行 k 重交叉验证训练,并尝试利用来自相关 DL 社区的想法(例如 PrediNet )。两人一组训练,最后一个例子测试。只有在收敛&零交叉验证错误后,我们才能进行实际的测试用例。主要问题:每个例子的在线训练。这可能会变得相当计算密集型。

一种利用尝试可能性的可能方式可能是元强化学习目标的形式。这可以允许快速适应。因此,我们将在与 oracle 的 3 次闭环交互中优化性能。这也可以通过训练一个 RL LSTM 来完成,它接收先前的尝试反馈作为输入。以下是一些更具挑战性的见解:

  • 必须有涉及适应或程序合成的特定任务训练。仅仅将所有先验硬编码到一个简单的前馈网络中是不够的。
  • 当我们人类看到输入-输出对时,我们会立即找出正确的先验来处理运行中的测试示例。这包括定义解决方案空间的调色板。如果训练输出具有三种类型的唯一数字像素值,则测试输出不太可能有 20 个。
  • 我意识到,当我试图解决一个任务时,我会做很多跨任务推理。双重检查假设并执行基于模型的交叉验证。将推断框定为重复假设检验可能是一个很酷的想法。
  • 最小化逐像素的 MSE 损失在根本上是有限的。因为在解决方案的评估中没有半错,所以即使很小的 MSE 损失也会导致错误的输出。
  • 核心知识很难编码。关系深度学习和几何深度学习提供了有前途的前景,但仍处于初级阶段。我们还远远不能用元学习来模拟进化。
  • 试图解决所有问题的目标过于雄心勃勃(就目前而言)。

Chollet 自己提议进入一个叫做 程序合成 的领域。直觉上,这需要你自己生成程序来解决一些任务,然后在更高的层次上学习这样的程序生成。

尽管如此,所有这些想法都留下了一个问题,即归纳偏见应该用于哪些方面:视觉处理的回旋,集合运算的注意力,记忆的 RNN,以及对抗遮挡/客体持久性?我为每个有兴趣开始使用基准测试的人起草了一个小笔记本。你可以在这里找到。在这里你可以找到一个 Kaggle 内核,它为 ARC 中的 10 个任务提供“手动”解决方案。

我非常喜欢杰弗里·辛顿的这句话:

“未来取决于某个对我所说的一切深感怀疑的研究生。”

这是一种严重怀疑的表达,尽管反向传播和重大深度学习突破无处不在。在过去的日子里,我的经历让我非常谦卑,也让我看清了许多事情。我喜欢被最近的进展所宣传,但在 ML 社区面前也有巨大的挑战。深度学习目前的形式绝对不是智能的圣杯。它缺乏灵活性、效率和分发性能。智能系统还有很长的路要走。ARC 基准提供了一个很好的途径。所以让我们开始吧。

附注:挑战持续 3 个月。

原载于 2020 年 2 月 10 日https://roberttlange . github . io

深度神经网络的优化

原文:https://towardsdatascience.com/on-optimization-of-deep-neural-networks-21de9e83e1?source=collection_archive---------22-----------------------

对经典发展的随机漫步,使深度学习成为最终的学习机器

图片来源:A. Amini 等.端到端控制的空间不确定性采样。NeurIPS 贝叶斯深度学习 2018

AlexNet 在一个流行的图像分类基准上的成功让深度学习在 2011 年成为焦点。自那时以来,它在许多领域取得了非凡的成就。

最值得注意的是,深度学习对计算机视觉、语音识别和自然语言处理(NLP)有着特殊的影响,单枪匹马地让人工智能再次焕发生机。

表面上,人们可以将功劳归于大型数据集和计算资源的高可用性。但从根本上来说,它们只是为神经网络提供燃料,让其更进一步。

是什么帮助神经网络理解了庞大的数据集?

在过去十年中,使神经网络成为最终学习机器的少数但非凡的发展到底是什么?

早在 1998 年,Yann LeCun 等人发表了一章关于 高效反向传播 的文章。为了有效地训练神经网络,作者提出了一些实用的指导方针。

这些指南强调随机学习、样本混排、标准化输入、激活函数、网络初始化和自适应学习速率。

不幸的是,没有标准化的工具来应用这些现成的想法。要聚合一个深层网络是极其困难的,更不用说在看不见的数据上推广它了。

幸运的是,这些指南为未来几年开发更正式的工具铺平了道路。

神经网络在努力解决什么问题?

训练深度神经网络的许多困难是由于网络初始化不良和较低层的梯度不足造成的。

Hinton 等人和 Yoshio 等人探索了贪婪分层训练的思想。在这一范式中引人注目的两篇论文是“和“ 深度网络的贪婪分层训练。这两篇论文首次成功训练了更深层次的网络。

不幸的是,前面提到的仍然需要额外的努力来一层一层地训练网络,然后对整个网络进行微调。

为了获得我们今天看到的深度学习的巨大成功,需要开发正式的技术,而不仅仅是黑客。

我们需要能够跨领域、在各种环境下工作的工具。我们需要一个生态系统来训练神经网络。

幸运的是,在少数精英的所有指导原则和非凡努力下,我们已经走过了深度学习可以展示其真正潜力的临界点。

以下是深度学习生态系统中一些重要的发展,这些发展使它成为每个工程师工具箱中家喻户晓的名字。

激活功能

非线性是神经网络的动力。没有它,神经网络就缺乏表达能力,只能简单地归结为输入数据的线性变换。

不幸的是,涉及指数(sigmoid,双曲线正切等)的激活。)用于实现非线性已经有了它们的问题。一旦到达饱和区域,它们就变得极其不愿意允许梯度流,这极大地抑制了网络的学习潜力。

幸运的是,AlexNet 前来救援,并首次展示了整流线性单元(ReLU)作为激活函数的未触及潜力。

ReLU 有助于更快地训练网络(由于其不饱和的性质),并使得以端到端的方式训练更深的网络成为可能。

ReLU 成为深度学习工具包的默认激活选择。从优化的角度来看,它解决了长期存在的所谓消失梯度的问题。

规范化初始化

优化神经网络是一个高度非凸的问题。很少有什么事情比网络权重初始化不好更有害的了。

确定一个好的初始化策略的挑战首先在有影响力的工作“理解训练深度前馈神经网络的困难”中被探索和解决。

在这里,作者推导出每一层的均匀分布的适当范围。该分布用于对网络初始化的权重进行采样。它通常被称为泽维尔的初始化。

遗憾的是,作者为得出采样分布范围所做的假设导致了 Xavier 初始化与 ReLUs 的糟糕结合(记住激活的默认选择!).幸运的是,论文“深入研究整流器”通过调整适合 ReLUs 的均匀分布范围,提供了一个解决方案。该修复使其工作得如此之好,以至于这篇论文成为 ImageNet 分类的获奖作品。这种初始化通常被称为明凯初始化。

Xavier 和明凯的初始化都提供了开箱即用的初始化工具包。现在,当事情没有按计划进行时,研究人员又少了一件可以指责的事情!

权重正则化

在给定大量参数的情况下,神经网络可以很容易地(过度)适应训练示例。这自然要求网络正规化。

权重衰减(也称为 L2 正则化)是机器学习中常用的正则化技术之一。不幸的是,这可能会限制网络发挥其全部潜力。

Hinton 等人引入了 dropout 的概念,这可能是迄今为止网络正规化最优雅的解决方案。提出的关键思想是在训练中随机丢弃单位(因此得名 dropout)。这有助于避免特征的共同适应,从而大大减少过度拟合。

从优化的角度来看,对于任何给定的训练示例,只有一部分网络权重被更新。

这在集成方法的精神上是相似的,其中每个学习者仅暴露于部分训练数据。最终,最终训练的网络是具有共享权重的(指数数量的)网络的集合。

Dropout 提供了一种现成的解决方案来规范深度神经网络。

特征标准化

数据规范化或标准化的概念在机器学习中并不新鲜。数据标准化可以有效优化学习算法。

深度学习只是一堆层,将它的输入转换并传递给下一层。因此,没有充分的理由将数据规范化限制在第一层。

对每一层的输入进行规范化的想法最初是在名为批处理规范化的论文中正式提出的。这项工作在 ImageNet 分类基准测试中取得了最佳性能,以快一个数量级的训练时间打破了所有以前的记录。

特征标准化可能是加速深度网络优化的最有效的技术。批处理规范化是这个范例中的明显赢家!

批处理规范化也适用于各种学习速率,并减少了对显式网络规范化的需求。它为加快培训提供了现成的解决方案。

网络体系结构

随着深度而来的是抽象的力量。这导致更好的概括和测试误差的改进。不幸的是,梯度流不足成为训练更深网络的瓶颈。

这一次 ResNets 前来救援。微软研究院的研究人员在他们名为图像识别深度残差学习的里程碑式论文中提出了残差连接的想法。

捷径连接和剩余学习的想法并不新鲜。人们可以将它与其他经典著作相比较,包括高速公路网络长短期记忆(LSTM)网络。在深度学习之外,梯度增强决策树(GBDT)还学习每个连续树中的剩余函数。

也就是说,深度剩余学习论文的作者首次展示了如何通过身份映射的方式有效地实现剩余学习!

本文中的关键假设是剩余函数更容易学习。这可以通过简单地提供从层输入到层输出的直接连接来实现。这导致向前传递期间更好的信息流和向后传递中有效的梯度流。

从优化的角度来看,它简单地消除了梯度消失的问题,并使理论上训练非常深的网络成为可能。

Residual connections 提供了一个现成的解决方案,可帮助您更深入地了解情况。

优化者

前述工具提供了获得网络参数更新的适当梯度的必要元素。最终,我们需要设计一个有效的策略来利用这些梯度。

这一次,灵感以 动量 的形式来自物理学。

最常用的优化器之一是随机梯度下降(SGD)。不幸的是,SGD 有内在的局限性,因为它只采用一阶信息。它无法与使用二阶信息(即所谓的动量)的优化器竞争。

通过利用二阶动态,优化器可以有效地获得每个参数的自适应学习率。这反过来有助于极快的收敛,如下图所示,作者是亚历克·拉德福德。这里,SGD 与其他使用动量的优化器进行比较。

图片来源:亚历克·拉德福德

如何直观地思考动量?

想象两个球,一个在斜坡上滚动,另一个在碗中滚动。如果两个球都听天由命,会发生什么?

对于第一个碗,它不断增加其速度(换句话说,动量),而对于第二个碗,在几次摆动后,它将简单地在碗的底部静止不动。

同样的事情也会发生在参数上。如果重量倾向于向某一特定方向移动,动量就会增加(就像一个滚球在向下的斜坡上)。通过考虑这种势头,人们可以更快地更新权重,并以更少的步骤收敛。相反,如果重量主要围绕某一点波动(就像碗内滚动的球),这就破坏了动量。这将有效地将学习率设置为接近于零,最终将参数设置为其局部最优。

这一范式中最引人注目的作品是 Adam:一种随机优化的方法。在撰写本文时,它被引用了超过 40k 次(与 ResNet 大致相同),是深度学习从业者中明显的赢家和优化器的共同选择。

结束语

早在 1998 年就有一章关于高效反向传播的文章发表,这激发了许多上述当代工具的发展。

我们花了将近 20 年的时间开发工具,在广泛的环境中优雅地解决几个培训问题。幸运的是,随着所有这些进步,训练神经网络不再是一门艺术

一个勤奋的工程师可以简单地用几行 Python 代码将不同的部分组合在一起,几乎可以保证获得好的结果。

这真正将 黄瓜农民场景 带入了生活,导致深度学习的广泛适应,该领域不再局限于少数精英。

政策上的 v/s 政策外的学习

原文:https://towardsdatascience.com/on-policy-v-s-off-policy-learning-75089916bc2f?source=collection_archive---------6-----------------------

了解政策外学习的重要抽样

在本文中,我们将试图理解策略上学习和策略外学习的区别,这对于刚接触强化学习的人来说可能会有点困惑。并将深入研究非政策学习的重要抽样概念。在进一步讨论之前,让我们先来看看两个术语。

  1. 目标策略 pi(a|s):它是代理试图学习的策略,即代理正在学习该策略的值函数。
  2. 行为策略 b(a|s):它是代理用于动作选择的策略,即代理遵循该策略与环境交互。

行为和目标政策示例,通过https://app.diagrams.net/制作的图像

政策学习:

基于策略的学习算法是评估和改进用于选择动作的相同策略的算法。这意味着我们将尝试评估和改进代理已经用于操作选择的相同策略。简而言之,[目标策略==行为策略]。策略上算法的一些例子是策略迭代、值迭代、用于策略上的蒙特卡罗、Sarsa 等。

政策外学习:

偏离策略学习算法评估和改进不同于用于动作选择的策略的策略。总之,【目标政策!=行为政策】。非策略学习算法的一些例子是 Q 学习、预期 sarsa(可以以两种方式起作用)等。

注意:行为策略必须覆盖目标策略,即 pi(a|s) > 0,其中 b(a|s) > 0。

为什么使用非策略?

非策略方法的一些好处如下:

  1. 持续探索:当代理正在学习其他策略时,它可以用于在学习最优策略的同时继续探索。而按策略学习次优策略。
  2. 从演示中学习:代理可以从演示中学习。
  3. 并行学习:这加速了收敛,即学习可以很快。

对不符合策略的情况使用重要抽样

到目前为止,我们知道了保单外和保单内的区别。所以出现的问题是,我们如何在遵循另一个政策的同时,在一个政策下得到国家价值的期望值。这就是重要采样派上用场的地方。让我们用蒙特卡洛更新规则来理解。

图像通过强化学习:介绍
理查德 s 萨顿和安德鲁 g 巴尔托

如您所见,更新规则由来自一个州的所有抽样奖励的平均值组成。这些奖励是按照行为策略 b(a|s)抽样的,但是我们想要估计目标策略 pi(a|s)的值,并且需要从目标策略 pi(a|s)抽样的奖励。我们可以通过简单地将“ρ”乘以从行为政策中抽取的每个奖励来实现。‘ρ’的值等于目标策略 pi(a|s)下的轨迹概率除以行为策略 b(a|s)下的轨迹概率。轨迹的这些概率被定义为代理在状态 St '采取行动' At '并进入状态' St+1 '然后在时间 t 之前采取行动' At+1 '的概率。这个概率可以分成两部分,即在某个状态' St '采取行动' At '的概率和通过在状态' S '采取行动' At '而在某个状态' St+1 '结束的概率。简而言之,随机政策和随机环境。

重要抽样的推导:

假设从概率分布‘b’中抽取一个随机变量‘x ’,我们想估计‘x’相对于目标分布‘pi’的期望值。期望可以写成

现在,我们可以通过‘b’乘以采样 x 的概率。通过将 b(x)移至 pi(x)以下,我们得到了重要的采样比‘ρ’。

现在,如果我们把 xρ(x)看作一个新变量,那么我们可以把它写成 b 下的期望。

现在,我们可以将数据的期望值写成加权样本平均值,其中“ρ”用作权重。

现在我们可以从“b”中抽取“x ”,并使用上面的公式估计它在“pi”下的期望值。

所以,本文到此结束。谢谢你的阅读,希望你喜欢并且能够理解我想要解释的东西。希望你阅读我即将发表的文章。哈里奥姆…🙏

参考资料:

[## 强化学习

由阿尔伯塔大学提供。强化学习专业化包括 4 门课程探索权力…

www.coursera.org](https://www.coursera.org/specializations/reinforcement-learning) [## 强化学习,第二版

显着扩大和更新的广泛使用的文本强化学习的新版本,最…

mitpress.mit.edu](https://mitpress.mit.edu/books/reinforcement-learning-second-edition)

论再现性

原文:https://towardsdatascience.com/on-reproducibility-aa6b22b2623d?source=collection_archive---------39-----------------------

可再生科学

再现性对科学很重要。直到多项研究得出相同的结论,科学结果才被认为是确定的。此外,如果新的工作能够建立在过去工作的基础上,它会更有效率。

我对科学有看法,因为我是物理化学家。现在我进入了数据科学领域,我将把这些观点带在身边。这就是为什么我决心让我的作品具有可复制性。

我在 Metis 数据科学训练营认识到这一点,当时我和我的团队使用四个不同的人开发的代码对相同的数据进行相同的分析,并在四台机器上得到完全相同的结果,一台是 Mac,三台运行某种风格的 Linux。

简而言之,该项目包括向一个假设的客户提出建议,告诉他何时何地在地铁站附近部署街头团队,以便尽可能多的人拿到关于该组织即将举行的晚会的小册子。我与埃里克·巴塞特、伊莱·t·德拉姆和乔安娜·纳赫曼一起工作。该项目的细节,包括自述文件,在这里。

为了组织这个项目,我从 cookie cutter 数据科学模板中获得了灵感,并根据我们的需求做了一些简化。下面是目录结构的简要总结:

.
├── data
│   ├── interim
│   └── raw
├── notebooks
│   └── code
│      
├── references
└── reports
    └── figures

这里有几个关键特征。首先,数据从 jupyter 笔记本和 python 代码中分离出来。这种分离有助于保持事物的条理性。

其次,数据被分为原始数据和临时数据。顾名思义,文件夹data/raw用于存放从纽约市大都会运输管理局(MTA)下载的原始形式的数据。这确保了即使 MTA 网站关闭,分析也可以始终从相同的起点运行。data/interim也是顾名思义,是存放已经部分处理过的数据的文件夹。在分析过程中保存部分数据可以节省开发和重新运行数据操作过程的后续步骤的时间。

一个技术提示:我们需要采取一个额外的步骤来允许在code文件夹中的 python 脚本“看到”在data文件夹中的数据。下面是允许这样做的代码摘录:

from pathlib import Path
PROJECT_DIR = str(Path(__file__).resolve().parents[2])

现在,在加载数据时,只需将/data/raw/filename.csv添加到PROJECT_DIR字符串中。不管项目目录放在哪里,这都可以工作,并且在 Mac 和 Linux 机器上都可以工作。(大概在 Windows 上也是如此,尽管我们还没有测试过)。

我来自物理化学领域,习惯于测量微弱、嘈杂的信号,每次运行的数据都会略有不同,尽管数据背后的模式应该是一致的。相比之下,对于这个项目,我们有一个数据集,每次我们运行分析的“实验”都会产生相同的结果。当然,举例来说,如果我们分别分析不同连续年份的数据,我们会得到不同但可能相似的结果。无论如何,这种精确的再现性对我来说是全新的,让我感到相当惊讶。

与此相关,当我得知计算机的随机数生成器是确定性的和“伪随机的”时,我很惊讶。但那是另一篇博文了。

回到正题,这个组织方案有一个很大的好处。有一次,我和一个小组成员得到了与我们认为的相同过程不同的结果。幸运的是,我们知道在哪里寻找生成这些结果的代码,并很快发现了问题。(我对一个关键步骤的替代计算方法做了错误的假设)。在这之后,计算得出了同样的结果。

我希望有人会拿起这个过程,并尝试运行我们所做的分析,如果只是为了表明他们可以。在同一栋大楼工作的四个人进行相同的分析是一回事。如果一个我从未交谈过的陌生人也能做到这一点,那就更好了。如果你愿意尝试,我鼓励你在这里派生和克隆项目的回购并告诉我进展如何。

感谢您的阅读,如果您对此有任何问题或意见,请告诉我!

原载于 2020 年 1 月 13 日https://ekand . github . io

ROC 曲线与精确回忆曲线

原文:https://towardsdatascience.com/on-roc-and-precision-recall-curves-c23e9b63820c?source=collection_archive---------9-----------------------

卡洛斯·阿泽维多的照片

它们有什么不同,它们携带什么信息,为什么一个不能取代另一个

在机器学习中,当面临二分类问题时,每个数据科学家使用的度量工具主要有两种:接收者操作特征( ROC 曲线)和精度-召回( PR 曲线)。

本文的主要目标是介绍如何解释这些曲线以及它们固有的混淆矩阵和阈值。

我们从覆盖这些曲线的原始数据开始:混淆矩阵。然后我们浏览实际的曲线,最后,我们展示当问题没有正确设置时,这些曲线会是什么样子。

混淆矩阵

混淆矩阵是我们将在这里展示的一切的原始数据:它是一个包含真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)数量的表格。使用 ROC 和 PR 曲线的优点是它们总结了与二元分类问题相关的性能信息。与拥有几个混淆矩阵(每个阈值一个)相比,它更容易阅读和解释,然后计算一些比率来粗略了解这些数字(TP,TN,FP,FN)的含义。,我们刚刚定义了 ROC 和 PR 曲线所代表的东西——我们从几个混淆矩阵中得到的数字的比率。混淆矩阵支持几个类,但是在本文中,我们将集中讨论二进制分类问题。

 | predicted negative  | predicted positive  |
|-----------------|---------------------|---------------------|
| actual negative | True Negative  (TN) | False Positive (FP) |
| actual positive | False Negative (FN) | True Positive  (TP) |**True Positives (TP)**: Positive samples predicted as positive
**True Negatives (TN)**: Negative samples predicted as negative**False Positives (FP):** Negative samples predicted as positive
**False Negatives (FN)**: Positive samples predicted as negative

当处理平衡的数据集时,混乱矩阵是完美的。当我们处理不平衡的数据集时,我们需要一个更复杂的评估指标,让我们能够清楚地进行权衡。

ROC 和 PR 曲线

指标和目标——完美的分类器

维基百科有一个很棒的页面,上面有关于二进制分类的所有指标。我发现同一个度量标准有几个名称令人困惑。在这里,我将主要列出与本文相关的变量,以及最常用的变量:

**Negatives (N):** Total number of negative samples.
N = FP + TN**True Positive Rate (TPR)**: ratio of correct positive predictions to the overral number of positive examples in the dataset.
TPR = Recall = Sensitivity = TP / P**False Positive Rate (FPR)**: ratio of correct negative predictions to the overral number of negative samples in the dataset.
FPR = 1 - Specificity = FP / N**Precision**: From the positive predictions what proportion of it is correct.
Precision = TP / (TP + FP)**Important:** Note that the ***y-axis* of the ROC curve** (Sensitivity) **is the same as the *x-axis* of the PR curve** (Recall).

完美的分类器。:作为分类器输出的分数和水平线给出的 5 个不同的阈值。右上:映射了 5 个阈值的 ROC 曲线。右下:映射了 5 个阈值的 PR 曲线。

  • 左图:沿着 y 轴,我们有分数,而 x 轴只是通过使其更分散来帮助可视化,这样我们可以很容易地看到分数数据点。有 5 条不同的水平线,代表不同的阈值:在这条线以下,所有的数据点被分类为阴性(类 0 ),如果数据点在线以上或得分相同,则被分类为阳性(类 1 )。每条线都有不同的颜色,以便将它们映射到另外两条曲线:ROC 和 PR 曲线。
  • 右上图:这是 ROC 曲线。 x 轴为 FPR, y 轴为灵敏度(或召回或 TPR)。随着左边图上的阈值从底部到顶部,ROC 曲线从右到左发展。该图中的每个数据点代表一个不同的阈值,在每个步骤中,该阈值将正预测变为负预测。
    ROC 空间中的目标是在左上角——这是点(0,1 ),意味着我们没有假阳性( FPR=0 ),并且我们将所有阳性分类为阳性(回忆=1 )。对角线虚线(无技能分类器的“曲线”)是我们在单位区间内随机抽取分数或者我们的预测全为 0 或全为 1 时的平均值。
  • 右下图:这是 PR 曲线。PR 曲线的 x 轴和 ROC 曲线的 y 轴都代表回忆,所以我们看到它们的发展是相似的。这条曲线主要关注积极阶层的表现,这在处理不平衡阶层时至关重要。在公关领域,目标是在右上角——右上角(1,1)意味着我们将所有阳性分类为阳性( Recall=1 ),并且我们分类为阳性的一切都是真阳性(Precision = 1)——后者意味着零假阳性。在这种情况下,无技能分类器的“曲线”是由 P/(N+P)获得的水平线,由虚线表示——在这种情况下,分类器总是预测少数类,,即为正。

ROC 空间或 PR 空间中的每个点代表一个特定的阈值,该阈值改变混淆矩阵(TP,TN,FP,FN ),从而改变召回率、精确度和 FPR。

精确度和召回率之间通常存在一种权衡,这是由区分正面案例和负面案例的阈值决定的,这种权衡通常与业务决策者讨论,以最终决定应该放在哪里。

另一个伪例子如下,其中我们不能通过阈值处理获得完美的分离:

不完美的分类器。:作为分类器输出的分数和水平线给出的不同阈值。右上 : ROC 曲线,其中映射了阈值。右下 : PR 曲线,其中映射了阈值。

走查示例

让我们将刚刚学到的知识付诸实践,看看下面的动画,它将作为接下来的模板:

  • 请注意阈值总是跳到下一个样本:这是因为在样本之间,指标保持不变,因此连接 ROC 和 PR 曲线中各点的线没有意义。
  • ROC 曲线中点之间的距离是恒定的:它仅取决于样本总数——每个样本一个点,只要没有分数完全相同,那么移动阈值会改变两个数据点的决策。
  • PR 曲线中各点之间的距离随着方向而变化:如果步长是水平移动的(回想一下),那么它是恒定的,就像 ROC 曲线一样。对于垂直步长(精度),这取决于有多少个阴性样本——假阳性(FP)的数量越多,步长越小——精度= TP / (TP + FP)。

阈值动画。 Left :作为分类器输出的分数和一个自下而上的移动阈值。右上:根据移动阈值计算的 ROC 曲线。右下:根据移动阈值计算的 PR 曲线。

根据设计,ROC 曲线总是呈 U 形发展,除非有什么问题——所以关于上面的动画,随着阈值的上升,只有两个选择:向左或向下。

  1. 左移:将假阳性(蓝十字)变为真阴性(蓝点)。这种行为代表了正确的决定,因此降低了假阳性率( x 轴)。当阈值在底部从-1.5 向上移动到-0.5 时,很容易观察到,其中每次转换都连续减少假阳性的数量。
  2. 向下步进:将一个真阳性(橙色圆点)变为假阴性(蓝色十字)。这种行为代表了一个错误的决定,因此降低了召回率( y 轴)。很容易观察到,当阈值在 0.5 到 1.5 时,每次转换都错误地将阳性样本分类为阴性。

不平衡数据的影响

到目前为止,我们研究了两个有一个共同点的例子:两个数据集都非常平衡——相同数量的阳性和阴性样本。与 ROC 曲线相比,PR 曲线的亮点在于当我们处理不平衡数据集,并且我们对少数类感兴趣时。让我们看一个例子。

ROC 和 PR 曲线的最佳阈值之间的差异。:作为分类器输出的分数,以及 ROC(紫色)和 PR(绿色)的最优阈值。右上 : ROC 曲线及其最佳阈值(绿色)和 PR 最佳阈值(灰色)。右下 : PR 曲线及其最佳阈值(紫色)和 ROC 最佳阈值(灰色)。

根据 ROC 曲线判断,我们可能对我们的分类器过于乐观——我们可以从几个有性能的阈值中选择。然而,PR 曲线告诉我们一个不同的故事——就像数据点的曲线图一样。由于类别分布中的大偏斜,PR 曲线对算法的性能更有洞察力:当阴性样本的数量大大超过阳性样本的数量时,假阳性数量的大变化会导致 ROC 分析中使用的假阳性率的小变化。另一方面,Precision 通过将假阳性与真阳性而不是真阴性进行比较,来捕捉大量阴性样本对算法性能的影响。

我们决定优化哪条曲线的方式取决于具体情况。如果我们正在处理欺诈检测,那么针对 PR 曲线进行优化可以通过标记欺诈而不使误报检查超载来提供最大的好处,而如果我们正在处理癌症检测,那么误报的成本很高,因此针对 ROC 曲线进行优化是更可取的——然而,这需要业务专业知识来决定算法在权衡中的位置。

杂项——当它做错了

在这里,我们将展示另外两个不经常看到的场景,原因是这意味着问题被错误地表述了——所以当我们做错事情时,我们仍然会看到它,这是一个很好的提醒,它不应该看起来像什么。

  • 类的设置与相反:正的应该是负的,反之亦然。这很容易通过 ROC 曲线识别——只要曲线在对角线的错误一侧,就意味着我们的标签是错误的。

  • 小众阶层被错误设定为负面阶层。根据定义,利益阶层,我们称之为积极阶层,是少数阶层。这很容易通过 PR 曲线识别,我们看到在 Recall=1 时,精度为 0.9,这告诉我们数据类别不平衡倾向于类别 1。

  • 当我们两个都错了的时候,这就是它的样子:标签和少数阶级。这里两条曲线都告诉我们有些奇怪的事情——上面的两种情况都出现了。

我希望这篇文章能让你更熟悉 ROC 曲线和 PR 曲线,从而推断出关于数据和分类器本身的知识。让我知道,如果你觉得有什么东西不见了,这将是有意义的添加到这个职位。我总是乐于探索基础的细节。

这里是用来为这篇文章创建内容的 github repo 。

参考文献

[1]戴维斯,杰西和马克戈德里奇。"精确回忆和 ROC 曲线之间的关系."第 23 届机器学习国际会议论文集。2006.

[2]https://machine learning mastery . com/threshold-moving-for-unbalanced-class ification/

[3]https://www . r-bloggers . com/what-it-the-diversion-of-the-diagonal-for-a-roc-curve/

论人工智能的社会特征

原文:https://towardsdatascience.com/on-social-characteristics-of-artificial-intelligence-5fb85ed2e69d?source=collection_archive---------44-----------------------

理解负责任的人工智能系统的组成部分

人类 vs 人工智能招聘人员

嗯,可能最近,你已经听过很多次类似的短语了,如下:

  • 人工智能是人类的救星!
  • 人工智能是神奇的,它将解决我们所有的问题,它将创造地球上的天堂!
  • AI 是邪恶的!它会夺走我们的工作,让我们失业!
  • AI 要终结人类了!让我们在它阻止我们之前阻止它!

基本上 AI 就是一个工具,就像锤子一样。当然,更加复杂、先进和不断发展,但仍然是一种工具。同样,就像任何其他工具一样,你可以根据你如何使用它来产生好的或坏的结果。你可以用锤子砸碎核桃或者破坏别人的车。所以,它是反映用户意图的媒介。有时候,我们可能在头脑中有一个很好的目标要用我们的工具来实现,但是我们可能会达到一个完全的灾难,因为我们没有完全的能力来使用它。

虽然有许多人工智能应用领域(约束编程,逻辑编程,推理等。),这里我们将主要关注机器学习(ML)。它是人工智能的后起之秀和旗舰,但它是万能的、公平的和完美的吗?当然不是。我们需要处理许多问题和缺陷。

机器学习是科学和艺术的结合,你根据历史/收集的数据建立决策系统。利用这些数据,人们可以设计一个智能系统,为手头的任务提供解决方案。让数据自己说话,它会给你指明方向。ML 帮助您轻松决策、解决问题和自动化日常任务。但是,它真的足够成熟来承担其决策的责任吗?答案是,这取决于应用程序的严肃程度。或许,如果亚马逊推荐给你一些你完全不感兴趣的东西,你不会那么失望。但是,你真的会相信一个建议你做手术的临床应用程序吗,或者你也想和医生确认一下吗?或者一个机器人法官真的会对任何犯罪嫌疑人公正无私吗?你会接受这样一个机器人的评判吗?

即使作为 ML 系统的忠实粉丝、供应商、应用者和支持者,在当前的缺点和不足下,我也不会 100%依赖 ML 系统在所有应用领域的决策。我可以愉快地使用一个应用程序,它可以跟踪我的杂货购物,估计下一个购物清单中的项目,并对它们进行排序。如果它没有为我点牛奶,我也不会如此沮丧。但如果一份申请建议我辞去目前的工作,在一个我认为自己没有相关技能和经验的新行业开始新的职业生涯,我会非常讽刺。

作为一个面向生活的算法应用程序的用户,一个人想要理解其决策的原因(可解释的),并学习它是否是无偏见的(公平的),一致的((不)敏感的)和进步的(进化的)。请注意,这些也反映了我们的本性:人工智能,这是人类的孩子,也有类似的缺点。我们希望看到人工智能在我们失败的地方取得成功。现在,让我们更详细地讨论它们。

可解释性

目标是找到人工智能做出某个决定的原因:决策过程应该是可追踪和透明的。想一个典型的例子:招聘。你不会质疑人工智能招聘人员为什么拒绝你申请的某个职位吗?今天使用的大多数 ML 系统都是作为黑盒部署的。深度网络是当今最流行的最大似然系统,尤其是那些在中间层具有非线性激活函数的系统,由于它们具有大量的参数并且难以解释它们,因此理解起来非常复杂。另一方面,决策树是可追踪的,对于规则提取来说非常方便,但是它可能不够精确,不能作为商业产品部署。即使它们是学术界(主要在卷积神经网络-CNN 中)提取和量化人工智能系统决策原因的一些尝试,如逐层相关传播 LRP 或集成梯度,但当前的度量标准对于构建可理解的系统来说不合适或不够好。我们需要新的损失函数和度量来创建可解释的人工智能系统。

公平

让我们继续以招聘为例:在两个几乎具有相同属性(如教育、技能、经验等)的候选人中,一个比另一个更受青睐。但这是公平的选择吗?这是政治学或司法制度等许多社会科学的基本问题之一。我们如何确保我们给出一个公正、公平的决定?对此没有简单的普遍答案。因为对于公平的定义,还没有一个共同的结论。公平的含义是什么?公平还是平等?根据我们拥有的个人特征或根据我们所属的群体(如性别)特征,被选中的机会(概率)相等吗?其实 ML 不公平的主要原因是生活本身的不公平。我们收集的数据应该代表我们可能遇到的所有情况;因此,这是一个很好的样本。但是在选择样本(例如,可能排除人口中的某个亚群体)或创建数据(例如,由于所用设备的缺陷,可能在某些情况下引入测量偏差)的过程中,可能会引入偏差。即使数据集是无偏的,在应用程序的设计、实现和部署期间,系统中也会引入偏差。最后,作为一个极端情况,系统的输出也可能被错误地解释,无论是否有任何恶意意图。请注意,这里讨论的偏差并不是 ML 算法(误差的偏差-方差分解)中固有的偏差,这是由于设计期间引入的假设或放宽。招聘人员系统拒绝你是因为你是前一个人类招聘人员有偏见的种族群体的成员吗,这种偏见也嵌入在历史数据中?或者你被拒绝不是因为缺乏一些技能,而是因为一些有利于其他候选人的积极的区别对待?在文献中,定义了 150 多种不同的偏见(性别、种族、教育、社会地位等。)在日常生活中,其中一些可能不可避免地嵌入到数据中。

(不)敏感

如果你的简历中有不同的爱好(被认为与职位要求无关),或者如果你的简历中有一个打字错误,导致在解析过程中丢失了一个特征,人工智能招聘人员还会在候选人列表中按相同的顺序排列你吗?不敏感性关注的是人工智能系统对其输出的一致性。该决定应该依赖于直接影响输出的区别特征。它还应该对输入中的微小变化或小误差鲁棒或不敏感,以便输出不会剧烈变化。例如,你期望年薪的 1 美元的变化不应该导致你被淘汰。只要变化不在区别特征的主要集合中,或者它们在可容忍/可忽略的范围内,输出就不能颠倒变化。如何定义或衡量这种(不)敏感性是另一回事。在文献中,特别是在信号处理领域,有量化灵敏度的方法。

演变

随着时间的推移,社会在变化,工作条件和环境也在变化。随着技术的进步,我们获得了新的工具,我们需要新的技能来掌握这些工具。新概念导致了职业的出现,或者破坏了某个职位的现有技能要求。你还想让一个人工智能招聘人员评估一个数据科学家的职位吗?这个人工智能招聘人员一直在用 2005 年以前的就业历史数据进行培训(深度神经网络时代之前,没有 TensorFlow 或 PyTorch!)?同样,作为一名雇主,你会热衷于使用这样的系统来寻找你的完美匹配的理想员工吗?ML 系统的进化是其作为生命体的本性要求。它应该能够消化可能由新出现的、以前不存在的条件引起的新情况,并适应它们。但它仍然必须是一致的。说起来容易,做起来难。例如,当我们开始殖民火星时,在地球(某个国家)训练的机器人法官也应该用在火星上吗?很可能,对于一个机器人法官来说,在火星上从零开始建立所有的司法系统将是一个几乎不可能完成的任务。注意,这里所说的进化,我指的不是更快的计算或更高的准确率,而是处理看不见的情况或异常的能力。《星际迷航》系列中的通用翻译器将是这种进化人工智能的一个绝佳例子。一个可以在“初次接触”中学习新文明的语言和文化的翻译家!!!难以想象,不是吗?

下一步是什么?

在这里,我们讨论人工智能的哲学方面,而不是技术方面:当我们为对人们生活有深刻影响的领域/领域构建人工智能系统时,我们应该记住什么。我给出的列表可以扩展,或者它可能已经遗漏了一些要点(例如,用户的隐私问题和决策步骤的跟踪支持/可审计性)。请注意,也有关于人工智能系统所采取行动的后果的法律责任的持续讨论:该怪谁?我在参考资料中给出的材料的帮助下,结合自己的想法和理解,写了这篇文章。想了解更多更详细的信息,你可以向他们申请。

看好你的 AI 孩子,让它成长为一个有担当的少年!:)不要糟蹋它!

PS:我感谢我的妻子 Elif Semerci 创作了这些可爱的漫画!

参考文献:

关于 2020 年选举,德州扑克和蒙特卡洛

原文:https://towardsdatascience.com/on-the-2020-elections-texas-holdem-poker-and-monte-carlo-43807a4c068e?source=collection_archive---------45-----------------------

当数据成为个人信息时

图片由阿曼达·琼斯Unsplash 上提供。

有一段时间,我经常玩扑克,尤其是德州扑克。我喜欢它的一切——试图预测对手的下一步行动,根据我仅有的一点信息计算概率,下注大小,管理心态,包括驾驭游戏的高潮和低谷。

在扑克中,有一句流行的谚语,“玩(wo)人,而不是牌。”换句话说,你不会得到游戏中其他牌的所有信息,所以你必须尽你所知了解对手的玩法。

最近,我读了一本由获奖心理学家 Maria Konnikova 所著的书The big Bluff,这本书讲述了她成为扑克冠军的经历以及她从游戏中学到的关于生活的东西,这让我想起了这一点。在她的书中,Maria 讨论了玩扑克的批判性思维,游戏如何教会你在有限的信息下做出更好的选择,以及处理这些决定结果的策略。

正如 Konnikova 指出的,在现实生活中,我们也经常被迫在有限的信息下操作。你只能如此肯定地预测筹码将如何下跌——归根结底,这只是一个非常有根据的猜测。我们进行这些有根据的猜测的主要方法之一是通过统计,最受欢迎的统计方法之一是蒙特卡洛模拟,它恰如其分地以世界扑克之都摩纳哥的蒙特卡洛命名。

蒙特卡罗模拟和不可靠的数据

任何统计学家都会告诉你,蒙特卡洛模拟有许多引人注目的应用,从公司财务和风险分析到——你猜对了——扑克

简而言之,蒙特卡洛模拟基于在复杂情况下使用大量随机模拟来预测结果的想法,通常是在你没有封闭形式的分析模型时。

然而,即使使用像蒙特卡罗这样的技术,数据也很少是完整或准确的,即使是最完整的数据集和实验条件也应该经过仔细检查。

我们将这种非常普遍的不可靠数据称为数据宕机。严格来说,数据宕机指的是数据丢失、不准确或出现其他错误的时间段,从扑克玩家到数据团队的每个人都是接收方。

这对美国选举意味着什么

图片来自蒂芙尼在 Unsplash 上的第三次亮相。

即将到来的 2020 年美国大选本身就是一个有趣的事件,但也因为这类事件的结果难以预测(比如我们的 2016 年总统大选)。

每个选举周期, FiveThirtyEight 都使用蒙特卡洛来估计选举结果。他们在各州进行了 40,000 次蒙特卡洛模拟,以产生一系列可能的结果,并根据发生的可能性进行排名。FiveThirtyEight 的数据科学家和记者团队从各州的民意调查中获得数据,并结合人口统计、经济和其他数据来预测谁将获胜。随着选举的临近,越来越多的投票信息变得可用,他们的预测变得不那么不确定。

我还没有遇到一个数据科学家愿意承认他们的数据是“完美的”或者他们的预测是 100%可靠的。选举也不能幸免于数据问题。

这对你意味着什么

选举预测并不是数据宕机影响我们个人的唯一地方。一个更明显的例子是 2020 年美国人口普查,这是一项对美国人口的年度统计,确定每个州在美国众议院的席位数量,并向地方社区分配数十亿美元的联邦资金。像 FiveThirtyEight 一样,美国人口普查局也使用蒙特卡洛模拟,在他们的案例中评估新统计方法的质量,并分析人口样本调查中的测量误差。

2020 年,美国人口普查数据收集过程受到数据停机问题的困扰,例如过时的技术、重复的地址,以及由于新冠肺炎而缩短的最后期限。总而言之,这些因素影响了人口普查的完整性和准确性,阻碍了民主,并证明了数据宕机不仅仅是一个业务问题。

底线是:数据可能是个人的,像这样的事件更加明显地表明,我们需要以应有的勤奋对待数据。正如最好的统计学家会告诉你的,即使是一个伟大的蒙特卡洛模型也无法保存你的数据。

热爱扑克和蒙特卡洛模拟?伸出手去 巴尔摩西。

论数学之美

原文:https://towardsdatascience.com/on-the-beauty-of-math-f2453be9db84?source=collection_archive---------10-----------------------

伟大的数学家欧拉和他对著名的巴塞尔问题的精妙解答

图 bysash kin/shutterstock . com

德国数学家、天文学家和物理学家卡尔·弗里德里希·高斯被许多人认为是“自古以来最伟大的数学家”曾经宣称:

“对欧拉著作的研究仍将是不同数学领域的最佳学校,其他任何东西都无法取代它。”

—卡尔·弗里德里希·高斯

图 1:卡尔·弗里德里希·高斯的肖像,被称为“自古以来最伟大的数学家”(来源)。

本文将描述瑞士数学家莱昂哈德·欧拉是如何解决著名的巴塞尔问题的。欧拉是历史上最伟大的数学家之一。他的多产是传奇的素材,他的作品集填满了 92 大卷皮埃尔·西蒙·拉普拉斯断言了欧拉对数学的影响,他有一句名言:

“读欧拉,读欧拉,他是我们所有人的主宰。”

—皮埃尔·西蒙·拉普拉斯

图 J. E. Handmann 拍摄的莱昂哈德·欧拉肖像(来源)。

巴塞尔问题

意大利数学家皮埃特罗·门戈利于 1650 年首次提出了巴塞尔问题,欧拉于 1734 年解决了这个问题,使他立即得到了认可。该问题要求自然数平方的倒数之和:

等式 1:巴塞尔问题。

许多有影响的数学家试图找到平方倒数之和的公式。微积分的两位共同发明者,约翰·沃利斯和伟大的 T2,戈特弗里德·莱布尼茨,都曾尝试过并遭遇过失败。欧拉在年轻时(他 28 岁)就解决了这个问题,他的答案的数学本质让数学界感到惊讶。他的第一个证明(他后来提供了其他几个)并不严谨,但它的美丽、简单和独创性令人惊讶。

图 3:欧拉的故乡巴塞尔(来源)。

欧拉杰出的洞察力是写下 sinc(πx)函数

等式 2:sinc(πx)函数的定义。

作为零数的乘积。

图 4:归一化和非归一化 sinc(x)函数(分别用蓝色和红色表示)(来源)。

为了理解这一点,例如,考虑下面的四次多项式写为其零点上的乘积:

等式 3:一个四次多项式 f(x)被写成其零点上的乘积。

将表达式相乘,我们得到:

等式 4:乘以因子后的等式 3。

欧拉的策略是将同样的扩展应用于超越函数。

超越函数

这种函数不满足多项式方程,例如方程。4.指数函数三角函数对数函数是三个众所周知的例子。

图 5:指数函数()、对数函数()和三角函数()的曲线图。

sinc( πx )函数有以下根源:

等式 5:sinc(πx)函数的根。

欧拉继续用与等式 f ( x )相同的方式写出 sinc(x)。3.使用基本的数学恒等式

因为对于等式中的每个根。5 有一个相应的消极的他能够写:

等式 6:sinc(πx)函数表示为其零点的乘积。

下一步是将等式中的各项相乘。6 但是只关注二次方程:

等式 7:等式 6 乘以各项后,只关注二次项。

泰勒级数

泰勒级数将函数表示为无穷多个项的和。每一项都是从函数在一个单点的导数的值计算出来的(更多细节见链接)。

图 6:增加泰勒级数的次数,它收敛到正确的函数。黑色曲线代表 sin(x)。其他曲线是泰勒近似,是 1、3、5、7、9、11 和 13 次多项式(来源)。

图 6 所示的七个泰勒级数具有以下代数形式:

等式 8:对应于函数 sin(x)的若干次泰勒多项式。这些函数的曲线如图 6 所示。

sinc(x)函数的泰勒展开式为:

等式 9:sinc(πx)的泰勒级数。

可以想到情商。8 作为一个具有无限次数的“伪多项式”。这样的伪多项式有无穷多个根。等式中给出了根。5.

比较两种结果

比较情商。7 和情商。我们得到了我们想要的结果:

方程式 10:巴塞尔问题的欧拉解。

作为奖励,欧拉的推导给了我们众所周知的沃利斯积。只需在等式中代入 x = 1/2 即可。6 并将其倒置。我们获得:

等式 10:作为证明巴塞尔问题的奖励而获得的 Wallis 乘积。

图 7:戈弗雷·内勒的约翰·沃利斯肖像(来源)。

严格的证明

在这最后一节,我们将看到如何获得欧拉结果的严格证明(这个证明的作者是丹尼尔·p·吉西)。考虑功能:

等式 11:d . p . Giesy 在证明巴塞尔问题时引入的辅助函数。

(通常以不同的形式书写)。然后定义数字 E ( n )并计算它,在等式 2 的第二个等式之后积分表达式。11:

等式 12:数 E(n)的定义。

很明显,对于偶数 k 来说,右边的和是零。因此,可以用(2 k -1)代替 k ,并且只考虑 E 的子索引为奇数的项:

等式 13:等式。12 仅用于 E. 的子索引的奇数值

现在,为了完成证明,我们需要证明这个表达式消失了。由于这个演示相当费力,也不是很有启发性,所以就省略了。结果是:

等式 14:证明有效的必要条件。

经过一些简单的代数运算后,我们再次得到方程。10:

等式 15:使用简单的代数运算,就可以得到最终结果。

我的 Github 和个人网站 www.marcotavora.me 有一些关于数学和其他主题的有趣材料,如物理、数据科学和金融。看看他们!

雨天的可能性

原文:https://towardsdatascience.com/on-the-chances-of-rainy-days-5699e73919d2?source=collection_archive---------31-----------------------

如何使用组合学的力量进行简单的概率计算?

普吉岛邦陶海滩,作者拍摄

在我们的泰国假期开始前不久,我查看了普吉岛的天气预报,发现在我们为期 10 天的旅行中,预计会有四个雨天。可能仍然会很有趣,但是我想知道,如果根据维基百科的记录,二月份平均只有四天下雨,那么在我们 10 天的假期中,这四天都下雨的概率是多少?

作者截图

假设

为了找到答案,我做了一些假设。首先,让我们假设这 4 个雨天随机出现在二月,并且彼此独立,也就是说,某一天下雨对另一天下雨的可能性没有影响。第二,让我们假设下雨天的概率在整个二月是均匀分布的,所以下雨天在二月初和二月末的概率是一样的。当然,这是一种过于简化的说法,真实的天气比这个(见脚注 5) 要复杂得多,但是对于我的偶然计算,它仍然有效。最后,为了简单起见,我们假设二月有 28 天。

用组合数学回答概率问题

这个问题有一个可能的解决方案。借助组合学,我们可以在结构上接近它。这里的直觉是得到在 10 天内所有 4 个雨天都被选中的方法的数量,然后用它除以所有可能的方法从 28 天中选出 10 天。首先,让我们找出我们整个空间的所有可能组合是什么?

二月份我们有 24 个晴天和 4 个雨天。

我们从中抽取 10 个。

从 28 个项目中抽取 10 个项目总共有多少种方法?对于第一天,我们有 28 种可能性,然后,一旦我们选择了第一种,就有 27 种剩余的可能性,第二种之后是 26 种,以此类推,直到 19 种。

这给了我们【28 * 27 * 26 * 25 * 24 * 23 * 22 * 21 * 20 * 19】或者

从 28 天中选择 10 天的总可能性。(分母(28–10)!干脆把 28 中 18 及以下的因素全部抵消!).

但是,这样我们计算了 10 天假期中所有可能的排列,这意味着第一个时段的晴天和第二个时段的雨天将与第一个时段的雨天和第二个时段的晴天分开计算,即使它们是相同的天数组合-一个晴天和一个雨天。

为了得到独特的组合,我们需要将所有可能排列的空间除以我们可以重新排列 10 天的方式的数量。想象一下,对于 10 天的单一唯一组合,我们可以将第一天放在 10 个开放时段,第二天放在 9 个,依此类推。所有可能排列的数目将是【10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1】10!。

通过从 28 个项目中选择 10 个项目来计算唯一组合数量的最终表达式是:

当然,你可能已经认识到二项式系数的公式,也被称为 n-choose-k 。这正是我们在这里所做的——从 total n 对象池中选择 k 对象,在我们的例子中 n =28, k =10。https://en.wikipedia.org/wiki/Binomial_coefficient

现在我们知道了从 28 种组合中选择 10 种独特组合的所有可能方法。为了找出这 10 天中所有 4 个雨天出现的概率,我们需要找出所有 4 天都出现的组合的数量。

我们如何做到这一点?让我们想象一下这个场景。我们对宇宙的版本感兴趣,当所有四个雨天都发生在我们的 10 天时段。

在我们的总空间 28 中选择 10 种可能的组合,这种情况会出现在多少种组合中?我们有 6 个开放的假期,还有 24 天可以选择。在这里,我们有 24 种方法来选择第一个桶,23 秒..正如我们在上面看到的,这给了我们 24 个选择 6 个可能的组合,当所有 4 个雨天都发生在我们的 10 个假期时。

现在我们只需要在所有可能的组合空间中找到这 4 天组合的分数。

令人惊讶的是,根据假设,在我们的假期中,所有 4 个雨天发生的几率只有 1%多一点!毕竟,在我们的旅行中不可能观察到所有的四个雨天:)

当解决类似的问题时,验证解决方案并确保直觉是正确的总是有帮助的。值得庆幸的是,对于少量的组合,很容易就可以“暴力”解决方案,并简单地列举所有可能的组合。只是用 Python 写了几行代码;)

三个雨天的可能性有多大?

恰好 3 个雨天的概率是多少?这里变得更加微妙了。在所有四个雨天的情况下,只有一种方法从总共四天的降雨中选择四天的降雨。但是现在我们只选择 3 天。从 4 天中选择 3 天的方法有多少种?有 4 选 3 或 4 种方式。因此,当 10 天中有 3 天下雨时,我们总共有 4 个组合。

这些三胞胎各包含多少种组合?通过应用相同的逻辑,从 25 或 25-choose-7 总可用天数中选择剩余的 7 天。

但是在这里,由于其中一个雨天仍然留在池中,所以我们会在 25-choose-7 三胞胎的分支中过度计数四个雨天的情况。

为了避免过多计算 4 个雨天的案例,我们需要从 24 个晴天的集合中选择,而不是从 25 天的总集合中选择:

导致:

现在,3 天或更长时间的雨会怎么样?在这种情况下,我们只需要将上面计算的 4 天组合的总数相加。

至少有一个雨天的概率。

最后,至少有一个雨天的概率呢?如果我们应用上面的逻辑,这里会变得有点令人毛骨悚然,特别是如果雨天的数量变得更多。我们需要计算 3,4,2,1 个雨天的组合数,然后把它们加起来。

但是对于至少有一个雨天的情况,如果我们考虑反问题,我们真的可以简化这个过程——没有雨天发生的概率是多少?那么至少有一个雨天的概率是:

不下雨的概率很容易计算:

这给出了至少一个雨天的概率:

我希望你喜欢这个小概率练习,如果你能想到一个替代的解决方案,请在评论中分享! Jun Mei 建议使用泊松分布对预期计数进行建模,敬请关注后续情况。;)

PS。我们在普吉岛的 10 天里只下过一次雨:)

脚注:

  1. 这里有一个关于 Khan Academy 的优秀视频,讲述了一个非常相似的问题,以及关于组合和概率主题的其他宝石。https://www . khanacademy . org/math/statistics-probability/counting-permutations-and-combinatorics-probability/v/probability-of-dependent-events-2
  2. 类似结构题:https://en.wikipedia.org/wiki/Poker_probability
  3. 如上所述,4 个雨天是一个平均值,可能在某些月份会有更多或更少的雨天。如果我们有额外的分散测量,如标准偏差或随机变量的整个分布,其他统计方法会给出更准确的结果。
  4. 在我的例子中,我使用了苹果的天气预报应用。与维基百科使用的泰国气象部门相比,天气频道可能使用了不同的雨天概念。https://www.bbc.com/news/uk-44238426T2
  5. 见《现代天气预报概述》作者 内特·西尔弗 ,改编自他的著作 【信号与噪音】 https://www . nytimes . com/2012/09/09/magazine/the-weatherman-is-not-a-moron . html

论硬物的复杂性

原文:https://towardsdatascience.com/on-the-complexity-of-hard-things-dd8d1f207644?source=collection_archive---------50-----------------------

乌列尔 SCUnsplash 上拍摄的照片

“请尽可能对一个小孩或一只金毛猎犬说话。”

《阿甘的呼唤》是我最喜欢的电影之一,电影中的这句台词也是我一直以来最喜欢的俏皮话之一。当我第一次看这部电影时,在学术界的阵痛中,它带来了干巴巴的喜剧救济,反映了我走进论文答辩研讨会的经历,研讨会上经常挤满了时间紧迫、高度尖刻的高级学者。

在我担任数据和数字转型顾问期间,我目睹了人们对“易于理解”的标题的贪得无厌,比如“数据驱动的文化”或“利用我们的数据”。十年过去了,这个话题仍然让我既着迷又惊愕。如今,似乎每个人都想四处散布数据,但在充满易于理解的标题和一些深思熟虑的点头的令人振奋的 Powerpoint 演示后,兴趣很快就消失了。就在几周前,有人告诉我,他们不想知道为什么一个模型看起来不稳定(数据反映了时变的市场条件)——他们只是需要它给我一个数字。

简单的感觉很好

关于良好的技术交流的重要性,不乏可读的材料;事实上,许多关于弥合商业和技术领域之间差距的讨论都指向简化作为答案。这个前提似乎很有说服力,几乎到了陈述显而易见的地步——领导者希望信息成为易于消化、快速消耗的决策“零食”;因此,简化一切是最终的解决方案,是行还是不行的关键区别。

降低报价的复杂性在许多层面上都是诱人的。明显的清晰度提供了一种速度感。一张格式良好的图表配上一两个清晰的标题,会让人立刻产生理解和幸福感。让一些这样的图表在数据探索的交互式仪表板中可访问,这混合了控制和理解的感觉。感觉在控制和理解中通常会导致相信问题已经解决了。

精明的顾问对此深有体会;他知道要把注意力吸引到泡泡上,而不是浴缸上。当然,都是用简单的语言。因为如果说“规模”和“价值”足够多次就能让观众感到愉悦,那么为什么要进入构建数据基础设施或大规模机器学习的黑暗现实呢?此外,如何实际大规模部署模型是𝚗̶𝚎̶𝚛̶𝚍̶𝚜̶交付团队要担心的。

把复杂性放在橱柜里不会让它消失

我对不善于辨别的技术决策者的担心是,他们很容易将模糊的复杂性误认为优雅的解决方案。简单的陈述吸引了系统 1,我们固有的倾向不是根据证据的可靠性,而是根据连贯性来衡量一个故事的价值。

问题是随之而来的低估——尤其是任务的规模。这通常是在一篇文章的后期实现的,因为容易理解的高管简报的温暖被交付的严酷、冰冷的现实所取代。

以数据湖的构建为例。通常,开发关键数据基础设施的大部分精力都花费在供应商选择上,这是一种过于简化的观点,即“一旦我们锁定了一家供应商,我们就会购买一个数据平台,我们的数据驱动文化就会到位”。构建数据平台的现实是,整个组织需要改变访问、生成、移动、整合、存储和检索数据的方式。随着项目的展开,在现场工作的转型团队意识到,高管演示中关于“改变我们的工作方式”的一句话包括试图说服某人在使用了 20 年的 Windows 资源管理器和本地存储之后采用 Git。

困难的事情其实很复杂

说实话,决策是复杂的——尤其是涉及技术和量化资产的时候。

为了在商业和技术领域之间的有限空间中有效地执行,人们必须掌握 10,000 英尺的战略任务,准确地将其映射到人员、流程、基础设施和软件的几乎不可协商的需求。虚拟专用网络要么配置了适当的访问控制,要么没有,无论人们在 Powerpoint 幻灯片“自动化安全网络”上写了多少次。

数据增加了工程的复杂性,因为它随时间和空间改变状态的倾向可能会带来一些令人费解的问题。例如,考虑电子商务 CX 最终一致性的影响——客户可能会看到陈旧的信息,因为数据库更新需要时间在您的“云原生架构”中同步。当然,在 CX 团队的设计任务中,理解这种可变性的界限是很重要的。

并且然后机器学习的加入进一步指数化了数据管理压力。我们现在不仅需要保持关键基础设施、软件和数据资产同步运行,我们还必须确保能够使用(和滥用)ML 的组合方式得到谨慎管理。"你说我应该担心使用准确率 100%的模型是什么意思?"

数据和机器学习是热门的例子,但研究培训教会我的是,所有的学科都有难以置信的复杂性,在追求一个好故事的过程中常常被掩盖。

金毛猎犬不应该做艰难的决定

鉴于现代企业的复杂性,首席商业领袖或许不应该试图效仿金毛猎犬。考虑到手头决策的重要性,作为数据从业者,我们最终需要考虑如何传达实质内容,而不是虚假的清晰。

这需要一个看似很小但很贴切的转变:远离简单,走向准确(和精确)。也就是说,以如此迫切寻求的清晰度为目标,只需要尽可能多的复杂性来支持——但不要搞错:复杂性是传达的必要条件。作为从业者,我们对如何负责任地消费数据负责;如果一个商业用户因为训练数据中的偏见而准备按下一个按钮,部署一个歧视少数族裔的神经网络,他们需要听到的是关于阶级不平衡的伦理、权衡和风险,而不是你如何使用谷歌或 OpenAI 的最新艺术架构。

对于决策者来说,深入细节的想法起初可能听起来令人倒胃口;我的建议是至少搅拌一下洗澡水,分离泡沫。几个精辟的问题会很有帮助——“告诉我如何执行”,或者“告诉我什么会出错”,很快就会揭示隐藏在(泡沫)表面下的东西。

虽然交流和消费复杂性都不会令人愉快,但良好的技术交流的影响是无可争议的。我的希望是,作为一个行业,我们应该学会重视物质而不是糖,并在简单讲述故事之前奖励执行良好的策略。

机器学习的黄金入场券

原文:https://towardsdatascience.com/on-the-golden-ticket-into-machine-learning-87b3f8b0aa6c?source=collection_archive---------29-----------------------

有比问你是否需要数学来做机器学习更好的方法

介绍

在过去的几年里,我从人们那里看到和得到的一个更流行的问题是“进入机器学习需要多少数学和统计学知识?”我理解这个问题的潜在动机,但它没有抓住要点。这些好奇的朋友和同事认为他们在问一个相对直截了当的问题,但现实却大不相同。问这样的问题类似于问“在医院工作你需要了解多少生物学知识?”或者“打击犯罪需要了解多少法律?”

具体一点

我相信你看到了这个答案:看情况。当然,要看情况。更重要的是为什么和如何依赖,以及你需要知道什么来有效地回答你自己的问题。这个问题没有唯一的答案;在明确了想要什么样的工作之后,每个人的答案都是不同的。

所以,你想在医院工作?太棒了。你在那里做什么——进行手术、安排预约或打扫厕所?这些角色需要不同的经验和个性背景,在收集到更多的信息之前,人们无法对最初的问题给出充分的答案。

随着时间的推移,人工智能行业已经融合到一些不同的角色分工中,包括使用数据和算法向我们的世界提供优秀的新产品和服务的所有领域。下面,我会给你一个感觉,这样你就能更好地回答你的燃眉之急,并继续前进。

支持 ML 的软件工程师

你是一名软件工程师,积极寻求在不断增长的软件开发就业市场中保持优势吗?你会听到越来越多的关于人工智能是新的电力数据是新的石油的说法。毫无疑问,这是一列您不想错过的火车,因此您希望确保了解这些解决方案如何集成到现有生产系统中,以便为用户提供更多价值。您可能对与流行病毒模型的库轻松交互感兴趣,比如那些可以看到这张图片并确定“那是一只猫!”仅来自像素值。你寻找的角色通常有宽泛的头衔,比如“软件工程师——机器学习”。

照片由Ramiz deda kovi在 Unsplash 上拍摄

对于这类人来说,这是个好消息!进入这些角色相对容易。从 Fast.aiUdacity 再到 Coursera ,网络上存在大量速成教育内容。这些网站中有许多对开发人员非常友好,提供实践学习方法,帮助您开始使用自己的实现。对于许多人来说,这将“挠痒痒”,这是他们对机器学习和人工智能的感觉。

数据分析师

数据分析师喜欢机器学习解决方案,但不喜欢设计或开发它们的细节。更确切地说,重点是放在有根据的、经过时间验证的描述和数据的统计汇总上,以便为一个不一定以数据为导向的产品带来更多的商业价值。此外,通常在这些角色中使用的数据是非常结构化的(时间戳、真/假、这个或那个字段),而不是非结构化的(像素、音频样本、传感器测量),这使得分析更加直接。

例如,一项常见的数据分析工作是从几个现有的数据库中获取数据,汇总数据字段及其交互,并解释更改一个字段的值如何影响其他字段。更改后的字段可能是一个城市中优步司机的平均日人数,以及增加更多司机将如何增加收入和减少取件时间,同时增加要支付的员工工资总额。

来源: Tableau 服务器

没什么可怕的,对吧?从事这一行的人通常会将他们的代数和基本统计知识与一些业务和数字演示能力结合起来,以便从人群中脱颖而出。

数据工程师

随着大数据将数量呈指数级增长的数据带入传统数据库,导致延迟大幅增加,并推动分布式计算和水平扩展等领域的创新,数据工程师的角色应运而生。虽然数据分析师通常会假设一个准备就绪的数据库正在等待分析,但数据工程师的工作却在幕后。

数据工程师的工作包括处理各种动态数据结构,以可复制的方式将它们吸收到数据分析师和其他商业智能(BI)代表工作的一个或多个数据库中。然而,这项工作并不像为不同的数据库编写一堆 SQL 命令那么简单。

来源:亚马逊 AWS 博客

在当今数据杂乱的世界中,数据工程师必须了解如何利用分布式数据库和计算架构来提供可水平扩展的数据管道,这些管道可以每天运行几次,以创建相对简化的数据存储,供其他人使用。如果没有这些英雄,分析师和 BI 代表所花费的时间和精力将远远超过为客户生成的常规报告。

机器学习工程师

到目前为止,我们的数据工程师正在与大量不同的数据进行有效的斗争,使数据分析师能够定期提供公司内外的见解。除了这种洞察力,企业现在还使用数据和 ML 算法来取代我们以前必须手动执行的越来越多的艰巨而复杂的任务。

例如,银行应该如何确定向申请贷款的潜在客户提供的利率?很自然,你会期望它随着客户无法偿还贷款的可能性而变化。他们应该如何确定该估计值?进入机器学习。

更值得注意的是,越来越多的公司正在构建数据优先的产品,利用算法和数据的强大组合来构建解决方案,这些解决方案打破了以前的产品。例如,我们在 Pindrop 开发的产品之一是一个文本独立的语音生物识别系统,它利用了最近深度学习的复兴,使你与行业领导者的所有语音交互安全而无摩擦。

机器学习工程师站在他们的数据工程师和支持 ML 的软件工程师的肩膀上,在内部和云中培训和部署已建立的机器学习模型,以使“物联网”成为“智能物联网”。这些人了解所有最新的云软件生态系统,但也不害怕一些微积分、统计和线性代数。他们是您连接工程和研究部门的王牌,弥合了从前沿到交付价值的差距。

来源: mc.ai

话虽如此,他们并不期望不断推动国家的艺术。这更是下一个角色的领土。

研究员/数据科学家

啊,是的。我们到了。这是许多人在说“不,真的”时想到的角色。我想深入这个领域,理解算法的核心,并推动艺术向前发展。现在,你需要多少数学和统计数据来计算?”

你需要很多

图片由横山由纪美Pixabay 拍摄

该领域发展迅速,仍处于相对初级阶段。每月都有来自不同学术背景的最新进展。计算机科学家使用算法优化和计算基础设施扩展来解决以前“棘手”的问题。数学家证明了允许新算法创建和/或简化的定理。信号处理专家以有效和有启发性的转换形式提供了有益的偏差,使模型能够快速开始学习过程。物理学家利用对场、波和粒子理论的深入了解,从完全不同的角度来处理最优化问题。如果你现在还没有注意到,这甚至不是一个“好吧,我就去拿个博士学位”的前提——学术界的许多领域都在为创新机器学习算法做出贡献。即使你的决定是去读博士,你仍然需要决定你喜欢的学习方向。

瞄准你的智力十字准线的有用方法不是“知道你需要多少数学”更确切地说,这是一个循序渐进的过程(我想大多数人会在第一步停止):

  1. 根据上面的描述,在你的生活中,哪一个方面是你真正热衷于日复一日挖掘的?
  2. 如果你仍然选择“机器学习算法开发”,你最终仍然需要比其他人更熟悉一些科目。你的时间和精力是一场零和游戏——你不可能用有限的资源同等地掌握所有的科目。

值得注意的是,从以上题目中选择,当然不是非黑即白。但是,与引导你的注意力和努力类似,精通这些领域必然会错失专攻其他领域的机会。我坚信在“多面手”和“一招小马”之间的灰色地带运作,重要的是你要明白你在这个光谱中的位置,并与它一起工作。

你喜欢什么软件?

来源:微软 Azure 博客

在所有试图区分这些角色的行话中,这里有一个单独的、粗略的方法来估计你的激情方向:你最喜欢使用和学习什么软件库和语言?虽然这些答案不会完全准确,但它们应该给你一个公平的想法,让你做更多的挖掘。

您喜欢在 Kubernetes 中使用容器编排吗?或者,对于现代 ML 爱好者来说,您喜欢 Go 结合了 Java 和 C++世界的精华吗?你可能会走上支持 ML 的软件工程师之路。

你喜欢处理数据和视觉效果,但不喜欢编码吗?如果你喜欢 Excel 中的数据透视表或 Tableau 中漂亮的仪表板,那么听起来我在和一位数据分析师交谈。

“别管模特了,伙计。如果他们得不到正确的数据,他们就做不了什么。模型需要可扩展的数据交付解决方案。”如果这些话从你嘴里说出来,并且你对你的 AWS EMR 集群中具有 Spark transforms 的可再生气流管道垂涎三尺,你应该申请数据工程师的职位。

对于那些无法从将一份新的白皮书转化为训练有素的模型和在云提供商上部署它以可靠地为各地的客户提供价值这两个世界中获得足够多的人来说,情况又如何呢?你永远不会完全适应“我喜欢数学,但不喜欢代码”和“我会整天集成 API,只是不要让我做集成”的人群,因为你喜欢两样都做。如果你在 Jupyter 笔记本上与熊猫进行数据交流,任何一天都是好日子。我的朋友,你是一个真正的机器学习工程师

或者是你,谁嘲笑所有这些软件库和语言废话?你希望只有一种大家都使用的语言和库,这样我们就可以专注于用统计方法、巧妙的推导假设和新的数学突破的应用来推动艺术的发展。你将学习如何让计算机做你想做的事情,但在此之前,你要在白板前开发你的下一个算法。为你,潜入数据科学机器学习研究的世界。

图片来自 PixabayKirk Fisher

从这里去哪里

如果您没有从本文中获得任何其他信息,那么就让它成为以下内容:

你通往无处不在的机器学习和人工智能的未来之路不需要数学上的严格性,如果你不想这样做的话。

我相信绝大多数人问这个问题是因为潜意识里他们希望答案是“不多”不完全是,答案是“不一定很多”这个领域正在向各个方向扩展,如果你现在还看不出来,那就是全力以赴的努力。拿起你最喜欢的工具,跳上船吧!

许多组织有自己的定义(不同的正确性),与这里给出的定义相冲突。我希望更多的当前工作列表会与我的定义相冲突;然而,行业仍在学习这些角色定义。大家需要一段时间来凝聚共识。

原载于 2020 年 1 月 11 日【https://lifewithdata.org】

古德哈特定律对数据科学的启示

原文:https://towardsdatascience.com/on-the-implications-of-goodharts-law-for-data-science-8f4c5cd81d2e?source=collection_archive---------38-----------------------

2002 年,老布什总统签署了《不让一个孩子掉队》( NCLB)法案,这是一项教育政策,规定所有接受公共资助的学校必须对学生进行年度标准化评估。该法的一项规定要求学校在标准化评估中逐年取得适当的年度进展(AYP)(即当年参加评估的三年级学生必须比前一年的三年级学生表现更好)。如果学校继续无法达到 AYP 的要求,将会产生严重的后果,包括学校重组和学校关闭。因此,许多学区管理者制定了内部政策,要求教师提高学生的考试分数,并将这些分数作为衡量教师质量的标准。最终,随着他们的工作岌岌可危,老师们开始“为考试而教”事实上,这种政策无意中刺激了作弊,这样老师和整个学校系统就可以维持必要的资金。涉嫌作弊的最突出的案例之一是亚特兰大公立学校作弊丑闻。

这种意想不到的后果实际上非常普遍。英国经济学家查尔斯·古德哈特曾经说过:“当一个衡量标准成为目标时,它就不再是一个好的衡量标准。”这种说法被称为古德哈特定律,除了社会政策和经济之外,实际上还可以应用于许多现实世界的场景。

来源:Jono Hey,草图解释 (CC BY-NC 3.0)

另一个常见的例子是,呼叫中心经理设定目标,增加中心每天接听的电话数量。最终,呼叫中心员工人数的增加是以实际客户满意度为代价的。在观察员工的谈话时,经理注意到一些员工在没有确保客户完全满意的情况下就匆匆结束了通话。这个例子,以及“不让一个孩子掉队”的问责措施,强调了古德哈特定律最重要的元素之一— 目标可以而且将会被博弈。

资料来源:绍博·维克托, Unsplash

考虑到人工智能和机器学习模型可能容易受到游戏和/或入侵的影响,游戏的威胁要大得多。2019 年对 Youtube 上 84695 个视频的分析发现,国有媒体今日俄罗斯的一个视频被 200 多个频道推荐,远远超过 YouTube 上其他视频的平均推荐数量。分析结果表明,俄罗斯以某种方式操纵了 YouTube 的算法,在互联网上传播虚假信息。该平台依赖收视率作为用户满意度的衡量标准,这进一步加剧了这个问题。这造成了意想不到的后果 刺激了关于主要媒体机构的不可靠和不诚实的阴谋论 ,这样用户将继续从 YouTube 获取他们的信息。

“摆在我们面前的问题是,仅仅因为它能增加人们在网站上的停留时间,就把人们引入充满错误信息和谎言的可恨的兔子洞,这是道德问题——而且它确实起作用了” Zeynep Tufekci

那么能做些什么呢?

在这种情况下,重要的是要批判性地思考如何有效地衡量和实现预期的结果,以最大限度地减少意想不到的后果。这其中很大一部分并没有过于依赖单一的指标。相反,理解变量的组合如何影响目标变量或结果有助于更好地将数据联系起来。《纽约时报》首席数据科学家克里斯·维金斯提供了四个有用的步骤来创建符合道德的计算机算法,以避免有害的结果:

1.从定义你的原则开始。我建议[特别是五个],它们是由关于研究伦理的贝尔蒙特门洛报告的作者的集体研究提供的信息,并因对产品用户安全的关注而增加。选择是重要的,因为选择提前定义指导您公司的原则,从高层企业目标到单个产品关键绩效指标(KPIs 或指标]。

2.下一步:在优化 KPI 之前,考虑这个 KPI 是否符合你的原则。现在记录下来并进行交流,至少在内部交流,如果不对外或只是在线交流的话。

3.下一步:监控用户体验,定量的和定性的。考虑一下你观察到了哪些意想不到的用户体验,以及不管你的 KPI 是否在改善,你的原则是如何受到挑战的。

4.重复:这些冲突是公司学习和成长的机会:我们如何重新思考我们的 KPI,使其与我们的目标和关键结果(okr)保持一致,这些目标和关键结果应该来自我们的原则?如果你发现自己说你的一个指标是“事实上的”目标,那你就错了。****

虚拟变量和交互作用在线性回归中的作用

原文:https://towardsdatascience.com/on-the-role-of-dummy-variables-and-interactions-in-linear-regression-558d9644fc67?source=collection_archive---------13-----------------------

入门

了解这一点将有助于您在拟合线性模型时更好地控制局面

我们都熟悉线性回归的典型例子:根据房子的大小、房间和浴室的数量等等来预测房价。然而,我们也可能经常想在我们的模型中引入分类变量,例如房子是否有游泳池或者它的邻居。

线性回归模型的一个问题是它们只能解释数字输入。因此,我们需要一种方法,将像街区名称这样的词翻译成模型可以理解的数字。

最常见的方法是创建虚拟变量。假设我们正在查看三个主要城市的西班牙房屋,我们有一个分类变量来捕捉房屋所在的城市。这个分类变量可以取值为“Barcelona”、“Madrid”和“Valencia”,因此,如果我们希望我们的模型能够解释它,我们需要对它进行转换。我们这样做的方法是通过创建 m-1 虚拟变量,其中 m 是我们数据集中唯一城市的总数(本例中为 3)。因此,我们将用“城市”变量代替下面的两个虚拟变量:

作者图片

这些虚拟变量非常简单。如果城市是巴塞罗那,第一个将等于 1,否则将等于 0。同样,当且仅当城市是马德里时,秒将等于 1。你能明白为什么我们只需要添加 m-1=2 个虚拟变量来代表所有可能的情况吗?如果这两个假人都是 0,那一定是城市是瓦伦西亚的情况。如果我们天真地包括三个虚拟变量,我们会为自己制造一个多重共线性问题,因为这三个变量将完全共线。请注意:

作者图片

其中 cᵥ代表瓦伦西亚市的虚拟变量。因此,我们应该只创建 m-1 虚拟变量,以避免过度参数化我们的模型。

现在,让我们看看著名的鸢尾花数据集,罗纳德·费雪在他 1936 年的论文中介绍了多重测量在分类学问题中的应用。尽管他使用它来展示他的线性判别式,并且它被广泛用于分类技术的教学,但在这里我们将使用它来展示虚拟变量和交互作用在多元线性回归中的重要性和解释。

数据集由来自三种鸢尾花的每一种的 50 个样本组成:刚毛鸢尾、海滨鸢尾和杂色鸢尾。每朵花有四个测量值:萼片长度、萼片宽度、花瓣长度和花瓣宽度。

Unsplash 上由zdenk macha ek拍摄的照片

让我们假设我们对萼片长度(sepalL)和花瓣长度(petalL)之间的关系感兴趣。这种关系看起来是这样的:

作者图片

为了更好地理解萼片长度和花瓣长度之间的关系,我们可能希望拟合以下简单的线性回归模型:

作者图片

也就是说,我们将花 i 的花瓣长度建模为其萼片长度(加上截距项)的函数。将该模型与我们的数据进行拟合,我们发现最佳拟合线如下所示:

作者图片

然而,通过观察这条线,我们已经可以看到我们是如何高估了鸢尾的花瓣长度——注意我们的模型(最佳拟合线)几乎完全位于红点上方。同时,我们也低估了其他两个物种的花瓣长度。通过查看我们模型的标准化残差,我们也可以看到这一点:

作者图片

回想一下,残差是观测值和预测值之间的差值。因此,负残差意味着预测值高于观测值(高估),而正残差意味着预测值低于观测值(低估)。理想情况下,我们希望看到标准化残差随机分布在 0 附近,没有清晰的模式。不幸的是,我们可以清楚地看到,上面两个图表中的情况并非如此,我们需要做得更好。

看起来我们可以从增加一个虚拟变量来代表花的种类中获益。因此,与我们之前对西班牙城市所做的类似,我们可以创建两个虚拟变量:

作者图片

因此,我们现在将从简单回归转向多元线性回归。新模型将具有以下形式:

作者图片

现在,注意这将如何根据花的种类产生三条不同的线。如果花是鸢尾:

作者图片

如果花是杂色鸢尾:

作者图片

如果花是海滨鸢尾:

作者图片

请注意 Iris virginica 是我们的参考类别。当花是鸢尾或杂色花时,虚拟变量具有改变截距的效果。由于斜率没有变化,这意味着拟合这个模型将给出三条平行线——每个物种一条。让我们看看它的表现如何:

作者图片

标准化残差:

作者图片

这个型号比上一个型号好得多。允许三种不同的截取给了我们的模型更多的灵活性。现在它可以更好地代表这三个物种——我们可以在两个图中看到这一点。但是我们仍然可以做得更好一点。看起来考虑到不同的坡度也是有价值的,特别是在看鸢尾花的时候。

用数学术语来说,这意味着我们需要在物种模型和萼片长度之间添加一个相互作用。这是我们的最终模型:

作者图片

再次注意,这将根据花的种类产生三条独特的线。不同的是,这一次,截距和斜率将被允许不同。如果花是鸢尾:

作者图片

如果花是杂色鸢尾:

作者图片

最后,如果花是鸢尾:

作者图片

在这种情况下,我们可以看到如何将相互作用项添加到我们之前的模型中,从而使模型提供具有不同截距和不同斜率的三条线。让我们来拟合这个模型,看看我们得到了什么:

作者图片

标准化残差:

作者图片

现在我们可以看到我们的模型与数据非常吻合。看看那个残差图——它几乎是完美的!

为了完整起见,下面的表格显示了三种模型的调整后的 R 平方(越高越好)和剩余标准误差(越低越好):

作者图片

我希望我已经能够传达理解虚拟变量和交互项在线性回归的上下文中所起的作用是多么重要。了解这一点将有助于您在对数据进行线性模型拟合时,更好地控制自己的行为和决策。

关于倒数级数的和

原文:https://towardsdatascience.com/on-the-sums-of-series-of-reciprocals-6711437ad893?source=collection_archive---------13-----------------------

伟大的数学家欧拉和他的伟大发现

图片由来自皮克斯拜皮特·林福思拍摄

1735 年,著名数学家莱昂哈德·欧拉发表了论文“De summis serierum reciprocarum”(关于倒数级数的和)如图 1 所示(点击此链接查看全文)。在这篇论文中,大师发现了求和的一般封闭公式:

等式 1:整数的偶次幂的倒数之和。

欧拉惊人聪明的方法开始就让数学家们着迷。欧拉在 1734 年已经证明了巴塞尔问题。这个结果将巴塞尔问题从指数 2 推广到任何偶数指数。

图 1:欧拉和他的里程碑式论文“De summis serierum reciprocarum”(来源)。

前三个例子是:

等式 2:等式的前三个例子。1,对于 k=1,2 和 3。第一个是巴塞尔问题,一年前由欧拉首次证明。

注意等式中的第一种情况。2 是巴塞尔问题,也是由欧拉(1734 年)解决的,在我最近的一篇文章中探讨过。

图 2:1712 年 Seki kūwa s Katsuyo sanpús的一页,他在其中列出了二项式系数和伯努利数(来源)。

但在进行欧拉的精彩证明之前,必须解释一下伯努利数的概念。

图 3:他家族中几位杰出的数学家之一,雅各布·伯努利,发现了伯努利数,并以其命名(来源)。这些数字是由日本数学家 Seki kūwa 独立发现的。

伯努利数

这是证明的第一部分。我们首先提醒读者泰勒级数的概念。泰勒级数可以很快定义为“一个函数关于一个点的级数展开”泰勒级数的主题非常广泛,因此我将只讨论一个例子,即指数函数 e ˣ.的展开,而不是在这里详细探讨由下式给出:

等式 3:指数函数的泰勒级数。它的收敛半径∞,因此它对所有的ℝ.值都收敛

e ˣ 的收敛半径 r 为 R=∞。这意味着 Eq。3 是一个幂级数,它收敛于 x ∈ ℝ.的所有值

图 4:这个动画显示了当我们在等式中包含更多的项时。3 我们走近ˣ.

现在,为了获得伯努利数,我们执行两个步骤。第一个是琐碎的:我们从等式两边减去 1。3 除以 x,我们得到:

等式 4:在对等式进行简单处理后,ˣ-1)/x 获得了函数(e 的泰勒级数。3.

x ≠ 0 有效。伯努利数通过将该级数倒置来定义,如下所示:

等式 5:伯努利数是如何(间接)定义的。

为了找到 B,我们将使用一个数学技巧。自从情商。4 和 Eq。5 是彼此的倒数(通过构造),它们的乘积是 1。然后,我们可以将两个等式的右边相乘,然后将所得乘积乘以 n !。

经过一些简单的代数运算,我们得到了一个很好的表达式,它允许我们立刻确定伯努利数:

等式 6:可以快速计算伯努利数的等式。

得到的第一个伯努利数是:

等式 7:从等式 7 获得的第一个伯努利数。6.

正切函数及其幂级数

我们现在提供证明的第二部分。在本节中,我们将需要用伯努利数来表示 x 的正切值。让我们首先考虑以下恒等式:

这给出了:

等式 8:伯努利数的幂级数。

我们现在执行两个简单的步骤。将等式 8 右边的 x 替换为 2 ix (其中 i 为虚数单位)得到:

现在,在等式的左边做同样的替换。8 我们得到:

等式 9:用伯努利数表示的 x cot x 的幂级数。

然后我们用三角恒等式

还有情商。9、到达:

等式 10:tan x 的幂级数用伯努利数表示。

余切函数及其部分分数

现在是证明的第三部分,也是最后一部分。利用部分分数,欧拉得出了如下展开式:

等式 11:x cotπx 对非整数 x 的展开,也是欧拉发现的。

我们现在比较情商。9 和情商。11 前者用πx 代替 x。经过一些简单的操作,我们得到了这个奇妙的表达式:

等式 12:我们想要的结果。注意指数总是偶数。对于奇指数没有等价的展开式。

有趣的是,对于奇指数没有类似的公式(对于 k =1,立方的倒数之和等于一个数~1.20,称为阿普里常数),但是没有像等式这样的通用公式。12).也许有人读到这里会发现这一点!

我的 Github 和个人网站 www.marcotavora.me 有一些其他有趣的材料,既有关于数学的,也有关于物理、数据科学和金融等其他主题的。看看他们!

论度量的专制和度量的固定

原文:https://towardsdatascience.com/on-the-tyranny-of-metrics-and-metric-fixation-b4c1d44b5f6c?source=collection_archive---------42-----------------------

图片由 Pixabayarielrobin 提供

在一个充满指标的世界里,我们需要清楚地认识到那些弊大于利的指标

从 20 世纪 70 年代和 80 年代开始,我们可以观察到在企业管理中作为绩效衡量标准的度量概念的迅速崛起。彼得·德鲁克,这位据说发明了现代商业管理的人,曾经写道“你不能管理你不能衡量的东西”。从那时起,这句名言中的思想不仅被应用于商业环境,而且基本上被应用于所有行业,包括教育、医疗保健、军事等。

然而,度量标准并不是衡量业务不同方面效率的灵丹妙药。此外,人们经常错误地认为度量是数字的,并且在某种程度上是标准化的,它们背后有强大的科学推理。

在 Nate Silver 的《信号与噪音》和 Cathy O'Neil 的《数学毁灭武器》等书中,我们可以读到不同的统计/机器学习算法如何在无意中弊大于利。度量标准也是如此,因为选择一个错误的或有偏见的度量标准会导致错误的和潜在有害的结论。Jerry Muller 在他的书《度量的暴政》中关注于度量的固定性,即相信标准化的度量包含了做出明智决策所需的所有相关信息。这样,决策者通常将度量和改进视为同一件事,这导致了用度量来代替由经验和才能支持的判断。

来源:好阅读

与度量固定相关的两个固有且经常被引用的定律是坎贝尔定律和古德哈特定律。

坎贝尔定律:

“任何量化的社会指标越多地用于社会决策,它就越容易受到腐败压力的影响,就越容易扭曲和腐蚀它打算监测的社会进程。”

古德哈特定律(由玛丽莲·斯特拉瑟恩解释):

"当一个度量成为目标时,它就不再是一个好的度量."

两者都有相同的基本概念,即当给定的绩效指标成为人们/公司试图实现的目标时,完全相同的指标不再是最初试图衡量的良好代表,因为总会有实体试图利用该指标为自己谋利。

在这篇文章中,我探讨了一些与作者在度量的暴政中描述的度量崇拜有关的问题,以及我们如何不应该盲目地遵循有偏见/游戏化的度量作为真理的来源。

度量固定引起的潜在问题

我将尝试简要描述由度量固定引起的潜在问题,并用真实的例子来说明它们。为了更深入的分析,我推荐阅读《度量的暴政》

测量最容易测量的

当我们实际想要测量的东西非常复杂或不可捉摸时,我们经常试图使用简单的测量方法。在这种情况下,我们经常选择更简单、更容易测量的代理,它可能只捕捉到我们想要测量的实际事物的一小部分(或者实际上什么也没有)。问题也出现在隧道视野的名下。

当然,这个问题没有放之四海而皆准的解决方案,有些事情太复杂了,无法用一个或几个指标完全衡量。重要的是要记住,所选择的指标/代理实际上是对实际问题的简化,它抛弃了在做决策时不应被忽略或忘记的许多复杂性。

照片来自 Pexels

衡量投入而不是产出

与前一个问题相联系,衡量一个项目所花费的资源量(无论是货币还是其他可量化的单位)通常比努力的结果更容易。这在政治中经常可以观察到,在政治中,各方陈述投入到某项计划中的资金数量,而不是陈述项目的结果或对人们生活的影响。

通过标准化降低信息质量

量化是非常诱人的,因为它在广义上组织和简化了知识。通过使用标准化的度量标准,我们可以很容易地获得我们在人(员工、学生等)之间进行比较的数字信息。)或实体(学校、医院等。).

这个问题的一个例子可以是学校给定班级后的标准化考试。理论上,他们应该衡量学生在学习 X 年后的知识水平。然而,他们实际上告诉学生在测试中做得如何(仅测试所有理论上获得的知识的子集),而没有说明其他重要的事情,如激励学生追求知识,团队合作,发展个性等。

此外,指标提供的过度简化(为了确保可比性)会导致扭曲,因为指标会将信息从上下文、历史和意义中剥离出来。回到测试结果,只看数字可以掩盖一个事实,即一所学校取得的数字与其他学校相比可能较低,但它们实际上是一项成就,因为该学校位于一个动荡的街区,并处理有困难的个人/家庭情况的孩子。

通过剥离不确定性、警告和模糊性来创建度量标准,我们最终获得了确定性和权威知识的外观,因为我们假设度量标准必须有深刻的科学背景。

通过奶油游戏度量标准

通过创造,穆勒的意思是人们可以通过找到更容易或更简单的案例来保留或改进当前指标的案例。他提供了一个基于医疗保健行业的例子,其中外科医生可以选择易于手术的患者,这样可以最大限度地降低手术失败的风险,从而降低外科医生或医院的成功率。不幸的是,在这种情况下,情况复杂的病人可能会被拒绝手术,这对他们的康复甚至存活的机会产生负面影响。

通过省略或歪曲数据来提高数字

这是衡量标准的另一种游戏形式,其中相关方可以省略或扭曲数据来改进衡量标准。书中的一些例子包括:

  • 警察降低犯罪的严重性(将重罪归类为轻罪),
  • 将邻近地区的多个犯罪案件归为一类,即使它们明显没有联系,
  • 一些学校曾经将成绩差的学生归类为残疾学生,以便将他们从普通学生群体中剔除,从而提高平均成绩。

通过降低标准来改进指标

这种谬论的一个明显例子存在于教育部门。一些学校可以简单地降低获得及格分数所需的分数,以增加毕业学生的指标。通过这种方式,看起来学校实际上比实际情况做得更好。

Unsplash 上的 chuttersnap 拍摄

另一个真实的案例是航空公司操纵航班时间。有些航空公司会人为地延长航班的预定时间。通过这种方式,他们试图考虑潜在的延误,并玩弄航班准点率的衡量标准。当所有的初始航班时间都被夸大时,即使途中发生了一些延误,也更有可能按时到达。

目标位移

目标位移是指由于专注于优化特定指标,个人或机构的目标向非最优轨迹转移的现象。让我们用一个商业例子来说明这一点。当基于一个或几个指标对员工进行评估时,就会发生目标位移,这可能无法说明员工的全部职责及其对公司成功的影响。

想象一下,一个员工的评估仅仅基于一个指标,如解决的客户支持票据的数量。在这种情况下,这样的员工会尽最大努力关闭尽可能多的票,以保住工作,获得加薪等。但与此同时,该员工只专注于完成工作单,可能会错过他或她可以为公司做的其他潜在事情,例如指导更多初级同事、提出潜在的新项目、发现 CS 工作单中的模式并向适当的团队提及,以便解决/改善客户旅程中的棘手问题等。所有这些都没有在绩效评估指标中考虑,这限制了员工只能专注于一项活动。

值得一提的是,这种衡量标准对于从事重复性、非创造性工作的员工来说可能非常合适,比如工厂工人或打电话推销的广告客户。

目标转移的另一个例子可以在教育行业再次找到。我们已经看到了标准化考试的例子,标准化考试是用来衡量知识的总体水平的。这种考试导致了一种普遍的现象,即为考试而教,老师们专注于教授考试中可能出现的内容和过去已经出现的内容,而忽视了其他方面。一个例子可能是忽略较长的论文,而倾向于对考试中的问题给出简洁的答案。

限制创造力和企业家精神

度量固定会导致限制员工的创造力和他们的创业精神。这与目标位移有关,因为员工很可能会根据他们的评估指标进行优化,而不是发挥创造力和提出新想法。实验和创业的问题在于,新的、大胆的想法伴随着风险。许多想法可能会失败,而有些想法可能会改变一些企业的游戏规则。然而,这种突破性的想法伴随着不可估量的风险,并且不能很好地与非常具体的性能指标一起工作。这就把我们带到了由公制固定引起的下一个问题。

短期主义

许多企业(但不仅仅是企业)可能会关注短期,因为在不久的将来为指标进行优化要容易得多。上市公司就是这种情况,它们每个季度都会公布收益。因此,为下一季度设定现实且可实现的预期,并真正实现它们,是这些公司最关注的。

许多潜在的革命性想法和项目可能需要大量的时间来开发和实施,这与实现短期目标的优化不一致。此外,创新项目是不确定的,可能不会导致公司市场状况的实际改善。这就是为什么高管们经常将资金从 R&D 的部门转移到那些可以更有效地利用这些资金来实现短期目标的部门。

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

数据收集的无形成本

指标固定的一个通常被忽视的因素是收集计算指标所需数据的实际成本。虽然数据收集和分析是许多企业的关键组成部分(因此数据科学迅速崛起,数据科学家被评为 21 世纪最性感的工作),但教育或医疗保健等行业的情况并非如此。

通常,医生/教授自己必须收集所需的病例文档并将数据手动输入到某种中央系统中,这可能需要大量的时间,并且通常是在没有额外补偿的情况下加班完成的。另一个问题是机会成本,在这种情况下,这是教授或医生在收集所需数据时可以做的事情:改进课程,帮助学生,治愈更多的人,等等。

结论

《度量的暴政》是一本警示性的书,作者在书中指出了度量固定的主要特征:

  • 用标准化的数字指标取代基于经验的判断的强烈意愿。
  • 一种信念是,将绩效指标公之于众将确保相应的机构正确地履行其职责。不幸的是,由于文章中描述的各种形式的衡量标准博弈,情况并非如此。
  • 天真地认为,基于标准化指标的奖励/惩罚是一种通用的解决方案,可以适当地激励相关方持续改进他们的绩效。

从本书中可以吸取的教训是,在许多情况下,标准化的度量标准是对现实的过度简化,并没有考虑到情况的整个范围。因此,正如生活中的许多事情一样,适度是关键。我们绝不应该停止使用度量标准,因为没有适当的度量标准来运行任何组织都是适得其反的。我们应该使用它们,但同时也要意识到它们的缺点,并结合基于经验的判断来使用它们,以做出可能的最佳决策。

当提出新的指标时,我们应该始终努力确保:

  • 我们实际上需要新的度量标准,因为度量标准的丰富性不是我们想要的,
  • 度量尽可能准确地反映我们想要测量的实际事物,
  • 这个度量标准并不是一个几乎毫无价值的不可测量事物的代理,
  • 如果指标涉及到员工,请尝试让他们参与到建立指标的过程中,因为他们通常拥有深入的领域知识,而高层管理人员在建立指标时可能会忽略这些知识。

这本书包含了更多真实生活中的例子,这些例子都是由度量标准的固定所导致的潜在谬误。但同时,它不仅仅是悲观的,还展示了一些使用度量标准实际上改善了情况的例子。

就个人而言,我非常希望在书中看到更多的空间来解决问题,设计更有意义的度量标准,并实际使用它们和领域专业知识来增强决策过程。

在电车上,自动驾驶汽车上,为了树木而错过森林。

原文:https://towardsdatascience.com/on-trolleys-and-missing-the-forest-for-the-trees-or-how-i-went-from-fearing-self-driving-cars-to-a27210456ccf?source=collection_archive---------21-----------------------

我是如何从害怕自动驾驶汽车到相信它们可以拯救我们的。

TL, 博士:我曾经认为自动驾驶汽车会导致各种各样的伦理问题,应该劝阻其发展。思考如何将 无轨电车问题应用于自动驾驶汽车 让我改变了想法,现在我相信它们的好处远远大于它们的风险,从道德上来说,我们必须尽快建造和部署它们。然而,它们带来的一些伦理困境仍然存在,因此它们的广泛采用需要仔细规划,并包括某些护栏。

为什么我害怕无人驾驶汽车:

我以前真的很讨厌自动驾驶汽车这个想法。这是小小的嫉妒:在公众心目中,自动驾驶汽车象征着当前人工智能和人工智能范式转变所承诺的可能性。另一方面,在零售和数据科学领域之外,很少有人理解我自己的需求预测和库存优化日常工作与任何计算机视觉或 NLP 问题一样值得拥有人工智能的绰号。

好吧,我太幼稚了。实际上,我认为无人驾驶汽车带来的坏处比好处多,还有两个更深刻、更严重的原因:

  • 当谈到无人驾驶汽车时,我觉得在责任和道德责任问题上有几个伦理困境。尽管这些问题还没有答案,但鉴于最终将制造和运营自动驾驶汽车的公司可能的财务实力,为这些困境拟定的答案肯定不会有利于公众。例如:一个人因嵌入式计算机视觉模型的错误分类而被自动驾驶汽车伤害,该模型通常有 99.99%的准确率。自动驾驶汽车公司将进行游说,将这类事件归类为反常的统计事件,以避免对随后的损害和伤害承担责任。毕竟,在当今世界,没有一个硬件制造商期望他们的产品达到 100%的可靠性,卷积神经网络只是另一个技术神器。另一方面,一个在过去 30 年里从未闯红灯的人类司机,因为他从未误认为是绿灯,但他今天第一次意外地错分了十字路口信号灯的颜色,并最终在这个过程中伤害了某人,他将无法声称他的红色分类准确率迄今为止为 99.9995%,这只是一个反常的统计事件。从刑罚的角度来看,基于他良好的记录,他可能会得到宽大处理,但他仍然要对损害和费用负责。
  • 在更大的范围内,我觉得自动驾驶汽车是第一种严重威胁社会的技术。也有其他信息技术和自动化取代人力的案例,但其影响或多或少局限于有限的领域,或者新技术的采用是渐进的,社会能够适应(你们中有多少人因为被网飞解雇的重磅炸弹员工而失眠?).自动驾驶汽车的情况并非如此:在发达国家,驾驶某种车辆谋生可能是那些没有大学教育或其他专业技能的人最稳定、最赚钱、最广泛的职业之一。优步估计到 2017 年底,他们在美国有 130 万司机(现在这个数字可能更高)。美国还有350 万卡车司机,还有成千上万的公交司机、送包裹司机、送餐司机等等。与此同时,在中国,滴滴拥有多达 3100 万司机 。采用也不会是缓慢渐进的。一旦第五级自动驾驶汽车(即完全不需要司机的汽车)实现,它们的采用将会非常非常迅速。科技公司、乘车共享和其他运输公司以及汽车制造商已经预见到了这一点,并为此做出了规划。此外,它们将降低成本,比普通汽车方便得多,只要汽车公司能够以足够快的速度生产它们,它们的广泛采用将比拼车服务取代老式出租车服务所需的时间更短。自 19 世纪初以来,技术反对者、勒德分子和其他各种悲观主义者就一直在警告技术失业。对此的回应一直是,到目前为止,世界末日的情景还没有成为现实,技术创造的就业机会一直比它带走的多。但鉴于自动驾驶汽车的速度和影响范围,它们的影响会有所不同。如此迅速地让如此多的在职成年人失业将会产生严重的经济和社会后果,这一次,我们将无法躲避技术失业的子弹。

概括地说,我非常担心 L5 自动驾驶汽车的到来,因为:(1)它们提出了伦理困境,这些困境可能会以有利于大公司的方式解决,而不利于骑手的安全和财务,(2)它们可能会导致工人大规模和突然的失业,这是我们作为一个社会没有能力应对的。

车辆自主性的 0-5 等级(来源:https://www . nhtsa . gov/technology-innovation/automated-vehicles-safety)

输入台车问题:

T 电车难题是由菲利帕·福特在 1967 年提出的一个现代形式的思维实验。其基本公式如下:

你正看着一辆失控的电车沿着轨道冲下山坡,有 5 个人被卡在轨道上,几秒钟之内就会被轧死,所以在那之前没有机会把他们从轨道上解救出来。在你旁边是一个杠杆,如果拉动它,它会将手推车重新引导到一个侧轨道上,一个 5 岁的小女孩正在轨道上玩耍。如果你拉动杠杆,那 5 个人得救了,但是小女孩死了。如果你不拉操纵杆,那 5 个人都会死,但是那个女孩什么也不会发生。你应该拉操纵杆,还是让电车继续在轨道上行驶?

这是一个奇怪的场景,在现实生活中几乎不会发生。其最初的目的是证明结果主义伦理学(其中结果决定哪种行为最道德)和义务论伦理学(其中普遍规则决定哪种行为最道德)之间可能的冲突:一个结果主义者会选择拉杠杆来拯救 5 个人并牺牲那个女孩,因为 5 个生命比一个生命更有价值,而义务论者会选择不拉杠杆,因为否则他会谋杀一个无辜的女孩,而什么也不做。 他没有犯任何错误,即使这 5 个人被困在原来的道路上运气不好(注意,我们在这里不考虑不作为有罪的情况)。

在它存在的大部分时间里,手推车问题主要是学术兴趣,或者是在晚宴上提出来让自己显得有趣和深刻的东西。没有人会真的面对一个真实的世界,在那里他们有几秒钟的时间进行道德计算,并决定他们是伊曼纽尔·康德的信徒还是约翰·斯图亚特·穆勒的信徒。差不多吧。这确实发生过一次,是火车,不是电车。

但是随着自动驾驶汽车成为现实,电车问题突然变成了一个非常实际的问题:

当一辆配备了最新图像识别和实体检测算法的自动驾驶汽车发现自己处于必须在撞到左边的 5 个人和右边的一个年轻女孩之间做出决定的情况下,会发生什么?需要提供一种算法来做出这样的决定:我们是否把它变成一个优化问题,用一个数值目标函数来计算每一个行动过程将拯救多少生命?或者,我们是否对一些明确的“如果-那么”类型的规则进行编码,以反映“无论代价如何,你都不应伤害一个无辜的人”这一原则?

这个问题开始引起一大堆议论:哲学毕业生现在可以考虑在谷歌担任产品经理,而不是被迫去社区大学教书。开发人员会喜欢尝试解决这种类型的问题,而不是花费他们的日日夜夜苦干,想出另一个微服务 REST API,也许有 5 个人会在未来 2 年内使用。深刻的哲学问题和算法/建模挑战的交集让每个人都觉得他们是在现实生活中的阿西莫夫的故事。在晚宴上提出手推车问题的人现在可以在哲学玩笑中说出特斯拉和 Waymo 的名字,并表现为都是与尖端技术领域相关的渊博的知识分子

最近偶然看到这篇很棒的帖子,让我想起了电车问题的这个新化身:“电车问题不再是理论上的”。它对电车问题给出了一个清晰明了的概述,也是一个关于各种伦理框架(义务论、结果论等)的很好的入门,这些伦理框架可以用来解决人工智能的伦理困境。

我开始研究无轨电车问题的逻辑,试图弄清楚为什么这对人工智能驾驶的车辆来说是一个现实世界的困境,但对人类司机来说却很少如此?毕竟,Foot 最初的表述涉及到人类决策者,基于此,想象处理“类似手推车问题”的情况实际上是准备驾照考试时标准道路规则培训材料的一部分并不牵强。

答案是:在这种情况下,人类司机很少能够诉诸逻辑。他们无法在头脑中做出如此闪电般快速的纯理性计算,同时他们还试图保持对碰撞车辆的控制,也在认真思考自己的死亡。他们将无法以所需的速度处理信息,更不用说在管理情绪、肾上腺素和任何其他生理影响的同时处理信息了,这些都是由于不可避免的碰撞造成的。

这是我突然想到的:无人驾驶汽车将是比人类好得多的驾驶员!首先,尽管自动驾驶汽车将不得不处理偶尔的技术缺陷或软件错误,但总体而言,它们比人类司机更不容易出错。自动驾驶汽车绝不会边发短信边开车,也不会酒后驾车,更不会故意超速行驶,等等…

更重要的是(对于 Trolly 问题),在碰撞或其他高风险情况下,他们在瞬间做出决定时会更加理性。因此,他们需要能够进行解决诸如手推车问题这样的困境所需的伦理演算。另一方面,人类太慢,太依赖生理因素,太情绪化,永远无法在必要的时间框架内解决它们,这样的伦理困境与他们的驾驶技能没有实际关联。现在我们明白了为什么考驾照时不需要手推车问题的知识。

缩小以查看森林:

好的但是如果自动驾驶汽车比人类司机更好,那么这里就不仅仅是电车问题这样的边缘案例,或者自动驾驶汽车的责任和代理问题了。

绝大多数车祸都是由各种人为错误造成的:分心驾驶、鲁莽驾驶、疲劳驾驶、酒后驾驶、未打信号等。例如,我的家乡华盛顿州 2015 年造成碰撞的统计数据见下表(我认为可以肯定的是,类似的模式正在国家层面发生,在大多数其他发达国家也是如此)。

统计数据来自华盛顿州运输部 2015 年年度碰撞总结:请注意,有缺陷的设备——这是任何自动驾驶汽车最有可能发生碰撞的情况——导致了 2559 起碰撞。相比之下,分心驾驶的次数为 46348 次,超速驾驶的次数为 19662 次,未让出优先通行权的次数为 18876 次,所有这些原因都可以通过适当设计的自动驾驶汽车来消除。

这意味着自动驾驶汽车的广泛采用将大大减少因交通事故而发生的死亡、受伤以及物质和经济损失的数量。事实上,可以想象自动驾驶汽车技术将会进步(通过将 M.L .和 A.I .与各种控制工程和基于规则的护栏相结合),达到汽车碰撞接近零的程度。尽管上面讨论的一些伦理困境(电车问题、自动驾驶汽车的责任和道德代理等)仍然相关,但与自动驾驶汽车在拯救生命方面的总体优势相比,它们的重要性显著下降(注意,我在这里使用的是结果主义思维模式,以便做出最后一个声明)。

说到树…

今天的汽车平均有 95%处于闲置状态。让我们先看看我自己家庭的使用模式:每天早上我开车 2.8 英里/7 分钟到离我们家最近的公交车站,然后把我的车留在公交车站,乘公交车去西雅图市区。我妻子大部分时间在家工作,但每周有两天不得不去华盛顿大学上课。她开车约 6 英里/14 分钟到达当地校园。她的通勤时间总是和我的不一样。对于其他任务,如购物和周末,我们只使用我的车。由于这种时间冲突,我和我妻子的通勤时间表之间每周有两个早晨,这意味着我们不得不在家里养两辆车,而不是一辆。

有了自动驾驶汽车,这种情况将不复存在。自动驾驶汽车带我去汽车站。在我妻子需要去 UW 的日子里,车会自己回家,然后送我妻子去学校。我可能会在白天给她发短信或电子邮件,告诉她我会在 18:00 回到汽车站,那时她可以派车来接我。我们获得了前两辆车相同的物流灵活性,排放率大致相当,但现在只生产和维护一辆车而不是两辆车的环境足迹。

使用合适的优化和车辆路线安排技术,上述优点可以应用于更大的人群和组织。理论上,我们可以有效地达到这样一个点,即每个人口中心都有一个单一的集体运输系统,该系统仍然提供个人拥有车辆的物流灵活性,但车辆数量要少得多(尽管实现这样一个 u̵n̵i̵v̵e̵r̵s̵a̵l̵̵p̵u̵b̵l̵i̵c̵̵t̵r̵a̵n̵s̵p̵o̵r̵t̵a̵t̵i̵o̵n̵系统的社会障碍,至少在美国,将是令人生畏的)。当然,这意味着汽车制造和维护对环境的影响将显著降低,交通拥堵和通勤时间的显著减少也将带来社会(和精神健康)效益。

自动驾驶汽车是一种道德要求:

所以现在我们已经确定无人驾驶汽车有潜力做到以下几点:

  • 通过消除由人的失误和弱点造成的汽车碰撞,每年挽救大量的生命,这些失误和弱点构成了汽车碰撞的绝大多数。
  • 显著降低汽车制造和维修行业对环境的影响。
  • 通过大幅减少世界各大城市的汽车数量,从而减少或完全消除交通堵塞,提供显著的社会效益。

正因为如此,我现在相信,自动驾驶汽车的潜在好处对改善人类状况是如此引人注目和至关重要,以至于有能力这样做的当局和组织在道德上必须尽一切努力制造自动驾驶汽车,并确保它们尽快得到广泛采用。

让我用另一种更戏剧化的方式来表达:

据估计,全世界每年有 125 万人死于车祸。因此,发达国家政府和主要科技公司必须尽快开发无人驾驶汽车的道德义务,与世界各国政府和医疗机构在出现危险的传染病如 SARS 或 2019-nCoV 冠状病毒时必须开发疫苗的道德义务是相同的。

我意识到这是一个非常强烈,甚至激进的说法。但正如我在上面所说的,我认为自动驾驶汽车对人类和环境的积极影响确实证明了这种必要性。

太好了,如果你相信那个论点,那我们就都准备好了!!!自动驾驶汽车或多或少是一种绝对的好处,任何关心自己未来孙子、讨厌交通堵塞的负责任的好公民都应该开始给他的国会议员打电话,或者尝试在 Waymo 找份工作。在这种关于自动驾驶汽车的新的宏伟观点中,那些讨厌的伦理困境不再是存在的问题。相反,它们仅仅是设计细节,无论哪个软件团队被指定为他们工作,他们都可以担心,而我们却在期待一个更清洁、无交通堵塞的星球,一个 17 岁的 Snapchat 用户不再有能力摧毁一个家庭。

没那么快!!!!我们实际上让困境变得更糟……

无轨电车问题,非常严重…

我们忘记了我关于自动驾驶汽车的第二个严重问题:几乎所有以驾驶陆地车辆为生的人突然大规模的技术失业。事实上,我们现在发现自己正在处理一个“宏观”层面的电车问题:

自动驾驶汽车带来的“真正”电车问题:权衡自动驾驶汽车将为人类和地球带来的巨大好处,以及那些将被自动驾驶汽车淘汰的人的生计和人类尊严。

当权衡自动驾驶汽车的潜在好处,还是纠结于各种哲学谜题,如最初的自动驾驶汽车电车问题或自动驾驶汽车的道德机构问题时,选择是显而易见的。

但是当我们考虑到技术失业的问题时,那么做一个简单的成本效益分析就不再可能了。事实上,我们开始看到后果主义方法的局限性:在这种情况下计算效用是很难的——与全人类相比,数百万职业司机中只有几千万人受到影响,但我们是否考虑了他们的家庭和社区?如此大规模的失业对经济和整个社会的连锁反应如何?可以想象,如此大规模的失业将导致如此严重的社会冲突,以至于首先抵消了自动驾驶汽车的好处。

在这一点上,我们必须进入康德的领域:康德的伦理学方法是义务论方法的缩影,他谈到了“目的王国”,一个理想的社会,在这个社会中,每个人都被视为自己的“目的”,没有人被视为仅仅是实现另一个人或团体的目标的手段,无论这些目标多么高尚或崇高。

这里有一个非常黑暗、令人毛骨悚然的思想实验来说明康德关于目的王国的概念:

想象一下,我告诉你可以实现一个持久的世界和平:一个可持续的结束所有的战争和所有的冲突和意识形态的斗争,但前提是你必须履行以下仪式:你需要带一个 4 岁的孩子,把他们关在黑暗的地下室里度过余生,每天,你必须进入地下室,用喷灯折磨他们 30 分钟。这是为了世界和平可以接受的代价吗?

大多数人会响亮地回答:“不!”。

从这个角度来看,如何潜在地避免汽车碰撞,或者如此激进地减少流通车辆的数量会对环境产生什么影响都无关紧要:只要哪怕是一个人的尊严,一个“终点”被践踏,那么自动驾驶汽车就不是我之前认为的绝对积极的东西。

我觉得还是有希望的。虽然我认为自动驾驶汽车的大规模采用将比其他技术快得多,自由市场的极度便利和效率乐于助人,但它仍然不会是瞬间的。在 L5 自动驾驶汽车的第一个成功量产模型和它的广泛采用之间,仍将有几个月的时间(或者至少我希望如此。如果我们的技术和商业模式以比这更快的速度发展,那么我们将面临更大的人工智能相关问题,我们都应该为数字末日做好准备。在此期间,不同的世界政府和组织可能会探索不同的解决方案。这些解决方案必须经过周密的计划(以便在执行时干扰最小),并且需要足够的勇气。

作为可以实施的政策类型的一个例子:我在 2003 年参加了一个海洋生物学会议(在过去的生活中,我将神经网络和预测算法应用于沙丁鱼和鲭鱼种群)。毛里求斯代表解释了该国政府如何作为拯救珊瑚礁努力的一部分,实际上向沿海渔民支付全额工资,不让他们在任何受影响的珊瑚礁区捕鱼。这就是我所说的有勇气:美国政府有没有勇气向 3000000 多名美国卡车司机支付报酬,让他们在 4 或 5 年内不要驾驶卡车,或者提供其他形式的安全网,让他们过渡到新的就业形式?

一句警告:

你可能已经注意到,在提到自动驾驶汽车的好处时,我经常使用“潜在”这个词。这并不是因为我认为 L5 自动驾驶汽车的未来在某些方面是不确定的。一点也不。这是因为更深层次的风险:

仅仅因为一项新技术具有显著改善人类状况的潜力,并不意味着该技术的实际应用会带来这样的结果。只要看看互联网,它本应是知识共享和统一的工具,但却变成了相反的东西:错误信息、宣传和分裂的工具。或者更接近眼前的主题:看看打车服务,它承诺减少流通车辆的数量,因为许多人会发现使用它们作为他们的默认交通方式比拥有一辆汽车更少麻烦,更具成本效益。相反,它们导致许多大城市的车辆数量增加,因为驾驶拼车服务被视为一种容易获得和灵活的工作,几乎不需要或根本不需要资格。

同样的风险也适用于自动驾驶汽车:它们在社会中的部署必须谨慎进行,并得到指导,以便我们作为一个社会努力实现它们的潜在好处。否则,它们可能会变成不同的东西,导致更多而不是更少的车祸,或者将我们已经拥堵的道路变成自主的深度卷积网络驱动的无政府状态。今天,大多数在线广告服务都是完全自动化的,由客户目标 ML 算法运行,没有任何人工干预——看看由此产生的垃圾网站、垃圾窗口和恶意软件网页,它们已经成为现代浏览体验的定义。现在,将那些作为在线加法行业特征的相同设计原则、商业模式和技术过度应用于从 Roomba 到 18 轮车大小的自动驾驶汽车,想象一下对我们的基础设施和环境的影响……你看到了吗?一想到这件事就害怕得不敢去想。

这就是说,为了防止自动驾驶汽车的部署陷入算法-机械混乱,政府和大技术必须协同工作,确保它们的采用和使用遵循严格的计划和规则,在所有阶段都将康德的“目的王国”概念作为指导原则。

鉴于各国政府在其它任何重要的全球问题上几乎没有达成一致,它们如何才能实现所需的协调规划水平?我不知道,但我确实有希望,因为在这种情况下,Bigtech 有影响力,有手段,也有自我利益,来引导自动驾驶车辆朝着正确的方向正确部署。

结论:

在这篇文章中,我解释了我是如何从觉得无人驾驶汽车将是最大的问题来源,转变为相信使用无人驾驶汽车的优势将解决如此多的问题,以至于政府和科技公司在道德上有义务尽快提供它们。我认为,尽管有诸多积极影响,自动驾驶汽车仍将带来前所未有的技术就业水平,带来可怕的社会和经济后果。我认为,基于康德的目的王国的概念,我们不应该忽视那些被自动驾驶汽车淘汰的人的困境,因为这将把他们视为手段,而不是目的。最后,我呼吁,一旦实现了必要的技术创新,L5 自动驾驶汽车用于公共用途的部署应该谨慎并根据预定的计划进行,以确保它们确实完全实现其承诺,并减轻它们将导致的工人失业的影响。

同样,CRISP-DM 方法

原文:https://towardsdatascience.com/once-again-crisp-dm-methodology-13f02557b632?source=collection_archive---------33-----------------------

弗兰基·查马基在 Unsplash 上拍摄的照片

快速浏览机器学习项目的著名方法之一

如果你正在读这篇文章,说明你对机器学习和数据科学感兴趣。你可能会尝试在这个领域开始你的职业生涯。或者简单地说,你想更新这种方法。

无论如何,非常欢迎你继续阅读!

老实说,这是许多关于这种方法的帖子之一。你不会在这里发现其他帖子没有的新东西。然而,我会给它一个不同的方法。不是如何将这种方法应用到你在互联网上找到的数据集,而是如何在实际的商业问题中使用它。

长话短说 CRISP-DM ,代表数据挖掘的跨行业标准流程,是一个由几个步骤组成的迭代过程。它为如何从头开始构建数据宁敏项目设定了框架。

基于 CRISP-DM 流程的米格尔·托雷斯图像

业务理解

如果你想成为一名成功的数据科学家,你需要对业务有高度的理解。我肯定你已经听过这句话很多次了。

好吧,惊讶吧,是我再一次告诉你,不管你认为你对这个行业或这个行业了解多少,你知道的还不够。

我说的不是理解你 Kaggle 项目的栏目。我的意思是,拥有高水平的商业专业知识,这需要很多年才能实现。只是不要忘了一直学习业务,研究你正在工作的行业。

基本上,没有业务专业知识,你不知道你的模型需要什么样的关键特性。此外,你不会有无限的时间只专注于了解行业或领域。你将有许多其他任务要做,例如,照顾数据,维护,运行和部署其他模型。

总之,依靠与业务相关的人会帮助你更快地实现这一点。向他们提问、学习并创造协同效应。

对这个行业非常好奇

一旦你了解了业务,并且你有一个问题要解决,设定目标,写下它们,并使它们清晰公开,这样业务人员就可以联合起来。(请注意,这些目标很可能会改变)

数据理解

Adeolu EletuUnsplash 上拍摄的照片

现在你认为你了解这个行业了吗?理解数据是一个全新的世界。这需要专业技能,更重要的是,需要大量的时间和耐心。可能你不会有。这将不会是几个表或只是一个简单的排序和清理 CSV。幸运的是,很少有大的数据库。

数据理解和业务理解一样,是一个漫长的过程,在你的整个职业生涯中,你都将经历这个过程。

对数据充满好奇

数据准备

想想你需要什么来创建理想的数据集,然后疯狂地获取它们。不要只关注数据库中的内容。离开它们,去其他网页(也叫网络报废),去仓库,甚至,让你的公司购买它。

这一步有时被称为特征工程,它包括数据清理、分类和删除相关变量等任务。

这被认为是一个创造性的过程,也是这个项目的真正价值所在。当然,这将是你花费大部分时间的地方。有人说,大约 80%的时间花在数据争论上。

所以…

沉迷于功能

建模与评估

我不会在这上面花太多时间,但是如果你想节省时间和头痛…

先试试 XGBoost

这会给你带来非常好的结果。并且您不必花费大量时间来选择最合适的算法和更改超参数。你可以花很多时间只是为了稍微减少你的模型的误差。真的值得吗?将这些额外的时间用在特性工程阶段会更好吗?在这个阶段,你可以产生更大的影响。

部署和监控

如果你到了这里,炒作是真实的。这意味着商业人士对你所做的很满意,并且已经可以使用了。否则,你不会这样做。

这里的目标是…

尽可能自动化。

有许多不同的部署。它可以只是一个报告,或每晚的批处理,或一个 CSV 文件。大多数情况下,您必须将您的模型放在一个生产服务器中,并且它将由第三方使用。随着时间的推移,模型的准确性会降低,必须用新的模型来代替。因此,创建必要的指标来自动跟踪它何时不能正常工作。

结论

这是迭代的,意味着您将在不同的步骤上来回多次。因此,这可能导致项目并不总是到达最后一步。试着不要沮丧,一切都是学习过程的一部分,基本上,统计。你可以一直责怪数据:)

这是一般项目的完美方法,不管你在哪个领域。它会给你保持某种组织的力量,在这个过程中你不会迷路。基本上,只要遵循这种结构,你就能获得很高的收益。

然而,一旦你深入具体的行业,你可能会有其他更适合的方法。它将永远取决于你正在解决的问题!

你喜欢邮报吗?检查其他我有,他们更实际的真实数据,我相信你会喜欢他们:D

[## 面对神经网络的 ARIMA 模型

北京污染的时间序列预测

towardsdatascience.com](/facing-the-arima-model-against-neural-networks-745ba5a933ca)

感谢阅读!别忘了保持你的数据项目整洁、有记录和有条理!😄

从前的知识库:如何用 PyTorch 编写可读、可维护的代码

原文:https://towardsdatascience.com/once-upon-a-repository-how-to-write-readable-maintainable-code-with-pytorch-951f03f6a829?source=collection_archive---------24-----------------------

现实世界中的数据科学

深度学习代码库系列的英雄之旅—第一部分

丹·马洛瓦尼加尔·海姆斯
创作的快板艾团队

我们的目标都是编写一个可维护的模块化代码库,支持从研究到生产的 R&D 过程。高效和成功的深度学习项目的关键,这不是一个容易的壮举。这就是为什么我们决定写这个博客系列——分享我们从众多深度学习项目中获得的经验,并展示使用开源工具实现这一目标的方法。

本系列的第一篇文章是关于如何利用 PyTorch 生态系统和 Allegro Trains experiments manager 来轻松编写可读和可维护的计算机视觉代码的教程。我们主要关注 PyTorch 生态系统中的两个包,Torchvision 和 Ignite。Torchvision 是一个流行的包,由流行的数据集包装器、模型架构和计算机视觉的通用图像转换组成。Ignite 是一个新的库,可以简单明了地将指标报告、提前停止、模型检查点和其他功能添加到您的培训循环中。在这篇文章中,我们编写了一个代码库,在 COCO 数据集上训练和评估一个 Mask-RCNN 模型。然后,我们将训练数据(损失、准确性等)注册到 Pytorch 本机 Tensorboard 中,并使用Allegro Trainsexperiment&autoML manager 来管理和跟踪我们的训练实验。通过这些步骤,我们实现了一个无缝的、有组织的、高效的模型培训流程。

我们的开源资源

Ignite 框架的本质是它的引擎类,该类在数据集上循环给定次数,并执行处理功能。例如,训练引擎循环遍历训练数据集并更新模型参数。此外,引擎具有可配置的事件系统,便于运行的每个步骤上的交互:(1)引擎启动/完成;(2)纪元开始/完成;(3)迭代开始/完成。因此,您可以将自定义代码作为事件处理程序来执行。
Allegro Trains 是一个“自动逻辑”实验& AutoML manager,它通过代码版本控制、性能指标和模型来源来跟踪和控制培训过程。Trains 还为工作人员灵活地执行队列管理,并使多个用户能够协作和管理他们的实验。

让代码开始

请注意,为了运行本教程,应该安装以下开源包:PyTorch、TorchVision、Ignite、TensorBoard、NumPy 和 Allegro Trains。请访问以下页面进行安装:

我们从 Trains 两条线的集成开始编码。将这两行代码添加到任何代码都会在您执行 Trains 任务时启动它。project_name 参数将在 Trains web app 中打开一个专用项目(如果不存在),并以 task_name 参数中定义的名称注册您的实验。

每次你执行代码时,Trains 会自动在创建的任务中记录你所有的实验信息(git repo、commit id、使用的 python 包、argparse 参数等),这将让你在默认的演示服务器或你自己的私有 Trains 服务器上跟踪、复制和管理你所有的实验(即做科学实验)。此外,将 argparse 参数注册到 Trains 任务中可以在以后使用 Trains 代理执行自动超参数优化。

*from* trains *import* Task
task = Task.init(project_name='Object Detection with TRAINS, Ignite
                               and TensorBoard',
                 task_name='Train MaskRCNN with torchvision')

Trains 具有的另一个有用的特性是将配置数据连接到模型的能力,因此在系统中注册的每个模型都将包括用于训练它的配置数据。您可以连接一个配置文件,或者只提供一个配置字典。为此,我们还将在两行集成代码之后添加以下两行代码。

# Connect the model configuration data to train as well: configuration_data = {'image_size': 512,
                      'mask_predictor_hidden_layer': 256}
configuration_data = task.connect_configuration(configuration_data)

数据争论

为了训练 Torchvision 模型,我们使用 getitem 方法将数据集设置在一个类中,该方法将下一个数据集实例作为 PIL 图像元组和元数据字典返回。元数据字典包括将用于在每个图像上训练模型的地面真相的盒子、标签和遮罩。getitem 方法通过对图像和元数据执行提供给类构造函数 init 的转换来结束。

*class* CocoMask(CocoDetection):
    *def __init__*(self, *root*, *annFile*, *transform*=*None*,
                 *target_transform*=*None*, *transforms*=*None*,
                 *use_mask*=*True*):
        super(CocoMask, self).__init__(*root*, *annFile*, *transforms*,
              *target_transform*, *transform*)
        self.transforms = *transforms* self.use_mask = *use_mask

    def __getitem__*(self, *index*): 
        coco = self.coco
        img_id = self.ids[*index*]
        ann_ids = coco.getAnnIds(imgIds=img_id)
        target = coco.loadAnns(ann_ids)
        *if* len(ann_ids) == 0:
            *return None* path = coco.loadImgs(img_id)[0]['file_name']
        img = Image.open(os.path.join(self.root,
                         path)).convert('RGB')

        # From boxes [x, y, w, h] to [x1, y1, x2, y2]
        new_target = {"image_id":torch.as_tensor(target[0]
                                 ['image_id'], dtype=torch.int64),
                      "area":torch.as_tensor([obj['area'] 
                             *for* obj *in* target],
                             dtype=torch.float32),
                      "iscrowd":torch.as_tensor([obj['iscrowd'] 
                                *for* obj *in* target], 
                                dtype=torch.int64),
                      "boxes":torch.as_tensor([obj['bbox'][:2] + 
                              list(map(add, obj['bbox'][:2], 
                              obj['bbox'][2:])) 
                              *for* obj *in* target], 
                              dtype=torch.float32),
                      "labels": torch.as_tensor([obj['category_id'] 
                                *for* obj *in* target], 
                                dtype=torch.int64)}
        *if* self.use_mask:
            mask = [coco.annToMask(ann) *for* ann *in* target]
            *if* len(mask) > 1:
                mask = np.stack(tuple(mask), axis=0)
            new_target["masks"] = torch.as_tensor(mask,
                                  dtype=torch.uint8)

        *if* self.transforms *is not None*:
            img, new_target = self.transforms(img, new_target)

        *return* img, new_target

一旦使用 getitem 方法将数据包装在一个类中,就可以将训练验证集构造为 PyTorch 数据集,并启动相应的数据加载器。DataLoader 类基本上提供了一个高效的迭代器,它使用 CPU 加载和准备数据,而 GPU 运行深度学习模型。该类为用户提供了对常见深度学习数据加载属性的控制,如批量大小、随机播放等。注意,除了加载器之外,下面的函数也返回‘标签枚举’。它是一个字典,将标签名称与它们的数字 id 连接起来,这些数字 id 将在稍后阶段使用。

*def* get_data_loaders(*train_ann_file*, *test_ann_file*, *batch_size*,
                     *test_size*, *image_size*, *use_mask*):
    # Create PyTorch dataset objects, for train and validation data.
    dataset = CocoMask(
        root=Path.joinpath(Path(*train_ann_file*).parent.parent, 
             *train_ann_file*.split('_')[1].split('.')[0]),
        annFile=*train_ann_file*,
        transforms=get_transform(train=*True*, image_size=*image_size*),
        use_mask=*use_mask*)
    dataset_test = CocoMask(
        root=Path.joinpath(Path(*test_ann_file*).parent.parent, 
             *test_ann_file*.split('_')[1].split('.')[0]),
        annFile=*test_ann_file*,
        transforms=get_transform(train=*False*,image_size=*image_size*),
        use_mask=*use_mask*)

    labels_enumeration = dataset.coco.cats

    indices_val = torch.randperm(len(dataset_test)).tolist()
    dataset_val = torch.utils.data.Subset(dataset_test,
                  indices_val[:*test_size*])

    # set train and validation data-loaders
    train_loader = DataLoader(dataset, batch_size=*batch_size*, 
                   shuffle=*True*, num_workers=6,
                   collate_fn=safe_collate, pin_memory=*True*)
    val_loader = DataLoader(dataset_val, batch_size=*batch_size*, 
                 shuffle=*False*, num_workers=6,
                 collate_fn=safe_collate, pin_memory=*True*)

    *return* train_loader, val_loader, labels_enumeration

创造火炬点燃引擎

完成数据集准备后,我们用下面的“运行”方法训练 MaskRCNN 模型。首先,为任务设置模型(作为 GPU 模型—如果机器上有此选项)。如果您从先前的训练方案继续,加载预训练的模型权重。然后,设置前面代码片段中定义的数据加载器。由于 TensorBoard 现在是 Pytorch 的原生版本,您可以轻松导入并设置 TensorBoard SummaryWriter 来记录您的所有报告。此外,您所有的 TensorBoard 报告将自动注册到 Trains 服务器中,以便您能够实时监控您的所有实验。只需设置 Tensorboard Summary Writer,并在相关的引擎事件处理程序中添加标量和图像的报告。
最后,创建 Ignite 训练器和评估器引擎,并运行训练器引擎。

*def* run(*task_args*):
    # Define train and test datasetstrain_loader, val_loader, labels_enum = 
       get_data_loaders(*task_args*.train_dataset_ann_file,
                        *task_args*.val_dataset_ann_file,
                        *task_args*.batch_size,
                        *task_args*.test_size,
                        configuration_data.get('image_size'),
                        use_mask=True) val_dataset = list(chain.from_iterable(zip(*batch) 
                  *for* batch *in* iter(val_loader)))
    coco_api_val_dataset = convert_to_coco_api(val_dataset)
    num_classes = max(labels_enum.keys()) + 1  
    configuration_data['num_classes'] = num_classes

    # set the training device to GPU if available
    device = torch.cuda.current_device() 
             *if* torch.cuda.is_available() *else* torch.device('cpu')
    # optimization for fixed input size    
    torch.backends.cudnn.benchmark = *True 
             if* torch.cuda.is_available() *else False* 

    model = get_model_instance_segmentation(
            num_classes, 
            configuration_data.get('mask_predictor_hidden_layer'))
    iou_types = get_iou_types(model)    # if there is more than one GPU, parallelize the model
    *if* torch.cuda.device_count() > 1:
        print("{} GPUs were detected - we will use all of 
              them".format(torch.cuda.device_count()))
        model = torch.nn.DataParallel(model)

    # copy the model to each device
    model.to(device)

    *if task_args*.input_checkpoint:
        print('Loading model checkpoint from'
              .format(*task_args*.input_checkpoint))
        input_checkpoint = torch.load(*task_args*.input_checkpoint,
                           map_location=torch.device(device))
        model.load_state_dict(input_checkpoint['model'])

    writer = SummaryWriter(log_dir=*task_args*.log_dir)

    # define Ignite's train and evaluation engines
    trainer = create_trainer(model, device)
    evaluator = create_evaluator(model, device)### Here we will later define the engines events handlers ###

    trainer.run(train_loader, max_epochs=task_args.epochs)
    writer.close()

让我们深入了解一下 Ignite 的训练引擎从内部看起来是什么样子。每个引擎都有更新功能,根据给定的数据批次更新模型。它向前传递数据以计算损失,然后通过反向传播更新模型权重,最后返回输入数据、地面实况和损失字典。

*def* create_trainer(*model*, *device*):
    *def* update_model(*engine*, *batch*):
        images, targets = copy.deepcopy(*batch*)
        images_model, targets_model = prepare_batch(*batch*,
                                      device=device)

        loss_dict = model(images_model, targets_model)
        losses = sum(loss *for* loss *in* loss_dict.values())

        # reduce losses over all GPUs for logging purposes
        loss_dict_reduced = utils.reduce_dict(loss_dict)
        losses_reduced = sum(loss *for* loss *in* loss_dict_reduced.values())

        loss_value = losses_reduced.item()

        *engine*.state.optimizer.zero_grad()
        *if not* math.isfinite(loss_value):
            print("Loss is {}, resetting loss and skipping training
                  iteration".format(loss_value))
            print('Loss values were: ', loss_dict_reduced)
            loss_dict_reduced = {k: torch.tensor(0) *for* k, v *in* loss_dict_reduced.items()}
        *else*:
            losses.backward()
            *engine*.state.optimizer.step()

        *if engine*.state.warmup_scheduler *is not None*:
            *engine*.state.warmup_scheduler.step()

        images_model = targets_model = *None

        return* images, targets, loss_dict_reduced
    *return* Engine(update_model)

定义 Ignite 处理程序

一旦定义了引擎,您就可以释放 Ignite 事件处理程序的能力。每个引擎都连接有 Ignite 处理程序,一旦事件发生,这些处理程序就可以执行给定功能。函数的定义是通过在函数中添加一个装饰器来完成的,说明相关的引擎和事件,在我们的例子中,引擎是训练器和评估器。请注意,操作人员必须熟悉他们的引擎。将事件设置为定义引擎的函数的嵌套函数,只是该需求的一个简单实现。下面是我们感兴趣的处理程序。您可以在代码中找到更多信息。

第一个要讨论的训练员是训练开始。在这个处理程序中,在训练过程开始时执行,设置模型优化器和学习率。

@trainer.on(Events.STARTED)
*def* on_training_started(*engine*):
    # construct an optimizer
    params = [p *for* p *in* model.parameters() *if* p.requires_grad]
    *engine*.state.optimizer = torch.optim.SGD(
                             params,
                             lr=task_args.lr,
                             momentum=task_args.momentum,                  
                             weight_decay=task_args.weight_decay)
    *engine*.state.scheduler = torch.optim.lr_scheduler.StepLR(
                             *engine*.state.optimizer, 
                             step_size=3, 
                             gamma=0.1)
    *if* task_args.input_checkpoint *and* task_args.load_optimizer:
       *engine*.state.optimizer.load_state_dict(
       input_checkpoint['optimizer']) *engine*.state.scheduler.load_state_dict(
       input_checkpoint['lr_scheduler'])

epoch-completed 处理程序将 epoch 平均精度标量注册到 TensorBoard,这使得它可在 Trains-Server webapp 上查看。然后,它保存模型检查点,该检查点自动神奇地连接为 Trains-task 输出模型。

@trainer.on(Events.EPOCH_COMPLETED)
*def* on_epoch_completed(*engine*):
    *engine*.state.scheduler.step()
    evaluator.run(val_loader) *for* res_type *in* evaluator.state.coco_evaluator.iou_types:
        average_precision_05 =
        evaluator.state.coco_evaluator.coco_eval[res_type].stats[1]
        writer.add_scalar("validation-{}/average precision 0_5"
                          .format(res_type), average_precision_05,
                          *engine*.state.iteration) checkpoint_path = os.path.join(task_args.output_dir,
                    'model_epoch_{}.pth'.format(*engine*.state.epoch))
    checkpoint = {
        'model': model.state_dict(),
        'optimizer': *engine*.state.optimizer.state_dict(),
        'lr_scheduler': *engine*.state.scheduler.state_dict(),
        'epoch': *engine*.state.epoch,
        'configuration': configuration_data,
        'labels_enumeration': labels_enum}
    utils.save_on_master(checkpoint, checkpoint_path)
    print('Model checkpoint from epoch {} was saved at {}'
          .format(*engine*.state.epoch, checkpoint_path))

以下句柄是评估时句柄的一个示例。它计算并注册调试图像到 TensorBoard,可以在 Trains-Server 上查看——类似于 TensorBoard 标量。这使用户可以密切监视模型的进展性能。

@evaluator.on(Events.ITERATION_COMPLETED)
*def* on_eval_iteration_completed(*engine*):
    images, targets, results = *engine*.state.output *if engine*.state.iteration % task_args.log_interval == 0:
        print("Evaluation: Iteration: {}"
              .format(*engine*.state.iteration))

    *if engine*.state.iteration % task_args.debug_images_interval== 0:
        *for* n, debug_image *in* enumerate(
               draw_debug_images(images, targets, results)):
            writer.add_image("evaluation/image_{}_{}"
                             .format(*engine*.state.iteration,n),
                             debug_image,trainer.state.iteration,
                             dataformats='HWC')
            *if* 'masks' *in* targets[n]:
                writer.add_image("evaluation/image_{}_{}_mask"
                                 .format(*engine*.state.iteration, n),
                                 draw_mask(targets[n]), 
                                 trainer.state.iteration,
                                 dataformats='HW')
                curr_image_id = int(targets[n]['image_id'])
                writer.add_image(
                       "evaluation/image_{}_{}_predicted_mask"
                       .format(*engine*.state.iteration, n),
                       draw_mask(results[curr_image_id]).squeeze(),
                       trainer.state.iteration, 
                       dataformats='HW')

坐下来,放松并监控你的实验

现在我们的代码库已经准备好了,我们可以执行 train 脚本,并在 Trains webapp 中监控它的进度。由于统计数据和调试图像记录在 Trains 中,您可以在您自己的专用 Trains 服务器(或 Trains 演示服务器)上查看它们。通过查看统计数据和调试图像,您可以跟踪训练过程,并确保它按计划运行。例如,查看报告的调试图像可以让您知道您的基本事实是否有问题和/或数据扩充是否产生了错误的结果。

图 Allegro Trains webapp 的调试图像快照

在上面的快照中,您可以查看实验列表,这些实验是同一个项目的一部分。点击特定的实验使我们能够在训练周期中监控预测的遮罩和边界框。在下面的快照中,您可以看到同一实验的训练统计数据—在本例中,是边界框和遮罩的平均精度。

图 Allegro Trains webapp 中培训过程的快照

摘要

我们希望你喜欢这个教程,并且现在已经更好地掌握了如何编写可读、可维护和可复制的深度学习代码。使用 Ignite 和 Trains 可以实现更简单、更高效的机器和深度学习工作流。完整的代码可以在这里找到。
我们的代码库受到 PyTorch 的 mnist with tensorboardX 和 torch visionobject detection fine tune 教程的启发。

在本系列的下一篇文章中,我们将展示我们在这里展示的代码库的模块化结构如何能够用 SSD 模型轻松替换 MaskRCNN。我们将解释单镜头和双镜头对象检测模型之间的差异,以及如何在 TorchVision 特征提取器上设置 SSD 模型。然后,我们将执行我们刚刚与您一起编写的训练和评估脚本——这一次使用单次检测器。敬请期待!

原载于 2020 年 1 月 30 日https://allegro . ai

Keras 中的单类神经网络

原文:https://towardsdatascience.com/one-class-neural-network-in-keras-249ff56201c0?source=collection_archive---------10-----------------------

为单类分类任务开发卷积 VGG

Unsplash 上由 Rodion Kutsaev 拍照

无监督学习应用于一类分类,旨在发现在没有标签的情况下区分正常和异常数据的规则。一类 SVM (OC-SVM)是一种常见的无监督方法来检测异常值。它将所有的数据点视为积极标记的实例,并在它们周围建立一个平滑的边界来检测“奇怪”的样本。

最近,基于特征提取模型的各种方法似乎是与 OC-SVM 一起使用的有效工具。随着深度神经网络作为特征提取器的惊人成功,利用深度学习和 OC-SVM 的不同方法被引入作为多步骤单类过程。

在这篇文章中,我们提出了一个单类卷积神经网络架构(如这里介绍的),它合并了深度网络的能力,以提取有意义的数据表示以及单类目标,所有这些都在一步中完成。

模型

该结构由两部分组成:特征提取器和多层感知器。这种方法的一个基本方面是,任何预先训练的深度学习模型都可以用作特征提取的基础网络。最常见的选择是采用标准网络模块进行特征提取,例如,VGG、ResNet 或 Inception 可能是这一特定任务的良好替代方案。对于在何处切割网络以生成有意义的要素制图表达,没有固定的规则。多层感知器部分位于末端,它接收嵌入的表示,并试图将它们分类为 0 或 1。这里,1 意味着输入样本属于真正的目标类,而 0 意味着输入样本属于噪声类。和以前一样,这部分的结构选择是不固定的。可以对其进行操作和调整,以实现更好的性能。

在特征提取模块和最终的多层感知器网络之间发生了奇迹。正是在那里,我们可以找到整个过程的核心思想,它允许我们将特征提取与分类结合在一起,所有这些都在一个步骤中完成,并且只有一组标签可供处理。嵌入的数据样本被“破坏”,增加了一些零中心高斯噪声。然后,将这些修改后的样本与其原始配对进行批量连接。这种方法的结果是,我们有一批由原始样本(类别 1)和损坏样本(类别 0)形成的复制图像。我们的目标是,我们的分类层可以理解这种差异,并将真实图像与所有其他图像区分开来。

提议方法的模式。来源此处

实验

我们尝试使用 Tensorflow 和 Keras 的多功能性来复制上述工作流程。首先,我们需要一个一类分类问题。所有的分类任务都可以看作是一类问题。我们可以简单地选择一个我们感兴趣的标签,然后训练一个模型来识别它,这正是我们所做的。

猫和狗的任务听起来不错。这是因为我们可以利用一些标准和预训练的深度学习模型来利用迁移学习的力量。

训练样本图片数据

我们开始选择自己感兴趣的标签,比如说“猫”。我们在训练数据中只取猫的图像。这些狗在测试期间被找回。在猫,我们给它贴上 1 的标签。标签 0 是在训练期间自动创建的,由一些随机高斯图像组成。原来只有猫的批量输入是这样复制的,现在是由标记数据和随机信号形成的。真实图像被馈入特征提取器网络。在我们的例子中,它由一个预先训练好的 VGG 组成。VGG 为我们的真实图像创建了一个有意义的嵌入式表示,这些图像与随机图像连接在一起。此时,它们通过一个多层感知器神经网络,其中的权重是可训练的。最后,我们有了一个完整的架构,可以识别猫,并且只对猫进行训练!模型的推论可以一如既往地计算出来。我们停用负责产生随机嵌入表示的网络部分,并且只保留特征提取器和多层感知器。我们测试程序传递给网络猫和狗的图像。如果成功,狗必须被归类为噪音(相当于标签 0)。

为了得到可靠的结果,拟合过程必须应用于我们所掌握的所有类。在我们的例子中,我们仅用“猫”来拟合模型,然后仅用“狗”来拟合模型。总性能是所有单个任务性能的平均值。我们获得了大约 85%的最终准确率,这对于一类学习过程来说是非常好的!

摘要

在这篇文章中,我们介绍了一个在单类分类任务上进行端到端训练的架构。这种方法适用于利用预先训练的迁移学习表示的每个领域。它也是一个很好的资源,可以应用于检索标记数据需要大量成本的每一个场景。

查看我的 GITHUB 回购

保持联系: Linkedin

参考文献

一类卷积神经网络。Poojan Oza,IEEE 学生会员,和 Vishal M. Patel,IEEE 高级会员

一个事件来统治他们

原文:https://towardsdatascience.com/one-event-to-rule-them-all-e9adf04667a3?source=collection_archive---------50-----------------------

理解大数据

将实时分析提升到新的水平

图片由 鲁斯兰发牢骚 shutterstock.com下发给远出者

我们已经基于 Apache Kafka、Spark Streaming 和 Apache Druid 运行实时分析一年多了。在解决了连接这些技术的问题之后,正如我最近的博客文章所描述的,我们向我们的系统添加了许多用例。一般来说,每个用例都是根据以下原则构建的:从一个 Kafka 主题中读取原始事件,在 Spark 流作业中处理它们,写入另一个 Kafka 主题,并摄取到 Apache Druid 中。

作者图片

它使我们能够从实时仪表盘中获得广泛的洞察力。然而,每种类型的事件都有自己的流程和可视化,独立于其他类型的事件。例如,我们有一个单独的视图来显示我们所有的点击和我们的印象。我们可以创建一个仪表板,并排显示两个磁贴——一个用于点击,一个用于展示。

作者图片

但是,我们无法同时获得基于这两个流的指标。例如,我们无法计算 CTR — 点击率——这是广告技术行业非常重要的指标。计算点击率需要特定时间段的点击数除以印象数。对于关系数据库来说,这是一项非常简单的任务——使用连接语法从两个或多个表中选择一个表来运行一个查询。德鲁伊就不是这样。加入操作最近被添加到了最新的德鲁伊版本中,然而,它主要被用作查找功能的一部分。完整的连接支持预计将在下一个版本中提供,直到 2020 年底。

联合与加入

为了最大限度地利用我们的实时分析系统,我们希望找到一种方法来根据不同类型的事件计算指标,而不使用连接。我们在寻找一个创新的想法。我们决定使用逻辑联合来解决这个问题。

让我们考虑下面的例子:我们有一个包含两种类型事件的大表——点击和印象。

作者图片

我们看到,在特定的时间段内,我们获得了三次点击和五次展示。所以那段时间的 CTR 是 3/5=0.6

类似地,我们可以计算另一个重要的指标——RPM——每千次展示的收入。

这两个指标都是从单个表中计算出来的,不需要连接到其他表。这里的技巧是“标记”不同类型的事件,以便在查询期间区分它们。

实时事件—实时数据的中心。

基于这个例子,我们构建了一个系统,将几种不同的事件类型流式传输到一个 Kafka 主题,然后传输到 Druid。该系统包含几个 Spark 流作业,每个作业处理一种特定类型的事件。每个作业从原始 Kafka 主题中读取事件级数据,用更多字段丰富它,并写入输出 Kafka 主题。注意,所有的作业都写进了同一个卡夫卡主题。每个作业根据具体的业务逻辑,除了其他字段外,还为每个事件添加一个“event_type”字段。通常作业会添加一些布尔字段,例如处理点击的作业可以验证点击状态,并将“is_valid_click”设置为 0 或 1。这使得这些字段能够在 Druid 和 SQL 查询中得到有效处理。

作者图片

数据采样

实时处理如此大量的数据是资源密集型的。我们需要 Spark 流集群中的资源来运行 Spark 流作业。我们需要 Kafka 集群中的资源来包含所有类型事件的统一主题。最后,我们需要 Druid 集群中的资源来存储所有这些事件。

让我们回顾一下——我们想从这个系统中获得什么好处?我们的目标是建立一个系统,为我们的数据提供实时视图。我们的目标是缩小基于批处理的主数据处理系统造成的差距,该系统每小时利用 Hive、Vertica、Tableau 和数百个 ETL 作业。批处理过程提供了对数据的可访问性,有几个小时的延迟。相比之下,基于 Druid 构建的系统应该快速灵活,我们还可以允许一些数据差异。因此,我们决定通过对数据进行采样来降低系统的负载。

火花作业中的取样。

我们使用 RDD.sample API 对从 Kafka 主题中读取的事件进行采样。采样率是我们所有 Spark 工作的一个参数。

rdd.sample(false,sampleRate,seed);

每个作业的采样率可以不同。例如,印象的数量远大于点击的数量,因此我们可以对 100%的点击进行采样,但只能对 1%的印象进行采样。

这个技术减少了火花,卡夫卡和德鲁伊的负荷。然而,我们需要记住,我们只有德鲁伊所有事件的一部分。我们如何保证从德鲁伊那里查询的数据是正确的,并得到完整的图片?

在德鲁伊教中处理采样。

假设我们在 Spark 流工作中对 1%的印象事件进行采样。因此在德鲁伊中我们只有 1%的印象。请注意,印象的所有记录都有以下标记字段: is_impression = 1 。通常,在没有抽样的情况下,我们会在 Druid 中运行以下查询来获得印象数:

从 realtime_event 中选择 SUM(is _ impression);

现在,对采样数据运行这个查询,我们需要记住结果应该乘以 100。如果我们将采样率从 1%提高到 10%,会发生什么?在这种情况下,我们需要将来自 Druid 的查询结果乘以 10。这种手动方法可以运行一些特定的查询。但是,对于包含多个 Spark 作业(每个作业都有自己的采样速率)的系统,它是不可伸缩的。此外,我们为来自不同团队的多个用户开发了我们的系统——采样方法应该对他们透明。他们应该能够简单透明地查询数据。

添加样本因子

为了能够透明地处理我们在 Druid 中的数据,我们提出了以下想法:我们为每个事件添加了一个“sampleFactor”字段,通过以下公式计算:

采样因子= 1/采样速率。

因此,对于 1%的采样速率,采样因子为 100。因此德鲁伊的度量值应该乘以 100。

我们使用样本因子来计算德鲁伊在摄取卡夫卡时的重要度量。

选择抽样

将这些实时数据应用到生产中时,我们面临一项新的需求——需要对特定流量进行“完全采样”的场景。例如,特定发布者的流量。使用 Spark 流作业可以轻松实现这一新要求。首先,我们检测事件是否属于特定的发布者,这应该是完全抽样的。如果是肯定的,我们不为此事件应用rdd . sample();我们还将 sampleFactor=1 添加到该事件中。使用这种方法,我们仍然可以在德鲁伊得到正确的数字,即使一些事件被完全采样。

抽样与汇总

为什么我们开发我们的特别“抽样”机制,而不是使用 Druid 内置的 rollup 特性?原因是 realtime_event 数据源是几个事件类型的联合。它还包含各种维度的联合。该数据源中有 100 多个维度。我们可以根据需要相对容易地添加更多的维度。使用 Druid 的 rollup 特性来计算可用维度的数量是没有效率的。Druid 为汇总数据源添加了内部计数器和总和。定义大约 100 维的 rollup 减少了两个事件具有完全相同的维(一分钟)的概率。然而,内部计数器和求和的开销仍然存在,使其效率低下。

摘要

通过在 Druid 中将不同的事件类型合并到一个数据源中,我们构建了一个非常广泛的实时数据视图。这便于不同团队使用不同的数据分析用例。它还允许聚合传统上使用表间连接计算的各种度量。我们通过对事件进行采样来处理伸缩和资源问题。我们的采样技术可以根据需要轻松扩展。此外,我们管理 Druid 中的数据,以便底层采样对使用 Druid 数据的团队保持透明。

Hopsworks ML 实验 MLflow 的开源替代方案

原文:https://towardsdatascience.com/one-function-is-all-you-need-for-ml-experiments-43c04bc331cb?source=collection_archive---------33-----------------------

TLDR;Hopsworks 为机器学习(ML)实验提供支持。也就是说,它可以自动跟踪您的 ML 程序的工件、图形、性能、日志、元数据和依赖性。你们中的许多人已经知道像 MLflow 这样的平台,那么为什么还要阅读 Hopsworks 实验呢?因为你不必重写你的 tensor flow/py torch/Scikit-learn 程序来获得免费的跟踪和分发 ML,TensorBoard 是内置的。我们将讨论 Hopsworks 如何独特地支持隐式起源来透明地创建元数据,以及它如何与遗忘训练函数相结合来使您的训练分布透明。

Hopsworks 游戏攻略

Hopsworks 是数据科学和数据工程的单一平台,既有开源平台又有 SaaS 平台,包括内置的功能库。您可以在 GPU 上大规模训练模型,使用 pip/conda 轻松安装任何您想要的 Python 库,将 Jupyter 笔记本作为作业运行,将这些作业放在气流管道中,甚至编写大规模运行的(Py)Spark 或 Flink 应用程序。

作为一个开发环境,Hopsworks 提供了一个集中的协作开发环境,使机器学习团队能够轻松地与队友分享结果和实验,或为项目利益相关者生成报告。所有资源在 Hopsworks 中都有强大的安全性、数据治理、备份和高可用性支持,而资产则存储在单一的分布式文件系统中(数据存储在云中的 S3 上)。

Hopsworks ML 实验存储关于您的 ML 训练运行的信息:日志、图像、感兴趣的度量(准确性、损失)、用于训练模型的程序、其输入训练数据以及所使用的 conda 依赖性。可选输出为超参数、张量板和火花历史服务器。

每个超参数试验的日志都可以通过点击其日志来检索,TensorBoard 可以可视化不同的试验结果。TensorBoard HParams 插件也可用于进一步深入测试。

跟踪

当您在 Hopsworks 平台上运行 Python 或 PySpark 应用程序时,它可以创建一个实验,其中包括程序生成的传统信息(结果、日志、错误)以及特定于 ML 的信息,以帮助跟踪、调试和重现您的程序及其输入和输出:

  • 超参数:ML 程序本身不更新的训练运行参数;
  • 度量:在这个实验中训练的模型的损失或准确性;
  • 程序神器:python/pyspark/air flow**程序、及其 conda 环境
  • 模型工件:序列化的模型对象、 模型模式模型检查点
  • 执行:能够重新执行实验的信息,包括参数、输入的版本化特征、输出文件等;
  • 版本化特征:为了能够重现一个实验,我们需要来自运行的精确的训练/测试数据,以及它是如何从特征库中被创建的;
  • 可视化:训练和评分过程中生成的图像。还可以使用 TensorBoard 可视化训练——hops works 透明地聚合所有员工的结果;
  • 日志(用于调试):模型权重、梯度、损耗、优化器状态;
  • 自定义元数据:标记实验并对其进行自由文本搜索,管理实验(标记为‘PII’、‘数据保持期’等),并重现训练运行。

在一个库中进行实验跟踪和分布式 ML

def train(data_path, max_depth, min_child_weight, estimators):
    X_train, X_test, y_train, y_test = build_data(..)
    ...
    print("hello world") # monkeypatched - prints in notebook
    ...
    model.fit(X_train, y_train) # auto-logging
    ...
    hops.export_model(model, "tensorflow",..,model_name)
    ...
    # create local files ‘logile.txt’, ‘diagram.png’
    return {'accuracy': accuracy, 'loss': loss, 'logfile':
       'logfile.txt', 'diagram': 'diagram.png'} # track dictfrom maggy import experiment
experiment.lagom(train, name="My Experiment", ...)# To launch as a distributed ML HParam Tuning job:
# sp=Searchspace(max_depth=('INTEGER',[2,8]),min_child_weight
# =('INTEGER', [2, 8]), )
# experiment.lagom(train, name=“HP, optimizer='randomsearch',
# direction='max', num_trials=15,)

支持实验跟踪的平台要求用户在某个函数或某个显式作用域(如 MLFlow 中的“with … as xx:”参见附录 A)中重构他们的训练代码,以确定实验何时开始,何时结束。在 Hopsworks 中,我们要求开发人员在函数中编写他们的训练代码。

我们称这个 Python 函数为不经意训练函数,因为这个函数不知道它是在 Jupyter 笔记本的 Python 内核上运行还是在集群中的许多工人上运行,详见我们的博客Spark/AI 峰会演讲。也就是说,您只需编写一次训练代码,在笔记本电脑上训练小型模型时,或者在大型 GPU 或 CPU 集群上执行超参数调优或分布式训练时,就可以重用相同的函数。

我们还使用这个“包装器”Python 函数来启动/停止实验跟踪。实验跟踪和分布透明度在一个单一的功能,很好!

在 Hopsworks 中,玛吉库运行实验,见上面的代码片段。如您所见,与最佳实践 TensorFlow 程序相比,用户需要的唯一代码更改是:

  1. 因子训练代码在一个用户定义的函数( def train(..):);
  2. 返回一个 Python dict,其中包含用户希望在实验中被跟踪以及稍后在实验 UI 中可访问的结果、图像和文件;和
  3. 使用实验. lagom 功能调用训练功能。

超参数可以在一次执行中固定下来,或者如代码片段的最后 4 行所示,您可以执行 train 函数,作为一个分布式超参数调优作业,跨多个并行工作器执行(如果需要,可以使用 GPU)。

Hopsworks 将自动:

  • 追踪训练函数的所有参数作为这个实验的超参数,
  • 在 model.fit 中使用 Keras 回调自动记录日志;
  • 在 HopsFS 中创建一个版本化的目录,其中聚集了程序的副本、它的 conda 环境以及来自所有 workers 的所有日志;
  • 跟踪此应用程序的所有出处信息—来自此实验中使用的 HopsFS 的输入数据(来自功能存储的训练/测试数据集),以及所有输出工件(模型、模型检查点、应用程序日志);
  • 将 workers 中执行的所有 print 语句重定向到 Jupyter notebook 单元格,以便于调试(见下面的 GIF 每个 print 语句都以 worker ID 为前缀)。

在 Hopsworks,工人的日志可以在培训期间打印在你的 Jupyter 笔记本上。拿着数据块!

张量板支架

def train():
from maggy import tensorboard
...
model.fit(.., callbacks=[TensorBoard(log_dir=tensorboard.logdir(),..)], ...)

TensorBoard 可以说是用于可视化、分析和调试机器学习实验的最常见和最强大的工具。Hopsworks 实验与 TensorBoard 无缝集成。在训练函数内部,数据科学家可以简单地导入tensorboardpython模块,并获得写入所有 tensor board 文件的文件夹位置。然后从每个执行器收集文件夹的内容,并放在 HopsFS 的实验目录中。由于 TensorBoard 支持在同一个图形中显示多个实验运行,可视化和比较多个超参数组合变得像启动实验服务中集成的 TensorBoard 一样简单。默认情况下,Tensorboard 配置了有用的插件,如 HParam、Profiler 和调试。

分析和调试

Hopsworks 1.4.0 附带了 TensorFlow 2.3,其中包括 TensorFlow 分析器。一个期待已久的新功能,最终允许用户分析模型训练,以确定训练过程中的瓶颈,如 CPU + GPU 配置中缓慢的数据加载或糟糕的操作放置。

TensorFlow 2.3 还包括调试器 V2,可以轻松找到 NaN 之类的模型问题,这对于在复杂模型中找到问题的根本原因非常重要。

**

模型注册表

在训练代码中,模型可以导出并保存到 HopsFS。使用跳跃库中的模型* python 模块,很容易对模型进行版本化并附加有意义的元数据,以反映给定模型版本的性能。*

Hopsworks Model Registry 是一项服务,其中列出了所有模型以及有用的信息,如哪个用户创建了模型、不同的版本、创建时间和评估指标(如准确性)。

模型注册中心提供了基于模型名称、版本号和导出模型的用户进行过滤的功能。此外,可以在 UI 中对模型版本的评估度量进行排序,以找到给定模型的最佳版本。

在模型注册表 UI 中,您还可以导航到用于训练模型的实验,并从那里导航到用于训练模型的训练/测试数据,以及从那里导航到用于创建训练/测试数据的功能存储中的功能。谢谢出处!

导出模型

通过使用模型模块中的导出功能,可以以编程方式导出模型。在导出模型之前,实验需要将模型写到 HopsFS 上的文件夹或路径中。然后,将该路径与模型的名称和应该附加的评估指标一起提供给函数。 export 调用将把文件夹的内容上传到您的模型数据集中,它也将出现在模型注册表中,每次导出都会增加一个版本号。

*from hops import model# local path to directory containing model (e.g. .pb or .pk)
path = os.getcwd() + “/model_dir”# uploads path to the model repository, metadata is a dict of metrics
model.export(path, “mnist”, metrics={‘accuracy’: acc})*

获取最佳模型版本

当将模型部署到实时服务基础架构或加载模型以进行离线批量推理时,应用程序可以查询模型库,以根据附加到模型版本的元数据(如模型的准确性)找到最佳版本。在以下示例中,将返回精确度最高的 MNIST 模型版本。

*from hops import model  F
from hops.model import Metric
MODEL_NAME=”mnist”
EVALUATION_METRIC=”accuracy”best_model = model.get_best_model(MODEL_NAME, EVALUATION_METRIC, Metric.MAX)print(‘Model name: ‘ + best_model[‘name’])
print(‘Model version: ‘ + str(best_model[‘version]))
print(best_model[‘metrics’])*

细节决定成败

以上是 Hopsworks 实验和模型注册表的简要概述。您现在可以在 www.hopsworks.ai 上试用它,或者在您可以接触到的任何服务器或虚拟机上安装 Hopsworks Community 或 Enterprise。如果您想了解更多关于我们如何实现管道的信息,请继续阅读。

具有 PySpark 的透明分布式 ML

Hopsworks 使用 PySpark 透明地分发遗忘训练功能,以便在工人身上执行。如果 GPU 由工人使用,Spark 会将 GPU 分配给工人,并支持动态执行器,确保在训练功能返回后释放 GPU,在此阅读更多信息。这使您能够保持笔记本电脑打开,并以交互方式可视化培训结果,而不必担心您仍在为 GPU 付费。

与将训练代码作为 Docker 映像(如 AWS Sagemaker )提供的方法相比,Hopsworks 编程模型的优势在于,您可以就地编写定制的训练代码,并直接在笔记本上进行调试。您也不需要为训练代码编写 Docker 文件,Python 的依赖关系可以通过使用来自 Hopsworks UI 的 PIP 或 Conda 简单地安装库来管理(我们为您透明地编译 Docker 映像)。

遗忘训练函数可以在不同的执行环境中运行:Python 内核中的 Jupyter 笔记本(最左边),并行 ML 实验(中间),以及集体 allreduce 数据并行训练(最右边)。玛吉和霍普斯沃斯负责复杂的任务,如安排任务、收集结果和生成新的超参数试验。

HopsFS 存储实验数据和工人在培训期间生成的日志。当通过 API 启动一个实验时,会在 HopsFS 的实验数据集中创建一个子文件夹,并将关于该实验的元数据附加到该文件夹。Hopsworks 使用隐式出处自动将这些元数据同步到 elasticsearch。

元数据可以包括诸如实验名称、实验类型、导出的模型等信息。由于实验的存在是由目录跟踪的,这也意味着删除文件夹也会从跟踪服务中删除实验及其关联的元数据。

跟踪具有隐含出处的元数据

用于跟踪 ML 工件谱系的现有系统,如 TensorFlow Extended 或 MLFlow,需要开发人员更改他们的应用程序或库代码,以将跟踪事件记录到外部元数据存储中。

在 Hopsworks 中,我们主要使用隐式出处来捕获元数据,在这里我们使用我们的分布式文件系统、HopsFS 和一些库来捕获对 ML 工件的更改,只需要对标准 TensorFlow、PyTorch 或 Scikit-learn 程序进行最少的代码更改(详见我们的USENIX OpML’20 论文)。

文件系统事件,例如从训练/测试数据集中读取特征,以及将模型保存到目录中,这些事件在 HopsFS 中被隐式记录为元数据,然后在 Elasticsearch 中被透明地索引。这允许在 UI 中对 ML 工件、元数据和实验进行自由文本搜索。

Hopsworks 中的实验是 ML 训练管道的第一部分,从特征存储开始,到模型服务结束。ML 工件(训练/测试数据集、实验、模型等)可以存储在 HopsFS 上,它们还可以附加定制的元数据。

定制元数据与工件紧密耦合(删除文件,其元数据将被自动清除)——这是通过将元数据存储在 HopsFS 使用的相同横向扩展元数据层中来实现的。这种定制元数据也会自动同步到 Elasticsearch(使用一种叫做 ePipe 的服务),从而在 Hopsworks 中实现对元数据的自由文本搜索。

伙计们,现在就到这里吧!

在所有用于数据科学的开发工具中,管理 ML 实验的平台近年来出现了最多的创新。开源平台已经出现,如 MLFlow 和我们的 Hopsworks 平台,以及专有的 SaaS 产品,如 WandB、Neptune、Comet.ml 和 Valohai。

Hopsworks 实验的不同之处是什么?您可以编写干净的 Python 代码,并分别借助隐式出处和不经意训练函数免费获得实验跟踪和分布式 ML。

越来越多的人一致认为,平台应该跟踪 ML 实验中进出的东西,以便进行调试和再现。您可以检测您的代码来跟踪输入/输出,或者您可以让框架使用隐式来源来管理它。

Hopsworks 实验是我们降低 ML 投入生产的复杂性的任务中的一个关键组成部分。未来几个月,实时功能工程和监控运营模型领域将出现更多突破性创新。敬请期待!

附录 A

在下面的代码片段中,我们比较了如何使用 MLFlow 编写 Hopsworks 实验。相似之处多于不同之处,但是在 Hopsworks 中不需要显式记录到跟踪服务器。

*def train(data_path, max_depth, min_child_weight, estimators):
    X_train, X_test, y_train, y_test = build_data(..)
    ...
    print("hello world") # monkeypatched - prints in notebook
    ...
    model.fit(X_train, y_train) # auto-logging
    ...
    hops.export_model(model, "tensorflow",..,model_name)
    ...
    # create local files ‘logile.txt’, ‘diagram.png’
    return {'accuracy': accuracy, 'loss': loss, 'logfile':
       'logfile.txt', 'diagram': 'diagram.png'} # track dictfrom maggy import experiment
experiment.lagom(train, name="My Experiment", ...)# To launch as a distributed ML HParam Tuning job:
# sp=Searchspace(max_depth=('INTEGER',[2,8]),min_child_weight
# =('INTEGER', [2, 8]), )
# experiment.lagom(train, name=“HP, optimizer='randomsearch',
# direction='max', num_trials=15,)def train(data_path, max_depth, min_child_weight, estimators, model_name):  # distribution external
X_train, X_test, y_train, y_test = build_data(..)
mlflow.set_tracking_uri("jdbc:mysql://username:password@host:3306/database")
mlflow.set_experiment("My Experiment")
with mlflow.start_run() as run:
    ...
    mlflow.log_param("max_depth", max_depth)
    mlflow.log_param("min_child_weight", min_child_weight)
    mlflow.log_param("estimators", estimators)
    with open("test.txt", "w") as f:
        f.write("hello world!")
    mlflow.log_artifacts("/full/path/to/test.txt")
    ...
    model.fit(X_train, y_train) # auto-logging
    ...
    mlflow.tensorflow.log_model(model, "tensorflow-model",
      registered_model_name=model_name)*

像 MLFlow,但是更好?

附录 B

管道是编排端到端培训和模型部署工作执行的程序。在 Hopsworks 中,您可以将 Jupyter 笔记本作为可调度作业在 Hopsworks 中运行,这些作业可以作为 Airflow 管道的一部分运行(Airflow 也是 Hopsworks 的一部分)。管道运行后,数据科学家可以在实验服务中快速检查训练结果。

构成完整培训和部署流程的典型步骤包括:

  • 通过从特征存储中选择特征来具体化训练/测试数据,
  • 对训练/测试数据进行模型训练并将模型导出到模型注册处,
  • 模型的评估和验证,如果它通过了健壮性、偏差和准确性测试,模型部署。

这篇文章最初发表在逻辑时钟网站上。所有图片版权归 Logical Clocks AB 所有,经许可使用。

一次热编码,标准化,PCA:python 中分段的数据准备

原文:https://towardsdatascience.com/one-hot-encoding-standardization-pca-data-preparation-steps-for-segmentation-in-python-24d07671cf0b?source=collection_archive---------3-----------------------

照片由梅尔·巴兰德Unsplash 上拍摄

获得正确的数据,实现完美的细分!

数据驱动的客户定位或产品捆绑对于企业在激烈的竞争中保持相关性至关重要。消费者现在有太多的选择,更喜欢个性化的产品。随着以人工智能和大数据技术的巨大增长为形式的第四次工业革命的到来,现在是利用细分模型进行此类分析的最佳时机。但是在我们深入研究这些模型之前,我们应该知道这些模型需要什么样的数据。这是我博客的重点,因为我们将经历将原始数据集转换为训练和测试分割算法所需格式的所有必要步骤。

数据

在这个练习中,我们将使用来自一家为孕妇提供服装的在线商店的点击流数据。它有从 2008 年 4 月到 2008 年 8 月的数据,包括产品类别、图片在网页上的位置、IP 地址的来源国以及产品的美元价格等变量。我选择这个数据集的原因是点击流数据正在成为提供关于客户行为的精细信息的一个非常重要的来源。它还为我们提供了一个具有典型挑战的数据集,如高维度、对特征工程的需求、分类变量的存在和不同规模的字段。

我们将尝试通过执行以下步骤为产品细分准备数据:

  1. 探索性数据分析
  2. 特征工程
  3. 一个热编码
  4. 标准化
  5. 主成分分析

探索性数据分析(EDA)

我们将首先尝试读取数据集(使用read_csv函数)并查看前 5 行(使用head函数):

# Read dataset and look at top records
import pandas as pd
df = pd.read_csv('e-shop clothing 2008.csv', delimiter=";")
df.head(5)

图 1:前 5 条记录

我们有多个服装模特每天的数据(字段名:“第 2 页(服装模特)”)。接下来,让我们检查行数和列数及其类型(使用info函数)

#Check the number of rows and columns and their types
df.info()

图 2:检查字段类型

我们有 165474 条记录和 14 个字段。需要注意的一点是,很多字段都是数值型的,但理想情况下应该是字符串。让我们使用as.type(str)函数将字段转换为字符串:

# Convert categorical variables to string
cat_vars = ['year', 'month', 'day', 'country', 'session ID',
               'page 1 (main category)', 'page 2 (clothing model)',   'colour',
               'location', 'model photography', 'price 2', 'page']
df[cat_vars] = df[cat_vars].astype(str)
df.info()

图 3:转换后检查字段类型

接下来让我们检查数字字段的属性:

# Check properties of numeric fields
df.describe()

图 4:检查数值字段的属性

如图 4 所示,产品价格(字段名:“价格”)比一个会话期间的点击序列(字段名:“订单”)要大得多。这意味着我们必须将这些场标准化,使它们具有相同的比例,因为基于距离的模型(如 K-means)会受到场的比例的影响。

特征工程

如前所述,我们的数据集是每日级别的,我们需要在产品级别聚合数据,因为我们想要执行产品细分。我们在产品级别聚合时创建了以下功能:

  1. 最常出现的产品颜色、浏览日期、国家、照片类型(个人资料、正面)、价格类型(高于或低于类别平均值)、网站内的页码以及产品照片在页面上的位置(使用mode功能)
  2. 唯一会话 id 的总数(使用nununique函数)
  3. 单次点击序列的中值、最小值和最大值以及产品价格(使用medianminmax功能)
# Feature Engineering
from scipy.stats import mode 
df2 = df.groupby(['country','page 1 (main category)','page 2 (clothing model)']).agg(
                                                                             median_no_of_clicks_per_session=('order', 'median'),
                                                                             min_no_of_clicks_per_session=('order', 'max'),
                                                                             max_no_of_clicks_per_session=('order', 'min'),
                                                                             median_price=('price', 'median'),
                                                                             min_price=('price', 'max'),
                                                                             max_price=('price', 'min'),
                                                                             total_number_of_sessions =('session ID', pd.Series.nunique),
                                                                             most_frequent_day=('day', lambda x: mode(x)[0][0]),
                                                                             most_frequent_colour=('colour', lambda x: mode(x)[0][0]),
                                                                             most_frequent_location=('location', lambda x: mode(x)[0][0]),
                                                                             most_frequent_photo_type=('model photography', lambda x: mode(x)[0][0]),
                                                                             most_frequent_price_type =('price 2', lambda x: mode(x)[0][0]),
                                                                             most_frequent_page_number =('page', lambda x: mode(x)[0][0])
                                                                            )df2

图 5:特征工程

一个热编码

一种热编码创建虚拟变量,虚拟变量是代表分类变量的一个级别的重复变量。水平的存在由 1 表示,不存在由 0 表示。如果分类变量是有序的(即变量的类别是有序的),那么我们可以使用OrdinalEncoder函数将变量转换为数值变量。在我们的例子中,分类变量没有任何顺序性,因此,我们使用get_dummies函数来创建虚拟变量。

# One hot encoding - to convert categorical data to continuouscat_vars = ['most_frequent_day',
           'most_frequent_colour', 'most_frequent_location',
           'most_frequent_photo_type', 'most_frequent_price_type',
           'most_frequent_page_number']
df2[cat_vars] = df2[cat_vars].astype(str)
df3 = pd.get_dummies(df2)df3.head(5)

图 6:一个热编码

如果我们的标称特征是整数,我们也可以使用OneHotEncoder函数代替get_dummies函数。

标准化

如图 4 所示,我们的数字特征有不同的标度。缩放有助于将不同范围或单位的独立要素转换为可比值后进行比较。有两种主要的缩放方法:

作者图片

当我们知道数据的分布不遵循高斯分布时,或者对于不假设任何数据分布的算法(如 K-最近邻和神经网络),归一化是理想的选择。另一方面,当数据遵循高斯分布时,可以使用标准化。但是这些并不是严格的规则,理想情况下,我们可以两者都尝试,并选择给出最佳集群验证结果的选项。在这个例子中,我们将使用StandardScaler函数来标准化我们的数字字段。

# Standardizingfrom sklearn.preprocessing import StandardScaler
con_vars = ['median_no_of_clicks_per_session', 'min_no_of_clicks_per_session',
           'max_no_of_clicks_per_session', 'median_price', 'min_price',
           'max_price', 'total_number_of_sessions']scaler = StandardScaler()
df3[con_vars]=scaler.fit_transform(df3[con_vars])
df3.head(5)

图 7:标准化

主成分分析

主成分分析以特定的方式结合我们当前的特征来创建新的特征,然后我们可以丢弃“最不重要的”,同时仍然保留所有原始变量中最有价值的部分。当我们有很多特性要处理时,这是一个有用的方法。它计算所有特征的协方差矩阵,然后从矩阵中生成特征向量和特征值。然后,协方差矩阵乘以特征向量以创建主分量。这些主成分是基于我们的原始特征的新特征,并且它们在解释数据集中的可变性方面的重要性由特征值给出。我们可以保留解释原始数据集中最小方差的排名最高的主成分。

我们可以使用来自sklearn.decomposition模块的pca函数实现 PCA 分析。我设置了一个循环函数来识别能够解释数据集中至少 85%方差的主成分的数量。

# PCAfrom sklearn.decomposition import PCA# Loop Function to identify number of principal components that explain at least 85% of the variance
for comp in range(3, df3.shape[1]):
    pca = PCA(n_components= comp, random_state=42)
    pca.fit(df3)
    comp_check = pca.explained_variance_ratio_
    final_comp = comp
    if comp_check.sum() > 0.85:
        break

Final_PCA = PCA(n_components= final_comp,random_state=42)
Final_PCA.fit(df3)
cluster_df=Final_PCA.transform(df3)num_comps = comp_check.shape[0]
print("Using {} components, we can explain {}% of the variability in the original data.".format(final_comp,comp_check.sum()))

图 8: PCA 输出

如图 8 所示,15 个成分能够解释我们数据集中 85%的差异。我们现在可以在我们的无监督模型中使用这些特征,如 K 均值、DBSCAN、分层聚类等来细分我们的产品。

结论

在这篇文章中,我们了解了为细分分析准备数据所需的步骤。

具体来说,我们了解到:

  • 我们应该如何通过查看数据、字段类型和数值字段的属性来执行探索性数据分析。
  • 我们可以从原始分类字段和连续字段中创建何种特征的示例。
  • 如何在 python 中实现一个热编码以及顺序编码
  • 各种类型的缩放技术以及如何在它们之间进行选择
  • 什么是 PCA 以及如何在 python 中使用它进行特征约简

你对这个博客有什么问题或建议吗?请随时留言。

最后,我鼓励您阅读下面的文章,以深入了解选择最佳分类数的不同方法:

在 Python 中实现 7 种选择最佳聚类数方法的备忘单

感谢您的阅读!

如果你像我一样,对人工智能、数据科学或经济学充满热情,请随时在 LinkedIn 上添加我。

现在,每两个皮达尼斯人中就有一个应该学习戈朗语

原文:https://towardsdatascience.com/one-in-two-pythonistas-should-learn-golang-now-ba8dacaf06e8?source=collection_archive---------3-----------------------

意见

为什么 Google 的语言在 web 开发、系统编程等方面击败了 Python

谷歌地鼠在工作。图片来自 Golang 网站

Y Y 我们一般的软件工程师还在爱着 Python。甚至结婚了。

但谷歌、优步、Dropbox、Soundcloud、Slack 和 Medium 的员工却没有。顶级公司的程序员早已爱上了这种有着可爱吉祥物的语言。

这并不是说 Python 不好。太棒了!

但是,无论是 API、web 服务还是数据处理——尽管大多数开发人员仍在使用 Python,但表现出色的人正在越来越多地采用 Golang,或 Go。因为它很棒。

由先驱者创造

围棋是由谷歌的全明星三人组发明的:罗伯特·格里斯默是谷歌 V8 JavaScript 机器的负责人之一,也是谷歌发明的另一种语言 Sawzall 的主要开发者。Rob Pike 共同开发了 Unix 环境,并共同创建了 Limbo 编程语言。有了 Ken Thompson,这个团队就有了 Unix 的发明者和 B 语言——C 语言的前身——的创造者。

Google 最初是用 Python 编写的——是的,Python 仍然很酷——但是在 2007 年左右,工程师们在寻找一种更好的语言来执行 Google 的典型任务。根据 Rob Pike 在 2012 年的一次演讲,他们遇到了这样的问题:

  • 缓慢的构建:产生新代码要花很长时间。听起来很熟悉!
  • 不受控制的依赖关系:你有没有试过安装一个软件包,却发现你必须安装至少五个其他的依赖关系和无数的子依赖关系才能让它工作?事实证明,即使是谷歌员工也有这个问题。
  • 每个程序员使用不同的语言子集:在 Python 中,一个开发人员可能使用 numpy 包,另一个更喜欢 scipy,以此类推。当程序员想要将他们的代码混合到一个包中时,事情就变得混乱了。
  • 糟糕的程序理解:那些说他们在阅读代码的那一刻就理解了代码的人是在撒谎。至少如果它不是一个非常简单的“Hello World”程序的话。并且代码的文档通常没有帮助——在大多数情况下,它甚至不存在,或者写得很差。
  • 重复工作:你有没有从程序的一部分复制一段代码,只是为了把它复制到别的地方?不好的做法。但是大多数编程语言都很容易做到。
  • 更新的成本:面对上述的混乱局面,更新软件需要花费大量的时间和脑力,你真的会感到惊讶吗?不酷。
  • 版本偏差:重复代码到处都是,工程师可能只更新原始代码片段的一个版本,而忘记了其他版本。所以你最终会得到一个包含新旧代码的版本。听起来很混乱?确实是。
  • 编写自动化工具的难度:编写自己编写代码的程序是可能的——事实上,大多数程序在某个阶段都会这样做。但是用现代编程语言,这仍然很难实现。
  • 跨语言构建:你知道问题所在——Python 非常适合中小型脚本,C++非常适合复杂的程序,Java 非常适合 web 开发,Haskell 非常适合懒惰但健壮的代码。结果是一个程序经常包含许多不同语言的代码片段。但是为了编译、调试和简洁起见,用一种语言编写程序要好得多。

因此,三人组着手设计一种干净、简单、易读的语言。这种语言将会消除或者至少减轻软件工程中这些太常见的问题。

[## 为什么要学围棋?

" Go 将成为未来的服务器语言."Tobias Lütke,Shopify

medium.com](https://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65)

精益语言…

这些常见问题的根源是现代语言的复杂性。想想 Python 或 C——你有没有尝试过阅读完整的文档?祝你好运。

相比之下,围棋最大的特点就是简单。这并不意味着你不能用它来构建复杂的代码。但是 Go 是非常谨慎的,不要有带来更多复杂性而不解决问题的特性。

例如,Go 不像其他面向对象语言那样有类。作为其他语言的一个常用特性,类对于让一个对象继承另一个对象的属性非常有用。问题是,如果你试图改变一个对象的结构而不改变其他对象的结构,你会破坏代码。Go 有一个替代方法,叫做 struct,它更倾向于组合而不是继承。

谷歌应用引擎的地鼠。图片来自 Golang 网站

Go 的其他主要功能包括:

  • 类型安全:在 C 中,你可以使用指针做任何事情——包括让程序崩溃。围棋不会让你这样乱来的。
  • 可读性:和 Python 一样,Go 把可读性放在第一位。这使得它比大多数语言对初学者更友好,也使得代码更容易维护。
  • 文档:特别是初级开发人员发现写一些关于你的代码的简介让其他人可以使用是很乏味的。有了 Godoc,这个过程比大多数语言自动化得多——开发者不必浪费宝贵的时间写下他们一直在做的事情。
  • 正交性:这意味着如果你改变了代码中的一个对象,其他对象不会因此而改变。从这个意义上说,收音机是正交的,因为如果你换台,音量不会改变。例如,与 C 语言非常不同——如果你改变了一件事,那么其他人可以依赖于它而改变。Go 是正交的,因为它使事情变得更简单。
  • 在 Go 中,编写一段代码只有一种方法。与 Python 相比,你有无数种方法来编写一个东西!
  • 实用性:重要的东西应该易于编码——即使这意味着其他事情在 Go 中是不可能完成的。这里的逻辑是,您希望通过使重复任务变得快速和简单来提高开发人员的生产率。如果有更复杂的问题——这种情况很少发生——他们总是可以用另一种语言来写。

所有这些听起来可能很无聊,没有创意。从某种意义上来说,这是真的——这是一种没有可以用来给别人留下深刻印象的时髦特征的语言,解决问题的过多方法,没有没有限制的自由。Go 不是一种可以用来探索和研究的语言。

但是当你试图建造一些有用的东西时,这是很神奇的。当你在一个团队中,有很多来自不同背景的不同的人在编写相同的代码。当你厌倦了其他语言带来的混乱时。

如何 gopher?图片来自 Golang 网站

…一个繁荣的社区

由于其简单性,Go 是当今最具协作性的语言之一。程序员过去常常坐在他们的小隔间里,从不与他人见面的时代已经过去了。

现在,我们有了 StackExchange 来解决我们所有的编码问题。我们有 Slack、Zoom、Google Meet 等工具来与我们的团队保持联系。但是现代语言仍然是为小隔间里的小书呆子量身定做的。

Go 改变了这一切。尽管比 Python 年轻 20 年,但它有一个充满活力的社区。

所以毫不奇怪,他们把尊重、开放和友好放在他们行为准则的首位。虽然其他语言,如 Python 或 C,也有类似的社区声明,但对这些基本价值的强调较少。

因此,社区在年度 Go 调查中扮演明确的角色就不足为奇了——不像在许多其他语言中。

关于社区和领导力的问题,来自 2019 Go 开发者调查

数据不言自明

根据 2019 Go 调查,谷歌的语言最常用于 web 开发、网络和系统编程。Python 的前景看起来非常相似:

Python 的使用,来自 2019 Python 开发者调查

唯一显著的区别是 Python 用于数据分析和机器学习的程度。在这些领域,其他热门的新语言正在出现。

除此之外,你可以看到 Python 的许多用法可以被 Go 取代。其中包括 46%的网页开发,37%的系统管理和开发,19%的网络编程。即使你假设许多开发人员做所有这三项工作,你也可以有把握地假设一半的 Pythonistas 正在做他们在 Go 中可以做的事情。

事实上,开发人员意识到了 Go 提供的巨大潜力。根据 Hackerrank 的数据,2019 年大约有三分之一的程序员想要学习围棋。

根据黑客排名,接下来最热门的语言。

这种趋势是真实的——由于围棋非常容易学习,我们应该会在未来几年看到从 Python 到围棋的转变。对于大多数公司来说——尤其是那些没有 Dropbox 或 Medium 那么大和资金充足的公司——重写他们所有的代码将会非常昂贵。但是对于新项目,你至少应该尝试一下。

在最大的公司里,开发人员已经在用 Go 建立他们的成功。你什么时候会?

一行 Python 代码帮助您理解一篇文章

原文:https://towardsdatascience.com/one-line-of-python-code-to-help-you-understand-an-article-c8aacab33dcb?source=collection_archive---------11-----------------------

纳西索 1Pixabay 拍摄的照片

使用stylecloud生成花哨的掩蔽词云图像

当有人说我们需要从一篇文章中提取主题时,你会想到 NLP(自然语言处理)算法、RNN 深度学习等吗?嗯,这些都是正确的答案,但有时对于一个简单的问题来说可能有点小题大做了。

你可能听说过也可能没有听说过云这个词。我想说的是,在某些用例中,这是一个非常充分、有趣且快速的解决方案,可以用来展示一篇文章的主题,或者仅仅是一段文字。基本上,它可以做以下事情:

  • 提取文章的关键词
  • 基于出现次数可视化关键词
  • 以一种奇特的方式呈现视觉化

在本文中,我将介绍一个最容易使用的 Python 库— stylecloud ,它可以为我们生成这个单词云图像。

快速启动

像素上的像素拍摄的照片

安装 stylecloud 库和其他库一样简单。只是用pip如下。

pip install stylecloud

那么,让我们快速开始。您将会看到,使用这个库可以非常容易地生成一个漂亮的单词云图像。

有人曾经问我“数据架构师是做什么的?”当然,回答这个问题的最佳方式是使用一系列要点来阐述一般数据架构师的主要职责。然而,我们也可以用“云”这个词来“形象化”这些概念上的点。

让我们使用维基百科中的术语。例如,下面的网页显示了术语数据架构师的内容。

我们可以复制这一页上的所有内容,然后简单地保存到文本文件中。然后,魔术时间到了。

import stylecloud as scsc.gen_stylecloud(
    file_path='data_architect.txt', 
    output_name='data_architect.png'
)

所以,我们只是把文本文件名给了 stylecloud 库。单词云图像将按照我们为output_name参数指定的那样简单地生成。

非常酷。这是我为数据工程师角色生成的另一个单词云。我们可以把它们放在一起进行比较。

当然,我们不能指望一行 Python 代码就能产生像 RNN 模型给我们的一样精确的东西。然而,我想说它是数据可视化、非结构化数据的一个极好的替代方案:)

从两个单词的云图中,我们可以忽略一些没有太大意义的东西,比如单词“percent ”,只关注我们感兴趣的东西。通常可以看出,数据架构师的角色更多的是一个组织级别,为项目设计数据架构,必须具备一些管理技能,而数据工程师的角色则侧重于工程,需要更多的技术技能。

一些高级用法

拍摄的照片Pixabay

你有没有注意到我们生成的两幅图像都是国旗形状的?是的,这是 stylecloud 最棒的功能之一——屏蔽。

假设我们想要为新冠肺炎生成一个单词云图像。在这个例子中,我再次使用了维基百科上的页面。那么,我们如何才能使图像看起来更适合我们要生成的主题呢?我不想要 stylecloud 默认的“flag”掩码,因为它对病毒的主题没有太大意义。

stylecloud 库使用 FontAwesome 作为它的图标库。FontAwesome 通常用于网页设计。例如,许多小图标,如 Twitter、Linkedin 等。得到了 FontAwesome 的支持。基本思想是使用一个 HTML 类使 HTML 元素显示为一个好看的图标。不要担心,如果你不知道 web 开发,在这种情况下你不需要知道。

这里是 FontAwesome 的链接。

[## 字体真棒

世界上最受欢迎和最容易使用的图标集刚刚得到了升级。更多图标。更多款式。更多选择。

fontawesome.com](https://fontawesome.com/)

我们可以简单地搜索“病毒”,我们会得到如下病毒图标页面。

唯一需要做的就是复制类名fas fa-viruses并在gen_stylecloud()函数中使用它,如下所示。

sc.gen_stylecloud(
    file_path='covid-19.txt',
    icon_name='fas fa-viruses',
    output_name='covid-19.png'
)

将 Stylecloud 和维基百科库结合起来

照片由 geraltPixabay 上拍摄

现在,我要给你看一些更“蟒蛇”的东西。Python 的一个令人惊奇的特点是有如此多令人惊奇的库可用。在上面的例子中,我们一直使用维基百科,并手动将内容复制到文本文件中。那一点也不方便。

在我以前的一篇文章中,我介绍了一个 Python 库,可以开箱即用地删除维基百科中的内容。

[## Python 中的三个“开箱即用”的 Web 内容抓取应用程序

你不需要通过使用它们来学习刮削

towardsdatascience.com](/three-out-of-box-web-content-scraping-applications-in-python-e342a6836ba4)

我们可以一起使用这两个库!

首先,我们来安装维基百科 Python 库。

pip install wikipedia

然后,导入库以供使用。

import wikipedia

第三,让我们摇滚吧!这里有一个 LinkedIn 的例子。

sc.gen_stylecloud(
    text=wikipedia.summary("linkedin"),
    icon_name='fab fa-linkedin-in',
    output_name='linkedin.png'
)

还有推特。

sc.gen_stylecloud(
    text=wikipedia.summary("twitter"),
    icon_name='fab fa-twitter',
    output_name='twitter.png'
)

我猜想例子的数量已经足够了。接下来,你自己去图书馆看看吧!

摘要

照片由 Pixabay 上的 mat_hias 拍摄

在本文中,我介绍了另一个令人惊叹的 Python 库——style cloud。最漂亮的是,它可以生成一个带有遮罩图标的单词云的图像。

这样一个库的使用非常简单。也就是一个功能几乎可以实现一切。然而,这背后的逻辑并不像我们如何使用它那么简单。感谢每一个为社区做贡献的人。

[## 通过我的推荐链接加入 Medium 克里斯托弗·陶

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@qiuyujx/membership)

如果你觉得我的文章有帮助,请考虑加入灵媒会员来支持我和成千上万的其他作家!(点击上面的链接)

在 Jupyter 笔记本中点击鼠标来标记图像

原文:https://towardsdatascience.com/one-mouse-click-to-label-an-image-within-a-jupyter-notebook-40053095333a?source=collection_archive---------58-----------------------

一个交互式笔记本,使您在处理图像识别时更有效地标记数据

照片由陈茂三潭Unsplash 上拍摄

训练图像识别模型的关键是拥有大量手动标记的图像。这需要时间,所以您希望添加每个标签的过程越快越好,最好只需点击一下鼠标。

当我遇到这个问题时,我很惊讶我找不到任何免费的一键解决方案。所以我自己造了一个:

[## g morinan/click 2 标签

要开始标记图像,只需单击鼠标,打开 labelling.ipynb 并执行前两个代码单元格。每…

github.com](https://github.com/gmorinan/click2label)

如果您打开labelling.ipynb并运行前两个单元格,您将能够像这样做:

作者图片

看看click2label.py的底层代码。

我本可以为现有的开箱即用服务付费。但是作为一名数据科学家,我更希望有一段 Python 代码,我可以根据每个项目的持续需求快速定制。

另外,使用 Jupyter 笔记本使我不必打开另一个程序。

我在 机器医学技术 工作,我们使用计算机视觉,但这篇文章与我们在那里做的任何事情完全无关。此外,给猫&狗的基因贴标签比从视频中检测人类生物标记要容易得多。

在 R 中进行方差分析时最常见的错误之一

原文:https://towardsdatascience.com/one-of-the-most-common-unintentional-mistakes-when-running-an-anova-in-r-cfa55d332a?source=collection_archive---------14-----------------------

或者:为什么 OLS 回归(lm)和方差分析(aov)函数有时会不同,以及如何使用 car 软件包解决这个问题。

想象一下这个场景:你在 R 中运行 ANOVA,同时控制其他变量(技术上来说,是 ANCOVA)。然而,结果看起来很奇怪:独立变量的顺序很重要并影响结果——怎么会这样呢?如果你尝试输入相同的模型作为线性回归,结果也完全不同。再说一遍,这怎么可能呢?

这篇文章旨在阐明这个共同的问题。首先,让我们从重现这个问题开始。如果你正在寻找关于 ANOVAs 的更全面的介绍,可以看看我关于这个主题的文章。

许多人没有注意到他们的 ANOVAs 是错误的。(图片由loc fürhoffUnsplash 上拍摄)

我们将使用 base R 中包含的薪水数据集重新创建这个问题。它包含教授薪水和其他变量的数据,这些变量会直观地影响教授的薪水,如学科和资历。您可以使用以下命令来访问它。

df=Salaries

现在,假设我们感兴趣的是,在控制其他直观上重要的自变量时,教授的性别是否会影响他们的工资。人们可以使用方差分析来分析这些差异。因此,让我们用 ANOVA 分析数据集中两组之间的差异。

aov1.1=aov(salary~sex+rank+yrs.since.phd+yrs.service+discipline,df)summary(aov1.1)

这个方差分析似乎暗示性别对教授的工资有显著影响。但是,如果你运行与线性回归模型相同的分析,就会得出不同的结论。

lm1.1=lm(salary~sex+rank+yrs.since.phd+yrs.service+discipline,df)summary(lm1.1)

在这里,性别对教授工资的影响似乎微不足道。那是什么呢?性别到底有没有影响教授的工资?另一件奇怪的事情出现了:如果你重新运行 ANOVA 1.1,但改变了自变量的顺序,它也会显示不同的结果。在下面的例子中,我们改变了独立变量性别和等级的位置。

aov1.2=aov(salary~rank+sex+yrs.since.phd+yrs.service+discipline,df)summary(aov1.2)

同样,不同的结果。现在我们有三组结果和终极困惑。性别对于回归是不显著的,但是,例如,yrs.since.phd 也是不显著的,这与回归结果不同。这是怎么回事?哪个自变量影响教授的工资?为什么所有的结果都不一样?

原因是类平方和。它描述了 R 如何将误差项合并到回归模型中,以及合并误差的不同方式导致不同的拟合模型。默认情况下,R 使用类型 I(“一”)方差分析的平方和,类型 1 非常适合只有一个自变量的方差分析。然而,当你添加更多的自变量(技术上是 ANCOVA)时,I 型将产生不正确的结果。对于回归(当使用 lm()函数时),R 默认使用类型 III(“三”)平方和。

在上面的例子中,所有的 ANOVAs 都是错误的,只有 lm()函数产生了正确的结果虽然我不会解释不同类型平方和之间的区别,但可以说你应该几乎总是使用第三类平方和。如果你想了解更多关于不同类型平方和的信息,请查看安迪·菲尔德的书《使用 R 发现统计学》中的这一页

因此,如果我们运行一个具有多个自变量的 ANOVA(技术上是 ANCOVA),我们需要覆盖 R 的默认设置,并告诉它必须使用类型 III 平方和。

由于 aov()函数不允许我们修改平方和的类型,我们需要使用另一个不同包中的 ANOVA 函数来指定这一点。我们将使用赛车套件。运行下面的命令来安装 car 包,如果你还没有安装的话。

install.packages("car")

然后加载包。

library(car)

然后,在我们的原始 ANOVA 对象(aov1.1)上运行 car Anova 命令,指定我们希望使用 III 类误差。

Anova(aov1.1, type=”III”)

现在查看结果,您可以看到它们与回归输出一致。

我以前从未注意到的过度拟合的一个潜在原因

原文:https://towardsdatascience.com/one-potential-cause-of-overfitting-that-i-never-noticed-before-a57904c8c89d?source=collection_archive---------31-----------------------

机器学习

当训练数据中的性能比测试数据中的性能好得多时,就会发生过度拟合。机器学习包中的默认超参数可能会让你陷入过度拟合的问题。

乔·塞拉斯Unsplash 上的照片

“为什么我调好的模型还是过拟合?”

"你使用交叉验证了吗?"

“当然可以。”

"你用的是什么模型,你调的超参数是什么?"

"随机森林回归器和我调整了每棵树的树数和最大特征数."

“我需要检查你的代码。”

这是我和妻子在做一个迷你项目时的对话。

老实说,根据她的描述,我想不出程序中有什么错误。然而,在我一行一行地检查她的代码后,我发现了导致过度拟合的问题,这是我以前从未想到过的。

我们一起来解剖一下她的代码。

这是在训练数据集中调整模型的代码块,也是问题发生的

*def train_pipeline_rf(X,y):
    # X are factors
    # y is output
    # impute missing X by median
    X_prepared = pre_pipeline.fit_transform(X)
    # set cross-validation
    tscv = TimeSeriesSplit(n_splits=10)
    data_split = tscv.split(X_prepared)
    # hyper-parameter space
    param_grid_RF = {
        'n_estimators' : [10,20,50,100,200,500,1000],
        'max_features' : [0.6,0.8,"auto","sqrt"]
    }
    # build random forest model
    rf_model = RandomForestRegressor(random_state=42,n_jobs=-1)
    # gridsearch for the best hyper-parameter
    gs_rf = GridSearchCV(rf_model, param_grid=param_grid_RF, cv=data_split, scoring='neg_mean_squared_error', n_jobs=-1)
    # fit dataset
    gs_rf.fit(X_prepared, y)
    return gs_rf*

预处理

代码中的 pre_pipeline 是用于缺失值插补和特征缩放的流水线,两者都是数据预处理中必不可少的步骤。它看起来是这样的:

*pre_pipeline = Pipeline([
        ('imputer', SimpleImputer(strategy="median")),
        ('std_scaler', StandardScaler()),
    ])*

她在这里使用的 估算器 是用列中值替换 NA 值,而 定标器 是标准定标器,它将列归一化为:

z = (x — u) / s

其中 u 为均值, s 为列[1]的标准差。也可以使用sk learn包中的其他一些 估算器缩放器 。但这部分与过拟合问题无关。

在交叉验证中设置数据拆分

 *# set cross-validation
    tscv = TimeSeriesSplit(n_splits=10)
    data_split = tscv.split(X_prepared)*

这里她使用了一种专门为时序数据设计的方法,***。*****

通常,人们使用 k-fold 交叉验证来随机分割训练数据,或者使用分层 k-fold 交叉验证来保留每个类别的样本百分比[2]。但是这两种方法不适合时间序列数据,因为它们没有保持数据点的原始顺序。

这一步非常标准,与过度拟合问题无关。

超参数空间和定义模型

 **# hyper-parameter space
    param_grid_RF = {
        'n_estimators' : [10,20,50,100,200,500,1000],
        'max_features' : [0.6,0.8,"auto","sqrt"]
    }
    # build random forest model
    rf_model = RandomForestRegressor(random_state=42,n_jobs=-1)**

关于超参数调优,要给出一组候选,通常在sk learn包中定义为字典格式。超参数的名称是从模型中建立的,例如,我妻子的代码中的【RandomForestRegressor】

所谓的“tuning-hyperparameter”步骤是在交叉验证过程中,从你给定的候选项中选择出优于其他超参数组合的最佳超参数组合。

这是导致过度拟合问题的零件。

解决过拟合问题。

如果参考 sklearn 中随机森林回归器的手册页,可以看到函数RandomForestRegressor(此处未列出,有兴趣请参考网页)

然而,在上面的代码中,在调优过程中,只有 n_estimatorsmax_features 被传递给函数,这导致所有其他参数都采用默认的值。****

函数中有一个参数叫做 max_depth ,是你的随机森林模型中树的最大深度。它的缺省值是“无”,这意味着决策树将深入到每个叶子是纯的或者所有叶子最多有 m 个样本的深度,其中 m 由 min_samples_split(缺省值= 2) 定义。

该设置显著增加了训练模型的复杂性。并且基于 偏倚和方差 之间的权衡,在上面的代码中训练的模型具有低偏倚和高方差。当然最后导致了过拟合问题。

我通过添加 max_depth 到超参数空间解决了这个问题。

 **# hyper-parameter space
    param_grid_RF = {
        'n_estimators' : [10,20,50,100,200,500,1000],
        'max_features' : [0.6,0.8,"auto","sqrt"],
        'max_depth' : [4,5,6]
    }**

其实RandomForestRegressor中还有一些其他参数可以影响模型的复杂度,但不建议全部放入超参数空间。

上面代码中额外的超参数已经将计算成本增加了三倍。因此,仅仅调整更多参数而成倍增加运行时间是不值得的。****

相反,您可以像这样在模型初始化中设置它们中的一些。

**# hyper-parameter space
    param_grid_RF = {
        'n_estimators' : [10,20,50,100,200,500,1000]
    }
# build random forest model
    rf_model = RandomForestRegressor(random_state=42,n_jobs=-1,max_features=0.6,max_depth=5)**

在上面的代码中,唯一调整过的超参数是max _ features、 以及 max_depth、 在训练过程中是固定的。调谐的或固定的参数不必如此。

已经 对一些超参数的选择有所了解时,设置的基本原理是减少计算成本。

是的,我妻子的问题已经解决了。然而,老实说,我不可能找到它,直到我检查了软件包中所有的默认参数。这就是为什么我想与你分享这个经验,以便你可以在你的机器学习模型训练过程中更加小心默认参数。

过拟合是数据科学中最常见的问题之一,主要来源于模型的 高复杂度 和数据点的缺失。**

为了避免它,最好完全控制你使用的软件包。

希望这条建议能帮到你。

Joshua Sortino 在 Unsplash 上拍摄的照片

参考资料:

  1. https://sci kit-learn . org/stable/modules/generated/sk learn . preprocessing . standard scaler . html # sk learn . preprocessing . standard scaler
  2. https://sci kit-learn . org/stable/modules/generated/sk learn . model _ selection。StratifiedKFold.html
  3. https://en.wikipedia.org/wiki/Random_forest

更正:

我要感谢 Antonio Carlos 在我最初的帖子中指出了这个问题。他还建议了一个不错的帖子“用管道预处理数据,以防止交叉验证过程中的数据泄漏”到题。我真的很感激。

它与 预处理 部分的流水线有关。它不应该在整个训练数据集上进行,而应该在交叉验证步骤的每次迭代中进行,因为训练数据的整体归一化将导致 CV 步骤中训练和验证数据集之间的泄漏。

因此,我将相应的修正代码放在下面:

**def train_pipeline_rf(X,y):
    # X are factors
    # y is output
    # set cross-validation
    tscv = TimeSeriesSplit(n_splits=10)
    data_split = tscv.split(X)

    # build a pipeline of pre-processing and random forest model
    my_pipe = Pipeline([
        ('imputer', SimpleImputer(strategy="median")), 
        ('std_scaler', StandardScaler()),
        ('rf_model', RandomForestRegressor(random_state=42,n_jobs=-1))
    ]) # hyper-parameter space
    param_grid_RF = {
        'rf_model__n_estimators' : [10,20,50,100,200,500,1000],
        'rf_model__max_features' : [0.6,0.8,"auto","sqrt"],
        'rf_model__max_depth' : [4,5,6]
    }
    # gridsearch for the best hyper-parameter within the pipeline.
    gs_rf = GridSearchCV(my_pipe, param_grid=param_grid_RF, cv=data_split, scoring='neg_mean_squared_error', n_jobs=-1)
    # fit dataset
    gs_rf.fit(X, y)
    return gs_rf**

一次比例和拟合优度检验(在 R 和手工中)

原文:https://towardsdatascience.com/one-proportion-and-goodness-of-fit-test-in-r-and-by-hand-8c7997013c84?source=collection_archive---------55-----------------------

了解如何执行单一比例和拟合优度测试,这对于检查分布是否遵循特定的已知分布非常有用

照片由罗曼·马格拍摄

介绍

在之前的一篇文章中,我介绍了 R 中独立性的卡方检验,它用于检验两个分类变量之间的独立性。在本文中,我展示了如何执行,首先在 R 中,然后手动执行:

  1. 一比例检验(也称为单样本比例检验)
  2. 卡方拟合优度检验

当定性变量只有两个类别时,第一个测试用于比较观察比例和预期比例。第二个测试用于比较多个观察比例和多个预期比例,在这种情况下,定性变量有两个或更多类别

这两种检验都允许检验定性变量水平之间的比例是否相等,或者检验给定比例是否相等。这些给定的比例可以任意确定或基于已知分布的理论概率。

在 R 中

数据

在本节中,我们使用与关于描述性统计的文章中相同的数据集。这是众所周知的iris数据集,我们向其中添加了变量size。如果花瓣的长度小于所有花的中值,变量size对应small,否则对应big:

# load iris dataset
dat <- iris# create size variable
dat$size <- ifelse(dat$Sepal.Length < median(dat$Sepal.Length),
  "small", "big"
)# show first 5 observations
head(dat, n = 5)##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  size
## 1          5.1         3.5          1.4         0.2  setosa small
## 2          4.9         3.0          1.4         0.2  setosa small
## 3          4.7         3.2          1.3         0.2  setosa small
## 4          4.6         3.1          1.5         0.2  setosa small
## 5          5.0         3.6          1.4         0.2  setosa small

一比例检验

对于这个例子,我们有一个 150 朵花的样本,我们想测试小花的比例是否与大花的比例相同(通过变量size测量)。以下是按大小排列的花朵数量,以及相应的比例:

# barplot
library(ggplot2)
ggplot(dat) +
  aes(x = size) +
  geom_bar(fill = "#0c4c8a") +
  theme_minimal()

# counts by size
table(dat$size)## 
##   big small 
##    77    73# proportions by size, rounded to 2 decimals
round(prop.table(table(dat$size)), 2)## 
##   big small 
##  0.51  0.49

在构成我们样本的 150 朵花中,51%和 49%分别是大的和小的。为了测试两种尺寸的比例是否相同,我们使用接受以下参数的prop.test()函数:

  • 成功次数
  • 观察/试验次数
  • 预期概率(我们要测试的概率)

(任意地)考虑到big是成功的,我们有: 1

# one-proportion test
test <- prop.test(
  x = 77, # number of successes
  n = 150, # total number of trials (77 + 73)
  p = 0.5
) # we test for equal proportion so prob = 0.5 in each grouptest## 
##  1-sample proportions test with continuity correction
## 
## data:  77 out of 150, null probability 0.5
## X-squared = 0.06, df = 1, p-value = 0.8065
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4307558 0.5952176
## sample estimates:
##         p 
## 0.5133333

我们通过零概率(0.5)、检验统计量(X-squared = 0.06)、自由度(df = 1)、p-值(p-value = 0.8065)、替代假设(true p is not equal to 0.5)、95%置信区间(也可以用test$conf.int提取)和样本中的比例(0.5133333)获得一个输出。

p 值为 0.806,因此,在 5%的显著性水平上,我们不拒绝小花朵和大花朵的比例相同的无效假设。

prop.test()binom.test()的假设

注意prop.test()使用二项式分布的正态近似值。所以这个测试的一个假设是样本量足够大(通常是, n > 30 )。如果样本量较小,建议使用精确二项式检验。

可以使用binom.test()函数执行精确的二项式测试,并接受与prop.test()函数相同的参数。对于本例,假设我们有一个 12 朵大花和 3 朵小花的样本,我们想测试两种花的比例是否相同:

# barplot
barplot(c(12, 3), # observed counts
  names.arg = c("big", "small"), # rename labels
  ylab = "Frequency", # y-axis label
  xlab = "Size" # x-axis label
)
abline(
  h = 15 / 2, # expected counts in each level
  lty = 2 # dashed line
)

# exact binomial test
test <- binom.test(
  x = 12, # counts of successes
  n = 15, # total counts (12 + 3)
  p = 0.5 # expected proportion
)test## 
##  Exact binomial test
## 
## data:  12 and 15
## number of successes = 12, number of trials = 15, p-value = 0.03516
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
##  0.5191089 0.9566880
## sample estimates:
## probability of success 
##                    0.8

p 值为 0.035,因此,在 5%的显著性水平上,我们拒绝零假设,我们得出结论,小花和大花的比例显著不同。这相当于断定大花的比例与 0.5 显著不同(因为只有两种大小)。

如果要测试大花比例大于 50%,在binom.test()函数中加入alternative = "greater"自变量: 2

test <- binom.test(
  x = 12, # counts of successes
  n = 15, # total counts (12 + 3)
  p = 0.5, # expected proportion
  alternative = "greater" # test that prop of big flowers is > 0.5
)test## 
##  Exact binomial test
## 
## data:  12 and 15
## number of successes = 12, number of trials = 15, p-value = 0.01758
## alternative hypothesis: true probability of success is greater than 0.5
## 95 percent confidence interval:
##  0.5602156 1.0000000
## sample estimates:
## probability of success 
##                    0.8

p 值为 0.018,因此,在 5%的显著性水平上,我们拒绝零假设,我们得出结论,大花的比例明显大于 50%。

卡方拟合优度检验

现在假设定性变量有两个以上的级别,如变量Species的情况:

# barplot
ggplot(dat) +
  aes(x = Species) +
  geom_bar(fill = "#0c4c8a") +
  theme_minimal()

# counts by Species
table(dat$Species)## 
##     setosa versicolor  virginica 
##         50         50         50

变量Species有 3 个级别,每个级别有 50 个观察值。假设在这个例子中,我们想测试这三个物种是否同样常见。如果它们同样普遍,那么它们将平均分布,每个物种的预期比例将是 1/3。

这个测试可以用chisq.test()函数完成,接受以下参数:

  • 代表观察到的比例的数字向量
  • 代表预期比例的概率向量(与观察到的比例长度相同)

适用于我们的研究问题(即,这三个物种是否同样常见?),我们有:

# goodness of fit test
test <- chisq.test(table(dat$Species), # observed proportions
  p = c(1 / 3, 1 / 3, 1 / 3) # expected proportions
)test## 
##  Chi-squared test for given probabilities
## 
## data:  table(dat$Species)
## X-squared = 0, df = 2, p-value = 1

p-值为 1,因此,在 5%的显著性水平上,我们不拒绝所有物种之间比例相等的无效假设。

即使在进行统计测试之前,这也是非常明显的,因为每个物种正好有 50 朵花,所以很容易看出这些物种是同样常见的。然而,我们仍然进行了测试,以显示它在实践中是如何工作的。

我的分布是否遵循给定的分布?

在上一节中,我们自己选择了比例。拟合优度测试对于将观察到的比例与基于某种已知分布的预期比例进行比较也特别有用。

记住测试的假设:

  • H0:观察到的频率和预期的频率之间没有显著的差异
  • H1:观察到的频率和预期的频率有很大的差异

对于这个例子,假设我们测量了 100 个有 5 个孩子的家庭中女孩的数量。我们想测试(观察到的)数字女孩的分布是否遵循二项分布。

观察到的频率

在我们的 100 个有 5 个孩子的家庭样本中,每个家庭的女孩数量分布如下:

以及相应的频率和相对频率(记住相对频率是频率除以总样本量):

# counts
dat##   Girls Frequency Relative_freq
## 1     0         5          0.05
## 2     1        12          0.12
## 3     2        28          0.28
## 4     3        33          0.33
## 5     4        17          0.17
## 6     5         5          0.05

预期频率

为了将观察到的频率与二项式分布进行比较,并查看两种分布是否匹配,我们首先需要确定在二项式分布的情况下将获得的预期频率。假设生女孩的概率为 0.5(5 个孩子中的每一个),预期频率如下:

# create expected frequencies for a binomial distribution
x <- 0:5
df <- data.frame(
  Girls = factor(x),
  Expected_relative_freq = dbinom(x, size = 5, prob = 0.5)
)
df$Expected_freq <- df$Expected_relative_freq * 100 # *100 since there are 100 families# create barplot
p <- ggplot(df, aes(x = Girls, y = Expected_freq)) +
  geom_bar(stat = "identity", fill = "#F8766D") +
  xlab("Number of girls per family") +
  ylab("Expected frequency") +
  labs(title = "Binomial distribution Bi(x, n = 5, p = 0.5)") +
  theme_minimal()
p

# expected relative frequencies and (absolute) frequencies
df##   Girls Expected_relative_freq Expected_freq
## 1     0                0.03125         3.125
## 2     1                0.15625        15.625
## 3     2                0.31250        31.250
## 4     3                0.31250        31.250
## 5     4                0.15625        15.625
## 6     5                0.03125         3.125

观察频率与预期频率

现在,我们将观察到的频率与预期的频率进行比较,看两者是否有显著差异。如果两者相差很大,我们就不接受每个有 5 个孩子的家庭的女孩数量服从二项式分布的假设。另一方面,如果观察到的和预期的频率相似,我们不拒绝每个家庭的女孩数量遵循二项分布的假设。

视觉上我们有:

# create data
data <- data.frame(
  num_girls = factor(rep(c(0:5), times = 2)),
  Freq = c(dat$Freq, df$Expected_freq),
  obs_exp = c(rep("observed", 6), rep("expected", 6))
)# create plot
ggplot() +
  geom_bar(
    data = data, aes(
      x = num_girls, y = Freq,
      fill = obs_exp
    ),
    position = "dodge", # bar next to each other
    stat = "identity"
  ) +
  ylab("Frequency") +
  xlab("Number of girls per family") +
  theme_minimal() +
  theme(legend.title = element_blank()) # remove legend title

我们看到观察到的和预期的频率非常相似,所以我们预计有 5 个孩子的家庭中女孩的数量遵循二项分布。然而,只有拟合优度测试会证实我们的信念:

# goodness of fit test
test <- chisq.test(dat$Freq, # observed frequencies
  p = df$Expected_relative_freq # expected proportions
)test## 
##  Chi-squared test for given probabilities
## 
## data:  dat$Freq
## X-squared = 3.648, df = 5, p-value = 0.6011

p-值为 0.601,因此,在 5%的显著性水平上,我们不拒绝观测频率和预期频率相等的无效假设。这相当于得出结论,我们不能拒绝五个孩子的家庭中的女孩数量遵循二项分布的假设(因为预期频率是基于二项分布的)。

请注意,拟合优度测试当然可以用二项式分布以外的其他分布类型来执行。例如,如果您想要测试观察到的分布是否遵循泊松分布,此测试可用于将观察到的频率与泊松分布情况下获得的预期比例进行比较。

用手

既然我们已经展示了如何在 R 中执行一次比例和拟合优度测试,那么在本节中我们将展示如何手工执行这些测试。我们首先说明一比例检验,然后是卡方拟合优度检验。

一比例检验

对于这个例子,假设我们投掷一枚硬币 100 次,注意到它有 67 次正面朝上。接下来,我们要测试硬币是否公平,即测试正面或反面落地的概率是否等于 50%。

对于许多假设检验,我们通过 4 个简单的步骤来完成:

  1. 陈述无效假设和替代假设
  2. 计算检验统计量(也称为 t-stat)
  3. 找到拒绝区域
  4. 通过比较检验统计量和拒绝区域得出结论

第一步。

在我们的例子中,无效假设和替代假设是:

  • H0: p0 = 0.5
  • H1: p0 ≠ 0.5

其中 p0 是头部着地的预期比例。

第二步。

测试统计为: 3

(如果你在计算检验统计量时需要更多帮助,请参阅如何在一个闪亮的应用程序中执行假设检验。)

第三步。

通过正态分布表找到拒绝区域。假设显著性水平α = 0.05,我们有:

z(α/2) = z(0.025) = 1.96

第四步。

我们将测试统计(在步骤 2 中找到)与拒绝区域(在步骤 3 中找到)进行比较,并得出结论。视觉上,我们有:

测试统计位于拒绝区域内(即灰色阴影区域)。因此,在 5%的显著性水平上,我们拒绝零假设,我们得出结论,头部(以及尾部)的比例显著不同于 50%。换句话说,仍然在 5%的显著性水平,我们得出结论,硬币是不公平的。

如果您更喜欢计算p-值,而不是比较 t-stat 和拒绝区域,您可以使用这个闪亮的应用程序来轻松计算不同概率分布的p-值。打开应用程序后,设置 t-stat,相应的选项,你会在页面顶部找到p-值。

R 中的验证

为了便于说明,下面是上面例子在 R 中的验证:

# one-proportion test
test <- prop.test(
  x = 67, # number of heads
  n = 100, # number of trials
  p = 0.5 # expected probability of heads
)test## 
##  1-sample proportions test with continuity correction
## 
## data:  67 out of 100, null probability 0.5
## X-squared = 10.89, df = 1, p-value = 0.0009668
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5679099 0.7588442
## sample estimates:
##    p 
## 0.67

p-值为 0.001,因此,在 5%的显著性水平上,我们拒绝正面和反面比例相等的无效假设,我们得出结论,硬币是有偏差的。这和手动发现的结论是一样的。

拟合优度检验

我们现在用下面的例子来手工说明拟合优度测试。

假设我们掷骰子 100 次,我们记下它落在每个面上的次数(1 到 6),然后测试骰子是否公平。以下是观察到的骰子点数:

## dice_face
##  1  2  3  4  5  6 
## 15 24 10 19 19 13

对于一个公平的骰子,我们会期望它在每个面上降落 100/6 ≈ 16.67 次(这个期望值在上图中用虚线表示)。尽管观察到的频率不同于预期值 16.67:

##   dice_face observed_freq expected_freq
## 1         1            15         16.67
## 2         2            24         16.67
## 3         3            10         16.67
## 4         4            19         16.67
## 5         5            19         16.67
## 6         6            13         16.67

我们需要测试它们是否有显著的不同。为此,我们按照上面提到的 4 个简单步骤进行适当的假设检验:

  1. 陈述无效假设和替代假设
  2. 计算检验统计量(也称为 t-stat)
  3. 找到拒绝区域
  4. 通过比较检验统计量和拒绝区域得出结论

第一步。

拟合优度检验的无效假设和替代假设是:

  • H0:观察到的频率和预期的频率之间没有显著的差异
  • H1:观察到的频率和预期的频率有很大的差异

第二步。

测试统计数据为:

其中 Oi 是观察到的频率,Ei 是预期的频率,k 是类别的数量(在我们的例子中,有 6 个类别,代表 6 个骰子面)。

这种χ2 统计量是通过计算每个类别中观察到的病例数和预期病例数之间的差异获得的。该差值被平方(以避免正负差值被补偿)并除以该类别中的预期病例数。然后将所有类别的这些值相加,总和被称为χ2 统计量。该检验统计量的大值导致无效假设被拒绝,小值意味着无效假设不能被拒绝。 4

根据我们的数据,我们有:

第三步。

χ2 检验统计量是小还是大取决于拒绝区域。通过χ2 分布表找到拒绝区域。自由度等于 k1(其中 k 为类别数),假设显著性水平α = 0.05,则我们得到:

χ2(α;k1)=χ2(0.05;5) = 11.0705

第四步。

我们将测试统计(在步骤 2 中找到)与拒绝区域(在步骤 3 中找到)进行比较,并得出结论。视觉上,我们有:

测试统计不在拒绝区域内(即灰色阴影区域)。因此,在 5%的显著性水平,我们不拒绝零假设,即观察到的频率和预期的频率之间没有显著差异。换句话说,仍然在 5%的显著性水平上,我们不能拒绝骰子是公平的假设。

同样,您可以使用闪亮的应用程序轻松计算给定测试统计的p-值,如果您更喜欢这种方法而不是 t-stat 和拒绝区域之间的比较。

R 中的验证

为了便于说明,下面是上面例子在 R 中的验证:

# goodness of fit test
test <- chisq.test(dat$observed_freq, # observed frequencies for each dice face
  p = rep(1 / 6, 6) # expected probabilities for each dice face
)test## 
##  Chi-squared test for given probabilities
## 
## data:  dat$observed_freq
## X-squared = 7.52, df = 5, p-value = 0.1847

测试统计和自由度与手动发现的完全相同。p-值为 0.185,仍处于 5%的显著性水平,得出的结论与手动得出的结论相同(即未能拒绝零假设)。

感谢阅读。我希望这篇文章能帮助你理解并手工执行一比例和拟合优度检验。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

  1. 选择大或小作为成功事件给出了完全相同的结论。
  2. 同样,这个自变量也可以加入到prop.test()函数中,检验观察比例是否大于预期比例。如果您想测试观察到的比例是否小于预期的比例,请使用alternative = "less"
  3. 这个测试的一个假设是 n⋅p≥5 和 n⋅(1−p)≥5.假设得到满足,因此我们可以使用二项分布的正态近似。
  4. 来源:http://uregina.ca/~gingrich/ch10.pdf

相关文章

原载于 2020 年 5 月 13 日 https://statsandr.com**的

ML 的一小步…

原文:https://towardsdatascience.com/one-small-step-for-ml-b5f4fca7cb4b?source=collection_archive---------45-----------------------

ML 能帮助我们发现飞船的新材料吗?

我通过总结激动人心的新研究论文来探索人工智能对传统科学的影响。在这篇文章中,我正在讨论另一篇很酷的新论文:“多性能优化的γ′强化钴基高温合金的机器学习辅助设计”()npj computu。脱线。,6,62,2020 )。

1|我们如何发现新材料?

想象一下,你是一名航空工程师,正试图为火箭设计一个新的发动机。你想用什么材料?为了经受住像巨型火箭发动机那样恶劣的条件,材料必须具有非常特殊的性质;一个真正高熔点,低密度和化学稳定性,仅举几例。当你进入细节时,几乎没有任何已知的材料实际上足够好,这就是为什么我们真的需要开发新的材料。

SpaceX 猎鹰重型发射,航空航天工程的惊人范例。图片来自Unspalsh.com

合金真的很有趣;它们是多种不同金属的原子混合在一起的材料。改变所用的金属及其在成分中的比例可以改变合金的物理和化学性质。超级合金是一种合金,即使在接近其熔点的高温下(想想 1000 C 以上)也具有难以置信的强度!).它们是这些航空航天应用的绝佳候选材料,但开发最佳高温合金实际上非常困难。

你如何为你的合金选择最好的金属;铝、钴、钛、铁、铬、钼或钨……有这么多可供选择!更复杂的是,提高合金一种性能的元素会破坏另一种性能。这种同时进行多种性能优化的平衡行为使得新合金的开发如此具有挑战性和趣味性。这就像一个拼图游戏,其中的碎片一直在移动。传统上,这是通过实验室研究的常规“试错法”来完成的——尝试制造一些全新的东西,然后测试它的性能,看看它有多好。这种标准的研究方法是如此的低效和昂贵;这可能需要几个月的时间(或者如果你不走运,甚至几年!)在你甚至不确定新材料是否具有你真正想要的特性时,找出制造新材料的方法。对新材料的测试既昂贵又耗时,而且毕竟你可能不得不重新开始整个过程,因为你制作的材料并不像你希望的那样。一定有更好的办法!

实验性的实验室工作,既昂贵又危险,而且耗时。图片来自Unsplash.com

2|也许机器学习能有所帮助?

如果我们不必浪费时间在试错上呢?如果我们可以使用 ML 来预测元素的组合,从一开始就给出最佳的超级合金,会怎么样?这种加速的研究方法可能会彻底改变材料科学,推动科学发现以前所未有的速度向前发展。这是刘培和他的同事在他们最近的论文“多性能优化的γ′强化钴基高温合金的机器学习辅助设计”中探索的想法。他们想有效地开发一种新的钴基高温合金,该合金具有用于航空航天应用的优化性能。让我们来看看他们做了什么!

3|理想的高温合金应该是什么样的?

基于以前的超级合金,选择钴、铝、钨、镍、钛、钽和铬的化学混合物,其中合金中每种元素的百分比是要改变的变量。由于对每种元素的最小值和最大值有一些限制,总共有 210,792 种可能的高温合金可供选择。你可以明白为什么没有 ML 会很难!

α-铁金属结构的结构,这是用于制造新型高温合金的元素之一。图片来自Unsplash.com

作者有很多物理性质,他们希望他们的最佳高温合金满足,并通过计算从如此多的选择中识别它,他们首先必须设置数值目标。首先要知道的是合金可以有不同的相。相位是相同原子的不同排列。这些排列可以导致同一合金的不同相具有不同的性质,即不同的熔化温度、不同的强度等。这使得事情更加复杂;除了元素原子的排列方式,你还必须控制合金中的元素。

合金材料的一个样品可以具有彼此相邻的不同相的区域,并且这些相的相对量影响材料的整体性能。γ和γ′是指合金的两种不同相,其中γ′是较强的相。作者希望这种强相构成他们优化材料的大部分(60%)。

γ′固溶线温度非常重要——这听起来很复杂,但实际上是强γ′转化为弱γ的温度。由于作者想要避免这种转变,他们正在寻找具有真正高固溶线温度的材料——超过 1250 C!

他们还希望各相之间有较宽的温度窗口(以使加工更容易),耐化学反应(氧化)和低密度材料(≤ 8.7 克/厘米 3)——好的合金必须很轻,这样才不会加重飞机的重量。

4|用 ML 加速研究

显然,要从 210,792 种候选合金中正确地找到具有所有这些特性的材料需要做大量的工作。为了帮助应对这一挑战,这个过程被分成几个阶段。

一.顺序滤波器

首先,一系列的过滤器被应用到选择中,尽可能快速地删除不可行的选项。作者运用自己的文献知识删减了不合理的合金成分。然后,他们使用热力学数据库来计算预测合金的相,并确定有希望的γ和γ’混合物的候选物。

他们还将不同的回归模型应用于已知合金的物理属性,以预测新材料的密度和相变温度。尝试了六种不同的模型(支持向量机Ada BoostKNN决策树随机森林梯度树提升(点击每一个查看背景),但是梯度树提升给出了最好的结果!下图显示了已知合金的真实密度与回归模型预测的密度之间的相关性。仅仅使用这些简单的回归技术就能准确预测复杂合金材料的实验性能,这真是令人惊讶。这允许不太可能满足目标的候选材料被拒绝。尽管经过如此广泛的筛选,他们仍然有 6000 多份候选材料!

显示真实γ′固溶线温度和梯度树推进回归模型预测值之间相关性的图表。在知识共享许可下,经原始论文许可复制。

二世。高效全局优化算法(EGO)

接下来,他们使用一个 EGO 来寻找具有最佳γ′固溶线温度的合金,因为这是最重要的属性。优化问题可能需要计算非常复杂的函数,这非常慢并且计算量很大。基于元模型的优化算法真的可以帮助解决这个问题,EGOs 是最受欢迎的。他们的工作方式是仅从点的样本中创建代理模型,然后逼近函数。这用于通过计算预期改善(EI)来自适应地采样新点,并通过添加具有最高 EI 的点来更新模型。重复这一过程,直到达到比传统优化技术更有效的最优值。

这是非常酷的,因为即使这些简单和众所周知的 ML 技术也可以在这个领域得到一些非常好的结果!

三。实验验证和反馈

EGO 仅用于推荐四种具有高γ′固溶线的合金,然后对其进行实验制造和测试,以了解它们的实际物理性质。然后将这些结果反馈到数据集中,并再次重复该过程,直到在实验中找到与他们期望的目标相匹配的材料。

图片显示了用于识别新型高温合金的研究途径。在知识共享许可下,经原文许可复制。

4|结果

这听起来工作量很大,但迭代过程只需重复三次,就能找到一些真正令人兴奋的高温合金。这意味着从 210,792 种未知合金中,使用 ML 技术可以同时优化多种性能,因此只需制造 12 种材料。与正常的实验工作相比,这种效率令人难以置信,而且确实减少了昂贵的实验时间!

他们发现的性能最好的合金是钴-镍(36%)-铝(12%)-钛(2%)-钽(4%)-钨(1%)-铬(2%)。这种材料真的很棒,其成分中高达 74.5%是强合金相(他们的目标是至少 60%),固溶线温度高达 1267 C。这一结果甚至超过了一些基准合金。考虑到它的重量也很轻,密度只有 8.68 克/立方厘米,这是一个全面的超级合金。

STEM 研究了这种最好的材料(在上周的论文中讨论过!)显示不同金属原子在合金中的位置。如果你看下面的图片,你甚至可以看到不同的合金相(正方形区域是γ′相,中间的位是γ),不同的合金成分分布在各处。

优化高温合金的 STEM 图像。左上是主干图像,其余的彩色图像显示了不同元素的分布。根据知识共享许可,经原创论文许可改编。

5|对结果的一些想法

  1. 虽然这项研究的结果很有希望,但合金的稳定性(抗氧化性)还可以更好一些。由于 EGO/experimental 循环仅执行了 3 次迭代,因此有可能通过更多次迭代来改进。
  2. 在我们知道这种材料是否适用于工业用途之前,还需要测试其他物理特性,但这仍然是一个很好的开始。

总的来说,这篇论文是 ML 加速传统科学研究能力的一个很好的例子,如果你想了解更多细节,我鼓励你完整阅读这篇论文。但这还不止于此……这种 ML/实验相结合的方法正被用于加速许多领域的研究,如新药开发识别新超导体。随着人工智能的不断进步,它的潜力在传统科学中得到认可,我确信我们将会从这种交叉中看到更多令人兴奋的结果。

离 Neuralink 更近一步?通过互联网成功连接生物和人工神经元

原文:https://towardsdatascience.com/one-step-closer-to-neuralink-95af55a0d852?source=collection_archive---------39-----------------------

约书亚·索蒂诺在 Unsplash 上拍摄的照片

南安普顿大学(University of Southampton)本周发表的一项研究表明,培养自大鼠的生物神经元可以通过物理突触样元件将信息传递给人工神经元,反之亦然。研究的所有三个要素;人工神经元、生物神经元和突触组件位于世界各地的不同位置,通过网络连接在一起。

近年来,世界各地都在努力推进神经电子连接技术,这将在我们的大脑和互联网之间建立联系。这种系统可能会让我们的大脑与数据实时互动,就像我们与自己的知识、思想和记忆互动一样。

埃隆·马斯克的公司 Neuralink 投入巨资开发了这一概念,提出在大脑中植入一个微型设备,将我们直接连接到互联网。

生物

在自然界中,大脑通过一个巨大的神经元网络发挥作用,这些神经元通过电信号向其他神经元发送信息,这些电信号分别被称为“动作电位”。这种信号在神经元之间传递的空间被称为突触。

神经元只能向一个方向发送信息。一个信号将通过一个神经元,到达它的输出端。信息穿过突触,刺激其接收端的下一个神经元,以此类推。

图改编自可汗学院和原始研究论文(塞尔维亚,a .,索蕾娜,a .,乔治,R. 忆阻突触连接大脑和硅尖峰神经元。 Sci Rep 10, 2590 (2020)。https://doi.org/10.1038/s41598-020-58831-9

这项研究由三个相互作用的部分组成。苏黎世大学和苏黎世联邦理工学院培养了老鼠的生物神经元,并将其组织到电极阵列上。通过完善的实验室技术,可以发送来自这些神经元的电信号,并接收捕获的信号。

人造神经元是由意大利帕多瓦大学开发的,并被安装在硅微芯片上。很像生物神经元,它们能够发送和接收可以读取和测量的信号。

Brian Kostiuk 在 Unsplash 上拍摄的照片

在南安普顿大学,科学家们使用忆阻器(一种能够传递电荷的微小电路元件)来创建物理设备,这些设备可以将信息从生物神经元传输到人工神经元,反之亦然。由此产生的人工突触被称为 突触

由于神经元之间输入和输出的差异,创建了两个独立的突触来完成电路,一个代表脑-硅,一个代表硅-脑

两个突触器中使用的尖端纳米技术的细微差异导致了单向电路。从这个意义上来说,该系统模仿大脑,信息只能以一个方向通过各自的系统。

该团队能够利用互联网成功地将电子信号传递到研究的所有部分。这是第一次人工和生物成分在不同的地方以这种方式联系在一起。

这些结果在神经界面研究领域意义重大,很可能会影响许多其他领域的研究。这项工作背后的科学家指出,他们希望这可能是神经电子学互联网的开始(由科学日报报道)。

原始研究文章可在https://www.nature.com/articles/s41598-020-58831-9找到

注:可汗学院所有内容均可在(www.khanacademy.org)——https://khanacademy . zendesk . com/HC/en-us/articles/202262954-Can-I-use-Khan-Academy-s-videos-name-materials-links-in-my-project-

研究论文获得知识共享署名 4.0 国际许可,该许可允许以任何媒体或格式使用、共享、改编、分发和复制【http://creativecommons.org/licenses/by/4.0/】

LSTM 一步预测法:预测酒店收入

原文:https://towardsdatascience.com/one-step-predictions-with-lstm-forecasting-hotel-revenues-c9ef0d3ef2df?source=collection_archive---------15-----------------------

使用 LSTM 生成单步预测

来源:图片来自 PixabayPexels

注意:这是对我之前的文章 的更新,预测使用 LSTM 的酒店的平均每日价格趋势。此后,我意识到了最初分析中的几个技术错误,并决定写一篇新文章来解决这些问题,并扩展我之前的分析。

背景

在这种情况下,使用 LSTM 模型的目的是预测酒店的平均每日房价。

ADR 计算如下:

ADR = Revenue ÷ sold rooms

在本例中,计算了客户每周的平均 ADR,并将其公式化为时间序列。然后,LSTM 模型用于逐周预测这一指标。

Antonio、Almeida 和 Nunes (2019)的原始研究可在此处找到。

使用熊猫,每周计算平均 ADR。以下是每周 ADR 趋势图。

来源:Jupyter 笔记本输出

注意,本例中的 Jupyter 笔记本可以在本文末尾找到。

数据准备

1.用 MinMaxScaler 归一化数据

与任何神经网络一样,数据需要进行缩放,以便网络进行正确的解释,这一过程称为标准化。最小最大缩放器用于此目的。

然而,这伴随着一个警告。在数据被分成训练集、验证集和测试集之后,必须进行缩放,每个数据集都被单独缩放。第一次使用 LSTM 时的一个常见错误(这是我自己犯的错误)是在分割数据之前先对数据进行归一化。

这是错误的,因为归一化技术将使用来自验证和测试集的数据作为整体缩放数据时的参考点。这将无意中影响训练数据的值,本质上导致验证和测试集的数据泄漏。

在这方面,100 个数据点被分成训练集和验证集,最后 15 个数据点作为测试数据,用于与 LSTM 预测进行比较。

train_size = int(len(df) * 0.8)
val_size = len(df) - train_size
train, val = df[0:train_size,:], df[train_size:len(df),:]

形成数据集矩阵:

def create_dataset(df, previous=1):
    dataX, dataY = [], []
    for i in range(len(df)-previous-1):
        a = df[i:(i+previous), 0]
        dataX.append(a)
        dataY.append(df[i + previous, 0])
    return np.array(dataX), np.array(dataY)

此时,训练数据可以按如下方式缩放:

scaler = MinMaxScaler(feature_range=(0, 1))
train = scaler.fit_transform(train)
train

以下是输出示例:

array([[0.35915778],
       [0.42256282],
       [0.53159902],
...
       [0.0236608 ],
       [0.11987636],
       [0.48651694]])

同样,验证数据也以同样的方式进行缩放:

val = scaler.fit_transform(val)
val

2.定义回顾期

“回顾周期”定义了使用多少个先前的时间步长来预测随后的时间步长。对此,我们采用的是一步预测模型。

在这种情况下,回看周期被设置为 5 。这意味着我们使用 t-4、t-3、t-2、t-1、t 的时间步长来预测时间 t+1 的值。

# Lookback period
lookback = 5
X_train, Y_train = create_dataset(train, lookback)
X_val, Y_val = create_dataset(val, lookback)

注意回望周期的选择是一个相当随意的过程。在这种情况下,显示了 5 的回看窗口,以展示在测试集上的最佳预测性能。然而,另一种选择是使用 PACF 指示的滞后数量来设置回看窗口的大小,如数据科学堆栈交换所述。

让我们来看看 X_train 的归一化窗口。

array([[0.35915778, 0.42256282, 0.53159902, 0.6084246 , 0.63902841],
       [0.42256282, 0.53159902, 0.6084246 , 0.63902841, 0.70858066],
       [0.53159902, 0.6084246 , 0.63902841, 0.70858066, 0.75574219],
...

以下是前三个条目。我们可以看到,紧接在我们试图预测的一个时间步骤之前的五个时间步骤以步进运动的方式移动。

例如,第一个条目在时间 t 显示 0.63902841。在第二个条目中,该值现在向后移动到时间 t-1

让我们举一个适用于这种情况的例子。例如,对于希望预测第 26 周的 ADR 值的酒店,酒店将使用该模型,使用第 21、22、23、24 和 25 周的数据来进行前一周的预测。

现在,输入被整形为【样本、时间步长、特征】格式。

# reshape input to be [samples, time steps, features]
X_train = np.reshape(X_train, (X_train.shape[0], 1, X_train.shape[1]))
X_val = np.reshape(X_val, (X_val.shape[0], 1, X_val.shape[1]))

在这种情况下,输入的形状是【74,1,1】

在训练数据中存在 74 个样本,模型在 1 的时间步长上运行,并且在模型中使用 1 个特征,即时间序列的滞后版本。

LSTM 模型

LSTM 模型定义如下:

# Generate LSTM network
model = tf.keras.Sequential()
model.add(LSTM(4, input_shape=(1, lookback)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
history=model.fit(X_train, Y_train, validation_split=0.2, epochs=100, batch_size=1, verbose=2)

用 4 个神经元创建 LSTM 模型。考虑到我们正在处理一个回归问题,均方误差被用作损失函数。此外,还使用了 adam 优化器,进行了 100 多个时期的训练,验证比例为 20%。

以下是培训和验证损失的直观概述:

# list all data in history
print(history.history.keys())
# summarize history for accuracy
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper left')
plt.show()

我们可以看到,在验证损失的初始增加之后,损失在大约 10 个时期之后开始减少。

现在,预测被转换回原始比例:

# Convert predictions back to normal values
trainpred = scaler.inverse_transform(trainpred)
Y_train = scaler.inverse_transform([Y_train])
valpred = scaler.inverse_transform(valpred)
Y_val = scaler.inverse_transform([Y_val])
predictions = valpred

在训练和验证集上计算均方根误差:

# calculate RMSE
trainScore = math.sqrt(mean_squared_error(Y_train[0], trainpred[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
valScore = math.sqrt(mean_squared_error(Y_val[0], valpred[:,0]))
print('Validation Score: %.2f RMSE' % (valScore))

获得的 RMSE 值如下:

  • 列车误差: 3.88 RMSE
  • 验证错误: 8.78 RMSE

整个验证集的平均 ADR 值为 69.99,相比之下,验证误差非常小(约为平均值的 12%),这表明该模型在预测 ADR 值方面做得很好。

这是一个跨训练和验证集的预测与实际 ADR 值的图表。

# Plot all predictions
inversetransform, =plt.plot(scaler.inverse_transform(df))
trainpred, =plt.plot(scaler.inverse_transform(trainpredPlot))
valpred, =plt.plot(scaler.inverse_transform(valpredPlot))
plt.xlabel('Number of weeks')
plt.ylabel('Cancellations')
plt.title("Predicted vs. Actual Weekly ADR")
plt.show()

来源:Jupyter 笔记本输出

我们可以看到,LSTM 模型通常捕捉时间序列的方向振荡。然而,在 ADR 的极端峰值期间,例如第 60 周,该模型的表现似乎不太好。

但是,为了完全确定模型是否具有预测能力,现在将使用它来预测系列中的最后 15 个时间步长,即测试数据。

Xnew = np.array([tseries.iloc[95:100],tseries.iloc[96:101],tseries.iloc[97:102],tseries.iloc[98:103],tseries.iloc[99:104],tseries.iloc[100:105],tseries.iloc[101:106],tseries.iloc[102:107],tseries.iloc[103:108],tseries.iloc[104:109],tseries.iloc[105:110],tseries.iloc[106:111],tseries.iloc[107:112],tseries.iloc[108:113],tseries.iloc[109:114]])

在这个例子中,Xnew 使用前面的五个时间步长在时间 t+1 进行预测。例如,第 95 至 100 周用于预测第 101 周的 ADR 值,然后第 96 至 101 周用于预测第 102 周,依此类推。

来源:Jupyter 笔记本输出

上图显示了 LSTM 预测值与测试集(系列中的最后 15 个点)中的实际 ADR 值。

获得的 RMSE 和 MAE(平均绝对误差)值如下:

  • 梅: -27.65
  • RMSE: 31.91

测试集的 RMSE 误差明显高于验证集的误差——这是意料之中的,因为我们正在处理看不见的数据。

然而,在测试集上的平均 ADR 值为 160 的情况下,RMSE 误差约为平均值大小的 20%,表明 LSTM 在确定下一时间步的值时仍然具有相当强的预测能力。

理想情况下,人们希望使用大得多的数据样本来验证 LSTM 是否能保持对新数据的预测能力。此外,如这个 Reddit 线程所示,LSTMs 可能会根据数据样本的大小而过度拟合。

在这方面,需要更大的数据样本来验证该模型在现实世界中是否可行。然而,这个案例的初步结果看起来很有希望。

结论

在本例中,您看到了:

  • 如何正确设置数据格式以使用 LSTM 模型
  • 一步 LSTM 预测模型的建立
  • 解释 RMSE 和梅值,以确定模型的准确性

非常感谢您的阅读,非常感谢您的任何反馈或问题。你可以在这里找到这个例子的 Jupyter 笔记本。

此外,我还强烈推荐 Machine Learning Mastery 的本教程,它被用作设计本例中使用的 LSTM 模型的指南。

免责声明:本文是在“原样”的基础上编写的,没有任何担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。作者与本文提及的任何第三方无任何关系。

一年的数据科学博客——值得吗?

原文:https://towardsdatascience.com/one-year-of-data-science-blogging-was-it-worth-it-6022d38b9a02?source=collection_archive---------16-----------------------

你应该试一试吗?

自从我的第一篇文章发表以来,大约一年过去了。我正在写我的第 115 篇文章,但这是第一篇关注数据科学软技能的文章。那么,这一切值得吗?这正是本文旨在揭示的内容。

安德鲁·尼尔Unsplash 上拍照

这里有一个快速总结——是的,写关于数据科学的博客绝对值得。数据科学现在很热门,每天都有新的工具/库发布,所以你永远不会没有东西可写。对于一个新人来说,我认为最有趣的统计数据是收入潜力——所以让我们抛开这个不谈。

以下是我过去一年的平均收入(仅限博客):

  • 每天 66.86 美元(每月 30.42 天)
  • 每周 469.35 美元(每月 4.33 周)
  • 每月$ 2033.70

这么多吗?在美国,可能不会。在我的国家(克罗地亚),这大约是 2 个月的平均工资。所以,是的,对于美国以外的人来说,博客赚钱听起来容易得多,如果我们不考虑说流利外语的困难。

以下是我的一些其他统计数据,你可能会感兴趣:

但这不全是钱的问题。我知道对我来说说起来容易,但是写博客在大多数时候并不是一件确定的事情。在某些月份,我的文章获得了 20 万以上的浏览量,而在其他月份,我很难获得其中的一半。写博客不是普通的朝九晚五,因为不能保证你会赚多少钱。

此外,这种不确定性不会让你在早上 5 点起床,所以金钱本身并不是一个很重要的因素。下面我将列出并解释把写博客作为你的副业的好处和坏处,以及如何开始。

好人👍🏻

让我们先谈谈好的方面——因为好的方面远远超过坏的方面。

正反馈

没有什么比知道你已经帮助别人完成了你的写作(这里是代码)以更简单或更有效的方式解决任务更好的了。当你通过评论区和社交媒体发布好的内容时,收到积极的反馈是经常发生的事情。

我不得不承认,后者发生得更频繁,就我而言,至少每周一次。LinkedIn 上总有人告诉我 X 文章是如何帮助他们解决问题的,在写了 100 多篇文章后,这正是我保持动力水平所需要的。

工作提议

我在很多地方读到过博客是推进你事业的重要工具,我完全同意。原因有很多,让我列举几个:

  1. 正如阿尔伯特·爱因斯坦所说,如果你不能简单地解释事情,你就理解得不够好
  2. 雇主会看到你所知道的和你的总体想法——这让你更容易被雇佣

后一个非常重要,因为它开启了新的机会——也是好的机会——因为如果雇主喜欢你的写作,你很有可能从第一天起就在公司里受到尊重。

如果你已经在数据科学领域工作了一个多月,你就会知道找工作并不容易,因为大多数职位都是高级职位。这就是写博客能给你优势的地方,即使你没有足够的工作经验。

除了常规的工作邀请,时不时还会有兼职的提议——如果你想让写博客成为日常工作,这可能是你更喜欢的事情。

坏事👎🏻

有好事就有坏事,博客也不例外。这些对你的影响有多大取决于你自己,只是要做好准备,不是每个人都会喜欢你要说的话。

语法怪胎

不时会有人在评论区觉得有必要纠正我的语法。

当然,你应该经常检查你的文章的拼写,但是由于我们大多数人都是用外语写作,偶尔的拼写错误是不可避免的。这是非常好的,只要没有太多的一件。

做好准备——总有一个悲伤的人在某个地方无事可做,只是在等待这样的机会。我不知道为什么,好像一个放错位置的字母就让你的文章无法阅读。我已经学会忽略它们,这是你能做的最好的事情。

人们急于下结论

仅仅陈述一次是不够的——关键思想应该在整篇文章中多次重复或重新表述。这在简单的基于教程的数据科学文章中并不常见,但在观点文章中却很常见。

为什么?

好吧,很多次我在引言部分做了大胆的假设,并在后来证明了这些假设。总有人不会读整篇文章,但会跳到评论区,问一些文章中已经回答的问题,就在下面几段。

忽略这些人是一件好事,因为有时他们太多了,无法与之对抗。此外,正如我已经说过的,在整篇文章中多次重复关键思想。

👉🏻如何入门?

如果你决定尝试写博客,那么恭喜你,你做了一个伟大的决定。有许多优秀的平台,但在我看来,中型平台是最好的起点,原因有很多:

  • 它有固定的受众,不需要在广告上花费时间和金钱
  • 它有很棒的出版物——数据科学是数据科学中最好的
  • 书写和编辑感觉很自然——格式化内容的选项有限,这是一件好事,因为整体用户体验是一流的

此外,为大型出版物写作使得策展过程更快(事先阅读策展指南)。我已经开始阅读写给数据科学的文章,检查他们的指导方针,并通过电子邮件提交我的帖子。

我认为为 TDS 写作应该是任何有抱负的数据科学作家的最终目标,因为它是一个拥有大量追随者和每月浏览量的成熟出版物。

如果他们不接受你的文章,不要气馁——同样,检查他们的指导方针,确保你的文章是体面的。你随时可以重新提交。

扩展选项💪🏻

我提到过 Medium 是一个很好的起点,TDS 是任何有抱负的数据科学家的起点,但是如果您想要更多的自由呢?几个月前我就是这种情况,因为我想进一步分散我的收入来源。

我已经开始:

  • 更好的数据科学 —我的个人网站
  • YouTube 频道——因为很多人更喜欢视频而不是文字
  • 加盟计划通过 亚马逊 Udemy —推荐我喜欢的书籍和课程

我必须承认——制作 YouTube 视频是如此耗时,以至于我还没有 100%地投入其中,但这是一个建立追随者并在未来赚几个钱的好选择。

对于网站,我选择用 WordPress 来创建,因为这是最简单的选择。尽管如此,我还是喜欢 Medium 的帖子编辑器,而不是 WordPress 上那个有问题的小东西。

这是三个额外的收入来源,就像这样。这些都需要几年的时间来建造,但是时间总会流逝,所以为什么不充分利用它呢?

带回家的点👌🏻

总而言之,是的,你应该尽快开始写关于技术和数据科学的博客。以下是你应该记住的事情:

  • 从简单开始 —中型和向数据科学发展是最好的起点,您可以随时扩展
  • **慢慢来——你不会一夜之间赚到房租,但这只是时间问题
  • **写下你关心的事情——如果你关心这个话题,读者会觉得和你更亲近
  • 忽略反对者——仅仅因为有人被困在朝九晚五并不意味着这是唯一的选择
  • 坚持发表 —至少对数据科学来说,每周 1 到 4 次就足够了

大概就是这样。这不像看起来那么容易,但也没那么难。此外,至少在数据科学方面,有太多的主题可以写,所以你不应该很快就没有主意了。

感谢阅读。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

* [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)*

加入我的私人邮件列表,获取更多有用的见解。

一年的彩票研究(浅述)

原文:https://towardsdatascience.com/one-year-of-lottery-ticket-research-a-light-overview-b4d53d430887?source=collection_archive---------32-----------------------

获奖门票于 2018 年 3 月被发现,并于同年在 ICRL 颁奖。它引起了很多关注。它揭示了神经网络未知的潜在属性,似乎是更快训练和更小模型的关键之一。我们如何处理神经网络体系结构设计的总体思路?

没错,这就是莱克斯·弗里德曼(Lex Fridman),他与彩票的研究无关(除了在他的牛逼讲座系列中提到它是 2020 年深度学习的主要研究领域之一)。但是他比任何股票图片更能引起标题中的任何关键词(来源)。

Lex Fridman 在他的深度学习艺术状态 2020 讲座中提到,深度学习的获奖门票是 2019 年最重要的话题之一。这篇文章旨在总结我阅读后的理解。希望你会喜欢它。

修剪

众所周知,DL 模型通常具有繁重的计算要求,并且在特定设置中可能会阻塞。例如,ResNet 一次推理需要 5000 万次运算。他们一直在努力用量化知识提炼修剪来减少参数的数量。

修剪移除最不重要的权重或通道。最不重要可以意味着具有最小量级或其他启发的一个。这种技术运行良好,可以减少网络中高达 90%的权重,同时保持大部分原始精度。虽然修剪可以帮助减少模型的大小,但它无助于更快地训练它。一般是后处理步骤,训练之后。重新训练一个修剪过的模型不会产生和训练后修剪一样的结果。如果有可能直接训练修剪过的模型,在不牺牲性能的情况下训练得更快。

但是在他们的论文中,Jonathan FrankleMichael Carbin 通过实验发现,我们可以先训练较小的网络,而不是训练大型网络,然后缩小它们的规模:

密集的、随机初始化的前馈网络包含子网(“优胜门票”),当被隔离训练时,在相似的迭代次数下,达到与原始网络相当的测试精度。

中奖彩票

为了找到中奖的门票,初始化似乎是关键:

当它们的参数被随机重新初始化[…]时,我们的中奖彩票不再与原始网络的性能相匹配,这证明这些较小的网络不能有效地训练,除非它们被适当地初始化。

他们发现,在用原始模型的参数重新初始化权重后,我们可以再次训练一个修剪过的模型。这给出了比随机重新初始化更好的系统结果。多次执行此过程称为迭代修剪(无需重新初始化):

1\. Randomly initialize a neural network [with weights θ0] 
2\. Train the network for j iterations, arriving at parameters θj 
3\. Prune [by magnitude] p% of the parameters in θj , creating a mask m 
4\. Reset the remaining parameters to their values in θ0 
5\. Goto 2

如果由这种技术产生的子网与原始网络的性能相匹配,它就被称为一张中奖票。下图显示了 MNIST 数据集上 LeNet(全密度)网络上五次运行的平均结果。这种模式以不同的方式进行了删减:

  • [蓝色]完成上面的食谱
  • [橙色]与蓝色相同,但将步骤 4 替换为“随机初始化其余参数”
  • [红色]与没有步骤 5 的橙色线相同
  • [绿色]与蓝色相同,但没有步骤 5

我们可以看到,步骤 4 是关键,因为绿线和蓝线始终表现更好,并且比随机重新初始化的网络训练得更快。他们还在 MNIST 和 CIFAR10 上发现了类似于 VGG 和 ResNet 这样的卷积网络的结果(在原始论文中有许多更多细节)。

提早修剪

但是上面的方法似乎很难对付更深层次的网络。在后续论文(2019 年 3 月)中,作者稍微改变了其余参数的重置方式(步骤 4):

我们将中奖彩票的权重设置为少量训练迭代后获得的权重,而不是将其设置为初始初始化值(后期重置)。使用后期重置,我们在 Imagenet 上确定了 Resnet-50 的第一张中奖彩票。

下图描绘了深度模型的不同稀疏度水平下的性能,使用不同的值进行重绕(重绕权重的迭代)。我们可以看到,在迭代 0 时重绕并不比原始网络执行得更好,而在更高迭代时重绕则可以:

那些更深入的模型正在抵制上面的获胜秘诀,但是在查看了它们的稳定性之后发现了一些有趣的事情:

  • 修剪的稳定性:“单独训练的子网络的权重和在更大的网络中训练的相同子网络的权重之间的距离”。它捕捉到了“一个子网在孤立状态下训练并仍能到达与更大网络相同的目的地的能力”。如果一个神经元是稳定的,它就不会受到它的邻居通过掩蔽消失的太大影响。
  • 对数据顺序的稳定性:“用不同数据顺序训练的子网的两个副本的权重之间的距离”。它捕捉到了“尽管 SGD 存在梯度噪声,子网仍能一致到达同一目的地的内在能力”。

下表显示了不同网络的稳定性。预热意味着学习率在训练过程中计划缓慢增加,可能会降低优化器的噪音。 IMP 是生成中奖票的原始配方:

我们可以看到,在不改变学习率的情况下,IMP 无法在更深的网络中找到获胜的门票。我们还可以看到,性能和稳定性指标之间存在联系。“中奖票比随机子网更稳定”。

其他领域呢?

到目前为止,中奖彩票已经在相同的数据集和计算机视觉任务上进行了测试。有人可能会问,这是否仅仅是严重的过度匹配,或者中奖彩票是否会发生转移。

脸书发表了一篇论文(2019 年 6 月),在六个视觉数据集上测试了获奖门票的评估和转移。例如,在 ImageNet 上测试生成中奖票,并在其他地方进行测试(如 CIFAR-100):

他们观察到,中奖彩票在所有数据集上的表现都(至少)接近原始彩票。而且,在较大数据集上生成的中奖彩票比其他彩票更通用,这可能是由于原始模型中的类别数量。最后,本文还成功测试了跨不同优化器的迁移。

图像分类以外的其他任务呢?脸书同时发表了一篇论文(2019 年 6 月),该论文测试了强化学习和 NLP 任务中的优胜券。

对于 NLP,我们发现,对于在语言建模上训练的递归 LSTM 模型和在机器翻译上训练的 Transformer 模型,获胜的票证初始化都优于随机票证。[……]对于 RL,我们发现,在经典控制问题上,以及对于许多(但不是全部)Atari 游戏,赢票初始化大大优于随机票。

TLDR

  • 许多神经网络是过度参数化的
  • 弗兰克尔&卡宾发现了一种简单的算法,可以在较大的网络中找到较小的网络
  • 这些子网络是可以从头开始训练的,至少可以表现得一样好,甚至更好
  • 是什么让中奖彩票如此特别还不清楚,但这似乎是深入理解神经网络潜在属性的关键一步

来源

最初发表于data-soup.github.io/blog/

posted @ 2024-10-14 11:49  绝不原创的飞龙  阅读(294)  评论(0)    收藏  举报