TowardsDataScience-博客中文翻译-2020-七-

TowardsDataScience 博客中文翻译 2020(七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

为什么您需要在部署后管理 ML 模型

原文:https://towardsdatascience.com/a-beginners-guide-to-machine-learning-model-monitoring-36bf7faf3616?source=collection_archive---------15-----------------------

机器学习模型监控初学者指南

图片由穆罕默德·哈桑拍摄,来自皮克斯拜

目录

  1. 简介
  2. 什么是模型监控
  3. 为什么模型监控很重要
  4. 模型监控中的指标

介绍

机器学习(ML)模型的生命周期非常长,而且它肯定不会在你建立模型后结束——事实上,这只是开始。一旦你创建了你的模型,下一步就是生产你的模型,这包括部署你的模型并监控它。虽然这听起来成本很高,但为了从 ML 模型中获得最大价值,在使用模型的过程中监控模型是非常必要的。

想象一下监控一个 ML 模型,就像你想做年度体检或定期给你的车换油一样。模型建模是一项操作任务,它允许您检查您的模型是否发挥了最佳性能。

在本文中,您将了解什么是模型监控,以及为什么它对于生产化模型如此重要。

什么是模型监控

模型监控是机器学习生命周期中的一个操作阶段,在模型部署之后,它需要“监控”您的 ML 模型,例如错误、崩溃和延迟,但最重要的是,确保您的模型保持预定的预期性能水平。

为什么模型监控很重要

为什么模型监控很重要的简单答案是,随着使用时间的推移,您的模型会退化,这被称为模型漂移。模型漂移,也称为模型衰减,指的是由于各种原因(我将在下面解释)导致的模型预测能力的退化。

看不见的数据

一般来说,机器学习模型仅在域内数据总人口的大约百分之十的样本大小上进行训练[1],并且通常是由于标记数据的稀缺或训练大量数据的计算限制。虽然构建机器学习模型是为了减少偏差并能够归纳数据,但总会有模型输出不正确、不准确或低于标准的数据样本。

环境的变化和变量之间的关系

人们经常忘记的是,模型是基于其创建时的变量和参数进行优化的,ML 模型也不例外。想象一下 20 年前创建的垃圾邮件检测模型现在会如何运行。二十年前,互联网还不算什么!垃圾邮件变得越来越复杂,变化也越来越大,因此人们可能会怀疑垃圾邮件检测模型是否能够发挥作用。这是环境变化的一个例子。

影响模型环境及其变量之间关系的另一个因素是我们对数据的解释。例如,十年前创建的情感模型可能会错误地对各种单词和短语的情感进行分类,因为我们说话的方式、我们使用的单词和我们开发的俚语会随着时间不断变化。你再也听不到有人用古英语说话了,是吗?

上游数据变更

这指的是数据管道中的操作数据变化。实际上,这很常见,因为数据科学团队或部门通常无法控制输入数据来自的每个系统。例如,一个完全孤立的软件工程团队可能会将一个变量的度量单位从摄氏温度改为华氏温度,尽管其余的数据是以摄氏温度存储的。例如,如果一个人试图找到平均温度,这可能会导致严重的后果。上游数据更改的一个更简单的例子是不再生成要素,从而导致丢失值。

总体而言…

机器学习模型的阶段环境永远不会无限期地等同于生产环境,因为我们生活的世界总是在变化。基于上述原因,对你投入生产的任何 ML 进行监控是非常必要的。在下一章中,我们将讨论您可以监控的各种指标,以及在决定要监控什么指标时应该考虑的因素。

模型监控中的度量

有几个指标可以用来监控 ML 模型。您选择的指标取决于多种因素:

  • 是回归还是分类任务?
  • 商业目标是什么?精确度与召回率
  • 目标变量的分布是什么?

以下是模型监控中常用的各种指标:

类型 1 错误

也被称为假阳性,这是模型错误预测阳性类别的结果。例如,当你没有怀孕时,一个结果为阳性的妊娠测试就是一个 1 型错误的例子。

第二类错误

也被称为假阴性,这是模型错误预测阴性类别的结果。这方面的一个例子是,当一个结果说你没有患癌症,而你实际上患了癌症。

精度

模型的准确性简单地等于模型正确预测的分数,由以下等式表示:

精度

Precision 试图回答“多大比例的肯定识别实际上是正确的?”并且可以由下面的等式表示:

回忆

回忆试图回答“多大比例的实际阳性被正确识别?”并且可以由下面的等式表示:

F1 得分

F1 分数是对测试准确性的一种衡量——它是精确度和召回率的调和平均值。它的最高分是 1(完美的精确度和召回率),最低分是 0。总的来说,它是对模型的精确性和稳健性的一种度量,可以用以下等式表示:

R 平方

r 平方是一种度量,它告诉你因变量的方差在多大程度上是由自变量的方差来解释的。更简单地说,当系数估计趋势时,R 平方表示最佳拟合线周围的散布。

例如,如果 R 是 0.80,那么 80%的变化可以用模型的输入来解释。

如果 R 为 1.0 或 100%,这意味着因变量的所有变动都可以完全由自变量的变动来解释。

调整后的 R 平方

添加到模型中的每个额外的独立变量总是增加 R 值,因此,具有几个独立变量的模型可能看起来更适合,即使它不是。这就是调整后的 R 的用武之地。调整后的 R 补偿每个额外的独立变量,并且仅在每个给定变量将模型改进到超出概率可能的程度时才增加。

平均绝对误差

绝对误差是预测值和实际值之间的差值。因此,平均绝对误差是绝对误差的平均值。

均方误差

均方误差或 MSE 与 MAE 类似,只是取预测值和实际值之间的平方差的平均值。

因为差值是平方的,所以较大的误差被赋予更高的权重,所以当您想要最小化较大的误差时,这应该在 MAE 上使用。下面是 MSE 的等式和代码。

O 总之,您选择监控的指标最终取决于手头的任务和您工作的业务环境。

例如,在数据科学领域,众所周知,准确性指标与欺诈检测模型无关,因为欺诈交易的百分比通常不到 1%。因此,即使欺诈检测模型有 99%的准确率,因为它将所有交易归类为非欺诈交易,这也不能帮助我们确定该模型是否有效。

另一个例子是,当涉及到癌症筛查测试时,假阴性分类的严重性比假阳性分类严重得多。说一个癌症患者没有癌症最终会导致他或她的死亡。这比说一个病人得了癌症,进行进一步的检查,却发现病人没有癌症要糟糕得多。(安全总比后悔好!)

更多类似的文章,请查看 https://blog.datatron.com/Datatron 的媒体页面或他们的博客

感谢阅读!

如果你喜欢我的工作并想支持我,我会非常感谢你在我的社交媒体频道上关注我:

  1. 支持我的最好方式是在媒体T10【这里上关注我。
  2. 推特关注我这里
  3. 点击这里订阅我的新 YouTube 频道
  4. LinkedIn 上关注我这里
  5. 在我的邮箱列表 这里报名。
  6. 查看我的网站terenceshin.com

资源

[1]德什穆克,奥姆(2019)。部署了你的机器学习模型?以下是你需要了解的后期制作监控。分析维迪亚。
https://www . analyticsvidhya . com/blog/2019/10/deployed-machine-learning-model-post-production-monitoring/

神经网络初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-neural-nets-5cf4050117cb?source=collection_archive---------17-----------------------

全民数据科学

对“黑匣子”的探究

介绍

如果你正在阅读这篇文章,你可能已经知道神经网络(NN)和深度学习的好处,但也许你想了解它们是如何工作的。你来对地方了!

当我第一次了解神经网络时,最让我惊讶的是它们的数学简单性。尽管神经网络在计算机视觉[1]和自然语言处理[2,3]等领域处于突破的前沿,但它们的内部工作原理很容易理解。

在这篇文章中,我们将通过使用“Hello World!”相当于深度学习——手写数字识别。

所以让我们直入主题吧。

NN——它们是如何工作的?

NNs 包含两个阶段;

  1. 正向传播
  2. 反向传播

在神经网络的训练过程中,你执行这两个阶段。当您希望神经网络对未标记的示例进行预测时,您只需执行正向传播。反向传播确实是一种魔力,它使得神经网络能够很好地完成传统上计算机很难完成的任务。

正向传播

为了给神经网络一些背景知识,我们将考虑它所应用的原始问题之一——手写数字识别[4]。这个问题通常是深度学习的学生首先遇到的问题之一,因为它代表了传统机器学习方法难以解决的问题。

想象一下,我们的任务是编写一个可以识别手写数字的计算机程序。我们收到的每张图像都是 28 x 28 像素,我们还可以访问该图像的正确标签。我们做的第一件事是建立我们的神经网络,如下图所示。

图 1:通用神经网络

图 1 中的每个圆圈代表一个“ 神经元 ”。一个神经元仅仅保存一个标量值,即一个数。红色神经元定义输入层。这是我们输入图像的地方。蓝色神经元代表隐藏层。它们被称为隐藏层,因为用户从不与这些神经元直接交互。绿色神经元代表输出层。这是神经网络将输出其对图像中数字的预测的地方。

我们总共有 784 个像素(28 x 28),所以我们的输入层由 784 个神经元组成。让我们将图 1 中顶部的红色神经元称为神经元 1,底部的神经元称为神经元 784。每个神经元的值采用它所连接的像素的值。例如,如果我们图像的像素深度为 8 位,那么单个像素可以取 0 到 256 (2⁸).)之间的值 0 将表示全白像素,256 将表示全黑像素,在这些值之间有一个滑动标度。一个神经元的值叫做它的 激活 。我们将用符号 a 来表示神经元的激活。

我们要做的下一件事是将输入层的每一个神经元连接到下一层的每一个神经元。这在图 1 中显示为灰色线。我们还为每个连接添加了一个权重。权重就像神经元的值一样,只是一个标量值。图 2 显示了为我们的神经网络标记的三个权重。这里的下标只是帮助我们跟踪权重对应哪两个神经元。例如,权重 w31 是输入层中的神经元 1 和第一个隐藏层中的神经元 3 之间的连接的权重。神经元之间的权重越大,它们之间的联系就越强。

图 2:带权重的通用神经网络

现在我们需要计算出第一个隐藏层中神经元的激活值。我们分两部分做这件事。在第一部分中,我们简单地将前一层中每个神经元的激活乘以与其相关的权重。然后,我们将所有这些项相加,并添加一个“”项,我们将其表示为 b。最后,我们将这个加权和通过一个非线性函数,如 tanh(x)或 sigmoid 函数,我将用σ表示。【参见* 【问题】 部分,如果您对我们为什么使用偏置项和非线性函数感兴趣。]*

让我们把它分解一下。如果我们考虑在隐藏层的第一个神经元上发生了什么,那么我们就有了图 3 所示的结果。

图 3:标记了权重和激活的一般神经网络

该神经元具有来自第一层中所有神经元的贡献。第一层中的每一个神经元都有自己的权重,并乘以权重。然后我们将所有这些项相加,再加上单个偏置项。这个加权和由符号 z₁表示,其中 1 表示我们正在讨论该层中的第一个神经元,上标的 2 表示我们正在讨论网络中的第二层。然后,将该加权和通过非线性函数,以获得第一隐藏层(网络的第二层)中的第一神经元的激活,我们将称之为 a₁。

图 4:定义第一个隐藏层中第一个神经元的加权和与激活的等式

我们对第一个隐藏层中的所有神经元重复这一过程:将稍后输入的每个神经元乘以将其连接到第一个隐藏层中的神经元的权重,添加偏差项,然后将这个加权和 z 放入非线性函数中。

现在我们有了第一个隐藏层中所有神经元的激活,我们重复这个过程来获得第二个隐藏层中神经元的激活,然后再次获得输出层的激活。要知道不同层之间的权重是不同的,这一点很重要。

由于我们的任务是预测图像中的数字,输出层将包含 10 个神经元,代表数字 0,1,2,…,9。最终层中的每个神经元将包含 0 和 1 之间的激活值,并且我们将具有最高激活的神经元作为 NNs 对图像中哪个数字的猜测。

在训练神经网络之前,网络很可能无法正确识别图像中的数字。例如,考虑图 5 所示的情况。

图 5:通用神经网络,显示了数字 7 输入的网络输出

将数字 7 的图像输入到 NN 中,并计算所有的激活。我们在输出层看到的是,代表数字 8 的神经元的激活值最高,因此神经网络认为数字 8 在图像中,这显然是错误的。因此,我们需要做的是改变所有权重和所有偏置的值,以便将输出层中所有神经元的激活推向 0,除了代表数字 7 的神经元。

如今的网络可以轻易地包含数百万,甚至数十亿的权重和偏见,我们到底要如何做出这些改变才能让我们更接近正确答案呢?

事实证明,我们知道,而且已经做了相当长一段时间[5],一种非常有效地计算所需变化的技术。这种算法叫做 反向传播。

反向传播

为了开始调整我们的权重和偏差以使神经网络更接近正确答案,我们需要做的第一件事是定义一个 成本函数 。成本函数只是量化了一个系统的错误程度。让我们用均方差(MSE)来表示。为了计算单个训练示例的 MSE,我们通过我们的 NN 运行我们的数字,并计算输出层中神经元的激活与期望激活之间的差异。然后,我们对这些值求平方,将它们相加,然后除以相加的项数,在我们的例子中是 10。

图 6:图像显示了单个培训示例的成本计算

图 6 示出了数字 0 的训练示例的成本函数的计算。这是单个训练例子的成本。然后,我们通过网络运行其余的训练示例,并计算它们的所有成本。我们定义一个数字,称为 平均成本, 是所有单个示例成本的平均值。例如,如果我们有 400 个训练示例,我们的平均成本将是这 400 个示例的所有成本的总和除以 400。这给出了 1 轮训练的平均成本(通常称为 epoch),让我们用 C(w)来表示。

现在,我们想改变所有的权重和偏差,使这个成本尽可能小。

为了更好地理解这一点,想象整个系统的特点是一个单一的重量,而不是我们目前有几千个。那么我们的成本函数可能如图 7 所示。

图 7:显示成本函数 C(w)(红色)和 w 的两个可能值(蓝色圆圈)及其梯度(黑色虚线)的图表

用红色绘制的是不同 w 值的平均成本 C(w)。如前所述,我们希望最小化 C(w)。换句话说,我们想改变 w,使我们达到红色曲线的最小值。

图 7 中还示出了作为蓝色圆圈的 w 的两个可能值,它们的相关梯度作为黑色虚线。从图 7 中我们可以推断出,如果当前点的梯度是负的,我们应该向右移动 w,如果梯度是正的,我们应该向左移动 w。

此外,我们应该移动一个与梯度成比例的量。如果梯度大,我们应该比梯度小移动更大的量,因为这表明我们接近红色曲线的最小值。这个逻辑可以用 权重更新方程来概括。

图 8:权重更新公式

注意:记住我们不知道如图 7 所示的 C(w)的精确表面,否则我们可以简单地改变我们的重量到最佳值来最小化 C(w)。取而代之的是,我们必须使用我们对梯度的局部测量,来告诉我们向哪个方向移动,以使我们更接近最小值。

权重更新等式告诉我们,下一个训练游程(下一个时期)w(t+1)中的权重应该等于由当前游程的梯度 dC(w)/dw 调整的当前游程的权重 w(t)。η称为‘学习率’,它控制当前梯度对权重更新的影响有多大。它通常是一个小值,如 0.01 或 0.001。

这个计算你当前位置的梯度然后移动与梯度成比例的量的过程叫做‘梯度下降’。**

为了执行梯度下降,我们需要计算 C(w)相对于我们的 NN 中的每个权重的导数。寻找神经网络中每个权重的梯度的技术被称为反向传播,是神经网络的主力。它被称为反向传播,因为您从计算 C(w)相对于输出层中权重的梯度开始。那么 C(w)相对于输出层之前的层的梯度取决于输出层的梯度。通过这种方式,您可以“反向传播”您对梯度的计算,以计算出权重的梯度,并进一步返回到网络中。

摘要

因此,为了训练我们的神经网络,我们需要执行所有训练图像的前向传播。计算平均成本 C(w)。然后使用反向传播来计算 C(w)相对于 NN 中所有权重的导数。最后,使用更新等式使用梯度下降来逐渐将权重移动到 C(w)的最小值。简单!

这里我唯一没有介绍的是如何计算 C(w)的梯度,因为这有点复杂,而且不可避免地要包括一些看起来相当吓人的数学。不管方程的形式如何,我认为它们很简单,只需要求导和使用我们在中学微积分课上学过的链式法则。然而,我将把它留给另一篇文章。

我希望你喜欢了解 NNs 的内部。下一篇文章再见。

保持好奇。

问题

偏见术语 b 有什么必要?

如果我们能想象出它在做什么,那么偏置项是最容易理解的。首先让我们使用 sigmoid 函数作为我们的非线性激活函数。让我们也考虑一个简化的网络,其中有一个单一的加权 w₁和来自前一层 x₁.的单一输入

图 9:对于偏置项的不同值,第二层中第一个神经元的激活

图 9 的左边是单个权重 w₁.的 3 个不同值的 sigmoid 函数你可以看到,如果神经网络改变权重,这将简单地改变图形的陡度。

如果当 x₁ = 2,这给了这个神经元一个非常强的激活,我们得到一个高成本函数 C(w)呢。网络然后决定实际上使这个神经元的激活接近于 0 对 C(w)有好处。仅仅改变重量是不可能激活这个神经元的。这就是偏见术语的由来。

从图 9 的右侧可以看到,偏置项使整个函数沿 x 轴移动,但并没有改变它的整体形状。因此,你现在可以看到,对于 2 的输入,如果 b₁ > 0,你可以得到接近 0 的激活。同样,如果你的偏差项是负的,你会得到相反的情况。

本质上,偏差项给神经网络更多的自由度来拟合你提供给它的数据。

非线性激活函数σ有什么必要?

简而言之:没有非线性函数,许多权重和激活的相乘只是输入的线性函数。因此你只能解决线性可分的问题。

长答案:我们所说的线性可分是什么意思?这意味着你的问题可以用超平面来解决。二维的超平面是一条线,三维的超平面是一个平面(就像一张纸),通常我们称之为超平面。

例如,考虑图 10 的左手侧,其包含用绿色和橙色着色的两个不同的组。蓝线显示了解决这个分类任务的一个可能的超平面。这是一个线性可分问题的例子

图 10:(左)线性分类问题和(右)非线性分类问题

现在考虑一个不是线性可分的问题。这类问题最简单的例子是异或门。它有两个输入,让我们称之为 x₁和 x₂和一个输出。XOR 问题显示在图 10 的右侧。在这种情况下,没有一个超平面可以完美地区分这两个类别。

这与神经网络的非线性功能有什么关系?在没有非线性函数的情况下,多层权重和激活乘法可以由一个大矩阵 M 来表示,该矩阵将输入向量 X 映射到输出向量 Y(即 M.X = Y)。这个矩阵将是线性的,因此不能解决 XOR 问题。手写数字识别是非线性问题的另一个例子。因此,非线性函数打破了神经网络的线性,使它们能够解决更复杂的问题。

参考书目

[1] 克日涅夫斯基、亚历克斯、伊利亚·苏茨基弗和杰弗里·e·辛顿。"使用深度卷积神经网络的图像网络分类."神经信息处理系统的进展。2012.

[2] Jozefowicz,Rafal 等,“探索语言建模的极限”arXiv 预印本 arXiv:1602.02410 (2016)。

[3] Sutskever,Ilya,Oriol Vinyals,和 Quoc V. Le。"用神经网络进行序列对序列学习."神经信息处理系统的进展。2014.

[4] LeCun,Yann 等,“用反向传播网络进行手写数字识别”神经信息处理系统的进展。1990.

鲁梅尔哈特、戴维·e·杰弗里·e·辛顿和罗纳德·j·威廉姆斯。"通过反向传播误差学习表征."性质 323.6088(1986):533–536。

如何开始使用脸书检测器 2

原文:https://towardsdatascience.com/a-beginners-guide-to-object-detection-and-computer-vision-with-facebook-s-detectron2-700b6273390e?source=collection_archive---------12-----------------------

在许多不同的物体探测技术中,脸书提出了它的模型:探测器 2。这种模型与 Yolo 模型类似,能够围绕对象绘制边界框,并通过全景分割模型进行推理,换句话说,它不是围绕对象绘制一个框,而是“包裹”对象边界的真实边界(可以将其视为 photoshop 的智能剪切工具)。)

行动中的探测器 2(原始图像由尼克·卡沃尼斯拍摄)

介绍

本指南的目的是展示如何轻松实现预训练的 Detectron2 模型,能够识别来自 COCO (上下文中的公共对象)数据集中的类所代表的对象。本指南旨在为计算机视觉初学者提供一个起点,旨在解释实现预训练模型的第一步是什么,其最终目标是激发您学习更多内容的兴趣,并在这个势不可挡的领域安排您的想法。我提供了一个 Google Colab 笔记本,你可以随意克隆和使用,也可以跟进和编码!

可可数据集一瞥(来源:https://github.com/nightrome/cocostuff)

安装依赖项

要开始使用,必须安装其核心依赖项:

  • PyTorch
  • Cython
  • 检测器 2
  • OpenCV

这些任务可能需要几分钟,因为你需要一个 GPU 来运行这个笔记本,我建议你克隆我的 Colab 笔记本,并从 Google Colab 编写所有内容,这也将帮助你对命令行片段和云中的文件管理更加自信!

!pip install -U torch==1.4+cu100 torchvision==0.5+cu100 -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html)!pip install cython pyyaml==5.1!pip install -U ‘git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'!git clone [https://github.com/facebookresearch/detectron2](https://github.com/facebookresearch/detectron2) detectron2_repo!pip install -e detectron2_repo#!pip install opencv-python Google Colab already comes with OpenCV

导入库和所需的文件

一旦安装了这些依赖项,您很可能需要重启您的运行时/内核。现在,我们需要导入一些我们需要导入、处理和推断预测的库,其中包括我们已有的库……

由于我使用的是 Google Colab,功能cv2.imshow()不可用,如果你在本地机器上运行这个笔记本,我需要使用一个“补丁”版本来摆脱它。

# import some common librariesimport numpy as npimport cv2import randomfrom google.colab.patches import cv2_imshow # On your local machine you don’t need it.# import some common detectron2 utilitiesfrom detectron2 import model_zoofrom detectron2.engine import DefaultPredictorfrom detectron2.config import get_cfgfrom detectron2.utils.visualizer import Visualizerfrom detectron2.data import MetadataCatalog

在本指南中,我使用了我的 google drive 中的一个图像,您可以安装您的 Google Drive 并使用您选择的图像:

from google.colab import drivedrive.mount(‘/content/drive’)

现在让我们得到一张我们想要运行模型的图片:

im = cv2.imread(“./drive/My Drive/turin.png”)cv2_imshow(im)

图片来自我的谷歌硬盘(来源:谷歌街景)

拟合模型

一旦我们的图像被加载,我们需要加载我们的模型和一点配置。首先,我们从 Detectron 加载配置,然后我们对其应用来自COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml的自定义配置。然后设置阈值,因此检测对象时模型的灵敏度(玩这些参数!).下一步是加载与该模型相关的检查点,换句话说,就是以.pkl格式加载模型本身。下一步是实例化模型本身,像在 scikit 中一样思考——例如,当您想要进行回归时,学习:

reg = LinearRegression() reg.fit(X, y) reg.predict(X_test)然而,我们没有将数组X_train传递给我们的预测器,而是传递我们的图像,该图像也对应于一个数组(准确地说是一个 3D 数组:一个轴代表宽度,另一个轴代表高度,最后一个轴代表图像的颜色)。

我们使用预训练模型而不是训练我们的模型的原因可以通过描述文件 detectron2/MODEL_ZOO 的前两行来解释:

“该文件记录了 2019 年 9 月至 10 月用 detectron2 训练的大量基线。所有数字都是在带有 8 个 NVIDIA V100 GPUs 和 NVLink 的大盆地服务器上获得的。使用的软件是 PyTorch 1.3、CUDA 9.2、cuDNN 7.4.2 或 7.6.3。”。

然而,当然,你可以使用一个基线模型来进一步训练它识别一个特定的物体,这个过程被称为转移学习。

cfg = get_cfg()cfg.merge_from_file(model_zoo.get_config_file(“COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml”))cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5 # set threshold for this modelcfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(“COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml”)predictor = DefaultPredictor(cfg)outputs = predictor(im)

如果我们检查由模型生成的outputs,我们会看到一个大规模的字典(请参考 Colab 笔记本),这个字典包含检测到的对象的数量(num_instances)、关于图像的信息和应该绘制框的图像的坐标,以及每个框(实例)的标签(pred_classes)。让我们看看第一个盒子:

[1314.3333, 485.8268, 1345.7896, 539.3832]

有 4 个值,每个值分别代表矩形的 x、y、宽度和高度。(有时,在 OpenCV 中,当迭代检测到的对象时,你会做一个类似于for x, y, w, h in ...的循环)

获取输出图像

现在,我们可以可视化图像以及显示图像中预测对象的方框,为了实现这一点,我们必须使用一个特定的对象,让我们将预测与原始图像合并,这个对象称为Visualizer,一旦用我们的图像和元数据实例化了Visualizer,我们就可以调用带有outputs作为参数的draw_instance_predictions方法:

v = Visualizer(im, MetadataCatalog.get(cfg.DATASETS.TRAIN[0]), scale=1.5) # Scaling the image 1.5 times, for big images consider a value below 0v = v.draw_instance_predictions(outputs[“instances”].to(“cpu”))cv2_imshow(v.get_image())

最终图像,带有识别检测到的“对象”的绘制框

现在去哪里?

计算机视觉是一个存在学习障碍的领域,也有一些进入障碍:通常很难获得特定的硬件,一个模型可能需要几个小时的训练,我们的小型笔记本电脑经常会死机,因此很难遵循“经典”的试错学习路径,也许我们在破解 scikit-learn 时尝试一些机器学习算法时会遵循这一路径!

既然(希望)你现在对工作流程有了一个基本的概念,从如何导入图像到如何显示图像,只要如何从 detectron2 库中加载模型,下一步可能是尝试重新训练它,使用(我建议)一些云提供商,可以是 Google Colab,Paperspace Gradient,Azure Notebooks 或任何其他东西。另一个很好的前进步骤可能是尝试实现探测器 2“对手” Yolo ,也许使用 CoreMLtools 在 iOS 应用程序中实现它

**I have a newsletter 📩.**Every week I’ll send you a brief findings of articles, links, tutorials, and cool things that caught my attention. If tis sounds cool to you subscribe.*That means* ***a lot*** *for me.*

[## 米尔斯形式

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)

绘制数据的初学者指南(Python & R)

原文:https://towardsdatascience.com/a-beginners-guide-to-plotting-your-data-python-r-11e435262ac1?source=collection_archive---------32-----------------------

为您的特征变量选择正确的图表

当分析数据时,比如说,确定您希望使用的回归类型时,首先弄清楚您实际拥有的数据类型是很重要的。事实上,在进行任何形式的分析之前,我们都应该进行数据探索,因为这可以节省我们以后的大量工作。例如,我们可能意外地选择了错误的回归模型,因为变量 1 和变量 5 之间存在不可预见的相互作用,如果我们事先仔细查看我们的数据,这是可以避免的。数据分析在很大程度上取决于您的特征变量类型、它们是如何分布的、它们是如何相互关联的,等等。

定量变量与分类变量

在进行任何数据分析之前,我们必须首先区分定量和定性/分类变量。

数量变量是可以测量的变量,它们用数字表示。另一方面,分类变量是描述性的,通常采用名称或标签等值。定性数据可以根据相似的特征进行分组,因此是分类的。

选择正确的图表

图形选择摘要

所有提到的图形都可以很容易地用 Python 和 Seaborn 库(如果愿意,也可以用 Matplotlib)绘制,或者用 R 和 ggplot 绘制。

我们必须首先将数据作为数据帧加载到 Python 中。在这里,我从同一个目录中的 csv 文件加载它。

import pandas as pd
import seaborn as snsdata = pd.read_csv("filename.csv", sep=" ", header="infer")

或者将其作为数据帧加载到 R 中。

library(tidyverse)data <- read_csv("filename.csv")

条形图

如果您希望可视化单个分类变量,您应该使用条形图,其中 x 轴是变量,y 轴是计数轴。

在 Python 中:

sns.catplot(x = "categorical var", kind = "count", data = data)

在 R 中:

ggplot(data, aes(x = categorical var)) + geom_bar()

分组条形图

如果我们有两个分类变量,我们将进行分组条形图。这是按第二个分类变量分组的,通常是分类较少的那个。

在 Python 中:

sns.catplot(x = "categorical var1", hue = "categorical var2", kind = "count", data = data)

在 R 中:

ggplot(data, aes(x = categorical var1, fill = categorical var2)) + geom_bar(position = "dodge")

柱状图

直方图对于可视化定量变量非常有用。这里,我们希望确保选择适当数量的箱来最好地表示数据。这个数字很容易根据过去的经验来选择,可以摆弄箱的数量,或者使用一个客观的箱选择公式,如斯特奇斯规则。

在 Python 中:

sns.distplot(data["quantitative var"], bins = 10, kde = False) 

在 R 中:

ggplot(data, aes(x = quantitative var)) + geom_histogram(bins = 10)

并排箱线图

当我们有一个定量变量和一个定性变量时,我们将使用并排箱线图来最好地展示数据。

在 Python 中:

sns.boxplot(x = "categorical var", y = "quantitative var", data = data)

在 R 中:

ggplot(data, aes(x = categorical var, y = quantitative var)) + geom_boxplot()

分组箱线图

当我们有两个分类变量和一个定量变量时,使用分组箱线图。让分组在具有较少组的分类变量上完成。

在 Python 中:

sns.boxplot(x = "categorical var1", y = "quantitative var", hue = "categorical var2", data = data)

在 R 中:

ggplot(data, aes(x = categorical var1, y = quantitative var, fill = categorical var2)) + geom_boxplot()

散点图

需要散点图来显示一个量化变量与另一个量化变量之间的关系。这在评估定量特征变量/解释变量和定量响应变量之间存在的关系类型时非常常见,其中 y 轴始终代表响应变量。

在 Python 中:

sns.scatterplot(x = "explanatory variable", y = "response variable", data = data)

在 R 中:

ggplot(data, aes(x = explanatory variable, y = response variable)) + geom_point()

分组散点图

如果我们试图可视化两个定量变量和一个分类变量,我们将使用散点图,散点图中的点按分类变量分组。

在 Python 中:

sns.scatterplot(x = "explanatory variable", y = "response variable", hue = "categorical var", data = data)

在 R 中:

ggplot(data, aes(x = explanatory variable, y = response variable, color = categorical var)) + geom_point()

Scikit 初学者指南-学习

原文:https://towardsdatascience.com/a-beginners-guide-to-scikit-learn-14b7e51d71a4?source=collection_archive---------7-----------------------

入门

开始使用排名第一的 python 机器学习库

照片由克莱门特 HUnsplash 上拍摄

Scikit-learn ,最初是作为 2007 年谷歌代码之夏项目开发的,现在被广泛认为是最受欢迎的机器学习 Python 库。

这个库被视为机器学习项目的最佳选择之一,尤其是在生产系统中,原因有很多。这些包括但不限于以下内容。

  • 它对库的开发有高级别的支持和严格的管理,这意味着它是一个非常健壮的工具。
  • 有一个清晰、一致的代码风格,确保您的机器学习代码易于理解和可复制,同时也大大降低了编写机器学习模型的门槛。
  • 它受到第三方工具的广泛支持,因此可以丰富功能以适应各种用例。

如果你正在学习机器学习,那么 Scikit-learn 可能是最好的入门库。它的简单性意味着它相当容易掌握,通过学习如何使用它,你也将很好地掌握典型的机器学习工作流程中的关键步骤。

下面的文章是对该工具的初学者友好的介绍,应该给你足够的理解,能够开发一个简单的机器学习模型。

要安装最新版本的 Scikit-learn,请运行以下命令。

pip install scikit-learn

本文中的代码示例都是在经典的 wine 数据集上运行的,该数据集可以直接从 Scikit-learn API 导入。

评估者

Scitkit-learn 库提供了非常多种预构建的算法来执行有监督和无监督的机器学习。他们通常被称为估计器

您为项目选择的评估者将取决于您拥有的数据集和您试图解决的问题。Scikit-learn 文档提供了下图,帮助您确定哪种算法适合您的任务。

来源: Scikit-learn 文档

Scikit-learn 之所以如此易于使用,是因为不管您使用的是什么模型或算法,用于模型训练和预测的代码结构都是相同的。

为了说明这一点,我们来看一个例子。

假设您正在处理一个回归问题,并希望训练一个线性回归算法,并使用生成的模型进行预测。使用 Scikit-learn 的第一步是调用逻辑回归估计器,并将其保存为一个对象。下面的例子调用算法并将其保存为一个名为 lr 的对象。

下一步是使模型符合一些训练数据。这是使用 fit() 方法完成的。我们在特性和目标数据上调用**lr.fit()**,并将结果模型保存为一个名为模型的对象。在下面的例子中,我也使用了**train_test_split()**方法将数据集分成测试和训练数据。

接下来,我们使用该模型和 predict() 方法来预测之前未见过的数据。

如果我们现在使用 Scitkit-learn 来执行不同的任务,比方说,我们想要训练一个随机森林分类器。代码看起来非常相似,并且有相同的步骤数。

这种一致的代码结构使得开发机器学习模型非常直接,并且还产生了高度可读和可再现的代码。

预处理

在大多数现实世界的机器学习项目中,您使用的数据不一定准备好训练模型。很可能首先需要执行一些数据预处理和转换步骤,例如处理缺失值、将分类数据转换为数值或应用要素缩放。

Scikit-learn 具有执行这些预处理步骤的内置方法。例如,simple imputr()使用您选择的方法来填充缺失值。

Scikit-learn 文档在这里列出了数据预处理的全部选项

估价

一旦一个模型被训练好了,你就需要衡量这个模型对新数据的预测能力。这一步被称为模型评估,您选择的度量标准将由您试图解决的任务决定。例如,通常在回归问题中,你可能选择 RMSE,而对于分类,你可能选择 F1 分数。

所有估计器都包括一个 score() 方法,该方法返回一个与它们执行的机器学习任务最相关的默认度量。

Scikit-learn 另外还有一组度量函数,为模型提供更详细的评估。例如,对于分类任务,库有一个分类报告,它提供精确度、召回率、F1 分数和总体准确度。

分类报告代码和输出如下所示。

模型优化

Scikit-learn 库中的所有估计器都包含一系列参数,这些参数有多个选项。您为特定算法选择的值将影响最终模型的性能。例如,使用 RandomForestClassifier,您可以将树的 max_depth 设置为任何值,根据您的数据和任务,此参数的不同值将产生不同的结果。

这个尝试不同参数组合以找到最佳组合的过程被称为超参数优化

Scikit-learn 提供了两个工具来自动执行这项任务, GridSearchCV 实现了一种称为穷举网格搜索的技术,以及 RandomizedSearchCV 执行随机化参数优化

以下示例使用 GridSearchCV 来查找 RandomForestClassifier 的最佳参数。输出显示在代码下方。

管道

Scikit-learn 包以管道的形式提供了更方便的代码封装形式。该工具将所有预处理任务与分类器步骤链接在一起,因此只需在单个管道对象上调用 fit()或 predict()即可执行工作流中的所有步骤。

这有助于提高代码的可读性,并减少机器学习工作流程中的重复步骤。

要创建管道,我们首先在下面的代码中定义我称为管道的对象中的步骤。然后我们可以简单地在这个对象上调用 fit 来训练模型。管道对象还可以用于对新数据进行预测。

如果您喜欢这篇文章,并想进一步探索 Scikit-learn 库,您可能会喜欢阅读下面显示的我的早期帖子。

[## Scikit-learn 管道简单指南

了解如何在 scikit-learn 机器学习工作流中使用管道

medium.com](https://medium.com/vickdata/a-simple-guide-to-scikit-learn-pipelines-4ac0d974bdcf) [## 关于 Scikit 你不知道的 10 件事-了解

…直到现在

towardsdatascience.com](/10-things-you-didnt-know-about-scikit-learn-cccc94c50e4f)

感谢阅读!

我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分!

Python 情感分析初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-sentiment-analysis-in-python-95e354ea84f6?source=collection_archive---------0-----------------------

关于使用文本数据构建单词云、漂亮的可视化和机器学习模型的端到端指南。

照片由来自 StockSnap 的 Ryan McGuire 拍摄

什么是情感分析?

情感分析是一种检测一段文本中潜在情感的技术。

它是将文本分类为阳性、阴性、中性的过程。机器学习技术用于评估一段文本,并确定其背后的情感。

情感分析为什么有用?

情感分析对于企业评估客户反应至关重要。

想象一下这个 :你的公司刚刚发布了一款新产品,正在多个不同的渠道做广告。

为了衡量客户对此产品的反应,可以进行情感分析。

客户通常会在社交媒体和客户反馈论坛上谈论产品。可以收集和分析这些数据,以评估客户的总体反应。

更进一步,还可以检查数据的趋势。例如,某个年龄组和人口统计的客户可能对某个产品的反应比其他产品更积极。

根据收集到的信息,公司可以对产品进行不同的定位,或者改变他们的目标受众。

分析

在本文中,我将引导您完成对大量数据执行情感分析的端到端过程。

我们将使用 Kaggle 的亚马逊美食评论数据集中的Reviews . CSV文件来执行分析。

我使用 Jupyter 笔记本进行所有的分析和可视化,但是任何 Python IDE 都可以完成这项工作。

步骤 1:读取数据帧

*import pandas as pd
df = pd.read_csv('Reviews.csv')
df.head()*

检查数据帧的头部:

我们可以看到数据帧包含一些产品、用户和评论信息。

我们在此分析中最常用的数据是“摘要”、“T17”、“T18”文本、“T19”和“T20”分数**

文本 —该变量包含完整的产品评论信息。

总结 —这是整个复习的总结。

评分— 客户提供的产品评分。

第二步:数据分析

现在,我们来看看变量“得分”,看看大多数客户评级是正面还是负面。

为此,你必须先安装。**

**# Importsimport matplotlib.pyplot as plt
import seaborn as sns
color = sns.color_palette()
%matplotlib inline
import plotly.offline as py
py.init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.tools as tls
import plotly.express as px# Product Scoresfig = px.histogram(df, x="Score")
fig.update_traces(marker_color="turquoise",marker_line_color='rgb(8,48,107)',
                  marker_line_width=1.5)
fig.update_layout(title_text='Product Score')
fig.show()**

结果图如下所示:

从这里,我们可以看到大多数客户的评价是积极的。这让我相信大多数评论也会是非常正面的,这将在一段时间内进行分析。

现在,我们可以创建一些 词云 来查看评论中最常用的词。

**import nltk
from nltk.corpus import stopwords# Create stopword list:
stopwords = set(STOPWORDS)
stopwords.update(["br", "href"])
textt = " ".join(review for review in df.Text)
wordcloud = WordCloud(stopwords=stopwords).generate(textt)plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.savefig('wordcloud11.png')
plt.show()**

运行上面的代码会生成一个单词云,如下所示:

这里可以观察到的一些流行词有“品味、“产品、“爱情、“亚马逊”这些词大多是积极的,也表明数据集中的大多数评论表达了积极的情绪。

第三步:分类推文

在这一步中,我们将评论分为“正面”和“负面”,因此我们可以将此用作情感分类模型的训练数据。

正面评价将被归类为+1,负面评价将被归类为-1。

我们会将所有‘得分’> 3 的评论归类为+1,表示它们是正面的。

所有带“分数”的评论< 3 will be classified as -1. Reviews with ‘Score’ = 3 will be dropped, because they are neutral. Our model will only classify positive and negative reviews.

**# assign reviews with score > 3 as positive sentiment
# score < 3 negative sentiment
# remove score = 3df = df[df['Score'] != 3]
df['sentiment'] = df['Score'].apply(lambda rating : +1 if rating > 3 else -1)**

Looking at the head of the data frame now, we can see a new column called ‘sentiment:’

Step 4: More Data Analysis

Now that we have classified tweets into positive and negative, let’s build wordclouds for each!

First, we will create two data frames — one with all the positive reviews, and another with all the negative reviews.

**# split df - positive and negative sentiment:positive = df[df['sentiment'] == 1]
negative = df[df['sentiment'] == -1]**

文字云—正面情绪

**stopwords = set(STOPWORDS)
stopwords.update(["br", "href","good","great"]) ## good and great removed because they were included in negative sentimentpos = " ".join(review for review in positive.Summary)
wordcloud2 = WordCloud(stopwords=stopwords).generate(pos)plt.imshow(wordcloud2, interpolation='bilinear')
plt.axis("off")
plt.show()**

Wordcloud —负面情绪

**neg = " ".join(review for review in negative.Summary)
wordcloud3 = WordCloud(stopwords=stopwords).generate(neg)plt.imshow(wordcloud3, interpolation='bilinear')
plt.axis("off")
plt.savefig('wordcloud33.png')
plt.show()**

如上所见,积极情绪词云中充满了积极的词语,如“

《负面情绪词云》中充斥的大多是负面词,如“*,“以及“”。*****

”和“”这两个词最初出现在负面情绪词云中,尽管是正面词。这可能是因为它们被用在了否定的语境中,比如“ 不好 ”正因如此,我把那两个字从单词 cloud 里去掉了。**

最后,我们可以看看评论在整个数据集中的分布情况:

**df['sentimentt'] = df['sentiment'].replace({-1 : 'negative'})
df['sentimentt'] = df['sentimentt'].replace({1 : 'positive'})
fig = px.histogram(df, x="sentimentt")
fig.update_traces(marker_color="indianred",marker_line_color='rgb(8,48,107)',
                  marker_line_width=1.5)
fig.update_layout(title_text='Product Sentiment')
fig.show()**

步骤 5:构建模型

最后,我们可以建立情感分析模型!

这个模型将把评论作为输入。然后它会给出一个关于评论是正面还是负面的预测。

这是一个分类任务,因此我们将训练一个简单的逻辑回归模型来完成它。

作为参考,再看一下数据框:

我们需要采取几个步骤:

  • 数据清理

我们将使用汇总数据进行预测。首先,我们需要删除数据中的所有标点符号。

**def remove_punctuation(text):
    final = "".join(u for u in text if u not in ("?", ".", ";", ":",  "!",'"'))
    return finaldf['Text'] = df['Text'].apply(remove_punctuation)
df = df.dropna(subset=['Summary'])
df['Summary'] = df['Summary'].apply(remove_punctuation)**
  • 分割数据帧

新的数据框应该只有两列—“摘要”(评审文本数据)和“情绪”(目标变量)。

**dfNew = df[['Summary','sentiment']]
dfNew.head()**

看一下新数据帧的头部,这是它现在将包含的数据:

我们现在将把数据帧分成训练集和测试集。80%的数据将用于训练,20%将用于测试。

**# random split train and test dataindex = df.index
df['random_number'] = np.random.randn(len(index))train = df[df['random_number'] <= 0.8]
test = df[df['random_number'] > 0.8]**
  • 创造一袋文字

接下来,我们将使用 Scikit-learn 库中的计数矢量器。

这将把我们的数据框中的文本转换成一个单词包模型,它将包含一个整数的稀疏矩阵。每个单词出现的次数将被计算并打印出来。

我们需要将文本转换成单词袋模型,因为逻辑回归算法不能理解文本。

**# count vectorizer:from sklearn.feature_extraction.text import CountVectorizervectorizer = CountVectorizer(token_pattern=r'\b\w+\b')train_matrix = vectorizer.fit_transform(train['Summary'])
test_matrix = vectorizer.transform(test['Summary'])**
  • 导入逻辑回归
**# Logistic Regressionfrom sklearn.linear_model import LogisticRegression
lr = LogisticRegression()**
  • 分割目标和自变量
**X_train = train_matrix
X_test = test_matrix
y_train = train['sentiment']
y_test = test['sentiment']**
  • 拟合模型上的数据
**lr.fit(X_train,y_train)**
  • 做出预测
**predictions = lr.predict(X_test)**

我们成功地建立了一个简单的逻辑回归模型,并对数据进行了训练。我们还使用该模型进行了预测。

第六步:测试

现在,我们可以测试模型的准确性了!

**# find accuracy, precision, recall:from sklearn.metrics import confusion_matrix,classification_report
new = np.asarray(y_test)
confusion_matrix(predictions,y_test)**

你会得到一个类似这样的混淆矩阵:

**print(classification_report(predictions,y_test))**

分类报告:

该模型在测试数据上的总体准确率约为 93%,考虑到我们没有进行任何特征提取或大量预处理,这已经相当不错了。

还有…就是这样!

我希望你能从这篇教程中学到一些有用的东西。在这之后,你可以尝试的一个很好的练习是在你的分类任务中包括所有三种情绪——积极、消极中立。

感谢阅读,记住— 永远不要停止学习!

世界是一所大学,里面的每个人都是老师。确保你早上醒来时,你去上学。

用 Python 模拟动态系统的初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-simulating-dynamical-systems-with-python-a29bc27ad9b1?source=collection_archive---------5-----------------------

Python 中数字积分微分方程

丹·梅耶斯在 Unsplash 上的照片

考虑单摆。

我们有一个质量为 m 的物体,挂在一根长度为 L 的绳子上,绳子来回摆动。

这基本上是我们能使用的最简单的系统。但是不要让这种简单欺骗了你,它可以创造一些有趣的动态。我们将以此为起点,介绍一些控制理论,并将其与连续控制强化学习进行比较。在此之前,我们需要花一些时间来了解系统的动态以及如何模拟它!

TL;速度三角形定位法(dead reckoning)

我们推导了质量和摆系统的动力学,并使用 Python 的一个集成包和使用欧拉方法建立了两个独立的仿真模型。这为更复杂的系统提供了一个很好的垫脚石;机器人控制中的许多关节和系统甚至可以建模为链接在一起的钟摆。

你也可以在这里查看的原始帖子,这里的方程格式比 Medium 允许的要好得多。

挥杆动力学

如果我们想模拟这个系统,我们需要了解动力学。首先,我们将绘制一个单摆的自由体图(FBD ),其中显示了长度、质量、重力和作用在系统上的力矢量。

单摆的自由体图。

画 FBD 有助于明确所有的力,以确保我们不会错过任何东西。一旦我们有了这个,我们就可以用牛顿第二运动定律来得到动力学。你可能熟悉 F=ma 的形式,但是我们将对旋转运动稍微修改一下,写成:

在这种情况下,τ是关于原点的力矩,III 是转动惯量,α是角加速度。力矩由施加在质量上的力的垂直分量给出(关于原点的力矩),转动惯量正好是 I=mL,角加速度是θ的二阶时间导数。我们可以将这些值代入上面的牛顿第二定律,我们得到:

为了完整起见,我们还可以考虑摆上的摩擦力,这样我们可以得到:

首先要注意的是,由于方程中的二阶导数(θ),我们手上有一个二阶常微分方程。我们想把这个简化为一阶系统来积分模拟。这是以复杂性为代价的,因为我们将把一个二阶系统分解成两个一阶方程。在这种情况下,成本相对较小,但对于更复杂的模型(我们将在以后的文章中讨论),这可能会变得非常棘手。

为此,我们需要引入两个新变量,我们称之为θ_1 和θ_2,定义如下:

这很有帮助,因为我们现在可以说θ2 =θ,并降低了方程的阶数。

现在,我们有:

有了我们的方程,让我们转向建模的代码。

模拟钟摆动力学

首先导入相关的库。

import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt

我们需要设定一些价值观。让质量和长度分别为 1 kg 和 1 m,至少现在,我们将通过设置 b=0 忽略摩擦力。我们将模拟钟摆从π/2(向右提升 90 度)开始摆动,并在没有初始速度的情况下释放。我们可以用 0.02 秒的时间离散化(δt)对此进行 10 秒的模拟。

# Input constants 
m = 1 # mass (kg)
L = 1 # length (m)
b = 0 # damping value (kg/m^2-s)
g = 9.81 # gravity (m/s^2)
delta_t = 0.02 # time step size (seconds)
t_max = 10 # max sim time (seconds)
theta1_0 = np.pi/2 # initial angle (radians)
theta2_0 = 0 # initial angular velocity (rad/s)
theta_init = (theta1_0, theta2_0)
# Get timesteps
t = np.linspace(0, t_max, t_max/delta_t)

我们将演示两种模拟方法,首先是使用scipy进行数值积分,然后再次使用欧拉方法。

科学整合

为了使用scipy进行集成,我们需要为我们的模型构建一个函数。在我们的综合模拟中,我们称它为int_pendulum_sim。该模型将采用θ_1 和θ_2 的初始值(上面标记为theta_init)并对单个时间步长进行积分。然后它返回得到的θ值。函数本身就是我们上面推导的θ1 和θ2 的两个方程。

def int_pendulum_sim(theta_init, t, L=1, m=1, b=0, g=9.81):
    theta_dot_1 = theta_init[1]
    theta_dot_2 = -b/m*theta_init[1] - g/L*np.sin(theta_init[0])
    return theta_dot_1, theta_dot_2

我们可以通过将函数作为参数传递给scipy.integrate.odeint来模拟我们的系统。此外,我们需要给出我们的初始值和模拟结束的时间。

theta_vals_int = integrate.odeint(int_pendulum_sim, theta_init, t)

odeint函数接收这些输入,并为我们整合θ\ dot { \ theta }θ值,然后将这些结果再次反馈到函数中,作为下一个时间步的初始条件。重复这个过程,直到我们对所有的时间步长 t 积分。

我们可以绘制θ和θ,看看位置和速度如何随时间演变。

在我们的模型中,没有摩擦力或其他力,所以钟摆会在π/2 和π/2 之间来回摆动。如果你增加初始速度,比如说,10 弧度/秒,你会看到位置继续增加,因为模型显示它一次又一次地旋转。

半隐式欧拉方法

通过集成求解模型相对容易,但是集成可能非常昂贵,尤其是对于较大的模型。如果想看到模型的长期动态,可以用欧拉法来代替,对系统进行积分模拟。这就是如何在 OpenAI 中解决控制问题,如推车杆,并允许我们为 RL 控制设置问题。

要做到这一点,我们需要得到我们的颂歌的泰勒级数展开 (TSE)。TSE 只是一种近似函数的方法。级数越多,你越精确。出于我们的目的,我们只展开到一阶导数,并截断高阶项。

首先,注意我们需要一个θ(t)的函数。如果我们将 TSE 应用于关于 t-t_0 的θ(t ),我们得到:

其中,O(t)仅代表高阶项,可以去掉而不会损失太多保真度。请注意,这只是根据 TSE 的一般公式得出的。有了这个等式,我们就可以参考上面的 ODE 替换,即:

这样,我们可以将 TSE 与我们的 ODE 链接起来:

这为我们提供了一种在每个时间步长更新模型的便捷方式,以获得θ_1 (t)的新值。我们可以对θ(t)重复展开和代入,得到如下结果:

当我们在模拟中循环时,我们会将 t0t_0t0 更新为之前的时间步长,因此我们会逐步向前移动模型。此外,请注意,这是半隐式欧拉方法,这意味着在我们的第二个方程中,我们使用我们计算的最新θ_1 (t ),而不是直接应用泰勒级数展开式得到的θ_1 (t_0)。我们做了这个微妙的替换,因为没有它,我们的模型将会发散。本质上,我们使用 TSE 得出的近似值存在一些误差(请记住,我们丢弃了那些高阶项),并且这种误差是复合的。在这个应用中,误差给我们的钟摆引入了新的能量——这显然违反了热力学第一定律。进行这种替换可以解决所有问题。

def euler_pendulum_sim(theta_init, t, L=1, g=9.81):
    theta1 = [theta_init[0]]
    theta2 = [theta_init[1]]
    dt = t[1] - t[0]
    for i, t_ in enumerate(t[:-1]):
        next_theta1 = theta1[-1] + theta2[-1] * dt
        next_theta2 = theta2[-1] - (b/(m*L**2) * theta2[-1] - g/L *
            np.sin(next_theta1)) * dt
        theta1.append(next_theta1)
        theta2.append(next_theta2)
    return np.stack([theta1, theta2]).T

现在运行这个新函数:

theta_vals_euler = euler_pendulum_sim(theta_init, t)

剧情看起来不错,就看和我们之前的结果是否吻合了。

mse_pos = np.power(
    theta_vals_int[:,0] - theta_vals_euler[:,0], 2).mean()
mse_vel = np.power(
    theta_vals_int[:,1] - theta_vals_euler[:,1], 2).mean()
print("MSE Position:\t{:.4f}".format(mse_pos))
print("MSE Velocity:\t{:.4f}".format(mse_vel))

MSE Position:	0.0009
MSE Velocity:	0.0000

不同方法之间的均方误差非常接近,这意味着我们得到了一个非常好的近似值。

我们使用了两种不同的方法,因为我说过应用欧拉方法比用odeint积分求解要快。与其相信我的话,不如让我们来验证一下这个说法。

%timeit euler_pendulum_sim(theta_init, t)

2.1 ms ± 82.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)%timeit integrate.odeint(int_pendulum_sim, theta_init, t)

5.21 ms ± 45.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

与积分法相比,欧拉法的速度提高了约 2 倍。

这样,我们学会了如何根据基本原理建立和模拟一个动态模型,并将其应用于一个简单的无摩擦摆。

像这样的动力系统对于理解自然是非常强大的。我最近用同样的技术写了一篇文章,展示了我们如何模拟病毒爆发在人群中的传播。ODE 对于机器人和工程中的反馈控制和其他相关应用也非常有用,所以掌握基本的数字积分是必须的!

SQL 初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-sql-b8a94be51db9?source=collection_archive---------43-----------------------

在不到 10 分钟的时间里学会一项最渴望的技术技能

照片由 Unsplash 拍摄

简介

数据库是计算机系统,允许存储和方便地访问数据。根据数据的组织方式,数据库可以是关系型的( RDBMS )或非关系型的( NoSQL )。关系数据库以表格的形式构建,类似于彼此相关的 csv 文件或 excel 电子表格。虽然,关系数据库比 csv 或 json 文件健壮得多。与单个文件不同,如果多个用户试图与存储在数据库中的数据进行交互,所采取的操作不会相互影响,并且只有根据某些规则有效时才会被保存。此外,如果操作的一部分失败,整个操作将失败,数据库将保持不变;一旦完成,它将被永久保存(即使数据库崩溃)。

下图显示了关系数据库的一个示例,其中的表有一个带主键的列,该列包含每行的唯一值。表也可以有外键,作为到其他表的链接。这些链接定义了关系数据库。

关系数据库的一些例子是 MySQL 和 PostgreSQL(免费和开源)或 Oracle 和 Microsoft SQL(主要由公司使用)。

所有这些数据库都可以用 SQL 来访问和操作,SQL 是一种编程语言,代表结构化查询语言。学习 SQL 比学习其他编程语言容易得多,因为它读起来像一种自然语言。在接下来的部分中,我将展示如何在 SQL 数据库中创建、操作和查询数据。

用 SQLite 建立数据库

在本练习中,我们将使用 SQLite,它类似于其他 SQL 数据库,只是它是一个单磁盘文件,因此没有中间服务器进程。这些特性使得 SQLite 更适合小型项目,因为它是基于文件的,所以不需要任何安装。在您的命令行中,您可以简单地键入sqlite3 ,后跟您想要访问或创建的数据库的名称exercise.sqlite

您会注意到终端提示符变成了sqlite>。您可以在这里键入您的 SQL 命令,后跟一个分号(;)来执行它们。

创建表格

我们现在将尝试重新创建上面的插图,它显示了客户表和贷款表。SQL 命令的语法遵循简单的模式:CREATE TABLE table_name (column_name data_type constrains)创建表,ALTER TABLE table_name ADD/DROP COLUMN column_name修改表。

指定哪种数据将被插入到表中是很重要的。SQL 支持不同的字段类型,包括字符串、数字、日期和时间。有关不同数据类型的更多细节,您可以查看此链接

创建表时,还可以添加几个约束。最常见的是NOT NULL,它防止列有空值,以及PRIMARY KEYFOREIGN KEY,它们唯一地标识一个表中或另一个表中的记录。

CREATE TABLE customers (
    customer_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(50) NOT NULL
);CREATE TABLE loans (
    loan_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    customer_id INTEGER NOT NULL,
    requested DOUBLE NOT NULL,
    approved DOUBLE NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers (customer_id) ON DELETE CASCADE ON UPDATE CASCADE
);

到目前为止,我们的数据库有一个结构,但没有数据。您可以通过键入以下代码向表中添加数据。请注意,两个表的第一列只支持主键,因此,如果我们使用现有的条目,我们将会得到一个错误。

/*Data for the table customers */INSERT INTO customers (customer_id,name,email) VALUES (1,'Grace','grace@gmail.com');
INSERT INTO customers(customer_id,name,email) VALUES (2,’James’,’james@gmail.com’);
INSERT INTO customers(customer_id,name,email) VALUES (3,’Tony’,’tony@gmail.com’);
INSERT INTO customers(customer_id,name,email) VALUES (4,’Alex’,’alex@gmail.com’);/*Data for the table loans */INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (1,1,80.00,80.00);
INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (2,4,100.00,80.00);
INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (3,4,50.00,50.00);
INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (4,2,140.00,0.00);
INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (5,1,200.00,0.00);
INSERT INTO loans(loan_id,customer_id,requested,approved) VALUES (6,1,100.00,100.00);

要更新或删除记录,您可以使用UPDATEDELETE命令。

示例:UPDATE loans SET customer_id = 3 WHERE loan_id = 1;将表 loans 中的 customer_id 更改为 3,其中 loan_id 等于 1。

示例:DELETE FROM customers WHERE name like 'Leonard';客户表中删除所有名为“伦纳德”的客户。

在 Python 环境中查询数据库

就我个人而言,我更喜欢使用 Jupyter Notebook 来查询数据库,而不是终端,因为它有更好的视觉效果。有几种方法可以直接在笔记本上运行 SQL。

一个不需要安装任何库的选项是使用 Python SQLite3 包。只需导入库并运行下面的代码来建立与数据库的连接。

import sqlite3                              # import library
sqlite_db = 'exercise.sqlite'               # select database
conn = sqlite3.connect(sqlite_db)           # connect
c = conn.cursor()                           # create cursor object

使用 SQLite3 时,有必要创建 cursor 对象来迭代数据行并获取信息。创建表的语法类似于控制台,只是现在我们需要编写括号内的 SQL 代码,并使用游标对象c.execute()方法执行它。

c.execute("INSERT INTO customers VALUES (5,’Ann’,’ann@gmail.com’);")# commit changes
conn.commit()

从表中选择列

现在我们都设置好了,我们可以运行我们的第一个数据查询。每个数据查询中必须存在的两个主要子句是SELECTFROM

SELECT允许从数据库中选择我们想要的列。

FROM指定我们从哪个表中提取列。

要使用 SQLite3 包运行查询,首先我们需要存储我们的结果,然后使用.fetchall()方法提取它们。

results = c.execute("SELECT * FROM loans")    
results.fetchall()

另一种方法是使用 pandas 函数.read_sql()将 SQL 查询读入数据帧。

sql_query = (“SELECT * FROM loans”) 
pd.read_sql(sql_query, con=conn)

请注意,要选择所有列,可以使用星号(*)。SQL 也是不区分大小写的,这意味着键入SELECTselect没有区别。

聚合函数

聚合函数接受值列表并返回单个值。它们可以在SELECT语句中使用,通常与GROUP BY函数结合使用。

最常见的有:AVG()COUNT()MAX()MIN()SUM()

sql_query = (“SELECT AVG(requested) FROM loans”) 
pd.read_sql(sql_query, con=conn)

在此示例中,查询返回请求贷款的平均金额。

过滤数据

WHERE子句是在 SQL 中过滤结果的最常见方式。它出现在FROM子句之后,包含一个或多个逻辑表达式,用于评估每一行,如果条件为真,则返回这些表达式。

WHERE子句中最常用的比较运算符有:=(等于)、< > or!=(不等于)、<(小于)、>(大于)、< =(小于等于)、> =(大于等于)。

逻辑运算符,如ANDORLIKE,也可用于检验条件的真值。要获得所有逻辑运算符的完整列表,我建议查看这个链接

sql_query = ("""SELECT * FROM customers
WHERE name = 'Tony' OR name = 'Grace'""")
pd.read_sql(sql_query, con=conn)

上面的查询返回姓名为“Tony”或“Grace”的客户。

分类数据

可以使用ORDER BY子句对查询结果进行排序。该子句出现在FROM子句和WHERE子句(如果存在)之后。要对结果进行排序,您需要指定要对值进行排序的列和顺序(升序ASC或降序DESC)。

sql_query = ("""SELECT loan_id, customer_id, requested 
FROM loans
WHERE approved != 0
ORDER BY customer_id ASC""")
pd.read_sql(sql_query, con=conn)

在此示例中,查询从表“loans”中选择三列,筛选数据,使批准的金额不等于 0,然后按 customer_id 以升序对结果进行排序。

分组数据

SELECT语句之后使用GROUP BY子句将行组合成组。如果您想在分组之前过滤行,那么在GROUP BY子句之前应用WHERE子句,而要过滤组,您需要在分组之后使用HAVING子句。

sql_query = ("""SELECT customer_id, AVG(requested) AS avg_requested 
FROM loans
GROUP BY customer_id
HAVING avg_requested > 100
ORDER BY customer_id ASC""")
pd.read_sql(sql_query, con=conn)

这里,数据按 customer_id 分组并进行筛选,以便每个客户的平均请求量大于 100。请注意,最后添加了ORDER BY子句。

连接表格

到目前为止,我们一直是一次查询一个表,但是我们也可以将表链接在一起,同时查询它们。这个过程被称为“连接”,类似于交叉表的概念。最常见的连接类型有:

INNER JOIN:只保留两个表共有的行。

LEFT JOIN:将保留第一个表格的行。

RIGHT JOIN:将保留第二个表格的行。

FULL OUTER JOIN:将保留两个表中的行。

sql_query = ("""SELECT * FROM customers
LEFT JOIN loans ON customers.customer_id = loans.customer_id""")
pd.read_sql(sql_query, con=conn)

在此查询中,我们将连接列“customer_id”上的两个表。因为我们使用了LEFT JOIN,所以即使 Ann 没有申请贷款,结果也会包含“customers”表中的所有行。

如果我们使用INNER JOIN,结果将只包括请求贷款的客户。

其他资源和注意事项

本教程到此为止!如果你喜欢它,请继续关注,因为还会有更多的。与此同时,您可以查看sqltutorial.org了解更多关于 SQL 语法和子句的细节。

注意,根据您使用的数据库,SQL 有许多方言,所以一定要检查可能的差异。

领英:https://www.linkedin.com/in/veronica-nigro/

[## veronicanigro -概述

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

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

自然语言处理词干初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-stemming-in-natural-language-processing-34ddee4acd37?source=collection_archive---------26-----------------------

通过减少单词的词干来降低维数并改善结果

照片由 Pixabay 发自 Pexels

我的工作几乎完全专注于 NLP。所以我用文字工作。很多。

文本 ML 有它自己的挑战和工具。但一个反复出现的问题是维度过多。

在现实生活中(不是 Kaggle),我们通常只有有限数量的带注释的例子来训练模型。并且每个例子通常包含大量的文本。

这种稀疏性和缺乏共同特征使得很难在数据中发现模式。我们称之为维度诅咒

一种降维技术是词干

它从一个单词中去掉后缀,得到它的“词干”。

于是fisher变成了fish

让我们来学习词干是如何工作的,为什么要使用它,以及如何使用它。

什么是词干?

后缀

词干提取通过去除后缀来减少单词的词干(词根)。

后缀是修饰词义的词尾。这些包括但不限于...

-able
-ation
-ed
-er
-est
-iest
-ese
-ily
-ful
-ing
...

显然,runnerrunning这两个词有不同的意思。

但当涉及到文本分类任务时,这两个词都暗示着一个句子在谈论类似的东西。

该算法

词干算法是如何工作的?

简而言之,算法包含一系列删除后缀的规则,这些规则有条件地应用于输入令牌。

这里没有任何统计数据,所以算法是非常基本的。这使得词干分析可以在大量文本中快速运行。

如果你感兴趣,NLTK 的波特词干算法是免费的,这里是的,解释它的论文是这里是

也就是说,有不同的词干算法。仅 NLTK 就包含波特、斯诺鲍和兰开斯特。一个比一个更积极地阻止。

阻止文本的原因

语境

NLP 的很大一部分是弄清楚一个文本主体在说什么。

虽然不总是正确的,但包含单词planting的句子经常谈论与包含单词plant的另一个句子相似的事情。

考虑到这一点,为什么不在训练一个分类模型之前,先把所有的单词归到它们的词干中呢?

还有另一个好处。

维度

大量的文本包含大量不同的单词。结合有限数量的训练示例,稀疏性使得模型很难找到模式并进行准确的分类。

减少单词的词干减少了稀疏性,使发现模式和做出预测变得更容易。

词干分析允许每个文本字符串用一个更小的单词包来表示。

举例:词干化后的句子,"the fishermen fished for fish",可以用这样一包词来表示。

[the, fisherman, fish, for]

而不是。

[the, fisherman, fished, for, fish]

这既降低了样本之间的稀疏性,又提高了训练算法的速度。

根据我的经验,与使用单词嵌入相比,通过词干处理丢失的信号非常少。

Python 示例

我们将从一串单词开始,每个单词的词干都是“鱼”。

'fish fishing fishes fisher fished fishy'

然后对该字符串中的标记进行词干处理。

from nltk.tokenize import word_tokenize
from nltk.stem.porter import PorterStemmer text = 'fish fishing fishes fisher fished fishy' # Tokenize the string
tokens = word_tokenize(text)
print(tokens) 
#=> ['fish', 'fishing', 'fishes', 'fisher', 'fished', 'fishy'] stemmer = PorterStemmer()
stems = [stemmer.stem(w) for w in tokens]
print(stems)
#=> ['fish', 'fish', 'fish', 'fisher', 'fish', 'fishi']

结果是。

['fish', 'fish', 'fish', 'fisher', 'fish', 'fishi']

请注意,它并没有将所有记号都简化为“fish”这个词干。波特算法是最保守的词干提取算法之一。也就是说,这仍然是一个进步。

结论

有趣的是,预处理是 NLP 管道中最重要的(也是被忽略的)部分。

它决定了最终馈入 ML 模型的数据的形状,以及馈入模型质量数据和垃圾之间的区别。

正如他们所说,垃圾进,垃圾出。

在删除标点符号和停用词之后,词干是大多数 NLP 管道的关键组成部分。

词干化(和它的表亲词汇化)会给你更好的结果,使用更少的数据,并减少模型训练时间。

监督机器学习算法初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-supervised-machine-learning-algorithms-6e7cd9f177d5?source=collection_archive---------52-----------------------

预测分析路线图

照片由威廉·布特Unsplash 拍摄

如果你在这里阅读这篇文章,你一定很清楚机器学习的重要性。近年来,由于许多商业领域的高需求和技术的进步,机器学习的流行程度已经大大增加。有各种各样的机器学习算法,可以分为三个主要类别:

  • 监督学习算法在给定一组观察值的情况下,对特征(独立变量)和标签(目标)之间的关系进行建模。然后,该模型被用于使用这些特征来预测新观察的标签。
  • 无监督学习算法试图在未标记的数据中找到结构。
  • 强化学习基于行动奖励原则工作。一个代理通过迭代计算其行动的回报来学习达到一个目标。

在这篇文章中,我将向您概述常用的监督机器学习算法。监督学习算法试图使用特征(自变量)来预测目标(因变量)。根据目标变量的特性,可以是分类(离散目标变量)或回归(连续目标变量)任务。我们将讨论的算法包括:

  • 线性回归
  • 支持向量机
  • 朴素贝叶斯
  • 物流回归
  • k-最近邻
  • 决策树
  • 随机森林
  • 梯度推进决策树

我们开始吧。

线性回归

线性回归试图通过对数据拟合线性方程来模拟目标变量和一个或多个自变量之间的关系。顾名思义,目标变量是连续的,如价格、对象的面积或长度。

线性回归是一个好的选择,自变量和目标变量之间需要有线性关系。有许多工具可以探索变量之间的关系,如散点图和相关矩阵。例如,下面的散点图显示了两个变量之间的正相关关系。一个增加,另一个也增加。

线性回归模型试图将回归线拟合到最能代表关系或相关性的数据点。最常用的技术是普通最小二乘法 (OLE)。使用这种方法,通过最小化数据点和回归线之间距离的平方和来找到最佳回归线。对于上面的数据点,使用 OLE 获得的回归线看起来像:

这是一个自变量和一个目标变量的情况。对于包含多个独立变量的问题,我们也可以使用线性回归。

支持向量机

支持向量机(SVM)主要用于分类任务,但也适用于回归任务。

SVM 通过画一个决定边界来区分阶级。如何绘制或确定决策边界是 SVM 算法中最关键的部分。在创建决策边界之前,在 n 维空间中绘制每个观察值(或数据点)。“n”是使用的特征数量。例如,如果我们使用“长度”和“宽度”来对不同的“细胞”进行分类,则观察值被绘制在二维空间中,而决策边界是一条线。如果我们使用 3 个特征,则判定边界是三维空间中的平面。如果我们使用 3 个以上的特征,决策边界就变成了一个超平面,很难可视化。

二维空间中的决策边界

以到支持向量的距离最大化的方式绘制决策边界。如果决策边界离支持向量太近,会对噪声高度敏感,不能很好地泛化。即使独立变量非常小的变化也可能导致错误分类。

如果你想阅读一个关于 SVM 实现的更详细的帖子,你可以访问下面的帖子:

[## 支持向量机—解释

详细的理论解释和代码示例

towardsdatascience.com](/support-vector-machine-explained-8d75fe8738fd)

朴素贝叶斯

朴素贝叶斯是一种用于分类任务的监督学习算法。因此,它也被称为朴素贝叶斯分类器。

朴素贝叶斯假设特征相互独立特征之间没有相关性。然而,现实生活中并非如此。这种特征不相关的天真假设是这种算法被称为“天真”的原因。

朴素贝叶斯算法背后的直觉是贝叶斯定理:

p(A|B):给定事件 B 已经发生的概率

p(B|A):事件 B 的可能性给定事件 A 已经被占用

p(A):事件 A 的概率

p(B):事件 B 的概率

朴素贝叶斯分类器计算给定一组特征值(即 p(yi | x1,x2,…,xn))的类的概率。将此输入贝叶斯定理:

p(x1,x2,…,xn | yi) 表示给定类别标签的特征的特定组合的概率。为了能够计算这一点,我们需要非常大的数据集来估计所有不同特征值组合的概率分布。为了克服这个问题,朴素贝叶斯算法假设所有特征都是相互独立的。此外,分母(p(x1,x2,…,xn))可以被移除以简化方程,因为它仅归一化给定观察值的类的条件概率的值(p(yi | x1,x2,…,xn))。

一个类的概率(p(yi))很容易计算:

在特征相互独立的假设下, p(x1,x2,…,xn | yi) 可以写成 :

给定类标签(即 p(x1 | yi))的单个特征的条件概率可以更容易地从数据中估计出来。该算法需要独立地存储每个类别的特征的概率分布。例如,如果有 5 个类别和 10 个特征,则需要存储 50 个不同的概率分布。

综上所述,对于朴素贝叶斯算法来说,计算观察一类给定值的特征的概率( p(yi | x1,x2,…,xn) ) 变得很容易

下面是一篇关于朴素贝叶斯的更详细的文章,并附有一个例子:

[## 朴素贝叶斯分类器-解释

scikit-learn 的理论和实现

towardsdatascience.com](/naive-bayes-classifier-explained-50f9723571ed)

逻辑回归

逻辑回归是一种监督学习算法,主要用于二元分类问题。虽然“回归”与“分类”相矛盾,但这里的重点是“逻辑”一词,指的是在该算法中执行分类任务的逻辑函数。逻辑回归是一种简单但非常有效的分类算法,因此它通常用于许多二元分类任务。客户流失、垃圾邮件、网站或广告点击预测是逻辑回归提供强大解决方案的一些领域的例子。

逻辑回归的基础是逻辑函数,也称为 sigmoid 函数,它接受任何实数值并将其映射到 0 到 1 之间的值。

假设我们要求解以下线性方程:

逻辑回归模型将线性方程作为输入,并使用逻辑函数和对数比值来执行二元分类任务。然后,我们会得到著名的逻辑回归 s 形图:

我们可以“原样”使用计算出的概率。例如,输出可以是电子邮件是垃圾邮件的概率是 95%,或者客户将点击该广告的概率是 70%。然而,在大多数情况下,概率被用来分类数据点。如果概率大于 50%,则预测为正类(1)。否则,预测为负类(0)。

如果你想深入了解,这里有一个更详细的帖子:

[## 逻辑回归—已解释

详细的理论解释和 scikit-learn 示例

towardsdatascience.com](/logistic-regression-explained-593e9ddb7c6c)

K-最近邻(kNN)

k-最近邻(kNN)是一种受监督的机器学习算法,可用于解决分类和回归任务。kNN 背后的主要思想是,数据点的值或类由其周围的数据点决定。

kNN 分类器通过多数表决原则确定数据点的类别。例如,如果 k 设置为 5,则检查 5 个最近点的类。根据多数类进行预测。类似地,kNN 回归取 5 个最近点的平均值。让我们看一个例子。考虑以下属于 4 个不同类别的数据点:

让我们看看预测类如何根据 k 值变化:

确定最佳 k 值是非常重要的。如果 k 太低,模型太具体,不能很好地概括。它对噪音也很敏感。该模型在训练集上实现了高精度,但是在新的、以前看不到的数据点上将是差的预测器。因此,我们很可能以一个过度拟合的模型而告终。另一方面,如果 k 太大,则该模型太一般化,并且在训练集和测试集上都不是好的预测器。这种情况被称为欠适配。

以下是 kNN 上更详细的帖子:

[## k-最近邻(kNN)-解释

详细的理论解释和 scikit-learn 实现

towardsdatascience.com](/k-nearest-neighbors-knn-explained-cbc31849a7e3)

决策树

决策树建立在反复询问问题以划分数据的基础上。用决策树的可视化表示来概念化分区数据更容易:

这代表了预测客户流失的决策树。第一次拆分基于每月费用金额。然后算法不断提问分离类标签。随着树越来越深,问题也越来越具体。

你在每一步问什么是最关键的部分,并极大地影响决策树的性能。例如,假设数据集的“要素 A”范围为 0 到 100,但大多数值都在 90 以上。在这种情况下,首先要问的问题是“特征 A 大于 90 吗?”。问“特性 A 大于 50 吗?”是没有意义的因为它不会给我们太多关于数据集的信息。

我们的目标是在每次分区时尽可能增加模型的预测性,以便模型不断获得关于数据集的信息。随机分割要素通常不会给我们提供关于数据集的有价值的信息。增加节点纯度的分割更能提供信息。节点的纯度与该节点中不同类的分布成反比。要问的问题是以增加纯度或减少杂质的方式选择的。

我们要问多少问题?我们什么时候停止?什么时候我们的树足以解决我们的分类问题?所有这些问题的答案将我们引向机器学习最重要的概念之一:过拟合。模型可以一直提问,直到所有节点都是纯的。纯节点只包括来自一个类的数据点。

模型可以一直提问(或者拆分数据),直到所有的叶子节点都是纯的。然而,这将是一个过于具体的模型,不能很好地概括。它在训练集上实现了高精度,但在新的、以前看不到的数据点上表现不佳。

随机森林

随机森林是许多决策树的集合。随机森林是用一种叫做装袋的方法构建的,其中每个决策树都被用作并行估计器。如果用于分类问题,结果基于从每个决策树接收的结果的多数投票。对于回归,叶节点的预测是该叶中目标值的平均值。随机森林回归取决策树结果的平均值。

随机森林降低了过度拟合的风险,并且准确性比单个决策树高得多。此外,随机森林中的决策树并行运行,因此时间不会成为瓶颈。

随机森林的成功高度依赖于使用不相关的决策树。如果我们使用相同或非常相似的树,总体结果将不会比单个决策树的结果有太大的不同。随机森林通过自举特征随机性实现不相关的决策树。

  • Bootsrapping 是从带有替换的训练数据中随机选择样本。它们被称为 bootstrap 样本。下图清楚地解释了这一过程:

图源

  • 通过为随机森林中的每个决策树随机选择特征来实现特征随机性。随机森林中每棵树使用的特征数量可通过 max_features 参数控制。

特征随机性

自助样本和特征随机性为随机森林模型提供了不相关的树。

下面是一篇关于决策树和随机森林的详细文章,并附有一个实现示例:

[## 决策树和随机森林—解释

详细的理论解释和代码示例

towardsdatascience.com](/decision-tree-and-random-forest-explained-8d20ddabc9dd)

梯度推进决策树(GBDT)

GBDT 算法,该算法使用助推方法来组合个体决策树。

Boosting 是指将一个学习算法串联起来,从许多顺序连接的弱学习器中实现一个强学习器。在梯度提升决策树算法的情况下,弱学习器是决策树。

每棵树都试图最小化前一棵树的错误。boosting 中的树是弱学习器,但是连续添加许多树,并且每个树集中于前一个树的错误,使得 boosting 成为高效且准确的模型。与装袋不同,增压不涉及自举取样。每次添加新树时,它都适合初始数据集的修改版本。

由于树是按顺序添加的,boosting 算法学习起来很慢。在统计学习中,学习速度慢的模型表现更好。

梯度提升算法以这样的方式顺序地组合弱学习器,即每个新的学习器适合于来自前一步骤的残差,从而改进模型。最终的模型汇总了每一步的结果,从而形成了一个强学习者。梯度提升决策树算法使用决策树作为弱学习器。损失函数用于检测残差。例如,均方误差(MSE)可用于回归任务,对数损失(log loss)可用于分类任务。值得注意的是,当添加新的树时,模型中现有的树不会改变。添加的决策树符合当前模型的残差。

GBDT 算法非常强大,已经实现了许多升级版本,如 XGBOOST、LightGBM、CatBoost。

以下是关于 GBDT 的详细帖子:

[## 梯度推进决策树-解释

详细解释了 boosting 和 scikit-learn 实现

towardsdatascience.com](/gradient-boosted-decision-trees-explained-9259bd8205af)

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

参考文献

工具变量初学者指南

原文:https://towardsdatascience.com/a-beginners-guide-to-using-instrumental-variables-635fd5a1b35f?source=collection_archive---------22-----------------------

当他们可能成为你的超人时[包括 R 代码]

埃斯特万·洛佩兹在 Unsplash 上的照片

作为一名大学生,我学习经济学,这意味着我研究了很多回归。这基本上是课程的 90%(当然,当我们不讨论供需曲线时)。腐败对相扑的影响回归。最低工资变动对新泽西州一家温蒂的影响回归。又或许 僵尸律师天启 更是你的速度(还好,不是回归,不过标题很酷)。

不管怎样,我的大学生涯教会了我三件事:1)供给和需求,2)回归是生活,3)经济学家认为它们非常可笑。

但是如果你的回归失败了呢?如果它没有预测到它应该预测的事情,因为你的 X 与你没有数据的事情联系在一起,那该怎么办?

好吧,我的朋友们,那就是你可能要考虑使用静脉注射的时候了。

一个工具变量是第三个变量,Z,当你有内生变量时用于回归分析,这些变量受模型中其他变量的影响。换句话说,您可以用它来解释变量之间的意外行为。使用工具变量来识别隐藏的(未观察到的)相关性可以让您看到解释变量和响应变量之间的真实相关性,Y. — 统计如何

让我们把其中的一些分解成我们能理解的部分。

第 1 部分:线性回归方程

假设你有两个你认为相关的变量,教育和工资(X 和 Y)。你想调查教育是否会导致更高的工资,即 X → Y。这很有道理。你写 y = α + βx + ε ,然后,满足于自己,用剩下的时间狂吃权力的游戏。

等等。慢点。首先让我们澄清一些事情。

  • 【α=“起点”。并非所有回归都从零开始;例如,如果 X 是教育水平,Y 是工资,你不会从零教育水平开始(T4),因为现在大多数人不会在 2 年级、3 年级、4 年级甚至 9 年级后辍学(耶,进步!).你可能会考虑从高中文凭开始的教育,一年一次,截距解释了这一点。
  • β=X 影响 y 的权重。例如,如果 1 年的教育预计会带来 100 美元的额外工资,那么系数 β 就是 100。β指定了多受一年教育能给你带来多少。
  • ε =误差项。经济学家喜欢使用花哨的行话和希腊语,就像他们喜欢时髦的标题一样,所以ε只是错误的一个花哨的“e”。这吸收了 X 不能完美映射到 Y 的任何东西;很少会出现一对一映射的完美直线。

既然我们已经把 y = x 翻译成了 y = α + βx + ε。现在的问题与理论有关,如果X 真的导致 y。教育导致工资,这是有道理的;但是,如果努力接受高等教育的人也将获得更高的工资,因为他们是人口中更有活力、更有抱负、更有动力的一部分,那又会怎样呢?

这是个大问题。为什么?因为不是 X 导致了 Y,而是别的什么导致了 Y,那个“别的什么”目前被吸收在误差项里,因为我们无法衡量野心。这违反了线性回归的基本假设。经济学家称之为内生性。

埃斯特万·洛佩兹Unsplash 上的照片

第 2 部分:选择工具变量

我们想用 y = α + βx + ε ,但很快就清楚了,x、教育和 y、工资,也受到 z、野心/驱动力/那种创造出迈克尔·乔丹这样的人的神奇品质的影响。既然我们无法衡量抱负并将其转化为一个整洁的 CSV,我们该怎么办?

我们用别的东西,一些可测量的东西,与教育(X)相关,但与误差项(ε)无关。

这些是 IV 的要求:1)它们不能与错误(外生性)相关,2)它们与 X(教育)相关

在这种情况下,早期吸烟行为是一个很好的工具。为什么?因为早期吸烟行为和受教育年限是相关的。另一方面,早期吸烟行为和野心则不是;许多成功人士都有吸烟的艰难童年。事实上,Matt Dickson 博士已经发表了一篇关于这种效应的论文。

我在例子中使用了太多表情符号吗?🤷表情符号中的耸肩

第 3 部分:通过 2SLS 使用工具变量

现在你有了 X ( 学历),Y ( 工资),Z ( 早期吸烟行为)的数据。你已经宣布 Z 将成为一个很好的工具变量来处理 x 的内生性遗传。还有一个问题:我们如何在回归方程中包含一个工具变量?

我们将通过创建两个方程来做到这一点,这被称为两阶段最小二乘(2SLS) 估计。它所实现的只是将教育变量稍微重新定义为早期吸烟行为的函数:

  • 教育= c + d(早期吸烟行为)+ v*
  • 工资=α+β学历+* ε**

在这个例子中, c 是起点(像 α),d 是权重(像),而是误差(像 ε )。我们首先将教育变量重新校准为早期吸烟行为的函数,然后将我们的新定义代入原始方程。这就是为什么它被称为两阶段最小二乘法;我们创建了两个方程来正确回答第一个方程。**

第 4 部分:R 中的分析

你现在已经有了理解什么是工具变量,以及我们如何在 IRL 和 2sl 中使用它所需的所有理论。在 R 中运行分析非常简单:

**install.packages("AER")          # library with ivreg() function
library(AER)reg_1 = ivreg(wages ~ education | early_smoking_age, data = _source)**

用人类的话来说;这种回归是关于工资的教育,早期吸烟年龄被用作一种工具。正在使用的数据源称为 *_source* 。我将这个回归命名为 *reg_1* ,这样我以后可以调用它。

整个ivreg()文档在这里

照片由阿里·科卡布Unsplash 上拍摄

第五部分:结论

我花了很长的时间才明白一个工具变量的用途,或者说如何挑选一个很棒的;在完全理解之前,我甚至在 2019 年 UChicago 计量经济学比赛中获得了第二名。出于这个原因,如果你不完全理解静脉注射的一切,那也没什么,完全正常。

我希望你现在对使用工具变量有了更多的了解;如果你有任何想法,请在下面评论(或留下掌声)。感谢阅读!❤️

—阿曼达

参考文献

大卫·卡德和艾伦·克鲁格,《最低工资和就业:新泽西和宾夕法尼亚快餐业的案例研究》,1993 年 10 月(https://www.nber.org/papers/w4509.pdf)

马特·迪克森,重新审视教育对工资的因果影响,2009 年 9 月(http://ftp.iza.org/dp4419.pdf)

马克·达根和史蒂芬·列维特,《胜利不是一切:相扑中的腐败》,2000 年 7 月(https://pubs.aeaweb.org/doi/pdf/10.1257/000282802762024665)

黄文雄和科里·罗森,《僵尸律师启示录》,2014 年 8 月(https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2550498)

TensorFlow Lite 初学者入门

原文:https://towardsdatascience.com/a-beginners-introduction-to-tensorflow-lite-924320deed5?source=collection_archive---------15-----------------------

本文简要介绍了 TensorFlow,并概述了 TensorFlow Lite,包括它的优点和广泛使用的替代工具。

TensorFlow 徽标图像

本文的目标读者是那些想简单了解 TensorFlow 和 TensorFlow Lite 的人,不需要复杂的术语和代码。

机器学习技术在当前以各种形式可用的几个应用中得到利用。大多数利用机器学习,更具体地说,深度学习的应用程序都有需要 GPU 进行推理的 ML 模型。

面临的挑战是,我们如何让需要 GPU 能力的 ML 模型在处理芯片和存储空间不太强大的移动设备上有效运行。

通常,要在移动或嵌入式设备上访问 ML 功能,ML 模型需要托管在云服务器上,并通过 Restful API 服务访问。

但今天,我们将探索工具,使 ML 模型足够高效和优化,以驻留在这些设备中。

这就是 TensorFlow 和 TensorFlow Lite 的用武之地。

什么是张量流?

“TensorFlow 是一个端到端的开源机器学习平台”——Tensorflow.org

来自官方网站的 Tensorflow 的定义可以被分解成单独的组件,这些组件提供了对流行的机器学习框架对机器学习社区的贡献的理解。

首尾相连。 Tensorflow 为各个阶段的机器学习问题提供了全面的解决方案。短语端到端意味着张量流在以下阶段是有用的:

  • 机器学习模型的实现和发展
  • 机器学习模型的训练和评估
  • 机器学习模型的部署和生产

开源。Google Brain 团队开发了 TensorFlow ,但该软件于 2015 年 11 月获得开源状态,这意味着 TensorFlow 的源代码对 ML 社区公开以供测试和修改。

机器学习平台。 Tensorflow 提供了一系列工具,使机器学习模型能够实现各种目的和环境。在整理的工具中有 TensorBoard (与 ML 模型相关的度量/数据的可视化和跟踪工具)和 Colab (用于实现 ML 模型的在线 Jupyter 笔记本环境)。

什么是 TensorFlow lite?

当使用 TensorFlow 实现和训练 ML 模型时,您通常会得到一个需要足够存储空间和 GPU 来运行推理的模型文件。大存储空间和 GPU 等奢侈品是大多数移动设备所不具备的。

TensorFlow Lite 是在移动设备中启用 ML 模型的解决方案。

TensorFlow Lite 是一个开源的深度学习框架,用于设备上的推理。—Tensorflow.org/lite

我们之前已经介绍了什么是开源,大多数读者都熟悉术语'深度学习',如果不熟悉,请查看这篇文章,其中包括一些标准 ML 术语的定义,包括深度学习。

[## 你是什么类型的人工智能爱好者?

根据人工智能领域内的常用术语,衡量你在人工智能爱好者等级中的排名。

towardsdatascience.com](/what-type-of-artificial-intelligence-enthusiast-are-you-32ca88c01a7e)

设备上的推断。此短语指的是在智能手机等设备中利用 TensorFlow Lite 实现的模型的能力,更重要的是在存储空间有限的设备中。

TensorFlow Lite 模型存在于设备中,具有低延迟,这对于实时推理应用程序至关重要,因为从移动设备到托管模型的云服务器的网络往返可能会考验应用程序用户的耐心。

TensorFlow Lite 采用现有的 TensorFlow 模型,将它们以. tflite 文件的形式转换成优化的高效版本。流线型模型足够小,可以存储在设备上,并且足够精确,可以进行适当的推断。

TensorFlow Lite 可以用在哪里?

TensorFlow Lite 的应用领域在本文中已经提到过几次,但本节将详细讨论 TensorFlow lite 的应用领域。

  • 移动设备(iOS 和 Android) :移动设备是利用 TensorFlow Lite 模型的主要设备。TensorFlow Lite 提供了各种预训练模型,可以轻松转换为。tflite 版本,并在其专用开发环境中与移动应用程序集成。
  • 物联网设备
  • 树莓派

Tensorflow Lite 有哪些优点?

  • 轻松将 TensorFlow 模型转换为 TensorFlow lite 模型,用于移动优化模型
  • 轻松开发 iOS 和 Android 设备的 ML 应用程序
  • 与基于服务器的模型相比,移动模型支持的更有效替代方案
  • 在移动设备上启用离线推断
  • Tensorflow Lite 使您能够在移动和嵌入式设备上以低延迟快速运行机器学习模型,因此您可以在这些设备上执行典型的机器学习,而无需使用外部 API 或服务器。这意味着您的模型可以在离线设备上运行。
  • 您训练一个 TensorFlow 模型,然后将其转换为 TensorFlow Lite 模型,通过 TensorFlow lite 模型文件,您可以将您的应用程序转换为 android 应用程序或 iOS 应用程序

Tensorflow Lite 有哪些缺点?

  • 一些型号仍然太大,无法存储在设备上
  • TensorFlow Lite 模型中的效率和优化成本是对模型准确性的权衡。因此,TensorFlow Lite 模型的精确度低于其同类产品。

Tensorflow lite 有哪些替代品?

  • Core ML :这是苹果发布的一个框架,用来打造 iOS 专用机型。CoreML 为常见的机器学习任务(如识别和检测)提供了一些模型。它是 TensorFlow Lite 的 iOS 专用替代产品。
  • py torch Mobile:py torch 是一个流行的机器学习框架,被广泛用于机器学习相关的研究。PyTorch mobile 可以与 TensorFlow Lite 相比较,因为它能够将 PyTorch 训练模型转换为移动优化版本,可以在 iOS 和 Android 设备上利用。虽然,PyTorch Mobile 还处于起步阶段,目前处于实验发布状态。
  • 在云服务上托管模型 ( GCPAWS )并通过 REST APIs 公开功能

随着我探索更多的生态系统并在实际环境中利用它们,我将在 TensorFlow 和 TensorFlow Lite 上写更多的东西。

如果你喜欢这篇文章,并想阅读类似的内容,请在 Medium 上关注我。

异步编程的更好方法:多线程上的异步

原文:https://towardsdatascience.com/a-better-way-for-asynchronous-programming-asyncio-over-multi-threading-3457d82b3295?source=collection_archive---------3-----------------------

用 Python 中的 asyncio 库应对 I/O 限制挑战。我将为您提供一个完美的解决方案来获取数百万个 URL,这将击败多线程的性能。

卡罗琳娜·格拉博斯卡像素上拍摄的照片

如果您来到这里,可能是因为您听说过 Python 3.4 中引入的 asyncio 模块。你可能想知道你是否应该开始使用它。我记得那一刻我被它精彩的表演惊呆了。在我了解 asyncio 之前,我一直在使用多处理和线程来提高作业速度。它们工作得很好,直到有一天我在处理数亿个 URL 调用时遇到了瓶颈。这一挑战促使我寻找其他可行的解决方案来完成 I/O 任务。虽然它的语法和概念初看起来很复杂,但 asyncio 最终成为了改变人生的工具。

异步编程

一个 syncio 完全是关于异步编程的,但它不是异步运行作业的唯一选项。你可能会在这里打断我,问我,什么是异步编程?简单来说,异步编程允许不同的任务开始执行,而不需要等待前一个任务完成。这是一个巨大的数字,因为读取 URL 的大部分时间是由网络延迟造成的。在等待另一台服务器的响应时,没有必要忍受高延迟并保持机器空闲。异步编程正好解决了这个问题。

多线程上的异步

多线程是异步执行任务的传统解决方案。异步和多线程同时运行。哦,等等,什么是并发?并发是与并行相对的概念;它意味着同时执行多个任务,但不一定是同时执行,而并行意味着同时执行任务。这两个概念之间的区别在博客中并不重要(参见此处了解更多关于区别的信息),但是请记住,我们并不是在这篇博客中探索并行解决方案。听起来不错,并行对于 I/O 受限的任务来说并不理想;它可以很好地处理 CPU 绑定的任务。

那么如果都属于异步编程,为什么 asyncio 比多线程快呢?这是因为 asyncio 在任务调度方面更加健壮,并为用户提供了对代码执行的完全控制。您可以通过使用 await 关键字暂停代码,在等待期间,您可以什么都不运行或者继续执行其他代码。因此,资源在等待期间不会被锁定。

多线程的任务轮流方式完全不同。在线程中,Python 解释器负责任务调度。在事先不知道代码或任务的情况下,解释器在切换到下一个线程之前给每个线程一段时间来轮流利用资源。这种安排存在一定程度的低效。一个简单的任务可能会中途中断,不管它有多琐碎。资源可能被锁定到一个线程,在该线程中,任务仍在等待来自外部服务器的响应,因此没有准备好继续进行。因此,在时间和资源上仍然存在一些浪费。

多线程基准测试

在我们进入 asyncio 之前,让我们使用多线程作为基准!对于所有的例子,我的机器有 8 个 CPU。

用于测试的所有库都在前面导入。是的,我使用日志。我基本上已经把打印掉了,换成了记录。记住总是使用异常。一个详细的例外是最好的。但是如果你不知道或者不关心,就用通用异常

代码片段中有两个函数。

  • 第一个函数, fetch_url 使用 requests 模块和 GET 方法从指定的 url 检索数据。try 和 except 块捕获服务器或超时错误,这样我们就可以不间断地运行多线程。
  • 第二个函数, fetch_all 使用线程池通过 concurrent.futures 模块中的 ThreadPoolExecutor() 异步执行第一个函数。 map 方法收集所有线程的响应。
  • 在这两个函数之外,它多次调用 fetch_all 。每次,我们传递一个不同长度的 URL 列表,并记录它所花费的时间。

现在让我们来看看一些性能结果:

INFO:root:Fetch 1 urls takes 0.7269587516784668 secondsINFO:root:Fetch 10 urls takes 0.7232849597930908 secondsINFO:root:Fetch 100 urls takes 5.631572008132935 secondsINFO:root:Fetch 500 urls takes 10.897085905075073 secondsINFO:root:Fetch 1000 urls takes 20.450702905654907 seconds

结果一点都不差。你可以看到多线程在读取 1000 个 URL 方面做得相当不错。

asyncio 简介

**import** asyncio
**from** aiohttp **import** ClientSession

async **def** fetch(url):
    async **with** ClientSession() **as** session:
        async **with** session.get(url) **as** response:
            return await response.read()

这基本上就是 asyncio 版本的 fetch_url。我使用 aiohttp ,因为它提供了一个优秀的客户端会话,我们可以在其中异步地发出 http 请求。

除了 aiohttp 。使用异步等待语法,代码可能看起来很奇怪。这两个是 asyncio 的关键符号。 async defasync with 语句创建可暂停执行的协程对象; await 关键字告诉程序等待哪个执行。这两个关键字的使用使得代码异步运行成为可能。

我们不直接调用 fetch 函数来启动异步执行。相反,我们需要创建一个事件循环,并在循环中添加任务。下面两行代码帮助您开始只获取一个 URL。

loop = asyncio.get_event_loop()
loop.run_until_complete(fetch(url))

要运行多个 URL 并异步收集所有响应,您需要利用来自 asyncio确保 _ 未来收集函数。

一个完美的例子

我希望你还记得之前的多线程例子,因为我现在向你展示的是一个完整的 asyncio 版本!代码片段的结构与多线程示例相同。

使用 asyncio 获取 URL

  • 它拥有从之前的 asyncio 介绍中升级的 fetch 功能。它通过启用额外的异常来升级。另一个大的变化是客户端会话变成了函数的一个参数。
  • fetch_asyncfetch_allasyncio 版本。函数创建了一个客户端会话,其中创建了一个事件循环并加载了任务,其中一个 URL 请求就是一个任务。这是一个重要的经验,让一个客户机会话处理所有 HTTP 请求是一种更好、更快的方式。
  • 异步操作的结果是一个未来对象,并且在 fetch_async 中使用一个 gather 方法来聚集结果。
  • 一个定时器围绕着 fetch_async 函数调用来跟踪时间。

代码在与之前相同的 8 CPU 机器上执行,结果显示如下:

INFO:root:Fetch 1 urls takes 1.5993337631225586 secondsINFO:root:Fetch 10 urls takes 1.2335288524627686 secondsINFO:root:Fetch 100 urls takes 2.6485719680786133 secondsINFO:root:Fetch 500 urls takes 4.8839111328125 secondsINFO:root:Fetch 1000 urls takes 6.814634084701538 seconds

结果分析

  • 您可能已经注意到,在这两个例子中,1 个 URL 所需的时间比 10 个 URL 所需的时间稍长。这可能看起来与通常的做法相反。但是仔细想想。多线程和 asyncio 都是为“并行”任务设计的,它们都消耗了额外的资源来更快地完成任务。使用它们中的任何一个来阅读一个 URL 都不会节省你的时间,如果不是浪费你的时间的话。
  • 在 1 到 10 个 URL 之间, asyncio 花费更多的时间来发送请求和收集响应。这可能意味着多线程是小型 I/O 任务的首选。
  • 从 10 到 100 个 URL 之间的某个地方开始, syncio 的执行时间下降到多线程之下。随着 URL 数量的增加,两种解决方案的时间差越来越大。这说明了 asyncio 在大量 URL 请求上的卓越性能。

成为数据科学家比在线课程更好的方式

原文:https://towardsdatascience.com/a-better-way-to-become-a-data-scientist-than-online-courses-2abc343d4d55?source=collection_archive---------1-----------------------

意见

我认识的人是如何成为数据科学家的(包括我自己)

来自 Pexels 的 Andrea Piacquadio 的照片

这是一篇观点文章。我很想听听你下面的反驳。

你想成为一名数据科学家吗?

我和 50 多位数据科学家一起喝咖啡,并和另外几位一起工作。

在这里,我将解释这些人是如何过渡到数据科学的。

附:这不是网上课程。

1.用机器学习解决一个现实问题

挑一个现实问题,然后用机器学习解决。

这很难,因为没有路线图。但它提供了真实的经历和推销自己的故事,不管你是成功还是失败。

以下是你可以解决的问题:

  • 检测假新闻
  • 预测你家附近的房价
  • 根据人们的生活方式向他们推荐宠物

如果你的解决方案可行(甚至勉强可行),那么就建立一个其他人可以使用的 UI,并发布在黑客新闻或产品搜索上。

以“数据科学家”为标题,将经历加入简历。如果它解决了机器学习的一个问题,没有人会在乎这是一场独角戏。

现在你可以在面试中把这作为一个故事来讲述,这将比一个在线认证更有分量。

2.找一个人工智能专家的导师

与有经验的人建立关系,他们可以为你试图解决的问题推荐人工智能驱动的解决方案。

我就是这样闯入数据科学的。

作为一名软件工程师,一家创业加速器每周借给我的公司几个小时的人工智能博士学位。

每周,我们讨论问题和潜在的解决方案,我负责实施,然后我们回顾和重复。6 个月后,我们解决了几个重要的问题,这一经历是无价的。

我按照以下流程寻找后续的数据科学导师。

  • LinkedIn 上你所在城市的消息数据科学家
  • 邀请他们喝咖啡
  • 心中有一个具体的问题,以及你自己的潜在解决方案,以获得反馈
  • 实施解决方案后跟进结果

3.做机器学习实习

接受一份短期工作,报酬会少一些,但会让你接触到一个实现人工智能的真实项目。

我创业时的一名前 ML 实习生现在是脸书的一名数据工程实习生,这可能会成为一份全职工作。

这条路并不适合每一个人,如果你还年轻或者还在上学,效果会更好。不是每个人都有能力辞掉工作成为一名实习生,但是你也许可以在兼职或者网上找到工作。

其中重要的一部分是在你的简历中获得与人工智能相关的经验。

4.在你目前的工作中开始做数据科学

弄清楚你现在的公司如何利用 AI 解决一个问题。那就解决。

当你在工作的时候,你可能在 9 点到 5 点之间没有时间。但是如果你有动力,那就在晚上或者周末做。然后分享你的成就。

如果你现在的公司很小,没有人会反对你增加更多的价值。如果它真的有价值,你可能会被允许把它作为你的日常项目之一。

之后,如果可以的话,把这个项目放在你的简历上,并更新你的职位名称。

5.举办一次数据科学训练营

参加付费的数据科学训练营。

这要花钱,而且不是所有的训练营都是平等的,但我知道至少有 10 个人在训练营结束后进入了数据科学领域,而且都在声誉良好的大公司工作。

最好的训练营只接受博士,所以候选人的成功可能依赖于生存偏差(训练营接受无论如何都会成功的学生)。

新兵训练营在几个方面给候选人带来好处。

  • 候选人为真实的公司做咨询
  • 毕业生与寻求招聘的公司有联系
  • 提供工作准备

也就是说,不是每个毕业生都能找到工作。

6.先成为一名软件工程师

我在这里写了这个。

只要数据科学家用代码解决问题,就会和软件工程有很大的重叠。

在获得软件工程师的经验后,找一份使用与你的经验类似的技术堆栈(即:数据库、语言、框架、包)的数据科学工作。

如果你能勾选大多数工作要求框,你就有很好的机会获得面试。

首先成为一名软件工程师还有其他好处。

  • 挣一份体面的薪水
  • 在雇佣数据科学家的公司工作
  • 建立通才技术背景
  • 证明你可以做类似的工作

7.读一个技术博士或硕士学位,然后申请工作

你有 2 到 6 年的学习时间吗?我不知道。

但是我遇到的大部分数据科学家都走的这条路。

他们要么:

  • 人工智能相关的硕士学位
  • 技术博士(不一定是人工智能相关的)

我不建议你回到学校去研究数据科学。但如果你目前在学校,并且可以转到人工智能相关的学位,那么就去吧。有趣的是,人工智能薪水最高的需要更高的学位。

虽然昂贵且耗时,但传统学位具有在线认证所不具备的信任度。

网络课程呢?

有一个在线课程的地方。但不是为了找工作。

课程的好处包括学习你不知道的东西,深入钻研特定的技术。

但另一方面,课程给人一种成就感,而不会让你做最难、最有卖点的事情,解决一个真正的问题。

我会说,找到一个要解决的问题,然后使用在线课程来学习解决它。

你是如何看到人们闯入数据科学的?我喜欢在下面听到它。

使用 Spark NLP、Kafka 和 Vegas 可视化对 Meetup 事件进行大数据分析

原文:https://towardsdatascience.com/a-big-data-analysis-of-meetup-events-using-spark-nlp-kafka-and-vegas-visualization-af12c0efed92?source=collection_archive---------48-----------------------

使用流数据、命名实体识别和 Zeppelin 笔记本寻找趋势 Meetup 主题——疫情时报期间一个超级热情的工作小组的故事

我们从 bigdata.ro 开始作为一个工作组。这个团队由瓦伦蒂娜·克里桑奥维迪乌·波德里乌玛利亚·卡塔纳、克里斯蒂安·斯坦西乌勒斯库、埃德温·布林扎和我、安德烈·德乌斯特努组成。我们的主要目的是学习和实践 Spark 结构化流、机器学习和 Kafka。我们设计了整个用例,然后从头开始构建架构。

由于 Meetup.com 通过一个实时 API 提供数据,我们把它作为我们的主要数据源,我们没有把数据用于商业目的,只是用于测试。

这是一个学习案例故事。我们从一开始就不知道什么是可能的,什么是不可能的。回过头来看,有些步骤本可以做得更好。但是,嘿,生活就是这样的。

我们试图解决的问题:

  • 允许 meetup 组织者确定与其 meetup 相关的热门话题。我们根据与我们感兴趣的标签相匹配的事件描述来计算趋势话题。我们使用 John Snow Labs Spark NLP 库来提取实体。
  • 确定哪些 Meetup 活动在我们地区吸引了最多的响应。因此,我们根据与我们感兴趣的领域——大数据——相关的某些标签来监控聚会的回复。

为此,我们开发了两套可视化工具:

  • 趋势关键词
  • RSVPs 分布

体系结构

前两个元素在两组可视化中是通用的。这是从 Meetup.com API 读取数据并保存在 2 个 Kafka 主题中的部分。

  1. 流阅读器脚本从 Meetup 流 API 中获取由特定标签过滤的 Yes RSVPs 上的数据。然后,它选择我们需要的相关列。之后,它将这些数据保存到 rsvps_filtered_stream Kafka 主题中。
  2. 对于每个 RSVP,只有在 events.idx 文件中不存在 event_id 时,流读取器脚本才会为其获取事件数据。这样,我们可以确保只读取一次事件数据。流阅读器脚本的设置可以在-> 安装 Kafka 并获取 RSVP中找到

趋势关键词

趋势关键词建筑

3.Spark ML — NER 注释器从 Kafka 主题事件中读取数据,然后使用 Spark NLP 应用命名实体识别管道。最后,它将注释数据保存在 Kafka topic TOPIC_KEYWORDS 中。有密码的笔记本可以在这里找到

4.使用 KSQL,我们创建了 2 个后续流来转换数据,最后创建了一个表,Spark 将使用它进行可视化。在大数据架构中,SQL 引擎只构建一个逻辑对象,该对象将元数据分配给物理层对象。在我们的例子中,这些是我们在主题之上构建的流。我们通过 KSQL 将来自 TOPIC_KEYWORDS 的数据链接到一个新的流,称为 KEYWORDS。然后,使用 Create as Select,我们创建一个新的流 EXPLODED _ KEYWORDS,用于分解数据,因为所有的关键字都在一个数组中。现在,每个关键字都有一行。接下来,我们统计每个关键字的出现次数,并将其保存到一个表 KEYWORDS_COUNTED 中。用 KSQL 代码建立流和表的步骤可以在这里找到:卡夫卡——详细架构

5.最后,我们使用 Vegas 库来生成趋势关键词的可视化。描述所有步骤的笔记本可以在这里找到。

NER 管道的详细说明

为了注释数据,我们需要将数据转换成某种格式,从文本转换成数字,然后再转换回文本。

  1. 我们首先使用 DocumentAssembler 将文本转换成文档类型。
  2. 然后,我们使用句子检测器将文档分成句子。
  3. 在这之后,我们通过使用记号化器找到单词的边界来将文本分成更小的单元。
  4. 接下来,我们使用规格化器从文本中移除 HTML 标签和数字符号。
  5. 在准备和清理文本之后,我们需要把它转换成数字格式,向量。我们使用一个预先训练好的英语单词嵌入模型。
  6. 接下来是使用英语 NerDLModel 注释器进行实际的关键字提取。NerDL 代表命名实体识别深度学习。
  7. 接下来,我们需要将数字转换回人类可读的格式,即文本。为此,我们使用一个 NerConverter 并将结果保存在一个名为 entities 的新列中。
  8. 在将模型应用到我们的数据之前,我们需要运行一个空的训练步骤。我们在空数据帧上使用 fit 方法,因为模型是预先训练好的。
  9. 然后,我们将管道应用于我们的数据,并只选择我们感兴趣的字段。
  10. 最后我们将数据写入卡夫卡:主题 _ 关键词

RSVPs 分布

RSVPs 分布体系结构

3.使用 KSQL,我们聚合并连接来自 2 个主题的数据,以创建 1 个流 RSVPS_JOINED_DATA,并随后创建 1 个表 RSVPS_FINAL_TABLE,其中包含所有 RSVPS 计数。KSQL 操作及其代码可以在这里找到:卡夫卡——详细架构

4.最后,我们使用 Vegas 库来制作 RSVPs 在世界各地和罗马尼亚的分布的可视化。飞艇笔记本可以在这里找到。

基础设施

我们使用了一台来自 Hetzner Cloud 的机器,其规格如下:CPU:英特尔至强 E3 处理器–1275 V5(4 核/8 线程),存储:2×480 GB 固态硬盘(RAID 0),RAM: 64GB

形象化

RSVPs 分布

这些可视化是对世界协调时 5 月 8 日 22:15 到 6 月 4 日 11:23 之间的数据进行的。

全球 RSVPs 数量最多的国家

全球 RSVPs 数量最多的城市

如你所见,大多数回复发生在美国,但是回复数量最多的城市是伦敦。

全球—按回复人数排名的热门事件

罗马尼亚—罗马尼亚 RSVPs 数量最多的城市

如你所见,大多数 RSVPs 都在这个国家最大的城市。这可能是因为公司倾向于在这里设立办事处,因此吸引人才到这些地方。

罗马尼亚—热门 Meetup 活动

罗马尼亚— RSVPs 分布

*这是 Grafana 使用在 Spark 中处理并保存在本地的 RSVP 数据制作的。

欧洲— RSVPs 分销

*这是 Grafana 使用在 Spark 中处理并保存在本地的 RSVP 数据制作的。

趋势关键词

全球

这个可视化是根据 7 月份的数据完成的。

罗马尼亚

这种可视化是对从 8 月初开始的近 1 周的数据进行的。原因详见“遇到的问题”一节的第 5 点。

过程中发现的问题

所有这些在出版的笔记本中都有提及。

  1. 使用 Helium Zeppelin 插件和 Vegas 库直接从流中可视化数据是行不通的。我们必须将数据溢出到磁盘,然后在文件上构建数据帧,最后进行可视化。
  2. Spark NLP 不适用于 Spark 独立本地集群安装(带有本地文件系统)。独立本地集群意味着集群运行在同一台物理机器上——Spark Cluster Manager & Workers。这样的设置不需要分布式存储,如 HDFS。我们的解决方法是将 Zeppelin 配置为使用 local Spark,local (*),这意味着 Zeppelin 中可用的非分布式单 JVM 部署模式。
  3. Vegas 插件最初无法启用。运行github—% dep z . load(" org . Vegas-viz:Vegas _ 2.11:{ Vegas-version } ")—建议总是出现错误。解决方法是在/opt/spark/jars 中手动添加所有依赖项。这些依赖关系可以在使用 Vegas 库部署 spark shell 时找到—/opt/spark/bin/spark-shell–packages org . Vegas-viz:Vegas-spark _ 2.11:0 . 3 . 11
  4. 氦气飞艇插件不起作用/无法启用。当在我们的配置中从 Zeppelin GUI 启用它时,这也产生了一个错误。我们没能解决这个问题。这就是为什么我们只使用维加斯,虽然它不支持地图可视化。最后,我们发挥了一点创意——我们导出了数据,并将其加载到 Grafana 中进行地图可视化。
  5. Kafka 的默认保留策略是 7 天。这意味着超过 1 周的数据将被删除。对于一些主题,我们更改了此设置,但对于一些主题,我们忘记了这样做,因此我们丢失了数据。这影响了我们对罗马尼亚热门关键词的可视化。

结论和学习要点

  • 在大数据的世界中,在构建数据架构之前,你需要明确你试图回答的问题,然后按照计划行事,以确保你仍在按照这些问题进行工作。否则,你最终可能会得到一些不能满足你实际需要的东西。这听起来是一个相当笼统的说法,而且相当“显然是”。一旦我们看到了可视化,我们意识到我们没有根据我们最初的每个国家的关键字分布可视化来创建 Kafka 对象—例如,我们在 KEYWORDS_COUNTED 表中创建了每个国家的计数聚合。再加上忘记更改默认的 7 天 Kafka 保留期的错误,当我们意识到这个错误时,我们已经丢失了历史数据。主要学习点。
  • 数据应该在 ML/NLP 过程之前进行过滤 —我们应该删除一些没有确切意义的关键字,例如“的”、“打”。为了获得更相关的见解,可能需要几轮数据清理和提取关键词。
  • 在看到最终的可视化效果后,我们可能应该过滤掉一些显而易见的单词。例如,毫无疑问,Zoom 是得分最高的关键词,因为到 6 月份,每个人都只在 Zoom 上运行在线聚会。

T 他的研究小组是我们了解端到端解决方案的一个很好的途径,该解决方案使用 Kafka 摄取流媒体数据,Spark 处理流媒体数据,Zeppelin 进行可视化。我们向任何有兴趣与其他热情的人一起在一个休闲友好的环境中学习大数据技术的人推荐这一体验。

本文原载于 https://bigdata.ro/2020/08/09/spark-working-group/的

欧盟通用数据保护法规的二元模型分析

原文:https://towardsdatascience.com/a-bigram-analysis-of-the-eu-general-data-protection-regulation-33685e32bde7?source=collection_archive---------44-----------------------

用单词云可视化

图片由穆罕默德·哈桑拍摄,来自皮克斯拜

《通用数据保护条例》( GDPR)于 2018 年 5 月实施,是欧盟乃至全世界迄今为止最全面的数据保护法。在这篇面向初学者的教程中,我将使用 RWeka 把 GDPR 的语料库可视化成 R 语言的 bigram 单词云。

字云及其弱点

文字云是一个简单而强大的文本可视化工具。它允许您根据关键字在数据集中出现的频率,按比例打印不同大小的关键字。这是直观的和视觉上令人愉快的。但致命的是,它断章取义。

例如,在上面的表示中,很容易理解“权威”是我们数据集中的一个突出的词。但是,因为它已经被剥离了周围的词,我们不知道它是在“宣战权”中作为权利使用,还是在“地方权力”中作为政府机构使用,还是在“有约束力的权力”中作为引用来源使用。

二元模型和 GDPR

缓解这个问题的一个方法是制作一个两个单词的单词云。当然,即使是二元词——技术上称为双词复合词——也不能完全捕捉原始完整句子文本数据的细微差别和上下文。但幸运的是,GDPR 的许多核心概念通常由两个词组成:

  • 监督机构:监督 GDPR 在欧盟成员国的应用的公共机构
  • 一致性机制:确保 GDPR 在整个欧盟范围内统一适用的合作体系
  • 合法利益:处理个人数据的六个合法理由之一

因此,进行二元语法分析而不是默认的一元语法分析是可取的,这将在语义上撕裂那些只有在复合形式下才有意义的概念。

数据导入和语料库创建

让我们从安装和加载必要的包开始。

tm包是一个广泛使用的文本挖掘工具,用于提炼原始文本数据。同样,RWeka是一个简化复杂的预处理技术和其他机器学习算法的接口。在本教程中,我将专门使用它来将成对的单词组合成二元模型。然后我们将使用ggplot2绘制一个探索图,最后打印我们的单词云。

首先,加载文本数据并检查是否一切都完好无损。正文以该法案的官方长标题开始,以时任欧盟理事会主席的名字结束。

检查数据的前几行和后几行总是一个好习惯。

然后,我们使用VCorpus()函数创建一个语料库。一个语料库是一个抽象结构,当我们使用tm包时,它保存文档。在硬件层面上,VCorpus(易失性语料库)将文档存储在内存中,而PCorpus(永久性语料库)则利用单独的数据库。对于我们的目的来说,VCorpus已经足够了——只是要记住,在清除内存或关闭 RStudio 时,corpus 对象将会丢失。

我们现在已经从文本文件创建了一个语料库,并准备挖掘。

预处理

正如我们从上面的head()tail()函数的结果中看到的,在机器看来,原始文本数据充满了拼写不一致。有数字、标点符号和大写字母,文本似乎也是双倍行距。我们将把它和tm包统一起来,使它更容易使用。

tm_map()函数是简单文本细化的银弹。通过在第二个参数中提供不同的参数,如removeNumbersremovePunctuation,该函数从语料库中删除数字和标点符号。为了改变内容而不是简单地删除,例如从大写变成小写,我们使用content_transformer()

然后是停用词。停用词是由于它们在自然语言源中的语义可忽略性而应该被过滤掉的词。尽管它们缺乏实质意义,但它们经常在一篇文章中出现多次,并扭曲了频率分析的结果。例子包括冠词“the”和“a/an”以及介词“on”、“of”和“about”。"

tm包提供了一组不同语言的校对过的停用词。为了访问英语集,我们将参数设置为stopwords()中的"english"。因为这里只包含了最常见的例子,所以我添加了一组自定义的停用词。使用removeWords,选择的停用词将被删除。最后,通过stripWhitespace,我们去除了语料库中的空行和空格。

同一文本的第 21 行现在看起来“干净”了,可以让RWeka包捆绑成有意义的二元模型。

然而,在我们继续之前,我们还必须执行基本的引理运算,以防止将同一个单词的不同形式作为单独的单词进行计数。词条释义是将一个单词的词形变化合并成标准词典形式的过程。例如,它可以帮助我们的机器将“runs”、“ran”和“running”都视为“run”的规范实例。

有像 textstem 这样的 R 包来促进这个过程。请随意试验它们,但是请记住,一些 lemmatisation 函数可能弊大于利。例如,他们可能会将“通用数据保护条例”变成“通用数据保护条例”在我们的例子中,我们想要做的就是将某些二元模型的复数形式视为单数,因此不值得冒这种破坏性改造的风险。

为了用单数形式替换复数形式,我们提供了gsub函数作为content_transformer()的参数。pattern参数接收要替换的字符模式,而replacement参数定义如何改变该模式。

不幸的是,RWeka包并不评估二元模型的语义可行性,而是简单地返回它在语料库中可以识别的每个词对。检查最重要的结果并消除无意义的分组是非常重要的。

符号化

为了用[RWeka](https://cran.r-project.org/web/packages/RWeka/RWeka.pdf)生成二元模型,必须对语料库进行标记。记号化是将字符串分割成称为记号的更小单元的过程。令牌可以是一个单词、几个单词、一个句子或任何其他逻辑片段。在我们的二元模型分析中,一个 token 应该由两个单词组成,所以在NGramTokenizer()Weka_control()minmax参数中,分别输入2

然后,我们将数据塞进一个文档术语矩阵,这是一个数学矩阵,将术语的频率组织成行和列。接下来,按降序对矩阵进行排序,从最频繁到最少排列术语。前十名和后十名的结果如下:

我们已经成功地从语料库中提取出二元模型。

使用 ggplot2 进行探索性可视化

让我们用一个带ggplot2的条形图来简单地想象一下。

这是一个柱状图,显示了 15 个最常见的二元模型。我将 x 轴标为“二元模型”,y 轴标为“频率”,并沿着 x 轴调整了术语的位置和角度。

图表显示了前两个二元模型的压倒性出现。这意味着我们的词云将既不平衡也不漂亮,但在世界上最广泛的个人数据立法中有太多的“个人数据”调用可能并不令人惊讶。

词云

接下来让我们打印出 word cloud。首先,我们按原样打印所有内容,以检查数据的形状,然后,将最小频率设置为 2,以丢弃只出现一次的统计上无关紧要的二元模型。最后,我们可以应用一些格式,用深蓝色强调出现超过 20 次的主要二元模型,而用浅蓝色保留其余部分。

全部打印

最小尺寸 2

颜色编码

如果我们暂时将前两个数据点视为异常值,我们也可以得出如下表示:

众所周知,bigram 词云没有克服词云或频率分析的固有缺点。然而,它们可以为文本提供双重有趣的洞察力。

对我的软件工程角色的全新看法

原文:https://towardsdatascience.com/a-brand-new-perspective-on-my-software-engineering-role-907b58eb9a40?source=collection_archive---------42-----------------------

凤凰计划如何改变我看待工作的方式

夏嫣·胡伊津加Unsplash 上的照片

我最近读完了吉恩·金的《凤凰计划》。多么精彩的一本书。我不知道一本关于我工作中最不令人兴奋的部分的书会如此吸引人。总的来说,我对自己的软件工程师和 IT 职业有了全新的认识。

这本书对信息技术领域的每个人都是必不可少的,不管你的角色是什么。要在组织层级中的任何一级创造价值,理解高层管理人员为什么要做他们正在做的事情是很重要的。

这本书让你对 IT 运营有一个整体的了解。无论你是谁,它都会让你想到某个负责做出直接影响你日常生活的决定的人。

这篇文章是从一个人的角度写的,这个人在这个行业和一个大型组织中工作的时间相对较短。你可以称之为“新鲜的眼睛”。

学校里没教你这些。为什么?我不知道。但是你将在本书中找到的教训不仅会帮助你在 IT 世界生存,而且会让你茁壮成长。

Gene Kim 将带您踏上一段情感之旅,从与企业讨论功能,到将代码部署到生产环境,再到当一切不可避免地出错时随之而来的混乱。伴随着你一路上遇到的每一个不同的个性和自我所带来的血、汗和泪。

简要

首先,我给你简单介绍一下剧情,以防你不熟悉。

Bill Palmer 是一家大型汽车零部件公司的中级 IT 经理。他喜欢他的团队,他的责任感,他日常工作中的简单挑战,工作与生活的平衡。他很开心。

突然,他的老板和他老板的老板被解雇了,因为公司开始陷入困境。现在有一个主管的空缺。首席执行官找到他,说如果他不能胜任这个职位,不仅是 IT 部门,整个公司都将面临严重的危险。

前美国海军陆战队员比尔觉得拯救公司是他的责任,不情愿地接受了这份工作。

他不知道他将要步入什么,因为他现在被迫从头开始建立 IT 部门。

我学到的教训

以下是我从这本书中学到的一些经验。

4 种类型的工作

当比尔正在努力了解他的组织内部到底出了什么问题时,他被带到了一个看起来古怪的疯子的羽翼下,但最终却成为了理性的声音(由一个名叫埃里克的角色代表)。他解释说,比尔并不真正理解什么是工作。此外,比尔不知道有四种工作。这四个工种是什么?

业务项目:这是对公司有收益或战略意义的工作。就优先顺序而言,这是最重要的。目标是让客户满意或发展业务,这也是这些项目的目标。

内部项目(IT 运营工作):工作帮助更高效地交付业务项目,让你的团队更有生产力。换句话说,增加业务项目的吞吐量。

变更:变更,更具体地说,计划变更和实施变更,是稳定 IT 运营各个方面以及推动业务发展的必要组成部分。根据你所拥有的变更管理系统,这可以是平稳运行,也可以是绝对的噩梦,占用你最重要资源的宝贵时间。

计划外(消防):最危险的工种。这项工作阻止了其他三类工作的完成。当任何资源花费时间处理某个问题(环境中断、数据库故障、防火墙问题等)时。),这减少了他们处理公司首要任务的时间。这种情况太多,或者处理不当,都会对您的业务造成破坏。

我对“工作”的看法

想到这和我有什么关系,我意识到我做过的每一件“工作”都属于这四类中的一类。

认识到这一点,它让我明白了为什么我花了这么多时间在我所拥有的东西上。作为团队中相对较新的成员,我的大部分时间都花在处理计划外的工作变更上。

为什么?因此,我们的顶级资源(最有经验的开发人员、主题专家)可以将时间花在业务的首要任务上,即产生收入的项目上。当他们在做计划外的工作时,我们公司处于停滞状态。

这有助于解释为什么食物链是这样构成的。这是我成为顶尖高手的动力。这样我就可以花更少的时间在最后两种工作上(变更计划外工作),花更多的时间推动公司向前发展前两种工作(业务内部项目)。

一个人能拥有的力量

在任何技术堆栈和应用程序中,总会有一个人拥有大部分的知识和经验。这个人由一个名叫布伦特的人物来代表。当事情开始朝着错误的方向发展时,谁知道如何解决一切?布伦特。

这说明了文档、知识转移和培训团队其他成员的重要性。它还强调了正确管理这一资源的重要性。Brent 花在修复 IST2 中断(或任何任意的计划外工作)上的时间越多,花在开发 Phoenix 项目的主要功能(该公司的首要任务)上的时间就越少。如果对团队中的其他人进行适当的培训,他们可以解决停机问题,Brent 可以继续完成任务,为公司创造收入。

我对“布伦特”的看法

我每天都觉得需要布伦特。由于我在技术方面缺乏经验,我有很多问题要问布伦特。

布伦特对公司来说是宝贵的资源,但是如果每 30 秒就有一个开发人员问他一个问题,布伦特就无法完成自己的工作。这些问题他已经回答了一千次了。

我怎样才能最大限度地降低对布伦特原油的依赖程度?我可以从写下他告诉我的每一件事开始,然后把这些答案储存在一个容易找到的集中的地方。

团队其他成员可以访问的文档。这不仅有助于我将来的发展,也有助于团队中有一天会和我有同样问题的其他成员。

这是我现在的一点额外工作,以节省未来过多的工作。

在鸟瞰了占用 Brent 的时间会如何阻碍剩余的操作后,我觉得不主动与他沟通几乎是自私的。

持续改进的重要性

这是 IT 运营中的重要一课,但也是更重要的人生一课。在我们不断努力发展的过程中,下面这句话是我们永远不要忘记的:

重复创造习惯,而习惯是掌握的基础。无论你是在谈论体育训练,学习一种乐器,还是在特种部队训练,没有什么比练习和操练更重要的了。研究表明,每天练习五分钟比每周练习一次三个小时要好。”

如果我们想教或学某样东西或应用一种新的实践,就要不断改进。一致性是建造任何东西的关键。吉恩·金强调了这一点:

只要你在改进某件事,你改进什么并不重要。为什么?如果你没有进步,熵保证你实际上变得更差。

我很喜欢这一节,它讲述了随着时间的推移,我们如何实现变革和发展。这让我感到鼓舞,对未来充满希望。

结论

无论你的职位是什么,你将从凤凰计划中学到的经验对你作为一名 IT 专业人员的成长至关重要。

如果你想进一步讨论,请留下评论。这是一个我希望听到一些反馈的话题,更具体地说,这本书如何帮助你在职业生涯中达到你想要的位置。

深层图像修复的突破

原文:https://towardsdatascience.com/a-breakthrough-in-deep-image-inpainting-review-generative-image-inpainting-with-contextual-1099c195f3f0?source=collection_archive---------24-----------------------

基于上下文关注的生成式图像修复综述

欢迎回来伙计们!很高兴见到你们:)上一次,我们意识到复制粘贴是如何嵌入 CNN 进行深度图像修复的。你能领会主旨吗?如果是的话,很好!如果没有,不用担心!今天,我们将深入研究深层图像修复的突破,为此提出了上下文注意。通过使用上下文注意,我们可以有效地从遥远的空间位置借用信息来重建局部缺失的像素。这个想法实际上和复制粘贴差不多。让我们看看他们如何一起做到这一点!

回忆

我之前的帖子中,我已经介绍了移动连接层,其中来自已知区域的 特征作为缺失区域内生成特征的参考,以允许我们进一步细化生成的特征,从而获得更好的修复结果 。这里,我们假设所生成的特征是对基本事实的合理估计,并且根据来自已知区域的特征和缺失区域内所生成的特征之间的相似性来确定合适的参考。

动机

对于图像修复任务, 细胞神经网络的结构不能有效地模拟缺失区域和由遥远的空间位置 给出的信息之间的长期相关性。如果你熟悉 CNN,你应该知道核大小和扩张率控制卷积层的感受野,网络必须越来越深,才能看到整个输入图像。这意味着 如果我们想要捕捉图像的上下文,我们必须依赖更深的层,但我们会丢失空间信息,因为更深的层总是具有更小的空间尺寸特征 。因此,我们必须找到一种方法,在不深入网络的情况下,从遥远的空间位置借用信息(即理解图像的上下文)。

如果你记得什么是扩展卷积(我们在之前的文章中已经讨论过),你会知道扩展卷积是一种在早期卷积层增加感受野的方法,而不需要增加额外的参数。然而, 扩张卷积有其局限性。它跳过连续的空间位置,以便扩大感受野 。注意,跳过的连续空间位置对于填充缺失区域也是至关重要的。

介绍

这项工作分享了类似的网络架构,损失函数和相关技术,我们已经涵盖了前。对于架构, 提出的架构由两个发生器网络和两个鉴别器网络 组成。这两个生成器遵循具有扩展卷积的全卷积网络。一个生成器用于粗略重建,另一个用于精细重建。这被称为标准的由粗到细的网络结构。 两个鉴别器也同时全局和局部查看完成的图像 。全局鉴别器将整个图像作为输入,而局部鉴别器将填充区域作为输入。

对于损失函数,简单地说,他们也采用对抗损失(GAN 损失)和 L1 损失(为了像素重建精度)。对于 L1 损失,他们使用一个 空间折扣 L1 损失 ,其中为每个像素差异分配一个权重,该权重基于一个像素到其最近的已知像素的距离。对于 GAN 损失,他们使用一个 WGAN-GP 损失 而不是我们介绍的最标准的对抗性损失。他们声称,这种 WGAN 对抗损失也是基于 L1 距离度量的,因此网络更容易训练,并且训练过程更稳定。

在这篇文章中,我想重点介绍一下提出的。因此,我在上面简要介绍了由粗到细的网络架构、WGAN 对抗性损耗和加权 L1 损耗。感兴趣的读者可以参考我之前的帖子和本作的论文了解更多详情。

解决方案(简而言之)

提出了 上下文注意机制,有效地从遥远的空间位置借用上下文信息来重建缺失像素 。上下文关注被应用于第二细分网络。第一粗略重建网络负责丢失区域的粗略估计。和前面一样,全局和局部鉴别器被用来鼓励生成像素的更好的局部纹理细节。

贡献

图一。在自然场景、人脸和纹理图像上的修复结果的一些例子。图片来自于佳卉等人的论文 [1]

本文中最重要的思想是上下文注意,它允许我们利用来自遥远空间位置的信息来重建局部缺失像素。第二, WGAN 对抗损失加权 L1 损失的使用提高了训练的稳定性。此外,所提出的修复框架在各种数据集(如自然场景、人脸和纹理)上实现了高质量的修复结果,如上图 1 所示。

方法

图二。所提出的修复框架的网络结构。图片来自于佳卉等人的论文

图 2 显示了所提出的修复框架的网络架构。如上所述,它由两个发生器两个鉴别器组成。如果你读过我以前的帖子,你会发现这是典型的深层图像修复网络架构。

语境注意

这是这篇文章的重点。让我们看看所提出的上下文注意层是如何被设计来借用由遥远空间位置处的已知区域给出的特征信息来在缺失区域内生成特征的。

图 3。提议的上下文注意层的图示。图片来自于佳卉等人的论文【1】

图 3 以图形方式展示了所提议的上下文关注层。 运算可微且全卷积

图 4。上下文注意力层的更具体的例子。图片作者。

图 4 是提议的上下文注意层的更详细的例子。如图 3 所示,前景表示缺失区域内生成的特征,而背景表示从已知区域提取的特征。类似于复制粘贴的方法,我们首先要 将缺失区域内生成的特征与缺失区域外的特征 进行匹配。

以图 4 为例,缺失区域内生成的特征大小为 64×64×64,假设缺失区域外的特征分为 128 个大小为 64×3×3 的小特征块。请注意,本例中特征的通道大小为 64。然后,利用 128 个小特征块和缺失区域内生成的特征进行卷积,得到大小为 128×64×64 的特征图。在论文中,这种操作被描述为,

其中{ f _ xy }为前景补片(缺失区域内生成的特征补片),{b_x’y’}为背景补片(缺失区域外提取的特征补片)。 s _ xyx’y’是生成的以缺失区域为中心的面片( xy )与以已知区域为中心的已知面片(x’y’)之间的相似度。实际上,这是一个标准的余弦相似性度量过程。

当我们沿着通道维度观察时,128 个元素代表了所有已知补片和缺失区域内特定位置之间的相似性。这反映了 128 个已知斑块对该位置的贡献。然后,我们沿着通道维度对特征图执行 Softmax 归一化,如图 4 中蓝色区域所示。在 Softmax 归一化之后,沿着通道维度的每个位置的总和应该是 1。

与我在上一篇文章中提到的移位网相比,你可以看到,这次我们为每个已知特征块分配了一个权重,以表明它对于重建缺失区域内每个特征位置的重要性(软分配),而不是只保留与缺失区域内每个特征位置最相似的已知特征块(硬分配)。这也是为什么提出的语境注意是可微的原因。

最后,我们使用注意特征图作为输入特征,使用已知补丁作为核,通过反卷积来重建缺失区域内的生成特征。对于对实际实现感兴趣的读者,可以访问他们的 github 项目页面了解更多细节。

注意力传播

注意力传播可以被视为注意力特征图的微调。这里的关键思想是 相邻像素通常具有更接近的像素值 。这意味着他们考虑邻域的关注值来调整每个关注分数,

例如,如果我们考虑左右邻居的关注值,我们可以使用上面列出的等式来更新当前的关注值。注意 k 控制要考虑的邻居数量。

作者声称,这可以进一步改善修补结果,并且这也可以通过以单位矩阵作为核的卷积来完成。

关于注意机制的另一点是,使用了两种技术来控制提取的已知特征补丁的数量。 i) 提取步幅较大的已知特征面片,减少核的数量。 ii) 操作前对特征图大小进行下采样,得到关注图后再进行上采样。

网络注意力

图 5。在第二细化网络中嵌入上下文注意层的图示。图片来自于佳卉等人的论文 [1]

图 5 显示了作者如何将提出的上下文关注层整合到第二个细化网络中。你可以看到 又引入了一个分支来应用上下文关注,然后两个分支被连接起来以获得最终的修复结果 。注意力地图颜色编码用于可视化注意力地图。例如,中间的白色表示像素聚焦于自身,粉色在左下区域,绿色在右上区域,等等。你可以看到这个例子有一个粉红色填充的注意力地图。这意味着填充区域从左下区域借用了很多信息。

实验

作者首先与我们之前介绍过的之前的最新技术进行了比较。

图 6。提议的基线模型与 GLCIC 的比较[2]。从左至右,输入图像、GLCIC 结果和基线结果。图片来自于佳卉等人的论文

图 6 显示了所提出的基线模型和之前的最新技术 GLCIC [2]的修复结果。提议的基线模型如图 2 所示,没有提议的上下文注意分支。很明显,基线模型在局部纹理细节方面优于 GLCIC。请放大以便看得更清楚。

图 7。基线和完整模型修复结果的视觉比较。从左到右,地面实况、输入图像、基线结果、全模型结果、全模型注意力图。图片来自于佳卉等人的论文 [1]

图 7 显示了在 Places2 数据集上使用基线模型和完整模型(注意上下文)的定性结果。很明显,完整模型提供了更好的修复结果,具有精细的局部纹理细节。这反映了上下文注意层可以有效地从远处的空间位置借用信息来帮助重建丢失的像素。请放大以获得更好的视图,尤其是注意力地图。

表 1。Places2 数据集上不同方法的定量比较。表由于佳卉等人从他们的论文 [1]

表 1 列出了一些客观的评估指标供参考。如前所述,这些度量不能完全反映修补结果的质量,因为有许多可能的解决方案来填充缺失区域。你可以看到,建议的完整模型提供了最佳的 l 1、 l 2 损耗和 PSNR。对于电视损耗,PatchMatch 提供了更低的电视损耗,因为它直接复制原始图像补丁来填充孔洞。

作为参考,建议的全模型有 2.9M 参数。对于 512×512 大小的图像,在 GPU 上每张图像需要 0.2 秒,在 CPU 上每张图像需要 1.5 秒。

消融研究

注意机制不是一个新的想法,在文献中有几个注意模块。作者做了使用不同注意力模块的实验。

图 8。使用不同注意模块的修复结果。从左到右:输入、使用空间变换网络的结果、使用外观流的结果、以及使用提议的上下文注意的结果。图片来自于佳卉等人的论文

作者对比了文献中两个著名的注意模块,即空间变换网络[3]和表象流[4]。简单来说,对于外观流,使用卷积层来代替上下文注意层,以直接预测 2D 像素偏移作为注意。这意味着我们添加了一个卷积层来预测已知像素向缺失像素的偏移。在图 8 中,您可以看到使用外观流(中间)的结果为不同的测试图像提供了相似的注意力图。这意味着注意力地图对于给予我们想要的“注意力”没有用。您还可以观察到,空间转换器网络(左)无法为图像修复任务提供有意义的注意力图。一个可能的原因是空间变换网络预测全局仿射变换的参数,这不足以帮助填充也需要局部信息的缺失区域。在这里,我没有深入探讨不同的注意力模块。感兴趣的读者可以参考报纸了解更多的细节。

选择 GAN 损失进行图像修复。作者实验了不同的 GAN 损失,例如 WGAN 损失、典型对抗损失和最小平方 GAN。他们凭经验发现,WGAN 损失提供了最好的修复结果。

基本重建损失。作者在没有 L1 损失的情况下训练精化网络。他们发现,L1 损失是必要的,以确保像素重建精度,即使 L1 损失使修补结果模糊。因此,L1 损失对于确保完整图像的更好的内容结构是至关重要的。

感性丧失、风格丧失、电视丧失。我们将很快涵盖感知损失和风格损失。这里一个简单的结论是,这三个损失并没有给修复结果带来明显的改善。因此,他们的模型仅使用加权 L1 损耗和 WGAN 损耗来训练。

结论

显然,本文的核心思想是语境注意机制。上下文关注层嵌入在第二细化网络中。注意,第一粗略重建网络的作用是对缺失区域进行粗略估计。这种估计用于上下文注意层。通过匹配缺失区域内的生成特征和缺失区域外的特征,我们可以知道缺失区域外的所有特征对缺失区域内每个位置的贡献。注意,上下文注意层是可微分的和完全卷积的。利用提出的上下文注意,他们实现了最先进的修复结果。

外卖食品

你可能会发现,我们正在越来越深入到深层图像修复领域。在我之前的文章中,转移连接层被介绍,它以硬分配的形式将复制粘贴的概念嵌入到 CNN 中。本文以软分配的形式制定了上下文注意层,使得该层是可微分的,并且可以在不修改梯度计算的情况下端到端地学习。

希望你能掌握本文提出的情境注意层的关键思想,尤其是它的提法如图 3 和图 4 所示。对于想了解更多网络架构和损失函数的读者,请参考论文

下一步是什么?

在以后的文章中,我们将会研究更多的特定任务修复技术。希望我们能一起学习和享受!

参考

[1],林哲,,沈晓辉,路欣,,Proc .计算机视觉与模式识别* ( CVPR ),2018。*

[2]饭冢聪,埃德加·西莫-塞拉,石川宽,“全局和局部一致的图像完成ACM Trans .论图形,第 36 卷,№4,第 107 条,出版日期:2017 年 7 月。

[3] M. Jaderberg,K. Simonyan,A. Zisserman 等人,“空间变换网络”,载于《神经信息处理系统进展》,2017–2025 页,2015 年。

[4] T. Zhou,S. Tulsiani,W. Sun,J. Malik 和 A. A. Efros,"通过外观流的视图合成," Proc .2016 年欧洲计算机视觉会议 ( ECCV )。

再次感谢你阅读我的帖子!如果您有任何问题,请随时给我发电子邮件或在这里留言。

事实上,我尽量缩短文章的长度,只关注文章的一个关键观点。我认为读者已经从我以前的帖子中了解了深层图像修复的基本知识。顺便说一下,我必须不断提高我的写作技巧,以更有效地表达我对论文的理解。欢迎任何建议。系统学习对我们来说极其重要。非常感谢,下次再见!😃

使用 Python 和 R 进行数据插补的简要指南

原文:https://towardsdatascience.com/a-brief-guide-to-data-imputation-with-python-and-r-5dc551a95027?source=collection_archive---------33-----------------------

数据科学提示

让数据变得干净

胡安·戈麦斯Unsplash 上拍照

我们都知道,数据清理是数据分析过程中最耗时的阶段之一。我们需要获取缺失值检查它们的分布,找出模式,并决定如何填充空间。此时,您应该意识到,缺失数据模式的识别和正确的插补过程将影响进一步的分析。所以,让我介绍一些常见分析语言的技巧:R 和 Python。

为什么数据丢失了?

在开始插补过程之前,我们应该首先获取数据,并找到缺失数据的模式或方案。简单地说,有两种类型的缺失数据:MCAR 和 MNAR。

MNAR(非随机缺失)是数据最严重的问题。这意味着,我们需要找到缺失功能之间的依赖关系,并开始数据收集过程。它提供了某种分析步骤,包括使用不同的数据源、分析连接和搜索替代数据。

MCAR(完全随机缺失)意味着缺失值中没有深层模式,因此我们可以利用这一点来决定是否可以移除或估算一些行/要素。这是我们可以处理的事情,但只能在经验范围内,因为可能有太多的缺失数据(占总记录的百分比)。

因此,为了便于说明,我们将使用下一个玩具示例:

我们可以看到对多个缺失值、数值和分类缺失值的影响。

R 的力量

R 编程语言有一个很棒的社区,给 R 开发仓库增加了很多包和库。所以,这并不奇怪,我们有了鼠标包。它包括许多与链式方程多元插补相关的功能(即 MICE 算法)。您可以深入文档了解细节,但我将给出基本示例。

首先,让我们看看上面提到的玩具示例中缺失数据的模式:

library(mice)
md.pattern(df_test)

Mice 包内置工具md.pattern(),显示缺失值的分布和缺失特征的组合。你可以在我之前的关于用 R 熟悉缺失数据的文章中读到更多关于这个工具的内容。这个函数也给了我们一个很好的例子:

使用 mice-imputor 的工作分为两个阶段。在第一阶段,我们准备估算器,在第二阶段,我们应用它。

插补准备包括预测方法的选择以及在计算中包括/排除列。我们只需要通过$method属性重写必要列的默认插补方法。在我们的例子中,我们对第一列和第三列使用了mean(无条件均值),对第五列使用了pmm(预测均值匹配),对第四列使用了 norm(基于其他特征的贝叶斯线性回归预测),对条件变量使用了logreg(对 2 值变量的逻辑回归预测)。关于mice()方法和命令methods(your_mice_instance),请参见文档中的更多。我们还从算法中排除了第二列。

现在我们已经为第二阶段做好了准备:重用当前的 mice 实例作为实际估算器的输入值:

imputation <- mice(df_test, method=init$method, 
                            predictorMatrix=init$predictorMatrix, 
                            maxit=10,
                            m = 5,
                            seed=123)

MICE 软件包的一个主要特性是生成几个插补集,我们可以在进一步的 ML 模型中使用它们作为测试示例。因此,我们将能够选择最合适的设置。在我们的例子中,我们有m=5,所以算法生成 5 个估算数据集。你可以在这个包的作者的文章中阅读更多关于生成的数据集的工作和它们在你的 ML 管道中的使用。

最后一步是用估算数据集的具体数字运行算法:

imputed <- complete(imputation, 2)

您可以在 mice 实例的$imp属性中看到所有生成的集合。不过,我选择了第二个生成集:

Pythonic 式的

在其他编程语言中,Python 拥有来自社区的最强支持。数据科学包有特别棒的代码库。你可能会在著名的 [scikit-learn](https://scikit-learn.org/stable/modules/impute.html) 里找到几种插补算法

这个软件包也支持多变量插补,但正如文档所述,它仍处于实验阶段。那么,我们来看一个不那么复杂的算法:SimpleImputer。尽管如此,sklearn软件包的估算组件有更酷的特性,比如通过 K-nearest 算法进行估算,所以你可以在文档中自由地探索它。

我们将使用相同的玩具示例。当然,一个简单的插补算法并不那么灵活,给我们的预测能力也比较低,但它仍然可以处理这项任务。我将跳过缺失数据检查这一部分,因为它与前面的示例相同。不过,你可以在我的文章中找到一些关于 Python 中丢失数据的好习惯用法。

from sklearn.impute import **SimpleImputer**
impNumeric = **SimpleImputer**(missing_values=np.nan, strategy='mean')
impCategorical = **SimpleImputer**(missing_values=np.nan, 
                               strategy='most_frequent')

我们为每个数字列选择了mean策略,为分类列选择了most_frequent策略。你可以在SingleImputer的文档页面上阅读更多关于应用策略的信息。您可能还注意到,SingeImputer允许设置我们视为缺失的值。进一步的过程比 R 中的要短得多:input 类和其他sklearn组件有相同的拟合转换过程。因此,我们再次为每一列设置插补策略(第二列除外):

这是我们估算的数据集:

您可以自由地试验、比较和选择 R 和 Python 实现中最好的一个。

数据清理只是分析过程的开始,但是这个阶段的错误可能会对后续步骤造成灾难性的影响。清理数据,查看我的 Github 上的文章中的工作代码:

[## 中级/中等 _jupyter_notes

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/Midvel/medium_jupyter_notes/tree/master/data-imputation)

另外,请确保您没有错过我的其他数据清理文章:

[## 每个数据科学家都应该知道的获取缺失值的 7 个习惯用法

你应该把命令自动化

towardsdatascience.com](/7-idioms-to-acquire-missing-values-every-data-scientist-should-know-2edf4224360c) [## 用 R: 10 日常习惯用法处理缺失数据

你应该把命令自动化

towardsdatascience.com](/handle-missing-data-with-r-10-daily-used-idioms-13d849d01690)

法律技术中的数据科学简史

原文:https://towardsdatascience.com/a-brief-history-of-data-science-in-legal-tech-dc91daadffb2?source=collection_archive---------48-----------------------

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

法律技术中的数据科学

论法律技术的过去、现在和未来

想象一个律师!许多人脑海中浮现的第一个画面是穿着西装的人,在一大堆印刷的判例法中辛勤工作。虽然西装仍然是标准,但这张照片的其余部分已经变得有些多余。在很大程度上,法律行业的特点是在创新方面相当保守和迟钝。尽管如此,即使是数字革命也严重改变了这一景观。

支持法律专业人员日常工作或完全自动化流程的软件和数字服务被称为法律技术。关于这一领域的学术文献非常稀少,因为在很长一段时间内,法律专业人员使用的技术解决方案非常保守,持有上述适应缓慢的刻板印象。随着法律技术的创新势头越来越快,这种情况肯定会发生变化——但稍后会有更多内容——让我们先看看这一切是从哪里开始的。

第一次浪潮——有时被称为法律技术 1.0——自 20 世纪 80 年代初以来席卷了法律领域,起初很慢,但随着技术的进步,变得越来越普遍。这一浪潮最突出的方面是数字化,出现了像 Westlaw 这样的法律数据库。这些数据库最初是通过安装在法律办公室的大型终端提供的,取代了大量的印刷判例法,现在只需按一下按钮,就可以通过在线门户网站如 EUR-Lex making EU law、判例法等在线获得。尽管这对律师如何访问工作所需的数据来说是革命性的,但这还没有将数据科学引入法律行业。

《福布斯》的马克·科恩甚至将法律部门描述为“数字时代的数据荒原”。除了其通常保守的特征之外,还有一个简单的原因;迄今为止,创新的动力是缺乏的。法律是非常劳动密集型的,但是(通常是巨大的)劳动成本可以转嫁给客户——没有必要通过技术来降低它们。但这种情况正在开始改变——legal tech 2.0 正在获得动力——数据科学处于法律和法律领域变革的最前沿。

LegalTech 2.0 不仅仅是帮助律师事务所的日常工作,而是自动化律师事务所的各种流程。这种情况普遍存在;内部运营,如智能法律计费(如 Apperio)或知识管理(如 Intel lex);以及面向客户的流程。一个突出的例子是 flight right——它使消费者能够完全在线为取消的航班索赔。

但是,是什么能够突破法律的技术昏睡呢?这里有两个因素在起作用。首先,律师事务所开始意识到,数据对于简化内部运营至关重要——使他们能够降低无法转嫁给客户的成本,评估和减轻风险,以及衡量、解释和利用绩效数据。但或许更重要的是,外部压力正迫使他们接受并努力创新。客户的压力可能是最引人注目的因素。但许多其他因素,从不断变化的人口结构到立法带来的竞争压力——如英国 2007 年的《法律服务法》(在法律行业启用替代业务结构(ABS)),也有所贡献。

对于 LegalTech,我们应该满怀期待地向前看,既要看到 2.0 解决方案的扩展,也要看到 LegalTech 3.0 有望实现法律流程的完全自动化。极大地扰乱了法律环境!抛开邀请数据科学解决方案的内部流程,而不是专注于面向客户端的服务,数据科学可以找到广泛的实现。

机器学习本身可以实现比它在法律数据库评估和发现方面的表面应用更多的功能,这在过去是非常劳动密集型的。过去,病例评估和预测是一项基于经验的长期技能,现在可以全面普及。通过将案件数据输入机器学习算法,可以帮助预测潜在或当前案件的结果。预测分析对所有法律专业人士都很有价值。数据科学可以用来更有效地洞察对手,根据特定法官过去的裁决对案件进行微调等等。

进一步探索 LegalTech 3.0,当从现状中观察时,它甚至可以获得一种有点超凡脱俗的特性。如果应用程序开始自动化整个法律过程,受过训练的法律专业人员将开始失去他们在执业法律上的垄断地位。区块链系统可以取代房地产中的公证员。在普通案件中,网上争议解决可以取代法官。基于人工智能的聊天机器人可以取代律师提供法律建议。显然,在未来几年,随着技术的进步,法律和数据科学将变得越来越复杂,此后法律领域将发生巨大变化。

这篇文章最初发表在 UCL 数据科学协会的数据博客上,现在仍然可以在那里找到,此外还有许多讨论数据科学最新发展的深刻文章。

[## 帖子| UCLDSS

数据科学可能是人类最有用的发明之一。我们研究和建立共享 DS 系统和博客…

www.ucldss.co.uk](https://www.ucldss.co.uk/blog/)

熵的简史:第一章

原文:https://towardsdatascience.com/a-brief-history-of-entropy-chapter-1-9a2f1bc0d6de?source=collection_archive---------21-----------------------

虽然熵的概念是在从热力学角度研究系统的过程中引入的,但这一概念在多个不相关的领域激发了新的创新,其中最突出的是人工智能的计算机算法设计和通信系统的设计。加入我的这一系列文章,我将带你和我们的朋友熵一起踏上旅程,他将从热力学走向深度学习中使用的分类算法。

第一章:热力学

19 世纪初,法国工程师萨迪·卡诺正在研究热机所做的功。经过一些详细的分析,他得出结论,任何热机,不仅需要一个热的身体,而且还需要一个温度较低的第二个身体来运行。在一个思想实验中,他设计了一种热机,它以最大可能的效率工作(每单位能量你从发动机得到的功),任何发动机都可以以这种效率工作,这就是著名的卡诺热机。卡诺热机的细节可以在任何一本热力学标准书中找到。但我们最关心的是,在分析他的发动机时,卡诺意识到下面的等式成立:

等式 1

热机。图片提供:维基百科,【https://en.wikipedia.org/wiki/Carnot_cycle

卡诺循环。图片提供:维基百科,https://en.wikipedia.org/wiki/Carnot_cycle

也就是说,从热储器获取的热量与热储器的温度之比等于排出到冷储器的热量与冷储器的温度之比。他的发动机的另一个重要特性是发动机以可逆过程运行。这一性质来自于过程中没有耗散力的假设和卡诺循环的巧妙设计,由于卡诺循环,没有必要将循环的任何部分近似为准静态过程(总是平衡的过程)。因此,这种理论上的发动机没有任何能量损失的余地,这使得它很容易逆转……但它永远不可能达到完美的效率。

卡诺对可逆发动机的分析随后也得出结论,只有可逆发动机才能具有最大效率。但是,他的分析只适用于可逆过程,这在自然界中很少发现。因此,等式 1 对大多数现实生活中的过程都不成立,因为自然界中的大多数过程不会自行逆转。物体总是下落,永远不会自己上升……热量总是从热的物体流向冷的物体,而不是从冷的物体流向热的物体……自然界有很多这样的例子。在不可逆过程中,为什么自然总是喜欢它而不是可逆过程?

当我们无法解释一个过程时,我们该怎么办?我们让它成为一个构成法,一个把观察描绘成一个规则,并且说这个规则不能被违反的法律。这是热力学第二定律,至少当它由开尔文-普朗克和克劳修斯(独立地)阐明时是这样。总的来说,该定律表明,如果没有外力确保热量从冷的物体流向热的物体,热量就不能从冷的物体流向热的物体。这是自然界中一个明显的现象,没有人知道为什么会这样。这里我想强调外部代理的作用。因此,除非有外力介入这个过程,否则热量无法从冷的物体流向热的物体……这表明,前面提到的所有观察结果都只发生在系统没有被篡改的时候,或者用正式的术语来说,是一个封闭的系统。

解释我刚才的陈述的一种方式是假设外部因素以工作的形式影响系统。这给了我们克劳修斯对第二定律的陈述。但是,嘘嘘,在我们继续讨论之前,让我们看看熵作为一个概念是如何在这样的背景下诞生的…

熵的诞生

热力学(至少在当时)是对系统状态变量的研究。卡诺方程(1)使克劳修斯在能量守恒定律和前者之间画出了平行线,并且他假设,也许,这个量 Q/T 在可逆过程中是守恒的。他将这个量称为熵(通常用 S 表示),并声称这也是一个状态变量。酷!所以,熵在可逆过程中是守恒的。但是不可逆的呢?

让我们考虑一个不可逆的过程,即热量从热的物体传导到冷的物体。热物体熵的变化将为=(它损失的热量/热物体的温度),而冷物体获得的熵=(它获得的热量/冷物体的温度)。记住热物体失去的热量和冷物体得到的热量是一样的,由这两个物体组成的系统的熵的总变化将是:

等式 2

因此,在这个不可逆过程中,熵增加了。请原谅,但在这里我必须扩展我的主张,即任何不可逆过程的熵都会增加。

好,我们定义可逆过程的熵为 Q/T,对于可逆过程,熵是守恒的。但是很明显,对于不可逆过程,熵是不守恒的。

根据所述的第二定律,我们的分析可以得出以下两个结论:

  • 封闭系统的熵总是随时间而增加。一个封闭的系统只能有不可逆的过程发生,因为它不能有任何外部影响。
  • 关于开放系统的熵,没有什么可说的。

到目前为止,我们只是列出了一些观察结果,作为我们不会违反的规则。那么我们能证明为什么这样的观察存在吗?这个问题的答案在于物质的运动论和气体的统计分析。

熵的概率解释

到目前为止,没有人知道这个新提出的状态变量——熵——的本质,它是什么?我们能不能把它和现实生活中可以观察到的一些属性联系起来?在我们正式在概率和熵之间画出一些相似之处之前,让我们先对其建立一个直观的感觉。

假设一个容积为 V2 的容器里装着一种气体,现在它的体积是 V1。有一个分区阻止它,当删除该分区时,它会扩展到卷 V2。我们通过给它一些热量 Q 来确保这个过程是等温的,因为气体在膨胀过程中会趋于冷却。因此,与此过程相关的熵变为:

等式 3

其中 N 是参与膨胀的气体分子数,k 是玻尔兹曼常数。

用这个例子,我们可以基于概率解释熵的增加。在膨胀之前(就在隔板被抬起之后),气体分子存在于 V1 体积中的概率是 V1/V2。在一个 V1 体积中出现两个分子的概率是(V1/V2)。因此,体积为 V1 的气体中存在 n 个气体分子的概率为(V1/V2)^N.)。膨胀后,气体分子占据体积为 V2 的气体分子的概率为 1。如果我们将 N 个气体分子存在于体积 V1 中的概率表示为 w1,将 N 个分子存在于体积 V2 中的概率表示为 w2,则它们的比率为:

等式 4

比较等式 3 和 4,

等式 5

玻尔兹曼公式

1872 年,路德维希·玻尔兹曼发表了一个公式,其中他将系统在某一状态下的熵表示为与该状态概率的对数成比例。比例常数后来被称为玻尔兹曼常数。

等式 6

我们可以很快验证,等式 5 可以从等式 6 推导出来。

熵的这一新定义使熵的可加性显而易见。假设一个系统由处于状态 1(概率为 w1)和状态 2(概率为 w2)的两个子系统组成。整个系统处于这种状态的概率是 w1*w2。因此,这个系统的熵将是

等式 7

因此,系统的熵是其子系统熵的总和。

熵作为无序度的量度

给定一个处于某种状态的系统,玻尔兹曼公式将其熵与该系统处于当前状态的可能性联系起来。概率越高,熵越高。所以一个问题自然出现……比其他状态更有可能出现的状态是什么?

在我们进入上述问题之前,我们必须问自己一个更基本的问题。作为一个人,我所感知的系统状态是什么?这两种状态的区别是什么?让我们用一个例子来说明这一点:

假设我们有三个球,可以是以下两种颜色中的任何一种:红色或蓝色。因此,这种 3 球系统可以有以下 8 种配置:

作者图片

这 8 个状态中的每一个都不能进一步分解成状态。给这些基本状态的一个通俗术语是“微观状态”。现在的问题是,对你来说,什么构成了一种状态?你可以说,所有这些微观状态,至少有两个蓝色的球,是一种状态,其余的是另一种状态。是的,这是一个国家的有效定义。同时,另一个人可以说,对他来说,所有那些至少有一个蓝球的微观状态是一种状态,其余的是另一种状态。你看到了吗,一个人所感知的状态取决于他的目的和决定。顺便说一下,这些“虚构”的状态必须是微观状态的组合,通常被称为“宏观状态”。

尽管有绝对的自由来选择由自己喜欢的微观状态组成的状态,但我们作为人类(至少是我们大多数人)有敏锐的眼睛来观察这些微观状态中的模式,并为这些状态指定一个特殊的类别,称为“秩序”。例如,我认为所有红色和蓝色的球(S1 和 S8)都是“秩序”,因为观察这些状态对我来说是一种奇怪的满足,我相信我的许多人类同胞会很高兴地同意我的观点。但是最常发生的是我们人类认为的有序的子集,与我们认为的“无序”相比是非常小的。因此,在这种状态的二元分类中,系统更可能处于“无序”状态,而不是“有序”状态。

概率越高,熵越大,因此无序越大。

重温第二定律

当熵被引入解释第二定律时,我们得出结论,对于一个封闭的系统,熵随时间而增加。这是第二定律的另一种说法。但是熵的概率性质告诉我们第二定律在多大程度上是正确的。热力学第二定律是概率性的,而不是像牛顿定律那样是确定性的。这是一个必然要遵循的规律,只有我们给这个系统足够的时间去遵循它。如果从长远来看,系统增加了它的熵,那么它在短时间内减少它的熵是允许的(对于那些读过丹·布朗的《起源》的人来说,这句话有很多共鸣:)。长跑有多长?我们不能说……对气体分子来说可以短到几纳秒,对某些其他系统来说可以是几年,但我们可以肯定的是,给定 lot 时间,熵会增加(这就是数学家所说的概率收敛)。

麦克斯韦妖

1867 年,詹姆斯·克拉克·麦克斯韦(没错,就是提出四个电磁方程的那个人)提出了一个思想实验,这个实验提出了违反热力学第二定律的一种可能方式。他的实验如下:

麦克斯韦的恶魔。图片提供:维基百科,【https://en.wikipedia.org/wiki/Maxwell's_demon

考虑一个装有一定温度气体的容器。容器在中间被隔开,壁上只有一个门,在任何给定的时间只有一个气体分子可以通过。现在麦克斯韦提出让一个有智慧的生物(恶魔)站在门的旁边,在所有从左边部分接近门的分子中,只允许那些比某个阈值速度快的分子移动到右边部分,同时在所有从右边部分接近门的分子中,只允许那些比某个阈值速度慢的分子移动到左边部分。

现在你需要明白这样一个存在的后果。但在此之前,有没有可能这样的存在是有能力存在的?是的,很明显;我们这些做决定的人就是这类人的一个很好的例子。让我们看看恶魔在我们的容器里做了什么。恶魔充当了过滤器的角色,将速度较快的分子与速度较慢的分子分离开来。所以,本质上,它创造了秩序。同样在分离过程中,较快的分子聚集在容器的一侧,而较慢的分子聚集在另一侧。右边分子的平均动量高于左边分子的平均动量,直接暗示右边的温度高于左边的温度。那么这个恶魔完成了什么?

  • 它创造了秩序,因此减少了熵
  • 它产生了一个温度梯度,从而能够从系统中提取功

但是恶魔完成这一壮举的代价是什么?

这个问题是麦克斯韦思想实验的症结所在。我们很容易认为恶魔不是系统的一部分,并认为容器是一个开放的系统,因此外部干扰是允许的,因此如果熵减少就完全没问题。但是如果我们强迫自己认为恶魔是我们系统的一部分,这个论点就失败了,这是完全正当的,因为我们可以完全自由地选择构成我们系统的东西。

另一个容易受骗的论点来自第二定律的概率性质,即它允许熵减少,至少在短时间内。但人们可以很容易地得出结论,这个系统中的熵永远不会增加,因为恶魔一直在努力分离分子,并将永远继续这样做。

如果由容器和恶魔组成的系统是开放的,那么漏洞在哪里?这个系统是如何获得能量在自身内部创造秩序的?但是如果这个系统是封闭的…如果我们把热力学第二定律视为神圣不可侵犯…这里到底发生了什么?这里有一个相关的问题:

你不认为恶魔需要某种方法来获取关于分子速度的信息吗?难道这种方法会消耗能量,从而在这个“封闭系统”中产生泄漏吗?

这是 Leó Szilárd 在 1929 年提出的论点。他提出,恶魔需要某种手段来测量分子速度,这种获取信息的方法耗费能量。恶魔在消耗能量时,只能增加自己的熵,因为容器中气体的熵明显在减少。Szilard 认为恶魔的熵增加应该比容器中分离过程引起的熵减少更多。相当合理的解释!除了问题…增加妖的熵是什么意思?恶魔的哪一部分变得比以前更混乱了?在实验过程中,当我观察到电流表的读数后,我变得更加混乱,这意味着什么?

一个问题引出了其他几个问题。那么我来结束一下趋势……观察数据是什么意思?

在第 2 章中找出如何驱除麦克斯韦妖!

AutoML 简介

原文:https://towardsdatascience.com/a-brief-introduction-to-automl-4854c76877b6?source=collection_archive---------33-----------------------

我的读者选择 AutoML 作为在短时间内对他们的工作/行业影响最大的趋势。它是什么,你为什么要关心?

【机器学习&人工智能mikemacmarketing 授权于 CC BY 2.0

在我的暑假期间,我偶然看到了一份名为“2020 年人工智能趋势观察”的 CBInsights 报告。我很好奇我的同事和读者会怎么看待所选的趋势,所以我发起了一个调查,看看他们是怎么想的。我简单问了一个问题:“根据你的个人经历,哪一个对你的工作/行业影响最大?”这些是结果:

调查结果显示,AutoML 是迄今为止影响最大的趋势

调查结果很清楚:到目前为止,AutoML 是我的听众认为对他们的工作/行业影响最大的趋势。在这篇文章中,我将尝试向你介绍 AutoML 的概念,以及它在短期内对人工智能意味着什么。

什么是 AutoML?

AutoML 可以定义为一组工具,可以自动化用机器学习解决问题的过程。这样的过程包括几个需要该领域特定专业知识的步骤,例如数据预处理、特征工程、提取和选择。不仅如此,机器学习专家还必须选择正确的算法,并在超参数中执行优化任务,以最大限度地提高其准确性。

当与用于大规模开发和部署机器学习模型的 MLOps 方法和框架相结合时,AutoML 可以成为商业组织民主化 AI 的有趣工具。

一个典型的机器学习过程,其中 AutoML 可以帮助自动化步骤

为什么 AutoML 对一个愿意采用 AI 的公司有意思?

对于一个愿意加速采用的组织来说,AutoML 可以是常规机器学习项目的一个非常好的补充。我们可以确定其目标和挑战,并将它们分为四类,目的是为人工智能计划实现持续的价值生成:

AutoML 有利于人工智能的采用和大规模民主化的四个领域

对于其中的每一个领域,AutoML 都可以帮助实现与 AI 民主化和可扩展采用相关的目标。尽管如此,它也给组织带来了一些挑战,如下所列:

AutoML 的战略、组织、运营和创新目标及挑战

AutoML 解决方案的现状如何?*

首先,值得注意的是,您可以找到不同种类的工具,这些工具可以归类为 AutoML。对它们进行分类的一种方法是,将专注于机器学习过程自动化的特定部分的那些和试图覆盖端到端的那些分开。对于后者,Forrester 在 2019 年发布了其Forrester New Wave:Automation-Focused Machine Learning solutions,其中得出结论,H20.ai 和 DataRobot 是最受欢迎的 AutoML 解决方案,正如 Forrester 提到的,它们是最成熟的解决方案之一。

虽然 Forrester 报告中没有提到,但我也将 Dataiku 列为顶级商业解决方案之一。

数据机器人

DataRobot 可能是 AutoML 最知名的商业解决方案,而是人工智能领域的独角兽之一,估值超过 10 亿美元。在这篇博客文章中,他们总结了你应该在 AutoML 解决方案中寻找的 10 个顶级特性(当然也是 DataRobot 提供的),包括:

  • 数据预处理
  • 特征工程
  • 多样的算法
  • 算法选择
  • 培训和调整
  • 组装
  • 面对面的模特比赛
  • 人性化的见解
  • 易于部署
  • 模型监控和管理

DataRobot 的产品由四个独立的产品(自动机器学习、自动时间序列、MLOps 和 Paxata)组成,您可以通过多种方式使用这些产品,从托管云到私有云或混合云。你可以在这里找到的详细内容

H2O.ai

H20.ai 将 it 平台定义为“人工智能和机器学习领域的开源领导者,其使命是为每个人实现人工智能的民主化”。该公司提供了一个 AutoML 包作为其开源平台的一部分,根据其网站,该包包括以下功能:

  • 数据预处理,包括插补,一键编码,标准化。分类特征的特征选择和/或提取以及计数/标记/目标编码。
  • 模型生成,包括笛卡尔或随机网格搜索和贝叶斯超参数优化。
  • 合奏。

H2O.ai 还出售名为无人驾驶 AI 的企业版,他们在其网站上用架构图很好地概括了这一点。

大台库

正如该公司在最近的一篇博客文章中提到的,他们不仅长期专注于功能工程 AutoML 功能,还提供了一个可视化工具,可以训练模型选择最佳模型、功能等。只需点击一个按钮(如果用户愿意,仍然可以手动完成训练过程的不同步骤)。

Dataiku 提供四种产品包装,从免费到企业。你可以在这里找到不同版本如何比较

除了这些特定的 AutoML 解决方案,超大规模计算开始将自动机器学习功能纳入其开发工具。以下是 AWS、Google Cloud 或微软等人工智能公司开始引入 AutoML 功能的非详尽列表。

超大规模人工智能开发工具中由 AutoML 驱动的功能的非详尽列表

你已经在使用 AutoML 功能来扩展和民主化人工智能了吗?如果是这样,我很乐意在评论区听到你的经历。

请注意,本文中提供的信息是在编写时通过提到的不同公司的公开网站收集的,因此在阅读时可能不准确。

如果你喜欢阅读这篇文章,请 考虑成为会员 以便在支持我和媒体上的其他作者的同时,获得每个故事的全部信息。

无服务器计算简介

原文:https://towardsdatascience.com/a-brief-introduction-to-serverless-computing-e867eb71b54b?source=collection_archive---------43-----------------------

入门

泰勒·维克在 Upsplash 上拍摄的照片

变得抽象

在过去的一二十年里,云计算已经主导了开发“现代”软件所需的许多技能和过程。对于相邻的领域也是如此,包括数据科学领域(以及其他领域)。这种全面转向“云”的趋势之一是,关于开发团队如何与运行他们的应用程序的基础设施进行交互的抽象水平不断提高。

可以说,在这个抽象金字塔的顶端是无服务器计算的概念,它建立在这样的想法上(顾名思义),开发人员不需要花时间配置服务器和编写样板应用程序代码,而是应该直接编写和部署“真正”推动商业价值的代码。这还可以让开发人员、数据科学家和其他人非常容易地部署简单的应用程序和服务,而几乎没有或根本没有配置部署“经典”web 应用程序所需的基础架构的经验。如果这听起来对你有用,那太好了!这篇文章旨在为你提供:

  • 对无服务器计算的高度理解。
  • 了解无服务器计算的相对优点及其一些缺点。
  • 在 Google Cloud 上设置自己的无服务器 Python 函数的简短指南。

让我们开始吧。

经典方法

要了解无服务器计算的潜在优势,不妨后退一步,看看在云中为最新、最棒的应用程序设置新服务器的“经典”工作流程。如果你以前做过这个(也许是用烧瓶Express 应用程序),这可能看起来很熟悉:

  1. 在您选择的云提供商上创建一个新的虚拟机:选择您的系统资源(内存、CPU 数量等。),选择您想要使用的操作系统,或许还可以创建一些凭证来远程访问您的新机器。
  2. 将您的新机器配置为接受特定端口上的公共流量。
  3. 设置 NGINX (或其他网络服务器)将请求从这个端口转发到你的应用。
  4. 配置自动缩放规则(如果需要)。
  5. 编写应用程序的特定于框架的样板文件,如请求处理程序和其他服务器代码。
  6. 写出你的商业逻辑。

虽然这是一个做作,但事实仍然是,使用这种“经典”工作流部署你自己的应用程序需要花费大量的时间和精力在任务而不是上,而不是编写你的“核心”应用程序代码。更重要的是:你将为你的服务器运行的每一秒钟付费,不管它被使用了多少。如果你的应用程序有很长的静默期(比如说一整夜),这可能会在你(或你公司)的口袋里烧一个洞。

进入无服务器

您可能已经看到了这一点:如果您不需要做大量的(通常是死记硬背的)配置,而是直接投入到具体的编码问题中,会发生什么?这是无服务器计算背后的核心理念。从根本上说,服务器仍然以某种形式存在,但是公开应用程序的服务器的设置和配置被抽象掉了。从实际角度来看,这意味着:

  • 您不必手动配置和维护您的虚拟机。
  • 你不必写()样板框架代码。
  • 您不需要配置任何防火墙规则、端口转发或自动扩展。

本质上,无服务器计算的一个关键目标是通过最大化开发人员花费在编写最终驱动业务价值的业务逻辑上的时间,以及更少的编写逻辑的时间,来显著减少开发人员的典型工作量。作为开发人员,您编写一个函数来捕获一些有价值的业务逻辑,并可以立即将其作为可大规模扩展的服务发布。理论上,这是缩短价值实现时间的好方法。借用谷歌的说法,无服务器计算允许任何人使用他们的应用程序:

“从原型到生产再到星球规模。”

还有一件事。您只需为您使用的东西付费。如果你对你的服务的需求很低,你付的钱就少。对于上面讨论的传统虚拟机部署,这不太可能是真的。

事件驱动架构

那么它是如何做到这一点的呢?

无服务器计算的关键使能技术之一是所谓的“微虚拟机”,如鞭炮。此类技术允许云提供商快速“启动”新虚拟机,以便按需运行您的代码,然后在不使用时快速关闭它们。这就是“事件驱动架构”这个术语的由来:你的代码和它所在的虚拟机只有在被一个事件触发时才会运行(例如,对函数的请求,或者其他一些触发,比如来自调度器的在特定时间运行函数的信号)。

额外的好处是,云提供商将根据需要“启动”尽可能多的虚拟机来满足您的服务需求,这意味着您的功能/应用程序可以近乎无限地扩展(尽管这将变得非常昂贵!).实际上,这意味着在最小的情况下,您需要做的就是用您选择的语言编写一个简单的函数,并告诉您选择的提供者将其公开为无服务器函数。

实际上,这意味着在最小的情况下,你需要做的就是用你选择的语言写一个简单的函数,并告诉你选择的提供者将其公开为无服务器函数。

你所需要做的就是坚持一些规则和惯例,它将会开箱即用。一会儿你就会明白这句话是多么的字面意思。听起来很酷,对吧?

秘密地

这一切似乎好得令人难以置信。许多这样的工具和框架落入了夸大其词的陷阱,结果只是把问题拖来拖去。但是在无服务器的情况下,真的那么好吗。至少有时候是这样。通常情况下。前提是你至少同意一些(可能很小,但可能是致命的)警告。以下是一些需要注意的主要问题:

  • 冷启动——如你所见,当不使用时,管理你的无服务器代码的“实际”服务器可能会停止运转。这为您节省了资金,但是当您向无服务器功能发送请求以启动机器时,也会增加(通常很短)延迟。这种延迟可能是一两秒的量级,特别是对于一些众所周知启动时间很慢的解释语言。当你的功能重新启动后,它将在几分钟内保持高度响应,在此之后,如果没有使用,它将重新关闭。如果您的应用程序不能容忍这种延迟,那么无服务器功能可能会有问题。
  • 资源有限&可配置性 —无服务器计算的好处之一也是其潜在的缺点之一:它限制了运行代码的环境、操作系统和“硬件”的可配置性。如果您想运行大量 CPU 或内存密集型操作的代码,这就很麻烦了(许多数据科学问题都有这种情况)。如果你需要大量的 CPU 和 RAM 来运行你的函数,你可能需要去别处看看。
  • 调试 —这个可能会有问题。由于您对代码运行的环境没有相同级别的控制,因此很难有效地调试一些问题,并且在开发期间建立一个有代表性的测试环境比正常情况下更难。此外,如果您的应用程序最终运行多个无服务器功能作为其架构的一部分,那么随着应用程序复杂性的增加,跟踪正在发生的事情和发生的位置会变得非常困难。
  • 供应商锁定 —最后,云提供商通常会提供自己的框架来在其平台上部署无服务器功能。这使得将代码从一个提供者迁移到另一个提供者变得更加困难。

综上所述,如果你有一个应用程序可以忍受低需求时期的偶尔延迟,你的工作负载对资源的要求相对较低,并且你不介意潜在地依赖于特定的云提供商,那么无服务器很可能是解决你的问题的理想解决方案。

是时候写点代码了

还感兴趣吗?很好。这里有一个简单的例子,说明如何将自己的 Python 函数部署为Google Cloud Function——Google 的无服务器计算产品。首先,如果你还没有一个谷歌云账户,你应该去注册一个新账户。新注册的用户可以获得 300 美元的积分,所以这个例子不会花你一分钱。

接下来,安装 Google gcloud命令行工具。谷歌的文档给出了如何在你的平台上做这件事的演示。

好了,该编码了。下面是您将要部署的代码:

def say_hello(request): 
    name = request.args.get("name") 
    return f"Hello there, {name}!"

这很简单。您真正需要理解的唯一一件事是,这个函数的request参数是一个 Flask 请求上下文。如您所料,该对象包含特定于您的请求的信息,包括作为 URL 的一部分传递的参数。在这种情况下,您将从 URL 中取出name参数。具体地说,如果你向some.domain.name/say-hello?name=Jane发送一个请求,这将提取name参数。通过这种方式,您可以让函数访问任意的有效负载。

接下来,在您选择的新目录中,将这段代码复制到名为main.py的文件中。Google 的框架期望一个这个名字的文件,所以最好打球。如果您想安装额外的包,您可以在与您的main.py相同的目录中包含一个requirements.txt文件,这些将在您的功能部署时为您安装。现在,您已经准备好部署您的功能了。

要进行部署,您可以运行:

gcloud functions deploy say-hello --entry-point=say_hello --runtime=python37 --project={project} --allow-unauthenticated --trigger-http

让我们打开包装。

  • 命令gcloud functions deploy告诉gcloud你想要部署一个函数,下一个参数say-hello就是你的云函数的名字。这也将用作您的功能的路线(即,它将在/say-hello可访问);
  • --entry-point指向main.py中您想要公开的函数,而--runtime告诉部署工具您想要将代码部署到哪个云函数运行时(在本例中是 Python 3.7);
  • 然后,--project参数指定您希望在其上部署云功能的 Google Cloud 项目 ID(请确保在这里输入您自己的项目 ID!);
  • 最后,--allow-unauthenticated标志告诉部署工具公开公开该函数(您可能希望在生产中更改这一点!),而--trigger-http请求告诉它在 HTTP 请求时被触发。

运行该命令,几分钟后,您应该能够转到如下 URL(记住替换您自己的子域—您可以在上面命令的控制台输出中找到它):

[https://{subdomain}.cloudfunctions.net/say-hello?name=World](https://{subdomain}.cloudfunctions.net/say-hello?name=World)

你应该会得到回应:

Hello there, World!

好了,你已经部署了一个谷歌云功能!

原载于 2020 年 7 月 22 日https://mark . douthwaite . io

软件测试简介

原文:https://towardsdatascience.com/a-brief-introduction-to-software-testing-38499dd4189?source=collection_archive---------34-----------------------

您的应用程序需要什么样的测试?

来自 Pexels创业股票照片

在软件开发中,任何代码都需要经过一系列步骤才能发布。无论应用领域、目标受众/平台或规模如何,所有开发人员都必须经历软件开发过程。

这个过程包括 6 个主要步骤:收集项目/应用程序需求,分析这些需求,设计软件,测试和调试,部署和维护项目。

可以说,这个过程中最关键的步骤是测试步骤。尽管在循环中测试步骤在设计步骤(包括设计、概述和实现代码)之后,但实际上,测试与编写代码是并行的。

作者照片(使用 Canva 制作)

软件测试的主要目标是消除代码中的错误。然而,一个项目可以从一个好的测试过程中获得额外的好处。好处,如增强性能、用户体验和整个项目的安全性。

通常,在处理大项目时,团队被分成几个部分。每个都有其开发任务,每个任务都有其独立的功能。然后将这些任务组合起来,形成整个软件产品。这就是为什么每个部分都必须经历自己的测试过程,以确保它在添加到主项目之前正常工作。

现在的问题是,应该使用什么样的测试?

软件测试的类型

您可以使用许多不同类型的软件测试来确保代码正常运行,并且对代码的任何更改都不会丢失项目的全部功能。尽管所有的测试技术都是有用的,但并不是所有的技术都是一样的。在这篇文章中,我们将讨论不同的测试实践之间的区别。

让我们开始测试…

我们通常可以将软件测试分为两大类:功能测试和非功能测试。

功能测试

功能测试包括软件应用程序功能方面的测试。当你执行功能测试时,你必须检查代码中的每个功能。您需要确保代码的每个部分都正常运行。有许多类型的功能测试,例如:

  1. 单元测试。
  2. 集成测试。
  3. 端到端测试。
  4. 烟雾测试。
  5. 回归测试。

非功能测试

非功能测试的目标是应用程序的非功能方面,如性能、可靠性、可用性和安全性。非功能性测试旨在提高代码的质量。手动执行这种类型的测试并不容易。因此,这些测试通常使用特殊的测试工具来执行。无功能测试的一些例子有:

  1. 性能测试。
  2. 安全测试。
  3. 兼容性测试。
  4. 可用性测试。
  5. 可扩展性测试。

功能测试与非功能测试

问题不是选择功能性测试还是非功能性测试,而是您应该为特定的应用程序选择哪种类型的功能性测试或非功能性测试。原因是,使用功能测试和非功能测试的目的是完全不同的。

如果你想确保你的代码的所有组件都按照它们应该的方式运行,你将使用功能测试。但是,如果你已经知道一切都正常工作,然而你需要分析代码的性能,那么你将使用非功能性测试。

作者照片(使用 Canva 制作)

功能测试的类型

功能测试有许多种类,您可以根据您执行测试过程的目标使用不同的种类。为了更好地讨论各种功能测试类别之间的区别,让我们来讨论 5 种最常用的功能测试技术。

№1:单元测试

单元测试通常由开发人员编写不同的 单元测试 来执行,以实现代码中的特定功能。例如,您可以为一个特定的函数编写不同的测试来测试它在不同输入下的行为。

这通常需要编写单元测试,在每个单元测试中使用不同的输入来调用函数,并验证其输出。代码覆盖率对于单元测试质量至关重要。所有的测试用例需要涵盖三个方面:

  1. 线路覆盖。
  2. 代码路径覆盖率。
  3. 方法覆盖率。

单元测试是大多数数据科学应用程序遵循的主要测试技术。

№2:集成测试

通常,一个项目由不同的代码文件(模块)组成,每个代码文件执行整个项目中的特定任务。单元测试对于测试这些文件中的每一个是否能独立工作非常重要;然而,当所有这些模块组合在一起时,我们需要集成测试。

集成测试确保不同的模块能够正确地协同工作。通常,您需要执行的集成测试比单元测试少。

单元和集成测试的两个有用工具是 JasmineMocha

№3:回归测试

构建和维护软件项目通常是一个持续的过程。从来都不是一蹴而就的。通常,会频繁添加新的特征和属性。

如果您需要在对任何模块或功能进行更改后测试您的项目,那么您需要一种测试整个系统的测试技术,那就是回归测试

回归测试不需要像最初的单元和集成测试那样广泛,但是应该确保覆盖的数量,以证明功能是稳定的。

一些有用的回归测试工具有 TestCompleteSeleniumAppium

№4:端到端测试

端到端测试是对整个软件系统的功能测试。该测试仅在系统集成测试完成时执行,包括功能和非功能需求。

当您测试的项目涉及用户交互时,这种类型的测试是最佳的。端到端测试确保代码的每一部分,从源代码到用户,都能正常运行。

黄瓜量角器Karma 是一些很棒的端到端测试工具。

№5:烟雾测试

冒烟测试,也被称为构建验证测试,是一种专注于确保最重要功能工作的软件测试。这个测试的结果被用来决定一个构建是否足够稳定以进行部署。

“烟雾测试”一词来自一种类似的硬件测试的软件测试,在这种测试中,如果设备在第一次打开时没有释放任何烟雾,则通过测试。

结论

测试是软件开发中最重要的步骤之一。无论你提交的是什么或者你的申请是什么,在你发布一个项目之前,你都需要经历不同阶段的测试。

软件测试有两大类,功能性的和非功能性的。功能性测试侧重于测试代码的功能,而非功能性测试的目标是代码的性能。

基于您的应用程序和最终目标,您可以使用不同的功能性和非功能性测试技术。通常,功能测试会在非功能测试之前运行,因为您需要在决定增强项目性能之前确保项目正常运行。

时间序列分类算法综述

原文:https://towardsdatascience.com/a-brief-introduction-to-time-series-classification-algorithms-7b4284d31b97?source=collection_archive---------0-----------------------

专门为时间序列分类设计的专用算法

杰拉德皮克斯拜

时间序列机器学习的一个常见任务是分类。给定一组带有类标签的时间序列,是否可以训练一个模型来准确预测新时间序列的类?

来源:用 sktime 进行单变量时间序列分类

专门用于时间序列分类的算法有很多!这意味着您不必将数据放入 scikit-learn 分类器中,也不必求助于深度学习来解决每个时间序列分类任务。

在本文中,我将介绍五类时间序列分类算法,并详细介绍具体的算法。在大量不同的数据集上,这些特定的算法已经显示出比基线分类器(KNN)平均执行得更好[1]。

  1. 基于距离(具有动态时间弯曲的 KNN)
  2. 基于间隔(时间序列森林)
  3. 基于字典(BOSS,cBOSS)
  4. 基于频率(上升-类似时间序列森林,但具有其他功能)
  5. 基于 shape let(shape let 变换分类器)

最后,我简要介绍了如何选择合适的算法。

本文描述的算法已经在[sktime](https://github.com/alan-turing-institute/sktime) python 包中实现。

[## Sktime:用于时间序列机器学习的统一 Python 库

用于时间序列预测、分类和回归的“sklearn”

towardsdatascience.com](/sktime-a-unified-python-library-for-time-series-machine-learning-3c103c139a55)

为什么要为时间序列设计专用算法?

在时间序列分类问题上,时间序列分类算法往往比表格分类器表现更好。

时间序列分类的一个常见但有问题的解决方案是将每个时间点视为一个单独的特征,并直接应用标准学习算法(例如 scikit-learn 分类器)。在这种方法中,算法忽略数据的时间顺序中包含的信息。如果要素顺序被打乱,预测不会改变。

使用深度学习对时间序列进行分类也很常见。LSTMs 和 CNN 能够挖掘时间序列的动态特征,因此获得了成功。然而,神经网络有一些挑战,使它们不适合许多分类任务:

  • 选择高效的架构
  • 超参数调谐
  • 有限的数据(神经网络需要许多例子)
  • 训练缓慢

尽管存在这些挑战,但确实存在用于时间序列分类的特定神经网络架构。这些已经在 sktime-dl python 包中实现了。

时间序列分类的基本概念

时间序列转换

许多时间序列特定算法是转换后的时间序列和常规分类算法的组合,例如 scikit-learn 中的算法。

特征提取非常多样和复杂。

可以全局地(在整个时间序列上)或者局部地(在规则间隔/箱、随机间隔、间隔的滑动窗口等等上)提取特征

系列可以转换成原始值(如平均值、标准差、斜率)或其他系列(如傅立叶变换、拟合自回归系数系列)。

最后,变换可以是一维的或多维的

[## 高度比较的时间序列分析——一篇论文综述

用于比较、聚类、分类和注释的时间序列特征提取分析

medium.com](https://medium.com/towards-artificial-intelligence/highly-comparative-time-series-analysis-a-paper-review-5b51d14a291c)

收缩的

收缩是本文描述的大多数算法中使用的关键概念。

简单来说,收缩限制了算法的运行时间。直到分配的时间到期,算法继续迭代以学习给定的任务。

基于距离的分类

这些分类器使用距离度量来确定类成员。

时间序列的 k-最近邻(具有动态时间弯曲)

流行的 k 最近邻 (KNN)算法可以通过用动态时间弯曲 (DTW)度量代替欧几里德距离度量来适应时间序列。DTW 测量在时间、速度或长度上可能不完全一致的两个序列之间的相似性。(点击此处了解我对时间序列聚类的 DTW 的解释)。

KNN 与 DTW 通常被用作评估时间序列分类算法的基准,因为它简单,稳健,不需要大量的超参数调整。

虽然 KNN 和 DTW 很有用,但需要大量的空间和时间来计算。在分类期间,KNN-DTW 将每个对象与训练集中的所有其他对象进行比较。此外,KNN 提供的关于为什么将一个系列归入某一类的信息有限。

KNN 也可能在有噪声的序列中表现不佳——序列中的噪声可能盖过形状的细微差异,而形状的细微差异对于类别区分是有用的[4]。

区间分类器

这些分类器基于包含在系列的不同区间中的信息进行分类。

时间序列森林分类器

时间序列森林(TSF)分类器使随机森林分类器适应序列数据。

  1. 将序列分割成随机间隔,具有随机起始位置和随机长度。
  2. 将每个区间的汇总特征(均值、标准差和斜率)提取到单个特征向量中。
  3. 在提取的特征上训练决策树。
  4. 重复步骤 1-3,直到完成所需数量的树或时间用完。

新系列是根据森林中所有树木的多数投票进行分类的。(在多数投票中,预测是由最多的树预测的类是森林的预测)。

实验研究表明,时间序列森林可以胜过基线竞争者,例如具有动态时间扭曲的最近邻[1,7]。

时序森林的计算效率也很高。

最后,时间序列森林是一个可解释的模型。时间特征重要性可以从时间序列森林中提取,如 sktime 单变量时间序列分类演示所示。

基于词典的分类

基于字典的分类器首先将实值时间序列转换成离散的“单词”序列。然后基于提取的符号词的分布进行分类。

字典分类器都使用相同的核心过程:长度为w的滑动窗口在一系列中运行。对于每个窗口,数字序列被转换成长度为l的“单词”。这个单词由α可能的字母组成。

SFA 符号包(BOSS)

使用符号傅立叶近似 (SFA)变换从序列中提取 BOSS 分类器的单词特征:

  1. 计算窗口的傅立叶变换(如果发生归一化,则忽略第一项)
  2. 使用多系数宁滨 (MCB)将第一个l傅立叶项离散成符号,形成一个“单词”。MCB 是一种监督算法,它将连续的时间序列分成一系列字母。

如不同位置的绿线所示,MCB 独立于其他时间点对每个时间点进行分类。SAX 是另一种宁滨系列算法,它独立地对每个时间序列进行分类。来源: pyts 文档

当窗口滑动时,这些单词的字典被构建,记录每个单词的频率。如果同一个单词是由两个或两个以上的连续窗口产生的,那么这个单词只计算一次。当滑动窗口完成时,序列被转换成基于字典的直方图。

最后,任何分类器都可以根据从系列中提取的单词直方图进行训练。

老板乐团

最初的 BOSS 算法实际上是先前描述的 BOSS 分类器的集合。BOSS 集成在单个 BOSS 分类器的参数(lαwp)之间进行网格搜索。(p控制子系列是否规范化。)集成仅保留其准确度在最佳分类器的 92%准确度内的成员。

BOSS 集成使用最近邻算法作为其分类器。分类器使用一个定制的非对称距离函数:一个部分欧几里德距离,只包括测试实例的直方图中包含的单词。

由于在大的预定义参数空间上搜索,BOSS 会带来时间开销和内存使用不稳定的风险。

BOSS ensemble 是大型时间序列分类竞赛论文【1】中最准确的基于字典的分类器。

可承包老板

cBOSS 算法比 BOSS 快一个数量级。与 BOSS 相比,cBOSS 在 UCR 分类档案库中的数据集上的准确性没有显著差异。

cBOSS 不像 BOSS 那样在整个参数空间进行网格搜索,而是从参数空间随机采样,没有替换。然后,cBOSS 对每个基本分类器的数据进行二次采样。

cBOSS 通过保留固定数量的基分类器,而不是保留给定性能阈值以上的所有分类器,来提高 BOSS 的内存需求。最后,cBOSS 根据训练精度指数加权每个基本分类器的贡献。

基于频率的

基于频率的分类器依赖于从序列中提取的频率数据。

随机间隔光谱集合

随机区间光谱集合,或上升,是时间序列森林的一个流行的变种。

RISE 在两个方面不同于时序森林。首先,它对每棵树使用一个时间序列间隔。第二,使用从系列中提取的光谱特征而不是汇总统计来训练它。

RISE 使用几个串到串特征提取变压器,包括:

  • 拟合自回归系数
  • 估计的自相关系数
  • 功率谱系数(傅立叶变换的系数)

上升算法很简单:

  1. 选择一个系列的随机间隔(长度是 2 的幂)。(对于第一棵树,使用整个系列)
  2. 对于每个序列的相同间隔,应用序列到序列特征提取转换器(自回归系数、自相关系数和功率谱系数)
  3. 通过连接提取的特征来形成新的训练集
  4. 训练决策树分类器
  5. 合奏 1-4

类别概率按基本分类器投票的比例计算。RISE 通过创建一个自适应模型来控制构建单棵树的运行时间。这对于长序列(如音频)很重要,因为很大的间隔意味着很少的树。

基于 Shapelet 的分类器

Shapelets 是代表一个类的时间序列的子序列或小的子形状。它们可用于检测“同一类别内系列之间的独立于相位的局部相似性”[1]。

蓝线是原始时间序列。红线是从中提取的 shapelet。从[4]修改的图像。

单个 shapelet 是时间序列中的一个间隔。任何序列中的间隔都可以被枚举。例如,[1,2,3,4]有 5 个区间:[1,2][2,3][3,4][1,2,3][2,3,4]

基于 Shapelet 的分类器搜索具有辨别能力的 shape let。

然后,这些 shapelet 特征可用于解释基于 shapelet 的分类器-某些 shape let 的存在使一个类比另一个类更有可能。

Shapelet 变换分类器

在 Shapelet 变换分类器中,该算法首先识别数据集中的前 k 个shape let。

接下来,计算新数据集的 k 个特征。每个特征被计算为系列到每个k sshapelet 的距离,每个 shape let 一列。

最后,任何基于矢量的分类算法都可以应用于 shapelet 变换的数据集。在[1]中,使用了加权集成分类器。在[2]中,作者仅使用了一个旋转森林分类器,这是一个基于树的集成,在 PCA 变换的特征子集上构建每棵树[5]。平均来说,对于具有连续特征的问题,旋转森林是最好的分类器,如图【6】

[sktime](https://github.com/alan-turing-institute/sktime)中,默认使用随机森林分类器(500 棵树),因为 python 中还没有旋转森林[8]。

算法如何识别和选择 shapelets?

sktime中,shapelet 搜索过程不会完全枚举和评估所有可能的 shape let。相反,它随机搜索 shapelets 进行评估。

根据信息增益来评估所考虑的每个 shapelet。保留最强的非重叠小形状。

您可以指定在执行 shapelet 变换之前搜索 shape let 的时间。sktime的默认时间是 300 分钟。

集成分类器

蜂巢

基于变换的集成的分层投票集合(HIVE-COTE)是建立在前面讨论的分类器上的元集成。

" HIVE-COTE 1.0 的系综结构概述."

HIVE-COTE 预测是其成员生成的预测的加权平均值:shapelet 转换分类器、BOSS、时序森林和 RISE。

每个子分类器估计每个类别的概率。控制单元然后组合这些概率(CAPWE)。权重被分配为在训练数据上找到的分类器的相对估计质量。

使用哪个分类器?

选择时间序列分类器时有三个主要考虑因素:预测精度、时间/内存复杂性和数据表示。

在没有具体数据信息的情况下,从 火箭蜂巢开始。(ROCKET 是一个简单的线性分类器,基于随机卷积核——随机长度、权重、偏差、膨胀和填充)。[2]的作者认为“在没有相反的专家知识的情况下,最准确的算法设计是集成基于不同表示的分类器。”平均来说,ROCKET 并不比 HIVE-COTE 差,而且要快得多。

[## ROCKET:快速准确的时间序列分类

“时间序列分类的任务可以被认为是学习或检测信号或模式…

link.medium.com](https://link.medium.com/qYcaC7lL69)

当最佳特征可能是一系列中相位无关模式的存在或不存在时,基于 Shapelet 的分类器会更好。

当您可以使用模式的频率进行区分时,基于字典的 (BOSS) 或基于频率的 (RISE) 分类器会更好。

最后一句话

如果您喜欢这篇文章,请关注我,了解更多关于数据科学主题的内容!我计划继续撰写关于时间序列分类、聚类和回归的文章。

[## 阅读亚历山德拉·阿米登(以及媒体上成千上万的其他作家)的每一个故事

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

alexandra-amidon.medium.com](https://alexandra-amidon.medium.com/membership)

感谢 Markus Loning 对本文的反馈,感谢 Anthony Bagnall 对模型选择的指导。

参考

[1] Bagnall,Anthony 等人,“伟大的时间序列分类烘焙:对最近算法进展的回顾和实验评估。”数据挖掘与知识发现 31.3(2017):606–660。还有

[2] Bagnall,Anthony,等.两个工具包的故事,报告之三:关于 HIVE-COTE v1.0 的使用和性能.《2019

[3] Fawaz,Hassan Ismail 等,“时间序列分类的深度学习:综述”数据挖掘与知识发现 33.4(2019):917–963。

[4] L .叶和 e .基奥。时间序列 shapelets:一种允许精确、可解释和快速分类的新技术。数据挖掘和知识发现,22(1–2):149–182,2011。

[5] Rodriguez,J,等.旋转森林:一种新的分类器集成方法。2006 年 11 月 IEEE 模式分析与机器智能汇刊 28(10):1619–30。DOI: 10.1109

[6] Bagnall,Anthony 等,“旋转森林是具有连续特征问题的最佳分类器吗?”2018.arXiv: 1809.06705。

[7]邓,H,等.一种用于分类和特征提取的时间序列森林信息科学 239:142–153(2013)。

[8] Bagnall,Anthony 等.“两个工具包的故事,报告第一个:对时间序列分类算法的正确性和效率进行基准测试。“2019。

[9] Dempster A,Petitjean F,Webb GI (2019) ROCKET:使用随机卷积核的异常快速和准确的时间序列分类arXiv:1910.13051

sk time 中基于字典的时间序列分类

sktime 的单变量时间序列分类教程

XGBoost 简介

原文:https://towardsdatascience.com/a-brief-introduction-to-xgboost-3eaee2e3e5d6?source=collection_archive---------12-----------------------

用 XGBoost 实现极限梯度提升!

XGBoost 简介

XGBoost 是一个优化的梯度增强机器学习库。它最初是用 C++编写的,但是有其他几种语言的 API。核心 XGBoost 算法是可并行化的,即它在单个树中进行并行化。使用 XGBoost 有一些缺点:

  1. 它是最强大的算法之一,具有高速度和高性能。
  2. 它可以利用现代多核计算机的所有处理能力。
  3. 在大数据集上训练是可行的。
  4. 始终优于所有单一算法方法。

这里有一个简单的源代码来理解 XGBoost 的基础知识。

代码:

步骤 1:导入所有必要的库,对于 xgboost 我们需要导入“XGBoost”库,然后使用 pandas 读取文件。

步骤 2:将整个数据集按照称为 X 的特征和称为 y 的目标向量分割成样本矩阵,如下所示:

第三步:分割数据集进行训练和测试,这里我把它分割成 80%训练和 20%测试,然后实例化 XGBClassifier(因为输出需要分类的形式,要么是 1,要么是 0)。它的一些超参数是“客观的”,它指定了所用算法的类型,这里我使用了“二元:逻辑”,这意味着二元分类的逻辑回归,输出概率和“n_estimators”,它调整了决策树的数量。

第四步:拟合和预测模型,然后计算精度。

精确度:0.78333

让我们更深入地了解这个超级强大的算法!

XGBoost 通常使用树作为基本学习器,决策树由一系列二元问题组成,最终预测发生在叶子上。XGBoost 本身就是一个系综方法。迭代地构造树,直到满足停止标准。

XGBoost 使用 CART(分类和回归树)决策树。CART 是在每个叶子中包含实值分数的树,不管它们是用于分类还是回归。如果有必要,实值分数可以被转换成用于分类的类别。

XGBoost 中的模型评估

在这里,我们将看到模型评估过程与交叉验证的过程。那么,什么是交叉验证呢?

交叉验证

交叉验证是一种稳健的方法,通过将许多非重叠的训练/测试拆分为训练数据并报告所有数据拆分的平均测试集性能,来估计模型在未知数据上的性能。

下面是一个例子,

下面是上面代码涉及的步骤:

第 2 行和第 3 行包括必要的导入。第 6 行包括加载数据集。第 9 行包括将数据集转换成 XGBoost 的创建者创建的优化的数据结构,该数据结构赋予包性能和效率增益,称为 DMatrix。 为了使用 XGBoost cv 对象,这是 XGBoost 的学习 API 的一部分,我们必须首先明确地将我们的数据转换成一个 DMatrix。

第 12 行包括创建一个参数字典来传递给交叉验证,这是必要的,因为 cv 方法不知道使用了哪种 XGBoost 模型。第 15 行包括调用 cv 方法,并传入存储所有数据的 DMatrix 对象(参数字典、交叉验证折叠数和需要构建的树数、要计算的度量、是否将输出存储为 pandas 数据帧)。第 18 行包括将公制转换为精确度,结果是 0.88315。

XGBoost 与梯度升压

XGBoost 是一种更加规则化的渐变增强形式。XGBoost 使用高级正则化(L1 & L2),这提高了模型泛化能力。

与梯度增强相比,XGBoost 提供了高性能。它的训练速度非常快,可以跨集群并行化

什么时候使用 XGBoost?

  1. 当有大量训练样本时。理想情况下,多于 1000 个训练样本,少于 100 个特征,或者我们可以说特征的数量< number of training samples.
  2. When there is a mixture of categorical and numeric features or just numeric features.

When not to use XGBoost?

  1. Image Recognition
  2. Computer Vision
  3. When the number of training samples is significantly smaller than the number of features.

这是关于 XGBoost 算法的简要信息。

经典人工智能的早期简史

原文:https://towardsdatascience.com/a-brief-pre-history-of-classical-ai-40a98a6e6db4?source=collection_archive---------35-----------------------

Giammarco Boscaro 在 Unsplash 上拍摄的照片

推理和经典人工智能

人工智能的两个基本概念

要谈推理,理解我们是如何走到这一步的很重要。这篇文章涵盖了我所谓的经典人工智能的前历史——故事中发生在现代计算机发明之前(20 世纪 50 年代之前)的那些部分,但对于理解我们为什么相信人工智能是可能的至关重要。

这是推理系列的第二部分。

像大多数事情一样,经典人工智能的起源植根于哲学,始于古代世界(希腊人、印度人和中国人都有一些早期的逻辑形式)。但是,由于我不是一个受虐狂,我们从更现代的时代开始,有两大思想为现代人工智能奠定了基础:

  1. 将智能机械化——是否存在一个可信的、自动的过程,它接收一些信息并吐出新信息?可信赖的,在这种情况下,意味着所产生的信息得到所获取的信息的支持。自动表示无需人为干预即可工作。当然,简单地发现新信息可能看起来像是非常有限的智能定义,但它反映了人工智能的数学起源,这些技术最初应用于自动定理证明等主题。
  2. 可计算性——有可能在计算机上实现这个自动过程吗?

命题逻辑

逻辑的发展是人类在智能机械化方面的第一次伟大尝试,现代逻辑的基础在于乔治·布尔、查尔斯·皮尔斯和戈特洛布·弗雷格。乔治·布尔不满足于为现代计算机打下基础(你好,布尔代数),还发明了命题逻辑(T14)差点毁掉了我初出茅庐的研究生生涯(我的 PHIL 650 逻辑导论课不及格)。命题逻辑通过一组事实或命题来表示世界的当前状态。这些命题可以用布尔运算符组合起来形成公式。例如:
猫在狗的左边,或者 Whiskers 是猫,Fido 是狗,Whiskers 坐在 Fido 的左边

除了当前状态,命题逻辑还有以 if-then 规则形式存储的关于世界的知识。
如果 络腮胡是一只猫 那么 络腮胡有四只脚,络腮胡有一条尾巴或者
如果 络腮胡是一只猫而 Fido 是一只狗 那么 Fido 害怕络腮胡

新的事实是使用一个非常重要的演绎工具从目前已知的事实中推导出来的,这个工具叫做假言假语,它说当你有一个这样的规则:如果 p 然后 q 并且事实 p 为真,那么事实 q 为真。

图片由 Unmesh Kurup 提供

假言可能看起来微不足道,但它保证当知识以可信任的规则的形式表示时,使用假言从这些规则生成的新信息也是可信任的。

机械化过程称为规则匹配,将规则应用于事实。作为例子,考虑只有一个规则的情况:
如果 猫在狗的左边,狗在人的左边 那么 猫在人的左边。 现在想象一下,在这种情况下有两个你知道为真的事实:
狗的左边有一只猫
人的左边有一只狗 规则匹配过程将这两条信息与规则匹配,并创建第三个事实:
人的左边有一只猫

在我们的例子中,只有一个匹配的规则,而且只匹配一次。但是想象有一个额外的事实:
人类在灯的左边
和一个额外的规则:
如果 猫在人类的左边,人类在灯的左边 那么 猫在灯的左边 一旦第一个规则匹配,并且添加了猫在人的左边的事实,我们的新规则将匹配并添加第四个事实:
灯的左边有一只猫

图片由 Unmesh Kurup 提供

将规则应用于当前情况会产生新的信息。这个新信息触发另一轮匹配(使用一组可能不同的规则),产生附加的新信息。这个重复的过程就是命题逻辑自动寻找新信息的方式。

谓词(一阶)逻辑

现在,我们不应该让乔治独霸我的博士学位过早夭折的所有荣誉。查尔斯·皮尔斯和戈特洛布·弗雷格对这个故事同样重要,因为他们发明了谓词或一阶逻辑。举一个猫离开狗离开人的例子。这不仅仅适用于猫、狗和人类。任何三件事都是如此。有了命题逻辑,你必须为你能想到的每一组三个规则写下来…狗在猫的左边,人在猫的左边,狗在猫的左边,猫-猫-狗,猫-人-水豚,人-番茄-勃肯斯托克……你明白了。有一些变通方法可以更简洁地表示信息,但是在大多数情况下,以这种方式表示事实是非常乏味的,也不是非常有用。

使用谓词逻辑,您可以使用变量来表示事实。不写:
如果猫在狗的左边,狗在人类的左边, 那么 猫在人类的左边
你可以写:
对于所有的 A、B、C: 如果 A 在 B and B 的左边 然后 A 在 C 的左边,涵盖了动物、人类、无生命物体等广泛的场景,大家耐心地坐在一起。 代表所有的
称为量词,允许谓词逻辑代表可以代表所有对象的变量。还有一个额外的量词—“There exists”——允许谓词逻辑表示代表一件事情的变量。例如:
存在 x:这样 x 是一个人,x 是美国总统**

谓词(和命题)逻辑可以写成更短、更易读的形式:
【left of(A,B)】&left of(B,C) → LeftOf(A,C)
在这里,的
left 被称为谓词,A 和 B 是代表命题的变量。谓词逻辑使用与命题逻辑相同的词汇——命题、布尔运算符、推理规则(通常是假言词)——外加变量和两个量词。这些增加使得谓词逻辑在表示规则方面更加强大,但代价是运行起来更加复杂(由于需要匹配变量)。**

还有二阶谓词逻辑,您甚至可以为的Left 使用一个变量,因为适用于 Left 的也适用于其他类似的谓词。于是,我们可以把 LeftOf(A,B) & LeftOf(B,C) → LeftOf(A,C) 写成 D(A,B) & D(B,C) → D(A,C) 。其中 D 可以是左、右、上、下、前、后等等。二阶逻辑使规则匹配变得更加困难,我从未见过在野外使用的规则匹配,但我的逻辑入门课程不及格,所以我知道什么。**

从命题逻辑和谓词逻辑中,我们可以提炼出机械化智能意味着三个要求:

  1. 一种表现你的知识的方式(例如规则)
  2. 一种表示当前情况的方式(命题或谓词)
  3. 一种自动保持将知识(从 1)应用于当前情况(2)的方法,以生成/推断/推导值得信赖的新信息。(形式和规则匹配)

这些要求并不特别苛刻。神经网络满足这些条件中的大部分——权重矩阵代表知识,输入矩阵是当前状况,前向传递是应用知识发现新信息的方式。神经网络失败的唯一地方是,它们没有将该过程应用于新信息(递归网络是例外)。神经网络显然不是逻辑系统。一个真正的逻辑系统有更严格的要求和定义,我们将在后面遇到。我们目前的目的是引入智能机械化的思想,即确定一个智能(狭义定义为发现新信息)是自动的过程。

离题进入健全和完整。

让命题逻辑和谓词逻辑(以及其他形式的逻辑)有趣的不仅仅是你能用它们做什么,而是你能证明什么;特别是称为稳固性完备性可判定性的三个属性。如果你还不知道这些概念,那么你应该密切关注,因为这可能是你今天会读到的最酷的东西:

如果从一个逻辑系统中得到的任何信息都是真实的,那么这个逻辑系统就是合理的。在一个合理的逻辑系统中,如果你从一组事实开始并运行逻辑机器,产生的所有信息在逻辑上都是可证明的,也就是说,你可以相信机器只产生正确的信息。

完整性是硬币的反面。一个逻辑系统(初始事实+过程)被认为是完整的,如果该系统中所有真实的信息都可以使用逻辑过程从开始的事实集中导出,也就是说,如果有新的信息在逻辑上遵循系统所知道的,系统将最终找到它。

总的来说,健全性和完整性使得一个逻辑系统是可靠的,因为你可以确定从它里面出来的所有东西都是有效的,并且它会找到任何逻辑上有效的东西。为了真正有用,逻辑系统也必须是可判定的。也就是说,需要有一种有效的方法(一种在有限的时间内运行的方法,尽管可能非常长)来确定该逻辑系统中的语句是真还是假。

命题逻辑是合理的、完整的、可判定的。一阶谓词逻辑是合理和完整的,但对于非平凡系统是不可判定的。(注:你可以有一门 5 学分的研究生水平的课程来证明上述观点)

健全性、完整性和可决定性共同赋予我们对机械过程的选择以尊严,因为它为我们提供了关于其有效性的理论保证。

无论如何,这里有三个要点供仍在阅读的人参考。

  1. 布尔、皮尔斯和弗雷格奠定了逻辑、推理和人工智能的基础
  2. 如果你学的是计算机科学,那就选数学系而不是哲学系提供的逻辑入门课程。你以后会感谢我的。
  3. 吸它布尔,皮尔斯和弗雷格。我拿到了博士学位。

关于逻辑的最后一点。逻辑可以绊倒任何人。伯特兰·罗素花了一生的时间试图建立对数学的逻辑理解。他想从几个假设(四个或五个)出发,证明所有数学的都可以通过逻辑机器从这些假设中推导出来。他的尝试最终是徒劳的,就像我试图通过我的逻辑入门课程一样。当他未能找到数学的逻辑基础时,他确实成功地完成了一些其他的事情——在广泛的学科范围内广泛地写作,创造了全新的学科,彻底改变了对数学和逻辑的理解,获得了诺贝尔奖。真是个懒鬼。玩笑归玩笑,罗素是 20 世纪哲学和自由主义的巨人之一。他看穿了布尔什维克主义的外表,随着希特勒的崛起,他的和平主义信仰出现了例外,担任印度联盟主席,并在 89 岁时因参加反核示威而入狱。真的,值得学习的人。

丘奇-图灵论题

逻辑系统(命题和谓词逻辑)彻底改变了我们对机械过程如何产生新信息的理解。丘奇-图灵论题让我们相信,建造一台真正实现这种过程的机器是可能的。

美国数学家阿隆佐·邱奇发明了一种数学逻辑系统,称为λ演算,作为解决数学问题的框架。Lambda 演算的表达能力允许它表示各种各样的逻辑。艾伦·图灵(他因图灵测试而出名)当然是图灵机的发明者,图灵机是一种用于计算的机器。丘奇和图灵意识到,任何用λ演算表示的东西都可以用图灵机来计算,反之亦然。由于 Lambda 演算涵盖了包括一阶逻辑在内的广泛过程,Church-Turing 论题考虑到了可以展示推理和智能的计算机器的可能性。

丘奇-图灵假说也是我们称大脑为计算机的原因。这并不是因为我们的大脑和计算机的计算方式相似。我们称大脑为计算机是因为

  1. 据我们所知,大脑正在实现一个可计算的功能,
  2. 图灵机可以实现任何可计算的功能,并且
  3. 计算机是图灵机。

因此大脑作为计算机的类比。

我们不知道这个可计算的函数是什么,也不知道它是如何实现的。但可计算功能及其实现之间的这种区别反映在经典人工智能和神经网络等概率对等物之间的分歧上。经典人工智能有一个很好的故事,讲述了这个可计算的函数看起来是什么样子,但在实现中却不那么令人信服。神经网络有一个关于实现可能看起来像什么的很好的故事,但是关于它们正在实现什么样的可计算功能就不那么令人信服了。

最后,很有可能存在许多不同但等价的这种可计算功能以及实现它们的许多不同方式。人工智能的历史是试图找到一个这样的功能和实现的故事(而认知科学的历史是试图确定人类智能背后的特定可计算功能和实现)。

这个系列的下一部是什么?

我最初打算这篇文章是经典人工智能的简史,但我很快意识到我必须把它分成两篇文章——这一篇讨论史前史,下一篇将关注自 20 世纪 50 年代以来的发展。

本系列的前几篇文章

六个容易和不那么容易的 AI 棋子
第一部分:什么是推理?

免责声明:本文表达的观点是我自己的观点,不一定代表我的雇主的观点。

你可以在我很少发帖子的 Medium 上关注我,也可以在我很少发微博的 Twitter (@manashastram)上关注我。😃

Scikit-learn (Sklearn)简介

原文:https://towardsdatascience.com/a-brief-tour-of-scikit-learn-sklearn-6e829a9db2fd?source=collection_archive---------23-----------------------

Sklearn 简介

照片由阮光拍摄

对于机器学习来说,Python 和 R 是当今应用最广泛的编程语言。Scikit-learn 是一个 python 库,它提供了数据读取、数据准备、回归、分类、无监督聚类等方法。在本帖中,我们将回顾一些构建回归模型的基本方法。该软件包的文档内容丰富,是每位数据科学家的绝佳资源。你可以在这里找到文档。

我们开始吧!

数据准备

对于我们的回归问题,我们将使用天气数据,这些数据可以在这里找到。

首先,让我们导入数据并打印前五行:

import pandas as pd 
df = pd.read_csv("weatherHistory.csv")
print(df.head())

接下来,让我们将日期列转换成熊猫日期时间对象,并创建年、月和日列:

df['Formatted Date'] = pd.to_datetime(df['Formatted Date'],  utc=True,)
df['year'] = df['Formatted Date'].dt.year
df['month'] = df['Formatted Date'].dt.month
df['day'] = df['Formatted Date'].dt.day

让我们再次打印前五行,以验证新列的创建:

print(df.head())

现在,让我们定义我们的输入和目标变量。我们将使用湿度、年、月、日、压力、能见度和风向来预测温度:

import numpy as np
X = np.array(df[[ 'Humidity', 'year', 'month', 'day', 'Pressure (millibars)', 'Visibility (km)', 'Wind Bearing (degrees)']])
y = np.array(df['Temperature (C)'])

然后,我们将分割数据用于训练和测试:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)

现在我们所有必要的变量都定义好了。让我们建立一些模型!

线性回归

先说线性回归。线性回归拟合带有系数的线性函数,使得目标和预测之间的残差平方和最小。

我们导入线性回归包如下:

from sklearn.linear_model import LinearRegression

我们用来评估模型性能的误差指标是均方误差(MSE)。MSE 由以下等式定义:

这里,y 是实际值,y-波形符是预测值。

让我们定义一个线性回归对象,拟合我们的模型,并评估性能:

reg = LinearRegression()
reg.fit(X_train, y_train)
y_pred = reg.predict(X_test)from sklearn import metrics
print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred))

表演不是很好。这仅仅意味着输入和目标之间的关系不是线性的。此外,探索性数据分析(EDA)可以进一步通知智能特征选择和工程,这可以提高性能。

随机森林

现在我们来看看随机森林。随机森林是一种基于树的方法,它集成了多个单独的决策树。

我们导入 RandomForestRegressor 包,如下所示:

from sklearn.ensemble import RandomForestRegressor

让我们定义一个随机森林回归对象,拟合我们的模型,并评估性能:

reg_rf = RandomForestRegressor()
reg_rf.fit(X_train, y_train)
y_pred = reg_rf.predict(X_test)from sklearn import metrics
print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred))

我们可以看到随机森林的性能比线性回归好得多。

我们还可以打印特征重要性。这使我们能够了解哪些变量对温度预测最为重要:

feature_df = pd.DataFrame({'Importance':reg_rf.feature_importances_, 'Features': [ 'Humidity', 'year', 'month', 'day', 'Pressure (millibars)', 'Visibility (km)', 'Wind Bearing (degrees)'] })
print(feature_df)

我们可以看到月份具有最高的重要性,这是有道理的。

我想指出的是,通过不传递任何参数,比如 max_depth 和 n_estimators,我选择了默认的随机森林值(n_estimators = 10 和 max_depth = 10)。我们可以通过优化随机森林中的参数来进一步提高性能。这可以手动完成,也可以使用网格搜索技术自动完成。我将把参数优化的问题留给另一篇文章。

支持向量机

我要讨论的下一个方法叫做支持向量回归。这是支持向量机(SVM)的扩展。支持向量机在高维特征空间中构造一组超平面,可用于回归和分类问题。

我们导入 SVR 包,如下所示:

from sklearn.svm import SVR

由于 SVR 的训练速度很慢,我将只选择前 100 条记录进行训练和测试。请随意在完整的数据集上进行训练和测试,以便更好地比较不同型号之间的性能。

df = df.head(100)

让我们定义一个支持向量回归对象,拟合我们的模型,并评估性能:

reg_svr = SVR()
reg_svr.fit(X_train, y_train)
y_pred = reg_svr.predict(X_test)from sklearn import metrics
print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred))

我们看到支持向量回归比线性回归表现更好,但比随机森林差。同样,这种比较并不完全合适,因为我们没有使用完整的数据集进行训练。

类似于随机森林示例,可以优化支持向量机参数,使得误差最小化。

K-最近邻居

我将讨论的最后一种方法是 k- 最近邻回归法。k-最近邻使用欧几里德距离计算,其中预测是 k最近邻的平均值。

我们导入 KNeighborsRegressor 包,如下所示:

from sklearn.neighbors import KNeighborsRegressor

让我们定义一个 k- 最近邻回归对象,拟合我们的模型,并评估性能:

reg_knn = KNeighborsRegressor()
reg_knn.fit(X_train, y_train)
y_pred = reg_knn.predict(X_test)
from sklearn import metrics
print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred))

我们看到 k- 最近邻算法在全数据集上训练时优于线性回归。

结论

我将在这里停下来,但是您可以随意选择模型特性,看看是否可以改进其中一些模型的性能。

概括地说,我简要介绍了 python 机器学习库。我讲述了如何定义模型对象、使模型适合数据,以及使用线性回归、随机森林、支持向量机和最近邻模型来预测输出。此外,通过探索这些不同类型的模型,我们能够窥视机器学习库的内部。请注意我们在库中使用的四个模块:

  1. 线性模型
  2. 全体
  3. SVM
  4. 邻居

虽然我们只看了回归方法,但是每个模块都有额外的分类方法。在另一篇文章中,我将概述 python 机器学习库中最常见的一些分类方法。

我希望这篇文章是有益的。这篇文章的代码可以在 GitHub 上找到。感谢阅读,机器学习快乐!

流失分析商业实践指南

原文:https://towardsdatascience.com/a-business-practical-guide-on-churn-analysis-for-analysts-ebdeb4e0424?source=collection_archive---------31-----------------------

分析客户流失时,实践、理论和技术的正确方法

编辑过的照片,由马頔·库多罗日科夫Unsplash 上原创

为什么大多数关于客户流失的文章没有帮助 没有人喜欢被忽略,企业也是如此。为了尽量减少这种情况,我们分析流失。当我开始学习客户流失分析时,我选择了 Medium 和 Kaggle。在阅读了许多文章和笔记本之后,我得出了一些促使我写这篇文章的结论。大多数作品要么是:

o Too 技术:代码多,推理少。我们处理的数据是对现实的描述,但许多文章缺乏交流。

o 太理论化:很多你应该做流失分析的理由,也许是一些数学,缺乏清晰的例子。经常跟着炒作。

o Too Specific: 商业是实用的,大多数文章都过于深入后两部分,对商业没有重大价值。分析师通过可操作的见解提供价值。一般如何获得这样的见解?

嗯,有些作品太无聊了!所以,我会把我们的分析总结在约会的世界里。毕竟我们不希望 Jack 永远一个人:)

因此,这篇文章将带你经历如何进行流失分析的步骤,我向你保证会有代码,我会把它弄清楚。这篇文章总结在下面的文氏图中,以约会酱为顶:

作者图片|我对作为分析师获得可行见解的看法

因为当我们过于关注理论时,我们可能会忽略科学过程,这使得证明我们的结论更加困难。

当我们对技术部分关注太少时,我们就会错过开展工作所必需的技能和经验。

当我们对实践方面关注太少时,我们会忽略我们的工作对商业的必要性和价值。

所以取得平衡是关键,尽管我们有时需要关注三者中的一个,但我们绝不能忽略任何一个!

说了这么多,还是走一遍流程吧!

1) 是否应该进行流失分析?开始时的实际关注点

让我们开始实际的。在开始分析之前,考虑努力和它的价值。你将不得不获取数据,处理数据,并以一种能被理解和有用的方式使数据呈现出来。尽管早期评估价值可能很难,但没有人希望他们的工作不被注意。要回答这个问题,您需要了解以下内容:

  • 学会了解你的公司所处的商业环境(大时代?探索新的选择?糟糕的时光?).想到什么先分析给定的情况,然后沟通。
  • 你的经理可能不知道什么是最好的,或者只有一个大概的想法。积极主动,协助选择项目。杰克并不知道约会的所有事情,帮助他专注于重要的事情。
  • 瞄准低垂的果实,能快速实现什么价值?当你不把所有时间都花在一件事情上时,你的工作可能会更有价值。杰克也有自己的生活,要努力让你的时间发挥最大价值。
  • 复杂性很重要。如果分析太难,就需要太多时间。开始之前,考虑并讨论结果的价值。

何时进行客户流失分析?

我们进行流失分析,以估计人们离开的原因,并预测哪些人可能会离开,所有这些都是为了防止这种情况发生。什么时候这种分析是优先考虑的?按照正确的顺序查看一些触发事件或进行流失分析的原因:

  1. 你的公司从未分析过客户流失,最近的数据可以用来进行良好的分析 - >你有一些日期,但还没有反映出来。
  2. 过去曾做过分析,但客户获得量下降或离职率上升->没有计划日期或取消了太多日期。
  3. 过去做过分析,但我们有改进的数据,或者过去的见解已经过时->女士们,对 X 博士说‘你好…

没错,这意味着如果你过去做过客户流失分析,当没有好的理由来改进或扩展之前的分析时,你就不应该在客户流失上花费时间!..更有可能是收购或协助现有业务。

关于 1,数据对于一个好的分析意味着什么?它是指对满足任何分析的基本要求的数据进行的分析。

  1. 我们有足够的样本进行分析吗?
    考虑你今年预期的(客户)人口,我们假设一千人。然后你要有足够的样本。我敢说,至少有一百个这样的数据。
  2. 样本是否代表真实人群?
    同样重要且相关的是,你的样本反映了你要研究的人群的相似属性。花时间去了解你感兴趣的人。
  3. 我们是否收集了有助于回答问题的数据?
    不是所有重要的东西都能被测量,也不是所有被测量的东西都重要。最喜欢的颜色作为一个变量可能对人们是否离开没有太大影响。然而,年龄与人生阶段有关,在这个阶段,我们会改变自己的观点和偏好,对产品也是如此。
  4. 数据收集是否正确?
    每一个数据条目都是在某个时间、地点、通过某个上下文内的方法收集的。这些元素中有什么改变了(很多)吗?问问你自己:在收集这些数据的过程中,发生了什么变化?请注意,当您分析数据时,您的目标是从噪声中提取有用的信号。把它看作一台收音机,你需要调到正确的频率来听音乐。当采集条件改变时,就像增加了噪声,这意味着如果不是不可能的话,也将更难获得想要的信号。

我得到了所有这些混合信号,她是什么意思?!—杰克在夜总会

2)如何进行流失分析?理论焦点塑造思想

第一步:定义问题

我们要做分析了,万岁!那么,我们该如何着手呢?首先,我们看问题陈述,作为科学过程的第一步。将这一点与我们项目的商业价值结合起来——这是项目选择过程中的一个要求——您实际上已经为自己的成功做好了准备。

因此,这个项目的商业价值是什么?嗯,客户流失是指客户离开,这意味着收入减少。然而,客户总是会离开,这是正常的,所以流失本身是一个现实,而不是一个问题。然而,如果它太大,就会成为一个问题。从这个意义上说,流失分析的价值在于防止损失太多收入。

什么叫过分?如果这是你的第一次流失分析,那么我们可以说,当它与收购率相匹配,或者高于收购率时,流失率肯定过高。如果这是一个持续的分析,或者如果你的企业的目标是将其流失 KPI 设置为不超过 10%,那么就这样做。关键是你需要以一种可衡量的方式定义你的问题,例如:

问题陈述示例:
“我们在【时间段】内的平均流失率..
..大于或等于保留率"
或"..高于我们 10%的目标”

在下面的部分中,我们将处理理论步骤,然后应用这些步骤。

第二步: 理解问题

要知道如何解决这个问题,你需要了解问题的本质,尽管初看起来客户流失率似乎是一个简单的指标,但它可以针对每个企业进行独特的定义。因此,定义客户流失是一个可以单独填充一篇文章的主题。虽然我不会在这里深究,但请知道大致有两种类型的流失:契约性和非契约性。不同的是,契约式流失是由契约来固定的。客户通过明确不续订合同来终止服务。对于非契约性流失,事件不会被明确观察到。这意味着这两种类型都有自己的问题要解决。

  • 合同流失是一个分类问题
    →从返回变为不返回→日期继续
  • 非合同性流失是一个异常检测问题
    →行为变化→日期异常

由于定义非合同流失的复杂性,大多数执行流失分析的分析师将只研究合同流失。如果你确实想阅读关于后者的分析,请点击从这篇文章中了解更多。

接下来,要明白客户流失是决策过程的结果,是所有对我们重要的因素汇集在一起的过程。我们可以将这些元素排列成一个模型。有了模型,我们可以展示和复制这个过程。

第三步:创建心智模型

我们已经定义并理解了这个问题,现在我们考虑与之相关的元素。什么与客户流失有关?哪些影响它?头脑风暴这些项目对不同的人意味着什么,并写下来。

我们从一般的开始,比如人们想要什么和你能提供什么?然后想象一个合适的分数作为结果。对于电信行业,可能如下:

按作者分类的图片|不同客户与电信产品的对比,结果是适合

或者如果我们用约会来类比:

按作者分类的图片|不同的日期与 Jack 的个人资料(个性、体格、知识)的对比,结果为符合

然后,我们可以简单地将物品与人进行对比,以获得分数:

图片作者|市场中的每个人都有自己独特的产品偏好组合

你注意到我是如何将不同的产品项目作为变量分类到颜色组中的吗?杰克正在寻找一个有个性、有知识、体格对他有吸引力的人。大多数人都在寻找相同的东西,所以我们的分类足够广泛,可以用于更广泛的人群。

我们可以使用这些类别来创建一个简单的心理模型,作为一个线性方程,其中每个人指定一个数字来表示他们认为个性、知识和体格有多重要,乘以杰克的档案。我们进行计算,然后将其相加,得到一个合适的分数:

契合度得分= (Pers * Pers。W) +(知道知道。W) + (Phys * Phys.W)
Pers =性格,Know =知识,Phys =体格,w =体重*

如果我们现在通过这个模型输入大量数据,我们就可以评估杰克和他的约会对象之间的契合度。但是这是一个好的模式吗..?分数对他有用吗?我现在知道杰克在找谁了吗?不要!约会是微妙的,这太笼统而没有用。抱歉杰克。尽管我们的目标是实用,但我们如何才能制作出一个我们都能理解和使用的性能良好的模型呢?

第四步:理解(变量之间的)关系

首先,我们需要看看我们的变量以及它们与客户流失的关系。如果变量 X 发生变化,对 Y 有什么影响?有直接的因果关系,还是更像是关联?我们正在进入假说发展的领域,这对创造一个好的心智模型是有用的。

然而,我们需要理解每一件事情是如何相互联系的吗?再想想实际。我们只需要知道事物或多或少是如何相互联系的。因此,我们不需要进入测试或获得深刻的知识。例如,如果你喜欢某人,你只是喜欢某人。你的感受与你和那个人的关系密切。就这么简单。

别想多了杰克!你知道这是怎么回事。打一针,然后过去!

为了更好地解释这是如何工作的,从现在开始我将使用数据和编码。别担心。我尽可能简单,让每个人都明白。人们喜欢你的经理,其他同事,也许还有你的下一个约会对象!

3)进行第一次分析:工作的技术重点

我将使用一个常用的客户流失数据集,电信客户流失数据集。与分析师获得的任何数据一样,我们首先要问:

第一步:我们有什么数据? 电信客户流失 数据集 是关于一家提供家庭电话和互联网订阅的虚拟电信公司。该数据涵盖了第三季度加州的 7043 名客户,包含 21 个不同的变量,包括流失标签。避免这里的第一个错误,阅读变量定义。如果你没有你正在看的东西的定义,去获取它们。接下来,检查数据。

为了简洁明了,我将输出和定义放在一起:

# Getting necessary packages.
import pandas as pd
import numpy as np# Getting the data.
file_handler = open("Telco Churn Dataset.csv", "r")
data = pd.read_csv(file_handler)
file_handler.close()# Having a first look at the data.
data.info()

电信数据—如果您收到“502 错误网关”错误,请刷新:)

好的,所有的栏目包括 7043 个条目。因此,没有空条目。我们有 18 个包含文本(对象)数据的列和三个数字(int 和 float)列。

接下来,我们检查格式。

# Checking the first 5 entries.
data.head()

电信公司优先数据条目—如果您收到“502 错误网关”错误,请刷新:)

我们检查了我们的数据,注意到一些不一致的地方需要修正。
要解决的问题有:
客户 ID、任期和性别→姓名需要像其他人一样大写
总费用→以文本形式存储的货币数字
高级公民→是和否作为 1 和 0,使用文本进行业务解释

# Proper capitalization of variable names
data.rename(columns={'customerID':'CustomerID', 'gender':'Gender', 'tenure':'Tenure'}, inplace=True)# Change the variable format, set any errors to NaN (Not a Number).
data['TotalCharges'] = pd.to_numeric(data['TotalCharges'], errors='coerce', downcast='integer')# Drop missing NaN values
data.dropna(inplace=True)# Changing 1 and 0 to Yes and No
data['SeniorCitizen'].replace({0:'No',1:'Yes'}, inplace=True)

由于更正了格式,我们在 TotalCharges 中发现了 11 个缺失值,并删除了这些条目。原因是我们开始注重实际:努力与价值。为了获得完整的数据,丢失 11 个条目是可以忽略的。

别担心细节,杰克,继续前进。

第二步:将数据与问题联系起来

我们现在是在向机器学习迈进吗?啊-啊。还是太早了!我们现在必须考虑我们的数据如何与问题联系起来。我们用一个简单的单变量分析来看我们关心的东西,客户流失。因为我们可能认为我们了解我们的问题,客户流失,但是我们的数据也和这些想法相似吗?在开始分析之前,我们会确认客户流失是否是一个问题。

# Plotting non-churners versus churners.
data['Churn'].value_counts().plot.bar(title='Count of Churn')# How big is the churn proportion in percentages?
print(data.Churn.value_counts(normalize=True))

作者图片|客户流失条形图

No     0.73463
Yes    0.26537
Name: Churn, dtype: float64

好的,那么到第三季度末,大约有四分之一的客户流失了。这个高吗?那么,在第 3 季度,有多少客户的租期为 3 个月或更短?

# Finding acquisition in Q3.
data.Acquisition = (data['Tenure'] <= 3)# Creating a churn to acquisition table to then plot the data.
Churn = data.Churn.value_counts().values
Acquisition = data.Acquisition.value_counts().values
index = ['No', 'Yes']
pd.DataFrame({'Churn':Churn, 'Acquisition':Acquisition}, index=index).plot.bar(rot=0)

按作者分类的图片|流失率与收购率的条形图

好吧,所以在同一时期,更多的客户是在流失,而不是被收购。所以,做这样的分析对支持业务是有意义的!

还要注意的是,如果我们要谈论平衡,搅拌器似乎在数据集中代表不足。大约 27%被搅动,而不是 50%。很高兴知道进一步的分析!因为即使减少搅动器对企业更好,如果我们现在使用机器学习会发生什么..它会最了解谁?没错,73%的非搅拌者!我们想了解搅拌者,以及是什么将他们与非搅拌者区分开来。因此,我们有了第一次学习:我们需要稍后解决不平衡,以便进行更深入的分析。

你看,杰克,如果你想更擅长约会,你只需要有更多的约会

这意味着杰克也将不得不遇到更多的拒绝,以便进一步学习。可怜的杰克。幸运的是,我们可以人工制造更多的搅拌器。我们的方法是对它们进行过采样(制造更多的)。当业务需要时,我们将在稍后阶段这样做,现在我们从我们的自然样本中了解更多:)。到目前为止最好的结论是:我们 27%的流失率大于收购率,并造成了业务问题。

第三步:创建心智模型(用数据)

还记得我们的心智模型是如何由许多不同的项目组成的吗?有些是关于市场和其中的客户,有些是关于产品和规格。我们集思广益,衍生出与客户流失相关的项目。比如上网时的网速..我们有客户选择有线电视还是更快的光纤互联网的数据。

因此,我们将理论与数据联系起来。不幸的是,我们永远不会有所有必要的数据来联系我们最初的想法,然而我们的头脑风暴确实给我们带来了更广阔的视角,如果我们立即跳到数据上,我们就会错过这个视角。非常重要。

现在转到我们的客户流失变量,为了大致了解它们之间的关系,我们进行双变量分析。也就是说,我们将每个变量与我们的流失变量进行比较。

# Counting unique values per column.
for column in data.columns:
    print(column + ':' + str(data[column].nunique()))
    print(data[column].unique())
    print('-'*40)

电信公司变量信息—如果您收到“502 错误网关”错误,请刷新:)

更仔细地观察我们的变量,根据上下文,我们可以看出一些列是关于与订阅互联网服务或电话服务相关的附加服务。明智的做法是将它们分组,类似于我们之前的分组。

# Grouping variables.
dependent   = ['Churn']
identifier  = ['CustomerID']
numerical   = ['Tenure', 'MonthlyCharges', 'TotalCharges']
categorical = [col for col in data.columns if col not in numerical + dependent + identifier]# Grouping add-on sub-groups.
internet_add_on = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies']
phone_add_on = ['MultipleLines']

关于数据,我们的大部分分类数据包含“是”或“否”,有时还包含关于客户是否拥有主要服务的第三个选项。

例如,有“无互联网服务”作为互联网附加变量的第三个选项。作为一个是或否问题的答案,这似乎有点奇怪。这里我们需要避免错误的两个原因是:

  1. 在直观比较选项时,我们希望比较两个变量。如果我们问杰克是否尝试过网上约会,我们不会添加第三个变量来使比较复杂化,例如,他是否有互联网?
  2. 一组在购买主要服务(互联网)时接受附加服务,另一组不购买主要服务。这些群体各不相同,我们希望避免从他们那里得出混淆的结论。

处理这个问题的正确方法是有一个关于主服务是否被购买的单独的列,并且将变量限制为两个选项。下一步是在可视化数据时注意组的大小。让我想象一下:

# importing visual packages.
import matplotlib.pyplot as plt
import seaborn as sns# Showing two countplots: Before and After
sns.countplot(data=data, x='OnlineSecurity', hue='Churn')
plt.show()sns.countplot(data=data[data['OnlineSecurity'] != 'No internet service'], x='OnlineSecurity', hue='Churn')
plt.show()

图片由作者提供|第 1 组:有互联网的人,他们是否参加了在线安全+第 2 组:没有互联网服务的人,他们是否参加了在线安全

作者图片|第一组:有互联网的人以及他们是否采取了网络安全措施

现在你可能会想,这不是很明显吗..?好吧,我已经看到这个简单的错误发生在相当多的笔记本和媒体文章中,以此来证明这一点。好了,是时候一起看看我们所有的分类变量了!

# We have 16 categorical variables so a 4 by 4 matrix is nice.
fig, axes = plt.subplots(nrows = 4,ncols = 4,figsize = (16, 16))# Selecting and plotting the data, inputting them into the matrix.
for i, item in enumerate(categorical):
    if item in internet_add_on: 
        df = data[data['InternetService'] != 'No']
    elif item in phone_add_on: 
        df = data[data['PhoneService'] != 'No']
    else: df = data if i < 4:
        ax = sns.countplot(data=df, x=item, hue='Churn',
        ax=axes[0, i]) elif i >=4 and i < 8:
        ax = sns.countplot(data=df, x=item, hue='Churn',
        ax=axes[1, i-4]) elif i >=8 and i < 12:
        ax = sns.countplot(data=df, x=item, hue='Churn',
        ax=axes[2, i-8]) elif i < 16:
        ax = sns.countplot(data=df, x=item, hue='Churn',
        ax=axes[3, i-12])# Limiting characters to 5 and setting the title on top.
    ax.set_title(item)
    ax.set_ylabel('')
    ax.set_xlabel('')
    ax.set_xticklabels(item.get_text()[:5] for item in
    ax.get_xticklabels())

作者图片|分类变量的计数图

这个视觉效果的好处在于,它显示了每组的大小,旁边是其中的搅拌器数量。因此,我们避免了因群体规模而产生的偏见。

我们在这里学到了一些东西!比他们的对手有更多变动的群体是老年人,没有伴侣的人,有光纤网络的人,没有网络安全的人;在线备份或高级技术支持,每月签约的客户,以及自动支付电费的客户。不错!

然而,这一切对约会意味着什么呢?我的意思是,杰克似乎有点缺乏数据。嗯,杰克最近有一个很棒的约会,一些给他的建议是,不是所有的浪漫想法都适用于所有的情况…

杰克最后一次约会!图片作者|原始照片作者(上)奥克塔视觉项目和下图(马頔·胡多罗日科夫)在 Unsplash

嗯…杰克,玩得很开心,这才是最重要的!正如你所看到的,杰克可能没有太多的“约会”,但他仍然在那里!当他回顾这顿饭时,他想知道:什么食物对约会的成功最有帮助?当他绘制食物等级与后续日期的关系时,我们可以以他为例来研究我们自己的数字数据:

# Histogram and scatterplot, 3 numerical variables, 2 by 3 matrix.
fig, axes = plt.subplots(nrows = 2, ncols = 3,figsize = (16, 8))# Selecting and plotting the data, inputting them into the matrix.
for i, item in enumerate(numerical + numerical):
    if i < 3:
        sns.histplot(data[numerical + dependent], x=item,
        hue='Churn', ax=axes[0, i])
    elif i >= 3 and i < 6:
        df = data[numerical + dependent]
        df.replace({'Yes':1, 'No':0}, inplace=True)
        df = df.groupby(item).Churn.mean().reset_index()
        sns.scatterplot(data = df, x=item, y='Churn', 
        ax=axes[1, i-3])

按作者分类的图像|第一行=按流失分类的直方图。第二行=每组平均流失散点图

好吧好吧好吧,我们这里有什么!似乎流失率随着任期的增加而降低,所以我们对相对较新的客户感兴趣!这也反映在较低的总费用中较高的流失率。此外,月度费用显示,大多数客户似乎每月支付 20 美元左右,当每月支付 70 美元或更多时,流失率相对较高。虽然我们的散点图可以更好,因为我们看到宁滨的结果确实改善了我们的分析,我们发现有用的结论。

第四步:理解关系(变量之间,用数据!)

关于关联性,我们的变量是如何相互作用的。为此,我们看一个相关图。相关图以及我们最终的机器学习模型将使用数字数据。为此,我们希望将我们的分类格式化为是或否问题,其中是为 1,否为 0。

杰克:所以。我们有一个很棒的约会…这让我想到,她是我的唯一吗?

# Changing our binominal data into numerical
numerical_format = {'No':0, 'No internet service':1, 'No phone service':0, 'Yes':1, False:0, True:1}
data.replace(numerical_format, inplace=True)# Creating a list of dummy variables for our remaining categoricals.
dummies = []
for column in categorical:
    if data[column].dtype == 'O':
        if column not in dummies:
            dummies.append(column)# Generating the dummy variables
data = pd.get_dummies(data = data, columns = dummies, drop_first=True)# Fiber optic and DSL stayed but I'm more interested in no internet.
data['InternetServiceNone'] = ((data['InternetService_DSL'] == 0) & (data['InternetService_Fiber optic'] == 0)).astype('int')
data.drop(columns='InternetService_DSL', axis=1, inplace=True)# Adjusting the long names.
data.rename(columns={'Gender_Male':'Male', 'InternetService_Fiber optic':'InternetFiberOptic', 'Contract_One year':'ContractOneYear',
'Contract_Two year':'ContractTwoYear', 'PaymentMethod_Credit card (automatic)':'PmCreditCard','PaymentMethod_Electronic check':'PmElectronicCheck', 'PaymentMethod_Mailed check':'PmMailedCheck'}, inplace=True)# Create the correlation matrix, rounding to one decimal
corr = data.corr().round(1)# Generate a mask for the upper triangle; True = do NOT show
mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True# Setup the correlation matrix as a heatmap with diverging colors
f, ax = plt.subplots(figsize=(11, 9))
cmap = sns.diverging_palette(220, 10, as_cmap=True)# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(corr, mask=mask, cmap=cmap, annot=True, vmax=1, vmin=-1, center=0, square=True, linewidths=.5)

按作者分类的图像|数据集中所有变量的相关矩阵

我们又发现了有趣的东西!光纤与月费高度正相关。或许纤维价格过高?因为我们看到这个团队中有很多人流失!当我们看到这个结论与没有互联网有很强的负相关性时,我们会发现更多的支持。

太好了,现在我们对数据有了一个大致的概念。我们现在继续分析吗?没有。我们只触及了表面,但已经学到了很多。

这对现在来说已经足够了。准备好您的报告,并与组织分享您的经验!人们可能会提出有趣的评论,如确认之前的预感,怀疑数据的正确性以及其他重要的事情,以便尽早沟通。

报告写完了吗?不要忘记传达接下来的步骤。从而帮助你的经理做出是否继续分析的实际决定。如果实际需要深入研究,我们将进一步将其与以下理论和技术项目相结合:

  1. 用机器学习解决班级失衡
  2. 利用机器学习细分客户
  3. 用机器学习预测未来的客户流失

杰克:我想我现在明白了,昨天的约会非常成功!我现在就打电话给她!

华纳:不,不,不!耐心点,杰克。她需要一些时间来消化。

感谢阅读,请在评论中告诉我你的想法!欢迎在 LinkedIn 上与我联系。还想知道更多吗?你准备好下一步了吗?

(工作正在进行中,欢迎提出想法:)点击此处阅读下一篇文章,该文章将讨论如何通过将机器学习应用于下一次流失分析来获得可操作的见解。

公海利他主义案例及其他有趣的故事

原文:https://towardsdatascience.com/a-case-for-altruism-on-the-high-seas-and-other-interesting-stories-970a04444db2?source=collection_archive---------33-----------------------

从 Kaggle 十年前的泰坦尼克号数据集得到的新推论

作者图片

在我与泰坦尼克号数据集讨论的过程中,一些独特的小插曲被抛了出来。其中一些在过去有很好的记录,一些没有。几个例子:

  • 如果你坐二等舱或三等舱旅行,你会觉得更安全吗?与因好莱坞电影而出名的流行观点相反,如果你乘坐三等舱而不是二等舱,成年男性在泰坦尼克号上幸存的几率会增加一倍
  • “名字里有什么?我们称之为玫瑰的东西,不管叫什么名字,闻起来还是一样香”——第二幕,第二场。不幸的是,泰坦尼克号的数据似乎与茱丽叶的说法大相径庭,因为与长名字的人相比,短名字的人在泰坦尼克号上的死亡率极高
  • 公海上利他主义的一个例子——那天晚上达尔文被证明是错误的,但是数据是否提到了其他没有记录在案的利他主义行为?3 个独立的证据出现在更近的观察中
  • 哎呀,泰坦尼克号数据集教程博客上的勘误表— 一个原始错误,几个副本
  • 泰坦尼克号上的女性可能要多付一点— ,但是男性要多付很多
  • 相关性不是因果关系— “群体生存”结论的谬误
  • Titanic 数据集上最大的生存指标是什么— 不,它不是数据集中列出的 11 列中的任何一列
  • 填空— 在填补缺失的年龄时,是否有关于女性儿童的重要线索被忽略了?
  • 不管领导怎么说,单干并不一定意味着你生存的机会更低。如果你是女性,为了在泰坦尼克号上生存下来,你会想单飞。在探究原因后,这些数据讲述了一个令人心碎的故事,涉及 100 多年前那个灾难性的夜晚上演的终极牺牲行为……

卡格尔主持泰坦尼克号比赛已经快十年了。对于任何有抱负的数据科学家来说,这就像众所周知的“成年礼”。你可以看到当今 Kaggle 的一些大师是世界上最好的数据科学家之一,他们在过去的某个时候在这个数据集上留下了不可磨灭的印记。这是一个简单得可笑的小数据集,但在数据科学和机器学习的几乎所有方面都提供了令人惊讶的好练习——从数据探索/可视化到猜测缺失值、特征工程,再到测试许多 ML 模型。

比赛的细节可能已经众所周知,我用两到三句话来总结——它涉及预测泰坦尼克号上的乘客是否能够生还..给出一组特征,如他们的年龄、性别、旅行等级、上船港口等。有抱负的数据科学家应该让他的模型从训练数据集(包含一个关于乘客是否幸存的附加列)中“学习”,并将这些“学习”应用于测试数据集,并预测测试数据集中的哪些乘客幸存。

虽然许多年过去了,但数据集中仍然隐藏着数量惊人的信息。不过,经过一点哄骗,它非常愿意说出自己的秘密。因此,我们没有费太多周折,直接进入了我用 Python 对这个迷人的数据集进行讨论的文字记录——我学习这种语言就是为了和它交流。我们将仅使用 Kaggle 数据集来得出我们的结论,不会参考任何外部数据源。所以这个分析只能从那个角度来看,可能是也可能不是真实事件的反映。

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plttest_data = pd.read_csv (‘/kaggle/input/titanic/test.csv’)
train_data = pd.read_csv(“/kaggle/input/titanic/train.csv”)*##These survival rates will be used as a reference*
print(round(train_data [['Pclass','Survived']].groupby(['Pclass']).mean()*100,1))print(round(train_data [['Sex', 'Pclass','Survived']].groupby(['Pclass', 'Sex']).mean()*100,1))

基本的观察结果是众所周知的,因此可以用几句简短的话来概括。乘客的性别和他们乘坐的舱位(Pclass)似乎与存活率有着最高的相关性。年龄似乎是一个因素。其他因素,如港口着手似乎发挥了很小的作用。上述数字似乎也符合普遍预期。

我们从紫罗兰图开始分析。

sns.violinplot(x=’Pclass’, y=’Age’, hue=’Survived’, split=True, data=train_data, palette={0: “r”, 1: “g”});

我们马上看到一些令人困惑的事情需要调查。Pclass 2 和 3 在 20-35 岁年龄范围附近有一个非常明显的到期峰值。然而,Pclass 1 的情况并非如此。除了 50 岁左右的人之外,PClass 1 在所有年龄段都有更多的幸存者。60 岁以后,寿命会急剧增加。这在 Pclass 2 或 3 中没有那么尖锐。这是一个奇怪的现象。让我们调查一下。

**print**('Pclass 1 survivors above Age 60:', round(len(train_data[*(train_data['Pclass']==1) & (train_data['Age']>59) & (train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==1) & (train_data['Age']>59)])*100,1), '%')**print**('Pclass 2 survivors above Age 60:', round(len(train_data[*(train_data['Pclass']==2) & (train_data['Age']>59) & (train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==2) & (train_data['Age']>59)])*100,1), '%')**print**('Pclass 3 survivors above Age 60:', round(len(train_data[*(train_data['Pclass']==3) & (train_data['Age']>59) & (train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==3) & (train_data['Age']>59)])*100,1), '%')**print**('Pclass1 survivors between 20-30 Age:',round(len(train_data[*(train_data['Pclass']==1) & (train_data['Age']>19) & (train_data['Age']<31) & (train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==1) & (train_data['Age']>19) & (train_data['Age']<31)])*100,1),'%')**print**('Pclass2 survivors between 20-30 Age:',round(len(train_data[*(train_data['Pclass']==2) & (train_data['Age']>19) & (train_data['Age']<31) &(train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==2)&(train_data['Age']>19) &(train_data['Age']<31)])*100,1),'%')**print**('Pclass3 survivors between 20-30 Age:',round(len(train_data[*(train_data['Pclass']==3) & (train_data['Age']>19) & (train_data['Age']<31) &(train_data['Survived']==True)*])/len(train_data[(train_data['Pclass']==3) & (train_data['Age']>19) &(train_data['Age']<31)])*100,1),'%')

事实上,在 Pclass=1 的情况下,如果一个人的年龄在 20-30 岁之间,那么他的存活几率是 60 岁的 2.5 倍。随着阶级的变化,我们可以看到 2 个年龄组之间的生存差距是如何缩小的。这怎么解释呢?这是一种利他主义行为吗——让年轻一代活下去?为什么这仅限于第一类?是不是只是数据的一个怪癖,意义不大?对数据的快速分析表明,Pclass 2 和 Pclass 3 的老年乘客数量在统计上不显著。任何幸存者都有可能扭曲百分比。但是,Pclass1 有 17 人年龄超过 60 岁,这不是一个微不足道的数字。

一种可能是,在第一类人群中,老年群体中男性较多,中年群体中女性较多..这就是差距的原因。一系列快速命令显示,与中年组 19 个中的 9 个相比,pclass 1 中 14 个中只有 2 个大于 60 的男性存活。因此,即使在考虑了所有参数后,我们仍然看到 14%的存活率与接近 50%的存活率之间的差异,这是一个谜。这并不是说中年人欺负老年人。事实上,除了不幸的最后几分钟,大部分疏散都是有序的。大多数退出的人都是身体健康的中年男性..这就是为什么那天晚上我谈到达尔文被证明是错误的,作为利他主义的第一个行为。但就头等舱乘客而言,这一理论似乎有些扭曲。看起来确实是一些年长的雄性主动为年轻的雄性让路..这可能是泰坦尼克号上的第二次利他行为吗?数据很少,但并非完全无关紧要,它确实指向那个方向。

当我们进一步将“性别”列添加到过滤器中时,另一个惊人的数据出现了。我们看到中年组(20-30 岁)的 33 名 Pclass 2 男性无一存活。正如我们之前看到的,Pclass2 男性乘客的存活率为 16%,因此这很奇怪。事实上,很奇怪的是,我扩大了年龄范围,发现 20-60 岁年龄组的 72 名男性中只有 4 人幸存。与 Pclass2 雄性的 16%的存活率相比,这只是 5%。这可能意味着两种情况之一:要么是 p 2 班比正常情况下有更多的孩子存活下来,要么是 p 2 班中有超过%的男孩存活下来。这意味着,与第三组相比,第二组的成年雄性实际上存活的机会更少,这有点颠覆了流行的理论。让我们检查一下…

令人难以置信的迷人,这是一个奇迹,至今没有记录。直截了当地说,如果你是一名成年男性,如果你在泰坦尼克号上订了三等舱而不是二等舱,你有两倍的生存机会!这确实颠覆了流行的理论..到目前为止,我们已经在泰坦尼克号上发现了三种利他行为。第一个是众所周知的。第二个是由于缺乏足够的数据,不是很有结论性,但在统计上不是无关紧要的。第三个让我大吃一惊。一大块 Pclass 2 男性自愿放弃了他们的生命,以便更多的女性和儿童(来自所有阶层)生存下来。还有表演吗?让我们看看。

但在此之前,让我们用 facetgrid 图来分析 apollowed 列。

fg = sns.FacetGrid(train_data, row='Embarked', aspect=2)
fg.map(sns.pointplot, 'Pclass', 'Survived', 'Sex')
fg.add_legend()

你有没有注意到船上的港口发生了一些奇怪的事情?就性而言,那些登上 C 港的乘客已经完全颠覆了生存几率。大部分雄性活下来,雌性断气!这是错误的信息&可以通过查询收集按性别分组的 C 港登船幸存者的年龄百分比来快速验证。很明显,中间一排的雄性&雌性的颜色混淆了。如果您的控制台警告被抑制,您甚至可能不会注意到它..幸运的是,警告是明确的。请使用“订单”参数,否则您可能会得到不正确的订单

fg = sns.FacetGrid(train_data, row='Embarked', aspect=2)
fg.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', hue_order=['female','male'], order=[1,2,3],palette={'female':"r",'male': "g"})
fg.add_legend()

更好!一个非常受欢迎的博客帖子(& 至少有十几个其他副本)做出了这个错误的观察,并继续讨论其他话题,好像这是完全正常的数据行为。我提出这一有限观点的唯一目的是要求年轻读者不要把数据探索阶段看得好像是一种需要在进入真正的 ML 建模之前快速完成的形式。请深入研究数据,尤其是如果您看到需要进一步调查的模式或 anamolies。

现在让我们取很小的偏差..只是为了好玩,我试着分析女性乘客的票价,看看她们是否与男性不同。这仅仅是一种干扰……就费用而言,列出(可能的)性别歧视的证据从未在我的议程上,但以下是我的观察:

看起来,平均来说,女性票的价格在第一组中高出 20%,在第二组中高出 8%,在第三组中高出 4%。我停止我的案子。也许男人讨价还价更多,以获得更好的交易?在任何情况下,票价显然更有利于男性,但他们得到的比他们最终讨价还价的更多。另外,我有时觉得我们认为这些绅士的骑士精神是理所当然的,并认为同样的事情在任何情况下都会发生,但在其他一些类似的悲剧中显然不是这样(在这些事件中,妇女和儿童的死亡率低于男性)。所以铁达尼号上的这些绅士肯定有些特别之处..也可能是剧组和领导团队促成了这一切。我们只能推测…

现在让我们把注意力转向一个流行的观点——2-4 人一组的人有很好的生存机会,5 人一组的人生存机会较低。

train_data[‘FamilyCount’]=train_data[‘Parch’]+train_data[‘SibSp’]+1sns.countplot(x=’FamilyCount’, hue=’Survived’, data=train_data)

看来独自旅行的人风险很高。从 2-4 组开始,虽然存活率很高,但从 5 组开始,存活率完全下降。几乎所有的 Kaggle 帖子都提出了这一观点,事实上一些非常高的领导者也在他们的分析中提出了这一观点。直觉上,这似乎是真的——如果你在一个较大的团队中旅行,你可能会更快地意识到即将发生的悲剧,因为这个团队的规模很大。另一方面,独自旅行的人可能在铺位上睡得很熟,可能很晚才得到消息。随着群体规模的增加,也许越来越难以召集所有人&向安全的地方冲去,所以也许随着群体规模的扩大,趋势变得消极,存活率下降。

我最初的猜测是,虽然这可能是真的,但我觉得这可能是一个相关的案例,而不是因果关系。换句话说,更大的群体并没有“导致”存活率下降。我感觉实际上发生的是,大群体在 3 级群体中更普遍,无论如何,根据旅行等级,他们生存的机会更低。换句话说,Pclass=3 是高死亡率的原因,而组大小> 4 只是与较高的死亡率相关。然而,我确实觉得独自一人会增加死亡率。让我们快速看看这一切是不是真的。

这确实是一种关联,而不是因果关系!正是 Pclass 在这里扮演了一个隐藏的角色。让我们重新绘制这张图,但是是在一个普通的平面上。

sns.countplot(x=’FamilyCount’,hue=’Survived’,data=train_data[(train_data.Pclass==3) & (train_data.FamilyCount >1)])

现在情况看起来很糟糕&与先前的图表完全相反。所以群体大小在生存中似乎没有太大的作用。是否单飞对 T1 有影响,但除此之外,团队的规模对 T2 似乎没什么影响。它可能会不必要地给出一些假阳性,并且人们必须考虑该信息是否足够相关以被馈送到最终的 ML 模型。

即使是“独奏”功能也值得讨论。一般来说,独自旅行的人死亡率较高。让我们检查一下这个。

单身女性逆势而为。但是你可能会说这不是一个公平的比较,因为女性无论如何都有更好的存活率。让我们做一个最后的图表,比较单独旅行者和非单独旅行者之间的 Pclass 3 女性死亡率。

plt.figure(figsize=(16, 6))
sns.countplot(x='FamilyCount',hue='Survived',data=train_data[(train_data.Sex=='female') & (train_data.Pclass==3)])

我们现在看到,在 Pclass 3(或任何一个 Pclass)中,单身女性的死亡率百分比比非单身女性的死亡率百分比低得多。所以基本上,如果你是一个独自旅行的女性,你比有团体或家庭的女性有更好的生存机会……请注意,这些数据在统计学上并不是无关紧要的。这种极其奇特的趋势的原因是什么?

在 3 班有 60 名女性单独旅行者,相比之下有 84 名非单独的女性旅行者,也许正是在这里我们看到了泰坦尼克号上第四次也是最伟大的利他行为。虽然这可能有其他原因,但在我看来,这种情况的发生是因为这里的妇女带着她们的丈夫和男性子女(> 12 岁)旅行,即使他们有机会这样做,也不可能想离开他们!!一些个人的骑士精神和利他主义行为在泰坦尼克号上得到了认可,但这也许是其中最伟大的,遗憾的是这一点至今没有被唤起。

我们还没有分析姓名和机票列。在检查变量之间的相关性时,我发现了一些不可思议的事情..那些名字很长的人显然有很高的生存机会!然后我意识到婚前姓是已婚女性名字的一部分。因此,如果我们按名字的长度排序,我们首先得到的几乎是所有的女性,然后是男性。因为不可否认的是,在所有阶层中,女性的死亡率明显高于男性,这就解释了这种相关性。许多其他内核也做出了这个有趣的观察。

另一个有趣的方面是,名字和票结合在一起让我们能够对人进行分组。他们将为我们提供有价值的线索,告诉我们谁在一起旅行……这就把我们带到了最后也是最重要的一点。我在绘制群体规模与存活率的关系时意识到了这一点。在分析数据时,我注意到虽然大群体和存活率之间没有联系,但群体内成员的存活率之间有明确的联系。这比性别、阶级和年龄更能决定一个人是否能存活下来,对于绝大多数人来说(不包括几乎总能存活下来的 1 级和 2 级女性)。更具体地说,在一个群体中,如果我们根据性别和年龄进行分组,我们可以很好地预测存活率。甚至可以通过建立母系关系(使用女性乘客的婚前姓氏)来加强分组。

泰坦尼克号数据集有很多缺失的年代。我们通过分析如何做到这一点从基础到高级的各种观点来结束这篇博客。最简单的方法是使用平均值或中值来填充所有缺失的年龄。平均年龄在 30 岁左右。然而,通过计算一组“相似乘客”的平均年龄,可以更准确地推算出失踪年龄。例如,可以选择计算 Pclass1 乘客的平均值,并将其分配给所有 Pclass1 失踪年龄..以及 Pclass2 和 Pclass3 的 likeways。

但我们可以在此基础上进一步即兴创作。因为(比方说)Pclass3 中的女性很可能与 Pclass 1 中的女性有不同的平均年龄,所以一个更好的方法(大多数 Kaggle 领导者采用的方法)是根据性别对人们进行分组,Pclass。如果你想进一步完善它,你可以使用“标题”和 Pclass,它会给出比 Sex 和 PClass 稍好的结果。“标题”可以很容易地从名称中提取出来。

人们可以通过建立关系和计算年龄的缺失值来进一步即兴创作。例如,假设您有一对夫妻旅行,丈夫的年龄丢失,而妻子的年龄给定。你可以用妻子年龄+某个数字(比如 5)来“猜测”丈夫的年龄。同样,你可以根据另一个兄弟姐妹或者父母的孩子的年龄来猜测一个失踪兄弟姐妹的年龄。

此外,人们甚至可以使用 ML 模型来预测年龄的缺失值,就像一些内核所做的那样。但是此时一个相关的问题出现了。年龄的数值对生存的贡献有多大?这对生存会有很大影响吗?答案是否定的。还有其他更重要的因素。然而,不管这个人是儿童、成人还是老年人,这个事实在生存中确实起着至关重要的作用。只要你能把缺失的时代归类为属于这个群体中的一个,那就很好!特别是,我们应该花更多的时间去担心这个人(缺少年龄)是不是一个孩子?这对生存机会有很大影响。我们如何做到这一点?对男孩来说很容易,因为他们的名字前面有“主人”的头衔。但是我们如何在失踪的年龄中识别一个女孩呢?没有专门针对女性儿童的称谓。所有年龄段的未婚女性都有“小姐”头衔。

因此,这里有一个简单的线索来识别这些人,并估算他们失踪的年龄。到目前为止,我还没有看到它被用在任何内核中(至少我经历过的那些)。我们可以通过检查 Parch 标志来识别这种情况。如果羊皮纸标志> 0,那么他们很可能是女孩。因此,在我们完成所有其他步骤后,最好添加这个重要的启发式规则…

train_data['Title'] = train_data.Name.str.extract(' ([A-Za-z]+)\.', expand=False) print ("Avg age of 'Miss' Title", round(train_data[train_data.Title=="Miss"]['Age'].mean()))print ("Avg age of 'Miss' Title travelling without Parents", round(train_data[(train_data.Title=="Miss") & (train_data.Parch==0)]['Age'].mean()))print ("Avg age of 'Miss' Title travelling with Parents", round(train_data[(train_data.Title=="Miss") & (train_data.Parch!=0)]['Age'].mean()), '\n')Avg age of ‘Miss’ Title 22
Avg age of ‘Miss’ Title travelling without Parents **28**
Avg age of ‘Miss’ Title travelling with Parents **12** !!

看到巨大的差异了吧!如果我们使用平均值而不考虑羊皮纸,我们将会犯可怕的错误。即使在这里,p 类之间也有巨大的差距,我们需要在输入最终值之前考虑到这一点。

《泰坦尼克号》数据集在问世十年后仍继续给人们带来惊喜和灵感。泰坦尼克号上的高分遵循一种波浪模式。每隔几年,就会有新的兴趣出现,下一代数据科学家会将最高分略微提高。几年前,Chris Deotte——目前 Kaggle 上讨论量排名第一,笔记本数量排名第二——以 84%的分数提高了赌注(让我们忽略 100%的分数,甚至是带有预调优超参数的内核)。我真的希望阅读这篇博客的新晋数据科学家有动力重新审视这个极其迷人的数据集,并将分数推得更高。我了解克里斯,如果发生这种情况,他会是第一个鼓掌的人!

万事如意!

请务必查看我的笔记本——用 Python 与泰坦尼克号数据集的迷人对话。https://www . ka ggle . com/allo hvk/charminating-conversations-with-the-titanic-dataset它有很多文档,即使是 ML 和 Python 的初学者也非常容易理解。

利用 Python 将多格式数据从 Excel 导入 MySQL 的案例研究

原文:https://towardsdatascience.com/a-case-study-for-transferring-multi-format-date-data-from-excel-into-mysql-through-python-f87d3c2a1859?source=collection_archive---------49-----------------------

实践教程

照片由Cookie PomUnsplash 拍摄

在数据分析中,日期格式和相关问题是令人头疼的问题。今天我想举一个例子来说明现实中的日期数据存在什么样的问题,如何用 Python 来处理,插入到 MySQL 数据库中。

案例分析

一家公司需要合并全球员工的信息,因为数据来自不同的国家,将生日输入到 Excel 中有不同的约定,并且也有错别字,所以当数据被合并时,生日看起来像:

Excel 中的表格(图片由作者提供)

生日 1 :原来的生日是什么样子(为了表示,加了一个类似'的字符,使其显示原来的格式)
生日 2 :我电脑上 Excel 里的生日是什么样子

如果我们总结一下这个案例,有如下表的情况:

可能的案例分析(图片由作者提供)

你可能已经知道了,数据左对齐默认是字符串,比如' 2010–13–09 ',数据右对齐默认是日期或者数字,比如' 9/13/2010 ',我不确定 20100913 的类型,就这样吧。

我把日期分为两种情况:

1.有一个大于 12 的数字(年份除外)

在这种情况下,有三种情况,分别是:
A. 字符串包含正斜杠'/'或破折号'-' ,例如:' 2010/09/13 ',' 2010–09–13 '
b .字符串不包含正斜杠'/'或破折号'-' ,而是包含其他类似逗号或 Punkt 的字符,例如:' 2010,09,13 ',' 2010.09。

2.如果没有大于 12 的数字(年份除外)

在这种情况下,还有三种情况,分别是:
A. 字符串中包含正斜杠'/'或破折号'-' ,例如:' 2010/09/02 ',' 2010–09–02 '
b .字符串中不包含正斜杠'/'或破折号'-' ,而是包含其他类似逗号或 Punkt 的字符,例如: '2010,09,02 ',' 2010

现在让我们将其导入 Python:

df = pd.read_excel('employee.xlsx')

看起来像是:

Python 中的数据(图片由作者提供)

Excel 中的日期在 python 中被转换成时间戳格式,现在右边是无日期数据,但不是时间戳格式。

表 employee_birthday 已经在 MySQL 中创建为:

让我们尝试将姓名和生日 2 的数据插入数据库。

当第一个错误发生时,它停止了。错误信息如下所示:

**DataError: 1292 (22007): Incorrect date value: '2010-13-09' for column 'birthday' at row 1**

用 Python 传输多格式数据的解决方案

因此,我们需要在插入之前更正所有不正确的日期值。

首先,让我们检查错误日期值的类型,以“2010–13–09”和“20100913”为例。结果是:

  • 对于数据类型为 str,使用 datetime.strptime 进行测试:

  • 对于 int,首先将其转换为 str,然后使用 datetime.strptime,我们来试试:

它也能工作。

现在进入正题:有这么多不同的格式,我们如何高效地处理它们?让我们将情况分为四种情况:

  1. 如果类型(生日)是熊猫。时间戳,返回生日
  2. 如果类型(生日)是一个字符串,则创建一个格式列表,并与 datetime.strptime 组合以返回正确的日期
  3. 如果类型是 int,首先将它转换成一个字符串,然后使用步骤 2 中的方法
  4. 其他例外

当数据类型为 str 时,格式列表中有一个窍门。

1.如果连接符是正斜杠或破折号,如果没有大于 12 的数字(年份除外),Excel 将以“yyyy-mm-d”或“mm/d/yyyy”的格式将数据传输到 date,如下所示:所有这些日期都将以熊猫的形式传输。时间戳

作者图片

2.如果连接符是正斜杠或破折号,如果有一个大于 12 的数字(年份除外),默认情况下,Excel 将以“yyyy-m-d”或“m/d/yyyy”的格式传输数据,除非:如果日期(大于 12)在默认月份中,则这些情况需要在“fmt”中列出,以用于正斜杠和破折号:

  • %Y-%d-%m,如“2010–13–09”
  • %d-%m -%Y,如“2010 年 13 月 9 日”
  • %d/%m%Y,如 2010 年 13 月 9 日
  • %Y/%d/%m,例如“2010/13/9”

作者图片

3.对于其他连接器,应列出所有可能的情况。它们是:' %Y.%m.%d ',' %Y.%d.%m ',' %m.%d.%Y ',' %d.%m.%Y ',' %Y,%m,%d ',' %Y,%d,%m ',' %m,%d,%Y ',' %m,%d,%Y ',' %d,%m,%Y '

作者图片

因此,填充列表应该类似于:
('%Y-%d-%m ',' %d-%m-%Y ',' %Y/%d/%m ',' %d/%m/%Y ',' %Y . %m . %d . %m ',' %m.%d.%Y ',' %d.%m.%Y ',' %Y,%m,%d . % m . %Y ',' %Y,% m,%d,%d ',' % Y,%d,% m,%d ',' % Y,%d,% d,% d '

完整的日期解析函数如下:

结果:

现在让我们再次尝试插入 MySQL。使用以下代码从表中查询数据:

结果如下图所示:

数据查询来自 MySql

备注:

在本文中,我将重点介绍如何使用 Python 自动更正多格式日期数据,以便将日期数据从 Excel 插入 MySQL。

最后,我想澄清另外两点:

  1. 对于 2010–9–2 和 2010–2–9 这样的数据:当从 Excel 导入到 python 时,系统已经将其转换为 yyyy-m-d 格式,如果要解析为 yyyy-d-m,这里解释的这种方法不起作用。
  2. 对于Excel中不正确的日期,如果你想在 Excel 中进行处理,也有一些点击供你参考。
  • 使用“替换”来转移除正斜杠('/')和破折号('-')以外的连接器
  • 使用函数=Date+right(),left() and mid(),将数字转换为日期,例如:对于 20100209,使用' =DATE(LEFT(cell,4),MID(cell,5,2),RIGHT(cell,2))'将其转换为' 2/9/2010 '

感谢阅读,并享受它。

狄拉克符号的临时指南

原文:https://towardsdatascience.com/a-casual-guide-to-dirac-notation-17961670ae7a?source=collection_archive---------18-----------------------

理解量子力学中的常用符号

来自 Pexels 的 Andrea Piacquadio 的照片

量子力学

"如果你没有被量子力学完全弄糊涂,你就不会理解它."—尼尔斯·玻尔

量子力学的概念已经存在了将近一百年。尽管如此,由于相互竞争的理论和概率性质,它仍然是一个非常难以学习和理解的课题(如玻尔的引用所示)。无论多么难以理解,仍然有一些深奥的理论是现代量子力学的支柱。量子力学的一个更有趣的应用,特别是我自己的研究,是在量子计算领域。这绝不是一篇解释叠加、纠缠或平行世界潜力的文章。尽管如此,我还是想介绍一下讨论这些话题时常用的符号——当你读到它们时,你会对它们所描述的系统有一个大致的了解。

Kets

让我们来看看三维空间中的传统向量…

三维空间中的基向量被定义为…

更一般地说,不管维数如何,基向量都表示为…

这意味着任何向量都可以分解成基本向量的线性组合…

类似地,使用狄拉克符号,ket 可以用来表示向量…

基向量也可以写成 kets…

这意味着我们可以使用 kets 将原始向量分解成基本向量的线性组合…

布拉斯

让我们考虑三维空间中的同一个向量…

转置和取复共轭产生…

转置将列向量转换为行向量,在这种情况下,复共轭只产生我们的原始值(因为我们假设它们是实数)。这被称为埃尔米特共轭,用匕首表示。

使用狄拉克符号,这可以写成一个 bra 向量…

胸罩扣

Bras 和 kets 也可以写在一起,表示内部产品。这个内积是点积的推广。考虑三维空间中的原始向量…

如果我们想用狄拉克符号来表示这个向量和它的厄米积之间的点积,我们可以把 bra 和 ket 组合成…

结论

量子力学既有趣又复杂。这个领域的重要性不能低估,尤其是量子计算机即将问世。理解这些研究领域的常用符号是发展对基本理论理解的第一步。如果你有兴趣了解更多关于量子力学的知识,我推荐这本书:

严肃的量子力学

关于在 NumPy 中生成随机数的备忘单

原文:https://towardsdatascience.com/a-cheat-sheet-on-generating-random-numbers-in-numpy-5fe95ec2286?source=collection_archive---------19-----------------------

澳门图片社Unsplash 上拍摄的照片

查看 NumPy 中最常用的生成随机数的函数。

NumPy 是我们用于机器学习研究和其他科学计算工作的最基本的 Python 包之一。作为一个 C 实现库的包装器,NumPy 在其多维数组和矩阵数据结构上提供了大量强大的代数和转换操作。

除了这些数学运算之外,它还提供了各种功能来生成随机数,这些随机数通常用于科学计算的不同目的。本文回顾了我们可以用来在 NumPy 中生成随机数的常用函数。

请注意如果您想在阅读时跟随本文,可以在 GitHub 上找到所有相关代码。

首先,我们将通过运行import numpy as np首先导入 NumPy 模块,允许我们访问模块中所有相关的函数。

1\. rand(d0, d1, ..., dn)

这种方法生成给定形状的随机数。下面是一些常见的例子。注意在rand()函数中指定的数字对应于将要生成的数组的维数。一个特例是,当函数中没有指定数字时,会生成一个随机值。

带有 rand()的随机数

2.randn(d0,d1,…,dn)和 standard_normal([size])

这两种方法都用于从标准的正态分布中产生随机数,其曲线如下图所示。红色曲线显示的是平均值为 0、标准差为 1 的标准正态分布。

读取曲线显示的标准正态分布(来源:维基百科

这两种方法都是从分布中随机抽取数字来生成定义形状的数组。它们的用法大致相同,只是对于standard_normal()方法,我们需要使用一个tuple来设置形状大小。下面是一些常见的例子。

带有 randn()和 standard_normal()的随机数

需要注意的一点是,因为我们知道这些方法是从标准正态分布中创建数字样本,因此我们可以验证这是否是下图所示的情况。

用 randn()生成的随机数直方图

与这两种方法相关的,还有一种方法叫做normal([loc, scale, size]),利用这种方法我们可以从locscale参数指定的正态分布中生成随机数。

3\. randint(低[,高,尺寸,数据类型])

该方法生成离散均匀分布的从low(含)到high(不含)size定义形状的随机整数。可选地,我们也可以将dtype设置为int64int或其他,默认值为np.int

需要注意的一点是,当我们不设置high参数时,数字会在[0,low的范围内生成。

带有 randint()的随机数

4.random_sample([尺寸])、random([尺寸])、ranf([尺寸])、sample([尺寸])

所有这些函数都是为了在[0.0,1,0]范围内产生由size定义的形状的随机浮点数,这是一个连续的均匀分布。以random_sample()为例,相关用例如下所示。

需要注意的一点是,由于这些随机数是从[0.0,1.0]的连续均匀分布中抽取的,因此这些数的平均值在 0.5 左右,是 0.0 和 1.0 之和的一半。

带有 random_sample()的随机数

与这四种方法相关的,还有一种方法叫做uniform([low, high, size]),利用这种方法我们可以从lowhigh参数指定的半开均匀分布中产生随机数。

5.choice (a[,尺寸,替换,p])

该方法从参数a指定的给定一维数组中生成一个随机样本。然而,如果a被设置为一个 int,这个方法将会像a是从np.arange(a)生成的ndarray一样运行。使用这种方法的一些例子如下所示。

size参数指定返回的ndarray的形状,而p参数是一个浮点数列表,表示a中的元素被绘制的概率。需要注意的是,如果您设置了p参数,那么概率值的总和必须是 1.0。

带选择的随机数()

6.shuffle (x)和permutation (x)

这两种方法都用于随机排列序列。它们之间的主要区别在于,shuffle()方法就地修改序列并返回None,而 permutation()方法在修改后生成一个相同形状的新ndarray。下面我们来看一些例子。

需要注意的一点是,当我们置换一个多维数组时,它只在第一个轴上工作,如最后两个例子所示。换句话说,多维数组中子数组的内容保持不变。

具有洗牌()和排列()的随机数

外卖食品

本文回顾了在 NumPy 中生成随机数的常用方法,NumPy 是执行数组和矩阵计算的最强大的包之一。还有更多可以在它的官网探索。同样,感兴趣的读者可以在 GitHub 上找到本文的相关代码。

在您离开之前,这里有一个关于这些方法的快速备忘单供您快速参考。

关于在 NumPy 中生成随机数的备忘单

仔细查看数据集列

原文:https://towardsdatascience.com/a-closer-look-at-dataset-columns-d6551b9d39e2?source=collection_archive---------32-----------------------

图片来源:“Via Design Pickle”——更多关于属性

查看数据集的列和其他相关的关键术语

介绍

R 研究人员和数据科学家处理数据集。数据集是原始材料。当我们将分析技术应用于这些原材料时,我们产生了总结、列表、估计和其他输出。

我之前解释过数据集由行和列组成。在工作过程中,我们有时也会将列称为维度或变量。

交换和互换这些术语(列、维度、变量等。)会导致混乱。本文试图通过展示我们有时如何以及为什么使用其他术语(如维度或变量)而不是列来澄清这种混乱。

数据

本文用一个称为 auto dataset 的数据集演示了它的关键术语和短语,该数据集由 Stata Corporation 提供,该公司是流行的 Stata 统计编程软件的制造商。图 1 显示了这个数据集的专家。

图 1:流行的 Stata 自动数据集的摘录。

假设您有一个包含 Pandas 的 Python 配置,您可以使用以下三行代码生成类似的输出:

import pandas as pddf = pd.read_stata('http://www.stata-press.com/data/r15/auto2.dta')df[['make','price','mpg','weight','foreign']].head(n=8)

维度是字面意义上的,而不是比喻意义上的

为了开始理解为什么我们有时互换使用术语“维度”来指代数据集的列,请看图 2。

图 2:1978 年汽车数据散点图。

图 2 是每加仑英里数(mpg,沿垂直 y 轴)和重量(重量,沿水平 x 轴)的散点图。散点图是一种以图形形式显示两个变量之间关系的方法。

当可视化为图表时,该图或任何散点图展示了 y 和 x 变量如何对应于图表的 y 和 x 维度。这就是为什么研究人员和数据科学家有时会将数据集的互换为维度

为了进一步说明,有时我们想要添加第三、第四或第 k 个维度。图 3 显示了变量英里每加仑(mpg,沿垂直 y 轴)和重量(重量,沿水平 x 轴)和长度(长度,沿另一个水平 z 轴)的散点图。

图 3:1978 年汽车数据的三维散点图。

这种可视化技术有助于说明这三个变量之间的关系。然而,在三维之外,就很难想象了。但是,在这种情况下,技术上有第四维。虚线代表第四维度。在这种情况下,蓝色代表外国品牌,黄色代表国内品牌。

为了进一步处理额外的维度,可以使用各种统计技术,这些技术可以导出一个总结这种多维(也称为多变量)关系的方程。总结通常以等式的形式表示。

这个方程式反过来解释了为什么与维度同义的,也与变量同义。

变量也是一种文字构造

看看这些等式,开始理解为什么我们有时互换使用术语变量来指代数据集的

这两个等式总结了图 2 和图 3 所示的关系。等式 1 表明,车辆重量每增加一磅,每加仑英里数将减少 0.0060 英里。

等式 1:汽车重量和每加仑英里数之间的估计线性关系。

再次回到上面的图形示例,这个方程可以在 y 和 x 维坐标上绘制。这样一条线看起来如图 4 所示。

图 4:图 1 的复制品,增加了由等式 1 绘制的线。

展示如何将这些列或维度之间的关系总结为数学方程,说明为什么我们有时也将数据集的称为变量。作为惯例,当处于方程形式时,习惯上将这些结构称为变量

* [## 加入我的介绍链接媒体-亚当罗斯纳尔逊

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

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

结论

本文讨论了为什么我们有时会互换地将数据集的称为维度变量。为此,本文还展示了散点图作为一种分析技术,可以帮助理解两个或更多变量之间的关系。

鸣谢:三维可视化灵感来自@ 迪潘坚(DJ)萨卡尔 多维数据有效可视化的艺术

感谢阅读

如果你喜欢我要说的话,可以在:adamrossnelson.medium.com找到更多。

感谢阅读。把你的想法和主意发给我。你可以写信只是为了说声嗨。如果你真的需要告诉我是怎么错的,我期待着尽快和你聊天。推特:@ adamrossnelson| LinkedIn:亚当·罗斯·纳尔逊 |脸书:亚当·罗斯·纳尔逊。*

透视报道的冠状病毒数量

原文:https://towardsdatascience.com/a-closer-look-at-the-reported-coronavirus-numbers-in-perspectives-abd4791f5e84?source=collection_archive---------47-----------------------

根据国家规模分析病例数

免责声明: 迈向数据科学 是一份以研究数据科学和机器学习为主的媒体出版物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

在短短几个月的时间里,冠状病毒(新冠肺炎)已经蔓延到世界各地,导致了事实上的全球疫情。在许多国家和地区,确诊病例仍在成倍增长。随着每天报告的确诊病例数,我非常关注病毒如何影响人们的生活、市场和全球经济。他来自中国北京,对 2003 年非典爆发记忆犹新。然而,我惊讶地发现,西方有那么多人对新冠肺炎的严重性漠不关心:“这只是一场流感”,“它只影响老年人”,“媒体宣传”,“群体免疫”……这些来自普通公众的高度让我夜不能寐。

也许有些人对报道的病例数量不以为然,认为大多数感染病例远在世界的另一端。我同意,的确,看那些确诊病例数字是抽象的。在这里,我画了一些图,把这些数字放入透视图中。

注意事项:模型的好坏取决于数据的来源。所有确诊的新冠肺炎病例都是由约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)提供的,该中心汇编了来自世卫组织和世界各国政府的官方报告数字。毫无疑问,由于缺乏诊断测试、政府缺乏透明度以及人们因无知而未能接受测试,大多数国家都存在报告不足的情况。

以下所有数字均基于截至 2020 年 3 月 15 日的新冠肺炎确诊病例。

区域级累积案例

按累计确诊新冠肺炎病例排列的受影响最大的国家/地区

许多可视化(比如 this )只显示国家级的统计数据。从区域级别的图中,我们可以分离中国的不同省份和美国的不同州。湖北,曾经是新冠肺炎的中心,与中国几乎所有其他省份一样,确诊病例数量已经持平。伊朗、韩国、意大利和许多欧洲国家超过了中国第二大受灾省份广东。

拟合指数增长

接下来,让我们看看新冠肺炎在地区内传播的速度。我用指数函数拟合了累计确诊病例,y= exp(a+bx)。这里我用普通最小二乘法(OLS)来确定参数 ab ,斜率 b 对应的是指数曲线的陡度。

事实上,几乎没有什么会无限期地遵循指数增长。然而,传染病的初始爆发可以用指数函数来建模。对于不同的地区,我拟合了最初阶段累计确诊的新冠肺炎病例数,定义为至少 5 至 10 天有 50 例病例。根据指数函数对拟合的斜率( b )进行排序,我发现了一个惊人的列表,其中包括伊朗、芬兰、葡萄牙、意大利、韩国、丹麦、斯洛文尼亚和西班牙,这些国家的增长率在01/23左右高于湖北,其中许多国家现在正在经历指数增长(截至 3 月 15 日)。此外,美国的纽约州和华盛顿州在全球传播最快的地区中也分别排名第 15 和第 19 位。

发展最快的地区/国家。图例表示指数函数中的 b 和用于拟合增长曲线的日期周期。

另一方面,我们也可以发现新冠肺炎传播最慢的地区和国家。前 20 名几乎全在亚洲,其中许多是中国偏远的人口较少的省份,如宁夏、内蒙古和新疆。值得注意的是,自 2 月中旬以来,新加坡和日本出现了新冠肺炎病例,但传播速度要慢得多,这可能是因为早期有效地实施了社交距离。

传播最慢的地区/国家。

对人口进行标准化

正确看待感染人数的一个方法是根据该地区或国家的人口规模进行标准化。下面我列出了感染新冠肺炎病毒人口比例最高的 20 个地区/国家。圣马力诺,一个被意大利包围的飞地小国,人口密度在新冠肺炎排名第一。冰岛等其他人口较少的国家也名列前茅。

标准化到区域

了解感染人数的另一种方法是根据地区/国家的面积进行标准化,以得出地理上的病例密度。由于面积小,圣马力诺再次名列榜首。许多城市和城邦也名列前茅:澳门、新加坡和 DC 华盛顿。

使医院容量正常化

看待新冠肺炎病例数量的一个更有效的方法是量化该地区医院的负担。这可以通过对医院容量进行标准化来实现,医院容量是通过医院病床的估计数量来衡量的。

目前的新冠肺炎感染患者足以占据圣马力诺 72%的医院床位,而圣马力诺只有一家医院。负担非常重的其他国家包括冰岛、伊朗、义大利和卡达,新冠肺炎病患占用超过 10%的医院病床。请注意,这是假设最好的情况,即患者按比例分布在各个医院,这样他们就不会涌向同一家医院。

还应该考虑 ICU 的床位数和可用的机械通气机的数量,这些对于挽救那些症状严重的患者是必不可少的。根据美国医院协会的数据,ICD 的床位占美国所有医院床位的 5%。假设所有这些病人都需要入住 ICU,那么大约 10%的病床就变成了可怕的大约 200%的 ICU 容量。

基于截至 3 月 21 日确诊病例的最新医院负担

我能够使用来自的数据来估算美国各州的医院床位。如图所示,圣马力诺的确诊病例已经超过了医院的床位数。意大利的医院负担跃升至约 23%。美国的三个州,纽约州、华盛顿州和新泽西州也排在前 20 名,假设所有医院都需要住院治疗,则所有医院床位的 16%、12%和 4%可能被确诊的新冠肺炎病例占用。

代码:

https://github.com/wangz10/covid_19_analyses

A Cloud ML first: Google 的 AI 平台深度学习容器,搭配 NVIDIA Tensor Core A100 GPU

原文:https://towardsdatascience.com/a-cloud-ml-first-googles-ai-platform-deep-learning-container-with-nvidia-tensor-core-a100-gpu-53ab9d313d17?source=collection_archive---------28-----------------------

在本文中,我们提供了对谷歌人工智能平台和深度学习容器的介绍,然后探索 A100 GPU 的惊人性能。

授权给作者的图像

基于云的深度学习的关键一步;数据科学家第一次可以访问 NVIDIA A100 Tensor Core GPU 前所未有的加速。

在本文中,我们提供了对谷歌人工智能平台和深度学习容器的介绍,然后探索 A100 GPU 的惊人性能。

谷歌云人工智能平台

对于那些不熟悉人工智能平台的人来说,本质上它是谷歌云平台上的一套服务,专门用于在云中构建、部署和管理机器学习模型。

人工智能平台旨在使数据科学家和数据工程师简化他们的 ML 工作流程。我们经常在 AutoML (Google 的点击式 ML 引擎)中使用它,但除此之外,它还支持使用 Tensorflow 构建的高级模型的训练、预测和版本管理。

通过像 TPUs 和 tensor flow
Google Cloud这样的工具,利用谷歌在人工智能方面的专业知识,将我们的尖端人工智能技术注入到您的应用程序中

云人工智能平台服务

AI Platform 有一套服务,用于支持典型 ML 工作流中的活动。

谷歌云 AI 平台服务(图片来源谷歌云)

在本文中,我们将重点关注深度学习容器(这些属于上图中的管道部分)。虽然其他服务不在本文讨论范围内,但我们已经包括了对每个服务的简要描述以及一些链接,以防您想了解更多。

1。准备

我们通常首先在 大查询数据集 中准备(摄取、清理、特征工程)我们的数据,大查询数据集是 Google Clouds 超大规模数据仓库中的表集合。

Google 提供了一个 数据标注服务 用于标注训练数据
(通常我们用于图像、视频、音频和文本的分类)。

2。构建

我们已经提到过 AutoML ,训练模型的零代码平台。

我们使用 AI 平台笔记本 (托管 Jupyter 笔记本)来构建定制模型(通常是 Tensorflow 或 SkLearn)。

最后,我们使用 AI 平台训练 进行方便的模型训练。

3。验证

可解释 AI 是一套非常棒的工具,可以帮助您理解模型的输出,验证模型行为,识别模型中的偏差,并获得改进模型和训练数据的方法。这确实有助于消除模型调优等活动中的猜测。

AI 平台 Vizier 更进一步,提供黑盒优化服务,调整超参数,优化模型输出。

4。展开

无论您是使用无代码 AutoML 训练的模型,还是使用 AI 平台笔记本构建的高级 Tensorflow 模型,AI 平台都提供了许多服务来帮助部署模型和生成预测。

[AI 平台预测](http://AI Platform Prediction that manages the infrastructure needed to run your model and makes it available for online and batch prediction requests. You can also use AutoML Vision Edge to deploy your models at the edge and trigger real-time actions based on local data. TensorFlow Enterprise offers enterprise-grade support for your TensorFlow instance.) 管理运行您的模型所需的基础设施,并使其可用于在线和批量预测请求。

AutoML Vision Edge帮助部署 Edge 模型(在本地设备上运行,例如智能手机、物联网设备)并可以基于本地数据触发实时操作。

TensorFlow Enterprise为您的 tensor flow 实例提供企业级支持。****

5。ML 管道(ML 操作)

ML Ops 是部署健壮的、可重复的和可伸缩的 ML 管道来管理您的模型的实践。人工智能平台提供了许多服务来协助这些管道。

授权给作者的图像

[AI 平台管道](http://Continuous evaluation helps you monitor the performance of your models and provides continual feedback on how your models are performing over time.) 提供使用 Kubeflow 管道或 TensorFlow Extended (TFX)创建 ML 管道的支持。

[持续评估](http://Continuous evaluation helps you monitor the performance of your models and provides continual feedback on how your models are performing over time.) 帮助您监控您的模型的性能,并对您的模型在一段时间内的表现提供持续反馈。

深度学习虚拟机映像 支持轻松调配深度学习 ML 应用的云虚拟机。

最后, 深度学习容器 为深度学习环境提供预配置和优化的容器。

深度学习容器

授权给作者的图像

AI 平台深度学习容器为您提供性能优化的一致环境,帮助您快速原型化和实施工作流。深度学习容器映像预装了最新的机器学习数据科学框架、库和工具。
谷歌云

人们很容易低估启动和运行机器学习项目所需的时间。通常,这些项目需要您管理不断发展的软件堆栈的兼容性和复杂性,这可能会令人沮丧、耗时,并使您无法做您真正想做的事情:花费时间迭代和细化您的模型。

深度学习容器旨在加速这一过程。

所有深度学习容器都有一个预先配置的 Jupyter 环境,因此每个容器都可以直接作为原型空间使用。首先,确保你已经安装并配置了 gcloud 工具。然后,确定您想要使用的容器。所有容器都托管在 gcr.io/deeplearning-platform-release,下,可以使用以下命令列出:

**gcloud container images list --repository=”gcr.io/deeplearning-platform-release”**

每个容器都提供了一个与相应的深度学习虚拟机一致的 Python3 环境,包括选定的数据科学框架 conda,用于 GPU 映像的 NVIDIA 堆栈(CUDA,cuDNN,NCCL),以及许多其他支持包和工具。

创建 CPU Tensorflow 容器的示例

这真的很简单。以下命令将在分离模式下启动 TensorFlow 深度学习容器,将正在运行的 Jupyter 服务器绑定到本地机器上的端口 8080,并将容器中的/path/to/local/dir 挂载到/home。

**docker run -d -p 8080:8080 -v /path/to/local/dir:/home \
gcr.io/deeplearning-platform-release/tf-cpu.1–13**

然后,可以在 localhost:8080 访问正在运行的 JupyterLab 实例。确保在/home 中开发,因为当容器停止时,任何其他文件都将被删除。

如果你想使用支持 GPU 的容器,你需要一个 CUDA 10 兼容的 GPU,相关的驱动程序,并安装 nvidia-docker 。然后,您可以运行类似的命令。

**docker run --runtime=nvidia -d -p 8080:8080 -v /path/to/local/dir:/home \
gcr.io/deeplearning-platform-release/tf-gpu.1–13**

现在您只需使用这个容器开发您的模型。

NVIDIA A100 张量核心 GPU

所以,现在你已经定位于谷歌云人工智能平台及其深度学习容器,让我们先探索一下云;能够访问由 NVIDIA A100 Tensor Core GPU 驱动的深度学习容器。

授权给作者的图像

A100 GPU。加速我们时代最重要的工作。
英伟达

那么这在现实世界中到底意味着什么呢?

首先要注意的是,这条 GPU 线是专门针对深度学习和其他高计算人工智能应用而设计的。第二点要注意的是,与它的前辈相比,A100 提供了高达20 倍的性能,而代码变化为零。这是一个巨大的飞跃。

高性能计算吞吐量(图像来源 Nvidia)

A100 GPU 技术规格

A100 的数据表的亮点包括:

  • 40GB 的 GPU 内存
  • 1.6 TB/秒内存带宽
  • 深度学习的 312 万亿次浮点运算(前代的 20 倍)
  • 250W-450W 最大功耗
  • 结构稀疏性A100s 张量内核的架构支持高达 2 倍的“稀疏”模型(其参数集包含大量零的模型,非常适合 NLP 应用)性能增益。

如果其中一个功能不足以满足您的使用案例,不要担心,因为由于 NVIDIA 的一些聪明的 SDK 支持,这些功能将扩展到 1000 个 A100 GPUs。

对 A100 进行基准测试;训练伯特

BERT 代表来自变压器的双向编码器表示。最近由 Google 发布的 BERT 是一个自然语言处理(NLP) ML 模型。由于完全训练模型需要高计算量,BERT 经常用于基准测试。

A100 产生了一些惊人的结果:

性能基准训练 BERT(图片来源 Nvidia)

那么谷歌人工智能平台的深度学习容器中有哪些 A100 选项呢?

每台虚拟机高达 16 个 GPUs】

对于要求苛刻的工作负载,可以选择 a2-megagpu-16g 深度学习容器。使用16A100 GPU,这提供了惊人的640 GB GPU 内存,并在使用新的稀疏特性时,在单个虚拟机中提供高达 10 petaflops 的 FP16 或 10 petaflops 的 int8 的有效性能。哇哦。我们不得不把这些数字读两遍。

然后,我们必须加倍占用系统内存;惊人的 1.3 TB。并且不用担心访问它的任何瓶颈,内存总线支持高达9.6 TB/s。

足以消耗最苛刻的工作负载…

授权给作者的图像

当然,A100 驱动的虚拟机也有较小的配置,允许您匹配应用对 GPU 计算能力的需求。

后续步骤

1.阅读谷歌云 AI 平台发布说明

2.了解更多关于安科瑞斯数据,分析&人工智能

3.与作者连线

编码疗法

原文:https://towardsdatascience.com/a-coding-cure-for-our-current-coronavirus-culture-57d6df4527dd?source=collection_archive---------47-----------------------

现实世界中的 DS

对于我们目前的冠状病毒培养

Unsplash 上的融合医学动画拍摄的照片

是的,很严重。

是的,我们都应该认真对待它。

是的,当你无法走出去逃避它时,你很难从它身上分心,每个新闻节目都征用每个电台来谈论它。

谢谢你,冠状病毒,谢谢你让我们在别人的大型、恐怖、疫情主题的恐怖电影中成为临时演员,谢谢你让我们所有人都蹲在家里,不管什么房间现在都成了我们自己的私人密室。

这可能会令人沮丧…然而,也不一定如此。

如果你仔细想想,这也是一个巨大的机会。

你赢得了一些时间。

没有通勤。不要为了避开同事而在办公室里快速走动。没有没完没了的会议。不要重复去街角的咖啡店买咖啡(你知道你无论如何都需要减少咖啡因的摄入)。

在那里的某个地方,你可能每天花至少半个小时,如果你幸运的话,一个小时。

不管你是对编码感兴趣,还是对数据科学或 UX/UI 感兴趣,为什么不花时间投资自己,学习那些你一直向自己承诺要掌握的优秀编码技能呢?

我们现在被告知,我们可能会“生活在封锁中”至少一个月,所以也许是时候充分利用你的情况,学习一些真正有价值的编程语言,你可以在疫情爆发的另一边利用它们。

塔玛斯·考托瑙在 Unsplash 上拍摄的照片

所以,如果你一直在思考这个问题,这是博斯科博士为我们常见的冠状病毒文化开出的药方——每天在网上吃一片,早上给我打电话(如果你感觉很好,吃两片):

PYTHON

Python 不仅会一直流行下去,而且流行速度如此之快,很可能会成为未来几年的主流编程语言。

语言本身是逻辑的,代码是可读的,编程语法是简单的。它可以应用于非常广泛的情况,例如数据科学、数据可视化、游戏等等。

它可能是你今天需要了解的最重要的编程语言,并且有望成为未来编程语言的主导力量。

SQL

结构化查询语言(SQL)是一种编程语言,用于与数据库进行交互,并通过查询来分析和理解数据。

现在对它的需求非常大,因为许多公司都用它来运行查询,并对他们利用的数据进行分析。很可能你现在工作的公司正在使用它,你希望有一天为之工作的公司也在利用它。

无论是像谷歌和亚马逊这样的大公司,还是中等规模的公司,SQL 无处不在,帮助你快速了解它的课程也是如此。

JAVASCRIPT

JavaScript 是世界上最流行的编程语言之一,它是一种面向对象的编程语言,旨在简化 web 开发。

它允许你通过使网页上的元素具有交互性来赋予它们生命。你可以用它来创建菜单、动画、地图和视频播放器。

JavaScript 用于开发网页、移动应用程序、基于浏览器的游戏等。有太多的东西等着用 JavaScript 来创造,许多公司愿意付钱给你来完成它。

照片由拍摄狄龙在 Unsplash 上摇晃

你只需在谷歌上搜索一下,就能看到数百个令人生畏的课程链接,这些链接声称能够指导你学习代码,所以请允许我帮你缩小范围。

我一直很偏爱曾经和 总会Udemy、data camp的经历。请注意,这里没有有偿代言,只有我的个人经历。

我建议你开始回顾它们,并根据你想要学习的内容、事情如何与你自己的学习风格和工作日程同步,以及一旦冠状病毒文化最终消退,你可能希望用你新发现的编码知识实现什么,做出自己的决定。

我们都需要保持乐观。

我们会变得更好,现在我们可以利用这段时间来学习如何编码,这样我们都可以在我们所做的事情上做得更好。

然后我们都可以利用我们的新技能让世界变得更好。

梅和 RMSE 的普通人指南

原文:https://towardsdatascience.com/a-common-mans-guide-to-mae-and-rmse-d5efcd238221?source=collection_archive---------22-----------------------

用简单的话来理解——它们在现实世界中意味着什么,什么时候选择哪个?

图片由皮克斯拜的 Gerd Altmann 提供

一位商人,我的潜在客户,昨天当我向他展示我的预测模型时,他问我,“你认为这些预测模型会有多准确?”。我准备好回答这个问题了。“非常”,我颇有些自信地说道。“它具有极低的 MAE”。

对我天真的回答,他藏起笑容,看着我,就像一个老人看着一个还不了解人情世故的青少年一样,他又问了一遍。“我不太擅长理解高级金融和数学术语,你能以简单的方式给我解释一下吗?这样我就能明白,相信你的预测,我在这里冒了多大的风险?”。

常识不是那么普通,简单也不是那么容易获得。

于是我礼貌地要求再给一天时间,跟他告辞了。

错误造就人

我们在生活中非常清楚地知道,同样大的错误在不同的情况下会有不同的分量。当你和朋友参加一个非正式的聚餐时,迟到 10 分钟可能不是坏事,但当你妻子的父母请客时,这将是一个改变一生的灾难性事件。

大多数情况下,你只要说自己很守时,就可能逃脱惩罚。你基本上是在要求考虑你的平均表现。

对你来说,这就是平均误差或平均误差。

我们应该从我委托人的角度考虑这个问题。几个月前,他开了一家不太大的家庭餐馆。他的任务是预测每天的顾客流量,以便他能够计划从批发市场购买正确数量的原材料。作为一家新企业,他同样害怕由于一天结束时浪费了过多的食物而招致损失,以及因为他没有更多的食物来烹饪一天而不得不请顾客回去。

让我们以周为单位来想象一下。假设这些是每天的实际客户数量:

每日顾客流量

我创建模型,并预测类似这样的事情:

每日预测

然后,我计算模型犯下的一个或多个错误:

预测误差

总误差= 0。很容易看出这种逻辑的谬误。我在积极方向上的错误被那些在消极方向上的错误抵消了。

我说,错误就是错误。从数学上来说,这意味着取错误的绝对值。

平均绝对误差

我们刚刚理解了什么是 MAE(平均绝对误差)。

它说,平均来说,我会错误预测一天的客户数 6.285。我是否会预测更多或更少,通过了解 MAE 并不明显。我的客户可能每天浪费 6.285 人的食物,或者平均每天拒绝 6.285 名顾客。

为了便于理解,让我们假设我的模型只在正向出错,也就是说,我可能会错误地说,“今天会有 25 个客户”,而实际上可能只有 20 个。但绝不会出现我低估这个数字只有 15 的情况。这基本上意味着食物可能会被浪费掉,但所有的顾客都会得到款待。

一个是小偷,另一个是强盗

那么这是否意味着具有相同 MAE 的两种方法(模型)同样好(或坏)?

想象一下,我的一个竞争对手,我称之为 BloodyC Pvt. Ltd .,也试图向这位拥有餐馆的先生推销它的方法。我们的预测大概是这样的:

两个预测,相同的 MAE

我每天都犯小错误,而 BloodyC 在大多数日子里都很准确,但在某些日子里会犯更大的错误。哪个更好?

光看数字是无法得出答案的。这是关于商业,它的愿景,它的道德和它背后的人。所以我会让你们想象一个离现实不远的情况,在这个情况下,我的模型会更好。

(资料)科学从来都不是数字和逻辑。永远都是关于情感和生活的。

在许多国家、商店和家庭,当有多余的食物时,我们会尽量给那些比其他人更需要的人,或者喂宠物&流浪动物,如果这对它们无害的话。当然,每个人都有极限。因此,如果只剩下 2-3 个人的食物,很容易立即找到需要的人,但如果数量更多,大部分食物通常会被扔进垃圾箱。不是每个店主都和无家可归者收容所或类似的服务机构有联系。

我的潜在客户,餐馆老板,也有类似的行为。对许多人来说,看到如此多的食物被浪费也是一种情感上的痛苦。虽然对他来说在经济上是一样的,但他更喜欢我的型号,它每天浪费很少,相比之下,BloodyC 的几天就浪费很多。

发现情况太抽象或假设?这里有一个非常真实的例子:

$克鲁奇·麦克达克

职业交易员通常更喜欢通过衍生品——期货期权——在股票市场进行投资/交易。在许多策略中,人们押注的是一只股票或衍生品在未来 n 天的价格区间。

我的模型现在感觉比 BloodyC 的更安全吗?即使我出错了,我也会出错一点点。交易者仍然会在这个有限的范围内赚钱,即使他的赌注不准确。如果价格大幅偏离交易者所相信的预测,这意味着在的一次错误投资中损失了巨额资金——相信 BloodyC 会让他付出高昂的代价。

如果这让您觉得我的模型更适合您的业务案例,那么在比较这两个模型时,您使用哪个指标来表达这一点?梅当然不能惩罚一个比另一个多。

进来吧,RMSE

R MSE 是 M的平方 R oot 可以是 S的平方Eerror。因此,如果你计算预测中每个错误的平方,并把它们加起来,然后除以 7(预测的总数),你就得到 MSE。如果你想要 RMSE,只需要做一个额外的平方根。(唷,那不是一口!)

让我们看看 RMSE 如何看待我们的预测:

均方根误差

哟呼呼!

更大的错误,更大的惩罚——这是 RMSE 的特点之一。我的预测得到了比 BloodyC 的( 3.505 )更低的 RMSE ( 2.138 )值,这意味着当用这个目标评估时它更好。

向 RMSE 祈祷吧!

这是否意味着我们应该一直使用 RMSE 来检验模型的准确性?绝对不行!

如果我的潜在客户出售的不是米饭、鸡肉和印度咖喱,而是可以轻松存放数年的泡菜,允许一天的剩余很容易在第二天出售,那么他更有可能从关注 MAE 或任何其他类似指标中受益。

RMSE、梅、MAPE(平均绝对百分比误差)还有其他几个细微差别,人们当然应该考虑阅读这些,并深入研究其背后的数学。我觉得有趣的几篇文章是这个这个(跳转到第 11 节:时间序列预测的准确性度量),供那些希望进一步探索的人参考。

离别的思绪

我希望我的潜在客户现在能够明白,通过相信我的预测,他将承担多大的风险,以及承担何种类型的风险。他的问题让我再次思考什么更适合他的用例。

至于那个不太守时的丈夫,他只能希望当他在不久的将来犯了大错时,不要被 RMSE 评头论足!

对分享想法、提问或简单讨论想法感兴趣?在 LinkedInYouTubeGitHub 上或通过我的网站与我联系:我只是一个学生

回头见&学习愉快!

为什么不应该将 LabelEncoder 用于分类特征

原文:https://towardsdatascience.com/a-common-mistake-to-avoid-when-encoding-ordinal-features-79e402796ab4?source=collection_archive---------21-----------------------

如何处理分类特征和避免一个常见的陷阱

英格玛机

在处理分类特征时,选择一种合适的方式对它们进行编码可能并不那么简单。这是一个需要考虑的非常重要的方面,它将决定一个特性将为模型增加的价值。

这同样适用于顺序特征,这是一种非常常见的分类数据类型,其中不同的类别呈现出一种自然顺序。一个例子可以是是温度特征,取类别温和热。

一个相当常见的错误是,只给特性的每个类别分配一个唯一的数值,而不考虑它可能具有的任何顺序。并且类似地具有标称特征;不同之处在于它们并不自然地呈现任何顺序。

这篇文章的想法是探索和理解为什么这不是一个好主意,用一个带有顺序特征的例子来更好地说明这一点,以及我们应该用什么方法来代替。

找到所有的代码连同解释 也作为一个 jupyter 笔记本

将特征的固有顺序映射到错误的比例会对模型的性能产生非常负面的影响(即与特征的相关性成比例)。

如前所述,序数特征有一个自然排序,或者换句话说,它们有一个带有等级的序数尺度。因此,如果我们想在编码后保留特性的值,我们想确保它类似于它们的排名。

照片由 veeterzy像素拍摄

用决策树可视化

一种直观的思考方式是决策树设置阈值的方式。在训练过程中,决策树将学习在每个节点设置的最佳特征,以及确定未知样本通过每个节点的路径的最佳阈值。

如果我们用一个简单的LabelEncoder对一个序数特征进行编码,这可能会导致这样一个特征,比如说1代表2可能会翻译成,而0代表沸腾。在这种情况下,结果将是一个具有不必要的大量分裂的树,因此对于本应更简单的建模来说,复杂性要高得多。

虽然实际上看到为什么这是一个坏主意会比仅仅是文字更直观。让我们用一个简单的例子来说明上面的内容,这个例子由两个序数特征组成,这两个特征包含一个学生准备考试所花费的小时数和所有以前作业的平均分数的范围,以及一个指示考试是否通过的目标变量。我已经将数据框的列定义为[pd.Categorical](https://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html):

将分类列定义为熊猫分类的好处是,我们可以在它的分类中建立一个顺序。这使得基于既定顺序的排序比基于词汇排序快得多。它也可以作为一种简单的方法,根据不同类别的顺序得到不同类别的代码

也就是说,对于使用fit / transform方法的更一般的方法,我们应该看看其他工具,我将在下一节中介绍。

因此,我们将使用的数据帧如下所示:

 Hours_of_dedication   Assignments_avg_grade  Result
0                20-25                       B    Pass
1                20-25                       C    Pass
2                 5-10                       F    Fail
3                 5-10                       C    Fail
4                40-45                       B    Pass
5                  0-5                       D    Fail
6                15-20                       C    Fail
7                20-25                       A    Pass
8                30-35                       B    Pass
9                 5-10                       B    Fail
10               10-15                       D    Fail
...

如上所述,我们可以使用[pd.Series.cat.codes](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.cat.codes.html)方法,根据categories参数中的顺序,获得分配给每个类别的代码:

X = df.apply(lambda x: x.cat.codes)
print(X) Hours_of_dedication  Assignments_avg_grade  Result
0                     4                      3       1
1                     4                      2       1
2                     1                      0       0
3                     1                      2       0
4                     7                      3       1
5                     0                      1       0
6                     3                      2       0
7                     4                      4       1
8                     6                      3       1
9                     1                      3       0
10                    2                      1       0
...

现在让我们安装一个[DecisionTreeClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html),看看树是如何定义分割的:

from sklearn import tree
dt = tree.DecisionTreeClassifier()
y = X.pop('Result')
dt.fit(X, y)

[sklearn.tree](https://scikit-learn.org/stable/modules/generated/sklearn.tree.plot_tree.html#sklearn.tree.plot_tree)模块提供了绘制拟合决策树的功能。让我们用它来看看决策树是什么样子的:

g = tree.plot_tree(dt, 
                   feature_names = X.columns,
                   class_names=['Failed', 'Pass'],
                   filled = True,
                   label='all',
                   rounded=True)

就这些吗??嗯… 是的!我实际上以这样一种方式设置了特征,即在Hours of dedication特征和考试是否通过之间存在这种简单而明显的关系,这表明问题应该非常容易建模。

现在让我们试着做同样的事情,用一个我们可以通过LabelEncoder获得的编码方案直接编码所有的特征,所以不考虑特征的实际普通性,只是随机分配一个值:

from sklearn.preprocessing import LabelEncoderX_wrong = df.apply(LabelEncoder().fit_transform)
dt_wrong = tree.DecisionTreeClassifier()
dt_wrong.fit(X_wrong, y)g = tree.plot_tree(dt_wrong, 
                   feature_names = X_wrong.columns,
                   class_names=['Fail', 'Pass'],
                   filled = True,
                   label='all',
                   rounded=True)

正如所料,对于我们试图建模的简单问题来说,树结构比必要的要复杂得多。为了让树正确地预测所有的训练样本,它已经扩展到深度为4,这时单个节点就足够了。

这意味着分类器可能会过拟合,因为我们大大增加了复杂性。通过修剪树和调整必要的参数来防止过度拟合,我们也没有解决问题,因为我们通过错误地编码特征添加了太多的噪声

序数特征应该如何编码?

在上面的例子中,我们已经看到了一种使用pd.Categorical对序数特征进行编码的简单方法。但是大多数时候,我们感兴趣的不仅仅是转换一组给定的特性,还包括在看不见的数据上复制应用的转换。

为此,我们有来自类别编码器[OrdinalEncoder](https://contrib.scikit-learn.org/categorical-encoding/)。本课程使我们能够:

  • 定义将类别映射到代码的字典
  • 用映射字典安装编码器,用转换看不见的数据

让我们通过一个例子来看看如何使用它,这个例子包含几个特性:

OrdinalEncoder接收一个映射参数,期望一个字典列表,每个字典包含键colmapping:

然后,我们可以使用以下内容创建编码器的新实例:

import category_encoders as ce
encoder = ce.OrdinalEncoder(mapping = ordinal_cols_mapping, 
                             return_df = True)

因此,通过在与上述相同的数据框架上进行转换,我们得到:

df_train = encoder.fit_transform(df)
print(df_train) Outlook  Temperature  Humidity  Windy  PlayTennis
0         2            2         1      0           0
1         2            2         1      1           0
2         1            2         1      0           1
3         0            1         1      0           1
4         0            0         0      0           1
5         0            0         0      1           0
6         1            0         0      1           1
7         2            1         1      0           0
8         2            0         0      0           1
9         0            1         0      0           1
10        2            1         0      1           1
11        1            1         1      1           1
12        1            2         0      0           1
13        0            1         1      1           0

因此,总而言之,一旦对特征进行编码,保持它们的平凡性是至关重要的,否则正如这个例子所表明的那样,我们将失去它们所有的可预测能力,而只是将噪声添加到我们的模型中。

找到所有的代码和解释,也可以作为一个笔记本。希望你喜欢并发现这很有帮助!

Cloudera、Amazon Web Services 和 Microsoft Azure 的比较研究

原文:https://towardsdatascience.com/a-comparative-study-on-cloudera-amazon-web-services-and-microsoft-azure-32c0b240fb8e?source=collection_archive---------18-----------------------

Unsplash 上由 C Dustin 拍摄的照片

理解大数据

摘要 —本文旨在比较 Cloudera、亚马逊 Web 服务和微软 Azure 提供的云计算服务。大数据是指大量数据,包含结构化、半结构化和非结构化数据。传统技术无法存储和处理大数据。Hadoop 框架支持存储和处理如此复杂的数据。Cloudera、Amazon Web Services 和 Microsoft Azure 部署了 Hadoop 框架,并在云上实现数据存储和处理。这三个发行版都提供了云计算、云存储、数据库和机器学习。他们在不同方面都有自己的长处和短处。用户必须选择最符合他们需求的发行版。

关键词—大数据、云计算、Hadoop、AWS、Azure

一.导言(简要背景)

B ig 数据是一个术语,指庞大的规模(容量)、高增长率(速度)和各种数据集(多样性)。传统的技术和工具,例如关系数据库管理系统(RDBMS),既不充分也不适合管理、捕获、处理或分析大数据并从大数据中创造有意义的洞察力[1][4]。

RDBMS 只适用于以表格形式存储的结构化数据,而对于大数据,数据种类繁多,不仅仅是表格。大数据包括非结构化数据,如移动生成的信息、图像、视频和 RFID。在 RDMBS 中,数据是基于关系进行分析的,这导致了它的另一个局限性,因为维护非结构化数据关系是不可想象的(至今)。除此之外,RDBMS 不能保证快速的处理速度,这是分析大数据的主要问题之一。因此,大数据分析更适合采用分布式文件系统方法的 NoSQL。最后但同样重要的是,在存储和处理大数据时,传统技术和工具将是一种昂贵的方法。[4]

图一。大数据的五大特征。(图片由作者提供)

从上面的陈述中,大数据被描述为具有巨大的量、高的多样性以及高的速度。从[2]和[7]来看,大数据还有另外两个定义,就是准确性和价值。

卷:卷是指数据的大小。随着每秒钟产生大量数据,数据量已经从兆字节和千兆字节增长到千兆字节。据预测,到 2020 年,将会产生 40zb 的数据,这是 2005 年的 300 倍[1] [2]。

图二。数据量的增长。(图片由作者提供)

多样性:多样性是指不同类型的数据和不同来源的数据。大数据不仅仅是行和列形式的结构化数据,事实上,大数据中只有一小部分是结构化数据,大部分生成的数据是非结构化数据或半结构化数据,例如,音乐、视频、图像、电子邮件或社交媒体数据。Twitter 上有 2 亿活跃用户,每天发送 4 亿条推文。所有这些都有助于各种大数据的增长[1] [2]。

图 3。数据类型。(图片由作者提供)

速度:速度是指产生数据的速度和处理数据的速度。有不变的静态数据,也有变化非常频繁的数据。对于频繁变化的数据或高速生成的数据,例如社交媒体帖子,处理速度必须足够快,因为数据有时可能在[1] [2]之后不再有用。

准确性:准确性是指数据的准确性或不可靠性。收集数据的不一致性和不完整性导致数据的不确定性[2]。

价值:价值是指可以从数据中获得的利益。从[7],大数据生态系统表明,数据购买者和数据使用者可以从数据价值链中其他人收集和组合的信息中提取价值。

I .发行版/服务的历史和演变

随着传统技术和工具不再适合大数据存储和处理,各种分发和服务被发布。大多数发行版都支持 Hadoop 框架,能够处理复杂的大数据。

Hadoop(高度归档分布式面向对象编程)是一个开源的 Apache 框架,用 Java 编写,旨在使用简单的编程模型支持跨计算机集群的大规模数据集的分布式并行处理。Hadoop 得名于创造者儿子的玩具大象。2005 年,两名雅虎员工创建了 Hadoop,最初是为了支持开源网络爬虫 Nutch。2003 年,Google 发布了 Google 文件系统和 Google Map Reduce,随后 Google 在 2004 年的白皮书中分享了 Google 文件系统和 Map Reduce 的解释。谷歌激发了 Hadoop 的产生。2005 年,Hadoop 开始在雅虎服务。2008 年,Apache 接管了 Hadoop,这就是 Hadoop 现在被称为 Apache Hadoop 的原因。同时,Hadoop 已经成为分布式应用最强大的数据存储和处理框架之一[3] [4]。

Hadoop 有助于以分布式方式以最低的成本存储、访问和获取大数据中的大量资源,具有高扩展性和高可用性,因为它本身可以在应用层确定故障,这使得它非常具有容错性。Hadoop 不仅可以处理大量数据,还可以处理各种各样的数据,如图像、视频、音乐音频、文件、文件夹、软件和电子邮件。简而言之,Hadoop 可以处理任何类型的结构化、半结构化和非结构化数据。Cloudera、Hortonworks 和 MapR 是 Hadoop 的商业支持发行版[4]。

图 4。Hadoop 组件。(图片由作者提供)

Hadoop 提供多种服务,其中包括文档、位置感知、源代码和工作调度。Hadoop 包包含两个主要部分和其他各种组件。两个主要部分是 Hadoop 分布式文件系统(HDFS)和 MapReduce。HDFS 主要用于数据存储,MapReduce 用于数据处理和数据分析。HDFS 和 MapReduce 都实行主从架构。其他组件包括 Zookeeper、Sqoop、Pig、Oozie、Hive、HBase、Flume 和 Avro [3] [4]。

HDFS 是 Java 可移植文件系统,它在 Hadoop 框架环境中更具可伸缩性和可信任度。HDFS 包含一个名称节点和一个数据节点群集。数据节点存储文件数据,而名称节点存储元数据,如每个数据块地址的名称、文件属性、副本和位置。如果数据节点的数据块在复制副本中丢失或出现故障,名称节点将创建数据块的复制副本。数据节点中的块数由名称节点监控。因此,名称节点是非常重要的,因为只有它知道所有文件存储在哪里,这也是与数据节点通信的唯一方式[3]。

Map Reduce 是一款用于处理大型数据集的软件。它的名字代表了它的两个主要功能,Map 和 Reduce。映射函数将数据分离成一对键和值,减少推断最终输出,并生成中间值[4]。如上所述,MapReduce 采用与 HDFS 相同的主/从架构。在 MapReduce 中,主节点是作业跟踪器,从节点是任务跟踪器。在收到用户的订单后,MapReduce 向 HDFS 请求数据集。在此过程中,用户与 MapReduce 主节点(作业跟踪器)通信,然后作业跟踪器从 HDFS 的 Name 节点获取要处理的数据的位置。之后,作业跟踪器将作业传递给任务跟踪器进行处理。对于 HDFS 和 MapReduce,从节点和将定期向主节点发送心跳信号,以确保主节点仍然活着[5]。

Hadoop 是不可替代的,因为它的框架使大数据的存储和处理成为可能。虽然 Hadoop 架构是基于 Google 文件系统和 Google Map Reduce 的,但是提供的服务是免费的,因此许多发行版都部署了 Hadoop 的实现。

A.Cloudera

如前所述,Cloudera 是 Hadoop 的商业支持发行版之一。2008 年,Cloudera 由包括甲骨文、脸书、谷歌和雅虎在内的硅谷领先公司的最聪明的头脑创建。。Hortonworks 成立于 2011 年,由 24 名雅虎!工程师,来自最初的 Hadoop 团队。Hortonworks 和 Cloudera 都认为开放标准、开源和开放市场对公司来说是最好的。2019 年,Cloudera 已经与 Hortonworks 合并[8]。

Cloudera 的创始人坚持认为,有了 Hadoop,整个商业市场都可以获得优势。例如,石油和天然气公司可以用一种新方法分析他们的油藏数据,这种方法可能提供不同的见解。该声明得到了 Accel Partners 的足够重视,Accel Partners 愿意投资资金启动 Cloudera 项目。然而,VMware 的联合创始人戴安娜·格林(Diana Greene)和 MySQL 的前首席执行官马丁·米科斯(Marten Mickos)以及脸书的首席财务官吉迪恩·于(Gideon Yu)也向该公司投入了资金。Cloudera 计划出售他们的咨询和支持服务,尽管 Hadoop 仍然是免费的[9]。

B.亚马逊网络服务

亚马逊作为全球在线销售的领导者,拥有自己的云计算,即亚马逊网络服务(AWS)。2006 年,AWS 成立并开始向个人和组织提供云计算[6]。AWS 是作为 Amazon.com 的副业引入的[10]。AWS 业务的领导者 Andy Jassy 提到,AWS 不是任何一个人的想法,它的成立是因为该公司在推出新项目和支持客户的能力方面遇到了挫折。没有人知道 AWS 会成长为今天这样一个万亿美元的技术市场[11]。

根据 Jassy 的说法,在 AWS 的构建阶段,他们很快面临第一个关键决策,是应该从存储解决方案、计算解决方案和数据库解决方案中构建一个服务,还是构建一个包含所有三种服务的平台。由于他们认为所有应用程序都需要计算解决方案,大多数需要数据库,几乎所有应用程序都需要存储,因此他们得出结论,大多数开发人员需要这三种服务的组合。然后。AWS 于 2006 年 3 月推出[11]。

C.微软 Azure

微软 Azure 于 2010 年首次发布。微软 Azure 使用户能够在云上运行服务,或者将云计算服务与任何基础设施、数据中心或应用程序相结合[6]。微软 Azure 原名 Windows Azure,2014 年 4 月 3 日更名为微软 Azure。同一天,微软声明他们将 Azure 作为客户的公共云平台。微软 Azure 支持来自任何公共云的各种操作系统、语言和服务,例如 Hadoop [12]。微软 Azure 是在 2008 年微软专业开发者大会上首次推出的,同时推出的还有微软 SQL 服务。NET Services、Live Services 以及 Microsoft SharePoint Services 和 Microsoft Dynamics CRM Services SaaS。随着这一系列新产品的推出,微软提供了五大关键类别的云服务,而不仅仅局限于云计算。Windows Azure 提供计算、存储和网络服务,而微软 SQL Services 提供数据库服务[14]。

微软一直是 IT 市场的领导者。虽然微软 Windows 软件过去和现在都在人们的生活中很受欢迎,但微软决定将他们的重点从个人电脑转移到移动和云计算。这一决定被证明是明智的决定,因为销售额翻了一番,股票上涨了 6.2%。

二。分发/服务及其组件的亮点

表 1。三种分布的比较概要。(图片由作者提供)

A.Cloudera

Cloudera Enterprise 非常适合希望建立自己的企业大数据中心并在其上执行数据分析的组织。Cloudera Enterprise 利用 Hadoop (CDH)的开源 Cloudera 发行版,这是目前使用的 Hadoop 部署最多的实现之一[17]。

CDH 提供启动和运行大数据环境所需的所有工具。通过与 Apache Kudu 项目和 Apache Impala 项目的集成,Cloudera 现在能够支持实时分析和 SQL 分析查询。Cloudera 提供的四个主要功能是开源数据平台、分析、数据管理和预测建模。Cloudera 数据平台(CDP)拥有 Hortonworks 和 Cloudera 的最佳技术,可作为首个企业数据云。CDP 不仅包括数据中心服务,还包括数据仓库和机器学习。它提供了一个集成的控制平面来管理数据、基础架构和分析,CDP 还支持混合云或多云环境。CDP 是完全开源的发行版,可以避免供应商锁定。对于价格,Cloudera 提供了各种选项,包括 4,000 美元起的年费和每小时 0.08 美元的服务使用费[17]。

B.亚马逊网络服务

Amazon Web Services 在存储和使用的服务方面提供高度可定制的服务。此外,成本是根据选择的服务数量计算的。这对小型和大型组织都非常有益。AWS 还提供 12 个月的免费试用。然而,AWS 目前有一些客户支持问题[6]。

AWS 提供的云计算服务可以分为 19 个类别,分别是计算、存储、数据库、迁移、网络和内容交付、开发者工具、管理工具、人工智能、分析、安全、身份和合规、移动服务、应用服务、消息传递、业务生产力、桌面和应用流、软件、物联网、联络中心和游戏开发[16]。

在所有服务中,AWS 最受欢迎的服务之一是用于云计算的弹性计算云(EC2)。它提供免费层、按使用付费和快速部署。付款从每小时 0.0059 美元开始。接下来是简单存储服务(S3),也是免费层,适用于主存储和备份,因为他们声称该服务具有几乎 100%的耐用性。Glacier 是 AWS 提供的另一种存储服务,适用于档案存储,与 S3 集成。另一个流行的服务是关系数据库服务(RDS ),它提供六种数据库引擎供选择,价格从每小时 0.017 美元开始。亚马逊在人工智能方面有强大的投资,他们提供了亚马逊机器学习,能够进行实时预测,并包含可视化工具和向导。该费用按使用次数计算,其中数据分析和模型构建每小时花费 0.42 美元,批量预测每 1000 次交易花费 0.10 美元,实时预测每次预测花费 0.0001 美元[16]。

AWS 提供的最大好处是按使用付费,这使它不仅适用于大型组织,也适用于中小型企业,甚至个人。

C.微软 Azure

微软 Azure 为不同类型的行业提供了各种各样的服务。他们考虑了各种业务需求,并推出了各种足以满足各种行业需求的软件包。它兼容 Windows 和 Linux,并提供 12 个月的免费试用。然而,它比 AWS 更贵,因为服务是打包提供的,这意味着即使你可能不需要某项服务,你仍然必须购买它[6]。

微软 Azure 提供的云服务可以分为 14 类,分别是计算、网络、存储、Web +移动、容器、数据库、数据+分析、AI +认知服务、物联网、企业集成、安全+身份、开发者工具、监控+管理、微软 Azure 栈[14]。

根据[14],从 Azure 提供的各种各样的服务来看,最受欢迎的服务是用于计算的虚拟机、Blob 存储、SQL 数据库、用于安全+身份的 Azure Active Directory 以及用于开发人员工具的 Visual Studio Team Services。微软 Azure 的虚拟机提供按使用付费,每小时只需 0.018 美元。此外,虚拟机支持各种服务器软件,包括 Window Server、Linux、SOI Server、IBM、SAP 和 Oracle。对于 Blob 存储,价格取决于访问,以及它对大规模可扩展对象存储的支持。虚拟机和 Blob 存储都提供免费层,用户可以免费试用服务。其次是 SQL 数据库,它也提供按使用付费,价格从 0.10 美元到 3.23 美元每小时使用。Azure Active Directory 为云和云上应用程序提供单点登录服务,并与 Office 365 等微软云服务集成。提供免费等级,高级 P2 服务的费用为每个用户每月 9 美元,基本服务的费用为每个用户每月 1 美元。Visual Studio Team Services 对订阅其他微软服务的开发人员是免费的。对于不是微软服务订阅者的用户,前五个用户的服务是免费的,第六到第十个用户每月 6 美元,第 11-100 个用户 8 美元,第 101-1000 个用户 6 美元,其他用户 4 美元。

简而言之,微软 Azure 对那些已经在使用微软软件(例如 Windows 和 Office)的个人或组织有利。通过使用微软 Azure,微软服务用户可以很快采用它,并且微软 Azure 提供的一些服务对微软服务用户是免费的[14]。

三。分销商/服务及其组成部分之间的比较(分析/结果)

所有三个发行版,Cloudera,Amazon Web Services 和 Microsoft Azure 都支持数据存储,数据库,网络安全,云计算和机器学习。每种发行版都有自己的优缺点。本节将比较这三个发行版各自提供的服务。

基于产品功能和客户对 Cloudera、AWS 和 Microsoft Azure 的评级和评论可在[15]上获得。根据过去 12 个月的评级和评论[15],Microsoft Azure 的总体同行评级最高,其次是 Cloudera,然后是 AWS。产品能力方面,Cloudera 和微软的平均评分高于 4.0,AWS 的平均评分在 3.5 左右。评级显示,AWS 在持续加载数据和查询多种数据类型/数据源方面的性能较低,而 Cloudera 在行政和管理方面较弱。除了管理大量数据、对许多数据类型/来源的查询、系统可用性和用户技能水平支持之外,Microsoft Azure 在大多数方面都获得了最高评级。AWS 在系统可用性方面排名最高,而 Cloudera 在许多数据类型/数据源的查询方面排名最高。就客户体验而言,所有三个发行版的平均评分都在 4.0 以上。Microsoft Azure 在所有标准方面都获得了最高评级,包括定价灵活性、易于部署、供应商响应的及时性和技术支持的质量。

根据评级,微软在大多数方面都是最好的,包括价格和部署的便利性。然而,基于[6],微软 Azure 被评为昂贵。两个来源之间的差异,这是因为微软 Azure 非常适合已经是 Windows 服务订户的组织。他们可以获得一些免费的 Azure 服务,界面也更加熟悉,这使得他们更容易部署 Microsoft Azure。

根据评级[15]和评论[6],AWS 在系统可用性方面有很高的评级,并推荐其低价和按使用付费的支付方式。但是,与其他两个发行版相比。AWS 在加载数据和执行查询方面较弱,而 Cloudera 在这方面有很强的性能。再者,AWS 不支持 Cloudera 和微软 Azure 这样的混合云环境,在某些方面限制了它的应用。

四。讨论和推荐(应用领域)

由于不同的分布有不同的优缺点,它们在现实生活中的大数据上的应用也是不同的。微软 Azure 对 Windows 服务有很强的支持,非常适合教育等广泛使用 Windows 服务的行业。从学生到教师或讲师,甚至是管理人员,都使用像 Microsoft Office 这样的 Windows 服务。大多数大学订阅了微软 Office 365 服务用于教育用途。Microsoft Office 365 的应用程序包括学生的作业、学生的讲课记录,以及学生和大学所有员工的详细记录。

Cloudera 是 Hadoop 部署最多的实现之一,具有最强的数据加载和查询能力,适合处理非结构化的复杂数据。比如医疗数据。不同病人身上疾病的特点和症状是不同的。Cloudera 还支持科学数据可视化。因此,Cloudera 适合在医疗保健领域应用。

亚马逊网络服务(AWS)适用于公共部门,因为支付是按使用量收费的。公共部门包括政府组织和非政府组织,他们可以使用 AWS 提供的服务来存储他们从调查中收集的数据,并在 AWS 平台上立即执行数据分析。AWS 允许按使用付费,这在成本方面可能对组织有利。AWS 也提供了机器学习服务,组织可以使用机器学习进行预测,例如预测住宅区的用电量。

从我的角度来看,所有这三个发行版都将增长,并在提供的服务方面变得越来越成熟,在产品质量、安全性、易于部署和客户服务方面。分布的应用范围只会越来越大。有可能在未来的某个时候,随着发行版之间的竞争,越来越多的服务变得免费。也有可能在未来的某个时候,云服务已经被创新,直到我们可以用智能设备而不是个人电脑或笔记本电脑来控制一切。大数据存储、处理、数据分析和机器学习都可以通过手指触摸来完成。

如果这已经成为我们的现实,网络安全对于发行版将是非常重要的。当我们生活中的一切都在云上时,如果云中断了,那将是一场灾难。那时,当人们选择服务时,发行版的安全性和持久性将是首先考虑的问题。

动词 (verb 的缩写)结论

总之,每个发行版都有其独特的功能、优点和缺点。因此,建议用户根据自己的情况选择最适合自己的发行版。 Cloudera 部署了 Hadoop 最多,因此在处理复杂数据方面有非常强的性能。亚马逊网络服务以其价格灵活性而闻名,它适合每一个用户。微软 Azure 最适合 Windows 服务用户

保持联系

订阅 YouTube

参考

[1] H. S. Bhosale 和 P. D. P. Gadekar,“关于大数据和 Hadoop 的综述论文”,《国际科学与研究出版物杂志》,第 4 卷第 10 期,2014 年 10 月。

[2] R. Beakta,《大数据与 Hadoop:综述论文》,国际计算机科学与信息技术杂志,2015 年第 2 卷第 2 期。

[3] B. Saraladevi,N. Pazhaniraja,P. V. Paul,M. S. Basha 和 P. Dhavachelvan,“大数据和 Hadoop-安全视角的研究”,载于第二届大数据和云计算国际研讨会,钦奈,2015 年。

[4] P. Vijay 和 B. Keshwani,“使用 Hadoop 的大数据的出现:综述”,《IOSR 工程学报》,第 6 卷,第 3 期,2016 年 3 月。

[5] M. R. Ghazi 和 D. Gangodkar,“Hadoop、MapReduce 和 HDFS:一个开发者的视角”,载于印度智能计算、通信&融合国际会议,2015 年。

[6] N. Drake,“2019 年最佳云计算服务:面向数字化转型”, TechRadar ,2019 年 11 月 4 日。【在线】。可用:https://www . techradar . com/best/best-cloud-computing-services。[访问时间:2019 年 10 月 13 日]。

[7] S. Gnanasundaram 和 A. Shrivastava,《信息存储和管理:以传统方式存储、管理和保护数字信息》,第二版。,交叉点大道:约翰威利父子公司,2012 年。【电子书】。

[8]《关于| Cloudera》, Cloudera ,2019。【在线】。可用城市:https://www.cloudera.com/about.html.[访问时间:2019 年 10 月 18 日]。

[9] A .万斯,“将谷歌和脸书背后的魔力装瓶”, Bits,2009 年 3 月 16 日。【在线】。可查:https://bits . blogs . nytimes . com/2009/03/16/bottling-the-magic-behind-Google-and-Facebook/。[访问时间:2019 年 10 月 18 日]。

[10] R. Miller,《AWS 是如何诞生的》, TechCrunch ,2016 年 7 月 2 日。【在线】。可用:https://TechCrunch . com/2016/07/02/Andy-jass ys-brief-history-of-genesis-of-AWS/。[访问时间:2019 年 10 月 29 日]。

[11] J. Furrier,“独家:AWS 和 Andy Jassy 的万亿美元宝贝的故事”, Medium ,2015 年 1 月 30 日。【在线】。可用:https://medium . com/@ furrier/original-content-the-story-of-AWS-and-Andy-jass ys-万亿美元-baby-4e8a35fd7ed。[访问时间:2019 年 10 月 29 日]。

[12] S. Martin,“Window Azure 即将更名”,T20 微软 Azure,2014 年 3 月 24 日。【在线】。可用:https://azure . Microsoft . com/en-us/blog/upcoming-name-change-for-windows-azure/。[访问时间:2019 年 10 月 29 日]。

[13] A. G. Tharakan 和 J. Dastin,“由于云业务超过预期,微软股价创下新高”,路透社,2016 年 10 月 21 日。【在线】。可用:https://uk . Reuters . com/article/uk-Microsoft-results-idukkcn 12k 2 JC。[访问时间:2019 年 10 月 29 日]。

[14] C .哈维,《微软 Azure》,数据化,2017 年 5 月 23 日。【在线】。可用:https://www . data mation . com/cloud-computing/Microsoft-azure . html[访问时间:2019 年 11 月 2 日]。

[15]《比较 Cloudera、微软、亚马逊网络服务(AWS)》, Gartner 。【在线】。可用:https://www . Gartner . com/reviews/market/data-warehouse-solutions/compare/cloud era-vs-Amazon-we B- services-vs-Microsoft。[访问时间:2019 年 11 月 2 日]。

[16] C. Harvey,“亚马逊网络服务(AWS)”,数据化,2017 年 5 月 11 日。【在线】。可用:https://www . data mation . com/cloud-computing/Amazon-we b-services . html[访问时间:2019 年 11 月 3 日]。

[17] S. M. Kerner,“Cloudera 企业:服务概述与洞察”,数据化,2019 年 4 月 25 日。【在线】。可用:https://www . data mation . com/big-data/cloud era-enterprise-data-analytics-tools . html[访问时间:2019 年 11 月 5 日]。

Bandit 算法的比较

原文:https://towardsdatascience.com/a-comparison-of-bandit-algorithms-24b4adfcabb?source=collection_archive---------13-----------------------

婴儿机器人强化学习指南

多武装匪徒:第 6 部分

杰森·登特Unsplash 上的照片

概观

在本系列的课程中,我们已经了解了用于定义多臂匪徒的框架和术语。然后,我们将注意力转向一些可以用来解决这个问题的算法,从简单的贪婪算法,到复杂的汤普森抽样贝叶斯方法。现在只剩下一个问题需要回答了。这些方法中哪一种最能解决土匪问题?

对于那些还不熟悉多臂土匪问题,或希望刷新他们的知识的任何特定领域,在这一系列的其他部分如下:

bandit 算法和测试框架的所有代码都可以在 github 上找到: Multi_Armed_Bandits

概述

机器人宝宝在商场走失。利用强化学习,我们想帮助他找到回到妈妈身边的路。然而,在他开始寻找她之前,他需要从一组电源插座充电,每个插座的电量略有不同。

使用多臂强盗问题中的策略,我们需要在最短的时间内找到最好的插座,让机器人宝宝充电上路。

机器人宝宝进入了一个充电室,里面有 5 个不同的电源插座。每个插座返回的电荷数量略有不同。我们希望在最短的时间内给机器人宝宝充电,所以我们需要找到最好的插座,然后使用它,直到充电完成。

这与多臂强盗的问题是一样的,除了我们不是在找一个能给出最好回报的老丨虎丨机,而是在找一个能给出最多电量的电源插座。

Bandit 算法的比较

为了回答哪个是最好的 bandit 算法的问题(就我们已经研究过的算法而言),我们可以根据我们自己的问题来重新构建问题:哪个算法会让婴儿机器人在最短的时间内充满电?

为了进行这个实验,我们首先需要准确定义充满电的含义。对于这一点,我们将任意定义婴儿机器人在有足够的电量运行一小时(3600 秒)时充满电。

有了这个定义,我们现在可以运行每一个 bandit 算法,最多运行 500 个时间步,结果如下:

(注:用于生成这些结果的完整测试系统可在 github 笔记本中获得。)

图 6.1:在 5 插座电源问题上 bandit 算法的比较。

从上图我们可以看出:

  • 乐观贪婪,UCB汤普森采样都在大约相同的时间步数内达到所需的最大电荷(这就是为什么乐观贪婪汤普森采样的线被 UCB 的线遮住)。
  • 在每种情况下, 后悔 对于这些算法来说几乎为零。当任何插座的最大可用电量为 12 秒时,每个插座仅用了 300 个时间步来达到 3600 秒的最大所需电量。所以最佳插座被快速定位,然后被充分利用。
  • Epsilon Greedy 另一方面,达到最大充电量需要稍长的时间。因为它在整个运行过程中继续探索套接字集,所以它未能完全利用最佳套接字。
  • 而且,最糟糕的是贪心算法。它实际上无法在可用时间内达到最大电量。

所以,从给婴儿机器人充电的角度来看,任何一种乐观贪婪UCB汤姆森采样算法都可以完成这项工作。但是需要注意的是乐观贪婪UCB 都需要设置一个参数(这些参数是乐观贪婪的初始值和 UCB 的置信度值)。对这些参数做出错误的选择会导致算法性能下降。

由于汤普森采样不需要设置参数,所以这不是问题,因此这可能是选择使用哪种算法的决定性因素。

增加了问题难度

我们到目前为止所使用的套接字问题被故意做得非常简单,以允许对每个算法的探索和利用机制进行说明。然而,在寻找最佳算法方面,它有几个主要缺点。

  • 首先,它只有五个插座。因此,即使使用贪婪算法的随机搜索,也有 20%的机会找到最佳插座。对于更高级的搜索机制,它们可以快速定位并锁定最佳插座,因为要测试的插座很少。
  • 其次,每个插座都有非常明显的奖励。由于我们设置的实验中插座的充电间隔为 2 秒钟,其奖励有一个单位变化,因此插座和下一个最佳插座返回的电量几乎没有重叠。一旦尝试了最好的插座,任何其他插座返回的电荷都不太可能大于该值。这使得识别哪个插座是最佳的变得非常容易。

为了克服我们原始实验中的这些不足,让我们将插座的数量增加一倍,并减少插座可以返回的电荷数量的差异,将充电时间从 2 秒减少到 0.2 秒。有了这些值,套接字的输出现在看起来如下:

图 6.2:10 个插座的奖励分布。插座顺序定义了插座的相对品质,从最低到最高输出,10 是最好的(插座 4),1 是最差的(插座 3)。

图 6.3:插座输出的密度图。插座 4 的平均输出最高,插座 3 的平均输出最低。

现在我们有 10 个插座,一个插座的平均回报和下一个最好的插座之间有 0.2 秒的充电差异。这意味着回报有更大的重叠。

插座顺序[7,5,1,10,2,3,6,8,9,4]以递增的顺序定义了插座的好坏,因此插座号 1 是第七好的插座,并且将具有(70.2 +2) = 3.4 秒的充电的平均回报(+2 只是防止插座具有负值的偏移值)。因此,最好的插座是插座 4,平均回报为(100.2 +2) = 4,最差的插座是插座 3,平均回报为(10.2 +2) = 2.2。*

需要注意的其他几点是:

  • 因为我们已经减少了插座平均值的分布,最好的插座现在的输出比我们只测试 5 个插座时的输出低。因此,达到我们定义的最大总奖励(充电 3600 秒)所需的时间步数将会增加。
  • 我们在 5 插槽实验中为 UCB乐观贪婪算法保留了相同的参数,因此调整这些值可能会得到更好的结果。

使用此新设置运行会产生以下结果:

**

图 6.4:bandit 算法在 10 插座电源问题上的比较,电荷分布为 0.2 秒。

现在我们可以看到算法性能的一些分离:

  • 和以前一样,贪婪算法的表现比其他算法差得多。 Epsilon Greedy ,虽然比简单的 Greedy 算法好很多,但还是比其他 3 个算法差。
  • 虽然数量不多,但汤普森取样比其他的要好。

如下所示,对于 100 个套接字,随着套接字数量的增加和平均奖励值的分布的减小,算法中的这种差异变得更加明显,分布为 0.1(注意,现在最大套接字输出再次为 12 (=0.1100 +2)😗

**

图 6.5:bandit 算法在 100 插座电源问题上的比较,电荷分布为 0.1 秒。

对于 100 个插槽,有趣的是注意到 UCB乐观贪婪算法的性能比ε贪婪算法差。事实上,当汤普森取样达到最大电荷时,这些其他算法都没有超过ε贪婪的总平均回报。

可以看出,这是由 UCB乐观贪婪算法的启动回合引起的,在此期间,每个插座被精确地测试一次(注意直到第 100 个时间步长的较低梯度)。因此,对于第一个 100 时间步, UCB乐观贪婪正在努力完成 100 个套接字中的每一个,而ε贪婪汤姆森采样已经开始利用他们发现的最好套接字。

如果我们让实验运行更多的时间步,那么 UCB乐观贪婪可能会超过ε贪婪的平均总回报,并在此之前达到满负荷。然而,如果机器人宝宝用汤普森取样算法选择了插座,他就已经充满电了。

语境强盗

我们看到的基本 bandit 算法的一个主要缺点是它们没有考虑任何可用的上下文信息。

例如,想象一下电源插座是用颜色编码的,这种颜色表示将返回的电量。如果在完成我们的试验后,我们发现蓝色插座充电很多,而黄色插座充电很少,那么下次我们进入充电站时,优先选择蓝色插座而不是黄色插座是有道理的。

基本的强盗算法只是采取一个行动,收集奖励,并不关注他们的当前状态。因此,可能有助于选择最佳行动的当前状态的潜在有用信息被简单地忽略。

情境强盗(也称为“关联强盗”)通过使用来自当前状态的信息来帮助指导他们选择行动,从而解决了这一限制。因此,它们既可以被认为是复杂的强盗算法,也可以被认为是强化学习的简化版本。

在完全强化学习问题中,所采取的行动可以导致状态的改变,并因此导致新的上下文信息。因此,所选择的行动会对未来可能获得的回报产生影响。例如,在一盘棋中,一个看起来很好并能立即给予很大回报的走法(比如拿下对方的皇后)实际上可能会导致你输掉比赛。因此,这实际上被认为是一个糟糕的举动。真正的奖励会延迟,直到游戏结束才会收到。

在上下文盗匪中,这些条件都不存在;行动不会改变状态,回报是即时的,而不是延迟的。

Bandit 算法的使用

那么,除了给婴儿机器人充电或者下次你在拉斯维加斯时在吃角子老丨虎丨机上赢得你的财富,多臂强盗算法还能用来做什么呢?

免责声明: 众所周知,拉斯维加斯的赌场老板对在赌场中使用算法的人非常敏感。因此,在使用这些算法的过程中,我不承担任何物理或经济损失的责任!

多武装匪徒可能有两个主要的使用领域:

首先是我们如何使用它们,作为全面强化学习的垫脚石。多臂土匪的很多概念,比如动作和奖励,直接适用于完全强化学习(RL)问题。实际上,在完全强化学习中,一个多臂强盗可以被认为代表一个单一的状态。此外,贪婪的动作选择虽然可能不是解决 bandit 问题的最佳方法,但通常用于在 RL 中的不同动作之间进行选择。

bandit 算法的第二个主要应用领域是在真实世界测试中。这可以发生在任何领域,但在在线商务、医疗保健和金融领域尤为普遍。

例如,当评估网页的变化如何影响其性能时,这可以通过多种方式来衡量,如页面产生的销售额或点击率,标准方法是使用 A/B 测试。这需要两个或更多不同的页面变体,然后通常将每个变体同等地呈现给站点用户,以观察他们的表现。在预定的时间段之后,比较来自每个页面的统计数据,然后将表现最好的页面作为获胜页面。

很明显,这种形式的测试有一个主要缺点:在测试期间,相同数量的客户被发送到一个性能不佳的网页。如果这个页面的性能特别差,它可能会对你的网站的整体性能产生很大的负面影响。通过有一段时间专门用于勘探,A/B 测试继续调查表现不佳的选项。

相比之下,在多臂 Bandit 方法中,页面根据用户测量的相对性能呈现给用户。表现好的页面将越来越多地显示,表现差的页面将较少显示。以这种方式,可以测试对网站的改变。提高性能的好特性会立即得到提升,产生积极的影响,而在 A/B 测试中会持续产生负面影响的坏特性会很快被丢弃。

多臂匪在临床试验中的使用方式类似。显然,在药物试验期间,继续给患者服用会导致患者出现负面副作用的药物是个坏主意。因此,多臂 Bandit 算法已经被用于决定给患者的药物和剂量,以最大化积极的结果。

为了更全面地了解 Bandit 算法的实际应用,我推荐阅读以下文章:

" 多武装背景土匪 实际应用调查",Djallel Bouneffouf,Irina Rish (2019)

结论

我们已经看到,当面临必须在各种不同选项之间进行选择的问题时,选择这些选项中任何一个的回报最初都是未知的,诸如汤姆森抽样置信上限(UCB)* 之类的算法比简单地从选项中随机选择要好得多。有了这些算法,我们可以最大限度地减少尝试错误行动的次数,最大限度地增加采取最佳行动的次数。*

通过在插座选择问题中使用这些算法,我们能够快速定位和利用最佳插座,并让机器人宝宝充电上路。

在后续文章中,我们将会看到更高级的强化学习(RL)* 技术,其中一些利用了这些 bandit 算法。利用这些,我们将帮助机器人宝宝找到回到妈妈身边的路!*

注意:虽然我们已经研究了很多解决多臂强盗问题的方法,但是我们实际上只是触及了所有可用算法的皮毛。如果你想看得更多的话,可以看一看强盗的书。

参考资料:

[1] " 强化学习:导论 ",萨顿&巴尔托(2018)

[2]“汤普逊取样教程 ”,鲁索等,(2017)

[3]“一场语境化的土匪烘培赛 ”,比提等人,(2020)

[4] " 关于多武装和背景土匪的实际应用的调查 ",Djallel Bouneffouf,Irina Rish (2019)

bandit 算法和测试框架的所有代码都可以在 github 上找到:

* [## 我在想什么/婴儿机器人

婴儿机器人强化学习指南。通过创建一个……

github.com](https://github.com/WhatIThinkAbout/BabyRobot)*

下一个系列…

*强化学习导论:第 1 部分

陈述价值和政策评估*

* [## 国家价值观和政策评估

强化学习简介:第 1 部分

towardsdatascience.com](/state-values-and-policy-evaluation-ceefdd8c2369)*

使用 TF/Keras 比较 DNN、CNN 和 LSTM

原文:https://towardsdatascience.com/a-comparison-of-dnn-cnn-and-lstm-using-tf-keras-2191f8c77bbe?source=collection_archive---------6-----------------------

视频教程

快速浏览不同的神经网络架构及其优缺点。

视频教程

实验机器学习变得如此有趣!在我对用深度神经网络取代一些信号处理算法进行研究之后,我开始尝试另外两种著名的神经网络架构:LSTM 和 CNN,感兴趣的读者可以参考文章“机器学习和信号处理”。

介绍 CNN 和 LSTM

在我们进入我的比较的细节之前,这里有一个介绍,或者说,我对其他神经网络架构的理解。我们都理解深度神经网络,它只是每层的一组神经元依次与下一层的另一组神经元互连,以此类推。每个神经元实现等式y = f(Wx+b)用于输入 x 和输出 y ,其中 f 是非线性激活函数, W 是权重矩阵,而【t3t】这是一张来自 https://playground.tensorflow.org/的图片

美国有线新闻网;卷积神经网络

一个卷积神经网络,CNN,正在增加额外的“过滤”层,除了每个神经元的权重和偏差之外,还可以学习过滤器权重(或者卷积核,如果你喜欢更华丽的词:)。仍然是反向传播在为我们做这项工作,但是我们不能让它对可靠的工作载体反向传播变得太容易!

这是我用 PowerPoint 制作的一张图片,用来解释 CNN。网上有更好的图片,图形很酷,但我不想抄袭别人的作品。当我创作我的内容时,我也必须创作我自己的插图!这就是为什么内容创作是一项艰巨的工作。尽管如此,今天的互联网是由那些创造了令人敬畏的内容的人建立的,因为他们乐在其中!

正如你在上面的图片中看到的,CNN 有几个平行的过滤器,可以被调整以提取不同的感兴趣的特征。当然,我们不会像信号处理中那样设计滤波器,但我们会让反向传播计算滤波器权重。

熟悉信号处理的读者可以连接滤波器组来分离高频和低频。这种思想在图像压缩中有重要作用,可以用滤波器组来分离低频和高频,只需要保留低频。然而,让我们不要跑题。

输入向量被这些“卷积”层中的每一层过滤。它们将输入向量与内核(滤波器脉冲响应)进行“卷积”。卷积是线性系统中的基本运算之一,就像乘法对于数字一样重要。实际上,卷积运算与多项式乘法完全相同。如果您将两个多项式相乘,并用 x=10 来计算结果,您将得到数字的常规长乘法。我又跑题了。

然后,每个卷积层生成自己的输出向量,因此,如果我们有 K 个卷积层,则维度增加 K 。为了减少维度,我们使用“池化”层—计算最大/最小或一定数量样本的平均值。连接所有池层的输出,并通过密集层来生成输出。

RNN 和 LSTM

LSTM(长短期记忆)是一种递归神经网络(RNN),其中通过“时间”上的输入序列来训练相同的网络。我用引号将“时间”括起来,因为这只是将输入向量分割成时间序列的一种方式,然后通过序列循环来训练网络。

由于在每个时间实例中训练的是同一个网络,或者更确切地说是同一套神经元,我们需要有一种跨时间传递“状态信息”的方法。在一个时间实例中神经元进化到的状态被用作下一个时间实例中神经元的附加输入。希望下图能说明这一点。

如果我们用“LSTM 层”代替 RNN 的单一致密层,我们就会得到一个 LSTM 网络。网上有很好的解释 RNN 和 LSTM 的文章——这里有一篇来自 Colah 的博客:“了解 LSTM ”。

RNN 或 LSTM 捕捉输入向量中跨时间序列的相关性。使用 DNN 可以实现相同的效果,但这需要收集跨时间的输入向量,然后将其馈送到一个较大的图层,与 RNN 相比,这需要训练更大的参数集。

比较时间序列预测

有了对 CNN 和 RNN 的介绍,让我们进入本文的主题——比较 DNN、CNN 和 RNN/LSTM。我们将选择时间序列预测作为我们想要解决的问题,但有一个转折!一旦训练好网络,我们不仅会根据输入样本评估它们的预测,还会附加预测样本作为输入,以查看网络生成时间序列的效果如何。基于旧预测的新预测——这是一个很好的挑战!除了是一个有趣的实验,这也有实际应用。

例如,WLAN 中的信道估计发生在前同步码期间,但是需要用于解调,直到整个分组结束。如果它是一个很长的包,信道将随着时间慢慢变化,并且接近包的末尾,如果我们不跟踪信道的变化,我们将得到一个很差的信道估计。由于在有效载荷期间我们没有得到额外的训练符号来估计信道,所以我们需要“预测”信道变化来更新信道。基于预测更新信道估计,然后再次用于下一次预测。如果其中一个预测是错误的,这将导致该错误传播到未来的预测。

作为 ML 从业者的标准,我使用 Jupyter 笔记本来写这篇文章和相关的代码。让我们继续导入常用的。

让我们使用正弦曲线的总和作为输入时间序列。我挺喜欢这个数据的。即使只有三个正弦波叠加,时间序列看起来也足够随机!

DNN 预测性能

我们将从 DNN 开始。我们将向 DNN 提供时间序列的 64 个样本,而 DNN 需要预测第 65 个样本。取 4000 个样本长的时间序列数据,我们将其分成 64 个样本的重叠序列,以生成大约 4000 个批次(换句话说,4000 个输入向量,每个 64 个样本长)。请随意将代码复制到您的 Python 或 Colab 环境中运行,并感受一下我们正在做的事情。

DNN 模型是一个 3 层顺序网络,第一层有 32 个神经元,第二层 8 和第三层 1。

现在让我们开始训练模型,很简单:)

Model: "sequential_7"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_14 (Dense)             (None, 32)                2080      
_________________________________________________________________
dense_15 (Dense)             (None, 8)                 264       
_________________________________________________________________
dense_16 (Dense)             (None, 1)                 9         
=================================================================
Total params: 2,353
Trainable params: 2,353
Non-trainable params: 0
_________________________________________________________________
DNN training done. Time elapsed:  11.484532 s

我们现在生成测试数据的方式与生成训练数据的方式完全相同,并使用它来评估网络。正如您所看到的,预测与预期输出在合理的准确度上相匹配。

但是基于输入样本的预测很容易。我们有 64 个输入样本来预测第 65 个。让我们评估一下,如果 DNN 必须根据它过去的 64 次预测来预测第 65 个样本,它的表现会有多好!我们在这里所做的就是运行模型来获得每个预测,将预测附加到输入中,并在循环中重复这个过程。

下面的输出显示了相当好的性能。我们可以直观地看到,基于自己过去的预测生成的输出与输入模式相匹配。这意味着我们可以在任何时候关闭网络的输入,让网络依靠自己的输出来产生后续输出,就像信号发生器一样。到目前为止一切顺利!

使用 CNN 预测

现在让我们构建一个 CNN,但是每次只使用 16 个输入来预测下一个样本。“卷积”应该已经能够提取样本之间的时间相关性,并且我们使用 3 个不同的滤波器,每个滤波器具有 4 个抽头的核大小。如果下面的代码被很好地注释了,那么让我们快速地通过训练和验证,进入有趣的部分。

Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv1d_2 (Conv1D)            (None, 13, 3)             15        
_________________________________________________________________
average_pooling1d_2 (Average (None, 3, 3)              0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 9)                 0         
_________________________________________________________________
dense_6 (Dense)              (None, 16)                160       
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 17        
=================================================================
Total params: 192
Trainable params: 192
Non-trainable params: 0
_________________________________________________________________
CNN training done. Time elapsed:  14.113128 s

同样,基于输入样本的预测非常好。但是,亲爱的读者,你有没有注意到 CNN 只需要 192 个参数,而 DNN 需要 2353 个参数?那就小了一个数量级!但是训练有点慢,DNN 是 16 秒,而不是 11 秒。

让我们来看看 CNN 的“信号生成”能力如何。运行下面的代码,我们看到 CNN 的输出在根据过去的预测生成时正在慢慢“衰减”。我知道,用引号说“腐朽”不是一个很科学的分析,但这只是一个有趣的实验!

虽然 CNN 只用 192 个参数就做了很好的预测,但与 DNN 相比,它在永久信号生成方面做得不好。也许增加 CNN 的规模会让它变得更好?很容易得到答案——试一试就知道了!然后去 LSTM。

LSTM 预测

为 LSTM 准备好数据取决于我们希望“回顾”到什么程度。换句话说,在产生输出之前,将训练输入 LSTM 序列的数量。对于我们的例子,我们将使用 4 个序列的回看,并且每个序列是 8 个样本长。请注意,Keras LSTM 层要求输入张量的形状为 (batch_size,lookback=4,input_size=8) ,因此我们只对第一批采样 0 至 31,对第二批采样 1 至 32,依此类推。,连接成一个向量,然后我们将它调整到合适的尺寸。

Model: "sequential_14"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm_8 (LSTM)                (None, 16)                1600      
_________________________________________________________________
dense_23 (Dense)             (None, 1)                 17        
=================================================================
Total params: 1,617
Trainable params: 1,617
Non-trainable params: 0
_________________________________________________________________
LSTM training done. Time elapsed:  27.157384 s 

我们看到,基于输入样本的预测性能非常准确,但训练速度要慢得多,即使参数数量是 DNN 的一半。

如果我们在信号产生模式下运行 LSTM,它似乎表现不错,但仍会遗漏 DNN 设法捕捉到的低频调制。这又是一个假象,DNN 看了 64 个样本,而 LSTM 只看了 32 个。继续尝试将回看增加到 8,让 LSTM 每次输出 64 个样本,你会发现它做得和 DNN 一样好。

顺便说一句,如果你尝试了上述改变回看的实验,你会注意到关于 LSTM 的另一个很酷的事实。当您改变回望时,我们必须训练的参数数量保持不变。这意味着你可以在不增加网络规模的情况下观察很长的输入序列——这就是它的威力所在!

LSTMs 已经非常成功地用于语音识别和 NLP 中的各种各样的问题,在这些问题中,我们必须着眼于长期历史。想象一下和 DNN 这样做,你会有一个庞大的网络在手。

%tensorboard --logdir logs

结束语

总结一下,我们看到,对于我们选择进行实验的简单时间序列预测问题,所有三个网络都表现相似。如果我们评估它们根据以前的预测生成新预测的能力,我们会再次看到,只要每个网络都在相同数量的输入样本上进行训练,性能还是相似的。

#plt.plot(dnn_predictions[1000:1200])
#plt.plot(lstm_predictions[1000+8:1200],'r')
#plt.show()
mse_dnn = np.mean(pow(keras_dnn_err,2))
mse_cnn = np.mean(pow(keras_cnn_err,2))
mse_lstm = np.mean(pow(keras_lstm_err,2))
print("MSE for DNN, CNN and LSTM: ", mse_dnn, mse_cnn, mse_lstm)MSE for DNN, CNN and LSTM:  0.015292015168751526 0.10264436557722294 0.021495189602411965# Summary of training run time
print("DNN training time: ", dnn_train_time, "s")
print("CNN training time: ", cnn_train_time, "s")
print("LSTM training time: ", lstm_train_time, "s")DNN training time:  11.484532 s
CNN training time:  14.113128 s
LSTM training time:  26.689297 s

CNN 可以用来减少我们需要训练的参数数量,而不牺牲性能——结合信号处理和深度学习的力量!但是训练比 DNN 慢了一点点。

LSTM 比 CNN 需要更多的参数,但只有 DNN 的一半。虽然训练速度最慢,但它们的优势在于能够在不增加网络规模的情况下观察长序列的输入。

亲爱的读者,这篇文章到此结束。我感谢你的时间,并希望你得到一点点的洞察力作为回报。

https://www.linkedin.com/in/prasannasethuraman/

XGBoost & PyTorch 之战

原文:https://towardsdatascience.com/a-comparison-of-xgboost-pytorch-a87fb1bb267c?source=collection_archive---------44-----------------------

XGBoost 和 PyTorch 的非技术性比较

Unsplashattendee拍照

TL;DR —这篇文章比较了 XGBoost 和 py torch——两个最流行的 ML 库——并讨论了哪一个更好。你可以在现场调查中了解社区的想法。

免责声明 :所有观点都是我的,不代表我雇主的。我交替使用“算法”、“模型”和“库”。

一个选择

在一次虚拟咖啡会上 COVID 期间保持联系的新方式——我最小的表弟正在完成他的数据科学硕士学位,Shawn 问道:“在 XGBoost 和 PyTorch 之间,我应该学哪个?”

事实上,我经常遇到同样的问题,甚至当我与有多年行业经验的客户一起工作时。

一方面,XGBoost 帮助赢得了大部分 Kaggle 比赛。另一方面,PyTorch 已经被领先的技术和研究公司公认为最佳图书馆。这两个库在构建质量和活跃的社区支持方面不相上下。

如果你有世界上所有的时间、资源和精力,答案显然是“两者都学”。我们大多数人都没有这样的奢侈。在大多数情况下,我建议:从 XGBoost 开始,然后是 PyTorch。

让我们从三个简单的角度来看:供给、需求、以及你的情况和愿望。

1.供给:图书馆擅长什么?

通过设计,XGboost 和 PyTorch 可以有效地解决不同类型的 ML 用例。

XGBoost 对于使用结构化数据的“传统的”ML 用例非常有效(例如,使用良好的旧表格数据进行分类或回归)。PyTorch 专为需要神经网络模型架构的非结构化数据(例如,使用图像的生成模型或使用文本的自然语言处理)的“创新”用例而构建。每个图书馆的教程页面都反映了这种差异和他们想要的“定位”。

XGBoost 教程关于牛逼的 XGBoost ,2020 年 5 月 22 日抓拍

官方 PyTorch 教程页,拍摄于 2020 年 5 月 24 日

鉴于 XGBoost 和 PyTorch 的不同优势,我们必须根据实际的 ML 用例进行挑选。

在学习的背景下,我相信一项新技能应该为我们提供最大限度的即时适用性(我能即时并频繁地使用它吗?),这通常会带来更多的职业选择。

2.需求:工作中通常需要什么样的 ML 解决方案?

“无聊”和简单的东西。根据最新的 Kaggle 调查(以及我自己与该行业团队合作的经验),大多数数据科学家将大部分时间花在使用“基本”ML 解决方案解决问题上,如线性回归、决策树或梯度推进。 XGBoost 擅长这些任务。

作者基于 2019 年 Kaggle 调查的分析

换句话说,如果你学习并使用 XGBoost,你可以更好更快地解决大部分枯燥的问题。然后,用节省下来的时间,你可以用 PyTorch 做创新的事情(或者只是喝杯咖啡,和家人在一起,或者做其他你喜欢的事情)🙂

3.你:你今天在哪里,你的志向是什么?

根据我的调查和一般观察,我们大多数人都在大公司工作,作为默默无闻的英雄——专注于非研究、运营业务问题的数据科学家。

作者的数据和分析

在大公司中,增加价值和获得认可的最直接、最可行的方法是进行渐进式创新。大公司中许多现有的 ML 应用程序是“无聊”的,但却是业务的核心用例;它们由过时和简单的算法驱动,例如使用 Sklearn ( Kaggle 调查和作者的行业经验)的逻辑回归识别客户倾向,或者根据监管和领域经验使用基于规则的定制引擎标记欺诈活动。

用 XGBoost 改进这些应用程序可能会在最短的时间内提供最大的预期投资回报,相比之下,比如说,说服你的老板使用花哨的 PyTorch 模型将客户情绪与面部识别结合起来。

总之,如果你喜欢操作问题,并希望在当前的职位上留下来并取得进步,学习 XGBoost(以及类似的算法,如 Light GBM)可以让你立即取得成果,并使你成为一个著名的英雄。

如果你像调查中的许多人一样,希望成为超级极客,专注于研究型项目,仍然学习 XGBoost 以最大化职业选择性,但现在投资 PyTorch。

现场调查

这是一个现场社区调查,以捕捉更多人的想法,并消除我的观点和经验的偏见。

喜欢读什么? 与我连线上 LinkedIn,或者Twitter。还有,作为一名数据科学家,要不要学习商业思维和沟通技巧?查看我的《 用机器学习影响 》指南。

您可能也会喜欢这些文章:

[## 最有用的 ML 工具 2020

每个懒惰的全栈数据科学家都应该使用的 5 套工具

towardsdatascience.com](/the-most-useful-ml-tools-2020-e41b54061c58) [## 我们应该留在数据科学领域吗?

数据科学家的 4 个现实职业选择

towardsdatascience.com](/the-most-realistic-data-science-career-guide-d12c4af87cc8) [## 下一个最佳数据科学工作

数据科学家最受欢迎的过渡路线

towardsdatascience.com](/the-best-data-science-transition-routes-e809254934d0) [## 被遗忘的算法

用 Streamlit 探索蒙特卡罗模拟

towardsdatascience.com](/how-to-design-monte-carlo-simulation-138e9214910a) [## ML 和敏捷注定的联姻

如何不对 ML 项目应用敏捷

towardsdatascience.com](/a-doomed-marriage-of-ml-and-agile-b91b95b37e35) [## 优步的机器学习让我失望

实时对抗优步黑客&给优步的建议

towardsdatascience.com](/how-to-improve-uber-machine-learning-c83051d6e57f)

免费数据科学资源汇编

原文:https://towardsdatascience.com/a-compilation-of-free-data-science-resources-7861f572cc85?source=collection_archive---------22-----------------------

自定进度学习

对于那些对学习数据科学感兴趣的人

想自学数据科学?不知道从哪里开始?或者,也许你想加深对某些话题的理解?继续读。

我已经按照媒体类型对免费资源的汇编进行了分类,其中一些可能包含统计、数据分析、python、机器学习和/或深度学习等主题的混合。我将说明(只要适用)何时资源仅用于一个特定的数据科学主题。也有很多网站可以帮助你学习/练习 R、Python、SQL 等语言的编码技巧。(HackerRank 是一个有趣的工具),但本文将更侧重于帮助您学习数据科学概念以及如何在数据分析/机器学习应用程序中使用编码语言的工具。

快乐学习!

网站

数据科学 101

这个网站有非常棒的资源档案(这个部分的标题直接链接到免费的资源)。从的教科书到常春藤联盟的课程笔记到博客文章,你可以从数据科学 101 中学到很多东西。

开源代码库

卢克·切瑟Unsplash 拍摄的照片

GitHub 奇妙的协作精神导致了数据科学博客这个巨型列表。这里有大量的博客,所以我会确保你选择阅读/关注的博客是可信的。

宾州州立大学在线统计

在您开始学习数据科学之前,这份在线课程材料对于学习基础统计学非常有用。我收藏了好几页宾夕法尼亚州立大学的书作为参考。

Udemy 上的免费机器学习课程

哇!本页有很多关于机器学习的免费课程。我建议看看评价最高的,也看看评论,找到一个适合你的需求。

开源教科书

用于数据分析的 Python

老实说,我不相信这本书是免费的。在 Python 中,使用 Pandas 和 NumPy 库进行数据分析非常深入。还有一个 GitHub 库,里面有 Jupyter 笔记本,每一章都有练习的答案!****

深入学习

开源,找到贡献者这里

我本人没有读过这本书,但它是我的数据科学导师推荐给我的。它的格式非常好,带有讨论板和 GitHub 上补充代码的链接。主题包括多种类型的神经网络、优化算法&计算性能、自然语言处理、推荐系统等等。当我有时间的时候,我很高兴能读完这本书。

播客

来自dataskeptic.com

数据怀疑论者

这是我听过的唯一一个数据科学播客,但它太有趣了!对于主持人来说,现在的一大焦点是机器学习的可解释性,但他也在他的最新章节中涵盖了其他相关主题(如对抗性神经网络和伦理算法设计)。有些插曲对我来说有点太深入了,但总体来说,它加深了我对该领域热门话题的理解,并有助于增加我对数据科学的热情。(数据怀疑论者)

其他的

数据科学会议

meetup.com网站,搜索你所在地区的数据科学会议(这主要适用于那些生活在大城市或大城市附近的人)*。我住在丹佛附近,我参加了一个为数据科学领域的女性举办的名为“代码和咖啡”的聚会这是一个与其他女性讨论数据科学的美好时光,这些女性要么已经在这个领域工作,要么希望进入这个领域。这个团队的领导者非常棒——他们真心希望帮助其他女性实现职业目标或她们的副业项目。

  • 由于冠状病毒疫情,目前没有安排见面会。但是,您仍然可以在他们的页面上搜索组。

就我在本文中包含的链接数量而言,有些链接肯定会在某个时候过期或更改。如果您发现某个链接不再有效,请在下面发表评论。此外,请随意评论您自己喜欢的免费资源,这些资源不在此列表中!

所有没有注明出处的图片都是我自己在 canva.com 制作的。

文档相似性算法初学者完全指南

原文:https://towardsdatascience.com/a-complete-beginners-guide-to-document-similarity-algorithms-75c44035df90?source=collection_archive---------18-----------------------

了解欧几里得距离、余弦相似度和皮尔逊相关度背后的代码和数学,为推荐引擎提供动力

照片由泰勒·尼克斯Unsplash 上拍摄

我已经在产品中部署了一些推荐系统。毫不奇怪,最简单的被证明是最有效的。

大多数推荐系统的核心是协同过滤。协同过滤的核心是文档相似性。

我们将介绍计算文档相似性的 3 种算法。

1)欧几里德距离
2)余弦相似度
3)皮尔逊相关系数

即使是对它们如何工作的一般直觉也会帮助你选择合适的工具来工作,并建立一个更智能的引擎。

这些算法的共同点

在我们讨论算法时,请记住这些警告。

  1. 计算在对象的矢量表示上进行。每个对象必须首先转换成一个数字向量。
  2. 一次计算一对向量之间的相似性/距离。
  3. 无论算法如何,特征选择都会对结果产生巨大影响。

欧几里得距离

简单地

欧几里德距离是多维空间中两点之间的距离。

更近的点彼此更相似。进一步的点彼此更不同。所以以上,马里奥和卡洛斯比卡洛斯和珍妮更相似。

我有意选择了二维(又名。特点:【财富,朋友】)因为容易剧情。我们仍然可以计算超过 2 维的距离,但是需要一个公式。

直观上,这种方法作为距离测量是有意义的。您将文档绘制成点,并且可以用尺子测量它们之间的距离。

用欧几里德距离比较城市

让我们比较三个城市:纽约、多伦多和巴黎。

多伦多= [3,7]
纽约= [7,8]
巴黎= [2,10]

特征向量包含两个特征:[population, temperature]。人口以百万计。温度单位是摄氏度。

现在,因为我们再次将问题框定为二维,我们可以用尺子测量点之间的距离,但我们将使用这里的公式。

无论是 2 维还是 1000 维,该公式都适用。

在 Python 中实现欧几里德距离

没有人比我更讨厌数学符号,但下面是欧几里得距离的公式。

原谅我的徒手画

让我们写一个函数来实现它并计算两点之间的距离。

from math import sqrtdef euclidean_dist(doc1, doc2):
    '''
    For every (x,y) pair, square the difference
    Then take the square root of the sum
    '''
    pre_square_sum = 0
    for idx,_ in enumerate(doc1):
        pre_square_sum += (doc1[idx] - doc2[idx]) ** 2

    return sqrt(pre_square_sum) toronto = [3,7]
new_york = [7,8] euclidean_dist(toronto, new_york)
#=> 4.123105625617661

好吧。多伦多和纽约之间的距离是4.12

使用 Sklearn 的欧几里德距离

我们上面写的函数效率有点低。Sklearn 使用 Numpy 实现了一个更快的版本。在生产中,我们只用这个。

toronto = [3,7]
new_york = [7,8]import numpy as np
from sklearn.metrics.pairwise import euclidean_distancest = np.array(toronto).reshape(1,-1)
n = np.array(new_york).reshape(1,-1)euclidean_distances(t, n)[0][0]
#=> 4.123105625617661

注意,它需要数组而不是列表作为输入,但是我们得到了相同的结果。布雅!

余弦相似性

简单地

余弦相似度是多维空间中两点之间夹角的余弦。角度越小的点越相似。角度越大的点差别越大。

虽然难以理解,余弦相似性解决了欧几里德距离的一些问题。即大小。

一篇文章中提到“烹饪”和“餐馆”的次数

在上图中,我们根据三个文档包含单词“cooking”和“restaurant”的次数来比较它们。

欧几里德距离告诉我们博客和杂志比博客和报纸更相似。但我认为这是误导。

博客和报纸可以有相似的内容,但在欧几里得意义上是遥远的,因为报纸更长,包含更多的单词。

在现实中,他们都更多地提到“餐馆”而不是“烹饪”,可能彼此更相似。余弦相似度不属于这个陷阱。

用余弦相似度比较书籍和文章

让我们完成上面的例子。我们将基于特定单词的计数来比较文档

magazine_article = [7,1]
blog_post = [2,10]
newspaper_article = [2,20]

我们现在从原点开始,取它们之间角度的余弦,而不是取它们之间的距离。现在,即使只是目测,博客和报纸看起来更相似。

在 Python 中实现余弦相似性

注意余弦相似度不是角度本身,而是角度的余弦。因此,较小的角度(小于 90 度)返回较大的相似性。

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

让我们自己实现一个函数来计算这个。

import numpy as np
from math import sqrtdef my_cosine_similarity(A, B):
    numerator = np.dot(A,B)
    denominator = sqrt(A.dot(A)) * sqrt(B.dot(B))
    return numerator / denominator

magazine_article = [7,1]
blog_post = [2,10]
newspaper_article = [2,20]m = np.array(magazine_article)
b = np.array(blog_post)
n = np.array(newspaper_article)

print( my_cosine_similarity(m,b) ) #=> 0.3328201177351375
print( my_cosine_similarity(b,n) ) #=> 0.9952285251199801
print( my_cosine_similarity(n,m) ) #=> 0.2392231652082992

现在我们看到,博客和报纸确实更加相似。

与 Sklearn 的余弦相似性

在生产中,我们最好导入 Sklearn 更高效的实现。

from sklearn.metrics.pairwise import cosine_similaritym = np.array(magazine_article).reshape(1,-1)
b = np.array(blog_post).reshape(1,-1)
n = np.array(newspaper_article).reshape(1,-1)print( cosine_similarity(m,b)[0,0] ) #=> 0.3328201177351375
print( cosine_similarity(b,n)[0,0] ) #=> 0.9952285251199801
print( cosine_similarity(n,m)[0,0] ) #=> 0.2392231652082992

相同的价值观。太好了!

皮尔逊相关

这通常量化了两个变量之间的关系。比如教育和收入。

完全虚构的数据

但是我们也可以用它来度量两个文档之间的相似性,我们将第一个文档的向量视为x,将第二个文档的向量视为y

因为皮尔逊相关系数r返回 1 和-1 之间的值,所以皮尔逊距离可以计算为1 — r以返回 0 和 2 之间的值。

用 Python 实现皮尔逊相关系数

让我们自己实现这个公式来理解它是如何工作的。

https://en . Wikipedia . org/wiki/皮尔逊相关系数

我们将生成一些代表少数人的假数据。我们将基于三特征向量来比较它们有多相似。

emily = [1,2,5]
kartik = [1,3,5]
todd = [5,3,5]

我们的实现。

import numpy as npdef pearsons_correlation_coef(x, y):
    x = np.array(x)
    y = np.array(y)

    x_mean = x.mean()
    y_mean = y.mean() x_less_mean = x - x_mean
    y_less_mean = y - y_mean

    numerator = np.sum(xm * ym)
    denominator = np.sqrt(
        np.sum(xm**2) * np.sum(ym**2)
    )

    return r_num / r_denpearsons_correlation_coef(emily,kartik)
#=> 0.9607689228305226

酷毙了。艾米莉和卡蒂克看起来很相似。我们一会儿将把这三个和 Scipy 进行比较。

皮尔逊相关系数与 Scipy

Scipy 实现了一种更高效、更健壮的计算。

emily = [1,2,5]
kartik = [1,3,5]
todd = [5,3,5]pearsonr2(emily,kartik)print( pearsonr2(emily, kartik) ) 
#=> (0.9607689228305226, 0.1789123750220673)
print( pearsonr2(kartik, todd) ) 
#=> (0.0, 1.0)
print( pearsonr2(todd, emily) ) 
#=> (0.27735009811261446, 0.8210876249779328)

虽然我选择了随机数作为数据点,但我们可以看到艾米丽和卡蒂克比艾米丽和托德更相似。

结论

虽然我们已经解决了这个难题的一部分,但是通往完全成熟的推荐器的道路还没有完成。

在电子商务引擎的上下文中,我们接下来将构建每对用户之间的相似性得分矩阵。然后我们可以用它来推荐相似用户购买的产品。

也就是说,一个好的推荐系统可能还包含基于领域的规则和用户偏好。

Python Numpy 数据科学矩阵乘法初学者完全指南

原文:https://towardsdatascience.com/a-complete-beginners-guide-to-matrix-multiplication-for-data-science-with-python-numpy-9274ecfc1dc6?source=collection_archive---------7-----------------------

通过 Python 示例学习机器学习的矩阵乘法

线性代数是从逻辑回归到深度神经网络的机器学习的基础。

如果你从事数据科学已经有一段时间了,但是不理解它背后的数学,矩阵乘法是最好的起点。它平易近人,实用,让你熟悉机器学习的数学对象:标量,向量和矩阵。

哦,是的,Numpy 在公园里散步。

到本文结束时,您将对矩阵乘法有一个实际的理解。

什么是矩阵

这里我们将对比矩阵和标量。

一个矩阵是一个 2D 数组,其中数组中的每个元素有 2 个索引。比如[[1, 2], [3, 4]]是一个矩阵,1的索引是(0,0)。

我们可以用 Python 和 Numpy 来证明这一点。

import numpy as npA = [[1, 2], 
     [3, 4]]np.array(A)**[0,0]**
=> 1

当谈到矩阵的形状时,我们说“行 x 列”。我们会说下面的第一个矩阵的形状是 2x2,第二个矩阵的形状是 3x2。

[[1, 2], 
 [3, 4]][[10, 20],
 [11, 21],
 [12, 22]]

相比之下,标量只是一个数字,就像数字5一样。

标量乘法

矩阵乘法的简单形式叫做标量乘法,将一个标量乘以一个矩阵。

标量乘法一般很容易。输入矩阵中的每个值都乘以标量,输出与输入矩阵的形状相同。

让我们用 Python 的 Numpy 来做上面的例子。

a = 7
B = [[1,2],
     [3,4]]np.dot(a,B)=> array([[ 7, 14],
=>        [21, 28]])

再举一个标量乘法的例子。这次是一个标量乘以一个 3×1 矩阵。

在 Numpy。

a = 4 
B = [[1],[2],[3]]np.dot(a,B)=> array([[ 4],
=>        [ 8],
=>        [12]])

标量乘法的顺序无关紧要。“标量 x 矩阵”和“矩阵 x 标量”给出了相同的结果。但当两个矩阵相乘时就不一样了

矩阵乘法

现在到了有趣的部分。将 2D 矩阵乘以 2D 矩阵。

有几件事需要记住。

  1. 现在秩序很重要。AB != BA
  2. 如果第一个矩阵的列数等于第二个矩阵的行数,则矩阵可以相乘
  3. 乘法是行和列的点积。第一个矩阵的行和第二个矩阵的列

示例 1

在上图中,输出矩阵的(0,0)索引中的19是第一个矩阵的第一行和第二个矩阵第一列的点积。

让我们用 Python 复制这个结果。

A = [[1,2],
     [3,4]]B = [[5,6],
     [7,8]]np.dot(A,B)=> array([[19, 22],
=>        [43, 50]])

让我们反复强调秩序这一点。试试np.dot(A,B)再试试np.dot(B,A)

np.dot(A,B)
=> array([[19, 22],
=>        [43, 50]])np.dot(B,A)
=> array([[23, 34],
=>        [31, 46]])

现在请注意输出是如何不同的!你会发现在纸上计算它会得到同样的结果(如果你不熟悉矩阵的话,这是很不直观的)。

示例 2

现在我们将一个 2×3 的矩阵乘以一个 3×2 的矩阵。

而在 Python 中用 Numpy。

A = [[1,2,3],
     [4,5,6]]B = [[10,11],
     [20,21],
     [30,31]]np.dot(A,B)=> array([[140, 146],
=>        [320, 335]])

示例 3

最后一个例子。将 1×5 乘以 5×1 矩阵。

请注意,我们在这里做的所有计算都只是返回输出矩阵中的一个单元格。

同样,在 Python 中。

A = [[1,2,3,4,5]]B = [[10],
     [20],
     [30],
     [40],     
     [50]]np.dot(A,B)=> array([[550]])

这涵盖了矩阵乘法的 3 种独特情况,应该能让你对它的工作原理有一个大致的了解。我在图表的每一步都展示了所有的计算,所以你很容易理解。

结论

矩阵乘法(和线性代数)是深度学习和机器学习的基础。

虽然你不需要它来即插即用 Sklearn,但对它的工作原理有一个清晰的印象将有助于你理解它的模型。有了这种理解,就可以更高效地调整这些模型,以获得更好的性能。

使用分类的机器学习完全入门

原文:https://towardsdatascience.com/a-complete-beginners-introduction-to-machine-learning-using-classification-c2ab1cfa7093?source=collection_archive---------45-----------------------

真诚媒体Unsplash 上拍摄的照片

如果你对数据科学、人工智能或机器学习领域感兴趣,但不知道该去哪里或做什么,那就别再找了。如果你想在大考或面试前温习你的 ML 技能,你来对地方了。这个关于机器学习的介绍,会涉及到行业内数据科学家每天使用的一些最流行的机器学习算法。到本文结束时,您应该会对机器学习的概念更加熟悉,并觉得有能力大胆尝试一些自己的模型。

机器学习基础

我们实施算法不是因为它们存在,我们实施算法是因为它们适合我们正在处理的数据。

-苏马纳·拉维克里希南

  1. 机器学习历史
  • 信不信由你,人工智能和机器学习的想法首次出现在 20 世纪 50 年代,当时艾伦·图灵引入了图灵测试的概念。投入人工智能的时间和金钱一直在波动,但人们对这个主题的兴趣空前高涨。

2.机器学习的类型

  • 监督学习:您的模型正在从您试图预测的结果中获得的示例数据中学习(想想 x 值和 y 值)。这意味着您已经对目标以及它如何处理输入数据有了概念。
  • 无监督学习:你的模型是从只有输入数据(基本上是没有 y 值的 x 值)的例子数据中学习的。因此,模型必须依靠自己的算法来检测观察值之间的模式。
  • 半监督学习:您的模型正在从带有“半监督”数据和“半非监督”数据(一些 x 值有 y 值,一些没有)的示例数据中学习。
  • 强化学习:你的模型正在从你试图预测的结果中获得的样本数据中学习——但是,该模型也从它在预测过程中收到的正面/负面反馈中学习。这种类型的学习与尝试和错误的想法有关。

3.监督学习的类型

  • 有两种主要类型的监督学习,分类和回归。尊重上面 Sumana 给出的建议并选择适合您正在处理的数据的算法是很重要的。这将决定你使用哪一种。
  • 分类:目标反应,或 y,是绝对的。例如,这可能是一个需要预测测试结果(通过/失败)、天气类型(晴天/下雨/刮风)或大学年份(大一/大二等)的模型。
  • 回归:目标响应,或 y,是连续的或数字的。在这种情况下,这可能是一个可以预测美元年薪或千克体重的模型。

4.假设检验

  • 假设检验由两个假设组成:零假设和替代假设。
  • 当我们进行假设检验时,我们从检验中得到的驱动我们最终决策的可量化结果被称为 p 值。
  • 显著性水平,或者我们希望在测试准确性上给自己留的回旋余地,被称为 alpha。
  • 这种检验的目的是探索零假设是否成立,或者正在讨论的数据是否提供了足够的信息,使我们能够拒绝零假设并接受替代假设。

数据本身并不有趣。我们真正感兴趣的是对数据的解释。

——苏马纳·拉维克里希南

朴素贝叶斯分类

  1. 分类
  • 分类是监督学习的一种形式,旨在预测分类变量(职业、团队名称、颜色等)。)

2.条件概率

  • 条件概率用于计算两个或更多相关事件发生的概率。
  • 相关事件是其结果相互之间有某种影响的事件
  • 例如,一个人从一副牌中抽出一张 k 和一张 8 的概率
  • 这个事件是相关的,因为取出一张牌会使牌堆变小,并且在第二次尝试时更容易得到你想要的那张牌。

3.贝叶斯定理

  • 在许多情况下,科学家需要知道一个事件发生的可能性。此外,他们通常有以前事件的数据来帮助他们的计算。贝叶斯定理来了,计算某个事件的概率,事件 B,给定一个已经发生的事件,事件 a。
  • 通过使 P (B|A)和 P (A|B)相等,并做一些重新排列,贝叶斯定理的公式变成:

照片由 WWCode 数据科学公司提供

4.朴素贝叶斯

  • 使用朴素贝叶斯时,您正在处理的数据集应分成两部分:
  • 要素(x)-数据集中会以某种方式影响结果变量的列。把这些想象成一堆潜在的“事件作为”。
  • 类变量(y)-数据集中我们试图预测或分类的列。将这些视为潜在的“事件 Bs”。
  • 你可能在想——为什么贝叶斯如此天真?这是因为该定理的这个特定版本假设数据集的每个要素都是独立的(意味着一个要素对另一个要素没有影响)。
  • 要使用朴素贝叶斯公式,您需要做的就是将表格数据转换为一个或多个列联表,这只是一个包含每个类别计数的表。这些计数将在适当的时候代入公式。

照片由 WWCode 数据科学公司提供

5.朴素贝叶斯变异

  • 朴素贝叶斯算法有许多变体,对于某些数据集来说非常方便。

高斯朴素贝叶斯

  • 当您有连续的数字特征时,您可以利用高斯朴素贝叶斯算法来预测分类结果。

多项式朴素贝叶斯

  • 当您有一堆文本数据要用来预测分类结果时,此算法非常有用。
  • 多项式朴素贝叶斯在计算中使用词频来进行预测。

贝叶斯网络

  • 当您想要更复杂地调查特征子集之间的条件概率时,贝叶斯网络很有帮助。

决策树和随机森林分类

1.决策树

  • 决策树是一种分类算法,它从数据集中学习一组规则,并使用它们进行预测。
  • 决策树就像一个流程图。

照片由 WWCode 数据科学公司提供

  • 一个根节点(正方形)和一个内部节点(圆形)都代表将要被询问的某种问题。天气晴朗吗?湿度是高、中还是低?
  • 分支(线)表示在根或叶节点处对问题的回答。答案决定了您从一个节点沿着哪个分支前进。是的,是晴天还是不是,不是晴天。
  • 叶节点(三角形)表示对正在讨论的数据点的最终预测。因为天气晴朗,湿度低,我们预测高尔夫球比赛将会举行。
  • 通过观察熵和信息增益这两个度量来构建决策树,这将在下面解释。

2.熵

  • 熵基本上是数据样本中不确定性的度量。
  • 可以这样想,如果你的数据集中所有 100 场高尔夫比赛都进行了,并且没有一场被取消,那么熵值很低…因为你对这场比赛是否会进行的怀疑很低。
  • 如果你的数据集中有 100 场高尔夫比赛,其中 50 场进行了,50 场取消了,这就是高熵。你对下一场比赛有很高的怀疑,因为数据是“命中或错过”。
  • 这个过程需要两个熵公式——目标响应的熵(上图)和给定某个特征 X 的目标响应的熵(下图)。

照片由 WWCode 数据科学公司提供

3.信息增益

  • 信息增益描述了我们通过向决策树添加节点来了解数据集的知识量。
  • 这里有一个真实的例子——假设下周有一场高尔夫球比赛。如果我们知道会下雨,那么我们的预测就会有很大的不同,因为下雨对高尔夫比赛取消有很大的影响。知道是否在下雨会产生很高的信息增益。
  • 信息增益的公式使用上面的公式。(这是有道理的,因为随着我们降低不确定性,我们获得了信息。)

照片由 WWCode 数据科学公司提供

4.建造圣诞树

  • 基本上,构建决策树的过程是这样的:计算数据样本中每个特征的潜在信息增益。选择具有最高信息增益的一个作为当前节点中的“决策”特征。对其余特征重复计算。
  • 一旦您的所有分支都指向一个叶节点(这意味着最终决策),您就可以停止。

5.优点和缺点

  • 决策树易于理解和解释,这使它们成为进行预测的直观方式。
  • 此外,它们是朴素贝叶斯的升级,因为特性并不被认为是同等重要的。决策树的整个思想是把最重要的特征放在第一位。
  • 然而,当类别标签开始增长时,决策树具有昂贵且复杂的计算。此外,他们无法估计缺失的数据。
  • 最后,决策树容易过度拟合,因为它们总是偏向于具有更多样本的类值。例如,如果您的数据样本中有 100 场高尔夫比赛,其中 87 场比赛的湿度较低,那么低湿度可能会导致比赛无法进行。

6.克服决策树的缺点

  • 减少决策树缺点的两种方法是剪枝和集成学习。
  • 修剪一棵树就是删除那些几乎没有预测能力的节点和分支。我们可以将这些分支视为“边缘情况”或“随机噪声”,因此切断它们可以减少过度拟合。
  • 集成学习是将多个“弱”机器学习模型放在一起以形成一个大型、性能更好的学习单元的过程。

7.随机森林

  • 随机森林是一种用于决策树的特定类型的集成学习。
  • 模型建立在数据的随机子集上,每个模型只关注特征的随机子集。
  • 每个单独的树(或“弱学习者”)将做出预测。森林中投票最多的结果将成为真正的预测。

照片由 WWCode 数据科学公司提供

我希望你喜欢这本初学者分类指南。如果你有兴趣将这些知识付诸实践,你可以看看为数据科学 Github 编写代码的女性,在那里她们有我们上面提到的每种机器学习算法的 Python 笔记本。

这篇文章是由从事数据科学编程的女性在为期六周的机器学习入门课程中发表的博文汇编而成。该系列的第一篇帖子最初发表于 2020 年 5 月 17 日https://data dreamer . io

完整的数据科学组合项目

原文:https://towardsdatascience.com/a-complete-data-science-portfolio-project-ebbced35ea84?source=collection_archive---------5-----------------------

我最新的端到端数据科学项目概述

马库斯·温克勒在 Unsplash 上的照片

在这篇文章中,我想展示我的有史以来最简单的数据科学项目

过去,我花了数小时训练一个复杂得多的模型,并努力寻找正确的参数来创建机器学习管道。

尽管很简单,但如果我只能在简历上展示一个项目,那就是这个项目。

我来解释一下原因。

包装决定礼物的价值吗?

小时候,我总是对假期感到兴奋,因为我可以得到礼物。就迁就我一下吧,我保证我确实有道理。我阿姨送给我这件漂亮的衣服,也许比我那天收到的任何礼物都漂亮。

但问题是——我甚至不想打开它。她用报纸破旧地包了起来,在我看到里面的东西之前,礼物似乎已经失去了一半的价值。

回答上面的问题,没有。包装绝不决定礼物的价值。

然而,它可以极大地影响你对里面东西的期望,并改变你对它的看法。

你花数周时间训练的机器学习模型很棒。证明一下。不要让它们死在你的笔记本里。

招聘人员有数百份简历要看。他们几乎不可能通读你在 GitHub 上的所有代码,理解你所有的项目。

要想脱颖而出,你需要做一些稍微不同的事情。创造一个他们可以互动的界面。也许他们可以玩一个实时仪表盘。

即使它不是最好的仪表板或界面,它也会引起人们的兴趣,因为你创造了他们实际上可以使用的东西。

我正是想这样做,这就是为什么我想出了这个投资组合项目。在接下来的几节中,我将详细解释我做了什么,而不会过多涉及技术细节。

目标

我的目标是展示以下领域的技能:

  • 数据收集
  • 数据争论
  • 数据可视化
  • 机器学习
  • Web 开发

为此,我在项目中创建了以下组件:

  • 前端接口
  • 电影仪表板
  • 电影推荐系统

我将详细解释和演示每个组件。

注意:如果你不想通读整篇文章,只想看一看最终产品,只需向下滚动,看一看“ 链接 ”部分。

前端接口

过去,我会创建项目,让代码放在我的 GitHub 存储库中。我偶尔写一篇文章来解释 Medium 上的项目。

在这里,我采取了不同的方法。

我创建了一个网页,并解释了我的项目的不同组成部分。我简要地写了用户如何与我创建的系统交互,并放上了我的代码和媒体文章的链接。

整个项目可以通过一个页面来理解和访问,这使得人们更容易参与其中。

你可以在这里查看笔记本电脑或个人电脑上的网站,以获得更好的用户界面体验。

电影仪表板

接下来,我用 Tableau 创建了一个电影仪表盘。

涉及的步骤:

数据收集

我不得不从各种不同的地方收集数据。我还想可视化这些电影的 Bechdel 分数(衡量好莱坞女性代表性的指标),所以我使用了一个 API 来获取这些数据。

数据争论

我清理了数据并将数据集合并在一起。一旦我完成了,我终于可以想象它了!

数据可视化

令人惊讶的是,与这个项目的其他部分相比,这占据了我很大一部分时间。

我花了两天时间试图创建一个视觉上吸引人的仪表板。

我用 Python Dash 应用程序创建了一个。我对布局不太满意,尝试用 R 语言创建一个闪亮的 web 应用程序。

它比我的 Dash 应用程序要好,我喜欢它的功能。然而,我根本不觉得这个设计有吸引力。

最后决定用 Tableau。这只花了我大约一个小时来创作。如果想入门 Tableau,可以看看我创作的这个教程

您可以在这里查看我的仪表板—在笔记本电脑或 PC 上查看以获得更好的 UI 体验

推荐系统

最后,机器学习!

我使用与仪表板相同的数据创建了一个简单的推荐系统,并将其部署到 Dash 应用程序中。

只需输入电影名称,它就会使用后端推荐系统为您生成电影建议。

其实这个推荐系统是我刚开始学机器学习的时候创建的。

我在我的 Jupyter 笔记本中找到了代码,并决定对其进行一些清理,以创建这个简单的应用程序。

你可以看看这里的推荐系统—在笔记本电脑或 PC 上查看,以获得更好的 UI 体验

就是这样!

链接

我希望你喜欢这篇文章,并发现上面的提示很有帮助。Jupyter 笔记本很棒,但是不要让你的项目就这么放在那里。

用你的创造力创造一些其他人可以与之互动的东西。

我在 GitHub 上看到过一些只有一颗星的不可思议的项目。另一方面,我也看到一些非常简单的项目仅仅因为它的呈现方式就获得了很多关注。

然而最重要的是,创建你喜欢做的项目,做你觉得有趣的事情!

关于使用 AWS Glue、Athena 和 QuickSight 的无服务器数据湖的完整指南

原文:https://towardsdatascience.com/a-complete-guide-on-serverless-data-lake-using-aws-glue-athena-and-quicksight-3a8a24cfa4af?source=collection_archive---------9-----------------------

无服务器数据湖

无服务器数据湖中 ETL 数据处理、查询和可视化的分步演练

照片由乔治·沙卡拉什维利Unsplash 上拍摄

在上一篇 文章 中,我们为流数据创建了一个无服务器的数据湖。我们处理流数据,使用 Kinesis Data Analytics 执行窗口功能,将其存储在 S3 上,使用 AWS Glue 创建目录,使用 AWS Athena 执行查询,最后在 QuickSight 上可视化。

现在让我们通过引入批量摄取来完成我们的 lambda 架构

关于 Lambda 架构的一些背景知识

Lambda 架构 是一种数据处理设计模式,用于处理海量数据,并将批处理和实时处理集成在一个框架内。Lambda 架构是一种混合批处理和流(实时)数据处理的方法,并通过服务层使组合数据可用于下游分析或查看。

待办事项

在本教程中,我将通过自动化批处理摄取工作流来完成我们的 Lambda 架构。

本文将涵盖以下内容:

  • 编写 Python Shell 作业以从本地文件服务器获取数据
  • 编写一个 Pyspark 作业来处理 upserts、到 parquet 的转换并创建分区
  • 运行爬网程序并更新数据目录
  • 通过粘合工作流程自动化粘合作业和爬虫
  • 在 AWS Athena 中编写分析查询
  • 使用 Lambda 函数更新 Quicksight 的数据源
  • 在 Quicksight 中创建视觉效果

解决方案概述

这篇帖子是我上一篇帖子的后续: 无服务器数据湖:使用 AWS 存储和分析流数据。我将使用相同的数据集芝加哥犯罪。该数据集包含 6M 条记录,重 2 GB。我们将把文件放在本地文件服务器上。Python Shell Glue 作业将被安排为每天运行,它将执行批处理摄取。它还将处理 CDC(变更数据捕获)。文件的初始加载完成后,我们将运行 ETL 作业来进行转换和分区数据存储。一旦我们的粘合工作完成,我们将运行我们的爬行器,以注册新创建的分区和模式更改。目录更新后,Athena 将使用 Glue Catalog 对 S3 数据进行查询。我们将使用 lambda 函数来更新 Quicksight 数据源。然后我们的图表会在 Quicksight 上更新。

这里是高层架构:

体系结构

步骤 1-创建您的数据接收作业

首先,我们需要一个数据转储自动化作业,从本地文件服务器的文件夹中取出文件,并将其转储到 S3 存储桶中。这一过程可以通过 Python-Shell Glue job 实现自动化,因为不需要对数据进行转换,而且它是简单的 I/O。我们将使用 python-shell job,该 job 在第一次运行时将执行满负荷,在后续运行时将仅转储新创建或更新的文件。

下面是 Glue Python-Shell 代码:

让我们深入代码,看看那里发生了什么。首先,我们正在导入 boto3 SDK。我们将使用 SSM 参数存储来存储文件服务器的凭证、存储桶路径、文件夹路径和上次 ETL 执行时间。要在参数存储中创建参数,只需登录 AWS 控制台,转到系统管理器,创建一个标准参数并保存其值。我已经分别创建了所有的参数,你可以做同样的事情或者用逗号分隔的值存储一个参数,然后在你的代码中分割它们。

以下是创建参数的方法:

参数存储 Gif

这里我只是加载所有的参数。

接下来,我们使用给定的凭证创建一个与 FTP 服务器的安全 ssh 连接,然后继续打开 SFTP 连接。

这里,我们正在设置 TransferConfig 参数。当上传、下载或复制文件或 S3 对象时,您可以将配置设置存储在boto 3 . S3 . transfer . transfer config对象中。对象被传递给一个传输方法(上传文件、下载文件等)。)在 Config=参数中。通常默认设置非常适合一般情况,但是您可以更改此配置来处理您的特殊情况。我正在设置以下参数:

  • multipart_threshold: 当文件大小超过 multipart_threshold 属性值时,会发生多部分传输。我已经设置为 100MB
  • multipart_chunksize: 多部分传输的每个部分的分区大小。我将它设置为 20MB,因为我的文件是 200MB(最大值),默认情况下 max_concurrency 是 10,我的线程得到了适当的利用。你可以根据你的上网带宽定制,增加并发。
config = TransferConfig(multipart_threshold=100 * MB, multipart_chunksize=10 * MB)

接下来,我将遍历文件服务器中的文件,并将它们的最后修改日期与我的 last_etl_execution_time 进行比较。每次我的作业成功完成时,它都会将 last_etl_execution_time 存储在参数存储中,以便下次我只加载 last_etl_execution_time 之后更新/创建的文件。

重要的一点

这里需要注意的重要一点是,我使用≥来比较时间,而不是更长,这有一个重要的原因:当我们在 SSM 注册我们的 last_etl_execution_time 时,完全有可能一些新文件上传到我们的文件服务器中,并与我们的 last_etl_execution_time 进行了相同的修改,因此我们需要使用≥来上传我们的 S3 桶中的那些文件,以便任何新文件也得到上传,同时,任何重复的文件都将被自动覆盖(默认的 S3 行为)。

所以总结一下,

  • 我们仅在 S3 上使用 last_etl_execution_time 上传新建或更新的文件。
  • 使用≥以便与我们的 last_etl_execution_time 具有相同修改日期的任何文件都不会丢失。

最后,我们正在更新我们在 SSM 的last _ ETL _ execution _ time。请记住,第一次执行这个作业时,它将执行满负荷,因此您需要将这个 last_etl_execution_time 设置为一个更早的日期。在我的场景中,我将其设置为 2000–01–01 00:00:00

ssm.put_parameter(Name='Last_ETL_Execution_Time', Value=str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')),
                  Type='String', Overwrite=True)

嗯,就是这样。到目前为止,我们已经完成了 Python-Shell 的工作,并将文件转储到了 S3 bucket 上。现在让我们转到数据的转换和分区。

步骤 2-创建 Pyspark ETL 作业

现在我们将创建一个 Pyspark 作业,该作业将获取更新的或新的文件,根据某个列对它们进行重新分区,并保存为bucket/year =/month =/格式和 parquet 格式。我们需要一种方法来跟踪着陆桶中已处理的数据。

使用工作书签跟踪已处理的数据

AWS Glue 通过保存作业运行的状态信息来跟踪在 ETL 作业的上一次运行中已经处理过的数据。该持久状态信息被称为作业书签。我们将为 Glue Pyspark 作业启用书签。

让我们去 AWS 控制台

步骤 1: 在 AWS Glue 控制台中创建一个新的 Pyspark 作业。

步骤 2: 附加一个具有所需权限的 IAM 角色。在我的例子中,我附加了 AmazonS3FullAccessAWSGlueServiceRoleCloudWatchLogsFullAccessamazonsmsmfullaccess策略

第三步:选择一个由你创作的新剧本。

第四步:在类型中选择 Spark ,在 ETL 语言中选择 Python

步骤 5: 在高级属性中,启用作业书签。

步骤 6: 其余配置可以保留默认配置,在运行和测试胶合作业时,您可以以较低的成本将最大容量更改为 2 个 dpu。

这里是我的配置的一瞥

粘附配置

现在让我们深入研究 ETL 脚本

这里是 Github 上传的代码。请关注或给一颗星:)

让我们一部分一部分地分解它:

  • 首先,我导入 Glue 库并创建 Glue 上下文。
  • 从目录表创建动态框架。如果您还没有创建表,您需要转到表>添加新表>手动添加列并定义文件的模式。
  • 将动态帧转换为数据帧以利用 spark SQL。
  • 然后,我创建分区键(月、日)并追加到现有的数据框中(不需要创建年份,因为它已经存在于数据集中)。
  • 在我们的bucket/year =/month =/data文件夹中,我们将存储按天分区的数据文件(每天单独的文件)。
  • 如果在源文件(本地文件服务器)中更新了文件,那么各个 S3 分区文件夹中的数据将被最新的数据覆盖(处理的更新)
  • 重新划分的数据帧被转换回动态帧并存储在 S3 桶中,其中提到了分区键和拼花格式。

这是我们的 Glue Pyspark 作业的输出

S3 桶数据

查看 S3 桶中的输出文件。数据以拼花格式按年和月进行分区。每个月文件夹中的每个文件都包含按天划分的犯罪数据。

创建你的爬虫

一旦您的工作完成,您需要在 S3 桶中注册新创建的分区。我们将使用这项工作的爬虫。如果您的模式从不改变,您可以使用batch_create_partition() glue api 来注册新的分区。更多信息,请参考我的博客这里。在这里,因为我们需要检测任何模式更改,所以我们将为这项工作运行一个 crawler。以下是爬虫的配置。

爬虫配置

运行此 crawler 来注册分区。接下来,我们将在工作流程中使用这个爬虫。

步骤 3:让我们用粘合工作流来编排粘合作业和触发器

工作流通过在粘合实体(触发器、爬行器和作业)之间建立依赖关系来实现 ETL 工作负载的编排。您可以在控制台上直观地跟踪工作流中不同节点的状态,从而更容易监控进度和解决问题。此外,您可以在工作流程中的实体之间共享参数。

通过使用工作流,您不必手动设置不同触发器、爬行器和粘合作业之间的流程

所以是时候了!我们应该创建一个工作流程。但是首先,我们需要决定执行流程。

ETL 执行流程

以上是我们的 ETL 执行流程。我们可以创建一个工作流,轻松监控进度并排除错误,而不是配置 Cloudwatch 事件并自行管理。

现在让我们创建第一个工作流程!!!

  • 转到 AWS Glue 控制台,选择工作流程。
  • 给它起个名字描述。点击添加

  • 选择您的工作流程并移至图表选项卡。
  • 选择添加触发器。
  • 选择添加新的,给它一个名称和描述。
  • 选择触发类型为计划。
  • 选择运行触发器的时间,然后单击添加。
  • 现在您可以添加一个将被触发的节点。添加您的 Python-Shell 作业。
  • 选择 Python-Shell 作业后,在它之后添加另一个触发器节点,并继续执行流程。最后,您的工作流将如下所示:

胶水工作流程

完成粘合工作流程后,您就可以运行您的工作流程了。

重要提示:完成教程后,不要忘记删除您的工作流,否则它将被安排在您设定的时间运行。

用亚马逊雅典娜分析数据

Amazon Athena 是一种交互式查询服务,它使得使用标准 SQL 分析亚马逊 S3 中的数据变得很容易。Athena 能够查询 CSV 数据。然而,Parquet 文件格式大大减少了查询数据的时间和成本。

现在来查询一些数据吧!!!

打开 Athena 的 AWS 管理控制台,连接你的数据库

让我们看看芝加哥每年的犯罪率是多少。

每年的犯罪率

我们将在 Athena 中创建视图,稍后将由 Quicksight 导入。您只需在查询请求中添加以下行。

CREATE OR REPLACE VIEW chicago_crimes_usecase1 AS

让我们来看看每月的犯罪率

CREATE OR REPLACE VIEW chicago_crimes_usecase3 AS
SELECT
  "date_format"("incident_date", '%M') "month"
, "primary" "primary_type"
, "count"(*) "count"
FROM
  chicago_crimes_batch_bucket
WHERE ("primary" IS NOT NULL)
GROUP BY "primary", "date_format"("incident_date", '%M')
ORDER BY "month" ASC

下面是查询结果:

每月犯罪率

让我们来看看芝加哥排名前五的犯罪趋势。

CREATE OR REPLACE VIEW chicago_crimes_usecase6 AS
SELECT
  "primary"
, "incident_year"
, "count"
FROM
  (
   SELECT
     "primary"
   , "incident_year"
   , "count"("primary") "count"
   , "row_number"() OVER (PARTITION BY "incident_year" ORDER BY "count"("primary") DESC) "rn"
   FROM
     chicago_crimes_batch_bucket
   WHERE ("incident_year" BETWEEN '2001' AND '2070')
   GROUP BY "primary", "incident_year"
)  tmp
WHERE ("rn" <= 5)
GROUP BY "primary", "incident_year", "count"
ORDER BY "incident_year" ASC

热门犯罪

我们也有位置数据,所以我们可以显示前 5000 个位置点,并确定哪些地方是热点犯罪区域。

QuickSight 在一张地理图上最多只能显示 5000 个位置点

CREATE OR REPLACE VIEW chicago_crimes_usecase8 AS
SELECT
  TRY(CAST("col20" AS double)) "latitude"
, TRY(CAST("col21" AS double)) "logitude"
FROM
  chicago_crimes_batch_bucket
WHERE (("col20" <> 'null') AND ("col21" <> 'null'))
LIMIT 5000

位置数据

您可以创建更多类似的查询并分析您的数据。将它们存储在视图中,接下来我们将在 QuickSight 中导入它们。

在我的 Github 上上传了其余的查询

是时候使用 QuickSight 进行一些数据可视化了

第一步:打开亚马逊 QuickSight 控制台如【1】所述。

第二步:第二步:设置亚马逊 QuickSight 账号设置访问雅典娜和你的 S3 桶。您可以查看[1]了解更多信息。

第三步:选择管理数据。

第四步:选择新数据集然后选择雅典娜

步骤 5: 输入您的数据源名称并选择您的视图。

第七步:这里你可以选择香料(缓存)。

第 8 步:你可以添加一个新的可视化,字段和指标。

这里有一些我用 Athena 的视图创建的样本图表。

快速浏览图表

您还可以创建报表可视化,就像这里的这个。它将为您提供雅典娜风格的查询输出外观。

Quicksight 报告可视化

QuickSight 仪表板中的计划数据刷新

您可以使用时间表自动刷新 SPICE 数据集。标准版或企业版可以选择每日每周每月

  • 每日:每天重复
  • 每周:每周的同一天重复
  • 每月:每月的同一天重复。要在每月的 29 日、30 日或 31 日刷新数据,从列表中选择每月的最后一天

仅限企业版,可以选择小时。此设置从您选择的时间开始,每小时刷新您的数据集。

但是,如果您想要维护数据集刷新的自定义计划,可以使用 AWS SDK Boto3 来实现。在 lambda 函数中运行下面的代码,并调度您的 lambda。

从上面的代码中得到的关键信息:

  • 过滤掉带有前缀“chicago_crimes”的数据集
  • 在第一个循环中为每个数据集启动数据集刷新过程
  • 检查第二个循环中每个数据集的状态

就是这样!

很棒吧?

在这个逐步演练中,我们使用 AWS Glue、AWS Athena 和 AWS QuickSight 开发了一个无服务器数据湖。我们执行了从摄取和治疗到可视化的每个步骤。

对于即将到来的故事,你应该关注我的简介。

当你点击并按住拍手按钮时,你想看到一些魔法吗?

  • 每当我发表一篇文章,就会收到一封 [电子邮件](http://Get an email whenever I publish an article) ,如果你喜欢这个故事,可以考虑成为 会员
  • 在 insta gram上与 45,000+ 其他关注者一起关注我,了解技术更新、谷歌的工作文化以及更多信息。
  • 48,000+ 人们在 Linkedin 上关注职业建议、技术建议和日常激励。

参考资料:

[1]https://AWS . Amazon . com/blogs/big-data/create-real-time-click stream-sessions-and-run-analytics-with-Amazon-kinesis-data-analytics-AWS-glue-and-Amazon-Athena/

深度学习推理的人工智能加速器完全指南——GPU、AWS 推理和亚马逊弹性推理

原文:https://towardsdatascience.com/a-complete-guide-to-ai-accelerators-for-deep-learning-inference-gpus-aws-inferentia-and-amazon-7a5d6804ef1c?source=collection_archive---------2-----------------------

了解 CPU、GPU、AWS 推理和 Amazon 弹性推理,以及如何为推理部署选择正确的 AI 加速器

如何选择—推理用 GPU、AWS 推理和亚马逊弹性推理(作者图解)

让我们从回答“什么是 AI 加速器”这个问题开始。

人工智能加速器是一种专用处理器,旨在加速机器学习计算。机器学习,特别是它的子集,深度学习主要由大量的线性代数计算组成,(即矩阵-矩阵,矩阵-向量运算),这些运算可以很容易地并行化。人工智能加速器是一种专门的硬件,旨在加速这些基本的机器学习计算,提高性能,减少延迟,并降低部署基于机器学习的应用程序的成本。

机器学习(ML)推理需要 AI 加速器吗?

假设你有一个 ML 模型作为你软件应用的一部分。预测步骤(或推断)通常是应用程序中最耗时的部分,会直接影响用户体验。一个需要数百毫秒来生成文本翻译或对图像应用过滤器或生成产品推荐的模型,可以让用户远离你的“迟缓”、“缓慢”、“令人沮丧”的应用。

通过加速推理,您可以减少应用程序的整体延迟,并提供可以用“流畅”、“爽快”和“令人愉快”来描述的应用程序体验。你可以通过将 ML 模型预测计算卸载到 AI 加速器来加速推断。

随着巨大的市场需求而来的是大量的替代产品,因此自然有多种方式来加速您在云中的 ML 模型。

在这篇博文中,我将探索三种流行的选择:

(作者插图)

  1. GPU:特别是高性能的英伟达 T4 和英伟达 V100 GPUs
  2. AWS 推理:AWS 定制设计的机器学习推理芯片
  3. Amazon Elastic Inference(EI):一个加速器,通过为不需要专用 GPU 的模型提供可变大小的 GPU 加速来节省成本

为您的工作负载选择正确的硬件加速类型可能是一个很难做出的选择。在这篇文章的其余部分,我将带您了解各种考虑因素,如目标吞吐量、延迟、成本预算、模型类型和大小、框架选择以及其他因素,以帮助您做出决策。我还将展示大量代码示例,并讨论开发人员友好性和选项的易用性。

免责声明:本文中的观点和建议是我自己的,不代表我现在或过去的雇主的观点。

一点硬件加速器的历史

(作者插图)

在计算的早期(70 年代和 80 年代),为了加快计算机上的数学计算,你将 CPU(中央处理器)与 FPU(浮点单元)配对,也就是数学协处理器。想法很简单——允许 CPU 将复杂的浮点数学运算卸载到专门设计的芯片上,这样 CPU 就可以专注于执行应用程序的其余部分,运行操作系统等。由于系统有不同类型的处理器(CPU 和数学协处理器),这种设置有时被称为异构计算。

快进到 90 年代,CPU 变得更快、更好、更高效,并开始配备集成浮点硬件。更简单的系统占了上风,而协处理器和异构计算对于普通用户来说已经过时了。

大约在同一时间,特定类型的工作负载开始变得更加复杂。设计师需要更好的图形,工程师和科学家需要更快的计算机进行数据处理、建模和模拟。这意味着对高性能处理器有一些需求(和市场),这种处理器可以比 CPU 更快地加速“特殊程序”,从而释放 CPU 来做其他事情。计算机图形是工作负载被卸载到特殊处理器的早期例子。你可能知道这种特殊的处理器的通用名,古老的 GPU。

2010 年代初,又出现了另一类工作负载——深度学习,或具有深度神经网络的机器学习——需要硬件加速才能实现,就像计算机图形一样。GPU 已经出现在市场上,经过多年的发展,已经变得高度可编程,不像早期的 GPU 是固定功能的处理器。自然地,ML 从业者开始使用 GPU 来加速深度学习训练和推理。

CPU 可以将复杂的机器学习操作卸载到人工智能加速器上(作者的插图)

如今的深度学习推理加速格局有趣多了。CPU 获得了对高级向量扩展(AVX-512)的支持,以加速深度学习中常见的矩阵数学计算。GPU 获得了新的功能,例如支持简化精度算法(FP16 和 INT8),进一步加快了推理速度。

除了 CPU 和 GPU,今天你还可以使用专门的硬件,定制设计的芯片只是为了深度学习推理而构建的。如果处理器支持您的工作负载,这些专用处理器,也称为专用集成电路或 ASICs,与通用处理器相比,性能更高,成本更低。这种专用处理器的一个很好的例子是 AWS Inferentia,这是 AWS 为加速深度学习推理而定制设计的 ASIC。

一开始,为您的应用选择正确的硬件加速可能并不明显。在下一节中,我们将讨论每种方法的优势和考虑事项,如吞吐量、延迟、成本和其他会影响您选择的因素。

人工智能加速器和如何选择正确的选项

很难回答“GPU 比 CPU 好吗?”或者“CPU 比 GPU 便宜吗”或者“ASIC 总是比 GPU 快吗”。实际上,没有一种硬件解决方案能适用于所有使用情形,答案取决于您的工作负载和几个考虑因素:

  1. 模型类型和可编程性:模型大小、定制操作符、支持的框架
  2. 目标吞吐量、延迟和成本:在预算范围内提供良好的客户体验
  3. 编译器和运行时工具链的易用性:应该有快速的学习曲线,不需要硬件知识

虽然模型支持和目标延迟等考虑是客观的,但易用性可能是非常主观的。因此,我反对不考虑上述所有具体应用的一般性建议。这种高水平的建议往往是有偏见的。

让我们回顾一下这些关键考虑事项。

1。型号类型和可编程性

(作者插图)

对人工智能加速器进行分类的一种方式是基于它们的可编程程度。在“完全可编程”的一端,有 CPU。作为通用处理器,你可以用定制的层、架构和操作为你的机器学习模型编写定制的代码。

另一个极端是 ASICs,如 AWS Inferentia,它通过 AWS Neuron SDK 编译器公开了一组固定的受支持操作。介于两者之间,但更接近 ASIC 的是 GPU,它比 ASIC 更具可编程性,但远不如 CPU 通用。在通用和提供性能之间总会有一些折衷。

定制代码可能会退回到 CPU 执行,从而降低整体吞吐量(作者的插图)

如果您正在通过自定义神经网络操作来拓展深度学习研究的边界,您可能需要为自定义操作编写自定义代码。你通常用像 Python 这样的高级语言来做这件事。

大多数人工智能加速器不能自动加速用高级语言编写的定制代码,因此这段代码将退回给 CPU 执行,降低了整体推理性能。

NVIDIA GPUs 的优势在于,如果你想提高自定义代码的性能,你可以使用 CUDA 编程语言重新实现它们,并在 GPU 上运行它们。但是如果你的 ASIC 的编译器不支持你需要的操作,那么 CPU 回退可能会导致较低的性能。

2。目标吞吐量、延迟和成本

一般来说,与通用处理器相比,专用处理器(如 AWS Inferentia)往往提供更低的性价比,并改善延迟。但在人工智能加速的世界里,所有的解决方案都可能是有竞争力的,这取决于工作负载的类型。

GPU 是吞吐量处理器,可以在指定的延迟时间内提供高吞吐量。如果延迟不重要(批处理、离线推理),那么 GPU 利用率可以保持在较高水平,使其成为云中最具成本效益的选项。CPU 不是并行吞吐量设备,但是对于较小模型的实时推理,CPU 可能是最具成本效益的,只要推理延迟低于您的目标延迟预算。如果您的模型完全受 AWS Neuron SDK compiler 支持,AWS Inferentia 的性能和较低的成本可能使其成为相对于 CPU 和 GPU 最具成本效益和性能的选择。

这确实是一个微妙的话题,并且非常依赖于工作负载。在接下来的章节中,我们将进一步了解每个加速器的性能、延迟和成本。如果某个特定的选择不适合你,没关系,在云中切换选项很容易,直到你找到适合你的选项。

3。编译器和运行时工具链以及易用性

为了在人工智能加速器上加速您的模型,您通常必须经历一个编译步骤,该步骤分析计算图形并针对目标硬件进行优化,以获得最佳性能。当部署在 CPU 上时,深度学习框架拥有您需要的一切,因此通常不需要额外的 SDK 和编译器。

如果你正在部署一个 GPU,你可以依靠深度学习框架来加速你的模型进行推理,但你将把性能留在桌面上。为了充分利用你的 GPU,你必须使用一个专用的推理编译器,比如 NVIDIA TensorRT。

(作者截图)

在某些情况下,与使用深度学习框架相比,您可以获得 10 倍以上的额外性能(见图)。我们将在后面的代码示例部分看到如何重现这些结果。

NVIDIA TensorRT 是两件事——推理编译器和运行时引擎。通过使用 TensorRT 编译您的模型,您可以获得更好的性能和更低的延迟,因为它执行了许多优化,如图形优化和量化。同样,当以 AWS 推理为目标时,AWS Neuron SDK 编译器将执行类似的优化,以充分利用您的 AWS 推理处理器。

让我们更深入地挖掘一下这些人工智能加速器选项

加速器选项 1:用于推理的 GPU 加速

(作者插画)

您在 GPU 上训练您的模型,因此很自然会考虑将 GPU 用于推理部署。毕竟,GPU 大大加快了深度学习训练,而推理只是你已经在 GPU 上加速的神经网络的向前传递。这是真的,GPU 确实是推理的优秀硬件加速器。

首先,我们来谈谈 GPU 到底是什么。

GPU 首先是吞吐量处理器,正如 NVIDIA 的这篇博客文章所解释的。它们旨在利用算法中固有的并行性,并通过并行计算来加速算法。GPU 最初是作为计算机图形的专用处理器出现的,但今天的 GPU 已经发展成为可编程处理器,也称为通用 GPU (GPGPU)。它们仍然是专门的并行处理器,但也是高度可编程的,用于可以通过并行化来加速的狭窄范围的应用。

事实证明,早在深度学习之前,高性能计算(HPC)社区就已经在使用 GPU 来加速线性代数计算了。深度神经网络计算主要由类似的线性代数计算组成,因此用于深度学习的 GPU 是寻找问题的解决方案。毫不奇怪,Alex Krizhevsky 的 AlexNet 深度神经网络赢得了 ImageNet 2012 竞赛,并(重新)向世界介绍了深度学习,它是在 NVIDIA 现成的可编程消费 GPU 上训练的。

自那以后,GPU 的速度变得更快了我会让你去 NVIDIA 的网站了解他们最新的流行机型的训练和推理基准。虽然这些基准很好地表明了 GPU 的能力,但您的决定可能取决于下面讨论的其他因素。

1。GPU 推理吞吐量、延迟和成本

由于 GPU 是吞吐量设备,如果您的目标是最大限度地提高吞吐量,它们可以根据所需的延迟提供同类最佳的吞吐量,具体取决于部署的 GPU 类型和型号。GPU 大放异彩的一个用例是离线或批量推理。GPU 还将为小批量预测提供一些最低的延迟,但如果您无法始终将 GPU 利用率保持在最高水平,例如由于零星的推理请求(波动的客户需求),您的成本/推理请求会上升(因为您为相同的 GPU 实例成本提供的请求较少)。对于这些情况,您最好使用 Amazon Elastic Inference,它可以让您以较低的成本获得足够的 GPU 加速。

在示例部分,我们将看到不同精度(FP32、FP16、INT8)的 GPU 性能比较。

2。GPU 推理支持的模型大小和选项

在 AWS 上,您可以使用不同的 NVIDIA GPUs、vCPUs 数量、系统内存和网络带宽启动 18 个不同的 Amazon EC2 GPU 实例。两种最受欢迎的深度学习推理 GPU 是 G4 EC2 instance type 提供的英伟达 T4 GPU 和 P3 EC2 instance type 提供的英伟达 V100 GPUs。

博文:为 AWS 上的深度学习选择合适的 GPU(作者截图)

关于 AWS 所有 GPU 实例类型的完整总结,请阅读我之前的博客文章:为 AWS 上的深度学习选择正确的 GPU

G4 实例类型应该是深度学习推理部署的首选 GPU 实例。

基于英伟达图灵架构,英伟达 T4 GPU 具有 FP64、FP32、FP16、张量内核(混合精度)和 INT8 精度类型。它们还拥有 16 GB 的 GPU 内存,对于大多数型号来说已经足够了,并结合了降低的精度支持。

如果您需要更大的吞吐量或每个 GPU 需要更多的内存,那么 P3 实例类型提供了更强大的 NVIDIA V100 GPU,通过p3dn.24xlarge实例大小,您可以访问 NVIDIA V100,它具有高达 32 GB 的 GPU 内存,可用于大型模型或大型图像或其他数据集。

3.GPU 推理模型类型、可编程性和易用性

与固定功能处理器的 AWS Inferentia 等 ASICs 不同,开发人员可以使用 NVIDIA 的 CUDA 编程模型来编写自定义层,这些层可以在 NVIDIA GPU 上加速。这正是 Alex Krizhevsky 在 2012 年对 AlexNet 所做的。他手工编写定制的 CUDA 内核,在 GPU 上训练他的神经网络。他称他的框架为 cuda-convnet,你可以说 cuda-convnet 是第一个深度学习框架。如果你正在推动深度学习的边界,并且不想将性能留在桌面上,GPU 是你的最佳选择。

可编程性与性能是 GPU 最大的优势之一

使用 NVIDIA 的 CUDA 编程模型来编写可以在 NVIDIA GPU 上加速的自定义层。(作者插图)

当然,你不需要写低级别的 GPU 代码来做深度学习。NVIDIA 已经通过 cuDNN 和 cuBLAS 等库提供了神经网络原语,TensorFlow、PyTorch 和 MXNet 等深度学习框架在幕后使用这些库,因此您只需使用这些框架就可以免费获得 GPU 加速。这就是 GPU 在易用性和可编程性方面获得高分的原因。

4.NVIDIA TensorRT 的 GPU 性能

如果你真的想让你的 GPU 发挥最佳性能,NVIDIA 提供了 TensorRT,一个用于推理部署的模型编译器。对经过训练的模型进行额外的优化,完整的列表可在 NVIDIA 的 TensorRT 网站上找到。需要注意的关键优化是:

  • 量化:将模型精度从 FP32(单精度)降低到 FP16(半精度)或 INT8 (8 位整数精度),从而减少计算量,加快推理速度
  • 图形融合:在 GPU 上将多个层/操作融合成一个对 CUDA 内核的函数调用。这减少了每个层/操作的多个函数调用的开销

使用 NVIDIA TensorRT 部署 FP16 非常简单。TensorRT 编译器将在编译步骤中自动量化您的模型。

要使用 INT8 precision 进行部署,需要量化模型的权重和激活,以便可以使用适当的范围将浮点值转换为整数。你有两个选择。

  • 选项 1 :执行量化感知训练。在量化感知训练中,从量化权重和张量到 INT8 的误差在训练期间被建模,允许模型适应和减轻该误差。这需要在培训期间进行额外的设置。
  • 选项二:进行训练后量化。在量化后培训中,不需要任何部署前准备。您将提供全精度(FP32)的训练模型,还需要提供训练数据集中的数据集样本,TensorRT 编译器可以使用该样本来运行校准步骤以生成量化范围。在下面的示例 2 中,我们将看看选项 2 的实现。

GPU 加速推理示例

使用以下 AWS 深度学习 AMI 在亚马逊 EC2 g4dn.xlarge上测试了以下示例:深度学习 AMI (Ubuntu 18.04)版本 35.0。为了运行 TensorRT,我使用了以下 NVIDIA TensorFlow Docker 映像:nvcr.io/nvidia/tensorflow:20.08-tf2-py3

数据集:50000 张测试图片的 ImageNet 验证数据集,转换为 TFRecord
模型:resnet 50 的 TensorFlow 实现

您可以在 Jupyter 笔记本上找到以下示例的完整实现:

https://github . com/shashankprasanna/ai-accelerators-examples/blob/main/GPU-TF-tensorrt-resnet 50 . ipynb

示例 1:部署 ResNet50 TensorFlow 模型(1)框架的原生 GPU 支持和(2)NVIDIA tensort

TensorFlow 的原生 GPU 加速支持开箱即用,无需额外设置。您不会获得 NVIDIA TensorRT 所能提供的额外性能,但当一切正常工作时,生活会变得多么轻松,这一点毋庸置疑。

使用框架的本地 GPU 支持运行推理需要 3 行代码:

model = tf.keras.models.load_model(saved_model_dir)for i, (validation_ds, batch_labels, _) in enumerate(dataset):
    pred_prob_keras = model(validation_ds)

但是你真的把性能留在桌面上了(有时是性能的 10 倍)。为了提高 GPU 的性能和利用率,您必须使用推理编译器和运行时,如 NVIDIA TensorRT。

下面的代码展示了如何用 TensorRT 编译您的模型。你可以在 GitHub 上找到的完整实现

摘自:https://github . com/shashankprasanna/ai-accelerators-examples/blob/main/GPU-TF-tensorrt-resnet 50 . ipynb(作者截图)

TensorRT 编译有以下步骤:

  1. 向 TensorRT 的TrtGraphConverterV2(用于 TensorFlow2)提供您未编译的 TensorFlow 保存模型
  2. 指定 TensorRT 编译参数。最重要的参数是精度(FP32、FP16、INT8)。如果您正在使用 INT8 支持进行编译,TensorRT 希望您从训练集中提供一个代表性样本来校准比例因子。当您调用converter.convert()时,您将通过为参数calibration_input_fn提供一个 python 生成器来实现这一点。您不需要为 FP32 和 FP16 优化提供额外的数据。
  3. TensorRT 编译您的模型并将其保存为 TensorFlow 保存的模型,该模型包括特殊的 TensorRT 运算符,可加速 GPU 上的推理并更有效地运行它们。

以下是 TensorFlow ResNet50 推理的准确性和性能对比:

  1. TensorFlow 原生 GPU 加速
  2. tensor flow+tensort FP32 精度
  3. tensor flow+tensort FP16 精度
  4. tensor flow+tensort int 8 精度

(作者截图)

我测量的不仅仅是性能,还有精度,因为降低精度意味着信息的损失。在 ImageNet 测试数据集上,我们看到所有精度的精度损失可以忽略不计,而吞吐量略有增加。您的里程可能因型号而异。

示例 2:使用 Amazon SageMaker 托管 ResNet50 TensorFlow 模型

在示例 1 中,我们离线测试了性能,但是在大多数情况下,您将在云中托管您的模型,作为客户端应用程序可以向其提交推理请求的端点。最简单的方法之一是使用 Amazon SageMaker 托管功能。

这个例子是在亚马逊 SageMaker Studio 笔记本上测试的。使用以下亚马逊 SageMaker Studio conda 环境运行该笔记本:TensorFlow 2 CPU 优化。完整的实现可从以下网址获得:

https://github . com/shashankprasanna/ai-accelerators-examples/blob/main/sage maker-TF-CPU-GPU-ei-resnet 50 . ipynb

使用 SageMaker 托管模型端点包括以下简单步骤:

  1. 使用您的 TensorFlow 保存的模型创建 tar.gz 存档文件,并将其上传到亚马逊 S3
  2. 使用 Amazon SageMaker SDK API 创建一个 TensorFlowModel 对象
  3. 使用英伟达 T4 GPU 将 TensorFlowModel 对象部署到 G4 EC2 实例

使用 TensorFlow 保存的模型创建 model.tar.gz:

$ tar cvfz model.tar.gz -C resnet50_saved_model .

将模型上传到 S3 并部署:

您可以通过调用端点来测试模型,如下所示:

输出:

加速器选项 2: AWS 推理

(作者插画)

AWS 推理是亚马逊设计的定制芯片,用于经济高效、高吞吐量、低延迟的推理。

詹姆斯·汉密尔顿(AWS 副总裁兼杰出工程师)在他的博客文章 AWS 推理机器学习处理器中深入探讨了 ASICs、通用处理器、AWS 推理以及围绕它们的经济学,如果你对人工智能硬件感兴趣,我鼓励你阅读这篇文章。

针对特定工作负载使用特定处理器的想法并不新鲜。降噪耳机中的芯片和 DVD 播放器中的视频解码器是专用芯片的例子,有时也称为专用集成电路(ASIC)。

ASICs 有一项工作(或有限的责任),并被优化来做好它。与通用处理器(CPU)或可编程加速器(GPU)不同,大部分芯片并不专用于运行任意代码。

AWS 推理是专门为在云中以最低的成本提供高推理性能而构建的。AWS 推理芯片可以通过 Amazon EC2 Inf1 实例访问,这些实例有不同的大小,每个实例有 1 个 AWS 推理芯片,每个实例最多有 16 个 AWS 推理芯片。每个 AWS 推理芯片有 4 个神经元,支持 FP16、BF16 和 INT8 数据类型。NeuronCore 是一个高性能的脉动阵列矩阵乘法引擎,每个都有一个两级内存层次,一个非常大的片上缓存。

在大多数情况下,如果您的模型:

  • 曾在 MXNet、TensorFlow、PyTorch 接受培训或已转换为 ONNX
  • 拥有由 AWS Neuron SDK 支持的操作符

如果您有 AWS Neuron SDK 不支持的操作符,您仍然可以在 Inf1 实例上成功地部署它,但是这些操作将在主机 CPU 上运行,并且不会在 AWS Inferentia 上加速。正如我前面所说的,每个用例都是不同的,所以用 AWS Neuron SDK 编译您的模型,并测量性能,以确保它满足您的性能、延迟和吞吐量需求。

1.AWS 推理吞吐量、延迟和成本

AWS 比较了流行模型的 AWS 推理与 GPU 实例的性能,并报告了流行模型的较低成本: YOLOv4 模型OpenPose ,并提供了 TensorFlow、MXNet 和 PyTorch 的 BERT 和 SSD 的示例。对于实时应用程序,AWS Inf1 实例是 AWS 上可用的所有加速选项中最便宜的,与 GPU 和 CPU 相比,AWS Inferentia 可以在目标延迟下以更低的成本提供更高的吞吐量。最终,您的选择可能取决于下面讨论的其他因素。

2。AWS 推理支持的模型、运算符和精度

AWS 推理芯片支持通过 AWS Neuron SDK 公开的一组固定的神经网络操作符。当您使用 AWS Neuron SDK 编译一个面向 AWS 推理的模型时,编译器将检查您的模型中是否有您的框架支持的操作符。如果不支持某个操作符,或者如果编译器确定某个特定操作符在 CPU 上执行效率更高,它将对图形进行分区,以包括 CPU 分区和 AWS 推理分区。亚马逊弹性推理也是如此,我们将在下一节讨论。如果您将 TensorFlow 与 AWS 推理一起使用,这里列出了所有在 AWS 推理上加速的 TensorFlow 操作。

定制操作将是 CPU 分区的一部分,并将在主机实例的 CPU 上运行(作者的插图)

如果您在 FP32(单精度)中训练您的模型,AWS Neuron SDK 编译器会自动将您的 FP32 模型转换为 BF16 以提高推理性能。如果您更喜欢在 FP16 中提供模型,无论是通过在 FP16 中训练还是通过执行训练后量化,AWS Neuron SDK 将直接使用您的 FP16 权重。虽然 INT8 受 AWS 推理芯片支持,但 AWS Neuron SDK 编译器目前不提供支持 INT8 的部署方式。

3。AWS 推理灵活性和对如何使用推理神经元的控制

在大多数情况下,AWS Neuron SDK 使 AWS 推理真正易于使用。使用 AWS 推理和 GPU 的用户体验的一个关键区别是,AWS 推理让您可以更好地控制每个内核的使用方式。

AWS Neuron SDK 支持两种利用所有 NeuronCores 提高性能的方式: (1)批处理(2)流水线。因为 AWS Neuron SDK 编译器是一个超前编译器,所以您必须在编译阶段显式启用这些选项。

让我们看看这些是什么以及它们是如何工作的。

a .使用批处理来最大化较大批量的生产量

当您使用 AWS Neuron SDK 编译器编译一个大于 1 的模型时,批处理将被启用。在推理过程中,您的模型权重存储在外部存储器中,当开始向前传递时,由神经元运行时确定的层权重子集被复制到片上缓存中。使用缓存中该图层的权重,对整个批次计算向前传递。

(作者插图)

之后,将下一组图层权重加载到缓存中,并对整个批次计算向前传递。这个过程继续进行,直到所有的权重都用于推理计算。当层仍在缓存中时,通过对大批量进行推理,批处理允许更好地分摊从外部存储器读取权重的成本。

所有这些都发生在后台,作为用户,您只需在编译期间使用示例输入设置所需的批处理大小。

即使批处理大小是在编译阶段设置的,在启用动态批处理的情况下,模型也可以接受可变大小的批处理。在内部,neuron runtime 将把用户批量分解为编译后的批量,并运行推理。

b .使用流水线技术,通过跨多个神经元缓存模型来改善延迟

在批处理期间,模型权重从外部存储器逐层加载到片内缓存。借助流水线技术,您可以将整个模型权重加载到多核的片上缓存中。这可以减少延迟,因为神经元运行时不必从外部存储器加载权重。同样,所有这些都发生在幕后,作为用户,您只需在编译阶段使用—-num-neuroncores设置所需的内核数量。

(作者插图)

批处理和流水线可以一起使用。但是,您必须尝试不同的流水线内核和编译批处理大小的组合,以确定最适合您的模型的组合。

在编译步骤中,批次大小和神经元核心数量的所有组合(对于流水线)可能都不适用。您必须通过扫描不同的值并监控编译器错误来确定批处理大小和神经元核心数量的工作组合。

在你的 Inf1 实例上使用所有神经核心

根据您编译模型的方式,您可以:

  1. 编译您的模型,以便在具有特定批处理大小的单个 NeuronCore 上运行
  2. 通过管道将模型编译到具有特定批处理大小的多个神经元

成本最低的 Amazon EC2 Inf1 实例类型,inf1.xlarge有 1 个 AWS 推理芯片和 4 个神经元。如果您将模型编译为在单个 NeuronCore 上运行,tensorflow-neuron将自动在所有 4 个 neuron core 上并行执行数据。这相当于将您的模型复制 4 次,并将其加载到每个 NeuronCore 中,然后运行 4 个 Python 线程将数据输入到每个核心中。自动数据并行执行在 1 AWS 推理芯片之外不起作用。例如,如果您想将您的模型复制到一个inf1.6xlarge上的所有 16 个神经元,您必须生成多个线程来向所有 AWS 推理芯片提供数据。在 python 中你可以使用concurrent . futures . threadpoolexecutor

(作者截图)

当你为多个神经核心编译一个模型时,运行时将为每个神经核心分配不同的子图(作者截图)

当你用流水线编译一个模型时,运行时会给每个 NeuronCore 分配不同的子图(作者截图)

4。在 Inf1 实例上部署多个模型

AWS Neuron SDK 允许您将神经元分组到逻辑组中。每组可以有一个或多个神经元,可以运行不同的模型。例如,如果您在 inf1.6xlarge EC2 Inf1 实例上进行部署,您可以访问 4 个推理芯片,每个芯片有 4 个神经内核,即总共有 16 个神经内核。你可以把 16 个神经元分成 3 组。第 1 组有 8 个神经元核心,将运行一个使用流水线来使用所有 8 个核心的模型。第 2 组使用 4 个神经元核心,运行用 1 个神经元核心编译的模型的 4 个副本。第 3 组使用 4 个神经元核,并运行用 2 个神经元核通过流水线编译的模型的 2 个副本。您可以使用 neuron core _ GROUP _ size 环境变量来指定此配置,并将其设置为 NEURONCORE _ GROUP _ SIZES =,1,1,1,1,2,2

之后,您只需在单个 python 进程中按指定顺序加载模型,即首先加载编译为使用 8 个内核的模型,然后加载编译为使用 1 个内核的模型四次,然后使用加载编译为使用 2 个内核的模型两次。适当的核心将被分配给模型。

Amazon EC2 Inf1 实例上的 AWS 推理加速推理示例

AWS Neuron SDK 预装在 AWS 深度学习 AMI 上,你也可以安装 SDK 和神经元加速的框架和库 TensorFlow、TensorFlow Serving、TensorBoard(带神经元支持)、MXNet 和 PyTorch。

下面的例子是在亚马逊 EC2 Inf1.xlarge和深度学习 AMI(Ubuntu 18.04)35.0 版本上测试的。

您可以在 Jupyter 笔记本上找到以下示例的完整实现:

https://github . com/shashankprasanna/ai-accelerators-examples/blob/main/in f1-neuron-SDK-resnet 50 . ipynb

示例 1:在 AWS 推理系统上部署带有 AWS Neuron SDK 的 ResNet50 TensorFlow 模型

在这个例子中,我比较了 3 个不同的选项

  1. 无批处理,无流水线:编译 ResNet50 模型,批量= 1,核数= 1
  2. 有批处理,无流水线:编译 ResNet50 模型,批处理大小= 5,内核数= 1
  3. 无批处理,带流水线:编译 ResNet50 模型,批量= 1,核数= 4

你可以在这个 Jupyter 笔记本中找到完整的实现。我就在这里回顾一下结果。

下面的比较表明,在 Inf1.xlarge 实例上,使用选项 2(批处理大小= 1,无流水线)可以获得最佳吞吐量。您可以在大型 Inf1 实例上用其他组合重复这个实验。

(作者截图)

加速器选项 3:亚马逊弹性推理(EI)推理加速

亚马逊弹性推理(作者插图)

亚马逊弹性推理(EI) 允许您向纯 CPU 实例添加经济高效的可变大小 GPU 加速,而无需配置专用的 GPU 实例。要使用 Amazon EI,您只需提供一个纯 CPU 实例,如 Amazon EC2 C5 实例类型,并在发布时从 6 个不同的 EI 加速器选项中进行选择。

EI 加速器不是构成您的 CPU 实例的硬件的一部分,相反,EI 加速器通过使用 AWS PrivateLink 端点服务的网络连接,该服务将流量从您的实例路由到使用您的实例配置的弹性推理加速器。当您使用支持 EI 的服务框架(如 TensorFlow serving)时,所有这些都在幕后无缝发生。

弹性推理允许您访问可变大小的 GPU 加速(作者插图)

Amazon EI 使用 GPU 来提供 GPU 加速,但与专用 GPU 实例不同,您可以选择添加 6 种不同加速器大小的 GPU 加速,您可以通过每秒万亿次浮点运算(TFLOPS)或 GPU 内存来选择。

为什么选择 Amazon EI 而不是专用 GPU 实例?

正如我前面所讨论的,GPU 主要是吞吐量设备,当处理实时应用程序常见的较小批量时,当您部署不需要 GPU 的全部处理能力或全部内存的模型时,GPU 往往得不到充分利用。此外,如果您没有足够的需求或多个模型来服务和共享 GPU,那么单个 GPU 可能不具成本效益,因为成本/推理会上升。

您可以从 6 种不同的 EI 加速器中进行选择,这些加速器提供 1–4 TFLOPS 和 1–8 GB 的 GPU 内存。假设您有一个计算要求较低的模型,内存占用较小,您可以将最小的 EI 加速器(如eia1.medium)连接到一个 CPU 实例,该加速器提供 1 TFLOPS 的 FP32 性能和 1 GB 的 GPU 内存。如果您有一个要求更高的模型,您可以将一个具有 4 TFLOPS 性能和 8 GB GPU 内存的eia2.xlarge EI 加速器附加到一个 CPU 实例上。

CPU 实例+ EI 加速器的成本仍然比专用 GPU 实例便宜,并且可以降低推理成本。您不必担心 GPU 利用率的最大化,因为您添加的容量刚好满足需求,不会过度配置。

什么时候选择亚马逊 EI 而不是 GPU,选择什么样的 EI 加速器尺寸?

让我们考虑下面的假设场景。比方说,如果您的总延迟(应用+网络+模型预测)低于 200 毫秒,您的应用可以提供良好的客户体验。比方说,使用 G4 实例类型,您可以将总延迟降至 40 毫秒,这完全在您的目标延迟范围内。您还尝试了使用纯 CPU C5 实例类型进行部署,您只能获得 400 毫秒的总延迟,这不符合您的 SLA 要求,导致客户体验不佳。

通过弹性推理,您可以将足够的 GPU 加速通过网络连接到一个 CPU 实例。在探索了不同的 EI 加速器尺寸(比如eia2.mediumeia2.largeeia2.xlarge)之后,您可以使用eia2.large EI 加速器将总延迟降至 180 毫秒,低于预期的 200 毫秒。由于 EI 比配置专用 GPU 实例便宜得多,因此您可以节省总部署成本。

1。亚马逊弹性推理性能

由于 GPU 加速是通过网络添加的,因此与专用 GPU 实例相比,EI 会增加一些延迟,但仍比纯 CPU 实例更快,并且比专用 GPU 实例更具成本效益。与 EI 相比,专用 GPU 实例仍将提供更好的推理性能,但如果额外的性能没有改善您的客户体验,使用 EI 您将保持在目标延迟 SLA 之下,提供良好的客户体验,并节省总体部署成本。AWS 有许多博客帖子,谈论与使用流行的深度学习框架的 CPU 和 GPU 相比的性能和成本节省

2。支持的型号类型、可编程性和易用性

亚马逊 EI 支持在 TensorFlow、Apache MXNet、Pytorch 和 ONNX 模型上训练的模型。在您启动一个连接了 Amazon EI 的 Amazon EC2 实例后,要访问加速器,您需要一个支持 EI 的框架,比如 TensorFlow、PyTorch 或 Apache MXNet。

支持 EI 的框架预装在 AWS 深度学习 AMI 上,但如果你更喜欢手动安装,Python wheel 文件也已可用。

大多数流行的模型,如 Inception,ResNet,SSD,RCNN,GNMT,都经过测试,在与 Amazon EI 一起部署时,可以节省成本。如果您正在部署带有自定义操作符的自定义模型,则支持 EI 的框架会对图形进行分区,以便在主机 CPU 上运行不支持的操作符,并在通过网络连接的 EI 加速器上运行所有支持的操作。这使得使用 EI 非常简单。

示例:使用 Amazon EI 部署 ResNet50 TensorFlow 模型

这个例子是在亚马逊 EC2 c5.2xlarge 下面的 AWS 深度学习 AMI 上测试的:深度学习 AMI (Ubuntu 18.04)版本 35.0

您可以在此处找到 Jupyter 笔记本的完整实现:

https://github . com/shashankprasanna/ai-accelerators-examples/blob/main/ei-tensor flow-resnet 50 . ipynb

Amazon EI enabled TensorFlow 提供的 API 允许您使用 EI 加速器加速模型,其行为就像 TensorFlow API 一样。作为一名开发人员,您应该尽可能少地修改代码。

要加载模型,只需运行以下代码:

from ei_for_tf.python.predictor.ei_predictor import EIPredictoreia_model = EIPredictor(saved_model_dir,accelerator_id=0)

如果有多个 EI 加速器连接到您的实例,您可以使用 accelerator_id 参数来指定它们。只需用 eia_model 替换 TensorFlow 模型对象,脚本的其余部分保持不变,您的模型现在在 Amazon EI 上加速了。

下图比较了在同一个 CPU 实例上的纯 CPU 推理和 EI 加速推理。在本例中,您可以看到使用 EI 加速器后速度提高了 6 倍以上。

(作者截图)

摘要

如果我想让你从这篇博文中学到什么,那就是:部署需求是独一无二的,没有放之四海而皆准的方法。回顾您的部署目标,将它们与本文中的讨论进行比较,并测试所有选项。云让你在提交之前尝试变得简单。

在选择时,请牢记以下注意事项:

  • 模型类型和可编程性(模型大小、自定义操作符、支持的框架)
  • 目标吞吐量、延迟和成本(在预算范围内提供良好的客户体验)
  • 编译器和运行时工具链的易用性(快速学习曲线,不需要硬件知识)

如果可编程性非常重要,并且您的性能目标较低,那么 CPU 可能正好适合您。

如果可编程性和性能很重要,那么您可以为在 GPU 上加速的定制操作开发定制 CUDA 内核。

如果您想要最低成本的选项,并且您的模型在 AWS 推理上受支持,那么您可以节省总体部署成本。

易用性是主观的,但没有什么能打败原生框架体验。但是,稍加努力,AWS Neuron SDK for AWS Inferentia 和 NVIDIA TensorRT for NVIDIA GPUs 都可以提供更高的性能,从而降低成本/推理。

感谢您的阅读。在本文中,我只能给你一瞥我们在本文中讨论的所有样本代码。如果您想重现结果,请访问以下 GitHub repo:

https://github . com/shashankprasanna/ai-accelerators-examples

如果你觉得这篇文章有趣,请看看我在媒体上的其他博文。

想让我写一个特定的机器学习主题吗?我很想收到你的来信!在 twitter ( @shshnkp ), LinkedIn 关注我或者在下面留言评论。

置信区间的完整指南,以及 Python 中的示例

原文:https://towardsdatascience.com/a-complete-guide-to-confidence-interval-and-examples-in-python-ff417c5cb593?source=collection_archive---------1-----------------------

蒂姆·蒂德曼在 Unsplash 上的照片

对统计学中一个非常流行的参数——置信区间及其计算的深入理解

置信区间是统计学中的基本概念,对数据科学家来说非常重要。在本文中,我将用必要的公式彻底解释它,并演示如何使用 python 计算它。

置信区间

听起来,置信区间是一个数值范围。在理想情况下,它应该包含统计参数的最佳估计。它用百分比表示。95%置信区间最常见。如果您的研究需要,您可以使用其他值,如 97%、90%、75%,甚至 99%的置信区间。我们通过一个例子来理解一下:

这里有一个声明:

“在对 659 名带着蹒跚学步的孩子的父母进行的抽样调查中,大约 85%的人表示,他们在带着孩子的所有旅行中都使用汽车安全座椅。根据这些结果,提供了 95%的置信区间,从大约 82.3%到 87.7%。”

这句话的意思是,我们 95%确定带着蹒跚学步的孩子旅行时使用汽车安全座椅的人口比例将会下降到 82.3%到 87.7%。如果我们从这 659 人中抽取一个不同的样本或子样本,在 95%的时间里,带着他们的孩子在所有旅行中使用汽车安全座椅的人口比例将在 82.3%和 87.7%之间。

记住,95%的置信区间并不意味着 95%的概率

置信区间如此流行和有用的原因是,我们无法从所有人群中获取数据。就像上面的例子一样,我们不可能从所有有小孩的父母那里得到信息。我们必须计算来自 659 位家长的结果。从这个结果,我们试图得到一个总人口的估计。因此,合理的做法是考虑误差幅度并取一个范围。这就是为什么我们取一个置信区间,它是一个范围。

我们需要一个简单的随机样本和一个正态分布来构造一个置信区间。但是,如果样本量足够大(30 或更多),正态分布是没有必要的。

来源:吉菲

如何计算置信区间

置信区间的计算包括通过样本和误差幅度获得的最佳估计。因此,我们采用最佳估计,并加上误差幅度。下面是置信区间和误差幅度的公式:

这里 SE 是标准误差

通常,CI 是针对两个统计参数计算的:比例和平均值。

结合上面的这两个公式,我们可以将 CI 的公式阐述如下:

人口比例或平均数是从样本中计算出来的。在“带着蹒跚学步的孩子的父母”的例子中,在带着他们的孩子的所有旅行中使用汽车座椅的父母的最佳估计或人口比例是 85%。所以,最好的估计(人口比例)是 85。置信水平(CL)的 z 得分是固定的。

对于足够大的样本量(30 或更多),95%置信区间的 z 得分为 1.96。

以下是一些常用置信度的 z 值:

计算标准误差的方法因人口比例和平均值而异。计算人口比例标准误差的公式为:

计算样本平均值标准误差的公式为:

根据这份声明,带着孩子旅行时使用汽车安全座椅的人口比例为 85%。所以,这是我们最好的估计。我们需要增加误差幅度。为了计算误差幅度,我们需要 z 分数和标准误差。我将计算 95%的置信区间。z 值应该是 1.96,我已经提到了人口比例的标准误差公式。插入所有值:

置信区间是 82.3%和 87.7%正如我们之前在声明中看到的。

来源: GIPHY

Python 中的置信区间

我假设你已经是 python 用户了。但是,即使您不是 python 用户,您也应该能够理解计算的概念,并使用自己的工具进行计算。我在这个练习中使用的工具是:

  1. Numpy 图书馆
  2. 熊猫图书馆
  3. Statsmodels 库
  4. Jupyter 笔记本环境。

如果你安装了一个 anaconda 包,你会得到一个 Jupyter 笔记本和其他工具。如果您还没有安装 anaconda 包,youtube 上有一些很好的视频可以演示如何安装。

Python 中人口比例的 CI

我将使用来自 Kaggle 的心脏数据集。请点击链接下载数据集。首先,我导入了包和数据集:

import pandas as pd
import numpy as np
df = pd.read_csv('Heart.csv')
df

数据的最后一栏是“AHD”。它说一个人是否有心脏病。一开始,我们也有一个“性”专栏。

我们将为患有心脏病的女性人口比例构建一个 CI。

首先,在新列“Sex1”中用“男性”和“女性”替换 1 和 0。

df['Sex1'] = df.Sex.replace({1: "Male", 0: "Female"})

我们不需要数据集中的所有列。我们将只使用“AHD”列,因为它包含一个人是否患有心脏病以及我们刚刚创建的性别 1 列。制作一个只有这两列的数据帧,删除所有的空值。

dx = df[["AHD", "Sex1"]].dropna()

我们需要患心脏病的女性人数。下面的代码行将给出患有心脏病和没有心脏病的男性和女性的数量。

pd.crosstab(dx.AHD, dx.Sex1)

以下是输出表:

患有心脏病的女性人数是 25。计算女性人口中患心脏病的比例。

p_fm = 25/(72+25)

“p_fm”是 0.26。女性人口数量:

n = 72+25

女性人口为 97 人。计算标准误差

se_female = np.sqrt(p_fm * (1 - p_fm) / n)

标准误差为 0.044。

现在使用上面的公式构建配置项。对于 95%的置信区间,z 得分为 1.96。

z_score = 1.96
lcb = p_fm - z_score* se_female #lower limit of the CI
ucb = p_fm + z_score* se_female #upper limit of the CI

置信区间为 0.17 和 0.344。

您可以使用库“statsmodels”来计算它。

import statsmodels.api as sm
sm.stats.proportion_confint(n * p_fm, n)

置信区间出来和上面一样。

来源: GIPHY

人口比例差异 CI

女性患心脏病的人口比例和男性患心脏病的人口比例一样吗?如果它们相同,那么两者的人口比例差异将为零。

我们将计算患有心脏病的女性和男性人口比例差异的置信区间。

以下是一步一步的过程:

使用相同的程序计算患有心脏病的男性人口比例和标准误差。

p_male = 114/(114+92)  #male population proportion
n = 114+92             #total male population

患有心脏病的男性人口比例为 0.55,男性人口数量为 206 人。计算男性人口比例的标准误差。

se_male = np.sqrt(p_male * (1 - p_male) / n)

男性人口的标准误差为 0.034。计算标准误差的差值。

标准误的区别不仅仅是减法。使用适当的公式。

下面是计算两个标准误差之差的公式:

让我们用这个公式来计算患有心脏病的男性和女性人口的标准误差的差异。

se_diff = np.sqrt(se_female**2 + se_male**2)

使用此标准误差计算患有心脏病的男性和女性的人口比例差异,并构建差异的置信区间。

d = 0.55 - 0.26
lcb = d - 1.96 * se_diff  #lower limit of the CI
ucb = d + 1.96 * se_diff  #upper limit of the CI

置信区间为 0.18 和 0.4。此范围中没有 0。这两个数字都大于零。因此,我们不能得出女性患心脏病的人口比例与男性患心脏病的人口比例相同的结论。如果置信区间为-0.12 和 0.1,我们可以说男性和女性患心脏病的比例是相同的。

资料来源: GIPHY

平均值置信区间的计算

我们将使用相同的心脏病数据集。数据集有一个包含胆固醇水平的“胆固醇”列。对于这个演示,

我们将计算女性平均胆固醇水平的置信区间。

让我们找出女性人口的平均值、标准差和人口规模。我也想得到男性人口的相同参数。因为它将对我们的下一个练习有用。为此,请使用 pandas groupby 和 aggregate 方法。如果您需要了解 pandas groupby 和 aggregate 方法,请查看这篇文章:

[## Pandas 的 Groupby 功能详细,可进行高效的数据汇总和分析

学习对数据进行分组和汇总,以使用聚合函数、数据转换、过滤、映射、应用函数…

towardsdatascience.com](/master-pandas-groupby-for-efficient-data-summarizing-and-analysis-c6808e37c1cb)

以下是获取男性和女性人口的平均值、标准差和人口规模的代码:

df.groupby("Sex1").agg({"Chol": [np.mean, np.std, np.size]})

如果我们只提取女性人口的必要参数:

mean_fe = 261.75  #mean cholesterol of female
sd = 64.9         #standard deviation for female population
n = 97            #Total number of female
z = 1.96          #z-score from the z table mentioned before

这里 1.96 是 95%置信水平的 z 值。

使用平均值的标准误差公式计算标准误差

se = sd /np.sqrt(n)

现在我们有了一切来构建女性平均胆固醇的置信区间。

构造 CI

lcb = mean_fe - z* se  #lower limit of the CI
ucb = mean_fe + z* se  #upper limit of the CI
(lcb, ucb)

CI 出来是 248.83 和 274.67。

这意味着女性胆固醇的真实平均值将在 248.83 和 274.67 之间

资料来源: GIPHY

计算均值差的置信区间

有两种方法可以计算两个总体均值差异的置信区间。

集合方法和非集合方法

如前所述,我们需要一个简单的随机样本和一个正态分布。如果样本很大,正态分布是不必要的。

集合方法还有一个假设。即两个总体的方差相同或几乎相同。

如果方差不相同,则无池方法更合适。

集合方法的标准误差公式为:

这里,s1 和 s2 是人口 1 和人口 2 的标准误差。同样,n1 和 n2 是人口 1 和人口 2 的人口规模。

无池方法的标准误差公式为:

这里,我们将构建男性和女性人群胆固醇水平均值差异的置信区间。

在前一个例子中,我们已经从数据集中获得了所有必要的参数。他们在这里:

n1 = 97
n2 = 206
mean_female = 261.75
mean_male = 239.6
sd_female = 64.9
sd_male = 42.65

我们可以看到,两个目标人群的标准差是不同的。所以。方差也必须不同。

因此,对于本例,无缓冲池方法更合适。

使用我们在上一示例中使用的公式计算男性和女性人口的标准误差

sem_female = sd_female / np.sqrt(97)
sem_male = sd_male / np.sqrt(206)

两个样本平均值的差异

mean_d = mean_female - mean_male

平均值' mean_d '的差值为 22.15。

使用无池方法的公式,计算标准误差的差异:

sem_d = (np.sqrt((n1-1)*se_female**2 + (n2-1)*se_male**2)/(n1+n2-2))*(np.sqrt(1/n1 + 1/n2))

最后,构建均值差异的 CI

lcb = mean_d - 1.96*sem_d  #lower limit of the CI
ucb = mean_d + 1.96*sem_d  #upper limit of the CI
(lcb, ucb)

置信区间的下限和上限分别为 22.1494 和 22.15。他们几乎是一样的。这意味着女性人口的平均胆固醇与男性人口的平均胆固醇没有不同。

结论

在本文中,我试图用 python 中的计算过程来详细解释置信区间。我在这里使用的 Python 代码足够简单,任何人都可以理解。即使你不是 python 用户,你也应该能够理解这个过程并以你的方式应用它。

来源: GIPHY

推荐阅读:

[## 数据科学家使用 Python 进行假设检验的完整指南

用样本研究问题、解决步骤和完整代码清楚地解释

towardsdatascience.com](/a-complete-guide-to-hypothesis-testing-for-data-scientists-using-python-69f670e6779e) [## 熊猫时间序列分析终极指南

在 Pandas 中执行时间序列分析所需的所有 Pandas 功能。您也可以将此用作备忘单。

towardsdatascience.com](/an-ultimate-guide-to-time-series-analysis-in-pandas-76a0433621f3) [## Python 中多元线性回归的逐步实现

学习用 Python 从头开始开发任意数量变量的多元线性回归。

towardsdatascience.com](/multivariate-linear-regression-in-python-step-by-step-128c2b127171) [## Numpy 中 1D、2D 和 3D 数组的索引和切片

本文从基础到高级展示了 Numpy 数组的索引和切片。

towardsdatascience.com](/indexing-and-slicing-of-1d-2d-and-3d-arrays-in-numpy-e731afff0bbe) [## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## Python 中从头开始的完整 K 均值聚类算法:分步指南

还有,如何使用 K 均值聚类算法对图像进行降维

towardsdatascience.com](/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461)

假设检验完全指南

原文:https://towardsdatascience.com/a-complete-guide-to-hypothesis-testing-2e0279fa9149?source=collection_archive---------19-----------------------

从控制测试错误到选择正确的测试

照片来自升压分析

假设检验是一种统计推断的方法,它考虑了零假设 H 与替代假设 H a 的对比,在这种情况下,我们通常会评估针对 H 的证据。此类测试用于将数据集相互比较,或将数据集与某种外部标准进行比较。前者是双样本检验(独立或配对),后者是单样本检验。比如“A 组比 B 组有更高的疼痛耐受度吗?”或者“对照组的平均年龄是 21 岁吗?”,分别为。假设检验以基于预先指定的显著性水平α的决策结束——当我们有足够强的证据反对时拒绝零假设,或者拒绝零假设失败。

测试误差

现在的问题是,我们如何知道我们是否有足够强的证据来反对这个无效假设?要回答这个问题,我们必须首先了解测试中不同类型的错误。

任何一个错误都被认为是不好的,因此当对假设检验做出决定时,我们希望将这种错误的概率降到最低。通常,我们用α= P(I 型误差)和β= P(II 型误差)来表示。

控制第一类错误

重申一下,第一类错误包括错误地拒绝零假设,而事实上零假设是真的。如果您熟悉假设检验,您可能已经看到统计学家通常将显著性水平设置为α = 0.05,并在 p 值小于或等于α时拒绝零假设。也就是说,如果 null 为真,那么我们拒绝它的概率很小(I 型错误)。顺便提一下,p 值对应于如果 H 为真,我们获得类似结果的可能性。

控制第二类错误

另一方面,第二类错误包括当零假设实际上为假时不拒绝它。如前所述,β = P(第二类误差)。不犯第二类错误的概率叫做幂,幂= 1 - β。请注意,我们需要低β,因此高功率很好。功效取决于真参数θ的值和样本大小。

我们如何估计功率?考虑下面这个例子:假设我们测试 h₀:𝜇= 9 vs . ha:𝜇≠9,其中𝜇是总体均值,但实际上,𝜇 = 8。这意味着 H 是不正确的,我们想要拒绝它。为了确定这种情况发生的可能性有多大,我们还需要总体标准偏差,比如我们在之前的研究中得到𝜎 = 3,样本量,比如
n = 20。然后,我们通过从真实分布中反复抽取随机样本并测试其平均值是否为 9 来估计功效。如果我们对 1000 个随机样本进行测试,并正确剔除 H 比方说357 次,则估计功效为 0.357。

权力的另一个用途是,通常,研究人员会用它来确定他们研究所需的样本量。换句话说,需要多大的样本才能达到一定的功效?

样本和测试类型

假设检验可以是单样本检验、双样本检验或配对检验。此外,这些测试可以是单面或双面的。这两者之间的区别在于我们希望测试什么。

一个样本

单一样本测试包括将数据与外部值进行比较。这不是将两组进行比较,而是将一组与所述外部标准进行比较。

两个独立的样本

双独立样本测试将数据中的一组与另一组进行比较,其中两组是独立的。也就是说,为这些组记录的观察结果是独立的,然后我们将它们相互比较。

配对

当我们对每个受试者进行两次测量时,我们就有了配对,或两个从属样本。通常,我们会在一段时间后对受试者进行重新测试时看到这种情况。

单边测试和双边测试的区别

片面的

当我们希望确定比较组之间或与外部标准相比的差异在哪个方向时,就会出现单侧检验。在这种情况下,测试的目的只包括检查一端,而忽略另一端发生的情况。一个例子是测试 A 组是否比 B 组在考试中表现得更好。这里,我们注意到我们只关心 A 和 B 之间的差何时为正。

双面的

双边测试包括测试比较组之间或与外部标准相比是否存在差异。在这种情况下,差异可以是正的,也可以是负的。

检查假设

评估常态

t 检验的主要假设是数据呈正态分布。更准确地说,我们需要样本均值的抽样分布近似正态…但我们现在忽略这一点,因为这需要一些关于 bootstrap 分布的知识,并简单地考虑数据的近似正态性。通常,对于大样本量,我们通过中心极限定理得到近似正态性。然而,如果我们的样本不是那么大,在进行 t 检验之前评估正态性是一个好主意。

检查正态分布数据的一些简单方法是检查数据的箱线图或直方图表示。在 Python 中获得这种图形的一个快速方法是通过 Seaborn 库。例如,这里有一个快速获得这些图的方法,其中 x 代表我们想要评估的数据样本。

import numpy as np 
import seaborn as sns
from matplotlib import pyplot as plt# generate normal data
sns.set()
np.random.seed(100)
x = np.random.normal(size=100)# put plots side by side
fig, ax = plt.subplots(1, 2, figsize=(15, 6))
# histogram
sns.distplot(x, kde=False, ax=ax[0]).set_title("Histogram")
# boxplot
sns.boxplot(x=x, orient="v", ax=ax[1]).set_title("Boxplot")

从上面两个图中的每一个来评估正态性是非常简单的。对于直方图,我们希望看到关于平均值和相当均匀的尾部的对称性。对于箱线图,我们希望胡须长度相当均匀(与正态分布的尾部相关)。此外,在这两种情况下,我们都不希望看到任何异常值,也不希望看到有偏差的数据。如果数据是右偏的,那么我们会注意到直方图上的大部分条形会浓缩到左边,并且箱线图上会有一个较长的上须。在我们的示例中,考虑到用于生成上述图的数据是从正态分布中直接采样的,因此生成的图符合正态分布是有意义的。

评估差异

一旦我们得出结论,我们的数据是近似正常的,我们需要决定使用哪两个样本 t 检验,因为还有进一步的假设要检查。该决定基于被比较的两组是否具有相等的价差/方差。为了评估这一点,我们将查看两组的箱线图。如果价差相同,两个箱线图的四分位数间距 ( IQR)将大致相同。

选择正确的测试

最常见的假设检验是 t 检验。然而,t 检验(类似于其他检验)带有假设,如果这些假设不满足,结果就没有意义。除了数据中被比较的组的数量之外,我们还必须根据数据的分布选择合适的测试。下面提到的大多数测试都可以通过 Python 的 Scipy 库访问。

t 检验

如果我们得出数据具有近似正态性的结论,那么我们可以使用 t 检验。有单样本 t 检验和两种双样本 t 检验:混合 t 检验(等方差)和 Welch-Satterthwaite t 检验(不等方差)。t 检验的另一种情况是当我们有两个彼此相关的样本时,即配对情况,我们将使用配对 t 检验。

对于一个单样本 t 检验,零假设 H 是“平均值等于θ ”对比另一个假设 H a 是“平均值不等于/小于/大于θ ”。

from scipy import stats
# one sample t-test (two-sided)
stats.ttest_1samp(group1, null_mean)

对于两个样本的 t 检验(其中样本是独立的),H 是“a 组的平均值等于 b 组的平均值”,而另一个假设 H a 是“a 组的平均值不同于/大于/小于 b 组的平均值”。在两个样本的情况下,每个组都需要满足近似正态性。此外,我们需要评估两组的方差来决定使用哪两个样本 t 检验。缺省值是不等方差。

from scipy import stats
# two sample t-test (two-sided)
stats.ttest_ind(group1, group2, equal_var=True) #for Pooled

对于配对 t 检验,H 为“两组的平均值相等”或“两组平均值之间的真实差值为 0”。在这里,两组之间的差异必须是近似正常的。

from scipy import stats
# matched pairs t-test
stats.ttest_rel(group1, group2)

方差分析

当每个独立组都近似正态,并且正在比较三组或更多组的独立观察值时,我们必须使用方差分析(ANOVA)。ANOVA 有 H “所有组都有相同的平均值”与 H a “至少一个组有不同于其他组的平均值”。

同样,与 t-test 一样,我们需要检查各组之间的方差是否相等。如果两组之间的差异相等,我们可以进行常规的单向方差分析。如果各组之间的差异不相等,我们将需要使用韦尔奇方差分析。后一种测试可通过 Python 的 Pingouin 库获得。

from scipy import stats
# one-way ANOVA
stats.f_oneway(group1, group2, group3, ...)

请注意,这个测试不会让我们知道差异在哪里,因此我们必须做进一步的测试,以找出哪个组与其他组不同,如果有的话。在方差相等的情况下,我们将用 TukeyHSD 检验继续分析。在方差不相等的情况下,Games-Howell 是可行的。

符号测验和情绪中值测验

如果我们得出数据不是近似正态的结论,我们就不能从 t 检验中得到任何有意义的或可靠的结果。然后我们必须求助于一个不依赖于分布对称性的检验。对于一个样本测试,我们应该求助于符号测试。虽然当测试两个或更多组时,我们将使用 Mood 的中位数测试。这些测试基于数据的中位数而不是平均值来评估组间的关联。值得注意的是,这些基于中位数的测试并没有对数据的基本分布做任何假设。

符号检验有 H “中值等于θ ”,而 Mood 中值检验的零假设是“各组有相同的(大)中值”,而替代假设是“其中一组的中值不同于大中值”。

from scipy import stats
# Mood's median test
stats.median_test(group1, group2, ..., ties)

Mood 的中位数检验可用于比较两组或更多组。因此,如果我们比较两个以上的组,类似于方差分析,我们需要找到中位数的差异发生在哪里(如果有的话)。我们通过成对中位数检验来实现。

使用句子嵌入 BERT 模型将学习从英语转移到其他语言的完整指南

原文:https://towardsdatascience.com/a-complete-guide-to-transfer-learning-from-english-to-other-languages-using-sentence-embeddings-8c427f8804a9?source=collection_archive---------13-----------------------

这个故事旨在向机器学习实践者提供关于句子嵌入 BERT 模型的细节。

用连体伯特网络嵌入句子的思想📋

W ord Vector 使用神经向量表示法在自然语言处理(NLP)的所有子领域中已经变得无处不在,这显然是很多人熟悉的领域[1]。在这些技术中,句子嵌入思想具有各种应用潜力,它试图将一个句子或短文本段落编码成一个固定长度的向量(密集向量空间),然后使用该向量来评估它们的余弦相似度如何反映人类对语义相关度的判断[2]。

句子嵌入在自然语言处理中有着广泛的应用,例如信息检索、聚类、自动文章评分和语义文本相似性。到目前为止,比较流行的生成定长句子嵌入的方法论有:连续词包 (CBOW) 序列到序列模型 (seq2seq)和来自变形金刚的双向编码器表示 (BERT)。

  • CBOW【3】是一种极其幼稚的方法,其中一个简单的求和(或平均)的单词嵌入由 word2vec 算法编码来生成句子嵌入。老实说,这是一种在句子中捕捉信息的糟糕方式,因为它完全不考虑单词的顺序。

同样 CBOW 嵌入 ,尽管它们的 含义与 相反(图片由作者)

  • Seq2seq 模型 [4]如 RNNs、LSTMs、GRUs 等..另一方面,获取一个项目序列(单词、字母、时间序列等),并通过逐个处理单词嵌入来输出另一个项目序列,同时保持存储上下文信息的隐藏状态。由编码器产生的嵌入以隐藏状态向量的形式捕获输入序列的上下文,并将其发送到解码器,解码器然后产生执行一些其他任务的输出序列。这种方法能够根据句子中的单词顺序进行区分,因此可能比 CBOW 提供更丰富的嵌入。

Seq2seq 注意(来源)

  • BERT 模型【5】在各种句子分类、句子对回归以及语义文本相似性任务上实现了最先进的性能。 BERT 使用交叉编码器网络,将两个句子作为变压器网络的输入,然后预测目标值。然而,在一个由大量句子组成的语料库中,寻找相似的句子对需要大量的推理计算和时间(即使使用 GPU)。成对句子推理在计算上是相当昂贵的,并且与O(*n.(n-1*)/2)成比例。例如,对于 1000 个句子,我们需要1000.(1000 – 1)/2 = 499500推理计算。具体来说,如果我们想要使用与 BERT 的成对比较技术在 Quora 上的 4000 万个问题中过滤出最相似的问题,查询将需要 50 多个小时才能完成。下图解释了如何使用 BERT 进行句子对分类。

用 BERT 进行句子对分类(来源

为了克服这个问题,我们可以借鉴计算机视觉研究人员的想法,使用连体三元组网络结构来导出固定大小的句子嵌入向量,然后使用类似余弦相似度或曼哈顿/欧几里德距离的相似性度量来计算语义相似的句子[6]。这个解决方案是由来自泛在知识处理实验室(UKP-TUDA)Nils Reimers 和 Iryna Gurevych 提出的,它被称为句子-BERT (SBERT)。通过使用优化的索引结构,模型求解上述 Quora 示例所需的运行时间可以从 50 小时减少到几毫秒!!!

SBERT 的体系结构简单到足以说明。首先,原始句子对通过 BERT / RoBERTa 来嵌入固定大小的句子。然后在池层中,平均聚合,被证明与最大值CLS 聚合相比具有最佳性能,被用于生成 uv

SBERT 具有分类目标函数的架构(图片由作者提供)

分类目标函数

然后我们连接嵌入如下:(u,v,‖u-v‖),乘以可训练的权重矩阵 W∈ℝ ᴺ ˣ ᴷ,其中 n 是句子嵌入维数,k 是标签的数量。我们优化交叉熵损失。

Softmax(Wt(u,v,| u v |)

SBERT 带回归目标函数的架构( 图片作者)

回归目标函数

在回归任务的情况下,我们计算句子嵌入和各个句子对的余弦相似性。我们使用均方误差损失作为目标函数。

MSE(Wt(u,v,余弦- sim(u,v))

SBERT 具有三个目标函数的架构(图片由作者提供)

三元目标函数

给定一个锚定句 A,一个肯定句 P,一个否定句 N,数学上。我们最小化 P 距离度量和 N 距离度量的损失函数。保证金ɛ确保 p 至少是ɛ更接近 a 比 n

迁移学习句子嵌入📊

到目前为止,我们可以看到 SBERT 可以用于信息检索,聚类,自动短文评分,以及语义文本相似性,具有不可思议的时间和高准确性。然而,SBERT 的局限性在于它目前只支持英语,而对其他语言则保持空白。为了解决这个问题,我们可以使用类似于连体三联体网络结构的模型架构来扩展 SBERT 到新语言【7】。

这个想法很简单,首先我们用 SBERT 产生英语句子中的句子嵌入,我们称之为教师模型。然后我们为我们想要的语言创建新的模型,我们称之为学生模型,,这个模型试图模仿教师模型。换句话说,原始英语句子将在学生模型中训练,以便得到与教师模型中的向量相同的向量。

如下例所示,“Hello World”和“Hallo Welt”都是通过学生模型输入的,该模型试图生成两个与教师模型中的向量相似的向量。经过培训后,学生模型应具备用英语和所需语言对句子进行编码的能力。

英语到德语的迁移学习示例结构(来源)

让我们从零开始,用一个例子把 SBERT 英语转换成日语。

首先,我们需要安装 SBERT 和 MeCab 包(将日语句子解析为含义词的重要包)。

!pip install -U sentence-transformers
!pip install mecab-python3

MeCab 解析日语句子后的示例

然后,一些人类智能需要为翻译数据集以及英语和日语的语义文本相似度数据集准备几对句子。在预处理日语句子后,我们将得到如下所示的数据

EN-JA 的翻译数据集

面向 EN-JA 的语义文本相似度数据集

我使用 XLM-罗伯塔创建单词嵌入作为学生模型(当然,如果你愿意,你可以尝试其他 BERT 预训练模型,即 mBERT ),来自 SentenceTransformer 的“bert-base-nli-stsb-mean-tokens”作为教师模型均值聚合作为池层。其他参数是 max_seq_length = 128 和 train_batch_size = 64(如果超出了内存限制,可以将 batch_size 减少到 32 或 16)。

在创建了教师模型学生模型之后,我们可以开始加载训练、开发、测试数据集和训练模型。训练集和测试集是翻译数据集,而 dev 集是遵循迁移学习 SBERT 体系结构的语义文本相似度数据集。在本例中,我将在 20 个时期内训练模型,学习率= 2e-5,ε= 1e-6,您可以自由尝试另一个超参数,以获得您的语言的最佳结果。我还为下游应用程序保存了模型,如果您只想玩玩这个,可以通过设置 save_bet_model = False 来关闭它。

最后,让我们享受结果。我们将在英语和日语语料库中使用相同的句子含义来评估学生模型

结果很好,我们在语料库中得到了相似的句子

让我们在日语语料库中检查学生模型的能力

厉害!!我们的模型也可以得到日语和英语中相似的句子

最后的想法📕

我们可以看到,在从英语 SBERT 中提取知识之后,现在我们的模型有能力从 NLP 的任何下游任务中嵌入新的语言句子。你可以试着用你自己的语言训练 SBERT,然后让我知道结果。此外,学生模型能力不仅限于 2 种语言,我们可以扩展语言的数量。准备新的语言数据集,一切准备就绪。你可以使用之前解释过的代码(现在学生模型将变成教师模型来教新学生😅) .然而,作为一个经验法则,准确性会随着能力的降低而降低。

如果你想进一步讨论,可以随时联系我。下面是我的链接

尽情享受吧!!!👦🏻

附录

如果设置 save_bet_model = True,就可以很容易地用这段代码预加载模型

from sentence_transformers import SentenceTransformermodel = SentenceTransformer('output/model-2020-05-21/')

参考

[1] Jeffrey Pennington,Richard Socher 和 Christopher Manning,GloVe:单词表示的全局向量。《2014 年自然语言处理经验方法会议论文集》(EMNLP 2014),第 1532–1543 页,2014 年。

[2] Quoc Le 和 Tomas Mikolov,句子和文档的分布式表示。ICML 2014 年会议录。PMLR,2014 年。

[3]托马斯·米科洛夫、程凯、格雷戈·科拉多和杰弗里·迪恩,向量空间中词表示的有效估计,2013 年。

[4] Ilya Sutskever,Oriol Vinyals 和 Quoc V. Le,用神经网络进行序列到序列学习,2014 年。

[5] Jacob Devlin,Ming-Wei Chang,Kenton Lee 和 Kristina Toutanova,BERT:用于语言理解的深度双向转换器的预训练,2019。

[6] Nils Reimers 和 Iryna Gurevych,句子-BERT:使用暹罗 BERT-网络的句子嵌入,2019 年。

[7] Nils Reimers 和 Iryna Gurevych,使用知识蒸馏使单语句子嵌入多语言,2020 年。

Python 用户输入完全指南

原文:https://towardsdatascience.com/a-complete-guide-to-user-input-in-python-727561fc16e1?source=collection_archive---------4-----------------------

Python 初学者

详细了解 Python 输入函数及其许多用例

照片由凯特琳·贝克Unsplash 上拍摄

ser 输入对于构建交互式程序至关重要。每种编程语言都有其独特的输入接口实现。C++有scanf,Java 有Scanner类,Ruby 有gets

虽然在大多数情况下,这种输入来自键盘,但也有其他形式,如鼠标点击、跟踪板、传感器等。也是可能的。

和往常一样, Python 提供了一个简单的框架,以input()函数的形式获取用户输入

input 函数从控制台读取一行,转换成字符串,然后返回。

在本教程中,我们将通过各种用例详细介绍input()功能。我们将讨论输入可能存在的几种形式,以及如何在代码片段的帮助下将输入解析成我们需要的格式

资料来源:吉菲

句法

输入([提示])

这里,
提示:可选字符串参数,用于向用户显示消息。示例:“输入姓名:”

当调用input()功能时,程序流程暂停,直到用户输入一些输入。然后用户添加一些信息并按下Enter键。input 函数用输入的字符串返回程序。

entered_value = input('Enter some value: ')
print(entered_value)

输出:

来源:作者

输入类型

input 函数将接收到的所有信息转换为字符串格式。让我们看一看:

输出:

Enter name: Chaitanya Baweja
Enter age: 20
data_type of name:  <class 'str'>
data_type of age:  <class 'str'>

我们使用了 类型函数 来检查对象的数据类型。正如您在上面看到的,我们输入数字还是字符串并不重要。两者都以字符串对象的形式返回。

接受用户输入的整数

由于input()函数以字符串的形式返回所有内容,我们需要执行一些显式的 类型转换 来接受整数。这里,我们将使用[int()](https://www.w3resource.com/python/built-in-function/int.php)函数。

输出:

Enter first num: 10
Enter second num: 5
Type of num_1: <class 'int'>
Type of num_2: <class 'int'>
The sum of given numbers is :  15

int(string)将给定的字符串转换为整数类型。

接受来自用户的浮点输入

类似地,我们可以使用[float()](https://www.geeksforgeeks.org/float-in-python/)函数获得一个浮点值。

输出:

Enter value: 5.6
Type of float_1: <class 'float'>
Twice the given numbers is :  11.2

用户输入异常处理

类型转换的一个常见问题是 值错误 异常

当用户输入无法转换成给定类型的输入时,我们会得到一个 ValueError 异常。

例如,用户输入一个随机字符串作为年龄。

num = int(input('Enter age: '))

在这里,int()函数期望一个包装在字符串中的整数值。任何其他类型的值都会导致错误。看看当我们输入'nope'作为输入时会发生什么。

输出:

Enter age: nope---------------------------------------------------------
ValueError                    Traceback (most recent call last)
<ipython-input-10-1fa1cb611d10> in <module>
----> 1 num_1 = int(input('Enter age: '))

ValueError: invalid literal for int() with base 10: 'nope'

为了确保用户输入有效的信息,我们需要处理用户输入中经常出现的错误。为此我们将使用 Python 异常处理 。看一看:

同样,如果我们输入'nope'作为输入:

Enter a number: nope
This is not a number.

在上面的代码片段中,如果用户输入一个非整数的输入,代码将引发一个异常。这个异常被 except 语句捕获,我们在其中打印:‘This is not a number’

由于这个 try-except 块,我们的程序不会因为错误的用户输入而崩溃。

资料来源:吉菲

我们可以将异常块与循环一起使用。因此,用户将被反复提示,直到他们提供有效的输入

来源:作者

单行中的多个输入值

我们也可以只调用一次input()函数,直接在一行中请求多个值。例如,让我们从用户那里获得一些关于学生的信息,并将其存储在不同的变量中。

输出:

Enter student's name, age and score separated by space:Chaitanya 20 100
Student Name: Chaitanya
Student Age: 20
Student Score: 100

这里,我们使用[split()](https://www.w3schools.com/python/ref_string_split.asp)方法用空格分隔输入字符串。

获取一个数字列表作为输入

但是当您不知道输入值的数量时会发生什么呢?

让我们假设您需要输入一个数字列表并返回它们的总和。您不知道列表中的元素数量。我们如何输入这个列表?

我们同时使用了贴图 功能。split()方法将把输入的字符串分成一个字符串列表。然后,map()函数将对所有列表元素执行int操作。

输出:

Enter a list of numbers separated by space: 10 20 30 40 50 60
Intermediate_list:  ['10', '20', '30', '40', '50', '60']
Number List:  [10, 20, 30, 40, 50, 60]
List sum: 210

在上面的代码中:

  • input()返回包含由空格分隔的数字的字符串。
  • split()返回按空格划分的字符串列表。
  • map()对所有列表元素执行int()操作,并返回一个 map 对象。
  • list()函数将地图对象转换回列表。

资料来源: Giphy

来自用户的多行输入

input()函数在遇到换行符时返回(当用户按下Enter键时)。因此,如果你试图发送多行信息,input()将只返回第一行。

为了克服这一点,我们可以使用 for-loop 。每次迭代我们得到一行输入,当我们得到一个空行时停止(在空行上按 Enter 键)。我们将所有这些行组合成一个列表。

输出:

结论

Python 为获取用户输入提供了一个简单的框架。 输入函数 从控制台读取一行,转换成字符串,并返回。

输入函数将其接收的所有信息转换成 字符串格式 。我们使用 类型转换 将输入转换成所需的格式。

因无效输入而发生的异常可使用 try-except 块 进行管理。 拆分映射 功能帮助在同一行输入多个值。

柴坦尼亚·巴韦贾 渴望用工程解决方案解决现实世界的问题。在 Twitter 和 Linkedin 上关注他的旅程。

使用 PyTorch 的 TensorBoard 完全指南

原文:https://towardsdatascience.com/a-complete-guide-to-using-tensorboard-with-pytorch-53cb2301e8c3?source=collection_archive---------2-----------------------

艾萨克·史密斯在 Unsplash 上拍摄的照片

在本文中,我们将把 TensorBoard 集成到我们的 PyTorch 项目中。TensorBoard 是一套用于检查和理解模型运行和图形的网络应用程序。TensorBoard 目前支持五种可视化:标量、图像、音频、直方图和图形。在本指南中,我们将涵盖除音频之外的所有五个方面,并学习如何使用 TensorBoard 进行高效的超参数分析和调谐。

安装指南:

  1. 确保您的 PyTorch 版本高于 1.10。对于本指南,我使用的是版本 1.5.1。使用此命令检查您的 PyTorch 版本。
import torch
print(torch.__version__)

2.安装 TensordBoard 有两个包管理器— pip 或 Anaconda 。根据您的 python 版本,使用以下任一选项:

Pip 安装命令:

pip install tensorboard

Anaconda 安装命令:

conda install -c conda-forge tensorboard

注意:安装 TensorFlow 并不是运行 TensorBoard 的先决条件,尽管它是 TensorFlow 生态系统的产品,TensorBoard 本身可以与 PyTorch 一起使用。

简介:

在本指南中,我们将使用 FashionMNIST 数据集(60,000 张服装图片和不同服装类型的 10 个类别标签),这是一个内置在 torch vision 库中的流行数据集。它由衣服、鞋子、配饰等图像组成。以及对应于每个类别的整数标签。我们将创建一个简单的 CNN 分类器,然后从中进行推论。尽管如此,本指南将帮助您将 TensorBoard 的功能扩展到 PyTorch 中的任何项目,包括使用自定义数据集创建的项目。

请注意,在本指南中,我们不会详细介绍如何实现 CNN 模型以及如何设置训练循环。相反,本文的重点将是深度学习项目的簿记方面,以获得模型内部工作的可视化(权重和偏差)和评估指标(损失,准确性,数量 _ 正确 _ 预测)以及超参数调整。如果你是 PyTorch 框架的新手,在继续之前,看看我的另一篇关于在 PyTorch 中实现 CNN 的文章(处理数据集,将数据移动到 GPU,创建模型和训练循环)。

导入库和帮助函数:

import torch
import torch.nn as nn
import torch.optim as opt
torch.set_printoptions(linewidth=120)
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
**from torch.utils.tensorboard import SummaryWriter**

最后一个命令使我们能够导入 Tensorboard 类。我们将创建“summary writer”的实例,然后添加我们模型的评估特性,如损失、正确预测的数量、准确性等。敬它。TensorBoard 的一个新颖特性是,我们只需向它输入输出张量,它就会显示所有这些指标的绘图,这样 TensorBoard 就可以为我们处理所有的绘图工作。

def get_num_correct(preds, labels):
    return preds.argmax(dim=1).eq(labels).sum().item()

这一行代码帮助我们在训练模型并将训练好的模型应用到测试集之后获得正确标签的数量。 "argmax " 获取张量中最高值对应的索引。它是在 dim=1 上拍摄的,因为 dim=0 对应于一批图像。“eq”将批中的预测标签与真实标签进行比较,如果匹配则返回 1,如果不匹配则返回 0。最后,我们取 1 的总和来得到正确预测的总数。对张量执行操作后,输出也作为张量返回。 "item" 将 correct_predictions 的一维张量转换为浮点值,以便将其附加到列表(total_correct)中,以便在 TensorBoard 中绘图(张量如果附加到列表中,则不能在 TensorBoard 中绘图,因此我们需要将其转换为浮点值,将其附加到列表中,然后将此列表传递给 TensorBoard 进行绘图)。

CNN 模型:

我们创建了一个简单的 CNN 模型,将图像通过两个卷积层,然后是一组完全连接的层。最后,我们将在最后使用一个 Softmax 层来预测类标签。

class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)

        self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=60)
        self.out = nn.Linear(in_features=60, out_features=10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, kernel_size = 2, stride = 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, kernel_size = 2, stride = 2)
        x = torch.flatten(x,start_dim = 1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.out(x)

        return x

导入数据并创建列车加载器:

train_set = torchvision.datasets.FashionMNIST(root="./data",
train = True,
 download=True,
transform=transforms.ToTensor())train_loader = torch.utils.data.DataLoader(train_set,batch_size = 100, shuffle = True)

用 TensorBoard 显示图像和图形:

**tb = SummaryWriter()**
model = CNN()
images, labels = next(iter(train_loader))
grid = torchvision.utils.make_grid(images)
**tb.add_image("images", grid)
tb.add_graph(model, images)
tb.close()**

我们创建一个 SummaryWriter 的实例‘TB ’,并通过使用 tb.add_image 函数向其添加图像。它有两个主要参数,一个是图像的标题,另一个是图像的张量 。在这种情况下,我们已经创建了一批 100 个图像,并将它们传递给一个网格,然后将其添加到 tb 实例中。对于 tb.add_graph 函数,我们传递我们的 CNN 模型和一批输入图像来生成模型的图形。运行代码后,将在项目目录中创建一个“runs”文件夹。所有进行中的运行将按日期在文件夹中分类。这样你就有了一个所有跑步的有效日志,可以在 TensorBoard 中查看和比较。

现在使用命令行(我使用 Anaconda 提示符)重定向到 runs 文件夹所在的项目目录,并运行以下命令:

tensorboard --logdir runs

然后,它将在本地主机上为 TensorBoard 提供服务,其链接将显示在终端中:

“TensorFlow 未安装”警告可以忽略

打开链接后,我们将能够看到我们所有的运行。图像在“图像”选项卡下可见。我们可以使用正则表达式过滤运行,并勾选我们感兴趣的可视化。

张量板中图像的网格图

“图表”选项卡下,您将找到该型号的图表。它给出了在每一次卷积和线性层操作之后,整批图像的尺寸如何变化的整个管道的细节。只需双击任一图标,即可从图表中获取更多信息。它还通过双击任何 Conv2d 或线性层给出所有权重和偏差矩阵的维度。

使用张量板为 CNN 模型生成的图形

可视化评估的训练循环:

device = ("cuda" if torch.cuda.is_available() else cpu)
model = CNN().to(device)
train_loader = torch.utils.data.DataLoader(train_set,batch_size = 100, shuffle = True)
optimizer = opt.Adam(model.parameters(), lr= 0.01)
criterion = torch.nn.CrossEntropyLoss()

**tb = SummaryWriter()**

for epoch in range(10):

    total_loss = 0
    total_correct = 0

    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)
        preds = model(images)

        loss = criterion(preds, labels)
        total_loss+= loss.item()
        total_correct+= get_num_correct(preds, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

 **tb.add_scalar("Loss", total_loss, epoch)
    tb.add_scalar("Correct", total_correct, epoch)
    tb.add_scalar("Accuracy", total_correct/ len(train_set), epoch)

    tb.add_histogram("conv1.bias", model.conv1.bias, epoch)
    tb.add_histogram("conv1.weight", model.conv1.weight, epoch)
    tb.add_histogram("conv2.bias", model.conv2.bias, epoch)
    tb.add_histogram("conv2.weight", model.conv2.weight, epoch)**

    print("epoch:", epoch, "total_correct:", total_correct, "loss:",total_loss)

**tb.close()**

或者,我们也可以使用 for 循环迭代所有模型参数,包括 fcsoftmax 层:

for name, weight in model.named_parameters():
 **tb.add_histogram(name,weight, epoch)
    tb.add_histogram(f'{name}.grad',weight.grad, epoch)**

我们运行循环 10 个时期,在训练循环结束时,我们将增量传递给我们创建的 tb 变量。我们已经创建了 total_losstotal_correct 变量来跟踪每个时期结束时的损失正确预测。注意,每个“tb”都有三个参数,一个是字符串,它将是折线图/直方图的标题,然后是包含要绘制的的张量,最后是全局步骤。由于我们正在做一个纪元式分析,我们将其设置为纪元。或者,也可以通过使用“枚举”移动 for 循环内的 tb 命令,将其设置为批处理 id ,并将步骤设置为批处理 id ,如下所示:

for batch_id, (images, labels) in enumerate(train_loader):
......
    **tb.add_scalar("Loss", total_loss, batch_id)**

如下图所示,运行前面提到的命令来运行 TensorBoard 将显示损失、数量 _ 正确 _ 预测精度的线图和直方图。

线条图:

沿着图表移动橙色圆点将为我们提供该特定时期的相应度量(准确度/正确/损失)的日志。

TensorBoard 生成的线图

直方图:

TensorBoard 生成的直方图

超参数调谐:

首先,我们需要将 batch_size、learning_rate、shuffle 更改为动态变量。我们通过创建如下的字典来实现这一点:

from itertools import product
parameters = dict(
    lr = [0.01, 0.001],
    batch_size = [32,64,128],
    shuffle = [True, False]
)

param_values = [v for v in parameters.values()]
print(param_values)

for lr,batch_size, shuffle in product(*param_values):
    print(lr, batch_size, shuffle)

这将允许我们获得三个元组,对应于三个超参数的所有组合,然后在运行每个历元循环之前对它们调用 for 循环。这样,我们将能够对所有不同的超参数组合进行 12 次运行(2(learning _ rates)* 3(batch _ size)* 2(shuffles)),并在 TensorBoard 上进行比较。我们将按如下方式修改训练循环:

改进的训练循环:

for run_id, (lr,batch_size, shuffle) in enumerate(product(*param_values)):
    print("run id:", run_id + 1)
    model = CNN().to(device)
    train_loader = torch.utils.data.DataLoader(train_set,batch_size = batch_size, shuffle = shuffle)
    optimizer = opt.Adam(model.parameters(), lr= lr)
    criterion = torch.nn.CrossEntropyLoss()
    **comment = f' batch_size = {batch_size} lr = {lr} shuffle = {shuffle}'
    tb = SummaryWriter(comment=comment)**
    for epoch in range(5):
        total_loss = 0
        total_correct = 0
        for images, labels in train_loader:
            images, labels = images.to(device), labels.to(device)
            preds = model(images)

            loss = criterion(preds, labels)
            total_loss+= loss.item()
            total_correct+= get_num_correct(preds, labels)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

        **tb.add_scalar("Loss", total_loss, epoch)
        tb.add_scalar("Correct", total_correct, epoch)
        tb.add_scalar("Accuracy", total_correct/ len(train_set), epoch)**

        print("batch_size:",batch_size, "lr:",lr,"shuffle:",shuffle)
        print("epoch:", epoch, "total_correct:", total_correct, "loss:",total_loss)
    print("__________________________________________________________")

 **tb.add_hparams(
            {"lr": lr, "bsize": batch_size, "shuffle":shuffle},
            {
                "accuracy": total_correct/ len(train_set),
                "loss": total_loss,
            },
        )**

**tb.close()**

如上所述,我们已经将所有内容移到 for 循环下,以检查所有不同的超参数组合,并且在每次运行时,我们必须重新实例化模型以及重新加载数据集的批次“注释”允许我们根据指定的超参数在 runs 文件夹中创建不同的文件夹。我们将这个注释作为参数传递给 SummaryWriter 。请注意,我们将能够一起查看所有运行,并在 TensorBoard 中绘制所有超参数的对比分析。 tb.add_scalar 与之前的相同,只是这次我们将它显示在所有运行中。 tb.add_hparams 允许我们在里面添加超参数作为参数来跟踪训练进度。它将两个字典作为输入,一个用于超参数,另一个用于要分析的评估指标。结果被映射到所有这些超参数上。从底部的图形映射图可以清楚地看到。

组合图:

组合可视化的 12 次运行图

如上所述,我们可以过滤我们想要的任何运行,或者将它们绘制在同一个图表上。通过这种方式,我们可以对模型在多个超参数上的性能进行比较研究,并将模型调整到能够提供最佳性能的模型。在弹出框中可以看到所有细节,如批量大小、学习率、随机播放和相应的精度值。

从结果中可以明显看出,批量大小为 32,shuffle 设置为 True,学习率为 0.01 时产生最好的结果。出于演示的目的,它只运行 5 个时期。增加历元的数量可以很好地影响结果,因此用几个历元值进行训练和测试是很重要的。

超参数图:

张量板生成的超参数图

该图包含所有 12 次运行的组合日志,因此您可以使用最高的准确度和最低的损失值,并将其追溯到相应的批次大小、学习率和洗牌配置。

从超参数图可以清楚地看出,将 shuffle 设置为 False(0)往往会产生非常差的结果。因此,将 shuffle 设置为 always True(1)对于训练是理想的,因为它增加了随机化。

结论:

请随意使用 TensorBoard,尝试向图中添加更多的超参数,以获得尽可能多的关于给定各种超参数的模型的损失收敛模式和性能的信息。除了 Adam 之外,我们还可以添加一组优化器,并进行对比研究。在类似 LSTMs 的序列模型中,GRUs 可以将时间步长添加到图表中,并得出深刻的结论。希望这篇文章能让你对使用 PyTorch 的 TensorBoard 有一个全面的了解。

链接到代码:https://github.com/ajinkya98/TensorBoard_PyTorch

阿帕奇气流公司简介

原文:https://towardsdatascience.com/a-complete-introduction-to-apache-airflow-b7e238a33df?source=collection_archive---------3-----------------------

关键概念、安装和一个真实世界的 DAG 示例

照片由ahin yeilirapakUnsplash 上拍摄

气流是一种自动化和计划任务和工作流的工具。如果您想以数据科学家、数据分析师或数据工程师的身份高效工作,拥有一个能够定期自动化您想要重复的过程的工具是至关重要的。这可以是从为常规分析报告提取、转换和加载数据到自动重新训练机器学习模型的任何操作。

气流使您能够轻松地自动化主要用 Python 和 SQL 编写的简单到复杂的过程,并拥有丰富的 web UI 来可视化、监控和解决任何可能出现的问题。

下面的文章是对该工具的完整介绍。我已经包括了从在虚拟环境中安装到运行你的第一个 dag 的所有简单步骤。

我把教程分成了 6 个部分,这样更容易理解,你可以跳过你可能已经熟悉的部分。包括以下步骤:

  1. 基本气流概念。
  2. 如何在虚拟环境中设置气流安装。
  3. 运行气流网络用户界面和计划程序。
  4. 常见 CLI 命令的列表。
  5. 网络用户界面之旅。
  6. 创建一个真实世界的 DAG 示例。

1.基本概念

在介绍气流的安装和使用之前,我将简要介绍该工具的几个核心概念。

熟练的技艺

该工具的核心是 DAG(有向无环图)的概念。DAG 是您希望作为工作流的一部分运行的一系列任务。这可能包括通过 SQL 查询提取数据,用 Python 执行一些计算,然后将转换后的数据加载到一个新表中。在《气流》中,这些步骤将被写成 DAG 中的单独任务。

您还可以通过气流指定任务之间的关系、任何依赖关系(例如,在运行任务之前已加载到表中的数据)以及任务的运行顺序。

DAG 是用 Python 编写的,并保存为.py文件。工具广泛使用 DAG_ID 来协调 DAG 的运行。

DAG 运行

我们具体说明了 DAG 应该在什么时候通过执行日期自动运行。DAG 按照指定的时间表(由 CRON 表达式定义)运行,可以是每天、每周、每分钟或几乎任何其他时间间隔

经营者

运算符将每个任务中要执行的操作封装在 DAG 中。Airflow 有各种各样的内置操作符,可以执行特定的任务,其中一些是特定于平台的。此外,还可以创建自己的自定义操作符。

2.装置

我将给你我个人在一个隔离的管道环境中的气流设置。如果您使用不同的虚拟环境工具,这些步骤可能会有所不同。这种设置很大程度上受到了这种优秀的 Stackoverflow 线程的启发。

对你的 Airflow 项目使用版本控制是一个好主意,因此第一步是在 Github 上创建一个资源库。我把我的名字叫做airflow_sandbox。一旦您使用git clone "git web url"在本地环境中创建了存储库克隆。

从终端导航到目录,例如cd /path/to/my_airflow_directory

在正确的目录中,我们安装 pipenv 环境以及特定版本的 Python、Airflow 本身和 Flask,后者是运行 Airflow 所必需的依赖项。为了让一切都正常工作,为所有安装指定特定的版本是一个好主意。

pipenv install --python=3.7 Flask==1.0.3 apache-airflow==1.10.3

Airflow 需要在您的本地系统上运行一个名为 AIRFLOW_HOME 的位置。如果我们不指定它,它将默认为您的路由目录。我更喜欢通过在. env 文件中指定气流来设置我正在工作的项目目录的路径。为此,只需运行以下命令。

echo "AIRFLOW_HOME=${PWD}/airflow" >> .env

接下来,我们初始化 pipenv 环境。

pipenv shell

Airflow 需要一个数据库后端来运行。默认设置使用 SQLite 数据库,这对于学习和实验来说很好。如果你想建立自己的数据库后端,airflow 文档有一个很好的指南。初始化数据库类型。

airflow initdb

最后,我们创建一个目录来存储我们的 Dag。

mkdir -p ${AIRFLOW_HOME}/dags/

这就是最初的基本设置完成。您现在应该有一个如下所示的项目结构。

3.运行气流

气流有一个优秀的网络用户界面,您可以查看和监控您的 Dag。要启动 web 服务器查看 UI,只需运行以下 CLI 命令。默认情况下,Airflow 将使用端口 8080,因为我已经使用它来运行我指定的 8081。

airflow webserver -p 8081

我们还需要启动调度程序。

airflow scheduler

现在如果我们导航到http://localhost:8081/admin/?showPaused=True 。我们将看到以下屏幕。

Airflow 有一组显示在用户界面中的示例 Dag。一旦您开始创建自己的 Dag,您可以通过点按屏幕底部的“隐藏暂停的 Dag”来隐藏它们。

4.基本 CLI 命令

让我们使用这些示例 Dag 来浏览一些常见的 Airflow CLI 命令。

让我们从教程 dag 运行睡眠任务。

airflow run tutorial sleep 2020-05-31

我们可以在教程 DAG 中列出任务。

bash-3.2$ airflow list_tasks tutorial

暂停这个 DAG。

airflow pause tutorial

Unpause 教程。

airflow unpause tutorial

回填(在过去的日期执行任务)。指定 dag_id(教程)、开始日期(-s)和结束日期(-e)。

airflow backfill tutorial -s 2020-05-28 -e 2020-05-30

有关 CLI 命令的完整列表,请参见文档中的第

5.网络用户界面

我们可以从 web UI 监控、检查和运行任务。如果我们回到 web 服务器,我们可以看到我们在教程 DAG 上运行的 CLI 命令的效果。为了便于查看,我隐藏了暂停的 Dag。

我们有许多方法可以检查 DAGS 的运行情况。

如果我们选择树形视图。

我们可以轻松查看哪些任务已经运行、正在运行或已经失败。

我们还可以通过点击小方块来运行、清除或标记特定的任务。

如果我们单击 Rendered 按钮,我们可以查看已经运行的代码或命令。

代码视图让我们看到组成 DAG 的代码。

图表视图是可视化任务如何排序或关联的好方法。

web UI 中的另一个重要区域是管理。在这里,您可以定义到其他平台(如数据库)的连接,并定义可重用的变量。

6.第一个 DAG

在这里,我将尝试给出一个接近真实世界的 DAG 示例,以说明至少一种使用气流的方法,并介绍随之而来的一些复杂性。

我将编写一个 Airflow DAG,它首先检查 BigQuery 公共数据集中是否存在感兴趣的日期的数据,然后将每天的数据加载到我自己的私人项目的一个表中。

BigQuery 有一个免费的使用层,允许您每月查询 1TB 的数据,因此如果您想亲自尝试,您将能够零成本地做到这一点。

BigQuery 设置

为了一起使用 Airflow 和 BigQuery,我们需要先完成一些额外的设置步骤。

为了能够通过 Airflow 在 BigQuery 中查询和加载数据,我们需要首先给予 Airflow 所需的安全权限。

为此,你需要在谷歌云平台上创建一个服务账户。这有点像创建一个有权限访问您的帐户的用户,但旨在允许其他平台访问。

首先从谷歌云控制台导航到服务账户。然后点击创建服务账户按钮。

接下来填写显示的表单。

在下一页,您需要选择想要授予的访问级别。我在所有资源中选择了编辑,因为这是我的个人账户,这里没有存储任何敏感数据。如果我更关心潜在的安全问题,那么我会授予更细粒度的权限。

接下来,您需要创建一个私钥,您可以通过选择创建密钥来完成。选择 JSON,因为这是你需要的气流。私钥将被下载到您的本地系统,您需要安全地存储它。

我们现在需要返回到 Airflow Web UI,用这个 JSON 文件的输出更新 bigquery_default 连接。您还需要添加一个默认的项目 id,如下所示。

我们还需要在 pipenv 环境中安装一些 Google Cloud 依赖项。我已经安装了以下软件。

pipenv install google-cloud-storage httplib2 google-api-python-client google-cloud-bigquery pandas_gbq

创建 DAG

下面是将执行上述步骤的 DAG 的代码。这应该作为一个.py文件保存在我们之前创建的 dags 目录中。

在 DAG 的顶部是必需的导入。Airflow 提供了一系列操作人员来执行谷歌云平台上的大多数功能。我已经导入了用于运行查询和加载数据的 BigQueryOperator ,以及用于检查特定日期的数据是否存在的 BigQueryCheckOperator

在 dag 的下一部分,我们定义 dag_args,然后创建 DAG,它提供诸如 dag_id、start_date 和任务运行频率等信息。Airflow 使用 CRON 表达式来定义时间表,有关这些表达式的更多信息,请访问此页面

然后,我们将每个步骤定义为一个任务,我将它们定义为变量 t1 和 t2。这些任务各自执行工作流中的特定步骤。在 DAG 的最底部可以找到它们的运行顺序。

我们现在可以转到 web 用户界面,运行 DAG。

如果我们转到 BigQuery 控制台,我们还会看到 Airflow 创建并加载了数据的表。

本文旨在全面介绍如何使用气流创建第一个 DAG。有关更详细的使用指南,可在这里找到气流文件。

文章中详细描述的完整项目的链接可以在这个 Github 资源库中找到。

感谢阅读!

我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分!

Python 中从头开始的完整 K 均值聚类算法:分步指南

原文:https://towardsdatascience.com/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461?source=collection_archive---------1-----------------------

彼得·诺伊曼在 Unsplash 上的照片

还有,如何使用 K 均值聚类算法对图像进行降维

什么是 K 均值聚类?

k 均值聚类是最流行和最广泛使用的无监督学习模型。它也称为聚类,因为它通过对数据进行聚类来工作。与监督学习模型不同,非监督模型不使用标记数据。

该算法的目的不是预测任何标签。取而代之的是更好地了解数据集并给它们贴上标签。

在 k 均值聚类中,我们将数据集聚类成不同的组。

下面是 k 均值聚类算法的工作原理

  1. 第一步,随机初始化几个点。这些点被称为簇形心。

在上图中,红色和蓝色的点是星团的质心。

可以选择任意数量的簇质心。但是聚类质心的数量必须少于数据点的总数。

2.第二步是集群分配步骤。在这一步,我们需要遍历每个绿点。根据这个点是靠近红点还是蓝点,我们需要把它分配给其中一个点。

换句话说,根据绿点是更接近蓝色簇形心还是红色簇形心,将绿点涂成红色或蓝色。

3.下一步是移动簇的质心。现在,我们必须取分配给红色聚类质心的所有红点的平均值,并将红色聚类质心移动到该平均值。我们需要对蓝色星团的质心做同样的操作。

现在,我们有了新的簇形心。我们必须回到第二步,集群分配步骤。我们需要将这些点重新排列成新的簇形心。在重复第三遍之后。

数字 2 和 3 需要重复几次,直到两个簇的质心都在合适的位置,如下图所示。

看,我们只是根据它们被分配到的簇质心给所有的绿点着色。蓝色群集质心位于蓝色群集的中心,而红色群集质心位于红色群集的中心。

当我们开发算法的时候,事情会变得更加清楚。我们将对此进行更详细的讨论。

开发算法

我将用于该算法的数据集是从 Coursera 的吴恩达的机器学习课程中获得的。以下是开发 k 均值算法的逐步指南:

1。导入必要的包和数据集

import pandas as pd
import numpy as np
df1 = pd.read_excel('dataset.xlsx', sheet_name='ex7data2_X', header=None)
df1.head()

数据集只有两列。我选择了两个特色数据集,因为它易于可视化。当你看到视觉效果时,你会更容易理解这个算法。但是同样的算法也适用于多维数据集。

我将把数据帧 df1 转换成一个 Numpy 数组,因为我们将在这个过程中处理其他数组:

X = np.array(df1)

现在,我将遵循我上面讨论的三个步骤。

2。第一步是随机初始化质心。

我将从数据集中随机初始化三个点。首先,我将在 0 和数据集长度之间选择三个数字。

import random
init_centroids = random.sample(range(0, len(df1)), 3)
init_centroids

输出:

[95, 30, 17]

以这三个数为指标,得到这些指标的数据点。

centroids = []
for i in init_centroids:
    centroids.append(df1.loc[i])
centroids

输出:

[0    3.907793
 1    5.094647
 Name: 95, dtype: float64,
 0    2.660466
 1    5.196238
 Name: 30, dtype: float64,
 0    3.007089
 1    4.678978
 Name: 17, dtype: float64]

这三个点是我们的初始质心。

我会把它们转换成二维数组。因为我更熟悉这种格式。

centroids = np.array(centroids)

输出:

array([[3.90779317, 5.09464676],
       [2.66046572, 5.19623848],
       [3.00708934, 4.67897758]])

3。实施集群分配步骤。

在这一步中,我们将遍历数据集中的所有数据点。

一个数据点意味着一行数据

让我们以单行数据为例,了解如何将该数据分配给一个集群。

我们将计算该数据到所有三个质心的距离。然后将该数据点分配给与它距离最小的质心。

正如我们看到的,我们必须计算两点之间的距离。让我们开发一个函数来计算距离。

def calc_distance(X1, X2):
    return(sum((X1 - X2)**2))**0.5

开发一个函数,将每个数据点分配给一个质心。我们的“质心”数组只有三个值。所以我们有三个指数:0,1,2。我们将这些指数中的一个分配给每个数据点。

def findClosestCentroids(ic, X):
    assigned_centroid = []
    for i in X:
        distance=[]
        for j in ic:
            distance.append(calc_distance(i, j))
        assigned_centroid.append(np.argmin(distance))
    return assigned_centroid

这是将数据点分配给聚类的功能。让我们使用这个函数来计算每个数据点的质心:

get_centroids = findClosestCentroids(centroids, X)
get_centroids

部分输出:

[2,
 0,
 0,
 2,
 1,
 2,
 2,
 2,
 1,
 1,
 2,
 2,
 2,
 2,
 2,
 2,
 0,

总输出长。我在这里展示了部分输出。输出中的第一个质心是 2,这意味着它被分配给质心列表的索引 2。

4。最后一步是根据数据点的平均值 移动质心

在这一步中,我们将取每个质心的所有数据点的平均值,并将质心移动到该平均值。

例如,我们将找到在索引 2 处分配给质心的所有点的平均值,并将质心 2 移动到平均值。对索引 0 和 1 处的质心做同样的操作。

让我们定义一个函数来做这件事:

def calc_centroids(clusters, X):
    new_centroids = []
    new_df = pd.concat([pd.DataFrame(X), pd.DataFrame(clusters, columns=['cluster'])],
                      axis=1)
    for c in set(new_df['cluster']):
        current_cluster = new_df[new_df['cluster'] == c][new_df.columns[:-1]]
        cluster_mean = current_cluster.mean(axis=0)
        new_centroids.append(cluster_mean)
    return new_centroids

这些都是我们需要开发的功能。

正如我之前讨论过的,我们需要重复这个聚类分配和移动质心的过程几次,直到质心在一个合适的位置。

对于这个问题,我选择重复这个过程 10 次。我将在每次迭代后继续绘制质心和数据,直观地向您展示它是如何工作的。

for i in range(10):
    get_centroids = findClosestCentroids(centroids, X)
    centroids = calc_centroids(get_centroids, X)
    #print(centroids)
    plt.figure()
    plt.scatter(np.array(centroids)[:, 0], np.array(centroids)[:, 1], color='black')
    plt.scatter(X[:, 0], X[:, 1], alpha=0.1)
    plt.show()

经过五次迭代后,质心被设置到它们的最佳位置。所以在那之后他们没有改变立场。

我建议,在尝试降维之前,请运行上面的所有代码并学好它。

否则你可能会不知所措!此外,我现在将移动得更快一点,因为我们已经详细解释了算法。

维度缩减

我想至少解释一下这个算法的一个用例。一个非常有用的用例是降维。

想一个形象。一幅图像中可能有许多不同的像素。在任何计算机视觉问题中,如果我们能够降低图片的尺寸,设备读取该图片的速度将会快很多!不是吗?

我们可以使用我们刚刚开发的算法来降低图片的尺寸。

我将用一只青蛙的图片来演示这一点:

作者图片

我把这张照片上传到了我笔记本的同一个文件夹里。让我们导入这个:

import cv2
im = cv2.imread('frog.png')
im

输出:

array([[[  2,  57,  20],
        [  2,  57,  20],
        [  2,  57,  21],
        ...,
        [  0,   5,   3],
        [  8,  12,  11],
        [ 91,  94,  93]],       [[  2,  56,  20],
        [  1,  54,  20],
        [  1,  56,  19],
        ...,
        [  0,   2,   1],
        [  7,   9,   8],
        [ 91,  92,  91]],       [[  2,  55,  20],
        [  2,  53,  19],
        [  1,  54,  18],
        ...,
        [  2,   4,   2],
        [  8,  11,   9],
        [ 91,  93,  91]],       ...,       [[  6,  76,  27],
        [  6,  77,  26],
        [  6,  78,  28],
        ...,
        [  6,  55,  18],
        [ 13,  61,  25],
        [ 94, 125, 102]],       [[  9,  79,  31],
        [ 11,  81,  33],
        [ 12,  82,  32],
        ...,
        [  6,  56,  19],
        [ 14,  61,  27],
        [ 96, 126, 103]],       [[ 43, 103,  63],
        [ 44, 107,  66],
        [ 46, 106,  66],
        ...,
        [ 37,  81,  50],
        [ 47,  88,  59],
        [118, 145, 126]]], dtype=uint8)

检查阵列的形状,

im.sgape

输出:

(155, 201, 3)

我将整个数组除以 255,使所有的值从 0 到 1。

然后将其整形为 155*201 x 3,使其成为二维数组。因为我们之前为二维数组开发了所有的函数。

im = (im/255).reshape(155*201, 3)

正如你在上面看到的,这么多不同的像素值。我们想减少它,只保留 10 像素的值。

让我们初始化 10 个随机索引,

random_index = random.sample(range(0, len(im)), 10)

现在,像我们在前面的例子中做的那样找到质心:

centroids = []
for i in random_index:
    centroids.append(im[i])
centroids = np.array(centroids)

输出:

array([[0.00392157, 0.21176471, 0.06666667],
       [0.03529412, 0.2627451 , 0.09803922],
       [0.29411765, 0.3254902 , 0.26666667],
       [0.00784314, 0.18431373, 0.05882353],
       [0.29019608, 0.49411765, 0.28235294],
       [0.5254902 , 0.61176471, 0.48627451],
       [0.04313725, 0.23921569, 0.09803922],
       [0.00392157, 0.23529412, 0.0745098 ],
       [0.00392157, 0.20392157, 0.04705882],
       [0.22352941, 0.48235294, 0.40784314]])

现在我也要把' im '转换成一个数组,

im = np.array(im)

数据准备好了。现在我们可以继续我们的聚类过程。但这一次,我不会把它形象化。因为数据不再是二维的了。所以,可视化并不容易。

for i in range(20):
    get_centroids = findClosestCentroids(centroids, im)
    centroids = calc_centroids(get_centroids, im)

我们现在得到了更新的质心。

centroids

输出:

[0    0.017726
 1    0.227360
 2    0.084389
 dtype: float64,
 0    0.119791
 1    0.385882
 2    0.247633
 dtype: float64,
 0    0.155117
 1    0.492051
 2    0.331497
 dtype: float64,
 0    0.006217
 1    0.048596
 2    0.019410
 dtype: float64,
 0    0.258289
 1    0.553290
 2    0.406759
 dtype: float64,
 0    0.728167
 1    0.764610
 2    0.689944
 dtype: float64,
 0    0.073519
 1    0.318513
 2    0.170943
 dtype: float64,
 0    0.035116
 1    0.273665
 2    0.114766
 dtype: float64,
 0    0.010810
 1    0.144621
 2    0.053192
 dtype: float64,
 0    0.444197
 1    0.617780
 2    0.513234
 dtype: float64]

这是最后一步。我们只会保留这 10 个点。

如果您也打印 get_centroids,您将看到集群分配。

现在,我们要遍历整个数组' im ',并将数据更改为其对应的聚类质心值。这样,我们将只有这些质心值。

我不想改变原来的数组,而是想做一个拷贝并在那里进行修改。

im_recovered = im.copy()
for i in range(len(im)):
    im_recovered[i] = centroids[get_centroids[i]]

正如你所记得的,我们改变了图像的维度,在开始时,使它成为一个二维数组。我们现在需要把它改成原来的形状。

im_recovered = im_recovered.reshape(155, 201, 3)

在这里,我将并排绘制原始图像和缩小图像,向您展示两者的区别:

im1 = cv2.imread('frog.png')
import matplotlib.image as mpimg
fig,ax = plt.subplots(1,2)
ax[0].imshow(im1)
ax[1].imshow(im_recovered)

作者图片

看,我们把图像的尺寸缩小了很多。尽管如此,它看起来像一只青蛙!但是电脑阅读的速度会快得多!

结论

在本文中,我解释了 k 均值聚类是如何工作的,以及如何从头开始开发 k 均值聚类算法。我还解释了,如何使用这种算法来降低图像的维度。请尝试使用不同的图像。

这是我在本文中使用的数据集的链接。

[## rashida 048/用 Python 进行机器学习

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/kmean.xlsx)

以下是完整代码的 GitHub 链接:

[## rashida 048/用 Python 进行机器学习

github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/k_mean_clustering_final.ipynb)

阅读推荐:

[## Python 中的线性回归算法:一步一步

学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法

towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8) [## Python 中多元线性回归的逐步实现

学习用 Python 从头开始开发任意数量变量的多元线性回归。

towardsdatascience.com](/multivariate-linear-regression-in-python-step-by-step-128c2b127171) [## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## Python 中从头开始的多项式回归

学习用一些简单的 python 代码从头开始实现多项式回归

towardsdatascience.com](/polynomial-regression-from-scratch-in-python-1f34a3a5f373) [## 用 Python 从头开始构建神经网络

神经网络的详细说明和逐步实现

medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## Python 中从头开始的完整异常检测算法:分步指南

基于概率的异常检测算法

towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## 学习机器学习和深度学习的优质免费课程

顶级大学高质量免费课程的链接

towardsdatascience.com](/great-quality-free-courses-to-learn-machine-learning-and-deep-learning-1029048fd0fc)

Python 中从头开始的完整逻辑回归算法:一步一步

原文:https://towardsdatascience.com/a-complete-logistic-regression-algorithm-from-scratch-in-python-step-by-step-ce33eae7d703?source=collection_archive---------5-----------------------

爱丽丝·华生在 Unsplash 上拍摄的照片

使用真实世界的数据集开发算法

逻辑回归是上个世纪以来流行的一种方法。它建立了分类变量和一个或多个自变量之间的关系。这种关系在机器学习中用于预测分类变量的结果。它广泛应用于许多不同的领域,如医疗领域、贸易和商业、技术等。

本文解释了开发二元分类算法的过程,并在 Kaggle 的心脏病数据集上实现了该算法。

问题陈述

在本文中,我们将使用来自 Kaggle 的数据集,其中包含人口的健康数据。它的最后有一栏包含一个人是否有心脏病。我们的目标是看看我们是否能利用表格中的其他列来预测一个人是否患有心脏病。

在这里,我将加载数据集。为此,我将使用熊猫:

import pandas as pd
import numpy as np
df = pd.read_csv('Heart.csv')
df.head()

数据集如下所示:

Haert.csv 数据集的前五行

查看数据集的最后一列。它是“AHD”。这表示有心脏病。我们将使用其余的专栏来预测心脏病。因此,在未来,如果我们有了所有的数据,我们将能够预测一个人是否患有心脏病,而无需医学检查。

我们的输出将是 0 或 1。如果一个人有心脏病,我们的算法将返回 1,如果一个人没有心脏病,算法将返回 0。

重要方程式

记住线性回归公式。直线的最基本公式:

Y= A+BX

其中 A 是截距,B 是斜率。如果我们避开等式中的“截距”A,则公式变为:

Y = BX

传统上,在机器学习中,它被表示为,

这里,“h”是假设或预测值,X 是预测值或输入变量。θ在开始时被随机初始化,随后被更新。

对于逻辑回归,我们需要使用一个返回从 0 到 1 的值的 sigmoid 函数来转换这个简单的假设。sigmoid 函数也可以称为逻辑函数。逻辑回归使用 sigmoid 函数来预测输出。这是 sigmoid 激活函数:

z 是输入特征乘以随机初始化项θ。

这里,X 是输入特征,θ是将在该算法中更新的随机初始化值。

我们需要使用逻辑函数的原因是,逻辑函数的曲线看起来像这样:

作者图片

从上图可以看出,它返回 0 到 1 之间的值。所以,对分类很有帮助。因为我们今天将研究二元分类,

如果逻辑函数返回的值小于 0.5,我们将返回零;如果逻辑函数返回的值大于或等于 0.5,我们将返回 1

成本函数

成本函数为您提供了预测输出(计算的假设“h”)与原始输出(数据集中的“AHD”列)之间的距离。

在深入研究逻辑回归的成本函数之前,我想提醒你一下线性回归的成本函数,它要简单得多。线性回归的成本是:

在哪里,

y 是原始标签(数据集的“AHD”列)

平均成本函数是:

在哪里,

m 是训练数据的数量

上面的等式首先取预测标签“h”和原始标签“y”之间的差。该公式包括平方以避免任何负值,并使用 1/2 来优化该平方。

这个简单明了的方程适用于线性回归,因为线性回归使用一个简单的线性方程:(Y= A+BX)。

但是逻辑回归使用的是非线性的 sigmoid 函数。

我们不能在这里使用简单成本函数,因为它不会收敛到全局最小值。为了解决这个问题,我们将使用日志来正则化成本函数,以便它收敛到全局最小值。

下面是我们将用来保证全局最小值的成本函数:

如果 y = 1,

成本(h,y) = -log(h)

如果 y = 0,

Cost(h,y) = -log(1 — h)

简化组合成本函数:

下面是成本函数表达式:

为什么是这个等式?看,我们只能有两种情况 y = 0 或 1。在上面的成本函数等式中,我们有两项:

  1. y*logh 和
  2. (1-y)*对数(1-h)。

如果 y = 0,第一项变为 0,第二项变为 log(1-h)。在等式中,我们已经在开头加了一个负号。

如果 y = 1,第二项变为零,只剩下 y 长项,开头是负号。

希望现在有意义!

梯度下降

我们需要更新随机初始化的θ值。梯度下降方程就是这样。如果我们对成本函数相对于θ取偏导数:

使用上面的这个表达式,梯度下降公式变成:

这里,α是学习率。

使用这个等式,θ值将在每次迭代中更新。你什么时候用 python 实现 thin,你就更清楚了。

这是使用上述所有等式来开发算法的时候了

模型开发

第一步:提出假设。

该假设只是 sigmoid 函数的实现。

def hypothesis(X, theta):
    z = np.dot(theta, X.T)
    return 1/(1+np.exp(-(z))) - 0.0000001

我从这里的输出中减去了 0.0000001,因为成本函数中有这样一个表达式:

如果假设表达式的结果是 1,那么这个表达式将是 0 的对数。为了减轻这一点,我在最后用了这个很小的数字。

第二步:确定成本函数。

def cost(X, y, theta):
    y1 = hypothesis(X, theta)
    return -(1/len(X)) * np.sum(y*np.log(y1) + (1-y)*np.log(1-y1))

这只是上面的成本函数等式的简单实现。

第三步:更新θ值。

θ值需要不断更新,直到成本函数达到最小值。我们应该得到最终的θ值和每次迭代的成本作为输出。

def gradient_descent(X, y, theta, alpha, epochs):
    m =len(X)
    J = [cost(X, y, theta)] 
    for i in range(0, epochs):
        h = hypothesis(X, theta)
        for i in range(0, len(X.columns)):
            theta[i] -= (alpha/m) * np.sum((h-y)*X.iloc[:, i])
        J.append(cost(X, y, theta))
    return J, theta

第四步:计算最终预测和精度

使用“gradient_descent”函数得出的θ值,并使用 sigmoid 函数计算最终预测值。然后,计算精度。

def predict(X, y, theta, alpha, epochs):
    J, th = gradient_descent(X, y, theta, alpha, epochs) 
    h = hypothesis(X, theta)
    for i in range(len(h)):
        h[i]=1 if h[i]>=0.5 else 0
    y = list(y)
    acc = np.sum([y[i] == h[i] for i in range(len(y))])/len(y)
    return J, acc

最终输出是每个时期的成本列表和精确度。让我们实现这个模型来解决一个实际问题。

数据预处理

我已经在开始展示了数据集。但是为了您的方便,我在这里再次包括它:

请注意,数据集中有一些分类要素。我们需要将它们转换成数字数据。

df["ChestPainx"]= df.ChestPain.replace({"typical": 1, "asymptomatic": 2, "nonanginal": 3, "nontypical": 4})
df["Thalx"] = df.Thal.replace({"fixed": 1, "normal":2, "reversable":3})
df["AHD"] = df.AHD.replace({"Yes": 1, "No":0})

为偏差添加一个额外的列。这应该是一列 1,因为任何实数乘以 1 都保持不变。

df = pd.concat([pd.Series(1, index = df.index, name = '00'), df], axis=1)

定义输入特征和输出变量。输出列是我们要预测的分类列。输入特征将是除了我们之前修改的分类列之外的所有列。

X = df.drop(columns=["Unnamed: 0", "ChestPain", "Thal"])
y= df["AHD"]

获得准确性结果

最后,在一个列表中初始化 theta 值,并预测结果和计算精度。这里我初始化θ值为 0.5。它可以初始化为任何其他值。由于每个特征应该具有相应的θ值,所以应该为 X 中的每个特征初始化一个θ值,包括偏差列。

theta = [0.5]*len(X.columns)
J, acc = predict(X, y, theta, 0.0001, 25000)

最终准确率为 84.85%。我用 0.0001 作为学习率,25000 次迭代。

我运行了几次这个算法来确定。

请检查下面提供的这个项目我的 GitHub 链接。

“预测”函数还会返回每次迭代的成本列表。在一个好的算法中,成本应该在每次迭代中保持下降。绘制每一次迭代的成本,以可视化趋势。

%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize = (12, 8))
plt.scatter(range(0, len(J)), J)
plt.show()

成本在开始时下降很快,然后下降的速度慢了下来。这是一个完美的成本函数的行为!

结论

我希望这是有帮助的。如果你是一个初学者,一开始要掌握所有的概念会有点难。但是我建议请你在笔记本上自己运行所有代码,仔细观察输出。这将非常有帮助。这种类型的逻辑回归对于许多现实世界的问题是有帮助的。我希望,你会用它来开发一些很酷的项目!

如果您在运行任何代码时遇到问题,请在评论部分告诉我。

在这里您可以找到完整的代码:

[## rashida 048/用 Python 进行机器学习

github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/LogisticRegressionWithHeartDataset.ipynb)

更多阅读:

[## Python 中的线性回归算法:一步一步

学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法

towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8) [## 一个完整的推荐系统从零开始:一步一步

基于用户评分的线性回归电影推荐系统

towardsdatascience.com](/a-complete-recommender-system-from-scratch-in-python-step-by-step-6fc17a4da054) [## Python 中从头开始的完整异常检测算法:分步指南

基于概率的异常检测算法

towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## 学习使用 Python 的 Scikit_learn 库通过项目开发 KNN 分类器

适合机器学习新手

towardsdatascience.com](/clear-understanding-of-a-knn-classifier-with-a-project-for-the-beginners-865f56aaf58f) [## 数据科学家使用 Python 进行假设检验的完整指南

用样本研究问题、解决步骤和完整代码清楚地解释

towardsdatascience.com](/a-complete-guide-to-hypothesis-testing-for-data-scientists-using-python-69f670e6779e)

scikit-learn 中完整的 NLP 分类管道

原文:https://towardsdatascience.com/a-complete-nlp-classification-pipeline-in-scikit-learn-bf1f2d5cdc0d?source=collection_archive---------15-----------------------

六路分类的混淆矩阵(TF-IDF 与朴素贝叶斯分类器)

使用这个自然语言处理分类管道的完整指南,从语料库到分类。

我们将在这个故事中讲述的内容:

  • 阅读文集
  • 基本脚本结构包括loggingargparseifmain
  • 训练/测试分割
  • 先验和后验类概率
  • 基线分类
  • FeatureUnion链接多个特征
  • 在一只熊猫DataFrame和一个困惑矩阵中显示结果

这个故事最重要的部分是 scikit-learn/sklearn 的PipelineFeatureUnionTfidfVectorizer和一个使用seaborn包的confusion_matrix 的可视化,但也包括更多的一般内容,如ifmainargparseloggingzip*args

资料组

我们将使用亚马逊评论的数据集和简单而有效的朴素贝叶斯进行分类。trainset.txt包含取自约翰霍普金斯大学多领域情感数据集的评论集,并在空格分隔的.csv文件中转换为以下格式。

music neg 575.txt the cd came as promised and in the condition promised . i 'm very satisfied

正如你所看到的,评论已经用来自nltk包的空白标记符进行了标记。每个评论占一行,前面有两个标签和评论的标识符:

  • 指定六个主题之一的标签:bookscameradvdhealthmusicsoftware
  • 用正值或负值表示评论所表达的情绪的标签:posneg

该数据集使我们能够对评论的情感进行二元分类或多类分类,并以这样一种方式创建我们的脚本,即用户可以指定要处理的分类任务。

脚本结构:导入、日志和 argparse

我们正在使用argparse和函数标志(如use_sentiment)设置我们的管道,以便我们能够从命令行执行二进制(pos | neg)分类任务和多类分类任务(book | camera | dvd | health | music | software)。

对于那些不熟悉的人来说,argparse是一个非常有用的包,它支持用户友好的命令行界面。如果缺少必需的参数,它会显示一个错误,并显示所有可以使用的不同参数。参数前面有参数标签--input和一个空格:

$ python3 pipeline.py --input trainset.txt --binary

我们还添加了一个verbosity标志--v,并使用 Python 的logging功能来输出警告、错误或信息。用args = parser.parse_args()解析完参数后,你可以在脚本中用args.inputargs.verbosity使用这些参数的输入。

注意 argparse没有type=bool,这意味着所有 get 都被解析为str。为了添加布尔标志,可以设置action="store_true",默认为False布尔,如果包含标志--binary,将自动产生True布尔。

我们将把这个故事中的所有函数链接到一个main()函数中,这个函数将被if __name__ == '__main__'语句自动调用。在命令行中调用这个文件时,Python 解释器读取源文件,并将__name__变量设置为'__main__'。这样,我们可以读取源文件并执行其中的函数,但也可以将该文件用作其他脚本的moduleimport ,而无需自动执行main()中的语句。

阅读语料库

首先我们需要阅读我们的文集。这个函数将利用来自我们的argparse函数的--binary标志来确定我们是在做二元分类还是多类分类。

训练/测试分割

现在我们在documents有了我们的评论,在labels有了我们的类,我们将把它们分成训练集和测试集,用于我们的分类器。我们将使用slice notation [:]进行 80%的培训和 20%的测试。首先,我们需要调整我们的数据,以确保这一部分不会影响结果:由于我们不知道语料库中的文档是如何排序的,因此在训练/测试集中,类可能会过多。例如,它们可以按字母顺序排序,这可能导致在我们的训练集中只有类别book | camera | dvd | health

因为我们正在创建一个这样的元组列表[(doc1, 'neg'), (doc2, 'pos')],所以我们可以使用一个简洁的 python 函数zip*来遍历这个列表,并将元组分隔在一个文档列表[doc1, doc2, doc3]和一个标签列表['pos', 'neg', 'pos']中。

:虽然这个函数看起来有点冗长,但我还是把它包括在内了,因为这样可以很好地看到这个函数背后发生了什么。您也可以使用 sklearn 的train_test_split函数,它的功能基本相同,或者使用k-fold cross-validation:在训练和测试中分割数据集k次,并取每个分类的平均值,以确保分割对分数的影响尽可能小。

先验和后验类概率

对于手头的分类任务,我们将使用朴素贝叶斯分类器,它利用了贝叶斯定理:计算结合了分类器中包括的特征(如 tf-idf 或 counts)的类的新概率分布,这将使新的概率分布更能代表数据。

为了理解后验概率,将它们与先验分布进行比较是有用的。因此,我们将首先计算我们的语料库中所有文档的类别的先验概率,或者反过来:我们的语料库中的一个文档具有某个类别的概率。后验概率可以用classifier.predict_proba来计算。

基线分类

为了比较评估度量(准确性)和朴素贝叶斯分类器的混淆矩阵,我们将创建一个非常简单的基线:使用random包,我们将从一组可能的标签中为每个文档随机分配一个标签。我们还可以创建一个基线,将每个类别的先验概率考虑在内。

具有 FeatureUnion 的多个功能

对于此分类任务,我们将添加分类器中包含的三个功能:

  1. 计数向量器,在每个标记后附加位置标签
  2. TF-IDF 矢量器(在文档频率中使用非常强大的术语频率)
  3. 特征工程的一个例子,特征长度包含在管道中,特征值映射到DictVectorizer中的向量。

现在这段代码有点复杂,但它只是一个示例,说明了如何在一个 FeatureUnion 管道中追加多个功能,甚至包括(. 3)中的管道。

我在函数feature_union()中为每个特性添加了一个标志,这样你就可以相应地打开和关闭特性。

显示结果

现在我们也要展示我们的成果。我们可以使用 sklearn 的classification_reportaccuracy_scoreconfusion_matrix以及最后一个的seaborn包。

tabular_results()用标记化的句子、实际标签、预测标签和先验/后验概率创建熊猫数据帧。class_report()显示分类器的准确度分数,并有一个标志show_matrix,用于使用vis()功能显示混淆矩阵的美丽可视化。

把管道拼起来!

我们阅读我们的语料库>分割训练/测试中的数据>计算先验概率>创建我们三个特征的特征联合>使分类器适合数据>进行预测>计算后验概率>创建数据帧>报告基线结果>报告朴素贝叶斯的结果。

对于我们的六类分类,基线的准确度分数保持在大约0.16/0.17左右,对于我们的二类分类,准确度分数保持在大约0.5左右,这是合乎逻辑的,因为它是类的概率/数量。对于所有三个特征的组合,朴素贝叶斯准确度得分为0.685,仅使用 tf-idf 向量时得分最高0.901。这表明特征工程并不总是产生更好的结果!

完整的脚本和数据集可以在这里找到。记住,您可以使用--v将二进制分类的--binary标志和详细度标志设置为不同的级别(4用于调试),以查看分类器的classification_report。此外,feature_union()具有开启/关闭不同功能的标志,class_report()具有显示混淆矩阵的标志。

完整的熊猫数据科学术语表

原文:https://towardsdatascience.com/a-complete-pandas-glossary-for-data-science-a3bdd37febeb?source=collection_archive---------10-----------------------

学习熊猫基础知识的最佳资源

像大多数其他人一样,我试图通过新兵训练营学习熊猫——不幸的是,新兵训练营的问题是,如果你不练习你所学的东西,你会很快忘记一切!

与此同时,我发现需要一个中央熊猫资源,以便我在从事个人数据科学项目时可以参考。这就是为什么会有这样的结果。把这个作为学习熊猫的资源,也作为参考!

目录

  1. 设置
  2. 创建和读取数据
  3. 操纵数据帧
  4. 汇总功能
  5. 映射功能
  6. 对变量进行分组和排序
  7. 处理缺失数据

设置

导入熊猫库

import pandas as pd

创建和读取数据

创建数据框架

数据帧只是一个由多个数组组成的表。在下面的示例中,代码将创建一个包含 ABC 和 DEF 两列的表。

pd**.DataFrame**({'ABC':[1,2,3],'DEF':[4,5,6]},index=[1,2,3])

创建一个系列

系列是一系列值,也称为列表。从视觉角度来看,想象它是表格中的一列。

pd**.Series**([1,2,3],index=[], name ='ABC')

将 CSV 文件读入数据帧

获取数据的最常见方式。这将 CSV 文件转换为数据帧。

# example
df = pd**.read_csv**("filename.csv", index_col=0)

将数据帧转换为 CSV 文件

反之亦然,如果您想将 DataFrame 转换成 CSV,可以使用下面的代码:

# example
df**.to_csv**("filename.csv", index_col=0)

确定数据帧的形状

这将告诉您数据帧有多大,格式是什么(行,列)。

df**.shape()**

查看数据帧的前 5 行

如果你想对数据帧有一个直观的了解。head() 返回给定数据帧的前 5 行。

df**.head()**

查看一列或多列的数据类型

# For one column
df.variable**.dtype**# For all columns
df**.dtypes**

将列转换为另一种数据类型

如果您想将整数转换成浮点数(反之亦然),这是很有用的。

df.variable**.astype()**

操作数据帧

从数据帧中选择系列

# a) Method 1
df.property_name# b) Method 2
df['property_name']

索引系列

# if you want to get the first value in a series
df['property_name'][0]

基于索引的选择

基于索引的选择根据数据在数据帧中的数字位置检索数据。它遵循行优先,列第二的格式。Iloc 的索引方案是这样的:第一个数字包含,最后一个数字不包含

df**.iloc[]**

基于标签的选择

基于标签的选择是索引数据帧的另一种方式,但它基于实际数据值而不是数字位置来检索数据。Loc 的索引方案使得的第一个和最后一个值都包含在内。

df**.loc[]**

使用现有列设置索引

因为基于标签的选择依赖于数据帧的索引,所以可以使用。set_index() 将一列分配给索引。

df.**set_index**("variable")

基于条件标签的选择

我们也可以使用基于标签的选择来过滤出数据帧。

# a) Single Condition 
df.loc[df.property_name == 'ABC']# b) Multiple conditions using AND
df.loc[df.property_name == 'ABC' & df.property_name == 'DEF']# c) Multiple conditions using OR
df.loc[df.property_name == 'ABC' | df.property_name == 'DEF']

选择值在值列表中的位置

我们也可以使用 isin() 来过滤数据帧。如果你懂 SQL,它类似于 WHERE ___ IN()语句。

df.loc[df.property_name **isin**(['ABC','DEF'])

选择值为空/不为空的位置

第一行代码将过滤 DataFrame,只显示属性名为 null 的行。
反之亦然,第二行代码用 filter it 使属性名不为空。

df.loc[df.property_name**.isnull**()]df.loc[df.property_name**.notnull()**]

添加新列

df['new_column'] = 'ABC'

重命名列

您通常会希望将列重命名为更容易引用的名称。使用下面的代码,列 ABC 将被重命名为 DEF。

df.**rename**(columns={'ABC': 'DEF'})

汇总函数

。描述()

这给出了数据帧或变量的高级摘要。它是类型敏感的,这意味着与字符串变量相比,数字变量的输出是不同的。

df**.describe()**
df.variable**.describe()**

。平均值()

这将返回变量的平均值。

df.variable**.mean()**

。唯一()

这将返回变量的所有唯一值。

df.variable**.unique()**

。值计数()

这显示了唯一值的列表以及数据帧中出现的频率。

df.variable.**value_counts()**

映射函数

。地图()

映射用于通过函数将一组初始值转换为另一组值。例如,我们可以使用映射将列的值从米转换为厘米,或者我们可以将这些值标准化。

。map()用于转换一个序列。

df.numerical_variable**.map()**

。应用()

。apply()类似于。map(),只是它转换整个数据帧。

df.numerical_variable**.apply()**

分组和排序

。groupby()

获取变量的每个值的计数(与 value_counts 相同)

df**.groupby**('variable').variable**.count()**

获取变量的每个值的最小值

df**.groupby**('variable').variable**.min()**

获取变量的每个值的汇总(长度、最小值、最大值)

df**.groupby**(['variable']).variable.**agg([len, min, max])**

多重索引

df.groupby(['variable_one', 'variable_two'])

对数据帧排序

按一个变量排序

df.**sort_values**(by='variable', ascending=False)

多变量排序

df.sort_values(by=['variable_one', 'variable_two'])

按指标排序

df**.sort_index()**

处理缺失数据

处理缺失数据是 EDA 中最重要的步骤之一。下面是一些处理缺失数据的方法。

计算每列中空值的数量

df.isna().sum()

删除包含空值的行

如果您有一个包含大量行的数据帧,并且您能够完全删除包含空值的行,那么。dropna()是一个有用的工具。

df.**dropna()**

删除包含空值的列

这与上面的类似,除了它删除任何具有空值的而不是行。

df.**dropna(axis=1)**

填充缺失值

如果您希望填充缺少的值,而不是完全删除行或列,可以使用下面的代码:

df.variable**.fillna**("n/a")

替换值

假设有一个数据帧,其中有人已经用“n/a”填充了缺失值,但是您希望用“unknown”填充缺失值。那么您可以使用下面的代码:

df.variable**.replace**("n/a", "unknown")

组合数据

。concat()

当您想要合并具有相同列的两个数据帧时,这很有用。例如,如果我们想将一月份的销售额和二月份的销售额结合起来分析长期趋势,您可以使用以下代码:

Jan_sales = pd.read_csv("jan_sales.csv")
Feb_sales = pd.read_csv("feb_sales.csv")

**pd.concat**([Jan_sales, Feb_sales])

。加入()

如果您想要合并具有公共索引的两个列(例如 customer_id),那么您可以使用。加入()。

使用上的参数来确定要连接的列。

要确定它是左连接、右连接、内连接还是外连接,可以使用参数

# example
table_1.**join**(table_2, on='customer_id', *how='left')*

如果你不了解 SQL joins,在这里阅读。本质上是一样的想法。****

希望这有帮助!如果你觉得我遗漏了什么或者有什么不清楚的地方,请提供意见。谢谢!

感谢阅读!

如果你喜欢我的工作,想支持我…

  1. 支持我的最好方式就是在媒体这里关注我**
  2. 在成为第一批在Twitter上关注我的人之一。我会在这里发布很多更新和有趣的东西!**
  3. 此外,成为第一批订阅我的新 YouTube 频道 这里
  4. 关注我LinkedIn这里。**
  5. 在我的邮箱列表* 这里报名。***
  6. 看看我的网站,terenceshin.com

完整的熊猫指南

原文:https://towardsdatascience.com/a-complete-pandas-guide-2dc53c77a002?source=collection_archive---------12-----------------------

构建强大的数据分析流程

数据科学项目中最耗时的部分是数据清理和准备。Pandas 是一个非常强大和通用的 Python 数据分析库,可以加速项目的预处理步骤。在这篇文章中,我将通过许多例子来介绍 Pandas 的许多功能,这些例子可以帮助您构建一个健壮而高效的数据分析过程。

Unsplash 上由 threeedil 拍摄的照片

这些主题按如下顺序排列:

  1. 输入数据
  2. 数据概述
  3. 处理缺失值
  4. 组合数据帧
  5. 选择数据帧上的数据
  6. 重塑数据帧
  7. 其他熊猫功能

Pandas 的基本数据结构是 DataFrame ,它以表格的形式表示数据,带有标记的行和列。

一如既往,我们从进口熊猫开始。

import numpy as np
import pandas as pd

1。输入数据

从文件中读取

在大多数情况下,我们从文件中读取数据并转换成数据帧。Pandas 提供了从许多不同的文件类型中读取数据的功能。最常用的是 read_csv 。其他类型也有,比如 read_excel,read_json,read_html 等等。让我们来看一个使用 read_csv 的例子:

df = pd.read_csv("Churn_Modelling.csv")
df.head()

我们需要指定文件的位置。在文件位于同一个工作目录或文件夹中时,你可以只写文件名。df.head()显示前 5 行。

如果我们只需要数据帧的一部分,而不想读取全部,我们可以用 usecols 参数指定列:

cols = ['CustomerId','CreditScore','NumOfProducts']
df = pd.read_csv("Churn_Modelling.csv", usecols=cols)
df.head()

我们还可以使用 nrows 参数选择要读取多少行。这在处理非常大的文件时非常有用:

df.shape
(10000, 3)df = pd.read_csv("Churn_Modelling.csv", usecols=cols, nrows=500)
df.shape
(500, 3)

原始数据帧有 10000 行,通过将 nrows 设置为 500,我们只读取前 500 行。

read_csv 函数还有许多其他参数,这使它变得强大而方便。

创建数据帧

在现实生活中,我们通常从文件中读取数据,而不是创建数据帧。Pandas 提供了函数来通过从各种文件类型中读取数据来创建数据帧。在这篇文章中,我将使用字典来创建一个示例数据帧。

df = pd.DataFrame({'a':np.random.rand(10),
                 'b':np.random.randint(10, size=10),
                 'c':[True,True,True,False,False,np.nan,np.nan,
                      False,True,True],
                 'b':['London','Paris','New York','Istanbul',
                      'Liverpool','Berlin',np.nan,'Madrid',
                      'Rome',np.nan],
                 'd':[3,4,5,1,5,2,2,np.nan,np.nan,0],
                 'e':[1,4,5,3,3,3,3,8,8,4]})
df

2。数据概述

照片由马库斯·温克勒Unsplash 上拍摄

Pandas describe 函数为数值(int 或 float)列提供汇总统计。它计算值的数量,并显示平均值、标准差、最小值和最大值以及 25%、50%和 75%的分位数。

df.describe()

虽然所有的列都有相同的行数,但是 d 列的计数不同,因为 describe 函数不计算 NaN(缺失)值。

value_counts() 以出现次数显示列中的值:

df.c.value_counts()
True     5
False    3
Name: c, dtype: int64

value_counts()不计算 NaN(缺失)值。

我们还应该检查数据类型,并在我们的分析中考虑它们。有些功能只能在某些数据类型上执行。我们可以使用 dtypes 轻松检查数据类型:

df.dtypes
a    float64
b     object
c     object
d    float64
e      int64
dtype: object

“d”和“e”列都有整数,但“d”列的数据类型是 float。原因是列 d 中的 NaN 值。NaN 值被认为是浮点型的,因此该列中的整数值被向上转换为浮点数据类型。

Pandas 1.0.1 允许使用 NaN 作为整数数据类型。我们只需要显式地将 dtype 表示为 pd。Int64Dtype():

pd.Series([1, 2, 3, np.nan], dtype=pd.Int64Dtype())
0      1
1      2
2      3
3    NaN
dtype: Int64

如果 pd。不使用 Int64Dtype(),整数值被强制转换为浮点数:

pd.Series([1, 2, 3, np.nan])
0    1.0
1    2.0
2    3.0
3    NaN
dtype: float64

3。处理缺失值

照片由法鲁尔·阿兹米Unsplash 拍摄

处理缺失值是数据清理和准备过程中必不可少的一部分,因为现实生活中几乎所有的数据都带有一些缺失值。

让我们先创建一个缺少值的数据帧。

df = pd.DataFrame({
'column_a':[1, 2, 4, 4, np.nan, np.nan, 6],     
'column_b':[1.2, 1.4, np.nan, 6.2 ,None, 1.1, 4.3],
'column_c':['a', '?', 'c', 'd', '--', np.nan, 'd'],
'column_d':[True, True, np.nan, None, False, True, False]
})df

np.nan、None 和 NaT(对于 datetime64[ns]类型)是熊猫的标准缺失值。

注意:Pandas 1.0 中引入的一种新的缺失数据类型(< NA >),它是一种整数类型的缺失值表示。

np.nan 是一个浮点数,所以如果你在一列整数中使用它们,它们将被转换成浮点数据类型,正如你在我们创建的数据帧的“column_a”中看到的。但是,可以和整数一起使用,不会导致向上转换。让我们使用向 dataframe 再添加一列,可以通过显式请求 dtype Int64Dtype()来使用它。

new_column = pd.Series([1, 2, np.nan, 4, np.nan, 5], dtype=pd.Int64Dtype())df['column_e'] = new_column
df

熊猫提供了 isnull()isna() 函数来检测缺失值。他们俩做着同样的事情。

df.isna() 返回带有布尔值的 dataframe,该值表示缺少的值。

也可以选择使用与 isna()正好相反的 notna()

df.isna()。any() 为每一列返回一个布尔值。如果该列中至少有一个值缺失,则结果为真。

df.isna()。sum() 返回每列中缺失值的数量。

并非所有缺失的值都是简洁明了的 np.nan 或 None 格式。比如,“?”数据帧 c 列中的“---”字符没有给我们任何有价值的信息或见解,因此本质上它们是缺失值。但是,这些字符无法被熊猫检测为缺失值。

如果我们知道哪种字符用作数据集中的缺失值,我们可以在使用 na_values 参数创建数据帧时处理它们:

missing_values = ['?', '--']
df_test = pd.read_csv('filepath.csv', na_values = missing_values)

另一种选择是在创建数据帧后使用 pandas replace() 函数来处理这些值:

df.replace(['?','--'],np.nan, inplace=True)
df

我们已经用 NaN 值替换了非信息单元格。就地参数保存数据帧中的变化。inplace 的默认值为 False,因此如果将其设置为 True,将不会保存更改。

没有处理缺失值的最佳方法。根据数据集和任务的特征,我们可以选择:

  • 删除缺少的值
  • 替换丢失的值

丢弃缺失值

我们可以使用 dropna() 函数删除缺少值的行或列。如何使用参数将条件设置为下降。

  • how='any ':如果有任何缺少的值,则删除
  • how='all ':如果所有值都丢失,则删除

此外,使用 thresh 参数,我们可以为丢失的值设置一个阈值,以便删除一行/一列。

df.dropna(axis=0, how='all', inplace=True)
df

参数用于选择行(0)或列(1)。

我们的 dataframe 没有一行充满缺失值,因此设置 how='all '不会删除任何行。缺省值是' any ',所以如果我们想使用 how='any ',就不需要指定它:

注意: 原位参数用于保存对原始数据帧的更改。默认值为 false,因此如果我们不将其设置为 True,我们所做的更改将不会保存在原始数据帧中。

将 thresh 参数设置为至少缺少 3 个值的 3 个丢弃行。

数据是宝贵的资产,所以我们不应该轻易放弃它。此外,机器学习模型几乎总是倾向于在更多数据的情况下表现更好。因此,根据具体情况,我们可能更喜欢替换丢失的值,而不是丢弃。

替换缺失值

fillna() 熊猫函数方便处理缺失值。使用 fillna(),缺失值可以由特殊值或聚合值(如平均值、中值)替换。此外,缺失的值可以用它之前或之后的值替换,这对时间序列数据集非常有用。

  • 用标量替换丢失的值:

  • fillna()也可以用于特定的列:

  • 使用方法参数,缺失的值可以用它们之前或之后的值替换。

ffill 代表“向前填充”用前一行中的值替换缺失的值。您也可以选择 bfill 代表“反向填充”。

如果一列或一行中有许多连续的缺失值,您可能希望限制向前或向后填充的缺失值的数量。

极限参数设置为 1,因此只有一个缺失值被向前填充。

4。组合数据帧

Denys Nevozhai 在 Unsplash 拍摄的照片

数据科学项目通常需要我们从不同的来源收集数据。因此,作为数据准备的一部分,我们可能需要组合数据框架。在这一部分,我将讨论以下主题:

  • 串联
  • 合并

串联

让我们首先创建两个数据帧:

df1 = pd.DataFrame({
'column_a':[1,2,3,4],
'column_b':['a','b','c','d'],
'column_c':[True,True,False,True]
})df2 = pd.DataFrame({
'column_a':[1,2,9,10],
'column_b':['a','k','l','m'],
'column_c':[False,False,False,True]
})

组合或连接数据帧的一种方法是 concat() 函数。通过改变参数,它可用于沿行或列连接数据帧。axis 参数的默认值为 0,表示沿行组合。

正如您在上面的第一张图中所看到的,保留了各个数据帧的索引。为了改变它并重新索引组合数据帧, ignore_index 参数设置为真。

concat()函数的 join 参数决定了如何组合数据帧。默认值为“outer ”,返回两个数据帧中的所有索引。如果选择了' inner '选项,则只返回具有共享索引的行。我将改变 df2 的索引,以便您可以看到“内部”和“外部”的区别。

df = pd.concat([df1,df2], axis=1, join='inner')
df

df = pd.concat([df1,df2], axis=1, join='outer')
df

Pandas 还提供了标记数据帧的方法,以便我们知道哪个部分来自哪个数据帧。我们只是使用参数按顺序传递组合数据帧列表。

df = pd.concat([df1, df2], keys=['df1', 'df2'])
df

它还使得方便地访问数据帧的不同部分变得更加容易:

关于 concat()函数的一个重要注意事项是,它制作了数据的副本。为了防止进行不必要的复印,需要将复印参数设置为假。默认值为 True。

append() 函数也用于组合数据帧。它可以被看作是 concat()函数的一个特例(axis=0,join='outer '),所以我不会详细讨论它,而只是给出一个例子来展示语法。

df = df1.append(df2)
df

合并

组合数据帧的另一个广泛使用的函数是 merge() 。Concat()函数只是将数据帧一个接一个地相加或并排相加。它更像是附加数据帧。Merge()根据共享列中的值组合数据帧。与 concat()函数相比,Merge()函数提供了更多的灵活性。看到例子就清楚了。

参数上的选择用于合并的列或索引级别。

df_merge = pd.merge(df1, df2, on='column_a')
df_merge

列名不必相同。我们关注的是列中的值。假设两个数据帧在一个列中有共同的值,您希望使用该列来合并这些数据帧,但是列名不同。在这种情况下,可以使用 left_onright_on 参数代替 on 参数。为了显示差异,我将在 df2 中更改列名,然后使用 merge:

df2.rename(columns={'column_a':'new_column_a'}, inplace=True)
df2

df_merge = pd.merge(df1, df2, left_on='column_a', right_on='new_column_a')df_merge

尽管 column_a 和 new_column_a 中的返回值是相同的,但由于具有不同的名称,合并的数据帧包括这两个列。

您也可以将多个值传递给参数上的。返回的数据帧仅包括在所有传递给参数上的的列中具有相同值的行。

df2.rename(columns={'new_column_a':'column_a'}, inplace=True)df_merge = pd.merge(df1, df2, on=['column_a','column_b'])
df_merge

df1 和 df2 是根据 column_a 中的公共值合并的,是时候介绍一下howmerge()的参数了。顾名思义,表示你想怎么组合。how 的可能值为“内部”、“外部”、“左侧”、“右侧”。

  • inner:只有在参数指定的列中有相同值的行( how 参数的默认值)
  • 外部:所有行
  • 左侧:左侧数据帧中的所有行
  • 右侧:右侧数据帧中的所有行

“如何”的概念在下图中更加清晰。如果您熟悉 SQL,其逻辑与 SQL 连接相同。

下面的数字更清楚地代表了参数的概念。

outer ',' left '和' right '选项包括不在其中一个数据帧中的数据。缺少的部分自动用 NaN 值填充。NaN 是熊猫缺失价值观的典型代表。

how 的默认值是“inner ”,因此您不必在函数中显式编写。“Inner”只返回 column_a 中具有公共值的行。

当 how 参数选择' outer '时,合并的数据帧包括两个数据帧中 column_a 的所有值。但是,公共值(column_a = 1 和 column_a = 2)不会重复。

当 how 参数选择' left '时,合并数据帧包括左侧数据帧中所有行。如果 column_a(传递给 on 参数的列)中的值不在右数据帧中,则右数据帧中的列将填充 NaN 值。很少使用“right”选项,因为您只能在 merge 函数中更改数据帧的顺序(而不是(df1,df2)使用(df2,df1))。

您可能已经注意到,两个数据帧中相同的列名会添加一个后缀。区分哪一列来自哪一个数据帧是很有用的。您可以使用后缀参数指定要添加的后缀。

5。选择数据帧上的数据

照片由 Bodie PyndusUnsplash 上拍摄

ilocloc 允许选择数据帧的一部分。

  • iloc:按职位选择
  • loc:按标签选择

让我们来看一些例子,因为一如既往,熟能生巧。在本节的示例中,我将使用以下数据帧:

iloc

选择第二行:

df.iloc[1] 
a    0.571258
b       Paris
c        True
d           4
e           4
Name: 1, dtype: object

选择第一行,第二列(即第一行中的第二个值):

df.iloc[0,1] 
'London'

所有行,第三列(与选择第二列相同,但我只想展示':'的用法):

df.iloc[:,2]
0     True
1     True
2     True
3    False
4    False
5     True
7    False
8     True
9     True
Name: c, dtype: bool

前两行,第二列:

df.iloc[:2,1]
0    London
1     Paris
Name: b, dtype: object

loc

最多 2 行,列“b”:

df.loc[:2,'b']
0      London
1       Paris
2    New York
Name: b, dtype: object

最多 2 行和最多“b”列:

df.loc[:2, :'b']

第“2”行和第“b”列:

df.loc[2, :'b']
a     0.16649
b    New York
Name: 2, dtype: object

您可能想知道为什么我们在 loc 和 iloc 中对行使用相同的值。原因是数字指数。Loc 按位置选择,但行的位置与索引相同。

让我们创建一个带有非数字索引的新数据帧,这样我们就可以看到不同之处:

index = ['aa','bb','cc','dd','ee']
df2 = pd.DataFrame({'a':np.random.rand(5),
                 'b':np.random.randint(10, size=5)},
                   index = index)
df2

df2.loc['bb','b']
1df2.loc[:'cc','a']
aa    0.892290
bb    0.174937
cc    0.600939
Name: a, dtype: float64

6。重塑数据帧

有多种方法可以重塑数据帧。我们可以选择最适合手头任务的一个。重塑数据帧的函数:

  • 融化
  • 堆叠和拆分

熔化

Melt 用于将宽数据帧转换为窄数据帧。我所说的宽是指具有大量列的数据帧。一些数据帧的结构是连续的测量值或变量用列来表示。在某些情况下,将这些列表示为行可能更适合我们的任务。

考虑以下数据帧:

df1 = pd.DataFrame({'city':['A','B','C'],
                   'day1':[22,25,28],
                   'day2':[10,14,13],
                   'day3':[25,22,26],
                   'day4':[18,15,17],
                   'day5':[12,14,18]})

我们有三个不同的城市,在不同的日子进行测量。我们决定用一列中的行来表示这些日子。还会有一列显示测量结果。我们可以通过使用融化功能轻松实现这一点:

df1.melt(id_vars=['city'])

默认情况下,变量和值列的名称是给定的。我们可以使用 melt 函数的参数 var_namevalue_name 来指定新的列名。如果我们按城市列对数据进行排序,效果会更好:

df1.melt(id_vars=['city'], var_name = 'date', value_name = 'temperature').sort_values(by='city').reset_index(drop=True)

堆叠和取消堆叠

堆栈函数增加了数据帧的索引级别。我所说的提高水平是指:

  • 如果 dataframe 有一个简单的列索引,stack 返回一个系列,其索引由原始 dataframe 的行列对组成。
  • 如果数据帧有多级索引,stack 增加索引级别。

用例子解释更好。考虑以下数据帧:

df1 有 3 行 6 列,具有简单的整数列索引。如果将 stack 函数应用于 df1,它将返回 3 x 6 = 18 行的序列。序列的索引将是[(0,'城市'),(0,'第 1 天'),…,(2,'第 5 天')]。

让我们也检查一下形状和指数:

df1.shape
(3,6)
df1.stack().shape
(18,)
df1.stack().index[0] #multilevel index
(0, 'city')

栈和非栈功能更常用于具有多级索引的数据帧。让我们创建一个具有多级索引的数据框架:

tuples = [('A',1),('A',2),('A',3),('B',1),('A',2)]index = pd.MultiIndex.from_tuples(tuples, names=['first','second'])df2 = pd.DataFrame(np.random.randint(10, size=(5,2)), 
                   index=index, columns=['column_x', 'column_y'])

如果我们对该数据帧应用堆栈功能,索引级别将会增加:

df_stacked = df2.stack().to_frame()
df_stacked

现在,列名(column_x 和 column_y)是多级索引的一部分。因此得到的数据帧有一列和一个 3 级多索引。

len(df_stacked.index.levels)
3len(df2.index.levels)
2

拆堆堆堆正好相反。如果我们对堆叠的数据帧应用拆分,我们将得到原始的数据帧:

df_stacked.unstack().index
MultiIndex(levels=[['A', 'B'], [1, 2, 3]],
           codes=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]],
           names=['first', 'second'])df2.index
MultiIndex(levels=[['A', 'B'], [1, 2, 3]],
           codes=[[0, 0, 0, 1, 1], [0, 1, 2, 0, 1]],
           names=['first', 'second'])

7.熊猫的其他功能

本部分涵盖的功能:

  • 激增
  • 努尼克岛
  • 检查
  • 在哪里
  • 推断对象

安德烈·费塔多在 Unsplash 上拍摄的照片

激增

假设您的数据集在单个观测值(行)中包含一个要素的多个条目,但您希望在单独的行中对它们进行分析。

df = pd.DataFrame({'ID':['a','b','c'],
                  'measurement':[4,6,[2,3,8]],
                  'day':1})
df

我们希望在单独的行上看到第“1”天“c”的测量值,使用 explode 很容易做到这一点:

df.explode('measurement').reset_index(drop=True)

最好也重置索引:

我们也可以在两列上使用爆炸作为一个链:

df2 = pd.DataFrame({'ID':['a','b','c'],
                   'measurement_1':[4,6,[2,3,8]],
                   'measurement_2':[1,[7,9],1],
                   'day':1})
df2

df2.explode('measurement_1').reset_index(drop=True).explode('measurement_2').reset_index(drop=True)

确保在第一次分解后使用 reset_index,否则会得到如下意外结果:

df2.explode('measurement_1').explode('measurement_2').reset_index(drop=True)

努尼克岛

Nunique 计算列或行中唯一条目的数量。它在分类特征中非常有用,尤其是在我们事先不知道类别数量的情况下。

凯尔·格伦Unsplash 上拍摄

假设我们有以下数据帧:

要查找列中唯一值的数量:

df.name.nunique()
5

我们可以用稍微复杂一点的语法使用 value_counts 获得相同的结果:

df.name.value_counts().shape[0]
5

然而, nunique 允许我们同时对所有的列或行执行这个操作:

df.nunique()  #columns
ID              8 
name            5 
measurement1    7 
measurement2    5 
measurement3    6dtype: int64df.nunique(axis=1) #rows
0    3 
1    4 
2    4 
3    5 
4    5 
5    3 
6    4 
7    4 
dtype: int64

检查

它可用于根据其他行、列对上的值在数据帧中查找值。这个函数最好通过一个例子来解释。假设我们有以下数据帧:

对于每一天,我们有 4 个人的测量值和一个包含这 4 个人的名字的列。我们希望创建一个新列,在“选择”列中显示该人的测量值:

df['Person_point'] = df.lookup(df.index, df['Person'])
df

我们不必对所有数据点都进行这种操作。只要行标签和列标签具有相同的大小,我们就可以使用特定的范围:

df.lookup(df.index[:5], df['Person'][:5])
array([4, 7, 9, 8, 1])

在哪里

“Where”用于根据条件替换行或列中的值。您还可以指定要替换的值。默认值为 NaN。让我们复习一个例子,这样就清楚了。

df['Person_point'].where(df['Person_point'] > 5)0    NaN 
1    7.0 
2    9.0 
3    8.0 
4    NaN 
5    6.0 
6    NaN 
7    9.0 
Name: Person_point, dtype: float64

我们可以指定替换值:

df['Person_point'].where(df['Person_point'] > 5, 'Not_qualified', inplace=True)df

推断对象

Pandas 支持广泛的数据类型,其中之一是对象。对象包含文本或混合(数字和非数字)值。但是,如果有不同的选项可用,则不建议使用对象数据类型。使用更具体的数据类型可以更快地执行某些操作。例如,我们更喜欢用整数或浮点数据类型来表示数值。

infer_objects 尝试为对象列推断更好的数据类型。我们来看一个例子。

df = pd.DataFrame({'A': ['a', 1, 2, 3],
                   'B':['b',2.1,1.5,2],
                   'C':['c',True,False,False],
                   'D':['a','b','c','d']})
df

df = df[1:]df.dtypes
A    object 
B    object 
C    object 
D    object 
dtype: object

df.infer_objects().dtypesdf.dtypes
A      int64 
B    float64 
C       bool 
D     object 
dtype: object

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

使用 Python 的 Scikit-Learn 库的完整推荐系统算法:分步指南

原文:https://towardsdatascience.com/a-complete-recommendation-system-algorithm-using-pythons-scikit-learn-library-step-by-step-guide-9d563c4db6b2?source=collection_archive---------34-----------------------

罗伯特·祖尼科夫在 Unsplash 上拍摄的照片

一个简单而有用的算法,只有几行代码

推荐系统的开发可以是自然语言处理(NLP)中的常见任务。YouTube 或网飞使用类似的技术向他们的客户推荐。他们分析客户以前的行为,并在此基础上为他们推荐类似的材料。在本文中,我将讨论如何使用 python 中的 scikit-learn 库开发一个电影推荐模型。它涉及许多复杂的数学。但是 scikit-learn 库有一些很棒的内置函数,可以处理大部分繁重的工作。随着练习的进行,我将解释如何使用这些函数及其工作。

数据集概述

在这个练习中,我将使用一个电影数据集。我在这一页的底部给出了数据集的链接。请随意下载数据集,并在笔记本上运行所有代码,以便更好地理解。以下是数据集的链接:

[## rashida 048/Some-NLP-项目

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/rashida048/Some-NLP-Projects/blob/master/movie_dataset.csv)

以下是电影推荐模型的逐步实现:

  1. 导入包和数据集。
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similaritydf = pd.read_csv("movie_dataset.csv")

2.数据集太大。因此,我不能在这里显示截图。以下是数据集的列。它们不言自明。列名会告诉你里面的内容是什么。

df.columns#Output:
Index(['index', 'budget', 'genres', 'homepage', 'id', 'keywords',        'original_language', 'original_title', 'overview', 'popularity',        'production_companies', 'production_countries', 'release_date',        'revenue', 'runtime', 'spoken_languages', 'status', 'tagline', 'title',        'vote_average', 'vote_count', 'cast', 'crew', 'director'],       dtype='object')

3.选择要用于模型的特征。我们不需要使用所有的功能。有些不适合这个模型。我选择这四个特征:

features = ['keywords','cast','genres','director']

请随意为实验添加更多功能或不同的功能。现在,将这些特征组合起来,用这四列组成一列。

**def** combine_features(row):
    **return** row['keywords']+" "+row['cast']+" "+row['genres']+" "+row['director']

4.如果我们有空值,这可能会在算法中产生问题。用空字符串填充空值。

for feature in features:
    df[feature] = df[feature].fillna('')
df["combined_features"] = df.apply(combine_features,axis=1)

5.将数据拟合并转换到“计数矢量器”函数中,为矢量表示准备数据。当您通过“计数矢量器”函数传递文本数据时,它会返回每个单词的计数矩阵。

cv = CountVectorizer() 
count_matrix = cv.fit_transform(df["combined_features"])

6.使用“余弦相似度”来查找相似度。这是一种寻找相似性的动态方法,该方法测量多维空间中两个向量之间的余弦角。这样,文档的大小就无关紧要了。这些文档可能相距很远,但它们的余弦角可能相似。

cosine_sim = cosine_similarity(count_matrix)

这个“余弦 _sim”是一个二维矩阵,它是一个系数矩阵。我不打算在这里详细解释余弦相似性,因为这超出了本文的范围。我想展示,如何使用它。

7.我们需要定义两个函数。其中一个函数从索引中返回标题,另一个函数从标题中返回索引。我们将很快使用这两个功能。

def find_title_from_index(index):
    return df[df.index == index]["title"].values[0]
def find_index_from_title(title):
    return df[df.title == title]["index"].values[0]

8.拍一部我们用户喜欢的电影。就拿《星球大战》来说吧。然后用上面的函数找到这部电影的索引。

movie = "Star Wars"
movie_index = find_index_from_title(movie)

《星球大战》的指数是 2912。正如我前面提到的,步骤 6 中的“余弦 _sim”是相似性系数的矩阵。该矩阵的行 2912 应该提供所有具有“星球大战”的电影的相似性系数。所以,找到矩阵‘余弦 _ sim’的第 2912 行。

similar_movies = list(enumerate(cosine_sim[movie_index]))

我使用枚举来获取索引和系数。‘similar _ movies’是包含索引和系数的元组列表。我喜欢在 python 中使用“枚举”。很多时候它会派上用场。

9.按照系数的逆序对列表“相似电影”进行排序。这样,最高的系数将在顶部。

sorted_similar_movies = sorted(similar_movies,key=lambda x:x[1],reverse=True)[1:]

我们没有从列表中选择第一部,因为列表中的第一部将是《星球大战》本身。

10.使用函数“find_title_from_index”获得与“星球大战”相似的前五部电影。

i=0
for element in sorted_similar_movies:
    print(find_title_from_index(element[0]))
    i=i+1
    if i>5:
        break

与《星球大战》最相似的五部电影是:

帝国反击战

绝地归来

星球大战:第二集——克隆人的进攻

星球大战:第三集——西斯的复仇

星球大战:第一集——幽灵的威胁

螺旋…加载

有道理,对吧?这就是电影推荐模型。如果你有任何问题,请随时问我。这是我在本教程中使用的数据集。

结论

这个推荐系统非常简单,但是很有用。这种类型的推荐系统在许多现实场景中都很有用。希望你能善用它。

更多阅读:

[## Python 中从头开始的完整异常检测算法:分步指南

基于概率的异常检测算法

towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## Python 中从头开始的完整 K 均值聚类算法:分步指南

还有,如何使用 K 均值聚类算法对图像进行降维

towardsdatascience.com](/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461) [## 编程、软件工程和数据科学的最佳免费课程

麻省理工、哈佛和斯坦福等顶尖大学的免费课程

towardsdatascience.com](/best-free-courses-for-computer-science-software-engineering-and-data-science-50cd88cafd74) [## 如何在 Python 中呈现多个变量之间的关系

了解如何使用 Python 中的多元图表和绘图来呈现要素之间的关系

towardsdatascience.com](/how-to-present-the-relationships-amongst-multiple-variables-in-python-70f1b5693f5) [## 逻辑回归模型拟合和寻找相关性,P 值,Z 值,置信度…

静态模型拟合和提取的结果从拟合模型使用 Python 的 Statsmodels 库与…

towardsdatascience.com](/logistic-regression-model-fitting-and-finding-the-correlation-p-value-z-score-confidence-8330fb86db19)

一个完整的推荐系统从零开始:一步一步

原文:https://towardsdatascience.com/a-complete-recommender-system-from-scratch-in-python-step-by-step-6fc17a4da054?source=collection_archive---------23-----------------------

卡米洛·希门尼斯在 Unsplash 上拍摄的照片

入门

基于用户评分的线性回归电影推荐系统

如今,我们到处都能看到推荐系统。当你在亚马逊、易贝或任何其他地方的在线市场买东西时,他们会推荐类似的产品。在网飞或 youtube 上,你会在你的主页上看到与你之前的活动或搜索相似的建议。他们是如何做到的?他们都遵循这个想法。也就是说,他们从您以前的活动中获取数据,并进行相似性分析。基于这种分析,他们会推荐更多你可能喜欢的产品、视频或电影。

概观

在本文中,我将解释一个使用相同思想的推荐系统。以下是将在此涉及的主题列表:

  1. 推荐系统的思想和公式。
  2. 从头开始开发推荐系统算法
  3. 用那个算法给我推荐电影。

我将使用 Python 的一些库,如 Numpy、Pandas 和 Matplotlib,以提高计算效率和速度。尽管我们的数据集并不太大。但是我们想开发一些适用于更大数据集的东西。我用的是 Jupyter 笔记本环境。随意使用你选择的任何其他笔记本。

这个推荐系统是如何工作的?

在这一节中,我将提供该过程的高级概述。如果你不能完全理解,请继续看下面的章节。因为在接下来的部分中,我将用 python 代码实现所有这些想法。这样,就更清楚了。

让我们开始吧。假设我们的数据集看起来像这样:

这里,我们有五部电影、四个用户和两个特性。每个用户都为每部电影提供了一些反馈或评级。当然,每个用户并没有看完所有的电影。因此,有时评级是不可用的。

最后我们有两个特点:浪漫和动作。他们让你知道这部电影有多浪漫或者有多刺激。此评级介于 0 和 1 之间。0 浪漫意味着没有浪漫,1 浪漫意味着充满浪漫。

这个算法将被开发成使用用户评分的推荐系统。

如果一个用户看了很多电影,并对它们进行了评级,这个算法将最适合这个用户。

但是,如果某个用户没有提供任何评级,他或她将获得基于其他用户评级的推荐。

丢失的电影评分怎么办?

这是一个合理的问题。不是所有的用户都观看所有的电影,有时他们只是在观看后不对电影进行评级。所以,有很多缺失数据是正常的。在这种情况下,我们需要找到一种方法来填补那些缺失的数据。

线性回归法可以用来填补那些缺失的数据。提醒一下,下面是线性回归的公式:

Y = C + BX

我们在高中都学过这个直线方程。这里,Y 是因变量,B 是斜率,C 是截距。传统上,对于线性回归,相同的公式被写成:

这里,“h”是假设或预测值,X 是输入特征,θ0 和θ1 是系数。

如果您以前没有研究过线性回归,请先阅读这篇关于线性回归的文章:

[## Python 中的线性回归算法:一步一步

学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法

towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8)

在这个推荐系统中,我们将使用同一部电影的其他评级作为输入 X,并预测缺失值。我们将避免偏差项θ0。

这里,θ1 在开始时随机初始化,并像线性回归算法一样通过迭代来细化。

如何细化 Theta1 的值?

与线性回归一样,我们将使用已知值来训练算法。以一部电影的已知收视率为例。然后使用上面的公式预测那些已知的评级。预测评级值后,将其与原始评级进行比较,以找出误差项。这是一个等级的误差。

同样,我们需要找出所有评级的误差。在此之前,我想介绍一下我将在整个教程中使用的符号,

这是总成本函数的公式,它将指示预测评级和原始评级之间的距离。

该公式的第一项表示误差项的平方。我们用正方形来避免任何负值。使用 1/2 来优化平方,我们计算误差项,其中 r(i,j) = 1。因为 r(i,j) =1 意味着用户提供了评级。

上述等式的第二项是正则化项。调整任何过拟合或欠拟合问题是有用的。

总成本函数?

如何知道一部电影是爱情片、喜剧片还是动作片?一直这样看完所有的电影,找出它的特点,真的会很费时间,很费钱。

所以,我们可以从用户的评分中得到启发。我们随机初始化θ值并通过迭代慢慢优化它的方式,我们可以对查找特征 x 做同样的事情。公式应该几乎类似于上面的成本函数。

在这两种情况下,都会有相同的误差项。我们可以添加θ和 x 的成本函数,如下所示:

梯度下降

梯度下降在每次迭代中更新θ和 X。以下是梯度下降的公式:

在这个公式中,α是学习率。在每次迭代中,θ和 X 值将被更新,并最终变得稳定。

电影推荐算法的实现

我将使用 Coursera 中的 Andrew Ngs 机器学习课程的数据集。他是把一个机器学习问题分解成碎片的最佳人选。请随意从该链接下载数据集并跟随:

[## rashida 048/推荐系统

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/rashida048/Recommender-System)

唯一的办法就是按照这个代码,边读边跑,如果你读这个是为了学习的话。

第一步:

导入必要的包和数据集。

import numpy as np
import pandas as pd

第一个数据集包含所有用户对所有电影的评级。

y = pd.read_excel('ex8_movies.xlsx', sheet_name = 'y', header=None)
y.head()

如果用户提供了评级,则下一个数据集包含 true,如果用户没有提供评级,则包含 False。

r = pd.read_excel('ex8_movies.xlsx', sheet_name='R', header=None)
r.head()

我们需要将这些布尔值转换成数值。我将用 1 代替 True,用 0 代替 False。

for i in range(len(r.columns)):
    r[i] = r[i].replace({True: 1, False: 0})

该数据集中有特征 X:

X = pd.read_excel('movie_params.xlsx', sheet_name='X', header=None)
X.head()

θ值存储在这里,

theta = pd.read_excel('movie_params.xlsx', sheet_name='theta', header=None)
theta.head()

让我们检查数据集的形状。

输入:

y.shape

输出:

(1682, 943)

这意味着我们有 1682 部电影和 943 个用户。

输入:

X.shape

输出:

(1682, 10)

正如你所记得的,X 包含了特性。该数据集中有 10 个要素。

输入:

theta.shape

输出:

(943, 10)

输入:

r.shape

输出:

(1682, 943)

这是这个算法需要的所有数据集。x 和θ可以随机初始化。我们将在最后看到它。现在,我们将使用这个 X 和θ。

现在,我们将开发所有必要的功能。

成本函数

非常简单,我们将使用上面描述的总成本函数。它将 X,y,r,theta 和 Lambda 作为输入,并返回成本和梯度。

def costfunction(X, y, r, theta, Lambda):
    predictions = np.dot(X, theta.T)
    err = predictions-y
    J = 1/2 * np.sum((err**2) * r)
    reg_x = Lambda/2 * np.sum(np.sum(theta**2))
    reg_theta = Lambda/2 * np.sum(np.sum(X**2))
    grad = J + reg_x + reg_theta
    return J, grad

梯度下降

在这个函数中,我们将使用上面讨论的梯度下降公式。它将 X,y,r,theta,Lambda,alpha 和迭代次数作为参数。我们将使用成本函数记录每次迭代的成本,并将返回更新后的 X、theta 和成本列表。

def gradientDescent(X, y, r, theta, Lambda, num_iter, alpha):
    J_hist = []
    for i in range(num_iter):
        cost, grad = costfunction(X, y, r, theta, Lambda)
        X = X -  alpha*(np.dot(np.dot(X, theta.T) - y, theta) + Lambda*X)
        theta = theta - alpha*(np.dot((np.dot(X, theta.T) - y).T, X) + Lambda*theta) 
        J_hist.append(cost)
    return X, theta, J_hist

正常化

在此函数中,我们将对评级“y”进行标准化。首先,我们将计算每部电影的平均收视率。为此,我们将对每部电影的评分进行求和,然后除以该电影的“r”的总和。请记住,如果用户提供评级,则“r”数据集包含 1,如果用户未提供评级,则包含 0。

标准化 y 将是 y(如果用户提供了评级)减去平均值“y”的总和。

def normalizeRatings(y, r):
    ymean = np.sum(y, axis=1)/np.sum(r, axis=1)
    ynorm = np.sum(y, axis=1)*np.sum(r, axis=1) - ymean
    return ymean, ynorm

所有的功能都是为了执行建议而开发的。现在,让我们使用这些函数。

给我推荐电影

为了给我推荐电影,我需要提供一些动作的评分。

my_ratings = np.zeros((1682,1))my_ratings[5] = 5 
my_ratings[50] = 1
my_ratings[9] = 5
my_ratings[27]= 4
my_ratings[58] = 3
my_ratings[88]= 2
my_ratings[123]= 4
my_ratings[165] = 1
my_ratings[187]= 3
my_ratings[196] = 2
my_ratings[228]= 4
my_ratings[258] = 5 
my_ratings[343] = 4
my_ratings[478] = 1
my_ratings[511]= 4
my_ratings[690] = 5
my_ratings[722]= 1
my_ratings[789]= 3
my_ratings[832] = 2
my_ratings[1029]= 4
my_ratings[1190] = 2
my_ratings[1245]= 5

我现在将在“y”数据框中添加我的评分。

y1 = np.hstack((my_ratings, y))

还需要添加“r”数据帧。这有点不同。因为“r”数据帧只显示我是否提供了电影的分级。然后,我将在索引中我的评级列表为 0 的地方放置 0,在我的评级列表有值的地方放置 1。

my_r = np.zeros((1682,1))
for i in range(len(r)):
    if my_ratings[i] !=0:
        my_r[i] = 1

现在,将这个 my_r 列表添加到“r”数据帧中,并将其命名为 r1。

r1 = np.hstack((my_r, r))

我们需要使用新的 y1 和 r1 找到一个归一化的 y 值。

ymean, ynorm = normalizeRatings(y1, r1)

你还记得吗,我在开始的时候说过,我们将在最后使用随机初始化的 X 和θ。

是时候了。我们试试用随机初始化的 theta 和 x 给我推荐电影吧。

num_users = y1.shape[1]
num_movies = y1.shape[0]
num_features = 10X1= np.random.randn(num_movies, num_features)
Theta1 = np.random.randn(num_users, num_features)
Lambda=10x_up, theta_up, J_hist = gradientDescent(X1, y1, r1, Theta1, 10, 500,0.001)

因此,我们得到了每次迭代的成本数据。我们来画一下。

import matplotlib.pyplot as plt
plt.figure()
plt.plot(J_hist)
plt.xlabel("Iteration")
plt.ylabel("$J(\Theta)$")
plt.title("Cost function using Gradient Descent")

看啊!经过几次迭代,代价函数变得稳定了!这意味着 X 和θ值在该点是稳定的。

推荐电影

使用我在开头提到的简单线性回归公式,我们来预测一下收视率。注意,我没有给所有的电影打分。因此,这里使用更新的参数,我们将预测所有用户的所有电影的评级。

p = np.dot(x_up, theta_up.T)

现在,当我使用 np.hstack 添加时,我的评分在第一列中。只分离我的评分,并使用上面的“normalizeRatings”函数中的“ymean”将其标准化。

my_predictions = p[:, 0] + ymean
my_predictions = pd.DataFrame(my_predictions)

现在,我将把这些评分添加到电影列表中。首先导入电影列表。

movies = open('movie_ids.txt', 'r').read().split("\n")[:-1]df = pd.DataFrame(np.hstack((my_predictions,np.array(movies)[:,np.newaxis])))

我们现在在一个数据框中并排显示电影列表和我的评分。如果我们只是对这个数据框架“我的评分”进行排序,我会找到最值得推荐的电影。根据我的评分,这里是我推荐的 10 部电影:

df.sort_values(by=[0],ascending=False,inplace=True)
df.head(10)

这些是根据我提供的评分推荐给我的电影。

结论

该算法使用用户的评级来工作。基于以前的购买记录、搜索记录或观看记录,可以开发一个类似的推荐系统。希望这对你有帮助。如果有任何问题,请不要犹豫在评论区提问。

欢迎在推特上关注我,并喜欢我的脸书页面。

您可以在这里找到本文的完整代码:

[## rashida 048/推荐系统

github.com](https://github.com/rashida048/Recommender-System/blob/main/movie_recommendation1.ipynb)

更多阅读:

[## 使用 Python 的 Scikit-Learn 库的完整推荐系统算法:分步指南

一个简单、容易、有用的算法,只有几行代码

towardsdatascience.com](/a-complete-recommendation-system-algorithm-using-pythons-scikit-learn-library-step-by-step-guide-9d563c4db6b2) [## Python 中从头开始的完整异常检测算法:分步指南

基于概率的异常检测算法

towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## Python 中从头开始的多项式回归

学习用一些简单的 python 代码从头开始实现多项式回归

towardsdatascience.com](/polynomial-regression-from-scratch-in-python-1f34a3a5f373) [## Python 中从头开始的完整逻辑回归算法:一步一步

使用真实世界的数据集开发算法

towardsdatascience.com](/a-complete-logistic-regression-algorithm-from-scratch-in-python-step-by-step-ce33eae7d703) [## 用 Python 从头开始构建神经网络

神经网络的详细说明和逐步实现

medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## Python 中用于检测心脏病的逻辑回归

发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法

towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## Python 中从头开始的完整 K 均值聚类算法:分步指南

还有,如何使用 K 均值聚类算法对图像进行降维

towardsdatascience.com](/a-complete-k-mean-clustering-algorithm-from-scratch-in-python-step-by-step-guide-1eb05cdcd461)

一个完整的带有亚马逊产品评论数据的 Python 情感分析算法:一步一步

原文:https://towardsdatascience.com/a-complete-sentiment-analysis-algorithm-in-python-with-amazon-product-review-data-step-by-step-2680d2e2c23b?source=collection_archive---------7-----------------------

Samuele Giglio 在 Unsplash 上拍摄的照片

使用 Python 的 Scikit_learn 库的 NLP 项目

在当今世界,情绪分析在任何行业都可以发挥至关重要的作用。使用自动化系统对推文、脸书评论或产品评论进行分类可以节省大量时间和金钱。同时出错的概率更低。在本文中,我将解释一个使用亚马逊产品评论数据集的情感分析任务。

我将使用 python 和一些 python 库。即使你以前没用过这些库,你也应该能很好地理解它。如果这对您来说是新的,请将每一步代码复制到您的笔记本上,并查看输出以便更好地理解。

使用的工具

  1. 计算机编程语言
  2. 熊猫图书馆
  3. sci kit-学习库
  4. 作为 IDE 的 Jupyter 笔记本。

数据集和任务概述

我将使用我前面提到的产品评论数据集。该数据集包含亚马逊婴儿产品评论。

如果你想用它练习,请从这个 链接 为自己下载数据集。

它有三列:名称、评论和评级。评论是文本数据,评级从 1 到 5,其中 1 是最差的评论,5 是最好的评论。

我们的工作是分析正面和负面的评论。让我们来看看数据集。这里我们使用前五个条目来检查数据。

import pandas as pd
products = pd.read_csv('amazon_baby.csv')
products.head()

作者图片

数据预处理

在现实生活中,数据科学家很少能获得非常干净并且已经为机器学习模型做好准备的数据。几乎每个项目,你都要花时间清理和处理数据。所以,让我们先清理数据集。

一个重要的数据清理过程是去除空值。让我们检查一下数据集中有多少空值。

在这个数据集中,我们必须处理这三列,这三列都很重要。如果数据在一列的任何一行中都不可用,则该行是不必要的。

len(products) - len(products.dropna())

我们在 1147 行中有空值。现在,检查一下我们总共有多少数据。

len(products)

我们总共有 183531 个数据。因此,如果我们删除所有的空值,我们仍然会有相当大的数据来训练算法。因此,让我们放弃空值。

products = products.dropna()

我们需要在 review 列中包含所有的字符串数据。如果有任何数据具有其他类型,将在后面的步骤中造成麻烦。

现在,我们将检查每一行的评审数据的数据类型。如果有任何一行的数据不是 string 类型的,我们将把它改为 string。

for i in range(0,len(products)-1):
    if type(products.iloc[i]['review']) != str:
        products.iloc[i]['review'] = str(products.iloc[i]['review'])

当我们进行情绪分析时,告诉我们的模型什么是积极情绪,什么是消极情绪是很重要的。

在我们的评级栏中,我们有从 1 到 5 的评级。我们可以定义 1 和 2 为差评,4 和 5 为好评。

3 呢?

3 在中间。不好也不坏。只是一般。但是我们要对好评和差评进行分类。所以,我决定去掉所有的 3。

这取决于雇主或你对好坏的看法。如果你认为你会把 3 放在好的评论位置,那就去做吧。但是我正在摆脱他们。

products = products[products['rating'] != 3]

我们将正面情绪记为 1,负面情绪记为 0。让我们写一个函数“情绪”,如果评分为 4 或更高,则返回 1,否则返回 0。然后,应用函数“情绪”并创建一个新列,将积极和消极情绪表示为 1 或 0。

def sentiment(n):
    return 1 if n >= 4 else 0
products['sentiment'] = products['rating'].apply(sentiment)
products.head()

作者图片

看,我们现在在末尾增加了“情感”一栏!

首先,我们需要准备培训功能。将“姓名”和“评论”列合并为一列。首先,编写一个函数“combined_features”来合并这两列。然后,应用该函数并创建一个新列“all_features ”,它将包含来自 name 和 review 列的字符串。

def combined_features(row):
    return row['name'] + ' '+ row['review']products['all_features'] = products.apply(combined_features, axis=1)
products.head()

作者图片

您可以在结尾处看到“所有功能”一栏。现在,我们准备开发情感分类器!

开发情感分类器

下面是一步一步的过程。

我们需要定义输入变量 X 和输出变量 y。

x 应该是“所有功能”列,y 应该是我们的“情感”列

X = products['all_features']
y = products['sentiment']

我们需要拆分数据集,以便有一个训练集和一个测试集。

scikit-learn 库中的“train_test_split”函数很有帮助。将使用训练数据集来训练该模型,并且可以使用测试数据集来测试该模型的性能。

“train_test_split”自动按 75/25 的比例分割数据。75%用于培训,25%用于测试。如果你想比例不同,你需要定义。

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

我将使用 scikit-learn 库中的'计数矢量器。CountVectorizer 生成字符串中所有单词的向量。导入 CountVectorizer,并将我们的训练和测试数据放入其中。

from sklearn.feature_extraction.text import CountVectorizercv = CountVectorizer()
ctmTr = cv.fit_transform(X_train)
X_test_dtm = cv.transform(X_test)

让我们深入到最初的模型部分。这是最好玩的部分。我们将使用逻辑回归,因为这是一个二元分类。让我们进行必要的导入,并将我们的训练数据放入模型中。

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
model = LogisticRegression()
model.fit(ctmTr, y_train)

用训练数据训练逻辑回归模型。

结果

使用上面训练好的模型来预测测试数据的情绪。如果我们通过测试特征,它将预测输出 y,即情感数据。

y_pred_class = model.predict(X_test_dtm)

输出:

array([1, 1, 1, ..., 1, 1, 0], dtype=int64)

这是测试数据的输出。如你所知,我们用 1 表示好评,用 0 表示差评。

使用 accuracy_score 函数获得测试数据的 accuracy_score。因此,它会将预测的“情绪”与原始的“情绪”数据进行比较,以计算准确性的百分比。

accuracy_score(y_test, y_pred_class)

这个数据我在测试集上得到的准确率分数是 84%,非常好。

结论

这个简单的情感分析分类器在许多其他类型的数据集中也很有用。它也可以用于现实世界的项目和业务。我们在这里使用的数据集类似于真实的业务数据集。请在其他数据集上尝试这种技术。

欢迎在推特上关注我,并喜欢我的脸书页面。

更多阅读:

[## 学习机器学习和深度学习的优质免费课程

顶级大学高质量免费课程的链接

towardsdatascience.com](/great-quality-free-courses-to-learn-machine-learning-and-deep-learning-1029048fd0fc) [## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## 完全理解精确度、召回率和 F 分数的概念

机器学习中如何处理倾斜数据集

towardsdatascience.com](/a-complete-understanding-of-precision-recall-and-f-score-concepts-23dc44defef6) [## 练习数据科学技能和制作优秀投资组合所需的所有数据集

一些有趣的数据集提升你的技能和投资组合

towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5) [## Python Matplotlib 的日常备忘单

完整的可视化课程

towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## 想在 12 周内成为数据科学家?

花钱前再想一想

towardsdatascience.com](/want-to-become-a-data-scientist-in-12-weeks-3926d8eacee2)

完全理解精确度、召回率和 F 分数的概念

原文:https://towardsdatascience.com/a-complete-understanding-of-precision-recall-and-f-score-concepts-23dc44defef6?source=collection_archive---------13-----------------------

李中清Unsplash 上拍照

机器学习中如何处理倾斜数据集

用倾斜的数据集开发有效的机器学习算法可能会很棘手。例如,数据集是关于银行欺诈活动或癌症检测的。你会在数据集中看到,99%的情况下没有欺诈活动,或者没有癌症。你可以很容易地作弊,只要一直预测 0(如果有癌症预测 1,如果没有癌症预测 0)就可以获得 99%的准确率。如果我们这样做,我们将有 99%准确的机器学习算法,但我们永远不会检测到癌症。如果某人患有癌症,她/他将永远得不到治疗。在银行里,不会有针对欺诈行为的行动。因此,对于这样一个有偏差的数据集来说,光靠准确性是无法决定算法是否有效的。

背景

有不同的评估矩阵可以帮助处理这些类型的数据集。这些评估指标被称为精确召回评估指标。

要了解精度和召回率,您需要理解下表及其所有术语。考虑二进制分类。它将返回 0 或 1。对于给定的训练数据,如果实际类为 1,预测类也为 1,则称为真正。如果实际类别为 0,而预测类别为 1,则这是一个假阳性。如果实际类别为 1,但预测类别为 0,则称为假阴性。如果实际类别和预测类别都是 0,则这是真否定

利用这些,我们将计算精度和召回率。

精确

Precision 计算我们预测为欺诈的交易(预测类别 1)中有多少部分实际上是欺诈的。精度可以用下面的公式计算:

进一步分解,这个公式可以写成:

从公式中可以看出,精度越高越好。因为更高的精度意味着更多的真阳性。这意味着当我们说这笔交易是欺诈性的,这是真的。

回忆

回忆告诉我们,所有最初是欺诈性的交易中有多少部分被检测为欺诈性的。这意味着当一笔交易实际上是欺诈性的,如果我们告诉适当的银行当局采取行动。当我第一次读到精确和回忆的定义时,我花了一些时间才真正理解它们的区别。我希望你越来越快。如果没有,那也不用担心。你并不孤单。

召回率可通过以下公式计算:

用上面 2 x 2 表中定义的术语表示:

根据精确度和召回率做出决策

精确度和召回率让我们更好地了解算法实际上是如何工作的,尤其是当我们有一个高度倾斜的数据集时。如果我们一直预测 0,并且得到 99.5%的准确率,那么召回率和准确率都是 0。因为没有真正的阳性。所以,你知道分类器不是一个好的分类器。当精确度和召回率都很高时,这表明该算法做得非常好。

假设我们只在高度自信的情况下,想预测 y = 1。因为有些情况下它非常重要。尤其是当我们处理医疗数据时。假设我们正在检测某人是否患有心脏病或癌症。预测假阳性会给一个人的生活带来很多痛苦。提醒一下,一般来说,如果假设大于或等于 0.5,逻辑回归预测 1,如果假设小于 0.5,逻辑回归预测 0。

如果假设≥ 0.5,则预测 1

如果假设< 0.5,则预测为 0

但是,当我们处理上述一些敏感情况时,我们希望对我们的结果更加确定,如果假设≥ 0.7,我们预测 1,如果假设< 0.7,我们预测 0。如果你想对你的结果更有信心,你可以看到像 0.9 这样的值。所以你可以 90%确定某人是否患有癌症。

现在,看看精度和召回公式。真阳性和假阳性都会降低。所以,精度会更高。但另一方面,假阴性会更高,因为我们现在会预测更多的阴性。那样的话,召回会更高。但是太多的假阴性也不好。如果某人确实患有癌症,或者某个账户有欺诈活动,但我们告诉他们,他们没有癌症,或者该账户没有欺诈活动,这可能会导致灾难。

为了避免假阴性并获得更高的召回率,我们需要将阈值更改为如下所示:

如果假设≥ 0.3,预测 1

如果假设< 0.3,则预测为 0

与前一种情况相反,我们将有更高的召回率和更低的准确率。

那么门槛怎么定呢?这将取决于你的要求是什么。根据您的数据集,您必须决定是需要更高的精度还是更高的召回率。这是精确回忆曲线:

精确召回曲线可以是任何形状。所以,我在这里展示了三种不同的形状。如果您不能自己决定是否需要更高的精确度或更高的召回率,您可以使用 F1 分数。

F1 分数

F1 得分是准确率和召回率的平均值。但是平均的公式是不同的。常规的平均公式在这里不起作用。看平均公式:

(精度+召回)/ 2

即使精度是 0 或者召回率是 0,平均值仍然是 0.5。记住我们之前的讨论,精度为零是什么意思。我们总是可以预测 y = 1。因此,这是不可接受的。因为精确回忆的目的就是避免这种情况。F1 方程式的分数是:

这里,P 是精度,R 是召回率。如果精度为零或召回为零,F1 分数将为零。所以,你会知道分类器没有像我们想要的那样工作。当精确度和召回率都达到完美时,这意味着精确度是 1,召回率也是 1,F1 的分数也将是 1。所以,完美的 F1 分数是 1。尝试不同的阈值并计算精确度、召回率和 F1 分数,以找出您的机器学习算法的最佳阈值,这是一个好主意。

结论

在本文中,您了解了如何处理有偏差的数据集。如何使用 F1 分数在精确度和召回率之间做出选择?我希望它有帮助。

更多阅读

[## 使用 Python 从零开始的多类分类算法:分步指南

本文介绍两种方法:梯度下降法和优化函数法

towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## 用 Python 从头开始构建神经网络

神经网络的详细说明和逐步实现

medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## Python 中用于检测心脏病的逻辑回归

发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法

towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 用几行代码在 Python 中搜索相似的文本:一个 NLP 项目

使用 Python 中的计数矢量器和最近邻法查找类似的维基百科简介,这是一个简单而有用的…

medium.com](https://medium.com/towards-artificial-intelligence/similar-texts-search-in-python-with-a-few-lines-of-code-an-nlp-project-9ace2861d261) [## 练习数据科学技能和制作优秀投资组合所需的所有数据集

一些有趣的数据集提升你的技能和投资组合

towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5)

解决文本分类问题的初学者综合指南

原文:https://towardsdatascience.com/a-comprehensive-beginners-guide-to-tackle-text-classification-problems-e39a8ce22cff?source=collection_archive---------31-----------------------

利用文本分类方法分析 Twitter 数据中的错误信息

作者 尼基尔·乔希 纳拉辛哈·卡马特·阿迪—2020 年 6 月 26 日

简介

众所周知,对数据科学家的需求一直在稳步上升。我们辞去了一份高薪的咨询工作,去追求数据科学领域的职业生涯。当我们作为学生开始我们的旅程时,我们真的不知所措,不知道如何开始学习过程。作为一个不断发展的领域,互联网上有很多内容/平台。当已经有这么多可能的事情时,一个人自然会发现很难找到一个完美的开始,我们在第一季度的前两个月面临同样的问题。

当我们在网上寻找内容时,他们大多专注于机器学习算法,NLP 概念,一开始看起来超级令人兴奋。此外,当我们开始了解 Python 及其内置库的重要性时,我们对自己的职业选择非常着迷。然而,作为一个初学者,我们面临着如此多的困惑,我们将在这个博客中讨论。这篇文章是有意针对新手候选人的,我们将尝试详细说明应该注意的每一点,以便在这一流程中建立一个坚实的基础。

数据科学不是闹着玩的!

这是一个极具挑战性的领域,需要纯粹的统计学知识来理解基本概念。ML 看起来很吸引人,Python 也做对了你的大部分工作,那为什么还要学统计学呢?这是我们关于数据科学的第一个流言被终结的地方。我们遇到了各种旨在通过将大部分精力集中在构建模型上来解决问题的帖子/项目,并得出结论,它对给定的用例执行准确!!这是我们大多数人出错的地方。你还在迷茫吗,别急!请允许我们通过考虑一个经典的文本分类问题来阐述这一点;我们的第一个数据科学项目教会了我们很多在学习阶段从未预料到的事情。

预测全球疫情期间推特上的错误信息

啊!众所周知,Twitter 是数据科学项目的金矿。但是我们应该用 Twitter 做什么项目呢?当我们在 GitHub 上寻找几个项目来获得灵感时,我们发现大多数项目都倾向于情感分析。等等,我们要进行情感分析吗?选择一个项目主题是我们作为初学者面临的首要挑战。

提示 1:一开始就着手一个复杂的项目是绝对不行的。要脚踏实地!一步一步来!

像其他人一样,我们在开始时太受驱动了,想做一个复杂的项目。然而,我们意识到这不是正确的方法。我们想先搞清楚基本情况,经过几天的头脑风暴,我们敲定了几个有趣的话题。最后,我们决定对 twitter 上有关抗病毒药物、消毒剂和冠状病毒预防措施的错误信息进行分析。此外,选择这一主题的动机是为了理解实现解决方案背后的数学原理,以减少 Twitter 上的有害内容。

我们是如何解决这个问题的?

大多数像我们这样的新手在项目期间犯的主要错误是直接跳到项目要使用的 ML 算法的类型上!

提示 2:控制你的肾上腺素分泌!先看问题。请不要忽视数据工程部分。分析问题陈述,看看在你目前的知识水平下是否可行。

谢谢你走了这么远。从这里开始,我们将解释解决这个问题的逐步方法。

第一步:获取 TWITTER 开发者账户访问权限

为了使用 twitter 数据,我们需要一个 twitter 开发者帐户。这将为我们提供通过 TweePy 获取 tweets 的授权。但是,我们是如何创建 twitter 开发者账户的呢?

遵循以下步骤:

a.登录开发者账号,点击“创建 app”

b.将出现一个弹出窗口。点击‘应用’并从下面的仪表板中选择相关选项。

c.填写所需的详细信息,并获取访问密钥和令牌

呜哇!!!第一步现已完成。获得访问权限后,请确保点击“密钥和令牌”选项卡,并复制所提供的令牌。它将进一步用于通过 TweePy 访问 REST API。

第二步:数据收集和存储

我们通过 TweePy 使用 REST API 抓取推文。在这篇文章中,我们假设我们所有的读者都已经有了很好的 Python 实践经验。如果没有,我们强烈建议访问任何免费的 Python 在线课程,让自己熟悉该语言的语法。

一旦从 Twitter 收到令牌和密钥并安装了 TweePy,就可以开始通过 Twitter API 提取数据了。您可以通过 Twitter 标准 API 搜索字段 找到不同的可用数据字段。

技巧 3:永远不要仅仅为了完成任务而写脚本。优化它以执行多个操作。下面的代码片段一次性完成了管道的获取和清理。编码是一门艺术!练习直到你做对为止!

首先,让我们导入所需的库:

**# Data extraction & exploratory analysis**
import tweepy
from textblob import TextBlob
from tweepy import OAuthHandler
import pandas as pd
import numpy as np 
import re**#NLP**
from textblob import TextBlob
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from nltk.stem import PorterStemmer
from nltk.stem import WordNetLemmatizer
nltk.download('punkt')
from nltk.corpus import words
nltk.download('stopwords')**#ML Libraries for text classification**
from sklearn.metrics import accuracy_score
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression

一旦你的申请被批准,使用下面的脚本添加你自己的个性化 tokes。

**# Removed access keys and tokens for the sake of security**access_token = ''
access_token_secret = ''
consumer_key = ''
consumer_secret = ''

如前所述,现在是我们开始从 Twitter API 中提取数据的时候了。

**# authorize access to TweePy**auth = tweepy.OAuthHandler(consumer_key,consumer_secret)
auth.set_access_token(access_token,access_token_secret)
api = tweepy.API(auth,wait_on_rate_limit=True, wait_on_rate_limit_notify=True)**# Fetch tweets**tweets = []
sentiments =[]
count = 1
query = "#hydroxychloroquine OR #remdesivir OR #Remdesivir OR hydroxychloroquine OR remdesivir OR #GileadSciences OR GileadSciences OR #drug OR drug OR #antiviral OR antiviral OR #Antibiotic OR antibiotic"for tweet in tweepy.Cursor(api.search,q=query,count=450).items(50000):
    print(count)
    count+=1

    try:
        data = [tweet.created_at,tweet.id,tweet.text,tweet.source,tweet.retweet_count,tweet.user._json['screen_name'],tweet.user._json['created_at'],tweet.user._json['location'],tweet.coordinates,tweet.entities['urls']]
        data = tuple(data)
        tweets.append(data)

    except tweepy.TweepError as e:
        print(e.reason)
        continue

    try:
        sentiment_data = [tweet.created_at,tweet.text]
        sentiment_data = tuple(sentiment_data)
        textWords=sentiment_data[1].split()
        #clean tweets
        cleanedTweet=' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)|(RT)", " ", sentiment_data[1]).split())
        analysis= TextBlob(cleanedTweet)
        polarity = 'Positive'
        if(analysis.sentiment.polarity < 0):
            polarity = 'Negative'
        if(0<=analysis.sentiment.polarity <=0.2):
            polarity = 'Neutral'
        #print (polarity)
        dic={}
        dic['Sentiment']=polarity
        dic['Tweet']=cleanedTweet
        dic['Polarity'] = analysis.sentiment.polarity
        dic['Created_at'] = sentiment_data[0]
        sentiments.append(dic)

    except tweepy.TweepError as e:
        print(e.reason)
        continue

    except StopIteration:
        break

df_analysis = pd.DataFrame(tweets, columns = ['created_at','tweet_id','tweet_text','tweet_source','retweet_count','screen_name','account_creation_date','location','coordinates','urls'])df_analysis.to_csv('File Path')df_sentiment=pd.DataFrame(sentiments)df_sentiment.to_csv('File Path'

我们使用查询字符串来添加我们正在寻找的任何标签、关键字、关键短语或句柄(例如 query = " #羟氯喹" ),然后使用。items()功能。

在上面的脚本中, 文本 Blob 将我们的文本分类为阳性、阴性和中性标签(基于极性)。但是,我们为什么要使用 NLTK 呢?使用这两个库的唯一目的是理解每个包如何以自己的方式对文本处理做出贡献。此外,我们还强烈推荐浏览 SpaCy ,这是一个高级自然语言处理的开源软件库。

此外,我们可以设置自定义日期过滤器(since 和 until 参数)来查询给定日期范围内的 tweets。在执行此脚本之前,请确保添加您的文件路径来存储原始数据集和干净数据集。

tweepy.Cursor(api.search,q=query,since=2020-06-26 count=450).items(50000)

但是,请记住,Twitter 标准 API 搜索只能追溯到当前日期的 7 天之后。此外,计数参数指的是速率限制,请保持不变,即 450。

除了下载我们在上面实现的历史推文,我们还可以使用流 API 下载实时推文。请 查看Twitter 开发者手册了解更多信息。

第三步:分析并理解我们如何应用分类方法

文本分类是一个有监督的学习问题,它在机器学习和自然语言处理的帮助下将文本/标记分类到有组织的组中。 点击这里 了解更多详情。另外,情绪分析的基础知识可以在 这里找到

下面是我们的干净数据集后处理的快照:

df = pd.read_csv("text_analysis_antiviral.csv")
df.head()

清理数据集快照

如果您仔细观察数据集,会发现添加了 2 个新属性,其中包括情感和极性。它们说明了什么?好吧,我们假设你已经浏览了我上面附加的链接,这些链接有助于你理解分类方法的基础。

我们如何使用机器学习将这些文本分类为正面、负面和中性标签?在此之前,为什么我们甚至把他们排到上述标签?由于 TextBlob 已经按照极性对数据进行了分类,我们将使用它作为机器学习分类器的训练数据集。NLTK 在这里的工作是删除停用词并将句子分解成标记。然后,这些标记将经历词干化或词汇化的过程。

**# Perform text processing operations on the cleaned tweets**
def preprocess_tweet_text(tweet):
    tweet.lower()

  **  # Remove urls**
    tweet = re.sub(r"http\S+|www\S+|https\S+", '', tweet, flags=re.MULTILINE)

    **# Remove stopwords**
    stop = stopwords.words('english')

    **#Tokenization**
    tweet_tokens = word_tokenize(tweet)
    filtered_words = [w for w in tweet_tokens if not w in stop]

    **# Stemming**
    ps = PorterStemmer()
    stemmed_words = [ps.stem(w) for w in filtered_words]

    **#Lemmatization**
    lemmatizer = WordNetLemmatizer()
    lemma_words = [lemmatizer.lemmatize(w, pos='a') for w in stemmed_words]

    return " ".join(filtered_words)

提示 4:在阅读下面的内容之前,请仔细阅读上面的链接,以便对主题有一个清晰的了解。

这里的第一种方法是找到包含虚假声明/信息的推文,并将它们贴上负面标签。但是,TextBlob 不是已经这样做了吗?为什么要走这么远,还要用 ML 分类器?这是一种我们一开始就在谈论的自省。数据科学不仅仅是建模和准确性!它有很多方面,但不幸的是大多数时候都被低估了。

以“孙杀”为例。你认为这篇文章的标签应该是什么?TextBlob 会将其识别为中性,这是绝对正确的,因为它预测了这里的情绪。然而,我们的问题声明指出,错误信息应被视为负面标签。请不要混淆:)我们使用 TextBlob 来减少准备带有标签的训练数据集的负担。但是,TextBlob 可能无法正确识别标签。现在这完全没问题,因为我们都刚刚步入数据科学的世界!因此,随着我们的前进,我们可以创建自己的带有所需标签的训练数据,并针对各种用例进行测试!

步骤 4:让我们应用期待已久的 ML 分类器来训练数据集!

在应用模型之前,我们使用 TF-IDF 技术为提取的记号分配加权因子。下面的代码片段还将数据分为训练和测试。此外,我们的火车数据集中有大约 76000 条推文。

tf_vector = get_feature_vector(np.array(dataset_train.iloc[:, 0]).ravel())
X = tf_vector.transform(np.array(dataset_train.iloc[:, 0]).ravel())
y = np.array(dataset_train.iloc[:, 1]).ravel()
X_train = X
y_train = y
X_test = tf_vector.transform(np.array(dataset_test.iloc[:, 0]).ravel())
y_test = np.array(dataset_test.iloc[:, 1]).ravel()

你们不要担心!我们还将附上 GitHub 资源库的链接,该资源库将包含本项目中使用的所有 Python 笔记本。现在请把注意力集中在正确的概念上!

我们应该考虑应用哪种 ML 模型?我们使用流行的 朴素贝叶斯分类器逻辑回归.) 进行分类。请点击 链接 了解这些型号之间的更多差异。

对 TextBlob 生成的数据集进行后训练,我们实现了 LR 模型 70%的准确率和 NB 模型 66%的准确率。

模特培训

第五步:测试时间到了!!

当我们将测试数据集输入 LR 模型时,我们发现了一些非常有趣的见解!!

根据 LR 模型测试数据集

哇哦。你们有没有看到《孙杀》已经被正确的认定为阴性了??在训练数据集时,除了 TextBlob 生成的数据之外,我们还包含了另外 300 个数据点!通过这种方式,它正确地将一些错误信息文本标记为负面的。不过,推文“我们喝漂白剂吧”还是中性的。有趣的是,我们训练过的模型错误标记了一些文本。这是我们作为数据科学家必须开始思考的地方。如前所述,我们刚刚开始我们的旅程。作为初学者完成这些步骤本身就是一项值得称赞的工作。因此,我们强烈建议正确理解这些概念。此外,一旦基础得到加强,高级思维的范围总是存在的!

如前所述,下面是GitHub 资源库链接 供大家参考!

谢谢大家!

如有任何问题或疑虑,您也可以发电子邮件给我们:

nikhiljoshi19@uchicago.edu&nkamathardi@uchicago.edu

参考

https://first draft news . org/latest/how-to-investigation-health-misinformation-and-any-otherwise-using-twitters-API/

WhatsApp 群聊的综合数据分析

原文:https://towardsdatascience.com/a-comprehensive-data-analysis-on-a-whatsapp-group-chat-25d9535f3c65?source=collection_archive---------8-----------------------

有没有想过你的哪个朋友发短信骂人最多?

照片由于切尔·莫兰Unsplash 上拍摄

在考虑我的下一个项目时,我的脑海中突然冒出了一个想法。为什么不对大学生的 WhatsApp 群聊进行数据分析,找出有趣的见解,如使用最多的表情符号,每个人的情绪得分,谁说的脏话最多,一天中最活跃的时间,或者该群体在大学教学时间使用手机吗?这些肯定会是一些有趣的见解,对我来说比对你更有意义,因为这次聊天的人是我个人认识的人。

注意:我用两个字母代表我的每个朋友,这是他们名字的缩写,以保持匿名。

数据检索和预处理

第一步是收集数据。WhatsApp 允许你通过. txt 格式导出聊天内容。打开这个文件,您会得到如下格式的消息:

说假话?不,爸爸!

由于 WhatsApp 的文本是多行的,你不能一行一行地阅读文件,然后得到你想要的每条信息。相反,您需要一种方法来识别一行是新消息还是旧消息的一部分。您可以使用正则表达式来实现这一点,但是我使用了一个更简单方法。我创建了一个名为 vali_date()的函数,如果传递的参数是有效的日期,它将返回 True。

我对自己如何命名这个函数感到非常自豪。

在读取每一行时,我根据逗号将其拆分,并获取 split()函数返回的第一项。如果该行是新消息,第一项将是有效日期,它将作为新消息附加到消息列表中。如果不是,则该消息是前一条消息的一部分,因此将作为一条连续消息附加到前一条消息的末尾。

从这里开始,只需要从每一行中提取必要的细节:发送日期、发送时间、发送者和消息本身。这只是使用一些简单的字符串处理函数,主要是 split(),然后用它制作一个数据帧。如果您使用相同的方法,请确保正确指定日期和时间格式。

该导出还包含人员何时被移除、人员何时被提升为管理员以及其他对我们没有用处的功能性消息。用我写的代码,这些消息被设置为带有空白消息的发送者姓名。为了过滤掉这些关键字,我使用了一个非常简单的函数来检查发件人的姓名是否包含这些关键字。为了说明没有硬编码到 if 条件中的其他消息,我检查了发件人姓名的字数。在我使用的导出中,我没有一个人的名字超过 3 个单词,但是如果你在做这样的事情,你必须考虑不同的名字。我还删除了一个朋友的旧号码,它不能通过上面的 if 条件,所以我必须用另一个条件来解释。如果你想避免这个痛苦的过程,你应该使用正则表达式,我很尴尬的没有这样做。

由于我以单一的 DateTime 格式加载了日期和时间,因此我可以轻松地从中提取特定的信息,比如发送日期或月份,这对热图很有用。

此时,我想我已经准备好开始分析了,所以我绘制了一个简单的线图来查看这些年来消息的频率。这个群是 2017 年最后一个季度创建的,聊天是 2020 年导出的。我希望看到一个漂亮的线图,在奇怪的地方有波峰和波谷。但是当我看剧情的时候,我看到了一些奇怪的东西。

请注意,导出的前半部分没有消息。这似乎很奇怪。起初,我以为是我的文本处理出了问题,但我最终发现,WhatsApp 聊天导出是有限制的,它们可以导出多少条消息。这个限制大约是 40,000,这解释了为什么导出的前半部分没有很多消息。观察数据帧的形状,它有 39,489 行。在这一点上,我感到失望的是,我几乎一半的数据都无法访问。

但是等等!

隧道尽头的光来了。我的朋友也在这个小组中,他提到他可以使用他的旧手机。他把旧手机里的聊天记录导出来,发了过去。我应用了与第一次导出时相同的提取技术,尽管由于不同的日期表示和不同的联系人姓名,我对代码做了一些小的修改,但这次新的导出有令人惊讶的 68,584 条消息(我不确定它怎么会超过 40,000 条)。我合并了这两个数据帧,删除了重复的,最终得到了总计 74,357 条消息,时间跨度超过 2.5 年。线图现在看起来好多了。

探索性数据分析

现在我们有了一个干净的数据框架,是时候对它进行分析了。首先,由于几乎所有的情节都是将一个人与另一个人进行比较,我将为每个人指定一种特定的颜色,这样就可以很容易地在多个情节中识别每个人。我从这个网站上选择了我的调色板。

接下来,我制作了一个字典,其中每个键都是名称,每个键的值都是分配给它们的颜色。我创建了一个函数,它给定一个名称列表,对颜色进行重新排序,以匹配绘图的顺序。这个函数将有序的名称作为输入,并返回一个重新排序的颜色列表。这个列表必须被传递到 seaborn 绘图函数的pallete参数中。

现在我们为每个人准备了一套很好的颜色,我们可以用触须来可视化。

我的第一个图是每个人发送的消息总数。为此,一个简单的 seaborn countplot 就足够了。下一个是每个人的平均消息长度。为此,我创建了一个名为msg_length的新列,它包含每条消息的长度,这是我通过使用 lambda 函数得到的,该函数返回给定消息的长度。我只是按名称对数据帧进行分组,然后对返回的 groupby 对象应用mean()

看到这样的剧情并排真的很有意思。例如,发短信最少的人,MM,平均打出了第二长的信息。这意味着这个人不会发送很多 WhatsApp 消息,但如果他们发送了,也很长。我们可以看到 BA 发送的消息最多,但消息长度相对较长。RF 似乎在平均消息长度上击败了所有人,但仔细观察,这是由于一些“异常值”,如下所示:

有人真的很执着。

由于这里没有关于什么是真正的消息的规则,我将把这些消息放在里面,不把它当作离群值。 WhatsApp 是野生的。

导出的聊天在导出时没有任何媒体文件。任何包含媒体的消息都用“”表示。我们可以用这个过滤掉,看看谁发的媒体最多。

巴遥遥领先于所有人。他在总消息数上排名第一,在平均消息长度上排名第三。最具奉献精神的贡献者奖授予 BA!

不是说它值多少钱。

时间

接下来我们可以检查从每条消息的日期时间戳中提取的月份。我们可以使用这些来制作热图,以检查最活跃的时间段。我会把两块地并排放在一起。

我按月份对数据帧进行分组,并对返回的对象应用 sum 函数。为了统计 groupby 的每个组中的消息数量,我已经创建了一个名为count的列,其中每条消息的编号为 1。因为月份是有序的,所以我传递了一个包含月份的字符串列表,以便传递给绘图函数的order参数。

我们可以看到,一年中的最后 3 个月比其他月份活跃得多。最活跃的日子是 11 月的星期五和 12 月的星期一,然而,我们不能从中推断出太多。这可能是由于某些日子,而不是重复模式。为了证明这一点,我们可以检查最活跃的日期,看看它们是在一周的哪几天。

最高的两天是在 11 月和 12 月,这导致了这几个月的高平均值。

为了清楚地了解不同日期的活动,我们通过汇总一周 7 天中每一天的消息计数来绘制一个单独的图。为了更进一步,我们可以查看一天中每个小时的聚合。

看起来除了星期六之外,这一天本身没有什么变化。这可能是因为周六是周五后的第一个周末,人们通常会休息并做其他活动,而不是在手机上发消息。

观察每小时的活动,我们可以看到大多数的群体活动发生在晚上。一些其他有趣的事情发生了:

  • 从上午 9 点到 10 点的秋天。上午 9 点是开始上课的时间,没有多少学生倾向于在这个时间使用手机,因为他们要么赶去上课,要么和朋友聊天。
  • 下午 1 点的小高峰。这是在大学的午餐时间,因为下课了,人们更倾向于使用手机。然而,从上午 11 点到 12 点只有轻微的增加,这一事实表明我们在教学时间积极参与小组活动。用数据证明这种行为并不令人惊讶,但仍然令人着迷。
  • 从下午 3 点跳到下午 4 点。这是因为群里每个人都是大学生。大学在下午 3:30 结束,我们所有人都开始回家——在此期间,我们要么在回家的路上睡在公交车上,要么忙于做其他事情。

表情符号

使用 Python 的emoji库,我们能够从短信中提取表情符号。

对于小组中的每个人,我将创建一个字典,其中包含作为关键字的表情符号和作为其值的出现次数。我试图让字典包含至少出现 1 次的表情符号,但我的代码中有些东西不起作用,所以我为小组中每个人的每个可用表情符号初始化了计数 0。效率低下,我知道,但很有效。

我遍历数据帧中的每一行,对于每条消息,我用消息中的表情符号索引字典,并将计数加 1。然后我把字典按降序排序,得到每个人最常用的表情符号。

还绘制了一个柱状图,给出了每个人的表情符号总数。

我们可以看到,最常见的表情符号是哭笑表情符号,这与 Unicode 协会的报告一致,该报告称😂是最常用的表情符号。

有一些表情符号不是由 Google Colab 提供的。这些可能是较新的表情符号。RF 似乎使用最多的表情符号,尤其是👍表情符号,有点可疑。我们可以看到,这是由于单一的信息,而不是他们的集体短信习惯。

脏话&情感

一些真正令人兴奋的事情!有一个名为profanity_check的库可以检查给定的消息是否包含脏话。我想知道脏话对信息的情绪有多大影响。

首先,我创建了一个新列,如果消息包含脏话,则包含 1,如果不包含,则包含 0。这是使用前面提到的库中的predict函数来完成的。然后,我们可以按姓名对数据帧进行分组,并获得骂人列的平均值,这就给出了每个人在邮件中含有脏话的百分比。

我们可以看到 BA,RF 和 GJ 说脏话最多。因为事实证明他从来没有做出多大贡献。其他人则介于两者之间。

现在,为了测试脏话是否会影响情绪,我需要找到每条信息的情绪。为此,我将使用两个不同的分析器:NTLK 的 VADER(价感知词典和情感推理器)和 TextBlob。首先是 VADER。polarity_scores函数返回一个字典,其中有许多关键字,如正面情绪、负面情绪和整体/复合情绪。我将在这里使用复合情绪,它可以给出范围从-1 到+1 的值,前者表示最消极,后者表示最积极。从 TextBlob 库中,TextBlob函数返回一个情感,该情感被分类为两极性和主观性。这里,我们将再次使用范围从-1 到+1 的极性。

对于 VADER 来说,因为我们取情感的平均值,所以条平均在零左右,因为在有情感的文本中有许多中性文本。我们可以看到,骂人最多的巴,平均情绪最消极。RF 和 GJ 是第二和最渴望骂人的用户,然而,GJ 的负面情绪比 RF 多,这表明单单脏话并不能决定信息的负面情绪。VADER 对社交媒体上表达的情绪特别敏感,因为 WhatsApp 是一款社交媒体应用,我们可以相信这些情绪在某种程度上是准确的。

有趣的是,除了、巴和得分最低的前两名,TextBlob 对所有人进行了完全不同的情感排名。尽管 VADER 将 3 个人归类为平均负面情绪,但 TextBlob 返回的平均情绪都是正面的。

为了更深入地了解哪一个更准确,我们可以查看根据 VADER 和 TextBlob 的极性得分排序的消息,并直观地检查这些消息,以查看给出的情绪是否有意义。

第一条消息看起来很有趣。让我们仔细看看。

这是一个带有大量心形表情符号的表情符号,VADER 将其归类为具有最高积极情绪的表情符号,这是理所当然的。邮件的长度可能是造成这种情况的原因之一。然而,TextBlob 似乎只给了它一点积极的情绪。

上面列表中的第五条消息是一家公司的促销活动:

嗨,来自的问候。这是关于那些参加过我们项目的人的新会员计划。我们正在为我们的公司寻找“学生大使”。如果你有兴趣,请通过 WhatsApp 或致电@对了,谁是学生大使?他/她将在各自的机构中代表他/她的职责是什么?代表在其机构内组织研讨会/竞赛/速成班/客座讲座。作为大使,你得到了什么?您可以免费参加我们的所有项目/活动。如果发现你有才华,你将被录用为实习生。最重要的是对你的研究或项目工作的支持和指导。在你完成学业后,你将继续成为团队的一员。

这一信息显然没有积极的基调,但 VADER 却给了它很高的极性分数。

让我们看看按 TextBlob 极性得分降序排序的消息。

看起来 TextBlob 更适合短消息,因为它对短消息的积极情绪评分为 1.0。在所有邮件中,有 251 封邮件的正面情绪得分为 1.0。

总的来说,我认为我更喜欢 VADER 的观点,因为它似乎更适合长消息,并且特别适合社交媒体上表达的观点。

结论

那很有趣!看到人们的短信习惯和日常生活中的事件反映在文本中真的很有趣。我建议你看看我的代码,并将其应用到你自己的群聊中。然而,必须在数据帧创建部分进行一些修改。如果你有兴趣,给我发消息,我会帮你分类。

感谢您的阅读!让我知道你对这篇文章的看法。

密码

激活功能综合指南

原文:https://towardsdatascience.com/a-comprehensive-guide-on-activation-functions-b45ed37a4fa5?source=collection_archive---------26-----------------------

对数据科学的许多曲线进行现代考察

自 2012 年以来,神经网络研究的进展主导了大多数人工智能(AI)文献,模型迅速接管了各种主题的基准。在这些创新的核心,激活函数在神经网络的效率和稳定性方面起着至关重要的作用。在这篇文章中,激活功能研究的最新发展水平将尽可能简要地概述,并清晰、实际地关注它们为什么被发明以及何时应该被应用。

paweczerwi ski 在 Unsplash 上的照片

目录

  • 为什么激活功能? :
    -强制非线性
    -强制特殊数字属性
  • 雷鲁家族
    ——整流器:
    雷鲁LeakyReLU 和 PReLU ——指数运算: ELUSELU ——非单调运算: 嗖嗖塞鲁
  • 特殊族
    -
    线性 : 需要原始输出或融合运算时会用到 -Tanh:归一化回归+L1/L2 -Sigmoid:二元分类+二元交叉熵。 -soft max:范畴分类+范畴交叉熵
  • 关闭

为什么要激活函数?

简而言之,激活函数解决了神经网络中的两个关键问题:

  1. 确保激活图是非线性的,因此是相互独立的;和
  2. 确保某些输出具有基本的数字属性,例如,在[-1,1]范围内或者是有效的概率分布。

非线性

为了理解非线性激活图的需要,考虑下面两个函数: f(x) = ax + bg(x) = (c+d)x + (e + f) 。前者只有两个常数,而后者有四个。问题是:它们实际上是两种不同的功能吗?

答案是否定的,“(c+d)”和“a”的表现力是一样的。如果你选择 c = 10d = 2 ,我可以选择 a = 12,我们会得到相同的结果。“(e + f)”和“b”也是如此。为了有效地拥有四个独立参数,它们必须不能组合。在数学术语中,这意味着参数之间的关系必须是非线性的。例如, h(x) = sin(cx + d) + fx + e 是一个有四个参数的非线性模型。

在神经网络中,如果层是线性的,两个连续的层将是可组合的。因此,它们实际上只是一层伪装。为了不是线性的,所有层都被传递到非线性函数中,例如 ReLU 和 Tanh 函数,将它们隔离到单独的功能单元中。

数字属性

当回答“是”或“否”的问题时,例如“图像中是否有人脸”,false 被建模为 0,true 被建模为 1。给定一个图像,如果网络输出是 0.88,我们说网络回答为真,因为 0.88 更接近于 1 而不是 0。然而,网络的输出可以是 2 或-7。怎么能保证它的答案会在[0,1]范围内呢?

为此,设计了几个激活函数来保证某些数值特性。对于二进制分类情况, sigmoid 函数( σ(x) )接受范围[-∞,∞]内的输入,并输出范围[0,1]内的值。同样,双曲正切函数( tanh(x) )将[-∞,∞]映射到[-1,1]。对于独热编码的分类数据, softmax 函数将所有值压缩到[0,1]区间,并确保它们的总和为 1。

通常,这些“数字属性”激活用于网络的最后一层,称为输出层,因为这通常是唯一需要特殊处理的层。对于所有其它的,使用更简单的非线性,例如 ReLU 族。虽然存在网络中间需要特殊激活的情况,例如在对象检测模型和注意层上使用的情况,但这些并不是标准情况,不在本文的讨论范围之内。

雷鲁家族

在上一节中,我们看到了为什么需要激活以及激活可以解决哪些问题。此外,我们注意到所有层都要求激活功能独立,但只有少数层需要特殊功能。对于所有普通层,通常使用 ReLU 系列的激活。

在进入肮脏的细节之前,我想强调的是,在 ReLU 类激活的领域中,使用其中一个而不是另一个并没有太多特定问题的理由。实际上,人们只是在一个循环中尝试十几个时期,看看哪个在他们的任务中表现最好。

也就是说,一个经验法则是在开发期间尽可能长时间地坚持原始的 ReLU 激活,如果您的模型表现不佳,请按照 Tensorflow 2 文档中给出的建议跳到 SELU 激活(即使对于 PyTorch 用户也是如此),并取消所有的批处理规范化。我知道这听起来有点刺耳,但它确实有效,可能会给你带来 5%到 10%的提升。

作为总结,下图总结了 ReLU 系列中最著名的激活,以及它们的图(左)和它们在 CIFAR-10 数据集上的性能(右)。

图 ReLU 系列中最广为人知的函数(左)及其在 CIFAR10 数据集上 200 个时期内各自的性能图(无遗漏)。摘自:缩放的指数正则化线性单元(SERLUs)的有效性

整流器线性单元(ReLU)

整流器的数学定义是:

ReLU(x) = max(0,x)

在英文中,如果是正数,返回 x ,如果是负数,返回 0。

这是可能的最简单的非线性之一;计算最大值函数非常简单。ReLU 函数的早期用途之一来自于 AlexNet 架构,它使用这种激活方式的训练速度几乎是更传统的 Tanh 函数的八倍。出于这个原因,直到今天,ReLU 系列激活是大多数层的事实上的选择,因为它们计算简单,但有效。双赢的局面。

此外,早期的神经网络被一个称为爆炸/消失梯度的问题所困扰。总之,在反向传播过程中,当您移回网络时,梯度会彼此相乘,因此具有大梯度的大梯度会使信号爆炸,而具有近零梯度的近零梯度会使信号消失。使用 ReLU 激活,只有两种可能的梯度:一是正部分,零是负部分。因此,关于激活函数在该问题上的作用,整流器有效地解决了爆炸问题,这可能是最糟糕的,同时产生了死梯度问题。

泄漏单元

大多数人第一次看到 ReLU 函数时提出的第一个顾虑是:负的部分真的被扔掉了吗?是的,它是。研究人员对此感到困惑,提出了 LeakyReLU。不要扔掉消极的部分,而是返回一个减少的版本。数学上:

LeakyReLU(x) = max(0,x) + min(0.01⋅ x,0)

这样,信号不会完全丢失,但会因泄漏因子而显著减弱。在实践中,这在某些情况下证明是有效的。此外,它还缓解了死梯度问题,允许至少一部分信号通过。在接下来的激活中,玩消极的部分是一个反复出现的主题。

下一次迭代是参数 ReLU,简称 PReLU。基本原理是:为什么是 0.01?相反,让我们引入一个α变量,让它是可训练的。这样,我们不需要自己定义泄漏系数;我们让网络自己学习最合适的值。在表达形式上:

PReLU(x) = max(0,x) + min(αx,0)

请记住,α变量不是全局变量。每个单位都有它的可训练α。这种激活展示了数据科学的思维方式:如果可以让模型决定什么是最好的,为什么要自己设置呢?

指数单位

继续追求更好的激活性能,2015 年底在产生了对负部分使用指数函数的想法。指数函数对于负值是饱和的,这意味着它平滑地趋向于一个固定常数。使用它,我们可以更接近地模拟原始的 ReLU 函数,它在零处饱和,同时仍然在某种程度上保留负的部分。这是它的数学公式:

ELU(x) = max(0,x) + min(eˣ — 1,0)

在许多情况下,ELU 函数是对原始 ReLU 函数的明显改进。相比之下,漏变量并不总是更好。

该领域的最新进展之一被称为缩放指数线性单元,或 SELU,其主要创新是自规范化。这意味着,当训练时,它将向输出零均值和单位方差的结果收敛。实际上,这使得批量规范化层变得过时。因此,使用 SELU 激活的模型更简单,需要的操作更少。最后,通过用神奇的常数简单地缩放正负部分,就可以实现自规范化属性。形式上:

⋅最大值(0,x)+1.7580⋅min(eˣ-1,0)卢瑟(x)≈1.0507

有关使用该激活函数和推导神奇常数的更多详细信息,请考虑阅读论文张量流文档。上面提到的常数是通过把原来的 SELU 表达式简化成更紧凑的形式而得到的。

非单调激活

到目前为止,ReLU 家族的所有激活都是单调递增的。在英语中,这意味着函数值只会增长。标志性的非单调函数有抛物线( x )和正弦函数( sin(x) ),抛物线上下周期性变化。

非单调激活的第一个成功提案是谷歌大脑团队的 Swish 函数,它被简单地定义为:

F(x) = x ⋅ σ(x)

σ(x)是 sigmoid 函数。虽然该表达式与 ReLU 函数不相似,但它们的图非常相似,正部分接近相同,负部分在零处饱和,负部分在零附近出现“凹陷”或“腹部”(图 1,蓝色)。这是通过“自门控机制实现的。基本上, x 是“信号”, σ(x) 是“选通函数”(在零点饱和的函数),将 σ 应用于 x 并乘以 x 就是取信号并自己选通,这样,一个自选通操作。在团队实验中,他们发现对于非常深的网络(30+层),这种激活优于 ReLU 功能。

最后, SERLU 激活是对 SELU 函数的改进,保留了自归一化属性,同时包括一个自门控机制,以便在负值时在零处饱和。作者通过使用指数函数作为门控操作,而不是 sigmoid,并重新计算魔法常数来实现这一点。这导致函数的负端出现一个大的“下降”,类似于 Swish 函数,但更明显(图 1,红色部分)。形式上,SERLU 被定义为:

塞卢(x) ≈ 1.0786 ⋅最大值(0,x) + 3.1326 ⋅ min(x⋅ eˣ — 1,0)

注意 x ⋅ eˣx ⋅ σ(x) 之间的相似性。两者都是自门控机制。

截至 2020 年,现在判断这些非单调函数是否能够经受住时间的考验,并取代 ReLU 或 SELU 成为一个良好的通用替代方案还为时过早。然而,如果可以的话,我敢打赌,自规范化特性将会一直存在。

特殊家庭

如前所述,有些层需要特殊处理,超出了 ReLU 类激活所能提供的范围。对于这些层,使用线性、sigmoid、tanh 和 softmax 激活,其用例如下:

  • 线性:当你需要网络的原始输出时使用。这对于融合运算很有用,例如 sigmoid-crossentropysoftmax-crossentropy ,它们在数值上更稳定,并且用于非标准化回归。此外,在理论分析中,这种激活对于调试和简化是有用的。
  • Tanh :用于归一化回归问题,其输出在[-1,1]范围内。通常与 L2 损失一起使用。
  • Sigmoid :见于二进制分类问题将输出压缩到[0,1]范围。几乎总是与二元交叉熵损失一起使用。
  • Softmax :在范畴分类上下文中看到,以强制网络输出是有效的概率分布。这意味着所有值都在[0,1]范围内,并且总和为 1。与分类交叉熵损失一起使用。

如您所见,给定一个问题,选择您应该使用哪个激活是很简单的。此外,所选函数提示了应该使用/考虑哪些损失函数。虽然这是一种简化,但作为一个起点是有用的。如前所述,一个经验法则是始终使用 ReLU 激活,为最后一层选择最合适的特殊函数,并在以后的迭代中,扩展这些初始选择并尝试替代公式。

最后,值得一提的是,对于某些问题,类并不是互斥的。在这种特殊情况下,单个输入可能会被标记为多个类。在这些情况下,每个类使用 sigmoid,而不是 softmax 激活。通过这种方式,所有输出都被压缩到[0,1]范围内,但不会强制累加到 1。

关闭

在这篇文章中,国家的最先进的激活功能进行了审查,与实际指导,使用和为什么。总之,激活用于使网络非线性化,并对输出图层实施特殊属性。对于内部层,使用 ReLU 系列,并且作为一个经验法则,尽可能长时间地坚持 ReLU 激活,然后切换到 SELU 激活,并移除所有批处理规范化操作。对于输出图层,考虑对非标准化/标准化回归使用线性/双曲正切激活,对二元/分类使用 sigmoid/softmax。

正如在任何指南中一样,总会缺少一些东西。在这里,我故意跳过了不太为人所知/使用过的选项,比如 softplussoftsign 和 relu6 函数。我选择这样做是为了让文章尽可能简短,而不影响流行的文章。如果您错过了正在讨论的任何激活功能,不同意某些东西或希望看到一些概念的扩展,请在评论部分让我知道,我将尽我所能保持这份文件的最新:)

如果您对本文有任何问题,请随时发表评论或与我联系。如果你刚接触媒体,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。

感谢阅读:)

用 Python 下载股票价格的综合指南

原文:https://towardsdatascience.com/a-comprehensive-guide-to-downloading-stock-prices-in-python-2cd93ff821d4?source=collection_archive---------0-----------------------

来源: Unsplash

下载历史股票价格,只有一行代码!

这篇短文的目的是展示用 Python 下载股票价格(和股票相关的数据)是多么容易。在本文中,我介绍了两种方法,都使用 Yahoo Finance 作为数据源。有许多替代产品(Quandl、Intrinion、AlphaVantage、Tiingo、IEX 云等)。),然而,雅虎财经可以被认为是最受欢迎的,因为它是最容易访问的(免费且无需注册)。

第一种方法使用一个名为yfinance的库,这绝对是我所知道的最简单的方法。第二个是yahoofinancials,稍微复杂一点,但是,由于我们在下载数据方面付出了额外的努力,我们收到了更多与股票相关的数据。

让我们开始吧!

设置

我们需要加载以下库:

import pandas as pd
import yfinance as yf
from yahoofinancials import YahooFinancials

你可以pip install你错过的图书馆:)

使用 yfinance 下载股票价格

yfinance是一个非常方便的库,是我下载股票价格的必去库。它以前被称为fix_yahoo_finance。这个库的简短历史是作为对流行的pandas_datareader库的修复而开始的。随着时间的推移,Yahoo Finance 改变了 API,相关的功能被弃用。这时候fix_yahoo_finance被引入,再次使从雅虎财经下载数据成为可能。它既是pandas_datareader的补丁,也是一个独立的库。

事不宜迟,下面我展示如何快速下载特斯拉的股票价格:

运行代码会产生下表:

默认情况下,该函数下载每日数据,但是我们可以将interval指定为以下之一:1m、5m、15m、30m、60m、1h、1d、1wk、1mo 等等。下载数据的命令可以简化为一行:

tsla_df = yf.download('TSLA')

然而,我想展示如何使用函数的参数。我提供了所考虑的时间范围的开始和结束日期,并禁用了进度条(对于如此少量的数据,显示它没有意义)。我们可以通过提供一个列表(比如[‘TSLA', ‘FB', ‘MSFT'])作为tickers参数,一次性下载多种资产的股票价格。此外,我们可以设置auto_adjust = True,这样所有显示的价格都会针对潜在的公司行为进行调整,比如拆分。

除了yf.download函数,我们还可以使用Ticker()模块。下面我给出一个下载特斯拉股票价格全部历史的简短例子:

运行代码会生成以下图形:

使用Ticker模块的好处是我们可以利用连接到它的多种方法。我们可以使用的方法包括:

  • info —打印出一个 JSON,其中包含许多有趣的信息,比如公司的全名、业务摘要、所处的行业、上市的交易所(还有国家、时区)等等。同样值得一提的是,JSON 包括一些财务指标,如 beta 系数。
  • recommendations —包含分析师提出的建议的历史列表
  • actions —显示股息和拆分等操作
  • major_holders —顾名思义,显示主要持有人
  • institutional_holders —显示机构持有人,如下图所示:

  • calendar —显示传入事件,如收益。我写了一篇关于从雅虎下载完整收益日历的最简单方法的文章。金融。

有关可用方法的更多信息,请务必查看yfinanceGitHub 资源库

使用 yahoofinancials 下载股价

本文中我想提到的第二个yahoofinancials。虽然我发现使用这个库要求有点高,但是它提供了很多在yfinance中没有的信息。让我们从下载特斯拉的历史股价开始:

我们首先通过传递 Tesla 的 ticker 实例化了一个YahooFinancials类的对象。这样做了之后,我们就可以用各种方法提取有用的信息。我们从历史股票价格开始。这个方法的用法是不言自明的。需要注意的一点是,结果是一个 JSON。这就是为什么我必须运行一系列操作来提取相关信息并将 JSON 转换成一个pandas数据帧。运行该代码片段会导致:

获得历史股票价格的过程比yfinance的情况要长一点。现在是时候展示yahoofinancials的光芒了。我简要描述一下最重要的方法:

  • get_stock_quote_type_data —返回股票的大量一般信息,类似于yfinanceinfo。使用方法返回以下内容:

  • get_key_statistics_data / get_summary_data —这两种方法返回许多统计数据(如 beta、市净率等。)
  • get_stock_earnings_data —返回收益信息(年度和季度)以及公司将报告收益的下一个日期:

这种形式的 JSON 可能不是最易读的,但是它适合屏幕:)

  • get_financial_stmts —获取公司财务报表信息的有用方法

我展示了一个使用这个库下载单个公司信息的例子。然而,我们可以很容易地提供一个公司列表,这些方法将返回适当的 JSONs,其中包含每个公司所请求的信息。让我们看一个下载多家公司调整后收盘价的示例:

将数据放入pandas DataFrame 需要多一点的努力,然而,代码可以很容易地重用(对于YahooFinancials类的不同方法也有轻微的修改)。

结论

在本文中,我展示了如何轻松地从 Yahoo Finance 下载历史股票价格。我从使用yfinance库的一行程序开始,然后逐渐深入提取更多关于股票(和公司)的信息。使用上面提到的库,我们可以在雅虎财经网站上下载几乎所有可用的信息。

您可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!

我最近出版了一本关于使用 Python 解决金融领域实际任务的书。如果你有兴趣,我贴了一篇文章介绍这本书的内容。你可以在亚马逊或者 Packt 的网站上买到这本书。

生成对抗网络综合指南

原文:https://towardsdatascience.com/a-comprehensive-guide-to-generative-adversarial-networks-gans-fcfe65d1cfe4?source=collection_archive---------20-----------------------

从噪音中产生有意义的数据

《活的蒙娜丽莎》来自现实神经说话头部模型的少数镜头对抗学习

在我看来,这个(GANs)以及现在被提出的变体是 ML 过去 10 年中最有趣的想法

——Yann le Cun(脸书副总裁兼首席人工智能科学家)在他的 Quora 会议上

gan 是深度学习的最新奇迹之一。这些能够从垃圾数据中产生智慧。他们可以用来生成图像,视频,改变图像和更多!GANs 最近的研究集中在制造(人类的)深度赝品并检测它们。

GAN 本质上是一种神经网络架构(与其说是架构,不如说是框架),其中生成性模型与非生成性模型配对;生成模型因生成质量差而受到惩罚,而另一个模型因生成模型生成质量好而受到惩罚。所以在某种程度上,这些模特竞争来实现他们各自的目标。原文论文建议,

生成对抗网络只不过是一个通过对抗过程来估计生成模型的框架。

在本文中,我们将了解什么是 GANs,它们是如何工作的,并浏览一些它的用例。让我们先来看看主要内容:

内容

  1. 创成式 v/s 判别建模
  2. 生成性对抗性
  3. 几个使用案例(让你思考)
  4. 结论

生成式 v/s 判别建模

图片由作者提供,背景由像素提供

生成建模

任何涉及学习给定数据分布的趋势并生成非常类似或属于该分布的样本的建模都可以称为生成式建模。生成模型的一个非常常见的例子是根据前面的单词预测句子中的下一个单词。

关于文本生成的更多内容,你可以参考我的关于文本生成的文章

生成模型是具有联合概率分布 P(X,Y) ( 或者如果没有Y就只有 P(X) )的统计模型,其中 X 是自变量,Y 是因变量。

P(X,Y) 可以读作变量 X Y 的概率分布。

甘也是生殖模型。但与其他的不同,新颖之处在于它的训练评估手段,也就是对手。

判别建模

而判别模型是对来自给定分布的数据进行判别(分类)的模型。辨别一幅给定的图片中有一只猫还是一只狗是辨别建模最简单的例子。

判别模型可以正式表示为 P(Y|X) ,其中 X 为自变量,Y 为因变量。

P(Y|X) 可以解释为“给定事件 X 已经发生,事件 Y 发生的概率”。

在 GANs 中,歧视者引入了我们将在下一节讨论的“敌对”性质。

通过谷歌开发者博客生成式 v/s 判别建模

生成性对抗性

在这里,我们讨论 GANs 的实际架构,看看它是如何工作的。

典型的甘

甘人就是这样被训练的。借助一个例子,我们将一个接一个地处理这个架构。假设我们想从随机数据中生成的图像。

噪音

这是随机分布的数据。这是转换成所需分布的分布(是的!在后台,GANs 将一个分布转换成另一个分布(即,他们将一个统计函数映射到另一个)。

来自真实分布的数据

这是实际的、期望的分布。GAN 的最终目标是从前面小节提到的噪声中产生(转换)属于该分布的数据。在我们的示例中,这是一组真实的狗图像,我们在这些图像上训练模型。

鉴别器

鉴别器

这是 GANs 区别于其他生成模型的地方。将一个生成模型与一个鉴别模型结合起来就是 GANs 的全部内容。让我们看看它是如何工作的。

鉴别器的唯一目的是将图像分类为真或假。所以,鉴别器有两个功能:

  1. 准确地将真实图像分类为真实的。
  2. 准确地将假图像分类为假的。

在我们的例子中,鉴别器可以是一个基本的基于 CNN 的二值图像分类器

但这里有一个问题,当我们训练鉴别器从假图像中“辨别”真实图像时,生成器被训练来欺骗鉴别器,使其落入陷阱,将生成的图像分类为真实图像。

是的,我在暗示,鉴别器只不过是一个可训练的评估指标,它告诉我们生成的数据质量有多好/多差。

好吧,我想现在你对两家网队是如何竞争的有所了解了。我们将在下一小节讨论发电机的工作原理。

发电机

发电机

这是氮化镓的主要成分。这里,生成网络试图学习分布的趋势,并生成属于该分布的数据。

那么我们如何做到这一点呢?这要看情况。在我们的例子中,为了生成狗的图像,我们的噪声将经历一些去卷积层,最后,输出将是一个图像,希望是一只狗的。生成的图像将被鉴别器分类为真或假。如果生成的图像远非“真实”,则生成器将受到损失更大的惩罚,并且随着它在欺骗鉴别器方面取得进展,损失将会减少。

这是发电机网络背后的基本思想。架构可能因用例而异。有一些 GAN 架构是有条件的,也就是说,除了噪声之外,还有一些生成数据的条件。这样的添加可能会改变一点架构,但对手的基本思想仍然存在。

我们现在继续发电机和鉴别器的集体训练。

将发生器和鉴别器组合训练为“GAN”

所以,甘是伟大的!但是生成器和鉴别器的组合训练带来了收敛问题。让我们看看 GAN 是如何训练的。

训练时,发生器应与鉴别器隔离,反之亦然。简而言之,首先对鉴别器进行几个时期的训练,然后对发生器进行训练,这一序列反复进行。这就保证了训练的方向是正确的。否则,同时训练这两者就像击中一个移动的目标,失败的可能性更大。

如果你不能训练一个分类器来区分真实数据和生成数据,甚至是初始的随机生成器输出,你就不能开始 GAN 训练。

谷歌开发者博客

此外,随着生成器越来越擅长欺骗鉴别器,作为一个推论,鉴别器的准确性会降低。当鉴别器达到精度 0.5 时,这表明鉴别器已经开始随机预测,即在掷硬币时(这显然是不应该的)。这对发电机培训没有任何帮助,反而可能降低其性能。

因此,GANs 的收敛并不稳定,这是一个主要问题。

培训损失

GANs 论文将培训损失定义为:

通过谷歌开发者博客的 Minimax 损失

这是最小最大损失,鉴别器试图使其最大化,发生器试图使 log(1 - D(G(z))) 最小化,因为它不能触及 log(D(x))。

然而,论文还建议修改发电机的这一损耗,以使 log(D(G(z))最大化。

几个用例(让你思考)

  • 普通的 GAN(GAN论文中描述的那些)可用于在不平衡或数据较少的情况下增加数据用于训练。
  • 深度卷积生成对抗网络或 DCGAN 是具有用于图像生成的卷积层的普通 GAN
  • pix2pix 模型可用于将结构的线框作为输入,并生成完整的结构作为输出。其他应用包括黑白图像着色。
  • CycleGAN 用于将图像从一个域转换到另一个域,无需任何成对的训练样本
  • DeepFake 生成和检测是 GANs 的最新研究课题之一,本质上是生成经过编辑或篡改的图像,肉眼看起来很逼真。这可以在照片/视频编辑软件的帮助下很容易地手动完成,因此很容易被误用。DeepFake 检测可以作为生成的一个推论。

我将在以后的文章中尝试介绍其中一些 gan 的实现。敬请关注!

结论

这篇文章的主要内容是生成模型的对抗性训练评估的概念。这为研究人员提供了许多分支,以提出类似的评估器来获得更好的模型性能。

我们还看到了生成式和判别式建模的概念,以及它们之间的区别。

我们研究了 gan 的工作原理及其背后的想法。总的来说,我们采取了务实的方法;我们讨论了 GANs 的培训方面以及实际培训网络时出现的问题。

最后,我们谈了一些众所周知的甘斯风味。

参考资料:

原文:https://arxiv.org/abs/1406.2661

有关 GANs 的数学转换方面的更多信息,请参考:

[## 理解生成敌对网络(GANs)

一步一步地建立导致 GANs 的推理。

towardsdatascience.com](/understanding-generative-adversarial-networks-gans-cd6e4651a29) [## 简介|生成性对抗网络|谷歌开发者

生成对抗网络(GANs)是机器学习领域一项令人兴奋的最新创新。甘是生殖的…

developers.google.com](https://developers.google.com/machine-learning/gan)

使用 PyTorch 进行 Seq2Seq 建模的神经机器翻译综合指南。

原文:https://towardsdatascience.com/a-comprehensive-guide-to-neural-machine-translation-using-seq2sequence-modelling-using-pytorch-41c9b84ba350?source=collection_archive---------11-----------------------

在本帖中,我们将构建一个基于 LSTM 的 Seq2Seq 模型,该模型采用编码器-解码器架构,用于无注意机制的机器翻译。

目录:

  1. 简介
  2. 数据准备和预处理
  3. 长短期记忆(LSTM) —引擎盖下
  4. 编码器模型架构(Seq2Seq)
  5. 编码器代码实现(Seq2Seq)
  6. 解码器模型架构(Seq2Seq)
  7. 解码器代码实现(Seq2Seq)
  8. Seq2Seq(编码器+解码器)接口
  9. Seq2Seq(编码器+解码器)代码实现
  10. Seq2Seq 模型训练
  11. seq 2 seq模型推断
  12. 资源&参考文献

1.介绍

N eural 机器翻译 (NMT)是一种机器翻译方法,它使用人工神经网络来预测单词序列的可能性,通常在一个单一的集成模型中建模整个句子。

对于计算机来说,用简单的基于规则的系统将一种语言翻译成另一种语言是最困难的问题之一,因为它们无法捕捉到翻译过程中的细微差别。然后不久,我们使用统计模型,但在深度学习进入后,该领域被统称为神经机器翻译,现在它已经取得了最先进的成果。

我希望这篇帖子对初学者友好,所以一种特定的架构(Seq2Seq)显示了成功的良好迹象,这就是我们在这里要实现的。

因此,本文中的序列到序列(seq2seq)模型使用一种编码器-解码器架构,该架构使用一种称为 LSTM(长短期记忆)的 RNN,其中编码器神经网络将输入语言序列编码为单个向量,也称为 上下文向量

这个 C 上下文向量 据说包含了输入语言序列的抽象表示。

这个向量然后被传递到解码器神经网络,用于输出相应的输出语言翻译句子,一次一个单词。

我正在做一个德语到英语的神经机器翻译。但是同样的概念可以扩展到其他问题,例如命名实体识别(NER),文本摘要,甚至其他语言模型等。

2.数据准备和预处理

为了以我们想要的最佳方式获取数据,我使用了 SpaCy(词汇构建)、TorchText(文本预处理)库和包含英语、德语和法语翻译序列的 multi30k 数据集

Torch text 是一个强大的库,用于为各种 NLP 任务准备文本数据。它拥有对文本数据进行预处理的所有工具。

让我们看看它能做的一些过程,

  1. 训练/有效/测试分割 :将你的数据分割到指定的训练/有效/测试集中。

  2. 文件加载 :加载各种格式的文本语料库(。txt,。json,。csv)。

  3. 标记化 :将句子拆分成单词列表。

  4. Vocab :从文本语料库中生成词汇列表。

  5. 单词到整数映射器 :将整个语料库的单词映射成整数,反之亦然。

  6. 词向量 :将一个词从高维转换到低维(词嵌入)。

7.:生成样本的批次。

所以一旦我们理解了在 torch text 中可以做什么,让我们来讨论一下如何在 torch text 模块中实现它。这里我们将利用火炬文本下的 3 个类。

1. 字段 :

  • 这是 torch text 下的一个类,在这里我们指定应该如何对我们的数据语料库进行预处理。

2.tabular dataset:

  • 使用这个类,我们实际上可以定义以 CSV、TSV 或 JSON 格式存储的列的数据集,还可以将它们映射成整数。

3.😗*

  • 使用这个类,我们可以填充我们的数据以进行近似,并用我们的数据进行批处理以进行模型训练。

这里,我们的源语言(SRC —输入)是德语,目标语言(TRG —输出)是英语。我们还添加了 2 个额外的标记“序列开始”和“序列结束”,用于有效的模型训练。

在设置了语言预处理标准之后,下一步是使用迭代器创建成批的训练、测试和验证数据。

创建批处理是一个详尽的过程,幸运的是我们可以利用 TorchText 的迭代器库。

这里我们使用 BucketIterator 来有效填充源句子和目标句子。我们可以使用。属性及其对应的(英语)数据批。trg 属性。此外,我们可以在标记数据之前看到数据。

我刚刚试验了 32 个批次的大小,下面显示了一个样本批次。句子被标记成单词列表,并根据词汇进行索引。“填充”令牌的索引为 1。

每一列对应一个句子,用数字索引,我们在单个目标批次中有 32 个这样的句子,行数对应于该句子的最大长度。短句用 1 填充以弥补长度。

下表(Idx.csv)包含该批次的数字索引,这些数字索引随后会被输入到 word embedding 中,并转换为密集表示以供 Seq2Seq 处理。

带索引的样本目标批次

下表(Words.csv)包含与批次的数字索引相对应的单词。

带单词的样本目标批次

3.长短期记忆(LSTM)

LSTM——引擎盖下。来源—作者

上图显示了单个 LSTM 单元下的单元。我会在最后添加一些参考资料来学习更多关于 LSTM 的知识,以及为什么它对长序列很有效。

但是简单地说,香草 RNN,门控递归单元(GRU)由于其设计的性质而不能捕获长期依赖性,并且严重地受到消失梯度问题的影响,这使得权重和偏差值的变化率可以忽略,从而导致较差的泛化能力。

在 LSTM 单元中,我们有一组小型神经网络,在最后一层有 sigmoid 和 TanH 激活,以及一些向量加法、连接和乘法操作。

*****Sigmoid NN*→压扁 0 和 1 之间的值。比方说,一个更接近 0 的值意味着忘记,一个更接近 1 的值意味着记住。

嵌入 NN →将输入的单词索引转换成单词嵌入

TanH NN →挤压-1 和 1 之间的值。有助于调节向量值,使其不会爆炸到最大值或收缩到最小值。

大门:

GATES 盖茨。来源—作者

但是 LSTM 有一些特殊的单元,称为门(记住(添加)门,忘记门,更新门),这有助于克服前面提到的问题。

  1. 遗忘门 →其中有 sigmoid 激活,取值范围在(0–1)之间,它在单元状态上乘以以遗忘某些元素。(“向量”* 0 = 0)****
  2. 添加门 →其中有 TanH 激活,取值范围在
    (-1 到+1)之间,在单元状态上添加以记住一些元素。(" Vector" * 1= "Vector ")
  3. 更新隐藏 →根据单元格状态更新隐藏状态。

隐藏状态和单元状态在这里被称为 上下文向量 ,其是来自 LSTM 单元的输出。输入是输入到嵌入神经网络的句子的数字索引。

4.编码器模型架构(Seq2Seq)

在开始构建 seq2seq 模型之前,我们需要创建编码器、解码器,并在 seq2seq 模型中创建它们之间的接口。

让我们通过德语输入序列“Ich Liebe Tief Lernen”翻译成英语的“ 我爱深度学习 ”。******

LSTM 编码器架构。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者

为了更轻松,我们来解释一下上图中发生的过程。Seq2Seq 模型的编码器一次接受一个输入。我们输入的德语单词序列是“ich Liebe Tief Lernen”。

此外,我们在输入句子的开始和结尾添加了序列“SOS”的开始标记和句子“EOS”的结束标记********

因此在

  1. 在时间步骤 0,发送“SOS”令牌,
  2. 在时间步骤 1,发送令牌“ich ”,
  3. 在时间步骤 2,发送令牌“Liebe ”,
  4. 在时间步骤 3,发送令牌“Tief ”,
  5. 在时间步骤 4,发送令牌“Lernen ”,
  6. 在时间步骤 4,发送令牌“EOS”。

编码器架构中的第一个模块是单词嵌入层(绿色模块所示),它将输入索引单词转换为称为单词嵌入的密集矢量表示(大小为 100/200/300)。

然后,我们的字嵌入向量被发送到 LSTM 单元,在那里它与隐藏状态(hs)和前一时间步的单元状态(cs)组合,并且编码器块输出新的 hs 和 cs,其被传递到下一个 LSTM 单元。据了解,到目前为止,hs 和 cs 捕获了句子的一些矢量表示。

在时间步长-0,隐藏状态和单元状态或者完全由零或者随机数初始化。

然后在我们发送了 pass 我们输入的所有德语单词序列后,最终得到一个 上下文向量 【黄色块中所示】(hs,cs),这是单词序列的密集表示,可以发送到解码器的第一个 LSTM (hs,cs)进行相应的英语翻译。

在上图中,我们使用 2 层 LSTM 架构,其中我们将第一个 LSTM 连接到第二个 LSTM,然后我们获得堆叠在顶部的 2 个 上下文向量 作为最终输出。这纯粹是实验性的,你可以操纵它。

我们必须在 seq2seq 模型中设计相同的编码器和解码器模块。

上述可视化适用于一批句子中的单个句子。

假设我们的批量大小为 5(实验性的),那么我们将一次一个单词的 5 个句子传递给编码器,如下图所示。

批量大小为 5 的 LSTM 编码器。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者

5.编码器代码实现(Seq2Seq)

6.解码器模型架构(Seq2Seq)

LSTM 解码器架构。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者

解码器也是一次做一步。

来自编码器块的 上下文向量 被提供作为解码器的第一个 LSTM 块的隐藏状态(hs)和单元状态(cs)。

句首“SOS”令牌被传递到嵌入 NN,然后传递到解码器的第一个 LSTM 单元,最后,它通过一个线性层【显示为粉红色】,该层提供一个输出英语令牌预测概率( 4556 个概率)【4556—如在英语语言的总词汇量中】、隐藏状态(hs)、单元状态(cs)。

从 4556 个值中选择具有最高概率的输出字,隐藏状态(hs)和单元状态(cs)作为输入被传递到下一个 LSTM 单元,并且这个过程被执行,直到它到达句子“EOS”的 结尾。

后续层将使用先前时间步长的隐藏和单元状态。

示教力比率:

除了其他模块,您还可以在 Seq2Seq 架构的解码器中看到如下所示的模块。

在模型训练时,我们发送输入(德语序列)和目标(英语序列)。从编码器获得 上下文向量 后,我们将它们向量和目标发送给解码器进行翻译。

但是在模型推断期间,目标是基于训练数据的概括从解码器生成的。因此输出预测字作为下一个输入字被发送到解码器,直到获得令牌。

所以在模型训练本身中,我们可以使用教导力比(tfr) ,在这里我们可以实际控制输入单词到解码器的流动。****

讲授力比法

  1. 我们可以在训练的时候把实际的目标词发送到解码器部分(以绿色显示)。
  2. 我们还可以发送预测的目标词,作为解码器的输入(以红色显示)。

发送单词(实际目标单词或预测目标单词)中的任何一个都可以用 50%的概率来调节,所以在任何时间步长,训练时都是通过其中一个。

这种方法的作用类似于正则化。以便模型在此过程中高效快速地训练。

上述可视化适用于一批句子中的单个句子。假设我们的批处理大小为 4(实验性的),那么我们一次向编码器传递 4 个句子,编码器提供 4 组 上下文向量,它们都被传递给解码器,如下图所示。

批量大小为 4 的 LSTM 解码器。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者

7.解码器代码实现(Seq2Seq)

8.Seq2Seq(编码器+解码器)接口

单个输入句子的最终 seq2seq 实现如下图所示。

  1. 提供输入(德语)和输出(英语)句子。
  2. 将输入序列传递给编码器,并提取 上下文向量。
  3. 将输出序列传递给解码器,来自编码器的上下文向量产生预测的输出序列。**

单句 Seq2Seq 数据流图。来源—作者

上述可视化适用于一批句子中的单个句子。假设我们的批处理大小为 4(实验性的),那么我们一次传递 4 个句子给编码器,编码器提供 4 组 上下文向量,它们都被传递给解码器,如下图所示。

批量大小为 4 的 Seq2Seq。来源—作者

9.Seq2Seq(编码器+解码器)代码实现

10.Seq2Seq 模型训练

例句的训练进度:

培训损失:

培训流失呈现良好趋势。

11.Seq2Seq 模型推断

现在让我们比较我们的训练模型和 SOTA 谷歌翻译。

模型推理样本

不错,但是很明显这个模型不能理解复杂的句子。因此,在接下来的一系列帖子中,我将通过改变模型的架构来增强上述模型的性能,如使用双向 LSTM,添加注意力机制,或者用变形金刚模型替换 LSTM 来克服这些明显的缺点。

12.资源和参考

我希望我能够对 Seq2Seq 模型如何处理数据提供一些直观的理解,请在评论部分告诉我您的想法。

查看包含全部代码实现的笔记本,并随意破解它。

完整的代码实现可从以下网址获得:

@GitHub

****** [## 巴拉语代码/自然语言处理

github.com](https://github.com/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural Machine Translation/1. Seq2Seq [Enc %2B Dec] Model for Neural Machine Translation (Without Attention Mechanism).ipynb)

@Colab

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/github/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural Machine Translation/1. Seq2Seq [Enc %2B Dec] Model for Neural Machine Translation (Without Attention Mechanism).ipynb)

@

* [## 神经机器翻译的 Seq2Seq 模型

使用 Kaggle 笔记本探索和运行机器学习代码|使用来自非数据源的数据

www.kaggle.com](https://www.kaggle.com/balakrishcodes/seq2seq-model-for-neural-machine-translation#12.-Seq2Seq-Model-Inference)*

对于那些好奇的人来说,本文中的可视化是由Figma&Google Drawing实现的。**

完成可视化文件Figma 上创建(。图)【LSTM,编码器+解码器,SEQ2SEQ】可用@ Github。

** [## 巴拉语代码/自然语言处理

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural Machine Translation/Visualizations_Figma_Files/FIGURES OF LSTM%2C ENCODER%2C DECODER%2C SEQ2SEQ.fig)**

参考资料: LSTM文字 _ 嵌入深度 _ 学习 _ 模型 _ 部署 _ON_AWS

在那之前,下次见。

文章作者:

BALAKRISHNAKUMAR V******

开始构建物联网产品的全面指南

原文:https://towardsdatascience.com/a-comprehensive-guide-to-start-building-an-iot-product-ba32dfb91c7a?source=collection_archive---------7-----------------------

罗宾·格劳泽在 Unsplash 上的照片

当我开始开发我的第一个物联网项目时,我希望我有这样的指南

什么是物联网?

我们举个简单的例子。你的手机。在它连接到互联网之前,它是哑的,真的是哑的。它只能播放你放在里面的歌曲。它只能给你有联系号码的人打电话。

然后神奇的事情发生了。我们把它连上了互联网

现在它可以播放任何歌曲。你不仅仅局限于一个联系号码来联系某人。您可以访问手中放不下数 TB 数据存储的信息。这就是连接互联网的力量。

互联网和智能手机,电脑确实是强大的工具,但智能手机不会给你的植物浇水,它不会打开你的门。这些设备的体能非常有限。

物联网旨在将互联网的力量从计算机和智能手机扩展到一系列其他事物、流程和环境。

我们如何做到这一点?我们如何将力量延伸到互联网?

通过在你周围的世界中放置能与物理世界互动和感知的组件,并将它们连接到互联网。这些组件是传感器和致动器的组合。

什么是传感器?

简单来说,传感器测量的是一种物理属性。像温度传感器测量温度。

什么是执行器?

你可以把执行器理解为传感器的对立面。就像传感器将外部变化转化为信号一样,执行器将信号转化为行动。就像打开门锁一样。

当然,对于这些传感器和致动器,您需要一些额外的硬件来控制它们,如果需要,还可以传输信息。

物联网改变世界

物联网使您能够比以往更密切地监控联网设备并对其采取行动。无论是管理机器的行业、检查庄稼的农民、管理边境的政府,还是监控空气或水质的管理部门,都不需要每周手动检查一次或两次。

一切都是实时发生的!

想想当你没有牛奶时会提醒你的智能冰箱,或者当它们干了时会提醒你浇水的智能植物,这些可能性只限于你的想象。

我们已经看到物联网带来了如此巨大的变化

  • 自动驾驶汽车
  • 智能家居和工业安全
  • 家庭自动化
  • 健身追踪器、智能手表和可穿戴设备
  • 自主高效农业

理解并想象一个物联网世界会是什么样子非常重要。这里有两个非常好的 Ted 演讲,可以帮助你想象物联网的未来世界

物联网:TEDxCIT 的约翰·贝瑞塔博士

物联网设计| Rodolphe el-Khoury | TEDxToronto

物联网项目的架构

物联网项目的架构

物联网项目有三个主要组成部分

  • 物联网硬件设备:与环境交互的物理设备
  • 连接:你的设备和云之间的链接
  • 产品云:服务器获取数据,处理数据,存储在数据库中,发出命令,执行分析,以一种有用的方式向所有不同的参与者提供数据

您可能熟悉连接和云,因为它与任何网站和应用程序都一样。但在这里,您还将管理设备的硬件,这带来了额外的复杂性。

物联网硬件设备

这是物联网产品中最复杂、最独特的部分。您可能希望根据自己的需要创建一个特定于设备的。

对于智能灌溉系统,您必须添加传感器来检测湿度水平并与泵进行交互,但对于家庭安全系统,您需要传感器来检测运动或摄像头,并对入侵者进行处理,然后发出警报或通知。

人们需要选择或定制硬件组件来服务于特定的使用情形以及将在该硬件上运行的软件。

产品硬件

硬件将有一个负责逻辑执行的中央处理器/控制器,以及收集数据并根据命令行动的传感器和致动器。

将这个中央处理器/控制器视为负责所有逻辑的大脑,皮肤、眼睛、手、腿作为传感器和致动器,感知并向大脑报告,大脑发出命令,然后在此基础上执行一些操作。

基于这个中央单元,有基于微控制器的物联网板和基于微处理器的板。

基于微控制器的

  • Arduino Uno,Mega :易于开发,大量引脚可连接外设,非常适合原型开发
  • ESP8266 / ESP32 板:具有 WiFi 和蓝牙连接,低成本(ESP8266 成本约为 3 美元),大量开发资源
  • STM32F 系列板:开发复杂,生产友好,易于制造,在生产中应用最广泛

基于微处理器:

  • 树莓派:很棒的社区,容易开发,可以运行像 Linux,windows 这样的 OS
  • 小猎犬骨:开源板,可以放 android、ubuntu 等 Linux,内置 flash 存储

raspberry pi model b、raspberry pi zero 和 Arduino Uno |照片由哈里森·布罗德本特Unsplash 上拍摄

在这些板上,你会看到一个微控制器和微处理器(中间的大黑芯片)。此外,还有许多标有数字的别针。这些引脚是 IO 引脚,用于连接您想要使用的任何传感器或执行器。此外,如果您需要使用多个微控制器/微处理器,也可以设置它们之间的通信。

因此,只需选择适合您要求的电路板,使用这些 IO 引脚,您就可以随心所欲地使用任何传感器。你选择的任何传感器都可能与所有的电路板兼容。

传感器和致动器的一些例子是:

  • 温度和湿度传感器
  • 压力传感器
  • 接近传感器
  • 气敏元件
  • 烟雾传感器
  • 酒精传感器
  • 超声波传感器
  • 继电器:以电子方式闭合和断开电路(开关)
  • 发动机

所以,假设你想建立一个火灾响应系统,你可以选择任何物联网板(Arduino,ESP8266),连接烟雾传感器和洒水器的继电器开关。每当烟雾传感器探测到烟雾时,发出继电器命令启动喷水器。

当然你需要把这个逻辑写在某个地方。这就是产品软件出现的原因。

产品软件

由于代码需要专门针对微控制器或微处理器进行编译,并且由于缺少像 Linux、Windows 这样的操作系统(它抽象了硬件变量),用于开发的软件和工具在很大程度上取决于您选择的芯片。尽管有多种框架试图支持大量芯片。

你需要检查的东西

  • Arduino 框架:支持多种板卡和芯片,如所有 Arduino、ESP8266、ESP32、STM32 芯片
  • FreeRTOS :非常流行的微控制器操作系统,轻量级,支持多种芯片
  • Amazon FreeRTOS :亚马逊版本的免费 RTOS,无缝连接到 AWS 物联网云,并支持许多其他功能,如空中更新、供应
  • Apache Mynewt :专注于基于无线的物联网产品开发

此外,您选择的芯片制造商可能也有一些开发工具,如 STM 提供自己的开发工具,也可以在其芯片上进行开发。一定要检查一下。

如果您使用的是功能更强大的物联网主板,如 raspberry pi,它可以运行 Linux、Windows 等成熟的操作系统,那么当然可以归结为开发 Linux 或 Windows 应用程序。尽管你仍然需要做一些硬件交互来从传感器获取数据。

连通性

连接技术的选择取决于产品所处的环境。例如,大多数家庭物联网将使用 wifi,因为每个家庭都可以使用 WiFi,但如果您在城市中建立空气质量测量仪,WiFi 可能不可用,您可能会决定使用 GSM/GPRS。

现在,对于农业来说,你有数百个传感器分布在大片土地上,你会希望使用一些无线电通信到中央控制中心,然后在需要时将所有数据传输到互联网。

所以通信技术是基于用例来选择的。一些通信技术是:

  • WiFi :适用于家庭和办公室物联网设备等室内设施
  • RFID/NFC :最常见的使用案例是基于卡的访问控制
  • GSM/GPRS :用于户外独立设备
  • 蓝牙:可穿戴设备和可使用智能手机控制的设备的最常见选择,也用于 wifi 配置(为设备配置 wifi 凭证),还可以为多个设备创建蓝牙网格
  • LoRaWAN :适用于 3-5 公里范围通信的工业和公共基础设施产品,专为物联网设备设计,可在大范围内创建网关网络
  • NB-IoT :窄带物联网是一种蜂窝通信技术,专为物联网通信设计,功耗极低

接下来是通信协议,将用于设备和云之间的通信。

消息通信协议

  • HTTP :最容易获取,有很多开销,不同步,非常适合单个请求,不连续通信
  • HTTP WebSockets :基于 HTTP 因此开销很大,但是支持连续通信
  • MQTT :最常用的物联网协议(亚马逊 FreeRTOS 等大多数解决方案默认使用这个),基于发布/订阅模型,非常轻量级,没有不必要的占用空间,非常灵活
  • AMQP :开源,面向消息,排队,路由,支持点对点和发布订阅模式

产品云

云是所有处理、分析和数据库驻留的地方。当云从数以千计的设备接收原始数据时,它需要转换数据、应用业务逻辑、以有利于检索的方式存储数据,并为物联网产品的应用提供动力。它还应该维护所有现场设备的状态和健康。推送空中更新以了解任何所需的更改,并跟踪哪些设备被更新,哪些设备被保留。

云还负责应用程序(应用程序和网站)与设备之间的交互。如果应用程序给出任何任务或命令,云负责将这些命令/任务发送到设备,并且还应该跟踪命令是否被成功执行。

要设计云架构,应该考虑这些因素

  • 将消息接收层与处理层分开,以避免任何消息节流
  • 始终考虑设备离线和故障
  • 为空中更新做好准备(需求中总会有错误和变化)
  • 所有通信都应该是安全的
  • 设置一个认证系统,以便一旦设备不能发布另一个设备的消息,也不能订阅不允许它的频道
  • 保持云中每个设备的当前状态
  • 因为数据的大小很快就会变得巨大,所以选择一个伸缩性好的数据库

有许多云解决方案可供使用:

  • 微软 Azure 物联网套件
  • 谷歌云的物联网平台
  • AWS 物联网平台:与亚马逊 FreeRTOS 集成良好
  • 沃森物联网平台

使用云将非常有益,因为它将防止许多设计错误,并且是在牢记最佳实践的基础上构建的。

你将被来自设备硬件、传感器、软件和通信的选择轰炸。你可以选择你想要的和你需要的。刚开始可能会有些不知所措,但是真的很有趣。

Seaborn 数据可视化综合介绍:分布图

原文:https://towardsdatascience.com/a-comprehensive-intro-to-data-visualization-with-seaborn-distribution-plots-888ff3436f36?source=collection_archive---------27-----------------------

基于 Python 的新冠肺炎疫情数据可视化

欢迎大家来到海波恩。在接下来的系列文章中,我将介绍 Seaborn 库的核心概念、它的优点以及如何和何时使用它。

粘土银行Unsplash 拍摄的照片

整个系列基于来自世界各地的不同冠状病毒数据集。我们将探索时间序列数据、人口统计数据、Corona 对不同行业的经济影响等等!所有数据集都是公开的。我们将一个接一个地探索它们,并熟悉如何探索个体变量之间关系的不同方法。

海生的

Python 中的库非常丰富,它们经常相互重叠。那么我们现在在哪里?Seaborn 构建在 Matplotlib 之上,它们在可视化地探索数据时可以很好地合作。该软件包以统计图形为导向,提供许多从置信区间或核密度估计开始的功能,称为 KDE。我们将在后面解释这些术语。除此之外,Seaborn 与熊猫合作得很好,它的数据帧结构。

我们可以说 Seaborn 是 Matplotlib 的统计扩展。该库提供了许多功能,旨在帮助您更好地理解您的数据。该图书馆将可视化和数据探索置于数据分析的中心。使该软件包与众不同的一点是,它提供了广泛的图表来分析多个变量之间的关系。Seaborn 还可以很好地处理分类变量,并显示聚合统计数据和计数图。
其他很酷的特性是二元图和多点网格。这些都是很好的工具,使您能够理解表格数据中看不到的潜在关系。您可以立即看到多个变量之间的相关性。
值得一提的还有分析数据集的样式和整体外观。各种不同的背景样式、调色板和其他自定义功能将增强您的受众对数据的理解。为了让你的见解更有影响力,你需要准确恰当地传达你的发现。Seaborn 有实用的工具来支持你。

海牛和熊猫

Seaborn 的设计可以很好地处理熊猫数据帧。值得一提的是,熊猫的数据集必须组织有序。在一个整洁的数据集中,每一行代表一个观察值,每一列都是可变的,通常称为要素。如果我们希望库正常运行,对数据的第一印象和理解是至关重要的。要确定数据集是否整洁,请尝试使用。头()和。tail()方法。

Seaborn 对 Matplotlib

如果你在 python 代码中见过缩写 SNS,它指的就是 Seaborn。导入它和导入任何其他 python 库一样简单。与 seaborn 一起,我们还需要导入 Matplotlib lib Pyplot 来利用两者的协同作用。尽管大部分工作可能由 seaborn 完成,但 Matplotlib 增加了一些功能:

导入库:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

加载数据

主要数据源可从 Kaggle 获得:

[## 新型冠状病毒 2019 数据集

新冠肺炎受影响病例的日水平信息

www.kaggle.com](https://www.kaggle.com/sudalairajkumar/novel-corona-virus-2019-dataset)

我们将从“COVID19_open_line_list.csv”开始,它包含冠状病毒个案的全球信息:

#loading the data
df = pd.read_csv("novel-corona-virus-2019-dataset 2/COVID19_open_line_list.csv")

让我们看看数据集是什么样子的:

#checking the structure
df.head()

输出:

#checking the shape
df.shape

输出:

(14126, 45)

让我们看看这些列:

#checking the columns
df.columns

输出:

Index(['ID', 'age', 'sex', 'city', 'province', 'country',
       'wuhan(0)_not_wuhan(1)', 'latitude', 'longitude',     'geo_resolution',
       'date_onset_symptoms', 'date_admission_hospital', 'date_confirmation',
       'symptoms', 'lives_in_Wuhan', 'travel_history_dates',
       'travel_history_location', 'reported_market_exposure',
       'additional_information', 'chronic_disease_binary', 'chronic_disease',
       'source', 'sequence_available', 'outcome', 'date_death_or_discharge',
       'notes_for_discussion', 'location', 'admin3', 'admin2', 'admin1',
       'country_new', 'admin_id', 'data_moderator_initials', 'Unnamed: 33',
       'Unnamed: 34', 'Unnamed: 35', 'Unnamed: 36', 'Unnamed: 37',
       'Unnamed: 38', 'Unnamed: 39', 'Unnamed: 40', 'Unnamed: 41',
       'Unnamed: 42', 'Unnamed: 43', 'Unnamed: 44'],
      dtype='object')

Dataframe 包含 45 列,具有许多不同的格式和数据类型。它以时间序列分析为导向,逐例描述冠状病毒。除了那些我们不确定它们代表什么的变量,我们也有明确的变量,我们在分析中探索这些变量。

重要的是,seaborn 的数据集必须整洁。因此,我们执行基本的数据转换:删除年龄的 nan 值,我们将绘制这些值,并删除范围和所有非数字值:

#keeping only numeric, not nan values and casting to integer type
df_age = df[df['age'].notna()]
df_age = df_age[df_age['age'].str.isnumeric()]
df_age['age'] = df_age['age'].astype(str).astype(int)

让我们从绘图开始:

有 Seaborn 的分布图

分析数据集时,您将一次从一个变量开始。查看数据的分布是单变量分析的一部分。为此,有分布图、散点图或直方图。

让我们绘制我们的第一个分布图,或者像在 Seaborn 中那样称为 distplot(年龄):

sns.distplot(df_age['age'])
plt.show()

输出:

为了比较 Seaborn 和 Matplotlib,让我们绘制相同的图形:

#plot the same histogram with matplotlib
df_age['age'].plot.hist()#show the plot
plt.show()

输出:

乍一看,我们可以看出 Seaborn 和 Matplolib 之间的区别。颜色是柔和的;我们在 Seaborn 中标记了 x 轴和更多有机定义的箱。除此之外,请看一条描述我们的分布的线,叫做核密度估计(KDE):

在统计学中,核密度估计 ( KDE )是一种估计随机变量概率密度函数的非参数方法。核密度估计是一个基本的数据平滑问题,其中基于有限的数据样本做出关于总体的推断。

来源:https://en.wikipedia.org/wiki/Kernel_density_estimation

基于可视化,我们可以说大多数确诊病例在 35-55 岁之间。

在 Seaborn 中,您可以随时添加一些自定义内容:

  • 设置样式
  • 移除 KDE 图,因为 kde=False
  • 或者改变颜色
#set sns style as sns.set()
sns.set()#create distplot without kde:
sns.distplot(df_age[‘age’], kde=False, color = 'y')#show the plot()
plt.show()

输出:

…或者将参数‘vertical’= True,使绘图垂直

#create vertical ditplot
sns.distplot(df_age['age'], kde = False, vertical=True, color="y")#show the plot()
plt.show()

输出:

如果你想从不同的角度看分布,Seaborn 还提供了一个 rub plot,它画出小垂直线来代表每个观察值。

#create ditplot with rugplot and 
sns.distplot(df_age['age'], rug=True, color="g")#show the plot()
plt.show()

一旦你完成了单变量分析,下一步就是理解两个或更多变量之间的关系。

理解两个变量之间分布的最常见图表是:

  • 线形图
  • 散点图
  • 或配对图

在下一个练习中,我们将使用与已确诊、已康复和已死亡病例总数相关的数据集。同样来自 Kaggle- 'covid_19_data.csv '。

经过一些数据转换步骤后,我们得到了以下数据框架:

df_cases_a.head()

这些要素代表一个国家、一个大洲、观察日期、确诊病例、死亡病例和恢复病例。除了观察日之外,我们还对数据集进行了转换,以获得首例确诊病例的起始日。

如前所述,还有更多绘制图表的方法—在大多数情况下,您将使用。relplot()

该函数提供了对几个不同的轴级函数的访问,这些轴级函数通过子集的语义映射来显示两个变量之间的关系。kind参数选择要使用的底层轴级函数:

  • **scatterplot()**(同kind="scatter";默认)
  • **lineplot()**(与kind="line"

线形图

让我们从折线图开始—折线图以直线连接的点的形式显示信息。折线图通常用于时间序列可视化或显示连续变量的趋势。让我们在这里画一个:

#create lineplot of ’day_since_first_confirmed’ and ’Confirmed’sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a)

输出:

我们在这里看到的是一条线,它连接了自全球范围内第一个患者被诊断患有新冠肺炎以来每天确诊的病例数。阴影区域是每次观察汇总数据时绘制的置信区间的大小。默认情况下,它是平均值,但可能会被标准偏差代替,设置 estimator=' std ':

#change estimator parameter to std
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, estimator = ‘std’)#show the plot
plt.show()

我们可以看到绝对值发生了变化,因为后台的计算发生了变化。我们将在下一个统计学系列中讨论标准差。

通常情况下,您希望在可视化中看到更多的值。您可以始终以颜色、标记和其他参数的形式添加尺寸:

#set hue=‘continent’ parameter and set ci=None
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, hue=’continent’, ci = None)#show the plot()
plt.show()

输出:

#set hue=‘continent’ parameter and set ci=None
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, hue=’continent’, ci = None)#show the plot()
plt.show()

我们看到的是,大多数确诊病例发生在北美,远远领先于任何其他大陆。

如果您想自定义您的绘图,您可以随时添加标记:

#set marker='o'.
sns.relplot(x='day_since_first_confirmed', y='Confirmed',kind = 'line', data=df_cases_a, hue='continent', marker='o', ci = None)#show the plot
plt.show()

输出:

为了更好地在图表中导航,在适当的位置放置标记通常是有用的。在这种情况下,由于极值,图表中的可见性和方向很麻烦。为了避免这种情况,我们可以使用对数函数,并为大陆的每个值添加不同的标记。设置 marker=True,style = ' continental'。

#add log_value of confirmed cases for all 3 variables
df_cases_a['log_value_confirmed'] = np.log(df_cases_a['Confirmed'])
df_cases_a['log_value_deaths'] = np.log(df_cases_a['Deaths'])
df_cases_a['log_value_recovered'] = np.log(df_cases_a['Recovered'])#set parameter markers to True and style='continent'
sns.relplot(x='day_since_first_confirmed', y='log_value_confirmed',kind = 'line', data=df_cases_a, hue='continent', style = 'continent', ci = None, markers = True)#show the plot
plt.show()

输出:

每个洲变量的值都得到了它的标记,以及确诊病例的规模,现在彼此之间是可比较的。当我们有强烈的偏斜分布时,应用对数变换。它有助于预测建模,以找到模式或使数据更好地解释。

散点图

让我们来看看两个变量之间的关系。比较两个变量及其分布的简便方法是用散点图。每个点代表一个观察。我们将看看 50 个国家中确诊、死亡和康复病例的最高值。要显示散点图,请设置 kind=' scatter ':

#plot a scatterplot with 'Confirmed' on x and 'Deaths' on y-axis
sns.relplot(x = 'Confirmed', y= 'Deaths', kind='scatter', data=df_cases_scatter)#show the plot()
plt.show()

散点图的解释相当简单。我们可以对死亡和确诊病例之间的关系做出假设。我们可以肯定地说,确诊病例越多,死亡就越多。我们将再次应用对数变换,因为我们仍然有偏斜的数据,并且大多数情况在左下角。

除了对数变换,我们再来增加维度。使用“col”参数,您可以单独显示变量的值。让我们将 col = ' continental '和 col_wrap=3 设置为每行只有三个图:

#plot a scatterplot with 'Confirmed' on x and 'Deaths' on y-axis
sns.relplot(x = 'log_value_confirmed', y= 'log_value_deaths', kind='scatter', 
            data=df_cases_scatter, col='continent', col_wrap=3)
#show the plot()
plt.show()

输出:

在分析中包含维度可以帮助您获得对数据的全面理解。我们可以假设为什么大洋洲的数字如此之低,为什么美国和欧洲受到如此严重的影响,等等。

通过设置 hue = ' continental ',size='log_value_recovered '或设置 markers=True 和 style = ' continental ',可以获得简化但信息更丰富的图,同时具有更多维度:

#assign 'continent' to hue and log_value_recovered to size
sns.relplot(x = 'log_value_confirmed', y= 'log_value_deaths', kind='scatter', 
            data=df_cases_scatter, hue ='continent', size = 'log_value_recovered')#show the plot
plt.show()

输出:

此外,设置标记=真,样式=“大陆”和 alpha=0.8 (80%)以获得更好的可解释性:

对群体观察应用不同的颜色或标记来提供更详细的信息是很常见的。我们还可以根据具体值给出每个点的大小,并创建一个气泡图。

联合地块

Seaborn library 还提供了下一级分布图——联合图。联合阴谋。Seaborn 的联合图显示了两个变量之间的关系以及它们的共同分布和个别分布。要创建一次,只需使用。接合图():

#jointplot of log_value_confirmed and log_value_deaths
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,
data=df_cases_scatter)#show the plot
plt.show()

默认情况下,联合图显示为散点图,分布为 log_value_confirmed 和 log_value_deaths。当你想在一个图表中检查单个分布和所有分布时,这是很方便的。

有几种不同的联合绘图图表样式,如:

  • reg 图
  • 十六进制图
  • KDE 图
#jointplot of log_value_confirmed and log_value_deaths, regression
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’reg’, color=’y’)#show the plot
plt.show()

#jointplot of log_value_confirmed and log_value_deaths, hex
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’hex’, color=’b’)#show the plot
plt.show()

#jointplot of log_value_confirmed and log_value_deaths, kde
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’kde’, color=’g’)#show the plot
plt.show()

密度图是直方图的升级版。如果您有相当多的观察值,并且散点图绘制过多,建议使用密度图,它在较小的区域内计算观察值的数量。该区域通常由六边形、正方形等形状定义。另一种更先进的方法是绘制 KDE 并显示其轮廓。

我们已经介绍了如何可视化变量分布的大多数方法。对于一些具体的案例,我们将在下一篇文章中详细讨论,比如回归图。

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

在 LinkedIn 上关注我

[## Filip Dzuroska —数据科学家—第一集团 IT | LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Filip Dzuroska 的个人资料。菲利普有一份工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/filipdzuroska/)

还有推特:

[## 菲利普·朱罗斯卡

菲利普·祖罗斯卡(@菲利普·祖罗斯卡)的最新推文。数据科学家,加州大学洛杉矶分校机器方面的研究生研究员…

twitter.co](https://twitter.com/filipdzuroska)

来源:

[## seaborn:统计数据可视化— seaborn 0.10.0 文档

Seaborn 是一个基于 matplotlib 的 Python 数据可视化库。它为绘图提供了一个高级接口…

seaborn.pydata.org](https://seaborn.pydata.org/index.html) [## 新型冠状病毒 2019 数据集

新冠肺炎受影响病例的日水平信息

www.kaggle.com](https://www.kaggle.com/sudalairajkumar/novel-corona-virus-2019-dataset) [## Python 图表库

欢迎来到 Python 图表库。该网站展示了数百张图表,始终提供可复制的 python…

python-graph-gallery.com](http://python-graph-gallery.com/)

神经网络综合介绍

原文:https://towardsdatascience.com/a-comprehensive-introduction-to-neural-networks-291ce078442f?source=collection_archive---------35-----------------------

从零到工作实现

在 Flickr 上由迈克·麦肯齐拍摄的图片

人工神经网络,我们文章的主题,是受生物神经网络启发并试图模仿它们的数学模型。由于生物神经网络是针对特定任务的更多神经元的组合,因此人工神经网络是通常称为人工神经元或感知器的更多线性模型的组合。如果你想了解更多关于感知器,这是最简单的神经网络,你可以在这里阅读更多关于它的

神经网络通常直观地表示为类似图形的结构,如下所示:

图片由 Glosser.ca / CC BY-SA 在维基共享

上面是一个有 3 层的神经网络:输入层、隐藏层和输出层,由 3、4 和 2 个神经元组成。
输入图层的结点数量与数据集的要素数量相同。对于隐藏层,你可以自由选择你想要多少个节点,你可以使用多个隐藏层。那些具有一个以上隐藏层的网络被称为深度神经网络,并且是深度学习领域的主要特征。只有一个隐藏层的网络通常被称为浅层神经网络。输出层的神经元数量应该与您想要预测的变量数量一样多。

还有更多种类的神经网络:卷积、递归、脉冲神经网络等等。但这里我们将只讨论简单的前馈神经网络或多层感知器。

神经网络可用于广泛的问题,包括分类和回归任务。为简单起见,在本文的大部分内容中,我们将只关注分类任务,正如我们将在后面看到的,我们通过本文了解到的关于神经网络的东西可以很容易地转化为回归问题。

除了输入层中的神经元之外,网络中的每个神经元都可以被认为是一个线性分类器,它将前一层中神经元的所有输出作为输入,并计算这些输出加上一个偏差项的加权和。然后,下一层中的神经元将把前一层线性分类器计算的值作为输入,然后计算这些值的加权和,等等。我们的希望是,通过以这种方式组合线性分类器,我们能够构建更复杂的分类器,可以表示我们数据中的非线性模式。

让我们看看下面的例子:

这个数据集显然不是线性可分的,我们不能用一条线将一个类与另一个类分开。但是我们可以通过使用 2 条线作为判定边界来进行这种分离。

因此,我们可能认为两个中间神经元可以完成这项工作。这两个神经元将学习上图中的两条分隔线。然后,我们将需要一个输出神经元,它将把这两个先前的神经元作为输入,然后它将能够正确地进行分类。

为了使最后一个神经元正确分类,如果我们将 n1 和 n2 个隐藏神经元绘制在 2d 平面上,则它们的输出需要是线性可分的。上面绘制的 2 条线具有以下等式:

这意味着 2 个隐藏神经元正在计算输入 x1 和 x2 的以下线性组合:

让我们现在画出 n1 和 n2,看看它们是否帮助了我们。

我们对我们小小的神经网络感到失望。n1 和 n2 的输出仍然不是线性可分的,因此输出神经元不能正确分类。
那么,问题出在哪里?事情是,任何线性函数的线性组合仍然是线性的,并不难在一张纸上说服自己这是正确的。因此,无论我们使用多少层或多少个神经元,到目前为止,我们的神经网络仍然只是一个线性分类器。我们需要更多的东西。我们需要将每个神经元计算出的加权和传递给一个非线性函数,然后将这个函数的输出视为该神经元的输出。这些函数被称为激活函数,正如你在我们的例子中看到的,它们对于神经网络学习数据中的复杂模式非常重要。已经证明[1]具有 2 层(除了输入层)和非线性激活函数的神经网络能够逼近任何函数,只要它在那些层中具有足够大数量的神经元。那么,如果只有两层就足够了,为什么现在人们使用更深的网络呢?嗯,仅仅因为这些 2 层网络“能够”学习任何东西,并不意味着它们很容易优化。实际上,如果我们让我们的网络产能过剩,他们会给我们足够好的解决方案,即使他们没有优化到他们能做到的程度。

还有更多种类的激活函数,其中两种我们想在上面的例子中使用。它们是 ReLU(RectivedLlinearUnit)和 tanh(双曲正切),如下所示。

思考神经网络的另一种方式是,它们试图同时学习分类和特征表示。如果你读过我的关于感知器的文章,你会在文章的最后看到我们如何通过向输入向量添加非线性特征,使用线性分类器来解决非线性分类问题。但是,为了获得好的结果,您如何总是知道将哪些额外的特性添加到输入向量中呢?神经网络试图通过学习什么样的特征表示是好的来解决这个问题。在隐藏层中,神经网络实际上学习输入数据的最佳表示,以便在进行实际分类的最后一层中表现良好。

现在,让我们继续我们的例子。如果我们在例子中使用 ReLU 激活,会发生什么?下面绘制了施加 ReLU 激活后神经元 n1 和 n2 的输出。

现在我们的两类点可以由一条线分开,因此输出神经元可以正确地对它们进行分类。

如果我们使用 tanh 激活,会发生类似的事情,但这次我们的点被更大的余量分开得更好。

同样,输出神经元可以正确分类这些点。

在我看来,神经网络的常见视觉表示,即讨厌的图形结构,可能有点令人困惑。尤其是如果你想实现它,就更难考虑你需要用那些到处浮动的连接和权重来做什么。在参数层次上思考可能很麻烦,但是在网络中进行的向量和矩阵运算的更高层次上思考更清晰,至少对我来说是这样。将神经网络视为函数的组合,向量函数的链,在我所做的实现中帮助了我,我希望它也能帮助你。请看下图:

如果我们将每一层的输入和输出值表示为向量,将权重表示为矩阵,将偏差表示为向量,那么我们将得到上面的神经网络的扁平化视图,它只是一系列向量函数应用。这些函数将向量作为输入,对它们进行一些变换,然后输出其他向量。在上图中,每一行代表一个函数,可以是矩阵乘法加偏置向量,也可以是激活函数。圆圈代表这些函数操作的向量。例如,我们从输入向量开始,然后将它输入第一个函数,该函数计算其分量的线性组合,然后我们获得另一个向量作为输出。我们将最后一个向量作为激活函数的输入,依此类推,直到到达序列中的最后一个函数。最后一个函数的输出将是我们网络的预测值。

这种表示也更接近我们实际要实现的东西。为了实现神经网络,我们实际上不需要存储通常用图像表示的图形。一个神经网络所做的一切就是矩阵运算,既用于预测,也用于训练。

我们已经看到了神经网络如何获得我们感兴趣的输出,它只是通过一系列函数传递其输入向量。但是这些函数依赖于一些参数:权重和偏差。

为了获得好的预测,我们实际上如何学习这些参数?

好吧,让我们回忆一下神经网络实际上是什么:它只是一个函数,一个由按顺序应用的较小函数组成的大函数。这个函数有一组参数,因为一开始我们不知道它们应该是什么,我们只是随机初始化它们。所以,一开始我们的网络只会给我们随机的值。我们如何改进它们?在尝试改进它们之前,我们首先需要一种评估网络性能的方法。如果我们没有一种方法来衡量我们的模型做得有多好或有多差,我们应该如何改进它的性能呢?为此,我们需要设计一个函数,将网络预测和数据集中的真实标签作为参数,并给出一个代表网络性能的数字。那么我们就可以把学习问题变成一个寻找这个函数的最小值或者最大值的优化问题。在机器学习社区中,这个函数通常衡量我们的预测有多糟糕,因此它被命名为损失函数。我们的问题是找到使这个损失函数最小的网络参数。

随机梯度下降

你可能熟悉微积分课上的求函数最小值的问题。在那里,你通常取函数的梯度,将其设为 0,找到所有的解(也称为临界点),然后从中选择一个使你的函数具有最小值的解。这是全球最小值。我们能做同样的事情来最小化我们的损失函数吗?不完全是。问题是神经网络的损失函数不像你通常在微积分教科书中找到的那样好和紧凑。它是一个非常复杂的函数,有几千、几十万甚至几百万个参数。甚至不可能找到这个问题的封闭解。这个问题通常通过迭代方法来解决,这种方法不试图找到一个直接的解决方案,而是从一个随机的解决方案开始,并试图在每次迭代中改进它。最终,在大量的迭代之后,我们会得到一个非常好的解决方案。

一种这样的迭代方法是梯度下降。你们可能知道,函数的梯度给了我们最陡上升的方向,如果我们取梯度的负值,就会给我们最陡下降的方向,也就是我们可以最快到达最小值的方向。因此,在每次迭代中,也称为历元,我们计算损失函数的梯度,并从旧参数中减去它(乘以称为学习速率的因子),以获得我们网络的新参数。

其中θ表示包含所有网络参数的向量。

在标准梯度下降法中,梯度是在考虑整个数据集的情况下计算的。通常这是不希望的,因为它可能在计算上很昂贵。在实践中,数据集被随机划分成更多的块,称为批,并且对这些批中的每一个进行更新。这被称为随机梯度下降

上述更新规则在每一步仅考虑在当前位置评估的梯度。这样,在损失函数表面上移动的点的轨迹对任何扰动都是敏感的。有时,我们可能希望让这个轨迹更加稳健。为此我们使用了一个来自物理学的概念:动量。这个想法是,当我们进行更新时,也要考虑以前的更新,这就累积成一个变量δθ。如果更多的更新是在同一个方向上完成的,那么我们会“更快”地向那个方向前进,不会因为任何微小的扰动而改变我们的轨迹。想象一下速度。

其中α是确定过去梯度贡献的非负因子。当它为 0 时,我们就不用动量了。

反向传播

我们如何计算梯度呢?回想一下,神经网络和损失函数只是函数的组合。我们如何计算复合函数的偏导数?使用链式法则。让我们来看下图:

如果我们想要计算第一层权重的损失 w.r.t. ( 相对于)的偏导数:我们取第一个线性组合 w.r.t .的导数,然后我们乘以下一个函数(激活函数)w.r.t .的导数,再乘以前一个函数的输出,等等,直到我们乘以损失 w.r.t .的导数,最后一个激活函数。如果我们想计算第二层重量的导数呢?我们必须执行相同的过程,但这一次我们从第二个线性组合函数的导数 w.r.t .及其权重开始,之后,当我们计算第一层权重的导数时,我们必须相乘的其余项也存在。因此,我们不会一遍又一遍地计算这些术语,而是将倒推,因此得名反向传播

我们将首先计算损耗对网络输出的导数,然后通过保持导数的连续乘积将这些导数向后传播到第一层。注意,我们有两种导数:一种是计算函数对输入的导数。我们将这些乘以导数的乘积,目的是跟踪网络从输出到算法中当前点的误差。第二种导数是那些我们想要优化的参数。我们不将它们与导数乘积的其余部分相乘,而是将它们存储为梯度的一部分,稍后我们将使用它来更新参数。

因此,在反向传播时,当我们遇到没有可学习参数的函数(如激活函数)时,我们只对第一类函数求导,只是为了反向传播误差。但是,当我们遇到具有可学习参数的函数时(如线性组合,我们有想要学习的权重和偏差),我们对两种类型都进行求导:第一种是误差传播的输入,第二种是权重和偏差,并将它们存储为梯度的一部分。我们从损失函数开始做这个过程,直到我们到达第一层,在那里我们没有任何要添加到梯度的可学习参数。这是反向传播算法。

生产能力过剩

在开始下一步之前,我想谈一点关于神经网络的能力过剩。回想一下我们之前的例子:

如你所见,解决这个分类任务所需的隐藏层中的神经元的最小数量是 2,上面两行中的每一行一个。在神经网络中,增加一些过剩的能力是一个好主意,即增加比解决特定问题所需的最少数量更多的神经元和/或层。这是因为添加更多的参数将使优化问题变得更容易。在上面的例子中,如果我们只使用 2 个隐藏的神经元,我们将需要它们中的每一个学习一条“几乎完美”的线,以便最终的结果是好的。但是,如果我们给我们的网络更多的自由,并在隐藏层中添加更多的神经元,它们就不需要完美。如果它们中的大多数至少对我们的分类任务有用,我们将能够得到好的结果。然后,我们可以认为最后一个神经元平均了每个神经元的决策边界。

思考为什么添加更多参数会使优化任务更容易的另一种方式是想象当我们添加更多参数时损失函数的“表面”会发生什么。在 2d 情况下,只有 2 个方向可以移动我们的(单个)参数,如果在这两个方向上损失函数的高度都比当前点大,那么我们将陷入局部最小值,并且我们可能完全错过全局最小值。现在,让我们想象一下,我们再增加一个参数,这样我们的图就变成了 3d 空间中的一个曲面。在这种情况下,我们有无限多的方向可以选择,并且有更多的机会在所有的方向中找到至少一个方向,使我们向下到达损失面上的一个更低的点。因此,陷入局部最小值的机会更少(至少与 2d 情况相比)。

增加我们网络的参数数量总是更好的?不。参数太多会使我们的网络更容易超载。因此,在使优化问题更容易和保持网络不过度拟合之间有一个权衡。

Softmax 激活和交叉熵损失

分类任务中最后一层常用的激活函数是 softmax 函数。

softmax 函数将其输入向量转换为概率分布。如果你看上面,你可以看到 softmax 的输出向量的元素都是正的,它们的和是 1。当我们使用 softmax 激活时,我们在最后一层创建与数据集中的类数量一样多的节点,softmax 激活将为我们提供可能的类的概率分布。因此,网络的输出将给出输入向量属于每一个可能类别的概率,我们选择具有最高概率的类别,并将其报告为我们网络的预测。

当 softmax 被用作输出层的激活时,我们通常使用交叉熵损失作为损失函数。交叉熵损失衡量两个概率分布的相似程度。我们可以将输入 x 的真实标签表示为概率分布:其中真实类别标签的概率为 1,其他类别标签的概率为 0。这种标签表示也称为一键编码。然后,我们使用交叉熵来衡量我们网络的预测概率分布与真实概率分布的接近程度。

其中 y 是真实标签的独热编码,y hat 是预测的概率分布,yi,yi hat 是那些向量的元素。

如果预测的概率分布接近真实标签的独热编码,那么损失将接近于 0。否则,如果它们非常不同,损失可能会增长到无穷大。

均方误差损失

到目前为止,我们专注于分类任务。但是,通过使用适当的损失函数,神经网络可以很容易地适应回归任务。例如,如果我们有一个想要近似的数字列表,我们可以使用均方误差(简称 MSE)损失来代替类别标签作为基本事实。通常当我们使用 MSE 损失时,我们在最后一层使用身份激活。

用 python 实现这个

现在是时候用 python 实际实现一个神经网络了,然后用几个例子来测试它,看看它的表现如何。

我认为真正理解神经网络如何工作的最好方法是从头开始实现一个神经网络。我向你挑战靠你自己去实现它。当你完成后,回到这里,与我的代码进行比较,做我在本文末尾做的例子,看看你是否得到类似的结果。如果你在某个时候遇到困难,可以来这里看看我是怎么做的。

我将创建一个 NeuralNetwork 类,我希望以这样一种方式设计它,使它更加灵活。我不想在其中硬编码特定的激活或损失函数,或优化器(即 SGD,Adam 或其他基于梯度的方法)。我将把它设计成从类外部接收这些,这样人们就可以获取类的代码,并传递给它他想要的任何激活/丢失/优化器。因此,我将实现激活和丢失函数,以及优化器类,我们希望在这里将它们与 NeuralNetwork 类分开使用。我们需要激活/损失函数及其导数。

为了允许批量大于 1,我们的激活和损失函数应该处理矩阵输入。这些矩阵中的行代表数据样本,列代表特征。我们的网络将允许两种激活功能:隐藏层和输出层。隐藏层激活应该对它们的输入向量进行元素方式的操作,因此它们的导数也将是元素方式的,为每个样本返回一个向量。但是输出激活允许基于输入向量中的所有元素来计算输出向量中的每个元素。这是为了能够使用 softmax 激活。正因为如此,它们的导数需要返回一个雅可比矩阵(一个由每个输出函数对每个输入分量的偏导数组成的矩阵;你可以在这里阅读更多关于每个样品的

这里我们将只使用 ReLU 作为隐藏激活;identity 和 softmax 将用作输出激活。

我们使用 EPS 变量,它是 float64 类型的最小正表示数,以避免被 0 除。为了避免 softmax 函数中的溢出错误,我们从输入中减去了每个样本的最大值。我们被允许这样做,因为它不会改变函数的输出,因为它的效果和分数的两项除以相同的量是一样的。

损失函数应该将两个矩阵作为输入:预测的 y 和真实的 y,它们的形式与激活函数中的相同。这些损失函数应该为每个样本输出一个数字。它们的导数应该为每个样本输出一个行向量,所有样本都堆叠成一个 3 维的数组。为了能够使用 numpy 的matmul()函数乘以输出激活的导数,需要该输出形状。注意下面的expand_dims()函数的使用,该函数用于返回所需的形状。

这里我们将只使用带动量的随机梯度下降作为优化方法,但是还有更多基于梯度的方法。一些流行的选择是:亚当,RMSprop,阿达格拉德。为了让我们的神经网络类能够处理所有这些,我们将把优化器作为一个单独的类来实现,使用一个返回更新参数的.update(old_params, gradient)方法。神经网络类将接收一个优化器作为参数。因此,想使用其他优化方法的人可以创建一个具有所需接口的类,并在实例化时将其传递给我们的神经网络类。

下面是新币+动量优化器:

为了将分类任务中的分类标签转换为一键编码,我们将使用to_categorical()实用函数:

现在,让我们从 NeuralNetwork 类的代码开始。实例化方法需要以下参数:

  • :由每层(包括输入和输出层)的节点数组成的列表
    例如:【5,10,2】表示 5 个输入,10 个隐层节点,2 个输出节点
  • 隐藏 _ 激活:激活隐藏层;一个形式的元组(activation_function,its_derivative)
    这个激活函数和它的导数应该在输入数组
    上按元素执行它们的任务,例如:(relu,d_relu)
  • output_activation :输出层激活;一个形式元组(activation_function,its_derivative)
    这个激活函数将一个形状数组(n,m)作为输入;n 个样本,输出层 m 个神经元;并返回 shape (n,m)数组;输出数组中一行上的每个元素都是输入数组中该行上所有元素的函数输出。
    它的导数将一个类似于激活所采用的数组作为输入,但它返回一个 shape (n,m,m)数组,该数组是一堆雅可比矩阵,每个样本一个。
  • 损失:形式的元组(loss_function,its_derivative)
    损失函数将形状(n,m)的两个数组(预测 y 和真实 y)作为输入;n 个样本,输出层 m 个神经元;并返回 shape (n,1)数组,其元素是每个样本的损失。
    它的导数将 shape (n,m)的数组作为输入,并返回 shape (n,1,m)的一个数组,该数组是由 m 个输入变量的导数 w.r.t .组成的行向量的堆栈。
    例如:(分类 _ 交叉熵,d _ 分类 _ 交叉熵)
  • 优化器:有方法的对象。update(old_params,gradient)返回新的参数
    ,例如:SGD()

然后,它使用 Xavier 初始化方法的变体初始化其权重和偏差。也就是说,我们从均值为 0 且标准差为的正态分布中得出权重和偏差:

其中 fan_in 和 fan_out 分别是前一层中的节点数和下一层中的神经元数。权重矩阵中的行数与前一层中的节点数相匹配,列数与下一层中的节点数相匹配。偏差是行向量,其元素数量与下一层中的节点数量相匹配。

为了方便地执行参数更新过程,我们将创建一个.__flatten_params(weights, biases)方法,将权重矩阵列表和作为输入接收的偏差向量转换为扁平向量。我们还需要一个.__restore_params(params)方法,将参数的扁平向量转换回权重和偏差列表。注意,方法名前面的 2 个下划线仅仅意味着该方法在 OOP 术语中是私有的。这只是意味着该方法应该只在类内部使用。

.__forward(x)方法通过网络传递输入数组 x,在这样做的同时,它跟踪每层的输入和输出数组。然后,它将此作为一个列表返回,其中第 I 个元素是一个形式为[第 I 层的输入,第 I 层的输出]的列表。我们将需要这些数组来计算后向传递中的导数。

.__backward(io_arrays, y_true)方法计算梯度。它将一个由.__forward(x)方法返回的表单列表和一个包含基本事实 y 的数组作为输入。它使用本文前面描述的反向传播算法计算权重和偏差的梯度。然后它返回一个元组(d_weights,d _ biases)。

实际协调所有培训的方法是.fit(x, y, batch_size, epochs, categorical),其中:

  • x 是输入数据
  • y 是基本事实
  • batch_size 是一批数据的大小
  • epochs 是遍历所有输入数据的次数
  • categorical 是一个可选参数,当设置为 true 时,会将 y 转换为一键编码

对于每批数据,它使用.__forward().__backward()方法计算梯度,然后使用.__flatten_params()拉平网络的当前参数和梯度。之后,使用self.optimizer.update()计算新的参数,然后使用__restore_params()将返回的向量恢复为正确的格式,并将其分配给self.weights, self.biases。每批结束时,打印进度和平均损失。维护并返回每个时期结束时所有损失值的列表。

默认情况下,.predict()方法将在输入 x 通过网络后返回输出节点中的精确值。如果 labels 参数设置为 true,则返回预测标签;这大概就是你在一个分类问题中想要的。
.score()方法默认返回平均损失。如果 accuracy 设置为 true,那么将返回精度。请注意,在分类问题中,如果您想要损失,那么 y 应该以一键编码格式提供,否则,如果您想要返回准确性,那么 y 应该只是常规的类标签。

最后,我们希望能够在本地保存参数,这样我们就不必在每次想要进行预测时训练我们的模型。请注意,以下方法只能保存和加载权重和偏差,而不能保存和加载关于层、激活、损失函数和优化器的全部信息。因此,您还应该保存用于实例化神经网络的代码。

以下是完整代码:

例子

下面我们将展示两个例子,其中我们使用了刚刚实现的 NeuralNetwork 类。

第一个例子包括对 MNIST 数据库中的手写数字图像进行分类。该数据集由 60,000 个训练和 10,000 个 28 x 28 像素的测试灰度图像组成。

我们使用 mnist 包(pip install mnist)来加载这个数据集。

然后我们构建一个神经网络,训练 100 个历元。

我们来绘制训练损失图。

让我们看看我们在训练集和测试集上获得的准确性:

并且得到了 99.8% 的训练和 95.9% 的测试精度。这对我们自制的神经网络来说相当不错。

现在我们来看第二个例子,在这个例子中,我们用神经网络来解决一个回归问题。
这次我们将使用 sklearn 软件包附带的加州住房数据集。该数据集由 8 个预测属性的 20640 个样本和目标变量 ln(房屋价值中位数)组成。该数据集来自 1990 年美国人口普查,每个人口普查区块组使用一行。街区组是美国人口普查局发布样本数据的最小地理单位。

这次我们将使用均方误差作为损失函数。

让我们画出训练时的损失。

让我们看看训练集和测试集的最终损失值是多少。

对于训练和测试,我们都损失了大约 0.36 。请注意,目标变量是对数标度。所以,这里对均方误差的解释有点不直观。我们通常说预测值平均相差+/-MSE 的平方根。现在,在我们的情况下,我们的网络预测的中值房屋价值平均偏离 e 的平方根一个因子(而不是+/-我们有乘/除)(在我们的情况下,这个因子大约是 1.83 )。

参考

[1] Cybenko,G.V. (2006 年)。“通过叠加 s 形函数进行近似”。在范舒彭,简 h(编辑。).控制、信号和系统数学。斯普林格国际公司。第 303-314 页。

你可以在 Github 这里找到笔记本和 python 文件。

我希望这些信息对您有用,感谢您的阅读!

这篇文章也贴在我自己的网站这里。随便看看吧!

Tensorflow Extended 的全面 ML 元数据演练

原文:https://towardsdatascience.com/a-comprehensive-ml-metadata-walkthrough-for-tensorflow-extended-953230770867?source=collection_archive---------28-----------------------

它存在的原因以及它在 Beam 管道组件中的使用方式

图片来自https://www.tensorflow.org/tfx/guide/mlmd

ML 元数据(MLMD) 是一个用于记录和检索与 ML 开发人员和数据科学家工作流相关的元数据的库。

TensorFlow Extended (TFX)是一个用于部署生产 ML 管道的端到端平台

在本文发布时,ML 元数据的当前版本是 v0.22(tfx 也是 v 0.22)。该 API 已经足够成熟,可以在公共云上进行主流使用和部署。Tensorflow Extended 将其广泛用于组件-组件通信、沿袭跟踪和其他任务。

我们将运行一个非常简单的管道,该管道将为著名的芝加哥出租车旅行数据集的样本 csv 生成统计数据和模式。这是一个大约 10mb 的小文件,管道可以在本地运行。

生成的工件列表

运行一次,打开metadata_store.db文件进行检查。

ML 元数据生成的表

ML 元数据存储关于 3 事物的信息:

  • 关于生成的工件的元数据
  • 关于这些组件执行的元数据—步骤
  • 关于管道和相关沿袭信息的元数据

Apache Beam Pipeline TFX 组件不会将整个二进制工件(由具有多个 io 的[ParDo](https://beam.apache.org/releases/javadoc/2.1.0/org/apache/beam/sdk/transforms/ParDo.html)处理)传递给下一个节点。相反,URIs 的神器被传来传去。工件通常存储在某种云文件系统上,如云存储桶

甚至 TFRecord tf。示例 保存的文件作为中间阶段工件处理。它们被压缩以节省空间。

> SELECT * FROM Artifact;

被储存的藏物

您可以看到,所有这些生成的工件父目录都被存储了起来,还有一个数字(稍后将详细介绍这个数字)、创建和更新时间。

CsvExampleGen/examples/1的例子中,我们得到了两个子目录,traineval,它们被存储为同一个工件。该路径的 /examples 部分是example_gen产生的工件的名称(查看管道代码),statistics_gen将其作为输入。

空值可能是正在进行的工作,因为商店是 v0.xx 版本。你可以在源代码协议缓冲区声明中看到 n 可以是UNKNOWN — PENDING — LIVE — MARKED_FOR_DELETION — DELETED并且名字很好,这个名字,除了type_id之外。

Types工作台与type_id如预期的一样:

类型

工件也支持属性映射。这些总结在ArtifactProperty表中。(例如,保存的 TFRecord 文件的校验和。它们通过 TFX 缓存中间步骤。)

工件属性图

  • 一个上下文包含多个工件、执行和事件
  • 一个事件包含工件和执行
  • 一个执行通常是一个独立的流水线步骤

对于工件的执行跟踪和沿袭跟踪功能(例如,告诉哪个模型或统计对应于哪个数据集或管道运行),我们必须处理事件、上下文和执行。

  • 事件关联artifact_idsexecution_ids
  • 执行只跟踪type_ids和时间戳
  • 上下文type_ids与管道运行和时间戳信息相关联

执行属性和上下文属性包含键值形式的额外数据。

  • ExecutionProperties 包含传递给每个组件的输入和输出配置,以及管道和步骤根目录,以及工件的 IO 位置。
  • 上下文属性context_ids与管道组件名称和时间戳相关联

对于更大的管道的其他步骤,如模型验证和祝福,产生的工件或多或少采用相同的格式。

访问数据

有大量的信息可用,仅仅是在本地运行的简单的 3 步管道。例如,这个管道可以在云中的Dataflow runner 上运行,只需对配置进行最小的更改。

在这种情况下,使用存储在数据库中的数据要比浏览服务器场上的云存储桶和虚拟机容易得多。

从这一点开始,您可以通过直接 SQL 连接或 gRPC(通过存根或普通的旧调用)连接到 ML 元数据存储。然后,就是选择您想要手动检查的数据类型的问题。例如,这可以是模式或统计 protobuf。

通常,您只需要访问资源的资源标识符。如果您在相同的环境中,您应该能够仅通过 URI 访问它们(例如 GCP 项目 VM 内的笔记本)。

示例使用案例

假设您有一个管道在某个时间间隔(或基于事件的触发)运行,并且有时您想要查看最新管道运行与前一次运行的数据统计。

  • 您需要两个不同管道运行的statistics gen/statistics工件(这些是 ExampleStatistics 类型,带有type_id 8)。这些可以在Artifact的桌子上找到。
  • 您还需要从正确的管道运行中访问工件。Attribution表格将context_idartifact_id相关联。唯一缺少的是精确定位您需要的 2 个context_id,以便进行简单的选择查询。
  • Context表还包含时间戳信息。例如,行Pipeline .2020–07–14T23:45:00.508181.StatisticsGen有一个context_id 5。

上下文 Id 5 对应于属性表中的工件 Id 3。工件 Id 3 确实是我们需要的统计工件。

幸运的是,kubeflow 管道 已经自动做到了这一点

结论

现在,您应该对 ML 元数据存储确切包含的内容以及为什么它是 TFX 生态系统中如此有用的组件有了一个明确的理解。

感谢一路读到最后!

定制工件

支持自定义工件。我们不会在这里深入探讨,因为这主要是针对 TFX 的生态系统。更多信息请看这里。

用于异常检测的深度学习:综述

原文:https://towardsdatascience.com/a-comprehensive-survey-on-deep-learning-for-anomaly-detection-b1989b09ae38?source=collection_archive---------10-----------------------

回顾深层异常检测的挑战、方法和机遇

这篇文章总结了一篇关于深度学习异常检测的综合调查论文——“深度学习异常检测:综述”[1],讨论了该方向的挑战、方法和机遇。

异常检测,也称为异常值检测,几十年来一直是一个活跃的研究领域,因为它在许多关键领域都有广泛的应用,如风险管理、合规性、安全、金融监控、健康和医疗风险以及人工智能安全。尽管这是一个在各个领域广泛研究的问题,包括数据挖掘、机器学习、计算机视觉和统计学,但仍然存在一些独特的问题复杂性和挑战,需要先进的方法。近年来,深度学习支持的异常检测已经成为应对这些挑战的一个重要方向。然而,对这一方向的研究进展缺乏系统的回顾和讨论。我们旨在对这一方向进行全面回顾,讨论主要挑战、大量最新方法、它们如何应对挑战以及未来的机遇。

异常检测中大量未解决的挑战

尽管异常检测是多年来持续活跃的研究领域,但由于异常的一些独特和复杂的性质,仍然存在许多基本上未解决的挑战,例如,未知性(它们在实际发生之前保持未知),异质性(不同的异常表现出完全不同的异常特征),稀有性(异常是很少发生的数据实例),不同形式的异常(点异常、上下文异常和组异常)。

最具挑战性的问题之一是难以实现高异常检测召回率(挑战#1) 。由于异常非常罕见且具有异质性,因此很难识别所有的异常。许多正常情况被错误地报告为异常情况,而真正复杂的异常情况却被遗漏了。

高维和/或非独立数据中的异常检测(挑战#2) 也是一个重大挑战。异常往往在低维空间表现出明显的异常特征,而在高维空间则变得隐蔽而不明显。高维异常检测是一个长期存在的问题。基于子空间/特征选择的方法可能是一种简单的解决方案。然而,识别复杂的(例如,高阶的、非线性的和异质的)特征相互作用和耦合在高维数据中可能是必不可少的,然而仍然是异常检测的主要挑战。

由于收集大规模标记异常数据的难度和成本,对正常/异常进行数据高效学习(挑战#3) 非常重要。两个主要的挑战是如何学习具有少量标记异常数据的表达性正常/异常表示,以及如何学习被推广到由给定标记异常数据发现的新异常的检测模型。

许多弱/半监督异常检测方法假设给定的标记训练数据是干净的,这对于被错误地标记为相反类别标签的有噪声的实例是非常脆弱的。这里的一个主要挑战是如何开发抗噪声异常检测(挑战#4)

现有的方法大多是针对点异常的,不能用于条件异常和组异常,因为它们表现出与点异常完全不同的行为。这里的一个主要挑战是将条件/组异常的概念结合到异常测量/模型中,用于这些复杂异常的检测(挑战#5)

在许多关键领域,如果将异常检测模型直接用作黑盒模型,可能会存在一些重大风险。例如,报告为异常的罕见数据实例可能会导致针对数据中出现的少数群体的算法偏见,例如欺诈检测和犯罪检测系统中代表不足的群体。减轻此类风险的有效方法是使用异常解释(挑战#6) 算法,这些算法提供了关于为什么特定数据实例被识别为异常的直接线索。在某些应用中,提供这样的解释可能与检测精度一样重要。从特定的检测方法中获得异常解释仍然是一个很大程度上未解决的问题,特别是对于复杂的模型。开发内在可解释的异常检测模型也是至关重要的,但在模型的可解释性和有效性之间取得平衡仍然是一个主要挑战。

利用深度异常检测应对挑战

简而言之,深度异常检测旨在通过神经网络学习特征表示或异常分数,以便进行异常检测。近年来,大量深度异常检测方法被引入,在解决各种现实应用中具有挑战性的检测问题时,表现出明显优于常规异常检测的性能。我们系统地回顾了当前的深度异常检测方法及其应对上述挑战的能力。

为了对该领域有一个透彻的了解,我们引入了一个层次分类法,从建模的角度将现有的深度异常检测方法分为三个主要类别和 11 个细粒度类别。图 1 显示了这些方法的分类概述,以及它们所面临的挑战。具体来说,深度异常检测由三个概念范式组成——用于特征提取的深度学习学习常态的特征表示端到端异常分数学习

图一。当前深层异常检测技术的层次分类。还提出了每一类方法可以解决的检测挑战。

用于特征提取的深度学习框架深度学习和异常检测在第一大类中完全分离,因此深度学习技术仅作为一些独立的特征提取器使用。在第二个主要类别中,这两个模块以某种形式相互依赖,即学习常态的特征表征,目的是学习常态的表达表征。这类方法可以根据是否将传统的异常测量纳入其目标函数而进一步分为两个子类。这两个子类别包含七个细粒度的方法类别,每个类别采用不同的方法来制定其目标函数。这两个模块完全统一在第三个主要类别中— 端到端异常分数学习,其中的方法致力于以端到端的方式通过神经网络学习异常分数。这些方法根据神经网络支持的异常评分公式进一步分为四类。

对于每一类方法,我们回顾详细的方法和算法,包括它们的关键直觉、目标函数、基本假设、优点和缺点,并讨论它们如何解决上述挑战。这里很难展示全部细节。有关详细信息,请参阅下面的全文:

ACM 计算调查的正式出版版本:

[## 用于异常检测的深度学习:综述

异常检测,也称为异常检测或新奇检测,已经成为一个持久而活跃的研究领域

dl.acm.org](https://dl.acm.org/doi/abs/10.1145/3439950)

或者,预印本 arXiv 版本:

[## 用于异常检测的深度学习:综述

异常检测,也称为异常检测或新奇检测,已经成为一个持久而活跃的研究领域

arxiv.org](https://arxiv.org/abs/2007.02500)

未来的机会

通过这样的回顾,我们发现了一些令人兴奋的机会。其中一些描述如下。

探索异常监控信号

信息监控信号是深度异常检测的关键,以学习正常/异常或异常分数的表达表示,并减少假阳性。虽然已经探索了各种各样的无监督或自监督监控信号,但是为了学习这些表示,这些公式的关键问题是它们的目标函数是通用的,但是没有专门针对异常检测进行优化。当前依赖于异常度量的特征学习方法通过施加从传统异常度量导出的约束来帮助解决这个问题。然而,这些约束可能具有一些固有的限制,例如,异常测量中的隐含假设。探索异常监控信号的新来源至关重要,这些信号超出了广泛使用的公式,如数据重建和 GANs,并且对异常分布的假设很弱。另一种可能性是通过利用领域知识(如应用程序特定的异常知识和/或专家规则)作为监管来源,开发领域驱动的异常检测

深度弱监督异常检测

深度弱监督异常检测旨在利用深度神经网络,利用一些弱监督异常信号,例如,部分/不准确/不准确标记的异常数据,学习异常通知检测模型。这些标记的数据提供了异常的重要知识,并且可以成为提高检测召回率的主要驱动力。一个令人兴奋的机会是利用少量准确标记的异常示例来增强检测模型,因为它们在现实世界应用中经常可用,例如,来自部署的检测系统/最终用户的一些入侵/欺诈,并由人类专家验证。然而,由于异常可能是高度异构的,可能存在未知/新颖的异常,其位于给定异常示例的跨度集之外。因此,这里的一个重要方向是未知异常检测,我们的目标是建立从有限的标记异常到未知异常的检测模型。

检测属于给定异常示例的相同类别的异常可能与检测新的/未知的异常一样重要。因此,另一个重要的方向是开发数据高效异常检测少量异常检测,其中我们旨在学习已知异常类的高度表达表示,仅给出有限的异常示例。应该注意的是,有限的异常示例可能来自不同的异常类别,因此表现出完全不同的流形/类别特征。这种情况从根本上不同于一般的少量学习,在一般的少量学习中,有限的例子是特定于类的,并假设共享相同的流形/类结构。

大规模常态学习

大规模无监督/自监督表示学习在实现下游学习任务方面获得了巨大的成功。这对于学习任务尤其重要,在学习任务中很难获得足够的标记数据,例如异常检测。目标是在无监督/自监督模式下从大规模未标记数据中学习可转移的预训练表示模型,并在半监督模式下微调检测模型。基于自监督分类的异常检测方法可以为正态学习提供一些初始监督来源。然而,必须采取预防措施以确保(I)未标记数据没有异常污染和/或(ii)表示学习方法对于可能的异常污染是稳健的。这是因为大多数方法隐含地假设训练数据是干净的,并且不包含任何噪声/异常实例。这种鲁棒性在预训练建模和微调阶段都很重要。此外,不同领域中的异常和数据集差异很大,因此大规模正态学习可能需要特定于领域/应用。

如果你觉得调查报告的摘要有趣且有帮助,你可以阅读全文以了解详情。

[1]庞,关松,,,曹,和安东·范登恒。“用于异常检测的深度学习:综述。”美国计算机学会计算调查(CSUR) 54,第 2 期(2021 年):第 1–38 页。[ CSUR 来源 ] [ arXiv 来源 ]

一个全面的教程,以信任运营商的初学者

原文:https://towardsdatascience.com/a-comprehensive-tutorial-to-rust-operators-for-beginners-11554b2c64d4?source=collection_archive---------23-----------------------

方法、相关函数、将 Python 转换成 Rust 等等

由 pikisuperstar 创建的健康矢量—www.freepik.com

**Table of Contents**[**Introduction**](#f77d)🦀 [Arithmetic Operators](#7b55)
🦀 [Comparison Operators](#ec1d)
🦀 [Logical Operators](#71e3)
🦀 [Bitwise Operators](#b809)
🦀 [Compound Assignment Operators](#06a0)
🦀 [Operator Overloading](#de94)
🦀 [XOR and Bitwise Operators Truth Table](#f515)
🦀 [Problem 1: Single Number](#bb38)
🦀 [Python Solution](#6fa3)
🦀 [Rust Code](#0af4)
🦀 [Method and Associated Functions](#c7fe)
🦀 [Solution Using an Associated Function](#7878)
🦀 [Problem 2: Number of Steps to Reduce a Number to Zero](#a615)[**Conclusion**](#678b)

[更新于 2020 年 2 月 18 日。代码更改为要点并添加了链接]

介绍

运算符告诉编译器或解释器执行特定的数学、关系或逻辑运算。许多编程语言都使用类似的操作符。

我们将讨论 Rust 中重要的算术、关系和逻辑操作符,并将它们与 Python 进行比较。

我们将学习方法和相关函数之间的区别。

我们还将两个简单的 Python 代码转换成 Rust 代码,以了解更多关于 Rust 编程的知识。

我们开始吧!

[## 通过将 Python 转换成 Rust 来学习 Rust

Rust 基础入门教程

towardsdatascience.com](/learning-rust-by-converting-python-to-rust-259e735591c6)

算术运算符

Rust 和 Python 算术运算符。图片由作者提供。

Python 和 Rust 共享相同的算术符号,如上表所示。锈称%余数 而不是 模数

我们将在后面的操作符过载中讨论“生锈过载特性”。

网上试试这个 Rust lang 代码。

输出:

a: 20, b: 20+1=21, c: 20-2=18, d: 20*3=60, e: 20/4=5, f: 20%3=2

在 Rust 中,不能在一个操作中使用不同的数据 类型。例如,如果你试图从一个 有符号整数 中减去一个 无符号整数 ,就会失败:

// This will fail.
fn main() {
    let a = 8u8;
    let b = 2i32;
    println!("{}", a - b);
}

Rust 使用[**as**](https://doc.rust-lang.org/std/keyword.as.html) 关键字原语类型之间进行强制转换。请点击阅读更多关于《铁锈》剧组的内容。

在线试用这个 Rust lang 代码。

输出:

6

指数 Python 使用**符号表示指数:

网上试试这个锈郎代码。

输出:

2^3 is  8
3^3 is  27
3^3.2 is  33.63473536961897

锈的用途**pow****powi****powf**取决于类型:

网上试试这个 Rust lang 代码。

输出:

2 ^ 3 in Rust: 2u8.pow(3) = 8
2 ^ 3 in Rust: 2i32.pow(3) is 8
3.0 ^ 3 in Rust: 3.0f32.powi(3) 27
3.0 ^ 3.2 in Rust: 3.0_f32.powf(3.2) is 33.63474
a = 3, a ^ 3 in Rust: i32::pow(a,3) = 27
b = 3.1, b ^ 3 in Rust: f64::powi(b, 3) = 29.791000000000004
b = 3.1, b ^ PI in Rust: std::f64::consts::PI) = 34.96699308140392

在 Rust 中,您可以注释类似于2u82_u8的数字类型。u8是一个无符号 8 位整数类型i32是一个有符号整数类型

[i32](https://doc.rust-lang.org/std/primitive.i32.html)[f32](https://doc.rust-lang.org/std/primitive.f32.html)有一组内置方法。所有的整数类型u8u16u32u64u128i16i32i64i128isizeusize都有[**pow**](https://doc.rust-lang.org/std/primitive.i32.html#method.pow)方法。

pub fn pow(self, exp: u32) -> i32

上面的定义告诉你,使用pow方法将 self 提升到exp(也就是u32)的幂,并返回i32(有符号整数)。

浮点类型f32f64[**powi**](https://doc.rust-lang.org/std/primitive.f32.html#method.powi)[**powf**](https://doc.rust-lang.org/std/primitive.f32.html#method.powf)方法。

**powi**对一个数字进行整数幂运算,而**powf**对一个数字进行浮点幂运算。

pub fn powi(self, n: i32) -> f32
pub fn powf(self, n: f32) -> f32

楼层划分 在 Python 中,我们用//来找一个楼层划分。比如5//2=2

网上试试这个 Rust lang 代码。

输出:

5 // 2 is  2
-5 // 2 is  -3

Rust 的浮点类型使用 floor 方法

试试这个 Rust lang 在线代码。

输出:

2
-3

比较运算符

Python 和 Rust 共享所有比较运算符的相同符号。

Rust 和 Python 比较运算符。图片由作者提供。

网上试试这个 Rust lang 代码。

输出:

 a: 7, b: 4, 
    c: 7 == 4 is false, 
    d: 7 != 4 is true, 
    e: 7<4 is false, 
    f: 7>4 is true, 
    g: 7<=7 is true, 
    h: 7>=7 is true

逻辑运算符

Rust 逻辑运算符符号不同于 Python 符号。

Rust 和 Python 逻辑运算符。图片由作者提供。

网上试试这个锈郎代码。

输出:

 a: true, b: false, 
    c: !true is false, 
    d: true && false is false, 
    e: true || false is true

按位运算符

所有 Rust 和 Python 按位运算符共享相同的按位运算符符号,除了按位 NOT。

Rust 和 Python 按位运算符。图片由作者提供。

网上试试这个 Rust lang 代码。

输出:

 a: 1, b: 2, 
    c: 1 & 2 is 0, 
    d: 1 | 2 is 3, 
    e: 1 ^ 2 is 3,
    f: 1 << 2 is 4,
    f2: 1 << 4 is 16,
    g: 1 >> 2 is 0,
    g2: 1 >> 2 is 1,
    h: !1 = -2

按位求反 !1返回-2。Rust 使用二进制补码来查找有符号类型的按位求反。Rust 的有符号整数类型被称为有符号二进制补码整数类型

可以用1 << n求出 2 的指数。

网上试试这个 Rust lang 代码。

输出:

2 ^ 3 = 8
2 ^ 4 = 16
2 ^ 5 = 32

复合赋值运算符

所有 Rust 和 Python 复合赋值运算符具有相同的符号,除了 Rust 不具有幂赋值**=和楼层划分赋值//=的等价性。

Rust 和 Python 复合赋值运算符

网上试试这个 Rust lang 代码。

输出:

a is 2
1: a += 5 is 7
2: a -= 2 is 5
3: a *= 5 is 25
4: a /= 2 is 12
5: a %= 5 is 2
6: a &= 2 is 2
7: a |= 5 is 7
8: a ^= 2 is 5
9: a <<= 1 is 10
10: a >>= 2 is 2

运算符重载

运算符重载就是在同一个范围内为一个运算符指定多个定义。 PythonRust 提供操作符重载。你可以在标准库 ops 模块中找到 Rust 重载运算符。

网上试试这个 Rust lang 代码。

输出:

Point { x: 3, y: 3 }

XOR 和按位运算符真值表

正如我们之前看到的,Python 和 Rust 对位符号ANDORXOR使用相同的符号。

&是按位AND|是按位OR^是按位异或(异或)。下面可以看到真值表和维恩图。

与、或和异或的真值表。

与、异或或文氏图

当您将XOR用于相同数字的偶数时,输出始终为 0。

在 Rust 中,可以用{:#b}打印二进制

网上试试这个 Rust lang 代码。

输出:

0 ^ 0 = 0
Binary: 0 ^ 0 = 0b0
1 ^ 1 = 0
Binary: 1 ^ 1 = 0b0
2 ^ 2 = 0
Binary: 2 ^ 2 = 0b0
3 ^ 5 ^ 3 ^ 5 = 0
Binary: 3 ^ 5 ^ 3 ^ 5 = 0b0
1 ^ 1 ^ 1 = 1
Binary: 1 ^ 1 ^ 1 = 0b1
1 ^ 1 ^ 5 = 5
Binary: 1 ^ 1 ^ 5 = 0b101

你可以在这里找到 Python 代码

问题一:单号

我们要用这个XOR来解决叫做单号的 LeetCoder 问题。

在这个问题中,一个数组输入有一对数字,除了一个,例如[1, 1, 5, 5, 2]。你需要从这个数组中找到一个 sing 数,在这种情况下,输出应该是2

更多例子:输入为[2, 2, 1]时,输出应为1。当输入为[4, 1, 2, 1, 2]时,输出应为4

这是一个使用XOR操作符的好例子。

Python 解决方案

我们简单地浏览一下 Python 解决方案,看看这个问题是如何解决的。

在线尝试这段 Python 代码。

输出:

4

第 1 行:我们使用的 Python typing是从 v3.5 引入的

第 3–4 行:导入List后,我们创建了一个名为Solution的类和一个名为singleNumber的方法。

使用 Python 类型提示,我们将类型的名称大写,并将集合中的类型名称放在括号中,如上所示num: List[int]

第 5–8 行:我们将变量ans设置为 0。使用一个for循环,我们使用XOR复合赋值ans ^= n迭代输入数组nums。这将从数组中输出一个数字。

第 10–11 行:我们实例化类Solution并调用方法singleNumber

(如果您对感兴趣,您可以在没有类型符号的情况下运行这段 Python 代码。)

以下是 LeetCode 环境的解决方案:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ans = 0
        for n in nums:
            ans ^= n
        return ans

Python 结果。

生锈代码

Rust 结构 包含命名字段。我们使用关键字struct并在花括号内设置字段类型。我们把方法放到一个impl块中。

起始代码

试试这个 Rust lang 在线代码。

输出:

1

第 1 行:我们取消dead_code警告。

第 2–4 行:创建一个名为Solutionstruct,它接受一个类型为Vec<i32>的字段nums 。(更多关于向量。)

第 6–10 行:我们在impl Solution中创建了一个方法single_numbersingle_number取第一个参数&self ( 详见 [self](/learning-rust-by-converting-python-to-rust-259e735591c6#f6fb) )。)而我们现在只是返回1

第 12–17 行:在 main 函数中,我们创建了一个实例并使用方法打印了1

看起来一切正常,所以我们接下来要完成single_number方法。

方法和相关功能

方法是在一个结构的上下文中定义的,它们的第一个参数总是self,它代表调用方法的结构的实例。Rust 编程语言

关联函数不把self作为参数,它们也不是方法,因为它们没有可以使用的结构实例。

一个很好的例子就是String::from函数。

我们使用带有结构名的::语法来调用这个关联的函数,而当我们调用一个方法时,我们使用.

一个常见的关联函数是new函数,它返回与关联函数相关联的类型的值。

网上试试这个 Rust lang 代码。

输出:

x: 5, y: 4
x: 8, y: 9

最终代码

网上试试这个 Rust lang 代码。

第 7–11 行:我们创建了一个类型为i32的可变变量ans。使用for循环,我们使用ans ^=n迭代&self.nums

输出:

5

我们根据 LeetCode 环境调整上面的代码。

impl Solution {
    pub fn single_number(nums: Vec<i32>) -> i32 {
        let mut ans: i32 = 0;
        for n in nums {
            ans ^= n;
        }
        ans        
    }
}

铁锈导致了 LeetCode

内存使用在 Rust 中是 2.2 MB,在 Python 中是 16.5 MB。(更多关于运行时&内存使用量)

使用关联函数的解决方案

既然学了关联函数,那就把它应用到这个问题上吧。

网上试试这个 Rust lang 代码。

输出:

1
4

第 6–10 行:我们创建一个关联函数,new,就像我们之前做的那样。这个new函数采用一个参数nums,该参数是一个带有i32项的向量。

当参数名和 struct 字段名完全相同时,我们可以使用 字段初始化简写 语法作为nums而不是nums: nums

在 main 函数中,我们调用一个关联函数new,并将nums作为参数传递。我们使用方法语法来调用ans3实例上的single_number方法。

问题 2:将一个数化为零的步骤数

这个问题中,你输入一个非负整数num,返回步数使其降为零。如果当前数是偶数,你就要把它除以 2,否则,你就要从中减去 1。

例如:

Input: num = 14
Output: 6
Explanation: 
Step 1) 14 is even; divide by 2 and obtain 7\. 
Step 2) 7 is odd; subtract 1 and obtain 6.
Step 3) 6 is even; divide by 2 and obtain 3\. 
Step 4) 3 is odd; subtract 1 and obtain 2\. 
Step 5) 2 is even; divide by 2 and obtain 1\. 
Step 6) 1 is odd; subtract 1 and obtain 0.Input: num = 8
Output: 4
Explanation: 
Step 1) 8 is even; divide by 2 and obtain 4\. 
Step 2) 4 is even; divide by 2 and obtain 2\. 
Step 3) 2 is even; divide by 2 and obtain 1\. 
Step 4) 1 is odd; subtract 1 and obtain 0.

这是一个很好的例子,我们可以使用模数/余数运算符和复合赋值运算符。

Python 解决方案

在线尝试这段 Python 代码。

输出:

6
4

第 3–10 行:我们对num > 0使用了一个while循环。如果模数是 0,那么它一定是一个偶数,所以我们使用复合赋值/=2num除以 2,否则,我们使用复合赋值-=1减去 1。我们将steps增加 1。最后,我们返回steps

我们根据 LeetCode 环境调整上面的代码。

class Solution:
    def numberOfSteps (self, num: int) -> int:
        steps = 0
        while num > 0:
            if num % 2 == 0:
                num //= 2 
            else:
                num -=1 
            steps += 1
        return steps

LeetCode 的 Python 结果。

防锈液

网上试试这个 Rust lang 代码。

输出:

6
4

在 Rust 中,我们采取了与 Python 相同的步骤。

第 7–16 行:我们将 0 赋给一个可变变量steps。当self.num大于 0 时,如果self.num的余数为 0,我们使用复合赋值/=2,否则,我们减去 1,并将步数增加 1。

我们根据 LeetCode 环境调整上面的代码。

impl Solution {
    pub fn number_of_steps (mut num: i32) -> i32 {
        let mut steps = 0;
        while num > 0 {
            if num % 2 == 0 {
                num /= 2;
            } else {
                num -=1;
            }
            steps += 1;
        }
        steps
    }
}

生锈是由漏电引起的

结论

我们在 Rust 中学习了算术、比较、逻辑、按位和复合赋值操作符。我们还学习了操作符重载、关联函数和方法之间的区别,以及如何通过将简单的 Python 代码转换为 Rust 来使用 Rust 中的操作符。

我希望你学到了一些东西,并为下一步做好了准备。请继续关注下一篇文章。

通过 成为 的会员,可以完全访问媒体上的每一个故事。

https://blog.codewithshin.com/subscribe

参考

以下资源用于编写这篇文章:

[## 无符号、有符号整数和 Rust 初学者的造型

理解符号和幅度、一的补码和二的补码

towardsdatascience.com](/unsinged-signed-integers-and-casting-in-rust-9a847bfc398f)

囚徒困境的计算方法

原文:https://towardsdatascience.com/a-computational-approach-to-the-prisoners-dilemma-837a799cedf0?source=collection_archive---------41-----------------------

在这种充满犯罪的“棘手情况”下,最好的决定是什么

你和你的朋友犯了谋杀罪。几天后,警察把你们两个带走,把你们放在两个独立的审讯室里,这样你们就不能互相交流了。你认为你的生活结束了,但是警察提出了一个交易:

出卖你的朋友,你的刑期会轻一些。

比尔·牛津在 Unsplash 上的照片

关键是你的朋友也能得到这笔交易。

更具体地说,如果你出卖了你的朋友,但你的朋友什么也没说,他们会被判重刑,而你会被判轻刑。如果你们出卖对方,双方都会受到重罚。如果你们两个都保持沉默,对你和你的朋友来说,判决都是轻的。

这些决定必须在彼此不沟通的情况下做出,你和你的朋友只有两个选择:“叛逃”并告发他们,或者“隐瞒”信息,保持沉默。

看看下面的图表,它描述了你的选择和句子:

给你和你朋友的惩罚图。

矩阵描述了根据你和你的朋友独立选择做的事情,你们两个人得到的年数。第一个数字代表你的入狱时间,第二个代表你朋友的。

例如,如果你向警察隐瞒信息,但你的朋友选择出卖你,你会在最高安全监狱服刑五年,但你的朋友只服刑一年。

在这种情况下,你会怎么做?

在这种情况下,你应该做什么?

这个问题没有简单的解决办法,对此有很多解释。功利主义者可能会说,扣留是更好的选择,因为它可以最大限度地减少两个人在监狱里度过的总年数(5 + 1 或 3 + 3,而不是 10 + 10)。概率怎么说?

解决困境

我创造了一群 1000 名囚犯,每个人都有 50-50 的机会成为叛逃者或扣留者。然后,我模拟了 500 对囚犯的互动,并记录了结果。这个实验我重复了 200 次。

叛逃者与扣留者(对半分)。

如你所见,如果叛逃者和扣留者的数量大致相同,那么试图扣留信息要好得多。大多数时候,回报会对你有利。叛逃者在监狱度过的平均年数是 5.75 年,而扣留者是 4.01 年。

我们可以通过改变叛逃者和扣留者的比例来让这变得更有趣一点。假设你在一个国家,每个人都不信任对方,75%的人是叛逃者,25%的人不信任对方。

叛逃者与扣留者(75-25 分)。

你最好的办法是向警方隐瞒信息。这是有道理的,因为如果你也背叛了,你很有可能以游戏中最糟糕的选择结束——10 年一件。

让我们再试一次。假设每个人都过度信任他人(尽管事实上他们刚刚犯了一桩谋杀案)。

叛逃者与扣留者(25-75 人)。

这个更有趣。看起来你隐瞒信息会稍微好一点,但是回报是非常不一致的(在某些情况下,结果比背叛还要糟糕!).这是因为在其他缺陷的情况下,扣留的刑期可能是三年或五年,而在其他缺陷的情况下,叛逃的刑期可能是一年或十年。3 和 5 之间的差异比 1 和 10 之间的差异要小得多,所以在后一种情况下差异要大得多。

在这种特殊情况下,你会怎么做?

如果你喜欢这篇文章,你可以在 Medium 上关注我,了解更多类似的内容。感谢阅读!

数据科学爱好者简明指南

原文:https://towardsdatascience.com/a-concise-guide-for-data-science-aspirants-49722ac91102?source=collection_archive---------87-----------------------

给数据科学领域求职新手的建议和对现实的一瞥!

图 1 -图片由弗兰基·查马基Unsplash 上拍摄

(与目前的时尚相反,文章标题传达了关于数据科学的负面观点,尽管它们揭示了真相和现实,但我决定用一个陈词滥调的标题:-P 既然每个人都在写数据科学——为什么一个人应该/不应该成为数据科学家,为什么它有趣/不有趣,我想我不妨写一个。我是一名数据分析师,在一家初创公司工作过一段时间,与数据科学家和产品经理共事过。我在这里根据我的经验分享我的观点,并在某些方面提供帮助)

TLDR: 这篇文章是为那些想进入这个领域的人写的,让他们知道应该/不应该从这个领域期待什么,在申请数据科学领域的工作时应该注意什么,以及当你想尝试管理角色而仍然与“数据”相关时有哪些不同的选择。

1。角色不同是什么意思?

让我先简单解释一下这些人们经常互换使用的流行语的意思,以澄清困惑。

数据分析师 数据分析师的角色主要包括(不限于,可以超越这一点,这取决于你所在公司的角色的灵活性)获取、争论或管理数据,然后从中获得洞察力,构建仪表板以可视化它们。现在, 业务分析师产品分析师 是 DA 的专门角色,他们与专注于具体工作的业务/产品团队密切合作

数据科学家——向前迈出一步,利用所获得的见解来制定决策和采取行动,用特定的假设进行实验,通过连接各个点来构建框架/流程,整合不同的部分以得出最终的解决方案

ML 工程师【1】—数据科学是关于在数据中寻找模式,ML 是关于使用机器对数据中的模式进行建模,以便解决特定问题,当涉及大型数据集时,自动化人类无法手动完成的任务。这项工作主要包括功能工程、构建模型、验证模型和部署模型。与数据科学不同,这里可能没有太多惊喜。

数据工程师 确保分析师和科学家随时可以获得他们需要的数据。他们的工作是:

  • 制作并提供实时数据集
  • 设置运行脚本、分析、模型
  • 帮助生产解决方案——通过建立工作岗位、管道、亲测试环境

图 2 - 数据流 (图片由作者提供)

扎实的数学和统计学基础是数据分析和科学的关键。当你转向 ML 工程和数据工程时,你需要做大量的编码工作,并且精通分布式系统和架构。然而,学术界/研究领域的 ML 涉及更多的理论和数学。担任这些角色的每个人都必须齐心协力为生活带来一个目标。也就是说,这些不同角色的工作在某种程度上是重叠的。

已经有一些关于这些与软件开发和工程的角色有多么不同的讨论。这是另一天的话题

【注:以上纯属我在印度市场的经验和观察】

2。想闯入 DS 的人应该警惕什么?

每个公司都想赶上数据科学的潮流,并开始对他们的业务产生巨大影响。但是你应该知道的是,并不是每家公司都确切地知道他们想怎么做和为什么要做。

1.很多时候,我碰到主题为——‘数据科学/ ML 人才供需有缺口’的文章。我不认为那是真的。但是,也不是那么容易被聘为 DS。原因如下。每个公司都在寻找不同的东西

  • 很少有公司在发布招聘广告时甚至不知道自己在寻找什么。他们可能刚刚开始从数据驱动的解决方案中寻找一些商业价值,但他们不知道要雇用谁,如何开始,做什么。有些是非常有选择性的,只雇佣博士候选人,研究生,在我看来,这不是筛选候选人的最佳方式。
  • 很少有其他公司知道他们在做什么,他们可能会开始自己的内部数据团队,因此,需要有经验的个人与领域专业知识开始。
  • 一些正在组建团队的公司会愿意雇佣刚毕业的大学生和有 1-2 年工作经验的人。

2.你需要知道你的目标是否与公司正在做的事情和他们的愿景一致。了解 DS/ML 是否被视为其业务的驱动力之一。如果那里不崇拜数据,那你就不会想去那里。因此,对你想加入的公司进行调查是至关重要的。让你内心深处的夏洛克开始挖掘信息吧!

3.你的角色可以是特定的,也可以是不同角色的组合(如上所述),这取决于公司所处的阶段。你的工作是了解工作范围。而且,这个范围可以根据个人的主动性和能力而超出界限。特别是,当公司处于初级阶段时,你可能会被期望戴上不同的帽子,扮演不同的角色。

4.你必须了解在同一个部门工作的员工(他们的资格),因为这些人将不时地指导你,你希望他们有经验,具备良好的知识和技能,并在遇到困难时指导你。在工作中,协作和分享知识是发展个人技能的核心。

3。期望与现实

你应该摆脱这样的错觉,即你所要做的只是使用你所学的那些花哨的算法,炮制一个将被公司不同团队的用户采用的解决方案/产品,以产生有意义的影响。好吧,走出幻想,看清现实——不像你想的那样梦幻而简单。哎哟!【3】

  1. 作为数据分析师或数据科学家,你的工作将主要围绕统计和数学中的基本概念——比率、比例、概率、线性代数、何时使用哪些指标、什么是原因、统计建模和一些基本算法。它可以从清理、转换数据到使用基础知识来发现数据中的模式,再到构建管道来生产可供其他团队使用的成品/工具。有时,数据修剪和预处理构成了一半以上的工作。你应该愿意做所有这些。
  2. 大多数商业问题可以用简单的统计方法来解决。这里有一个完美的迷因来说明这一点。

图 3- 一个人用剑,而不是刀来切他的食物 (图片由knowyourmeme*)*

然而,你应该跟上这个领域的最新发展以保持相关性。

3.通向解决方案的旅程可能不像你想象的那么顺利。你可能花了几个星期做某件事,结果却发现它不会成功。然后,你必须重新制定你的计划,重新发明轮子。因为有很多探索和实验,你可以预料到一些不确定性,耐心是关键。

图 4

4.生产(如果需要,部署和扩展)解决方案与实现它同等重要。重要的是,这些想法/解决方案以产品/工具的形式实现,可供其目标用户使用。努力必须持续到最后一英里。

5.要知道比起编写算法本身,更强调的是正确使用算法(ML/ DL /或 any)来解决你的问题。由于微软、亚马逊、谷歌(checkout H2O.ai)等大公司都有工具,可以帮助你在任何数据集上应用算法,所以没有必要从头开始构建。从功能工程到部署,他们可以做任何事情。尽管 AutoML 使用的增加减轻了数据科学家肩上的一些负担,但我相信它不能完全取代他们[4]。

6.你被期望拥有良好的沟通技巧,因为你会-

  • 在日常工作中积极与数据分析师和数据工程师合作
  • 与产品经理紧密合作;与他们交流来自不同团队的依赖关系,为制定服务于长期目标的路线图做出贡献。
  • 需要说服或传达给你的观众,为什么你做了你所做的,它是如何工作的,它会产生什么影响

7.精疲力竭并不罕见。你得想出如何应付和处理他们。在那些时候,让自己挺过来是这个过程的一部分。

4。想转向管理角色?

如果您想探索 Data domain 中的管理领域,那么这个角色非常适合您— 数据产品经理

图 5 -由游 X 创投Unsplash 上拍摄的照片

典型的数据 PM 的工作如下所示:

  • 充当产品、业务和数据团队之间的 POC,以沟通和管理最终目标的依赖性和期望
  • 根据这些数据驱动的决策的业务需求和附加值,对要完成的项目和任务进行优先级排序
  • 监督这些项目的开发,并协助在设定的期限内完成
  • 创建符合公司长期愿景的路线图

现在,监督专门为公司内部用户服务的数据产品开发的数据产品经理被称为数据平台产品经理 [5]

你不妨为自己创新一个新角色!

5。破解求职申请

这里有一些建议或提示,你可以遵循,这有助于你从那些追逐圣杯的人中脱颖而出

数字媒体正在蓬勃发展,你需要在你想从事的领域展示你的能力。所以,发表关于你的项目的文章和博客。把它们放到 Github 上。尽一切努力让招聘人员了解你的工作。

给负责招聘你的相关人员发电子邮件(或在 LinkedIn 上联系)。在起草电子邮件时,请记住以下几点:

  • 邮件要简洁直接。
  • 不要使用“但是”、“如果”这样的词语(不要贬低或贬低自己)。请改用“and”
  • 大致把邮件分成三部分-
  1. 介绍
  2. 中间部分:
  • 你是谁
  • 过去的相关项目(在线链接)
  • 为什么你对在这家公司工作感到兴奋
  • 向他们展示你对那里发生的事情有所了解

3.结论

F 在面试数据科学家职位的候选人时,一些被候选人忽略但被招聘人员认为很重要的事情:

  • 你如何将一个问题分解成更小的部分
  • 你如何与你的队友合作——沟通和反馈
  • 为了让其他人相信你的项目,你能在多大程度上有效地与各种利益相关者交流你的发现,讲述数据

假设有大量的应用程序可以通过利用数据来使用 DS 和 ML,并且这些应用程序每天都在增加,人们可以找到许多机会在这个领域开始他们的职业生涯。

例如,医疗保健、银行咨询投资部门、市场营销、地理信息学。见鬼,有一个专门的数据科学家为一个具有国际地位的足球俱乐部工作!![7]自然语言处理和计算机视觉的使用越来越普及,人们需要随时了解它们和其他发展的最新情况。走出去,为自己创造机会,建造东西,发明东西,享受这个过程。

祝所有想在数据科学领域发展的人好运。希望你觉得这有用!请在评论区留下你的反馈和建议。

参考

[1]更多关于 ML 工程师的期望— Ian Xiao数据科学很无聊

[2] Harshit Ahuja为什么数据科学正在失去魅力?

[3] Jonny Brooks-Bartlett这就是这么多数据科学家离职的原因

[4]深度洞察为什么 AutoML 无法取代数据科学家— Joseph Chin数据科学家之死

[5] Allyson Gale我从消费者到数据平台产品管理的转变中学到了什么

苏珊·霍尔科姆,数据科学家的非技术性职业技能,Spotify TDS 播客

[7]看看这段视频利物浦足球俱乐部的数据科学家利用以往赛事的数据点评估一名球员的控球能力

10+牛逼 Python 编辑器的简明指南,以及如何选择最适合你的编辑器:有利弊!

原文:https://towardsdatascience.com/a-concise-guide-of-10-awesome-python-editors-and-how-to-choose-which-editor-suits-you-the-best-465c9b232afd?source=collection_archive---------29-----------------------

帮助您在各种 python 开发环境中进行选择的简明指南

罗布·兰伯特在 Unsplash 上拍摄的照片

简介:

集成开发环境(IDE)是一种软件,它为程序的编译和解释提供了全面的工具。它为编码人员、爱好者和开发人员提供了一个平台,通过源代码编辑器、自动化工具和调试器来试验和解释代码/程序。IDE 既可以支持单一的编程语言,如 Python 独有的 Pycharm,也可以支持多种编程语言,如 Visual Studio 代码。

因为 python 是现代的流行语言,所以它有很多可用的开发软件,如 Pycharm、visual studio code、Jupyter notebooks 等。让我们对每个编辑器做一个完整的分解,以及你应该考虑什么时候使用它们。我将提供更详细的指南,介绍我更熟悉的编辑,以及我认为更有吸引力的内容。然而,我也将给出一些我不太熟悉的编辑器的概要。

注:文中提到的每一位编辑都绝对是梦幻般的牛逼。这个列表根据我个人的使用经验提供了一个简明的指南。你可能比其他人更喜欢一些。最终选择挑编辑器还是开发环境,完全是你自己的事情,不存在选择的对错。这些都有它的优点和缺点,每件事都以自己的方式令人惊叹。

5 个我最有经验并且经常使用的编辑器

1.Python 空闲

作者截图

这是在系统上安装 python 后得到的默认安装。这是编写 python 程序的最基本和最简单的模式。但是对于初学者来说,入门编程,了解 python 的基础知识,还是一个不错的选择。它附带了一些特性,比如 python shell,这是一个交互式解释器。它具有广泛的特性,如自动完成、语法高亮、智能缩进和一个基本的集成调试器。

优点:

  • 轻量级。
  • 适合初学者。

缺点:

  • 不适合复杂的项目。
  • 缺少高级功能。

2.崇高的文本

作者截图

Sublime Text 是一款免费软件,拥有广泛的社区支持,能够运行多种编程语言,包括 python。您可以在大多数情况下使用未注册的 Sublime Text,但偶尔您会收到一个弹出窗口,要求您注册该产品并获得许可证。它是高度可定制的,可以添加各种安装来提高 python 语言的工作质量,如调试、自动完成、代码林挺等。

优点:

  • 易于使用并且大部分是免费的。
  • 高度可定制。
  • 紧凑有效。

缺点:

  • 需要额外安装才能获得更好的 Python 体验。

3.Visual Studio 代码

作者截图

Visual Studio Code 是微软为 Windows、Linux 和 macOS 开发的免费源代码编辑器。特性包括对调试、语法高亮、智能代码完成、代码片段、代码重构和嵌入式 Git 的支持。它支持包括 python 在内的各种编程语言。您可能需要一些额外的安装来开始使用 Python,但是这非常简单。它不断更新,是 Python 和其他编程语言的最佳平台之一。我经常使用它,也强烈推荐它。

优点:

  • 不断更新的奇妙平台。
  • 与其他庞大的开发工具相比,软件内存的消耗非常低。
  • 控制台终端集成,易于使用。

缺点:

  • 有时,终端会变得有点问题,不能按预期运行。

4.Jupyter 笔记本

作者截图

Jupyter Notebook 是一个开源的 web 应用程序,允许您创建和共享包含实时代码、等式、可视化和叙述性文本的文档。用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。Jupyter 笔记本绝对是开始学习数据科学和机器学习的绝佳选择。这些笔记本可以与任何人共享,有助于更高效地协作编写代码。我强烈推荐使用 Jupyter 笔记本,因为你可以单独使用每个代码块,也可以选择使用降价。它被广泛应用于许多盈利的公司。

优点:

  • 数据科学入门的最佳平台。
  • 易于共享笔记本和可视化。
  • 降价和其他附加功能的可用性。

缺点:

  • 缺少一些 IDE 中包含的强大功能。

5.皮查姆

作者截图

PyCharm 是一个用于计算机编程的集成开发环境,专门用于 Python 语言。它是由捷克公司 JetBrains 开发的。因为这是专门为 Python 开发的,所以它拥有你想要的所有广泛的特性和额外的支持。这些包括代码完成、代码检查、错误突出显示、修复、调试、版本控制系统和代码重构。它可以在多种平台上使用,例如 Microsoft Windows、Linux 和 macOS。它有免费版和付费专业版。付费专业版有一些额外的功能,但免费版对于大多数编码和编程相关的活动来说已经足够了。如果你有至少 8GB 的内存和一台高质量的电脑,我会强烈推荐 Pycharm。

优点:

  • 惊人的内置功能。
  • 由对 python 支持最好的顶尖公司开发。
  • 也支持 anaconda 虚拟环境。

缺点:

  • Pycharm 的主要问题是,如果你有一台个人电脑或笔记本电脑是低端的,没有至少 8 GB 的内存,会有点滞后,速度很慢。

其他优秀的编辑:

1.Thonny 编辑

作者截图

Thonny 集成开发环境(IDE),预安装在 Linux 和基于 Linux 的平台上。但是,您必须在 Windows 平台上手动安装它。我对 Thonny 编辑器的体验主要是在树莓 Pi 上。这是一个很好的开发环境,初学者很容易上手。对于树莓 Pi 项目来说是极其牛逼的。它的一些特性包括语法错误突出显示、调试器、代码完成、单步执行表达式求值等。

优点:

  • 互动环境。
  • 适合初学者。
  • 可用于树莓 Pi 项目。

缺点:

  • 有时容易出问题。
  • 没有广泛的功能。

2.Spyder

作者截图

Spyder 是用 Python 语言进行科学编程的开源跨平台集成开发环境。Spyder 是一个强大的科学环境,它用 Python 编写,面向 Python,由科学家、工程师和数据分析师设计,并为他们服务。它将综合开发工具的高级编辑、分析、调试和分析功能与科学包的数据探索、交互式执行、深度检查和漂亮的可视化功能进行了独特的结合。在任何 Spyder 支持的平台上启动和运行 Spyder 的简单方法是下载它作为 Anaconda 发行版的一部分,并使用 conda 包和环境管理器来保持它和其他包的安装和更新。开发人员推荐最新的 64 位 Python 3 版本,除非您有特别的要求。

优点:

  • anaconda 提供的免费编辑器。
  • 很好的工作环境,可以并排看到解释和代码。
  • 拥有 python 独有的大量选项。

缺点:

  • 界面略显生疏。

3.原子

作者截图

这个 IDE 类似于 Sublime 文本编辑器,但对 Python 有额外的要求。它是高度可定制的,并支持 python 所需的许多包。这是崇高文本的另类选择。我在这方面的经验比较少,所以我会推荐 sublime text 而不是 Atom,但是对这两者都比较有经验的观众,请让我知道你更喜欢哪一个。Atom 中用于 Python 开发的一些常用包有 autocomplete-python、linter-flake8、python-debugger 等。

优点:

  • 好用。
  • 通过附加安装支持 python。

缺点:

  • 需要额外的 python 插件。
  • 更适合 git 应用。

4.精力

作者截图

Vim 是预装在 macOS 和 UNIX 系统中的文本编辑器。但是,您需要在 Windows 平台上手动下载它。由于 vim 的高计算能力和轻量级紧凑开发工作环境,大多数专家都非常喜欢它。不建议初学者使用它,因为它有一个陡峭的学习曲线,你必须花费额外的时间和精力来理解 VIM 软件。您可以添加插件来突出语法、代码完成、调试、重构等。到 Vim,并将其用作 Python IDE。

优点:

  • 轻量级。
  • 有效。
  • 富有成效。

缺点:

  • 你必须花费专门的时间来学习整个编辑器,它有一个陡峭的学习曲线。

5.记事本++

作者截图

Notepad++是一个文本和源代码编辑器,用于 Microsoft Windows。它支持选项卡式编辑,允许在一个窗口中处理多个打开的文件。项目的名字来自 C 增量运算符。Notepad++作为免费软件分发。notepad ++支持各种编程语言的许多开发环境,是一个值得考虑的选择。在我看来,有更好的选择,你也需要做一些额外的安装,以使它完全适用于 python。

优点:

  • 易于使用类似于记事本。
  • 可用于包括 python 在内的多种编程语言。

缺点:

  • 需要更多的设置和调整来运行 python。
  • 不在我的首选名单上,因为有很多更好的选择。

6.其他在线编辑

Programiz、tutorials point、w3schools 和其他一些网站为在线编辑提供了一些很棒的选择。我已经错过了一些,但检查了所有的在线编辑器,因为他们大多数都是免费的,玩起来很有趣。如果你懒得完成 python 的所有设置过程,那么就跳进在线编辑器的世界去探索吧。

优点:

  • 没有额外的安装或额外的设置程序。
  • 简单的代码可以轻松运行,没有太多的麻烦。

缺点:

  • 不如其他 IDE 强大。

Unsplash 上的窗口拍摄

结论:

唷!那是一个很长的名单。我已经介绍了几乎所有我使用过的 python 编辑器。然而,有趣的是,我可能错过了一些甚至很多,因为有太多的开发环境。也有大量的编辑器正在构建中,以使用户体验更加可定制和有趣。我希望这本简明指南能够帮助观众。如果我错过了什么,请随时告诉我。有这么多选择,但不要不知所措。我想重申,选择没有对错之分。

最后,选择你觉得最舒服、最喜欢的编辑器。

查看我最近的一篇文章,关于几乎任何人都可能犯的 5 个常见 python 错误以及如何避免它们。

[## 5 个常见的 Python 错误以及如何避免它们!

从初学者到专家,每个人在 python 和机器学习中都容易出现这些错误。

towardsdatascience.com](/5-common-python-errors-and-how-to-avoid-them-63d9afc1a58f)

请随意查看下面的文章系列,这些文章将从头开始涵盖对机器学习的全部掌握。它们将不断更新,本系列将从头开始涵盖与 python 进行机器学习相关的每个主题和算法。

[## 开始使用 Python 掌握机器学习的旅程

了解精通机器学习的基本要求

towardsdatascience.com](/starting-your-journey-to-master-machine-learning-with-python-d0bd47ebada9) [## 机器学习所需的 Python 基础知识及其库模块

学习 python 数据结构的基础知识,对机器所需的每个库有直观的理解…

towardsdatascience.com](/basics-of-python-and-its-library-modules-required-for-machine-learning-51c9d26026b8)

感谢大家阅读这篇文章。祝大家度过美好的一天!

参考资料:

  1. https://www.spyder-ide.org/
  2. https://www.programiz.com/python-programming/ide
  3. https://notepad-plus-plus.org/downloads/
  4. https://www.vim.org/
  5. www.trustradius.com
  6. https://en.wikipedia.org/wiki/Wiki

码头工人手册

原文:https://towardsdatascience.com/a-concise-guide-to-docker-f6b6d5fb56f4?source=collection_archive---------47-----------------------

码头工人简明指南

有几门关于这个主题的课程。有些非常短,除了“入门课程”之外没有任何其他用途,而另一些则非常长,需要你花几天时间来学习和理解一切。我写这篇教程的目的是在简洁和详尽之间找到平衡。

接下来的部分更多的是 Docker 的欣赏部分。如果你已经知道 Docker 是什么以及它是如何有用的,你可以跳到下一节来节省一些时间。

  1. 简介(你来了!)
  2. Docker 文件
  3. 基本对接命令
  4. 端口和卷映射
  5. Docker 联网
  6. 码头仓库
  7. Docker 撰写
  8. 删除 Docker 实体

Docker 是一个工具,旨在通过使用容器更容易地创建、部署和运行应用程序。容器允许开发人员将应用程序所需的所有部分打包,如库和其他依赖项,并作为一个包发送出去。

当您的应用程序需要多个组件相互交互时,通常会出现依赖库的版本需求冲突。一旦所有组件之间就其依赖关系的版本达成一致,添加另一个组件或甚至升级其中一个组件都会破坏这一协议。

没有码头工人的生活

Docker 解决这个问题的方法是将这些组件放入单独的隔离环境中,称为“容器”,并带有各自的依赖关系。所有这些容器仍然共享同一个内核。

简单的 docker 示例

与虚拟机相比,Docker 容器更轻(尺寸更小),启动时间更短,并且不是完全隔离的。

虚拟机架构

码头建筑

问题不在于使用虚拟机还是 Docker 容器。现代生产部署同时使用这两者。这种体系结构允许您减少虚拟机数量,从而减少资源消耗并加快启动速度。

docker-虚拟机架构

简单地说,docker 映像是应用程序及其环境的模板。我们可以从一个图像中旋转出多个容器。映像包含运行应用程序所需的一切,包括源代码、库、配置文件和环境变量。docker 容器是这个映像的运行时实例。

Docker 图像及其容器

Docker image 是一个超级强大的机制,可以扩展您的应用程序。您可以从单个映像运行任意数量的容器,所有容器都将支持完全相同的依赖关系。如果你正在使用一个容器编制器,像 Kubernetes 一样,你只需要说明你想要多少容器用于一个特定的图像,编制器就会在你所有的 Docker 服务器上创建和维护它们。

如果您使用 Docker 容器并且没有停机时间,那么升级生产系统是无缝的!您只需指示 orchestrator 您想要运行一个新的映像版本,它就会逐渐用运行新版本的容器替换每个容器。

的下一节中,我们将看到什么是 Dockerfile 以及如何编写 docker file?

参考:

[1] Docker, Docker 概述 (2020),Docker 文档

[2]穆姆沙德·曼南贝斯,为绝对初学者准备的 Docker(2020),KodeKloud.com

一种基于内容的电子商务网站推荐系统

原文:https://towardsdatascience.com/a-content-based-recommender-for-e-commerce-web-store-7554b5b73eac?source=collection_archive---------4-----------------------

矩阵相乘和余弦相似的简单算法实例研究

rupixen.comUnsplash 上拍照

从电子商务、社交媒体到新闻媒体,推荐系统在消费者日常生活的在线平台上已经无处不在。我们的偏好和偏见被机器学习算法超级充电,这些算法从我们的口味中学习,并推荐更多我们希望看到的东西。因为推荐系统对我们的生活,进而对社会有着如此深远的影响,我决定将 Metis 数据科学训练营(新加坡,第 5 批)的最后一个项目用于为电子商务网络商店创建一个简单的推荐算法。在我们开始我的项目之前,我想给你一个关于两种推荐系统的概述:

基于内容的过滤推荐器:顾名思义,这种推荐器利用项目或用户背景信息之间的相似性向用户提出推荐。例如,如果用户 A 通常给科幻电影一个好的评级,推荐系统将向用户 A 推荐更多的科幻类型的电影。在另一个例子中,如果用户 B 是较高收入群体的个人,银行推荐系统可能将用户 B 标记为额外投资计划的潜在客户。

  • 优点:容易克服冷启动问题——当没有或很少有用户-项目交互时,推荐器仍然能够向用户提供好的推荐。
  • 缺点:需要物品/用户的背景信息。每当有新的项目/用户时,这些背景信息必须被编目和添加进去。

协同过滤推荐器:这种类型的推荐器识别先前和其他用户-项目交互中的趋势和模式,并基于当前用户现有的交互向他建议类似的推荐。核心思想是基于将相似口味的消费者聚集在一起。例如,一个新闻推荐器检测到,消费支持唐纳德·特朗普的新闻的用户也对阴谋论相关的新闻感兴趣。因此,如果有用户最近对特朗普新闻感兴趣,他也将被推荐与阴谋论相关的新闻。

  • 优点:利用用户-项目交互背后隐藏的相关性,不需要大量的手工映射和数据编目。
  • 缺点:容易出现冷启动问题,在能够向现有用户提供有意义的推荐之前,需要现有的用户-项目交互库。

还有混合推荐系统,它结合了基于内容的过滤和协同过滤,实现了两个世界的最佳效果。然而,这种推荐系统通常是先进的,并且需要设计神经网络。

对于这个项目,由于短时间内数据的稀疏性,我决定采用基于内容的过滤来推荐电子商务网上商店的产品,方法是定制一个算法来处理不同类别的产品信息。

1.数据转换

Kaggle 开始,我在 2 个多月的时间里获得了一个电子商务网店大约 1.1 亿的用户-产品交互数据。由于数据量巨大,我决定将数据缩减到大约 5 天,并且只从产品类别中过滤“计算机”,这样就剩下大约 35 万个用户-产品交互数据。原始数据集如下所示:

列特性‘event _ type’将作为我的推荐器模型的目标,它有 3 个类别:视图、购物车和购买。然后,我根据这些用户-商品交互提供一个用户分数——查看:1,购物车:10,购买:50。此外,我还将物品分为 5 个不同的价格类别。稍后讨论的一些模型中的假设是,客户倾向于购买低端或高端产品。代码和生成的数据帧如下所示:

注意,每个用户项目条目被记录用于一个用户会话,因此每个用户每个项目可能有多个交互。因此,我进一步执行了一个 groupby 操作,以发现每个独特的用户-项目交互的用户得分总和。这形成了用于稍后建模的用户项目矩阵的“评级”。此外,我将 MinMaxScaler 应用于用户分数,以获得一个介于 0 和 1 之间的交互分数。高于 0.5 的交互分数指示发生购买的概率非常高,而低于 0.5 的阈值则没有购买发生。代码和生成的分组数据帧如下所示:

2.探索性数据分析

用条形图和直方图剖析数据集的目标(查看/购物车/购买)(图片由作者提供)

在模型选择和开发之前,我深入研究了推荐系统目标的数据可视化(查看/购物车/购买)。不出所料,这个目标高度失衡,从观看到购买的转化率约为 1.8%。此外,根据直方图,大多数顾客根本没有购买任何东西。正如我们将看到的,这表明推荐系统准确预测购买是具有挑战性的。

3.型号选择

继续进行模型选择,我首先使用一个简单的验证范例将所有“组”数据集分为训练、验证和测试数据集:

将数据集分成 60%的训练、20%的验证和 20%的测试。(图片由作者提供)

随后,我将训练集转换成一个稀疏的用户项目矩阵,将空条目填充为零作为用户得分:

现在,我将考虑 3 种不同的基于内容的过滤模型:

  • 按项目类别过滤
  • 按项目类别和价格类别过滤
  • 按项目类别、价格类别和品牌过滤

对于每个模型,我将根据下面所示的算法在用户-项目矩阵和项目-项目相似性矩阵之间应用矩阵乘积:

模型 1:按项目类别过滤(图片按作者)

模型 2:按项目类别和价格类别过滤(图片按作者)

模型 3:按商品类别、价格类别和品牌过滤(按作者分类的图片)

一旦矩阵乘法完成,就再次应用最小最大缩放器来获得预测交互得分的训练的用户-项目矩阵。为了简化说明,我将演示模型 3 的代码,如下所示:

然后,经过训练的用户项目矩阵被重新转换回数据框,然后与验证数据集合并。同样,预测交互得分高于 0.5 的项目被标记为客户的预测购买。

现在,比较客户对三个模型的实际购买和预测购买,模型 3 似乎是最有希望的,具有最高的精确度,与模型 2 相比,在召回方面没有牺牲太多。尽管如此,所有模型的精度和召回率都非常低,正如我在 EDA 过程中的分析所预期的那样。

三种基于内容的推荐模型在简单验证中的性能。(图片由作者提供)

4.模型评估

选择模型 3 作为我的推荐系统的最终模型,我继续一起重新训练训练和验证数据集,然后在测试数据集上进行评估,实现了 5.0%的召回率和 7.8%的精确度。

测试集的混淆矩阵,显示召回率和精确度。(图片由作者提供)

然而,当我根据独特购买的数量来评估精确度和召回率时,一个有趣的趋势是显而易见的。对于至少购买过一次的客户来说,模型的精确度实际上要高得多!因此,这意味着当模型向购买的顾客作出推荐时,我们更有信心顾客会实际购买该产品。因此,最终没有购买的客户的预测购买的假阳性降低了模型的整体精度。

此外,据观察,购买更多产品的客户召回率更高。这可能是因为衡量模型的方式更偏向于购买客户。因此,可以做进一步的调优和调整来提高模型的召回率。

5.模型演示

在这一部分中,我将演示在训练/验证数据集和测试数据集内特定客户(用户 ID: 518044530)的用户-项目交互,以及模型将为客户提供的潜在建议。在训练/验证数据集中捕获以下用户-项目交互:

训练/验证数据集中的客户(用户 ID: 518044530)。

在测试数据集中,我们看到模型准确地预测了用户购买。这是因为在训练/验证数据集中,客户对类似项目的互动得分很高。

测试数据集中的客户(用户 ID: 518044530)。

从这位客户(用户 ID: 518044530)的热门推荐中随机抽取一个样本,我们看到该模型产生了与他/她之前互动过的相似类别、价格范围和品牌的产品:

针对客户的随机前 10 项建议(用户 ID: 518044530)

6.结论

该项目详细介绍了执行基于内容的推荐系统的端到端管道,并作为 Metis 数据科学训练营最终项目的一部分完成。尽管这个模型远非完美,但它展示了一个基于内容的推荐器是如何过滤多个类别的产品信息的。在未来,理想情况下,可以通过建立深度神经网络来尝试更有效的混合推荐系统。

在这次为期 12 周的训练营结束之际,我真的要衷心感谢我的天才导师尼奥·韩伟,他让我学到了很多东西,我还要感谢我的队友,特别是丹尼尔·张和李心妮,他们给予了我精神和情感上的支持,使这次学习之旅成为可能。

另外,如果你感兴趣,下面是我在训练营期间精心制作的一些其他项目的链接:

项目 3

[## 用分类预测航空旅客的满意度

案例研究与 KNN,逻辑回归,高斯 NB,决策树和随机森林。

towardsdatascience.com](/predicting-satisfaction-of-airline-passengers-with-classification-76f1516e1d16)

项目 2

[## 回归预测国际足联足球运动员的市场价值

线性、套索、岭、弹性网和多项式回归的案例研究。

towardsdatascience.com](/predicting-market-value-of-fifa-soccer-players-with-regression-5d79aed207d9)

项目 1

[## 探索性数据分析 Data 十字转门街道交通分析

Metis 数据科学训练营的一个简单的探索性数据分析项目

towardsdatascience.com](/mta-turnstile-traffic-analysis-to-optimize-street-engagements-a7391adc4d45)

P.S .如果你对 加速学习数据科学 感兴趣,这里还有一篇关于养成良好学习习惯的极其有用的文章:

[## 数据科学有效学习完全指南

让你在数据科学(或任何学科)领域飞速发展的基本指南

towardsdatascience.com](/a-brief-guide-to-effective-learning-in-data-science-637de316da0e)

最后,非常感谢您的阅读!这里是到我的 GitHub 的链接,它包含了这个项目的所有代码和演示幻灯片。也可以通过我的 LinkedIn 联系我或者在下面评论来讨论!

支持我! —如果你没有订阅 Medium,并且喜欢我的内容,请考虑通过我的推荐链接加入 Medium 来支持我。

[## 加入我的介绍链接媒体-谭师鹏阿尔文

阅读谭·师鹏·阿尔文(以及媒体上成千上万其他作家)的每一个故事。您的会员费直接…

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

着火的大陆

原文:https://towardsdatascience.com/a-continent-on-fire-a8cc7b47e0f2?source=collection_archive---------50-----------------------

使用 BigQuery Geo Viz 可视化野火

这张图片是在 知识共享 许可下授权的

澳大利亚的野火已经烧毁了超过 1070 万公顷的土地。客观地说,这比苏格兰或韩国的面积还要大。破坏的规模确实是空前的。这场大火已经夺去了几十条生命和五亿多只动物的生命。

这个周末,当我看着悉尼港上空的雨时,我不禁想知道是否有一种方法可以让我成为这个挑战的长期解决方案的一部分。火灾一直是这片土地的特色,而且只会越来越严重。作为小小的第一步,我想至少想象一下这些火灾发生在哪里。

进入 BigQuery 的魔力。

构建数据管道

BigQuery 托管各种不同的数据集,这些数据集可以公开访问。这是一个很好的数据探索资源。在这个存储库中,我找到了一个来自 NASA 的数据集,它提供了关于全球野火位置的数据。

该数据集涵盖了位置(纬度和经度),以及上周检测到的火灾的各种属性。对于那些希望更深入了解的人,我从下面的 NASA 网站上剽窃了广告词。我说得再好不过了。

可见红外成像辐射计套件(VI IRS)375m(vnp 14 imgtdl _ NRT)主动火力产品是最新加入公司的产品。它提供来自 NASA/NOAA Suomi 国家极地轨道伙伴关系(Suomi NPP)和 NOAA-20 卫星上的 VIIRS 传感器的数据。375 m 数据补充了中分辨率成像光谱仪(MODIS)火灾探测;它们在热点探测方面都表现出良好的一致性,但 375 米数据的空间分辨率的提高对相对较小区域的火灾提供了更大的响应,并提供了较大火灾周界的改进绘图。375 米的数据也提高了夜间性能。因此,这些数据非常适合用于支持火灾管理(例如,近实时警报系统),以及需要改进火灾绘图保真度的其他科学应用。推荐阅读: VIIRS 375 m 主动火力算法用户指南

数据集的大小约为 40mb。与 Bigquery 能够处理的万亿字节和千兆字节规模的数据集相比,这实在是小得可笑。

我决定用一个简单的 SQL 语句将所有数据复制到一个项目中。

CREATE OR REPLACE TABLE
 `as-ghcn.nasa_wildfire.past_week` AS
SELECT
 ST_GEOGPOINT(longitude,
 latitude) AS longlat,
 *
FROM
 `bigquery-public-data.nasa_wildfire.past_week`

我需要将纬度和经度数据(FLOAT值)转换成GEOGRAPHY数据类型。这是形成数据并为 BigQuery Geo Viz 做好准备所需的唯一一点预处理。我将查询安排在每周一运行,并用 NASA 的最新数据更新数据集。

探索数据

BigQuery Geo Viz 是一个使用 Google Maps APIs 在 BigQuery 中可视化地理空间数据的 web 工具。您可以运行 SQL 查询并在交互式地图上显示结果。这是一个轻量级工具,允许您快速、交互式地浏览空间数据。我无法强调这有多痛苦。没有基本地图的配置或加载。

下面的查询加载了数据集中被高置信度检测到的所有火灾。我放大了澳大利亚的东海岸来提供一个可行的例子。该样式仅用于示例目的。

澳大利亚东海岸的野火

由于底层的基本地图是由谷歌地图支持的,因此有许多丰富的纹理特征可供用户使用,例如提供地形和卫星信息的视图。

澳大利亚维多利亚州的大火

你应该知道这个工具有一些限制。

  • Geo Viz 在地图上最多只能显示 2,000 个结果。
  • Geo Viz 支持众所周知的文本(WKT)格式的几何输入(点、线和多边形),存储在STRING列中。您可以使用 BigQuery 的地理功能将纬度和经度转换为 WKT。
  • 实时、交互式分析由您的浏览器在本地处理,并受浏览器功能的限制。
  • Geo Viz 不支持与其他人共享可视化、保存可视化或下载可视化进行离线编辑。

我发现最后一个限制非常令人失望,我希望产品团队将来能让 GCP 的客户也能使用它。

展望未来

放眼澳大利亚之外,我想看看世界其他地方是否有大火在燃烧。乍一看,中非和东南亚的大部分地区似乎都着火了。这肯定会成为全球新闻吧?

我在网上简单查了一下,你看到的火灾很可能是低强度的农业火灾。农民们通常会点燃农田,烧掉剩余的草和灌木。这种燃烧有助于保持肥沃的土壤。我记得我在坦桑尼亚的时候。

虚惊一场?也许吧,但我们无法确定,因为世界上许多地方都没有报道或报道不足。

基于 Theil-Sen 回归的相关性度量

原文:https://towardsdatascience.com/a-correlation-measure-based-on-theil-sen-regression-31b8b9ed64f1?source=collection_archive---------27-----------------------

来源:https://www.tylervigen.com/spurious-correlations

A 关联和相关测量是描述性统计和探索性数据分析的重要工具。它们为变量之间的函数关系提供了统计证据。

一个流行的测量方法是皮尔逊相关系数 r(⋅,⋅。对于度量数据样本 xy ,给出如下:

其中 s(⋅,⋅) 是样本协方差, s(⋅) 是样本标准差。

如果我们把 n 观测值 xy 的序列看作欧几里得空间 ℝⁿ 中的向量,那么相关系数就可以被几何解释。首先,我们通过重新调整 xy 来标准化样本,如下所示:

其中 μ(⋅) 是算术平均值(从每次观察中减去)。这里我们假设使用无偏样本协方差,即因子为 1/(n - 1) 的样本协方差。然后,我们发现归一化样本位于单位球面上,相关系数是它们的点积:

这种高维几何解释有助于理解皮尔逊相关的一些重要性质。例如,我们立即理解,该度量允许我们比较归一化样本所指向的方向: r(x,y) = 1 表示它们指向相同的方向, r(x,y) = -1 表示它们指向相反的方向。如果 r(x,y) 消失,则矢量 z(x)z(y) 正交。我们甚至可以通过关系式 r(x,y) = cos(φ) 计算归一化样本之间的“关联角度” φ

相关和回归

皮尔逊相关系数的另一个有用解释来自基于最小二乘法的简单线性回归。(其他解释见罗杰斯和尼斯旺 1988 。)在最后一段中,我们将两个样本视为两个维度为 n 的向量。我们现在要把它们看成是二维的 n 个数据点。如果我们使用最小二乘法来确定通过这些数据点的最佳拟合直线,其中我们将 y 视为响应变量,将 x 视为解释变量,则该直线的斜率为 m(y,x) = s(x,y) / (s(x)) 。反之,如果我们把 x 作为响应变量,把 y 作为解释变量,回归线就会有斜率 m(x,y) = s(x,y) / (s(y)) 。首先,我们观察到,无论哪个变量被视为因变量或自变量,回归线的斜率都不会改变符号。这一点,再加上一点代数,让我们得出结论:

简而言之:皮尔逊系数是最佳拟合直线斜率的(带符号)几何平均值,您可以通过最小二乘法绘制数据点。这个等式非常清楚地表明,皮尔逊系数测量了 xy 线性相关的程度。它还表明,皮尔逊系数与最小二乘法一样容易受到异常值的影响:它通常不被认为是稳健的统计量。Anscombe quartet 是一个旨在展示此类漏洞的合成测试数据集。尽管四个数据集以散点图的形式呈现非常不同,但基于最小二乘法的回归线是相同的:

来源:维基百科

简单线性回归的最小二乘法的另一种选择是 Theil-Sen 估计。这种更稳健的方法通过所有可通过数据点绘制的直线的斜率的中值来确定回归线的斜率:

因此,使用皮尔逊相关系数和最小二乘回归之间的上述关系,我们现在可以制定一个与泰尔-森估计相关的变量:

如果中值斜率具有相同的符号,否则为零。然而,在斜率的符号改变时将测量值设置为零的条件可能看起来是人为的:

  • 当交换 xy 时,中间坡度通称为不改变符号,
  • 当它出现时, xy 之间的肯德尔等级相关性消失。

这可以看如下。假设单个斜率的 K 为负,N-K为正。交换 xy 意味着取斜率的倒数。对斜率排序以计算其中值揭示了以下关系:

我们可以看到,只有当负斜率和正斜率一样多时,中间值的符号才会发生变化。然而,这意味着肯德尔等级相关性τ消失,这可以从该度量的以下重写中看出:

我们可以在 Anscombe 四重奏上评估这个基于 Theil-Sen 的相关系数,并将其与 Pearson 系数进行比较。下表显示了这种比较,以及基于等级统计的另外两种流行的度量,Spearman 的ρ和已经提到的 Kendall 的τ:

可能有点令人惊讶的是,对于 Anscombe 4 数据集,Theil-Sen、Spearman 和 Kendall 相关性测量被证明是高度不稳定的:即使是最小幅度的任何噪声添加到数据点都会产生任意的相关性值。对于基于等级的 Spearman 和 Kendall 测量,这可以很容易地解释:如果大多数的 x 值是相同的或几乎相同的,数据中的微小变化可以产生任意的等级。

另一方面,Theil-Sen 估计器对回归线 m(y,x) 的斜率产生任意大的值,对 m(x,y) 产生任意接近于零的值,这导致在受到噪声影响时产生不明确的乘积。

一般来说,如果至少有一个要比较的样本只显示出很小的离差,那么相关测量将变得不可靠。对于稳健的相关性测量,这种离差应该通过稳健的方法来测量。Anscombe 4 数据集内的 x 值的中值绝对偏差消失,因此 Theil-Sen 估计相关性和等级相关性度量不明确也就不足为奇了。

摘要

稳健简单线性回归的 Theil-Sen 估计可用于定义相关性度量,类似于 Pearson 相关系数与最小二乘回归的关系。在 Anscombe 四重奏上进行评估,它显示出类似于等级相关性度量的特征,例如 Spearman 的ρ或 Kendall 的τ。

参考文献

安斯科姆,F. J. (1973)。“统计分析中的图表”。美国统计学家。27 (1): 17–21.

罗杰斯;西弗吉尼亚州尼斯旺德(1988 年)。“看相关系数的十三种方法”。美国统计学家。42 (1): 59–66.

森·p·k .(1968)。“基于肯德尔τ的回归系数估计值”。美国统计协会杂志。63 (324): 1379–1389.

希尔,H. (1950 年)。“线性和多项式回归分析的秩不变方法”。内德尔。阿卡德。韦滕施。,继续。53: 386–392.

在 1 毫秒内达到 99.9%准确率的 COVID 测试——如何实现?

原文:https://towardsdatascience.com/a-covid-test-that-is-99-9-accurate-in-under-1-millisecond-how-47a935d536b9?source=collection_archive---------34-----------------------

你甚至不需要去看医生。这项测试结果总是阴性。

来源:Getty Images

截至目前,美国有超过 43.5 万例 COVID 病例,美国人口为 3.27 亿。这大约是感染 COVID 人口的 0.13%,相当于每 1000 人中有 1.3 人受到影响。虽然这听起来确实是一个相当大的百分比,但是一个一直显示阴性的测试只有 0.13%的情况是错误的,或者对其余的 99.87%是正确的!

塞犍陀·维韦克

或者,公式中正确结果的数量将是(327,000,000–435,000 ),用这个数字除以美国人口=327,000,000 得出 0.9987 或 99.87%。这告诉我们准确性可能不是衡量测试有效性的最佳方式。那还有什么?

统计数据不会说谎。但是统计数据可能会被曲解。

精密

假设我有一个更好的测试。如果你超过 85 岁,有潜在的疾病,正在经历咳嗽,发烧,疲劳,呼吸困难,需要尽快接上呼吸机,你可能患有 COVID,你不需要我告诉你去医院并被隔离。这个测试比总是阴性的测试更加精确。

塞犍陀·维韦克

再次以美国的 Covid 案例为例。在疾控中心昨天发布的数据中,住院病例比例最大的来自于>85;85 岁以上的 10 万人中有 17 人住院。这如何转化为 85 岁以上住院的美国人总数?根据老龄管理局的数据,2016 年 85 岁以上的美国人有 640 万。这相当于大约(17/100,000)*6,400,000 = 1,088 名 COVID 超过 85 岁的住院患者。假设我有一个测试,说这 1088 人有 COVID。尽管它遗漏了具有 COVID 的(435,000–1,088)中的其余部分,但它非常精确。虽然这比显示所有人都是阴性的测试稍微好一点,但也没有好到哪里去。那么我的统计工具箱里还有什么呢?

召回

我检测了美国所有人的 COVID,只发现 1088 人呈阳性(85 岁以上和住院),这意味着我错过了所有其他人。然后我把测试结果为阴性的放回他们的社区,不进行隔离。后来,我发现我的测试遗漏了大量受感染的人。我该怎么办?我应该召回那些人,直到他们开始出现更严重的症状,或者直到我确定他们不会传染给其他人。同时希望能有更好的测试。对这些我最初遗漏的阳性病例,错误地标记为阴性的测量被称为召回,顾名思义就是。它与召回被认为是好的设备或汽车有关,但结果证明是有问题的,如电池烧毁或安全气囊问题。

塞犍陀·维韦克

在测试的例子中,精确地确定 1088 名患者为阳性,但忽略了其余的阳性人,则召回将是 1088/(435000)= 0.002 或 0.2%。这太令人沮丧了。所以这很好地确定了我们的测试没有那么好。理想的情况是,我们希望所有的阳性患者都被立即确认,以及我们社区中所有其他的阳性患者,我们不知道。但那是不可能的。相反,统计学家试图在精确度(我应该相信多少阳性结果)和回忆(被正确识别的感染百分比)这两个最重要的因素之间找到平衡。

F1 分数

精确度和召回率之间的平衡是两者之间的调和平均值,称为 F1 得分

塞犍陀·维韦克

在上面的例子中,对于精确测量的 1088 名患者,precision=1,recall=0.002。F1 得分=2(10.002)/(1+0.002)=0.004。这表明测试做得不好,但比仅仅回忆好一点。

然而,这绝不是全部情况。考虑相反的情况。天理不容;美国有 3 亿人患有 COVID。记住美国人口是 3.27 亿。让我们考虑相反的第一个例子:一个分类器,说每个人都是积极的——并迅速重新计算所有的分数:

  1. 准确度。我已经正确识别了 300,000,000 个具有 COVID 的。然而,我错误地将 27,000,000 个额外病例识别为阳性,尽管它们是阴性的。精度为 300,000,000/327,000,000 =0.92
  2. 精度。这种情况下精度相同 =0.92 (感谢@lena 的修正)
  3. 回忆。我不需要回忆任何积极的东西,因为我现在正确地识别了所有积极的东西+ 27,000,000。召回 =1
  4. F1 比分。由于 F1 得分只是精度和召回率的组合,所以 F1 得分= 2 *(1 * 0.92)/(1+0.92)= 0.96

奇怪的是,在这个例子中,当我们面对相反的问题时,所有的测试似乎都失败了!然而,这并不是最糟糕的情况——更多的人被隔离总比没有好。这说明了阶层不平衡的问题。更高级的测试包括马修斯相关系数,这是一个更复杂的公式。该系数是一个平衡的度量,即使班级大小相差很大也可以使用。

总之,我已经展示了统计数据是如何经常误导人和难以解释的。简单的测试准确度是不够的,要谨防社交媒体上传播虚假信息和神奇测试的文章。流行病学家、疾控中心的人、医生以及医院都应该得到掌声。他们必须收集数据,进行统计分析,并以清晰、易懂的方式同时以正确的方式传达所有这些信息;因此,我们不会错误地解读数据显示的内容。下一次有人说某项测试有 90%的准确率时,想想为什么它可能没有那么有用。

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

来源:

  1. https://en . Wikipedia . org/wiki/2019% E2 % 80% 9320 _ 冠状病毒 _ 疫情 _ 按国家和地区
  2. https://www.cdc.gov/mmwr/volumes/69/wr/mm6915e3.htm
  3. https://ACL . gov/sites/default/files/Aging % 20 和% 20 disability % 20 in % 20 America/2017 olderamericansprofile . pdf

版本控制和 Git & GitHub 速成班

原文:https://towardsdatascience.com/a-crash-course-on-version-control-and-git-github-5d04e7933070?source=collection_archive---------47-----------------------

约翰·霍普斯金 DS 专业化系列

关于版本控制系统、Git & GitHub 和 VCS 的最佳实践

UnsplashGreg Rakozy 拍摄的照片

[Full series](https://towardsdatascience.com/tagged/ds-toolbox)[**Part 1**](/the-data-scientists-toolbox-part-1-c214adcc859f) - What is Data Science, Big data and the Data Science process[**Part 2**](/how-to-learn-r-for-data-science-3a7c8326f969) - The origin of R, why use R, R vs Python and resources to learn[**Part 3**](/a-crash-course-on-version-control-and-git-github-5d04e7933070) - Version Control, Git & GitHub and best practices for sharing code.[**Part 4**](/the-six-types-of-data-analysis-75517ba7ea61) - The 6 types of Data Analysis[**Part 5**](/designing-experiments-in-data-science-23360d2ddf84) - The ability to design experiments to answer your Ds questions[**Part 6**](/what-is-a-p-value-2cd0b1898e6f) - P-value & P-hacking[**Part 7**](/big-data-its-benefits-challenges-and-future-6fddd69ab927) - Big Data, it's benefits, challenges, and future

本系列基于约翰·霍普斯金大学在 Coursera 上提供的 数据科学专业 。本系列中的文章是基于课程的笔记,以及出于我自己学习目的的额外研究和主题。第一门课, 数据科学家工具箱 ,笔记会分成 7 个部分。关于这个系列的注释还可以在这里找到

介绍

如果你是计算机科学的初学者,或者你是一个刚刚开始学习编程基础的初学程序员,无论你是在学习 C、Swift、Python 还是 JavaScript,你肯定会在你的在线课程或 YouTube 视频教程中遇到版本控制。一开始,Git 和 GitHub 这两个词对你来说可能是陌生的,但是一旦你开始编写代码并在线分享,你就会在日常生活中使用它们。这里有一个版本控制和 Git 的快速介绍,以及学习它们的资源。

Git & GitHub

Git 和 GitHub 是每个程序员、数据科学家、机器学习工程师、web 开发者、全栈开发者等事实上的版本控制工具。用途。

Git 是什么?

由于它的速度和灵活性,Git 基本上是一个非常强大的源代码控制系统。虽然您可以通过使用 Git 的基本命令来完成这项工作,但是对于初学者来说,这可能是相当具有挑战性的,

虽然 Git 的名字是 GitHub,但它们是两个独立的东西,因为 Git 在 GitHub 之前就存在了。还有其他地方可以托管您的 Git 存储库,但是 GitHub 是最受欢迎和使用最广泛的站点。

什么是 GitHub?

因此 GitHub 只是一个让你管理你的 git 仓库的网站,还有很多其他的平台,像 BitBucket,Digital Ocean,Azure DevOps,但是 GitHub 有漂亮的用户界面并且很容易使用。

一个人能做什么 GitHub?

在 GitHub 上,您可以:

  1. 在线共享代码,并在改进程序时不断更新它,不受本地机器的限制,
  2. 为你的雇主创造一个震撼的投资组合,让他们惊叹你的能力。
  3. 它也是一个充满学习资源、解决方案和在线课程笔记等的地方。
  4. 为开源项目做贡献,培养你的技能。
  5. 与其他开发人员合作开发酷项目
  6. 叉很酷的项目,并以此为乐
  7. 等等。

为了有效地一起使用 GitHub 和 Git,您必须理解版本控制到底是什么,以及最常用的命令来增强您的工作流,使您成为一个更有效的程序员。

版本控制

卢克·切瑟在 Unsplash 上的照片

什么是 VCS?

版本控制系统(VCS)顾名思义很直观,它基本上是一个帮助你跟踪源代码或文件变更的工具集合。它维护了变更的历史,并促进了与其他开发人员的协作

你可以把 VCS 的工作想象成对你的代码和文件中的变更进行快照,并把信息存储为解释为什么做出变更以及是谁做出变更的消息。

为什么用 VCS

也就是说,VCS 非常乐于助人,主要有三个原因。

  1. 你的作品历史快照。—如果您想回顾项目的旧快照,以了解为什么进行了更改,同时像 Google Drive 一样作为备份存储。它还允许你在任何地方搜索你的代码或项目,只要你能登录到你的 GitHub 账户。
  2. 允许协作并处理冲突 —编程时协作是巨大的。协作时的一个主要问题是冲突,当两个人处理同一个文件,并上传他们各自的更改时,只有一个更改会被做出,而另一个会丢失。像这样的问题由 Git 处理,你可以在 GitHub 干净的 UI 上查看所有的问题和请求。
  3. 分支实验 —有时你想尝试一些新的东西,所以你会想复制你的代码,改变一些东西,而不影响你的原始源代码。这叫做分支,和 app 向公众发布 beta 程序一样,是主程序的分支。

基本 VC 词汇

  • Repository —项目文件夹或目录,所有 VC 文件都在这里
  • 提交— 保存所做的编辑和更改(文件快照)
  • 推送 —用您的编辑更新存储库
  • —将您的本地版本的回购更新到当前版本
  • 暂存 —准备提交文件
  • 分支 —具有两个同步副本的相同文件,创建一个分支以进行尚未与主回购共享的编辑
  • 合并 —分支合并回主回购,同一文件的独立编辑合并成一个统一的文件
  • 冲突 — 当两个人编辑同一行代码时,就会发生冲突,要么保留其中一个,要么保留另一个
  • 克隆(仅在本地机器上) —制作包含所有跟踪变更的 repo 副本
  • Fork(保留在 GitHub 中) —另一个人的回购的副本,编辑记录在您的回购上,而不是他们的

所以,VCS 的一个基本流程是——文件存放在与其他编码者在线共享的仓库里。你克隆你的回购,让本地拷贝编辑它。在做出更改之后,您存放文件并提交它。然后,你推动提交共享回购协议,在那里新文件在线,并有消息解释什么改变了,为什么改变,由谁改变。

Git 命令

如果有一天你想成为一名优秀的程序员,你应该记住一些基本的 git 命令。

以下是将 repos 克隆到本地机器时将使用的命令列表。

如果你还没有把你的机器连接到你的 GitHub 账户,那么在学习 Git 之前先这样做。这里有一篇约瑟夫·罗宾逊写的关于如何做到的文章。

基础

*git help  (get help for a command)# creating a new repo1\. git init  (let's you create a new git repo, stored in .git.)
2\. git add . (add your files)
3\. git commit -m "message"
4\. git push # cloning from repo on GitHub1\. **git clone** "url" 
2\. git status (tell's you which files have been staged)
3\. **git add .** (use . to add all unstaged files, specify files with <filename>)
4\. **git commit -m "message"** 5\. **git push*** 

这些命令是非常基本的,如果你想了解更多,可以参考这个神奇的网站

大多数人使用终端来运行这些命令,但也有其他选择来做 VCS,比如如果你喜欢点击而不是打字,可以使用 GitHub 桌面。ide 也很有用,因为它们内置了 Git 和 GitHub 特性,你可以无缝地使用它们。

VCS 的最佳实践

当你刚开始使用 VCS 时,你可能不知道什么时候提交代码,或者如何最好地使用 VCS,所以这里有一些有用的提示。

  1. 有目的地提交 —你的提交应该是有目的的,而不是琐碎的,它应该对你的代码做出实质性的改变。例如,键入一行新代码并提交是无效的,并且会妨碍您的工作效率。
  2. 关于提交的信息性消息 —您的提交应该有充分解释为什么做出某个更改的消息,以便将来您可以回去参考它。这也有助于其他人合作理解这些变化。
  3. 经常拉和推 —在进行公开回购时,拉是很重要的,这样你就可以随时了解最新的变化,你也应该经常推,让你的变化在 GitHub 上得到更新。
  4. 更多提示此处

摘要

照片由 Fotis FotopoulosUnsplash 上拍摄

获得并掌握 Git 对你成为程序员、数据科学家、web 开发人员等非常有帮助。

编写程序、创建游戏、网站、个人作品集、机器学习模型、移动应用程序等,所有这些都需要版本控制系统来帮助你有效地管理它们,当你开始与他人合作时,你会发现这是多么重要。

Github 是一个令人惊叹的网站,它不仅可以作为你的作品集,GitHub 上有大量的宝石,共享一个巨大的资源列表,这对初学者特别有帮助。

如果你正在寻找很酷的东西,GitHub 收藏是一个很好的起点。

如果您正在寻找数据科学资源,请查看我的文章

感谢阅读,我希望你学到了一些东西。一定要看下一部分,记得注意安全。

学习 Git 的资源

* [## 书

由斯科特·沙孔和本·施特劳布撰写并由 Apress 出版的 Pro Git 整本书可以在这里找到。所有内容…

git-scm.com](https://git-scm.com/book/en/v2) [## 给初学者的 Git:权威实用指南

锁住了。这个问题和它的答案被锁定是因为这个问题跑题了但是有历史意义。它…

stackoverflow.com](https://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide) [## 版本控制

版本控制系统(VCS)是用来跟踪源代码(或其他文件和…

missing.csail.mit.edu](https://missing.csail.mit.edu/2020/version-control/) [## 饭桶

Git 是一个分布式开源源代码控制(也称为“版本控制”)系统,通常用于跟踪…

www.fullstackpython.com](https://www.fullstackpython.com/git.html) [## 学习 Git 分支

一个交互式 Git 可视化工具,用于教育和挑战!

learngitbranching.js.org](https://learngitbranching.js.org) [## 了解 Git- Git 教程、工作流和命令| Atlassian Git 教程

定义:一个分支代表一个独立的开发路线。分支是对…的抽象

www.atlassian.com](https://www.atlassian.com/git)

如果您对学习数据科学感兴趣,请查看“超学习”数据科学系列!

[## 如何“超级学习”数据科学—第 1 部分

这是一个简短的指南,基于《超学习》一书,应用于数据科学

medium.com](https://medium.com/better-programming/how-to-ultralearn-data-science-part-1-92e143b7257b)

查看这些关于数据科学资源的文章。

[## 2020 年你应该订阅的 25 大数据科学 YouTube 频道

以下是你应该关注的学习编程、机器学习和人工智能、数学和数据的最佳 YouTubers

towardsdatascience.com](/top-20-youtube-channels-for-data-science-in-2020-2ef4fb0d3d5) [## 互联网上 20 大免费数据科学、ML 和 AI MOOCs

以下是关于数据科学、机器学习、深度学习和人工智能的最佳在线课程列表

towardsdatascience.com](/top-20-free-data-science-ml-and-ai-moocs-on-the-internet-4036bd0aac12) [## 机器学习和数据科学的 20 大网站

这里是我列出的最好的 ML 和数据科学网站,可以提供有价值的资源和新闻。

medium.com](https://medium.com/swlh/top-20-websites-for-machine-learning-and-data-science-d0b113130068) [## 开始数据科学之旅的最佳书籍

这是你从头开始学习数据科学应该读的书。

towardsdatascience.com](/the-best-book-to-start-your-data-science-journey-f457b0994160) [## 数据科学 20 大播客

面向数据爱好者的最佳数据科学播客列表。

towardsdatascience.com](/top-20-podcasts-for-data-science-83dc9e07448e)

连接

如果你想了解我的最新文章,请通过媒体关注我。

也关注我的其他社交资料!

请关注我的下一篇文章,记得保持安全!*

一份简历不足以让你得到一份数据科学的工作

原文:https://towardsdatascience.com/a-cv-isnt-enough-to-land-you-a-data-science-job-38db16c6f221?source=collection_archive---------46-----------------------

如何在简历之外成为更有吸引力的数据科学候选人

Felicia Buitenwerf 在 Unsplash 上拍摄的照片

介绍

在我上一篇文章的后面, 找到一份数据科学的工作比以往任何时候都难 我在 LinkedIn 上收到了很多关于如何对雇主更具吸引力的回复。

[## 获得数据科学工作比以往任何时候都难

以及如何利用找工作的困难成为你的优势

towardsdatascience.com](/getting-a-data-science-job-is-harder-than-ever-fb796aae1922)

在获得数据科学工作方面,我绝不是专家,但我非常幸运地接触到许多从事数据科学家工作的人,在招聘领域担任招聘人员的人,以及每天审查数百份申请的经理。

许多人可能不同意,我讨厌打破它。一份简历是远远不够的。

通过追溯单词resume viate(CV)的来源,我发现这是一个拉丁短语,大致翻译为“我的生命历程”。换句话说,简历非常适合总结经验、成就和个人技能。对你生活的初步总结可能会让你表现出兴趣——以面试的形式(或公司采取的任何阶段)——然而,兴趣并不总是超越吸引力。

为了明确这两个术语之间的区别,我将兴趣定义为从方法上评估一个人是否适合长期投资的好奇心,我们将吸引力定义为身体或情感上渴望接近某人的迹象,从商业角度来说,这意味着无论是谁雇佣你都希望你加入他们的团队。

为了获得下一份工作,我一直在和各种各样的人交谈,考虑如何提升自己,让自己成为对雇主更有吸引力的候选人,从而增加我获得更理想职位的机会,以下是我想到的两个常见的想法:

为开源做贡献

为开源做贡献是立即从雇主那里获得更多吸引力的一个很好的方式,因为这告诉他们如果他们雇佣你,他们能从你那里得到什么。

这里有一个关于现代社会的简单事实(也许它只适用于技术工作,但我不确定),无论你申请哪里,鉴于他们喜欢你的简历,随之而来的是谷歌搜索。

当你的名字在谷歌上被搜索时,你想得到的第一件事就是数据科学。

开源的本质很自然地把我们推到了舒适区的边缘。无论是修复 scikit-learn 框架中的一个错误,还是为 Tensorflow/PyTorch 创建一个初学者指南,或者部署您自己的机器学习 API,贡献(以及持续贡献)都会让我们立即对雇主更具吸引力,因为它展示了任何雇主都想要的 3 个主要特征:

  • 你很好奇
  • 你是一个初学者
  • 你决心提高自己/是一个积极主动的人

我们在总结部分简单地写下“我是一个好奇的人,喜欢学习”的日子已经一去不复返了,当我们积极地为社区做贡献时,这些事情实际上是推断出来的,因为我们被视为一个想要推动社区发展的人。

注意:对开源做出贡献的一种常见方式是一个文档化良好的项目

[## 如何让你的数据科学项目脱颖而出

创建有效的自述文件

towardsdatascience.com](/how-to-make-your-data-science-projects-stand-out-b91d3861a885)

网络

很可能你的理想工作会有成百上千的其他人申请,就像你一样,他们相信自己非常适合这个角色,因此吸引公司的注意力是找工作时要克服的最重要的障碍之一。

我喜欢 T4 的杰米·哈里斯的说法:

“因此,求职不仅仅是一场技能竞赛:在很大程度上,这也是一场带宽竞赛。”

与人建立真诚的关系是非常重要的,因为如果他们将你的申请推荐给他们的公司,这很可能会比那些通过一些工作网站上的 easy apply 提交申请的人更有影响力。

我个人认为,最好的方式往往是通过已经在你感兴趣的公司工作的人,尤其是如果你可以完全跳过简历筛选这一步——这就是我如何获得上一份工作的,我是根据经验说的。

在 Covid 改变世界之前,meetup 是我经常去的地方——即使我有工作,我也会去 meetup,不是因为我在搜索,而是因为建立你的联系和发展关系在任何行业都很重要。因此,我主要是在 LinkedIn 上,我现在意识到这并不是那么糟糕。

[## 每个有抱负的数据科学家需要了解的网络知识

一个典型的数据科学职位发布可以吸引数十甚至数百份申请。出于这个原因,最…

towardsdatascience.com](/what-every-aspiring-data-scientist-needs-to-know-about-networking-475cfaac15f8)

注意:上网时做好自己。不要说你不会当面说的话——那很奇怪。

包裹

对我来说,通过积极地把自己放在外面,把求职掌握在自己手中,是让自己成为更有吸引力的候选人的方法,因为这需要大量的承诺,在我看来,这让你在雇主面前更可信。另一方面,一份经过精心优化的简历最有可能获得许多雇主的关注,并仍有可能获得许多机会。

你同意/不同意这个帖子吗?让我们继续 LinkedIn 上的对话…

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/?originalSubdomain=uk)

涉足推特分析

原文:https://towardsdatascience.com/a-dabble-into-tweet-analysis-a-beginners-approach-6079ad4b23f9?source=collection_archive---------29-----------------------

快速探索 Twitter 上容易获得的数据,使用数据科学方法优化您的推文:一些可视化、相关性和 NLP。

发微博是我们很多人都在做的事情,但是我们当中有多少人真正去探究是什么让我们的微博成功了呢?我想相对于那些知道的人来说,相对来说很少。我一直在自学一些数据科学技能,我想在一些真实数据上测试我的技能。

我想,我感兴趣的东西会是一个很好的开始:我经常使用 Twitter,大部分时间都在发推特,所以在我看来尝试一下是有意义的。另一个关键点是,我最近发现我可以点击一个按钮导出我的推文数据,这样有助于决定做什么!

我敢肯定,我不是一个人说,我听到很多人说,如果你有更多的标签,你会得到更大的影响,或者如果你在你的推文中加入媒体,人们更有可能参与进来。我想弄清楚这是不是真的,但也想利用我已经开始掌握的一些数据科学技能。

现在,我肯定还有更详细的分析,来告诉你你的推文表现,在这里我将告诉你我的思考过程和我的发现。

获取数据

我没有注册 Twitter 的开发者账户,我使用的数据对所有用户开放。在你的电脑上,打开 Twitter,点击左侧面板中的“更多”,然后选择“分析”。

指向分析的 Twitter 截图

一旦你这样做了,一个新的标签将会打开。点击页面顶部的“tweets”链接,它会告诉你你的 Tweets 表现如何,最重要的是一个导出数据的按钮。我导出了按“Tweets”而不是“Day”分类的数据,因为这是我更感兴趣的。

Twitter 的屏幕截图,用于指导导出数据

这里要注意一点:虽然你可以在 Twitter 分析界面上查看长达 3 个月的数据,但你只能导出其中的 28 天。很遗憾,但不是世界末日。

初始清洁和探索

与所有数据项目的开始一样,我们需要知道我们已经获得了哪些数据,并对其进行清理,以便它处于适合我们使用的状态。一开始,我有许多列数据,其中许多我并不关心。

我删除了所有只包含空值的数据,以及所有与“推广”推文相关的列。我不推广我的任何推文,所以这与我无关。我期望所有这些都是 null,但是数据在那里放了一个'-',所以我最初的删除没有影响这些列。在我最初的筛选和清理之后,我只剩下了下面这些我想要的格式的专栏。主要是,这意味着丢掉我不感兴趣的东西,确保数字就是数字,日期就是日期。我做的唯一更复杂的操作是将给定的“时间”列分成日期和时间部分。

初步查看我的数据

过去,关于我的推文的影响范围,我想到了几个问题:是否有一天/一个月的某个时间意味着我的推文会更成功?我发现一个快速的情节是获得正在发生的事情的快照的最简单的方法。

绘图显示几天内的印象数

事实证明,绘制每条推文在一段时间内获得的印象数并没有多大帮助。我认为这是由多种因素造成的:上个月我只发了大约 80 条微博,而我只有这么短时间的数据。更有用的数据表示可能是查看一天中每个小时的印象数:

绘图显示一天中不同时间的印象数

现在,这更有趣了——我可以看到我在上午和下午之间最频繁地发微博,而在晚上很少。通常(除了这里的一个异常)在这段时间的推文。这很可能是因为在这段时间里,我的目标受众中有更多的人是清醒和活跃的。我知道我在世界各地都有联系人——我在学术 Twitter 环境中特别活跃,所以理论上说,一天到晚都有观众!如果你发微博的频率比我高,或许一天中比我多一点,这个图可能对你更有用。

剩下的数据呢?

上面,我只看了其中的两列,但是其他的呢?比较两列的所有组合效率太低。回顾这些数据,我想看的东西和变量有很多,它们可能彼此相关,因此相关矩阵似乎有助于这种情况:

数值数据的相关图

在开始看矩阵之前,在你的头脑中有一个好主意,你的因变量和自变量是什么。这将帮助你看到你可以改变和影响什么来创造你想要的效果。

看这个相关图,互动和媒体互动之间有很高的相关性(0.97)。这意味着人们越来越多地参与媒体的推文,但这是有意义的参与吗,即我关心的参与,即喜欢/回复/关注等。查看媒体参与栏,媒体参与与除 url 点击之外的所有点击都呈正相关(这是意料之中的,因为 twitter 显示推文的方式:媒体优先于 URL)。我的推文中的媒体与我最关心的参与度的喜欢和关注度最高。

URL 点击与数据中的所有其他属性具有低相关性或负相关性。看起来带 url 的推文最有可能被转发,而不是其他任何东西。

自然语言处理

如果我想了解我的实际推文在说什么,就需要进行一些文本分析。我想看看标签的影响,以及它们如何影响我的推文的“成功”。我还想看看我的推文的情绪是否与它们的成功有任何关系,即我快乐的推文是否比我不快乐的推文更成功?

为了解决第一点,我收集了所有的推文,并计算了每条推文中的标签数量。我将这个值作为一个新列添加进来,并重新运行我的相关矩阵。

数字数据的相关图,加上标签数

标签的数量与印象的数量最相关,其次是转发和标签点击。一般来说,更多的标签意味着更高的印象,这是有道理的,但由于这不是一个高相关性,这表明并不是所有的标签都对印象有用。

考虑到我的推文的情感,我使用了一个内置函数来为推文文本赋值。在大约 80 条推文中,超过一半是正面的,最少的是负面的:

显示发送的推文的情绪的图

但这对我在推特上获得的印象和有意义的参与有什么影响呢?

带有数字数据的关联图,包括标签号和推文情感值

简而言之:不太多。所有的价值观和情绪之间都有轻微的负相关,除了一个:回复。然而,这里的相关性是如此之小,以至于我发送的推文数量不太可能对我的推文成功产生重大影响。

我发现了什么?

从这个初步的分析中,我想我发现了以下几点:

  1. 我发推特的时间可能是“成功”的标志,但我需要更多的数据来确定这一点。从我有限的数据来看,上午晚些时候到下午三点钟似乎得到了最多的印象。
  2. 媒体可能会增加我的推文的参与度。
  3. 仅仅增加一条推文中的标签数量并不能保证这条推文更“成功”——关键是要仔细挑选标签。
  4. 我的推文有多开心对它们的“成功”没有重大影响。

最重要的是,我已经很好地利用了我的数据大脑,将我的知识应用到现实世界的例子中,并有可能提出一个更“有效”的推特策略。

基于这一分析,我不能说我会在如何发推特上有很大的改变:我会更肯定地包括媒体,我会对我使用的标签很挑剔——无论如何我都会尝试这样做。

毫无疑问,更深入的分析可能会提供更多关于我如何才能更成功的信息。或许我可以看看“最成功”的标签?或者我可以收集更多的数据来观察一段时间内的模式。当然,有许多选择可以探索。目前,这个初步的分析,使用了我一直在学习的一些技巧,给了我 Twitter 性能的一个基本指标。

如果你对我如何实现我的分析感兴趣,请随时联系/评论,我很乐意分享。我用 Python 做了所有的事情,因为它是我的首选语言,但毫无疑问还有其他的方法。

民主辩论的数据分析

原文:https://towardsdatascience.com/a-data-analysis-of-the-democratic-debates-670926568b16?source=collection_archive---------31-----------------------

戴维·拉古萨在 Unsplash 上的照片

谁在说话,他们在说什么?

随着民主党初选的升温和辩论人数的增加,很难理解候选人在说什么。然而,由于有了在线辩论记录,检索曾经说过的每一句话变得相当容易。

让我们处理和分析文本数据,探索到目前为止发生了什么,而不是进行阅读这些文字记录的枯燥练习。

数据采集和处理

以下是我获取和处理分析数据的 5 个步骤。我建议您跳过这一部分,除非您对技术细节感兴趣:

  1. 从一个名为 Rev.com的网站复制每场辩论的文本,并将数据存储在一个 python 字符串中。
  2. 在空白处拆分每个辩论字符串,并为发言者创建一个列表,为他们的相关引用创建一个列表。
  3. 将演讲者和引语列表压缩在一起,并将其转换为熊猫数据帧,其中每行代表候选人的一个不间断行。
  4. 将辩论数据帧结合在一起,为每个辩论添加一个标识符。
  5. 清理和规范候选人姓名。

分析

谁在说话?

让我们先来看看每位候选人在整个辩论中的参与程度。为了衡量参与度,我们将计算每位候选人的发言占总字数的百分比。我们将只包括出现在大多数辩论中的参与者,并排除前两次辩论,因为它们都发生在两个晚上。

首先映入我眼帘的是大量的辩论。在总共近 4000 名代表中,只有 65 名代表获奖,候选人已经 9 次登上舞台。同样值得注意的是,速度已经从 2019 年底的每月一场辩论增加到 2020 年的每两周一场。

随着辩论频率的加快,发言的分布更加紧张。在第三场辩论中,领先的候选人(拜登)和落后的候选人(桑德斯)之间的差距为 12%。到第九次辩论时,这一比例仅为 3%——基本上是五方平手。

这可能是两种情况的产物。首先,范围缩小了,主持人更容易确保候选人有平等的发言时间。其次,随着最近几周赌注的增加,候选人变得更加直言不讳。

另一个有趣的趋势是——对于许多候选人来说——所说的单词的%与主要表现相关。

这方面最强有力的例子是伊丽莎白·沃伦,她的平均民调支持率从 10 月份的 22%骤降至 2 月份的不到 13%,这反映了她说的话的百分比从 24%降至 14%。

虽然很难确定其中的因果关系,但这种相关性可能有几个原因。也许主持人会根据谁在民意调查中领先来调整他们的提问行为。或者可能是候选人缺乏攻击性让潜在选民望而却步。最后,候选人可能倾向于挑战和激怒他们认为最大威胁的竞争对手。

不管原因是什么,沃伦的团队很可能在内华达州之前发现了这一趋势——在内华达州,她是所有候选人中发言次数第二多的。

另一方面,从 9 月到 2 月,随着他的辩论参与率稳步上升,伯尼·桑德斯在全国民调中的平均支持率呈指数上升:

他们都说了些什么?

既然我们已经看了谁在讲话,让我们感受一下他们都在谈些什么。

首先,我们来看一个单词云,它向我们展示了候选人辩论中最常用的单词。我已经排除了停用词——没有太多语义价值的常用词——并采用了一种叫做词条化的方法来将单词简化到它们的核心意思,而不管它们的词性。

这里没有什么大的惊喜——候选人试图吸引 ,并解释他们 认为 什么,他们 打算 做什么,作为 总统 让这个 国家 变得更好。

也许更有见地的分析应该是看看候选人的用词是如何变化的。下面,我创建了一些更频繁出现的单词以及每个候选人使用它们的频率的热图。颜色越深,候选人使用的单词越多。

让我们浏览一下 10 个最有趣的单词和要点:

  1. 人物:桑德斯用这个词最多。这是有道理的,因为他被视为一个平民主义候选人,期待开始一场政治革命。
  2. 总统:Buttigieg 使用“总统”这个词的频率最高——也许是作为一种被认为是最“总统化”的策略
  3. 想一想:克洛布查尔以压倒性优势赢得了这场比赛。她经常以“我认为”作为自己观点的开头。我认为这与其说是缺乏自信,不如说是一种风格上的问题。
  4. 需要:沃伦把自己定位成一个能干的、解决问题的人,她知道这个国家及其人民需要什么。也许这也是她使用“家庭”和“工作”这两个词最多的原因。
  5. 特朗普:沃伦和拜登最少提到总统的名字。我想知道这是否是一个有意的举动,因为特朗普似乎受益于降名,有好有坏。
  6. 完成:拜登和克洛布查尔谈了很多关于他们所做的。这是有道理的,因为他们的吸引力很大一部分是经验。拜登从 1972 年到 2008 年担任了 8 年的副总统和参议员。Klobuchar 在明尼苏达州担任了三届参议员,是参议院中最活跃的人之一。这是与 Buttigieg 或 Steyer 等传统经验较少的候选人的一大区别。**
  7. ****事实:拜登使用填充短语“事实上”的频率很高,是第二名的两倍多。
  8. 气候:对于那些不太熟悉斯泰尔的人来说,这可能是一个惊喜,但是这位亿万富翁民主党人说他的首要问题是气候变化,并且他在辩论中支持这一点。
  9. 医疗保健:桑德斯在这一领域领先。他是拥有最独特的医疗保健计划(全民医保)的候选人,而且他不得不花大部分时间来捍卫其成本和可行性。使用“医疗保健”一词第二多的沃伦也同意桑德斯的计划,但自以来,她的立场已经软化
  10. 变革:这一点非常接近,因为大多数民主党人认为自己是变革的代表。但同样,桑德斯是最有兴趣改变政党和国家政治方向的候选人。

后续步骤

我在上面所做的仅仅触及了辩论笔录的表面。以下是扩展这一分析的三个想法:

  1. 探究候选人的词汇用法是如何随着时间的推移而变化的。
  2. 使用像 word2vec 这样的单词嵌入来衡量每个候选人之间的差异。
  3. 建立一个“谁说的”分类模型来预测哪个候选人说了给定的报价。

用 R 创建个人网站的数据分析师指南

原文:https://towardsdatascience.com/a-data-analysts-guide-to-creating-your-personal-website-with-r-f0079ba9b81c?source=collection_archive---------3-----------------------

忘记 Wix 或 WordPress,利用你已经知道的东西来编写你自己的站点

如果你看这篇文章有困难,你可以通过下面的链接访问我的网站,绕过 Medium 的付费墙。尽情享受吧!

[## 鲍比·马尔乔诺

数据分析师

www.bobbymuljono.com](https://www.bobbymuljono.com)

李·坎贝尔在 Unsplash 上的照片

你个人网站的重要性

对数据科学工作的需求一直在上升,申请人也加入了这一行列。由于硕士或博士是最主要的筛选条件,人力资源经理会毫不犹豫地拒绝简历平平的申请人。

一个展示你处理数据科学或分析项目能力的网站是从其他申请者中脱颖而出的一个很好的方式,尤其是如果你没有任何高等学位。

但是打住,我不知道 HTML/CSS/JS 建一个网站

如果你正在阅读这篇文章,那么你可能对数据分析感兴趣,或者你已经在处理大量的数据管理工作,并且你不会以任何特定的方式处理 HTML/CSS 代码。

无论您是数据分析师还是数据科学家,我们都同意一件事:我们的一般工作包括理解业务问题,使用定制的 SQL 查询提取必要的数据,使用 Python/R 清理和验证它们,最后可视化它们或执行某种预测以增强运营业务决策。

通常这个过程就是我们所说的模型级分析。这是大多数公司在将数据转化为可操作的见解时所寻求的基本要求。在这种情况下,您可能只需要处理很少的文件和脚本来提取和处理数据。

然而,当我们想到在移动中实现数据科学时,如 Youtube 的推荐系统,我们需要开始研究协作和 生产级脚本。这就是当您与一组数据科学家一起工作时,文件管理和版本控制变得非常重要的地方,这些科学家在一个给定的项目中分担他们的工作量。

当您构建网站时(我不是在说 Wix 或 WordPress 这样的高级网站构建者),您将处理大量 HTML/CSS 文件,这些文件将存储在您的计算机或 Github 存储库中以供部署。这是习惯生产级脚本的好方法。

好消息是。

你不需要知道任何 HTML/CSS 来用我们很多人都熟悉的东西,R 编程或 Python 来构建网站。然而,某些布局定制可能需要用户冒险进入 HTML 并修改几行代码。

你将学到什么

  1. 基本 Git 和 Github 导航
  2. 基本的 RStudio IDE(真见鬼,你甚至不需要接触任何 R 代码)
  3. 创建具有预定义主题的内容(这是困难的,但是一旦你习惯了,就可以管理)
  4. 网站部署和维护

在我开始之前,我必须表扬该表扬的地方。在我建立自己的网站之前,我从来没有想过用 R 来做这件事是可能的,因为 R 不是为建立网站而设计的。我只是浏览了 TDS 上的几篇文章,偶然发现了叶君写的这篇文章,他用 r

[## 用四个步骤让你自己的网站上线

使用 R Blogdown 的简单指南

towardsdatascience.com](/get-your-own-website-online-in-four-steps-adef65abe8bd)

我从他的教程中得到了一些提示,但是我用一个稍微不同的工作流程建立了我的网站:

记住整个工作流程,你应该能够创建一个自己的网站。

步骤 1–1:设置 R、RStudio 和您的项目

如果您的桌面上还没有 RStudio,那么像大多数其他程序一样,将它安装到您的系统中是非常容易和直观的。但是不要忘记在获得 IDE 之前下载 R GUI。您可以通过下面的链接获得该软件:

[## RStudio |面向数据科学团队的开源专业软件

控制你的 R 代码一个集成的 R 开发环境,有一个控制台,语法高亮编辑器…

rstudio.com](https://rstudio.com/)

启动并运行 RStudio 后,转到 console 选项卡并输入以下代码:

#To install blogdown package
install.packages("blogdown")#To install hugo within blogdown
blogdown::install_hugo()

然后,转到 IDE 的左上角,单击以下内容:

文件→新项目→新目录→使用 blogdown 的网站

在这个窗口中,你可以指定你的目录名,我把它叫做‘git projects’。接下来,您需要从这里选择一个 hugo 主题:

[## 一览表

编辑描述

themes.gohugo.io](https://themes.gohugo.io/)

在 Hugo theme 文本框中,您需要指定所选主题的 Github 存储库,例如,上面的图片链接到 github.com/易慧/hugo-lithium

完成后,‘git projects’文件夹将被主题源代码和 RProject 可执行文件填充。稍后这将被手动转移到克隆的 Github 存储库文件夹中。

步骤 1–2:设置 g ithub 存储库并将其与 Git 集成

我没有必要重复从以下链接中的其他人那里获得的任务:

[## 如何正确设置您的 Github 资源库— Windows 版本

作为一名数据科学家,我经常与有志于成为数据科学家的人打交道,通常我的一个…

medium.com](https://medium.com/@aklson_DS/how-to-properly-setup-your-github-repository-windows-version-ea596b398b)

总之,你需要设置一个 Github 库并安装 Git Bash 终端,以实现从桌面到库的源代码变更的无缝管道。

不过,有些事情我做得有点不同。不要键入命令:

mkdir ~/Desktop/projects

在文件夹‘Git projects’下,我已经有了要克隆存储库的目录,所以我在 Git Bash 终端中键入了以下内容:

cd ~/Desktop/"Personal Stuff"/GitProjects

之后,我使用新的 Github 库提供的链接克隆了我的库。

一旦完成,一个与你的 Github 库同名的新文件夹将出现在“GitProjects”文件夹中。

但是记得我把所有的主题源代码和 RProject 文件放在同一个文件夹里,把所有的东西都移到新创建的文件夹,我的 Github 文件夹叫做“my website”,在成功地把所有东西都移过来之后,继续把目录换到新的文件夹里,如下所示:

当您在目录末尾看到(主)分支时,您就知道您已经连接到 Github 存储库了。

此时,您已经成功地用 Git 连接到 Github,但是您新导入的文件还没有被识别。

步骤 2:将主题源代码添加到 Github 存储库中

现在,您需要将主题源代码添加到 Github 存储库中。您的本地文件夹应该如下所示:

在您的 Git Bash 终端中使用以下命令将所有文件添加到您的存储库中:

git add <foldername>

某些文件不是必须添加的,但是如果是,就在你的中添加。gitignore 文件,以便网站部署引擎不会将它们应用到您的网站上:

.Rproj.user
.Rhistory
.RData
.Ruserdata
public

最后,您现在可以开始为您的站点创建内容了!

步骤 3:创建/定制内容和布局

这是最难的部分!每个主题都应该有一个文档来导航整个源代码。您可以在 Rstudio 控制台中键入以下代码,在 Rstudio 的“查看器”选项卡中预览您的站点:

blogdown::serve_site()

对于初学者来说,最受欢迎的主题是“学术”主题,它有全面的文档,并得到了社区的大力支持。对于简历展示和个人博客来说,这是一个非常通用的主题。事实上,您可以查看下面的视频,了解 Rstudio 中“学术”主题的详细介绍:

请注意,视频有点过时,某些代码被放在不同的文件中。我最初选择这个主题是为了练习,但后来为了更好的布局,我换了另一个主题。我不会深入到关于内容创建和布局定制的教程中,因为它应该在主题文档中有清楚的解释。

步骤 4:提交您的变更,并将变更推送到您的存储库中

一旦您对微小的更改感到满意,在 Git Bash 终端中使用以下命令将您的更改提交到 Github 存储库中:

git commit <foldername or filename> -m "Your update message here"

当您对所有的更改感到满意后,在 Git Bash 终端中输入以下代码,以使更改在 Github 存储库中发生:

git push

就是这样!每次在 RStudio 中对网站进行更改时,您只需在 Git Bash 终端中重新输入这些命令。

步骤 5:使用 Netlify 部署您的网站

Netlify 是一个万无一失的网站部署解决方案,它可以自动将您的文件从 Github 存储库转换为网站。

只需确保您连接到了正确的存储库,并且准备就绪。但是在部署成功之前,您需要为 Netlify 设置正确的环境变量来识别文件结构。

为此,请转到 Netlify 仪表板,转到设置→构建和部署→环境,并设置以下环境变量。

不过,你的雨果版本可能和我的不一样。要检查您的 hugo 版本,请返回 RStudio 并在控制台中键入以下命令:

blogdown::hugo_version()

最后一步:自定义域名

部署附带的免费域名是 *.netlify.com 格式。如果不介意子域挂在身边,可以跳过这一步。否则,您可以从 DNS 提供商(如 NameCheap)注册您的域名。对我来说,我坚持使用 Netlify,因为这是一个更便宜的选择。com 扩展名。但是你应该总是做你的研究,找到什么是最适合你的网站。您可以在此阅读更多关于您网站的域名注册信息:

[## c 域名| blogdown:用 R Markdown 创建网站

虽然您可以使用 GitHub 或 Netlify 提供的免费域名,但拥有一个

bookdown.org](https://bookdown.org/yihui/blogdown/domain-name.html)

摘要

随着您不断使用 Git 和 RStudio 更新您的站点,您的后续工作流应该如下所示:

正如承诺的那样,对于一个有预定义主题的基本网站,你不需要了解 HTML/CSS/JS 的广泛知识,尽管如果你想改变字体、重新定位某些单词和自定义颜色,这样做是有帮助的。

对于我(一个 Windows 用户)来说,我总是使用友好的“F12”按钮来检查元素并找到负责该特定布局的文件。通过这种方式,我学会了阅读一些 HTML 代码,并做了一些修改,这样我的网站看起来比原来更加个性化。

最后但并非最不重要的一点,我鼓励你向你选择的主题的所有者进行小额捐赠。一些主题创作者允许你把他们的名字从版权标志上去掉,只要你为他们的主题捐款,这样你就可以把你的网站称为你自己的创作。同时,这也是对他们辛勤工作的一种感谢,这样你的网站才能看起来漂亮。

编码快乐!

理解网络攻击的数据驱动方法

原文:https://towardsdatascience.com/a-data-driven-approach-to-understanding-cyber-attacks-5cd8b5f91abe?source=collection_archive---------26-----------------------

在 VERIS 社区数据集上使用 Pandas 的探索性指南

照片马库斯·斯皮斯克

保护让社会正常运转的数字系统、应用和网络免受有意和无意的伤害是一个非常复杂的问题,仅靠人类的直觉是无法实现的。

网络安全领域正在发生一场觉醒,这种觉醒是由同样的商品推动的,这种商品曾导致亚马逊、脸书和谷歌等公司成为世界上最强大的私营公司: Data

数据科学在网络安全领域的应用为组织更好地保护自己免受网络威胁提供了重要的机会。一个常见的用例是实现机器学习模型来监控恶意用户行为,这是一个不适合人类分析师执行的任务,尤其是对于拥有数千名员工的大型组织。

在本文中,我使用 Python 和 Pandas 来探索由大约 8500 个真实世界网络事件组成的 VERIS 社区数据集,以回答一个广泛的研究问题:“网络事件的共同属性是什么?”。通过回答这个简单的问题,我希望展示如何利用数据将一个复杂的问题分解成微小而可行的见解。

导入和配置数据

我通过将 GitHub 上的整个 VERIS repo 克隆到我的本地环境来导入数据。因为每个事件都存储在一个单独的 JSON 对象中,所以我使用了有用的 verispy 包将数千个 JSON 对象提取到一个 pandas 数据帧中:

import pandas as pd
from verispy import VERISdata_dir = '/Users/danielharrison/VCDB-master/data/json/validated'
v =  VERIS(json_dir=data_dir) #creates a veris objectFound 8539 json files.veris_df = v.json_to_df(verbose=True) #creates a dataframe from the veris object

检查数据框架揭示了 VERIS 社区数据集的范围(截至 2020 年 1 月):

veris_df.shape()
(8539, 2347)

1.谁在引发网络事件?

了解谁会有意或无意地对数字资产造成潜在损害,是解决研究问题和探索数据的自然起点。

VERIS 数据库将网络威胁因素分为三类:

1.外部-组织之外的任何人,例如黑客、国家和前雇员

2.内部-受托访问内部系统的任何人,例如全职员工、承包商和实习生

3.合作伙伴——受影响组织的第三方供应商,通常对内部系统有一些可信的访问权限。

为了按参与者类型分解事件,我利用了 verispy 软件包提供的enum_summary函数:

df_actors_internal = v.enum_summary(veris_df, 'actor.internal.variety', by='actor')df_actors_external = v.enum_summary(veris_df, 'actor.external.variety', by='actor')

注意:我忽略了包括合作伙伴行动者类型,因为由合作伙伴引起的事件总数很低,这影响了以后的可视化。

在对df_actors_internaldf_actors_external 数据帧进行了一些清理之后(更多信息参见我的 GitHub 代码,我将它们连接成一个数据帧df_actors_combined:

df_actors_combined = pd.concat([df_actors_internal, df_actors_external])df_actors_combined.head()

串联数据帧 df_actors_combined 包含内部和外部参与者

由于 Plotly express 图形库,以视觉上令人惊叹的交互式方式呈现这些数据变得非常容易。我选择用一个旭日图来展示内部和外部参与者是如何被进一步分解成他们的参与者类型的:

import plotly.express as pxfig_1 = px.sunburst(df_actors_combined, path=['Actor Origin', 'Actor Type'], values='Count')fig_1.update_layout(uniformtext_minsize=12)plot(fig_1, filename = 'Actor Origin', auto_open=True)

内部和外部参与者被进一步分解为他们的角色或联盟

关于在页面中嵌入可视化的更多信息,我推荐下面的 文章

显而易见的是,由内部和外部行为者引起的事件几乎是平均分布的,52%是外部的,47%是内部的(大约 1%是合作伙伴&未知)。

赛博域深度挖掘 1

组织不能低估内部威胁带来的风险,他们对内部系统的特权访问和工作知识使他们很容易造成伤害-无论他们是否有意。

对于内部参与者的已知数据,很大一部分可归因于“最终用户”,VERIS 文档将其描述为应用程序的最终用户或正式员工。我将此解释为拥有系统标准访问权限并在日常工作中使用该系统的员工。

有趣的是,根据我在 DevOps 环境中的经验,考虑到软件开发人员所拥有的高级访问和工作知识,我预计由他们引起的事故数量会高得多。例如,开发人员可以修改软件应用程序的底层源代码,以某种方式为自己谋利,或者干脆将密码和 API 密钥等秘密暴露在 GitHub 上托管的代码中:

在 Github 上搜索“删除密码”会发现很多秘密被留在源代码中的例子

为了了解开发人员是恶意行为还是仅仅是犯了错误,我通过过滤内部开发人员的veris_df数据框架和他们的行为进一步分析了数据:

df_actors_developers = v.enum_summary(veris_df, 'action', by='actor.internal.variety')df_actors_developers = df_actors_developers[df_actors_developers['by'] == 'actor.internal.variety.Developer']df_actors_developers.plot(kind='bar', x='enum', y='x', legend=False)plt.xticks(rotation=25)
plt.ylabel('Count')
plt.savefig('df_actors_developers')

大多数由开发引起的事件是由错误引起的,很少是恶意的

生成的条形图显示,在 73 起与开发人员相关的事件中,56 起是错误(即意外),其余 17 起与误用、黑客攻击和恶意软件(即恶意软件)有关。有帮助的是,VERIS 提供了一个事件摘要,我从 14 个标记为“误用”的事件中提取了该摘要,并将其输出到一个 csv 文件中,以便于阅读:

df_actors_developers_misuse = veris_df.loc[(veris_df['actor.internal.variety.Developer'] == True) & (veris_df['action.Misuse'] == True)]df_actors_developers_misuse['summary'].to_csv('developers_misuse_summary.csv', index=False, header=False)

一个特殊的事件是由美国的一名高级 IT 主管引起的,他也是一名开发人员。该开发商:

“2005 年,他在“随机”数字生成计算机软件中添加了一个秘密代码,使他能够将多场比赛的中奖概率从高达 500 万分之一缩小到 200 分之一……他在科罗拉多州、威斯康星州、爱荷华州、堪萨斯州和俄克拉荷马州劫持了至少五张中奖彩票,奖金总额超过 2400 万美元”

确实非常淘气。[我已经将剩余的摘要上传到了我的 GitHub

本次网络领域深度探讨展示了我们如何从询问“谁造成了网络事件”这一非常普通的问题,一直到发现源代码完整性的价值。

2.什么样的行为会导致网络事故?

在探讨了开发人员通常如何引发网络事件后,我后退一步,分析了所有外部、内部和合作伙伴可能采取的威胁行动。这是很有用的,因为组织需要知道他们的内部和外部威胁可能如何实现,这样他们就可以实施足够的保护控制。

我想用更多的 Plotly 的交互式图表来形象化这种洞察力,并决定 Sankey 图将优雅地显示演员和动作之间的关系和流动。为了创建一个 Sankey,我过滤了 actor 和 action 上的veris_df 数据帧:

df_action_actor = v.enum_summary(veris_df, 'action', by='actor')

稍微整理了一下生成的数据帧:

df_action_actor.drop(['n', 'freq'], axis=1, inplace=True)df_action_actor.columns = ['Actor Origin', 'Action Type', 'Count']df_Unknown_3 = df_action_actor[df_action_actor['Actor Origin'] == 'actor.Unknown']df_action_actor.drop(df_Unknown_3.index, inplace=True)

并使用映射函数来阻止代码在每个单词前输出“actor ”,即“actor”。外在,演员。内部,演员。合作伙伴':

map_origin = {'actor.External':'External', 'actor.Internal':'Internal', 'actor.Partner':'Partner'}df_action_actor['Actor Origin'] = df_action_actor['Actor Origin'].map(map_origin)df_action_actor.head()

生成的数据帧现在可以生成桑基图,如下所示:

df_action_actor 数据帧存储了 actor 源和它们可能的动作类型之间的关系

我将上面的df_action_actor数据帧传递给了预建函数 gen_Sankey,指定了生成桑基图中的级别和值的列,并通过调用plot输出了结果图:

fig_4 = genSankey(df_action_actor, cat_cols=['Actor Origin', 'Action Type'], value_cols='Count', title='Sankey Diagram for Veris Community Database')plot(fig_4, filename = 'Cyber Actions Sankey Diagram', auto_open=True)

Sankey 图表明,数据集中的一些事件被分配了多种操作类型,因为内部、外部和合作伙伴事件的数量与之前的图表相比略有增加(按操作类型划分数据时,记录的事件有约 12%的差异)。

赛博域深潜 2

该图显示,约 90%与内部行为者相关的事件是由错误或误用造成的。这种洞察力告诉我们,安全部门可以预期内部威胁会以用户行为的形式出现,而不是恶意软件或黑客活动,后者通常需要略有不同的监控技术。这就是为什么用户行为分析(UBA)领域最近出现了爆炸式增长,并使组织能够检测到用户在一段时间内相对于其他用户或自己的异常行为。

与外部行为者相关的事件是由一系列更加多样化的行为引起的。这是有意义的,因为参与者必须采用更具创造性的方法来获得对系统的访问,以实现他们的结果。“黑客”行动似乎有点模糊:黑客到底意味着什么?我们能分离出黑客攻击的一些趋势吗?为了回答这些问题,我必须向数据帧添加一个日期时间索引,并过滤由黑客行为引起的事件(产生的数据帧称为combined)。有关我如何做到这一点的更多信息,请参考我的 GitHub ,因为它太长了,无法包含在本文中。

清理数据集后,我能够提取以下图形:

ax1 = combined.iloc[:, 2:10].plot(kind='bar', stacked=True, figsize=(10,5))

2006-2019 年黑客活动导致的网络事件频率

图表显示了更多关于什么行为构成“黑客攻击”的细节。拒绝服务(DoS)攻击在 2013 年和 2014 年困扰着组织,但最近,对数据集中的组织来说,威胁似乎已经变得不那么大了。这可能是因为反 DoS 技术近年来变得更加先进和流行:web 应用程序防火墙(waf)能够对传入的 Web 流量进行速率限制,通常由云供应商在内容分发网络(cdn)、应用程序负载平衡器和 API 网关上作为标准提供。

然而,VERIS 数据集现在可能会过时,因为数据表明自 2013 年以来黑客攻击一直在稳步下降。有大量其他数据集和统计数据表明情况并非如此。事实上,作为一个从事网络安全工作并对各种组织有看法的人,我可以凭第一手经验说,网络攻击的数量正在上升。

3.组织检测和响应网络事件需要多长时间?

能够及时检测和响应网络事件可以拯救整个组织免于破产。检测和响应网络事件花费的时间越长,组织面临的风险就越大,潜在的危害也就越大。

VERIS 将网络事件分为 4 个阶段,并记录组织达到该阶段所需的时间单位:

  • 妥协:参与者已经获得对信息资产的访问权或妥协,例如获得对销售数据库的访问权
  • 泄露:参与者从受害者组织获取非公开数据的点(不适用于所有事件)
  • 发现:组织意识到事件已经发生的时间点
  • 遏制:组织阻止事故发生或恢复正常业务的点。

N.B. VERIS 仅记录到达每个阶段的时间单位,即秒、分、小时,出于保密原因,不记录实际时间戳。

我想了解组织检测和响应网络事件需要多长时间,并使用热图表示这些信息。

为此,我首先必须从数据集中提取时间轴信息。我编写了一个函数(get_timeline_df(x, event)),该函数根据事件的特定阶段过滤数据集,并为下一阶段的处理格式化结果数据帧。关于get_timeline_df功能的更多详情,请参见 my GitHub 。我调用了这个函数 4 次,事件的每个阶段调用一次:

compromise_time = get_timeline_df(‘timeline.compromise.unit’, ‘Compromise’)discovery_time = get_timeline_df('timeline.discovery.unit', 'Discovery')exfiltration_time = get_timeline_df('timeline.exfiltration.unit', 'Exfiltration')containment_time = get_timeline_df('timeline.containment.unit', 'Containment')

然后将 4 个数据帧连接成一个:

timeline_df = pd.concat([compromise_time, discovery_time, exfiltration_time, containment_time])
timeline_df.head()

生成的数据帧如下所示:

串联时间轴 _ 测向数据帧

get_timeline_df函数中,我将字符串时间单位映射到一个从 1 到 8 的整数值,即‘秒’:1、…、‘天’:4、…、‘从不’:8,这样我就可以从最长到最短的时间跨度对值进行排序。

通过以矩阵形式传递数据,可以在 seaborn 中创建热图。我使用pd.pivot()函数将timeline_df数据帧转换成矩阵,根据事件的 4 个阶段重新索引数据,并将数据从最长时间单位到最短时间单位排序:

timeline_matrix = timeline_df.pivot('Time Unit', 'Timeline Event', 'Count')timeline_matrix.columnscolumns_matrix_titles = ["Compromise","Exfiltration", "Discovery", "Containment"]timeline_matrix = timeline_matrix.reindex(columns=columns_matrix_titles)timeline_matrix.sort_index(ascending=False, inplace=True)

生成的矩阵如下所示:

根据 VERIS,时间轴矩阵按网络事件的四个阶段进行索引

现在,我简单地将矩阵传递给 seaborn 的热图函数,并将时间单位重新标记为字符串值,以便于理解:

import seaborn as snsfig_heatmap = plt.figure(figsize=(10,8))r = sns.heatmap(timeline_matrix, cmap='BuPu', cbar_kws={'label': 'Count'}, linewidths=.05)plt.yticks([7.5,6.5,5.5,4.5,3.5,2.5,1.5,0.5], ['Seconds', 'Minutes', 'Hours', 'Days', 'Weeks', 'Months', 'Years', 'Never'], rotation=0)

产生了以下热图:

热图显示了网络事件在最初发生数月后才被发现的总体趋势

赛博域深度潜水 3

从热图中显而易见的是,与组织意识到发生了任何事情相比,危害和泄露数据所需的时间更短。根据 FireEye 的数据,在首次攻击数月后发现的大量事件与公认的 2017 年行业平均 101 天发现网络事件有很好的相关性。

网络专业人士通常将最初的妥协和发现之间的时间称为“停留时间”。驻留时间数字如此之高的一个原因可能是因为被称为“高级持续威胁”或“APTs”的特定网络事件子集。apt 喜欢在一个组织的系统上长时间不被注意。留在那里有助于威胁参与者了解组织如何工作,以实现他们的目标,例如窃取数据。

为什么停留时间很重要?T4 最近的一篇论文指出,停留时间和网络攻击的平均成本之间存在关联。 停留时间越长,攻击的代价就越大。

组织可以使用平均停留时间作为 KPI 来衡量威胁检测控制的有效性。只有通过测量,组织才能真正了解他们的网络风险。

网络安全是一个数据问题

数字世界里发生的一切都会被记录下来。用户点击浏览器中的链接、员工三次输错密码、文件从一个网络位置传输到另一个网络位置,都是以数字格式记录的事件。这些数字事件可以用来保护组织免受网络事件的影响,但前提是用户、员工和系统每天产生的海量数据可以作为一种有益的工具来使用。

VERIS 社区数据集只是应用数据分析来保护数字系统的一个用例。通过观察数以千计的事件的总体趋势,组织可以了解威胁最有可能来自哪里,以及他们可能如何试图造成伤害。

正如杰弗里·摩尔所说-

没有大数据分析,公司就像瞎子和聋子,像高速公路上的小鹿一样在网络上游荡。

美国社会距离的数据驱动研究

原文:https://towardsdatascience.com/a-data-driven-take-on-social-distancing-in-the-united-states-303dc4225155?source=collection_archive---------40-----------------------

在新冠肺炎疫情的最初几周,关于美国社会距离的有趣的、数据驱动的见解

布莱恩·麦高恩在 Unsplash 上的照片

本帖分享的分析和见解均来自safe graph分享的数据。SafeGraph 免费提供其各种数据集,以帮助世界各地的研究人员应对新冠肺炎(冠状病毒)。这些数据包括关于人们如何在美国各地移动的聚合和匿名数据集。如果你想志愿成为研究员,请在这里 报名

请注意,SafeGraph 提供的所有数据都是隐私安全和匿名的。为了增强隐私,如果在一个月内来自给定人口普查区块组的访问机构的设备少于五个,则 SafeGraph 会排除人口普查区块组信息。

新冠肺炎对流动性的影响

随着新冠肺炎病毒在美国迅速蔓延,查看移动数据以了解人们的行为如何随着社交距离政策的变化而变化是很重要的。

在本帖中,我将提供一些我从探索 SafeGraph 数据中收集到的有趣见解。

更多的人呆在家里吗?

数据范围为 2020 年 1 月 1 日至 2020 年 4 月 13 日

每日完全归位设备的百分比是使用 SafeGraph 的指标设备完全归位来计算的,该指标表明设备在一天中的移动没有超出其先前夜间位置的约 100 平方米。SafeGraph 还澄清说,当我们提到“家”时,我们实际上是指近几个月来最常见的夜间位置,其精度约为 100 平方米。我们不知道(也不想知道)匿名设备的确切家庭地址。

有明显的证据表明,越来越多的人呆在家里,保持着社会距离,然而,人们保持社会距离的程度因县、州等不同而有很大差异。(下文对此有更多讨论)。

更多人开始呆在家里的转变似乎也是在 2020 年 3 月 13 日之后开始的,这一天联邦政府宣布新冠肺炎进入全国紧急状态。

旅行的人变少了吗?

数据范围为 2020 年 1 月 1 日至 2020 年 4 月 13 日

不出所料,也有明显的证据表明人们正在减少旅行。从 2020 年 3 月 13 日以后,离家旅行的距离中位数也开始减少。

不同的州、县和城市之间的社交距离有什么不同?

待在家里指数将是我在下面一些图表中使用的指标。我通过观察 4 月第一周与 2 月第一周(基线)相比,完全在家的设备百分比的差异来计算。使用 7 天平均值来计算最终差异。居家指数为 0.2 表明,与 2 月的第一周相比,4 月的第一周有大约 20%的设备在家(基线)。这一指标的计算受到了 SafeGraph 在其 Shelter in Place 仪表板中使用的 Shelter in Place 指数的启发。

美国各州—居家指数

居家指数最高的前 5 个州是新泽西州、马萨诸塞州、马里兰州、罗德岛州和康涅狄格州。居家指数最低的 5 个州是南达科他州、蒙大拿州、怀俄明州、印第安纳州和新墨西哥州。

美国各县—居家指数

在各州内部,就不同的县如何实践社会距离而言,也有很多不同之处。更多的大城市和人口密集的县有更高的居家指数(更多信息见下文)。

美国城市——完全家庭化设备的百分比

这里的数据是美国人口最多的前 10 个城市的数据,范围从 2020 年 1 月 1 日到 2020 年 4 月 10 日

在这些城市中的大部分,人们在 3 月 13 日之后开始呆在家里。有趣的是,对于凤凰城等一些城市,官方的就地安置避难所命令直到 3 月 30 日才发布,但数据显示,鉴于新冠肺炎的肆虐,即使在这些城市中的一些城市,人们也从 3 月中旬开始呆在家里。

探索影响社会距离的因素

家庭收入中位数

这里的每个数据点代表一个美国邮政编码(n = 30,664)

这表明,能够呆在家里和在家工作是许多人的特权。与中等家庭收入较高的人相比,中等家庭收入较低的人不太可能呆在家里。

城市与农村人口

这里的每个数据点代表一个美国县(n = 3,228)

与农村人口比例较大的县相比,城市人口比例较大的县更有可能呆在家里。人口最稠密的县和城市已经显示出减少旅行最显著。

政治倾向(民主党对共和党)

这里的每个数据点代表一个美国县(n = 3,114)

有趣的是,在 2016 年总统大选中,民主党选民比例较大的县的人民也比共和党选民比例较大的县的人民更有可能呆在家里。这也与每个县的城乡人口比例有关。

不出所料,这些因素中有很多可能是相互交织、相互关联的,但需要注意的一点是,一个社区实施社交距离的程度是由很多外部因素决定的。虽然越来越多的人呆在家里,减少了全国各地的旅行,但数据显示,较富裕的城市工人呆在家里的时间最多,而农村地区收入较低的工人并不总是享受同样的奢侈。

使用的数据源

其他关于社交距离和移动性的有趣仪表板/报告

管理 ML 项目的数据工程方法

原文:https://towardsdatascience.com/a-data-engineer-approach-to-managing-an-ml-project-7bbfb6efd2df?source=collection_archive---------49-----------------------

使用 DevOps 电池的数据科学项目

项目管理技能的展示

最近, 劳伦斯·莫罗尼 建议专业人士通过在 GitHub 上发起一个涵盖你投资组合相关方面的项目来展示你的技能,并通过工作让你的专业网络了解你。我采纳了他的建议,在 GitHub 上做了一个项目。我写这篇文章是为了激励他人,也是为了建立我自己的投资组合。我将介绍这个项目的主要组成部分。下面是我的 GitHub 项目的链接。

[## amjadraza/零售销售预测

用机器学习预测零售店销售额的 Python 项目。这个项目是基于提供的数据…

github.com](https://github.com/amjadraza/retail-sales-prediction)

零售预测

有了数据工程和科学背景,我从 Kaggle 竞赛中选择了一个问题来预测一家零售店的销售额。

任务是使用厄瓜多尔的 Corporación Favorita 杂货店 连锁店提供的数据建立零售预测。数据是为 Kaggle 比赛提供的。我按照以下步骤来执行数据工程和建模。出于研究目的,我使用了 Jupyter 笔记本和 PyCharm IDE。

以下是我在这个项目中遵循的一些步骤。

  1. 关于法乌瑞塔杂货店的简要信息
  2. 探索性数据分析
  3. 特征工程和选择
  4. 模型训练和选择
  5. 准备/部署销售预测模型

我已经包括了用于探索性数据分析、特性工程和模型构建的 Jupyter 笔记本。

除了研究部分,我还使用 PyCharm IDE 和audreyrpython Project cooki cutter建立了 Python 项目。Cookiecutter 项目包括 DevOps 所需的大部分电池,但我也包括了一些自定义数据。我的项目的一些特点是

  1. 使用 Sphinx 和 readthedocs 模板的文档
  2. Jupyter 笔记本
  3. 使用 CLI 命令参数的运行程序
  4. 模块结构
  5. 自动测试
  6. 版本控制

DevOps 工具

一旦项目建立起来,就应该添加一些 DevOps 工具来构建和部署文档,运行测试,创建 PyPi 包,并在 PyPi 上部署。通常,这些步骤对数据科学家来说似乎很陌生,但是任何人只要稍加努力就能学会。

文档构建和部署

在本地测试完文档后,我在 readthedocs 服务器上创建了一个免费账户,并与 GitHub 链接。只需点击几下鼠标,即可构建和部署文档。下面是我的项目文档的链接。

[## 欢迎阅读零售预测文档!-零售预测文档

欢迎阅读零售预测文档!

-零售预测文档欢迎使用零售预测文档!零售销售预测](https://retail-sales-prediction.readthedocs.io/en/latest/)

Python 包自动测试

当构建大型项目时,无论是 PR、MR 还是 Push,只要有活动就运行自动测试是至关重要的。我已经使用 GitHub actions 设置了管道,以便在有推送时进行自动测试。目前,我只有演示测试,但它可以很容易地扩展。

创建一个 Python 包并部署在 PyPi 上

项目的最后一部分是创建一个可安装的 python 包,并在 PyPi 包发行版上发布。为此,我在 https://pypi.org/的上创建了一个免费账户。发布已经在 GitHub 上准备好了,使用 GitHub actions 工作流,我已经将包部署到 https://pypi.org/的。下面是我的包的链接。

[## 零售销售预测

用机器学习预测零售店销售额的 Python 项目。这个项目是基于提供的数据…

pypi.org](https://pypi.org/project/retail-sales-prediction/)

演示台

一个好的演示文稿是成功交付任何项目的关键技能。我准备了一套幻灯片来展示我的工作。您可以在 Slideshare 上的以下位置找到我的幻灯片。

结束语

在这篇文章中,我写了数据工程/科学项目的概述,包括项目所需的模型构建和 DevOps 工具。这个项目结构是可扩展的,并且以一种只需很少修改就可以用于生产的方式进行设置。

未来作品

这个项目可以增加很多东西

  1. 探索张量流模型
  2. 添加 docker 支持并发布 Docker 图像
  3. 用于模型开发的 Spark 集成
  4. 远程机器的可行部署
  5. 投稿指南和 Git 工作流程
  6. 创建和部署 Conda 包
  7. 云服务上的最终模型部署,例如 GCP

Go 与 Python 的数据工程观点(第 1 部分)

原文:https://towardsdatascience.com/a-data-engineering-perspective-on-go-vs-python-part-1-5dfb8bc08e7?source=collection_archive---------22-----------------------

介绍

探索 golang——我们能放弃 Python 吗?我们(比如“经常处理大量数据的人”)最终找到 go 的用例了吗?第 1 部分探讨了 Python 和 go 之间的高级差异,并给出了这两种语言的具体示例,旨在基于 Apache Beam 和 Google Dataflow 作为真实示例来回答这个问题。

Apache Beam 是我以前在这个博客上使用过几次的东西:它是一个针对批处理和流用例的统一编程模型,可以处理令人愉快的并行工作负载,允许许多自定义 I/O 和其他连接器,并运行在多种执行平台上,最著名的是 Flink、Spark 和 Google Cloud 的数据流。

您可以使用它来传输或批处理数据,以分析数据、运行 ETL、丰富数据——应有尽有。我其实几年前就用过Beam这里

现在,如果你去 Beam 的网站,你会发现这个奇妙的图形:

https://beam.apache.org/

它告诉你 Beam 要么用Java要么用Python来写,其他的都属于“其他语言”。

然而,有一个“实验性的”( GitHub )承诺我们使用go而不是Python——这让我很兴奋。

下一节将尝试对go做一个“简短的”(~3,000 字)介绍,并根据不同的处理数据工程特定用例以及在使用多线程应用时,将其与Python进行比较。请注意,这绝不是完全的比较。

这是第 1 部分,共 2 部分,重点介绍两种语言和 Apache Beam SDK 的当前状态。在第 2 部分(即将推出),我们将探索如何使用 *Beam* *go* SDK,我们将在 GCP 面临哪些限制,以及数据工程师的 *go* 之旅将走向何方。

所有示例代码在 GitHub 上都有。

最初发表于https://chollinger.com

Go vs. Python

如果你不熟悉,让我引用维基百科:

Go 是一种静态类型的编译编程语言,由 Robert Griesemer、Rob Pike 和 Ken Thompson 在 Google 设计。Go 在语法上类似于 C,但是具有内存安全、垃圾收集、结构化类型和 CSP 风格的并发性。

https://en . Wikipedia . org/wiki/Go _(编程 _ 语言)

Go有许多概念,应该会让您对处理数据的并行执行框架感到兴奋。在接下来的几节中,我们将探索一些精选的概念和示例,并以一个更长、更深入的并发示例结束。

速度

go是一种编译语言,而不是解释语言,应该比 Python 快。它还倾向于非常快速地编译东西,将编译好的代码发送给最终用户要比试图用 Python 做同样的事情容易几个数量级。

你可以在下面找到一些实际操作的例子。

使用 matplotlib 生成;CC BY-SA 3.0

静态打字

Python的动态类型相反,静态避免了在正确的时刻使用正确的数据类型带来的许多类型问题。

我并不想对静态和动态类型以及 Python 的复杂性进行一般性的比较,而只是从我的经验来看,特别是在数据空间中,每天都是如此。

在数据驱动的项目中,您会经常发现自己在处理非常严格的数据类型定义,这通常是某个领域的一个工件(理所当然如此),在这个领域中,所有公司数据都不可避免地存储在大型 RDMBs 中,例如 Oracle,强制执行严格的类型。

基于 Python 的框架,比如pySpark甚至pandas,都自带了提供类型的抽象层。

以这段代码为例,它是为pySpark编写的,这是一个流行的数据处理框架,在 Python(以及其他语言)中可用,使用了 NYC Yellow Cab 数据[0]。

首先,将一个 CSV 文件读入一个RDD,一个“有弹性的分布式数据集”,并对数据集中的每一行应用一些转换 lambdas。

# Read data
rdd = sc.textFile('data/yellow_tripdata_2019-01.csv')
# Parse the RDD
rdd = rdd.map(lambda r: r.split(','))\
         .map(lambda r: (r[10],r[13])) # Take 'fare_amount' and 'tip_amount'
rdd = rdd.filter(lambda r: 'fare_amount' not in r) # filter header
rdd.take(1)

这产生了:

[('7', '1.65'), ('14', '1'), ('4.5', '0'), ('3.5', '0'), ('52', '0')]

如果我们研究其中一个元组:

type(rdd.take(1)[0][0])

我们将把str视为数据类型。

现在,如果我们要减少这个数来合计出租车费和小费金额:

def sum_fares(fare, tip):
    return fare + tip

rdd.map(lambda r: sum_fares(*r)).take(5)

正如上面输出中的引号所示,结果是一个串联的strings列表。

['71.65', '141', '4.50', '3.50', '520']

而不是数学上正确的:

rdd.map(lambda r: sum_fares(*[float(x) for x in r])).take(5)
# [8.65, 15.0, 4.5, 3.5, 52.0]

新版本的 Python 支持type hints,Python 解释器跟踪变量类型。然而,正如上面的例子所强调的,我个人发现很难维护一个一致的、可读的、可维护的代码库,尤其是在复杂的应用程序上。

另一方面,go是静态类型的。

package main

import (
	"fmt"
	"reflect"
)

func main() {
    // Implicit
	str := "A String"
	fmt.Printf("%s is %s\n", str, reflect.TypeOf(str))

    // Explicit
	var x float64 = 3.14
	fmt.Printf("%v is %s\n", x, reflect.TypeOf(x))
}

将产生:

go run test.go
A String is string
3.14 is float64

鉴于此:

str = x

不会编译:

go run testvar.go
# command-line-arguments
./test.go:15:6: cannot use x (type float64) as type string in assignment

Go 不支持Generics,但Python也不支持。

我跳过了*go**empty interface{}*的概念,以支持任意值和处理未知类型;在需要弱类型抽象的情况下,可以使用这个概念**

【0】*Spark*的 SQL 接口将推断字符串类型,并允许对字符串进行数学运算,如果它们一致

接口和结构

Python确实有一个class结构(我已经广泛使用过了),而go使用了structsinterfaces(这是一个可怕的简化)。go没有继承,依赖于接口和组合。

在数据世界中,拥有严格的类结构,例如抽象转换、统计模型或简单的旧数据结构,可能既是痛苦也是诅咒。

Python广泛使用了dicts,它可以保存任意的键值对和嵌套结构,在语法上类似于JSON,并且为数据的结构化抽象定义了class。几乎每个数据框架都有自己的schema类。从理论上讲,go可以通过组合interfaces(用于标准)、静态类型(确保在正确的时刻使用正确的数据类型)和structs来定义结构和逻辑,从而避免这种情况。

这里有一个非常有用的例子,它使用接口CoordinateData和函数calculateDistance,在世界上最差的 GIS 分析平台上计算两个坐标元组之间的距离:)

*package main

import (
	"fmt"
	"math"
)

// A Resource we're trying to access
type CoordinateData interface {
	calculateDistance(latTo, lonTo float64) float64
}*

然后,我们实现地理空间数据和哈弗辛函数(以近似地球上的距离):

*type GeospatialData struct {
	lat, lon float64
}

const earthRadius = float64(6371)
func (d GeospatialData) calculateDistance(latTo, lonTo float64) float64 {
	// Haversine distance
	var deltaLat = (latTo - d.lat) * (math.Pi / 180)
	var deltaLon = (lonTo - d.lon) * (math.Pi / 180)

	var a = math.Sin(deltaLat / 2) * math.Sin(deltaLat / 2) + 
		math.Cos(d.lat * (math.Pi / 180)) * math.Cos(latTo * (math.Pi / 180)) *
		math.Sin(deltaLon / 2) * math.Sin(deltaLon / 2)
	var c = 2 * math.Atan2(math.Sqrt(a),math.Sqrt(1-a))

	return earthRadius * c
}*

在一个简单的二维平面上也是如此:

*type CartesianPlaneData struct {
	x, y float64
}

func (d CartesianPlaneData) calculateDistance(xTo, yTo float64) float64 {
	// Simple 2-dimensional Euclidean distance 
	dx := (xTo - d.x)
	dy := (yTo - d.y)
	return math.Sqrt( dx*dx + dy*dy )
}*

在这种情况下,main()函数只计算两种完全不同的距离:

*func main() {
	atlanta := GeospatialData{33.753746, -84.386330}
	distance := atlanta.calculateDistance(33.957409, -83.376801) // to Athens, GA
	fmt.Printf("The Haversine distance between Atlanta, GA and Athens, GA is %v\n", distance)

	pointA := CartesianPlaneData{1, 1}
	distanceA := pointA.calculateDistance(5, 5) 
	fmt.Printf("The Pythagorean distance from (1,1) to (5,5) is %v\n", distanceA)
}*

当然,这是一个非常简单的例子,简单地将结构强加到你的结构上。然而,与 Python 相比,我的选择有限:

*class CoordinateData:
    def calculateDistance(self, latTo, lonTo):
        pass 

class GeospatialData(CoordinateData):
    def __init__(self, lat, lon):
        self.lat = lat
        self.long = lon

    def calculateDistance(self, latTo, lonTo):
        # Haversine goes here :)
        return 95.93196816811724

class CartesianPlaneData(CoordinateData):
    def __init__(self, x, y):
        self.x = y
        self.x = y

    # Let's not implement calculateDistance()

if __name__ == "__main__":
    atlanta = GeospatialData(33.753746, -84.386330)
    distance = atlanta.calculateDistance(33.957409, -83.376801) # to Athens, GA
    print('The Haversine distance between Atlanta, GA and Athens, GA is {}'.format(distance))

    pointA = CartesianPlaneData(1,1)
    distanceA = pointA.calculateDistance(5, 5)
    print('The Pythagorean distance from (1,1) to (5,5) is {}'.format(distanceA))
    print('pointA is of type {}'.format(pointA.__class__.__bases__))*

这是有效的 Python — CartesianPlaneDataCoordinateData的子类(不是接口—Python 使用 duck-typing),因此,简单地使用没有返回类型的calculateDistance方法(参见上面的静态与动态类型),运行并返回:

*python3 interface_example.py
The Haversine distance between Atlanta, GA and Athens, GA is 95.93196816811724
The Pythagorean distance from (1,1) to (5,5) is None
pointA is of type (<class '__main__.CoordinateData'>,)*

Python 仍然允许接口抽象,你完全可以使用类来定义层次和逻辑,正如我在下面的PluginInterceptor中所做的,来确定一个定制插件是否是一个已定义基类的一部分;然而,这并不是在运行时强制执行的,如果您不正确地实现它,可能会失败。

*class PluginInterceptor:
    """Loads all allowed plugins, when they are a subclass of `BasePlugin` and have the constant `name` set (not `__name__`)
    """
    def __init__(self):
        self.cls = BasePlugin
        self.allowed_plugins = self.__load__allowed_plugins__()

    def __get_all_subclasses__(self, cls):
        return set(cls.__subclasses__()).union(
            [s for c in cls.__subclasses__() for s in self.__get_all_subclasses__(c)]) 

    def __load__allowed_plugins__(self):
        __allowed_plugins__ = {}
        for cls in self.__get_all_subclasses__(self.cls):
            if cls.name:
                __allowed_plugins__[cls.name] = cls
        return __allowed_plugins__*

https://github . com/otter-in-a-suit/稻草人/blob/master/plugin _ base/interceptor . py # L5

您还可以在下面的 Mandelbrot 示例中找到一个结构示例。

两颗北极指极星

go懂指针,不懂指针算术。go中的指针用于按指针传递操作,与按值传递相反。我不会深入讨论这个问题,给你一个来自go的例子,你可以参考这篇关于 Python 的精彩文章

*package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // point to i
	fmt.Println(*p) // read i through the pointer
	*p = 21         // set i through the pointer
	fmt.Println(i)  // see the new value of i

	p = &j         // point to j
	*p = *p / 37   // divide j through the pointer
	fmt.Println(j) // see the new value of j
}*

(来自https://tour.golang.org/moretypes/1

我对go的简短总结是:作为一名开发人员,我能够控制我是喜欢标准的C风格的行为——按值传递——还是一个指针,我仍然按值传递——但是在这种情况下,一个指向值的指针作为函数参数。**

Mandelbrot 集的并发性

简单、开箱即用、易于使用的并发是go中最精彩的事情之一。从同步到并发总共需要两个字母- go

让我们使用一种“令人愉快的并行”算法,即曼德尔布罗集合

Mandelbrot 集合是函数f_c(z) = z² + cz = 0开始迭代时不发散的复数c的集合,即序列f_c(0, f_c(f_c(0))等。,保持绝对值有界。

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

Mandelbrot 算法的输出;CC BY-SA 3.0

计算机编程语言

我们先来看 Python。

Python 提供了多种方式来表达并发性——threadingmultiprocessingsubprocessesconcurrent.futures等等——但是选择正确的方式编写清晰的代码是一个挑战。请允许我引用文件:

**本章描述的模块为代码的并发执行提供支持。工具的适当选择将取决于要执行的任务(CPU 受限与 IO 受限)和首选的开发风格(事件驱动的协作多任务与抢占式多任务)

我不会详细讨论什么情况下什么是正确的选择,全球 Python 解释器(GIL)如何影响它,或者一切是如何工作的,因为在网上可以很容易地找到数百篇关于这个主题的文章。然而,我想关注的是代码风格、易用性和性能。

单线程的

这可以这样表达(由 danyaal 作出,由你真正调整):

请记住,有更多、更快、优化的版本,但也有更多复杂的版本;下面的例子应该是简单明了的&,并且可以在 *go* *Python*之间几乎 1:1 地翻译**

首先,我们定义算法的迭代。这是可以并行运行的部分,我们马上就会看到。

**import numpy as np
import matplotlib.pyplot as plt

# counts the number of iterations until the function diverges or
# returns the iteration threshold that we check until
def countIterationsUntilDivergent(c, threshold):
    z = complex(0, 0)
    for iteration in range(threshold):
        z = (z*z) + c

        if abs(z) > 4:
            break
            pass
        pass
    return iteration**

下一个函数有点庞大,但最后,它简单地创建了实轴和虚轴,将它们分配给一个二维数组,然后运行循环。

**def mandelbrot(threshold, density):
    # location and size of the atlas rectangle
    # realAxis = np.linspace(-2.25, 0.75, density)
    # imaginaryAxis = np.linspace(-1.5, 1.5, density)
    realAxis = np.linspace(-0.22, -0.219, 1000)
    imaginaryAxis = np.linspace(-0.70, -0.699, 1000)
    realAxisLen = len(realAxis)
    imaginaryAxisLen = len(imaginaryAxis)

    # 2-D array to represent mandelbrot atlas
    atlas = np.empty((realAxisLen, imaginaryAxisLen))

    print('realAxisLen: {}, imaginaryAxisLen: {}'.format(realAxisLen, imaginaryAxisLen))

    # color each point in the atlas depending on the iteration count
    for ix in range(realAxisLen):
        for iy in range(imaginaryAxisLen):
            cx = realAxis[ix]
            cy = imaginaryAxis[iy]
            c = complex(cx, cy)

            atlas[ix, iy] = countIterationsUntilDivergent(c, threshold)
            pass
        pass

    return atlas.T**

计算在单个线程上进行,如下所示:

htop

多线程

现在,为了在多线程中运行它,我们可以使用multiprocessing模块并像这样运行它。

calc_row()函数可以简化,但它指出了我们的不同之处:逐行计算图像,而不是一次一个点。

**import multiprocessing as mp
import itertools

def calc_row(cx, cy, threshold=120):
    c = complex(cx[1], cy[1])
    return (cx[0], cy[0], countIterationsUntilDivergent(c, threshold))**

接下来,我做了一个有问题的决定,通过使用starmapPool来简化循环,直接将嵌套循环的排列作为参数。

换句话说,无论我们给进程池多少个进程,我们都在运行calc_row(cx, cy, threshold)multiprocessing库负责分别传递来自listiterator的参数。

我们还返回了一个看起来很奇怪的元组,所以我们可以跟踪图像中的索引。

**def mandelbrot_multi(threshold, density, cpus=4):
    realAxis = np.linspace(-0.22, -0.219, 1000)
    imaginaryAxis = np.linspace(-0.70, -0.699, 1000)
    realAxisLen = len(realAxis)
    imaginaryAxisLen = len(imaginaryAxis)
    atlas = np.empty((realAxisLen, imaginaryAxisLen))

    # Create list of permutations
    realAxis = [(i,e ) for i,e in enumerate(realAxis)] 
    imaginaryAxis = [(i,e ) for i,e in enumerate(imaginaryAxis)] 

    paramlist = list(itertools.product(realAxis, imaginaryAxis))
    paramlist = list(map(lambda t: t + (threshold,),paramlist))

    # Create a multiprocessing pool
    pool = mp.Pool(cpus)

    n = pool.starmap(calc_row, paramlist)
    pool.close()
    pool.join()
    return n, atlas**

它更巧妙的利用了我们现有的资源:

htop

从性能的角度来看,我们在单个 CPU 上同时使用了 8.4s2.53s ,由于使用了mutliprocessing模块,内存开销很大。

当然,有很多不同的方法可以加速这一过程,比如*Cython**numpy**tensorflow*,等等,但是看看现成的并发,让我们将它与 *go* 进行比较。我不擅长选择例子,分形很漂亮。😃****

让我们看看它在go是什么样子。

单线程的

单线程版本没有太大的不同。我重复使用了相同的代码,但是简单地在go中重写了它。

大多数 *go* 实现都使用 *Image* 包来生成 go 中的映像——这对于一个独立的项目来说是有意义的。然而,在这里,我将数组写到磁盘并在 *numpy* 中读取,因此, *Python* ,以保持代码简洁。 *Python* *go* 的性能数字都是 只是计算 ,不是 I/O 或绘图像素!

首先,我们导入所需的包并编写一个np.linespace()等价物,它返回指定间隔内的均匀分布的数字。

**package main

import (
	"bytes"
	"fmt"
	"log"
	"math/cmplx"
	"os"
	"strings"
	"time"

	"encoding/binary"
)

func linspace(start, end float64, num int) []float64 {
	result := make([]float64, num)
	step := (end - start) / float64(num-1)
	for i := range result {
		result[i] = start + float64(i)*step
	}
	return result
}**

代码的其余部分应该看起来很熟悉——注意非常具体的强类型数据类型和返回类型。

**func countIterationsUntilDivergent(c complex128, threshold int64) int64 {
	z := complex(0, 0)
	var ix int64 = 0
	for i := int64(0); i < threshold; i++ {
		ix = i
		z = (z * z) + c
		if cmplx.Abs(z) > 4 {
			return i
		}
	}
	return ix
}

func mandelbrot(threshold, density int64) [][]int64 {
	realAxis := linspace(-0.22, -0.219, 1000)
	imaginaryAxis := linspace(-0.70, -0.699, 1000)
	fmt.Printf("realAxis %v\n", len(realAxis))
	fmt.Printf("imaginaryAxis %v\n", len(imaginaryAxis))
	atlas := make([][]int64, len(realAxis))
	for i := range atlas {
		atlas[i] = make([]int64, len(imaginaryAxis))
	}
	fmt.Printf("atlas %v\n", len(atlas))
	for ix, _ := range realAxis {
		for iy, _ := range imaginaryAxis {
			cx := realAxis[ix]
			cy := imaginaryAxis[iy]
			c := complex(cx, cy)
			//fmt.Printf("ix, iy: %v %v\n", ix, iy)
			atlas[ix][iy] = countIterationsUntilDivergent(c, threshold)
		}
	}
	return atlas
}**

多线程

通过使用一个叫做goroutines的概念,Go 使这变得容易多了。我们可以简单地使用go指令,而不必处理 Python mutltiprocessing模块、poolsmap vs. starmap以及 Python 解释器的复杂性。

正如我前面提到的,这里的代码是有意简单的,可以进行简单的优化,但是我尽量让 *go* 代码尽可能接近 *Python* 代码。请原谅任何简化。

首先,我们将从 Python 中重新创建calc_row方法,这一次使用一个struct来返回索引和值,因为我们将在第二步中使用的channel不会采用多种返回类型:

**type triple struct {
	ix, iy int64
	c      int64
}

func calcRow(ix, iy int64, c complex128, threshold int64) triple {
	return triple{ix, iy, countIterationsUntilDivergent(c, threshold)}
}**

我们的主要功能将使用两个概念:channels和前面提到的goroutine

一个 goroutine 有一个简单的模型:它是一个与相同地址空间中的其他 goroutine 同时执行的函数。go 文档将其与 Unix shell &操作符进行了比较,我发现这是一个很好的类比。

我们正在使用的通道是一个缓冲通道,其作用类似于我们并发函数的管道,因为非缓冲通道天生就是阻塞的。

这导致了下面的代码,该代码包装了内部循环(见上面关于琐碎优化的评论和这里的缺乏——我相信甚至一个指向goroutine中的WaitGroup和一个更小的channel buffer的指针可能会加速这个过程,但是我还没有测试过它)。

**func mandelbrot(threshold, density int64) [][]int64 {
	realAxis := linspace(-0.22, -0.219, 1000)
	imaginaryAxis := linspace(-0.70, -0.699, 1000)
	atlas := make([][]int64, len(realAxis))
	for i := range atlas {
		atlas[i] = make([]int64, len(imaginaryAxis))
	}
	// Make a buffered channel
	ch := make(chan triple, int64(len(realAxis))*int64(len(imaginaryAxis)))

	for ix, _ := range realAxis {
		go func(ix int) {
			for iy, _ := range imaginaryAxis {
				cx := realAxis[ix]
				cy := imaginaryAxis[iy]
				c := complex(cx, cy)
				res := calcRow(int64(ix), int64(iy), c, threshold)
				ch <- res
			}
		}(ix)
	}

	for i := int64(0); i < int64(len(realAxis))*int64(len(imaginaryAxis)); i++ {
		select {
		case res := <-ch:
			atlas[res.ix][res.iy] = res.c
		}
	}
	return atlas
}**

现在,对于go,我们看到的是在单个 CPU 上的0.38 秒和代码中的0.18 秒,虽然相似,但要简洁得多。

最终性能

我要把这个留在这里。正如我之前概述的那样,goPython代码都可以进一步优化,但是我们仍然可以获得大约 45 倍的加速

使用 matplotlib 生成;CC BY-SA 3.0

现实生活中的考虑

谈论理论概念可能很有趣,但这只是难题中相对较小的一部分。虽然我确信 2020 年将是Haskell被广泛用于生产的一年,但我选择、使用和推荐人们学习一门语言的方法主要是基于现实生活中的使用,而不是学术理想。

语言流行度

这总是一个有趣的问题。

根据 StackOverflow 的说法,围棋相关问题的受欢迎程度甚至还赶不上主要玩家 Python。

https://insights.stackoverflow.com/trends?tags=go%2Cpython

将此与其他一些大大小小的玩家——Java、Haskell、Scala、Lisp——进行对比,结果相似:

https://insights.stackoverflow.com/trends?tags = go % 2c python % 2c Java % 2c Scala % 2c haskell % 2c lisp

现在:提问的百分比是一个很好的衡量标准吗?大概不会。Python 是一门非常受欢迎的学习语言——我自己刚刚参与了它的培训准备——自然会吸引大量的初学者和经验丰富的专业人士。

谷歌趋势显示了一个类似的故事:

https://trends.google.com

(红色—Python;蓝色- go)

我认为可以公平地说 Python 更受欢迎——但是go至少有一个利基市场,如果不是一个上升轨道的话。借助欺骗性可视化的力量,我们可以放大上面的 StackOverflow 图:

https://insights.stackoverflow.com/trends?tags=go

事实上,找到了一个上升的轨迹。

此外,如果 StackOverflow 的年度开发者调查可信,当被问及“最受欢迎的技术”时,go从 2018 年的 7.2%上升到 2019 年的 8.8%,并在 2020 年上升到 9.4%。

根据的同一项调查,美国go的程序员也以每年 14 万美元的薪酬排名第二(高于 2019 年的第三),仅次于Scala(15 万美元)。

有希望!😃

生态系统

解释前两张图的部分原因是 Python 的巨大生态系统——后端、前端、统计、机器学习、深度学习、图形分析、GIS、机器人——它就在那里,它将有成千上万的贡献者和成千上万的用户。

这里有对应的词,我试着总结了它们,以及它们在 GitHub 上的相对受欢迎程度:

此处链接:https://CHOL linger . com/blog/2020/06/a-data-engineering-perspective-on-go-vs .-python-part-1/#生态系统

很明显,至少从数据工程和数据科学的角度来看,围棋生态系统还有很长的路要走。

【1】阿帕奇光束不能替代 Spark

学习曲线

这个是主观的——我个人觉得Python只在表面上更容易学。如果你真的想理解底层的概念、架构和库,Python真的是一个兔子洞,不像Java

另一方面,go是一种相当简单的语言,它关注于某些元素。请允许我引用:

设计 Go 的时候,Java 和 C++是编写服务器最常用的语言,至少在 Google 是这样。我们觉得这些语言需要太多的记账和重复。一些程序员以效率和类型安全为代价,转向更动态、更流畅的语言,如 Python。我们觉得在单一语言中实现高效、安全和流畅应该是可能的。

Go 试图在单词的两个意义上减少打字量。在整个设计过程中,我们努力减少混乱和复杂性。没有转发声明,也没有头文件;所有东西都声明一次。初始化是富于表现力的、自动的和易于使用的。语法干净,关键字少。口吃(foo。Foo myFoo = new(foo。Foo))通过使用:= declare-and-initialize 构造的简单类型派生来减少。也许最根本的是,没有类型层次结构:类型就是类型,它们不需要声明它们之间的关系。这些简化使得 Go 既有表现力又易于理解,同时又不牺牲复杂性。*

另一个重要原则是保持概念的正交性。可以为任何类型实现方法;结构代表数据,而接口代表抽象;诸如此类。正交性使得更容易理解当事物组合时会发生什么。

https://golang.org/doc/faq#creating_a_new_language

快速浏览一下LinkedIn Learning就会发现go总共有 4 道菜Python有 168 道菜。

在我自己的经验中,最有帮助的事情是通过逐个例子并真正阅读文档。另一方面,Python 作为更广泛层次的外部教程、课程、认证、博客帖子[&mldr;]来自我这样的人,大学,大公司。

在谷歌上查询“go 语言教程”会返回 17 亿条结果,而“python 语言教程”会返回 1620 亿条结果

阿帕奇波束

现在,我们已经讨论了很多关于goPython的一般性问题。但是这个帖子的开篇是什么——BeamDataflow在哪里?

这一部分将在本文的第 2 部分进行简要阐述

一般来说,beam go SDK 确实提供了运行相对简单的任务所需的核心功能。然而,在撰写本文时(2020-06-11),它确实有一系列的缺点。

转换

让我们看看跨beam语言的可用转换。我挑选了几个,但是请随意参考所有的文档以获得完整的图片:

https://CHOL linger . com/blog/2020/06/a-data-engineering-perspective-on-go-vs .-python-part-1/# transformations

对于来自Python的人来说,最显著的不同将是管道的整体外观。

这是在Python中如何完成的(旁注:没有什么可以阻止你调用data.apply(func),因为操作符只是过载了):

**class CountWords(beam.PTransform):
  def expand(self, pcoll):
    return (
        pcoll
        # Convert lines of text into individual words.
        | 'ExtractWords' >>
        beam.FlatMap(lambda x: re.findall(r'[A-Za-z\']+', x))

        # Count the number of times each word occurs.
        | beam.combiners.Count.PerElement())

counts = lines | CountWords()**

go中,它看起来更像一个常规的旧函数:

**func CountWords(s beam.Scope, lines beam.PCollection) beam.PCollection {
	s = s.Scope("CountWords")

	// Convert lines of text into individual words.
	col := beam.ParDo(s, extractFn, lines)

	// Count the number of times each word occurs.
	return stats.Count(s, col)
}**

我们将在第二部分探讨这些细节

输入-输出

I/O 可能是go sdk 中最受限制的部分,有许多连接器不可用于 go。

请参见 此链接 了解最新概况。

https://beam.apache.org/documentation/io/built-in/

如果要我总结的话:beam上的go支持基本的Google Cloud服务和地方发展,而Java则涵盖了几乎所有情况。[2]

[2]请记住,一些连接器,如 *DatabaseIO* ,本质上是特定于语言的

滑行装置

最后,看看可用的运行器,go或多或少地受限于DirectDataflow,这符合我在 I/O 上的声明。

https://CHOL linger . com/blog/2020/06/a-data-engineering-perspective-on-go-vs .-python-part-1/# runners

答(是)表示这些跑步者有局限性

逐行示例

我建议通过[WordCount](https://beam.apache.org/get-started/wordcount-example/#minimalwordcount-example)

WordCount是一个很好的例子,因为它展示了以下概念:

  • 创建管道
  • 将转换应用于管道
  • 阅读输入
  • 应用帕尔多变换
  • 应用 SDK 提供的转换
  • 写入输出(在本例中:写入文本文件)
  • 运行管道

为了简洁起见,我不会在这一点上深入那些细节。

结论

首先要问的问题之一应该是:比较这两种语言有意义吗?我的答案可能是显而易见的——虽然go可能是为不同的用例设计的(通用脚本和机器学习用例与系统/“云”编程),但从数据工程的角度来看,上面概述的概念仍然让我兴奋不已。

go有许多概念,不需要庞大的pip依赖树就能工作,产生干净的代码,易于编译,非常快,而且(在我看来)对未来的数据和 ML 用例有很大的潜力。

总之: **go** **Python** 显然是非常不同的语言——正如我在上面的中用我精选的例子成功概括的那样。

后续步骤

由于我在这篇文章中只浏览了Apache Beam的表面,下一篇文章将关注以下问题,以将Dataflow用作“野外的go”的真实示例:

  • go Beam SDK 有多成熟?
  • 它支持什么?少了什么?
  • 什么是根本区别?
  • (如何)我们可以在GCP运行Dataflow作业?

所有的开发和基准测试都是在 GNU/Linux [PopOS!内核 5.4 上的 19.10]在 2019 System76 Gazelle 笔记本电脑上使用 12 个英特尔 i7–9750h v cores @ 4.5 GHz 和 16GB RAM

原载于 2020 年 6 月 11 日 https://chollinger.com **

从数据工程的角度看 Go 与 Python(第 2 部分——数据流)

原文:https://towardsdatascience.com/a-data-engineering-perspective-on-go-vs-python-part-2-dataflow-472b42a14f9?source=collection_archive---------60-----------------------

使用 Apache Beam & Dataflow 探索、剖析和基准测试 go SDK

介绍

在我们从数据工程的角度比较 Python 和 go 的第 2 部分中,我们将最终看一下 Apache Beam 和 Google Dataflow,以及 go SDK 和 Python SDK 的不同之处,我们正在处理的缺点,通过运行大量基准测试它有多快,以及进行转换的可行性。

你可以在这里找到《T4》第一部。

阿帕奇光束和谷歌数据流

虽然我们已经在之前的中多次使用过阿帕奇光束,请允许我再简单介绍一下。

Apache Beam 是一个开源的统一模型,用于定义批处理和流数据并行处理管道。使用一个开源的 Beam SDKs,您可以构建一个定义管道的程序。然后,管道由 Beam 支持的分布式处理后端之一执行,包括 Apache Flink、Apache Spark 和 Google Cloud Dataflow。

https://beam.apache.org/get-started/beam-overview/

Beam 可以用于各种数据用例,就像 Apache Spark 一样——ETL(提取、转换、加载)管道、流分析,或者从文件系统到 RDMBS 的简单数据移动。

为什么梁是有趣的

我得到的最好的专业建议之一是问“那又怎样?”。话虽如此:那又怎样,我为什么关心梁?

对我来说,Beam 模型最有趣的方面之一是管道逻辑、语言和执行环境的解耦。我可以在一张纸上设计我的逻辑(例如,用一些Beam-特定术语画一个DAG-我们马上就可以完成),用任何主要语言实现它-甚至是多种语言-并在任何支持的Runners上运行它。

上次我们在这个博客上使用它时,我们用它编写了一个管道来分析 reddit 帖子,并在Dataflow runner 上执行,如下所示:

因为这条管道是用 Python 编写的,所以没有什么可以阻止我们在本地 Hadoop 集群、AWS EMR 上运行完全相同的作业,或者只是使用DirectRunner在本地运行它。这种水平的可移植性,结合我碰巧发现比Spark更精简的编程模型,使得Beam成为一个非常有趣的框架。

实际上,我们将在本文的示例部分中这样做,并设计一个管道,用Pythongo编写它,并在不同的Runners上运行它。

核心概念

Beam中的一切都始于Pipeline.``Beam编程模型的工作原理是通过代码暴露高级抽象,允许您的Pipeline在给定数据集上执行PTransforms的图形,这在术语上是在不可变集合上操作,称为PCollections,可以通过IO操作将其移动到持久状态。作业可以在不同的Runners上执行,以提供一个(分布式)执行环境。

在我们看一个真实世界的例子之前,让我们深入研究一下这些概念。

这是一个浓缩版的 官方阿帕奇光束文档 ,建议你完整阅读以获得更深入的观点

管道

一个Pipeline对象是任何作业的起点,它通常由一个configuration对象初始化,该对象定义了如何你的管道在哪里运行。

p 收藏

与 Spark RDDDataFrame不同的是,PCollection是不可变的数据集合,可以通过管道的生命周期在内存中修改。

一个PCollection中的数据可以是任意类型,只要元素可以被编码为string以便在工人之间序列化它们。

可以是任意大小的,但是如果集合太大而不适合单个工作节点上的内存,它们的元素可能由不同的工作节点处理。此外,它们可以是有界的(即,具有固定的大小)或者是无界的(即,是“开放式的”,就像在流场景中一样)。

转换

Transforms通过apply运算用户代码和逻辑,在PCollection的单个元素上应用逻辑,并返回可在后续步骤中使用的完整的PCollection

https://beam . Apache . org/documentation/programming-guide/# applying-transforms

还可以通过将 DAG 分成多个独立的步骤来branch流水线:

https://beam . Apache . org/documentation/programming-guide/# applying-transforms

自定义transforms需要遵守一些规则,最显著的是可串行化(因为数据需要在工作线程之间传输)单线程执行(因为每个元素都应该在自己的线程中工作,由底层运行器协调),以及等幂(因为可能会发生重试)。

Beam提供了几个可以开箱即用的内核transforms:

  • ParDo
  • GroupByKey
  • CoGroupByKey
  • Combine
  • Flatten
  • Partition

帕尔多

ParDo转换可能是最常见的一种,因为它类似于map操作:将逻辑应用于PCollection的每个元素,并返回所述元素(或者不返回它,因此,filtering返回集合)。

ParDo作为构建博客的基础,在平面数据流上应用逻辑,然后可以通过groupingflattening和其他聚合逻辑进一步增强。

为了理解一个ParDo实际上做什么,Beam文档对一个ParDo的生命周期提供了很好的解释:

https://beam . Apache . org/documentation/programming-guide/# applying-transforms

CoGroupByKey

CoGroupByKey通过多个输入集合中的键聚集所有输入元素。CoGroupByKey 执行两个或更多具有相同键类型的键/值 p 集合的关系连接——这是一个非常有用的东西,我们将在下面的例子中使用。

计划

一个Schema定义了一个PCollection中元素的逻辑结构和数据类型。Beam Schemas类似于parquetdatabase模式,应该定义namestypes,以及关于字段是否可以是NULL的信息。

Beam 支持以下基本类型:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# schemas

输入-输出

I/O用于提供输入数据,并为管道提供一个或多个定义的输出。我将参考第 1 部分以获得 SDK 提供的所有I/O连接器的完整列表。

I/O还可以定制连接器,通过从现有基类继承来读取不支持的文件类型。这可能很有挑战性(因为您希望能够分割一个文件源,这样它就可以被多个工作人员处理),但是过一会儿,这就变得非常简单了。

滑行装置

Runners定义哪个系统执行流水线,例如通过本地运行(DirectRunner)、在Google Dataflow上运行或通过Apache Spark

I/O类似,请参考第 1 部分进行概述。

一个示例作业的用例

为了展示一些基本的区别,让我们定义一个可以在Pythongo中实现的用例。

在这个例子中,我们遵循这个简单的用户故事:“作为一个电影爱好者,我想找到符合我喜好的电影,这样我就可以看一部新电影了”

我们的偏好应为:

  1. 我们希望解析标题和评级(读取数据)
  2. 我们只对电影感兴趣,对电视剧不感兴趣;此外,电影应该在 1970 年之后制作,以获得一些更可靠的元数据作为我们决策的基础,因为旧的电影通常只有基本信息(过滤数据)
  3. 我们既要基本标题,也要来自不同来源的评级信息(组合数据)
  4. 我们想要可用格式的数据(写数据 ) [0]

为此,我们将使用 IMDb 数据集,它可用于非商业用途,并且每天更新。

完整的源代码可以在GitHub上获得。

到现在为止,您可能已经知道这些“偏好”是为了展示各种 *Beam* 功能——这不是一个花哨的推荐引擎,我们并不真正关心输出

绘制设计

正如我在引言中所说的,我们可以先从设计管道开始,然后再讨论特定于语言的逻辑。

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# drawing-the-design

这里我们有两个主要的流程,它们做类似的事情:它们读取数据,解析数据格式,并对数据应用自定义过滤器。接下来,它们被组合成一个一致的集合,并写入一个或多个 I/O 目标。

让我们来看看如何把它翻译成代码。

获取数据

如果你同意 IMDb 的许可证,你可以在这里找到数据。

我们将从基本的标题数据开始,并确保我们从一个小的测试集开始,这样我们就可以在没有集群的情况下进行本地开发。为了做到这一点,我们将获取随机测试数据,以及一部我们知道符合我们标准的电影,1971 年的经典“消失点”,id 为tt0067927(因为我们不太可能在我们将使用的 2 个数据集之间找到更多匹配,否则,鉴于体积)。

wget https://datasets.imdbws.com/title.basics.tsv.gz && gunzip title.basics.tsv.gz 
# Create a small test file
head -1 title.basics.tsv > title.basics.100.tsv
shuf -n 100 title.basics.tsv >> title.basics.100.tsv
grep "tt0067927" title.basics.tsv >> title.basics.100.tsv

title.basics

该数据集包含基本标题信息,并且是一个 564MB 制表符分隔文件

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# getting-data

我们将用它来过滤大部分记录。

title.ratings

该数据集包含所有标题的评级,并且是一个 18MB 制表符分隔文件

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# getting-data

创建管道

我们的 Beam 管道的第一步是创建一个创建Pipeline对象的框架代码,解析参数,并设置一个记录器。

计算机编程语言

我们首先需要通过运行pip3 install --upgrade pippip3 install apache-beam==2.22.0 --upgrade来安装 Beam。

我们的框架使用Python的标准logger模块来记录日志,使用argparse来读取将要传递给管道的参数。

from __future__ import absolute_import

import argparse
import logging
import apache_beam as beam
from apache_beam.io import ReadFromText
from apache_beam.io import WriteToText
from apache_beam.options.pipeline_options import PipelineOptions, GoogleCloudOptions
from apache_beam.options.pipeline_options import SetupOptions

def run(argv=None):
    # Parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('--input-ratings',
                        dest='input_ratings',
                        required=True,
                        help='Input rating file to process.')
    parser.add_argument('--input-titles',
                        dest='input_titles',
                        required=True,
                        help='Input title file to process.')
    parser.add_argument('--output',
                        dest='output',
                        required=True,
                        help='Output to write results to.')
    known_args, pipeline_args = parser.parse_known_args(argv)

    pipeline_options = PipelineOptions(pipeline_args)
    pipeline_options.view_as(SetupOptions).save_main_session = True

    # Create the pipeline
    with beam.Pipeline(options=pipeline_options) as p:
        # TODO: Run it
        pass

if __name__ == '__main__':
    # Set the logger
    logging.getLogger().setLevel(logging.INFO)
    logging.basicConfig(format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
        datefmt='%Y-%m-%d:%H:%M:%S',
        level=logging.INFO)
    # Run the core pipeline
    logging.info('Starting')
    run()

这里没有太多需要注意的地方——我们所有的管道代码都在with块下,一旦我们编写了自己的步骤,它将定义我们刚刚设计的DAG

对于go,我们可以通过go get安装beam,而不是通过go get -u github.com/apache/beam/sdks/go/...安装pip

接下来,我们的管道框架将使用flags包作为参数,使用log作为日志。

package main

import (
	"context"
	"flag"
	"log"

	"github.com/apache/beam/sdks/go/pkg/beam"
	"github.com/apache/beam/sdks/go/pkg/beam/io/textio"
	"github.com/apache/beam/sdks/go/pkg/beam/x/beamx"
)

func main() {
	// Define arguments
	var inputBasePath = flag.String("input-basics", "", "Input base file")
	var inputRatingsPath = flag.String("input-ratings", "", "Input ratings file")
	var outputPath = flag.String("output", "", "Output path")
	// Parse flags
	flag.Parse()

	// Initialize Beam
	beam.Init()

	// Input validation. Must be after Init().
	if *inputBasePath == "" || *inputRatingsPath == "" || *outputPath == "" {
		log.Fatal("Usage: movie_pipeline --input-basics $PATH, --input-ratings $PATH --output $PATH")
	}

	// Create a Pipeline
	p := beam.NewPipeline()
	s := p.Root()

    // Pipeline code

	// Concept #1: The beamx.Run convenience wrapper allows a number of
	// pre-defined runners to be used via the --runner flag.
	if err := beamx.Run(context.Background(), p); err != nil {
		log.Fatalf("Failed to execute job: %v", err)
	}
}

这里有几个值得注意的地方。首先,flags包不支持强制属性,因此我们必须手动检查由flag.Parse()传递的字符串指针。你会在整个代码中发现类似的块,因为go不知道Exception的概念,因此,错误是返回元素(例如,一个函数可能返回一个数据元组和一个可选错误),需要手动检查。

此外,注意如何在输入验证之前调用beam.Init()

读取和解析数据

接下来,我们需要读取数据并解析TSV格式。我们可以使用我们的第一个ParDo调用来实现这一点。

计算机编程语言

首先,让我们通过创建beam.DoFn的子类来定义ParDo操作,如下所示:

class ParseCsv(beam.DoFn):
    def __init__(self, col_names: list):
        self.col_names = col_names

    def process(self, string: str):
        reader = csv.DictReader(string.splitlines(), fieldnames=self.col_names, delimiter='\t')
        for row in reader:
            yield row

这个类将简单地把我们的 CSV 从行str解析成一个dict,给我们dict作为单独的元素在下一个transforms中使用。

对于自定义ParDo,方法process必须被覆盖。process应该是一个generator并因此,不得不yield单独记录。对于 *PCollection*中的每条记录,该函数将被调用。如果我们用return代替yield,你马上就会看到会发生什么。

自定义参数可以通过覆盖__init__()中的constructor传递给类。

为了将它与管道集成,我们需要定义流程。在Beam Python SDK中,>>|操作符在PCollection之上定义了我们单独的加工(apply)步骤。

对于每个步骤,我们可以调用beam.ParDo并提供一个DoFn子类的实例。

with beam.Pipeline(options=pipeline_options) as p:
    (p  | 'Read data' >> beam.io.ReadFromText(known_args.input_titles, skip_header_lines=1)
        | 'Parse CSV' >> beam.ParDo(ParseCsv(['titleId', 'ordering','title','region','language','types','attributes','isOriginalTitle']))
        | 'Print' >> beam.Map(print)
    )

这将读取文本文件,解析TSV,产生一个PCollection,并使用map简单地打印值。

输出如下所示:

{'titleId': 'tt0000001', 'ordering': '1', 'title': 'Карменсіта', 'region': 'UA', 'language': '\\N', 'types': 'imdbDisplay', 'attributes': '\\N', 'isOriginalTitle': '0'}
{'titleId': 'tt0000001', 'ordering': '2', 'title': 'Carmencita', 'region': 'DE', 'language': '\\N', 'types': '\\N', 'attributes': 'literal title', 'isOriginalTitle': '0'}

这个简单的起点展示了BeamPython一起使用的非常具体的语法。虽然它确实创建了一个清晰易读的逻辑,但它肯定比常规的方法链接方法更容易让人混淆。

在这里,我们可能会看到Pythongo之间一些最显著的差异——但正如我所发现的,也有同样显著的相似之处。

读取数据并应用下一个ParDo并不遵循Python的重载语法(使用>>|),而是导致在每个步骤后返回各种 *PCollections* :

// Parse the movies file
	lines_movies := textio.Read(s, *inputBasePath)
	base_movies := beam.ParDo(s, &movieFn{}, lines_movies)

虽然这可能看起来与Python非常不同,但从根本上来说,发生了同样的事情:图形的每一步都返回一个新的 *PCollection*,下一步可以对其进行处理。

这里要提到的另一件事是指针的使用。*inputBasePath是指向我们之前给出的flags参数的指针。在go中,一个*string可以是nil,而普通的字符串则不能(因为go中的nil表示“它不指向任何东西”,而string只能是空的或者被字符填充——下面会详细介绍)。众所周知,Python没有暴露的指针(T21 的另一种主要语言Java也没有)。

下一个看起来非常不同的东西是实际的ParDo。我们来分析一下。

Beam的泛型ParDo函数签名如下:

func ParDo(s Scope, dofn interface{}, col PCollection, opts ...Option) PCollection {
	ret := MustN(TryParDo(s, dofn, col, opts...))
	if len(ret) != 1 {
		panic(formatParDoError(dofn, len(ret), 1))
	}
	return ret[0]
}

其中s Scope是你的pipeline对象,dofn interface{}使用goempty interface逻辑来定义一个可能保存任何类型的值的接口(我一会儿再回到那个),而col显然是我们的PCollection,类似于我们在Python中看到的。

这意味着beam.ParDo(s, &movieFn{}, lines_movies)简单地声明:应用函数moveFn,它必须是一个ParDo(记住:静态类型!),并将名为line_moviesPCollection作为输入。

一旦理解了语法,这与

| 'Parse CSV' >> beam.ParDo(ParseCsv(['titleId', 'ordering','title','region','language','types','attributes','isOriginalTitle']))

在 Python 中。

我们将在下一节看看&movieFn{}做了什么。无论如何,在这一点上,我们有了输入TSV中每一行的结构化表示。

转换数据

接下来,我们需要转换我们的数据,以确保我们有可以在输出中使用的正确的数据类型,并确保我们在接下来的步骤中的filter逻辑是清晰的。

计算机编程语言

请注意上面输出中的NULL是如何被引用为\N的,以及isOriginalTitle听起来像是boolean,但实际上是integer

我们可以简单地创建另一个ParDo转换来处理这个场景。为了避免每个文件只有一个ParDo类,我们将使它动态化。

class CleanData(beam.DoFn):
    def __init__(self, bool_cols=[]):
        self.bool_cols = bool_cols

    def process(self, record: dict):
        for k in record:
            # Map \N to None
            if record[k] == '\\N':
                record[k] = None
        # Convert e.g., `isOriginalTitle` to Boolean
        for col in self.bool_cols:
            if record[col] == '0': 
                record[col] = False
            else:
                record[col] = True
        # Return
        yield record

因为Python dicts可以接受任意类型,所以简单地在 dict 中改变值是很容易的。请注意我们必须如何将0视为string,因为Python是动态类型的,在这里不强制类型,并且给定 TSV 输入,一切都是str

此时,您可能会发现自己处于两种思想流派之一:要么,您很高兴Python允许您使用dicts编写管道,而不关心它们各自的类型(甚至不关心dict中字段的数量或名称)!)——这使得编写管道更加容易。

或者,你遗漏了Javago强制的严格打字。在这两种情况下,在将任何数据持久化到任何地方之前,我们都被迫关心结构和类型,以避免无效的转换或错误的输出到我们的目标系统中。

对于go,让我们重温一下之前的&movieFn{}论点。

我们已经创建了一个名为moveFnstruct,它保存了我们的数据结构及其类型:

type movieFn struct {
	tconst, titleType, primaryTitle, originalTitle string
	isAdult                                        bool
	startYear, endYear, runtimeMinutes             int64
	genres                                         string
}

然后我们在这个struct上定义一个ParDo方法:

func (f *movieFn) ProcessElement(line string, emit func(movieFn)) {
	row := strings.Split(line, "\t")
	fmt.Printf("%v\n", row)
	// Skip the header
	if row[0] != "tconst" {
		// Map nulls

		// Convert the types
		startYear, err1 := strconv.ParseInt(row[5], 10, 64)
		endYear, _ := strconv.ParseInt(row[6], 10, 64)
		runtimeMinutes, err3 := strconv.ParseInt(row[7], 10, 64)
		// Convert Boolean
		isAdultInt, err4 := strconv.ParseInt(row[4], 10, 64)
		var isAdult bool
		if isAdultInt == 0 {
			isAdult = false
		} else {
			isAdult = true
		}
		if err1 == nil && err3 == nil && err4 == nil {
			// If the types match, return a rating struct
			m := movieFn{
				tconst:         row[0],
				titleType:      row[1],
				primaryTitle:   row[2],
				originalTitle:  row[3],
				isAdult:        isAdult,
				startYear:      startYear,
				endYear:        endYear,
				runtimeMinutes: runtimeMinutes,
				genres:         row[8],
			}
			fmt.Printf("%v\n", m)
			emit(m)
		}
	}
}

它将解析行和将类型转换成单个的ParDo结合起来。我们在 Python 中对此进行了分解以解释概念,但从根本上来说,发生了同样的事情:我们需要通过分隔符tab来分割行,并创建一个类似json的结构(这就是这个struct将在内部序列化的内容!).

为了避免不得不处理多个structs,因为我们(与 Python 相反)不能简单地“重用dict和改变类型【0】,我们在一个单一的步骤中进行转换。

在对ParDo的实际调用中,&movieFn{}简单地翻译为“对movieFn结构的内存位置的引用,它被初始化为空”。

最后但同样重要的是,注意函数的返回是怎样的emit func(movieFn))Beam SDK 使用反射从传入和传出的PCollections中收集类型,在我们的例子中,输入为line string,输出为movieFn——通过指定一个函数作为输入,我们称之为类似于Python的本机yield。请注意实际的函数没有返回任何东西,因为emit函数是我们的ParDo的一个参数!

您可以将这个函数称为任何东西— emit只是在 go 示例中找到的样式。

应该注意的是,这个struct当然也可以通过简单地提供更多的方法来保存自定义方法(类似于Python类)。

让我们重新访问一下stringnil注释,并尝试将'\N'转换为nil以匹配我们的Python管道,假设我们想要一个NULL类型用于将数据写入例如BigQuery:

func (f *movieFn) CleanNulls(row []string, nullColIds []int) []string {
	for i, _ := range row {
		if row[i] == "\\N" {
			row[i] = nil
		}
	}
	return row
}

当然,编译器不接受:

cannot use nil as type string in assignment

一种解决方法是使用*string或者跟随,例如[bigquery->InterSchema](https://godoc.org/cloud.google.com/go/bigquery#InferSchema)NULL映射到期望它用于字符串的系统。

此外,我们需要确保我们不会意外地导出这个方法,否则,我们将得到:

graph.AsDoFn: unexpected exported method CleanNulls present. Valid methods are: [Setup StartBundle ProcessElement FinishBundle Teardown CreateInitialRestriction SplitRestriction RestrictionSize CreateTracker

这可以通过以小写字母“c”开始函数而简单地不导出它来解决:

func (f *movieFn) cleanNulls(row []string) []string {
	for i, _ := range row {
		if row[i] == "\\N" {
			row[i] = ""
		}
	}
	return row
}

这是与Python的另一个区别,因为go确保我们遵循预期的interface

虽然我个人确实认为逻辑go强加了一个String要么为空要么不为空,拥有两个不同的“空”类型并没有增加多少价值,但是从PythonJava的角度来看,我可以看到这对来自go的人来说是非常令人不快的。

我想我们可以用一个 *interface{}*

过滤数据

接下来,我们要过滤数据,以确保我们只获得我们想要的电影和收视率。

计算机编程语言

过滤数据可以通过使用另一个ParDo类来完成,但是带有一个 catch。让我们试试这个:

class FilterBasicData(beam.DoFn):
    def process(self, record: dict):
        if record['titleType'] == 'movie' and not record['isAdult']:
            yield record
        else:
            yield None

输出看起来很糟糕:

None
{'tconst': 'tt3080844', 'titleType': 'movie', 'primaryTitle': 'Almost Holy', 'originalTitle': 'Crocodile Gennadiy', 'isAdult': False, 'startYear': '2015', 'endYear': None, 'runtimeMinutes': '96', 'genres': 'Biography,Documentary,Drama'}
None

然而,如果我们回忆起DoFn是一个生成器(而不仅仅是一个出于某种原因使用yield而不是return的方法),我们可以快速使用它,简单地让不返回无效记录(以及添加我们的其他过滤标准),从而创建一个更小的PCollection来处理:

class FilterBasicData(beam.DoFn):
    def process(self, record: dict):
        if record['titleType'] == 'movie' and not record['isAdult']: 
            yield record
        # No else - no yield

并获得看起来不错的输出:

{'tconst': 'tt3080844', 'titleType': 'movie', 'primaryTitle': 'Almost Holy', 'originalTitle': 'Crocodile Gennadiy', 'isAdult': False, 'startYear': '2015', 'endYear': None, 'runtimeMinutes': '96', 'genres': 'Biography,Documentary,Drama'}
{'tconst': 'tt7497202', 'titleType': 'movie', 'primaryTitle': 'Wonderful Losers: A Different World', 'originalTitle': 'Wonderful Losers: A Different World', 'isAdult': False, 'startYear': '2017', 'endYear': None, 'runtimeMinutes': '71', 'genres': None}

但是我们的按年过滤呢?如果我们尝试把and record['startYear'] >= 1970:作为一个条件,我们会遇到:

TypeError: '>=' not supported between instances of 'str' and 'int' [while running 'Filter data']

因为 Python 缺乏严格的类型(还记得我们是如何在任何地方都没有定义模式的)。我们可以通过扩展CleanData来修复这个问题:

class CleanData(beam.DoFn):
    def __init__(self, bool_cols=[], int_cols=[]):
        self.bool_cols = bool_cols
        self.int_cols = int_cols

    def process(self, record: dict):
        for k in record:
            # Map \N to None
            if record[k] == '\\N':
                record[k] = None
        # Convert e.g., `isOriginalTitle` to Boolean
        for col in self.bool_cols:
            if record[col] == '0':
                record[col] = False
            else:
                record[col] = True
        # Force-parse numeric values
        for col in self.int_cols:
            if record[col] and record[col].isdigit():
                record[col] = int(record[col])
        # Return
        yield record

并将我们的过滤器调整为:

class FilterBasicData(beam.DoFn):
    def process(self, record: dict):
        if record['titleType'] == 'movie' and not record['isAdult'] and record['startYear'] and record['startYear'] >= 1970:
            yield record
        # No else - no yield

这给了我们一个电影列表。

这里的过滤和go没有太大区别。我们可以犯和在Python中一样的错误,但是混淆return和(在本例中)一个emit函数:

// Filters Movies
func filterMovies(movie movieFn) movieFn {
	if !movie.isAdult && movie.startYear >= 1970 {
		return movie
	}
	return movieFn{}
}

它会回来的

{    false 0 0 0 }
{tt3080844 movie Almost Holy Crocodile Gennadiy false 2015 0 96 Biography,Documentary,Drama}
{    false 0 0 0 }

而我们在上一节中讨论的方法是可行的:

// Filters Movies
func filterMovies(movie movieFn, emit func(movieFn)) {
	if !movie.isAdult && movie.startYear >= 1970 {
		emit(movie)
	}
}

请注意我们的静态类型的struct不会有任何TypeError: '>=' not supported between instances of 'str' and 'int'类型的问题

侧面输入、CoGroupByKey 和连接

由于IMDb数据的关系性质,我们将不得不处理多个文件来获得我们需要的所有标准。

有两种主要的方法可以做到这一点:Side Inputs,如果数据足够小,可以轻松地放入内存,或者CoGroupByKey,这是一种更昂贵的变体,会导致shuffle

尽管我们只需要一种方法,但我们将两者都考虑。

让我们获取评级数据,并从上面的输出中抓取一些记录,以确保我们至少有一个匹配:

wget https://datasets.imdbws.com/title.ratings.tsv.gz && gunzip title.ratings.tsv.gz 
# Create a small test file
head -1 title.ratings.tsv > title.ratings.100.tsv # header
shuf -n 100 title.ratings.tsv >> title.ratings.100.tsv
grep "tt0067927" title.ratings.tsv >> title.ratings.100.tsv

CoGroupByKey

首先我们来看看CoGroupByKey。这通常是更明智的选择,除非其中一个数据集的大小要小得多,并且可以作为内存中的数据传递Side Input

计算机编程语言

我们可以简单地分割我们的管道,这一次,返回一个PCollection而不是将它传递给beam.Map(print)

with beam.Pipeline(options=pipeline_options) as p:
        basic_data = (p | 'Read data' >> beam.io.ReadFromText(known_args.input_basics, skip_header_lines=1)
           | 'Parse CSV' >> beam.ParDo(ParseCsv(columns_title_basic))
           | 'Clean data' >> beam.ParDo(CleanData(bool_cols=['isAdult'], int_cols=['startYear', 'endYear', 'runtimeMinutes']))
           | 'Filter data' >> beam.ParDo(FilterBasicData())
         )

由于side inputs不是PCollections,我们可以使用Mapratings转换为静态的json:

rating_data = (p | 'Read data (Details)' >> beam.io.ReadFromText(known_args.input_ratings, skip_header_lines=1)
           | 'Parse CSV (Details)' >> beam.ParDo(ParseCsv(columns_ratings))
           | 'Clean data (Details)' >> beam.ParDo(CleanData(int_cols=['numVotes'], float_cols=['averageRating']))
           | 'Filter data (Details)' >> beam.ParDo(FilterRatingData())
         )

        rating_data = (p | 'Read data (Details)' >> beam.io.ReadFromText(known_args.input_ratings, skip_header_lines=1)
           | 'Parse CSV (Details)' >> beam.ParDo(ParseCsv(columns_ratings))
           | 'Clean data (Details)' >> beam.ParDo(CleanData(int_cols=['numVotes'], float_cols=['averageRating']))
           | 'Filter data (Details)' >> beam.ParDo(FilterRatingData())
         )

一旦我们都有了PCollections,我们就可以为CoGroupByKey准备数据:

# Create keys
        movie_keys = (basic_data
               | 'movie key' >> beam.Map(lambda r: (r['tconst'], r))
               #| 'Print' >> beam.Map(print)
        )
        rating_keys = (rating_data
               | 'rating key' >> beam.Map(lambda r: (r['tconst'], r))
        )

最后,应用CoGroupByKey变换和FlatMap它们在一起:

joined_dicts = (
            {'movie_keys': movie_keys, 'rating_keys': rating_keys} 
            | beam.CoGroupByKey()    
            | beam.FlatMap(join_ratings)
            | 'mergedicts' >> beam.Map(lambda dd: {**dd[0], **dd[1]})
            | 'Print' >> beam.Map(print)
        )

产生一条记录(我们随机选择输入):

{'tconst': 'tt0067927', 'titleType': 'movie', 'primaryTitle': 'Vanishing Point', 'originalTitle': 'Vanishing Point', 'isAdult': False, 'startYear': 1971, 'endYear': None, 'runtimeMinutes': 99, 'genres': 'Action,Crime,Thriller', 'averageRating': 7.2, 'numVotes': 25933}

你会注意到缺少这些“高级”主题的例子,比如CoGroupByKey,尽管它们实际上存在于 godocs 中。因此,弄清楚这一部分花费的时间比我希望的要长一些,但是一旦理解了其中的逻辑,这是有意义的。

为了使用CoGroupByKey,我们需要为每个PCollection创建一个KV对:

func extractRatingId(r ratingFn) (string, ratingFn) {
	return r.tconst, r
}

func extractMovieId(m movieFn) (string, movieFn) {
	return m.tconst, m
}

改变我们的产品系列:

// Combine
	combined := beam.CoGroupByKey(s,
		beam.ParDo(s, extractMovieId, filtered_movies),
		beam.ParDo(s, extractRatingId, filtered_ratings))

并按如下方式匹配它们:

func combineFn(tconst string, movieIter func(*movieFn) bool, ratingIter func(*ratingFn) bool, emit func(targetMovie)) {
	// Pointers to structs
	m := &movieFn{tconst: tconst}
	r := &ratingFn{tconst: tconst}
	// If match, emit
	if movieIter(m) && ratingIter(r) {
		fmt.Printf("%v %v\n", tconst, m)
		emit(targetMovie{
			Id:             m.tconst,
			TitleType:      m.titleType,
			PrimaryTitle:   m.primaryTitle,
			OriginalTitle:  m.originalTitle,
			IsAdult:        m.isAdult,
			StartYear:      m.startYear,
			EndYear:        m.endYear,
			RuntimeMinutes: m.runtimeMinutes,
			Genres:         m.genres,
			AverageRating:  r.averageRating,
			NumVotes:       r.numVotes,
		})
	}
}

注意func(*movieFn) bool,期待一个指向struct的指针,它将告诉我们是否有匹配。

侧面输入

Side Inputs比它们在go中看起来要复杂得多,但在Python中相对简单。

计算机编程语言

如果我们想使用Side Inputs,我们可以将我们更小的ratings PCollection作为list:

joined_dicts = (
        basic_data
        | 'Join' >> beam.ParDo(JoinRatings(), AsList(rating_data))
    )

到新的ParDo:

class JoinRatings(beam.DoFn):
    def process(self, movie: dict, ratings_side):
        for k in ratings_side:
            if k['tconst'] == movie['tconst']:
                yield {**movie, **k}

或者用AsDict调用[0]:

class JoinRatings(beam.DoFn):
    def process(self, movie: dict, ratings_side):
        if 'tconst' in movie and movie['tconst'] in ratings_side:
            yield {**movie, **ratings_side[movie['tconst']]}

并得到相同的结果,这次使用侧面输入。

【0】一个 *dict* 在这里会比一个列表高效很多;不过据我看, *go* SDK 并不支持 SideInputs 作为*map*;因此,我用 *lists* *maps* / *dicts* 实现了 *Python* *SideInputs***

我们将在SideInput这里强调我在Python部分指出的可能性。

首先,我们需要另一个结构作为我们的输出结构:

*type targetMovie struct {
	Id             string
	TitleType      string
	PrimaryTitle   string
	OriginalTitle  string
	IsAdult        bool
	StartYear      int64
	EndYear        int64
	RuntimeMinutes int64
	Genres         string
	// Ratings
	AverageRating float64
	NumVotes      int64
}*

注意这些值是从导出的,即以大写字母开始。

我们简单地定义了一个combine类型的函数,它需要一个sliceratingFn,而不是一个PCollection:

*func combineMoviesRatings(movie movieFn, ratings []ratingFn, emit func(targetMovie)) {
	for _, r := range ratings {
		if r.tconst == movie.tconst {
			emit(targetMovie{
				Id:             movie.tconst,
				TitleType:      movie.titleType,
				PrimaryTitle:   movie.primaryTitle,
				OriginalTitle:  movie.originalTitle,
				IsAdult:        movie.isAdult,
				StartYear:      movie.startYear,
				EndYear:        movie.endYear,
				RuntimeMinutes: movie.runtimeMinutes,
				Genres:         movie.genres,
				AverageRating:  r.averageRating,
				NumVotes:       r.numVotes,
			})
		}
	}
}*

并且用Side Input这样称呼它:

*combined := beam.ParDo(s, combineMoviesRatings, filtered_movies,
		beam.SideInput{Input: filtered_ratings})*

这样,我们得到了相同的输出:

*{"Id":"tt0067927","TitleType":"movie","PrimaryTitle":"Vanishing Point","OriginalTitle":"Vanishing Point","IsAdult":false,"StartYear":1971,"EndYear":0,"RuntimeMinutes":99,"Genres":"Action,Crime,Thriller","AverageRating":7.2,"NumVotes":25933}*

类似于我们在Python中看到的,做 n 次这个列表比较,我们得到 O(nn)并且会非常无效。*

由于我仍然不知道go SDK 是否有一个等同于Pythonapache_beam.pvalue.AsDict,我想出了这个可怕的变通方法,将一个PCollection作为单例侧输入传递给一个ParDo,并创建一个map[string]ratingFn:

*func makeRatingsMap(rr int, ratings []ratingFn, emit func(map[string]ratingFn)) {
	m := make(map[string]ratingFn)
	for _, r := range ratings {
		m[r.tconst] = r
	}
	emit(m)
}

func combineMoviesRatings(movie movieFn, ratings map[string]ratingFn, emit func(targetMovie)) {
	r, ok := ratings[movie.tconst]
	if ok {
		emit(targetMovie{
			Id:             movie.tconst,
			TitleType:      movie.titleType,
			PrimaryTitle:   movie.primaryTitle,
			OriginalTitle:  movie.originalTitle,
			IsAdult:        movie.isAdult,
			StartYear:      movie.startYear,
			EndYear:        movie.endYear,
			RuntimeMinutes: movie.runtimeMinutes,
			Genres:         movie.genres,
			AverageRating:  r.averageRating,
			NumVotes:       r.numVotes,
		})
	}
}*

我们称之为:

*// Fake PCollection to only run the next parDo once
	fakePCol := beam.CreateList(s, [1]int{
		0,
	})
	// To Map
	filteredRatingsMap := beam.ParDo(s, makeRatingsMap, fakePCol, beam.SideInput{Input: filtered_ratings})
	// And match
	combined := beam.ParDo(s, combineMoviesRatings, filtered_movies,
		beam.SideInput{Input: filteredRatingsMap})*

虽然这可能属于“如果它有效,它就不愚蠢!”,我们将在后面的章节中查看在尝试使用Dataflow时导致的许多问题——不过,请注意,这段代码确实可以在DirectRunner上工作。

输入-输出

最后,让我们写我们的数据。我们将首先关注写入磁盘。

计算机编程语言

Python中,一个简单的调用将创建一个txt文件,包含上面的json:

*joined_dicts | 'write' >> beam.io.WriteToText('./movies.txt')*

Go在这方面也非常相似——然而,我们必须将struct“编码”为内联ParDo中的JSON:

*combinedString := beam.ParDo(s, func(v targetMovie) string {
		j, _ := json.Marshal(v)
		return fmt.Sprintf(string(j))
	}, combined)
	// Write
	textio.Write(s, *output, combinedString)*

DirectRunner(本地)

让我们快速运行并讨论一下性能。上次,在我们的Mandelbrot基准测试中,go几乎比Python快了 45 倍。让我们看看Beam是如何支撑的。

DirectRunner上比较性能几乎是毫无意义的,因为这个运行器是为本地调试和开发而设计的,而不是生产使用。

标杆管理

也就是说,我确实运行了一些基准测试,比较了分别使用Side Inputslistsdicts / mapsgoPython,以及使用三个不同测试数据集的CoGroupByKey:100 条记录@ 9KB、100,000 条记录@ 9MB 和 1M 条记录@ 100MB。

先看各种Side Inputs:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# direct runner-locally

这里的速度明显更快,但这是意料之中的,因为它本质上是单线程运行的。使用lists作为辅助输入要慢得多,以至于我已经放弃了在 1M 记录上运行goPythonas list用例。

现在,对于CoGroupByKey:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# direct runner-locally

我们看到一个非常相似的趋势,即go快了几个数量级。印象深刻!

推荐工作

我还用DirectRunner上的title.basics数据对wordcount例子进行了基准测试,以确保我不会因为无意中编写了根本不同的代码而将苹果和橙子进行比较。

我在go中是这样做的:

*go install github.com/apache/beam/sdks/go/examples/wordcount
time wordcount --input ~/workspace/beam-examples/data/title.basics.tsv --output countsgo.txt*

python:

*time python3 -m apache_beam.examples.wordcount --input ~/workspace/beam-examples/data/title.basics.tsv --output wordcountpy.txt # without multiple workers*

产生了:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# a-reference-job

这确实符合我们的观察,即Beamgo仍然比Python快一点。

数据流(谷歌云)

现在,在外部运行程序上运行这个程序只给我们留下了一个选项(因为go不支持其他运行程序),即Google CloudDataflow。我应该补充一下,goDataflow仍然在版本0.5中,还没有得到官方支持。

确保您拥有:

  1. 谷歌云项目
  2. 启用计费(或自由级合格帐户)
  3. 数据流 API 已启用
  4. gcloud sdk已安装,已运行gcloud initgcloud auth login
  5. GOOGLE_APPLICATION_CREDENTIALS被设定
  6. 如果你在谷歌上看到这篇文章,确保克里斯蒂安获得更多免费学分(可选步骤)**

计算机编程语言

对于Python,我们需要使用经过认证的gcloud sdk来运行它:

*pip3 install --upgrade "apache-beam[gcp]"
python3 movie_pipeline.py --input-basics "${BUCKET}/title.basics.tsv" \
    --input-ratings "${BUCKET}/title.ratings.tsv" \
    --output "${BUCKET}/out" \
    --runner dataflow \
    --project "${PROJECT}" \
    --region "${REGION}" \
    --temp_location "${BUCKET}/tmp/" \
    --staging_location "${BUCKET}/binaries/" #\
    #--num_workers 4*

但是,它将在Python 3.8失败,原因是

*Exception: Dataflow only supports Python versions 2 and 3.5+, got: (3, 8)*

所以这里用一个旧版本的Python3.7效果很好。

当作业运行时,它看起来像这样:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# data flow-Google-cloud

一旦完成,就像这样:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# data flow-Google-cloud

Go 数据流

本节将带您了解整个探索和开发过程,包括一些死胡同,以说明我所面临的一些挑战。如果你对解决方案感兴趣,跳到 最后一节

对于go,我们需要使用经过认证的gcloud sdk来构建和运行它。

首先,确保所有的定制structs都在init()中注册,类似于你在Spark中用Scala处理Kryo的操作。

*func init() {
	beam.RegisterType(reflect.TypeOf((*ratingFn)(nil)).Elem())
	beam.RegisterType(reflect.TypeOf((*movieFn)(nil)).Elem())
	beam.RegisterType(reflect.TypeOf((*targetMovie)(nil)).Elem())
}*

构建并运行:

*go build movie_pipeline.go
./movie_pipeline --input-basics "${BUCKET}/title.basics.tsv" \
    --input-ratings "${BUCKET}/title.ratings.tsv" \
    --output "${BUCKET}/out" \
    --runner dataflow \
    --project "${PROJECT}" \
    --region "${REGION}" \
    --temp_location "${BUCKET}/tmp/" \
    --staging_location "${BUCKET}/binaries/" \
    --worker_harness_container_image=apache/beam_go_sdk:latest #\
    #--num_workers 4*

但是当试图使用 **Side Input** **map** 路线时,它不会运行:

*panic: Failed to encode custom coder for type json. Make sure the type was registered before calling beam.Init. For example: beam.RegisterType(reflect.TypeOf((*TypeName)(nil)).Elem())*

注册数据流的类型

这里显而易见的方法是简单地注册类型。然而,在 Beam 中注册类型时,我遇到了一些棘手的问题。

RegisterType 将“外部”类型插入到全局类型注册表中,以绕过序列化并保留完整的方法信息。应该只在 init()中调用它。TODO(wcn):“外部”的规范定义在 v1.proto 中。我们需要这个重要概念的面向用户的副本。

https://godoc . org/github . com/Apache/beam/sdks/go/pkg/beam # register type

我们可以尝试这样注册map:

*func init() {
	// ..
	var m map[string]ratingFn
	beam.RegisterType(reflect.TypeOf(m).Elem())
}*

产量:

*panic: Failed to encode custom coder for type json. Make sure the type was registered before calling beam.Init. For example: beam.RegisterType(reflect.TypeOf((*TypeName)(nil)).Elem())
Full error:
        encoding custom coder map[string]main.ratingFn[json] for type map[string]main.ratingFn
unencodable type map[string]main.ratingFn*

当然,我们可以试着注册一个map:

*beam.RegisterType(reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf((*ratingFn)(nil)).Elem()))*

但这并没有达到预期的效果。为什么?

深入研究go SDK 源代码,我发现了以下函数:

*// TypeKey returns the external key of a given type. Returns false if not a
// candidate for registration.
func TypeKey(t reflect.Type) (string, bool) {
	fmt.Printf("%v => PckPath: %v Name: %v Kind: %v\n", t, t.PkgPath(), t.Name(), t.Kind())
	if t.PkgPath() == "" || t.Name() == "" {
		return "", false // no pre-declared or unnamed types
	}
	return fmt.Sprintf("%v.%v", t.PkgPath(), t.Name()), true
}*

我已经添加了fmt.Printf用于调试。

*main.ratingFn => PckPath: main Name: ratingFn Kind: struct
main.movieFn => PckPath: main Name: movieFn Kind: struct
main.targetMovie => PckPath: main Name: targetMovie Kind: struct
map[string]main.ratingFn => PckPath:  Name:  Kind: map
panic: invalid registration type: map[string]main.ratingFn*

此函数检查注册的类型是否实际上是自定义类型;一个map不是。PckPathName从未设置,因为map不是可以通过reflection注册的自定义类型。

通过吉拉,我找到这个 PR ,把我带到这个单元测试——让我相信go SDK 不允许maps使用定制类型。

我们能不能用一个list代替Side Input来让我们的生活更轻松?我想你知道答案——但是让我们来谈谈调试,因为我们已经在调试了。

性能工具—性能分析Go

如果我们要使用list而不是map,让我们快速使用来描述一下引擎盖下发生了什么。

对于这个测试,我使用了一个有 5,000,000 行的文件,总时钟大约为 500MB。

首先,按照说明为 profiler 添加额外的flags后运行作业:

*go run movie_pipeline.go --input-basics ../data/title.basics.5M.tsv --input-ratings ../data/title.ratings.5M.tsv --output ./test.txt  -cpuprofile ../profiler/cpu.out -memprofile ../profiler/mem.out*

尽管配备了英特尔 i7–9750h、16GB DDR 4 内存和 M.2 NVMe 固态硬盘,这项工作还是在本地花费了 84 分钟。

听听你可怜的笔记本电脑像喷气发动机的声音,并打印结果:

*go tool pprof --svg ./cpu.out > cpu.svg
go tool pprof --svg ./mem.out > mem.svg*

这就是结果:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# perf-tools-profiling-go

我们可以看到combineMovieRatings,低效的列表迭代占用了大部分时间,通过监控htop,我可以告诉你这个任务一直使用一个线程。

现在,看到迭代一个列表效率非常低并不奇怪——但是结合单线程执行(我认为这是由Splittable DoFn问题引起的),正在导致大规模的运行时峰值。

定制编码器之旅

在深入研究了吉拉和 GitHub 的 Pull 请求之后,我偶然发现了自定义编码者和他们对内部类型的用法。

我有一个绝妙的主意,为我们的地图类型注册一个自定义编码器:

*func NewCustomMap() (*coder.CustomCoder, error) {
	return coder.NewCustomCoder("customMap", reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf((*ratingFn)(nil)).Elem()), encCustomMap, decCustomMap)
}

func encCustomMap(v typex.T) []byte {
	dat, _ := json.Marshal(v)
	return dat
}

func decCustomMap(data []byte) typex.T {
	return string(data)
}*

不幸的是,[RegisterCoder](https://github.com/apache/beam/blob/master/sdks/go/pkg/beam/forward.go#L95)看起来是这样的:

*func RegisterCoder(t reflect.Type, encoder, decoder interface{}) {
	runtime.RegisterType(t)
	runtime.RegisterFunction(encoder)
	runtime.RegisterFunction(decoder)
	coder.RegisterCoder(t, encoder, decoder)
}*

因此,也调用RegisterType(t),这将再次无法注册我们的类型或编码器。

地图-> JSON ->地图

虽然我很有可能误解了上面所有的go代码和Jira标签,但我的下一个方法是自己做json解析。

首先,我们没有返回地图,而是返回了[]byte,它返回了一个json字符串:

*func makeRatingsMap(rr int, ratings []ratingFn, emit func([]byte)) {
	m := make(map[string]ratingFn)
	for _, r := range ratings {
		m[r.tconst] = r
	}
	jsonMap, err := json.Marshal(m)
	if err != nil {
		log.Fatal(err)
	}
	emit(jsonMap)
}*

然后,在我们的组合函数中,我们将数据unmarshall到一个map[string]ratingFn中。

*func combineMoviesRatings(movie movieFn, ratings []byte, emit func(targetMovie)) {
	ratingsMap := make(map[string]ratingFn)
	err := json.Unmarshal(ratings, &ratingsMap)
	if err != nil {
		log.Fatal(err)
	}
	r, ok := ratingsMap[movie.tconst]
	if ok {
		emit(targetMovie{
			Id:             movie.tconst,
			TitleType:      movie.titleType,
			PrimaryTitle:   movie.primaryTitle,
			OriginalTitle:  movie.originalTitle,
			IsAdult:        movie.isAdult,
			StartYear:      movie.startYear,
			EndYear:        movie.endYear,
			RuntimeMinutes: movie.runtimeMinutes,
			Genres:         movie.genres,
			AverageRating:  r.averageRating,
			NumVotes:       r.numVotes,
		})
	}
}*

不幸的是,现在每一步都需要执行marshalling,这极大地改变了本地性能数据:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# map-JSON-map

如您所见,json (*decodeState)mapassign导致了作业的巨大开销,至少在DirectRunner上,不是一个可行的替代方案

从头再来

此时,我们必须重新访问CoGroupByKey或其他选项;然而,这些问题确实显示了一些更奇怪的(我可以补充一下,完全没有记录的)问题和 SDK 的不足。

说一个Side Input是一个比CoGroupByKey更好的解决方案是有争议的,但是在我的例子中,我一般不能使用一个map作为一个Side Input。**

最终在数据流上运行

在切换回CoGroupByKey之后,这些变化最终允许我将任务提交给Dataflow。请记住,*go* SDK 还没有得到数据流的官方支持。

这里,我们还可以通过向我们的struct添加元数据来为BigQuery添加另一个输出:

*type targetMovie struct {
	Id             string `bigquery:"Id"`
	TitleType      string `bigquery:"TitleType"`
	PrimaryTitle   string `bigquery:"PrimaryTitle"`
	OriginalTitle  string `bigquery:"OriginalTitle"`
	IsAdult        bool   `bigquery:"IsAdult"`
	StartYear      int64  `bigquery:"StartYear"`
	EndYear        int64  `bigquery:"EndYear"`
	RuntimeMinutes int64  `bigquery:"RuntimeMinutes"`
	Genres         string `bigquery:"Genres"`
	// Ratings
	AverageRating float64 `bigquery:"AverageRating"`
	NumVotes      int64   `bigquery:"NumVotes"`
}*

并写信给 BQ:

*if *bq != "" {
		project := gcpopts.GetProject(ctx)
		bigqueryio.Write(s, project, *bq, combined)
	}*

提交后,我们将看到我们的 DAG:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# finally-running-on-data flow

可拆分 DoFns

免责声明:在需要加载大文件的用例中go SDK 的性能可能不如PythonJava。**

这是因为**go**SDK 不支持* 可拆分 DoFns 。参考见 BEAM-3301 。***

数据流性能

在比较性能时,我们将考察所有 3 种方法:

  1. 使用简单列表作为Side Input
  2. 使用dict作为Side Input (仅限 Python)
  3. 使用CoGroupByKey

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# data flow-performance

实际上,我必须计算 Python 上的list性能,因为作业在大约 2 小时后仍在运行,每秒大约 8-15 个元素。我通过查看CoGroupByKey运行的预期输出和运行时间来估算运行时间,因此实际数字可能会更差!

这符合我们在DirectRunner - go上看到的更快,尽管没有上一个 Mandelbrot 示例中的“常规”goPython代码快。我们无法比较dict / map逻辑,因为它只在DirectRunner上运行。

[0]我不确定为什么 *go* SDK 不产生“记录/秒”指标

绩效总结

上次,在我们的Mandelbrot基准测试中,go几乎比Python快了 45 倍。

这一次,总结是这样的:

https://CHOL linger . com/blog/2020/07/a-data-engineering-perspective-on-go-vs .-python-part-2-data flow/# data flow-performance

所有运行程序和用例的平均性能增益(由于开销和近似运行时间,不包括 100 条记录)是1290.19%——如果我们从list运行时间中取近似值,我们会看到 1351.40% ,尽管这并不真正公平。**

无论如何,这确实令人印象深刻。

结论

我们学到了什么?

动态与静态类型& dictstruct

这部分虽然非常主观,但让我思考了很多。当我第一次开始深入研究第 1 部分时,对我来说很明显Python缺乏静态类型往往是一种诅咒,而不是一种祝福。我不得不花费大量的时间夜以继日地想弄明白为什么一项工作(无论是BeamSparkPandasDask还是其他什么)不能完成我想要的工作,或者更迫切地说,当我从用户那里得到反馈说他们的数据看起来“不正常”时,这通常是由类型问题引起的。

我在第 1 部分中对此进行了阐述——Python 不强制类型化。我经常使用外部库,比如numpy,来编写在处理数据管道时使用外部配置强制输入的类。这可能遵循这样的逻辑“你的字典应该有属性averageTemp ( if 'averageTemp' in dict),那就是一个FLOAT64FLOAT64映射到 numpy 的np.float64;为了确保它确实是FLOAT64,我们将在作业的某一点尝试解析;如果失败,使用except静默捕捉并将其设置为None

另一方面,在go中,我不能舒服地那样做。我被迫遵守结构和类型——我甚至不能设置一个stringnil,尽管我可能已经非常习惯了。

现在,什么更好?嗯,我认为这是风格和设计的角度问题。虽然我发现在 Python 中“生产”级的工作通常很困难,但是由于上面的边缘情况和解决方法(请记住:如果我的数据不符合数据库规定的格式,我就是问题的一方!),可以是挑战。

与此同时,就我个人而言,在go写我的工作比在Python花的时间要长得多——因为我需要更多地思考我要做什么。经常像我对待bashzsh一样对待Python——输入一些东西,希望它有用。引导我去…

编译程序

…编译器。编译器是我已经学会既讨厌又喜欢的东西。由于我没有提到它,让我用几个精选的例子告诉你编译器(或者更确切地说是go工具链)是做什么的:

  1. 不能有未使用的变量
  2. 您不能有未使用的导入
  3. 你不能使用错误的类型

我说的cannot是指:“无论是go run还是go build都不会产生二进制”。

似乎很合理,对吧?嗯——借用我的评论,我发现它既有帮助又乏味。编写go代码就像编写Python代码,而pylint处于高度戒备状态——它不会让你做任何可能让编译器不舒服的事情,同时,确保你所产生的东西将实际工作,而没有副作用。

同时,具体到Dataflow,它显然不会捕捉任何特定于工具的东西——例如,不在init()中注册类只会在您提交作业时成为一个问题。

Python,另一方面,让我写的代码得到 1/10 的分数pyLint,这可能是未来 me 的问题。

可读性

我喜欢PythonBeam的语法。一旦你克服了它看起来有多“奇怪”,用类似伪代码的东西来构建DAG确实是一个很好的方法。

go的方法更加学术化。它遵循标准的语言流程——每个函数返回一个PCollection。这更加直观,但是我发现它失去了Python的“DAG-as-code”逻辑的好处。

但是我会让你自己判断——在 GitHub 上查看Pythongo的完整代码。

可拆分 DoFns 和性能

go中的性能提升是巨大的,老实说,出乎意料。平均而言, 1290.19% 的提高是不可小觑的。

Splittable DoFns另一方面,一旦我们越过相对较小的数据集,开始谈论多个 GB 或 TB,这实际上是一件大事——即使不是交易的破坏者,也使这种练习本质上主要是学术性的。

证明文件

这是我对 SDK 最大的不满之一,抱怨让我感觉很糟糕,因为绝对没有什么能阻止我致力于此(除了时间)。

goBeam文档非常乏味——许多功能和示例只适用于PythonJava。至少可以说,围绕go寻找例子、逻辑和整体架构细节是一项挑战。我主要依靠godocs和阅读相当多的源代码。

上面的报道应该可以证明这一点——我遇到了很多死胡同。

我使用go SDK 的过程看起来有点像这样:

  1. 在 Beam 的网站上吗?(通常没有)
  2. 有带注释的例子吗?我克隆了回购,用grep搜索关键字;没有很好的例子概述,提供的例子通常没有注释
  3. 难道是在godocs里?如果是,他们给出例子或者解释如何使用函数性吗?(参见上面的coder死胡同)
  4. 读取go SDK 源代码

不用说,Google / StackOverflow 的结果几乎为零。

和睦相处

我已经在第 1 部分提到过这一点,但是考虑到go SDK 的实验性质,与Beam特性和Runners的兼容性显然不如在PythonJava中那么好。然而,对于简单的管道和使用Dataflow作为流道,go确实涵盖了基本内容。然而,你确实失去了我在引言中提到的一些好处——更少的跑步者意味着更少的选择。

那又怎样?

go是一种有趣的语言,但是在花了很多时间写这些文章、摆弄代码、文档和环境之后,我现在不推荐使用go作为Beam管道——至少不推荐作为一个总括声明。

当然——它比Python有优势,语言本身清晰,有据可查,而且快速。

然而,一旦你超越了标准用例、Splittable DoFns问题、文档和兼容环境,功能性的缺乏使得使用Python(或Java)作为默认更加合理。虽然更熟悉Beamgo SDK 的人肯定可以解决我的一些问题——就像上面的map问题——但是仍然有很多事情使得在Dataflow管道的生产中使用go至少是有问题的。

然而,对于更简单的管道——我相信,如果你可以接受一个官方尚未支持的运行器(Dataflow),那么性能提升是值得的。

也就是说,我肯定会密切关注Beam SDK 的进展,如果有机会,我希望在未来致力于它——因为go是一门非常有趣的语言,不能忽视。

所有的开发和基准测试都是在 GNU/Linux [PopOS!20.04 在内核 5.4 上]在 2019 System76 Gazelle 笔记本电脑上使用 12 个英特尔 i7–9750h v cores @ 4.5 GHz 和 16GB RAM,使用 0.5 版本的 data flows Go Runner

最初发表@chollinger.com/blog

原载于 2020 年 7 月 6 日https://chollinger.com**

数据工程师对数据民主化的看法

原文:https://towardsdatascience.com/a-data-engineers-perspective-on-data-democratization-a8aed10f4253?source=collection_archive---------19-----------------------

数据工程在数据民主化中的作用

如何塑造数据工程工作,以促进数据访问和扩展数据驱动型公司

照片由小森正明Unsplash 上拍摄

数据民主化是使数据在组织中可访问的过程:消除数据和任何希望在公司中构建产品、分析或决策的人之间的障碍和瓶颈

为什么数据民主化是一个新话题?

在过去(云计算出现之前,Hadoop 出现之前),计算资源非常昂贵。数据工程师需要遵循严格的规则和建模技术,以经济可行的方式生成报告(和其他输出)。

在前云时代,公司有一个或几个集中的数据团队——充当仁慈的数据看门人。对数据、分析或数据驱动产品的任何请求都需要仔细规划、界定范围并交给这些团队。

虽然这种方法是必要的,但如此高水平的控制也带来了一些问题:

  • 数据团队成为瓶颈
  • 组织只能访问高度处理的 数据输出(报告、模型化的表格),领域专家不能探索数据集来寻找机会。
  • 数据的消费者对数据过程几乎没有可见性和理解,这种缺乏透明度导致对数据缺乏信心。
  • 领域专家不能参与数据的建模和转换,因此需求需要彻底定义

您的数据民主化程度如何?

对数据的访问通常是不平等的,这取决于一个人的技术能力和他所在的团队。为了评估给定业务中数据的民主化程度,我想提供以下场景作为起点:

担任 【数据工程师|数据科学家|数据分析师|软件工程师|产品经理|主管等..【移动团队|数据团队|营销团队】等..], 我能有多轻松...

  • ****发现可用的数据集和见解。
  • 浏览 元数据关于数据集的信息(列内容、表的更新速率、表的更新策略、表的健康状况,例如 QC 分数度量、表是如何产生的)。
  • ****探索原始或相当未加工的数据。
  • 从现有数据生成新的数据集。
  • ****创造和分享见解、发现和实验。
  • ****摄取新的数据源。

虽然本评估中强调的一些问题有不同的解决方案,这取决于组织的类型:其规模、资源/预算、数据用户的技术能力,但有一些模式和工具有助于大多数情况

在您的组织中民主化数据的方法

本节的目的是讨论一些非互斥的方法来使组织中的数据民主化。其中一些可能对您的组织有用,一些可能不够,但希望它能帮助您制定自己的解决方案!

Silas k hler 在 Unsplash 上拍摄的照片

团队结构

分散数据团队

在每个团队中嵌入数据工程师可以让团队自给自足。探索数据和创建数据管道的技术障碍可能仍然存在,但每个团队现在都拥有独立所需的技能

这些数据工程师也变得熟悉团队的任务,并获得领域专业知识,这使他们能够更好地理解需求。

数据平台团队

专注于数据基础设施和工具的团队可以帮助减少执行常见任务所需的技术技能。这个工具可以是现成的、开源的或者由团队开发的。

“数据平台化”项目示例:

  • 允许任何人将任意文件放入数据湖并定义模式的 Web 服务。
  • 托管 Airflow 并将其作为服务提供给其他团队。
  • 通过为 EMR 提供模板,抽象出为 Spark 定义集群资源的复杂性(例如,我想要一个“小型”集群,而不是:我想要一个按需配备 1 个 r5 . 2x 大型主节点、5 个 r5 . 4x 大型 Spot 机群的集群……)。

元数据中心

“元数据中心”通常采用内部搜索引擎的形式,对数据集进行分类,并公开潜在数据消费者使用表格所需的信息。至少,它应该回答以下问题:

  • ****表内容是什么(包括列级信息)。
  • ****桌主是谁(团队)。
  • 该表的健康程度(对该表进行评论,或 QC 评分)。
  • ****数据谱系是什么(例如,链接到气流 DAG,或图谱)。
  • 表中的更新策略是什么(如每日快照、每周增量更新)。

元数据中心的实现

许多公司已经实施了元数据中心解决方案:

AirBnb 的数据门户优步的数据手册网飞的 MetacatLyft 的阿蒙森,以及最近谷歌的数据目录。[以及 LinkedIn 的数据中心

(来源)

Amundsen、 DataHubMetacat 是开源的,可以在 GitHub 上获得,利用这些开源工具可以使资源有限的数据工程团队更容易支持元数据中心。

下面的文章更深入地介绍了每个项目的架构:

** [## LinkedIn、优步、Lyft、Airbnb 和网飞如何为机器解决数据管理和发现问题…

当谈到机器学习时,数据无疑是新的石油。管理数据集生命周期的流程是…

towardsdatascience.com](/how-linkedin-uber-lyft-airbnb-and-netflix-are-solving-data-management-and-discovery-for-machine-9b79ee9184bb)

数据质量检查(QC)

当表的创建是分布式的时,确保高数据质量是一个挑战。QC 过程也需要分布,创建表的人应该能够对他们自己的表进行 QC!

Earnest 时,我们有 2 个内部 QC 工具+ 1 个机器学习使能的异常检测工具,它们分发电子邮件和关于桌子健康的信息。然而,我们发现很难将扩展到分析师要求的更多 QC 检查,因为它们需要工程时间。

我们已经开始探索 Great Expectations (GE),我们希望通过让分析师参与到 QC 工作中来扩大规模。

点击此处了解更多关于远大前程的信息:

[## 打倒管道债务/引入更高的期望

TL;DR:管道债务是一种寄生于后端数据系统的技术债务。它会降低生产率,并且…

medium.com](https://medium.com/@expectgreatdata/down-with-pipeline-debt-introducing-great-expectations-862ddc46782a)

数据工程角色

从理论上讲,如果公司里的任何潜在数据消费者都获得了编写 ETL 所需的工具,这将是数据民主化的最大推动者之一。所以,自然,这是我非常感兴趣的事情(你也应该!).

“工程师不应该写 ETL。出于对职业中一切神圣不可侵犯的事物的热爱,这不应该是一个专注或专门的角色。没有什么比编写、维护、修改和支持 ETL 来产生您自己从未使用或消费过的数据更令人神魂颠倒的了。”

(来源)

[## 工程师不应该写 ETL:建立高功能数据科学部门指南

“你的团队和数据科学家之间的关系是什么样的?”毫无疑问,这是我的问题…

multithreaded.stitchfix.com](https://multithreaded.stitchfix.com/blog/2016/03/16/engineers-shouldnt-write-etl/)

数据工程师应该帮助简化编写 ETL 的过程,组织应该培训数据消费者使用数据工程师提供的工具。

一家公司需要在以下两者之间找到一个中间点:

  • 数据工程师创建完全抽象的工具,没有技术知识的数据消费者可以使用,但是需要大量的工程工作来创建。
  • 数据工程师提供的工具需要如此多的技术知识,以至于培训数据消费者使用它们是不可行的

数据构建工具(DBT)是编写转换逻辑工具的一个很好的例子。它将一个结构强加到基于 SQL 的项目中,并使用 Jinja (Python)提供 SQL 的模板。假设数据消费者知道 SQL,培训他们了解 DBT 的细节将允许他们在编写可维护的转换时能够自主

阅读更多关于 DBT 的信息:

[## dbt 到底是什么?

自从 2017 年写这篇文章以来,dbt 已经发生了巨大的变化。最大的变化是发布了一个…

blog.getdbt.com](https://blog.getdbt.com/what--exactly--is-dbt-/)

数据工程师不编写数据管道时的角色

数据工程师提供并支持组成管道的单个组件。例如,在 Earnest 中,我们在 Airflow 上运行大多数容器化的任务,因此作为数据工程师,我们维护多个容器化的 CLI 工具来执行任务,如将 Hive 模式转换为红移模式、在 Livy 上运行 Spark 作业、运行我们的自定义 QC 任务等..

数据工程师还提供工具(例如元数据中心、气流、远大前程、雪花),他们支持、扩展和创建抽象,以提高数据消费者的生产力

一旦数据工程师从制作单个管道中解脱出来,他们就可以研究有益于整个管道的工具。LinkedIn 的 Dr-Elephant,是一个检测 Spark 和 Hadoop 作业上常见优化机会的工具,是这种工具的一个很好的例子。

此外,数据工程师需要通过确保他们的工具可以被数据消费者直接使用来保持数据的可访问性,要求最少或没有工程的干预。

“数据工程师可以专注于管道等幂、数据湖中新资源的集成、数据血统和工具。”

(来源)

[## 数据工程师、数据分析师和数据科学家之间的协作

如何在生产中高效发布?

medium.com](https://medium.com/dailymotion/collaboration-between-data-engineers-data-analysts-and-data-scientists-97c00ab1211f)

最后

数据民主化是关于增加对数据的访问,确保拥有不同技能的不同团队同样有能力提供见解和数据产品。

成功的数据民主化的关键很可能是确保您的不同过程随着数据需求的增加而扩展

你的目标应该是识别并消除瓶颈

这篇文章中的问题和建议解决方案的摘要:

  • 问题:团队没有自主创建数据计划所需的技能| 解决方案:在团队中嵌入数据工程师
  • 问题:团队缺少执行常见数据任务的工具| 解决方案:创建数据平台计划
  • 问题:数据消费者很难找到他们需要的信息,以决定是否可能使用现有的表/数据集| 解决方案:创建一个中心位置来查找这些信息(“元数据中心”)
  • 问题:由于表的创建是分布式的,数据质量正在下降| 解决方案:提供工具,使团队能够拥有他们创建的表的 QC
  • 问题:创建 ETL 管道很慢,因为数据工程资源需求过大| 解决方案:使管道的创建民主化和分布化**

对话式人工智能的数据产品观

原文:https://towardsdatascience.com/a-data-product-view-on-conversational-ai-80284efe5a15?source=collection_archive---------45-----------------------

来源:伊利莎通过吉菲

“喂,你起来了?”

与人类不同,对话式人工智能(AI)目前最常通过聊天机器人部署,它在 100%的时间里都是“运行”的。

Smallbizgenius 很好地总结了聊天机器人的一些惊人统计数据:

  • 聊天机器人可以削减高达 30%的运营成本。
  • 到 2021 年,85%的客户交互将在没有人类代理的情况下处理。
  • 50%的企业计划在聊天机器人上的支出超过在移动应用上的支出。
  • 64%的互联网用户表示,24 小时服务是聊天机器人的最大特点。
  • 37%的人在紧急情况下使用客服机器人获得快速回答。
  • 2018 年,脸书有超过 30 万个聊天机器人。

除了聊天机器人,自动语音应答系统(尽管它们可能仍然很烦人)和虚拟语音助手都利用对话式人工智能来推动人机对话。

对话式人工智能概述

对话式人工智能是一种允许用户向机器提问并获得自动响应的技术。这些机器中最值得注意的是 Alexa、Siri 和 Google Assistant 等虚拟助手。对话人工智能的核心是自然语言处理(NLP)的利用。

作者图片

任何对话式人工智能实现都需要三个主要的 NLP 组件:

  1. 使用自然语言理解理解意图(NLU)
  2. 使用机器学习算法预测响应
  3. 通过自然语言生成的类似人类的反应(NLG)

作为人类,我们理解“你起来了吗?”可以有多种含义或意图。在高层次上,自然语言理解基于使用的单词和短语以及使用它的上下文将人类语言映射到意图。一旦确定了意图,就可以使用不同的机器学习技术来预测最佳响应。该响应很可能存储在数字表示中,同样根据上下文,自然语言生成可用于将响应映射回最合适的人类可理解的语言。

对于基于语音的系统,智能设备必须首先利用自动语音识别(ASR)将语音转换为文本,然后利用 NLP 处理意图并生成响应。在响应被预测并且 NLG 被用于生成类似人类的响应之后,语音合成被用于将响应从文本转换成声音。

人工智能,或者更具体地说,深度学习,是这些技术的核心,有助于人机对话和语音到文本的转换。此外,人工智能允许应用程序纠正错误,从经验中学习,并随着时间的推移进行改进,以便在未来不断使用时提供更好的响应。

作为一个快速题外话,随着深度学习应用的兴起,以及其阴暗面“深度假货”,语音克隆已经成为讨论的热点。基于深度学习技术,可以使用原始语音来训练模型,以生成具有相似语音的新音频。有一天,你甚至可以在你的虚拟助手上使用名人的声音。就目前而言,声音克隆技术的应用仍然取决于人类。

使用对话人工智能的数据产品类型

照片由 Cookie 在 Unsplash 上的 Pom 拍摄

如今,对话人工智能主要以三种方式出现在数据产品中。

  1. 聊天机器人

聊天机器人是对话式人工智能中最常见的应用。它们是您在网站上找到的基本应用程序,用于常见问题解答和引导您浏览网站的各种功能,并充当服务提供商的客户支持。一般过程是传递关于用户的文本查询的响应。然而,聊天机器人是基本形式,不具备深度学习融合的能力,如在未来的交互中学习和改进。

2。智能虚拟助理

智能虚拟助理被认为是更高级的对话式人工智能。属于这一类别的最受欢迎的设备和应用程序是亚马逊的 Alexa、苹果的 Siri、三星的 Bixby 和谷歌助手。这些虚拟助理针对不同形式的服务,如家庭语音助理,包括 Alexa 等。另一方面,Siri、Bixby 属于可以执行各种操作的移动助手类别,即文本到语音、导航、快速回复、天气响应和快速地址搜索等功能。

3。客服助理

这些是针对特定的面向服务的问题而进一步开发的。主要目的是提供高效的客户支持。客户服务助理越来越受欢迎,并且通常在电信提供商或电子和教育组织中使用,用于处理客户请求的平稳运行。这种虚拟助理在打开网站或浏览某个产品时弹出,以帮助购买或以帮助台的形式出现。

拥有对话人工智能产品的样本公司

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

我们非常了解 Alexa、Siri 和 Google Assistant 等热门产品,因为这些公司是该领域的市场领导者。然而,一些创业公司已经成功地实施了这些技术,根据他们的目标市场构建了类似的产品。以下是一些对话式人工智能和/或语音克隆公司的例子:

Kore.ai

Kore.ai 是一家企业虚拟助理平台和解决方案公司,帮助企业自动化并增强与客户、员工和合作伙伴的数字互动。我们提供基于对话式人工智能的无/低代码企业平台,以创建具有对话式和数字用户体验的虚拟助手。Kore.ai 还为银行、保险、人力资源和 IT 支持提供领域培训的预建虚拟助理,并推出了一款名为 Kora 的企业数字助理,作为员工的通用/主/礼宾助理。此外,Kore.ai 还提供名为 SmartAssist.ai 的基于云的呼叫自动化和数字偏转服务。Kore.ai 得到了 Gartner、Forrester、IDC、Everest 等领先分析师的认可,受到了全球财富 2000 强公司和合作伙伴的信任。

Houndify

Houndify 是一个语音人工智能平台,允许任何人给任何有互联网连接的东西添加智能的对话界面。一旦您与 Houndify 集成,您的产品将立即理解各种各样的口头问题和命令。让我们与众不同的是,Houndify 不是技术链中的一环,而是实现任何产品语音功能所需的所有技术的一站式目的地。它包括大规模语音识别,结合强大的自然语言理解。Houndify 集成了许多最受欢迎的内容提供商(包括 Yelp、优步、Accuweather 等),允许语音无缝访问信息。

莉莉 by Vozy

据该公司称,礼来旨在与客户进行更强大、更直观的互动。无论客户寻求自我管理还是个性化对话,礼来都能在整个渠道中提供高效的表现。人工智能、人类理解和语音技术的结合用于帮助与客户建立更有成效的对话,从而与客户建立更牢固的关系。虚拟助理能够为各种交易带来自动化,即从电话调查到复杂任务,从注册到领导资格,Lilly 能够处理各种不同的任务。

MindMeld

MindMeld 对话式人工智能平台是最先进的人工智能平台之一,用于构建生产质量的对话式应用。它是一个基于 Python 的机器学习框架,包含了为此目的所需的所有算法和实用程序。MindMeld 经过数年的发展,构建和部署了数十种可实现的最高级对话体验,并针对构建高级对话助手进行了优化,这些助手展示了对特定用例或领域的深刻理解,同时提供了非常有用和多样化的对话体验。

陆地机器人

Landbot 管理和自动化主要消息渠道上的对话,以帮助您每次更智能地转换。从同一个地方设计、部署和分析您的对话策略,无需一行代码即可传递信息。

使用 Landbot,你可以为 WhatsApp、web 或 Facebook Messenger 设计强大的自动化对话,并将它们与你已经使用的工具集成。一切都是实时发生的,用户的选择决定了整个过程。加入与他们的对话,将他们的信息发送到您的 CRM,或使用他们的数据通过即时消息定制和触发活动。

iSpeech

iSpeech 专注于语音克隆技术,在接近客户寻求产品、应用和服务时,使用更加熟悉和愉快的声音来改善客户关系。这项技术的一些特点如下。

  • 交互式培训和学习。
  • 为导航添加熟悉的声音。
  • 文本到语音应用程序的国际语言内容。
  • 有声读物旁白。
  • 名人声音克隆应用。
  • 提供城市指南。
  • 电影和动画。

回答者

reSpeecher 是另一种声音克隆技术,其简单的想法是克隆人类的语音并交换声音。该技术面向电影制作行业、电视制作人、游戏开发商、广告商、播客和一些类型的内容创作者,这些人的作品更具创造性。从演员配音到交换儿童的声音和表达不同的情感,reSpeecher 通过使用具有深度生成建模技术的经典数字信号处理算法涵盖了所有方面,结果是现场匹配。

构建您自己的聊天机器人

Kelly SikkemaUnsplash 上拍摄的照片

如前所述,聊天机器人是最常见的对话人工智能产品。想尝试开发自己的聊天机器人吗?Chatbots Life 有一篇很棒的文章,里面有代码示例,告诉你如何按照五个简单的步骤开发你的第一个聊天机器人:

  1. 准备依赖项
  2. 导入类
  3. 创建和训练聊天机器人
  4. 与聊天机器人的通信
  5. 聊天机器人的语料库数据训练

有关代码示例,请参考他们的原始文章:https://chatbotslife . com/how-to-create-an-intelligent-chatbot-in-python-c 655 EB 39d 6 b 1

结论

近年来,虚拟助手和聊天机器人的应用飞速发展。随着快节奏的技术发展,深度学习算法大大提升了这些智能系统的能力。各行各业对这种技术的需求越来越大,而且只会继续增长。然而,尽管这种技术具有各种优势,但仍有许多挑战和问题需要解决。此外,如何利用这些技术,如声音克隆,具有巨大的伦理影响。尽管取得了所有的进展,我仍然期待有一天我不再需要在与人工智能机器交谈时反复要求与人类代理说话。

Richard Sheng 是百威英博(Anheuser-Busch InBev)旗下 Z-Tech 的数据科学和分析全球总监,为全球小型企业带来数据驱动的技术解决方案。Richard 拥有 12 年以上为初创公司和财富 500 强公司开发数据产品的经验。

数据科学对话

原文:https://towardsdatascience.com/a-data-science-conversation-9ca398573d2f?source=collection_archive---------9-----------------------

(来源)

如何自学数据科学,通过项目获得数据科学工作,以及我在“走向数据科学”播客中采访的其他经验。

谈话很像写作,因为它迫使你把模糊的想法变成可以理解的、具体的概念。通常,我们认为我们知道一个想法,但我们并没有真正理解这个理论,除非我们能用语言清楚地与他人交流。这种通过交流强行理解的方式是促使我开始写数据科学的部分原因,也是促使我最近在走向数据科学播客上发言的原因。

在这一集里,我们(我和来自 CS Dojo 的主持人 YK)谈论我如何自学数据科学,我如何通过我的项目获得两份数据科学工作,如何让学习数据科学变得愉快,一种自上而下的学习方法,以及我在进入数据科学领域的旅程中得到的其他建议。你可以在 Spotify 上免费听完整集(以及 TDS 播客的所有其他集)。在这一集的下面,我捕捉到了一些关键的要点。

  • 不要指望一所正规大学会教你适用于在行业中实践数据科学的材料。在线课程更新迅速,通常是与公司一起开发的,是学习行业所需数据科学技能的更高效、更具成本效益的方式。
  • 数据科学项目、博客帖子或 Github repos 可以让你获得求职面试的机会。技术和沟通技能为你赢得这份工作(并在你的职业生涯中不断取得成功)。
  • 尝试自上而下的学习方法。在深入研究方法如何工作的细节之前,弄清楚一种技术或算法可以解决什么问题。
  • 专注于建立一个投资组合,由真实世界的数据科学项目组成,以展示您的技术技能。强调掌握技能,而不是获得证书,这在数据科学行业中意义不大。
  • 通过从事您个人感兴趣的项目或解决您或您周围的人遇到的问题,让学习数据科学变得有趣。我不断学习数据科学的动机不仅是因为它能为我赢得一份好工作,还因为学习数据科学本身就是一种享受。
  • 阅读,无论是技术性的还是个人学习,都是减少对世界误解的过程的一部分。你带着一些背景知识(先验)进入一本书,学习新的信息(收集数据),更新你的信念以更接近现实(后验)。试着选择那些能教会你一些东西并且你也觉得有趣的书。

我的第一个播客的总体体验是积极的,作为一个从播客中获益匪浅的人,从受访者的角度来看播客是非常有趣的。向所有致力于数据科学(博客和播客)的人致敬,我期待着为构建数据科学社区做出更多贡献。

一如既往,我欢迎反馈和建设性的批评。你可以在回复中联系,或者在 Twitter 上联系。

从数据科学的角度看群体免疫,我们需要付出什么来阻止病毒?

原文:https://towardsdatascience.com/a-data-science-view-of-herd-immunity-what-do-we-have-to-pay-to-stop-the-virus-3a05fc2ce720?source=collection_archive---------17-----------------------

由凯瑟琳·王创作,版权所有

从数据科学家的角度看新冠肺炎疫情,没有废话,没有指责,没有政治化。让数据告诉你真相。群体免疫是对抗新冠肺炎疫情的好策略吗?

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

ovid-19 像野火一样蔓延。这种微生物粒子正在迅速改变世界。在不到四个月的时间里,它已经从武汉(中国)发展到世界上几乎每个国家。

2020 年 3 月 31 日来自约翰·霍普金斯 CSSE 的数据和仪表板

2020 年 3 月 13 日,英国首相鲍里斯·约翰逊向全国发布了最新的冠状病毒简报。当时他提到,英国将利用科学研究,根据现有的证据建立最佳策略模型,这种松散的控制策略后来被英国首席科学顾问帕特里克·瓦兰斯(Patrick Vallance)指控为群体免疫。

英国将保持正常运作,没有任何严格的控制或封锁,但与此同时,鲍里斯提出,每个英国家庭都应该准备好“提前失去亲人”。

在提出群体免疫建议 14 天后,据报道鲍里斯·约翰逊与新冠肺炎的检测呈阳性。

3 月 27 日,鲍里斯·约翰逊被检测出新冠肺炎阳性

在同样的 14 天里,英国已经确认了近 20,000 例感染病例,超过 1,200 例死亡。(数据来自 2020 年 3 月 30 日,英国政府后来实施了更严格的立法来抑制疫情)

2020 年 3 月 30 日来自https://corona.help/的报告,红线表示 2020 年 3 月 13 日之后群体免疫公告后的病例增长。

那么到底什么是群体免疫呢?这是我们对抗病毒的最好方法吗?

让我们通过数据科学的镜头来讨论今天的话题。

一.简单的病毒传播模型。

病毒传播过程本质上极其复杂。有各种流行病学模型来解释或模拟传染病的传播。但是为了一个基本的理解,我们从一个简单的模型开始。

在这个模型中,我们有两个基本的基础概念(基本再生数和世代间隔)

  • 基本 R 生产编号

基本再生数(R0)定义为完全易感人群中单次(典型)感染产生的继发性病例的预期数量。

这将有助于我们理解传染病在人群中传播的速度。

如果 R0 小于 1,例如 0.5。那么一个人会产生 0.5 个新病例,继发的 0.5 个病例会把病毒传给下一个 0.25 个病例。因此,受感染的人口会越来越少。并且没有任何机会成为全球性流行病而消亡。

如果 R0 接近或等于 1,意味着一个人只会把病毒传给另一个人,然后传给下一个人。我们最终会得到一条感染病例的直线。因此我们称之为地方病(局部传播),例如水痘。

最后一种情况是,当 R0 大于 1 时,例如 2,那么增长将是指数的,从 2 到 4,从 4 到 8,最终达到临界点,它不能被包含在局部区域中。我们现在称之为疫情。

一旦病毒爆发成为疫情,通常有两种结局,患者要么死亡(打破循环),要么形成针对病毒的免疫系统。(停止蔓延)

总之,R0 越大,传染性越强。(有些科学家用 Rt 表示符号)

R0 的更现实的计算

来自斯坦福大学人类科学系

看一看一些众所周知的疾病的 R0。传染性最强的是麻疹,其基本繁殖率为 12-18,其次是白喉,R0 为 6-7。

来自维基百科 —基本复制数

世卫组织最初估计新冠肺炎 R0 为 1.4–2.5(平均值为 1.95),然而最近对 12 项研究的审查估计基本 R0 为 3.28,中值 R0 为 2.79。

  • 生成间隔间隔

什么是世代间隔?这是分隔连续感染的时间段。

简而言之,让我们假设一个新冠肺炎患者可以将疾病传染给另外两个人,那么这种传播需要多长时间?1 天、2 天或一周。这是数学模型中的另一个关键因素,两代人之间的间隔越短,传染性越强。

由凯瑟琳·王创作,版权所有

“A”感染病毒的时间用圆圈表示。过了一会儿,“A”显示了一些轻微的症状,用正方形表示。

圆圈和正方形之间的间隙是潜伏期。(从接触感染到出现第一批症状之间的时间)新冠肺炎的潜伏期变化很大,从 3 天到 20 天不等。我们来加权平均一下,8 天。

需要指出的是,患者“A”在整个潜伏期都具有传染性,因此可以在 8 天内的任何时间感染患者 B。那么 B 还需要 8 天才能出现症状(也标记为方形)。两个方块之间的时间间隔称为世代间隔。对于新冠肺炎来说,大约是 4 天。

就拿“Ro = 2.5”“世代间隔= 4”来说,如果没有干预,新冠肺炎要多久才能蔓延到整个欧洲?

到 2020 年 1 月 24 日,法国确诊首例新冠肺炎患者。不幸的是,当地政府没有给予足够的重视,从而给了病毒爆发的机会,但控制有限。

由凯瑟琳·王创作,版权所有

上述等式是基于几何级数求和推导出来的,它计算了冠状病毒在每一代中的累积预测病例数(R0=2.5)。欧洲的总人口是 7 . 41 亿,这是 23 代人的结果。

大多数人会对这个数字感到震惊,心想这怎么这么小。指数增长的魔力。

而当我们每代取 4 天时,最终结果对应的是 92 天。

从 2020 年 1 月 24 日算起,到 2020 年 4 月 25 日,新冠肺炎将在没有任何非药物干预(NPI)的情况下覆盖欧洲大陆的每个角落。

请记住,这是一个极其简单的模型,真实世界的情况要复杂得多,需要将更多变量的大小纳入动态流行病学模型。

这里有几个可以考虑模型,

  • SI 模型—[将人群分为易感人群 S(t)和传染性人群 I(t)。n 是总人口数量。那么我们有 S(t)+ I(t) = N.]
  • SIR 模型—[除了易感性和传染性,该模型假设从感染中恢复的人变得免疫,并且不能被第二次感染。S(t)+ I(t) +R(t)= N]
  • SIS 模型—[假设康复后的人仍然易患该疾病]
  • 贝叶斯分层模型(London‌帝国理工学院在其最新报告中使用,该模型易于解释和推断)
  • 等等。

二。群体免疫

最后,我们来看看群体免疫。

经济学家总结说,世界各国政府正在使用三种主要方法来对抗新冠肺炎。

  • 群体免疫 - >允许大多数被感染人群发展出免疫系统的情况。
  • 缓解 - >通常被称为“拉平曲线”,通过包括大规模检测、接触者追踪、隔离病例、隔离等手段降低疫情的强度。
  • 镇压 - >关闭城市,关闭公共活动,学校,大学以减少传播。

由 Catherine Wang 创建,数据来源于伦敦帝国理工学院报告,版权所有

如前所述,英国是第一个提出群体免疫方法来控制疾病的国家(如上图所示,英国是最后一个实施封锁的国家)

群体免疫。

这个理论是一个世纪前提出的(和很多数据科学经典模型一样)

由凯瑟琳·王创作,版权所有

  • 首先,让我们假设我们有一群人,他们正在爆发未知病毒
  • 大多数人将从疾病中康复,并建立起针对病毒的免疫系统。这个比率表示为 P,无免疫率为(1-p)
  • 取 R0 率,病毒只能传染给非免疫组。RO(1 名专业人员)
  • 如果我们设法得到[R0(1-P)]< 1, the disease will go away in a short period of time. To satisfy, we need to have P>1–1/R0(简单计算)。
  • 在这个等式中取新冠肺炎 R0 = 2.5,我们将有一个 P > 60 %。这意味着该群体中有 2/3 的人需要被感染并恢复免疫力才能阻止病毒。

来自其他颜色图片

正如你在左边的图像中看到的。

患病病例在开始时呈指数增长,并迅速感染大多数节点。(橙色)

但是一段时间后,越来越多的节点发展出免疫系统(紫色)。

因此,整个群体正在恢复到健康状态。

由凯瑟琳·王创作。版权所有

比方说,如果英国政府继续实施这种方法,6640 万* 60%≈4000 万人将被感染。此外,新冠肺炎目前的病死率(CFR)为 4%,预计中国和意大利为 8%,假设英国拥有世界上最好的医疗保健系统,可以将病死率降至 1%,仍将有约 4000 万* 1% = 40 万人死亡。

同样,领导新冠肺炎非药物研究 [ 论文研究的伦敦帝国学院教授 Neil Ferguson 说,他最初的估计仍然正确,该估计显示冠状病毒将在英国杀死 500,000 人(有限的 NPI,非药物干预),而一个反映封锁措施影响的新模型读数看到该估计缩小到 20,000 或

这个数字是什么意思?

2018 年,英国总死亡人数刚刚超过 50 万。通过群体免疫策略,新冠肺炎将在几个月内夺走几乎同样数量的人的生命。相比之下,第二次世界大战在英国只花费了超过 45 万人的生命,包括士兵,护士,市民等。这意味着新冠肺炎可能会比二战对英国产生更大的影响。

作者凯瑟琳·王,版权所有。

群体免疫方法的支持者认为,如果没有疫苗,这种流行病将在限制取消后的几周内卷土重来。每当这种疾病再次出现时,政府可能需要压制它。这种时断时续的循环必须重复,直到疾病在人群中传播,或者 6 个月后出现疫苗。

批评者辩称,没有科学证据支持新冠肺炎季节性爆发的理论,即使公众能够建立群体免疫力,当病毒变异时也不会有效。

三。群体免疫曾经阻止过流行病吗?

最好的例子是麻疹。

前提:

  • 麻疹的 R0 值为 12-18,极具传染性。
  • 人类是麻疹的唯一宿主。
  • 病死率低,为 0.3%。
  • 没有突变,人类可以对麻疹产生终身免疫。

对于所有这些特征,麻疹似乎是群体免疫的最佳候选者。

那么这种病很快就灭绝了吗?

麻疹的首次出现是在 10 世纪,直到 1980 年我们发现疫苗之前,它每年导致超过 260 万人死亡。

在接种 MMR 疫苗之前,90%(或者一些专家说 99%)的婴儿将会感染麻疹。典型的症状包括皮疹和肺炎,甚至小病例的脑损伤。

即使在我们发现 MMR 之后。麻疹仍然很难预防和控制。

使用前面的等式 P > 1-(1/R0)= 1-(1/15)= 93%。我们需要让 93%的人口建立起一个免疫系统来控制病毒。(世卫组织建议这个数字应该是 95%)。

但是,由于一些关于接种 MMR 疫苗后不良反应的负面评论,实际接种率仅为 86%。

1998 年,英国《柳叶刀》发表了一篇文章,谈到麻疹疫苗可能会导致儿童自闭症[参考文献]

我们已经消灭了天花,世卫组织接下来要消灭的是麻疹、脊髓灰质炎和新冠肺炎。

然而,为了抗击 R0=2.5、CER 为 1%的疫情,人们会愿意为了获得公众群体免疫而被感染吗?

缓解措施花费了太多的生命,抑制措施可能在经济上不可持续,群体免疫?我们能给人们的生活贴上价格标签吗?

由凯瑟琳王创作,版权所有。

当我看到英国首相和首席科学官的演讲时。我既震惊又失望。

长期以来,英国一直是伟大天才和艺术家的诞生地,他们是一些不朽的英雄。他们照亮了整个世界,牛顿、法拉第,是他们把人类带入了第三次工业革命;查尔斯·达尔文,他告诉我们我们的起源;莎士比亚和列侬,他们让我们笑出了眼泪;丘吉尔,他团结全国人民抵抗敌人入侵,捍卫国家主权。

一个最早创造出用于临床试验的疫苗的县,第一个进行流行病学研究的国家,拥有世界顶尖研究人员和最好医学期刊的国家。

有些人用第三次世界大战来比喻新冠肺炎,它将作为比西班牙流感和黑死病更大的事件被人类历史铭记和记录。

来自 quotemaster

我希望有一天,当下一代回顾历史,看到世界团结一致,不分意识形态和宗教,不分贫富,共同抗击病毒。

现在不是安逸舒适的时候,不是互相推诿和指责并把它作为政治武器的时候。

没有人知道我们将在未来几周面临什么,但每个人都知道,新冠肺炎将考验我们的能力,考验我们是否善良、慷慨,是否超越自我和自身利益。我们现在的任务是把最好的我们和我们的所作所为带到一个比我们任何人希望的都更复杂、更困惑的世界。愿我们都带着智慧和优雅前进。

参考

关于我,我是👧🏻现居澳大利亚墨尔本。我学的是计算机科学和应用统计学。我对通用技术充满热情。在咨询公司做 AI 工程师👩🏻‍🔬,帮助一个组织集成人工智能解决方案并利用其创新力量。在LinkedIn上查看更多关于我的内容。

来自吉菲

posted @ 2024-10-15 13:41  绝不原创的飞龙  阅读(187)  评论(0)    收藏  举报