TowardsDataScience 博客中文翻译 2020(九百五十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

在 Python 中使用 Reduce

原文:https://towardsdatascience.com/using-reduce-in-python-a9c2f0dede54?source=collection_archive---------8-----------------------

如何使用 Python 中的 reduce 函数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

凯文·Ku 在 Unsplash 上的照片

介绍

Python 是一种面向对象的编程(OOP)语言。然而,它提供了一些提供函数式编程风格的工具。其中一些工具包括 map()、filter()和 reduce()函数。在本教程中,我们将探索 reduce()函数,并揭示它提供的多功能性和实用性。

贴图()和滤镜()函数在这里详细介绍:

[## 在 Python 中使用地图和过滤器

如何使用 python 中内置的地图和过滤功能

towardsdatascience.com](/using-map-and-filter-in-python-ffdfa8b97520)

使用 For 循环

引入 reduce()函数的最佳方式是从一个问题开始,尝试用传统的方法解决它,使用 for 循环。然后,我们可以使用 reduce 函数尝试相同的任务。

假设我们有一个数字列表,我们想返回他们的产品。换句话说,我们希望将列表中的所有数字相乘并返回一个值。我们可以使用 for 循环来实现这一点:

我们有我们的数字列表。我们想把这个列表中的数字相乘,得到它们的乘积。我们创建变量 product 并将其设置为 1。然后,我们使用 for 循环遍历 num_list ,并将每个数字乘以前一次迭代的结果。在循环通过 num_list 之后,乘积或累加器将等于 120,这是列表中所有数字的乘积。

减少功能

事实证明,我们可以使用 reduce 函数代替 for 循环来完成上述任务。reduce 函数可以接受三个参数,其中两个是必需的。两个必需的参数是:一个函数(它本身接受两个参数)和一个 iterable(比如一个列表)。第三个参数是初始化式,是可选的,因此我们将在后面讨论它。

reduce(函数,可迭代[,初始值设定项])

导入减少

reduce 函数在模块 functools 中,该模块包含高阶函数。高阶函数是作用于或返回其他函数的函数。因此,为了使用 reduce 函数,我们要么需要导入整个 functools 模块,要么可以只从 functools 导入 reduce 函数:

import functoolsfrom functools import reduce

注意: 如果我们导入 functools,我们需要访问 reduce 函数,如下所示:functools.reduce(arguments)。如果我们只从 functools 模块导入 reduce 函数,我们只需输入 reduce(arguments)就可以访问 reduce 函数。

探索归约函数

如前所述,reduce 函数接受两个必需的参数:一个函数和一个 iterable。为了避免 reduce 函数和它作为参数的函数之间的混淆,我将 reduce 函数称为 reduce 。

reduce 接受的第一个参数,函数本身必须接受两个参数。Reduce 然后将这个函数累积地应用到 iterable 的元素上(从左到右),并将其减少到一个值。

我们来看一个例子:

假设我们使用的 iterable 是一个列表,比如上面例子中的 num_list :

num_list = [1,2,3,4,5]

我们用作 reduce 的第一个参数的函数如下:

def prod(x, y):
    return x * y

这个 prod 函数接受两个参数:x 和 y。然后返回它们的乘积,即 x * y。

让我们分别传入 prod 函数和 num_list 作为我们的函数和 iterable,以减少:

from functools import reduceproduct = reduce(prod, num_list)

我们的 iterable 对象是 num_list ,也就是 list: [1,2,3,4,5]。我们的函数 prod 接受两个参数 x 和 y。Reduce 将从接受 num_list 的前两个元素 1 和 2 开始,并将它们作为 x 和 y 参数传递给我们的 prod 函数。 prod 函数返回他们的乘积,即 1 * 2,等于 2。Reduce 随后将使用这个累加值 2 作为新的或更新的 x 值,并使用 num_list 中的下一个元素 3 作为新的或更新的 y 值。然后,它将这两个值(2 和 3)作为 x 和 y 发送给我们的 prod 函数,然后该函数返回它们的乘积 2 * 3 或 6。然后,这个 6 将被用作我们新的或更新的 x 值,并且 num_list 中的下一个元素将被用作我们新的或更新的 y 值,即 4。然后,它将 6 和 4 作为我们的 x 和 y 值发送给 prod 函数,后者返回 24。因此,我们的新 x 值是 24,我们的新 y 值是来自 num_list 的下一个元素,即 5。这两个值作为我们的 x 和 y 值传递给 prod 函数,然后 prod 返回它们的乘积,24 * 5,等于 120。因此,reduce 接受一个可迭代对象,在本例中是 num_list ,并将其缩减为一个值,120。然后将该值分配给变量 product。换句话说,x 参数用累积值更新,y 参数从 iterable 更新。

[## Python 中的迭代器和迭代器

Python 中的可迭代对象、迭代器和迭代

towardsdatascience.com](/iterables-and-iterators-in-python-849b1556ce27)

第三个参数:初始化器

还记得我们说过 reduce 可以接受可选的第三个参数,初始化器吗?它的默认值是无。如果我们传入一个初始化器,它将被 reduce 用作第一个 x 值(而不是 x 是 iterable 的第一个元素)。所以如果我们把上面例子中的数字 2 作为初始化式传入:

product = reduce(prod, num_list, 2)print(product) #240

那么 x 和 y 的前两个值或自变量将分别是 2 和 1。所有后续步骤都是一样的。换句话说,在计算中,初始化器放在 iterable 的元素之前。

使用 Lambda 表达式

在上面的示例中,我们可以使用 lambda 表达式(或匿名函数)来显著缩短代码,而不是将 prod 作为函数传入:

product = reduce(lambda x,y: x*y, num_list)

注意 lambda 表达式如何接受两个参数:x 和 y,然后返回它们的乘积 x * y。

以下是关于如何使用 lambda 表达式的完整教程:

[## Python 中的 Lambda 表达式

如何用 python 写匿名函数

towardsdatascience.com](/lambda-expressions-in-python-9ad476c75438)

使用 Reduce 的其他示例

我们可以使用 reduce 的场景还有很多。

例如,我们可以找到列表中数字的总和:

num_list = [1,2,3,4,5]sum = reduce(lambda x,y: x + y, num_list)print(sum) #15

或者我们可以在列表中找到最大数量:

num_list = [1,2,3,4,5]max_num = reduce(lambda x,y: x if x > y else y, num_list)print(max_num) #5

或列表中的最小数量:

num_list = [1,2,3,4,5]min_num = reduce(lambda x,y: x if x < y else y, num_list)print(min_num) #1

还有很多其他的应用!

注意:Python 确实有内置函数,比如 max()、min()和 sum(),这些函数对于这三个例子来说更容易使用。然而,目标是展示如何使用 reduce()来完成许多不同的任务。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑注册成为一名灵媒会员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 注册,我会赚一小笔佣金。

[## 通过我的推荐链接加入媒体——卢艾·马塔尔卡

阅读卢艾·马塔尔卡的每一个故事(以及媒体上成千上万的其他作家)。您的会员费直接支持…

lmatalka90.medium.com](https://lmatalka90.medium.com/membership)

结论

在本教程中,我们学习了如何在 python 中导入和使用 reduce 函数。然后我们看到 lambda 表达式如何作为一个参数传入 reduce。最后,我们看到了一些如何使用 reduce 的例子。

使用回归确定影响人均国内生产总值的最重要的社会因素

原文:https://towardsdatascience.com/using-regression-to-determine-the-most-important-social-factors-impacting-gdp-per-capita-2296f4f02dcf?source=collection_archive---------15-----------------------

基于回归系数的 t 统计量对社会因素进行排序

介绍

世界各地的经济学家使用各种指标来衡量一个国家的繁荣和经济发展。其中一个指标是人均国内生产总值。一个国家的 GDP 或国内生产总值是一个国家在特定时期内生产的最终商品和服务的货币价值。人口较多的大国往往会有较高的 GDP。因此,为了消除这种对高人口的偏见,GDP 除以该国的总人口,这就给了我们该国的人均 GDP。

一个国家的发展会受到各种经济和社会因素的影响。本文只关注影响一个国家人均 GDP 的社会因素。总共选择了七个社会因素进行分析。世界银行的数据被用来收集所有这些特征。

  1. 识字率:成人识字率是指 15 岁及以上能够读写并理解简单日常生活语句的人口比例
  2. 贫困:每日生活费不足 3.2 美元的总人口比例。
  3. 贫民窟下:居住在贫民窟的城市人口百分比。
  4. 腐败:得分在-2.5 到 2.5 之间,得分越高表示腐败越少。
  5. 政府效力:它反映了公众对公共服务质量、公务员质量及其不受政治压力影响的程度、政策制定和执行的质量以及政府对这些政策承诺的可信度的看法。这是一个介于-2.5 到 2.5 之间的分数,正值越大表示治理越好。
  6. 政治稳定:衡量没有暴力和恐怖主义。这是一个介于-2.5 到 2.5 之间的分数,正值越大,表明政治越稳定。
  7. 成人死亡率:是每 1000 人中 15 岁到 60 岁之间死亡的人数。

目标

该分析使用回归来发现所选择的因素是否影响人均国内生产总值。该研究还试图根据这些特征对人均国内生产总值的影响对其进行排名。

利益相关者

政府:知道了影响发展的特征的相对重要性,政府就可以计划投资资金和制定正确方向的政策。

投票者:投票者可以把它作为分析政府工作的一种手段,依据的是政府是否把重点放在重要的方面,或者它的政策是否针对对一个国家的发展贡献不大的因素。

变革者:希望在国家发展中有所作为的个人可以选择努力的方向,从而对国家的发展产生最大的影响。

分析

不同的特征是从世界银行的数据中收集的,并被争论以将它们转换成期望的结构。使用回归来确定系数。为此,对所有特征进行了缩放,使得通过拟合回归模型获得的权重对应于每个特征的相对重要性。

对缩放特征拟合线性回归模型的结果表明Literacy对人均 GDP 没有影响。这个结果看起来很奇怪,因为识字总是与发展联系在一起。为了研究这一点,绘制了单个解释变量,以了解它们与因变量人均国内生产总值的关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这种分析表明,这些特征不是线性的,这意味着线性回归模型不能适合给定的数据。该图表明 Y 轴上的最大变化是从 0 到 150,000,而 X 轴上的最大变化是从 0 到 100。因此,人均国内生产总值和其他变量之间没有明显的关系。因此,人均国内生产总值的对数被用来使两个变量相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对数变换后,X 轴和 Y 轴的变化变得相似,人均国内生产总值和其他独立变量之间几乎呈线性趋势。例如,从识字率图中可以看出,随着识字率的增加,人均国内生产总值的对数也在增加,同样,其他变量也可以观察到这种趋势。这给了使用 GLM(广义线性模型)的动机。从上面的图中可以看出,链接函数显然是一个log链接函数,因为在对数变换后,数据的趋势呈线性。现在的挑战是决定在 GLM 使用哪一个发行系列。为了有所了解,绘制了因变量的 pdf:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上述密度的形状和GDP per Capita是一个正连续量的事实表明Gamma分布可以用来模拟密度函数。

于是用具有log连接功能的Gamma分布族对缩放后的数据拟合出 GLM。

通过对数变换因变量GDP per Capita还拟合了一个线性模型。如果模型是为预测目的而建立的,那么转换因变量并不是一个好的做法。但是这里的主要任务是识别特性的重要性。另外,log作为单调递增函数不影响可解释性。因此,对数转换的线性模型被用作第二模型。

确定特征重要性

确定特征的相对重要性的最直观和简单的方法之一是通过直接评估与从拟合回归模型获得的缩放特征相关联的权重。但是这没有考虑在确定权重或者换句话说置信区间时的误差。因此,为了减轻这种影响,t statistic被用来衡量重要性,因为它也包含了计算权重时的相关误差。

代码和详细信息

整个分析是在 r 中执行的。要了解详细的代码和整个流程,数据争论是如何执行的,一些导致共线性的特性是如何处理的,以及其他微小的细节,请查看我的GitHub资源库中的笔记本。笔记本包含对每个步骤的文档分析,这将有助于更好地理解分析。

结果和结论

在考虑的七个因素中,只有以下四个特征对人均国内生产总值有独立影响:

  1. 识字
  2. 成人死亡率
  3. 政府效能
  4. 政治稳定

其他三个因素,即贫困、贫民窟和腐败,取决于上述四个因素。改变这四个变量可以改变三个因变量的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相关矩阵

上图显示了所有因素的相关值。相关性的数值从 0 到 1 不等。如果两个特征的相关性接近 0,这意味着这两个特征根本不相关,而如果相关性接近 1,则这两个特征可以被认为高度相关。负值表示增加一个变量会导致另一个变量减少,而正值表示增加一个变量会增加另一个变量。

  1. 贫民窟下:该变量与识字率呈高度负相关,与成人死亡率呈高度正相关。这表明贫民窟人口可以通过提高识字率、降低成人死亡率或改善健康状况来减少。
  2. 低于贫困水平:这一变量也与识字率高度负相关,与成人死亡率高度正相关。因此,可以通过提高识字率、降低成人死亡率或改善健康状况来减少贫困。
  3. 腐败:腐败与政府效能有非常高的正相关关系。因此,一个有效的政府可以帮助减少腐败,即增加腐败分数,因为较高的分数代表较低的腐败。

下图显示了四个独立特征如何影响人均 GDP:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上图中,可以得出结论:

  1. 提高识字率、政府效率和政治稳定性会导致人均国内生产总值的增加。
  2. 降低成人死亡率或改善健康状况可以提高人均国内生产总值。

现在我们知道了四个变量中的每一个是如何影响人均 GDP 的,让我们看看影响它的最重要的因素是什么:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里分析了两个模型,这两个模型对于特征的重要性给出了相同的结果。重要性与拟合两个模型得到的 t 统计量的绝对值成正比。从上面的两个图表中,可以观察到:

识字率是影响人均国内生产总值的最重要因素,其次是成人死亡率,然后是政府效率和持久的政治稳定。

国家比较

让我们看看 2018 年人均 GDP 最高的前 10 个国家

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图表显示,摩纳哥在 2018 年的所有国家中人均 GDP 最高,美国排名第十。

印度、中国和美国的比较

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据人均 GDP,美国排名第 10,中国第 90,印度第 182。识字率也有类似的差异。美国和中国的识字率非常高,分别为 99%和 97%,而印度远远落后,为 74%。

根据维基百科的数据,2014 年美国在教育上花费了其 GDP 的 5%。2016 年,中国将国内生产总值的 4%用于教育。另一方面,印度 2019 年的教育支出仅占 GDP 的 3%。这显示了一种严重的担忧。美国和中国都有很高的识字率,为了赶上他们,印度需要在教育上投入更多。

使用相关数据的回归

原文:https://towardsdatascience.com/using-regression-with-correlated-data-5845a2eed3d2?source=collection_archive---------13-----------------------

视频教程

教程(包括 R 代码)使用广义估计方程和多级模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由来自佩克斯布拉克 K 拍摄

虽然回归模型由于其简短的语法而易于运行,但这种可访问性也使得不适当地使用回归变得容易。这些模型有几个关键的假设,需要满足这些假设才能使它们的输出有效,但是无论这些假设是否满足,您的代码通常都会运行。

视频教程

对于线性回归(用于连续结果),这些假设如下:

  1. 独立性:所有观测值相互独立,残差不相关
  2. 线性:X 和 Y 之间的关系是线性的
  3. 同方差:不同 X 值的残差的恒定方差
  4. 正态性:数据应该在回归线周围呈正态分布

对于逻辑回归(与二元或有序分类结果一起使用),这些假设如下:

  1. 独立性:所有观测值相互独立,残差不相关
  2. logit 中的线性:X 和 Y 的 logit 之间的关系是线性的
  3. 正确指定模型,包括缺少多重共线性

在这两种简单的回归模型中,独立的观察值对于拟合一个有效的模型是绝对必要的。如果你的数据点是相关的,这种独立性的假设就被违反了。幸运的是,仍然有办法用相关数据生成有效的回归模型。

相关数据

数据中的相关性主要通过多次测量(例如,对每个参与者间隔 1 周进行两次测量,并且个体内部的数据点不是独立的)或者如果数据中存在聚类(例如,在不同学校就读的学生中进行调查,并且来自给定学校的学生的数据点不是独立的)。

结果是,结果是在单个观察的水平上测量的,但是存在单个(在多个时间点的情况下)或集群的第二个水平,在该水平上可以关联单个数据点。忽略这种相关性意味着标准误差无法精确计算,并且在大多数情况下会被人为降低。

了解您的数据是否相关的最佳方式是简单地通过熟悉您的数据和产生它的收集过程。如果您知道您有来自相同个体的重复测量,或者有可以分组到家庭或学校的参与者的数据,您可以假设您的数据点可能不是独立的。您还可以通过计算 ICC(组内相关系数)来确定数据点在可能的组内的相关程度,或者通过在残差中寻找相关性,来调查数据的可能相关性

相关数据的回归建模

如前所述,简单回归会产生不准确的相关数据标准误差,因此不应使用。

相反,您希望使用能够解释数据中存在的相关性的模型。如果相关性是由于一些分组变量(如学校)或随着时间的推移而重复测量,那么您可以在广义估计方程或多水平模型之间进行选择。这些建模技术可以处理二元或连续的结果变量,因此当数据相关时,可以用来代替逻辑或线性回归。

广义估计方程

广义估计方程(GEE)将给出与简单回归产生的β估计相同或相似的β估计,但具有适当的标准误差。当您对相同的个人或单位进行重复测量时,广义估计方程特别有用。当您有许多小的集群时,这种建模技术往往工作得很好,这通常是对大量参与者进行少量测量的结果。GEE 还允许用户指定众多关联结构中的一个,根据您的数据,这可能是一个有用的特性。

多层建模

多水平建模 (MLM)在数据点不独立时也提供了适当的标准差。当用户对聚类组内和聚类组之间的关系感兴趣,而不是简单地考虑标准误差估计中的相关性影响时,这通常是最佳的建模方法。MLM 还有一个额外的优势,就是能够处理两个以上级别的响应变量。MLM 模型的主要缺点是,它们需要在每个聚类中有更大的样本量,因此当聚类很小时可能不太适用。

在 r 中,GEE 和 MLM 都很容易使用。下面,我将介绍两种最常见的相关数据的示例:来自个人的重复测量数据和从具有重要分组变量(在本例中为国家)的个人收集的数据。我将为每个数据集拟合简单的回归、GEE 和 MLM 模型,并讨论哪种建模技术最适合这些不同的数据类型。

例子 1:来自脆弱家庭和儿童福利研究的数据

我将首先处理的数据来自普林斯顿大学9 年级和 15 年级的脆弱家庭&儿童福利研究,该研究跟踪了 1998 年至 2000 年间在美国主要城市出生的选定儿童的家庭。数据是公开的,可以通过在脆弱家庭数据和文件页面提交一个简短的请求来获取。由于这项研究年复一年地跟踪相同的家庭,来自相同家庭单位的不同时间点的数据点并不独立。

该数据集包含数十个变量,代表参与调查的儿童及其父母的健康状况。作为一名精神病学专家,我主要对检查儿童的心理健康感兴趣。参与的孩子们被问到他们是否经常感到悲伤,我将用这个“经常感到悲伤”问题的答案作为我的结果。由于药物使用与青少年心理健康状况不佳有关,我将使用代表酒精和烟草使用的变量作为预测指标*。

*注意:本文中创建的模型仅用于演示目的,不应视为有意义。在构建这些模型时,我没有考虑混杂、中介、其他模型假设或其他可能的数据问题。

首先,让我们加载将要使用的包。我加载了“tidyverse”来清理我们的数据,“haven”是因为我们将要读入的数据是 SAS 格式的,“geepack”运行我们的 GEE 模型,“lme4”运行我们的多级模型:

library(tidyverse)
library(haven)
library(geepack)
library(lme4)

现在让我们做一些数据清理,让这些数据为建模做好准备!

第 9 年和第 15 年的数据存放在单独的 SAS 文件中(可通过. sas7bdat 扩展名识别),因此我们有一个代码块来读入和清理每个文件。这种清理必须单独进行,因为变量名和编码在不同的研究年份略有不同(参见代码簿的数据和文档页)。

数据集中包含数百个变量,因此我们首先选择将在我们的模型中使用的变量,并为其分配有意义的变量名,这些变量名在数据框中保持一致。接下来,我们过滤数据,只包括我们感兴趣的变量的完整数据的个人(下面的代码排除了这些变量的缺失数据的个人以及拒绝回答的个人)。

然后,我们以标准的 1 =“是”,0 =“否”格式重新编码变量。对于“feel_sad”变量,这也意味着将变量分成 4 个等级,代表不同程度的悲伤。我们最终得到一个二元变量,其中 1 =“悲伤”,0 =“不悲伤。”一些回归技术可以处理您的响应变量中的多个级别(包括 MLM),但为了简单起见,我在这里将其二进制化。最后,我们创建一个“time_order”变量来表示观察结果是来自第一轮还是第二轮研究。

year_9 = read_sas("./data/FF_wave5_2020v2_SAS.sas7bdat") %>% 
  select(idnum, k5g2g, k5f1l, k5f1j) %>% 
  rename("feel_sad" = "k5g2g",
         "tobacco" = "k5f1l",
         "alcohol" = "k5f1j") %>% 
  filter(
    tobacco == 1 | tobacco == 2,
    alcohol == 1 | alcohol == 2,
    feel_sad == 0 | feel_sad == 1 | feel_sad == 2 | feel_sad == 3
  ) %>% 
  mutate(
    tobacco = ifelse(tobacco == 1, 1, 0),
    alcohol = ifelse(alcohol == 1, 1, 0),
    feel_sad = ifelse(feel_sad == 0, 0, 1),
    time_order = 1
  )year_15 = read_sas("./data/FF_wave6_2020v2_SAS.sas7bdat") %>% 
  select(idnum, k6d2n, k6d40, k6d48) %>% 
  rename("feel_sad" = "k6d2n",
         "tobacco" = "k6d40",
         "alcohol" = "k6d48") %>% 
  filter(
    tobacco == 1 | tobacco == 2,
    alcohol == 1 | alcohol == 2,
    feel_sad == 1 | feel_sad == 2 | feel_sad == 3 | feel_sad == 4
  ) %>% 
  mutate(
    tobacco = ifelse(tobacco == 1, 1, 0),
    alcohol = ifelse(alcohol == 1, 1, 0),
    feel_sad = ifelse(feel_sad == 4, 0, 1),
    time_order = 2
  )

然后,我们通过使用 rbind()堆叠两个清理过的数据框来合并第 9 年和第 15 年的数据。rbind()函数在这里工作得很好,因为两个数据框现在共享所有变量名。接下来,我们将“idnum”变量(它标识唯一的家族单元)转换成一个数值变量,以便它可以正确地用于对最终代码块中的数据进行排序。这一步是必要的,因为我们将用于运行 GEE 模型的 geeglm()函数假设数据帧首先按唯一标识符(在本例中为“idnum”)排序,然后按观察顺序排序(在此由新的“time_order”变量表示)。

fragile_families = rbind(year_9, year_15) %>% 
  mutate(
    idnum = as.numeric(idnum)
  )fragile_families = 
  fragile_families[
  with(fragile_families, order(idnum)),
]

上述代码生成了以下清理后的数据框,现在可以用于回归建模了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们适应我们的模型:

  1. 简单逻辑回归

首先,我们使用 glm()函数来拟合一个使用“脆弱家庭”数据的简单逻辑回归模型。因为我们有一个二元结果变量,“家庭=二项式”被用来指定应该使用逻辑回归。我们还使用“broom”包中的 tidy()来清理模型输出。我们创建这个模型只是为了进行比较——如前所述,已经违反了独立性假设,与这个模型相关的标准误差将无效!

glm(formula = feel_sad ~ tobacco + alcohol, 
    family = binomial, data = fragile_families) %>% 
  broom::tidy()

上面的代码产生了下面的输出,后续的建模方法将与它进行比较。吸烟和饮酒似乎都是参与儿童悲伤的重要预测因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2。广义估计方程

使用“geepack”包中的 geeglm()函数指定 GEE 模型的语法与标准的 glm()函数非常相似。“公式”、“系列”和“数据”是两个函数完全相同的参数。新增的是“id”、“waves”和“corstr”参数(参见包文档中所有可用的参数)。在“id”参数中指定了链接来自相同主题的观察的唯一标识符。在这种情况下,ID 是“idnum”,这是分配给参与研究的每个家庭的唯一标识符。在数据清理过程中创建的“time_order”变量在“waves”参数中起作用,它表示进行观测的顺序。最后,“corstr”可以用来指定主题内的相关结构。“独立性”实际上是这个参数的默认输入,它在这个上下文中是有意义的,因为当集群很小时它是有用的。然而,当一个对象内的所有观察值可以被认为是同等相关时,可以指定“可交换的”,当内部相关性随着时间而变化时,“ar1”是最好的。关于选择正确相关结构的信息可以在这里这里找到。

geeglm(formula = feel_sad ~ tobacco + alcohol, 
       family = binomial, id = idnum, data = fragile_families, 
       waves = time_order, corstr = "independence") %>% 
  broom::tidy()

我们的 GEE 模型给出了以下输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,我们的β估计值与使用 glm()得出的结果完全相同,但标准误差略有不同,因为已经考虑了数据中的相关性。虽然烟草和酒精仍然是悲伤的重要预测因素,但 p 值略有不同。如果这些 p 值更接近 0.05,那么通过精确的标准误差测量可以很容易地将 p 值推到显著性水平之上或之下。

  • *注:GEE 和逻辑回归的检验统计看起来完全不同,但这只是因为逻辑回归输出中提供的检验统计是 Z 统计,而 GEE 输出中提供的检验统计是 Wald 统计。Z 统计量的计算方法是将估计值除以标准误差,而 Wald 统计量的计算方法是将估计值除以标准误差的结果平方。因此,这两个值在数学上是相关的,通过对 GEE“统计数据”列中的值求平方根,您将会看到与初始 Z 统计数据相比更加温和的变化。

使用 geeglm()函数,验证您的分类是否被正确识别也很重要。您可以通过运行上面的代码来做到这一点,而不需要 broom::tidy()步骤,因此:

geeglm(formula = feel_sad ~ tobacco + alcohol, 
       family = binomial, id = idnum, data = fragile_families, 
       waves = time_order, corstr = "independence")

这段代码产生如下所示的输出。您需要查看输出的最后一行,其中描述了“集群数量”和“最大集群大小”。我们对几千个人进行了 2 次观察,因此这些值在我们的数据环境中是有意义的,并且表明函数正确地注册了聚类。但是,如果分类的数量等于数据集中的行数,则可能是工作不正常(很可能是数据的排序被关闭)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。多级建模

接下来,让我们使用来自 lme4 包的 glmer()拟合一个多水平模型。同样,所需的代码几乎与用于逻辑回归的代码相同。唯一需要的更改是在公式参数中指定随机斜率和截距。这是通过代码的“(1 | idnum)”位完成的,它遵循以下结构:(随机斜率|随机截距)。分组变量,在本例中为“idnum”,在|的右边被指定为“随机截距”,而“1”表示我们不希望预测因子的效果在不同的组之间有所不同。Rense Nieuwenhuis 的一篇有用的博客文章提供了这种 glmer()语法的各种例子。

lme4 包与 broom 包不兼容,因此我们在创建了一个包含模型输出摘要的列表后提取模型的系数。

mlm = summary(glmer(formula = 
                    feel_sad ~ tobacco + alcohol + (1 | idnum), 
                    data = fragile_families, family = binomial))mlm$coefficients

同样,输出类似于简单的逻辑回归模型,烟草和酒精的使用仍然是悲伤的重要预测因素。估计值与使用 glm()和 geeglm()函数得出的值略有不同,因为数据中的分组不再被忽略,也不再被视为需要通过纠正标准误差来解决的烦恼;相反,它们现在作为模型的一个重要部分被合并。与通过逻辑回归产生的估计值相比,所有估计值的标准误差估计值更高,Z 值和 p 值保持相似,但反映了估计值和标准误差值的这些重要变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例 2:来自全球学校学生健康调查的数据(GSHS)

我们将浏览的第二个数据集来自世卫组织的全球在校学生健康调查(GSHS)。这项调查在 13-17 岁的学龄儿童中进行,目的是帮助各国确定健康优先事项,确定健康相关行为的流行率,并促进直接比较各国的流行率。我们将使用来自两个国家的数据,分别是印尼孟加拉,这些数据可以直接从这些国家各自的描述页面下载。

这些数据是跨部门的:一次在两个国家的学生中进行了相同的调查。我感兴趣的是使用这个数据集中的变量来描述孩子是否有朋友,孩子是否被欺负(我的预测因素)以及孩子是否认真考虑过自杀(我的结果)之间的关系。很可能这两个国家之间的这些关系是不同的,孩子们与来自同一个国家的其他孩子更相似。因此,知道一个孩子是来自印度尼西亚还是孟加拉国提供了关于那个孩子的反应的重要信息,并且违反了独立观察的假设。

让我们再次加载包:

library(tidyverse)
library(haven)
library(lme4)
library(gee)

请注意,“geepack”包已被替换为“gee”包。“gee”软件包更容易用于(在我看来)按分组变量(如国家)进行聚类的数据,而不是具有多个观察值的个人数据。

接下来,让我们加载数据(也是 SAS 格式,所以我们再次使用“haven”包)并进行一些基本的清理。这里的数据清理遵循与脆弱家庭和儿童福利研究数据所使用的程序类似的结构:选择重要的变量并为其指定有意义的、一致的名称,并且创建一个新的变量来指示观察值属于哪个聚类(在这种情况下是新的“国家”变量)。

indonesia = read_sas("./data/IOH2007_public_use.sas7bdat") %>% 
  select(q21, q25, q27) %>% 
  rename(
    "bullied" = "q21",
    "suicidal_thoughts" = "q25",
    "friends" = "q27"
  ) %>% 
  mutate(
    country = 1,
  )bangladesh = read_sas("./data/bdh2014_public_use.sas7bdat") %>% 
  select(q20, q24, q27) %>% 
  rename(
    "bullied" = "q20",
    "suicidal_thoughts" = "q24",
    "friends" = "q27"
  ) %>% 
  mutate(
    country = 2
  )

同样,两个数据框堆叠在一起。由于在这两个国家的收集过程中变量的编码是一致的,因此使用这种组合数据集可以只进行一次清理。丢失的数据被删除,所有变量都从字符串格式转换为数字格式。最后,变量变异成一致的二进制格式。

survey = rbind(indonesia, bangladesh) %>% 
  mutate(
    suicidal_thoughts = as.numeric(suicidal_thoughts),
    friends = as.numeric(friends),
    bullied = as.numeric(bullied),
    suicidal_thoughts = ifelse(suicidal_thoughts == 1, 1, 0),
    friends = ifelse(friends == 1, 0, 1),
    bullied = ifelse(bullied == 1, 0, 1)
  ) %>% 
  drop_na()

我们清理后的数据框现在如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们适应我们的模型:

  1. 简单逻辑回归

除了变量名称和指定的数据之外,glm()代码与用于脆弱家庭研究数据的代码保持一致。

glm(formula = suicidal_thoughts ~ bullied + friends, 
    family = binomial, data = survey) %>% 
  broom::tidy()

不出所料,在这个样本中,孩子是否有朋友和是否被欺负都是自杀想法存在的重要预测因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2。广义估计方程

gee 包中的 gee()函数允许我们轻松地将 GEE 用于我们的调查数据。该函数比以前使用的 geeglm()函数更适合,因为数据不随时间相关,而是由一个单独的变量表示,该变量可以用“id”参数表示(在本例中为“country”)。formula 和 family 参数与 glm()函数中使用的参数相同,geeglm()函数中使用的“corstr”参数也是相同的。但是,与 geepack 包不同,gee 包与 broom::tidy()函数不兼容,因此使用 summary()函数查看输出。

gee = gee(suicidal_thoughts ~ bullied + friends, data = survey, 
          id = country, family = binomial, 
          corstr = "exchangeable")summary(gee)

我特别喜欢 gee()函数的一个原因是,输出中实际上包含了朴素的标准误差和 Z 检验统计数据(朴素的意思是这些值是由回归产生的,其中没有考虑聚类,您将看到这些值与上面的 glm()函数产生的值完全相同)。您会注意到使用 GEE(“稳健”)产生的标准误差和 Z 检验统计数据发生了巨大变化,尽管我们的两个预测值仍然很显著。似乎考虑到国内相关性,可以使用低得多的标准误差。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。多级建模***

    • *注:如上所述,模型仅用于演示目的,不一定有效。在这种情况下,对于我们的 MLM 模型,我们希望有两个以上的组(即来自其他国家的数据)。如果你真的只用两组 MLM 模型,你应该考虑一个小样本量修正

最后,我们用调查数据集尝试 MLM。代码与用于脆弱家庭研究数据的代码完全相同,但指定了新的公式、分组变量和数据集。

mlm = summary(glmer(formula = 
                    suicidal_thoughts ~ bullied + friends + 
                    (1 | country), 
                    data = survey, family = binomial))mlm$coefficients

同样,beta 估计值和标准误差估计值现在也比使用 glm()得到的值稍有调整。与“被欺负”和“朋友”变量相关的 z 值和 p 值略小,尽管欺负和有朋友仍然是自杀想法的重要预测因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

哪个模型最适合这些例子?

普林斯顿大学脆弱家庭和儿童福利研究的数据最好用 GEE 来表示。这是由于 2 个观察值的最大聚类大小,单个家庭在一段时间内有多个数据点的事实,以及我们更感兴趣的是在标准误差估计中考虑分组,而不是实际评估家庭之间的差异。

多水平建模最适合来自全球基于学校的学生健康调查(GSHS)的数据,因为这些数据是跨地区收集的,可以分为两大类。此外,可以进一步研究输出,以确定组内和组间的差异,我们可能对国家内部和国家之间的关系感兴趣。

如何解释违反独立观察假设的情况将取决于您的数据结构和您对数据收集过程的一般了解,以及您是否认为相关性是一个需要调整的烦恼或值得探索的事情。

总之,回归是灵活的,某些回归模型可以处理相关数据。然而,检查给定技术的假设并确保您的分析策略适合您的数据总是很重要的。

利用强化学习产生更好的连接排序策略

原文:https://towardsdatascience.com/using-reinforcement-learning-to-produce-better-join-ordering-strategy-2fd2761ebf3a?source=collection_archive---------19-----------------------

我们可以训练一个 AI 模型来决定首先加入哪些表吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

连接表格。由 Unsplash 上的 chuttersnap 拍摄

假设您在 RDBMS 上有以下查询:

从 A、B、C、D 中选择*

你是要先加入 A & B 再加入结果跟C&D 吗?还是先把 A & C 加入,再把结果用 B 加入,再把结果用 D 加入比较好?

今天我们将讨论一篇有趣的论文,作者是 Ryan Marcus 和 Olga Papaemmanouil,题目是“连接顺序枚举的深度强化学习”本文将机器学习世界与数据库世界交叉。他们试图训练一个强化学习代理来决定连接关系的顺序,即首先连接哪些关系(RDBMS 表),接下来是哪些关系,等等。作为一个具体的例子,假设我们有四个关系 A、B、C 和 D。我们希望代理决定是加入 A & B,然后将结果关系加入 C 并最终加入 D,还是先加入 A & C,然后加入 B & D,然后加入两个结果关系,或者任何其他排序可能性。

连接排序策略是数据库查询优化的一部分,其目标是产生一个低延迟运行的物理查询计划。我们可以把这个问题看作是搜索所有可能的连接顺序并选择最便宜的一个。如果我们可以生成一个可以减少初始步骤中的行数的顺序,那么我们就可以省去后续步骤来联接最终将被丢弃的行。目前,DBMSs 使用试探法来决定连接顺序。System-R 使用动态规划寻找一个代价最低的左深树,而 PostgreSQL 使用贪婪算法选择一个代价低的对,直到构建出整个订单。然而,这些策略在某种程度上是静态的,并且数据库不从反馈中学习(例如,基数、查询延迟)。因此,他们可能会重复使用同样糟糕的连接排序策略。

重新加入枚举器

现在让我们来谈谈 ReJOIN,这是一个通过使用强化学习来枚举和选择连接顺序的解决方案。

强化学习

我们将把连接顺序枚举问题建模成强化学习问题。在强化学习中,我们训练一个与环境交互的代理。环境将告诉代理当前状态 s 以及在 = { a₀、a₁、.。。,一个当前状态下可以拍的 }。然后,代理必须选择一个动作,并进入下一个状态,在该状态下,它将接收一组新的动作。代理反复执行这个过程,直到它到达一个终端状态,在这里没有更多的动作可用。此时,代理完成了一个,并将根据其采取的行动获得奖励。代理的目标是通过从经验中学习来最大化回报。

将连接顺序问题映射到强化学习的术语

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:二元连接树(Marcus & Papaemmanouil,2018)

连接排序可以表示为一棵二叉连接树,如上图所示。为了采用强化学习来连接排序问题,我们将使用以下映射:

  • 每个状态将代表一个二元连接树。然后,我们将这个二元连接树转换成一个状态向量,并添加更多的信息,如连接谓词和选择谓词。
  • 每个动作代表将两个子树合并成一个树。
  • 当我们已经加入所有关系时,一集就结束了。
  • 奖励将基于结果连接排序的成本模型评估来计算。

状态向量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:作为向量的状态表示(Marcus & Papaemmanouil,2018)

如前所述,我们将二叉连接树和进一步的连接信息表示为向量。我们将每个子树编码为大小为 n 的向量 v ,其中 n 是数据库中关系的总数。如果关系不在二元连接树中, vᵢ 的值为 0,并且 1/h(i,x) 其中 h(i,x) 是关系 i 在子树 x 中的高度(到根的距离)。例如,在图 2 的最左边,我们可以看到我们将子树 A 表示为[1 0 0 0],因为在这种情况下,关系 A 的高度为 1,其他关系不存在于子树中。在左起第二张图片上,假设我们连接了 AC ,产生了新的关系 A ⨝ C。现在 A & C 的高度为 2,因此我们用 1/2 填充 A & C 列上的值。列 B 和 D 保持为 0,因为它们不在这个子树中。

此外,我们添加了连接谓词和列选择谓词向量。连接谓词将是一个 n×n 二进制矩阵 m,其中如果在和之间存在连接谓词,则 m(i,j) 的值将为 1,否则为 0。在图 2 中, m(1,2) = m(2,1) 的值是 1,因为我们在 A 和 B 之间有一个连接谓词(A.id == B.id)。 m(1,3) = m(3,1) 的值也是 1,因为我们在 A 和 C 之间有一个连接谓词( A.id == C.id )

列选择谓词是一个 k 维二元向量,其中 k 是所有关系的属性总数。如果我们在这个属性中有选择谓词,那么这个向量中的项的值将为 1,否则为 0。在图 2 中,B.a2 的值是 1,因为在 SQL 查询中,我们有一个选择谓词 B.a2 > 100

训练模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:重新加入的架构(Marcus & Papaemmanouil,2018)

我们通过寻找产生最高回报的优化策略来训练强化学习代理。我们通过训练神经网络来实现这一点,该神经网络将状态向量作为输入,并将动作向量作为输出。动作向量是一个保存了 n 个项目的向量,每个项目代表一个可能采取的动作。我们在中间放置了两个隐藏层。我们训练模型来优化产生高回报行动的权重。

ReJOIN 将前几集的信息记录为一对权重及其奖励 (θ,r) 。然后,它使用此信息中的样本来估计接下来事件的政策梯度。

结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:性能比较(Marcus & Papaemmanouil,2018 年)

上图显示了使用 PostgreSQL 和 ReJOIN 生成的计划执行查询的比较。作者通过使用连接顺序基准数据集和查询来执行这个基准测试。正如我们所看到的,最初,ReJOIN 给出了一个糟糕的执行计划(例如,比 PostgreSQL 差 9 倍)。在几千集之后,它开始实现与 PostgreSQL 相同的性能,并且在某个时候,开始产生更好的执行计划。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:计划时间对比(Marcus & Papaemmanouil,2018)

本文的另一个极好的结果是,当我们向查询中添加更多的关系时,重加入的计划时间不会变长。在 PostgreSQL 的情况下,它花费更多的时间来计划更多关系的连接,因为可能的连接组合需要计算更多的成本。

你也可以在这个库中找到关于这篇论文的实现和扩展实验。

结论和公开挑战

这项研究显示了利用强化学习进行数据库优化的一些潜力。它显示了积极的结果,在某些查询上,该模型生成的连接顺序在执行性能和计划时间方面可以超过 PostgreSQL 生成的连接顺序。

然而,它花费了大量的片段(查询执行)来达到一个好的结果。然后,作者提出了未来研究的一些机遇和挑战,例如:

  • 使用实际查询延迟作为奖励。目前提出的方法是使用成本模型作为奖励。成本模型支持快速训练,但也容易出错,因为实际的查询延迟可能与成本模型不一致。
  • 扩展优化器。在查询优化的世界里,重加入只处理连接顺序问题。研究社区可以进一步研究在查询优化的其他方面应用类似技术的可能性,比如选择物理操作符、使用索引和合并谓词。

参考文献:

[1] Marcus,r .,& Papaemmanouil,O. (2018 年 6 月)。连接顺序枚举的深度强化学习。在第一届利用人工智能技术进行数据管理的国际研讨会会议录(第 3 页)。ACM。

使用 ResNet 处理心电图时间序列数据

原文:https://towardsdatascience.com/using-resnet-for-time-series-data-4ced1f5395e3?source=collection_archive---------24-----------------------

像普通 RNN 这样的递归神经网络或者像 LSTM 和 GRU 这样的更高级的模型曾经是深度学习实践者进入时间序列领域的 goto 模型。NLP 提供了丰富的序列数据,提供了一个自愿的对象。但是像伯特和 GPT 这样的变压器架构肯定已经占领了这个领域。除了这些变压器架构之外,CNN 还在时间序列领域取得了回归或进步。CNN 擅长模拟时间序列吗?

CNN 在模拟时间序列方面有多好?

为了回答这个问题,这篇文章复制了一篇名为“ECG heart beat class ification:A Deep Transferable re presentation”[1]的文章,该文章将基于 CNN 的架构 ResNet 应用于心电图(ECG)数据。把迁移学习应用到这个问题上。

Keras 代码是以笔记本的形式提供的,可以很容易地用例如 Google Colab 在这里执行。

这篇文章的概述

该职位的结构如下:

  • 数据集简介
  • ResNet 简介
  • 使用平原 MLP 和 ResNet 建立基线
  • 运用迁移学习
  • 讨论
  • 结论

数据集简介

与原始研究相关的文章使用了两组心电图数据:

(两个数据集都可以在 Kaggle 上获得,详情见笔记本。)

两个数据集都包含标准化的 ECG 信号。每次观察有 187 个时间步。在 2D 绘制的观察示例呈现:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

观察值的 2D 表示

在最初的麻省理工学院-BIH 数据集中,每个观察值被分配了以下标签之一:

  • 答:房性早搏
  • f:心室融合搏动
  • n:正常节拍
  • v:室性早搏)
  • n:正常窦性心律
  • 室性心动过速

在 Kaggle 数据集中,这恰好是最初研究的来源,这些标签被融合成 5 个类别。数据集提供了长度分别为 87554 和 21892 的训练和测试数据集。不算太寒酸!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

融合类别的分布

PTB 数据集(长度为 14552)仅将正常和异常标签分配给观察值;标签的分布如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PTB 数据集中标签的分布

在最初的研究中,适合麻省理工学院-BIH 数据集的模型权重被转移到 PTB 数据集。由于麻省理工学院-BIH 的数据集比 PTB 的数据集大得多,这可能是有意义的。

在复制开始之前,首先提供一个简短的 ResNet 刷新程序。

ResNet 简介

ResNet 的目标是允许优化具有更多层的深层网络。为此,ResNet 引入了跳过连接。跳过连接是通过将信号从前面的层添加到后面的层来创建的。原文中提供了一个很好的例证:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

研究的 ResNet 设置

这里发生了什么事?来自第一卷积层的信号被加到第一 ResNet 块中的第三卷积层的信号上。(注意,信号是在 ReLU 之前添加的。块末尾的池层严格来说不是 ResNet 块的一部分,它是特定于这个应用程序的。)

事实证明,增加这些跳跃连接可以实现深度学习网络。

关于卷积的一个注记。虽然输入数据是二维的,但它是一维的。因此,卷积也将是一维的;过滤器将从左向右移动。

让我们编码!

使用平原 MLP 和 ResNet 建立基线

在评估原始研究的迁移学习设置之前,首先在 PTB 数据集上拟合基线多层感知器(MLP)和没有迁移学习的 ResNet 模型。如果没有必要,为什么要把事情复杂化?有人可能会说深度学习模型本身就是一个复杂的问题。在这种情况下,有人会说神经网络很容易适应数据,给出了非常有效的实现。

基线 MLP 网络由 15、10 和 5 的 3 个隐藏 ReLU 层组成,后面是一个 sigmoid 激活层。Keras 制作了这个模型的图片:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

克拉斯笔下的 MLP

MLP 几乎以 97.5%的训练准确度解析了训练数据。这大概是这种架构的最大可能。尽管使用了一些 L2 正则化,对训练数据的过拟合还是发生了,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MLP 对训练数据的过度拟合

最终验证准确率为 95.2%,测试准确率为 95.1%。10%的小验证数据集似乎工作得很好。下面是使用测试数据生成的混淆矩阵。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MLP 模型的混淆矩阵

为了更好地测量,MLP 模型使用循环学习率进行优化,学习率使用学习率查找器进行估计。fast.ai 推广了这种做法。将这种做法应用于 SGD 和 Adam,这种设置的效果似乎提高了约 1%的准确性,即在验证数据集上从 93.7%提高到 94.7%。有趣到可以留到以后用。不幸的是,Keras 对这些工具的支持还没有标准化。

在 MLP 无法完全解析训练数据的情况下,ResNet 会像热刀穿过黄油一样处理数据。训练数据被完全解析,几乎验证数据也是如此。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ResNet 的损耗曲线

你肯定是在开玩笑吧,费曼先生?放大图的最后一点,由于验证损失增加,可以观察到一些过度拟合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

增加验证损失表明过度拟合

对于神经网络来说,解析训练数据集并不罕见,事实上这被认为是一个很好的开始实践。但是验证指标也非常好,准确率达到 99.7%。在讨论部分,产生了一个可以解释这些结果的假设。

运用迁移学习

对于迁移学习模型,ResNet 模型首先适用于更大的麻省理工学院-BIH 数据集。迁移学习设置很简单:最后完全连接的层在 PTD 数据集上重新训练。出于好奇,下面描述了实现这一点的代码片段。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Keras 中的迁移学习

使用汇总功能,可以验证可训练参数的数量已经显著减少。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可训练参数减少

在麻省理工学院 BIH 分校上的结果很好,准确率达到 98.5%。应用迁移学习后,在 PTB 数据集上的测试准确率达到 96.4%。原始论文报告迁移学习后的准确率为 95.9%,这些数字大致相同。

讨论

虽然这很有诱惑力,但在 PTB 数据集上没有迁移学习的 ResNet 的最初几乎完美的验证和测试分数应该非常谨慎地解释。对这些分数的合理解释可能是,由于训练、验证和测试集的随机化,网络实际上记住了样本所来自的人的心电图模式。处理这个问题的正确方法是确保验证和测试集中的数据不包含来自训练数据中存在的人的数据。在这个装置中,对人的概括被积极地测试。然而,造成这种情况的特征在数据中并不存在。

麻省理工学院-BIH 数据集上的 ResNet 结果没有证实这一假设:测试集上的准确率为 98.5%。即使对于倾斜的类,这也是一个非常好的结果。请注意,该模型必须预测 5 个类别,而不是 2 个,这是一项更困难的任务。

所使用的数据心电图是高度周期性的,幸运的是!这使得时间序列可以被格式化成更小的“瓦片”,在这些瓦片中可能存在与众不同的心脏活动模式。直觉上,CNN 网络非常适合这种环境。

就迁移学习而言,迁移学习能提高成绩的假设不无道理。潜在的假设是,构成信号形状的基本分量在具有不同标签的信号中是共享的。在这种情况下,结果并没有证实它的用途。通过在网络的末端重新训练更多的层,通过一次一步地将层的权重设置为可训练的,可以改善结果。

没有与 LSTM 或 GRU 的网络进行比较;这可能是以后的主题。

结论

虽然可能有一些方法上的缺陷进入了这一重复研究,但将 CNN 应用于时间序列的案例已经提出。对于心电图数据,搜索的是一组重复信号的重复模式:这正是 CNN 网络所擅长的。

参考

[1] Kachuee,m .,Fazeli,s .,Sarrafzadeh,m .:心电图心跳分类:一种深层次的可转换表示法。In: 2018 IEEE 医疗保健信息国际会议(ICHI)。第 443-444 页。IEEE (2018)。

[2]穆迪 GB,马克 RG。麻省理工学院-BIH 心律失常数据库的影响。医学和生物工程 20(3):45–50(2001 年 5-6 月)。

[3] Bousseljot R,Kreiseler D,Schnabel,a . EKG 的神经病学-信号数据库生物医学技术,40 级,ergnzungsband 1(1995)S 317。

使用 ResNets 检测工业物联网纺织品生产中的异常

原文:https://towardsdatascience.com/using-resnets-to-detect-anomalies-in-industrial-iot-textile-production-42da77d49ad2?source=collection_archive---------41-----------------------

用于图像分类的机器学习模型通常使用卷积神经网络(CNN)从图像中提取特征,同时采用最大池层来降低维度。目标是从图像区域中提取越来越高级的特征,最终进行某种预测,例如图像分类。

为了提高精度,简单地向网络添加更多的层是很有诱惑力的。然而,研究表明,添加太多的层会增加训练时间,甚至导致精度下降。

在这篇博客中,我们将深入探讨为什么深度神经网络会出现这种情况,如何解决这个问题,并以一个工业物联网用例为例,看看如何在感知实验室中构建一个更有效的模型。

消失的渐变问题

影像分类模型通常使用一系列相互反馈的层来实现其目标,其中额外的层可以提高最终分类的准确性。然而,添加太多的层会导致反向传播期间的消失梯度问题,其中损失函数的越来越小的梯度导致对权重的更新变得越来越小,直到它们趋向于零。这反过来会导致上面提到的培训问题。

拯救残余网络

克服这个问题的一种流行方法是合并残差块,它们共同形成一个残差网络 ( ResNet) 。残差块通过引入早期层跳过未来层的架构模式解决了这个问题。这些“跳过连接”通常通过一个加法操作来实现,由此,在一些卷积层之后,来自网络中较早的特征被添加到新计算的特征,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:残差块的概述。形象由 感知力 灵感 来源

跳跃连接为梯度在反向传播期间的流动提供了额外的、更短的路径,并且经验表明这使得更深的计算机视觉网络能够更快地训练。

残差块的工作方式如下:

  • 输入张量 X 流向 ResNet 块,并沿两条路径向下流动。
  • x 通过卷积层(如图 1 权重层所示)沿主路径向下流动,就像在普通 CNN 中一样,这通常被称为卷积块。结果输出近似于函数 F(x)。
  • X 还流经跳过连接,也称为身份 ,因为它只是转发 X,同时保留其维度。
  • F(x)和 X 然后被加在一起,然后被发送到激活函数(在这个例子中是 ReLU )。

如下面图 2 中的所示,残差块通常被“链接”在一起以形成 ResNets。来自最终残差块的输出与来自最终跳过连接的输出一起被组合,然后被传递到其他类型的层(例如,平均池和完全连接层)用于分类:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:50 层 ResNet 模型示例。形象由 感知力 灵感 来源

在用于图像分类的典型 CNN 中,较早的层通常学习较低级别的抽象(例如,线、角等。),而后续层学习更高级别的抽象(例如,形状组等)。).通过使用跳过连接,我们允许梯度通过网络,而不需要通过激活函数。这有助于网络将信息传递给网络中的后续层,使它们能够学习复杂的特征,而没有梯度消失的风险。

