如何训练你的连体神经网络
实践教程
训练时看不到的类的简单工作方式
由 Sereja Ris 在 Unsplash 上拍摄的照片
当你第一次开始机器学习时,从偏移中可以清楚地看到,精确而稳健的模型训练需要大量的数据。虽然这是事实,但当为了需要自定义数据集的目的而训练模型时,您通常需要在模型看到的数据级别上做出妥协。
这是我自己的情况;在 conservation tech 工作时,我们部署到一个区域的任何模型都是使用前几年调查中收集的数据构建的,这些数据在某些情况下可能是稀疏的(当然远不及 ImageNet [1]等基准数据集的水平)。更糟糕的是,在保护技术领域工作意味着使用开放的数据集。因为我们处理的动物是自由漫游的,所以不能保证我们用于模型训练的数据集将包含模型将在野外看到的所有事物的示例。
当试图使用传统的机器学习方法部署模型时,这导致了一场艰难的战斗。如果每门课都需要成千上万个例子,并且每年随着课程的变化都需要重新训练模型,那么建立一个守恒模型是没有用的。但是这个问题不仅限于保护,基准测试之外的许多领域都有类似的数据量和变化率问题。
在这篇文章中,我将讨论一种被称为连体神经网络的模型。希望在阅读之后,您将更好地理解这种架构不仅可以在保护方面有所帮助,而且可以在数据量有限且类别变化速度快的任何领域中有所帮助。
先决条件
在开始之前,你可能应该对机器学习有所了解,特别是卷积神经网络。如果你不知道,我发现 Sumit Saha 的帖子 是卷积神经网络的综合指南 ELI5 方式 是代替该领域正规教育的一个很好的起点。你应该先看看这个。
您还应该熟悉 Python、Keras 和 TensorFlow。在本文中,我们将学习代码示例,因为我发现这样做比自由格式文本本身更容易理解。本指南中的所有代码都是在 TensorFlow 1.14 中编写的,但没有理由认为这些代码不能在新版本中工作(可能需要一些修改),或者移植到其他深度学习框架,如 PyTorch。
什么是连体神经网络?
简而言之,连体神经网络是包含至少两个平行的、相同的卷积神经网络的任何模型结构。从现在开始我们称这些为 SNNs 和 CNN。这种并行 CNN 架构允许模型学习相似度,可以用来代替直接分类。snn 主要用于图像数据,如面部识别,尽管它们在这个领域之外也有用途。例如,赛仑·乌古罗格鲁在 NeurIPS 2020 上做了一个关于网飞如何利用社交网络根据电影元数据生成用户推荐的精彩演讲。在本指南中,我们将重点介绍图像数据。
构成 SNN 一部分的每个并行 CNN 被设计成产生输入的嵌入或缩减维度的表示。例如,如果我们指定嵌入大小为 10,我们可以输入大小为宽度 * 高度 * 通道的高维图像,并接收大小为 10 的浮点值向量作为输出,该向量直接表示图像。
然后,这些嵌入可用于优化排名损失,并在测试时用于生成相似性得分。理论上,并行 CNN 可以采取任何形式。然而,重要的一点是它们必须完全相同;它们必须共享相同的架构,共享相同的初始和更新权重,并具有相同的超参数。这种一致性允许模型比较它接收的输入,通常每个 CNN 分支一个。来自 Dey 等人【2】的图章纸对此提供了一个极好的可视化,可以在下面看到。
图章建筑。图片来自 Dey 等人。
SigNet 的目标是确定给定的签名是真实的还是伪造的。这可以通过使用两个平行的 CNN 来实现,这两个 CNN 在真实和伪造的签名对上进行训练。每个签名通过 SNN 的一个分支输入,该分支为图像生成一个 d- 维嵌入。正是这些嵌入被用来优化损失函数,而不是图像本身。更近版本的 SNNs 将很可能利用三分支甚至四分支,分别包含三个或四个平行的 CNN。
SNNs 有什么意义?
既然我们了解了 SNN 的构成,我们就可以强调它们的价值了。使用生成的 d- 维嵌入,我们可以创建一些 d- 维多维空间,允许绘制嵌入来创建集群。然后,可以使用主成分分析(PCA)将这个多维空间投影到二维空间进行绘图。
100 个训练时期后嵌入超空间的图,使用 PCA 投影到 2 维。使用基于笔记本的代码生成的图像。
该图显示了 MNIST 测试数据子集的嵌入位置[3]。这里,已经训练了一个模型来生成 10 个独特类别的图像嵌入(0 到 9 之间的手写数字的图像)。请注意,即使只经过 100 个训练时期,该模型也开始为同一类别的图像生成类似的嵌入。这可以从上图中相同颜色的点的聚类中看出——图中的一些聚类相互叠加,这是由于通过 PCA 降低到二维。在这种情况下,其他的观想,比如 t-SNE 图,或者降低到更高的维度,会有所帮助。
正是这种嵌入聚类使得 SNNs 成为如此强大的工具。如果我们突然决定要向数据中添加另一个类,那么就没有必要重新训练模型。新的类嵌入应该以这样一种方式生成,即当绘制到多维空间中时,它们远离现有的聚类,但是当它们被添加时,与新类的其他示例聚集在一起。通过使用这种嵌入的相似性,我们可以开始使用很少的数据为可见和不可见的类产生可能的分类。
模特培训
之前,我提到过 SNNs 由至少两个并行 CNN 分支组成,但现代实现往往依赖于更多分支。SNN 分店的数量对你的模特训练有很大的影响。您不仅需要确保您的数据以这样一种方式输入到 SNN,即每个分支都接收到训练样本,而且您选择的损失函数还必须考虑分支的数量。不管选择了多少个分支,损失函数的类型将可能保持一致。
排序损失,也称为对比损失,旨在预测投影到超空间时模型输入之间的相对距离。这与旨在预测一些类别标签集的更传统的损失相比。排序损失在 SNNs 中起着重要的作用,尽管它们对于诸如自然语言处理的其他任务也是有用的。有许多不同类型的排名损失,但它们都以相同的方式工作。
假设我们有两个输入,我们想知道它们有多相似。使用排名损失,我们将执行以下步骤:
- 从输入中提取特征。
- 将提取的特征嵌入到一个 d- 维的多维空间中。
- 计算嵌入之间的距离(例如使用欧几里德距离)以用作相似性的度量。
这里需要注意的是,我们通常并不特别关心嵌入的值,只关心它们之间的距离。以前面显示的嵌入图为例,注意所有点都位于 x 轴上大约-1.5,2.0 和 y 轴上大约-2.0,2.0 之间。嵌入在这个范围内的模型本身没有好坏之分,重要的是这些点在它们各自的类中聚集。
三重排序损失
用于 SNNs 的更常见的排序损失类型之一是三元组排序损失。你会经常看到 snn 使用这种称为三联体网络的损失函数,就好像它们是自己的东西一样(事实上这就是霍夫尔 e t al 对它们的定义。在最初构思它们的论文中,但实际上它们只是一个有三个分支的 SNN。因为三重态损失现在是如此普遍,这是我们将在本文后面使用的损失函数,所以理解它的工作原理很重要。
这个例子展示了三元组排序损失是如何将相同类别的嵌入图像拉近,而将不同类别的嵌入图像拉远的。图片作者。
顾名思义,三元组排序损失需要三个输入,我们称之为三元组。三元组中的每个数据点都有自己的工作。锚是某个 C 类的数据,它定义了三元组将在哪个类上训练模型。正是 c 类的另一个例子。负是某个类的数据点,它不是c。在训练时间,我们的每个三元组组件都被馈送到它自己的 CNN 分支进行嵌入。这些嵌入被传递给三元组损失函数,其定义为:
其中 D(A,P) 为锚点与正片的嵌入距离, D(A,N) 为锚点与负片的嵌入距离。我们还定义了一些边距——一个常用的初始值是 0.2,这是 FaceNet [5]中使用的边距。
该函数的目的是最小化锚和正片之间的距离,同时最大化锚和负片之间的距离。要更深入地了解三胞胎排名的损失,我建议这篇来自劳尔·戈麦斯的精彩文章。
半坚硬三重开采
由于三胞胎成分的重要性,当务之急是我们的 SNN 只提供三胞胎,这将使它能够学习。更具体地说,我们希望提供否定,以便我们的三元组允许模型学习,但不要太难以至于学习需要太长时间。
一个简单的方法是通过一个被称为半硬三重开采的过程。为此,我们首先定义三个三元组类别:
- 易三元组是那些其中 D(A,P) + margin < D(A,N) ,从而 L = 0 的。
- 硬三元组是那些 D(A,N) < D(A,P)的。
- 半硬三联体是那些 D(A,P) < D(A,N) < D(A,P) + margin 的。
目标是找到尽可能多的半硬三胞胎。这些三元组具有正损失,但是正嵌入距离比负嵌入距离更接近锚嵌入。这允许快速训练,但是对于模型来说,在训练期间实际学习某些东西仍然是足够困难的。
有两种方法可以找到这些半硬的三元组。在离线挖掘中,整个数据集在训练前被转换成三元组。在在线挖掘中,成批的数据被输入,随机生成三个一组。
作为一般的经验法则,在线挖掘应该尽可能地执行,因为它允许更快的训练,因为它能够随着训练的进行不断地更新我们的半硬三元组的阈值定义。这可以用数据扩充来补充,数据扩充也可以以在线方式进行。
推理时使用 SNNs
既然我们已经了解了 snn 是如何被训练的,我们接下来需要了解如何在推理时使用它们。在训练期间,我们使用 SNN 的所有分支,而推理可以使用单个 CNN 分支来执行。
在推理时,未知类别的输入图像由 CNN 分支处理并嵌入其特征。这种嵌入然后被绘制到超空间上,并与其他集群进行比较。这为我们提供了相似性分数的列表,或者未知类别的图像和所有现有聚类之间的相对距离。我们用来比较输入图像的聚类被称为支持集。让我们看一个例子来帮助理解这一点。
根据 Vetrova 等人[6]的数据,为测试图像蛾寻找最可能的家族类别。图像使用基于本笔记本的代码生成。
上面的图是我为了确定蛾的科学家族而创建的 SNN 的输出。数据集中的每张图片改编自 Vetrova 等人的【6】,被贴上了四个科学家族名称中的一个,或者被贴上了“幼虫”的标签,总共给出了五个类别。为了易于可视化(尽管事后看来不一定易于理解),每个已知标记的类别都显示在支持集中,如上面图的中间所示,使用来自每个类别的随机示例图像。在图的左边是一个测试图像;这是一张 SNN 没有看到的蛾的照片,它现在的任务是确定科学家族。
首先,SNN 使用在训练期间学习的嵌入函数嵌入测试图像。接下来,将该嵌入与支持集嵌入进行比较,支持集嵌入为测试图像提供了最可能的蛾类。在图的右边,我们可以看到支持集中的第一个图像已经被再次打印。
上面用于生成绘图的代码被告知首先显示测试图像族的相应示例(绘图代码知道正确的类,但 SNN 不知道)。因为第一个支持集图像再次显示在图的右侧,这告诉我们,SNN 在确定测试图像蛾的科学家族方面是正确的!如果这个图对您来说有点混乱,不要担心,因为我们稍后将在不同的、更简单的数据上创建相同的图。
如果嵌入被放置在超空间的一个新的区域中,并且超过了某个预定义的类距离阈值,则该代码可以被进一步扩展以警告用户。这可能表明 SNN 第一次看到了一个新的蛾类家族。
我们从哪里开始测量?
为了确定测试图像和支持集中的类之间的距离,我们需要每个类的测量位置。乍一看,从每个支持集类中随机选择一个嵌入似乎没问题;毕竟,如果所有的嵌入都完美地聚集在一起,那么我们使用哪一个并不重要?
虽然这个假设肯定成立如果我们的类嵌入是完美的集群,在一个真实的世界系统中不会是这种情况。让我们看看下面的玩具例子。
一个嵌入空间的例子,有两个类,十字和正方形,还有一个未定类的嵌入用三角形表示。图片作者。
在这个例子中,我们有两个类嵌入空间,一个用于十字,一个用于正方形。所有的方形类嵌入都聚集在图的右侧,但是交叉类有一个嵌入没有与左上方的其他嵌入聚集在一起。这个错误的十字被嵌入到方块通常聚集的空间中。在右上角还绘制了一个三角形,这是当前的测试图像,嵌入到空间中,但尚未根据其与其他聚类的距离分配到某个类别。
为了确定三角形实际上应该是十字形还是正方形,我们为每个类随机选择一个要测量的嵌入;错误的十字和左下角的方块被选中(都被圈起来)。如果我们比较这些嵌入的距离,选择的十字是最接近的,因此三角形将被标记为十字。
然而,从整体上来看,很明显,三角形可能应该被标记为正方形,而十字是一个异常值。通过选择随机嵌入来度量,我们冒着离群值扭曲距离度量的风险,从而扭曲最终结果。
这可以通过使用原型来解决,这是一个优雅且易于理解的问题解决方案。原型本质上是每个类的一般化嵌入,减少了离群值对距离测量的影响。这些可以用多种方法计算,但是简单的技术,比如取中间值,效果很好。让我们更新玩具的例子…
与之前相同的嵌入空间,但是包含了原型。图片作者。
现在,每个类都被赋予了一个靠近其类中心的原型(例如,Pₓ是交叉类的原型)。如果我们在测量相似性时选择了原型,我们的三角形就被正确地标记为正方形。这个简单的解决方案可以大大减少计算相似性时离群值的影响。
确定如何计算原型是很困难的,使用中位数等解决方案可能会在某些数据集上失效。例如,如果我们的所有交叉类示例围绕原点形成半径为 1 的圆,而方形类示例形成半径为 2 的圆,则原型现在都将在原点形成,从而产生相等的距离测量值。我们需要找到另一种方法来计算数据集的原型。
建立一个连体神经网络
既然我们已经掌握了 SNNs 的基本理论,以及为什么它们是一个重要的工具,那么让我们来看看如何构建一个 SNNs。如前所述,我们将为此使用 Python、Keras 和 TensorFlow 1.14,尽管实际上没有什么可以阻止这些代码被转换用于另一个框架,如 PyTorch 我使用 TensorFlow 是出于个人偏好,而不是因为它更适合制作 snn。为了一致性和便于训练,我们还将坚持使用 MNIST 作为我们的数据集。
这里的代码是基于各种来源的,我会在我们进行的过程中进行链接,但底层的构造是基于 Amit Yadav 的 Coursera,中描述的方法,它本身是基于 FaceNet [5]。
如果你喜欢完整的代码而不是片段,这可以从我的 Github 获得。
步骤 1:导入包
首先,我们需要导入所需的包。如需在虚拟机上运行该代码所使用的软件包版本的完整列表,请参见此处的。我用 Python 3.6.7 测试了这段代码。
步骤 2:导入数据
接下来,我们需要为 SNN 导入一个数据集。如前所述,我们将使用 MNIST,它可以通过 TensorFlow 的mnist.load_data()
加载。
数据加载后,将被重新整形和展平。这使得将数据读入 SNN 更加容易。
注意,我们这里只有高度和宽度,因为 MNIST 是灰度的,所以只有一个颜色通道。如果我们有一个包含多个颜色通道的数据集,我们需要修改我们的代码,例如使用x_train_w_h_c
来代替。
第三步:创建三胞胎
现在我们需要创造我们的 MNIST 三胞胎。为此需要两种方法。
第一个是create_batch()
,通过随机选择两个类标签生成三元组,一个用于锚/正,一个用于负,然后为每个随机选择一个类示例。
第二个,create_hard_batch()
,使用create_batch()
创建一批随机的三元组,并使用当前的 SNN 嵌入它们。这允许我们确定该批中的哪些三胞胎是半硬的;如果是,我们保留其中的num_hard
,用其他随机的三元组填充其余的批次。通过填充随机三元组,我们允许开始训练,并确保我们的批次大小一致。
步骤 4:定义 SNN
SNN 由两部分定义。首先,我们必须创建嵌入模型。该模型接收一个输入图像并生成一个维维嵌入。我们在这里创建一个非常浅的嵌入模型,但是可以创建更复杂的模型。
接下来,我们创建一个模型,该模型接收一个三元组,将其顺序传递给嵌入模型进行嵌入,然后将结果嵌入传递给三元组损失函数。
步骤 5:定义三重损失函数
为了让 SNN 使用三元组进行训练,我们需要定义三元组损失函数。这反映了前面所示的三重态损失函数方程。
步骤 6:定义数据生成器
为了将我们的三元组传递到网络,我们需要创建一个数据生成器函数。TensorFlow 需要一个x
和y
,但是我们不需要一个y
值,所以我们传递一个填充符。
步骤 7:为培训和评估做准备
现在,我们已经定义了 SNN 的基础知识,我们可以设置培训模型了。首先,我们定义超参数。接下来,我们创建并编译模型。我指定这是使用 CPU 执行的,但是根据您的设置,这可能不是必需的。
一旦模型被编译,我们存储测试图像嵌入的子集。这个模型还没有被训练,所以这给了我们一个很好的基线来显示嵌入是如何在训练过程中变化的。通过 PCA 嵌入可视化是基于阿德里安农的这本笔记本。
可以在我们的 SNN 上进行进一步的评估。这一步中使用的代码受 Eric Craeymeersch 的 One Shot Learning、Siamese Networks 以及 Keras 的 Triplet Loss 的影响很大。
我们来看看未经过训练的模特的评价。从图中,我们可以看到我们的模型无法区分相似和不相似的图像。这在第三个图中最为明显,突出显示了测试图像及其最可能的类别,它们的分数之间几乎没有差异。
使用基于本笔记本的代码生成的图像。
现在我们已经编译了模型,我们也可以生成示例随机和半硬三元组。这段代码基于 Ruochi Zang 的博客文章。
这会产生以下结果:
使用基于这篇博文的代码生成的图像。
我们的示例随机三元组包含锚和类别 4 的正,以及类别 6 的负。我们的半硬三联体包含一个锚和一个 8 类的阳离子,和一个 6 类的阴离子,但是请注意它们在组成上是多么的相似。
步骤 8:记录我们模型训练的输出
在训练我们的模型之前,让我们设置一些日志记录和自定义回调,如果我们需要在以后的某个日期再回来的话,可以帮助我们。Tensorboard logging callback 改编自 erenon 的有用的堆栈溢出答案,而基于验证损失的最佳模型的保存改编自另一个 OverLordGoldDragon 的堆栈溢出答案。
第九步:训练 SNN
现在我们所有的设置已经完成,是时候开始训练了!我首先从选择可用的 GPU 总数开始,并对它们进行并行模型训练。如果您没有访问多个 GPU 的权限,您可能需要对此进行修改。
注意,在运行model.fit()
时,我们提供训练和测试数据生成器,而不是直接提供训练和测试数据。这允许在线三元组挖掘发生。
步骤 10:评估训练好的模型
一旦模型训练完毕,我们就可以评估它并比较它的嵌入。首先,我们加载训练好的模型。我通过重新加载保存的日志文件来实现这一点,但是如果您只是在一个笔记本中作为一个封闭的系统运行这一切,那么一旦模型被训练,就没有必要重新加载。
一旦加载了模型,我们执行与未训练模型相同的 PCA 分解,以可视化嵌入是如何变化的。
在上述代码块的末尾,我们再次运行evaluate()
,这产生了下图:
使用基于本笔记本的代码生成的图像。
请注意第一个图现在如何显示 AUC 为 0.985,以及我们类别之间的距离增加。有趣的是,当查看测试图像及其最可能的类别时,我们可以看到,对于第二和第三测试图像,已经正确地实现了相应的类别(例如,以类别 0 的第二测试图像为例,我们可以看到所有支持集类别的最低分数也在类别 0),然而,查看第一测试图像,支持集类别的所有分数都非常接近,这表明训练的模型难以对该图像进行分类。
为了确认我们的模型已经正确训练,并且现在正在形成类簇,让我们绘制我们先前存储的 PCA 分解嵌入。
该代码产生以下输出:
使用基于本本的代码生成的图像。
左图显示了训练前的嵌入位置,使用 PCA 将其分解为二维以进行可视化,每种颜色代表一个不同的类别,如图例所示。请注意嵌入是如何混在一起的,没有清晰的聚类结构,这是有意义的,因为模型还没有学会将类分离出来。这与右图形成对比,右图显示了由经过训练的 SNN 嵌入的相同数据点。我们可以在地块的外围看到清晰的集群,但是中间看起来还是有点乱。我们的图表明,该模型已经很好地学习了对例如类别 1 的嵌入图像进行聚类(左下方的聚类),但是仍然与类别 5 的嵌入图像进行斗争,类别 5 的嵌入图像仍然主要位于中心。这一点得到了我们之前的图的支持,图中显示了模型在努力确定 5 类测试图像的最可能匹配。
量化我们的模型表现有多好将是一件好事。这可以通过利用我们之前讨论过的原型,使用 n 向准确度得分来实现。在 n 向精度中,val_steps
个随机选择的测试图像与大小为 n. 的支持集进行比较。当 n 与下面代码中的类总数num_classes
相同时,这提供了模型精度的指示。MNIST 有 10 个等级,给出 10 个方向的精确度。
当我们运行上面的代码时,SNN 实现了 97.4% 的 10 向准确率,这是一个值得称赞的分数。由于测试图像选择的随机性,如果您愿意,可以在这里进行交叉验证。
最后,让我们看看如何生成一个支持集图像,类似于上一个 moths 示例中显示的图像,只是这次是使用 MNIST 生成的。同样,我们将使用 10 类支持集。
这会产生以下情节:
使用基于本笔记本的代码生成的图像。
如果本文前面讨论的蛾的例子令人困惑,希望使用 MNIST 的相同情节更加清晰。代码随机选择了一个 2 类测试图像进行分类,并将其与支持集中所有其他类的原型进行比较。同样,绘图代码知道测试图像属于类别 2,因此首先显示支持集 2。在右侧,再次显示了相同的支持集 2,表明 SNN 已经正确地为测试图像确定了最可能的类别 2,这应该在大约 97.4%的时间内为其他测试图像完成!
结论
在本文中,我们已经了解了什么是连体神经网络,如何训练它们,以及如何在推理时利用它们。尽管我们通过使用 MNIST 使用了一个玩具示例,但我希望能够清楚地看到,当处理开放式数据集时,SNNs 的功能有多强大,在数据集创建时,您可能没有所有可用的类,以及模型将如何处理新的训练时未看到的类。
我希望我已经为您提供了理论知识和实际应用的良好平衡,我要感谢我自始至终提到的所有人提供了开源代码和堆栈溢出答案。没有这篇文章,事实上我自己在保护技术方面的工作也不可能完成。
当我刚开始写作时,我担心没有足够的内容值得去写。现在一切都结束了,我意识到我错了!希望如果你已经做到这一步(而不是跳到最后),这篇文章已经教会了你一些东西,如果是这样,请让我在 Twitter 或 LinkedIn 上知道。
参考
[1]邓军,董,魏,苏,李,李,李,,李,2009 年 6 月.Imagenet:一个大规模分层图像数据库。在 2009 年 IEEE 计算机视觉和模式识别会议(第 248–255 页)。IEEE。
[2] Dey,s .,Dutta,a .,Toledo,J.I .,Ghosh,S.K .,Lladós,j .和 Pal,u .,2017 年。Signet:用于独立于书写者的离线签名验证的卷积暹罗网络。 arXiv 预印本 arXiv:1707.02131 。
[3] LeCun,y .,Bottou,l .,Bengio,y .和 Haffner,p .,1998 年。基于梯度的学习在文档识别中的应用。IEEE 会议录, 86 (11),第 2278–2324 页。
[4]霍弗,e .和艾伦,n .,2015 年 10 月。使用三元组网络的深度度量学习。在基于相似性的模式识别国际研讨会(第 84–92 页)。斯普林格,查姆。
[5]施罗夫、弗洛里安、德米特里·卡列尼琴科和詹姆斯·菲尔宾。Facenet:人脸识别和聚类的统一嵌入。在IEEE 计算机视觉和模式识别会议记录中,第 815–823 页。2015.
[6]维特罗娃,v .,政变,s .,弗兰克,e .和克里,M.J .,2018,11 月。隐藏特征:细粒度多类和单类图像分类的特征转移实验。在 2018 新西兰图像与视觉计算国际会议(IVCNZ) (第 1–6 页)。IEEE。
如何将从维基百科提取的数据转换成 Python 中的地图
数据可视化
一个现成的代码,可以通过 Selenium、GeoPy 和 leav 在从维基百科提取的条目列表上创建一个地图
作者图片
在本教程中,我描述了一个从维基百科中提取地理条目的策略,这些条目被组织成列表,然后显示在地理地图上。我利用了以下 Python 库:
selenium
,这是一个 Python 库,用于从任何网站提取数据。关于如何使用selenium
的更多细节,你可以阅读我以前的文章,标题是用 Python Selenium 从嵌套的 HTML 页面抓取数据geopy
,这是一个 Python 库,作为最著名的地理编码服务的客户端。更多细节可以在 Eunjoo Byeon 的这篇有趣的文章中找到,标题为geo py 简介:在 Python 中使用您的纬度&经度数据。folium
,这是一个用于地理数据可视化的 Python 库。更多详情,可以阅读Dario rade CII的这篇有趣的文章,题为如何在几分钟内用 Python 和 Folium 制作出惊艳的互动地图。
例如,我利用了 5 个维基百科页面,与意大利犹太人社区相关:
所有被考虑的维基百科页面都包含一个条目列表,每个条目代表一个地理实体,即一个意大利城市。因此,我们的想法是用从维基百科中提取的所有地点构建一个地理地图。该过程分为三个步骤:
- 数据析取
- 数据清理
- 数据丰富
- 数据可视化
1 数据提取
所有被考虑的维基百科页面中的所有位置都被表示为无序列表的项目符号。因此,它们可以很容易地通过一个公共过程提取出来,通过selenium
库来实现。为了让你的代码工作,你应该为你的浏览器安装正确的selenium
驱动程序,如本视频中的所述。
现在,我已经准备好编写代码了。
首先,我导入驱动程序:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
然后,我定义了一个名为extract_list
的函数,它接收维基百科页面的 URL 作为输入,还接收用于从该页面提取数据的 XPath 表达式。该函数提取与该 XPath 关联的所有文本,按行拆分提取的文本,并返回项目列表作为结果:
def **extract_list**(url, xpath):
options = Options()
options.add_argument("--headless")
options.add_argument("--lang=it");
driver = webdriver.Chrome(options=options) driver.get(url)
table = [] # get the list of terms
words = driver.find_element_by_xpath(xpath).text
table.extend(words.split('\n'))
driver.close()
return table
现在,我可以为每个被考虑的维基百科页面调用该函数,为此我定义了一个列表:
pages = ['Comunit%C3%A0_ebraiche_italiane', 'Cimiteri_ebraici_in_Italia', 'Musei_ebraici_in_Italia','Ghetti_ebraici_in_Italia','Sinagoghe_in_Italia']
然后,我在创建的页面列表上构建一个循环,并调用extract_list
函数。我还将提取的表格转换成一个pandas
数据帧,并将每个提取的条目与一个类别相关联,对应于所考虑的页面(有一些风格上的变化):
import pandas as pddf_dict = {}
xpath = '//*[[@id](http://twitter.com/id)="mw-content-text"]'
table = {}
base_url = '[https://it.wikipedia.org/wiki/'](https://it.wikipedia.org/wiki/')**for page in pages**:
name = page.replace('_', ' ').title().replace('%C3%A0', 'à')
print(name)
url = base_url + page table[page] = extract_list(url,xpath)
df_dict[page] = pd.DataFrame(table[page], columns=['value'])
df_dict[page]['category'] = name
最后,我通过连接前面构建的数据帧来构建数据帧:
df = pd.DataFrame(df_dict[pages[0]])
for i in range(1,len(pages)):
df = pd.concat([df, df_dict[pages[i]]])
作者图片
提取的数据包含许多错误,需要纠正。但是,我可以将第一个原始数据集存储为 CSV 文件:
df.to_csv('data/raw_data.csv')
费尔南多·雷耶斯在 Unsplash 上拍摄的照片
2 数据清理
从电子社区页面中提取的地点可以进一步分为两类:活跃社区和不再活跃社区。查看保存的 CSV 文件,可以轻松提取这些信息。指数低于 83 的地区是指活跃社区,其他地区是指不再活跃的社区。
我定义了一个函数来提取这些信息。请注意,仅当考虑的类别为 Comunitàebra ICA Italiana(意大利犹太社区)时,此信息才有用:
df = pd.read_csv('data/raw_data.csv')
index_na = 83def **is_active**(x, index_na):
if x < index_na:
return True
return False
我在数据帧中创建了一个新字段,指定一个社区是否活动:
df['is_active'] = df['Unnamed: 0'].apply(**lambda x**: is_active(x, index_na))
作者图片
现在我需要清理value
字段,以便提取位置。该操作分两步完成:
- 删除不包含地点的记录
- 确定文本中的分隔符以提取准确的位置。
2.1 删除不包含地点的记录
看数据,对应于地点的记录很容易识别,因为它们包含一些特殊的关键字。因此,我定义了一个单词包,它只能用于选择地点:
bag_words = ['Comunità ebraica di', '(Provinc', '(Region', ' Provinc', 'ex circondario', 'Cimitero ebraico di', 'Museo ebraico di', 'Ghetto di', 'Sinagoga di', 'Cimitero israelitico di', 'Cimitero monumentale ebraico di']
现在,我定义一个函数来检查记录是否是一个位置:
def **is_locality**(x):
for bag in bag_words:
if bag in x:
return True
return False
我利用已定义的函数来构建数据帧的新列:
df['is_locality'] = df['value'].**apply**(lambda x : is_locality(x))
最后,我只选择具有is_locality
属性True
的记录:
df = **df[df['is_locality'] == True]**
df.reset_index(inplace = True)
作者图片
2.2 识别文本中的分隔符以提取准确的位置
查看记录,特别是在value
列,每个地点的名称在两个偏移量之间标识:(start,end)。起始偏移量可以是 0,也可以等于以下单词包的长度:
**start_bag** = ['Comunità ebraica di','Sinagoga di', 'Cimitero ebraico di','Sinagoghe del Ghetto di','. Getto di','Ghetto di','Cimitero monumentale ebraico di','Cimitero israelitico di', 'Museo ebraico di']
然后我定义一个函数,它提取起始偏移量:
def **get_start_index**(x):
start_index = 0
for bag in start_bag:
if bag in x:
return len(bag)
return start_index
关于结束偏移量,我定义了一个停止字符包,可以用来标识停止偏移量:
**stop_bag** = ['oratorio', '[', ',', 'aperta', 'viale', 'presso', '-', 'di rito','(']
然后,我定义一个函数,来确定止损点偏移量的最小指数:
def **get_min_index**(x):
min_index = len(x)
for stop in stop_bag:
try:
curr_index = x.index(stop)
if curr_index < min_index:
min_index = curr_index
except ValueError:
continue
return min_index
以及提取位置的函数:
def **get_locality**(x):
if 'Fiuggi' in x:
return 'Anticoli'
if x == 'Cimitero ebraico di viale Ippolito Nievo a Livorno (dismesso)':
return 'Livorno'
if x == 'Sinagoga di via dei Ramaglianti (Firenze), scomparsa':
return 'Firenze'
start_index = get_start_index(x)
stop_index = get_stop_index(x)
return x[start_index:stop_index].strip()
前一项职能还考虑了三种特殊情况(Fiuggi、Cimitero ebraico di viale Ippolito Nievo a Livorno(dismesso)和 Sinagoga di via Ramaglianti(费伦泽)、scomparsa),这些情况不属于一般情况。
现在,我在数据帧中创建了一个新列,其中包含每个地区的名称:
df['locality'] = df['value'].**apply**(lambda x: get_locality(x))
最后,我将结果导出为 CSV 文件:
df.**to_csv**('data/data_locality.csv')
安妮·斯普拉特在 Unsplash 上的照片
3 数据丰富
为了将提取的地点表示到地图中,我必须提取它们的地理坐标。这可以通过geopy
库来完成,它不是一个地理编码服务,而是一个面向外部地理编码服务的接口。
在本教程中,我利用了Nominatim
服务,并定义了一个提取坐标的函数:
from geopy.geocoders import Nominatimdef **get_coordinates**(city_list):
geolocator = Nominatim(user_agent="location script")
dicto = {}
for city in city_list:
try:
location = geolocator.geocode(city, country_codes='it')
except:
raise Exception("There was a problem with the getCoordinates function")
coordinate_values = (location.longitude, location.latitude)
dicto[city] = coordinate_values
return dicto
为了使地理编码服务更加精确,我将 country_code 设置为 Italy,因此该服务只在意大利境内。该函数返回一个字典,其中包含每个地区的经度和纬度。
city_coords_dict = **get_coordinates**(df['locality'].values)
我定义了一个中间函数,它只返回纬度或经度,给定一个位置:
def **get_coords**(x, city_coords_dict, coord = 0):
coords = city_coords_dict[x]
return coords[coord]
我利用它向我的数据帧添加了两个新列:
df['longitude'] = df['locality'].**apply**(lambda x : get_coords(x, city_coords_dict))
df['latitude'] = df['locality'].**apply**(lambda x : get_coords(x, city_coords_dict, coord = 1))
我将结果导出为 CSV 文件,以避免多次执行地理编码:
df.to_csv('data/geo_data.csv')
4 地图上的数据可视化
提取的地点可以显示在地图上。我利用folium
库来构建地图。
首先,我将维基百科的页面名称转换成人类可读的类别:
categories = []
for page in pages:
category = page.replace('_', ' ').title().replace('%C3%A0', 'à')
categories.append(category)
categories
然后,我构建基本地图,聚焦于意大利,从缩放级别等于 6 开始:
import foliummy_map = folium.Map(tiles='cartodb positron',location=[41.8719, 12.5674],zoom_start=6)
至于地图布局,我选择的是cartodb positron
地图。其他地图布局可以在官方folium
文档中找到。
然后,我定义一个函数,为数据帧中的每个位置添加一个标记:
def **add_markers_to_the_map**(the_map, df, icon, category, color): group = folium.FeatureGroup(name=category).add_to(the_map) for i in range(0, df.shape[0]):
popup_text = df.iloc[i]['value']
city = df.iloc[i]['locality']
long = df.iloc[i]['longitude']
lat = df.iloc[i]['latitude']
popup = folium.Popup(popup_text, autopan='False', parse_html=True)
marker = folium.Marker(location=[lat, long],
popup=popup,
icon = folium.Icon(icon_size=(25, 25), color=color, icon=icon, prefix='fa'))
group.add_child(marker)
return the_map
对于每个类别,我通过前面函数中的FeatureGroup()
类定义了一个新层,一个图标和一种颜色。然后,我为每个类别调用函数:
colors = ['green', 'blue', 'orange', 'brown', 'pink']
color = 0for category in categories:
df_selected = df[df['category'] == category] if category == 'Comunità Ebraiche Italiane':
add_markers_to_the_map(my_map, df_selected[df['is_active'] == True], 'flag', category + ' Attive', 'green') add_markers_to_the_map(my_map, df_selected[df['is_active'] == False], 'flag', category + ' Non più Attive', 'red') else:
add_markers_to_the_map(my_map, df_selected, 'flag', category, colors[color]) color = color + 1
在前面的函数中,以意大利电子社区为例,我创建了两个层,分别用于活跃社区和不再活跃社区。
为了使图层可选,我在地图上添加了一个LayerControl()
:
folium.LayerControl().add_to(my_map)
最后,我将地图导出为 html 格式:
my_map.save('mappa.html')
作者图片
摘要
在本教程中,我描述了一种从维基百科页面中提取地点的策略,通过地理编码服务丰富这些地点,最后将它们表示到地理地图中。
对于这篇文章,我要感谢 Alberta Odamea Anim-Ayeko ,他写了一篇精彩的文章,题为用 Geopy 和 leavy制作酷炫的地图,这启发了我做这篇教程:)
还有你,你用哪些库来实现 Python 中的地图?给我留言吧!我很乐意听听你的意见!
如果你已经走了这么远来阅读,对我来说今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。
你愿意支持我的研究吗?
你可以每月订阅几美元,并解锁无限的文章。
对于那些选择支持我的人(不仅仅是他们)来说,额外的奖励是一个在 leav 中实现鼠标悬停/鼠标释放工具提示的提示。
由于 leav 不支持 mouseover/mouseout,我可以直接修改 HTML 文件来支持它:
import re
import fileinputwith open("mappa.html") as inf:
txt = inf.read()#Find all the markers names given by folium
markers = re.findall(r'\bmarker_\w+', txt)
markers = list(set(markers))for marker in markers:
for linenum,line in enumerate( fileinput.FileInput("mappa.html",inplace=1) ):
pattern = marker + ".bindPopup"
pattern2 = marker + ".on('mouseover', function (e) {this.openPopup();});"
pattern3 = marker + ".on('mouseout', function (e) {this.closePopup();});"if pattern in line:
print(line.rstrip())
print(pattern2)
print(pattern3)
else:
print(line.rstrip())
离开前最后说一句:你可以从我的 Github 库:)下载本教程的完整代码
相关文章
参考
https://fontawesome.com/v5.15/icons/flag?style=regular https://stackoverflow.com/questions/41095716/hover-in-popup-in-folium https://stackoverflow.com/questions/55344513/add-menu-bar-on-folium-map-to-select-or-deselect-particular-object-marker https://stackoverflow.com/questions/51486454/convert-geopandas-shapely-polygon-to-geojson
从社会公正的角度看如何用 NLP 创建标签
那么,互联网是一种人工制品,既是正式教育过程的延伸,也是“非正式文化”,因此它是一种“主体性的发挥”。这一想法提供了另一个有利的角度,可以理解媒体中的代表性(和虚假陈述)是权力关系的一种表达方式——Safiya Umoja Noble(压迫的算法:搜索引擎如何强化种族主义,2018 年)
屏幕另一边的人工智能对谦逊声音的压制正在扩大。我最近遇到一个小企业主。她的商业吸引力减少了,因为她的网站不再符合最近更新的搜索引擎优化算法。她的问题的解决方案比用于故障排除的标准技术更复杂。与谷歌自然语言或“搜索引擎”算法合作的最佳方式是什么?人类可以“学习人工智能来设计他们的方式来提高谷歌搜索的排名吗?
谷歌使用复杂的语料库和单词包算法来绘制现有网站,每秒钟可以理解 40,000 次搜索。让少数民族、残疾人、退伍军人和女性拥有的企业等不太为人所知的声音发出来的方法是,让这些社区拥有一个能够理解并向 SEO 算法提供微调参数(词)的人工智能。有一种方法可以借鉴 Google NLP 算法,优化并动态更新自报能力。在本文结束时,您将会实现以下目标:
- 将句子转换成有意义的二元模型和三元模型。
- 轻松添加和更改数据框和数据类型。
- 对公开报道的利基数据应用 PMI、单词包、n-grams 和非结构化数据清理,以生成标签。
- 文本摘要、模型偏差和改进后端数据集的方法。
我们会从这里学习如何处理事情-
到这里-
让我们直接进入解决方案-
照片由Christian WiedLet ’ s sonUnsplash
数据集
纽约州在州属企业数据库中维护Disabled/Women/MBbusinessEE。审计官办公室托管主数据库,帝国审计官根据具体情况授予企业认证,并将其纳入法律登记处。纽约市为特定城市的公司维护另一个数据库。接下来的部分将介绍我们如何合并这些数据库和数据可视化。
州数据库可能很难导航。应该与自我报告功能相对应的 Google 搜索可能不会映射州数据库,因为它具有受保护的性质。在定义了问题之后,让我们更深入地研究数据库的核心。对于这个问题,我将使用的数据库是SDVOB——截至 2022 年 1 月 27 日,数据库中有 932 家认证的伤残退伍军人所有的企业。您可以通过按下搜索按钮下载 excel 文件。
乔希·阿佩尔在 Unsplash 上拍摄的照片
配方的模块
import numpy as np
import pandas as pd
from pandas import DataFrame, Series # for convenience
import re
import glob
import copy
import os
import xlrd
import nltk
import unicodedata
import re
from collections import Counter
from nltk.collocations import *
bigram_measures = nltk.collocations.BigramAssocMeasures()
trigram_measures = nltk.collocations.TrigramAssocMeasures()
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
import spacy
#!pip install -U pip setuptools wheel
#!pip install -U spacy
#!python -m spacy download en_core_web_sm
nlp = spacy.load("en_core_web_sm")
import en_core_web_sm
nlp = en_core_web_sm.load()
from bs4 import BeautifulSoup
from html import unescape
探索数据集
数据集包含 936 行× 21 列,其中一列包含自我报告功能-
-以及关键字和关于列。由于每一列都包含关键信息,这些信息可以让我们深入了解企业在做什么,因此我们需要训练一个模型,该模型使用这些信息的组合作为之前的,而没有任何嵌入的分类(或偏差)。这意味着我们的模型没有考虑信息是否来自关键字或关于列;该模型假设自我报告的信息与公共记录认证和验证的信息一样有价值。
因此,下一步是将信息组合成一个列表;列表的索引对应于企业在数据库中的位置。正如你可能看到的,特征数据是**不干净的,**有几个不需要的 ASCII 字符,但是如果你仔细观察,这些字符是分隔关键字的,例如:
string1 = "Marijuana Dispensary, Online Retail Sales"
string2 = "Environmental remediation services; Fire and or Water Damage Restoration Services"print(string1.split(sep =', '))
>>['Environmental remediation services', 'Fire and or Water Damage Restoration Services']#try - string2.split(sep='; ')
因此,要在没有 NLP 的情况下提取所需的二元模型和三元模型,我们可以使用分隔符,分隔符的选择取决于我们!这里有一些我可以观察到的分隔符&, --,: etc.
,所以在我们下一步清理数据之前,让我们列出一个可以循环的列表。
数据集分离
下面是我如何制作一个总数据的列表
在我们进入清理和提取 hashtags 的循环之前,我将定义关键函数来清理、提取和整理数据。
基本功能
- Basic clean 是最重要的函数,它使用 NLP 并返回一个没有 Unicode、ASCII 和停用词的字符串列表!通过使用 Beautifulsoup 来清理 HTML 语法或定义停用词,您可以将它提升到一个更高的水平。当我们在将成为数据框单元一部分的字符串列表中获得重复的时,该函数获取一组列表并将它们转换成一个字符串。
现在我们有了基本的清理,我们可以创建这个整洁的函数来大写单词-
- 下面的函数将帮助我们删除位于数据框单元格内的字符串列表中的重复项,并吐出组合了这些单词的字符串。
比如说—
`s = “ Hello Hello Sir”
strsetoflist(s.split())
>>'Hello Sir'
2.不幸的是, np nan 一直是我所有数据方的客人,我不得不使用这个函数将其从字符串列表中移除——
3.如果你没有字符串列表,那么在字符串中删除重复项就有点复杂了,所以为了安全起见,这里是第一个函数的扩展。
4.移除非类型是我们需要考虑的另一个麻烦。
标签生成
欢迎使用机器!这里有几个移动部分——选择和调整参数。其中第一个是字数*(len(q))第二个是三元组和二元组第三个是PMI(点态互信息)。我们使用 PMI 来识别“搭配的单词。首先,让我们解开双循环,走向 if-else。***
因为数据列表的长度等于行数,所以让我们在原始数据框中创建一个单独的列来开始操作。我们可以通过更改列表本身并将其附加到数据框来实现相同的目标。
- 首先,我们将对数据中的每个字符串元素使用
split()
函数来创建一个双列表。然后我们将basic_cleanandcapitalize()
这些单词,并开始一个接一个地删除和操作双列表中的每个单词/字符串。
2.我们将分割字符串(总数据中的单词)并创建一个我们想要检查的虚拟列表‘q’。
3.正如您可能看到的,我们希望将单词限制在长度 2–4 之间,所以我们想要一个长度在(1,5) 之间的字符串。然后,我们将列表放回字符串中,并将其与原始数据框连接起来。
4.否则——我们使用列表中的三元模型查找器,并应用过滤器 apply_freq_filter
( 移除频率小于 min_freq 的候选元模型)。— 1 表示单词至少出现一次,这是另一个可以考虑的值。这里你也可以使用一个 bigram_measures 和bigram collocation finder。**
5.我们还使用 finder 和 nbest 来测量 PMI 以检查单词一起是否有意义,并从该元组([0:1]) 中选择前两个候选项,这里的机制是位扭曲的,试错法将比 PMI 的数学解释得更多。
6.最后,我们将元组转换成字符串,并在将临时变量合并到数据帧之前使用 tidy 函数。我们可以通过制作标签来总结:
**df1['Hashtags'] = df1['Data_total_grams'].apply(nonetype_remove )**
结论
上述过程解释了如何将句子转换成有意义的两个或三个单词的组合,并选择适合应用的单词。这篇文章的总体目标是解释简单的人工智能算法如何帮助和授权资源有限的社区进行“标记”和“标注”。关于人工智能的社会挑战和组织人工智能伦理的定性文章阐明了这个问题。这篇文章是将事情付诸行动的一个小小尝试。我们可以在 https://toughleaf.com的找到算法的应用
在没有任何 Web 开发经验的情况下,如何将您的数据见解转化为网站
使用 WordPress 和 SQL 以视觉上引人注目的方式展示您的 Python 见解
通过使用 WordPress 和 SQL 让您的数据见解变得可访问——作者插图(官方示例图表/表格由 wpDataTables 提供)
当用 Python 完成一个漂亮的分析时,有没有感觉被切断了?我也是——我没有提交另一个 Jupyter 笔记本,里面有一些沉重的机器学习材料,充满了 seaborn 主题的情节,而是花了一整夜的时间研究如何让公众更容易获得这种分析,并以更专业的方式呈现见解。
**结果呢?**在 WordPress 上运行的网站以清晰的方式展示见解,并允许最终用户与数据交互。该网站通过使用简化的 Python 文件填充的数据库来访问分析数据。棘手?绝对不是,使用 WordPress 不需要大量的网页编码,并且允许通过拖拽来建立一个网站。
使用 WordPress 和 SQL 将您的数据见解发送到一个简单的 web 应用程序中——作者插图
因此,让我们把它分成小块,用一个简单的例子一步一步地完成整个过程。
#0 获取一些数据
重要提示: 下面讨论的所有代码片段也可以在 GitHub 上我的 资源库 中的一个完整的 Jupyter 笔记本文件中找到。
第一步从 python 文件(或 Jupyter 笔记本)开始,我们在其中执行分析任务,并加入额外的代码来与数据库交互:
通过 Python 与数据库交互的元素—作者插图
为了简化,我们将使用通过雅虎的金融 API 获得的一些股票数据,并创建一个简单的数据框架。
安装 Yahoo API 连接器库以下载历史市场数据:
$ pip install yfinance
获取特斯拉股票信息:
特斯拉上市前 100 天的股票信息——作者配图
#1 创建一个数据库
对于数据库系统,我们的目标是 PostgreSQL。这是最成熟的方法之一,可以完美地与 WordPress 网站配合使用。其他流行的 SQL 数据库有 MySQL 和 MS SQL。
有各种各样的提供商为在云中运行数据库提供负担得起的托管计划。除了现有的平台,如亚马逊 AWS 或微软 Azure,我建议你注册一个平台,免费为你提供(1)个基本计划,或者如果你只是想为自己复制展示,提供(2)个试用版本。
注意:你也可以在本地运行数据库设置和 WordPress 网站,这不需要任何托管。然而,由于我们对制作一个公共网站感兴趣,我们将致力于在云中部署。
在我的例子中,我使用的是elephantsql.com,它提供了一个免费版本,但没有提供任何支付细节。数据库的启动和设置都在短时间内完成:
- 去 elephantsql.com
- 创建一个帐户
- 选择免费计划(“小乌龟”)并完成配置过程(托管区域无关紧要)
- 转到控制台(customer.elephantsql.com ),单击刚刚创建的数据库
- 参见详细信息部分中的数据库凭证
连接到数据库所需的凭据详细信息–作者插图
注意:如果数据的持久性至关重要,我建议使用具有额外安全保护(SSL、IP 范围等)的方案。)和用于快速恢复的高可用性,这也是行业标准。
#2 连接到数据库
我们使用pg8000
作为 PostgreSQL Python 连接器,这需要 pip 安装。
注意:这个库是专门为 PostgreSQL 数据库设计的。对于 MySQL 或其他数据库,可能需要不同的连接器。
$ pip install pg8000
#3 创建模式和表
接下来,我们创建一个模式和表,将数据正确地存储在数据库中。PostgreSQL 中支持的常见数据类型有:
boolean
date
timestamp
decimal
float
varchar(n)
numeric
注意:数据类型因数据库系统而异。
为了简化,我们只检索Date
和Close
列,以便稍后创建一个简单的折线图。当我们想要发送查询来与数据库交互时,我们使用 SQL 语言(参见代码片段中的字符串)。
注意:[IF NOT EXISTS]是可选的,它检查具有该名称的表/模式是否已经存在。这有助于避免在常规测试中覆盖数据。
#4 向数据库发送数据
我们通过使用一个list of lists
(“obj”)将数据发送到数据库,其中每个列表代表数据帧中的一行。变量s
用 SQL 语法表示查询。我们引用希望填充到数据库中的列,并为它们的值提供“占位符”%s
。确保obj
的顺序必须符合查询中定义的顺序。
注意:游标方法允许遍历整个列表,这将只需要一个查询。
快速完整性检查,查看数据是否发送到数据库:
PostgreSQL 数据库中的前 5 行数据—作者插图
#5 WordPress 基础
背景 WordPress 是最强大的开源内容管理系统之一。最初是作为一个博客系统创建的,它已经发展到支持其他相关领域,如电子商务、报纸或企业网站。你使用模板来构建网站,这意味着你可以通过拖放来添加内容,而不必关心后端本身。您可以访问一个第三方插件池来构建非标准特性,在我们的案例中我们也会这样做。根据 w3techs.com,大约。排名前 1000 万的网站中有 41%运行在 WordPress 上,这充分说明了这个网站建设者的便利性和安全性。
WordPress 内容管理系统的技术架构——作者举例说明
这篇文章不包括 WordPress 网站的设置。已经有大量的文章对此进行了解释。如果你是一个完全的初学者,我建议你遵循下面列出的资源:
- https://www.youtube.com/watch?v=digtdXBkGWo
- WordPress 官方安装指南
由于我们的目标是部署一个在线网站,我们需要一个网站托管计划(包括一个域)。下面是一些提供特殊 WordPress 托管计划的提供商,在这些计划中,WordPress 可以立即配置(通常只需几次点击) :
托管计划(2021 年 5 月)-作者插图(维基媒体图片用于公司标志)
注意:WordPress 也需要一个数据库(与 MySQL 或 MariaDB 数据库配对)。理论上,也可以使用集成的。在某些提供商处,默认情况下并不总是提供对它的访问,这就是我们使用独立数据库的原因。
新手的动力
不要一开始就被 WordPress 冲昏了头脑,把下面的插图看做一点动力:
到达临界点——作者插图
开始的时候,这看起来像是一个失望的山谷,但是一旦你理解了基本原理,由于 WordPress 的低代码模板方法,你就能够在很短的时间内构建几乎所有的东西(例如,仅在一天内建立一个电子商务商店)。代码密集型 web 框架,如 Bootstrap 或 Python Django,对于初学者来说实际上是一场真正的斗争,并且对于每一个新的案例都需要额外的上下文知识。
#6 通过 WordPress 插件连接到数据库并创建可视化
一旦你有了一个运行在 WordPress 上的网站,我们就会寻找一个允许连接到 PostgreSQL 数据库的插件。
到目前为止,我用过的最好的与 SQL 数据库接口的 WordPress 插件叫做 wpDataTables 。它有一个免费的限量版和一个收费版,起价为 42 美元/年。它自动将 SQL 查询转换成可用于网站的表格,这些表格可以使用 JavaScript 或其他流行的图表呈现引擎进一步转换成图表。除了 PostgreSQL 连接,您还可以访问 MySQL 和 MS SQL 数据库,以及加载平面文件。
由 wpDataTables 官方提供的样表和图表
我建议使用付费版本(15 天退款保证),因为数据库连接只涵盖在付费版本。
关于如何安装这个插件的详细指南可以在他们的官方网站上找到。
一旦安装了插件,我们只需要建立一个连接并编写一个 SQL 查询来创建我们选择的可视化:
通过插件访问数据库的步骤——作者举例说明
连接数据库
在 WordPress 控制台中:
- 转到 WP 数据表一节
- 点击设置
- 选择独立数据库连接
- 插入您的数据库凭证(对于字段端口和*驱动程序,*分别填写 5432 和 ODBC。端口信息最初不会显示在 elephantsql.com 的控制台上)
- 点击保存更改创建连接
创建图表或表格
为了简化,我们选择股票表,并创建一个简单的图表。
注意:使用图表时,我们总是要先创建一个表格。
在 WordPress 控制台中:
- 转到第节 WP 数据表
- 点击创建表格
- 选择您的连接,然后选择创建一个链接到现有数据源的数据表
- 选择 SQL 查询作为输入数据源类型,并分配一个名称
- 编写 SQL 查询:
6.点击保存更改运行查询(如果查询成功,现在已经创建了表格)
7.转到创建图表
8.分配一个名称并选择一个图表渲染引擎(我推荐使用 chart.js )
在这一步之后,您将转到格式化和预览部分:
格式部分—作者插图
9.点击保存更改创建图表并获取短代码
快速实施的简码—作者举例说明
WordPress 中的 shortcode 是一小段代码,用方括号表示,指的是一个功能(这个图表,一个图库,等等)。) .现在,您只需要将这个短代码实现到您想要的页面中。不需要转换,在编辑页面时,只需将收到的短代码粘贴到文本元素中。
这是最后一步。您已经构建了第一个准备发布的小数据产品!
现在,您拥有了从 python 文件到网站的无缝连接,这意味着您可以更新 Python 文件,并且可视化效果将由于 SQL 查询而自动更新。
进一步的例子
我最近在一个大学项目中也使用了 WordPress。你可以在这里查看,或许还能获得一些设计网站的灵感。注意,这个项目的焦点不是分析本身,而是它的数据管道。
subway.christopherkindl.com 快照-作者插图
GitHub 知识库
https://github.com/christopherkindl/python-data-to-sql-database
参考文献:
[1]W3techs.com。(2021).内容管理系统使用统计https://w3techs . com/technologies/overview/content _ management。检索于 2021 年 5 月 29 日。
[2]Websitebuilderexpert.com。(2021).7 最便宜的 WordPress 托管https://www . websitebuilderexpert . com/we B- Hosting/Cheap-WordPress/。检索于 2021 年 5 月 29 日。
[3]Themeisle.com。(2021).WordPress 中的短码是什么?https://theme isle . com/blog/what-are-short codes-in-WordPress/。检索于 2021 年 5 月 29 日。
从学术界到数据科学
实用指南
图片来源: Unspash
哦,天啊,又一篇关于从学术界过渡到数据科学的博文。好吧,在这篇文章中,我会试着在一些更传统的建议之外,加入一些对通常建议的稍微不同的看法。这不是一步一步的指导,因为我不认为在这种情况下有这样的事情存在。相反,这篇文章将是我对如何从学术界平稳过渡到数据科学的个人观点。此外,这篇文章不是关于“如何获得数据科学工作”。我不会谈论你的简历,或者为面试做准备之类的事情。这篇文章是关于如何成为一名数据科学家的。
首先,我应该注意到,虽然我在这篇文章中涉及的许多事情可能是通用的,并适用于许多不同的情况,但我将首先提出一些假设。
- 你已经进入了一个技术领域(数学、统计、物理、化学、生物等)。
- 你有一定的编程知识(任何语言都可以)。
- 你打算从事的数据科学职业是应用型,而不是研究型的。
- 如果你正在攻读博士学位,所有这些可能会更适用,但对学士学位仍然适用。
好了,让我们开始吧。
数据科学到底是什么?
如果你偶然看到这个博客,你可能对数据科学有所了解,或者你认为你知道它是什么。数据科学可能意味着你整天管理数据库和编写 SQL 代码。这可能意味着您使用“大数据”工作,并使用 Hadoop(这可能还是一件事吗……)、Spark 和其他大数据工具做事。但愿不会,这可能意味着你在 Excel 中做的大部分工作都是制作线性回归模型。
但根据我的经验,当大多数人说数据科学时,他们真正的意思是“机器学习工程师”,即开发和应用 ML 模型到真实数据并部署它们以用于真实世界场景的人。当然,还有更多的内容,但这是要点,也是我在这篇文章的剩余部分中想到的那种数据科学家。
学术界是如何让我为这个角色做好准备的?
我知道当我还是研究生的时候,我以为我这辈子只准备做一件事——成为一名(天文)物理学教授/研究员(在一段漫长的博士后生涯之后)。在我读物理研究生的时候(2009 年至 2014 年),几乎没有人提到过任何其他职业轨迹。假设这是每个人都会走的路,这基本上意味着只有一种操作模式:写论文。
但是,在你的学术生涯中(无论是本科还是研究生)仍然会学到很多对你的数据科学(咳咳…机器学习工程师)生涯非常有用的东西。
学习斗争
有些技巧是教不来的。他们只能通过斗争来学习。如果你在你的学术领域做过任何种类的原创性研究,那么你就会知道其中的艰难。你必须学会自己解决问题,因为没有“正确的答案”可以在书的后面找到。如果你曾经编写过任何重要的代码库,那么你也知道其中的挣扎。你必须弄清楚如何将所有的东西放在一起,并调试不可避免会出现的错误。
在数据科学中,你的大部分时间都在挣扎,你需要能够对在特定时刻不知道该做什么感到舒服。你需要能够尝试,并且有可能失败。在许多情况下,利益相关者(想要某种 ML 产品/功能的个人/实体的花哨语言)并不太了解 ML,他们所知道的只是他们想要的最终产品是什么样子。事实上,在某些情况下,他们甚至不知道自己想要的最终产品是什么样子。更常见的情况是,他们拥有大量数据(当然是非常干净的),并且他们希望从这些数据中获得“洞察力”。作为机器学习工程师,你需要做好准备,努力找到他们问题的解决方案。
即使你将在基于 ML 的问题中经历的斗争可能与你在学术界经历的不同,但对不确定性感到舒适将为你作为机器学习工程师的职业生涯做好准备。
在下一节中,我将提供一些建议来更好地熟悉基于 ML 的斗争。
学习如何学习
与“奋斗”密切相关的是学会如何学习。每个人都以不同的方式学习,在你的学术生涯中,很有可能你已经发现了自己的方法。在很多情况下,尤其是在我的课堂上,你会意识到你并没有从课堂上学到很多东西。当然,你可能在考试中表现很好,但你会在一周内忘记一切。你通过做来学习。没有实践,所有的理论都是毫无价值的。你会相信一个花了几年时间研究最新外科技术,但从未真正实施过外科手术的医生吗?你会招募一个了解所有音乐理论但从未真正弹过吉他的“吉他手”吗?
稍后我将在这方面提供一些建议,但知道如何自主学习是数据科学或生活中最重要的技能之一。
“软技能”
总的来说,软技能是人际技能和沟通技能的结合。这一点很大程度上取决于你是否必须向技术和非技术观众展示你的作品。这也取决于你是否参与了一个大型合作项目。
也就是说,能够以清晰简洁的方式向非技术受众展示技术信息是一项技能,它将帮助你获得一份好的数据科学工作。正如我上面提到的,我专注于应用数据科学的工作,而不是研究数据科学家的职位。这意味着你需要能够与利益相关者以及你的队友沟通。
如果你有幸参与了一个大型协作项目,并与许多需要合作的不同团队合作,那么你将获得宝贵的技能,这些技能将真正在数据科学领域对你有所帮助。能够在不同群体之间进行翻译是一项非常有用的技能。例如,当我还是研究生时,我是数据分析小组的一员,我们主要使用贝叶斯技术。还有另一组人主要使用 T2 常客技术。从表面上看,这些事情可能非常不同,但两者之间有一些有用的翻译,我会说两种语言,这使得事情进展得更顺利。
同样,在下一节,我会给出一些关于如何练习沟通技巧的建议。
实用(而且非常固执己见)的建议
如题,这个建议很固执,但是这些方法对我来说效果很好。在给出实际建议之前,让我解释一下我对数据科学家候选人的要求:
- 一个容易相处并有良好的个人/沟通技巧的人。对于一个技术角色来说,这可能看起来不太重要,但对我来说却至关重要。大多数数据科学家在团队中工作,因此能够相处和沟通至关重要。
- 一个在过去表现出主动性并且相当自我激励的人。这不需要与 ML/数据科学相关,它可以应用于你的学术研究领域,但也可以应用于你向数据科学过渡的准备。
- 对“真实”数据有经验的人。我说的真实数据是指杂乱的数据。我想看到你已经学会了奋斗并接受了它。同样,这也适用于你的学术经历或数据科学准备。
- 能够谈论许多不同的 ML 技术的人。这并不意味着您需要非常深入地了解任何细节,但是您应该对现有的技术及其应用有所了解。
就这样,让我们得到建议
1.学习 Python
Python 是机器学习的语言。它非常容易使用,并且它主要包装了用更高性能的语言编写的库,比如 c。
python 的成长(来源: KDnuggets )
它在所有领域都在增长,不仅仅是 ML,但在这篇文章中,我将重点关注 ML。Python 在 ML 中非常强大,因为有几个专门构建的 ML 库,比如熊猫、 tensorflow 、 pytorch 、 scikit-learn 、 spacy 和变形金刚等等。
如果你已经知道 Python,那太好了。如果你没有,还有很多资源可以学习。我不建议用一本书来学习 Python,因为已经有这么多好的资源了。从 Matlab 转到 Python 之后,我学习了 Python,这些年来,我通过查看如上所述的设计良好的代码库,以及观看各种 YouTube 教程和其他在线资源,磨练了自己的技能。事实上,我从来没有读过关于 Python 编程的书(关于机器学习或深度学习或统计学,但我稍后会深入讨论)。
2.学习软件设计原则
好,那么你已经学了 Python。准备好了吗?不完全是,在我真正学会如何设计软件之前,我已经知道如何使用 Python 很长时间了。我总是用盖房子来比喻。你可能真的很擅长使用所有的工具,但是如果你没有蓝图,不知道各种各样的代码和标准,或者不知道从哪里以及如何获得所有的材料,那么你就不走运了。虽然了解 Python 语言非常重要,但实际上了解软件设计原则(主要是语言不可知的)将真正让你脱颖而出。
这一部分本身可以作为几篇博客文章,但我在这里只提到主要的亮点:
- 面向对象编程(OOP) :虽然函数式编程没有任何问题,但你确实会在日常生活中混合使用 OOP 和函数式编程。ML 生态系统(也就是上面提到的包,尤其是 PyTorch 和 scikit-learn)大部分在 OOP 阵营。能够理解基于 OOP 的包并能够编写自己的基于 OOP 的代码是非常重要的。
- 单元测试和持续集成(CI) :这两者通常是并行的。单元测试是指对你的代码“单元”进行特定的测试。这是为了检查您的代码是否正确,也是为了在您进行更改时防止代码被破坏。CI 基本上包括自动化这个测试过程,也可以包括单元测试之外的其他类型的测试。掌握这一点将会给你带来巨大的优势。
- 设计模式:这些是解决特定问题的可重复使用的模式。这些模式大多与语言无关。现在,您不需要知道所有不同的模式,也不需要总是使用它们;然而,对他们的所作所为有一个基本的了解(以及他们的存在)会让你处于一个很好的位置。
- 文档:在你的学术生涯中,你可能编写了适合你的代码。你知道如何使用它,而且它有效。作为数据科学团队的一员,其他人需要能够使用和理解您的代码。代码文档至关重要,了解最佳实践也非常重要。
上面的列表只是从细节上触及了表面。我为每一个提供了一个基本的教程链接,但是还有很多其他非常好的资源来学习正确的编码实践和工具。这里有几个:
- 生成 Pythonic 代码:关于代码分解和生成漂亮代码的精彩对话。
- 从头开始的深度学习库:包设计的良好入门,学习如何考虑构建包。
- cal code . io:大量关于各种工具和技术的有用视频
- Traversy Media:Python 网络开发方面的良好介绍。
在结束这一部分时,我要指出,根据我的经验,大多数数据科学家(尤其是机器学习工程师)对这些东西的了解非常有限。所以,这不是你在竞争中所缺少的东西。然而,如果你确实知道这些事情,并花时间去学习它们,那么它会让你在竞争中脱颖而出。更重要的是,它会让你成为更好的数据科学家。
3.做一些项目(并分享)
好了,这就是标准建议的来源,但它是标准的是有原因的。如果你来自学术背景,而不是数据科学背景,你必须做一些项目来填补你缺乏的在职经验。从某些方面来说,这是一个额外的收获,尤其是如果你的竞争对手是那些上过数据科学或类似领域的学校的人。记住我说过的自我激励。对于那些从事数据科学或分析项目的人来说,他们的大部分经历都是通过他们“不得不”做的课程获得的。对于你这个自学成才的数据科学家来说,你通过展示你已经完成的数据科学项目来表明你是自我激励的。
现在你可以做很多不同种类的项目。我将按照重要性的大致顺序列出三个:
- 数据讲故事项目:在我看来,这种项目是你能做的最有用的。基本上就是选择一个你感兴趣的领域,找数据,分析,讲故事。你甚至不需要做任何 ML。这些项目展示了你使用未经过滤的原始数据的技能,(尽量不要使用经过筛选的数据集),还可以让你在数据科学的斗争中获得一些经验。在我的案例中,我查看了警察枪杀平民,并从一些数据库中提取数据,包括人口普查数据、联邦调查局犯罪统计数据和当地警察局数据。在这个过程中,我花了很大的力气将所有这些资源整合在一起,并了解了大量关于熊猫和各种 python 地图包的知识。
- 完整的端到端 ML 应用:这种项目会给人留下非常深刻的印象,并显示出你有实际 ML 部署的经验,这是许多候选人和实际数据科学家(包括我自己)所缺乏的。
- 你可以通过做一些 Kaggle 比赛和查看公共笔记本来了解很多关于 ML 的事情。这些都在列表中,因为它们对你获得一些将 ML 应用于数据的经验很重要,但它们是最后的,因为这种工作现在无处不在,所以它不会让你与众不同。
一旦你做了一些项目,并通过大量的努力获得了一些 ML 和数据辩论技巧,现在你可以提高你的沟通技巧了。
首先,一定要把你做的任何事情放到 GitHub 上,这将公开你的工作,如果你还不知道的话,还会教你版本控制。请确保用项目自述文件记录您的项目。这只是最低级的分享你的作品。
接下来,你可能想在个人博客或媒体上分享这个作品。这是另一个磨练你的沟通技巧和确保你真正理解你的项目的好方法。测试你的知识的最好方法是试着向别人解释你的项目。然而,写博客仍然有些被动,这些技能不是成为一名成功的数据科学家所需的主要沟通技能。
最后,你可以通过演讲来展示你的作品。这种事情大概有很多论坛。就我而言,我在 Meetup 上寻找任何本地数据科学相关的团体。先参加一些聚会,并向组织者介绍自己,这可能是个好主意。他们通常在寻找任何想演讲的人。如果有机会,主动提出就你的一个项目做一个演示。
因此,这听起来很多,你未来的公司可能甚至不会看你做的所有工作,但即使他们不会看,你做了所有这些并发展和磨练了所有这些技能的事实将极大地帮助你作为数据科学家的整体职业生涯。
4.学习行话(假装直到你成功)
当我还是大学生的时候,我的一位物理学教授给了我一些很好的建议。他告诉我们,就你的职业生涯而言,最重要的事情之一是你“学习行话”,也就是说,你学习你正在从事或想要从事的领域的语言。例如,如果有人对你说他们“使用了一个变压器模型进行情感分析”,你需要从这句话中得到什么?你肯定不需要知道变压器模型是什么或如何实现它的任何细节,但你应该知道情感分析是指测量一段文本的“积极”或“消极”程度,而“变压器”模型是一种深度学习模型,现在在自然语言处理中非常流行。
换句话说,对许多概念有广泛但浅薄的理解要比对几个概念有非常深刻的理解好得多。这在很多情况下几乎与学术研究背道而驰。在学术界,一个人非常需要对自己的领域有非常深刻的理解,代价是对该领域以外的知识了解不多。作为一名数据科学家,情况正好相反,对许多概念及其用途有一个基本的了解要比知道精确的算法细节好得多。
这又回到了我早先提出的关于学会如何学习的观点。如果你对许多事情有肤浅的理解,那么这将允许你快速评估一个给定的问题,并提出一个潜在的解决方案;然而,要真正实现这个解决方案,你可能需要学习更多你目前所知道的东西。因此,你需要能够脚踏实地地学习。作为一名学者,似乎你总是需要提出新的东西,但在数据科学中,没有人真正关心你是否提出了新的东西,他们只关心你是否解决了问题。这意味着,在互联网上搜索与你类似的问题的解决方案,并对其进行调整以解决你的问题,这并不可耻。
所有这些似乎都是错误的,但这是我收到的最好的建议,我认为它对我帮助很大。现在,这一切听起来不错,但你怎么做呢?这是最难的部分。我认为发展这种技能的最好方法是允许自己探索许多领域,但也要控制自己不要挖得太深,至少在你还在学习的开始阶段。参加介绍性的在线课程,跟随教程,做一些简单的项目,但是不要认为你需要知道所有的细节。
5.在线学习
好了,现在来谈谈另一个有争议的建议。不要看书来学习你的数据科学/ML 技能。至少,不要把书作为主要的信息来源。我唯一会推荐的书籍是学习基本的编程语言基础知识,(尽管在线学习可能更好)。
我从未读过关于编程、机器学习、深度学习、统计学或通信的书籍,但在我的学术生涯中,我发表过几篇论文,并领导过大型工作组。在学术界之外,我进步相当快,并领导了几个人工智能领域的项目,所有这些都是严格通过在线学习实现的。
现在,在线学习并不意味着你被动地坐下来看一些 YouTube 视频。这意味着你看一些 YouTube 视频或在线课程或阅读博客帖子或 arXiv 论文,然后自己尝试这些东西。你挣扎。你多看多读。再奋斗一些。在你的工作或项目中应用这些技术。再奋斗一些。在这个阶段结束的时候,你会意识到你已经学会了很多,不是通过一些基础的方法,而是通过一个更随机的试错过程,最终导致对材料更深刻的理解。
这听起来可能很疯狂,可能对你无效,但对我有效,对许多其他伟大的数据科学家和机器学习工程师也有效。我有一个非常简单的学习方法,我涉猎了许多不同的东西,但是除了我已经在这篇文章中提供的资源之外,我还可以在这里提供一些好的资源。
- Coursera :这里有很多很棒的课程,可以给你很好的介绍很多话题,尤其是机器学习和深度学习。参加 Coursera 课程后,不要期望成为任何方面的专家,但他们可以给你一个良好的基础。
- fast.ai :我会说这是学习前沿深度学习技术的最佳资源。不幸的是,它是由一个软件库支持的,在我看来,这个库结合了所有最糟糕的编码实践,并把它们都放在一个地方。即便如此,还有两个很棒的深度学习课程和一个更不为人知的机器学习 ( github 此处)和线性代数课程。
- YouTube:你几乎可以在 YouTube 上找到任何你想要的关于数据科学/ML/编程的东西。问题是质量参差不齐。我不会推荐特定的频道或视频,(其中一些我已经在上面提到过了)我只会说,对我来说,在许多情况下最有用的视频是实时演练,他们在实时编码(这是 fast.ai 很棒的原因之一)。然而,有时你只是对一个概念感兴趣,所以编码并不重要。不管怎样,YouTube 是一个每个人都可以使用的神奇资源。
- 博客帖子:走向数据科学可能有一些非常好的帖子,但里程数各不相同。这主要是说,看看随机的博客帖子来学习东西可能不是一个坏主意。即使帖子本身不是很好,通常也有其他参考资料可以引导你找到你想要的东西。
- 代码文档和源代码:许多大型代码库都有大量的文档和教程。浏览这些教程是一次很好的学习经历。在其他一些情况下,查看源代码本身可以向您展示一些良好的编程实践,(在某些情况下,您会惊讶于各种项目的源代码有多糟糕)。对于组织良好且文档记录良好的代码,我推荐初学者使用 PyTorch 和 scikit-learn 。
- Twitter:可以是垃圾箱,但也可以是学习新事物和建立新联系的好工具。我实际上是通过一个 twitter 朋友找到我现在的工作的。这里不胜枚举,但搜索数据科学或机器学习,关注一些更受欢迎的帐户。最终,你会发展这个网络,并把它作为一种信息过滤器。
包裹
如果你能走到这一步,恭喜你!这篇文章比我最初计划的要长得多。我已经在这里介绍了很多东西,这可能看起来令人望而生畏。当我第一次开始这个旅程时,我一直在想,我不可能学会所有这些东西,也许留在学术界会更好。如果你对你的学术领域充满热情,那么无论如何不要放弃,但是如果你只是因为你认为没有其他选择而呆在那里,那么这是一个完全错误的假设。
我在这篇文章中提到的所有事情都是我在过去 3.5 年的数据科学家生涯中学到的。一开始我并没有做所有这些事情,从那以后我学到了很多。
最后,如果你正处于这种转变中,并且感到有压力,请记住,一旦你获得了这些技能,你将成为抢手货,几乎可以在任何地方找到一份令人满意的工作。
原载于 2021 年 1 月 3 日https://jellis 18 . github . io。
AI 配音过 Subs?用人工智能翻译和配音视频
除了为自己做饭和绕着房子走几圈,日本卡通(或者孩子们称之为“动画”)是我在隔离期间学会喜欢的东西。
不过,看动漫的问题是,如果不学习日语,你就要依赖人类翻译和配音员把内容翻译成你的语言。有时你得到了字幕(“subs”),但没有配音(“dubs”)。其他时候,整季的节目根本没有被翻译,你只能坐在座位的边缘,只有维基百科的摘要和 90 年代的网络论坛带你穿越黑暗。
那你该怎么办?答案显然不是让计算机将一部电视节目的全部片段从日语转录、翻译和配音成英语。翻译是一门精细的艺术,不能自动化,需要人手的爱心触摸。此外,即使你确实使用机器学习来翻译视频,你也不能使用计算机来配音……我的意思是,谁会愿意听一整季的机器声音呢?那会很糟糕。只有真正的神经病才会想要那个。
因此,在这篇文章中,我将向你展示如何使用机器学习来转录、翻译视频,并将视频从一种语言转换为另一种语言,即“人工智能视频配音”它可能不会给你带来网飞质量的结果,但必要时你可以用它来本地化在线对话和 YouTube 视频。我们将从使用谷歌云的语音转文本 API 将音频转换成文本开始。接下来,我们将使用翻译 API 翻译该文本。最后,我们将使用文本到语音转换 API 为翻译“配音”,根据文档,它产生的声音“像人一样”。
(顺便说一句,在你在评论中炮轰我之前,我应该告诉你,YouTube 将自动免费为你转录和翻译你的视频。所以你可以把这个项目当成你从头开始烘焙酸面团的新爱好:这是对 30 个小时的低效利用。)
人工智能配音的视频:它们通常听起来很棒吗?
在你开始这段旅程之前,你可能想知道你有什么期待。我们现实地期望从 ML 视频配音管道中达到什么质量?
这里有一个从英语自动翻译成西班牙语的例子(字幕也是自动生成的英语)。我没有对它进行任何调整或调节:
正如你所看到的,转录是体面的,但并不完美,同样的翻译。(忽略说话者有时语速太快的事实——稍后再谈。)总的来说,你可以很容易地从这个配音视频中了解事情的要点,但它并不完全接近人类的质量。
让这个项目比大多数项目更棘手(更有趣)的是,至少有三个可能的失败点:
- 语音转文本 API 可能会错误地将视频从音频转录为文本
- 翻译 API 可能会错误或笨拙地翻译该文本
- 这些翻译可能会被文本到语音转换 API 读错
以我的经验来看,最成功的配音视频是那些在清晰的音频流中有一个人说话,并从英语配音成另一种语言的视频。这主要是因为英语的转录质量(语音到文本)比其他源语言高得多。
事实证明,从非英语语言配音更具挑战性。这是我最喜欢的节目之一《死亡笔记》的一段特别平淡无奇的日语到英语的配音:
死亡笔记的原始视频
如果你想把翻译/配音留给人类,好吧——我不能怪你。如果没有,请继续阅读!
构建人工智能翻译配音员
和往常一样,你可以在用机器学习 Github repo 制作的中找到这个项目的所有代码。要自己运行代码,请按照自述文件配置您的凭证并启用 API。在这篇文章中,我将简单介绍一下我的发现。
首先,我们将遵循以下步骤:
- 从视频文件中提取音频
- 使用语音转文本 API 将音频转换为文本
- 将转录文本分割成句子/片段进行翻译
- 翻译文本
- 生成翻译文本的语音音频版本
- 加速生成的音频,使其与视频中的原说话者一致
- 将新音频缝合到折叠音频/视频的顶部
我承认,当我第一次着手构建这个配音器时,我充满了傲慢——我所要做的就是将几个 API 插在一起,还有什么比这更简单的呢?但是作为一个程序员,所有的傲慢都必须受到惩罚,好家伙,我也受到了惩罚。
具有挑战性的部分是我上面加粗的部分,主要来自于必须将翻译与视频对齐。但一会儿我们会详细讨论这个问题。
使用谷歌云语音转文本 API
翻译视频的第一步是将音频转换成文字。为此,我使用了谷歌云的语音转文本 API 。这个工具可以识别 125 种语言的音频,但正如我上面提到的,英语的质量最高。对于我们的用例,我们希望启用一些特殊功能,比如:
- 增强型。这些是经过特定数据类型(“视频”、“电话呼叫”)训练的语音到文本模型,通常质量更高。当然,我们将使用“视频”模型。
- 脏话过滤器。这个标志防止 API 返回任何不良单词。
- 字时间偏移。这个标志告诉 API 我们希望转录的单词和说话者说这些单词的时间一起返回。我们将使用这些时间戳来帮助我们的字幕和配音与源视频对齐。
- 语音适配。通常,语音到文本转换最难处理的是不常用的单词或短语。如果您知道某些单词或短语可能会出现在您的视频中(即“梯度下降”、“支持向量机”),您可以将它们以数组的形式传递给 API,这将使它们更有可能被转录:
client = speech.SpeechClient()
# Audio must be uploaded to a GCS bucket if it's > 5 min
audio = speech.RecognitionAudio(uri="gs://path/to/my/audio.wav")
config = speech.RecognitionConfig(
language_code="en-US"
# Automatically transcribe punctuation
enable_automatic_punctuation=True,
enable_word_time_offsets=True,
speech_contexts=[
# Boost the likelihood of recognizing these words:
{"phrases": ["gradient descent", "support vector machine"],
"boost": **15**}
],
profanity_filter=True,
use_enhanced="video",
model="video")
res = client.long_running_recognize(config=config, audio=audio).result()
API 将转录的文本连同单词级时间戳作为 JSON 返回。举个例子,我转录了这个视频。你可以在这个 gist 里看到 API 返回的 JSON。输出还让我们进行快速的质量健全性检查:
我实际说的:
“软件开发者。我们的摇滚风格并不出名,对吧?或者说是我们?今天,我将向你展示我如何利用 ML 让自己变得更时尚,从有影响力的人那里获取灵感。”
API 以为我说了什么:
“软件开发者。我们的摇滚和风格并不出名。我们还是今天的我们吗?我将向你展示我是如何利用 ml 从有影响力的人那里获取灵感来打造新的时尚潮流的。”
根据我的经验,这是你在转录高质量英语音频时可以期待的质量。注意标点有点偏。如果你对观众理解视频的要点感到满意,这可能已经足够好了,尽管如果你说的是源语言,你可以很容易地自己手动修改脚本。
此时,我们可以使用 API 输出来生成(未翻译的)字幕。事实上,如果您用`-srt '标志运行我的脚本,它会为您做到这一点( [srt](https://blog.hubspot.com/marketing/srt-file#:~:text=An%20SRT%20file%20(otherwise%20known,the%20sequential%20number%20of%20subtitles.) 是隐藏字幕的一种文件类型):
python dubber.py my_movie_file.mp4 "en" outputDirectory **--srt** **--targetLangs** ["es"]
机器翻译
现在我们有了视频抄本,我们可以使用翻译 API 来…嗯…翻译它们。
这是事情开始变得有点🤪。
我们的目标是这样的:我们希望能够翻译原始视频中的单词,然后在大致相同的时间点播放它们,以便我的“配音”声音与我的真实声音保持一致。
然而,问题是翻译不是逐字逐句的。从英语翻译成日语的句子可能语序混乱。它可能包含更少的词,更多的词,不同的词,或(如成语)完全不同的措辞。
解决这个问题的一个方法是翻译整个句子,然后试着调整这些句子的时间界限。但是即使这样也变得复杂了,因为你如何表示一个句子呢?在英语中,我们可以用标点符号来拆分单词,例如:
"Hi! My name is Dale. What's up?" --> ["Hi", "My name is Dale", "What's up"]
但标点符号因语言而异(英语中没有),有些语言根本不用标点符号分隔句子。
另外,在现实生活中,我们通常不会用完整的句子说话。你知道吗?
另一个让翻译抄本变得困难的问题是,一般来说,你输入到翻译模型中的越多上下文,你就能期待更高质量的翻译。举个例子,如果我把下面的句子翻译成法语:
“我感到忧郁,但我也喜欢粉红色。”
我去拿翻译过来的:
“我喜欢蓝色,但我也喜欢玫瑰.”
这是准确的。但是,如果我把这句话分成两部分(“我感到忧郁”和“但是我也喜欢粉红色”),并分别翻译每一部分,我会得到:
“Je me sens triste,mais j’aime aussi le rose”,即“我感到悲伤,但我也喜欢粉红色。”
这就是说,我们在将文本发送到翻译 API 之前分割得越多,翻译的质量就越差(尽管在时间上与视频保持一致会更容易)。
最终,我选择的策略是,每当说话者停顿时间超过一秒钟时,就把所说的话分开。这是一个看起来像什么的例子:
{
"en": "Software developers.",
"start_time": **0.2**,
"end_time": **1.5**,
},
{
"en": "We're not known for our Rock and style. Are we",
"start_time": **1.6**,
"end_time": **4.4**,
},
{
"en": "or are we",
"start_time": **5**,
"end_time": **6.2**,
},
这自然导致了一些尴尬的翻译(即“或者我们”是一个奇怪的翻译片段),但我发现它足够好。这里是代码中的逻辑。
侧栏:我还注意到,对于非英语语言,语音到文本 API 返回的时间戳的准确性明显较低,这进一步降低了非英语到英语配音的质量。
最后一件事。如果您已经知道希望如何翻译某些单词(例如,我的名字“Dale”应该总是简单地翻译为“Dale”),您可以利用高级翻译 API 的“词汇表”功能来提高翻译质量。我在这里写了一篇关于那个的博文。
碰巧的是,Google Cloud 正在开发一个新的 API 来处理翻译口语的问题。它被称为媒体翻译 API ,它直接在音频上运行翻译(即没有转录的文本中介)。我不能在这个项目中使用这个 API,因为它还没有返回时间戳(这个工具目前处于测试阶段),但是我认为在未来的迭代中使用它会很棒!
文本到语音转换
现在开始有趣的部分——挑选电脑声音!如果你读过我的 PDF 到有声读物转换器,你就会知道我喜欢听起来滑稽的电脑声音。为了生成配音音频,我使用了谷歌云文本到语音转换 API 。TTS API 可以用不同口音的不同语言生成许多不同的声音,你可以在这里找到并使用来弹奏。“标准”声音可能听起来有点,呃,*微小,*如果你知道我的意思,但是由高质量神经网络生成的 WaveNet 声音听起来很像人类。
在这里,我遇到了另一个我没有预见到的问题:如果计算机的声音比视频的原始扬声器慢得多,从而导致生成的音频文件太长,该怎么办?那么配音将不可能与源视频对齐。或者,如果译文比原文更加冗长,导致同样的问题,怎么办?
为了解决这个问题,我尝试了文本到语音转换 API 中的参数speakingRate
。这允许您加快或减慢电脑声音:
# Instantiates a client
client = texttospeech.TextToSpeechClient()
# Set the text input to be synthesized
synthesis_input = texttospeech.SynthesisInput(text="Hello World")
voice = texttospeech.VoiceSelectionParams(
language_code=languageCode, name=voiceName
)
# Select the type of audio file you want returned
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3,
# Speed up or slow down speaking
speaking_rate=speakingRate
)
# Perform the text-to-speech request on the text input with the selected
# voice parameters and audio file type
response = client.synthesize_speech(
input=synthesis_input,
voice=voice,
audio_config=audio_config
)
所以,如果电脑说一句话的时间比视频原声说话人说一句话的时间长,我就提高说话速度,直到电脑和人类花的时间差不多。
听起来有点复杂?代码如下所示:
**def** **speakUnderDuration**(text, languageCode, durationSecs, voiceName=None):
"""Speak text within a certain time limit.
If audio already fits within duratinSecs, no changes will be made.
Args:
text (String): Text to be spoken
languageCode (String): language code, i.e. "en"
durationSecs (int): Time limit in seconds
voiceName (String, optional): See https://cloud.google.com/text-to-speech/docs/voices
Returns:
bytes : Audio in wav format
"""
# First, generate audio with speakingRate = 1
baseAudio = speak(text, languageCode, voiceName=voiceName)
# Save audio to a temporary file
f = tempfile.NamedTemporaryFile(mode="w+b")
f.write(baseAudio)
f.flush()
# Get the sample's duration
baseDuration = AudioSegment.from_mp3(f.name).duration_seconds
f.close()
# How fast was the generated audio compared to the original?
ratio = baseDuration / durationSecs
# if the audio fits, return it
**if** ratio <= **1**:
**return** baseAudio
# If the base audio is too long to fit in the segment, increase
# the speaking rate
ratio = round(ratio, **1**)
# speakingRate must be <= 4
**if** ratio > **4**:
ratio = **4**
**return** speak(text, languageCode, voiceName=voiceName, speakingRate=ratio)
这解决了音频与视频对齐的问题,但有时这意味着我配音中的电脑扬声器有点笨拙地快。但是这对 V2 来说是个问题。
值得吗?
你知道这句话吗,“玩愚蠢的游戏,赢得愚蠢的奖品?”感觉我在这里建立的每一个 ML 项目都是一种爱的劳动,但这一次,我喜欢我的愚蠢的奖励:能够生成无限数量的怪异,机器人,笨拙的动画配音,有时还有点像样。
点击这里查看我的结果:
遵循dale quark为万物 ML。最初发表于 2021 年 2 月 2 日 https://daleonai.com*。*
如何将数据转化为可操作的见解
使用这个过程来发展一个无价的分析技能
在最近的一次数据演示中,我的利益相关者对我说“我不知道如何处理这些信息”。这句话萦绕在我的脑海中,因为我意识到我们不能总是假设我们的利益相关者能够将数据和可操作的见解联系起来。作为数据分析师,我们的工作就是帮助弥补这一缺失环节。今天,我将讨论我用来将数据转化为见解的流程,以及如何在您的工作中应用这一流程。
学习公司的商业模式
我首先回答关于公司业务的三个基本问题。
- 公司如何获得潜在客户? —根据商业模式,潜在客户可以是网站的访问者、销售团队的负责人或产品或服务的用户。营销通常负责通过各种数字渠道带来潜在客户,如有机搜索、付费营销、电子邮件等。了解公司如何获得客户非常重要,因为这有助于您了解业务影响,以及当与客户获得相关的 KPI 发生变化时,在哪里进行调查。
- 是什么影响了潜在客户的购买行为? —同样,根据业务模式,不同的因素会影响潜在客户的购买可能性。销售服务或产品的公司可以在购买前提供免费试用,或者电子商务公司可以在客户首次购买时提供折扣。关键是要知道影响你的公司的因素,以了解变化将如何影响业务。比如产品公司把他们的免费试用去掉了怎么办?这可能意味着更少的人会购买,因为他们不能免费试用,公司将赚更少的钱。
- 公司如何留住客户? —留住客户是保持收入的关键。电子商务公司有忠诚度计划,给顾客购买奖励积分,积分可以兑换成折扣。产品公司发布新功能,并不断改善产品体验,以吸引用户。了解影响客户保留率的因素对于查明与保留率 KPI 相关的问题非常重要。
使用漏斗分析绘制 KPI
在我了解公司的商业模式后,我使用漏斗分析将相关 KPI 映射到客户获取漏斗的每个部分。这有助于我识别 KPI 变化的业务影响。
让我们使用下面的电子商务收购漏斗示例来绘制一些电子商务KPI并讨论 KPI 的变化如何影响业务。
作者创建的电子商务收购漏斗图
- 访问者来到网站。 —总访客和营销渠道访客。访客越少,意味着购买量越少,收入越低。
- 参观者浏览商品。 —平均产品页面浏览量。产品页面浏览量减少可能意味着营销没有为网站带来合适的访客。
- 游客将感兴趣的产品添加到购物车。—添加到购物车的平均商品数。添加到购物车的平均商品数量的增加可以转化为更高的平均订单价值和更高的收入。
- 访客开始结账流程。 —弃车率。更低的购物车放弃率意味着更多的购买和更高的收入。
- 访客完成购买。 —采购总额、平均订单价值和转换率。更高的转换率意味着更多的访问者购买和更高的收入。
请注意,有些 KPI 跨越了漏斗的多个部分,因为数字本身可能没有意义。例如,购物车放弃率和转换率是使用漏斗不同部分的数据计算的重要 KPI。找出贵公司的关键 KPI,并将它们映射到客户获取漏斗的相关区域。
将数据转化为见解
现在,我们将回顾一些假设的 KPI 变化、业务影响,以及它们如何转化为可操作的见解。
- 与历史日平均水平相比,日购买量开始下降。—由于购买是客户获取漏斗的最后一个阶段,我们需要观察漏斗的不同部分,以找到下降的原因。购买是由游客推动的。从每日总访问量来看,我们发现网站的访问量没有变化。我们检查了产品页面浏览量和添加到购物车的商品的平均值,没有变化,但我们确实看到购物车放弃率有所增加。在与 product 交谈后,您发现有一个针对结帐流程的 A/B 测试正在运行,并且测试变体的表现比控制差。影响是测试运行时收入暂时减少。可操作的见解是,如果 A/B 测试达到了统计显著性,则关闭该测试;如果没有达到,则与产品部门讨论是否值得继续运行该测试,如果它影响了收入的话。
- 与历史平均水平相比,转换率下降。 —转化率通过购买量除以访客来计算。这意味着要么游客增加了,但他们的购买率不如以前,要么购买数量下降了。按渠道细分转化率,我们看到下降来自付费搜索。在与营销人员交谈后,我们发现他们推出了新的付费活动,与现有活动相比,转换率较低。业务影响是降低收入,可操作的见解是现在关闭新的活动,并找出为什么访客转换率比现有活动低。
最后的想法
了解贵公司的商业模式和客户获取渠道是学习如何将数据转化为可操作的见解的关键。我希望学习我的过程有助于你尽快发展这种无价的分析技能。感谢阅读和快乐的数据翻译!
你可能也会喜欢…
https://medium.datadriveninvestor.com/how-data-scientists-can-develop-business-acumen-870eb55866e6
如何对异常 KPI 变化进行故障排除
调查 DAU 下降的案例研究
来自 Pexels 的 Andrea Piacquadio 的照片
如果你从事数据分析工作,有时你会被要求调查公司 KPI 的异常变化。根本原因可能有很多种,但是如何进行故障诊断可能会占用您一天的大量时间,或者根本没有时间。作为一名数据分析师,我有过许多类似的问题,我想介绍一下我研究问题的步骤和最常见的原因,以帮助您更快地找到答案。
方案
让我们假设一个常见的 KPI,如贵公司仪表盘中的 DAU ,与之前的历史趋势相比,在 3 月 15 日出现了异常下降。
1.数据管道
使用此排除过程来确认 DAU 下降是否是由数据管道问题引起的。
- 找到生成仪表板使用的数据的 ETL 过程,并确定用于计算 DAU 的数据源。在这种情况下,DAU 由注册帐户的新用户和今天登录该帐户的现有用户组成。
- 确认 3 月 15 日新增和现有用户数据已成功加载到数据库中。
- 检查新的和现有的用户原始数据文件的记录计数是否与数据库匹配。如果某个 KPI 有多个数据源,则可能缺少一部分数据。新的用户数据加载可能不完整,这导致了 DAU 的下降。重新运行 ETL 来处理所有新的用户数据将会修复 DAU 下降。
- 如果原始数据和数据库之间的记录计数匹配,则按小时检查数据,以确认所有 24 小时都在 3 月 15 日完成。如果文件不是按小时划分的,可以找到一个时间戳字段,比如注册时间或登录时间。有时这是问题的根源,发送登录事件的服务在几个小时内失败,并且当天有部分数据。如果没有办法恢复数据,你能做的最好的事情就是通知利益相关者 DAU 下跌不是真的。
- 如果到目前为止所有检查都是好的,请检查仪表板是否使用了来自数据库的计划提取,并确认提取成功运行。我遇到过提取失败的情况,这导致仪表板上有错误的数据。
2.数据
如果数据管道没有问题,下一步就是检查数据本身。虽然数据可以成功加载到数据库中,但这并不意味着数据值是好的。
- 校验表字段已填充,并且没有不应该缺少的值。例如,DAU 应该填充用户 ID 和日期。如果 SQL 代码按日期计算用户 ID 和分组,则缺少的值将影响查询结果。
- 检查表格字段的值是否正确。运行按降序排序的每个字段分组的计数,以检查是否有任何包含大量记录的意外值。我曾经有一个包含错误值的表,该表打乱了用于计算 KPI 的 SQL 逻辑。运行频率检查发现了这个问题。
- 检查控制面板中的筛选器和计算字段,以确认没有需要包含的新值。我曾经让一个供应商在没有任何通知的情况下添加新的事件值来替换现有的事件值,并且不得不更改仪表板逻辑来获得正确的数字。
3.外部因素
如果不是数据管道或数据问题,第三项检查是寻找任何可能导致 DAU 下降的外部因素。
- 检查 3 月 15 日是否有用户无法登录或注册账户的技术问题。
- 向产品经理核实是否有任何 3 月 15 日开始的实验会影响 DAU。我们曾经做过一个实验,导致应用程序在打开时立即崩溃,一旦产品团队意识到这个问题,他们就会恢复控制。崩溃导致 DAU 下降,因为用户几个小时内无法登录。
- 3 月 15 日,确认将用户导向网站的电子邮件或发送用户进入应用程序的推送通知已成功发出。我曾经看到 DAU 下降时,推送通知提醒打破,用户停止进入应用程序。
- 3 月 15 日,与工程部门确认网站是否有任何更改或应用程序是否有新版本。可能是网站或应用程序发布导致事件停止发送到后端,工程人员修复了它,但在此期间导致 DAU 数据下降。
对异常 KPI 变化进行故障排除可能是一个耗时的过程。我发现以上三个原因占了我调查的大部分案例。你的公司会有特定的边缘案例,但是现在你知道去哪里找了,我希望你尽快找到答案。
你可能也会喜欢…
数据科学家如何像数据工程师一样解决 ETL 问题
常见原因及其处理方法
图片来自 Pixabay 的erikawittleb
如果你是一名数据科学家,在你职业生涯的某个阶段,你必须解决 ETL 问题。如果您是 ETL 故障排除的新手,并且不清楚从哪里开始,这些是我作为数据工程师遇到的问题的常见原因以及如何处理它们。
1.所有的源数据都可用吗?
典型的 ETL 作业要么从原始文件加载源数据,要么从另一个系统将数据提取到临时表中。在下面的 ETL 管道示例中,三个数据文件被转换、加载到一个临时表中,并最终聚合到一个最终表中。ETL 失败的一个常见问题是缺少最近一天运行的数据文件。
如何处理:
如果数据来自外部来源,请与提供商核实并确认文件是否运行延迟。如果数据是内部数据,如应用程序事件或公司网站活动,请与负责团队确认是否存在可能导致数据延迟或丢失的问题。一旦您获得了丢失的数据,您的 ETL 问题就解决了。如果数据被延迟,一旦数据可用,您可能需要手动重新运行 ETL。
作者创建的示例 ETL 管道
2.上游 ETL 依赖项运行完毕了吗?
当数据库表缺少最近一天的数据时,您可能会收到 ETL 问题的警告。如果这是一个聚合表,则在更新该表之前,您很可能需要完成多个作业。
如何处理:
找到负责更新表的 ETL 管道。使用上面显示的示例 ETL 管道,从聚集表向后工作到暂存表,并确认每个步骤都成功完成。如果在第一步中没有验证,请检查最近一天的数据文件是否可用。一旦您确定了失败的阶段,从该点重新运行以确认表在下游被更新。
3.数据文件是否完全加载到数据库中?
有时候,由于我无法理解的原因,数据没有完全加载到数据库中😫。
如何处理:
在这些情况下,将原始文件的记录计数与暂存表进行比较,以验证数据是否不完整。当昨天和今天的数据之间的行数变化超过历史平均百分比时,我通常运行这个检查。从头重新运行 ETL 管道来重新加载原始文件应该可以解决这个问题。
4.数据文件是否包含意外值?
如果 ETL 的重新运行继续失败,就应该检查日志,以验证它是与最初的失败相同的错误消息还是新的错误消息。如果幸运的话,日志文件可能会指出文件中的哪个行号或字段导致了数据库加载错误。
如何处理:
我遇到的最常见的意外值是数值字段中的字符、非 ASCII 字符以及超出表模式中定义的字段长度的字段值。如何处理坏数据取决于您的数据库和可用的工具,但这只是几个选项。
对于非 ASCII 字符,您可以删除原始文件中的坏行,或者使用终端命令将它们从文件中删除,然后重新运行 ETL 作业。
对于超过字段长度的数据,如果您有数据库管理员权限,可以改变表模式来增加字段长度。
对于数值字段中的字符,您可以增加因错误数据而跳过的最大行数,或者创建一个新的临时表,使用字符而不是数值字段在加载前清除或过滤错误数据。
5.数据文件不完整吗?
检查数据文件的行数是否与过去的文件相似。如果低于预期,当天的数据可能不完整。这可能是由于事件停止发送到后端或计划的系统维护造成的。
如何处理:
请与数据提供商联系,确认数据是否确实丢失,或者是否需要发送包含所有数据的新文件。如果需要发送新文件,请在数据更新后重新运行 ETL。
6.数据文件包含预期的格式吗?
数据格式可能会发生意外变化,尤其是外部数据。将 ETL 代码期望的分隔符和字段顺序与最新的文件格式进行比较。
如何处理:
如果格式已更改,请向数据提供商确认。如果没有,等待更新的文件并重新运行现有的 ETL。如果是,请自己修改生产代码或创建一个数据工程票证来处理新的格式更改。
7.有重复的吗?
这种情况并不经常发生,但是重复数据可能会进入您的数据中,并引起很大的麻烦。
如何处理:
使用上面的同一个 ETL 管道示例,向后工作,检查聚合表、临时表和数据文件中的重复项。删除重复项,并从该点重新运行 ETL。
最后的想法
当我第一次成为数据工程师时,我不知道如何解决 ETL 问题。经过反复试验,我想出了一个常见原因的清单,以便在进入更不寻常的原因之前进行检查。这个列表解释了我过去的大部分问题,现在你知道该找什么了,我希望你的许多问题也能得到解决。
你可能也会喜欢…
</6-best-practices-i-learned-as-a-data-engineer-9d3ad512f5aa> </6-bad-data-engineering-practices-you-shouldnt-apply-as-a-data-scientist-58de5eca14c3> https://medium.com/swlh/how-i-used-a-machine-learning-model-to-generate-actionable-insights-3aa1dfe2ddfd
如何解决 Python 中的内存问题
行业笔记
一个在生产环境中使用开源工具修复泄漏程序的真实例子。
发现应用程序内存不足是开发人员可能遇到的最糟糕的情况之一。一般来说,内存问题很难诊断和修复,但我认为在 Python 中更难。Python 的自动垃圾收集功能使得使用这种语言变得很容易,但是它太擅长于置身事外了,以至于当它不像预期的那样工作时,开发人员会不知如何识别和修复问题。
在这篇文章中,我将展示我们如何诊断和修复由 Alteryx 创新实验室开发的开源 AutoML 库 EvalML 中的内存问题。没有解决内存问题的神奇秘方,但是我希望开发人员,尤其是 Python 开发人员,能够了解在将来遇到这类问题时可以利用的工具和最佳实践。
读完这篇博文后,你应该会有如下收获:
- 为什么发现并修复程序中的内存问题很重要,
- 什么是循环引用,为什么它们会导致 Python 中的内存泄漏,以及
- Python 内存分析工具的知识,以及您可以用来识别内存问题原因的一些步骤。
设置舞台
在发布新版本的包之前,EvalML 团队运行了一套性能测试,以捕捉任何性能退化。这些性能测试包括在各种数据集上运行我们的 AutoML 算法,测量我们的算法获得的分数以及运行时间,并将这些指标与我们之前发布的版本进行比较。
一天,我正在运行测试,突然应用程序崩溃了。发生了什么事?
步骤 0 —什么是内存,什么是泄漏?
任何编程语言最重要的功能之一是它在计算机内存中存储信息的能力。每次你的程序创建一个新的变量,它会分配一些内存来存储变量的内容。
内核为程序定义了一个接口来访问计算机的 CPU、内存、磁盘存储等等。每种编程语言都提供了要求内核分配和释放内存块的方法,以供正在运行的程序使用。
当一个程序要求内核留出一块内存来使用时,就会发生内存泄漏,但由于一个错误或崩溃,程序永远不会告诉内核它何时用完了那块内存。在这种情况下,内核将继续认为正在运行的程序仍在使用被遗忘的内存块,其他程序将无法访问这些内存块。
如果在运行程序时重复出现相同的泄漏,被遗忘内存的总大小会变得很大,以至于它会消耗计算机内存的很大一部分!在这种情况下,如果一个程序试图请求更多的内存,内核将引发“内存不足”错误,程序将停止运行,或者换句话说,“崩溃”
因此,在您编写的程序中找到并修复内存泄漏是非常重要的,因为如果您不这样做,您的程序最终可能会耗尽内存并崩溃,或者会导致其他程序崩溃。
步骤 1:确定是内存问题
应用程序崩溃的原因有很多——可能是运行代码的服务器崩溃了,也可能是代码本身有逻辑错误——所以确定眼前的问题是内存问题非常重要。
EvalML 性能测试以一种异常安静的方式崩溃了。突然,服务器停止记录进度,作业悄悄地完成了。服务器日志会显示由编码错误引起的任何堆栈跟踪,所以我有预感这个无声的崩溃是由使用所有可用内存的作业引起的。
我再次运行了性能测试,但是这次启用了 Python 的内存分析器来获得一段时间内的内存使用情况。测试再次崩溃,当我查看内存图时,我看到了这个:
EvalML 性能测试的内存配置文件。作者创建的图像。
随着时间的推移,我们的内存使用量保持稳定,但后来达到了 8gb!我知道我们的应用服务器有 8g 的 RAM,所以这个配置文件证实了我们的内存不足。此外,当内存稳定时,我们使用大约 4 GB 的内存,但我们以前版本的 EvalML 使用大约 2 GB 的内存。因此,出于某种原因,当前版本使用的内存是正常情况下的两倍。
现在我需要找出原因。
第二步:用一个最小的例子在本地重现内存问题
查明内存问题的原因需要大量的实验和反复,因为答案通常不是显而易见的。如果是,你可能就不会把它写进代码了!出于这个原因,我认为用尽可能少的代码行重现问题是很重要的。这个最小的例子使您可以在修改代码时,在一个分析器下快速运行它,以查看您是否取得了进展。
在我的例子中,我从经验中得知,我们的应用程序在我看到峰值的时候运行了一个有 150 万行的出租车数据集。我把我们的应用程序精简到只有运行这个数据集的部分。我看到了一个类似于我上面描述的尖峰,但这一次,内存使用量达到了 10gb!
看到这个之后,我知道有一个足够好的最小的例子来深入研究。
出租车数据集中本地再现器的内存占用。作者创建的图像。
第三步:找到分配最多内存的代码行
一旦我们将问题隔离到尽可能小的代码块中,我们就可以看到程序在哪里分配了最多的内存。这可能是你需要重构代码和修复问题的确凿证据。
我认为 filprofiler 是一个很好的 Python 工具。它显示应用程序中每行代码在内存使用峰值点的内存分配。这是我的本地示例的输出:
fil-profile 输出。作者创建的图像。
filprofiler 根据内存分配对应用程序中的代码行(以及依赖项的代码)进行排序。线越长越红,分配的内存就越多。
分配最多内存的行正在创建 pandas 数据帧(pandas/core/algorithms.py 和 pandas/core/internal/managers . py ),数据量达到 4gb!我在这里截断了 filprofiler 的输出,但是它能够在创建 pandas 数据帧的 EvalML 中跟踪 pandas 代码。
看到这个有点令人费解。是的,EvalML 创建了 pandas 数据帧,但是这些数据帧在整个 AutoML 算法中是短暂的,一旦不再使用就应该被释放。因为事实并非如此,而且这些数据帧仍然在内存中存在足够长的时间,所以我认为最新版本引入了内存泄漏。
步骤 4:识别泄漏物体
在 Python 的上下文中,泄漏对象是指在使用完之后不会被 Python 的垃圾收集器释放的对象。由于 Python 使用引用计数作为其主要的垃圾收集算法之一,这些泄漏的对象通常是由于对象持有对它们的引用的时间超过了它们应该持有的时间。
这些类型的对象很难找到,但是有一些 Python 工具可以让搜索变得容易处理。第一个工具是 gc。垃圾收集器的 DEBUG_SAVEALL 标志。通过设置这个标志,垃圾收集器将在 gc.garbage 列表中存储不可到达的对象。这将让您进一步研究这些对象。
第二个工具是 objgraph 库。一旦对象出现在 gc.garbage 列表中,我们就可以将这个列表过滤为 pandas 数据帧,并使用 objgraph 查看还有哪些对象正在引用这些数据帧并将它们保存在内存中。通过阅读这篇奥赖利的博客文章,我得到了这个方法的灵感。
这是我在可视化其中一个数据帧时看到的对象图的子集:
pandas 数据帧使用的内存图,显示了导致内存泄漏的循环引用。作者创建的图像。
这就是我一直在寻找的确凿证据!dataframe 通过一个叫 PandasTableAccessor 的东西对自己进行引用,这就创建了一个循环引用,所以这将把对象保存在内存中,直到 Python 的垃圾收集器运行并能够释放它。(可以通过 dict、PandasTableAccessor、dict、_dataframe 来追踪循环。)这对 EvalML 来说是个问题,因为垃圾收集器将这些数据帧保存在内存中的时间太长了,以至于我们耗尽了内存!
我能够追踪 PandasTableAccessor 到木工库,并把这个问题提交给维护人员。他们能够在新版本中修复它,并向 pandas 知识库提交相关的问题——这是开源生态系统中可能的合作的一个很好的例子。
木工更新发布后,我可视化了同一个数据帧的对象图,循环消失了!
木制品升级后的熊猫数据框对象图。不再有周期!作者创建的图像。
步骤 5 —验证修复是否有效
当我在 EvalML 中升级了木制品版本后,我测量了我们的应用程序的内存占用,我很高兴地报告说,现在的内存使用不到以前的一半!
修复后性能测试的记忆。作者创建的图像。
结束语
正如我在本文开头所说的,没有解决内存问题的神奇方法,但是这个案例研究提供了一个通用的框架和一套工具,如果您将来遇到这种情况,您可以利用这些工具。我发现 memory-profiler 和 filprofiler 是调试 Python 中内存泄漏的有用工具。
我还想强调的是,Python 中的循环引用会增加应用程序的内存占用。垃圾收集器最终会释放内存,但是,正如我们在本例中所看到的,也许直到为时已晚!
在 Python 中,循环引用非常容易被无意引入。我能够在 EvalML 中找到一个无意的一个、 scikit-optimize 和 scipy 。我鼓励你擦亮你的眼睛,如果你在野外看到一个循环引用,开始一个对话,看看它是否真的需要!
原贴于 Alteryx 创新实验室 博客
如何尝试 CLIP: OpenAI 的零拍图像分类器
本周早些时候,OpenAI 向计算机视觉世界投下了一颗炸弹——你现在可以在不需要培训的情况下进行图像分类。
(引用)
本周早些时候,OpenAI 向计算机视觉世界投下了一颗炸弹:两个新的突破性模型暗示了大规模 GPT3 式变形金刚模型侵占视觉领域的未来。虽然 DALL-E (一种可以从文本提示中生成图像的模型)在本周获得了很多关注,但这篇文章主要关注的是剪辑:一种可以说更加重要的零镜头分类器。
到目前为止,对图像进行分类涉及收集数百、数千甚至数百万张标记图像的自定义数据集,这些图像适当地代表了您的目标类别,并使用它来训练监督分类模型(通常是卷积神经网络)。这种方法(以及像物体检测这样的扩展)导致了计算机视觉在过去十年中的快速发展(为从无人驾驶汽车到增强现实的一切提供动力)。
监督训练的缺点是,结果模型不能很好地概括。如果你给他们看一张不同领域的图片,他们通常不会比随机猜测做得更好。这意味着您需要收集各种各样的数据,这些数据足以代表您的模型将在野外执行的确切任务。
输入 OpenAI 剪辑
最近推出的剪辑(对比语言-图像预训练)打破了这一范式。这是一个零射击模型,这意味着它可以识别前所未见的大量事物。
剪辑就像最好的 AI 字幕写手。它能够从 32,768 个样本字幕中说出图像中的内容。图片来源: OpenAI
在传统的分类器中,标签的意义被忽略了(事实上,它们经常被简单地丢弃,并在内部用整数替换)。相比之下,CLIP 创建其类的编码,并在超过 4 亿个文本到图像对上进行预训练。这使得它能够利用 transformer 模型从文本中提取语义的能力,在不根据自定义数据进行微调的情况下,对图像进行开箱即用的分类。
你所需要做的就是定义一个可能的类别列表,或者描述,CLIP 会根据它的先验知识来预测一个给定的图像最有可能属于哪个类别。把它想象成问模型“这些标题中哪一个最匹配这张图片?”
在本帖中,我们将演示如何在您自己的图像上测试 CLIP 的性能,这样您就可以获得一些硬数字,并直观地了解 CLIP 在各种用例中的实际表现。我们发现 CLIP 在一个 花分类 任务上比 我们定制训练的 ResNet 分类模型 **。**它在一系列更模糊和更具挑战性的任务中也表现得令人惊讶(包括从我们的相机胶卷中识别蘑菇品种,以及识别狗和猫的品种)。
本教程中的资源:
- 夹标杆 Colab 笔记本
- 夹回购
- 相应的 YouTube
组装数据集
要试用 CLIP,您需要带一组您想要分类的图像,并将其划分到您想要查看的类别中。
如果你还没有数据集,想尝试一下新技术,看看 Roboflow 的公共计算机视觉数据集。
在本帖中,我们将对公开的花卉分类数据集进行基准测试。如果使用你自己的数据,将你的数据上传到 Roboflow 很容易,而且是免费的(最多 1000 张图片),然后你可以在这个博客中遵循同样的流程。
一旦你组装好你的数据集,它就会被放到 CLIP benchmarking Colab 笔记本上。
本文中使用的示例花卉分类数据集
安装剪辑依赖关系
要尝试裁剪自己的数据,请在驱动器中复制一份笔记本,并确保在运行时下选择了 GPU(Google Colab 会给你一个免费的 GPU 供你使用)。然后,我们在克隆 CLIP Repo 的同时进行一些安装。
将数据集下载到 Colab
下一步是将分类数据集下载到 Colab 中。
下载分类数据到本帖笔记本
如果你在 Roboflow 中创建了一个数据集,这可以通过点击Generate
,然后点击OpenAI CLIP Classification
格式的Download
来实现。这将把所有的测试图像放在一个名为test
的文件夹中,并为数据集中的每个类提供单独的图像子目录,并为您提供一个_tokenization.txt
文件,让您尝试“快速工程”,这可以极大地提高或降低模型的性能。
我们还为对象检测数据集创建了一个转换器,它将从现有的边界框创建文本描述。我们得到了不同的结果,但是玩起来肯定很有趣。
此外,我们已经将所有的开源数据集以剪辑格式免费下载。
用剪辑推断类别标签
最后一步是通过预测步骤传递您的测试图像。
CLIP 接受一个图像和一个可能的类标题列表作为输入。您可以在_tokenization.txt
文件中定义您认为合适的类别标题。请确保它们与按字母顺序排序的class_names
(由文件夹结构定义)保持相同的顺序。
notebook包含迭代测试集中每个类文件夹的代码,并通过预测步骤传递相关图像。
实验本体和结果
当您使用 CLIP 执行分类任务时,为您的分类本体尝试不同的类标题是很有用的,请记住,CLIP 被训练来区分图像标题。
在 flowers 数据集上,我们尝试了以下本体并看到了这些结果:
"daisy" vs "dandelion"]
- > 46%的准确率(比猜测差)"daisy flower" vs "dandelion flower"
- > 64%的准确率"picture of a daisy flower" vs "picture of a dandelion flower"
- >准确率 97%
97%的准确率高于我们在这个数据集上训练的任何 其他分类模型 。
这些结果显示了提供正确的类描述来剪辑和表达预处理过程的丰富性的重要性,这是在传统的二进制分类中完全丢失的特征。OpenAI 将这一过程称为“提示工程”。
翻转脚本
CLIP 可能有许多额外的用例,包括根据目标查询字符串对图像进行排序,或者根据图像的独特性对图像进行排序。
在笔记本中,你会看到定义两个变量image_features
和text_features
的代码。任何一对特征之间的余弦相似性代表了它们的语义距离——从我们目前的经验来看,这是非常准确的。这只是早期…
结论
如果您发现 CLIP 的性能没有您希望的那么高,您可能仍然希望考虑在监督下训练一个自定义图像分类模型。
关于剪辑研究的更多信息,可以考虑阅读论文和查看 OpenAI 的博客文章。如果你在玩模型的时候发现了什么有趣的东西,我们很乐意听到!请务必在推特上给我们留言。
一如既往,推理快乐!
雅各布·索拉维茨
原载于 2021 年 1 月 8 日 https://blog.roboflow.com**的 。
如何调整机器学习的超参数
调整超参数是机器学习过程中的关键部分。继续读下去,学习一些有效而直观的方法。
尼克·希利尔在 Unsplash 上的照片
在机器学习算法中,有两种参数——模型参数和超参数。通过训练过程学习模型参数,例如神经网络的权重。超参数用于控制训练过程;因此,必须在训练开始前进行设置。深度学习中超参数的一些例子是学习速率和批量大小。许多机器学习实践者忽略的一个问题就是如何设置这些超参数。未能进行良好的超参数调整可能会抵消您构建模型的所有努力。幸运的是,有一种通用的启发式方法来挑选超参数。对于更复杂的情况,也有自动超参数选择方法。在本文中,我们将讨论这两个问题。
挑选超参数的一般方法
考虑超参数选择的一个好方法是在模型容量的背景下考虑。从广义上讲,我们所说的模型容量指的是我们的模型能够表现的功能的数量。理想情况下,我们希望选择超参数,以便我们的模型的容量正好适合手头的问题。换句话说,我们想要避免欠拟合或过拟合的超参数。从视觉上很容易看出这一点。如果您要绘制一个图,y 轴为测试误差,x 轴为一个超参数值,大多数情况下您会得到如下结果:
作者图片
太小或太大的超参数对应于太大或太小的模型容量,导致高测试误差。因此,为了最佳地设置超参数,我们需要推理该超参数的特定值对模型容量有什么影响。
让我们看一个这种推理的例子。一个常见的超参数是神经网络中的节点数。节点数量和模型容量之间的关系非常明显——更多的节点意味着更多的模型容量,反之亦然。如果我们怀疑我们的模型过度拟合,例如,如果我们注意到一个非常低的训练误差,但一个相当大的测试误差,我们知道模型容量可能太大了。因此,我们需要减少神经网络中的节点数量。如果我们看到拟合不足(可能是如果训练集和测试集都有很高的错误),我们知道模型容量太小,我们应该增加节点的数量。
现在让我们考虑另一个常见的超参数——重量衰减系数。权重衰减是神经网络的一种正则化形式,顾名思义,它使权重变小。权重衰减系数的影响也非常明显——衰减系数越高,权重越小,模型容量也就越小。因此,如果我们怀疑过度拟合,我们应该增加衰减系数,如果我们怀疑不足拟合,我们应该减少它。
然而,在某些情况下,超参数如何影响模型容量尚不清楚。深度学习中的学习率就是这样一个例子。在这些情况下,我们可以使用自动超参数调整方法。
两种自动方法:网格搜索和随机搜索
这些自动方法背后的基本原理很简单。让我们从一个简单的例子开始,我们的模型只有一个超参数。让我们假设我们知道这个参数的合理值在 0 和 1 之间(例如,强化学习问题中的ε)。我们想尝试一些值,看看哪个是最好的。最明显的做法是尝试类似[0,0.2,0.4,0.6,0.8,1]或[0,0.33,0.66,1]的东西。这种以均匀间隔尝试数值的想法被称为网格搜索。如果我们有多个超参数,我们会尝试每个均匀分布的单个参数的组合。例如,我们可能有两个参数,并想尝试每个参数的值[0,1,2]。那么我们的网格搜索将需要尝试(0,0)、(0,1)、(0,2)、(1,0)、(1,1)、(1,2)、(2,0)、(2,1)、(2,2)。网格搜索也可以在对数而不是线性标度上运行,例如[0,10(-3),10(-2),10^(-1),1]。
网格搜索的一个问题是,我们需要尝试的组合数量是超参数数量的指数级。因此,如果我们有多个超参数,网格搜索将需要很长时间来运行。也有可能不是所有的超参数都会影响模型。如果是这样的话,那么网格搜索不仅要花很长时间,而且还要浪费大量时间去寻找不影响性能的超参数的变化。
随机搜索解决了这两个问题。随机搜索分两步进行。首先,我们为每个超参数定义一个边际分布。然后,我们从组合分布中抽取随机值,并选择最佳值。随机搜索避免了指数运行时间问题——它凭借其随机性探索相同的空间。它还避免了时间浪费问题——由于其随机性,随机搜索不会在特定超参数的相同值上花费时间(这可能根本不会影响模型)。
从经验上看,这些改进似乎使 随机搜索比 **网格搜索更有优势。**因此,如果你想用一种自动的方法来选择你的超参数,我建议用随机搜索代替网格搜索。
我希望这篇文章让您对如何调优超参数有了更多的了解。许多超参数可以通过思考超参数如何影响模型容量来进行调整。对模型容量(例如学习率)有复杂影响的超参数,或者超参数的大量组合,可以用上述自动方法进行调整。对于这些情况,我的建议是随机搜索。
请随时留下任何问题/评论。感谢阅读!
如何调整机器学习模型的超参数
使用来自 envato 元素的 BoykoPictures 的图像创建(经许可)。
数据科学 | 机器学习
使用 Scikit-learn 的分步教程
通常情况下,您会使用默认参数来构建机器学习模型。只需几段代码,您就可以为您的机器学习模型搜索最佳超参数。为什么?因为最佳的超参数集可以大大提高模型的性能。
在本文中,您将学习如何使用 scikit-learn 库在 Python 中执行随机森林模型的超参数调优。
注: 本文灵感来源于我前段时间做的一个 YouTube 视频(Python 中机器学习模型的超参数调优 )。
1.超参数
在应用机器学习中,调整机器学习模型的超参数代表了尽可能实现最佳性能的有利可图的机会。
1.1.参数与超参数
现在让我们定义什么是超参数,但在此之前,让我们考虑一下参数和超参数之间的区别。
参数可以被认为是模型固有的或内部的,并且可以在模型从数据中学习之后获得。参数的例子是线性回归中的回归系数、支持向量机中的支持向量和神经网络中的权重。
超参数可以被认为是模型的外在或外部参数,可以由从业者任意设置。超参数的例子包括 k-最近邻中的 k、随机森林中的树的数量和特征的最大数量、神经网络中的学习速率和动量、支持向量机中的 C 和 gamma 参数。
1.2.超参数调谐
由于没有通用的最佳超参数可用于任何给定的问题,超参数通常被设置为默认值。然而,超参数的最佳集合可以从手动经验(试错法)超参数搜索中获得,或者通过使用优化算法来最大化适应度函数以自动方式获得。
两种常见的超参数调谐方法包括网格搜索和随机搜索。顾名思义, 网格搜索 需要创建可能的超参数值的网格,从而以强力方式为所有这些超参数组合迭代构建模型。在 随机搜索 中,不是所有的超参数组合都被使用,而是每次迭代使用一个随机超参数组合。
比较两种常用超参数调整方法的示意图:(1)网格搜索与(2)随机搜索。作者绘制的图像。
此外,随机优化方法也可用于超参数调整,其将以算法方式自动导航超参数空间,作为损失函数(即性能度量)的函数,以便监控模型性能。
在本教程中,我们将使用网格搜索方法。
2.资料组
今天,我们既不使用虹膜数据集,也不使用企鹅数据集,而是要生成我们自己的合成数据集。但是,如果您想继续使用您自己的数据集进行替换,那就太好了!
2.1.生成合成数据集
2.2.检查数据集维度
现在让我们检查数据集的维度
这将给出以下输出:
((200, 10), (200,))
其中(200, 10)
是 X 变量的维度,这里我们可以看到有 200 行和 10 列。至于(200,)
,这是 Y 变量的维度,表示有 200 行和 1 列(没有显示数值)。
3.数据分割
3.1.检验训练集的维数
现在让我们检查一下训练集(80%子集)的维度。
这将给出以下输出:
((160, 10), (160,))
其中(160, 10)
是 X 变量的维数,这里我们可以看到有 160 行和 10 列。至于(160,)
,这是 Y 变量的维度,表示有 200 行 1 列(没有显示数值)。
3.2.检验训练集的维数
现在让我们检查一下测试集的维度(20%子集)。
这将给出以下输出:
((40, 10), (40,))
其中(40, 10)
是 X 变量的维数,这里我们可以看到有 40 行 10 列。至于(40,)
,这是 Y 变量的维度,表示有 40 行 1 列(没有显示数值)。
4.构建基线随机森林模型
这里,我们将首先构建一个基线随机森林模型,该模型将用作基线,以便与使用最佳超参数集的模型进行比较。
对于基线模型,我们将为 2 个超参数(例如n_estimators
和max_features
)设置一个任意数字,我们也将在下一节中使用该数字进行超参数调整。
4.1.实例化随机森林模型
我们首先导入必要的库,并将随机森林分类器分配给 rf 变量。
4.2.训练随机森林模型
现在,我们将应用随机森林分类器,使用训练数据上的rf.fit()
函数(例如X_train
和Y_train
)来构建分类模型。
模型定型后,会出现以下输出:
之后,我们可以应用训练好的模型(rf
)进行预测。在上面的示例代码中,我们应用模型来预测训练集(X_test
),并将预测的 Y 值赋给Y_pred
变量。
4.3.评估模型性能
现在让我们来评估模型性能。这里,我们计算 3 个性能指标,包括准确性、马修斯相关系数(MCC)和受试者工作特征曲线下面积(ROC AUC)。
5.超参数调谐
现在,我们将对随机森林模型的超参数进行调整。我们将调整的两个超参数包括max_features
和n_estimators
。
5.1.代码
应该注意的是,下面显示的一些代码改编自 scikit-learn 。
5.2.代码解释
首先,我们将导入必要的库。
scikit-learn 的GridSearchCV()
功能将用于执行超参数调谐。特别需要注意的是,GridSearchCV()
功能可以执行分类器的典型功能,如fit
、score
、predict
以及predict_proba
、decision_function
、transform
和inverse_transform
。
其次,我们定义了作为GridSearchCV()
函数必要输入的变量,这包括 2 个超参数(max_features_range
和n_estimators_range
)的范围值,然后将其作为字典分配给param_grid
变量。
最后,打印出最佳参数(grid.best_params_
)及其对应的度量(grid.best_score_
)。
5.3.性能指标
GridSearchCV()
的默认性能指标是准确性,在本例中,我们将使用 ROC AUC。
为了以防万一,您想知道可以使用哪些其他性能指标,运行以下命令来找出答案:
这将打印以下受支持的性能指标:
因此,在本例中,我们将使用 ROC AUC,并在GridSearchCV()
函数中设置输入参数scoring = 'roc_auc'
。
5.4.超参数调整的结果
第 5.1 节代码的第 14–15 行打印了性能指标,如下所示:
其表明最优或最佳超参数集具有 3 的max_features
和 60 的n_estimators
,ROC AUC 分数为 0.93。
6.调谐超参数的数据可视化
让我们首先来看看底层数据,稍后我们将使用它进行数据可视化。超参数调整的结果已被写出到grid.cv_results_
,其内容显示为如下所示的字典数据类型。
***grid.cv_results_***.
内容截图
6.1.准备数据帧
现在,我们将有选择地从grid.cv_results_
中提取一些数据,以创建一个包含 2 个超参数组合及其相应性能指标的数据框架,在本例中是 ROC AUC。特别地,下面的代码块允许组合 2 个超参数(params
)和性能度量(mean_test_score
)。
输出为以下数据帧,其中 3 列由max_features
、n_estimators
和ROC_AUC
组成。
包含超参数组合及其相应性能度量值的串联数据帧的输出屏幕截图。
6.2.重塑数据框架
6 . 2 . 1。分组列
为了将上述数据框可视化为等高线图(即 2D 或 3D 版本),我们首先需要重塑数据结构。
在上面的代码中,我们使用来自pandas
库的groupby()
函数根据两列(max_features
和n_estimators
)对数据帧进行分组,从而合并第一列(max_features
)的内容。
6 . 2 . 2。旋转数据**
通过将数据旋转到 m ⨯ n 矩阵中,数据被重新整形,其中行和列分别对应于max_features
和n_estimators
。
上面的代码块产生了下面的整形数据帧。
已准备好绘制等值线图的整形数据框的屏幕截图。
最后,我们将整形后的数据分配给各自的x
、 y
和z
变量,这些变量将用于绘制等高线图。
6.3.制作 2D 等高线图
现在,有趣的部分来了,我们将通过使用 Plotly 绘制 2D 等高线图,可视化我们正在调整的 2 个超参数的景观及其对 ROC AUC 分数的影响。前述x
、 y
和z
变量用作输入数据。
上述代码块生成以下 2D 等高线图。
6.4.制作 3D 等高线图
这里,我们将使用 Plotly 创建一个交互式 3D 等高线图,使用x
、y
和z
变量作为输入数据。
上述代码块生成以下 3D 等高线图。
2 个超参数相对于性能指标 ROC AUC 的 3D 等高线图的屏幕截图。
结论
恭喜你!您刚刚执行了超参数调优,并创建了数据可视化。希望您能够提高您的模型性能,与默认值相比。
下一步是什么?在本教程中,您已经研究了两个超参数的调优,但这还不是全部。对于随机森林模型,您还可以调整其他几个超参数。您可以查看来自scikit-learn
的 API,获得一个可以尝试的超参数列表。
https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
或者,您可以使用本文中描述的代码作为起始模板,尝试为其他机器学习算法调整超参数。
在评论里让我知道,你在做什么好玩的项目!
订阅我的邮件列表,获取我在数据科学方面的最佳更新(偶尔还有免费赠品)!
关于我
我是泰国一所研究型大学的生物信息学副教授和数据挖掘和生物医学信息学负责人。在我下班后的时间里,我是一名 YouTuber(又名数据教授)制作关于数据科学的在线视频。在我制作的所有教程视频中,我也在 GitHub 上分享 Jupyter 笔记本(数据教授 GitHub page )。
https://www.youtube.com/dataprofessor
在社交网络上与我联系
✅YouTube:http://youtube.com/dataprofessor/
♇网站:http://dataprofessor.org/(在建)
♇LinkedIn:https://www.linkedin.com/company/dataprofessor/
♇Twitter:https://twitter.com/thedataprof/
♇Facebook:http://facebook.com/dataprofessor/
♇github:https://github.com/dataprofessor/
♇Instagram:)
如何用 GridSearchCV 一次调优多个 ML 模型?
加快您的型号选择工作流程
模型选择是数据科学模型开发流程的重要组成部分。在执行特征工程之后,数据科学家需要选择具有最佳超参数集的模型,该模型对于训练数据集表现最佳。有各种自动化模型选择组件的 Auto-ML 库。
网格搜索是一种交叉验证技术,可用于调整机器学习模型的超参数。为了从 ML 模型列表中选择稳健模型,需要对每个模型进行多次交叉验证。在本文中,我们将讨论使用网格搜索和随机搜索交叉验证同时调优多个模型的技巧。
什么是网格搜索和随机搜索交叉验证?
GridSearchCV 或 RandomizedSearchCV 是交叉验证技术,用于执行超参数调整,以确定机器学习模型的最佳值。理想情况下,GridSearchCV 会尝试所有可能的参数值,而 RandomizedSearchCV 会随机选取参数并加速交叉验证工作流。
(作者代码),GridSearchCV 实现
上述代码片段可用于为随机森林分类器模型选择最佳超参数集。
理想情况下,GridSearchCV 或 RandomizedSearchCV 需要为多个机器学习模型运行多个管道,以挑选具有最佳超参数值集的最佳模型。数据科学家可能会花很多时间来开发代码并研究它。
通过创建多个参数字典并为每个字典指定模型,可以使用 GridSearchCV 或 RandomizedSearchCV 同时调整多个机器学习模型。一次调优多个模型的逐步方法是:
- 初始化多分类器估计器
- 准备第一个分类器的管道。
- 准备每个估计量的超参数字典,每个估计量都有一个作为“分类器”的关键字和作为估计量对象的值。超参数键应该以分类器的单词开始,用“__”分隔(双下划线)。
- 列出超参数字典。
- 使用管道和参数字典列表训练 GridSearchCV 模型。
实施:
(作者代码)
我使用了一个包含大约 5000 个实例和 29 个独立特征的样本二元分类数据集。为了训练一个健壮的机器学习模型,我已经初始化了 7 个机器学习估计器,包括:
- 随机森林
- 支持向量分类器
- 逻辑回归
- 决策图表
- k-最近邻
- 朴素贝叶斯
- 梯度推进
并进一步用变量名**param_i**
准备了它们对应的超参数字典。
Scikit-learn 包附带了 GridSearchCV 实现。我已经将带有管道和参数字典列表的第一个估计器传递给 GridSearchCV 模型。
GridSearchCV 需要 120 秒来训练 7 个估计器的 176 个模型。具有**C=10**
、**class_weight=None**
、**、**的支持向量分类器表现最好,交叉验证 ROC AUC 得分为 0.984,测试 ROC AUC 得分为 0.979。
RandomizedSearchCV 模型需要 9 秒来训练同一组模型。相同的支持向量分类器产生执行最好的结果。
结论:
在本文中,我们讨论了 GridSearchCV 和 RandomizedSearchCV 如何用于同时调优多个机器学习模型。这是一种非常方便的技术,可以加快模型选择工作流程。
参考资料:
[1] Scikit-learn 文档:https://sci kit-learn . org/stable/modules/generated/sk learn . model _ selection。GridSearchCV.html
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。
https://satyam-kumar.medium.com/membership
感谢您的阅读
如何把茱莉亚变成 Python!
如何在 Julia 编程语言中使用面向对象编程范式?
介绍
Julia 是一门相当新的编程语言,科学界的大多数人可能都很熟悉,或者想要熟悉它。Julia 编程语言有许多优点,这使它成为一门非常好的语言。虽然 Julia 传统上被认为是一种更函数式的编程语言,但使用一些 Julia 的酷技巧——如外部构造函数和令人难以置信的动态类型语法,我们实际上可以使编程语言非常快速和非常有效地成为面向对象的语言!
为什么要让 Julia 成为面向对象的编程语言?鉴于面向对象编程语言的流行,很容易理解为什么程序员可能最终想要使用支持这种范式的语言。子类型输入是很棒的,而且课程让很多事情变得轻而易举。虽然我们可能需要改变 Julia 中的一些东西,因为我们只是简单地使用内部和外部构造函数,并将我们的方法类型传递到一个结构中,但高级语法最终将保持不变。这意味着除了使用 Julia 之外,您还可以使用这种方法用这种语言重新创建您喜欢的 Python 包!
构造器
当然,为了让内部和外部构造函数更有意义,我们还需要看看我们通常认为的 Julia 语言中的构造函数。这当然是一种被构造成包含其他数据类型的类型。您可以将任何构造的类型视为保存数据类型的容器。在 Julia 中,我们为此使用 struct:
struct exampleend
正如人们可能想象的那样,数据被定义为带有回车的变量名:
struct example
x
y
end
我们刚刚创建的是一个外部构造函数。这是一种很好的方法,可以使构造的类型只需要保存将来可能通过方法传递的数据。然而,通常当我们想要一个类型返回时,我们不希望该类型只包含我们提供的数据,而是为我们获取它。考虑下面的例子,它是一个正态分布:
struct NormalDistribution
mu
sigmaend
当然,最终用户总是可以在其他地方计算他们的均值和标准差,然后输入:
using Lathe.stats: mean, stdstruct NormalDistribution
mu
sigmaendnorm = NormalDistribution(mean(x), std(x))
但是我们也可以通过简单地添加一个内部构造函数来更好地完成这项工作。为了添加内部构造函数,我们需要在这个结构中定义一个新函数。我们将使用 new()方法从这个内部构造函数返回新构造的类型。我们的构造函数将获取一个数组并从中返回一个正态分布:
struct NormalDistribution
mu::Float64
sigma::Float64
function NormalDistribution(x::Array)
return new(mean(x), std(x))
endend
现在,如果我们调用我们的正态分布,并为它提供一个位置参数,这个位置参数恰好是一个数组,我们将得到一个正态分布的返回,其中包含该数组的平均值和标准差。这可能开始看起来像一个类,因为我们有一个下面有函数的构造函数,但是这不是我们将要调用的函数。
面向对象的程序设计(Object Oriented Programming)
我们将使用一种新的方法来应用这个分布的概率函数,简称 pdf。正态分布的 pdf 非常简单,只需要我们减去平均值,然后除以数组中每个值的标准差。我们可以在 Julia 中用一行 for 循环来实现,就像这样:
**pdf(xt) = [i = (i-μ) / σ for i in xt]**
现在我们可以将它添加到之前的内部构造函数中:
struct NormalDistribution
mu::Float64
sigma::Float64
function NormalDistribution(x::Array)
**pdf(xt) = [i = (i-μ) / σ for i in xt]**
return new(mean(x), std(x))
endend
这将在这个函数的私有范围内定义 pdf()方法(将来,这个类型。)然而,问题是该类型现在对这个新的 pdf()方法一无所知,我们希望它成为它的子方法。第一步是设置变量类型。我们可以使用{}语法做到这一点。然后,我们将把一个新的数据类型 pdf 转换为该变量类型:
struct NormalDistribution{P}
mu::Float64
sigma::Float64
pdf::P
现在,我们需要做的就是在内部构造函数的返回中更改 new()方法调用,以包含 pdf()方法的类型,并向外部构造函数提供 pdf()方法:
function NormalDistribution(x::Array)
pdf(xt::Array) = [i = (i-μ) / σ for i in xt]
return new**{typeof(pdf)}**(mean(x), std(x), **pdf**)
end
现在,我们可以使用正态分布获得正态分布数据,就像我们在 Python 之类的东西中处理类似的对象一样!
x = [5, 10, 15, 20]
dist = NormalDistribution(x)
scaled_data = dist.pdf(x)
结论
我真的希望您喜欢这篇关于如何使用内部和外部构造函数使 Julia 编程像 Python 一样面向对象的概述!Julia 语言的伟大之处在于,这仅仅是一种选择,就方法论而言,它是选项海洋中的一条鱼。这不仅完全改变了范式,而且实际上非常有效!感谢您的阅读,祝您有美好的一天!
如何将你无聊的图表变成电子游戏
轻松将 R 图转换成游戏关卡的教程。高管们再也不会在你演讲的时候睡觉了。我保证。
图片作者。这是数据科学人,我们即将打造的游戏的主角。
有些英雄穿斗篷。其他英雄可能有活塞,剑,火箭发射器,或重力枪。
但不是我们的英雄。
不,我们的英雄 dual 挥舞着他传奇的笔记本电脑和 TI-83 计算器。我们的英雄用事实、数字和机器学习模型武装起来,将在 4 年内将利润率提高 1.2%。
这是数据科学人。
数据科学人在这里拯救你的图表,使其免于在你的观众心目中被归档为“无聊且易被遗忘”的可怕命运。
在本教程中,我们将使用 R 的 ggplot2 库绘制一家公司的股票价格,然后在 Unity 中将它轻松转换为实际的视频游戏。你将控制数据科学的人,因为他跌倒,跌跌撞撞的山下降的利润。
只是想玩游戏?滚动到文章底部的游戏网页链接,玩得开心!
是时候提升您的数据科学技能了!我们开始吧!
游戏计划
数据科学人总是有计划的,你也应该有!这是我们将要做的,按照我们将要做的顺序。
- 获取 Unity Systems Inc (U)去年的股价数据。这也恰好是制作 Unity 3D 的公司,我们将使用该软件制作游戏。
- 创建该股票价格数据的 ggplot2 折线图。这将有标签,日期,轴等。这将是游戏的‘水平’。
- 创建该股票价格的 ggplot2 面积图。这将是一个没有标签的透明背景上的黑色图表。它将成为数据科学人行走的无形地面。
- 将两个图表和上面的数据科学人绘图添加到一个新的 Unity 项目中。我们将添加一些代码使他移动。这看起来就像一个小人在你的星盘上奔跑。会很棒的。
- 你将说服你的老板,这是仪表板的未来,并获得制作视频游戏的报酬。
在 R 中建立关卡
获取一家公司的股价数据很容易,所以我们不要在这上面花太多时间。我们想要 Unity 系统公司去年的股票价格。我喜欢使用 Pythons 的 yfinance 库,因为它易于使用并且有很好的文档记录。这里有一个链接 到提取数据的 python 代码。你也可以从数百个免费提供股票数据的网站中下载。这里有一个链接到我们将要使用的数据 。
首先创建一个新的 R 项目和 R 脚本,并将股票数据 csv 放入同一个文件夹。r 项目允许我们使用相对路径,这对于教程来说非常好。顺便说一下,我的整个 R 项目可以在 GitHub 上找到,以防你觉得懒。
让我们从数据的主图表开始。这将是我们游戏的“水平”:
图片作者。
我们的第一个图表有标题、标签和日期。我们使用 tidyverse 库来选择我们想要的数据(时间和价格),然后使用 ggplot2 来制作线图。我们手动将 y 轴限制设置为 0–180。我们为两个图形手动执行此操作,因此它们的大小大致相同。
不幸的是,我们不能把这个图表导入到像 Unity 这样的游戏引擎中,让它作为一个关卡来使用。对 Unity 来说,这只是另一个图像,引擎不知道图表的线应该是地板,或者这个图像应该以任何特殊的方式进行交互。
在 Unity 中,游戏的边界被称为碰撞器。数据科学人的脚上会有一个对撞机,这个会和地板上的对撞机相互作用,给人一种在地上行走的感觉。
Unity 可能无法区分我们的图形中的线条和图像中的任何其他特征,但它确实有能力轻松地用仅由一个特征组成的整个图像制作碰撞器!我们所需要的是我们的图形在透明背景上的完全黑色版本,然后 Unity 将能够检测我们的图形的边界,并通过单击 1 个按钮创建一个地板!
幸运的是,ggplot2 非常棒,允许我们对任何图形做任何我们想做的事情。数据科学家对您的 n00b 友好开箱即用的仪表板解决方案嗤之以鼻!
这与之前的折线图相同,但使用了面积。我们还使用一些主题参数来删除图表中的所有内容(标签、刻度、背景颜色等)。).我们剩下的只是透明背景上的面积图,这意味着背景可能看起来是白色的,但实际上什么都没有。酷毙了。
图片作者。现在这是一个楼团结可以承认!
请注意,该形状与我们的折线图的形状相同。我们需要做的就是把面积图变成 Unity 中的碰撞器,把它和我们原来的折线图对齐,然后让它隐形!烟雾和镜子。
最后,我们将这两个图形保存到 images 文件夹中。
从静止到统一。把我们的图表变成一个水平。
首先,您需要在电脑上安装 Unity 3D。Unity 是免费的,你可以在这里下载。完成后,启动 Unity 并点击“新建”,然后创建一个名为“数据科学人”的项目。选择“2D”作为模板。
图片作者。
一旦你点击“创建”,你应该在统一编辑器内。如果这是你第一次使用 Unity,不要感到害怕。如果你按照我的步骤,你会得到游戏的工作。如果你觉得你需要学习更多,也有数百个针对初学者的 Unity 教程!
在主窗口的右下角,你会看到一个名为“资产”的文件夹。让我们把所有需要的图片都拖到这个文件夹里。您可以一次将多个文件从电脑直接拖到“资源”文件夹。
图片作者。
我们将使用的所有图片都位于GitHub 文件夹中。只需将它们全部下载到您的计算机上,然后放入 Unity。它们包括:
- 我们在 R 中做的折线图
- 我们在 R 中制作的面积图
- 数据科学人
- 一个叫做“地板”的红色方块
- 一个玩家动作脚本。这是让数据科学人心动的代码!
图片作者。将文件从电脑上的“图像”文件夹拖到 Unity 中的“资产”文件夹。
将白色“股价线”图拖到场景窗口。
图片作者。将白色折线图拖到场景中。
将黑色的“StockPriceArea”图像拖到场景窗口中。
图片作者。将黑色区域图拖到场景视图中。
现在,如果黑色面积图在白色折线图的上面,就像上面的截图一样,那就很好。如果黑色图表位于白色图表下方,只需点击场景视图中的黑色区域图表,并查看 Unity 右侧的检查器选项卡。找到“位置”并将 Z 值更改为-1。
图片作者。只有当黑色图表位于白色图表下方时,您才需要修改此设置。
接下来,您需要将面积图与折线图对齐。为此,您可以结合使用屏幕左上角的“缩放”和“移动”工具。不一定要精确,但你希望波峰和波谷尽可能排成一行。
图片作者。首先单击您的面积图,然后使用这两个工具来对齐它们。
图片作者。这些是要拖动的手柄。不一定要完美,足够接近就好。
现在是魔法酱的时候了。这是我们在 R 中所做的一切的目的,也是让我们能够将你们自己公司的数据转化为视频游戏水平的原因。点击场景视图中的黑色区域图,回到右边的检查器窗口。在底部,点击“添加组件”并输入“多边形”。选择“多边形碰撞 2D”。
图片作者。选择多边形碰撞器 2D。
嘣!!看看吧!
图片作者。
因为 ggplot2 允许我们自定义图表,我们认为合适,并把清晰的黑色形状放在透明的背景上,Unity 能够检测图表的边界,以创建多边形!这意味着这现在是我们视频游戏中的工作层。
这和你以前玩过的任何 2D 平台游戏中的山没有什么不同。但是你想一想……在二维空间里,一座山除了一系列间隔不一、坡度上下不一的数据点还能是什么?归根结底都是数学,伙计。自然界的一切都只是信息,从山坡到你细胞中的原子。我是不是陷入了二维空间?悖论!
哲学够了!
将数据科学人带入生活
现在我们有了一个关卡,是时候把数据科学家放进去,让他动起来了!
图片作者。把数据科学家拖到图表上!
现在数据科学家已经到了我们的水平,让我们在他的脚下添加一个物体,这样他就可以在地上行走了。在左侧的层次视图中右键单击“DataScienceMan ”,然后单击“创建空”。这就创建了一个空的游戏对象,它附属于我们的主角。
图片作者。右键单击数据科学人,然后单击创建空
将此对象重命名为“Origin”。然后使用移动工具,并调整它,使我们的新对象在我们的英雄的脚下。这将与我们的 R 图发生冲突,并使他看起来像是在我们的数据上行走(和跌倒)!
图片作者。
为了让我们的英雄移动,我们需要给他添加一个移动脚本。这个脚本在我们的 images 文件夹中,所以您应该已经把它拖到项目中了。我们需要做的就是将这个脚本从我们的 assets 文件夹拖到层次视图中的 DataScienceMan:
图片作者。将 Move.cs 拖动到“DataScienceMan”中。
现在是时候给数据科学人添加一些组件了。我们快完成了!点击层次视图中的 DataScienceMan,查看检查器。单击“添加组件”并键入“刚性”。从下拉菜单中选择“刚体 2D ”:
图片作者。添加刚体 2D 组件。
在 unity 中,给像 Data Science Man 这样的游戏对象添加新的组件会赋予它新的属性。刚体 2D 组件允许我们的角色受物理影响!不相信我?点击顶部的 play,看着他直接从地板上摔下来。
图片作者。这是播放按钮,它播放游戏。谁能想到呢?
地心引力正在把他往下拉!但是为了让他击中我们的图表并坚持下去,我们需要添加最后一个组件。点击“添加组件”并键入“box”,然后选择 BoxCollider2D:
图片作者。向 DataScienceMan 添加一个箱式碰撞器 2D 组件。
现在,如果你点击 play,我们的角色就会移动并站在我们的图上。只有一个问题,数据科学家是巨大的!让我们把他缩小一点,让他看起来像站在一座山上,而不是一个小山丘。
图片作者。数据科学人太大了。
再次点击“数据科学人”并返回到检查员。将他的 x 和 y 比例值设置为 0.5。现在他只有以前的一半了!
图片作者。缩放 x 和 y 改变他的尺寸。如果 DataScienceMan 出现在游戏中的物体后面,降低他的 z 位置会让他出现在前面。
数据科学家还有最后一件事要做。将我们创建的“原点”对象拖动到他的移动脚本的“光线原点”参数上。这是告诉我们的脚本,我们想用它作为他的脚!
图片作者。像这样拖动原点到移动脚本上。
你现在有一个工作的视频游戏!单击顶部的播放按钮查看。“A”键左移,“D”键右移,空格键跳跃!如果他掉下关卡,“R”键会重置游戏。
现在,当你跳跃的时候,数据科学人就像是发射到了外太空。我们可以做一些清理工作,让我们的游戏更有趣一点。
清理美学
首先,让我们摆脱面积图。这意味着是他的看不见的地面,我们希望他看起来像是在有标签的线图上走来走去。只需点击场景或层次视图中的黑色区域图,进入检查器并取消选中“精灵渲染器”。
图片作者。取消选中面积图的 sprite 渲染器。
这意味着图像不再被绘制,但是物体(以及碰撞器)仍然在那里。
好了,还有最后两件事要做。抓住红色的“地板”图像,并将其拖动到图表上方。使用缩放和移动工具将其拉伸到图表上方。在该对象的检查器中,单击“添加组件”,然后像我们处理数据科学人对象一样,在它上面放置一个 2D 碰撞器。
图片作者。将地板图像添加到游戏中,并在上面设置一个 2D 碰撞器。
这个对撞机将阻止数据科学人跳跃到达轨道。最后一步是调整相机,使其恰到好处。你可以点击“游戏”视图(它就在我们一直使用的“场景”视图旁边)来查看相机视窗。点击层次视图中的“主摄像机”并查看其检查器。
图片作者。游戏视图将向您展示摄像机看到的内容。使用此视图调整摄像机。
图片作者。点击“主摄像头”并调整它的“大小”来移动摄像头。位置 x 和 y 将上下左右移动它。滴管会将背景设置为与您的图表相同(先点按滴管,然后点按您的图表)。
选择了“游戏”视图(不是“场景”!)调整“大小”字段,直到图表刚好在视图中。确保我们的红色天花板不可见。最后,单击“背景”右边的滴管,并单击图表中的某个位置,使背景与我们的图表相匹配。
就是这样!你现在可以在我们的 R ggplot2 图表上行走、跳跃和翻滚了。当他从屏幕上掉下来时,只要按“R”就可以让他复活!
可能性是无限的
这是游戏能做到的最简单的事情了。但是停下来想象一下所有的可能性。我们每天使用的许多图表将会成为可爱的视频游戏。
旋转甜甜圈图作为刀片,条形图作为跳转的壁架,在树状图中滑行,在气泡图中浮动,甚至不要让我开始使用径向条形图和重力!
我保证我们会在以后的文章中做到这些。数据科学人的冒险才刚刚开始!
如果你时间紧迫,只想玩这个游戏,我已经在这里上传了它的网页版。尽情享受吧!
这个项目的所有代码包括 R 项目,制作游戏所需的图像,以及 Unity 项目都可以在 GitHub 上获得。
数据科学人永远遵循规律。这就是大数定律。你知道吗,在一篇文章中,你最多可以点击鼓掌按钮 50 次!