TowardsDataScience-博客中文翻译-2020-一百零二-

TowardsDataScience 博客中文翻译 2020(一百零二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

麻省理工学院的科学家利用人工智能发现了一种新的抗生素

原文:https://towardsdatascience.com/scientists-at-mit-have-discovered-a-new-antibiotic-using-artificial-intelligence-e3a3921420fb?source=collection_archive---------37-----------------------

我们发现新抗生素的方式将随着这项新技术的出现而改变,这项新技术利用神经网络和人工智能的深度学习,在比传统方法短得多的时间内筛选出数百万种潜在的治疗分子。

弗兰基·查马基在 Unsplash 上拍摄的照片

麻省理工学院和布罗德研究所的一组研究人员利用人工智能技术揭示了一种分子,这种分子能够有效杀死目前威胁人类健康的一些最重要的病原体。

随着抗生素耐药性问题的日益严重,发现和开发新的抗生素变得越来越迫切。抗生素发现的传统方法可能非常昂贵和耗时,然而,这项新技术可以将时间框架从几年减少到几周。

马库斯·斯皮斯克Unsplash 上拍摄

总的来说,这项技术并不新鲜,深度学习最著名的例子就是你可能放在口袋里随身携带的那个。苹果公司的 Siri 和亚马逊公司的 Alexa 都是神经网络的例子,你和它说话越多,它就能从你的声音中学到越多。

类似地,这个新程序首先提供了一个现有的约 2000 种分子的数据库,包括 FDA 批准的抗生素和其他化合物。然后,该团队能够训练神经网络识别其他能够杀死细菌的类似分子。他们让这个深度学习系统突出显示任何对测试细菌大肠杆菌具有抗菌活性的分子。

哈利辛

最初筛选的文库是“药物再利用中心”,其中包含超过 6000 个表征的分子。重复发现相同的化合物是传统药物发现方法的一个大问题。为了抵消这一点,只有与其他已知抗生素结构不同的化合物才会从测试库中取出。

经过反复的学习周期后,该系统能够识别出一个感兴趣的分子,该分子被预测对大肠杆菌具有非常高的效力,并且对人类具有低毒性。这个新分子被恰当地命名为 Halicin ,以《2001:太空漫游》中的人工智能机器命名。

然后,对 Halicin 进行了更常规的实验室测试,以发现它在杀死各种细菌物种方面的效率,并了解它使用哪种机制来做到这一点。人们发现,Halicin 会干扰细菌维持细胞壁梯度的能力,从而产生 ATP。ATP 是所有活细胞的能量货币,所以没有它,死亡是必然的。

在小鼠模型中,发现 Halicin 对一些最危险的耐药感染具有强大的抗菌活性,如艰难梭菌和泛耐药鲍曼不动杆菌。这两种细菌都被世卫组织列为病原体,我们迫切需要新的抗生素。

托比亚斯·菲舍尔在 Unsplash 上拍摄的照片

更大的数据库

在第一轮成功之后,科学家们转向了更大的化合物库。ZINC15 数据库包含超过 15 亿个分子,然而,只有 1.07 亿个被选中进行筛选。

在这些分子中,有 8 种被发现对至少一种选择进行测试的细菌物种具有活性,其中包括金黄色葡萄球菌肺炎克雷伯氏菌等。整个过程只花了 4 天,当你考虑到能够用经验方法人工筛选的最大的库要小 10 倍,并且可能需要数年时,这是令人震惊的。

发现其中两种化合物对所有测试的物种都有广泛的活性。其中一种抗生素的结构不同于任何其他已知的抗生素,而且预计对人类的毒性很低。毫无疑问,这个分子将是该小组未来研究的重点。

影响

这种方法有机会彻底改变我们发现抗生素的方式。通过传统技术和颠覆性技术的结合,该团队能够确定一种抗生素,他们认为这可能是有史以来发现的最重要的抗生素之一(由 T21 布罗德研究所报道)。

这对科学的许多领域都有巨大的影响。或许最重要的是,这可以极大地帮助对抗抗生素耐药性。

从这个角度来看,halicin 有潜力治疗的鲍曼不动杆菌菌株目前对所有已知的抗生素都有耐药性,目前是部署在伊拉克和阿富汗的美国士兵的一个大问题。这种细菌对健康人的威胁很小,然而,那些免疫系统较弱或受伤的人明显更容易受到感染,导致医院中的高发病率。据认为,士兵的感染率很高,这是因为新兵在受伤后返回祖国之前要忍受不同的医疗环境。这导致士兵的总体死亡率上升。

托马什·弗兰科斯基Unsplash 上拍摄的照片

将来的

就这项技术而言,这项研究背后的科学家强调,这只是一个开始。现在已经证明了这是一个多么强大的工具,人工智能方面可以不断改进,以便可以筛选更大的库。这可能会导致定期发现具有抗菌活性的分子。

还有机会定制深度学习算法,以精确定位可以杀死非常特定类型抗生素的分子。该团队希望,在未来,这可能会导致治疗方法的发展,可以通过静脉注射到精确的感染部位,从而不会干扰无害地生活在我们体内的细菌。

参考

原始研究论文抗生素发现的深度学习方法

人工智能产生新抗生素

药品再利用中心

介绍深度学习和神经网络—新手的深度学习(1)

解释:神经网络

物理性质对革兰氏阳性和革兰氏阴性病原体抗菌活性的趋势和例外

现代战争中的不动杆菌

与战斗相关感染的流行病学…:创伤和急救外科杂志

锌 15 —每个人的配体发现

Scikit-learn 预测高尔夫表现的线性回归

原文:https://towardsdatascience.com/scikit-learn-linear-regression-for-predicting-golf-performance-c92f31b69f92?source=collection_archive---------64-----------------------

我如何建立一个简单的工具来帮助玩家理解他们使用数据的技能。

资料来源:Unsplash/andrewricegolf

作为努力提高我的高尔夫球水平的一部分,我在过去的一年里一直在跟踪我在比赛关键领域的数据。当我在一轮结束时计算我的分数时,我也会计算推杆数、果岭数和球道数。这并不需要太多的努力,但它可以告诉你很多关于你的游戏需要练习的地方。

在 General Assembly 上数据科学课程时,我决定将我的最终项目集中在我收集的数据上。我使用 Python 中的 Scikit-learn 库构建了一个线性回归模型,该模型可以预测您的高尔夫表现。并且,我将我构建的模型打包在一个简单的 Flask web 应用程序中,该应用程序可以部署到 Heroku 以方便访问。可在 Github 上获得

我构建的模型侧重于两个主要用例…

根据分数预测统计数据

高尔夫球手通常会围绕他们想要打出的分数为自己设定目标。也许他们希望能够在资格赛中晋级,减少他们的障碍,或者只是打出他们个人的最好成绩。这个工具接受一个得分输入,并输出一个得分所需的平均统计预测。例如,如果你的目标是突破 80,这个工具可以给你具体的目标来实现它。

在模型中输入分数 79 时的示例输出。

根据数据预测得分

对于高尔夫球手来说,了解自己的技术水平很重要,这样他们就可以管理对高尔夫球场的期望,避免不必要的风险。这是帮助高尔夫球手计划比赛的有用工具。它以数据为输入,预测你最有可能投篮的得分。例如,如果你要去一个困难的球场,只希望打 5 个果岭,你可以生成一个得分预测,以了解你在那里可能会打出什么。

向模型中输入特定统计数据时的示例输出。

我们可以用数据来理解导致高分的行动。它可以帮助我们建立具体的目标,我们需要实现,以拍摄我们想要的分数。我们可以想出一个具体的计划来打出一个低分,而不是专注于短暂的挥杆想法,比如“低头”或“坚持到底”。例如,我们可以通过每次瞄准果岭的中心来制定击中更多果岭的具体计划。

构建模型

我用自己高尔夫比赛的数据开发了一个线性模型来预测数据和分数。我的数据集中的每个样本都代表我玩的一轮游戏,并对这一轮游戏进行统计。请参阅每个功能的以下定义…

  • 得分(整数):一轮击球的总次数
  • 果岭数(整数):规则中的果岭数(共 18 个)
  • 推杆(整数):一轮推杆的总数
  • 球道(INT):一轮比赛中击中球道的总数

在散点图上画出这些分数后,根据我对游戏的体验,这些趋势是有意义的。随着你推球次数的增加,你的分数也会上升。随着你击中果岭数量的增加,你的分数会下降。击中球道的次数和你的得分之间的相关性较小。

N=13 个样本

为了让数据代表更大范围的分数,我添加了来自 PGA 巡回赛数据集的样本。数据集中的每个样本都代表了一名职业巡回赛选手,以及他们在 2010 年至 2018 年期间在比赛各个领域的平均统计数据。原始数据集包含数千个值,但我随机抽取了 10 个值来代表得分范围在 69 到 75 之间的玩家。在将职业统计数据添加到我的个人数据集中之后,我重新创建了散点图。

N=23 个样本

因为统计数据似乎都与分数有线性关系,所以我选择用线性模型来拟合数据,这种模型训练速度快,解释简单,方差低,这意味着不管输入的数据是什么,它都会预测类似的结果。线性模型的缺点是,它可能比最先进的建模技术更有偏差。

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_validate, KFolddef fit_and_score_linear_model(data,target):

    # Define features
    features = ['Putts','Fairways','Greens']
    X = data[features]
    y = data[target]

    # Fit linear regression model
    lr = LinearRegression()
    lr.fit(X,y)
    y_pred = lr.predict(X)
    r2 = lr.score(X,y)

    # Cross validate model
    kf = KFold(n_splits = 5, shuffle=True, random_state=24)
    cv_results = cross_validate(lr,X,y,scoring='r2',cv=kf)

    print('r2 training: '+str(r2))
    print('r2 cross val: ' +str(cv_results['test_score'].mean()))

    return {'model':lr, 'predicted': y_pred}

我从 Scikit-learn 导入了线性回归模型,并构建了一个函数来用数据拟合模型,打印训练分数,并打印 5 倍的交叉验证分数。仅用我的个人数据运行该函数,我得到了以下准确度值…

r2 training: 0.5005286435494004
r2 cross val: -2.370294280122853

用我的个人数据结合专业数据运行该函数,我得到了以下准确度值…

r2 training: 0.9205079679115369
r2 cross val: 0.8118472290929108

加入职业高尔夫球手的数据后,R2 值显著增加。这可能是因为目标变量的差异更大,或者为模型学习正确的关系提供了更多的数据。在打印出我拟合的线性模型的系数后,我能够将下面的等式放在一起,以表示一名球员基于推杆、球道和果岭击球的总分。

为了创建一个基于输入 I 得分预测统计数据的工具,我用相同的数据拟合了多个不同的线性模型。我没有使用 Score 作为目标变量,而是使用它作为唯一的特征,将每个单独的 stat 作为目标变量。结果是推杆、球道和果岭的 3 个线性模型,分别以 0.44、0.33 和 0.83 的训练 R2 精度拟合数据。我又一次打印出了系数,将基于分数预测不同统计数据平均值的方程放在一起。

结论和后续步骤

这种模式在未来有几个方面可以改进或扩展。

更多数据-样本量较小,这导致在尝试交叉验证模型和寻找样本外精度时结果不一致。根据为我的 KFolds 交叉验证选择的数据子集,这些值会发生显著变化。

代表所有高尔夫球员-用于训练模型的数据仅代表我的技能和巡回赛职业的技能,在数据集中留下了很大的差距。该模型需要来自射击在 75-80 之间的高级玩家和射击超过 100 的初学者的额外样本。填补这一空白可以让我探索不同的模型,可能会导致更准确的预测。

一致的抽样方法——我的个人得分数据是以不同于职业得分数据的方式收集的。职业得分的每个样本都是多轮统计的平均值。我的每个分数样本代表了我玩的一个特定回合。取平均值可以消除数据中的重要差异,这些差异可用于做出更准确的预测。

更多功能—有可能创建/修改与分数更密切相关的功能。例如,不是所有的球场都有相同数量的球道。通过创建一个详细描述球场上球道数量的特征,我们可以将球道统计数据转换成一个百分比而不是一个绝对数字。

Scikit-learn、TensorFlow、PyTorch、Keras……但是从哪里开始呢?

原文:https://towardsdatascience.com/scikit-learn-tensorflow-pytorch-keras-but-where-to-begin-9b499e2547d0?source=collection_archive---------8-----------------------

关于机器学习任务可用内容的综合初学者指南。

Javier Allegue Barros 在 Unsplash 上拍摄的照片

如果你是机器学习的新手,这意味着你已经被这个不可思议的研究领域及其无限的视角所诱惑,祝贺你,欢迎你!

现在,你可能想预测下一任美国总统会是谁,用人工智能驱动的交易工具赚钱,或者只是在图片上检测猫和狗。幸运的是,有大量的在线资源可以帮助你实现这些目标。

存在许多机器学习(ML)和深度学习(DL)框架,但在本文中,我将只考虑使用 Python 的四个最常见的框架,即 Scikit-learnTensorFlowKerasPyTorch 。其中一些服务于不同的目的,一些比其他的更有用,这取决于你的目标和你的个人投资,一些对于结果的可解释性更好,等等。让我们一起回顾一下有助于回答这个重要问题的要点:

作为初学者,应该用哪个 ML 框架?

四个主要框架的简介

  • TensorFlow (TF)是谷歌的一个端到端的机器学习框架,允许你执行极其广泛的下游任务。有了 TF2.0 和更新的版本,给游戏带来了更多的效率和便利。
  • Keras 建立在 TensorFlow 之上,这使得它成为深度学习目的的包装器。这是难以置信的用户友好和容易拿起。一个坚实的资产是它的神经网络块模块化,以及它是用 Python 编写的这一事实,这使得它易于调试。
  • PyTorch 是 TensorFlow 的直接竞争对手,由脸书开发,广泛应用于研究项目。它允许几乎无限制的定制,非常适合在 GPU 上运行张量运算(实际上 TensorFlow 也是如此)。
  • Scikit-learn 是另一个用户友好的框架,它包含大量有用的工具:分类、回归和聚类模型,以及预处理、维度缩减和评估工具。

每个框架都是开源的,当然其他框架也是可用的,其中一些你可以在本文中了解

你的目的是什么?

马克·弗莱彻-布朗Unsplash 上拍摄

随着你对 ML 的了解越来越多,你会经常阅读本书,但是你最终用来执行任务的框架和模型应该取决于任务的性质。如果你想预测人们对电影评论的看法,那么使用 Keras 或 PyTorch 的深度学习方法是有意义的,如果你想预测未来 NBA 比赛门票的价格,那么 scikit-learn 处理结构化数据的能力就是你所需要的。

如果你正在进行学术研究,并且想要深入复杂的建模,那么 TF 和 PyTorch 就是为你准备的,去做吧!相比之下,使用 Keras 和 scikit-learn 可以在 5 分钟内完成编码,2 分钟内完成训练,10 分钟内完成部署。这就引出了我的下一个观点:

从简单开始!

mostafa meraji 在 Unsplash 上拍摄的照片

当我在大学课程中第一次开始学习 ML 和 AI 时,作业使用 PyTorch,我们被要求编写正则化函数,这在当时看起来非常复杂,让我自然而然地转向更简单的东西来构建神经网络:Keras。

关键是,并不是所有的框架都同样容易掌握。例如,您可以使用 scikit-learn 用大约三行代码构建和训练一个简单的模型:

***from** **sklearn.svm** **import** SVC
model = SVC()
model.fit(X, y)*

这不会给你最好的结果,但是从简单开始是熟练学习曲线的关键。然后,您将利用您的基础知识,探索其他模型,调整参数,并可能继续进行更复杂和更具挑战性的工作。

相比之下,从实现端到端 TensorFlow 或 PyTorch 模型开始可能会有点棘手,一开始会让人不知所措。

不要都学!

兰迪·雷伯恩在 Unsplash 上拍摄的照片

这一点似乎是显而易见的,但是相信我,对于初学者来说,认为他们需要彻底检查每个框架的源代码才能被聘为 ML 工程师或数据科学家是相当普遍的。让过多的信息充斥你的大脑可能会阻碍你解决问题的能力,这不是我们想要的,对吗?

一种更有趣的方式是学习基本概念,这将帮助你更好地理解为了解决你的问题,你应该熟悉框架的哪些特定部分。例如,您将在某个时候使用 scikit-learn 的度量函数来评估您的模型的性能,但是这并不意味着您应该记住所有可用的度量函数才能做得更好。

基本要点

  • 探索并权衡你的选择在承诺深入学习机器学习框架之前,你可能会对其他可用的东西感到惊讶。
  • 不要担心不能马上取得惊人的艺术效果。了解你的学习曲线,享受发现的乐趣。
  • 绝不半吊子两件事。全屁股一个东西。我保证,自信地使用任何一个提到的框架都是一笔宝贵的财富,没有必要了解所有的事情来解决问题。

感谢您的阅读,我希望这对您有所帮助,并且我成功地将您引向了正确的方向!

深度学习中的模型剪枝

原文:https://towardsdatascience.com/scooping-into-model-pruning-in-deep-learning-da92217b84ac?source=collection_archive---------35-----------------------

生产中的机器学习

本文讨论深度学习背景下的剪枝技术。

这篇文章是我上一篇关于 量子化 文章的后续。在本文中,我们将在深度学习的背景下讨论模型修剪的机制。模型修剪是一种丢弃那些不代表模型性能的权重的艺术。精心修剪的网络会产生更好的压缩版本,它们通常适用于设备上的部署场景。

文章的内容分为以下几个部分:

  • 函数和神经网络中“无意义”的概念
  • 修剪训练好的神经网络
  • 不同模型之间的代码片段和性能比较
  • 现代修剪技术
  • 最后的想法和结论

(我们将要讨论的代码片段将基于 TensorFlow (2)和 TensorFlow 模型优化工具包)

:文章镜像此处

函数中“无意义”的概念

神经网络是函数逼近器。我们训练他们学习函数,这些函数捕获了表达输入数据点的基本表示。神经网络的权重和偏差被称为其(可学习的) 参数 。通常,权重被称为正在学习的函数的 系数

考虑下面的函数-

在上面的函数中,我们在 RHS 上有两项: x 和 x,系数分别是 1 和 5。在下图中,我们可以看到,当轻推第一个系数时,函数的行为没有太大变化。

下面是原函数的不同变型中的系数,可称为。丢弃这些系数不会真正改变函数的行为。

神经网络的扩展

上述概念也可以应用于神经网络。这需要更多的细节来展开。考虑一个训练好的网络的权重。我们如何理解不重要的权重呢?这里的前提是什么?

要回答这个问题,请考虑梯度下降的优化过程。不是所有的权重都使用相同的梯度幅度来更新。给定损失函数的梯度是相对于权重(和偏差)取的。在优化过程中,用比其他权重更大的梯度幅度(正的和负的)来更新一些权重。这些权重被优化器认为是 显著的 ,以最小化训练目标。接收相对较小梯度的权重可以被认为是 不重要的

训练完成后,我们可以逐层检查网络的权重大小,并找出重要的权重。这个决定是用几种试探法做出的-

  • 我们可以按降序对权重大小进行排序,并选取队列中出现较早的权重。这通常与我们想要达到的稀疏水平(要修剪的权重的百分比)相结合。
  • 我们可以指定一个阈值,其幅度高于该阈值的所有权重将被认为是重要的。这个方案可以有几种风格:

i. 阈值可以是整个网络中最低的权重幅度。

二。阈值可以是网络内部各层的局部权重值。在这种情况下,重要的权重被逐层过滤掉。

如果所有这些变得难以理解,不要担心。在下一节中,事情会变得更清楚。

修剪训练好的神经网络

既然我们已经对所谓的重要权重有了相当多的了解,我们可以讨论基于 幅度的 修剪。在基于大小的剪枝中,我们认为权重大小是剪枝的标准。通过修剪,我们真正的意思是把不重要的权重归零。以下代码片段可能有助于理解这一点

(这段代码片段来自此处)

这里有一个图形表示,在 之后,权重 将会发生变化

它也适用于偏见。值得注意的是,这里我们考虑接收形状为(1,2)的输入并包含 3 个神经元的整个层。在网络被修剪以补偿其性能的任何下降之后,重新训练网络通常是明智的。在进行这种再训练时,重要的是要注意,在再训练期间,被修剪的权重 不会被更新

观看活动中的事物

废话少说!让我们来看看这些东西的作用。为了简单起见,我们将在 MNIST 数据集上测试这些概念,但是您也应该能够将它们扩展到更复杂的数据集。我们将使用一个浅层全连接网络,其拓扑结构如下-

该网络总共有 20,410 个可训练参数。对这个网络进行 10 个纪元的训练可以让我们得到一个很好的基线-

在这里与剧情互动

让我们现在修剪它!我们将使用tensorflow_model_optimization(别名为tfmot)。tfmot为我们提供了两种修剪方法:

  • 选择一个训练有素的网络,用更多的训练来修剪它。
  • 随机初始化一个网络,从头开始修剪训练它。

我们将对他们两个进行实验。这两种方法都应该包括一个修剪时间表,我们稍后将讨论这个时间表。以训练的形式修剪网络的基本原理是更好地引导训练目标,使得梯度更新可以相应地发生,从而以有效的方式调整未修剪的权重。

注意在你的模型中修剪特定的层也是可能的,并且tfmot允许你这么做。查看本指南以了解更多信息。

食谱 1:选择一个训练有素的网络,用更多的训练来修剪它

从现在开始,我们鼓励您跟随顶部提到的这个 Colab 笔记本。

我们将采用我们之前训练的网络,并从那里对其进行删减。我们将应用一个修剪计划,在整个训练过程中保持稀疏水平不变(由开发人员指定)。表达这一点的代码如下:

在我们开始训练它之前,修剪过的模型需要重新编译。我们以同样的方式编辑它,并打印它的摘要-

我们看到现在参数的数量已经改变了。这是因为tfmot为网络中的每个权重添加了不可训练的掩码,以指示给定的权重是否应该被删减。掩码为 0 或 1。

让我们训练它。

与剧情互动这里

我们可以看到,修剪模型并不影响性能。红线对应于修剪实验。

注意:

  • 修剪计划是必须指定的,以便在训练模型时实际修剪模型。我们还指定了[UpdatePruningStep](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/sparsity/keras/UpdatePruningStep)回调,以便它在训练期间负责修剪更新。
  • [PruningSummaries](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/sparsity/keras/PruningSummaries)提供了关于在训练期间如何保持稀疏度和幅度阈值的总结。你可以在这里看到一个这样的例子
  • 将修剪计划视为一个超参数。tfmot提供了另一个现成的修剪计划- [PolynomialDecay](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/sparsity/keras/PolynomialDecay)
  • 您可能希望将修剪计划中的end_step参数设置为小于或等于您将为其训练模型的时期数。此外,您可能需要试验一下frequency参数(它表示应该应用修剪的频率),以便获得良好的性能和期望的稀疏性。

我们还可以通过编写如下测试来验证tfmot是否达到了目标稀疏度:

在修剪过的模型上运行它应该为所有被修剪的层产生True

诀窍 2:随机初始化一个网络,通过从头开始训练来修剪它

在这种情况下,除了我们不是从一个已经训练好的网络开始,而是从一个随机初始化的网络开始之外,一切都保持不变。

在这里与剧情互动

绿线对应于从头修剪实验。我们可以观察到其他两个模型的性能有所下降,但这是意料之中的,因为我们不是从一个已经训练好的模型开始的。

在这里与剧情互动

当我们通过从头开始训练来修剪网络时,通常会花费最多的时间。这也是预期的,因为网络正在计算如何最好地更新参数,以便达到目标稀疏度水平。

所有这些都很好,但是为了能够真正体会到修剪的力量,我们需要挖掘得更深一些:

  • 导出同一网络的修剪和未修剪的变体,压缩它们,并记录它们的大小。
  • 量化它们,压缩它们的量化版本,记录它们的大小,并评估它们的性能。

让我们在下一节处理它。

性能赋值

我们将使用标准的zipfile库将模型压缩成.zip格式。当序列化修剪后的模型时,我们需要使用[tfmot.sparsity.keras.strip_pruning](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/sparsity/keras/strip_pruning),它将删除由tfmot添加到模型中的修剪包装器。否则,我们将无法在修剪后的模型中看到任何压缩优势。

然而,压缩常规 Keras 模型保持不变。

file应该是一个已经序列化的 Keras 模型的路径(修剪的和常规的)。

在下图中,我们可以看到压缩模型的重量比常规的 Keras 模型轻,但它们仍然有很好的性能。

我们可以使用 TensorFlow Lite 量化我们的模型,在不影响性能的情况下进一步减小它们的大小。注意在将修剪后的模型传递给 TensorFlow Lite 的转换器时,您应该在剥离修剪包装后传递它们。本报告更详细地讨论了量化。

除了精度测量之外,压缩比是另一种广泛使用的技术,用于测量特定修剪算法的功效。压缩比是剪枝网络中剩余参数分数的倒数。

这种量化也被称为训练后量化。因此,这里有一个简单的方法供您遵循,以优化您的部署模型:

在下一节中,我们将学习一些现代的修剪食谱。如果你想更多地追求模型优化领域,这些想法将值得进一步探索。

一些现代修剪食谱

让我们从以下激励性问题开始这一部分:

  1. 当我们重新训练一个修剪过的网络时,如果将 个未修剪的权重 初始化为它们原来的初始幅度会怎么样?如果你从一个已经训练好的网络(比如网络 A)中得到一个修剪过的网络,考虑网络 A 的这些初始大小。
  2. 当在具有预训练网络的迁移学习机制中执行 基于幅度的 修剪时,我们如何决定权重的重要性?

赢得门票的机会

弗兰克尔等人在他们关于彩票假说的开创性论文中对第一个问题进行了大量的探索。因此,在修剪了一个已经训练好的网络之后,具有上述初始化的子网被称为优胜标签。

来源:原始文件

作为这种方法背后的基本原理,您可以推断在网络的初始训练期间,参数的特定初始化引导了优化过程。现在,在优化领域反应良好的权重(意味着它们比其他权重走得更远)实际上最终赢得了彩票。因此,为了让它(重新)训练得更好,如果我们将权重初始化为它们最大的初始大小,优化过程就会很好地利用它们。感谢 Yannic Kilcher 的这个漂亮的解释

这篇论文提供了大量不同的实验来支持这个假设,绝对值得一读。

彩票假说的系统探索

在最初的彩票假设论文中,Frankle 等人只研究了如果幸存的权重在重新训练之前被重新初始化到它们的最大初始幅度,修剪后的网络如何表现。就在彩票假说在 2019 上提出后,周等人发表了一篇关于解构彩票的论文,研究了在修剪过程中处理存活和未存活的权重的不同方法。还提出了 supermasks 基本都是可以学习的面具。

来源:原始文件

彩票假说的推广

为了能够将彩票假设扩展到像 ImageNet 这样的数据集,Frankle 等人发表了一篇关于线性模式连通性的论文,这是彩票假设的一种推广。它提出了权重回卷作为一种潜在的方式来初始化修剪网络的幸存权重。之前,我们用它们的最大初始星等来初始化它们。权重倒带所做的是,它将幸存的权重倒带到原始网络训练中的某个地方。换句话说,幸存的权重被初始化为来自原始网络训练的时段 5 的幅度。

来源:原始文件

扩展这个想法,Renda 等人发表了一篇关于学习速率倒回的论文,该论文适用于在重新训练修剪过的网络时倒回学习速率表。作者还提出这是微调的替代方案。

所以,这些令人兴奋的想法主要是围绕着 基于幅度的 修剪发展而来的。在最后一节中,我们将看到一种比基于数量的剪枝更好的剪枝方法,特别是对于迁移学习机制。

基于权重移动的修剪

在他们关于移动修剪的论文中,Sanh 等人提出了一种基于幅度的修剪的替代方法,该方法专门用于处理迁移学习任务的预训练模型的修剪。

基于幅度的剪枝与我们之前已经讨论过的重要性概念正相关。在这种情况下,这里的重要性简单地表示权重的绝对大小。这些数值越低,意义越小。现在,当我们尝试使用一个在不同数据集上预先训练的模型进行迁移学习时,这种重要性实际上可以改变。优化源数据集时重要的权重对于目标数据集可能不重要。

来源:原始文件

因此,在迁移学习过程中, 移向零的预训练权重实际上可以认为相对于目标任务是不显著的,而 移得更远的权重可以认为是显著的。这就是这种方法的名字来源于——移动* 修剪。再次感谢 Yannic 的精彩解说。*

结论、致谢和最后的想法

如果坚持到最后,太好了!我希望这份报告让你对深度学习中的修剪有一个公平的想法。我要感谢(谷歌的)拉结尔和云璐,他们为我提供了关于tfmot的重要信息和一些关于修剪本身的额外想法。

我想在这方面进一步探讨的一些想法是:

  • 如果我们可以在训练和再训练网络时使用有区别的修剪时间表呢?
  • 在进行幅度修剪时,周等人向我们展示了在修剪后的网络中处理幸存权重的初始化的不同方式。我们可以学习一种有效的方法来系统地将它们结合起来吗?

在撰写本报告时(2020 年 6 月),最近的修剪方法之一是 SynFlow 。SynFlow 不需要任何数据来修剪网络,它使用突触显著性分数来确定网络中参数的重要性。

我愿意通过 Twitter ( @RisingSayak )听取你的反馈。

参考

(排名不分先后)

变量范围和 LEGB 规则

原文:https://towardsdatascience.com/scope-of-variable-and-legb-rule-4d44d4576df5?source=collection_archive---------44-----------------------

变量范围和 LEGB 规则。图片由作者

给 PYTHON 开发者的提示

变量范围是指你可以看到或者访问变量的地方

一开始,我假设您知道如何定义自己的函数,但不仅如此,您还知道如何编写具有多个参数的函数,并且可以使用元组返回多个值。

先决条件

如果你不熟悉定义自己的函数,下面的文章会给你更多的信息。

[## 编写自己的函数

数据科学家需要具有特定功能的函数

towardsdatascience.com](/writing-your-own-functions-40d381bd679)

我们现在将在用户定义函数的上下文中讨论作用域的概念。你已经在你的程序中定义了变量。到目前为止,您一直在使用这些变量,没有任何问题。然而,如果你记得不是你定义的所有对象在程序中的任何地方都是可访问的,那就更好了。这就是作用域的概念,它告诉你程序的哪一部分一个对象或者一个变量可以被访问。

变量或对象,如程序中定义的函数,都有名称,函数也是如此。

有几种类型的范围。第一个是全局范围,这意味着它是在脚本的主体中定义的。第二个是局部范围。局部作用域意味着它是在函数中定义的。一旦函数执行完毕,局部范围内的任何变量都会终止,这意味着在函数定义之外不能再访问这些变量。

第三个是内置范围。这由 Python 提供的预定义内置模块中的变量组成,比如 print 和 sum。最后一个是封闭函数,我们将在后面的嵌套函数部分讨论这一点。

让我们来看一个例子。

本地范围。图片作者作者

我们定义函数,然后调用它。如果我们试图在函数执行之前或之后访问变量名value,该变量是不可访问的。这是因为它仅在函数的局部范围内被定义。变量value没有被全局定义。

如果我们在定义和调用函数之前全局定义变量会怎么样?

全球范围。图片由作者

简而言之,任何时候我们调用全局范围内的变量,它都会访问全局范围内的变量名。然而,每当我们在函数的局部范围内调用变量时,它将首先在局部范围内查找。这就是为什么调用square(5)返回的结果是 25 而不是 30。

如果 Python 在局部范围内找不到变量,那么它会在全局范围内寻找。例如,我们在函数方块中访问一个全局定义的变量value。请注意,访问的全局值是调用函数时的值,而不是定义函数时的值。因此,如果我们重新分配value并调用该函数,我们会看到value的新值被访问。

很明显,当我们引用一个变量时,首先搜索局部范围,然后是全局范围。如果变量在局部和全局范围内不存在,则到达内置范围。如果我们想在函数调用中改变一个全局变量的值呢?这就是关键字 global 派上用场的地方。

内置范围。图片作者作者

在函数定义中,我们使用关键字global,后跟我们希望访问和更改的全局变量的变量名。比如这里我们把value改成它的平方。之后,我们将调用value变量。我们看到,通过运行函数 square,全局值确实被平方了。

嵌套函数

如果我们有一个在函数outside中定义的函数inside,并且我们在inside函数中引用了一个变量名x会怎么样?答案很直观。Python 搜索inside函数的局部范围。如果没有找到那个变量,它就搜索outside函数的范围,这个函数被称为封闭函数,因为它封闭了inside函数。如果 Python 在封闭函数的作用域中找不到那个变量,它只会搜索全局作用域,然后是内置作用域。

嵌套函数。图片作者作者

为什么我们要嵌套一个函数?

有一些很好的理由。假设我们想在一个函数中多次执行一个过程。例如,我们想要一个函数,它接受三个数字作为参数,并对每个数字执行相同的函数。一种方法是将计算写出来三次,但是如果您想经常执行它,这是不可伸缩的。相反,我们可以在函数定义中定义一个内部函数,并在需要的地方调用它。这称为嵌套函数。

我们来看另一个例子。

嵌套函数示例。图片作者作者

inside函数的语法与任何其他函数的语法相同。在这个例子中,我们定义了一个函数power_of,它包含一个名为inside的内部函数。现在看看power_of返回什么:它返回内部函数insidepower_of接受一个参数并创建一个函数inside,该函数返回任意数字的 n 次方。这有点复杂,当我们执行函数power_of时会更精确。

将数字 2 传递给power_of会创建一个对任意数字求平方的函数。同样,将数字 3 传递给power_of会创建一个对任意数字进行立方的函数。

一个有趣的细节是,当我们调用函数square时,它会记住值n=2,尽管power_of定义的封闭范围和n=2所在的局部范围已经执行完毕。这是一个细微的差别,在计算机科学的圈子里被称为闭包,你不应该太担心。然而,这是值得一提的,因为你可能会遇到它。

封闭范围内的变量。图片由作者

转到我们对作用域的讨论,您可以在函数定义中使用关键字global来创建和更改全局变量;类似地,在嵌套函数中,可以使用关键字nonlocal在封闭范围内创建和更改变量。

在这个例子中,我们修改了inside函数中n的值。因为我们使用了关键字nonlocal,它改变了封闭范围内n的值。这就是为什么调用outside函数会打印出函数inside中确定的n的值。

结论

变量引用搜索:

  • 局部范围
  • 封闭函数
  • 全球范围
  • 内置范围

这被认为是 LEGB 规则,其中 L 代表局部,E 代表封闭,G 代表全局,B 代表内置。此外,请记住,定义变量将只创建或更改局部名称,除非它们在使用关键字 global 或关键字 nonlocal 的全局或非局部语句中声明。

**Other Interesting Articles**#1 [Function Arguments: Default, Keyword, and Arbitrary](/function-arguments-default-keyword-and-arbitrary-9588b5eaaef3)#2 [Writing Your Own Functions](/writing-your-own-functions-40d381bd679)#3 [Python: Procedural or Object-Oriented Programming?](/python-procedural-or-object-oriented-programming-42c66a008676)#4 [Data Science with Python: How to Use NumPy Library](/data-science-with-python-how-to-use-numpy-library-5885aa83be6b)#5 [Do you have the Software Engineer and Data Scientist skills?](/do-you-have-the-software-engineer-and-data-scientist-skills-probably-not-7e8fb069e067)

关于作者

Wie Kiang 是一名研究员,负责收集、组织和分析意见和数据,以解决问题、探索问题和预测趋势。

他几乎在机器学习和深度学习的每个领域工作。他正在一系列领域进行实验和研究,包括卷积神经网络、自然语言处理和递归神经网络。

连接上LinkedIn

在 Bechdel 测试中给情景喜剧打分

原文:https://towardsdatascience.com/scoring-sitcoms-on-the-bechdel-test-41659d90d045?source=collection_archive---------29-----------------------

性别不平等躲不过 NLP

贝克德尔测试(BT),检查媒体中女性中心主义的基本水平,在其他地方已经被电影和的众包手动方法彻底覆盖,但据我所知,除了在非常选定的情况下的高水平之外。在获得了数百集情景喜剧的脚本后,我可以有计划地对这些情景喜剧的每一集进行测试,来比较这些节目,并跟踪它们运行过程中的变化。

我使用的数据和之前的文章中介绍的一样:过去 30 年中七部主要情景喜剧的大部分剧集的脚本。计算每一个场景和每一集的 BT 所需的信息可以从这些抄本中获得,只需要再做一点工作。你可以在这里看到这篇文章和前一篇文章的大部分代码。

该测试由三个部分组成:

  1. 场景中必须有两个女性角色。这很简单,因为抄本通常包含场景指示符。在某些情况下,我的处理不能挑选场景中断,或者抄本不包含任何;这些情节每个都被视为一个长场景,这使得通过第一步变得更容易,但与正确检测场景相比,通过其他步骤只是稍微容易一些。为了识别女性字符,我从数据集中所有说话字符的列表中手动选择姓名,包括主要字符和次要字符,但不包括像“女服务员”这样的未命名字符。
  2. 女性角色必须互相交谈。这可能是指一对一的谈话,但在情景喜剧中,一个场景中往往会出现一大群角色。为了通过这一步,我寻找了一个三行序列, A-B-A ,显示了两个女性角色之间可以构成对话的最少来回次数。
  3. 角色们必须谈论除了男性角色以外的事情。如果前后三行中的任何一行提到任何主要男性角色的名字,男性代词如“他”或“他的”,或者其他男性标识符的短列表中的任何一个,如“男人”、“男朋友”、“爸爸”或“先生”,则这一步失败。这种方法可能无法捕捉到一些情况,其中谈话的主题,广义地说,是一个男性角色,但出现了一个三行序列,没有提到他的名字或代词;但是如果一个男性出现在场景中的任何地方,就抛弃整个场景似乎太苛刻了,因为场景经常会涉及不同角色群体之间的多次对话。

每一步都按场景计算,并汇总到情节级别。我们可以通过测试步骤来查看每个节目的结果。(没有正确检测到场景中断的剧集被排除在步骤 1 的计算之外;这适用于所有的办公室插曲,所以没有第一步的要点。)

《老友记》在 BT 上表现最好,几乎每一集都通过了全面测试。威尔和格蕾丝也得分很高,通过格蕾丝-凯伦和在较小程度上凯伦-罗萨里奥的对话。已婚并有孩子的人(佩吉-马西和佩吉-凯利)和实习医生(主要是埃利奥特-卡拉)在第二步和第三步之间,这意味着他们经常有女性角色相互交谈,但在许多情况下,这只是关于男性角色。

《宋飞正传》的主要演员中只有一个女性角色,所以在这次测试中肯定会表现不佳;然而,几乎 90%的剧集都通过了第一步。这通常发生在伊莱恩与场景中的一个次要女性角色短暂重叠的时候。它的通过率在第二步和第三步急剧下降。弗雷泽的表现同样糟糕;虽然它的主要演员中有两个女性角色,罗兹和达芙妮的互动相对较少(这一对的对话只有 14%通过了 BT)。

将结果按节目和季节分类,并对照播出年份,有一些上升趋势的迹象。办公室在运行期间提高了通过率,宋飞和弗雷泽也是如此,但最后几季除外。结了婚有了孩子就往另一个方向走了。由于通过测试的一集通常只由一对说话者完成,结果对每一季的情节弧线很敏感,这些弧线会影响谁出现在场景中以及女性常客与谁相处的时间更长,如图中更易识别的情况所示。

接下来的情节进一步探索了男女角色在每一集里是如何互动的。它使用上面确定的相同行作为两个字符之间来回的一部分,并根据所涉及的一对字符的性别对这些行求和:女性-女性、男性-男性或男性-女性。

《老友记》、《威尔与格蕾丝》和《已婚有儿》中,不同性别角色之间的对话多于同性。这是每个性别可参与故事情节的主要人物数量的函数:在威尔和格蕾丝的极端情况下,如果人物被分成两对,唯一允许同性对话的组合是威尔-杰克和格蕾丝-凯伦,而其他两个可能的配对涉及不同性别的对话。不同性别的角色之间有很多台词会增加通过 BT 的难度;从这个角度来说,最好把男性角色集中在一个故事情节/场景中,女性角色集中在另一个故事情节/场景中。

《宋飞正传》、《弗雷泽》和《办公室》中的男性主角比女性主角多,所以不可避免地男性对话比女性对话多得多。然而,这并不是说这些节目充满了没有女性参与的男性与男性的对话:从 y 轴上没有低于 0.8 的节目这一事实可以看出,这些节目中男性与女性的对话和男性与男性的对话一样多,或者几乎一样多。

最后,虽然我们可以猜测结果会是什么,但我计算了测试的男性对等物:两个男性角色必须谈论女性角色以外的事情。这个测试通过的频率要高得多:几乎每部剧的每一集都通过(蓝色加紫色,如下):

然而,《老友记》、《威尔和格蕾丝》、《已婚并育有子女》确实展示了一些通过 BT 但没有男性版(橙色)的剧集。也有少数剧集没有通过任何一项测试(灰色)。如上所述,当故事情节将不同性别的角色配对在一起时,这种情况就会发生。除了《老友记》、《威尔与格蕾丝》和《已婚并育有子女》,其他剧集的男性角色数量不平衡,因此不太可能没有男性-男性故事情节。

ScrabbleGAN——对手写文本图像的生成

原文:https://towardsdatascience.com/scrabblegan-adversarial-generation-of-handwritten-text-images-628f8edcfeed?source=collection_archive---------20-----------------------

文本生成教程(TensorFlow 2)

照片由莫里茨·施米特Unsplash 上拍摄

1。动机

本文介绍了一个用于对手写文本图像生成的开源项目,它建立在【1,2】中提出的思想之上,并利用了生成对手网络(GANs【3】)的力量。尽管 GANs(特别是 cgan[4]和变体)在研究社区中受到了很多关注,但到目前为止,很少有人关注基于序列的图像生成(不要与文本到图像学习任务(如[5]或[6])相混淆)。此外,最近的工作([1,2])没有共享它们的源代码/评估代码,这使得清晰的比较变得困难,因为并不总是清楚哪个组件导致了改进。在这项工作中,模型/软件在 IAM 手写数据库上进行评估,并提供给社区进行进一步实验。

ScrabbleGAN:第 1 和第 15 纪元之间的训练进度(IAM 手写数据库)

注: 本文不是为了解释最先进的机器学习算法,而是为了突出这个项目中所做的设计决策。技术细节在GitHub repo中有很好的记录,可以在各自的参考文献中找到。

2.背景/相关性

在许多机构(如医疗保健或金融机构)中,手写仍然是数据收集的主要方法。虽然光学字符识别(OCR)现在通常被认为已经解决了,但是(离线)手写识别(HWR)仍然具有挑战性,因此使自动数据处理变得复杂。与印刷文本相比,手写在风格上有很大不同(众所周知,手写就像指纹一样独一无二,不会弄错),因此需要大规模的训练数据。因此,由于 GANs 的流行和成功,越来越多的工作集中在扩展现有数据集上。在接下来的部分中,介绍了两篇最近的论文(本文非常依赖于它们)。

在[1]中,作者训练了一个辅助分类器 GAN (AC-GAN [7]),以便扩展两个基准数据集(法语、阿拉伯语)。这里的主要思想是将每个单词嵌入到一个 128 维的特征向量中(类似于[5]),然后将该向量馈入 BigGAN [8]网络架构。为了控制生成的图像的文本内容,训练 CRNN [9]作为辅助分类器。源自 R 和 D 的梯度被平衡(考虑到它们不同的幅度),并最终反向传播到 G:

来源

尽管他们的工作显示出有希望的结果,但是仍然存在一些限制,这些限制在[2]中进行了阐述:

  • 生成任意长度的 word 图像:
    在[1]中,所有图像都被(白色)填充到相等的大小,同时保持原始的纵横比——超过给定阈值(128×512)的图像被移除。因此,在所有的单词长度上,只能生成相同大小的单词图像。在[2]中,G、D 和 R 都遵循完全卷积范式,这潜在地允许生成完整的句子。
  • 解开生成过程/嵌入: 不是像[1]中那样从整个单词表示中生成图像,而是单独生成每个字符(因此 Scrabble ),使用 CNN 的重叠感受域属性来考虑附近字母的影响。这主要是因为手写是一个局部过程,每个字母只受其前一个和后一个字母的影响。因此,G (D)可以被视为相同的类条件生成器(真实/虚假分类器)的串联:

来源

  • 去除 R 中的循环头 作者[2]发现,更好的 R 不一定带来更好的整体(代)性能。这是因为 CRNN 网络中的 RNN 层学习隐含的语言模型,从而能够识别正确的字符,即使它没有被清楚地书写。因此,为了迫使 R 仅基于视觉特征做出决策,移除了递归头部。

3.方法学

在这项工作中,使用了功能 API定制训练循环。大致结构基于 TensorFlow 教程关于深度卷积生成对抗网络;下一节重点介绍了主要区别。

加载并准备数据集

首先,IAM 手写(单词)数据库被转换成以下格式:

*res/data/iamDB/words-Reading/
    ├── Bucket 1
        ├── img_i.png
        ├── img_i.txt
        ├── ...
    ├── Bucket 2
        ├── ...
    ├── Bucket n*

其中桶 x 保存转录长度为 x 的所有样本,并且 img_i.txt 包含 img_i.png. 的基本事实注释(转录)

为了减少噪声,在本工作中只考虑正确分割的单词([a-zA-Z])(表示为“ok”)。此外,大小为> 的字 bucket_size ( 此处为 10 ) 被忽略,以断言 len(bucket)>>batch _ size。总之,这种预处理策略产生了 80.377 个独特的训练样本。

所有图像都被重新整形,以匹配[2]: (32,16)提出的每个字符的纵横比。例如,转录长度为 10 的单词具有形状(32,160) px。

最后,与 DCGAN-Tutorial 类似,图像被规范化为[-1,1],标签通过 char_vector(此处为:“abc…zA…Z”)进行编码:例如,“auto”变成[0,20,19,14]。

在每个训练步骤,一批随机单词沿着其编码的转录(相同随机桶的)被产生给相应的模型。

创建模型

从根本上说,ScrabbleGAN 是著名的 BigGAN 和 CRNN 架构的混合体。尽管有一些 BigGAN 的开源实现(例如 BigGAN-Pytorchresnet_biggan ),但据我所知,目前还没有“官方”的 TF2 实现。因此,我决定自己在 Tf2 中重写一个简化版的 google/compare_gan 。与原始作品相似,代码可通过 Gin 进行配置:

...
setup_optimizer.r_lr = 2E-4
setup_optimizer.beta_1 = 0.0
setup_optimizer.beta_2 = 0.999
setup_optimizer.loss_fn = @hinge
setup_optimizer.disc_iters=1
...
shared_specs.kernel_reg = @spectral_norm
...
shared_specs.g_bw_attention = 'B3'              
shared_specs.d_bw_attention = 'B1'
...
shared_specs.embed_y = (32, 8192)

CRNN-模型基于 CRNN-Tf2 。所有模型都是利用第 2 节所述的完全卷积范例实现的,以允许灵活的输入和输出形状。最终的“ScrabbleGAN”模型是通过将这些模型堆叠在一起而获得的(复合模型)。

为了简洁起见,感兴趣的读者可以参考 GitHub repo 了解更多信息。

定义损失和优化器

在这项工作中,基于compare _ gan/gans/loss _ lib . py,考虑了“非饱和”和“铰链”损耗。对于 CRNN 部分,照常使用 CTC 损耗

定义训练循环

训练循环从生成器接收一组随机种子和来自随机单词列表(这里: macOS 单词列表)的转录作为输入开始,以产生一组假图像。D(实数)和 R(实数)是分开计算的,而 D(虚数)和 R(虚数)现在是通过复合模型计算的。然后为这些模型中的每一个计算损失,并且梯度被用于更新鉴别器、识别器和复合模型。例如,后者更新如下:

recognizer.trainable = **False** discriminator.trainable = **False** gradients_of_generator = gen_tape.gradient(g_loss_balanced, composite_gan.trainable_variables)
generator_optimizer.apply_gradients(zip(gradients_of_generator, composite_gan.trainable_variables))

注意:在这项工作中,没有梯度平衡导致最好的结果(更多信息可以在各自的参考文献[1,2]中找到)。)

与[1,2]类似,R 只在真实图像上训练,以防止它学习如何识别生成的(和潜在的虚假)图像。

4.结果

所有实验(不同的模型配置)都是使用AWS p 3.2x 大型实例进行的;每个模型被训练 15 个时期。以下是一些直观的结果:

与[2]的比较:来自电影《欢乐满人间》的单词“supercalifragilisticepialidocious”(34 个字母)

更多的例子

更多例子 II

更多例子 III

参考

  1. E.Alonso,B. Moysset,R. Messina,基于序列的手写文本图像对抗生成 (2019),arXiv:1903.00277
  2. 南 Fogel,H. Averbuch-Elor,S. Cohen,S. Mazor,R. Litman, ScrabbleGAN:半监督变长手写文本生成 (2020),arXiv:2003.10557
  3. I. J. Goodfellow,J. Pouget-Abadie,M. Mirza,B. Xu,D. Warde-Farley,S. Ozair,a .,Y. Bengio,生成性对抗性网络 (2014),arXiv:1406.2661
  4. 米(meter 的缩写))米尔扎,s .奥辛德罗,条件生成对抗网 (2014),arXiv:1411.1784
  5. 南 Reed,Z. Akata,X. Yan,L. Logeswaran,B. Schiele,H. Lee,生成性对抗性文本到图像合成 (2016),arXiv:1605.05396
  6. T.乔,张,徐,陶, MirrorGAN:通过重新描述学习文本到图像的生成 (2019),arXiv:1903.05854
  7. A.Odena,C. Olah,J. Shlens,使用辅助分类器的条件图像合成 GANs (2016),arXiv:1610.09585
  8. A.Brock,J. Donahue,K. Simonyan,用于高保真自然图像合成的大规模 GAN 训练 (2018),arXiv:1809.11096
  9. B.石,x .白,c .姚,基于图像序列识别的端到端可训练神经网络及其在场景文本识别中的应用 (2015),arXiv:1507.05717

刮疾控中心为新冠肺炎病例

原文:https://towardsdatascience.com/scrape-cdc-for-covid-19-cases-a162924073ad?source=collection_archive---------33-----------------------

如何为已确认的新冠肺炎病例抓取 javascript 生成的表格

鉴于最近发生的事件,我认为获取美国各州确诊病例的数据是个好主意。虽然,CDC 网站因为没有及时更新和落后于实际传播和病例而受到了一定的批评,但由于它是确诊病例的唯一官方来源,它仍然是每天收集数据的一个很好的来源。

我们需要几个库:常见的请求、漂亮的 soup 和 selenium,因为 CDC 网站上的表格是 javascript 生成的。此外,除了 selenium 之外,我们还需要一个驱动程序,我更喜欢 chrome,因为使用 Chrome 更容易检查网站。你可以在这里下载 chromedriver ,确保下载与你的 chrome 浏览器兼容的版本。也正则表达式来清理数据和熊猫创建一个数据帧,并保存为 csv。

import re
import pandas as pd
import requests
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

让我们从用 chrome 驱动程序的显式路径声明 url 和驱动程序变量开始。美丽的汤将解析通过驱动程序的 page_source 和 get_info 函数将返回一个字典与总美国案件和更新日期。

url = '[https://www.cdc.gov/coronavirus/2019-ncov/cases-in-us.html'](https://www.cdc.gov/coronavirus/2019-ncov/cases-in-us.html')driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
    driver.get(url)
wait = WebDriverWait(driver, 10)
soup = BeautifulSoup(driver.page_source, 'html.parser')
dic = get_info(soup)
print(dic)

下面是获取这些数据的函数:

def get_info(info):
    date = info.find('span', class_="text-red").text
    summary = info.find('div', class_ = "2019coronavirus-summary").find_all('li')
    for i in summary:
        dic = {
            'total': summary[0].text,
            'deaths': summary[1].text,
            'jurisdictions': summary[2].text
        }
    dic['date'] = date
    return dic

请记住,例如,如果类名发生变化,函数可能需要更改。该函数的输出:

{'total': 'Total cases: 44,183',
 'deaths': 'Total deaths: 544',
 'jurisdictions': 'Jurisdictions reporting cases: 54 (50 states, District of Columbia, Puerto Rico, Guam, and US Virgin Islands)',
 'date': 'Updated March 24, 2020'}

我在 3 月 17 日第一次运行刮刀,我们来比较一下:

美国新冠肺炎病例总数

天哪,这些数字太可怕了,仅在 7 天内,冠状病毒病例数上升了 10 倍,死亡人数上升了 8 倍。认为这些数字可能落后于确诊病例的实际数量,并且有大量患有冠状病毒症状的人由于处于低风险群体而无法进行测试。但是我跑题了,所以为了得到美国各州的病例数,我们需要点击一个按钮来展开表格,用绿色圈起来的那个:

由于这是一个 iframe 对象,我们需要切换到 frame,等待数据变得可见,然后我们需要向下滚动页面,以便我们可以收集我们正在寻找的数据:

wait.until(EC.frame_to_be_available_and_switch_to_it("cdcMaps1"))
wait.until(EC.element_to_be_clickable((By.TAG_NAME, 'h3'))).click()
element = driver.find_element_by_tag_name('h3')
driver.execute_script('return arguments[0].scrollIntoView(true);', element)
for table in driver.find_elements_by_xpath('//[[@id](http://twitter.com/id)="root"]/section/section/div'):
        header = [item.text for item in table.find_elements_by_xpath('//[[@id](http://twitter.com/id)="root"]/section/section/div/div[1]/div[1]')]
        print(header)
for table in driver.find_elements_by_xpath('//[[@id](http://twitter.com/id)="root"]/section/section/div'):
        data = [item.text for item in table.find_elements_by_xpath('//[[@id](http://twitter.com/id)="root"]/section/section/div/div[1]/div[2]')]
        print(data)

在上面的代码片段中,在驱动程序向下滚动查看表格后,它通过 xpath 收集表格标题和数据抓取。Xpaths 不容易改变,这允许构建更健壮的 scraper 脚本,selenium 允许我们这样做。不要忘记退出 webdriver,即使你的代码引发了异常,这里是完整的代码:

该查询的结果将是一个需要清理并保存到 csv 中的列表。3 月 24 日的数字是:

2019 年 3 月 24 日州级新冠肺炎案件

2019 年 3 月 24 日州级新冠肺炎案例(续)

谢谢你的时间和阅读我的帖子。一如既往,我们随时欢迎您的反馈和建议。

在 2 分钟内从 Indeed 上刮下公司评论和评级

原文:https://towardsdatascience.com/scrape-company-reviews-ratings-from-indeed-in-2-minutes-59205222d3ae?source=collection_archive---------23-----------------------

网络抓取,数据科学

网上搜集员工在线评论

来源:来自 pixabay 的 ranjithsiji

在本教程中,我将向你展示如何使用 Anaconda Jupyter 笔记本和 BeautifulSoup 库来执行网络抓取。

我们将从 Indeed platform 收集公司评论和评级,然后将它们导出到 Pandas library dataframe,再导出到一个. CSV 文件。

让我们直接进入正题,然而,如果你正在寻找一个理解网络抓取的指南,我建议你阅读来自 Dataquest 的这篇文章。

让我们从导入我们的 3 个库开始

from bs4 import BeautifulSoup
import pandas as pd
import requests

然后,让我们去 indeed 网站查看我们想要的信息,我们将针对安永公司的页面,你可以从以下链接查看

[https://www.indeed.com/cmp/Ey/reviews?fcountry=IT](https://www.indeed.com/cmp/Ey/reviews?fcountry=IT)

根据我的位置,国家是意大利,但你可以选择和控制,如果你想。

在下一张图中,我们可以看到我们可以处理和收集的多种信息:

1-评论标题

2-审查机构

三级

4-审核者的角色

5-审查者的位置

6-审查日期

然而,你可以注意到第 4,5 和 6 点都在一条线上,将被刮到一起,这可能会给一些人造成一点混乱,但我的建议是先刮,然后再解决问题。所以,让我们试着这样做。

在知道了我们要刮什么之后,我们需要弄清楚我们需要刮多少,我们是不是只想要 1 条评论?1 页评论还是所有页面评论?我猜答案应该是全页!!

如果您向下滚动页面,转到第 2 页,您会发现该页的链接如下所示:

[https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start=](https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start=40)20

然后试着进入第 3 页,你会发现链接变成了如下:

[https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start=4](https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start=40)

看起来我们这里有一个模式,第 2 页=20,第 3 页= 40,然后第 4 页= 60,对吗?一直到第 8 页= 140

让我们回到编码,从定义你想要的数据帧开始。

df = pd.DataFrame({‘review_title’: [],’review’:[],’author’:[],’rating’:[]})

在下一段代码中,我将创建一个 for 循环,从 0 开始,跳到 20,在 140 停止。

1-在 for 循环中,我们将向 web 服务器发出一个GET请求,它将为我们下载给定网页的 HTML 内容。

2-然后,我们将使用 BeautifulSoup 库来解析这个页面,并从中提取文本。我们首先必须创建一个BeautifulSoup类的实例来解析我们的文档

3-然后通过检查 html,我们从网页中选择类,在抓取时使用类来指定我们想要抓取的特定元素。

4-然后我们可以通过将结果添加到之前创建的数据框架中来结束。

“我加了一张图下来说明代码应该是怎样的,以防你复制的时候加错了一些空格”

for i in range(10,140,20):
     url = (f’[https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start={i}'](https://www.indeed.com/cmp/Ey/reviews?fcountry=IT&start={i}'))
     header = {“User-Agent”:”Mozilla/5.0 Gecko/20100101 Firefox/33.0 GoogleChrome/10.0"}
     page = requests.get(url,headers = header)
     soup = BeautifulSoup(page.content, ‘lxml’)
     results = soup.find(“div”, { “id” : ‘cmp-container’})
     elems = results.find_all(class_=’cmp-Review-container’)
     for elem in elems:
         title = elem.find(attrs = {‘class’:’cmp-Review-title’})
         review = elem.find(‘div’, {‘class’: ‘cmp-Review-text’})
         author = elem.find(attrs = {‘class’:’cmp-Review-author’})
         rating = elem.find(attrs = {‘class’:’cmp-ReviewRating-text’})
         df = df.append({‘review_title’: title.text,
          ‘review’: review.text,
        ‘author’: author.text,
          ‘rating’: rating.text
            }, ignore_index=True)

完成了。让我们检查一下数据框

df.head()

现在,一旦刮,让我们试着解决我们的问题。

请注意,作者可能有 3 个不同的信息,用(-)分隔

所以,让我们把它们分开

author = df[‘author’].str.split(‘-’, expand=True)

现在,让我们重命名这些列并删除最后一列。

author = author.rename(columns={0: “job”, 1: “location”,2:’time’})del author[3]

然后,让我们将这些新列连接到原始数据框架,并删除旧的 author 列

df1 = pd.concat([df,author],axis=1)
del df1[‘author’]

让我们检查一下新的数据框架

df1.head()

让我们重新组织这些列并删除任何重复的内容

df1 = df1[[‘job’, ‘review_title’, ‘review’, ‘rating’,’location’,’time’]]
df1 = df1.drop_duplicates()

最后,让我们将数据帧保存到 CSV 文件中

df1.to_csv(‘EY_indeed.csv’)

现在,您应该对如何从 Indeed 中提取数据有了很好的理解。一个很好的下一步,如果你对网络抓取有点熟悉,你可以选择一个网站,自己尝试一些网络抓取。

快乐编码:)

从古代网站上搜集中世纪的资料

原文:https://towardsdatascience.com/scrape-medieval-data-from-an-ancient-website-684d9653f34a?source=collection_archive---------70-----------------------

使用 Selenium 和 Python 从过时和异常的网站中提取数据

安娜·格鲁在 Unsplash 上的照片

TLDR;你可以使用 Selenium 和 Python 来清理过时的网站。尽管这个例子看起来很深奥,但是在处理那些很难从他们的平台或奇怪配置的 Sharepoints 导出数据的数据供应商时,可以使用相同的原则。
如果你想访问 Jupyter 笔记本,你可以从我的 GitHub 账户下载

介绍

获取数据往往是数据科学的 yada-yada-yada 阶段。数据库通常是 IT 基础架构中最古老的部分,访问它们可能相当具有挑战性。

在某种程度上,每个数据专业人员都必须从古董数据库中提取信息。

罗格斯大学的中世纪和早期现代数据库(MEMDB)就是这样一个数据库。

了解网站

这个特殊的网站是在 90 年代中期建立的,当时的假设是合理的。我们的样本数据将是 MEMDB 中的 Prices (Metz) 数据库。

它的接口(如下)充当了一个 web 接口,我假设它是一个 SQL server。

作者照片

搜索框充当我们查询的参数,然而,我更感兴趣的是将所有数据放入 pandas 数据框架中,这样我可以更有效地操作它。

如果我们只单击按钮 submit query,它就相当于 SQL:

SELECT * FROM PRICES(METZ)

这将我们带到下一个网页:

作者照片

由于 90 年代中期的带宽限制,网站一次只返回 100 行数据。

更重要的是,共享 url 实际上并不调用数据库,你需要点击一个链接才能做到这一点,所以像 Beautiful Soup 这样更有效的网络抓取工具将无法工作。

幸运的是,我们可以使用 Python 的 Selenium 模块来抓取这些数据!

零件清单:

  • 浏览器驱动(我用的是 Chrome 驱动)
  • 对 HTML 的基本理解
  • 熊猫
  • 浏览器检查工具

有关安装说明,您可以访问 Selenium 文档

步骤 1:导入模块

#webscraper tool
from selenium import webdriver#Technically unneccesary, but I like to time how long some operations take
from datetime import datetime# For cleaning up data
import pandas as pd

第二步:设置驱动程序并导航到我们想去的网站

这里我们定义了我们试图抓取并打开的网站的根目录

# Instantiates the driver
driver = webdriver.Chrome()#I set the root of all the databases as the base for selenium so I #can recycle the code to scrape the other databases
home = '[http://www2.scc.rutgers.edu/memdb/database_list.html'](http://www2.scc.rutgers.edu/memdb/database_list.html')#Tells selenium to go to the base url
driver.get(home)

第三步:浏览网站

我们面临的一大挑战是,引导这个网站的 HTML 是古老的。幸运的是,我们需要点击的第一个链接确实有可识别的链接文本,所以我们可以告诉 selenium 找到链接文本。

作者图片

#This is the name of the link text in the first link
first_link = 'Prices (Metz)'#This is the command that tells Selenium to click the first link:
driver.find_element_by_link_text(first_link).click()

不幸的是,这是我们最后一次看到像标准 HTML 这样的东西

我们现在在数据库交互工具中,需要单击“提交查询”按钮:

作者图片

要点击“提交查询”按钮,我们需要使用 find_element_by_xpath 函数。我们可以通过使用浏览器检查器,使用“元素选择工具”选择按钮,并使用复制 xpath 功能来找到 xpath:

作者图片

导航到该表的代码如下:

#found by using the copy xpath tool in the browser inspector
second_link = '/html/body/main/table/tbody/tr/td[2]/form/p/input'#clicks the button
driver.find_element_by_xpath(second_link).click()

步骤 4:设置循环

现在我们实际上在表中。

作者图片

通过查看表的顶部,我们知道两件事,我们知道数据库中有多少行数据(39,973)以及一次将显示多少行(100)。

39,973/100 = 399.73,四舍五入到 400。我们知道我们需要遍历这个表的 400 个版本。

我们还需要一个文件来保存我们的信息。

我们将使用内置的 python 函数 open 来创建一个新的空。txt 文件。

# name of our text file
filename = 'Metz_prices_demo.txt'
# creates .txt file
file_object  = open(filename, "w+")

我们还需要设置一个计数器,并设置要追加的文本文件。
我还在这里包含了一个时间戳,因为这是我们的 while 循环的开始,我想知道运行它需要多长时间:

# Starts our counter for our while loop
counter = 0
# Sets our file to have table data appended to it
export = open(filename, 'a')
# Optional, but I like to time how long certain functions take
start = datetime.now()

while 循环由两部分组成:

  • 从页面获取表格数据并将其附加到。txt 文件
  • 让我们进入下一页的部分

第一部分:

我们根据我们知道必须循环的页数来设置 while 循环。

然后,我们使用代码检查工具来查找表的 xpath,就像我们以前做的一样。

然后,我们将表数据加载到一个变量中,并将该数据写入我们的。txt 文件,并创建一个新行以使以后的数据处理更容易:

# While loop that goes through each page and saves the data
while counter < 401:
    # The location of the table on every page
    table_loc = '/html/body/form/main/table/tbody/tr/td[2]/p[3]/table/tbody'
    # The selenium function that gets the data from the table and loads it into a variable
    page_text = driver.find_element_by_xpath(table_loc).text
    # The function that writes the table data into our .txt file
    export.write(page_text + '\n')

第二部分:

现在页面的数据已经复制到文件中,我们需要移动到下一页;但是有一个问题。移动到下一页有两种 html 格式。

在第一页上,只有一个按钮,因为只有一条路可走。

作者图片

在第二页以及除最后一页之外的所有其他页面上,我们有两个按钮,因为我们可以前进或后退:

作者图片

两种格式的 xpaths 略有不同:

  • /html/body/form/main/table/tbody/tr/TD[2]/center[3]/input
  • /html/body/form/main/table/tbody/tr/TD[2]/center[3]/input[2]

幸运的是,我们可以通过一个 try 块来解决这个问题,该块将尝试单击更常见的按钮配置,如果失败,将恢复到不太常见的配置:

try:
        # More common page layout
        button_path = '/html/body/form/main/table/tbody/tr/td[2]/center[3]/input[2]'
        driver.find_element_by_xpath(button_path).click()
    except:
        # Less common page layout
        button_path = '/html/body/form/main/table/tbody/tr/td[2]/center[3]/input'
        driver.find_element_by_xpath(button_path).click()
    # Adds 1 to the counter
    counter += 1

完整的 while 循环:

# Starts our counter for our while loop
counter = 0
# Sets our file to have table data appended to it
export = open(filename, 'a')
# Optional, but I like to time how long certain functions take
start = datetime.now()# While loop that goes through each page and saves the data
while counter < 401:
    # The location of the table on every page
    table_loc = '/html/body/form/main/table/tbody/tr/td[2]/p[3]/table/tbody'
    # The selenium function that gets the data from the table and loads it into a variable
    page_text = driver.find_element_by_xpath(table_loc).text
    # The function that writes the table data into our .txt file
    export.write(page_text + '\n')
    try:
        # More common page layout
        button_path = '/html/body/form/main/table/tbody/tr/td[2]/center[3]/input[2]'
        driver.find_element_by_xpath(button_path).click()
    except:
        # Less common page layout
        button_path = '/html/body/form/main/table/tbody/tr/td[2]/center[3]/input'
        driver.find_element_by_xpath(button_path).click()
    # Adds 1 to the counter
    counter += 1# Timestamps the end of the loop
end = datetime.now()
# Calculates the duration of the loop
duration = end - start#Prints the duration
print(duration)

步骤 5:将数据加载到 Pandas 中进行清理

现在我们已经将数据加载到一个. txt 文件中,我们可以将它加载到 Pandas 来清理它。

我们有三个主要的数据清理问题需要解决:

  1. 每 100 行中有一行带有标题
  2. 我们需要正确配置我们的列名
  3. 如果我们设置我们的计数器运行太多次,我们将有一些重复的行

幸运的是,建立这个数据库的人知道他们在做什么,并给了我们一个方便的名为“Num”的索引列

正在加载。txt 转换成数据帧:

因为标题与数据行的格式略有不同,所以我们应该手动设置列名

column_names = ['Num', 'Year', 'Month', 'Week', 'Product', 'Number_of_Malters_Sold', 'Currency', 'Price_per_Malter']

然后我们将使用 pd.read_csv()函数,它可以读取许多文本文件格式。通过基本的实验,我发现列分隔符是两个空格,我们需要跳过文件的前 3 行来加载数据。

# Opens the .txt, uses the two space delimeter, skips the first 3 #rows, and sets the column names to the list of names above
df = pd.read_csv('Metz_prices_demo.txt', sep = '  ', skiprows = 3, names = column_names, header = None)

删除无关的列标题:

使用 iloc 函数快速检查一下数据帧,会发现每 100 行就有一个标题

#Shows a header row that we need to clean
df.iloc[[100]]

幸运的是,数据库工程师知道他在做什么,我们可以通过从数据帧中移除所有在“Num”列中有字母的行来轻松移除这些。

# Removes all rows from the dataframe where the contents of the 'Num' column have letters in them
df = df[~df['Num'].str.contains("[a-zA-Z]").fillna(False)]

删除重复行:

我们的最后一个挑战是删除任何可能进入数据帧的重复行,这通常是由于将 while 限制设置得太高。同样,我们可以使用方便的“Num”列,因为作为数据库的索引,不应该有重复的数字。为了整洁起见,我们还应该重置数据帧的索引

# Removes duplicate rows that we might have accidentally grabbed from the data
df.drop_duplicates(subset = ['Num'], keep = 'first', inplace = True)
df.reset_index(inplace = True)

结论

Selenium 在自动化繁琐的数据获取任务方面有很多价值,尤其是在异常的 web 环境中。

如果你想看到整个 Jupyter 笔记本,或者抓住最后。csv 你可以从我的 GitHub 账户获得。

注册我的月度时事通讯,获得我这个月读过的最好的文章,以及最近的文章。

关于作者:

Charles Mendelson 是 PitchBook 的营销数据分析师。在过去的五年里,他一直在销售和营销机构工作,并在许多工作面试中取得了成功(但失败的机会更多)。他还获得了哈佛扩展学校的心理学硕士学位。如果你在寻找一个会议或研讨会的演讲者,或者如果你想问任何问题,你可以在 LinkedIn 上联系他:他有时会在那里发表文章。

参考资料:
[1]货币交易所(梅斯)包含 Rainer Metz 的货币数据, Geld,whrung und Preisentwicklung:der Niederrheinraum im europischen Vergleich,1350-1800(法兰克福,1990 年)。

用 Python 抓取表格数据

原文:https://towardsdatascience.com/scrape-tabular-data-with-python-b1dd1aeadfad?source=collection_archive---------19-----------------------

如何在 Python 中使用 BeautifulSoup,Selenium,Pandas 来抓取 NBA 球员的数据?

马库斯·斯皮斯克在 Unsplash 上的照片

O 执行机器学习项目的瓶颈之一是数据集组装。

数据集合的方式因数据类型而异,其中从 web 上抓取表格数据集是最典型的来源之一。我已经用了很长时间来高效地获取我需要的尽可能多的数据。

我用 NBA 球员的数据作为原始数据写了一段时间关于机器学习技术的文章。我最常被问到的一个问题是,我是否可以分享这些数据,因为人们喜欢玩这些数据。

亚洲有句老话,

给一个人一条鱼,你可以喂他一天;教一个人钓鱼,你就喂了他一辈子。

所以,在这篇文章中,我想和你分享如何用 Python 从网上抓取表格数据。

除了标准步骤,我还会介绍我遇到的实际问题以及解决这些问题的解决方案

准备工具

pip install beautifulsoup4 
pip install selenium
pip install requests
pip install pandas

上面的代码显示了完成这项工作所需的四个 python 包的安装,大多数时候它们已经足够了。

成功安装这些包后,只需将它们导入到 python 环境中。

import requests
from bs4 import BeautifulSoup
from selenium import webdriver
import pandas as pd

如果您使用谷歌 Chrome 作为您的默认浏览器,请确保 chromedriver 在您的 路径 中是可执行的。如果没有,你可能会遇到和我一样的问题,错误信息如下。

消息:“chromedriver”可执行文件需要位于路径中

要解决这个问题,只需从https://sites.google.com/a/chromium.org/chromedriver/home下载 chromedriver 并将其放入可执行路径或将其当前位置添加到系统 path 变量中。

要将其位置添加到 PATH 中,请打开~/。输入 bash_profile

vi ~/.bash_profile

然后将下面一行添加到文件的末尾,

# add chromedriverexport PATH="/Users/yourdirectorytoCHROMEDIRVER:$PATH"

要检查 chromedriver 是否可执行,只需在终端中键入 chromedriver 就可以看到来自软件包的消息,

宇峰运行 chromedriver

到目前为止,我们已经有了所有需要的工具。

检查网页

首先,我们需要找到一个目标页面。我将使用来自 篮球-参考 的 NBA 球员统计页面作为本教程的示例。这是我的目标页面的 URL:

URL = [https://www.basketball-reference.com/players/i/irvinky01.html](https://www.basketball-reference.com/players/i/irvinky01.html)

为了从特定的网页中抓取数据,我们需要从开发者的角度了解它的结构。右键点击页面,左键点击' 检查 '按钮,如下图。

通过玉峰检查页面视图

然后你会在右边看到如下图的网页脚本。

通过玉峰检查页面视图

上面显示的信息很难让人读懂,但是仔细检查后,您可能会发现一些模式。

例如,页面上的表格总是以 <表… > 开始,以</表> 结束(在上图中以蓝色突出显示)。这些表格正是我想要的。

擦桌子

现在,我们将使用 Beautifulsoup 从页面中删除这些表格。从页面中获取所有表格的标准方法是,

page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
tables = soup.find_all("table")

其中requests . get(URL)基本上是从页面中获取信息beautiful soup(page . content,' html.parser') 是解析信息。

然后我们可以将 find_all 函数应用于 soup 中解析的信息。soup . find _ all(" table ")正在收集以 <表> 开始,以</表> 结束的所有信息块。

对于变量中的每一个,通常情况下,表头从第<>开始,所有行的表格单元格都从 < td > 开始。因此,可以在下面的代码中提取该表并将其转换为 pandas 数据帧。

table = tables[0]
tab_data = [[cell.text for cell in row.find_all(["th","td"])]
                        for row in table.find_all("tr")]
df = pd.DataFrame(tab_data)

生成的数据帧如下:

玉凤创作的 df

要将第一行移到标题,只需键入

df.columns = df.iloc[0,:]
df.drop(index=0,inplace=True)

为了以与第一个表相同的方式获取页面中的所有表( tables[0] ),我创建了一个字典,并使用每个表的属性‘id’作为 for 循环中的键。

tabs_dic = {}

for table in tables:
    tab_name = table['id']

    tab_data = [[cell.text for cell in row.find_all(["th","td"])]
                        for row in table.find_all("tr")]
    df = pd.DataFrame(tab_data)
    df.columns = df.iloc[0,:]
    df.drop(index=0,inplace=True)

    #df = df.loc[df.Season != ""]
    tabs_dic[tab_name] = df

我之所以能够通过 table['id'] 提取牌桌 id,是因为 'id' 是牌桌的一个属性,是 'per_game' 如下图,

表属性由郁风

这样,我应该将所有的 pandas 数据帧格式的表存放在大字典 tabs_dic 中。

然而,我遇到了一个问题…

抓取多个表的问题

当我第一次尝试调查玩家页面上的牌桌号时,我发现了这个问题,我只从上面刮到了一张牌桌!!!

我确实用了 find_all("table") 如前面代码所示,怎么可能漏掉除了第一个以外的所有其他表呢?!

我检查了页面上的表的类型,发现从我的抓取中逃脱的表是 javascript 中的表。

然后,硒被用来解决这个问题。

driver = webdriver.Chrome()
driver.get(URL)
soup = BeautifulSoup(driver.page_source,'html')
driver.quit()
tables = soup.find_all('table')

上面的代码解决了这个问题,成功地获得了 75 个表格。

我又糊涂了,因为 75 对我来说太多了。我一遍又一遍地检查网页,发现即使有些块以开头,它们也只存放一两个值,不是我想要的表。

因此,我进一步修改了代码,根据表的 属性选择页面上的几个表类。

tables = soup.find_all('table',{"class":["row_summable sortable stats_table now_sortable","suppress_all sortable stats_table now_sortable","sortable stats_table now_sortable","suppress_glossary sortable stats_table now_sortable"]})

其中 类的 信息是以字典格式传递给函数的。

最后一共弄了 22 桌。

从篮球参考资料中抓取 NBA 球员数据的功能

要求球员的统计数据是我最频繁的操作之一,所以我写了一个大函数供将来使用。

def get_all_tabs_of_player_page(URL = '[https://www.basketball-reference.com/players/i/irvinky01.html'](https://www.basketball-reference.com/players/i/irvinky01.html')):
    driver = webdriver.Chrome()
    driver.get(URL)
    soup = BeautifulSoup(driver.page_source,'html')
    driver.quit()
    tables = soup.find_all('table',{"class":["row_summable sortable stats_table now_sortable","suppress_all sortable stats_table now_sortable","sortable stats_table now_sortable","suppress_glossary sortable stats_table now_sortable"]})
    tabs_dic = {}

    for table in tables:
        tab_name = table['id']

        tab_data = [[cell.text for cell in row.find_all(["th","td"])] for row in table.find_all("tr")]
        df = pd.DataFrame(tab_data)
        df.columns = df.iloc[0,:]
        df.drop(index=0,inplace=True)

        tabs_dic[tab_name] = df

    return tabs_dic

网页抓取是一项强大的技能,尤其是对于有兴趣将机器学习技术应用于 一些有趣的领域 的人来说。

例如,刮削技能是我写的关于机器学习和篮球的所有后续帖子的基础。

[## 谁是本赛季 NBA 的最有价值球员?

一个案例研究,展示一个机器学习项目从开始到结束的样子。

towardsdatascience.com](/whos-the-mvp-of-nba-this-season-3e347c66a40a) [## 给出了随机森林分类器的特征重要性

如何建立一个随机森林分类器,提取特征重要性,并漂亮地呈现出来。

towardsdatascience.com](/present-the-feature-importance-of-the-random-forest-classifier-99bb042be4cc) [## 使用三种机器学习模型基于勒布朗数据的端到端游戏预测方案

综合指导一个二元分类问题使用三个不同的分类器,包括逻辑…

towardsdatascience.com](/end-to-end-project-of-game-prediction-based-on-lebrons-stats-using-three-machine-learning-models-38c20f49af5f)

通常,在获得我们想要的数据后,下一步是建模部分之前的数据可视化。然而,数据可视化超出了本文的范围。有兴趣的可以参考我关于它的一个帖子:

[## NBA 球员统计数据 R 包“ggplot2”中数据可视化的实践指导

应用于 NBA 数据的 R 数据可视化工具“ggplot2”的 6 分钟之旅。

towardsdatascience.com](/hands-on-guidance-of-data-visualization-in-r-package-ggplot2-of-nba-players-stats-d812ed272d66)

就是这样!干杯!现在您应该知道如何用 Python 抓取表格数据了。

参考资料:

  1. https://www.crummy.com/software/BeautifulSoup/bs4/doc/#
  2. https://www.basketball-reference.com/
  3. https://stack overflow . com/questions/46305314/using-beautiful soup-to-scrape-tables-with-comment-tags
  4. https://sites . Google . com/a/chrome . org/chrome driver/downloads

塞勒斯·克罗桑在 Unsplash 上拍摄的照片

用 10 个简单的步骤搜集 1000 篇新闻文章

原文:https://towardsdatascience.com/scraping-1000s-of-news-articles-using-10-simple-steps-d57636a49755?source=collection_archive---------0-----------------------

如果你遵循这 10 个简单的步骤,使用 python 进行网络抓取是非常简单的。

迈克尔·波德格在 Unsplash 上的照片

网页抓取系列:使用 Python 和软件

Part-1: 不使用软件抓取网页:Python

第二部分: 利用软件抓取网页:octoporse

目录

1。简介

1.1 为什么写这篇文章?

谁应该阅读这篇文章?

2。概述

2.1 网页设计和 HTML 简介

2.2 使用 PYTHON 中的 BeautifulSoup 进行网页抓取

3。建议&结论

3.1 完整代码

介绍

为什么是这篇文章?

这篇文章的目的是使用 Python 从不同的网站收集新闻文章。一般来说,网络搜集包括访问大量网站并从这些网站收集数据。然而,我们可以限制自己从单一来源收集大量信息,并将其用作数据集。

网络抓取是一种用于从网站提取大量数据的技术,通过这种技术,数据被提取并以表格(电子表格)格式保存到您计算机中的本地文件或数据库中。

因此,当我在假新闻检测系统上进行我的机器学习项目时,我有动力去做网络搜集。每当我们开始一个机器学习项目时,我们首先需要的是一个数据集。虽然您可以在网上找到许多包含各种信息的数据集,但有时您希望自己提取数据并开始自己的调查。我需要一个数据集,但我无法根据需要在任何地方找到它。

资料来源:giphy.com

因此,这促使我相应地为我的项目制作我自己的数据集。这就是我如何从零开始做我的项目。我的项目基本上是基于将不同的新闻文章分为两大类假的 & 真的

假新闻数据集

对于这个项目,第一个任务是获得一个已经标记有“的数据集,因此这可以通过从一些经过验证的&认证新闻网站抓取数据来实现,我们可以依赖这些数据来获取新闻文章的事实,而获得真正的“假新闻确实是一个非常困难的任务。
我浏览这些新闻网站来获取我的假新闻数据集

  • Boom Live
  • Snopes
  • 政治事实
  • 所有方面

但是老实说,我最终还是从一个网站上搜集数据,即 Politifact。
有很强的理由这样做,当你浏览上面列出的链接时,你会得出结论,我们需要一个已经标记了类别的数据集,即“假的”,但我们也不希望我们的新闻文章以这样的形式修改。我们希望提取一篇原始新闻文章,其中没有任何指定数据集中给定新闻文章是否“虚假”的关键字。
因此,例如,如果您通过链接“BoomLive.in ”,您会发现指定“FAKE”的新闻文章并不是其实际形式,而是根据事实核查小组的一些分析进行了修改。因此,这种在 ML 模型训练中修改过的文本每次都会给我们一个有偏见的结果,而我们使用这种数据集制作的模型将导致一个哑模型,它只能预测带有关键字的新闻文章,如“假的”,“做了吗?”,“是吗?”并且在新的测试数据集上不会有很好的表现。
这就是为什么我们使用 Politifact 来搜集我们的“假新闻数据集”。

真实新闻数据集

第二项任务是创建一个"真实新闻"数据集,因此,如果您从诸如" TOI "、"今日印度"、" TheHindu" &等如此之多的可信或经过验证的新闻网站上搜集新闻文章,这是很容易的……因此,我们可以相信这些网站列出的是事实/实际数据,即使不是,我们也会假设它们是真实的,并相应地训练我们的模型。
但是对于我的项目,我只从一个网站(即 Politifact.com)抓取真实虚假的数据,因为我从它那里得到了我所需要的,而且当我们使用 python 抓取数据时,建议一次只使用一个网站。虽然您可以通过运行一个外部 for 循环在一个模块中抓取特定网站的多个页面。

世卫组织应该读读这篇文章?

无论谁在从事需要收集成千上万数据的项目,这篇文章绝对适合你😃。不管你是否有编程背景,因为很多时候,除了来自不同背景的程序员之外,其他人也需要数据来完成他们的项目、调查或其他任何目的。

但是非程序员发现理解任何编程语言都很困难,所以我将通过介绍一些软件让他们也能轻松地放弃,他们可以轻松地从这些软件中抓取大量的任何类型的数据。

虽然使用 python 抓取并不困难,如果你在阅读这篇博客的时候跟着我的话😎,你唯一需要关注的是网页的 HTML 源代码。一旦你能够理解网页是如何用 HTML 编写的,并且能够识别你感兴趣的属性和元素,你就可以抓取任何网站。

对于非程序员来说,如果你想用 python 做网页抓取,只需要主要关注 HTML 代码,python 的语法并没有那么难理解,它只是一些你需要记住和理解的库、函数和关键字。所以我试着用透明的方式解释每一步,我希望在这个系列的最后,你将能够了解不同类型的网页布局。

概观

这篇文章涵盖了第一部分:使用 PYTHON 的新闻文章 web 抓取。我们将创建一个脚本,从不同的报纸中抓取最新的新闻文章并存储文本,然后将这些文本输入到模型中,以获得对其类别的预测。

网页设计和 HTML 简介:

如果我们希望能够从网站中提取新闻文章(或者,事实上,任何其他类型的文本),第一步就是要知道网站是如何工作的。

我们将通过一个例子来理解这一点:

当我们将一个 URL 插入网络浏览器(如 Google Chrome、Firefox 等)并访问它时,我们看到的是三种技术的结合:

HTML(超文本标记语言):它是给网站添加内容的标准语言。它允许我们在网站上插入文本、图片和其他东西。一句话,HTML 定义了互联网上每个网页的内容。

CSS(层叠样式表):这种语言允许我们设置网站的视觉设计。这意味着它决定了网页的风格/外观,包括颜色、布局和字体。

JavaScript: JavaScript 是一种动态的计算机编程语言。它允许我们使内容和风格交互&提供了客户端脚本和用户之间的动态接口。

注意这三种都是编程语言。它们将允许我们创建和操作网页设计的每一个方面。

让我们用一个例子来说明这些概念。当我们访问 Politifact 页面时,我们会看到以下内容:

截图来自 Politifact 网站

如果我们禁用了 JavaScript ,我们将无法再使用此弹出窗口,正如您所见,我们现在看不到视频弹出窗口:

截图来自 Politifact 网站

如果我们在 inspect 窗口中使用 ctrl+F 找到 CSS 元素,然后将其从网页中删除,我们将会看到如下内容:

截图来自 Politifact 网站

所以,现在,我会问你一个问题。

如果想通过抓取网页内容,需要从哪里查找?

所以,在这一点上,我希望你们都清楚我们需要搜集什么样的源代码。是的,你是绝对正确的,如果你正在考虑 HTML 的话😎

所以,执行 web 抓取方法之前的最后一步是理解 HTML 语言。

HTML

HTML 语言是一种超文本标记语言,它定义了网页的内容,由元素和属性构成,为了抓取数据,你应该熟悉检查那些元素。**

  • 一个元素可以是一个标题、段落、分部、锚定标签等等…
  • 一个属性可以是标题是粗体字母。
    这些标签用开始符号<tag>和结束符号</tag>
    表示,

**`

This is paragraph.

This is heading one in bold letters

`**

使用 PYTHON 中的 BeautifulSoup 进行网页抓取

说够了,给我看看代码。

资料来源:giphy.com

步骤 1:安装软件包

我们将首先开始安装必要的软件包:

1.beautifulsoup4
要安装它,请在您的 python 发行版中键入以下代码。

**! pip install beautifulsoup4**

bs4 包下的 BeautifulSoup 是一个库,用于以一种非常简单方便的方式将 HTML & XML 文档解析为 python,并通过使用标签和属性来识别元素来访问元素。

它非常容易使用,但非常强大的软件包提取任何类型的数据从互联网上只有 5-6 行。

2.requests

要安装它,请在 IDE 中使用以下命令,或者在命令外壳中使用不带感叹号的命令。

**! pip install requests**

为了给 BeautifulSoup 提供任何页面的 HTML 代码,我们需要请求模块。

3.urllib
要安装它,使用以下命令:

**! pip install urllib**

urllib 模块是 python 的 URL 处理模块。它用于获取 URL(统一资源定位符)

虽然,在这里我们使用这个模块是为了不同的目的,来调用像这样的库:

  • time(使用它我们可以调用 sleep()函数来延迟或暂停执行给定的秒数。
  • sys(此处用于获取异常信息,如错误类型、错误对象、关于错误的信息。

步骤 2:导入库

现在我们将导入所有需要的库:
1。BeautifulSoup
要导入它,在您的 IDE 上使用以下命令

**from bs4 import BeautifulSoup**

这个库帮助我们获得我们想要处理的任何页面的 HTML 结构,并提供访问特定元素和提取相关信息的功能。

2.urllib
要导入它,键入以下命令

**import urllib.request,sys,time**
  • urllib.request:它有助于定义帮助打开 URL 的函数和类
  • urllib.sys:它的函数和类帮助我们检索异常信息。
  • urllib.time : Python 有一个名为 time 的模块,它提供了几个有用的函数来处理与时间相关的任务。其中最受欢迎的功能之一就是 sleep()。

3.requests
要导入它,只需在本库关键字前键入 import 即可。

**import requests**

该模块允许我们使用 python 向 web 服务器发送 HTTP 请求。(HTTP 消息由从客户端到服务器的请求和从服务器到客户端的响应组成。)

4.pandas

**import pandas as pd**

这是一个高级数据操作工具,我们需要它来可视化我们的结构化抓取数据。

将使用这个库来制作 DataFrame(这个库的关键数据结构)。数据帧允许我们存储和操作观察行和变量列中的表格数据。

**import urllib.request,sys,time
from bs4 import BeautifulSoup
import requests
import pandas as pd**

第三步:提出简单的请求

通过request模块,我们可以获取 HTML 内容并存储到page变量中。
发出一个简单的 get 请求(只是获取一个页面)

**#url of the page that we want to Scarpe
#+str() is used to convert int datatype of the page no. and concatenate that to a URL for pagination purposes.URL = 'https://www.politifact.com/factchecks/list/?page='+str(page)#Use the browser to get the URL. This is a suspicious command that might blow up.page = requests.get(url)**

既然, *requests.get(url)* 是一个可疑的命令,可能会抛出一个异常,我们就在 try-except block 中调用它

**try:
     # this might throw an exception if something goes wrong.
     page=requests.get(url)      # this describes what to do if an exception is thrown 
except Exception as e:    

    # get the exception information
    error_type, error_obj, error_info = sys.exc_info()      

    #print the link that cause the problem
    print ('ERROR FOR LINK:',url)

    #print error info and line that threw the exception                          
    print (error_type, 'Line:', error_info.tb_lineno)

    continue**

出于分页的目的,我们还将使用外部 for 循环。

步骤 4:检查响应对象

一、看服务器发回什么响应码(对
检测 4XX 或 5XX 错误有用。

**page.status_code**

输出:

HTTP 200 OK 成功状态响应代码表示请求已经成功。

二。以文本形式访问完整的响应(在一个大字符串中获取页面的 HTML)

**page.text**

输出:

它将以 Unicode 返回响应对象的 HTML 内容。
备选:

**page.content**

输出:

输出:

然而,它将以字节为单位返回响应的内容。

三。在响应中查找特定的文本子字符串。

**if "Politifact" in page.text:
         print("Yes, Scarpe it")**

四。检查响应的内容类型(查看是否得到了 HTML、
JSON、XML 等)

**print (page.headers.get("content-type", "unknown"))**

输出:

步骤 5:延迟请求时间

接下来使用时间模块,我们可以调用值为 2 秒的 sleep(2)函数。这里,它向 web 服务器发送请求的时间延迟了 2 秒。

**time.sleep(2)**

sleep()函数在给定的秒数内暂停当前线程的执行。

步骤 6:从 HTML 中提取内容

现在您已经发出了 HTTP 请求并获得了一些 HTML 内容,是时候解析它了,这样您就可以提取您正在寻找的值。

A)使用正则表达式
完全不建议使用正则表达式来查找 HTML 内容。

但是,正则表达式对于查找特定的字符串模式仍然很有用,比如价格、电子邮件地址或电话号码。

对响应文本运行正则表达式,以查找特定的字符串模式:

**import re  # put this at the top of the file
...
print(re.findall(r'\$[0-9,.]+', page.text))**

输出:

B)使用 BeautifulSoup 的对象汤
Beautiful Soup 是一个用于从 HTML 和 XML 文件中提取数据的 Python 库。它与您喜欢的解析器一起工作,提供导航、搜索和修改解析树的惯用方式。它通常可以为程序员节省数小时或数天的工作

**soup = BeautifulSoup(page.text, "html.parser")**

下面列出的命令将查找所有具有特定属性“o-listicle__item”的标签,例如<li>

**links=soup.find_all('li',attrs={'class':'o-listicle__item'})**

检查网页
为了能够理解上面的代码,你需要检查网页&请跟着做:
1)转到上面列出的 URL
2)按 ctrl+shift+I 检查它。
3)这是你的“检查窗口”的样子:

  • 按 ctrl+shift+C 选择页面中的元素进行检查,或者转到“检查”窗口标题中最左边的箭头。

4)用于在检查窗口中获取上述特定元素和属性

  • 首先,尝试进入网页的每个部分,并在 inspect 窗口中查看变化,您将很容易理解网页如何工作,以及哪个元素是什么,哪个特定属性对网页有贡献。
  • 完成上述步骤后,现在我假设你能理解上述元素<li>及其属性的工作原理。
  • 因为我需要某篇文章的新闻部分,所以我通过选择 inspect 窗口中的 inspect 元素选项转到该文章部分,它将在网页上突出显示该文章部分,并在 Inspect 窗口中突出显示其 HTML 源代码。瞧啊。✨

你能在你的机器上找到相同的标签吗?

如果是的话,你已经完全理解了我在代码中使用的所有 HTML 标签。

继续我的代码:😅

**print(len(links))**

这个命令将帮助你检查给定页面上有多少新闻文章。
相应地帮助你理解,为了提取大量数据,你需要对你的循环进行分页到什么级别。

步骤 7:查找元素和属性

  • 查找页面上的所有锚标签(如果您正在构建一个爬虫,并且需要找到下一个要访问的页面,这很有用)
**links = soup.find_all("a")**
  • 它将在<li>标签下找到一个 div 标签,其中 div 标签应该包含列出的或特定的属性值。这里的“j”是一个 iterable 变量,它对给定页面上列出的所有新闻文章的响应对象“Links”进行迭代。
**Statement = j.find("div",attrs={'class':'m-statement__quote'})**
  • text.strip()函数将返回包含在该标记中的文本,并从文本字符串对象中去除任何类型的额外空格,' \n ',' \t '。
**Statement = j.find("div",attrs={'class':'m- 
   statement__quote'}).text.strip()**

好极了!🌟我们已经刮出了第一个属性,即数据集的语句

  • 在同一个 division 部分,它将寻找锚标记并返回超文本链接的值。同样,strip()函数用于组织我们的值,以便我们的 CSV 文件看起来不错。
**Link=j.find("div",attrs={'class':'m-statement__quote'}).find('a')['href'].strip()**
  • 要获取日期属性,您需要先检查网页,因为它包含一个字符串。所以在没有指定索引的情况下调用文本函数,你会得到类似这样的结果

  • 但是除了日期之外,我们不需要文本,所以我使用索引。尽管您可以稍后使用一些正则表达式组合来清理您的属性。“footer”是包含所需文本的元素。
**Date = j.find('div',attrs={'class':'m-statement__body'}).find('footer').text[-14:-1].strip()**
  • 在这里,除了 get()之外,我做了和以前一样的事情,get()提取传递的属性(即 title)的内容
**Source = j.find('div', attrs={'class':'m-statement__author'}).find('a').get('title').strip()**
  • 因为,对于我的项目,我需要一个没有被改变的数据集,而且,我需要知道成千上万的文章,哪篇文章属于我的训练数据的哪个类别。没有人可以手动操作。所以,在这个网站上,我确实找到了已经贴有标签的文章,但是文本是不可检索的,因为它包含在图像中。对于这种特定的任务,您可以使用 get()来有效地检索特定的文本。这里,我将' alt '作为属性传递给 get(),它包含我们的标签文本。
**Label = j.find('div', attrs ={'class':'m-statement__content'}).find('img',attrs={'class':'c-image__original'}).get('alt').strip()**

在下面的代码行中,我将所有的概念放在一起,并尝试获取数据集的五个不同属性的详细信息。

**for j in links:
        Statement = j.find("div",attrs={'class':'m-statement__quote'}).text.strip()
        Link=st.find('a')['href'].strip()
        Date = j.find('div',attrs={'class':'m-statement__body'}).find('footer').text[-14:-1].strip()
        Source = j.find('div', attrs={'class':'m-statement__author'}).find('a').get('title').strip()
        Label = j.find('div', attrs ={'class':'m-statement__content'}).find('img',attrs={'class':'c-image__original'}).get('alt').strip()
        frame.append([Statement,Link,Date,Source,Label])
upperframe.extend(frame)**

步骤 8:制作数据集

将每个属性值附加到每个文章的空列表“框架”中

**frame.append([Statement,Link,Date,Source,Label])**

然后,将此列表扩展为每页的空列表“upperframe”。

**upperframe.extend(frame)**

步骤 9:可视化数据集

如果你想在木星上可视化你的数据,你可以使用 pandas DataFrame 来实现。

**data=pd.DataFrame(upperframe, columns=['Statement','Link','Date','Source','Label'])
data.head()**

步骤 10:制作 CSV 文件并保存到你的机器上

****A)打开&写入文件下面的命令将帮助你编写 CSV 文件,并将其保存到你的机器上保存你的 python 文件的同一个目录下

**filename="NEWS.csv"
    f=open(filename,"w")
    headers="Statement,Link,Date, Source, Label\n"
    f.write(headers)
    ....
        f.write(Statement.replace(",","^")+","+Link+",
"+Date.replace(",","^")+","+Source.replace(",","^")+","+Label.replace(",","^")+"\n")**

这一行将把每个属性写到一个文件中,用'^'.替换所有的','

**f.write(Statement.replace(",","^")+","+Link+","+Date.replace(",","^")+","+Source.replace(",","^")+","+Label.replace(",","^")+"\n")**

因此,当您在命令 shell 上运行这个文件时,它会在您的。py 文件目录。打开它时,如果你在抓取时没有使用 strip(),你可能会看到奇怪的数据。所以不要用 strip()检查它,如果你不用','替换'^',它看起来也会很奇怪。
所以,用这些简单的步骤替换它:

  • 打开您的 excel 文件(。csv 文件)
  • 按 ctrl+H(将出现一个弹出窗口,询问“查找内容并替换为”)

  • 给''取值给'找什么字段,给'中的''取值替换为'字段。****
  • 按全部替换
  • 点击关闭&哇哦!😍您已经完成了让数据集保持完美形式的工作。不要忘记在完成两个 for 循环后用下面的命令关闭文件,
****f.close()****

如果已经使用文件写入方法创建了数据集,则反复运行相同的代码可能会引发错误。

B)使用 to_csv()
将数据帧转换为 csv 文件因此,除了这种冗长的方法,您可以选择另一种方法:to_csv()也用于将数据帧转换为 csv 文件,并且还提供一个属性来指定路径。

****path = 'C:\\Users\\Kajal\\Desktop\\KAJAL\\Project\\Datasets\\'
data.to_csv(path+'NEWS.csv')****

为了避免歧义并允许代码的可移植性,您可以使用:

****import os
data.to_csv(os.path.join(path,r'NEWS.csv'))****

这将正确地将您的 CSV 名称附加到您的目标路径。

建议和结论

虽然我建议使用第一种方法,即打开文件,写入文件,然后关闭文件,但我知道实现起来有点冗长和俗气,但至少它不会像 to_csv 方法那样给你提供模糊的数据。

请看上图,它是如何提取语句属性的不明确数据的。
因此,与其花费数小时手动清理数据,我建议多写几行第一种方法中指定的代码。现在,你已经完成了。✌️

重要提示: 如果您尝试复制粘贴我的源代码来抓取不同的网站&运行它,它可能会抛出一个错误。事实上,它肯定会抛出一个错误,因为每个网页的布局是不同的&为此,你需要做出相应的改变。

完整代码

数据集:

这篇文章是网络搜集系列的第一部分,对于那些没有技术背景的人来说,可以在这里阅读这个系列的第二部分

所以,如果我的博客帖子对你有所帮助,而你此刻觉得很慷慨,请不要犹豫,请给我买杯咖啡。☕😍

是的,点击我。

****And yes, buying me a coffee **(and lots of it if you are feeling extra generous)** goes a long way in ensuring that I keep producing content every day in the years to come.****

我希望你会觉得有用,喜欢我的文章。😇请随时分享你的想法,如果你有任何疑问,请打电话给我。您可以通过以下方式联系我:

  1. 订阅我的 YouTube 频道 视频内容即将上线 这里
  2. 跟我上
  3. LinkedIn 上连接并联系我
  4. 跟随我的博客之旅:-【https://kajalyadav.com/】
  5. 成为会员:-https://techykajal.medium.com/membership

查看我的其他博客:

****** [## 8 ML/AI 项目,让您的投资组合脱颖而出

有趣的项目想法与源代码和参考文章,也附上一些研究论文。

towardsdatascience.com](/8-ml-ai-projects-to-make-your-portfolio-stand-out-bfc5be94e063) [## 基于 Python 的推特情感分析预测美国总统大选

修订数据科学基础的有趣项目,从数据集创建到数据分析再到数据可视化

medium.com](https://medium.com/datadriveninvestor/predicting-us-presidential-election-using-twitter-sentiment-analysis-with-python-8affe9e9b8f)******

在 PDF 中抓取表格,然后在 Python 中测试数据质量

原文:https://towardsdatascience.com/scraping-a-table-in-a-pdf-reliably-and-then-test-data-quality-6718bb91d471?source=collection_archive---------22-----------------------

如何在 Python 中抓取 PDF 中的表格,对数据进行质量单元测试,然后上传到 S3。

蒂姆·莫斯霍尔德在 Unsplash 上的照片

介绍

假设您需要将一些数据接收到您的数据仓库中,在与您的利益相关者进一步讨论之后,这些数据的来源是一个 PDF 文档。幸运的是,使用一个名为 tabula-py 的 Python 包很容易做到这一点。在这篇文章中,我将带你了解如何抓取嵌入在 PDF 文件中的表格,使用 Great Expectations 对数据进行单元测试,如果有效,将文件保存在 AWS 的 S3 中。你可以在 Github 上找到这篇文章的完整源代码,或者在 Google Colab 上找到一个工作示例。

0) 所需依赖关系

在编写任何代码之前,让我们安装所有必需的包。

pip install tabula-py
pip install great_expectations
pip install boto3

1)所需进口

from tabula import read_pdf
import great_expectations as ge
import boto3
from io import StringIO

2)阅读 PDF 文件

下面我有两个 PDF 文件,其中包括一些与 SpaceX 发射相关的数据。一个是干净的预期格式,另一个是有意的错误,我们将在单元测试数据输出时使用。

clean = "https://raw.githubusercontent.com/AshHimself/etl-pipeline-from-pdf/master/spacex_launch_data.pdf"messy = "https://raw.githubusercontent.com/AshHimself/etl-pipeline-from-pdf/master/spacex_launch_mess_data.pdf"source_pdf = read_pdf(clean, lattice=True, pages=”all”)df = source_pdf[0]

3)审查数据

让我们来看看我们的数据,看看 tabula-py 只用一行代码就工作得有多好!

df.head()

相当令人印象深刻!唯一值得注意的问题是,这些标题在数据库中不能很好地工作,所以让我们稍微清理一下。

#Rename the headers
fields = {‘Flight Numb’: ‘flight_number’, ‘Dr ate’: ‘date’,’Time (UTC)’: ‘time_utc’,’Booster Ver’:’booster_version’,’iLoanunch Site’:’launch_site’}df = df.rename(columns=fields) #rename columns
df.columns = map(str.lower, df.columns) ##lower case is nicer

到目前为止,我们已经从 PDF 中抓取了表格,并将其保存在熊猫数据框中,如果我们愿意,我们可以将数据框保存到 S3 的 CSV 文件中。然而,如果这个 PDF 的格式改变了,如果有人改变了域名,我们如何保证数据将可靠地保存在 S3?

4)断言数据

为了测试我们的数据,我们将使用一个名为 Great Expectations 的神奇包。我甚至不会触及这个包的表面,所以我强烈建议检查一下!。

如果我们现在运行代码,使用我们的预期 pdf ,它应该通过所有断言。然而,看看凌乱的 pdf 。我特意添加了一些重复的 flight_number 行,并重命名了输出列。如果我们使用混乱的 PDF 再次运行(从第 2 节更新 PDF 源文件),上面的代码应该返回“一些断言已经失败:(”。validation_results 的输出也相当详细,但是您可以在这里查看完整的输出。

{“Expected Column Position”: 7,”Expected”: “outcome”,”Found”: “mission outcome”}

像这样在 ETL 管道中进行一些基本的测试可以很容易地帮助确保数据质量的一致性和可靠性。

5)在 S3 保存我们的数据

教您如何设置具有正确权限的 S3 存储桶超出了本文的范围,所以我假设您知道如何做或者知道如何解决这个问题。

AWSAccessKeyId=’your_access_key_id’
AWSSecretKey=’your_secret_key’bucket = ‘scrape-pdf-example’ # your S3 bucketcsv_buffer = StringIO()s3 = boto3.client(‘s3’, aws_access_key_id=AWSAccessKeyId, aws_secret_access_key=AWSSecretKey)df.to_csv(csv_buffer) #save our dataframe into memory
s3_resource = boto3.resource(‘s3’)
s3_resource.Object(bucket, ‘df.csv’).put(Body=csv_buffer.getvalue()) #push CSV to S3

来自 Stefan 的代码片段!

搞定了。你现在应该在你的 S3 桶中有一个 CSV 文件,如果你愿意,它可以被其他 AWS 服务 (Glue,Redshift 等)接收。

您在生产中测试过数据的质量吗?

结束语

使用 AWS 服务 Textract 服务或其他 Python 包可以轻松实现上述代码,但对我来说,Tabula 在处理简单和更复杂的 PDF 文档时效果很好,这些文档包含多个表格和更复杂的表格结构。

总的来说,数据质量和测试数据至关重要,但却常常被忽视。像 DBT马提利翁这样的解决方案提供了测试/断言你的数据的功能,使这个过程变得非常容易。你使用什么工具?

将最终输出保存到 S3 显然是可选的。我只是选择这样做,因为未来的文章将利用 S3 的 CSV 文件作为起点。

关于我:对万物数据充满热情,活在 商业 数据 机器学习 。想聊天可以在LinkedIn上联系我!

用 Python 实现 4 行新闻的网络抓取

原文:https://towardsdatascience.com/scraping-a-website-with-4-lines-using-python-200d5c858bb1?source=collection_archive---------36-----------------------

抓取网站的简单方法

Unsplash 上的absolute vision拍摄

在本文中,我将向您展示如何从各种来源收集和删除新闻。所以,与其花很长时间为每个网站写抓取代码,不如用 newspaper3k 自动提取结构化信息。如果你不愿意看这篇文章,你可以在 github 的上看到我的完整代码。

让我们开始吧,第一步是安装将要使用的包,即使用 pip 的 newspaper3k。打开终端(Linux / macOS)或命令提示符(windows)并键入:

$ pip install newspaper3k

安装完成后,打开代码编辑器,导入包含以下代码的包

>>> from newspaper import Article

在这篇文章中,我将从《纽约时报》的标题为' 中摘抄一条新闻,标题为“一生与 艾哈迈德·阿贝里一起奔跑”,结尾是一段文字:“我们失去了莫德 ' ”。

接下来,输入要抓取的链接

>>> article = Article('https://www.nytimes.com/2020/05/10/us/ahmaud-arbery-georgia.html’)

您可以选择使用哪种语言。即便如此,报纸也能相当好地检测和提取语言。如果没有给出具体的语言,报纸会自动检测语言。

但是,如果您想使用一种特定的语言,请将代码更改为。

>>> article = Article(‘[https://www.nytimes.com/2020/05/10/us/ahmaud-arbery-georgia.html'](https://www.nytimes.com/2020/05/10/us/ahmaud-arbery-georgia.html'), ‘en’) # English

然后用下面的代码解析文章

>>> article.download()>>> article.parse()

现在一切都准备好了。我们可以开始使用几种方法来提取信息,从文章作者开始。

>>> article.authors['Richard Fausset']

接下来,我们将获得文章发表的日期。

>>> article.publish_datedatetime.datetime(2020, 5, 10, 0, 0)

从文章中获取全文。

>>> article.text‘Mr. Baker was with Mr. Arbery’s family at his grave site . . .’

你也可以从文章中获取图片链接。

>>> article.top_image'https://static01.nyt.com/images/2020/05/10/us/10georgia-arbery-1/10georgia-arbery-1-facebookJumbo-v2.jpg'

此外,newspaper3k 还提供了简单文本处理的方法,例如获取关键字和摘要。首先,使用初始化。nlp()方法。

>>> article.nlp()

获取关键字。

>>> article.keywords['running',
 'world',
 'needed',
 'arbery',
 'lifetime',
 'site',
 'baker',
 'text',
 'wished',
 'maud',
 'arberys',
 'lost',
 'pandemic',
 'upended',
 'ends',
 'ahmaud',
 'unsure',
 'mr']

接下来是新闻摘要,但是该功能仅限于几种语言,如文档中所述。

>>> article.summary'Mr. Baker was with Mr. Arbery’s family at his grave site.\nIt was Mr. Arbery’s birthday.\nA pandemic had upended the world, and Mr. Baker felt adrift.\nSometimes he wished to be called a musician, and sometimes he did not.\nHe was unsure what he would become or how he would get there.'

这篇文章的结论是,与我们必须花很长时间为每个网站编写抓取代码相比,使用 newspaper3k 包,我们可以很容易地在 python 中抓取各种来源的新闻。通过使用这个包,我们可以从新闻中检索所需的基本信息,如作者、出版日期、文本和图像。还有一些获取新闻关键词和摘要的方法。最重要的是,newspaper3k 可以用各种语言搜集新闻。

利用 IBM 的 Watson Discovery 搜集和查询黑客新闻

原文:https://towardsdatascience.com/scraping-and-querying-hacker-news-with-ibms-watson-discovery-50d5241e559?source=collection_archive---------37-----------------------

沃森最初是 IBM 设计的一个 AI 系统,用来赢得 Jeopardy!电视节目。为了成功,沃森必须查询一个庞大的知识库来回答节目中的问题(或质疑答案)。这个知识库包括 DBPedia、WordNet 和 Yago。节目结束后,沃森被分拆成多个产品,包括沃森发现、沃森文本到语音、沃森语音到文本、沃森助手和沃森知识工作室等。Watson Discovery 可用于查询文档,以找到回答您可能有的问题的相关段落/文章/段落。在本文中,我将向您展示如何使用 Watson Discovery 从 Y Combinator 的黑客新闻中获取信息,这将有助于回答有关黑客新闻主题的问题,但您可能希望将它重新用于您想要查询的其他文档。

如果你熟悉刮削,你可能会意识到即使刮削并不困难,它也会非常耗时。无论您的文档是 PDF、Word、PowerPoint、Excel、PNG、TIFF、JPG、JSON 还是 HTML,Watson Discovery 都能为您完成这项任务。Discovery 在抓取网站时可以节省大量时间,因为它会抓取该网站的主页,以及其他页面和外部网站的链接。这使得将它应用于黑客新闻成为一项简单的任务。

注册一个免费的 IBM Cloud 帐户

IBM 的沃森主要生活在云上,允许它扩展(和缩小)以满足你的工作需求。从为一个 IBM 云账户歌唱开始。跟随本教程学习所需的资源是免费的,但是为了完全公开,我确实为 IBM 工作。

然后你应该会收到一封激活你账户的邮件,这样做,你就可以开始了!

调配 Watson 发现的实例

现在当你登录时,你可能会被下面看到的一切淹没。我建议您点击顶部横幅中的目录按钮。

您可以浏览 IBM 提供的服务,但我们将在 AI 选项卡下使用 Discovery。单击“Discovery ”,我们可以对其进行资源调配。

现在我们可以选择选择一个精简(免费)版本或高级版本。出于我们的目的,我们只需要 lite,因为我们可以用它获得 1000 个文档的目录,这应该是我们查询黑客新闻的目标所需的全部内容。

启动沃森探索

通过点击左上角的汉堡包图标,并点击资源列表按钮,这将显示您已经创建的所有服务的列表。

在 services 选项卡下,选择您的发现实例,我的实例仍具有随机生成的默认名称。

现在单击页面中间的蓝色按钮“启动 Watson Discovery”。

创建文档集合

当你启动沃森发现,你会注意到已经有一些数据,称为沃森发现新闻。

Watson Discovery News 包含最近的新闻文章,让您快速了解一家公司的:

  • 过去两个月的头条新闻
  • 那些文章中提到的顶级实体(人、主题、公司)
  • 新闻中的舆情走向
  • 媒体大量报道的反常时期
  • 最常见配对实体的趋势(共同提及)

我们不会使用沃森探索新闻,但它是你的一个选择。相反,单击“连接数据源”按钮。现在,您将看到一个可供选择的数据源选项列表,我们将单击 Web Crawl,因为有关黑客新闻的文章存储在 Web 上。

现在,我们可以添加我们想要抓取的网站以及我们希望抓取的频率。

我添加了前 10 页的黑客新闻,我设置了每天一次的频率,并将语言内容保留为英语。

按下保存和同步按钮后,Watson Discovery 将开始检索您输入的 URL 上的文本以及这些 URL 链接到的页面上的文本。

查询文档

等了一会儿后,网络爬行已经完成,我可以看到它已经收集了 657 个文档,0 个失败。现在,我将单击页面左侧的放大镜,转到查询构建器。

在这里,您可以看到发现、搜索文档的一些主要功能。单击搜索文档开始编写一些查询。

您的查询可以使用两种格式编写,发现查询语言或自然语言。自然语言更接近谷歌搜索,而发现查询语言感觉更像正则表达式。首先,我将展示自然语言。我正在搜索关于编程语言 Go 的信息,因为我对学习它很感兴趣。

这将返回一些与我查询的内容相关的文本和段落,其中包含关于 Go 的有趣信息。当我在 Discovery 查询语言下搜索时,我可以要求在满足特定条件时返回信息。在下面的例子中,我要求文本必须包含单词 data science,我得到了一些关于自由职业者工作和 SQL 的文档。

为了更好地增强 Discovery 查询语言,您可能希望使用 Field 下的选项,这将允许您查找与预先定义的概念和实体相关的信息,要求文件类型是特定的,按网页制作日期过滤,或在 HTML 中查找内容。

很可能您会想要使用 Discovery 提供的许多其他功能。我建议查看:

包含所有这些特性的教程对于一篇文章来说是超载的,所以我将把我对其他用例的一些想法留给您。

个人项目想法

教程查找器

将网络爬虫设置到像 bookdown.org这样有大量高质量信息的网站可以帮助你快速找到你想要解决的问题的相关资料。你甚至可以把自己的课本上传成 pdf 格式,然后进行查询。

工作板刮刀

你可以设置一个 Watson Discovery 网页抓取功能来抓取几个招聘信息,然后使用自然语言查询,你就有希望找到一份最适合你的工作。例如,您可以要求工作描述包含单词“远程”、“java”和“数据科学家”,但不包含单词“excel”

业务用例想法

搜索求职者的简历

有了求职者的简历,你可以搜索你认为最重要的技能。为单词设置同义词也非常有用,这样当你寻找具有深度学习经验的候选人时,你可以获得 PyTorch 和 TensorFlow 返回的简历。

面向员工的内部搜索引擎

能够用谷歌搜索信息是很棒的,但是当你想搜索你的个人或公司文件时,你就不能用谷歌了。Watson Discovery 可以作为文档的搜索引擎,使您能够找到查询的答案,并在查找信息时节省时间。伍德赛德能源公司在下面的视频中就是这么做的。

面向客户的聊天机器人集成

当聊天机器人不知道你可能有的问题的答案时,与它交谈可能会令人沮丧。使用 Watson Discovery 增强聊天机器人是一种很好的方式,可以在您没有对特定问题的答案进行预编程的情况下回答客户可能提出的问题。如果你创建一个由 Watson Assistant 驱动的聊天机器人,这很容易做到。

用美汤刮去冠状病毒死亡人口统计

原文:https://towardsdatascience.com/scraping-coronavirus-death-demographics-with-beautiful-soup-9df7488fe84c?source=collection_archive---------41-----------------------

网页抓取教程

马库斯·斯皮斯克在 Unsplash 上的照片

随着冠状病毒在全球蔓延,详细的数据对于人们了解这种病毒变得至关重要。许多优秀的数据源已经发布了可供研究使用的数据(本文中的综述,以及本文中的中与 GIS 相关的综述)。但是,大部分数据来源集中在不同地点的确诊/死亡/康复计数和检测计数。如果您想要其他信息,例如性别和年龄等死亡人口统计信息,该怎么办?

在本教程中,我们将浏览伊利诺伊州卫生部每日新闻网页,使用 Python 和 Beautiful Soup library 获取冠状病毒死亡人口统计数据。

1.调查网页的逻辑结构

首先,我们知道伊利诺伊州卫生部(IDPH)有每日简报,其中包含死亡人口统计数据。让我们以 2020 年 4 月为例,访问以下网页

https://www.dph.illinois.gov/news/202004

快速浏览可以发现以下信息:

  • 该网址以的格式按年月组织。
  • 这个网页包含每月的所有每日报告,最新的报告在最上面。每条每日新闻都可以用相应的日期串来标识,格式为
  • 每日新闻只有一个部分显示在这个网页上。完整的每日报告实际上在右下角的“阅读更多”链接中。

2.准备汤品

因为我们知道 HTTP 地址,所以我们可以很容易地用漂亮的 soup 构造一个 Soup 对象。

3.查找相关信息

3.1 确定切入点

大多数现代网络浏览器都提供了查看网页源代码的基本工具。以 Chrome 为例,可以使用键调出侧面的 DevTools 控制台,如下图:

乍一看,右边的内容让人望而生畏,尤其是对于不熟悉 HTML 的人来说。怎么才能在这一大堆乱七八糟的东西中找到相关的信息呢?

好消息是,在大多数情况下,我们不必知道网页的完整结构。例如,由于在步骤#1 中我们已经确定日期字符串指定了新闻的位置,我们可以使用 Ctrl-F 搜索日期字符串“15th Apr ”,以快速定位感兴趣的部分:

如果您将鼠标悬停在“4 月 15 日”上,左侧网页上的相应部分将会高亮显示。这确认了代码位置。

在确认了逻辑位置之后,我们可以使用find_all函数在 soup 对象中复制它,以找到所有的 div ,并使用其 span 具有正确字符串的那个。

运行上面的代码后,我们可以打印 target_elm 来确认它是否是包含“2020 年 4 月 15 日”的元素:

3.2 找到从入口点到兴趣点的相对路径

正如我们在#1 中讨论的,详细的每日报告实际上在另一个位置,在“阅读更多”链接下。我们可以使用相同的技巧找到相对路径,即在 DevTools 控制台中搜索“Read more ”:

方便的是,包含“Read more”链接的元素和包含“15th Apr”字符串的元素属于同一个parent。因此,我们可以使用 soup 元素的parent属性来导航结构,然后使用.a.get('href')来获得超链接。

在获得日期的详细报告的超链接之后,我们可以请求新的网页,并相应地创建新的 soup 对象:

然后我们可以打开实际的每日报告页面,并使用相同的技巧,搜索“Cook County”来定位代码的相关部分。正如我们所看到的,详细的分解是在一个无序列表中(

标签),在一个 div 类“field-item even”下。

4.提取信息

找到列表后,我们可以通过使用find_all函数搜索< li >标签来迭代列表,然后使用.text属性获取相应的文本。

一旦我们得到诸如“1 男 30”这样的字符串,我们就可以从字符串中提取计数/性别/年龄信息。然后我们可以将它们放入熊猫数据框中进行进一步分析。

上面代码中的核心分析是我们必须实现的extract()函数。基本思想很简单——我们可以将字符串分成三个子字符串,然后相应地提取计数、性别和年龄。

然而,现实要复杂得多,也容易出错,就像任何网页抓取一样。因为新闻文本是由人类生成的,尽管格式相对稳定,但仍有许多细微差别可能会发生变化。仅举几个例子:

  • 在 2020 年 3 月 22 日之前,死亡人口统计日报的格式不太结构化。
  • 有时“年龄”部分不以“s”结尾。比如“1 男 100+”。更糟糕的是,有时它使用“青少年”或“婴儿”这样的词来指定年龄。
  • 有“未知”和“不完整”的条目。
  • 有时死亡计数“1”会被忽略。
  • ……

毕竟,完整的实现可以在这个 GitHub repo 中的utils.parse_IL_death_demographic()中找到。作为一条支持信息,我在输出数据框中添加了新闻页面的链接,以便在必要时可以快速验证结果。最终的输出数据帧如下所示:

5.绘制死亡人口统计图

经过以上努力,我们从《IDPH 日报》中获得了死亡人口统计数据框架。这样网页抓取就完成了。但是在宣布胜利之前检查结果总是一个好主意。Pandas pivot_table()提供了聚集数据的灵活方式。例如,我们可以看看每日死亡人数时间序列:

上述情节很容易被新闻来源所证实,这使我们对我们的结果有了一些信心。

最后,我们可以看看死亡人口统计。按年龄和性别划分的堆积条形图是一个很好的表示。这可以通过将数据框旋转到另一个方向来轻松实现:

最后注意:

一般来说,网页抓取并不健壮,因为网页会在你不知道的情况下改变。因此,我们总是更喜欢更健壮的 API。但是当这不可用时,网络搜集可以作为另一个获取数据的途径。

承认

我要感谢我的朋友 David Tian,他是一名机器学习工程师,他对本文提出了宝贵的建议。看看他有趣的自驾* DeepPiCar *博客。

使用 Python 抓取 COVID19 数据

原文:https://towardsdatascience.com/scraping-covid19-data-using-python-80120eb5eb66?source=collection_archive---------29-----------------------

乔希·希尔德在 Unsplash 上的照片

通过各种尝试来抑制 COVID19 对世界的影响,各种研究工作和创新措施依赖于从正确的数据中获得的洞察力。帮助创新所需的大部分数据可能无法通过应用编程接口(API) 或类似于“的文件格式获得。CSV’等待下载,但只能作为网页的一部分访问。所有代码片段都可以在这里找到。

Web scraping 是一个术语,用来描述使用程序或算法从 Web 中提取和处理大量数据。无论您是数据科学家、工程师,还是分析大量数据集的任何人,从 web 上抓取数据的能力都是一项有用的技能。

Worldometers 在全球拥有可靠的 COVID19 数据来源。在本文中,我们将学习如何使用 python 将下面描述的 COVID19 数据从网页抓取到站点的 Dask dataframe

来自 Worldometer 的 COVID19 病例报告

为什么是 Dask dataframe?

Pandas 已经成为 Python 编程语言中用于数据争论和分析的最流行和最受欢迎的数据科学工具之一。由于算法和本地内存限制,熊猫在大数据方面有自己的局限性。

然而, Dask 是一个开源的免费的 Python 库。Dask 提供了在性能和可伸缩性方面扩展 Pandas、 Scikit-LearnNumpy 的方法。在本文的上下文中,数据集必然会不断增加,这使得 Dask 成为理想的工具。

网页的元素

照片由 Pankaj PatelUnsplash 上拍摄

在我们深入研究网络抓取之前,让我们先弄清楚网页和网站的区别。一个网页可以被认为是一个单独的实体,而一个网站是多个网页的组合。在网站 HTTP 中,通过浏览器访问网页,并使用 DNS 协议来访问它。网站中的内容根据网页而变化,而网页包含更具体的信息。

网页有四(4)个基本元素,它们是:

  1. 结构
  2. 功能
  3. 内容
  4. 美学

上面列出的元素,属于但不限于这些可编程组件,如HTML—包含页面的主要内容, CSS —添加样式使页面看起来更好,最后JS—JavaScript 文件为网页添加交互性。****

当我们执行 web 抓取时,我们感兴趣的是从 web 页面的主要内容中提取信息,这使得很好地理解 HTML 变得很重要。

超文本标记语言(HTML)

来自 Logolynx 的 HTML 徽标

超文本标记语言(HTML)是一种创建网页的语言。HTML 不像 Python 那样是一种编程语言,相反,它是一种告诉浏览器如何布局内容的标记语言。

让我们快速浏览一下 HTML,这样我们就有足够的知识来有效地抓取。HTML 由称为标签的元素组成。

HTML 代码的外观

这是 HTML 网页的基本语法。每一个<tag>在网页里面服务一个区块。head标签包含了关于页面标题的数据,而 HTML 文档的可见部分在body标签之间。p标签定义了一个段落,标签内的任何文本都显示为一个单独的段落。最后,从我们的代码片段来看。我们添加了两个a标签,允许输入链接,并告诉浏览器呈现另一个网页的链接。标签的href属性决定了链接的位置。如需标签的完整列表,请点击 查看

另外,HTML 标签有时会带有idclass。属性为一个 HTML 标签指定了一个唯一的 id,这个值对于 HTML 文档来说必须是唯一的。class属性用于为同一个类的 HTML 标签定义相等的样式(CSS 操作)。

下载用于网络抓取的网页

要抓取一个网页,我们需要做的第一件事是下载页面。我们可以使用 Python 请求库下载页面。在我们使用它之前,我们必须安装它。在终端上,下面的代码将安装这个库。

pip install requests

请求库将向 web 服务器发出一个GET请求,它将为我们下载给定网页的 HTML 内容。

运行我们的请求后,我们得到一个响应对象。这个对象有一个status_code属性,指示页面是否下载成功。200中的status_code表示页面下载成功。以2开头的状态码通常表示成功,要了解更多关于状态码的信息,请点击链接

HTML 解析

解析简单地说就是在语法的指导下把句子结构分解成成分。因此,“HTML 解析”意味着接受 HTML 代码,并从其各种标签中提取相关信息。解析内容的计算机程序称为解析器。在本文中,我们将使用' BeautifulSoup '库来解析我们下载的 HTML 文档并帮助正确提取。在我们使用它之前,我们必须安装它。在终端上,下面的代码将安装这个库。

pip install beautifulsoup4

一旦安装了“BeautifulSoup”包,您就可以开始通过 BeautifulSoup 对象解析 HTML 文档了。

这里使用了“lxml”解析器,因为它可以处理不完整的 html,并且被广泛使用。

检查 HTML 网页

为了从网页中充分提取内容,我们必须检查网页以识别其属性和标签。通过右键单击网页上的任意位置并选择“检查”来检查网页在本文的上下文中,我们正在寻找与“已报告冠状病毒病例”更新表相关的属性和标签。这就是结果的样子。

HTML 检查

提取表格

<table id="main_table_countries_today" class="table table-bordered table-hover main_table_countries dataTable no-footer" style="width: 100%; margin-top: 0px !important;">

检查之后,属性“id”被识别出来,并将用于过滤 HTML 文档以获得所需的表格元素。

从提取的表格中获取文本

可以看出,提取的表格中嵌入了必不可少的 HTML 标签。本文的目标是从网页中取出一个表格,并将其转换成数据帧,以便使用 Python 进行操作。为此,我们首先以列表形式逐行获取所需的数据(文本),然后将该列表转换为 dataframe。

值得注意的是,标签tdtrth分别代表表格的列、行和表头。

转换成 Dask 数据帧

下一步是将该列表转换成 Dask 数据帧,以便进行数据操作和清理。如前所述。由于数据每天都在增加,建议使用 Dask 数据框架,它可以更有效地处理大数据。我们将创建一个 pandas 数据帧,并将其转换为 dask 数据帧以实现可伸缩性。生成的表格需要一些清晰的格式。

导出到 csv 以供将来使用

逗号分隔值( CSV )是一种广泛使用的文件格式,它将表格数据(数字和文本)存储为纯文本。它的流行和可行性是由于大量的程序和应用程序支持 csv 文件。

当视图显示从 Worldometers conoravirus 病例报告网页中成功提取的表格时,生成“csv”

我希望这篇文章有助于进一步的研究工作和创新,收集数据来抑制疫情。感谢阅读,并保持安全!

凯利·西克玛Unsplash 上拍摄的照片

抓取网络流量中的数据

原文:https://towardsdatascience.com/scraping-data-via-network-requests-4d5a89fb1626?source=collection_archive---------17-----------------------

在这一点上,我已经看到了许多关于如何使用 BeautifulSoup 或类似工具抓取数据的教程,但您可能没有考虑过从您感兴趣的网站抓取网络流量来获取数据。

为什么要刮网络流量?

您可能已经知道 http 请求为 web 提供了动力,您的浏览器发出了对某个网页的请求,并返回了该网页的数据。这不是对一个页面的单独请求,而是对不同数据的许多请求,这些数据被放在一起,形成您在浏览器中看到的内容。假设你在一个社交网站上发了一个帖子,然后你的朋友评论了这个帖子。您的浏览器只请求与您的帖子相关的数据,而不是请求重新加载整个页面来显示您朋友最近的评论。这减少了必须请求的数据量,最终用户不必经历整个页面被重新加载。这对于抓取数据来说是幸运的,因为您经常需要的数据可能在您可以捕获的请求中。

检查网络流量

为了从请求中抓取数据,在浏览器中检查网络流量是很有用的。比方说,你想获得北达科他州冠状病毒的数据,并决定删除北达科他州卫生部的网站。你很难抓取它,因为数据包含在一些交互式小部件(如下图)中,而不是像 HTML 表那样容易抓取的东西。

北达科他州卫生部

首先,您可以在页面上的任意位置单击鼠标右键,然后在 Mac 上单击“检查”或 Cmd+Option+i,在 Windows 上单击 Cmd+Shift+C。这将在你的浏览器中打开开发者工具,我正在使用谷歌浏览器,所以你的开发者工具可能看起来不同。单击网络选项卡将其打开。然后选择 XHR (XMLHttpRequests)。现在重新加载页面。

现在您可以看到,有一些数据通过网络传输。在本例中,包含北达科他州各县数据的是 4 个 CSV。这比用 BeautifulSoup 刮页面方便多了。

访问数据

在这里,您可以单击其中一个 CSV 来查看数据(如下所示),但是您可能希望采用一种更加程序化的方法,不需要任何手动步骤。

通过单击 Headers 选项卡,您可以看到获取这些数据是通过一个特定 url 上的 GET 请求完成的。我们可以获取这个 url,并在程序中发出这个请求。

使用 python 的 request、io 和 pandas 包,您可以从代码中请求有问题的 CSV。

这种方法可以使您拥有北达科他州新冠肺炎的数据可视化,显示与北达科他州卫生部一样最新的数据,而不必运行可能因页面布局的变化而频繁中断的刮刀。

发布请求中的数据

北达科他州冠状病毒数据相当容易访问,因为它保存在一个相对简单的 GET 请求中。让我们考虑一下南达科他州卫生部网站上的南达科他州冠状病毒数据。让我们从导航到开发者工具的网络流量窗格的相同过程开始。

如您所见,我们无法通过简单的 GET 请求轻松提取 CSV。我们需要的数据包含在名为 querydata 的第一个请求中。同步=真。这里,您需要用请求中正确的头和数据发出 POST 请求。右键单击它并导航到选项复制为卷曲。

现在,您可以将复制的内容粘贴到命令行中并运行它。您将得到一些很长的 JSON,可以通过解析找到您想要的数据。这是查找您可能感兴趣的数据的有用工具。

把 JSON 放在一个容易看到的地方可能会对你有用,你可以试着把这些都复制并粘贴到像 jsonformatter 或【jsonprettyprint.net】T4 这样的网站上,它们可以帮助你直观地解析数据。

将 cURL 转换为 python

即使你很擅长使用 cURL,阅读起来也会很棘手,很容易出错。有很多在线资源可以帮助你使用 cURL 并用你选择的编程语言重写它,比如trillworks.com,但是我建议你使用 Postman 。Postman 是一个很棒的免费应用程序,可以帮助你使用(和构建)API。由于 API 在处理数据中起着如此重要的作用,如果你真的想从事数据方面的职业,这是一个很好的学习工具。

下面,我画了 cURL 到 python 的转换,这是我选择的语言,Postman 已经帮我处理好了。

使用硒

Selenium 是一个流行的框架,用于在浏览器中运行自动化测试,实际上它可以用来抓取数据。从 Selenium Desired Capabilities 实现中,您可以提取您编写的自动化软件所访问的站点的请求。

希望这能让你看到一种更有效的收集数据的方法!

在 R 中抓取、下载和存储 pdf

原文:https://towardsdatascience.com/scraping-downloading-and-storing-pdfs-in-r-367a0a6d9199?source=collection_archive---------18-----------------------

网页抓取 pdf

嵌套擦伤,以避免按钮点击

来源:https://rstudio.com/resources/cheatsheets/

“汇流”一词的意思是事物的汇合或融合,通常指河流。我在西弗吉尼亚州长大,靠近 Gauley 河(为你椽子准备的世界级白水)和 Meadow 河(小嘴鲈鱼的天堂)。汇流这个词也很恰当地描述了我作品中的思想潮流是如何汇聚的。我的工作融合了统计学、数据科学和公共政策。如果是这些河流,数据科学无疑是最小的。虽然现在称自己为“数据科学家”很时髦,但我不是数据科学家。然而,我确实使用了数据科学家的许多工具、技术和流程。

我研究公共政策,因此,我没有形式和度量一致的数据(例如,对你们经济学家来说是美元和美分)。因此,有一天我正在使用机器学习技术对文本进行分类,第二天我正在为这些分类建立测量模型,之后我可能会为与数据相关的一些方面建立一个极端事件模型。所有这些意味着我做了很多数据科学家,特别是那些 Tidyverse 说服者,称之为“数据争论”的事情——清理、组织和转换数据以供分析。

我经常忘记需要处理数据的各种命令。RStudio 为数据科学和统计的各种包和过程提供了一套很好的备忘单。它们以 pdf 海报的形式出现,就像你在会议上看到的那样。我的问题是,我经常在西弗吉尼亚州的旅馆工作,那里的互联网连接是一个挑战,背景是高利河峡谷的轰鸣声。这意味着我经常搜索和下载我认为可能需要的备忘单。因为备忘单会不时更新,所以我冒着在本地存储过期备忘单的风险。这一切促使我考虑编写一个简短的脚本来访问所有 RStudio 备忘单并将其下载到本地。关于代码…

加载有用的库

至少对于那些使用 r 的人来说,tidyverse是这些类型操作的主力,特别是,rvest是读取和解析 HTML 的主要工具。最后,stringr提供了一致的处理文本字符串的方法——在抓取 URL 列表时非常有用。

library(tidyverse)
library(rvest)
library(stringr)

抓取链接和下载文件

下面的代码行通过识别和读取包含 RStudio Cheatsheets 的 pdf 的 Github 存储库的 HTML 来开始抓取。

page <- read_html("https://www.github.com/rstudio/cheatsheets")

如果您访问该存储库,您会发现单击表格中的一个 pdf 文件并不会单独生成相关的备忘单。它将我们带到存储库的第二级页面,并在代码编辑器中打开文件。获取文件以便在工作中引用意味着单击代码编辑器顶部菜单栏上的下载按钮。当然,没有什么刮擦练习是真正简单的。要获取文件,我们需要找到一种绕过“点击”下载按钮的方法。明确地说,一些脚本允许我们“点击”按钮,但是我在jsonlite中找到的那些比我在这里做的更复杂(虽然更有效)。

raw_list <- page %>% *# takes the page above for which we've read the html*
  html_nodes("a") %>%  *# find all links in the page* html_attr("href") %>% *# get the url for these links* str_subset("\\.pdf") %>% *# find those that end in pdf only* str_c("https://www.github.com", .) %>% *# prepend the website to the url* **map**(read_html) %>% *# take previously generated list of urls and read them*
  **map**(html_node, "#raw-url") %>% *# parse out the 'raw' url - the link for the download button*
  **map**(html_attr, "href") %>% *# return the set of raw urls for the download buttons*
  str_c("https://www.github.com", .) %>% *# prepend the website again to get a full url*
  walk2(., basename(.), download.file, mode = "wb") *# use purrr to download the pdf associated with each url to the current working directory*

我利用存储库主页上的链接来访问、记录和获取与每个备忘单的下载按钮相关联的链接列表。这种解决方法不需要为每个按钮编写一个“点击”按钮的脚本。这个脚本不是最高效的,但是您最终会在本地工作目录中找到所有优秀的 RStudio 备忘单。

前置很重要,因为每个对read_html的调用都需要完整的 URL。反过来,html_nodeshtml_attr中的解析依赖于已经读取了 HTML。来自stringr的字符串折叠函数str_c使这变得容易。对于解析,我们使用 Tidyverse 包purrr中的map函数。

重要花絮

  • 在最初的抓取中,str_subset("\\.pdf")告诉 R 返回所有带有 pdf 的链接。否则,您将获得整个存储库的链接,包括开发文件。
  • map(html_node, "#raw-url")告诉 R 查找与每个备忘单的下载按钮相关联的 URL。您可以通过使用 Google 的选择器小工具来识别这个标签——在上面搜索例子以及如何识别标签。
  • purrr::walk2download.file函数应用于每个生成的原始链接。的“.”告诉它使用前一个命令中的数据(原始 URL)。basename(.)告诉它给下载的文件一个 URL 的基本名称(例如,“purrr.pdf”)。
  • 根据您的 pdf 阅读器,您可能需要添加mode = "wb"。否则,文件可能会显示为空白、损坏或无法正确呈现。更多信息参见download.file()命令的文档。

老派

请注意,Tidyverse 的walk2和许多其他伟大的功能本身并不必要。下面的 for 循环是上面的walk2的老式实现。这里,download.file应用于raw_list中的每个 URL(URL 在这里只是对象raw_list中每一行的标签)。

for (url in raw_list){ download.file(url, destfile = basename(url), mode = "wb") }

包扎

因此,对于需要“点击按钮”的地方来说,这不是最有效的代码,但是它用最少的包和对json或其他语言的了解就完成了工作。现在我们已经完成了,我还可以说在 RStudio 的资源页面上可以找到备忘单。在那里,它们会更容易抓取,当然你可以点击下载。我经常向学生提及它们,因为它们是数据分析和统计教学的重要资源。

原载于 2020 年 4 月 10 日 https://www.samuelworkman.org

从维基百科上搜集信息

原文:https://towardsdatascience.com/scraping-from-all-over-wikipedia-4aecadcedf11?source=collection_archive---------51-----------------------

如何自动从多页中抓取

莎伦·麦卡琴在 Unsplash 上的照片

上周,我写了一篇关于如何从维基百科的一个表格中收集数据的文章(这里有一个链接让你了解)。在这篇文章中,我从这一页的上的一个表格中搜集了数据,上面有参赛者的姓名、年龄、职业,以及他们来自英国烘焙大赛第一季的地方。最终的结果是下面的字典:

{'Annetha Mills': [30, '/wiki/Essex'],
 'David Chambers': [31, '/wiki/Milton_Keynes'],
 'Edward "Edd" Kimber': [24, '/wiki/Bradford'],
 'Jasminder Randhawa': [45, '/wiki/Birmingham'],
 'Jonathan Shepherd': [25, '/wiki/St_Albans'],
 'Lea Harris': [51, '/wiki/Midlothian'],
 'Louise Brimelow': [44, '/wiki/Manchester'],
 'Mark Whithers': [48, '/wiki/Wales'],
 'Miranda Gore Browne': [37, '/wiki/Midhurst'],
 'Ruth Clemens': [31, '/wiki/Poynton,_Cheshire']}

如您所见,参赛者的全名是关键字,值是包含他们年龄的列表和包含他们家乡的维基百科页面 url 的 url 片段。现在,我可以很容易地得到这个城镇的名字,然后就到此为止。然而,如果我打算在收集的数据上运行某种模型,那就没什么用了。当您收集用于模型的数据时,可以收集的实际数字数据越多越好。因此,与其只收集一个地方的名称,不如收集一些关于这个地方的统计数据,比如人口或密度,会更有用。

当然,这些信息不会直接出现在 GBBO 的维基上,因为那与那个特定的页面无关,这也是为什么他们会链接到这个城镇的页面上。因此,这意味着如果我们想收集这些信息,我们必须自己去每一页搜集这些信息。你可以浏览每一个城镇页面,然后手动操作,但这很快就会变得乏味。这就是为什么我开发了一个脚本,可以自动进入每个页面并抓取信息。这样,实际的执行速度会更快,效率也会更高。

首先,下面是我编写的收集城镇人口和密度的完整函数:

现在我们要回到那里,解释这里到底发生了什么。

第二行我有下面的字典:

stats_dict = {'density':None, 'pop':None}

如果你看到最后,列表中返回的第二项是 stats_dict。通过使用空值字典,我们可以确保在页面上出现异常的情况下,我们仍然可以得到一些信息,并且可以从那里对有问题的单个项目进行故障诊断。

第四行如下:

if type(url_snippet) == str:

这确保了被传递的值是一个字符串,因为如果不是,函数的其余部分显然不能工作。第 5–8 行如下

area_url = 'https://en.wikipedia.org{}'.format(url_snippet)          area_page = requests.get(area_url)         
area_soup = BeautifulSoup(area_page.content)

它们创建完整的 url,请求 url,并制作我们将用于抓取信息的汤。

下一行是 for 循环,所有人口和密度的发现都在它下面

for item in area_soup.find_all('th'):

这实质上是说查看所有标记为“th”的项目,这是人口和密度信息通常放在下面的地方。第 11–17 行是关于查找密度信息,第 19–26 行是关于查找人口信息。以下是我如何找到密度信息的解释:

第 11 行和第 12 行如下:

if 'Density' in item.text:                
    if item.find_next_sibling().text:

这是在最初的 for 循环之后,查找所有标记为“th”的项目,所以这表示如果标记为标题的内容的文本是“density”,这意味着查找标记为 Density 的标题。下一行是说如果标记为 density 的东西的兄弟有文本,那么执行以下操作。

注意:通过这个过程,你会注意到有很多 if 语句。这是因为不同页面的格式偶尔会有细微的差异。对于页面浏览者来说,这并没有真正减少他们的体验。然而,当你处理一个脚本时,一个稍微不同的安排对你来说可能意味着一个错误。所以,你要做很多,“如果这个东西存在,就这么做”而不是只告诉函数做某件事。

以下几行是:

density_str = item.find_next_sibling().text                    
for elem in density_str.split():                        
    if "/km" in elem:

回到上一个 if 语句,这里的第一行是说,“现在我们知道这个东西存在,这个东西就是包含密度信息的字符串。”接下来的两行将文本分割成所有单独的部分,然后取包含每公里的人的信息的部分,因为我们希望确保我们的单位与我们得到的数字一致。下面两行实际上提取了数据(第一行溢出了一点):

d = int([item for item in re.split("(\d*,?\d*)",elem) 
if len(item)>1][0].replace(',','')) stats_dict['density'] = d

第一行是实际访问数字的内容。简而言之,它使用 regex 来拆分文本,如果该项可以拆分,则获取列表中的第一项,即数字本身,然后将文本中的逗号替换为空,然后将最后一个数字从字符串转换为整数。下一行返回到最初为空的字典,并使用前一行中收集的数字更新密度条目。

瞧,我们有了我们的密度!现在来看人口,我发现这个问题有点棘手,因为格式的变化比密度的变化要多一些。

if 'Population' in item.text:

像密度一样,我们开始寻找被标记为标题、文本为“人口”的项目然而,在这之后,我们开始偏离获得城镇密度的道路。在我们进入代码本身之前,我想确切地说明为什么它看起来比您最初认为的要复杂一些:

这是安娜莎·米尔斯的家乡埃塞克斯的维基百科页面:

https://en.wikipedia.org/wiki/Essex

在这里,我们基本上看到了我们在密度中看到的,我们正在搜索的数字在兄弟姐妹的文本中。然而,这并不是它一贯的格式。如果我们看看布拉德福德,爱德华“艾德”金伯的家乡:

https://en.wikipedia.org/wiki/Bradford

母体的数目在父代的兄弟文本中。因此,我们的下一行有点不同:

if item.find_next_sibling() is None:
     stats_dict['pop'] = re.split('(\d*,\d*)',item.parent.find_next_sibling().text)[1]

实质上,如果该项没有兄弟,就找到父项,找到父项的兄弟,然后从父项的兄弟中获取文本,将其拆分,并找到编号。这个数字现在是 stats_dict 中的 population(pop)条目的值。那么下一个条件如下:

elif item.find_next_sibling().text.startswith('%'):
     pass

在这种情况下,如果该项目有一个兄弟,但兄弟的文本以百分号开头,只需忽略它,因为它不会有您要寻找的信息。最后,如果该项有一个同级,并且该同级的文本不以百分号开头,则我们得到以下内容:

else:
     pop_str = item.find_next_sibling().text
     stats_dict['pop']= int(pop_str.split()[0].replace(',',''))

这远没有以前复杂。基本上,获取该项的兄弟,获取它的文本(pop_str),拆分该文本,获取拆分列表中的第一项(包含数字的项),去掉数字中的逗号,然后将其转换为整数。现在在 stats_dict 中被指定为“pop”值。我们终于有了回报声明:

return [url_snippet.split('/')[-1], stats_dict]

这将返回一个列表,其中第一项只是初始 url 片段中的地名。我在事件密度中保留这个名称,或者弹出一个 None 值。如果真的发生这种情况,我可以自己去看页面,然后手动抓取。列表中的第二项是包含密度和人口信息的 stats_dict。

现在我们已经有了一个函数,是时候使用它了。

我上一篇文章的最终产品,即本文开头所示的词典,将被命名为“参赛者姓名年龄城镇”

前三行表示对于字典值中的每个列表,城镇是该列表中的最后一项,现在应该使用 area_stats 函数扩展该列表,该函数将返回一个关于该地点的地名和统计信息的列表。最后,现在我们有了所有的区域统计数据,我们可以取出 url 片段。所有这些让这本字典:

{'Annetha Mills': [30, '/wiki/Essex'],
 'David Chambers': [31, '/wiki/Milton_Keynes'],
 'Edward "Edd" Kimber': [24, '/wiki/Bradford'],
 'Jasminder Randhawa': [45, '/wiki/Birmingham'],
 'Jonathan Shepherd': [25, '/wiki/St_Albans'],
 'Lea Harris': [51, '/wiki/Midlothian'],
 'Louise Brimelow': [44, '/wiki/Manchester'],
 'Mark Whithers': [48, '/wiki/Wales'],
 'Miranda Gore Browne': [37, '/wiki/Midhurst'],
 'Ruth Clemens': [31, '/wiki/Poynton,_Cheshire']}

到这本字典里:

{'Annetha Mills': [30, 'Essex', {'density': 427, 'pop': 1477764}],
 'David Chambers': [31, 'Milton_Keynes', {'density': 2584, 'pop': 229941}],
 'Edward "Edd" Kimber': [24, 'Bradford', {'density': 1290, 'pop': '539,776'}],
 'Jasminder Randhawa': [45, 'Birmingham', {'density': 4262, 'pop': '1,141'}],
 'Jonathan Shepherd': [25, 'St_Albans', {'density': 8140, 'pop': 147373}],
 'Lea Harris': [51, 'Midlothian', {'density': 260, 'pop': '91,340'}],
 'Louise Brimelow': [44, 'Manchester', {'density': 4735, 'pop': '552,858'}],
 'Mark Whithers': [48, 'Wales', {'density': 148, 'pop': '278,000'}],
 'Miranda Gore Browne': [37, 'Midhurst', {'density': 1467, 'pop': 4914}],
 'Ruth Clemens': [31, 'Poynton,_Cheshire', {'density': 1089, 'pop': 14260}]}

现在,我们实际上有了一些有用的区域统计数据,我们不必逐个梳理每个页面来查找这些信息!

用 Python 抓取谷歌地图评论

原文:https://towardsdatascience.com/scraping-google-maps-reviews-in-python-2b153c655fc2?source=collection_archive---------3-----------------------

使用 BeautifulSoup 和 Selenium 抓取最新评论

照片由亨利·佩克斯Unsplash 上拍摄

在这篇文章中,我想和你分享一些关于如何使用 Python SeleniumBeautifulSoup 库来应用数据抓取的知识:这两个工具以正确的方式结合起来允许定义一组 API 来从几乎任何网站收集数据。

注意:从网站收集的任何数据都可能受到版权保护,这意味着未经所有者同意不得重复使用,并且不得明确用于商业目的。

本文的主要目标是展示如何作为编码练习收集数据,以及如何为研究和/或个人项目构建数据集。

在这个简短的免责声明之后,我们可以开始了吗?

先从工具说起。

蟒蛇

Anaconda 是一个框架,它使用虚拟环境的概念,以透明的方式帮助维护每个项目的 Python 库依赖关系:您创建一个环境,在其中安装每个库,并根据您的需要激活/停用该环境,而不会干扰其他项目的依赖关系。你可以在这里下载

这个工具不是强制性的,它可以由任何虚拟环境库(例如:virtualenv)代替,但如果您想在这里介绍的管道末端添加进一步的步骤,如数据清理、数据分析和机器学习,它可能是有用的。此外,您也可以通过 pip 安装所描述的库。

无论如何,要创建我们的抓取环境,请运行以下代码:

conda create --name scraping python=3.6
conda activate scraping 

Selenium 是一个为 web 应用程序自动测试而构建的框架:它的 API 允许我们模拟点击、滚动和网站上发生的任何其他交互。因此,它对于抓取网站也非常有用:点击和滚动会触发页面的变化,从而加载更多的数据(或其他类型的数据)。

该库是用 Java、Python、C#、JavaScript 和许多其他语言编写的:在本文中,我们将使用 Python 实现来加载目标 web 页面,并生成检索附加信息所需的所有交互。

要安装 Selenium,请运行命令:

conda install -c conda-forge selenium

我们还需要安装我们想要使用的浏览器的 web 驱动程序。webdriver 是自动运行浏览器实例的软件,Selenium 将在其上工作。

我决定使用的谷歌 Chromedriver ,你可以从这里下载,但是任何驱动都可以正常工作。

注意:我们将在后面看到的手动测试必须使用我们在这一步选择的浏览器来运行。

美丽的声音

BeautifulSoup 是一个解析 HTML 和 XML 文件的原生 Python 库:它帮助导航树的节点,以非常直观的方式访问属性和特性。

对我们来说,主要用途是解析经过 Selenium 处理的 HTML 页面,将信息提取为原始文本,并将其发送给进一步的处理。

要在我们的 conda 环境中安装库,运行命令:

conda install -c anaconda beautifulsoup4

好了,现在我们应该准备好开始定义我们的抓取模块了!

目标示例将显示如何收集最新的 Google Maps 评论:我们将定义一个导航到特定兴趣点(从现在开始是 POI)并检索其相关最新评论的 scraper。

1。初始化

作为第一步,我们需要初始化我们的网络驱动。该驱动程序可以配置多个选项,但目前我们仅将英语设置为浏览器语言:

options = Options()
options.add_argument("--lang=en")
driver = webdriver.Chrome(chrome_options=options)

2.URL 输入

然后,我们需要提供我们的目标页面:当我们想要抓取 Google Maps 评论时,我们选择一个 POI 并获得直接指向评论的 url。在这一步中,驱动程序只需打开页面。

总经理评估的目标页面示例

这种类型的 URL 相当复杂:我们需要手动将其从浏览器复制到一个变量中,并将其传递给驱动程序。

url = [https://www.google.it/maps/place/Pantheon/@41.8986108,12.4746842,17z/data=!3m1!4b1!4m7!3m6!1s0x132f604f678640a9:0xcad165fa2036ce2c!8m2!3d41.8986108!4d12.4768729!9m1!1b1](https://www.google.it/maps/place/Pantheon/@41.8986108,12.4746842,17z/data=!3m1!4b1!4m7!3m6!1s0x132f604f678640a9:0xcad165fa2036ce2c!8m2!3d41.8986108!4d12.4768729!9m1!1b1)driver.get(url)

3.单击菜单按钮

现在,我们要提取 最新的评论,而页面默认设置呈现最相关的评论。我们需要点击“排序”菜单,然后点击“最新”标签。

这就是 Selenium(和编码技能)真正发挥作用的地方:我们需要找到按钮,单击它,然后单击第二个按钮。为此,我使用了 Selenium 提供的 XPath 搜索方法:这比 CSS 搜索更容易,这也要感谢 Chropath ,这是一个浏览器扩展,它将 XPath 解释器添加到浏览器开发工具中。

这样,我们检查页面以测试表达式,直到我们突出显示所需的元素:

第一个按钮的 XPath 表达式测试

第二个按钮的 XPath 表达式测试

不幸的是,这还不够。Google Maps 网站(和许多其他现代网站一样)主要是使用 AJAX 实现的:网站的许多部分是异步加载的,这意味着如果 Selenium 在加载页面后立即查找按钮,它们可能不会被加载。

但是在那种情况下我们也有解决办法。Selenium 实现了等待功能:在某些条件被验证之后或者在最大超时时间过去之后执行点击。等到元素在页面上出现并可点击,就解决了前面的问题。

该部分的代码是:

wait = WebDriverWait(driver, 10)
menu_bt = wait.until(EC.element_to_be_clickable(
                       (By.XPATH, '//button[[@data](http://twitter.com/data)-value=\'Sort\']'))
                   )  
menu_bt.click()
recent_rating_bt = driver.find_elements_by_xpath(
                                     '//div[[@role](http://twitter.com/role)=\'menuitem\']')[1]
recent_rating_bt.click()
time.sleep(5)

Sleep 函数被添加到这个块的末尾,因为点击触发了一个 AJAX 调用来重新加载评论,因此我们需要在进入下一步之前等待…

4.审查数据提取

现在,我们终于达到了目标,评论数据。我们将页面发送到 BeautifulSoup 解析器,它帮助找到正确的 HTML 标签、div 和属性。

首先,我们确定了 review 的包装器 div:find _ all 方法创建了一个 div 元素列表,这些元素具有特定的属性。在我们的例子中,列表包含页面上的评论的 div。

response = BeautifulSoup(driver.page_source, 'html.parser')
rlist = response.find_all('div', class_='section-review-content')

对于每个评论,我们解析它的信息:评级星、文本内容(如果有的话)、评论日期、评论者姓名、评论 id。

id_r = r.find('button', 
              class_='section-review-action-menu')['data-review-id']
username = r.find('div', 
                  class_='section-review-title').find('span').texttry:
    review_text = r.find('span', class_='section-review-text').text
except Exception:
    review_text = Nonerating = r.find('span', class_='section-review-stars')['aria-label']
rel_date = r.find('span', class_='section-review-publish-date').text

5.卷动

最后但同样重要的是:该页面已经加载了 20 篇评论,但是如果不向下滚动页面,其他评论就不可用。

Selenium API 中没有直接实现滚动,但是它们允许执行 JavaScript 代码并将其应用于页面的特定元素:我们标识可以滚动的 div 对象,并运行简单的 JS 代码行来滚动到页面底部。

scrollable_div = driver.find_element_by_css_selector(
 'div.section-layout.section-scrollbox.scrollable-y.scrollable-show'
                     )
driver.execute_script(
               'arguments[0].scrollTop = arguments[0].scrollHeight', 
                scrollable_div
               )

正如你所看到的,在这个简短的教程中,我试图解释从谷歌地图上抓取评论的核心要素,但同样的概念也适用于许多现代网站。复杂性很高,我在这里没有考虑所有的细节:如果你想有一个完整的例子,检查我在 Github 这里的知识库。

感谢您的阅读。让我知道你对它的想法,如果你有任何问题!

用 Python 抓取交互式折线图

原文:https://towardsdatascience.com/scraping-interactive-charts-with-python-2bc20a9c7f5c?source=collection_archive---------15-----------------------

带着穿过生产线

【www.freepik.com free pik 制作的 T2 商业照片

假设你想知道今天美元对欧元的表现。快速的谷歌搜索就能搞定,只需输入:“美元欧元”。你会看到这样一个交互式图表:

为了查看整个周期的值,您需要沿线移动光标,同时包含值和日期的标签会立即更新。

现在假设您想从这个图表中获取所有数据,并为自己创建一个数据库。如果标签中的值一直变化,如何从整行中刮出数据?既然你能看见它,你能刮它,就一定有办法。

如果你要手动完成,你要做的是沿着这条线移动光标,同时在 Excel 表格中输入每个值,或者甚至在笔记本上手写。在这篇文章中,我们将看到如何让 selenium 做同样的事情。我们将让它像人一样工作,遍历行并记录值。

虽然我们使用的是 Google 的图表,但是这里实现的逻辑可以适用于任何类似的图表。

我们基本上使用的是熊猫、日期时间模块。好了,在我们导入所有我们要用的东西后,让我们直接打开连接并抓取页面。

然后我们实例化 action 对象,我们将使用它来移动屏幕上的光标,以及 search_barsearch_button 对象,我们将使用它们来执行我们的搜索。完成后,只需使用 send_keys 方法编写搜索,并使用 click 方法点击搜索按钮。我们将使用 WebDriverWait ,以便它等待元素被完全加载到页面中:

现在让我们找到图表元素,并获取它在页面上的大小和位置。这很重要,这样我们就知道将光标移动到哪里。为此,我们还将使用 WebDriverWait

运行我们到目前为止所做的一切,这样您就可以看到以下输出:

{'x': 514, 'y': 262}
{'height': 134, 'width': 301}

现在我们有了这个信息,我们可以用它来移动光标到对象的最右边,使用move _ to _ element _ with _ offset。此方法将鼠标移动指定元素的偏移量。偏移量是相对于元素的左上角的,所以我们需要将对象的整个长度作为 xoffset 来传递。由于不需要在 y 轴上移动,yooffset可以设置为零:

如果我们使用 move_to_element 来代替,光标将被移动到元素的中心。

现在我们的光标在这里:

请注意图表最右边的光标。

然后我们得到第一个日期值对:

我们现在只需要光标继续向左移动。为此,我们需要设置:

  • 光标移动的速度;
  • 光标移动的截止日期。

我们将使用动作对象的 move_by_offset 方法将光标从其最后一个已知位置移动到下一个位置。无限循环将使光标移动到我们设置的截止日期。当日期超过极限时,我们称之为突破

这是我们预期的行为:

很酷吧。!每次光标向左移动,它都会从标签中抓取一个新的值和日期。就像人类移动鼠标做笔记一样!

如果你在谷歌的一个图表中这样做,并且你改变了图表的时间范围,比如说,到年,一些日期可能会被跳过。这些日期即使手动也无法访问。可能是因为 x 轴对于这么小的图表来说变得太大了。

此外,重要的是要明确节奏是由反复试验决定的。如果速度太小,光标将需要很长时间才能移动到图表中的下一个日期。如果太大,它可能会跳过日期。

然而,不可避免的是,有时光标仍然会在同一个日期,即使它刚刚移动。因此,最好将数据存储在字典中,并用它来丢弃重复的数据。当我们完成抓取时,我们可以将这个字典转换成一个数据帧。这是完整的代码:

这是我们刚刚收集的数据:

最后一个警告:如果你正在观察光标在这条线上的移动,你会注意到它在每一次循环中都回到了起点。即使 selenium 保持最后的位置,也会发生这种情况,但是您也可以注意到,光标在每个新循环中以我们建立的速度继续向左移动。所以,一切都按计划进行。

嗯,就是这样。我希望你喜欢它,这可能是有用的。如果你有问题,有建议,或者只是想保持联系,请随时通过 TwitterGitHubLinkedin 联系。

用 3 行代码一步一步地抓取实时交通数据

原文:https://towardsdatascience.com/scraping-live-traffic-data-in-3-lines-of-code-step-by-step-9b2cc7ddf31f?source=collection_archive---------9-----------------------

了解如何用最少的代码在 python 中 web 抓取实时更新的图表。

来源:TomTom。

鉴于最近的疫情,决策者实施的封锁措施已经停止了大部分经济活动。由于经济数据的滞后性,在数据中衡量消费者的实时行为并不总是容易的。事实上,数据往往至少有一个月的时滞,因此很难评估人们是否真的在四处走动。因此,政府、科学家和经济学家等一直在关注高频数据,这些数据提供了自限制实施以来全球经济运动如何变化的实时视图。TomTom 提供的流量数据是衡量活动进展的一个流行指标。该数据涵盖 57 个国家的 416 个城市,并计算整个道路网络上所有车辆的行驶时间。在 TomTom 的网站上,平均拥堵程度以实时交通图的形式显示。我选择了米兰:

米兰 TomTom 交通指数。来源:汤姆汤姆。

我们可以将鼠标悬停在图表上以获得每个单独的数据点,但无法从网站上下载数据。所以有两个选择:

  1. 个小时悬停在每个点上,记录每个数值…
  2. 刮吧!

检查数据

在任何网站上,网站在加载页面时都会加载一系列不同的信息,这是很常见的。这可能包括 cookies、数据文件、图像等等。我们可以通过检查页面来了解内幕。在 Chrome 中,按下' Ctrl+shift+I '就可以轻松做到这一点。将出现一个窗口,显示已加载到页面中的所有数据。我们想要的选项卡是弹出窗口顶部显示的网络选项卡。

检查 TomTom 米兰交通网页。

如果你看不到所有的数据,点击' Ctrl+R' ,重新加载页面,观察所有数据的加载。在名称选项卡上,你会看到许多不同的文件类型:。js,。json,。svg,。otf 等等。那么我们如何知道哪一个包含我们图表的底层数据呢?首先,我们需要通过 XHR 进行过滤。这是 XML HTTP 请求的简称。使用这种格式载入网页上的数据是很常见的。然后我们可以按大小过滤——底层数据通常是页面中包含的最大文件之一(可能以千字节而不是字节为单位)。最后,通常情况下,源数据会以的形式出现。json 文件。这代表了 Javascript 对象符号,这是存储大量数据的常用方式。

然而,查看我们的数据集,并不能立即看出 json 文件在哪里。下一步,让我们看看柱。因为我们已经通过 xhr 进行了过滤,所以我们应该在这个列中只看到 xhr 类型。说到这里,我们顺着栏目往下看,可以看到 xhr fetch获取类型意味着该数据从 API 或自动处理接口加载。获取类型查看数据,这个特定对象的文件名是“ITA _ Milan”。 看来我们已经得到了我们的数据!我们可以通过在新标签中打开它来检查它是否正确。当我们打开新选项卡时,我们看到这确实是我们想要的数据,在链接下面:【https://api.midway.tomtom.com/ranking/live/ITA_milan】这是从 API 中检索的。太好了——现在让我们将这些数据加载到 python 中,并开始清理它们以复制实时图表。

检索和清理数据

首先,请求是我们将用来加载数据的模块。在我们之前找到的 url 上使用 requests.get(),我们可以将该文件显示为一个 json ,并使用 python 中的 json 模块对其进行解包(是的,只使用了三行代码):

%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import json
import requests# retrieve json file
url_ = "[https://api.midway.tomtom.com/ranking/live/ITA_milan](https://api.midway.tomtom.com/ranking/live/ITA_milan)"
italy_req = requests.get(url)
italy_json = italy_req.json()

这为我们提供了以下输出:

{'data': [{'JamsDelay': 13.5,'TrafficIndexLive': 6,'TrafficIndexHistoric': 17,'UpdateTime': 1586608290000,'JamsLength': 1.4,'JamsCount': 4},{'JamsDelay': 4.2,'TrafficIndexLive': 6,'TrafficIndexHistoric': 17,'UpdateTime': 1586609190000,'JamsLength': 0.4,'JamsCount': 2},{'JamsDelay': 5.8,'TrafficIndexLive': 6,'TrafficIndexHistoric': 18,'UpdateTime': 1586610090000,'JamsLength': 0.4,'JamsCount': 2},

这个文件可能看起来有点混乱,有很多不同的标点和括号。它比看起来简单——JSON文件实际上是一个名为‘数据’的字典,其中包含一个字典列表。所以为了得到我们想要的信息。(“Time”和“TrafficIndexLive”),我们要调用每个想要检索的点的键。例如,要获得实时流量指数的第一个值,我们需要输入以下内容:

italy_json["data"][0]["TrafficIndexLive"]

然后,我们可以将字典中的每个条目添加到一个列表中,将每个列表转换为熊猫数据帧中的一列:

实时交通数据帧。

使用字典和一点点数据清理,我们已经做到了!让我们通过绘制图表来验证数据是否与实时图表相匹配:

米兰实时交通。

我们做到了!在几行代码中,我们能够从一个图表中检索数据,否则我们无法访问这些数据。原来他们说的是真的:看得见就刮!

感谢阅读! 如果您有任何见解,请随时发表评论。包含我用来做这个项目的源代码的完整 Jupyter 笔记本可以在我的 Github 资源库中找到。

参考资料:

[1] TomTom,2020。《米兰交通报道。可在:https://www.tomtom.com/en_gb/traffic-index/milan-traffic/

免责声明:本文表达的所有观点均为本人观点,与 先锋或任何其他金融实体没有任何关联。我不是一个交易者,也没有用本文中的方法赚钱。这不是财务建议。

抓取亚马逊商店以生成价格警报

原文:https://towardsdatascience.com/scraping-multiple-amazon-stores-with-python-5eab811453a8?source=collection_archive---------3-----------------------

只需几行 Python 代码,您就可以构建自己的 web 抓取工具来监控多个商店,这样您就不会错过很多东西了!

对那些亚马逊交易保持警惕!(照片由加里·本迪格拍摄)

我怎么会在这里?

我认为有一点是公平的,我们都有一个来自亚马逊的书签产品页面,我们疯狂地刷新它,希望价格能下降。

好吧,也许不是疯狂地,但肯定是一天几次。

我将向您展示如何编写一个简单的 Python 脚本,它可以从他们的任何商店抓取亚马逊产品页面,并检查价格,等等。我努力使它保持简单,如果你已经知道基本的东西,你应该能够顺利地跟上。以下是我们将在这个项目中做的事情:

  • 创建一个 csv 文件,其中包含我们想要的产品的链接,以及我们愿意购买的价格
  • Beautiful Soup 编写一个函数,该函数将循环遍历 csv 文件中的链接并检索关于它们的信息
  • 将所有东西存储在一个“数据库”中,并随时跟踪产品价格,这样我们就可以看到历史趋势
  • 安排脚本在一天中的特定时间运行
  • Extra —当价格低于你的限额时,创建电子邮件提醒

我还在编写一个脚本,它采用搜索词而不是产品链接,并返回所有商店中最相关的产品。如果你觉得这可能有用,请在评论中告诉我,我会写另一篇关于它的文章!

更新:我刚刚制作了一个全程视频!检查一下,让我知道你节省了多少:)

永恒的愿望清单…

将你的爱好扩展到更专业的领域,最悲哀的事情通常是需要购买更好的设备。以摄影为例。购买一台新相机是一个可以显著影响你睡眠时间的决定。众所周知,购买新镜头也会产生类似的效果——至少我是这么认为的!不仅技术方面非常相关,需要一些研究,而且你也希望得到尽可能好的价格。

研究完成后,就该在我们知道的每一个网店里搜索选中的型号了。

将你知道的商店数量乘以选择的型号数量,你就会得到我的浏览器上打开的标签的大概数量。大多数情况下,我最终会再次访问亚马逊……就我而言,因为我在欧洲,这通常涉及到搜索意大利、法国、英国、西班牙和德国等国家的亚马逊商店。我发现同样的产品有非常不同的价格,但更重要的是,每个市场都有特定的偶尔交易。我们不想错过这个机会…

这就是了解一点 Python 可以为您省钱的地方。字面意思!

我开始测试一些网页抓取来帮助我自动完成这项任务,结果发现每个商店的 HTML 结构都差不多。这样我们就可以在所有的中使用我们的脚本来快速获得所有商店的所有价格。

如果你想访问我的其他网络抓取文章——以及媒体上的几乎所有内容——你考虑过订阅吗?你会大力支持我的工作!

[## 阅读媒体上的每一个故事!

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@fneves/membership)

入门指南

我以前写过几篇关于网络抓取的文章,解释了漂亮的汤是如何工作的。这个 python 包非常容易使用,你可以查看 我写的这篇文章 是为了从房屋列表中收集价格。简而言之,Beautiful Soup 是一个工具,您可以使用它从 HTML 页面中访问特定的标签。即使你以前没有听说过它,我打赌你一看到代码就能明白它在做什么。

您需要一个名为 TRACKER_PRODUCTS.csv 的文件,其中包含您想要跟踪的产品的链接。本 Github 库中提供了一个模板。每次运行后,scraper 将结果保存在一个名为“search _ history _[随便什么日期]”的不同文件中。xlsx”。这些是 search_history 文件夹中的文件。您也可以在存储库中找到它。

这是我们需要的文件夹和文件结构

由于我不想让事情变得过于复杂,我将首先使用 Jupyter 笔记本向您展示代码输出。但是最后,我们会给这段代码一些类固醇,并在一个 Amazon_Scraper.py 文件中把它变成一个不错的函数。最重要的是,我们将创建一个计划任务来不时地运行它!

我们需要的就是汤

让我们从笔记本视图开始。在你的 Jupyter 笔记本上使用下面的代码片段,这样你就可以看到代码的每一部分是做什么的。

这里最不为人知的包大概就是 glob 了。这是一个很好的包,它允许你在一个文件夹中获得文件名列表之类的东西。请求将负责获取我们在跟踪列表中设置的 URL。美丽的汤是我们这次挑战的网络抓取工具。如果你需要安装它们中的任何一个,简单的 pip/conda 安装就可以了。有很多资源可以帮助你,但通常情况下, Python 包索引页面会有。

需要 HEADERS 变量来传递 get 方法。我在上面提到的其他文章中也讨论了它,但是当使用请求包访问 URL 时,您可以将它视为您的身份证。它告诉服务器你正在使用哪种浏览器。你可以在这里阅读更多关于这个的内容。

现在可以从 存储库 中获取名为 TRACKER_PRODUCTS.csv 的 csv 文件,并将其放在文件夹“trackers”中。

然后我们把它放进美味的汤里。这将使 HTML 变得更加“容易理解”,(巧妙地)命名为

新鲜的王子回归让你开心!

应该挑哪些食材?

我们从简单的东西开始,比如产品的名称。虽然这几乎是多余的,但是一旦我们检查了 excel 文件,给出一些关于产品的细节是一件好事。

我添加了其他字段,如评论分数/计数和可用性,不是因为它们与购买决策相关,而是因为我对这些东西有点强迫症,我更喜欢有“有一天会有用”的变量……看到特定产品的评论分数的变化可能会很有趣。也许不会,但无论如何我们会保留它!

每当你看到 soup.find 的时候,就意味着我们正在试图使用页面的 HTML 标签(比如 div,或者 span 等等)来寻找页面的元素。)和/或属性(名称、id、类别等。).与 soup.select 一样,我们使用的是 CSS 选择器。你可以在浏览器上使用 Inspect 功能并导航页面代码,但我最近发现了一个非常方便的 Chrome 扩展,名为 SelectorGadget ,我强烈推荐它。这使得找到正确的代码更加容易。

在这一点上,如果你觉得很难理解选择器是如何工作的,我鼓励你阅读这篇 文章 ,在那里我会更详细地解释一下

下面你可以看到每个部分返回的内容。如果您刚开始使用 web 抓取,但仍然不完全理解它是如何工作的,我建议您将代码分成几部分,慢慢弄清楚每个变量在做什么。

我总是在网络抓取文章中写这个免责声明,但是如果你几个月后阅读这篇文章,这里的代码可能不再正确工作了——例如,如果亚马逊改变页面的 HTML 结构,这可能会发生。

如果发生这种情况,我会鼓励你去解决它!一旦你分解代码,使用我的例子这真的没什么大不了的。只需要修复你的代码正在获取的选择器/标签。你可以在下面留言,我会尽力帮你。

(反)构汤

获得我们产品的名称应该是小菜一碟。价格部分更具挑战性,最后,我不得不添加几行代码来纠正它,但是在这个例子中,这部分就足够了。

您将在脚本的最终版本中看到,我还为在美国商店购物的读者添加了获取美元价格的功能!

这导致了 try/except 控件的增加,以确保我每次都得到正确的字段。在编写和测试 web scraper 时,我们迟早会面临同样的选择。

我们可能会浪费 2 个小时来获取每次都能得到页面正确部分的 HTML 片段,而不能保证这是可能的!或者我们可以简单地即兴创作一些错误处理条件,这将让我们更快地使用工作工具

我并不总是这样或那样做,但是当我写代码的时候,我确实学到了更多的注释。这真的有助于提高代码的质量,甚至当你想回去重新开始以前的项目时。

这是运行中的脚本

奇迹发生的地方

正如你所看到的,获得单独的成分是非常容易的。测试完成后,是时候编写一个合适的脚本了,它将:

  1. 从 csv 文件中获取 URL
  2. 使用 while 循环抓取每个产品并存储信息
  3. 在 excel 文件中保存所有结果,包括以前的搜索

要编写这个,您需要您最喜欢的代码编辑器(我使用 Spyder,它随 Anaconda 安装一起提供— 旁注:版本 4 非常好)并创建一个新文件。我们就叫它 Amazon_Scraper.py

对我们在上面看到的零碎内容有一些补充,但我希望评论有助于使它变得清楚。这个文件也在 资源库 中。

跟踪产品

关于文件 TRACKER_PRODUCTS.csv 的几点说明,这是一个非常简单的文件,有三列(“url”、“code”、“buy_below”)。您可以在这里添加想要监控的产品 URLs】。

你甚至可以把这个文件放在你同步的 Dropbox 文件夹的某个部分(之后用新的文件路径更新脚本),这样你就可以用你的手机随时更新它。如果您将脚本设置为在服务器或您家中的笔记本电脑上运行,它将在下次运行时从文件中选择新产品链接。

搜索历史

SEARCH_HISTORY 文件也是如此。第一次运行时,您需要将一个空文件(在 存储库 中找到)添加到文件夹“search_history”中。在上面脚本的第 116 行中,当定义 last_search 变量时,我们试图在搜索历史文件夹中找到最后一个文件这就是为什么你也需要在这里映射你自己的文件夹。只需将文本替换为运行这个项目的文件夹(在我的例子中是“Amazon Scraper”)。

价格预警

在上面的脚本中,第 97 行有一个区域,如果价格低于你的限制,你可以用它来发送一封带有某种警告的电子邮件。

每当你的价格达到目标时,就会发生这种情况。

它出现在 try 命令中的原因是,并不是每次我们从产品页面获得实际价格时,逻辑比较都会返回一个错误——例如,如果产品不可用。

我不想让脚本变得太复杂,所以我把它从最终代码中去掉了。然而,你可以在 这篇文章 中拥有来自一个非常相似项目的代码。

我在脚本中留下了一个带有购买警告的打印指令,所以您只需要用电子邮件部分替换它。就当是你的作业吧!

设置运行脚本的计划任务

亲爱的 Mac/Linux 读者,这部分将只讨论 Windows 中的调度程序,因为这是我使用的系统。对不起 Mac/Linux 用户!我 100%肯定这些系统也有替代方案。如果你能在评论里让我知道,我会在这里加上

设置一个自动化任务来执行我们的小脚本并不困难:

1 —首先打开“任务计划程序”(只需按下 windows 键并输入)。然后选择“创建任务”并选择“触发器”选项卡。我每天 10 点和 19 点 30 分跑步。

2 —接下来你移动到动作选项卡。在这里,您将添加一个操作,并为“程序/脚本”框选择 Python 文件夹位置。我的位于程序文件目录中,正如你在图片中看到的。

3 —在 arguments 框中,您要键入我们的函数文件名。

4 —我们将告诉系统在我们的文件 Amazon_Scraper.py 所在的文件夹中启动这个命令

从这里开始,任务就可以运行了。您可以探索更多的选项,并进行测试以确保它的工作。这是用 Windows 任务计划程序安排脚本自动运行的基本方法!

我认为我们涵盖了许多有趣的特性你现在可以用它们来探索其他网站或者构建更复杂的东西。感谢您的阅读,如果您有任何问题或建议,我会尽量回复所有邮件!如果我在下面看到一些请求,我可能会考虑做一个视频教程,所以让我知道你是否愿意把它和文章放在一起。

如果你想看我的其他网页抓取例子,这里有两个不同的项目:

[## 我在找房子,所以我用 Python 做了一个 web scraper!

几个月后,我将不得不离开我租的公寓,去找一个新的。尽管这种经历很痛苦…

towardsdatascience.com](/looking-for-a-house-build-a-web-scraper-to-help-you-5ab25badc83e) [## 用一个简单的 Python 机器人增加你的 Instagram 粉丝

我在 4 天内有了 500 个真正的追随者!

towardsdatascience.com](/increase-your-instagram-followers-with-a-simple-python-bot-fde048dce20d)

如果你读到这里,你可能已经意识到我喜欢摄影,所以为了表达我的谢意,我将留给你一张我的照片!

夜晚的卢浮宫金字塔,还有一个不要脸的塞给展柜我的一个爱好!

感谢您的阅读!一如既往,我欢迎反馈和建设性的批评。如果你想取得联系,可以在这里联系我或者直接回复下面的文章。

如何用 Python 抓取多个 URL:教程

原文:https://towardsdatascience.com/scraping-multiple-urls-with-python-tutorial-2b74432d085f?source=collection_archive---------0-----------------------

因为您想要的数据并不总是您拥有的数据

来源

在本文中,我将向您展示三种从多个 URL 获取数据的方法。更具体地说,我将展示如何遍历页码,遍历手动创建的 URL 列表,最后遍历一个粗略的 URL 列表。

我假设在本教程中,你有一些网页抓取的超级基础知识。如果你需要快速复习如何检查和抓取一个网站,看看这个。

[## 一个 Kaggle 不会教你的教程:网页抓取,数据清理等等

因为数据科学不仅仅是 EDA 和培训模型

towardsdatascience.com](/a-tutorial-of-what-kaggle-wont-teach-you-web-scraping-data-cleaning-and-more-16d402a206e8)

我将从 Hostelworld 收集旅馆数据,Hostelworld 是世界上寻找旅馆最好的网站。好了,现在我们开始吧!

在页码上循环

这是抓取多个页面的最简单、最直接的方式。让我们先来看看我们收集旅舍的 URL 的末尾(文章末尾有完整的 URL):

我们看到对于第一页,我们有 page=1。对于第二页,我们将有 page=2,依此类推。

因此,我们需要做的就是创建一个“for”循环,在这里我们改变最后一个数字。对于每个页面,循环将收集我们指定的信息。

这里是收集从市中心的距离的代码,宿舍床的价格,一个私人房间的价格,以及以前的客户对网站前 2 页找到的所有旅馆的平均评级。

  • 我在这里使用 selenium 是因为 hostelworld 页面是 JavaScript 渲染的,BeautifulSoup 无法处理。
  • 我去掉了" price-title 5" 元素,因为该元素允许我们知道价格是针对宿舍还是私人房间。
  • 睡眠功能有助于控制我们向网站服务器发出请求的速度(避免降低服务器速度),但也有助于确保 selenium 在继续运行之前找到我们想要的信息。

通常,我们会继续清理数据以使其可用,但我将在最后用最后一种方法来做这件事。让我们继续下一个方法。

遍历手动创建的 URL 列表

那太好了,但是如果你要抓取的不同网址没有你可以循环通过的页码怎么办?此外,如果我想要的具体信息只在旅舍的实际页面上提供,该怎么办?

第一种方法是手动创建一个 URL 列表,并遍历这个列表。下面是为前两个旅馆创建 URL 列表的代码:

url = ['[https://www.hostelworld.com/pwa/hosteldetails.php/Casa-Gracia-Barcelona-Hostel/Barcelona/45620?from=2020-07-03&to=2020-07-05&guests=1'](https://www.hostelworld.com/pwa/hosteldetails.php/Casa-Gracia-Barcelona-Hostel/Barcelona/45620?from=2020-07-03&to=2020-07-05&guests=1') ,
       '[https://www.hostelworld.com/pwa/hosteldetails.php/Itaca-Hostel/Barcelona/1279?from=2020-07-03&to=2020-07-05&guests=1'](https://www.hostelworld.com/pwa/hosteldetails.php/Itaca-Hostel/Barcelona/1279?from=2020-07-03&to=2020-07-05&guests=1',\)]

然后,您可以创建一个新的“for”循环,遍历列表中的每个元素并收集您想要的信息,其方式与第一种方法完全相同。

如果你只有几个 URL,那也可以,但是想象一下如果你有 100,1000 甚至 10000 个 URL!当然,手动创建列表不是你想要做的(除非你有大量的空闲时间)!

谢天谢地,有更好/更聪明的方法来做事。

循环浏览抓取的 URL 列表

这是本教程的最后一个方法。让我们仔细看看我们正在抓取的 Hostelworld 页面。

我们看到每个旅舍列表都有一个 href 属性,它指定了到单个旅舍页面的链接。这就是我们想要的信息。

方法如下:

  1. 创建一个“for”循环,抓取我们需要的所有页面的所有 href 属性(以及 URL)。
  2. 清理数据并创建一个包含所有收集的 URL 的列表。
  3. 创建一个新的循环,遍历 URL 列表,收集所有需要的信息。
  4. 清理数据并创建最终的数据帧。

需要指出的是,如果抓取的每一页都有不同的结构,这种方法将无法正常工作。网址需要来自同一个网站!

对于每一个旅舍页面,我都刮掉了旅舍的名称、一张床最便宜的价格、评论数量以及 8 个类别(位置、氛围、安全、清洁度等)的评论分数。).

这使得我们看到的第一种方法毫无用处,因为使用这种方法,我们可以获得所有相同的信息,甚至更多!

下面是获得干净的 URL 列表的代码。

  • 不需要的链接很可能会出现在你的 URL 列表中,就像这里的情况一样。一般来说,几乎总是有一个非常独特的模式来区分你想要的网址和其他网址(宣传等)。).在这种情况下,所有指向旅馆的链接都以/pwa/开头。
  • 我将字符串'https://www.hostelworld.com'添加到列表的每个元素中。在接下来的循环中,URL 需要用到这一部分。

现在我们有了干净网址的列表,我们可以通过循环列表来抓取我们想要的所有信息。

由于每次迭代大约需要 15-20 秒,所以我将只对这里的前 10 个旅舍这样做。你可以很容易地通过改变范围来改变它。

  • 当我收集评论数量时,由于该信息在每页上出现两次,所以我使用[-1]只获得最后一次发现的评论数量。
  • 通常有许多价格选择(取决于宿舍的类型)。最后给的价格永远是最便宜的,这也是我想保留的。如果找到多个,try/except 循环基本上保持最后的价格,如果只找到一个,则保持价格不变。

这种类型的循环是处理潜在错误的好方法!

收集完所有数据后,下面是清理数据并将其放入 dataframe 的代码:

这是最终数据帧的头部:

现在你有了,三种不同的抓取多个页面/URL 的方法。我真的希望这有所帮助,不要忘记负责任地刮。

非常感谢你的阅读!

参考

[## 便宜的巴塞罗那旅舍“旅舍宿舍和私人房间”旅舍世界

巴塞罗那拥有欧洲最好的夜生活,吸引了来自世界各地的背包客和派对爱好者…

www.hostelworld.com](https://www.hostelworld.com/s?q=Barcelona, Catalonia, Spain&country=Spain&city=Barcelona&type=city&id=83&from=2020-07-03&to=2020-07-05&guests=1&page=1)

用 Python 从公共 API 抓取新闻和文章

原文:https://towardsdatascience.com/scraping-news-and-articles-from-public-apis-with-python-be84521d85b9?source=collection_archive---------14-----------------------

让我们探索纽约时报、卫报、黑客新闻和其他 API,并为您的下一个项目收集一些新闻数据!

无论你是数据科学家、程序员还是人工智能专家,你都可以很好地利用大量的新闻文章。尽管获得这些文章可能具有挑战性,因为你必须经过相当多的环节才能获得实际数据——找到正确的新闻来源,探索它们的 API,找出如何根据它们进行认证,最后收集数据。那是很多工作而且没有乐趣。

因此,为了节省您的时间并帮助您入门,这里列出了我能够找到的公共新闻 API,并解释了如何验证、查询它们,最重要的是如何从它们那里获取您需要的所有数据的示例!

里沙布·夏尔马Unsplash 拍摄的原始照片

纽约时报

在我看来,第一个也是最好的数据来源是《纽约时报》。要开始使用它的 API,你需要在https://developer.nytimes.com/accounts/create创建一个账户,在https://developer.nytimes.com/my-apps/new-app创建一个应用程序。创建应用程序时,您可以选择激活哪些 API——我建议至少激活最受欢迎的文章搜索头条新闻归档 API。当您的应用程序被创建时,您将看到一个密钥,您将使用它来与所有选定的 API 进行交互,所以复制它,让我们开始查询吧!

我们可以用《T21 时报》API 做的最简单的查询就是查找当前的头条新闻:

上面的片段非常简单。我们针对提供了section名称和我们的 API 密钥的topstories/v2端点运行一个GET请求。在这种情况下,Section 是 science ,但是 NY Times 在这里提供了许多其他选项,例如时尚、健康、体育或戏剧。完整列表可在这里找到。这个特定的请求将产生类似如下的响应:

接下来,当你试图获得一些特定的数据集时,可能是最有用的端点是文章搜索端点:

这个端点具有许多过滤选项。唯一的必填字段是q(查询),这是搜索词。除此之外,您还可以混合匹配过滤查询、日期范围(begin_dateend_date)、页码、排序顺序和方面字段。过滤器查询(fq)是一个有趣的查询,因为它允许使用 Lucene 查询语法,可以使用逻辑操作符(ANDOR)、否定或通配符来创建复杂的过滤器。好看的教程可以在这里找到。

上述查询的示例响应可能是这样的(为了清楚起见,删除了一些字段):

我将在这里展示的纽约时报的最后一个端点是他们的归档 API,它返回了从 1851 年开始的给定月份的文章列表。如果您需要大量数据,并且不需要搜索特定术语,这将非常有用。

上面的查询搜索了 1852 年 6 月以来的所有文章,从下面的结果中我们可以看到,即使我们搜索了非常旧的文章,我们仍然得到了 1888 个命中结果。也就是说,其中大多数缺乏有用的数据,如关键词、字数、作者等。所以你最好还是搜索一些最近的文章。

这些只是纽约时报提供的一些(在我看来)更有用的 API。除了这些,在 https://developer.nytimes.com/apis 还有更多。为了探索每一个 API,我还推荐使用查询构建器,比如用于文章搜索的的,它让你不用任何编码就可以在网站上构建并执行你的测试查询。

《卫报》

接下来是另一个重要的新闻和文章来源——卫报。与纽约时报一样,我们首先需要注册一个 API 密钥。你可以在 https://bonobo.capi.gutools.co.uk/register/developer 办理,你会收到一封电子邮件,里面有你的钥匙。这样一来,我们可以导航到 API 文档并开始查询 API。

让我们简单地从查询卫报的内容部分开始:

这些部分将内容按主题分组,如果您正在寻找特定类型的内容,例如科学技术,这将非常有用。如果我们省略 query ( q)参数,我们将收到完整的部分列表,大约 75 条记录。

继续一些更有趣的事情——通过标签搜索:

这个查询看起来与前一个非常相似,也返回相似类型的数据。标签也将内容分成不同的类别,但是标签的数量(大约 50000 个)要比章节多得多。这些标签中的每一个都具有类似于例如world/extreme-weather的结构。这些在搜索实际文章时非常有用,这是我们接下来要做的。

你来这里的真正目的是文章搜索,为此我们将使用https://open-platform.theguardian.com/documentation/search:

我首先向您展示部分标签搜索的原因是,它们可以用于文章搜索。从上面可以看到,我们使用了sectiontag参数来缩小搜索范围,这些值可以使用前面显示的查询找到。除了这些参数,我们还为我们的搜索查询包括了明显的q参数,但也使用了from-dateshow-fields参数的开始日期,这允许我们请求与内容相关的额外字段——在这种情况下,这些将是标题、署名、评级和缩短的 URL。这里有更多的完整列表

与之前的所有问题一样,以下是示例响应:

黑客新闻

对于更多面向技术的新闻来源,人们可能会转向 HackerNews ,它也有自己的公共 REST API。https://github.com/HackerNews/API 上有记载。正如你将看到的,这个 API 是在版本v0中,目前非常简单,这意味着它并没有真正提供特定的端点,例如查询文章、评论或用户。

但是,即使它非常基础,它仍然提供了所有必要的东西,例如,获取头条新闻:

上面的代码片段没有前面的那么明显,所以让我们更仔细地看一下。我们首先向 API 端点(v0/topstories)发送请求,它不会像您所期望的那样返回热门故事,而实际上只是它们的 id。为了获得实际的故事,我们获取这些 id(前 10 个)并向v0/item/<ID>端点发送请求,端点返回每个单独项目的数据,在本例中恰好是一个故事。

您肯定注意到查询 URL 是用query_type参数化的。这是因为, HackerNews API 也为网站的所有顶部部分提供了类似的端点,即提问、展示、工作或新闻。

这个 API 的一个优点是它不需要认证,所以你不需要请求 API 密钥,也不需要像其他 API 那样担心速率限制。

运行这段代码将得到类似如下的响应:

如果你发现了一篇有趣的文章,想更深入地挖掘一下,那么 HackerNews API 也可以帮你。您可以通过遍历所述故事的kids字段找到每个提交的评论。这样做的代码如下所示:

首先,我们按照 ID 查找 story ( item),就像我们在前面的例子中做的那样。然后,我们迭代它的kids,用各自的 id 运行相同的查询,检索条目,在本例中是指故事评论。如果我们想要构建特定故事的评论的整个树/线程,我们也可以递归地遍历这些。

和往常一样,以下是回答示例:

电流

找到受欢迎和高质量的新闻 API 是相当困难的,因为大多数经典报纸没有免费的公共 API。然而,总的新闻数据来源可以用来从报纸上获取文章和新闻,例如金融时报彭博只提供付费 API 服务,或者 CNN 根本不公开任何 API。

其中一个聚合器叫做 Currents API 。它汇集了来自数千个来源、18 种语言和 70 多个国家的数据,而且还是免费的。

它类似于之前显示的 API。我们再次需要首先获得 API 密钥。为此,你需要在 https://currentsapi.services/en/register 注册。之后,在https://currentsapi.services/en/profile访问您的个人资料并取回您的 API 令牌。

准备好密钥(令牌)后,我们可以请求一些数据。只有一个有趣的终点,那就是 https://api.currentsapi.services/v1/search 的:

这个端点包括许多过滤选项,包括语言、类别、国家等等,如上面的代码片段所示。所有这些都是不言自明的,但是对于我提到的前三个,您将需要一些额外的信息,因为它们可能的值并不是很明显。这些值来自可用的 API 端点这里是,在语言和区域的情况下,实际上只是值到代码的映射(例如"English": "en"),在类别的情况下,只是可能值的列表。上面的代码中省略了它,以使它更短一些,但是我只是将这些映射复制到 Python dict中,以避免每次都调用 API。

对上述要求的回应如下:

如果您不搜索特定主题或历史数据,那么还有一个选项是 Currents API 提供的,即最新新闻端点:

它非常类似于search端点,但是这个端点只提供language参数并产生如下结果:

结论

互联网上有许多很棒的新闻网站和在线报纸,但在大多数情况下,你无法抓取它们的数据或以编程方式访问它们。本文中展示的是极少数具有良好 API 和免费访问的应用程序,您可以将其用于您的下一个项目,无论是一些数据科学、机器学习还是简单的新闻聚合器。如果你不介意为新闻 API 付费,你也可以考虑使用金融时报彭博。除了 API 之外,你还可以尝试用类似于 BeautifulSoup 的东西抓取 HTML 并自己解析内容。如果你碰巧发现任何其他好的新闻数据来源,请告诉我,以便我可以将其添加到这个列表中。🙂

本文最初发布于martinheinz . dev

[## 您需要开始使用的高级 SQLAlchemy 功能

通过 SQLAlchemy 及其混合属性、嵌套查询、表元数据,在 Python 中使用 SQL 很容易

towardsdatascience.com](/advanced-sqlalchemy-features-you-need-to-start-using-e6fc1ddafbdb) [## 你可以用 GitHub API 和 Python 做的所有事情

GitHub REST API 允许您管理问题、分支、回购、提交等等,所以让我们看看您如何使用…

towardsdatascience.com](/all-the-things-you-can-do-with-github-api-and-python-f01790fca131) [## 自动化 Python 项目的各个方面

每个 Python 项目都可以从使用 Makefile、优化的 Docker 映像、配置良好的 CI/CD、代码…

towardsdatascience.com](/automating-every-aspect-of-your-python-project-6517336af9da)

使用 Python 收集 NFL 数据并比较四分卫效率

原文:https://towardsdatascience.com/scraping-nfl-stats-to-compare-quarterback-efficiencies-4989642e02fe?source=collection_archive---------20-----------------------

使用 BeautifulSoup 收集 NFL 数据并绘制四分卫的雷达图

Riley McCullough 在 Unsplash 上拍摄的照片

我总是担心试图收集自己的数据,事实上,像 Kaggle 这样的网站聚集了如此高质量的数据集,使得学习这种技能变得不那么必要。然而,这个平台上大量关于数据科学的教育文章帮助我在收集自己的数据集方面取得了进展。很多搜集数据的灵感和方法都来自这里的。

在本文中,我将从 Pro Football Reference 中提取 2019–20 NFL 赛季的四分卫统计数据,并使用它们创建雷达图来评估 QB 效率。

加载包

为了打开网页并抓取数据,我们将使用两个模块,urllib.request打开 URL,BeautifulSoup解析 HTML。

# Import scraping modules
from urllib.request import urlopen
from bs4 import BeautifulSoup

除了这些包,我们还需要一些包来操作数据,numpypandas,并绘制我们的数据,matplotlib

# Import data manipulation modules
import pandas as pd
import numpy as np# Import data visualization modules
import matplotlib as mpl
import matplotlib.pyplot as plt

刮数据

我们要导入的数据是 2019 赛季的 NFL 传球数据,可以在这里找到。我们打开站点,并通过以下内容将其传递给BeautifulSoup:

# URL of page
url = 'https://www.pro-football-reference.com/years/2019/passing.htm'# Open URL and pass to BeautifulSoup
html = urlopen(url)
stats_page = BeautifulSoup(html)

请注意,通过将 URL 中的2019更改为您选择的年份,我们可以很容易地将所有这些分析调整到以前的年份。

我们将用来抓取页面的两个BeautifulSoup函数是findAll()getText(),它们基于我们正在抓取的页面的 HTML 返回值。我在下面给出了简化的用例——对于所有的可能性,你应该参考文档

findAll(name)Parameters
name -- HTML tags to use to parse webpageReturns array of all matches to name tag getText()Returns text from HTML

为了使这些有效,我们必须确定页面源中的模式。在我们的例子中,数据在表格中被很好地格式化,所以我们可以找到所有的表格行(tr)和列(td),并直接从单元格中提取文本。

首先,我们需要收集列标题,以便稍后在数据框架中使用它们。为此,我们找到页面中的第一个tr元素,并从所有表格标题中收集文本(th):

# Collect table headerscolumn_headers = stats_page.findAll('tr')[0]
column_headers = [i.getText() for i in column_headers.findAll('th')]

我们索引第一个元素,因为这是包含列标题的行。我们可以查看我们的结果:

print(column_headers)>>> ['Rk', 'Player', 'Tm', 'Age', 'Pos', 'G', 'GS', 'QBrec', 'Cmp', 'Att', 'Cmp%', 'Yds', 'TD', 'TD%', 'Int', 'Int%', '1D', 'Lng', 'Y/A', 'AY/A', 'Y/C', 'Y/G', 'Rate', 'QBR', 'Sk', 'Yds', 'NY/A', 'ANY/A', 'Sk%', '4QC', 'GWD']

为了收集实际的数据,我们将首先收集所有的表行(tr)并将它们存储在一个数组中。然后,我们遍历每一行,用getText()收集每一列中的文本(td):

# Collect table rows
rows = stats_page.findAll('tr')[1:]# Get stats from each row
qb_stats = []
for i in range(len(rows)):
  qb_stats.append([col.getText() for col in rows[i].findAll('td')])

我们跳过第一行,因为这些是我们之前刚刚收集的列标题。当我们检查qb_stats列表的第一行时:

print(qb_stats[0])>>> ['Jared Goff', 'LAR', '25', 'QB', '16', '16', '9-7-0', '394', '626', '62.9', '4638', '22', '3.5', '16', '2.6', '220', '66', '7.4', '7.0', '11.8', '289.9', '86.5', '', '22', '170', '6.90', '6.46', '3.4', '1', '2']

现在,我们可以将标题和统计数据合并到一个pandas数据帧中。如果您以前没有使用过pandas,它本质上是一个 Excel 电子表格,您可以通过编程来操作,因此它非常适合处理大型数据集。我们注意到上面的Rk列在我们的qb_stats列表中没有相应的数据——这是因为那些值都是表头,所以我们的findAll()函数没有提取它们的数据。无论如何,这些数据对于我们的分析来说都是无关紧要的,因此我们在创建数据帧时会将其忽略。

# Create DataFrame from our scraped data
data = pd.DataFrame(qb_stats, columns=column_headers[1:])

columns —数据框架的列标题(我们省略了Rk)

现在,让我们看看数据帧的前五行:

# Examine first five rows of data
data.head()

成功!

操作和清理数据

现在,我们可以处理这个数据框中的数据,得到我们需要的东西来制作我们的雷达图。首先,让我们看看集合中的所有列:

# View columns in data
data.columns>>> Index(['Player', 'Tm', 'Age', 'Pos', 'G', 'GS', 'QBrec', 'Cmp', 'Att', 'Cmp%', 'Yds', 'TD', 'TD%', 'Int', 'Int%', '1D', 'Lng', 'Y/A', 'AY/A', 'Y/C', 'Y/G', 'Rate', 'QBR', 'Sk', 'Yds', 'NY/A', 'ANY/A', 'Sk%', '4QC', 'GWD'], dtype='object')

我们立即看到一个问题—有两个标题为Yds的列;一个是传球码,另一个是因为被抢而失去的码。我们可以通过重命名后者来轻松解决这个问题:

# Rename sack yards column to `Yds_Sack`
new_columns = data.columns.values
new_columns[-6] = 'Yds_Sack'
data.columns = new_columns

现在,让我们再次查看我们的专栏:

# View columns in data
data.columns>>> Index(['Player', 'Tm', 'Age', 'Pos', 'G', 'GS', 'QBrec', 'Cmp', 'Att', 'Cmp%', 'Yds', 'TD', 'TD%', 'Int', 'Int%', '1D', 'Lng', 'Y/A', 'AY/A', 'Y/C', 'Y/G', 'Rate', 'QBR', 'Sk', 'Yds_Sack', 'NY/A', 'ANY/A', 'Sk%', '4QC', 'GWD'], dtype='object')

我们已经成功地将该列重命名为Yds_Sack,并且不再有列名冲突!接下来,让我们确定我们对可视化感兴趣的统计类别。我们将选择:

(1)完成百分比— Cmp%

(2)传球码— Yds

(3)传球达阵— TD

(4)拦截— Int

每次试跳 5 码— Y/A

(6)及格分数— Rate

# Select stat categories
categories = ['Cmp%', 'Yds', 'TD', 'Int', 'Y/A', 'Rate']

现在,让我们创建一个新的数据框架,作为原始数据的子集,只使用我们选择的类别中的数据。此外,我们将添加球员的名字和球队。

# Create data subset for radar chart
data_radar = data[['Player', 'Tm'] + categories]
data_radar.head()

现在我们有了数据子集,让我们检查数据类型,因为我们从 URL 中提取了文本形式的值:

# Check data types
data_radar.dtypes>>> Player    object
    Tm        object
    Cmp%      object
    Yds       object
    TD        object
    Int       object
    Y/A       object
    Rate      object
    dtype: object

我们所有的数字数据都被存储为对象,所以我们不能操作它们。因此,在我们继续之前,我们必须将所有这些数据转换成数值。为此,我们使用了一个名为pandas.to_numeric的函数。

# Convert data to numerical values
for i in categories:
  data_radar[i] = pd.to_numeric(data[i])

现在,让我们再次检查我们的数据类型:

# Check data types
data_radar.dtypes>>> Player     object
    Tm         object
    Cmp%      float64
    Yds       float64
    TD        float64
    Int       float64
    Y/A       float64
    Rate      float64
    dtype: object

我们还有最后一项数据清理工作要做。在最初的网站上,他们把装饰性的人物放在有季末成就的球员旁边,比如职业碗(*)或全职业(+)选择。我们将使用str.replace()移除这些:

# Remove ornamental characters for achievements
data_radar['Player'] = data_radar['Player'].str.replace('*', '')
data_radar['Player'] = data_radar['Player'].str.replace('+', '')

让我们把数据过滤到投球距离超过 1500 码的四分卫:

# Filter by passing yards
data_radar_filtered = data_radar[data_radar['Yds'] > 1500]

现在,对于我们的雷达图,我们想通过百分位数计算每个四分卫的统计排名,这在pandas中用DataFrame.rank(pct=True)很容易完成。rank()函数可以采用其他参数来根据其他参数进行排序,您可以查阅在线文档

此外,我们想翻转我们的拦截排名,因为我们不希望有最多拦截的 QB 有最高的百分位数!

# Create columns with percentile rank
for i in categories:
  data_radar_filtered[i + '_Rank'] = 
  data_radar_filtered[i].rank(pct=True)# We need to flip the rank for interceptions
data_radar_filtered['Int_Rank'] = 
1 - data_radar_filtered['Int_Rank']

现在我们检查我们的新数据:

# Examine data
data_radar_filtered.head()

太好了!我们现在可以进行可视化了!

生成雷达图

我们将从编辑一些通用的绘图参数开始。我们将生成一个极坐标图,因此 x 刻度对应于围绕圆的角度,我们将增加轴和刻度标签之间的填充:

# General plot parameters
mpl.rcParams['font.family'] = 'Avenir'
mpl.rcParams['font.size'] = 16
mpl.rcParams['axes.linewidth'] = 0
mpl.rcParams['xtick.major.pad'] = 15

对于图表中的颜色,我们将使用 NFL 球队颜色的十六进制代码,这些代码是从链接中收集的。

team_colors = {'ARI':'#97233f', 'ATL':'#a71930', 'BAL':'#241773', 'BUF':'#00338d', 'CAR':'#0085ca', 'CHI':'#0b162a', 'CIN':'#fb4f14', 'CLE':'#311d00', 'DAL':'#041e42', 'DEN':'#002244', 'DET':'#0076b6', 'GNB':'#203731', 'HOU':'#03202f', 'IND':'#002c5f', 'JAX':'#006778', 'KAN':'#e31837', 'LAC':'#002a5e', 'LAR':'#003594', 'MIA':'#008e97', 'MIN':'#4f2683', 'NWE':'#002244', 'NOR':'#d3bc8d', 'NYG':'#0b2265', 'NYJ':'#125740', 'OAK':'#000000', 'PHI':'#004c54', 'PIT':'#ffb612', 'SFO':'#aa0000', 'SEA':'#002244', 'TAM':'#d50a0a', 'TEN':'#0c2340', 'WAS':'#773141'}

我们绘制所有观点的角度将取决于我们所拥有的统计类别的数量。在我们的例子中,我们有 6 个类别,所以我们将每隔 2π/6 弧度或 60 度绘制我们的点。我们可以使用numpy.linspace()计算如下:

# Calculate angles for radar chart
offset = np.pi/6
angles = np.linspace(0, 2*np.pi, len(categories) + 1) + offset

我们添加了offset项来调整标签出现在圆上的位置(第一个标签不是 0 弧度,而是出现在π/6)。

当我们绘制数据时,我们需要实际复制第一个类别,这样形状就会自动闭合。如果你注意到当我们计算角度时,我们有 7 个数据点,第一个和最后一个角度对应于圆上的同一点。因此,当我们绘制数据时,我们使用以下内容(我们将把它变成一个函数,所以player_data表示我们将传递的一行特定于玩家的数据):

# Plot data and fill with team color
ax.plot(angles, np.append(player_data[-(len(angles)-1):], player_data[-(len(angles)-1)]), color=color, linewidth=2)ax.fill(angles, np.append(player_data[-(len(angles)-1):], player_data[-(len(angles)-1)]), color=color, alpha=0.2)

上面的代码是有效的,因为我们的类别是数据帧的最后 6 列,所以len(angles) — 1对应于这些类别中的第一列(因为 angles 有一个额外的元素)。然后,我们将第一个类别的值附加到该数组的末尾,这样我们就可以关闭该形状。

现在我们可以设置类别名称的标签(因为我们的类别比角度少一个,所以我们省略了最后一个元素):

# Set category labels
ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories)

最后,我们将在雷达图的顶部添加玩家的名字——我们将文本对象放置在绝对绘图坐标中的(π/2,1.7)处,以便它出现在轴的上方:

# Add player name
ax.text(np.pi/2, 1.7, player_data[0], ha='center', va='center', size=18, color=color)

我们可以将所有这些放在一起,创建一个辅助函数来生成我们的雷达图,如下所示:

让我们创建另一个助手函数,当给定一个团队输入时,返回 QB 数据的numpy数组:

# Function to get QB data
def get_qb_data(data, team):
  return np.asarray(data[data['Tm'] == team])[0]

可视化数据

NFC 西

因为我是 49 人队的超级粉丝,所以我们先来看看 NFC 西区 QBs 的雷达图:

# Create figure
fig = plt.figure(figsize=(8, 8), facecolor='white')# Add subplots
ax1 = fig.add_subplot(221, projection='polar', facecolor='#ededed')
ax2 = fig.add_subplot(222, projection='polar', facecolor='#ededed')
ax3 = fig.add_subplot(223, projection='polar', facecolor='#ededed')
ax4 = fig.add_subplot(224, projection='polar', facecolor='#ededed')# Adjust space between subplots
plt.subplots_adjust(hspace=0.8, wspace=0.5)# Get QB data
sf_data = get_qb_data(data_radar_filtered, 'SFO')
sea_data = get_qb_data(data_radar_filtered, 'SEA')
ari_data = get_qb_data(data_radar_filtered, 'ARI')
lar_data = get_qb_data(data_radar_filtered, 'LAR')# Plot QB data
ax1 = create_radar_chart(ax1, angles, lar_data, team_colors['LAR'])
ax2 = create_radar_chart(ax2, angles, ari_data, team_colors['ARI'])
ax3 = create_radar_chart(ax3, angles, sea_data, team_colors['SEA'])
ax4 = create_radar_chart(ax4, angles, sf_data, team_colors['SFO'])plt.show()

数据似乎支持我们从视力测试中看到的:

  1. Russell Wilson 处于精英水平,在所有统计类别中至少达到 75 个百分点。这个分析也没有考虑到他的扰流能力带来了什么。
  2. 吉米·加罗波洛通常是一个可靠的四分卫,但不时会投出一些愚蠢的拦截。
  3. 贾里德·戈夫(Jared Goff)获得了很多码,但这似乎并没有转化为大量生产(“空码”)。
  4. 凯勒穆雷很难判断,因为他是一个新秀,但他的效率看起来是四个人中最低的。像威尔逊一样,他的机动性在这个情节中没有被考虑。

MVP 赛

最有价值球员的争夺(在 QB)在拉塞尔·威尔逊和拉马尔·杰克逊(谁最终获胜)之间展开:

# MVP Race
# Create figure
fig = plt.figure(figsize=(8, 4), facecolor='white')# Add subplots
ax1 = fig.add_subplot(121, projection='polar', facecolor='#ededed')
ax2 = fig.add_subplot(122, projection='polar', facecolor='#ededed')# Adjust space between subplots
plt.subplots_adjust(hspace=0.8, wspace=0.5)# Get QB data
bal_data = get_qb_data(data_radar_filtered, 'BAL')
sea_data = get_qb_data(data_radar_filtered, 'SEA')# Plot QB data
ax1 = create_radar_chart(ax1, angles, sea_data, team_colors['SEA'])
ax2 = create_radar_chart(ax2, angles, bal_data, team_colors['BAL'])plt.show()

从一个纯粹的传球者的角度来看,拉塞尔·威尔逊有更平衡的数据,但拉马尔·杰克逊显然有更“划算”的传球码数,正如他的传球得分和四分卫得分所显示的那样。此外,拉马尔·杰克逊创造了一个赛季的 QB 冲刺记录,这在这张图表中没有体现出来。

起草第一轮 QBs 的团队

四名四分卫在 2020 年 NFL 第一轮选秀中被选中:乔·伯罗(CIN),图阿·塔戈瓦洛(米娅),贾斯汀·赫伯特(拉加),以及(令人惊讶的)乔丹·洛夫(英国)。让我们想象一下这些选秀会取代的四分卫的数据。

# 1st Round Draft Picks
# Create figure
fig = plt.figure(figsize=(8, 8), facecolor='white')# Add subplots
ax1 = fig.add_subplot(221, projection='polar', facecolor='#ededed')
ax2 = fig.add_subplot(222, projection='polar', facecolor='#ededed')
ax3 = fig.add_subplot(223, projection='polar', facecolor='#ededed')
ax4 = fig.add_subplot(224, projection='polar', facecolor='#ededed')# Adjust space between subplots
plt.subplots_adjust(hspace=0.8, wspace=0.5)# Get QB data
cin_data = get_qb_data(data_radar_filtered, 'CIN')
mia_data = get_qb_data(data_radar_filtered, 'MIA')
lac_data = get_qb_data(data_radar_filtered, 'LAC')
gnb_data = get_qb_data(data_radar_filtered, 'GNB')# Plot QB data
ax1 = create_radar_chart(ax1, angles, cin_data, team_colors['CIN'])
ax2 = create_radar_chart(ax2, angles, mia_data, team_colors['MIA'])
ax3 = create_radar_chart(ax3, angles, lac_data, team_colors['LAC'])
ax4 = create_radar_chart(ax4, angles, gnb_data, team_colors['GNB'])plt.show()

  1. 无论从哪方面来看,安迪·道尔顿都经历了一个糟糕的赛季——显然是时候继续前进了
  2. Ryan Fitzpatrick 在所有六个统计指标上都低于平均水平,这个赛季表现平平。考虑到乔什-罗森在菲茨派翠克的比赛中坐冷板凳,热火需要为图阿的未来投资。
  3. 菲利普·里弗斯实际上在大多数类别中表现平平,但显然有一些糟糕的决策,从他拦截的次数来看。
  4. Aaron Rodgers 经历了一个似乎高于平均水平的赛季,但从我们对他的高度期望来看,仍然低于平均水平。乔丹的爱情选择对每个人来说都是一个震惊。

其他分部

NFC 北方

NFC 东

NFC South

亚足联西区

AFC 北部

亚足联东区

亚足联南区

结束语

正如您所看到的,可能性是无限的——这个框架可以很容易地适用于其他统计数据,如抢断和接收指标。本文使用的 Jupyter 笔记本可以在这个 Github 资源库中找到。

感谢您的阅读!我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系以获得更多更新和文章。

从半结构化文档中抓取结构化数据

原文:https://towardsdatascience.com/scraping-structured-data-from-semi-structured-documents-d5fd2927a828?source=collection_archive---------39-----------------------

作为建立朋友角色网络项目的一部分,我需要从每一集收集信息

数据科学工具带来的最强大的功能之一是处理非结构化数据并将其转化为可结构化和可分析的数据的能力。任何称职的数据科学家都应该能够从文档中“抓取”数据,无论是来自网络、本地还是任何其他类型的基于文本的资产。

在这篇文章中,我将展示如何抓取电视节目 Friends 的在线脚本,目的是为每一集创建一个编号场景表以及这些场景中的角色名称。这是我建立互动朋友网络网站的第一步。这也是一个很好的抓取技术的测试案例,因为剧本都有一定的基本结构,但这种结构并不完全可以预测,编剧并不总是遵循每集相同的格式规则。

你可以在我的朋友项目的 Github repo 上找到这项工作的所有最终代码。

我要刮的脚本可以在这里找到。如果你点击每一个,你可以看到文件名有一个一致的格式,格式为[https://fangj.github.io/friends/season/[ss][ee].html](https://fangj.github.io/friends/season/0101.html),其中[ss]是两位数的季号,[ee]是两位数的集号。

为了有效地刮——你需要了解两件事:

  1. 您选择的语言的相关抓取包。在我将在这里使用的 R 中,这些包是rvestxml2。在 Python 里,大部分人用的都是美汤。如果你想要一个关于如何使用rvestxml2抓取网页的深入教程,请看我之前的文章这里,我建议你在阅读这篇文章之前先阅读一下。
  2. 使用regex(正则表达式的缩写)的能力,这是文本搜索的语言。在本文中,我们将更多地关注regexregex的语法在不同的平台上可能会有一些不同,但是大部分都非常相似。R 中regex的一个很好的备忘单是这里的。regex不是一个容易精通的话题——这个世界上很少有真正的regex专家——但是大多数数据科学家知道足够多的知识来执行最常见的任务,并且经常在网上搜索他们需要的其余内容。

看着老友记的剧本,想出我们需要做什么

让我们提醒自己这里的任务。我们对两件事感兴趣:

  • 我们想把一集分成几个场景
  • 我们想列出每个场景中出现的所有角色

让我们来看看第一季第一集的网页代码。你可以通过在 Google Chrome 中打开脚本,然后按下 CMD+Option+C(或者 Windows 中的 Ctrl+Shift+C)来打开 Elements 控制台,在这里你可以与页面本身并排查看页面的 HTML。

我们可以立即看到的一件事是,冒号前面的大多数单词都是我们感兴趣的。其实大部分都是在一个场景里说了些什么的角色名。我们还看到包含字符串"Scene:"的线条是场景边界的非常可靠的指示器。

我们可能要做的第一件事是在一个列表或节点向量中获取 HTML 代码,这些节点表示文档中不同的格式和文本。因为这将包含每个角色所说的单独的台词,这将对我们的工作非常有帮助。所以我们将使用我们漂亮的抓取包来下载 HTML 代码,将其分解成节点,这样我们就有了一个漂亮整洁的脚本内容向量。

library(rvest) # (also automatically loads xml2) url_string <- "https://fangj.github.io/friends/season/0101.html" nodes <- xml2::read_html(url_string) %>% 
  xml2::as_list() %>% 
  unlist()

现在,如果你看一下你的nodes对象,你会发现它是一个字符向量,包含许多不同的分割部分,但最重要的是它包含脚本中的行,例如:

> nodes[16] html.body.font.p 
"[Scene: Central Perk, Chandler, Joey, Phoebe, and Monica are there.]"

使用正则表达式提取我们需要的内容

为了对我们的任务有用,我们需要创建一个向量,如果该行代表一个场景的开始,则包含单词“New Scene ”,如果该行代表角色所说的话,则包含角色的名称。这将是我们想要做的最好的形式。

我们需要做的第一件事是将任何包含"Scene:"的文本字符串交换为字符串"New Scene"。我们可以非常简单地在nodes向量上使用ifelse(),其中我们使用grepl()来识别nodes中的哪些条目包含字符串"Scene:"

nodes <- ifelse(grepl("Scene:", nodes), "New Scene", nodes)

我们可以快速检查是否有包含"New Scene"的条目。

> nodes[nodes == "New Scene"] [1] "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" 
[9] "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" "New Scene" "New Scene"

效果很好。现在,你可能也注意到了冒号前面的字符名。因此,这可能是提取字符名称的好方法(虽然它可能会给我们一些脚本中冒号之前的其他内容,但我们可以稍后再处理)。

所以我们要做的是用regex告诉 R 我们正在寻找冒号前面的任何东西。我们将如下使用一个前瞻字符串:".+?(?=:)"

让我们看看这个字符串,确保我们知道它的意思。.+?组件的意思是“查找任意长度的任意文本字符串”。括号中的部分被称为 lookahead :它的意思是向前查找该字符串,并找到一个冒号作为下一个字符。因此,这指示 R 查找冒号前面的任何文本字符串并返回它。如果我们将包stringr和它的函数str_extract()与这个 regex 字符串一起使用,它将遍历nodes向量的每个条目,并将其转换为冒号前面的第一个文本字符串。如果没有找到这样的字符串,它将返回一个NA值。这对我们来说很好,因为我们知道口语字符名称总是在节点的开始,所以如果我们只取每行中的第一个实例,我们肯定不会错过任何一个。为了安全起见,我们还应该不要弄乱我们已经放入向量中的场景中断:

library(stringr) nodes <- ifelse(nodes != "New Scene", 
                stringr::str_extract(nodes, ".+?(?=:)"), 
                nodes)

现在让我们看看节点向量中有什么

> nodes[sample(100)]
  [1] "Joey"                       NA                         "Chandler"                  
  [4] NA                           "Phoebe"                     "All"                       
  [7] "Chandler"                   NA                           NA                          
 [10] NA                           NA                           NA                          
 [13] NA                           "Joey"                       "Chandler"                  
 [16] NA                           NA                           NA                          
 [19] NA                           "Transcribed by"             NA                          
 [22] "Joey"                       NA                           NA                          
 [25] NA                           NA                           NA                          
 [28] NA                           NA                           NA                          
 [31] "Phoebe"                     NA                           NA                          
 [34] "Monica"                     NA                           NA                          
 [37] NA                           NA                           NA                          
 [40] NA                           "Additional transcribing by" NA                          
 [43] "(Note"                      NA                           NA                          
 [46] NA                           NA                           NA                          
 [49] NA                           NA                           NA                          
 [52] NA                           "Monica"                     NA                          
 [55] NA                           NA                           "New Scene"                 
 [58] "Monica"                     NA                           "Ross"                      
 [61] NA                           NA                           NA                          
 [64] NA                           NA                           "Chandler"                  
 [67] "Joey"                       NA                           NA                          
 [70] "Chandler"                   "Chandler"                   NA                          
 [73] NA                           NA                           NA                          
 [76] NA                           "Written by"                 "Monica"                    
 [79] NA                           NA                           NA                          
 [82] "Ross"                       "Joey"                       "Monica"                    
 [85] NA                           NA                           NA                          
 [88] NA                           NA                           "Chandler"                  
 [91] "Phoebe"                     NA                           NA                          
 [94] "Chandler"                   NA                           NA                          
 [97] NA                           NA                           NA                          
[100] NA

所以这是可行的——但是我们有更多的清洁工作要做。例如,我们想要去掉NA值。我们还注意到,有一些序言行通常包含单词“by ”,我们可以看到括号中的字符串(如“(注意))似乎已被提取。如果我们不想要它们,我们可以创建一堆特殊的清理命令来清除它们。例如:

nodes <- nodes[!is.na(nodes)] # remove NAs

# remove entries with "by" or "(" or "all" irrelevant of the case
nodes <- nodes[!grepl("by|\\(|all", tolower(nodes))]

让我们看一个例子:

> nodes[sample(10)]
 [1] "Phoebe"    "Monica"    "New Scene" "Chandler"  "Chandler"  "Joey"      "Chandler"  "Monica"   
 [9] "Chandler"  "Phoebe"

这看起来不错。当然,我上面做的清理步骤并不完整,我们放在!grepl("by|\\(|all", tolower(nodes))中的那个字符串将会随着我们做越来越多的抓取而扩展,以解决解析中的常见故障。但是你明白了。请注意,当您在regex字符串中使用字符时,这些字符也被用作“特殊字符”,您需要在它们前面加上一个\\来对它们进行转义。我的意思是:R 需要知道你什么时候输入一个( -你的字面意思是你正在寻找一个(还是你正在启动一个前瞻命令或类似的东西。所以如果你想让一个特殊的字符按字面意思理解——是的,我真的想要一个字面的左括号——你应该在 regex 中把它写成\\(。请参考上面的备忘单链接或在线查看 regex 中的特价商品列表。

组织我们的产出

让我们假设我们的清理工作已经完成,我们有一个很好的向量,它包含在剧集中说台词的角色的名字或者“新场景”来表示我们正在穿越一个场景边界。我们现在只需要将这个向量转换成一个简单的数据帧,它有三列:episodescenecharacter

剧集编号是显而易见的,我们已经有了角色列表,所以我们真的只需要遍历我们的节点向量,对于每个条目,计算“新场景”之前出现的次数并加 1。我们可以通过以下方式做到这一点:

# number each scene
  scene_count <- c()

  for (i in 1:length(nodes)) {
    scene_count[i] <- sum(grepl("New Scene", nodes[1:i])) + 1
  }

然后,我们可以通过将三个向量放在一起并删除同一场景中任何重复的字符来最终确定我们的数据帧。我们还可以修正脚本以新场景开始的情况,我们可以一致地将角色名称格式化为标题大小写,以考虑不同的大小写类型:

library(tidyverse)

results <- data.frame(episode = 1, scene = scene_count, character = nodes) %>% 
    dplyr::filter(character != "New Scene") %>% 
    dplyr::distinct(episode, scene, character) %>% 
    dplyr::mutate(scene = scene - min(scene) + 1, # set first scene number to 1
                  character = character %>% tolower() %>% tools::toTitleCase()) # title case

让我们看看results数据框架的一些输出示例:

归纳为每一季和每一集的函数

当然,我们这里的目的不是只刮第一集,而是刮每一季的每一集。一名优秀的数据科学家现在将寻求概括他们所做的工作,并将其放入一个函数中,该函数将接受一个季节编号和一集编号,然后抓取该集并返回我们刚刚构建的数据帧。

如果我们看看第一季第一集的格式,我们会发现它在大部分——尽管不是全部——剧集中重复出现。有一些例外:

  • 第二季(第三集)的一些情节有不同的格式
  • 整个第十季似乎使用了一些不同的 HTML 格式,格式出现在冒号之前,而不是之后。

因此,有必要用if else语句扩展上面的代码,以考虑到我们知道格式会有些不同的情况。我们还需要尽可能地扩大我们的清理范围,以考虑到我们解析其他剧集时发生的我们没有预料到的事情。在抓取文本和清理意料之外的结果时,需要一点人力,这是很正常的。最终结果并非 100%无误也是很常见的。数据科学家必须确定什么时候结果足够接近他们需要的,什么时候清理剩余的 1-2%的错误不值得这么做。

这里是我的最后一集抓取功能,我很高兴做我需要的工作。你会看到代码锚围绕着我们上面所做的工作,但是把它扩展到所有的季节和剧集。

现在我们可以用这个简单的命令来抓取第九季第二集:

scrape_friends(9, 2)

这个功能将会变得非常有用,因为我们将会尝试根据出现在同一个场景中的角色来创建角色网络的边列表。在接下来的文章中,请留意这一点。

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn Twitter上找我。也可以看看我在drkeithmcnulty.com的博客。

《老友记》(NBC 提供)

从 PDF 表格中提取数据—使用 Python 中的一行代码

原文:https://towardsdatascience.com/scraping-table-data-from-pdf-files-using-a-single-line-in-python-8607880c750?source=collection_archive---------0-----------------------

在本文中,您将学习使用 python 从 PDF 文件的表格中提取数据并导出到 CSV/Excel 的最佳方式。

戴维·克洛德在 Unsplash 上的照片

从 PDF 文件中获取表格不再是一项困难的任务,您可以使用 python 中的一行代码来完成。

你将学到什么

  1. 安装磁盘库。
  2. 正在导入库。
  3. 阅读 PDF 文件。
  4. 读取 PDF 文件特定页面上的表格。
  5. 读取 PDF 文件同一页面上的多个表格。
  6. 将 PDF 文件直接转换为 CSV 文件。

白板

Tabula 是一个有用的软件包,它不仅允许你从 PDF 文件中抓取表格,还可以将 PDF 文件直接转换成 CSV 文件。

所以让我们开始吧…

1.安装磁盘库

pip install tabula-py

2.导入 tabula 库

import tabula

3.阅读 PDF 文件

让我们把这个 PDF 剪切成熊猫数据帧。

图片由 Satya Ganesh 提供

file1 = "[https://nbviewer.jupyter.org/github/kuruvasatya/Scraping-Tables-from-PDF/blob/master/data1.pdf](https://nbviewer.jupyter.org/github/kuruvasatya/Scraping-Tables-from-PDF/blob/master/data1.pdf)"table = tabula.read_pdf(file1,pages=1)table[0]

看看上面在 Google Colabs 中执行的代码片段的输出

图片由 Satya Ganesh 提供

4.读取 PDF 文件特定页面上的表格。

假设我们需要废弃这个包含多页的 PDF 文件

图片由 Satya Ganesh 提供

图片由 Satya Ganesh 提供

file2 = "[https://nbviewer.jupyter.org/github/kuruvasatya/Reading-Table-Data-From-PDF/blob/master/data.pdf](https://nbviewer.jupyter.org/github/kuruvasatya/Reading-Table-Data-From-PDF/blob/master/data.pdf)"# To read table in first page of PDF file
table1 = tabula.read_pdf(file2 ,**pages=1**)# To read tables in secord page of PDF file
table2 = tabula.read_pdf(file2 ,**pages=2**)print(table1[0])
print(table2[0])

5.如果一个 PDF 文件的同一个页面上有多个表格怎么办?

假设我们需要抓取这两个表格,它们在一个 PDF 文件 的同一页上。

图片由 Satya Ganesh 提供

To read multiple tables we need to add extra parameter**multiple_tables = True** -> Read multiple tables as independent tables
**multiple_tables = False** -> Read multiple tables as single table

5.1.将多个表作为独立的表读取

file3 = "[https://nbviewer.jupyter.org/github/kuruvasatya/Reading-Table-Data-From-PDF/blob/master/data3.pdf](https://nbviewer.jupyter.org/github/kuruvasatya/Reading-Table-Data-From-PDF/blob/master/data3.pdf)"tables = tabula.read_pdf(file3 ,pages=1, **multiple_tables=True**)print(tables[0])
print(tables[1])

图片由 Satya Ganesh 提供

图片由 Satya Ganesh 提供

5.2 将多个表作为单个表读取

tables = tabula.read_pdf(file3 ,pages=1,**multiple_tables=False**)tables[0]

图片由 Satya Ganesh 提供

6.将 PDF 文件直接转换为 CSV 文件

我们可以使用 tabula 库中的 convert_into() 方法将包含表格数据的 PDF 文件直接转换为 CSV 文件。

1.将一页 PDF 文件中的表格转换为 CSV 格式

# output just the first page tables in the PDF to a CSVtabula.convert_into("pdf_file_name", "Name_of_csv_file.csv")

2.将 PDF 文件中的所有表格转换为 CSV 格式

tabula.convert_into("pdf_file_name","Name_of_csv_file.csv",**all****=****True**)

结论

我希望您学会了一种使用 python 中的一行代码来抓取 PDF 文件表格的好方法。

查看我的相关文章

[## 从网站抓取表格数据—使用 Python 中的一行代码

本文将教您如何使用 python 中的一行代码从网站中抓取表格数据。

towardsdatascience.com](/scraping-table-data-from-websites-using-a-single-line-in-python-ba898d54e2bc) [## 新冠肺炎的影响-使用 Python 进行数据可视化

使用 python 在印度地图上可视化冠状病毒爆发的初级方法。当你到达…的终点时

towardsdatascience.com](/impact-of-covid-19-data-visualization-using-python-6f8e3bdc860b)

参考

[## 表格:将 PDF 中的表格读入数据框架表格文档

是 tabula-java 的一个简单的 Python 包装器,可以读取 PDF 的表格。您可以从 PDF 读取表格并转换成…

tabula-py.readthedocs.io](https://tabula-py.readthedocs.io/en/latest/)

感谢阅读😃过得愉快

从网站抓取表格数据—使用 Python 中的一行代码

原文:https://towardsdatascience.com/scraping-table-data-from-websites-using-a-single-line-in-python-ba898d54e2bc?source=collection_archive---------12-----------------------

本文将教您使用 python 中的一行代码从网站中抓取表格数据的最佳方式。

米卡·鲍梅斯特在 Unsplash 上的照片

介绍

D 如今,ata 已经成为最有价值的货币和珍贵商品,你使用它的方式将使你与普通人有所不同。您需要足够聪明来获取这些数据,这些数据在您身边随处可见,在本文中,您将能够学习一种简单的方法,使用 python 中的一行代码从任何网站获取表格数据。

对于数据收集,“越快越好”永远是最好的答案——玛丽莎·梅耶尔(雅虎前首席执行官!)

每天都有大量公开生成的数据,最常见的数据类型之一是 HTML 表格,有许多方法可以将这些数据放入笔记本,如使用 urllibBeautifulSoup 但这是一个漫长而耗时的过程,您可以在一行代码中使用 pandas 库来完成相同的任务。

我们开始吧

Pandas 库中的 read_html() 方法是一个 web 抓取工具,只需将所需的 URL 作为参数提供给该方法,就可以提取网站上的所有表格。

先决条件:导入熊猫库

import pandas as pd

1。获取网站上的所有表格

只需给出一个 URL 作为参数,就可以获得该特定网站上的所有表格。

pandas.**read_html**(URL)

例子:从维基百科中读取数据

#Data about Cricket World cupURL = ["https://en.wikipedia.org/wiki/Cricket_World_Cup](https://en.wikipedia.org/wiki/Cricket_World_Cup)"tables = pd.read_html(URL)print("There are : ",len(tables)," tables")
print("Take look at table 0")
print(tables[0])

2.从网站上读取特定的表格

如果一个网站上有很多表格,找到你要找的表格将会是一项繁琐的任务,你不能只手动搜索一个表格。为此,我们需要在 read_html() 方法中添加一个额外的参数( match) 来自动搜索所需的表。

match 属性可以将一个字符串或一个编译的正则表达式作为它的值

pandas.**read_html**(URL,match = ".+")

示例:使用 match 作为参数来抓取特定的表格

URL = "https://en.wikipedia.org/wiki/Cricket_World_Cup"tables = pd.read_html(URL,match="Performance details")print("There are : ",len(tables)," tables")print("Take look at table 0")tables[0]

由萨特雅·加内什创作

注意:搜索空间缩小,这可能有助于您快速搜索所需的表

3.格式化输出

Useful attributes  
1\. header    : The row to use to make as the column header.
2\. index_col : The column to use to create the index
3\. skiprows  : Number of rows to skip after parsing column integer

4。您也可以通过另一种方式瞄准特定的表格

pandas.**read_html**(URL,attrs = {'html_tag' : 'value'})

我们可以通过检查表格来直接定位对应于所需表格的 HTML 标签。

如何检查表格?

左键点击工作台并选择检查选项

图片由 Satya Ganesh 提供

在检查了查找该表专用的相关标签后,我们可以看到class:'wikitable'是一个标识该表的标签。

图片由 Satya Ganesh 提供

#By using this line of code we can hit the target table directly
pandas.**read_html**(URL,attrs = {'class' : 'wikitable'})

结论

读完这篇文章后,你将能够很快从任何网站上收集表格数据。

参考

[## 维基百科(一个基于 wiki 技术的多语言的百科全书协作计划ˌ也是一部用不同语言写成的网络百科全书ˌ 其目标及宗旨是为全人类提供自由的百科全书)ˌ开放性的百科全书

维基百科是一个免费的在线百科全书,由世界各地的志愿者创建和编辑,由维基媒体托管…

www.wikipedia.org](https://www.wikipedia.org/) [## pandas.read_html - pandas 0.23.4 文档

pandas.pydata.org](https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.read_html.html)

你可以在这里找到它的应用…

[## 新冠肺炎的影响-使用 Python 进行数据可视化

使用 python 在印度地图上可视化冠状病毒爆发的初级方法。当你到达…的终点时

towardsdatascience.com](/impact-of-covid-19-data-visualization-using-python-6f8e3bdc860b)

感谢阅读😃过得愉快

抓取没有文本的表格

原文:https://towardsdatascience.com/scraping-tables-without-text-881eb7ba12fc?source=collection_archive---------66-----------------------

有时你需要的数据是用颜色显示的,而不是文本。下面是获取数据的方法

安德鲁·雷德利在 Unsplash 上的照片

过去两周,我讨论了如何从维基百科的某些表格中抓取文本。两周前,我在这里展示了如何从维基百科抓取部分表格,上周,我在这里展示了如何从多个页面抓取数据。这一周,我们将解决一个稍微不同的与桌子相关的问题:颜色。

如果你只是想从维基百科中抓取一个完整的表格,你可以很容易地使用这个站点来生成一个 csv 文件。当然,你也可以在 python 中使用 Requests 和 BeautifulSoup 来做到这一点,但是坦率地说,当你有一个完全可行的选择时,没有必要重新发明轮子。然而,本周我们将关注英国烘焙大赛第一季的淘汰赛。

首先,让我们展示一下为什么使用 csv 网站行不通。当您在网站中运行 url 并查看为淘汰图表生成的 csv 时,您会看到以下内容:

Baker,1,2,3,4,5,6
Edd,,,,,,WINNER
Ruth,,,,,,Runner-up
Miranda,,,,,,Runner-up
Jasminder,,,,,OUT,
David,,,,OUT,,
Jonathan,,,OUT,,,
Annetha,,OUT,,,,
Louise,,OUT,,,,
Lea,OUT,,,,,
Mark,OUT,,,,,

这是表格在实际页面上的样子:

https://en . Wikipedia . org/wiki/The _ Great _ British _ Bake _ Off _(series _ 1)

显然,csv 文件未能捕捉到此图表上的颜色,正如我们在颜色键中看到的,这些颜色传达了潜在的有价值的信息:

因此,我们必须进入代码以获取所有信息。首先,和往常一样,我们将通过 BeautifulSoup 运行 url,这样我们就可以浏览 html:

import requests
from bs4 import BeautifulSoup
import pandas as pd
import reurl = '[https://en.wikipedia.org/wiki/The_Great_British_Bake_Off_(series_1)'](https://en.wikipedia.org/wiki/The_Great_British_Bake_Off_(series_1)')page = requests.get(url)soup = BeautifulSoup(page.content)

现在,我们将分离出排除图:

这几行实际上是说,“看看所有的表格,如果标题文本中有‘消除图表’,这就是我们定义的‘elim _ Chart’”

接下来,我们将制作一个包含每列标题的列表。如果我们看一下图表,这个列表应该是这样的:

['Baker', '1', '2', '3', '4', '5', '6']

要生成该列表,代码如下:

这些行实际上是说,“对于清除图表中标记为 th 的项目,只要项目的文本不以‘Elim’开头(因为我们不想删除‘清除图表’的较大标题),就将每个项目的文本添加到标题列表中”。rstrip()被添加到末尾,因为在初始列表中,6 后面有一个换行符,这会不必要地使事情复杂化。

换一种方式,我们将查看颜色键并创建一个字典,以便稍后在创建表格时使用。

meaning_list = soup.find('b', text=re.compile('Colour key:')).find_all_next('dd', limit = 6)

这一行基本上抓取了颜色键中显示的所有颜色信息和分配给它们的文本。通过在搜索文本时使用 re.compile,您不需要有精确的匹配,当您考虑到潜在的不可见字符(如空格和换行符)时,这可以使您的生活容易得多。从这里开始,我们通过执行以下操作来研究该列表:

首先,我们创建两个列表,color_list,它是颜色键中所有颜色的列表,以及 meaning_text_list,它是分配给每种颜色的文本的列表。我们通过对含义列表中每个项目的样式部分进行重新分割来访问颜色,使短语正好在颜色之前,background-color:,一个非捕获组,然后直接捕获它后面的单词。从这里开始,我们将颜色列表中的所有单词全部小写,以避免由于大小写不一致而导致的任何潜在的不匹配。为了获得每个颜色含义的文本,我们分割项目的文本并捕捉破折号后的单词,然后获取结果列表中的最后一个项目。从那里我们将这两个列表压缩到一个字典中,full_text_meaning_dict:

{'lightblue': 'Baker got through to the next round',
 'orangered': 'Baker was eliminated',
 'plum': "Baker was one of the judges' least favourite bakers that week, but was not eliminated",
 'cornflowerblue': "Baker was one of the judges' favourite bakers that week",
 'limegreen': 'Baker was a series runner-up',
 'yellow': 'Baker was the series winner'}

这样做的一个问题是在处理数据时这些值太长了。可能有更有效的方法,但我只是创建了以下列表:

shortened_text_list = ['next_round','eliminated','least_fav','fav','runner_up','winner',]

然后我压缩了列表和颜色列表,得到了这本字典:

{'lightblue': 'next_round',
 'orangered': 'eliminated',
 'plum': 'least_fav',
 'cornflowerblue': 'fav',
 'limegreen': 'runner_up',
 'yellow': 'winner'}

然后我添加了以下条目,silver 定义为 not_in_comp(不在比赛中),因为它不包含在颜色键中,但在查看表格时是必需的:

{'silver':'not_in_comp'}

从这里我们可以回到我们的淘汰表。这里提醒一下我们正在看的东西:

我们将通过执行以下操作来清理该表:

太多了,让我们从头到尾看一遍。首先,我们从创建一个行列表开始。这个行列表将是一个字典列表,其中键将是标题,值将是每一行的信息。

然后在接下来的三行中,我们开始查找所有面包师的名字,这是每行的第一项。从这里我们开始一个列表,row,它包含了我们访问过的每个条目的文本,也就是名称。从那里,我们得到每个名字的下六个兄弟姐妹。这六个兄弟姐妹对应于代表每集选手表现的六个不同的列。

从这里开始,我们查看每一行中的每一项(第 7 行)。对于每个项目,我们访问该项目的颜色,并且我们有一个设置为 1 的 col 变量。我们有这个 col 变量,因为有时,如果一个参赛者在连续两集里得到相同的结果(例如,他们连续两周是评委最喜欢的),代码只会说“创建一个两列宽的评委最喜欢的颜色块。”然而,当我们试图重新创建一个表,并且每行需要六个条目时,事情就变得复杂了。因此,第 12 行和第 13 行表示,“如果代码指定颜色块的宽度大于一列,则使 col 变量等于颜色块跨越的列数。”然后,第 15–17 行将该颜色添加到行列表中,方法是对第 9 行创建的颜色变量进行切片,以便只访问颜色名称,然后在我们创建的定义每种颜色含义的字典中运行该颜色,然后将该颜色乘以 col 变量。这确保了我们创建的每个行列表长度相同,并且表示重复的结果。最后,我们得到一个类似这样的行列表:

[{'Baker': 'Edd',
  '1': 'next_round',
  '2': 'fav',
  '3': 'fav',
  '4': 'least_fav',
  '5': 'fav',
  '6': 'winner'},
 {'Baker': 'Ruth',
  '1': 'fav',
  '2': 'next_round',
  '3': 'fav',
  '4': 'fav',
  '5': 'fav',
  '6': 'runner_up'},
 {'Baker': 'Miranda',
  '1': 'fav',
  '2': 'fav',
  '3': 'next_round',
  '4': 'fav',
  '5': 'least_fav',
  '6': 'runner_up'},
 {'Baker': 'Jasminder',
  '1': 'next_round',
  '2': 'next_round',
  '3': 'least_fav',
  '4': 'fav',
  '5': 'eliminated',
  '6': 'not_in_comp'},
 {'Baker': 'David',
  '1': 'least_fav',
  '2': 'least_fav',
  '3': 'least_fav',
  '4': 'eliminated',
  '5': 'not_in_comp',
  '6': 'not_in_comp'},
 {'Baker': 'Jonathan',
  '1': 'next_round',
  '2': 'fav',
  '3': 'eliminated',
  '4': 'not_in_comp',
  '5': 'not_in_comp',
  '6': 'not_in_comp'},
 {'Baker': 'Annetha',
  '1': 'fav',
  '2': 'eliminated',
  '3': 'not_in_comp',
  '4': 'not_in_comp',
  '5': 'not_in_comp',
  '6': 'not_in_comp'},
 {'Baker': 'Louise',
  '1': 'least_fav',
  '2': 'eliminated',
  '3': 'not_in_comp',
  '4': 'not_in_comp',
  '5': 'not_in_comp',
  '6': 'not_in_comp'},
 {'Baker': 'Lea',
  '1': 'eliminated',
  '2': 'not_in_comp',
  '3': 'not_in_comp',
  '4': 'not_in_comp',
  '5': 'not_in_comp',
  '6': 'not_in_comp'},
 {'Baker': 'Mark',
  '1': 'eliminated',
  '2': 'not_in_comp',
  '3': 'not_in_comp',
  '4': 'not_in_comp',
  '5': 'not_in_comp',
  '6': 'not_in_comp'}]

从这里开始,我们要做的就是把它变成一个真正的熊猫餐桌,如下所示:

df = pd.DataFrame.from_dict(row_list)df.set_index('Baker', *inplace*=True)

注意,我将 baker 列设置为索引,因为这对我更有意义。这段代码生成了下表:

现在,这实际上是直接从页面中抓取表格。然而,如果您想要对这些数据进行任何类型的分析,您将不得不创建虚拟变量。如果你不确定虚拟变量是什么,它本质上是一种表示分类数据的数字方式(在这种情况下,一个参赛者在一集里的表现)。在熊猫中,有一个函数叫做 get_dummies。如果我们这样做:

pd.get_dummies(df)

我们会得到这个:

注意:这只是生成的 25 列的一个示例

第一列中的 1 代表那个人是否在第一集被淘汰,第二列代表那个人是否是评委的最爱,等等。然而,假设你想把焦点放在某个选手何时是最受欢迎的或者刚刚进入下一轮。要做到这一点,可以翻转数据框,使索引变成列,然后执行我前面展示的 get_dummies 函数。在代码中,翻转看起来像这样:

t_df = df.transpose()

数据帧看起来像这样:

然后创建虚拟变量,如下所示:

pd.get_dummies(t_df)

这是结果:

从这里开始,您就有了可以处理和分析的数据(尽管六行数据可能并不多)。这就是我们如何获取丰富多彩的非文本表格,并将其处理成实际有价值的数据。

用熊猫抓取表格数据

原文:https://towardsdatascience.com/scraping-tabular-data-with-pandas-python-10cf2a133cbf?source=collection_archive---------21-----------------------

编程;编排

使用 Python 和 Pandas 进行网页抓取

图片来自 Pixabay自由照片

eb 抓取是一种从网站获取数据的技术。BeautifulSoup 和 Scrapy 是 Python 中两个广泛用于执行 Web 抓取的库。然而,使用这些库可能很麻烦,因为我们需要找到元素标签,从它们中提取文本,然后清理数据。

本文将向您展示一种使用 Pandas 提取表格数据的简单方法。是啊!熊猫!

从 HTML 页面提取表格

对于本教程,我们将从这个维基百科页面中摘录全球十大亿万富翁的详细信息。

我们将使用 Pandas 库的[read_html](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_html.html)方法来读取 HTML 表。

import pandas as pd

url = 'https://en.wikipedia.org/wiki/The_World%27s_Billionaires'

df_list = pd.read_html(url)

这个脚本将 HTML 表格返回到 DataFrame 对象列表中。

让我们检查找到的表的总数:

len(df_list)

# Output:
# 32

要访问特定表,只需访问列表中的元素。例如,
将返回下表:

将特定列设置为索引

我们可以通过使用index_col参数来选择表索引的特定列。

例如:

pd.read_html(url, index_col=1)[2]

返回下表:

返回包含字符串或正则表达式的表格

我们还可以使用match参数指定返回包含特定字符串或正则表达式的表列表。

举例:

pd.read_html(url, match='Number and combined net worth of billionaires by year')[0].head()

指定要识别为不适用的字符串

我们可以通过使用na_values参数来指定要识别为 NA/NaN 的字符串列表。

例如:

  • 未指定na_values:
pd.read_html(url)[0].tail()

不指定 na_values

  • 指定na_values后:
pd.read_html(
    url, 
    na_values=["Forbes: The World's Billionaires website"]
    )[0].tail()

指定 na_values 后

其他参数

  • skiprows参数允许我们跳过开始的“n”行
  • header参数可以用来使指定的行作为列标题

例如:

pd.read_html(url, skiprows=3, header=0)[0].head()

结论

在本文中,我们学习了如何使用read_html方法轻松地从页面中抓取 HTML 表格。此外,我们还学习了一些重要的参数,这些参数可以进一步帮助我们抓取所需的表。

参考

资源

本文中使用的代码片段可以在我的 GitHub 页面上找到。

让我们连接

领英:https://www.linkedin.com/in/jimit105/
GitHub:https://github.com/jimit105
推特:https://twitter.com/jimit105

在 Google Cloud Composer 上用 Selenium 抓取网页(气流)

原文:https://towardsdatascience.com/scraping-the-web-with-selenium-on-google-cloud-composer-airflow-7f74c211d1a1?source=collection_archive---------13-----------------------

澳门图片社Unsplash 上拍摄的照片

已经有很多不同的资源可以用来使用 Python 创建 web-scraper,这些资源通常基于众所周知的 Python 包urllib+beautiful soup 4Selenium 的组合。当您面临抓取大量 javascript 的网页的挑战,或者需要与内容进行一定程度的交互,而这仅仅通过发送 URL 请求是无法实现的,那么 Selenium 很可能是您的首选。我不想在这里详细介绍如何设置您的抓取脚本,以及如何以可靠的方式运行它的最佳实践。我只是想参考一下我找到的这个这个资源特别有帮助。

在这篇文章中,我们想要解决的问题是:作为一名数据分析师/数据科学家,我如何建立一个协调的、完全受管理的流程,以最少的开发操作来促进 Selenium scraper?这种设置的主要用例是在云中运行所有抓取作业的托管和预定解决方案。

我们将使用的工具有:

  • Google Cloud Composer 用于安排作业和协调工作流程
  • 为框架刮网站
  • Google Kubernetes 引擎在云中部署 Selenium 远程驱动程序作为容器化的应用程序

houssinganywhere的时候,我们已经在使用Google Cloud Composer完成许多不同的任务。Cloud Composer 是一个非常神奇的工具,可以轻松管理、调度和监控工作流,如有向无环图(Dag)。它基于开源框架Apache air flow并使用纯 Python,这使得它非常适合在数据领域工作的每个人。如果您不是来自 DevOps,那么自行部署气流的准入门槛相对较高,这导致一些云提供商提供托管气流部署,谷歌的 Cloud Composer 就是其中之一。

当部署 Selenium 进行 web 抓取时,我们实际上使用了所谓的 Selenium Webdriver。这个 WebDriver 是一个框架,允许你使用代码( Java,。Net、PHP、Python、Perl、Ruby 。对于大多数用例,你只需下载一个可以直接与 WebDriver 框架交互的浏览器,例如 Mozilla Geckodriver 或 ChromeDriver 。抓取脚本将在您的本地上启动一个浏览器实例**,并执行指定的所有动作。在我们的用例中,事情有点复杂,因为我们希望在不使用任何本地资源的情况下,按照循环的时间表运行脚本。为了能够在云中部署和运行 web 抓取脚本,我们需要使用一个Selenium Remote web driver(又名 Selenium Grid )来代替 Selenium WebDriver。**

来源:https://www . browser stack . com/guide/difference-between-selenium-remote web driver-and-web driver

使用 Selenium Grid 运行远程 web 浏览器实例

Selenium Grid 背后的思想是提供一个框架,允许您通过在一台或多台机器上运行 web 浏览器来运行并行抓取实例。在这种情况下,我们可以利用提供的独立浏览器(请记住,每个可用的浏览器,Firefox、Chrome 和 Opera 都是不同的图像),它们已经被包装为 Docker 图像。

Cloud Composer 在 Google Kubernetes 引擎(GKE)集群上运行 Apache Airflow。此外,它与其他谷歌云产品完全集成。新的 Cloud Composer 环境的创建还附带了一个功能性 UI 和一个云存储桶。所有 Dag、插件、日志和其他所需文件都存储在这个桶中。

在 GKE 上部署并公开远程驱动程序

您可以使用下面的 selenium-firefox.yaml 文件为 Firefox 独立浏览器部署 docker 映像,并通过运行以下命令在您的资源上应用指定的配置:

*kubectl apply -f selenium-firefox.yaml*

配置文件描述了你想要创建的类型的对象,它是元数据以及规格

我们可以在 Airflow 的管理界面中创建新的连接,然后在我们的插件中访问连接细节。连接细节要么在 yaml 文件中指定,要么可以在 Kubernetes 集群中找到。

气流连接

GCP 上的 Kubernetes 发动机

建立连接后,我们可以访问我们的抓取脚本(气流插件)中的连接,在那里我们连接到远程浏览器。

感谢Massimo Belloni为实现本项目和本文提供的技术咨询和建议。

使用 Python 抓取世界发展指标(WDI)数据库

原文:https://towardsdatascience.com/scraping-the-world-development-indicators-wdi-database-using-python-632f6b7c8319?source=collection_archive---------27-----------------------

本文提供了一个 python 函数的演示,该函数使用 xmltree 包从 WDI 数据库中一次抓取和处理多个序列的最新数据。

世界银行维护的世界发展指标数据库是最强大和最多样化的开放存取数据库之一。该数据库包含各种发展指标的数据集,对于任何有兴趣从数量或质量上研究发展问题的人来说,都是一个分析金矿。

就我个人而言,在我作为研究生的研究工作和作为科学家的职业生涯中,我经常依赖这个数据库。在本文中,我提供了一个脚本的演练,该脚本从 WDI 数据库中抓取数据集并将其保存到 dataframe 中。该脚本利用了 python 中的 xmltree 库,可以非常高效地从 WDI 数据库中抓取最新的可用数据。该脚本是我在过去一年中开发的更广泛的 python 数据处理项目的一部分。此处可进入项目。因此,不再浪费时间,让我们直接进入代码。

首先,让我们了解一下 WDI 网站的数据结构。我们将抓取为世界银行托管不同数据集的 WDI API。https://api.worldbank.org/v2/countries/all/indicators/ WDI API 包含以 xml 格式存储在 url- 的数据

任何用户都可以使用特定代码访问单个指示器。例如,代码‘AG。“CON.FERT.ZS”代表按国家和年份划分的施肥数据。因此,要访问这些数据,用户需要指定 URL—【https://api.worldbank.org/v2/countries/all/indicators/AG. CON.FERT.ZS 。

因此,第一步是将来自 WDI 的所有代码存储在一个列表中。为了简化,我在一个 csv 中存储了来自 WDI 的 300 个不同数据集的代码。csv 看起来如下所示,

为了使这变得更加容易,我将脚本构造为一个名为 WDIData 的函数。让我们首先从定义函数并在 python 中导入所需的库开始。如上所述,我们将需要 xml etree 包、numpy 和 pandas。我们还需要请求包,因为这是一个刮刀。

**def** WDIData():
    **import** numpy **as** np
    **import** requests
    **import** pandas **as** pd
    **import** xml.etree.cElementTree **as** et

现在让我们将上面提到的 WDICodes 文件读入一个名为 datadict 的对象。让我们创建一个空的数据帧来存储我们的数据集。

datadict = pd.read_csv(**'input\WDI\WDICodes.csv'**, encoding=**"ISO-8859-1"**)df=[]

对于 csv 中的每个代码,我们希望提取国家、代码、年份和值。因此,让我们为 WDI 代码创建一个 for 循环,其中我们为每个变量(国家、代码、年份和值)指定空列表。我们还必须创建一个 url 来从 API 请求数据。最后,我们将使用元素树中的“fromstring”函数从 url 中提取数据。

**for** row **in** datadict[**'WDI Code'**]:
    #Specify empty lists for required variables
    Countryname = []
    SeriesCode = []
    Year = []
    Value = [] #Create URL for each 
    url = **'http://api.worldbank.org/v2/countries/all/indicators/'** + str(row) + **'/?format=xml&per_page=20000'** #Get data from url and store to a variable r = requests.get(url, stream=**True**)
    root = et.fromstring(r.content)

对于每个代码中的数据,我们希望提取所有年份的所有值。这可以很容易地通过使用 for 循环来实现,这些循环使用 python 中 xml 树包内的‘ITER’函数。我们将为循环写 4 个,一个为系列 id、国家名称,一个为年份,一个为值。如果您跟踪上面提到的 URL,您会注意到数据存储在特定的属性中。

**for** child **in** root.iter(**"{http://www.worldbank.org}indicator"**):
    SeriesCode.append(child.attrib[**'id'**])
**for** child **in** root.iter(**"{http://www.worldbank.org}country"**):
    Countryname.append(child.text)
**for** child **in** root.iter(**"{http://www.worldbank.org}date"**):
    Year.append(child.text)
**for** child **in** root.iter(**"{http://www.worldbank.org}value"**):
    Value.append((child.text))

现在让我们为列表中的每个代码创建一个数据帧。这可以在 pandas 中使用 from_dict 函数来完成。我们还将转置数据集。我们将把代码数据存储到一个名为 test_df 的临时变量中。

test_df = pd.DataFrame.from_dict({**'SeriesName'**: SeriesCode,
                                  **'Country'**: Countryname,
                                  **'Year'**: Year,
                                  **'Value'**: Value}, orient=**'index'**)test_df = test_df.transpose()

为了最小化数据集的大小,我们将消除值、国家和系列名称中的空值。

test_df = test_df[pd.notnull(test_df[**'Value'**])]
test_df = test_df[pd.notnull(test_df[**'Country'**])]
test_df = test_df[pd.notnull(test_df[**'Series'**])]

现在,让我们将该代码的数据追加到我们在开始时创建的第一个空数据帧中。让我们使用 pandas 中的 pivot_table 函数从合并的数据集创建一个表。使用 pivot_table 函数的想法是将系列名称存储在列中。

df=pd.concat(df)data = pd.pivot_table(df, index=[**'Country'**, **'Year'**], columns=[**'Series'**], values=[**'Value'**],
                      aggfunc=[np.sum])

合并数据集存储为数据透视表。让我们将这个表存储为记录。最后,让我们返回数据,完成函数。

#Create the pivot table
data = pd.pivot_table(df, index=[**'Country'**, **'Year'**], columns=[**'Series'**], values=[**'Value'**],
                      aggfunc=[np.sum])#Convert the dataframe to records from a pivot table
data = pd.DataFrame(data.to_records())#Complete the function
**return** (data)

你有它!最终的数据集如下所示。如上所述,WDI 数据函数可以在 DataUpdate.py 文件中找到。请随时分享您对该职能的任何反馈。提取一个系列大约需要 5 秒钟,您可以用多达 1000 个文件更新 csv,以提取多个系列的最新数据。

如何使用 Python 和 BeautifulSoup 刮电视节目爱普西迪 IMDb 收视率

原文:https://towardsdatascience.com/scraping-tv-show-epsiode-imdb-ratings-using-python-beautifulsoup-7a9e09c4fbe5?source=collection_archive---------25-----------------------

简单易行——初学者指南。刮掉你最喜欢的电视节目的收视率!

有大量的教程教你如何从 IMDb 那里获得电影收视率,但我没有看到任何关于电视剧集收视率的教程。因此,对于任何想这样做的人,我专门为此创建了本教程。它主要是为了迎合网络抓取的初学者,因为这些步骤被分解了。如果你想要没有故障的代码,你可以在这里找到它。

Alex Olteanu 有一个精彩的 DataQuest 教程,深入解释了如何从 IMDb 收集 2000 多部电影,这是我学习如何收集这些集的参考。

由于他们的教程已经很好地解释了识别 URL 结构和理解单个页面的 HTML 结构的基础知识,我已经将这些部分链接起来,如果你还不熟悉的话,建议你阅读它们,因为我不会在这里解释它们。

这个教程中,我将而不是赘述他们已经做了什么1;相反,我会做许多类似的步骤,但它们将专门针对剧集评级(对任何电视剧都一样),而不是电影评级。

这个教程最好在我的网站上看,那里代码更清晰。随意查看 这里

分解它

首先,你需要导航到你选择的第一季的页面,上面列出了这一季的所有剧集。我将使用的系列是社区。它应该是这样的:

作者图片

获取该页面的 url。它应该是这样的结构:

http://www.imdb.com/title/TT 1439629/剧集?季节=1

粗体部分是节目的 ID,如果您不使用社区,它会有所不同。

首先,我们将通过使用get()向服务器请求网页的内容,并将服务器的响应存储在变量response中,并查看前几行。我们可以看到,response里面是网页的 html 代码。

from requests import geturl = 'https://www.imdb.com/title/tt1439629/episodes?season=1'response = get(url)print(response.text[:250])

使用 BeautifulSoup 解析 HTML 内容

接下来,我们将通过创建一个 BeautifulSoup 对象来解析response.text,并将该对象分配给html_souphtml.parser参数表明我们希望使用 Python 内置的 HTML 解析器进行解析。

*from* bs4 *import* BeautifulSouphtml_soup = BeautifulSoup(response.text, 'html.parser')

从这部分开始,代码将与电影示例不同。

我们将得到的变量是:

  • 剧集标题
  • 剧集编号
  • 广播日期
  • IMDb 评级
  • 总票数
  • 剧集描述

让我们看看我们感兴趣的容器。正如您在下面看到的,我们需要的所有信息都在<div class="info" ...> </div>中:

作者图片

黄色的中是代码的标签/部分,我们将调用这些标签/部分来获取我们试图提取的数据,它们在绿色的中。

我们将从页面中抓取<div class="info" ...> </div>的所有实例;每集都有一个。

episode_containers = html_soup.find_all('div', class_='info')

find_all()返回了一个ResultSet对象–episode_containers–这是一个包含所有 25 个<div class="info" ...> </div>的列表。

提取我们需要的每个变量

阅读 DataQuest 文章的这部分来理解如何调用标签。

在这里,我们将看到如何从每集的episode_containters中提取数据。

episode_containters[0]调用<div class="info" ...> </div>的第一个实例,即第一集。在第一对变量之后,你将理解调用 html 容器内容的结构。

剧集标题

对于标题,我们需要从<a>标签中调用title属性。

episode_containers[0].a['title']

'Pilot'

剧集编号

content属性下的<meta>标签中的剧集编号。

episode_containers[0].meta['content']

'1'

广播日期

Airdate 在带有类airdate<div>标签中,我们可以通过text属性获取它的内容,然后我们通过strip()移除空白。

episode_containers[0].find('div', class_='airdate').text.strip()

'17 Sep. 2009'

IMDb 评级

等级在带有类ipl-rating-star__rating<div>标签中,该标签也使用text属性来获取。

episode_containers[0].find('div', class_='ipl-rating-star__rating').text

‘7.8’

总票数

总票数是一样的,只不过是在不同的类别下。

episode_containers[0].find('span', class_='ipl-rating-star__total-votes').text

'(3,187)'

剧集描述

对于描述,我们做了与播放日期相同的事情,只是改变了类。

episode_containers[0].find('div', class_='item_description').text.strip()

‘An ex-lawyer is forced to return to community college to get a degree. However, he tries to use the skills he learned as a lawyer to get the answers to all his tests and pick up on a sexy woman in his Spanish class.’

最终代码——将所有代码放在一起

现在我们知道如何获得每个变量,我们需要为每一集和每一季进行迭代。这将需要两个for循环。对于每一季的循环,你必须根据你正在抓取的剧集有多少季来调整range()

输出将是一个列表,我们将成为一个熊猫数据框架。代码中的注释解释了每一步。

https://gist . github . com/isabellabenabaye/960 b 255705843485698875 DC 193 e 477 e

制作数据框

import pandas as pd 
community_episodes = pd.DataFrame(community_episodes, columns = ['season', 'episode_number', 'title', 'airdate', 'rating', 'total_votes', 'desc'])community_episodes.head()

这是你的新数据框架的头部应该看起来的样子(作者图片)

看起来不错!现在我们只需要稍微清理一下数据。

数据清理

将总票数转换为数字

首先,我们创建一个函数,它使用replace()total_votes中删除',','('和')'字符串,这样我们就可以将它变成数字。

def remove_str(votes):
    for r in ((',',''), ('(',''),(')','')):
        votes = votes.replace(*r)

    return votes

现在我们应用函数,取出字符串,然后使用astype()将类型改为 int

community_episodes['total_votes'] = community_episodes.total_votes.apply(remove_str).astype(int)community_episodes.head()

使评分成为数字而不是字符串

community_episodes['rating'] = community_episodes.rating.astype(float)

将广播日期从字符串转换为日期时间

community_episodes['airdate'] = pd.to_datetime(community_episodes.airdate)community_episodes.info()

太好了!现在数据已经整理好,可以进行分析/可视化了。

让我们确保保存它:

community_episodes.to_csv('Community_Episodes_IMDb_Ratings.csv',index=False)

就这样,我希望这是有帮助的!如有任何编辑或问题,请随时评论或 DM me

链接:

这个项目的 Github 库

Kaggle 上的最终社区评级数据集

我的网站/博客

使用 python 为 NLP 抓取 Twitter 数据

原文:https://towardsdatascience.com/scraping-twitter-data-using-python-for-nlp-d898e14cacfe?source=collection_archive---------30-----------------------

了解如何用几行代码从 twitter 创建自己的数据集。

约书亚·阿拉贡在 Unsplash 上拍摄的照片

“我们相信上帝。所有其他人都必须带数据。”— 爱德华·戴明

如果您是从 NLP 这个不可思议的领域开始,那么您会想要接触真实的文本数据,您可以使用这些数据来研究您所学到的概念。Twitter 是这类数据的绝佳来源。在这篇文章中,我将展示一个刮刀,你可以用它来刮你感兴趣的话题的推文,一旦你获得了你的数据集,你就会变得很无聊。

我使用了这个神奇的库,你可以在这里找到。我将介绍如何安装和使用这个库,并建议一些使用并行化使整个过程更快的方法。

装置

可以使用 pip3 通过以下命令安装该库

pip3 install twitter_scraper

创建关键字列表

下一个任务是创建一个你想用来抓取 twitter 的关键词列表。你会在 twitter 上搜索这些关键词,因此重要的是你要列出一个你感兴趣的关键词的综合列表。

抓取一个关键词的推文

在我们运行程序提取所有关键字之前,我们将用一个关键字运行程序,并打印出我们可以从对象中提取的字段。在下面的代码中,我展示了如何迭代返回的对象并打印出您想要提取的字段。您可以看到,我们提取了以下字段

  1. 推文 ID
  2. 是转发还是不转发
  3. 推文时间
  4. 推文的文本
  5. 对推文的回复
  6. 转发总数
  7. 喜欢推特
  8. 推文中的条目

对所有关键字按顺序运行代码

既然我们已经决定了要从我们的对象中存储什么样的数据,我们将依次运行我们的程序来获取我们感兴趣的主题的 tweets。我们将使用我们熟悉的 for 循环来逐个检查每个关键字并存储成功的结果。

并行运行代码

文档中,

多重处理是一个支持使用类似于线程模块的 API 生成进程的包。多处理包提供了本地和远程并发,通过使用子进程而不是线程有效地避开了全局解释器锁。因此,多处理模块允许程序员在一台给定的机器上充分利用多个处理器。

首先,我们将实现一个函数来抓取数据。

接下来,我们将创建子流程来并行运行我们的代码。

如您所见,我们将处理时间减少到了顺序执行的 1/4。您可以将此方法用于类似的任务,并使您的 python 代码更快。

使用 Python 抓取天气数据以在电子邮件中获得雨伞提醒

原文:https://towardsdatascience.com/scraping-weather-data-using-python-to-get-umbrella-reminder-on-email-8d00c7827c71?source=collection_archive---------53-----------------------

使用 Python 获得自动“雨伞提醒”电子邮件

图片由克里斯多佛·高尔——Unsplash

Python 在脚本编写、自动化、web 抓取、数据分析等方面创造了奇迹,这样的例子不胜枚举。在本文中,我混合了 web 脚本和自动化——因此,如果城市的天气是阴雨天,Python 脚本将发送一封“雨伞提醒”电子邮件。

库导入

from bs4 import BeautifulSoup
import smtplib
import requests as rq

“美丽的汤”用于从网站、Html 和 XML 页面中提取数据。“Requests”库用于发送 HTTP 请求,而“smtplib”用于向任何机器发送电子邮件。

获取天气数据

url = rq.get('https://forecast.weather.gov/MapClick.php?lat=40.71455000000003&lon=-74.00713999999994')

soup = BeautifulSoup(url.text, 'html.parser')

weather = (soup.select('#current_conditions-summary p')[0]).text
temperature = (soup.select('#current_conditions-summary p')[1]).text

我使用过国家气象局网站搜集纽约的天气数据。requests.get()函数接受要下载的 URL 字符串。BeautifulSoup()函数需要用一个包含它将解析的 HTML 的字符串来调用。

现在,BeautifulSoup 对象已经创建,您可以使用一个 "select" 方法从 web 页面中检索天气和温度的 web 元素。

构建 smtplib 对象

server = smtplib.SMTP('smtp.gmail.com', 587)
print(server.ehlo())
print(server.starttls())

server.login('Enter your email', 'Password')

我创建了一个带有参数“smtp.gmail.com”和 587 的 SMTP 对象。创建 SMTP 对象后,您可以使用您的电子邮件地址和密码登录。

注意:smtplib 中的参数可能会更改。SMTP()取决于域的 SMTP 服务器。如果您有 Gmail 帐户,您必须为您的电子邮件地址生成特定于应用程序的密码。否则,当您的程序试图登录时,您将得到一个特定于应用程序的需要密码的错误消息。

您可以使用本指南创建您的 Gmail 应用程序专用密码

发送电子邮件

if weather == 'Raining' or weather == 'Overcast' :

    subject = "Umbrella Reminder"
    body = f"Take an umbrella with you. Weather condition for today is {weather} and temperature is {temperature} in New York."

    msg = f"Subject:{subject}\n\n{body}\n\nRegards,\nVishal".encode('utf-8')
    print(msg)

    server.sendmail('Sender's Email', 'Recipient Email', msg)

    print("Email Sent!")

    server.quit()
else :
    print("There is going to be {} and temperature is {} in New York".format(weather, temperature))

如果来自 web 元素的天气结果是下雨或阴天,发件人将向收件人发送一封带有“雨伞提醒”消息的电子邮件。

这就是你如何使用 Python 从一小步开始并自动化你生活中的小事情。开始您的脚本之旅。

请联系我,在维沙尔·夏尔马寻求反馈或讨论!

Scrapy:这就是如何轻松成功登录

原文:https://towardsdatascience.com/scrapy-this-is-how-to-successfully-login-with-ease-ea980e2c5901?source=collection_archive---------1-----------------------

李晟从没开过

揭秘用 Scrapy 登录的过程。

一旦你理解了 Scrapy 的基本知识,第一个复杂的问题就是必须处理登录。要做到这一点,了解登录是如何工作的以及如何在浏览器中观察这个过程是很有用的。我们将在这篇文章中讨论这一点以及 scrapy 如何处理登录过程。

在本文中,您将了解到

  1. 如何将 FormRequest 类用于简单的登录过程
  2. 如何使用fromresponse方法进行更复杂的登录过程
  3. 如何实现基本的 XPATH 选择器
  4. 了解会话和令牌浏览器身份验证之间的区别
  5. CSRF 是什么,为什么知道它很重要
  6. 如何处理 Scrapy 中的令牌认证

简单的登录程序

当你输入数据到网站表单域时,这些数据被打包。浏览器将在标题中加入这一内容来执行 POST 请求。登录时可能会有许多 POST 和 redirect 请求。

要在 Scrapy 中做最简单的登录程序,我们可以使用 Scrapy 的 FormRequest 类。实际上,最好使用 FormRequests 方法之一来处理表单数据,但稍后会详细介绍!

让我们先看看它是如何工作的,然后在此基础上进行构建。为了在我们的 scrapy spider 中使用它,我们必须首先导入它。

from scrapy.http import FormRequest

现在,我们不再在蜘蛛的开头使用start_url,而是使用start_requests()方法。这允许我们使用与表单填充相关的方法。

让我们看看 scrapy.spider 代码的底层,看看它是如何工作的。请记住,这是我们在启动蜘蛛时经常提到的地方。

当我们从那个类中调用start_requests()方法时,这就是隐藏的内容。

def start_requests(self):
    for url in self.start_urls:
         yield self.make_requests_from_url(url)def make_requests_from_url(self, url): 
    return Request(url, dont_filter=True)

在这里,我们循环浏览start_urls的每个网址。对于每个 url,我们使用scrapy.requests()方法,并传递一个 URL 和一个名为 dont_filter 的关键字。现在dont_filter=True意味着不过滤重复的请求。

通过使用 FormRequest 子类,我们扩展了scrapy.http.Request类。FormRequest 为我们提供了从响应中预填充表单字段的功能。我们扩展了scrapy.http.Request,可以访问它所有的关键字参数。

让我们看看这是什么样子。

from scrapy.http import FormRequests
import scrapydef start_requests(self):
   return [
      FormRequest("INSERT URL", formdata={"user":"user",   
           "pass":"pass"}, callback=self.parse)]def parse(self,response):
    pass

笔记

1.默认的parse()函数处理脚本的响应和规则,以获取您想要的数据。
2。对于函数start_request,我们使用 FormRequest 类。我们向它提供一个 url 和关键字参数 formdata 以及我们的用户名和密码。

3.Scrapy 为我们处理饼干,而不需要我们在start_request中具体说明。

4.我们使用回调关键字参数将蜘蛛指向解析函数。

莫哈末·阿拉姆来自未喷涂

隐式数据

有些网站会要求您传递表单数据,这些数据乍一看似乎并不重要。登录,但有必要通过 cookies 认证网站。有时页面有一个隐藏的字段需要通过。获得该值的唯一方法是登录。

为了解决这个问题,我们需要做两个请求,一个请求传递一些数据并捕获隐藏的字段数据。第二次请求登录。

这次我们将使用一个start_request函数,但是传递第一个请求。我们将处理回调以将信息传递给第二个函数。

对于第二个请求,我们将使用FormRequest.from_response()方法。这个方法用我们指定的字段中填充的数据来模拟点击。返回一个新的 FormRequest 对象。这个对象的默认设置是模拟一个点击,这个点击有一个类型为<input_type=submit>的可点击项目。

我们可以在from_response()方法中指定不同的方式。参考 scrapy 文档是明智的!例如,如果你不想让 scrapy 点击进入,你可以使用关键字dont_click=True。来自from_response()方法的所有参数都被传递给 FormRequest。

def start_requests():
    return [
       Request("URL", callback = self.parse_item)
     ]def parse_item(self,response):
    return FormRequest.from_response(response, formdata= 
           {'user':'user', 'pass':'pass'})

在这里,我们从start_requests()获取所需的头,然后将其传递给parse_item()

使用FormRequest.from_response()我们传递带有适当标题的表单数据。

特雷布雷·巴黑斯

浏览器认证基础知识

HTTP 是一种无状态协议。这意味着从请求到响应,没有消息状态的记录。如果您作为一个请求登录,这将在另一个请求中被忘记。讨厌还是什么!

第一个解决方案是创建一个会话。当我们进行 POST 请求时,会在服务器数据库中创建一个会话。一个 cookie,它是一个字典,附加到带有会话 ID 的响应中。cookie 被返回给浏览器。

当我们用这个 cookie 尝试另一个请求时,服务器会查找它并检查会话 ID。获取配置文件数据匹配,并将响应发送回浏览器。

Cookie 身份验证是有状态的。认证记录存储在客户端和服务器端。

现在我们有了单页面应用程序,前端和后端的分离要复杂得多!当与另一个服务器联系时,我们从一个服务器获得的会话 cookie 将不起作用。这就是基于令牌的身份验证发挥作用的地方。

抢王从未破土而出

基于令牌的认证

令牌是另一种浏览器身份验证方法。现在使用的标准令牌是 Json web 令牌(JWT)。

基于令牌的认证的优点是它是无状态的。服务器不记录哪些用户登录。每个请求都有一个令牌,服务器用它来检查真实性。令牌通常在授权报头载体(JWT)中发送,但也可以在 POST 请求的主体中发送。

JWT 由三部分组成:报头、有效载荷和签名

###HEADER###
{
  "alg": "HS256",
  "typ": "JWT"
}###PAYLOAD###{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}###SIGNATURE###{
  HMACSHA256(base64UrlEncode(header) + "." +           base64UrlEncode(payload),   
secret)

现在 jwt 使用编码算法进行签名。例如 HMACSHA256,看起来像这样。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbyBLdWtpYyIsImFkbWluIjp0cnVlLCJpYXQiOjE0

这可以通过像这样的网站解码,知道数据没有加密是很重要的。

用户输入登录详细信息,令牌被附加。然后,服务器验证登录是否正确,然后发送的令牌被签名。这个令牌存储在客户端,但实际上可以存储为会话或 cookie。记住 cookie 是键和值的字典。

对服务器的请求包括此令牌以进行身份验证。服务器对这个令牌进行解码,如果令牌有效,请求就会被发回。当用户注销时,令牌在客户端被销毁。不与服务器交互。这为我们提供了一些保障。

孙富从无到有

CSRF 是关于什么的?

当谈到基于令牌的身份验证时,您会用到这个术语。所以了解它们是很有用的。这就是为什么基于令牌的认证变得流行的核心。

CSRF 代表跨站点请求伪造,是一个网络安全漏洞。它允许攻击者让用户执行他们不想执行的操作。例如通过改变账户的电子邮件地址。

CSRF 袭击的发生需要三个条件。首先是一个相关的动作,它是应用程序中有理由改变的东西。基于 cookie 的会话处理来进行身份验证,并且没有不可预测的请求参数。

有了这些,攻击者就可以创建一个带有表单的网页来更改电子邮件地址。用户输入数据,表单在对原始网站的请求中使用用户会话 cookie。而是使用新的电子邮件地址。

为了应对这种攻击,我们可以使用令牌来检查用户,而不是基于会话的 cookies。

克林特·帕特森

使用 Scrapy 处理基于令牌的认证

为了确定是否有必要使用令牌,我们必须使用 chrome/firefox 开发工具。为此我们将刮掉 quotes.toscrape.com。我们模拟登录过程,看看发送了哪些报头。为此,我们在登录前滚动到网络选项卡,然后模拟一个登录过程。所有请求将出现在下面。

Chrome 开发工具。红色方框显示登录过程

选择左侧的登录名,我们可以看到下面的请求标题。

登录过程的请求标头。突出显示 CSRF 令牌

正如您在表单数据中看到的,csrf_token是存在的。

请记住,当我们注销时,此令牌会被销毁。我们有必要在将它作为 POST 请求发送之前获取它。要做到这一点,我们必须看看 HTML。表单的 html 标签如下所示。

我们可以在这里看到表单字段< 【

XPATH Basics

Now to do any scrapping it’s useful to go to the shell to see if the xpath selectors will work in your spider. So here we fetch the url and test out the xpath we need.

fetch("url")
response.xpath('//*[@name='csrf_token']/@value').extract_first()

Output

u'xUdwZpPyvkEJYTHOogcAaNFVzuhKtLejqBfbSXMQRCmWDrsinGlI'

Lets break down the xpath selector.

First xpath hands html documents as a tree and seperates the document out into nodes. The root node is parent to the document element 【 . Element nodes represent html tags. Attribute nodes represent any attribute from an element node. Text nodes represent any text in the element nodes.

First 【 is a 【 which means it selects current node or any below it. 【 means to select all nodes without comments or text nodes.

We use 【 to specify the attribute 【 and 【 after this to specify it’s value. 【 will grab the first value it finds.

So we have our xpath selector to get the 【 , we can then use this to pass onto the FormRequest

Now that we have that understanding we can look at the code for using it.

import scrapy
from scrapy.http import FormRequestsclass LoginSpider(Scrapy.spider):
    name = 'login'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['[http://quotes.toscrape.com/login](http://quotes.toscrape.com/login)']def parse(self,response):
        csrf_token = response.xpath('//*[@name='csrf_token']
                     /@value').extract_first()') yield FormRequests.from_response(response, formdata={'csrf_token': csrf_token, 'user':'user', 'pass','pass'}, callback=self.parse_after_login)def parse_after_login(self,response):
    pass

Notes
1。我们像以前一样导入 scrapy 和表单请求

2.我们填充变量nameallowed_domainsstart_urls

3.我们将csrf_token分配给登录页面中令牌的 xpath 选择器值。

4.使用 FormRequests 子类,我们指定响应,并输入我们想要的表单数据。在这种情况下,我们指定了csrf_token以及用户名和密码。
5。登录成功后,使用回调将蜘蛛指向该函数。

唷!很难通过。希望让 Scrapy 的登录程序更易管理。下次见!

关于作者

我是一名医学博士,对教学、python、技术和医疗保健有浓厚的兴趣。我在英国,我教在线临床教育以及运行 www.coding-medics.com网站。

您可以通过 asmith53@ed.ac.uk 或 twitter 这里联系我,欢迎所有意见和建议!如果你想谈论任何项目或合作,这将是伟大的。

更多技术/编码相关内容,请点击这里注册我的简讯

相关文章

[## 如何使用 Python 下载文件

了解如何使用 Python 下载 web 抓取项目中的文件

towardsdatascience.com](/how-to-download-files-using-python-ffbca63beb5c) [## 你应该知道的 5 个 Python 技巧

如何轻松增强 python 的基础知识

medium.com](https://medium.com/swlh/5-python-tricks-you-should-know-d4a8b32e04db)

没有魔法的 Scrum

原文:https://towardsdatascience.com/scrum-without-magic-8cbb07eb4026?source=collection_archive---------41-----------------------

意见

当一个团队决定采用敏捷,尤其是 Scrum 时,他们通常会有这样的态度——一旦他们完成了所有神奇的仪式,一切都会神奇地运转起来。那就不会发生。

Muhammad Haikal SjukriUnsplash 上拍摄的照片

诚然,Scrum 有时类似于一种崇拜。

甚至会议也被方便地命名为“仪式”,就好像在 Scrum 中没有会议,而是有神奇的仪式。无数的 Scrum 教练和顾问看起来和说起来都像是信徒。

当一个团队决定采用敏捷,尤其是 Scrum 时,他们经常会有这样的态度——一旦他们完成了所有神奇的仪式,一切都会神奇地工作。所有的问题都会消失。如果他们一直重复这些咒语,他们的表现也会一飞冲天。

那就不会发生。人们变得幻灭和失望。他们在互联网上写了无数的文章,认为 Scrum 是一个骗局,根本不起作用。

好吧,Scrum 不是魔术。尽管有可怕的言辞和迷人的教练,Scrum 本身没有力量。它本身不能解决任何问题。

那又怎样?

我不是 Scrum 专家。我是一名软件工程师。你不必听我的。但是当我开始对敏捷感兴趣的时候,我惊讶于有多少人只是模仿 Scrum,而没有任何特定的需求或目标。

Scrum 有一个完整的宇宙:数百万的文章、课程和书籍,数以千计的演讲、认证和培训师。说了这么多,行动却这么少。

框架

让我们像工程师一样交谈。Scrum 被称为“框架”是有原因的。像许多框架一样,它不会给你解决问题的代码,它只给你一个结构。然后,作为 Scrum 大师、团队领导或工程师,你的任务就是填补空白。

你是如何编写代码的?我有个主意。对许多人来说,这听起来可能很奇怪,但这就是:不要光说不练,要去做。你如何称呼这个或那个,或者你的燃尽图有多漂亮,真的无关紧要。重要的是你的输入是否给了你正确的输出。

Sprint 作为一项功能

输入:任务

输出:一次迭代

Sprint 是敏捷的基石。最重要的功能。这不仅仅是一句话,或者一个仪式,或者仅仅两个星期的时间。许多团队只是在开始时将一些任务推给别人,然后,在两周结束时,他们将未完成的任务交给下一个“冲刺”。这不是冲刺,只是模仿。

每一次冲刺都应该从一张白纸开始。好的函数是幂等的。

此外,Sprint 不是经理的衡量工具。短跑只能用结果来衡量,用产出来衡量。

Sprint 是一个函数,一个应该产生迭代的动作——一些以前不存在的东西。一些你可以展示的东西。

如果你的工作不是迭代的——也许你只解决了未分类的错误,或者你正在建造一个卫星——那么你不应该试图将你的过程分成冲刺。

作为功能的“仪式”

它们可能被称为仪式,但不要混淆——最终,它们只是会议,如果有效地运行,可以发挥作用并产生结果。

如果会议没有产出,那么它应该以不同的方式运行,或者从人们的日历中删除。如果开会是一种仪式,那只是浪费每个人的时间。

时间的重要性

通常,工程师不喜欢开太多的会。几乎没有人喜欢冗长的会议。如果会议没有一个明确的目标,它就会变成一种折磨。如果一次会议没有产生任何结果,那就感觉毫无意义。如果毫无意义的会议定期重复,感觉就像一种仪式。

如果你的 Scrum 是由仪式组成的,那它就是模仿——当人们开始抱怨它不起作用时,任何人都不应该感到惊讶。

Artem Maltsev 在 Unsplash 上拍摄的照片

站立

输入:团队成员报告

输出:一天的计划

有数百万字是关于单口相声的。他们通常关注事情的“人”的方面——互相汇报,不要分心,在时间范围内。所有这些观点都是正确的。但是我们为什么要这么做呢?所以“每个人都知道每个人在做什么”。但是为什么呢?

他们应该知道,以便计划他们的一天。

积压优化

输入:要求

输出:明确定义的任务,全部记下

Backlog 精化获取原始需求,并将它们转换成明确定义的任务。

明确定义——这很重要。会后应该不需要提问了。请记住,这些任务将在整个流程中继续进行,并在 Sprint 规划期间反馈给您。

如果细化是无效的,它将使计划无效。

此外,规划扑克不只是一个无聊的游戏。“如何”并不重要。重要的是,你是否能迅速集体决定这项任务有多难。

评估定义了冲刺,冲刺定义了你要做什么和有多努力。如果扑克真的有所不同,那么每个人都会感兴趣。

冲刺规划

输入:明确定义的优先任务

输出:冲刺计划

Sprint Planning 将 Backlog 精化产生的东西,划分出来并转化为一个 Sprint。

关于冲刺计划的主要问题是它应该是严肃的。当你计划冲刺和“提交”时,它不应该只是一个象征性的姿态——你决定你要做什么。这将是你必须向同事展示的一个增量。

回顾的

输入:团队成员对冲刺的想法

产出:要实施的行动清单

我曾经在一个团队工作过,在那里,复古是每个人都互相喊叫和抱怨的时代。在另一个团队中,Retro 总是很安静,因为对每个人来说一切都很好。

在许多团队中,复古只是经理们的专利——工程师们只是等着回去工作。

回顾会应该收集每个人对工作过程的意见,并列出行动清单。然后就应该采取这些行动。

如果回顾没有产生任何改进,那就感觉是浪费时间。

演示

Sprint Demo 的存在是为了确保你已经产生了一个迭代。如果你没有什么可以展示的,也许那不是一次冲刺?

照片由马克·泰格霍夫Unsplash 上拍摄

圆圈

把 Scrum 想象成 Lambda 函数的流程图。由于这个过程是迭代的,它们不可避免地形成一个循环。

…改进->积压优化->积压->冲刺计划->冲刺->站立->演示->回顾->改进…

这是一个数据管道,真的。

正确的框架

Scrum 不会为团队创建一个过程。作为框架,只能对结构有帮助。这是团队写的“代码”。

为了让它起作用,我们不应该关心是否酷或者做对事情。我们应该关心结果。

尽管有很多关于敏捷是多么酷和有趣的谈论,但是敏捷实际上是关于纪律的。它是作为一个框架创建的,用于在不断变化的需求的混乱中导航。

Scrum 不一定要有趣。嗯,也不一定要无聊。最好是看不见的。最重要的是,它不应该分散人们的工作注意力,也不应该增加更多的混乱。

是的,有时候 Scrum 并不是团队的正确选择。

海洋穿越:从水下图像中去除水

原文:https://towardsdatascience.com/sea-thru-removing-water-from-underwater-images-935288e13f7d?source=collection_archive---------18-----------------------

一种新的工具,有可能彻底改变水下图像的计算机视觉。

信用:Derya Akkaynak

先说清楚一点:这不是 Photoshop 教程!当然,相当多的摄影师知道提高水下照片质量的技巧,这对人眼来说已经足够了。但是对于那些开发机器学习算法来分类和识别图像中的对象的人来说,这样的技术是完全不够的。我挑战任何阅读这篇文章的人,让他们想到机器学习和计算机视觉在水下成像和视频中的单一应用。这比你想象的要难。根据德雅·阿克凯纳克和程昕婷·特雷比兹的说法,原因是“目前不存在鲁棒的算法”来可靠地去除水生图像中持续存在的噪声…

…直到现在。

信用:Derya Akkaynak

有什么问题?

水下照片相当于在空气中拍摄的照片,但被厚厚的彩色雾覆盖,受白点和强度随距离变化的光源影响目前用于改进水下摄影的模型扩展了定期观测大气条件下的模型。然而,这些模型没有考虑水对光的极端影响。你知道吗光在水中的速度大约比在空气中的速度慢 46200 英里/秒

信用:Derya Akkaynak

变化的波长

这些速度的变化影响了我们看到的光的波长和颜色。让事情变得更加复杂的是,物体发出的光仅仅是折射阳光的反射。Akkaynak 和 Treibitz 试图通过认识到观察到的颜色波长是速度、距离和原始色调的函数来克服这一挑战。光在水中的速度是一个常数,光源色调也是如此。因此,如果我们知道一个物体的精确色调和与它的距离,我们就可以逆向工程出观察到的颜色的公式。总之,理论上是这样的。不幸的是,还有其他挑战需要考虑。

信用:Derya Akkaynak

后向散射

如果你曾经在浓雾中开车,你可能会倾向于打开你的远光灯,但你会很快意识到增加的光线更多的是致盲而不是有益的。这是因为空气中的水颗粒将更多的光反射回给你。在水下拍摄图像时也会发生同样的现象,因此会影响拍摄照片的颜色精度。随着与焦点物体的距离增加,反向散射强度增加。

有一种用于处理反向散射的估计器,称为暗通道先验(DCP),它是为在朦胧条件下拍摄图像而开发的。DCP 背后的思想基于以下内容:“室外无霾图像中的大多数局部斑块包含一些像素,这些像素在至少一个颜色通道中的强度非常低。将该先验与薄雾成像模型一起使用,我们可以直接估计薄雾的厚度并恢复高质量的无薄雾图像。

信用:Derya Akkaynak

克服障碍

Akkaynak 和 Treibitz 声称 DCP 的修改版本考虑了水的光吸收和反向散射。然而,这样做的公式需要已知的距离作为输入变量,并且期望用户对每张照片进行这样的测量是不切实际的。幸运的是,摄影测量领域的专家已经开发出处理这个问题的技术。例如,如果成像物体的尺寸是已知的,那么距离可以通过缩放得到。

多镜头相机,如现代智能手机上的相机,为使用视频测量提供了更优雅的解决方案。通过从两个或多个角度拍摄同一幅图像,并使用相机之间的已知距离,我们可以测量深度。(还记得你高中几何的 ASA 三角形吗?)你的手机已经能够实时进行这些测量和计算。最终的结果是一个有潜力为水下摄影和摄像带来计算机视觉革命的产品。

信用:Derya Akkaynak

关于 Sea-thru 的更多信息,包括该算法的未来可用性,请前往 https://www.deryaakkaynak.com/sea-thru。

刚刚发布的 Seaborn 0.11 具有很棒的新特性

原文:https://towardsdatascience.com/seaborn-0-11-just-released-with-great-new-features-c5b45efad7e2?source=collection_archive---------18-----------------------

Seaborn 刚刚好起来。

Seaborn 是一个基于 Matplotlib 构建的高级 Python 数据可视化库。它可以方便地创建许多不同的信息统计可视化。

照片由 Giovany Pineda GallegoUnsplash 拍摄

Seaborn 的新版本(0.11.0)刚刚发布,在现有版本的基础上增加了新的特性和增强功能。在本帖中,我们将通过可视化示例介绍大部分变化。

引入了三个新功能,分别是显示图历史图ecdfplot。这三个函数可用于可视化单变量或双变量数据分布。

注意:为了使用新功能,您需要更新到新版本,这可以通过pip install seaborn==0.11.0完成。

让我们从距离图开始。可以认为是另外两个的父类。distplot 使用种类参数,提供对 histplot、ecdfplot 和 kdeplot 的访问。因此,它是不同类型分布图的图形级界面。

这里有一个例子。

sns.displot(data=diabetes, x='Glucose', kind='hist', height=6, aspect=1.2)

我们绘制了一个直方图,显示了葡萄糖变量的单变量分布。

下面的代码将创建一个直方图,显示葡萄糖和血压变量的二元分布。

sns.displot(data=diabetes, x='Glucose', y='BloodPressure',
kind='hist', height=6, aspect=1.2)

区域的暗度随着该区域内数据点数量的增加而增加。

distplot 是图形级别的函数,而 histplot 是轴级别的函数。可以使用 histplot 函数的以下语法创建相同的图。

sns.histplot(data=diabetes, x='Glucose', y='BloodPressure')

如果你想了解更多关于 Matplotlib 的图形和轴的概念,这里有一个关于 Matplotlib 结构的详细帖子。

由于 displot 在一个面网格上绘制图形,我们可以在同一个图形上绘制多个图形。

sns.displot(data=churn, x='CreditScore', kind='hist',
col='Geography', hue='Exited')

ecdfplot(经验累积分布函数)提供低于数据集中每个唯一值的观察值的比例或计数。除了对变量分布的概述之外,与直方图相比,我们可以更清楚地了解数据中的每个观察值,因为没有宁滨(即分组)。

sns.displot(data=churn, x='Age', kind='ecdf', col='Geography', hue='Exited')

ecdfplot 只能绘制单变量分布。

新版本带有一个贬值的功能,即 distplot 。这是意料之中的,因为新函数(displot 和 histplot)似乎是 displot 的更好的替代物。

目前使用的一些功能也有所改进或增强。

联合图提供两个变量的单变量和双变量图。色调语义被添加到 jointplot,这增加了额外的信息能力。

sns.jointplot(data=diabetes, x='Insulin', y='BMI', hue='Outcome',
height=7)

jointplot 的另一个新增功能是 kind 参数的“hist”选项。kind 参数的缺省值是“散点”,但如果我们将其更改为“历史”,则会创建关节轴上的双变量直方图和边缘轴上的单变量直方图。

sns.jointplot(data=diabetes, x='Insulin', y='BMI', hue='Outcome',
kind='hist', height=7)

关于 API 的一些亮点

  • Set功能已被重命名为set_theme。它调整可视化中使用的主题的几个属性。
  • axlabel功能不再可用。建议用ax.set(xlabel=, ylabel=)代替。

我们已经介绍了一些主要的变化,但是如果你想看到所有的变化,这里有相关的 seaborn 文档

如果你想自己练习,你可以访问 Kaggle 上的数据集。

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

Python 中数据可视化的 Seaborn 基础

原文:https://towardsdatascience.com/seaborn-essentials-for-data-visualization-in-python-291aa117583b?source=collection_archive---------27-----------------------

可视化支柱的代码片段:分布、关系、比较、组合

照片由阿尔菲亚诺·苏蒂安托Unsplash 拍摄

之前说过,数据可视化的目的是沟通数据中隐藏的信息。可视化从根本上服务于数据科学中的 4 个目的,即理解:

  • 特征的分布
  • 两个或多个变量之间的关系
  • 变量间的比较
  • 数据的组成

你可以用各种方法识别和交流隐藏的信息,而且有工具可以做到这一点。无论您选择哪种编程语言,每种语言都有库来有效地处理数据可视化。

如果你使用 Python,你有几个选择,但是我发现seaborn是最好的。不是因为seaborn可以做一些其他库做不到的事情,而是因为它的简单和直观的代码结构。

因此,本文的目的是用代码片段演示 Seaborn 的一些用例。我的学习/教学哲学是从一个问题开始,然后找到可以解决它的工具。因此,我不打算展示太阳底下的一切,而是给出一个关于 Seaborn 如何工作以及如何解决我刚才提到的 4 类问题的直觉。

让我们开始吧。

内置数据集

seaborn自带 17 个内置数据集。这意味着你不必花费大量的时间去寻找合适的数据集并清理它来使 Seaborn 就绪;相反,您将关注 Seaborn 可视化技术的核心特性来解决问题。

首先,让我们看看数据集。

# get names of the builtin dataset
sns.get_dataset_names()

内置数据集 Seaborn 数据集

如果你在数据科学领域呆过一段时间,你会仅仅通过它们的名字就认出它们中的许多(泰坦尼克?艾瑞斯。).否则,只需加载数据集并调用head()函数来查看数据。

df = sns.load_dataset("iris")
df.head()

加载和查看 Seaborn 内置数据集

我将使用其中的一些数据集来展示不同种类的可视化技术,所以我将它们全部载入。如果你知道每个数据集是关于什么的,那很好,否则就不要麻烦了。只需知道每个数据集包含不同种类的变量;其中一些是离散变量(例如 10、20、30 英里/加仑),一些是连续变量(例如 5.2、3.6 瓣长),一些是分类变量(例如一周中的几天)。现在,知道不同的变量类型以及何时使用它们应该是可行的。

# loading additional datasets
tips = sns.load_dataset("tips")
mpg = sns.load_dataset("mpg")
fmri = sns.load_dataset("fmri")
car_crashes = sns.load_dataset("car_crashes")

分配

我们的第一类问题是理解数据的分布。我所说的分布指的是几件事:频率分布、概率分布或只是数据相对于中心值的分布(平均值、中间值等)。

直方图

假设我们有一个包含 1000 辆汽车及其燃油效率的数据集,单位为每加仑英里数(mpg)。直方图会告诉我们每一 mpg 类别中汽车数量的频率分布。

# Bar histogram
sns.distplot(mpg["mpg"], kde = False)

柱状图

内核密度图

统计学中使用的这种频率分布有一个更复杂的版本,叫做概率分布。你也可以画出来。

# Line histogram/kernel density plot
sns.kdeplot(mpg["mpg"], shade = True)

核密度图

箱线图

还有另一种类型的分布——更广为人知的是 spread——它显示了一个变量相对于其中心趋势是如何分散/扩散的。

箱线图以展示变量的离差而闻名,变量的值如中值、最小值、最大值和异常值都在同一个图中。

# boxplot
sns.boxplot(y = mpg["mpg"])

箱线图

关系

孩子随着年龄的增长而长高——这是两个变量之间的关系:身高和年龄。

房子越大,价格越高——这是变量之间的另一种关系:楼层大小和价格。

关系图显示变量之间的关系。

散点图

可视化可以检查和绘制变量之间的关联。对于连续变量,您可以非常直观地看到散点图中的任何东西,并直观地确定它们之间的关系。

# scatterplot
sns.scatterplot(x = "sepal_length", y = "petal_length", data = iris)

从下面的散点图可以看出,鸢尾花的花瓣长度与萼片长度呈正相关。

散点图

如果你很难直观地找出这种关系,还有一个选择——画一条趋势线。

# trend line
sns.lmplot(x = "sepal_length", y = "petal_length", data = iris, scatter = False)

趋势线/线性模型

下面的趋势线应用于散点图中与前一条相同的数据。您想使用哪一个取决于您的需求,但也有权衡。在散点图中,你可以看到二维空间中每个数据点的可变性,但不容易跟踪趋势。

在基于线性模型创建的趋势图中,您可以确定数据的总体趋势以及置信区间,但会丢失单个数据点(当然,您也可以在趋势图中显示点)。

使用线性模型的趋势线

比较

比较分析是许多商业决策的关键。哪种产品卖得更好——产品 A 还是产品 B?这两种药物的疗效有显著差异吗?在整个决策过程中,这类问题无时无刻不在被问到。

条形图

条形图是一些最简单、最古老但有效的可视化技术,用于交流比较分析。下图显示了顾客在一周的不同日子里支付的餐厅账单总额。这张图片比较了工作日的账单总额。

# bar chart
sns.barplot(x = "day", y = "total_bill", data = tips)

条形图

折线图

折线图是比较数据的另一种方式。它通常用于时间序列分析,比较两组观察值的时间演变。

# line chart/time series
sns.lineplot(x="timepoint", y="signal", hue="event", data=fmri)

折线图

作文

数据可视化的最后一个支柱是组合。成分图的目的是用绝对和相对术语(如百分比)显示一个或多个变量的成分。

在 Seaborn 中创建复合图有点复杂,它不像其他的那样是一行代码。所以请原谅我在下面举两个例子。

堆积条形图

堆积图在单个条形图中显示不同类别的变量的构成。例如,一个显示阿拉巴马州车祸总数的条形图,该条形图还按涉及酒精的车祸进行了分类(见下图)。

# Initialize the matplotlib figure
f, ax = plt.subplots(figsize=(10, 15))# Plot the total crashes
sns.set_color_codes("pastel")
sns.barplot(x="total", y="abbrev", data=crashes,label="Total", color="b")# Plot the crashes where alcohol was involved
sns.set_color_codes("muted")
sns.barplot(x="alcohol", y="abbrev", data=crashes, label="Alcohol-involved", color="b")# Add a legend and informative axis label
ax.legend(ncol=2, loc="upper right", frameon=True)

堆积条形图

堆叠区域

堆积面积图显示同一绘图区中不同观察组的值的变化。在这种情况下,这些值“堆叠”在彼此的顶部。

Seaborn 的内置数据集和代码对于显示堆叠面积图并不太有用,因此我们将创建一个简单的数据集,并使用matplotlib库显示一个“Seaborn 风格”的图表。

# stacked area
import numpy as np
import matplotlib.pytplot as plt# Data
x = range(1,6)
y = [[2,4,5,6,8], [2,3,6,7,10], [2,6,7,8,5]]# Plot
plt.stackplot(x,y, labels=['X','Y','Z'])
plt.legend(loc='upper left')
plt.show()

堆积面积图

离别赠言

本文的目的是使用 Python 库seaborn演示一些可视化技术。我想涵盖两件事——介绍您在数据科学中通常会遇到的不同类型的可视化,第二,一些使用 Seaborn 内置数据集的代码片段。希望这有用。想看更多这样的文章就大声喊出来。

Seaborn FacetGrid:进一步发展支线剧情

原文:https://towardsdatascience.com/seaborn-facetgrid-taking-subplots-further-15ee7af54e44?source=collection_archive---------7-----------------------

循序渐进的教程

马库斯·斯皮斯克在 Unsplash 上的照片

数据可视化在数据分析中至关重要。“一张图片胜过千言万语”这句名言同样适用于数据可视化领域。在这篇文章中,我将解释一个结构良好、信息量很大的支线剧情集:、FacetGrid

FacetGrid 基本上就是支线剧情的网格。Matplotlib 支持创建具有多个轴的图形,因此允许在一个图形中有子图形。FacetGrid 在 matplotlib 的子情节结构上放了什么:

  • 使过程更容易、更流畅(用更少的代码)
  • 将数据集的结构转移到子情节

使用 FacetGrids 可以很容易地发现变量的分布或变量之间的关系。它们最多可以有三个维度:色调。通过例子,我们会更清楚。那么,我们开始吧。

像往常一样,我们从导入库开始。

注意 : FacetGrid 需要存储在 pandas 数据帧中的数据,其中每行代表一个观察值,列代表变量。因此,我们也进口熊猫。

import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid', color_codes=True)%matplotlib inline

我们将使用 seaborn 的内置“tips”数据集。

tip = sns.load_dataset("tips")
tip.head()

FacetGrid 对象通过传递数据帧和变量名来初始化,以创建轴的结构。用于初始化 FacetGrid 对象的变量需要是分类的离散的。根据类别的数量创建网格结构。例如,“时间”列有两个唯一的值。

tip['time'].value_counts()
Dinner    176 
Lunch      68 
Name: time, dtype: int64

让我们通过将“时间”变量传递给参数来初始化 FacetGrid 对象。

g = sns.FacetGrid(tip, col='time')

我们刚刚创建了一个非常简单的包含两个方面的网格(每个子情节都是一个方面)。使用高度纵横比参数调整刻面的尺寸。

  • 高度是刻面的高度,单位为英寸
  • 纵横比是宽度和高度的比值(宽度=纵横比*高度)。坡向的默认值为 1。

让我们用更大的面来更新网格。

g = sns.FacetGrid(tip, col='time', height=5)

是时候使用 FacetGrid.map() 方法在网格上绘制数据了。它需要一个绘图函数和变量作为参数进行绘图。

g = sns.FacetGrid(tip, col='time', height=5)
g.map(plt.hist, "total_bill")

网格显示基于“时间”的“总账单”直方图。根据绘图函数的不同,我们可能需要为 map 方法传递多个变量。例如,散点图需要两个变量。

g = sns.FacetGrid(tip, col='time', height=5)
g.map(plt.scatter, "total_bill", "tip")

让我们用参数给网格增加一个维度。

g = sns.FacetGrid(tip, row='sex', col='time', height=4)
g.map(plt.scatter, "total_bill", "tip")

“性别”和“时间”列都有两个不同的值,因此创建了一个 2x2 FacetGrid。从上图中我们可以看出,男性和女性的“总账单”和“小费”变量具有相似的趋势。

色调参数允许用颜色给网格增加一个维度。

g = sns.FacetGrid(tip, row='sex', col='time', hue='smoker',    
                  height=4)
g.map(plt.scatter, "total_bill", "tip")
g.add_legend()

我们现在对“总账单”、“小费”和“吸烟者”变量之间的关系有了一个概述。

“日”列有 4 个唯一值:

tip.day.value_counts()
Sat     87 
Sun     76 
Thur    62 
Fri     19 
Name: day, dtype: int64

我们可以创建一个 FacetGrid,显示“total_bill”在不同日子的分布情况。它会显示顾客是否在某一天花费更多。

g = sns.FacetGrid(tip, row='day', 
                  row_order = tip.day.value_counts().index,
                  height=1.5, aspect=4)g.map(sns.distplot, "total_bill", hist=False)

似乎人们倾向于在周末多花一点钱。我们在该图中使用了行顺序参数。顾名思义,它决定了刻面的顺序。在前面的绘图中,我们使用了 matplotlib.pyplot 接口中的绘图函数。但是,对于最后一个,我们使用了 seaborn 包中的绘图功能。这是 FacetGrid 的一个很好的特性,提供了额外的灵活性。

为了丰富 FacetGrids 的功能和外观,可以在 facet grids 上添加更多的特性。如果你想更深入,我建议在 FacetGrid 上查看 seaborn 文档。

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

参考文献

Seaborn 绘图函数层次结构

原文:https://towardsdatascience.com/seaborn-plot-functions-hierarchy-ccc865d974f2?source=collection_archive---------29-----------------------

每个地块系列一个函数

照片由埃文·沃姆斯利Unsplash 上拍摄

python 中的 seaborn 包是我们大多数涉及数据可视化探索和提取洞察力的任务的首选。基于 matplotlib,seaborn 使我们能够生成更清晰的情节,更注重美感。

现在,随着本月 0.11.0 版本的发布,seaborn 不仅仅是一个绘图函数的集合,每个函数对应一种特定类型的绘图。

根据手头任务的性质,有明确定义的绘图功能层次和分组:

  • 单变量分析(分布): displot()
  • 关系分析(特征之间的相互作用和关系): relplot()
  • 分类特征分析: catplot()

这 3 个顶级功能,也称为图形级功能,可用于主类别下的所有图。

来源:Seaborn 文档https://seaborn.pydata.org/index.html

我们为什么要关心这个?嗯,理解 seaborn 如何开展工作的这种细微差别是有好处的。这些优势列举如下:

  • 你只需要知道三个函数——relplot()displot()catplot(),而不是全部十几个绘图函数。
  • 图形级功能为各自类别中的所有图提供了相同的界面/签名。
  • 默认情况下,这将确保图例(如果适用)绘制在绘图之外,从而减少对主要绘图元素的干扰
  • 与 matplotlib 相比,基于数据集的特征容易生成小平面图,代码也更容易阅读
  • 更简单的图形级定制

让我们来看看这些方面。我们将使用 seaborn 中内置的tips数据集。

单变量分析—分布

displot功能(你没看错!这不是印刷错误..是displot而不是distplot,后者现在已被弃用)迎合了描绘特征分布的三种类型的图——直方图、密度图和累积分布图。注意,我们在所有 3 种情况下都只调用了displot,只是改变了kind参数来得到一个不同的图。

双/多变量分析—关系图

relplot功能适用于 2 个或更多特征之间的关系图系列(显示关系/相互作用或缺乏关系)——散点图和线图。

对于lineplot,假设我们想要检查一周中每一天的平均账单金额的趋势。我们使用groupby()按照数据集中的day特征对观察值进行分组。然后,我们使用relplot绘制线图。我们可以看到,与工作日相比,周末餐厅的平均账单金额有明显增加。

分类特征分析

图形级函数catplot满足所有分类特征图

小平面图

与 matplotlib 相比,seaborn 的小平面绘图轻而易举,上面提到的图形级函数使用更少的代码和更少的混乱使它变得更加容易。查看以下图表:

可以通过添加col_wrap参数并传递一个整数值来包装这些列。

如果您是一个习惯性的生物,您仍然可以继续使用本文开头显示的图形级绘图函数下的单独绘图函数。

总结和结论

seaborn 0.11.0 版本中的通用图形级函数简化了绘图函数接口,并为每类绘图下的所有绘图提供了一个通用函数签名。这也减少了通过 matplotlib 实现相同结果的代码和混乱。小平面情节/支线情节也很容易用一行代码实现。

您可能还会喜欢以下关于简化数据可视化和探索性数据分析的文章:

[## 拼凑——下一代 ggplots

进一步扩展 ggplot2 的多功能性..

towardsdatascience.com](/patchwork-the-next-generation-of-ggplots-1fcad5d2ba8a) [## Matplotlib 多列、多行布局

..超越支线剧情中的标准网格布局

towardsdatascience.com](/matplotlib-multi-column-row-spanning-layouts-f026eb7c3c27) [## 使用 SmartEDA 开发的 EDA

探索性数据分析——更智能、更快速的方式..

towardsdatascience.com](/eda-in-r-with-smarteda-eae12f2c6094)

感谢您的阅读!

Seaborn: Python

原文:https://towardsdatascience.com/seaborn-python-8563c3d0ad41?source=collection_archive---------3-----------------------

Seaborn 是 Python 中的一个库,主要用于制作统计图形。

沃洛季米尔·赫里先科在 Unsplash 上的照片

Seaborn 是一个构建在 matplotlib 之上的数据可视化库,与 Python 中的 pandas 数据结构紧密集成。可视化是 Seaborn 的核心部分,有助于探索和理解数据。

要了解 Seaborn,你必须熟悉 NumpyMatplotlibPandas

Seaborn 提供以下功能:

  1. 面向数据集的 API 来确定变量之间的关系。
  2. 线性回归图的自动估计和绘制。
  3. 它支持多绘图网格的高级抽象。
  4. 可视化单变量和双变量分布。

这些只是 Seaborn 提供的部分功能,还有更多,我们可以在这里探索所有的功能。

要初始化 Seaborn 库,使用的命令是:

import seaborn as sns

使用 Seaborn,我们可以绘制各种各样的图,如:

  1. 分布图
  2. 饼图和条形图
  3. 散点图
  4. 配对图
  5. 热图

对于整篇文章,我们使用从 Kaggle 下载的 Google Playstore 数据集。

1.分布图

我们可以将 Seaborn 中的分布图与 Matplotlib 中的直方图进行比较。它们都提供了非常相似的功能。代替直方图中的频率图,我们将在 y 轴上绘制一个近似的概率密度。

我们将在代码中使用 sns.distplot() 来绘制分布图。

在继续之前,首先,让我们访问我们的数据集,

从我们的系统访问数据集

数据集看起来像这样,

来自 Kaggle 的谷歌 Play 商店数据集

现在,让我们看看分布图看起来如何,如果我们从上面的数据集中绘制“评级”列,

评级栏分布图的代码

评级栏的分布图如下所示,

分布图—评级

这里,出现在分布图上的曲线( KDE )是近似概率密度曲线。

类似于 matplotlib 中的直方图,在 distribution 中也是如此,我们可以改变箱的数量,使图形更容易理解。

我们只需要在代码中增加仓的数量,

#Change the number of bins
sns.distplot(inp1.Rating, bins=20, kde = False)
plt.show()

现在,图表看起来像这样,

具有特定箱数的分布图

上图中,没有概率密度曲线。要移除曲线,我们只需在代码中写‘kde = False’

我们还可以向分布图提供类似于 matplotlib 的条块的标题和颜色。让我们看看它的代码,

对于相同的列评级,分布图如下所示:

带标题的分布图

设计航海图

使用 Seaborn 的最大优势之一是,它为我们的图形提供了广泛的默认样式选项。

这些是 Seaborn 提供的默认样式。

'Solarize_Light2',
 '_classic_test_patch',
 'bmh',
 'classic',
 'dark_background',
 'fast',
 'fivethirtyeight',
 'ggplot',
 'grayscale',
 'seaborn',
 'seaborn-bright',
 'seaborn-colorblind',
 'seaborn-dark',
 'seaborn-dark-palette',
 'seaborn-darkgrid',
 'seaborn-deep',
 'seaborn-muted',
 'seaborn-notebook',
 'seaborn-paper',
 'seaborn-pastel',
 'seaborn-poster',
 'seaborn-talk',
 'seaborn-ticks',
 'seaborn-white',
 'seaborn-whitegrid',
 'tableau-colorblind10'

我们只需编写一行代码就可以将这些样式合并到我们的图表中。

将深色背景应用于我们的图表后,分布图看起来像这样,

深色背景的分布图

2.饼图和条形图

饼图通常用于分析不同类别中数值变量的变化情况。

在我们使用的数据集中,我们将分析内容评级栏中前 4 个类别的表现。

首先,我们将对内容评级列进行一些数据清理/挖掘,并检查那里有哪些类别。

现在,类别列表将会是,

内容分级计数

根据上面的输出,由于“仅 18 岁以上成人”和“未分级”的数量明显少于其他类别,我们将从内容分级中删除这些类别并更新数据集。

在更新表格之后,在“内容分级”栏中出现的类别是,

更新数据集后的内容分级计数

现在,让我们为“内容评级”列中的类别绘制饼图。

上面代码的饼状图如下所示,

内容分级饼图

从上面的饼状图,我们无法正确推断是否“人人 10+”和“成熟 17+”。当这两个类别的值有些相似时,很难评估它们之间的差异。

我们可以通过在条形图中绘制上述数据来克服这种情况。****

现在,条形图看起来像下面这样,

内容分级栏的条形图

类似于饼图,我们也可以定制我们的条形图,用不同颜色的条,图表的标题,等等。

3.散点图

到目前为止,我们一直只处理数据集中的单个数字列,如评级、评论或大小等。但是,如果我们不得不推断两个数字列之间的关系,比如“评级和大小”或“评级和评论”呢?

当我们想要绘制数据集中任意两个数值列之间的关系时,可以使用散点图。这些图是在机器学习领域使用的最强大的可视化工具。

让我们看看数据集“Rating”和“Size”中的两个数字列的散点图是什么样子的。首先,我们将使用 matplotlib 绘制图形,然后我们将看到它在 seaborn 中的样子。

使用 matplotlib 的散点图

**#import all the necessary libraries** **#Plotting the scatter plot** plt.scatter(pstore.Size, pstore.Rating)
plt.show()

现在,情节看起来像这样

使用 Matplotlib 绘制散点图

使用 Seaborn 的散点图

我们将在散点图和直方图的代码中使用 sns.joinplot()

sns.scatterplot() 在代码中仅用于散点图。

上面代码的散点图看起来像,

使用 Seaborn 的散点图

在 seaborn 中使用散点图的主要优点是,我们将在图形中获得散点图和直方图。

如果我们只想看到散点图,而不是代码中的“ jointplot ”,只需将其更改为“散点图****

回归图

回归图在接合图(散点图)中的两个数值参数之间创建一条回归线,并帮助可视化它们的线性关系。

该图如下所示,

在 Seaborn 中使用 jointplot 的回归图

从上面的图表中,我们可以推断,如果应用程序的价格增加,评级会稳步上升。

4.配对图

当我们想要查看 3 个以上不同数值变量之间的关系模式时,可以使用配对图。例如,假设我们想了解一家公司的销售如何受到三个不同因素的影响,在这种情况下,结对图将非常有帮助。

让我们为数据集中的评论、大小、价格和评级列创建一个配对图。

我们将在代码中使用 sns.pairplot() 一次绘制多个散点图。

上述图形的输出图形如下所示,

使用 Seaborn 的配对图

  • 对于非对角线视图,图表将是两个数值变量之间的散点图****
  • 对于对角线视图,它绘制了一个直方图,因为两个轴(x,y)是相同的。

5.热图

热图以二维形式显示数据。热图的最终目的是在彩色图表中显示信息摘要。它利用了使用颜色和颜色强度来可视化一系列值的概念。

我们大多数人都会在足球比赛中看到以下类型的图形,

足球运动员的热图

Seaborn 的热图正是创建了这些类型的图表。

我们将使用 sns.heatmap() 来绘制可视化。

当您拥有如下数据时,我们可以创建一个热图。

上表是使用 Pandas 的数据透视表创建的。你可以在我之前的文章 熊猫 中看到数据透视表是如何创建的。

现在,让我们看看如何为上表创建一个热图。

在上面的代码中,我们将数据保存在新变量“heat”中

热图如下所示,

在 Seaborn 上创建的默认热图

我们可以对上面的图形进行一些定制,也可以改变颜色渐变,这样最高值的颜色会更深,最低值的颜色会更浅。

更新后的代码将是这样的,

上面更新的代码的热图如下所示,

对代码进行了一些定制的热图

如果我们观察,在我们给出的代码“ annot = True ”中,这意味着,当 annot 为 true 时,图中的每个单元格显示其值。如果我们在代码中没有提到不能**,那么它的默认值是 False。**

Seaborn 还支持一些其他类型的图表,如线形图、条形图、堆积条形图、等。但是,它们与通过 matplotlib 创建的没有任何不同。

结论

这就是 seaborn 在 Python 中的工作方式,以及我们可以使用 Seaborn 创建的不同类型的图表。正如我已经提到的,Seaborn 构建在 matplotlib 库之上。因此,如果我们已经熟悉了 Matplotlib 及其函数,我们可以很容易地构建 Seaborn 图,并可以探索更深入的概念。

感谢您阅读快乐编码!!!

在这里查看我以前关于 Python 的文章

参考

Seaborn 可视化教程

原文:https://towardsdatascience.com/seaborn-visualizations-tutorial-c390bf1d43ce?source=collection_archive---------21-----------------------

使用 NHL 统计数据浏览 Seaborn 的工具箱

作者安德鲁·科尔

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

如果你和我一样,一个没有体育的世界根本就不是世界。然而,进入 2020 年和新冠肺炎的时间,我们在这里,看着 2003 年 NCAA 锦标赛第二轮的重播,假装我们就像 2020 年锦标赛一样投入(当我打这篇文章时,它应该正在发生)。这个不幸的疫情也意味着我们错过了一年中我个人最喜欢的时间,NHL 季后赛。因此,为了弥补运动带给我们如此多的人的生活的缺乏,我决定将 NHL 统计数据整理成一个给我们中的一些人带来生活的概述。

Seaborn 是 Python 最强大和最基本的可视化包之一,通过数据讲述可视化故事有无限的可能性。所有 NHL 的数据都是从 MoneyPuck.com 的 T4 收集的。这款笔记本的 GitHub 库可以在这里找到。

数据

我们先清理一下现有的信息。我们将从所有情况下的溜冰者中选择数据(5v5,男子优势,人手不足,等等。).接下来,因为有 31 支 NHL 球队,这对于这些教学目的来说是一个很大的处理量,所以我们将数据限制在仅来自中央赛区的球队:芝加哥黑鹰队、纳什维尔掠夺者队、圣路易斯蓝调队、科罗拉多雪崩队、明尼苏达怀尔德队、温尼伯喷气机队和达拉斯明星队。

我们将要处理的数据帧如下所示:

我们有来自 200 个玩家的 153 个统计特征的统计数据。我们将只关注基本的统计数据,如进球、得分、点球等。

海生的

要导入库:

import seaborn as sns

我们将 seaborn 重命名为“sns ”,以便以后在可视化时调用它。

散点图— sns.relplot()

与任何数据集一样,我们想看看统计关系。也许观察二元关系的最好方法是使用散点图。每个点将显示一个统计要素中观测值的联合分布及其第二个要素的位置。我们先来看看积分是怎么来的(1 球= 1 分,1 助攻= 1 分;1 球+ 2 助攻= 3 分)

我们可以看到,正如你直觉所料,玩的游戏越多,得分越高。这只是你的基本散点图,那么我们如何让这个图表给我们更多的信息呢?让我们添加一个色调。

色调图— sns.relplot()

通过在 sns.relplot()代码中添加“hue”参数,我们能够看到每个团队的得分/比赛分布情况。我们能更进一步吗?这个情节只告诉我们每支队伍的分数和比赛,但是还有更多信息需要了解!职位呢?在那些单独的队伍中,谁得分更多?我们来加点支线剧情了解一下。

现在我们有了和上面一样的图表,按团队和位置分类。每行代表不同的球队,每列代表不同的位置(进攻或防守)。举个例子,我们可以看到芝加哥有一个前锋在刚刚打完的 60 多场比赛中得分超过 80 分,而芝加哥的大部分防守队员无论打多少场比赛得分都不到 20 分(只有一个例外)。

直方图— sns.distplot()

直方图是任何分析师都能创建的最强大的可视化工具之一。直方图以图形方式总结了所有数据的分布。简单来说,直方图显示了数据集中每个值出现的频率。x 轴包含变量度量,而 y 轴包含观察值的相对频率。

上面的直方图告诉我们,绝大多数联盟得分在 0 到 20 分之间。我们看到的平滑线是核密度估计(KDE)——一种基于我们已有样本估计未知变量概率分布的技术。更简单地说,如果新的玩家数据被引入到集合中,它最有可能落在平滑线的最高峰之下。我们在图表底部看到的刻度线被称为地毯。rug 简单地向我们展示了各个数据观察值在图表上的位置。您可以通过将代码参数设置为 False 来消除直方图中的 KDE 和地毯。

box plot—SNS . cat plot(kind = ' box ')

另一种有助于我们了解数据的图表是箱线图。具体来说,箱线图帮助我们确定数据的中位数、范围和可变性在哪里。团队得分的箱线图如下所示:

我们看到的方框显示了分布的三个四分位数(大的彩色方框),该组的平均值(通过团队方框中间的水平线),以及异常值(图表上方的点)。例如,科罗拉多州的得分率大多在 0-32 之间。科罗拉多州盒子上方的点是异常值,这意味着雪崩有一个明显高于团队其他人的单点得分,因此使其成为异常值。

为了使这个图更具描述性,我们可以再次添加“位置”作为色调,以显示每个位置(进攻或防守)的团队中的异常信息。

小提琴情节— sns.catplot(kind = 'violin ')

小提琴图是一种不太流行但更具描述性的可视化方法。箱线图实际上没有考虑数据的分布。如果数据发生变化(比如增加整个联盟的数据,而不仅仅是中部地区的数据),中位数和范围不会变化,但小提琴图反映这种变化。小提琴图将“变宽”,以表示该值附近更高的观察密度。

我们现在可以看到,芝加哥的防守得分在 0-40 分之间,而明尼苏达的防守得分范围要大得多。小提琴图越宽,观察值处的数据越密集。

我们还可以通过添加一个“分割”来创建一个更精简的版本:

图表显示了同样的事情,只是通过将防御和进攻小提琴合二为一而简化了。芝加哥的前锋得分范围很大,而其防守队员的得分都集中在 0 到 20 分之间。

蜂群图— sns.catplot(kind = 'swarm ')

群体图基本上就是一个散点图,X 轴代表一个分类变量。

我们可以通过这个群集图看到,温尼伯拥有分区最高的进球得分者,但他们球队的大部分得分都在 10 分以下。让我们翻转类别,按职位和团队查看目标。

现在我们可以看到前锋明显比防守队员进更多的球,迄今为止最高的射手为温尼伯效力。

抖动图— sns.catplot(抖动=真)

抖动图与我们的蜂群图非常相似,但它让我们更有条理。这是你正常的点状图,但是它增加了一个“抖动”——一个点与点之间的间隔,以便更好的可视化。让我们用一个抖动图来看看各个位置的罚分数量。我们可以看到所有被罚 16 分以上的球员都是前锋

Jointplot — sns.jointplot()

jointplot 是 seaborn 在显示单变量概要文件的同时显示双变量关系的方法。本质上结合了散点图和直方图(没有 KDE)。让我们来看看一个接合图,看看采取的处罚数量是如何与点生产。

如果我们看主要的散点图,我们真的不能做出很大的区别。人们固有地认为,少量的点球意味着更多的时间待在冰上,这意味着更多的得分机会。然而,散点图本身并没有显示任何方向上的强关系。但是,jointplot 为我们提供了沿着顶部和右侧脊线显示分布的好处。通过查看这些,我们可以看到随着处罚数量的增加,这些地区的玩家越来越少。积分也是如此。因此,我们可以推断,两者之间存在轻微的正相关关系。

hex plot—SNS . joint plot(kind = ' hex ')

另一种可视化双变量关系的方法是 hexplot,特别是当我们有大量数据时。六格图将绘图窗口分成几个六格,然后落入每个格中的观察值的数量用一种颜色表示密度。颜色较深的六边形意味着在那个区域有更多的观察,或更多的密度。观察频率条形图可以沿着脊柱看到,作为额外的参考信息。我们将使用六边形图来分析进球数与射门次数之间的关系。

同样,这个图表可能是固有的。正如伟大的韦恩·格雷兹基/迈克尔·斯科特曾经说过的,“你没有出手的时候,你百分之百会错过”。我们相信随着射门次数的增加,进球数量也会增加。hexplot 重申了这个观点。我们在右下角看到了最暗的 hexbin,因为它是最密集的,因为在 NHL 中进球不是一件容易的事情,大多数球员都将集中在这个区域。当我们向右上方增加六边形时,颜色开始慢慢变淡,这表明射门次数和得分之间的正相关关系逐渐减少。

核密度估计-joint plot-SNS . joint plot(kind = ' kde ')

与 hexbin 相似的二元图是核密度估计联合图。KDE 联合图也使用颜色来确定观察值最密集的地方,但不是将它们放入预定义的六边形中,而是使用新数据引入的概率来制作连续图。让我们看看同样的射门次数/进球次数的关系。

我们可以看到,给我们的信息与在 hexbin 图中给我们的信息相同,但这显示了观察位置的概率视图。hexbin 没有向我们显示大多数球员都属于低进球/低射门尝试类别,我们可以看到更多射门尝试等于更多进球的概率越来越呈正相关,最大的球员集中在 0-50 次射门尝试范围和 0-5 次进球范围。

相关

双变量关系可以告诉我们很多,但是仅仅看分布图和散点图可能不足以提供我们所需要的关于数据表面数字下发生的事情的所有信息。相关性向我们展示了一个变量的值对另一个变量的影响程度。强相关性(1.00)表示当一个变量发生变化时,另一个变量也会发生 100%的正向变化(相反方向为-1.00)。让我们看看 NHL 中的某些变量在相关性方面有多重要。下面是检查相关性的代码:

观察这些数字让我们明白了很多,注意,z 轴向右下方移动代表了变量与自身的完美相关性。我们可以看到,像分数这样的某些变量与射门次数、密切相关,因为相关系数都远高于 0.5。但是统计数据和数据集通常不像体育统计数据那样直观,所以让我们看看如何让这个相关图表对用户更友好。

热图— sns.heatmap()

热图只是我们在上面制作的关联表的一种更友好的可视化方式。如果相关系数较高,表明两个变量之间的相关性更显著,则颜色会更深。同样,参考深蓝色的 z 轴来表示变量与其自身之间完美的 1:1 相关性。

这张热图只是以一种更简单的方式将我们的目光吸引到最佳和最差的相关性上。例如,我们很容易看到射门次数和射门次数的相关性最强,而命中率与进球的相关性最小。

Pairplot — sns.pairplot()

最后,或许对任何分析师来说,最强大、最有用的工具之一就是 Pairplot。pairplot 可视化了单个变量的分布以及与其他变量的双变量关系。简单地说,我们将为数据框架中的每个变量创建一个二元散点图,然后将它们放入一个屏幕中。

这个庞大的图表有一大堆,但是它也非常有助于获得我们正在寻找的东西的整体视图。我们阅读它就像阅读二元散点图一样。如果我们看到两个变量之间有很强的正/负关系,我们就知道这些变量及其关系值得进一步研究。

就是这样!目前…

Seaborn 是一个非常强大的工具,可以将复杂的数据转化为易于理解的信息。可能性似乎是无穷无尽的,但希望这是所有可能性的良好开端。因此,请大家保持安全,保持健康,待在室内,我们都会没事的:)。

用深度学习搜索 COVID 论文

原文:https://towardsdatascience.com/search-in-covid-papers-with-deep-learning-a3c14a61f501?source=collection_archive---------48-----------------------

一个语义浏览器使用深度学习和弹性搜索来搜索 COVID 论文

今天,我们将使用深度学习建立一个语义浏览器,在超过 5 万篇关于最近新冠肺炎病的论文中进行搜索。

所有代码都在我的 GitHub repo 上。而这篇文章的现场版是这里

其核心思想是将每篇论文编码成一个表示其语义内容的向量,然后使用查询和所有编码文档之间的余弦相似性进行搜索。这与图像浏览器(例如 Google Images)搜索相似图像的过程相同。

因此,我们的难题由三部分组成:数据、从论文到向量的映射以及搜索方法。

大部分工作都是基于这个项目,在这个项目中,我和来自意大利的里雅斯特大学的学生一起工作。此处有现场演示

我们开始吧!

数据

一切从数据开始。我们将使用来自 Kaggle 的数据集。由白宫和领先研究团体联盟准备的超过 57,000 篇学术文章的列表。实际上,我们唯一需要的文件是包含论文信息和摘要全文的metadata.csv。您需要将文件存储在./dataset中。

让我们来看看

import pandas as pddf = pd.read_csv('./dataset/metadata.csv')df.head(5)

如你所见,我们有很多信息。我们显然对文本栏感兴趣。和熊猫一起工作并不理想,所以让我们创造一个Dataset。这将允许我们稍后创建一个DataLoader来执行分批编码。如果你不熟悉 Pytorch 数据加载生态系统,你可以在这里阅读更多关于的内容

按照顺序,我子类化了torch.utils.data.Dataset来创建一个定制数据集。数据集需要一个 dataframe 作为输入,我们只保留了感兴趣的列。然后,我们删除了一些行,其中的abstracttitle列分别与FILTER_TITLEFILTER_ABSTRACT中的一个“垃圾”单词相匹配。这样做是因为文章以自动的方式被废弃,并且许多文章有不相关的条目而不是标题/摘要信息。

数据集返回一个字典,因为 PyTorch 不支持pd.DataFrame类型。为了给我们的搜索引擎更多的上下文,我们将titleabstract合并在一起,结果存储在title_abstract键中。

我们现在可以调用数据集,看看是否一切都是正确的

ds = CovidPapersDataset.from_path('./dataset/metadata.csv')ds[0]['title']

输出:

'Sequence requirements for RNA strand transfer during nidovirus discontinuous subgenomic RNA synthesis'

把…嵌入

我们现在需要一种方法从每个数据点创建一个向量(嵌入)。我们定义了一个类Embedder,它使用 sentence_transformers 库从 HuggingFace 的 [transformers](https://github.com/huggingface/transformers)中自动加载一个模型。

选择的模型是gsarti/BioBERT-nliaBioBERT模型,在 SNLIMultiNLI 上进行微调,以产生通用句子嵌入。Gabriele Sarti 进行了微调,复制它的代码可从这里获得。

BioBERT 特别适合我们的数据集,因为它最初是在生物医学科学出版物上训练的。因此,考虑到与我们的数据的相似性,它应该创建更好的上下文感知嵌入。

在幕后,模型首先将输入字符串标记化,然后为每个标记创建一个向量。因此,如果我们在一篇论文中有N个标记,我们将得到一个[N, 768]向量(注意,一个标记通常对应一个单词片段,在这里阅读更多关于标记化策略。因此,如果两篇论文有不同的字数,我们将有两个不同的第一维向量。这是一个问题,因为我们需要将它们与搜索进行比较。

为了获得每篇论文的固定嵌入,我们应用平均池。这种方法计算每个单词的平均值,并输出一个固定大小的 dims 向量[1, 768]

所以,让我们编写一个Embedder

我们可以在数据点上尝试我们的嵌入器

embedder = Embedder()emb = embedder(ds[0]['title_abstract'])emb[0].shape // (768,)

瞧啊!我们对一篇论文进行了编码。

搜索

好的,我们知道如何嵌入每篇论文,但是我们如何使用查询来搜索数据呢?假设我们已经嵌入了所有论文,我们也可以嵌入查询并计算查询和所有嵌入之间的余弦相似性。然后,我们可以显示按距离(分数)排序的结果。直觉上,它们在嵌入空间中离查询越近,它们共享的上下文相似性就越大。

但是,怎么做呢?首先,我们需要一种适当的方法来管理数据,并足够快地运行余弦相似性。幸运的是,弹性搜索来救援!

弹性搜索

弹性搜索是一个目标只有一个的数据库,是的你猜对了:搜索。我们将首先在 elastic 中存储所有嵌入,然后使用它的 API 来执行搜索。如果你像我一样懒,你可以用 docker 安装弹性搜索

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.6.2
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.6.2

完美。下一步是在弹性搜索中存储嵌入和论文信息。这是一个非常简单的过程。我们需要创建一个index(一个新的数据库),然后为每篇论文建立一个条目。

为了创建一个index,我们需要为 elastic 描述我们希望存储的内容。在我们的案例中:

你可以在弹性搜索文档上阅读更多关于索引创建的内容。最后一个条目将embed字段定义为带有768的密集向量。这确实是我们的嵌入。为了方便起见,我将配置存储在一个.json文件中,并创建了一个名为ElasticSearchProvider的类来处理存储过程。

大部分工作都是在create_and_bulk_documents完成的,在那里我们每次只解构一个条目,并添加两个弹性搜索参数。

不幸的是,弹性搜索无法序列化numpy数组。所以我们需要为我们的数据创建一个适配器。该类将纸张数据和嵌入作为输入,并“调整”它们以在我们的ElasticSearchProvider中工作。

好了,我们一切就绪。一种表示数据的方法,一种将数据编码成向量的方法和一种存储结果的方法。让我们把所有的东西都包起来,把所有的文件都编码。

这里有两个技巧,首先,我们使用torch.utils.data.DataLoader创建一个批处理式迭代器。总的来说,将数据成批地而不是作为一个单独的点提供给模型可以提高性能(在我的例子中是 x100)。其次,我们替换DataLoader构造函数中的collate_fn参数。这是因为,默认情况下,Pytorch 会尝试将我们所有的数据转换成一个torch.Tensor,但是它无法转换字符串。通过这样做,我们只返回一个字典数组,即来自CovidPapersDataset的输出。所以,batch是一个长度为batch_size的字典列表。我们做完后(1080ti 上~7m),可以看一下[http://localhost:9200/covid/_search?pretty=true&q=*:*](http://localhost:9200/covid/_search?pretty=true&q=*:*.)

如果一切正常,您应该会看到弹性搜索显示我们的数据

进行查询

我们差不多完成了。拼图的最后一块是在数据库中搜索的方法。弹性搜索可以在所有文档中的一个输入向量和目标向量场之间执行余弦相似性。语法非常简单:

{
    "query": {
        "match_all": {}
    },
    "script": {
        "source":
        "cosineSimilarity(params.query_vector, doc['embed']) + 1.0",
        "params": {
            "query_vector": vector
        }
    }
}

其中vector是我们的输入。因此,我们创建了一个类,它将一个向量作为输入,并显示查询的所有结果

让我们看看第一个结果(我已经复制并粘贴了第一篇匹配论文的摘要)

es_search = ElasticSearcher()
es_search(embedder(['Effect of the virus on pregnant women'])[0].tolist())

作为应对新发感染的公共卫生专业人员,需要特别关注孕妇及其后代。孕妇可能更容易感染新出现的感染,或受到更严重的影响。新的母体感染对胚胎或胎儿的影响很难预测。一些推荐用于预防或治疗的药物可能会伤害胚胎或胎儿。我们讨论了应对孕妇中新出现的感染的挑战,并提出了克服这些挑战的策略。

成功了!我还创建了一个命令行,用户可以在其中输入查询。最后的结果是:

更多查询

最后可以提一个问题,找感兴趣的论文。从经验上看,越详细的查询效果越好,因为它们提供了更多的上下文。

例如,我们可能想知道氯喹对新冠肺炎有什么效果。结果是

或者新冠肺炎如何与 ACE2 受体结合?**

搜索引擎似乎工作良好,但它并不完美,在本教程的下一部分,我们将努力提高其准确性。

结论

在这个项目中,我们建立了一个语义浏览器来搜索超过 5 万篇新冠肺炎论文。我和的里雅斯特大学的学生合作的最初项目是这里的。这里有现场演示

你也可以使用命令行程序,你需要按照这里的指示。

承认

我要感谢 Gabriele Sarti 对我撰写本文的帮助, Marco FranzonTommaso Rodani 对我在弹性搜索实现中的支持。

感谢您的阅读

注意安全,

弗朗西斯科·萨维里奥·祖皮奇尼

搜索(第 1 部分)——一个温和的介绍

原文:https://towardsdatascience.com/search-pt-1-a-gentle-introduction-335656c0f814?source=collection_archive---------43-----------------------

从基本的积木到 DIY 搜索引擎

照片由 PhotoMIX 公司Pexels 拍摄

T4 在不到一秒钟的时间里搜索整个网络,寻找我们想知道的任何东西的能力是近代史上最伟大的成就之一。但是它是如何工作的呢?它的组成部分是什么?而且,最重要的是,……我们能不能拼凑出我们自己的版本?后者很重要,因为搜索不可避免地是个人化的:它关乎我们的关注点、偏好、可支配的资源甚至情感。另外,它真的很酷!

在这个由三部分组成的系列中,我将:

  • Pt 1。提供一个温和的介绍使用 Google 和 Elasticsearch 作为例子进行搜索
  • Pt 2。我们将解释一些最新的自然语言处理技术,将结果与传统方法进行比较,并讨论利弊
  • Pt 3。提供一份黑客指南,帮助您构建自己的搜索引擎包含 100 万条新闻标题的 elastic search engine&采用最先进的自然语言处理技术进行增强的语义搜索…

搜索-简而言之

如今,当我们谈论搜索时,我们通常指的是语义搜索。你会问,什么是语义搜索?想象一下,搜索“病毒威胁”这个词。一个简单的词汇搜索方法将返回包含单词的文档,并且按照特定的重要性顺序排列。另外,关于“安全威胁”的文档也将被认为是相关的,因为它们包含查询的一部分。

另一方面,语义搜索也能够获得“疾病”、“感染”和“电晕”的概念——我们有一个更广泛、潜在更准确的搜索,反映我们正在寻找的东西的“意义”,而不是坚持特定的关键词。在这一部分,我经常从巴斯特,汉娜的作品中获得灵感;比约恩·布赫霍尔德;埃尔马尔·奥斯曼(2016 年)。“文本和知识库的语义搜索”。他们在文中指出:

语义搜索表示有意义的搜索,与词汇搜索不同,词汇搜索是搜索引擎在不理解查询的整体意义的情况下寻找查询词或其变体的文字匹配

下图显示了这种搜索引擎的核心组件

作者图片

我们专注于对带有一些附加注释(如姓名、日期、链接等)的文本的语义搜索,而不是对结构化数据库的搜索。这基本上是我们一直在使用的典型网络搜索

请注意,本文处理的是产生相关文档或单个事实列表的搜索,而不是额外的步骤,如基于源质量的排名,如 PageRank、结果汇总等。

查询类型

这些可以分为:

  • 关键词 -这些是速记搜索,不是正确的句子,但其中的一组关键词和有时的顺序带有语义,例如尼尔·阿姆斯特朗的出生日期,10 分钟内的意大利面食谱
  • 结构化/半结构化 -查询中使用的特殊语法。它可以表示完整的查询,也可以只是对它的细化。例如,这可能是仅搜索特定来源的限制,例如仅来自 AP 的新闻。在其他情况下,这可能会限制结果的语言或陈述查询的强制元素
  • 自然语言&自然问题——完全或大部分语法形式的问题:“尼尔·阿姆斯特朗的生日是哪一天?”。这是与搜索交互的最自然的方式,然而,这也带来了许多困难。例如,我们可以同时问多个问题“哪里可以停车,营业时间是什么时候?”或者提出哲学上的问题,而不是事实上的问题“生命的意义是什么?”。从例子中可以看出,问题的范围相当广泛。虽然这些对我们来说有意义,但算法往往专注于狭窄的任务,因此需要各种算法协同工作,能够确定哪些结果是合适的。

询问处理

在将原始条目传递给搜索算法之前,系统可能需要对其执行不同类型的转换。那些可能是

  • 提取 -提取特定的名称、实体、位置,以进一步帮助搜索并与文档元数据中的值或知识库进行比较。例如,在下面的查询 Neil Armstrong 中,左边的信息框是调用 google 知识库的结果,因为该查询与其中的一个条目成功匹配

  • 过滤器和限制 -在半结构化查询对结果指定了一些限制的情况下,例如,只有英语新闻,搜索范围将被转换到搜索引擎
  • 其他转换是对搜索的修改,例如针对通配符或模糊搜索。在这种情况下,原始查询可以被转换成一个或多个变体。例如,使用模糊搜索,我们可以允许对输入的关键字进行一些字符修改,直到找到最有可能被搜索的单词。请看下面,当我在谷歌上搜索尼尔·阿姆斯隆时的结果。即使一个叫 Armslong 的先生可能存在并且很重要,系统认为我们更有可能是打错了。

搜索和排名

最后,可以使用一种或多种类型的搜索和排序方法。这些将能够找到答案或者返回匹配查询的结果的排序列表。排名确保更相关的结果在更高的位置-这些结果可能比其他结果更频繁地提到搜索的关键字,或者在其标题或开头段落中包含与查询相关的信息。有:

  • 关键词搜索——最常见的类型,精确或非常接近文字匹配。搜索的主要部分仍然是这样完成的。什么使它们具有语义——它们将使用术语出现来排列与某个关键词更相关的更高的文档,并识别出某些关键词何时是罕见的,这些关键词的命中率高于查询中更“常见”的词的命中率。有许多算法可用:BM25、tf-idf、各种学习排序方法等。
  • 上下文搜索——我指的是任何基于文本嵌入的搜索,试图完全使用查询并找到上下文相关的结果。这与单独依赖任何特定的关键词或短语来确定结果相反。我们将在稍后重点讨论这个问题,因为它是本系列的核心。NLP 技术的一些最新进展将帮助我们显著提高搜索质量。

让我们快速地进行一个面对面的关键词对比上下文搜索。搜索“病毒线程”,在新闻标题上,左边的结果来自关键字方法,而右边的结果来自上下文搜索。后者给了我们一些结果,这些结果与任何搜索词都不匹配,如右边的示例 5:“世卫组织强调病媒传播疾病的危险”

  • 知识库 -如上所述,知识库中的条目可以直接与知识库中的条目匹配,并进一步用于生成结果。也可以应用更高级的技术,其中关键字或自然语言查询可以被转换成对知识库的查询。例如,“月球上的宇航员”将返回另一个知识库结果

  • 问答——传统上,搜索引擎已经使用处理步骤的修改,将一个自然的问题转换成一个更像关键词的查询,并照此进行处理。最近,自然语言处理的进展显示了算法的强大性能,这些算法直接指出在特定文档中是否以及在哪里可以找到自然问题的答案。与上面的其他搜索范例不同,问答侧重于提供一个实际的(单个)答案,而不是一系列文档(就像这个列表中的其他文档)。当我们把登月作为一个自然的问题来问时,会发生什么。除了一系列答案之外,我们还会得到一个具体的答案。

然而,这项技术同样适用于一个不太自然的问题“首次登月的年份”

最后,对查询的轻微修改可能会破坏结果,我们不再得到明确的答案,我们甚至完全在其他地方着陆

把所有的放在一起

总之,任何查询类型都可以经过许多不同的修改,并可以通过许多搜索机制中的任何一种来产生候选结果。这些方法中的每一种都将表达其结果的置信度,然而,不同算法之间的不同置信度分数可能不可比较。在这一阶段,进一步的决策算法将能够确定哪些答案是非常合适的,并且足够“自信”以作为最终的答案列表传递给用户。

作者图片

一个正常运行的搜索引擎可以包含该过程三个步骤中的任何一个或至少一个。我们已经看到谷歌在幕后使用了它们中的大部分,但是如何制作我们自己的呢...

我应该透露我的秘密议程…

事实上,我一直想黑掉我自己的搜索引擎。

选择的工具是 Elasticsearch,主要是因为它实际上自带了很多搜索功能。同时,它得到了很好的支持,并在开源特性方面给了你很大的帮助。

这里是一个图表,显示了我们在讨论中使用 Elastic 后得到的结果。请注意,您不应该相信我的总结完整性,因为我心中有一个具体的目标。

作者图片

您会注意到,Elastic 可以处理任何类型的查询(尽管它们在默认情况下都由关键字搜索机制处理),并允许进一步修改您的查询,以模糊、通配符和许多其他类型的查询。如果数据允许,人们还可以对结果应用任意数量的结构化条件:出版日期、来源等。

就搜索和排名而言,关键字搜索有很大的灵活性,但其他的就不多了。

总的来说,这是一个令人印象深刻的开箱即用特性列表。事实证明,通过一些额外的跑腿工作,我们甚至可以添加上下文搜索。这就是我们接下来要做的...

结论

我们探讨了搜索的主要组成部分,它们是如何协同工作的,以及对搜索结果的影响。不同类型的查询可能触发不同的搜索算法,结果是各种方法的混合。从 Google 的例子中我们可以看到,相同的用户体验(在一个简单的文本框中输入)是由多种技术提供的。

在接下来的文章中,我们将并排比较上下文搜索和关键字搜索( Pt 2 ),最后,我们将结合一些不同的工具来扩展 Elasticsearch 的功能,增加上下文搜索功能来构建我们自己的语义搜索引擎( Pt 3 )。

顺便说一句,尼尔·阿姆斯隆

我希望你喜欢阅读这篇文章,下周我们将在第二部分中带来更多内容。与此同时,如果你想打招呼或者只是想告诉我我错了,请随时通过 LinkedIn 联系我

特别感谢 Rich Knuszka 的宝贵反馈。

请注意,我与谷歌或 Elasticsearch 没有任何关系,观点和分析是我自己的

搜索(第二章)——语义赛马

原文:https://towardsdatascience.com/search-pt-2-semantic-horse-race-5128cae7ce8d?source=collection_archive---------28-----------------------

领先的自然语言处理与传统搜索

诺亚·西利曼在 Unsplash 上的照片

在这篇非技术性的文章中,我们将比较上下文搜索和基于关键字的方法。对于前者,我们将利用 NLP 的一些最新发展来搜索大量的新闻。我们将重点解释这种方法与传统方法的区别、优缺点。

这是一个关于搜索的三部分系列。

的第一部分——一个温和的介绍中,我们提供了一个搜索基本构件的概述。

最后, Pt 3 (Elastic Transformers) 包含了如何构建一个索引的纯技术考虑,作为一个带有上下文文本嵌入的弹性搜索引擎。对于当前的讨论,我们将使用该搜索索引的一些结果。

在本文中,我们将

  • 了解关键字和上下文搜索如何与进行比较,以及 NLP 中的最新技术可以在哪些方面帮助我们进行搜索
  • 考虑一些例子测试不同的查询以及两者有何不同
  • 最后,我们将一起考虑这些方法的利弊

图片由作者使用 gifox

在上一篇文章中,我们鸟瞰了搜索的工作原理、构建模块以及它们之间的区别。这里,我们将考虑上下文搜索和关键字搜索之间的实际比较。对于上下文搜索,我们具体指的是使用 NLP 转换器的文本嵌入,我们稍后会深入探讨。

传统的关键词搜索倾向于使用特定的关键词频率来识别搜索查询的最佳匹配。然而,在某些情况下,这可能是有限制的,特别是,如果我们使用的关键字不代表我们正在搜索的文档。例如,我们可能查找“自然灾害”,但是可用的文档可能包含许多特定灾害的示例,例如“飓风”、“地震”等。而不像我们明确选择的那样提及那些“自然灾害”。这就是语境嵌入可以发挥作用的地方。

为上下文搜索输入文本嵌入

文本嵌入是单词、句子或文档作为向量的数学表示。这意味着我们可以用允许我们对文本进行数学运算的方式来表示文本。我们可以这样说,数字 2 更接近于 3 而不是 10,它们之间的距离都更接近于 100。如果我们能够以这种方式对一个文档的全部含义进行编码,我们就可以使用这些属性来寻找文档之间的相似性,将它们分组到有意义的簇中,等等。

在大多数情况下,机器“学习”这种表示的方式是给它们大量的文本阅读,并敦促它们学习哪些单词或句子“放在一起”。著名的:

交的朋友就知道一个词——弗斯,J. R

一些陷阱和拯救变形金刚

早期的文本嵌入工具通常只能捕获单个单词(Word2Vec、GloVe 等),然而,对于短语可能与其中的单词有不同含义的例子,这仍然是个问题。“自然”和“灾难”放在一起意味着完全不同的东西。最近自然语言处理的进展,已经产生了一批上下文嵌入模型,如【ELMo】BERT等。(这里有一个很好的概述)。然而,通常这些都是预先训练好的工具,仍然需要针对特定任务进行微调。这样的任务可以是:句子情感识别、句子相似度、问答等。Huggingface 的 变形金刚库使得这些工具的使用变得非常容易。

野兔,我们将使用句子转换器——这是一个 Python 库,它(除其他外)为我们带来了 SBERT 模型,这些模型为句子语义相似性的任务进行了预训练,允许我们比较整个句子的意思。(一定要看看的论文。这是我们所做工作的关键使能因素,因为如果没有强大的文档级嵌入(在这种情况下,新闻标题就是文档),我们就无法在查询和搜索的文档之间提取有意义的比较。注意,SBERT 不是唯一的方法,其他的方法也可以,例如使用推断等等。此外,这种搜索方法试图将查询与查询中提到相似单词的结果进行匹配。在这种情况下,它类似于关键字搜索,即寻找使用相同查询词的文档,但不取代“问答”,即我们寻找某个问题的特定答案。

现在…真正的赛马…

在这里,我将比较我们并排查询这两种方法得到的结果。我将试着比较这些差异,并从中得出一些结论。

请注意,类似任务的更正式的评估IR-BERT 中完成(任务是找到给定(查询)文章的最佳支持文章,任务 1 在此为)。作者证明了上下文方法(SBERT)明显优于纯关键词方法(BM25),然而,当使用更先进的关键词加权技术时,结果是混合的。

首先,在许多情况下,简单的关键字搜索就足够了。考虑搜索“苹果公司”。我们不需要一个语义引擎。因为要寻找的是一个“命名实体”,精确匹配是有意义的,近似匹配可能是完全错误的。在某种程度上,当我们非常明确我们在找什么的时候,在找具体的名字、日期、id 等等。精确匹配可能就足够了。然而,如果我们遗漏了我们需要的确切术语(参见之前的“自然灾害”示例),我们将受益于基于上下文的结果,而不是精确匹配。****

****设置:我在一些查询中并排比较了关键字和上下文搜索的最佳结果。我用绿色突出显示与搜索明显相关的结果,琥珀色——不明确的结果,红色——不相关的结果。请注意,我们使用了一百万个新闻标题——来源于美国广播公司新闻,即新闻有一些澳大利亚的焦点。

病毒威胁

让我们搜索一下“病毒威胁”

作者图片

这两种方法都产生了良好的结果。注意结果#5。“世卫组织强调病媒传染疾病的危险”不包括我们的任何搜索词,但仍然高度相关。以下是上下文搜索结果不包含任何关键字的更多示例。我们看到相关提及:疫情、感染、寄生虫

作者图片

自然灾害

语料库中有大量“自然灾害”的精确匹配,因此在两种搜索形式中,前 10 次提及彼此非常接近。然而,考虑没有与关键字精确匹配的上下文结果。我们可以看到相关的提及,如:洪水、反常风暴、灾难性火灾

作者图片

“监管风险银行业改革”

进一步扩展查询会使事情变得更加复杂。首先,关于查询:这里的问题有点模糊,因为用户显然对银行改革和监管感兴趣,但没有具体说明什么、谁、何时。这可能是在一个更广泛的研究背景下,试图比较和对比案例。因此,一个好的结果(独立于搜索方法)是寻找不同的例子。巧合的是,结果的多样性也是上下文搜索表现更好的 IR-BERT 中考虑的一个指标

作者图片

从上下文结果来看,似乎很明显,主题是银行业,但缩小到监管/改革主题会导致有争议的结果。提到了 RBA(澳大利亚中央银行),但并不总是与监管风险相关,还提到了 皇家委员会 (该委员会正在调查金融服务中的一系列金融不当行为)与金融相关,但并不总是与银行业相关。然而,在关键字搜索方面,尽管缺乏好的文档,但一致返回的文档在查询中至少会有 2 个单词,这似乎经常使结果“语义相关”——只要有几个关键字,结果就可能是相关的。还要注意关键词搜索的可解释性如何帮助我们立即排除一些情况。例如,关键词结果#8“政府互联网监管计划受到批评”——我们确切地知道这是为什么建议,因此可以很快排除它。相比之下,上下文结果# 5“RBA 考虑信用卡附加费的上限”并不清楚为什么模型认为它是一个好的结果

好的和坏的…

与关键字搜索相比,上下文搜索的优点和缺点是什么

赞成的意见

上下文位— 正如我们所见,关键字搜索有时会有局限性。这在做研究或刚开始探索一个主题时尤为重要,因为我们经常不会搜索相关的术语、关键词和实体

并排功能 —在当前设置中,我们可以轻松地在关键字和上下文搜索之间切换。可以进一步做一些工作来使两个结果并排排列。然而,需要一些假设。请注意,关键字搜索也可以用作良好候选项的初始过滤器,以提高解决方案的整体速度。更多关于速度的考虑在第 3 集中。

骗局

可解释性 —我们不能轻易地逆向工程为什么模型决定显示一个特定的结果。在结果中看到我们的搜索词有助于我们清楚地决定是否同意这些结果。这是一个正在进行的研究和开发领域。最近,谷歌发布了一个工具,用于对语境嵌入的可解释性。然而,这里的使用不是一个简单的应用程序,因为我们还需要评估搜索匹配的具体驱动因素。

上下文是与上下文相关的— 谈论语义搜索和意义可以是我们实际寻找的高度特定的领域。例如,我们可能对自己健康背景下的“疫苗”感兴趣,或者作为投资者决定公司支持,或者作为研究人员——寻找试验、方法等的技术细节。这些方面可以通过细化查询来部分解决,但是结果的质量将受到索引中可用文档以及上下文嵌入的训练方式的限制。特别值得关注的是,系统没有配备向用户指示特定领域查询的质量可能很差——它将始终尽职尽责地提供排序结果的列表。实际上,特定领域搜索引擎有助于解决这个问题。一个例子是基于特定领域的文章和研究为 COVID 搜索者提供的专门工具。这类工具的几个例子是 Corona Papers 和 Google 的 COVID Research Explorer ,它们都使用 CORD-19 (特定于 COVID 的研究文章数据库)来将所使用的文本嵌入上下文化

结论

我们已经看到了什么是文本嵌入以及它们如何帮助上下文搜索的概要。

我们用一些对比例子来说明,并看到上下文搜索如何帮助我们找到我们在查询中没有预料到的主题和术语。

最后,我们讨论了这种方法的一些缺点——缺乏可解释性以及特定领域的查询可能不能很好地工作。

剩下的就是展示构建这样一个工具的技术实现和考虑事项——我们将在第三部分中看到

希望这是有用的。感谢您的阅读。如果你想打招呼,请通过 LinkedIn 联系

搜索和替换文本

原文:https://towardsdatascience.com/searching-and-replacing-text-db983d19a184?source=collection_archive---------28-----------------------

Python 中的文本操作

来源

文本操作包括诸如分离字符串、搜索、替换和解析等操作。虽然这些任务中有许多可以使用 python 中的内置字符串方法来完成,但更复杂的操作需要正则表达式。在这篇文章中,我们将讨论如何使用 python 中的正则表达式模块来搜索和替换文本。

我们开始吧!

首先,让我们考虑下面的字符串文字:

text1 = "python is amazing. I love python, it is the best language. python is the most readable language."

假设,出于某种疯狂的原因,我们想用“c++”替换“python”。我们可以使用“str.replace()”方法:

text1 = text1.replace('python', 'C++')

让我们打印结果:

print(text1)

对于更复杂的模式,我们可以使用“re”模块中的“re.sub()”方法。让我们导入正则表达式模块“re”:

import re

假设我们想将以下字符串中的日期格式从“12/01/2017”更改为“2017–12–01”:

text2 = "The stable release of python 3.8 was on 02/24/2020\. The stable release of C++17 was on 12/01/2017."

我们可以使用' re.sub()'方法来重新格式化这些日期:

text2 = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
print(text2)

替换方法中的第一个参数“r'(\d+)/(\d+)/(\d+)'”是要匹配的模式。“\d+”表达式对应于 0–9 范围内的数字字符。第二个参数“r'\3-\1-\2 '”是替换模式。替换模式中的数字指的是模式中的捕获组号。在这种情况下,组 1 是月,组 2 是日,组 3 是年。我们可以使用“group()”、“match()”和“compile()”方法直接看到这一点:

date_pattern = re.compile(r'(\d+)/(\d+)/(\d+)')
date_pattern.match(“12/01/2017”)
print(date_pattern.group(1))
print(date_pattern.group(2))
print(date_pattern.group(3))

编译替换模式还会提高重复替换的性能。让我们编译匹配模式:

date_pattern = re.compile(r'(\d+)/(\d+)/(\d+)')

然后使用替换模式调用替换方法:

date_pattern = date_pattern.sub(r'\3-\1-\2', text2)

我们还可以为更复杂的替换指定一个替换回调函数。例如,如果我们要将“2017 年 12 月 1 日”重新格式化为“2017 年 12 月 1 日”:

from calendar import month_abbr
def format_date(date_input):
    month_name = month_abbr[int(m.group(1))]
    return '{} {} {}'.format(date_input.group(2), month_name, date_input.group(3))print(date_pattern.sub(format_date, text2))

另一个要考虑的有趣问题是如何以不区分大小写的方式搜索和替换文本。如果我们考虑前面的例子:

text3 = "Python is amazing. I love python, it is the best language. Python is the most readable language."

现在,这篇课文中第一句和第二句的第一个单词是大写的。在这种情况下,替换方法将以区分大小写的方式替换文本:

print(text3.replace('python', 'C++'))

我们看到只有小写的“python”被替换了。我们可以使用' re.sub()'通过传递' flags = re 以不区分大小写的方式替换文本。子方法的“IGNORECASE ”:

print(re.sub('python', 'C++', text3, flags =re.IGNORECASE))

我们看到我们得到了想要的结果。我就讲到这里,但是我鼓励你自己去研究代码。

结论

总之,在这篇文章中,我们讨论了如何使用 python 中的正则表达式模块来搜索和替换文本。我们展示了如何使用替换方法重新格式化字符串中的日期,并以不区分大小写的方式替换文本。如果你想学习更多关于 python 中正则表达式的知识,我推荐 Python 指南 的 中的“第二章:字符串和文本”。这篇文章的代码可以在 GitHub 上找到。我希望你觉得这篇文章有用/有趣。感谢您的阅读!

搜索和排序加密数据

原文:https://towardsdatascience.com/searching-and-sorting-encrypted-data-59fc95d961b7?source=collection_archive---------36-----------------------

走向安全的云数据库

Mauro Sbicego 在 Unsplash 上拍摄的照片

假设有一天,你的老板走进办公室,给你一份工作:

老板:我要你对一组数据进行排序

你:好吧!给我意见,我会处理的

老板:我不信任你,我的数据对我来说是合理的

你:如果你不想给我数据,我该怎么分类?

老板:不知道!想办法!这就是我付钱给你的原因😤

如果你没有数据,你怎么能对一组数据进行排序呢?

和大多数隐私问题一样,答案在于 密码术 的秘密。

斯蒂芬·斯坦鲍尔在 Unsplash 上拍摄的照片

关于通用加密的一个词

我想我们所有人,作为程序员,都至少在自己写的软件中使用过一次密码学。有些人可能只是在服务器上启用 TLS,有些人可能编写了特殊的加密软件。在所有这些情况下,您都有一些想要加密的数据。

最常见的加密方案,如 AES、RSA 等。有一个至关重要的特性:它们在语义上是安全的。这是什么意思?嗯,是关于两个人的游戏。

照片由JESHOOTS.COMUnsplash 上拍摄

在这个游戏(称为 IND-CPA 游戏)中,一个玩家是攻击者,另一个是挑战者。游戏如下:

  1. 攻击者选择一些消息,挑战者提供这些消息的密文
  2. 攻击者选择两条相同长度的消息发送给挑战者
  3. 挑战者从两条消息中随机选择一条,加密并发送给攻击者
  4. 如果攻击者猜对了哪条消息被加密,该方案就被破解了

下图说明了这个游戏:

Ryan Henry I 538 /B 609:密码学简介

回到老板的问题

所以你的老板有一些数据,他想排序,但他不想给你看😵

你可能想告诉你的老板在把数据交给你之前先加密。假设数组只包含两个元素: m1m2 。计划如下:

  1. 老板使用某种加密方案对这两个元素进行加密,得到两个密文: c1c2
  2. 你比较一下 c1c2。如果 c1 < c2 你告诉你老板,排序后的数组是[ m1m2 ]。否则你告诉你老板,排序后的数组是[ m2m1 ]。

为此,你需要一个保序的加密方案。

也就是说,该方案保留了明文的顺序。举个例子,如果 c1m1 的加密, c2m2m1 < m2 的加密,那么 c1 < c2

如果你正在考虑一个共同的加密方案,如 AES 或 RSA,它不会工作。为什么?记住所有这些方案都是语义安全的。

如果你能比较两个密文,并推断出明文的顺序,你就能打破 IND-CPA 游戏。

方法如下:

游戏第一步,你会选择两条消息 m1m2(m1<m2)。挑战者将返回两条消息的密文: c1c2 。然后,在步骤 2 中,您将向挑战者发送在第一步中选择的相同消息( m1m2 )。挑战者将返回一个密文 c ,该密文将是 m1 的加密或 m2 的加密。如果 c 是对 m1 的加密,那么 c < c2 如果 c 是对 m2 的加密,那么 c > c1

因此,您不能使用 AES、RSA 或任何其他众所周知的加密方案。那你应该用什么呢?

Boldyreva 的加密方案是您的正确答案

如果你想了解更多可以阅读原文 这里

现在,让我们开始工作,实现加密数据的排序和搜索。

照片由 Corinne KutzUnsplash 上拍摄

在 python 中排序和搜索加密数据

Boldyreva 的方案已经在 pyope 库中实现。因此,让我们导入库:

要使用该方案,我们必须首先生成密钥并实例化密码:

让我们用一个简单的数组来排序它:

为了加密这个数组,我们需要在 simple_array 的每个元素上调用密码对象的加密方法T3:

只需对列表进行排序:

现在您已经对数组进行了排序,让我们解密它,并验证原始元素是否按升序排列。为此,您需要在simple _ array _ encrypted:的每个元素上调用 cipher 对象的 decrypt 方法

你应该看到[1,2,3,4,7]。

如果你的老板给你一个加密的元素,并询问它是否存在于他给的加密数组中,你只需从 numpy 库中调用search sorted函数即可:

您应该看到 2。

结论

恭喜你!你刚刚意识到了不可能。

威尔·斯图尔特在 Unsplash 上拍摄的照片

您能够在不知道元素本身的情况下对元素列表进行排序和搜索。保序加密和揭示序加密是密码学中非常活跃的研究领域。这些加密方法有许多应用,尤其是在数据库领域。随着数据量的增加,通过个人资源维护数据库变得越来越困难。你需要把你的数据放到云中。然而,没有必要以清晰的形式给出你的数据。你可以使用像保序加密这样的东西,首先加密你的数据,然后把它发送到云端。加密方案允许您继续使用数据库,即使数据一直被加密。这就是密码学的美妙之处,❤️.

感谢您的阅读😊

另外,我为你准备了一个 colab 笔记本,上面有所有代码。你可以从这里进入。

在 SQL Server 中搜索数据库对象和表数据

原文:https://towardsdatascience.com/searching-for-database-objects-and-table-data-in-sql-server-f42f7e3e76a1?source=collection_archive---------46-----------------------

让我们来看看 SQL Server 中数据库数据和对象搜索的复杂性,并看看如何使用标准脚本和特定工具来执行它。

图片来自 Piqsels (CC0)

您好,欢迎来到我的系列文章的第四部分,它将帮助您了解如何设计和使用数据库。这一次我们将深入研究 SQL Server 中复杂的数据和对象搜索问题,这将首先在标准脚本的帮助下进一步进行,然后使用 dbForge 搜索工具

我们经常会遇到这样的情况,我们需要找到:

  1. 数据库对象(表、视图、存储过程、函数等)。).
  2. 数据(值和包含它的表)。
  3. 数据库对象定义中的代码片段。

使用标准脚本在 SQL Server 中搜索数据和对象

让我们首先展示如何在标准脚本的帮助下做到这一点。
您可以使用以下脚本在数据库中搜索雇员表:

select [object_id], [schema_id],
                  schema_name([schema_id]) as [schema_name],
                  [name],
                  [type],
                  [type_desc],
                  [create_date],
                  [modify_date]
from sys.all_objects
where [name]='Employee'

脚本的结果将如下所示:

Img.1 .雇员表的搜索结果

它显示:

  1. 对象的标识符和对象所在的架构。
  2. 架构的名称和对象的名称。
  3. 对象类型和描述。
  4. 创建和修改对象的日期和时间。

要查找“项目”字符串的所有条目,可以使用以下脚本:

select [object_id], [schema_id],
           schema_name([schema_id]) as [schema_name], 
           [name], 
           [type], 
           [type_desc], 
           [create_date], 
           [modify_date] 
from sys.all_objects 
where [name] like '%Project%'

结果将是下表的输出:

Img.2 .跨所有数据库对象的“项目”子字符串的搜索结果

如结果所示,“Project”字符串不仅包含在 Project 和 ProjectSkill 表中,还包含在一些主键和外键中。

要了解哪个表包含这些键,让我们通过执行以下操作将 parent_object_id 字段、其名称及其所在的模式添加到输出中:

select ao.[object_id], ao.[schema_id],
          schema_name(ao.[schema_id]) as [schema_name],
          ao.parent_object_id,
          p.[schema_id] as [parent_schema_id],
          schema_name(p.[schema_id]) as [parent_schema_name],
          p.[name] as [parent_name],
          ao.[name],
          ao.[type],
          ao.[type_desc],
          ao.[create_date],
          ao.[modify_date] 
from sys.all_objects as ao 
left outer join sys.all_objects as p on ao.[parent_object_id]=p. [object_id] 
where ao.[name] like '%Project%'

结果将是带有父对象详细信息的表输出,这意味着,在指定主键和外键的地方:

Img.3 .包含父对象详细信息的所有数据库对象中“项目”子字符串的搜索结果。

查询中使用了以下系统对象:

  1. sys.all_objects 表。
  2. schema_name 标量值函数。

您可以通过这个解决方案找到所有数据库表中的字符串值。让我们简化这个解决方案,并展示如何用下面的脚本找到值“Ramiro”:

输出可能如下所示:

Img.4 .数据库搜索结果

这里,输出显示了表的名称,哪些列存储了包含子串“Ramiro”的值,以及找到的匹配表列的该子串的输出数。

要查找其定义包含给定代码片段的对象,可以使用以下系统视图:

  1. sys.sql_modules
  2. 系统所有 sql 模块
  3. sys.syscomments

例如,使用最后一个视图,您可以在以下脚本的帮助下找到其定义包含给定代码片段的所有对象:

select obj.[object_id], 
            obj.[name], 
            obj.[type_desc], 
            sc.[text] 
from sys.syscomments as sc 
inner join sys.objects obj on sc.[id]=obj.[object_id] 
where sc.[text] like '%code snippet%'

这里,输出显示了对象的标识符、名称、描述和完整定义。

使用 dbForge Search 搜索数据库数据和对象

借助现成的便捷工具,搜索数据和对象要方便得多。其中一个工具就是 dbForge Search

要调用此工具,请在 SSMS 窗口中按 dbForge 搜索。将出现搜索窗口:

Img。5 dbForge 搜索的搜索窗口

请注意顶部面板(从左到右),因为您可以更改:

  • 搜索模式(搜索 DDL(对象)或数据)。
  • 我们实际搜索的内容(哪个子串)。
  • 区分大小写,搜索单词的精确匹配,或搜索字符串条目。

Img.6 .搜索模式

您还可以:

  • 使用顶部中间的按钮(由花括号连接的两个正方形)按对象类型对结果进行分组。
  • 为搜索选择必要的对象类型:

Img.7 .为搜索选择对象类型

  • 为搜索设置几个数据库,并选择一个 MS SQL Server 实例

这是对象搜索模式,即包括 DDL 时:

Img.8 .按 DDL 对象搜索

在数据搜索模式中,唯一不同的是对象类型选择:

Img.9 .按数据搜索

也就是说,只有存储数据的表可供选择:

Img.10 .选择用于数据搜索的表格

现在,和以前一样,让我们在对象名中找到所有“项目”子串条目:

Img.11 .数据库对象名称中所有“项目”字符串条目的搜索结果

显然,搜索模式是由 DDL 对象设置的,我们正在寻找“项目”字符串,所以它是填充的,其他一切都是默认的。

当选择检索到的对象时,您可以在下面看到给定对象及其父对象的定义代码。

此外,您可以通过按下下面显示的按钮将导航切换到检索到的对象:

Img.12 .将导航转移到检索到的对象

您也可以按类型对找到的对象进行分组:

Img.13 .按类型分组的对象进行搜索的结果

请注意,甚至包含名称中包含“Project”子字符串的字段的表也会显示出来。但是,让我提醒您,搜索模式是可以改变的:搜索整个匹配或部分匹配,区分大小写与否。

现在,让我们找出所有表中的“Ramiro”值:

Img.14 .跨所有数据库数据的“Ramiro”子字符串的搜索结果

请注意,将显示所选 Employee 表上包含“Ramiro”子字符串的所有字符串。

此外,您可以像之前一样,通过按下下面显示的按钮将导航切换到找到的对象:

Img.15 .将导航转移到找到的对象

因此,我们可以在数据库中搜索所需的对象和数据。

结论

简而言之,从创意到实现招聘服务数据库,我们走过了漫长的道路。让我们总结一下到目前为止我们所取得的成就:

就这样,数据库已经准备好可以使用了,在测试运行之后,它可以被集成,并且它将存在。那么下一步是什么?稍后,我们将需要维护数据库,并在需要时引入更改。

另请阅读:

  1. SQL 数据库设计基础及示例
  2. 用测试数据填充员工数据库
  3. 导出和导入 JSON 数据

原载于 2020 年 8 月 11 日https://blog.devart.com

在 SQL Server 数据库中搜索无效对象

原文:https://towardsdatascience.com/searching-for-invalid-objects-in-the-sql-server-database-a90fab49a66a?source=collection_archive---------43-----------------------

本文旨在解决在 SQL Server 数据库中查找和修复无效对象的问题。

图片来自 Piqsels (CC0)

本文讨论数据库开发人员和管理员工作中的一个瓶颈,即无效对象的出现以及在 SQL Server 数据库中找到它们的方法。

在之前的文章中,我们涵盖了从创意到实现招聘服务数据库的所有过程:

如何使用 SQL Complete 查找无效对象

让我们在 SQL Complete 工具的帮助下查看无效对象的搜索。假设我们用雇员的地址定义了一个新表,并将其命名为 Address:

员工可能有不同的地址。同时,几个雇员可以有相同的地址。因此,这些实体之间的关系是多对多的:

Img.1 .雇员和地址之间的关系

我们不考虑每个雇员只有一个指定地址的居住登记情况。我们对所有地址都感兴趣,包括那些指定员工倾向于在哪里度过时间(他居住和睡觉的地方)的地址。这样的地方可能有几个。

现在,让我们创建一个 vEmployeeAddress 视图,以如下方式显示雇员的数据和地址:

问题是我们忘记了更改 vAddressEmployee 视图,它现在引用了不存在的表。

不久之后,一个用户或者如果我们幸运的话,一个测试人员发现了一个问题,每当调用 vAddressEmployee 视图时,系统的一部分功能就会崩溃。

为了避免这种情况,每次将更改引入数据库时,我们都需要检查是否存在无效对象。

为此,选择您需要的数据库,在 SSMS 的菜单栏中,选择 SQL Complete\Find Invalid Objects 命令:

Img.2 .在 SQL Complete 中选择“查找无效对象”命令

在出现的窗口中,单击窗口左上角或中间的“分析”按钮:

Img.3 .运行无效对象的搜索

请注意,您可以在“数据库”面板上一次选择多个数据库:

Img.4 .选择多个数据库

对无效对象的搜索完成后,我们可以看到显示 vAddressEmployee 视图的结果,该视图引用了不存在的表 AddressEmployee 和 Address:

Img.5 .搜索无效对象的结果

考虑到地址在雇员表中,重写 vAddressEmpoyee 视图就足够了,如下所示:

ALTER VIEW [dbo].[vAddressEmpoyee] AS
SELECT emp.[EmployeeID]
      ,emp.[FirstName]
      ,emp.[LastName]
	  ,emp.[EmployeeID] AS [AddressID]
	  ,emp.[Address]
  FROM [JobEmpl].[dbo].[Employee]		 AS emp
GO

完成后,当您第二次搜索无效对象时,将找不到它们:

Img.6 .未找到任何无效对象

请注意,AddressID 列根本不应该显示在 vAddressEmployee 视图中。但是,如果系统使用它,我们需要以两种方式确定变化的过程:

  1. 如果该字段仅用于提供信息,而不用于搜索相同的地址,是否可以用 EmployeeID 中的值替换 AddressID。
  2. 是否可以完全不显示 AddressID。

如果执行第一点失败,我们将不得不在应用程序的逻辑中引入变化,同时执行第二点。

然而,如果第一点是可行的,这将是一个快速解决问题的方法,您可以稍后通过一个修补程序或下一个更新来执行第二点。

简而言之,我们已经考虑了找到无效对象并修复它们的重要性。

结论

总之,我们研究了为招聘服务创建数据库的整个过程,从想法开始,到在生产中实现,并对模式进行进一步的修改。

给定的数据库允许我们执行快速搜索,并根据以下指标汇总数据:

  1. 用人公司。
  2. 位置。
  3. 项目。
  4. 技能。

值得一提的是,这个模式为 IWU 团队的创业提供了基础。

原载于 2020 年 8 月 11 日【https://blog.devart.com】

基于 Python 中的属性对对象列表进行搜索或排序

原文:https://towardsdatascience.com/searching-or-sorting-a-list-of-objects-based-on-an-attribute-in-python-6cffb26a57c3?source=collection_archive---------8-----------------------

当你想找出哪个(狗)学生和其他(狗)学生的数量最多时

通常,当您有一组对象时,您可能不希望根据它们在内存中的位置,而是根据感兴趣的属性对它们进行排序。今天,我们将看看 Python 的内置工具:operator.attrgetter,以及这个工具包中的相关工具和实现类似目标的替代方法(使用 lambdas 和迭代器/理解)。

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

对于我们今天的数据集,我们将使用一个由 100 只狗组成的虚拟数据集。狗学生类有属性:nameyrstrengthsareas_for_growthworks_well_withnot_works_well_withhas_sat_byhas_not_sat_bynotes。它有添加、获取、移除和这些属性的方法,加上返回各自列表中朋友/敌人数量的get_n_not_works_wellget_n_works_well

如何使用 attrgetter

Attrgetter 是一个属性 getter。您可以通过几种方式使用它:

  1. 您可以创建一个 attrgetter“可调用对象,该对象从其操作数中获取 attr ”(从文档)属性。
from operator import attrgetterfriend_getter = attrgetter('works_well_with')
print(friend_getter(dog_pack[1]))

这里,friend_getter 返回 dog_pack[1]的works_well_with列表:

[Student('Qeb', 12), Student('Putty', 6), Student('Douglas', 3), Student('Denali', 5), Student('Asher', 12), Student('Portia', 3), Student('Suki', 2), Student('Olive', 14), Student('Peri', 8), Student('Mari', 5), Student('Snowflake', 2), Student('Guayaba', 12)]

我仍在寻找你会在dog_pack[1].works_well_with上这样做的背景。我们将在下面看到我遇到的一个例子,但我不确定我是否被说服了。

马特·尼尔森在 Unsplash 上拍摄的照片

2.可以将 attrgetter 用于需要函数参数的函数。比如作为 sorted()、max()、min()的键;或者用 map()、itertools.groupby()等。

要得到最老的狗:

# to get the object with the characteristic (max yr)
oldest = max(dog_pack, key=attrgetter("yr"))
print(f"Oldest Dog\nname: {oldest.name}\nage: {oldest.yr}", 
      f"Strengths: {oldest.strengths}")

打印:

Oldest Dog
name: Abbey
age: 15
Strengths: ['snuggly', 'snuggly', 'plays well', 'fetch']

这里我们实际上有多个最老的狗,所以我们想使用过滤/条件列表理解来获得最老的狗的列表:

[d for d in dog_pack if d.yr == max(d.yr for d in dog_pack)]

返回

[Student(Abbey, 15),
 Student(Radar, 15),
 Student(Pinot, 15),
 Student(Lucci, 15),
 Student(Leona Mae Alcott Helmsley Cole, 15),
 Student(Stella, 15),
 Student(Whiskers, 15)]

不要忘记,如果我们想要值本身,而不是带有值的对象,就没有必要使用attrgetter

max(d.yr for d in dog_pack)

它返回15

Bharathi KannanUnsplash 上拍摄的照片

方法的 Attrgetter:方法调用方

Methodcaller 的工作方式与 attrgetter 非常相似,但是当您希望使用类的“方法”而不是“类”属性的返回时。

例如,如果我想让狗学生与最少的其他学生一起工作:

min_works_well = min(dog_pack, key=methodcaller('get_n_works_well'))print(f"""Works Well With The Fewest Dogs
          name: {min_works_well.name}
          works well with: {min_works_well.get_n_works_well()} dogs
          strengths: {min_works_well.strengths}
          areas for growth: {min_works_well.areas_for_growth}""")

返回:

Works Well With The Fewest Dogs
name: Pringles
works well with: 4 dogs
strengths: ['leave it', 'snuggly', 'comes when called']
areas for growth: ['playing with others']

attrgettermethodcaller的另一个区别是,对于attrgetter,附加参数是要获取的附加属性,而对于methodcaller,它们是作为参数传递给方法的。

照片由 gotdaflowUnsplash 上拍摄

其他数据结构的 attr getter:item getter

attrgetter作用于类,而itemgetter作用于其他数据结构(列表、元组、字典等)。

如果我们的 dog_pack 被构造成一个字典列表:

oldest = max(dogs_dict_list, key=itemgetter('yr'))print(f"Oldest dog\nname: {oldest['name']}",
      f"strengths: {oldest['strengths']}")

itemgetter使用“yr”作为关键字并返回:

Oldest dog
name: Dollie
strengths: ['plays well', 'ignores food on the sidewalk']

如果它被构造成这样的元组列表:

dogs_tups = [('Bella', 5, 'labrador', 'yellow'), 
             ('Dollie', 12, 'austrailian sheppard', 'cream, brown')]youngest = min(dogs_tups, key=itemgetter(1))print(f"Youngest Dog:\nname: {youngest[0]}\nbreed: {youngest[2]}")

itemgetter将使用参数 1 作为索引并返回

Youngest Dog:
name: Bella
breed: labrador

attrgetter一样,itemgetter在提供多个参数时返回一组查找值。

卡米洛·菲耶罗在 Unsplash 的照片

获取子属性

如果你想对我们的狗进行分类,不是根据这些一级属性中的一个,而是根据属性的一个组成部分,我看到了四个选项:

  1. 如果属性是一个类,你可以通过将第二个属性名和第一个属性名一起传递给attrgetter来访问你的属性的一个属性。例如,如果我们改变 name 属性来创建类名的一个实例,我们可以像在 docs 示例中一样,用sorted(dog_pack, key=attrgetter("name.first")按名字排序。
  2. 如果你可以访问这个类,或者这个类有一个方法返回你感兴趣的子属性,你可以使用methodcaller来访问/排序这个子属性。
from operator import methodcallersorted(dog_pack, key=methodcaller("get_area_for_growth", 0))

这里的growth_sorted是一个列表,按照它们的第一个成长领域排序(按字母顺序)。

再次注意,methodcaller 向该方法传递附加参数。这与 attrgetter 不同,在 attr getter 中,额外的参数被作为额外的属性来读取,支持多属性键。对于带有 methodcaller 的多属性键,您需要一个 lambda 函数。

3.使用 lambda 或定义的函数。

sorted(dog_pack, key=lambda x: (x.get_area_for_growth(0),
                                x.name.first)

或者相当于:

def first_growth_first_name(x):
    "Returns the first area for growth and first name of Dog x" first_growth = x.get_area_for_growth(0)
    first_name = x.name.first
    return (first_growth, first_name) sorted(dog_pack, key=first_growth_first_name)

4.组合 lambda 和 attrgetter/methodcaller。

sorted(dog_pack[0:5], key = lambda x: attrgetter("strengths")(x)[0])

这个例子对我来说很复杂,它依赖于群体中的每只狗在那个位置的力量。但在某些情况下这可能是正确的做法。与lambda和直接属性访问相比,我不确定attrgetterlambda组合的相对计算时间。

Anoir ChafikUnsplash 上拍摄的照片

attr getter/item getter/method caller 与 lambda

内置函数似乎运行得更快,这对您的场景来说可能重要,也可能不重要。互联网上的人们似乎不同意哪个更优雅/更漂亮/更漂亮。字符串的使用阻碍了许多代码编辑器的自动完成功能,这需要键入/拼写/知道他们想要什么属性。不理想。对我来说不是交易破坏者。

这些都可以很容易地用 lambda 函数(或定义的函数)来代替:

attrgetter

按年份和名称对我们的狗群进行分类:

sorted(dog_pack, key=attrgetter(“yr”, "name.first"))成为

sorted(dog_pack, key=lambda x: (x.yr, x.name.first))

itemgetter

dogs_tups = [('Bella', 5, 'labrador', 'yellow'), 
             ('Dollie', 12, 'austrailian sheppard', 'cream, brown')]

将这些狗元组按品种分类:

sorted(dogs_tups, key=itemgetter(2)成为

sorted(dog_pack, key=lambda x: x[2])

方法调用程序

根据狗狗们玩耍的数量对狗群进行分类:

sorted(dog_pack, key=methodcaller(“get_n_works_well”))变成了

sorted(dog_pack, key=lambda x: x.get_n_works_well())

何时使用 lambda、自定义函数或理解

如果您需要在排序/获取最大值/最小值/无论什么之前处理属性数据,那么您可能需要使用attrgetter的替代方法。

例如,最初,我的狗的名字有不规范的大写。如果您没有访问该类的权限,可以使用以下方法进行更正:

sorted(dog_pack, key=lambda x: x.name.first.lower())

或者如果你正在寻找名字以 A 开头的狗:

[d for d in dog_pack if d.name.first.lower() < 'b']

点击查看 GitHub 库。编码快乐!

照片由 allison christineUnsplash 上拍摄

在云中搜索无服务器 GPU

原文:https://towardsdatascience.com/searching-the-clouds-for-serverless-gpu-597b34c59d55?source=collection_archive---------31-----------------------

一个未完成的任务?

泰勒·范·里佩尔在 Unsplash 上的照片

无服务器是云计算的一大趋势。关注代码,而不是基础设施,对于许多开发人员(或者像我这样的数据科学家)来说是一件非常简单的好事。此外,如果您不喜欢为闲置的服务器付费,那么现收现付的定价模式是非常好的。同时,人工智能(主要是深度学习)的快速发展极大地增加了对 GPU 作为计算密集型任务加速器的需求。鉴于 GPU 价格昂贵,将其放在无服务器架构中不是很好吗?是的,那太好了!

我的使用案例

对于一个爱好项目,我一直在开发一个简单的应用程序,它提供了一个神经类型转移的用户界面。不熟悉这种技术?简而言之,神经风格转移(NST)是一种深度学习技术,可用于风格化图像。该算法将内容图像样式图像作为输入,并使用它们来生成显示内容图像的内容和样式图像的样式的新图像。明白了吗?如果你想更深入地了解 NST,请查看这篇文章,这篇文章很好地解释了它!

现在回到我的爱好项目。我开发的应用程序允许用户在一个简单的图形用户界面中选择内容图像和样式图像,并通过单击按钮生成风格化的图像——简单明了。

该应用程序在我的本地环境中运行良好。现在,我很想在网上发布这个应用程序,这样每个人都可以访问并使用它来创建自己的人工艺术。由于它仍然是一个爱好项目,我想以一种经济高效的方式来做这件事。为了实现这一点,我想在一个无服务器平台上运行 NST 算法;这样,我只会在用户积极使用应用程序时付费。哦,是的,我想在 GPU 上运行该算法,这样一幅图像就可以在一瞬间生成,用户不必像 CPU 支持的计算那样等待几秒钟。

关于我的用例,我想我们已经明白了为什么无服务器 GPU 有时会派上用场。现在让我们看看市场上有什么!

GPU 显卡——Rafael Pol 在 Unsplash 上拍摄的照片

云提供了什么

在我寻找无服务器 GPU 的过程中,我了解了很多目前可用的不同无服务器选项。让我与你分享这些发现。

功能即服务

无服务器框架已经存在了很长一段时间,所有主要的云提供商都提供了一个成熟的功能即服务(FaaS)平台:AWS 有 Lambda ,Azure 有功能应用,Google 有云功能 ( 这里有一篇比较三者的文章!).到目前为止一切顺利。但是,如果我们想在 GPU 上运行我们的无服务器计算,而不是在传统的 CPU 上呢?太糟糕了!不可能。这里提到的三个 FaaS 平台都不支持 GPU 支持的服务器。在撰写本文时,我们只能依靠 CPU 来利用 Lambda、函数应用程序或云函数。

人工智能平台

谷歌云将他们的人工智能平台描述为一种轻松“将你的机器学习项目投入生产”的方式。它目前提供三种补充服务:

  • AI 平台笔记本
  • AI 平台培训
  • AI 平台预测

因为在我的例子中,我已经有了一个经过训练的 AI 模型(具体来说是 TensorFlow SavedModel),所以我在这里的重点将是预测服务。我的目标是为我的人工智能模型服务,根据用户输入推断新的值。人工智能平台预测在这方面应该是完美的,因为它的建立正是为了做到这一点:为现有模型获得新的预测。这是一个无服务器的平台,所以我们不必担心基础设施或为闲置的服务器付费。好消息是,它在一些可用的机器类型上支持 GPU(甚至 TPU )!

嗯,任务完成了,你可以这么想!我唯一要做的事情就是将我的模型部署到平台上,然后继续我的在线预测。然而,因为我们生活在现实世界中,当然有一些如果和但是。在这种情况下,一些技术细节被证明是不可逾越的。不涉及太多细节,它与输入大小的限制和对库的有限版本支持有关。我现在的结论是,由于这些问题,目前不可能在我的场景中使用人工智能平台预测。

无服务器容器

我探索的第三种选择是无服务器容器服务。我研究得相当透彻的一个是谷歌云运行。云运行“抽象出所有基础设施管理”,因此您可以轻松地将您的容器部署到生产中。因为它是按使用付费的,你只在你的代码运行时付费。太棒了。

许多集装箱——由 Guillaume BolducUnsplash 上拍摄

当你意识到云运行也只有对 CPU 的支持时,失望来了。如果您选择完全管理选项,至少情况是这样。还可以选择在 Kubernetes 集群上运行容器,这为您的基础设施提供了充分的灵活性,并支持使用 GPU。这种方法的缺点是您需要维护(并支付)您的集群,从而消除了无服务器的两个主要好处!因此,Kubernetes 上的云运行对我来说不是一个有吸引力的选择。

除了 Google Cloud Run,还有用于在无服务器框架上运行容器的 AWS FargateAzure 容器实例。我还没有仔细研究这些替代方案,尽管从表面上看,它们本质上与 Google Cloud Run 非常相似,因此对我的用例同样不满意。

超越三巨头

你有时会忘记,除了云计算的“三巨头”:AWS、Azure 和 Google Cloud,还有更多值得探索的东西。在谷歌上简单搜索“无服务器 gpu”,你会很快找到像 nuclio 这样的公司。他们自称是“第一个支持 GPU 优化利用和共享的无服务器平台”。我不知道你怎么想,但我觉得这听起来不错!然而,nuclio 似乎不像三大巨头那样提供自助服务环境。他们的目标似乎是更大的企业,而不是像我这样的私人客户。所以有一个障碍使得他们的服务不适合我。

包装它

所以我在这里,暂时结束了我对无服务器 GPU 的搜寻。我的结论是,目前,在撰写本文时,没有简单的方法在 GPU 加速的无服务器平台上部署 AI 模型。由于云计算的发展速度非常快,我毫不怀疑这一市场空白将在短时间内被填补。我决定耐心等待,同时让自己忙于其他项目和冒险!

如果我错误地提出了错误的主张,或者遗漏了重要的东西,请告诉我。当然,我也很高兴听到你是否知道在哪里可以找到无服务器的 GPU!

分割东京的 Airbnb 社区:调查周围环境

原文:https://towardsdatascience.com/sectioning-airbnb-neighborhoods-in-tokyo-survey-the-surroundings-31edd55b37d9?source=collection_archive---------20-----------------------

您下次去东京时打算住在 Airbnb 吗?瞥一眼周围是什么样子,看看其他类似的区域。

前言

Despite rising tension with the government authority in recent years, Tokyo has been a growing market for property owners renting out their space for the public; 民泊 or minpaku as they would call in Japanese. Airbnb, just as in other major cities, is among the popular platforms to find one, especially for foreigners who possess little or no local language understanding.

当到达 Airbnb 时,人们往往会想知道附近有哪些好景点。隐藏的被低估的寿司店,正宗的当地拉面摊,或者那些“可语法化的日式咖啡馆”正等着被发现。快速的谷歌搜索就可以了,但是如果我们能在预订之前就探索在哪个地区有什么样的地方呢?还是找出特色相似但花费较少的地区?我们也许可以节省更多的时间来决定去哪里,甚至更好地计划我们的旅行。这个照明项目旨在回答这个问题。它不仅针对旅行者,也可能对那些有兴趣在附近经营住宿或相关业务的人有用,甚至对那些考虑住在世界上人口最多的大都市并想知道社区是什么样子的人有用。

准备数据

Inside Airbnb 拥有世界上任何 Airbnb 城市中更新最多的数据库之一,而且是免费的;感谢他们的抓取工具成功地从 Airbnb 网页相对复杂的 HTML 结构中提取文本。仅获取必要的分析数据后,由 13367 个列表(截至 2019 年 11 月)组成的数据将如下所示:

数据集 1:东京 Airbnb 房源

然后我汇总数据,找出每个街区的房源数量、平均价格和经纬度坐标。为了增加一些趣味,我在东京维基百科的特殊选区页面上做了一个快速的漂亮的图片抓取,这个页面包含了该市 23 个行政区的人口和面积数据。

数据集 2:每个邻域的聚合属性

随后,基于坐标,我使用 Foursquare API 检索了步行距离半径(小于 1 公里)内每个区域的最多 100 个推荐地点。有些区域可能不如其他区域集中,因此周围的斑点较少。我发现看到获得的结果很有趣,因为我不知道周围一些相当不错的地方,尽管我在这个地区生活了多年。下面显示的是收集的 2216 条记录的前几行。我们会在场地类别上查找更多信息,以浏览周围环境并回答项目问题。让我们开始进一步的分析。

数据集 3:每个邻近区域的推荐景点列表

视察社区

简要检查

下面的图表总结了所有的信息,让我们一瞥病房之间的比较。我正在使用 Plotly 进行可视化,所以你可以随意在周围徘徊。

注:圆圈的大小表示人口数量。x 轴是对数刻度。

总体而言,东京房源平均每晚花费12000 ~ 15000 日元(110~140 美元)。这与世界其他主要城市的平均水平相当或低于平均水平,但由于今年夏天奥运会前需求的上升,实际上从去年开始变得越来越贵。

面积和人口似乎有很好的相关性,因为练马、足立江户川太田的大小和颜色大致相同。有趣的是,Bunkyo 是最贵的病房,尽管它在列表数量上排名倒数第三。此外,尽管在人口和面积上与两个最便宜的地区不相上下,江户川的价格还是出现了飙升,这可能是因为它很容易到达东京迪士尼度假区和市中心。5 离群值很容易识别,因为有 1000~个列表;这似乎有一个明显的原因,我们将在接下来的几行中看到。

你可能想知道东京的 Airbnb 房源大多集中在哪里。这是一张地图,显示了公寓的位置(半径越小意味着花费越少)和标记图标所指的 23 个特殊病房。

大致有 3 大组和几个较小的上市集群。位于中野标志 4 点钟位置的是新宿区,这里是日本最繁忙的地区,也是东京约 17%的房源所在地。拥有城市的中央车站和许多景点可能是出租公寓聚集在那里的主要原因。稍微往北一点,我们可以看到第二个拥挤的区域——丰岛——著名的池袋区的所在地。它是连接东京和邻近郊区的主要枢纽之一,也是生活便利的地区之一。最后一个团位于台东隅田基地的东侧。必须参观的浅草真宗寺和东京晴空塔每天都会吸引大量游客。我对周围的环境不太熟悉,但我听说由于合理的租金和不断改善的基础设施,越来越多的人来到这里居住。

将病房分组

在数据集 3 中,有 242 个独特的类别,其中“便利店”、“拉面餐厅”、“日本餐厅”(你不要说)、“咖啡馆”和“清酒吧”名列榜首。诸如“井”、“白俄罗斯餐馆”和“十字路口”之类的随机类别也出现在列表中。

为了弄清楚社区是什么样子,我列出了每个区最常见的场所类别,然后使用相对频率值进行细分。聚集表是一个稀疏的 23×243 矩阵。

这一次,我将只使用 k-means 聚类算法来查找相似的邻域组,因为它对于无监督的任务来说是常见且强大的。我在考察了肘法和剪影评分后选择 4 作为 k 的最佳数。数据集 2 中的其他要素不包括在拟合模型中,以避免人口统计和空间噪声。但是它们在比较聚类之间的差异时非常有用,如下表所示:

第一个和第二个集群看起来像这样,

这是剩下的第三和第四个。

对于那些不熟悉东京的人来说,仅仅从上面的表格中很难看出地理模式,所以下面的精确可视化可能会有所帮助。

我们仅从基础地理空间数据、Airbnb 列表和 Foursquare 的相对较小的数据集观察到有趣的发现。在简单检查部分,你可以有一个大的图片,哪一个社区适合你的需要。例如,如果你想住在公共区域的一个地方,并愿意收取高于平均水平的费用,将你的过滤搜索设置为列表数量最多的 5 个病房之一。或者那些为了更便宜的租金而牺牲更多的交通和通勤时间的人可能会在 Nerima 和 Adachi 附近找到适合他们的地方。

聚类结果也出乎意料的好。在没有将地理坐标数据放入 k-means 拟合中的情况下,结果似乎找到了形成将邻域与其空间上接近的对应物分组的线段的方法。如果我可以包括我自己的领域知识,集群 1 由郊区组成,集群 2 代表对旅行者友好的区域,集群 3 似乎是全才(商业、购物、旅游),集群 4 基本上是随机。进一步来看,每个集群的特征如下:

  • 集群 1:房源少,价格低,人口多,面积大,便利店占主导
  • 集群 2:很多上市,平均价格,游客的热门停留区域,拉面餐厅和酒吧是最常见的
  • 集群 3:房源多,价格高,人口少,面积小,场地多样
  • 集群 4:房源少,价格平均,混合了普通住宅、学生和游客的住宿区

附言

当预订 Airbnb 或其他租赁住宿时,了解其特点和周围环境可能会很有用。通过考虑位置、平均价格和/或人口密度,你可以知道哪些社区适合或不适合你的偏好。像新宿、涩谷、池袋、上野和浅草这样的热门地区是出租公寓集中的地方。然而,不太出名的街区也值得一试,而且花费相对较少;也许你会发现隐藏的宝石和沿途的当地经历。数据显示,日本首都可以分为 4 个区域。郊区?旅行者之群?全能区?还是一般的地区?你喜欢哪一个?

本文是 IBM 数据科学专业证书 应用顶石项目的一部分。

加密数据上的安全协作 XGBoost

原文:https://towardsdatascience.com/secure-collaborative-xgboost-on-encrypted-data-ac7bc0ec7741?source=collection_archive---------61-----------------------

一个使用安全飞地进行多方训练和 XGBoost 模型推理的库

马库斯·斯皮斯克在 Unsplash 上拍摄的照片(已修改)。

TL;DR: 在加州大学伯克利分校的 RISE 实验室,我们一直在构建 Secure XGBoost ,这是一个支持协作XGBoost对加密数据进行训练和推理的库。为了便于使用,我们提供了一个与 XGBoost 几乎相同的 Python API,只是增加了一些集成安全性。Secure XGBoost 是 umbrella MC 项目的一部分,在这个项目下,我们正在开发各种保护隐私的机器学习工具。

特别是,Secure XGBoost 有助于安全的协作学习——相互不信任的数据所有者可以在他们的数据上联合训练一个模型,但不会向彼此透露他们的数据。安全协作学习是一种强大的范式,可能是开启更具弹性和稳健模型的关键。我们一直在与行业中的一些团队合作,包括丰业银行和蚂蚁金服,以部署 Secure XGBoost 来努力实现反洗钱和欺诈检测。

动机

训练机器学习模型需要大量高质量的数据。实现这一点的一种方法是组合来自许多不同数据组织或数据所有者的数据。但是,出于隐私方面的考虑,数据所有者通常不愿意彼此共享他们的数据,这可能源于商业竞争,也可能是法规遵从性的问题。

问题是:我们如何减轻这样的隐私问题?

安全的协作学习使许多数据所有者能够在他们的集体数据上建立稳健的模型,但不会相互泄露他们的数据。银行可以合作开展反洗钱工作,同时保持客户数据的私密性。医疗保健机构可以将他们的患者数据集中在一起,并在医学研究方面进行合作。可能性是巨大的,充满希望的。

安全 XGBoost 简介

作为朝着这个方向迈出的一步,我们很高兴推出 Secure XGBoost ,这是一个支持协作 XGBoost 对加密数据进行训练和推理的库。简而言之,多个客户端(或数据所有者)可以使用这个库,在云环境中基于他们的集体数据联合训练一个 XGBoost 模型,同时保护他们个人数据的隐私。虽然我们在本文的其余部分关注协作学习,但是 Secure XGBoost 也支持那些只是想将计算外包给云,但不想以纯文本形式将数据暴露给云的人。

在其核心部分,Secure XGBoost 使用安全飞地(如英特尔 SGX)来保护数据,即使是在充满敌意的云环境中。也就是说,即使培训在云中运行,每个客户端的数据仍然对云提供商和其他客户端隐藏。客户端远程编排训练管道,但是协作,并且安全 XGBoost 保证每个客户端保留对其自身数据的控制。**

安全的飞地

安全区域是计算机处理器技术的最新进展,它允许在不可信的机器上创建安全的内存区域(称为区域)。放置在 enclave 中的任何数据或软件都与系统的其余部分隔离开来。同一处理器上的任何其他进程都不能访问该内存,即使是操作系统或虚拟机管理程序等特权软件也不能。secure enclave 技术的示例包括英特尔 SGX、AWS Nitro Enclaves、ARM TrustZone 和 AMD 内存加密。

此外,enclaves 通常支持一个名为远程证明的特性。该特性使客户端能够以加密方式验证云中的 enclave 正在运行可信的、未经修改的代码。

Secure XGBoost 构建于 Open Enclave SDK 之上,这是一个开源 SDK,提供了跨不同 Enclave 技术的单一统一抽象。Open Enclave 的使用使我们的库能够兼容许多不同的 Enclave 后端,如英特尔 SGX 和 OP-TEE。

减轻旁道攻击

在飞地之上,Secure XGBoost 增加了第二层安全,额外保护数据和计算免受飞地上的大类攻击。

研究人员已经表明,攻击者可能能够通过利用辅助泄漏源(或“旁道”)了解 SGX 飞地内数据的敏感信息,即使他们无法直接观察数据。存储器访问模式就是这种旁路的一个例子。

在 Secure XGBoost 中,我们设计并实现了用于模型训练和推理的数据无关算法。在高层次上,我们的算法产生相同的存储器访问序列,而不管输入数据如何。因此,内存访问模式不会向攻击者透露任何有关底层数据的信息。

然而,额外的安全性是以牺牲性能为代价的。如果这种攻击超出了用户的威胁模型,他们可以禁用这种额外的保护。

系统结构

安全 XGBoost 的部署由以下实体组成:(I)多个数据所有者(或客户),他们希望在他们各自的数据上协作训练模型;以及(ii)在飞地机器集群中托管安全 XGBoost 平台的不可信云服务。

安全 XGBoost:架构

  • 嫖客。客户是指与其他客户一起参与协作学习过程的数据所有者。客户端通过远程调用其 API 在安全的 XGBoost 平台上共同执行计算管道。
  • 有飞地的云服务。云服务由一个虚拟机集群组成,每个虚拟机在一个安全的飞地中托管安全的 XGBoost。在训练和推理过程中,Secure XGBoost 将计算分布在飞地集群中。飞地通过 TLS 通道相互通信,TLS 通道在飞地内部开始和结束。云还托管一个不受信任的 orchestrator 服务。orchestrator 协调客户机和部署在 enclaves 中的安全 XGBoost 平台之间的通信。

工作流程

每个客户端将它们的加密数据上传到云服务,然后共同调用安全的 XGBoost API 来处理它们的数据。端到端示例工作流如下:

安全 XGBoost:工作流

  1. 客户端认证云上的 enclave(通过 enclave 的远程认证程序)以验证预期的安全 XGBoost 代码已经安全地加载到每个 enclave 中。作为证明的一部分,他们从飞地接收一个公钥 pk。每个客户端生成一个对称密钥 k_i ,使用 pk 对其进行加密,并将其发送到 Secure XGBoost。
  2. 客户端上传加密数据到云存储。每个客户端用他们的对称密钥 k_i 加密数据,并上传到云存储。
  3. 客户端共同协调数据处理。客户端同意预先确定的命令(一个命令是一个 XGBoost API 调用)序列,这些命令将在它们的数据上联合执行。客户端提交一个签名的命令给 orchestrator,orchestrator 将其转发给 Secure XGBoost。命令的结果(例如,加密的训练模型或加密的预测结果)被返回给客户端。

该过程继续,直到所有命令都被执行。

用户 API

从用户的角度来看,上面工作流的所有复杂性都被抽象到了库中,使用这个库非常简单。在很大程度上,Secure XGBoost 保留了常规 XGBoost 公开的 API,只需要很少的添加就可以在 enclaves 的多方设置中工作。

假设每个客户端都已经将它们的加密数据上传到了云服务器,这里有一个客户端如何使用 Secure XGBoost 的例子。

  1. 每个客户端首先初始化它们的密钥,并连接到云中的安全 XGBoost 部署。
*import securexgboost as xgbxgb.init_client(user1,
                symmetric_key,
                public_key,
                certificate,
                server_addr)*

2.接下来,每个客户端验证 enclaves,以验证它们正在运行真实的、未经修改的安全 XGBoost 代码。

*xgb.attest()*

然后,客户端调用安全的 XGBoost APIs。这些与普通的 XGBoost 非常相似,在支持多个数据所有者方面略有不同。

3.将来自不同数据所有者的数据加载到服务器的单个“数据矩阵”中。

*dtrain = xgb.DMatrix({user1: “/path/to/data/on/server”,
                      user2: “/user2/data/on/server”})*

4.根据加载的数据训练模型。

*params = {"tree_method": "hist",
          "objective": "binary:logistic",
          "min_child_weight": "1",
          "gamma": "0.1",
          "max_depth": "3"}num_rounds = 5booster = xgb.train(params, dtrain, num_rounds)*

5.使用模型运行预测。Secure XGBoost 发送加密的结果,这些结果在客户机上本地解密。

*dtest = xgb.DMatrix({username: “path/to/data/on/server”})predictions, num_preds = booster.predict(dtest)*

应用程序

在过去的几个月里,我们一直在与行业中的几个团队合作,包括加拿大丰业银行、爱立信和蚂蚁金服,以开发和部署安全的 XGBoost。特别是,我们正在努力使用 Secure XGBoost 进行反洗钱、欺诈检测和信用风险建模。

资源

我们对这个项目的方向及其潜在的应用感到非常兴奋。代码库是开源的。要开始,请查看我们在 Github 上的项目页面。如果您想进一步了解该项目或有任何疑问,请提出问题或通过以下方式联系我们:

Secure XGBoost 是 umbrella MC 项目的一部分,在这个项目下,我们正在开发各种保护隐私的机器学习工具。请查看我们的项目页面获取更新。

作者

里沙布·波德达尔、切斯特·梁、郑文婷、拉卢卡·阿达·波帕和扬·斯托伊察(里塞拉布,加州大学伯克利分校)**

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

使用密码保护您的数据工具

原文:https://towardsdatascience.com/secure-your-data-tool-part-1-2-1585029d59e9?source=collection_archive---------27-----------------------

作为一名数据科学家,如何使用 NGINX 保护数据工具

TL;博士: NGINX 是一种安全访问数据科学工具(如 Airflow 或任何 web 应用程序)的快速简单的方法,不需要完整的 web 开发技能。

框住的熊Unsplash 上拍照

想象一下…你是一名数据科学家,有一个棘手的问题要解决,你发现了一个很棒的开源工具,可以解决这个问题。也许你希望开始用 MLflow 跟踪不同的模型版本……或者你想用 Apache Airflow 建立数据管道……或者你想开始在 JupyterHub 中合作。这些工具都有一个超级简单的安装指南。您运行几个 bash 命令,然后将 web 浏览器指向localhost:port,您就可以启动并运行了。

让我们假设你正在使用气流。在本地使用它之后,您希望开始定期使用 Airflow 和/或与团队中的其他人分享。为此,您可以使用由云提供商(如 AWS EC2 或 GCP 计算引擎)管理的虚拟机,并遵循与在本地机器上类似的步骤。一旦 airflow 启动并运行,您需要能够通过一个网址访问,而不需要提供整个互联网访问。作为一名 web 安全经验有限的数据科学家,这第一次可能是一项艰巨的任务。本教程将向您展示如何以安全的方式在虚拟机上快速托管气流,而无需成为安全或 web 工程师!您也可以轻松地将这些方法应用于其他数据科学工具。

免责声明:本指南旨在为数据科学家提供一种设置密码保护的简单方法。在对敏感用户或公司数据或系统使用这些方法之前,请务必咨询您的内部(或外部)安全专家。#保护数据

先决条件:

本教程假设您已经在 EC2 机器上运行了一个 Apache Airflow 应用程序。这里是阿帕奇气流的一个很好的例子。许多其他数据科学工具都有关于如何设置的类似教程!您还应该非常熟悉 bash 脚本。在本教程中,我们在 EC2 实例上使用 Ubuntu。

此时,您应该能够通过http://<webserver_location>:port在互联网上访问您的 web 应用程序(这种访问可以通过安全组来设置——下面有更多信息!).此时,Airflow 前面没有密码保护,您的浏览器指示您的连接不安全。

必要的工具

NGINX

NGINX (发音为“engine x”)是一个漂亮、强大、全功能的 web 服务器,它为 web 开发人员提供了许多优秀的功能。这意味着数据科学家需要的少量功能实际上很难设置。您可以将它用于一些关键的功能:

  • 向我们的 web 应用程序添加身份验证(这篇文章)
  • 用域名给我们的网络应用添加加密,这样我们就可以访问 HTTPS 上空的气流

NGINX 是免费和开源的。要在 Ubuntu 服务器上安装 NGINX,请运行:

sudo apt-get install nginx

htpasswd

htpasswd 是一个超级简单的系统,用于管理用户列表和认证密码。我们将使用 htpasswd 来管理访问 Airflow 的用户的用户名和密码。要安装 htpasswd,请运行

sudo apt-get install apache2-utils

AWS 安全组

如果您使用 Airflow running,您可能已经在这里完成了,但是您需要访问 AWS 中的输入/输出端口安全设置来完成本教程。如果你在 AWS 上有一个管理员级别的帐户,你应该没有问题访问它。如果您的访问权限较低,请要求您的管理员授予您 EC2 安全组访问权限。

下面,您将看到对端口8080(它将在没有密码的情况下指向气流)、端口22(它将自动为 SSH 启用)和端口8081(它将在有密码保护的情况下指向气流)的开放访问。

要添加对这些端口的访问,只需编辑入站列表并点击“添加规则”。接下来从下拉列表中选择“自定义 TCP 规则”,添加您的端口号,并指定谁应该能够访问。您可以在开放访问、当前 IP 和自定义 IP 地址之间进行选择。小心开放访问——互联网上的任何人都可以访问!在这里,我们正在为8081港设置开放访问。

设置步骤

测试出 NGINX

NGINX 是通过一系列配置来管理的。在默认安装 Ubuntu 的情况下,这些配置会在/etc/nginx(找不到这个文件?更多详情此处)。您将在这个配置文件中看到各种目录和文件。你在乎的那个叫sites-enabled ( 为什么?)。在这个目录中,您会发现default,这是默认的配置文件。继续打开那个文件。为了保持整洁,让我们继续删除这个文件中的所有内容(提示:如果您正在使用 vim,请键入dG)。

为了确保 NGINX 正常工作,我们将设置一个超级简单的“代理传递”,将一个运行在8080上的 web 服务器“传递”给8081。为此,将以下内容粘贴到新清除的default文件中:

server {
        listen 8081;

        location / {
        proxy_pass http://127.0.0.1:8080;
        }
}

保存并退出该文件后,您需要使用sudo service nginx restart重启 NGINX(这对您不起作用吗?更多选项此处)。假设没有弹出错误,您新创建的代理通行证现在应该可以工作了!如果没有,检查您的安全组设置(前面已经讨论过)以确保端口8081是可访问的。这意味着您现在也应该能够从端口8081获得气流:

注意:气流现在仍然在端口 8080 上可用,但现在也在端口 8081 上可用。

添加身份验证

接下来,我们要添加一个用户名和密码认证到我们新的代理端口 8081。我们将使用 htpasswd 来管理用户名和密码,NGINX 将引用它们。

首先,让我们设置我们的第一个新用户。为此,请运行以下命令:

sudo htpasswd -c /etc/.htpasswd testuser

-c应该只是添加了的第一个时间,而不是当你添加新用户之后,/etc/.htpasswd可以是任何文件位置,请小心你放置这个的地方!testuser是用户名。

这将提示您输入密码并确认密码!该命令用您的username:password组合设置一个纯文本文件字符串。尽管密码是以加密格式存储的,但是仍然要确保谁可以访问这个文件。

要添加额外的用户名和密码,只需重新运行上面不带-c的命令:

sudo htpasswd /etc/.htpasswd testuser2

现在我们有了用户设置,我们应该回到default NGINX 配置文件。我们需要增加两条新线路。第一个设置登录提示文本,第二个引用最近创建的密码文件:

server {
        listen 8081;

        location / {
        proxy_pass http://127.0.0.1:8080;
 **auth_basic "Please Login";
        auth_basic_user_file /etc/.htpasswd;**
        }
}

随着 NGINX 配置文件的每次更新,我们需要使用 sudo service NGINX restart 来重启服务。现在前往8081端口,你会看到新的安全网页:

现在您已经在端口 8081 上设置了密码,您可以通过安全组设置删除对端口 8080 的访问。现在,用户将只能通过密码安全链接访问气流!

关于这一节的更多细节,这里还有另一个很棒的教程

注意:此时,任何窥探您连接的人都可能在传输过程中窃取您的密码。这就是为什么有一个关于“你与这个网站的连接不是私人的”的说明为了避免这种情况,您应该只在安全、可信的 wifi 网络上使用它,或者使用 VPN。您也可以用自己的域名设置 HTTPs,这样就不用担心这个问题了。NGINX 有很棒的教程这里

问题,想法,错误?请在评论中让我知道。感谢阅读!

保护网络上的 ML 服务

原文:https://towardsdatascience.com/securing-ml-services-on-the-web-69408e8554d0?source=collection_archive---------36-----------------------

来源:https://pix abay . com/photos/vault-business-bank-vault-bank-1144249/

HTTPS 和访问控制

如果您希望在 web 上托管机器学习服务,那么通常有必要锁定端点,以便对服务的调用是安全的,并且只有授权用户才能访问服务。为了确保敏感信息不会暴露在 web 上,我们可以使用安全的 HTTP (HTTPS)来加密客户端和服务之间的通信,并使用访问控制来限制谁可以访问端点。如果你在 2020 年建立一个机器学习服务,你应该计划为你的端点实现安全 HTTP 和访问控制。

本文将展示如何构建一个用 Flask 实现的安全端点来托管 scikit-learn 模型。我们将探索以下方法:

  • 使 HTTPS 直接在烧瓶中
  • 使用 WSGI 服务器(Gunicorn)
  • 使用安全的负载平衡器(GCP)

我们将在 GCP 生态系统中使用 Docker 和 Kubernetes 托管服务。为了限制授权用户的访问,我们将探索以下服务访问控制方法:

  • 基于令牌的身份验证(Flask)
  • OAuth 认证(破折号)
  • 白名单

根据您的组织部署服务的方式,这些选项中的一些可能不可用,但获得锁定服务的各种不同方法的经验是很好的,通常使用多种方法锁定端点是个好主意。这篇文章是从托管用 Python 编写的 web 服务的角度来写的,并建立在我以前关于模型作为 web 端点的文章的基础上。

[## 作为 Web 端点的模型

《生产中的数据科学》摘录

towardsdatascience.com](/models-as-web-endpoints-162cb928a9e6)

烧瓶用 HTTPS

如果您计划在 web 上托管一个机器学习模型,那么您应该在项目早期考虑数据和结果的安全传输需求。Chrome 在 2018 年年中开始将 HTTP 网站标记为不安全,现在有很多工具可以使用 HTTPS 来保护模型端点。安全 HTTP 利用安全套接字层(SSL)来确保客户端和服务器之间的通信是加密的,并使用公钥基础设施(PKI)来确保客户端与其预定目标进行通信。本文主要关注第一个方面,客户端和服务器之间发送的流量是加密的。若要完全设置 HTTPS,您需要设置一个对应于您的端点 IP 地址的 DNS 条目,以便您可以创建一个签名证书,将您的端点标识为受信任的主机。一旦你设置了 DNS 入口,这一步对于谷歌云平台(GCP)来说是很简单的,但是管理一个网络域和 DNS 查询不在这篇文章的讨论范围之内。

一般来说,最好使用 Flask 以外的系统来保护端点,因为 Flask 不应该直接用作 web 应用程序。相反,最好使用 Gunicorn 或 Nginx 等工具在非安全的 Flask 应用程序上提供一个安全层。然而,有时候 Flask 应用程序,比如在 Flask 上用 Dash 构建的交互式 web 应用程序,需要提供端到端的安全连接。这就是像 Flask Dance 这样的库有用的地方。

首先,我们需要安装 Python 和相关库。对于本教程,我们将安装以下库来设置 Flask 端点、Dash 应用程序和客户端应用程序:

pip3 install --user pandas 
pip3 install --user scikit-learn
pip3 install --user flask
pip3 install --user Flask-HTTPAuth
pip3 install --user requests
pip3 install --user cryptography
pip3 install --user gunicorn
pip3 install --user dash
pip3 install --user flask_dance
pip3 install --user dash-google-auth

我们首先在 Flask 中构建一个预测建模端点,返回用户购买新游戏的倾向。模型的输入是一个特征向量,它描述了用户以前是否购买过小目录中的游戏。代码在我以前关于模型的帖子中有更详细的描述,名为 web 端点。下面的代码片段显示了如何设置 Flask 端点,该端点首先训练一个 scikit-learn 模型,在“/”处设置一个端点来服务该模型,然后直接启动应用程序。

基本 HTTP Flask 应用程序。

在使用python flask_html.py运行应用程序之后,我们现在有了一个运行在端口 80 上的模型服务器应用程序。

* Serving Flask app "app" (lazy loading)
* Environment: production
* Debug mode: off
* Running on [http://0.0.0.0:80/](https://0.0.0.0:443/) (Press CTRL+C to quit)

我们还可以使用 Python 测试端点,如下面的代码片段所示:

用于通过 HTTP 调用模型端点的 Python 客户端。

运行客户端代码的结果是使用requests库通过不安全的 HTTP 调用模型端点,然后打印结果。我们希望达到同样的结果,但要让通话在 HTTPS 进行。要设置此协议,我们可以锁定 Flask 端点,使用 web 服务在 Flask 上提供一个安全层,或者使用负载平衡器来提供 HTTPS 功能,同时仍然在虚拟私有云(VPC)中使用 HTTP。

直接使用 Flask 使用 Flask 应用程序启用安全 HTTP 的第一种方法是在 Flask 中建立安全连接。这不是推荐的方法,因为在生产环境中直接使用 Flask 不是最佳实践,而是应该使用诸如 Gunicorn 之类的 WSGI 服务器来包装 Flask 应用程序。但是如果您想在开发期间锁定服务,那么这种方法可能是合适的。在 Flask 端,从 HTTP 到 HTTPS 的更改只需要更改一行,这是前面 Flask 代码片段中的最后一行。

app.run(host='0.0.0.0', port=443, ssl_context='adhoc')

我们修改了应用程序,使其运行在端口 443 上,这是 HTTPS 的默认端口,而不是 HTTP 的默认端口 80。此外,我们还设置了一个 SSL 上下文,它告诉 Flask 使用 SSL 来提供安全连接。adhoc参数告诉 Flask 动态生成未签名的凭证,而不是将已签名或未签名的凭证传递给服务器。当您运行更新后的示例时,您会看到服务的端口和协议都发生了变化,如下所示。

* Serving Flask app "app" (lazy loading)
* Environment: production
* Debug mode: off
* Running on [https://0.0.0.0:443/](https://0.0.0.0:443/) (Press CTRL+C to quit)

该服务现在使用 SSL 来提供客户端和服务器之间的安全连接,但是使用adhoc设置意味着证书的来源没有经过可信机构的验证。为了创建正确签名的证书,我们需要将模型托管在一个命名的 URL 上,比如[https://cat-classifier.ml.com](https://cat-classifier.ml.com),而不仅仅是一个 IP 地址,比如[https://10.0.0.1](https://10.0.0.1)。如果您能够设置一个 DNS 条目来将您的 IP 地址映射到一个命名的 URL,那么您可以使用一个认证机构来创建正确的凭证。与此同时,我们将继续使用adhoc方法,这意味着当您试图使用 Google Chrome 查看模型端点时,会得到以下警告。

使用临时凭据会导致未签名的证书。

此外,如果您修改前面的客户端示例,使用 HTTPS 代替 HTTP,您将得到下面的警告。

requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1076)')))

我们现在有了作为安全端点运行的模型,但不是可信端点。为了创建受信任的端点,我们需要一个签名证书来验证发送到端点的流量实际上对应于模型端点,并且不能被冒充我们的服务的第三方截获。我们不会在本文中涉及这方面的内容,但是我们将在下一节中展示如何设置自签名证书。

使用 WSGI 服务器 与其直接运行 Flask 应用,不如在将模型服务应用部署到生产时,使用可扩展的 web 服务器框架,如 Gunicorn 或 Nginx。要修改我们的应用程序以使用 Gunicorn,我们首先需要创建一个自签名证书,该证书可用于建立安全连接。下面显示的命令显示了如何使用 Gunicorn 在 HTTPS 上提供 Flask 应用程序。

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem 
            -keyout key.pem -days 365 gunicorn --certfile cert.pem --keyfile key.pem 
         -b 0.0.0.0:443 flask_http:app

结果与上一节类似,现在我们有了一个受不可信模型保护的端点。这两个例子的主要区别在于 Gunicorn 方法可以处理更大的流量。

使用负载均衡器 还有第三种方法可以用来建立安全的 flask 应用程序,即构建一个 Flask 应用程序,它使用 HTTP 来服务请求,但是将这个服务包装在一个私有集群中。这种方法是安全的,但是不使用端到端加密。一旦流量被路由到私有集群,云内的机器之间就会使用不安全的连接,这些机器通常没有公共 IP 地址。实现这种设置的一种方法是使用 Google Kubernetes 引擎(GKE)来托管您的容器化 Flask 应用程序,并使用节点端口和入口来设置 HTTPS 安全负载平衡器。结果是,从客户端到服务器的流量将被加密到入口端点,并且从该端点到容器将在内部使用 HTTP。同样,这种方法导致了一种安全但不可信的方法。然而,如果您的端点有一个 DNS 条目,那么使用 Google 管理的 SSL 证书创建一个合适的证书是很简单的。

这一部分专门针对 GCP,但是这种方法应该适用于其他 Kubernetes 环境。下面是一般的方法:

  1. 使用 Docker 将您的应用程序容器化
  2. 在没有公共 IP 的 Kubernetes 集群中托管容器
  3. 使用节点端口服务类型在 VPC 中公开服务
  4. 使用启用了 HTTPS 的服务入口启用外部连接

要设置 GCP 帐户、创建凭证并启用这种方法所需的容器注册和 GKE 服务,需要遵循许多步骤。在我之前关于在 GCP 建立模型服务的文章中提供了更多的细节。我将在这篇文章中介绍的主要区别是使用节点端口加入口设置(第 7 层)与使用负载平衡器作为 TCP 端点来直接公开服务(第 4 层)。

[## 与 GCP 合作开发数据科学

为模型服务部署生产级容器

towardsdatascience.com](/devops-for-data-science-with-gcp-3e6b5c3dd4f6)

第一步是将端点设置为 Docker 应用程序。为了实现这一结果,我们需要创建一个 docker 文件来设置 Python 生态系统,安装所需的库,并定义要运行的应用程序。我们将使用 Gunicorn 来包装 Flask 应用程序,并通过 HTTP 托管这个端点,如下面的 Dockerfile 所示:

FROM ubuntu:latest
MAINTAINER Ben WeberRUN apt-get update \
  && apt-get install -y python3-pip python3-dev \
  && cd /usr/local/bin \
  && ln -s /usr/bin/python3 pythonRUN pip3 install flask
RUN pip3 install pandas
RUN pip3 install gunicorn
RUN pip3 install scikit-learnCOPY app.py app.pyENTRYPOINT ["gunicorn", "--bind", "0.0.0.0:80", "app:app"]

接下来,我们将构建容器,然后在将容器推送到注册中心之前在本地测试容器。

sudo docker image build -t "model_service" .
sudo docker images
sudo docker run -it -p 80:80 model_service

要将容器推送到 Google Container Registry,我们首先需要在推容器之前执行docker login。关于设置这些证书的细节,请参见我之前在 GKE 的模特服务上的帖子。执行完这些步骤后,我们将在 GCP 上有一个可用的容器,我们可以用它在 GKE 部署服务。

将图像推送到 Google 容器注册表。

将容器推送到 GCP 后,我们将启动一个 GKE 集群,并将容器部署为一个工作负载。一旦您设置了一组 pod 并运行服务,您就可以通过首先设置节点端口服务类型来安全地公开服务,如下图所示。

在 VPC 中公开模型服务。

下一步是为服务创建一个入口,将端点暴露给开放的 web,而不仅仅是在您的 VPC 中。要设置入口,请浏览至服务和入口选项卡,选择您刚刚创建的节点端口,然后选择“创建入口”。

从节点端口创建入口。

从这一步开始,我们可以设置一个具有 HTTP 和 HTTPS 端点的负载平衡器。如果要禁用模型服务的非安全流量,可设置仅 HTTPS 端点。如果选择 HTTPS 选项,则需要指定要使用的证书。您可以暂时假装这一步,选择使用 Google 管理的证书并选择任何域。结果将是一个无效的证书,但是您将能够测试设置一个支持 HTTPS 的负载平衡器。

使用 GCP 负载平衡设置 HTTPS 端点。

结果将是一个 HTTPS 端点,您现在可以在“服务和入口”选项卡中查看。模型服务现在在[https://34.107.189.4](https://34.107.189.4)运行,但是端点不是受信任的 URL。

由此产生的 HTTPS 端点。

我们现在已经探索了将 Flask 应用程序设置为安全端点的三个选项。虽然使用的方法会根据您的云平台和组织偏好而有所不同,但是使用安全 web 服务包装 Flask 应用程序的第二种方法可能是最合适的方法。

烧瓶的访问控制

我们已经讨论了锁定模型服务的第一个方面,即确保客户端和服务器之间发送的流量是加密的。下一步是使用访问控制工具来限制谁可以访问该工具。加密可确保第三方无法监听主机之间的流量,而访问控制可确保未授权方无法访问该服务。如果您在公司网络中工作,那么一种可能已经存在的访问控制形式是仅限于 VPN 的访问。我们不会在这篇文章中讨论这种方法,因为 VPN 的设置可能非常复杂,并且在不同的组织中差异很大。相反,我们将通过令牌、OAuth 和白名单来探索访问控制。

本文没有涉及的另一种访问控制方法是使用 web 服务层,例如 Nginx,在将流量转发到 Flask 应用程序之前进行用户授权。这种方法非常适合数据科学团队,因为它实现了关注点的分离,数据科学团队建立模型服务容器,DevOps 团队管理对端点的访问。对于成熟的组织来说,这是一个很好的方法,但对于负责端到端模型部署的数据科学团队来说,这可能不可行。

基于令牌的认证 启动并运行锁定端点的最简单方法是拥有一个公共秘密,客户端可以使用该秘密向模型服务进行认证。在最简单的情况下,这意味着拥有单一的共享密码,客户端可以使用该密码来建立对资源的访问。这种方法以及大多数访问控制方法只有在使用安全连接与模型服务进行通信时才有效。一般来说,如果没有安全的通信协议,您就不能拥有有效的访问控制。下一步是为不同的用户提供不同的访问令牌或密码,并为不同的角色提供不同的访问级别。

我们将使用令牌方法开始,因为密码管理是一个庞大的主题,我无法在一篇简短的帖子中对其进行公正的讨论。事实上,我建议不要使用任何直接的密码管理,而应该使用 OAuth 之类的协议,这将在下一节中讨论。我们将浏览的示例使用单个令牌进行访问,但是可以扩展到使用一组令牌。理想情况下,您应该有一个工具来生成令牌,存储关于用户和角色的元数据,并能够拒绝令牌或使令牌过期。对于这个简单的例子,我们将使用 Flask-HTTPAuth ,它提供令牌和摘要认证。

向 Flask 应用程序添加令牌认证只需要几个步骤。我们需要使用@auth.login_required 注释来识别哪些路由是安全的,并实现一个verify_token函数来认证客户端。在这种情况下,我们检查来自用户 (1234567890abcdefg )的已知令牌。对于生产系统,通常将令牌存储在数据库中,并将令牌映射到不同的访问策略。

用固定令牌保护 Flask 应用程序。

现在我们已经锁定了端点,当客户端试图在没有令牌的情况下访问端点时,将被拒绝访问,如下所示。

尝试在没有令牌的情况下访问模型服务。

要访问模型服务,我们需要更新客户机请求示例,以便在请求头中提供令牌。下面的代码片段显示了如何更新请求,将令牌添加到请求中的headers参数。现在,结果应该与第一个示例相同,但是我们现在已经使用令牌将模型服务锁定到客户端。

使用用于访问的令牌调用模型端点。

在与第三方合作时,令牌方法非常有用,因为您可以允许大量用户进行访问。但是,这种方法不如使用 OAuth 之类的协议安全,OAuth 可以用来限制对一组指定用户的访问。

OAuth 认证 令牌对于模型端点很有用,因为您可能需要提供预测,而不需要客户端通过 web UI 登录。但是如果你的目标应用是一个交互式应用,而不是模型预测,那么 Dash 这样的工具会非常有用。我喜欢用 Dash 来构建 web 应用程序,因为我可以用 Python 编写 web 应用程序,并使用 OAuth 等安全特性来验证用户。使用 OAuth,您可以将身份验证委托给已知的提供者,比如 Google 来建立用户的身份。您仍然定义可以访问您的应用程序的用户列表,但是您依赖可信的提供者来完成确保身份的复杂工作。

下面的例子展示了如何使用 Google Oauth 2.0 来锁定 Dash 应用程序。Dash 是建立在 Flask 之上的框架,本例中使用的 Flask Dance 库可以应用于所有 Flask 应用程序。为了让这个例子工作,您需要在 GCP 中配置一个 OAuth 规则。

用 OAuth 2.0 保护的 Dash 应用程序示例。

这种方法的结果是,当您试图访问模型服务端点时,您将得到一个登录页面。如果您提供了凭据并且在允许的用户列表中,您将获得以下内容:

该应用程序服务于授权用户。

使用 OAuth 的主要好处是第三方负责建立用户的身份,这是一个标准协议。如果您正在设置一个基于 GUI 的 web 服务,这是一个很好的方法。

第三种实施访问控制的方式是限制哪些机器可以访问服务。这种方法被称为白名单,因为只有授权 IP 地址列表上的机器才被授权使用该服务。这种方法不验证发出调用的客户端的身份,但是锁定了对少量机器的访问。这种方法对于 VPN 设置很有用,在 VPN 设置中,到 VPN 的连接是安全的,流量通过带有静态地址的 VPN 传输。这对于需要与已知 IP 地址的第三方服务交互的模型端点也很有用。

如果您使用 GKE 服务入口方法来设置负载平衡的 HTTPS 端点,那么您可以使用 GCP 云盔甲来设置白名单规则。所有不允许访问服务的传入流量都将返回 403 响应代码(禁止)。要为负载平衡器设置白名单,请在 GCP 控制台中浏览到 Cloud Armor,然后单击“创建策略”。您可以配置一组阻止的 IP 和允许的 IP。在下面的示例中,默认情况下所有流量都被阻止,优先级更高的第二个规则允许来自 IP 1.2.3.4的访问。设置好 IP 规则后,我们可以使用目标部分将这个新策略应用到模型服务负载平衡器。

将单个 IP(1.2.3.4)加入 GCP 云防护的白名单

这种方法的结果是,来自指定 IP 地址的流量将被允许,所有其他流量将得到禁止响应。这种方法不直接对用户进行身份验证,而是依赖于来自已知静态 IP 地址的流量。这类似于在 AWS 上配置 EC2 安全组时设置入站流量规则。

结论

如果您计划建立将在 web 上提供的机器学习模型,那么您应该从项目一开始就计划安全性和访问控制。虽然通常使用包装数据科学团队建立的服务功能的工具来提供安全措施,但是任何发布服务的团队都应该确保 web 服务是安全的,并且仅限于授权用户。

本·韦伯是 Zynga 杰出的数据科学家。我们正在招聘

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

安全认证与授权:您需要了解的内容

原文:https://towardsdatascience.com/security-authentication-vs-authorization-what-you-need-to-know-b8ed7e0eae74?source=collection_archive---------31-----------------------

史蒂夫·哈拉马在 Unsplash 上拍摄的照片

软件术语可能会令人困惑。许多单词可能听起来相似,但却是计算机安全和网络的不同方面,有时,很难将它们区分开来。

关于安全系统,术语“认证”和“授权”的混淆是一个典型的例子。

它们经常被错误地互换使用。

虽然它们听起来相似,但它们是两个完全不同的安全概念。

开发人员集成了强大的身份验证和授权过程,以保护他们的应用程序免受恶意行为者的攻击。

有数以百万计的 web 应用和服务需要认证才能正常工作,因为它们的大部分服务/意图依赖于用户的行为:博客、论坛、购物车、协作工具和基于订阅的内容/服务。

但是,这并不等同于授权。

安全认证与授权:有什么区别?

安全认证和授权到底有什么不同?

在这一节中,我们将进一步了解安全认证和授权。

什么是认证?

认证是断言和证明一个人的身份。我的身份是“joe _ user”(userID),我可以证明我是 Joe,因为我知道 Joe 的密码(其他人都不知道)。

身份认证是验证用户身份以授予他们访问系统或网络的权限的过程。它决定了用户访问诸如服务、数据服务器、网络、数据库、文件等资源的权利。

web 应用程序如何向用户提供身份验证?

大多数应用程序都有一个登录页面,用户必须输入凭据来证明自己的身份。这些凭证可能包括他们的用户 ID、用户名、电子邮件或电话号码以及与之关联的密码。

如果用户提供的凭证与存储在应用程序数据库中的数据相匹配,那么用户就通过了身份验证,并被授权访问应用程序。

常见的身份验证方法有哪些?

有几种方法可以执行身份验证,包括一次性密码、生物识别、身份验证应用程序、硬件令牌、软件令牌等。

最常见的身份验证方式之一是密码,如果用户输入正确的密码,系统会检查凭据并授予用户访问权限。

然而,密码经常成为黑客的目标,并且容易受到网络攻击,如暴力攻击、数据泄露、中间人攻击和密码破解。

因此,企业通常使用其他安全方法,如双因素或多因素身份验证(2FA/MFA)来加强密码之外的安全性。

在多因素身份认证中,系统可能要求在向用户授予访问权限之前成功验证多个因素。

什么是授权?

一旦用户通过身份验证,应用程序就知道你是谁。授权决定了用户可以在应用程序中做什么(垂直授权,例如,用户是否拥有管理员权限,或者他们是普通用户?)以及他们可以访问哪些数据?(横向授权,Joe 用户应该不能访问 Mary Smith 的数据)。

授权是授予用户访问特定资源(如文件、数据库、位置、资金、文件、信息以及应用程序中的几乎任何内容)的必要权限的过程。简而言之,授权评估用户访问系统的能力和程度。

根据 2019 年全球数据风险报告,近 53%的公司发现超过 1000 个敏感文件对每个员工开放。

为了维护强大的安全性,授权必须在身份验证之后进行,即系统在根据用户的权限授予访问权限之前验证用户的身份。

例如,您可能希望允许管理员查看敏感信息,但限制第三方供应商访问这些敏感数据。授权通常与用户访问控制和用户特权互换使用。

授权有哪些不同的方法?

说到授权,您可以采取不同的方法。什么最适合你取决于你的需求。

不同的授权方法包括:

  • 基于令牌:用户被授予一个令牌,该令牌规定了用户被授予什么特权以及他们可以访问什么数据,其中令牌被加密签名。
  • 基于角色的访问控制(RBAC): 用户被识别为处于规定他们拥有什么特权的角色中。此外,他们的用户 ID 会限制他们可以访问的数据。
  • 访问控制列表(ACL):ACL 指定哪些用户可以访问特定的资源。例如,如果用户想要访问特定的文件或文件夹,他们的用户名或详细信息应该在 ACL 中提及,以便能够访问某些数据。

企业通常批量为用户分配权限和 ACL,他们可能会实现“组”和“角色”,这两个功能可以对用户进行分类,并根据他们的组织地位和工作职能为他们分配访问控制和权限。

通常,一旦经过身份验证的用户可以访问他们的帐户,他们就可以执行他们有权执行的所有操作。

例如,一旦您登录到您的电子邮件帐户,您就可以查看您的所有电子邮件,回复它们,删除它们,对它们进行分类,修改您的个人信息,以及执行其他与电子邮件相关的任务。

但是,如果用户希望执行特别敏感的操作,他们可能需要采取额外的步骤来授权请求。

例如,如果用户试图进行支付,他们可能需要重新输入密码,或者重复身份验证过程,以再次验证他们的身份。

在安全环境中,如果某些应用程序观察到异常的用户行为,如 IP 地址、异常的登录时间或进行高价值交易的尝试,它们可能会使用这种预防性授权方法。

这是为了确保只有授权用户才能访问他们的帐户,并证明他们的帐户没有被恶意行为者劫持或破坏。

身份验证与授权:一个示例

还不清楚身份验证和授权的区别吗?

一个真实世界的例子可以帮助您更好地理解认证和授权之间的区别。

比方说,你想在线访问你的银行账户。

如果您需要登录您的银行应用程序,您必须拥有您的帐户凭证。如果您输入正确的用户名和密码,您就可以访问您的帐户。该应用程序只向拥有正确凭据的用户授予访问权限。

这是认证。

如果您忘记了密码,他们可能会问您一些只有您知道的安全问题,或者他们可能会通过电子邮件向您发送密码重置令牌。

这也是认证。

一旦您成功登录您的用户帐户,您就可以访问您的个人资料、下载您的银行对账单、进行交易以及进行许多其他与银行相关的活动。所有这些活动都是经过授权的。你被授予执行它们的特权。

现在,让我们假设你想在你的账户上访问一个高级服务。虽然您可以访问您的帐户(身份验证)并获得服务,但您可能不被允许(授权)访问高级服务。

在这种情况下,应用程序将在后端数据库中检查您的用户权限,并且只有当您有权访问这些高级服务时,才允许您使用它们。

外卖食品

认证和授权是网络安全的两大支柱,可以保护数据免受潜在的网络攻击。

身份验证是通过检查用户的凭据来验证用户是否是他们所声称的人的过程。授权是检查用户权限并仅授予对特定资源的访问权限的方法。

简而言之,身份验证和授权都是至关重要的,但一个不能替代另一个。

将身份验证和授权视为互补的系统,两者都需要。

理想情况下,您应该在安全系统中实现身份验证和授权。这是确保您的系统和网络安全的最佳方式。

如果您想进行网络安全审计或代码审查,请联系我们。

关于作者:

Steve Kosten 是 Cypress Data Defense 的首席安全顾问,也是“Java/JEE 中的 SANS DEV541 安全编码:开发可防御应用程序”课程的讲师。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

透过树看到森林

原文:https://towardsdatascience.com/seeing-the-forest-through-the-trees-45deafe1a6f0?source=collection_archive---------42-----------------------

一窥决策树和随机森林算法的内部工作原理。

Unsplashveeterzy 拍摄的照片

决策树如何工作

形象地说,决策树就像一个流程图,其中父节点代表一个属性的测试,叶节点代表分配给该叶节点的数据点的最终类别。

图 1-学生样本分布

在上图中,从学生成绩数据集中随机抽取了 13 名学生。散点图显示了基于两个属性的样本分布:

  1. 举手次数:学生在课堂上举手提问或回答问题的次数。
  2. visitedResources:学生访问课程内容的次数。

我们的目的是手动构建一个决策树,该决策树能够最好地将样本数据点分成不同的类别——L,M,H,其中:

L =较低性能类别

M =中等(平均)性能类别

H =高性能类别

选项 A

一种选择是在点标记 70 处沿着属性 visitedResources 分割数据。

这“完美地”将 H 类与其他类区分开来。

选项 B

另一种选择是在点标记 41 处沿同一属性 visitedResources 进行分割。

任何类别都无法实现“完美”的分离。

选项 C

另一个选项是在点标记 38 处沿属性“举手”进行分割。

这“完美地”将 L 类与其他类区分开来。

选项 A 和 C 在分离至少一个类方面做得更好。假设我们选择选项 A,结果决策三将是:

左边的分支只有 H 班的学生,因此不能再分开了。在右边的分支上,结果节点在 M 和 L 班各有四名学生。

请记住,这是我们分离练习的当前状态。

如何最好地将剩余的学生(数据点)划分到相应的班级?是的,你猜对了——多画几条线!

一种选择是在点标记 38 处沿着属性“举手”进行分割。

同样,可以绘制任意数量的分割线,然而,这个选项似乎产生了一个好的结果,所以,我们将使用它。

分割后得到的决策树如下所示:

显然,数据点被完美地分成了适当的类,因此不需要进一步的逻辑分离。

迄今吸取的经验教训:

  1. 用 ML 的说法,这个建立一个对给定数据集进行最佳分类的决策树的过程被解释或称为学习
  2. 这个学习过程是迭代的。
  3. 根据所做的拆分属性选择和允许的树深度,可以从同一个数据集中导出不同预测准确度级别的几个决策树。

在手动构建决策树的过程中,我们了解到分隔线可以沿着数据集中可用的任何属性在任何点绘制。问题是,在任何给定的决策节点,哪种可能的属性和分离点会更好地将数据集分离为所需或接近所需的类或类别?确定这个问题答案的工具是基尼系数。

基尼杂质

假设我们有一个新生,我们根据班级的概率分布将这个新生随机分为三个班级。基尼系数是对新的随机学生(变量)进行错误分类的可能性的度量。这是一个概率度量,因此它的范围在 0 和 1 之间。

我们的样本数据集中总共有 13 名学生,H、M 和 L 类的概率分布分别为 5/13、4/13 和 4/13。

以下公式用于计算基尼系数杂质:

上述公式在我们的示例中应用时变成:

因此,在任何分割之前,决策树的根节点处的 gini 杂质将被计算为:

回想一下前面讨论的根节点处的拆分选项 A 和 C,让我们比较一下这两个选项的基尼系数,看看为什么选择 A 作为更好的拆分选项。

选项 A

选项 C

因此,用分割选项 A 去除的杂质数量—基尼系数为:0.66–0.3 =0.36。而拆分选项 C 的值为:0.66–0.37 =0.29

很明显,基尼系数 0.36>0.29,因此,选项 A 是一个更好的分割选择,告知早先选择 A 而不是 c 的决定。

在一个节点上,所有的学生都是一个班的,比如说 H,基尼系数总是等于零,这意味着没有杂质。这意味着一个完美的分类,因此,没有进一步的分裂是必要的。

随机森林

我们已经看到,可以从同一个数据集生成许多决策树,并且这些树在正确预测未知示例方面的性能可能会有所不同。此外,使用单一的树模型(决策树)很容易导致过度拟合。

问题变成了:我们如何确保构建尽可能好的性能树?对此的答案是智能地构造尽可能多的树,并使用平均来提高预测精度和控制过拟合。这种方法称为随机森林。它是随机的,因为每个树不是使用所有的训练数据集而是数据集和属性的随机样本来构造的。

我们将使用 Scikit-learn python 包中的随机森林算法实现来演示如何训练、测试随机森林模型,以及可视化构成森林的一棵树。

在本练习中,我们将训练一个随机森林模型,根据学生在课堂/学习过程中的参与程度来预测(分类)学生所属的学术表现类别(班级)。

在本练习的数据集中,学生的参与被定义为四个变量的衡量标准,它们是:

  1. 举手:学生在课堂上举手提问或回答问题的次数(数字:0-100)
  2. 访问过的资源:学生访问课程内容的次数(数字:0–100)
  3. 查看公告:学生查看新闻公告的次数(数字:0–100)
  4. 讨论组:学生参加讨论组的次数(数字:0-100)

在下面的示例摘录中,前四(4)个数字列对应于前面定义的学生参与度,最后一列——类别,代表学生的表现。一名学生可以参加三(3)个班中的任何一个——低、中、高。

图 1:数据集摘录:学生参与度和表现类

基本数据准备步骤:

  1. 加载数据集
  2. 清理或预处理数据。该数据集中的所有要素都已采用正确的格式,并且不存在缺失值。根据我的经验,在 ML 项目中很少出现这种情况,因为通常需要某种程度的清理或预处理。
  3. 编码标签。这是必要的,因为该数据集中的标签(类)是分类的。
  4. 将数据集分成训练集和测试集。

上述所有步骤的实现如下面的代码片段所示:

接下来,我们将创建一个 RandomForest 实例,并使模型适合(构建树)训练集。

其中:

  1. n_estimators =组成森林的树木数量
  2. 标准 =为决策树挑选最佳属性分割选项时使用的方法。在这里,我们看到基尼系数被使用。
  3. 这是树木深度的上限。如果在这个深度,没有得到明确的分类,模型将认为该层的所有节点是叶节点。此外,对于每个叶节点,数据点被分类为该节点中的多数类。

注意,最佳 n 估计量和 max_depth 组合只能通过试验几种组合来确定。实现这一点的一种方法是使用网格搜索方法。

模型评估

虽然存在几种评估模型的度量标准,但我们将使用其中一种(如果不是最基本的话)——准确性。

训练集上的准确率:72.59%测试集上的准确率:68.55%——可以更好,但不是一个坏的基准。

想象森林中最好的树

随机森林模型中的最优树可以很容易地可视化,使工程师、科学家和商业专家对模型的决策流程有所了解。

下面的代码片段从上面训练的模型中提取并可视化了最佳树:

从随机森林中提取的决策树。

结论:

在本文中,我们成功地了解了决策树的工作原理,了解了如何使用 gini 杂质进行属性分割选择,如何将几个决策树组合起来形成随机森林,最后,通过训练随机森林模型来演示随机森林算法的用法,以根据学生在课堂/学习过程中的参与程度将他们分类到学术表现类别中。

感谢阅读。

机器学习时代用模型看世界

原文:https://towardsdatascience.com/seeing-the-world-in-models-in-the-age-of-machine-learning-24b5ecec91ef?source=collection_archive---------65-----------------------

电气工程师如何看世界:模型、系统、代码;和机器人

最好的机器人团队并不都是计算机科学家——他们有电气和机械工程师、计算机科学家、机器人等等来填补空缺。这篇文章探索了不同的思维方式是如何在机器人领域做出贡献的——并延伸到许多软件工程项目。

你如何总结你本科专业的总体概念主题?

这最初发布在我关于机器人学的免费时事通讯上&自动化、 民主化自动化

看模特

我主要不是通过电路设计或纳米制造来描述 EE。我花了很长时间才弄清楚我的电子工程(ee)学位和类似的计算机科学学位有什么不同。我的很多同学都获得了软件工程师(SWE)的工作,我们真的不同吗?我知道课程是不同的,但有可能这些课程在不同的课程和时间表中教授相同的概念。

有人会问,EEs 有什么不同?他们学会用模型看世界。我们从事的所有不同任务都有一套不同的假设和工具。我们需要小心并理解我们使用的模型在哪里是正确的,以及我们可能在哪里损害性能(以不确定性的形式)。电路设计有一个 Cadence 库形式的模型,用于特定的制造运行,微机电系统有通常基于物理的模型(但许多其他因素会影响最终的器件),信号处理使用模型来确定它们看到和发送什么信息,等等。

专业的数学,比如傅立叶变换,小波,电磁学等等,都是不同的模型集合。与深度学习相比,这些分析需要大量的数学基础(线性代数、多变量微积分和概率)。学习这些包含系统的严格性使得 EEs 看待机器学习模型的范围有其局限性。

随着每家公司都试图用机器学习 模型 解决新问题,这种用模型看世界的方式变得更加有价值。我的实验室小组几乎完全是电子工程类型的人,科学的、受约束的思维方式将比传统的电子工程设计空间更有助于系统。

也许把这个发给一个你不知道是什么意思的朋友?

f(x) = x*sin(x)。图片作者。

系统思维

除了用模型看世界,今天制造的大多数东西都是一系列极其复杂的相互联系中的一个齿轮。事实上,大多数工程师都在做一件具有许多下游效应的作品(例如,考虑一下推荐系统如何影响远不止用户)。这是未建模 动力学 的复杂形式(或者是扰动,有些场会这么说)。

我今天认识的机械工程师对系统中他们无法控制的部分有直觉。制造一件硬件?他们会思考它会触动什么,以及如何影响设计。这是一种思维方式,在这种思维方式中,你制造的任何东西都不会存在于泡沫中。

我没有完全掌握这里,因为我不是机械工程师,所以我很好奇什么人可以帮我填写。我有一种预感,热力学、控制理论、静力学等在 EE 中有重叠的主题,但我的印象是如何训练 mech-e 思考和处理事情有点不同。这种方法上的差异就是增加 mech-e 和 EE 的价值所在。

这就好像用不同的参照系覆盖相同类型的主题有助于冗余。我还会将化学工程循环到本节讨论的许多主题中。最终,它指向了计算机科学与工程的讨论,在未来十年我们将会有更多的讨论。

不含像素

一切都是可能的

我发现,与全职计算机科学家一起工作时,最大的收获是他们的乐观。软件正在改变世界(或者,称之为魔法),有人相信他们可以构建任何东西。乐观和黑客文化确实有其优点。

我认为计算机科学也建立了很强的主题 抽象 。无论是软件抽象(常见的方式)还是系统层次结构,在计算机科学领域都有一些真正优雅的解决方案。与计算机科学和广义人工智能的发展趋势相比,我不看好集合论、基本算法、编译器等事物的发展速度。这种从理论基础领域和思想结构公式到实现和制造事物(在教育的正式阶段——这具有巨大的价值)的指导的分歧,将定义计算机科学的未来。我想关注一下,与像伯克利和斯坦福这样的学校相比,规模较小的文科学校是如何教授计算机科学的。

那些建立了自己的计算机科学系的学校将会为他们的进步感到高兴。由于工具在社会中的流行,注册人数将持续上升。那是第一层点。其次,通过分离学校,人们会更好地意识到这些群体中有不同的思维方式。计算机科学家理应能够快速移动并打破事物,但是被打破的事物不可能是我们社会的结构。

免于像素

无形的(不可捉摸的)东西

大规模建造任何东西需要的不仅仅是受过工程训练的人。也许某个自学成才的人会填补“实际可行”的一些漏洞,或者(工程师优势-复杂触发警告)当设计产品时,没有受过工程师培训的人仍然有有效的输入。

许多无形资产的好处会在几年后显现出来。我喜欢的一个例子是,如果有人设计了一个推荐系统,试图让用户自我感觉良好。这不是短期的收入游戏(与风险投资模式相冲突),但我认为一家 5 年前开始这样做的公司现在会成为所有科技新闻业的黄金盘上的帮手,并且在财务上是不可战胜的(股票市场游戏)。

把它放在一起

机器人技术是一个奇怪的领域。人们实际行为的差异如此之大。这是一个更明显的例子,说明我们需要一种多样化的思维方式,但同样的趋势最终会适用。

作为一名研究人员,我花了第一个“富有成效”的月份追逐一架无人机,所以当它撞到天花板、检测到碰撞并关闭时,我可以抓住它,这样它就不会撞到地面,让我重新组装并从零开始。

  • 或者,我有一个朋友试图将电动机安装到自行车的杆上,制造自动自行车(被微型移动人群吞没)。
  • 或者,亚马逊的研究人员用许多“简单”的机器人管理他们的仓库,我是在开玩笑,提高了受伤率。
  • 或者,你在一个专注于深度强化学习的实验室工作,成功的衡量标准是在计算任务上超越基线。

这些都是正确的答案,但我正试图澄清作为一名机器人专家意味着什么。我试图让人们明白,我们需要各种各样的人来解决这些问题。

信念的飞跃是看到我们需要的不仅仅是计算机科学家来制造产品(即使它们没有在物理上体现出来)。如果一个纯软件项目成功了,那么这个项目将会发展壮大,而随着这种发展,如果在项目的制作过程中没有多样化的想法,那么这个团队可能会准备不足。我不打算指出最近的 ML 系统的道德和实施失败,但它们是普遍存在的。思想的交叉授粉有助于消灭这种恶意的角度。

[## 自动化大众化

一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…

robotic.substack.com](https://robotic.substack.com/)

这最初发布在我关于机器人学的免费时事通讯上&自动化、 民主化自动化

分割和对象检测—第 1 部分

原文:https://towardsdatascience.com/segmentation-and-object-detection-part-1-b8ef6f101547?source=collection_archive---------16-----------------------

FAU 讲座笔记关于深度学习

细分基础

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座

这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!

航行

上一讲 / 观看本视频 / 顶级/下一讲

欢迎回到深度学习!所以今天,我们想讨论几个更面向应用的话题。我们希望研究图像处理,特别是分割和对象检测。

道路场景中的语义分割。使用 gifify 创建的图像。来源: YouTube

让我们看看我为你准备了什么。下面是接下来五个视频的大纲:我们首先介绍话题,当然。然后,我们再来讲细分。因此,我们将激发它并讨论细分的问题所在。接下来,我们将介绍几种可以实现良好图像分割的技术。你会发现实际上有一些非常有趣的方法,它们非常强大,可以应用于各种各样的任务。在此之后,我们想继续谈论对象检测。所以,这是一种相关的话题。对于对象检测,我们希望研究如何在场景中找到对象以及如何实际识别哪个对象属于哪个类的不同方法。所以,我们先从介绍开始。

分割、对象检测和实例分割。 CC 下的图片来自深度学习讲座的 4.0 。

到目前为止,我们研究了图像分类。从本质上讲,你可以看到问题在于你只是简单地进行了分类,但是你不能从物体之间的空间关系中得到任何信息。一个改进是图像分割。所以在语义分割中,你试图找到图像中每个像素的类别。在这里,你可以看到我们用红色标记了所有属于“猫”类的像素。现在,如果我们想讨论对象检测,我们必须研究一个稍微不同的方向。因此,这里的想法是基本上识别感兴趣对象所在的区域。你可以在这里看到,如果我们使用,例如,我们在可视化中学到的方法,我们可能不会很高兴,因为我们只会识别与该类相关的像素。所以,这必须以不同的方式完成,因为我们实际上对寻找不同的实例感兴趣。所以我们希望能够在一张图片中找出不同的猫,然后找到包围盒。因此,这实质上是对象检测和实例识别的任务。最后,当我们掌握了这两个概念后,我们还想谈谈实例分割的问题。在这里,不仅仅是你找到所有显示猫的像素,而是你实际上想要区分不同的猫,并将分割分配给不同的实例。这就是实例分割,它将出现在关于这些主题的最后一个视频中。

在这个例子中,图像分割试图找到与图像中的计划相关联的所有像素。 CC 下的图片来自深度学习讲座的 4.0 。

所以,让我们继续谈一谈关于图像分割的想法。现在在图像分割中,我们想要准确地找到哪些像素属于那个特定的类。我们想从本质上描绘有意义的物体的边界。因此,在边界内的所有这些区域应该具有相同的标签,并且它们属于相同的类别。因此,每个像素都有一个语义类,我们希望生成像素级的密集标签。这些概念,当然,在这里显示在图像上,但从技术上讲,你也可以在声音上做类似的事情,例如,当你看光谱图时。图像的概念是,我们想把左边的图像变成右边的图像。你可以看到,我们找到了由飞机标识的区域,我们找到了边界。

语义边缘分割直接找到语义类的边界。使用 gifify 创建的图像。来源: YouTube

当然,这是一个更简单的任务。在这里,你也可以考虑更复杂的场景,比如这个自动驾驶的例子。在这里,我们感兴趣的是街道在哪里,人在哪里,行人在哪里,车辆在哪里,等等。我们想在这个复杂的场景中标记它们。

分段的应用。 CC 下的图片来自深度学习讲座的 4.0 。

类似的任务也可以用于医学成像。例如,如果你对不同器官的识别感兴趣,比如肝脏在哪里,血管在哪里,或者细胞在哪里。所以,当然,还有很多很多的应用我们不会在这里讨论。如果你处理卫星图像,当然还有航拍图像,自动机器人,还有图像编辑,你可以展示这些技术非常有用的特性。

图像分割的评价指标。 CC 下的图片来自深度学习讲座的 4.0 。

当然,如果我们想这样做,我们需要谈一谈评估指标。我们必须以某种方式来衡量分割算法的有用性。这取决于几个因素,如执行时间、内存占用和质量。一个方法的质量,我们需要用不同的度量来评估。这里的主要问题是,这些类通常不是平均分布的。因此,我们必须以某种方式解释这一点。我们可以通过增加背景类的数量来做到这一点。然后,我们可以确定,例如,类别 I 的像素被推断为属于类别 j 的概率。例如,p 下标 I,I 将表示真阳性的数量。

两个流行的评估指标。来自深度学习讲座CC BY 4.0 下的图片。

这就引出了几个度量标准,例如,像素精度,即正确分类的像素数量与像素总数之间的比率,以及平均像素精度,即每类基础上正确分类的像素的平均比率。

两个更受欢迎的指标。 CC 下的图片来自深度学习讲座的 4.0 。

实际上,评估分割更常见的是平均交集/并集,即两个集合的交集和并集之间的比率,以及一个并集的频率加权交集,这是一个平衡版本,其中还将类频率纳入该度量。因此,有了这些衡量标准,我们就可以知道什么是好的细分。

我们可以重用分类网络进行图像分割吗?来自深度学习讲座的 4.0CC 下的图片。

然后,我们继续,当然,我们遵循使用完全卷积网络进行分段的思想。到目前为止,如果我们一直使用全卷积网络,我们基本上有一个高维输入——图像——然后我们使用这个 CNN 进行特征提取。然后,输出实际上是不同类别的分布。因此,我们基本上有了一个编码类别概率的向量。

传统的全卷积网络只允许很差的空间分辨率。 CC 下的图片来自深度学习讲座的 4.0 。

所以,你也可以把它转换成一个完全卷积的神经网络,然后从本质上解析整个图像,并把它转换成热图。所以,当我们谈到不同的激活时,我们已经在可视化中看到了类似的想法。我们基本上也可以遵循这条解释线,然后我们会得到一个非常低维非常粗糙的“虎斑猫”类的热图。当然,这是一种可行的方法,但是您无法非常详细地识别属于该特定类的所有像素。因此,你必须做的是,以某种方式将分割或类别信息恢复到原始图像分辨率。

编码器-解码器网络似乎有希望用于图像分割。编码器分支本质上是对类进行编码。来自深度学习讲座CC BY 4.0 下的图片。

在这里,关键的想法是不只是使用 CNN 作为编码器,但你也可以使用解码器。因此,我们最终得到一个类似 CNN 的结构,你甚至可以说是沙漏,其中有一个编码器和一个解码器,再次进行上采样。顺便说一下,这不是一个自动编码器,因为输入是图像,但输出是分段掩码。网络的编码器部分本质上是一个 CNN,这与我们已经谈论了很多的技术非常相似。

解码器分支将分类结果提升回原始图像分辨率。 CC 下的图片来自深度学习讲座的 4.0 。

所以,另一方面,我们需要一个解码器。该解码器然后被用于再次对信息进行上采样。实际上有几种方法可以做到这一点。早期的一个是 Long 等人的全卷积网络[13]。还有 SegNet [1],我认为最流行的是 U-net [21]。这也是我暗示过的有很多参考文献的论文。所以,U-net 真的很受欢迎,你可以看到你可以每天查看引用计数。

为了再次提高分辨率,我们需要上采样技术。 CC 下的图片来自深度学习讲座的 4.0 。

好吧,让我们讨论一下我们该怎么做。主要问题是上采样部分。所以在这里,我们希望有一个解码器,以某种方式创建一个像素预测。可能有不同的选项,例如,取消轮询。你也可以转置卷积,这实际上不是使用池的概念,而是使用卷积的概念,而是转置,从而提高分辨率,而不是进行二次采样。

最近邻和甲床上采样。来自深度学习讲座CC BY 4.0 下的图片。

那么,让我们更详细地看看这些上采样技术。当然,您可以做一些类似最近邻插值的事情。在那里,你只需简单地获取低分辨率信息,然后通过获取最近的邻居来解除轮询。有一个钉床,它只接受一个值,你只需要把它放在其中一个位置。所以,剩下的图像看起来像一床钉子。这里的想法是,当然,你只是把信息放在你知道它属于的位置。然后,剩余的缺失条目应该由一个可学习的部分来填充,然后在网络的后续步骤中引入该可学习的部分。

记住池索引是使用上下文信息的一种方式。 CC 下的图片来自深度学习讲座的 4.0 。

另一种方法是使用最大汇集指数。因此,这里的想法是,在编码器路径中,执行最大池化,并保存池化实际发生位置的索引。然后,您可以在上采样步骤中再次获取该信息,并在最大值出现的位置准确写入该信息。这非常类似于最大池的反向传播步骤。

转置卷积允许可训练的上采样。 CC 下的图片来自深度学习讲座的 4.0 。

当然,也有像转置卷积这样可以学习的技术。在这里,您将学习上采样,有时也称为去卷积。实际上,对于输入中的每一个像素,滤波器会在输出中移动两个像素。您可以使用步幅控制更高的上采样。让我们看看这个例子。我们有一个单独的像素,然后被取消。在这里,你产生这个 3 x 3 转置卷积。我们用两个步幅展示它。然后,我们移动到下一个像素,你可以看到一个重叠区域出现在这种情况下。在那里,你必须对这个重叠区域做些什么。例如,您可以简单地将它们相加,并希望在随后的处理中,您的网络学会如何处理上采样步骤中的这种不一致性。

最好避免重叠配置。来自深度学习讲座CC BY 4.0 下的图片。

在本例中,我们可以继续对其他两个像素执行此操作。然后,你看到我们有这个十字形区域。因此,当内核大小不能被步幅整除时,转置卷积会导致不均匀的重叠。这些轴上不均匀的重叠成倍增加,他们创造了这个典型的棋盘格人工制品。原则上,如前所述,您应该能够学习如何在后续层中再次移除那些工件。在实践中,它会导致冲突,我们建议完全避免它。

避免棋盘状伪影的策略。 CC 下的图片来自深度学习讲座的 4.0 。

那么,如何避免这种情况呢?嗯,你选择一个合适的内核大小。您选择内核大小的方式是它可以被步幅整除。然后,您还可以从卷积中进行单独的上采样来计算特征。例如,您可以使用神经网络或线性插值来调整图像的大小。然后,添加一个卷积层。所以,这是一种典型的方法。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。

好吧。到目前为止,我们已经了解了执行图像分割所需的所有基本步骤。实际上,在下一个视频中,我们将讨论如何集成编码器和解码器,以获得良好的分段蒙版。我可能已经告诉你了,有一个你必须要做的特殊技巧。如果不使用这一招,很可能得不到很好的分割结果。所以,请继续关注下一个视频,因为在那里你会看到你如何做好细分。您将了解这些高级分段技术的所有细节。非常感谢大家的收听,下期视频再见。拜拜。

胸部 x 光的分割结果。使用 gifify 创建的图像。来源: YouTube

如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTubeTwitter脸书LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客

参考

[1] Vijay Badrinarayanan, Alex Kendall, and Roberto Cipolla. “Segnet: A deep convolutional encoder-decoder architecture for image segmentation”. In: arXiv preprint arXiv:1511.00561 (2015). arXiv: 1311.2524.
[2] Xiao Bian, Ser Nam Lim, and Ning Zhou. “Multiscale fully convolutional network with application to industrial inspection”. In: Applications of Computer Vision (WACV), 2016 IEEE Winter Conference on. IEEE. 2016, pp. 1–8.
[3] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs”. In: CoRR abs/1412.7062 (2014). arXiv: 1412.7062.
[4] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs”. In: arXiv preprint arXiv:1606.00915 (2016).
[5] S. Ren, K. He, R. Girshick, et al. “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”. In: vol. 39. 6. June 2017, pp. 1137–1149.
[6] R. Girshick. “Fast R-CNN”. In: 2015 IEEE International Conference on Computer Vision (ICCV). Dec. 2015, pp. 1440–1448.
[7] Tsung-Yi Lin, Priya Goyal, Ross Girshick, et al. “Focal loss for dense object detection”. In: arXiv preprint arXiv:1708.02002 (2017).
[8] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, et al. “A Review on Deep Learning Techniques Applied to Semantic Segmentation”. In: arXiv preprint arXiv:1704.06857 (2017).
[9] Bharath Hariharan, Pablo Arbeláez, Ross Girshick, et al. “Simultaneous detection and segmentation”. In: European Conference on Computer Vision. Springer. 2014, pp. 297–312.
[10] Kaiming He, Georgia Gkioxari, Piotr Dollár, et al. “Mask R-CNN”. In: CoRR abs/1703.06870 (2017). arXiv: 1703.06870.
[11] N. Dalal and B. Triggs. “Histograms of oriented gradients for human detection”. In: 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition Vol. 1. June 2005, 886–893 vol. 1.
[12] Jonathan Huang, Vivek Rathod, Chen Sun, et al. “Speed/accuracy trade-offs for modern convolutional object detectors”. In: CoRR abs/1611.10012 (2016). arXiv: 1611.10012.
[13] Jonathan Long, Evan Shelhamer, and Trevor Darrell. “Fully convolutional networks for semantic segmentation”. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015, pp. 3431–3440.
[14] Pauline Luc, Camille Couprie, Soumith Chintala, et al. “Semantic segmentation using adversarial networks”. In: arXiv preprint arXiv:1611.08408 (2016).
[15] Christian Szegedy, Scott E. Reed, Dumitru Erhan, et al. “Scalable, High-Quality Object Detection”. In: CoRR abs/1412.1441 (2014). arXiv: 1412.1441.
[16] Hyeonwoo Noh, Seunghoon Hong, and Bohyung Han. “Learning deconvolution network for semantic segmentation”. In: Proceedings of the IEEE International Conference on Computer Vision. 2015, pp. 1520–1528.
[17] Adam Paszke, Abhishek Chaurasia, Sangpil Kim, et al. “Enet: A deep neural network architecture for real-time semantic segmentation”. In: arXiv preprint arXiv:1606.02147 (2016).
[18] Pedro O Pinheiro, Ronan Collobert, and Piotr Dollár. “Learning to segment object candidates”. In: Advances in Neural Information Processing Systems. 2015, pp. 1990–1998.
[19] Pedro O Pinheiro, Tsung-Yi Lin, Ronan Collobert, et al. “Learning to refine object segments”. In: European Conference on Computer Vision. Springer. 2016, pp. 75–91.
[20] Ross B. Girshick, Jeff Donahue, Trevor Darrell, et al. “Rich feature hierarchies for accurate object detection and semantic segmentation”. In: CoRR abs/1311.2524 (2013). arXiv: 1311.2524.
[21] Olaf Ronneberger, Philipp Fischer, and Thomas Brox. “U-net: Convolutional networks for biomedical image segmentation”. In: MICCAI. Springer. 2015, pp. 234–241.
[22] Kaiming He, Xiangyu Zhang, Shaoqing Ren, et al. “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”. In: Computer Vision — ECCV 2014. Cham: Springer International Publishing, 2014, pp. 346–361.
[23] J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, et al. “Selective Search for Object Recognition”. In: International Journal of Computer Vision 104.2 (Sept. 2013), pp. 154–171.
[24] Wei Liu, Dragomir Anguelov, Dumitru Erhan, et al. “SSD: Single Shot MultiBox Detector”. In: Computer Vision — ECCV 2016. Cham: Springer International Publishing, 2016, pp. 21–37.
[25] P. Viola and M. Jones. “Rapid object detection using a boosted cascade of simple features”. In: Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision Vol. 1. 2001, pp. 511–518.
[26] J. Redmon, S. Divvala, R. Girshick, et al. “You Only Look Once: Unified, Real-Time Object Detection”. In: 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). June 2016, pp. 779–788.
[27] Joseph Redmon and Ali Farhadi. “YOLO9000: Better, Faster, Stronger”. In: CoRR abs/1612.08242 (2016). arXiv: 1612.08242.
[28] Fisher Yu and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions”. In: arXiv preprint arXiv:1511.07122 (2015).
[29] Shuai Zheng, Sadeep Jayasumana, Bernardino Romera-Paredes, et al. “Conditional Random Fields as Recurrent Neural Networks”. In: CoRR abs/1502.03240 (2015). arXiv: 1502.03240.
[30] Alejandro Newell, Kaiyu Yang, and Jia Deng. “Stacked hourglass networks for human pose estimation”. In: European conference on computer vision. Springer. 2016, pp. 483–499.

分割和对象检测—第 2 部分

原文:https://towardsdatascience.com/segmentation-and-object-detection-part-2-a334b91255f1?source=collection_archive---------45-----------------------

FAU 讲座笔记关于深度学习

跳过连接和更多

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座

这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!

航行

上一讲 / 观看本视频 / 顶级 / 下一讲

用于细胞分割的 U-net。使用 gifify 创建的图像。来源: YouTube

欢迎回到深度学习!所以今天,我们想谈谈更高级的图像分割方法。让我们看看我们的幻灯片。你可以在这里看到这是图像分割和物体检测系列讲座视频的第二部分。

如何整合语境知识? CC 下的图片来自深度学习讲座的 4.0 。

现在,我们需要知道的关键思想是如何整合上下文知识。仅仅使用我们在上一个视频中谈到的这种编码器-解码器结构不足以获得良好的分割。关键的概念是,你必须以某种方式告诉你的方法在哪里发生了什么,以便得到一个好的分段掩码。你需要平衡本地和全球信息。当然,这是非常重要的,因为局部信息对于给出好的像素精度是至关重要的,并且全局上下文对于正确地找出类是重要的。CNN 通常在这种平衡中挣扎。因此,我们现在需要一些关于如何整合这些上下文信息的好主意。

Long 等人在[13]中展示了整合上下文的第一个想法。来自深度学习讲座CC BY 4.0 下的图片。

现在,Long 等人展示了这样做的第一种方法。他们本质上使用由可学习的转置卷积组成的上采样。关键的想法是,您想要添加链接,将最终预测与更精细的步骤中的先前较低层相结合。此外,他在池层之后进行了 1x1 卷积,然后将预测相加,以使用全局结构进行局部预测。因此,网络拓扑是一个有向无环图,从较低层到较高层有跳跃连接。因此,您可以细化一个粗略的分段。

Long 等人对早期阶段知识进行了补充和整合。 CC 下的图片来自深度学习讲座的 4.0 。

所以,让我们更详细地看看这个想法。你现在可以看到,如果你在右下角有地面实况,这有很高的分辨率。如果你简单地使用 CNN 和上采样,你会得到一个非常粗糙的分辨率,如左边所示。那么,龙等人的提议是什么呢?他们建议使用来自先前下采样步骤的信息,该步骤仍具有较高的分辨率,并在解码器分支内使用该信息,通过求和产生分辨率更高的图像。当然,您可以在解码器分支中再次这样做。你可以看到,这样我们可以对分段进行上采样,并重用来自编码器分支的信息,以产生更好的高分辨率结果。现在,您可以引入这些跳过连接,它们可以产生比仅使用解码器和上采样信息好得多的分段。

SegNet [1]重用了最大池索引。 CC 下的图片来自深度学习讲座的 4.0 。

你看,整合背景知识是关键。在 SegNet 中,这里采用了不同的方法。还有这种卷积编码器-解码器结构。这里,关键思想是在上采样步骤中,在下采样步骤中重用来自最大池的信息,以便获得分辨率更高的解码。这已经是一个整合上下文知识的好主意了。

Ronneberger 在[21]中引入了跳过连接。来自深度学习讲座CC BY 4.0 下的图片。

然后,一个更好的想法在 U-net 中展示出来。这里,网络由编码器分支组成,该分支是捕获上下文的收缩路径。解码器分支为定位进行对称扩展。因此,编码器遵循 CNN 的典型结构。解码器现在包括上采样步骤和相应编码器步骤的各个层的先前特征图的连接。因此,训练策略也依赖于数据扩充。有非刚性的变形、旋转和平移被用来给 U-net 带来额外的性能提升。

U-net 设计。 CC 下的图片来自深度学习讲座的 4.0 。

你可以说 U-net 本质上是最先进的图像分割方法。这也是它有这个名字的原因。源于其形。你可以看到你得到了这个 U 型结构,因为你在精细层次上有很高的分辨率。然后降采样到较低的分辨率。解码器分支再次对所有内容进行上采样。这里的关键信息是连接解码器和编码器的两个相应级别的跳跃连接。这样你可以得到非常非常好的图像分割。训练非常简单,这篇论文已经被引用了数千次(2020 年 8 月 11 日:16471 次引用)。每天你都可以查看引用次数,它已经增加了。Olaf Ronneberger 能够在这里发表一篇非常重要的论文,它主宰了整个图像分割领域。

U-net 的变体。来自深度学习讲座的 4.0CC 下的图片。

您可以看到还有许多其他方法。它们可以通过 U-net 实现。所以他们可以使用扩张卷积等等。已经提出了许多这些非常小的变化,它们可能对特定的任务有用,但是对于一般的图像分割,U-net 已经被证明仍然优于这样的方法。尽管如此,仍然有一些东西可以使用,如扩张卷积,有网络堆栈可以非常有益,还有多尺度网络,然后甚至进一步深入到在不同尺度上使用图像的想法。您还可以做一些事情,比如将上下文建模推迟到另一个网络。然后,你也可以加入循环神经网络。同样非常好的想法是使用一个条件随机场来改进产生的分割图。

扩张卷积也可以应用于 U-net。 CC 下的图片来自深度学习讲座的 4.0 。

我们这里有一些额外的方法,这样你就能明白我们在说什么。这里的扩大卷积,是你想要使用我们已经讨论过的那些萎缩卷积的想法。因此,我们的想法是,在不损失分辨率的情况下,使用扩张卷积来支持感受野的指数级扩张。然后,引入控制上采样因子的膨胀率 L。然后你把它叠加在上面,这样你就能使感受野呈指数增长,而滤波器的参数数量呈线性增长。因此,在需要进行大范围放大的特定应用中,这非常有用。所以,这真的取决于你的应用。

在各种分割方法中已经采用了扩展卷积。来自深度学习讲座CC BY 4.0 下的图片。

这方面的例子有 DeepLab、ENet 和[28]中的多尺度上下文聚合模块。当然,主要问题是没有有效的实现。因此,这种好处还不清楚。

堆叠沙漏模块。 CC 下的图片来自深度学习讲座的 4.0 。

我想向大家展示的另一种方法是所谓的堆叠沙漏网络。所以,这里的想法是,你使用一个非常类似于 U-net 的东西,但是你要在 skip 连接中加入一个额外的可训练部分。所以,这基本上是主要的想法。

堆叠模块导致堆叠沙漏网络。来自深度学习讲座的 4.0CC 下的图片。

然后,您可以使用这个沙漏模块,并将其堆叠在彼此后面。因此,基本上有多个细化步骤,并且总是返回到原始分辨率。你可以插入第二个网络,本质上是一种伪像校正网络。现在,这种沙漏网络方法的真正好处是,你可以回到原来的分辨率。

卷积姿态机器还将几个模块堆叠在彼此之上,以实现姿态跟踪。这也可以与分段相结合。使用 gifify 创建的图像。来源: YouTube

假设你同时在预测几门课。然后,你会得到几个不同类别的分段掩码。这个想法可以在一个叫做卷积姿态机的东西中被提取出来。在回旋摆姿机中,你使用沙漏连接的区域,这里你有一个 U 形网基本上叠在另一个 U 形网的上面。在这一层,您还可以使用每个类的结果分割图,以便相互通知。因此,您可以使用在图像中检测到的其他事物的上下文信息来控制这种细化。在卷积姿态机器中,你为身体模型关节的姿态检测做那件事。当然,如果你有左膝关节和右膝关节以及身体的其他关节,关于其他关节的信息有助于解码正确的位置。

X 射线变换不变标志检测Bastian Bier。来自深度学习讲座的 4.0CC 下的图片。

这个想法也被我的同事 Bastian Bier 用于在 x 射线投影分析中检测解剖标志。我在这里放一个小视频。您已经在简介中看到了这一点,现在您终于有了理解该方法所需的所有上下文。因此,这里有一种非常类似于卷积姿态机器的方法,然后开始通知地标彼此的方向和位置,以获得更好的检测结果。

条件随机场也可以作为层引入。 CC 下的图片来自深度学习讲座的 4.0 。

那还有什么?我已经暗示了条件随机场。这里的想法是使用条件随机场来优化输出。因此,像素被建模为随机场中的一个节点。这些基于像素对的术语非常有趣,因为它们可以捕捉长程相关性和精细的局部信息。

结果使用通用报告格式。来自深度学习讲座CC BY 4.0 下的图片。

如果你看到这里的输出,这是来自 DeepLab 的。在这里,您可以看到条件随机场的迭代优化如何帮助改进分割。因此,你也可以像在[4]中那样将它与阿图斯卷积结合起来。你甚至可以用递归神经网络来模拟条件随机场,如参考文献[29]所示。这也允许整个条件随机场的端到端训练。

对抗性损失也适用于图像分割。 CC 下的图片来自深度学习讲座的 4.0 。

还有几个高级主题我仍然想暗示一下。当然,你也可以带着损失工作。到目前为止,我们只看到了分割损失本身,但是当然,您也可以混合和匹配我们在本课程中已经看到的以前的想法。例如,你可以使用 GAN 来增加你的损失。这里的想法是,你可以创建一个分割器。然后,您可以使用分割器的输出作为 GAN 类型鉴别器的输入。鉴别器现在的任务是判断这是自动分段还是手动分段。那么,这可以被用作一种由生成性对抗网络的思想所启发的额外的对抗损失。你会发现,在文学作品中,这通常被称为对抗性的失败。

对抗性损失通常与分割损失相结合。 CC 下的图片来自深度学习讲座的 4.0 。

那么,这是如何实现的呢?这个想法是,如果你有一个数据集给定的 N 个训练图像和相应的标签图,那么你可以建立以下损失函数:这本质上是多类交叉熵损失,然后你把对你的分割掩模起作用的对抗性损失放在上面。所以在这里,你可以用事实标签和欺骗鉴别器来训练你的分段。这本质上就是一种带有对抗性任务的多任务学习方法。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座CC BY 4.0 下的图片。

好吧。所以,今天的短片到此结束。你可以看到,我们已经了解了如何构建良好的细分网络的关键理念。尤其是,U-net 是您应该了解的关键概念之一。既然我们已经讨论了分割网络,我们可以在下节课讨论对象检测以及如何快速实现它。所以,这是图像解读的另一面。我们还将能够找出图像中不同实例的实际位置。所以我希望,你喜欢这个小视频,我期待着在下一个视频中见到你。非常感谢,再见。

如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTubeTwitter脸书LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客

参考

[1] Vijay Badrinarayanan, Alex Kendall, and Roberto Cipolla. “Segnet: A deep convolutional encoder-decoder architecture for image segmentation”. In: arXiv preprint arXiv:1511.00561 (2015). arXiv: 1311.2524.
[2] Xiao Bian, Ser Nam Lim, and Ning Zhou. “Multiscale fully convolutional network with application to industrial inspection”. In: Applications of Computer Vision (WACV), 2016 IEEE Winter Conference on. IEEE. 2016, pp. 1–8.
[3] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs”. In: CoRR abs/1412.7062 (2014). arXiv: 1412.7062.
[4] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs”. In: arXiv preprint arXiv:1606.00915 (2016).
[5] S. Ren, K. He, R. Girshick, et al. “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”. In: vol. 39. 6. June 2017, pp. 1137–1149.
[6] R. Girshick. “Fast R-CNN”. In: 2015 IEEE International Conference on Computer Vision (ICCV). Dec. 2015, pp. 1440–1448.
[7] Tsung-Yi Lin, Priya Goyal, Ross Girshick, et al. “Focal loss for dense object detection”. In: arXiv preprint arXiv:1708.02002 (2017).
[8] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, et al. “A Review on Deep Learning Techniques Applied to Semantic Segmentation”. In: arXiv preprint arXiv:1704.06857 (2017).
[9] Bharath Hariharan, Pablo Arbeláez, Ross Girshick, et al. “Simultaneous detection and segmentation”. In: European Conference on Computer Vision. Springer. 2014, pp. 297–312.
[10] Kaiming He, Georgia Gkioxari, Piotr Dollár, et al. “Mask R-CNN”. In: CoRR abs/1703.06870 (2017). arXiv: 1703.06870.
[11] N. Dalal and B. Triggs. “Histograms of oriented gradients for human detection”. In: 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition Vol. 1. June 2005, 886–893 vol. 1.
[12] Jonathan Huang, Vivek Rathod, Chen Sun, et al. “Speed/accuracy trade-offs for modern convolutional object detectors”. In: CoRR abs/1611.10012 (2016). arXiv: 1611.10012.
[13] Jonathan Long, Evan Shelhamer, and Trevor Darrell. “Fully convolutional networks for semantic segmentation”. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015, pp. 3431–3440.
[14] Pauline Luc, Camille Couprie, Soumith Chintala, et al. “Semantic segmentation using adversarial networks”. In: arXiv preprint arXiv:1611.08408 (2016).
[15] Christian Szegedy, Scott E. Reed, Dumitru Erhan, et al. “Scalable, High-Quality Object Detection”. In: CoRR abs/1412.1441 (2014). arXiv: 1412.1441.
[16] Hyeonwoo Noh, Seunghoon Hong, and Bohyung Han. “Learning deconvolution network for semantic segmentation”. In: Proceedings of the IEEE International Conference on Computer Vision. 2015, pp. 1520–1528.
[17] Adam Paszke, Abhishek Chaurasia, Sangpil Kim, et al. “Enet: A deep neural network architecture for real-time semantic segmentation”. In: arXiv preprint arXiv:1606.02147 (2016).
[18] Pedro O Pinheiro, Ronan Collobert, and Piotr Dollár. “Learning to segment object candidates”. In: Advances in Neural Information Processing Systems. 2015, pp. 1990–1998.
[19] Pedro O Pinheiro, Tsung-Yi Lin, Ronan Collobert, et al. “Learning to refine object segments”. In: European Conference on Computer Vision. Springer. 2016, pp. 75–91.
[20] Ross B. Girshick, Jeff Donahue, Trevor Darrell, et al. “Rich feature hierarchies for accurate object detection and semantic segmentation”. In: CoRR abs/1311.2524 (2013). arXiv: 1311.2524.
[21] Olaf Ronneberger, Philipp Fischer, and Thomas Brox. “U-net: Convolutional networks for biomedical image segmentation”. In: MICCAI. Springer. 2015, pp. 234–241.
[22] Kaiming He, Xiangyu Zhang, Shaoqing Ren, et al. “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”. In: Computer Vision — ECCV 2014. Cham: Springer International Publishing, 2014, pp. 346–361.
[23] J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, et al. “Selective Search for Object Recognition”. In: International Journal of Computer Vision 104.2 (Sept. 2013), pp. 154–171.
[24] Wei Liu, Dragomir Anguelov, Dumitru Erhan, et al. “SSD: Single Shot MultiBox Detector”. In: Computer Vision — ECCV 2016. Cham: Springer International Publishing, 2016, pp. 21–37.
[25] P. Viola and M. Jones. “Rapid object detection using a boosted cascade of simple features”. In: Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision Vol. 1. 2001, pp. 511–518.
[26] J. Redmon, S. Divvala, R. Girshick, et al. “You Only Look Once: Unified, Real-Time Object Detection”. In: 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). June 2016, pp. 779–788.
[27] Joseph Redmon and Ali Farhadi. “YOLO9000: Better, Faster, Stronger”. In: CoRR abs/1612.08242 (2016). arXiv: 1612.08242.
[28] Fisher Yu and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions”. In: arXiv preprint arXiv:1511.07122 (2015).
[29] Shuai Zheng, Sadeep Jayasumana, Bernardino Romera-Paredes, et al. “Conditional Random Fields as Recurrent Neural Networks”. In: CoRR abs/1502.03240 (2015). arXiv: 1502.03240.
[30] Alejandro Newell, Kaiyu Yang, and Jia Deng. “Stacked hourglass networks for human pose estimation”. In: European conference on computer vision. Springer. 2016, pp. 483–499.

分割和对象检测—第 3 部分

原文:https://towardsdatascience.com/segmentation-and-object-detection-part-3-abb4ec936fa?source=collection_archive---------43-----------------------

FAU 讲座笔记关于深度学习

一家地区性有线电视新闻网

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座

这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!

航行

上一讲 / 观看本视频 / 顶级/下一讲

野外物体检测。使用 gifify 创建的图像。来源: YouTube

欢迎回到深度学习!所以今天,我们想多谈谈物体检测的概念。我们将从对象检测的一个小动机和如何实际执行的一些关键想法开始。

也可以使用对象检测方法来检测猫。 CC 下的图片来自深度学习讲座的 4.0 。

那么,让我们来看看我们的幻灯片。你看,这已经是我们关于分割和物体检测的短片系列的第三部分了。现在,主题是物体检测。好吧,让我们稍微激励一下。这个想法——你还记得——是我们想要定位物体并对它们进行分类。所以,我们想知道猫在图像中的位置,我们想知道它们是否真的是猫。这通常通过生成关于边界框的假设来解决,然后对这些框进行重新采样,并应用分类器。因此,这些方法的主要区别在于如何组合和替换这些步骤,以实现更高的速度或精度。

包围盒是物体检测的关键。来自深度学习讲座CC BY 4.0 下的图片。

我们也可以看看这个平面例子。当然,我们正在寻找边界框,边界框通常被定义为完全包含所讨论的对象的最小的框。然后,这通常被定义为具有宽度 w 和高度 h 以及边界框的一些分类器置信度的左上角。你可以看到,我们也可以用它来检测整个飞机,或者我们也可以用它来检测飞机的一部分。

对于特殊的应用,存在传统的方法。来自深度学习讲座的 4.0CC 下的图片。

这实际上是我们已经有了不同成功故事的悠久历史的事情。一个非常早期的继任者是 Viola 和 Jones 算法,这是最早的真正有效的人脸检测器之一。这里你可以看到例子。这是使用哈尔特征,然后这些哈尔特征被用于一种提升级联,以便非常快速地检测人脸。所以,它使用了大量可以高效计算的特征。然后,在提升级联中,他们将只选择最有可能在给定位置检测到人脸的特征。然后用所谓的梯度方向直方图和经典方法对此进行了改进。你总是有一个好的特征提取加上一些有效的分类。当时,支持向量机非常普遍。

常见深度学习对象检测方法综述。 CC 下的图片来自深度学习讲座的 4.0 。

当然,也有基于神经网络的方法。你可以用一个预先训练好的 CNN 很容易地做到这一点。因此,您可以简单地使用滑动窗口方法,然后通过 CNN 检测每个可能的窗口。有像 RCNN 这样的区域提议 CNN,先找到感兴趣的图像区域,然后用我们的 CNN 进行分类。我们将在下一个视频中讨论单次检测器,它可以进行联合检测和分类。我认为最著名的例子之一是 YOLO——你只需看一次——我们在介绍中已经有了这个例子。这是一种非常好的方法,可以实时完成所有这些检测方法。

为什么。不就是用推拉窗吗?来自深度学习讲座CC BY 4.0 下的图片。

嗯,在滑动窗口方法中,你可以简单地拿起你预先训练好的 CNN,在图像上移动它。当你发现一个高度自信的领域时,你可以说:“好的。有一张脸,我想检测这张脸!”现在,这里最大的缺点是,你不仅要检测人脸,而且人脸可能有不同的分辨率。所以,你要在多个分辨率上重复这个过程。然后,您已经看到逐片检测会产生大量的补丁。你要做大量的分类。所以,这可能不是我们想要走的路。当然,一个好处是我们不需要重新训练。在这种情况下,我们可以简单地使用我们训练过的分类网络。但它的计算效率非常低,我们希望寻找一些如何更有效地做到这一点的想法。

更好的方法是完全卷积处理。 CC 下的图片来自深度学习讲座的 4.0 。

一个想法是,当然,你用它与完全卷积神经网络,并理解以下方法。所以,我们可以考虑如何将一个完全连接的层应用到一个任意形状的张量。一个想法是你将激活扁平化,然后运行你的全连接层,你可以得到一个分类结果。相反,您可以重塑权重,然后使用卷积。这将产生完全相同的结果。我们在讨论逐个卷积时已经讨论过了。现在,这里好的性质是,如果我们遵循这个想法,我们也可以处理任意形状的空间输入大小。通过使用卷积,我们还将产生更大的输出大小。所以,我们有点摆脱了移动窗口的方法,但我们仍然有一个问题,我们必须查看不同的比例,以便找到所有有趣的对象。

区域 CNN (RCNN)综述。来自深度学习讲座CC BY 4.0 下的图片。

这就是为什么人们一直在关注基于区域的检测器。因此,我们知道 CNN 是强大的分类器,全卷积神经网络有助于提高效率。但他们还是有些蛮力。那么,我们能做些什么呢?我们可以通过像我们的眼睛一样只考虑感兴趣的区域来提高效率。所以,这就引出了 RCNN,区域性的 CNN。这里,您有一个多步骤方法,可以生成区域建议和选择性搜索。然后,将区域建议的内容分类到一个优化的边界框中。

首先,我们必须找到区域。 CC 下的图片来自深度学习讲座的 4.0 。

让我们更详细地看一下这个问题。在这里,我们的区域建议,你通过一组具有相似纹理和颜色的像素来生成这些候选对象。然后你产生几千个目标提案,比如每个图像两千个。您会注意到,这比可能的窗口数量小得多。你基本上是基于一种粗略的分割形式。

RCNN 使用经典的超像素方法。来自深度学习讲座CC BY 4.0 下的图片。

在最初的 RCNN 论文中,他们实际上使用了一种叫做超像素的方法。超像素允许你生成更小和更大的区域。所以,你可以看到我们如何从左到右增加区域大小。然后,我们可以使用这些区域,以便用另一个检测器找到感兴趣的区域。然后,这些感兴趣的区域可以进入分类器的下一阶段。

其次是美国有线电视新闻网专题敲诈加 SVM 分类。 CC 下的图片来自深度学习讲座的 4.0 。

因此,在第二阶段,一旦我们有了这些区域,我们基本上就有了一个卷积神经网络。一方面,这产生了细化边界框的框回归。另一方面,这也作为一种表示学习提供给支持向量机进行最终决策。因此,这比我们之前在 2013 年那个时候看到的要好,但仍然很慢,而且不是端到端的。所以,如果我们想加速这个过程,我们会发现 RCNN 仍然存在问题。

为什么我们必须单独处理每个包围盒? CC 下的图片来自深度学习讲座的 4.0 。

因为我们对每个地区的提案都进行了全面的审核,这意味着这种培训很慢,推理也很慢。我们可以在计算特征图时共享计算,因为我们一直在做相同或相似的计算。然后,为了提高推理速度,关键思想是在特征图上使用区域建议。

空间金字塔池允许我们只运行一遍 CNN 特征提取。它将检测到的 ROI 映射到最大汇集空间。来自深度学习讲座CC BY 4.0 下的图片。

所以,你要做的是通过网络传递整个图像来生成特征地图。然后,将区域建议应用到最后一个卷积层。因此,您必须调整它们的大小才能应用到图层。您可以这样做,因为您可以通过计算合并步骤来重新格式化检测到的超像素,从而预测该特定图层的大小。分类 CNN 具有固定的输入大小。因此,您使用所谓的空间金字塔池,通过最大池将其重新采样为固定大小。最初,这是用三种不同的窗口大小和跨度完成的。然后,你基本上共享了这种基于图像的计算,这大大加快了推理的速度。你已经可以将推论加速 24 倍到 104 倍。尽管如此,你有缓慢的训练,这不是端到端的。

重新绑定到固定的输入大小是通过池化实现的。 CC 下的图片来自深度学习讲座的 4.0 。

一个原因是,我们有这个区域提案库,您可以根据区域标识中的这些建议进行汇总。你可以简单地用最大池来实现。如果你只是在一个固定的采样中做,你在这一步会丢失一些信息。

快速 RCNN 的剩余问题。来自深度学习讲座CC BY 4.0 下的图片。

此外,这种空间金字塔池用于一个输出地图。他们有一些想法来更好地选择小批量的样品。你可以随机抽取 128 个均匀的感兴趣区域,如果你这样做,那么特征图通常不会重叠。相反,您也可以进行分层采样,然后从几幅图像中进行采样,但会有许多 ROI,比如 64 个。然后,你产生一个高度重叠。将支持向量机和回归替换为用于分类的 softmax 图层和用于边界框微调的回归图层。这将导致多任务丢失,并且总的来说,训练比 RCNN 快 9 倍。但我们仍然不是实时的。因此,除了投资回报提案,我们几乎是端到端的。

家居用品也可以在货架上检测到。未来的超市会使用这种技术吗?使用 gifify 创建的图像。来源: YouTube

为了进一步加速,你可以做的就是所谓的更快的 RCNN。这里的关键思想是,您添加一个区域建议网络,输入现在是生成的特征地图,输出是我们的区域建议。

使用区域提议网络,我们可以端到端地训练我们的 RCNN。来自深度学习讲座的 4.0CC 下的图片。

这集成到快速 RCNN 中。这里的想法是用不同的比例和纵横比定义锚定框,通常是三个比例和三个纵横比。这导致了有效的多尺度。因此,图像大小和过滤器大小都不需要改变。您可以获得大约 4000 个盒子参数和 2000 个分数,因为您拥有用于对象/非对象检测的 softmax。

快速 RCNN 的配置。 CC 下的图片来自深度学习讲座的 4.0 。

这样,你就有了一个完全卷积的端到端系统,但这个系统仍然不是实时的。那么,让我们来比较一下这些方法。在这里,您可以看到基于 RCNN 的不同架构的概述。

RCNN、快速 RCNN 和更快 RCNN 的比较。来自深度学习讲座CC BY 4.0 下的图片。

你可以看到 RCNN 本身也在进行选择性搜索。然后,根据产生感兴趣区域的选择性搜索,调整大小。你使用一个 CNN,然后由支持向量机处理,你还做了一个包围盒回归,以完善包围盒。因此,快速 RCNN 在完全卷积方法中使用一个 CNN 进行特征提取。一步就可以制作出完整的特征地图。您仍然可以进行选择性搜索,然后生成感兴趣区域,您可以在空间金字塔池中使用它们,以便为完全连接的图层提供信息。然后,你有包围盒检测头和正在做这种多任务预测的类头。在更快的 RCNN 中,你真正进入了一个端到端的系统。这里,你有 CNN 特征提取。从这些提取的特征中,你做区域提议。随后进行 ROI 合并,然后得到边界框预测头和类头,这在训练、端到端方面快得多,在推理方面也快得多。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。

尽管如此,我们仍然不能进行实时分类,这就是为什么我们下次要讨论能够做到这一点的单次检测器。我真的希望你喜欢这个视频,我期待着在下一个视频中见到你。拜拜。

这个皮卡丘探测器不会帮你玩 Pokemon Go。使用 gifify 创建的图像。来源: YouTube

如果你喜欢这篇文章,你可以在这里找到更多的文章,在这里找到更多关于机器学习的教育材料,或者看看我们的深度 学习 讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube、Twitter、脸书、LinkedIn 或 T21。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中生成文字记录,试试自动博客

参考

[1] Vijay Badrinarayanan, Alex Kendall, and Roberto Cipolla. “Segnet: A deep convolutional encoder-decoder architecture for image segmentation”. In: arXiv preprint arXiv:1511.00561 (2015). arXiv: 1311.2524.
[2] Xiao Bian, Ser Nam Lim, and Ning Zhou. “Multiscale fully convolutional network with application to industrial inspection”. In: Applications of Computer Vision (WACV), 2016 IEEE Winter Conference on. IEEE. 2016, pp. 1–8.
[3] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs”. In: CoRR abs/1412.7062 (2014). arXiv: 1412.7062.
[4] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs”. In: arXiv preprint arXiv:1606.00915 (2016).
[5] S. Ren, K. He, R. Girshick, et al. “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”. In: vol. 39. 6. June 2017, pp. 1137–1149.
[6] R. Girshick. “Fast R-CNN”. In: 2015 IEEE International Conference on Computer Vision (ICCV). Dec. 2015, pp. 1440–1448.
[7] Tsung-Yi Lin, Priya Goyal, Ross Girshick, et al. “Focal loss for dense object detection”. In: arXiv preprint arXiv:1708.02002 (2017).
[8] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, et al. “A Review on Deep Learning Techniques Applied to Semantic Segmentation”. In: arXiv preprint arXiv:1704.06857 (2017).
[9] Bharath Hariharan, Pablo Arbeláez, Ross Girshick, et al. “Simultaneous detection and segmentation”. In: European Conference on Computer Vision. Springer. 2014, pp. 297–312.
[10] Kaiming He, Georgia Gkioxari, Piotr Dollár, et al. “Mask R-CNN”. In: CoRR abs/1703.06870 (2017). arXiv: 1703.06870.
[11] N. Dalal and B. Triggs. “Histograms of oriented gradients for human detection”. In: 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition Vol. 1. June 2005, 886–893 vol. 1.
[12] Jonathan Huang, Vivek Rathod, Chen Sun, et al. “Speed/accuracy trade-offs for modern convolutional object detectors”. In: CoRR abs/1611.10012 (2016). arXiv: 1611.10012.
[13] Jonathan Long, Evan Shelhamer, and Trevor Darrell. “Fully convolutional networks for semantic segmentation”. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015, pp. 3431–3440.
[14] Pauline Luc, Camille Couprie, Soumith Chintala, et al. “Semantic segmentation using adversarial networks”. In: arXiv preprint arXiv:1611.08408 (2016).
[15] Christian Szegedy, Scott E. Reed, Dumitru Erhan, et al. “Scalable, High-Quality Object Detection”. In: CoRR abs/1412.1441 (2014). arXiv: 1412.1441.
[16] Hyeonwoo Noh, Seunghoon Hong, and Bohyung Han. “Learning deconvolution network for semantic segmentation”. In: Proceedings of the IEEE International Conference on Computer Vision. 2015, pp. 1520–1528.
[17] Adam Paszke, Abhishek Chaurasia, Sangpil Kim, et al. “Enet: A deep neural network architecture for real-time semantic segmentation”. In: arXiv preprint arXiv:1606.02147 (2016).
[18] Pedro O Pinheiro, Ronan Collobert, and Piotr Dollár. “Learning to segment object candidates”. In: Advances in Neural Information Processing Systems. 2015, pp. 1990–1998.
[19] Pedro O Pinheiro, Tsung-Yi Lin, Ronan Collobert, et al. “Learning to refine object segments”. In: European Conference on Computer Vision. Springer. 2016, pp. 75–91.
[20] Ross B. Girshick, Jeff Donahue, Trevor Darrell, et al. “Rich feature hierarchies for accurate object detection and semantic segmentation”. In: CoRR abs/1311.2524 (2013). arXiv: 1311.2524.
[21] Olaf Ronneberger, Philipp Fischer, and Thomas Brox. “U-net: Convolutional networks for biomedical image segmentation”. In: MICCAI. Springer. 2015, pp. 234–241.
[22] Kaiming He, Xiangyu Zhang, Shaoqing Ren, et al. “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”. In: Computer Vision — ECCV 2014. Cham: Springer International Publishing, 2014, pp. 346–361.
[23] J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, et al. “Selective Search for Object Recognition”. In: International Journal of Computer Vision 104.2 (Sept. 2013), pp. 154–171.
[24] Wei Liu, Dragomir Anguelov, Dumitru Erhan, et al. “SSD: Single Shot MultiBox Detector”. In: Computer Vision — ECCV 2016. Cham: Springer International Publishing, 2016, pp. 21–37.
[25] P. Viola and M. Jones. “Rapid object detection using a boosted cascade of simple features”. In: Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision Vol. 1. 2001, pp. 511–518.
[26] J. Redmon, S. Divvala, R. Girshick, et al. “You Only Look Once: Unified, Real-Time Object Detection”. In: 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). June 2016, pp. 779–788.
[27] Joseph Redmon and Ali Farhadi. “YOLO9000: Better, Faster, Stronger”. In: CoRR abs/1612.08242 (2016). arXiv: 1612.08242.
[28] Fisher Yu and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions”. In: arXiv preprint arXiv:1511.07122 (2015).
[29] Shuai Zheng, Sadeep Jayasumana, Bernardino Romera-Paredes, et al. “Conditional Random Fields as Recurrent Neural Networks”. In: CoRR abs/1502.03240 (2015). arXiv: 1502.03240.
[30] Alejandro Newell, Kaiyu Yang, and Jia Deng. “Stacked hourglass networks for human pose estimation”. In: European conference on computer vision. Springer. 2016, pp. 483–499.

分割和目标检测—第 4 部分

原文:https://towardsdatascience.com/segmentation-and-object-detection-part-4-f1d0d213976b?source=collection_archive---------52-----------------------

FAU 讲座笔记关于深度学习

单发探测器

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座

这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是讲座视频&配套幻灯片的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!

航行

上一讲 / 观看本视频 / 顶级 / 下一讲

今天的话题是复杂场景下的实时物体检测。使用 gifify 创建的图像。来源: YouTube

欢迎回到深度学习!所以今天,我们想讨论一下单次检测器,以及如何实现实时物体检测。

单次触发探测器的一般概念。 CC 下的图片来自深度学习讲座的 4.0 。

好了,分割和对象检测的第四部分——单次检测器。所以,难道我们不能在《你只看一次》中使用区域提议网络作为检测器吗?这是 YOLO 的想法,这是一个单触发探测器。您只需查看一次-将边界框预测和分类合并到一个网络中。

YOLO 算法。 CC 下的图片来自深度学习讲座的 4.0 。

这是通过将图像基本上细分成 S×S 个单元来完成的,并且对于每个单元,并行地进行分类概率图计算,并且产生边界框和置信度。这将为每个单元格提供 B 个边界框,这些边界框带有一个置信度得分和类置信度,由 CNN 生成。所以 CNN 预测 S 乘以 S 乘以(5 B + C)的值,其中 C 是类的数量。最后,为了产生最终的对象检测,计算边界框与相应类别概率图的重叠。然后,这允许您计算这个边界框内的平均值,以产生相应对象的最终类。这样你就能解决像这样的复杂场景,而且这是实时的。

来自深度学习讲座CC BY 4.0 下的 YOLO9000 图片规格。

所以有 YOLO9000,它是 YOLO 的改进版,被宣传为更好、更快、更强。所以更好是因为用了批量归一化。他们还进行高分辨率分类,将平均精度提高了 6%。通过对训练数据进行聚类而找到的锚框将召回率提高了 7%。多尺度训练让 YOLO9000 更容易检测到不同分辨率的物体。它更快,因为它使用了不同的 CNN 架构,加快了向前传递的速度。最后,它更强大,因为它在树上具有这种分层检测,允许组合不同的对象检测数据集。所有这些都使 YOLO9000 能够实时或更快地检测到多达 9000 个类别。

YOLO9000 在行动。使用 gifify 创建的图像。来源: YouTube

还有[24]中的单次多盒检测器。这是一个受欢迎的 YOLO 的替代品。也是像 Yolo 一样只有一次前向通过 CNN 的单发探测器。

单次多盒探测器。 CC 下的图片来自深度学习讲座的 4.0 。

它被称为多框,因为这是[15]中边界框回归技术的名称,它显然是一个对象检测器。它在几个方面不同于 YOLO,但有着相同的核心思想。

RetinaNet 是一个多尺度单次检测器。来自深度学习讲座CC BY 4.0 下的图片。

现在,你仍然有一个多重分辨率的问题。特别是,如果你想到像组织学图像这种分辨率非常高的任务。然后,你也可以使用像 RetinaNet 这样的探测器。它实际上使用的是一个 ResNet CNN 编码器/解码器。这与我们在图像分割中已经看到的非常相似。它使用特征金字塔网络,允许您将不同的特征地图与解码器生成的原始输入图像结合起来。所以你可以说它非常类似于 U-net。与 U-net 相比,它使用特征金字塔网络的每个尺度上的子网进行类别和盒子预测。因此,你可以说它是一个单次检测器,同时使用 U-net 进行类和箱预测。此外,它还利用了我们将在几张幻灯片中讨论的焦点损失。

不同物体探测器的比较。 CC 下的图片来自深度学习讲座的 4.0 。

让我们来看看速度和准确性之间的权衡。你可以看到,一般来说,非常精确的网络并没有那么快。这里,您可以在 x 轴上看到 GPU 时间,在 y 轴上看到总体平均精度。您可以看到,您可以将单次检测器(RCNN)等架构或更快的 RCNN 等理念与不同的特征提取器(如 Inception-ResNet、Inception 等)相结合。这使我们能够产生许多不同的组合。你可以看到,如果你在计算上花更多的时间,那么你通常也可以提高精度,这反映在这个图中。

我们如何处理阶层失衡? CC 下的图片来自深度学习讲座的 4.0 。

类的不平衡是解决速度-精度权衡的关键。所有这些单触发检测器评估许多假设位置。大部分都是很容易否定的。因此,目前的培训没有解决这种不平衡。在经典方法中,我们通常用硬负挖掘来处理这个问题。现在,问题是“我们能不能改变损失函数来减少对简单例子的关注?”。

焦点损失。来自深度学习讲座CC BY 4.0 下的图片。

这个想法恰恰把我们带到了焦点损失。在这里,我们基本上可以将对象性定义为二进制的,不管它是不是一个对象。然后,你可以把它模拟成伯努利分布。通常的损失只是交叉熵,也就是正确类别的负对数。你现在可以看到,我们可以把它调整到所谓的焦点损失。这里,我们引入一个附加参数α。α是作为类别频率倒数计算的不平衡重量。此外,我们还引入了超参数γ。这允许减少简单例子的影响。所以,你可以看到γ对左手边的图的影响。你增加的γ越多,你各自的体重就越多,这样你就可以真正专注于不太频繁的课程。

物体检测概述。 CC 下的图片来自深度学习讲座的 4.0 。

那么,我们来总结一下物体检测。主要任务是检测包围盒和相关的分类。滑动窗口方法效率极低。区域建议网络减少了候选的数量,但是如果你真的想走向实时,那么你必须使用像 YOLO 这样的单次检测器来避免额外的步骤。当然,对象检测器概念可以与我们前面看到的任意特征提取和分类网络相结合。此外,请记住速度和精度之间的权衡。所以,如果你想变得非常快,那么你当然要减少预测的包围盒的数量,因为这样你会变得更快,但是你可能会错过真正的肯定。请注意,许多实现已经可用[31]。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。

我们现在讨论了细分。我们现在讨论了对象检测以及如何非常快速地进行对象检测。下一次,我们将探讨两者的融合,也就是实例细分。所以,非常感谢你观看这个视频,我期待着在下一个视频中见到你。

Yolo COCO 物体探测器在工作。使用 gifify 创建的图像。来源: YouTube

如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTubeTwitter脸书LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客

参考

[1] Vijay Badrinarayanan, Alex Kendall, and Roberto Cipolla. “Segnet: A deep convolutional encoder-decoder architecture for image segmentation”. In: arXiv preprint arXiv:1511.00561 (2015). arXiv: 1311.2524.
[2] Xiao Bian, Ser Nam Lim, and Ning Zhou. “Multiscale fully convolutional network with application to industrial inspection”. In: Applications of Computer Vision (WACV), 2016 IEEE Winter Conference on. IEEE. 2016, pp. 1–8.
[3] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs”. In: CoRR abs/1412.7062 (2014). arXiv: 1412.7062.
[4] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs”. In: arXiv preprint arXiv:1606.00915 (2016).
[5] S. Ren, K. He, R. Girshick, et al. “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”. In: vol. 39. 6. June 2017, pp. 1137–1149.
[6] R. Girshick. “Fast R-CNN”. In: 2015 IEEE International Conference on Computer Vision (ICCV). Dec. 2015, pp. 1440–1448.
[7] Tsung-Yi Lin, Priya Goyal, Ross Girshick, et al. “Focal loss for dense object detection”. In: arXiv preprint arXiv:1708.02002 (2017).
[8] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, et al. “A Review on Deep Learning Techniques Applied to Semantic Segmentation”. In: arXiv preprint arXiv:1704.06857 (2017).
[9] Bharath Hariharan, Pablo Arbeláez, Ross Girshick, et al. “Simultaneous detection and segmentation”. In: European Conference on Computer Vision. Springer. 2014, pp. 297–312.
[10] Kaiming He, Georgia Gkioxari, Piotr Dollár, et al. “Mask R-CNN”. In: CoRR abs/1703.06870 (2017). arXiv: 1703.06870.
[11] N. Dalal and B. Triggs. “Histograms of oriented gradients for human detection”. In: 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition Vol. 1. June 2005, 886–893 vol. 1.
[12] Jonathan Huang, Vivek Rathod, Chen Sun, et al. “Speed/accuracy trade-offs for modern convolutional object detectors”. In: CoRR abs/1611.10012 (2016). arXiv: 1611.10012.
[13] Jonathan Long, Evan Shelhamer, and Trevor Darrell. “Fully convolutional networks for semantic segmentation”. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015, pp. 3431–3440.
[14] Pauline Luc, Camille Couprie, Soumith Chintala, et al. “Semantic segmentation using adversarial networks”. In: arXiv preprint arXiv:1611.08408 (2016).
[15] Christian Szegedy, Scott E. Reed, Dumitru Erhan, et al. “Scalable, High-Quality Object Detection”. In: CoRR abs/1412.1441 (2014). arXiv: 1412.1441.
[16] Hyeonwoo Noh, Seunghoon Hong, and Bohyung Han. “Learning deconvolution network for semantic segmentation”. In: Proceedings of the IEEE International Conference on Computer Vision. 2015, pp. 1520–1528.
[17] Adam Paszke, Abhishek Chaurasia, Sangpil Kim, et al. “Enet: A deep neural network architecture for real-time semantic segmentation”. In: arXiv preprint arXiv:1606.02147 (2016).
[18] Pedro O Pinheiro, Ronan Collobert, and Piotr Dollár. “Learning to segment object candidates”. In: Advances in Neural Information Processing Systems. 2015, pp. 1990–1998.
[19] Pedro O Pinheiro, Tsung-Yi Lin, Ronan Collobert, et al. “Learning to refine object segments”. In: European Conference on Computer Vision. Springer. 2016, pp. 75–91.
[20] Ross B. Girshick, Jeff Donahue, Trevor Darrell, et al. “Rich feature hierarchies for accurate object detection and semantic segmentation”. In: CoRR abs/1311.2524 (2013). arXiv: 1311.2524.
[21] Olaf Ronneberger, Philipp Fischer, and Thomas Brox. “U-net: Convolutional networks for biomedical image segmentation”. In: MICCAI. Springer. 2015, pp. 234–241.
[22] Kaiming He, Xiangyu Zhang, Shaoqing Ren, et al. “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”. In: Computer Vision — ECCV 2014. Cham: Springer International Publishing, 2014, pp. 346–361.
[23] J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, et al. “Selective Search for Object Recognition”. In: International Journal of Computer Vision 104.2 (Sept. 2013), pp. 154–171.
[24] Wei Liu, Dragomir Anguelov, Dumitru Erhan, et al. “SSD: Single Shot MultiBox Detector”. In: Computer Vision — ECCV 2016. Cham: Springer International Publishing, 2016, pp. 21–37.
[25] P. Viola and M. Jones. “Rapid object detection using a boosted cascade of simple features”. In: Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision Vol. 1. 2001, pp. 511–518.
[26] J. Redmon, S. Divvala, R. Girshick, et al. “You Only Look Once: Unified, Real-Time Object Detection”. In: 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). June 2016, pp. 779–788.
[27] Joseph Redmon and Ali Farhadi. “YOLO9000: Better, Faster, Stronger”. In: CoRR abs/1612.08242 (2016). arXiv: 1612.08242.
[28] Fisher Yu and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions”. In: arXiv preprint arXiv:1511.07122 (2015).
[29] Shuai Zheng, Sadeep Jayasumana, Bernardino Romera-Paredes, et al. “Conditional Random Fields as Recurrent Neural Networks”. In: CoRR abs/1502.03240 (2015). arXiv: 1502.03240.
[30] Alejandro Newell, Kaiyu Yang, and Jia Deng. “Stacked hourglass networks for human pose estimation”. In: European conference on computer vision. Springer. 2016, pp. 483–499.
[31] Object Detection Algorithms and Libraries, Neptune.ai Blog Post: https://neptune.ai/blog/object-detection-algorithms-and-libraries

分割和目标检测—第 5 部分

原文:https://towardsdatascience.com/segmentation-and-object-detection-part-5-4c6f70d25d31?source=collection_archive---------46-----------------------

FAU 讲座笔记关于深度学习

实例分割

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座

这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是讲座视频&配套幻灯片的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!

航行

上一讲 / 观看本视频 / 顶级 / 下一讲

实例分割也可以用于视频编辑。使用 gifify 创建的图像。来源: YouTube

欢迎回到深度学习!今天,我们想谈谈物体检测和分割的最后一部分。我们想了解实例分段的概念。

语义分割与实例分割。 CC 下的图片来自深度学习讲座的 4.0 。

那么,让我们来看看我们的幻灯片。你看这已经是最后一部分了。第五部分,现在我们要谈谈实例分割。我们不只是想检测立方体的像素在哪里,而不是杯子的像素在哪里。我们想真正弄清楚哪些像素属于哪个立方体。这本质上是对象检测和语义分割的结合。

实例分割方法的例子。 CC 下的图片来自深度学习讲座的 4.0 。

潜在应用的例子是关于遮挡的信息、对属于同一类的元素的数量进行计数、检测物体边界,例如在机器人学中抓取物体。这是非常重要的,文献中有同时检测和分割的例子,DeepMask、SharpMask 和 Mask RCNN[10]。

掩模 RCNN 是最广泛使用的实例分割方法之一。来自深度学习讲座CC BY 4.0 下的图片。

让我们更详细地看看[10]。我们实际上回到了仓库。我们将目标检测和分割结合起来。我们使用 RCNN 进行目标检测。它本质上解决了实例分离。然后,分割细化每个实例的边界框。

掩模 RCNN 的概念。 CC 下的图片来自深度学习讲座的 4.0 。

工作流程是一个两阶段的过程。你有提出物体边界框的区域提议。然后,使用边界框回归进行分类,同时进行分割。因此,您有一个多任务损失,它本质上结合了分割的像素分类损失、框损失和用于产生正确的类/边界框的类损失。所以,你有这三个术语,然后结合在一个多任务损失。

掩模 RCNN 的体系结构。 CC 下的图片来自深度学习讲座的 4.0 。

让我们更详细地了解两阶段程序。两级网络有两种不同的选择。您可以有一个联合分支,该分支在 ROI 上工作,然后在稍后阶段拆分为掩膜分割和类及边界框预测,或者您可以提前拆分。然后,你在两个独立的网络中运行,在两个版本中,你都有这种多任务损失,它结合了逐像素分割损失、盒损失和类损失。

实例分割结果。来自深度学习讲座CC BY 4.0 下的图片。

让我们来看一些例子。这些也是来自掩模 RCNN 的结果。你可以看到,老实说,这些是相当令人印象深刻的结果。所以,确实有疑难病例。你辨认出这些人在哪里,你也看到不同的人,当然,是不同的例子。所以,非常令人印象深刻的结果!

Mask RCNN 也适合支持自动驾驶。使用 gifify 创建的图像。来源: YouTube

所以让我们总结一下目前为止我们所看到的。分割通常通过分析图像并随后细化粗略结果的架构来解决。完全卷积网络保留了空间布局,并通过池支持任意输入大小。

分割和目标检测综述。来自深度学习讲座的 4.0CC 下的图片。

我们可以使用对象检测器,并将它们实现为一系列区域提议和分类。那么这基本上导致了 RCNN 型网络族。或者,您可以使用单次检测器。我们研究了 YOLO,这是一种非常常见且非常快速的技术,如 YOLO9000。我们研究了 RetinaNet,如果你真的有一个规模的依赖,你想检测许多不同的规模,如组织切片处理的例子。因此,对象检测和分割是密切相关的,组合是常见的,正如您在这里看到的实例分割的目的。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。

让我们看看这节课还需要讲些什么。即将出现的是减轻标签负担的方法。因此,我们将讨论弱注释。我们如何生成标签?这也引出了自我监督的概念,这是现在非常流行的话题。为了建立更好的网络,它被大量使用。这些方法还能够稀疏地或者甚至完全地重新使用未标记的数据。我们将研究一些更先进的方法。我稍后要展示的一个想法是使用已知运算符。我们如何将知识整合到网络中?这有哪些属性?我们也展示了一些想法,关于我们如何潜在地使部分网络可重复使用。所以,激动人心的事情还在后面。

一些综合性的问题。来自深度学习讲座CC BY 4.0 下的图片。

我有一些综合性的问题要问你,比如“语义分段和实例分段的区别是什么?”,“与物体检测有什么联系?”“我们如何构建一个接受任意输入大小的网络?”,“什么是投资回报池?”,“我们如何通过投资回报池层执行反向传播?”,“评估细分的典型方法是什么?”例如,我可以请你解释一种实例分割的方法。

我还有几篇关于链接的阅读材料。Yolo 的创始人 Joseph Redmond 有一个很棒的网站。我认为这是一个非常好的库,叫做 darknet 。你也可以研究约瑟夫·雷德蒙的简历,我这里有的链接。我认为,如果你遵循这种布局,这肯定会推动你的职业生涯。请慢慢看,也看看下面的参考资料。我们选择了非常好的最先进的论文,我们绝对可以推荐看一看。非常感谢你们来听这个讲座,我希望你们喜欢我们对分割和物体检测等更应用领域的短暂探索。我希望这对你有用,我也希望我们能在下一个视频中再次看到。所以,非常感谢,再见!

如果你喜欢这篇文章,你可以在这里找到更多的文章,在这里找到更多关于机器学习的教育材料,或者看看我们的深度 学习 讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube、Twitter、脸书、LinkedIn 或 T21。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中生成文字记录,试试自动博客

参考

[1] Vijay Badrinarayanan, Alex Kendall, and Roberto Cipolla. “Segnet: A deep convolutional encoder-decoder architecture for image segmentation”. In: arXiv preprint arXiv:1511.00561 (2015). arXiv: 1311.2524.
[2] Xiao Bian, Ser Nam Lim, and Ning Zhou. “Multiscale fully convolutional network with application to industrial inspection”. In: Applications of Computer Vision (WACV), 2016 IEEE Winter Conference on. IEEE. 2016, pp. 1–8.
[3] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs”. In: CoRR abs/1412.7062 (2014). arXiv: 1412.7062.
[4] Liang-Chieh Chen, George Papandreou, Iasonas Kokkinos, et al. “Deeplab: Semantic image segmentation with deep convolutional nets, atrous convolution, and fully connected crfs”. In: arXiv preprint arXiv:1606.00915 (2016).
[5] S. Ren, K. He, R. Girshick, et al. “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”. In: vol. 39. 6. June 2017, pp. 1137–1149.
[6] R. Girshick. “Fast R-CNN”. In: 2015 IEEE International Conference on Computer Vision (ICCV). Dec. 2015, pp. 1440–1448.
[7] Tsung-Yi Lin, Priya Goyal, Ross Girshick, et al. “Focal loss for dense object detection”. In: arXiv preprint arXiv:1708.02002 (2017).
[8] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, et al. “A Review on Deep Learning Techniques Applied to Semantic Segmentation”. In: arXiv preprint arXiv:1704.06857 (2017).
[9] Bharath Hariharan, Pablo Arbeláez, Ross Girshick, et al. “Simultaneous detection and segmentation”. In: European Conference on Computer Vision. Springer. 2014, pp. 297–312.
[10] Kaiming He, Georgia Gkioxari, Piotr Dollár, et al. “Mask R-CNN”. In: CoRR abs/1703.06870 (2017). arXiv: 1703.06870.
[11] N. Dalal and B. Triggs. “Histograms of oriented gradients for human detection”. In: 2005 IEEE Computer Society Conference on Computer Vision and Pattern Recognition Vol. 1. June 2005, 886–893 vol. 1.
[12] Jonathan Huang, Vivek Rathod, Chen Sun, et al. “Speed/accuracy trade-offs for modern convolutional object detectors”. In: CoRR abs/1611.10012 (2016). arXiv: 1611.10012.
[13] Jonathan Long, Evan Shelhamer, and Trevor Darrell. “Fully convolutional networks for semantic segmentation”. In: Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015, pp. 3431–3440.
[14] Pauline Luc, Camille Couprie, Soumith Chintala, et al. “Semantic segmentation using adversarial networks”. In: arXiv preprint arXiv:1611.08408 (2016).
[15] Christian Szegedy, Scott E. Reed, Dumitru Erhan, et al. “Scalable, High-Quality Object Detection”. In: CoRR abs/1412.1441 (2014). arXiv: 1412.1441.
[16] Hyeonwoo Noh, Seunghoon Hong, and Bohyung Han. “Learning deconvolution network for semantic segmentation”. In: Proceedings of the IEEE International Conference on Computer Vision. 2015, pp. 1520–1528.
[17] Adam Paszke, Abhishek Chaurasia, Sangpil Kim, et al. “Enet: A deep neural network architecture for real-time semantic segmentation”. In: arXiv preprint arXiv:1606.02147 (2016).
[18] Pedro O Pinheiro, Ronan Collobert, and Piotr Dollár. “Learning to segment object candidates”. In: Advances in Neural Information Processing Systems. 2015, pp. 1990–1998.
[19] Pedro O Pinheiro, Tsung-Yi Lin, Ronan Collobert, et al. “Learning to refine object segments”. In: European Conference on Computer Vision. Springer. 2016, pp. 75–91.
[20] Ross B. Girshick, Jeff Donahue, Trevor Darrell, et al. “Rich feature hierarchies for accurate object detection and semantic segmentation”. In: CoRR abs/1311.2524 (2013). arXiv: 1311.2524.
[21] Olaf Ronneberger, Philipp Fischer, and Thomas Brox. “U-net: Convolutional networks for biomedical image segmentation”. In: MICCAI. Springer. 2015, pp. 234–241.
[22] Kaiming He, Xiangyu Zhang, Shaoqing Ren, et al. “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”. In: Computer Vision — ECCV 2014. Cham: Springer International Publishing, 2014, pp. 346–361.
[23] J. R. R. Uijlings, K. E. A. van de Sande, T. Gevers, et al. “Selective Search for Object Recognition”. In: International Journal of Computer Vision 104.2 (Sept. 2013), pp. 154–171.
[24] Wei Liu, Dragomir Anguelov, Dumitru Erhan, et al. “SSD: Single Shot MultiBox Detector”. In: Computer Vision — ECCV 2016. Cham: Springer International Publishing, 2016, pp. 21–37.
[25] P. Viola and M. Jones. “Rapid object detection using a boosted cascade of simple features”. In: Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision Vol. 1. 2001, pp. 511–518.
[26] J. Redmon, S. Divvala, R. Girshick, et al. “You Only Look Once: Unified, Real-Time Object Detection”. In: 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). June 2016, pp. 779–788.
[27] Joseph Redmon and Ali Farhadi. “YOLO9000: Better, Faster, Stronger”. In: CoRR abs/1612.08242 (2016). arXiv: 1612.08242.
[28] Fisher Yu and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions”. In: arXiv preprint arXiv:1511.07122 (2015).
[29] Shuai Zheng, Sadeep Jayasumana, Bernardino Romera-Paredes, et al. “Conditional Random Fields as Recurrent Neural Networks”. In: CoRR abs/1502.03240 (2015). arXiv: 1502.03240.
[30] Alejandro Newell, Kaiyu Yang, and Jia Deng. “Stacked hourglass networks for human pose estimation”. In: European conference on computer vision. Springer. 2016, pp. 483–499.

网店顾客的细分

原文:https://towardsdatascience.com/segmentation-of-online-shop-customers-8c304a2d84b4?source=collection_archive---------38-----------------------

使用 Web 分析数据和 k-Means 聚类

作者识别相似客户/图像的集群

在这篇文章中,我将描述我们如何根据网上商店的网络分析数据对客户进行细分。基于该结果,可以实现现场个性化,并且可以针对细分市场中的用户开始有针对性的活动。

在这个过程中,我们将首先更详细地探索数据(“探索性数据分析”),然后对数据进行适当的预处理,计算分割,最后可视化聚类。对于计算,我们将使用 Google Colab

数据

www.kaggle.com

数据来自 Kaggle 数据平台,包含一家大型多品类网店一个月(2019 年 10 月)的网络追踪数据。文件中的每一行代表一个事件。有不同类型的事件,如页面视图、购物车操作和购买。

该记录包含以下信息:

  • 事件时间/事件是何时触发的?(世界协调时)
  • 事件类型/视图,购物车,购买
  • 产品标识/产品标识
  • 类别标识/类别标识
  • 类别代码/类别名称
  • 品牌/品牌名称
  • 价格/价格
  • 用户标识/客户标识
  • 用户会话/会话 ID

数据以 CSV 文件的形式从客户数据库平台导出,用于分析。

让我们导入数据:

先看数据

2019 年 10 月有超过 4200 万条记录可用。

数据集的前 10 条记录

这些数据来自超过 300 万的访问者。购买了超过 166,000 种不同的产品。

客户旅程示例

为了显示一个客户访问的示例,我们查看了针对某个 Session_id 存在的所有条目,并尝试解释它们:

客户旅程示例

  • 用户已经查看了几部 iPhones
  • 一次点击购买的 iPhone(无购物车事件)
  • 考虑品牌领域的 2 种未知产品
  • 查看一些苹果耳机并购买一个
  • 后来他去了一家更贵的,但决定不买了。

客户历史示例

为了查看特定用户在该月的所有操作,我们使用他的用户 ID 过滤所有记录。

客户历史示例

探索性数据分析

每天在 web 分析中记录了多少事件?

2019 年 10 月记录的事件数量/作者图片

事件类型的数量

数据中发生了哪些事件,发生的频率如何?

事件类型/作者图片

大多数数据包括 96%的页面浏览量,其余的数据包括购物车和购买行为。

来访者的特征

我们为每个访问者计算最重要的特征,并把它们放在一个表中。

  • 浏览量
  • 参观
  • 购买的产品数量
  • 购物车中的产品数量
  • 总支出
  • 每次就诊的支出
  • 每次访问的页面浏览量
  • 每次访问的购物车操作

我们从行动中过滤购买

在下一步中,我们从数据中过滤购买,以便能够更精确地分析它们。我们将结果保存在一个单独的表中。

购买的关键数字

一个买家购买多少产品?
每位买家的平均购买价值是多少?

平均而言,每位买家的购买量略高于 2 次
每位买家的平均购买价值为 773.85

品牌知名度

从哪些品牌购买产品?
让我们来看看排名前 10 的品牌的柱状图。

作者的流行品牌/图片

为了进一步分析,我们将购买分为最常见的品牌组(前 5 名)。而剩下的变成了一群“其他人”。

我们计算每个买家在 6 个品牌类别中的购买份额,并将它们存储在买家表中。

产品类别

有哪些产品类别?

产品类别以分层代码的形式存在。我们提取第一个级别,并将其保存为一个单独的特征。

作者购买的每个顶级类别/图片

有 13 个主要类别。我们将购买价格在每个主要类别中所占的份额作为附加功能添加到买家表中。

将购买特征添加到所有访问者的特征中

我们现在将购买特征添加到所有访问者的表中,从而获得一个包含所有访问者和特征的表。

因此,我们有 3,022,290 个用户的数据,其中每个用户都存储了 27 个特征。

用户数量的限制

为了将集群的计算和可视化保持在一定的范围内,我们将把自己限制在下面的前 50,000 个用户。

转换为矩阵格式以进行聚类计算

在开始计算聚类之前,我们必须将数据转换成适当的格式,作为二维数组。

数据的缩放

为了确保所有特征都以统一的尺寸标度表示,通过移动平均值并除以标准偏差来缩放矩阵。

计算不同聚类数的客户群

“k-Means 方法”用于计算线段。这是一种用于聚类分析的方法,其中一组对象必须形成 k 个组,这些组必须预先给定。

[## 理解机器学习中的 K-均值聚类

K-means 聚类是最简单和最流行的无监督机器学习算法之一。

towardsdatascience.com](/understanding-k-means-clustering-in-machine-learning-6a6e67336aa1)

因为我们正在处理非常大量的数据,所以我们使用该过程的“小批量”变体,该变体在每次迭代中仅使用部分数据来计算新的聚类中心。

如何设置最佳聚类数(“k 值”)?

我们计算不同 k 值的聚类,然后搜索最佳值。计算的轮廓分数是聚类质量的度量。该值越接近 1,分类的质量越好。我们用它来确定集群的数量。

[## 在 KMeans 算法中选择最佳聚类数(轮廓得分)

KMeans 是一种无监督的机器学习技术,主要用于将相似的实例组合在一起。万一…

medium.com](https://medium.com/@jyotiyadav99111/selecting-optimal-number-of-clusters-in-kmeans-algorithm-silhouette-score-c0d9ebb11308)

作者对不同 k 值/图像的轮廓评分

现在我们用确定的最佳聚类数来计算聚类。

并考虑分配给每个细分市场的客户数量。

作者提供的集群大小/图像

集群的可视化

为了获得集群的印象,我们用“tSNE”方法创建了一个可视化。t 分布随机近邻嵌入(tSNE)是一种降维技术,特别适合于高维数据集的可视化。

[## 用 Python 例子介绍 t-SNE

介绍

以 Python 为例 Introductiontowardsdatascience.com 的 t-SNE](/an-introduction-to-t-sne-with-python-example-5a3a293108d1)

作者用 tSNE / Image 实现的集群可视化

现在让我们用更少的集群来计算可视化。对于该过程来说,将各个区域分成不同的片段要困难得多。

tSNE 有 5 个集群/作者提供的图像

细分市场的特征

为了能够解释细分市场,我们创建了图形表示,例如,以“雷达图”的形式一次性显示每个细分市场的类别特征。这有助于解释各段的含义。

作者在群集/图像中的类别

例如,在“儿童”和“运动”领域具有高购买份额的细分市场,以及在“电子产品”领域具有高购买份额的其他细分市场。

基于 U-网的 OCT 图像分割

原文:https://towardsdatascience.com/segmentation-of-optical-coherence-tomography-images-with-diabetic-macular-edema-the-gluon-82093cfd8e24?source=collection_archive---------39-----------------------

内部 AI

使用基于 Apache Mxnet 和 Gluon 框架的光学相干断层扫描报告诊断糖尿病性黄斑水肿的深度学习方法

克劳迪亚·拉米雷斯Unsplash 上拍照

糖尿病性黄斑水肿

糖尿病性黄斑水肿是由称为糖尿病性视网膜病变的 II 型糖尿病引起的恶化。糖尿病性视网膜病变是最常见的糖尿病性眼病之一,通常会导致失明。粗略估计,770 万美国人被诊断患有这种糖尿病,其中大约 75 万人患有糖尿病性黄斑水肿。

光学相干断层扫描(OCT)

OCT 是对 DME 的诊断测试。这项测试使用一种特殊的光源和一台相机来获得视网膜的全面内细胞层。它可以感知视网膜的厚度,并有助于确定视网膜的肿胀程度。

u 型网

在 2015 年 5 月 18 日,Olaf Ronneberger、Philipp Fischer 和 Thomas Brox 发表了一篇关于用于生物医学图像分割的卷积神经网络(CNN)的论文。传统上,细胞神经网络用于图像分类和目标检测。这种方法并不适合,因为期望的输出是定位的输出,其中类标签被分配给每个像素。因为与图像分类问题或物体检测问题相比,生物医学任务没有大量的正样本。Ciresan 等人试图训练一个网络,使用滑动窗口设置,通过使用感兴趣区域或像素周围的小块作为输入特征来预测每个像素的类别标签。这种方法虽然新颖,但却相当稳定,并且由于补丁重叠而导致大量冗余。此外,在小块尺寸和定位精度之间有一个折衷。斑块大小越大,背景越高,但这会导致最大池层数增加,从而减少空间信息,导致定位精度降低。如果小块尺寸减小了,那么上下文也就减小了。这导致了 U 型网络的产生,这是一种伪全连接网络

主要建议是提供一个连续层的正常卷积网络。最大池层被上采样层取代,从而提高了像素密度,最终提高了分辨率。来自卷积路径的这些较高分辨率特征与上采样输出连接。添加连续的卷积层作为扩展路径,这导致特征通道的数量增加,以使网络能够将空间信息传递到高分辨率层。该模型不包含任何完全连接的层,并使用每个特征提取器的最重要部分(卷积)。整体结构呈 U 形,因此得名 U 形网。在较大图像的情况下,通过翻转输入图像和对输入图像执行不同的增强来产生缺失的上下文,这不会改变图像的含义,但是有助于提取每个输入图像的更多特征。

来源:“U-Net:生物医学图像分割的卷积网络”

参考上面的图像,论文的作者使用了具有 ReLu 激活功能的连续 Conv3D 层。最低分辨率为 32×32 像素。卷积层的每个连续块被最大化汇集并相互堆叠。为了形成 U-Net 的基础,为了数据一致性,创建了由 3 个卷积层组成的平台块,其具有相同数量的输入和输出通道。后来通过转置卷积层对它们进行了上采样。反过来,这些层与相应的深度卷积块连接在一起。连接的输出被传递到 U-Net 的上升分支或扩展块。在每一个深度级别,空间信息通过连接不断传递。

你可以在https://arxiv.org/abs/1505.04597查看原文,了解更多细节。

资料组

我使用了 OCT 图像的分割:光学相干断层扫描(OCT)和糖尿病性黄斑水肿(DME)数据集,该数据集由 Paul Mooney 在 kaggle 上提供。你可以在 https://www.kaggle.com/paultimothymooney/chiu-2015亲自看看

截图来自“kaggle.com”

数据集由以下文件组成

来自我的文件浏览器的屏幕截图

完整的源代码

马库斯·斯皮斯克Unsplash 上拍摄

您可以在我的 GitHub 资源库中找到我的实现的完整源代码。

[## sid 0312/oct image 分段

从头开始建立使用 Apache MxNet 和胶子图像分割光学相干断层扫描图像与…

github.com](https://github.com/sid0312/OCTImageSegmentation)

使用 MxNet 的 UNet】

我使用 Apache MxNet 框架和 Gluon API 从头开始构建了一个 U-Net,它类似于 Tensorflow 框架的 Keras

我的存储库中的 model.py 如下所示

现在让我们逐行查看我们的 model.py 文件

  • 导入我们的依赖关系

  • 为 U-Net 创建类

U-Net 被实现为一个混合胶子块。

class network(gluon.nn.HybridBlock):
  • 创建卷积零件功能

这作为单个收缩块,可以在卷积路径中多次使用。它由 3 个 Conv2D 层组成,每个层的内核大小为 3,ReLu 激活函数和 BatchNorm 层用于规范化输入,最后是一个 max pooling 层。它是混合顺序块,因为信息需要顺序传递。

  • 创建去卷积零件功能

这就像是 U 型网络的一个单独的组成部分。它也可以在 U-Net 架构中多次使用。它由 Conv2D 层组成,每个层的内核大小为 3,ReLu 激活函数和 BatchNorm 层用于规范化输入,Conv2DTranspose 层用于扩展输入大小(换句话说就是增加特征图的大小)

  • 创建坪块功能

这一层充当了 U-Net 的瓶颈。它是为数据一致性而创建的,具有相同数量的输入和输出通道。

  • 创建输出层功能

该层充当 U-Net 的输出分段图。它紧接在广阔的道路之后发生。请注意,这几乎类似于卷积部分函数,但它包含一个用于鲁棒特征提取的额外参数。

  • 创建连接功能

这是 model.py 文件中最重要的函数之一。它将从卷积路径获得的较高分辨率特征与最初来自平台块的上采样输出层连接起来。它还填充这些层以给出适当形状的合成层。我花了很长时间来编写这个函数,由于形状不一致,它有很多错误。

然而,这个函数现在工作得非常好。我们使用了边缘填充,以便用输入数组的边缘值填充特征图。简要地看一下 mxnet 在 http://beta.mxnet.io/r/api/mx.nd.pad.html 的官方文档会对理解下面的代码有很大的帮助。也试着在 http://beta.mxnet.io/r/api/mx.nd.concat.html查阅 mxnet.nd.concat 文档

  • 创建 init 函数来分配层

我们已经为每个层创建了函数,但是要真正创建层,我们需要在 init 方法中创建层。请注意,**kwargs 对于混合顺序块参数很重要。

  • 创建 hybrid_forward 方法

我们已经分配了层,但是我们需要顺序地堆叠它们,传递输入 ndarray 并获得输出 ndarray。

  • 为网络类创建对象
net = network(input_channels=1,output_channels=2)

我们已经完成了整个模型。py. 是时候可视化我们的模型了

print(net)

输出:

我的谷歌实验室笔记本截图

让我们使用 Xavier 初始化初始化网络的权重,并在获得上下文(无论代码是在 gpu 还是 cpu 上运行)后,使用形状的样本数组(5,1,284,284)检查模型摘要

输出:

来自我的 google colab 笔记本的截图

足够的可视化。现在让我们使用 prepare_data.py 来准备我们的数据

create_pipeline 方法有助于创建输入管道,即使用。数据集的 mat 文件。

load_dataset 方法将输入管道分为两部分,即训练和验证

现在我们已经有了我们的训练特征、训练标签、验证特征和验证,是时候训练我们的模型了!!

我们的批量大小为 6,运行 100 个时期的训练。

这里使用的损失函数是 mxnet . gluon . loss . softmaxcrossentropyloss()。可以在https://mxnet . incubator . Apache . org/API/python/docs/API/gluon/loss/index . html了解更多亏损情况

使用的优化器是一个胶子教练对象。使用的优化算法是随机梯度下降,学习率为 0.0004。你可以在https://mxnet . incubator . Apache . org/API/python/docs/API/gluon/trainer . html了解更多关于 gluon 训练师的信息

我训练的一些日志

我获得了 88 %的验证准确率,这是相当不错的。

在训练我们的模型之后,我们获得我们的模型参数,我们把它保存在一个文件中,比如说,net.params

我们可以使用 model.params 文件加载我们的模型以进行进一步的预测

让我们使用 results.py 文件绘制一些结果

为了理解这个文件需要一些 matplotlib.pyplot 的知识,你可以在https://matplotlib.org/users/pyplot_tutorial.html获得这些数据可视化的知识

结果

以下是我在使用训练好的模型后获得的一些结果

在我的谷歌协作笔记本上绘制训练示例和结果

我们的验证示例的性能

结论

U-Nets 给出了比滑动窗口分割模型更好的结果。他们也处理最少的数据。

进一步改进

请注意,我在这个数据集上使用了 Conv2D 操作。Conv3D 在 4 维数据集上会工作得更好,这通常是光学相干断层扫描图像的情况,因为会保留 3 维空间信息。

作者注

准确性不是一个合适的参数(灵敏度和特异性才是),用来判断为医疗目的而制作的模型的稳健性,但本笔记本旨在使用 Apache MXNet 框架解释 UNet 架构,而不是目前的评估指标。请继续关注仓库,了解关于指标的进一步更新

快乐的计算机视觉和快乐的深度学习。非常感谢你的时间。真的激励我去开发更多,写更多。

细分简介

原文:https://towardsdatascience.com/segmentation-u-net-mask-r-cnn-and-medical-applications-9a84bddf313e?source=collection_archive---------39-----------------------

U-Net、Mask R-CNN 和医疗应用

分割在医学成像(定位肿瘤、测量组织体积、研究解剖学、计划手术等)中有许多应用。)、自动驾驶汽车(定位行人、其他车辆、刹车灯等。)、卫星图像解译(建筑物、道路、森林、农作物)等等。

这篇文章将介绍分段任务。在第一部分中,我们将讨论语义分割和实例分割的区别。接下来,我们将深入研究用于语义分割的 U-Net 架构,并概述用于实例分割的 Mask R-CNN 架构。最后一节包括许多示例医学图像分割应用和视频分割应用。

分割任务

图片来源:林等 2015 微软 COCO:语境中的常见对象

上图说明了四种常见的图像任务:

  • (a)分类,其中模型输出图像中类别的名称(在这种情况下,人、羊和狗);
  • (b)目标定位,通常称为“目标检测”,其中模型输出图像中每个目标的边界框坐标;
  • (c)语义分割,其中模型为图像中的每个像素分配对象类别标签。在本例中,绵羊像素是蓝色的,狗像素是红色的,人像素是蓝绿色的,背景像素是绿色的。请注意,虽然图像中有多只绵羊,但它们都有相同的标签。
  • (d)实例分割,其中模型给图像中的每个像素分配一个“单个对象”标签。在这个例子中,每只羊的像素被分别标记。我们没有一个通用的“sheep”像素类,而是为五只绵羊创建了五个类:sheep1、sheep2、sheep3、sheep4 和 sheep5。

这是语义分割和实例分割之间差异的另一个说明,显示了在语义分割中所有“椅子”像素如何具有相同的标签,而在实例分割中,模型已经识别了特定的椅子:

图片来源: StackExchange

以下是对藻类图像的语义分割和实例分割的应用:

图片来源: Ruiz-Santaquiteria 等 2020 微观藻类检测中的语义与实例分割。

下图显示了实例分段的模型预测:

图片来源:陈等 MaskLab:用语义和方向特征细化对象检测的实例分割。

图片来源:皮涅罗等 2015 学习分割对象候选人。

图片来源: matterport/Mask_RCNN

U-Net:用于生物医学图像分割的卷积网络

U-Net 论文(可从这里获得: Ronneberger et al. 2015 )介绍了一种语义分割模型架构,这种架构已经变得非常受欢迎,被引用超过 10,000 次(在这个知识库中列出了五十篇不同的后续论文)。它最初是在生物医学图像的背景下提出的,但后来也被应用于自然图像。

U-Net 的基本思想是执行以下任务:

细胞/掩模图像来源: Ronneberger 等人 2015

给定输入图像,在这种情况下,是细胞的灰度显微图像,U-Net 模型产生 1 和 0 的二进制掩码,其中 1 表示细胞,0 表示背景(包括细胞之间的边界)。请注意,这是一个语义分割任务,因为所有细胞都接收相同的“细胞”标签(即,我们没有不同的标签来区分不同的单个细胞,就像我们例如分割一样。)

该示意图显示了训练 U-Net 模型的设置:

在模型被完全训练之前,对于给定的输入图像,它将产生有问题的二进制分割掩模,例如上图所示的“预测的二进制分割掩模”,其中一些单元丢失或具有不正确的边界。U-Net loss 函数将预测掩码与真实掩码进行比较,以实现参数更新,这将允许模型在下一个训练示例上执行更好的分割。

这是 U-Net 架构:

图一。Ronneberger 等人的 2015 年

从这个图中可以看出,“U-Net”这个名字是显而易见的,因为架构图显示了一个 U 形。U-Net 的基本思想是首先通过传统的卷积神经网络获得图像的低维表示,然后对该低维表示进行上采样,以产生最终的输出分割图。

使用右下角提供的架构图很有帮助,它解释了每种箭头类型对应的操作:

U-Net 由“收缩路径”和“扩张路径”组成:

由图 1 修改而来。2015 年

“收缩路径”是产生低维表示的传统 CNN。“扩展路径”对表示进行上采样,以产生最终的输出分割图。灰色箭头表示复制操作,其中来自“收缩路径”的高分辨率特征地图被复制并连接到“扩展路径”中的特征地图,以使网络更容易学习高分辨率分割。

U-Net 没有任何完全连接的层,这意味着 U-Net 是一个完全卷积的网络。

生成预测分割图:1×1 卷积和像素级 Softmax

在 U-Net 的最后一层,应用 1×1 卷积将每个 64 通道特征向量映射到期望数量的类别,在本文中被认为是两个类别(细胞/背景)。如果你想使用 U-Net 对几个类别进行语义分割,例如 6 个类别(狗、猫、鸟、龟、牛、背景),那么 64 通道特征向量可以映射到 6 个类别(6 个通道)。

这是图 1 的特写,显示了“扩展路径”的最后一部分,其中通过[conv 3×3,ReLU]操作产生 64 通道特征向量,并最终使用代表 1×1 卷积的蓝绿色箭头映射到 2 通道特征向量(细胞与背景):

修改自 Ronneberger 等人 2015 的图 1

将逐像素的 softmax 应用于最终的[2 通道,388 高度,388 宽度]表示,以获得最终的输出,即预测的分割图。

像素级 softmax 函数为:

关于 softmax 函数的更多细节,见这篇文章

基于像素的 softmax 可以概念化如下。将输出地图想象成 388 x 388 的图像。该图像中的每个像素由 K 个值表示,K 个通道各有一个值,其中 K 是感兴趣类别的数量。对于每个像素,我们在 K 个通道上取一个 softmax,这样一个通道将“突出”为最高值;这个最高通道确定分配给该像素的类别。

U-Net 加权交叉熵损失

使用交叉熵损失来训练 U-Net:

这是一个典型的交叉熵损失,增加了权重 w (x) ,它提供了一个权重来告诉模型一些像素比其他像素更重要。

权重图 w 是使用传统的计算机视觉技术基于每个基础事实分割预先计算的。具体地,形态学图像处理被应用于基本事实分割,以识别分隔细胞的细边界,然后创建权重图,使得分隔细胞的这些细边界被赋予高权重。将这个权重图合并到交叉熵损失中意味着,如果 U-Net 遗漏了细胞之间的这些细边界,或者如果它将它们画在错误的位置,它将受到严重的惩罚。在损失中使用权重图的总体目标是“迫使网络学习接触细胞之间的小分离边界[……]”

U-Net 数据增强

构建数据集来训练分段模型是非常耗时的,因为需要手工绘制正确的基本事实分段。因此,最终数据集的大小可能很小。在 U-Net 论文中,作者采用数据扩充来增加训练数据的有效大小。他们对训练样本应用随机移位、旋转、灰度值变化和随机弹性变形。弹性变形在医学图像中特别有用,因为(通俗地说)生物样本通常是“粘糊糊的”,这意味着弹性变形的输出仍然是“真实的”

下面是一些应用于大脑图像的数据增强的例子,来自 Quantib 博客:

图片来源: Quantib 博客

总的来说,在发表时,U-Net 模型在细胞语义分割任务上取得了最先进的结果,并且随后被用于各种各样的自然图像和医学图像分割应用。

屏蔽 R-CNN 进行实例分割

实例分段呢?回想一下,在实例分割中,我们不仅仅想要识别细胞与背景像素,我们还想要分离单个细胞。可以执行实例分割任务的一个模型是 Mask R-CNN 。Mask R-CNN 是流行的更快 R-CNN 对象检测模型的扩展。

掩模 R-CNN 的全部细节需要一整篇文章。这是对 Mask R-CNN 背后的思想的一个快速总结,为如何实现实例分割提供了一个思路。

在掩模 R-CNN 的第一部分中,选择感兴趣区域(ROI)。RoI 是输入图像的一部分,其中包含一个概率较高的对象。为每个输入图像识别多个 ROI。

在 Mask R-CNN 的第二部分,如下图所示,每个 RoI 用于获得三个模型输出:

  • 该 RoI 的最终预测类别(对象的类别,例如“人”)
  • 从这个 RoI 获得的最终预测边界框(边界框角的坐标,它提供基本的对象定位)
  • 最终预测的分割(例如,提供非常详细的对象定位的人的轮廓)

图片修改自何等 2018 口罩 R-CNN

如果 RoI 与真实边界框有足够的重叠,则被认为是“正的”。掩模 R-CNN 包括掩模损失,其量化预测的分割掩模与基本事实分割掩模的匹配程度。仅针对正 RoI 定义掩模损失,换句话说,仅当相关 RoI 与图像中的真实对象足够重叠时,才定义掩模损失。

在被训练之后,掩模 R-CNN 可以为单个输入图像同时产生类别、边界框和分割掩模注释:

图片来源:何等 2018 口罩 R-CNN

掩模 R-CNN 也可以用于关键点检测。在下面的示例中,关键点显示为由线连接的点:

图片来源:何等 2018 口罩 R-CNN

创建数据集以训练实例分割模型

有趣的是,要考虑创建适合训练实例分割模型的数据集需要多少工作。一个流行的实例分割数据集是 MS COCO,它包括 328,000 个实例分割的图像。可可小姐的创作分三个阶段:

  1. 类别标记:为每张图片标记每个对象类别的一个实例。每个图像 8 个工人。91 个可能的类别。20,000 工时。
  2. 实例定位:用“x”标记每个对象的每个实例,每张图片 8 个工人。10,000 工时。
  3. 实例分割:对每个实例进行分割,即手动跟踪所有对象实例的轮廓。每幅图像由 1 名训练有素的工人分割,并由 3-5 名其他工人检查。55,000 个工时。

总计 85,000 个工时,相当于一个人每周工作 7 天,每天工作 12 小时,工作时间超过 19 年!

如果您有兴趣进一步探索实例分段,可以从这里下载 COCO 数据集。

图片来源:林等 2015 微软 COCO:语境中的常见对象。

医学图像分割

下面是医学成像中一些很酷的分割应用的例子。

分割细胞核(深紫色。)来源: matterport/Mask_RCNN在显微图像中分割细胞核

核磁共振成像扫描中的脑肿瘤分割。来源:陈等 2019 3D 扩张多纤维网络用于 MRI 实时脑肿瘤分割。

在 CTs 中分割肝脏和肿瘤。来源:姜等 2019 AHCNet:注意机制和混合连接在 CT 卷肝脏肿瘤分割中的应用

分割肺的不同叶(右上叶、右中叶、右下叶、左上叶、舌部、左下叶)。来源:王等 2019 利用协同引导的深度神经网络自动分割肺叶。

分割白内障手术器械。来源:倪等. RAUNet:用于白内障手术器械语义分割的剩余注意 U-Net。

腹腔镜手术图像的多器官分割。来源: Haouchine 等人 2016 使用来自点云的结构对术中腹腔镜图像进行分割和标记。

视频分割示例

还可以将分割算法应用到视频中!这里有两个简单的例子:

GIF 来源: matterport/Mask_RCNN 。要观看完整的 30 分钟视频,请参见凯罗尔·马杰克的Mask RCNN-COCO-instance segmentation。

分割手术机器人。来源: matterport/Mask_RCNN

总结

  • 在语义分割中,每个像素被分配给一个对象类别;
  • 在实例分割中,每个像素被分配给一个单独的对象;
  • U-Net 架构可以用于语义分割;
  • 掩模 R-CNN 架构可以用于实例分割。

关于特色图片

专题图片来自面膜 R-CNN 论文:何等 2018 面膜 R-CNN

最初发表于 2020 年 1 月 21 日http://glassboxmedicine.comT22。

使用无监督学习技术的分割——聚类

原文:https://towardsdatascience.com/segmentation-using-unsupervised-learning-technique-clustering-bb4089c6392e?source=collection_archive---------28-----------------------

基于案例研究的使用分类技术确定高价值细分市场的实践指南

梅尔·普尔在 Unsplash 上的照片

“注意—细分练习在医疗保健和以客户为中心的行业中非常常见。细分分析有助于企业将精力和投资集中在高价值、忠诚或未开发的客户上。这对推动增长和收入非常重要。为了帮助您更全面地了解行业中通常是如何进行细分的,作者编写了一个问题陈述和一个虚拟数据来模拟这些分析的实时进行方式。

以下是我们将要讲述的五件事

  • 问题陈述
  • 方法
  • 聚类技术
  • 眼前的步骤
  • 让您的结果具有商业意义

问题陈述

Andias Pharmaceutical 是一家总部位于美国的零售药店,在美国拥有约 3500 家门店。20%的商店每周 7 天、每天 24 小时营业,然而,其余的商店在正常营业时间营业。Andias Pharmaceuticals 在 2019 年第四季度的平均销售额增长了 3%,但客户群几乎保持不变。为了获得更多的病人,它正计划扩大业务,底特律(密歇根州的一个城市)是重点关注的地区。作为该计划的一部分,位于国会街西段的 Guardian 大楼附近的一家社区药房将于 2020 年 5 月开业。这家药店将是底特律第一家此类药店,将全天候运营。它将拥有训练有素的专业人员和药剂师,他们将帮助患者了解他们的保险细节,补充后续措施,药物摄入,甚至记录药丸可能产生的任何副作用。

为了让更多人了解该计划,运营总监 Sheldon Mall 先生希望联系药房内外的医生(也称为内科医生/处方医生)。由于财务部门没有为此计划分配更高的预算,他们计划将活动分为两部分。销售代表(Rep)瞄准高机会医生,直接邮寄给低机会医生。您需要确定 3 到 4 组这样的医生,以便开展活动。

进场

为什么我们需要分类技术?

问题陈述表明,该活动将使用两种不同的媒体展开:

销售代表瞄准 —药店的销售代表将亲自前往与处方医生交谈。由于锁定销售代表的成本远高于数字或直接邮件营销活动,我们需要确定能够带来更多业务的高价值处方商

如何定义高值处方

  • 现有业务良好的处方医生
  • 具有高市场机会的处方者
  • 有经验的处方医生(多年实践)
  • 附属(执业)于多家医院的处方医师
  • 处方量较高的处方者
  • 患者人数较多的处方医生
  • 具有已知专业的处方医生,如肿瘤学家、心脏病专家、家庭医生等。

直邮 —包含商店及其服务信息的小册子将直接邮寄到处方者的地址。

  • 我们可以看到,问题陈述要求我们根据医生/开处方者的执业特征来创建他们的组。活动的类型和活动的内容可以基于组所显示的特征来定制

处方者特质对信息传递的影响

聚类技术

什么是聚类?

基于某些标准(也称为变量)对相似的数据实体进行分组的技术。

  • 例如,我们可以根据标准/变量(如收入、患者数量、总处方量、经验年限等)对处方者进行分组

无监督学习 的一种形式——因为算法没有关于不同数据实体如何分组的预定义规则。

  • 例如,数据集没有处方者组的预定义标签。该算法需要研究数据并将每个个体处方者分配到一个组中

所以,这是一种 数据调查 的方法——一种研究数据中重要模式或结构的方法。

  • 例如,算法将研究所用变量的模式,并对数据进行分组。现有收入在 100 美元至 150 美元之间且有 200 至 300 名患者的处方者可以被分组为一个组

使用一维数据的聚类示例

  • 我们取一个一维轴,代表一个英超赛季的进球数。这条线上显示的每个点代表一名足球运动员的总进球数
  • 使用传统的统计数据,我们可以知道一个职业联赛赛季的平均进球数是 23 个,但是,如果我们必须根据进球数揭示数据中的一些模式,如球员之间的关系,我们会看到有两到三个更广泛的球员群体
  • K 均值聚类可以发现这样的组或模式,而不需要我们事先告诉它

什么是 K-Means 聚类?

K-Means 算法是一种将数据集划分为多个聚类(比如 K)的方法,这样每个聚类都是不同的,即一个聚类不会与另一个聚类重叠,并且每个数据点只属于一个特定的聚类。它试图以这样一种方式构建聚类,使得一个聚类内的所有点(聚类内点)非常相似,但是来自不同聚类的点(聚类间点)是不同的。

它将数据点分配给一个聚类,使得数据点和聚类质心(属于该聚类的所有数据点的算术平均值)之间的平方距离之和最小。聚类中的差异越小,同一聚类中的数据点就越相似。

优势

  • 当使用的数据集包含连续变量时效果最佳,例如,在问题陈述中,我们需要考虑收入、处方、经验年限、患者人数等指标,这些指标可能包含特定范围内的任何可能值。收入范围从 0 到 1000 美元不等,因此被称为持续收入
  • 当观察的数量很大时,K 均值比其他聚类技术工作得更快,例如,在底特律开业的开处方者的数量是 5000。K-Means 在这种情况下会工作得更快
  • 当聚类变量彼此不同或分离良好时,给出更有利的结果,例如,如果处方者实际上彼此非常不同,那么 K-Means 将产生良好的结果

缺点

  • 无法处理分类变量,即颜色、类型、品牌名称、专业等变量。
  • 如果数据高度重叠,则很难确定 k 个聚类。对于所有数据变量的特征都非常相似的情况,K-Means 通常不能产生不相交的聚类,例如,如果处方者实际上彼此没有很大的不同,那么 K-Means 将产生很差的结果
  • 欧几里德距离可以不平等地加权潜在因素,即在使用 K-Means 形成聚类时,不可能对单个或一组变量进行加权。例如,企业希望包括所有可能的变量,但在聚类过程中更重视收入和患者数量。这在 K-Means 中是不可能的

K-意味着如何工作?

  • 从数据集中随机选择 k 形心,使得每个数据点只能分配给一个形心。通常,大多数算法选择 K 个没有任何缺失值的随机点作为它们的初始质心,然而,对于一些统计包,使用替换=部分或全部的概念来确定初始质心
  • 选择质心后,计算每个数据点和所选质心之间的欧几里德距离。注意,聚类遵循最小平方估计的概念,即对于属于聚类的点,质心和数据点之间的欧几里德距离应该最小
  • 对于数据集中的每个观测值,将计算它们跨这些聚类质心的距离,然后将观测值分配给欧氏距离最短的那个聚类
  • 将观察值分配给一个聚类后,会重新计算质心。聚类质心是分配给每个聚类的观察值的平均值。这个过程持续到满足局部收敛为止,即在当前迭代中形成的聚类类似于在先前迭代中形成的聚类

聚类—聚类工作方式的图形表示

直接步骤

数据准备

第一步: 离群点处理:任何与数据集中其余数据点有很大不同的数据点都被认为是离群点。例如,在开处方者数据集中,大多数收入指标介于 100 美元到 300 美元之间,但是,我们也观察到 1200 美元的值。在这种情况下,1200 美元是一个异常值。然而,一般来说,可以使用下面的方法来识别异常值,这种方法通常被称为 winsorization。

  • 任何超出平均值正负 2/3 标准偏差的值都被视为异常值(两个标准偏差为 5 和 95 个百分点值,而三个标准偏差为 0.3 和 99.7 个百分点值)
  • 或 Q1 之外的任何值-1.5 * IQR 和 Q3+1.5*IQR,其中 Q1 和 Q3 是第一和第三四分位数,IQR 是四分位数之间的范围,被视为异常值
  • 移除异常值取决于业务需求和业务意识,但是建议在执行聚类练习之前移除任何异常值或限制它们
  • 查看数据集时,您可以看到收入数字的巨大差异。总会有开处方者的收入远远高于其他群体。他们是现实中的异类吗?答案是否定的。但是将它们保留在数据集中会使聚类结果产生偏差,因此我们在分析中删除了这些数据

第二步: 缺失值处理。任何缺失的值都应在聚类之前删除或处理。缺失值通常用数据集的中心趋势替换,即所考虑变量的平均值、中值或众数。通常使用像 K-最近邻这样的增强技术来代替集中趋势来处理这些缺失值。

  • 例如,在我们的问题陈述中,当我们处理收入时,我们可以用人口的平均收入替换所有缺失的收入数字,但是在替换多年经验时,我们可以使用人口的模式来替换这些数字。从商业角度看,像底特律这样的地区可能有更多经验丰富的处方医生,因此最好看看人口模式

第三步: 检查聚类变量是否高度相关。如果变量高度相关,那么可以去掉其中一个变量。这是因为相关变量往往会否定非相关变量的影响和重要性。

第四步: 在运行 K 均值模型之前,标准化所有分析/聚类变量。由于 K-Means 使用欧几里得距离将值分配给它们的聚类,因此在将所有变量用于建模练习之前,确保它们属于相似的范围是很重要的。

为什么扩展/标准化在集群中很重要

在上面的示例中,我们看到聚类变量具有不同的标度,因此,与多年的经验相比,收入、患者总数和处方数等更大的变量对距离计算的影响更大。通常,最小-最大缩放、z 分数标准化和对数缩放是行业中使用的一些流行的标准化技术。

[## 对于数据科学的工作,你的编码技能够好吗?

5 编码嗅探如果你在数据科学行业工作,你必须知道

towardsdatascience.com](/are-your-coding-skills-good-enough-for-a-data-science-job-49af101457aa)

代码片段

#--------------------------------Project: Identifying Physician Groups for Community Pharmacy Campaign-------------------
 #--------------------------------Author: Angel Das--------------------------------
 #--------------------------------Create Date: Mar 2, 2020--------------------------------
 #--------------------------------Last Modified: Mar 2, 2020--------------------------------
 #--------------------------------Description: Extract and transform prescriber level information and create clusters using K-Means algorithm--------------------------------#--------------------------------Note: Dummy Data is used for this analysis, not a lot of data is required to complete the analysis#-------------------------------Getting Required Libraries in R--------------------------------------
 install.packages('gdata') #------contains function to read Excel files
 install.packages("corrplot")#------drawing a correlogram
 install.packages("purrr")
 install.packages("factoextra")
 install.packages("dplyr")library(gdata)
 library(corrplot)
 library(purrr)
 library(factoextra)
 library(dplyr)
 #------------------------------Storing Folder address from where inputs will be extracted and outputs will be stored-------------------
 #folder_address="C:/Users/91905/Desktop/Clustering"#--------------------------------Extracting Prescriber Information---------------------------------------
 #--------------------------------QC: 99 observations and 12 variables are read for the analysisprescriber_data=read.csv("C:/Users/91905/Desktop/Clustering/Physician_Data.csv",header=TRUE)#--------------------------------Variable Definition---------------------------------------------------------
 #--1\. HCP: Unique Identifier to of a prescriber
 #--2\. Scripts: Total prescriptions that came to Andias Pharmaceutical in the last 3 months
 #--3\. Market_Scripts: Total prescriptions written in the last 3 months
 #--4\. Revenue: Total Revenue of Andias Pharmaceutical in the last 3 months
 #--5\. Market_Revenue: Revenue generated in the market in the last 3 months
 #--6\. scripts_Share: Scripts/Market_Scripts (share of business)
 #--7\. Revenue_Share: Revenue/Market_Revenue
 #--8\. Pat_count: Patients visiting a prescriber in the last 3 months
 #--9\. Affiliation: Number of Hospitals where an HCP Practices
 #--2\. Experience: Number of Years since the Prescriber has started practicing
 #--2\. Specialty: Specialty of the Prescriber#------------------------------Exploratory Data Analysis in R-------------------------------------------
 #------------------------------Analyzing variables to understand missing observation, mean, median, percentiles etc.prescriber_data_upd<-subset(prescriber_data, select=-c(HCP,Specialty))
 variable_summary=summary(prescriber_data_upd)#------------------------------Display Variable Summary--------------------------------------------------
 variable_summary#--------------------------------Findings: Variables Scripts, Market_Revenue, scripts_share, Affiliation, Experience & Conference_Attended have missing values"
 Once the data summary is obtained, it is important to perform an outlier treatment before missing values are treated.
 As discussed we often replace missing values using Mean, hence mean calculated directly without an outlier treatment will skew the figures.
 "#--------------------------------Box plots to check Outliers-------------------------------------------boxplot(prescriber_data_upd$Scripts, prescriber_data_upd$Market_Scripts, prescriber_data_upd$Revenue, prescriber_data_upd$Market_Revenue,
         main = "Multiple boxplots for comparision",
         at = c(1,2,4,5),
         names = c("Scripts", "Market Scripts", "Revenue", "Market_Revenue"),
         las = 2,
         col = c("orange","red"),
         border = "brown",
         horizontal = TRUE,
         notch = FALSE
 )#--------------------------------Missing Value Treatment------------------------------------------------
 "
 1\. There are two ways to treat missing values. Omit all records which have at least one missing value using na.omit()
 2\. Replace observations with missing value using population mean, median and mode. This is preferable for any business problem
 as you don't want to lose out an entity just because one field or two fields are missing. Comes in handy especially where the number of observation
 is less."#--------------------------------Removing records with missing value---------------------------
 #--------------------------------QC: 80 observations
 prescriber_data_mst<-na.omit(prescriber_data_upd)#---------------------------------Correlation Check. Pearson Correlation coefficient--------------------correlation_data<-round(cor(prescriber_data_mst,method="pearson"),2)#--------------------------------Use corrplot() to create a correlogram--------corrplot(correlation_data, type = "upper", order = "hclust", 
          tl.col = "black", tl.srt = 45)
 wss <- function(k) {
   kmeans(prescriber_data_scale, k, nstart = 10)$tot.withinss
 }# Compute and plot wss for k = 1 to k = 15
 k.values <- 1:10# extract wss for 2-15 clusters
 wss_values <- map_dbl(k.values, wss)"
 Revenue, Scripts Share, and Pat Counts are highly correlated. This is because higher the scripts, higher the revenue and patient count"#---------------------------------Retaining non-correlated variables: Scripts, Market Revenue, Revenue Share, Affiliation, conference attended and experience---------------------------wss_valuesprescriber_data_req<-subset(prescriber_data_mst, select=c(Scripts,Market_Revenue,Affiliation,Conference_Attended,Revenue_Share,Experience))#--------------------------------Standardizing Variables: Make sure to remove any categorical variable during scaling-----------------------------------
 prescriber_data_scale<-scale(prescriber_data_req)#--------------------------------Clustering: Elbow Plot
 set.seed(123)# function to compute total within-cluster sum of squareplot(k.values, wss_values,
      type="b", pch = 19, frame = FALSE, 
      xlab="Number of clusters K",
      ylab="Total within-clusters sum of squares")

决定 K-均值中的 K

在运行 K 均值算法时,决定聚类的数量是很重要的。由于 K-Means 聚类是一种无监督学习形式,因此事先并不知道最适合数据集的聚类数。你可以按照下面的步骤得出 k 的最佳值。

步骤 1 :对于 i=1 到 n(其中 n 表示所需的最大集群数),运行以下步骤:

  • 步骤 1.1 :设置 K=i,使用任意聚类函数进行聚类(基本上会创建 K 个聚类)。对于 i=1,将创建一个集群,对于 i=2,将创建两个集群,依此类推
  • 步骤 1.2 :找出创建的 K 个聚类的 SSE(误差平方和)。 SSE 是一个点到聚类质心的距离的平方之和
  • 步骤 1.3 :重复步骤 1.1 & 1.2,直到 i=n,即循环遍历所需的最大聚类数

第二步:使用折线图绘制上证综指穿过 k 线

第三步:用折线图绘制上证综指在 k 线上的变化。这将有助于随着集群数量的增加,可视化 SSE 的变化

第四步:计算每个聚类值的输出,如总内数、中间数、方差分析、大小以及中间数与内数之比

弯头绘图图

集群 EDA

cluster_results=kmeans(prescriber_data_scale,8, nstart=13)
 #cluster_resultsfviz_cluster(cluster_results, data = prescriber_data_scale)cluster_numbers<-as.data.frame(cluster_results$cluster)
 names(cluster_numbers)[1] <- "cluster"final_result=cbind(prescriber_data_req,cluster_numbers)write.csv(final_result,"C:/Users/91905/Desktop/Clustering/Results.csv")final_result %>%
   group_by(cluster) %>%
   summarise_all("mean")

让您的结果具有商业意义

一旦结果出来,对你的结果进行商业意义上的分析是很重要的。以下是我遵循的一些最佳实践:

  • 计算每个聚类组的描述性统计数据,即参与聚类的所有变量的平均值、中值、最小值和最大值
  • 描述性统计将帮助我们理解和识别每个聚类的特征。在上面的例子中,具有较低收入和较高市场脚本的聚类表示具有机会或潜力的处方者群体,即他们具有良好的市场存在,但是为 Andias 药房编写的脚本很少
  • 为每个集群指定业务名称,而不是集群编号。利益相关者更容易理解每个集群的含义,而不仅仅是查看图表
  • 记住,任何业务都需要理解不同的集群意味着什么。这给了他们对细分的信心,以及某个特定的计划是否合适

最后,如果时间允许,进行一个快速的前后分析,以检查这些分类的描述性统计数据是否随时间而变化。

[## Hive 简介

Hive & SQL 编码初学者指南

towardsdatascience.com](/introduction-to-hive-859ba31a5769)

关于作者:高级分析专家和管理顾问,帮助公司通过对组织数据的商业、技术和数学的组合找到各种问题的解决方案。一个数据科学爱好者,在这里分享、学习、贡献;可以和我在 上联系 推特

使用 K 均值、RFM 和交易记录对客户进行细分

原文:https://towardsdatascience.com/segmenting-customers-using-k-means-and-transaction-records-76f4055d856a?source=collection_archive---------21-----------------------

rupixen.comUnsplash 上拍照

在本文中,我将向您介绍我是如何应用 K-means 和 RFM 分割来根据在线礼品店客户的交易记录对他们进行聚类的。

介绍

上大学的时候,我开了一个简单的卖宠物用品的网店。当时,我只收集了足够的客户信息来进行销售,并把我的产品卖给他们。简单来说,我只有他们的交易记录和地址。

当时,我认为我没有足够的信息来进行任何有用的细分。但是,我最近偶然发现了一种叫做 RFM ( R 频率 F 频率 M 一元值)的直观分割方法,它可以很容易地应用于基本的客户交易记录。

关于 RFM 分割

以下是 RFM的每个字母的含义:

  • R ecency:客户上次向您购买产品已经有多长时间了(例如,几天,几个月)?
  • F 频率:客户在一段固定时间内(如过去 3 个月、去年)从你这里购买了多少次
  • M 一元值:客户在一段固定时间内(应该是为 F 频率设置的同一时间段)在您的商店消费了多少钱。

我们可以对客户进行分组,并根据 RFM 分数提出商业建议。例如,您可以提供促销活动来重新吸引最近没有在您的商店购物的顾客。你可以进一步优先考虑你的促销策略,把重点放在那些经常购买并且至少花费平均货币价值的顾客身上。

使用 K-Means 代替传统的方法

传统的 RFM 方法要求你手动对客户的 RFM 特征从 1 到 5 进行排名。定义等级的两种方法是创建相等间隔的组(例如,范围/5),或者基于百分位数对它们进行分类(那些达到第 20 百分位数的将形成等级)。

既然我们是数据科学家,为什么不使用无监督的学习模型来完成这项工作呢?事实上,我们的模型可能比传统方法表现得更好,因为它根据客户的 RFM 值而不是他们的排名对客户进行分组。

数据

数据集来自 UCL 的机器学习知识库。该文件包含一家英国在线礼品店在 2009 年至 2010 年以及 2010 年至 2011 年期间的 100 万条客户交易记录。excel 文件中有两张表(每年一张),每张表都有相同的 8 个特征:

  • 客户 ID
  • 国家/地区(我没有真正关注这一点,因为大多数客户也来自英国)
  • 发票代码
  • 发票日期
  • 股票代码
  • 股票描述
  • 单价
  • 单位数量

数据清理

由于两个数据集包含相同的要素,我将其中一个附加到另一个上。接下来,我删除了具有以下内容的行:

  • 缺少客户 ID
  • 缺少库存描述
  • 不符合预期格式的异常股票代码,例如以字母开头且少于 5 位数的股票代码。这些往往来自手动输入(股票代码“M”)、邮费(股票代码“DOT”)和取消订单(股票代码以“C”开头)。然而,我保留了以字母结尾的库存代码,因为这些代码倾向于表示产品差异(例如,图案、颜色)。

在为每个客户创建了 RFM 特征之后(参见特征工程),我还移除了偏离平均值超过 4 个标准差的极端异常值。移除极端异常值非常重要,因为它们会扭曲使用基于距离的测量的无监督学习模型。

特色工程

为了得出客户的最近购买时间,我计算了组合数据集中最近一次购买和客户最后一次购买之间的时间差(以天为单位)。分数越低表示购买时间越近,这对商店越有利。

我通过聚合创建了与每个客户的购买频率(在 2 年内)和总支出(货币价值)相对应的特征:

  • 频率:统计每个客户的唯一发票代码的数量
  • 货币价值:所有购买物品的价格总和

我还创建了其他特性,我认为这些特性是有用的集群描述符:

  • 每张发票的总支出
  • 订单之间的时间(天数)

使用轮廓分数选择无监督学习模型

剪影分数可用于评估地面真相未知的无监督学习模型的质量。轮廓分数测量观察值与其自己的聚类相比与其他聚类的相似程度。

值越接近 1 表示聚类分离越好,而值越接近 0 表示聚类重叠。避免负值。

我对数据应用了 3 个无监督学习模型,并选择了 K-Means,因为它具有最佳的轮廓分数,而不管聚类的数量。

基于聚类数的无监督学习模型的轮廓分数

选择 K-均值聚类的数目

为了选择簇的数量(n_clusters),我考虑了每个簇的轮廓分数。最佳情况下,每个聚类的系数值应高于平均轮廓得分(在图中,每个聚类的峰值应超过红色虚线)。我还考虑了每个集群的 RFM 值。

我改变了 K 均值聚类的数量,并检查了模型的 RFM 值和轮廓分数。我决定使用 n_clusters =5,而不是更低的值,尽管剪影得分更低,因为只有当 n_clusters = 5 时,具有良好 RFM 值的重要客户群才会出现。出现在 n_clusters = 5 之外的聚类不太重要,因为它们具有较差的 RFM 分数。

描述 n 个聚类的轮廓分数的表,以及每个聚类的系数值是否高于每个模型内的平均轮廓分数

可视化和描述集群

选择了一个无监督的学习模型和适当数量的聚类后,我使用 3D 绘图可视化了这些聚类。

使用 RFM 分割和 K-均值得出的描述客户细分的 3D 图

聚类 4 和聚类 2 具有更好的 RFM 分数,代表商店的核心顾客。其他 3 个群体似乎是购买频率较低的因果型客户。

核心客户

根据该数据集,18%的客户是核心客户,他们在过去两年中贡献了 62%的收入。他们花钱多,采购频繁,每一两个月一次,还在和店家接洽。由于在线商店产品的典型价格往往较低,集群的平均支出表明他们正在大量采购,因此他们可能是批发商和转售商店商品的较小商店。

描述核心客户主要特征的表格。非百分比数字代表平均值。

散客

至于临时顾客,我想强调一下第 0 类顾客(我称之为礼品猎人),因为他们对商店来说是最重要的。他们贡献了大约四分之一的收入,这比其他休闲集群多得多。他们倾向于每个季度从商店购买一次少量商品,这表明他们是为特殊场合购买的个人。

描述临时客户主要特征的表格。非百分比数字代表平均值。

可以采取的促销策略

鉴于集群的特点,我提出以下针对关键群体的推广策略:

  • 批发商:考虑到他们的数量很少,让他们直接参与进来建立商誉和忠诚度可能是有意义的。最好用定制的解决方案锁定它们。
  • 小商店:探索可以在后续购买中使用的返现折扣。这也将降低他们的成本,鼓励他们花更多的钱。
  • 寻找礼物者:在特殊场合前吸引他们,给他们免费礼物,最低消费高于他们目前 347 英镑的平均消费,鼓励他们多花钱。

结束掉…

我认为 RFM 细分与无监督学习模型非常匹配,因为它们消除了营销人员手动细分客户记录的需要。我希望我已经阐明了如何从最基本的客户信息中创造有意义的客户群。更多细节,你可以看看我的笔记本。它包含了我研究的其他模型的代码和细节。

感谢阅读!

从多个维度对客户进行细分(或者为葡萄酒爱好者使用 Python)

原文:https://towardsdatascience.com/segmenting-your-customers-on-many-dimensions-or-python-for-wine-lovers-8e7768bf86d6?source=collection_archive---------26-----------------------

使用 K-意味着对两个或三个以上的属性进行聚类。

我最近读了一本关于数据分析的书,名为 Data Smart ,作者是 MailChimp 的产品负责人约翰·福尔曼。这本书是一本优秀的商业分析入门书,带你了解各种机器学习用例,包括样本数据集和如何在 Excel 中设置和解决每个案例的详细说明。

有一个案例特别引起了我的注意。它描述了一个虚构的葡萄酒批发企业,该企业希望通过根据购买行为将客户(餐馆和酒店老板)分成不同的群体来优化销售。这是各种各样的企业面临的一个非常普遍的问题,从沃尔玛和塔吉特百货这样的大型零售商到你友好的社区酒类商店。在我看来,这是一个用聚类算法实践我的新 Python 技能的好机会。

提供的数据集包括两个文件,一个列出了一年中提供的大约 36 种产品折扣,另一个列出了客户及其购买细节。目标是找出未来哪种类型的折扣最吸引哪些客户。这是一个典型的客户细分或聚类问题。

每个折扣优惠都有六个属性——月份、葡萄酒品种、最小数量、折扣百分比、原产国和过去的峰值(T/F)。这里列出了 32 种不同的优惠,每种都有不同的属性组合。客户列表包括大约 100 个客户的 324 笔交易。因此,这个挑战涉及的维度比你通常在聚类的机器学习教程中看到的要多得多。

福尔曼先生做了一项出色的工作,带领读者在 Excel 中使用几种类型的成分距离计算方法(欧几里德距离、曼哈顿距离和余弦距离)完成 K 均值聚类过程。这对于小数据集很有效,但是当你进入数十万或数百万行时,Excel 就不管用了。在这本书的最后,福尔曼先生用他最喜欢的大数据语言 R 重新创建了每个分析,但不是用 Python。因此,我尝试为这个集群用例创建一个 Python 教程。我已经上传了完整的 Python 笔记本到我的 Github 库这里

第一步是使用 pd.read_csv 命令将两个数据文件上传到 Pandas dataframes 中。这是两个数据框架。

优惠:

客户/交易:

第 2 步是创建一个数据透视表矩阵,它可以被输入到 Python 中的 Scikit Learn 库中提供的 K-means 聚类算法中。该矩阵将显示垂直列为索引的客户,顶部显示报价数字,每笔交易显示为“1”值,所有空值都转换为“0”。下面是代码和对结果矩阵的快速查看。

为了开始聚类过程,我们需要选择我们想要开始的聚类的数量,即使我们还不知道最佳数量是多少。最常见的方法是创建一个“Scree 图”,该图显示随着聚类数量的增加,类内误差平方和(WCSSE)即“失真”逐渐减少。你希望看到的是图表上 WCSSE 下降趋于平稳的一点。这就是所谓的“肘点”。下面是代码和最终的 Scree 图。

显然,这个图并没有显示出我们想要看到的真正清晰的“拐点”。我认为这表明这些数据比我们希望的要混乱一些。但这在现实世界中并不罕见。每次给定一个数据集都能快速生成清晰简明的见解是相当不寻常的。尽管如此,如果我们愿意花一些时间研究不同的参数,我们仍然可以做出一些有趣的观察。

在上面的碎石图中,看起来有两个点,在这两个点上,线的斜率减小,分别在 3 个簇和 8 个簇处。让我们尝试另一种过滤技术来帮助确定 K-means 算法的聚类数,剪影分数

轮廓分数将每个聚类中的数据点之间的平均距离与相邻聚类中的数据点之间的平均距离进行比较。它是一个介于-1 和 1 之间的值。越接近 1 越好。

我已经计算了下面每一组的轮廓分数。

看起来最高的平均分是四类和八类。因此,让我们尝试八个集群,看看会发生什么。

既然我们已经提供了与每个集群的事务计数一致的详细信息,我们就可以按照从大到小的顺序对每个集群进行排序,并观察详细信息中的模式。

在第一个聚类“0”中,我们观察到所有这些买家都是黑皮诺爱好者。

在第二组“1”中,我们观察到这些人是亲法分子。他们喜欢法国制造的任何东西。

通过聚类“2”,我们找到了所有的起泡酒爱好者。

通过聚类“3”,我们找到了更多的起泡酒爱好者。有了这种重叠,也许我们应该合并集群 2 和集群 3?

在聚类“4”中,我们观察到不同品种的混合,但大多数购买量较低。因此,这些人可能是我们推销剩余交易的对象。

在聚类“5”中,我们看到一些噪音,但是我们可以观察到这些人似乎既喜欢起泡酒又喜欢红酒。

在聚类“6”中,除了霞多丽,这些人似乎也喜欢红酒和起泡酒。也许我们应该合并第五组和第六组?

最后,对于聚类“7”,我们观察到更多红酒和起泡酒买家的组合,加上一些“吵闹的”灰皮诺买家。

在这八个集群中,我们发现了一些重叠和其他有些嘈杂的结果。那么,如果我们尝试另一个 K-means 算法运行,这次只有四个集群,会发生什么呢?

这一次我们得到了更清晰的结果:

一群香槟和红酒爱好者,大多是亲法人士。

闪闪发光的泡泡风扇。

低销量买家。

以及我们永远忠诚的黑皮诺爱好者!

那么我们今天在这里学到了什么?即使是包含许多不同维度的有点嘈杂的数据集,我们也可以使用 K-means 聚类将我们的客户分为不同的组,从而揭示有趣的购买模式,这将为我们提供一些关于未来特殊折扣优惠的想法,以优化我们的销售结果。

具体来说,我们发现了香槟迷、红酒迷、黑皮诺爱好者和低销量买家这几个截然不同的群体来推销我们的剩菜。您可能还会发现,只有一两个属性真正有所不同。在这种情况下,它是葡萄酒品种类别,在较小的程度上,是购买的最小数量。

在这个特殊的用例中,虚构的买家是餐馆和酒类商店的老板,或者“B2B”买家。如果我们面对的是个人零售客户呢?如果我们还可以获得客户的外部数据,让我们有更多的属性进行排序,比如平均收入、生活方式偏好、社会关系或工作类型,这不是很有趣吗?这难道不允许我们将营销计划提升到一个全新的水平吗?

现在有成千上万的数字经济企业在收集这类关于我们的数据。脸书、谷歌和亚马逊是这一群体中最知名的。虽然这听起来有点像“老大哥”,但实际上这和你友好的邻居杂货商几代人以来一直坚持的“了解你最好的顾客”的习惯是一样的。

但是现在随着云计算资源和像 Python 这样容易学习的计算语言的出现,这种聪明的商业思维可以扩大到数百万的数量!欢迎来到大数据的美丽新世界!

如果您有意见或想法要与我分享,请通过 LinkedIn 联系我

选择行时使用。通信线路(LinesofCommunication)

原文:https://towardsdatascience.com/selecting-rows-with-loc-276d217c4ea5?source=collection_archive---------33-----------------------

数据科学/ Python 代码片段

从熊猫数据框架中选择数据子集的初学者指南。

丘特尔斯纳普Unsplash 上拍照

作为数据科学家,我们大部分时间都在用熊猫处理数据。在本帖中,我们将关注。根据一些预定义的条件来选择行。

我们打开 Jupyter 笔记本,我们来扯皮吧!

数据

我们将使用来自圣安东尼奥市开放数据网站的 311 服务呼叫数据集来说明不同之处。锁定技术有效。

家政

在我们开始之前,让我们先做一点家务。

这里没什么特别的。我们只是导入强制的 Pandas 库并设置显示选项,这样当我们检查数据帧时,列和行就不会被 Jupyter 截断。我们将它设置为显示单个单元格中的每个输出,而不仅仅是最后一个。

在上面的代码中,我们定义了一个函数,它将向我们显示缺失值或空值的数量及其百分比。

获取数据

让我们将数据加载到数据帧中。

快速浏览一下df.head(),我们将看到前五行数据:

df.info()将让我们看到列的数据类型。

然后,show_missing(df)向我们显示数据中是否有丢失的值。

选择列是否为空的行。

让我们选择'Dept'列有空值的行,并过滤排除了空值的数据帧。

首先,我们对“Dept”列进行了值计数。方法.value_counts()返回一个熊猫系列,列出指定列的所有值及其频率。默认情况下,该方法忽略 NaN 值,并且不会列出它。但是,如果您包含参数dropna=False,它将在结果中包含任何 NaN 值。

接下来,行df_null = df.loc[df['Dept'].isnull()]告诉计算机选择df中列'Dept'为空的行。产生的数据帧被分配给df_null,它的所有行将作为“Dept”列中的值。

类似地,行df_notnull = df.loc[df['Dept'].notnull()]告诉计算机选择df中列'Dept'不为空的行。产生的数据帧被分配给df_notnull,并且它的所有行在‘Dept’列中没有任何 NaN 值。

这两种技术的一般语法如下:

df_new = df_old.loc[df_old['Column Name'].isnull()]
df_new = df_old.loc[df_old['Column Name'].notnull()]

选择列为特定值的行。

'Late (Yes/No)'专栏看起来很有趣。让我们来看看吧!

同样,我们对'Late (Yes/No)'列进行了快速的数值计算。然后,我们过滤掉那些晚于df_late = df.loc[df['Late (Yes/No)'] == 'YES']的案例。类似地,我们反其道而行之,将'YES'改为'NO',并将其分配给不同的数据帧df_notlate

除了在列和我们想要比较的值之间增加了一个==符号之外,语法和前面的例子没有太大的不同。它基本上是针对每一行,询问特定列(左侧)上的值是否与我们指定的值(右侧)相匹配。如果匹配为真,则在结果中包含该行。如果匹配是假的,它忽略它。

以下是df_late的结果数据帧:

这是给df_notlate的:

这种技术的一般语法是:

df_new = df_old.loc[df_old['Column Name'] == 'some_value' ]

选择列不是特定值的行。

我们已经学习了如何基于“是”和“否”来选择行,但是如果值不是二进制的呢?例如,让我们看看“类别”列:

192,197 行或记录没有分配类别,但是我们得到的不是 NaN、empty 或 null 值,而是类别本身。如果我们想过滤掉这些呢?回车:!=操作符。

像往常一样,我们对'Category'列进行了常规值计数,以查看我们正在处理的内容。然后,我们创建了df_categorized数据帧,以包含df数据帧中任何在'Category'列中没有'No Category'值的记录。

下面是对df_categorized数据帧的'Category'列进行数值计算的结果:

如上面的截图所示,值计数保留了除“无类别”之外的所有内容。

这种技术的一般语法是:

df_new = df_old.loc[df_old['Column Name'] != 'some_value' ]

基于多个条件选择行。

让我们考虑下面的列,'Late (Yes/No)''CaseStatus':

如果我们想知道现在哪些打开的案例已经通过了 SLA(服务级别协议),该怎么办?我们需要使用多个条件来过滤新数据框架中的案例或行。输入&符。

语法与前面的相似,除了在括号中引入了&操作符。在df_late_open = df.loc[(df[‘Late (Yes/No)’] == ‘YES’) & (df[‘CaseStatus’] == ‘Open’)]这条线上,有两个条件:

  1. (df[‘Late (Yes/No)’] == ‘YES’)
  2. (df[‘CaseStatus’] == ‘Open’)

我们希望这两个都为真来匹配一行,所以我们在它们之间包含了操作符&。简单地说,&位操作符就是 AND 的意思。其他按位运算符包括表示 or 的管道符号|和表示 NOT 的波浪号~。我鼓励您尝试使用这些按位运算符,以便更好地了解它们能做什么。只要记住将每个条件用括号括起来,这样就不会混淆 Python。

这种技术的一般语法是:

df_new = df_old.loc[(df_old['Column Name 1'] == 'some_value_1') & (df['Column Name 2'] == 'some_value_2')]

选择列值属于某个值列表的行。

让我们看看'Council District'列的值计数:

如果我们想把重点放在第 2 区、第 3 区、第 4 区和第 5 区,因为它们位于圣安东尼奥南部,并且以城市服务质量差而闻名,会怎么样?(顺便说一句,这完全是我瞎编的!)在这种情况下,我们可以像这样使用.isin()方法:

记得在.isin()方法中像['choice1', 'choice2', 'choice3']一样传递你的选择,否则会导致错误。对于我们例子中的整数,没有必要包含引号,因为引号只适用于字符串值。

这是我们新数据框架df_south的结果:

这种技术的一般语法是:

df_new = df_old.loc[df_old[Column Name'].isin(['choice1', 'choice2', 'choice3'])]

结论

就是这样!在本文中,我们将 311 服务调用数据加载到一个数据帧中,并使用.loc方法创建了数据子集。

感谢阅读!我希望你喜欢今天的帖子。数据争论,至少对我来说,是一项有趣的练习,因为这是我第一次了解数据的阶段,它给了我一个机会来磨练我在面对真正混乱的数据时解决问题的技能。快乐的争吵的人们!

敬请期待!

你可以通过推特或 T2【LinkedIn】联系我。

[1]圣安东尼奥市公开数据。(2020 年 5 月 31 日)。 311 服务电话。https://data.sanantonio.gov/dataset/service-calls

选择效应——它是什么,为什么重要

原文:https://towardsdatascience.com/selection-effect-what-it-is-and-why-it-is-important-33e9a6b05d55?source=collection_archive---------15-----------------------

营销分析师应该注意选择效应。如果不加以检查,选择效应偏差会导致误报和错误的投资。

来源:Pixabay 开放许可

选择效应是对任何营销分析有效性的普遍威胁。因此,分析师应该敏锐地意识到这一现象,以确保他们不会夸大营销影响。

这篇文章简要讨论了选择效应,以及我在营销分析的日常工作中是如何努力克服这种偏见的。

这绝不是一个权威的指南——你可以在这里找到关于选择效应的学术文章和这里

从介绍开始

选择效应是当一种方法、应答样本或分析偏向于目标人群的特定子集时引入的偏差。这意味着它不能反映作为一个整体的实际目标人群。

让我们来看几个简单的例子。

例一。您对 SEM 活动进行分析。您的分析着眼于您通过链接点击购买付费搜索广告的投资回报率(ROI)。然而,该分析并没有考虑那些无论如何都会购买你的产品的“点击链接者”。在这个例子中,没有考虑选择效应意味着你的分析给了你的 SEM 广告不适当的信任,投资回报率被夸大了。

例二。你测试了保健食品的整体品牌认知度,并决定通过在健身房和健康商店的面对面访谈来收集数据。在本例中,数据是有偏差的,因为您的方法针对的是经常去健康相关场所的人群,因此他们很可能倾向于健康食品。这可能会夸大你的保健食品的整体品牌知名度。

通过一个非常小的跳跃,例 1 显示了当选择效应被忽略时,任何归因算法都很容易过分相信 SEM 广告。

例子 2 强调了没有仔细询问可能的偏见的实验的危险。

使用这两个例子,很容易想象忽略选择效应会如何迅速导致容易出错的结果,从而导致糟糕的投资建议和大量浪费的营销投资的恶性循环。当然,没有人希望这样。

最小化选择效应的方法

选择效应是营销分析中一直存在的挑战。这部分是由于工作的性质,部分是由于组织偏好精选分析技术、快速跟踪实验和积极的结果。

以下是我在自己的实践中尝试最小化选择效应的几种方法:

  • 随机对照试验(RCT)—RCT 是我实验和衡量增量营销活动的黄金标准。良好的实验是最小化选择效应的核心,在目标人群中进行随机对照试验是获得代表性结果的最佳方式之一。由于一些媒体策略的复杂性和无法控制印象,RCT 在营销中并不总是可行的。也就是说,我总是从 RCT 作为最佳实践开始。
  • 在多个实验中验证学习成果——只要实验设计合理,在多个实验中验证学习成果是建立对特定证据的信心和最小化意外选择效应的一个很好的方法。
  • 在开始之前记录测量设计、目标和分析类型——提前定义测量设计和分析技术有助于最大限度地减少分析类型或细分带来的选择影响。选择效应可能在分析过程的不同阶段悄悄出现,因此在整个过程中保持勤奋非常重要。
  • 标准化模板、记录的受众定义和正式报告流程 —除了提前定义测量设计,标准化模板和报告流程还有助于在整个分析过程中最大限度地减少偏差。这是通过确保有一致的方法、格式和受众定义来限制分析师在细分受众或显示结果以突出目标人群子集的某个结果时选择效应偏差的能力。
  • 媒体组合的随机可变性 —随机可变性是指在给定的时间框架内,通过媒体渠道发布的印象数量中引入显著可变性的做法。这是针对由于复杂的媒体组合而无法选择随机对照试验的情况,因此需要对营销影响进行建模。在媒体投放中实施随机和高度可变性是一种实验性杠杆,用于操纵自变量(例如,印象)并试图评估对因变量(例如,购买)的任何影响。这种不自然的随机化是减少选择效应的一种方式,它通过在活动中插入随机控制的元素(来自 RCT 剧本),即使整个实验是不可控的。
  • 同行评审是检查某些证据有效性的另一种方式。我们经常会陷入自己的工作中,以至于需要外界的意见才能注意到任何未受抑制的选择效应。测量计划和分析结果的同行评审有助于限制任何无意的选择效应。

偏见就像死亡和税收

归根结底,偏见始终存在,选择效应也不例外。事实上,人类创造的任何事物都有这样或那样的偏见。我们能做的最好的事情就是意识到不同的偏见,并采取措施尽可能地限制这些偏见。

选择效应与我们这些营销分析人员尤其相关。因此,它应该是我们要追踪和最小化的偏见列表中的首要问题。在我看来,在分析工作流程的所有阶段限制选择效应的可能性的最佳方式是通过 RCT、标准化流程和经验证的学习的结合。

硒在起作用

原文:https://towardsdatascience.com/selenium-in-action-2fd56ad91be6?source=collection_archive---------25-----------------------

自动化示例

Python 中的网络抓取和自动化

卡尔·海尔达尔在 Unsplash 上拍摄的照片

1.硒简介

你们中的许多人可能以前在 Python 中玩过 web 抓取。有几个 Python 包可以根据网页(HTML)元素提取网站信息;一些例子是 BeautifulSoupScrapyurllib 2。这些包通常依赖 XPATH 或 CSS 等 web 元素来提取数据。它们各有利弊,但它们可以毫无问题地处理来自许多网站的抓取。

然而,越来越多的网站采用 JavaScript 和其他方法来增加抓取的难度,甚至完全阻止抓取。例如, NYPD 开放数据门户的“下载”按钮直到用户点击“导出”按钮后才会显示。因此,使用 XPATH 或 CSS 的常规抓取方法将无法正常工作,因为直到用户单击按钮时才会找到 web 元素。在你开始拔头发之前,硒来拯救你了!

传统上,Selenium 被设计用于 web 应用程序的自动化测试。这个包的本质是自动化浏览器行为,它可以在很多语言中使用,比如 Java、Python、Ruby 等。因为 Selenium 模仿用户行为,所以一个明显的缺点是速度。然而,由于像人一样自由地行动,Selenium 是一个强大的 web 抓取工具,与传统的 web 抓取包相比,它的限制最少。让我们深入研究一下,看看它是如何工作的。

2.设置 Selenium Webdriver

为了部署 Selenium,您需要根据您的操作系统为您的浏览器设置 Webdriver。这里我将以 Chrome 为例。

  • 第一步:找到你的 Chrome 版本。你可以在“关于谷歌浏览器”找到你的浏览器版本

关于谷歌浏览器

  • 第二步:根据你的 Chrome 版本下载 网络驱动
  • Windows 用户的第 3 步:你需要下载基于你的系统(32 位或 64 位)的 Chrome Webdriver,然后将chromedriver.exe放在你的路径中。
  • Mac 用户第三步:下载 Mac 版 Chrome 驱动后,导航到这个目录/usr/local/。然后检查bin文件夹是否存在。如果不存在,创建一个bin文件夹,将驱动程序放在/usr/local/bin中。运行cd ~/bin && chmod +x chromedriver使其可执行。

3.一个例子:USAC 开放数据——电子汇率数据

以下是练习中需要的包。让我们导入它们吧!

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from bs4 import BeautifulSoup
import requests
from urllib.parse import urljoin
import pandas as pd
import time

现在你已经设置好了 Chrome Webdriver 环境,让我们将 Selenium 投入使用吧!在本文中,我将使用 USAC E-Rate 数据门户作为一个例子。假设用户想要下载所有与 E-rate 相关的数据集,让我们在这个数据门户上设计用户路径,然后我们将尝试用 Selenium 复制用户操作。

步骤 1:收集所有与 E-Rate 相关的数据集 URL

我们将前往 USAC 开放数据搜索 E-rate 数据集。我们发现结果页面只有 2 页,因此我们可以编写以下代码来抓取所有与 E-Rate 数据相关的 URL,供 Selenium 稍后使用。

result_links = []
# Get all e-rate URLs from USAC data page
for i in range(2): # 2 is the total number of pages
 url = ‘[https://opendata.usac.org/browse?category=E-rate&limitTo=datasets&page='](https://opendata.usac.org/browse?category=E-rate&limitTo=datasets&page=') + str(i + 1)
 req = requests.get(url)
 soup = BeautifulSoup(req.content)
 erate_links = lambda tag: (getattr(tag, ‘name’, None) == ‘a’ and
 ‘href’ in tag.attrs and
 ‘e-rate’ in tag.get_text().lower())
 results = soup.find_all(erate_links)
 links = [urljoin(url, tag[‘href’]) for tag in results]
 links = [link for link in links if link.startswith(‘[https://opendata.usac.org/E-rate’](https://opendata.usac.org/E-rate'))]
 result_links.extend(links)print(‘In total, there are ‘ + str(len(result_links)) + ‘ links retrieved.’)

执行时,会弹出一条消息:“总共检索到 15 个链接。”

步骤 2:下载 E-Rate 数据集,用数据字典 pdf 抓取相关元数据

现在我们已经有了想要下载的数据集的所有链接,下一步将是下载它们。如果我们是用户,操作链将是:我们将点击链接,然后点击“导出”按钮,最后选择 CSV 选项进行下载。

导出按钮

CSV 按钮

一些额外的元数据也将有助于数据集文档。在数据集页面上,我们希望获得一些关键项目,包括简介、更新日期、联系人、电子邮件、更新频率和更新 url。这些元数据可以在“关于这个数据集”一节中找到。

元数据部分

这里有一个简单的例子,展示了如何使用 Selenium 来自动化重复性工作和构建数据收集。请注意,睡眠时间是任意的。这里的目标是像人类一样行动,所以确保你的行动链有意义,并分配一个适当的睡眠时间。

# set up driver
driver = webdriver.Chrome()# set up dataframe for metadata
metadata = pd.DataFrame(columns = ['Intro', 'Update Date', 'Contact', 'Email', 'Update Freq', 'URL'])for i in range(len(result_links)):
    # extract metadata by XPATH
    data_dict = {}
    driver.get(result_links[i])
    intro = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/div/div[1]/table/tbody/tr[1]/td[2]/span").text
    update_date = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/dl/div[1]/div/div[1]/div/dd").text
    contact = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/dl/div[3]/div/div[2]/dd").text
    email = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/div/div[1]/table/tbody/tr[4]/td[2]/span/a").text
    update_freq = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/div/div[1]/table/tbody/tr[6]/td[2]/span").text

    # update data_dict with new metadata
    data_dict.update({'Intro': intro, 'Update Date': update_date,
                     'Contact': contact, 'Email': email, 
                     'Update Freq': update_freq, 'URL': result_links[i]})
    # update dataframe
    metadata = metadata.append(data_dict, ignore_index = True)

    time.sleep(5)
    action = ActionChains(driver)

    # Click Show More
    showmore = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[2]/div[1]/section/div[2]/div/div[5]/a[1]")
    action.move_to_element(showmore).perform()
    showmore.click()
    time.sleep(5)

    # Download glossary PDFs
    glossary = driver.find_element_by_xpath("//a[contains([@href](http://twitter.com/href), '.pdf')]")
    glossary[0].click()
    time.sleep(5)

    # Click Export
    action = ActionChains(driver)
    exportmenu = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="app"]/div/div[1]/div/div/div[1]/div/div[2]/div/div[2]/button")
    action.move_to_element(exportmenu).perform()
    exportmenu.click()

    # Click to download CSV file
    downloadmenu = driver.find_element_by_xpath("//*[[@id](http://twitter.com/id)="export-flannel"]/section/ul/li[1]/a")
    action.move_to_element(downloadmenu).perform()
    downloadmenu.click()

如前所述,Selenium 比大多数 web 抓取包都要慢。另一个明显的缺点是,如果网站的所有者改变了设计,所有的 XPATHs 都需要更新。但除此之外,它是一个非常强大的工具,我鼓励你去尝试和探索更多。

我的下一篇文章将是一篇教程,介绍如何使用 Airflow 来调度 Selenium 作业,使其更加强大。敬请期待:)

参考:

  1. 下载 chromedriver 二进制文件并添加到您的自动化功能测试路径中
  2. 硒与蟒蛇

1 |自我关注的基础

原文:https://towardsdatascience.com/self-attention-5b95ea164f61?source=collection_archive---------23-----------------------

变形金刚,一次一个概念

TL;DR-Transformers 是机器学习(ML)中令人兴奋的(相对而言)新的部分,但是在你能够理解它们之前,有很多概念需要被分解。这是我写的关于他们的专栏的第一篇文章。在这里,我们重点关注基本的自我关注机制是如何工作的,这是 Transformer 模型的第一层。本质上,对于每个输入向量,自我关注产生一个向量,该向量是其邻域中向量的加权和。权重由单词之间的关系或连通性决定。这个专栏是针对那些对变形金刚下发生的事情感到好奇的 ML 新手和爱好者的。

内容:

  1. 简介
  2. 自我关注——数学
  3. 参考文献

1.介绍

变压器是一种 ML 架构,已经成功地用于各种 NLP 任务,尤其是序列到序列(seq2seq)任务,如机器翻译和文本生成。在 seq2seq 任务中,目标是获取一组输入(例如英语单词)并产生一组期望的输出(德语中的相同单词)。自 2017 年成立以来,他们已经为 seq2seq 篡夺了当时的主导架构( LSTMs ),并且几乎无处不在地出现在任何关于 NLP 突破的新闻中(例如 OpenAI 的 GPT-2 甚至出现在主流媒体上!).

图 1.1 —机器翻译(欧洲→ DE)⁴

本专栏旨在非常温和、渐进地介绍 Transformer 架构背后的数学、代码和概念。没有比注意力机制更好的起点了,因为:

最基本的变形金刚完全依靠注意力机制。

2.自我关注——数学

我们希望 ML 系统能够学习单词之间的重要关系,就像人类理解句子中单词的方式一样。在图 2.1 中,你和我都知道“The”指的是“animal ”,因此应该和那个词有很强的联系。正如图表的颜色编码所示,这个系统知道“动物”、“十字路口”、“街道”和“the”之间有某种联系,因为它们都与句子的主题“动物”的相关。这是通过自我关注实现的。⁴

图 2.1—“The”关注哪些词?⁴

在最基本的层面上,自我关注是一个过程,其中一个向量序列 x编码成另一个向量序列 z (图 2.2)。每一个原始向量都只是一个数字块,其中代表一个单词。**其对应的 z 向量既表示原始单词又表示其与其周围其他单词的关系。****

图 2.2:输入向量序列 x 变成另一个同样长的向量序列 z

向量代表了空间中的某种东西,比如海洋中的水粒子流或者地球周围任何一点的重力效应。你能不能把词想成词的总空间里的向量。每个词向量的方向意味着某事。向量之间的异同对应于单词本身之间的异同(我在这里之前已经写过这个主题)。**

让我们先来看看前三个向量,特别是向量 x2 ,我们的“猫”向量,是如何变成 z2 的。所有这些步骤将对输入向量的每个重复**

首先,我们将聚光灯下的向量 x2 与一个序列中的所有向量相乘,包括其自身。我们将做每个向量和转置(对角翻转版本)x2 的乘积(图 2.3)。这与做点积是一样的,你可以把两个向量的点积看作是对它们相似程度的度量。**

图 2.3:转置乘法(上标“T”=“转置”)

两个向量的点积与它们之间角度的余弦成正比(图 2.4),因此它们的方向排列越紧密,点积就越大。如果它们指向完全相同的方向,那么角度 a 就是 0⁰,0⁰的余弦等于 1。如果它们指向相反的方向(因此 A = 180⁰),那么余弦就是-1。

图 2.4-两个向量的点积

作为题外话,注意我们用来得到向量间乘积的运算是一个我们可以选择的超参数。点积只是我们拥有的最简单的选项,在 中使用的那个选项就是你所需要的全部注意力【AIAYN】*。*****

如果你想在这个问题上有一个额外的直观视角, Bloem 的帖子讨论了自我关注如何类似于推荐系统确定电影或用户相似性的方式。

因此,我们一次将一个单词放在聚光灯下,并从其邻近单词中确定其输出。这里我们只看单词之前和之后,但我们可以选择在未来扩大窗口。

图 2.5-每个第 j 个向量的原始权重

如果聚光灯下的单词是“猫”,我们要复习的单词顺序是“the”,“cat”,“sat”。我们在问**单词“cat”应该分别对“ the”、“cat”和“sat”给予多大的关注(类似于我们在图 2.1 中看到的)。**

将我们的聚光灯单词向量的转置和它周围的单词序列相乘,将得到一组 3 个原始权重(图 2.5) 。每个权重与这两个词在意思上的联系程度成正比。然后,我们需要将它们规范化,以便它们更容易使用。我们将使用 softmax 公式来完成这项工作(图 2.6)。这将数字序列转换到 0,1 范围内,其中每个输出与输入数字指数成比例。这使得我们的权重更容易使用和解释。****

图 2.6:通过 softmax 函数归一化原始重量

现在我们取归一化的权重(每个向量一个,在 j 序列中),将它们分别与 x 输入向量相乘,对乘积求和,然后就成功了!我们有一个输出 z 向量,(图 2.5)!当然,这只是 x2 ("cat ")的输出向量——这一操作将对 x 中的每个输入向量重复,直到我们得到如图 2.2 所示的输出序列。

图 2.7:得到新的向量序列的最后操作, z

到目前为止,这种解释可能引发了一些问题:

  • 我们计算的权重不是高度依赖于我们如何确定原始输入向量吗?
  • 为什么我们要依赖向量的相似度?如果我们想在两个‘相异’的单词之间找到联系,比如“猫坐在马特上”的宾语和主语,该怎么办?

在下一篇文章中,我们将回答这些问题。我们将为每个不同的用途转换每个向量,从而更精确地定义单词之间的关系,这样我们可以得到更像图 2.8 的输出。**

图 2.8—橙色栏粉色栏中的“cross”关注的是哪个词?

我希望你喜欢这篇文章,我感谢任何数量的掌声。欢迎在评论中留下任何反馈(积极的或建设性的),我会尽可能快地把它写下来。

对我的理解帮助最大,我非常感谢的人是 Peter Bloem(如果你像我一样喜欢数学优先的机器学习方法,他的帖子是一个很好的开始)和 Jay Alammar(如果你想从自上而下的角度开始,我推荐他的文章)。

3.参考

  1. 插图变压器。(2018)https://jalammar.github.io/illustrated-transformer/【2020 年 6 月 27 日访问】**
  2. 从无到有的变形金刚。(2019)http://www.peterbloem.nl/blog/transformers。[2020 年 6 月 27 日获取]
  3. Vaswani A .等人,2017 年 12 月。你所需要的只是关注。第 31 届神经信息处理系统会议(NIPS 2017),美国加州长滩。https://papers . nips . cc/paper/7181-attention-is-all-you-need . pdf【2020 年 6 月 27 日访问】。 arXiv:1706.03762
  4. 瓦斯瓦尼 a .等人 2018 年 3 月 arXiv:1803.07416互动笔记本:【2020 年 6 月 29 日访问】

自平衡二分搜索法树 101

原文:https://towardsdatascience.com/self-balancing-binary-search-trees-101-fc4f51199e1d?source=collection_archive---------4-----------------------

自平衡二分搜索法树简介

数据结构是一种在计算机中组织和存储数据的专门方法,通过这种方法,我们可以更有效地对存储的数据执行操作。在现有的众多数据结构中,二分搜索法树在高效操作中扮演着重要角色。由于我的上一篇文章每个程序员都必须知道的 8 种常见数据结构收到了很多兴趣和友好的回复,所以我将在本文中简要解释一下自平衡二分搜索法树(BST)。

什么是二分搜索法树?

如果你读过我之前关于数据结构的文章,你就会知道二叉查找树(BST) 是一棵二叉树,其中的数据以层次结构组织。

二叉查找树展示了一个独特的属性,称为二叉搜索树属性

x 是二叉查找树中的一个节点。

  • 如果 y 是 x 的子树中的一个节点,那么 y.key ≤ x.key
  • 如果 y 是 x 的子树中的一个节点,那么 y.key ≥ x.key

图一。二分搜索法树基本术语的可视化。

什么是自平衡二分搜索法树?

自平衡二叉查找树(BST)是一种自动尝试始终保持其高度尽可能小的二叉查找树(即使在执行插入或删除等操作后)。

如果你翻阅过 Big-O 算法复杂度备忘单,可以看到 BST 运算的平均时间复杂度为θ(h),其中 h 为树的高度。因此,在执行大量操作时,高度越小越好。因此,引入了自动平衡 BST,它可以自动将高度保持在最小值。然而,您可能认为每次执行操作时都必须进行自平衡是低效的,但这可以通过确保稍后在 BST 上执行大量快速操作来补偿。

高度为 h 的二叉树最多可以有2⁰+2¹+···+2ʰ = 2⁽ʰ⁺¹⁾−1个节点。

n≤2⁽ʰ⁺⁾1

h ≥ ⌈log₂(n+1) - 1⌉ ≥ ⌊log₂(n)⌋

因此,对于自平衡 BSTs,最小高度必须始终是向下舍入的 对数 ₂( n) 。此外,如果每个节点的左右子节点的高度相差 -10+1 ,则称二叉树是平衡的。该值被称为平衡系数

平衡因子=左子树的高度-右子树的高度

自平衡二分搜索法树是如何平衡的?

说到自平衡,BST 在执行插入和删除操作后执行旋转。下面给出了两种类型的旋转操作,可以在不违反二叉搜索树属性的情况下执行这两种操作来平衡 BST。

1.向左旋转

当我们绕节点 x 向左旋转时,节点 y 成为子树的新根。节点 x 成为节点 y 的左子节点,子树 b 成为节点 x 的右子节点。

图二。在节点 x 上向左旋转

2.向右旋转

当我们围绕节点 y 向右旋转时,节点 x 成为子树的新根。节点 y 成为节点 x 的右子节点,子树 b 成为节点 y 的左子节点。

图三。在节点 y 上向右旋转

请注意,一旦您完成了旋转,前一个和最后一个树中节点的有序遍历是相同的,并且二叉搜索树属性保持不变。

自平衡二分搜索法树的类型

下面给出了几种自平衡 BST。

  1. AVL 树
  2. 红黑色的树
  3. 张开树木
  4. Treaps

自平衡二分搜索法树的应用

自平衡 BST 用于构建和维护有序列表,如优先级队列。它们也用于关联数组,其中键-值对根据仅基于键的排序插入。

计算几何中的许多算法利用自平衡 BST 来有效地解决问题,例如线段相交问题。此外,可以扩展自平衡 BST 来执行新的操作,这些操作可用于优化数据库查询或其他列表处理算法。

AVL 树作为自平衡 BST 的一个例子

阿德尔森-维尔斯基和兰迪斯 ( AVL )树是平衡的二叉树。AVL 树中的所有节点存储它们自己的平衡因子。

在 AVL 树中,每个节点的平衡因子是-1、0 或+1。

换句话说,对于 AVL 树中的所有节点,左侧子树的高度和右侧子树的高度之差不能超过 1。

AVL 树示例

图 4。AVL 树示例

在图 4 中,节点上方红色的值是它们对应的平衡因子。您可以看到,在图 4 所示的 AVL 树的所有节点中都满足了平衡因子条件。

AVL 树的旋转

在 AVL 树中执行插入或删除后,我们必须检查所有节点是否满足平衡因子条件。如果树不平衡,那么我们必须做旋转来使它平衡。

对 AVL 树进行的旋转可以分为四种主要类型,分为两类。他们是,

  1. 单转左(LL)转右(RR)转
  2. 双旋转左右(LR)旋转左右(RL)旋转

下面给出的图表将解释每种旋转类型。

1.单次向左旋转(LL 旋转)

在这种类型的旋转中,我们将所有节点向左移动一个位置。

图五。LL 旋转

2.单次右旋转(右旋转)

在这种类型的旋转中,我们将所有节点向右移动一个位置。

图六。RR 旋转

3.左右旋转(左右旋转)

顾名思义,这种类型的旋转包括左旋和右旋。

图 7。左右旋转

4.左右旋转(左旋转)

这种类型的旋转包括右旋转和左旋转。

图 8。RL 旋转

向 AVL 树中插入元素

考虑图 4 中给出的 AVL 树。我们想给这个树添加一个新的节点 105。图 9 显示了插入新节点和重新平衡树的步骤。

图九。插入和平衡

添加节点 105 后,树中将总共有 12 个节点。如果我们计算出平衡树的可能高度,

h ≥ ⌈log₂(n+1) — 1⌉

h ≥ ⌈log₂(12+1) — 1⌉

h ≥ ⌊log₂(12)⌋ = ⌊3.58496250072⌋ = 3

但是,插入后生成的树的高度为 4。此外,节点 102 的平衡因子是-2。从这些事实可以看出,插入后得到的树是不平衡的。因此,我们必须通过旋转来平衡它。可以看到,应该旋转以节点 102 为根的子树,并且应该使用 RL 旋转。执行这个旋转后,我们得到一个高度为 3 的平衡树。

最后的想法

我希望这篇文章作为自平衡二分搜索法树的简单介绍对你有用,在这里我们以 AVL 树为例进行了讨论。我很想听听你的想法。😇

非常感谢你的阅读。😊请继续关注接下来的文章,我将在其中解释更多关于自平衡 BST 的内容。

干杯!😃

参考

[1] CS241 —讲义:自平衡二叉查找树

[2] 自我平衡的二叉查找树——维基百科

[3] 数据结构教程— AVL 树|示例|平衡因子

Jupyter 笔记本中的独立报告

原文:https://towardsdatascience.com/self-contained-reports-from-jupyter-notebooks-219a3887979d?source=collection_archive---------48-----------------------

使它们具有交互性和可隐藏的代码单元

介绍

你刚刚写了一个非常棒的 Jupyter 笔记本,你想把它发给你的同事。要求他们安装 Jupyter 是不可行的,要求他们提供一台服务器来托管你的页面也是不可行的。你是做什么的?

我将向您展示如何将您的笔记本导出为独立的 html 报告,任何人都可以在浏览器中打开该报告。我将从如何导出 html 报告的最简单的例子开始,然后我将展示如何隐藏输入单元格,最后我将展示如何切换显示/隐藏代码单元格。

可以在这里找到原始资料。

Hello world 示例

让我们从最简单的例子开始——我们有一个“hello world”笔记本,我们希望将它导出为一个自包含的 html 报告。我们可以通过跑步做到这一点

如果查看build目录并在浏览器中打开生成的html文件,我们会看到

这是一个自包含的文件,您可以将它作为电子邮件附件发送给任何人,他们将能够在他们的浏览器中打开它!

斐波那契示例

现在假设我们有一个笔记本,它计算前 100 个斐波纳契数并绘制它们。如果我们的最终目标是向非技术同事发送报告,我们可能希望从报告中排除任何代码单元,只保留输出和降价。

我们可以用--no-input标签:如果我们跑

然后我们得到一个独立的报告,有一个交互式的情节,没有代码单元,任何人都可以在他们的浏览器中打开它!

斐波那契示例—切换显示/隐藏代码单元格

在前面的例子中,所有的代码单元格在报表中都是隐藏的。但是,如果我们仍然希望让我们的最终用户能够有选择地显示或隐藏它们,那该怎么办呢?这需要一点技巧。

  • 步骤 2:编辑该单元格的元数据,使其包含标签remove-input。您可以通过单击左侧窗格中的属性检查器来编辑单元格的元数据:

  • 第三步:如果有任何其他单元格的输入(或输出)你想保持总是隐藏,添加remove-input (resp。remove-output)到它们的元数据;
  • 步骤 4:从终端运行

最后,您将得到一个切换按钮,通过它您可以有选择地显示或隐藏您的代码单元格!

结论

我已经向您展示了如何从 Jupyter 笔记本中导出包含隐藏代码单元格的自包含交互式报告。如果您需要与他人共享 Jupyter 笔记本,而不必要求他们安装任何额外的工具,这是一个很好的解决方案。原始资料可以在这里找到

https://marcogorelli.github.io/】原载于

自动驾驶汽车:我们离完全自主还有多远?

原文:https://towardsdatascience.com/self-driving-cars-how-close-are-we-from-full-autonomy-ccf31cea771?source=collection_archive---------30-----------------------

意见

我们现在是在 2020 年。我的机器人出租车在哪里?让我们看看技术的当前状态,做一个有根据的猜测

迪伦·卡勒伊在 Unsplash 上拍摄的照片。

毫无疑问,全自动驾驶技术(或第五级自动驾驶)将是我们未来的一部分。问题是——它什么时候到达?下一个十年?未来五年?明年?明天吗?让我们看看目前的技术水平,做一个预测。

剧透:大概不会晚于 2025 年。

哪个公司会先到达那里?

如果有谁能在 2025 年前解决完全自动驾驶( level 5 autonomy ),那就是特斯拉。你可能听说过 Waymo 机器人出租车,但这些出租车在非常有限的区域内运营,需要高分辨率的地图和路线准备(四级自主)。这是一个很好的尝试,但目前的方法不可扩展。

特斯拉将率先解决完全自动驾驶的主要原因是:

  • 数据:他们拥有最大的真实世界数据集,驾驶里程数十亿。
  • 高效硬件:一组智能传感器和一个内部设计的深度学习芯片。
  • 高级软件:神经网络驱动 Teslas 是一个非常复杂的多任务问题。

在接下来的部分中,我将对这三个主题中的每一个进行阐述,然后我将构建我的预测时间表——让我们开始吧。

数据

有超过 100 万辆汽车在收集数据,特斯拉在竞争中遥遥领先。此外,随着产量的增加,特斯拉车队的规模将在未来几年急剧增加。请看这张图表,它显示了自动驾驶的预计行驶里程。

估计特斯拉自动驾驶里程。莱克斯·弗里德曼拍摄的图片。

在深度学习应用中,拥有大量数据是游戏规则的改变者。特别是对于自驾这种复杂的问题,需要在多任务问题中分析多个传感器的数据。

通常,在现实世界中,可能场景的分布有一个非常长的尾巴——这意味着汽车可能面临的罕见情况的数量几乎是无限的。拥有一个收集数据的大型车队,可以对逐步改善所需的边缘案例进行采样。目标是随着时间的推移使模型越来越健壮。

为了收集真实数据,需要一组传感器。这让我想到了下一个话题——硬件。

硬件

用于完全自动驾驶的一组硬件通常由几个摄像头、激光雷达传感器、雷达传感器和超声波传感器组成。

  • 摄像头用于采集车辆周围的图像;
  • 激光雷达发送快速激光脉冲,这些脉冲在物体上反射,允许以高分辨率制作周围的三维地图;
  • 雷达类似于激光雷达,但它工作在无线电波长上,允许在雾和灰尘条件下以较低的图像分辨率换取更好的性能;
  • 超声波传感器用于近距离,非常精确地检测近距离物体的距离。

这个领域的大多数人都非常依赖激光雷达,通过一些摄像头和超声波传感器进行增强。然而,特斯拉正在以不同的方式解决这个问题——不使用任何激光雷达。这让特斯拉的问题更加棘手! 他们为什么采用这种方法?

我们确信基于视觉的方法可以可靠地驾驶汽车——我们每天开车时都会使用两个摄像头传感器(也称为眼睛)。另一个重要的考虑因素是激光雷达传感器价格昂贵。随着时间的推移,价格可能会降低,但在此之前,汽车会明显变得更加昂贵。同样,如果我们可以用眼睛开车,那么人工智能可以通过让更多的眼睛无时无刻不在工作而不受干扰,来学习做得更好。雷达传感器非常重要,主要是为了即使在有雾和灰尘的情况下也能增强前视能力。再次检查前方物体的距离也很重要。这种传感器与激光雷达相比也更便宜。

下面的视频清楚地解释了特斯拉为传感器套件采取的方法,以及为什么用埃隆·马斯克的话说:“任何依赖激光雷达(完全自动驾驶)的人都注定要失败”。我发现关于使用雷达自动标记数据以利用相机进行深度估计的讨论特别有趣。他们还提到深度估计可以使用自我监督在没有标签的情况下实现——这是一种非常有前途的技术,在几个深度学习应用中正在获得动力。

Elon Musk 在相机上对比自动驾驶和自动驾驶汽车的激光雷达。

总的来说,我们看到特斯拉正在通过不依赖激光雷达和直接研究基于视觉的方法来解决一个更困难的问题。这是一个正确的方法,因为它是可扩展的,并导致更低成本的汽车,最终将能够提供机器人出租车的最低价格,并加速向电动汽车的过渡。

关于硬件的另一个重要方面是,特斯拉开发了一种深度学习芯片(硬件 3.0 ),它有能力以节能的方式实现完全自动驾驶。现在只需将软件安装到位,并通过无线更新进行部署。

聊到软件,我们转到下一个话题,看看特斯拉 autopilot 背后的神经网络。

驱动特斯拉汽车的神经网络

在过去的几年里,自动驾驶软件逐渐得到了改进。一些令人兴奋的消息是,特斯拉一直在对神经网络结构进行重大更新,使其能够与 4D 数据一起工作,而不是 2D 图像的组合。因此,随着特斯拉人工智能团队进一步探索他们计划在 2020 年底部署的系统的潜力,未来几个月的进展速度可能会更快。

我强烈推荐下面的视频,是特斯拉人工智能总监 Andrej Karpathy 关于全自动驾驶人工智能状态的演讲。我现在将描述一些主要的亮点。

安德烈·卡帕西——全自动驾驶的人工智能。

新的神经网络接收来自所有传感器的输入,并结合神经网络特征空间中的数据(下图中的融合层),创建周围环境的实时三维表示。这种表示然后被提供给一个鸟瞰网络( BEV Net ),从该网络中需要预测一组广泛的任务。

特斯拉自动驾驶神经网络。图片来自 Andrej Karpathy 在 ScaledML 2020 会议上的演示,可在 YouTube 上查看。(点按 YouTube 链接以转到确切的视频位置)

演示中涉及的另一个非常有趣的主题是他们如何处理边缘情况。下图展示了一个很好的例子——停车标志。有人会认为神经网络很容易捕捉和学习停车标志。但是如果它们被部分遮挡了呢?或者,如果他们有一个修饰语,如下面的例子所示,停车处下面的标牌上写着“右转除外”。无人驾驶汽车有望在所有这些场景中发挥作用。

真实世界长尾分布场景的例子。图片来自 Andrej Karpathy 在 ScaledML 2020 会议上的演示,可在 YouTube 上查看。(点按 YouTube 链接以转到确切的视频位置)

训练巨大的神经网络以在类似上述例子的边缘情况下表现良好的过程包括以“影子模式”运行一个小型网络,从特斯拉车队中检索类似的样本。获得的样本随后用于改进训练数据集。那么大的神经网络可以被重新训练以达到更好的精度。对于停车标志的情况,标签“停车标志”需要有修饰语来覆盖边缘情况。

对于这样一个复杂的多任务问题的验证也是本演示中涉及的一个非常重要的主题。

在最近 CPRV 2020 会议的主题演讲中,卡帕西做了一个类似的介绍,并增加了一些有趣的例子。从一个边缘案例的好例子开始。我想除了这些是从特斯拉车队采集的真实图像之外,没有其他评论需要了。

真实世界长尾分布场景的极端例子。图片来自 Andrej Karpathy 在 CPRV 2020 大会上的演讲,可在 YouTube 上获得。(点按 YouTube 链接以转到确切的视频位置)

另一个疯狂的例子是下图。你能应付这样的迂回吗?关于这个例子,Karpathy 提出了一个有趣的观点,他们不需要处理每一个可能的情况。如果无法处理的案例是已知的,一个可能的选择是遵循不同的轨迹来避免特定的情况。作为人类,我肯定会避开下图中的环岛。

极端困难的情况。Andrej Karpathy 在 CPRV 2020 大会上的演讲图片可在 YouTube 上获得。(点按 YouTube 链接以转到确切的视频位置)

我相信上面的图片也暗示了他们正在努力解决环形路和十字路口的问题。这是继红绿灯和停车标志之后的合理步骤,也是实现功能完整的自动驾驶的重要一步。

我的预测时间线

在今年 4 月 12 日的一条推文中,Elon Musk 提到了关于 robotaxi 发布的时间表,“今年功能看起来仍然不错。监管部门的批准是一个巨大的未知数。然而,埃隆对这些时间表过于乐观。然而,进展是稳步的,我们越来越接近了。

现在,让我最后写下我的时间表,它基于我能找到的关于自动驾驶当前状态的所有公开信息,并试图做出乐观但现实的预测:

  • 2020 年末或更有把握的 2021 年:特斯拉自动驾驶将功能齐全。它将能够在大多数情况下导航,但远非完美。在城市环境中,将一直需要人工监管,人工干预将很常见。
  • 2021/2022: 随着越来越多的数据被收集并用于改进系统,改进将非常稳定。人为干预将会减少,而无人干预的出行将会逐渐变得更加频繁。
  • 2023: 自动驾驶仪将能够在大多数情况下完美导航。人类干预将是零星的。大多数旅行不需要任何干预。今年有可能在选定的地方开始 robotaxi 实验——4 级自治。
  • 2024: 软件将达到一种状态,在无人监管的情况下,可以安全行驶。边缘情况可能仍然存在,但可以通过人类语音命令反馈或通过规划旅程来解决,以避免特定的问题情况。特斯拉将开始一项重要任务,向监管机构展示这项技术在没有人类监管的情况下可以安全地用作 robotaxis 第 5 级自治。
  • 2025/2026: 特斯拉将逐渐获得监管机构的批准,在越来越多的地区运营。批准可能首先在美国进行(在一些州可能最早在 2024 年),并逐渐扩展到其他地区。对于欧洲,我预计批准时间会比美国晚一年。

总而言之,到 2025 年(在欧洲和其他地区可能是 2026 年),我希望能够在应用程序中安排我的 robotaxi 之旅,去我选择的任何目的地。我期待着那一天!

结束语

这只是我对全自动驾驶未来的设想。没有人知道未来会怎样。等式中有许多不确定因素。我的预测只是我认为最有可能的情况。请在评论中告诉我你的想法。

更多关于我的事

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

自从 2017 年开始学习 Python 以来,我一直遵循的道路是成为一名独自参加 Kaggle 比赛的大师…

towardsdatascience.com](/my-3-year-journey-from-zero-python-to-deep-learning-competition-master-6605c188eec7)

感谢阅读!祝您愉快!

无人驾驶汽车——管理项目

原文:https://towardsdatascience.com/self-driving-cars-managing-a-project-57372db4e739?source=collection_archive---------27-----------------------

本文已在https://www.thinkautonomous.ai/blog/?更新 p =自动驾驶汽车管理项目

米勒·桑德斯Unsplash 上的照片

制造自动驾驶汽车是一项紧张的活动。很多时候,不是一个公司一个人做的事情。特别是,我注意到在项目开发过程中我们经常交流的 3 个不同的概要文件。

虽然我从未有过“项目经理”的头衔,但我与 3 名项目经理密切合作,维护并发展了与两家外部供应商的关系,并在 Perception 管理着一个由 7 名实习生组成的团队。它让我对项目管理有了很好的理解,我可以自己做这项工作。

如果你正在考虑成为一名自动驾驶汽车项目经理,也许你不知道该期待什么。
自动驾驶汽车项目经理日常做什么?

鉴于现在有很多项目管理技术(敏捷、Scrum 等等),我将只讨论任务而不是使用的方法或工具
还有,由于我在创业环境中工作过,我就从这个角度讲讲我的故事。

📩在我们开始之前,我邀请您订阅我的私人邮件列表,并接收像这样的每日信息!

🚀你也可以在我的入门课程中开始学习自动驾驶汽车。

项目经理有很多事情要做。在这里,我将确定该角色涉及的每项任务和联系人。

开发者

照片由 Fabian GrohsUnsplash 上拍摄

在自动驾驶汽车中,我们很少创造一种可以开到任何地方的车辆。
总有一个明确的目标,比如“高速公路驾驶”或“市中心送餐”。
这一目标对车辆的开发有影响。

所需的算法将取决于车辆的任务。
如果一辆汽车在城市里行驶,它将需要一个交通灯检测系统。在高速公路上不是这样。

项目经理的第一个角色就是意识到这种差异。
当我们创建一个约会 app,想在一个新城市部署,其实并没有那么大的区别。

在无人驾驶汽车中,扩展更加困难,因为它涉及许多新的应用。
澳大利亚的自动驾驶汽车必须开发袋鼠检测模型。
加拿大的自动驾驶汽车必须检测和分割雪域。

项目经理必须确定所有这些必要的任务,并与开发人员沟通,以确保及时开发和测试所有东西。
它涉及了解自动驾驶汽车的完整架构,并为每项任务制定详细的时间表。

在自动驾驶汽车里,时间表是最难定义的!如果你需要试车跑道,你可以从下个月开始租两天。如果算法比计划晚了 7 天,其他一切都有风险。如果机器人化没有及时完成,本地化就无法测试,甚至无法开发。

有些模块包括在试车跑道上。
这是本地化的情况,因为开发人员必须准确地知道 GPS 周围的情况,有哪些地标……
为此,开发人员需要在测试轨道上,并记录场景。

规划每一项任务意味着你可以预见问题。如果汽车在测试中出现电池问题,必须在 2-3 天内修复。否则,开发人员将会浪费时间。

需要了解技术挑战,如果经理了解,他会更好。
但是,我见过对算法一点头绪都没有,而信任工程师的项目经理。根据我的经验,这对项目没有太大影响。我不会建议经理不知道激光雷达是如何工作的,或者为什么我们不能将汽车更新到新的 Ubuntu 版本。

我会告诉你相反的情况。非常接近技术挑战,因为你与开发人员交流的方式可能会帮助他们重新思考情况,并帮助你更好地估计时间。

当人们埋头苦干时,最好有一个能帮上忙的人。

  • 每天与每个开发人员进行 15-30 分钟的交谈,将有助于更快地解决这些挑战,并让您更接近现实。

更精细的项目管理方法被发明出来了,我建议你看看这个

在更大的范围内,项目经理还与各种服务提供商、客户和潜在客户合作。

供应商

照片由i̇rfan·西姆萨尔Unsplash 上拍摄

让我们以一家初创公司为例,它的任务是开发一种自主航天飞机。如果创业公司不处理开发的一个方面,比如机器人化,它将需要外包。

项目经理的角色是确定提供商,协商价格,并确保硬件架构符合算法。如果你是一名计算机视觉工程师,你可能知道相机的位置对 3D 渲染很重要。如果相机有某种镜头,它会改变距离感。

一切都很重要。
从买来的传感器类型,到每个传感器的位置。
冷却系统…除了加热计算机和图形处理器…
掌握自动驾驶汽车自动化过程的每个方面是一项需要经验的艰巨任务。

您可能需要处理的提供商有:

  • 机器人化和汽车制造商🚘
  • 传感器提供商📷
  • 算法提供商💻

购买传感器时,你必须确保工程师知道如何使用它。
让我们来看看这样一个现实:一家初创公司无法为每项任务雇佣 50 名工程师。如果你的公司已经雇佣了工程师,发展会受到他们的技能和愿望的影响。

购买算法的时候,一定要和团队紧密合作。
如果你的创业公司没有计算机视觉工程师,而你需要一个车道线感知系统,这是一个新项目。

创业公司可以为开发者付费,也可以为解决方案付费。

总之,车道线检测系统取决于它将行驶的环境类型,就像几乎所有其他东西一样。这意味着车队也需要使用赛道来测试他们的软件
这是一个你不能使用车辆完成任何其他任务的时间段

正如我所说,制定时间表是一项非常困难的任务,它需要对技术挑战有非常好的理解,以及对问题有很好的预见能力。

客户

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

经理接触的最后一类人是客户。

客户给公司钱以换取服务或产品。

如果经理负责与客户的关系,他必须非常清楚正在发生的一切。

对很多人来说,与客户的关系是最难处理的。

客户可以改变很多想法。
他们可能会突然想要一个前一天不需要的功能。
他们可能需要加快截止日期,以配合您不知道的特定媒体活动。经理必须足够灵活,这样一天的轮班不会毁掉一切。

通常,最后期限是由客户设定的。如果期限太短,整个项目可能很难计划。

有时,客户可能需要你做你不理解的事情。客户对经理的信任至关重要。
如果客户觉得和其他人在一起不安全,他可能会要求经理每天都在现场…
这通常是不必要的,而且会危及项目。

即使不需要,也是客户的条件。
如果经理接受了,那就成了新的问题需要处理。

经理必须:

  • 让客户满意
  • 但是要确保它不会影响项目本身

可能需要一些额外的任务,比如谈判,但在初创公司,通常是直接与首席执行官谈判。

项目管理是一项基本任务。许多公司认为他们不需要项目经理,因为开发人员可以应付。这在自动驾驶汽车创业公司里简直是不可能的。这些工作都非常不同。

项目经理的最后接触是和他的主管。我们不要深究细节。

经理必须能够跟上最后期限和进度。客户、提供商和开发者是我们能找到的三个主要的人。

(来源)

杰里米·科恩。

💌订阅私人邮件列表每天学习自主机器人!

🚎如果你想了解更多关于自动驾驶汽车的知识,你可以参加我的课程自动驾驶汽车:学习将改变我们生活的尖端技术的指南

基于深度强化学习的自我改进聊天机器人

原文:https://towardsdatascience.com/self-improving-chatbots-based-on-reinforcement-learning-75cca62debce?source=collection_archive---------14-----------------------

自我改进聊天机器人的强化学习(RL)模型,专门针对 FAQ 类型的聊天机器人。

埃琳娜·里恰尔代利,德布马尔亚·比斯瓦斯

摘要。 我们提出了一个自我改进聊天机器人的强化学习(RL)模型,专门针对 FAQ 类型的聊天机器人。该模型的目的不是从头构建一个对话系统,而是利用用户对话中的数据来提高聊天机器人的性能。我们的方法的核心是一个评分模型,该模型被训练为基于用户反馈对聊天机器人话语响应元组进行评分。由该模型预测的分数被用作对 RL 代理的奖励。策略学习离线进行,这要感谢一个用户模拟器,它从 FAQ 数据库中输入话语。使用具有ε贪婪探索的深度 Q 网络(DQN)代理来实施策略学习,该代理被定制为有效地包括范围外问题的回退答案。从一个企业聊天机器人中提取的一个小案例展示了我们方法的潜力。它表明,在 20-30 个训练周期内,绩效从最初的 50%提高到 75%。

发表的版本的论文可在以下获得,刊登在 2019 年蒙特利尔第四届强化学习与决策多学科会议论文集(RLDM)(论文 ) ( 代码)

图 1: RL 模型架构(图片由作者提供)

1 导言

企业环境中的大多数对话代理都是特定领域的,由一个自然语言理解(NLU)单元组成,该单元被训练成以受监督的方式识别用户的目标。然而,为生产系统收集一个好的训练集是一个耗时且繁琐的过程。由于意图重叠和混淆,涵盖广泛意图的聊天机器人经常面临糟糕的性能。此外,考虑到来自实际使用或测试阶段的用户反馈,很难自主地重新训练聊天机器人。自我改进的聊天机器人很难实现,主要是因为很难选择和优先考虑聊天机器人性能评估的指标。理想情况下,人们希望对话代理能够从用户的经验中学习并自主改进。

在这项工作中,我们提出了一种自我改进聊天机器人的强化学习方法,特别针对 FAQ 类型的聊天机器人。这种聊天机器人的核心是一个意图识别 NLU,它通过问题变体的硬编码示例进行训练。当没有符合 30%以上置信度的意图时,聊天机器人会返回一个后备答案。对于所有其他情况,NLU 引擎会随响应一起返回相应的可信度。

几篇研究论文[2,3,7,8]显示了 RL 方法在开发对话系统中的有效性。这种方法的关键是选择一个好的奖励模式。一个典型的奖励模型是对每个对话回合实施一个惩罚项。然而,这种奖励只适用于任务完成聊天机器人,其中代理的目的是在最短的时间内满足用户的请求,但它不适合 FAQ 类型的聊天机器人,其中聊天机器人被期望在一个回合中提供一个好的答案。用户的反馈也可以用作在线强化学习中的奖励模型。然而,在实时对话中应用 RL 可能具有挑战性,并且在 RL 失败的情况下可能会产生巨大的成本。

对于已部署的系统,更好的方法是离线执行 RL 训练,然后一旦达到令人满意的性能水平就更新 NLU 策略。

2 强化学习模型

RL 模型架构如图 1 所示。该模型的各种组件是:NLU 单元,用于在预热阶段最初训练 RL 代理;用户模拟器,其从用户体验数据库中随机提取用户话语;分数模型根据具有反馈的用户对话和基于深度 Q 网络(DQN)网络的 RL 代理进行训练。

2.1 对话系统

我们在一个 FAQ 类型的聊天机器人上应用了强化学习方法。

在聊天机器人的核心,有一个意图识别 NLU,它是用问题变化的硬编码示例训练的。意图被定义为用户的意图,其通过话语来表达。对于这项工作,我们选择了来自 Rasa 的开源 NLU,使用 TensorFlow 管道。然而,RL 方法独立于所选的 NLU,对于生产中的系统,它可以很容易地扩展到 NLU 引擎,如 IBM Watson 或 Amazon LEX。

2.2 真实用户对话

在我们的工作中,我们使用了在开发实际内部聊天机器人过程中获得的用户反馈。

聊天机器人的工作范围是回答员工有关办公大楼设施、人力资源政策和福利等问题。

所有参与测试阶段的 10 名用户都被告知,他们的反馈将用于改善聊天机器人的性能。测试人员在每轮对话后提供一个(二元)反馈,从而对话语-回应元组进行评级。因此,历史数据包含以下格式的四个部分:(话语、响应、NLU 置信度和反馈)。通过移除无效对话(即缺乏反馈或反馈无效的对话),我们最终得到 550 个用户对话,触发了大约 120 个意图。尽管我们已经在所有对话中测试了评分模型,但 RL 模型仅应用于 155 个对话的子样本,触发了前 5 个意向。在这个子集上,用户的满意度是 50%。

表 1:来自数据库的对话示例,以及由模型和用户提供的分数

2.3 奖励功能:分数模型

评估聊天机器人的性能是计算语言学中长期存在的问题。从机器翻译(例如[6])借用的自动度量在短句(例如[4])上表现不佳,例如聊天机器人话语-响应元组。另一方面,人类对聊天机器人的评级是目前评估聊天机器人成功与否的事实上的标准,尽管这些评级往往很难收集,而且成本高昂。

为了评估聊天机器人响应的正确性,我们提出了一种新的方法,该方法利用在聊天机器人的开发和测试阶段收集的用户对话日志。每个用户都被要求在每次聊天机器人回合时提供一个二元反馈(正面/负面)。

为了在离线强化学习中使用用户反馈,我们开发了一个分数模型,能够为看不见的话语响应元组的二元反馈建模。在受监督的方式中,分数模型学习如何将话语和响应的向量表示投影到线性变换的空间中,使得相似的向量表示给出高分。至于句子的向量表示,我们通过通用句子编码器[1]计算句子嵌入,该编码器可通过 TensorFlow Hub 获得。为了训练模型,利用 L2 规则对(模型预测和人类反馈之间的)平方误差损失进行优化。为了评估该模型,预测的分数然后被转换成二进制结果并与目标(用户反馈)进行比较。对于那些既具有正反馈又具有接近 1 的 NLU 置信水平的已识别意图的话语对,我们执行数据扩充,给话语和后退意图的组合分配低分。

[4]提出了一种类似的聊天机器人评估方法。作者通过使用一组经过标记的对话对分数进行建模,这些对话还包括通过众包收集的模型和人类生成的响应。

我们的方法与上述作者的不同之处在于,它只需要一组带标签的话语响应元组,这些元组在聊天机器人开发和用户测试阶段相对容易收集。

2.4 与 DQN 的政策学习

为了学习策略,RL 代理使用 DQN 架构的 Q 学习算法[5]。在 DQN,训练一个神经网络来逼近状态-动作函数 Q(s_t,a_t,θ) ,它代表在状态 s_t 提供的动作 a_t 的质量,而 θ 是可训练的参数。至于 DQN 网络,我们采用了[3]提出的方法,使用一个全连接的网络,由一个经验重放池缓冲区提供,它包含话语和响应的一键表示以及相应的奖励。在这种情况下,一次性表示是可能的,因为我们对于话语(由日志中真实用户的问题数量给出)和响应(等于在我们的测试用例中使用的意图数量,5)有有限的可能值。在热身阶段,DQN 在 NLU 上进行训练,使用 NLU 置信度作为奖励。每当状态-动作对具有高于阈值的置信度时,通过将零权重分配给给定状态和所有其他可用动作,DQN 训练集被扩充。因此,在 RL 训练开始时,代理的表现类似于 NLU 单元。

在 RL 训练期间,我们使用ε-贪婪探索,其中根据概率ε探索随机动作。我们使用随时间变化的ε,这有助于在训练开始时进行探索,在最后一个历元期间 e_t0 = 0.2ε_t = 0.05 。为了在选择随机动作时加速学习,我们还强制更高的概率来获得“没有检测到意图”,因为几个问题实际上不在聊天机器人的范围内,但是它们被 NLU 错误地匹配到错误的意图。在一个时期内,我们模拟一批大小为 n 集的对话(在我们的实验中范围为 10 到 30 集),并用元组 (s_t,a_t,r_t) 填充体验重放缓冲区。缓冲区的大小是固定的,当代理性能提高到指定的阈值以上时,它会第一次被刷新。在状态-动作元组获得大于 50%的奖励的那些情节中,我们通过对当前状态的任何其他动作的分配分配零奖励来执行数据扩充。

图 2:分数模型的性能。左侧面板:交叉验证的测试集准确度,对于具有不同意向数量的不同子样本,具有 95%的置信区间。水平红线表示整个样本的性能。右侧面板:不同子样本的 ROC 曲线。

3 模型评估

3.1 评分模型评估

为了评估模型,我们选择对话的子集,触发前 N 个意图,N 在 5 到 50 之间。图 2 总结了评分模型的结果,显示了测试集的交叉验证(5 倍 CV)准确性和作为意向数量函数的 ROC 曲线。

对于整个对话样本,我们获得了 75%的交叉验证准确率和 0.84 的 AUC。

然而,通过仅选择那些触发前 5 个意向的对话,从而包括每个意向的更多示例,我们获得了 86%的准确率和 0.94 的 AUC。对于 RL 模型评估,我们重点关注 5 个意向子集;这确保了我们有最可靠的回报。

3.2 强化学习模型评估

RL 训练的学习曲线如图 3 所示。在左侧面板中,我们将 RL 训练和奖励模型与直接奖励(以交互方式)进行的测试进行了比较,显示得分模型给出了与奖励已知的参考案例相似的表现。平均分的大幅波动是由于有限的批量 (n 集= 10) 和相对较大的ε。我们还显示了从完整样本中提取的 20 个对话的测试集的成功率,其中为所有话语手动提供了“黄金响应”。

在仅仅 30 个时期内,代理成功率从最初的 50%增加到 75%,显示了这种方法的潜力。

在右边的面板中,我们显示了使用 n 集= 30 的结果,显示了类似的性能,但具有更平滑的学习曲线。

图 3:学习曲线显示了基于 20 个对话的标记测试集的 DQN 代理的每个训练时期的平均分数(连续黑线)和成功率(紫色阴影区域)。左侧面板:具有互动奖励(黑线)和奖励模型(蓝色虚线)的 direct RL 的学习曲线,每个时期使用 10 集。右侧面板:模型奖励的学习曲线,每个时期使用 30 集。

4 个结论

在这项工作中,我们根据用户测试阶段的反馈,展示了强化学习方法在提高 FAQ 类型聊天机器人性能方面的潜力。为了实现这一点,我们开发了一个分数模型,它能够预测用户对话语响应元组的满意度,并实现了一个 DQN 强化模型,使用分数模型预测作为奖励。我们已经在一个小型但真实的测试案例上评估了该模型,展示了有希望的结果。更多时代的进一步培训和包括更多数据,以及对模型超参数的广泛测试正在进行中。我们的方法的价值在于提供了一种实用的工具,以基于用户反馈的自动化方式来改进大规模聊天机器人(具有大量不同的意图)。

最后,我们注意到,虽然本文中提出的强化学习模型适用于 FAQ 类型的聊天机器人,但它可以通过合并更复杂的分数模型来概括包括对话的顺序性质。

参考

[1]丹尼尔·瑟尔等人。艾尔。通用句子编码器。CoRR,abs/1803.11175,2018。

[2]李继伟、威尔·门罗、艾伦·里特、米歇尔·格里、高剑锋和丹·茹拉夫斯基。对话生成的深度强化学习。arXiv 预印本 arXiv:1606.01541,2016。

[3]、Yun-Nung Chen、高剑锋和 Asli Celikyilmaz。端到端任务完成神经对话系统。2017 年第八届国际自然语言处理联合会议。

[4]瑞恩·洛威等人。艾尔。走向自动图灵测试:学习评估对话反应。《计算语言学协会第 55 届年会论文集》(第 1 卷:长篇论文),第 1116-1126 页。计算语言学协会,2017。

[5] Volodymyr Mnih 等。艾尔。通过深度强化学习实现人类水平的控制。《自然》, 2015 年第 2 期,第 518:529 页。

[6]基肖尔·帕皮尼尼、萨利姆·鲁科斯、托德沃德和威-朱婧。Bleu:一种自动评估机器翻译的方法。计算语言学协会第 40 届年会论文集,ACL '02,311-318 页,2002。

[7]彭,,高剑锋,,黄锦辉.Deep dyna-q:任务完成对话策略学习的集成规划。《计算语言学协会第 56 届年会论文集》(第 1 卷:长篇论文),第 2182-2192 页。计算语言学协会,2018。

[8]尤利安·弗拉德·塞尔班等。艾尔。一个深度强化学习聊天机器人。更正,abs/1709.02349,2017。

冠状病毒正在创造新一代的游戏玩家

原文:https://towardsdatascience.com/self-isolation-is-creating-a-new-generation-of-gamers-367075ab8346?source=collection_archive---------36-----------------------

在堡垒之夜战斗车上不需要社交距离

照片:格伦·卡斯滕斯-彼得斯

C ovid-19 并没有提供多少好消息,特别是在过去的几周里,因为“自我隔离”和“社会距离”成为拉平曲线的不可协商的问题。这些都是艰难的步骤。人类是群居动物——被迫与我们周围的人断开联系打击了我们情感和心理的健康。

在这个大规模隔离的黑暗时刻,社会很快就转向了一个出口,既提供逃避现实的机会,又提供了一个在线聚会和社交的结构。以下是一些令人震惊的统计数据,显示了自闭者对网络游戏的狂热:

  • 在完全封锁的意大利,电信官员报告互联网使用增长了 70%—特别将增长归功于“在线游戏,如堡垒之夜”。
  • 在部分封锁的美国,数据报告显示在高峰时段玩在线游戏的人数激增了 75%(还没有数据显示这些游戏玩家中有多少人应该在家工作)。
  • 一周前,超过 2000 万人同时登录 Steam,打破了历史记录。从那以后,这个数字基本上每天都在增加——就在今天,Steam 创下了 2250 万的新纪录
  • 一款全新的游戏《使命召唤:战争地带》在发布的前两周就有3000 万玩家——这个数字对于一款新游戏来说基本上是前所未有的,即使是在免费游戏中。

当然,这是真的,自我隔离的无聊的人在休闲选择上有点缺乏。社交距离意味着你不能去看一部新电影,不能和你的社交篮球队一起打篮球,也不能和朋友去酒吧。由于我们平时做的很多娱乐活动都不在餐桌上,游戏是我们真正能做的为数不多的活动之一。

然而,有一个很好的理由来解释为什么电子游戏的发展速度比 Wasgij 拼图还要快..

逃离新冠肺炎世界的完美方式

网络游戏的两个方面使得它们几乎是为疫情充斥的世界中自我孤立的个人的困境量身定制的。首先,游戏让玩家有机会逃离现实,进入一个沉浸式的虚拟现实,远离压力和喧嚣。第二,网络游戏是一种基本的社交媒体,给玩家一个不需要离开休息室的社区。

我们先来看看逃避现实的强大功能。与书籍或拼图游戏相比,游戏为玩家提供了更深的沉浸感,这得益于独特的幻想世界、夸张的画面和令人上瘾的反馈循环。沉迷于电子游戏是非常容易的。当然,这并不总是一件好事,但它确实为那些寻求逃离日常生活中新冠肺炎无所不在的势力的玩家提供了一种受欢迎的解脱。

任何阅读这篇文章的人都会知道冠状病毒的讨论有多普遍,从媒体到日常谈话,无所不包。这种疫情带来的持续的精神紧张和焦虑是一个非常现实的问题,特别是对于那些有亲人直接受到病毒影响的人(无论是感染了病毒,还是在经济冲突中失去了工作)。游戏为这种压力提供了一个没有新冠肺炎的出口。举个例子,引用一个游戏玩家的话, [NPR 和](/"It's kind of escapism," she says. "Right now things are really scary and I just can't wait to go onto an island and be in debt to a raccoon, and not have coronavirus. I can make my island whatever I want it to be. I can have all my villagers and they're all nice. It's just very idealistic.")谈到了在疫情玩动物穿越和口袋妖怪:

这是一种逃避现实的方式。现在事情真的很可怕,我等不及要去一个岛上,欠一只浣熊的债,而且不要有冠状病毒。我可以把我的岛变成我想要的样子。我可以拥有我所有的村民,他们都很好。只是很理想化。

另一方面,其他处于封闭状态的人拼命寻求的是一种新的社会生活结构——随着我们所有的典型社区因社交距离的需要而被连根拔起,我们现在需要技术来给我们人类所需的联系和社区感。这方面的一个例子是聊天应用“家庭聚会”的爆发,这是一种促进朋友之间轻松交流的有效方式。

网络游戏为自我隔离的朋友提供了一个重要的方式,让他们继续一起参加有意义的活动。像 Apex Legends 这样受欢迎的游戏完全是围绕着小的玩家群体——小队——一起工作和交流以取得成功。游戏还为朋友和社区提供了类似于锦标赛赛季的结构。游戏既提供了与朋友共度时光的有趣方式,也提供了一致的社交基础设施。当大多数其他社会活动被新冠肺炎完全打乱时,这可不是一件小事。

正如一位自我封闭的游戏玩家在《边缘》中所说,社交互动的结构甚至可能是在线游戏最重要的特征:

当你一整天独自在家工作,穿着你的慢跑裤(希望是洗过的),玩游戏有时更多的是和其他人一起玩,而不是游戏本身。

通过这种方式,在线游戏为冠状病毒的隔离和破坏性特征提供了一个真正的对抗手段。谢天谢地,因为我们还远远没有摆脱自我孤立。

封锁的时代才刚刚开始

在我的家乡新西兰,总理今天宣布全国将在 48 小时内进入一级防范禁闭状态,并持续四周。这个决定做出后,肯定有一定程度的震惊,但大多数新西兰人同意总理——我们宁愿承受短期的痛苦,也不愿像意大利一样,病毒肆虐,死亡人数不断增加。

“锁定”在实践中意味着什么?对我和其他所有不在基本服务部门工作的新西兰人来说,我们将整整一个月呆在家里。与我交谈过的大多数人都计划充分利用在家的额外时间,而不是哀叹通过 Zoom 进行的一个月的工作会议。这当然是一个朋友的可行方法,他今天被发现带着一个全新的 PlayStation 和三个闪亮的新游戏离开商场,让他忙个不停。

促使新西兰决定进入一级防范状态的强大公共卫生逻辑同样适用于其他所有抗击新冠肺炎的国家。困难的事实是,意大利锁定得太晚了,现在正在为早期预警信号管理不善付出代价。

关于如何使曲线变平,科学是如此清晰,以至于连 T2 都在关注。接下来,许多其他国家也在考虑如何最大限度地自我隔离,即使这涉及到将整个国家封锁起来。印度已经封锁了超过 1 亿人以阻止病毒的传播,更多人将会跟进。法国西班牙丹麦马来西亚都在最近几天实施了封锁。

在这种危险的发展速度下,预测世界上大多数国家可能会实施自我隔离以阻止病毒传播已经不再令人愤慨。这种做法的实际效果是让数十亿人像我在新西兰一样呆在家里。就像我的朋友和他的新 PlayStation 一样,许多新近被孤立的人将把游戏作为一种发泄方式。

出于一系列原因,我们应该庆祝新一代游戏玩家的诞生。玩网络游戏提供了一种逃离疫情的方式和一个现成的网络社区。随着群居动物受到孤立的严重打击,我们可能会做得更糟。

如果你对这类关于游戏的社会影响的思考感兴趣,你可能会喜欢我的新出版物。我会定期写技术如何改变社会,比如我最近的一篇关于冠状病毒如何让大规模监控成为我们的新常态的文章。

自组织地图简介

原文:https://towardsdatascience.com/self-organizing-maps-for-dimension-reduction-data-visualization-and-clustering-ff966edd311c?source=collection_archive---------6-----------------------

用于降维、数据可视化和聚类的自组织映射

安德鲁·斯图特斯曼在 Unsplash 上的照片

S 自组织映射(SOM) 是一种常见的无监督神经网络模型。SOM 已被广泛用于聚类、降维和特征检测。SOM 是由 Kohonen 教授首先提出的。正因如此,SOM 也叫科霍宁地图。它有许多实际应用,包括机器状态监控、故障识别、卫星遥感过程和机器人控制[1]。此外,SOM 通过利用拓扑相似性属性将高维数据投影到低维空间来用于数据可视化。在模型开发过程中,SOM 利用竞争学习技术,而传统的神经网络通过梯度下降算法的反向传播来应用误差减少过程。在这篇文章中,我分享了我对 SOM 的理解,它是如何学习的,方法,以及 SOM 的局限性。

SOM 如何学习?

SOM 的架构非常类似于神经网络架构,但它比人工神经网络(ANN)简单得多。SOM one 包含两层:输入层和输出层(特征地图)。SOM 通过初始化权重向量来开始特征映射。SOM 中的权重与 ANN 中的权重具有完全不同的内涵。在神经网络建模中:将激活函数应用于权重和输入值的线性组合,以产生架构中每个神经元的输出。另一方面,SOM 不应用激活功能。并采用权重作为架构中神经元的特征。权重通常是随机生成的。使用权重向量作为神经元特征的动机是将给定数据的每一行(观察值)推入一个虚拟空间,其中每一行充当一个点。这是高级官员会议的核心。一次,每个数据保存一个输入空间的虚点,然后搜索最近的点(数据)。

假设我们有一个只有四个观察值(行)的三维数据集(特征-x1、x2 和 x3)。我们希望对数据集应用 SOM 方法以达到降维的目的,即我们希望将数据从给定的三维空间转换到二维空间。SOM 中有几个参数,例如神经元的数量。我们选择两个神经元,因为我们想将数据转换到二维空间。这意味着,SOM 包含两层:输入层(3 个神经元/节点)和输出层(2 个神经元/节点)。这里,我们介绍 SOM 的几个步骤:

1.初始化随机权重向量 —在该步骤中,随机权重向量被初始化。对于像人工神经网络这样的迭代方法来说,良好的初始近似是一个众所周知的挑战。虽然权重的随机初始化是一种常见的做法,但利用数据的第一主成分空间的主成分初始化由于结果的可重复性而获得了极大的欢迎[3]。神经元的权重向量维数/大小应该是输入空间的大小。在这个例子中:神经元 W1 和 W2 分别与权重向量(1,2,3)和(6,5,4)相关联。

2.随机选择一个输入— 假设随机选择的输入是最后一行(1,1,1)

winner 神经元的计算过程

3.使用欧几里德距离计算赢家神经元 —在这一步,计算随机选择的输入和每个神经元之间的欧几里德距离。下表显示了两个神经元的计算。距离最短的神经元是获胜神经元。这里,W1 是获胜神经元。获胜的神经元被称为最佳匹配单元(BMU)。除了欧几里德距离,我们还可以使用其他距离度量来计算身体质量指数。在此步骤中,计算 BMU 的邻域,其中基于指数衰减函数考虑邻域大小[2]。随着时间的推移,BMU 周围的邻域变小。以下等式显示了指数衰减函数,其中 t 是当前时间步长,sigma0 是初始时间的半径,是依赖的时间常数,以及该方法的选定迭代次数。

用于查找邻居大小的指数衰减函数

BMU 附近半径的缩小

4。 更新神经元权重— 在此步骤中,调整 BMU 和邻域的权重,以调查与输入向量最相似的神经元,并预期更靠近 BMU 的邻域会有显著变化。离 BMU 越远的邻居了解得越少(权重变化不明显)。以下等式显示了更新神经元的计算:

更新神经元权重的公式

其中 t 是当前时间步长,L 是学习率,也是一个指数衰减函数,与上一个函数类似:

学习率的方程式

n 是影响率(另一个指数衰减函数),其决定邻域的半径(大小),并且随着迭代的增加,大小逐渐缩小,并且最终邻域在迭代(训练)结束时缩小到大小为零[2]。下面的等式是影响率的表达式:

影响率方程

这里,距离是每对神经元(W_i 和 W_j)之间的晶格距离。

5。 重复 2–4 直到训练结束— 重复步骤 1–4 直到神经元的位置稳定。

虽然 SOM 是一种广泛使用的易于解释的无监督技术,它允许在低维网格内可视化观察之间的相似性,但它有一些限制:

  1. SOM 需要足够的数据量来生成有意义的聚类,因为不足的或无关的数据可能会给聚类增加额外的随机性。
  2. SOM 遇到分类数据聚类的困难[5]。SOM 通常在将数据转换为指示变量(如二元变量)后应用于分类变量。分类特征之间的相似性属性可能由于转换而丢失有价值的信息,因此,经过训练的 SOM 可能无法呈现数据的正确拓扑属性。

相关文章-

机器学习管道中的挑战

阅读默罕默德·马苏姆博士(以及媒体上成千上万的其他作家)的每一个故事。

你的会员费将直接支持和激励穆罕默德·马苏姆和你所阅读的成千上万的其他作家。你还可以在媒体上看到所有的故事—https://masum-math8065.medium.com/membership

快乐阅读!

参考:

[1]https://users . ics . Aalto . fi/jhollmen/di PPA/node 28 . html #应用程序

https://www.saedsayad.com/clustering_som.htm

[3] A .钱皮,y .莱切维利耶,《大型多层次数据集的聚类:一种基于科霍宁自组织图的方法》,载于 D.A .齐格德、j .科莫洛夫斯基、j .兹特科(编辑。),PKDD 2000 年,施普林格·LNCS(LNAI),第 1910 卷,第 353-358 页,2000 年。

[4]https://www . cs . HMC . edu/~ kpang/nn/som . html #:~:text = The % 20 main % 20 draw back % 20 of % 20 The,be % 20 totally % 20 accurate % 20 or % 20 informationary

[5]https://www . comp . NUS . edu . SG/~ rudys/Arnie/tnn-som-categoricaldata . pdf

用于机器学习的自定进度学习

原文:https://towardsdatascience.com/self-paced-learning-for-machine-learning-f1c489316c61?source=collection_archive---------14-----------------------

提高神经网络收敛的聪明方法(并发现异常…)

你通过无情地向你的神经网络灌输数据来折磨它!通常,当用随机梯度下降(SGD)训练机器学习模型时,训练数据集会被打乱。通过这种方式,我们可以确保模型以无特定顺序看到不同的数据点,并且可以均衡地学习任务,而不会陷入局部最优。然而,早在 2009 年,Bengio 等人就证明了某种排序是有益的。他们将他们的方法称为课程学习,并表明如果机器学习模型的训练数据按照特定的顺序,它会达到更高的准确性。更准确地说,开头的例子比较容易,结尾的例子比较难。在他们的实验中,他们使用了一个已经训练好的模型,并让这个模型决定什么样的数据点容易或难。然后,一个新的模型在正确排序的数据集上进行训练,并收敛到比随机排序或相反课程训练的模型更高的精度。

在我目前的项目中,我遇到了一种叫做的自定进度学习 (SPL)的技术。这不是一个新的想法,相应的论文发表于大约 10 年前。无论如何,这种技术非常有趣而且仍然重要,因为它有助于随机梯度下降(SGD)更快地收敛,甚至更高的精度。它会跳过某些被认为太难的数据点。它基于课程学习,但在训练时对数据进行分类。不需要额外的预训练模型来决定排序。因此得名自学

苏珊·d·威廉姆斯在 Unsplash 上的照片

SPL 背后的直觉

自定进度学习这个术语起源于人类使用的一种学习技术。它允许你定义自己的速度,以适应你的学习模式。SPL 可以被看作是在学习或训练一项特殊技能,例如数学。当我们开始学习数学时,我们从数数开始,然后是加法、减法等等。我们直到某个年龄才听说矩阵乘法或者导数。同样,机器学习的 SPL 从非常简单的例子开始,一旦学会,就从已经学会的“基础”中受益,继续学习更难的例子。我把 SPL 想象成随着时间的推移缩小任务范围的一种方式。考虑一个二维空间中的简单分类任务和一个需要在正确点分割两个点云的模型。较容易的样本远离相交区域。较硬的样品靠近相交区域。模型的初始状态是这个空间某处的一条线。如果我们只从简单的数据点开始,模型会得到告诉它向某个方向前进的梯度。如果我们只从硬点开始,我们的模型会知道它是错误的,会得到一个方向,但可能会远离另一边。将点缩小到正确的区域有助于模型避免超调并更平滑地收敛,正如我在下面创建的动画中看到的那样。

简单数据集上的自定进度学习

该算法

诀窍很简单。它使用一个阈值,我们称之为λ。它的存在是为了与训练集中数据点的损失值进行比较。通常,λ从一个接近 0 的数开始非常低。对于每个时期,λ被乘以一个大于 1 的固定因子。被训练的模型必须计算其训练点的损失值以执行 SGD。通常,这些损失值随着进一步的训练迭代而变得更小,因为模型在训练任务方面变得更好,并且犯的错误更少。阈值λ现在确定数据点是被认为容易还是困难。每当一个数据点的损失低于λ时,它就是一个容易的数据点。如果是上面的,那就算辛苦了。在训练期间,反向传播步骤仅在容易的数据点上执行,而困难的数据点被跳过。因此,该模型在训练过程中每当其进展足够大时就增加训练实例的难度。当然,在开始时,模型可能认为没有数据点是容易的,根本不会训练。因此,SPL 的作者引入了一个热身阶段,在这个阶段不允许跳跃,只使用训练集的一小部分。

数学

损失函数最小化

SPL 的论文介绍了一种两步学习法。这里,损失函数被训练两次,保持一些变量对于每一步是固定的。给定模型权重“w”和变量“v”,损失函数需要最小化。在损失函数中,我们看到几项。第一项“r(w)”是一个常用的正则项,有助于模型避免过度拟合。这也是其他与 SPL 无关的损失函数的一部分。第二项是我们模型的数据点损失“f(x,y,w)”乘以变量“v”的总和。这个变量“v”稍后将决定当前数据点“(x,y)”是否足够容易进行训练。第三项是所有“v”的总和乘以阈值“lambda ”,我们在前面的章节中已经提到过。变量“v”是整数,只能取值“0”或“1”。在第一学习步骤中,变量“w”是固定的,只有变量“v”根据优化而改变。如果你仔细观察损失函数,我们会发现“λ”确实起到了阈值的作用。如果“f(x,y,w)”小于λ,并且“v”是 1,我们将从正则项中减去一些。因此,在“v=0”的情况下,我们不会减去任何东西,这比减去一些东西要大。如果“f(x,y,w)”大于λ,并且“v=1”,“f(x,y,w)-λ”将为正,我们将添加一些东西。因此,在“v=0”的情况下,我们不会添加任何东西,这比添加一些东西要小。总之,每当“f(x,y,w)”小于“λ”时,第一步通过将“v”设置为“1”来优化“L”,否则设置为“0”。第二步固定之前计算的“v”并优化“w”。如果“v”是“1”,则执行通常的模型更新,例如反向传播。如果“v”是“0”,则“f(x,y,w)”的梯度也将是 0,并且不执行更新(除了正则化项,但是为了更好地理解,现在可以忽略它)。在开始时,将阈值设置为非常低的数字将不会产生任何结果,因为所有的“v”都将是“0 ”,因为没有数据点丢失会低于阈值。因此,SPL 的作者建议在没有 SPL 的情况下进行一定次数的迭代,然后从 SPL 开始。

PyTorch 实现

在下面的代码示例中,我展示了如何在虚拟数据集上用 PyTorch 实现 SPL。特别是,我们将为我在这篇博文开头展示的动画进行训练。首先,我们将定义一个非常简单的模型,接受 2 个特征并输出两个数字,这两个数字定义了每个类别的概率。输出告诉我们模型认为它看到的是什么类。为了将输出转换成概率,我们使用了 softmax 函数。不过,在代码中,我使用了 log_softmax 函数。这是由于我稍后使用的损失函数。最后,模型以同样的方式训练。

**import** torch
**import** torch.nn **as** nn

**class** Model(nn.Module):
    **def** __init__(self, input_size, output_size):
        super(Model, self).__init__()
        self.input_layer = nn.Linear(input_size, output_size)

    **def** forward(self, x):
        x = self.input_layer(x)
        **return** torch.log_softmax(x, dim=1)

损失函数代码可以在下一节看到。这里我们计算每个点的损耗,也就是 NLL 损耗。如果损失小于阈值,我们将损失乘以 1,否则乘以 0。因此,零乘损失对训练没有任何影响。

**import** torch
**from** torch **import** Tensor
**import** torch.nn **as** nn

**class** SPLLoss(nn.NLLLoss):
    **def** __init__(self, *args, n_samples=0, **kwargs):
        super(SPLLoss, self).__init__(*args, **kwargs)
        self.threshold = 0.1
        self.growing_factor = 1.3
        self.v = torch.zeros(n_samples).int()

    **def** forward(self, input: Tensor, target: Tensor, index: Tensor) -> Tensor:
        super_loss = nn.functional.nll_loss(input, target, reduction=**"none"**)
        v = self.spl_loss(super_loss)
        self.v[index] = v
        **return** (super_loss * v).mean()

    **def** increase_threshold(self):
        self.threshold *= self.growing_factor

    **def** spl_loss(self, super_loss):
        v = super_loss < self.threshold
        **return** v.int()

最终,训练函数看起来和往常一样。我们加载一个数据加载器,初始化模型和优化器,并开始多次遍历数据集。为了简单起见,我省略了动画的绘图功能。

**import** torch.optim **as** optim

**from** model **import** Model
**from** dataset **import** get_dataloader
**from** loss **import** SPLLoss

**def** train():
    model = Model(2, 2, 2, 0)
    dataloader = get_dataloader()
    criterion = SPLLoss(n_samples=len(dataloader.dataset))
    optimizer = optim.Adam(model.parameters())

    **for** epoch **in** range(10):
        **for** index, data, target **in** dataloader:
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target, index)
            loss.backward()
            optimizer.step()
        criterion.increase_threshold()
    **return** model

整个项目可以在我的 GitHub 库中找到。你可以随意摆弄它。此外,绘图功能可以在那里找到。

异常检测

由于 SPL 方法是以某种方式根据基于损失的硬度对数据点进行排序,所以我有了用它进行异常检测的想法。异常是指与数据集中的任何其他数据点都不相似的数据点,距离很远,可能是错误输入或系统错误的结果。如果数据集中出现异常,其损失应该高于正常点的损失,因为机器学习模型不能概括错误,如果它们很少出现。SPL 的方法最终应该会越过异常点。这样,通过观察数据点的“激活”顺序,我们可以很容易地将它们归类为异常,即认为它们很容易。

对于这个实验,我使用了前面提到的代码,并且没有运行固定数量的时期。相反,只要有超过阈值的 5 个数据点,我就运行训练,因此被认为是困难的。一旦我有 5 个或更少,我就停止训练,把它们标为红点。正如你在下面的动画中看到的,算法在蓝云的左下部分发现了异常。我添加了这个异常,从橙色质心取最远的点,并将其类改为“橙色”。

最后用红点表示异常

当然,这个例子并不难,但它说明了异常检测面临的问题。如果维度多于 2 或 3,任务会变得更加复杂,并且会出现明显的异常,就像我们的例子中发现的那样不容易。

结论

为什么不是每个人都用 SPL?找到阈值的正确起始因子值和增长因子值需要一些时间,因为这不是通用的,会因模型、损失函数和数据集而异。对于我在这篇文章中使用的例子,我不得不多次尝试,最终找到正确的配置。假设你有一个非常大的数据集和一个非常大的模型。在你开始实际训练之前,多次检查整个进度基本上是不可行的。然而,还有多种适合不同培训设置的其他课程学习技巧。尽管有这些观点,目前的想法是一个非常直观的想法,很容易掌握,工作起来也很有趣。它基本上只是你需要优化的另一组超参数;-)

资源

链接

报纸

用于密集光流估计的自监督注意机制

原文:https://towardsdatascience.com/self-supervised-attention-mechanism-for-dense-optical-flow-estimation-b7709af48efd?source=collection_archive---------30-----------------------

内部人工智能

使用自监督深度学习的多目标跟踪

在我们进入自我监督注意力的含义之前,让我们先了解一下光流估计的直觉,以及它如何作为人类和计算机视觉系统跟踪物体的一种方法。

来源

人们一致认为,物体跟踪是人类婴儿在大约两到三个月的早期发展起来的基本能力。然而,在神经生理学的水平上,人类视觉系统的实际工作机制仍然有些模糊。与人类视觉系统类似,计算机视觉系统也广泛用于各种应用,如视频监控和自动驾驶。跟踪算法的目标是在给定的视频序列中重新定位在初始帧中已经识别的一组特定的对象。在与跟踪相关的研究文献中,它在两个主要类别下被研究,即视觉对象跟踪(VOT)和半监督视频对象分割(半 VOS)。第一种(VOT)旨在通过在整个视频序列中重新定位对象边界框来跟踪对象。而后者(半 VOS)通过像素级分割掩模在更细粒度的级别上跟踪对象。在这篇博客中,我们将讨论后一种方法背后的原始想法,即密集光流估计,以及这种密集跟踪方法是如何通过自我监督的注意机制实现的。

密集光流估计

稠密光流是光流概念的范畴之一。光流可以定义为视频序列的连续帧之间的物体运动,是物体和摄像机之间相对运动的结果。用科学的语言来解释,我们可以说,光流是图像中亮度模式的表观运动速度的分布,它是由物体和观察者的相对运动产生的。光流研究为稀疏光流密集光流稀疏光流导出帧中仅几个感兴趣像素的流矢量,这些流矢量描绘了对象的某个边缘或角落。另一方面,密集光流导出给定帧中所有像素的流矢量,从而以更多的计算和更低的速度为代价给出更高的精度。

网球运动员的密集光流估计

密集光流为视频序列中的每一帧的每个像素计算一个光流向量。与稀疏光流不同,这种方法为视频分割和运动结构学习等应用提供了更合适的输出。密集光流可以通过各种方法实现。其中,使用最简单的算法之一是 Farneback 方法。它基于 Gunner Farneback 的算法,Gunner Farneback 在 2003 年的“基于多项式展开的两帧运动估计”中解释了该算法。OpenCV 为这个算法提供了代码函数来寻找密集光流。要快速体验 Farneback 的算法是什么,请运行下面的代码片段。

运行上述代码后,您将在视频(Dense-optical-flow.mp4)中获得以下输出(右侧)

在下面的 GIF 中描述了可视化的光流。(重 gif,可能需要时间加载)

Farneback 算法是一种通过比较视频序列中的两个连续帧来估计某些图像特征的运动的有效技术。该算法首先使用多项式展开变换 通过二次多项式逼近图像帧的窗口。多项式展开变换是专门在空间域中设计的信号变换,并且可以用于任何维度的信号。该方法观察多项式变换的平移,以从多项式展开系数估计位移场。该方法然后在一系列迭代改进之后计算密集光流。在实现代码中,该算法从一个双通道流向量阵列(dx/dt,dy/dt)计算光流的方向和大小。然后,计算的方向和大小通过 HSV 颜色表示的值可视化,该值被设置为最大值 255 以获得最佳可见性。

用于密集光流估计的深度学习

从历史上看,光流问题是一个优化问题。在深度学习的最近发展之后,许多研究人员已经应用深度学习来解决这个优化问题,通过处理连续的视频帧作为输入来计算运动物体的光流。尽管这些方法一次只处理两个连续的帧,但是视频的本质仍然在这两个帧中被捕获。视频与图像的主要区别在于,除了图像的空间结构之外,视频还拥有时间结构。然而,视频也有其他形式,如声音,但它们在这种情况下没有用。因此,连续的帧流可以被解释为以特定时间分辨率(fps)操作的图像的集合。这意味着视频中的数据不仅在空间上编码,而且在顺序上编码,这使得对视频进行分类非常有趣,同时也具有挑战性。

来源

通常,深度神经网络需要大量的训练数据来学习和优化逼近函数。但是在光流估计的情况下,训练数据尤其难以获得。这背后的主要原因是难以将图像中每一点的精确运动精确标记到亚像素精度。因此,为了解决标记视频数据的问题,计算机图形被用于通过指令来模拟大量的现实世界。由于指令是已知的,所以视频帧序列中每个像素的运动也是已知的。试图解决光流问题的一些最近的研究是 PWC-Nets、ADLAB-PRFlow 和 FlowNet。光流被许多应用广泛继承,如通过基于特征的光流技术从固定的摄像机或附着在车辆上的摄像机进行目标检测和多目标跟踪的车辆跟踪和交通分析。

用于跟踪的自我监督深度学习

如前所述,在视频分析领域,视觉跟踪对于许多任务都是不可或缺的,如识别、交互和几何。但与此同时,由于对标记视频数据的巨大需求,使用深度学习来完成这些任务变得不可行。无论如何,为了实现高性能,大规模跟踪数据集变得必要,这反过来需要大量的努力,从而使深度学习方法更加不切实际和昂贵。牢记这一点,最近的研究人员将他们的信心放在了一种有前途的方法上,通过利用大量未标记和原始视频数据,使机器在没有人类监督的情况下进行学习(标记数据)。这种对自我监督学习的追求始于谷歌研究团队的一项研究提案,该提案建议通过在视频彩色化的代理任务上训练一个模型来制作一个视觉跟踪系统,这不需要任何额外的标记数据(自我监督)。然而,研究表明,不是让模型预测输入灰度帧的颜色,而是它必须学会从一组参考帧中复制颜色,从而导致能够在时间设置中跟踪视频序列的空间特征的指向机制的出现。这些自我监督方法的可视化和实验表明,尽管在没有任何人工监督的情况下训练了网络,但是在网络内部自动出现了用于视觉特征跟踪的机制。在对从互联网上收集的未标记视频进行大量训练后,自监督模型能够跟踪视频帧序列的初始帧中指定的任何分割区域。然而,自我监督的深度学习方法是在假设帧序列中的颜色是时间稳定的情况下训练的。显然,也有例外,比如视频中的彩灯可以打开和关闭。

在视频着色代理任务上训练的指针机制- 来源

跟踪中的自监督学习的目标是学习适合于沿着视频的帧序列匹配对应的特征嵌入。通过利用帧序列中的自然时空一致性来学习对应流。对应流可以理解为连续帧之间存在的特征相似流。用简单的语言来说,这种方法学习一种指针机制,它可以通过从一组参考帧中复制像素信息来重建目标图像。因此,要制作这样的模型,研究人员在设计架构时必须谨记一些注意事项。首先,我们必须防止模型学习该任务的琐碎解决方案(例如,基于低级颜色特征匹配连续帧)。第二,我们必须使跟踪器漂移不那么严重。跟踪器漂移(TD)主要是由于对象的遮挡、复杂的对象变形和随机的光照变化引起的。TD 通常通过在具有周期一致性和预定采样的长时间窗口上训练递归模型来处理。

对应流匹配视频上帧之间的对应关系— 来源

最后,在我们深入了解这个指针机制之前,让我们先了解一下上面提到的在设计这种模型时必须考虑的一些要点。首先,重要的是要记住,对应匹配是这些模型的基本构件。因此,在通过逐像素匹配进行帧重建时,模型很有可能会学习平凡解。为了防止模型过度适应一个平凡的解决方案,添加颜色抖动和通道方向的丢失是很重要的,这样该模型被迫依赖于低级别的颜色信息,并且必须对任何类型的颜色抖动都是鲁棒的。最后,如前所述,为了处理 TD,在具有前后一致性和预定采样的长时间窗口上进行递归训练是减轻跟踪器漂移问题的最佳方式。如果我们应用上述方法,我们可以确定模型的鲁棒性将增加,并且该方法将能够利用视频的时空一致性,并且颜色将能够充当用于学习对应关系的可靠的监督信号。

引擎盖下自我监督的注意力

如果你更深入地观察这里所学的指针机制,你会得出结论,它是一种注意力机制。是的,它最终是著名的 QKV 三重奏(查询-关键-值,大多数注意力机制的基础)。

来源

正如我们所知,自监督模型的目标是通过有效地编码特征表示来学习鲁棒的对应匹配。简单地说,有效复制的能力是通过对代理任务的训练来实现的,其中模型通过线性组合来自参考帧的像素数据来学习重建目标帧,权重测量像素之间的对应强度。然而,分解这个过程,我们发现我们处理的每个输入帧都有一个三元组(Q,K,V)。Q、K、V 指的是查询、键和值。为了重建 T 帧中的像素 I,注意机制被用于从原始序列中的先前帧的子集复制像素。只是,在这种情况下,查询向量(q)是当前帧(I)的特征嵌入(目标帧),关键向量是先前的 frame's(I⁰)特征嵌入(参考帧)。现在如果我们计算点积。)并取计算乘积的 softmax,我们可以得到当前帧(I)和先前参考帧(I⁰).)之间的相似性当在推断期间与参考实例分割掩模(V)相乘时,该计算的相似性矩阵将为我们的目标帧提供指针,从而实现密集光流估计。因此,这个指针只是 Q、K 和 V 的组合,是在这个自我监督系统下工作的实际注意力机制。

每个人都需要关注— 来源

注意力机制训练的一个关键要素是建立一个适当的信息瓶颈。为了避开注意力机制可能求助的任何学习捷径,使用了前面提到的有意丢弃输入颜色信息和通道丢失的技术。然而,颜色空间的选择仍然在通过自我监督训练这些注意机制中起着重要作用。许多研究工作已经验证了使用去相关颜色空间导致自监督密集光流估计的更好特征表示的推测。简单地说,使用 LAB 格式的图像比 RGB 格式的效果更好。这是因为所有 RGB 通道都包含一个亮度表示,使其与 Lab 中的亮度高度相关,因此成为一个微弱的信息瓶颈。

限制对最小化物理内存成本的关注

上面提出的注意机制通常伴随着高的物理存储成本。因此,处理用于对应匹配的高分辨率信息会导致较大的存储器需求和较慢的速度。

来源

为了避免存储开销,ROI 定位用于从存储体中非局部地估计候选窗口。直观上,我们可以说,对于时间上接近的帧,时空一致性自然存在于帧序列中。这种 ROI 定位导致注意力受限,因为现在目标帧中的像素仅与参考帧的空间相邻像素进行比较。可比较像素的数量由注意力被限制的扩大窗口的大小决定。窗口的扩展速率与存储体中当前帧和过去帧之间的时间距离成比例。在计算受限注意区域的亲和度矩阵之后,可以以非局部方式计算细粒度匹配分数。因此,通过提出的记忆增强的限制注意机制,该模型可以有效地处理高分辨率信息,而不会导致大量的物理内存开销。

结论

在这篇博客中,我们首先介绍了光流的概念,并研究了它在物体跟踪中的应用。我们还研究了这个概念如何启发了深度学习跟踪系统,以及自我监督和视觉注意力如何在制作这些系统中发挥关键作用。计算出的光流矢量开启了无数可能的应用,这些应用需要对视频进行如此深入的场景理解。所讨论的技术主要应用于行人跟踪、自主车辆导航和许多更新颖的应用。可以应用光流的各种应用仅受限于其设计者的独创性。

我个人认为,由于自我监督的普遍性和灵活性,它将很快成为被监督的对手的有力竞争者。在看不见的物体类别上,自我监督轻而易举地超越了大多数监督方法,这反映了它在未来的时间里的重要性和力量,因为我们正在朝着解决人类智能的方向前进。

我的博客反映了我的工作,并简单地传达了我对这些话题的理解。我对深度学习的解读可以和你不一样,但我的解读只能和我一样无误。

参考

[1] [1981-AI,Horn-Schunck 方法]确定光流

[2] [2003-SCIA,法内贝克流]基于多项式展开的两帧运动估计

[3] [2007-DAGM,TVL1 方法]一种基于对偶的实时 tv-l1 光流方法

[4]赖,子航,,谢."视频通信流的自我监督学习."ArXivABS/1905.00875(2019):n . PAG。

[5]赖,郑,陆,鄂,谢,魏(2020).主追踪器:记忆增强自我监督追踪器。 ArXiv,abs/2002.07793

[6]冯德里克、施里瓦斯塔瓦、法蒂、瓜达拉马和墨菲(2018 年)。跟踪是通过给视频着色而出现的。 ArXiv,abs/1806.09594

SFM 自我监督深度估计:打破观念

原文:https://towardsdatascience.com/self-supervised-depth-estimation-breaking-down-the-ideas-f212e4f05ffa?source=collection_archive---------7-----------------------

无需手动标注的学习深度

1.概观

这篇文章最后一次更新是在 2020 年 8 月 10 日

视差预测

这篇文章致力于探索通过自我监督学习进行深度估计的想法。关于深度估计的一些概念性想法充当先决条件。你可以参考这篇讨论相关话题和相关问题的文章。

自我监督的方法放松了对有注释的基础事实的硬性要求,这本身是麻烦的。它需要使用昂贵的高分辨率激光雷达,必须与相机进行良好的校准,以获得准确、良好的投影深度和同步数据。

由于上述原因,这种方法在研究人员中日益流行。它始于周[1]的开创性工作,其准确性大大落后于监督学习方法。从那以后,人们对这一领域的兴趣激增。许多工作已经开始系统地确定和解决这个框架中的每个组件,迅速缩小与监督学习方法的差距。

在本文中,我们将介绍以下内容:

  • 自我监督深度估计框架:训练深度模型所需的组件
  • 管道中每个组件需要考虑的相关问题
  • 致力于解决这些问题的研究工作。

从 RGBD 序列重建的场景

2.自我监督的深度估计是如何工作的?

这种方法是自我监督的,因为地面实况来自输入信号本身。在这种情况下是 RGB 图像。不需要任何外部数据或信号来教导网络→深度估计器本身就是自己的老师!

因此,我们将目标定义为基于一些输入图像重新合成图像。在我们的上下文中,通过利用 3D 场景几何来合成图像。其以数学理论为基础来模拟 3D 世界和图像平面之间的关系。

A.自我监督学习框架

自监督深度估计流水线

在大画面上,当提供了深度和自我运动时,我们可以通过从相机视点应用投影扭曲来合成新的视图(目标)。从上图可以看出,变形是使用视图合成模块实现的。请注意,深度是模块的输入,在我们的例子中,深度是由神经网络预测的。

然后,通过最小化目标和预测目标之间的代理光度损失来指导学习,并且通过双线性采样器模块和深度网络来导出和传播梯度。因此,如果目标图像和预测的目标在外观上相似,这意味着深度是隐含地和正确地学习的。

源图像可以取自视频序列或从其他相机(如双目或三目设置)捕获的图像。前者需要估计[R|t],而后者需要在摄像机之间进行良好的校准,以获得外部属性。

我们将关注基于 SFM 的自监督深度估计,其需要从神经网络估计姿态。

SFM 管道公司

B.从结构到运动的深度[SFM]

使用 SFM 的深度估计源于这样的想法,即我们能够通过在 3D 环境周围移动来感知和从结构上理解 3D 环境。当观察者移动时,它们周围的物体根据它们与观察者的距离而移动不同的量。这被称为 运动视差 ,从这个深度信息可以用来生成我们周围世界的精确 3D 表示。

在计算机视觉中,这是通过移动📷捕捉场景并测量每个时间步的视图变化之间的重叠。深度网络用于理解运动视差。而姿态网络用于预测帧间观察的变化。

C.深度模型

该网络不是直接回归深度,而是通过输出图层经过 sigmoid 激活来预测差异,从而给出 0-1 之间的连续值。

因此,可以使用1/(a*disp + b)将该值转换为深度,其中 a、b 控制获得的最小和最大深度值的范围。

多尺度预测 :这是用来缓冲从低纹理区域学习的影响,这在合成时经常是不明确的。因此,建议通过使用较低分辨率的特征来增加可以导出梯度的空间区域。

为此,来自解码器的中间输出将分别通过 sigmoid 激活,以预测每个相应比例的视差。

深度推理流水线

维姿网络

姿态网络应该预测从I_t-1 / I_t+1I_t的摄像机姿态[R|t]的 6 自由度相对变化。最终卷积层的输出缩放至 0.01,如[5]所示。网络输出的旋转角度遵循轴角表示法,可以使用 Rodrigues 旋转公式转换成旋转矩阵R

注意,输入之间存在时间一致性,从而保持顺序。这简化了学习过程。

姿态推理管道

E.视图合成

如前所述,目标是在给定源图像的情况下合成目标图像。我们想重现从不同摄像机视角看到的场景。这可以通过将目标像素坐标投影到另一个给定深度和视图相对变化(姿态)的摄像机视点上来实现。

有了预测的深度、depth_pred和姿态[R|t]_pred,下一步就是把图像I_t-1, I_t+1投影扭曲成I_t

如果目标图像I_t和扭曲图像I_t_pred之间的像素亮度相似,这意味着深度和姿态网络确实已经成功地学会预测深度和相对相机姿态。

要执行转换,请执行以下操作:

  • 首先使用depth_pred将目标图像I_t反投影到 3D 点云。我已经写了一篇关于深度反投影的文章。你可以参考它来理解背后的概念,并看到它的实际应用。
  • 接下来,使用预测的相机姿态对点云执行线性变换,以获得cam_t->t-1/cam_t->t+1坐标中的目标点。然后通过投影变换将三维点投影到图像平面上。
  • 使用类似于 STN [3]中介绍的可微分双线性采样方法的机制,从源图像I_t-1/I_t+1中采样相应的像素坐标,以获得两个样本的I_t_pred

下图总结了这些步骤。

查看合成管道

F.设计损失函数

通过计算目标和合成视图之间的代理光度损失来更新和学习权重。有几种方法可以测量图像之间的外观。最常见的是天真的 L1/MSE。从那以后,为了更好地捕捉图像中的外观和结构,已经提出了一些修改。我们将在这里讨论它们。

考虑结构内容:由于 L1/MSE 只考虑了像素间的亮度差异,因此没有结构内容的概念。即许多失真的图像可能产生相同的强度误差

结构相似指数,SSIM :该度量将相似性度量的任务分成 3 个比较;两幅图像之间的亮度、对比度和结构。这个想法是通过减少亮度和对比度的权重来更加强调图像的结构。

3.普通框架的问题

不幸的是,通过实现上述流水线,可以用不同程度的伪像来训练深度估计。仍然存在几个需要解决的问题。在本节中,我们将讨论一些不足之处。

该图示出了预测图像和目标图像之间的像素级绝对差异,观察到模型在边界和细长结构附近挣扎。L1 误差图中较高的强度表示较高的绝对差异。

A. SFM 在静态世界的前提下运作

在自然场景中,它通常既包括静止的背景,如墙壁、结构和建筑物,也包括运动的实体,如人。通过采用 SFM,我们假设了一个静态世界假设,并且只有静态部分可以实现。

静态假设是什么意思?

  1. 静态:视频中静态部分的运动完全由摄像机运动和深度结构引起。帧之间的投影 2D 图像运动可以完全由深度结构和相机运动来确定
  2. 动态:具备大位移*(想想光流)的特点。由摄像机运动和特定物体运动共同作用。这不是 SFM 的模型。*

B.SFM 对损失的暗示

除了违反静态世界假设之外,该框架还带来了许多其他考虑

  1. 未考虑物体运动:当使用估计的姿态将目标点转换到另一个摄像机视图时,构建的场景不会考虑场景中的运动,而只是基于预测的自身运动。导致具有运动的像素的目标图像和预测图像之间的不匹配。
    这暗示了即使模型正确预测了深度,模型仍然会受到惩罚。
  2. 深度的性能与姿态网络紧密耦合:性能不佳的姿态网络会降低深度性能。因为姿态网络负责计算视图中的相对变化。
  3. 预测“无限深度”或洞:这是动态物体的另一个结果,也是一个非常特殊的例子,其中物体以与相机相同的速度移动。*物体相对于摄像机看起来是静止的。这也可以在任何事物无限远的情况下实现。物体的任何移动都被认为是不可观察的,并且看起来是静止的。这可以触发深度网络来预测无限深度,因为对象不移动,表现为洞。*

来源

C.光度损失是你最好的赌注吗?

基于外观的损失是深度损失的有效替代。然而,使用图像强度作为衡量标准有一定的缺陷。

  • 我们无法从 2D RGBD 图像中推断出世界的实际大小:由于我们在 2D 图像空间中计算损失,因此在双线性采样阶段后,我们会丢失比例信息。即许多投影预测实际上可以给出相同的正确图像*。更多细节可以在这个帖子中找到。结果,所学习的深度在 3D 度量空间中将是尺度模糊的,但是在图像空间中是一致的。
    关于 Kitti 基准上的结果,许多工作依赖于根据地面真实情况找到中值深度来解决比例问题。*
  • 标度模糊导致深度收缩 : 标度模糊的另一个危险方面是深度塌陷的可能性。本文表明,随着比例的减小,相同的场景可以用更小的深度图来构建,直到它退化为零。该论文建议通过增加归一化步骤来防止平均深度崩溃

  • 即使合成图像在几何上不一致,损失也能得到满足:在某些场景中,当深度预测错误而姿态正确时,或者反之亦然,重建图像仍有可能得到很好的预测。这种情况在无纹理的区域更常见,如墙壁和天空。在这种情况下,深度和姿态网络不会因为不良预测而受到惩罚和奖励。
  • 不同的视图会导致严重的损失:考虑像素在目标图像中可见而在源图像中被遮挡或不在视图中的情况。当重新投影这些点时,在这些区域中将会出现不匹配。因此,即使深度被正确预测,模型仍然是不利的。
  • 要考虑的边缘情况:除了上面提到的,反射的表面(违反视图之间的朗伯假设)、失真的图像或色彩饱和的图像也会导致不匹配并降低损耗计算。

由于非朗伯曲面,在 SFM 环境中不一致的场景

D.对深度模型的影响

考虑到上述因素,文献中的大多数深度模型倾向于产生具有以下伪像的结果:

  1. 沿遮挡边界的平滑深度和深度不连续:深度网络倾向于预测这些边界附近的过度平滑深度,而不是保留边缘。这可能是由于缺少明确定义的边缘感知,并且损失主要由平滑表面造成。这导致了出血边缘效应。反向投影的点没有被很好地定义。

来源

2。闪烁效果:深度图随时间推移产生的几何效果不一致。在下图中可以观察到深度的巨大变化。尤其是在薄结构和边界处。

4.研究进展

这一部分将根据新的发现不断更新。

在对相关问题有了更清楚的理解之后,让我们继续讨论文献中提出了什么解决方案来试图解决这些问题。我将在这里强调一些文件。

已经提出的许多想法可以大致归类为解决以下任务:

  1. 使光度损失有意义:通过考虑场景中的运动和遮挡,或者从损失计算中移除它们。
  2. 解决尺度模糊:为了在 3D 空间中进行度量上合理的深度预测,存在通过利用帧之间的额外一致性来解决这个问题的工作
  3. 通过注入额外的模态来提高性能:许多人利用了各种模态,例如使用光流、表面法线来模拟物体运动,或者使用语义分割来提高场景理解。
  4. 边界细化:通过使用额外的模态或作为后处理阶段,一些努力集中于明确地细化边缘和遮挡边界。
  5. 设计更好的深度网络:关于如何最好地表现深度和视差,有许多工作正在进行。或者设计更好地保存和捕捉场景结构的架构。
  6. 采用半监督框架:想法是通过具有某种形式的注释,通过从低分辨率激光雷达获取稀疏地面真实,模型将受益于弱监督。

A.解决不完美的光度损失

MonoDepth2,ICCV2019 中对此进行了大量调查和处理。他们的想法简单而有效,可以提高性能。

自动屏蔽源和目标之间的静止像素:为了防止静态场景违规,他们提出在计算损失时简单地忽略这些像素。当其他对象以与相机相同的速度移动时,或者当相机在帧之间静止时,会发生这种情况。

针对所有预测视图逐个像素地选择最小误差:这种情况处理相邻视图中由于自身运动造成的遮挡或视图外像素。这种简单的方法能够锐化遮挡边界并减少伪影。

因为 I_t+1 预测没有被遮挡,所以在该区域中选取像素,并丢弃那些来自 I_t-1 的像素

B.模型进展

这里,我们看到的架构设计本质上应该能够最好地从 RGB 图像中捕获结构信息,并提取连续的深度/视差值。一个研究方向主要集中在通过修改基本编码器-解码器架构来保留空间内容,而另一个方向集中在开发视差输出的更好表示。

编码-解码特性:这一系列工作寻求优化网络中的信息流。在 SuperDepth ICRA2019 中,他们提出使用亚像素卷积层来有效和准确地超解析来自其较低分辨率输出的差异,取代解码器中的上采样层。

操作如下:使用相移对图像进行整形,称为像素混洗,其重新排列 H × W × C r 张量的元素以形成 rH × rW × C 张量。

子像素卷积:像素在深度和空间维度之间混洗

PackNet,CVPR2020 中,他们认为编码器中的标准下采样阶段在空间上对密集深度预测有害。类似地,上采样策略无法在解码器层传播和保留足够的细节来恢复准确的深度预测。他们提出通过用打包解包块来代替下采样池和上采样来保存信息。因此,不是执行 2x2 最大池,即选择 4 像素区域中的最大值并丢弃其余值,而是通过Space2Depth操作将特征打包到深度维度中。这样,就不会有信息被删除。在论文中,他们提到卷积 2D 并不是为捕获深度通道而设计的。因此,特征空间被扩展到 4D,并通过卷积 3D 馈送。解包块执行相反的操作,其工作方式与超深度相同,使用子像素卷积来恢复特征。

包装和拆包

着眼于表现深度和视差:除了预测每像素深度,还有其他人着眼于深度预测,以提高鲁棒性和稳定性。

神经 RGB- > D Sensing,CVPR2019 中,他们决定将不确定性估计纳入视差估计,同时在贝叶斯滤波框架下随时间累积,生成视差概率体(DPV)。然后降低深度不确定性估计并提高鲁棒性。

在这篇论文中,他们提出预测离散视差体积,ECCV2020 。这是受众所周知的监督方法 DORN,CVPR2018 的启发,该方法选择将回归任务构建为有序回归问题。DORN 在单目深度估计中取得了优异性能。

C.探索不同的模式

表面法线、视差和光流在表示图像中的结构方面与深度有许多相似之处。表面法线可以解释为深度梯度的方向。光流可以通过自我运动和物体运动自然地链接到深度。视差与深度成反比关系。虽然语义没有任何直接关系,但许多人使用分割图作为学习更精细深度的指导。有许多研究这些联合互补性质的著作。

在多任务学习框架中共同学习:学习的一个方向是与其他任务一起共同学习深度。这些工作中有许多在经验上显示出积极的结果,并证明它是一个有前途的方向。这些任务是紧密相关的,在共享主干的多任务环境中,它们将相互受益。在 GeoNet,CVPR2018 中,考虑联合学习光流、深度和姿态,同时加强几何一致性,而在另一个作品 SceneNet 中,CVPR2019 专注于学习深度和分割。

地理网

SceneNet

利用语义分割:语义本身与深度没有任何数学关系。然而,一些作品在语义应该通过提供某些线索来指导深度估计的想法上追求这个方向。例如,天空应该位于远处,并且自然地具有非常高的深度值。像素标签的变化很可能指示对象的边界,并导致深度的显著变化。

本作品由 TRL,ICLR2020 完成。他们提出用语义模型来指导几何表征学习。他们设计了一个精心制作的语义指导功能模块,在网络的不同阶段注入语义信息。

来源

D.解决比例模糊

如前一节所述,预测的深度在比例上是不明确的。在与 PackNet 相同的论文中,他们表明来自姿势的预测平移分量和地面真实姿势之间的位移的弱监督可以解决度量尺度。通过约束姿态,它确保姿态网络预测度量准确的估计。

F.稀疏深度半监督

假设某种形式的深度可以从距离传感器(如激光雷达)获得,那么可以以半监督的方式使用它来创建稀疏深度图。这已经在熊伟桂子林等人的 2019 年 CoRL2019 中进行了广泛的探讨。我认为这是一个有趣的分析。他们研究了与训练期间可用的激光雷达点的数量相关的深度改善的效果。

来源

自我监督关键点学习综述

原文:https://towardsdatascience.com/self-supervised-keypoint-learning-aade18081fc3?source=collection_archive---------6-----------------------

关键点或兴趣点检测是许多计算机视觉任务的一个重要组成部分,例如 SLAM (同时定位和地图绘制)【SfM】(从运动得到的结构)和摄像机校准。关键点检测在深度学习之前有很长的历史,许多广泛行业应用中的辉煌算法(如 FASTSIFTORB )都是基于手工制作的特征。正如在许多其他计算机视觉任务中一样,人们一直在探索如何使用深度学习来胜过手工制作的算法。在本帖中,我们将回顾这一领域的一些最新进展。

语义关键点与兴趣点

在我们继续之前,让我们弄清楚一些概念。在计算机视觉中通常使用两种类型的关键点。语义关键点是对图像中的物体具有语义意义的兴趣点,例如人脸的左眼角、人的右肩或汽车的左前轮胎轮毂。兴趣点更多的是可能没有明确语义的低级点,比如线段的一个角点或者终点。

深度学习方法主导了最先进的语义关键点检测。Mask RCNN(ICCV 2017)和pif PAF(CVPR 2019)是语义关键点检测的两种代表性方法。这些方法是监督学习,需要大量昂贵的人工注释。这使得它们难以容易地应用于兴趣点检测,因为兴趣点在语义上是不明确的,因此人类注释者不能可靠地和重复地识别同一组兴趣点。因此,不可能将兴趣点检测的任务公式化为监督学习问题。

现在进入自我监督学习。自监督学习(或无监督学习,如果你关注它不需要明确的人类注释的事实)是 2020 年初重新出现的话题。这包括最近的进展,如 FAIR 的 、MoCo 和 Geoffrey Hinton 团队的 SimCLR 。(关于自我监督学习的更多一般趋势,我会推荐 Lilian Weng 的博客。)与监督学习相比,自监督学习受益于每个训练样本多几个数量级的监督比特,并且不需要昂贵的和特定任务的人工注释。由于难以从人类获得可靠的注释,这非常适合于兴趣点检测。

这篇文章的主题是将自我监督学习应用于兴趣点学习。下面我们将互换使用兴趣点关键点

下面这篇博文是基于我第一次阅读这篇论文时的笔记。欢迎星/叉/评论!

[## 帕特里克-llgc/学习-深度学习

这个知识库包含了我关于深度学习和机器学习的论文阅读笔记。它的灵感来自丹尼·布里兹…

github.com](https://github.com/patrick-llgc/Learning-Deep-Learning)

超级点

SuperPoint :自监督兴趣点检测与描述 (CVPR 2018)是利用自监督学习进行兴趣点检测与描述的开创性工作。总之,它首先在合成数据上预训练兴趣点检测器,然后通过使用已知的单应变换生成图像对来学习描述符。

寻找兴趣点的任务由探测描述组成。检测是图像中感兴趣点(或特征点,或关键点,取决于文献)的定位,描述是用向量(即描述符)描述每个检测到的点。总体目标是有效和高效地找到有特征的和稳定的视觉特征。在下面的博文中,我们将看到兴趣点学习是如何处理检测和描述这两项任务的。

本文仍然遵循许多经典算法的思路:先检测后描述。首先如何学习一个健壮的检测器?我们可以使用已知兴趣点的 3D 对象来绘制 2D 投影,例如长方体的角和线段的端点。作者称这种探测器为 Magic point(Magic Leap 的作者起的一个好听的名字。).

现在你可能会说,这与兴趣点在语义上定义不清的事实相矛盾,但在实践中,这似乎工作得很好。当然,这就为以后的作品留下了一个需要改进的地方(比如下面讨论的)。

MagicPoint:对合成数据进行预处理

从合成图像到真实图像,为了弥补真实图像之间的差距,使用测试时间增强(TTA)来积累兴趣点特征。这种密集的 TTA(约 100 次扩充)被称为“单应适应”。该步骤隐含地要求 MagicPoints 以低假阳性率产生高精度检测结果。聚合步骤是增加回忆和创造更多兴趣点。类似的技术也在最近的作品 UR2KiD 中使用(他们在一种称为组-概念检测器-描述的技术中聚集了来自不同概念组的关键点)。

单应性适应:一种弥合模拟真实传输差距的 TTA 方案

现在,从生成建模的角度来看,如果我们知道一幅图像的关键点,我们就可以将图像和关键点一起进行单应变换。这将生成大量的训练数据来学习描述符。作者使用对比损失 (CVPR 2006,Yann LeCun 的小组)来学习描述符,该描述符基本上包括成对点的拉动项和不成对点的推动项。注意这个损失中有很多项,O(N)其中 N 是每个图像的点数。这是将明确定义的数学问题的知识转移到神经网络的又一个例子。

SuperPoint 对检测器和描述符使用相同的编码器,以便快速推断

我发现一项特别有趣的技术是,检测器使用分类和通道 2 图像技巧来实现高精度检测。总之,它将特征图中每个像素表示的输入图像中的每个 8×8 像素扭曲为 64 个通道,后跟一个垃圾箱通道。如果在 8×8 区域没有关键点,垃圾箱具有高激活度。否则,其他 64 个通道通过 softmax 在 8×8 区域找到关键点。

以上步骤很大程度上总结了 SuperPoint 的主要思路。

  • MagicPoint:对关键点检测器的合成数据进行预处理
  • 同形适应:实像上的 TTA
  • SuperPoint: MagicPoint,使用经过已知单应变换的图像对训练的描述符。描述符用于图像匹配任务。

SuperPoint 的三个主要步骤

在大多数基准测试中,SuperPoints 优于手工算法。在配有 GPU 的机器上,480p (480x640)的运行速度为 13 毫秒或 70 FPS,240p (320x240)的运行速度为 167 FPS。

未点

:端到端无监督兴趣点检测器和描述符通过消除检测器预训练步骤,进一步采用了 superPoint 的概念。关键点在训练中自然出现。****

该网络的架构在一个 VGG 风格的主干上有三个头。

  • 第一个输出是粗略评分热图(x8 下采样)。它消除了 NMS 的需要,并鼓励关键点更均匀地分布在图像上。
  • 子像素位置回归以预测 8×8 像素区域内的精确位置。
  • 描述符描述。它使用子像素位置进行插值。

未点的网络架构

SuperPoint 之间有几个区别/改进:

  • 没有对关键点位置的直接监督。没有对合成数据和单应自适应繁琐的预处理。
  • 用于亚像素位置预测的直接回归而不是逐通道分类。
  • 插值发生在网络内部。SuperPoint 在推理后做插值,占用宝贵的 CPU 周期。

未点引入吨损失!平衡它们是一项艰巨的任务。为了计算这些损失,必须建立点对对应关系。UnsuperPoint 使用了贪婪匹配算法。如果目标图像(pt)中的点在已知的单应变换(pt)下变形到源图像后,在源图像中有一个关键点(ps)在阈值(4 个像素)内,那么 ps 和 pt 称为点对***

寻找点对(来源: KP3D

注意,这不是匈牙利匹配,因此不是内射的。换句话说,目标图像中的一个点在源图像中可能有多个匹配。在没有直接监督的其他数据协会论文中可以找到类似的匹配步骤,例如,像素到图形 (NeurIPS 2017)。

利用定义的点对,定义了以下损失项。

  • 点对的位置损失:像素坐标间的欧几里德 L2 距离。
  • 点对的分数损失:点对中的点应该有相似的分数。
  • 匹配损失:它确保点分数实际上是关键点的置信度分数。它鼓励网络为网络认为在单应变换下可以可靠检索的点输出高分。具体地说,它是点对的平均得分和零均值距离的乘积。
  • 均匀分布损失:它鼓励[0,1]内分布均匀。这取决于排序函数是可微的这一事实。这是第一次(正如作者所声称的,据我所知)损失被应用于强制神经网络预测的特定分布。
  • 描述符损失:对比损失,同 SuperPoint。
  • 去相关损失:鼓励描述符之间的维度是独立的。具体是相关矩阵中非对角元素的 L2 范数(见ICCV L2 网 2017 )。

通过仔细平衡这些损失项,UnsuperPoint 在准确性和速度方面都优于 superPoint。UnsuperPoint 对于 480p 图像以 65 FPS 运行,对于 240p 图像以 119 FPS 运行,比 superPoint 稍慢。

KP2D

【KP2D】:自监督关键点学习的神经离群点剔除 (ICLR 2020)是丰田研究所的后续工作之一。虽然工作看起来是渐进的,但是建议的技巧产生了具体的改进。

相对于 UnsuperPoint 有三大改进。

  • 一种更具表现力的关键点位置回归方法。UnsuperPoint 将子像素回归的输出限制在[0,1]内,甚至使用了专门设计的损失来强制每个 8×8 像素区域中的均匀分布。KP2D 没有鼓励[0,1]的分布是均匀的,而是深入研究了分布不均匀的原因,并将值放宽到[0,1]之外,允许每个 8×8 像素区域为其边界之外的关键点投票。

我认为这是因为点对匹配不是内射的。仅通过距离阈值就可以将源图像中的一个点匹配到目标图像中的多个点。

KP2D 中的每个 8×8 像素区域可以为其相邻区域中的关键点投票

  • 快速和学习的上采样层,即亚像素 ConvNet ( 使用高效亚像素卷积神经网络,CVPR 2016)的实时单个图像和视频超分辨率)用于在执行插值之前将特征地图上采样 2x2。

用于快速超分辨率的亚像素卷积(通道 2 空间)

  • 基于异常值拒绝的附加代理任务,仅在训练期间使用。所谓的 InlierOutlierNet (IO-Net)的灵感来自于神经引导的 Ransac (ICCV 2019),其本身就是受 PointNet 的启发。IO-Net 接受一个点对(2 个点的坐标,带有一个数量的附加描述符距离),并预测该点对是否是用于下游任务(如单应性估计)的 Ransac 类鲁棒匹配方案中的内侧集。

此外,在超点和非超点中使用的对比损失由三重损失代替。总体而言,KP2D 始终比 UnsuperPoint 表现出色。它的运行速度与 SuperPoint 和 UnsuperPoint 差不多,在 240p (320x240)下为 175 FPS。

KP3D

KP3D :用于自我运动估计的自监督 3D 关键点学习 (ArXiv 12/2019)由来自丰田研究所的 KP2D 的相同作者完成,并将自监督关键点学习的思想进一步推进到 SLAM 的端到端视觉里程表前端。KP3D 结合了近年来新兴的两个热门话题:基于视频的关键点自监督学习(如 KP2D)和单目逐像素深度估计(如 sfm 学习器野外深度尺度一致 sfm 学习器)。

KP3D 借鉴了 KP2D (ICLR 2020)和规模一致的 sfm 学习者 (NeurIPS 2019)在上述两个领域的 SOTA 表现。特别地,在尺度一致的 sfm 中,学习器增加了帧之间的深度一致性,这对于精确的自我运动估计是至关重要的。

综合来看,KP3D 有一个令人惊叹的 SLAM 演示视频。作为一种单目方法,KP3D 击败了所有以前的 SOTA 单目和几乎所有的立体 SLAM 方法。它唯一没有胜过的立体 SLAM(DVSO:深度视觉立体里程计,ECCV 2018)也是基于深度学习的方法。

2D 关键点完全从无标签的单目视频中学习,匹配稀疏缓慢,并在 KP3D 中产生惊人的远程单目视觉里程计

注释

乍一看,这篇论文数学很重。确切地说,它需要更多的 SLAM 领域知识来理解。为了更深入地研究算法,我们必须考虑一些符号约定:

  • pt∈是目标图像中的关键点,PS∈是源图像中的关键点。
  • pt(MV)∈是基于描述子空间的源图像中 pt 的匹配关键点。(MV 是多视图的简写)基于这对 pt↔pt(MV,我们可以计算相关的自我运动 Xt→s。描述符损失基于此。
  • pt∑∈是源图像中的扭曲 pt(类似于 UnsuperPoint 和 KP2D 中的 pt)。稀疏关键点位置损失介于 pt(MV)和 pt 之间。
  • 一旦 Xt→s 已知,密集光度损失和稀疏关键点位置损失被公式化。

在整个流水线中,计算 pt 是最难的。在以前的 2D 关键点作品(例如,SuperPoint、UnsuperPoint、KP2D)中,pt可以很容易地计算,但是在多视图适应中,这很难,并且需要首先用估计的深度投影到 3D,然后用估计的自我运动投影到另一个视图。**

我认为 KP3D 的作者误解了单应适应的原始命名,这是 SuperPoint 中第第二阶段使用的 TTA 技术。他们似乎把这种技术误认为是第第三阶段的超级要点,即利用已知的单应变换来产生训练信号。这个细节不会对我们理解这篇论文有太大影响。

根据多视图适应变换的各种关键点

可微分三维姿态估计

KP3D 不是直接使用 CNN 来进行姿态估计(在 sfm 学习器中的 PoseNet),而是使用匹配的关键点来进行姿态估计,这可能是更好的性能的关键,因为上面回顾的上述 2D 关键点学习方法已知会产生非常好的 HA 或单应性准确性。

本文的一个主要贡献是如何以完全可微的方式从匹配的 2D 点执行姿态估计。快速入门经典算法基于 极线几何 从两幅图像中匹配的 2D 点估计自我运动。基本思想是估计图像对的基本矩阵或本质矩阵,然后从任一矩阵中恢复旋转和平移。

极线约束:三维点及其在 2D 图像上的投影之间的几何关系

因为我们联合估计每个像素的密集深度,所以我们可以使用 Epnp ( 透视 n 点)来估计帧之间的相对姿态。然而,这是不可微的,因此只能作为一个初步的猜测。

KP3d 提出的方法是,我们可以粗略地使用关键点的变换的 3D 位置(具有初始猜测)来获得点在新的相机坐标中的 3D 位置。那么本质上,该问题被简化为基于两组匹配的 3D 点来估计相对相机姿态变化。这个问题被称为正交 Procrustes 问题,具有诸如 ICP(迭代闭合点,通常用于激光雷达点云配准)的良好解决方案。在我们知道 3D 点之间的匹配的假设下,ICP 具有基于 SVD(矩阵的奇异值分解)的封闭形式的公式,称为 Kabsch 算法

外卖食品

近年来,使用深度学习的关键点检测和描述领域受到了越来越多的关注。正如 KP2D 的公开评论中所指出的,“ 这个问题是老问题,但还没有完全解决,因为手工制作的 SIFT 仍然在基准测试中胜出。

  • SuperPoint 提出使用已知单应变换来生成用于关键点检测和描述的监控信号。这是这篇文章中所有论文探索的开创性思想。
  • SuperPoint 使用合成数据来预训练关键点探测器,并使用称为单应自适应的测试时间增加技术来转换到真实数据。
  • UnsuperPoint 建议取消关键点检测器繁琐的预训练阶段。通过巧妙地平衡损失,关键点的检测和描述都将从训练中出现。
  • KP2D 用几种技术改进了 UnsuperPoint,最显著的是用代理损失来确定建议的点对是否匹配 inlier。
  • KP3D 结合了 KP2D 的工作和单目深度估计的最新进展,以提供基于 SOTA 单目 SLAM 系统。

参考

自我监督学习和深度学习中减少标记数据的探索

原文:https://towardsdatascience.com/self-supervised-learning-and-the-quest-for-reducing-labeled-data-in-deep-learning-db59a563e25b?source=collection_archive---------8-----------------------

深度学习的现状以及自我监督如何可能是更健壮模型的答案

图片来自来自 www.picjumbo.com 的免费库存照片来自 Pixabay

T 这里有一件事是每个深度学习实践者都同意的。

深度学习模型是数据低效的。

让我们首先考虑计算机视觉中流行的分类任务。以 ImageNet 数据库为例。它包含来自 1000 个不同类别的 130 万张图片。对于这些图像中的每一个,都有一个人注释的标签。

ImageNet 无疑是当前深度学习复兴的垫脚石之一。其中大部分始于 2012 年的那篇(krijevsky 等人)论文。在这里,ConvNets 第一次大幅度击败了当前最先进的模型。在竞争对手中,它是基于 ConvNet 的单一解决方案。之后,ConvNets 变得无处不在。

在深度学习之前,ImageNet 挑战一直被认为是非常困难的。在主要原因中,其较大的可变性最为突出。事实上,要建立能在这么多种类的狗中通用的手工制作的特征并不容易。

然而,随着深度学习的发展,我们很快意识到,让 ImageNet 如此艰难的原因实际上是让深度学习如此有效的秘密成分。这就是丰富的数据。

然而,经过多年的深度学习研究,有一点变得很清楚。用于训练精确模型的大型数据库的必要性成为一个非常重要的问题。当需要人工标注的数据时,这种低效率会成为一个更大的问题。

而且,在当前的深度学习应用中,数据的问题无处不在。再以 DeepMind 的 AlphaStar 模型为例。

来源: AlphaStar:精通即时战略游戏星际争霸 2

AlphaStar 是一个深度学习系统,使用监督和强化学习来玩星际争霸 2。在训练过程中,AlphaStar 只能看到来自游戏控制台的原始图像像素。为了训练它,DeepMind 的研究人员使用了一种分布式策略,他们可以并行训练大量的代理人。每个代理都经历了至少 200 年的实时星际争霸游戏(不间断)。AlphaStar 接受了与职业选手相似的训练。它在官方游戏服务器上的活跃玩家中排名超过 99.8%——这是一个巨大的成功。

尽管使用了所有通用技术来训练系统,但有一件事对成功构建 AlphaStar(或几乎任何其他 RL 代理)至关重要——数据的可用性。事实上,最好的强化学习算法需要许多(但许多)试验才能达到人类水平的性能。这与我们人类的学习方式完全相反。

因此,巨大的成功来自于有大量可用数据的受限的、定义良好的场景。看看 DeepMind 的这篇论文。最好的 RL 方法需要近 100 小时(1080 万帧)的不间断播放,才能达到专业人员在一套 Atari 游戏上的相同性能水平。尽管最近有所改善,但这似乎还是太多了。

学分:彩虹:结合深度强化学习的改进

要了解更多关于 AlphaStar 的信息,请看一下这个来自 批次 的简短摘要。

我可以用更多的例子来烦你,但是我想这两个例子说明了我想要表达的观点。

目前的深度学习是基于大规模数据的。当它们的环境和约束得到满足时,这些系统就像魔法一样工作。然而,在一些奇怪的情况下,他们也会灾难性地失败。

让我们稍微回到 ImageNet 上的分类。具体来说,该数据库估计人为错误率为 5.1% 。另一方面,目前最先进的 深度学习 top-5 准确率在 1.8% 左右。因此,人们完全可以说深度学习在这项任务上已经比人类做得更好了。但是是吗?

如果是这样的话,我们如何解释这些事情?

学分:用对抗性例子攻击机器学习

这些例子在互联网上非常流行,被称为反例。我们可以认为这是一个优化任务,旨在欺骗机器学习模型。这个想法很简单:

我们如何改变先前被分类为“熊猫”的图像,以便分类器认为它是“长臂猿”?

我们可以简单地认为它是精心设计的输入示例,用来欺骗 ML 模型,使其犯分类错误。

致谢:愚弄深度神经网络的一个像素攻击

正如我们所看到的,优化是如此有效,以至于我们无法(用肉眼)感知真实(左)和对立(右)图像之间的差异。事实上,造成错误分类的噪声不是任何类型的已知信号。相反,它被精心设计来探索这些模型中隐藏的偏见。此外,最近的研究表明,在某些情况下,我们只需要改变 1 个像素,就可以完全欺骗最好的深度学习分类器

在这一点上,我们可以看到问题开始相互叠加。我们不仅需要大量的例子来学习一项新的任务,而且我们还需要确保我们的模型学习正确的表示。

来源:用对立的例子愚弄图像识别

当我们看到深度学习系统像那样失败时,一个有趣的讨论就来了。显然,我们人类不会轻易被这样的例子愚弄。但这是为什么呢?

有人可能会说,当我们需要掌握一项新任务时,我们实际上并不是从零开始学习。取而代之的是,我们使用了大量在我们的生活和经历中获得的先验知识。

我们了解重力及其含义。我们知道,如果我们让一枚炮弹和一根鸟毛从同一个起点落下,由于两个物体中空气阻力的不同作用,炮弹将首先到达地面。我们知道物体不应该浮在空中。我们了解世界如何运转的常识。你知道如果你的父亲有一个孩子,他或她将是你的兄弟姐妹。我们知道,如果我们在报纸上看到有人出生在 20 世纪,他/她可能已经不在人世,因为我们知道(通过观察世界)人们通常不会活超过 120 岁。

我们理解事件之间的因果关系。最令人好奇的是,我们实际上在生命的早期就学习了许多这些高层次的概念。事实上,我们只用 6 到 7 个月就学会了像重力和惯性这样的概念。这个年纪,和世界的互动几乎没有!

婴儿的早期概念习得。 Yann LeCun 幻灯片

从这个意义上说,有人可能会说,将算法的性能与人类进行比较是不“公平的”

在他的一次关于自我监督学习的演讲中,Yann LeCun 认为至少有三种方法可以获得知识。

  • 通过观察
  • 来自监督(大多来自家长和老师)
  • 来自强化反馈

人类通过生活获得的不同知识来源。通过观察/互动、监督和反馈来学习。

然而,如果我们以人类婴儿为例,在那个年龄几乎没有互动。然而,婴儿设法建立一个直观的世界物理模型。因此,像重力这样的高级知识只能通过纯粹的观察来学习——至少,我还没有见过任何父母给 6 个月大的婴儿教物理。

只是在生命的后期,当我们掌握了语言并开始上学时,监督和互动(有反馈)才变得更加普遍。但更重要的是,当我们到达人生的这些阶段时,我们已经发展出一个强健的模型世界。这可能是为什么人类比现在的机器数据效率更高的主要原因之一。

正如 LeCun 所说,强化学习就像蛋糕中的樱桃。监督学习是糖衣,自我监督学习是蛋糕!

来源: Yann LeCun

自我监督学习

在自我监督学习中,系统学习从其输入的其他部分预测其输入的一部分— LeCun

自监督学习源于无监督学习。它涉及从未标记的数据中学习语义上有意义的特征。在这里,我们主要关注的是计算机视觉环境下的自我监督。

一般的策略是通过设计一个借口任务,将一个无监督的问题转化为一个有监督的任务。通常,一个借口任务有一个总的目标。这个想法是让网络从图像或视频中捕捉视觉特征。

借口任务和常见的监督问题有一些相似之处。

我们知道监督训练需要标签。反过来,这些通常是由人类注释者收集的。然而,在许多情况下,标签要么非常昂贵,要么不可能获得。此外,我们还知道深度学习模型天生就需要数据。其直接结果是,大规模标注数据集成为进一步发展的主要障碍之一。

嗯,自我监督学习也需要标签来训练托词任务。然而,这里有一个关键的区别。用于学习借口任务的标签(或伪标签)具有不同的特征。

事实上,对于自监督训练,伪标签仅从数据属性中单独导出。

换句话说,不需要人为标注。事实上,自我学习和监督学习的主要区别在于标签的来源。

  • 如果标签来自人类注释者(像大多数数据集一样),这是一个监督任务。
  • 如果标签来自数据,在这种情况下,我们可以自动生成它们,我们谈论的是自我监督学习。

最近的研究提出了许多借口任务。一些最常见的包括:

  • 旋转
  • 七巧板
  • 图像彩色化
  • 图像修复
  • 使用 GANs 生成图像/视频

在这里 查看每个 借口任务的概要描述。

学分:深度神经网络的自我监督视觉特征学习:综述

在自我监督训练期间,我们挑战网络来学习托词任务。同样,伪标签是从数据本身自动生成的,并用作训练目标。一旦训练结束,我们通常使用学习到的视觉特征将知识转移到第二个问题——下游任务中。

一般来说,下游任务可以是任何被监督的问题。这个想法是使用自我监督的特性来提高下游任务的性能。通常,下游任务的数据有限,过度拟合是一个大问题。在这里,我们可以看到在大型标记数据库(如 ImageNet)上使用预训练的 ConvNets 进行普通迁移学习的相似性。但有一个关键优势。

通过自我监督训练,我们可以在难以置信的大型数据库上预先训练模型,而不用担心人类标签。

另外,托辞和平时的分类任务有个茬儿区别。在纯分类中,网络学习表示,目标是在特征空间中分离类别。在自我监督学习中,托辞任务通常挑战网络来学习更一般的概念。

以图像着色托辞任务为例。为了在其中脱颖而出,网络必须学习解释数据集中对象的许多特征的通用特征。这些包括物体的形状,它们的一般纹理,担心光线,阴影,遮挡等。

简而言之,通过解决托词任务,网络将学习语义上有意义的特征,这些特征可以很容易地转移到学习新问题。换句话说,我们的目标是在接受监督之前从未标记的数据中学习有用的表示法

结论

自我监督学习允许我们在不使用大型注释数据库的情况下学习良好的表示。相反,我们可以使用未标记的数据(这是丰富的)并优化预定义的借口任务。然后,我们可以使用这些特征来学习数据稀缺的新任务。

感谢阅读

参考

  • 用对立的例子攻击机器学习
  • 阿尔法星:精通即时战略游戏星际争霸 2
  • 《彩虹:结合深度强化学习的改进》第三十二届 AAAI 人工智能大会。2018.
  • 景,龙龙,田英丽。"深度神经网络自监督视觉特征学习:综述." arXiv 预印本 arXiv:1902.06162 (2019)。
  • Gidaris,Spyros,Praveer Singh 和 Nikos Komodakis。"通过预测图像旋转的无监督表示学习." arXiv 预印本 arXiv:1803.07728 (2018)
  • 较少标签的高保真图像生成。 arXiv 预印本 arXiv:1903.02271 (2019)
  • 苏、佳伟、达尼洛·瓦斯康塞洛斯·巴尔加斯和樱井幸一。"愚弄深度神经网络的一个像素攻击." IEEE 进化计算汇刊 (2019)。

基于图像上下文恢复的医学图像分析自监督学习

原文:https://towardsdatascience.com/self-supervised-learning-for-medical-image-analysis-using-image-context-restoration-557c8c35d27f?source=collection_archive---------23-----------------------

一种称为上下文恢复的新型自我监督学习策略

这是论文“使用图像上下文恢复进行医学图像分析的自我监督学习”的博客帖子。

原载于wiki . tum . de

介绍

深度学习方法在计算机视觉领域取得了巨大成功。特别是,CNN 最近在医学图像领域,如疾病分类[1]和器官分割[2]中展示了令人印象深刻的结果。好的深度学习模型通常需要相当数量的标签,但在许多情况下,未标记的数据量远远大于已标记的数据量。此外,来自自然图像的预训练模型在医学图像上没有用,因为强度分布不同。此外,标记自然图像很容易,简单的人类知识就足够了。然而,医学图像的注释需要专业知识。

那么,我们应该如何学习无标签的表征呢?

答案很简单;从数据或图像本身获得监督。这意味着我们可以通过以特定的形式构建监督学习任务来实现这一点,以利用其余信息来预测仅一部分信息。这就是所谓的自我监督学习

什么是自我监督学习?

它仍然是监督学习,因为它使用标记数据。它提取并使用自然可用的相关上下文。从这一事实来看,有监督的大量训练实例是可用的。由于这一点,基于这种自我监督来预训练 CNN,它导致基于具有有限人工标签的数据来初始化后续 CNN 的有用权重。图 1 向我们展示了自我监督学习的概要。

图一。自我监督学习概述[3]

由于现有的自我监督学习策略在医学图像上没有显著的性能改善,作者提出了另一种自我监督策略,称为上下文恢复

图二。上下文恢复方法概述(图片由作者提供)

图 2 是上下文恢复如何工作的很好的概述。基本上,有输入图像,然后算法破坏并试图恢复它们。在这个恢复过程中,它学习权重,这将在处理后续任务时给我们带来更好的结果。

其中一项名为通过上下文预测的无监督视觉表示学习【4】的自我监督研究,从给定图像中预测 3 × 3 面片网格中中心面片与其周围面片之间的相对位置。例如,图 3-a 向我们展示了猫的右耳相对于猫的眼睛应该在右上的位置。但是它有三个缺点:可能有多个正确答案(例如,汽车或建筑物),它仍然学习在医学图像中没有用的琐碎特征,最后,补丁不包含关于图像的全局上下文的信息。

在特征学习方面,提出了另一个自我监督的研究,名为上下文编码器:通过修复进行特征学习[5]。它被训练来填补图像中缺失的一块,如图 3-b 所示,因此,在学习有意义的潜在表征的同时,重构原始输入。此外,这种方法也有一些缺点:它改变了图像的强度分布。因此,所得到的图像属于另一个域,并且所学习的特征对于原始域中的图像可能是无用的。

图 3。相对位置(a)和上下文预测(b)方法的演示[4,5]

方法学

论文提出了一种新的自我监督策略,他们称之为上下文恢复。该方法很简单,在给定的图像中随机选择两个孤立的小块并交换它们的上下文。重复这些操作 T 次,直到强度分布仍然保留,但其空间信息被改变。图 4 向我们展示了迭代 1 和 10 后的情况。

本文在医学成像中的三个常见问题上验证了上下文恢复策略:分类定位分割。胎儿 2D 超声图像中的扫描平面检测:在计算机断层摄影(CT)图像中定位腹部器官;为了分割多模态磁共振(MR)图像中的脑肿瘤,使用了。

图 4。生成用于自监督上下文乱序的训练图像:分别是大脑 T1 MR 图像、腹部 CT 图像和 2D 胎儿超声图像。在第二列的图中,红框突出显示了第一次迭代后交换的面片。(图片由作者提供)

所提出的自监督学习策略使用了细胞神经网络,它由两部分组成:一个分析部分和一个重构部分。图 5 示出了可行 CNN 的一般架构的概述。分析部分将给定的无序图像编码成特征图,重建部分使用这些特征图来产生正确上下文的输出图像。

分析部分

这部分包括卷积单元和下采样单元的堆栈,它们从给定的图像中提取特征图。

重建部分

这里,它包括卷积层和上采样层的堆栈,从而恢复图像。每个后续任务的重建部分是不同的。对于分类任务,简单的结构如几个反褶积层是优选的。对于分割任务,与分割 CNN 一致的复杂结构是优选的。

结果,几乎所有后续分割 CNN 的权重都可以使用在自我监督预训练中学习到的权重来初始化。

图 5。用于上下文恢复自监督学习的通用 CNN 结构。(图片由作者提供)

实验装置

所提出的使用上下文恢复任务的自我监督可以由 CNN 在三个不同的数据集上执行,包括脑部 MR 图像、腹部 CT 图像和胎儿 US 图像,并且他们使用预训练的 CNN 分别执行后续任务,例如分类、定位和分割。对于这些问题中的每一个,使用不同的 CNN 架构和数据:

分类

该数据集由 2694 个胎龄在 18 至 22 周之间的胎儿(224×288)的 2D 超声检查组成[6]。

这个分类问题的 CNN 是 SonoNet-64,它在[6]中取得了最好的性能。

CNN 在这种分类任务中的性能通过精确度、召回率和 F1 分数来测量。

本地化

采用了来自 150 名受试者 3D 腹部 CT 图像的数据集[7]。

数据集被随机分成两半。前半部分用于训练和验证,另一半用于测试。

用于多器官定位任务的 CNN 类似于 SonoNet [6]。由于输入图像为 512×512,大约是每侧已处理 2D 超声帧的两倍,因此它比 SonoNet 多了一个卷积堆栈和池层。

通过计算边界框之间的质心和墙的距离来测量性能。

分割

BraTS 2017 挑战赛的数据集,由 285 名受试者组成[8]。每个对象都有多种模式的 MR 图像,即自然 T1 (T1)、增强后 T1 加权(T1-Gd)、T2 加权(T2)、T2 液体衰减反转恢复(FLAIR)。如果您想进一步了解这些术语,请访问本网站

285 幅图像中的 142 幅用于训练和验证,剩余的 143 幅用于测试。

本实验中使用的 CNN 是 2D U-Net [9]。

他们在 BraTS 2017 挑战赛中使用了相同的评估指标:骰子得分、灵敏度、特异性和 Hausdorff 距离。

作者比较了不同的自我监督学习策略,即随机[6],随机+增强,自动编码器[10],使用补丁相对位置预测的自我监督[4],Jigsaw [11],以及使用局部上下文预测的自我监督[5]和提议的上下文恢复。

结果和讨论

图 6。胎儿 2D 超声图像标准扫描平面的分类(图片由作者提供)

图 6 展示了不同配置下 CNN 的性能结果。由于自我监督的预训练,当使用小训练数据集时,CNN 的性能可以得到改善。上下文恢复预训练对 SonoNet 性能的改善最大。

图 7。CNN 在不同训练环境下解决多器官定位(本结果中为左肾)问题的表现(图片由作者提供)

图 7 表示 CNN 在不同训练方法中的定位性能。在某些情况下,使用上下文恢复预训练的 CNN 在更多标记的训练数据上与无预训练相当甚至更好。就在左肾上的性能而言,CNN 在半个训练数据上略微优于在所有训练数据上。值得注意的是,如果较少的训练数据导致结果显著下降,自我监督学习往往会显著改善结果。

图 8。不同训练设置下定制 U-Nets 的分割结果(图片由作者提供)

图 8 显示了 BraTS 问题的结果。增强的肿瘤核心中的 Dice 分数甚至稍好。并且,它向我们展示了使用一半的训练数据集,所提出的自监督策略产生了与使用整个训练数据集相似的性能。同样,我们可以看到基于上下文恢复的自我监督为分段任务提供了最佳的预训练方法。

提出了一种新的基于上下文恢复的自监督学习策略。这使得 CNN 能够在没有任何标签的情况下学习有用的图像语义,并用于后续任务。因此,我们可以总结出以下要点:

  • 在分类、定位和分割这三项任务中,使用上下文恢复预训练比其他方法表现更好
  • 如果减少训练数据导致性能显著下降,上下文恢复预训练可以提高性能
  • 语境还原有三个显著特征;学习语义图像特征;这些语义特征对于不同的后续任务是有用的;实现简单明了
  • 缺点是 L2 损失导致图像模糊。

未来作品

探索更有效的自我监督学习策略,使自我监督预训练在未来能像监督预训练一样好,是值得关注的。此外,还会出现以下问题:

  • 如果使用更大的数据集会发生什么?还是优化的自我监督学习模型?
  • 如果他们可以使用 3x3 补丁并随机交换,结果会受到什么影响?
  • 添加额外的模型?
  • 使用另一种损失函数代替 L2,例如对抗性损失?

作者:粱晨、保罗·本特利、森健作、三泽和里、藤原道孝、丹尼尔·吕克特

关于这项工作的更多细节,请查看关于科学指导的论文

参考

[1]王,x,彭,y,陆,l,陆,z,巴盖里,m,萨默斯,R. M,2017 .ChestX-ray8:医院规模的胸部 X 射线数据库和常见胸部疾病的弱监督分类和定位基准。IEEE 计算机视觉和模式识别会议论文集。第 3462-3471 页。网址 https://arxiv.org/abs/1705.02315。

[2]Suk h .-I .,Lee s-w .,Shen d .,Initiative,A. D. N .等人,2014 年。用于 AD/MCI 诊断的分层特征表示和具有深度学习的多模态融合。神经影像 101,569–582。网址https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4165842/

[3] Yann LeCun,自我监督学习:机器能否像人类一样学习,2018。网址youtube.com

[4]多尔施,c .,古普塔,a .,埃夫罗斯,A. A .,2015。基于上下文预测的无监督视觉表征学习。IEEE 计算机视觉国际会议论文集。第 1422-1430 页。网址https://arxiv.org/abs/1505.05192

[5] Pathak,d .,Krahenbuhl,p .,Donahue,j .,Darrell,t .,Efros,A. A .,2016 年。上下文编码器:通过修补进行特征学习。IEEE 计算机视觉和模式识别会议论文集。第 2536-2544 页。网址https://arxiv.org/abs/1604.07379

[6]鲍姆加特纳,C. F .,卡姆尼萨斯,k .,马修,j .,弗莱彻,T. P .,史密斯,s .,科赫,L. M .,坎因茨,b .,吕克特,d .,2017。SonoNet:徒手超声中胎儿标准扫描平面的实时检测和定位。IEEE 医学成像汇刊 36 (11),2204–2215。网址https://arxiv.org/abs/1612.05601

[7] Tong,t .,Wolz,r .,Wang,z .,Gao,q .,Misawa,k .,藤原,m .,Mori,k .,Hajnal,J. V .,Rueckert,d .,2015 年。用于腹部多器官分割的判别字典学习。医学图像分析 23 (1),92–104。网址 https://www.ncbi.nlm.nih.gov/pubmed/25988490。

[8] Menze,B. H .,Jakab,a .,Bauer,s .,Kalpathy-Cramer,j .,Farahani,k .,Kirby,j .,Burren,y .,Porz,n .,Slotboom,j .,Wiest,r .,等人,2015 年。多模态脑肿瘤图像分割基准(BRATS)。IEEE 医学成像汇刊 34 (10),1993–2024。网址 https://ieeexplore.ieee.org/document/6975210。

[9]罗内贝格,o .,菲舍尔,p .,布罗克斯,t .,2015。生物医学图像分割的卷积网络。医学图像计算和计算机辅助介入国际会议论文集。第 234-241 页。网址https://arxiv.org/abs/1505.04597

[10]本吉奥,y .,兰布林,p .,波博维奇,拉罗歇尔,h .,2007 年。深度网络的贪婪分层训练。神经信息处理系统进展。第 153-160 页。网址https://papers . nips . cc/paper/3048-greedy-layer-wise-training-of-deep-networks . pdf

[11]诺鲁齐,m .,法瓦罗页,2016 年。通过解决拼图游戏实现视觉表征的无监督学习。《欧洲计算机视觉会议论文集》。第 69-84 页。网址https://arxiv.org/abs/1603.09246

视频的自监督表示学习

原文:https://towardsdatascience.com/self-supervised-representation-learning-on-videos-3a63872971c5?source=collection_archive---------64-----------------------

如今,从 Imagenet 迁移学习是计算机视觉中的绝对标准。自我监督学习主导了自然语言处理,但这并不意味着计算机视觉没有值得考虑的重要用例。

在处理图像时,确实有很多很酷的自我监督的任务,比如拼图游戏、图像着色、图像修补,甚至是无人监督的图像合成。

但是当时间维度开始起作用时会发生什么呢?您如何处理您想要解决的基于视频的任务?

所以,让我们从头开始,一次一个概念。什么是自我监督学习?和迁移学习有什么不同?什么是借口任务?

自我监督学习与迁移学习

毫无疑问,迁移学习是一个公平的起点。

迁移学习使我们能够利用用于任务 A 的神经网络的权重,并将其应用于另一个任务(B),假定输入域以某种方式相关

任务 A 中的训练过程在机器学习术语中称为预训练。这背后的核心思想是,任务 A 所获得的“知识”可以被用来增强任务 b 中的概括。这通常是这样,因为谁想从随机权重初始化开始呢?

显然,迁移学习是最大化模型性能的一种方式,通过在类似的监督的(视频)数据集上预训练。然而,在视频等领域,标注(监督)的问题很快出现。很难找到视频注释数据和转移权重。

但在此之前,我们先来澄清一下自我监督学习 VS 迁移学习的内在区别。我创建这个简单的图表是为了让事情变得非常清楚:

作者图片,自我监督 VS 迁移学习

作为监督缺失领域的解决方案,自我监督学习是转移权重的一种方式,通过在标签上预先训练你的模型,这些标签是从 数据/视频中人工产生的

正如我们将看到的,这可以通过一系列不同的(有时是欺骗性的)转换来实现。这就是我们所说的自我监督的表征学习。

注意,对于自我监督学习,你甚至可以只使用你自己的数据,没有提供的标签。

本质上,在自我监督学习中,我们试图 猜测 一个相关的任务 A,因此将权重转移到任务 B,将是比随机更好的初始化点。

符号、概念和示例任务

设计的自我监督任务 A 通常被称为借口代理任务,而我们想要解决的期望任务 B 在文献中被称为下游任务。我通常也称之为原始任务。

回到视频的世界,基于视频的学习属于顺序学习的范畴。这些方法可以大致分为两类:序列预测验证。此外,(图像)元组指的是将被用作深度学习架构的输入的一串视频帧。

连体模型或多分支模型在不同论文中交替使用。基本上是多个输入数据的独立预测*。您可以简单地认为,在向后传递之前,必须执行暹罗模型的许多向前传递,而提取的特征将在接下来的层中进行融合。因此,将反向传播的损失考虑了所有正向传递。*

现在我们对自我监督有了明确的高层概念。让我们看看它为什么重要,尤其是在视频数据集上!

为什么要自我监督学习?

首先,你不能为每个特定的任务创建一个新的视频数据集(或任何种类的数据集)。视频注释也是昂贵且耗时的。其次,在医学影像这样的领域,根本很难获得任何专家的注释。另一方面,youtube 上每天都有数十万小时的未标记视频被上传!如果你仍然不相信自我监督学习是一个令人敬畏的方向,让我们向专家提出建议:

我们人类学习的大部分东西和动物学习的大部分东西都是在一种 自我监督模式 下进行的,而不是强化模式。它基本上是观察这个世界,并与它进行一点互动,主要是通过独立于测试的方式进行观察。~艾研究中心主任杨乐存(公正)

现在我相信你已经被说服了。然而,要知道每一个令人兴奋的想法都伴随着它的假设和对应物。但在此之前,让我们先澄清我们的术语。

继续,视频自我监督学习的核心假设是什么?

直觉上,我们认为成功地解决“托词”任务 A 将 允许我们的模型学习有用的视觉表示,以恢复视频的时间连贯性 ,或者通常从视频的统计时间结构中学习。

时间一致性的一个例子可能是观察物体(汽车、人)如何在场景中移动。

你可能会想到的一些问题:

  1. 给定空间和时间视频结构,模型如何在没有监督的情况下从视频中学习?
  2. 自我监督模型学习什么样的表征?有意义吗?
  3. 与监控的图像/视频数据相比,学习的表示是互补的还是相似的?"

我们将通过考察不同的方法来回答这些问题。但即使在此之前,一个人如何设计一个自我监督的任务

“总之,一个好的自我监督的任务既不简单也不含糊”
~
诺鲁齐等人【6】*。
*

我们考虑的另一个关键因素是人类是否能解决借口任务。举个例子,试着理解下面这些帧的顺序。通过一点点关注相对姿势和对“一个人如何移动”的猜测,我们可以预测这些帧的时间顺序。

图片由李信颖等人制作**

此外,我们需要选择一些事情,如果解决了,就需要理解我们的数据。这就是为什么无论如何它都属于表征学习的范畴:)。

洞察力:关键思想是利用原始图像的固有结构和 问题公式化为判别(分类)或引入重建损失函数来训练网络。

也就是说,我希望你已经准备好简要地检查最有影响力的视频自我监督表示学习论文。

1.洗牌和学习:使用时序验证的无监督学习,ECCV 2016

这是 Misra 等人[1]介绍的首批作品之一。他们将他们的托词任务公式化为序列验证问题。

在时序中,一个预测序列的''。**

在这项工作中,作者探索了任务视频帧序列是否处于正确的时间顺序。为了做到这一点,他们必须使用一种采样方案来对视频进行采样。这很重要的原因当然是计算的复杂性。**

为此,他们根据每帧的平均光流幅度对高速运动的图像进行采样。为了创建阳性和阴性元组,使用五个帧的样本作为输入。正样对应正确顺序,而负样是指错误顺序中的帧。下图进一步说明了这种差异。**

视频混洗的例子,正反例子。由 Misra 等人[1]拍摄的图像。链接:https://link . springer . com/chapter/10.1007/978-3-319-46448-0 _ 32

训练技巧:在训练过程中,作者使用了相同的开始和结束帧,而只改变了正反例的中间帧。因此,鼓励网络关注这个信号,以了解积极和消极之间的微妙差异,而不是无关的特征。**

提议的网络架构概述。由 Misra 等人[1]拍摄的图像。链接:https://link . springer . com/chapter/10.1007/978-3-319-46448-0 _ 32

基于该架构方案,值得注意的是,AlexNet 独立地处理每一帧,而图像特征输出被连接用于最终分类。**

最后,他们使用了大约 90 万个图像元组,具有正负实例的平衡小批量比率。正如所发现的那样,对于订单验证来说,拥有更大比例的反面例子(75%)是至关重要的。

结果和讨论

提出的问题是模型真正从时间结构中学到了什么?在下图中,作者声称显示了这些单位的感受野(用红框标出)。由于我们的网络是在人体动作识别视频上训练的,许多单元显示出对人体部位和姿势的偏好,因为它们与高速运动有关。虽然在论文中它被称为感受域,但事实是这是层的特征激活。**

可视化激活,如原文所述。图片由 Misra 等人提供。链接:https://link . springer . com/chapter/10.1007/978-3-319-46448-0 _ 32

在数字上,通过将该方案与 imagenet 预训练权重相结合,我们获得了与视频监督几乎相同的平均准确度,如下图所示(UCF sup。是有动作视频的监督数据库):

图片由 Misra 等人提供。链接:https://link . springer . com/chapter/10.1007/978-3-319-46448-0 _ 32

挑战性动作识别任务的结果。

最后,基于呈现的结果,可以验证序列验证需要理解手边的基于视频的任务(动作识别)。

2.通过排序序列的无监督表示学习,ICCV 2017

核心贡献:Lee 等 2017 [2]提出了一种顺序预测网络(OPN)架构,通过成对特征提取解决序列排序任务。

扩展之前的工作,我们正在尝试排序混洗图像序列。如果验证需要理解图像的统计时间结构,人们可能会猜测图像分类将提供更丰富和更一般化的视觉表示。为此,作者尝试在给定四个采样图像的元组的情况下,使用这样的代理任务进行训练,如下所示。**

形象由李信颖等人塑造。顺序采样和排序****

对于一个有 n 帧的元组,有 n!(!是阶乘的可能组合。在实践中,作者使用了四个随机洗牌的框架。类似于拼图难题[6],他们把问题铸为多类分类。对于每个四帧元组,有 24 种可能的排列。然而,向前和向后的排列可以被转换为一个类,因为它们可以是动作的可能的解决方案,导致总共 12 个类。

训练数据采样

与其他作品类似,他们基于运动幅度对帧进行采样。除了仅使用光流大小进行帧选择之外,他们进一步选择具有大运动的空间补片(图中的 a)。另外,它们在已经提取的裁剪图像中应用空间抖动(如图中的 b 所示)。此外,他们引入了一种新的策略,称为渠道分裂(如 c 所示)。这大致类似于使用灰度图像,但是基于实验分析,它表现得更好。具体来说,他们选择一个通道,并将值复制到 RGB 图像的其他两个通道。结果,引导网络关注图像的语义,而不是低级特征。**

训练抽样技巧。 图片由李新英等人制作**

模型架构、数据和一些结果

与[1]类似,它们基于典型的卷积神经网络产生图像特征。在文献中,这被称为连体建筑。同样,每个帧由同一个模型独立处理(通常称为多分支,更好一些),而参数是相同的。另一个要点是成对特征提取,如架构概述所示。如下所示,fc6 特征的特征用于形成帧特征对。这些允许某种融合,或者换句话说,考虑特征的成对关系。

具有成对特征提取的连体模型架构。 图片由李新英等人*制作*

最后,他们从~30K 的 UCF-101 动作识别数据集提取 280k 元组作为训练数据,相对大批量 128。输入补丁为 80x80。值得注意的是,使用较大补丁的性能不佳的一个潜在原因可能是训练数据量不足。

下面是一些功能激活的图示。可以观察到,特征激活对应于人的头部和对象部分。

原作中呈现的激活。 形象由李新英等人【2】

3.2017 年 CVPR,利用奇数一输出网络的自监督视频表示学习

让我们从这个被设计出来的任务开始,这个任务叫做奇数一个出局。简而言之,奇一出学习的目标是从一组其他相关元素中预测* 奇(不相关** ) 元素。*****

形式上,给定一组多个相关元素和,只有一个奇数元素构成问题 q = {I_1,.。。,I_{N+1},其中 I_i 是元素。在这种情况下,我 {1},。。。,I 是从视频中采样的子序列集。所描述的 N 个子视频具有正确的时间顺序。奇数不相关视频子序列是来自同一视频的无效顺序。为了防止平凡的解决方案,作者随机化奇数元素的位置。因此,奇一出预测任务被视为一个 N+1 分类问题。**

模型架构

预测模型是多分支 CNN,称为奇一出网络(O3N)。O3N 由 N + 1 个输入分支组成,每个分支包含 5 个 conv。图层(权重在输入图层间共享)。奇数一出任务需要在(N+1)个元素中进行比较。要解决这个问题,不能只看单个的元素。因此,他们进一步引入了一个融合层来合并来自不同分支的信息。最后,他们实验了两种融合,串联和差和。

模型概述。图像由 徐等人【4】

4.通过视频剪辑顺序预测的自我监督时空学习,CVPR 2019

再次,徐等 2019 [4]制定的任务顺序预测,作为一个分类问题。除了以前的作品,他们通过制作小视频剪辑的独立特征而不是纯图像来整合 3D CNN。因此,手头的任务现在被称为剪辑顺序预测。他们的方法可以总结如下:**

  • 首先,从视频中采样几个固定长度(16 帧)的剪辑并随机打乱,
  • 然后,使用共享权重(暹罗架构),使用 3D CNNs 来提取这些片段的独立特征。
  • 最后,使用一个简单的神经网络来预测混洗剪辑的实际顺序。

学习的 3D CNNs 可以用作剪辑特征提取器或预训练模型,以针对动作识别进行微调。为了证明他们的想法,评估了三种强大的 3D-CNN 架构,即 C3D [9]、R3D 和 R(2+1)D [10](在下图中表示为 3D ConvNets)。提议的架构概述如下:

建议的模型架构。图像由 徐等人【4】

注意:由于剪辑顺序预测只是一个代理任务,并且目标是学习视频表示,所以该任务应该是可解决的。对于元组长度,每个元组选择 3 个片段,批量大小为 8 个元组。视频剪辑由用于 3D CNNs 的 16 帧组成,而视频之间的间隔被设置为 8 帧,以避免琐碎的解决方案。

为了验证所学习的表示,他们使用基于从 3D-CNN 产生的特征的最近邻检索。为了评估他们的动作识别方法,从视频中采样 10 个剪辑以获得剪辑预测,然后对其进行平均以获得最终的视频预测。

最后一点,虽然这项研究显示了有希望的结果,但在较大数据集(如 Kinetics)上监督预训练的微调仍然是最佳预训练方案**

结论

我希望你现在明白了。我们将会看到越来越多的自我监督学习的酷应用。简而言之,我们开始了自我监督学习,重点是视频。我们介绍了额外时间维度带来的问题以及如何应对它们。

另外,Yann LeCun 在 ICLR 2020 中做了一个非常值得一看的鼓舞人心的演讲。我想虚拟会议的积极一面。我很喜欢看这部电影。

对于那些想要更高级的东西的人,你可以继续前往自我监督的生成对抗网络,因为你知道我们有多喜欢人工智能夏天的生成学习。最后,为了更全面地总结大量自我监督的表征学习(没有关注视频),请查看 Lilian Weng 的这篇博客文章【8】。**

参考

[1] Misra,I .,Zitnick,C. L .,& Hebert,M. (2016 年 10 月)。洗牌学习:使用时序验证的无监督学习。欧洲计算机视觉会议(第 527–544 页)。斯普林格,查姆。**

[2]李海燕,黄,J. B .,辛格,m .,,杨,M. H. (2017)。通过排序序列的无监督表示学习。IEEE 计算机视觉国际会议论文集(第 667-676 页)。

[3] Fernando,Basura,et al . .用单输出网络进行自监督视频表示学习IEEE 计算机视觉和模式识别会议论文集。2017.**

[4]徐,丁,肖,赵,赵,邵,谢,庄,杨(2019).通过视频剪辑顺序预测的自我监督时空学习。在IEEE 计算机视觉和模式识别会议论文集(第 10334–10343 页)。**

[5]焦,j .,德罗斯特,r .,德鲁克尔,l .,帕帕乔乔,A. T .,&诺布尔,J. A. (2020 年 4 月)。超声视频的自监督表示学习。载于 2020 年 IEEE 第 17 届国际生物医学成像研讨会(ISBI) (第 1847-1850 页)。IEEE。

[6]米·诺鲁齐和法瓦罗出版社(2016 年 10 月)。通过解决拼图游戏对视觉表征进行无监督学习。欧洲计算机视觉会议(第 69–84 页)。斯普林格,查姆。**

[7] Gopnik,a .,Meltzoff,A. N .,& Kuhl,P. K. (2000 年)。 婴儿床里的科学家:早期学习告诉我们关于大脑的什么 。威廉·莫罗平装本。

[8] 自我监督表征学习,翁,李莲 2019

[9] Tran,d .,Bourdev,l .,Fergus,r .,Torresani,l .,和 Paluri,M. (2015 年)。用 3d 卷积网络学习时空特征。IEEE 计算机视觉国际会议论文集(第 4489–4497 页)。**

[10] Tran,d .,Wang,h .,Torresani,l .,Ray,j .,LeCun,y .,& Paluri,M. (2018 年)。近距离观察用于动作识别的时空卷积。在IEEE 计算机视觉和模式识别会议论文集(第 6450–6459 页)。**

原载于 2020 年 7 月 29 日 https://theaisummer.com**T21

通过视频彩色化的自我监督跟踪

原文:https://towardsdatascience.com/self-supervised-tracking-via-video-colorization-7b2b066359d5?source=collection_archive---------44-----------------------

作为代理任务的视频着色和作为下游任务的对象跟踪

普里西拉·杜·普里兹在 Unsplash 上的照片

在这篇文章中,我们将了解一种新颖的自监督目标跟踪方法。自我监督是模型自我学习的一种方法😎,这本身就让题目很有意思。在这里,我们将看到我们的模型如何学会自己跟踪对象。我们将从物体跟踪的基础开始,然后讨论什么是计算机视觉的自我监督学习,最后详细讨论这种方法。

这个方法的实现可以在这里找到

对象跟踪简介🎯

用简单的语言来说,它可以理解为在整个视频序列中识别唯一的对象。要跟踪的对象通常被称为目标对象。跟踪可以通过 包围盒 或者 实例分割 来完成。有两种类型的公共对象跟踪挑战。

  1. 单个对象跟踪:在整个视频序列中跟踪感兴趣的对象。例如 VOT 挑战
  2. 多目标跟踪:在整个视频序列中跟踪多个感兴趣的目标。例如 MOT 挑战

研究趋势

用于解决对象跟踪的一些著名的经典 CV 算法是:

  1. 均值漂移
  2. 光流
  3. 卡尔曼滤波器

其中最著名的多目标跟踪算法 SORT 以卡尔曼滤波器为核心,非常成功。

随着深度学习时代的到来,非常创新的研究进入了社区,DL 在公共跟踪挑战方面成功地胜过了经典的 CV 方法。尽管 DL 在公共挑战上取得了巨大成功,但它仍在努力为现实世界的问题陈述提供通用的解决方案。

深度模型的挑战💭

当训练深度 CNN 模型时,我们面临的主要挑战之一是训练数据。

  • 训练数据:深度学习方法需要大量数据,这几乎每次都会成为瓶颈。此外,像多目标跟踪这样的任务很难注释,并且这个过程变得不切实际且昂贵。

DL 模型需要大量数据

自我监督学习营救😯

我们都知道监督和非监督学习技术。这是一种相当新的类型,被称为自我监督学习。在这些类型的学习中,我们试图利用数据中已经存在的信息,而不是任何外部标签,或者有时我们说模型自己学习。在现实中,我们所做的是训练 CNN 模型来完成一些其他的任务,间接帮助我们实现我们的目标,模型会自我监督。这些任务被称为“代理任务或“借口任务”。
代理任务的几个例子是:

  • 着色

CNN 模型学习从灰度图像预测颜色。[ 来源

  • 将图像补丁放置在正确的位置

这些小块是从图像中提取出来的,并被混洗。该模型学习解决这个拼图,并按照正确的顺序排列瓷砖,如图 3 所示。[ 来源

  • 按照正确的顺序放置框架

该模型学习对视频序列中的混洗帧进行排序。[ 来源

许多这样的任务可以用作计算机视觉问题的代理任务。这种培训的一个主要好处是,培训不需要手动注释数据,并且适合解决现实生活中的用例。

通过视频彩色化的自我监督跟踪

我们已经看到了什么是自我监督模型,你一定已经猜到了我们将使用着色作为我们的代理任务的名称。

[## 通过给视频着色,跟踪出现了

我们使用大量未标记的视频来学习模型,以便在没有人工监督的情况下进行视觉跟踪。我们…

arxiv.org](https://arxiv.org/abs/1806.09594)

介绍

着色是我们的代理任务借口任务,物体跟踪是主任务下游任务。大规模无标签视频用于训练模型,没有任何单个像素被人类标注。视频的时间相干性用于使模型学习给灰度视频着色。这可能看起来令人困惑,但坚持下去,我会把事情弄清楚。

模型将如何学习跟踪?

我们将取两个帧一个目标帧(在时间 t)和一个参考帧(在时间 t-1),并通过模型。期望该模型根据参考帧的颜色的先验知识来预测目标帧的颜色。这样,模型内部学习指向正确的区域,以便从参考帧复制颜色,如图所示。这种指向机制可以用作推断过程中的跟踪机制。我们将很快看到如何做到这一点。

该模型接收一个彩色帧和一个灰度视频作为输入,并预测下一帧的颜色。该模型学习从参考帧复制颜色,这使得能够在没有人类监督的情况下学习跟踪机制[ 来源

我们不复制网络中的颜色,而是训练我们的 CNN 网络来学习目标帧的像素和参考帧的像素之间的相似性(相似性是灰度像素之间的相似性),然后当与参考帧的真实颜色线性组合时,该相似性矩阵给出预测的颜色。数学上,让 Cᵢ 是参考帧中每个像素 i 的真实颜色,让 Cⱼ 是目标帧中每个像素 j 的真实颜色。该模型给出了目标帧和参考帧之间的相似性矩阵 Aᵢⱼ 。我们可以通过线性组合得到预测的颜色 yᵢ

[ 来源

等式 1 :预测颜色与参考颜色的线性组合

相似矩阵怎么算?

当通过模型时,图像、参考帧和目标帧都学习对每个像素的低级嵌入,这里 fᵢ 是对参考帧中的像素 i 的嵌入,类似地, fⱼ 是对目标帧中的像素 j 的嵌入。那么相似性矩阵可以通过下式计算:

等式 2: 内部
产品相似度由 softmax 归一化

相似性矩阵中的每一行表示参考帧的所有像素 i 和目标帧的像素 j 之间的相似性,因此为了使总权重为 1,我们对每一行应用 softmax。

Lets look an example with dimension to make it clear,we try to find a similarity matrix of 1 pixel from target frame.
An illustration of this example is shown below.Consider reference image and target image, size (5, 5) => (25,1)for each pixel, cnn gives embedding of size (64, 1)
*fᵢ*, embedding for reference frame, size (64, 25)
*fⱼ*, embedding for target frame, size (64, 25)
*at j=2 f₂*,  embedding for 3rd pixel in target frame, size (64, 1)**Similarity Matrix,** between reference frame and target pixel, j=2
 *Aᵢ₂* =softmax *(fᵢᵀ x f₂)* , size (25, 64) *x* (64, 1) => (25,1) =>   (5, 5)
we get a similarity between all the ref pixels and a target pixel at j=2.**Colorization,** To copy the color (here, colours are not RGB but quantized colour of with 1 channel) from reference frame,
*cᵢ*, Colors of reference frame size (5, 5) => (25, 1)
*Aᵢ₂*, Similarity matrix, size (5, 5) => (1, 25)**Predicted color** at j=2, 
*y₂ = Aᵢ₂ x cᵢ*, size (1, 25) *x* (25, 1) => (1, 1)From the similarity matrix in below figure, we can see reference color at i=1 is dominant(0.46), thus we have a color copied for target, j=2 from reference, i=1**PS:** 1\. ᵀ denotes transpose
2\. matrix indices starts from 0

(a)示出了大小为(5,5)的 2 个帧,(b)参考帧嵌入和 j =2 处的目标像素嵌入的内积,(softmax 之后的相似性矩阵,(d)相似性矩阵和参考帧的真实颜色的线性组合[ ]

类似地,对于目标帧中的每个目标像素( (5,5)= > 25 像素),我们将具有大小为(5,5)的相似性矩阵,即大小为(5,5,25) = (25,25)的完整相似性矩阵 Aᵢⱼ
我们将在实现中使用(256 x 256)图像扩展相同的概念。

图像量化

第一行显示原始帧,第二
行显示来自 Lab space 的 ab 颜色通道。第三行将颜色空间量化为离散的面元,并扰动颜色以使效果更加明显。[ 来源

颜色是低空间频率,所以我们可以使用低分辨率的帧。我们不需要 C(255,3) 颜色组合,所以我们创建了 16 个聚类,并将颜色空间量化到这些聚类中。现在我们只有 16 种独特的颜色,(见上图第三栏)。聚类是使用 k-means 完成的。16 个簇会丢失一些颜色信息,但足以识别物体。我们可以增加聚类的数量来提高着色的精度,但代价是增加计算量。

为什么 LAB 色彩空间优于 RGB?

来源

为了将图像量化成簇,我们将使用 LAB 色彩空间的 AB 通道,而不是 RGB 色彩空间。上图显示了 RGB 和 LAB 通道间相关性,我们可以从图中得出以下结论

  • RGB 往往比 LAB 有更多的相关性。
  • LAB 将迫使模型学习方差,它将迫使学习更健壮的表示,而不是依赖于局部颜色信息

可以使用 sklearn 的 KMeans 包来完成集群。

这个类将被用来制作颜色簇,我们将把它作为泡菜来保存。

履行💻

注意:我用 pytorch 实现,它遵循(N,C,H,W)格式。在处理矩阵整形时,请记住这一点。如果你对形状有任何疑问,请联系我们。

该模型从参考帧学习给视频帧着色。[ 来源

投入

该模型的输入是下采样到
256 × 256 的四个灰度视频帧。三个参考帧和一个目标帧。

预处理

首先,我们将把所有的训练视频压缩到 6 帧/秒。然后预处理帧以创建两个不同的集合。一个用于 CNN 模型,另一个用于着色任务。

- Video fps is reduced to 6 fps**SET 1 - for CNN Model**- Down sampled to 256 x 256- Normalise to have intensities between [-1, 1]**SET 2 - for Colourization**- Convert to LAB colour space- Downsample to 32 x 32- Quantize in 16 clusters using k-means- Create one-hot vector corresponding to the nearest cluster centroid

模型架构

使用的主干是 ResNet-18 ,因此结果与其他方法相当。ResNet-18 的最后一层被更新以给出 32 x 32 x 256 的尺寸输出。ResNet-18 的输出然后被传递到 3D-Conv 网络,最终输出是 32 x 32 x 64。(下面的代码块显示了从 ResNet-18 网络获取输入的 3D 网络)

培养

培训可分为以下 3 个步骤:

  1. 网络通道
    我们将使用预处理帧的集合 1,即大小为(256 x 256)的 4 个灰度帧通过网络,以获得具有 64 个通道的(32 x 32)空间图。这可以解释为对(32 x 32)图像的每个像素进行 64 维嵌入。因此,我们有四个这样的像素级嵌入,三个用于参考图像,一个用于目标图像。

  2. 相似性矩阵 利用这五个嵌入,我们找到参考帧和目标帧之间的相似性矩阵。对于目标帧中的像素,我们将通过 softmax 将所有三个参考帧中的所有像素的相似性值归一化为 1。

3。着色 我们将使用预处理帧的集合 2,即四个下采样为(32 x 32)并量化的帧用于着色。将三个参考帧与相似性矩阵组合以获得预测的量化帧。我们用预测的颜色找到 交叉熵损失 (记得我们将帧量化为 16 个簇,现在我们有 16 个类别。我们在这些颜色上发现了多类别交叉熵损失。)

推理

跟踪预测示例[ 来源

在学习了着色的任务之后,我们有了一个可以为一对目标和参考帧计算相似矩阵 Aᵢⱼ 的模型。现在对于实际的跟踪任务,我们利用了我们的模型在标签空间中是非参数的特性。我们简单地重复使用 e 方程 1 来传播,但是不是传播颜色,而是传播类别的分布。对于第一帧,我们有地面真实遮罩,我们将把所有实例遮罩安排为独热向量 c ᵢ(这类似于训练期间使用的量化颜色的独热向量)。将 c 与我们的相似性矩阵 Aᵢⱼ 结合起来,找到蒙版的新位置,但是记住预测 c 在随后的帧中会变软,表示模型的置信度。要做一个艰难的决定,我们可以简单地取最有信心的一类。推理的算法将是:

**WHILE (**target frame, reference frames) in the videostep 1\. Pass the target and reference frames through CNN modelstep 2\. Find Similarity Matrixstep 3\. Take ground truth object masks as one-hot encodingstep 4\. Linear combine the object masks with similarity matrixstep 5\. Update ground truth object masks by predicted masks

故障模式

让我们讨论一下在某些情况下模型什么时候会失败,这主要是着色失败的情况,这意味着着色与跟踪有很高的相关性。
在以下情况下会发现一些故障:

  • 当视频中的光线剧烈或频繁变化时
  • 该方法成功地跟踪具有轻微到中等遮挡物体,但是当物体经历较大遮挡时仍然失败
  • 物体尺寸的突然变化

结论

在这里,我们看到了一个模型如何在没有任何手动注释数据的情况下从自己的模型中学习。我们学习了如何在一些代理任务上训练 CNN 模型,并利用这种学习来完成实际的任务。我们使用着色作为代理,但不限于此,各种新的方法作为新的代理任务出现。自我监督的方法是当前的需要,它们可以消除现实世界用例的昂贵数据收集的主要限制。这个模型还不能击败目前的 SOTA 监督模型,但优于许多其他模型。

该方法在方法和灵活性方面非常有前途。由于自身的优势,自监督模型将很快成为解决最大似然问题的首选。这篇文章是基于“ Google Research ”的研究和他们所有的功劳。我试图根据我的知识和理解来解释这项研究。

关于我

我是 Tushar Kolhe,在 Fynd 担任深度学习工程师。我的兴趣是建立解决现实世界问题的计算机视觉模型。
通过电子邮件寻求任何建议或帮助。

我坚信,如果有足够的动力,任何人都可以学到任何东西,深度模型也是如此😛。

附录

目标跟踪领域的一些有趣研究:

  1. 简单的在线实时跟踪,具有深度关联度量。【 论文→扩展排序
  2. 没有花里胡哨的跟踪。【 论文
  3. 单次多目标跟踪的简单基线- FairMOT论文
  4. 学习用于多目标跟踪的神经解算器。【 论文**

你可以找到更多有趣的研究,评论你觉得有趣的研究。

参考

  1. 冯德里克、施里瓦斯塔瓦、法蒂、瓜达拉马和墨菲(2018 年)。跟踪是通过给视频着色而出现的。 ArXiv,abs/1806.09594
  2. 。用于图像识别的深度残差学习。ArXivABS/1512.03385
  3. 张曦轲菲利普·伊索拉阿列克谢·阿·埃夫罗斯。彩色图像彩色化。ArXivT58ABS/1603.08511
  4. 迈赫迪·诺鲁齐,保罗·法瓦罗。通过解决拼图游戏实现视觉表征的无监督学习。 ArXiv abs/1603.09246
  5. 李新英贾-黄斌辛格明-杨玄。通过排序序列的无监督表示学习。 ArXiv abs/1708.01246
  6. https://www.fast.ai/2020/01/13/self_supervised/

自学成才的数据科学家:用个人网站展示自己

原文:https://towardsdatascience.com/self-taught-data-scientist-showcase-yourself-with-a-personal-website-79fc31580c2?source=collection_archive---------16-----------------------

一个简单且几乎免费的初学者循序渐进指南

爱丽丝·山村在 Unsplash 上的照片

没有数据科学的大学学位,很难让别人相信你的技能。没有任何工作经验更是难上加难。

我知道,这似乎不公平!

当你在电脑上花了无数个小时努力开发所有这些技能,弄清楚那些令人绞尽脑汁的算法是如何工作的时候,你认为雇主必须承认你是一名体面的数据科学家,并给你你努力争取的工作机会。

除非你用确凿的证据向他们展示你的所有技能,让自己与众不同,否则这种情况不会发生。

拥有一个个人网站为你提供了一个展示技能的平台。

在这篇文章中,我将解释你如何能容易地并且几乎免费地创建你的网站。

在这篇文章的第一部分,我将介绍你应该在你的网站上展示什么。然后在后面的部分,我会告诉你如何从头到尾处理网站开发任务,包括设置主机/域名服务和处理 HTML/CSS 开发。

所有的源代码都在我的 GitHub 库中提供,你可以访问我的个人网站来查看所有的操作。

作为一名自学成才的数据科学家,你应该在你的网站上展示什么

在开始开发你的网站之前,你应该考虑如何构建你网站的内容。下面是你的网站应该包含的主要部分;

  • 您的博客帖子
  • 您的数据科学产品组合
  • 你的简历
  • 您的社交媒体资料

开始写博客

如果你在自学数据科学家之旅的早期就开始写博客,会有很大帮助。写文章不仅能让你在旅途中学到的东西具体化,还能向别人展示你的发现和论点传达得有多好。

以下是您可以撰写的数据科学主题列表;

  • 数据采集和准备
  • 特征工程
  • 机器学习
  • (英)可视化(= visualization)
  • 传达调查结果

你可以开发自己的博客网站,也可以使用免费平台,如 Medium

亚历杭德罗·埃斯卡米拉在 Unsplash 上的照片

发展你的投资组合

你可能会参加许多 CourseraBootcamp 的课程,但让你与众不同的是你如何将你的知识应用到实际问题中。这是让招聘人员相信你的技能的原因。

因此,拥有一个适当的数据科学组合并在您的网站上展示它会产生巨大的影响。

但是,什么是好的数据科学投资组合呢?

  • 独立边项目:这些项目向别人展示你在现实生活中如何运用你的数据科学知识。最好不要使用概念验证数据库来解决琐碎的问题。相反,开发你独特的数据库,调查一个有趣的问题。
  • Kaggle 竞赛:参加 Kaggle 竞赛是展示你相对于该领域其他人的技能水平的一种方式。
  • 开源项目:开源项目为您提供了一个发展数据科学经验的绝佳机会。

创建您的简历

招聘人员浏览简历以确定可能的候选人。因此,拥有一份结构良好、易于阅读的简历会增加你被聘用的机会。为了更好地展示自己,你至少应该在简历中包括以下内容:

  • 个人信息
  • 位置
  • 教育
  • 项目
  • 能力和个人技能

建立你的社交媒体档案

作为一名数据科学家,你需要在一定程度上使用社交媒体。推特是和你的同龄人交流的最好方式。它有助于保持更新。

如果你想被雇佣,你应该使用 LinkedIn,因为它是招聘人员寻找潜在候选人的主要来源。

Igor Miske 在 Unsplash 上拍摄的照片

如何建立你的网站

一旦你完成了开发和组织内容这一过程中的困难部分,剩下的就很容易了。

由于提供了免费的服务、库和模板,开发一个个人网页从未如此容易。

我会用 Bootstrap 4.0 这是一个开源的前端 web 开发库。它支持响应式和移动优先的网页开发流程,确保我们的网站能够在移动设备上正常运行。

连同 Bootstrap 4.0,我将在我的项目中使用免费版的 字体牛逼 图标库。

不是从头开始处理所有的 HTML/CSS 开发工作,我将修改一个我从这个链接下载的引导模板。

对于托管我的网站,我将使用 谷歌 Firebase ,并带有自定义域名。我在 isimtescil.net注册了我的自定义域名,花了 8 美元。你可以随意使用任何其他的主机和域名服务。

让我们建造它

在本地计算机上创建一个包含所有项目文件的文件夹结构。

****$ mkdir** ds-personal-website
**$ cd** ds-personal-website
**$ mkdir** public**

然后 把自由职业者模板 的源代码下载到你的电脑里,把你的‘public’项目文件夹里的所有文件都复制下来。稍后,Firebase 会在将文件部署到托管服务器时查看公共文件夹,因此将所有文件复制到我们刚刚创建的‘public’文件夹中非常重要。

Github 中的自由职业者免费模板源代码

卡尔·海尔达尔在 Unsplash 上拍摄的照片

修改 HTML 的 Head 部分

作为第一步,我们需要做的是根据我们的需要修改 HTML 元素。让我们在编辑器中打开 'index.html' ,先修改 head 部分。

我修改的是网页的元数据和标题。这些标签向搜索引擎提供关于我们页面内容的数据。

此外,我已经修改了与 root 相关的 href 属性,以便可以在托管环境中访问 CSS & JavaScript 源文件。

我在下面用粗体标出了修改。

****Modifications are noted in bold
../public/Index.html**<head><meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1,   
 shrink-to-fit=no"><meta name="description" content="**Erdem Isbilen - Automotive & 
 Mechanical Engineer,Machine Learning and Data Science Enthusiasts**"><meta name="author" content="**Erdem Isbilen**"><title>**Erdem ISBILEN - My Personal WebPage**</title><!-- Custom fonts for this theme --><link **href="../vendor/fontawesome-free/css/all.min.css"**     
 rel="stylesheet" type="text/css">

 <link href="https://fonts.googleapis.com/css?
 family=Montserrat:400,700" rel="stylesheet" type="text/css"><link href="https://fonts.googleapis.com/css?  
 family=Lato:400,700,400italic,700italic" rel="stylesheet" 
 type="text/css"><!-- Theme CSS -->
 <link **href="../css/freelancer.css"** rel="stylesheet"></head>**

修改 HTML 的导航部分

我在导航部分添加了我的 logo,保持导航部分的其余部分基本不变。多亏了引导库,导航条可以完美地工作,并通过折叠来调整自己以适应不同的屏幕尺寸。

我在导航栏的布局上做了一些小改动,分别添加了作品集、博客、简历和联系我部分。

根据您希望呈现内容的方式,您可以添加任意多个部分。

****Modifications are noted in bold
../public/Index.html**<!-- Navigation -->
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav"><div class="container">**<a class="navbar-brand js-scroll-trigger" href="#page-top">
 <img class="brand-logo" src="/img/eisbilen-logo.svg" alt="">
</a>**<button class="navbar-toggler navbar-toggler-right text-uppercase   
 font-weight-bold bg-primary text-white rounded" type="button" data-
 toggle="collapse" data-target="#navbarResponsive" 
 aria-controls="navbarResponsive" aria-expanded="false"
 aria-label="Toggle navigation">
   <i class="fas fa-bars"></i>
 </button><div class="collapse navbar-collapse" id="navbarResponsive"><ul class="navbar-nav ml-auto">

   <li class="nav-item mx-0 mx-lg-1">
    <a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger"    
    **href="#portfolio">Portfolio**</a>
   </li><li class="nav-item mx-0 mx-lg-1">
    <a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" 
    **href="#blog">Blog**</a>
   </li>

   <li class="nav-item mx-0 mx-lg-1">
    <a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" 
    **href="#resume">Resume**</a>
   </li><li class="nav-item mx-0 mx-lg-1">
    <a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" 
    **href="#connect">Connect Me**</a>
   </li>

 </ul>
</div>
</div>
</nav>**

修改 HTML 的报头部分

在 HTML 的报头部分,我添加了我的照片、名字和头衔。

由于这一部分位于页面折叠的上方,访问者无需滚动就可以看到,所以它是访问者在网站上看到的第一个内容。

为了给人留下良好的第一印象,放上你最好的职业照片,并选择最恰当的词语来描述你。

拥有一张自己的专业照片也将有助于他人信任你和你的企业。

****Modifications are noted in bold
../public/Index.html**<!-- Masthead -->
<header class="masthead bg-primary text-white text-center">
 <div class="container d-flex align-items-center flex-column"><!-- Masthead Avatar Image -->
 **<img class="masthead-avatar mb-5" src="/img/ei-photo-min.png"   
 alt="">**<!-- Masthead Heading -->
 **<h2 class="masthead-heading text-uppercase mb-0">ERDEM ISBILEN</h2>**<!-- Icon Divider -->
 <div class="divider-custom divider-light">
  <div class="divider-custom-line"></div>
   <div class="divider-custom-icon">
    <i class="fas fa-star"></i>
   </div>
  <div class="divider-custom-line"></div>
 </div><!-- Masthead Subheading -->
 **<h8 class="masthead-subheading font-weight-light mb-0">Automotive 
  & Mechanical Engineer</h8>
  <h8 class="masthead-subheading font-weight-light mb-0">Machine 
  Learning and Data Science Enthusiasts</h8>**</div>
</header>**

修改 HTML 的其余部分

以类似的方式修改其余的 HTML 部分,因此您可以根据需要调整它们或包含额外的内容。

博客、简历和投资组合部分是你的网页上应该有的最少部分,以恰当地传达你的数据科学技能和专业。

照片由 imgixUnsplash 上拍摄

设置 Google Firebase

现在,我们已经准备好了所有的项目文件,是时候用免费的“星火计划”来建立托管我们内容的 Firebase 了。

假设你已经有了一个‘谷歌账户’,登录 FireBase 并创建一个新项目。

Firebase —创建新项目

Firebase 仪表板

此时,我们已经准备好使用带有 Firebase CLI 的本地计算机将文件部署到 Firebase。

将您的网站部署到 Firebase

在将我们的网站部署到 Firebase 之前,我们应该在本地计算机上安装 Firebase CLI。

****$** npm install -g firebase-tools**

然后,我们将登录并初始化 Firebase。转到项目文件夹的根目录,使用下面的终端命令登录 Firebase。它会引导你到一个网站,在那里你使用你的“谷歌账户”来授权 Firebase。

****ds-personal-website$** firebase login**

登录后,现在我们可以初始化 Firebase 项目并配置主机细节。

选择‘Hosting’选项,并提供公共目录作为‘public’,所有准备部署的文件都存储在本地计算机中。不要选择覆盖到“index.html”选项,因为这将修改您的“index.html”。

****ds-personal-website$** firebase initYou're about to initialize a Firebase project in this directory:
**/Users/erdemisbilen/Angular/my-personal-webpage**Before we get started, keep in mind:
***** You are initializing in an existing Firebase project directory? **Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices.**Hosting: Configure and deploy Firebase Hosting sites**=== Project Setup** First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running **firebase use --add**, but for now we'll just set up a default project.**i ** .firebaserc already has a default project, using my-personal-webpage-c7096.**=== Hosting Setup** Your **public** directory is the folder (relative to your project directory) that will contain Hosting assets to be uploaded with **firebase deploy**. If you have a build process for your assets, use your build's output directory.? **What do you want to use as your public directory?** public
? **Configure as a single-page app(rewrite all urls to /index.html)?**No
? **File public/404.html already exists. Overwrite?** Yes
**✔ ** Wrote **public/404.html**? **File public/index.html already exists. Overwrite?** No
**i ** Skipping write of **public/index.html
i ** Writing configuration info to **firebase.json**...
**i ** Writing project information to **.firebaserc**...**✔ ** Firebase initialization complete!**

现在您已经登录并初始化了 Firebase,您可以用一行命令部署所有文件。

如果你成功地完成了正确的设置,Firebase 将部署你所有的文件,并给你一个网址,你可以在你的浏览器上看到你的网站。

****ds-personal-website$** firebase deploy**=== Deploying to 'my-personal-webpage-c7096'...****i ** deploying **hosting
i  hosting[my-personal-webpage-c7096]:** beginning deploy...
**i  hosting[my-personal-webpage-c7096]:** found 91 files in **public
✔  hosting[my-personal-webpage-c7096]:** file upload complete
**i  hosting[my-personal-webpage-c7096]:** finalizing version...
**✔  hosting[my-personal-webpage-c7096]:** version finalized
**i  hosting[my-personal-webpage-c7096]:** releasing new version...
**✔  hosting[my-personal-webpage-c7096]:** release complete**✔ ** **Deploy complete!****Project Console:** [https://console.firebase.google.com/project/my-personal-webpage-c7096/overview](https://console.firebase.google.com/project/my-personal-webpage-c7096/overview)**Hosting URL:** [https://my-personal-webpage-c7096.firebaseapp.com](https://my-personal-webpage-c7096.firebaseapp.com)**

在 Firebase 中配置您的自定义域名

你不能使用 Firebase 提供的 URL,因为它是让你试验你的设计并在浏览器上看到它的东西。

当你对你的网站在浏览器上的外观感到满意后,还有最后一步用自定义域名使你的网站独一无二。

有几个提供商可以让你注册一个特定的域名。对我来说,它是【www.erdemisbilen.com】,我在【isimtescil.net】注册了这个域名,每年花费 8 美元。

您可以向您选择的任何 DNS 服务提供商注册您的域名。

注册了唯一的域名后,进入 Firebase Dashboard——托管部分,Firebase 会要求您添加自定义域名。

向 Firebase 提供自定义域名后,您将获得一个 TXT 文件。使用您的 DNS 提供商的仪表板,用 Firebase 提供的记录替换您的域名的 TXT 记录。

一旦完成,Firebase 将要求您修改“A”记录。因此,相应地修改 A 记录。

几个小时后,您会看到 Firebase 连接到您的自定义域。

也就是说,所有的工作都完成了,你的网站开始运行了!

Firebase 自定义域名配置

摘要

在这篇文章中,我试图解释我为自学成才的数据科学家建立个人网站的方式。

我希望我的文章能帮助你建立自己的网站,展示你的数据科学技能。

自然语言理解的自我训练

原文:https://towardsdatascience.com/self-training-for-natural-language-understanding-d5c369b5a7f6?source=collection_archive---------24-----------------------

这篇文章将解释自然语言处理中令人兴奋的发展。提出了一种半监督学习算法,该算法通过自训练显著提高了 RoBERTa 的性能。如果你喜欢这篇论文的视频解释,请看看这个!

迁移学习在深度学习方面取得了极大的成功。这描述了用从另一个任务学习的权重初始化深度神经网络。在计算机视觉中,这另一项任务通常是 ImageNet 监督学习。在自然语言处理中,另一项任务通常是使用互联网规模的语料库进行自我监督的语言建模。

迁移学习的成功激发了深度学习研究人员探索更多用于预训练的任务。一个有希望的替代任务是自我训练。自训练是知识蒸馏的逆过程,它被开发来压缩大型深度神经网络。

自我训练和知识蒸馏描述了使用一个神经网络来标记另一个神经网络的训练数据。知识蒸馏用较大网络标注较小网络的数据,自练用较小网络标注较大网络的数据。这可以循环渐进增长或收缩的几个步骤。

自我训练在嘈杂学生的框架内实现了图像网络分类的最先进水平[1]。在其他组成部分中,吵闹的学生在半监督学习的环境中实现自我训练。Zoph 等人[2]表明,在从分类到对象检测和语义分割的一些计算机视觉问题上,自训练优于使用 ImageNet 监督学习的预训练。如果感兴趣,下面的视频解释了这项研究,它与我们在本文中讨论的论文极其相似:

半监督学习描述了这样一种环境,其中我们有少量的已标记数据和大量(通常是绝对大量的)未标记数据。表征学习的许多最新进展,如 SimCLRv2 [3],就是以这种方式工作的。这似乎适用于大多数深度学习问题,如图像分类、问题回答,甚至是蛋白质结构建模等应用,其中有一小组实验验证的 3D 结构和一大组在自然界中发现的验证的氨基酸序列。

本文讨论了在半监督学习环境下,应用于自然语言理解的自我训练。

使半监督学习工作良好的一个核心因素是未标记的数据至少与标记的数据在同一域内。这是什么意思?对于下游的 NER 生物医学任务,没有标签的生物医学论文比流行文化新闻文章要好。Gururangan 等人[4]在“不要停止预训练”中用更多相关领域的顺序语言建模证明了这一点。例如,在为文章主题分类装配标签之前,从普通爬行到用于语言建模的新闻文章。下面的视频解释了那篇论文,如果感兴趣的话:

作者提出了 SentAugment 来过滤基于最域内和相关子集的未标记数据。该算法通过训练语义文本相似性模型来工作,该模型将整个未标记集(例如来自常见爬行的 50 亿个句子)嵌入到向量空间中。这些向量空间被称为“大规模句子嵌入空间”。

使用相同的编码模型将整个标记数据集嵌入到单个矢量表示中。这是通过对每个标记句子的向量进行平均、基于下游标签进行平均或者对标记集合中的每个句子使用单独的查询来完成的。查询向量用于在未标记的文档索引中查找最近的邻居。像 FAISS [5]这样的库加速了这个过程。

所以总而言之,算法是这样工作的:

  • 语义相似度模型被训练并嵌入未标记集合中的每个句子。该模型还形成了标记集的嵌入,以用作检索查询。
  • 教师模型最初是在小标签集上用监督学习来训练的。该教师模型然后伪标记来自检索的前 K 个最相似的文档。
  • 学生模型在老师的这些伪标签上训练。
  • 你可以根据需要切换学生和老师,通常每一步都增加学生的规模(在自我训练的情况下,注意知识升华与此相反)。

本文探讨的完整管道的可视化

作者使用常见的爬行语料库和一些范围从大约 5k 到 65k 的标记示例的文本分类数据集进行实验。文档和查询编码器用由释义和平行句子数据集组成的数据集上的三元组损失来训练。

表 2 显示了来自预训练的 RoBERTa 大模型的自我训练的收益。请注意,持续的语言建模(ICP)会损害性能,可能会过度适应自我监督的学习任务。还要注意的是,SST-2 比其他数据集拥有更多的数据,而其他数据集的增益要大得多。

表 4 显示了 SentAugment 的优势。顶行突出显示了 RoBERTa Large 的表现明显优于 RoBERTa small。中间一行(GT)显示了使用标记数据集从大到小的知识提取的成功。在中间一行中,(RD)指的是从未标记和标记的组中随机取样进行蒸馏。在中间一行中,(SA)显示 SentAugment 几乎恢复了单独使用最近邻检索的蒸馏的地面真实性能。底部一行显示了使用额外的未标记数据的好处(比如 100K 对 5k,与中间一行进行比较)。与随机选择未标记的句子进行提取相比,这显示了检索过滤的巨大优势。

表 3 显示了少量学习的结果。这描述了使用极小的标记集,例如在情感分类中的正面和负面类别中的每个类别中有 20 个例子。与最近的结果相比,如 GPT-3,或更实际的模式探索训练,这是一个有希望的结果,解释如下:

作者进一步研究了构造 SentAugment 算法的不同方法。值得注意的是,他们探索了使用 word2vec 嵌入与使用串联文本相似性语料库训练的 Transformer 嵌入之间的差异。他们还研究了为监督学习集构建查询的不同方法。如果您有兴趣学习更多关于检索模型的知识,我强烈推荐您查看检索增强生成模型。如果你感兴趣,这里有一个解释这一点的视频:

作者还包括这个检索系统的不同查询的最近邻居的可视化,如下所示。我很喜欢用“大规模句子嵌入空格”这个术语来描述这项研究。

我一直认为知识提炼是成功的,因为老师利用其较大的模型尺寸为较小的学生制作了更详细的标签。自我训练的成功表明不仅仅是这样。我怀疑这种转移与优化格局有关。感谢您的阅读!

参考

[1]与吵闹的学生一起进行自我训练可提高 ImageNet 分类。谢启哲,Minh-Thang Luong,Eduard Hovy,郭诉乐。https://arxiv.org/abs/1911.04252

[2]反思职前培养和自我培养。Barret Zoph、Golnaz Ghiasi、宗、尹翠、刘韩啸、Ekin Cubuk、Quoc V. Le。https://arxiv.org/pdf/2006.06882.pdf

[3]大的自我监督模型是强的半监督学习器。陈婷,西蒙·科恩布鲁斯,凯文·斯维斯基,穆罕默德·诺鲁齐,杰弗里·辛顿。https://arxiv.org/abs/2006.10029

[4]不要停止预训练:使语言模型适应领域和任务。Suchin Gururangan,Ana Marasovic,Swabha Swayamdipta,Kyle Lo,Iz Beltagy,Doug Downey,Noah A. Smith。【https://arxiv.org/pdf/2004.10964.pdf

[5] Faiss:一个用于高效相似性搜索的库。埃尔韦·杰古,马特吉斯·杜泽,杰夫·约翰逊。https://engineering . FB . com/data-infra structure/faiss-a-library-for-efficient-similarity-search/

自我训练提高自然语言理解的预训练:https://arxiv.org/pdf/2010.02194.pdf

感谢阅读,如果你喜欢深度学习论文的摘要,请在 YouTube 上查看 Henry AI Labs!

基于全卷积网络的语义图像分割

原文:https://towardsdatascience.com/semantic-image-segmentation-using-fully-convolutional-networks-bf0189fa3eb8?source=collection_archive---------10-----------------------

语义分割/扩展卷积

Severstal 钢缺陷检测——案例研究

人类有一种与生俱来的能力,能够识别他们在周围世界看到的物体。我们大脑中的视觉皮层几乎可以在短时间内毫不费力地区分猫和狗。这不仅适用于猫和狗,也适用于我们看到的几乎所有物体。但是计算机没有人脑聪明,无法自己做到这一点。在过去的几十年里,深度学习研究人员试图通过一种特殊类型的人工神经网络(称为卷积神经网络(CNN))来弥合人脑和计算机之间的这种差距。

什么是卷积神经网络?

在对哺乳动物大脑进行了大量研究后,研究人员发现,大脑的特定部分在特定类型的刺激下会被激活。例如,当我们看到垂直边缘时,视觉皮层的一些部分被激活,当我们看到水平边缘时,一些部分被激活,当我们看到特定的形状、颜色、脸等时,一些部分被激活。ML 的研究人员将这些部分想象成神经网络的一层,并考虑了这种层的大型网络可以模仿人脑的想法。
这种直觉导致了 CNN 的出现,这是一种神经网络,其构建块是卷积层。卷积层只不过是一组称为核或滤波器的权重矩阵,用于对诸如图像的特征矩阵进行卷积运算。

卷积: 2D 卷积是一个相当简单的操作,你从一个内核开始,然后“跨越”(滑动)2D 输入数据,与它当前所在的输入部分执行逐元素乘法,然后将结果相加到单个输出单元中。内核对它滑过的每个位置重复这个过程,将 2D 特征矩阵转换成另一个 2D 特征矩阵。
内核在输入特征矩阵上滑动的步长称为 步距 。在下面的动画中,输入矩阵的四边都添加了额外的零条纹,以确保输出矩阵的大小与输入矩阵的大小相同。这称为(零)填充。

2D 卷积 : 内核大小=3x3,填充=1 或‘相同’,步幅= 1【GIF 来源: pyimagesearch

语义图像分割

图像分割是基于一些特征将数字图像分割成多个片段(像素组)的任务。目标是将图像简化或改变成更有意义和更容易分析的表示。
语义分割是指给定图像中的每个像素分配一个类别标签。参见下面的例子。

图片来源:马丁托马/ CC0

请注意,分段不同于分类。在分类中,完整的图像被分配一个类别标签,而在分割中,图像中的每个像素被分类到一个类别中。

1.商业问题

对卷积网络和语义图像分割有了一个公平的想法,让我们进入我们需要解决的问题。

****

图片来源: Kaggle

俄罗斯北方钢铁公司是世界 50 大钢铁生产商之一,也是俄罗斯高效钢铁开采和生产的最大参与者。谢韦尔钢铁公司的主要产品之一是钢板。平板钢板的生产工艺精细。从加热和轧制,到干燥和切割,当扁钢准备装运时,几台机器会接触到它。为了确保钢板生产的质量,今天,谢韦尔钢铁公司使用高频摄像机的图像来驱动缺陷检测算法。
通过这次比赛,Severstal 希望人工智能社区能够通过
定位和分类钢板上的表面缺陷来改进算法。

业务目标和约束

  1. 有缺陷的纸张必须被预测为有缺陷的,因为如果我们将有缺陷的纸张错误地分类为无缺陷的,将会有严重的质量问题。即每个类别都需要高召回值。
  2. 我们不需要一眨眼就给出给定图像的结果。(没有严格的延迟问题)

2.机器学习问题

2.1.将业务问题映射到 ML 问题

我们的任务是

  1. 使用图像分割检测/定位钢板中的缺陷
  2. 将检测到的缺陷分成[1,2,3,4]中的一个或多个类别

放在一起就是一个语义图像分割问题。

2.2.绩效指标

使用的评估指标是平均 Dice 系数。Dice 系数可用于比较预测的分割与其对应的基本事实之间的逐像素一致性。该公式由下式给出:

其中 X 是预测的像素组,Y 是地面实况。
在这里阅读更多关于骰子系数的内容

2.3.数据概述

我们收到了一个 2GB 大小的 zip 文件夹,其中包含以下内容:

  • **train_images**—包含 12,568 张训练图像的文件夹(。jpg 文件)
  • **test_images** —包含 5506 个测试图像的文件夹(。jpg 文件)。我们需要检测和定位这些图像中的缺陷
  • **train.csv** —为属于 ClassId = [1,2,3,4]的缺陷提供分段的训练注释
  • **sample_submission.csv** —正确格式的样本提交文件,每个 ImageId 重复 4 次,4 个缺陷类别各一次。

关于数据的更多细节将在下一节讨论。

3.探索性数据分析

解决任何机器学习问题的第一步应该是彻底研究原始数据。这为我们解决问题的方法提供了一个合理的思路。通常,它还能帮助我们发现数据的一些潜在方面,这些方面可能对我们的模型有用。让我们分析这些数据,试着得出一些有意义的结论。

3.1.正在加载 train.csv 文件

train.csv 告知图像中哪个像素位置存在哪种类型的缺陷。它包含以下列:

  • **ImageId**:图像文件名。jpg 扩展
  • **ClassId**:缺陷的类型/等级,为【1、2、3、4】中的一种
  • **EncodedPixels**:以游程编码像素的形式表示图像中缺陷像素的范围(缺陷开始的像素数<空格>缺陷的像素长度)。
    例如“29102 12”表示缺陷从像素 29102 开始,总共有 12 个像素,即像素 29102、29103、………、29113 有缺陷。像素从上到下,然后从左到右进行编号:1 对应于像素(1,1),2 对应于(2,1),依此类推。
**train_df.ImageId.describe()**count              7095
unique             6666
top       ef24da2ba.jpg
freq                  3
Name: ImageId, dtype: object
  • 有 7095 个数据点对应于包含缺陷的 6666 张钢板图像。

3.2.分析 train_images 和 test_images 文件夹

训练和测试图像的数量 让我们了解一下训练和测试图像的比例,并检查有多少训练图像包含缺陷。

Number of train images :  12568
Number of test images :  5506
Number of non-defective images in the train_images folder: 5902
  • train_images 文件夹中的图像比 train.csv 中的唯一图像 id 还多。这意味着,并非 train_images 文件夹中的所有图像都具有缺陷 1、2、3、4 中的至少一个。

列车数据中有缺陷和无缺陷图像的百分比

训练图像和测试图像的尺寸 让我们检查一下训练图像和测试图像的尺寸是否相同。如果没有,我们必须使它们大小相同。

{(256, 1600, 3)}
{(256, 1600, 3)}
  • 训练和测试文件夹中的所有图像大小相同(256×1600×3)

3.3.标签分析:ClassId

让我们看看训练数据是如何分布在各个类中的。

Number of images in class 1 : **5150 (77.258 %)**
Number of images in class 2 : **897 (13.456 %)**
Number of images in class 3 : **801 (12.016 %)**
Number of images in class 4 : **247 (3.705 %)**
  • 数据集看起来不平衡。
  • 与其他类别的图像相比,具有类别 3 缺陷的图像的数量非常高。77%的缺陷图像具有 3 级缺陷。
  • 类别 2 是最少出现的类别,train.csv 中只有 3.7 %的图像属于类别 2。

注意,上述分析中的百分比值之和大于 100,这意味着一些图像具有属于一个以上类别的缺陷。

每幅图像标记的标签数量

Number of images having 1 class label(s): **6239 (93.594%)**
Number of images having 2 class label(s): **425 (6.376%)**
Number of images having 3 class label(s): **2 (0.03%)**
  • 大多数图像(93.6%)只有一类缺陷。
  • 只有 2 个图像(0.03%)具有 3 类缺陷的组合。
  • 其余的图像(6.37%)具有两类缺陷的组合。
  • 没有图像具有所有 4 类缺陷。

4.数据准备

在我们继续训练深度学习模型之前,我们需要将原始数据转换为可以输入模型的形式。此外,我们需要构建一个数据管道,它将执行所需的预处理,并为训练生成成批的输入和输出图像。

作为第一步,我们创建一个 pandas dataframe,包含列**ImageId**下的列车图像的文件名,以及一个或多个列**Defect_1****Defect_2, Defect_3, Defect_4** 下的 编码像素,这取决于 train.csv 中图像的ClassId没有任何缺陷的图像将这 4 列全部留空。以下是数据帧的示例:****

4.1.列车,CV 分流 85:15

我会在 85%的训练图像上训练我的模型,并在 15%上验证。

(10682, 5)
(1886, 5)

4.2.用于将 RLE 编码像素转换为遮罩的实用函数,反之亦然

让我们想象一下每个班级的一些图片和他们的面具。钢板图像中属于缺陷区域的像素在掩模图像中用黄色表示。

****

我们的深度学习模型将钢板图像作为输入(X)并返回四个掩码(Y)(对应于 4 个类别)作为输出。这意味着,为了训练我们的模型,我们需要将成批的训练图像和它们相应的掩码输入到模型中。
我已经为 train_images 文件夹中的所有图像生成了遮罩,并将它们存储在名为 train_masks 的文件夹中。

4.3.使用 tensorflow.data 的数据生成器

以下代码是数据管道,用于对输入图像应用预处理、增强,并生成用于训练的批次。

4.4.定义度量和损失函数

我使用了一个混合损失函数,它是由【BCE】骰子损失 组合而成的。BCE 对应于每个像素的二进制分类(当与地面真实掩模比较时,0 表示该像素处缺陷的错误预测,1 表示正确预测)。骰子损失由(1 骰子系数)给出。
BCE 骰子损失= BCE +骰子损失

5.模型

有几种用于语义图像分割的模型/架构。在这个案例研究中,我尝试了其中的两个:i)U-Net 和 ii) Google 的 DeepLabV3+。

5.1。第一个切割解决方案:用于语义图像分割的 U-Net

这个模型是基于德国弗赖堡大学*的 Olaf RonnebergerPhilipp FischerThomas Brox 于 2015 年发表的研究论文 U-Net:卷积网络用于生物医学图像分割 。在本文中,作者构建了一个优雅的架构,称为“全卷积网络”。他们已经将此用于电子显微镜堆栈和少数其他生物医学图像分割数据集中的神经元结构的分割。*

5.1.1。架构
网络的架构如下图所示。它由收缩路径(左侧)和扩张路径(右侧)组成。扩展路径与收缩路径对称,使得网络的形状类似于英文字母“U”。由于这个原因,这个网络被称为 U-Net。

U-net 架构(以最低分辨率的 32x32 像素为例)。每个蓝框对应一个多通道特征图。盒子的顶部标明了频道的数量。x-y 尺寸位于框的左下边缘。白色方框表示复制的要素地图。箭头表示不同的操作。[图片来源:弗赖堡大学 ]

收缩路径遵循卷积网络的典型架构。它由两个 3×3 卷积(无填充卷积)的重复应用组成,每个卷积后跟一个整流线性单元(ReLU)和一个跨距为 2 的 2×2 最大池操作,用于下采样。在每个下采样步骤中,特征通道的数量会翻倍。在此路径中,模型从图像中捕获重要的特征(类似于钢板中的缺陷)并丢弃不重要的特征,从而降低图像在每个卷积+最大池层的分辨率。
在扩展路径中,每一步都包括特征图的上采样,随后是将特征通道的数量减半的 2x2 卷积(
上卷积)、与来自收缩路径的相应裁剪的特征图的连接,以及两个 3x3 卷积,每个卷积之后是 ReLU。由于每次卷积都会丢失边界像素,因此裁剪是必要的。在最后一层,使用 1x1 卷积将每个 64 分量的特征向量映射到所需的类别数(在我们的例子中为 4)。
为了精确定位,来自收缩路径的高分辨率特征被裁剪并与上采样输出相结合,并被馈送到后续卷积层,该卷积层将学习组装更精确的输出。

  • 不是在第一层中使用 64 个滤波器,而是仅使用 8 个滤波器(后续层中的滤波器数量也相应改变)。这导致较不复杂的模型,与具有 64 个过滤器的模型相比,训练更快。
  • 钢板图像的原始尺寸为 256x1600。大尺寸图像包含更多像素,因此需要更多卷积、池化等计算。由于计算资源的限制,我已经将图像的大小调整到一半(128x800)。
  • 我在每个卷积块后添加了一个小的 dropout = 0.2,以避免模型过度拟合。

U-Net 模型的代码可以在我的 GitHub 库中找到。

5.1.2。训练
我已经使用 Keras Adam optimizer 以 50 个时期的默认学习速率训练了模型。优化器试图最小化的损失函数是 bce_dice_loss ,在前面的第 4.4 节中定义。

随着培训的进行,我已经使用 Keras 模型检查点来监控验证骰子系数,并保存具有最佳验证骰子系数分数的模型。TensorBoard 已被用于在训练时动态绘制损失和得分。

5.1.3。训练图

****

5.1.4。测试

由于 Kaggle 要求我们提交原始大小的预测,而不是一半大小的图像,我用输入大小= (256,1600,3)重建了模型,并加载了在 128×800 图像上训练的模型的权重。我这么做是因为 CNN 对于不同的输入大小是相当稳定的。

  • 当我在 Kaggle 上上传这个模型的预测时,Dice 系数得分相当不错。我在私人排行榜得到了 0.80943 的分数,在公共排行榜得到了 0.81369 的分数。

5.2.最终解决方案:DeepLab V3+

DeepLab 是谷歌在 2016 年设计并开源的最先进的语义分割模型。从那以后,对该模型进行了多次改进,包括 DeepLab V2、DeepLab V3 和最新的 DeepLab V3+。
DeepLab V3+基于 Google 于 2018 年发表的论文采用阿特鲁可分离卷积进行语义图像分割的编解码器

5.2.1。架构 与前面讨论的 U-Net 类似,DeepLab V3+也是一种编解码架构。主要区别在于它使用阿特鲁卷积而不是简单卷积。在这一节的后面,我们将了解更多关于阿特鲁卷积的知识。

****

****DeepLab V3+架构【图片来源:原创研究论文

编码器模块通过在多个尺度上应用复杂的卷积来编码多尺度上下文信息,而简单的 effective 解码器模块沿着对象边界重新定义分割结果。

阿特鲁卷积
在二维信号的情况下,对于输出特征图 y 上的每个位置 i 和卷积滤波器 w ,如下所示对输入特征图
×
应用 atrous 卷积:**

其中, r 决定了我们对输入信号进行采样的步距。注意,标准卷积是速率 r = 1 的特例。通过改变膨胀/收缩率值,滤波器的视野得到自适应修改。

****标准卷积(左)vs 扩张或阿特鲁卷积(右)【GIF 来源: Sik-Ho Tsang 经由走向数据科学

图片来源: ResearchGate/CC

深度方向可分离卷积 深度方向可分离卷积通过将标准卷积分成两个子部分
i .深度方向卷积
ii,大大降低了计算复杂度。逐点卷积。

第一部分是深度方向卷积,为每个输入通道独立执行空间卷积。其后是逐点卷积(即 1×1 卷积),用于合并深度卷积的输出。

让我们借助一个例子来理解这一点。假设我们有一个由 3 个通道组成的 12×12 的图像。我们希望对该输入应用 5×5 的卷积,得到 8×8×256 的输出。

在第一部分,深度方向卷积,我们给输入图像一个不改变深度的卷积。我们通过使用 3 个形状为 5×5×1 的核来实现。

****第一部分:深度卷积【图片来源:齐-汪锋经由走向数据科学

逐点卷积之所以如此命名,是因为它使用 1×1 核或遍历每个单点的核。无论输入图像有多少通道,该内核都具有深度;在我们这里是 3 个。因此,我们通过我们的 8×8×3 图像迭代 1×1×3 核,得到 8×8×1 图像。

****第二部分:逐点卷积【图片来源:齐-汪锋经由走向数据科学

为了获得 8×8×256 的输出图像,我们需要简单地将 1×1×3 核的数量增加到 256。

编码器架构 DeepLab V3+编码器使用 例外架构 进行以下修改—

  • 我们在中间流程中添加更多的层
  • 所有的最大池操作都被具有步长的深度可分卷积所取代
  • 在每个 3×3 深度方向卷积之后,添加额外的批标准化和 ReLU。

编码器的输出是比输入特征图小 16 倍的特征图。这由解码器进行补偿,该解码器将编码器特征图上采样 4 倍两次(参考模型架构图)。

****DeepLab V3+编码器架构【图片来源:原创研究论文

5.2.2。训练 我已经使用 Keras Adam optimizer 以 47 个时期的默认学习率训练了模型。优化器试图最小化的损失函数是 bce_dice_loss ,在前面的第 4.4 节中定义

与 U-Net 的情况一样,我保存了具有最佳验证 dice_coefficient 的模型的权重。

5.2.3。训练图

请注意,模型在第 37 个时期后开始过度拟合,验证分数没有进一步提高。因此,我使用了保存在第 37 纪元的模型权重。

5.2.4。测试 下图显示了来自验证数据的一些样本图像,以及它们的基本事实遮罩和预测遮罩。

****

在这种情况下,使用原始输入大小(256,1600,3)重建模型并加载按一半大小训练的模型的权重效果不佳。我不得不使用不同的策略——我使用训练好的模型在 128×800 的图像上进行预测,并将预测的遮罩大小调整为 256×1600。这种方法在 DeepLab V3+上运行得非常好。

结果比较和最终提交

我最后提交的是 DeepLab V3+,无论是私信还是公信都给了一个像样的分数。

现有方法和改进

这个 Kaggle 比赛很受欢迎,许多人用不同的方法解决了这个问题。然而,他们中的大多数都使用了 U-Net 的某种变体或类似的编码器-解码器架构。

我使用 simple U-Net 作为我的第一个 cut 解决方案,它在测试数据上给出了不错的性能,这要归功于半尺寸上的训练和全尺寸策略上的预测。

我已经实现了 DeepLab V3+,这是一种从零开始的语义图像分割技术。帮我把分数从 0.809 提高到 0.838。

未来的工作

  • 一些超参数调整可以用 U-Net 来完成。
  • 可以尝试其他图像分割架构,如 U-Net++、SegNet 和 Mask R-CNN。
  • 可以利用在大数据集上训练的各种骨干的迁移学习的思想。

结论

谢谢你看了这么长的博客,感谢你的耐心。我非常喜欢写它,希望你也喜欢读它。

我跳过了大部分代码,因为我不想用代码淹没读者。请参考我的 GitHub 库获取完整的 Keras 代码。

如果您有任何疑问、建议或讨论,请随时在下面的评论区提出。我将尽我所知努力解决这些问题。
你可以在 LinkedIn 上联系我,这是我的简介

参考

  1. https://www.kaggle.com/c/severstal-steel-defect-detection/
  2. https://arxiv.org/abs/1505.04597v1
  3. https://arxiv.org/abs/1802.02611v3
  4. https://www . analyticsvidhya . com/blog/2019/02/tutorial-semantic-segmentation-Google-deep lab/
  5. https://arxiv.org/abs/1610.02357
  6. https://github . com/MLearing/Keras-deep lab-v3-plus/blob/master/model . py
  7. https://www.appliedaicourse.com/

用 5 行代码对 150 类对象进行语义分割

原文:https://towardsdatascience.com/semantic-segmentation-of-150-classes-of-objects-with-5-lines-of-code-7f244fa96b6c?source=collection_archive---------16-----------------------

用 PixelLib 对 150 类对象进行语义分割

现在可以使用带有 PixelLib 的 ade20k 模型对 150 类对象进行分割。Ade20k 模型是在 ade20k 数据集上训练的 deeplabv3+模型,ade 20k 数据集有 150 个对象类。感谢tensorflow deep lab 的模型动物园,我从它的 tensor flow 模型检查点提取了 ade20k 模型。

安装最新版本的 tensorflow (tensorflow 2.0)和:

  • pip3 安装张量流

安装 Pixellib:

  • pip3 安装 pixellib —升级

用 PixelLib 实现语义分割:

用 deeplabv3+模型实现语义切分的代码在 ade20k 数据集上进行训练。

我们将观察每一行代码:

import pixellib
from pixellib.semantic import semantic_segmentation segment_image = semantic_segmentation()

执行语义分割的类是从 pixelLib 导入的,我们创建了该类的一个实例。

segment_image.load_ade20k_model(“deeplabv3_xception65_ade20k.h5”)

在上面的代码中,我们加载了在 ade20k 上训练的用于分割对象的 xception 模型。模型可以从这里下载。

segment_image.segmentAsAde20k(“path_to_image”, output_image_name = “path_to_output_image)

我们加载了该函数来对图像执行分割。该函数有两个参数…

  • 路径至图像:- 这是待分割图像的路径。
  • 输出图像名称:- 这是保存分割图像的路径。它将保存在您当前的工作目录中。

Sample.jpg

来源:W ikicommons (CC0)作者 Acabashi

注: 使用 Ade20k 模型,可以用 PixelLib 对室内和室外场景进行语义分割。

输出图像

室外场景的语义分割

分割后保存的图像,图像中的物体被分割。如果您愿意,可以在图像上应用分段覆盖。

segment_image.segmentAsAde20k("sample.jpg", output_image_name = "image_new.jpg", overlay = True)

我们添加了额外的参数叠加,并将其设置为,我们获得了一个对象上带有分割叠加的图像。

Sample2.jpg

来源:W ikicommons 。由卡伦·马尔达尔

segment_image.segmentAsAde20k(“sample2.jpg”, output_image_name = “image_new2.jpg")

输出图像

室内场景的语义分割

PixelLib 的特殊用途可能需要您返回分段输出的数组:

使用代码获得分段输出的数组

segmap, output = segment_image.segmentAsAde20k()

您可以测试获取数组的代码,并通过修改下面的语义分段代码打印出输出的形状。

  • 使用以下代码获得 segmap 和分段覆盖图的数组,
segmap, seg_overlay = segment_image.segmentAsAde20k(overlay = True)

基于 ADE20K 模型的视频分割

我们将在下面解释每一行代码。

import pixellibfrom pixellib.semantic import semantic_segmentationsegment_video = semantic_segmentation()

我们导入了用于执行语义分段的类,并创建了该类的一个实例。

segment_video.load_ade20k_model("deeplabv3_xception65_ade20k.h5")

我们加载了在 ade20k 数据集上训练的 xception 模型来执行语义分割,它可以从这里下载。

segment_video.process_video_ade20k("video_path",  overlay = True, frames_per_second= 15, output_video_name="path_to_output_video")

我们调用函数对视频文件进行分割。

它采用以下参数:-

  • video_path :这是我们要分割的视频文件的路径。
  • 每秒帧数:该参数用于设置保存的视频文件每秒帧数。在这种情况下,它被设置为 15,即保存的视频文件每秒将有 15 帧。
  • 输出 _ 视频 _ 名称:这是保存的分段视频的名称。输出的视频将保存在您当前的工作目录中。

样本 _ 视频

输出视频

这是使用 ade20k 模型保存的分段视频。

现场摄像机的语义分割。

我们可以使用相同的模型在相机上执行语义分割。这可以通过对用于处理视频文件的代码进行少量修改来实现。

import cv2capture = cv2.VideoCapture(0)

我们导入了 cv2 并包含了捕捉相机帧的代码。

segment_video.process_camera_ade20k(capture,  overlay = True, frames_per_second= 15, output_video_name="output_video.mp4", show_frames= True,frame_name= "frame")

在执行分割的代码中,我们将视频的文件路径替换为捕获,即我们正在处理摄像机捕获的帧流,而不是视频文件。为了显示摄像机画面,我们添加了额外的参数:

  • 显示帧:该参数处理分段摄像机帧的显示,按 q 退出帧的显示。
  • 帧名:这是显示的摄像机帧的名称。

展示 pixelLib 使用 ade20k 模型对摄像机输入进行语义分割的输出的演示。

干得好!它成功地把我分段了。

访问 PixelLib 的官方 GitHub 库。

访问 PixelLib 的官方文档

通过以下方式联系我:

电子邮件:olafenwaayoola@gmail.com

推特: @AyoolaOlafenwa

脸书:阿尤拉·奥拉芬娃

Linkedin: 阿尤拉·奥拉芬娃

如果您喜欢这篇文章,您会喜欢阅读关于 PixelLib 的其他文章:

用 5 行代码实现图像分割

[## 用 5 行代码实现图像分割

用 PixelLib 进行语义和实例分割。

towardsdatascience.com](/image-segmentation-with-six-lines-0f-code-acb870a462e8)

用 5 行代码实现视频分割

[## 用 5 行代码实现视频分割

视频的语义和实例分割。

towardsdatascience.com](/video-segmentation-with-5-lines-of-code-87f798afb93)

使用 Django API——DeepLabV3 进行语义分割

原文:https://towardsdatascience.com/semantic-segmentation-using-a-django-api-deeplabv3-7b7904ddfed9?source=collection_archive---------53-----------------------

构建一个 Django API,使用语义分段执行后台定制

Sole D'Alessandro G. 在 Unsplash 上拍摄的原始照片

介绍

图像分割一直是热门话题。涉及分割的各种用例出现在许多不同的领域,机器视觉、医学成像、物体检测、识别任务、交通控制系统、视频监控等等。这些智能系统背后的直觉是捕捉形成图像的各种组件,从而教会计算机视觉模型掌握更多洞察力,更好地理解场景和背景。

左边是 Melody JacobUnsplash 上的原图,右边是分段版

常用的两种图像分割类型是:

  • 语义分割:识别图像中的不同类别,并相应地分割
  • 实例分割:预先确定图像中的不同类别,识别每个类别包含的实例数量。图像被分解成与模型被训练的不同类实例相关的多个标记区域。

在本文中,我将使用 Google DeepLab V3 分割模型的 Pytorch 实现来自定义图像的背景。其目的是分割前景,并将其与其余部分分离,同时用一幅完全不同的图片替换剩余的背景。该模型将通过 Django REST API 提供服务。

概观

  1. DeepLab V3 的一点背景知识
  2. 使用 Pytorch 的 DeepLab V3-Resnet101 实现
  3. 设置 Django API
  4. 结论

你可以在我的 Gihut repo 下查看这个项目的全部代码。

[## aymanehachham/背景-定制

在 GitHub 上创建一个帐户,为 aymanehachham/后台定制开发做贡献。

github.com](https://github.com/aymanehachcham/Background-Customization)

1.DeepLab V3 的一点背景知识

分割模型使用完全卷积神经网络 FCNN 在之前的图像检测阶段,将遮罩和边界放置到位,然后通过深度极大的网络处理输入,在该网络中,累积的卷积和汇集会导致图像的分辨率和质量显著降低,因此产生的结果会损失大量信息。DeepLab 模型利用阿特鲁卷积和阿特鲁空间金字塔池(ASPP)架构解决了这一挑战。

不同分割模型之间的差异和比较,鸣谢:Francisco Massa, Torchvision 0.3:分割、检测模型、新数据集等

在 DeepLab 架构的正向流程中涉及四个主要阶段:

  • 用主干模型提取图像特征。我们案例中使用的主干是 Resnet 101 对象检测模型,作为第一个卷积管道来捕捉和屏蔽重要的特征图。
  • 为了控制输出特征图的大小,在主干的最后几层中使用阿特鲁卷积。
  • 在最后阶段,ASPP 架构对输出图像的不同像素进行分类,并通过 1 x 1 卷积层进行处理,以恢复其原始大小。

具有 atrous 卷积(ASPP)的并行模块,增强了图像级特征,信用: 重新思考用于语义图像分割的阿特鲁卷积

2.使用 Pytorch 的 DeepLab V3-Resnet101 实现

让我们通过创建一个包装原始 DeepLab V3 模型的 Pytorch 模块来开始这个过程。最初,Pytorch 团队已经提出了他们在 COCO 数据集上预先训练的 Google DeepLab V3 架构的实现,以及可供选择的各种主干。对于我们的特定任务,我们将使用可从torchvision.models.segmentation API 包轻松加载的 deeplabv3-resnet101 预训练模块。

创建您的 python 虚拟环境

使用pip virtualenv设置您的 python 虚拟环境,并安装所有需要的包:

。指定 python 虚拟环境的路径:

virtualenv absolute/path/to/virtual/env/pytorch-en

二。激活您的虚拟环境:

source /absolute/path/pytorch-env/bin/activate

三。安装所需的库:

pip install torch torchvision

pip install opencv-python

pip install numpy

pip install Pillow=2.2.1

实现数据集示例

在编写 Pytorch 包装器之前,您需要定义一个 Pytorch 数据集类,用多种方法将输入图像文件采样到一个高级对象中。这样,模型将处理被采样的对象,而不是转换和处理所有相关的文件。

def __init__(self, root_dir, image_file, device)init 方法负责将图像文件转换为Pillow图像对象,然后转换为 torch 张量,在内部定义一组预处理规则,将初始张量转换为更适合 deeplabv3 模型的输入。目的是生成一个形状良好的张量,以避免图像文件和模型之间任何令人讨厌的不匹配。

为 DeepLab V3 推理创建 Pytorch 包装器模块

SemanticSeg(nn.Module)包装器模块有三个主要方法:

  • def __init__(self, pretrained, device)用预训练值初始化加载一个已经训练好的 deeplabv3-resnet101 模块,设备参数指定处理推理时的 CPUGPU 加速。
  • def forwar(self, input)SegmentationSample输入应用模块推理,并返回预测张量。
  • def load_model(self, pretrained=False)torchvision.models.segmentation API 加载 deeplabv3-resnet101 模块。

添加一个方法来帮助处理结果。请记住,输出张量有 21 个通道与模型训练的每个目标类的预测结果相匹配。因此,我们需要解码张量形状,以便能够输出正确的图像结果。

background_custom(self, input_image, source, background_source, channel=21)该方法采用具有[1, 21, H, W]形状的输出张量图像、图像文件的路径、背景图像文件的路径以及已经设置为 21 的通道数。目标是从输出中提取人物通道( class 15 ),排除所有标记为背景的剩余通道,最后将定义的背景与新的图像源合并。

设置 Django API

我们将使用 Django REST 框架为我们的模型构建一个简单的 API。关键的想法是配置所有需要的文件,包括模型、路由管道和视图,这样我们就可以通过一个简单的转发 POST 和 GET 请求轻松地测试推理。

你也可以遵循 Bennett Garner 的教程,它详细介绍了让你的 API 运行的所有必要步骤。

[## 用 Django REST 框架构建您的第一个 REST API

在 Django 中构建 REST API 非常简单。在本教程中,我们将逐步完成您的第一个 API

medium.com](https://medium.com/swlh/build-your-first-rest-api-with-django-rest-framework-e394e39a482c)

通常,API 是数据库的一个窗口。API 后端处理数据库查询和响应格式化。您收到的是一个静态响应,通常是 JSON 格式的,是您请求的任何资源的静态响应。

建立 Django 项目

安装djangodjangorestframework : pip install django pip install djangorestframework

前往你将要工作的地方,开始你的项目:django-admin startproject semanticsegmentation

semanticsegmentation/文件夹中,您将找到一个manage.py脚本来运行您的 localhost 项目:python manage.py runserver

在 127.0.0.1:8080 港口,您应该登陆欢迎 Django 页面:

Django 本地主机 127.0.0.1:8080

从现在开始,你的 Django 后端已经正确设置并运行了。

创建您的 API 应用程序

您将在前一个文件夹中生成一个专门用于 API 管理的新应用程序。

运行以下命令创建文件夹:python manage.py startapp api

向项目文件夹注册新的 API app:转到semanticsegmentation/settings.py添加 API 的路径,

INSTALLED_APPS = [
'api.apps.ApiConfig',
'django.contrib.admin',
'django.contrib.auth',
...
]

定义您的模型并使用 Django ORM 管理它们

现在,为了从 Django 数据库中保存和检索对象,您需要构建一个模型类来表示我们将在 API 请求中处理的实体。对于我们的特殊情况,我们需要张贴图像,应用模型推理来获得语义过滤器,然后恢复它们。因此,最合适的是一个具有两个属性的类,用于将输入和输出图像文件上传到服务器,一个特定的 id models.UUIDField链接到每个存储的图像,一个名称CharField用于标识它们,并且可选地,一个DateTimeField用于保存它们被存储的确切时间。

在单独的脚本中定义处理文件上传逻辑的方法:

get_input_image_path

get_output_image_path

将您的更改迁移到数据库:python manage.py makemigrations

python manage.py migrate

定义与模型类匹配的序列化程序,一个序列化程序用于输入图像,另一个用于输出结果:

在管理站点admin.site.register(ImageSegmentation)注册你的新模型

建立你的观点

我们将创建简单的 get 和 post 方法来处理简单的操作:

  • POST api_view :发送两个文件图像,应用模型推理进行处理,保存到对应的输入输出文件夹。

  • GET api_view: 检索保存的图像,并将其作为静态资源。

配置 URL 端点并运行您的 API

  1. semanticsegmentation/urls.py文件中设置 url 模式:
urlpatterns = [
   path('admin', admin.site.urls),
   path(r'bg_custom_api', include('API.urls'))
]

2.在api.urls文件中定义 API 端点的地址:

urlurlpatterns = [
 path(r'test/', views.test_api, name='test_api_communication'),
 path(r'images/', views.get_images, name='get_images'),
 path(r'api/', views.run_inference, name='run_inference_on_images'),
]

在邮递员上运行您的 API

下载 Postman 并开始在本地测试您的 API。

截屏(邮递员)127 . 0 . 0 . 1 上的 post 请求:8000/api/inference/

  • 127 . 0 . 0 . 1:8080/API/gray/上运行灰度推断

左上角的 Calvin LupiyaUnsplash 上的原始照片,其右侧为灰度版本,左下角的 Unsplash 上的 CDC 的原始彩色照片,其右侧为分段版本。

  • 127 . 0 . 0 . 1:8080/API/inference/上运行后台自定义推理

乔安娜·尼克斯-沃克普在 Unsplash 上的照片 Kiana BosmanUnsplash 上的照片

结论

一旦你设置了 API 正确运行所需的所有组件,你就可以开始用 DeepLab V3 尝试一些非常酷的功能,包括背景自定义、背景灰度、背景模糊以及我相信你能想到的许多其他创造性的东西。

在为模型服务构建 API 之后,一个自然的步骤是开发一个小的移动应用程序,作为与 Django 后端交互的客户端,因此您可以测试并获取之前看到的所有结果。我愿意在我的下一篇文章中考虑这个选项,所以请继续关注第二部分。

如果您对代码有任何疑问,请与我联系,不要犹豫,给我发电子邮件到aymanehachchaming@gmail.com

本文的整个项目代码可以在我的 GitHub repo 中找到:

[## aymanehachham/背景-定制

在 GitHub 上创建一个帐户,为 aymanehachham/后台定制开发做贡献。

github.com](https://github.com/aymanehachcham/Background-Customization)

本文的参考资料

推荐环境中的语义相似度

原文:https://towardsdatascience.com/semantic-similarity-in-the-context-of-recommendation-9d088aab9e95?source=collection_archive---------28-----------------------

如何利用语义提高传统最大似然推荐算法的性能

相似性、距离和相关性是数据科学中的核心概念。它们对事物有多“近”或“远”这一基本问题给出了一个数字尺度。有许多不同的方法来计算相似性,如余弦相似性皮尔逊相关系数等等。在本文中,我将讨论语义相似度及其在推荐算法中的应用。

经典的协作过滤(CF)推荐器是基于行为数据的。我们收集用户评级或使用行为,并创建一个“评级矩阵”,从中我们可以识别统计模式并计算行为相似性。基于这种相似性,推荐器预测用户行为->这就是推荐。

行为的相似性会产生令人惊讶而又令人耳目一新的推荐。零售商发现的一个真实行为模式的例子表明,购买尿布的人通常也会购买啤酒。现在我们需要问:我们是否要向一位刚刚订购了尿布的顾客推荐一种啤酒?它是否符合企业的最大利益?它“有意义”吗?

用行为相似性来补充语义相似性可以确保 CF 推荐器将产生与企业的最佳利益和策略一致的推荐。在某种程度上,我们可以将其视为基于特征的相似性的集合,它由基于内容的过滤推荐和我们在项目-项目协同过滤算法中计算的行为相似性使用,但具有更高的准确性。在基于内容的过滤中计算的相似度是基于一个扁平的长特征列表,而语义相似度是基于一个更加丰富的分层数据模型(即图形和本体),因此我们可以计算出一个更加复杂和精确的相似度,更好地与业务策略和兴趣保持一致。

在这篇文章中,我将展示如何在推荐的上下文中使用语义相似性,通过增加语义的行为相似性,使推荐更好地符合业务和客户的最佳利益。

什么是语义相似度

语义相似性解释起来很简单,但计算起来要困难得多。直觉上,人们用符号和概念来思考,所以当你问某人两个现实生活中的物体如何比较时,你得到的答案是概念上的语义相似。

语义相似有语境。当你问两个物体是否相似时,你必须定义你想看的物体的方面。例如,两种产品可能价格相似,但功能集却大不相同。邻居在他们家的地理上是相似的,但是在他们的文化背景方面可能是非常不同的。记住上下文,我们可以讨论“有效相似性”,它定义了对于特定问题的相似性度量最有效的上下文。为特定领域定义数据模型的本体是一个很好的工具,可以根据特定的上下文来查看对象。从包含我们感兴趣的两个对象并且基于领域本体设计的知识图中,我们可以计算特定用例的两个概念之间的有效距离/相似性。

如何计算语义相似度

在语义相似性领域有许多研究,且有许多不同方法来计算它。论文“提高知识图质量的语义相似性度量框架”总结了最流行的方法。为了在准确性和召回率方面获得最佳性能,最好结合多种资源特征,例如共享信息的层次结构、邻居、数据属性和特殊性。
GADES ,A neiGhborhood-bAseDgraphEentitySimilarity,是一种语义相似度计算方法,综合了知识图中实体的几种资源特征。

语义相似度是多种因素的综合。来自 GADES 的论文(见参考文献)

等级相似性

用于计算语义相似性的第一个也是最流行的资源特征是分级相似性,其测量对象在本体分级树中有多远以及它们的最低共同祖先(LCA)有多深。直觉是,相似的实体有一个深刻而密切的最低共同祖先。计算等级距离有两种常用方法。两者都使用 LCA 和距离“d ”,距离“d”是仅考虑 rdfs:subClassOfrdf:type 关系(即边)的两个节点之间的跳数。

Dtax

二苯砜

使用一个或另一个没有明显的优势,两者在语义相似性框架中同样受欢迎。

相似度只是距离的倒数,或者换句话说:

邻域相似性

告诉我你的邻居,我会告诉你你是谁。邻域相似性基于定义其邻域的关系来测量两个实体之间的相似性。

邻域是关系实体对 N(e)的集合,其实体在源实体(e)的一跳距离处。

对于每个邻居,我们需要使用知识图(即本体)的关系和类层次中编码的知识来考虑邻居实体(e)和边的关系类型(r)

让我们称之为“邻居对”。p =(r;e)。由于实体的邻域是邻域对的集合,为了计算实体 e1 和 e2 的邻域的相似性,我们首先需要知道如何比较两个个体对的相似性:P1 =(R1;e1)和 p2 =(R2;e2)。

既然我们知道如何计算邻域对的相似性,我们就可以计算两个实体的整个邻域之间的相似性。
为了聚集两个邻域之间的相似性,GADES 使用度量来组合配对比较。

编写相同计算的另一种方法是:

共享信息的特殊性

这里的直觉是,两个实体共享的特定信息越多,我们就会认为它们越相似。同样,一个概念出现的次数越少,它就被认为越具体。如果两个实体在语料库中被类似地使用,则它们被认为共享大量信息。将知识图视为语料库,由两个实体 x 和 y 共享的信息与在它们的邻域中 x 和 y 在一起的实体的数量成正比,即,x 和 y 在实体的邻域中的同现。

让我们把它放入一个公式:
首先让我们定义:事件(e)为在其邻域中有 e 的实体的集合。

有了它,我们可以计算相似性:

该公式的分母有助于降低关于抽象或非信息实体的相似性,这些实体在语料库中是常见的,因此不被认为是特定的。

属性相似度

知识图中的实体不仅与其他实体相关,还通过数据类型属性与属性相关,例如温度、日期等。这些属性可以告诉我们很多关于给定上下文中实体的相似性。例如,查看出生日期属性可以在长期投资建议的上下文中驱动相似性计算。

GADES 只考虑共享属性,即通过相同的 datatype 属性连接到实体的属性(例如,DateOfBirth 是 rdfs:subClassOfrdf:type human ) 实体的所有实例的共享属性)。
考虑到属性可以与领域相似性度量进行比较(例如,向量的余弦、曼哈顿、欧几里德距离),GADES 没有描述用于比较各种属性的特定度量。根据领域的不同,专家将为每种类型的属性选择一个相似性度量。

总体相似性

上面描述的每个相似性就其本身而言都是有价值的,但是 GADES 的力量来自于将所有的相似性组合成一个单一的度量α。
GADES 使用聚合函数的组合来组合个体相似性度量以产生相似性值。不同聚集函数β和γ的详细定义以及组合它们的三角范数 T 是特定于域的。

摘自论文:语义相似性度量框架
提高知识图质量

例如,在长期投资推荐用例的上下文中,领域专家可能决定放大属性相似性,因为客户的年龄是要考虑的首要因素,所以 T 的系数表达了这一点。

GADES 实施

GADES 是一篇学术论文,不幸的是没有商业实现。下面的存储库包含一个 java 实现

推荐的相似性

协同过滤(CF)推荐算法使用某种相似性函数来预测用户行为,即推荐。这可以是用户行为之间的相似性,或者是项目之间的相似性,因为它们以相似的模式被喜欢或不喜欢。因为相似性是根据评级矩阵计算的,所以它是设计行为,并不反映所涉及项目的语义。有时,这正是业务对算法的期望,但在其他情况下,忽略语义会产生没有意义或没有反映业务最佳利益的结果。用语义相似性补充行为相似性并将其插入推荐引擎可以提高其性能,因为它将为企业和客户产生更有效的结果。

项目-项目协同过滤

Item-Item CF 查找与用户已经评分的项目相似的项目,并推荐最相似的项目。项目-项目 CR 相似性是行为性的,即人们如何根据喜欢和不喜欢来对待两个相同的项目。通过对目标用户在这些相似项目上的评级(V)进行加权平均来计算预测(即,推荐)。换句话说,为了计算用户 u 对项目 I 的预测,我们计算用户对类似于 I 的项目给出的评级的总和。每个评级由项目 I 和 j 之间的相应相似性 si,j 加权。

项目-项目协同过滤

为了学习更多关于算法的知识,我推荐阅读原始的论文,它清晰易懂。
该算法的一个好处是相似度计算是可插拔的。最初的论文建议使用皮尔逊-r 相关或余弦相似度,但它对任何其他有意义的相似度计算都是开放的。我们建议使用从评级矩阵中提取的行为相似性与使用 GADES 从知识图中提取的语义相似性的组合。

用户-用户

用户-用户协同过滤可能是最流行的 CF 推荐算法,可能是因为它很容易理解。
从评分矩阵中,我们找到在喜好和厌恶方面与目标用户行为相似的用户,然后我们对他们的评分进行加权平均,对他们进行排序,并使用最佳列表作为推荐。

这里关于语义的问题是,相似性是用户行为之间的,而不是属于目标领域的概念之间的,所以开箱即用,我们不能将语义相似性插入到算法中。为了解决这个问题,我们必须将评级矩阵映射到属于目标领域但仍然保留用户行为的东西。论文基于语义的协同过滤增强推荐提出了一种方法。从评分矩阵中,我们创建了一个基于语义相似度和传播激活算法的兴趣矩阵(IS)。
IS(C j,u)和 IS(C j,v)分别是用户 u 和 v 的简档中与概念 j 相关联的兴趣得分。现在,我们可以计算相似性(或距离)并将其插入用户-用户算法。

来自论文:一个语义相似性度量的框架来增强知识
图的质量

学术研究成果

我想强调几篇相关学术论文中的两个结果。

  • 在精确度、召回率和 F1 指标方面,使用行为和语义相似性的组合,CF 算法的性能得到显著提高。

摘自论文:语义相似度度量框架增强知识
图质量

  • GADES 在准确性方面表现出最佳的性能结果。

来自 GADES 的论文(见参考文献)

下表显示了在 CESSM 2008 和 2014 上采用黄金标准 ECC、Pfam 和 SeqSim 的最新相似性度量和 GADES 之间的皮尔逊系数。
我们观察到,在 2008 年和 2014 年两个版本的知识图中,GADES 是与三个金标准度量最相关的度量。

我们的实验

第一步是实现项目-项目 CF 算法的 python jupyter 记事本。我们用于健全性测试的数据集是来自 iMDB 数据库的电影用户评级的集合。我们基于流派、演员和导演实现了一个简单的语义相似度,并将其与上述权重为 20%的行为相似度相结合。

我们看到性能平均值精度提高了 0.935897,召回率提高了 0.941935,但最重要的是,我们看到推荐的结果共享了一个类别。在现实生活中,这可能不是企业想要的电影推荐引擎,但对于其他用例,如产品推荐,这样的行为是可取的。

结论

语义相似度可以使用 GADES 等方法从知识图中有效地计算出来。一旦计算出来,它就可以用于许多数据科学任务。在本文中,我们展示了如何在推荐的上下文中使用语义相似性,通过增加语义的行为相似性,使推荐更好地符合业务和客户的最佳利益。

参考

基于语义的协同过滤增强推荐

加迪斯

增强知识的语义相似性度量框架
图形质量

未标记数据的半监督分类(PU 学习)

原文:https://towardsdatascience.com/semi-supervised-classification-of-unlabeled-data-pu-learning-81f96e96f7cb?source=collection_archive---------7-----------------------

布鲁诺·马丁斯在 Unsplash 上的照片

当你只有几个正样本时,如何对未标记数据进行分类

假设您有一个支付交易的数据集。一些交易被标记为欺诈,其余的被标记为真实,您需要设计一个模型来区分欺诈和真实的交易。假设您有足够的数据和良好的特征,这似乎是一个简单的分类任务。但是,假设只有 15%的数据被标记,并且被标记的样本仅属于一个类,因此您的训练集由 15%被标记为真实的样本组成,而其余的样本未被标记,并且可能是真实的或欺诈的。你将如何对它们进行分类?需求的这种扭曲是否只是将这项任务变成了一个无人监督的学习问题?嗯,不一定。

这个问题通常被称为 PU(阳性和未标记)分类问题,应该首先与两个类似的常见“标记问题”区分开来,这两个问题使许多分类任务变得复杂。第一个也是最常见的标签问题是小训练集的问题。虽然你有大量的数据,但实际上只有一小部分是有标签的。这个问题有很多种类,也有不少具体的训练方法。另一个常见的标记问题(经常与 PU 问题混淆)涉及我们的训练数据集被完全标记的情况,但是它只包含一个类。例如,假设我们只有一个非欺诈性交易的数据集,我们需要使用这个数据集来训练一个模型,以区分(类似的)非欺诈性交易和欺诈性交易。这也是一个常见的问题,通常被视为无监督的离群点检测问题,尽管在 ML 环境中也有相当多的工具广泛可用,专门用于处理这些场景(OneClassSVM 可能是最著名的)。

相比之下,PU 分类问题是一种涉及训练集的情况,其中只有部分数据被标记为正,而其余部分未被标记,可能是正的也可能是负的。例如,假设你的雇主是一家银行,它可以为你提供大量交易数据,但只能确认其中一部分是 100%真实的。我将在这里使用的例子涉及到一个关于假钞的类似场景。它包括 1200 张钞票的数据集,其中大部分没有标签,只有一部分被确认为真实的。虽然 PU 问题也很常见,但与前面提到的两个分类问题相比,它们通常很少被讨论,而且很少有实际操作的例子或库可以广泛使用。

这篇文章的目的是提出一种可能的方法来解决我最近在一个分类项目中使用的 PU 问题。它基于查尔斯·埃尔坎和基思·诺托写的论文“仅从正面和未标记的数据中学习分类器”(2008),以及由亚历山大·德鲁因写的一些代码。尽管在科学出版物中有更多的 PU 学习方法(我打算在以后的文章中讨论另一种相当流行的方法),Elkan 和 Noto 的(E & N)方法非常简单,可以很容易地用 Python 实现。

一点理论(请耐心听我说……)

照片由安托万·道特里Unsplash 上拍摄

E&N 本质上声称,给定一个数据集,其中我们有正的和未标记的数据,某个样本为正的概率[ P( y =1| x )]等于该样本被标记的概率[P( s =1| x )]除以在我们的数据集中正样本被标记的概率[P( s =1| y 【T19

如果这种说法是真的(我不打算证明或捍卫它——你可以阅读论文本身的证明,并用代码进行实验),那么它似乎相对容易实现。这是因为虽然我们没有足够的标记数据来训练分类器来告诉我们样本是阳性还是阴性,但在 PU 场景中,我们有足够的标记数据来告诉我们阳性样本是否可能被标记,并且根据 E & N,这足以估计它是阳性的可能性有多大。

更正式地说,给定一个只有一组标记为正的样本的未标记数据集,如果我们估计P(s= 1 |x)/P(s= 1 |y= 1),我们就可以估计出未标记样本 x 为正的概率。幸运的是,我们可以根据以下步骤使用几乎任何基于 sklearn 的分类器来估计这一点:

(1) 在使用无标签指示器作为目标的同时,在包含有标签和无标签数据的数据集上安装分类器 y 。以这种方式拟合分类器将训练它预测给定样本 x 被标记的概率— P( s =1| x )。

(2) 使用分类器预测数据集中已知阳性样本被标记的概率,从而预测结果将代表阳性样本被标记为—P(s= 1 |y= 1 |x)的概率**

计算这些预测概率的平均值,这就是我们的P(s= 1 |y= 1)

已经估计了 P( s =1| y =1),为了根据 E & N 预测数据点 k 为正的概率,我们需要做的就是估计 P( s =1| k )或它被标记的概率,这正是我们训练的分类器(1)知道如何做的。

(3) 用我们在 (1) 上训练过的分类器来估计 k 被标注的概率或者**P(s= 1 |k)

(4) 一旦我们估算出了**P(s= 1 |k),我们实际上就可以将 k 除以第P(s= 1 |y= 1)(已经在第(2)步估算过了)

现在让我们对此进行编码和测试

上述步骤 1-4 可以按如下方式实施:

****# prepare data**x_data = *the training set*
y_data = *target var (1 for the positives and not-1 for the rest)***# fit the classifier and estimate P(s=1|y=1)**classifier, ps1y1 = 
       fit_PU_estimator(x_data, y_data, 0.2, Estimator())**# estimate the prob that x_data is labeled P(s=1|X)**predicted_s = classifier.predict_proba(x_data)**# estimate the actual probabilities that X is positive
# by calculating P(s=1|X) / P(s=1|y=1)**predicted_y = estimated_s / ps1y1**

先说这里的主招: fit_PU_estimator() 方法。

fit_PU_estimator() 方法完成两个主要任务:它将您选择的分类器拟合到阳性和未标记训练集的样本上,然后估计阳性样本被标记的概率。相应地,它返回拟合的分类器(学会估计给定样本被标记的概率)和估计的概率P(s= 1 |y= 1)。之后我们要做的就是求 P( s =1| x )或者说 x 被标注的概率。因为这就是我们的分类器被训练要做的,我们只需要调用它的 predict_proba() 方法。最后,为了对样本 x 进行实际分类,我们只需要将结果除以我们已经找到的P(s= 1 |y= 1)。这可以用代码表示为:

fit_PU_estimator ()方法的实现本身是不言自明的:

为了测试这一点,我使用了钞票认证数据集,它基于从真钞和伪钞图像中提取的 4 个数据点。我首先在带标签的数据集上使用分类器,以便设置基线,然后移除 75%样本的标签,以便测试它在 P & U 数据集上的表现。正如输出所示,这个数据集确实不是最难分类的数据集之一,但是您可以看到,虽然 PU 分类器仅“知道”大约 153 个阳性样本,而所有其余的 1219 个样本都是未标记的,但是与具有所有可用标签的分类器相比,它表现得相当好。然而,它确实丢失了大约 17%的召回,因此丢失了相当多的真阳性。然而,当这是我们所拥有的一切时,我相信这些结果与其他选择相比是相当令人满意的。

****===>> load data set <<===**data size: (1372, 5)**Target variable (fraud or not)**:
0    762
1    610***===>> create baseline classification results <<===*****Classification results:**f1: 99.57%
roc: 99.57%
recall: 99.15%
precision: 100.00%***===>> classify on all the data set <<===*****Target variable (labeled or not)**:
-1    1219
1     153**Classification results**:f1: 90.24%
roc: 91.11%
recall: 82.62%
precision: 99.41%**

几个重要的笔记。首先,这种方法的性能很大程度上取决于数据集的大小。在这个例子中,我使用了大约 150 个阳性样本和大约 1200 个未标记的样本。这远远不是这种方法的理想数据集。例如,如果我们只有 100 个样本,我们的分类器就会表现很差。第二,如附件所示,有几个变量需要调整(例如要留出的样本大小、用于分类的概率阈值等),但最重要的可能是所选择的分类器及其参数。我选择使用 XGBoost,因为它在具有很少特性的小数据集上表现相对较好,但是需要注意的是,它不会在每个场景中都表现最佳,并且测试正确的分类器也很重要。

笔记本在这里有售。

尽情享受吧!

基于 GAN-BERT 的半监督意图分类

原文:https://towardsdatascience.com/semi-supervised-intent-classification-with-gan-bert-934d8659bca2?source=collection_archive---------21-----------------------

基于 GAN-BERT 的半监督学习方法在 CLINC150 数据集上的意图分类

甘伯特建筑。来源:" GAN-BERT:健壮文本分类的生成式对抗学习"

有没有可能对 150 个目标类别进行文本分类,每个类别只使用 10 个标记样本,但仍能获得良好的性能?

从那个简单的问题开始,我开始做研究,以便回答那个问题。花了几个小时后,我终于和甘伯特在一起了。甘伯特是什么?我用甘博特做了什么实验?在本文中,我将尝试简要介绍 GAN-BERT,并使用 CLINC150 数据集实现其意图分类。

在自然语言处理(NLP)领域, BERT 或来自 Transformers 的双向编码器表示是一种基于 Transformers 架构的众所周知的技术,用于执行广泛的任务,包括文本分类。然而,当有“足够”的标记训练数据要利用时,这种技术可以很好地执行,而获得标记数据是耗时且昂贵的过程。对此的潜在解决方案是使用半监督学习方法。

半监督学习是机器学习领域中的一种方法,它在训练过程中结合了标记数据和未标记数据。目标与监督学习方法相同,即在给定具有若干特征的数据的情况下预测目标变量。当我们没有这么多标记数据,而我们的模型需要大量训练数据才能表现良好时,这种方法是至关重要的。

最近在 2020 年 7 月,一篇名为“GAN-BERT:具有一堆标记示例的健壮文本分类的生成对抗学习”的论文,试图在生成对抗设置中扩展具有未标记数据的 BERT 类架构的微调。在高层,他们试图从 SS-GAN (半监督 GAN)的角度丰富 BERT 微调过程。

“在本文中,我们在生成性对抗设置中使用未标记数据来扩展 BERT 训练。特别是,我们在所谓的 GAN-BERT 模型中,从 SS-GAN 的角度丰富了 BERT 微调过程

甘伯特

这种体系结构结合了 BERT 和 SS-GAN 的能力来进行文本分类。生成器通过从高斯分布中提取 100 维噪声向量的输入来产生“假”示例。鉴别器是在 BERT 上的 MLP,它接收输入向量或者是由发生器产生的假向量或者是来自 BERT 产生的真实数据的向量。鉴别器的最后一层是 softmax 层,它输出 logits 的 k+1 维向量,其中 k 是数据集中类的数量。这里,真实数据被分成两部分,它们被标记为(L)和未标记的(U)数据。

甘伯特建筑。来源:" GAN-BERT:健壮文本分类的生成式对抗学习"

鉴别器旨在对输入是否为真实实例进行分类。如果它预测输入是真实的实例,那么它必须预测输入属于哪个类。

训练过程试图优化两个竞争损耗,它们是鉴别器损耗和发电机损耗。鉴别器损耗是另外两个损耗的总和:监督损耗和非监督损耗。监督损失测量将错误的类别分配给原始 k 个类别中的真实示例的误差,而非监督损失测量不正确地将真实(未标记的)示例识别为假的并且不识别假的示例的误差。发电机损耗也是另外两个损耗求和的结果:特征匹配和无监督损耗。特征匹配损失旨在确保生成器应该产生其在输入到鉴别器时提供的中间表示与真实表示非常相似的示例,而无监督损失测量由鉴别器正确识别的虚假示例引起的误差。

基思·约翰斯顿在 Unsplash 上拍摄的照片

在训练期间,每一类中的样本以 log (2|U|/|L|)的因子被复制,以保证在每一批中存在一些标记的实例,从而避免由于对抗训练的无监督成分而导致的发散。在推理过程中,生成器被从体系结构中丢弃,而保留其余部分。

这意味着相对于标准的 BERT 模型,在推断时没有额外的成本。

实验设置

在本实验中,使用了 CLINC150 数据集。该数据集由 10 个领域的 150 个意图类组成。提供的数据有 4 种变型:不平衡OOS+、这里用的是变型对于每个意图,有 100 个训练话语、20 个验证话语和 30 个测试话语。实际上,除了 150 个意向范围内类之外,该数据还提供了范围外类(OOS)。但是,在这个实验中,我只关注范围内的类预测。

由于实际的 CLINC150 数据集不是为半监督学习设置而构建的,因此在这里,我尝试用 6 种不同的训练数据进行实验。对于每个变体,训练数据被分成标记的和未标记的集合。第一个变体由 10%标记的和 90%未标记的数据集组成。因为训练数据中的话语总数是 100,所以对于第一种变型,有标记集合有 10 个话语,无标记集合有 90 个话语。

训练数据的变量。来源:作者的财产

我对所有训练数据变量使用完全相同的参数设置。唯一的区别是训练时期的数量。我使用 20、18、16、14、12、10 个历元数分别表示第一个到最后一个变量。

实验结果

CLINC150 论文上的结果表明,通过利用 BERT,他们在测试数据集上获得了 96.2%的准确率。这里使用相同的测试数据集是跨越 6 个训练数据变化的 GAN-BERT 的结果。

跨 6 个训练数据变量的测试数据集的准确性。来源:作者的财产

我们可以看到,在训练过程中,即使在每个意图中仅使用 10 个标记的话语,GAN-BERT 也能够给出合理的性能。甘伯特的性能随着标记话语数量的增加而增加。第四、第五和第六变型的性能彼此相似。这表明,即使仅使用 60%的标记训练数据,GAN-BERT 的性能也类似于使用 80%甚至 90%的标记训练数据训练的模型。

最后的话

GAN-BERT 在多文本分类任务的半监督学习中具有很大的潜力。仅给定有限的标记训练数据,它表现良好。然而,这只是在文本分类任务中处理有限标记训练数据的方法之一。还有另一种方法叫做少镜头文本分类。如果你有更多的兴趣,你可以阅读这篇论文,它也使用 CLINC150 作为他们的训练数据。

您可以在这里找到本文中使用的所有代码。

关于作者

Louis Owen 是一名数据科学爱好者,他总是渴望获得新知识。他获得了最后一年的全额奖学金,在印尼顶尖大学 的万隆技术学院 攻读数学专业。

Louis 曾在多个行业领域担任分析/机器学习实习生,包括 OTA ( Traveloka )、电子商务( Tokopedia )、fin tech(Do-it)、智慧城市 App ( Qlue 智慧城市 ),目前在世界银行担任数据科学顾问。

查看路易斯的网站,了解更多关于他的信息!最后,如果您有任何疑问或需要讨论的话题,请通过 LinkedIn 联系 Louis。

基于 K 均值聚类的半监督学习

原文:https://towardsdatascience.com/semi-supervised-learning-with-k-means-clustering-6e837158c54a?source=collection_archive---------19-----------------------

机器学习

有限数据标签下 NBA 球员位置预测的半监督学习案例研究。

照片由бодьсанал·布吉Unsplash 拍摄

有监督学习和无监督学习是机器学习中的两大任务。当所有实例的输出可用时,使用监督学习模型,而当我们没有“真实标签”时,应用无监督学习。

尽管无监督学习的探索在未来的研究中具有巨大的潜力,但有监督学习仍然主导着该领域。然而,当我们的数据中没有足够的标记样本时,我们通常需要建立一个监督学习模型。

在这种情况下,可以考虑半监督学习。其思想是基于非监督学习过程的输出来构建监督学习模型。

我想举一个简单的例子。

问题:我们可以根据 NBA 球员的比赛数据来对他们的位置进行分类吗?

我收集了 2018-2019 赛季 NBA 球员的场均数据。球员的位置被定义为传统的篮球位置:控球后卫(PG)、得分后卫(SG)、小前锋(SF)、大前锋(PF)和中锋(C)。

在建模过程之前,我对数据集做了一些预处理。首先,去掉每场比赛上场时间不到 10 分钟的球员。然后,用 0 填充 NA 值(比如中锋球员从来不投三分球)。

df_used = df_num.loc[df.MP.astype('float32') >= 10]
df_used.fillna(0,inplace=True)

预处理后,数据如下所示:

df_used.head()

数据头

然后,我将数据分离到训练集和测试集。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df_used, labels_)

监督学习(给出所有玩家的位置)

如果所有标签(玩家位置)都给了,那就是一个简单的监督分类问题。我用一个简单的逻辑回归模型来拟合训练数据集。

from sklearn.linear_model import LogisticRegression 
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScalerpipeline = Pipeline([
        ("scaler", StandardScaler()),
        ("log_reg", LogisticRegression()),
    ])pipeline.fit(X_train, y_train)

我在测试数据集上评估了这个模型。

pipeline.score(X_test, y_test)

这个过程给出 0.644,这意味着 64.4%的预测是正确的。从这个结果中,我们知道分类器的改进空间非常大。然而,在本文中,我并不关注分类器的开发。

我将讨论数据标签仅部分可见的情况。

半监督学习(只给出 100 个玩家的位置)

如果只允许我看到训练数据中 100 个球员的位置信息,会对模型的性能产生怎样的变化?有许多策略可以用来选择 100 个玩家作为分类器的输入。

第一种策略是随机选择 100 个玩家,比如前 100 个玩家。我检查了只在这个子集上训练的逻辑回归模型的性能。

n_labeled = 100pipeline.fit(X_train[:n_labeled], y_train[:n_labeled])
pipeline.score(X_test, y_test)

这次我只得到 56.8%的准确率。这是意料之中的,因为我只看到了真实标签的一个子集。

然而,我们可以通过选择 100 个标签的不同子集来提高性能吗?答案是肯定的。

第二种策略是应用无监督学习过程来对整个训练数据集中的数据进行聚类,并暴露每个聚类的代表的标签。这样,我们可以假设在聚类空间中彼此接近的数据点应该有很高的机会拥有相同的标签。

换句话说,比赛数据相似的球员应该在场上打同样的位置。

from sklearn.cluster import KMeansk=100
kmeans = KMeans(n_clusters=k)
X_dist = kmeans.fit_transform(X_train) 
representative_idx = np.argmin(X_dist, axis=0) 
X_representative = X_train.values[representative_idx]

在代码中,X_dist 是到聚类质心的距离矩阵。representative_idx 是最接近每个聚类质心的数据点的索引。

在选择了特征空间中的代表之后,我们收集了这些数据点的真实标签。这里,我只需要从原始数据中提取标签。

y_representative = [list(y_train)[x] for x in representative_idx]

但是请注意,实际情况是我们不知道有什么真正的标签,所以需要手动标注这些选中的数据点。

让我们来检查在这个训练数据子集上训练的模型的性能。

pipeline.fit(X_representative, y_representative)
pipeline.score(X_test, y_test)

我得到了 59.6%的准确率!尽管它不能与在整个训练集上训练的模型相比,但它比随机选择的 100 个数据点要好。

讨论

随着篮球的发展,根据球员的比赛数据来判断他们的位置变得越来越困难。这就是为什么我们只有 60%左右的准确率。

尽管在聚类质心上训练的模型的性能比在随机数据点上训练的模型的性能好,但是改进是有限的。这可以解释为,在目前的 NBA 中,同一位置的球员的比赛数据可能会有很大的差异。

参考资料:

  1. 用 scikit 动手机器学习——学习 keras 和 tensorflow
  2. 篮球参考。

希望这篇短文对你有用!干杯!

数据科学的开创性论文:大型共享数据库的关系模型

原文:https://towardsdatascience.com/seminal-papers-in-data-science-a-relational-model-for-large-shared-data-banks-892fccf97fd1?source=collection_archive---------34-----------------------

50 年后,回顾了 e . f . Codd 1970 年论文中的一些主要概念,这些概念为关系数据库和 SQL 奠定了基础

弗兰基·查马基在 Unsplash 上拍摄的照片

即使 NoSQL越来越受欢迎,大多数公司仍然在使用某种形式的基于 SQL 的关系数据库管理系统。虽然 SQL(当时叫做 SEQUEL)是由 IBM 的 Donald D. Chamberlain 和 Raymond F. Boyce 在 1974 年首次引入的,但是他们的工作是建立在 Edgar F. Codd 的思想之上的。Codd 是另一位 IBM 计算机科学家,他在 1970 年提出了数据库管理的关系模型。在这篇文章中,我讨论了 Codd 有影响力的论文中的一些主要观点,以及他的观点如何与我们现代使用 SQL 相关联。

关系

Codd 使用术语关系来描述他的模型的基石。该关系正式描述如下:

给定集合 S1,S2,…,Sn(不一定不同),R 是这 n 个集合上的一个关系,如果它是一个 n 元组的集合,每个元组的第一个元素来自 S1,第二个元素来自 S2,等等。我们将 Sj 称为 R 的第 j 个域。如上所述,R 的阶数为 n。阶数为 1 的关系通常称为一元关系、阶数为 2 的关系、阶数为 3 的关系和阶数为 n 的关系。

-Codd (1970 年)

这个定义可能看起来完全陌生,但是如果您熟悉 SQL,那么 Codd 实际上是指一些非常熟悉的东西。Codd 建议可以基于以下条件将关系表示为数组:

代表 n 元关系 R 的数组具有以下属性:

(1)每行代表 r 的一个 n 元组。

(2)行的顺序并不重要。

(3)所有行都是不同的。

(4)列的排序是重要的——它对应于定义 R 的定义域的 S1,S2,…,Sn 的排序(然而,参见下面关于定义域有序和定义域无序关系的注释)。

(5)通过用相应域的名称对其进行标记,来部分传达每个列的意义。"

-Codd (1970 年)

Codd 还展示了下面图 1 中关系的数组表示示例。

Codd (1970 年)

乍一看,Codd 的关系数组表示与现代 SQL 表有许多相似之处。例如,上面的 4 度关系(或者,与四个域的关系)看起来类似于我们在 SQL 中称之为具有四列的表。这个表将被命名为 supply ,Codd 的域将对应于 SQL 列。SQL 表也类似于 Codd 的关系,因为行的顺序并不重要,行是不同的,每一列都有标签。

然而,Codd 的关系和 SQL 表之间有一个显著的区别:Codd 规定列的排序是重要的,而在 SQL 中肯定不是这样。这与 Codd 的断言是一致的,即关系的每一行都是一个n-元组——在 SQL 中,由于表的列顺序通常是不相关的,所以 SQL 表的每一行不需要都是元组。

那么,为什么 Codd 会提出在关系中需要列排序呢?他用论文中的图 2 给出了一个例子(见下文)。

Codd (1970 年)

图 2 中的组件关系中,Codd 呈现了两个域(列)同名的情况——part。为了跟踪这两个零件列,为这些列分配一个固定的顺序是有意义的。虽然 Codd 在 1970 年的论文中认为这是一个合理的问题,但现在情况不同了,因为现代 SQL 数据库不允许同一个表中的两列具有相同的名称。

规范化集合

Codd 将规范化称为从关系中消除非简单域。但是 Codd 所说的非简单域是什么意思呢?

“非原子值可以在关系框架内讨论。因此,一些域可能具有作为元素的关系。反过来,这些关系可以在非简单域上定义,等等。”

-Codd (1970 年)

在下面的图 3(a) 中,Codd 通过绘制一组非规范化关系的树形图示例进一步阐述。员工关系由简单域男号姓名生日和非简单域工作历史子女组成。这些非简单域本身可以被认为是关系,包含它们自己的简单和非简单域。

Codd 注意到,这种非规范化的关系集不能用一个二维数组来表示。但归一化后,这组关系可以表示为四个二维数组(见图 3(b) )。

Codd (1970 年)

但是,究竟应该如何执行这种规范化呢?Codd 阐述了:

从树顶部的关系开始,取其主键,并通过插入该主键域或域组合来展开每个直接的从属关系。每个扩展关系的主键由扩展前的主键和从父关系复制下来的主键组成。现在,从父关系中删除所有非简单域,删除树的顶部节点,并对每个剩余的子树重复相同的操作序列。”

-Codd (1970 年)

因此,图 3(a) 中基于树的关系被转换为图 3(b) 中的规范化形式,去掉了非简单域,并且定义了一个主键来唯一标识每个关系中的行。主键可以是单个域(对于雇员关系为人员# ),也可以是多个域(对于工作历史关系为人员#、工作日期)。此外,每个关系可以使用 man# 域相互交叉引用。这几乎类似于现代 SQL 模式中的一个基本概念——一个表的主键可以作为另一个表的外键,因此,当表保持独立的二维数组时,可以保留表之间的关系。

连接

Codd 概述了许多可以在关系(表)上执行的操作,其中之一是连接。

“假设我们有两个二元关系,它们有一些共同的领域。在什么情况下,我们可以将这些关系组合起来,形成一个三元关系,保留给定关系中的所有信息?”

-Codd (1970 年)

Codd 提供了两个关系 RS 如何使用各自的 part 域连接的示例:

Codd (1970 年)

由于每个关系的零件域具有不唯一的值,由于相同的零件值可能导致供应商项目的多个组合,因此 RS 的“自然连接”包含的行(5)比两个表(3)中的任何一个都多。

如果我们假设 rs 是 SQL 数据库中的表,下面的 SELECT 语句将产生与 Codd 的“自然连接”相同的结果:

从 s.part = r.part 上的 r JOIN s 中选择供应商、r.part、项目;

SELECT * FROM r 自然联接 s;

在 SQL 中,自然联接默认执行与内部联接相同的任务,但是每个表中同名的列只会出现一次。

关闭

Codd 1970 年的论文中还有很多我没有讨论的概念,但在这篇文章中我将把它们留在这里。如果您有兴趣进一步了解关系数据库和 SQL 的基础是如何形成的,请查阅下面参考资料中的文章。

参考

[## 2019 年数据库趋势- SQL 与 NoSQL、顶级数据库、单数据库与多数据库使用

想知道哪些数据库是 2019 年的趋势?我们询问了数百名开发人员、工程师、软件架构师、开发人员…

scalegrid.io](https://scalegrid.io/blog/2019-database-trends-sql-vs-nosql-top-databases-single-vs-multiple-database-use/)

向 BigQuery 发送 Google Analytics 点击量数据

原文:https://towardsdatascience.com/send-google-analytics-hit-level-data-to-bigquery-5093e2db481b?source=collection_archive---------17-----------------------

如何发送标准的谷歌分析点击量数据到 BigQuery?

Graphicssc ,来源 pixabay

标准的谷歌分析不提供其点击量数据,我们必须购买 GA 360 来获得它,这是非常昂贵的。

在本指南中,我将帮助您建立一个数据管道,允许您在 BigQuery 中存储 GA 的数据。这将是一个命中水平的数据,不仅可以让你生成谷歌分析提供的所有报告,还可以应用先进的机器学习技术,将你的业务提升到一个新的水平。

为什么发送命中水平数据?

以下是存储 GA 命中水平数据的许多使用案例中的一些:

  1. 无数据抽样。存储点击量数据让我们在不进行任何采样的情况下创建报告。对于那些每天流量都很大的网站来说,这是一个巨大的进步。
  2. 构建任何报告。GA 报告有限。点击级别数据允许您使用任何配置构建包含任何分段的任何报告。
  3. 机器学习。应用先进的机器学习技术,获得对你的业务有用的细分和预测。
  4. 数据仓库将 GA 数据与其他营销活动数据联系起来,以便更全面地了解您的营销工作
  5. 可视化。在你喜欢的任何地方可视化数据(不仅仅是在谷歌数据工作室)

还有很多!

数据管道

由 Muffaddal 创建的 GTM 到 BigQuery 数据管道

这难道不是一个简单的数据管道吗?确实是!

我们的 ELT 数据管道使用 Google Tag Manager 来获取发送到 GA 的 hit,使用 Cloud 函数来获取和处理从 Tag Manager 收到的 hit,使用 BigQuery 来存储数据。我们还将使用 Bigquery 的查询调度器进行原始数据转换。

我从 Simo Ahava 在 tag monitor guide 上的帖子中获得了这个想法,并将其用于将 GA 的数据发送给 BigQuery。所以,如果你对监控你的标签感兴趣的话,一定要去看看

: 我将使用 GTM 发送和谷歌云平台处理和存储点击数据,但这些工具不是强制性的。一旦您理解了数据如何在这些组件之间移动,任何技术栈都可以用来实现这个数据管道。而且如果你有兴趣探索 GCP 这边的东西我会推荐 谷歌的 GCP 课程

谷歌标签管理器

测量协议是一个向 Google Analytics 发送数据的 API。我们发送到 GA 的任何调用,无论是使用代码片段还是使用标记管理器,都将被发送到测量协议。我们的想法是捕获相同的击中,这将是测量协议,并将其发送到我们的数据仓库。

但是怎么做呢?嗯,Google analytics 对象提供了一个回调函数,当调用被发送到 GA 时触发该函数。使用该功能,我们可以访问正在发送的命中级别数据。该功能被称为[customTask](https://www.simoahava.com/analytics/customtask-the-guide/?utm_source=medium&utm_medium=referral&utm_campaign=muffaddal.qutbuddin&utm_content=send_ga_hit_data_to_bigquery)

显示数据如何在自定义任务和其他工具之间移动的数据流图,由 Muffaddal

让我们使用自定义函数类型的变量在 Google 标签管理器中创建一个自定义任务句柄函数

通过 Muffaddal 为 customTask 选择自定义 JavaScript

并按原样粘贴下面的代码。

通过 Muffaddal 向云函数发送 hit 的自定义任务代码

你只需要在一个名为“云函数 URL”的常量变量中提供到云函数的链接,GTM 就会开始向云函数发送 GA 的数据。

与云函数链接的 GTM 常量变量,由 Muffaddal

将自定义函数变量命名为“自定义任务”。接下来,转到您的设置变量,在“要设置的字段”中添加 customTask,并为其提供我们的变量。

通过 Muffaddal 在设置变量中添加 customTask 字段

将 customTask 直接添加到 GA 设置变量可以确保我们的函数在每次命中 GA 时触发。

谷歌云功能

接下来,我们必须设置我们的云函数来接收来自 GTM 的点击,并将其发送给 BigQuery。我将在本指南中使用 Node.js,但它也可以用任何其他语言实现,比如 Python。首先让我们配置我们的云功能

云功能配置,由 muffaddal

我已经将分配的内存设置为 512 MB。您可能希望根据您预期收到的点击量来更新此信息。但大多数情况下,512 MB 应该就可以了。

将下面的代码复制到package.json文件中,告诉我们的云函数使用的节点依赖关系。我们将在 Node.js 代码中使用 BigQuery 和云存储。

为什么选择云存储?稍后会详细介绍。

云函数的 Package.json,由 Muffaddal

接下来,在您的index.js文件中添加下面的 Node.js 8 代码,并根据您的 GCP 环境设置‘projectId’、‘dataset’、‘tableName’和‘bucket name’。

用于处理 GA 命中的云函数代码,由 Muffaddal 编写

在上面的代码中,我们还在原始的 hit 对象中包含了时间戳(第 38 行)。这是为了在我们的数据集中有一个日期参数。这将允许我们对数据执行基于日期的操作。

此外,如果我们在向 BigQuery 插入原始命中时遇到任何错误,我们会将该命中存储到云存储中。这样做确保我们至少不会错过击中。一旦进入云存储,就可以根据错误进行处理并转发给 BigQuery。

有无错误的数据流,由 Muffaddal

我根据错误类型在 bucket 中创建了一个子文件夹。这将有助于区分点击,并允许我们相应地处理它们。

我已经在文章的最后提到了错误的可能原因。

谷歌大查询

用类型字符串创建一个包含两列hit_timestamppayload的表。确保该表的名称与您在云函数中添加的名称相同。

这是它的样子。

BigQuery 中的原始数据表,由 Muffaddal

有效负载栏中长而怪异的字符串正是 Google analytics 从网站接收点击的方式,也是我们存储它的方式。它将所有数据点格式化为查询参数。在本节的后面,我们将把它转换成可读的格式。时间戳是我们在云函数代码中添加的列。

一旦表被创建,我们的数据管道接收谷歌分析点击量数据准备好了!

接下来,我们将把这些原始数据转换成可读的格式。

转换原始数据

想法是从有效负载列中提取参数值,并将它们存储在转换后的表中。为此,我们将使用 SQL 查询。查询将做的是每天从原始数据中提取我们需要的值,并将其附加到转换后的表中。

下面是一个从原始点击中提取数据的查询

通过 Muffaddal 转换原始数据的查询

我将 hit_timestamp 转换为纽约时间,因为我的 Google Analytics 时间设置为纽约。我希望我的 BigQuery 数据能够与谷歌分析的数据相媲美,我建议你也这样做。这有助于匹配事物。

您可能还会问为什么查询只从以前的数据中提取日期?这是有原因的。我将在下一节讨论这一点。

运行上述查询将获得以下转换格式的数据

由 Muffaddal 转换的 GA 数据表

BigQuery 查询调度程序

接下来,我们希望我们的转换查询能够每天获取格式数据,这样我们就不必在处理数据集时自己转换它。查询调度器可以帮助我们做到这一点。它将在每天的 00:30 运行,并提取前一天收到的数据,对其进行转换,并将其添加到我们转换后的数据表中。

数据转换流程,由 Muffaddal

下面是要使用的计划程序设置。

Muffaddal 的 BigQuery 查询调度程序设置

为什么我把它安排在 00:30?

调度程序的工作是运行 SQL 查询。该查询从运行时开始获取前一天的所有内容。因此,日期一改变,我就运行调度程序,这样我们就能得到前一天收到的所有信息。这确保我们获得前一天的所有用户活动,并将其存储在转换后的表中。

调度器还被设置为将查询结果追加到目标表中。因此,每天结束时,我们都会在 BigQuery 中获得转换后的数据。

下面是基于上述 SQL 查询的转换表的模式。

转换的数据表架构,bu Muffaddal

搞定了。

好了,我们的数据管道已经完成,可以捕获 GA hit,并将其发送到云功能。后者将其转发给 BigQuery。在 BigQuery 查询调度器中处理原始数据,对其进行格式化,并将其存储在我们的表中,以便能够构建报告并对其进行分析。

我们为什么不直接在云函数中转换命中数据?

在 BigQuery 中存储 Google analytics 的原始点击比只存储转换后的点击数据有很多优势。其中一些是:

  1. 变换过程中的任何错误都可能导致整个命中的丢失。这本身就是巨大的损失。
  2. 谷歌分析跟踪的变化可能会改变整个转型过程。
  3. 转换后的表模式中的任何变化都会导致转换过程在存储新的命中之前发生变化。

在 BigQuery 中直接存储原始命中数据的优势:

  1. 可以直接查询原始数据。
  2. 在转换后的数据或表格中出现任何错误的情况下,回溯变得更加容易。
  3. 您可以随时从原始数据中直接过滤数据点,以便在转换后的版本中包括(或排除)数据点。
  4. 您可以用类似的方式从原始数据中提取任何新的维度或值。
  5. 转换后的表可以随时从原始数据重建。

需要注意的几个要点

实现以上内容将使您能够在 BigQuery 中处理 GA 数据。然而,我想指出的是,在实现数据管道时,应该考虑几件事情。

Google Analytics 自定义维度

并不是所有的东西都通过它的 API 发送到 GA。因此,我建议在你的谷歌分析中实现以下自定义维度,这将丰富你的点击量数据。

  1. 地理定位:获取用户在你的数据集中的位置
  2. 设备类型:每次点击获取设备信息。
  3. 用户代理:这个维度可以让你得到多个其他维度,比如浏览器及其版本。它还可以帮助您过滤垃圾邮件流量,因为垃圾邮件发送者没有用户代理。
  4. 会话 Id :这将有助于按会话分组和过滤你的数据集。发送显式会话 id 有助于简化会话级分析过程。

如果你需要我的帮助来建立这个端到端的数据管道,请在 LinkedIn 上告诉我。

请注意,在 GA 中设置 session-id 维度的传统方式不起作用。与传统方式一样,我们将随机 id 发送给 GA,GA 将收到的最后一个 id 作为会话 id 存储在自定义维度中。在我们的例子中,您必须为整个会话发送相同的 id 值,以便在 BigQuery 中,您可以在会话的每次点击中看到相同的 id。

人口统计信息

由于人口统计信息是从 GA 的后端添加到 GA 中的,所以我们将无法在我们的点击量数据中获得人口统计信息。尽管您可以使用来自 hit 数据集的客户端 id 或用户 id 从 GA 的 API 中提取此类数据。

SQL 查询中的查询参数

上面转换原始数据的 SQL 查询涵盖了 GA hit 拥有的许多参数,但不是全部,比如增强的电子商务的参数。您可能需要根据您的 google analytics 实现来更新查询。

错误

如上所述,如果我们的云函数遇到错误,我们的管道会将命中结果存储在云存储中。云函数中可能会出现错误,原因有很多,其中包括:

  • 已达到 BigQuery 报价限制。
  • 云函数收到了不必要的点击(例如,由于垃圾邮件),这可能会导致我们的代码中出现错误。
  • 由于不需要的架构命中架构,BigQuery 拒绝插入。
  • 可能还有其他不可预见的运行时错误

在任何情况下,这个想法是至少存储 GA 命中,以便我们不会错过它。

云存储中的数据需要根据其存储在云存储中的错误进行处理。

时区

您将不得不更新 SQL 查询,以匹配您的谷歌分析的时间,使数字具有可比性。

GCP 组件限制

云函数和 BigQuery 都有限制,根据你的流量,你可能需要增加两个组件的配额限制。

  • 云函数可以每 100 秒处理 1 亿次调用。
  • BigQuery 接受每个项目每秒 100,000 行。

您还可以在将数据发送到 BigQuery 之前,使用一个中间组件临时批处理数据。

实时数据管道

还可以进行管道转换,并在 Bigquery 中实时存储数据,而不是由调度程序引起的延迟。这个想法是,你从云函数接收到的有效载荷中提取参数,直接发送给 BQ。

如果你使用实时管道,我会建议你仍然存储原始的点击,因为它有助于在事情发生时进行回溯。

结束了

尽管标准的谷歌分析并不提供其点击率数据。通过实现一个简单的数据管道,我们可以在我们的数据仓库中捕获谷歌分析点击。

我们使用 GTM 将 GA 命中结果发送给云函数,云函数将命中结果以原始格式转发给 BigQuery。其中我们利用了一个查询调度器来将原始数据转换成转换格式。这样做允许我们将 Google Analytics 的点击量数据存储在我们的数据仓库中。它可以用于执行任何类型的分析和/或创建我们喜欢的报告。

类似的读数

  1. 使用 GCP 自动将数据导入谷歌分析
  2. 使用 BigQuery ML 执行 RFM 分析

参考

Github 代码

[## muffaddal 52/Send-Google-Analytics-Hits-to-big query

这个回购有代码来帮助发送谷歌分析点击量数据到 BigQuery。它使用了 GTM,云函数,BigQuery 和…

github.com](https://github.com/muffaddal52/Send-Google-Analytics-Hits-to-BigQuery)

用 Python 发送股票数据到你的手机!

原文:https://towardsdatascience.com/send-stock-data-to-your-phone-in-seconds-with-python-39759c085052?source=collection_archive---------61-----------------------

了解如何利用 Python 的力量在股票市场中取胜…

来自 Pixabay3D 动画制作公司的图片

随着股市每天都在快速变化,许多初出茅庐的投资者使用 Robinhood 等移动应用进行交易,不断保持更新是必不可少的,否则就有被落在后面的风险。这正是为什么我创建了这个快速的~150 行 Python 程序,它可以将实时股票数据直接发送到我的手机上,以便于访问。既然对这样一个程序的需求已经很清楚了,那就让我们开始编写代码吧!

导入依赖项并设置参数

首先,我们必须导入将在代码中使用的依赖项,并设置程序正确执行所需的参数。如果有任何模块没有下载到您的机器上,您可以很容易地打开您的终端或命令提示符,并使用 pip 来安装软件包。stock_list 变量必须设置为股票列表,如上所示。开始和结束日期可以更改,但必须保持日期时间格式!

将消息直接发送到您的手机的功能!

为了让代码工作,我们必须用我们的电子邮件更新 email 变量,用相应电子邮件的密码更新 password 变量。对于 sms_gateway 变量,您可以直接进入这个链接,输入您的电话号码,然后复制 SMS 网关地址响应。SMS 网关地址的一个例子是 1234567890@tmomail.net。您也可以根据需要更改文本的主题,但我将它保留为股票数据。

免责声明:您必须在 Gmail 帐户设置中将“允许不太安全的应用程序”设置为开! 这允许 Python 访问您的 Gmail 帐户来发送 SMS 文本消息。如果你有困惑,请按照这个 教程

现在我们已经设置了 sendMessage 函数,我们可以继续实际获取数据了!

收集股票数据并发送消息的功能!

上面的代码由 getData 函数组成,它计算每只股票的不同指标,然后回调 sendMessage 函数向您的手机发送 SMS 消息。

在这个特定的示例中,度量是使用模块 TaLib、NumPy 和 nltk 计算的。它们包括股票的当前价格、当前新闻情绪、beta 值和相对强弱指数(RSI)值。当然,这可以根据您想要接收的数据根据您的喜好进行更改。

程序的最后两行调用 getData 函数,该函数又调用我们不久前创建的 sendMessage 函数。

这就是这个项目的全部内容,如果您对代码的任何部分或任何指标的计算有任何疑问,请随时联系我们。整个程序的所有代码都在下面的 GitHub gist 中!

所有的代码!

请记住在您的 Gmail 帐户设置中将“允许不太安全的应用程序”设置为“开”,这样该程序才能运行!我希望这段代码在将来对你有用,非常感谢你的阅读!

免责声明:本文材料纯属教育性质,不应作为专业投资建议。自行决定投资。

如果你喜欢这篇文章,可以看看下面我写的其他一些 Python for Finance 文章!

[## 使用 Python 在几分钟内解析数千份股票推荐!

了解如何在不到 3 分钟的时间内解析顶级分析师的数千条建议!

towardsdatascience.com](/parse-thousands-of-stock-recommendations-in-minutes-with-python-6e3e562f156d) [## 用 Python 制作股票筛选程序!

学习如何用 Python 制作一个基于 Mark Minervini 的趋势模板的强大的股票筛选工具。

towardsdatascience.com](/making-a-stock-screener-with-python-4f591b198261) [## 在 3 分钟内创建一个财务 Web 应用程序!

了解如何使用 Python 中的 Streamlit 创建技术分析应用程序!

towardsdatascience.com](/creating-a-finance-web-app-in-3-minutes-8273d56a39f8)

使用 Python 通过电子邮件和短信发送新年祝福

原文:https://towardsdatascience.com/send-your-new-year-greetings-by-email-and-text-message-using-python-6222a2836538?source=collection_archive---------14-----------------------

安妮·斯普拉特在 Unsplash 上的照片

有时,开发人员喜欢通过编程解决常规任务来使事情复杂化。我选择使用 Python 编写一些代码来发送我的新年祝福。不是因为容易;这是因为它很难——在某种程度上。不管怎样,编码很有趣!

新年到了。虽然我们开发者一般不会费心维护友情(到底是不是开玩笑?),我们不介意把我们的问候发给我们的朋友,只要有一个程序化的方法来完成这件事!

在这里,我将分两部分向您展示如何使用 Python 通过电子邮件和文本消息发送问候。

第一部分:发送电子邮件问候

Python 有一个名为[smtplib](https://docs.python.org/3/library/smtplib.html)的内置库——一个可以用来创建 SMTP 客户端会话对象的模块,允许我们向任何实施 SMTP 或 ESMTP 的电子邮件服务提供商发送电子邮件。发送电子邮件的另一个有用的模块是email包,它提供了与电子邮件相关的功能,比如读和写。

首先导入相关模块: **smtplib** **email**

为了当前教程的简单性,我们将只发送一封纯文本电子邮件。为此,我们只需要 MIMEText 来创建电子邮件正文。在后面的教程中,我可以向您展示如何发送更复杂的电子邮件(例如,图像附件)。

import smtplib
import email
from email.mime.text import MIMEText

其次,创建发送邮件所需的变量。

在本教程中,我将使用 gmail 帐户发送电子邮件。请注意,您需要更新您的 gmail 安全设置(https://myaccount.google.com/lesssecureapps),以允许您的电子邮件使用 Python 以编程方式发送。

email_host = "smtp.gmail.com"
email_port = 587
email_sender = "" # change it to your own gmail account
email_password = "" # change it to your gmail password
email_receivers = ["xxx@gmail.com", "yyy@gmail.com", "zzz@gmail.com"] # the list of recipient email addresses

第三,起草信息。

接下来,您可以撰写您的邮件。您可以将发件人指定为您自己的电子邮件帐户。对于打算发送的邮件列表,可以使用以下格式:首先,最后,这是邮件收件人的标准格式。

message = MIMEText("I wish you a great 2020.")
message["From"] = ""  # your email account
message["To"] = "John Smith<xxxx@gmail.com>, Mike Dickson<yyyyy@hotmail.com>" # the list of email addresses
message["Subject"] = "Happy New Year"

第四,发送消息。

您使用主机和端口来创建所需的 SMTP 会话。在初始化期间,Python 将通过调用 connect 方法自动建立 SMTP 连接。然后,出于安全原因,我们启动 TLS。

您只需要使用电子邮件帐户和密码来验证您的身份。如前所述,对于 gmail,您必须先放松安全设置,然后才能使用此方法登录。

您可以简单地调用sendmail方法来发送消息并退出会话。

email_server = smtplib.SMTP(email_host, email_port)
email_server.starttls()
email_server.login(email_sender, email_password)
email_server.sendmail(email_sender, email_receivers, message.as_string())
email_server.quit()

第二部分。发送短信问候

实际上,有多种方法可以使用 Python 通过短信发送新年祝福。

方法一。电子邮件发送选项的调整。

你们很多人可能都知道,许多手机运营商允许你用电子邮件发送短信。以下是美国主要航空公司的简短列表。

  • cell-phone-number@txt.att.net 美国电话电报公司
  • 冲刺:cell-phone-number@messaging.sprintpcs.com
  • t-Mobile:cell-phone-number@tmomail.net
  • cell-phone-number@vtext.com 威瑞森

因此,您可以简单地使用 1234567890@txt.att.net 作为电子邮件收件人之一,而不是使用电子邮件地址作为email_receivers变量。

但是,有一个问题,你可能必须知道与该号码相关的运营商。如果你不知道,你可以写一些代码来创造所有可能的变化(如 1234567890@messaging.springtpcs.com,1234567890@tmomail.net),以涵盖所有的可能性。我还听说有付费的第三方服务可以让你查找某个电话号码的运营商。但是我想这对于我们想要完成的目标来说有点过头了。

方法二。通过 AWS 发送

您也可以使用 AWS SNS 发送短信。显然,您需要注册一个 AWS 帐户,这超出了当前教程的范围。可以参考官网(https://AWS . Amazon . com/premium support/knowledge-center/create-and-activate-AWS-account/)。

首先,安装 AWS boto3 模块。

在终端或命令行工具中运行代码(pip install boto3)。boto3 库是为 AWS 相关管理开发的 Python 模块。

其次,用 Python 创建一个 SNS 客户端。

SNS 是一款 AWS 产品,允许开发者向最终用户发送文本消息和其他通信(例如,电子邮件)。

import boto3
client = boto3.client(
    "sns",
    aws_access_key_id="", # your aws access key
    aws_secret_access_key="", # your aws secrete access key
    region_name="us-east-1"
)

第三,创建话题,添加订阅者。

要向多个电话号码发送问候语,您需要创建一个主题,该主题允许您向该主题添加订阅者。每个用户由一个电话号码指定,电话号码还应该包括国家代码(例如,美国为+1),即 E.164 格式。因为我们正在发送消息(即短消息服务或 sms),所以我们将协议指定为sms

topic = client.create_topic(Name="new_year") # create a topic
topic_arn = topic['TopicArn']  # get its Amazon Resource Name# Add SMS Subscribers to this topic
phone_numbers = ["+1234567890"] for phone_number in phone_numbers:
    client.subscribe(
        TopicArn=topic_arn,
        Protocol='sms',
        Endpoint=phone_number
    )

第四,发布消息给题目。

将订阅者添加到主题后,就可以向主题发布消息了。您只需要提供消息,并指定要发布该消息的主题。通过这样做,所有的用户都将收到文本消息。

client.publish(Message="Happy New Year!", TopicArn=topic_arn)

方法三。通过 Twilio 发送

您也可以选择使用 Twilio 发送短信。当然,它需要一个 Twilio 帐户,可以免费注册,类似于 AWS 帐户。一旦您创建了 Twilio 帐户,我们就可以开始玩游戏了!

首先,安装 Twilio 模块。

运行命令pip install twilio安装 Twilio 模块,这将使您能够访问 Twilio 提供的各种功能。短信只是其中之一。

其次,用 Python 创建一个 Twilio 客户机

Cilent方法将用于通过获取您的 Twilio 帐户 SID 和 AUTH Token 来创建 Twilio 客户端,这两者都可以在您的 Twilio 帐户的仪表板上找到。

from twilio.rest import Clientclient = Client(
    "", # your Twilio Account SID
    "", # your Twilio AUTH token
)

第三,创建和发送消息。

您创建了一个列表,列出了您要发送新年祝福的所有电话号码。请再次注意,电话号码使用 E.164 格式,类似于 AWS SNS 的使用。

一个问题是,使用免费的 Twilio 帐户,你只能向你验证过的电话号码发送短信,与 AWS SNS 相比,你的灵活性较低。但是,您可以升级您的 Twilio 帐户,这样您就可以选择以非常低的成本(每条消息不到 1 美分)向您选择的多个电话号码发送消息。

phone_numbers = ["+1234567890", "+1234567891"] # the list of phone numbers to receive the messagesfor phone_number in phone_numbers:
    client.messages.create(
        to=phone_number,
        from_="", # your Twilio phone number
        body="Happy New Year!"
    )

结论

通过学习本教程,您应该已经为每个作业创建了多个 python 脚本。以后,你可以使用这些脚本非常方便地发送电子邮件和短信。

所以实际上,编程确实使某些事情变得更容易,不是吗?

通过串行蓝牙从 Raspberry Pi 传感器单元发送数据

原文:https://towardsdatascience.com/sending-data-from-a-raspberry-pi-sensor-unit-over-serial-bluetooth-f9063f3447af?source=collection_archive---------6-----------------------

一个关于如何使用蓝牙将信息从树莓派发送到手机、平板电脑或便携式笔记本电脑的教程。

塞缪尔·切纳德在 Unsplash 上的照片

介绍

在构建便携式传感器时,我们通常希望在允许它们远程记录数据之前校准并仔细检查它们的读数。在开发它们的时候,我们可以很容易地 SSH 到它们,并把任何结果写到屏幕上。然而,当我们在世界上一个非常偏远的地方,没有笔记本电脑,无线网络或信号,会发生什么?

在本教程中,我们将探讨如何利用 Raspberry Pi Zero(无 WiFi)的蓝牙功能将初始结果传输到我们选择的手持设备。在我们的情况下,将通过使用手机或 android 平板电脑,这样我们就可以比较传感器和 GPS 读数。

安装和设置

在我们开始之前,蓝牙需要做一些改变。这些概述如下。

配置设备蓝牙

我们从更改已安装的蓝牙库的配置开始:

sudo nano /etc/systemd/system/dbus-org.bluez.service

在这里,我们找到从ExecStart开始的行,并用以下内容替换它:

ExecStart=/usr/lib/bluetooth/bluetoothd --compat --noplugin=sap
ExecStartPost=/usr/bin/sdptool add SP

添加了“兼容性”标志后,我们现在必须重新启动 Pi 上的蓝牙服务:

sudo systemctl daemon-reload;
sudo systemctl restart bluetooth.service;

配对我们的监控设备

为了防止在野外配对蓝牙设备时出现问题,预先配对设备总是一个好主意——保存它们的配置。

为此,我们按照下面链接中描述的过程使用bluetoothctl:

[## 使用终端配对蓝牙设备

在使用 raspberry pi zero 时,您会受到 USB 端口的限制。而不是总是有一个 USB 集线器连接到…

medium.com](https://medium.com/cemac/pairing-a-bluetooth-device-using-a-terminal-1bfe267db35)

  1. 找到我们的主机 MAC 地址
hcitool scan

这将产生以下格式的结果:

Scanning ...XX:XX:XX:XX:XX:XX device1XX:XX:XX:XX:XX:XX device2

2.选择我们想要的设备并复制其地址。

3.执行以下操作:

sudo bluetoothctl

4.在蓝牙控制台中运行以下 3 个命令(替换您复制的地址):

discoverable on# thenpair XX:XX:XX:XX:XX:XX# and trust XX:XX:XX:XX:XX:XX# where XX corresponds to the address copied from above

配对时,可能会要求您确认两台设备上的 pin。trust将设备地址保存到信任列表。

要使 PI 在启动时可被发现,您可以查看下面的代码:

[## 保持蓝牙可被发现(RPI / Unix)

如何从开机就启用蓝牙可见性和配对?

medium.com](https://medium.com/cemac/keep-bluetooth-discoverable-rpi-unix-bbe1c9ecbdb6)

启动时启用通信

最后,我们希望告诉设备在启动时注意蓝牙连接。为此,我们可以将以下文件添加到/etc/rc.local(在exit命令之前)。

sudo rfcomm watch hci0 &

注意在末尾加上&符号,否则,它会停止设备的启动过程。此外,如果您正在通过串行读取另一个设备,例如 GPS 接收器,您可能希望使用rfcomm1而不是hci0 (rfcomm0)

从另一台设备连接到蓝牙串行接口

根据您使用的设备,读取串行监视器的方法会有所不同。在 android 设备上,您可以采用 node/javascript 方法(这应该适用于所有操作系统!).出于演示的目的,我将描述一种使用 python 来检查 MacBook Pro 上的工作情况的方法。

确定端口名称

如果你有一个终端,最简单的方法就是输入

ls /dev/tty.

然后点击 tab(自动完成)按钮。

假设你没有改变这一点,这应该是你的设备hostname后跟串行端口。新安装的 raspberry pi 的默认串行端口路径应该是

/dev/tty.raspberrypi-SerialPort

读取接收的数据

为了读取接收到的任何数据,我们可以使用 python serial库和下面的代码片段。

import serialser = serial.Serial('/dev/tty.raspberrypi-SerialPort', timeout=1, baudrate=115000)serial.flushInput();serial.flushOutput()

while True:
    out = serial.readline().decode()
    if out!='' : print (out)

请注意,这是一个无限循环,不断打印它接收到的任何内容。要在收到“退出”消息时取消它,我们可以使用:

if out == 'exit': break

从传感器发送数据

从壳里

测试时,发送数据最简单的方法是从 raspberry pi shell 将数据回显到/dev/rgcomm0。这允许我们在编写更复杂的东西之前,手动测试端口上的通信。

echo "hello!" > /dev/rfcomm0

来自 python 脚本

如果从 raspberry pi 读取数据并对其进行预处理,我们很可能会使用 python 来完成繁重的工作。从这里我们可以将rfcomm0 通道视为一个文件,并按如下方式写入:

with open(‘/dev/rfcomm0’,’w’,1) as f:
     f.write(‘hello from python!’)

结论

如果我们想快速检查传感器在野外的表现,我们可以利用 Raspberry Pi 的蓝牙功能。这是通过创建一个蓝牙串行端口并通过它发送数据来实现的。如果我们不想携带笨重的笔记本电脑,或者在 WiFi 网络被占用或不可用的情况下,这些方法特别有用。

更复杂的任务,比如向 Raspberry Pi 发送命令,甚至通过蓝牙进入它也是可能的,但是超出了本教程的范围。

敏感性、特异性和有意义的分类器

原文:https://towardsdatascience.com/sensitivity-specificity-and-meaningful-classifiers-8326738ec5c2?source=collection_archive---------37-----------------------

解释冠状病毒检测时有时会混淆的概念

肯德尔Unsplash 上的照片

我们如何评估机器学习分类器或测试模型的表现?我们如何知道一项医学测试是否足够可靠,可以用于临床?

虽然高度准确的冠状病毒检测在发病率较高的地方可能有用,但为什么它在发病率较低的人群中信息较少?这听起来违反直觉,令人困惑,但确实可以应用于确定您自己的二元分类器的效用!

我们通过测量测试的特异性和敏感性来定义测试的有效性。很简单,我们想知道该测试多久识别一次真阳性和真阴性。

我们的灵敏度描述了我们的测试捕捉所有阳性病例的能力。灵敏度的计算方法是将真阳性结果的数量除以阳性总数(包括假阳性)。

我们的特异性描述了我们的测试如何将阴性病例归类为阴性。特异性的计算方法是将真阴性结果的数量除以阴性总数(包括假阴性)。

费安多/CC BY-SA(https://creativecommons.org/licenses/by-sa/4.0)

重要的问题是一个模型是否有意义?仅仅依靠敏感性和特异性是不够的!为了确定一项检测对一个人群的意义或临床用途,我们需要关于疾病的预期发病率或流行率的基础信息。我们使用贝叶斯定理来理解这一点:

我们有 1 00 万人口,其中 10%的人患有某种疾病。我们使用一种非常可靠的测试,具有 98%的特异性和敏感性。在这里,事件 A 描述了这种疾病在人群中的无条件概率。 P(A) = 0.10

事件 B 是我们测试结果为阳性的无条件概率。我们可以通过查看我们将得到的总阳性数来计算 P(B) 。在该人群中,我们预计有 98 000 例真阳性,通过将发病率乘以总人群和敏感性计算得出。对于假阳性,我们取不患这种疾病的概率 (0.90) ,乘以人群和(1-特异性)。所以在这种情况下我们得到了 18 000 个误报。我们的总阳性率是 11.6%。

现在事情变得有点复杂了。所有这些值描述了该测试对于该人群的准确性。但是它没有告诉我们一个检测呈阳性的人患这种疾病的几率。我们需要应用贝叶斯定理,使用这些无条件值作为我们的先验假设。

由你友好的邻居作者创作

那么,如果有人检测结果呈阳性,那么这种疾病存在的概率是多少?

这里我们可以开始定义我们的变量。

  • P(A) = 0.10
  • P(B) = 0.116
  • P(B|A) 描述得到阳性结果的概率,不管它是否是真阳性,而 P(A)是疾病的存在。因此 P(B|A)是我们的灵敏度。 P(B|A) = 0.98。
  • P(A | B)= 0.98 * 0.1/0.116 =84.5%

因此,我们在这里看到,即使有很高的灵敏度和特异性,该测试在某些人群中可能不准确。使用贝叶斯定理,我们可以很容易地计算出来。

如果这种疾病在我们的人口中不那么常见,会发生什么呢?回想一下,灵敏度和特异性保持在 98%。

  • P(A) = 0.01
  • P(B) =(真阳性+真阴性)/总人口=(0.01 * 0.98+0.02 * 0.99)/10000000 =(9800+19800)/1000000 = 0.0296
  • P(A | B)= 0.98 * 0.01/0.296 =33.1%

由于这种疾病现在越来越少,当你患病时,获得阳性检测结果的后验概率更低。随着人群中疾病患病率的下降,我们的阳性预测值也在下降!

生成生物医学测试或另一个二元分类模型时,请记住它可能有用的时间。看看我们的测试对我们的特定人群有多有效,因为疾病的患病率足够低——这可能不是很有用!

因此,如果您正在为一般人群中可能罕见的事物生成分类器,您需要非常高的灵敏度和特异性,以获得高阳性预测值!

基于传感器的物联网预测性维护——为什么数字信号处理是机器学习的必备条件

原文:https://towardsdatascience.com/sensor-based-iot-predictive-maintenance-why-digital-signal-processing-is-must-for-machine-880e30df5804?source=collection_archive---------32-----------------------

DSP+AI 工作流程。@版权

工厂由几种类型的资产组成。基于传感器的物联网用于资产诊断和预测。机器资产的旋转部件经常遭受机械磨损。如果没有对这种磨损进行监控,可能会导致机器故障和工厂意外停机。除了机械故障,机器也可能出现电气故障。因此,这些机器的状态监控对于早期故障检测非常重要,以避免计划外维修,最大限度地减少停机时间,从而保证机器的可靠性、正常运行时间和可持续性。几种非侵入式机器状态监控技术使用传感器。大多数是基于感应电流、振动、机器的声发射[2]。为了获得这些信号,需要传感器。远程监控需要物联网管道到位。

设备(电气和非电气)的状态监控是工业物联网工业 4.0 的主要要求之一。虽然基于传感器的数据驱动解决方案看起来像一个机器学习问题,但它不可能用 ML 解决组件级诊断。例如,感官数据可能有噪声;并且根据 SNR,传统的 ML 方法将训练噪声而不是所需的信号本身。另一个问题是,如果没有像傅立叶、小波、时间-频率、希尔伯特等的信号变换,时域数据签名不能区分、隔离或理解机器的下划线问题。

小齿轮故障电机的时域振动特征(时间序列)

在上面的例子中,小齿轮故障数据显示在时域中。当在 ML 上训练时,信号将很难推断出任何东西,因为它不能区分噪声和异常。在动态负载和噪声下,阈值方法也不是一个好主意。

通过对信号进行傅立叶变换,我们可以绘制出指向机器中特定异常的许多特征。由于模式具有不同的特征,这种方法是无监督的并且不需要大量历史数据来创建推断。

时域签名的频谱能够识别带有互调的小齿轮问题

让我们看看电梯系统振动的另一个例子。正常操作和异常模式特征之间的差异在谱域中清晰可见。

正常和异常操作的频谱@版权所有

该系统的时域特征不能区分正常和异常模式。低频谐波尖峰在频谱域中清晰可见。

另一个例子是门操作的声学频谱图。该信号包含门的各种操作,并且可以使用信号处理来识别某些操作并创建退化模型。

不同签名的时域门操作及其谱图@版权所有

什么是数字信号处理

看完上面的例子,让我们先来识别什么不是 DSP。嗯,数字 信号处理不是 关于傅里叶变换(FFT)或者 FFT 不是 DSP 在数据科学界被广泛误解。数字信号处理领域有数百种算法。另一个趋势是统计学和信号处理的融合——统计信号处理。它应用 ML 和信号处理来推导推论。

下表显示了一些选定的算法

表 1-信号处理的几种算法@版权所有

在下面的示例中,数字滤波器应用于 ISO 规范定义的特定截止频率,以滤除特定频率成分的噪声信号。否则使用移动平均线是不可能实现的。数据是电梯在 100 赫兹时的 3 个轴向加速度曲线。

ISO 标准巴特沃兹低通滤波器应用于振动信号@版权所有

数字信号处理和模拟信号处理是工程中处理传感器信号的两个分支。DSP 应用包括音频和语音处理、声纳、雷达和其它传感器阵列处理、频谱密度估计、统计信号处理、数字图像处理、数据压缩、视频编码、音频编码、图像压缩、电信信号处理、控制系统、生物医学工程和地震学等。

DSP 可能涉及线性或非线性运算。非线性信号处理与非线性系统识别密切相关,可以在时域、频域和时空域中实现。[1]

如何使用 DSP 进行 AI/ML

DSP 有两种应用方式。

基于 DSP 的数据转换—

在这种方法中,DSP 被简单地用作 ETL 工具。转换后的数据用作数据集的另一个要素。ML/AI 的下游块在统计意义上消耗数据,并学习下划线模式以得出推断。大多数数据科学家都使用这种方法,但是在许多用例中,由于缺少领域推理和对转换理解,这种方法并不理想。

基于 DSP 的设计和推理-

在这种方法中,使用 DSP 对数据进行预处理/转换到其他域,但是使用 DSP 的域知识来导出进一步用于增强下游 AI/ML 算法的推理。在这里,对信号和系统的深刻理解是创建最佳 ML 模型的先决条件。

在用例中,需要对资产的内部组件进行诊断——不仅仅是趋势——那么这种方法是强制性的。如图 1 所示,原始 ML 或 DSP 无法将齿轮-小齿轮问题检测为 ETL + ML。我们需要了解谐波的含义、频带中能量的含义、噪声水平、衰减、相位关系、区分信号和噪声的能力等。这适用于几乎所有的资产类别——电机、泵、压缩机、发电机、输送机、发动机等。

物联网传感器应用的 DSP 和 AI 工作流程

DSP+AI 工作流程。@版权

基于 DSP 的人工智能应用的工作流程如上图所示。

数据采集过程

这个过程对于任何应用都是最关键的。选择传感器类型、传感器规格、采样频率、模数转换、传感器接口的决策对诊断和预测性维护最终目标的成功起着至关重要的作用。

我在下图中强调了传感器接口的一些关键组件。在这个过程中,我分析了一些供应商,所以他们的名字是可见的。然而,市场上有许多具有不同规格的参与者,特定组件的选择取决于感兴趣的机器/源的许多领域相关规格和最终目标。

许多现成的智能传感器提供商已经集成了 ADC、接口和连接。

传感器接口规范@版权所有

接下来是 DSP 的关键模块,如前所述,该模块执行信号处理操作,从滤波、变换到多个域,如表 1 所示

DSP 之后是特征工程部分,从转换后的数据中提取特征。这些要素是对数据集中原始要素的补充,提供了对数据的深刻见解,否则这是不可能的。

接下来我们分成两个分支。在领域特定路径中,我们从领域角度推断通过多重转换得到的签名,并从中导出诊断模型。进一步向下,具有诊断特征的高级模型训练可用于训练 AI 模型,以导出 RUL 和其他预测性维护相关的度量。

另一条路径是基于统计推断的方法,用于为模型构建提供额外信息,但本质上是纯统计的。

结论

我们了解了什么是数字信号处理,以及它对基于物联网传感器的用例有何意义。

我们看到了传统的基于统计的人工智能建模和基于信号处理的方法之间的差异。

我们看到传感器接口规格涉及上游和下游集成、ADC、采样速率、连接性。

我们讨论了基于 DSP 的人工智能工作流。

参考

  1. https://en.wikipedia.org/wiki/Digital_signal_processing
  2. 使用压缩信号处理、Meenu Rani、Sanjay Dhok 和 Raghavendra Deshmukh 传感器的机器状态监控框架。
  3. 数字信号处理:原理、算法和应用,J.Proakis,2007。
  4. 统计信号处理基础,第三卷:实用算法开发。
  5. 智能传感器与系统— 2015,林永龙,等人,施普林格。

基于迁移学习的句子正确性分类器

原文:https://towardsdatascience.com/sentence-correctness-classifier-using-transfer-learning-with-huggingface-bert-8884795ba5ca?source=collection_archive---------24-----------------------

学习简单地使用 huggingface 构建生产级 NLP 应用程序

来源-https://blog . Rosetta . ai/learn-hugging-face-transformers-Bert-with-py torch-in-5-minutes-acee 1 e 3 be 63d?gi=ec612e84d08d

下面是 链接直播仪表盘

在本文中,我们将利用自然语言处理领域的最新突破,构建一个接近艺术水平的句子分类器。我们将重点关注迁移学习在 NLP 中的应用,以在一系列 NLP 任务中以最小的努力创建高性能模型。

介绍

在过去两年左右的时间里,与应用深度学习的其他领域相比,NLP 的研究一直非常迅速。Allen AI 的 ELMO、OpenAI 的开放 GPT 和谷歌的 BERT 等模型允许研究人员在特定任务中以最小的微调打破多个基准。因此,NLP 研究复制和实验变得更加容易。

伯特

谷歌研究人员在 2018 年底发布的 BERT(来自变压器的双向编码器表示)是我们将用来训练句子分类器的模型。

我们将在预训练的 BERT 模型上使用迁移学习。这种方法比从零开始训练像 GRU 或 LSTM 这样的深度模型要好,因为:

  • 预先训练的 BERT 模型权重已经编码了许多关于我们语言的信息。因此,训练我们的微调模型所需的时间要少得多。我们将使用超参数扫描来训练我们的模型,以便在 colab 上在一个小时内找到最佳组合,而在 GPU 上从头训练单个深度 RNN 模型将需要数百个小时以上!
  • 因为我们本质上是在进行迁移学习,所以我们需要少得多的数据来建立一个精确的系统。与从头开始训练一个模型所需的数百万个数据点相比,我们只需要几千个数据点就可以完成同样的任务。

图片来源—https://towards data science . com/Bert-explained-state-of-art-language-model-for-NLP-F8 b 21 a9b 6270

基于 transformer network 的 BERT 是一个双向网络,它为建模、分类等各种任务生成语言编码。

谷歌表示,BERT 有助于更好地理解搜索中单词的细微差别和上下文,并更好地将这些查询与更相关的结果匹配起来。它也用于特色片段。这里有一个例子。

图片来源——blog.google.com

让我们看看这个模型的另一个令人兴奋的应用,即句子分类。

正在安装 Huggingface 库

现在,我们将快速进入培训和实验,但如果你想了解更多关于环境和数据集的细节,请查看克里斯·麦考密克的本教程

让我们首先在 colab 上安装 huggingface 库:

!pip install transformers

这个库带有各种预先训练的艺术模型。对于我们的句子分类,我们将使用BertForSequenceClassification模型。

可乐数据集

我们将使用语言可接受性语料库(CoLA) 数据集进行单句分类。它是一组被标记为语法正确或不正确的句子。它于 2018 年 5 月首次发布,是“GLUE Benchmark”中包括的测试之一,BERT 等模型正在进行竞争。

让我们下载并解压缩数据集

如果一切执行无误,您将获得以下文件:

如你所见,我们已经有了数据集的标记化版本,但我们需要再次标记它,因为为了应用预训练的 BERT,我们必须使用模型提供的标记化器。这是因为:

  • 该模型具有特定的、固定的词汇表,并且
  • BERT 记号赋予器有一种特殊的方式来处理词汇表之外的单词。

解析数据集

让我们通过使用 pandas 解析数据集来看看数据集的格式

这里需要注意一些事情:

  • 我们只有 8551 个数据点,通过使用迁移学习来训练 SOTA 深度模型。
  • 我们关心的属性是句子和 it 标签
  • 可接受性判断,其中 0 =不可接受,1 =可接受。

最后,我们来列出这些句子。

标记化

如前所述,要输入到 BERT 模型中的句子必须使用 BERT 记号化器进行记号化。让我们看一个例子。

Using this tokenizer on a sentence would result into something like this:Original:  Our friends won't buy this analysis, let alone the next one we propose.Tokenized:  ['our', 'friends', 'won', "'", 't', 'buy', 'this', 'analysis', ',', 'let', 'alone', 'the', 'next', 'one', 'we', 'propose', '.']Token IDs:  [2256, 2814, 2180, 1005, 1056, 4965, 2023, 4106, 1010, 2292, 2894, 1996, 2279, 2028, 2057, 16599, 1012]

在我们使用这个记号赋予器处理整个数据集之前,我们需要满足几个条件,以便为 BERT 设置训练数据:

  • 在每句话的开头和结尾添加特殊标记。在每句话的末尾,我们需要添加特殊的[SEP]标记,对于分类任务,我们必须在每句话的开头添加特殊的[CLS]标记。
  • 填充和截断所有句子,使其长度保持不变
  • 明确区分真实标记和带有“注意掩码”的填充标记。“注意屏蔽”只是一个由 1 和 0 组成的数组,表示哪些标记是填充的,哪些不是

以下是经过所有预处理后,网络架构如何对特定输入进行操作。

图片来源—http://www.mccormickml.com/assets/BERT/padding_and_mask.png

第一个任务是决定一个句子的最大长度。

输出

Max sentence length:  47

为了遵循大小应该是 2 的幂的一般惯例,我们将选择最接近的 2 的幂的数字,即 64。

现在,我们准备执行真正的标记化。但是当我们使用变压器时,我们可以使用一个内置函数 tokenizer.encode_plus ,它可以自动完成以下所有任务:

  1. 把句子分成几个标记。
  2. 添加特殊的[CLS]和[SEP]标记。
  3. 将令牌映射到它们的 id。
  4. 将所有句子填充或截短至相同长度。
  5. 创建注意屏蔽,明确区分真实令牌和[PAD]令牌。

我们将把数据分成训练集和测试集。将我们的训练集划分为 90%用于训练,10%用于验证。

加载数据

接下来的步骤需要我们猜测各种超参数值。我们将通过扫描所有参数的所有值组合来自动完成这项任务。为此,我们将在开始训练循环之前初始化一个 wandb 对象。当前运行的超参数值保存在 wandb.config.parameter_name 中。

这里,我们使用 RandomSampler 对训练集进行采样,使用 SequentialSampler 对验证集进行采样。

建立培训模型

我们将使用经过预先训练的机器人进行序列分类。我们将添加单个密集或全连接图层来执行二进制分类任务。我们将把程序的每个部分作为一个独立的功能块。

num_labels 参数描述了最终输出神经元的数量。

我们将使用由 huggingface 提供的内置权重衰减机制的 Adam 优化器的实现。学习率将由 wandb.config 提供

我们还将初始化一个学习率调度程序来执行学习率衰减。训练时期也是一个超参数,所以我们将使用 wandb.config 来初始化它。

初始化权重和偏差

在我们训练我们的模型之前只剩下一步了。我们将设置一个配置文件,列出一个超参数可以取的所有值。然后,我们将初始化我们的 wandb sweep 代理,以记录、比较和可视化每个组合的性能。

我们希望最大化的指标是 val_accuracy ,我们将在训练循环中记录它。

在 BERT 论文中,作者描述了执行迁移学习的最佳超参数集,我们对超参数使用了相同的值集。

现在我们有了运行扫描所需的扫描 id。我们现在只需要一个 train 函数,它将在每次扫描中被重复调用。

训练模型

选择最佳模型超参数

在运行 wandb 扫描时,除了我们手动记录的图像之外,您还会获得一些自动可视化图像。现在是做扣除的时候了。

关于模型性能的一些最重要的信息可以直接从参数相关图中推导出来。

Wandb 的平行坐标图-报告中的链接

在这里,我们可以看到在最大化验证准确性的任务中所有运行是如何执行的。我们可以推断出最佳的超参数组合是批量为 16,学习率为 3e-5,训练 3 个时期,这将导致大约 84%的准确率。

如果您想要一个更简单的可视化,只比较每次运行所用的时间以及它在优化所需指标方面的表现,您可以参考仪表板中的另一个有用的可视化,它比较验证准确性与特定运行的时间。

现在,让我们看看我们记录的指标的可视化效果。

扫描中每次运行的分批列车损失

扫描中每次运行的平均验证损失

扫描中运行的平均训练损失比较

多次运行记录的验证准确度的比较

现在,您已经有了在最佳超参数值集上训练的 BERT,用于执行句子分类以及支持参数选择的各种统计可视化。

这篇文章演示了使用预训练的 BERT 模型,您可以根据您感兴趣的特定 NLP 任务,使用 huggingface 界面通过最小的微调和数据快速创建模型。

我希望这是一本好书。本文中的所有结果都可以使用这个 colab 笔记本重现,并且可以在这个 wandb 扫描页面中查看比较各种运行的可视化效果。

句子嵌入与 CoreNLP 的递归情感模型

原文:https://towardsdatascience.com/sentence-embeddings-and-corenlps-recursive-sentiment-model-d88af7f7b4f5?source=collection_archive---------32-----------------------

入门

理解并实现 CoreNLP 的情感模型。

你好。几周前,我发布了关于库 coreNLP和更具体的情感分析模型的系列文章** 的第一篇。第一篇文章是对 Java 包及其主要特性的介绍,特别针对像我这样习惯于使用 Python 的人。正如所承诺的,本系列的第二篇文章将更深入地探讨 CoreNLP 的情感注释器:为什么它不是你常用的情感分类器,它背后的递归模型,以及如何用一些简单的 Java 脚本来实现它(你可以在我的 github 上找到它!).**

我想,在我开始之前,我应该警告读者:⛔️这篇文章很少谈到情感分析和很多关于句子嵌入的⛔️.不要害怕,希望在你阅读的时候这对你有意义!

梁杰森Unsplash 上的照片

让我们从…谷歌一下 CoreNLP 情绪模型开始!当点击进入 coreNLP 情感分类器的官方页面时,我们发现了以下描述

大多数情绪预测系统的工作原理只是孤立地看单词,对正面单词给出正面分,对负面单词给出负面分,然后将这些分相加。那样的话,单词的顺序会被忽略,重要的信息也会丢失。相比之下,我们新的深度学习模型实际上基于句子结构建立了整个句子的表示。它根据单词如何组成更长短语的意思来计算情感。这样模型就不像以前的模型那么容易被忽悠了。

看完这一段,我们已经可以分辨出两件事:

  1. 这不是一个普通的情绪预测器,而是更有趣的东西(可能更有效!)
  2. 这个模型和其他情感模型之间的核心区别似乎不是分类器本身,而是输入文本的表示(T2)。

第二点已经揭示了这篇文章的中心主题:文本表示。为了深入了解为什么 CoreNLP 的情感模型如此强大和有效,我们首先需要理解恰当地表示输入文本的重要性。而这就是我们下面要讲的!

我先介绍一下文本表示的复杂性(我称之为语义建模)是什么,以及 word2vec 等知名单词嵌入模型的局限性 。然后我将谈论语义组合性的概念以及 coreNLP 如何使用它来创建一个非常强大的递归情感分析模型。最后,我将给出一个 Java 中的简单实现的例子。我们走吧!****

文本表示或语义建模

我喜欢把语义建模想成这样:人类可以阅读和理解一系列字母和符号(就像这句话),然而,ML 算法只能理解数字序列。为了让情感分类器或任何其他模型处理文本,必须将文本从人类可读形式翻译成计算机可读形式。

原来有许多方法来表示文本:作为一个单词包,一个热编码,基于逻辑的框架,嵌入空间上的语义向量…并且重要的是选择最好的一个,因为这将直接影响你的模型的性能。想想看:如果模型连输入的文本都不能理解,我们怎么能指望它去分类呢!

在我上面提到的所有语义建模技术中,语义向量的使用被认为是 NLP 文献中首选文本表示选项之一。特别是,近年来,单词嵌入已经成为一种非常流行的方法并引起了很多关注。想想 word2vecGloVeFastText

  • 单词嵌入及其局限性

单词嵌入是建立在这样一个理念上的:从语境中推断出一个给定单词的意思是可能的(Mitchell and la pata,2010)。

在这个框架中,单词** 基本上由向量来表示,这些向量携带特定单词的潜在语义信息(Socher,2013)。图 1 表示简单的语义二维空间。请注意,相似的单词看起来更接近。**

图 1 (Mitchell 和 Lapata,2010 年,图 1,第 1390 页)语义向量空间中表示的单词。它们之间的接近表明语义相似。

然而,尽管它们被广泛使用,当我们对计算一个短语或句子的表示感兴趣时,这些模型的局限性变得非常明显。单词嵌入模型只能孤立地表示单词并且不能说明它们之间的句法和语法关联。

当我们想要表示一个句子,但是我们只有它的单词的嵌入时,更常用的解决方案之一是平均它的单词向量以获得一个句子向量。这种方法已经被证明在某些情况下足够有效,但是我个人认为它非常简单,因为句子的特定句法、语法和依赖性都被忽略了。

  • 复合性

作为一个有语言学和文学背景的人,在做文本分析时考虑句法、语法和词序是我甚至不会质疑的事情!!在亲身经历了单词嵌入的局限性之后,我偶然发现了语义组合的原则,并开始思考将它应用到语义建模任务中会有多酷。这项原则规定:

“一个(句法上复杂的)整体的意义只是它的(句法)部分的意义以及这些部分组合的方法的函数”(Pelletier,1994 年,第 11 页)。

NLP 文献中,弗雷格原理最常见的解释和使用是作为一个理论基础它规定一个人应该能够根据短语来解释一个完整句子的意思,同样,也应该能够根据单词来解释这些短语。****

因此,当涉及到语言的表示时,建模者应该意识到每个句法操作额外隐含了一个语义操作** (Mitchell and Lapata,2010)。Partee (1995,第 313 页)正式提出了表达两个元素 uv 的组合的公式 1 ,其中 f 是作用于两个成分的组合函数R 说明了 uv 之间的句法关系(Mitchell and Lapata**

公式 1 (Mitchell 和 Lapata,2010 年,第 1393 页)

在单词嵌入的基础上,一些作者试图包含不同的组合方法,目的是嵌入语言的各个方面,如词序和句法(Socher,2013)。这方面的一个例子是理查德·索赫尔和他的递归模型。

用于句子嵌入的递归神经网络

当我了解到 Socher 的工作时,我变得非常兴奋,因为他基本上是在试图将这种作曲的想法融入到他的模型中,以构建一种更完整的嵌入句子的形式。为此,他提出了一种基于递归神经网络(RecNN)的新方法。****

该模型基于这样的思想:从更简单的元素(即单词)开始计算句子嵌入,然后以自下而上的方式递归使用相同的合成函数。这种分解句子然后以递归的、自下而上的方式构建句子的方式将允许最终输出更好地捕捉关于句子的语义、句法和情感的复杂信息。我觉得这太酷了!****

  • 型号概述

现在,我将概述一下 Socher 等人(2013) 提出的方法背后的直觉。图 2** 展示了构建递归模型的组合思想的简化版本。在本节中,我将使用这个三元组作为例子。**

图 2 将句子及其内部元素描述为解析树的节点。这种解析树被称为二进制,因为每个父节点只有两个子节点。RecNN 模型的基本元素是树的叶子,因此处理从将句子分割成单词和计算每个单词的单词嵌入量开始。在上面的例子中,第一步是分别计算单词“not”、“very”和“good”的表示法 abc

图 2 (Socher 等人,2013 年,图 4,第 4 页)

随后,这些单词表示中的两个将被配对,以便计算一个更高级别的短语表示。计算将由合成函数完成。在图 2 中, p 1 是通过将组合函数 g 应用于单词嵌入 bc 来计算的。

这种用于配对节点的组合方法将自底向上递归重复,直到到达树的根。在图 2 中,根节点是 p 2,它是通过将组合应用于单词嵌入 a 和短语嵌入 p 1 来计算的。根节点是树中最高的节点,通常代表完整的句子

值得注意的是,在本例中,组合函数 g 对于两个组合是相同的。类似地,对于更长的句子,合成函数将始终保持不变,并将始终将任何一对向量作为输入。这些向量可以表示任何级别的任何节点(例如,单词、子短语、短语),但是它们必须总是具有相同的大小。当组合向量 bc 时,组合 p 1 的输出也将具有与 bc 相同的维数。同样的,组合 ap 1 的输出 p 2 也将具有相同的大小。为了允许递归使用相同的复合函数,这是基本的。

  • Sooo,感情在哪里?

你可能想知道这其中的情绪在哪里!

****使用 softmax 分类器在每个节点实际预测情感,该分类器使用节点向量作为输入特征。这在图 2 中由从节点 cp1p2 出现的彩色圆圈表示。

此外,情感分类是多标签,因此情感得分将在 0-4 之间变化:0 表示非常负面,1 表示负面,2 表示中性,3 表示正面,4 表示非常正面。

在树的根节点预测的情感将是分配给特定句子的最终情感。在图 2 的例子中,我们可以看到根节点被归类为否定,因此整个句子将是否定的。****

实施

我现在将呈现一个非常简短的前一篇文章的脚本扩展,以便通过情感分类器运行一些输入文本,并获得一些关于预测输出的指标。

第一步是将解析情感包含在我们的注释器列表中(我们需要解析来运行情感分析)。

// set the list of annotators to run
props.**setProperty**("annotators", "tokenize,ssplit,pos,lemma,ner,depparse,parse,sentiment");

这样,我们知道输入文本现在将通过情感预测器,因此我们只需检索结果。我们首先想知道特定句子的最终情感得分是多少(在根节点的预测)。

**Tree** tree = sentence.**sentimentTree**();//get overall score
**int** sentimentScore = RNNCoreAnnotations.**getPredictedClass**(tree);//print score to terminal 
System.out.println("Final score " + sentimentScore );

我们这样做是为了将最终得分保存在一个名为 sentimentScore 的变量中。这个数字总是 0、1、2、3 或 4。

此外,我们想知道预测者分配一个句子属于每个类别的概率是多少。我们通过以下方式获得此类信息:

**SimpleMatrix** simpleMatrix = RNNCoreAnnotations.**getPredictions**(tree);//Gets probability for each sentiment using the elements of the sentiment matrix**float** veryneg = (float)Math.round((simpleMatrix.**get**(0)*100d));
**float** neg = (float)Math.round((simpleMatrix.**get**(1)*100d));
**float** neutral = (float)Math.round((simpleMatrix.**get**(2)*100d));
**float** pos = (float)Math.round((simpleMatrix.**get**(3)*100d));
**float** verypos = (float)Math.round((simpleMatrix.**get**(4)*100d));

概率将存储在变量 verynegnegnearyposverypos 中。

现在让我们运行整个文件coreNLP _ pipeline 3 _ LBP . Java来获得一个示例输出。我们将使用以下文本作为输入,以便观察预测中的变化:“这是一个可怕的句子。我太喜欢这句话了!这是正常的一句话”。该文本保存为 coreNLPinput_2.txt 。使用以下命令运行脚本:

java -cp "*" coreNLP_pipeline3_LBP.java

一手牌的结果将打印在终端上,如下图所示。我们可以观察到分配的分数(“最终分数”)对句子有意义:否定、肯定和中性。我们也看到概率是一致的,加起来是 100。

终端输出

此外,所有结果都被打印到一个. txt 文档 coreNLP_output2.txt 中,使用下面的命令可以很容易地将该文档作为 DataFrame 导入 python。结果数据帧将有 13 列:' par_id ',' sent_id ',' words ',' lemmas ',' posTags ',' nerTags ',' depParse ',' perspective ',' veryneg ',' neg ',' neu ',' pos '和' verypos '。

import pandas as pd
df = pd.read_csv('coreNLP_output.txt', delimiter=';',header=0)

从输出创建的数据帧。txt 文件

下次……

暂时就这样吧!希望您喜欢它,并且像我第一次看到这个模型时一样,对在句子向量中包含语法感到兴奋!我觉得对于像我这样的文学专业学生来说,这是一个非常令人满意的模式,因为它建立在实际的语言学基础上。

****下次我们将继续讨论句子嵌入!我们将介绍如何从 coreNLP 注释对象中提取它们,将它们与其他更基本的句子嵌入进行比较,并使用一些特征约简和可视化方法探索它们的信息性。我们还将进一步使用这些向量来计算更全面的文档嵌入,以便在文档级别执行情感分析!✌🏻

**GitHub:【https://github.com/laurabravopriegue/coreNLP_tutorial **

文献学

弗雷格,g .,1980 年。算术的基础:对数字概念的逻辑数学探究。西北大学出版社。

米切尔,j .和拉帕塔,m .,2010 年。语义分布模型中的合成。认知科学34 (8),第 1388–1429 页。可从以下网址获得:https://online library . Wiley . com/doi/full/10.1111/j . 1551-6709 . 2010 . 01106 . x

帕蒂,b,1995 年。词汇语义和组合性。认知科学的邀请:语言1 ,第 311–360 页。

罗瑟尔,曼宁,C.D .和 ng,纽约,2010 年 12 月。用递归神经网络学习连续短语表示和句法分析。在NIPS-2010 深度学习和无监督特征学习研讨会的会议录(2010 卷,第 1–9 页)。可在:https://nlp.stanford.edu/pubs/2010SocherManningNg.pdf

Socher,Lin c . c .,Manning c .和 ng,A.Y .,2011 年。用递归神经网络解析自然场景和自然语言。在第 28 届机器学习国际会议(ICML-11)的会议记录中(第 129-136 页)。可在:https://NLP . Stanford . edu/pubs/SocherLinNgManning _ icml 2011 . pdf查阅

Socher,b . Hu val,c . d . Manning 和 a . y . Ng,2012 年 7 月。通过递归矩阵向量空间的语义合成。在2012 年自然语言处理和计算自然语言学习经验方法联合会议记录(第 1201-1211 页)。计算语言学协会。

Socher,r .,Perelygin,a .,Wu,j .,Chuang,j .,Manning,C.D .,ng,a .,Potts,c .,2013 年 10 月。情感树库语义合成的递归深度模型。在2013 年自然语言处理经验方法会议记录(第 1631-1642 页)。可在:https://www.aclweb.org/anthology/D13-1170

** [## 概观

高性能人类语言分析工具,现在带有 Python 中的原生深度学习模块,可用于许多…

stanfordnlp.github.io](https://stanfordnlp.github.io/CoreNLP/) [## 单词嵌入和 Word2Vec 简介

单词嵌入是最流行的文档词汇表示之一。它能够捕捉…的上下文

towardsdatascience.com](/introduction-to-word-embedding-and-word2vec-652d0c2060fa) [## 感人至深:用于情感分析的深度学习

这个网站提供了预测电影评论情绪的现场演示。大多数情绪预测系统都有效…

nlp.stanford.edu](https://nlp.stanford.edu/sentiment/)**

基于名词和数值的句子评分

原文:https://towardsdatascience.com/sentence-scoring-based-on-noun-and-numerical-values-d7ac4dd787f2?source=collection_archive---------22-----------------------

在处理文本数据时,句子评分是自然语言处理(NLP)领域中最常用的过程之一。这是一个根据所用算法的优先级将数值与句子相关联的过程。

这个过程尤其在文本摘要中被高度使用。有许多流行的句子评分方法,如 TF-IDF、TextRank 等。在这里,我们将检查一种新的方法,根据名词、数值和 word2vec 的相似性对句子进行评分。

步骤 1:导入库

步骤 2:文本处理和方法

从 BBC 的一篇随机新闻文章中随机选取了一段进行研究。处理步骤如下所述:

  1. 使用 NLTK sent_tokenize 中的句子标记器拆分每个句子。

2.诸如%、$、#、@等特殊字符已被删除。

3.每个句子的所有单词都被标记了。

4.停用字词列表中包含的停用字词(如 and、but、or)已被删除。

5.确保一个句子中的所有单词只出现一次。

6.词汇化已经被用来寻找词根

加工

方法

步骤 3: Gensim Word2Vec

使用 Gensim Word2Vec skip-gram 方法创建一个词汇化文本列表的向量列表。

第四步:句子评分

为了给一个句子打分,使用了两种方法:meanOfWord()和 checkNum()。这个方法有两个 pos 值列表,包括名词和数字。但问题是像“234”、“34.5”(数字前的空格)这样的数字在 NLTK pos_tag()中被视为名词。因此,使用了另一种方法 checkNum()来确认它是否是一个数字。meanOfWord()中使用的程序已经在下面提到:

  1. 从 word2vec 模型中找出每个单词的相似度,并计算平均相似度
  2. 检查这个单词是否是一个数字
  3. 如果是数字,则平均相似度加 1,如果是名词,则平均相似度加 0.25
  4. 返回更新后的平均值

对于词汇化列表中的每个句子,已经计算了平均分数并将其推入分数列表中。分数的输出将是该句子的索引号和该句子的数值分数。

我的输出是:

[[0, 2.875715106488629], [1, 3.3718763930364872], [2,2.117822954338044], [3, 4.115576311542342]]

这表明:

'China remains the main area of concern for BMW after sales there fell 16% last year.' got 2.875715106488629 score.'However, BMW is hopeful of a much better year in 2005 as its direct investment in China begins to pay dividends.' got 3.3718763930364872 score.'The company only began assembling luxury high-powered sedans in China in 2003.' got 2.117822954338044 score.'2004 was generally a good year for BMW, which saw revenues from its core car-making operations rise 11%.' got 4.115576311542342 score.

第四个句子得分最高,因为它比其他句子包含更多的名词和数值。它可能会有所不同,因为 word2vec 模型可能会为不同的迭代生成不同的向量。

完整代码如下:

注意:

在名词和数值数量非常多的情况下,这种方法会提供更好的性能。

如果你觉得这个方法有用,你可以使用它并与他人分享。欢迎在评论区写下你的建议。

谢谢你!

亚马逊电子数据集评论的情感分析和产品推荐——第一部分

原文:https://towardsdatascience.com/sentiment-analysis-and-product-recommendation-on-amazons-electronics-dataset-reviews-part-1-6b340de660c2?source=collection_archive---------8-----------------------

第 1 部分:探索性数据分析(EDA)

介绍

互联网彻底改变了我们购买产品的方式。在在线市场的零售电子商务世界中,体验产品是不可行的。还有,在今天的零售营销世界里,每天都有如此多的新产品涌现出来。因此,客户需要在很大程度上依靠产品评论来做出更好的购买决策。然而,搜索和比较文本评论可能会让用户感到沮丧。因此,我们需要更好的数字评级系统的基础上审查,这将使客户购买决策容易。

在他们的决策过程中,消费者希望使用评级系统尽快找到有用的评论。因此,能够从文本评论中预测用户评级的模型至关重要。获得文本评论的整体感觉反过来可以改善消费者体验。此外,它可以帮助企业增加销售,并通过了解客户的需求来改进产品。

考虑了电子产品的亚马逊评论数据集。还考虑了用户对不同产品给出的评论和评级,以及关于用户对产品的体验的评论。

马尔特·温根Unsplash 上拍摄的照片

问题陈述

目标是开发一个模型来预测用户评级、评论的有用性,并基于协同过滤向用户推荐最相似的项目。

数据收集

电子数据集由来自亚马逊的评论和产品信息组成。该数据集包括评论(评级、文本、有用性投票)和产品元数据(描述、类别信息、价格、品牌和图像特征)。

产品完整点评数据

该数据集包括电子产品评论,如评级、文本、有用性投票。这个数据集是从http://jmcauley.ucsd.edu/data/amazon/获得的。原始数据是 json 格式的。json 被导入并解码,以将 json 格式转换为 csv 格式。样本数据集如下所示:

示例产品评论数据集

每行对应一个客户评论,包括以下变量:

产品元数据

该数据集包括电子产品元数据,例如描述、类别信息、价格、品牌和图像特征。这个数据集是从http://jmcauley.ucsd.edu/data/amazon/获得的。json 被导入并解码,以将 json 格式转换为 csv 格式。示例产品元数据数据集如下所示:

示例产品元数据集

每一行对应于产品,包括以下变量:

数据争论

合并数据帧

json 文件中的产品评论和元数据集保存在不同的数据框架中。使用左连接将两个数据帧合并在一起,并将“asin”保留为普通合并。最终合并的数据框描述如下所示:

合并数据帧信息

为了减少运行模型的时间消耗,只选择了耳机产品,并采用了以下方法。

  1. 在 1689188 行中,45502 行在产品标题中为空值。这些行被删除。
  2. 从合并的数据帧中提取产品名称为“耳机”、“头戴式耳机”、“头戴式耳机”的数据集。最终的耳机数据集是 64305 行(观察值)。

处理重复项、缺失值

  1. brand 列中有 22699 行被视为空值。为了解决这个问题,从标题中提取品牌名称,并替换品牌中的空值。
  2. 已删除“审阅者姓名”、“价格”、“描述”和“相关”中缺少的值。
  3. “审查文本”和“总结”连接在一起,并保存在“审查文本”功能下
  4. 有益的功能被分为正面和负面反馈。
  5. 大于或等于 3 的评级被归类为“好”,小于 3 的评级被归类为“差”。
  6. 有用性比率是基于该评论发布反馈/总反馈来计算的
  7. 已删除基于“asin”、“reviewerName”、“unixReviewTime”的重复项。删除重复项后,数据集由 61129 行和 18 个要素组成。
  8. ReviewTime 已转换为 datetime“% m % d % Y”格式。
  9. 为清楚起见,对列进行了重命名。

耳机数据集的描述

描述统计学

获得了以下汇总统计数据

耳机数据集的汇总统计如下所示:

汇总统计数据

预处理文本

因为文本是所有可用数据中最不结构化的形式,所以文本中存在各种类型的噪声,并且在没有任何预处理的情况下,数据不容易分析。对文本进行清理和标准化,使其无噪声并可供分析的整个过程称为文本预处理。在本节中,应用了以下文本预处理。

移除 HTML 标签

HTML 标签,它通常不会为理解和分析文本增加多少价值。HTML 单词已从文本中删除。

去除重音字符

重音字符/字母被转换并标准化为 ASCII 字符。

扩张收缩

缩写是单词或音节的缩写。它们以书面或口头的形式存在。现有单词的缩短版本是通过删除特定的字母和声音创建的。在英语缩写的情况下,它们通常是通过从单词中去掉一个元音而产生的。

本质上,缩写确实给 NLP 和文本分析带来了问题,因为首先,我们在单词中有一个特殊的撇号字符。理想情况下,我们可以为缩写和它们相应的展开建立一个适当的映射,然后用它来展开文本中的所有缩写。

删除特殊字符

文本规范化的一个重要任务是去除不必要的和特殊的字符。这些可能是出现在句子中的特殊符号,甚至是标点符号。该步骤通常在标记化之前或之后执行。这样做的主要原因是因为当我们分析文本并利用它来提取基于 NLP 和 ML 的特征或信息时,标点符号或特殊字符通常没有多大意义。

词汇化

词汇化的过程是去除词缀以获得单词的基本形式。基本形式也被称为词根,或引理,将始终存在于字典中。

删除停用词

停用词是意义不大或没有意义的词。它们通常在处理过程中从文本中删除,以保留具有最大意义和上下文的单词。停用词通常是在你根据单数标记聚合任何文本语料库并检查它们的频率时出现次数最多的词。像 a、the、me 等词是停用词。

构建文本规范化器

基于我们上面写的函数和附加的文本校正技术(例如小写文本,并删除多余的换行符、空格、撇号),我们构建了一个文本规范化器,以帮助我们预处理 new_text 文档。

在对“review_text”文档应用文本规范化器之后,我们应用标记化器为干净的文本创建标记。结果,我们总共有 3070479 个单词。清洗后,我们有 25276 个观察值。

干净的数据集将允许模型学习有意义的特征,而不会过度适应不相关的噪声。在完成这些步骤并检查其他错误之后,我们可以开始使用干净的、带标签的数据在建模部分训练模型。

探索性数据分析

收集数据后,对数据进行辩论,然后进行探索性分析。通过探索性分析探讨了以下见解。

  • 根据评论预测评分
  • 对大量评论有用
  • 评分与评论数量
  • 评级与评论比例
  • 有用比例与评论数量
  • 评级与有用性比率
  • 最受欢迎的 20 种产品
  • 垫底的 20 种受评产品
  • 积极和消极的话
  • 不同评级、品牌等的世界云

20 大最受关注品牌

评论最多的 20 大品牌

20 大最少评论品牌

前 20 个评论最少的品牌

20 大最受关注产品

20 大最受关注的产品

评论最积极的耳机

亚马逊在耳机类别下评价最高的产品是“松下 ErgoFit 入耳式耳塞耳机 RP-HJE120-D(橙色)动态晶莹剔透的声音,符合人体工程学的舒适贴合”。该产品总体优良率超过 3。

以上产品几年后会怎么样?

从 2010 年起,松下耳塞耳机获得了总体正面评价。评级在一段时间内的分布如下所示。该产品的总体良好均值评级超过 4。

松下耳塞耳机的年平均额定值对比

这个词来自对上述产品的良好评级评论。从卖家的角度来看,它显示了主要的洞察力。表示大部分积极的客户同意“非常合适”、“价格合理”,最不同意“音质”。同样,该词来源于对上述产品的不良评级评论。表示大部分客户认可“质量差”和“声音太差”。 从卖家的角度来看,本产品需要更新“更好的声音”和“质量”,以获得客户的积极反馈。

来自松下耳机良好评级评论的真知灼见

来自松下耳机不良评级评论的真知灼见

评论最负面的耳机

亚马逊耳机类别中评论最负面的产品是“我的区域无线耳机”。该产品的整体不良评级低于 3。

以上产品几年后会怎么样?

除 2012 年外,从 2010 年起,我的 zone 无线耳机受到了全面的负面评价。评级在一段时间内的分布如下所示。该产品的总体不良均值评级约为 2.5。

My zone 无线耳机的年度与平均等级对比

下面显示了来自上述产品的良好评级评论的词云。从卖家的角度来看,它显示了主要的洞察力。表示大部分积极的客户同意“轻松设置”、“配合电视工作”,而不太同意“工作出色”。同样,上述产品的不良评级引发的“云”一词也显示如下。表示大部分客户认同“电池问题”、“糟糕的接收”、“静电干扰”。 从卖家角度看,本产品需要更新“优质电池”、“收货问题”、“静态问题”,以获得客户的积极反馈。

我的区域无线耳机好评中的真知灼见

我的区域无线耳机差评中的真知灼见

哪个评分获得的评论数最高?

顾客对他们在 2000 年至 2014 年期间从亚马逊购买的耳机写了评论,评级从 1 到 5。评级与评论数量的分布和百分比如下所示。与其他评级相比,评级为 5 的评论数量较高。总的来说,顾客对他们购买的产品很满意。大约 50%的顾客给他们购买的产品打了 5 分。只有 15%的顾客给出了低于 3 分的评价。

评分与评论数量

评分分布与评论数量

评级分为两类。低于 3 的评级被分类为“差”,其余的评级被分类为“好”。评级类别与评论数量的分布如下所示。它表明,约有 50000 条评论被评为良好评级。

每个评级类别的审核总数

评级与有用性比率的分布如下所示。这表明所有评级都具有相同的有用性比率。

评级中的有用性

哪个评分获得了最高数量的评论长度?

评分与评论长度

哪一年的评论数最高?

每年的审查总数如下所示。2000 年至 2010 年期间,审查数量较少。2013 年评论数最高。

评分与评论长度

哪一年的客户数量最多?

每年的独立客户总数如下所示。在 2000 年至 2010 年期间,独立客户数量较低。2013 年的客户数量最多。

每年的独特客户

哪一年的产品数量最多?

每年的独特产品总数如下所示。2000 年至 2010 年期间,独特产品的数量很少。2013 年产品数量最多。

每年独特的产品

哪一年的产品数量最高?

除了 2001 年,“良好评级”的百分比超过了 80%。2001 年的整体满意度最低,为 69%。在 2000 年,良好评级的百分比是 90%。从图表中可以看出,耳机产品的总体好评率在 81%到 90%之间。

一段时间内良好评级等级的分布

产品的平均有用性

每个产品的平均有用性分布

评审长度分布

评论长度的分布

哪个评论长度 bin 的好评率最高?

如下图所示,96 %的好评在 0-1000 字之间,而 80%的好评在 1700-1800 字之间。随着审查时间的延长,良好评级会增加。一般来说,写了较长评论(超过 1900 字)的客户往往会给出好的评价。

评论长度与良好评级的分布

哪个评论长度 bin 的有用性比率最高?

从下面可以看出,最高的帮助率在 0-1200 个单词之间,0.8,而最低的帮助率在 1200-1300 个单词之间,0.6。随着审查时间的延长,有用性比率趋于增加。一般来说,写了较长评论(超过 1300 字)的客户往往有较高的有用性比率。

综述长度与有用性比率的分布

有益和无益的审查长度的频率如下所示。它表明,总的有益和无益的比例是相同的较长的审查长度。在小篇幅评论情况下,无用比率较高。

评论长度与有益和无益的分布

获得好评的热门词汇?

下面列出了最常见的 50 个单词,这些单词属于良好评级类别。它展示了顾客对产品的所有好评。

好的评价词

差评热门词汇?

同样,最常见的单词,属于差评类,如下所示。它显示了顾客对产品的所有负面评价。

不良评价词

代码:

数据争论:

https://github . com/umar aju 18/Capstone _ project _ 2/blob/master/code/Amazon-Headphones _ data _ wrangling . ipynb

EDA:

[## umaraju18/Capstone_project_2

github.com](https://github.com/umaraju18/Capstone_project_2/blob/master/code/Amazon-headphones_EDA.ipynb)

第二部分:情感分析和产品推荐

亚马逊电子数据集评论的情感分析和产品推荐——第二部分

原文:https://towardsdatascience.com/sentiment-analysis-and-product-recommendation-on-amazons-electronics-dataset-reviews-part-2-de71649de42b?source=collection_archive---------22-----------------------

第 2 部分:情感分析和产品推荐

情感分析

机器学习模型以数值作为输入。评论是由句子组成的,所以为了从数据中提取模式;我们需要找到一种方法,以机器学习算法可以理解的方式来表示它,即作为一系列数字。

特征抽出

特征工程是使用数据的领域知识来创建使机器学习算法工作的特征的过程。要素本质上通常是数字,可以是绝对数值或分类要素,可以使用一种称为“一键编码”的过程将这些要素编码为列表中每个类别的二进制要素。提取和选择特征的过程既是艺术又是科学,这个过程称为特征提取或特征工程。

作为其中的一部分,单词包模型、TF-IDF、哈希矢量器、Word2Vec 以及将最常见的单词添加到停用词列表、SMOTE、PCA 和截断 SVD 技术作为特征工程和选择的一部分添加到以下部分中的分类模型中。

数据预处理

出于计算方面的考虑,2010 年早些时候评论的 good_rating_class_reviews 超过 150 个单词的功能被删除。最终的数据集由 15000 个观察值组成。从数据集中,“干净文本”和“评级类别”分别被视为“X”(特征)和“Y”(变量)。数据集被分成 75%作为训练,25%作为测试。

机器学习模型

该模型需要根据从亚马逊购买耳机的客户撰写的评论来预测情绪。这是一个有监督的二元分类问题。Python 的 Scikit 库被用来解决这个问题。实现了以下机器学习算法。

逻辑回归

逻辑回归,尽管它的名字,是一个线性模型的分类,而不是回归。逻辑回归在文献中也称为 logit 回归、最大熵分类(MaxEnt)或对数线性分类器。在这个模型中,描述单个试验的可能结果的概率使用逻辑函数建模。

朴素贝叶斯

朴素贝叶斯为多项式分布数据实现了朴素贝叶斯算法,并且是文本分类中使用的两种经典朴素贝叶斯变体之一(其中数据通常表示为词向量计数)。该算法是流行的朴素贝叶斯算法的一个特例,它专门用于我们有两个以上类的预测和分类任务。

随机森林分类器

随机森林是一种元估计器,它在数据集的各个子样本上拟合多个决策树分类器,并使用平均来提高预测精度和控制过拟合。子样本大小始终与原始输入样本大小相同,但如果 bootstrap=True(默认),则使用替换来绘制样本。

XGBoost 分类器

XGBoost 的意思是极端的梯度增强。XGBoost 是一个基于决策树的集成机器学习算法,它使用了一个梯度推进框架。在涉及非结构化数据(图像、文本等)的预测问题中。)人工神经网络往往优于所有其他算法或框架。然而,当涉及到中小型结构化/表格数据时,基于决策树的算法目前被认为是同类最佳的。

CatBoost 分类器

CatBoost 是一种在决策树上进行梯度提升的算法。“CatBoost”名字来源于两个词“Category”和“Boosting”。该库适用于多种类别的数据,如音频、文本、图像,包括历史数据。

评估指标

由于我们的案例中存在数据不平衡,因此必须使用适当的度量来评估分类器的性能,以便考虑类别分布并更多地关注少数类别。基于这一思想,使用 f1 分数作为我的评估标准,f1 分数是精确度和召回率的调和平均值。

理解我们的模型产生的错误类型是很重要的。可视化信息的一个好方法是使用混淆矩阵,它将我们的模型做出的预测与真实标签进行比较。考虑到这一点,除了我们的评估指标(f1 分数)之外,还使用了混淆矩阵。

建模

由于评论的等级不是正态分布的,等级 1-2 被归类为“差”,等级 3-4-5 被归类为“好”。在特征选择方面,使用了最小/最大方向图、主成分分析和奇异值分解的单词出现阈值。对于特征工程,将计数矢量器、TF-IDF、散列矢量器和 Word2Vec 应用于文本数据,以便将文本文档集合转化为数字特征向量。

袋字模型

单词袋模型可能是从文本文档中提取特征的最简单也是最强大的技术之一。这种特定的策略(标记化、计数和规范化)被称为单词袋或“n-grams 袋”表示法。该模型的本质是将文本文档转换成向量,使得每个文档都被转换成表示该特定文档的文档向量空间中存在的所有不同单词的频率的向量。下图显示逻辑回归以 0.896267 胜出。

F1 平均分数

TF-IDF 型号

TF-IDF 代表术语频率-逆文档频率,这是两个指标的组合:术语频率和逆文档频率。为了更多地关注有意义的单词,TF-IDF 得分(术语频率-逆文档频率)被用于我们的单词袋模型之上。TF-IDF 根据单词在我们的数据集中的稀有程度来衡量单词,忽略那些过于频繁并且只会增加噪音的单词。-IDF 的工作方式是通过为这些常用词分配较低的权重来惩罚它们,同时对出现在特定文档的子集中的词给予重视。下图显示 CatBoosting 以 0.896533 分胜出。

F1 平均分数

哈希矢量器

哈希矢量器被设计成尽可能地节省内存。矢量器不是将记号存储为字符串,而是应用哈希技巧将它们编码为数字索引。这种方法的缺点是,一旦矢量化,就无法再检索要素的名称。下图显示 CatBoosting 以 0.894133 分胜出。

F1 平均分数

将最常用和最不常用的词添加到停用词表(计数矢量器)

因为在不同的类中没有太多不同的词,所以应用添加到停用词列表和模型中的最常见和最不常见的 70 个词,以便查看评估度量中的任何变化。下图显示 CatBoosting 以 0.890133 分胜出。将最常用和最不常用的单词添加到停用词表中对模型的性能没有影响。

F1 平均分数

应用 Word2Vec 和简单神经网络

我们使用 Word2Vec 创建了单词向量,该模型有 26548 个唯一的单词,其中每个单词的向量长度为 100。然后我们在一个简单的神经网络中使用这些密集的向量——单词嵌入——来进行预测。在训练和验证准确度图中,模型在第一个时期后开始过度拟合。这个简单神经网络的精度是 0.7992。

上面给出了在用 t-SNE 将感兴趣的单词和它们的相似单词的维数减少到 2-D 空间之后,使用它们的嵌入向量对它们进行可视化。也可以查看基于 gensim 模型的类似单词。

产品推荐

直到最近,人们通常倾向于购买朋友或信任的人推荐给他们的产品。这曾经是对产品有任何疑问时的主要购买方法。但随着数字时代的到来,这个圈子已经扩大到包括利用某种推荐引擎的在线网站。

推荐引擎使用不同的算法过滤数据,并向用户推荐最相关的项目。它首先捕捉客户过去的行为,并在此基础上推荐用户可能会购买的产品。

如果我们能够根据客户的需求和兴趣向他们推荐一些商品,这将对用户体验产生积极的影响,并导致频繁的访问。因此,现在的企业正在通过研究用户过去的行为来构建智能的推荐引擎。使用项目-项目协同过滤。

数据处理

在将电子评级数据集与产品元数据合并后,空值将从数据集中删除。总特征是 7530925。最终数据集如下所示。

产品推荐的最终数据集

项目-项目协同过滤

当用户数量多于推荐的项目时,这种协作过滤是有用的。用户数(4053964)大于项目数(469625)。

在该过滤中,计算每个项目对之间的相似度,并基于该相似度推荐用户过去喜欢的相似项目。采用“项目用户”评级的加权总和。基于项目的过滤过程如下所示。

作者绘图。来自 Unsplash 的免费图片

用户评分总和排名前十的热门产品

按用户评分总和列出的十大热门产品

产品推荐

产品推荐

结论

使用计数向量、TF-IDF、散列向量、Word2Vec、分类模型和简单神经网络,并向 CountVect 添加最常用和最不常用的词,来预测基于顾客留下的评论的评级分数。从分析中发现,具有 TF-IDF 的 CatBoosting 得分为 0.890586)或具有计数矢量化的 Logistic 回归(f1 得分为 0.899891)是最佳模型。将最常用和最不常用的单词添加到停用词表中并不会对模型的性能产生影响。

代码:

情感分析:

https://github . com/umar aju 18/Capstone _ project _ 2/blob/master/code/Amazon _ headphones _ Analysis _ CV _ IF _ IDF _ hash . ipynb

https://github . com/umar aju 18/Capstone _ project _ 2/blob/master/code/Amazon _ headphones _ word vec . ipynb

推荐系统:

https://github . com/umar aju 18/Capstone _ project _ 2/blob/master/code/Amazon _ electronics _ recommendation . ipynb

第一部分:探索性数据分析

情绪分析和股票市场:一个新的巴西故事?

原文:https://towardsdatascience.com/sentiment-analysis-and-the-stock-market-a-brazilian-tale-be128098787e?source=collection_archive---------45-----------------------

尽管规模很小,但巴西 Fintwit 增长迅速,引发了人们对巴西股市泡沫的担忧。

自由股票Unsplash 上的照片

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

巴西经济最近的周期性变化导致大量个人进入股票市场。由于该国的历史高利率,这些投资者习惯于将资金投资于政府债券或储蓄账户,但是,一旦通胀自 2016 年以来似乎得到控制,随着央行降低基本利率(即 SELIC),低风险投资的回报开始受到影响。

正如我们在下图中看到的,LTN 债券的年回报率曾经超过 10%,但目前的名义收益率不超过 6%。

LTN 自 2002 年起放弃申办

随着巴西投资者开始寻找新的替代投资方式,Ibovespa(巴西市场的主要指数)开始无情地上涨,直到最近冠状病毒爆发。正如我们在下图中看到的,在冠状病毒爆发后,巴西股市跟随世界其他市场的趋势,恢复得非常快。

Ibovespa 指数(2016–2020)

尽管目前尚不清楚价格是否会回到 2019 年 12 月的水平,但许多基金经理已经提出了资产价格可能已经过高的可能性,因为这一运动涉及巴西投资者资源的重新分配。无论如何,其中一位经理最近提出了一种可能性,即巴西的 fintwit 社区可能会引发查尔斯·金德尔伯格(Charles Kindleberger)所说的“欣快症”——为股市泡沫铺平道路。这真的会发生吗?

本文的目标是评估这种可能性,首先提供该社区规模的概述。最后,应用情感分析算法,了解这些推文中的观点是否在总体上保持平衡趋势。重要提示:我们不打算分析这些观点最终是推动市场,还是受市场影响。而仅仅是为了了解这些观点是否过于积极,以这种方式营造出一种欣快的氛围。这样,我不仅会使用 tweets,还会使用 retweets,因为这让我们更清楚地知道有多少人可能会查看这些信息。

当然,我们的第一步是收集推文。我不打算对此进行过多的探讨,因为这里有无数的文本在讨论不同的程序和技术。对于这个分析,我将使用 R 和 twitteR 包。这个包有一个限制:我们不能收集超过七天的推文。尽管有这个限制,让我们看看这个短时间范围能告诉我们什么。我搜索的术语是:

  • IBOVESPA
  • 投资
  • Ibov
  • Ibovespa 指数中的所有资产(76 项资产)

因此,我们的时间范围和搜索的术语如下所示:

setup_twitter_oauth(consumerKey, consumerSecret, 
                    access_token = accessToken, 
                    access_secret = accessTokenSecret)#Collect the tweets into lists
list1 <- searchTwitter('Ibovespa',n=10000, lang="pt", 
                       since='2020-08-26', until ='2020-09-03')
list2 <- searchTwitter('Investimento', n=10000,  lang="pt", 
                       since='2020-08-26', until ='2020-09-03')
list3 <- searchTwitter('Ibov', n=10000, lang="pt", 
                       since='2020-08-26', until ='2020-09-03')
list4 <- searchTwitter(list_of_assets, n=10000, lang="pt",
                       since='2020-08-26', until ='2020-09-03')#Concatenate them
list_ <- c(list1, list2, list3, list4)#Create a df from the list_assets
df_assets <- twListToDF(list_assets)
df_assets <- df_ativos[, order(names(df_assets))]
df_assets$created <- strftime(df_assets$created, '%Y-%m-%d')

有了我们的 df,我们可以看到每天有多少 tweets 是用搜索词生成的。首先,我不会考虑 RTs,正如我们在下图中看到的,图表显示,每天人们可以在 Twitter 上找到至少 1400 条关于这些术语的推文,我认为这是很重要的,因为尽管巴西股市最近有所扩张,但它仍然高度集中。因此,能够在 Twitter 上生成内容或单独发表观点的用户数量非常少。

#Df with number of tweets each day
df_q <- data.frame(df_assets %>% count(created))
ggplot(df_q, aes(created, n)) + 
  geom_bar(stat = "identity", color="black", fill=rgb(0.1,0.4,0.5,0.7)) +
  labs(y="# of Tweets", x = "Date of the Tweets")

每天的推文

所有这 22,000 条推文都是由大约 5,000 名用户创建的,这意味着在此期间,每个用户都发了 4 次关于这些主题的推文。但是我们忽略了一些东西:有多少用户真正加入了这个社区。虽然不可能说有多少其他用户看到了这些推文,但我们可以评估他们的参与度。我们可以很容易地看到波纹管。“favoriteCount”变量的平均值为 14,547,retweetCount 的平均值为 1,437。这就是为什么我们可以说,参与度并不真正重要:每天 1400 条推文中的每一条,平均来说,都不会超过 10 个 Favs 和 1 个 Rt。

#Df with sum of favs and rts for each tweet per day
df_favs <- aggregate(favoriteCount ~ created, df_assets, sum)
df_rts <- aggregate(retweetCount ~ created, df_assets, sum)
df_interac <- merge(df_favs, df_rts)df_interac2 <- melt(df_interac)ggplot(df_interac2, aes(x=created, y=value, fill=variable)) +
  geom_bar(stat='identity', position='dodge') +
  labs(y="#", x = "Date of the Tweets")

每天的交互(Favs 和 Rts)

在我们的样本中,这种参与是由 11,700 个独立用户产生的,仅占当前投资者总数的 0.44%。这并不真正具有代表性,但我们至少可以说,在这个社交网络中真的有一种欣快感,最终可能会影响股票市场吗?为了进行分析,我们需要一个函数,它能够根据之前选择的正面和负面单词来确定每个文本的得分。

#Positive and Negative Word
pos <- scan('positive_words.txt', what='character', comment.char=';') 
neg <- scan('negative_words.txt', what='character', comment.char=';')#Sentiment score model
score.sentiment <- function(sentences, pos.words, neg.words){
  scores <- laply(sentences, function(sentence, pos, neg){
    sentence <- gsub('[[:punct:]]', "", sentence)
    sentence <- gsub('[[:cntrl:]]', "", sentence)
    sentence <- gsub('\\d+', "", sentence)
    sentence <- str_replace_all(sentence, "[^[:alnum:]]", " ")
    sentence <- tolower(sentence)
    word.list <- str_split(sentence, '\\s+')
    words <- unlist(word.list)
    pos.matches <- match(words, pos.words)
    neg.matches <- match(words, neg.words)
    pos.matches <- !is.na(pos.matches)
    neg.matches <- !is.na(neg.matches)
    score <- sum(pos.matches) - sum(neg.matches)
    return(score)
  }, pos.words, neg.words)
  scores.df <- data.frame(score=scores, text=sentences)
  return(scores.df)
}#Applying the model to the dataset
Dataset <- df_assets
Dataset$text <- as.factor(Dataset$stripped_text)
scores <- score.sentiment(Dataset$stripped_text, pos.words, neg.words)stat <- scores
stat$created <- stripped_text$created
stat$created <- as.Date(stat$created)
stat <- mutate(stat, tweet=ifelse(stat$score > 0, 'positive', 
                                  ifelse(stat$score < 0, 'negative', 'neutral')))
by.tweet <- group_by(stat, tweet, created)
by.tweet <- summarise(by.tweet, number=n())ggplot(by.tweet, aes(created, number)) + geom_line(aes(group=tweet, color=tweet), size=1) +
  geom_point(aes(group=tweet, color=tweet), size=4) +
  labs(y="# of Tweets", x = "Date of the Tweets")
theme(text = element_text(size=10), axis.text.x = element_text(angle=90, vjust=1)) +
  ggtitle('cted tweets: FintwitBr')

该图向我们展示了 3 种类型的类别,它们是正面的(得分> 1),负面的(得分<1) and neutral. At least in our sample, there is clear evidence that tweets are likely to be more positive than negative. And the proportion changed significantly on August 28th and September 1st. But, since the community is not representative in relation to the market as a whole, it would be an exaggeration to claim that the euphoria on Twitter is impacting the market.

Sentiment Analysis

That doesn’t mean that there isn’t something happening in the Brazilian stock market; I really think it is. It just means that, for the moment, there is a little bit of alarmism — and with some reason. Especially because, when Robert Shiller warned the market about the irrational exuberance that could bring the financial market to a breakdown in his 2005 book, nobody took him seriously. I mean, nowadays you can find several profiles, either on Twitter, YouTube or Instagram talking about investments, for an audience that until the last few years used to see this as something no more than obscurantism.

¹ You can find Charles Kindleberger’s book in Portuguese ( Manias,p nicos e Crises:Uma históRIA das catástrofes econ micas mundiais)或英文( Manias,Panics,and Crashes:A History of Financial crisis)。

AWS 理解的情感分析和实体提取

原文:https://towardsdatascience.com/sentiment-analysis-entity-extraction-with-aws-comprehend-618a7bec60b8?source=collection_archive---------17-----------------------

在 Python 中使用 AWS Lambda、Boto3 和 understand 执行高级 NLP 任务的快速概述

图片来自 Unsplash

介绍

亚马逊网络服务(AWS)一直在不断扩展其在各个领域的机器学习服务。 AWS 领悟是自然语言处理的 AWS 发电站( NLP )。NLP 中常见的两个项目有情感分析实体提取。我们经常使用 NLTK、Spacy、Transformers 等库从头开始构建定制模型。虽然定制模型肯定有它们的用途,并且当你对你要解决的问题有领域知识时表现得特别好,但是从头开始构建它们也是非常耗时的。这就是 AWS intensive 的用武之地,它为情感分析和其他 NLP 任务提供高级服务。对于本文,我们将使用理解进行情感分析和实体检测。为了通过 AWS understand 访问这些服务,我们使用了另一个名为 AWS Lambda 的 AWS 服务。Lambda 是一个无服务器的计算平台,允许你通过 Boto3 、PythonT21 的 AWS SDK 调用这些服务。我将提供一个我们将要使用的服务列表,并在此广告之后提供更深入的定义,但是如果您已经熟悉这些服务,可以随意跳到情感分析&实体提取的代码演示。****

目录

  1. AWS 服务
  2. 带有 AWS 理解的情感分析
  3. AWS 综合实体检测
  4. 代码和结论

AWS 服务

AWS 领悟 : AWS NLP 服务,使用 ML 来执行诸如情感分析、实体提取、主题建模等任务。对于这个例子,我们只探索其中的两个任务。

[## 亚马逊理解-自然语言处理(NLP)和机器学习(ML)

发现文本中的见解和关系亚马逊理解是一种自然语言处理(NLP)服务,使用…

aws.amazon.com](https://aws.amazon.com/comprehend/)

AWS Lambda:一种无服务器计算服务,允许开发人员在不管理或供应服务器的情况下运行代码。

[## AWS Lambda -无服务器计算-亚马逊网络服务

运行代码时不考虑服务器。只为您消耗的计算时间付费。AWS Lambda 让你运行代码…

aws.amazon.com](https://aws.amazon.com/lambda/)

Boto3 :针对 Python 开发者的 AWS 软件开发工具包(SDK),可以在你的 Lambda 函数中使用这个来调用领悟 API 及其特定服务。

[## Boto3 文档- Boto3 文档 1.16.6 文档

Boto 是 Python 的 Amazon Web Services (AWS) SDK。它使 Python 开发人员能够创建、配置和管理 AWS…

boto3.amazonaws.com](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)

AWS SageMaker :允许构建、培训和部署定制的 ML 模型。还包括各种预训练的 AWS 模型,可用于特定任务。

[## 亚马逊 SageMaker

Amazon SageMaker 是一个完全托管的服务,为每个开发人员和数据科学家提供构建…

aws.amazon.com](https://aws.amazon.com/sagemaker/)

带有 AWS 理解的情感分析

数据

您可以通过多种方式在 AWS 中访问数据。 S3 是大多数开发人员最受欢迎的数据存储选择,它最常用于实时项目或大型数据集。然而,由于我们所拥有的只是一个基本的例子,我们将使用几个 JSON 格式的文本句子供我们的 AWS Lambda 函数访问。

例如数据

情感分析的代码和解释

一旦您通过 JSON、S3 或您正在使用的任何存储格式提取了数据,就该见识一下 understand 的魔力了。在将近 5 行代码中,定制模型构建和调优中所做的脏工作被处理掉了。您必须输入的两个参数是您正在分析的文本和您的文本所在的语言。正如您在下面的结果中看到的,返回了一个总体情绪正面、负面或中性,以及这些情绪各自的百分比。****

从 JSON 和情感分析中提取数据

情感分析呼叫的结果(作者截图)。

使用detect _ 情操调用需要注意的一个关键点是文本字符串不能大于 UTF-8 编码字符的 5000 字节。当处理较大的文档或字符串时,可以使用batch _ detect _ perspection调用来解决这个问题,这允许最多 25 个字符串/文档都以 5000 字节为上限。批处理调用中的过程也非常相似,但是根据您的具体用例,您可以弄清楚如何为批处理调用预处理/分割数据。

基于 AWS 理解的实体提取

与情感分析调用类似,detect_entities 调用接受文本输入和文本语言中的两个参数。定制模型还有第三个参数,使用端点 ARN 来访问您为实体提取创建的模型,而不是默认的理解模型。正如您在下面的结果中看到的,调用返回了它在检测中的置信度、实体的类型、被识别为实体的文本以及文本的位置。例如,我们在实体的位置类型中看到纽约和弗吉尼亚。****

代码和解释实体提取

实体检测代码

实体检测调用的结果(作者截图)。

与 detect _ opposition 类似,detect_entities 不能接受大于 5000 字节的 UTF-8 编码字符的字符串。幸运的是,我们还有一个 batch_detect_entities 调用,它也允许最多 25 个字符串/文档都限制在 5000 字节。

整个代码和结论

** [## RamVegiraju/comprehende demo

使用 AWS 理解进行情感分析和实体提取的代码演示 GitHub 拥有超过 5000 万…

github.com](https://github.com/RamVegiraju/ComprehendDemo)

Boto3 与 AWS intensive 配合使用,可以让非 ML 工程师或数据科学家轻松完成许多通常需要几个小时的任务。当然,如果给定领域知识和分析问题的时间,定制模型将执行得更准确,但是 understand 消除了预处理、清理、构建和训练您自己的模型所花费的大量时间。对于那些对在 NLP 或 ML 的任何其他领域中构建定制模型感兴趣的人来说, AWS SageMaker 允许您在 Jupyter 笔记本环境和更加传统的 ML 工作流中构建、训练和部署您自己的模型。

我希望这篇文章对试图使用 AWS 服务和 NLP 的人有用。如果您对 ML &数据科学感兴趣,请随时在评论中留下任何反馈或通过 Linkedln 与我联系。感谢您的阅读!**

苹果企业社会责任报告的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-for-apples-csr-report-92e94b18b1ef?source=collection_archive---------23-----------------------

R 中的情感分析简介

梅达·达伍德Unsplash 拍摄的照片

你曾经想了解一份报告试图传达的语言或语气的类型吗?

有数百万的报告、文章、网站、书籍等。这个过程允许用户更快地理解焦点的主要主题,而不需要深入文本。

从本教程开始,您需要具备使用 R Studio 的初级/中级工作知识。如果你没有访问我的其他帖子来了解更多—R 中的文本分析

文件

访问苹果(或任何其他网站)获取其 2019 企业社会责任 (CSR)报告。我更喜欢阅读文本格式的数据。

下面是我为准备加载到 R Studio 中的文件所做的工作。

  1. 全选—突出显示文档中的所有内容
  2. 复制和粘贴—将整个报告粘贴到您计算机上的文本文件应用程序中。(Windows —记事本和 Macs 文本编辑器)
  3. 将文件保存到您的工作目录中,或者记住您的文件位置。

如果你在这一步遇到困难,请下载我的apple . txt文件。

图书馆

library(textreadr)
library(tidytext)
library(stopwords)
library(dplyr)

在文件中读取

如果你没有把你的工作目录设置到和你的 Apple.txt 文件相同的位置,那么你需要粘贴完整的路径。如果您已经设置了工作目录,下面是代码。

apple <- read_document(file="apple.txt")

设置数据框架

我们需要采取三个步骤来准备好数据帧。

  1. 将我们加载的文件转换成数据帧
  2. 将列名重命名为“text”(这将有助于我们以后的工作更轻松)
  3. 将数据帧转换成字符,这样我们就可以使用文本分析
**#setup the dataframe** apple_df <- as.data.frame(apple)**#rename column to text** colnames(apple_df) <- c("text")**#convert column type to character** ap_df <- data.frame(lapply(apple_df, as.character), stringsAsFactors=FALSE)

前 15 排。

情感库

现在我们已经准备好要分析的文本,我们可以使用任何 3 R 库。我们将使用 get _ opinions 函数来获得洞察力。

要使用情感函数,我们需要对单词进行标记,同时过滤掉停用词。

标记化是将每个单词分离出来的过程,使每个单词成为一个独立的点用于分析。例如,使用标记化,句子“棕色狐狸跳了”,将是“the”、“brown”、“fox”和“jumped”

停用词将过滤掉报告中任何不必要的词,例如,“我”、“我”、“the”等。

阿芬

[AFINN](https://www.tidytextmining.com/sentiment.html) 词典给单词打分在-5 到 5 之间,负分表示负面情绪,正面评分表示正面情绪。

afinn_ap <- ap_df %>%
  unnest_tokens(word, text) %>% **#tokenizing the dataframe**
  anti_join(stop_words) %>% **#filtering out the top words**
  inner_join(get_sentiments("afinn")) %>% **#getting the sentiment**
  count(word, value, sort=T) **#sorting for most frequent words**

基于字数的前 10 个单词

[bing](https://www.tidytextmining.com/sentiment.html)词典以二元方式将单词分为积极和消极两类。按照同样的结构,我们可以得到对 bing 库的看法。

bing_ap <- ap_df %>%
  unnest_tokens(word, text) %>%
  anti_join(stop_words) %>%
  inner_join(get_sentiments("**bing**")) %>%
  count(word, **sentiment**, sort=T)

请注意我们的代码中有两件事发生了变化。第一个是加载了“bing”库。另一个变化是单词代替了值*** (Afinn 代码)。这是因为这两个图书馆以不同的方式标注他们的情感。***

必应最常用的 10 个词

我们可以看到 Bing 和 Afinn 的结果几乎相同。

(美国)全国科学研究委员会(National Research Council)

现在,我最喜欢的图书馆——NRC。[nrc](https://www.tidytextmining.com/sentiment.html)词典以二元方式(“是”/“否”)将单词分为积极、消极、愤怒、期待、厌恶、恐惧、快乐、悲伤、惊讶和信任等类别。

同样,我们可以看到与前面的库类似的结构。

*nrc_ap <- ap_df %>%
  unnest_tokens(word, text) %>%
  anti_join(stop_words) %>%
  inner_join(get_sentiments("**nrc**"))%>%
  count(word, sentiment, sort=T)*

NRC 图书馆中出现频率最高的单词

有趣的是看 R 怎么把同一个词分成不同的情感类别。我们把资源*这个词归类为喜悦、积极、信任。***

后续步骤

既然我们有了从报告中获取情感值的基本想法,现在我们可以使用文本分析为更高级的技术做准备了。我将发布一个后续教程,深入研究 r 中的 wordcloud 分析。

辅导的

如果你想更多地练习 R 中的文本分析,可以看看我的其他帖子。

资源

社交媒体上低资源语言的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-for-low-resourced-languages-on-social-media-128bf01f2547?source=collection_archive---------39-----------------------

进入真正的语言混乱的 NLP 之旅

最近,社交媒体风暴席卷了整个世界,它赋予了每个连接到互联网的人在地球上任何时间任何地点公开表达意见的特权。由此产生的互联网上流行的有意见的文本为数据科学研究和行业提供了一个挖掘这些数据进行情感分析的机会,这是一种快速人工方法,用于衡量大众对产品、新闻、事件和政策的意见,其中每条文本都会自动分类为积极、消极或中立。

然而,将单词分类为情感类别的复杂性因语言而异。它极大地依赖于语言资源的可用性和语言的自然稀疏性。例如,丰富的数字词典、语料库和带标签的数据集很好地推进了英语情感分析科学,但对于资源较少的语言,如阿拉伯方言口语,即我博士研究的更广泛领域,则没有那么好或那么快。

词汇稀疏性

稀疏性是一种语言中单词的词汇数量,属于一种语言的单词的形式数量越多,该语言的稀疏性就越高:

稀疏度= ∑单词 x 形式【单词】

在英语中,屈折形式享受、享受、和衍生形式享受可以很容易地与积极情感词享受对应起来。对于形态丰富的语言来说,词形变化不仅限于时态和数,还包括主语、宾语、代词、阴丨蒂和性别。一个简单的例子是阿拉伯语中的حبّt11】一词;它可以屈折为我爱你(男性)* احبكَ 、我爱你(女性) احبكِ 、我爱你(复数) احبكم 、我们爱他们 احببناهم 、我们将爱你(复数) سنحبكم 在这条战线上达到 100 多个屈折。另一方面,源自一个词的词汇由前缀、中缀、后缀和音调符号组成,例如情感 محبة ,亲昵 تحابب ,合意 محبب ,优选 مستحب ,友好 متحاب ,有利 محبذ 所有都源自同一个词。*

背景来自 myfreetextures

“交一个在友谊中诚实的朋友,因为友谊的真诚在一个诚实的朋友身上”——未知。(所有名词都源于صدق 诚实)。

阿拉伯语的派生词法与三个字面量的单词非常和谐,只是太复杂了,无法通过词干分析器、词尾分析器或分词器进行分类。例如,单词استنكار 否认的行为可以映射成 11 个不同意思的单词:استنارانارسترستارسارسكركرتنكتنكرنكرنار。

如果没有一致的正字法,一种形态丰富的语言的词汇稀疏性会变得非常大,在这种情况下,一个单词的每种形式都可能有不同的拼写。拼写不一致对于纯口语的语言来说是常见的,这样,如果转录,就没有标准的拼写可以遵循,结果每个人在文本中以不同的方式表达他们的舌头。方言阿拉伯语就是这种情况,这是一种对4 . 2 亿本地人的每个地区来说都是深奥的阿拉伯语口语。不同地区的不同阿拉伯方言在词汇选择、解释、词法、发音和语速方面都有所不同,而且由于英语、法语、西班牙语、意大利语和土耳其语等外语在该地区历史上的影响,外来词也有所不同。

让-巴蒂斯特·希莱尔,耶尼·卡米伊和 i̇stanbul 港,18 世纪晚期

阿拉比齐

在大约 30 年前数字通信兴起之前,方言阿拉伯语一直被认为是一种口语语言,当时一种新的阿拉伯语变体 Arabizi 诞生了,Arabizi 是 Araby 和 Englizi 的组合,是我博士研究的主要重点。Arabizi 是一个非常非正式的拉丁脚本口语方言阿拉伯语转录。更不用说方言阿拉伯语在拼写上自然缺乏共识,阿拉伯人开始试探性地用一种不同语言的文字来映射他们的音素。这进一步扩大了正字法的不一致性,因为:

  1. 一个单词是根据它的发音来转录的,因此同一个单词的不同发音会有不同的转录:例如,在阳性 wordخير fine 中的一个字母元音音素ي /yā/发音为/y/KHāyr 或/eh/ kher,因此常见的是同一个单词既有 khayr 又有 kher 的转录。
  2. 关于如何转录不同的元音音素,没有一致的正字法。同一个单词的读音 khāyrkher 可以被转录为 kher、kheir、khair、kheyr、khayr、或者甚至省略掉大部分或全部元音字母 khyr
  3. 在如何转录不同的辅音音素方面几乎没有一致性,例如在口腔的后舌音区发音的喉音حḥā'、خ·卡瓦、ع ᶜayn、غ·盖恩和喉塞音ء·哈姆扎。例如,来自同一个 wordخير khāyr 的خ Khā'在某些地区在某种程度上被标准化为复合字母 kh 或数字 5 甚至 7 '。这立即使 wordخير Khāyr 的拼写法数量增加了三倍。

因此,简单三字基 wordخير Khāyr 可能的正字法有: kher,kheir,khair,kheyr,khayr,khyr,5er,5eir,5air,5eyr,5yr,7'er,7'eir,7'air,7'eyr,7'ayr,7'yr。

现在很明显,词汇稀疏度的大小等于每个单词的屈折变化的数量乘以其可能的正字法的数量。

稀疏度= ∑单词 x(形态学 x 正投影)形式【单词】

代码转换

最后,词汇稀疏性以代码转换为顶点,将阿拉伯语与其他拉丁脚本语言混合,主要是英语或法语。几个地区的阿拉伯青年在说话时不断地在阿拉伯语和法语或英语之间转换;因为阿拉伯语是口语的转录,所以在他们的文本中看到这一点并不奇怪。在阿尔及利亚、摩洛哥和 Tunisia⁴,阿拉伯语和法语的混合很正常,在 Lebanon⁵和 Egypt⁶.,阿拉伯语和英语的混合也很正常语码转换可能发生在各部分使用不同语言的对话中,每个分句都使用不同语言的句子中,或者是断断续续使用语码转换词的句子中。这可以从黎巴嫩的一份《脸书邮报》中得到证明:

脸书会话中的语码转换

这种语码转换意味着阿拉伯语不是一种独立的语言,而是与其他语言紧密相连的。因此,为阿拉伯人解决自然语言处理(NLP)任务的努力,尤其是情感分析,需要与阿拉伯本地人在社交文本中使用的英语或法语单词和短语相集成。这就造成了两种语言之间的重叠,对词语歧义的另一个挑战,如诱饵 (بيت家)、该死( ضمن 投保或包含)、罚款( فيني I-can)、杀死( كل 凡)、疯狂( انساني 人道)。

因此,词汇稀疏性变成了:

稀疏度= ∑单词 x(形态学 x 正投影)形式[单词] +(英语和法语)单词

为了弄清楚这能达到多大,我们需要先解决我的一个博士研究问题:

如何将阿拉伯语情感词与其屈折变体和正字法变体进行映射?

单词匹配

别忘了,阿拉伯语资源极其匮乏,我们没有起点,尤其是黎凡特方言。我们创建了带标签的数据集,并训练了一个语言识别器,从语码转换的脸书数据中汇编了一个包含 100 万条评论的阿拉伯语语料库。

我们在脸书语料库上训练了单词嵌入,由此语料库中的每个单词都被神经网络架构作为实数值向量投影到新的阿拉比齐嵌入空间中。然后,我们将余弦向量相似度与基于规则的方法相结合,从该嵌入空间中发现输入情感词的屈折形式及其拼写变体。

图片由作者使用神经网络背景

我们发现几乎每一个我们输入的情感词都有屈折和正字法形式,但令我们惊讶的是,有些词达到了 1K 多种形式!如字 i7tiram احترام 尊敬:

1,069 个表单匹配积极情感阿拉伯语单词 i7tiram(尊重)

情感分析

一个词的 1K+形式对情感分析意味着什么?

情感分析的基本技术是无监督和有监督的 approaches⁷,称为基于词典和机器学习的方法。

在基于词典的方法中,在预定义的正面和负面单词列表或具有情感得分的单词列表中搜索输入文本中的每个单词,凭直觉判断句子中正面或负面单词的数量决定了该句子的情感。这在很大程度上是正确的,但是它对缺乏情感词的肯定句或否定句无效,例如在讽刺或多词表达中。

在一种更智能的方法中,机器学习,一种算法通过从训练数据中学习来学习将输入文本分类为正面、负面或中性,这些训练数据是由人类注释者预先标记为正面、负面或中性的句子。为算法提供的训练数据越多,它在学习哪些模式、单词或单词共现导致正确的情感类别方面就变得越好。这种方法在对缺乏情感词的句子进行分类时应该表现得更好,但是创建大型数据集在时间和价格方面都非常昂贵。

非常大的词汇稀疏性挑战了这两种技术:

我们怎样才能创建一个包含所有形式的情感词汇的词典呢?另一方面,有标签的数据集应该有多大才能覆盖所有形式的情感词?

预计到这两种方法面临的挑战的复杂性,我决定尽可能自动地为 Arabizi 归纳出形态上和拼写上丰富的情感词典。我们在项目-rbz 上发布这项工作的成果出版物和资源。

音译

尽管阿拉伯语是用拉丁字母书写的,但它毕竟是阿拉伯语,所以为什么我要把它当作一种新的语言,并赋予它感情;我们就不能把它音译成阿拉伯文字吗?

作者图片

首先,这种非正统的转录产生了严重的单词歧义。因为阿拉伯语有短元音和长元音音位,以及轻声和重读辅音音位,所以一个阿拉伯语单词很容易与两个或更多的阿拉伯语单词混淆。

短元音是音调符号,长元音是元音字母ا و ي / ā、σ(或 wā)和 yā(或ī)/,为此,单词 غابة ghābeh 森林与长元音 ā 会与黎凡特方言阿拉伯语中的否定词غبي·加贝愚蠢与短元音 a 混淆。由于没有长短元音之分,两者都可以转录为 ghabeh。

至于轻声和重读辅音音素对应词,ذ د ك س ت和ظ ض ق ص ط是两个不同的字母组,分别代表轻声和重读字母 th、d、k、s、t 。阿拉伯语单词 dareb 可能是否定的ضربḍarb(强调)击中或物理打击或درب darb(软 d) 路径或路线的转录。

因此,映射到两个或更多阿拉伯字母的元音字母和拉丁辅音字母的拼写不一致会影响音译,从而为大多数阿拉伯语单词提供了几种可能性。音译在线进行,逐字逐句,用户在输入每个阿拉伯语单词后,从可能的音译列表中手动选择他们想要的阿拉伯语单词。 Yamli 以此闻名:

Yamli 阿拉伯音译

其次,Arabizi 是方言阿拉伯语的转录,而不是现代标准阿拉伯语(MSA ),其中的单词选择和表达因地区而异。因此,开发一个适合所有人的音译方法而不去迎合每一种方言是幼稚的。这是谷歌对整个文本进行自动化音译的努力,我们测试了一条来自黎巴嫩的积极的阿拉伯语推文:da5l Jame lik w hadam tik/oh-my(表情)你的美丽和你的幽默(女性)。

2019 年谷歌翻译;2020 年,它给出了:走进你的句子,摧毁你

在这种情况下,与将其音译为错误的阿拉伯语单词并试图在之后对其进行分类相比,包含屈折的积极单词 jamelik (your-beauty)hadam tik(your-hum)的阿拉伯语情感词典将更好地将该句子分类为积极的。

第三,出于情感分析的目的,方言阿拉伯语是资源贫乏的:把一种资源贫乏的语言的文字转换成另一种文字有什么意义?

原图: Benhance 画廊,我所想我所说的 Ghonemi

结论

简而言之,我通过我的研究了解到,充分吸收一种语言带来的挑战,并在处理任务之前评估所需 NLP 任务的可用或所需资源是至关重要的。

虽然阿拉伯语包含了太多的挑战,但不一致的拼写和拉丁化并不是新现象。例如,爪哇方言和 Alsatian⁸语是启发式转录的;希腊语、波斯语、印地语、孟加拉语、乌尔都语、泰卢固语和泰米尔语也被转录成拉丁文字,称为希腊语、芬利语、 Hinglish、Binglish

我希望我对这篇文章中详细描述的 Arabizi 的词汇挑战的理解能够对社交媒体上低资源语言的情感分析的复杂性有所启发,并激励 NLP 社区探索为其他高稀疏性语言提供资源的类似方法。

[1] Baly,Ramy 等人,“情感树库和形态学丰富的递归深度模型,用于有效的阿拉伯语情感分析。” ACM 亚洲和低资源语言信息处理汇刊(TALLIP)16.4(2017):1–21。

[2]法尔哈、易卜拉欣·阿布和瓦利德·马格迪。" Mazajak:一个在线阿拉伯情感分析器."第四届阿拉伯语自然语言处理研讨会会议录。2019.

[3]穆罕默德·阿里·亚甘。"“Arabizi”:阿拉伯俚语的一种当代风格."设计问题24.2(2008):39–52。

[4] Seddah,Djamé等人,“建立一个用户生成内容的北非阿拉伯语树库:应对地狱”计算语言学协会第 58 届年会论文集。2020.

[5]沙利文,娜塔莉。写阿拉伯语:在推特上用罗马化的黎巴嫩阿拉伯语拼写变体。Diss。2017.

[6]马里亚姆·阿布莱兹。"拉丁化的阿拉伯语和双语能力的联系."兰卡斯特大学语言学研究生会议语言教学。英国兰卡斯特。第三卷。2009.

[7]张,雷,,刘兵."用于情感分析的深度学习:一项调查." Wiley 跨学科评论:数据挖掘与知识发现 8.4 (2018): e1253。

[8]米勒、爱丽丝和卡伦堡。"文本语料库和新书写语言的挑战."第一届资源不足语言口语技术(SLTU)和资源不足语言协作与计算(CCURL)联合研讨会会议录。2020.

希望你喜欢这篇文章,我有时会在推特上发一些关于资源匮乏的自然语言处理的东西: @TahaTobaili

不到 50 行 Python 代码中的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-in-less-than-50-lines-of-python-fc6451114c6?source=collection_archive---------45-----------------------

神经网络并不总是答案……

照片由 pixabay 上的 Free-Photos-242387 拍摄

自然语言处理(NLP)可能是一个难以理解的话题。NLP 涵盖了大量不同的学科和建模技术,从主题分析到机器翻译和语音识别到语音合成。情感分析包含在 NLP 系列中,是对一段文本中表达的情感进行量化的过程。通常,情感是根据文本的积极或消极程度来评估的。

最先进的情感分析技术通常涉及循环神经网络,如长期短期记忆模型(LSTMs)或计算成本高昂的 BERT 嵌入,大量的优秀材料已被写入如何创建和训练这些。然而,也许你不需要复杂的建模或大量的代码来实现有竞争力的性能。

那么,我们如何着手创建自己的情感分析模型呢?

数据

这里使用的数据可以在 Kaggle 上找到,包括训练集中的 27,481 条带标签的推文和测试集中的 3,534 条推文。因此,让我们继续使用每个数据科学家最好的朋友熊猫来加载数据:

import pandas as pdtraining_df = pd.read_csv("train.csv")
training_df.head()

让我们对测试集做同样的事情:

test_df = pd.read_csv("train.csv")
test_df.head()

注意,测试集没有selected_text列。因此,让我们确保我们所做的任何数据清理都适用于训练集和测试集的text列。

数据处理

为了简单起见,我们不想在清理方面做得太多,但我们可以做一些简单的事情来帮助任何模型识别情绪。数据清理过程如下:

  1. 删除推文中的所有超链接
  2. 替换常见的缩写
  3. 删除标点符号(分词器为我们做了这件事)

在我们清理的同时,我们还可以将情感标签映射到整数,并从同一个函数返回它们。

import reCONTRACTIONS_DICT = {"can`t":"can not",
                     "won`t":"will not",
                     "don`t":"do not",
                     "aren`t":"are not",
                     "i`d":"i would",
                     "couldn`t": "could not",
                     "shouldn`t": "should not",
                     "wouldn`t": "would not",
                     "isn`t": "is not",
                     "it`s": "it is",
                     "didn`t": "did not",
                     "weren`t": "were not",
                     "mustn`t": "must not",
                    }def prepare_data(df:pd.DataFrame) -> pd.DataFrame:

    df["text"] = df["text"] \
              .apply(lambda x: re.split('http:\/\/.*', str(x))[0]) \
              .str.lower() \
              .apply(lambda x: replace_words(x,contractions_dict))

    df["label"] = df["sentiment"].map(
                        {"neutral": 1, "negative":0, "positive":2 }
                        )
    return df.text.values, df.label.valuesdef replace_words(string:str, dictionary:dict):
    for k, v in dictionary.items():
        string = string.replace(k, v)
    return stringtrain_tweets, train_labels = prepare_data(train_df)
test_tweets, test_labels = prepare_data(test_df)

句子分词器:

现在我们需要将每条 tweet 标记成一个固定长度的向量——特别是一个嵌入了的 TFIFD。为了实现这一点,我们可以使用 Keras 的内置Tokenizer(),适合训练数据。

from keras.preprocessing.text import Tokenizertokenizer = Tokenizer()
tokenizer.fit(train_tweets)train_tokenized = tokenizer.texts_to_matrix(
                             train_tweets,
                             mode='tfidf'
                             )test_tokenized = tokenizer.texts_to_matrix(
                             test_tweets,
                             mode='tfidf'
                             )

系统模型化

接下来,我们需要选择我们的模型。当谈到情感分析时,世界是你的牡蛎,然而为了长话短说,我们求助于每个数据科学家的第二好朋友, sk-learn 的随机森林分类器:

from  sklearn.ensemble import RandomForestClassifierforest = RandomForestClassifier(
                                n_estimators=500, 
                                min_samples_leaf=2,
                                oob_score=True,
                                n_jobs=-1,
                                )
forest.fit(train_tokenized,train_labels)print(f"Train score: {forest.score(train_tokenized,train_labels)}")
print(f"OOB score: {forest.oob_score_}")

选择n_estimatorsnum_samples_leaf时进行了少量的超参数调整,以尝试最大化分数,同时避免过度拟合。这给了我们 0.77 的训练得分和 0.69 的出袋得分(关于出袋得分的更多信息,这篇文章很好地解释了这一点,但是 TL;DR 是随机森林的验证分数的代理)。

现在,让我们来看看测试集上的性能:

print("Test score: {forest.score(test_tokenized,test_labels)"}

这个值为 0.69,所以到目前为止,我们进展顺利!

混淆矩阵

sk-learn 可以轻松获取分类器和测试数据来生成混淆矩阵,显示测试集的性能,如下所示:

from sklearn.metrics import plot_confusion_matrixplot_confusion_matrix(
    forest,
    test_encoded_docs,
    test_labels,
    display_labels=["Negative","Neutral","Positive"],
    normalize='true'
)

正如混淆矩阵所显示的,到目前为止,当谈到我们卑微的随机森林时,一切都很好。

这告诉我们很多关于我们所犯错误的类型。大多数错误发生在预测积极和中性情绪以及消极和中性情绪之间的差异时,在错误的大格局中,这并不是最糟糕的。然而值得庆幸的是,我们很少混淆积极情绪和消极情绪,反之亦然。

我们与 VADER 相比如何?

VADER 是一个“基于规则的情绪分析工具,专门针对社交媒体表达的情绪”。但是,对我们来说重要的是,这是一个现成的模型,可以用作基准。

from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzeranalyzer = SentimentIntensityAnalyzer()
vs=[]
for sentence in test_tweets:
    vs.append(analyzer.polarity_scores(sentence)["compound"])vader_scores = []
for v in vs:
    if v < -0.5:
        score = 0
    elif v < 0.5:
        score = 1
    else:
        score = 2
    vader_scores.append(score)

给定阈值 0.5,VADER 在中性情绪类上实现了大致相同的真阳性率,但在积极和消极情绪类上的表现都比我们的模型差——很高兴知道训练我们自己的模型是值得的!

那么我们在这里学到了什么?

情绪分析并不像看起来那么神秘。当然,如果我们增加模型的复杂性,改进数据清理和使用更复杂的嵌入,我们可以做得更好,我们仍然能够实现合理的性能,而不需要任何东西。当你考虑到当前 Kaggle 竞赛的领先者得了 0.73 分,而我们用不到 50 行代码就达到了 0.69 分,我很高兴把它留在那里…

情感分析:朴素贝叶斯算法介绍

原文:https://towardsdatascience.com/sentiment-analysis-introduction-to-naive-bayes-algorithm-96831d77ac91?source=collection_archive---------3-----------------------

来源:stocksnap.io

数据集:https://www . ka ggle . com/c/情操分析电影评论/数据

本教程假设读者对贝叶斯定理和文本分析完全无知。你只需要按照教程和一切都解释了一个新鲜的人工智能/毫升。如果你是专业用户,希望快速修改概念,你可以访问 我的 github 库(Senti _ analysis . ipynb)上的代码。

对于任何类型的数据科学项目,您需要做的第一件事就是加载数据并使用它。我更喜欢(也是我认识的大多数数据科学家)用二手熊猫来下载数据(图 1)。给定数据以为单位。tsv 格式(制表符分隔变量)。我已经把它转换成。csv 使用 excel,同时可以使用*。tsv 格式也是。当我加载数据时,我遇到了一个小问题,因为在一些行中使用了特殊字符(大约 4 行包含/、分隔符和反斜杠)。在加载数据之前,我必须手动删除这些字符。

图 1:加载数据

我强烈建议新用户使用基本的熊猫指令来玩游戏。您可以使用:dataset.info()来获得不同列的汇总,如果任何列包含任何带有 NAN 数据的行(如果是,那么有多少?).请使用 dataset.head()、dataset.tail()、dataset.describe()、dataset['\(ColumnName'] e.t.c 来深入了解数据集。例如(图 2)使用数据集。\)ColumnName.value_counts()给出每种情绪的计数(设 0 为一星评价,4 为五星评价)。从这里我们可以猜测,平均来说这部电影似乎是一部三星级电影。

图 2:基本 pandas 命令的使用

为了进一步进行情感分析,我们需要进行文本分类。我们可以用“词袋(BOW)”模型进行分析。用外行人的话来说,BOW 模型将文本转换成数字形式,然后可以在算法中用于分析。

具体来说,BOW 模型用于文本数据中的特征提取。它返回一个包含所有单词和每个单词重复次数的向量。它被称为 BOW,因为它只关心一个单词重复的次数,而不是单词的顺序。让我们举一个例子来更好地理解它(假设每个文档只包含一个句子):

文件 1:瑞士是一个美丽的国家。文档 2:印度是一个拥有聪明的 IT 专业人士的国家。美国是一个充满机遇的国家。

下表称为文档术语矩阵(DTM)。
———————
| Words->Swzld 是一个聪明的 IT 教授美丽的国家印度美国 opport
| Doc 1 Vector->1 1 1 1 1 0 0 0 0 0 0
Doc 2 Vector->0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 0
| Doc 3 Vector->0 1 1 0 1 0 1 0 1 0 1 1 1
|累计->1 3 1 3 1 2 1 1 1 1 1 1 1 1 1 1 1
———————
上图所示型号为 monogram 型号。 如果一次取两个单词(例如:瑞士是一个美丽的国家……),那么它被称为双字母模型,同样地,一次取 N 个单词,它将是 N 字母模型。较高克数的模型往往比 monogram 模型效果更好。

每个文档中的内容越长,每个向量的长度就越长(将包含许多零)。如果文档太大,文档向量将是稀疏向量。稀疏向量需要大量内存来存储,并且由于长度的原因,即使是计算也会变得很慢。为了减少稀疏向量的长度,可以使用诸如词干化、词汇化、转换成小写或忽略停用词等技术

现在,我们将使用 sci-kit-learn 的 CountVectorizer 模块生成 DTM(图 3)。要阅读更多关于 CountVectorizer 的参数,您可以访问 这里 。如上所述,我们将使用:

  • tokenizer =覆盖字符串记号化步骤,我们从 NLTK 的 Regex 记号化器生成记号化器(缺省情况下:None)
  • lowercase = True(不需要使用,因为默认情况下设置为 True)
  • stop_words = 'english '(默认情况下不使用,为了改善结果,我们可以提供一个自定义的停用词列表)
  • ngram_range = (1,1)(默认情况下,将使用 its (1,1),即严格的单字母组合,(2,2)仅使用双字母组合,而(1,2)两者都使用)

图 3:使用计数矢量器准备“单词包”

我们现在将分割数据用于训练和测试,以检查我们的模型表现如何(图 3)。此外,我们将随机化数据,以防我们的数据首先包括所有积极的,然后是所有消极的或其他类型的偏见。我们将使用:scikit_learn 的train _ test _ split()来拆分 text_count(其中包含我们的 X)和 dataset[‘情绪’](其中包含 Y)。

图 4:使用 train_test_split 将数据分为训练和测试数据集。

现在我们有了训练和测试数据。我们应该开始分析了。我们的分析(和大多数 ML 分析一样)将分为 5 个步骤(记住它们的一个助记法是 DC-FEM 记住哥伦比亚特区消防和紧急医疗服务):

  1. 定义模型
  2. 编译模型
  3. 拟合模型
  4. 评估模型
  5. 用模型做预测

1.定义模型

我们将使用 朴素贝叶斯【NB】分类器之一来定义模型。具体来说,我们将使用 多项式分类器 。作为一个 ML 的新生,你可以使用 sklearn 这里 给出的备忘单来决定用于特定问题的最佳模型。它告诉我们使用 NB 分类器。让我们绕道了解更多关于 NB 模式的信息。

朴素贝叶斯模型

该模型应用贝叶斯定理,并天真地假设不同特征之间没有关系。根据贝叶斯定理:

后验=可能性*命题/证据

或者

P(A|B) = P(B|A) * P(A)/P(B)

举个例子:在一副扑克牌中,选择一张牌。假定一张牌是一张脸牌,那么这张牌成为皇后的概率是多少?
这个可以用贝叶斯定理解决。
P(皇后给脸牌)= P(皇后|脸)
P(给脸皇后)= P(脸|皇后)= 1
P(皇后)= 4/52 = 1/13 P(脸)= 3/13 从贝叶斯定理:
P(皇后|脸)= P(脸|皇后)P(皇后)/P(脸)= 1/3

对于具有多个变量的输入:
P(y|x1,x2,… xn) = P(x1,x2,… xn|y)* P(y)/P(x1,x2,…xn)
使用朴素贝叶斯我们假设 x1,x2 … xn 相互独立,即:
P(x1,x2,…xn | y)= P(x1 | y)* P(x2 | y)…* P(xn | y)
P(Xi)分布中的假设例如,假设高斯分布将产生高斯朴素贝叶斯(GNB),或者多项式分布将产生多项式朴素贝叶斯(MNB)。

朴素贝叶斯模型特别适用于文本分类和垃圾邮件过滤。使用 NB 算法的优点是:

  • 需要少量的训练数据来学习参数
  • 与复杂的模型相比,可以相对快速地进行训练

NB 算法的主要缺点是:

  • 这是一个不错的分类器,但却是一个糟糕的估计器
  • 它适用于离散值,但不适用于连续值(不能用于回归)

NB 算法的困境

关于 NB 算法的一个具有挑战性的问题是:尽管 NB 算法中的条件独立性假设在现实生活中几乎不成立,但是 NB 算法作为分类器是如何工作得如此之好的呢?我不会在这里讨论解决方案,而是将您引向包含解决方案的资源( 这里 )。简而言之,答案在于依赖性的分布,而不是依赖性,不知何故,由于分布,依赖性的影响抵消了。

NB 分类的损失函数

NB 分类使用零一损失函数。在此函数中,错误=错误分类的数量。这里,误差函数不考虑概率估计的准确性,假设具有最高概率的类被正确预测。比如说有 A 和 B 两个类,给了不同的属性(x1,x2,… xn)。P(A |所有属性)= 0.95,P(B |所有属性)=0.05,但是 NB 可能估计 P(A |所有属性)= 0.7,P(B |所有属性)= 0.3。这里虽然估计得远不准确,但分类是正确的。

让我们回到我们的分析。定义和编译模型的前两步简化为从 sklearn 中识别和导入模型(正如 sklearn 给出的预编译模型)。

2.编译模型

因为我们使用 sklearn 的模块和类,我们只需要导入预编译的类。Sklearn 在这里 给出了所有 职业的信息。

图 5:从 sklearn 库中导入多项式朴素贝叶斯模型

3.拟合模型

在这一步中,我们在多项式 b 中生成模型拟合数据集。为了寻找拟合模型时可以传递的参数,建议查看正在使用的模块的 sklearn 网页。对于 MNB 可以在这里勾选

图 6:在多项式朴素贝叶斯中拟合数据。

4.评估模型

这里我们量化我们模型的质量。我们使用 sklearn 库中的 度量 模块来评估预测(图 7)。

图 7:使用 sklearn 的度量来评估模型

调整模型

我们观察到我们的模型的准确率超过 60%。我们现在可以利用我们的模型来增加它的准确性。

尝试不同的 n-grams

详情见图 8(二元模型)和图 9(三元模型)。

图 8:文本矢量化的二元模型。

图 9:文本矢量化的三元模型。

尝试不同的朴素贝叶斯算法

参考图 10(补码 NB)、图 11(高斯 NB)、图 12(伯努利 NB)。

图 10:使用互补朴素贝叶斯模型进行情感分析

图 11:使用高斯朴素贝叶斯模型进行情感分析

图 12:使用伯努利朴素贝叶斯模型进行情感分析

提高准确性

我们已经尝试使用不同的 n-grams 和不同的朴素贝叶斯模型,但最高准确率徘徊在 60%左右。为了改进我们的模型,让我们尝试改变方式,创建弓。目前,我们用 CountVectorizer 创建了 BOW,它计算文本中单词的出现次数。一个词出现的次数越多,它对分类就变得越重要。

术语频率-逆文档频率

让我们使用 TF-IDF,它考虑了术语频率和逆文档频率的乘积。术语频率是一个术语在文档中出现的频率。假设一个术语在一个文档中出现了“f”次,带有“d”个单词。
词频= f/d
IDF 为‘逆文档频率’。如果一个语料库包含 N 个文档,而我们感兴趣的术语只出现在 D 个文档中,那么 IDF 是:
IDF = log(N/D) TF-IDF 是术语频率和逆文档频率的乘积。 TF-IDF 显示了一个词在语料库中的稀有度。如果一个词很少见,那么它可能是某个特定情感/信息的标志性词汇。

图 13:使用中的 TfidfVectorizer

尝试非贝叶斯算法

即使是 Tfidf 矢量器(即创建不同的弓)也无助于提高模型的准确性。除了朴素贝叶斯算法,我们还可以选择随机梯度下降分类器或线性支持向量分类器。众所周知,这两种方法都能很好地处理文本数据分类。让我们试着用这些:

图 14:尝试不同的文本分类算法

推理

我们观察到,使用 TF-IDF 创建的 BOW 的线性支持向量分类器给出了最好的结果,准确率达到 63.88%。虽然准确性仍然很低,但仍需要对模型进行改进,以给出更好的结果。

祝贺大家完成教程。您应该已经了解了如何使用不同的分类器,以及朴素贝叶斯定理和与之相关的不同算法。我已经分享了一个关于建立和评估模型(DC-FEM)的广泛策略。还讨论了与朴素贝叶斯算法相关的挑战。我们讨论了“单词包”(BOW)模型以及使用 CountVectorizer 和 TfidfVetorizer 创建 BOW 的两种不同方式。

****建议读数:

我的 github 库访问完整代码。

从零开始展开朴素贝叶斯

使用 NLTK 的初学者文本分析

基于监督学习的书籍情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-a-book-through-supervised-learning-d56ba8946c64?source=collection_archive---------38-----------------------

用 Python 和 scikit 分析一本书的情感的简单教程——学习

图片来自 Pixabay马雷克·斯图津斯基

在本教程中,我将解释如何通过基于支持向量机(SVM)的监督学习技术来计算一本书的情感。

本教程计算圣奥古斯丁忏悔录的情感分析,可以从古腾堡项目页面下载。这部杰作分为 13 本书(章)。我们将每本书存储在不同的文件中,名为 number.text(例如 1.txt 和 2.txt)。每个文件的每一行只包含一个句子。

jupyter 笔记本可以从我的 Github 资源库下载:https://github.com/alod83/papers/tree/master/aiucd2021

一本书的情感分析的类似实验可以在下面的链接找到:https://towards data science . com/perspective-analysis-of-a-book-through-unsupervised-learning-df 876563 dd1b。在这种情况下,我解释了如何利用无监督学习技术来执行情感分析。

入门指南

监督学习需要一些带注释的文本来训练模型。因此,第一步包括读取注释文件并将其存储到数据帧中。注释文件包含每个句子的相关分数,该分数是正数、负数或空值。

import pandas as pddf = pd.read_csv('sources/annotations.csv')
df

我们可以计算一些关于注释的统计数据,比如正面、负面和中性分数的数量,以及注释的总数。我们可以使用应用于数据帧的count()方法。

df.count()
df[df['score'] > 0].count()
df[df['score'] < 0].count()
df[df['score'] == 0].count()

准备训练集和测试集

为了计算每个句子的情感,我们将利用监督学习技术,该技术利用二进制分类模型。该模型将一个句子作为输入,根据句子是否被正面评价,返回 1 或 0。因为我们的模型是二进制的,所以我们必须删除所有带有中性分数的注释。

import numpy as np
# Remove any 'neutral' ratings equal to 0
df = df[df['score'] != 0]

现在我们可以向 dataframe 添加一列,称为Positively Rated,包含 1 或 0,这取决于一个正的或负的分数。我们使用where()方法为数据帧的这个新列分配适当的值。

df['Positively Rated'] = np.where(df['score'] > 0, 1, 0)

计算情绪

我们定义一个辅助函数,称为calculate_indexes(),它接收监督学习模型(将在后面描述)和CountVectorizer向量作为输入,如后面所述。

在该函数中,我们通过open()函数打开对应于每本书的文件,我们通过函数file.readlines()读取所有行,并通过将predict()函数应用于模型来计算每一行的分数。

那么,我们可以定义三个指数来计算一本书的情绪:正面情绪指数(pi)、负面情绪指数(ni)和中性情绪指数(nui)。一本书的圆周率对应于一本书中的肯定句的数量除以该书的总句子数量。同样,我们可以计算一本书的 ni 和 nui。

def calculte_indexes(model,vect):
    pos_index = []
    neg_index = []
    neutral_index = []
    all_text = ""
    for book in range(1,14):
        file = open('sources/' + str(book) + '.txt')
        lines = file.readlines()
        pos = 0
        neg = 0

        for line in lines:
            score = model.predict(vect.transform([line]))

            if score == 1:
                pos += 1
            else:
                neg += 1
            all_text += ' ' + line.lower() 

        n = len(lines)
        pos_index.append(pos / n)
        neg_index.append(neg / n)

    return pos_index,neg_index

现在我们可以训练算法了。我们定义了两种不同的情况:第一种情况我们不考虑 ngrams,第二种情况我们考虑。我们定义了一个名为train_algorithm()的函数,可以通过指定 ngrams 的用法来调用它。

在函数中,我们首先通过名为train_test_split()scikit-learn函数将数据集分为训练集和测试集两部分。训练集将用于训练算法,测试集将用于测试算法的性能。

X_train, X_test, y_train, y_test = train_test_split(df['sentence'], 
                            df['Positively Rated'], random_state=0)

然后,我们构建标记计数矩阵,即包含每个句子哪些标记可用的矩阵。这可以通过类CountVectorizer来完成,该类接收要考虑的 ngrams 数量作为输入。在本教程中,只考虑两个 ngrams。我们只考虑最小文档频率等于 5 的标记。

vect = CountVectorizer(min_df=5).fit(X_train)

然后我们可以构建模型:我们使用包含在scikit-learn中的LinearSVC()类,并用训练集model.fit(X_train_vectorized, y_train)训练它。

model = LinearSVC()
model.fit(X_train_vectorized, y_train)

最后,我们通过预测测试集的输出并将结果与测试集中包含的真实输出进行比较来测试算法的性能。作为指标,我们测量 AUC,但我们也可以计算其他指标。

predictions = model.predict(vect.transform(X_test))
print('AUC: ', roc_auc_score(y_test, predictions))

一旦训练好模型,我们就可以通过calculte_indexes()函数来计算指标。最后,我们绘制结果。

这里是功能train_algorithm()的全部代码。

from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as pltdef train_algorithm(df, ngrams=False):
    # Split data into training and test sets
    X_train, X_test, y_train, y_test = train_test_split(df['sentence'], 
                                                    df['Positively Rated'], 
                                                    random_state=0)

    # Fit the CountVectorizer to the training data
    vect = CountVectorizer(min_df=5).fit(X_train)
    if ngrams:
        # Fit the CountVectorizer to the training data specifiying a minimum 
        # document frequency of 5 and extracting 1-grams and 2-grams
        vect = CountVectorizer(min_df=5, ngram_range=(1,2)).fit(X_train)
        print('NGRAMS')
    else:
        print('WITHOUT N-GRAMS')
    # transform the documents in the training data to a document-term matrix
    X_train_vectorized = vect.transform(X_train)
    # Train the model
    model = LinearSVC()
    model.fit(X_train_vectorized, y_train)

    # Predict the transformed test documents
    predictions = model.predict(vect.transform(X_test))print('AUC: ', roc_auc_score(y_test, predictions))

    pos_index, neg_index = calculte_indexes(model,vect)

    X = np.arange(1,14)
    plt.plot(X,pos_index,'-.',label='pos')
    plt.plot(X,neg_index, '--',label='neg')
    #plt.plot(X,neutral_index,'-',label='neu')
    plt.legend()
    plt.xticks(X)
    plt.xlabel('Libri')
    plt.ylabel('Indici')
    plt.grid()
    if ngrams:
        plt.savefig('plots/svm-ngram-bsi.png')
    else:
        plt.savefig('plots/svm-1gram-bsi.png')
    plt.show()

进行实验

现在我们可以在启用和禁用 ngrams 的情况下运行实验。

train_algorithm(df, ngrams=False)
train_algorithm(df, ngrams=True)

没有 n-grams 的实验

用 n-grams 做实验

吸取的教训

在本教程中,我向你展示了如何通过监督学习技术来计算一本书每一章的情感:

  • 监督学习需要一些训练集,即一些手动标注的数据。因此,在开始玩模型之前,您应该做注释数据的(小)部分这一枯燥的任务。训练集越大,算法的性能越好;
  • 要计算一个句子的情感,你应该使用一个(二进制)分类算法,比如支持向量机(SVM)。scikit-learn 库提供了许多分类算法;
  • 一旦选择了模型,就可以用训练集对其进行训练;
  • 别忘了测试模型的性能:)

基于无监督学习的书籍情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-a-book-through-unsupervised-learning-df876563dd1b?source=collection_archive---------44-----------------------

用 Python 分析一本书情感的简单教程

foto diChen specdaPixabay

入门指南

在本教程中,我将向您展示如何通过基于 AFINN 词典的无监督学习(UL)技术,对包含在书中的文本进行情感分析。本教程利用了仅适用于英语和丹麦语的afinn Python 包。如果你的文本被写成不同的语言,你可以先翻译成英文,然后使用afinn包。

这个笔记本应用了情绪分析圣奥古斯丁忏悔,可以从古腾堡项目页面下载。这部杰作分为 13 本书(或 13 章)。我们将每本书存储在不同的文件中,名为 number.text(例如 1.txt 和 2.txt)。每个文件的每一行只包含一个句子。

你可以从我的 Github 库下载代码:https://github.com/alod83/papers/tree/master/aiucd2021

首先从afinn包中导入Afinn类。

from afinn import Afinn

然后通过指定使用的语言创建一个新的Afinn对象。

afinn = Afinn(language=’en’)

计算情绪

使用 Afinn 给出的分数来计算情感

afinn对象包含一个名为score()的方法,该方法接收一个句子作为输入,并返回一个分数作为输出。分数可以是正的、负的或中性的。我们计算一本书的分数,只需简单地将该书所有句子的分数相加。我们定义了三个变量> pos、neg 和 neutral,分别存储一本书所有句子的所有正面、负面和中性得分的总和。

首先,我们定义三个索引,它们将在后面使用。

pos_index = []
neg_index = []
neutral_index = []

我们通过open()函数打开对应于每本书的文件,我们通过file.readlines()函数读取所有行,并为每一行计算分数。

那么,我们可以定义三个指数来计算一本书的情绪:正面情绪指数(pi)、负面情绪指数(ni)和中性情绪指数(nui)。一本书的圆周率对应于一本书中的肯定句的数量除以该书的总句子数量。同样,我们可以计算一本书的 ni 和 nui。

for book in range(1,14):
    file = open('sources/' + str(book) + '.txt')
    lines = file.readlines()
    pos = 0
    neg = 0
    neutral = 0

    for line in lines:
        score = int(afinn.score(line))

        if score > 0:
            pos += 1
        elif score < 0:
            neg += 1
        else:
            neutral += 1

    n = len(lines)
    pos_index.append(pos / n)
    neg_index.append(neg / n)
    neutral_index.append(neutral / n)

绘图结果

以图形方式显示结果

最后,我们可以通过使用matplotlib包来绘制结果。

import matplotlib.pyplot as plt
import numpy as npX = np.arange(1,14)
plt.plot(X,pos_index,'-.',label='pos')
plt.plot(X,neg_index, '--',label='neg')
plt.plot(X,neutral_index,'-',label='neu')
plt.legend()
plt.xticks(X)
plt.xlabel('Libri')
plt.ylabel('Indici')
plt.grid()
plt.savefig('plots/afinn-bsi.png')
plt.show()

吸取的教训

在本教程中,我向您展示了一个简单的策略来计算包含在一本书中的文本的情感。这可以通过 Python 提供的afinn包来实现。您可以遵循以下步骤:

  • 把书的正文分成几章,然后把每一章存放在一个单独的文件里
  • 把每一章的所有句子分成不同的行
  • 通过Afinn类提供的score()方法分别计算每个句子的分数
  • 计算每个章节的正面情感指数、负面情感指数和中性情感指数
  • 绘图结果。

如果想应用监督学习技术进行情感分析,可以继续关注:)。

基于朴素贝叶斯的微博情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-a-tweet-with-naive-bayes-ff9bdb2949c7?source=collection_archive---------14-----------------------

每秒发布数百万条推文。它帮助我们了解公众对特定事件的反应。为了获得推文的情感,我们可以使用朴素贝叶斯分类算法,这只是贝叶斯规则的应用。

贝叶斯规则

贝叶斯规则仅仅是描述一个事件发生的概率,而这个概率是建立在与它相关的另一个事件发生的先验知识之上的。

那么假设事件 B 已经发生,事件 A 发生的概率为

假设事件 A 已经发生,事件 B 发生的概率是

使用这两个方程,我们可以将它们统一改写为

让我们看看推文,以及我们如何从推文中提取特征

我们将有两个推特语料库,正面和负面推特。

正面推文:“我很开心,因为我在学习 NLP”,“我很开心,不难过。”

负面推文:“我很难过,我没有学习 NLP”,“我很难过,不开心。”

预处理

我们需要对数据进行预处理,这样可以节省大量内存,减少计算过程。

  1. 小写:我们将所有的文本转换成小写。这样,像学习和学习这样的词就可以理解为同一个词
  2. 删除标点符号、网址、名称:我们将删除标点符号、网址、名称或标签,因为它们对推文的情感分析没有帮助。
  3. 去除停用词:像“The”、“is”这样的停用词对情感没有帮助。因此,这些词必须删除。
  4. 词干:像“take”、“taking”这样的词被视为相同的词,并转换为基本词,这里是“take”。这样可以节省大量内存和时间。

概率方法:

为了获得单词的概率统计,我们将创建一个这些单词的字典,并统计每个单词在正面和负面推文中的出现次数。

让我们看看这些单词计数如何有助于找到这两个类的单词的概率。这里,单词“I”出现了三次,并且阳性语料库中的唯一单词总数是 13。因此,假设推文是正面的,单词“I”出现的概率将是

freq 表示一个词出现的频率,class: {pos,neg}

对我们词汇表中的所有单词都这样做,我们会得到这样一个表格:

在朴素贝叶斯中,我们将发现每个词是如何对情感做出贡献的,这可以通过正类和负类的词的出现概率的比率来计算。我们来举个例子;我们可以看到,‘sad’这个词出现的概率更多的是针对否定类而不是肯定类。因此,我们将通过公式找到每个单词的这些概率的比率:

这个比率被称为似然性,其值介于(0,∞)之间。趋向于零的值表示与在负面推特中发生的概率相比,它在正面推特中发生的概率非常低,而趋向于无穷大的比值表示与在正面推特中发生的概率相比,它在负面推特中发生的概率非常低。换句话说,比值高意味着积极。此外,比率值 1 表示名称是中性的。

拉普拉斯平滑

有些单词可能只在某个特定的班级出现过。没有出现在否定类别中的单词将具有概率 0,这使得比率不确定。所以,我们将使用拉普拉斯平滑技术来追踪这种情况。让我们看看应用拉普拉斯平滑后等式是如何变化的:

通过在分子中添加“1 ”,使概率不为零。这个因子叫做α因子,在(0,1)之间;具体来说,当我们将该α因子设置为 1 时,平滑被称为拉普拉斯平滑。同样,概率之和将保持为 1。

在我们的示例中,唯一单词的数量是 8,因此 V= 8。

拉普拉斯平滑后,概率表将看起来像这样:

朴素贝叶斯:

为了估计一条推文的情绪,我们将取推文中出现的每个词的概率比的乘积。请注意,不在我们的词汇表中的单词将不起作用,并将被视为中性的。在我们的应用程序中,朴素贝叶斯的等式如下:

m =一条推文中的字数,w =一条推文中的字数

由于数据可能不平衡,并可能导致特定类别的有偏差的结果,因此我们将上面的等式乘以一个先验因子,该因子是正面推文的概率与负面推文的概率之比。

朴素贝叶斯的完全方程

因为我们取所有这些比率的乘积,我们可能会得到一个太大或太小而无法存储在我们的设备上的数字,所以这里出现了对数似然的概念。我们在朴素贝叶斯方程上取对数。

取似然方程的对数后,标度将改变如下:

让我们看一个例子。推特:“我很高兴,因为我在学习。

这是我们推文的总体对数可能性。

因此,推文的总体对数似然值大于零,这意味着推文是正面的。

缺点:

  1. 朴素贝叶斯算法假设单词相互独立。
  2. 语料库中的相对频率:有时人们会屏蔽可能具有攻击性的特定类型的推文,等等。这导致了数据的不平衡
  3. 词序:通过改变词序,情感可能会改变,但是使用朴素贝叶斯,我们不会遇到这种情况。
  4. 删除标点符号:记得在数据预处理中,我们删除了标点符号,这可能会改变推文的情绪。这里有一个例子:‘我敬爱的祖母:(’

结论:

朴素贝叶斯是一种简单而强大的算法,知道了数据就可以相应地对数据进行预处理。朴素贝叶斯算法也用于社会的许多方面,如垃圾邮件分类、贷款审批等。

一段时间内(1958 年至 2019 年)所有 Billboard 热门 100 首歌曲的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-all-billboard-hot-100-songs-over-time-1958-2019-3329439e7c1a?source=collection_archive---------32-----------------------

流行音乐歌词平均每年多得 1.3%的负面!

马里乌斯·马萨拉尔在 Unsplash 上的照片

我是老派灵魂乐和说唱音乐的粉丝。我还是一名数据科学家,专攻自然语言处理(NLP)和自然语言理解(NLU)。在听音乐的时候,我发现自己在想,为什么旧学校的音乐似乎比现代音乐更积极、更有益健康。

在我看来,我听的大多数老校魂歌曲都是关于爱情和舞蹈的,而且它们通常含有相对较少的亵渎性语言。他们似乎更快乐,总体上也更积极。与此同时,我听的大多数当代说唱歌曲对亵渎性语言的使用要慷慨得多,而且总体上看起来更加愤怒和消极。我想知道这是否真的是普遍的情况。作为一名数据科学家,我为了满足自己的好奇心,对数据进行了深入研究。

我决定对过去几十年的代表性音乐样本进行情感分析,看看音乐是否变得越来越消极。我想知道随着时间的推移,流行音乐歌词中使用的语言的积极性得分是否有显著变化。

数据

我决定用 Billboard Hot 100 作为代表样本。Billboard Hot 100 是美国追踪一周前 100 首最流行歌曲的标准图表。我使用了一个数据集,包含了从 1958 年 8 月 2 日到 2019 年 6 月 22 日的所有 Billboard Hot 100 条目。

在获得 Billboard Hot 100 数据集后,我使用 LyricsGenius API 客户端抓取了 genius.com 上所有条目的歌词。我成功地为 26138 首独特的歌曲搜集了歌词。我对歌词进行了情感分析,以下是我的结果:

结果

  1. 平均而言,进入 Billboard Hot 100 的歌词倾向于接近中性。数据集中所有歌词的平均情感极性是 0.125。其中-1 完全为负,1 完全为正。
  2. 2019 年记录了最多的负面歌词,1979 年记录了最多的正面歌词。
  3. 2019 年的歌词比 1979 年的歌词负面 4 倍
  4. 平均而言,在 1958 年至 2019 年期间,歌词情绪每年比 1.3%。

5.1958 年歌词热门关键词包括:【“喜欢”、“来了”、“渺小”、“曼宁”、“知道”、“跳喜欢”、“好”、“时间”】

6.2019 年歌词热门关键词包括:["喜欢"、"耶"、"黑鬼"、"婊子"、"小婊子"、"爱"、"需要"、"操"]

分析

在这里,我详细说明了我得到结果的步骤。

  1. 安装和导入库:我使用了一些流行的 Python 模块进行文本处理。我还用 LyricsGenius 刮过 genius.com。

  2. API 认证:在使用 LyricsGenius 包之前,我注册了一个 Genius 客户端访问令牌。

3.下载 Billboard Hot 100 数据集:我从数据世界获得 Billboard Hot 100 数据集。

4.定义函数:我为这个项目写了四个函数。

a.一个从 genius 中抓取歌词的功能。

b.一个获取歌词情感的函数。

c.一个处理所有文本预处理的函数。

d.一个函数,以获取歌词中的关键词。

5.把所有的东西放在一起:在导入包和数据,然后定义函数之后,我把函数应用到数据上,得到我的结果。

结论

这是什么意思?这一分析表明,流行音乐歌词可能越来越消极。然而,从这项分析中不清楚的是,这是否反映了社会趋势。作为一个社会,我们变得越来越消极了吗?根据我们创造和消费的文化艺术品,我们能对人类状况做出多少假设?这些是我在分析中没有探讨的问题。然而,这些问题很有趣,可以作为后续研究的基础。

如果您有兴趣自己探索这些数据,或者有兴趣查看我关于这个项目的 Jupyter 笔记本,请随意查看项目 GitHub 资源库

动物穿越评论的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-animal-crossing-reviews-7ae98bc91dd3?source=collection_archive---------43-----------------------

在对星谷的狂热之后,我想我再也不会回到任何需要耕种/囤积/捕鱼/采矿的游戏中去了。但是我在这里:自从我 3 月 22 日买了《动物穿越:新视野》(ACNH)以来,总共花了 100 个小时,这比 BotW 还多小时。说真的,ACNH 不是一个我认为我会喜欢的游戏:没有什么太令人兴奋的,只是一堆研磨。但它很可爱,而且它来得正是时候,让我(和许多人)在保持社交距离的同时与朋友联系。Polygon 上有一篇关于这种游戏中的研磨元素如何提供一定程度的放松和舒适的文章。因此,自 3 月 20 日发布以来,ACNH 的销量直线上升就不足为奇了,谷歌对 ACNH 的搜索量也是如此。

谷歌搜索对动物穿越和任天堂 Switch 的兴趣

该图还显示,对 ACNH 的兴趣增加也增加了对任天堂 Switch 的兴趣。而且,任天堂 Switch 现在几乎在所有地方都卖光了,包括在 T2。新闻报道 ACNH 打破了任天堂 Switch 冠军在日本的销售记录。亚马逊上的 ACNH 纸质版的价格也几乎翻了一番。我大胆的推断是,任天堂 Switch 销量的增加和 ACNH 销量的增加是正相关的。

似乎 ACNH 很受玩家欢迎。然而,当我在一些游戏网站上查看评论时,如 GameSpot 和 Metacritic,平均用户评分分别为 6.4 和 5.2/10,尽管该网站的官方评级为 9/10。那么,为什么玩家对这款游戏的评价比官方评测人员差呢?我对用户评分感到惊讶(我会给 7/10,比神奇宝贝剑与盾更好),我很好奇用户对 ACNH 的看法。

所以,我做了一个快速的情感分析(因为我刚刚从克里斯·毛雷尔教授本周的文本分析课上学到了它)。我首先使用 Python 上的beautiful soup从 Metacritic 中删除评审数据。然后,在使用 r 进行情感分析之前,我对 CSV 文件进行了一点格式化。我比较了来自词典包的几个词典,并决定 Hu-Liu、Jockers-Rinker 和 NRC 词典最适合我在分析元评论时使用,因为它们在情感评分方面具有一致性。

用户评论的平均情感分数

平均情绪得分

由三个词典生成的平均情感得分表明,用户评论通常不太正面(0 为中性,1 为正面)。然而,在最近的评论中有一个越来越积极的趋势。评论中不太积极的情绪得分并不令人惊讶,因为在 3450 个用户评级中,几乎有 50%是负面的。高度正面的评论可以被高度负面的评论抵消,从而得到相对中性的分数。

用户评论中的正面词和负面词

那么,这些 Metacritic 用户在评论中谈论的是什么呢?我整理了由胡-刘和 Jockers-Rinker 词典(未显示)生成的消极和积极词汇的列表,并根据它们的频率制作了词云。

否定词云

我猜人们不喜欢这个游戏中的资本主义思想,并把汤姆·努克描述成独裁者,而我们(玩家)是他的奴隶(支付我们的住房贷款)。限制”是最常出现的负面词汇。我推断这种频繁发生是由于用户抱怨每个控制台一个岛的限制(也许?). '“失望”出现,表明由于炒作,这些用户的期望很高。

正词云

这个正面词云以“好玩”为最常出现的正面词。像“享受”、“享受”和“享受”这样的词经常出现,足以推断一些用户确实喜欢这个游戏。

这两个字云恰恰说明了喜欢游戏的人对游戏的趣味性和创意元素赞不绝口,认为这个游戏很神奇(等等。).他们非常喜欢这个游戏,因此给予了积极的评价和很高的评分。那些不喜欢游戏的人给了很低的分数(读“0”),并在他们的评论中使用更严厉的词语,如“独裁者”、“奴隶”、“失望”。这些恰恰说明 ACNH 是一个收到两极分化意见的游戏。

用户评论中的情感

词语及其与情感的关联

我还用 NRC 的词典研究了与这些评论相关的情绪。尽管用户最常使用与信任相关的词,但像“系统”、“账户”和“系列”这样的词并不能表达用户对游戏的态度。像“长”、“等待”和“开始”这样的期待词在这里也没有太多意义。表示快乐的单词似乎也出现得更频繁。悲伤、厌恶、愤怒和恐惧是在这个评论集中检测到的负面情绪。他们最有可能与那些评价低的评论联系在一起。

情感-词词云

出于好奇,我做了这个分析。似乎 Metacritic 用户对 ACNH 的意见两极分化,如中性情绪得分、正面和负面词云以及网站上的评级百分比所示。但这种感性的分析并没有讲述 ACNH 评论的全部故事。我意识到这个分析的局限性,尤其是关于情感的分析。Metacritic 用户也不能很好地代表 ACNH 玩家,因为它只是为数不多的游戏评论网站之一。YouTube 可能是另一个平台,玩家可以在这里谈论游戏并分享他们的经历。

德里推特的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-delhi-tweets-877e060823b1?source=collection_archive---------43-----------------------

演职员表:莎拉·库菲斯,Unsplash

估计推文中的正面/负面分数

数据是一个比许多人认为的更广泛的术语。它不仅包含 Excel 文件或等效的结构化表格数据,还包含文本文件、音频文件、图片等非结构化数据。考虑到所有数据格式的详尽列表,可以很好地认识到结构化数据只是冰山一角。尤其是文本数据,可以在大多数主题中找到。

本文旨在使用关键词和特定位置的技术从 Twitter 上抓取推文。此外,我还将展示可以用来评估一条 tweet 的情绪的软件包。我感谢 Twitter 社区允许我们访问这些数据。使用的编程语言是 Python 3.3,使用的 IDE 是 Spyder 3.3.3。

检索推文

Python 提供了一些有趣的包来从 Twitter 中抓取 tweets。GetOldTweets3 就是这样一个包(我觉得它很方便,因为它很灵活)。

#Importing the Packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import GetOldTweets3 as got#Setting the Parameters
text_query = 'coronavirus'
location = 'Delhi'

tweetCriteria = got.manager.TweetCriteria()
.setQuerySearch(text_query).setNear(location)
.setSince("2020-03-01").setUntil("2020-05-05")#Creating a list of all tweets
tweets = got.manager.TweetManager.getTweets(tweetCriteria)#Creating list of chosen tweet data
text_tweets = [[tweet.text] for tweet in tweets]
text_date = [[tweet.date] for tweet in tweets]tweets = pd.DataFrame(list(zip(text_date, text_tweets)), 
columns = ['Date', 'Tweet'])

在导入基本的和必需的包之后,我们首先设置服务于我们目的的基本参数。这些参数包括:

setQuerySearch :一条推文应该包含的关键词或短语。

setNear :推文的参考位置。

setSince :需要抓取推文的日期。

set until:tweets 需要被抓取的日期。

出于这个分析的目的,我将参考位置设置为德里,将文本查询设置为冠状病毒(因为这是人们目前在推特上谈论的主要内容)。开始日期设定为2020–03–01(2020 年 3 月 1 日)至2020–05–05(2020 年 5 月 5 日)。这是两个月多一点。

运行时间主要取决于 tweets 被抓取的数量和互联网速度。

一旦 tweet 被抓取,就会创建一个带有单独的日期和 tweet 列的数据框。该数据集包含 37,135 条推文和 2 列(日期和推文)。

In [2]: tweets.shape
Out[2]: (37135, 2)

清理推文以供进一步分析

Tweets 预清理

一旦创建了基本的数据框架,清理推文以供进一步分析就变得非常重要。这包括删除不必要的括号、撇号、用户名等。

#Cleaning the Tweetsfrom nltk.corpus import stopwords
date = []
tweet = []
words = set(nltk.corpus.words.words())
for i in range(0,len(tweets)):
 date.append(tweets.iloc[i,0])
 string = tweets.iloc[i,1]
 string = re.sub(r”http\S+”, “”, string) #Removes Hyperlink
 string = re.sub(‘@[^\s]+’,’’,string) #Removes Usernames
 string = re.sub(‘#[^\s]+’,’’,string) #Removes Hashtags
 tweet.append(string.strip(“[“).strip(“]”))new_tweet = pd.DataFrame(list(zip(date, tweet)), columns = [‘Date’, ‘Tweet’])

上面几行代码删除了特殊字符和短语,如标签、超链接、用户名和括号。最后,我们得到一个相对干净的数据框架。

清理后的推文

寻找推文的情感分数

Python 提供了多个包来评估文本的情感。在这个实例中使用的包是Vader perspection。更多关于这个包的信息可以在找到。

#Checking the Polarity
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
sent = SentimentIntensityAnalyzer()
sentiment_dict = []
for i in range(0,len(new_tweet)):
 sentiment_dict.append(sent.polarity_scores(new_tweet.iloc[i,1]))positive = []
neutral = []
negative = []
compound = []
for item in sentiment_dict:
 positive.append(item[‘pos’])
 neutral.append(item[‘neu’])
 negative.append(item[‘neg’])
 compound.append(item[‘compound’])sentiment_df = pd.DataFrame(list(zip(positive, neutral, negative, compound)), columns = [‘Positive’, ‘Neutral’, ‘Negative’, ‘Compound’])

new_tweet[‘Positive’] = sentiment_df[‘Positive’]
new_tweet[‘Negative’] = sentiment_df[‘Negative’]
new_tweet[‘Neutral’] = sentiment_df[‘Neutral’]
new_tweet[‘Compound’] = sentiment_df[‘Compound’]

Vader perspection以字典的形式返回输出,包含 4 个键( pos,neu,neg,compound )。 pos、neuneg 的值介于 0 和 1 之间,0 表示不具有该词的任何特征,1 表示很可能是正面、负面或中性评论。最后一项复合表示根据 pos、neuneg 得分计算的范围(-1,1)内的最终得分。

运行代码,我们得到以下输出:

情感得分

让我们讨论上面输出中的一些实例。

索引 11 上的推文:推文是用印地语写的。因此,该算法无法为其分配任何情感,并且默认给出完美的中性分数。

指数 4 上的推文:空白推文被分配一个完美的中性分数。

索引 12 上的推文:用英语写的印地语推文也被分配为中性。

有许多推文是用印地语写的,因为参考地点是德里。反击的一个方法是删除所有中立的推文。这符合逻辑,因为我们主要关注的是正面和负面的推文。

#Removing all the neutral comments
wf_tweet = new_tweet.loc[new_tweet[‘Neutral’] != 1].reset_index()
wf_tweet = wf_tweet.drop(‘index’, axis = 1)

最终输出

我们现在已经给所有的推文分配了情感分数。具有负复合值的推文描绘负面情绪,而具有正复合值的推文描绘正面情绪。

我们现在可以将复合值分为正值和负值。

输出

结论

我们有一个如上给出的最终输出。可以对数据框进行进一步分析,以挖掘信息,从而有趣地洞察德里(印度)民众对冠状病毒的看法。日期列可以证明是一个重要的属性,也可以看出人们的态度/情绪是如何随时间变化的。根据情绪得分,人们还可以发现哪些标签在负面和正面的推文中使用最多。然而,这种分析超出了本文的范围。

感谢您的阅读。我真诚地希望它对你有所帮助,我一如既往地欢迎讨论和建设性的反馈。

给我发邮件:icy.algorithms@gmail.com

你可以在领英上找到我。

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

使用 Python 和情感分析探索和可视化您的 LinkedIn 网络

原文:https://towardsdatascience.com/sentiment-analysis-of-linkedin-messages-3bb152307f84?source=collection_archive---------18-----------------------

希望优化您的 LinkedIn 个人资料?为什么不让数据为你服务呢?

照片由亚当·索罗门Unsplash 拍摄

动机

如果你是 LinkedIn 的用户,你有没有想过你的社交网络中的人群?如果你正在努力拓展你在数据科学领域的人脉,你的人脉中的大多数人都在数据科学相关领域工作吗?

你的留言呢?它们是否大多是积极的,关于与你兴趣相关的话题?

作为 LinkedIn 上的一名活跃用户,我有超过 500 个联系,我对我的网络中的人的统计数据以及我在过去两年中收到的消息感到好奇。

分析 LinkedIn 数据有什么好处?好吧,如果你正在为工作机会优化你的 LinkedIn 档案,为什么不使用可用的数据作为你的工具呢?

在本文中,我将结合可视化和自然语言处理来分析我的网络和消息。读完这篇文章后,你应该能够分析自己的 LinkedIn 数据,并从中获得见解!

数据

我没花太多力气就拿到了数据,因为你可以直接从 LinkedIn 上下载。这里的是你可以怎么做的。

具体来说,我导入了消息和连接数据。

我将使用 Datapane 嵌入来自每个库的可视化,这是一个用于发布和共享 Python 报告的 Python 框架和 API。如果您想为我下面的任何一个图或表格留下评论,请随时点击左上角的“查看完整报告”留下您的评论,我会尽快回复您!

这里是这篇文章的笔记本,这样你就可以跟随文章并可视化你自己的数据!

网络

连接的日期

从导入开始并检查数据

在上表中,我只展示了我最近的 10 个关系作为例子。Connected On表示我与那个人联系的日期。我将把该列转换成日期-时间并用 Plotly 可视化

我每天的新连接数都有一个峰值,特别是 2020 年 1 月到 2020 年 7 月,是我在 LinkedIn 上最活跃的时期。

公司

我网络中的人在哪些组织工作?我可以用这样的条形图:

但是在这种情况下,也许 treemap 在可视化公司方面做得更好?

树形图将分层数据显示为一组嵌套矩形。每个组由一个矩形表示,矩形的面积与其值成比例。

有了树形图,比较一家公司与其他公司的相关比例就更容易了!看起来我的网络中有很大一部分人来自拜耳作物科学。第二大百分比来自我的大学。

位置

哇!没想到会看到这么多数据科学家。我人际网络中最常见的职位是我的人际网络目标群体,这很好。

有些人的头衔可能以“数据科学家”开头,但头衔中也有更多的词。找出所有以“数据科学家”开头的职位

>>> network.Position.str.startswith('Data Scientist').sum()
268

消息

是时候分析消息了!在过去两年的 3895 封邮件中,我可以发现哪些隐藏的事实?

这些数据中有一些有趣的栏目。既然我们对消息的内容感兴趣,那就让我们更深入地挖掘一下。

语言检测

除了英语,我的一些信息是越南语,一些是其他语言(我不知道它们是什么意思)。由于我只想分析英文消息,所以我将使用来自 spacy_langdetect 的 LanguageDetector 从其余消息中提取英文消息。

例如,我将检查文本“这是英语测试”是否被检测为英语文本

{'language': 'en', 'score': 0.9999987378584019}
This is an english text. {'language': 'en', 'score': 0.999998324978528}

99%认为是英语考试。让我们用越南语文本再试一次

{'language': 'vi', 'score': 0.9999995883738908}
Đây là Tiếng Việt {'language': 'vi', 'score': 0.9999981449655853}

而且被检测出是越南人!现在让我们用它来表达整个信息

厉害!现在我们所有的信息都是英文的。

命名实体

命名实体是一个现实世界的对象,如人、地点、组织、产品等..比如,巴拉克·奥巴马是人名还是地名?纽约是一个地点还是一个组织?

有很多方法可以检测命名实体,但是 SpaCy 是我喜欢的工具。让我们用这条消息来测试一下:

"This is amazing Tran, it's wonderful you could experience that part of Mexico. Yes, I was born in Guadalajara, and lived in Morelia when I was a kid. I visited Guanajuato just a couple of times. What is even better, I have been living in Japan and Singapore for many years, and about 6 months in Hà Nội. I was amazed about the tons of similarities between Vietnam and Mexico "
[(Tran, 'ORG'),
 (Mexico, 'GPE'),
 (Guadalajara, 'GPE'),
 (Morelia, 'GPE'),
 (Guanajuato, 'PERSON'),
 (Japan, 'GPE'),
 (Singapore, 'GPE'),
 (many years, 'DATE'),
 (about 6 months, 'DATE'),
 (Hà Nội, 'ORG'),
 (tons, 'QUANTITY'),
 (Vietnam, 'GPE'),
 (Mexico, 'GPE')]

ORG是组织,GPE是地缘政治实体,PERSON是人名,DATE是日期实体,QUANTITY是数量实体。

displacy.serve(message1, style=’ent’)

我们甚至可以想象句子中的命名实体

其中一些分类不正确,如 Tran(人名)或 Guanajuato(地点),但大多数都是正确的!让我们找到所有消息的命名实体

我的消息中的大多数命名实体都是个人实体!这看起来像是我们在消息中获得了许多个人实体,但是我们也应该小心模型的正确性。虽然大部分分类正确,但也有部分不正确。

最常见的单词

我的 LinkedIn 留言里最常见的词是什么?

从一些基本的数据处理开始

清理完文本后,让我们想象一下我们得到了什么

这些大词是我们希望从 LinkedIn 信息中看到的词。我们也知道我的谈话是真的进入数据。相当酷!

情感分析

我的 LinkedIn 消息的情绪是什么?我猜大部分都是正面的,但是有多少百分比呢?因为我没有可用的训练数据集,所以我使用预训练数据集。来自 NLTK 的 SentimentIntensityAnalyzer 是一个完美的工具。

{'neg': 0.0, 'neu': 0.323, 'pos': 0.677, 'compound': 0.6369}

SentimentIntensityAnalyzer 分析中性、消极和积极的百分比。Compound是百分比组合的最终结果。因此,我们可以创建基于复合的情感分析功能

使用此函数预测样本文本的情感

>>> predict_sentiment
('Negative', 62.9)>>> predict_sentiment('It is super useful')
('Positive', 77.3)>>> predict_sentiment('It is just okay')
('Positive', 38.8)

这似乎工作得很好!如果对你的文本不起作用,在这里找到提取情绪的其他方法

现在我们可以将这一点应用到我们所有的信息中

正如所料,大多数信息都是积极的。我不记得什么时候我的信息是负面的。有哪些负面信息,哪些词让它们变得负面?

让我们看看一些消极的词汇,并把它们形象化

>>> sample = list(sentiment_df[sentiment_df['Sentiment'] == 'Negative'].Message)[2]
>>> sample'lots code gets shipped w technical debt'

因为词债是负的!

正面词的指标有哪些?我们拿一个肯定句的例子来找出答案

“高兴”这个词使句子更加积极!

结论

恭喜你!您刚刚学习了如何使用自然语言处理来分析您自己的 LinkedIn 数据或者类似的文本数据。我们不知道数据中隐藏着什么,直到我们努力去发现它。分析你自己的数据,你会对你所看到的感到惊讶,并且学到一些有用的东西!

如果你有任何问题,请给我留言!你可以在这篇报道的文章中找到所有的图表!

想要根据您的 LinkedIn 数据生成您自己的报告?这篇文章的笔记本可以在这里找到。一定要在笔记本的目录下添加 CSV 文件,准备好分析!

我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。

这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:

[## 用 Python 模块 Newspaper 和 NLTK 查找文章中的常用词

使用 newspaper3k 和 NLTK 从报纸中提取信息和发现见解的分步指南

towardsdatascience.com](/find-common-words-in-article-with-python-module-newspaper-and-nltk-8c7d6c75733) [## 如何用 Python 对 Tweets 进行标记

我们应该选择 TweetTokenizers 还是其他 4 种常见的 Tokenizers?

towardsdatascience.com](/an-introduction-to-tweettokenizer-for-processing-tweets-9879389f8fe7) [## PyTorch 是什么?

想想 Numpy,但是有强大的 GPU 加速

towardsdatascience.com](/what-is-pytorch-a84e4559f0e3) [## 自然语言处理中的卷积神经网络

什么是卷积神经网络,如何利用它进行情感分析?

towardsdatascience.com](/convolutional-neural-network-in-natural-language-processing-96d67f91275c) [## 我收集了超过 1k 的顶级机器学习 Github 配置文件,这就是我的发现

从 Github 上的顶级机器学习档案中获得见解

towardsdatascience.com](/i-scraped-more-than-1k-top-machine-learning-github-profiles-and-this-is-what-i-found-1ab4fb0c0474)

基于拥抱脸管道特征的政治演讲情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-political-speeches-using-hugging-faces-pipeline-feature-3109c121d351?source=collection_archive---------51-----------------------

在评估政治演讲时,你更相信谁——人类专家还是算法?2020 年 2 月至 6 月期间,在新加坡对新冠肺炎的演讲进行了测试,得出了一些有趣的结果。

选举季节让我们许多人充满恐惧。但这也是一个很好的机会,可以用一个实际的用例来测试一些新的 NLP 特性。

最近几周,我一直在试验拥抱脸(Hugging Face)的 HF 管道功能,看看如何轻松快速地使用它们来分析/总结新加坡的政治演讲。这篇文章将概述我对上述演讲进行短期和长期情绪分析的尝试,这些演讲在 2020 年 2 月至 6 月之间发表,具有 HF 的管道特征。

我发现结果相当令人印象深刻,尽管只是使用默认模型,没有对本地数据进行额外的微调。随着美国和新加坡等国家的选举即将到来,测试这些基于变形金刚的模型在不同政治环境下的表现还有进一步的空间。

回购、数据和警告

这篇文章的 Github repo 包含一个笔记本和生成这篇文章中的一些图表所需的数据,以及 Plotly 图表和 CSV 结果表的样本。如果您希望一次生成多个演讲的结果,可以很容易地调整代码。

这些数据包括来自新加坡政府和总理办公室网站的六份官方演讲记录。这些演讲的重点是政府应对新冠肺炎挑战的计划,并将为即将到来的大选提供更广泛的辩论框架。为了更公平地评估情绪,一些过长的文本被分成了更小的段落,但绝大多数演讲都是以原始形式进行分析的。

更严格的情感分析应用需要使用特定领域的数据对模型进行微调,尤其是在涉及医学或法律问题等专业主题的情况下。然而,在这篇文章中,我使用 HF 管道进行“开箱即用”的情感分析,这意味着结果是基于默认蒸馏模型(更具体地说:蒸馏-基础-未装箱-微调-SST-2-英语)。HF 的网站上有一个与情感分析和文本分类任务兼容的其他模型的列表,如果你想进一步实验的话。

分析一篇演讲的情感

感谢 HF 的优秀员工,pipeline API 处理了复杂编码方面的繁重工作。在简单的文本预处理(分成段落)和清理之后,执行情感分析只需要几行代码

管道生成情感标签以及分数。通过将标签和分数提取到一个单独的数据框中,我们可以轻松地检查结果,并查看模型可能出现错误的地方:

对我来说,更棘手的任务是找到一种可视化和注释结果的好方法。为了清晰和易于使用,我最终选定了一个组合 Plotly 和谷歌幻灯片。请随意切换到您选择的可视化库。

这是来自数据集中第一个语音的情感分析的样本结果:

HF 的情绪分析管道对这次演讲的 33 个段落中的 23 个段落进行了积极的评估。

一眼看去,你就能知道说话者在积极或消极的领域停留了多长时间。在这种情况下,我们可以看到新加坡总理李显龙如何平衡新冠肺炎经济影响的严峻警告与政府计划帮助新加坡人应对失业的保证。他还以积极的方式结束了 6 月 7 日的演讲,将全国人民团结在一个共同的挑战周围。

分析一组演讲的情绪

如果我们将一系列的“情绪结构”图表组合在一起,我们可以很快了解来自同一机构的发言者是否在以不同的语气传递一致的信息,或者每个人是否在唱不同的调子。你也可以用这个来观察一个主题的情绪是如何随着时间而变化的。

下图以 10 次演讲为例,展示了新加坡政治领导人在 2 月至 6 月期间,在预期的民意调查之前,是如何改变他们在新冠肺炎问题上的讲话语气的。如果你比较左右两边的专栏,你会注意到整体情绪(对新冠肺炎)有明显的转变,从 2 月到 4 月底以消极为主,到 6 月份变得更加积极:

这一结果并不令人惊讶,因为在政府于 5 月份成功控制疫情之前,新加坡 4 月份的疫情明显恶化。随着选举的临近,高层政治领导人显然需要转向一种新的沟通策略——和语气——他们在 6 月份就这么做了。

2 月和 4 月下旬的讲话不包括在回购中,但可以在上述两个政府网站的链接中找到。

我认为这可以用来分析,比如说,川普在新冠肺炎疫情爆发初期和后期的语调变化。我也很想在拜登和特朗普的辩论中验证这一点。

算法出错的地方

这篇文章中的演讲分析结果可以从这里下载快速浏览。看看你是否同意算法的评估。

当然也有错误。下面的图表显示,在分析新加坡国家发展部长王冠逸的新冠肺炎 6 月 9 日在 T4 的演讲时,Distilbert 模型至少在两个方面出现了错误:

该算法错误地将他演讲中讨论新加坡新的测试和接触者追踪能力的一部分贴上了负面标签,而这一部分本应被视为中性或积极的。在演讲接近尾声时,它再次出错,错误地将一段赞扬商界贡献的段落标为负面。

在其他地方,这种算法可能会被对一种可怕情况的模糊而笼统的描述所“击败”,比如新加坡内阁资政张志勇·何岸 6 月 11 日演讲的第二段:

上一段中的语言大大低估了新冠肺炎造成的破坏的程度和严重性,有趣的是,算法将其标记为积极的。人类分析师会得出相反的结论。

结束注释+进一步工作

一个显而易见的改进是用一个关于新加坡政治和/或新冠肺炎的定制数据集对模型进行微调。然而,这个任务看起来并不简单(至少对我来说),找到一个相关的标记的训练数据集并不容易。

我也很有兴趣看看 HF 的 pipeline 的结果如何与其他已知的情感分析方法相比较。

但总的来说,尽管这种方法有明显的局限性,我还是对 HF 管道的结果印象深刻。显然,围绕演讲的情绪不仅仅取决于所用的词语,还取决于演讲者的演讲和举止。

一个完整的基于人工智能的演讲情感分析应该理想地结合使用计算机视觉和音频取证,以更好地理解演讲者的面部表情和说话声音如何增加演讲的整体情感。但是这超出了本文的范围。

同时,如果您发现了错误或者用这种方法做了一些有趣的事情,请告诉我。在以下时间 Ping 我:

推特:蔡振鸿

领英:www.linkedin.com/in/chuachinhon

基于 Python 的社交媒体情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-social-media-with-python-45268dc8f23f?source=collection_archive---------12-----------------------

用于对社交媒体文本中的情感进行分类的 Python 工具的初学者友好概述。我讨论了我使用不同工具的经历,并提供了一些建议,帮助您开始自己的 Python 情感分析之旅!

T. Selin ErkanUnsplash 上的照片

在古罗马,公共话语发生在城市中心的广场上。人们聚集在一起交流思想,讨论与社会相关的话题。如今,这种公共话语已经转移到 Reddit 等网站的数字论坛、Twitter 的微博平台和其他社交媒体上。也许作为一名研究人员,你很好奇人们对某个特定话题的看法,或者作为一名分析师,你希望研究贵公司最近营销活动的效果。用情感分析监控社交媒体是衡量公众意见的好方法。幸运的是,使用 Python 有许多选择,我将讨论我已经试验过的方法和工具,以及我对这种体验的想法。

在我的学习之旅中,我从最简单的选项 TextBlob 开始,通过 PytorchTensorflow 逐步使用 transformers 进行深度学习。如果您是 Python 和情绪分析的初学者,不要担心,下一节将提供背景知识。否则,请随意跳到下面的图表,查看 Python 自然语言处理(NLP)领域的可视化概述。

情感分析简介

情感分析是 NLP 的一部分;文本可以通过情感(有时称为极性)进行分类,可以是粗粒度的,也可以是细粒度的。粗略情感分析可以是二元(正面或负面)分类,或者是包括中性的 3 分等级。而 5 分制是精细分析,代表高度积极、积极、中立、消极和高度消极。早期的分析依赖于基于规则的方法,如 Python 库 TextBlobNLTK-VADER 所使用的方法,这两种方法在初学者中很受欢迎。大多数机器学习(ML)方法都是基于特征的,并且涉及浅度或深度学习。浅层方法包括在单层神经网络中使用分类算法,而 NLP 的深度学习需要神经网络中的多层。这些层中的一层(第一个隐藏层)将是一个嵌入层,它包含上下文信息。

对神经网络的详细解释超出了本文的范围,但是对于我们的目的来说,过于简化就足够了:神经网络是一组算法,它们以模拟人脑中神经元网络的方式来学习关于数据的关系。为了更深入地探究神经网络背后的迷人理论,我建议这篇介绍性文章

我注意到的一个共同的主题是,一种方法越善于从上下文中捕捉细微差别,情感分类的准确性就越高。有几种技术可以以捕捉上下文的方式编码或嵌入文本,以获得更高的准确性。因此,嵌入层对于深度学习模型的成功是不可或缺的。今天,深度学习正在以令人兴奋的速度推进 NLP 领域。深度学习的前沿是 transformers ,预训练的语言模型可能有数十亿个参数,它们是开源的,可以用于最先进的准确度分数。我创建了下面的图表来展示可用于情感分析的 Python 库和 ML 框架,但是不要感到不知所措,有几个选项可供初学者使用。

可用于情感分析的 Python 库和机器学习框架。图片作者。

基于规则的 Python 库

TextBlob 很受欢迎,因为它使用简单,如果您是 Python 新手,这是一个很好的起点。我的一个早期项目涉及用 TextBlob 计算的极性和主观性分数的数据可视化。下面的代码片段显示了对从 Twitter 实时流出的 tweets 的 TextBlob 的简单实现,完整代码请查看我的要点

虽然使用 TextBlob 很容易,但不幸的是它不是很准确,因为自然语言,尤其是社交媒体语言,很复杂,并且基于规则的方法会忽略上下文的细微差别。 NLTK-VADER 是一个专门为处理社交媒体文本而开发的 NLP 包。我建议,如果你正在处理 tweets,并且正在为 TextBlob 寻找一个比较点,那就去看看吧。

TextBlob 示例,完整的要点和实时 Twitter 流可用。

基于特征方法的机器学习

我意识到,如果我想要更高的准确性,我需要使用机器学习;语境化是关键。我从传统的浅层学习方法开始,如单层神经网络中使用的逻辑回归和支持向量机算法。除了比深度学习需要更少的工作之外,其优势还在于从原始数据中自动提取特征,只需很少或不需要预处理。我使用 NLP 软件包 spaCy 和 ML 软件包 scikit-learn 来运行简单的实验。我受到了一篇博文的启发,作者使用这两个包来检测社会评论中的侮辱,以识别欺凌者。对于细粒度的情感分类,机器学习(基于特征)比基于规则的方法有优势,这篇优秀的帖子5 级斯坦福情感树库(SST-5)数据集上比较了基于规则的方法和基于特征的方法的准确性。

深度学习:嵌入和变形金刚

深度学习和单词嵌入进一步提高了情感分析的准确度。2013 年,谷歌创建了 Word2Vec 嵌入算法,它与手套算法一起仍然是最受欢迎的两种单词嵌入方法。要进行实际演练,请查看的这篇文章,作者在文章中使用嵌入式技术创建了一个图书推荐系统。传统上,对于深度学习分类,单词嵌入将被用作递归卷积神经网络的一部分。然而,这些网络需要很长时间来训练,因为递归和卷积很难并行化。注意力机制提高了这些网络的准确性,然后在 2017 年,transformer 架构引入了一种使用注意力机制的方法,没有递归或卷积。因此,在过去几年中,NLP 在深度学习方面的最大发展无疑是变形金刚的出现。

Python 深度学习库

当我开始研究深度学习时,我依靠 Reddit 的建议选择了一个 Python 框架作为起点。对初学者的最大建议是 Python 库, Keras ,它是一个功能 API。我发现它非常容易理解,特别是因为它建立在 Tensorflow 框架之上,具有足够的抽象性,细节不会变得令人不知所措,并且足够简单,初学者可以通过玩代码来学习。仅仅因为 Keras 简化了深度学习,这并不意味着它不具备以复杂的方式处理复杂问题的能力。在必要时,用 Tensorflow 工具来增加 Keras 相对容易,以便在较低的抽象层次上调整细节,因此 Keras 是深度学习战场上的有力竞争者。在下面的代码片段中,我试图从预训练的语言模型中构建一个分类器,同时尝试使用多样本丢失分层 k 折叠交叉验证,所有这些都可以使用 Keras 实现。

多辍学模型的 Keras 代码片段,带有分层 k-fold 交叉验证的抽样。

我对变形金刚的介绍是可爱命名的 Python 库,拥抱变形金刚。这个库使得将变形金刚与主要的机器学习框架、 TensorFlowPytorch 一起使用变得简单,并且提供他们自己的hugging faceTrainer来微调他们提供的预训练模型的分类。最受欢迎的 transformer BERT 是一个在巨大语料库上预先训练的语言模型;基本模型有 1.1 亿个参数,大型模型有 3.4 亿个参数。对于情感分类,BERT 必须在下游分类任务中使用带有情感标签的数据集进行微调。这被称为迁移学习,它利用预先训练的模型权重的力量,允许在微调过程中迁移上下文嵌入的细微差别。还有其他几个变压器,如罗伯塔,阿尔伯特和伊莱克特拉,仅举几例。除了非常容易使用之外, Huggingface 还有很好的文档,如果你有兴趣探索其他模型的话,链接于此。此外,由于在 CPU 上进行微调需要时间,我建议利用 Colab 笔记本,这将允许你在谷歌的云 GPU 上免费运行实验(有每月速率限制),以加快训练时间。

哪个机器学习框架适合你?

我可以根据我的经验提供我对我更喜欢哪个机器学习框架的看法,但我的建议是至少尝试一次。OG 框架 Tensorflow 是一个优秀的 ML 框架,但是在我的 NLP transformers 实验中,我主要使用的是 Pytorch 框架(富于表现力、非常快速、完全控制)或 HF Trainer(直接、快速、简单)。我对 Pytorch 的偏爱是因为它允许在设计和修补实验时进行控制——而且它比 Keras 更快。如果你喜欢面向对象编程胜过函数式编程,我建议你使用 Pytorch 框架,因为它的代码使用了类,因此简洁明了。在下面使用 Pytorch 的代码片段中,我创建了一个分类器类,并使用构造函数从该类创建一个对象,然后由该类的 forward pass 方法执行。

使用 Huggingface 预训练模型的 BERT py torch 实现片段。

需要额外的代码来运行向后传递,并使用优化器来计算损失和更新权重。 Pytorch 的代码明显比 Keras 所需的代码长。如果你喜欢快速编写代码,而不是详细说明每一个训练步骤,那么 Keras 是你更好的选择。然而,如果你想了解训练中发生的一切, Pytorch 让这成为可能。要获得带示例的 Pytorch 的分步指南,请查看这篇介绍性帖子。对于一个使用 Pytorch 的很酷的项目,我推荐维尼林·瓦尔科夫的这个很棒的教程,他向你展示了如何使用 BERT 和hugging face transformersPytorch ,然后用 FASTAPI 部署那个模型。

希望这篇文章能让你明白从哪里开始用 Python 进行情感分析,以及随着你的进步你有什么选择。就我个人而言,我期待了解更多关于 NLP 的最新进展,这样我就可以更好地利用现有的令人惊叹的 Python 工具。

纽约巨人队 2020 年选秀的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-the-new-york-giants-2020-draft-6f095e2363af?source=collection_archive---------84-----------------------

图片来源于NorthJersey.com 的克里斯·佩多塔——今日美国网

体育分析

对巨人队选秀权的球迷情绪的深入观察

对于纽约巨人队的球迷来说,过去 10 年左右的选秀之夜传递了各种各样的情感。有高潮也有低谷。根据选秀之夜的反应和在球场上的表现,前台已经确定了几个人选,最著名的是小奥黛尔·贝克汉姆和萨昆·巴克利。不幸的是,对于每一个 Saquon 或 Odell,都有一些 Ereck Flowers 或 Eli Apples 加入其中。

不久前,球迷对 NFL 选秀的反应主要是通过现场球队球迷的嘘声或欢呼声来衡量的。然而,在当今世界,球迷们迅速涌向 Twitter 或 Reddit 等社交媒体网站,让人们听到他们对球队未来发展方向的看法。我开始通过 Python 使用网络抓取和情感分析来捕捉这种反应。

我决定收集 Reddit 的评论,而不是 Twitter,因为在我看来,Reddit 用户的反应往往比 Twitter 上常见的“烧掉它”人群更合理。本文将介绍通过情感分析获取、探索和分析数据的过程。我的目标是足够详细,读者可以为他们自己喜欢的 NFL 球队复制这一分析。

我将使用 Python 和 Jupyter Notebook 作为 IDE 来进行这个分析。下面列出了使用的包和依赖项。

获取数据

一旦包被导入,第一步是获得实际的 Reddit 评论数据。幸运的是,PRAW 包(Python Reddit API Wrapper)让这个任务变得简单了。

要打开一个连接,登录 Reddit,然后跟随这个链接。接下来,点击下面截图左下角显示的“创建另一个应用程序”按钮。

然后填写申请表。填写您的姓名,选择一个脚本,并添加您计划如何使用从 API 提取的数据的简短描述。对于重定向 URL,请始终输入“http//localhost:8080”。

现在已经创建了应用程序,返回到 Jupyter 笔记本,并使用 praw.Reddit 创建一个到 Reddit 的连接。client_id 是一个 14 个字符的字符串,它将出现在上面访问的 Reddit 应用程序页面上您的姓名和“个人使用脚本”下。你可以在创建 app 后找到“client_secret”,它是一个 27 个字符串。其余的字段非常简单明了,包括输入 Reddit 帐户信息。

一旦连接建立,您将能够访问 PRAW 提供的所有强大功能。出于我的目的,我只需要从 Reddit 访问标题、时间戳和评论数据。然而,你还可以获得更多的特性,比如文章正文、投票数和评论数。

为了访问我正在寻找的信息,我从 NYGiants subreddit 中的最后 750 个帖子中提取了帖子 id。这样,我确信我会涵盖 4 月 23 日至 25 日发生的整个 NFL 草案。

在访问了 post ids 之后,我编写了一个嵌套的 for 循环来捕获我正在寻找的信息。首先,我遍历每个 id,从相关帖子中提取评论。然后我循环浏览每一条评论,找出它们的标题和日期。Praw 文档提供了可以从 Reddit 帖子中提取的提交对象的详尽列表。

结果数据帧

争论数据

上面的数据框提供了必要的数据来捕捉今年选秀期间纽约巨人队球迷的时代精神。运行这个循环需要相当长的时间,所以我复制了一份数据,并将其写入一个 CSV 文件,以便以后访问。我还过滤了数据,以便它只包含从 4 月 23 日开始到 4 月 25 日午夜结束的 Reddit 评论,以确保我只查看 NFL 选秀日。顺便提一下:我已经养成了从数据帧的一部分复制数据的习惯。这个习惯确保我不会遇到任何来自熊猫的复制警告的场景。

然而,我不想只是全面地探索草案评论,所以我还为巨人的每个顶级选秀(前 4 轮)创建了一个特定的草案名称。为了实现这个目标,我使用了一个正则表达式来查找包含每个选秀名称的 Reddit 帖子标题。我将正则表达式设置为选择每个草稿的名字或姓氏,而忽略字母大小写。当然还有更彻底的表达方式可以使用,但我觉得这种方法抓住了绝大多数的评论。仅安德鲁·托马斯一人就在 3 天内发表了 972 条评论。不出所料,球员被选中的时间越晚,他们从巨人队球迷那里得到的评论就越少。

可视化数据

现在数据准备好了,我可以研究数据,看看它显示了什么。我最喜欢的一种可视化文本数据的方式是单词云的形式。我认为这是一种有趣而简单的方式来理解纽约巨人队球迷对选秀的看法。

要生成单词云,您需要安装软件包并编写一个函数来生成图像。通过调用 WordCloud 函数,您可以轻松地定制单词云的不同方面,如最大字数、字体大小和配色方案。包含一个停用词列表是非常重要的,这样你的词云就不会被诸如 I、and、am 等填充词所占据。向海王星实验室人工智能大声喊出来,获得如何生成单词云的精彩教程。

戴夫·盖特勒曼在 2020 年 NFL 选秀中以第四顺位选中了安德鲁·托马斯,这多少有些出人意料。然而,许多球迷(包括我自己)对这个选择感到高兴,因为它有助于巩固过去几年来糟糕透顶的进攻线。下面是一个单词云,描述了巨人队球迷对安德鲁·托马斯的选择的感受。作为参考,在其他单词的上下文中较大的单词比其他单词包含在更多的 Reddit 帖子中。有几个词会立即出现,比如“棒极了”,这可能代表了许多发帖人对该作品质量的看法。“加强”和“铲球”对我来说也很突出,显然是关于修复纽约巨人队进攻线的上述问题。

安德鲁·托马斯词云

单词云并不是一种分析文本的复杂方法,但它确实提供了一种快速查看数据集中哪些单词最常见的方法。为了简洁起见,我不会包括其他选秀状元的词云。但是,如果您感兴趣,一旦编写了函数,代码很容易被其他玩家复制。

基本情感分析

情感分析使用自然语言处理(NLP)来确定一串文本是否具有正面、中性或负面的含义。这是快速解决我正在试图解决的问题的完美工具…巨人队的球迷对 2020 年 NFL 选秀有什么感觉?

我将使用一个名为 TextBlob 的包来完成这项任务。通过 TextBlob 运行情感分析将返回两个值,一个极性得分和一个主观性得分。极性分值的范围从-1 到 1,适用于字符串中的每个单词。肯定暗示的单词得分为 1,而否定暗示的单词标记为-1。串中这些分数的平均值产生最终的极性分数。主观性得分的范围是从 0 到 1,简单地衡量一个字符串的主观程度。例如,句子“我午餐吃了一份鸡肉三明治”的主观性得分较低,因为这是事实,因此没有解释的余地。在本文中,我将更多地关注极性得分。 TextBlob 网站有更多与其情感分析功能相关的信息。

下面的函数允许我将极性得分应用到每个球员的数据框中的每个评论。使用这个函数,我将一个字符串放入一个 TextBlob 中,然后删除停止的单词,最后计算剩余单词的极性得分。有必要删除停用词,以免夸大中性评论的数量。

一旦创建了“polarity_score”函数,就可以很容易地将它应用于每个球员的数据框,以计算每个评论的情绪。

在我分析的这一点上,我意识到我想要容易地分析每个玩家对彼此的情绪。所以我运行了几行代码,将每个玩家组合到一个数据框中。首先,我添加了一个名为“Player”的特性来识别评论是针对哪个玩家的。接下来,我将每个球员添加到一个名为“draft_class”的数据帧中。

现在,我可以轻松地比较 2020 年每个选秀权的球迷情绪了。为了完成这个任务,我决定使用 Plotly express ,因为它能够交付交互式可视化。这对于关注数据的特定部分以及悬停在数据点上查看特定值非常有用。

import plotly.express as px

我决定首先探索巨人的前四个选秀权的极性得分的分布。为了做到这一点,我创建了一个直方图,每个玩家都有不同的分布。Plotly express 还允许用户轻松调整直方图仓的数量、图表颜色和图表/轴标签,如下面的代码所示。下面的缩写循环删除了图表右侧自动生成的球员姓名的文本标签。我觉得包括这些标签是多余的,因为图例也是可用的。

注意:我为这篇文章中没有直接嵌入的可视化图形道歉。Embed.ly,支持媒体嵌入的技术遇到了一些技术问题。

[## 巨人选秀的极性得分分布| Bkmurphy 制作的直方图| Plotly

Bkmurphy 的“巨人选秀极性得分分布”交互图和数据是一个直方图,显示…

chart-studio.plotly.com](https://chart-studio.plotly.com/~bkmurphy/1.embed)

数据显示,所有 2020 年巨人队的选择都遵循类似的极性得分分布。对每个球员的大部分评论都围绕着一个中性的内涵。不过我们也看到 2020 选秀班正面评价明显多于负面。这可能预示着一些事情。首先,这可能意味着巨人的粉丝群对选秀的整体方向感到满意,对前台的工作感到满意。我认为这将是一个有点合理的结论,考虑到许多球迷希望看到今年选秀中的进攻线和防守。或者,这可能意味着球迷们正在合理化,选择的球员是最好的,有助于巨人未来的改善。

在查看了极性得分分布后,我对了解每个玩家正面、中立或负面评论的百分比很感兴趣。我很快编写了一个函数,将大于 0 的值分类为“正”,如果值等于 0 则为“中性”,如果小于 0 则为“负”。

然后,我将这个函数应用于每个玩家数据框的极性得分,为情绪创建一个新列。生成的数据框如下图所示。

每个草图拾取的最终数据框

此时,我可以操纵数据来显示每个玩家的每种情绪类型的百分比。我决定将数据可视化在一个堆积条形图中。这样做需要对上面显示的数据框进行一些额外的数据操作。对于每个玩家,我创建了一个新的数据框,通过将每个情感类型的值计数除以数据长度来实现。然后,我必须组合这些数据框,并将值放入数据透视表中,以正确格式化堆积条形图的数据。生成的数据透视表如下所示。

情感价值数据透视表

这个数据透视表提供了一种在交互式条形图中可视化结果的方式。我选择不包含开发数据透视表的代码,因为它有些冗长。如果有人感兴趣,我很乐意与大家分享本文之外的代码。

[## 纽约巨人 2020 选秀阶级情绪| Bkmurphy 制作的堆积条形图| plotly

Bkmurphy 的“纽约巨人队 2020 选秀阶层情绪”互动图和数据是一个堆积条形图,显示…

chart-studio.plotly.com](https://chart-studio.plotly.com/~bkmurphy/13.embed)

快速浏览一下 2020 年选秀班的情绪可以发现,大约 55%与安德鲁·托马斯有关的评论都有积极的内涵。相反,约 14%的评论对选择他持负面看法。再次,这支持了巨人队的球迷对安德鲁·托马斯作为第一轮选秀权感到满意的想法。

大多数选秀权都和安德鲁·托马斯有相似的正面/负面评论比例。我确实注意到负面评论的比例在高轮选秀中显著增加。这让我很惊讶,因为我预计中性评论的数量会增加,因为球迷不太可能熟悉后面几轮的球员。我怀疑负面评论的增加是因为许多球迷在选秀中更倾向于选择某个球员。也许他们认为这个球员是偷来的,认为巨人不选他是疯了。当巨人不选择这个球员时,我认为球迷更有可能消极地看待最终的选秀权。当然,这更多的是个人偏见的反映,而不是对真正的巨人选秀权的损害。

结论

好了,现在您应该能够通过从 Reddit API 中提取评论来运行完整的情感分析。情感分析是一种快速了解人们对某个特定话题的感受的方法。

虽然我将这个过程应用于 NFL 草案评论,但这个过程在许多不同的应用程序中是可重复的。例如,一家企业可以收集 Twitter 或 Reddit 上的评论来了解客户的声音,或者《星球大战》等电影系列的粉丝可以分析粉丝对最新电影发行的感受。可能性是广泛的,并为一些创造性的项目留下了很大的空间。

我希望这个教程是有用的。如果你有任何问题,评论,建设性的批评,或其他想法,请随时在下面的评论中告诉我!

基于深度学习的优步和奥拉情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-uber-ola-using-deep-learning-5c281d353e13?source=collection_archive---------21-----------------------

了解印度出租车服务客户的需求

肖院长在 Unsplash 上的照片

本文介绍了我们使用深度学习来了解优步和 Ola 在印度各地的出租车服务的研究。

要点

  1. 我们的工作针对不同人群的日常交通方式,以及他们对服务提供商的期望。
  2. 目前在印度最受欢迎的两家出租车服务是优步和 Ola,拥有大量生活方式不同的用户。
  3. 如今,Twitter 正处于数据高峰期,每天有数百万人发推文,目前优步和奥拉在 Twitter 上的粉丝分别为 315.2K 和 244.9K。
  4. 用于理解人们情绪的深度学习算法是卷积神经网络。
  5. 我们评估情绪类别的模型,例如积极和消极,以找出它相对于用例产生的准确性。

介绍

Twitter 情绪分析用于发现推文背后人们的情绪或情感。通过推文分析个人/客户的评论,这有助于公司进一步了解客户对公司提供的产品或服务的评论。自从 Twitter 情感分析开始以来,从客户的角度提取、量化和理解他们产品的价值对公司来说是非常有益的。虽然 Twitter 情绪分析可以在任何领域进行,但选择的领域是优步和奥拉出租车服务公司。选择优步和奥拉的原因是因为可以从出租车用户那里收集到大量的数据。这可以在以后用于提取推文,以了解客户对服务是否满意&他们面临什么问题。

研究人员已经对 3000 条推文进行了情感分析,在提取这些推文后,必须清除它们中的停用词、超链接和空格。我们想到使用的方法是深度学习,以更敏锐地理解它如何对优步和奥拉的 Twitter 情绪分析产生影响。对于我们的数据集,使用的算法是深度前馈神经网络(DFF)和卷积神经网络(CNN)。这两种算法都属于深度神经网络(DNN)的范畴。清理完 tweets 后,首先使用的技术是 Google Word2Vec。Google Word2Vec 是一种训练文本中词汇的高级方法。它训练词汇,使其尽可能接近单词的意思。各种参数是感知器的权重乘法、各种激活函数、用于优化输出和损失函数的优化器。精度是基于损失函数计算的。该函数用于计算训练和测试数据之间的损失,从而使我们了解深度学习算法如何影响优步和奥拉的推特情感分析。

资料组

使用 API 从 Twitter 获得用于情感分类的数据集。

CSV 格式的 Excel 表格

需要记住的重要一点是,可以从文本(用户的推文)中获得情感分类的相关信息。

情感分类涉及的步骤

获得所需用例有不同的步骤,它们是

情感分析的步骤

情感分析包括 7 个步骤,分别是:

1.文本输入

数据是从优步和 Ola 收集的,并牢记用例的相关参数。

2.标记化

符号化是从整体中提取有意义的数据的过程。

3.停止单词过滤

停用词是应该被过滤的常用词。

4.否定处理

否定处理决定了不同类型否定的否定范围。

5.词干

词干是一种压缩不同单词形式的方法。

6.分类

用于情感分析的分类算法,将在其中创建模型。

7.情感类

情感类别分为正面和负面,或者对于不同的用例可以有所不同。

词云生成

词云只不过是在特定文本中出现次数较多的词的可视化表示。单词越大,出现的次数越多,反之亦然。

词云让我们正确理解一个特定的词是如何与用例相关联的。

优步的文字云生成

优步的圆形文字云—作者图片

Ola 的词云生成

Ola 的圆形单词云—作者图片

算法

使用深度学习来理解情感的算法有

非深度前馈神经网络

单层神经网络—图片由作者提供

深度前馈神经网络

多层神经网络—作者图片

卷积神经网络(CNN)

一维卷积神经网络—图片由作者提供

谷歌 Word2Vec

Google Word2vec 是一种更好的训练文本理解不同单词之间词汇的方法。NLP 使用不同的词汇表进行改进,因为 word2vec 是两层的,包含不同的单词和单词之间的相似性,这有助于特定文本以更好的方式理解含义。关于网格的 google word2vec 的表示如下所示。

Google Word2Vec 展示——作者图片

深度学习用于尽可能最好地理解 Word2Vec。

实验

这项研究的实验部分由通过执行迭代获得的各种测试和结果组成。情感分析涉及的步骤有:
使用 TwitterAPI 从 Twitter 收集数据
CSV 文件包含两个数据集的 3000 条推文
获取每条推文的情感评分
将推文分为正面&负面
正面== 1 &负面== 0
生成单词词汇
将数据划分为 2400 个训练&测试

谷歌 Word2Vec 地图

越接近的点越相似——作者图片

特征数量与推文数据集——按作者分类的图片

用于优化网络的公式

感知器的权重乘法感知器具有一个输入,该输入具有一些输入值,并被传递到具有一些分配的权重的节点,该权重被加上偏差并被传递到激活函数。每个感知器的公式如下所示。

带输入和偏差的广义权重乘法—作者图片

激活函数权重相乘得到的值&加上偏置赋予激活函数,有不同的激活函数,本文使用的两个是 ReLu & Sigmoid 激活函数。

ReLU 激活功能—作者图片

Sigmoid 激活功能—图片由作者提供

优化输出的优化器优化器用于通过各种迭代来优化值,有不同数量的优化器可供使用。用于 DNN 的优化器是 Adadelta。Adagrad optimizer 的缺乏是由于分母值的增加导致了学习率的增加,为了克服这种影响,使用了 Adadelta。

Adadelta 优化器—作者图片

损失函数用于处理输出损失的损失函数是
二元交叉熵损失函数。使用二进制是因为输出分别为 0 & 1。

二元交叉熵损失函数—作者图片

为分类创建的模型

非深度神经网络

单层神经网络

在不同的时间间隔上训练非深度神经网络,以了解这如何影响大多数数据集的准确性。该模型分别针对优步和奥拉的数据集进行了训练。

单层神经网络获得的精度和损失

NDNN 的训练和验证准确性/损失

【NDNN 的 500 个数据集区间的精度

增加 500 条推文的数据集

该表具有以百分比表示的准确度,并且可以观察到,对于 500 个数据集,生成的准确度对于优步是 87.00 %,对于 Ola 是 70.00 %。Ola 从基本数据集得到的准确性相对较低,因此它为 3000 个数据集生成了最高的 81.88 %。优步数据集的平均准确率为 92.99 %,Ola 的平均准确率为 75.18 %,比优步低 17.81 %。

深度神经网络

多层神经网络

深度前馈神经网络也在超参数优化的帮助下使用,以了解各个模型需要多少个隐藏层。用于深度学习模型的隐藏层的数量是 2-隐藏层,所有其他参数保持不变。与批量大小为 50 的非深度神经网络相比,该模型中使用的时期也是 20。

多层神经网络获得的精度以及损失

DNN 的培训和验证准确性/损失

DNN 500 个数据集区间的精度

增加 500 条推文的数据集

可以观察到,优步数据集的基本精度为 88.00 %,奥拉数据集的基本精度为 71.00 %,优步数据集的最高精度为 96.33 %,奥拉数据集的最高精度为 82.05%,与模型的 1 层相比,精度没有显著提高。与非深度学习神经网络相比,优步数据集增加了 0.16 %,Ola 数据集增加了 0.17 %。

卷积神经网络

卷积神经网络

有一个维数为 300 和字数为 2200 的 1-嵌入层,它连接到 128 个内核大小为 3,4,5 的滤波器,并且使用的激活函数是 ReLu。Max Pooling 还用于从格网中获取最大值,这些值通过激活函数 Sigmoid 传递到输出层。

从卷积神经网络获得的精度以及损失

CNN 的培训和验证准确性/损失

CNN 500 个数据集区间的精度

增加 500 条推文的数据集

可以观察到,为优步数据集生成的最小准确度是 91.00 %,而 Ola 数据集是 65.00 %,这优于非深度神经网络和深度神经网络的准确度。优步和奥拉数据集的最大准确率分别为 96.00 %和 80.37 %,与其他两个模型的准确率接近。优步数据集的平均准确率为 93.59 %,而 Ola 数据集的平均准确率为 74.42 %。

结论

这些数据在深度学习算法的帮助下进行训练,以更深入的方式理解情绪。Google word2vec 用于生成词汇,并使数据集中的词与相似的词得到正确的理解。所有三个模型都计算了精确度。为优步数据集生成最佳精度的模型是具有两个隐藏层的深度神经网络。超参数优化提供了使用两个隐藏层的选择,这反过来最适合优步推文。类似地,为 Ola 数据集生成最佳准确度的模型是具有两个隐藏层的相同深度神经网络。据观察,与优步相比,Ola 推文的准确性并不是那么好,因为提取的推文有许多格式不正确的文本,尽管清理工作已经完成,但仍无法产生预期的准确性。还观察到 CNN 模型在 DNA 方面是温和的,这是有疑问的。卷积神经网络在图像处理方面更为人所知,但也用于理解它在文本分析中的表现。

参考

[1]去,亚历克,黄蕾,和 Richa Bhayani。“推特情绪分析。”熵 17 (2009): 252。

[2] Sharma、Anuj 和 Shubhamoy Dey。"情感分析的特征选择和机器学习技术的比较研究."2012 年 ACM 应用计算研究会议录。2012.

[3]金,尹。"用于句子分类的卷积神经网络."arXiv 预印本 arXiv:1408.5882 (2014)。

[4]塞弗林、阿利亚克塞和亚历山德罗·莫斯奇蒂。"用深度卷积神经网络进行推特情感分析."第 38 届国际 ACM SIGIR 信息检索研究与发展会议录。2015.

[5]王、博、。"基于方面的情感分析的深度学习."斯坦福大学报告(2015)。

在你走之前

研究论文:https://ieeexplore.ieee.org/document/9215429

代号:【https://github.com/yashindulkar/Uber-Deep-Learning

代号:【https://github.com/yashindulkar/Ola-Deep-Learning

posted @ 2024-10-16 09:00  绝不原创的飞龙  阅读(266)  评论(0)    收藏  举报