图 3 描绘了 ResNet 块对图像分类模型的应用:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:由使用卷积和批量归一化计算的两层组成的 ResNet 块的示例。在此示例中,在通过 RelU 生成标识块(x)的激活之前,通过 skip 连接将 ResNet 块的输出添加到标识块(x)。当输入与输出激活具有相同的维度时,可以使用这种架构。图片由 感知 灵感 来源

注意,在某些情况下,可以用卷积块代替恒等块,例如当输入和输出尺寸不同时:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:ResNet 块的例子,其中输入和输出具有不同的维度。在这种情况下,在生成卷积块(x)的激活之前,ResNet 块的输出通过 skip 连接被添加到卷积块(x)。形象由 感知器 灵感 来源

由于残差块,梯度现在可以在通过两条路径的反向传播期间流回网络:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5:示出了梯度在反向传播期间可以流经的两个路径的图。形象由 感知力 灵感 来源

当梯度流回穿过梯度路径-2 时,残差块中的权重层(在图 5 中表示为 F(x ))被更新,并且新的梯度值被计算。随着梯度继续流过较早的残差块,它将继续减小(即,趋向于 0)。但是,梯度也会流回跳过连接,从而完全避开残差块中的权重层,因此将保留其值。这允许保持完整的渐变值传播回早期层,允许它们学习激活,从而避免渐变消失的问题。

将 ResNets 应用于工业物联网应用

图像分类技术对于计算机视觉问题特别有用,例如在工业物联网(例如,制造业)中遇到的那些问题。

为了说明这一点,我们在 GitHub 上整合了一个纺织品分类项目。该项目以 72000 幅纺织纤维的特写图像作为输入,每幅图像包含六种可能的制造分类之一(例如,颜色问题、织物切割等)。),以及每个图像的相应分类:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6:具有各种类型制造分类的纺织织物图像示例。其中五个代表异常,而“良好”分类意味着在图像中没有发现问题。图像由感知。

项目中的示例 PerceptiLabs 模型包含三个 ResNet 块,每个 ResNet 块对图像进行卷积以提取特征,并包含直接按原样转发每个块的输入(即,作为标识块)的跳过连接。使用配置为应用加法操作的合并组件,将其添加到块的输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7:感知实验室中的纺织品图像分类模型概述。图像由感知。

该项目展示了这种模型如何用于工业物联网的质量控制。例如,相机可以在制造过程中随机拍摄织物的特写照片,然后将它们呈现给模型以进行异常检测。

最重要的是,这个项目展示了在 PerceptiLabs 中构建 ResNet 块是多么容易。

结论

具有大量层的神经网络容易遭受消失梯度问题,由此在反向传播期间梯度趋向于零。由于梯度值如此之小,网络中位于较早位置的层可能很少更新或根本不更新其激活,从而导致训练速度变慢、停止,甚至失去其准确性。

ResNet 块是这个问题的一个很好的解决方案,因为它们允许你使用大量的层,最重要的是,它们很容易在 PerceptiLabs 中构建。

因此,要想知道这有多简单,请务必查看我们在 GitHub 上的纺织品分类项目。一如既往,我们希望您能参与我们的社区频道的讨论。

使用 RStudio 项目模板帮助数据科学团队实现项目标准化

原文:https://towardsdatascience.com/using-rstudio-project-templates-to-help-the-project-standardization-in-data-science-teams-a963db12abac?source=collection_archive---------45-----------------------

改善数据科学中的团队协作和项目标准化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

数据科学领域的许多工作仅仅依靠数据科学家/分析师来保证项目的标准化和代码的可复制性;不幸的是,这变成了混乱/混乱的来源,因为每个人(即使在同一个团队)都有不同的工作策略。为了帮助确保团队共享相同的项目标准,RStudio 提供了一种 cookiecutter,您可以在其中开发(以包的形式)许多模板,供同一团队的用户共享。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

项目模板背后的故事

最近的研究旨在为社会提供方法,帮助用户更好地理解和组织他们的项目、数据和从这些数据中产生的见解。从 CRISP-DM 一直到团队数据科学流程,经过 KDD ,我们经历了许多方式来增强我们在团队中的工作能力,共同努力以更快的速度和更高的可重复性获得所需的洞察力。

尽管如此,这个过程会重复无数次,并且回过头来重新开发一个洞察力,或者重新训练一个模型的过程会变得很有挑战性,因为很久以前编写的代码不容易获得,并且可能很难理解几周/几个月/几年前开发这个项目的整个过程。

一些项目可能看起来像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代表无组织方式存储数据和代码的图像

即使只是打开一个存储库,把脚本、文件、函数。gitignores 和任何类型的文件需要交付一个闪亮的网页或机器学习模型,或某种分析,这个过程缺乏创建代码和过程的能力,这些代码和过程可以被将来可能被分配到这个项目的任何其他人理解。

因此,这个 RStudio 项目模板旨在帮助用户在开始项目时创建某种模式,帮助团队标准化项目组织,以便每个人都可以轻松地被分配到一个项目,并了解那里发生了什么。

也许,把项目变成这样:

-- project_directory/
 | -- data/
    | -- raw/
    | -- reference/
    | -- processed/
 | -- scripts/
    | -- modelling/
    | -- analysis/
    | -- production/
 | -- markdown/
 -- .gitignore
 -- project_directory.Rproj

创建新的 R 包

项目模板可用于创建具有预先指定结构的新项目,创建这些项目模板的一种方法是创建 R 包,这将允许用户与任意多的用户共享其模板。

R 包的创建过程(相当简单)非常简单。 Hadley 的 R 包指南涵盖了创建包过程中的许多注意事项。但是由于我们的包将只包含一个函数,它不应该需要开发一个更健壮的包所涉及的复杂性。

从项目的菜单中创建一个 R 包很容易,应该让用户看到一个样例包,它包含 R 包结构、hello.R函数和一些其他文件。第一步是删除位于R/hello.R文件和位于man/hello.Rd文件。之后,我们从一个干净的包开始,第一步是创建我们的函数。

创建将创建模板的函数

为了“创建模板”,我们必须指示 R 将如何处理它,以及当我们在新的项目菜单中提供这个函数时,它将如何表现。因此,这个函数采用一个强制参数,另一个是附加参数,可以帮助您的项目创建工具的逻辑。第一个参数将始终是这个新项目的路径,因为它也将创建一个. RProj 文件,它将驻留在一个新文件夹中。该函数的其他参数作为...传递,可以在代码中用它们的名字调用它们,或者将它们分配给dots <- list(...)

我们的函数将执行一些任务,显示一些可以嵌入到项目创建模板中的特性。它将:

  • writeLines()创建一个 README.md 文件;
  • 如果一个复选框被选中,它将创建一个.gitignore文件;
  • 给定来自用户的选定输入,创建具有特定名称的文件夹;

为了创建一个函数,并确保roxygen2可以解释它,并导出应该由最终包导出的函数,我们将根据下面的语法编写函数。

#' This package will create a function called create_project()
#'
#' It's callback is at: inst/rstudio/templates/project/create_project.dcf
#'
#' @exportcreate_project <-
function(path, ...) {# Create the project path given the name chosen by the user:
dir.create(path, recursive = TRUE, showWarnings = FALSE)# Change the working directory to the recently created folder:
setwd(file.path(getwd(), path))# Collect the list of inputs in a list to be called later:
dots <- list(...)# In the project template we've added 2 choices for the user:
# * One allows them to select if the project will have a .gitignore file
# * The other will create a folder, given a select input from the user# Check .gitignore argument
if(dots[["createGitignore"]]) {
git_ignores <-
c(
'.Rhistory',
'.Rapp.history',
'.RData',
'.Ruserdata',
'.Rproj.user/',
'.Renviron'
)writeLines(paste(git_ignores, sep = '\n'), '.gitignore')
}# Check selected folder
if(dots[["folder"]] == "Production"){
dir.create("production", recursive = TRUE, showWarnings = FALSE)
} else {
dir.create("development", recursive = TRUE, showWarnings = FALSE)
}}

创建.dcf 文件

创建了函数文件后,下一步是创建.dcf文件。这个文件负责创建用户将与之交互的框。除了用户将要输入的路径,您还可以创建任意数量的复选框/文本输入/选择输入,以便向最终用户授予定制权限。对于我们的项目,我们将创建一个复选框,以便用户可以决定是否创建.gitignore文件和一个选择输入,以便用户可以定义项目的范围(开发或生产);

本解决方案(开发或生产)仅用于说明目的,并不反映项目的任何实际状态。

必须在文件夹inst/rstudio/templates/project中的包内用您选择的名称创建.dcf文件,它应该遵循下面的语法:

Binding: create_project
Title: My First Project Template
OpenFiles: README.md
# In the project you can also add icons (the icon should be a PNG, smaller than 64kb
# and in the inst/rstudio/templates folder
# Icon: name_of_pic.pngParameter: folder
Widget: SelectInput
Label: Choose the scope of the project
Fields: Production, Development
Default: Production
Position: leftParameter: createGitignore
Widget: CheckboxInput
Label: Create .gitignore
Default: On
Position: right

devtools::document() + devtools::install()

现在我们的包结构已经创建好了,我们可以使用devtools::document()函数来创建它的文档页面。尽管这个包主要是作为 RStudio 的一个插件开发的,但是在将它安装到 R 中之前,最好对它进行文档化,因为它会搜索项目运行所需的任何依赖项和包。

通过运行devtools::install()函数,在我们的包中,我们将安装它,并从现在开始使它在任何其他 R 会话中可用。这应该足以使 RStudio 可以将外接程序作为新的项目模板进行访问。

之后,您的项目模板应该可以在 RStudio 的项目列表中找到。如果您想了解更多关于调整您的项目模板并增加更多可定制性的不同功能,请查看 RStudio 项目模板页面。

结论

鉴于数据科学的最新发展及其与软件工程技术的集成,团队内标准化项目的需求变得很方便,以确保每个人都能理解,并被他们的搭档理解。这允许更快地调试项目,并减少了遗留代码的缺点,这些代码是同一个团队中的人无法理解的。当然,这个特性本身不会帮助记录代码,或者标准化编写 R 脚本的方式(请参考tidy verse 风格指南),但是它是一个工具,可以帮助用户创建关于项目管理的模式。

查看托管本文中使用的代码的 GitHub 页面,如果您想尝试这个例子,可以克隆这个库,或者通过运行:devtools::install_github('paeselhz/rstudioProjectTemplate')将其安装在 R 中。

利用卫星描绘纽约市的经济机会

原文:https://towardsdatascience.com/using-satellites-to-map-economic-opportunity-in-new-york-city-3059aece5404?source=collection_archive---------64-----------------------

纽约市高低经济机会的光谱特征初探。

纵观历史,纳入空间背景的数据揭示了在不断增加的海量数据中不可见的变革性见解。在 19 世纪中期的英国,一位名叫约翰·斯诺的医生因追踪 1854 年伦敦霍乱爆发而闻名。斯诺以绘制霍乱病例地图并展示其在城市水井周围的聚集而闻名——他认为霍乱是通过受污染的水源传播的,而不是像当时普遍认为的那样通过“不良空气”传播的。由于 Snow 的空间数据工作,公共卫生政策和实践在霍乱的检测和缓解方面取得了进展。在新冠肺炎指数感染全球数百万人的时候,似乎应该记住斯诺的经典著作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

霍乱病例地图。来源:《论霍乱的传播方式》约翰·斯诺著,检索自维基百科

作为洛克菲勒基金会的一名空间数据科学家,我使用卫星和地理参考数据集来获得关于跨景观的模式和关系的见解,这是受雪的启发。洛克菲勒基金会和我们在股权和经济机会方面的工作感兴趣的一个主题是机会区 (OZs),这是官方指定的经济困难社区,作为备受讨论的 2017 年减税和就业法案的一部分,投资者可以获得特殊的税收减免。如果人口普查区的个人贫困率至少为 20 %,家庭收入中位数不超过该地区中位数的 80 %,并且州政府从所有合格的人口普查区中选择一部分人口普查区,那么这些人口普查区就有资格获得 OZ 地位。今年早些时候,我们的团队询问是否有可能使用卫星图像来识别纽约市的机会区域。这个问题的核心是一个更深层次的问题:*在高收入和低收入地区,我们的建筑环境中是否有独特的特征和模式?*换句话说,高收入地区和低收入地区之间是否存在空间和光谱上截然不同的特征?

我们假设,是的,低收入和高收入地区之间确实存在显著的特征和模式,这将有助于不同的光谱特征,并决定在纽约市测试这一假设。在多项研究中,研究人员发现,纽约市和美国 T2不同地区的经济状况(以及其他社会经济因素)可以使用谷歌街景图像进行统计评估。虽然卫星图像是从上面捕捉的,分辨率低得多——通常捕捉地面上几十平方米的像素——但其他研究人员发现,卫星测量的夜光可以解释发展中地区高达 75%的经济成果。我们还认识到,卫星数据对于捕捉机会区域并不完美,因为它是栅格类型(或多或少是连续的)数据源,而人口普查边界是矢量类型(多边形),可捕捉指定区域内不同社会经济因素的平均值;我们并不期望在卫星数据中找到完美的边界框,而是簇的梯度显示或多或少可能是机会区域的区域。

作为我们的遥感负责人,我首先使用中位数家庭收入百分比和个人贫困率百分比确定了 2011 -2015 年期间纽约市内符合 oz 资格的所有人口普查区域——总共 806 个。在这项工作中,所有符合条件的人口普查区域都被视为机会区,并在下方以深绿色显示在纽约市边界上方,以白色显示。然后,我使用谷歌地球引擎,用 Sentinel-2(一颗中等分辨率的公共卫星,每 10 天重复一次)为 2016 年的纽约市创建了一张合成的镶嵌图像。请注意,2016 年是 Sentinel-2 影像与所使用的 2011-2015 年人口普查数据最接近的一年。为了做到这一点,我提取了纽约市地区 2016 年全年的所有图像(总共超过 500 张图像),并通过过滤云来处理每张图像,然后在所有重叠图像的每个波段的每个像素处取平均值。这个过程产生了一组相邻的图像,每个波段中的每个像素都包含 2016 年的平均反射率值,然后我将它们拼接在一起,创建了一个单一的图像。这种合成使数据集正常化,并使季节变化以及云覆盖的差距均匀化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有资格成为机会区的人口普查区域以绿色显示,覆盖在白色的纽约市上。

再次使用 Earth Engine,我使用 60,000 个点(代表不到 1%的可能像素)训练了随机森林分类器和最大熵分类器,这些点是使用 oz 和非 oz 的普查几何从合成 Sentinel-2 图像中提取的。我将这些分类器应用于整个合成图像,以将每个像素分类为 OZ 或 non-OZ,然后使用多数投票(一致)将两者组合成一个集成。生成的分类器如下所示,深绿色显示分类为 OZ 的像素,白色显示非 OZ。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

集合 OZ 分类器,其中绿色分类为可能是 OZ,而白色分类为可能不是 OZ。

概括地说,这个模型比 random 要好,在 Bronx 和东布鲁克林表现得特别好,这两个地区的剪辑如下所示。我们第一个问题的答案是肯定的,纽约市的高收入和低收入地区有不同的共享光谱特征。很明显,拥有大量植被的区域往往被归类为非机会区域(公园是白色块证明了这一点),而拥有大量水泥和沥青的区域往往被归类为机会区域(深绿色的主要道路证明了这一点)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

布朗克斯:左边是 OZs,右边是 Classifier。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

东布鲁克林和皇后区:左边是 oz,右边是 Classifier。

很明显,拥有大量植被的地区往往被归类为非 OZ(公园是白色块证明),而拥有大量水泥和沥青的地区往往被归类为 OZ(深绿色的主要道路证明)。然而,这些并不是唯一的驱动因素——否则,机场周围的区域将由于跑道而被完全归类为机会区域。因为对这种分类最重要的光谱带是红色、近红外和短波红外,所以植被、人造材料类型以及水和湿气积累可能起了重要作用。同样可能的是,某些类型的屋顶、街道的宽度和经常在街道上行驶的汽车数量也对分类有很大的影响。随着纽约市的街区继续中产阶级化,建筑物在新的发展时期之前被重新规划,过渡中的区域很可能提供混合的光谱特征。曼哈顿下城就是一个例子:虽然生活成本在过去几十年里飙升,但新建筑很少,改建的旧建筑受到青睐。分类器在曼哈顿下城的表现特别差,可能就是因为这个原因。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

曼哈顿下城:左边是真正的 OZs,右边是分类器。

这项工作仍处于早期阶段,但它支持这样的假设,即存在与卫星可观测的经济机会相关的不同光谱特征的空间模式。卫星数据可能是一种有价值的工具,可用于以高分辨率了解经济机会、追踪某些类型的中产阶级化,以及以低成本和跨时间总体了解整个城市的社会阶层状况。随着新冠肺炎对纽约市的毁灭性影响,这种卫星地图的潜在用途已经成为前沿。在疫情早期就很清楚,低收入家庭更有可能生病,但也更有可能遭受严重的医疗并发症,从长远来看,更有可能受到不利影响。其他博客、文章和媒体来源已经利用公开的纽约市健康数据将病例与邮政编码联系起来,对此进行了广泛的研究(尽管许多研究人员没有按照人口对邮政编码数据进行标准化),我在这里不会深入研究这些趋势。展望未来,当我们学习减轻新冠肺炎时,高分辨率制图工具在选择测试地点或弹出式诊所方面可能是无价的。本着 John Snow 的精神,洛克菲勒基金会的数据科学团队致力于探索数据科学在现实世界问题中的这些新颖应用,以实现高效的社会变革。

将散点图发挥到极致

原文:https://towardsdatascience.com/using-scatter-diagrams-to-their-max-potential-fbbac6a7c489?source=collection_archive---------23-----------------------

制图指南

我会教你散点图的来龙去脉;如何获得见解,以及如何以最具影响力的方式展示这些见解。啪啪!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“简单性可以归结为两步:

识别本质。

排除其他的。”—利奥·巴伯塔

我记得当我第一次开始为工作创建报告时,我想通过展示各种图形和图表来展示我的技能。我的想法是通过从每个角度呈现每个数据点,包括尽可能多的细节到一个图表中,来最大化我的报告和演示。我现在一想到这个就害怕。随着时间的推移,我了解到每个图表都有一个正确的情况,当涉及到用数据有效地传达一个故事时,越少越好。这就是我今天想和大家分享的信息。

无论您是专家还是新手,我相信这篇文章对任何想要提高或更新图形知识的人来说都是一个很好的资源。在这篇文章中,我想回顾以下内容:

  1. 何时使用散点图
  2. 如何在散点图中表示数据
  3. 理解和解释你的散点图

通过这些部分,我的目标是帮助你识别不必要的琐碎和噪音,为你的观众呈现一个简单、直白的故事,同时尽量避免过于专业。

何时使用散点图

散点图主要用于确定一对数值数据点之间是否存在因果关系。散点图在显示关系方面很有效,因为它可以很好地显示任何部分的数据点范围。如果我们使用条形图或折线图,我们能得出的最好结果就是数据的趋势。我们会错过很多其他潜在的见解。让我们看一个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里的图形表示相同的数据点,但是表示为折线图和散点图(忽略我不会画直线)。数据点是虚构的。它们并不代表任何已开展研究的实际数据。

假设我们有一组弓箭手的数据以及他们的高度和射击精度。如果我们用这些数据画一个线形图,我们可以看到身高和准确性之间有一个积极的趋势:射手越高,射得越准。但是这条线的方向并没有给我们带来额外的意义,并且使图表更加混乱。两点之间的线一般代表一段时间(通常是时间)内的变化,而不是其他数值。如果我们将数据绘制成散点图格式,我们可以看到高度和准确度对之间的趋势,并正确地看到值的范围。如果数据点没有趋势,那么折线图就不会给我们任何信息。我们只会看到像意大利面条一样的混乱,唯一可以接受的时候是当你是一个蹒跚学步的孩子发脾气的时候。

这里有一些问题,你可以问自己,以确定是否应该使用散点图:

  1. 我的数据需要用时间来表示吗?
  2. 我的数据需要汇总吗(取数据的平均值或总和)
  3. 我的数据是否少于两个非日期/时间变量?

如果你对这三个问题都回答了,那么使用散点图应该没问题。

因此,在比较两个变量(其中一个不是时间)时,最好用散点图来表示数据,以便于阅读和分析。

如何在散点图中表示数据

现在我们知道了什么时候使用散点图,让我们花一些时间来确定如何最好地表示我们的图表。根据散点图的结果,我们可以专注于讲述一个特定的故事或发现。以下是我们强调我们发现的方法。

趋势线

趋势线是显示数据对之间关系的好方法。数据显示的是正相关还是负相关?数据对之间的相关性有多强?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正相关还是负相关?左图显示了身高和准确度之间的正相关关系,而左图显示了负相关关系。

看左边的图表,我们可以看到趋势线向上倾斜,显示了射手的高度和准确性之间的正相关,但这些点离趋势线相当远,表示弱相关。相比之下,右边的图表显示数据点向下倾斜并接近趋势线,表明有很强的负相关性。

斜率也告诉我们趋势线是完全水平还是垂直。水平趋势线表示 x 轴上的变量不影响 y 轴上的变量,而垂直趋势线告诉我们 x 轴变量与 y 轴变量无关。这两个结果是可以互换的,因为我们可以将 x 轴和 y 轴设置为任意一个变量。

使用趋势线,我们可以更容易地解释我们绘制的数据的性质。我在下面添加了趋势线能告诉我们的更简洁的定义:

**趋势线斜率:**趋势线的陡度告诉我们 y 轴的变化率是由 x 轴引起的。从原点向上或向下的斜率分别代表正向或负向趋势。完全水平的趋势线表示 y 轴没有变化,这取决于 x 轴的变量。垂直趋势线将显示 y 轴上的变化是由 x 轴上使用的变量之外的其他变量引起的。

**趋势线的数据密度:**趋势线的数据密度告诉我们变量之间的相互依赖程度。如果数据点接近趋势线,它们是非常依赖的。较低的密度(远离趋势线的数据点)表示其他因素可能与 y 轴或 x 轴相关。

**趋势线的曲率:**一条直的趋势线代表一个恒定的比率变化:对于 x 中的每个值,y 中的一个定义值都会发生变化。如果我们看到一条曲线趋势线(抛物线),那么变化率可能沿着 x 轴加速或减速。

如果您需要更多详细信息,下面是一个很好的资源,提供了有关趋势线、如何理解其斜率以及在坐标几何中的一般用途的更多信息:

[## 线的斜率(m)(坐标几何)-数学开放参考

定义:直线的斜率是一个衡量其“陡度”的数字,通常用字母 m 表示。它是…

www.mathopenref.com](https://www.mathopenref.com/coordslope.html)

将趋势线与图表的各个部分结合起来可以帮助我们讲述关于数据的更具体的故事。

横截面

根据我们试图告诉观众的故事,我们可以专注于散点图的某些部分。通常,从对数据的一般性解释开始,然后进行更深入的研究是一个好主意。这有助于你的观众理解并参与故事。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建你的散点部分将有助于吸引你的观众的眼睛到与你的故事相关的信息。

从上图中,我们可以看出弓箭手数据的两个特点:

  1. 平均身高在 5 英尺 4 英寸到 5 英尺 6 英寸之间的弓箭手的准确度低于平均水平。我们可以做出这样的推断,因为该范围内的大多数数据点都低于趋势线。
  2. 6 ‘到 6’ 8 "之间的弓箭手往往是平均身高和准确度。我们看到大多数数据点聚集在这个区域,代表平均值。

分割散点图的各个区域是关注平均值、高于/低于平均值的比率,甚至数据集的异常的好方法。使用这种技巧将真正帮助我们引导我们的观众通过我们试图讲述的故事。

环绕星团

当我们绘制散点图时,我们不一定会生成带有明显趋势线的图表,但这并不意味着我们不能从数据中获得洞察力。正如我们在趋势线部分所讨论的,我们可以有一个散点图,其中趋势线可以是垂直的或水平的。见下文:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同样,这个图表不是用任何事实数据构建的。其目的是为了说明一个观点。具体来说,要说明很多点!(双关绝对有意)。

这里我们有一个不同的数据集(最后,我也厌倦了弓箭手的数据)。x 轴代表作家使用的平均字数,y 轴代表他们的经验年限。让我们通过圈出数据点的聚类来看看我们能从这个数据集看出什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

是的,我确实意识到我说过散点图不应该与时间间隔一起使用,但是在这个场景中,年不是作为一个连续的时间间隔使用的。岁月是对一个人有多少经验的定量衡量,而不是过去了多少时间。

看上面图表中圈出的数据,似乎有几年写作经验的作家,以及有更多年写作经验的作家,倾向于使用更短的词。另一方面,中等写作经验范围内的作家使用更长的单词。我们可以从中得出的结论是:

新写手的词汇量更小/更简单,因此单词长度更短。随着作者变得更有经验,词汇量扩大,使用更长的单词。最有经验的作家会重新使用较短的词语,因为经验告诉他们,易读性有助于更好的写作和更广泛的受众。

我们不需要寻找一种趋势来确定一种模式。我们可以把重点放在聚类或异常上,看看我们是否能理解这些数据,或者下一步把我们的研究重点放在哪里。

理解和解释你的散点图

我们花了大量时间讨论解释和呈现数据的不同方式,但知道如何真正理解和解释数据所呈现的内容同样重要。从散点图中很容易做出有偏见的假设,所以让我们来看看一些潜在的陷阱,看看我们如何避免犯这些错误。

确保样本具有总体代表性

我们的散点图很少包含我们试图考虑的全部人口。包括我们自身偏见在内的不同因素会影响我们对数据的采样方式。谷歌新闻就是一个很好的例子。根据你过去的搜索历史,谷歌会向你展示“相关的”新闻话题和广告,但这些话题和广告并不代表整个人群,它只是你感兴趣的范围。

如果你想了解更多关于如何让谷歌新闻表面不偏不倚的文章,你可以在这里查看我早先的媒体帖子:

[## 使用谷歌新闻获取公正的信息:为什么它很重要

在我们这个以技术进步、数字化和几乎无限制为特征的全球社会中…

medium.com](https://medium.com/@irfanhashmi/using-google-news-for-unbiased-information-why-it-matters-6d0fba31138f)

让我们看看下面的图表,更深入地了解这一现象。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代表财富和爱猫/爱狗人士平均分配的图表。(这是我不介意进入的朋友区)。

让我们假设我们生活在一个财富与某人更喜欢狗还是猫没有关联的世界。在这个世界上,事实是富有的爱狗人士和不那么富有的爱狗人士一样多,猫也是如此——人口分布均匀。现在让我们假设你主要和富有的养猫人在一起。如果你根据对你相处过的人的调查制作了一个散点图,你会错误地看到爱猫的人和更富有的人之间的相关性。你会错过调查铁杆爱狗人士和财富地位较低的人。

这里有另一个例子:你向所有 1000 名订户发送了一封电子邮件,宣传一种要出售的新产品。您的 100 名订户购买了该产品。其中 60 人住在俄亥俄州,其余 40 人住在其他州。你可以使用 100,并确定:*“哇,俄亥俄州人特别喜欢我的产品!”*现在,假设你的 1000 名用户中有 800 名来自俄亥俄州。这改变了现在的故事,不是吗?你刚刚向比其他州更多的俄亥俄州人推销。俄亥俄州人不一定喜欢你的产品,只有 7.5%的人买了你的产品。另一方面,20%的非俄亥俄州人也购买了你们的产品。(不过,俄亥俄州人很喜欢你,所以订阅了你的博客)。

为了确保您有一个良好的样本集,请确保您使用的数据真正代表您试图描绘的洞察力。一个很好的练习是:

  1. 记下你试图评估的行为或活动。
  2. 确定进行评估需要考虑的所有变量。
  3. 检查您当前的取样方法是否足够彻底,能够包含步骤 2 中确定的变量。

相关性并不总是可传递的

每个人都得到一个坚韧不拔的重启这些天…smh

如果所有的鲍勃都是建筑工人,并且所有的建筑工人都能修理它,那么所有的鲍勃都能修理它吗?是的,他们可以。因为能够“修复”是 bob 的传递相关性。但是在这个例子中,关键字是所有。我们做了一个非常笼统的陈述。如果我们说如果所有的 bob 都是建造者,并且一些建造者可以修复它,那么不是所有的 bob 都可以修复它。

所以当我们制作多重散点图时,我们必须小心不要假设不同的相关性和它们的变量是相互关联的。它们并不总是可传递的。

这里有一个更非 SAT 风格的场景。假设我们绘制了两个图表:

  1. 睡眠时间与生产时间的对比图
  2. 生产小时数与一天内写的文章数的关系图。

如果两个图表都显示了每个变量的正相关,那么似乎合乎逻辑地说*“一个睡得更多的人可以在一天内写更多的文章。”这可能是真的,但我们无法推断出这个结论。我们不知道相关性是否传递。一个人写更多的文章可能是因为他们吃了富含碳水化合物的早餐,为他们的大脑提供了能量。我们真的不知道。所以最好避免这种比较,除非我们能证明相关性是传递的。如果你能花时间证明传递性的存在,那么添加这些细节可能是值得的。*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

老实说,这是我在会议中最喜欢画的图表之一。(请随意使用它来获得“房间里最聪明的人”奖。我知道,出于同样的原因,我也很内疚。

让我们用上面的图表来说明这个例子。这包括一些多维图形,我们不会在这里深入讨论(关于理解这一点的参考资料在文章的底部)。可以说,“x”是一个向量,代表我们的样本的所有睡眠时间,“y”是一个向量,代表我们的同一样本的所有生产时间,“z”是一个向量,代表同一样本撰写的所有文章。相差小于 90 度的矢量被称为相关矢量,因为它们通常在同一方向运动。这些是向量 x 和 y,y 和 z。如果我们观察矢量‘x’和‘z ’,它们有一个大于 90 度的差,表明这两个矢量是相关的。

所以为什么要费这么大的劲来解释这个呢?因为,作为讲故事的人,你的工作是引导你的听众,帮助他们避免对你的发现的误解。我个人发现在白板上使用向量示例对解释这个概念非常有帮助。许多企业将根据这些发现做出决策,因此确保我们帮助他们做出最好、最准确的决策非常重要。

决定先有鸡还是先有蛋的问题

我们已经学到了很多关于从散点图中可以做出什么样的推论,但是我们仍然需要确定先有鸡还是先有蛋?

我们已经看到了弓箭手的身高和他们的准确性之间的正相关关系,但是是高的弓箭手更准确还是射击准确的弓箭手变高了?这可能听起来像是一个荒谬的问题,但这是一个你必须以某种方式证明的观点。

这里有一个更模糊的例子。让我们假设比一般孩子更爱发脾气的孩子和学校成绩差之间存在关联。哪个是原因,哪个是结果?成绩差会让孩子发更多的脾气吗,或者发脾气的孩子成绩更差吗?鸡还是蛋?

隔离相关结果的一个好方法,或者像我喜欢说的,“快速和肮脏的方法”,是创建更多的可能因素的图表。我们可以检查营养如何影响成绩吗?我们还可以检查单亲家庭或双亲家庭是否有所不同吗?可能会发生很多反复,但在我们向观众讲述之前,我们作为故事讲述者有责任确定真相。

如你所见,我们可以做很多事情,甚至在创建散点图时需要考虑更多。为了帮助总结它们,下次创建散点图时,请记住以下问题:

  1. 我想向我的观众展示什么故事或推荐?
  2. 使用散点图是表示我的数据的最佳方式吗?
  3. 关于我绘制的数据,我的趋势线告诉了我什么?或者还有其他出现的模式吗?
  4. 我的数据集能代表整个人口吗?
  5. 我是否恰当地关联了我的发现?
  6. 我是否采取了足够的步骤来确定真正的因果性质?

浏览这些步骤将帮助您识别数据中最重要和最相关的方面,并恰当地呈现它们。由于我们还进行了一些关于如何思考你的发现的心理练习,你将能够在演示环境中自信地对你的观众说话。

如果你喜欢学习散点图和可以深入其中的思想,我强烈推荐阅读乔丹·艾伦伯格的书《如何不出错:数学思维的力量

*这是我 2019 年最喜欢的读物,你可以从中学习很多很好的概念,并将其应用到日常工作中。本书的第 4 部分, *Regressions,有很多关于如何从概念上看待数据以及从中可以得出什么含义的详细内容。这本书那一部分大量使用了散点图。它还包含了许多其他易于理解和有力使用的数学概念。(上述链接是一个附属链接,我可能会通过该链接的销售佣金得到补偿)。

我喜欢收到对我工作的反馈,所以请随意评论或给我发消息。如果你对我写的任何东西有任何问题或需要澄清,请随时给我发消息这里。我很乐意尽我所能帮忙!

快乐学习!

使用 Scikit-learn 的二叉树有效地查找经纬度邻居

原文:https://towardsdatascience.com/using-scikit-learns-binary-trees-to-efficiently-find-latitude-and-longitude-neighbors-909979bd929b?source=collection_archive---------4-----------------------

在不破坏 Python 解释器的情况下将多组 GPS 坐标连接在一起

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由穆罕默德·哈桑来自 Pixabay

来自纬度和经度数据的工程特征看起来像是一项杂乱的任务,可能会诱使新手创建自己的 应用函数 (或者更糟:一个巨大的 for 循环 )。然而,这些类型的 强力 方法是潜在的陷阱,当数据集的大小增加时,这些陷阱会很快暴露出来。

例如:假设您有一个包含 n 项的数据集。将这些 n 项与 n-1 其他项进行显式比较所需的时间基本上接近 n 。这意味着数据集中的行每增加一倍,查找所有最近邻的时间就会增加 4 倍!

幸运的是,你不需要计算每个点之间的距离。在scikit-learn中有一些数据结构可以有效地确定邻居权限,这些数据结构利用了 优先级队列 的力量。

它们可以在邻居模块 中找到 ,本指南将向您展示如何使用这些难以置信的类中的两个来轻松解决这个问题。

入门指南

首先,我们加载库。

import numpy as np
from sklearn.neighbors import BallTree, KDTree# This guide uses Pandas for increased clarity, but these processes
# can be done just as easily using only scikit-learn and NumPy.
import pandas as pd

然后我们将根据从国家海洋和大气管理局公开获得的气象站位置制作两个样本数据框架。

# Column names for the example DataFrame.
column_names = ["STATION NAME", "LAT", "LON"]# A list of locations that will be used to construct the binary
# tree.
locations_a = [['BEAUFORT', 32.4, -80.633],
       ['CONWAY HORRY COUNTY AIRPORT', 33.828, -79.122],
       ['HUSTON/EXECUTIVE', 29.8, -95.9],
       ['ELIZABETHTON MUNI', 36.371, -82.173],
       ['JACK BARSTOW AIRPORT', 43.663, -84.261],
       ['MARLBORO CO JETPORT H E AVENT', 34.622, -79.734],
       ['SUMMERVILLE AIRPORT', 33.063, -80.279]]# A list of locations that will be used to construct the queries.
# for neighbors.
locations_b = [['BOOMVANG HELIPORT / OIL PLATFORM', 27.35, -94.633],
       ['LEE COUNTY AIRPORT', 36.654, -83.218],
       ['ELLINGTON', 35.507, -86.804],
       ['LAWRENCEVILLE BRUNSWICK MUNI', 36.773, -77.794],
       ['PUTNAM CO', 39.63, -86.814]]# Converting the lists to DataFrames. We will build the tree with
# the first and execute the query on the second.
locations_a = pd.DataFrame(locations_a, columns = column_names)
locations_b = pd.DataFrame(locations_b, columns = column_names)

这创建了两个极小的数据帧:一个有 7 行,一个有 4 行。对于这么小的数据集,我们将要使用的数据结构不会在性能上提供任何帮助(实际上会是一个障碍)。 文档 提供了更多关于何时选择一种算法比另一种算法更有利的信息。

使用 k-d 树

我们先用一棵 k-d 树 来演示。它会将数据点分割成二叉树,每次评估一个维度,并在中间值上进行分割。然后,将使用另一组点和值 k 对其执行查询,以确定每个点要返回多少个相邻点。

# Takes the first group's latitude and longitude values to construct
# the kd tree.
kd = KDTree(locations_a[["LAT", "LON"]].values, metric='euclidean')# The amount of neighbors to return.
k = 2# Executes a query with the second group. This will return two
# arrays.
distances, indices = kd.query(locations_b[["LAT", "LON"]], k = k)

结果是两个数组。一个用于距离,一个包含相邻位置的索引(指用于构建树的数据帧)。

然后,索引可以被 映射到 到有用的值,并且两个数组容易地 与其余数据合并

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显示的距离是原始坐标之间的欧几里德距离。

一些限制

k-d 树在没有大量维度的情况下表现很好。虽然这似乎适合这里的数据;在纬度和经度的情况下,基于欧几里德距离的差异进行评估将会以精度为代价。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 PixabayGerd Altmann

为了更接近地近似坐标间的实际距离,我们可以使用。不幸的是,k-d 树算法对此不起作用,因为它对于每个维度都有一种有点僵硬的方法。要查看哪些可用的距离度量可用于 k-d 树数据结构,请使用以下命令:

*KDTree.valid_metrics*

使用球树

一个 球树 类似于一个 k-d 树,除了它不是在一个单独的维度上进行划分,而是根据到中心的径向距离来划分点。它能更好地处理更高维度的数据,也允许使用哈弗斯度规。

要在 scikit-learn 中使用具有哈弗线距离的球树,必须首先将坐标从角度转换为弧度。

*# Creates new columns converting coordinate degrees to radians.
for column in locations_a[["LAT", "LON"]]:
    rad = np.deg2rad(locations_a[column].values)
    locations_a[f'{column}_rad'] = rad
for column in locations_b[["LAT", "LON"]]:
    rad = np.deg2rad(locations_b[column].values)
    locations_b[f'{column}_rad'] = rad*

除此之外,这两个 API 几乎是相同的,并且大部分过程将在最小的修改下重复。

*# Takes the first group's latitude and longitude values to construct
# the ball tree.
ball = BallTree(locations_a[["LAT_rad", "LON_rad"]].values, metric='haversine')# The amount of neighbors to return.
k = 2# Executes a query with the second group. This will also return two
# arrays.
distances, indices = ball.query(locations_b[["LAT_rad", "LON_rad"]].values, k = k)*

****最后一点注意:返回的距离将基于半径为 1 的 单位球体 。如果您想查看反映典型测量值的值,这是一个简单的转换。

  • ****到英里:距离 x 3,958.8(地球的半径以英里为单位)
  • ****到千米:距离 x 6,371(地球半径以千米为单位)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以英里为单位的最终数据帧。

在这个例子中只有 12 个数据点,使用具有哈弗斯度量的球树的优势无法显示。但是在一个更大的稀疏度更低的数据集中,这将是你在用纬度和经度进行评估时想要做出的选择。

当然,这两种算法都不仅限于这种用例,此处显示的步骤可以扩展到可以通过多种距离度量之一排序的任何一组要素。

我们建模的复杂系统有无数的影响因素,这些因素导致了数据科学家们一直在努力减少的误差水平。有了这些工具,您将更有能力有效地发现其他因素,并将特征工程提升到一个新的水平。

使用 scispaCy 进行命名实体识别(第 1 部分)

原文:https://towardsdatascience.com/using-scispacy-for-named-entity-recognition-785389e7918d?source=collection_archive---------20-----------------------

从生物医学文献中提取数据的分步指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

比阿特丽斯·佩雷斯·莫亚在 Unsplash 上的照片

2019 年,艾伦人工智能研究所(AI2)开发了 scispaCy,这是一个完整的开源 Python 空间管道,旨在使用自然语言处理(NLP)分析生物医学和科学文本。scispaCy 是一个强大的工具,特别是用于命名实体识别(NER),或识别关键字(称为实体)并将其分类。我将向您介绍在 NER 使用 scispaCy 的基本知识,您将很快成为 NLP 大师。

议程

  1. 设置环境
  2. 安装熊猫
  3. 安装 scispaCy
  4. 选择型号
  5. 导入包
  6. 输入数据
  7. 选择数据
  8. 实现命名实体识别
  9. 更大的数据

设置环境

第一步是选择一个工作环境。我用过 Google Colab,但 Jupyter 笔记本或简单地从终端工作也很好。如果您确实在终端上工作,请确保创建一个虚拟的工作环境。如果你是在 Google Colab 工作,没必要这么做。关于创建虚拟环境的简单易懂的说明可以在这里找到。

因为我使用的是 Google Colab,所以使用的语法可能与其他环境下使用的略有不同。

这个项目的完整代码可以在这里找到。

自从写了这篇博客之后,这个项目的代码已经被更新了。总体布局保持不变。

安装熊猫

Pandas 是一个用于数据操作的 Python 库。这将有助于导入和表示我们将要分析的数据(在下一节中讨论)。如果你使用 Google Colab,pandas 是预装的,所以你可以忽略这一步。否则,使用 Conda 或 PyPI(无论您喜欢哪个)安装 pandas。您可以在此查看安装过程的所有步骤。

安装 scispaCy

安装 scispaCy 非常简单。它的安装就像其他 Python 包一样。

!pip install -U spacy
!pip install scispacy

选择一个预先训练好的科学模型

安装 scispaCy 之后,接下来需要安装他们的一个预制模型。科学模型有两种风格:核心和 NER。基于存储的词汇数量,核心模型有三种大小(小、中、大),它们识别实体但不对它们进行分类。另一方面,NER 模型对实体进行识别和分类。有 4 种不同的 NER 模型建立在不同的实体类别上。您可能需要尝试不同的模型,以找到最适合您需求的模型。型号和规格的完整列表可在这里找到。一旦你选择了一个模型,使用模型 URL 安装它。

!pip install [https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.2.4/en_core_sci_sm-0.2.4.tar.gz](https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.2.4/en_core_sci_sm-0.2.4.tar.gz)

安装“en_core_sci_sm”模型的例子

导入您的包

一旦您安装了所有的软件包,并且创建了一个虚拟环境,只需导入您刚刚下载的软件包。

import scispacy                                                            import spacy                                                                import en_core_sci_sm                                                       from spacy import displacy                                                 import pandas as pd

您可能会注意到我们还导入了一个额外的包“displacy”。Displacy 不需要执行任何 NER 动作,但它是一个可视化工具,可以帮助我们看到正在发生的事情。

导入数据

对于这个例子,我们使用了来自 CORD-19 的元数据,这是一个关于新冠肺炎研究论文的开放数据库。元数据,以及文章的完整收藏,可以在这里找到。

元数据文件有点挑剔,所以如果该文件不符合您的要求,只需将内容复制到一个新文件中。这应该可以解决您在使用该文件时遇到的任何问题。

为了导入数据,我们使用 pandas read_csv() 函数。

df = pd.read_csv(“content/sample_data/metadata.csv”)

该函数读入文件路径并将数据存储为 DataFrame,这是 Pandas 的主要数据结构。关于 pandas 如何存储和操作数据的更多信息,你可以在这里查看文档

如果您使用的是 Colab,可以将文件拖到“文件”部分,然后右键单击并选择“复制路径”来轻松访问您想要的文件的路径。

选择相关数据

元数据提供了大量关于 CORD-19 中 60,000 多篇论文的有用信息,包括作者、参考号等。然而,出于我们的目的,我们关心的数据是摘要。每篇论文的完整摘要列在“摘要”一栏下。所以,我们的下一步是选择这段文字。我们将使用 DataFrame loc 函数来实现。该函数接收数据帧中单元格的位置,并返回该单元格中的数据。要访问特定的摘要,只需键入所需的特定行和列标题,并存储为字符串变量。

text = meta_df.loc[0, “abstract”]

这将找到位于表的第一行的摘要(记住,在 Python 中,索引从 0 开始)。然后,您可以打印新创建的字符串,以验证您是否拥有所需的数据。它应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

命名实体识别

现在你有了你的文本,你可以进入有趣的部分。多亏了 scispaCy,实体提取相对容易。我们将使用核心模型和 NER 模型来强调两者之间的差异。

核心型号:

nlp = en_core_sci_sm.load()
doc = nlp(text)
displacy_image = displacy,render(doc, jupyter = True, style = ‘ent’)

您的输出应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

NER 模式:

nlp = en_ner_jnlpba_md.load()
doc = nlp(text)
displacy_image = displacy,render(doc, jupyter = True, style = ‘ent’)

在这里,我们使用了一个模型来识别 DNA、细胞类型、RNA、蛋白质、细胞系类型的实体

输出应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

扩展到更大的数据

就这样,你成功地在一个样本文本上使用了 NER!但是,这只是 CORD-19 元数据中超过 60,000 个摘要中的一个。如果我们想在 100 篇摘要中使用 NER 会怎样?1000 呢?他们所有人呢?这个过程,虽然需要更多的技巧,但本质上和以前是一样的。

当你阅读这一部分的时候,我强烈推荐跟随 Google Colab 项目来充分理解我们正在做的事情。

所以,第一步和之前一样。我们需要读入数据。

meta_df = pd. read_csv(“/content/metadata.csv”)

再次使用元数据文件的特定路径

接下来,我们加载我们的模型。对于这个例子,我们将使用所有 4 个 NER 模型,所以如果您还没有安装和导入它们,您将需要安装和导入它们。只需按照前面描述的说明,然后加载它们。

nlp_cr = en_ner_craft_md.load()
nlp_bc = en_ner_bc5cdr_md.load()
nlp_bi = en_ner_bionlp13cg_md.load()
nlp_jn = en_ner_jnlpba_md.load()

接下来,我们想要创建一个空表来存储实体和值对。该表将有 3 列:“doi“”、“*实体”*和“类”。该表将被规范化,以便每个实体/类对的 doi 将在“*doi”*列中,即使该 doi 已经被列出。这样做是为了在任何列中都没有空格,如果您以后想将数据用于其他程序,这将很有帮助。要创建这个表,您需要创建一个包含 3 个列表的字典。

table= {“doi”:[], “Entity”:[], “Class”:[]}

现在事情变得有点复杂了。我们将从遍历整个文件开始。为此,我们使用 pandas index 函数,它给出了值的范围(行数)。然后我们使用 itterrows() 函数迭代整个文件。所以,你的循环应该是这样的。

meta_df.index
for index, row in meta_df.iterrows():

对于循环的每次迭代,我们想要提取相关的抽象和 doi。我们也想忽略任何空洞的摘要。在 Python 中,空单元格存储为 nan,其类型为 float。

text = meta_df.loc[index, “abstract”]
doi = meta_df.loc[index, “doi”]
if type(text) == float:
    continue

continue 语句结束循环的当前迭代,并继续下一次迭代。这允许我们跳过任何带有空白摘要的行。

现在我们有了文本,我们需要使用之前加载的一个模型来提取实体。如果你在 Google Colab 上查看代码,这个步骤被分成了几个独立的方法,但是也可以不使用任何 helper 方法来编写。但是,请注意,最好是一次运行一个模型,尤其是在 Colab 中,读写文件需要相当长的时间。使用 4 个 NER 模型之一的聚合代码应该如下所示:

doc = nlp_bc(text)
ent_bc = {}
for x in doc.ents:
    ent_bc[x.text] = x.label_for key in ent_bc:
    table[“doi”].append(doi)
    table[“Entity”].append(key)
    table[“Class”].append(ent_bc[key])

记住所有这些代码都在最初的 for 循环中

这段代码可能看起来很吓人,但实际上,它与我们已经练习过的非常相似。我们通过一个模型传递文本,但是这次不是使用 displacy 显示结果,而是将它存储在一个字典中。然后,我们遍历字典,将结果以及我们正在查看的文章的相应 doi 添加到我们的表中。我们继续这样做,循环遍历文件中的每一行。一旦表被填充,并且 for 循环已经结束,最后一步是创建一个输出 CSV 文件。感谢熊猫,这很容易。

trans_df = pd.DataFrame(table)
trans_df.to_csv (“Entity.csv”, index=False)

您可以为输出文件选取任何标题,只要它遵循所示的格式。一旦你的代码运行完毕,输出文件就会出现在 Google Colab 的“文件”部分。然后你可以下载文件,欣赏你所有的辛勤工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 bc5cdr 模型的 CSV 输出示例(在 Excel 中打开)

或者,您可以从 Gofile 下载所有 4 个输出 CSV 文件。

进一步探索

有许多方法可以使用我们刚刚收集的数据。我们可以采取的一个方向是使用图形数据库在语义上链接发布。查看这个项目的第二部分,我将带你了解如何创建一个图表并对我们的数据建模。

结论

如果你关注了这篇文章,那么恭喜你!你刚刚在科学文献的科学空间和 NER 的世界里迈出了第一步;然而,还有更多的东西需要探索。仅在 scispaCy 中,就有缩写检测、依存解析、句子检测等方法。我希望您喜欢学习一些关于 scispaCy 的知识,以及如何将它用于生物医学 NLP,并且我希望您继续尝试、探索和学习。

资源:

  1. https://uoa-e search . github . io/e search-cookbook/recipe/2014/11/26/python-virtual-env/
  2. https://github . com/akash-Kaul/Using-scis pacy-for-Named-Entity-Recognition
  3. https://pandas . pydata . org/pandas-docs/stable/getting _ started/install . html
  4. https://allenai.github.io/scispacy/
  5. 【https://www.semanticscholar.org/cord19/download
  6. https://pandas.pydata.org/pandas-docs/stable/index.html

使用 SelectFromModel & SHAP 创建一个更好解释的 XGBClassifier 模型

原文:https://towardsdatascience.com/using-selectfrommodel-to-create-a-better-xgbclassifier-model-ddebdf9b68fe?source=collection_archive---------30-----------------------

如何改进你的模型,并将结果传达给你的非技术团队。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Aral TasherUnsplash 上拍摄

处理零售数据总是很有趣,尤其是与客户的人口统计数据结合在一起的时候。当我在探索星巴克简化的促销、产品组合和顾客数据时,我知道我想用它做什么。这很简单;练习一些编码、数据工程、特征工程和模型设计。

该模型将用于更好地预测未来促销的影响,以及谁将从中受益。然而,我在这里的真正目标是探索*【选择来自模型】函数&【SHAP】*库。

因为我们需要一个分类模型,我们有一些很好的选项可以尝试。我们可以尝试集合方法,或者 KNN,神经网络,或者任何可以完成这项工作的方法。然而,由于数据是高度分类的,并且神经网络计算量大,我们将使用集成方法。此外,将神经网络用于所有事情会阻止我们扩展我们的技能集和对数据的理解。

数据探索和清理

除了客户的收入和性别。三个数据框中的所有字段都没有丢失任何值。例外的两个字段是不可归入的,因为许多值缺失(各 12.79%),并且由于没有提交此类数据的客户也提供了假的出生年份(他们是 118 岁,这不太可能)。由于估算是不可能的,而且我不想输入缺少所有人口统计数据的记录,所以这些记录被从数据框中删除了。

之后,是 ol '常规预处理;更正数据类型,为非二进制分类字段创建虚拟变量,解析字段,并删除不重要的字段。

数据和特征工程

为了利用一些看起来不重要或无用的领域,需要设计新的领域。字段*“time”包含从数据收集开始到一个月之前的小时计数器。我已经创建了字段“一天中的某个小时”“一周中的某天”*。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Isaac SmithUnsplash 上拍摄

出于探索的目的,我还在字段*【值】之外创建了字段【关键字】【值】。然而,它们没有任何用处,因为“价值”中的不同值表示不同的概念(一些是花费的金额,另一些是报价标识符),而“密钥”只是降级的“标签”*。

此外,我还创建了字段*“任期”*来显示每个人注册该应用程序后的天数。

现在,这三个数据框已准备好合并成一个大数据框。

模型设计和改进

我决定对购买的状态进行分类,不管是不是已经兑现。我选择分类的一个原因是,数据不包含要约-赎回交易的支付金额。如果所有交易的价值都是可用的,我们可能会得到一个更好的模型,甚至更好,探索每个报价对销售和收入的影响。

有四个标签要分类;a) 【交易】,当没有报价要查看时进行交易,b) 【报价已接收】,报价已发送,但未被查看,c) 【报价已查看】,发送的报价已被用户查看,但未被兑换,最后,d) 【报价已完成】,用户已兑换报价。

在将数据帧合并成一帧并删除所有不需要的列之后。我已经将数据分为训练和测试特征和标签。我手动这样做是为了确保标注的比例与原始数据框的比例相同。

第一个分类器表现不错;其准确率为 84.23%。然而,只有少数特征变得重要,其余的对模型的结果几乎没有影响。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

初始 XGBClassifier 的特征重要性

如上所示,一些顶级特性是工程变量。由此可见,深入理解数据是多么重要。我没有进一步探索模型的性能,因为数字功能将大幅减少,模型的参数肯定会变得更好。

对模型的偏差结果有一个奇怪的观察。混淆矩阵显示,该模型能够 100%正确地对*“收到的报价”进行分类。然而,它只在 44%的情况下正确地分类了“交易”*。

在将我们的模型传入 “SelectFromModel” 函数,并迭代各种阈值后,我得到了以下模型,性能达到 84.73%的准确率。

SelectFromModel(estimator=XGBClassifier(base_score=0.5,
                                       booster='gbtree',
                                       colsample_bylevel=1,
                                       colsample_bynode=1,
                                       colsample_bytree=1, gamma=0,
                                       learning_rate=0.01, 
                                       max_delta_step=0,
                                       max_depth=3,  
                                       min_child_weight=1,
                                       missing=None,
                                       n_estimators=100,
                                       n_jobs=1, nthread=None,
                                       objective='multi:softprob',
                                       random_state=1, reg_alpha=0,
                                       reg_lambda=1,
                                       scale_pos_weight=1,
                                       seed=None, silent=None, 
                                       subsample=1,
                                       verbosity=1),
                max_features=None, norm_order=1, prefit=True,
                threshold=0.0058939322)

微调和结果解释

由于人口统计不适合作为特征,我保留了之前删除的记录,然后再次运行改进的模型。这导致模型的准确性略微提高了 1.28%(现在为 86.01%)。

更好的是,该模型对*“transaction”的偏见大幅减少,59%的时间正确标记了类别。【报价已完成】【报价已查看】*偏差略有增加。然而,这个模型现在看起来好多了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

微调后的混淆矩阵

接下来,我们应该尽可能地解释结果。这将有助于决策者更好地理解数据、模型和输出,从而做出明智的决策。

我为此使用了*“SHAP”*库(SHapley Additive exPlanations 的简称)。这个库将 ML 模型从黑盒变成了人类可读的图形。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征对标签分类的影响

该图显示了我们选择的每个特征对每个标签的分类的影响。请注意,并非所有功能都对每个标签有影响。

接下来,我们将分别探讨对每个标签的影响,以更好地理解每个特征的值如何影响分类器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征对交易的影响

现在我们看到了每个标签上的每个功能的影响。我们可以用人类能够理解的方式向决策者解释我们的发现和模型。类似于*“随着报价难度的增加,客户更有可能进行常规交易。”更老的*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

功能对已查看产品的影响

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

功能对报价的影响已完成

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

功能对收到的报价的影响

客户更有可能兑现优惠。然而,这并不意味着年轻客户更喜欢不兑现优惠。听起来比好多了“年龄对要约兑现有负面影响。”

请注意,某些特征对某些标签来说比其他标签更重要。如果每个标签上的每个特征的效果被适当地解释,而不是特征的一般意义,这将使行动的计划变得容易得多。

此外,我们可以看到,并非所有类别的功能都很重要。在对通信渠道进行处理后,我们可以看到只有*【移动】类别的【渠道】*特征对分类有一定的影响。

结论

这是数据分析的一个经典案例,其中包括探索、预处理、建模和微调。这可以通过创建一个端到端的管道来自动化整个过程,或者至少是大部分过程来进一步改进。

使用 Selenium 和 deepL 自动翻译 PowerPoint 文件

原文:https://towardsdatascience.com/using-selenium-and-deepl-to-automate-the-translation-of-power-point-files-3c01f81f113?source=collection_archive---------26-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Aaron BurdenUnsplash

曾经想要高效地翻译 PowerPoint 幻灯片吗?了解如何使用 Python 自动完成这一过程!

对自动化的需求

像许多顾问一样,我非常习惯使用 PowerPoint 演示文稿。但是最近,我被要求以一种非常特殊的方式与那些 *打交道。pptx 文件。我没有展示我的工作或任何策略,而是被要求将一打又一打的幻灯片从法语翻译成英语。我的第一个想法和你一模一样:“真无聊…!!"。

是的*,很无聊*!但是你知道吗?事实是,开发人员非常喜欢被分配无聊的工作。这样他们就可以自动操作了!下面是我翻译数百张幻灯片中数万个单词的故事。

在本文中,您将发现如何用 Python 操作 PowerPoint 文件,以及如何从翻译网站提取信息。但是让我们从一个小的基准开始,从为什么开始,然后再到如何

寻找现有的解决方案

紧接着绝望的*“太无聊了…”、和自信的“我会花一天时间给自己造一个神奇的机器人,这将使我接下来 3 天的工作顺利进行”之后,是务实的“我肯定能在网上找到免费的 PowerPoint 翻译器”。*

一个表演工具需要调和两者:

  • 短句和长句的良好翻译水平
  • 不修改原始文件的设计

在用于文档修改的免费在线工具的丛林中,很容易找到来自 *的转换器。pdf 至 **。docx,*来自倍数 。jpgs 到单个。pdf、文本翻译、表格提取、文件压缩等。表现非常好。不幸的是,PowerPoints 是复杂的文档,你可以找到许多不同的对象,它们可以组合在一起。

我轻而易举地找到了提供这种服务的网站,在几张幻灯片上做了一些测试,然后……立刻让自己完全听天由命了。在尝试了不同的翻译器之后,结果相当令人失望:翻译过于近似,并且字体/大小/颜色与源文档相比不时改变。毫无疑问,这可以完成部分工作。但是我仍然需要非常谨慎和耗时地阅读这些文件。冒着忘记明显的误译的风险,这些误译一眼就能看穿我。不会吧。

但愿我已经听同事们谈论过 PowerPoint 模板脚本,并阅读了许多关于这个主题的文章。有几个星期,我想实现一个 selenium 项目,那里有强大的在线翻译器,对网络用户免费。定制工具的想法诞生了。

基准测试和起草工具

堆栈展示

经过一些研究后,我相信下面的堆栈会产生有趣的结果。使用 python-pptx 包与文件进行交互。它允许我们处理演示文稿、幻灯片、形状、表格、段落、分组框等等。这个工具似乎很有前途。对于翻译部分,我会选择由人工智能驱动的翻译机。由于它的 API 不是免费的,Selenium 将非常适合访问网页和自动翻译。

为什么选择 Python-pptx?

Python-pptx 是一个 Python 包,可以通过常用的pip install python-pptx命令行获得。它允许我们以一种非常结构化的方式探索 PowerPoint 文件。首先处理一个Presentation对象,它包含所有高级信息。然后你访问Slides对象,在每张幻灯片中你访问Shapes对象。形状可以是文本框、表格、图表、图像,甚至是一组形状。非常直观。

当你处理一个text_frame实例时,你可以访问文本和字体。看起来完美地满足了我们的需求:翻译文本而不改变其他任何东西!

最重要的是,文档非常全面,写得很好。

为什么是 DeepL?

DeepL 是一个基于卷积神经网络的人工智能翻译器,它是在linguie数据库上训练的。它于 2017 年推出,据报道,很快就在盲测中超越了竞争对手,包括谷歌翻译、微软翻译和脸书。与竞争对手的速度一样,它也将更加精确,更加细致入微。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个强大的基于人工智能的翻译器,在线提供

我不会实现一个完整的基准,但这里有一个 DeepL 和谷歌翻译之间的比较。

英文原文

在过去,蚂蚁和蝉是朋友。他们非常不同。当蚂蚁努力工作的时候,蝉什么也没做。他们整天唱歌跳舞。

谷歌翻译

秋天、四月和十一月。 Ils 培训课程差异。在工作期间,没有香烟。在整个旅程中,他们都在歌唱和跳舞。

深度翻译

家庭旅游、旅游和吸烟。Ellesétain tèRSdifferentes。在这四个月的工作中,没有香烟。在整个旅程中。

对于不懂法语的读者,我们在这里介绍了 Google 和 DeepL 之间的两项重大改进:性别检测(在法语中,蝉和蚂蚁都是阴性词,因此我们用 elles 而不是ils来修饰它们,后者是 elles 的阳性词),以及时间的一致性,即根据事件发生的时间使用正确的变化形式。

这里的例子已经足够了,但是在很少的单词的短句中,翻译也要好得多,并且可以很好地处理停用词。这对 PowerPoint 用例非常重要。我们开始吧,我们将使用 DeepL。

为什么是硒?由于 DeepL 的 API 不是免费的,我们将不得不从它的网络接口使用它。无需争辩,Selenium 是完成这类任务的完美工具。正如他们自己所说:

Selenium 自动化浏览器

要发现 Selenium 的威力,我建议你阅读这篇文章,它详细介绍了这个库,并解释了如何创建 Instagram 机器人。

动手操作

从无到有的工具

正如你可能已经猜到的,这个项目有两个不同的部分,这基本上意味着三个步骤:

  • 构建翻译器
  • 与 PowerPoint 演示文稿互动
  • 放在一起

让我们深入研究并发现解决方案是如何工作的!

构建翻译器

为了记住这个过程,我们要做的是

  • 创建 selenium 驱动程序
  • 打开 deepL 网页
  • 将文本发送到网页的输入文本区域
  • 从翻译文本区域阅读翻译文本
  • 关闭页面和 selenium 驱动程序

直截了当,是吧?

不幸的是,deepL 页面都是用 Javascript 编写的,翻译后的文本不会出现在 HTML 内容中,即使显示在屏幕上也是如此。这是第一个挑战:不可能确定从哪个 Html div(或其他什么)组件中提取文本内容。

希望 Selenium 是一个伟大的工具,deepL 在另一点上使它变得容易:他们为我们提供了一个“复制到剪贴板按钮”。识别之后,只需单击一下就可以将翻译后的文本放入剪贴板(注意剪贴板库已经(安装&)导入到第 3 行。

注意:在文本输入和点击复制按钮之间有一个等待时间:time.sleep(3)。这是由于互联网连接和通过网络的请求。除了翻译过程之外,无论文本有多长,在您的浏览器中收到翻译文本之前都有一个最短的等待时间。

这里有一个句子翻译器。现在,如何从单个句子到一个完整的语料库?第一种解决方案是循环整个过程。但是考虑到3s-translation需要等待,对于更长的语料库来说,它会非常慢。想象一下,一个有 50 张幻灯片的 PowerPoint,包含一个标题和几个文本框,需要几个小时。

但是再一次,DeepL 让我们变得容易了。它允许我们一次翻译不同的段落。因此,我们可以同时发送多个句子,从句子中建立一个语料库。为了实现这一点,我们通过将句子连接成一个长字符串来创建一个更长的文本。为了确保算法不会在我们的句子之间添加任何上下文,我们使用一个连接字符串进行连接。翻译后,连接符字符串被用作拆分符字符串,这样我们就可以逐句得到翻译。

从不同的句子创建单个字符串语料库

太棒了。所以,如果我发送我的全部语料库,我将在几秒钟内得到它的翻译?

还没有。使用 DeepL,对翻译的字符数有限制。让我们发现这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 DeepL 网站的截图

注意:您可以看到“翻译文档”选项。如果你点击它,你就可以上传一个 PowerPoint 文件。不幸的是,文件大小是有限的,并且有一个到高级选项的重定向,这不是免费的。

事实上,如右下角所示,翻译的限制是 5000 个字符。如果有人试图多放一些,页面就会变红,翻译只针对文本第 5000 个字母之前的句子。

这不是一个真正的问题,只要它是一个非常合理的限制,我们可以创建调整后的批量句子。想法是这样的:给定一个巨大的语料库,我们将创建一批句子,这样每一批大约(略少于)5000 个字符。

对于每一批,我们将运行前面的函数。如果我们有一个 200 个句子的语料库,平均 90 个字符(15 个单词,5 个字母/单词+1 个空白/单词),总共 18 000 个单词,它将可能创建 4 批:35000 + 13000。计算并不完全正确,因为由于 joiner 而有额外的字符,但你得到了想法。

调整语料库的大小

注意:随着文本大小的增加,翻译时间也会增加。它不是线性增加的,但是为了翻译 5000 个字符,在将翻译的文本提取到剪贴板之前,等待 20 秒而不是 3 秒是合理的。时间也取决于翻译语言。例如,如果你想从英语翻译成法语或西班牙语,它很快。翻译成中文要长得多。我做了一些测试,在那种情况下等待的时间更多在 45s 左右。关于翻译的准确性,我相信 DeepL,但我无法验证!

太好了!现在一切都好吗?我能把我最喜欢的书从葡萄牙语翻译成荷兰语吗?

*再次,有一些新的挑战。运行前面的脚本可以很好地处理少量文本。事实上,selenium 的send_keys功能模拟了一个人在键盘上一个接一个地按键。它做得更快,但他做到了。这意味着 deepL 一个接一个地接收近 5000 个字符。**网站检测到这是一个机器人行为。*然后反机器人插件将翻译过程替换为一种不稳定的行为:改变 DeepL 网站的页面,打开弹出窗口,或者试图在你的计算机上下载翻译。非常糟糕。

我没有做很多测试来了解速度限制是什么,因为对于大型语料库来说,打字慢会花很多时间。

另一个非常直观的方法是更好地模仿人类与网页互动的方式。确实如此。如果让你翻译十句话,你会把这十句话从头开始写到文本框里吗?或者你会从你的原始文件中使用一个基本的复制/粘贴*?就是它:复制/粘贴现在是我们最好的盟友。*

使用 Selenium 的复制/粘贴功能

警告 : selenium 复制/粘贴的方式似乎取决于你使用的操作系统和导航器。我来解释一下:当你模拟使用你的键盘时,在 MacOS 中你会实现 COMMAND + V,而在 Windows 上,你会实现 CONTROL + V。

在 MacOS + Chrome 上,我发现它可以很好地与:element.send_keys(Keys.SHIFTT, Keys.INSERT)

好了,我们快好了。这很好,但是还有另一个问题需要解决:当我们添加这么多文本时,翻译框变得更大:比你的屏幕还要大。

起初,这似乎不会改变什么,但是我们使用的“复制到剪贴板按钮”位于页面的底部。而现在已经出屏了。那么我们仍然可以在 Html 语法中检测到它,但是 selenium 不能模拟对它的点击。

下一步:滚动页面。Selenium 有一个内置的方法来做到这一点。

使用 Selenium 进行滚动,以便能够点击选定的按钮

我们到了!我们的翻译器现在可以工作了,可以翻译我们需要的所有文本了。免费准确的翻译。太好了!

一个好的实践是将 selenium scrappers 实现为类。基于我们在这里看到的,你可以在这里找到完整的seleniumDeepL类,这使得翻译更加容易。注意,它从同一个 GitHub repo 中的可用的类继承了一些基本的 selenium 属性。

三句话语料库中的翻译示例

*corpus_fr = [
    "Bonjour j’aimerais traduire tous ces documents",
    "Mais je ne suis pas sur d’avoir un niveau d’anglais suffisant",
    "Et surtout ! Je suis Data Scientist, pas traducteur."
]*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 句话翻译的外壳日志

seleniumDeepL对象提供了那篇文章中没有讨论的有趣的附加特性,例如:

  • 选择翻译的目标语言。我们可以使用 DeepL 中所有可用的语言。截至今日,已有:英语( en )、法语( fr )、西班牙语( sp )、德语( de )、荷兰语( nl )、葡萄牙语( pt )、波兰语( pl 【T24)、汉语(zh日语(* ja 【T30)DeepL 会自动检测源语言,要选择目标语言,您需要将www.deepl.com/en/translatorURL 中的en更改为所需的语言。*
  • 通过只翻译语料库或当前批次中尚未看到的句子,加快处理速度。
  • 从/向 json 文件导入和导出翻译{句子 1:翻译 1,句子 2:翻译 2,…}

总而言之,我们已经看到了如何:

  • 以字符串列表的形式加载数据,使用连接字符串将它们以 5k 字母为一批连接起来,并在一个较小的语料库中转换这些批次,以加快翻译速度。
  • 通过将它们添加到剪贴板来翻译每个批处理,并从剪贴板粘贴到 DeepL 翻译框中。我们等待几秒钟的翻译,找到,滚动并点击“复制到我的剪贴板按钮”。最后一步是使用 joiner 字符串将翻译后的数据分割成原始大小。

PowerPoint 探索

这一部分更短更简单:给定一个 PowerPoint 文件,我们希望提取它的所有文本,将其提供给我们的翻译人员,并用他们的翻译替换所有文本。

提取文本

我们现在想要获取演示文稿中的所有文本。接下来阅读所有这些需要有条不紊地浏览文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PowerPoint 屏幕截图—全文(1/3)

每个演示文稿都以相同的方式构建:

  • 演示文稿包含幻灯片
  • 幻灯片包含形状
  • 形状可能包含文本

python-pptx 有对应的内置对象。这迅速导致了这个功能:

用 python-pptx 从 PowerPoint 中提取文本

我们现在有演示文稿的所有文本吗?全部吗?真的吗?我们去看看。

为了确定我们正在收集的文本,我不是只收集文本,而是用空字符串替换它们,然后以空版本保存演示文稿。打开它,我们将快速检查是否所有的文本都已被选中(和删除),并推断我们的算法是否运行良好。

让我们分两步来做:

  1. texts.append(paragraph.text)替换为paragraph.text = ‘’
  2. 在我们的get_texts_from_file 函数的末尾使用prs.save(output_file)

这是上一张图片的演示结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PowerPoint 屏幕截图—空文本(2/3)

这看起来几乎不错,但你可能会在第三张幻灯片上看到,我们还有一个文本。

事实上,在代码中,我们检查了所有将has_text_frame属性设置为True的形状。

但是所有的形状并不完全具有相同的类型。具体来说,我们要处理两种特殊形状:**

  • 组合形状 : 您可能知道,在 PowerPoint 中编辑包含大量信息的文件时,您可能会选择几个形状并将它们组合在一起。如果你仔细观察第一张截图,你会发现在的右边部分有两个矩形(一个用于图片,一个用于文本),而在的左边部分只有一个。这是因为 Selenium 徽标和 Selenium 文本组合在一起。在 python-pptx 中,这些元素被称为 GroupShapes ,事实上,GroupShapes 没有text_frames属性,因此has_text_frame属性默认设置为False。这就是为什么我们的算法没有隐藏该文本。希望 GroupShapes 有一个Shapes属性,它包含组合形状的单独形状。
  • ***表格:*上例中没有表格,但问题是一样的。有些形状,除了has_text_frame,形状还有一个has_table属性。而当has_table is True我们可以访问对象。表格没有文本值,但是Table包含cell,单元格有text_frame对象。问题解决了。

当这两种类型的形状都考虑在内时,结果要令人满意得多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PowerPoint 屏幕截图—空文本(3/3)

注意:还有一些其他形状,但它们主要是图形,并不意味着文本,所以我们不需要为它们费心。但是如果你必须处理 PowerPoint 文件,你肯定应该仔细看看写得很好的 python-pptx 文档;) !

现在我们确信我们已经阅读了演示文稿的所有文本,让我们进入下一步。

翻译

我们有一个句子列表,它看起来像一个为我们的翻译格式化的语料库。这个把它转化成批量语料库,在 deepL 网站上做一些迭代,返回一个字典。

我们可以再次遍历我们的 PowerPoint 并使用翻译词典替换文本。关键词是原文,价值是译文。

插入文本

这是最后一步:重新插入文本。这和我们以前做的没什么不同。我们必须检查文件的每一个text_frame,而不是设置空值,我们将设置翻译。

注意:为了简化代码,我们在 l.15 上迭代通过all_presentation_text_frames。这是为了说明的目的:处理表格和分组形状的真实过程并不那么简单。ppt 操作的完整代码可从这里获得。

最后一次更新是必要的。这里我们替换了text_frame.paragraph.text值。事实上,它封装了比文本更多的信息。要理解这一点,您必须知道每个形状都有自己的参数(颜色、大小、位置、格式和字体)。这些是给定形状和 PowerPoint 模板的默认值。但有时我们可以手动更改这些信息。例如,如果文本太长,人们可能会决定将默认大小点从 16 改为 14,以便它正确地适应形状。在这种特定情况下,信息存储在text_frame.paragraph.text.runs中。这样我们就不能轻易地覆盖文本。

不幸的是,这是一个关键点:我们必须保持与输入文件完全相同的结构!

当然,有一个字体属性给出了关于字体的信息。但是这个不能存放和更换。因此,我们必须在幻灯片/形状/文本 _ 框架/段落/运行分析中更深入地修改文本,而不修改字体,并最终获得我们期望的结果。

我想说,尽管这是项目的终极挑战,但也是最难克服的。它需要理解runs的概念,并仔细阅读 python-pptx 文档。因为它变得非常技术性,我把这个函数放在这里,以防你对它感兴趣,但是如果你不明白它是如何工作的,不要担心。

替换 text_frame 文本而不影响字体属性

所以我们来了!我们漫长旅程的终点!还有最后一件事要做:从头开始运行所有这些!

放在一起

我们已经到了最后一步:使用我们构建的翻译器进行 PowerPoint 转换。我不会在这上面花太多时间,因为它只是我们到目前为止所看到的所有内容的组合,还做了一些重构。

翻译 PowerPoint 文件

结论

我们已经看到了如何创建一个很好的工具来自动翻译 PowerPoint 文件,而不需要修改它们的外观,并且非常自信。尽管如此,请记住没有什么是完美的。因此,它不会阻止重新讲授输出,以检测最终的错误。事实上,DeepL 是一个非常强大的工具,但有时如果我们没有给它足够的上下文信息,它可能会产生近似的翻译。

该项目的一个关键成果是翻译部分,毫无疑问,它非常有用,对于所有涉及翻译的用例都是可重用的。

这也让我发现了 python-pptx 库,这是一个有趣而伟大的 PowerPoint 版本工具。

下一步,我们可以想象构建一个基本的 web 界面,包括上传区、目标语言下拉列表和翻译下载按钮。像烧瓶破折号这样的框架可以完成这项工作。

最后,我希望你喜欢阅读那个故事/教程,就像我喜欢这个项目一样。意识到这一点比花几天时间翻译幻灯片有趣得多。请注意,所有代码都可以在我的 Github 上的这个库中找到。如果你想使用它,请随意,不要犹豫让一个明星参与项目。当然,欢迎任何备注或建议:)!

我要感谢我的同事和朋友 Ismail Mebsout ,他刚刚发表了一堆关于深度学习基础的文章,并激励我发表了这第一篇帖子!

使用语义 ML 构建语言驱动的应用程序

原文:https://towardsdatascience.com/using-semantic-ml-to-build-apps-powered-by-language-7be2a4e7e689?source=collection_archive---------55-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用语义 ML 构建语言驱动的应用

作者戴尔·马科维茨 — 7 分钟阅读

大多数人更擅长用语言描述世界,而不是用代码描述世界(嗯……大多数人)。那么,如果机器学习可以帮助弥合这两者之间的差距,那就太好了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用神经网络预测能源需求

蔡佳顺李、胡图、以及奎月咏家 — 24 分钟读完

本文总结了我们用来赢得由新加坡南洋理工大学和 ai4impact 联合举办的深度学习数据大会的方法。如有任何疑问,请通过 LinkedIn 联系我们。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

德里克·汤姆森在 Unsplash 上拍摄的照片

用数据理解幸福动态(第一部分)

通过 Lina Faik — 12 分钟阅读

在这些特殊时期,封锁给我们许多人留下了很多思考的时间。想想过去和未来。想想我们的生活方式和我们的成就。但最重要的是,想想我们对这个世界的贡献。

用通用句子编码分析不同音乐类型的歌词

原文:https://towardsdatascience.com/using-sentence-embeddings-to-explore-the-similarities-and-differences-in-song-lyrics-1820ac713f00?source=collection_archive---------24-----------------------

应用谷歌的通用句子编码器和主成分分析来识别不同音乐流派的异同

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

UnsplashAnnie Theby 拍摄的照片

TLDR:使用谷歌的通用句子编码器/ PCA 和 Plotly 在 3d 空间中表示歌词。点击这里玩:【https://plotly.com/~kitsamho/238/

我对音乐的持久热爱始于 1992 年,在我 12 岁的圣诞节,溺爱我的父母掏钱给我买了一台 Alba HiFi。

皮带传动转盘?检查!
双卡带播放器?检查!
低音增强的图形均衡器?当然啦!

从那以后,我一直在听各种各样的音乐。

我现在快 40 岁了,在这 28 年的音乐生涯中,我加深了与音乐的关系。我是一名吉他手,一名 DJ,一名舞曲制作人。音乐以多种快乐的方式打断了我的生活——我想对你们许多人来说也是如此。

因此,尽管我觉得我(相当)有资格谈论音乐流派,但我发现很难定义它们和/或区分它们。

流派不断演变,流派是主观的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 IJ 波特温Unsplash 上拍摄

划分流派的界限是模糊的,随着时间的推移,这种界限更加模糊。滚石乐队和甲壳虫乐队最初被一些人指责为魔鬼的作品,但如今却像平板家具一样成为主流。

*** 杀戮者 在位至尊为恶魔的作品仅供参考。\m/

流派被操纵

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash猎人赛跑的照片

当商业利益盖过真实性时(几乎总是令人难过),就可以制造“类型”。这些人为的标签被唱片公司用来锁定客户群以获得商业优势,有时以某种方式反映出社会中更深层次的缺陷。

那么我们有什么方法可以衡量流派呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

威廉·沃比在 Unsplash 上拍摄的照片

很明显,流派分类可能是主观的、有争议的,甚至可能是徒劳的——毕竟,好音乐就是好音乐,对吗?

然而,我想说至少有两种有效的方法来区分不同的流派:一首歌的音乐性和歌词。

这音乐听起来像什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Blaz ErzeticUnsplash 上拍摄的照片

是不是…

  • 直播还是测序?(摇滚 vs. Techno?)
  • 大声还是安静?(Dubstep vs. Chillout?)
  • 不协和还是有旋律?(痛击金属 vs 灵魂?)
  • 可预见还是不可预见?(流行与爵士?)

音乐在说什么,它是如何被表达的?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由维达尔·诺德里-马西森Unsplash 上拍摄

  • 歌词是否基于某种情绪(如悲伤、快乐、愤怒)?
  • 歌词是在说话题(爱情、失去、战争、不公、压迫、死亡)吗?

对于这个项目,我想特别关注歌曲作者在歌曲中使用的歌词和语言。

我们都觉得抒情的内容因流派而异。但是有没有一种方法可以定量地测量这个呢?

项目目标

不同流派的歌词之间存在差异,我们可以量化和衡量这一点!

挑战和方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由帕特里克·帕金斯Unsplash 拍摄

我们从哪里获得数据?

  • 我们将从Musixmatch.com搜集歌词,这是一个免费网站,拥有大量准确的歌词内容

什么样的方法/度量将允许我们以直观的方式量化抒情多样性?

  • 我们将使用来自谷歌通用句子编码器的高维向量来表示歌词
  • 我们将应用主成分分析(PCA) 将这些高维表示降低到 n=1,2,3 维

我们如何以一种有意义的方式将它可视化?

  • 我们将使用 Plotly 并建立一个简单的情节和更复杂的 2d 和 3d 散点图的组合,以查看歌词的相似之处和不同之处

我的 GitHub 这里 有所有笔记本和全部原始数据

获取数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://www.musixmatch.com/

为了准备这个项目,我发现很难在网上找到准确的歌词来源。歌曲要么不完整,要么可用的音量不够全面。

Musixmatch.com 似乎是少数几个遗址之一:

  1. 有很多内容。
  2. 相当准确。

所以让我们把它作为我们的数据源。

Musixmatch 有一个开发者 API,我们可以用它来获取歌词数据,但他们只允许你一天打 2k 个电话,而且你只能玩每首歌 30%的歌词。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料来源:Giphy

让我们通过结合使用请求HTML 解析来解决这个问题。这是一个“浏览器外”的过程,因此我们可以轻松实现多线程来加快进程。这意味着我们可以在更短的时间内获得更多的内容。

我在下面写了一个 Python 类,它包含了为艺术家提取歌词内容的所有方法。

Musixmatch.com 的 Python scraper 类

运行铲运机

你所需要做的就是用一个 Musixmatch 艺术家 URL 和一个流派标签来实例化这个类…

scraper = MusixmatchScraper('[https://www.musixmatch.com/artist/Jack-Johnson'](https://www.musixmatch.com/artist/Jack-Johnson'),'folk')

…然后调用self.Run()方法启动刮刀。

告诫 —如果你想刮很多歌词,在可能的情况下,你应该轮换你的 IP 地址。如果你向 Musixmatch.com 发出太多请求,你的 IP 地址将会被屏蔽,尽管只是暂时的。我发现在这种情况发生之前,你可以删除 c.250 歌曲。

刮多个艺术家

MusixmatchScraper()的编码方式允许你抓取一个艺术家的内容。如果你想得到多个艺术家,你可以像这样创建一个循环:

抓取多位艺术家的歌词

该类返回一个熊猫数据帧,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

示例数据帧输出

太好了,现在我们有数据了。让我们研究一下数据,看看我们有什么。

探索性数据分析

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由卢克·切瑟Unsplash 上拍摄

在我们开始看句子嵌入之前,让我们用 Plotly 来激发一些简单的情节。

熊猫& Plotly

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料来源:www.plotly.com

比起其他任何东西,我通常更喜欢视觉化的情节。它们看起来更好,具有交互性,你可以使用 Plotly Chart Studio 轻松管理和分享它们。唯一的缺点是它需要相当多的代码(和许多嵌套的字典!)从 Plotly 中获得有用的东西,当你只想快速浏览数据时,这很烦人。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料来源:Giphy

我推荐的一件事是将 Plotly 更新到至少 4.8 ,因为熊猫现在可以使用 Plotly 作为后端绘图的库,而不是“审美受损”的 Matplotlib。

在下面的代码块中——我们可以通过将.plot.bar()添加到 DataFrame 对象中,从 Pandas DataFrame 中生成一个简单的条形图。

简单如 123,abc!

pd.DataFrame([1,2,3],['a','b','c']).plot.bar()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Plotly 后端输出示例

如果你想的话,你可以调整你的图形的外观和感觉,通过使用你通常用在 Plotly Graph Objects 上的相同参数,这样就有了额外的熟悉的灵活性。

好了,回到这个项目…

我们有哪些流派和艺术家?

我决定从一系列流派中挑选歌词,有些流派比其他流派更极端,以便看看我们是否能看到差异,但我也选择了非常重叠的流派,看看是否有共性。

让我们看看每个流派有多少首歌曲。

#plot genres
fig_genre = pd.DataFrame(df.genre.value_counts()).plot.bar(template='ggplot2')#title parameters
title_param = dict(text='<b>Count of Genre</b><br></b>', 
                        font=dict(size=20))#update layout
fig_genre.update_layout(title=title_param,
                  width=1000,
                  height=500,        
                  xaxis = dict(title='Genre'),
                  yaxis = dict(title='Count'))#change the colour
fig_genre.update_traces(marker_color='rgb(148, 103, 189)')#show plot
fig_genre.show()

每一种类型都有相当好的表现——至少足以进行有意义的比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里的原剧情:https://chart-studio.plotly.com/~kitsamho/240/#/

按流派划分的艺术家呢?

让我们带着一些视觉化的东西进城,创建一个流派和艺术家的旭日图。如果想和剧情互动,原剧情的链接在脚注里。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里互动剧情:【https://plotly.com/~kitsamho/254/

我有一系列的乐队和艺术家,我觉得他们代表了这些流派。你可能不同意我的观点。没关系,流派的定义可能会有争议。

歌词长度有区别吗?

让我们按体裁来探讨歌词长度。

#get lyric frequencies for each song
df['lyric_count'] = df['lyrics'].map(lambda x: len(x.split()))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此处原创剧情:【https://chart-studio.plotly.com/~kitsamho/244】T4

Hip-hop 是一个非常抒情的流派——许多描述 hip-hop 歌词数量的关键描述性指标都不同于所有其他流派。

当我们分析那些歌词的内容时,看看那些歌词的内容是否也不同,这将是很有趣的。这很方便地把我带到了 EDA 的下一部分——词性(PoS)分析。

词性分析

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由布雷特·乔丹Unsplash 上拍摄

所以下一件有趣的事情是理解这些歌词的内容。为了做到这一点,我将使用空间模型将歌词内容分类到其相关的词类中,即分类歌词中的哪些词是名词、动词、形容词等等。这将使我们对不同体裁的抒情内容的差异有更多的了解,并可能暗示相似和不同之处。

import spacy#load spacy model
nlp = spacy.load('en_core_web_sm')def pos(string,pos):

    """Returns any token that qualifies as a specific part of speech"""

    doc = nlp(string) #fit model

    return ' '.join(list(set([i.text for i in doc if i.pos_ == pos]))) #return any tokens that qualify

让我们在一个循环中调用上面的函数,并获得包含所有有用词类的新列。

#get nouns
pos_of_interest = ['NOUNS','VERBS','ADJ','ADV]#loop through each PoS
for pos in pos_of_interest:
      df[pos] = df.lyrics.map(lambda x: pos(x,pos))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PoS 的示例数据帧输出

最常见的单词

下面是一个计算字符串中最常见标记的函数。我们可以用它来分析一首歌中最常见的词,包括我们刚刚制作的词表。

计算字符串中最常见单词的函数

#call the function on one gram
musixmatch_mostcommon(df.lyrics,token=1).head(10)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

示例数据帧输出

更有用的是找到一种方法,在所有的体裁和不同的词类中使用这种功能。一种有效的方法是使用树形图可视化。Plotly 对此有一个很好的模板,所以我构建了一个函数来完成这项工作。

树形图可视化

在 Plotly 中创建树形图可视化的函数

让我们调用该函数并查看输出

noun_treemap = musixmatch_genremap(df,pos='nouns')

警告——其中一些歌词很露骨

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里互动剧情:【https://plotly.com/~kitsamho/246/

如果你使用的是台式机,我强烈建议你访问树状图脚注中的链接(如上),以便与之互动。

通用句子编码

现在我们开始真正有趣的部分——使用向量来代表我们的歌词。然后,我们可以使用各种技术来显示哪些向量/歌词是相似的或不同的。

什么是向量表示?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

单词的向量表示对于自然语言处理来说是一个重大的进步。试图“理解”语言的早期方法通常涉及计数单词(例如单词袋模型或加权模型/ TFIDF 方法)。这些方法的局限性在于它们没能抓住语言的语境。毕竟,*‘孩子弄坏滑板’这句话和‘滑板弄坏孩子’的意思很不一样……*尽管有相同的类型和字数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:Giphy——孩子玩滑板

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:Giphy——滑板断了孩子

Tomas Mikolov 等人的 Word2vec 是游戏规则的改变者,因为单词不再基本上表示为计数,而是表示为高维向量。这些向量,或者说嵌入,是通过在文本语料库上训练一个简单的神经网络而产生的。这些单词嵌入表示一个单词与相邻单词的关系,因此也表示其上下文。因此,单词“walking”和“walked”的向量将比单词“swimming”和“swam”更相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://developers . Google . com/machine-learning/crash-course/embeddings/translating-to-a-lower dimension-space

如果你想了解这方面的更多信息,我建议你阅读原始白皮书我与 ASOS 评论在 TrustPilot 上做的一个项目

谷歌的通用句子编码器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://tfhub.dev/google/universal-sentence-encoder/ 4

在这个项目中,我们将使用谷歌的通用句子编码器,这是一种经过数百万(可能数十亿)人训练的最先进的编码器?)的文档。

它就像 word2vec,但使用了类固醇。

通用语句编码器将文本编码成高维向量,这些向量可用于文本分类、语义相似性、聚类和其他自然语言任务。

该模型针对大于单词长度的文本进行训练和优化,例如句子、短语或短段落。它在各种数据源和各种任务上接受训练,目的是动态适应各种各样的自然语言理解任务。

来源:【https://tfhub.dev/google/universal-sentence-encoder/】T44

如果你想了解更多关于这个模型的信息,我强烈建议你阅读关于 TensorFlow hub 的文档,因为它涵盖了更多的细节。

在我们的歌词数据上使用谷歌通用句子编码器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://tfhub.dev/google/universal-sentence-encoder/4

让我们使用 Tensorflow Hub 加载模型…

#get universal sentence encoder
USE = hub.load("[https://tfhub.dev/google/universal-sentence-encoder/4](https://tfhub.dev/google/universal-sentence-encoder/4)")

让我们写一个简短的函数,它可以使用这个模型获得任何字符串输入的高维向量。

def getUSEEmbed(_string,USE = USE):

    """Function takes a string argument and returns its high dimensional vector from USE"""

    return np.array(USE([_string])[0])

让我们得到一个简单句子的向量…

example = getUSEEmbed('Hello how are you?')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

高维向量表示“你好吗?”

如你所见,一个简单的句子现在已经被编码成一个形状为(512,)的高维向量

评估向量之间的相似性和差异

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

弗兰克·麦肯纳在 Unsplash 上拍摄的照片

这个项目的基石是想办法找到歌词的异同。当我们将歌词编码成向量表示时,我们需要使用一些技术来让我们找到向量的相似性和差异性

我们可以通过以下方式做到这一点:

  1. 使用余弦相似度
  2. 维度缩减和可视化(使用类似主成分分析的东西)

余弦相似性

通常,当我们拥有连续的低维数据时,我们会使用类似欧几里德距离的东西来衡量相似性/差异。我们将把这个距离度量用于类似 KNN 分类器的东西,或者甚至在聚类维数减少的向量时,例如在 PCA 之后。

然而,因为我们来自句子编码器的向量具有非常高的维度,那么使用余弦相似度是一个比欧几里德距离更好的接近度度量,至少开始是这样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

余弦相似度将相似度计算为两个向量的归一化点积/来源:【https://en.wikipedia.org/wiki/Cosine_similarity

余弦相似度越接近 1,意味着两个向量之间的差异最小(输入字符串相似),而余弦相似度越接近 0,意味着两个向量非常不同(输入字符串不同)

让我给你看一个有四个句子的例子。

其中两个是关于天气的…

  • “今天天气会很暖和”
  • “今天将是一年中阳光最充足的一天”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由清水久美子Unsplash 上拍摄

另外两个是关于早餐

  • “我喜欢我的鸡蛋单面煎”
  • “早餐是我最喜欢的一餐”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由威廉·冈克尔Unsplash 上拍摄

我特别选择了一些例子,在这些例子中,单词“sunny”/“sunniest”被用作隐喻和形容词。让我们看看编码是否能捕捉到这种差异。

#some example sentences
example_sentences = ["The weather is going to be really warm today",

                     "Today is going to be the sunniest day of the year",

                     "I like my eggs sunny side up",

                     "Breakfast is my favourite meal"]#get embeddings for each example sentence
embed = [getUSEEmbed(i) for i in example_sentences]#set up a dictionary where each sentece is a key and its value is its 512 vector embedding
dic_ = dict(zip(example_sentences,embed))#let's find all the unique pairwise sentence combinations
combo = [list(i) for i in itertools.combinations(example_sentences, 2)]

现在我们需要一个函数来计算相似度。

def cosineSimilarity(vec_x,vec_y):

    """Function returns pairwise cosine similarity of two vector arguments"""

    return cosine_similarity([vec_x],[vec_y])[0][0]

让我们制作一个数据框架,映射每个独特句子对的余弦相似度。

#empty list for data
cs = []#lop through each unique sentence pairing
for i in range(len(combo)):

    #get cosine similarity for each
    cs_ = cosineSimilarity(dic_[combo[i][0]],dic_[combo[i][1]])

    #append data to list
    cs.append((combo[i][0],combo[i][1],cs_))#construct DataFrame
cs_df = pd.DataFrame(cs,columns['sent_1','sent_2','cosine_similarity']).\
                    sort_values(by='cosine_similarity',ascending=False)

让我们检查数据帧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

比较四个句子的余弦相似度

这太酷了。最相似的句子有更多的相似向量(余弦相似度 0.41 / 0.51)。即使使用一个作为隐喻和形容词的词有歧义,编码也是足够不同的。让我们看看是否可以将这一点应用到我们的歌词中。

获取每首歌曲的嵌入

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

塞萨尔·马丁内斯·阿吉拉尔Unsplash 拍摄的照片

首先,我们需要得到每首歌的向量。

#get USE embeddings for each song
df_embed = pd.DataFrame([getUSEEmbed(df.lyrics[i]) for i in range(df.shape[0])],\
                        index=[df.song[i] for i in range(df.shape[0])])

df_embed.head(5)检查数据帧

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每首歌曲的向量—高维度/列

让我们使用另一种数据简化技术— 主成分分析,来减少这些嵌入的维度,同时保留尽可能多的方差。

我构建了一个全面的函数来完成这项工作。

PCA 函数将维数减少到 n=1,2,3 个分量

让我们调用这个函数并获得三个新的数据帧。

pc_1 = musixmatch_PCA(df,df_embed,n_components=1)
pc_2 = musixmatch_PCA(df,df_embed,n_components=2)
pc_3 = musixmatch_PCA(df,df_embed,n_components=3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

示例数据帧输出

我们来做一些分组,探讨一下哪些艺人的歌词彼此最相似。

正如我们所看到的——即使只有一个组成部分,不同流派的艺术家也倾向于聚集在一起。死亡金属、重金属和摇滚彼此略有不同,但与流行音乐和灵魂乐有很大不同。这是有道理的。

如果你熟悉这些乐队,当你向下滚动时,你会对流派如何演变有强烈的感觉,我们可以在主成分 1 的变化中看到这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此处原创剧情:https://chart-studio.plotly.com/~kitsamho/248

让我们看看同样的分析,但是是按流派分组的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此处原创剧情:https://chart-studio.plotly.com/~kitsamho/248

这个平均视图证实了我们上面的怀疑。

让我们做一个更复杂的可视化,使用散点图来显示这些数据。

我们可以在二维空间(PC1、PC2)中观察,也可以在三维空间(PC1、PC2、PC3)中观察

下面的函数将上面的一些函数与一些更复杂的 Plotly 函数结合起来,生成二维(PC1 / PC2)或三维(PC1 / PC2 / PC3)散点图

让我们调用函数,看看情节是什么样的。同样,我强烈建议你点击页脚处的剧情链接,如果你想和所有类型互动,以及它们在剧情中的位置。

scatPlot_2 = musixmatch_scatplot(df,df_embed,n_components=2)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

互动剧情点击这里:https://plotly.com/~kitsamho/236/

我们也可以创建一个类似的图,但是利用 PCA 的 3 个维度。

scatPlot_3 = musixmatch_scatplot(df,df_embed,n_components=3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

互动剧情点击这里:https://plotly.com/~kitsamho/238/

结论

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

亚历克斯Unsplash 上的照片

我们已经表明,不同音乐流派的歌词确实有所不同,尽管有趣的是,当我们以逐步的方式从一种流派转移到另一种流派时,歌词内容之间有着非常明显的关系。我认为下面的形象化很清楚地将这一点带到了生活中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不同流派的歌词并不完全相互排斥——除非你比较两个极端。也就是说,死亡金属和灵魂乐之间有很大的区别,但区别流行音乐和流行摇滚的方式却很少。

这些发现反映了音乐的真实本质,因为音乐类型是不固定的,对于每一种类型,都可能有一种“邻近的”类型在抒情内容上是相似的。

毕竟很多 r&b/soul 的粉丝也会喜欢 pop……但也许不是朋克和/或金属?

应用程序

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由JESHOOTS.COMUnsplash 上拍摄

我们已经表明,通用句子编码/迁移学习是一种非常强大和非常简单的技术,可以用来找出不同流派歌词的差异和相似之处。

它在其他问题上的应用有很多:

  • 歌曲/歌词推荐系统 —使用相似性度量来查找具有相似歌词的歌曲
  • 通过查找相似的文档(如电子邮件、客户反馈/评论)对大量文本进行分段
  • 识别抄袭
  • 用作分类任务的特征

感谢您的阅读,如果您想进一步交流,请联系我们!我把笔记本保存在 GitHub 上,所有代码都准备好了,可以在其他项目中使用。如果有,请告诉我,我很想看。

萨姆(男子名)

参考和链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值