TowardsDataScience-博客中文翻译-2021-五十五-

TowardsDataScience 博客中文翻译 2021(五十五)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

在 Keras 中实现单触发检测器(SSD ):第五部分——预测解码

原文:https://towardsdatascience.com/implementing-single-shot-detector-ssd-in-keras-part-v-predictions-decoding-2305a6e4c7a1?source=collection_archive---------26-----------------------

Keras 中的物体检测

构建 Keras 层以解码由 SSD 网络产生的预测

预测解码过程。由作者编辑。来源:玛西娅·索利戈

一.导言

根据前面的四篇文章,我们能够训练 SSD 网络,并生成能够根据输入图像进行预测的模型权重文件。对于具有 VGG16 主干的 SSD300,网络产生(8732 * num_classes+1)个预测。显然,这是一个巨大的数量,其中大部分需要过滤掉。因此,本文将概述解码和过滤这些初步预测的步骤。此外,本文还提供了创建 Keras 层的代码片段,以达到同样的目的。

这篇文章是一个更大的系列的一部分,叫做在 Keras 中实现单次检测器(SSD)。下面是系列的概要

第一部分:网络结构第二部分:损失函数第三部分:数据准备第四部分:数据扩充 第五部分:预测解码(本文) 部分

二。该算法

为了对 SSD 网络输出的预测进行解码,SSD 的作者设计了一种算法,该算法包括 4 个步骤:包围盒解码、置信阈值、非最大值抑制和 Top-K 滤波。下面详细讨论这些步骤。

下面的代码片段是基于 NumPy 的。下一节将把这些代码片段转换成 Keras,并把它们放到 Keras 的层中。

本文中显示的所有代码都可以在这个回购:https://github.com/Socret360/object-detection-in-keras。GitHub repo 中的许多代码都是从 https://github.com/pierluigiferrari/ssd_keras中获取并修改而来的。

步骤 1:边界框解码

图 1:解码 ssd(带有标准偏差编码的质心)边界框的公式。由作者创建。

从该系列的第三部分中,我们了解到 SSD 的预测是用标准差进行质心编码的。因此,第一步是解码那些编码的预测,使它们回到 cx,cy,width,height 的格式。这可以通过图 1 所示的公式来完成。

步骤 2:置信度阈值(针对每个类别)

在解码包围盒预测之后,我们需要移除置信度得分低于特定阈值的包围盒。这个过滤过程是针对每个类进行的。由于 SSD 网络通过 Softmax 函数(第二部分)产生类别预测,我们可以通过特定类别在 Softmax 输出中的位置来获得其置信度得分。这个置信度分数告诉我们,模型有多确定该特定的对象存在于边界框内。下面的代码片段假设您已经创建了一个形状为(total_default_boxes,1 + 4)的 y_pred numpy 数组,其中 1 是我们感兴趣的类的置信度得分的,4 是 xmin、ymin、xmax、ymax 值。

步骤 3:非最大抑制(针对每个类别)

一旦我们过滤掉了类别置信度较低的包围盒,我们就需要将重叠的包围盒合并在一起。这个过程被称为非最大值抑制(NMS)。通过将重叠的预测合并成一个预测,有助于进一步减少预测的数量。类似于本系列第三部分中的将默认框与基础真值框匹配的过程,为了测量两个边界框预测之间的重叠程度,我们计算它们之间的 IOU。以下代码片段执行了 NMS 版本:

步骤 4: Top-K 选择

即使在对每个类别执行置信度阈值和 NMS 之后,剩余预测的数量仍然可能是巨大的。然而,这些预测中的大多数是不需要的,因为可以出现在图像中的(我们感兴趣的)物体的数量是有限的。因此,我们可以根据它们的置信分值对这些预测进行排序,并选择最高置信分值的 k

第五步:产生最终结果

顶部 K 选择产生 k 预测。这些 k 预测每一个都有一定的置信度得分。为了产生最终结果,我们进一步缩小了预测的范围,只选择那些置信度高于某个阈值的预测。通常,该阈值是通过在模型评估期间选择产生最高贴图的阈值来选择的。我们将在下一篇文章中讨论如何评估这个模型。

三。Keras 的 SSD 预测解码层

在理解了解码 SSD 预测的每一个步骤之后,我们可以将它们放在一个 Keras 的层中。为解码过程创建 Keras 层的好处是,我们可以创建一个内置解码过程的模型文件。当我们想要在不同的平台上部署模型时,这是很有用的。下面是对 SSD 输出的预测进行解码的 Keras 层。

四。结论

本文概述了对 SSD 网络产生的预测进行解码的步骤,并提供了代码片段,说明如何实现 Keras 层来实现这一目的。在下一篇文章中,我们将学习如何评估模型的性能。

喜欢这篇文章并想表达您的支持?关注我或者给我买咖啡

参考

毛,L. (2019)。物体检测中的包围盒编码和解码。检索自https://lei Mao . github . io/blog/Bounding-Box-Encoding-Decoding/

Sambasivarao。K. (2019 年 10 月 1 日)。非最大抑制(NMS) 。走向数据科学。检索自https://towardsdatascience . com/non-maximum-suppression-NMS-93ce 178 e 177 c

在 Keras 中实现单触发探测器(SSD ):第六部分——模型评估

原文:https://towardsdatascience.com/implementing-single-shot-detector-ssd-in-keras-part-vi-model-evaluation-c519852588d1?source=collection_archive---------14-----------------------

Keras 中的物体检测

评估经过训练的 SSD 模型

在 PASCAL VOC 2007 trainval 上训练的 SSD300-VGG16 的图在测试集上评估。图片作者。

一.导言

在本系列的前几部分中,我们深入探讨了 SSD 背后的概念以及这些概念是如何在代码中实现的。通过这个,我们能够构建 SSD 网络,训练它产生一个 Keras 模型,我们可以用它来进行预测。然而,我们仍然需要弄清楚模型的表现有多好。要回答这个问题,我们需要执行一个评估过程。目标检测的不同竞争/挑战有其自己的一套评估指标。由于在之前的文章中,我们在 PASCAL VOC 数据集上训练了我们的 SSD 网络,因此本文重点关注理解 PASCAL VOC 挑战评估过程所需的概念。特别地,我们将详细了解如何计算目标检测模型的平均精度(mAP)

注意:除了 PASCAL VOC challenge 为本次评估提供的 Matlab 代码,您还可以在评估过程中使用其他开源工具(例如review _ object _ detection _ metrics)。此处的目标是让您了解地图指标的使用和计算方式,以便您能够解读评估结果。

本文是一个更大的系列的一部分,称为在 Keras 中实现单次检测器(SSD)。以下是系列的概要

第一部分:网络结构第二部分:损失函数第三部分:数据准备第四部分:数据扩充第五部分:预测解码 第六部分

二。计算地图:一个简单的例子

图 1:类别“dog”的检测结果。图片作者。来源:丹尼尔·林肯埃莉诺拉·卡塔拉诺张轩睿贾卡琳·比厄斯

图 2:类别“cat”的检测结果。图片作者。来源:丹尼尔·林肯埃莉诺拉·卡塔拉诺张轩睿贾卡琳·比厄斯

为了更好地理解评估过程,让我们看一个简单的例子。假设我们为猫和狗这两个类训练了一个 SSD300-VGG16 模型。我们对模型在包含狗和猫的 4 幅图像的测试集上的表现感兴趣,因此我们在测试集中的所有图像中运行了我们训练的模型。基本事实边界框以绿色绘制,而检测(预测边界框)以红色绘制。图 1 显示了一组图像,这些图像显示了“狗”类的所有检测及其基本事实。类似地,图 2 显示了一组图像,这些图像显示了“cat”类的所有检测及其基本事实。我们可以看到总共有 12 个检测(5 猫 7 狗)和 7 个地面真相盒(4 猫 3 狗)。此外,如前几篇文章所述,每个检测都有一个置信度得分。请记住这些数字,因为它将在下面的步骤中对我们有用。

步骤 1-确定“狗”类的 AP

1.1-将每个“狗”检测状态确定为 TP 或 FP

在评估过程中,我们需要完成的第一件事是确定哪些检测是“正确的”,哪些是“不正确的”。这就是混淆矩阵的由来。一个类别(例如狗)的混淆矩阵将该类别的所有检测分为四类:真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)。在对象检测设置中,

  • 真阳性(TP) —真实边界框的正确检测。
  • 误报(FP) —对不存在的对象的错误检测或对现有对象的错误检测。
  • 假阴性(FN) —一个未被检测到的真实边界框。
  • 真底片(TN) —不适用,因为在一幅图像中有无限数量的边界框需要检测。

为了将检测分类为阳性或阴性,使用预测边界框和基本事实框之间的 IOU。PASCAL VOC 挑战将 IOU 阈值设置为 50% (Everingham 等人,2009 年)。如果有两个或更多的检测具有 50%或更高的 IOU,并且具有相同的基本事实,那么具有最高 IOU 的检测被标记为 TP,而所有其他的被标记为 FP。在我们的例子中,IOU 阈值设置为 30%,而不是 50%。浏览所有的检测和地面真理,我们有以上的类“狗”,我们可以构建下表:

表 1:“狗”类的检测及其 TP 和 FP 状态

请注意,检测列表也是按置信度得分降序排列的(从大到小)。这样做是为下一步做准备,在下一步中,我们需要计算所有置信度下的精确-召回对。

1.2 —计算每个置信度级别的精确度/召回率

你可以试试这个互动演示来更直观地了解精确/召回是如何工作的。

图 3:计算精度和召回率的公式。图片作者。

知道每个检测的 TP 和 FP 状态并不能为我们提供关于模型性能的任何有价值的信息。我们需要能够将这些检测的状态合并到一个指标中。为了解决这个问题,可以使用信息检索领域中的精确度和召回率之间的关系。在对象检测的情况下:

  • 精度 —测量模型仅识别相关对象的能力。(帕迪拉等人,2020 年)
  • 回忆——测量一个模型找到所有相关案例(所有真实边界框)的能力(Padilla 等人,2020)

根据上述概念,我们需要确定哪些检测是“相关”的,哪些是“不相关”的。为此,我们使用每个检测附带的置信度阈值(𝜏)。置信度得分≥ 𝜏的检测将被认为是相关的,而置信度得分

表 2:“狗”类的检测,它们的 TP 和 FP 状态,以及在每个置信度阈值的精度/召回值。作者图片

由于 1.1 中的列表是按照置信度得分以降序排序的,因此计算每个置信度得分级别的精确召回对只是遍历列表(自上而下),同时在每次迭代中将要考虑的项目数(从 1 开始)增加 1。因此,在第一次迭代中,要考虑的检测数量将仅为 1(检测 B)。因此,在这个置信度级别的精度是 1.00,而召回率是 0.33。在第二次迭代中,要考虑的检测的数量增加到 2(检测 B 和检测 E ),给我们 1.00 的精确度和 0.66 的召回率。重复这个过程,直到所考虑的项目数等于列表的大小。

1.3-绘制精度-召回(PR)曲线

计算特定置信度级别的精度和召回率,可以告诉我们特定类别的模型在特定置信度阈值下的性能。然而,要了解模型在特定类别上跨所有置信度得分阈值的整体性能,我们可以转向精确召回(PR)曲线。它显示了精确度和召回率之间的权衡。为了构建曲线,我们可以在不同的置信度下绘制精度/召回率对。PR 曲线向右上角倾斜得越多越好,因为它表明模型很可能识别相关对象(高精度),同时还能够找到所有相关对象中的大多数(高召回率)。对于我们的示例,类别“dog”的 PR 曲线如下所示:

图 4:“狗”类的精确召回曲线。作者图片

1.4-确定的 11 点插值精度/召回对和 AP

我们可以通过估计曲线的曲线下面积(AUC)将 PR 曲线的特征总结为一个值。AUC 值越大,该模型在所有阈值范围内对该类别的表现越好。尽管在 PR 曲线中精度和召回率之间存在权衡关系,但精度值可能会随着召回率值的增加而降低,也可能不会。这导致曲线有时具有之字形图案,这对于估计 AUC 来说不是直线的。为了解决这个问题,PASCAL VOC 挑战赛使用了 11 点插值平均精度(AP)方法。这种方法通过对一组 11 个等距召回水平的最大精度值进行平均来总结 PR 曲线(Padilla 等人,2020)。特定召回级别的最大精度值是该召回级别右侧的最大精度值。此外,由于回忆范围从 0 到 1,11 个等间隔的回忆水平是[0,0.1,0.2,… 0.8,0.9,1]。较高的 AP 值(接近 1)意味着该模型对于该特定类别具有较高的召回率和精确度。在我们的示例中,11 点插值精度是下图中的红点:

图 5:具有 11 点插值精度的“dog”类的精度-召回曲线。作者图片

因此,在我们的例子中,类“dog”的 AP 是:(1+1+1+1+1+1+0+0+0+0)/11 = 0.63 = 63%。

步骤 2—确定“cat”类别的 AP

为了确定类别“cat”的 AP,我们简单地再次重复步骤 1,其中我们的检测和基础事实列表是类别“cat”。通过这种方式,我们确定“cat”类的 AP 为 45%。

表 3:类别“cat”的检测,它们的 TP 和 FP 状态,以及在每个置信度阈值的精度/召回值。作者图片

图 6:具有 11 点插值精度的“cat”类的精度-召回曲线。作者图片

步骤 3-计算地图

在估计了每个类的 AP 之后,我们可以通过计算 mAP 来总结模型跨所有类的性能,mAP 的值也在 0 到 1 的范围内。它只是所有班级 AP 的平均值。高 mAP 值(接近 1)意味着模型在所有类别中表现良好。因此,在我们的例子中,模型的映射是(63 + 45) / 2 = 54%。

图 7:类别“猫”和“狗”的精确回忆曲线。作者图片

三。SSD300-VGG16 经过 PASCAL VOC 2007 培训

我用来执行评估过程的代码可以在 evaluate.py 中找到。

在从上述示例中了解了 mAP 计算之后,我将使用这一部分展示我在 PASCAL VOC 2007 trainval 数据集上训练的 SSD300-VGG16 模型的评估结果(批处理大小= 32,epochs = 275 ≈ 42k 迭代),并提供我对如何改进它的一些意见。评估是在同一数据集的测试集上完成的。SSD 模型产生的检测数量设置为 200(与 SSD 纸张相同),而 IOU 阈值设置为 50%,如 PASCAL VOC 挑战中一样。

图 8:在 PASCAL VOC 2007 trainval 上训练的 SSD300-VGG16 的图。图片作者。

图 PASCAL VOC 2007 数据集中 20 个类的精确召回曲线。图片作者。

很明显,一张 38.58%的地图与 SSD 的作者在他们的论文中所展示的(68%的地图)并不相符。以下是我对如何改进结果的看法:

  1. 进一步的训练:由于时间/资源的限制,我在 42k 迭代时停止了我的训练。我相信进一步的训练可以改进模型的映射,因为 1)当我停止训练时,训练损失和验证损失仍然在很好地减少 SSD 的作者在没有随机扩展增强的情况下训练相同的模型配置多达 60k 次迭代,在有随机扩展增强的情况下训练多达 120k 次迭代。
  2. 改进数据扩充和生成器:数据生成器的当前实现没有考虑过小的边界框或退化框(具有 xmax < xmin 和 ymax < ymin 的框)。移除这样的边界框将有助于模型产生更好的边界框预测。此外,可以改进增强管道,以更好地匹配 SSD 的原始 Caffe 实现中所示的管道。此外,在训练过程中使用的增强方法的更有效的实现也可以帮助加速训练过程。

三。结论

这标志着“在 Keras 中实现单次检测器(SSD)”系列的结束。就我个人而言,在这个系列的工作中,我学到了很多关于 SSD 的知识。因此,我希望这一系列文章对您有所帮助,就像它对我一样,帮助您实现了解 SSD 并自己实现它的目标。

喜欢这篇文章,想表示你的支持?关注我或者给我买咖啡

参考

j .戴维斯和 m .戈德里奇(2006 年)。精确回忆与 ROC 曲线的关系。2006 年 ICML 第 23 届国际机器学习会议论文集。https://doi.org/10.1145/1143844.1143874

Everingham,m .,Van Gool,l .,Williams,C. K .,Winn,j .,& Zisserman,A. (2009 年)。Pascal 视觉对象类(VOC)挑战。国际计算机视觉杂志88 (2),303–338。https://doi.org/10.1007/s11263-009-0275-4

Géron,A. (2020)。第 1 章——机器学习的前景。在使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习:构建智能系统的概念、工具和技术(第 3–34 页)中。论文,奥赖利。

谷歌。(未注明)。分类:真与假、正与负。谷歌。https://developers . Google . com/machine-learning/速成课程/分类/真-假-正-负。

谷歌。(未注明)。评估模型|自动视觉物体检测|谷歌云。谷歌。https://cloud . Google . com/vision/automl/object-detection/docs/evaluate。

马纳尔·埃尔·艾杜尼。(未注明)。https://manalelaidouni.github.io/.

r .帕迪拉,Netto,S. L .,& da Silva,E. A. (2020 年)。目标检测算法的性能度量综述。 2020 年系统、信号和图像处理国际会议(IWSSIP) 。【https://doi.org/10.1109/iwssip48289.2020.9145130

Phy,V. (2019 年 12 月 11 日)。分类任务精度不够。中等。https://towardsdatascience . com/accuracy-is-not-sufficient-for-class ification-task-47 FCA 7d 6 a 8 EC。

精确召回。sci kit-学习。(未注明)。https://sci kit-learn . org/stable/auto _ examples/model _ selection/plot _ precision _ recall . html

拉斐尔·帕迪拉。(未注明)。rafaelpadilla/对象检测指标。GitHub。https://github.com/rafaelpadilla/Object-Detection-Metrics.

t .沙阿(2020 年 7 月 10 日)。关于机器学习中的训练、验证和测试集。中等。https://towards data science . com/train-validation-and-test-sets-72 CB 40 CBA 9 e 7。

Solawetz,J. (2020 年 10 月 5 日)。什么是物体检测中的平均精度(mAP)? Roboflow 博客。https://blog.roboflow.com/mean-average-precision/.

在 Keras 中实现单触发探测器(SSD ):第一部分——网络结构

原文:https://towardsdatascience.com/implementing-ssd-in-keras-part-i-network-structure-da3323f11cff?source=collection_archive---------4-----------------------

Keras 中的物体检测

在 Keras 中实施 SSD 网络

一.导言

当我试图在 Keras 中实现 SSD 时,我首先考虑的是 SSD 网络的结构。我只能通过首先理解所涉及的概念来理解 SSD 网络,这些概念包括网格检测器、默认框、特征图、基本网络和卷积预测器。因此,本文将首先讨论这些主要概念,然后再讨论它们如何构成 SSD 网络。本文将以在 Keras 中构建一个版本的 SSD 网络的代码示例结束。

这篇文章是一个更大的系列的一部分,叫做在 Keras 中实现单次检测器(SSD)。以下是系列的概要

第一部分:网络结构(本文) 第二部分:损失函数第三部分:数据准备第四部分:数据扩充第五部分:预测解码

二。概念

栅格探测器

图 1:网格检测器。输入图像被分成网格,以便检测不同位置的物体。来源: Alvan Nee

训练对象检测模型的一种简单方法是将边界框预测器添加到现有的图像分类网络中。当输入图像中只有一个对象时,这种方法效果很好。当输入图像中有两个或更多对象时,模型将无法生成正确的边界框来覆盖这些对象。这是因为没有约束来帮助边界框预测器知道它负责预测哪个对象(Hollemans,2018)。网格检测器有助于对象检测模型检测不同位置的多个对象。这是通过将输入图像分成多个网格单元(例如 3×3、10×10)来完成的,其中每个网格单元具有其自己的简单对象检测模型。因此,使用 3×3 网格的对象检测模型对于每个单独的网格单元将具有 9 个简单的对象检测模型。每个检测器专门检测和分类落入各自网格单元内的对象。

要深入了解为什么网格探测器是有用的,请参考 Matthijs Hollemans 的这篇伟大的文章单阶段物体探测

默认框

图 2:默认框。这些盒子以一定的偏移量(通常是中心)放置。来源: Alvan Nee

再次想象通过仅仅将边界框预测器添加到图像分类模型来构建简单的对象检测模型。边界框预测器将很难预测具有许多不同形状的对象的边界框。虽然网格检测器允许对象检测模型检测输入图像上不同位置的对象,但是默认框允许对象检测模型检测具有不同形状的对象。这些默认框设置了更多的约束,允许边界框预测器仅专注于检测特定形状的对象(Hollemans,2018)。每个默认框的形状由其宽度和高度表示。每个默认框都有一个简单的对象检测模型,专门预测具有特定形状的对象。因此,使用 5 个默认框的对象检测模型将具有 5 个简单的对象检测模型,每个形状一个。我们稍后将研究如何选择这些盒子。

特征地图

图 3:特征地图。CNN 开头的特征映射对应于原始图像上的线条,而结尾的特征映射对应于更具描述性的特征。

CNN 中的每个卷积层都会产生一个相同比例的特征图(Seif,2019)。每个特征地图项目对应于输入图像上的特定位置/斑块(泽勒&弗格斯,2013 年)。CNN 中的卷积层越深,特征图的描述性就越强。在 CNN 的前几层中,这些层产生的特征地图项目对应于原始图像中的边缘、线或角的小块。在 CNN 的更下方,特征地图项目对应于输入图像上更大的补丁。这些大块可能是物体的一部分,甚至是完整的物体(泽勒&弗格斯,2013)。

基于 CNN 网络

基础网络(又名。主干网络)是一种 CNN 网络,用于对象检测中的特征地图提取(Amjoud & Amrouch,2020)。它们大多是为处理图像分类任务而开发的 CNN。这是因为在图像分类任务上表现良好的网络也被证明是对象检测模型的良好特征图提取器。流行的基础网络包括 AlexNet、VGG-16、ResNets、DarkNet-19、GoogLeNet、MobileNet、ShuffleNet 等。当训练对象检测模型(即 SSD)时,这些基本网络通常是预训练的,并且它们的权重在训练过程中保持不变。这些基本网络的预训练权重往往是在大型图像分类数据集(如 ImageNet、COCO 等)上训练的权重。这是因为由这些预先训练的权重产生的特征图已经显示为对象检测模型提供了有用的表示,以检测和分类新的或类似的对象。

卷积预测器

为处理图像分类任务而创建的 CNN 通过完全连接的层产生其最终输出。然而,全连接层的使用提出了两个主要问题。首先,它会导致特征地图所提供的空间信息的丢失(张、李普顿、李& Smola,2020)。第二,如果有大量的特征图,参数的数量会变得非常大。卷积预测器可以解决这些问题。不是将特征图展平成 1D 向量并将其馈入完全连接的层,而是使用小的卷积滤波器(例如大小为 1×1、3×3 等)来产生预测。由于我们没有将宽 x 高 x 通道大小的要素地图转换为完全连接图层的 1D 矢量,因此空间信息不会丢失。此外,如果我们使用完全连接的图层,大小为 38 x 38 x 512 的要素地图将产生 739,328 个参数,而不考虑我们需要预测的类的数量。另一方面,卷积预测器只会产生大小为 38 x 38 x num_classes 的预测。

三。SSD 网络结构

了解了上述概念后,我们可以开始研究这些部分如何组合在一起形成 SSD 网络结构。SSD 网络背后的核心思想是让 CNN 接受图像作为输入,并在不同的比例、形状和位置进行检测。

SSD 的论文中提到了两个版本的 SSD:SSD 300 和 SSD500。下面,我们将只看 SSD300,因为两者之间唯一的主要区别是输入大小。

检测不同比例的物体

图 3:基于 VGG16 网络的 SSD300 的功能图。来源:

为了产生不同尺度的检测,SSD 网络使用来自修改的 VGG16 网络的不同层的特征图。VGG16 网络的变化包括:

  • 通过使用阿特鲁卷积,VGG16 的 fc6 和 fc7 变成卷积层。
  • pool5 的池大小从(2,2)更改为(3,3),步长为(1,1)。
  • VGG16 网络的 conv4_3 增加了 L2 归一化功能。然后,网络通过 SSD 的额外功能层进行扩展。

在 SSD 论文中,基础网络是 VGG16,更具体地说是 VGG16 配置 D(刘,安盖洛夫,尔汉,赛格迪,里德,傅,& Berg,2016)。即使选择的基础网络是 VGG16,SSD 的作者提到也可以使用任何其他基础网络(刘等人,2016)。由于每个特征映射项目对应于原始图像中的不同位置/小块,在网络起点的特征映射允许检测小物体,而在网络终点的特征映射允许检测大物体。用于利用 VGG16 基本网络构建 SSD300 的特性图为:conv4_3、fc7、conv8_2、conv9_2、conv10_2 和 conv11_2。

检测不同位置的物体

图 4:特征图的大小被用来将图像划分成网格。

为了在图像中产生不同位置的检测,SSD 网络使用网格检测器。特征图的前两个维度可以被认为是将输入图像划分成的网格大小。因此,38 x 38 x 512 的特征地图可以被视为将输入图像分成 38 x 38 的网格。conv4_3 的栅极尺寸为 38 x 38,fc7 为 19 x 19,conv8_2 为 10 x 10,conv9_2 为 5 x 5,conv10_2 为 3 x 3,conv11_2 为 1 x 1。这允许 SSD 网络检测每个要素地图图层的不同位置的对象。

检测不同形状的物体

图 5:默认框被添加到每个特征地图中的每个网格单元。

为了在图像中产生不同形状的检测,SSD 网络使用默认框。每个网格单元都被分配了 N 个默认框,其中心位于距网格单元一定偏移量处(通常是中心)。在 SSD 中,每个默认框的宽度和高度可以通过两个值来检索:框的纵横比和框相对于输入图像大小的比例(即,SSD300 为 300,SSD500 为 500,等等)(图 6,等式 1 和 2)。两个值(纵横比、比例)在不同的特征地图之间是不同的。特定要素地图的纵横比列表可通过查看数据集中对象的纵横比来确定,并由浮点值表示。在 SSD 论文中,对于在 Pascal VOC 数据集上训练的具有 VGG16 基础网络的 SSD300,作者说:

“对于 conv4_3、conv10_2 和 conv11_2,我们仅在每个功能图位置关联 4 个默认框,忽略 1/3 和 3 的纵横比。对于所有其他层,我们放置 6 个默认框(1,2,3,2/3,1/3)。”

图 6:计算默认框的宽度、高度和比例的公式。

同样,特定要素地图图层的默认框的比例由图 6 中的公式 3 确定。该公式的作用是根据 CNN 中的顺序输出要素地图的比例值。最低的要素地图的比例为 sₘᵢₙ,较高的图层的比例为 sₘₐₓ,而所有其他图层的比例值在 sₘᵢₙ和 sₘₐₓ.之间保持一定的间隔此外,对于默认框列表中长宽比为 1 的要素地图,作者添加了另一个长宽比为 1 的默认框,s'ₖ的比例由图 6 的等式 4 给出。

产生检测

在 SSD 中,预测的数量固定为( total_default_boxesnum_classes + 1 + 4 + 8),其中 total_default_boxes 是所有要素地图中默认框的总数,而 num_classes 是类的数量。为了对某个特征图进行预测,SSD 应用了两个小的 3 x 3 卷积滤波器:

  • 3×3×(num _ default _ boxes * 4)来产生所有边界框的边界框预测。
  • 3 x 3 x(num _ default _ boxes *(num _ classes+1))为数据集中的所有类加上一个背景类生成类预测。

然后,它使用过滤算法的组合来过滤掉这些预测。我们将在本系列的后续文章中研究如何过滤掉这些检测。

四。代码

本文中显示的所有代码都可以在这个回购:https://github.com/Socret360/object-detection-in-keras。在本文中,我将展示代码的关键片段,并提供包含完整代码的相关文件的链接,而不是直接展示所有代码示例。这将确保文章不会因代码示例而过载。GitHub repo 中的许多代码都是从 https://github.com/pierluigiferrari/ssd_keras中获取并修改而来的。

代码示例将展示如何使用 VGG16 作为基础网络构建 SSD300。以下是我在工作时采取的步骤:

  1. 创建一个配置文件来存储所有参数。
  2. 构建所有必要的自定义 Keras 层,以完成 SSD 网络。其中包括:默认盒子层和 L2 规范化层
  3. 构建固态硬盘网络

创建一个配置文件来存储所有参数

当我开始编写 SSD 网络结构时,我发现将所有必要的/参数分组到一个配置文件中很有帮助。我可以将这个配置文件加载到 python 字典中,然后将该字典传递给函数,而不是将大量参数传递给函数。你可以看一下 ssd300_vgg16.json 作为这个文件的样本。将 json 文件加载到 python 字典中相对容易。您可以使用下面的代码来实现:

构建默认框和 L2 归一化图层

为了构建一个完整的 SSD 网络,我们需要首先构建 2 个自定义 Keras 层,它们是默认的盒子和 L2 归一化层。以下是需要这些层的原因:

默认框层:该层用于构建特征地图的默认框。在训练阶段,不需要该层的值。然而,在推断阶段,来自该层的值对于解码由网络产生的边界框预测将是至关重要的。关于构建该层的完整代码,您可以参考 default_boxes.py

L2 归一化层:该层用于应用带有可学习标度值的 L2 归一化。它将仅用于 conv4_3 要素地图图层。据作者称,

“与其他图层相比,conv4_3 具有不同的特征比例,我们使用 L2 归一化技术将特征图中每个位置的特征范数缩放至 20,并在反向传播过程中学习该比例。”

要构建这一层,你可以遵循 l2_normalization.py 中的代码。

构建固态硬盘网络

由于前面几节已经完成了所有的基础工作,我们终于可以构建 SSD 网络了。实现这一点的思考过程概述如下:

  1. 构建基础网络,加载预训练的权重,并冻结基础网络层,使其权重在训练期间不会改变。
  2. 构建 SSD 的额外功能层。
  3. 确定默认框的所有可能比例。
  4. 对于每个特征图:(1)应用 3×3 卷积预测器来产生形状的分类预测(w,h,num _ default _ boxes (num_classes + 1))和形状的定位预测(w,h,num_default_boxes4),其中 w 和 h 分别是特征图的宽度和高度(2)将那些预测重新整形为用于分类的形状(whnum_default_boxes,num _ classes+1)和用于定位的形状(whnum_default_boxes,4)。(3)为该特定层生成默认框,并将其从(w,h,num_default_boxes,8)的形状重新整形为(whnum_default_boxes,8)的形状
  5. 将来自每个特征映射的分类预测连接在一起,并应用 Softmax 激活以获得最终分类结果。
  6. 将每个特征地图的本地化预测连接在一起
  7. 将每个要素地图图层的所有默认框连接在一起
  8. 将所有分类、本地化和默认框连接在一起,以产生 shape 的最终输出(total _ default _ boxnum_classes + 1 + 4 + 8)

结论

看完这篇长文,希望它能给你提供足够的理解,让你在 Keras 中构造自己的 SSD 网络。在下一篇文章中,我们将探讨用于优化 SSD 网络的损失函数,当然还有如何在 Keras 中对它们进行编码。

喜欢这篇文章并想表达您的支持?关注我或者给我买咖啡

参考

阿姆茹德,文学学士和硕士(2020 年)。用于目标检测的卷积神经网络主干。图像和信号处理(第 282-290 页)。多伊:https://doi.org/10.1007/978-3-319-94211-7

霍利曼斯,M. (2018)。一阶段目标检测。检索自:https://machinethink.net/blog/object-detection/

刘,w,安盖洛夫,d,尔汉,d,塞格迪,c,里德,s,傅,C.Y,&伯格,A. C. (2016)。SSD:单次多盒探测器。https://arxiv.org/abs/1512.02325

Seif,G. (2019)。用于深度学习的可视化过滤器和特征地图。检索自:https://link.medium.com/EkLIlHHOycb

Simonyan 和 a . zisser man(2015 年)。用于大规模图像识别的非常深的卷积网络。2015 年学习代表国际会议(ICLR)。https://arxiv.org/abs/1409.1556

泽勒博士和弗格斯博士(2013 年)。可视化和理解卷积网络。检索自:https://arxiv.org/abs/1311.2901

张,李春钟,李,m,斯莫拉,J. A. (2020)。现代卷积神经网络。深入学习(第 268-270 页)。检索自:https://d2l.ai/d2l-en.pdf

实现从 RGB 到多通道图像的迁移学习

原文:https://towardsdatascience.com/implementing-transfer-learning-from-rgb-to-multi-channel-imagery-f87924679166?source=collection_archive---------10-----------------------

使用 ResNet50 主干+金字塔池的语义分割

介绍

最近,我有幸有机会与 OmdenaWeedBot 合作参加了一个计算机视觉挑战赛,这是一个受影响驱动的初创公司,开发了一种激光除草机械,让农民可以用激光束找到并清除杂草。

照片由贡纳尔·里德斯特伦Unsplash 拍摄

我们探索了作物与杂草分类的图像分割技术,并探索了语义和实例分割方法。在本文中,我们将探索在项目的语义分割部分中实现的两个不同的概念——

多通道输入的迁移学习

什么是迁移学习?

迁移学习是一种机器学习技术,用于在新问题上重用预先训练好的模型。

在迁移学习中,机器利用从不同任务中获得的知识,通过为新的但相关的任务从新样本中提取有用的特征来提高泛化能力。

例如,在训练一个分类器来预测狗的品种时,人们可以使用在训练中获得的知识来区分一般的动物。

优势

使用迁移学习有很多好处。好处是它节省时间,提供更好的性能,并且需要更少的数据。

自然语言处理和计算机视觉问题的深度学习模型通常需要大量数据供模型学习。这可能既耗时又昂贵,并且可能是个人和小组织采用机器学习的巨大障碍。

迁移学习减少了这一障碍,它允许一个人采用一个已经训练好的模型,并将其应用于一个不同但相关的问题。因为模型是预先训练的,这意味着我们不是完全从零开始训练,而是利用模型已经学到的东西。

为挑战提供的是分辨率为 3008x3008 的 775 幅图像。鉴于图片数量较少,迁移学习似乎是一个很好的探索途径。

公开可用的是在公开可用的数据集上训练的开源模型,例如 ResNet、AlexNet、VGG 等等。两个这样的常见数据集是 ImageNetCoco 数据集。这些数据集分别由超过 14M 和 330K 的图像组成。

从 RGB 到多通道

我们的研究提出了三种方法,可以用来将 3 个通道上训练的模型转换为更多的通道。这些方法跨越不同的复杂程度。我们将简要讨论这些方法—

  • 一种方法是简单地扩展权重维度以考虑额外的通道数量,并随机初始化这些值。
  • 第二种方法与第一种类似,只是我们不是用随机初始化的值来填充这些值,而是用其他值的平均值来填充。我们在一篇科学论文中发现了这种方法,该论文描述这种方法比第一种方法更有效。这是我们将在本文中探索的方法。
  • 理论上,最终方法应该提供最佳性能。然而,就训练时间而言,这种方法需要更长的时间。这种方法表明,前面讨论的方法会偏向于前三个通道,因为这是预训练模型最初训练的内容。相反,这种方法提出的是,我们创建第二个并行网络,对剩余的通道执行特征提取,然后将输出与原始预训练模型的输出连接起来。以这种方式,第二模型学习特定于附加通道的表示,并且我们仍然利用按原样使用预先训练的模型。这种方法将在另一篇文章中探讨。

ResNet50 主干和 15 通道图像

为此问题选择的主干模型是 ResNet50。ResNet50 是“残差网络”的缩写,是一个 50 层深度卷积神经网络,利用残差学习。

resnet50 架构

值得一提的是,使用预训练模型的一个特征是,模型期望新任务的输入维度与其预训练的旧任务的输入维度相同。

resnet50 模型在高度和宽度为 224x224 的输入维度上进行预训练,RGB 有 3 个通道。

对于这个分割任务,我们使用了许多特征生成技术,在原始的 3 通道 RGB 图像上增加了额外的 12 通道。有关如何生成额外通道的更多信息,请参阅本文。

当时的挑战是获得预训练的 resnet50 模型,以 480x400 的新图像尺寸作为输入,第三维具有 15 个通道。

我们将做一个代码演练,看看这是如何实现的。首先,我们使用 Keras 下载并导入 resnet50 模型—

在这里,我们指定希望下载 imagenet 的预训练权重。通常,在迁移学习中,我们会排除最后一层,用对新任务更具体的层来代替它。设置“include_top=False”允许我们排除最后一层。如果我们用预先训练好的模型进行推理,而不是实现迁移学习,那么这个应该设置为真。

此时,我们需要将分辨率(高度和宽度)从 224x224 更改为 480x400,并将通道数量从 3 更改为 15。因为更改输入的高度和宽度不会影响权重的尺寸,所以更改起来更简单。

另一方面,改变输入通道的数量确实会影响权重的维数。让我们更详细地研究一下这个问题。

出于比较目的,我们将使用修改后的 uNet 架构,我们可以通过首先改变高度-宽度,然后改变通道数量,来比较 224x224x3 输入和 480x400x15 输入的模型概要。

semantic_segmentation(224, 224, 3).summary()

semantic_segmentation(400, 480, 3).summary()

我们注意到参数的总数保持不变。这证实了输入的高度和宽度不会影响重量尺寸。现在,让我们来看看改变频道的数量—

semantic_segmentation(400, 480, 15).summary()

我们注意到参数的数量从 18,515 增加到 20,243。我们还注意到,这仅仅是因为第一卷积层的参数从 448 增加到 2176,而后续层的参数数量保持不变。

无需在 Keras 中进行尝试,通过回忆卷积层的权重维度由滤波器的高度和宽度、输入深度和输出深度决定,就可以从理论上确认这一点。图像的高度和宽度与此无关。

更改输入维度的第一步涉及复制模型的配置信息。这为我们提供了字典格式的模型组成。我们可以通过更改输入维度来编辑这个字典,并使用编辑过的配置字典创建一个新模型—

我们现在已经创建了一个与 ResNet50 具有相同网络结构的新模型。值得注意的是,这不会自动复制 resnet50 模型的重量,这是这样做的主要目的。

为此,我们需要遍历 resnet50 模型和新创建的模型的层,并复制权重。

然而,我们会遇到一个问题,因为尺寸不匹配。我们之前证实了改变通道的数量会影响权重的维度。为了解决这个问题,我们扩展了权重维度,以更准确地表示通道的增加,并复制权重的平均值。这是按如下方式完成的—

这负责语义分割模型的 ResNet50 主干。

金字塔池模块

在另一篇文章中,我讨论了在探索语义分割时,我们分成多个团队来探索不同的分割模型。在探索 PSPNet 的时候,我们注意到虽然这个模型不完全准确,但是它产生了平滑的分段。

我们推测这可能是模型利用金字塔池模块的结果。为了最终的模型。我们决定将它与 resnet50 一起用作主干。

金字塔池模块

金字塔池通过观察整个要素地图以及不同位置的子区域来工作。池内核覆盖图像的全部、一半、1/4 和 1/8,并被融合为全局先验。然后,这与来自主干的原始特征图相结合。

跟随这个 Colab 笔记本

参考

林 T,梅尔 M,贝隆吉 S,布尔德夫 L,吉尔希克 R,海斯 J,佩罗娜 P,拉玛南 D,兹尼克 L,多尔 P 2014 微软可可:背景中的共同对象【https://arxiv.org/abs/1405.0312

甲等魏东理查德·索彻李——李凯https://ieeexplore.ieee.org/document/5206848李菲菲 2009 ImageNet:一个大规模分层图像数据库

Donges N 2019 什么是迁移学习?探索流行的深度学习方法https://builtin.com/data-science/transfer-learning

何 K,张 X,任 S,孙 J 2015 用于图像识别的深度残差学习https://arxiv.org/pdf/1512.03385.pdf

赵等人 2016 传销资金池模块

在 PyTorch 中实现视觉转换器(ViT)

原文:https://towardsdatascience.com/implementing-visualttransformer-in-pytorch-184f9f16f632?source=collection_archive---------1-----------------------

作者图片

我在LinkedIn,过来打个招呼 👋

嗨,伙计们,新年快乐!今天我们要实现中提出的著名的Vi(sion)T(transformer)一个图像抵得上 16X16 个字:大规模图像识别的变形金刚

代码在这里,本文的互动版可以从这里下载。

ViT 可在我的新计算机视觉库上获得,名为 眼镜

这是一个技术教程,而不是你的普通媒体文章,在那里你可以找到熊猫的五大秘密功能,让你变得富有。

因此,在开始之前,我强烈建议您:

-看看令人惊叹的图文并茂的变形金刚网站
-观看 Yannic Kilcher 关于 ViT的视频-阅读 Einops doc

因此,ViT 使用一个普通的转换器(在中提出的那个,你所需要的就是注意力)来处理图像。但是,怎么做呢?

下图是 ViT 的架构

论文作者(Alexey Dosovitskiy 等人)提供的图片

输入图像被分解成 16x16 的拼合面片(图像未按比例缩放)。然后,使用正常的全连接层嵌入它们,在它们前面添加一个特殊的cls令牌,并对positional encoding求和。产生的张量首先被传递到标准转换器,然后传递到分类头。就是这样。

这篇文章分为以下几个部分:

- Data
- Patches Embeddings
    - CLS Token
    - Position Embedding
- Transformer
    - Attention
    - Residuals
    - MLP
    - TransformerEncoder
- Head
- ViT

我们将采用自底向上的方法一个模块一个模块地实现这个模型。我们可以从导入所有需要的包开始

这里没有什么花哨的,只是 PyTorch +的东西

首先,我们需要一张图片,一只可爱的猫就可以了:)

图片来自维基百科

然后,我们需要对它进行预处理

torch.Size([1, 3, 224, 224])

第一步是将图像分解成多个小块并展平。

论文作者(Alexey Dosovitskiy 等人)提供的图片

引用报纸上的话:

使用 einops 可以很容易地做到这一点。

现在,我们需要使用一个正常的线性层来投影它们

论文作者(Alexey Dosovitskiy 等人)提供的图片

我们可以创建一个PatchEmbedding类来保持代码整洁

torch.Size([1, 196, 768])

注意在检查了原始实现后,我发现作者使用 Conv2d 层而不是线性层来提高性能。这是通过使用等于“补丁大小”的内核大小和步幅来获得的。直观地说,卷积运算单独应用于每个面片。因此,我们必须首先应用 conv 层,然后平坦的结果图像。

CLS 代币

下一步是添加cls token和位置嵌入。cls token只是一个放在每个序列的中的数字

torch.Size([1, 197, 768])

cls_token是一个随机初始化的火炬参数,在forward方法中,它被复制b(批处理)次,并使用torch.cat添加在投影的补丁之前

位置嵌入

到目前为止,这个模型还不知道这些碎片的原始位置。我们需要传递这个空间信息。这可以用不同的方法来完成,在 ViT 中我们让模型学习它。位置嵌入只是一个形状为N_PATCHES + 1 (token), EMBED_SIZE的张量,它被添加到投影的面片上。

论文作者(Alexey Dosovitskiy 等人)提供的图片

torch.Size([1, 197, 768])

我们在.positions字段中添加了位置嵌入,并将其与.forward函数中的面片相加

现在我们需要工具转换器。在 ViT 中,仅使用编码器,其架构如下图所示。

论文作者(Alexey Dosovitskiy 等人)提供的图片

让我们从注意力部分开始

注意力

因此,注意力接受三个输入,著名的查询、键和值,使用查询和值计算注意力矩阵,并使用它来“关注”值。在这种情况下,我们使用的是多头注意力,这意味着计算被分割到具有较小输入大小的n头上。

论文作者(Alexey Dosovitskiy 等人)提供的图片

我们可以使用 PyTorch 的nn.MultiHadAttention或者实现我们自己的。为了完整起见,我将展示它的样子:

所以,一步一步来。我们有 4 个完全连接的层,一个用于查询、键、值,最后一个用于删除。

好的,这个想法(真的去读一下图中的 Transformer )是使用查询和键之间的乘积来知道每个元素相对于其他元素的重要性。然后,我们使用这些信息来调整这些值。

forward方法将来自前一层的查询、键和值作为输入,并使用三个线性层对它们进行投影。因为我们实现了多头注意力,我们必须在多头中重新排列结果。

这是通过使用 einops 的rearrange完成的。

查询、键和值总是相同的,所以为了简单起见,我只有一个输入(x)。

产生的键、查询和值具有BATCH, HEADS, SEQUENCE_LEN, EMBEDDING_SIZE的形状。

为了计算注意力矩阵,我们首先必须执行查询和关键字之间的矩阵乘法,也就是最后一个轴上的总和。这可以使用torch.einsum轻松完成

产生的矢量具有形状BATCH, HEADS, QUERY_LEN, KEY_LEN。那么注意力最终是所得向量的 softmax 除以基于嵌入大小的缩放因子。

最后,我们用注意力来衡量价值

我们得到一个大小为BATCH HEADS VALUES_LEN, EMBEDDING_SIZE的向量。我们将标题连接在一起,最终返回结果。

注意我们可以使用单个矩阵一次性计算queries, keys and values

残差

变压器块有残余连接

论文作者(Alexey Dosovitskiy 等人)提供的图片

我们可以创建一个漂亮的包装器来执行剩余的加法,这在以后会很方便

注意力的输出被传递到一个完全连接的层,该层由两层组成,并以输入的expansion倍进行上采样

论文作者(Alexey Dosovitskiy 等人)提供的图片

简单补充一下。我不知道为什么,但我从未见过有人子类化nn.Sequential来避免编写forward方法。开始做吧,这就是对象编程的工作方式!

最后,我们可以创建变压器编码器模块

论文作者(Alexey Dosovitskiy 等人)提供的图片

ResidualAdd允许我们以优雅的方式定义这个模块

让我们测试一下

torch.Size([1, 197, 768])

您也可以 PyTorch 内置多头注意力,但它需要 3 个输入:查询、键和值。您可以将其子类化并传递相同的输入。

变压器

在 ViT 中,只使用原始变压器的编码器部分。很容易,编码器是TransformerBlockL块。

很简单!

最后一层是正常的全连接,给出了类概率。它首先对整个序列进行基本平均。

论文作者(Alexey Dosovitskiy 等人)提供的图片

我们可以组合PatchEmbeddingTransformerEncoderClassificationHead来创建最终的 ViT 架构。

我们可以使用torchsummary来检查参数的数量

summary(ViT(), (3, 224, 224), device='cpu')

好了

我检查了其他实现的参数,它们是相同的!

在本文中,我们看到了如何以一种良好的、可伸缩的、可定制的方式实现 ViT。我希望它是有用的。

顺便说一下,我正在开发一个名为 眼镜 新计算机视觉库,如果你喜欢的话,可以去看看

保重:)

弗朗西斯科

在一行代码中导入所有 Python 库

原文:https://towardsdatascience.com/import-all-python-libraries-in-one-line-of-code-86e54f6f0108?source=collection_archive---------2-----------------------

为写多个导入语句而烦恼?让 PyForest 为你做这项工作

哈姆扎·蒂格扎Unsplash 上拍摄的照片

Python 是数据科学家用于数据科学项目的主要语言,因为存在数千个开源库,可以简化和执行数据科学家的任务。超过 235,000 个 Python 包可以通过 PyPl 导入。

在数据科学案例研究中,需要导入多个库和框架来执行任务。每次数据科学家或分析师启动新的 jupyter 笔记本或任何其他 IDE 时,他们都需要根据自己的需求导入所有的库。有时,反复编写多行相同的 import 语句会令人沮丧。在这里 pyforest 图书馆来拯救你,它为你工作。

Pyforest 图书馆:

图片来自 PixabayStockSnap

Pyforest 是一个开源的 Python 库,使数据科学家能够感受到自动化导入的幸福。在进行数据科学案例研究时,需要导入多个包或库,如 pandas、matplotlib、seaborn、NumPy、SkLearn 等。每次都导入所有这些库可能会很无聊,并且会破坏您工作的自然流程。此外,您无需搜索确切的导入语句,如**from sklearn.ensemble import RandomForestClassifier**

使用 pyforest one 可以克服这些问题。Pyforest 使您能够使用所有您喜爱的库,而无需导入它们。Pyforest 通过自动导入您想要用于案例研究的库来为您完成这项工作。

一旦在一行中导入了 pyforest 库,现在就可以像平常一样使用所有的 python 库了。您使用的任何库都不会被导入,Pyforest 会自动为您导入。这些库只有在您调用它们或创建它们的对象时才会被导入。如果没有使用或调用某个库,pyforest 不会导入它。

安装:

可以使用以下命令从 Pypl 安装 Pyforest:

**pip install pyforest**

安装完这个库之后,您只需要用一行代码导入它。现在你可以像平常一样使用你最喜欢的库了,不用写导入。在下面的示例 jupyter 笔记本中,我们没有导入 pandas、seaborn 和 matplotlib 库,但是我们可以通过导入 pyforest 库来使用它们。

(作者代码)

pyforest 可以导入所有库吗?

这个包旨在添加所有占导入量 99%以上的库,包括热门库如pandaspdNumPynpmatplotlob.pyplotpltseabornsns等等。除了这些库之外,它还有一些助手模块,如ostqdmre等等。

如果您想查看库列表,请使用**dir(pyforest)**

要将您自己的导入语句添加到 pyforest 库列表中,请在您的主目录**~/.pyforest/user_imports.py** 中的文件中键入您的显式导入语句。

pyforest 的功能:

Pyforest 会在需要时自动调用 python 库。Pyforest 提供了一些函数来了解库的状态:

  • active_imports() :返回已经导入并正在使用的库列表。
  • lazy_imports() :返回 pyforest 库中要导入的所有库的列表。

结论:

在本文中,我们讨论了 pyforest 库,这是一个自动导入库。使用这个库可以减少导入大量必要库的压力,相反,它会自动导入需求。对于经常使用新的 jupyter 笔记本来探索数据科学案例研究的数据科学家来说,这个库很有帮助,现在他们可以不用导入库,从而加快他们的工作流程。

参考资料:

[1] Pyforest 文件(2020 年 4 月 17 日):https://pypi.org/project/pyforest/

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。

https://satyam-kumar.medium.com/membership

感谢您的阅读

损失函数在深度学习和 Python 实现中的重要性

原文:https://towardsdatascience.com/importance-of-loss-functions-in-deep-learning-and-python-implementation-4307bfa92810?source=collection_archive---------19-----------------------

来源:Unsplash 上的 Mikael Kristenson

我们知道在神经网络中,神经元用相应的权重、偏置和它们各自的激活函数工作。权重与输入相乘,然后在进入下一层之前对元素应用激活函数。最后通过输出层得到预测值(yhat)。但是预测总是更接近实际(y),我们称之为误差。因此,我们定义了损失/成本函数来捕捉误差,并试图通过反向传播来优化它。

基于问题陈述,有不同类型的损失函数,我们试图对其进行优化。在本文中,我们将讨论深度学习中的不同损失函数。我们将详细讨论下面的损失函数:

作者图片

1) 回归基础问题中的损失函数

a) 均方误差损失

均方差(MSE)是回归问题中非常常用的损失函数。

如果目标变量的分布是高斯分布,则 MSE 是优选的损失函数。均方误差被定义为预测值和实际值之间的平方差的平均值。成本函数看起来像:

作者图片

结果总是积极的。由于正方形,较大的错误比较小的错误导致更多的错误。换句话说,MSE 是在惩罚犯了更大错误的模型。

优点:

由于该方程本质上是二次的,梯度下降只有一个全局最小值。

二。不存在局部最小值。

三。惩罚犯较大错误的模型。

缺点:如果数据包含异常值,这个损失函数是不稳健的

注意:如果目标列的范围相当分散,在这种情况下,由于 MSE 的性质,预测大值可能会严重影响模型。在这种情况下,代替 MSE,使用均方对数误差(MSLE)损失。这里,首先计算实际值和预测值的自然对数,然后计算均方误差。成本函数看起来像:

作者图片

b) 平均绝对误差损失

平均绝对误差(MAE)也是回归问题中另一个重要的损失函数。它被定义为实际值和预测值之间的绝对差值的平均值。成本函数看起来像:

作者图片

优点:与 MSE 相比,MAE 对异常值更稳健。

缺点:

I .计算成本高,因为与平方误差相比,模数误差很难求解。

二。可能存在局部最小值。

三。即使损失很小,梯度也会变大,因为梯度在过程中保持不变,这不适合学习。为了解决这个问题,可以使用动态学习率。

c) 胡伯损失(平滑平均绝对误差)

Huber 损耗通过结合 MSE 和 MAE 起着重要的作用。如果损失更高,它将二次方程变为线性方程。如果误差小于临界值(ε),则使用 MSE,否则可以使用 MAE。损失函数定义为:

作者图片

Huber 损耗曲线围绕最小值,这降低了梯度,这与 MAE 相比更好,因为 MAE 具有恒定的大梯度。这导致在使用梯度下降的训练结束时丢失最小值。另一方面,与均方误差损失相比,Huber 损失对异常值不太敏感。

请注意,增量的选择很重要,因为它有助于确定异常值标准。

优点:

I .对异常值的处理是明智的。

二。不存在局部最小值。

三。它在 0 也是可微的。

缺点:需要优化额外的超参数(ε),这是一个迭代的过程。

从下图可以清楚地看出,Huber 结合了 MAE 和 MSE,并采用了一种理想的方法来克服 MSE 和 MAE 的缺点。

图片来自作者

2) 基于二值分类问题中的损失函数

a)二元交叉熵

交叉熵是用于分类问题的常用损失函数。它测量两个概率分布之间的差异。如果交叉熵很小,则表明两个分布彼此相似。

在二元分类的情况下,预测概率与目标/实际(0 或 1)进行比较。二元交叉熵计算分数,该分数提供了用于预测类别 1 的实际概率和预测概率之间的负平均差。该分数基于与期望值的距离来惩罚概率。损失函数定义为:

作者图片

b) 铰链损耗

铰链损失是二进制分类问题的另一个损失函数。它主要是为支持向量机(SVM)模型开发的。铰链损耗是根据“最大裕度”分类计算的。

如果目标值在集合(-1,1)中,则使用该损失函数。必须将目标变量修改为集合中的值(-1,1),这意味着如果 y 的值为 0,则需要将其更改为-1。

损失函数定义为:

作者图片

如果实际类别值和预测类别值之间的符号存在差异,则铰链损失函数试图通过分配更多误差来确保正确的符号。

3) 基于多类分类问题中的损失函数

一)多类交叉熵

在多类分类的情况下,将预测概率与目标/实际概率进行比较,其中每个类被分配一个唯一的整数值(0,1,3,…,t),假设数据有 t 个唯一的类。它计算一个分数,该分数提供所有类的实际概率和预测概率之间的负平均差。损失函数定义为:

作者图片

对于分类交叉熵损失函数,需要确保在 n 维向量中,除了对应于类别的条目为 1(一次热编码)之外,所有条目都为 0。

例如,对于 3 类分类问题,其中第一个观察属于第三类,第二个观察属于第一类,第三个观察属于第二类,目标(y)将是: y = [[0,0,1],[1,0,0],[0,1,0]]

b) 稀疏多类交叉熵损失

两者,多类交叉熵和稀疏多类交叉熵具有相同的损失函数,上面提到过。唯一的区别是真实标签(y)的定义方式。对于稀疏分类交叉熵,只需要提供一个整数单元,而不是一个 n 维向量。请注意,整数代表数据的类别。

对于多类交叉熵,实际目标(y)是一热编码的。对于三级分类[[0,0,1],[1,0,0],[0,1,0]]

对于稀疏多类交叉熵,实际目标(y)是整数。对于以上三类分类问题:[3]、[1]、[2]

与多类交叉熵相比的优势:以上示例表明,对于多类交叉熵,目标需要一个包含大量零值的热编码向量,这导致了显著的存储器需求。通过使用稀疏分类交叉熵,可以节省计算时间,降低内存需求,因为它只需要一个单一的整数作为一个类,而不是一个完整的向量。

稀疏多类交叉熵的缺点:多类交叉熵可用于任何一类分类问题。然而,稀疏分类交叉熵只能在每个输入只属于一个类时使用。

例如,如果我们有 3 个类(a,b,c ),假设一个输入属于 b 类和 c 类,那么多类交叉熵的标签可以表示为[0,1,1],但不能表示为稀疏多类。

c)kull back lei bler(KL)发散损失

Kullback Leibler 散度是一种度量,它显示了两个概率分布彼此之间的差异程度。损失函数定义为:

作者图片

KL 散度损失为 0 表明分布是相同的。

KL 散度在某种程度上类似于交叉熵。像多类交叉熵一样,这里也需要对实际目标(y)进行一次性编码。如果使用预测的概率分布来近似期望的目标概率分布,则它计算有多少信息丢失。

KL 散度主要用于变分自动编码器。在这里,自动编码器学习如何将样本编码成潜在的概率分布,该概率分布被进一步馈送到解码器以生成输出。此外,KL 散度可用于多类分类。

使用 Keras 定义不同损失函数的 Python 片段

作者图片

何时使用哪些损失函数

如果目标变量是连续的(回归问题),那么可以使用 MSE、MAE 和 Huber 损失。通常,MSE 是常用的损失函数,但如果数据有异常值,则可以使用 MAE。但是如果使用 MAE,由于模数函数,它的计算量很大,并且还会产生梯度下降的问题。为了克服这些问题,Huber 损失被公认为损失函数,尽管δ的选择是迭代的和重要的。

对于分类问题,如果目标类是二进制的,则使用二进制交叉熵损失。另一方面,对于多类分类,可以使用多类交叉熵损失。与多类交叉熵相比,稀疏多类交叉熵要快得多,因为输入目标考虑的是整数,而不是一次性编码的向量。然而,多类交叉熵更一般化,因为输入目标可以表示为前面提到的多个类。铰链损失主要用于 SVM 模型的二元分类。KL 散度主要用于比简单的多类分类更复杂的函数(如变分自动编码器)。

希望你喜欢这篇文章!!

免责声明:本文所表达的观点是作者以个人身份发表的意见,而非其雇主的意见

参考文献:

https://ml-cheat sheet . readthedocs . io/en/latest/loss _ functions . html #交叉熵

https://keras.io/api/losses/

https://heart beat . fritz . ai/5-regression-loss-functions-all-machine-learners-should-know-4fb 140 e 9 D4 b 0

https://www . machine curve . com/index . PHP/2019/12/21/how-to-use-kull back-lei bler-divergence-KL-divergence-with-keras/

在 Neo4j 中导入 CSV 文件

原文:https://towardsdatascience.com/importing-csv-files-in-neo4j-f3553f1a76cf?source=collection_archive---------1-----------------------

实践教程

为简单或快速而设计的两种不同方法的比较

图由马丁格兰德让,马丁格兰德让,CC BY-SA 3.0<https://creativecommons.org/licenses/by-sa/3.0>,通过维基共享。我没有改变这个形象。

最近,基于图的数据科学和机器学习已经成为各个领域的热门话题,从欺诈检测到知识图生成,社交网络分析等等。 Neo4j 是世界上最受欢迎和使用最广泛的图形数据库之一,为数据科学社区提供了巨大的好处。虽然 Neo4j 在系统中内置了一些训练图,但在某些时候,数据科学家会希望用自己的数据填充它。

Neo4j 接收数据最简单的格式是 CSV。关于如何填充数据库的网络搜索揭示了几种潜在的方法,但是在这篇文章中,我将把重点放在两种最常见和最强大的方法上,您可能希望考虑每一种方法,并浏览一些如何使用它们的示例。

我们将要经历的方法是

  1. LOAD CSV:当图形很小时的简单方法
  2. Neo4j 管理工具:当图形变大时的快速方法

我将在这篇文章中演示这两种方法,并讨论你什么时候会用到它们。

必要的工具

为了开始,我们需要在我们的主机上安装 Neo4j。您可以使用 Neo4j Desktop 浏览下面的数据加载示例,它提供了一个不错的 UI,是学习如何使用数据库的好地方。

然而,为了这篇教程,我选择使用一个简单的 Docker 容器 ,原因如下。

伊恩·泰勒Unsplash 上的照片

首先是,容器是凉的。我总是把事情搞砸,这是一个不会毁掉一切的非常安全的方法。

其次,如今 Docker 容器中发生了如此多的数据科学,以至于可以认为 Neo4j 也在容器中。

最后一点,再现性在数据科学中非常重要,因此使用容器可以实现这一点。

综上所述,您将需要以下内容来运行下面的示例:

  1. Docker(安装说明可以在这里找到)
  2. 一个 Neo4j Docker 镜像(我将使用neo4j:latest,在我写这篇文章的时候是 4.2.2 版本)
  3. CSV 格式的数据集

对于数据集,我将使用流行的权力的游戏图来演示数据加载,该图可从 Andrew Beveridge 维护的知识库中获得。

https://github.com/mathbeveridge/gameofthrones

使用该图作为演练的一个原因是数据被很好地格式化并且相当干净— 您将发现在加载数据时属性非常有用!尽管如此,随着我们继续进行下去,我们将不得不做一些数据清理和重新格式化,但这些都不是太重要。

https://networkofthrones.wordpress.com/

说到清理数据集,请注意在其中一个文件名中存在拼写错误或命名约定不一致。你会看到第五季节点文件被命名为got-s5-node.csv,而不是我们期望的got-s5-nodes.csv的模式。

最后,我假设读者对 Cypher 有些熟悉。如果这不是你目前拥有的技能,我强烈推荐 Neo4j 网站上的在线密码教程(esp。关于创建数据的部分)。特别是,如果你刚刚开始学习密码,我可能会建议你查看一下[LOAD CSV](https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/)[MERGE](https://neo4j.com/docs/cypher-manual/current/clauses/merge/)[MATCH](https://neo4j.com/docs/cypher-manual/current/clauses/match/)[SET](https://neo4j.com/docs/cypher-manual/current/clauses/set/)[PERIODIC COMMIT](https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/#load-csv-importing-large-amounts-of-data)的文档,我们将在下面使用这些文档。

https://neo4j.com/graphacademy/training-intro-40/enrollment/

码头集装箱

在启动 Docker 容器之前,我们需要做一些整理工作,将数据文件放在正确的位置。

首先,我们要确保 CSV 文件在正确的位置。当然,你可以告诉 Docker 在你想放它们的地方找。在我的例子中,我创建了一个目录~/graph_data/gameofthrones/,并将我所有的。csv 在那里。

所有这一切就绪后,从 CLI 运行以下命令:

**docker** run -p 7474:7474 -p 7687:7687 \
  --volume=$HOME/graph_data/data:/data \ 
  --volume=$HOME/graph_data/gameofthrones/data:/var/lib/neo4j/import \
  --env NEO4JLABS_PLUGINS='["apoc", "graph-data-science"]' \
  --env apoc.import.file.enabled=true \
  --env NEO4J_AUTH=**neo4j/1234** \
  neo4j:latest

让我们来分析一下。我们在那里进行了一些端口转发,这将允许您通过 BOLT 协议在端口 7687 连接到localhost:7474.上的网络浏览器中的 Neo4j 浏览器 UI ,您可以通过 Python 或其他编程语言的程序进行访问数据库的连接。

接下来,我们将一系列文件夹转发到容器中,以便在本地机器和容器之间进行读/写。

之后,我们引入一些环境变量。这些几乎都是可选的,但我把它们包括在上面,以防你想使用像 APOC 或 GDS 这样的库。第一个命令告诉容器加载最新版本的 APOC 和 GDS 库作为插件。我们还传递了一个配置设置作为环境变量,告诉 Neo4j 允许 APOC 读取文件。

最后为默认的neo4j用户设置一个密码(非常复杂的1234)。(您可以选择不使用这个位,但是如果您这样做了,那么您必须在每次启动容器时为用户重置密码。)

唷,好了。

最后要注意的是,容器会自动改变文件的所有权和权限,并且只有根用户才能访问。所以如果你打算在sudo之外查看或编辑它们,你可以考虑在容器接触不到它们的地方保存它们的备份。

假设一切顺利,您应该能够将 web 浏览器指向localhost:7474并看到一个正在运行的 UI。所以现在我们可以进入下一步了!

Neo4j 浏览器 UI

加载 CSV:简单的方法

LOAD CSV命令是将数据存入数据库的最简单的方法之一。这是一个 Cypher 命令,通常可以通过 Neo4j UI 运行。然而,它也可以通过 Python 连接器(或者您选择的语言的连接器)传入。对于另一篇博文,我们将通过 Python 保存与数据库的接口。

https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/

如果您有一个“小”图,这种方法非常好。但是什么构成了小呢?一个很好的经验法则是,如果你的节点和边少于 100,000 个,而权力的游戏图确实有,那么这是一个很好的选择。但是,这并不是最快的方法(就像批量加载器一样),所以如果您的图形有点大,您可能需要考虑切换到其他加载方法。

查看我们的节点文件,我们可以看到每个季度都有一个文件。文件本身遵循一种非常简单的格式Id, Label,其中 ID 只是名称的大写,标签是实际的角色名称。

got-s1-nodes.csv

一般来说, 在节点上创建一些唯一性约束 是很好的实践,以确保没有重复。这样做的一个好处是,这将为给定的标签和属性创建一个索引。除了加快对该数据的查询搜索之外,它还将确保节点上的 MERGE 语句(比如我们的 load 语句中使用的那个)明显更快。为此,我们使用:

CREATE CONSTRAINT UniqueCharacterId ON (c:Character) ASSERT c.id IS UNIQUE

请注意,在 Neo4j 中,标签、关系类型和属性键是区分大小写的。所以id不等同于Id.常见错误!

现在,我们可以使用以下方法将节点数据加载到数据库中:

WITH "file:///got-s1-nodes.csv" AS uriLOAD CSV WITH HEADERS FROM uri AS rowMERGE (c:Character {id:row.Id})
SET c.name = row.Label

是的,您确实需要使用 3 个斜线,但是好消息是,如果您将您的数据链接到/var/lib/neo4j/import,这是容器中用于读取文件的默认目录,并且您不需要指定冗长的目录结构,这是非常危险的!

从上面我们可以看到,我们一次加载一行字符,并创建一个名为Character的节点标签和一个名为id的属性,同时创建一个名为name的新属性,我们将该属性设置为等于Label的 CSV 值(不要将该名称与所有节点都有一个Character标签的事实相混淆)。

(请注意,uri实际上也可以替换为 CSV 文件的 web 位置,因此您不必受限于将实际文件保存在本地计算机上。)

注意,我们在这里使用了MERGE命令。我们也可以使用CREATE命令,但是它们的作用有很大的不同。MERGE查看是否已经有节点的实例,然后不创建它。它充当MATCHCREATE。只有在数据库中尚未找到新节点时,才会创建新节点。
如此这般, ***MERGE*** 命令都是等幂的。

接下来是引入边缘文件的时候了。这些格式与Source, Target, Weight, Season类似。

got-s1-edges.csv

要加载这些内容,我们将在浏览器中使用以下命令:

WITH "file:///got-s1-edges.csv" AS uri
LOAD CSV WITH HEADERS FROM uri AS row
MATCH (source:Character {id: row.Source})
MATCH (target:Character {id: row.Target})
MERGE (source)-[:SEASON1 {weight: toInteger(row.Weight)}]-(target)

同样,上面的命令逐行读取文件,并用源角色和目标角色设置边。在这种情况下,这些引用节点文件中Id的值。

我还分配了一个边缘类型:SEASON1(并在随后的几季中改变它),根据源角色和目标角色在那一季中的互动次数来加权边缘。

我还应该简单提一下,这个图是作为无向图加载的(如数据存储库中所指定的)。根据没有箭头显示从源到目标的方向,您可以在最后一行中看出这一点。如果我们希望这是一个有向图,我们可以通过使用箭头来表示,这将改变格式为(source)-[...]->(target)

请注意,Neo4j 将 CSV 中的每个值 视为一个字符串 ,因此我已经通过toInteger将权重转换为整数,如果您希望使用算法,这对于一些计算是必要的。同样,如果你想引入其他季节,你只需冲洗和重复每个边缘文件。

关于以这种方式导入较大的图形,有一点需要注意:Neo4j 是事务性的,对于单个事务中的大量导入,它会占用大量内存。

您可能需要通过定期将数据写入数据库来减少导入的内存开销。为此,在查询前添加以下内容(前缀:auto仅在 Neo4j 浏览器中有效):

:auto USING PERIODIC COMMIT 500

这告诉 Neo4j 每隔 500 行写入数据库。这是一个很好的实践,特别是当你的内存有限的时候。

现在我们有了一个用于未来图形分析的填充数据库!它应该大致看起来像这样(虽然我没有显示每个节点,并修补了毛团以画出某些字符):

Neo4j UI 中所有季节的《权力的游戏》图表

有许多可视化选项,有兴趣的读者可以参考列表中的选项。

https://neo4j.com/developer/tools-graph-visualization/ [## 图形可视化工具-开发人员指南

neo4j.com](https://neo4j.com/developer/tools-graph-visualization/)

neo4j-管理导入

既然我们已经看到了通过简单的 CSV 文件加载数据,我们将使它稍微复杂一些,但是 明显更快

让我们假设你有一个真正“大”的图表。在这种情况下,我说的是节点和边数超过 1000 万的图。上面的方法需要很长时间,主要是因为它是事务性的,而不是离线加载。

如果实时更新数据库,您可能需要使用 LOAD CVS。但是即使在这种情况下,相对于整个数据库的大小,更新通常会以较小的批次进行。

导入工具的数据格式

在填充图表之前,我们必须以一种非常特殊的方式格式化我们的数据。我们还需要确保数据异常干净。对于节点列表,我们将把格式改为(显示前几行):

Id**:ID**,name,**:LABEL**
ADDAM_MARBRAND,Addam,Character
AEGON,Aegon,Character
AERYS,Aerys,Character
ALLISER_THORNE,Allister,Character
ARYA,Arya,Character

对于这个数据集来说,这可能看起来相当简单,但是我们不应该低估它的力量。这是因为它允许一次轻松导入多个节点类型。

例如,也许你有另一种节点类型,它是故事中的一个位置。你所要做的就是改变:LABEL的值来达到这个目的。此外,您可以通过添加一个像propertyName这样的列来添加节点属性,然后在每一行中给出值作为另一个单元格条目。

以类似的方式,我们重新构造边缘文件,如下所示:

:START_ID,:END_ID,weight:int,:TYPE
NED,ROBERT,192,SEASON1
DAENERYS,JORAH,154,SEASON1
JON,SAM,121,SEASON1
LITTLEFINGER,NED,107,SEASON1
NED,VARYS,96,SEASON1

如您所料,我们需要图中的每条边都有一行,即使边的类型发生了变化(例如::SEASON1:SEASON2中两个字符之间的关系)。

这里保持命名约定是非常重要的!例如,您的节点文件必须总是有一个标记为:ID的列,并且可以有一个名为:LABEL的可选列用于节点标签。此外,还可以在这里指定任意数量的节点属性(尽管这个数据集中没有任何节点属性)。您的 edge 文件必须始终有一个:START_ID:END_ID和可选的:TYPE。这些标记后缀的名称不能更改。

(注意,在这种情况下,我已经创建了新的文件和文件名来反映格式的变化。)

重要提示!!!第一季的 edge 列表中有一个关于 Vardis Egen 的错别字(别担心…我也必须查一下那是谁)。节点列表有他的Id拼写为VARDIS_EGEN,但是边列表有几个地方,虽然不是全部,是拼写为VARDIS_EGAN的地方。这个问题最近已经得到了解决,但是如果您有一个旧版本的存储库,您可能需要进行更新。
否则,假设您不关心这个特定字符,最简单的解决方法就是将他作为另一个节点添加到拼写错误的节点列表中,或者解决边列表中的拼写问题(这就是我所做的)。这不会导致前面的方法出现问题,但是导入工具对这类问题更加敏感。

有很多选项可以用于这种格式…太多了,这篇文章无法一一介绍。鼓励有兴趣的读者阅读这种格式的文档,可以在这里找到。

https://neo4j.com/docs/operations-manual/current/tutorial/neo4j-admin-import/

使用导入工具

在摄取大量数据的情况下,Neo4j 提供了一个用于摄取大量数据的命令行工具:neo4j-admin import,可以在容器内部的/var/lib/neo4j/bin/neo4j-admin处找到。

https://neo4j.com/docs/operations-manual/current/tools/neo4j-admin/

这个工具的问题是,当数据库(至少在 Neo4j Community Edition 中)正在运行时,您不能实际使用它来创建图表。数据库必须首先关闭,这给我们的 Docker 容器带来了一点问题。在这种情况下,我们将从数据库尚未运行的新容器开始。

然后,我们将在本地机器的命令行中发出以下命令:

docker run \
  --volume=$HOME/graph_data/data:/data \
  --volume=$HOME/graph_data/gameofthrones/data:/var/lib/neo4j/import \ 
  neo4j:latest bin/neo4j-admin import --nodes import/got-nodes-batch.csv --relationships import/got-edges.batch.csv

这将启动一个容器,该容器立即运行导入工具。我们在容器中指定数据文件所在的目录(确保使用更复杂的 CSV 格式的文件),相对于/var/lib/neo4j。在我们的例子中,本地机器上的数据将连接到import/中。

一旦运行这个命令,就会创建一个数据库,您可以在$HOME/graph_data/data本地访问这个数据库。从这里,我们可以使用本文顶部的命令启动容器。(但是,请注意,如果您想要使用新的数据库和容器重新开始,必须通过 root 删除整个目录。)

既然已经填充了数据库并且启动了容器,我们可以通过localhost:7474进入 UI 并像平常一样与之交互。

总结想法

一旦所有东西都被加载(包括所有 8 个季节),不管你用什么方法,你都应该得到一个如下所示的模式:

看起来像泰里尔家族:)

你会发现你有 407 个节点,4110 个关系。

我介绍了两种将数据从 CSV 文件导入 Neo4j 数据库的常用方法。然而,像任何软件一样,实际上有无数种方法可以达到同样的效果。

我希望这篇文章提供了一种清晰的方式来理解主要的方法,希望这只是你数据科学和机器学习之旅的开始!

如果你正在寻找下一步如何实际做一些与图形数据科学相关的事情,请查看我在如何开始使用 Neo4j 的图形数据科学库的帖子。

特别感谢 Mark Needham 在一些查询调优方面的帮助!

PS:另一个注意事项是,告诉 Neo4j 应该给数据库分配多少内存通常是个好主意。数据科学家想要运行的许多 Neo4j 算法都是内存密集型的。当然,确切的配置取决于您运行的机器。数据库配置是您的独特需求,超出了本文的范围。有兴趣的读者可以在这里查阅文档进行微调。现在我只是继续使用(尽管有限的)内存设置。

在 PostgreSQL 中导入 CSV 并进行回归分析

原文:https://towardsdatascience.com/importing-csvs-in-postgresql-and-conducting-regression-analysis-77ff92f5a283?source=collection_archive---------31-----------------------

如何将数据集导入 PostgreSQL 并进行回归分析

来源:图片由 geraltPixabay 拍摄

作为数据科学家,我们通常更喜欢用 Python 和 r 进行回归分析——当然也包括几乎所有形式的分析。

也就是说,虽然跨小型数据集或在辅助项目中使用 CSV 文件是很常见的,但任何实际大小的真实世界数据几乎总是存储在 SQL 数据库中。

通常,将整个表导入 Python 或 R(取决于其大小)是不切实际的。

假设我们希望对从 SQL 数据库导入的特定数据集进行回归分析。据我们所知,对该数据集进行回归分析的结果可能是虚假的,这意味着提取数据进行更高级的分析浪费了宝贵的时间和资源。

在将数据导入外部程序进行更高级的分析之前,用 SQL 进行一些初步的分析不是更有效吗?

嗯,使用 SQL 进行简单的回归分析确实是可能的。让我们来看看这是如何做到的。

数据集和从 CSV 导入

考虑一个汽车销售数据集(可从我的 GitHub 获得),其中提供了特定车辆的售价,以及诸如购买者的月收入水平、他们的总债务以及每月驾驶的平均英里数等因素。

虽然数据可能已经在 SQL 数据库的一个表中提供了,但我们经常希望从 CSV 文件中导入数据。让我们看看如何做到这一点。

首先要确保 SQL 具有访问 CSV 文件的适当权限。例如,假设您正在使用 LibreOffice Calc(我是一个 Linux 用户),您将需要通过右键单击 CSV 文件,选择 Properties,并切换到 permissions 来确保权限是允许的:

资料来源:图书馆办公室计算

在导入 CSV 文件之前,需要创建数据库和表,并在后者中定义适当的变量。

创建并打开数据库(在本例中称为车辆,输入以下内容:

sudo -u postgres createdb vehicles
sudo -u postgres psql vehicles

现在,名为汽车的表格被创建:

vehicles=# create table cars (
vehicles(# age decimal(8,2),
vehicles(# gender decimal(8,2),
vehicles(# miles decimal(8,2),
vehicles(# debt decimal(8,2),
vehicles(# income decimal(8,2),
vehicles(# sales decimal(8,2)
vehicles(# );

创建表格后,我们现在可以将数据从 CSV 文件导入表格:

vehicles=# copy cars (age, gender, miles, debt, income, sales)
vehicles-# from '/home/Desktop/cars.csv'
vehicles-# DELIMITER ','
vehicles-# CSV HEADER;
COPY 963

对于数据集中的 963 个条目, COPY 963 消息表明这些值被正确传输。

我们现在可以通过从表中选择前 10 个观察值来验证这些值是否存在:

vehicles=# select * from cars limit 10;
  age  | gender | miles |   debt   | income  |  sales   
-------+--------+-------+----------+---------+----------
 28.00 |   0.00 | 23.00 |     0.00 | 4099.00 |   620.00
 26.00 |   0.00 | 27.00 |     0.00 | 2677.00 |  1792.00
 30.00 |   1.00 | 58.00 | 41576.00 | 6215.00 | 27754.00
 26.00 |   1.00 | 25.00 | 43172.00 | 7626.00 | 28256.00
 20.00 |   1.00 | 17.00 |  6979.00 | 8071.00 |  4438.00
 58.00 |   1.00 | 18.00 |     0.00 | 1262.00 |  2102.00
 44.00 |   1.00 | 17.00 |   418.00 | 7017.00 |  8520.00
 39.00 |   1.00 | 28.00 |     0.00 | 3282.00 |   500.00
 44.00 |   0.00 | 24.00 | 48724.00 | 9980.00 | 22997.00
 46.00 |   1.00 | 46.00 | 57827.00 | 8163.00 | 26517.00
(10 rows)

相关系数和回归分析

现在数据已经导入,让我们开始进行一些分析。

特别是,我们想确定哪些变量对每辆车的销售价格有特别的影响。如上所述,在考虑更高级的分析之前,我们希望通过使用 SQL 来确定是否有特别相关的发现。

相关系数

首先,让我们生成以下变量之间的相关系数(衡量两个变量之间关系的强度):

  • 销售和收入
  • 销售和债务
  • 销售额和里程

为了计算销售和收入之间的相关系数,我们将输入以下内容,首先输入 Y(因变量),然后输入 X(自变量):

vehicles=# select corr(sales, income) as correlation from cars;
    correlation    
-------------------
 0.674685436054842
(1 row)

分析得出的相关系数为 0.67,表明这两个变量之间存在正相关。

作为参考,相关系数 1 表示完全正相关,-1 表示完全负相关,而 0 表示不相关。

以下是其他变量的相关系数:

vehicles=# select corr (sales, debt) as correlation from cars;
   correlation    
------------------
 0.83554132018907
(1 row)vehicles=# select corr (sales, miles) as correlation from cars;
    correlation    
-------------------
 0.636675650108261
(1 row)

有趣的是,我们看到销售额和债务在 0.83 处有最强的相关性。这可能向我们表明,持有更多债务的客户更有可能贷款购买汽车。直觉上,这是有道理的——因为更昂贵的汽车通常是通过债务融资,而不是现金购买。

回归分析

为了更深入,让我们进行一个回归分析。

我们将首先根据收入回归销售额:

vehicles=# select round(regr_slope(sales, income)::numeric, 2) as slope, round(regr_intercept(sales, income)::numeric, 2) as y_intercept from cars;
 slope | y_intercept 
-------+-------------
  1.86 |      205.29
(1 row)

分析得出的斜率为 1.86,表明收入每增加 1 美元,销售额就会增加 1.86 美元。在这种情况下,截距有些虚假,但本质上代表了如果客户的收入为 0 美元时的最小销售额。

现在,让我们对其他变量进行回归分析:

vehicles=# select round(regr_slope(sales, debt)::numeric, 2) as slope, round(regr_intercept(sales, debt)::numeric, 2) as y_intercept from cars;
 slope | y_intercept 
-------+-------------
  0.41 |     5892.27
(1 row)vehicles=# select round(regr_slope(sales, miles)::numeric, 2) as slope, round(regr_intercept(sales, miles)::numeric, 2) as y_intercept from cars;
 slope  | y_intercept 
--------+-------------
 427.69 |     -158.93
(1 row)
  • 债务每增加 1 美元,销售额就增加 0.41 美元。截距表明,如果债务为 0 美元,最小销售数将为 5,892.27 美元。
  • 每天平均行驶里程每增加 1 英里,销售价格就会增加 427.69 美元。这与我们的预期相反——我们认为汽车行驶的里程越多,销售价格就越低。然而,在这种情况下,平均每天行驶的英里数才是问题中的变量——而不是总英里数。在这种情况下,从建模的角度来看,这个变量很可能是虚假的,并不能真正告诉我们对销售价格的具体影响。

r 平方

为了更好地衡量这些读数的意义,让我们来看看一个被称为 R 平方的统计数据。

本质上,任何因变量(在这种情况下,销售)都受模型中的自变量和这些变量没有拾取的随机变量的影响。

R-Squared 用于衡量模型在多大程度上解释了因变量的总变化。R 平方值介于 0 和 1 之间,0 表示模型考虑了因变量的变化,而 1 表示模型考虑了因变量的所有变化。

以下是对相关变量的 R 平方计算:

vehicles=# select round(regr_r2(sales, income)::numeric, 3) as r_squared from cars;
 r_squared 
-----------
     0.455
(1 row)vehicles=# select round(regr_r2(sales, debt)::numeric, 3) as r_squared from cars;
 r_squared 
-----------
     0.698
(1 row)vehicles=# select round(regr_r2(sales, miles)::numeric, 3) as r_squared from cars;
 r_squared 
-----------
     0.405
(1 row)

我们可以看到,销售额对债务的回归具有最高的 R 平方,接近 70%,这意味着债务变量几乎占销售额总变化的 70%。

结论

这是对 PostgreSQL 中回归分析使用的介绍。您还看到了如何导入 CSV 格式的数据集,并将其传输到 SQL 表中。

我推荐阅读 Anthony DeBarros 的《实用 SQL 》,更深入地了解如何使用 SQL 实现回归分析和其他分析工具。

如前所述,在对特定数据集进行“快速而粗略”的分析时,SQL 非常有用——这可以极大地帮助确定是否需要使用外部程序(如 Python 或 r)进行进一步的分析。

虽然更深入的回归分析(如 t-test 计算)可能难以在 SQL 中实现(通常不推荐),但在数据库表本身中进行初步分析总是有其优势的。

非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。你可以在michael-grogan.com找到更多我的内容。

参考

免责声明:本文是在“原样”的基础上编写的,没有任何担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释是作者的发现和解释,不被本文中提到的任何第三方认可或隶属于任何第三方。作者与本文提及的任何第三方无任何关系。

用 Python 将熊猫数据帧导入数据库

原文:https://towardsdatascience.com/importing-pandas-dataframe-to-database-in-python-7212de1028c9?source=collection_archive---------24-----------------------

了解如何将你的数据从熊猫数据框架上传到云中的数据库。

作者创造的形象

在本文中,我们将讨论如何将您的数据从 pandas 数据框架上传到云中的数据库。这是一篇文章的续篇— 数据分析项目理念将让你得到这份工作 ,在这篇文章中,我们讨论了构建你需要的唯一一个数据科学项目,并且我介绍了你可以为数据科学项目构建的基础设施。第一部分是从一个 API 收集数据作为数据源。在我们之前的博客— 使用 Python APIs 进行数据科学项目 中,我已经向您介绍了如何做到这一点。既然您已经将来自 API 的数据保存在 pandas dataframe 中,我们需要将它放入数据库表中。

Github 链接:https://github.com/Strata-Scratch/api-youtube

作者通过 YouTube 发布的视频

为什么我们需要将熊猫数据帧导入数据库?

将数据保存到数据库的最大原因是将所有数据保存在另一个服务器(数据库)上,而不是存储在本地计算机上,这样会占用内存。您可以存储数据的清理版本,而不必在每次构建分析时都进行清理。

另一个原因是,大多数数据科学公司将他们的数据存储在数据库中,因此学习如何从数据库中提取和推送数据非常重要。

让我们看一下如何将数据从 pandas 数据帧加载到云中的数据库表,并执行第二次操作,用新数据更新同一个表。我们将以一种可伸缩的方式做到这一点,这意味着我们的代码可以处理潜在的数百万行,而不会破坏 pandas 或耗尽内存。

设置

在云上创建数据库(AWS)

我们将在 AWS 上创建一个 Postgres 数据库,并使用 psycopg2 库连接到 python 上的数据库。有很多关于如何做到这一点的教程,所以我不会详细介绍如何启动数据库。

我正在 AWS 上创建一个 RDS 实例,如您所见,我的数据库名为“database-yt”

截图自 AWS

我们所有的连接信息也可以在 AWS 上找到。

截图来自 AWS

保存所有信息,以便在 python 中连接到数据库时使用。

创建一个 Google Colab 或 Jupyter 笔记本

就像我们的其他项目一样,我们可以使用 Google Colabs 或 Jupyter 笔记本。我要用 Google Colabs。

要做的第一件事是安装 python-postgres 包装器 psycopg2,以便更容易通过 python 连接到您的数据库。我也在导入必要的库来完成我的工作,比如熊猫。

!pip install psycopg2
import psycopg2 as ps
import pandas as pd

连接到数据库

输入您创建的数据库的凭据。

host_name = 'database-XXXX.us-west-1.rds.amazonaws.com'
dbname = 'XXXX'
port = '5432'
username = 'XXXX'
password = 'XXXXX'

现在,让我们创建一个函数,允许您将凭证传递给数据库并建立连接。

def connect_to_db(host_name, dbname, port, username, password):
   try:
       conn = ps.connect(host=host_name, database=dbname, user=username, password=password, port=port)

   except ps.OperationalError as e:
       raise e
   else:
       print('Connected!')
       return conn

上传/导入数据

此时,您可以导入您的数据并将其保存为 pandas dataframe。如果你知道我在做什么,我通过连接到 Youtube API 并从那里提取数据来提取我的数据。参考我们之前的文章— 使用 Python APIs 进行数据科学项目

在这里,我们将保持整洁,使用两个独立的笔记本将我们的数据从一个笔记本转移到另一个,我们将它保存为 csv 并上传。但实际上,如果我们从 API 中收集数据,并将其保存为熊猫数据帧,我们将使用相同的笔记本将其上传到我们的数据库。

youtube_videos = pd.read_csv('youtube_videos.csv', index_col=0)
youtube_videos.head()

创建数据库表

SQL 创建表命令

让我们创建表格。很明显,我们将使用 SQL 来创建表,但是我们将在 CREATE TABLE 命令中添加一个变量 %s ,这样我们就可以在不使用实际 SQL 命令的情况下更改表名。这使得实验和测试更容易,减少了人为错误。

我们有一个 CREATE TABLE IF NOT EXISTS,然后是参数 %s ,其中 %s 是我的表名的占位符。因为我们已经知道了表模式,因为我们已经有了数据的 pandas 数据框架,所以我们将命名列并添加数据类型。这是一个标准的创建表 SQL 查询。然后,我们将所有内容保存在名为 create_table_command 的变量中。

create_table_command = ("""CREATE TABLE IF NOT EXISTS %s (
                   video_id VARCHAR(255) PRIMARY KEY,
                   video_title TEXT NOT NULL,
                   upload_date DATE NOT NULL DEFAULT CURRENT_DATE,
                   view_count INTEGER NOT NULL,
                   like_count INTEGER NOT NULL,
                   dislike_count INTEGER NOT NULL,
                   comment_count INTEGER NOT NULL
           )""")

就像创建到数据库的连接一样,我们将把一切都包装在一个名为 create_table 的函数中。

def create_table(curr, tablename):
   create_table_command = ("""CREATE TABLE IF NOT EXISTS %s (
                   video_id VARCHAR(255) PRIMARY KEY,
                   video_title TEXT NOT NULL,
                   upload_date DATE NOT NULL DEFAULT CURRENT_DATE,
                   view_count INTEGER NOT NULL,
                   like_count INTEGER NOT NULL,
                   dislike_count INTEGER NOT NULL,
                   comment_count INTEGER NOT NULL
           )""")

   curr.execute(create_table_command, [ps.extensions.AsIs(tablename)])

将数据库连接传递给函数

我们将把名为 curr 的 Postgres 连接 cursor() 和表名传递给 create_table 函数。游标是一个类实例,允许您运行 SQL 命令并获取结果。它基本上允许 python 代码在数据库会话中执行 sql 命令。

conn = connect_to_db(host_name, dbname, port, username, password)
curr = conn.cursor()

执行 SQL 命令

然后,我们将对我们的 cursor() 类使用 execute() 方法来执行 SQL 命令。

curr.execute(create_table_command, [ps.extensions.AsIs(tablename)])

execute()方法的第一部分需要保存在 create_table_command 中的 SQL CREATE TABLE 命令,因为有一个参数 %s 表示表名,所以我们还需要将表名传递到命令中。我们可以通过使用[PS . extensions . asis(tablename)]在变量 tablename 中传递表名来做到这一点。

AsIs() 是一个函数,用来去掉表名两边的引号。因为如果我们传递一个没有这个函数的表名,它会像“video”一样在 SQL 查询中加引号,所以我们使用 AsIs()告诉 postgre 你应该把它作为没有引号的名字。

现在,我们可以连接到数据库,命名我们的表,并使用这三行代码在云中的数据库上创建表。

curr = conn.cursor()
TABLE_NAME = "videos"
create_table(curr,TABLE_NAME)

将数据加载到数据库表中

数据在我们的熊猫数据框里。有两种方法可以将所有数据从 dataframe 传递到数据库。您选择的方法取决于数据的性质和大小。

  1. 行一旦进入数据库,就不会被更新。
    ~在这种情况下,您只需要在数据库表中添加新数据作为新行。
  2. 当列中有新数据时,行被更新
    ~在这种情况下,不仅需要添加新数据作为新行,还需要更新现有行中的值。例如,因为我正在处理来自我的频道的 Youtube 视频数据,所以我有一个我的频道上的视频列表,它们的观看计数和评论计数。这些数量会随着时间的推移而变化,所以当我第二次从 Youtube API 中提取数据时,我需要更新现有视频的数量,并向数据库表中添加新的视频。这是一个复杂得多的过程。

可扩展性案例

根据您从 API 或数据库获得的数据量,您可能不希望一次更新所有的表。这可能会导致大量的插入和更新,从而根据数据量带来性能和内存问题。一种解决方法是一次更新一行。

在我们的例子中,我们没有很多数据,但是我们需要检查数据库表中是否存在一个视频,并用新的计数更新它。我们还需要插入从 Youtube API 中提取的新视频。所有这些数据都保存在我们的本地计算机(或谷歌的 Colab 服务器)上,直到它进入我们的数据库,所以随着我的视频列表的增长,更新所需的内存量也在增长。这就是为什么逐行更新是最好的。

更新数据库表中的现有视频

检查视频是否存在

我们先检查一下视频是否存在。这将有助于我们第一次将所有视频加载到数据库中,以及以后的所有时间。

但是,如果视频存在,我们希望执行更新;如果视频不存在于数据库表中,我们希望将新视频追加到数据库表中。所以一些伪代码可能是这样的。

for i, row in df.iterrows():
       if check_if_video_exists(): # If video already exists then we will update 
update_row()
       else: # The video doesn't exists so we will append to the db table append(row)

基本上,这段代码说的是使用 iterrows() 一次遍历数据帧的一行,并检查视频是否存在。如果是,则对该行进行更新。如果没有,则将视频信息附加到数据库表中。 DataFrame.iterrows 是一个生成索引和行(作为一个序列)的生成器。

这也适用于初始加载,因为视频将不存在,因为表中没有视频。

我们先写 check_if_video_exists()函数

为了检查数据库中是否存在视频,我们运行一个简单的 SQL 命令。我们只需要给命令提供来自熊猫数据帧的视频 id。

query = ("""SELECT video_id FROM VIDEOS WHERE video_id = %s""")
curr.execute(query, (video_id,))

为了将它包装在一个函数中,我们将编写:

def check_if_video_exists(curr, video_id):
   query = ("""SELECT video_id FROM VIDEOS WHERE video_id = %s""")

   curr.execute(query, (video_id,))
   return curr.fetchone() is not None

fetchone()从表中返回一行,所以如果我们找到一个具有所需 id 的视频,它应该返回该行,否则它将返回 None。(https://py native . com/python-cursor-fetchall-fetchmany-fetch one-to-read-rows-from-table/)

如果视频存在,则更新表格

假设我们的视频存在于数据库表中。现在,我们应该用从 Youtube API 中提取的新计数来更新这些数据库记录,这些新计数保存在我们的 pandas 数据帧中。

这是一个简单的更新 SQL 命令:

query = ("""UPDATE videos
           SET video_title = %s,
               view_count = %s,
               like_count = %s,
               dislike_count = %s,
               comment_count = %s
           WHERE video_id = %s;""")
   vars_to_update = (video_title, view_count, like_count, dislike_count, comment_count, video_id)
   curr.execute(query, vars_to_update)

这是一个常规的更新 SQL 命令。%s 只是变量的参数,因此我们可以在 SQL 命令中插入适当的值。

同样,让我们用一个函数来包装它:

def update_row(curr, video_id, video_title, view_count, like_count, 
dislike_count, comment_count):
   query = ("""UPDATE videos
           SET video_title = %s,
               view_count = %s,
               like_count = %s,
               dislike_count = %s,
               comment_count = %s
           WHERE video_id = %s;""")
   vars_to_update = (video_title, view_count, like_count, dislike_count, comment_count, video_id)
   curr.execute(query, vars_to_update)

我们的循环的和函数现在看起来如下。两个函数的共同之处是数据库连接。行['video_id']* 和其他列代表熊猫数据帧中的列,在那里我们的循环的将逐行进行。 df.iterrows() 返回两个参数 I 即行索引和 row 即作为元组的行,但是在我们的例子中,我们不需要使用 I,只需要 row。*

for i, row in df.iterrows():
       if check_if_video_exists(curr, row['video_id']): # If video already exists then we will update

update_row(curr,row['video_id'],row['view_count'],row['like_count'],
row['dislike_count'],row['comment_count'])
       else: # The video doesn't exists so we will add it to a temp df and append it using append_from_df_to_db
           tmp_df = tmp_df.append(row)

这里,我们将把所有新视频(即数据库表中不存在的视频)追加到另一个 pandas 数据帧中。

在新的熊猫数据帧中存储新的视频

但是数据库表中不存在的新视频怎么办?让我们在另一个 for 循环中解决这个问题。但是我们能做的是将所有的新视频存储在一个新的熊猫数据框架中。我们的 for 循环现在完成了这个逻辑。

for i, row in df.iterrows():
       if check_if_video_exists(curr, row['video_id']): # If video already exists then we will update

update_row(curr,row['video_id'],row['view_count'],row['like_count'],row['dislike_count'],row['comment_count'])
       else: # The video doesn't exists so we will add it to a temp df and append it using append_from_df_to_db
           tmp_df = tmp_df.append(row)

将新视频插入数据库表

创建插入 SQL 命令

为了在我们的数据库表中插入新的视频,我们需要编写一个 SQL INSERT 命令。

 insert_into_videos = ("""INSERT INTO videos (video_id, video_title, upload_date,view_count, like_count, dislike_count,comment_count)
   VALUES(%s,%s,%s,%s,%s,%s,%s);""")

   row_to_insert = (video_id, video_title, upload_date, view_count, 
   like_count, dislike_count, comment_count)

   curr.execute(insert_into_videos, row_to_insert)

以同样的方式,我们编写了 UPDATE 和 CREATE TABLE SQL 语句,我们只需要编写一个常规的 SQL 语句,并使用 %s 作为列的参数。

我们将创建一个函数来存储这些命令,这样我们只需要传递视频信息和连接来执行插入。

def insert_into_table(curr, video_id, video_title, upload_date, 
view_count, like_count, dislike_count, comment_count):
   insert_into_videos = ("""INSERT INTO videos (video_id, video_title, upload_date, view_count, like_count, dislike_count,comment_count)
   VALUES(%s,%s,%s,%s,%s,%s,%s);""")
   row_to_insert = (video_id, video_title, upload_date, view_count, 
   like_count, dislike_count, comment_count)
   curr.execute(insert_into_videos, row_to_insert)

逐行添加新视频

让我们一行一行地将视频数据插入表中。为此,我们需要使用一个 for 循环来逐行遍历 pandas 数据帧,并将行一行一行地插入数据库。

就像上一个循环的一样,这个 for 循环将遍历数据帧中的每一行,然后运行 insert_into_table() 函数,该函数将对数据库中的表执行插入命令。

def append_from_df_to_db(curr,df):
   for i, row in df.iterrows():
       insert_into_table(curr, row['video_id'], row['video_title'], 
       row['upload_date'], row['view_count'], row['like_count'], 
       row['dislike_count'], row['comment_count'])

把所有东西打包

我们已经编写了处理所有工作的所有函数。我们需要一些代码来执行脚本主要部分的功能。

main 的第一部分将调用 update_db() 函数,在这里我们传递数据库连接和熊猫数据帧以及我们的视频信息。 update_db() 函数将使用新的计数更新数据库表中找到的现有视频,或者将数据库表中没有找到的视频信息存储在新的 pandas 数据帧中,我们称之为 new_vid_df

new_vid_df = update_db(curr,df)
conn.commit()

现在我们有了一个要插入到数据库表中的新视频列表,让我们调用 append_from_df_to_db()函数将这些视频插入到数据库表中。

append_from_df_to_db(curr, new_vid_df)
conn.commit()

如果你看一下数据库表,数据就在那里。现在,尝试使用这段代码更新数据库中的数据,使用一个新的 pandas dataframe,它是从 API 中提取的更新数据。

结论

在这篇文章和上一篇关于从 API 中提取数据的文章之间,我们基本上建立了一个数据管道。所有需要做的就是添加一个调度程序来自动从 API 中提取新数据并刷新数据库表。如果你能够建立一个数据管道,你就已经成功地在你的项目中迈出了第一步,这是你需要的

这个解决方案是可伸缩的,因为它可以处理数百万甚至数十亿行。并且代码是用良好的软件开发基础编写的。

https://www.stratascratch.com】最初发表于https://www.stratascratch.com/blog/importing-pandas-dataframe-to-database-in-python/?utm_source=medium&utm_medium=click&utm_campaign=blog

从 Kaggle Noob 的印象

原文:https://towardsdatascience.com/impressions-from-a-kaggle-noob-dd923e8024bf?source=collection_archive---------29-----------------------

我从我的第一个 Kaggle 比赛中学到的是:泰坦尼克号数据集

未知作者,公共领域,通过维基共享

这段时间从圣诞节前后到新年的第一周或第二周,通常是留给学习和提高技能,或者尝试新事物的。去年,我研究了深度学习,对它的工作原理有了基本的了解。可惜还是离我现在的工作现实太远了,所以就到此为止了。尽管如此,我还是对新知识感到高兴。

从去年夏天开始,我越来越关注成为一名更好的数据科学家的旅程。我最近换到了商业智能部门,处理数据成了我的日常工作。下班后和周末,我赶上了基本的 ML 算法,并使用 Scikit-Learn 编写了一些分析脚本。这被证明是非常富有成效的,因为我能够直接将我所学到的应用到我的日常工作中。

机器学习是我仍然欠缺的,也是我在 2021 年最关注的领域。圣诞节后,我得到了一些关于这个话题的好书。此外,我终于开始关注吴恩达在 Coursera 上的著名课程,尽管我发现自己很容易对被动的坐听课程感到厌倦(公平地说,Ng 的课程并不是这样)。

然而,用真实的数据集解决真实的问题通常会让我进入心流状态。在重新开始工作之前,我还有一整个周末的时间,我很想尝试一些新的东西。在书本、课程和工作之外,我可以提高我的数据科学技能,并从实践中学习。

我并没有告诉任何人什么新的东西,我只是说 Kaggle 似乎是一个很好的地方。虽然我自己从未尝试过。由于我的印象是完全新鲜的,我想与你分享这些。不要指望这篇文章会成为成为一名卡格尔大师的指南!我最近刚从新手毕业成为竞赛贡献者(这还没什么值得骄傲的)。然而,如果你自己也要开始,并且不想重复我的错误,这可能仍然是一个有趣的阅读。

我将描述我的一般方法,并在最后总结我的五点心得。

关于我自己的一点背景

如前所述,我是一家快速消费品巨头的初级数据分析师。在我的工作中,我创建商业报告,钻研 CRM 和数字媒体数据,并与同事讨论如何让他们的工作生活更有成效。我不是 ML 工程师,也不是计算机科学家。我学了哲学(文学学士)和管理学(理学硕士)

为了从数据中创造更多的知识,我不断努力提高我的数据科学技能,但我才刚刚开始我的旅程。我可以用 R 和 Python 编写代码,熟悉像 PowerBI 这样的报告工具,并使用像 SQL 和 BigQuery 这样的查询语言。我知道一些最大似然算法和回归问题,但是,我的经验有限(因此初级)。

简而言之:虽然我在工作中从数据中创造商业价值,但我并不期望拥有在激烈的竞争中表现出色的必要工具。但这对我来说不是重点。目标是通过在工作之外的数据集上应用机器学习算法来获得更多经验。跳下飞机,一边下落一边组装降落伞,对吧?

过程:进入泰坦尼克号竞赛

当开始阅读数据科学时,没有人能够逃避一些数据集。对于图像分类来说,MNIST 数据集是 Kaggle 初学者的泰坦尼克号数据集。卡格尔泰坦尼克号比赛的任务是预测谁将在泰坦尼克号失事中幸存。

1912 年 4 月 15 日,在她的处女航中,被广泛认为是“不沉”的皇家邮轮泰坦尼克号在与冰山相撞后沉没。不幸的是,没有足够的救生艇容纳船上的每个人,导致 2224 名乘客和船员中的 1502 人死亡。

虽然幸存有一些运气成分,但似乎某些群体比其他群体更有可能幸存。

在这个挑战中,我们要求你建立一个预测模型来回答这个问题:“什么样的人更有可能生存?”使用乘客数据(即姓名、年龄、性别、社会经济阶层等)。— Kaggle 网站

您从大约 900 个实例和 10 个特征开始,构建您的模型,预测另外 400 个实例的生存状态,并将您的预测上传到 Kaggle 以检查准确性。

所以每个人都从相同的数据开始但是参赛的模特表现非常不同。如你所知,重要的不仅仅是型号。发现新特性(特性工程)和决定在训练阶段保留哪些特性和忽略哪些特性可能同样重要,甚至更重要

尽管如此,由于这是一个相当小的数据集,而且竞争已经存在了一段时间,所以有许多共同的策略。然而,由于我的目标是通过尝试学习尽可能多的东西,我决定在我第一次上传之前什么都不读。

在最初的特征工程中,第一阶段仅创建了“甲板”特征,该特征基于船舱编号中的字符(例如船舱“C103”中的“C”)。一项小小的研究表明,上层甲板(A、B 和 C)的船舱是最豪华、最昂贵的,装饰精美,并且尽可能远离船底隆隆作响的机器。这肯定起作用了吧?有钱人生存?事实证明,拥有一间小屋已经是财富的象征了。

维基百科:https://en . Wikipedia . org/wiki/First-class _ facilities _ of _ the _ 泰坦尼克号

在那之后,我开始查看 EDA 阶段的数据,看看我是否能在视觉上找到特征之间的关系。我不想在这里关注它,我计划很快写一个关于我的过程和发现的 Kaggle 笔记本(链接将在这里添加,但请随意关注我的 Kaggle 个人资料)。我创建了一个总结图表,你应该提供一个清晰的画面:主要是上层阶级和女性在这场悲剧中幸存下来。

接下来,我对数据进行预处理,为 ML 算法做准备。我做了一些非常标准的事情,比如用变量的中值替换缺失值(比如年龄和费用),用 sklearn 的 StandardScaler 标准化数值,用 sklearn 的 OneHotEncoder 将类别转换成“数值”,所有这些都放在 ColumnTransformer 中。如果你对代码感兴趣,可以看看我的 GitHub repo 来了解一下。

train_df 和 test_df(我需要预测)已经为某些模型做好了准备!现在有趣的部分来了,训练 ML 模特!从我的工作经验来看,我已经非常熟悉基本的随机森林,所以很自然地,这就是我开始的地方。我没有过多关注交叉验证或选择的准确性分数,因为我只想得到一个基线。我上传了我的预测,得到了……0.46 分……对于二进制分类问题,我可能会使用类似抛硬币(np.random.binomial(1,0.5))的方法得到比我的“复杂”ML 模型更好的结果。

这是我开始研究其他人如何处理数据集以及他们的特征工程和模型如何工作的地方。我的目标是学习更多关于一般过程的知识,我已经花了几个小时完全靠自己,所以我对得到一些灵感没什么意见。

我特别喜欢 Ken Jee 的视频初学者 Kaggle 数据科学项目走查(泰坦尼克号)。在坚持使用我的预处理数据集和特征的同时,在观看了他的视频并阅读了他在 Kaggle 上的笔记本后,我又创建了几个模型,如逻辑回归、朴素贝叶斯和基于这些模型的投票分类器。

https://www.youtube.com/watch?v=I3FBJdiExcg

Kaggle 笔记本以及泰坦尼克号比赛的讨论区被证明是向他人学习的好地方。虽然你基本上可以从其他人那里“窃取”完整的代码,以便在比赛中取得好成绩,但这并不是一个符合我目标的策略。尽管如此,它帮助我提出了几个平均交叉验证分数达到 0.82 的模型(这尖叫着过度拟合,但我决定现在忽略它)。

我准备上传更多的预测。

总的来说,虽然在训练阶段很好,但我发现随机森林模型在实际的待预测数据集上效果不佳(或者我是这样认为的)。然而,投票分类器在硬投票和软投票版本中的表现明显更好,得分为 0.62200。

当时我很开心,但也很困。所以我决定今天到此为止,去睡觉。第二天,我回到了特性工程阶段,并结合了一些我在讨论部分读到的技术。我的分数变得更差了,我又回到了前一天晚上离开的地方。

一些模型现在达到了 0.62200 分,我决定比较预测结果。结果是,所有的模型都一致地预测了这个班级:无人幸存,全是 0 。当然,当泰坦尼克号的基线存活率大约为 32%时,我肯定经常是对的。

用我后来在阅读分类性能测量时了解到的术语来说:我的召回率是完美的(我识别了所有的非幸存者),但我的精确度(考虑到假阳性)是糟糕透顶。原来这个问题被称为精确-召回权衡。只有随机森林分类器预测了几个幸存者,但没有正确的,因此得分更低。

作者小土豆https://medium . com/@ syuumak/precision-recall-trade off-1 F5 b 10 cc 729d

我最终在代码的预处理部分发现了问题,解决了它,重新运行了所有的模型。这一次,我在将预测表上传到 Kaggle 之前检查了它们,结果成功了。由于现在的模型是根据正确的训练数据训练的,我的分数显著提高了

截至撰写本文时,用 RandomizedSearchCV 调优的随机森林模型是我最好的模型,得分为 0.77511,我对此非常满意。它仍然落后于 Jee 的模型 0.79425,但它使我达到了前 55%,并让我对 Kaggle 如何工作以及在处理这样的分类问题时什么是重要的有了更好的了解。

下面总结一下这两天学到的东西。

学习、收获和未来

嗯,最明显的收获和学习 1 是在将预测上传到 Kaggle 之前检查输出,并思考它们是否脱离模型有意义。当你处于心流状态和兴奋时(尤其是缺乏睡眠时)很容易忘乎所以,但这是一个容易实现的目标!

我很晚才发现我的错误的原因是我对 Kaggle 分数的痴迷。0.62200 的分数高于我的其他型号,所以它一定更好,对不对?嗯,模型预测所有人都死了,当存活率为 0.31 时,大多数情况下都是正确的。学习二:不要太执着于准确率分数否则会蒙蔽你的双眼。

训练阶段的分值也被证明是误导性的。尽管我使用了交叉验证,让<1000k instances and 30+ features resulted in overfitting. The Kaggle score was found to be 3% to 8% less than the training score using cross validation. 学习 3:不时地尝试一下,上传一些预测,看看哪些模型在真实数据上工作得很好,而不是在训练数据上过度拟合。

Kaggle 在学习方面比我想象的要好。这个社区非常活跃,人们在讨论区和笔记本区以及 Kaggle 之外的 YouTube 视频、GitHub 上或通过媒体帖子分享他们的方法和代码。我听说在真实的竞争中这是真的,而且结合其他人的方法甚至是获得高分的必要条件,这让我想起了股票估值中的市场效率辩论,但那是另一个故事了。然而,在 Kaggle 的世界里工作(例如,通过阅读和写笔记本,参与讨论)是提高个人技能的一个很好的方法,这也是我的学习 4。

谈论 Kaggle 笔记本:我倾向于在 Spyder 中工作,并将我的脚本分割成多个部分,以便我随后运行。Spyder 4 的新功能是一个很好的扩展,我可以在新的绘图部分观察所有的绘图。在用 Kaggle 做实验之前,我就知道数据科学家喜欢 Jupyter 笔记本,主要是因为它将编码和文档以一种发布就绪的格式结合在一起。没有 Spyder 的变量资源管理器和 df,我无法生活。head(5)对我来说不合适。但是,Spyder 一个人真的没有 EDA 那么伟大。在#comments 和' ' ' docstrings ' ' '中记录调查结果在视觉上不如一个优秀的笔记本吸引人。这让我想到了我最后的学习 5:数据科学家喜欢 Jupyter/Kaggle/Google Colab 笔记本是有原因的,我应该开始在那种工作中更多地使用它们(EDA,记录方法,总结发现,与他人分享,等等。).

2021 年 1 月 4 日更新:在 Jupyter 笔记本上工作时摆弄功能让我进入了前 7%。我在卡格尔的第三天。

联系我:

https://www.kaggle.com/jonasschroeder

领英:https://www.linkedin.com/in/jonas-schr%C3%B6der-914a338a/

研究门:https://www.researchgate.net/profile/Jonas_Schroeder

资源:

GitHub 泰坦尼克号回购:https://github.com/JonasSchroeder/kaggle_titanic

乔纳斯·施罗德的大众媒体文章:

可以从 LinkedIn 抓取数据吗?(走向数据科学)

线下和线上社交网络影响力研究(面向数据科学)

insta gram 上相关标签的社交网络分析(使用 InstaCrawlR,GitHub 上的代码)

Plotly 和 Sphinx 令人印象深刻的互动演示

原文:https://towardsdatascience.com/impressive-and-interactive-presentation-with-plotly-and-sphinx-1c55ee829bbb?source=collection_archive---------3-----------------------

数据科学家不用 PowerPoint 也能做更好的演示

新加坡 HDB 公寓——照片由 Unsplash 上的 Rigel 拍摄

PowerPoint 的局限性是什么?

至少 25%的数据科学家的日常工作涉及沟通和管理利益相关者,从管理层和客户那里获得认同和信心。这些都需要强有力的演示。大多数时候,PowerPoint 幻灯片是主要的工具,但它并不总是最好的选择。

  • PowerPoint 幻灯片没有交互性——你可以在 Jupyter 笔记本上创建交互式图表,但是一旦你把它们粘贴到桌面上,它们就变成静态的了。
  • PowerPoint 幻灯片不能包含太多信息——受画布大小和美学设计的限制,不建议在幻灯片上详细说明信息。然而,当其他人在演讲后提到你的幻灯片时,这样的记录会很有帮助。

Jupyter 笔记本是比较好的展示选择,但肯定不是最好的。原因是与他人共享笔记本并不简单——您需要设置 Python 依赖项并传输图表背后的数据,以便为您的同事和客户启用笔记本。我们都知道这可能非常麻烦,有时甚至是不可能的。

那么,如何才能为演示文稿创建文档,使支持交互式图表允许详细阐述、易于与他人分享?我们可以通过结合 Plotly 和 Sphinx 来实现!

第一步:交互式图表——非常精彩!

Plotly 是 Python 中最流行和最有用的图形和图表库之一。它有精心设计的高级功能,用户可以简单地调用这些功能来创建交互式图表。与其他 Python 绘图库不同,例如 MatplotlibSeaborn 生成静态图表,Plotly 生成支持悬停、缩放甚至动画的图表。

让我们在下面的例子中比较一下最简单的 Seaborn 和 Plotly 条形图。很明显,由于悬停信息和放大/缩小功能,Plotly 表现更好。

Seaborn 和 Plotly 基本条形图的比较—图片由作者提供

更重要的是,创建上面的图表一点也不难!参考下面的截图,这两个图表都是由一行代码生成的。只需将参数传递给函数,就可以轻松调整快速格式化。在 Plotly 画廊展示了许多更酷的例子。看看他们。

轻松格式化—按作者排序的图像

与将图表导出为 JPG/PNG 格式的 MatplotlibSeaborn 不同,Plotly 可以导出 HTML 格式的图表。导出的图表可以直接用浏览器打开,所有的交互都保持不变。

步骤 2:演示文档——Sphinx!

Sphinx 是一个文档生成器,它基于输入的 reStructuredText (RST)或 Markdown 文档创建 HTML/PDF 文件。它通常用于代码、API 和包文档中。比如这个网站就是斯芬克斯创建的。Sphinx 还提供了详细的快速入门介绍

为了说明如何使用 Sphinx 进行演示,我在这里创建了一个示例文档。内容摘自维基百科

登陆页面作为一个议程。通过点击链接,您将被引导至相应的主题。您也可以点击左侧面板“下一主题”下方的“历史”链接进入下一页。

登录页面—作者图片

根据日程安排,第一个主题是 Python 的历史。您可以插入流程图、时间线或任何类型的图像,并在演示过程中与他们交谈。文本描述可以作为单独的会话添加,以补充可视化,供人们更详细地参考。

首页—作者图片

第二个话题是 Python 的设计哲学。以 HTML 格式保存的 Plotly 图表可以直接加载到 Sphinx 页面中。如示例所示,图表的所有交互都保持不变。在演示过程中,你可以在现场进行切割,更清晰地传递信息。

第二页—作者图片

第三步:与他人分享斯芬克斯文档

Sphinx 创建了带格式化文件的离线 HTML 页面,这些页面可以压缩在一起,并通过正常方式共享,例如电子邮件/SharePoint。如果您选择在安装时将源目录和构建目录分开,那么您只需要共享构建文件夹。保持文件夹结构不变,告诉你的同事查找。/build/html/index.html。在下一个级别,这些文件可以很容易地托管在 web 服务器上。托管完成后,您可以像访问任何其他网站一样,通过在浏览器中输入 URL 来访问这些页面。

结束语

概括地说,使用建议的演示方法有三个主要优点:

  • 图表交互性
  • 允许详细的文本解释
  • 通过电子邮件/URL/SharePoint 轻松与他人分享

根据我与客户和领域专家的个人经验,我发现使用这种方式比 PowerPoint 幻灯片更容易说服他们。它使工作更加透明和可信。

感谢阅读。提前祝耶稣受难日快乐!

如何改善 Kubernetes 上的开发体验

原文:https://towardsdatascience.com/improve-development-experience-kubernetes-5d16da4105d7?source=collection_archive---------22-----------------------

如何减少与 Kubernetes 的摩擦,走得更快

容器的抽象是消除复杂性和减少开发人员与基础设施之间摩擦的一大步。然后,用 Kubernetes 编排这样一个容器也使 DevOps 方面的事情变得容易了。

反正我们对这个结果不满意。即使我们通过应用这些技术节省了大量时间并提高了质量,我们仍然想知道我们是否能节省更多时间并简化管理部分。

这就是为什么,现在有许多应用程序开发平台旨在创建一种开发体验,其中唯一的焦点是应用程序,自动化和抽象所有其他部分。

在本文中,我将测试 Shipa Corp 的解决方案,它在 Kubernetes 的基础上运行,用于管理应用程序,而无需了解 YAML 文件、Helm、Docker 或市场上的任何其他工具。

Kurt CotoagaUnsplash 上拍摄

什帕是什么

Shipa 的目标是通过添加一个与任何 DevOps 工具兼容的层来减少使用 Kubernetes 的影响,并且只将注意力集中在需要您努力的地方。Shipa 提供了一个以开发人员为中心的工作流程来管理和操作您在 Kubernetes 上的应用程序。

这种方法让开发者专注于交付应用程序,而不是 Kubernetes 清单或其他技术细节。相反, DevOps 只需预定义控件和护栏,并为相关团队提供高效的工作流程。因此,DevOps 将不再需要输入应用程序逻辑,因为开发人员将完全自主地管理应用程序。此外,在对应用程序和服务进行全面观察的同时,每个人都将能够了解幕后发生的事情。

当您将 Shipa 框架连接到 CI 管道时,Shipa 会自动为集群中的应用程序创建 Kubernetes 对象。所以,你不会被 YAML 的定义拖慢速度,你也不必处理大量的舵图模板。随着部署的进行,框架策略会自动应用,您只需关注应用程序代码。

创建集群

第一个要求是要有一个工作的集群。为此,我们可以使用数以千计的主机提供商之一。我在本文中解释了如何创建一个 Kubernetes 集群,但是这次我想使用提供 100 美元免费积分的 Linode 服务。

第一步是登录并创建一个集群。下图显示了如何做到这一点。

集群创建

第二步是在集群上添加一个节点来运行我们的应用程序。在下图中,您可以看到可以配置节点大小的面板。

向群集中添加节点

现在,我们必须下载连接到集群的配置文件。

正在下载集群配置

要检查连接是否正常,我们只需运行以下命令:

kubectl get pod -A

运行此命令后,您应该会在控制台中看到来自集群的系统窗格的一些行。

现在我们有了集群,是时候开始玩 Shipa 了。

安装和配置 Shipa

Shipa 的安装相当容易。它主要通过命令行完成,包括以下步骤:

  1. 为 Shipa 创建一个名称空间。这使得 Shipa 资源与其他资源隔离开来,并且避免在手工操作 Kubernetes 安装时造成混乱
  2. 使用 Helm 命令安装 Shipa 资源

作为第一步,我们必须为您的新 Shipa 安装创建一个带有管理设置的配置文件。用以下内容创建一个名为values.override.yml的文件:

auth:   
  adminUser: admin-email-here   
  adminPassword: admin-password-here

终端是我们完成这一部分所需要的,所以让我们打开它玩吧!运行以下命令:

kubectl create namespace shipa-systemhelm repo add shipa-charts [https://shipa-charts.storage.googleapis.com](https://shipa-charts.storage.googleapis.com)helm install shipa shipa-charts/shipa -n shipa-system  --timeout=1000s -f values.override.yaml

上面的命令只是为 Shipa 创建了一个名为shipa-system的新名称空间,并将使用 Helm 脚本安装软件。

在这一步之后,你会看到你的系统稍微思考了一下,因为这是一个需要时间来完成的步骤。几分钟后,您应该会看到这样的消息:

NAME: shipa
LAST DEPLOYED: Fri Apr 23 17:22:55 2021
NAMESPACE: shipa-system
STATUS: deployed
REVISION: 1
NOTES: <omitted for brevity>

上面的消息确认安装已成功完成。为了简洁起见,这里省略了注释部分,它将为您提供一些完成安装的进一步说明。

现在,如果我们想看看 Shipa 名称空间内部发生了什么,我们只需启动kubectl get pod -n shipa-system命令并检查创建了多少个 pod。

下一步需要确定您的输出 IP 地址和主机名。

kubectl --namespace=shipa-system get svc shipa-ingress-nginx -o jsonpath="{.status.loadBalancer.ingress[0]}

输出将采用以下格式:

map[hostname:myhostname.com ip:xxx.xxx.xxx.xxx]

现在安装已经完成,我们可以进入下一部分,学习如何安装 Shipa 客户端。

安装和配置 Shipa 客户端

要安装 Shipa 客户端,您只需在终端中运行一个命令:

curl -s https://storage.googleapis.com/shipa-client/install.sh | bash

这将完成所有的步骤,你将在几秒钟内准备好。现在,您可以使用 Shipa 客户机来部署 web 应用程序。

看下一个剧本。

shipa target-add shipa $SHIPA_HOST -sshipa login [m](mailto:daniele.fontani@gmail.com)yloginaddress
shipa app-list

上面的命令为部署添加了一个目标,登录到平台并显示您已经安装了多少应用程序。

现在,我们已经安装了 Shipa 客户机,并准备好部署新的应用程序了!在下一节中,我们将看到这一点。

用 Shipa 部署第一个应用程序

在本节中,我们将创建并部署一个简单的 web 应用程序。Shipa 支持最常见的框架,如 Python ,。Net、Java、Ruby 等等。在我们的例子中,我们将使用 PHP。设置分为三个步骤:

  1. 通过运行shipa platform add php启用 PHP 框架
  2. 创建应用程序,通过运行命令shipa app create appname php,你基本上告诉添加一个名为appname的应用程序,并基于php框架。
  3. 开始发展!

如您所见,设置非常简单,我们可以从头开始关注应用程序开发。我们要做的就是创建一个标准的 PHP 应用程序。

在我们的例子中,我们将创建一个包含以下内容的简单 PHP 页面

<center>
   <h1>
     <?php echo "Hello world php deployed"; ?>
   </h1>
   <img scr="https://www.shipa.io/logo.png">
</center>

然后是看到代码运行前的最后一步。我们必须向 Shipa 解释我们的应用程序是如何工作的。事实上,PHP 框架允许许多场景(使用 Nginx 或 Apache 作为前端、主机配置、PHP 版本等等)。所有这些设置都可以用源代码中的一个 YML 文件进行配置,开发者可以理解和掌握。在我们的例子中,我们使用了下面的方法:

php:
 version: 5.6
 frontend:
  name: nginx
 interpretor:
  name: fpm
 composer: true

这个文件必须被命名为shipa.yml,并放在项目根目录下。现在,最后,是时候通过运行以下命令来部署我们的应用程序了:

shipa app deploy -a appname -f .

这将把应用程序部署到 Kubernetes 集群,并且它将是可用的。接下来的窗口显示最终结果。

应用程序已部署

带什么回家

Kubernetes 是一个巨大的框架,它制造复杂的东西(可伸缩性、编排等..)简单。所有这些功能的副作用是,您经常需要付出额外的努力来正确定义您的设置,并且理解整个过程并不总是容易的。一个解决方案可能是转向完全无服务器的解决方案:这将消除 Kubernetes 的摩擦,但也有 Kubernetes 的优势,这可能是不必要的。切换无服务器解决方案的替代方法是找到一种自动化和简化与 Kubernetes 交互的方法。

Shipa 是市场上众多旨在实现这一目标的工具之一。在本文中,我们看到了如何安装和配置部署应用程序

利益

  • 减少开发人员和运营人员之间的摩擦,让他们各司其职
  • 该操作是基于终端的,因此可以很容易地自动化
  • 您不必玩容器,开发人员也不需要了解 YAML 文件或任何其他 Kubernetes 细节
  • Dev 和 Ops 之间的结合是一个包含应用程序需求的简单文件。
  • 支持大多数应用程序框架
  • 成本适中(免费自托管,然后按使用付费模式)

缺点

  • 它适用于定制应用程序,但是如果您必须使用遗留应用程序或产品,它可能更难配置
  • 在开发过程中,您必须建立一个本地环境,该环境是生产环境的复制品:您失去了使用容器的部分好处,因为开发部分

包装所有的东西 Shipa 是降低 Kubernetes 复杂性的好工具,如果它适合您的需要,也是加速应用程序开发的好方法。

参考

时间序列预测的改进线性回归方法

原文:https://towardsdatascience.com/improve-linear-regression-for-time-series-forecasting-e36f3c3e3534?source=collection_archive---------15-----------------------

结合线性模型和决策树进行更好的预测

帕特里夏·瑟纳在 Unsplash拍摄的照片

时间序列预测是一项非常有趣的任务。然而,构建一个机器学习算法来预测未来数据比预期的要棘手。最难处理的是数据中存在的时间依赖性。就其本质而言,时间序列数据会发生变化。这可能导致各种类型的时间漂移,这可能使我们的算法不准确。

我推荐的一个最好的技巧是,当建模一个时间序列问题时,保持简单。大多数时候,就准确性和适应性而言,越简单的解决方案越好。它们也更容易维护或嵌入,对可能的数据转移更持久。从这个意义上说,时间序列建模的黄金标准在于采用基于线性的算法。它们需要很少的假设和简单的数据操作来产生令人满意的结果。

在本文中,我们执行销售预测任务。我们使用标准线性回归及其改进版本提供未来预测。我们指的是线性树。它们与经典决策树一样,属于模型树家族,但它们是不同的,因为它们计算线性近似(而不是常数)来拟合树叶中的简单线性模型。计算训练以评估数据上拟合多个线性模型的最佳分区。最终模型是基于树的结构,在叶子中具有线性模型。

线性树的 python 实现在Linear-tree:一个 python 库,用叶子上的线性模型构建模型树。该软件包可与 sklearn 完全集成。它提供了简单的基本估计器,这些估计器包装了sklearn.linear_model中出现的每个线性模型,以构建一个最优的线性树。

数据

在我们的实验中,我们模拟了一些复制商店销售的数据。我们生成 400 家商店的人工销售历史。其中商店销售受许多因素影响,包括促销、假期和季节性。我们的职责是提前一年预测未来的日销售额。

当我们提供预测时,我们不使用任何过去的信息。我们设计所有的回归变量,使其在未来的任何时期都是准确和可访问的。这使我们能够提供长期预测。

我们有 400 家店铺,拥有不同年份的历史销售额,每日都有明显的季节性。

模拟店铺销售系列(图片由作者提供)

建模

我们的目标是预测未来一年我们所有商店的销售额。为了实现这一点,我们在商店层面建立了一个不同的模型。我们对每个商店的训练集进行独立的参数调整。我们以 400 个特别训练的模型结束。该程序是计算拟合简单的线性回归和线性树。以这种方式,我们可以通过比较两种模型类型在看不见的测试数据上的性能来验证 400 个独立拟合的良好性。

训练线性树就像训练标准线性回归一样简单。当我们训练线性树时,我们只是在不同的数据分区上拟合多个线性模型。我们可以清楚地理解,我们受益于相同的优点,即简单的预处理和良好的解释能力。

检查各种拟合的树路径,我们可以理解算法所采取的决策。在线性树的情况下,我们确定哪些特征负责分割原始数据集,并提供进一步拟合的好处。

不同商店安装的不同线性树的学习树路径(图片由作者提供)

正如我们所看到的,不同的模型用于不同的月份、一年中的不同周,或者一周中的不同天。这并不奇怪,因为单一的线性回归不能很好地概括所提供的整个数据集。线性树直接查看数据,评估并选择最佳分区,而不是手动搜索完美的数据分区。

来自测试数据的预测和真实值(图片由作者提供)

基于线性回归的测试数据的预测在平均值附近看起来更稳定。用线性树作出的预测很好地适应了数据,更好地适应了各种季节模式并再现了峰值。最后,我们比较了这两种模型的性能。根据测试数据,我们计算所有商店的均方根误差(RMSE)。这使我们能够验证线性树比线性回归好多少倍。

在预测商店销售额方面,线性树优于线性回归多少倍(反之亦然)

在 10 倍的测试中,线性树的表现似乎超过了经典线性回归的 9 倍。这对我们来说是一个很好的结果,这意味着在我们的场景中使用线性树有优势。

摘要

在这篇文章中,我们使用线性模型进行了时间序列预测。我们测试了简单的线性回归和线性树来预测综合的未来商店销售额。结果很有趣。线性树学习更好的数据表示,在大多数情况下提供更准确的预测。这可以简单地通过在按照简单的决策规则获得的指定数据分区中拟合多个线性回归来实现。

查看我的 GITHUB 回购

保持联系: Linkedin

通过组合分类特征提高 ML 模型性能

原文:https://towardsdatascience.com/improve-ml-model-performance-by-combining-categorical-features-a23efbb6a215?source=collection_archive---------21-----------------------

提高模型性能的一个简单技巧。

照片由来自佩克斯乔伊·凯伯拍摄

当您训练机器学习模型时,您的数据集中可以有一些表示分类值的要素。分类特征是可以分组的数据类型。

有三种常见的分类数据类型,它们是:

  1. 序数 —这有一组顺序。例如:用 1-10 的尺度给幸福打分
  2. 二进制 —只有两个值。例如:男性或女性
  3. 名义 —它没有任何订单集。示例:国家

大多数机器学习算法需要数字输入和输出变量。因此,您必须将数据集中的分类特征转换为整数或浮点数,以供机器学习算法使用。您可以对二进制特征使用标签编码,或者对名义特征使用一次热编码方法。

在本文中,您将了解组合分类特征如何提高机器学习模型的性能。

所以让我们开始吧。🚀

在机器学习模型中组合分类特征

您可以创建一个由其他两个分类要素组合而成的新要素。您还可以组合三个或四个以上甚至更多的分类特征。

df["new_feature"] = (
	df.feature_1.astype(str)
	 + "_"
	 + df.feature_2.astype(str)
	)

在上面的代码中,您可以看到如何使用 pandas 合并两个分类要素,并在数据集中形成一个新要素。

那么你应该结合哪些分类特征呢?这个问题没有简单的答案。这取决于您的数据和要素类型。一些领域知识可能对创建这样的新特性有用。

为了说明整个过程,我们将使用来自 Zindi competition 页面非洲金融包容性数据集,它具有许多分类特征,我们可以将其中一些特征结合起来,看看我们是否可以改进模型性能。

该数据集的目标是预测谁最有可能拥有银行帐户。所以这是一个分类问题。

1.加载数据集

我们的第一步是确保我们已经下载了比赛中提供的数据集。你可以在这里下载数据集。

导入重要的 python 包。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
np.random.seed(123)
warnings.filterwarnings('ignore')
%matplotlib inline

加载数据集。

# Import datadata = pd.read_csv('data/Train_v2.csv')

让我们观察数据集的形状。

# print shapeprint('data shape :', data.shape)data shape : (23524, 13)

上面的输出显示了数据集中的行数和列数。数据集中有 13 个变量,12 个自变量和 1 个因变量。

我们可以通过使用 pandas 库中的 head() 方法来观察数据集中的前五行。

# inspect data data.head()

样本 daa

理解每个要素的含义非常重要,这样您才能真正理解数据集。您可以阅读 VariableDefinition.csv 文件来理解数据集中出现的每个变量的含义。

2.了解数据集

通过使用 pandas 的 info() 方法,我们可以获得更多关于这些特性的信息。

#show Some information about the datasetprint(train_data.info())

数据描述

输出显示变量/特征列表、大小(如果包含缺失值)以及每个变量的数据类型。从数据集中,我们没有任何缺失值,我们有 3 个整数数据类型的特征和 10 个对象数据类型的特征(大多数是分类特征)。

3.机器学习模型的数据准备

下一步是从数据中分离出自变量和目标(bank_account)。然后使用 LabelEncoder 将目标值从对象数据类型转换成数值。

#import preprocessing module
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler# Convert target label to numerical Data
le = LabelEncoder()
data['bank_account'] = le.fit_transform(data['bank_account'])#Separate training features from target
X = data.drop(['bank_account'], axis=1)
y = data['bank_account']print(y)

目标值已转换为数字数据类型,1 表示“是”,0 表示“否”。

我创建了一个简单的预处理函数来:

# function to preprocess our data def preprocessing_data(data): # Convert the following numerical labels from interger to float
    float_array = data[["household_size", "age_of_respondent", "year"]].values.astype(float
    )

    # categorical features to be converted to One Hot Encoding
    categ = [
        "relationship_with_head",
        "marital_status",
        "education_level",
        "job_type",
        "country",
    ]

    # One Hot Encoding conversion
    data = pd.get_dummies(data, prefix_sep="_", columns=categ)

    # Label Encoder conversion
    data["location_type"] = le.fit_transform(data["location_type"])
    data["cellphone_access"] = le.fit_transform(data["cellphone_access"])
    data["gender_of_respondent"] = le.fit_transform(data["gender_of_respondent"])

    # drop uniquid column
    data = data.drop(["uniquid"]), axis=1)

    # scale our data 
    scaler = StandardScaler()
    data = scaler.fit_transform(data)

    return data

让我们预处理我们的数据集。

# preprocess the train data processed_test_data = preprocessing_data(X_train)

4.模型建立和实验

数据集的一部分将用于评估我们的模型。

# Split train_data
from sklearn.model_selection import train_test_spilt
X_Train, X_val, y_Train, y_val = train_test_split(processed_train_data, y_train, stratify = y, test_size = 0.1, random_state=42)

只有数据集的 10% 将用于评估机器学习模型。参数分层= y 将确保训练集和验证集的两个类的值相等(“是”和“否”)。

对于这个分类问题,我们将使用逻辑回归算法来训练和预测谁最有可能拥有银行账户。

#import classifier algorithm here
from sklearn.linear_model import LogisticRegression# create classifier
lg_model = LogisticRegression()#Training the classifier
lg_model.fit(X_Train,y_Train)

训练完分类器之后,让我们使用训练好的模型来预测我们的评估集,看看它的表现如何。我们将使用准确性作为我们的评估标准。

# import evaluation metrics
from sklearn.metrics import confusion_matrix, accuracy_score# evaluate the model
y_pred = lg_model.predict(X_val)# Get the accuracy
print("Accuracy Score of Logistic Regression classifier: ","{:.4f}".format(accuracy_score(y_val, lg_y_pred)))

Logistic 回归分类器的准确率得分: 0.8874

第一个实验:结合教育水平和工作类型特征。

现在我们知道了基本的模型性能,让我们看看是否可以通过结合 education_leveljob_type 特性来改进它。

我们在第一个实验中需要做的是更新我们已经创建的预处理函数,然后运行剩余的代码。

# function to preprocess our data 

def preprocessing_data(data): # Convert the following numerical labels from integer to float
    float_array = data[["household_size", "age_of_respondent", "year"]].values.astype(float) # combine some cat features 
    data["features_combination"] = (data.education_level.astype(str) + "_" + data.job_type.astype(str) ) # remove individual features that are combined together
    data = data.drop(['education_level','job_type'], axis=1) # categorical features to be converted by One Hot Encoding
    categ = [
      "relationship_with_head",
      "marital_status",
      "features_combination",
      "country"
      ] # One Hot Encoding conversion
    data = pd.get_dummies(data, prefix_sep="_", columns=categ) # Label Encoder conversion
    data["location_type"] = le.fit_transform(data["location_type"])
    data["cellphone_access"] = le.fit_transform(data["cellphone_access"])
    data["gender_of_respondent"] = le.fit_transform(data["gender_of_respondent"]) # drop uniquid column
    data = data.drop(["uniqueid"], axis=1) # scale our data 
    scaler = StandardScaler()
    data = scaler.fit_transform(data) return data

在上述预处理函数中,我通过以下方式更新了代码

  • 将 educaion _ level 和 job_type 组合起来,创建一个名为" features_combination "的新特性。
  • 从数据集中移除单个要素(education_level 和 job_type)。
  • 在分类特征列表中添加一个名为“feature _ combination的新特征,通过 One Hot Encoding 进行转换。

注意:我只选择了名义分类特征(有 2 个以上的唯一值)。

在为第一个实验重新训练逻辑回归分类器后,模型性能从 0.8874 提高到 0.8882 。这表明组合分类特征可以提高模型性能。请记住,我们没有改变任何东西,如机器学习分类器中的超参数。

第二个实验:结合与头部的关系和婚姻状况特征

在我们的第二个实验中,我们将结合另外两个分类特征,它们是与头部的关系婚姻状况

我们只需要更新预处理函数(就像第一个实验一样),然后运行剩下的代码。

# function to preprocess our data def preprocessing_data(data): # Convert the following numerical labels from integer to float
    float_array = data[["household_size", "age_of_respondent", "year"]].values.astype(
        float
    )

    # combine some cat features 
    data["features_combination"] = (data.relationship_with_head.astype(str) + "_"
                           + data.marital_status.astype(str) 
                      )
    # remove individual features that are combined together
    data = data.drop(['relationship_with_head','marital_status'], axis=1) # categorical features to be converted by One Hot Encoding
    categ = [
        "features_combination",
        "education_level",
        "job_type",
        "country",
    ] # One Hot Encoding conversion
    data = pd.get_dummies(data, prefix_sep="_", columns=categ) # Label Encoder conversion
    data["location_type"] = le.fit_transform(data["location_type"])
    data["cellphone_access"] = le.fit_transform(data["cellphone_access"])
    data["gender_of_respondent"] = le.fit_transform(data["gender_of_respondent"]) # drop uniquid column
    data = data.drop(["uniqueid"], axis=1) # scale our data 
    scaler = StandardScaler()
    data = scaler.fit_transform(data) return data

在上述预处理函数中,我通过以下方式更新了代码

  • 结合 relation_with_head 和 marriage _ status 创建一个名为“ features_combination ”的新特征。
  • 从数据集中移除单个要素(relation_with_head 和 marriage _ status)。
  • 在分类特征列表中添加一个名为“ feature_combination 的新特征,通过 One Hot Encoding 进行转换。

在为第二个实验重新训练逻辑回归分类器之后,模型性能从 0.8874 下降到 0.8865 。这表明,有时当你结合分类特征时,你的机器学习模型不会像你预期的那样改善。因此,你将需要运行大量的实验,直到你从你的机器学习模型中获得令人满意的性能。

包扎

在本文中,您了解了如何组合数据集中的分类特征,以提高机器学习模型的性能。正如我所说的,为了让您的模型获得令人满意的性能,您需要拥有关于您正在解决的问题的领域知识。此外,您需要运行大量需要更多计算资源的实验。

恭喜👏👏,你已经做到这篇文章的结尾了!我希望你学到了一些新的东西,对你的下一个机器学习或数据科学项目有所帮助。

如果你学到了新的东西或者喜欢阅读这篇文章,请分享给其他人看。在那之前,下期帖子再见!

也可以在 Twitter @Davis_McDavid 上找我。

之前发布的此处

使用 ctypes 提高 Python 性能

原文:https://towardsdatascience.com/improve-python-performances-with-ctypes-ef51cee2eb59?source=collection_archive---------22-----------------------

ctypes 的一个应用实例:Levenshtein 距离计算

unsplash 上来自 @chrislivernani 的转速表

语境

当谈到 python 的性能时,如果与 C 或 C++之类的编译和低级语言相比,python 通常被证明是非常慢的。大幅提高代码速度的一个方法是借助 numpy 将其矢量化。为了进一步提高速度,你可以看看 numba,它通常是一个很好的选择,只需要一个装饰器就可以把一个缓慢的算法变成一个真正快速的算法。

也就是说,我喜欢回到像 C 这样的低级语言。Python 内核是用 C 写的,所以我们为什么不试着为计算密集型部分建立自己的库呢?这就是下一篇文章的目标。

Python-C 接口

当需要将 python 代码与一些 C 库接口时,您主要有两种选择:

  • 使用第三方工具/库,它用 transpiler 把你的代码翻译成相应的 C 代码
  • 手动加载 C 库并将数据整理到相应的 C 部分

运输工具

第一种方法不是我最喜欢的,是使用中间 transpiler 将 python 代码转换成 C 代码。我只知道 Cython,但也许还有其他人存在。Cython 非常接近 python(支持原生 python 和 numpy ),这是一个很大的优势。然而,我发现它太接近 python 了,调整代码以真正提高性能可能很难。有时候你必须声明变量的类型,有时候不需要。你有一个分析器来帮助你找到代码中的瓶颈,这很有帮助,但是真的,我发现这很难学,也很难达到最佳性能。

因此,与其尝试修改一些不那么 python 化、不那么 C 的代码,我们为什么不直接使用 C 代码呢?这就是 ctypes 发挥作用的地方。

用 ctypes 编组

ctypes 是 python 中的一个本地库,根据它的文档

ctypes 提供了 C 兼容的数据类型,并允许调用 dll 或共享库中的函数。它可以用来用纯 Python 包装这些库。

因此,ctypes 真正有趣的是,您可以用纯 C 语言开发您的库,像使用任何 C 库一样编译和调试它,并直接在 python 中使用它!有点神奇。

加载 C 库非常简单:

我们现在能够调用库的任何函数,就像您调用 python 模块一样。唯一困难的是要意识到你调用了一个 C 函数,所以它需要类型化的参数,所以你必须给它正确的参数类型

为了说明所有这些,让我们举一个简单的例子。两弦间 Levenshtein 距离的计算

莱文斯坦距离

Levenshtein 距离是一个距离(从数学上来说),它度量两个字符串之间的版本距离。它测量要插入、删除或替换的字符数,以匹配两个字符串。两根弦相差越大,距离就越大。

为了计算距离,我们允许三种编辑操作:删除、插入或替换一个字符。有时与每个操作相关的成本是相同的,等于 1,有时我们将替换操作的成本设置为 2,因为它可以被分解为一个删除操作和一个插入操作。该算法非常简单,包括构建一个秩为MxN的矩阵,其中M是源字符串的字符数加 1,N是目标字符串的字符数加 1。于是,Levenshtein 距离就是矩阵的元素D[M,N]

矩阵初始化

计算矩阵D的第一步是初始化它。我们构造一个秩为MxN的空矩阵,其中M是源字符串的字符数加 1,而N是目标字符串的字符数加 1,以允许使用空字符#

然后,矩阵的第一行计算从空字符串到目标字符串的每个子字符串的距离。例如,让我们把单词levenshtein作为我们的源字符串,把levenstein作为我们的目标(这里省略了字母h)。然后,对于目标的每个子字符串,我们在每一列中都有一个成本ins_cost。的确,要从空字符串'#'到达字符串'l',我们必须插入一个字母,所以距离'#' → 'l'等于ins_cost。我们用同样的方法计算第一行的距离'#' → 'le',它等于2 x ins_cost,依此类推。推理与第一列相同,但是使用了del_cost而不是ins_cost,因为从'l''#'的距离是通过删除成本来测量的。删除和插入成本为 1 时,得到的初始矩阵为

距离矩阵初始化

矩阵元素计算

一旦矩阵被初始化,就该根据 Levenshtein 算法填充它了:

Levenshtein 距离计算算法

因此,我们从两个字符串的第一个字母开始,即我们感兴趣的单元格D[1, 1].

  • 该算法的第一行告诉我们获取当前列的前一行的内容('#' → ‘l'的成本)并将其添加到删除成本中
  • 第二行开始添加当前行前一列的插入成本('l' → '#'的成本),因此它是总成本'l' → '#' → 'l',等于 2
  • 对于最后一行,我们注意到对于这个单元格,源和目标的字母是相同的,所以我们简单地取前一行和前一列的成本,即我们不需要任何编辑来执行这个步骤。
  • 最后,我们保留三个成本中的最小值,在本例中为 0

矩阵计算

使用这种算法,我们迭代矩阵的每个单元

矩阵计算结果

两个字符串'levenshtein''levenstein'之间的最小编辑距离等于 1,这非常有意义,因为我们只需要从源字符串中删除一个字母就可以到达目标字符串。

算法实现

Levenshtein 算法实现起来非常简单(您可以找到它的许多版本),使用 C 语言通常不会有什么挑战。尝试 ctypes 的最佳时机!这里是我的算法的简单 C 实现:

我们已经遵循了算法的所有步骤,从初始化到每个单元的迭代。我选择了返回整个矩阵,但是我们也可以选择只输出距离。

如果我们注意到在计算时只需要访问前一行(或前一列)的内容,那么前面的实现可以得到改进。因此,我们可以只使用一行,并在执行计算时更新其内容。实现的改进版本如下(注意,我们现在返回的是距离,而不是整个矩阵,因为我们没有把它保存在内存中)

从 python 调用 C 函数

现在我们已经构建了我们的 C 库,由于ctypes,我们可以将它直接加载到 python 代码中,并调用其中的任何函数。

ctypes加载库很简单:

唯一棘手的部分是 C 是一种类型化语言,而不是 python,因此ctypes需要将 python 变量整理成相应的 C 类型。在第 5 行和第 11 行中,我们明确地告诉 C 函数它期望什么类型的变量,以及我们得到什么类型的结果。在我们的例子中,我们传递两个字符串(指向二进制格式的char的指针)加上三个整数,我们期望结果是一个整数。

我们现在只需要调用这个函数:

结论

我们在这里对ctypes做了一个简单的介绍,以展示我们可以多么容易地用 C 库提高 python 代码的性能:

Levenshtein 距离的 C 版本的性能

Levenshtein 距离的 python 版本的性能

正如我们已经提到的,numbacython是可供选择的商品,但我个人觉得它们更难使用和优化。使用原始 C 代码对我来说非常有意义,我真的很喜欢使用ctypes这样简单的代码。

通过这 10 个常见问题提高 Python 子串知识

原文:https://towardsdatascience.com/improve-python-substring-knowledge-with-these-10-frequently-asked-question-4c726fef4fc4?source=collection_archive---------37-----------------------

与字符串切片、索引、子字符串搜索类型、替换、子字符串重复等相关的解释

设计生态学家在 Unsplash 上拍摄的照片

子串是字符串的一部分或子集。文本数据中的任何修改都在子串过程中进行。

例如:——“这是一个很好的 whether。我们有时应该出去走走。”是一个字符串。还有弦乐的一部分“我们有时应该出去走走。”是子字符串。

这一年来,我面对了很多子串相关的问题。我把它编译成了一个关于子串的常见问题。你可能已经知道一些子串问题。有些对你来说是新的。

你可以浏览一下名单。你可能会发现一些有趣的东西。

  1. 关于字符串切片的所有内容
  2. 为什么索引显示索引越界错误但不切片?
  3. 检查字符串中是否存在子串
  4. 在字符串中搜索子字符串
  5. 字符串中存在的子字符串的百分比
  6. 使用单词或字符将字符串拆分为子字符串
  7. 获取句子的最后一个子串,不考虑长度
  8. 替换子字符串
  9. 统计子字符串在字符串中的出现次数
  10. 字符串中重复子字符串的索引

让我们开始讨论这些问题。

1.关于字符串切片的所有内容

最常见和最基本的切片模板是 string[start _ index:end _ index:step]。

仅指定切片的起点(start_index)。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[8:]                                                                                                                                                           
Out[2]: "what happens when you're busy making other plans."

仅为切片指定端点(end_index)。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[:8]                                                                                                                                                           
Out[2]: 'Life is '

指定 start_index 和 end_index。保持 start_index < end_index.

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[8:21]                                                                                                                                                         
Out[2]: 'what happens '

Keep start_index > end_index。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[10:3]                                                                                                                                                         
Out[2]: ''

如果 start_index 值大于 end_index 值,那么 text_data 的切片将不返回任何内容。

从 text_data 中提取一个字符。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[10]                                                                                                                                                          
Out[2]: 'a'

在切片过程中添加一个步骤。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[8:21:2]                                                                                                                                                      
Out[2]: 'wa apn '

在切片过程中添加一个负步骤。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data[::-1]                                                                                                                                                        
Out[2]: ".snalp rehto gnikam ysub er'uoy nehw sneppah tahw si efiL"

负阶跃的输出也反转该单词。你可以用这个方法来检查回文单词。

示例:

In [16]: is_palindrome = 'malayalam'In [17]: reverse = is_palindrome[::-1]In [18]: reverse == is_palindrome                                                                                                                                               
Out[18]: True

请指定负的 start_index 和 end_index。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [19]: text_data[-6:-1]                                                                                                                                                       
Out[19]: 'plans'

在 python 中,字符串末尾的索引从-1 开始,而不是从 0 开始。

 L    I    f    e
 0    1    2    3
-4   -3   -2   -1

2.为什么索引显示索引超出范围错误,但不切片?

In [1]: index_error = 'Life'
In [2]: index_error[5]                                                                                                                                                          
--------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-2-83a895f5645d> in <module>
----> 1 index_error[5]IndexError: string index out of rangeIn [3]: index_error[5:]                                                                                                                                                         
Out[3]: ''

index_error[5]尝试返回索引 5 处的值。但是,如果索引 5 处的值不可用,那么它将显示一个错误。切片返回值的序列。因此,如果索引[5]处的值丢失,python 不会给出任何错误。

如果你不确定文本数据的长度,那么总是使用切片。

3.检查字符串中是否存在子串

我们将使用“in”操作符来检查字符串中是否存在子字符串。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: 'Life' in text_data                                                                                                                                                     
Out[2]: TrueIn [3]: 'plant' in text_data                                                                                                                                                    
Out[3]: False

4.在字符串中搜索子字符串

我们将使用 find()函数来查找字符串中存在的子字符串的起始索引。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: sub_text_var1 = 'happens'In [3]: text_data.find(sub_text_var1)                                                                                                                                           
Out[3]: 13In [4]: sub_text_var2 = 'plants'In [5]: text_data.find(sub_text_var2)                                                                                                                                           
Out[5]: -1

如果子串在字符串中不可用,find()函数将返回-1。

5.字符串中存在的子字符串的百分比

我们可以使用 Jaccard 相似度方法来找出一个字符串中子串重复的百分比。

如果一个子串与一个字符串相同,那么 jaccord_coeff 值为 0.5。如果 substring 和 string 之间的相似度是一半,那么 jaccord_coeff 值将是 0.25。

6.使用单词或字符将字符串拆分为子字符串

In [1]: text_data = "Life is what happens when you're busy making other plans."

假设您有一个业务需求,每当一个繁忙的单词出现在一个字符串中时,程序会将该字符串拆分为子字符串。您可以使用下面的代码来实现这一点。

In [2]: if 'busy' in text_data: 
   ...:     print(text_data.split('busy')) 
   ...:                                                                                                                                                                         
["Life is what happens when you're ", ' making other plans.']

您也可以使用单个字符拆分字符串。

In [3]: if '.' in text_data: 
   ...:     print(text_data.split('.')) 
   ...:                                                                                                                                                                         
["Life is what happens when you're busy making other plans", '']

7.获取句子的最后一个子串,不考虑长度

您可以使用下面的代码获取字符串的最后一部分。它也可以处理不同长度的句子。

In [1]: text_data_var1 = "Life is what happens when you're busy making other plans."In [2]: text_data_var2 = "Today is a beautiful day."In [3]: for i in [text_data_var1, text_data_var2]: 
   ...:     print(i.split()[-1]) 
   ...:                                                                                                                                                                         
plans.
day.

8.替换子字符串

您可以使用 replace()方法替换一个单词或一组单词。

In [1]: text_data = "Life is what happens when you're busy making other plans."In [2]: text_data.replace('other','no')                                                                                                                                         
Out[2]: "Life is what happens when you're busy making no plans."In [3]: text_data.replace('making other','with')                                                                                                                                
Out[3]: "Life is what happens when you're busy with plans."

9.统计子字符串在字符串中的出现次数

借助 find()和 replace()方法,您可以统计一个单词在文档中的出现次数。请在下面找到相关代码。

In [1]: text_data_test = "Life is what life happens when you're busy life making other life plans."In [2]: count = 0In [3]: while 'life' in text_data_test: 
   ...:     text_data_test = text_data_test.lower().replace('life','',1) 
   ...:     count+=1 
   ...:In [4]: f'occurrence of word life is {count}'                                                                                                                                   
Out[4]: 'occurrence of word life is 4'

如果删除 lower()方法,单词 life 的出现次数将为 3。因为 replace()是区分大小写的函数。

尝试更改函数 replace()的输入以获得不同的结果。

10.字符串中重复子字符串的索引

可以使用 find()方法在文本或字符串中定位子字符串的所有索引。

python 中没有任何内置函数,它可以给你一个字符串中所有重复子串的索引。所以,我们需要建立一个新的。你可以使用上面的代码或者写一个新的代码。

结论

Python 开发人员总是面临与 substring 相关的问题。这些只是与 substring 相关的 10 个最常出现的问题的汇编。在本文中,我解释了切片、重复字符串、在字符串中查找子字符串、索引外问题等。

如果您有任何与 substring 相关的新问题,请告诉我。

希望这篇文章能帮助你解决与 substring 相关的问题。

用线性模型改进随机森林

原文:https://towardsdatascience.com/improve-random-forest-with-linear-models-1fa789691e18?source=collection_archive---------10-----------------------

随机森林如何在漂移中生存

奥利弗·帕斯克在 Unsplash 上拍摄的照片

随机森林可能被大多数人认为是监督预测任务中的银弹。当然,任何参与标准机器学习应用的数据科学家都被用来拟合和测试随机森林。原因是多方面的。随机森林是文献中众所周知的算法,并且被证明在回归和分类环境中都达到了令人满意的结果。它能够轻松地学习复杂的数据关系。有许多开源的高效实现可供我们所有人使用(scikit-learn 提供的实现肯定是最著名的)。

“权力越大,责任越大”。 随机森林达成的成功可能隐藏了它的弱点。众所周知,当样本属于训练期间探索程度较低的区域时,可能会产生低质量的预测。这在许多实际使用案例中很典型,在这些案例中,数据不是静态的,并且超出了拟合时所探索的范围。作为数据科学家,我们的职责是提前发现这些可能的缺陷,并帮助我们的模型尽最大努力。根据我们的领域知识和初步的数据探索,我们可以开发最合适的预处理流水线。我们还可以更进一步,根据我们数据的特点选择最佳模型。

从这个意义上来说,当对一个不稳定的系统建模时,线性模型可能与基于树的模型一样好,因为它们能够学习趋势行为。为什么不把它们结合起来呢?为什么不创建一个模型,同时学习线性和更复杂的关系?

在这篇文章中,我们将介绍线性随机森林,如本书中所建议的。我们尝试执行一个模拟回归任务,其中我们希望预测未来的目标是多个复杂源(不仅仅是线性源)的组合。我们使思想变得更加辛辣,引入了一个增加的趋势,这可能会在简单的基于树的模型的推理时引起一些问题。我们很想知道在这种情况下,如何从线性模型和随机森林的结合中获益。

线性随机森林的实现在 线性树中简单可用。它为分类和回归上下文提供了 LinearTreeLinearForest、LinearBoosting 的实现。该软件包旨在提供现成的算法,与 scikit-learn 生态系统完全兼容,混合了线性模型和决策树的学习能力

数据

我们模拟来自高斯分布的数据。然后,我们对特征子集应用特定类型的变换,例如线性、平方、正弦和交互。我们想要预测的目标是先前转换的特征的组合。下一步,我们复制我们的数据,并为所有特征添加增长趋势。新目标显示了所有预测指标的相同增长趋势。

无趋势的模拟数据(左);模拟趋势(中间);趋势模拟数据(左)[图片由作者提供]

建模

我们必须执行双重预测任务。首先,我们尝试在没有数据偏移的情况下预测我们的目标,然后我们做同样的事情,但数据会发生漂移。为了模拟我们的模型如何随时间变化,我们为各种训练测试重新划分重复拟合。我们从少量的训练数据开始,然后逐步增加。

培训-测试策略概述[图片由作者提供]

在没有移位的情况下,特征的分布随着各种分裂重新划分而保持不变。这与数据漂移的情况完全不同。在后一种情况下,数据开始遵循较高的趋势行为。训练区和试验区的分布差别很大。

对于建模阶段,我们选择在两种场景中测试三种不同的替代方案。我们从一个简单的线性回归开始,然后传递到一个随机森林,最后,我们评估它们的混合是否能提供一个提升。像往常一样,在对我们的训练数据进行简单的调整和交叉验证之后,我们报告测试数据的性能。

我们根据简单线性回归获得的误差的均方误差偏差(MSE)来探索结果。大于 1 的值意味着该模型获得的误差比线性回归获得的误差更差。对于小于 1 的值,情况正好相反。我们在同一张图中绘制了两种情况下(有趋势和无趋势)、所有模型和所有测试规模的所有误差。

测试结果与线性回归性能的偏差[图片由作者提供]

我们可以看到,同样在没有趋势的情况下,线性森林比线性回归和随机森林做得更好。简单的线性基线模型可以获得与随机森林相同的结果。在漂移的情况下,差异变得更大。Randon Forest 从基线开始恶化,而 Linear Forest 改善了与其竞争对手之间的差距。

如果我们知道线性森林是如何工作的,这些结果是可以预料的。首先,我们选择一个线性模型来拟合原始数据,以逼近目标。第二步(也是最后一步),在同一组数据上训练一个随机森林,以再现上一步的残差。最终预测是线性预测和森林预测的总和。线性森林达到的良好性能是通过混合线性回归学习线性关系的能力(也是在不稳定的情况下)和随机森林逼近复杂模式的更复杂的能力而获得的。

摘要

在这篇文章中,我们介绍了线性随机森林,这是一种推广算法,在某些情况下,可以提高简单随机森林和线性回归的学习能力。结果反映了我们的预期,并与论文中显示的结果一致。一如既往,在任何情况下都能达到最佳效果的完美算法是不存在的。作为数据科学家,我们有责任选择并验证最佳方案。

查看我的 GITHUB 回购

保持联系: Linkedin

用哈希函数改进训练测试分割

原文:https://towardsdatascience.com/improve-the-train-test-split-with-the-hashing-function-f38f32b721fb?source=collection_archive---------12-----------------------

马库斯·斯皮斯克Unsplash 拍摄的照片

入门

更新数据集时,确保定型集和测试集不会混淆的最佳方法是

最近,我在阅读 Aurélien Géron 的用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习(第二版),这让我意识到,在为机器学习模型准备数据时,我们处理训练测试分割的方式可能存在问题。在本文中,我快速演示了问题是什么,并展示了如何修复它的示例。

说明问题

我想提前说,我提到的问题并不总是问题本身,这完全取决于用例。在准备用于培训和评估的数据时,我们通常使用 Scikit-Learn 的train_test_split 等函数分割数据。为了确保结果是可重复的,我们使用了random_state参数,所以无论我们分割相同的数据集多少次,我们将总是得到完全相同的训练测试分割。这句话中存在我之前提到的潜在问题,特别是在关于相同数据集的部分。

想象一下这样一种情况,您构建了一个预测客户流失的模型。您收到了令人满意的结果,您的模型已经投入生产并为公司创造了价值。干得好!然而,一段时间后,随着更多的客户加入公司,客户中可能会出现新的模式(例如,全球疫情改变了用户行为),或者您只是收集了更多的数据。出于任何原因,您可能希望重新训练模型,并使用新数据进行训练和验证。

这正是问题出现的时候。当您在新的数据集上使用好的旧的train_test_split(所有的旧的观察结果+自训练以来收集的新的观察结果)时,不能保证您在过去训练的观察结果将仍然用于训练,对于测试集也是如此。我将用 Python 中的一个例子来说明这一点。

首先,我生成了一个包含 1000 个随机观察值的数据框架。我使用random_state应用了 80–20 训练测试分割,以确保结果是可重复的。然后,我创建了一个新的数据帧,在初始数据帧的末尾添加了 500 个观察值(在这种情况下,重置索引对于跟踪观察值非常重要!).我再一次应用了训练测试分割,然后调查了初始集合中有多少观察值实际出现在第二个集合中。为此,我使用了 Python 的set的便捷的intersection方法。答案是 800 分中的 669,200 分中的 59。这清楚地表明,数据被重新洗牌。

这种问题的潜在危险是什么?这完全取决于数据量,但在一次不幸的随机抽取中,所有新的观察结果都将出现在其中一个集合中,这对正确的模型拟合没有多大帮助。尽管这种情况不太可能发生,但更有可能出现的在集合中分布不均匀的情况也不是那么理想。因此,最好是将新数据平均分配给两个集合,同时将原始观测值分配给各自的集合。

解决问题

那么我们该如何解决这个问题呢?一种可能性是基于某个唯一的标识符将观察值分配给训练集和测试集。我们可以使用某种散列函数来计算观察值标识符的散列,如果该值小于最大值的 x%,我们就将该观察值放入测试集。否则,它属于训练集。

您可以在下面的函数中看到一个示例解决方案(基于 Aurélien Géron 在他的书中提出的解决方案),它使用 CRC32 算法。算法的细节我就不赘述了,你可以在这里阅读关于 CRC 的内容。或者,在这里你可以找到一个很好的解释,为什么 CRC32 可以很好地充当哈希函数,以及它有什么缺点——主要是在安全性方面,但这对我们来说不是问题。该函数遵循上一段中描述的逻辑,其中 2 是该散列函数的最大值。

注意:上面的函数适用于 Python 3。要针对 Python 2 进行调整,我们应该遵循crc32的文档,使用方法如下:crc32(data) & 0xffffffff。你也可以在这里阅读更详细的描述

在实际测试该函数之前,有一点非常重要,那就是应该为散列函数使用一个唯一且不可变的标识符。对于这个特定的实现,也是一个数字(虽然这可以相对容易地扩展到包括字符串)。

在我们的 toy 示例中,我们可以安全地使用行 ID 作为惟一的标识符,因为我们只在初始数据帧的末尾添加新的观察值,从不删除任何行。然而,在使用这种方法处理更复杂的情况时,需要注意这一点。因此,一个好的标识符可能是客户的唯一编号,因为根据设计,这些编号应该只会增加,不会有重复。

为了确认这个函数正在做我们想要它做的事情,我们再次运行测试场景,如上所示。这一次,对于两个数据帧,我们都使用了hashed_train_test_split函数。

当使用散列的唯一标识符进行分配时,我们实现了训练集和测试集的完美重叠。

结论

在本文中,我展示了如何使用散列函数来改进训练测试分割的默认行为。对于许多数据科学家来说,所描述的问题不是很明显,因为它主要发生在使用新的和更新的数据集重新训练 ML 模型的情况下。所以这并不是教科书中经常提到的东西,或者人们在使用示例数据集时不会遇到它,即使是来自 Kaggle 竞赛的数据集。我之前提到过,这对我们来说可能不是问题,因为这真的取决于用例。然而,我确实相信一个人应该意识到这一点,并且如果有这样的需要,应该知道如何修复它。

您可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特上或者评论里联系我。

如果您喜欢这篇文章,您可能还会对以下内容感兴趣:

</5-free-tools-that-increase-my-productivity-c0fafbbbdd42>

参考

  • Géron,A. (2019)。使用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习:构建智能系统的概念、工具和技术。第二版,奥赖利媒体。

通过有意义的文本和注释提高可视化可读性

原文:https://towardsdatascience.com/improve-visualization-readability-with-meaningful-text-and-annotations-b5d93eaadf4b?source=collection_archive---------11-----------------------

确保其他人能够欣赏你用 Plotly 有效描述的可视化的全部潜力

作者照片

文本肯定不是可视化中最有趣的部分,但正确的文本可以显著提高可读性,并提供额外的细节和深度。另一方面,忽略足够的描述会大大降低你的 viz 清晰度,并使接收者感到困惑。

如果您的分析是跨团队共享的,那么好的注释尤其重要,因为它使得在没有可视化数据集的先验知识的情况下更容易阅读。充分的解释有助于避免诸如“这种颜色是什么意思”之类的问题,这使得每个人的工作都更容易。

在本文中,我的目的是演示如何通过对注释和文本的一些改进,使 Plotly 的可视化更具吸引力,更易于阅读。我使用了华沙 60 平方米以下房产的租金价格和折线图。同样的技术可以用于任何数据集和图表类型。

样本数据和代码可在 GitHub 获得,使用nb viewer探索交互情节。

1.基本线图

基本折线图

基本折线图的代码

我们从一个简单的线图开始,向我们展示了过去 8 个月华沙月租金的总体趋势。vanilla Plotly 注释只显示了 x 和 y 值,没有任何额外的解释——让我们看看如何改进它。

2.向注释添加多个尺寸

具有多维注释的折线图

带有额外注释的折线图代码

首先,我们可以在注释中添加多个维度,并在文本属性中添加一些额外的描述,如上面的代码所示。数据很少只有两个我们可以轻松可视化的维度——添加其他维度作为注释有助于我们更好地理解数据点之间的关系。

在分析的案例中,我添加了每月变化、报价计数和平均面积,以便能够快速评估每月价格变化和分析报价的关键特征。为了向文本字符串中添加这些特性,我使用了一个. format()函数,并在数据帧的第 14–19 行中的每一行上进行迭代。

既然我们能够更好地描述可视化数据,我们应该集中精力改进格式,使其更具可读性,更整洁。

3.改进的格式

带批注的格式化折线图

带注释的格式化折线图的代码

这个情节看起来比上一个整洁多了。这一实质性的视觉改进只需要对 Plotly 中的文本属性进行 3 处小的修改。

首先,我用 hovertemplate= '%{text}' 属性移除了 x 和 y 的基本 Plotly 注释,以仅显示来自文本变量的特征和格式。

然后,我限制了显示的小数位数,就像在 print()函数中一样——使用{:。xf},其中 x 表示我们希望看到的小数位数—取决于我使用的变量 0 到 2。

最后但同样重要的是,我利用使用基本 html 格式化文本数据的能力来突出最重要的特性:标题和轴标题以及注释中的月平均价格特性。我所需要做的就是在文本和标题中添加 HTML。

4.用颜色和尺寸可视化多维度

多维可视化折线图

多维可视化折线图代码

我们可以通过添加颜色和标记大小来增加图表上显示的功能数量,以突出每月变化和报价计数。增加显示的维度数量会使图形更加健壮,但是如果没有适当的描述,它会变得更加难以理解。

在本例中,我添加了一行额外的标题来解释线条、大小和颜色所代表的内容,并为颜色图例添加了一个有意义的标题来提高可读性。

5.比较多个数据段

多段折线图

在这个额外的可视化中,我想展示当我们深入到更复杂的图形中时,清晰的注释变得更加重要。按主要地区划分平均价格要求我们添加单独的散点图,用 mode="text "显示地区标签。

当有多个细分市场时,我们可以使用注释来显示横向和纵向关系,在本例中,我们显示了每个地区的月度变化以及每个地区在月度总报价中的份额。

6.摘要

我希望我成功地展示了一些小的改变如何显著地提高你的图表的质量和可读性。

此外,在维数、数据类型、数量级和单位方面,文本的限制比绘图少。这允许用细节特征丰富基本图,增加我们分析的深度,并确保我们不会错过影响我们关键变量的其他重要特征。

由于好奇心是数据科学家的关键美德之一,我们可能会倾向于忽略最简单的解决方案,而去寻找更复杂、更有趣的解决方案。

不要让你的数据可视化的最简单的元素对整体效果产生负面影响——花几分钟在文本上,这样其他人可以欣赏你的可视化的全部潜力!

利用这些数据分布可视化改进您的分析项目

原文:https://towardsdatascience.com/improve-your-analytics-projects-w-these-data-distributions-visualizations-7ba3821f2092?source=collection_archive---------4-----------------------

带有增强的示例代码,可以激发您的制图创造力

注:本帖代码可在 这里 找到

可视化发行版的不同方法(图片由作者提供)

理解变量在数据中的分布是一个重要的步骤,应该在探索性数据分析 ( EDA )过程的早期进行。有许多工具可以用来分析数据的分布。可视化辅助工具可能是最受欢迎的,因为一个构造良好的图表可以快速回答关于数据的重要问题。例如:

  • 有哪些中枢倾向?平均值、中间值和众数。
  • 有哪些分散措施?范围、IQR、方差和标准差。
  • 分布的形状是什么?均匀、参数化、对称还是偏斜?
  • 是否存在异常值或极值?

在本文中,我们将看看用来表达数据分布的最流行的图表。我们主要关注单变量数据,但也有机会根据第二个变量对子集进行比较。

数据集介绍

数据集来自对一家信用卡发行商的流失分析,包括人口统计和财务数据。既有分类又有数值离散还是连续。离散变量只能取某些值,而连续变量可以取不可数的值。离散变量的值是通过计数获得的,而连续变量是通过测量获得的。大约有 10,000 行,其中一行代表一个客户。

# Import Dependenciesimport pandas as pd
import os
import matplotlib.pyplot as plt
import math# Import Datafile_path=os.path.join('BankChurners.csv')
df=pd.read_csv(file_path)

本文的主要目标是分析数据是如何分布的,即查看不同类别中的记录数量。所演示的语法假设之前没有执行转换,并且每一行代表一个唯一的客户端。对于文章中包含的基本绘图,我们将使用 熊猫。DataFrame.plot() 方法,而对于更高级的绘图,我们将结合使用 NumpyMatplotlib。Pyplot 允许更多的定制

频率表和列联表

很多数据探索都是从 频率表 开始的。频率表显示了与单变量数据的每个类别相关的记录数。列联表是频率分布表的二元版本。它一目了然地显示了多个变量之间的高层关系。

# Frequency Tabledf['Customer_Age_bin'].value_counts()
df.pivot_table(columns='Education_Level', 
               index='Customer_Age_bin', 
               aggfunc='size')

客户年龄和教育水平频率表

我们首先检查我们的数据集是否能很好地代表不同的人群。这将让我们了解数据中是否存在采样偏差。频率表显示,在 10K 顾客中,大多数顾客年龄在 40 至 55 岁之间。进一步观察教育水平的权变表,大多数人口统计组都有代表,尽管具有大学教育水平的客户比我预期的要少。

升级——百分比列联表可能有助于了解比例。

权变 _ 表格. py

对频率表的工作原理有了大致的了解后,我们可以探索表达频率表的各种可视化方式。

热图

热图可以使包含许多类别的列联表更容易理解。它强调使用颜色来表示每个汇总统计量的大小。结果是相对频率的非常直观和易于阅读的表示。

流失客户和现有客户的人口统计分布热图显示了相似的分布

Pandas 中热图的语法需要对数据帧进行样式化。根据偏好,style . background _ gradient()方法可以采用其他颜色图( cmap )。

df[['Customer_Age']].style.background_gradient()

热图显示,虽然数据中流失的客户明显较少,但他们的人口统计特征分布似乎与现有客户相似。这可能表明 1)与收入和流失决定没有很强的关联,或者 2)数据是有意抽样的,以保持两组在每个类别中的比率。我们可以继续检查两组的其他特征。

饼图

也许可视化分布的最简单图表是 饼状图 。饼状图简单易懂。它在展示跨类别的分数关系方面是有效的。

Pandas 中饼图的语法要求将数据从原始数据转换成唯一值的计数:

# Need to transform raw data into counts of unique values - the number of rows in the series that is calling the .plot() method will represent the number of slicesdf['Attrition_Flag'].value_counts().plot(kind='pie')

现有客户与流失客户以及每个客户的关系数量

此客户流失指标饼图代表与流失客户和现有客户相关的数据集部分。上面的可视化显示了 16.1%的流失率,这对公司来说确实是一个大问题。通过总关系计数的嵌套饼图进一步研究,可以发现大多数现有客户(83.9%中的 49.6%)与该金融机构有 3 个以上的关系。相比之下,流失客户的比例要小得多(16.1%中的 6.4%),这表明与金融机构有更多关系的客户不太可能流失。

升级-嵌套饼图可以通过将一个饼图层叠在另一个饼图上来创建。如果处理得当,它可以提供一个有趣的视角。

绘图嵌套饼图

条形图

当有太多窄的切片时,饼图会失去效用,因为它会变得太忙。当有许多类别时,另一种可视化是频率 条形图 。这种类型的条形图为每个选定的类别绘制一个条形,每个条形的高度表示该类别的频率。

Pandas 中频率条形图的语法再次要求将数据从原始数据转换为唯一值的计数:

# Need to transform raw data into counts of unique values - the number of rows in the series that is calling the .plot() method will represent the number of barsdf['Contacts_Count_12_mon'].plot(kind='bar')

现有与流失的客户和联系人数量(过去 12 个月)

该条形图显示了 12 个月内联系次数,将联系次数为 0 到 6 次的客户分为不同类别。上面的图像显示,大多数客户在 12 个月内联系 2 到 3 次。我们可以通过分层进一步研究这如何影响他们继续或停止使用服务的决定。并排条形图堆积条形图并不能完全说明问题。然而,与交叉制表的百分比堆积条形图一起,它们表明联系更频繁的客户可能是流失客户。此外,客户可能会在第 6 次也是最后一次联系时终止关系。

升级-通过将一个条形图层叠在另一个之上并设置底部或每个后续条形图,可以创建百分比堆积条形图。

绘图 _ 堆叠 _ 条形图 _ 百分比

直方图

我们可以使用条形图来比较分类(或离散)变量的频率。这与 直方图 非常相似,也是列表频率的图形表示。用于显示离散和连续数值变量的分布。为了计算连续变量出现的频率,必须首先将它们放入离散区间——这一过程称为宁滨。直方图的 x 轴代表平均划分为一组条柱的数据,y 轴(条形高度)代表每个条柱的观察计数。对于直方图,x 轴上的条块顺序很重要,并且条块之间没有间隙。

Pandas 中直方图的语法不需要任何转换。虽然 Matplotlib 和 Pandas 会自动选择一个合理的 bin 宽度,但创建自定义 bin 可能会更有利——这可以通过 Numpy 轻松完成。

# No need to transform raw data - the series that is calling the .plot() method needs to contain all values in the distributionmin_amt=data['Total_Revolving_Bal'].min()
max_amt=data['Total_Revolving_Bal'].max()
first_bin=min_amt//bin_width*bin_width
n_bins=math.ceil((max_amt-min_amt)/bin_width)bins=[first_bin+i*bin_width for i in range(n_bins+1)]df['Total_Revolving_Bal'].plot(kind='hist', bins=bins)

大约在 1500 美元左右,循环余额直方图类似于钟形曲线

循环余额直方图显示,有一群客户的余额为 0 美元,正好是 2,517 美元,其中许多客户会流失。过滤掉两个极端的客户后,分布显示出大约 1500 美元左右的对称性,至少对现有客户是这样。他们通常还保持大约 500 美元以上的余额。这种钟形分布因其“正态性”而被认可,正态性可以通过其均值、标准差来定义,在这种情况下是峰度(也称为“尾部”)。了解这个分布的这些特征会非常有用。流失客户的分布看起来更加均匀。这表明循环余额本身可能不是损耗的好信号。

升级-可以通过将一个直方图层叠在另一个直方图上来创建重叠直方图。它可以显示数据集中不同类别出现的频率。这是并排直方图或堆积直方图的更好的替代方法,因为它易于解释。

绘图 _ 重叠 _ 历史

升级-选择料箱宽度是一个重要参数。为了避免在选择箱子宽度时出错,通常要尝试不同的选项。

实验历史箱

密度图

查看直方图的一个有用的统计方法是将计数表示为相对频率,或总数的百分比。对于离散数据和箱大小为 1,这是每个选项的密度。对于连续变量,相对频率需要进一步除以箱的大小,以得到每个箱的密度。这可以解释为给定值出现在 bin 中的经验概率。因此,所有条形的面积总和等于 100%。这就是所谓的归一化直方图。在 密度图 中,我们试图通过在无限小的面元宽度处绘制密度曲线来可视化连续变量的潜在概率分布——这被称为概率密度函数。该图/函数的一个重要方面是,它通过估算使概率分布变得“平滑”。估算背后的想法是,我们将我们的数据视为我们感兴趣的更大列表的子集——总体。我们可以通过对所有成分进行加权求和来估计该分布,其中一个成分是以记录数据点为中心的分布(基于选择的内核)。查看密度图时,我们可以将某个值落在某个范围内的概率解释为曲线下的面积。

密度图的语法与直方图的语法非常相似。

# No need to transform raw data - the series that is calling the .plot() method needs to contain all values in the distributiondf['Total_Trans_Ct'].plot(kind='kde')

交易计数的密度图显示了两种模式

总事务数的密度图显示,在~45 和~75 处有两种分布模式。巧合的是,这些接近于由磨损标志分层的个体密度图的模式。这表明总事务计数可能是流失的良好信号。也就是说,交易越频繁的客户流失的可能性越小。或许直觉告诉我们,经常使用信用卡的顾客可能在他们的账户上设置了自动支付功能,这使得他们不愿离开。知道了高联系数和客户流失之间的关联,过去 12 个月联系数的岭图显示,客户可能在每次联系后开始逐步停止使用信用卡。

升级-山脊图按不同类别对密度图进行分层。它可以通过使用来自 Scipy 的期望核迭代计算概率密度函数来创建。每个数据子集的统计。比较概率密度可以揭示不同类别的行为差异。

箱线图

直方图和密度图的另一种选择是 箱形图盒须图,也简称盒图,是一种常用的通过四分位数概括数据集分布的定性方法。方框包围了上四分位数和下四分位数之间分布的中间一半,而触须则用于表示外部的可变性。箱线图也可以将异常值显示为与须状线一致的单个点。虽然它们可能看起来很原始,但它们有简单的优点,这在比较不同群体时很有用。

Pandas 中方框图的语法不需要任何转换。有许多修饰性配置可以与盒图相关联地进行调整:平均值、中值、异常值、须状和盒形。(参见文档)。重要的是,当使用带有shower filers参数的图表时,我经常选择关闭异常值。

# No need to transform raw data - the series that is calling the .plot() method needs to contain all values in the distributiondf[‘Total_Trans_Ct’].plot(kind=’box’, vert=False)

具有不同配置的箱线图

总交易量的箱线图揭示了与总交易计数非常相似的故事。也就是说,流失客户倾向于减少信用卡消费。尽管分布是以更简单的方式总结的。我们可以清楚地看到,现有客户的支出比流失客户分散得多。此外,通过在手动绘制的异常值上应用一点抖动,我们可以看到有一个高消费的现有客户集群。这些客户的流失风险非常低。通过根据收入类别对盒状图进行分层,我们可以看到,虽然在收入阶梯上的中间支出没有明显的模式,但在平均值上有一个模式。

升级-当异常值变得很多时,将异常值单独绘制成散点图可能更容易。如果我们对一个轴施加小的“抖动”,那么为了便于观察,它们就变得交错。

在另一项分析中,我们将着眼于高消费客户群,看看我们能否识别出他们的一些独特特征。

摘要

在本文中,我们查看了用于可视化数据分布的不同图表。我们通过对客户流失的分析,强调并展示了每种图表类型的优势。我希望这些要点对你有所帮助。请随意使用/修改它们用于其他目的。我很高兴看到你会创造出什么样的创造性的视觉效果。

提高你的底线

原文:https://towardsdatascience.com/improve-your-bottom-line-8f2db94f3e7e?source=collection_archive---------29-----------------------

实践教程

预测联合循环电厂电力输出的机器学习模型。

加州圣克拉拉硅谷电力公司。美国公共权力协会。

介绍

加快气候变化的速度需要开发和部署更多的可再生能源,同时减少化石燃料的消耗。增加电能消耗可以进一步对气候变化产生积极影响;随着世界从内燃机过渡到电动汽车,人类对电力的需求可能会增加的一个领域是汽车。

满足这种需求激增可能需要增加发电量,但如果我们要实现气候变化目标,就必须在不增加发电所需化石燃料使用量的情况下实现这一增产。进入联合循环发电厂(CCPP)。

这项研究的目标是设计一个最佳的机器学习模型,使用四个变量预测 CCPP 的电力输出(本文中标为 PE ),这四个变量是以摄氏度测量的环境温度(AT)、以毫巴测量的环境压力(AP)、以百分比记录的相对湿度(RH)以及以厘米汞柱测量的工厂气体压缩机的排气真空压力(V)。输出功率以兆瓦(MW)为单位,研究中的 CCPP 发电能力约为 490 MW。

原始数据集是在一项实验中产生的,在该实验中,放置在 CCPP 特定位置的传感器用于收集 2006 年至 2011 年期间电厂满负荷运行时的环境温度、压力、相对湿度、排气真空度和净发电量的读数。每个观测点的值都是每小时的平均值,包含所有变量的完整数据子集总共有 9658 个观察值。

这项研究基于从长达 6 年的实验中收集的数据集,该实验随后被捐赠给加州大学欧文分校的机器学习和智能系统中心。你可以在这里找到数据。在迭代了三个机器学习回归器模型后,我发现随机森林回归器(RFR)的性能最好。然后,我对 RFR 模型进行了一些超参数调整,结果均方根误差为 3.443,平均绝对误差为 2.418,R 平方值为 0.960。

联合循环电厂——概述

CCPP 结合了两种涡轮机系统的使用,一种是燃烧燃料来发电的燃气涡轮机,另一种是利用燃气涡轮机的废热产生的蒸汽来产生额外的电力的蒸汽涡轮机。从燃气轮机排出的热量被转换成蒸汽,该蒸汽被引导到蒸汽轮机用于额外的发电。

CCPP 用同样数量的燃料比传统的简单循环发电厂多生产 50%的电力。因此,CCPP 每生产一兆瓦能源消耗的天然气较少。要了解更多关于 CCPP 内部运作的信息,请访问本页。联合循环工艺流程图见图(1)。

图①。联合循环工艺流程图,显示从燃气轮机回收的热量如何用于通过蒸汽轮机产生额外的电力。余热蒸汽发生器是 CCPP 系统的关键部件。资信证明: 马丁安德森普利司通联合有限公司。2020 年 5 月

方法学

该数据集有 40 个重复行,在数据争论过程中被删除。结果,最终的数据集减少到大约 9527 个观察值,而原始的 5 个变量保持不变。

在五个变量中,电力输出(PE)被设置为目标,而天气参数被设置为特征;燃气轮机的功率输出主要取决于环境温度、大气压力和相对湿度。

汽轮机的功率输出和汽轮机的排气真空之间也有关联。因此,排气真空被添加到三个天气参数中,以形成 9527×4 的特征矩阵。

一旦目标和特征被建立和分离,我就对数据集进行 80/20 的训练/测试分割,分成 X_train、y_train 和 X_test、y_test。然后,我使用 Select K Best for k=1 到 4 加上一个线性回归模型来确定用于测试模型的最佳特征数。接下来是训练和测试回归模型,以找到产生最低误差度量的模型。我测试的回归模型如下:

  1. 线性回归
  2. 随机森林回归量,以及
  3. 梯度推进回归器

为了挑选最好的模型,我重点测量了三个关键的回归指标:均方根误差(RMSE)、平均绝对误差(MAE)和每个测试模型的 R 平方值。然后,我做了一些超参数调整,以优化最终模型。

探索性数据可视化

下面是一些图表,可以更好地理解每个变量,并了解这些变量之间的一般关系,尤其是与目标变量的关系。

功率输出直方图(PE)

图(2)是显示目标变量的分布的直方图,以兆瓦(MW)测量的电能功率(PE)的输出。该曲线看起来有点双峰,大部分数据在 435 MW 到 445 MW 范围内。在 420 MW 附近似乎也有一个异常值。

图(2)。以兆瓦为单位测量的电力输出(PE)分布。

热图

图(3)中的热图显示了变量之间的相关性。我们看到输出(PE)和温度(AT)之间的负相关系数约为-0.95,输出和排气(V)之间的负相关系数约为-0.87。大气压力(AP)和相对湿度(RH)与 PE 呈正相关,但相关性较弱。

图(3)相关热图

回归图—功率(PE)和温度(AT)

图(3)还显示了在-0.95 处功率和环境温度之间存在最高的相关性。这种强相关性在图(4)所示的回归图中很明显。温度以摄氏度为单位。

图(4)。PE V AT 的回归图

回归图—功率(PE)和相对湿度(RH)

功率和相对湿度之间的相关性显示为正,但是在大约 0.39 处较弱。与上面显示的温度点相比,这些点看起来更加分散。这种关系见图(5)中的图表。

图(5)。PE 对 RH 的回归图

回归图—功率(PE)和大气压力(AP)

与目标变量正相关的另一个特征是大气压力(AP),它与目标的相关系数为 0.52。图(6)中所示的图表上的点比图(5)的相对湿度图中的点更集中在趋势线周围。大气压是以毫巴为单位测量的。

图(6)。PE 与 AP 的回归图

回归图—功率(PE)和排气真空(V)

除了环境温度,排气真空是与目标变量负相关的另一个特征。它还具有第二高的相关性,为-0.87。真空度的测量单位是厘米汞柱。这种关系的曲线图见图(7)。

图(7)。排气真空回归图。

基线分析

在深入构建任何预测模型之前,有必要建立一个基线作为衡量模型性能的标准。从图(2)所示的目标变量的分布来看,一个好的基线估计将是目标变量的平均值。在这种情况下,它是 y_train 的平均值。

对于训练数据,RMSE 是 17.012,平均误差是 14.765,而对于测试数据,RMSE 是 17.143,平均误差是 14.973。训练和测试数据的 R 平方值都为零。

特征选择

为了确定使用哪些功能运行我们的模型,我使用 Select K Best 从 k=1 到 k=4 迭代来拟合和转换数据,然后通过线性回归模型运行拟合和转换的数据。这样做了四次,从一个特性开始,然后每次运行增加一个额外的特性。对于每次运行,计算由使用的特征数量产生的 MAE。

对于 1 个特征,MAE 是 4.283,对于 2 个特征是 3.897,对于 3 个特征是 3.870,对于 4 个特征是 3.621。因此,当数据集的所有 4 个特征都用于构建模型时,MAE 最低。

构建和测试模型

我使用数据集中的所有四个特征运行了方法会议中列出的所有三个模型;我在训练数据集上拟合每个模型,对训练数据运行预测以获得训练指标,然后对测试数据运行预测以获得测试指标。以下是从每次模型运行中获得的指标。

线性回归

对于训练数据,RMSE 为 4.551,平均平均误差为 3.625,R 平方为 0.928。对于测试数据,RMSE 为 4.587,平均相对误差为 3.621,R 平方值为 0.928。对于线性回归模型,训练和测试数据的指标实际上是相同的,我们看到了相对于基线模型的显著改进。

随机森林回归量

对于训练数据,RMSE 为 1.240,平均平均误差为 0.878,R 平方为 0.995。对于测试数据,RMSE 为 3.453,平均相对误差为 2.419,R 平方值为 0.959。随机森林回归器的训练和测试数据的指标显示出比线性回归模型有所改进。

梯度推进回归器

对于训练数据,RMSE 为 3.671,平均平均误差为 2.804,R 平方为 0.953。对于测试数据,RMSE 是 3.984,平均相对误差是 3.007,R 平方值是 0.946。梯度推进回归器的训练和测试数据的度量也显示出相对于线性回归模型的改进,但是度量不如从随机森林回归器模型获得的度量好。

随机森林回归方程的超参数调整

随机森林回归器具有最低的误差数字,是我进行超参数调整的候选对象。我用来调优随机森林回归器的代码片段显示在单元格(1)中。

单元格(1)。使用 GridSearchCV 和 5 折交叉验证的超参数调整方法。

运行调优代码后,我使用最佳估计器来创建电力输出预测的最终模型。最终模型显示为单元格(2)。最终模型中未显示的调整阶段中包含的任何超参数都有默认值。

单元格(2)。网格搜索最佳超参数的随机森林回归模型

对于训练数据,RMSE 为 1.435,平均平均误差为 1.000,R 平方为 0.993。对于测试数据,RMSE 为 3.443,平均相对误差为 2.418,R 平方值为 0.960。超参数调整的随机森林回归模型的训练和测试数据的指标显示,与常规的未调整随机森林模型相比,有非常轻微的改进,并用作该项目的最终预测模型。

结果和可视化

表(1)显示了使用优化的随机森林回归器测试的所有模型的测试数据的指标,显示了所有方面的最佳数字。

表(1)显示了模型性能的最终结果

排列重要性

排列重要性告诉我们一个特性对模型的整体性能有多重要。图(8)中的条形图显示了用于构建模型的四个特征的重要性。

图(8)。与其他特征相比,环境温度具有不成比例的重要性。这表明环境温度对模型性能的影响最大。

如图所示,毫不奇怪,环境温度的变化对模型性能的影响最大,排气真空(V)对模型性能的影响仅次于环境温度,尽管其影响远远小于环境温度。相对湿度和环境压力对模型性能的影响几乎可以忽略不计。

部分相关性图(PDP)

接下来,我将展示一些部分依赖图,以可视化对模型输出影响最大的两个特性的具体效果。图表将显示环境温度和排气真空对功率输出的影响。

图(9)。环境温度的部分相关图。

图(9)中的曲线显示了环境温度的变化如何影响模型对目标变量的预测。随着温度的升高,我们看到总功率输出稳步下降,考虑到这两个变量之间的反比关系,这是有意义的。但具体来说,PDP 告诉我们,如果我们将环境温度从大约 2.5 摄氏度更改为大约 26.5 摄氏度,假设其他变量保持不变,我们应该预计预测的功率输出会下降大约 50 MW。超过 26.5 度。在数据集中标记最高温度点,输出不受干扰。

图(10)。排气真空的部分依赖图(V)

在图(10)中排气真空的情况下,PDP 显示,对于大约 20 cm Hg 和大约 42 cm Hg 之间的真空点,预测的功率输出不变。但是随着排气真空继续增加,预测的功率输出开始下降。具体来说,在大约 42.5 厘米汞柱和大约 68 厘米汞柱之间,预测的功率输出遭受大约 7.5 毫瓦的下降,如果我们将真空从 72 厘米汞柱增加到大约 80 厘米汞柱,模型预测输出将看到大约 0.5 毫瓦的边际增加。

图(11)。PDP 互动图表—输出对 V 和 AT 的部分依赖性。

图(11)中的 PDP 图表显示了预测输出对排气真空(V)和环境温度(AT)组合的部分依赖性。因此,网格中的任何点都代表模型仅基于 AT 和 V 的预测。我们注意到,与横轴(at)上的变化相比,纵轴(V)上的功率变化较小,这进一步表明模型的预测更依赖于环境温度而不是排气真空。

最高和最低温度的 SHAP 观测图

图(12)。观测到的最高温度的 SHAP 图。

图(12)中的 SHAP 图是测试数据集中最大观察温度下的模型功率输出预测。此时的环境温度(AT)为 35.2℃,排气真空(V)为 73.56 cmHg,大气温度(AP)为 1000.56 毫巴,相对湿度(RH)为 45.72%。该模型预测的功率输出为 434.36 MW,并且该图显示 at 和 V(蓝色)比 RH(红色)对较低结果的贡献更大,RH 对预测值的正面影响小得多。

图(13)。观测最低温度的 SHAP 图。

在温度谱的另一端,图(13)示出了 SHAP 曲线图,其中温度(At)为 2.58℃,排气(V)为 39.42 cmHg,压力(AP)为 1028.68 毫巴,相对湿度(RH)为 69.03%。由于 RH、V 和 AT 的积极影响,该点的预测功率输出为 489.81 MW。在上述两个图中,环境压力没有显示,因为其对预测的贡献可以忽略不计。

结论、局限性和展望

随着世界向更清洁、更可再生的能源过渡,CCPP 将继续在应对气候变化方面发挥关键作用;在这个关键的过渡时期,它可以作为燃煤发电厂的有价值的替代品,并随着更多零排放能源的出现,有助于减少对全球能源系统的冲击。

为了确保 CCPPs 持续高效运行,需要预测电厂的满负荷输出能力。做出这一预测是必要的,不仅是为了最大限度地提高效率,也是为了确保电厂的可持续性和可靠性,所有这些都有助于提高发电业务的底线。

在这项研究中,我能够应用机器学习算法建立一个模型来预测 CCPP 的满载功率输出。我测试的最佳模型是超参数调整的随机森林回归器,它给出了均方根误差和平均绝对误差的最低值。

为 CCPP 等能源生产系统建立预测模型的一个主要障碍是缺乏公开可用的数据,这是由于这些数据的专有性质。这项研究中设计的模型肯定会得到更多数据的增强,这些数据来自世界不同地区的不同植物,在更长的时间内收集。

对于目前没有使用机器学习作为预测工具的 CCPPs,我计划开发和部署一个 web 应用程序,它可以用作满负荷功率输出预测器,以提高运营效率。随着越来越多的发电厂被数字化,我预计将有更多的领域应用机器学习的力量,作为能源和相关行业的持续改进工具。

参考资料:

[1]:图费克奇,2014 年 9 月。“使用机器学习方法预测基本负荷运行的联合循环发电厂的满负荷电力输出”国际电力杂志&能源系统,第 60 卷,第 126-140 页,ISSN 0142-0615

使用随机搜索改善您的超参数调谐体验

原文:https://towardsdatascience.com/improve-your-hyperparameter-tuning-experience-with-the-random-search-2c05d789175f?source=collection_archive---------23-----------------------

学习通常比常规网格搜索更实用的超参数优化方法的内部工作原理

照片由 PexelsNicholas Githiri 拍摄

当开发一个机器学习分类器时,不存在哪个超参数将为您提供最佳性能模型的经验法则。出于这个原因,获得最佳超参数的一种非常常见的方法是尝试超参数的每种组合。

这种类型的超参数调整被称为网格搜索,它需要测试超参数的每一个组合,以找到为相关数据提供最佳模型的组合。

网格搜索是最广为人知的超参数优化形式,原因显而易见。

网格搜索不仅易于直观理解,而且保证为您的分类器获得理想的超参数。

也就是说,还有一种超参数优化技术没有得到足够的重视:随机搜索。

随机搜索

随机搜索与网格搜索非常相似。

然而,随机搜索只测试随机选择的一定数量的组合,而不是测试超参数的每个组合。

乍一看,随机搜索似乎没有吸引力。毕竟,如果你不能测试每一个超参数组合,你不太可能找到最好的一个。

然而,这种方法确实有一些好处。

首先,由于随机搜索测试更少的模型架构,所以它需要更少的时间和更少的计算来获得结果。

尽管随机搜索不一定能找到最佳的超参数集,但它可以提供在性能方面接近理想模型的模型。

随机搜索与网格搜索

如果您是数据科学项目的新手,您可能会坚持使用网格搜索。毕竟,多花一点时间有什么问题,如果这意味着你可以获得最好的模型?

在处理简单数据集时,这可能是一个合理的论点。然而,当您开始处理包含数百万条记录的数据时,测试每一个模型架构所需的时间和计算将是巨大的。

此外,如果您正在为客户构建一个模型,您将无法证明仅仅为了模型性能的轻微提高而分配这么多资源是合理的。

不幸的是,网格搜索很浪费;它不会从以前的模型中“学习”。

例如,如果您要通过从 1000 个不同的超参数组合中进行选择来构建一个分类器,那么您只对产生最佳性能指标的单个组合感兴趣。测试其他 999 种组合不会带来额外的好处。

随机搜索通过限制被测试的超参数组合的数量来解决这个问题。尽管这意味着该模型的性能指标可能没有理想模型的高,但这种差异可以忽略不计。

随机搜索可能不像纸上的网格搜索那样吸引人,但是在实践中,它们是获得期望的模型体系结构的更具成本效益的方式。

个案研究

让我们通过建立一个预测泰坦尼克号生存能力的模型来探索随机搜索方法(数据集可访问此处)。

资料组

代码输出(由作者创建)

在任何数据建模之前,需要为机器学习算法准备数据集。

数据预处理包括:

  • 移除不需要的功能
  • 删除缺少值的记录
  • 编码分类特征
  • 将数据分成训练集和测试集
  • 归一化整数特征

数据预处理

在使用随机搜索之前,我们将使用网格搜索作为一种参考形式来进行超参数调整。

sklearn 模块中的 GridSearchCV 对象允许我们使用每个期望的超参数组合对分类器执行网格搜索。

对于本案例研究,我们将重点关注使用最佳超参数构建随机森林分类器。将使用 f-1 评分标准对模型进行评估(即最佳模型的 f-1 评分最高)。

这里是将要测试的所有超参数,以及存储在字典中的分配给每个超参数的值。

超参数

如果你使用网格搜索方法,你将不得不用 5832 不同的超参数组合来构建随机森林分类器。

下面的代码显示了适合每个可能的模型架构的数据。每个模型都被赋予训练集的 f-1 分数。

GridSearchCV

GridSearchCV 提供了一些属性,有助于获得关于最佳性能模型的更多信息。这些属性包括:

  • best_estimator_:返回得分最高的估计值
  • best_params_:返回理想模型中的超参数值
  • best_score_:返回最佳模型的平均交叉验证分数

使用实现最高性能模型的最佳参数属性。

使用最佳参数

代码输出(由作者创建)

使用 best_score_ 找出最佳模型的平均 f1 分数。

使用最佳分数

代码输出(由作者创建)

理想模型的 f-1 分数为 0.831。

现在我们已经用网格搜索建立了一个模型,让我们用随机搜索做同样的事情,并比较一下它的效果。

sklearn 模块中的 RandomizedSearchCV 对象允许我们使用随机选取的一定数量的超参数组合对分类器进行随机搜索。

随机搜索

随机搜索的实现与常规网格搜索非常相似。但是,在分配的参数方面有一些关键的区别。

由于随机搜索并不测试每一个可用的组合,您可以通过为“n_iter”参数赋值来选择构建和评估的模型数量。这里,我们将值 500 分配给参数(即测试 500 个超参数组合)。

注意:该函数还允许您选择一个随机状态。这不是强制性的,但仍然鼓励这样做,以便您的结果是可重复的。

让我们看看随机搜索产生的最佳模型是什么样的。sklearn 模块为 RandomizedSearchCV 提供了与 GridSearchCV 相同的属性。

这里是用随机搜索建立的最佳模型的超参数。

使用最佳参数

代码输出(由作者创建)

现在让我们来看看使用这组超参数得到了什么样的 f-1 分数。

使用最佳分数

代码输出(由作者创建)

可以看出,随机搜索选择的超参数与网格搜索选择的超参数非常不同。因此,它登记的分数也较低。

但是 f-1 成绩的差距只有 0.013。此外,该结果是通过测试少于十分之一的用网格搜索测试的超参数组合获得的。

在使用 RandomizedSearchCV 找到最佳模型架构之后,您可以使用 best_estimator_ attribute 来使用测试集创建预测。

生成预测

代码输出(由作者创建)

总而言之,网格搜索比随机搜索稍微好一点。但是,为了这样一点点的性能提升,测试 10 倍以上的模型架构是合理的吗?

如果一个项目优先考虑限制成本和时间,那么随机搜索无疑是更好的选择。

结论

照片由 Unsplash 上的 Prateek Katyal 拍摄

总而言之,您对超参数调优技术的选择应该取决于您在模型成本和性能之间权衡的优先级。

网格搜索可以获得理想的模型体系结构,但是考虑到它所引起的成本,它不一定适用于许多现实生活场景。

另一方面,随机搜索提供了一种获得可靠模型(尽管不是最好的)的方法,同时节省了金钱和时间。

我祝你在机器学习的努力中好运!

使用 MLflow 改善您的机器学习渠道

原文:https://towardsdatascience.com/improve-your-machine-learning-pipeline-with-mlflow-6bdbb70fde36?source=collection_archive---------26-----------------------

一个让你的机器学习管道更有能见度的教程

亚历杭德罗·皮涅罗·阿梅里奥在 Unsplash 拍摄的照片

简介

机器学习管道是数据应用的重要组成部分。我们构建它是为了将原始数据转化为有洞察力的预测。管道包含许多步骤,如数据摄取、数据预处理、特征工程、模型拟合和性能评估。

当数据科学家开始开发 ML 管道时,他们试图快速构建整个管道,并通过改变一些超参数来重复该过程,以获得最佳结果。在这个过程中有许多超参数需要调整。

如果能 跟踪那些超参数 的变化就最好了。我们将对我们的 ML 用例有更深入的了解。例如,当我们更改特定的超参数时,我们可以看到准确性或 AUC 等性能指标是如何上升或下降的。

另一个好处是,我们可以 分析那些测井数据 并得出在特定区域开发模型的内部最佳实践。

例如,我们可以推导出随机森林深度的合适范围或神经网络层的数量,以在像倾向或流失模型这样的超参数调整过程中进行尝试。它有助于减少模型开发的大量时间消耗。

我们如何做到这一点?

这就是本文的目的。有几个有用的开源库支持机器学习管道的创建。今天我们将关注一个图书馆。

  • MLflow 是一个管理 ML 生命周期的开源平台,包括实验、可复制性、部署和中央模型注册。
  • 截至 2020 年 12 月 17 日,MLflow 在 GitHub 上接收 8K 颗星星。许多公司使用这个项目并为此做出贡献。
  • 我有机会使用集成了 MLflow 的 Databricks 平台。这是一次宝贵的经历,它教会了我记录/跟踪系统有多重要。

让我们看看如何利用它来改善我们的 ML 管道。

您可以从使用pip install mlflow安装 MLFlow 开始。然后,您可以通过在终端中键入一个mlflow ui命令行来启动 MLFlow 提供的跟踪用户界面。

如果你能看到下图,那么你就可以开始了。我在这里提供了一个在 GoogleColab 中使用它的例子。

ML 流量跟踪用户界面:作者图片

可以看到 MLflow 提供给用户的一个漂亮的追踪系统。我们这里还没有任何数据。所以让我们放点东西进去。

首先,您必须了解如何将 MLFlow 元素插入到代码中。

无论您的代码是什么模式,您都可以用上面的代码片段包装一切,让 MLflow 为您跟踪结果。结果将根据 MLflow 的安装位置存储在本地。

在数据块中,有一个专门的空间用于存储指标数据。

通过这简单的 3 行代码,您可以在 MLflow 中跟踪任何您想要的东西。MLFlow 将跟踪您在with条件下运行的任何东西,并通过跟踪系统显示出来,如下图所示。

没有 MLflow,可能需要自己做一个日志系统。 这减少了你的登录系统的设置时间帮助你更专注于机器学习代码。

使用 MLflow 可以记录很多东西,比如模型的混淆度量图、拟合模型本身、重要特性名称的 pickle 文件。我在 Databricks 平台上使用它时就是这么做的。

有了这个能力,MLflow 有什么好的用例?

通常,当我用第三方工具如hyperpt调整超参数 时,我总是使用 MLflow。超点是一个超参数调整使用贝叶斯方法,以找到一个更好的超参数集使用。

我们可以整合 MLflow 来记录每个远视试验,以查看合适的超参数范围。这减少了我过去达到可接受的模型性能所需的大量建模时间。

此外,它让您 更好地了解您的模型中的每个参数如何表现 。下一次,你可以直接去它应该去的地方,而不用浪费时间在超参数空间里进行网格/随机搜索。

让我向您展示如何使用 MLflow 和 hyperOpt 库。我们可以通过下面的代码片段创建一个远视。

通常,超点通过将超参数空间传递给目标函数来工作。然后计算出在试验次数内使目标函数最小的值。

上面的例子是为了最小化从fit_model函数返回的损失值。

根据上面的代码,hyperOpt 将从提供的space变量运行 100 次max_evals,并返回 hyper-parameter 的best组合。

每次运行中使用的所有模型、超参数和分数都将存储在 MLflow 目录中。您可以在完成超视跑步后访问最佳模式。这有助于确保您的机器学习模型在开发过程中的可重复性。

一旦你意识到模型开发过程中跟踪系统的好处。你将永远不会停止使用它。❤️

MLflow 有用的另一个方面是

第二个用例是,我一直在我部署的机器学习管道中使用它。MLflow 使我能够在拟合最新数据时跟踪新的重新拟合模型的性能。我们可以记录特性的重要性,并可视化随时间的变化。

每次运行时,所有拟合的模型都可以存储在 MLflow 工件存储中。我们可以回头参考当时的模型以获得再现性。它帮助您确保模型版本的有效性。

我通常用测试数据来模拟我的预测结果。例如,我从我的人群中随机抽取 A 边组,并将它们与我的预测的最高分进行比较。然后我测量了这两个群体中销售的产品的转化率。这是带有历史数据的 A/B 测试模拟,可以帮助您在现实世界中更舒适地使用您的预测。

所有的模拟结果都可以用 MLflow 记录和可视化。不需要数据科学家手动跟踪他们的模型结果。您可以使用 MLflow 实现自动化和可视化。

不仅是机器学习的相关内容,MLflow 也可以用于质量检查和测试过程。我曾经编写过将测试结果记录到 MLflow 的单元测试。代码运行后,我可以在同一个地方立即检查结果。

用 MLflow 养成良好的习惯

马丁·施瑞德Unsplash 上的照片

我曾经为临时工作做快速的机器学习模型开发。对我来说,跟踪开发过程中的所有度量和参数是一件痛苦的事情。有时候,我会报告重启 Jupyter 笔记本内核后无法重现的结果。这根本不是一个愉快的时刻。

幸运的是,正如我上面提到的,这些问题可以用 MLflow 来解决。如果你把它变成一种习惯,我相信你在机器学习管道中的开发时间和错误将会缩短。此外,当您使它自动化时,推广到其他上下文也变得简单了。

“最成功的男人工作聪明,不努力”
【哈比亚利马纳】、 【智慧明珠】

这是我认为对数据科学至关重要的技能。但在网络课程或互联网上并没有指出那么多。这就像是你在工作旅途中逐渐积累的最佳实践。它将成为您达到更高水平的工具箱,让您的数据科学生活更加成功。

此外,MLflow 提供了许多令人兴奋的特性,我在这里没有提到,比如模型部署和自动化日志记录。如果你想了解更多,请点击这里

帕泰鲁什·西达

如果你喜欢这篇文章,并希望看到更多这样的东西。

改进您的 MLflow 实验,跟踪历史指标

原文:https://towardsdatascience.com/improve-your-mlflow-experiment-keeping-track-of-historical-metrics-6e70a6c7b201?source=collection_archive---------21-----------------------

今天,我们将扩展我们的 SDK,增加交互跟踪运行指标的功能,我们将最终运行我们的 SDK

图片由萨汉德·巴巴里Unsplash 上拍摄

https://medium.com/@stefanobosisio1/membership

欢迎回到我们 MLflow 旅程的第二部分。今天,我们将扩展当前的 SDK 实现,增加两个功能来报告历史指标和自定义指标。然后,我们将最终看到 SDK 与一个简单的例子一起工作。下一次,我们将深入探讨 MLflow 插件,我们将为 GCP 人工智能平台创建一个“部署”插件

这是我关于 MLflow SDK 创建的第一篇文章:

目录

我们今天需要什么将实验的运行指标报告给最近一次运行
将自定义指标报告给一次运行
更新实验跟踪界面
创建您最终的 MLflow SDK 并安装它
SDK 运行!

我们今天需要什么

首先,让我们考虑主 SDK 协议的设计。今天的目标是让数据科学家能够:

  1. 将先前运行中计算的历史指标添加到给定的实验运行中
  2. 向特定运行添加自定义计算指标

因此,我们可以考虑实现以下两个功能:

  • 这个函数将从以前的实验运行中收集所有的指标,并将它们分组到一个交互式的图表中,这样用户可以立即发现问题并了解总体趋势
  • report_custom_metrics:该函数返回数据科学家的度量注释,向给定的实验发布一个字典。如果数据科学家希望坚持使用一些关于看不见的数据的指标进行特定的实验,这可能是有用的。

将实验的运行度量报告给最近的运行

该功能利用 MLflow Tracking 中的MLflowClient客户端管理实验及其运行。从MLflowClient中,我们可以检索给定实验的所有运行。从那里,我们可以提取每次运行的指标。一旦我们收集了所有的指标,我们就可以进行第二步,我们将使用plotly来制作一个交互式html图。这样,用户可以在 MLflow 服务器人工制品框中分析所有运行的每个数据点。

图 1 显示了report_metrics_to_experiment功能的第一部分。首先,用给定输入tracking_uri初始化MlflowClient。然后,用client.get_experiment_by_name检索实验的信息,并将其转换成一个字典。这里列出了每个实验的运行情况,runs_list。每次运行都有自己的run_id,它可以将度量信息存储在字典models_metrics中。此外,可以通过run.to_dictionary()['data']['metrics']访问指标。该值返回指标的名称。

图 1:函数 report_metrics_to_experiment 的第一部分。在这个片段中,我展示了如何从实验运行中检索指标的数据点。最终的指标值与运行 id、指标的步骤和值一起存储在一个字典中

根据指标的名称,可以通过client.get_metric_history()记录指标的数据点。该属性返回指标的步骤和值,因此我们可以添加到列表中并保存在models_metrics[single_run_id][metric] = [x_axis, y_axis]

图 2 显示了report_metrics_to_experiment的第二部分。首先,初始化一个新的plotly数字fig = go.Figure().,然后从models_metrics中读取指标并添加为散点图。最终的图形以html格式保存,以便进行交互式可视化。

图 2:功能报告的第二部分-度量-实验。这里,所有检索到的指标都显示在 plotly 图上,然后以 html 格式保存

向跑步者报告自定义指标

我们今天要实现的最后一个功能是报告特定运行的自定义输入。在这种情况下,数据科学家可能从运行的模型中获得一些带有看不见的数据的指标。该函数如图 3 所示。给定一个输入字典custom_metrics(例如{accuracy_on_datasetXYZ: 0.98}),该函数使用MlflowClientlog_metric来表示一个特定的run_id

图 3: report_custom_metrics 获取一个输入字典,其中包含看不见的度量或数据,它使用 log_metric 向 MLflow 运行报告键和 val。

更新实验跟踪界面

现在,两个新闻函数已经添加到主 MLflow 协议中,让我们将它们封装到我们的 [experiment_tracking_training.py](/scale-up-your-models-development-with-mlflow-4b78a5f22cb7#b9d2)中,特别是,end_training_job可以调用report_metrics_to_experiment,因此,在任何训练结束时,我们都可以跟踪给定实验的所有历史指标,如图 4 所示

图 4:可以在任何培训作业结束时调用 report_metrics_to_experiment,并将其添加到 end_training_job 功能中。

此外,为了允许用户向特定的运行添加他们自己的度量,我们可以考虑一个add_metrics_to_run函数,它接收实验跟踪参数、我们想要处理的run_id和自定义字典custom_metrics(图 5)作为输入:

图 5:可以通过 experiment _ tracking _ training . add _ metrics _ to _ run 模块报告自定义指标。

创建您的最终 MLflow SDK 并安装它

将所有部分修补在一起,SDK 包应该以类似的方式构建:

mlflow_sdk/
           mlflow_sdk/
                      __init__.py
                      ExperimentTrackingInterface.py
                      experiment_tracking_training.py
           requirements.txt
           setup.py
           README.md

requirements.txt包含了我们安装 SDK 所需的所有包,特别是默认情况下需要numpy, mlflow, pandas, matplotlib, scikit_learn, seaborn, plotly

setup.py允许在给定的 Python 环境中安装您自己的 MLflow SDK,脚本的结构应该是这样的:

图 6:在给定的 Python 环境中安装 mlflow_sdk 包的 Setup.py

要安装 SDK,只需使用 Python 或 virtualenv Python:python setup.py install

SDK 在行动!

是时候将我们的 MLflow SDK 付诸行动了。我们将用一个sklearn.ensemble.RandomForestClassifier虹膜数据集 ⁴ ⁵ ( 来源和许可开放数据共享公共领域专用和许可)来测试它。图 7 显示了我们将要使用的完整示例脚本(我的脚本名是1_iris_random_forest.py)

tracking_params包含设置 MLflow 服务器的所有相关信息,以及运行和实验名称。加载数据集后,我们将使用sklearn.model_selection.train_test_split创建一个列车测试分割。为了在 MLflow 工件中显示不同的度量和图表,我运行了1_iris_random_forest.py 5 次,用以下值改变test_size:0.3, 0.2, 0.1, 0.05, 0.01

图 7:在这个例子中,我们将对 iris 数据集运行一个随机森林。MLflow SDK 将在训练期间跟踪模型信息,并使用 add_metrics_to_run 报告所有附加指标。

一旦数据已经设置好,clf=RandomForestClassifier(n_estimators=2)我们就可以调用experiment_tracking_training.start_training_job。该模块将与 MLflow 上下文管理器交互,并向 MLflow 服务器报告运行模型的脚本以及模型的信息和工件。

在培训结束时,我们希望在一个图中报告所有实验运行的指标,并且,仅仅为了测试,我们还将保存一些“假”指标,如false_metrics = {"test_metric1":0.98, ... }

在新的终端选项卡中运行1_iris_random_forest.py之前,打开与 MLflow 服务器的连接,如mlflow ui所示,并导航至http://localhost:5000http://127.0.0.1:5000。然后,按照python 1_iris_random_forest.py运行上述示例,并针对test_size的不同值重复运行 5 次

图 8:运行示例脚本后的 MLflow UI

图 8 应该类似于运行示例脚本后的结果。在Experiments下面列出了实验的名称。每个实验都有一系列的跑步,特别是在random_forest下,你会找到来自1_iris_random_forest.py的随机森林跑步

对于每次运行,我们可以立即看到一些参数,这些参数由mlflow.sklearn.autolog()自动记录,以及我们的假指标(例如test_metric1)自动记录功能也保存Tags,报告估计器类(例如sklearn.ensemble._forest.RandomForestClassifier)和方法(RandomForestClassifier)。

单击单次运行,将显示更多详细信息。首先,您将看到所有的模型参数,这些参数也是由 autolog 功能自动报告的。向下滚动页面,我们可以访问指标图。在这种情况下,我们只有一个数据点,但对于更复杂的模型,您可以有一个完整的图,作为步骤数的函数。

图 MLflow SDK 保存的工件。在 artifacts 框中,您可以找到用于运行模型的代码(在我的例子中是 1_iris_random_forest.py ),以及 model 文件夹下的模型 pickle 文件和所有交互式度量图以及混淆矩阵。

然后,最重要的信息将存储在工件箱下(图 9)。在这里,您可以找到由我们的mlflow_sdk:创建的不同文件夹

  • 首先,code是一个文件夹,它存储了用于运行我们的模型的脚本——这是在第 24 行的experiment_tracking_training中用traceback这里是链接完成的,并被推送到第 31 行的run_training函数的 MLflow artefacts、这里是链接
  • 接下来,model存储二进制 pickle 文件。MLflow 自动保存模型文件及其要求,以允许结果的再现性。这在部署时非常有用。
  • 最后,你会看到所有的互动情节。(*.html),在培训结束时生成,以及我们在培训期间计算的其他指标,如training_confusion_matrix.png

如您所见,我们以最少的干预为 ML 模型添加了完整的跟踪路线。实验在开发阶段至关重要,通过这种方式,数据科学家可以轻松使用 MLflow 跟踪功能,而无需过度修改他们现有的代码。从这里,您可以探索报告的不同“色调”,为每次运行添加进一步的信息,以及在专用服务器上运行 MLflow 以允许跨团队协作。

罗纳德·费希尔《分类问题中多重测量的使用》优生学年鉴7.2(1936):179–188。

爱德华·戴明。“对数理统计的贡献。拉。纽约:威利;伦敦:查普曼&霍尔出版社,1950 年。655 页“科学113.2930(1951):216–217。

R. O .杜达和 P. E .哈特。“模式分类和场景分析。(Q327。D83)约翰·威利父子公司。”(1973): 218.

⁴·达萨拉西,贝鲁尔 v 在邻居周围搜寻:在部分暴露环境中识别的新系统结构和分类规则〉 IEEE 模式分析和机器智能汇刊1(1980):67–71。

⁵·盖茨,杰佛瑞。“简化的最近邻规则(corresp。)."IEEE 信息论汇刊 18.3(1972):431–433。

今天就到这里吧!希望您喜欢这两篇关于 MLflow 及其 SDK 开发的文章。下一次,我们将深入 MLflow 插件世界,从理论上讲,这也可以引导您的团队进入部署阶段。

如果你有任何问题或好奇,请给我发电子邮件到 stefanobosisio1@gmail.com

使用自动编码器提高模型性能

原文:https://towardsdatascience.com/improve-your-model-performance-with-auto-encoders-d4ee543b4154?source=collection_archive---------6-----------------------

使用自动编码器作为特征提取器

图片由 ar130405 来自 Pixabay

除非您评估模型的性能,否则您永远不知道模型的性能如何。数据科学家的目标是开发一个健壮的数据科学模型。模型的健壮性是通过计算它在验证和测试指标上的表现来决定的。如果模型在验证和测试数据上表现良好,则它在生产推断期间往往表现良好。

有各种各样的技术或技巧来提高模型的性能。正确的特征工程策略有助于提高模型的性能。在本文中,我们将讨论并实现使用自动编码器的特征提取。

什么是自动编码器?

自动编码器是一种无监督的神经网络,它从输入的未标记数据中学习有效的编码。自动编码器试图通过最小化重建损失来重建输入数据。

标准自动编码器架构具有编码器和解码器层:

  • 编码器:从输入空间到低维空间的映射
  • 解码器:从低维空间重构到输出空间

(来源),自动编码器架构

跟随我以前的文章来了解自动编码器的应用或用法

</6-applications-of-auto-encoders-every-data-scientist-should-know-dc703cbc892b>

想法:

自动编码器将输入数据(X)编码成另一维度(Z),然后使用解码器网络重构输出数据(X’)。与输入层相比,编码嵌入优选地在维度上较低,并且包含输入层的所有有效编码。

想法是通过在训练样本上训练自动编码器来学习编码器层权重。通过在训练样本上训练自动编码器,它将试图最小化重构误差并生成编码器和解码器网络权重。

稍后,解码器网络可以被裁剪掉,并且可以使用编码器网络来生成特征提取嵌入。这种嵌入可用于监督任务。

现在,让我们深入研究上面讨论的思想的一步一步的实现。

第 1 步—数据:

我使用的样本数据集是使用 make_classification 函数生成的,包含 10k 个实例和 500 个特征。将数据集分成训练、验证和测试样本,以避免数据泄漏。此外,标准化数据样本。

步骤 2 —定义自动编码器:

我已经在自动编码器架构中定义了两层编码器和两层解码器网络。每个编码器和解码器层都有一个批量标准化层。

编码层的尺寸需要通过实验来决定。

步骤 3 —自动编码器培训:

使用 Keras 和 adam optimizer 编译并运行自动编码器架构,并使用均方误差损失来重构输入数据。

我将运行流水线 50 个时期,批处理大小为 64。

步骤 4——绘制重建误差:

将训练和测试重建损失的变化可视化。

(作者提供图片),用纪元训练和验证 MSE

步骤 5 —定义编码器并保存权重:

一旦自动编码器、权重被优化,我们可以裁剪解码器网络,并且仅使用编码器网络来计算输入数据的嵌入。这些嵌入可以进一步用作监督机器学习任务的特征。

第 6 步—训练受监督的任务:

来自解码器网络的嵌入可以用作分类或回归任务的特征。

基准测试:

现在,让我们通过将原始输入要素更改为编码要素来比较模型的性能。我们将用两个模型的默认超参数训练一个逻辑回归估计量。

(图片由作者提供),性能指标评测

第一列提到了具有 500 个特征的原始输入数据的度量性能。对于使用自动编码器的编码器网络的编码特征,我们观察到性能指标的改进。

结论:

使用自动编码器的特征提取捕获输入数据的有效编码,并将其投影到相同或更低的维度。对于具有大量输入要素的输入数据,最好将数据投影到较低的维度中,并将这些要素用于监督学习任务。

另外,请阅读我以前的一些文章来提高模型性能:

https://medium.com/geekculture/essential-guide-to-improve-imbalanced-data-classification-model-performance-c8cf0125b731

参考资料:

[1]https://machine learning mastery . com/auto encoder-for-class ification/

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。

https://satyam-kumar.medium.com/membership

感谢您的阅读

通过贝叶斯优化超参数调整提高模型性能

原文:https://towardsdatascience.com/improve-your-model-performance-with-bayesian-optimization-hyperparameter-tuning-4dbd7fe25b62?source=collection_archive---------19-----------------------

实践教程

照片由丹尼斯·莱昂Unsplash 上拍摄

介绍

“我为什么要看这篇文章?”

如果你已经开始在你的项目中使用 ML,或者只是为了好玩,你可能已经意识到调整你的模型的任务是多么的具有挑战性,尤其是它是非常耗时的。如果你不是一个专业的 ML 从业者,对应该使用哪些超参数做出有根据的猜测将是一个挑战。此外,您正在使用的算法可能对超参数选择非常敏感,因此测试更多的实现是有用的。在本文中,我将根据经验展示贝叶斯优化对于超参数调优的强大功能,并将其与更常见的技术进行比较。

背景

“超参数调优快速回顾”

在 ML 领域,评估几组超参数的最已知技术是网格搜索随机搜索。下面是它们工作原理的形象化展示:

作者图片,灵感来自随机搜索超参数优化 (James Bergstra,Yoshua Bengio)

x 轴和 y 轴代表两个假设超参数的取值范围,在左图中,您可以看到算法尝试预定义的参数组合(GridSearch),而在右图中,超参数是从一个范围内随机选择的(RandomSearch)。

在图中,您还可以看到,对于每个超参数,都有一个函数来定义超参数本身与其对模型性能的贡献之间的关系。你的目标是优化函数以找到最大值。然而,超参数越多,就越难找到最佳点。

然而,这个例子不是很现实,因为 ML 算法可能有一个长的可以调整的超参数列表,并且可能组合的数量可能变成无法估计。我们的目标确实是试图找到性能最好的型号,同时尝试最少的组合

贝叶斯优化

“让超参数搜索更加数据驱动”

网格搜索和随机搜索并不是仅有的两种进行超参数调整的技术。我确实想展示另一个可以用来实现这个目标的方法,那就是贝叶斯优化

我不会深究算法是如何工作的,我将只限于给出一个大概的概述。由此,您可以找到算法所采取的步骤:

  • 通过对超参数随机值进行采样来启动
  • 观察生成的输出(模型性能)。
  • 基于这些观察,它符合高斯过程。
  • 它使用这个 G 高斯过程均值作为未知的函数近似值
  • 为了理解哪个超参数应该在下一个被采样,它使用采集函数(我们可以将其视为采样策略)。采集功能还定义了算法应该探索超参数空间或利用已知区域的程度。
  • 再次安装模型并观察输出并在相同过程中重复直到达到最大迭代次数。

通过阅读以上几点,你应该已经明白为什么这个方法在理论上比我在上一段提到的方法更好。该方法使用来自上一次运行的信息通知下一次运行。这是一个非常强大的工具,因为它允许我们在整个过程中缩小超参数搜索的范围,以主要关注超参数范围中非常有利可图的领域。

更一般地说,每当你需要优化一个黑盒函数时,可以使用贝叶斯优化。这意味着您可以使用这种方法来搜索任何函数的全局最优解,而您只能观察该函数的输入和输出。

为了使用贝叶斯优化进行超参数调整,我使用了模块' scikit-optimize ,我发现它非常直观和用户友好。在他们的文档中没有很多例子,但是你需要做的就是实现它。

实验设置

“不错的理论,但它在实践中意味着什么?”

在这个实验中,我们将比较 GridSearch、RandomSearch 和 Bayesian 优化超参数调优的结果。我使用的数据是加州住房数据集,其目标是预测中值房价。为了达到这个结果,我使用了 GBM 算法

值得一提的是,这个练习旨在比较超参数算法和而非 以获得最佳模型,因此我不对数据进行任何转换。我正在做一个被蒙住眼睛的插件和游戏,这当然是不建议在现实世界中做的(总是吃你的胡萝卜和看数据)。

为了解决模型性能问题,我使用了 MAE 指标K 倍交叉验证

在每个模型之后,我绘制每次迭代的超参数以及跨越 K 倍的平均负 MAE 度量(我所绘制的实际上是跨越迭代的负 MAE 和最高负 MAE 之间的差异)。我这样做是为了更清楚地了解超参数对模型性能的影响。

我选择优化的超参数是:

  • 最大深度
  • 最小样本分割
  • 学习率
  • 子样品
  • 最大 _ 特征
  • n _ 估计量

实验

“我们来看一些剧情”

在下面的代码块中,我将导入必要的模块,并生成一些函数来可视化结果。

import pandas as pd
import numpy as np
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV, train_test_split
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
from scipy.stats import randint, uniform
import seaborn as sns
import matplotlib.pyplot as pltdef parameter_over_iterations(model_result):
  '''
  This function is generating a subplots with the hyperparameter values for each iteration and the overall performance score.
  The performance score is the difference between the best performing model and the worst performing model

  model_result: CV object
  '''
  param_list = list(model_result.cv_results_['params'][0].keys())
  max_col_plot = 2
  row_plot =int(np.ceil((len(param_list) + 1)/max_col_plot))
  fig, axs = plt.subplots(nrows=row_plot, ncols=np.min((max_col_plot, (len(param_list) + 1))), figsize=(30,12))
  for i, ax in enumerate(axs.flatten()):
    if i == len(param_list):
      break
    par = param_list[i]
    param_val = list()
    for par_dict in model_result.cv_results_['params']:
      param_val.append(par_dict[par])
    sns.barplot(y=param_val, x=np.arange(len(param_val)), ax=ax)
    ax.set_title(par)
  dt = pd.DataFrame({key:val for key,  val in model_result.cv_results_.items() if key.startswith('split')})
  mean_metric = dt.mean(axis=1)
  sns.barplot(y=(mean_metric.values + abs(np.min(mean_metric.values))), x=np.arange(len(mean_metric) ), ax=axs.flatten()[i])
  axs.flatten()[i].set_title('overall metric')

网格搜索

在本节中,我们将看到使用 GridSearch 选择最佳超参数的结果。

param_test = {'max_depth':range(5,15,5), 'min_samples_split':range(200,800,300), 'learning_rate': np.arange(0.05,0.55,0.25), 'subsample': np.arange(0.4,1,0.4),
              'max_features': np.arange(0.4,1,0.3), 'n_estimators': np.arange(40,160,60)}gsearch = GridSearchCV(estimator = GradientBoostingRegressor(random_state=10), 
param_grid = param_test, scoring='neg_mean_absolute_error',n_jobs=4,iid=False, cv=5)
gsearch.fit(X_train,y_train)parameter_over_iterations(gsearch)

在上图中,我们可以看到每个超参数选择的模型性能。在前 6 个子图中,我绘制了在每个特定迭代中使用的超参数值(迭代总数为 64)。

最后一个图(在左下方)是性能图,对该图的解释是,越高,越好,模型的性能就越好。

从上面的图中,我们可以清楚地看到两件事:学习率为 0.3 会对模型性能产生积极影响(您可以看到图右侧的值更高),估计器的数量越多,性能也越好(在图的开始,您可以看到当估计器的数量较高时,峰值最高)

总之,通过这次搜索,我发现最佳超参数组合是

  • 学习率:0.3
  • 最大深度:5
  • 最大特征数:0.4
  • 最小样本数:500
  • n _ 估计值:100
  • 子样本:0.8

这导致了一场 35212.30 的 MAE。

随机搜索

RandomSearch 应该比 GridSearch 产生更好的结果,即使它通常不能达到未知函数的全局最优。

param_distrib = {'max_depth':randint(5,15), 'min_samples_split':randint(200,800), 'learning_rate': uniform(loc=0.05, scale=0.50), 'subsample': uniform(loc=0.4, scale=0.6),
              'max_features': uniform(loc=0.4, scale=0.6), 'n_estimators': randint(40,160)}rsearch = RandomizedSearchCV(estimator = GradientBoostingRegressor(random_state=10), 
param_distributions = param_distrib, scoring='neg_mean_absolute_error',n_jobs=4, n_iter=64,iid=False, cv=5)
rsearch.fit(X_train,y_train)parameter_over_iterations(rsearch)

事实上,随机搜索方法导致了更好的超参数选择,导致 MAE 为 33942

选定的超参数有:

  • 学习率:0.23
  • 最大深度:5
  • 最大 _ 特征:0.88
  • 最小样本数:337
  • n _ 估计值:125
  • 子样本:0.75

贝叶斯优化

现在是测试贝叶斯优化算法来调整模型的时候了。

正如您在下面的脚本中看到的,除了我为每个超参数指定值范围的字典之外,我还指定了一些将影响贝叶斯算法行为的值。我为获取函数指定了一些参数(xi 和卡帕)。这两个参数控制了采集函数在多大程度上倾向于探索到开发。较高的 xi 和卡帕值意味着更多的探索,而较低的值意味着更多的开发。

关于这个主题的更多信息可以在这里找到:https://sci kit-optimize . github . io/stable/auto _ examples/exploration-vs-exploitation . html?highlight=kappa

from skopt import BayesSearchCV
from skopt.space import Real, Integeroptimizer_kwargs = {'acq_func_kwargs':{"xi": 10, "kappa": 10}}space  = {'max_depth':Integer(5, 15),
          'learning_rate':Real(0.05, 0.55, "uniform"),
          'min_samples_split':Integer(200, 800),
          'subsample': Real(0.4, 1, "uniform"),
          'max_features': Real(0.4, 1, "uniform"),
          'n_estimators': Integer(40, 160)}bsearch = BayesSearchCV(estimator = GradientBoostingRegressor(random_state=10), 
search_spaces = space, scoring='neg_mean_absolute_error',n_jobs=4, n_iter=64,iid=False, cv=5, optimizer_kwargs=optimizer_kwargs)
bsearch.fit(X_train,y_train)parameter_over_iterations(bsearch)

如果我们在迭代中观察超参数,我们确实看到,对于某些参数,随着时间的推移,这些值趋向于变得更加稳定。这表明算法正在向最优值收敛。然而,对于相当多的迭代来说,该算法似乎在某些局部最优上停滞不前(这表明更多的探索将对该算法有益)。事实上,如果我们查看学习率,我们会发现在迭代 10 和迭代 53 之间,该值几乎没有变化,但学习率为 0.19 时会获得最佳结果。

看起来这种方法将受益于更多的迭代,然而,这种方法能够找到一组可能导致 32902 的 MAE 的超参数。

  • 学习率:0.19
  • 最大深度:7
  • max_features: 0.73
  • 最小样本数:548
  • n _ 估计数:134
  • 子样本:0.86

结论

“贝叶斯优化值得吗?”

在这个简短的(肯定不是详尽的)例子中,我们可以清楚地看到 GridSearch 肯定是探索超参数空间最差的方法,而 RandomSearch 和贝叶斯优化都表现良好。然而,特别是当超参数的数量很高时,随机搜索可能不会提供最好的结果,而潜在的贝叶斯优化会提供最好的结果,因为它基于观察到的性能通知未来的超参数选择。此外,贝叶斯优化应该花费较少的迭代来达到全局最优,而随机搜索可能需要大量的迭代才能达到。

通过 Pod 就绪关口提高应用程序可用性

原文:https://towardsdatascience.com/improving-application-availability-with-pod-readiness-gates-4ebebc3fb28a?source=collection_archive---------39-----------------------

当 Pod 就绪和活性探测不够好时,您能做什么?

Kelly SikkemaUnsplash 上拍摄的照片

使用 Pod 活跃度和就绪度探测器,确保您在 Kubernetes 上运行的应用程序可用并准备好服务流量是非常容易的。但是,并不是所有应用程序都能够使用探测器,或者在某些情况下需要更复杂的就绪检查,而这些探测器根本无法执行这些检查。然而,如果 Pod 探针不够好,还有其他解决方案吗?

准备关卡

答案很明显,是。借助就绪门,可以为 Kubernetes Pods 执行复杂的定制就绪检查。

就绪门允许我们创建类似于PodScheduledInitialized的自定义状态条件类型。然后,这些条件可用于评估 Pod 准备情况。

通常情况下,箱准备状态仅由箱中所有容器的准备状态决定,这意味着如果所有容器都是Ready,那么整体也是Ready。如果准备状态门被添加到一个箱,那么一个箱的准备状态由所有集装箱的准备状态和所有准备状态门条件的状态决定。

让我们看一个例子,以便更好地理解这是如何工作的:

上面的清单显示了一个名为www.example.com/some-gate-1的有单一准备门的分离舱。查看 status 节中的条件,我们可以看到ContainersReady条件是True,这意味着所有容器都准备好了,但是定制就绪门条件是False,因此 Pod 的Ready条件也必须是False

如果您在这样的 pod 上使用kubectl describe pod ...,您还会在条件部分看到以下内容:

基本原理

我们现在知道实现这些额外的就绪条件是可能的,但是它们真的有必要吗?难道仅仅利用探针进行健康检查还不够吗?

在大多数情况下,探测应该足够了,但是也有需要进行更复杂的准备状态检查的情况。准备就绪关口最常见的用例可能是与外部系统同步,例如云提供商的负载平衡器。例如 GKE 的 AWS 负载平衡器容器本地负载平衡。在这些情况下,就绪门允许我们让工作负载网络感知。

使用准备状态门的另一个原因是,如果您有外部系统,可以使用应用程序指标对您的工作负载执行更彻底的健康检查。这有助于将您的系统集成到 Kubernetes 的工作负载生命周期中,而不需要对 kubelet 进行更改。它还允许外部系统订阅 Pod 条件变化并对其采取行动,可能应用变化来补救任何可用性问题。

最后,如果您有部署到 Kubernetes 的遗留应用程序,而该应用程序与活性或就绪性探测不兼容,那么就绪性检查可以是一个救命稻草,但是它的就绪性可以通过不同的方式来检查。

要了解该特性的完整原理,请查看 GitHub 中的原始 KEP。

创建第一个门

说够了,让我们创建我们的第一个就绪门。我们所需要做的就是在 Pod spec中添加readinessGates节,其中包含我们想要的条件的名称:

添加门很容易,但是更新稍微复杂一点。kubectl子命令不支持对象状态的修补,因此我们无法使用kubectl patch将条件设置为True / False。相反,我们必须使用直接发送到 API 服务器的PATCH HTTP 请求。

访问集群 API 服务器最简单的方法是使用kubectl proxy,它允许我们在localhost上访问服务器:

除了在后台启动代理之外,我们还使用curl来检查服务器是否可达,并向服务器查询我们将要更新的 pod 的清单/状态。

既然我们有了到达 API 服务器的方法,让我们尝试更新 Pod 状态。每个就绪门状态条件默认为False,但让我们从显式设置它开始:

在这个代码片段中,我们首先使用针对 API 代理服务器的PATCH请求,将 JSON 补丁应用到 Pod 的status.condition字段。在这种情况下,我们使用了add操作,因为状态尚未设置。此外,您还可以看到,当我们列出带有-o wide的 pod 时,READINESS GATES列显示0/1,表明闸门设置为False。在kubectl describe的输出中也可以看到同样的情况。

接下来,让我们看看如何将值切换到True:

与前面的代码片段类似,我们再次使用PATCH请求来更新条件,但是这一次我们使用了replace操作,特别是在由/status/conditions/0指定的列表中的第一个条件上。但是请注意,自定义条件不一定要在列表中排在第一位,所以如果您将使用一些脚本来更新条件,那么您应该首先检查您应该更新哪个条件。

使用客户端库

像我们上面看到的用curl更新条件适用于简单的脚本或快速手动更新,但是通常你可能需要更健壮的解决方案。考虑到kubectl在这里不是一个选项,您的最佳选择将是 Kubernetes 客户端库之一。出于演示目的,让我们看看如何在 Python 中实现:

我们需要做的第一件事是向群集进行身份认证并创建 Pod。在这种情况下,使用从~/.kube/config加载您的凭证的config.load_kube_config()来完成身份验证部分,一般来说,虽然使用服务帐户和令牌来对集群进行身份验证更好,但是可以在文档中找到相关示例。

至于第二部分——Pod 创建——这相当简单,我们只需应用 Pod 清单,然后等待,直到它的状态阶段从Pending开始发生变化。

在 Pod 运行的情况下,我们可以通过将其状态设置为初始值False来继续:

除了设置状态,我们还在更新后查询集群的当前 Pod 状态。我们查找对应于Ready条件的部分并打印其状态。

最后,我们可以用下面的代码将值翻转到True:

这里的代码与前面的例子非常相似,但是这一次我们寻找类型为www.example.com/gate-1的条件,我们用print验证它的当前状态,然后使用replace操作将更改应用到在index列出的条件。

结束语

上面的 shell 脚本和 Python 代码都演示了如何实现就绪门及其更新。但是在实际应用中,您可能需要一个更健壮的解决方案。

这种情况的理想解决方案是定制控制器,它可以监视 pod,将readinessGate节设置为相关的conditionType节。然后,控制器将能够根据观察到的 pod 状态更新条件,无论是基于定制 pod 指标、外部网络状态还是其他。

如果您正在考虑实现这样的控制器,那么您可以从现有的解决方案中获得一些灵感,比如前面提到的 AWS 和 GKE 负载平衡器或者(现在已存档的)[kube-conditioner](https://github.com/itaysk/kube-conditioner)

本文最初发布于martinheinz . dev

https://itnext.io/hardening-docker-and-kubernetes-with-seccomp-a88b1b4e2111

使用数据改善家务劳动

原文:https://towardsdatascience.com/improving-chores-using-data-d972e5f24475?source=collection_archive---------24-----------------------

野外的数据科学

对付多动症的方法

我们先说,我不记得有什么事情做得这么好。我记得我感兴趣的事情,但我患有多动症,这意味着我在追逐多巴胺。这些年来,我已经能够欺骗我的大脑来提高我做不有趣的任务或杂务的能力,但它一直具有挑战性。

在压力很大的情况下,我会用音乐来保持精力充沛的状态,但是我必须持续保持活跃才能很好地工作。在某些时候也有一个崩溃期。对于搬到一个新的地方,这是一个有用的工具。

通常,列表是最有帮助的。大约六个月前,我创建了一个包含三列的表格:{任务、询问日期、完成日期}。目的是帮助了解哪些事情是重要的,以及我完成工作的效率如何。我可以看看这个清单,找到我能完成的事情。

所有图片由作者提供

数据分析

几个月后,我决定做一些分析,看看我在完成任务方面是否有所进步。数据中唯一的问题是,通过观察和记录这类数据,影响了我的行为。

我开始按月查看一些指标:

最大的改进是当天完成。我最终完成了 90%我想完成的事情。完成任务的平均时间普遍下降,这可能与一些长期任务有关。

我也按周查看了这些数据

利用这些数据,我做了一个散点图来寻找任何趋势。但是,似乎并没有大的趋势。

我们可以从整体上看这些数据,以了解任务完成的速度。似乎我能够在一周内完成 70%的任务,在两周内完成 80%多一点的任务。然后是长尾,这主要是由于新任务的优先级推低了旧任务。

星期几呢?对我来说,周二似乎是最不适合完成任务的一天,但是周六承担了很多完成任务的负担。

完成时间可能看起来有点长,但是如果有一个稳定的任务完成流,那么单个任务的持续时间是由优先级的重新调整驱动的。看看每周的要求和完成的任务,每周都有稳定的任务流被完成。

每次我觉得数据没什么用的时候,它似乎成了过更好生活的绝佳解决方案。有时候,没有目标是很难完成任务的,但这个列表绝对给了我一个目标和一个指定的目标。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以在 Medium 或者 Patreon 上关注我。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页

数据科学:基础知识

数据展示要领

生活色彩数据

如何轻松进入数据科学领域

数据科学家的一天

机器学习中的隐私:PII

收集爱好数据集:咖啡

使用自适应滤波器的车道识别

用规划图提高经典人工智能规划的复杂性

原文:https://towardsdatascience.com/improving-classical-ai-planning-complexity-with-planning-graph-c63d47f87018?source=collection_archive---------23-----------------------

使用一个新的搜索空间,规划图,以提高表现力和复杂性的问题,发现在经典的规划方法。

规划图(图片由作者提供)

介绍

人工智能规划的经典方法使用状态空间计划空间来搜索解决方案以解决规划问题。在状态空间搜索中,通过应用适当的动作,初始世界状态经历几次变换,直到找到解决方案以达到目标,或者搜索算法终止并返回失败。我们可以使用 BFS、DFS、Dijkstra、A*等搜索算法。

状态空间(作者图片)

由此产生的解决方案是一系列动作,当应用时,通过一个或多个步骤将初始世界状态转换为目标状态。

国家空间计划(图片由作者提供)

另一个搜索空间是计划空间,我们将计划作为我们的节点,并尝试以 开放(未解决)目标威胁 的形式解决 缺陷

平面空间规划(作者图片)

这种方法本身相当复杂,我们不打算在这里讨论细节,如果你有兴趣了解更多,你可以阅读这篇文章:

https://medium.com/swlh/plan-space-search-2d877b4ab231

改善空间的大小

在《自动化规划:理论与实践》一书中,Malik、Dana 和 Paolo 提到传统方法的研究由于表达性和复杂性的原因而停滞不前,规划图——一种新的搜索空间,允许搜索空间大小的改进,从而为解决更复杂的规划问题开辟了一条道路。

我们将在下面的章节中探讨细节,以理解它如何改进传统规划方法中发现的问题。

码头工人机器人规划领域

对于我们的例子,我们将使用简化的码头工人机器人(DWR)领域和问题,经常在人工智能规划教程中使用。

简单码头工人机器人领域(图片由作者提供)

在这个领域中,我们有两个机器人 robrrobq ,两个容器 contacontb ,以及两个位置 loc1loc2

有三种可能的操作:

  • 装载(位置、容器、机器人):将容器装载到机器人上
  • 移动(位置,位置):从一个位置移动到另一个位置
  • 卸载(位置、容器、机器人):从机器人上卸载容器

动作的 前置条件效果 的细节可以在下面的 pddl 文件中看到。

我们还有五个谓词来表示状态:

  • 相邻(位置 1,位置 2) —这是关于位置的静态信息
  • atl(机器人,位置) —描述机器人的位置
  • 已装载(机器人,集装箱) —机器人是否已装载,哪个集装箱在机器人上
  • 卸载(机器人) —机器人卸载
  • 在(集装箱,位置) —描述集装箱的位置

我们用 PDDL (规划领域定义语言)来表示我们的规划领域和规划问题。下面是我们感兴趣的领域的 pddl 文件。

现在让我们开始深入研究规划图及其规划器。

规划图

规划图基于可达性分析的思想,可达性分析是一种计算一组状态是否可以从一组初始状态到达的过程。

让我们通过一个例子来逐步理解这个概念。首先,这是我们的初始状态:

初始状态(图片由作者提供)

我们使用谓词来表示我们的世界状态(为了简单起见,我们省略了相邻的谓词):

  • in(conta,loca 1)
  • in(contb,loc2)
  • atl(机器人,位置 1)
  • atl(robq,loc2)
  • 空载(机器人)
  • 空载(robq)

我们想知道这个状态是否可以达到:

目标状态(图片由作者提供)

我们没有在图片中展示机器人,因为我们不关心它们的位置,我们只对集装箱的位置感兴趣。我们用这种方式表示它:

  • in(contb,loc1)
  • in(conta,loc2)

可达性树

现在,最简单的方法是使用可达性树。我们从初始状态(根节点)开始,搜索状态(边)的适用动作,然后我们生成预测状态(子节点),我们对所有子节点重复该过程,直到达到指定的 深度

这是深度=1 的可达性树。

可达性树-深度=1(作者图片)

并且,这是深度=2 的可达性树。

可达性树-深度=2(作者图片)

我们可以看到,这并没有很好地扩展,当我们增加深度时,节点的数量会激增。此外,我们还没有在这个深度找到目标,我们需要进一步扩展它。

可达性图

我相信你会这样想,我们可以用图来改善它,因为有些节点确实是重复的。这是深度=2 的图形版本。

可达图—深度=2(作者图片)

它略有改进,但要达到我们的目标(红色节点),我们需要深度=6,如下所示:

可达图—深度=6(作者图片)

很吓人吧?规模确实很大,因为当我们增加深度时,复杂程度会增加,如果我们想解决更复杂的问题,这在某些时候变得不切实际。

规划图的可达性

规划图的概念是带有松弛的的可达性图。在每个深度(也称为 )它不使用单个状态,而是使用状态的联合,因此我们可以认为每个级别只有一个节点。

与我们通过应用可应用的动作来生成节点的可达图不同,所有的动作都用来生成状态的联合

规划图(图片由作者提供)

另一个区别是,在可达图中,一个状态是一组一致命题,但在规划图中,它不是。例如在图中的前提条件 1 中, robr 的位置可以同时在 loc1loc2 中。

类似地,这些动作并不总是兼容,它们可能会抵消彼此的影响。

在规划图中,为了跟踪这些不一致的命题不兼容的动作,我们使用了所谓的互斥(mutex)。在每个级别,我们都有:

  • 一组命题互斥体
  • 一组动作互斥体

创建计划图表

现在,让我们看看如何一步一步地构建规划图。最初,我们有 0 级,其中只有前提条件 0,等于初始状态。

0 级(图片由作者提供)

接下来,我们建立下一个级别,级别 1。从一系列行动开始:

A1 号楼(图片由作者提供)

这个等式的意思是 A1 是一组动作,它们:

  • 当前状态满足前提条件,并且
  • 在命题互斥中没有成对的前提条件

下一步是建立一套主张:

建设 P1(图片由作者提供)

我们采用先前构建的 A1,并创建所有行动的积极效果的联合。

接下来的两步是构建互斥体,从 A1 的互斥体开始:

为 A1 构建互斥体(图片由作者提供)

A1 的两个动作是互斥的,如果它们是依赖的(它们互相抵消对方的效果)或者它们的前提条件是 P0 的互斥。如果有负面影响会抵消行动正面影响的前提条件,则两个行动是相关的:

依赖动作(作者图片)

最后一步是为 P1 构建互斥体:

为 P1 构建互斥体

这基本上意味着 P1 的一对命题是互斥的,如果:

  • 中,A1 的所有动作对都有正面效果,这些动作是互斥的,并且
  • 在 A1 中没有一个动作可以同时产生这两种效果

现在,这很复杂,但这一步可以简单地重复到下一个级别。这是深度=3 的规划图的结果。

规划图—深度=3

在这一点上,我们可以看到,与可达性树和可达性图相比,规划图的构建要复杂得多,但正如您所看到的,它的搜索时间更快,大小更小,更重要的是,它更易于我们进行分析或调试。

构建规划图时的另一个要点是,在一定深度后,它将是固定的,这意味着动作集和命题集不会再发生任何变化。

我们的目标在第三级达到了,我们可以看到这两个命题:

  • in(contb,loc1)
  • in(conta,loc2)

在 P3(见上图)。

搜索计划图表

现在我们有了规划图——数据结构,我们可以使用搜索算法来为我们的规划问题找到解决方案。

这种方法中的计划不是一系列的行动,而是一系列行动的集合。一个级别集合中的所有操作都可以独立执行,这意味着它们之间没有顺序约束。

在我们的例子中,从 P3 到 P0 向后执行搜索,递归地求解目标中的所有命题。在我们解决它们之后,我们递归地使用行动的前提条件作为子目标,直到我们达到 P0。

向后搜索(作者图片)

我们跳过的一件重要的事情是,在每一关我们都有 虚拟动作 ,它们什么也不做——它们的前提条件和效果是一样的。这允许算法对于那些在较低级别中已经被满足的命题平稳地工作。

对于我们的示例,我们的解决方案是:

  • 级别 1:
  • 级别 2:
  • 级别 3:

结论

我们现在有希望理解如何通过使用规划图方法来改进传统规划方法的复杂性。与可达性树和可达性图相比,规划图的构建更为复杂,但它节省了我们搜索解决方案的时间和空间,如分步示例所示。

我希望你理解这个概念,在下一篇文章中,我们将用 Python 实现这个方法来证明它是可行的,并帮助我们进一步理解它。

使用自适应阈值改善咖啡研磨分布

原文:https://towardsdatascience.com/improving-coffee-grind-distribution-using-adaptive-thresholds-194e001f301?source=collection_archive---------45-----------------------

咖啡数据科学

利用图像处理了解磨床性能第 4 部分

之前,我已经使用了筛子和不同的成像技术来改进咖啡磨粒分布测量,现在我将应用我的一项旧技术来更好地收集成像数据。通常,图像很容易找到依据,但有些却不是。由于光线与咖啡的相互作用,简单的阈值并不总是有效,所以我仔细观察了一下。

由此产生的变化使我能够测量的咖啡颗粒的数量增加了两倍,这是一个直接的自适应滤波器,有助于解决照明问题。

快速回顾

我拍了一张照片,用一张纸确定了测量地面的真实情况(像素到毫米),然后用一个阈值来寻找粒子。

所有图片由作者提供

适应滤波器

我从看一些图片开始。我觉得这些分布没有完全捕捉到微粒的数量。所以我看着我的灰度图像,它是红色、绿色和蓝色平面的乘积。然后我取逆得到黑点为 1 为最高值。

我以两种方式想象这一点:

  1. 假色
  2. 带有虚假颜色的网格

它揭示了有许多较亮的斑点可能没有达到阈值。在这种情况下,阈值为 0.9,这有两种影响:

  1. 抛出小颗粒
  2. 减少其他粒子的边缘,这会影响过度分布。

低通滤波器(自适应滤波器)

在我攻读硕士学位期间,我在计算机视觉的青铜时代研究过一辆自动驾驶汽车。使用低级别图像处理,我开发了一种称为低滤波器的方法,用于在尝试进行车道线识别(自主移动机器人的车道识别和路径规划)时改善滤除噪声。

“低”过滤器基于这样的观察结果:从图像底部到顶部,平均行值会增加。这可以用来帮助滤除全局阈值不能滤除的不太理想的像素。

左上:原图。右上:桶被移除。左下角:应用了低通滤波器。右下:门槛。

该过滤器的工作原理是基于该阈值丢弃每个颜色平面中的像素:

阈值=平均值(行)+ A *标准值(行),其中 A 是用户定义的常数。

所以我把这个想法应用到咖啡渣上!

用低滤器过滤咖啡

我按行和列的方式应用了这个过滤器,我发现 A=2.5 对我的应用程序来说相当不错。我似乎比以前获得了更多的粒子和粒子边缘。

我们可以查看三幅图像的总计数,几乎是三倍。

咖啡分发

我展示了前后粒子分布的对比。我在顶部有三个设置,然后我在下面拆分每个设置。

对于最小的设置有轻微的偏移,这证实了该技术能够挑选出更小的颗粒,或者至少它挑选出更多的小颗粒。

这看起来像是 15 号场景怪异分布的转变。

我越看这些分布,它们似乎越不符合我的想法,因为它们很不平坦。除了轻微的移动,这个基本上不受影响。

粒子分布

这些分布很接近,所以我观察了原始粒子的分布。

正如你在这张设置分类图中看到的,这两者非常接近。曲线的形状有些变化。

主要的问题仍然是假设咖啡是圆的,但它不是。然而,这种技术仍然可以比较好地比较不同的研磨设置和研磨机。我更有信心有一个自适应过滤器来帮助表征粒子。这种技术也使整个过程对光照变化更加鲁棒。

下一步是比较多个研磨设置和研磨机。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

使用图像处理测量咖啡研磨颗粒分布

浓缩咖啡过滤器:分析

浓缩咖啡过滤篮:可视化

建模咖啡研磨机

浓缩咖啡过滤器对比:佩萨多 vs VST

浓缩咖啡篮(VST):有脊与无脊

IMS superficial vs VST:小样浓缩咖啡过滤器对比

浓缩咖啡模拟:计算机模型的第一步

克鲁夫:对技术状态的进一步分析

克鲁夫咖啡筛:一项分析

浓缩咖啡篮隆隆作响:机器人 vs 铂尔曼 vs 正派

使用筛子改进咖啡研磨测量

原文:https://towardsdatascience.com/improving-coffee-grind-measurement-using-a-sifter-7b358f9c8331?source=collection_archive---------43-----------------------

咖啡数据科学

使用图像处理了解磨床性能第 2 部分

在之前的中,我研究了使用图像处理来测量研磨颗粒分布,我发现这很有挑战性。拍摄图像需要细心,但这还不是全部。咖啡似乎发生了一些事情,因为根据图像处理技术,在壁龛上设置 15 和 30 产生了类似的结果。我怀疑这是由于地面粘在一起,为了测试这一点,我将使用筛子。

我有一个 Kruve 筛,我有几个筛(250,400,500,800),但我主要用 400um 和 500um。考虑到我最关心的是使用一些利基研磨水平来制作一个断奏镜头,我将注意力集中在这两个屏幕上,这两个屏幕给出了三个筛选水平。

所有图片由作者提供

我用了 4 或 5 颗豆子,所以测试很快。然后我筛出每一层的粉末,测量每一层的重量,然后把每一层的粉末放在纸上成像。

这里是使用研磨设置 15 在纸上的三个筛水平。

设置 15 幅图像:左边是<400um, Middle is between 400um and 500um, and the right is > 500um

我使用了从每个筛子测得的重量,并将其与成像测量结合起来,给出了下面的这些分布。这假设粒子是球形的(它们不完全是但是任何 3D 形状都与三次方成比例)。

然而,这些图表并不正确。设置 15 和 0 看起来太接近了,它们看起来都有很多较粗的颗粒,这是不可能的,因为使用了筛子将它们过滤掉。让我们看看设置 0 和每个筛子中颗粒的分布:

大于 500 微米的粉末数量是有问题的。对于< 400um 或中间值,任何高于 500um 的值都是错误的。很可能是由于多个粒子聚集在一起导致算法出现问题。

此外,如果我们合计三个筛子的体积,我们不会得到相对于地面事实的正确分布。

如果我们忽略所有期望筛之外的颗粒,我们得到的分布看起来好得多。这些曲线是在合并筛上数据时忽略筛范围之外的颗粒的结果。

将成像和筛子结合起来似乎是一种可以廉价确定咖啡研磨颗粒分布的技术,但这仍然没有达到更理想的情况,即任何人都可以将咖啡研磨颗粒放在一张纸上,并拍摄图像以获得颗粒分布。

第 3 部分中,我将研究这些数据,看看使用图像处理来自动清理图像可以做出哪些改进。

如果你愿意,可以在 TwitterYouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在关注我。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页

使用图像处理测量咖啡研磨颗粒分布

浓缩咖啡过滤器:分析

浓缩咖啡过滤篮:可视化

造型咖啡研磨机

浓缩咖啡过滤器对比:佩萨多 vs VST

浓缩咖啡篮(VST):有脊与无脊

IMS 超细 vs VST:小样浓缩咖啡过滤器对比

浓缩咖啡模拟:计算机模型的第一步

克鲁夫:对技术状态的进一步分析

克鲁夫咖啡筛:一项分析

咖啡篮隆隆声:机器人 vs 铂尔曼 vs 体面

提高机器学习成果

原文:https://towardsdatascience.com/improving-machine-learning-outcomes-by-focusing-on-framing-timing-and-targets-28d5d112b697?source=collection_archive---------36-----------------------

关注框架、时机和目标

阿尔瓦罗·雷耶斯在 Unsplash 上拍摄的照片

介绍

为了构建成功的机器学习解决方案,每个相关人员都需要理解一些基本的想法。在这篇博文中,我们来看看设计过程的三个关键早期阶段,经理们可以关注这些阶段,以确保项目朝着成功的方向发展。

这篇文章假设读者已经了解机器学习的区别,如监督和非监督模型,训练和测试阶段,以及整个机器学习生命周期。回到定义业务问题的最早阶段,我们将注意力集中在三个关键目标上。

三个关键目标:框架、时机和目标

数据科学培训在一定程度上介绍了这些目标。然而,他们往往没有得到应有的重视。部分原因是,从表面上看,它们似乎是显而易见的:框定问题,决定何时进行预测,并确定模型学习的目标变量。

这是项目涉众可以用来影响项目成功可能性的三个主要杠杆。出于这个原因,深入研究每一个问题是很重要的,以便发现一些微妙之处,这些细微之处可以区分是否获得了解决您的业务问题的模型。

目标一:框定你的问题

在应用机器学习的世界中,需要决定机器学习模型将如何与业务进行交互。这包括确定模型做出的预测将如何影响或决定决策。具体一点,通过模型的输出被业务使用的确切的机械方式来思考。企业是否只在模型产生特定价值时才采取行动?或者企业总是采取行动,但是模型输出修改了行动?预测的具体真实值会影响行动吗?还是仅仅决定团队是否采取行动?

人们很容易认为这种关系会非常简单,或者对于一个给定的问题只有一个选项,然而通常情况并非如此。让我们来看一个例子,它说明了如何针对一个常见的问题生成可能产生更好结果的替代框架。

例子:重构预测问题

许多组织遇到了与预测未来给定时间点将订购或需求的货物量相关的挑战。想要理解那些数字的欲望通常与 一个关键的商业决策 有关。它可以确定:手头是否有足够的库存?或者也许:会有足够的仓库空间吗?

在框定机器学习项目时,这意味着什么?

有时,人们非常重视一个模型,该模型试图预测将被销售或交付的小部件的确切数量,然而在现实中,支持特定业务所需的只是一个传达该数量是否会超过给定阈值的模型。在许多情况下,构建后一种模型会更容易、更有效。

这就是关注问题框架的含义:仔细思考为了达到为目标业务问题提供解决方案的结果,有必要知道什么。

这里的一个很好的经验法则是,通过 使机器学习模型的输出更接近企业期望做出的具体决策 ,可以实现更好的结果。这可能有所帮助的原因是因为 模型将集中在业务部门需要了解的决策 上,而不是试图对每一个细节进行建模。

如果你对重构预测问题的其他例子感兴趣,那么我推荐你在 AWS Summit Online 网站上观看 Charles Prosper 的精彩演讲。

目标 2:解决方案的时机

所有的机器学习模型都需要产生一个输出,并且在特定的时间点产生这个输出是物理上的必然。例如,这个时间是星期四下午 3 点可能并不重要,但重要的是相对于被预测事件的时间。

例如,在客户关闭账户前一个小时预测客户是否会流失,与在客户流失发生前一个月预测客户流失有很大的不同。另一个重要因素是需要采取的行动。不同的行动需要不同的时间来实施和生效。向不满意的客户发送即时报价短信可以快速实施并取得成效。相反,如果需要的行动是派遣员工去拜访客户以解决他们的问题,那就需要更多的时间。

这看起来像是一个独立于构建模型以预测客户流失的任务的实现细节,但在许多情况下并非如此。为什么?模型依赖于数据,而数据只有在关键时间点才变得可用。如果客户流失模型依赖于以简化的方式使用企业服务的客户的信息,那么,尽管它是准确的,但它可能无法产生足够早的预测以采取行动。

出于所有这些原因,仔细考虑模型的预期动作是很重要的。考虑执行这些操作所需的时间,然后确保设计的计时组件足以让这些操作生效。与数据科学团队清楚地沟通 以确保他们仅使用在事件被预测之前足够远的时间内可用的数据,以允许预期的行动 。数据科学培训和测试程序应反映这一时间安排,以便用于评估模型的任何性能指标都能准确反映模型在现场如何执行

目标 3:确定一个可靠的目标变量

在机器学习的大多数实际应用中,需要确定一个历史信号来通知正在建立的模型。在监督机器学习中,该信号通常被称为目标变量。

在某些情况下,定义目标变量可能很简单,而在其他情况下,定义目标变量似乎很困难。为了说明困难的常见来源,让我们再看一个例子。

示例:定义一个不会强化现状的目标变量

一家大型连锁超市要求数据科学团队开发一个应用程序,向忠诚会员推荐要购买的产品。最初的诱惑可能是把这个项目定位为产品推荐者。可能有一个团队成员对此有直接的经验,这意味着团队可以立即开始工作。然而,进一步挖掘可能会发现,推动该项目的主管实际上希望这些建议推动鼓励健康饮食的目标。现在,问题不再是简单的推荐,而是决定如何为忠诚会员确定产品,这些产品既是他们可能购买的东西又是健康饮食的选择

在这种情况下,客户的历史购买模式可以用来确定推荐者的信号,但这不会产生正确的结果。这只会鼓励他们继续购买他们以前购买的东西,或者有类似经历的人购买的产品。简而言之,这将巩固现状。

定义这个特定目标最困难的部分是如何确定一个健康的饮食选择,这也是一些人可能会购买的东西。是否需要手动将一些购物篮分类为健康与不健康?有可能从产品描述或成分中提取信息吗?是否值得查看顾客的历史购物篮,并对哪些内容是健康的进行分类,以便从他们自己以前的健康行为中获得建议?

有许多方法可以解决这个问题,但关键是不能盲目地将所有历史数据用作训练集,因为企业希望推动的结果不同于历史行为。

虽然这是一个微不足道的例子,但它表明了一个普遍存在的问题: 依赖历史数据并不总是会导致企业正在努力实现的结果。 机器学习项目管理的最佳实践是严格的目标变量评审会议。在该会议中,所有利益相关者可以坐在一起,确定提议的目标变量和封装它的数据是否会准确地产生一个产生他们期望的结果的模型。

结论

有了框架、时机和目标这三个核心目标,企业可以确保他们的机器学习项目与他们的目标保持一致。这些主题可以在评审项目和向业务的其他部分展示项目时用作基线。虽然它们不能保证成功,但是定义这些目标通常意味着即使一个简单的模型也能交付业务成果。

改进机器学习团队的模型管理实践

原文:https://towardsdatascience.com/improving-model-management-practices-for-machine-learning-teams-3bec1dc40929?source=collection_archive---------24-----------------------

如何通过模型管理功能识别使机器学习活动更有效的问题

在本文中,我们阐述了如何通过模型管理功能来识别使机器学习(ML)活动更有效的问题。然而,我们并没有提出任何具体的解决方案,而是提供了一个系统地思考模型管理问题的框架。这样一个框架对于那些处于产业化或扩展他们的 ML 系统的边缘的团队来说是很有用的,他们可以在处理 ML 模型时解决技术债务或缺口。如果你对此感兴趣,请继续阅读。

图 1:只有一小部分真实世界的机器学习系统由机器学习代码组成,如中间的小黑框所示。所需的周边基础设施庞大而复杂。最初发表在论文机器学习系统中隐藏的技术债务。

ML 系统是复杂的,因为它们将所有的技术问题与维护代码库结合在一起,而代码库又是由数据和建模问题产生的。如图 1 所示,生成 ML 模型的代码只是整个系统中用于端到端模型处理的一小部分。模型管理的目标是使所有建模活动中的 ML 模型的处理尽可能简单和高效。在接下来的小节中,我们将简要描述建模活动以及管理功能。如果您已经熟悉这些概念,请跳到下两个部分。

ML 建模中的活动

图 2:ML 中的三个主要建模活动:开发、选择和应用。这些活动具有线性相关性。这些活动主要由数据科学专家监督和执行,而活动的结果可由利益相关方(如业务方的代表)访问和批准。这些活动是在团队可访问的基础设施上的一系列平台上进行的。图片由作者提供。

图 2 描述了 ML 建模中的三个主要活动:模型开发、选择和应用。模型开发是使用训练数据训练新模型的过程。模型选择是从一组训练好的模型中选出一个获胜模型的过程。模型应用是使用选定的模型进行预测工作以促进业务流程的过程。这些活动具有线性依赖关系,这意味着它们必须按照一定的顺序执行。例如,在生产中应用一个模型一段时间后,它的性能可能会因为不同的原因而下降。在这种情况下,需要重新开发和选择新的模型。

建模活动的结果最终会进入业务流程,并且很可能需要得到业务代表的理解和批准。这些活动由数据科学专家执行,即在这些活动中具有知识和/或经验的分析师、科学家、工程师。这些活动在众多平台上开展。为了更好地理解,我们在这里列出了几个这样的平台:

现代组织中的团队访问云计算服务提供的基础设施中的大多数平台,如 Azure 。你会发现来自其他提供商的类似平台,比如谷歌云亚马逊网络服务

模型管理功能

图 3:模型管理过程中的关键能力:跟踪、注册、服务、分析、监控和文档化。ML 建模活动使用这些能力来更有效和透明地管理这些活动的输入和输出。数据科学专家是这些能力的主要利益相关者。这些功能主要是由团队中的工程专家通过团队可以访问的一系列平台提供的。图片由作者提供。

模型管理功能使得使用模型变得更加简单、透明和高效。如图 3 所示,主要功能是跟踪、注册、服务、分析和监控。模型跟踪是保持关于建模活动的关键信息记录的能力。模型注册是使用一系列打包格式将模型注册为版本化模型的能力。此外,它让模型处于众所周知的状态,例如,测试、生产、存档等。并且能够改变模型的状态。模型服务是使模型可用于预测过程的能力。模型分析是通过输入和输出的质量来评估模型质量的能力。模型监控是跟踪模型和数据质量并对不可接受的变化做出反应的能力。模型文档是在执行活动的团队之内和之外获取和传递关于建模活动的部落知识的能力。

模型管理功能由图 1 中描述的不同系统来表示。我们在此列举几个众所周知的公共平台作为例子:

改进建模活动

图 4:模型管理能力与建模活动之间的关系。颜色编码的模型管理功能作为较小的表示放在不同的建模活动中。图片由作者提供。

图 4 展示了模型管理功能和建模活动监控之间的关系。我们建议,改进模型训练需要关注模型跟踪、注册、分析和记录。改进模型选择需要关注模型注册、服务、分析和记录。改进模型应用需要采用所有的模型管理功能。

为了更好地阐明这一点,我们提出了下面的框架,重点关注七个改进挑战。

模型管理挑战

为了更好地理解这些挑战,我们使用了一些改进因素:

  • 持续时间:完成挑战需要多长时间?
  • 准确性:解决挑战的解决方案/方法的质量如何?
  • 清晰的范围:在不同的上下文中使用模型有多容易?
  • 便携性:在任何地方使用该机型有多容易?

挑战 1: 观察并展示跑步过程中发生的事情

相关性:所有三个建模活动

关键改善因素:

  • 持续时间:当模型跟踪使用不是专门为模型管理而构建的不同技术时,该任务需要很长时间。为了应对这个挑战,有必要关注一个模型跟踪工具,它提供了一个单一的面板来捕获和显示所有的信息。您可以从现代代码管理工具中获得灵感,例如 GitHub ,它提供了一个 CLI 和一个 UI 来处理许多代码更改。

挑战 2: 决定一个模型的质量是否适合生产使用

相关性:模型开发和选择

关键改进因素:

  • 准确性:当模型分析和测试方法不充分且不一致时,决策的准确性较低。因此,有必要集中精力提高可重复和可再现的模型分析和测试的覆盖率。您可以从测试驱动开发的实践中获得灵感,在这种实践中,从一开始就以某种方式为代码开发考虑一系列单元、集成和其他种类的测试。
  • 持续时间:如果模型分析和测试方法大部分是手工完成的,那么这个任务需要很长时间。因此,有必要关注尽可能自动化的分析和测试。您可以从代码变更的持续集成实践中获得灵感,其中自动化单元和集成测试扮演着至关重要的角色。

挑战 3: 在生产中高效使用模型

相关性:模型应用

关键改进因素:

  • 持续时间:由于缺乏良好的模型服务解决方案,准备运行预测作业花费的时间太长。为了应对这一挑战,有必要投资一个好的模型服务解决方案(购买或内部开发)。你可以从构建能够对几乎所有查询提供亚秒级响应的搜索引擎中获得灵感。
  • 清晰的范围:当缺乏定义模型版本和状态的能力时,模型的范围是不清晰的。此外,当一个模型通过它的存储位置而不是一个(唯一可识别的)名称被引用时,情况会变得更糟。为了应对这一挑战,有必要采用一种注册管理机构模式。为了获得灵感,你可以查看 API 版本控制技术

挑战 4: 监控生产中模型的质量

相关性:模型应用

关键改进因素:

  • 准确性:当数据、概念和模型发生漂移时,模型的质量会降低。如果不测量这种漂移,就很难确定是否/何时会发生这种漂移,从而影响对降级作出反应的机会。此外,不知道漂移的严重程度会导致不正确的响应。为了解决这个问题,重要的是进行这样的测量,并将其作为常规分析的一部分。从过去的经验中收集知识也很重要,这将为未来的事件建立反应基准。为了获得灵感,考虑一下仪表盘和现代汽车的基本技术,它会在轮胎压力低、发动机温度高等情况下发出警告。以及对这种警报的不同程度的反应。
  • 持续时间:如果大部分步骤是手动进行的,那么捕捉漂移的持续时间太长。为了应对这一挑战,有必要投资一个良好的监控解决方案(购买或内部开发)。要获得灵感,您可以看看基础设施监控解决方案

挑战 5: 使用开发团队范围之外的模型

相关性:模型应用

关键改善因素:

  • 可移植性:如果意大利面条式的代码溢出到打包的模型中,那么使用模型的依赖性就很高。此外,缺乏模型元信息,例如,输入-输出模式和样本数据、种子、超参数等。,与模型使问题变得更糟。为了解决这个问题,有必要遵循一个好的模型验证机制,这包括采用更好的模型分析和模型注册解决方案。为了获得灵感,考虑一下 Python 库打包,它支持在任何操作系统环境中安装新的库。

挑战六:重现一次奔跑

相关性:所有三个建模活动

关键改善因素:

  • 准确性:缺乏重现运行能力的主要原因是缺少代码、配置、数据和任何其他使其可行的依赖版本。关注这些工件的更好的版本控制能力是很重要的。从更简单的对应物中获取灵感,即 GitHub 提供的代码版本控制能力。
  • 持续时间:延迟执行任务的主要原因是缺乏良好的跟踪能力和任何利用跟踪版本的工作流自动化能力。因此,关注基于版本化信息的工作流非常重要。为了获得灵感,你可以看看关于代码测试覆盖率和代码版本质量分析的[持续集成](http://continuous integration)过程。

挑战 7 :执行整个流程,包括但不限于安排活动、处理对资源和工件的依赖、准备、风险监控等。建模活动

相关性:所有三个建模活动

关键改善因素:

  • 准确性:一个不准确的过程的主要原因是在大多数阶段严重依赖于人工参与,并且分散的技术不是主要为模型管理而构建的。重要的是尽可能地转换手动步骤,同时采用一个解决方案框架,能够使用几个窗格完成大多数步骤。你可以从空中交通管制活动和实践中获得灵感。
  • 持续时间:需要很长时间来应对这一挑战的主要原因是大多数步骤都是手动的。重要的是尽可能自动化这些步骤,使它们易于执行和简化。您可以从空中交通管制活动和实践所采用的技术中获得灵感。

整体挑战:传授建模活动的知识

相关性:所有三个建模活动和以上所有七个挑战

关键改善因素:

  • 准确性:准确性低的主要原因是缺乏针对不同技能水平的足够的文档。重要的是专注于全面记录以捕捉所有细节。从知名图书馆的文档中获取灵感,例如 scikit-learn
  • 持续时间:持续时间长的主要原因是缺乏良好的文档组织。不管理信息,不提供良好的结构,不在更少的地方维护,不提供容易访问的机制,就会导致这样的情况。从知名图书馆的文档中获取灵感,例如 scikit-learn

评论

一次性解决所有这些挑战是不可行的。当一个团队没有解决一些或所有的挑战时,采取一种务实的方法是很重要的。我们在这里提供一种方法。挑战 1-4 比其余的更重要。因此,我们作为一个团队可以对属于该组的挑战进行优先排序。在每个挑战中,准确性和功能性比持续时间和文档化更重要。

显然,细节决定成败。你面临这些挑战吗?这些澄清有用吗?你不同意这样的观点吗?让我们知道。

我要感谢我在 H&M 的同事,他们为这篇文章提供了意见和反馈。

使用缺失值改进模型

原文:https://towardsdatascience.com/improving-models-with-missing-values-52fb19559948?source=collection_archive---------37-----------------------

数据科学

从缺失值中获取有价值的信息。

图片由作者提供。

当我加载一个新的数据集时,我首先检查的事情之一是我们有多少丢失的值。看到所有这些南价值观令人失望和沮丧。超过 50%的值缺失的列并不罕见。我们都对新的数据集感到兴奋,主要是因为新的数据集意味着更多的数据和更多的改进。但是像任何其他以前的数据集一样,新的数据集充满了无用的缺失值!!!!

但是等等!缺失的价值观真的无价吗?我能从缺失的值中获得一些额外的信息或见解吗?

在这篇短文中,我将改变你对缺失数据的看法。我将向您展示如何以不同的方式看待缺失值,并利用缺失数据提高模型性能。让我说清楚,专业数据科学家和普通数据科学家之间的主要区别之一是他们如何处理缺失值并从中获得有价值的信息。

我先问个问题。当您看到缺少值时,您会怎么做?我们中的许多人最初(或永久)移除它们。我们中的一些人折磨自己几个星期来归咎于他们。

在调查其背后的原因之前,删除或输入缺失的值有三个负面后果。

  1. 删除缺失值的样本(即行)会迫使我们忽略其他非缺失值,这些值可以帮助我们构建更好的预测模型。
  2. 移除具有大量缺失值的特征(即,列)会再次移除该特征的其他非缺失值,这是对数据的浪费。
  3. 有时,缺失值本身就具有很好的信息,这些信息对于改进分析或我们预测模型的性能是必要的。
  4. 删除或输入缺失值会给我们的模型带来偏差。

让我说清楚。我不反对删除或添加丢失的值,但是你可以问自己几个问题。这里有三个重要的问题,在遗漏数据删除或插补之前,你必须问自己。

马库斯·温克勒在 Unsplash 上的照片

是什么产生了这些缺失值?

想象一下,我们有一个医学研究小组收集的患有和未患有某种癌症的人的数据集。你有两组的所有信息。缺失的一列可能是活检测试结果。没有癌症的人的价值观缺失是有道理的,但为什么我们对最终确诊为癌症的人有很多价值观缺失呢?一个简单的解释是,收集数据的医学研究小组无法找到一些患者的活检结果,因此跳过了这些结果。但一个更重要的原因可能是医生因为其他因素而没有安排活检。例如,可能其他测试结果使医生确信应该诊断癌症(即使没有活检)。或者另一种可能性是,医生无法诊断癌症,并拒绝安排活检测试。如果您删除或忽略丢失的值,您将丢失大量信息。在本例中,缺失值是这种特定类型癌症的症状非常明确和非常不明确的一类患者。活检结果中没有缺失值的患者(样本)是具有足够症状的患者,医生为他们安排了活检。

如您所见,缺失值为我们提供了至关重要的信息。获得这些有价值信息的唯一方法是思考为什么我们会看到一个缺失的值并理解它的意义。

请记住,缺失值不仅仅是由数据收集者的错误造成的。也许,其他因素(本例中的医生)出于某些原因决定将其作为缺失值。

迈克·阿隆佐在 Unsplash 上的照片

缺失数据和其他数据之间有关联吗?

有时,一个或几个特征与缺失值之间有很好的相关性。换句话说,缺失值不是随机缺失的。

一个非常简单的例子是从患者信息表中收集的数据。这些数据中的许多(尤其是原始数据集)都缺少关于怀孕问题的值。男人不检查这些问题(当然),这些表格的原始数据集将在那些列中充满缺失值。请注意,一些女性可能没有检查这些问题,但是男性患者的缺失值与女性患者的缺失值的含义不同。

有时,您可能会看到丢失的值与一些奇怪的特征(如 id 或代码号)之间的关联。例如,在医院中,患者 ID 号或订单编号可能有特定的含义。有时,缺失值和 ID 号之间的关联可以帮助我们理解缺失值以及这些代码和数字背后的结构。

戴维·特拉维斯在 Unsplash 上拍摄的照片

有缺失值的样本是否存在偏倚?

(在调查缺失值背后的原因之前)移除缺失值样本的另一个危险是给我们的模型或研究带来偏差。假设我们有一个在线约会应用程序的用户资料数据库。该数据库可以基于年龄和种族为可选问题的问卷来制作。我们应该期待女性或少数民族群体对这些与年龄和种族相关的问题不予回答吗?我认为这是一种可能性。如果我们删除基于缺失值的行,我们会在模型中引入偏差。我的假设(应该被检验)是,在去除了提到的缺失值的样本后,数据库应该更偏向于白人男性。通过这个假设的例子,我想向您展示,在不考虑固有偏差的情况下删除缺失值的样本会如何导致有偏差的模型。

摘要

缺失值可能包含重要的信息,这些信息不仅可以改善我们模型的性能,还可以改善我们正在解决的业务问题。

在删除或添加丢失的值之前,问自己三个问题。

1)是什么产生了这些缺失值?

2)缺失数据和其他数据之间有什么关联吗?

3)有缺失值的样本是否存在偏倚?

利用因果关系改进自然语言处理

原文:https://towardsdatascience.com/improving-nlp-with-causality-2dec1fa90b74?source=collection_archive---------10-----------------------

因果推理在提高自然语言处理模型的健壮性、公平性和可解释性方面的潜在用途

克里斯·劳顿在 Unsplash 上的照片

两年前,谷歌宣布正在使用一种人工智能语言模型,命名为 BERT,以改进谷歌搜索;当时大约有 10%的搜索使用了这个词。一年后,在一篇题为“人工智能如何为更有帮助的谷歌提供动力”的文章中,该公司报告称,100%的搜索查询都在使用 BERT。然而,这些公告并没有包括模型中编码的性别和种族偏见的信息。自从 BERT 公开发布以来,许多研究人员已经注意到模型中存在的偏差( Kurita 等人 2019Bhardwaj 等人 2020Bender 等人 2021 )。然而,谷歌尚未解决围绕这一如今无处不在的模式的许多紧迫的伦理问题。抛开令人失望的问责缺失,我们可以选择专注于解决方案;因此,本文主要讨论如何使用因果关系来改进像 BERT 这样的 NLP 模型。

之前的一篇文章中,我提到了最近的一篇计算语言学调查论文(费德等人,2021a ),该论文着眼于因果关系和 NLP 模型之间的关系。我的前一篇文章关注的是如何将 NLP 方法用于文本变量进行因果推理,而本文关注的是反向连接。在这里,我探索因果推理如何帮助改进传统的 NLP 任务,如文本分类、情感分析或文本生成。我首先简要介绍像 BERT 这样的 NLP 模型,强调其固有的弱点,并提出因果关系可以解决现有缺点的广泛方法。接下来,我将讨论伪相关性,并介绍一个实际的案例研究,该研究将在本文的剩余部分中使用。接下来,我将重点关注健壮性和敏感性——特别是因果驱动的数据增强和分布标准可以克服挑战的方式。这导致了对 NLP 模型中的公平性和偏见的讨论,以及如何使用因果关系来解决提高公平性和减少偏见的目标。最后一节讨论了因果关系在提高 NLP 模型的可解释性和可解释性中的应用。最后,我对未来的工作提出了一些想法,这些工作将进一步探索因果关系和 NLP 之间的关系。

相关预测模型

BERT 代表了 NLP 的一个突破时刻, Transformer 架构的使用和上下文嵌入的双向特性已经被许多研究人员采用,衍生出了诸如 RoBERTaM-BERTALBERTERNIE 等模型。然而,这些架构不区分原因、结果和混杂因素。费德在阿尔。(2021a) 解释这些模型并不试图确定因果关系。因此,“一个特征可能是一个强大的预测器,即使它与期望的输出没有直接的因果关系”( Feder et al .,2021a )。为了更好地介绍这些以芝麻街角色命名的模特,我推荐这本由 Jay Alammar 撰写的视觉入门。

根据 Feder et al. (2021a) ,当前的 NLP 模型可以被描述为“相关性预测模型,其中预测是由于相关性(可能是虚假相关性)而不是因果关系。因此,尽管取得了最先进的结果,这些相关性预测模型可能是不可信的,并可能导致分布外设置的错误(费德等人,2021a )。关于信任, Jacovi 等人(2021) 探索了人工智能模型的可信度——他们讨论了“有保证的”信任意味着什么,以及如何通过内在推理和外在行为来实现信任。他们提出了设计可信人工智能的方法,一个关键的发现是信任和可解释人工智能(XAI)之间关系的重要性——这是使用因果关系来提高人工智能可解释性的进一步理由。此外, McCoy et al. (2019) 展示了人工智能语言模型如何在错误的原因下往往是正确的,并且会由于依赖易错的语法试探法(虚假的“快捷方式”)而在非分布设置中出错。显而易见,缺乏因果关系会导致难以解释的模型,而这些模型的概括能力很差。

相关性预测模型还存在另外两个问题:“用户组之间不可接受的性能差异,以及他们的行为太难以理解而无法纳入高风险决策的问题”( Feder 等人,2021a )。例如,一项名为“男性也喜欢购物”的电子商务研究讨论了性别偏见放大,并展示了这些人工智能模型如何在不同用户群之间表现出不同的表现(赵等人,2017 )。此外,如上所述,像 BERT 这样的黑盒模型的一个常见问题是,它们缺乏用于高风险决策的透明度( Guidotti 等人,2018 )。在处理人的生命或生计受到威胁的场景时,依赖内部逻辑被隐藏的 AI 模型是不道德的。

解决相关预测模型的这四个已知缺点的解决方案是将因果观点应用于模型开发和验证。最近的研究表明,可以“利用观察值和标签之间的因果关系知识,将虚假相关性形式化,并减轻预测者对这些相关性的依赖”( Feder 等人,2021a )。换句话说,理解数据生成过程(DGP)的因果结构可以帮助识别潜在的混杂因素。例如, Veitch 等人(2021) 建议使用压力测试作为一种形式化要求的方式,即改变输入的不相关部分不应改变模型的预测(反事实不变性)。这项工作还表明,反事实不变性的意义和含义取决于数据的真正潜在因果结构。因此,不同的因果结构需要不同的正则化方案来诱导反事实不变性(维奇等人,2021)

因果关系的另一个优点是,它提供了一种语言来说明和推理公平条件。 Kilbertus 等人(2017) 探索了如何使用因果推理来避免歧视,他们通过用因果推理的语言来构建歧视问题来做到这一点。他们声称这是必要的,因为观察标准有内在的局限性,阻止他们决定性地解决公平问题。这意味着,与其关注什么是正确的公平标准,不如关注应该对因果 DGP 做出什么样的假设。

此外,当涉及到测试时,解释预测的任务可以通过用反事实的术语来表述预测来完成。Feder 等人(2021b) 在 BERT 上测试了这种方法,在最近的一篇论文中,他们概述了通过反事实语言模型进行因果模型解释的框架。他们的方法是微调像 BERT 这样的深度情境化嵌入模型,使用从预测问题的因果图中导出的辅助对抗性任务。他们表明,有可能选择辅助对抗性训练前任务,使伯特有效地学习一个感兴趣的概念的反事实表征。然后,这种反事实表示可以用来估计概念对模型性能的真正因果影响。本质上,“一个反事实的语言表示模型被创建,它不受测试概念的影响,这使得它有助于减轻训练数据中存在的偏见”(费德等人,2021b)

虽然最近的因果动机研究给了我们有希望的结果,但由于当前 NLP 模型带来的鲁棒性和可解释性挑战,“有必要开发新的标准来学习超越利用相关性的模型”(费德等人,2021a )。下一节通过一个实际例子强调了这些挑战,并更详细地讨论了伪相关性。

虚假相关性&案例研究

随后的章节讨论了关于稳健性的伪相关性问题,以及处理公平性和可解释性问题的因果方法。为了有助于下面几节中的解释,我们需要一个实际的例子来说明这些挑战。因此,我依赖一个取自之前提到的调查论文的例子( Feder 等人,2021a )。考虑这样一个场景,我们希望构建一个分类器来预测诊断/医疗状况,给定一个书面的临床叙述,并使用来自多家医院的带标签的训练集。下图显示了此示例,其中 Z 代表医院,Y 是医生指定的诊断标签,W 是书面的临床叙述,Y_hat 是来自分类器的预测。

分类问题,其中预测(Y_hat)取决于临床叙述(W),临床叙述本身受诊断标签(Y)和医院(Z)的影响,这两者恰好相关。来源:费德等人,2021a

分类器 Y_hat(W)将临床叙述(W)的文本作为输入,并输出诊断预测。然而,叙述是基于医生的诊断(Y ),也受医院 Z 使用的写作风格的影响。在这种情况下,根据费德等人的说法(2021a ),我们希望在保持标签(Y)不变的情况下对医院 Z 进行干预。反事实地,我们将医院设置为( z ),这给了我们反事实叙事 W( z ),而 Y 是固定的。给定反事实叙事 W( z )的输入,分类器 Y_hat(W)的输出是反事实预测 Y_hat(W( z ))。

因为训练数据具有来自多个医院的记录,所以可能存在这样的医院,在该医院中,患者更有可能被诊断为具有特定状况。也可能是由于特定医院的惯例,该医院的医生倾向于使用独特的文本特征。如果我们要使用 BERT 建立一个相关性预测模型,该预测器将使用携带医院信息(Z)的文本特征(X),这些特征对于预测任何特定医院内的诊断都是无用的( Feder 等人,2021a )。因此,挑战在于较差的分发外性能。由于写作风格和医疗诊断之间的虚假相关性,预测对于训练数据之外的医院将无效。

Feder 等人(2021a) 指出,出现伪相关性必须满足两个条件:首先,在训练数据中,需要有一个因子(Z)来提供关于特征(X)和标签(Y)的信息,其次,Y 和 Z 必须以某种方式依赖于训练数据,而这种方式一般不能保证成立。在这个医疗诊断分类器示例中,如下图所示,Z 与 y 相关。

医疗诊断分类器示例,其中诊断标签(Y)与医院(Z)相关。资料来源:费德等人,2021a

医院 Z 和标签 Y 之间的这种虚假关联存在于训练数据中;因此,预测器将学习 X 中提供医院 z 信息的部分。然而,该预测器并不稳健,因为特征 X 和标签 Y 之间的学习关系在部署期间将不会成立( Feder 等人,2021a) 。下面的章节描述了如何利用因果关系来解决这类问题。

灵敏度和鲁棒性

当处理像 BERT 这样依赖相关性进行预测的人工智能语言模型时,确保预测不会因为错误的原因而变得正确是至关重要的。有两种类型的评估可用于这项任务:不变性测试和敏感性测试。不变性测试“评估预测是否受到与标签没有因果关系的扰动的影响” (Feder 等人,2021a) 。另一方面,敏感性测试“应用的扰动在某种意义上应该是转换真实标签所需的最小变化”( Feder 等人,2021a )。因果动机不变性测试的目的是观察当给定反事实输入时,预测者是否表现不同。如果 Z 是文本中应该与标签 Y 因果无关的原因的标签,那么反事实输入将是 X(Z = ~z )。根据 Veitch 等人(2021) 的说法,在某些情况下,一个其预测在这些反事实中不变的模型在 Y 和 z 之间具有不同关系的测试分布中表现更好。

敏感性测试类似于不变性测试,因为它们也是对反事实的评估;但不同的是,标签 Y 被改变了,但所有其他对 X 的因果影响保持不变( Kaushik et al .,2020 )。敏感性测试的反事实可以表示为 X(Y = ~y)。敏感性和不变性测试是测试稳健性的一种方式,并且有几种学习预测器的方法可以通过这种测试。这些方法是将数据因果结构的领域知识结合到学习目标中的一种方式,这意味着它们是因果驱动的方法。在这篇文章中,我介绍了费德等人(2021a) 描述的两种方法:反事实数据扩充和因果驱动的分布标准。

数据扩充是指构建反事实实例并将其纳入训练数据。这种方法对不变性和敏感性都有效。例如,利用不变性,可以向学习目标添加一项,该项惩罚反事实对的预测中的不一致(例如,X(Z = z 和 X(Z = ~z ))。如果我们测试敏感性,干预将在标签 Y 上,我们将用标签反事实 X(Y = ~y)来增加训练数据。这将“降低对噪声的敏感性,提高域外泛化能力”( Feder 等人,2021a )。

有几种方法可以生成反事实的例子,如手动后期编辑、关键字的启发式替换或自动文本重写( Feder et al .,2021a )。手动编辑的第一种选择通常是准确的,但是昂贵的。使用关键字的第二种选择只在某些场景下有效;例如,当反事实可以通过像代词这样的词的局部替换来获得时。然而,这种关键字方法不能“保证流畅性或覆盖所有感兴趣的标签和协变量,并且难以跨语言推广”( Feder 等人,2021a )。最后一个选项是完全生成的方法,其目标是“将手动编辑的准确性和覆盖范围与词法试探法的便利性结合起来”( Feder 等人,2021a )。

对于所有这三种选择,都存在引入虚假相关性的风险。例如,如果关键字词典不完整,关键字替换方法可能会引入新的虚假相关性( Feder 等人,2021a )。手动编辑和自动文本生成的其他两个选项具有相同的问题,即反事实的生成也会引入新的虚假关联。反事实的例子可能是“强有力的,因为它们直接解决了因果推断固有的缺失数据问题”(费德等人,2021a ),但是反事实的数据增强容易受到虚假相关性的影响。因此,另一种选择是“直接对观察数据进行操作的因果动机分布标准”(费德等人,2021a )。

根据定义,反事实不变预测器将满足可从 DGP 的因果结构中导出的独立性标准( Veitch 等人,2021) 。通过推导不变预测器的分布特性,我们可以确保这些特性被训练的模型所满足。对于我们的医疗示例,我们希望确保改变医院书写风格 Z 不会改变诊断 Y,因为这是一个虚假的相关性。根据 Feder et al. (2021a) 这种对 Z 的反事实不变性,给定一个预测因子 f 和文本特征 X,可以形式化为f(X(Z)=f(X(Z’))对于所有Z;。这里,Z 和 Y 都是 X 的原因,因此反事实不变预测器将给出独立于协变量 Z 的预测 f (X ),条件是真实标签 Y。也就是说,“标签不是文本的影响”( Feder 等人,2021a)

除了为不应该影响预测的文本原因设置明确的标签 Z(这是我们的医学示例的情况)之外,还有两种其他的方法来获得分布标准。第一种选择是将训练数据视为“源自一组有限的环境,其中每个环境在原因上具有唯一的分布,但是 X 和 Y 之间的因果关系在环境之间是不变的”( Feder 等人,2021a) 。环境不变性标准的目的是确保我们有一个表示,其中相同的预测值在每个环境中都是最佳的。这可以被认为是领域泛化。另一个选择是控制混杂;如果 Z 是一个混杂因素,根据费德等人(2021a) 的说法,一个与将观察概率转换为干预概率的“后门调整”相关的因子分解可用于控制 Z 的混杂特征(珀尔,2000 )。

与数据扩充相比,分布式标准需要“比监督学习问题通常可用的数据更丰富的训练数据”( Feder 等人,2021a )。因此,方法的选择应取决于是否更容易获得分布标准所需的观察数据,或者是否更容易创建反事实实例来扩充训练集( Feder 等人,2021a )。下一节讨论公平和偏见,这是可以通过数据扩充或分配标准解决的问题。

公平和偏见

当谈到确保模型公平和无偏见时,“因果关系提供了一种语言,用于指定跨种族和性别等人口统计属性的期望公平条件”( Feder 等人,2021a )。例如,哈特等人(2016) 表明,需要进行因果分析,以确定观察到的数据分布和预测是否会引起公平性问题。他们讨论了反歧视法如何要求人工智能模型不会延续现有的不平等,这项工作通常专注于“受保护”的属性,如性别、种族和宗教等。“通过无意识的公平”的想法表明,人工智能模型只需要忽略这些受保护的属性;然而, Hardt 等人(2016) 声称这是无效的,因为冗余编码使得从其他特征预测受保护的属性成为可能。他们测试各种“不经意”的方法,发现它们无效;因此,他们得出结论,因果关系是必要的,以确定公平的关注。

如前一节所述, Kilbertus 等人(2017) 表明,DGP 的因果解释可以激发公平性度量。与 Hardt 等人(2016) 类似,他们提出这种方法是因为观察数据在正确解决公平性问题方面存在固有的局限性。 Kusner 等人(2017) 定义了“反事实公平”的概念,其中,如果对于每个个体,预测对于通过改变受保护属性而创建的个体的反事实版本保持相同,则预测器是公平的。他们声称这是必要的,因为历史数据可能包含偏见,人工智能模型必须考虑这一点,以避免歧视。

使用因果推理 Kusner 等人(2017) 开发了一个模型公平的框架,该框架捕捉了一个直觉,即一个决定对一个人是公平的,如果它在真实世界中与在反事实世界中是相同的,其中该个人属于不同的人口统计组。也就是说,改变一个受保护的属性,比如种族,在预测上应该具有反事实不变性。费德等人(2021a )解释说,将受保护的属性视为服从反事实推理或干预的变量的合法性存在问题。作为一个解决方案, Kilbertus et al. (2017) 提出可以用名字等可观察的代理来测试不变性。

根据 Feder 等人(2021a) 的说法,有几种方法可以使用反事实数据增强来减少偏差。例如,可以通过交换“身份术语”列表来构建反事实,目的是减少文本分类中的偏差 (Garg 等人,2019) 。另一项研究将代词等性别标记物用于指代消解,指代消解是指文本中的同一实体(赵等,2018) 。反事实数据扩充也已经被用于减少像 BERT 这样的模型的预训练中的偏差;然而,这种预训练模型中的偏差会在多大程度上传播到下游应用,目前尚不清楚( Feder 等人,(2021a )。迄今为止,分配标准还没有经常被用来提高公平性。由 Feder 等人(2021a) 提到的一项值得注意的研究使用不变风险最小化来减少对毒性检测数据集的虚假种族相关性的使用 (Adragna 等人,2020)

回到我们的医疗诊断示例,假设训练数据包含患者和医生的受保护属性,也许这些方法中的一些可能有助于提高公平性。然而,一个值得关注的问题应该是书面叙述中潜在的偏见;例如,批判种族理论认为用来描述有色人种的语言可以不同于用来描述白人的语言。从历史上看,人口统计受贫困等社会问题的影响,这意味着某些医院服务区可能有更高比例的 BIPOC 患者,同时获得的资金和财政捐赠也较少。此外,还有大量关于有色人种和女性面临的医疗保健不平等的研究。例如,引用美国律师协会的话,“黑人根本得不到与白人同等质量的医疗保健,这种二流的医疗保健缩短了他们的寿命。”。

所有这些因素都可能对用于构建诊断预测因子的书面临床叙述产生影响,并且偏倚可能被硬编码到医生诊断标签本身中。因果关系可以帮助确定预测是否公平和公正,例如,因果数据扩充可以测试预测的不变性。然而,同样重要的是,这种决策的透明度,这需要可解释和可说明的人工智能模型。下一节将讨论这个问题。

因果模型的可解释性&可解释性

虽然像 BERT 这样的 NLP 模型目前是“难以理解的黑匣子,难以解释,但有必要诊断错误并与决策者建立信任”( Feder 等人,(2021a )。目前,费德在艾尔。(2021a) 陈述了一种常见的方法是利用网络工件,例如注意力权重,来生成解释。理由是注意力权重是在生成预测的路径上计算的(王等,2016 )。另一种方法是试图通过使用测试实例或其隐藏表示的扰动来估计更简单和更可解释的模型( Kim 等人,2017 )。这两种基于注意力和干扰的方法都有重要的局限性,会使它们产生误导。例如,“基于注意力的解释通常只可能用于单个标记,因此不能用抽象的语言概念来解释预测”( Feder 等人,(2021a )。此外,基于扰动的方法“不允许估计句子级估计的影响,并且经常会产生不可信的反事实”( Feder 等人,(2021a )。

鉴于现有可解释性度量的问题,有应用因果观点的空间。根据费德在阿尔。(2021a) ,一种方法是使用数据扩充生成反事实示例,然后将每个示例的预测与来自生成的反事实的预测进行比较。反事实数据增强使得计算观察到的文本和如果文本中不存在特定概念时的文本之间的差异成为可能。在这种情况下,生成反事实文本似乎是合理的,这就有可能估计基于文本的模型的因果效应( Feder 等人,(2021a )。

例如, Ross 等人(2021) ,为了促进数据扩充,创建了一个任务不可知的生成系统,它以语义受控的方式干扰文本。这个系统被他们命名为 Tailor,它使用了不相似性训练和一个生成器,该生成器遵循一系列来自语义角色的控制代码,这些控制代码的修改允许细粒度的扰动。使用 Tailor 生成反事实,减少了通常与特定任务扰动生成器相关的开销,并具有提高模型可解释性的优势。 Gardner et al. (2020) 试图通过使用“对比集”来评估模型的决策边界,从而提高模型的可解释性。他们建议,在构建数据集后,作者应该以小而有意义的方式手动扰动测试实例,以创建对比集。这些对比集应该“提供模型决策边界的局部视图,然后可以用来更准确地评估模型的真实语言能力”( Gardner 等人,2020)

尽管在生成自然语言反事实方面取得了进展,但对于风格、主题或情感等抽象语言概念来说,通常不可能“自动生成有意义的反事实,手动生成成本太高”( Feder 等人,(2021a )。鉴于这一问题,提出了一种替代方法,其中文本本身被搁置,而文本的表示被操纵。这种方法的一个例子是前面提到的 Feder 等人(2021b) 关于反事实语言表征模型的工作。他们通过预先训练分类器使用的语言表示模型(BERT)的附加实例来计算反事实表示,并使用对抗性辅助任务来控制混淆概念。另一个例子是 Ravfogel 等人(2020) 的工作,其中提出了一种使用迭代零空间投影从模型中移除信息的方法,以保留受保护的属性。

到目前为止,所讨论的可解释性方法使用反事实来确定不变性,一种“补充方法是生成具有最小变化的反事实,以获得不同的模型预测”( Feder 等人,(2021a )。这种敏感性方法提高了可解释性,因为它强调了改变模型预测所需的变化。例如,莫西拉尔等人(2020) 开发了一个框架,用于生成和评估一组不同的反事实解释,作为提高模型可解释性的一种方式。本质上,将不变性和敏感性测试合并到模型开发过程中,是一种使用因果关系来提高可解释性和可解释性的方法。

最后的想法

因果关系可以通过增加鲁棒性、公平性和可解释性来改进 NLP 模型。做出这些改进应该有助于解决当前最先进的人工智能语言模型(如 BERT)中存在的一些问题。我相信因果推理在伦理人工智能的发展中有一定的作用。事实上,我最近描述了神经科学和批判理论如何能够启发基于突触可塑性的道德人工智能系统,这些系统使用因果推理。最近的研究加强了这一观点,即因果关系可以提供一种识别和减轻偏见的方法。然而,最终还是要靠公司和从业者来利用我在本文中描述的一些因果方法。我希望这些因果驱动的技术能够成为标准实践。

目前,我主要关注的是使用 NLP 进行因果推理的潜力。然而,在没有首先解决鲁棒性、公平性和可解释性问题的情况下,追求将 NLP 模型用于因果社会科学研究是不负责任的。完成我的尽职调查后,我打算回到我的第一篇文章中关于因果推理和 NLP 的观点。由于这一领域的研究刚刚开始获得牵引力,因此缺乏实用教程来帮助数据科学家将这些想法融入他们自己的工作中。因此,我的下一篇文章将是如何使用 NLP 估计因果关系的实际 Python 代码演练。

我欢迎反馈和问题,请随时通过 Linkedin 与我联系。

改进 Deutsch 和 Jozsa 量子算法

原文:https://towardsdatascience.com/improving-the-deutsch-and-jozsa-quantum-algorithm-760b2dab12b3?source=collection_archive---------30-----------------------

一个著名量子算法的实践指南

量子机器学习要不要入门?看看 动手用 Python 学习量子机器。

之前的一篇文章中,我们了解了由 David Deutsch 和 Richard Jozsa 开发的算法。第一批证明量子算法如何比经典算法快一倍的算法之一。

作者图片

该算法在一次运行中评估我们提供的输入是恒定的还是平衡的。作为一个例子,我们看了一枚硬币。要说一枚硬币是否公平,还得多次折腾评估。另一方面,Deutsch-Jozsa 量子算法只计算一次。

然而,该算法有一些缺点。

首先,我们用完全不同的神谕来表示公平和欺骗的硬币。所以,在创造量子电路时,我们必须决定硬币是公平的还是被欺骗的。

第二,我们没有一个量子位来告诉我们硬币是否公平。相反,我们必须测量三个量子位。

第三,当神谕将量子位置于代表其输入值的状态时,该输入值并不用于决定硬币是公平的还是被欺骗的。我们甚至可以跳过将量子位放入正确状态的步骤。只要我们选择正确的先知,这个算法仍然可以工作。

总而言之,在运行量子电路之前,我们需要决定甲骨文(常数/狡猾或平衡/公平),量子电路应该会告诉我们我们拥有哪种硬币。

所以,让我们解决这些缺点。

我们从设置开始。在这里,我们从 Qiskit 导入所有需要的库。

接下来,我们创建我们的广义甲骨文。它将两个量子寄存器和配置(config)作为参数。量子寄存器包含量子位,允许我们使用它们。config包含一个由01组成的字符串。每个数字代表我们要分类的函数的一个输出——或者如果你愿意,也可以是投掷硬币的结果。

如果字符串包含三个0或三个1,则为常量函数(或骗币)。如果字符串至少包含一个0和一个1,则为平衡函数(或公平币)。

oracle功能中,我们评估config字符串(第 6 行)的每个位置。注意这一点很重要,因为它解决了我们提到的第一个缺点。在量子电路的准备过程中,我们不会在任何时候使用整个配置字符串。相反,我们让量子算法来评估整个字符串是恒定的还是平衡的。

对于config串中的每个位置(即1),我们应用一个受控非门,其中代表掷的量子位作为控制量子位,辅助量子位作为目标量子位。

显而易见的问题是:“我们为什么要这样做?”

在我们回答这个问题之前,我们应该看看整个量子电路。但是,在应用 oracle 之前,只需关注量子位的初始化(第 8-13 行)。

下图描述了两个量子位系统(仅一个 toss)的初始化和 oracle。

作者形象

"那么,这样的电路是做什么的?"首先,我们把上面的量子比特放入|+⟩州,把下面的量子比特(辅助)放入|−⟩.州在这些状态下,我们以 50%的几率将每个量子位测量为01。唯一的区别是量子位相位。

当我们应用受控非门时,这种差异很重要。它翻转了|01⟩和|11⟩态的振幅(顶部的量子位在右边)。但是这两种状态的振幅绝对值相等。因此,该门不会影响最终的测量概率。

下图描述了测量概率的变化。

作者形象

我们看到顶部量子位从“关闭”位置开始(意味着 0%的几率被测量为1)。底部的量子位也是如此。但是𝑋门将其翻转到“开”(100%的几率被测量为1)。阿达玛门将两个量子位等同叠加,有 50%的几率被测量为1。受控非门不会改变这些概率。

那么,我们为什么要使用这个门呢?与最初的 Deutsch-Jozsa 算法一样,答案是相位反冲。底部的量子位在|−⟩.州虽然它具有与状态|+⟩相同的绝对振幅,从而具有相同的测量概率,但它的相位是偏移的。看看布洛赫球就知道了。

作者形象

顺便说一下,布洛赫球生动地说明了为什么 x 门没有改变|+⟩和|−⟩.X 门通过 X 轴镜像量子位状态向量。但这两种状态都存在于这个轴上。因此,在 X 轴上反射不会改变任何东西。

但是受控非门会影响控制量子位的相位。下图显示了应用受控非门后量子位的状态。

作者形象

由于甲骨文对config串中的每个1应用了受控非,它有效地翻转了这些量子位的相位,并将它们置于|1⟩.状态但是当我们在config串中有一个0时,神谕什么也不做,把这些量子位留在|+⟩.状态

现在,让我们继续电路的其余部分。下图描述了这部分电路。

作者图片

首先,一连串的哈达玛门将量子位元带回基本状态。如果量子位在|+⟩状态,哈达玛门会把它变成|0⟩.如果我们没有在甲骨文中的这个量子位上应用受控非门,情况就是这样。它代表config字符串中的一个0。如果量子位在|−⟩状态,哈达玛门会把它变成|1⟩.当我们应用受控非门时,情况就是这样,它在我们的字符串中代表一个1

辅助量子位不变。所以,它仍然在|−⟩,哈达玛门把它变成了|1⟩.下面的非门将这个量子位翻转回|0⟩.状态

接下来,我们应用 MCX 门。这是一个多控非门。它需要任意数量的控制量子位和单个目标量子位。它仅对处于|1⟩.状态的所有控制量子位在目标量子位上应用非门这意味着,如果我们的config字符串意味着一个总是返回1的常数函数,我们就将辅助量子位翻转到|1⟩。

接下来,我们用非门翻转三个输入量子位,然后用另一个 MCX 门翻转。现在,如果我们的config字符串暗示一个总是返回0的常数函数,我们将辅助量子位翻转到|1⟩。

仅此而已。如果没有一个 MCX 门将我们的辅助量子位翻转到|1⟩态,我们的输入一定是一个平衡函数。

因此,我们修正了原始 Deutsch-Jozsa 算法的第二个缺点。也就是说,我们看不到单一量子位元的结果。在我们改进的电路中,我们只需要测量辅助量子位。

让我们看一看。下图显示了常量000配置的输出。我们也包括所有量子位元的测量,以说明输入量子位元也有正确的值。

作者图片

我们看到只有辅助量子位导致1。但是所有的输入量子位都是0,因此是不变的。接下来,我们看看常数1函数。

作者图片

我们看到所有量子位的结果都是1,包括辅助量子位。接下来,我们来看一个平衡函数。

作者图片

在这种情况下,一个平衡函数,我们测量辅助量子位为0。下图显示了完整的电路。

作者图片

结论

Deutsch-Jozsa 算法是最早和最著名的量子算法之一。它生动地说明了我们如何使用量子相位反冲来创建一个比经典算法快得多的量子算法。

在这篇文章中,我们解决了原始算法的三个缺点。首先,我们对所有可能的输入使用相同的 oracle 函数。第二,我们可以使用单个(辅助量子位)来衡量输入函数是恒定的还是平衡的。第三,我们用来将输入标记为01的量子门对于它们的输出值以及我们是否将整体函数分类为常数或平衡是决定性的。

Deutsch-Jozsa 算法的这种扩展并不打算以任何方式降低原始性能。Deutsch 和 Jozsa 在 1992 年开发了他们的算法。他们没有学习量子计算的教科书。他们没有模拟器,也没有真正的设备。最重要的是,他们第一时间想出了相位反冲!这个扩展简单地使用它并简化算法的其余部分。

我们本可以进一步简化整个算法。我们可以不用一连串的哈达玛门和受控非门,只需用 x 门将输入量子位放入|1⟩状态。然而,我们不会使用相位反冲。这是算法教给我们的一课。

量子机器学习要不要入门?看看 动手用 Python 学习量子机器

在这里免费获得前三章。

提高 TabNet 的推理速度

原文:https://towardsdatascience.com/improving-the-inference-speed-of-tabnet-971397b74f63?source=collection_archive---------41-----------------------

小窍门

通过修改一行代码来加速 TabNet 推理的简单方法。

TabNet[1]是一个基于深度神经网络(dnn)的表格数据集模型。TabNet 的作者声称,dnn 对于图像数据、序列数据(例如,文本)是成功的,但是当涉及到表格数据时,它的性能比 LGBM 或 XGBM 等梯度增强模型差。作者试图用 dnn 解决这个问题。他们可以为表格数据集开发一种新的基于 dnn 的模型,并表明 TabNet 的性能明显优于梯度推进模型。此外,TabNet 在一项 Kaggle 竞赛中提供了其卓越的性能——动作预测机制[2]。

尽管 TabNet 的性能很好,但它有一个弱点——推理速度慢。我先解释一下为什么推理速度慢(如果不感兴趣可以跳到下一段下一段)。由于其特征选择步骤,TabNet 很慢。TabNet 使用“sparsemax”[3]选择其特征,对于向量\(z\),sparse max 定义为:

sparsemax_i(z) = [z_i - \tau(z)]_+ 

Sparsemax 输出稀疏概率,这在进行特征选择时很有用。例如,假设我们有 3 个特征(A、B 和 C),只有 A 与预测相关。在这种情况下,sparsemax 在 A 上分配概率 1,在 B 和 C 上分配概率 0,以便只处理合适的特征。我们在 softmax 上没有看到这种趋势。

现在,我们来谈谈为什么 sparsemax 会让 TabNet 变慢。慢度来自上面函数中的\(\tau(z)\)值。为了获得\(\tau(z)\),它涉及排序和搜索时间复杂度分别为 O(n*log(n))和 O(n)的最大值,其中\(n\)是向量\(z\)的长度。

那么,我们该如何解决这个问题呢?我建议使用 softmax 而不是 sparsemax,但要用 multiplier \(m\)

softmax_i(z,m) = exp(m*z_i)/(exp(m*z_1)+...+exp(m*z_n))

Sparsemax V softmax:从左到右,乘数分别设置为 3、1 和 5。z 的长度是 2。

上图显示了 sparsemax 和 softmax 之间的比较。正如 sparsemax[3]的作者所声称的,sparsemax 在创建稀疏概率方面可以比乘数为 1 的 softmax 执行得更好。然而,当我们增加乘数幅度时,softmax 相当好地逼近 sparsemax,尤其是当乘数等于 3 时。此外,计算 softmax 比计算 sparsemax 要快得多。因此,我们可以期待快速的推理速度!

性能对比:我将这个修改版的 TabNet 应用于 Kaggle 竞赛,简街市场预测[4]。在那场比赛中,一个人需要在 16 毫秒内决定是否接受金融交易机会,给出的数据是表格。虽然这是一个金融交易决策问题,但我不认为它可以用时间序列来表述,因为大部分数据都是匿名的:匿名的特征、匿名的证券类型、匿名的市场等等。不管怎样,我能得到 7990.420 分,而其他人只能得到 5000 分。在比赛中,大多数人因为 TabNet 的推理时间慢而停止使用它,而我利用了 softmax 的快速推理。

综上所述,我建议使用带乘法器的 softmax 来提高 TabNet 的推理速度。虽然我没有将它应用于许多其他数据集,但它似乎不会因为使用 softmax 和 multiplier 而降低性能;它有时会提高性能。

请务必让我知道,如果你发现任何错误或如何在媒体中键入数学方程式。感谢您阅读我的文章。

参考

[1] Arik,S.O .和 Pfister,t .,2019 年。Tabnet:专注的可解释表格学习。 arXiv 预印本 arXiv:1908.07442

[2]卡格尔。2020.作用机制(MoA)预测。https://www.kaggle.com/c/lish-moa

[3] Martins,a .和 Astudillo,r .,2016 年 6 月。从 softmax 到 sparsemax:注意力和多标签分类的稀疏模型。在机器学习国际会议(第 1614–1623 页)。PMLR。

[4]卡格尔。2021.简街市场预测。https://www.kaggle.com/c/jane-street-market-prediction

为鸟类改善世界

原文:https://towardsdatascience.com/improving-the-world-for-birds-3ab0ecbdbe21?source=collection_archive---------28-----------------------

变更数据

一次一只捕食者

怀塔克里山脉的惠亚湾。得到凯莉·贝内特许可的照片

想象一下,就一会儿,你可以通过在你的社区做一些小事来改变现状。这就是成千上万的新西兰人在全国各地所做的,他们一起努力捕捉入侵的食肉动物。新西兰是一个鸟类之国,但负鼠、老鼠、刺猬和鼬(雪貂、黄鼠狼和白鼬)已经大量减少了鸟类的数量,并且在许多地区还破坏了原始森林。新西兰人正在夺回国家,改善鸟类的世界,一次一个捕食者。只需要一点时间,正确的诱捕方法和足够多的邻居。

新西兰“干净、绿色”的形象有点像神话。今天的国家是一个高度改良的环境,其中最深刻的改变是哺乳动物的引入。政府保护部门记录了澳大利亚的刷尾负鼠,不仅严重破坏了标志性的本土树木,如 Pohutukawa ,还吃掉鸟蛋甚至雏鸟。在这段视频中,kea 保护基金会记录了负鼠对活着的 Kea 雏鸟的捕食。

刺猬通常被认为是可爱的,虽然它们在英国受到保护,但在新西兰,刺猬攻击南岛辫状河上的涉禽巢穴,并吃掉大量的本地无脊椎动物。当亚南极山毛榉森林或罗汉松森林有所谓的“肥大年”时,船鼠、挪威鼠和老鼠繁殖迅速,它们的数量激增。这些啮齿动物是贪婪的掠食者,不仅捕食鸟蛋,还捕食当地特有的昆虫,如湿地鼠和本地石龙子。视频中甚至有老鼠啃食活信天翁幼鸟的记录。

白鼬和其他鼬类动物,如雪貂和黄鼠狼,是最凶残的外来食肉动物。它们不寻常的生殖系统允许它们优化利用现有的食物,它们在肥大的年份享用老鼠爆发的食物。众所周知,它们很难被捕获。

在新西兰捕捉捕食者有一个不寻常的方面,那就是将努力转化为一个公民科学项目。许多人统计他们的诱捕捕获量,并将它们输入数据库。有几个应用程序可用于记录和总结捕获量。在某些情况下,这些应用程序还提供有毒杂草和鸟类的数量。

这些数据本身对于追踪减少或甚至从景观中消除入侵捕食者的进展非常有用。在某些情况下,消灭是可能的,新西兰已经在世界上率先消灭了隐藏着珍贵本土动植物的近海岛屿上的食肉动物。捕食者自由 2050 是一个政府资助的项目,有着更广泛的抱负仍然有争议。无论最终是否有可能从新西兰消灭捕食者,无可争议的是,邻里诱捕具有减少当地捕食者数量和改善鸟类生活环境的潜力。

将陷阱与摄像机配对

动物的行为很复杂,通过使用野生动物摄像机观察陷阱周围的行为,可以提高邻里诱捕的成功率。在 Waitakere 山脉的 Huia 进行诱捕时拍摄的镜头很有启发性。

在这个视频中,老鼠研究了一个自动化的 Goodnature A24 陷阱。然后,一只负鼠试图袭击陷阱,触发装置,产生一个错误的捕杀记录。第二天晚上,一只老鼠被 A24 捕鼠器杀死,第二天早上,尸体被一只猫吃掉了,没有尸体。如果没有录像,就不可能知道一个是假杀,一个是真杀。

下一个视频解决了一个谜,一个捕鼠笼陷阱被触发,诱饵被移走,但陷阱里什么也没有。为了确定谁该负责,我安装了一个摄像头。答案是老鼠触发陷阱并吃掉诱饵,而老鼠和一只乌鸫也从陷阱内外同时吃掉诱饵。这个问题是通过在鼠笼附近设置捕鼠夹来解决的。

另一个问题是诱饵是从捕鼠夹里偷出来的。这段视频展示了一只大的雄性老鼠在一只负鼠到来之前从捕鼠夹里偷取野生饲料诱饵。解决办法是在负鼠陷阱附近放置一些捕鼠器,以杀死诱饵袭击者。

在下一个视频例子中,诱饵从 Goodnature A24 自动捕鼠器中消失,一台摄像机让我确定罪犯是老鼠。一只刺猬的死亡证明了捕鼠器已经装好并且正在工作,这只刺猬尝试了和老鼠一样的把戏。

最后,运动感应相机可能会捕捉到尚未被捕捉到的重要掠食者。在这个例子中,相机捕捉到一只白鼬。这是非常重要的信息,因为白鼬很怕陷阱,通常只对用整只蛋做诱饵的陷阱感兴趣。它们是新西兰最具破坏性的哺乳动物掠食者。

摄像机截图显示一只尚未被陷阱捕获的白鼬。照片由惠亚陷阱组的戴夫·明蒂许可。

视频显示白鼬拿一个鸡蛋。视频许可戴夫明蒂,惠亚陷阱组。

数据探索

经过三年的邻近诱捕,我们现在在 Huia 有超过 1000 次捕获,所以我们可以对数据提出一些探索性的问题。首先,我们在抓什么?答案主要是大鼠和小鼠(图 1B 和 A),刺猬(图 1C)和负鼠(图 1D)少得多。老鼠是最丰富的捕获物(图 1B)。第二个问题是捕获量是否有季节性?有了四年的数据,捕鼠的季节模式很明显(图 1A),但老鼠、刺猬或负鼠没有明显的季节模式。老鼠在冬天更容易被抓到(图 1A)。也有一些迹象表明,更多的老鼠是在秋季或冬季被捕获的,尽管与老鼠相比,这种模式在不同年份之间变化更大(图 1B)。

图 1:在过去的 4 年中,新西兰怀塔克里山脉的休伊阿地区的邻里捕获组捕获的捕食者。所有这些食肉动物都是已知会破坏鸟类生活的哺乳动物。这项诱捕行动是对新西兰政府保护部 2050 年无捕食者行动的自愿贡献。

密码

使用 tidyverse 系统用 R 编写了这个初步分析的代码。的完整剧本可以在这里下载。代码的解释如下。

加载必要的库:

*# plot_catches
library*(tidyverse)
*library*(tibbletime)
*library*(lubridate)
*library*(gridExtra)
*library*(ggthemes)
*library*(ggpubr) 

原始数据是从我们的 Huia 项目中导出的。新西兰网站。这段代码使用的数据可以从这里下载

*# load raw data* series <- *read_csv*("./data/export.csv")

陷阱存储的数据。由于储存的方式,新西兰需要一些操作。日期以字符形式存储,渔获量作为一个称为“捕获的物种”的单一变量存储,而不是作为每个物种的单独变量存储,这很不方便。

以下代码将导出的数据转换为结构合理的时间表,每个物种有单独的变量:

*# keep the required variables* series2 <- *select*(series, Date, "Trap type", "Trap", "Recorded by", "Species caught")

*# create new variable  with Date in the correct format,
# and new variables for catches by species* series2 <- *mutate* (series2,
                   date = *dmy_hm*(Date, tz = "Pacific/Auckland"),
                   rats = *ifelse* (series2$"Species caught" %in% *c* ("Rat", "Rat - Ship", "Rat - Norway"), 1, NA),
                   mice = *ifelse* (series2$"Species caught" == "Mouse", 1,NA),
                   possums = *ifelse* (series2$"Species caught" == "Possum", 1,NA),
                   hedgehogs = *ifelse* (series2$"Species caught" == "Hedgehog", 1,NA),
                   scavenged = *ifelse* (series2$"Species caught" == "Unspecified", 1, NA)
)
*# convert tibble to tibble time
# summarize catches by time interval* series2 <- *as_tbl_time*(series2, index = date)
series2 <- *arrange*(series2, date)

*# keep the required variables* series2 <- *select*(series2, date, rats, mice, possums, hedgehogs, scavenged)

现在,时间变量可用于方便地将数据分组为四分之一年的季节:

grouped_data <- *collapse_by*(series2, "quarterly") %>%
  dplyr::*group_by*(date) %>%
  dplyr::*summarise_all*(sum, na.rm=TRUE)

接下来,绘制数据:

*# Plots* mp <- *ggplot*(grouped_data, *aes*(x = date, y = mice)) +
  *geom_bar*(stat = "identity") +
  *geom_bar*(stat="identity", fill="darkblue") +
  *annotate*("text", x = grouped_data$date[1:16], y = -12,
           label = *rep*(*c*("Spring","Summer","Autumn","Winter"),4),
           size=3.5, angle = 70) +
  *ylim*(-20,80) +
  *theme_hc*(base_size = 18)

rp <- *ggplot*(grouped_data, *aes*(x = date, y = rats)) +
  *geom_bar*(stat = "identity") +
  *geom_bar*(stat="identity", fill="dark gray") +
  *annotate*("text", x = grouped_data$date[1:16], y = -12,
           label = *rep*(*c*("Spring","Summer","Autumn","Winter"),4),
           size=3.5, angle = 70) +
  *ylim*(-20,80) +
  *theme_hc*(base_size = 18)

hp <- *ggplot*(grouped_data, *aes*(x = date, y = hedgehogs)) +
  *geom_bar*(stat = "identity") +
  *geom_bar*(stat="identity", fill="dark gray") +
  *annotate*("text", x = grouped_data$date[1:16], y = -12,
           label = *rep*(*c*("Spring","Summer","Autumn","Winter"),4),
           size=3.5, angle = 70) +
  *ylim*(-20,80) +
  *theme_hc*(base_size = 18)

pp<- *ggplot*(grouped_data, *aes*(x = date, y = possums)) +
  *geom_bar*(stat = "identity") +
  *geom_bar*(stat="identity", fill="dark gray") +
  *annotate*("text", x = grouped_data$date[1:16], y = -12,
           label = *rep*(*c*("Spring","Summer","Autumn","Winter"),4),
           size=3.5, angle = 70) +
  *ylim*(-20,80) +
  *theme_hc*(base_size = 18)

sc<- *ggplot*(grouped_data, *aes*(x = date, y = scavenged)) +
  *geom_bar*(stat = "identity") +
  *geom_bar*(stat="identity", fill="dark gray") +
  *annotate*("text", x = grouped_data$date[1:16], y = -12,
           label = *rep*(*c*("Spring","Summer","Autumn","Winter"),4),
           size=2.5, angle = 70) +
  *ylim*(-20,80)

*# layout plots on the page
ggarrange*(mp, rp, hp, pp,
          labels = *c*("A", "B", "C", "D"),
          ncol = 2, nrow = 2)

本文描述了一个简单的探索性数据分析。从这些数据中可以得出更多信息。我们将在后续的文章中进一步探讨这个问题。

结论

最后,我要强调的是,将相机与陷阱配对,为揭示动物行为增加了一个额外的维度。对陷阱周围动物行为的了解使得诱捕策略得以改进,使其更加有效。相机也可能揭示惊喜,如隐形,难以捕捉的捕食者。有了这些知识,就可以有针对性地把注意力放在那些害怕陷阱的动物身上。

数据的收集和管理对于保护工作非常重要。没有渔获量的数据,就不可能制定指标来衡量诱捕努力的成功。通过将诱捕数据与对鸟类鸣声的环境监测配对,有可能确定邻里诱捕努力是否达到了改善鸟类世界的预期效果,一次一只捕食者。

改进对比表征学习中的变换不变性

原文:https://towardsdatascience.com/improving-transformation-invariance-in-contrastive-representation-learning-63f881ea1ac2?source=collection_archive---------31-----------------------

转换不变性对对比学习有什么作用?

在这篇博文中,我想快速回顾一下我最近与 Adam Foster 和 Tom Rainforth 合作的关于提高对比表征学习中的转换不变性的工作,我们试图回答“转换不变性在对比学习中的作用是什么?”我们的方法是加强更强的不变性,并表明这导致下游任务的性能提高。

我们的方法是加强更强的不变性,并表明这导致下游任务的性能提高。

对比学习

对比学习是一种自我监督的方法,通过利用来自未标记数据的信号来学习有用的数据表示。为了评估这种方法,我们重新引入标签,并在冻结的表示上安装线性分类器。最近的对比学习方法已经在这个评估任务上实现了最先进的性能,并且几乎消除了与监督学习的差距,例如 SimCLRMoCo 。这些方法的主要思想是学习对诸如随机裁剪或旋转之类的有害变换不变的表示。我们问了以下问题

  1. 我们能在这种对比环境中提高不变性吗?
  2. 不变性越强,性能越好吗?

SimCLR 体系结构学习用不同的变换来匹配相同输入的低维投影。—作者图片

这些方法的主要思想是学习对诸如随机裁剪或旋转之类的有害变换不变的表示。

我们的方法

我们提出了 2 个想法 1)一个新的梯度正则化 2)特征平均来鼓励更强的不变性。我们另外提出了一个新的数据集 Spirograph 来探索我们在完全可微分的生成过程中的想法。

变换不变性是什么样子的?这里我们看到了相同输入的不同转换,我们希望它们的表示接近。

作者图片

梯度正则化子

我们感兴趣的许多变换(例如颜色失真)是可微的,并且由连续参数α控制。如果我们用一个变换参数α,z_α来调用一个输入的表示,我们可以通过条件方差正式地测量该表示如何随着变换的变化而变化

我们想把这一项减到最小,这样当我们应用不同的变换时,表示就不会有太大的变化。

由于变换是可微的,我们可以取表示相对于α 的梯度。鼓励这个梯度变小将使表示随着变换的改变而缓慢改变。在本文中,我们在这个梯度和条件方差的近似值之间建立了联系。我们的最后一个正则项是不同输入的近似条件方差,以促进输入之间的不变性。

梯度相对于α的条件方差的近似值。

梯度正则化-利用相对于变换参数的梯度来近似条件方差。—作者图片

由于变换是可微的,我们可以取表示关于α的梯度。鼓励这个梯度变小将使表示随着变换的改变而缓慢改变。

特征平均

对于测试时间,标准协议是使用来自未转换输入的表示。我们建议,在测试期间利用转换,对来自同一输入的不同转换的多个表示进行平均。该方法产生了一个强不变的表示
,包括不可微的变换(例如随机水平翻转),因此在第一个想法中不能被正则化。

要素平均-相同输入但使用不同变换的平均表示。—作者图片

我们建议,在测试期间利用转换,对来自同一输入的不同转换的多个表示进行平均。

肺活量记录仪

肺活量描记器的产生。

受 spirograph 模式的启发,我们提出了一个新的数据集,该数据集允许从有害转换因子 (6 个因子)中分离出感兴趣的生成因子 (4 个因子),并由完全可微分的生成过程形成。

下游任务是使用冻结表示上的线性回归来恢复生成因子。下图显示了具有相同生成因子但具有不同变换因子的肺活量图。

肺活量图数据集的样本。两组四幅图像(左和右):每组
显示应用于感兴趣的相同生成因子的不同变换。—作者图片

这里讨厌的变换超出了改变纹理的传统变换,即相同输入的颜色。螺旋图变换也使用相同的生成因子改变图像的结构,如下所示。这允许我们在不变性确实存在的地方探索变换不变性的贡献。

仅改变变换参数 h 对相同生成因子的影响。—作者图片

实验

我们将展示我们在 CIFAR-10、CIFAR-100 和 spirograph 数据集上的实验结果。让我们回到我们的问题

我们能在这种对比环境中提高不变性吗?

是的,有可能学到更强的不变性。如图所示,我们的梯度正则化有效地降低了 CIFAR-10 上的条件方差。

CIFAR-10 的条件方差

不变性越强,性能越好吗?

是的,梯度正则化和特征平均都能带来更好的下游性能。

不同数据集上半监督任务的梯度正则化性能

不同数据集的特征平均性能,其中虚线表示来自未转换输入的表示性能。

当结合我们的两种方法时,我们在 CIFAR-10、CIFAR-100 数据集上实现了一流的性能。

对测试时引入不可见转换的鲁棒性

除了改进下游性能之外,我们发现我们的正则化器还导致对变换参数α的移动更鲁棒的表示,例如,移动α分布的均值,增加α分布的方差。

密码

您可以在这里找到可复制的代码

使用分层位置编码改进用户界面布局理解

原文:https://towardsdatascience.com/improving-ui-layout-understanding-with-hierarchical-positional-encodings-b19e1e9235e?source=collection_archive---------14-----------------------

思想和理论

我们如何为以用户界面为中心的任务修改转换器?

【杰森·李】**【康纳约翰逊】 ,以及 瓦伦奈尔

用户界面包含丰富的元素层次结构,可以用基于树的表示进行编码。(图片由作者提供)

布局理解是人工智能的一个子领域,它使机器能够更好地处理布局中的语义和信息,如用户界面(ui)、文本文档、表格、演示幻灯片、图形设计组合等。许多公司已经在他们的网络/移动应用的用户界面和用户体验上投入了大量的资源(UX),据《快速公司》报道,在 UX 上投入的每 1 美元可以获得 2-100 倍的投资回报。因此,人工智能和深度学习工具有很大的潜力来帮助和加速迭代设计过程。

在这篇博客文章中,我们将分享我们的发现和教训,利用基于深度学习的布局理解模型来完成以用户界面为中心的任务。这项研究是与位于 Uizard 的机器智能团队合作进行的。

具体来说,我们重点研究如何改变变压器模型的位置编码( Vaswani,2017 ),以编码更好的布局表示。我们强调:

  • 用户界面的分层信息是丰富的信息源,可以使用新颖的位置嵌入(Shiv&Quirk,2020 )注入到变压器模型中。
  • 处理好 UI 领域特有的特性将是成功训练模型的关键。

这是一个相对未探索的领域,仍有许多工作要做——我们希望使用这篇短文来指导未来对布局理解的研究,并释放深度学习在设计领域的更多潜力。

我们将首先完成一些与 UI 布局理解相关的任务,然后分享一些我们认为有用的论文背景,最后更详细地讨论上面列出的要点。

相关任务

当试图在 transformer 模型中构建良好的 UI 布局表示时,考虑数据集和许多类型的任务来帮助构建这些表示是很重要的。我们使用 RICO 数据集,这是一个 9.3K Android 应用的数据集,具有超过 66k 个独特 UI 屏幕和 3M+ UI 元素的视觉、文本、结构和交互设计属性。我们还提出了构建布局表示的四个任务,到目前为止已经独立研究过这些任务:

对后续任务有用的布局理解预培训任务示例(左上和右上由 Javier Fuentes Alonso ,左下由 Gupta 等人,2020 ,右下由李等人,2020 )。

令牌分类

在令牌分类中,除了一个目标元素之外,所有 UI 元素的类名都会呈现给我们,并要求我们预测该目标元素的类。我们还知道所有元素的边界框位置,包括目标元素。

语义分组

在此任务中,我们将看到 UI 元素的类名和边界框位置,并被要求预测输入序列中元素集的分组。例如,给定一个图像、段落和图标,我们可能希望将这个组归类为卡片元素。

布局生成

布局生成遵循我们在 LayoutTransformer ( Gupta 等人,2020 )中研究的工作,通过生成与训练数据集中的示例相似的布局。我们大概可以使用 RICO 数据集训练一个布局生成模型来生成真实的 UI 元素。

层次树生成

该任务遵循李等人在2020中研究的工作,其中基于变换器的树解码器模型用于接受 UI 元素作为输入,并输出元素的层次结构。这个任务可以被认为是语义分组的一个更复杂的版本,其中可以找到其他分组的组并将其分配给一个树。

虽然我们在工作中没有尝试所有这些任务,但我们希望这能给出对理解布局有用的任务类型的一般概念。采用多任务学习框架,类似于文本到文本转换转换器 (T5)模型,这些任务甚至可以通过一个模型来组合和解决。我们下面的发现将讨论标记分类(即序列标记)任务。

相关著作

除了上面的任务之外,这里有几篇论文为我们在布局理解方面的工作提供了信息。我们在下面提供了最有影响力的几部作品的摘要和其他作品的链接。

LayoutLM

LayoutLM 模型的架构深受 BERT 的启发,同时结合了来自更快的 R-CNN 模型的图像嵌入。LayoutLM 输入嵌入作为文本和位置嵌入的组合生成,然后与图像嵌入组合。屏蔽视觉语言模型(受原始 MLM 的启发)和多标签文档分类模型(模型如何很好地聚类相似的文档)主要用作 LayoutLM 的预训练任务。LayoutLM 模型对于版面理解是足够有用和动态的,表单理解、收据理解和文档图像分类作为下游任务包含在本文中。在我们的例子中,微调的主要下游任务是屏蔽(元素)语言建模,屏蔽表示 UI 的每个元素的标记。

LayoutLM 模型架构—(图片来自徐等,2020 )

原始 LayoutLM 模型在 IIT-CDIP 测试集 1.0 上进行预训练,该测试集包含超过 600 万个文档,以及超过 1100 万个扫描文档图像。正如在相关任务一节中介绍的,我们针对我们的目的对 RICO 数据集上的模型进行了微调。

我们考虑改进 LayoutLM 论文,因为它将现成的 OCR 视为基本事实,这对于从业者来说不太实际。对 OCR 有更大程度的控制可以提供更好的下游任务相关的结果。

CanvasEMB

CanvasEmb 模型的架构——(图片来自谢等,2020 )。

CanvasEMB 是一个大规模、自我监督、预训练的模型,用于学习上下文布局信息,如 LayoutLM,它将布局分解为类型、几何形状、颜色和内容相关属性。该模型可以应用于下游任务,如角色标签和图像字幕(具有 SOTA 性能),也可以用于布局自动完成和布局检索。

在该模型中,从 0 到 N 的每个视觉元素 X_i 由属性元素 0 到 M 组成,这些属性元素被投影并连接成元素嵌入。对于分类属性(类型、颜色),使用嵌入矩阵,对于数字属性,采用正弦位置编码。

该模型基于 BERT 或 LayoutLM 等屏蔽语言建模进行训练,其他微调任务添加了特定于任务的层,如:

  • 元素级别—预测元素的特定特征/属性
  • 元素对元素—预测一对元素之间的关系

该模型根据带标签的数据进行预训练,并根据演示幻灯片数据集进行微调,这意味着与其他模型预训练的文档不同,该模型包含不同类型的语义信息。

支持基于树的变压器的新颖位置编码

这篇论文( Shiv 等人,2020 )提出了一种生成新的位置编码来编码分层信息的技术。在像 RICO 这样的数据集里,用户界面有丰富的层次信息,普通变形金刚中的顺序位置嵌入是不够的。本文针对常规树提出了这种技术,其中形成了类似堆栈的数据结构,并且针对树中向下的每一步将一个向量添加到堆栈中,n 长向量中的一个向量(针对每个节点的 n 个节点)表示当前节点是上一级的下一个分支。****

因为我们不是在处理常规的树(其中每个节点都有相同数量的子节点),所以必须对本文中的技术进行修改,以使其可行。下面将更详细地讨论新颖的位置编码和这些变化的示意图。

调查的结果

#1 —用户界面的分层信息是一个丰富的信息源,可以使用新颖的位置嵌入将其注入到变压器模型中。

用户界面通常在组成它的元素集合中包含丰富的层次结构。例如,一个列表可以包含几个列表项,每个列表项可以包含一个卡片对象,这个卡片对象可以包含一个图像、一个段落和一个图标。我们也不需要一个固定的事实来获得这个信息——如果除了元素类名之外还存在边界框信息,那么我们可以通过查看哪些边界框相互重叠来推断哪些元素是子元素。

我们试图解决的第一个任务是上面的标记分类(即序列标记)任务。我们修改了我们最初研究的模型 LayoutLM,使其能够输入边界框和类标签信息。与大多数传统的 transformer 模型一样,LayoutLM 接受由序列中的位置编码的固定大小的输入。然而,由于我们知道用户界面的层次信息是一个丰富的信息源,我们可以通过将 LayoutLM 方法与基于树的新颖位置嵌入相结合来利用这个信息

Shiv & Quirk,2020 到变压器的基于树的输入的新颖位置编码(图片来自 Shiv & Quirk,2020 )。

直观地说,通过注入关于输入令牌(UI 元素)如何相互关联的附加信息,我们应该能够更好地执行下游任务。否则,该信息可能已经由模型在多个训练步骤之后或者在看到许多示例之后学习到,但是通过在输入中显式地提供它,我们允许模型的参数编码其他(并且希望更有用)表示。

元素之间的关系由 JSON 文件中的 RICO 数据集提供,它告诉我们每个 UI 元素的祖先和子元素。我们找到了树的最大度数(n)和树的最大深度(k ),并为每个示例中的每个元素形成了 n×k 大小的向量,为每个单独节点未使用的每个值添加了填充。这个大小是一致的,因此解码器可以理解这些嵌入。

虽然我们相信有很好的理由通过这些位置嵌入来提高性能(如上所述),但实际上它们很难实现。我们面临的一些挑战包括:

  • 为基于树的位置编码的维度(n 和 k 的值)选择适当的值。
  • 将基于树的位置编码投影到令牌表示的维度(例如 512)以进行拼接。

当实现这些分层位置嵌入时,由于在所有示例中简单使用最大深度和度时位置编码向量的稀疏性,为维度选择适当的值是重要的。我们将在下一节进一步讨论这些挑战。

#2 —处理好特定于用户界面领域的特征将是成功训练模型的关键。

为了探索布局理解模型,我们使用了前面提到的 RICO 数据集,它由超过 66k 个独特的 UI 屏幕的视觉、文本、结构和交互设计属性组成。当探索这样的数据集时,最初的认识是 UI 屏幕并不总是像我们预期的那样出现,例如,它们可能具有非常高的信息密度。下面的示例显示了在 RICO 数据集的任何给定级别上具有最大节点数的 UI:421。

下面的示例显示了在 RICO 数据集的任何给定级别上具有最大节点数的 UI—总共 421 个。(图片由作者提供)。

当使基于树的位置嵌入适应于非规则树(其中每个节点可以有不同数量的孩子)时,一个考虑是存储器使用。为异常值示例添加的填充如果过多,在微调变压器时会给计算带来很大压力。回想一下,我们的基于树的位置嵌入向量的维数和填充是数据集中任何单个节点(包括根)的总最大深度和总最大分支的乘积。

在下面的方框图中,我们看到绝大多数 UI 屏幕的元素层次最多有 25 个分支或者更少。如果我们保留离群值,位置嵌入向量的维数将大几个数量级。在 80/20 训练测试分割且没有过滤的情况下,包含训练示例的位置嵌入向量的文本文件是 3.09 千兆字节,其在投影层中被投影为 631.40 千兆字节。通过过滤具有最多 80 个分支的示例,我们能够将每个向量的维数从 2947 (4217)减少到 560 (807),由于填充和削减存储嵌入的存储器,使得向量不那么稀疏,减少了 80%以上。虽然过滤减少了内存占用,但使用 560 的令牌嵌入维度仍然会导致向量投影到 79.11 千兆字节,远远超过(我们的)典型 GPU 上可用的 16 千兆字节内存。**

RICO 数据集中示例树层次结构中节点的最大分支数量的箱线图(图片由作者提供)。

有了这些信息,改进模型在 RICO 数据集上的微调方式的一个可能的解决方案是在进一步使用的示例中过滤最大数量的节点(从 421 个节点到 25 个节点),以便更好地反映数据集本身的分布。另一种方法是从数据集中移除被认为是“装饰性元素”的内容。对数据集的分析显示,所有叶子(没有子节点的节点)的 39%多一点存在于数据集中的第一级树上。

我们还可以通过限制层次结构的深度来过滤 RICO 数据集中的元素。虽然最大深度是 7,但超过 99%的叶子都集中在每个示例树的前三层,这意味着很少有分支到达第 7 层甚至第 4 层(0.6%的叶子位于该层)。

总之,过滤数据集中使用了哪些示例以及每个示例中包含了哪些节点的信息会导致有价值的语义信息的显著丢失,这些信息有助于识别复杂的 UI 元素分组。然而,保留所有信息会在训练时导致严重的内存问题,我们认为过滤是对 RICO 数据集上的 LayoutLM 等模型进行微调以执行相关下游任务的必要的第一步。

未来的工作

布局理解是一个子领域,在未来的几年里已经成熟,可以取得更大的进步,我们希望这项工作能够展示一些潜力。最近将 LayoutLM 添加到 HuggingFace transformers 库中也应该允许研究社区进行更快的迭代。总结一下:

  • 用户界面的分层信息是一个丰富的信息源,可以使用新颖的位置嵌入将其注入到变压器模型中。
  • 处理好特定于用户界面领域的特征将是成功训练模型的关键。

如相关任务部分所述,布局理解任务可以在多任务训练中结合起来,以获得更好的表征学习(类似于 T5 模型, Raffel 等人,2020 )。其他未来的工作包括试验其他形式的位置嵌入,并将这项工作扩展到下一代版本的 LayoutLM (LayoutLMv2 — 徐等人,2020 )。

承认

感谢 Javier Fuentes Alonso、Arturo Arranz 和 Tony Beltramelli 在过去几个月对这项工作的支持。要了解更多关于 Uizard 如何将机器学习应用到设计中,请查看 Uizard 的研究页面这里

这篇文章的作者也是杜克应用机器学习(DAML)的成员,这是杜克大学的一个学生团体,致力于应用人工智能项目和研究——点击这里了解更多关于 DAML 的信息。

使用 Python 中的堆叠条形图改进数据可视化

原文:https://towardsdatascience.com/improving-your-data-visualizations-with-stacked-bar-charts-in-python-f18e2b2b9b70?source=collection_archive---------23-----------------------

大蟒

使用 pandas 和 Plotly Express 可视化分类数据并显示数据集的趋势

我才华横溢的姐姐的作品

仅仅看表中的数字可能会使识别数据集中的趋势变得困难。可视化数据使人们更容易快速理解关键思想。数据可视化的一个重要部分是根据正在分析的数据类型选择正确的图表类型。

标准散点图、折线图和条形图非常适合可视化各种数值和分类数据。您可以通过添加附加功能来改进这些基本图表,使最终用户更容易理解数据。

在这篇文章中,让我们来看看如何使用 Python 中的 Plotly Express 库来创建和定制堆积条形图以实现数据可视化。我们还将使用 Pandas 库进行一些数据预处理步骤,所以请确保您已经安装了这两个包。然后,导入以下内容,并准备好在您自己的 Jupyter 笔记本上继续学习!

import pandas as pd
import plotly.express as px
import random

我们开始吧!

用 Plotly Express 实现简单的堆积条形图

首先,让我们生成一些样本数据,用于我们的数据分析和可视化。为此,请运行以下代码。

expense_data = {
    "Person": random.choices(["A", "B"], k=30),
    "Amount": random.sample(range(100, 200), 10) + random.sample(range(0, 99), 10) + random.sample(range(49, 499), 10),
    "Category": ["Groceries"] * 10 + ["Restaurant"] * 10 + ["Appliances"] * 10,
    "Date": pd.to_datetime(pd.date_range('2020-01-01','2020-10-01', freq='MS').tolist() * 3)
}
df = pd.DataFrame(data=expense_data)

作者图片

在这篇文章中,我们将分析和可视化一些随机生成的个人支出数据。该代码应该生成一个 Pandas 数据框架,其中包含一段时间内三个不同类别的 30 行费用。

此数据分析的目标是检查每个月每个类别的支出,并潜在地确定一段时间内发生的趋势。因此,让我们用一些熊猫来对每个类别每月的总支出进行分组。您可以使用下面的两行代码来做到这一点。

df_grouped = df.groupby(by=[pd.Grouper(key="Date", freq="1M"), "Category"])["Amount"]
df_grouped = df_grouped.sum().reset_index()

作者图片

现在我们的数据已经被处理以适应我们最初的问题,我们可以直接进入可视化数据。Plotly 库使看起来干净的可视化比你用 Pandas(或 matplotlib)创建的标准图形更有风格。Plotly Express 更进了一步,使创建可视化变得简单得可笑。我们将用下面的一行代码创建初始图表。

fig = px.bar(df_grouped, x="Date", y="Amount", color="Category")
fig.show()

作者图片

bar方法的第一个输入是我们刚刚创建的分组数据帧。然后,我们将数据帧中的列名传递给bar方法的xy参数。最后,要实现堆叠条形图,我们需要做的就是将想要堆叠的列名传递到color参数中。

通过填写可选的barmode参数,您可以进一步定制堆积条形图。你可以在下面看到一个例子和结果图。

fig2 = px.bar(df_grouped, x="Date", y="Amount", color="Category", barmode="group")
fig2.show()

作者图片

group作为参数传递给barmode给我们一个类似上面的图,其中每个月的每个类别的费用条并排分组,而不是垂直堆叠。

有四个可能的选项可以传入 **barmode** :堆栈、组、覆盖和相对。作为探索性数据分析阶段的一个示例,您可以运行以下代码来查看条形图的所有不同选项。

barmodes = ["stack", "group", "overlay", "relative"]
for barmode in barmodes:
    fig_bar = px.bar(df_grouped, x="Date", y="Amount", color="Category", barmode=barmode)
    fig_bar.show()

作者图片

作者图片

作者图片

作者图片

每个条形模式选项显示的图形略有不同。“相对”栏模式仅在您有负值时才相关,因为此模式将导致 Plotly 在轴下方显示负值的相关类别。

您可以将上面的代码块封装到一个函数中,然后作为探索性数据分析(EDA)的一部分在您的数据上运行它,在这里您还可以找出这些图形中的哪一个最适合您正在查看的数据。然后,一旦你决定了哪种条形模式最适合你,你可以选择只生成一个图形或者从你的笔记本中将图形导出为 png(这是 Plotly Express 的一个便利特性)。

使用 Plotly Express 在堆叠条形图中实现附加功能

我们来看看条形图的其他一些功能,让我们继续分析我们的样本数据并比较一段时间内的人均支出数据。为此,我们将使用与之前相同的groupby方法再次对数据进行分组。

df_people = df.groupby(by=[pd.Grouper(key="Date", freq="1M"), "Person"])["Amount"]
df_people = df_people.sum().reset_index()

作者图片

得到的数据框架将给出我们数据集中每人每月的总支出。我们现在可以像以前一样将这个数据帧插入到 Plotly bar方法中,但是有一个小的增加。

fig_people = px.bar(df_people, x="Date", y="Amount", color="Person", barmode="stack", text="Amount")
fig_people.show()

作者图片

通过这张图表,我们现在可以清楚地看到哪个人每月花费更多。因为我们处理的是财务数据,所以将每个类别的金额直接显示在条形图上可能会有用(而不必从轴上猜测大致的金额)。

为此,我们将bar方法中的text参数设置为我们希望显示为条形标签的列,在本例中是“Amount”。然后,您可能会从图表中删除 y 轴,因为它现在是多余的,因为文本标签直接在列上。

通过分析每个类别的人均支出,我们可以探索 Plotly Express 中条形图的最后一个特性。我们将通过运行下面的代码,首先将我们的数据按类别和人员分组到一个新的数据框架中。

df_category = df.groupby(["Category", "Person"]).sum().reset_index()

作者图片

现在,使用这个分组的数据帧,我们可以使用相同的 Plotly express bar方法,使用我们到目前为止探索过的特性,但是增加了一些内容。

fig_category = px.bar(df_category, x="Amount", y="Person", color="Category", text="Amount", orientation="h")
fig_category = fig_category.update_traces(insidetextanchor="middle", texttemplate="$%{text}")
fig_category = fig_category.update_xaxes(visible=False, showticklabels=False)
fig_category.show()

作者图片

首先,您将看到我们创建了一个水平条形图,而不是我们以前使用的垂直格式。我们所要做的就是将“h”传递给 bar 方法中的参数orientation。然后,我们还想再次拥有文本标签,但是为了确保文本标签出现在条形标签的中间,我们将使用update_traces方法,并将“中间”传递给insidetextanchor参数。

此外,我们可以通过在update_traces方法的texttemplate参数中设置文本标签的自定义格式。我们将简单地在标签前添加一个美元符号,所以在这种情况下,我们传入"$%{text}",因为在 Plotly Express 中,您可以通过使用百分号后跟括号中的列名来引用列。

最后,由于我们已经添加了一个美元符号来使条形值非常清楚,我们可以继续使用update_xaxes方法并设置visibleshowticklabels参数为“False”来删除带有“Amount”列值的轴。

仅此而已!

我希望你会发现这个用 Python 编写的关于堆积条形图的快速介绍对你的数据分析很有用。使用 Plotly Express,您只需插入一个 Pandas 数据框架,只需几行代码就可以直接可视化您的数据。

再次感谢您的阅读!如果你正在考虑成为 Medium 的付费会员,如果你使用我下面的推荐链接注册,我会非常感激!这会让直接收到你的一部分会费,所以这将是一个很大的帮助。

https://byrondolon.medium.com/membership

**More by me:** - [Check for a Substring in a Pandas DataFrame](/check-for-a-substring-in-a-pandas-dataframe-column-4b949f64852?sk=bfb5bbab11ae45c47bfb316d931c3b56)
- C[onditional Selection and Assignment With .loc in Pandas](/conditional-selection-and-assignment-with-loc-in-pandas-2a5d17c7765b?sk=e5672d859a3964c1453a1c09edca22cf)
- [2 Easy Ways to Get Tables From a Website With Pandas](/2-easy-ways-to-get-tables-from-a-website-with-pandas-b92fc835e741?sk=9981ddaf0785a79be893b5a1dd3e03dd)
- [Top 4 Repositories on GitHub to Learn Pandas](/top-4-repositories-on-github-to-learn-pandas-1008cb769f77?source=friends_link&sk=d3acc38062490a86ecb46875342224e6)
- [Level Up Your Data Visualizations with Trend Lines in Python](/level-up-your-data-visualizations-with-trend-lines-in-python-6ad4a8253d6?sk=d9174bf7fd3394000acd92289ac41623)
- [Better Data Visualization with Dual Axis Graphs in Python](/better-data-visualization-with-dual-axis-graphs-in-python-a7f35a493558?sk=4e080437f9d29818e25120e287fa550d)

用一行代码将图像匹配结果提高 14%

原文:https://towardsdatascience.com/improving-your-image-matching-results-by-14-with-one-line-of-code-b72ae9ca2b73?source=collection_archive---------1-----------------------

OpenCV 4 . 5 . 1 版包括 BEBLID,这是一个新的本地特性描述符,允许您这样做!

OpenCV 4.5.1 中最令人兴奋的功能之一是 BEBLID(增强的高效二进制局部图像描述符),这是一种新的描述符,能够提高图像匹配的准确性,同时减少执行时间!这篇文章将向你展示这个魔法是如何实现的。所有源代码都存储在这个 GitHub 存储库中:

https://github.com/iago-suarez/beblid-opencv-demo/blob/main/demo.ipynb

在本例中,我们将匹配这两幅因视点变化而相关的图像:

首先,确保安装了正确版本的 OpenCV 是很重要的。在您喜欢的环境中,您可以使用以下命令安装并检查 OpenCV Contrib 版本:

**pip install "opencv-contrib-python>=4.5.1"**
python
>>> import cv2 as cv
>>> print(f"OpenCV Version: {cv.__version__}")
OpenCV Version: 4.5.1

用 Python 加载这两幅图像所需的代码是:

为了评估我们的图像匹配程序,我们需要两幅图像之间正确的(即地面真实)几何变换。这是一个称为单应性的 3×3 矩阵,当我们将第一幅图像中的一个点(在齐次坐标中)相乘时,它会返回第二幅图像中该点的坐标。让我们加载它:

下一步是检测图像中一些容易在其他图像中发现的部分:局部图像特征。在这个例子中,我们将使用快速可靠的检测器 ORB 来检测角点。ORB 检测强角点,在不同的尺度上进行比较,并使用其 FAST 或 Harris 响应来选择最佳角点。它还使用局部面片一阶矩找到每个角点方向。让我们在每幅图像中最多检测 10000 个角:

在下图中,您可以看到用绿点标记的 500 个检测响应最强的角点特征:

干得好!现在是时候用一种我们可以在其他图像中找到的方式来表示这些关键点了。该步骤被称为描述,因为每个角周围的局部小块中的纹理由来自图像上不同操作的数字矢量表示 (即被描述)。有许多描述符,但如果我们想要一些准确的东西,甚至在手机或低功耗设备上实时运行,OpenCV 有两种重要的方法:

  • ORB(定向快速旋转简报):经典的替代品,已有 10 年历史,效果相当不错。
  • BEBLID(提升的高效二进制局部图像描述符):2020 年引入的新描述符,已被证明在几个任务中提高了 ORB。由于 BEBLID 适用于多种检测方法,因此您必须将 ORB 关键点的比例设置为 0.75~1。

是时候匹配两幅图像的描述符以建立对应关系了。让我们使用强力算法,它基本上将第一幅图像中的每个描述符与第二幅图像中的所有描述符进行比较。当我们处理二进制描述符时,使用汉明距离进行比较,即计算每对描述符之间不同的位数。

这里还使用了一个叫做比率测试的小技巧。它确保不仅描述符 1 和 2 彼此相似,而且没有其他描述符像 2 一样接近 1。

因为我们知道正确的几何变换,所以让我们检查有多少匹配是正确的(内嵌)。如果它在图像 2 中的点和它从图像 1 投影到图像 2 的点之间的距离小于 2.5 个像素,我们将认为马赫是有效的。

既然我们在 inliers1 和 inliers2 变量中有了正确的匹配,我们可以使用 cv.drawMatches 对结果进行定性评估。每一个对应点都可以帮助我们完成更高层次的任务,如单应性估计透视-n 点平面跟踪实时姿态估计图像拼接

因为很难对这种结果进行定性比较,所以让我们绘制一些定量评估指标。最能反映我们的描述符可靠性的指标是内联体的百分比:

Matching Results (**BEBLID**)
*******************************
# Keypoints 1:                          9105
# Keypoints 2:                          9927
# Matches:                              660
# Inliers:                              512
# Percentage of Inliers:                **77.57%**

使用 BEBLID 描述符获得一个 77.57% 的内联器。如果我们在 description 单元格中注释 BEBLID 并取消注释 ORB 描述符,结果将下降到 63.20% :

Matching Results (**ORB**)
*******************************
# Keypoints 1:                          9105
# Keypoints 2:                          9927
# Matches:                              780
# Inliers:                              493
# Percentage of Inliers:                **63.20%**

总之,只需更改一行代码,用 BEBLID 替换 ORB 描述符,我们就可以将这两幅图像的匹配结果提高 14%。这对需要局部特征匹配的高级任务有很大的影响,所以不要犹豫,试试 BEBLID 吧!

Python 中从头开始的估算类

原文:https://towardsdatascience.com/imputer-class-in-python-from-scratch-66df6ae067e1?source=collection_archive---------18-----------------------

“从零开始估算”项目是我在 OOP 课程中展示我对面向对象编程理解的选择,被评为 97%。

类图

假设

这份实验室工作报告的主要重点是展示对面向对象编程原则的理解以及如何应用它们。

实现的每一步都有说明;因此,假设额外的代码文档是多余的。然而,为了展示对 PEP 257 中描述的文档约定的理解,示例包含在类inputr中。

由于代码是为了演示的目的而不是为了重用,错误处理也简化为在类估算器中产生错误的两个例子。

履行

估算器将执行其估算选择的策略模式,这使得所使用的算法能够在运行时独立变化。从而应用设计原则 1: 识别应用程序中变化的方面,并将它们与保持不变的方面分开。

导入库

导入一个用于定义抽象基类的元类,以及一个指示来自 abc 模块的抽象方法的装饰器。

from abc import ABCMeta, abstractmethod

导入 deepcopy 以制作复合对象的唯一副本。

from copy import deepcopy

策略界面

首先定义了策略界面。

插补策略类是所有复合类继承的超类,它定义了一个接口,其默认行为集等于所有具体策略。从而将设计原则 2: 程序应用于一个接口,而不是一个实现,以及设计原则 3: 重组合轻继承。

class ImputationStrategy(metaclass=ABCMeta): @abstractmethod
    def _imputation(self, my_list: list, missing_values: str) -> float:
        """Must be implemented in order to instanciate"""

算法家族

第二,明确具体策略。一系列算法被封装在单独的类中,并通过拥有相同的接口而变得可互换。

每个家庭成员都可以定义新的行为;然而,它们继承了所有超类的行为,可以通过覆盖它们来替换。在超类中定义 abstractmethods 要求任何子类实现特定的行为,从而实现一个公共的默认接口。

由于这些类只有一个单一的责任设计原则 6: 一个类应该只有一个改变的理由。已应用。

具体战略 1

用平均数估算平均数是一组数字的平均总和。

class ImputeByMean(ImputationStrategy): def _imputation(self, my_list: list, missing_values: str) -> float:
        temp_sum = 0
        count = 0
        for num in my_list:
            if num != missing_values:
                temp_sum += num
                count += 1
        mean = (temp_sum/count)
        return round(mean, 2)

具体战略 2

按中位数估算
中位数是一个排序的数字列表的中间值。

class ImputeByMedian(ImputationStrategy): def _imputation(self, my_list: list, missing_values: str) -> float:
        temp_list = []
        for num in my_list:
            if num != missing_values:
                temp_list.append(num) temp_list.sort()
        temp_len = len(temp_list) if temp_len % 2 == 0:
            median1 = temp_list[temp_len//2]
            median2 = temp_list[temp_len//2 - 1]
            median = (median1 + median2)/2
        else:
            median = temp_list[temp_len//2]
        return round(median, 2)

具体战略 3

通过模式估算
模式是最频繁的值。

注意:模式包含在上下文中,但出于演示目的在下面实施。

class ImputeByMode(ImputationStrategy): def _imputation(self, my_list: list, missing_values: str) -> float:
        frequency = {}
        for item in my_list:
            if item != missing_values:
                if (item in frequency):
                    frequency[item] += 1
                else:
                    frequency[item] = 1
        mode = max(frequency, key=frequency.get)
        return round(mode, 2)

具体策略实例化

通过实例化类并引用对象实例,只需要创建一个对象。从而应用设计原则 5: 依赖抽象。不要依赖于具体的类。

如果直接调用这个类,每次都会定义新的对象。

mean = ImputeByMean()
median = ImputeByMedian()
# mode = ImputeByMode()

背景

Imputer 是策略模式上下文,包含对具体策略对象的实例化的引用。

估算器使用策略接口调用由具体策略定义的算法;然后每个具体的策略实现一个算法。
因为这是估算器和策略接口之间的唯一连接,所以应用了设计原则 4: 争取交互的对象之间的松耦合设计。

当需要一个操作时,具体的策略对象运行算法,而输入者不知道策略的实现。

如果有必要,可以实例化附加的估算对象,将数据从估算对象传递到策略接口,从而排除它作为单一候选对象。

class Imputer:
    """
     The base class for imputer objects.
     Enables the user to specify which imputation method, and which "cells" to 
     perform imputation on in a specific 2-dimensional list. 
     A unique copy is made of the specified 2-dimensional list before
     transforming and returning it to the user.
    """ def __init__(self, strategy="mean", axis=0) -> None:
        """
        Defining instanse attributes on instansiation. Args:
            strategy (str, optional): A concrete strategy. Defaults to "mean".
            axis (int, optional): Column=0 or Row=1\. Defaults to 0.
        """ # Reference to the concrete strategy object being used.
        self._strategy = strategy
        # Calling internal method.
        self.__strategy_prosessor()
        # Reference to the axis orientation being used.
        self._axis = axis
        # Reference to the keyword for missing values.
        # Defined as public, as per convention.
        self.missing_values = "nan"
        # Defines which column or row to start.
        self._from_item = None
        # Defines which column or row to end.
        self._to_item = None def __strategy_prosessor(self) -> None:
        """
        Internal method validating that selected strategy is allowed.
        If so, selecting its imputation method. Raises:
            AssertionError: If the selected strategy is not allowed.
        """ allowed_strategies = ["mean", "median", "mode"]
        if self._strategy == allowed_strategies[0]:
            self._strategy = mean._imputation
        elif self._strategy == allowed_strategies[1]:
            self._strategy = median._imputation
        elif self._strategy == allowed_strategies[2]:
            self._strategy = mode._imputation
        else:
            assert self._strategy in allowed_strategies, (
                f"Can only use these strategies: {allowed_strategies}, "
                f"got strategy = {self._strategy}") def __transpose(self, my_matrix: list) -> list:
        """
        Transposes 2-dimensional list. Args:
            my_matrix (list): 2-dimensional list. Returns:
            list: 2-dimensional list transposed.
        """ trans_matrix = []
        temp_matrix = [[my_matrix[j][i] for j in range(len(my_matrix))]
                       for i in range(len(my_matrix[0]))]
        for row in temp_matrix:
            trans_matrix.append(row)
        return trans_matrix def fit(self, my_matrix: list, from_item: int, to_item: int) -> object:
        """
        Passes in the 2-dimensional list for imputation, 
        and sets from which column to start with, and end by. Args:
            my_matrix (list): 2-dimensional list.
            from_item (int): The column to start with.
            to_item (int): The column to end by. Raises:
            ValueError: If axis is not equal to the defined options. Returns:
            object: The same imputer object that calls the method.
        """ self._to_item = to_item if self._axis == 0:
            self._array = my_matrix
            self._from_item = from_item - 1
        elif self._axis == 1:
            self._array = self.__transpose(my_matrix)
            self._from_item = from_item
        else:
            raise ValueError(
                f"Can only use integer value 0 or 1: "
                f"got axis = {self._axis}")
        return self def __axis_lister(self, matrix: list, col: int) -> list:
        """
        Generates a list for all values in a 2-dimensional list column. Args:
            matrix (list): 2-dimensional list.
            col (int): selected column to generat list from. Returns:
            list: All values in a 2-dimensional list column.
        """ temp_list = []
        for row in range(len(matrix)):
            temp_list.append((matrix[row][col]))
        return temp_list def _imputation(self, my_list: list, missing_values: str) -> float:
        """
        Passing a list to the concrete strategy object with the desired
        imputation algorithm. For this reason, the method cannot be private, 
        but have to be public or protected. Args:
            my_list (list): The list to be calculated by the algorithm.
            missing_values (str): The keyword for the missing values. Returns:
            float: The calculated value to swap with the missing value keyword
        """ return_value = self._strategy(my_list, missing_values)
        return return_value def transform(self) -> list:
        """
        Inserts the imputed column value in each column-row ("cell") of the 
        2-dimensional list where the missing value keyword exists. Returns:
            list: A unique copy of the selected 2-dimensional list after 
            it has been imputed.
        """ return_matrix = deepcopy(self._array)
        for col in range(self._from_item, self._to_item):
            imputed_value = self._imputation(
                self.__axis_lister(self._array, col), self.missing_values)
            for row in range(len(return_matrix)):
                if return_matrix[row][col] == self.missing_values:
                    return_matrix[row][col] = imputed_value
        if self._axis == 0:
            pass
        elif self._axis == 1:
            return_matrix = self.__transpose(return_matrix) return return_matrix def __str__(self) -> str:
        """
        Provides users with an easy to read representation of the class. Returns:
            str: The class name.
        """ return f"{self.__class__.__name__}" def __repr__(self) -> str:
        """
        Provides developers with unambigous information of the class. Returns:
            str: The class name and the state of instance variables.
        """
        return "{self.__class__.__name__}" \
               "(Strategy: {self._strategy}, " \
               "Axis:{self._axis}, " \
               "Missing value: {self.missing_values}, " \
               "From:{self._from_item}, " \
               "To:{self._to_item})".format(self=self)

示范

数据预处理

具有用于转置二维列表的方法和基于单词长度用制表符打印该列表格式的方法的类被实例化。

class Matrix:
    def transpose(self, my_matrix):
        trans_matrix = []
        temp_matrix = [[my_matrix[j][i] for j in range(len(my_matrix))]
                       for i in range(len(my_matrix[0]))]
        for row in temp_matrix:
            trans_matrix.append(row)
        return trans_matrix def printer(self, my_matrix, title=None, axis=0):
        my_matrix = deepcopy(my_matrix)
        if title is not None:
            if axis == 0:
                my_matrix.insert(0, title)
            elif axis == 1:
                for i in range(len(my_matrix)):
                    my_matrix[i].insert(0, title[i])
        str_matrix = [[str(entity) for entity in row] for row in my_matrix]
        max_len_col_str = [max(map(len, col)) for col in zip(*str_matrix)]
        form = "\t".join("{{:{}}}".format(x) for x in max_len_col_str)
        matrix_row = [form.format(*row) for row in str_matrix]
        return_matrix = "\n".join(matrix_row)
        print(return_matrix)matrix = Matrix()

提供了一个用于演示的模拟数据集。

dataset = list([["Country", "Age", "Salary", "Children", "Cars"],
                ["Swe", 38.0, 47200.0, 1, 1],
                ["Den", 27.0, 48000.0, 0, 6],
                ["Nor", 30.0, 54000.0, 2, "nan"],
                ["Den", 38.0, 61000.0, "nan", 1],
                ["Nor", 40.0, "nan", 2, 1],
                ["Swe", 35.0, 58000.0, 1, 1],
                ["Den", "nan", 52000.0, 0, "nan"],
                ["Swe", 48.0, 67900.0, 2, 1],
                ["Nor", 50.0, 88300.0, 6, 2],
                ["Swe", 37.0, 67900.0, "nan", 2]])

模拟了一些数据预处理。首先,从列表中删除标题行,并将其插入到自己的列表中供以后使用。

dataset_title_row = dataset.pop(0)
display(dataset_title_row)
display(dataset)['Country', 'Age', 'Salary', 'Children', 'Cars'][['Swe', 38.0, 47200.0, 1, 1],
 ['Den', 27.0, 48000.0, 0, 6],
 ['Nor', 30.0, 54000.0, 2, 'nan'],
 ['Den', 38.0, 61000.0, 'nan', 1],
 ['Nor', 40.0, 'nan', 2, 1],
 ['Swe', 35.0, 58000.0, 1, 1],
 ['Den', 'nan', 52000.0, 0, 'nan'],
 ['Swe', 48.0, 67900.0, 2, 1],
 ['Nor', 50.0, 88300.0, 6, 2],
 ['Swe', 37.0, 67900.0, 'nan', 2]]

定义数据集的转置版本,以便稍后演示轴功能。

dataset_trans = matrix.transpose(dataset)

模拟预处理结束后,演示矩阵对象打印方法;传入所需的数据集以及可选的标题行。

matrix.printer(dataset, dataset_title_row)Country	Age 	Salary 	Children	Cars
Swe    	38.0	47200.0	1       	1   
Den    	27.0	48000.0	0       	6   
Nor    	30.0	54000.0	2       	nan 
Den    	38.0	61000.0	nan     	1   
Nor    	40.0	nan    	2       	1   
Swe    	35.0	58000.0	1       	1   
Den    	nan 	52000.0	0       	nan 
Swe    	48.0	67900.0	2       	1   
Nor    	50.0	88300.0	6       	2   
Swe    	37.0	67900.0	nan     	2

现在,对转置版本执行相同的过程。但是,有必要将 axis 属性设置为1来表示转置矩阵,以确保正确的输出格式。

注意:为了正确显示转置矩阵的预期输出,运行 Jupyter 的网络浏览器必须具有默认缩放级别。

matrix.printer(dataset_trans, dataset_title_row, 1)Country 	Swe    	Den    	Nor    	Den    	Nor 	Swe    	Den    	Swe    	Nor    	Swe    
Age     	38.0   	27.0   	30.0   	38.0   	40.0	35.0   	nan    	48.0   	50.0   	37.0   
Salary  	47200.0	48000.0	54000.0	61000.0	nan 	58000.0	52000.0	67900.0	88300.0	67900.0
Children	1      	0      	2      	nan    	2   	1      	0      	2      	6      	nan    
Cars    	1      	6      	nan    	1      	1   	1      	nan    	1      	2      	2

使用估算器

用平均值估算

首先,实例化默认插补器、平均值插补和列插补。

mean_imputer = Imputer()

演示了在估算类中定义的__str____repr__方法。

print(mean_imputer) # <- __str__
mean_imputer        # <- __repr__ImputerImputer(Strategy: <bound method ImputeByMean._imputation of <__main__.ImputeByMean object at 0x10f3dbf50>>, Axis:0, Missing value: nan, From:None, To:None)

定义估算者应使用哪个数据集作为数据源,以及从哪个列开始和结束。

mean_imputer = mean_imputer.fit(dataset, 2, 5)

现在,估算器复制二维列表,使用所需的策略对象根据轴设置计算所有选定的列或行值,然后将结果返回给用户。

dataset_by_mean = mean_imputer.transform()

显示插补的结果。

matrix.printer(dataset_by_mean, dataset_title_row)Country	Age  	Salary  	Children	Cars
Swe    	38.0 	47200.0 	1       	1   
Den    	27.0 	48000.0 	0       	6   
Nor    	30.0 	54000.0 	2       	1.88
Den    	38.0 	61000.0 	1.75    	1   
Nor    	40.0 	60477.78	2       	1   
Swe    	35.0 	58000.0 	1       	1   
Den    	38.11	52000.0 	0       	1.88
Swe    	48.0 	67900.0 	2       	1   
Nor    	50.0 	88300.0 	6       	2   
Swe    	37.0 	67900.0 	1.75    	2

通过平均值估算—转置

现在演示由平均值估算的的转置版本,以及从和到设置。在这个例子中,最后一行被省略了。

首先,实例化均值插补器、均值插补器和 row。然后,执行与平均值输入的所示相同的步骤。

mean_imputer_trans = Imputer("mean", 1)
mean_imputer_trans = mean_imputer_trans.fit(dataset_trans, 1, 4)
dataset_by_mean_trans = mean_imputer_trans.transform()
matrix.printer(dataset_by_mean_trans, dataset_title_row, 1)Country 	Swe    	Den    	Nor    	Den    	Nor     	Swe    	Den    	Swe    	Nor    	Swe    
Age     	38.0   	27.0   	30.0   	38.0   	40.0    	35.0   	38.11  	48.0   	50.0   	37.0   
Salary  	47200.0	48000.0	54000.0	61000.0	60477.78	58000.0	52000.0	67900.0	88300.0	67900.0
Children	1      	0      	2      	1.75   	2       	1      	0      	2      	6      	1.75   
Cars    	1      	6      	nan    	1      	1       	1      	nan    	1      	2      	2

按中位数估算

首先,对中位数估算值进行实例化,按中位数和列进行估算。然后,执行与由平均值输入的所示相同的步骤。

median_imputer = Imputer("median")
median_imputer = median_imputer.fit(dataset, 2, 5)
dataset_by_median = median_imputer.transform()
matrix.printer(dataset_by_median, dataset_title_row)Country	Age 	Salary 	Children	Cars
Swe    	38.0	47200.0	1       	1   
Den    	27.0	48000.0	0       	6   
Nor    	30.0	54000.0	2       	1.0 
Den    	38.0	61000.0	1.5     	1   
Nor    	40.0	58000.0	2       	1   
Swe    	35.0	58000.0	1       	1   
Den    	38.0	52000.0	0       	1.0 
Swe    	48.0	67900.0	2       	1   
Nor    	50.0	88300.0	6       	2   
Swe    	37.0	67900.0	1.5     	2

扩展估算器

定义了一个新的具体策略类来证明估算器是可扩展的,而不影响任何现有的策略。启用新策略所需的唯一更新代码是在 Imputer _ _ strategy _ prosessor 方法的 allowed_strategies 列表中添加一个选项,以及在同一方法的 if 语句中添加一个选项。

class ImputeByMode(ImputationStrategy): def _imputation(self, my_list: list, missing_values: str) -> float:
        frequency = {}
        for item in my_list:
            if item != missing_values:
                if (item in frequency):
                    frequency[item] += 1
                else:
                    frequency[item] = 1
        mode = max(frequency, key=frequency.get)
        return round(mode, 2)

按模式估算

首先,模式估算器被实例化,按模式和列进行估算。然后,执行与平均值输入的所示相同的步骤。

mode = ImputeByMode()
mode_imputer = Imputer("mode")
mode_imputer = mode_imputer.fit(dataset, 2, 5)
dataset_by_mode = mode_imputer.transform()
matrix.printer(dataset_by_mode, dataset_title_row)Country	Age 	Salary 	Children	Cars
Swe    	38.0	47200.0	1       	1   
Den    	27.0	48000.0	0       	6   
Nor    	30.0	54000.0	2       	1   
Den    	38.0	61000.0	2       	1   
Nor    	40.0	67900.0	2       	1   
Swe    	35.0	58000.0	1       	1   
Den    	38.0	52000.0	0       	1   
Swe    	48.0	67900.0	2       	1   
Nor    	50.0	88300.0	6       	2   
Swe    	37.0	67900.0	2       	2

UML 类图

使用 PlantUML 生成 UML 类图的演示。

from zlib import compress
import base64
import string
import requests# This was taken from plantuml library
plantuml_alphabet = string.digits + \
    string.ascii_uppercase + string.ascii_lowercase + '-_'
base64_alphabet = string.ascii_uppercase + \
    string.ascii_lowercase + string.digits + '+/'
b64_to_plantuml = bytes.maketrans(base64_alphabet.encode(
    'utf-8'), plantuml_alphabet.encode('utf-8')) def deflate_and_encode(plantuml_text):
    """
    zlib compress the plantuml text and encode it for the plantuml server.
    """
    zlibbed_str = compress(plantuml_text.encode('utf-8'))
    compressed_string = zlibbed_str[2:-4]
    return base64.b64encode(compressed_string).translate(b64_to_plantuml).\
        decode('utf-8') def render_uml(uml, fmt="svg"):
    uri = "http://www.plantuml.com/plantuml/{}/{}".format(
        fmt, deflate_and_encode(uml))
    r = requests.get(uri)
    if r.ok:
        return r.contentdiagram = """
@startumlskinparam class {
    BackgroundColor White
    ArrowColor Gray
    BorderColor Black
}
skinparam stereotypeCBackgroundColor Gray
hide circletitle Imputer Strategy Patternclass Client
hide Client methods
hide Client attributesclass Imputer
Imputer : +fit()
Imputer : +transform()
Imputer : #imputation()
Imputer : -strategy_prosessor()
Imputer : -transpose()
Imputer : +missing_values : str = "nan"
Imputer : #strategy : str = "mean"
Imputer : #axis = int = 0
Imputer : #from_item : int
Imputer : #to_item : int
note Top: Contextclass ImputerStrategy <<Interface>>
ImputerStrategy : #imputation()class ImputByMean
ImputByMean : #imputation()
note Bottom: Concrete Strategy 1class ImputByMedian
ImputByMedian : #imputation()
note Bottom: Concrete Strategy 2class ImputByMode
ImputByMode : #imputation()
note Bottom: Concrete Strategy 3Imputer <-- Client : Requests
Imputer *- ImputerStrategy : Strategy
ImputerStrategy <|-- ImputByMean : Extends
ImputerStrategy <|-- ImputByMedian : Extends
ImputerStrategy <|-- ImputByMode : Extends@enduml
"""from IPython.display import SVG
SVG(render_uml(diagram))

导出为 png 文件格式。

from IPython.display import Image
Image(render_uml(diagram, "png"))

结论

虽然我更愿意使用 sklearn 进行插补,但从头开始制作插补器教会了我很多关于面向对象编程的知识。

关于作者

Lewi Uberg 是挪威应用数据科学专业的一名四年级学生,拥有各行各业的极客、IT 经理和 CAD 工程师的背景。请随意在 中关注他的 或访问他的 网站

使用 sklearn 中的 SimpleImputer 类输入缺失值

原文:https://towardsdatascience.com/imputing-missing-values-using-the-simpleimputer-class-in-sklearn-99706afaff46?source=collection_archive---------5-----------------------

了解如何使用 SimpleImputer 类来替换 Pandas 数据帧中的 nan

照片由 Unsplash 上的 sanga Rima Roman Selia 拍摄

在训练机器学习模型之前,您需要执行的任务之一是数据预处理。数据清理是数据预处理任务的一个关键部分,通常涉及删除具有空值的行,或者用一些估算值替换它们。

“估算”一词指的是通过对其所贡献的产品或过程的价值进行推断而赋予某物的价值。在统计学中,插补是用替代值替换缺失数据的过程。

在这篇文章中,我将向你展示如何使用 sklearn 中的简单估算器类来快速方便地替换你的熊猫数据帧中缺失的值。

加载样本数据

对于本文,我有一个简单的 CSV 文件( NaNDataset.csv ),如下所示:

A,B,C,D
1,2,3,'Good'
4,,6,'Good'
7,,9,'Excellent'
10,11,12,
13,14,15,'Excellent'
16,17,,'Fair'
19,12,12,'Excellent'
20,11,23,'Fair'

以下代码片段将 CSV 文件加载到 Pandas 数据帧中:

import numpy as np
import pandas as pddf = pd.read_csv('NaNDataset.csv')
df

数据帧看起来像这样:

替换丢失的值

数据帧中所有缺失的值都用 NaN 表示。通常,您可以删除它们,或者用一些推断值替换它们。例如,要用平均值填充 B 列中的 NaN,您可以这样做:

df['B'] = df['B'].fillna(df['B'].mean())
df

B 列中的空值现在用该列的平均值填充:

这很简单,但有时你的填充策略可能会有所不同。您可能希望用最常出现的值来填充缺少的值,而不是用列的平均值来填充。一个很好的例子是 D 列,其中出现最多的值是“优秀”。

要用最频繁出现的值填充 D 列中缺少的值,可以使用以下语句:

df['D'] = df['D'].fillna(df['D'].value_counts().index[0])
df

使用 sklearn 的 SimpleImputer 类

使用 fillna() 方法的替代方法是使用 sklearn 的simple imputr类。你可以从 sklearn.impute 包中找到 SimpleImputer 类。理解如何使用它的最简单的方法是通过一个例子:

from sklearn.impute import SimpleImputerdf = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='mean', missing_values=np.nan)
imputer = imputer.fit(df[['B']])
df['B'] = imputer.transform(df[['B']])
df

首先,通过指示策略( mean )以及指定想要定位的缺失值( np.nan ),初始化 SimpleImputer 类的一个实例:

imputer = SimpleImputer(strategy='mean', missing_values=np.nan)

一旦创建了实例,您就可以使用 fit() 函数来拟合您想要处理的列的估算值:

imputer = imputer.fit(df[['B']])

现在,您可以使用 transform() 函数根据您在simple import类的初始化器中指定的策略来填充缺失的值:

df['B'] = imputer.transform(df[['B']])

注意, fit()transform() 函数都需要一个 2D 数组,所以一定要传入一个 2D 数组或 dataframe。如果你传入一个 1D 数组或者熊猫系列,你会得到一个错误。

transform() 函数将结果作为 2D 数组返回。在我的例子中,我将值赋回给列 B:

df['B'] = imputer.transform(df[['B']])

更新后的数据帧如下所示:

替换多列

要替换数据帧中多个列的缺失值,只需传入包含相关列的数据帧:

df = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='mean', missing_values=np.nan)
imputer = imputer.fit(**df[['B','C']]**)
**df[['B','C']]** = imputer.transform(**df[['B','C']]**)
df

以上示例使用“平均”策略替换了 B 列和 C 列中缺少的值:

使用中间值替换

除了使用每列的平均值来更新缺失值,还可以使用 median:

df = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='**median**', missing_values=np.nan)
imputer = imputer.fit(df[['B','C']])
df[['B','C']] = imputer.transform(df[['B','C']])
df

结果如下:

用最常用的值替换

如果要用最频繁出现的值替换缺失值,请使用“most _ frequency”策略:

df = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='**most_frequent**', 
                        missing_values=np.nan)
imputer = imputer.fit(df[['D']])
df[['D']] = imputer.transform(df[['D']])
df

这种策略对于分类列很有用(尽管它也适用于数字列)。上述代码片段返回以下结果:

用固定值替换

您可以使用的另一个策略是用一个固定(常量)值替换缺失值。为此,为策略指定“常量,并使用 fill_value 参数指定填充值:

df = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='**constant**',
                        missing_values=np.nan, **fill_value=0**)imputer = imputer.fit(df[['B','C']])
df[['B','C']] = imputer.transform(df[['B','C']])
df

上面的代码片段用 0 替换了列 BC 中所有缺失的值:

将简单估算器应用于整个数据帧

如果您想对整个数据帧应用相同的策略,您可以用数据帧调用 fit()transform() 函数。当结果返回时,您可以使用 iloc[] 索引器方法来更新数据帧:

df = pd.read_csv('NaNDataset.csv')imputer = SimpleImputer(strategy='most_frequent', 
                        missing_values=np.nan)
imputer = imputer.fit(**df**)
**df.iloc[:,:]** = imputer.transform(**df**)
df

另一种技术是使用由 transform() 函数返回的结果创建一个新的数据帧:

df = pd.DataFrame(imputer.transform(df.loc[:,:]), 
                  columns = df.columns)
df

在任何一种情况下,结果都将如下所示:

在上面的例子中,“最频繁”策略应用于整个数据帧。如果您使用中位数或均值策略,您将会得到一个错误,因为列 D 不是一个数字列。

结论

在本文中,我将讨论如何使用 sklearn 的simple imputr类替换数据帧中缺失的值。虽然您也可以使用 fillna() 方法手动替换缺失值,但是simple imputr类使得处理缺失值变得相对容易。如果您正在使用 sklearn ,那么将simple imputrPipeline 对象一起使用会更容易(在以后的文章中会有更多相关内容)。

输入数字数据:每个数据科学家必须知道的 5 大技巧

原文:https://towardsdatascience.com/imputing-numerical-data-top-5-techniques-every-data-scientist-must-know-587c0f51552a?source=collection_archive---------13-----------------------

从简单到高级,但对每个数据科学项目都至关重要。

马库斯·温克勒在 Unsplash 上的照片

缺失值是日常数据科学工作的残酷现实。大多数数据集都不是 100%完整的,所以你的工作就是想出一个最佳的插补方法。幸运的是,今天你将学习 5 种处理缺失数值的基本技巧,比如年龄、价格、薪水等等。

这篇文章的结构如下:

  • 缺失值的简要介绍
  • 数据集加载和设置
  • 1 —任意值插补

  • 2 —分布插补的开始/结束

  • 3 —均值/中值/众数插补

  • 4 — KNN 插补

  • 5 —误森林插补

  • 结论

缺失值的简要介绍

看到一堆缺失值简直是噩梦。除非你是一个领域专家,否则你没有办法对它们进行最佳估算。一个变量的丢失可能有无数的原因——也许它在 ETL 管道中没有得到正确的处理,也许用户没有使用那个特性,或者也许它是一个派生变量,因为其他变量也丢失了。

这是个问题。

你可能知道,最流行的机器学习库——Scikit-Learn——不支持在不完整的数据上建立模型。这意味着你必须以某种方式估算数据或完全删除缺失的记录。第二个选项可能会删除大部分数据集。

插补技术可以提供一个不错的解决方案,但是没有办法知道如果数据集是完整的会是什么样子。嗯,如果数据不是随机丢失的,并且您有一些领域经验的话,情况可能就不是这样了。

所有缺失的数据可以分为三类:

  • 随机缺失(3 月) —你有可能在不同的样本上获得更多的数据。例如,关注隐私的人不太可能泄露个人信息。
  • 完全随机缺失(MCAR) —缺失值和其他观察值之间不存在关系,因此可以删除这些记录。
  • 非随机缺失(MNAR) —值缺失是有原因的。例如,用户可能没有订阅某个功能。这些记录应该被标记,而不是删除。

您可以看到领域专业知识对于输入缺失值是多么有用,尤其是对于 MAR 和 MNAR。如果你不确定——问,不要假设。

数据集加载和设置

在演示缺失值插补技术之前,我们需要一个数据集。让我们坚持一些众所周知的,如泰坦尼克号数据集

您可以使用下面的代码片段直接从 web 加载它,并在此过程中进行一些转换。所有这些都被评论为:

下面是前五行的样子:

图片 1 —泰坦尼克号数据集的头部(图片由作者提供)

只有一列— Age包含缺失值。以下行将显示每列缺失值的百分比:

结果如下:

图 2-缺失值的百分比(作者提供的图片)

我们现在有了开始输入所需的一切!

#1 —任意值插补

这可能是处理缺失值的最简单的方法。除了扔掉它们。简而言之,如果变量分布为正,所有缺失值都将被替换为任意值,如 0、99、999 或负值。

这种方法假设数据不是随机缺失的(MNAR ),所以我们希望标记这些值,而不是用统计平均值或其他技术来输入它们。

优势:任意值插补易于实施,可帮助您的模型捕捉缺失值的重要性(如果存在)。

缺点:它可以对变量分布做可怕的事情,因为它改变了均值、方差和协方差。

让我们使用这种技术来估算缺失的年龄值。代码如下:

以下是汇总统计数据:

图 3 —任意值插补的汇总统计数据(作者提供的图片)

呀。使用这种方法来估算不能为负或高于某个阈值的年龄值没有多大意义。但是在做出结论之前,让我们来看看插补的直观表示:

图 4 —任意值插补可视化(图片由作者提供)

如您所见,新的峰值被引入变量,完全改变了原来的分布。总之,这种方法可能是有用的,但将取决于变量类型和数据是否随机丢失。

#2 —分布插补的开始/结束

前一种技术合乎逻辑的下一步是对位于分布末端的值进行插补。如果一个变量是正态分布的,你可以用平均值的正/负 3 个标准差来确定两端。正如你可能知道的,在正态分布中,任何超出三个标准差的东西都可以被认为是异常值。

这种技术再次假设值不是随机丢失的(MNAR)。出于这个原因,我们希望标记这些值,而不是用统计平均值或其他技术来估算它们。

优点:该技术实现简单,可以帮助您的模型捕捉缺失值的重要性,如果它存在的话。

缺点:它可以对变量分布做可怕的事情,因为它改变了均值、方差和协方差。

现在让我们假设Age是正态分布的,并用分布值的开始和结束来估算缺失值。下面的代码片段可以做到这一点:

以下是汇总统计数据:

图 5 —分布开始/结束插补的汇总统计数据(按作者分类)

不太好。新的峰值将在分布端上升,这对Age没有多大意义。这是它的视觉效果:

图 6 —分布插补可视化的开始/结束(作者提供的图片)

总而言之——这可能是一种有用的技术,但在我们的情况下不太管用。与前面的技术相同。

#3 —均值/中值/众数插补

用统计平均值输入缺失值可能是最常见的技术,至少在初学者中是这样。如果变量呈正态分布,则可以用平均值估算缺失值,如果分布有偏差,则可以用中值估算缺失值。统计模式更常用于分类变量,但我们也将在这里讨论它。

这些技术假设数据完全随机缺失(MCAR),所以在你的项目中要记住这一点。

优点:易于实现和理解,对任何规模的数据集都很快。

缺点:可以轻微或剧烈地改变原始分布,具体取决于缺少多少值。

让我们使用这种技术来估算缺失的年龄值。代码如下:

以下是汇总统计数据:

图 7——平均值/中值/众数插补的汇总统计数据(作者提供的图片)

至少可以说,结果看起来很有希望。在下结论之前,让我们直观地探索一下:

图 8 —均值/中值/众数插补可视化(作者提供的图片)

比前两种技术好多了。中间值可能在这里效果最好,因为分布略有偏斜。

#4 — KNN 插补

接下来让我们探索一些更高级的东西。KNN 代表 K-最近邻,这是一种基于定义的最近邻数量进行预测的简单算法。它计算要分类的实例与数据集中所有其他实例之间的距离。在这个例子中,分类意味着插补。

由于 KNN 是一种基于距离的算法,您应该考虑缩放数据集。一会儿你就会明白了。

优点: KNN 插补易于实现和优化,看起来也比以前的技术“聪明”。

缺点:由于欧氏距离公式,对离群点比较敏感。它不能应用于分类数据,并且在大型数据集上计算开销很大。

让我们首先从数据集缩放开始。我们还将使用未缩放的数据集,以便之后可以进行公平的比较。以下代码片段使用MinMaxScaler来缩放数据集:

以下是缩放数据集的外观:

图片 9-原始数据集的缩放版本(图片由作者提供)

让我们现在进行插补。您需要知道n_neighbors参数的值,但这是您可以在以后优化的。价值 3 应该很适合我们。插补后,我们将不得不使用MinMaxScaler中的inverse_transform()函数,以原始形式显示缩放后的数据集。代码如下:

最后,让我们来看看结果:

以下是汇总统计数据:

图 10——平均值/中值/众数插补的汇总统计数据(按作者分类)

汇总统计数据看起来令人印象深刻,但在下结论之前,让我们先直观地了解一下结果:

图 11 — KNN 插补可视化(图片由作者提供)

这是不同的东西。KNN 插补,尤其是在缩放数据集上,产生了迄今为止最好的结果。如果你想了解更多关于 KNN 插补及其优化的知识,这里有一篇文章适合你:

还有一项技术需要探索。

#5 —误森林插补

MissForest 是一种基于机器学习的插补技术。它使用随机森林算法来完成任务。它基于一种迭代方法,每次迭代生成的插补都更好。

与 KNN 不同,MissForest 不关心数据的规模,也不需要调优。开箱即用更容易,但这并不意味着结果会更好。

优点:它不需要数据准备,因为随机森林算法可以确定哪些特征对插补很重要。它不需要调优,并且可以处理分类变量。

缺点:在处理大型数据集时,计算开销会很大。

让我们使用这种技术来估算缺失的年龄值。代码如下:

以下是汇总统计数据:

图 12 —误报森林插补的汇总统计数据(作者提供的图片)

结果看起来很有希望——平均值和标准偏差略有不同,但这是意料之中的。让我们直观地看看结果:

图 13 —误森林插补可视化(作者提供的图片)

总的来说,这些结果比用简单的方法得到的结果好得多,但我还是要说 KNN 做得更好。

如果你想更多地了解 MissForest,这里有一篇文章给你:

结论

这就是你要的——输入缺失值的五种技巧。多元插补技术(KNN 和米斯福里斯特)被证明是更适合泰坦尼克号数据集的整体方法,但这并不适用于所有数据集。

如果可能,在处理缺失值之前,尽可能多地了解数据。作为一名数据科学家,你不可能成为每个领域的领域专家,所以如果可能的话,试着向某人咨询。如果没有,用你的分析技巧找到一种方法,使分布的变化最小化,你就可以开始了。

请继续关注博客,因为将会涉及更多缺失值估算技术。下一篇文章将介绍输入分类变量的最佳技术。

感谢阅读。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

在数据科学中,要么专门化,要么死亡

原文:https://towardsdatascience.com/in-data-science-its-specialize-or-die-7ede67a58676?source=collection_archive---------10-----------------------

数据科学通才是指在该领域了解不多的人。

照片由 Unsplash 上的 sanga Rima Roman Selia 拍摄

注: 这只是我的看法!如果你不同意我的观点,留下你的回复,我们可以讨论一下。我喜欢和我不同意的人讨论。对我来说,这比呆在回音室里有趣多了。

D ata 科学是一个非常广阔的领域,我指的是广阔。随着越来越多的数据产生,这意味着公司需要利用和理解越来越多的数据来执行重要决策。事实上,做出可能决定公司未来成败的决定。但即使是这种对数据的使用也不是唯一的。

包括我在内的许多数据科学家和机器学习工程师不喜欢公司理解数据的千篇一律的盒子。生物学领域的数据科学家与商业领域的数据科学家有着本质的不同。虽然编程工具和范例几乎完全重叠,但科学家的领域专长是他们区别于其他候选人的地方。

我喜欢音乐。有时甚至超过我自己。我知道这很奇怪,但这是我真正关心的少数事情之一,以至于所有认识我的人都知道我的两件事:编程和音乐。

当我意识到数据科学的广阔潜力时,我很快意识到我想进入音乐领域。就我个人而言,我不太关心数据科学的大多数应用,但我能够找到我真正关心的东西:利用数据为艺术家提供激励,以激励我们所有人。

在研究如何学习音乐时,更具体地说,是学习录制音乐中的数据时,我意识到我必须学习各种数字信号处理技术,以便能够以可理解的方式处理歌曲,这需要对电气工程领域有很多了解。所以,我咬紧牙关,决定学习什么是需要的,不仅是对我自己,也是对我未来的职业生涯。这样做无疑是我职业生涯中最伟大的决定。

事实证明,学习如何理解音频数据不仅是一个有趣的激情项目,还让我为自己不断增长的工具箱获得了更多工具,我可以随心所欲地使用它们。随着我对音乐的了解越来越多,我开始尝试更多的应用,比如自动语音识别、语音转文本、文本转语音和自动去噪。我可以自信地解决这些问题中的任何一个,因为我决定专注于音频数据。

如果你想在一家大型科技公司工作,并在他们创造的众多虚拟助理中的一个工作,你很可能会在面试中遇到一个基于音频的问题。不太了解数字信号处理的数据科学家可能会一败涂地。为什么?因为在那一刻,他们缺乏解决问题所需的知识。代表录制的音频的最佳方式是什么?语音转文本的最佳算法是什么?这些相同的算法能用于盲源分离吗?为什么?

这就是为什么专业化是关键。

简历中有数据科学家的头衔,并不代表你能胜任每一份数据科学家的工作,没错,我也包括在这份声明中。我不想听起来刺耳,但这就是事实。就像我之前说的,我可以处理很多基于音频的问题。然而,如果你给我一个与商业相关的问题,我可能会比那些已经了解商业和理论各个方面的人花更长的时间来得到相同的结果,如果不是更不利的话。在你的职业生涯中尽早认识到这一点会让你避免浪费申请机会,同时也能在这个过程中最小化你的自负。

作为一名数据科学通才,你声称你可以解决从无人驾驶汽车到 NLP、股票价格预测到蛋白质折叠等领域的问题。所有这些问题都属于数据科学的广阔领域,因为它们需要数据来解决。祝你好运,你可以向招聘人员证明,你可以像那些每天花几个小时钻研这些领域的人一样做好所有这些事情。

你知道多少算法并不重要。如果你不知道你在学习什么,那么你在学习什么呢?数据科学是一门任何人都可以磨练和完善的艺术。这就是我如此喜欢它的原因。然而,找到自己心中最好的数据科学家需要一点反思、一点奉献和大量的热情。

感谢您的阅读。

为认知媒介辩护

原文:https://towardsdatascience.com/in-defense-of-a-cognitive-medium-9d6f91336625?source=collection_archive---------33-----------------------

图片由我美丽的女友 Beatriz Belbut 提供。

从静态认识到动态探索

从铅笔到其他东西

如果我问你 10 乘以 3 是多少,你可能会很快回答:“30!”。不需要任何巨大的努力。然而,如果我问你 3498 乘以 2345 是多少,你可能很难直接回答。相反,如果我让你用铅笔和纸,你会没有问题,在几分钟内你会写下数字,并很快得到答案。

作者图片

你可以说 铅笔和纸在某种程度上增强了你、 。我说的增加是指 增加你可以执行 的思维和操作范围,让你一次专注于问题的小部分,最终得出正确的答案。

请注意,你仍然在使用你的头脑并在精神上努力,然而,通过使用适当的媒介来帮助这种努力,你的短期记忆的负担会大大减少。

今天,用于“知识工作”的技术似乎高度集中于外包我们的脑力:我们用谷歌在几秒钟内找到答案,我们使用计算器,一切都在我们的指尖,以一个应用程序的形式设计,完全或几乎完全取代我们的脑力工作。

另一方面,当谈到可以与我们合作以增强我们能力的技术时,我认为我们没有外包部门那么丰富和多样化。

重点不是批评任何这样的技术本身,人们甚至可以说,像谷歌这样的东西以某种方式增强了我们的能力,但还是要把重点放在它们设计背后的动机上,它们更多地是为被动而不是为主动参与和思考而设计的。

这篇文章的目的是论证一种不同类型的动态思维媒介的重要性,这种媒介考虑了人类理解模式的多样性,侧重于扩展我们的认知能力。

从柏拉图到现代表征

哲学中有一个传统,可以追溯到柏拉图,将技术或技巧作为人类的一个独特标志,我们用它来克服我们自己脆弱的人类状况。

这个想法来自普罗米修斯的神话,神话中说,普罗米修斯让人类能够控制火(技术的隐喻),这样人类就可以利用自然来克服自身的身体限制。

图片作者。灵感来自 Ted-Ed 的这个视频

技术概念的基础在于它是人类能力的补充工具。然而,历史上发生了一些事情,技术似乎已经走上了替代的道路:语音、通信、计算、物理能力……我们用机器来为我们做这些事情。**

图片作者。灵感来自 Ted-Ed 的视频中的图片

我认为,旨在帮助人类从事知识工作的技术是最好的例子。它们是为被动而设计的,而我们拥有的许多能力并没有集成在这样的设计中。

我认为这应该得到纠正,应该更加重视适当的思考媒介,考虑到有意义的上下文表征,以增强我们的思考能力。

上下文表征

这里我所说的 表示 具体指的是 数据结构和类似程序的结构,我们可以用它们来生成洞察力 。这个定义属于我最喜欢的一个技术专家 Brett Victor,摘自他的讲座:“思想的人性化表示”

当我们使用笔和纸时,我们可以感觉到这种表达的价值。数字是一种表示,加号是另一种表示。这些塑造了我们对世界的理解,并严重依赖于表达它们的媒体。

例如,用铅笔和纸很难有意义地描述时间动态。人们可以写一个“时间”轴,但这与拥有一个实际上是动态的、代表时间行为的媒介是不一样的。

铅笔和纸作为思想表达的媒介,就像其他媒介一样,它们所允许的表达方式是有限的。

《平地》埃德温·阿博特。图片取自维基媒体:https://commons . wikimedia . org/wiki/File:Flatland (first _ edition) page _ 100 . png公共领域。

表象是我们可以使用、操纵和发展的心智工具,以建立对世界的复杂理解。本质上,它们是积木,是我们头脑中用来构建思想的“乐高积木”。

然而,正如我之前所说,它们高度依赖于表达它们的媒介。我们可以把铅笔和纸这样的媒介想象成我们大脑的显微镜,通过在有意义的上下文中使用丰富的表征来减轻我们短期记忆的负担,让我们看到以前看不到的东西。

好的思维媒介有可能通过促进我们接触更丰富的表象来增强我们的能力,我们可以利用这些表象来收集洞察力、解决问题和思考细节。

与这样的媒介一起工作拓宽了我们的思想范围,就像显微镜拓宽了我们能看到的东西的范围一样。

图片作者。

这种表示在不同文化中是共享的(例如,数字和等式在我们的文化中广泛用于数学)。这些心智工具很重要,它们是我们思考复杂事物能力的支柱。

以这个例子为例,想象你在家里,你想去某家餐馆。所以你打开你的智能手机,在谷歌地图上输入你选择的餐馆的地址,这个应用程序就会给你指路。

然而,该应用程序只能到此为止。现在你面前有了地图,就看你自己去解读这些图像和指示对到达你的位置意味着什么了。因为你知道它们的意思,你可以快速浏览这些方向图,你就可以轻松到达目的地。

你能想象这有多难吗?如果这款应用不是用图像和箭头来显示地图,而是只向你展示如何到达目的地的口头描述。

作者提供的图片和 googlemaps.com 的截图

解码书面版本比理解地图要多得多的不必要的脑力劳动!为什么?因为 有好坏之分的表象。 在这种情况下,带箭头的地图是指引人们走向某个地点的很好的表示。这种情况下的文本不是。

可以说 地图是方向信息 的适当表示。然而,如果我们讨论的是历史或哲学,用地图可能就不太管用了。我们会失去书面语言所能提供的描述困难的、细粒度的抽象概念的信息。人们会用地图来指引人们,用文字来解释存在主义和生存的可怕痛苦。

图片 ay 作者。

这里的要点是要理解媒介和表现应该适合问题、任务或手边的背景,使用错误的媒介或错误的表现自然会阻碍我们思考特定主题的能力。

当我们思考事物时,由于历史的某些原因,我们只专注于符号表征,作为我们表达思想和交流思想的主要渠道。

然而,随着技术的发展,我们现在有了历史上独一无二的机会来重新考虑我们被迫的选择,并从我们用来做所有知识工作的这些矩形盒子中进化出来。

知识工作不一定非得是打字和点击这种受约束和身体限制的过程。它应该整合一系列更加多样化和人性化的渠道来吸收和处理信息。

通过表象思考

表征直接影响我们的思维方式。语言可能是表现力量的终极例子。当我们给某物命名时,我们就获得了对它的控制,这就是授权。

表征允许我们将我们希望理解的东西内在化。例如,当你想到数学时,你可能会想到:

照片由舒巴姆·莎兰Unsplash 拍摄

复杂的符号方程在一个大板上。这种主要存在于符号领域的数学思想是数学符号进化的副产品,换句话说,是数学表示的进化。举一个简单的例子:

  1. 一个数的平方。
  2. x

就像地图的情况一样,每次我们打算使用 x 时都要写下对它的描述是不可思议的,但是曾经有一段时间数学是通过书写而不是通过我们今天使用的符号来完成的。

这种演变对数学至关重要,因为这种简单而紧凑的表示允许我们有效地压缩信息,极大地提高了数学家可以处理的复杂程度。

我展示的例子都是关于把复杂的结构打包成能立即显示其核心直觉的东西。

人们如何思考

布雷特·维克托(Brett Victor)在他的演讲《思想的人性化表达》(A humanual Representation of thinking)中精彩地指出,今天用于思考和解决问题的主流媒介(如电脑和平板电脑)是简化的,因为它们只强调了我们所拥有的理解模式范围中的一小部分。他来自皮亚杰的观点,认为我们有以下几种理解模式:

  • 视觉的
  • 耳的
  • 触觉的
  • 动觉的
  • 空间的

他还提到了其他关于这个问题的观点,比如杰罗姆·布鲁纳的观点:制定的、标志性的和象征性的。他的论点是,我们使用的 技术限制了这些模式的大部分,媒体只占专注于视觉和符号表示的子集。

我们受限于这种低带宽的知识表达渠道, 这与我们拥有的多样化的思维和理解模式形成了鲜明对比。我们被这些屏幕所包围,这些屏幕并没有设计成包含我们可以思考的全部思想。我们可以打字、点击和绘图,就是这样!维克多说得更好:

它限制了我们知识经验的范围

他为动态媒体的立场辩护,这种媒体将跨越人类的全部能力,以一种解放我们而不是像我们一直随身携带的这些媒体消费设备那样奴役我们的方式。

虽然我认为 AR 和 VR 可以在适当的情况下(这肯定不能保证)缓解这个问题的一部分,但他的批评是独特的,因为 它质疑了我们如何做知识工作的本质以及我们用来做知识工作的材料。

迈克尔·尼尔森(Michael Nielsen)的两篇伟大文章讨论了这种潜在动态媒介的子集,分别是“重新发明的解释”“走向数学的探索媒介”

在这些文章中,他从有意义的互动解释(前者)的角度来探讨对这种媒介的需求,以及如何开始构思这种媒介来探索数学概念(后者)。在后一篇文章中,他展示了一个足以发现和理解一种叫做奇异值分解的数学的环境原型。

尼尔森先生提出的观点是,我们需要重新思考我们如何理解解释以及我们用来产生解释的“传统”媒介。

从不足到理解

从我还是个孩子的时候起,我就对数学和物理这样的理论课题同时感到着迷,同时又对自己从事这些课题的真正能力感到可怕的无能。

虽然我总是可以在学校表演,但我仍然觉得缺少了一些东西: 一种工具,一种以自然和快速的方式表达我所想的方式,让我可以在不感到无聊或沮丧的情况下摆弄我的想法。

这种感觉追了我一辈子,当我开始用 python 进行深度学习和编程时,事情开始对我产生影响。从那一刻起,我变得更加投入,有了这个简单的工具,我可以以我从未想过的速度将我的想法变成现实。

虽然我完全被迷住了,但这种感觉并没有消失。即使我可以编写比我以前尝试过的任何其他工具更快实现我的想法的程序,它仍然不够快。

考虑这个试图理解什么是导数的简单例子。更好的是,让我们试着勾勒出理解导数是函数在任一给定点的切线斜率所需的工作流程。

我想展示我将如何使用我目前的工具来观察这些行为,并从导数的定义出发,得出关于平方函数及其导数之间关系的一些令人满意的结论:

图片作者。

我的第一步是画一个函数,来了解正在发生的事情。之后,我将使用 matplotlib 和小部件编写一个简单的交互式工具,来绘制通过函数上两点的割线的行为:

*# %matplotlib widget
%matplotlib inline
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set()def plotDerivative(a,h):
    """
    Print the current widget value in short sentence
    """
    x = np.arange(-5,10,1)
    f = lambda i: i**2
    pointA = (a,f(a))
    pointH = (a+h,f(a+h))
    m = (f(a+h) - f(a))/float(h)
    print(f"m = {m}")
    y = m*(x-a) + f(a)
    plt.plot(x,f(x), color="blue")
    plt.plot(x,y, color="red")
    plt.scatter(pointA[0],pointA[1],c="purple")
    plt.scatter(pointH[0],pointH[1],c="purple")
    plt.xlim(-20,20)
    plt.ylim(-20,30) widgets.interact(plotDerivative,a=widgets.IntSlider(min=-10, max=10, step=1, value=5),h=widgets.IntSlider(min=0, max=5, step=1, value=1))*

此时,我有一个问题:生成这样一个简单的可视化工具所花费的平均时间是否使得这种方法值得?

好吧,有更好的方法来用代码形象化这一点,但重点是当你还不知道导数是什么(在这种情况下,作为在任何给定点与函数相切的线的斜率)时理解导数,用这种方法我可以看到一些有意义的行为(当一个点接近另一个点时,线变得与函数相切),但代价是要花几分钟来获得正确的代码。

这里的问题是,对于这个问题的如此低维的表示,它所花费的时间使它成为一个非理想的思考工具,至少对于这个主题来说。

当然,我本可以以花费更多时间编码为代价生成一个更好的工具,或者一些能够更紧密地处理衍生产品核心的方法,但是,从试图快速可视化一种关系并了解正在发生的事情的因果关系的人的角度来看,使用一个不是为快速思考而设计的工具是没有意义的。

我正在努力思考衍生产品,而思考发生得很快,如果我要使用一个工具来思考, 工具的速度应该与我对我正在研究的主题有想法的速度相匹配。

然而,我仍然认为,与其他方法相比,今天的编码可能是我们拥有的最接近一般意义上的思维工具的东西之一,这回避了什么可能更好的问题?

为了举例说明对比,让我们看看一个叫做 desmos 的工具,特别是图形功能,它可以很容易地在交互式二维网格中可视化任何简单的功能。

以下是一个工作流程的快速视频,显示了与之前相同的问题的解决方案,但在 desmos 中:

作者关于 youtube.com 的视频

又快又简单!它仍然需要一些直观的实践,可能需要几分钟,但它比编码快得多,并能快速提供更多的交互功能,因此对于基本的数学绘图工作流来说,它比编码更好。我可以写下我在高中数学时代就非常熟悉的符号表达式,并立即绘制出图形!

现在,这不是一个关于衍生产品的讲座,也不是一个关于为什么 desmos 比编程更好的讲座,而是展示一个给定主题的更合适的工具如何增强我们对它的思考。

来自“三蓝一棕”频道的 Grant Sanderson 展示了一个非常好的数学思维流程:

你可以看到他是如何在设计、编程和写作之间切换的,因为 每种媒介都提供了合适的环境,在那里人们可以以适当的方式操纵合适类型的表达,从而在需要的时候获得有意义的洞察力。

从这里得到的教训是,不仅要有适当的表现,而且媒体也很重要,它应该整合可控性、交互性、即时反馈和许多其他元素,使其成为理想的思维媒体。

关于思维媒介草图的最后思考

随着我们的思维速度快速地表达知识,就是要与允许对信息进行快速有效的上下文压缩的环境一起工作。

互动作为思想本身的一个基本组成部分的想法并不新鲜。道格拉斯·恩格尔巴特是引入交互技术理念的基础思想家之一。在过去的 10 年里,像芭芭拉·特沃斯基、迈克尔·尼尔森、肯·珀利姆和布雷特·维克托这样的作家以这样或那样的方式为适当思维技术的需要辩护。

铅笔和纸是思维压缩的好工具,但是它们被限制在我们能思考的事物范围的一个非常低的维度上。

我们今天知道在课堂上记笔记能增强学习,因为当我们记笔记时,我们有意义地接触了材料。我们不知道的是,如果我们有更合适的媒介来表达我们的想法,与我们拥有它们的速度相匹配,我们可以观察到学习中潜在的巨大进步。

就像计算机的发明给我们思考无法通过分析完成的更复杂过程的能力带来了巨大的好处一样,一个更具活力和人性化的思考和解决问题的媒介也会产生类似的积极影响。

至于这样一个思考空间的要素,我建议看看维克多先生的著作以及肯·佩里姆的 chalktalk。我认为基本要素是:

  • 直接操纵
  • 交互性
  • 即时反馈
  • 能够随时提供系统的整体视图
  • 在上下文操作中

这些理论基础应该是创造思维环境的核心。

重新思考你的工作空间

举个例子,你今天可以做的一件事就是 重新思考你的工作空间 。以前,我认为知识工作是一种坐下来的活动,包括点击、打字、有时画画和做手写笔记,但在深入思考这个话题并受到布雷特·维克托、迈克尔·尼尔森、芭芭拉·特沃斯基和肯·佩里姆等人的严重影响后,我决定对我来说最好的事情是重新设计我的工作空间,以考虑到站起来和多动。

这还不是故事的结尾,因为技术是问题的主要核心,但它确实有助于参与,以及感受到思考是我们可以体现的东西!哲学家弗里德里希·尼采过去常常长途跋涉去帮助他思考。这不是从他的工作流程中分离出来的东西,而是作为他思考过程的一部分整合在一起的。

现在,我有了白板,我的显示器可以扩展到站着和四处移动使用(不仅仅是在桌子上)。我还想集成一个桌面触摸屏,这样我可以站起来,但仍然能够有效地与我的电脑进行数字交互。

这里的主要思想是创造一个运动的动机,而不是把一切都集中在坐下这个想法上。

尽管这是一个进步,但它并没有解决当今思维技术的主要认知缺陷。这将需要整个集体的人思考更好的方法来建立和传播知识,并参与社会使之成为一个优先事项。

这样做的一个危险是,资本的逻辑往往是短视的,错误的选择往往会殖民整个技术景观,所以这取决于人们是否意识到 我们被喂养的小矩形笼子不够人性化,不足以成为我们思维空间的未来。

谢谢,下次再见!;) .

如果你喜欢这篇文章在 Medium 上关注我,在 TwitterLinkedIn 上与我联系。

参考

为统计建模辩护

原文:https://towardsdatascience.com/in-defense-of-statistical-modeling-e73d889b475d?source=collection_archive---------25-----------------------

意见

持续不断的评论说数据科学被夸大了。不要相信。

数据科学在已经热了多年,吸引了关注和人才。然而,有一种持续的评论说,数据科学的统计建模核心技能被夸大了,经理和有抱负的数据科学家应该专注于工程。Vicki Boykis 的 2019 年博客文章是我记得的第一篇沿着这些思路写的文章。她写道:

…数据科学正逐渐向工程靠拢,数据科学家前进所需的技能更少基于可视化和统计,更符合传统的计算机科学课程…

在这个前提下,她的合理建议是:

不要攻读数据科学学位,不要参加训练营…通过“后门”进入数据科学和技术职业要容易得多,也就是说,从初级开发人员开始,或者在开发运维、项目管理领域,以及可能最相关的领域,担任数据分析师、信息经理或类似职位…

她列出的一个有抱负的数据科学家应该学习的技能完全由数据工程、MLOps 和工具组成,她故意省略了建模,说:

虽然调整模型、可视化和分析占据了您作为数据科学家的部分时间,但数据科学一直以来都主要是在一个地方获取干净的数据以用于插值。

最近,Gartner 的 2020 年人工智能炒作周期报告承认了数据科学家的作用,但表示:

Gartner 预测开发人员将是人工智能的主要力量。

Chris I. 说得更直白,有一篇文章题为《不要成为数据科学家》。

每个人和他们的祖母都想成为一名数据科学家…我经常收到新毕业生和转行者的消息,向我咨询进入数据科学的建议。我告诉他们要成为一名软件工程师。

米哈伊尔·埃里克在一篇题为“我们不需要数据科学家,我们需要数据工程师”的文章中呼应了这一想法。

如今,在帮助公司将机器学习和建模见解应用于生产中心的数据问题方面存在瓶颈……这听起来可能很无聊,也不性感,但倾向于数据的老派软件工程可能是我们现在真正需要的……对于市场上大量受过数据科学培训的新人来说,职位会越来越少。

我同意这些文章的观点,即数据工程和 MLOps 对于应用行业数据科学工作非常重要,但我也相信数据科学的核心技能——统计建模——正变得越来越重要,而不是越来越不重要。由于在这个 Covid 时代,我们没有太多机会进行面对面的辩论,所以我想象这些怀疑论者会如何进行辩论。

作者图片

数据科学这个术语被淡化了

怀疑论者: “数据科学”这个术语到底是什么意思?这么宽泛模糊的称呼,再加上 这年头大家都自称数据科学家 ,所以完全淡化了。

我:数据科学就是一个大帐篷。当人们谈论术语应该是的意思时,它通常围绕着统计建模的核心技能。例如,boykis引用“机器学习、深度学习和贝叶斯模拟”作为初级数据科学家期望从事的工作,而不是他们最终完成的“清理、塑造数据并将其从一个地方移动到另一个地方”的工作。Eric 将数据科学家描述为“负责构建模型以探索从一些数据源中可以学到什么的人,尽管通常是在原型而不是生产层面。”

统计建模是大多数统计学、机器学习和数据科学课程中教授的内容。除其他外,它包括:

  • 传统的预测模型,即回归和分类。所有最成功的方法——线性模型、提升树、神经网络等等——都属于这一类
  • 时间数列预测法
  • 实验设计和分析
  • 因果推理

模型训练将会过时;软件工程师可以做这项工作

怀疑论者 : 所以数据科学只是训练模型?随着 AutoML 和像 GPT-3 这样的大规模预训练模型的崛起,这难道不是已经过时了吗?随着 模型的构建变得商品化*软件工程师 将会做这些工作,而不是 方法论者 *

我:统计建模涉及的不仅仅是按下通用 scikit-learn 或 PyTorch 脚本上的按钮。AutoML 工具可以帮助一些部分,如超参数搜索和特征选择,但还有更多功能。

正如我几周前写的,数据科学家需要做的第一件事是理解业务问题,并将它们表述为建模任务。例如,您希望减少客户流失,但是您应该将其视为二进制分类还是事件时间问题?一个预测模型就够了吗,还是需要得出因果结论?你将如何进行实验来验证模型的有效性?

建模的下一步是彻底理解和清理数据。这项工作本身通常会创造大量的价值,因为数据科学家通常是唯一有资格在业务逻辑和数据工程之间进行转换并发现问题的人。

模型拟合过程正在不断发展,尤其是像 MLFlowCometWeights&bias等模型训练平台已经成熟。但是,许多组件仍然不能自动化或抽象出来。例如,数据科学家必须决定如何评估模型性能。对于一个预测模型,我们应该使用随机的还是时间的训练测试分割?什么评估指标最符合业务用例?

建模过程的最后一块是沟通。数据工程和 MLOps 需要知道如何在生产中实现模型(如果这不是数据科学家的工作的话)。业务部门至少需要对模型如何工作的基本直觉,以及对意外预测的解释。

至于像 GPT-3 这样的大规模预训练模型,当然,大多数公司的大多数数据科学家不应该浪费时间试图从头构建它们。但是这些模型覆盖了真实世界用例的一小部分;绝大多数应用程序没有预先训练好的模型来构建。

数据科学家花大部分时间做其他事情

怀疑论者: 很公平。但是我听数据科学家说 超过 超过 建模工作只占他们时间的一小部分。甚至说* 数据工作应该在 建模之前。因此,如果我是一名招聘经理,我不应该首先关注数据工程和 MLOps 工程师吗?如果我选择我的职业,数据工程不是更安全的选择吗?*

我:让我们先达成共识。问题公式化、数据探索和数据清理是统计建模的部分。理解数据工程和模型部署管道如何工作是统计建模的部分(尽管设计和实现这些系统不是)。即使是只想做统计建模的数据科学家也应该接受这些任务。**

我同意从组织的角度来看,数据工程比统计建模具有更高的优先级。甚至实验分析——不需要部署——也完全依赖于良好的仪器和数据管道。

更小、更有竞争力的公司的数据科学家将更多时间花在数据工程和 MLOps 上。更喜欢专注于统计建模的人应该关注更大、资金更充足、拥有更多专业团队的公司。不过,我会告诫不要过早进行职业专业化,因为了解一些工程知识可以让数据科学家在一个组织的技术和业务方面之间充当一座非常有价值的桥梁。这也为将来转向更偏重于工程的角色留下了余地。

大多数数据科学项目都失败了

怀疑者: 给怀疑者打一分。我还读到过,大多数数据科学 项目 失败 ,所以我不明白为什么一个公司——尤其是一个小而好斗的公司——要在数据科学家身上浪费资源。

我:我见过那些说 85%或 87%的项目失败的消息来源,但他们似乎只是凭空捏造数字。数据在哪里?我对你的怀疑态度表示怀疑!

更严重的是,一个数据科学项目的失败意味着什么?Kohavi、Tang 和 Xu 指出,大多数实验都失败了,因为提议的改变并不比现有系统更好。然而,这并不是商业意义上的失败,因为这些实验仍然会导致好的决策和快速的创新节奏。

更一般地说,统计建模者带来的最有价值的东西是他们的文化。数据科学家坚持用证据而不是直觉来证明想法,特别是通过量化模型性能。在我们进行实验之前,我们需要知道我们用什么指标来评估一个新想法。在部署复杂的预测模型之前,我们需要知道基线是什么。很可能是目前确定性的,硬编码的系统,你连模型都没想到,更别说度量了!因此,即使一些项目失败,强大的数据科学家也会提高整个组织的标准。

建模专家还通过提前发现潜在的建模问题来加快创新的步伐。例如,在推荐系统中,提前考虑如何避免闭环反馈、如何解决冷启动问题以及如何确保算法的公平性非常重要。

然而,在数据科学项目中,并不是所有的事情都是可以计划的。与其他工程学科不同,**我们不能先验地向我们的合作伙伴承诺具体的结果**甚至是可靠的路线图,因为我们不知道我们会在数据中发现什么。拥有独特的数据科学角色有助于传达这种局限性。

数据科学家太多了

怀疑论者: 也许高级数据科学家真的很好增值但是现在有了https://www.mihaileric.com/posts/we-need-data-engineers-not-data-scientists*初级数据科学家 。这些穷人最终会在没有准备好统计模型的公司工作,浪费他们的培训和才能。***

我:**我们上面说过,数据清洗是统计建模的部分,数据科学培训项目更应该强调这一点。想专攻模特的人应该去大公司找工作,尽管这也不是万灵药;理解数据和工程管道总是很重要的。

数据科学劳动力供大于求可能是真的,至少就有明确“数据科学家”头衔的工作而言。这种观点只见树木不见森林。有抱负的数据科学家可能不得不将他们的求职范围扩大到其他职位或特定业务部门的目标角色,但统计建模可以而且应该应用于几乎所有行业职位。不管头衔如何,建模技术好的人会更有效果,更能登顶。****

不管是通过学位、训练营还是自学,真正学习统计建模是很重要的。一个人不能完全专注于数据工程和 MLOps 来获得一份工作,然后希望在没有任何建模经验的情况下转到数据科学团队。

结论

在过去的 10 年里,数据科学领域肯定受到了大量的炒作,一定程度的抵制是不可避免的,甚至是富有成效的。但是我们不要忘记它的统计建模核心技能带来的价值。

原载https://www.crosstab.io/articles/defending-data-science交叉表风筝。****

为 Zillow 被围攻的数据科学家辩护

原文:https://towardsdatascience.com/in-defense-of-zillows-besieged-data-scientists-e4c4f1cece3c?source=collection_archive---------12-----------------------

意见

模型必须小心使用

网上流传的许多 Zillow 笑话之一

Zillow 的即时购买(又名 Zillow Offers)业务本月戏剧性地内爆了。3.5 年后,Zillow 做出了艰难的决定,关闭他们的 Zillow 优惠业务。最后的结果[1]:

  • 劳动力减少 25%
  • 以 28 亿美元购买的 7000 套未售出房屋(第四季度预计减记 3.04 亿美元)。
  • -股票下跌 30%
  • -第三季度亏损 2.45 亿美元

这场灾难的规模令人印象深刻。错误的是,大部分责任都被推到了数据科学家身上;那些盲目创造和信任他们的模型的“书本智能万事通”,嘲笑 ZEstimate 和 Zillow 用数十亿美元信任它的想法是懒惰的[2]。也很容易嘲笑预测科学和 Zillow 的数据科学家只是使用“pip install prophet”(利润)来获得生产模型的概念[3]。

所有这些都是错误的。Zillow Offers and iBuying 是一项具有内在风险的业务,由 Zillow 的商业领袖鲁莽执行,他们希望在短短几年内接管房地产市场。正如 Zillow 的竞争对手 Opendoor 和 Offerpad 所证明的那样,iBuying 确实有效!但这需要耐心、经验和对风险的健康尊重。相反,Zillow 的商业领袖一头扎进了浅水区。

什么是 iBuying

iBuying 是一个新兴的、有些未经证实的行业。Opendoor (2014)和 Offerpad (2015)已经在这方面做了多年,并取得了越来越大的成功。这个概念很简单:让人们可以立即以微小的折扣出售他们的房子,同时省去繁琐、痛苦和高风险的出售过程。任何买卖过房子的人都有同样的体会:购房过程迫切需要现代化和创新。即使在 2021 年,它仍然在很大程度上是一个握手和纸张业务。

iBuying 的核心不是市场投机,也不是电视真人秀式的一夜翻新。Zillow 自己花在装修上的运营成本不到 2%(与油漆工作的成本相差不远)。这也不是一项自动化的业务;Zillow 派出家庭检查员,并对每一笔购买进行亲自评估。

困难在于:iBuying 的利润率非常低。Zillow 在第三季度销售了 12 亿美元的房屋,但他们只获得了 2150 万美元的利润……少得可怜的 1.8%。竞争对手的表现要好得多,同期利润率在 7%至 9%之间。这不是巧合,这些接近总房地产经纪人的佣金。对于价值数十亿美元的科技公司 Zillow 来说,只有当它能够将业务规模扩大到 200 亿至 1000 亿美元时,这些微薄的利润才具有吸引力。

Zillow 相信 iBuying 是房地产的未来,他们将会占据主导地位。他们预计这将在几年内成为 200 亿美元的业务,并需要在全国范围内的所有市场积极扩张。当竞争对手继续采取有条不紊、谨慎的方法时,Zillow 的高管们承担了所有的风险。

数据科学挑战

为了取得成功,Zillow 需要超精确的预测模型来预测未来 3-6 个月的房屋销售价格,误差在+/- 3%以内[4]。过高的估计可能会使利润化为乌有,或者更糟,导致超过 1 亿美元的损失。低估将导致拒绝低价报价,削弱 Zillow 购买房屋的能力(即购买者转化率低)。虽然基于机器学习的预测模型是技术领域的标准做法,但住房也受到重大和不可预测的宏观经济趋势的影响。根据预测经验,要预测未来 X 个月的情况,需要 2X 个月的历史数据。然而,只有当你的历史数据代表未来时,这条规则才有效。持续的全球疫情、快速的通货膨胀、消费者行为的转变以及房价的大幅波动都确保了这是不可能的:我们正处于前所未有的境地。

房地产交易方许可使用的图像

激进的增长和商业目标扼杀了 Zillow Offers

为了积极扩大 Zillow Offers 业务,Zillow 高管有意向上调整他们的算法估计,这实现了增加购买转化率的目标,但出价更高[5]。Zillow Offers 由于价格大幅升值,实现了 15%的毛利率,表现得相当自信,并继续扩张。不幸的是,第三季度市场发生逆转,房地产市场非但没有出现+12%的增长,反而出现了-5–7%的下跌,导致 3 亿美元的损失和预计 2 . 45 亿美元的资产减记。这是算法上的失败吗?不,相比之下,Opendoor 报告的第三季度利润为 1.7 亿美元,毛利率为 7.3%。随着 Zillow 退出 iBuying 业务,Opendoor 将坚持到底,继续完善他们的模型,同时非常尊重地对待波动性。失败不在于模型,而在于使用模型的人。模型不是万能的,那些选择以模型为基础创业的人需要了解它们的细微差别和局限性。

参考

  1. Zillow 公司(2021 年)。Q3 财报。https://s24 . q4c dn . com/723050407/files/doc _ financials/2021/Q3/Zillow-Group-Q3 ' 21-Shareholder-letter . pdf
  2. https://twitter.com/ryxcommar/status/1456079677957804038
  3. 《Zillow,Prophet,时间序列和价格》2021 年 11 月 6 日。https://ryxcommar . com/2021/11/06/zillow-prophet-time-series-and-prices/
  4. Vashishta ,Vin。" Zillow 只是让我们看到了机器学习的未来."2021 年 11 月 4 日。https://vinvashishta . substack . com/p/zillow-just-give-us-a-look-at-ok-machine
  5. 克拉克,帕特里克,纳塔拉詹,斯里达尔,佩尔伯格,希瑟。“这一决定是在该公司调整了让该公司能够提出更高报价的算法之后做出的,在房价上涨有所降温之际,该公司赢得了一系列竞标。”——Zillow 在彭博翻转 Halt 后,寻求以 28 亿美元出售 7000 套房屋。2021 年 11 月 1 日。https://www . Bloomberg . com/news/articles/2021-11-01/zillow-selling-7000-homes-for-20-80 亿-after-flip-halt
  6. Opendoor Technologies Inc .(2021)Opendoor 宣布 2021 年第三季度财务业绩。https://investor . opendoor . com/news-releases/news-release-details/opendoor-announced-2021 年第三季度财务业绩

特别感谢来自房地产的迈克为鲍勃·罗斯迷因。

线性回归建模的深入概述

原文:https://towardsdatascience.com/in-depth-overview-of-linear-regression-modelling-a46ac4eb942a?source=collection_archive---------23-----------------------

数据科学家应该知道的关于线性回归建模的一切的简化和详细的解释

首先,由于各种原因,几乎不可能涵盖这个主题的所有内容。这篇博客的目的是简化大多数概念,并展示它们的实际应用,因为它涉及到一个数据科学家。

所以我们走吧!

简介

线性回归建模是一种受监督的机器学习算法,它对自变量(X)和连续因变量(y)之间的线性(直线)关系进行建模。线性回归问题可以被定义为简单问题或多重问题,这取决于其特征的数量(即分别为单一特征或多重特征)。多元线性回归不应与多元线性回归混淆,在多元线性回归中,预测的是多个因变量,而不是一个定标变量。

术语“连续因变量”在这里是指输出值是实数值(如 112,15110.15 等。)与分类问题的离散输出值相反。

考虑样本数据的散点图:

输出:样本数据的散点图,显示自变量和因变量之间的线性关系。图片作者。

线性回归模型有助于找到穿过样本点的最佳拟合直线(回归线),该直线可用于根据输入特征(X)估算目标输出(y)。

使用如下所示的 Scikit-Learn 包实现一个线性模型可以让我们深入了解线性回归建模的目的:

输出:简单线性回归及其最佳拟合线和样本预测的示例。

如上所述,线性回归建模的目的是拟合预测模型,该预测模型反映一组独立变量(X)与 y 和 X 值的观察数据集的输出变量(y)之间的线性关系;使得如果给出了 X 的附加值而没有其伴随的 y 值,则拟合的模型可以用于基于输入 X 来预测 y的值

*# Linear regression function.
y = F(X)
where: y= dependent variable
       x= independent variable*

关于将数据集中的哪个变量设置为因变量或自变量的决定通常基于因变量的值受自变量影响(在这种情况下为线性)的假设,即 X 的变化会导致 y 的一些变化。但情况并不总是如此,因为可能有一些操作原因需要根据其他变量对变量进行建模。

由于线性回归函数是输入变量的线性组合,因此 y 和 X 之间的直线关系可以表示为:

*y = mX + c 
Where: ***m*** is the coefficient.
       ***c*** *is the intercept*.*

获取函数的权重和系数的最佳值是定义最佳线性预测函数的关键,该函数可根据输入(X)精确得出输出(y)。最佳权重使得它们产生最小的预测误差(也称为残差)。

线性模型的假设。

当确定预测函数时,线性模型对特征和目标变量及其关系做出某些假设。这些假设包括:

  1. 预测变量和目标变量之间存在线性关系(线性)。
  2. 目标的每个特征都有一个正态分布(多元正态)。
  3. 没有一个要素与其他要素高度相关(非多重共线性)。
  4. 预测变量是无误差的(弱外生性)。
  5. 目标变量的误差方差相同,与预测变量的值无关(同方差)。

虽然这些假设中的一些在实际意义上是不现实的(如同质性和弱外生性),但有一些回归方法(如加权、广义和偏最小二乘法)能够处理这些假设可能产生的误差。

既然我们了解了线性回归建模的目的,我们应该关注如何实现这一目的,即在确定线性函数的最佳权重时,哪些概念是有用的?

拟合线性回归模型

我们将考虑一些最流行的方法来拟合线性回归模型,如最小二乘法,梯度下降法和惩罚估计法。

在深入研究这些方法以及它们如何帮助拟合精确的线性回归线之前,让我们简要讨论一下本节中非常常用的一个术语,即成本函数**

成本函数是用于测量机器学习模型的性能的函数,它们量化预测值和真实值之间的误差,并帮助评估模型的准确性。因为我们对推导精确的预测函数感兴趣,所以我们能够使用成本函数来衡量我们的模型表现得有多好(或多差)。

用于评估回归模型的一些最常见的成本函数是平均绝对误差(MAE)、均方误差(MSE)、均方根误差(RMSE)和残差平方和(RSS)。

我们将利用这些成本函数中的一些来研究预测线如何精确地适合回归问题,并在以后研究另一些。

现在来看拟合优化回归模型的方法:

1。普通最小二乘法(OLS 法)。

普通最小二乘法(OLS) 是拟合线性模型最常见的估计量。最小二乘法基于这样一种理论,即最适合一组给定观察值的曲线被认为是与给定数据点的垂直距离(残差或误差)的平方和最小的曲线。这可以简单地理解为具有最小预测误差的最佳预测函数(成本函数)。

给定数据点[(y₁x₁,)(y₂)….x₂)的垂直距离平方和的残差(OLS 方法的成本函数)(yₙxₙ)]定义为:

OLS 方法背后的思想是,由于残差平方和评估特定预测函数的总预测(或残差)误差,因此我们可以使用该成本函数( RSS )来导出当其预测误差最小时该函数的参数值( mc )。

这种推导是通过在最小值(0)时对( RRS )误差进行部分求导,找到系数( m )的表达式,以数学方式实现的。 m 的表达式如下:

其中 x̅是 x 变量的平均值,ȳ是 y 变量的平均值。

当最佳系数 m 使用上述导出的表达式确定时,我们因此可以通过在等式中输入 m 来使用它计算最佳截距 c :

因此,我们能够将最优线性回归线的参数估计为样本点的误差平方和最小的参数。

也许,一个实际的例子可以更好地解释如何利用普通的最小二乘法来确定预测函数的最佳参数。

考虑下面给出的样本数据:

***# independent variables
X = [8, 3, 2, 1, 2, 0, 1, 4, 3, 6, 5, 6, 8, 5, 6, 5, 5, 4, 8, 3] # dependent variables 
y =[12, 1, 2, 1, 5, 1, 2, 6, 4, 9, 6, 10, 14, 10, 6, 4, 9, 10, 8, 8]***

数据的散点图

如前所述,我们需要一个预测函数来拟合样本点的最佳直线。我们将利用 mc 的表达式来获得预测的最佳参数。虽然我们可以手工实现,但用 python 代码实现要容易得多。

显示系数和截距最佳值的输出

然后,我们可以将样本数据的最佳预测函数定义为:

***y = 1.33x + 0.76***

使用普通最小二乘法获得最佳回归线的数据点散点图

拟合线与给定数据点的垂直距离平方之和最小。

虽然普通的最小二乘解尽可能接近地解决了回归问题,但是它的应用受到限制,因为它的唯一目标函数是距离平方的和。我们可以利用一种更有效的方法来实现数据的线性回归建模,这种方法称为梯度下降法,可以应用于任何目标函数,而不仅仅是平方距离。

2。梯度下降法。

梯度下降是一种寻找函数局部极小值的迭代优化算法。它基于这样的思想,即当在函数的初始梯度的相反方向上采取重复步骤时,可以在函数的全局最小值处导出最优函数。

简而言之,梯度下降是一种通过反复降低成本函数来寻找函数最佳权重的方法。这是通过沿着初始梯度的相反方向逐渐移动成本函数的梯度来实现的。

梯度下降的 2D 表示。图片作者。

这如何帮助我们拟合最佳回归线?

嗯,如果我们可以在给定点导出我们的成本函数的梯度(一阶导数),那么我们可以通过沿着梯度的相反方向重复下降,在曲线的全局最小值处达到最佳预测函数(如上所示)。

那么,我们如何沿着成本函数梯度的相反方向下降,以达到全局最小值呢?

为此,让我们使用均方误差(MSE)作为成本函数。它是预测值和实际值之间的平均平方差的度量。MSE 由下式给出:

当我们将线性预测函数输入方程时,我们得到如下关系:

MSE 是可微分的,因此可以用来优化预测函数。使用 MSE,我们可以将成本函数在给定点的梯度导出为 mc 的偏导数,使得:

然后,我们可以通过逐步向导出的(初始)梯度的相反方向“移动”,使梯度向最小值下降。我们通过使用导出的梯度计算 mc 的电流值来进行数学计算,如下所示:

因为我们是沿着梯度一步一步地下降,所以控制我们下降的步长是有效的,这样我们就不会错过全局最小值,如下所示:

为了避免错过全局最小值,我们将包括一个称为学习率的参数,其基本功能是控制向全局最小值前进的步长。**

通过多次重复这些步骤(迭代)并连续确定参数和梯度的新值,我们逐渐向全局最小值移动,该全局最小值给出具有最小预测误差的预测函数(成本函数)的最优参数。

如果梯度下降法还不清楚,也许实用的方法更可取。让我们使用这种方法来获得一个最佳预测函数,该函数与前面使用 python 代码的示例中使用的数据相同。

***# independent variables
X = [8, 3, 2, 1, 2, 0, 1, 4, 3, 6, 5, 6, 8, 5, 6, 5, 5, 4, 8, 3]# dependent variables 
y =[12, 1, 2, 1, 5, 1, 2, 6, 4, 9, 6, 10, 14, 10, 6, 4, 9, 10, 8, 8]***

请注意成本(MSE)的持续降低,以及第 1200 个历元的参数如何等同于用 OLS 方法和。我们还可以调整超参数,如增加或减少学习率和迭代次数的值,以控制学习过程。

绘制学习率为 0.001 的前 50 次迭代的成本显示了向全局最小值的下降。

在我们的示例中,在通过偏导数调整权重之前,我们计算了每次迭代中所有样本的均方误差,这是一种梯度下降方法,称为批量梯度下降(BGD)* 。这种方法对于相对较小的数据集(如示例中所示)是有效的,但是对于较大的数据集,可能证明计算开销很大。对于更大的数据集,另一种方法是随机梯度下降****【SGD】,其中在每次迭代中仅评估随机样本的成本后调整参数。最常用的方法是小批量梯度下降,在每次迭代中使用一批样本进行训练,而不是像 SGD 那样只使用一个随机样本,或者像 BGD 那样使用所有样本。***

为了简单起见,到目前为止的例子包括了简单的线性回归问题。通过遵循以下关系,所讨论的方法也可以应用于多元线性回归:

***y = *m*₁X₁+ *m*₂X₂+ *m*₃X₃+…*m*ₙXₙ + cWhere: ***m*ᵢ** is the coefficient for each feature.
       ***c*** *is the intercept*.***

前面讨论的线性回归模型的一个缺点是系数有时可能取高值,导致模型预测的不稳定性,这在机器学习中通常被称为过拟合。解决这个问题的一种常见方法是规则化。

3。线性回归的正则化方法。

正则化或收缩是一种控制预测函数系数权重的方法,这样它们就不会取很大的值。

如前所述,线性模型对要素和目标变量做出某些假设,例如非多重共线性假设。例如,如果数据包含对预测模型有相反影响的负相关要素,这可能会使模型不稳定,因为要素的微小变化可能会导致预测中的较大差异。

虽然这个问题可以通过特征选择来解决(在这种情况下只保留一个相关的特征),但使用正则化(或惩罚)方法通常是更好的方法,因为这样可以避免遗漏有用的数据。这些方法通过严重惩罚这些特征的系数来解决这类问题,使得它们接收极低的权重。为此,我们将更改线性回归的成本函数,以包含系数,并大幅缩小取值非常高的系数。

岭回归、套索和弹性网是线性回归问题中最常见的收缩方法。

3i。岭回归中,我们简单地将权重的平方和添加到最小二乘成本函数中:**

通过将权重的平方和添加到成本函数,当优化例程试图在训练期间最小化前面的函数时,它不得不大幅降低系数值。alpha 参数用于控制收缩量。alpha 值越大,收缩越大。请注意,只有权重被正则化,而截距没有被正则化。这种类型的正则化技术被称为 L2 正则化。

L2 正则化方法的一个缺点是它不能促进稀疏性,因此可能会为高维数据集产生不可解释的模型。如果一个模型的大部分系数降为零,则称该模型为稀疏模型。解决稀疏性问题的一种方法是使用 L1 正则化的 Lasso 回归。

3ii。最小绝对收缩和选择算子 ( LASSO )是一种替代的正则化方法,与岭回归相比,它可以产生稀疏模型。

在 LASSO 中,很多系数都被降为零。它对于特征选择也很有用,因为它只选择一个相关特征,这与岭回归不同,在岭回归中,相关特征的系数被赋予相同的权重,尽管这通常会使岭回归模型具有更强的预测能力。

LASSO 通过用系数的绝对值之和而不是岭回归中的平方和来惩罚系数来实现这些。这就是所谓的 L2 正规化。

虽然套索方法解决了稀疏性问题,但它也有局限性,因为在特征选择过程中相关信息会丢失。在前面的方法之间达成折衷的一种方法是线性组合两者以产生具有 L1 和 L2 正则化子的优点的正则化子。

3iii。 弹性网络正则化是 L1 和 L2 正则化的线性组合,具有两种方法的优点。弹性网络函数定义为:

调整 alpha 参数可以让我们在两个正则项之间取得平衡。

虽然在不确定要使用的正则化方法时,使用弹性网正则化器可能是一个不错的选择,但根据数据集的结构和计算要求可以做出更好的选择。

线性回归模型的评估指标

由于我们已经介绍了如何在评估(和拟合)回归模型中使用残差平方和和以及均方误差,我们将介绍另外两个常见的评估指标,即平均绝对误差(MAE)* 和均方根误差(RMSE) 。***

i. 平均绝对误差(MAE) 是预测值与实际值之间的绝对差值的度量。MAE 由下式给出:

MAE 依赖于输入数据的规模,只能用于在基于类似规模的数据训练的模型之间进行比较。

二。均方根误差(RMSE)或均方根偏差(RMSD)* 是预测误差的标准偏差。它是预测误差分布的度量,显示了回归线周围数据的集中程度。它由 MSE 的平方根决定(顾名思义),计算公式如下:***

在现实世界的应用中,我们可能会对这篇博文中所涉及的方法和概念的更有效的实现感兴趣。这些方法很容易用 Scikit-Learn 的方法在 Python 中实现。

最后,让我们使用 Scikit-Learn 框架处理一个线性回归问题,实践这些概念如何结合起来解决现实世界的问题。

用 Scikit-Learn 实现线性回归建模

数据:我们将使用波士顿住房数据集。该数据集通过 13 个特征包含波士顿各种房屋的 506 个样本点。

任务:使用数据集建立一个线性回归模型,以估计给定特定特征的区域中的房屋价格。

  1. 加载和拆分数据集:数据集和一些其他流行的数据集在 Scikit-Learn 数据集包中可用,可以使用适当的方法调用来加载。数据集已经进行了使用前的预处理,因此我们可以继续将它分为训练集和测试集,用于模型构建。

输出:特征的数据帧

目标的数据框架

2.建立线性回归模型:我们通过创建 Sklearn 的 linear regression 方法的对象来建立线性回归模型。我们将设置参数来分别标准化和集中数据,以便更好地处理和建模。然后,我们将通过将训练特征和目标传递给模型的拟合函数来训练数据上的模型。最后,我们将显示拟合模型的截距和系数。**

输出:特征的系数

3.模型评估:我们将通过绘制残差图并检查其平均绝对误差来评估模型。**

该模型的 MAE 为 3.75。残差图显示,大多数残差分散在零附近。

总结:该帖子强调了线性回归模型的大部分概念、假设和评估,无论是在理论上还是在实践中。它考虑了解决线性回归的 OLS 和梯度下降方法,正则化方法的使用和公共评估指标,如 MSE,MAE 和 RMSE。最后,我展示了一种使用 Sklearn 框架进行线性回归建模的简单方法。

在建模中,第一步是最难的

原文:https://towardsdatascience.com/in-modelling-the-first-steps-are-the-hardest-a4250b80a0f2?source=collection_archive---------14-----------------------

以及为什么它们会影响你的其他工作

我已经在之前的博客中展示过模特天生缺乏安全感,培养这种不安全感很重要。我也已经提到过科学是流动的,机遇是有条件的。总之,这意味着事实核查是无用的,因为“事实”从属于当前的知识和依赖于其他机会的机会。因此,只有在您非常清楚这些组是谁的情况下,才可能按组对策略进行分类。因此,基于单一变量的指数化是极不可能的,当然也是极不可取的。

今天我想说的是,对于建模来说,最后一段并不是最难的。不,这只是第一步。当你开始做一个模型的时候,很重要的一点就是要快速明确你要建模什么,为什么要建模。想要“快”有时会妨碍过程,因为你一直在做假设。重要的是你让它们有多重要,尤其是在数据很少的情况下。此外,重要的不是数据量,而是数据是如何创建的。

我们中的许多人都是从数据集开始的,当我们谈论第一步时,我们谈论的是基于数据集创建第一个模型。对于新冠肺炎病毒,情况略有不同。数据每天都有,而正是你的模型在初始阶段的目标决定了行动。矛盾的是,甚至可能是这样的情况,开始时的不确定性决定了未来的进程,因为对病毒的反应也会影响病毒。例如,很有可能在一个模型中使用不同的初始假设会导致不同的政策,从而导致不同的过程。

所有这些现在都是桥下溢出的水,但重要的是要认识到每个模型都是脆弱的,尤其是在开始的时候。

看看下面的指数曲线就知道了:

图片作者。

这种图表的危险之处在于,这里的数据已经相当先进了。先进到足以发布指数曲线(y ~ b1*(1+b2)^x).即使你不确定公式的系数,数据也足以找到系数并画出曲线。换句话说,当你在这个阶段收集数据时,你很清楚你在看什么。

library(brms)
library(tidyverse)
library(cmdstanr)
library(kinfitr)
library(nls.multstart)
library(nlme)
library(hrbrthemes)
library(broom)
library(viridis)
library(epifitter)
library(nls2)
library(nlstools)
library(lattice)
library(bayesrules)
library(tidyverse)
library(janitor)
library(rstanarm)
library(bayesplot)
library(tidybayes)
library(broom.mixed)
library(modelr)
library(e1071)
library(forcats)
library(grid)
library(gridExtra)
library(fitdistrplus)
library(ggpubr)set.seed(1123)
b <- c(10, 3
x <- rnorm(200)
y <- rnorm(200, mean = b[1]*(1+(b[2])^x), sd=15)
dat1 <- data.frame(x, y)
plot(dat1$x,dat1$y)

prior1 <- prior(normal(10,30), nlpar = "b1") +
  prior(normal(4, 16), nlpar = "b2")
fit1 <- brm(bf(y ~ b1*(1+b2)^x, b1 + b2 ~ 1, nl = TRUE),
            data ​= dat1, 
            prior = prior1,
            sample_prior = T,
            chains=4,
            cores = getOption("mc.cores", 8),
            threads =16, 
            backend="cmdstanr")
summary(fit1)
plot(fit1)
plot(conditional_effects(fit1), 
     points = TRUE,
     rug=TRUE,
     theme=theme_bw()))

dat1 %>
  add_fitted_draws(fit1, n = 150) %>%
  ggplot(aes(x = x, y = y)) +
  geom_line(aes(y = .value, group = .draw), alpha = 0.05) + 
  geom_point(data = dat1, size = 0.05)+theme_bw()

dat1 %>%
  add_predicted_draws(fit1, ndraws = 4) %>%
  ggplot(aes(x = x, y = y)) +
  geom_point(color="black", alpha=0.2)+
  geom_point(aes(x = x, 
                 y = .prediction, 
                 group = .draw, colour=((y-.prediction)))) +
  facet_wrap(~ .draw) + theme_bw()

图片作者。

但是,如果您的数据没有超出最开始的范围呢?如果我只是删除一些数据,然后重新参数化模型呢?不难看出,在这个阶段我知道的很少,当我试图推断我的模型时,我会到处去。因为我做的模型是贝叶斯模型,先验现在占了大部分权重,曲线看起来是指数型的。,但这一切都是基于假设。

图片作者。

上图显示了基于不完整数据以及整个数据集的假设轨迹。两种情况都有可能。甚至有一个超出想象的预测,这是先验与可能性无关的明显标志。

我想展示的另一个例子是基于 Gompertz 曲线。Gompertz 公式如下所示,用于许多过程。例如,在 Gompertz 中可以捕捉到一个人的成长,也可以捕捉到一头猪的成长。它还有助于监测病毒感染,因此在下文中,它已被用于捕捉对“英国变种”增长的估计。我关心的是模型估计,它远远超出了萌芽监测的观察结果。用贝叶斯术语来说——先验 far 否决了可能性。这不是一个问题,因为当我们说话的时候数据正在进来,但是它确实保证持续更新。

图片来源:
国家公共卫生与环境研究所;厚生劳动省。

从建模的角度来看,上图实际上是不可能的,因为数据甚至没有越过拐点。拐点是递增增长和递减增长的分界线。现在的情况是,图表非常清楚地表明红色曲线来自一个模型,但它没有说明该模型是基于哪个数据产生的。我们不知道先前的假设。

让我模拟数据来说明我的意思。

dat<-sim_gompertz(N  = 10
                  dt = 0.5, 
                  y0 = 0.01, 
                  r  = 0.07, 
                  K  = 1, 
                  n  = 20,  
                  alpha = 1)
dat<-as.data.frame(dat)
plot(dat$time, dat$random_y)

g1<-ggplot(dat, aes(x=time))+
  geom_line(aes(y=y)) +
  geom_point(aes(y=random_y), color="grey", alpha=0.2)+
  labs(title="Gompertz Curve", 
       x="Total time course of the epidemic", 
       y="Disease Intensity")+theme_bw()

g2<-ggplot(dat, aes(x=time))+
  geom_boxplot(aes(y=random_y, group=time), color="grey", alpha=0.2)+
  geom_line(aes(y=y)) +
  labs(title="Gompertz Curve", 
       x="Total time course of the epidemic", 
       y="Disease Intensity")+theme_bw()

g3<-ggplot(dat, aes(x=time, y=random_y))+
  stat_summary(fun.data = "mean_cl_boot", colour = "black", size = 0.2)+
  geom_smooth(color="red", alpha=0.5)+
  labs(title="GAM model", 
       x="Total time course of the epidemic", 
       y="Disease Intensity")+theme_bw()

g4<-ggplot(dat, aes(x=time, y=random_y))+
  geom_point(color="black", alpha=0.2)+
  geom_smooth(aes(color=as.factor(replicates),
              fill=as.factor(replicates)), alpha=0.2)+
  facet_wrap(~replicates)+
  labs(title="LOESS model", 
       x="Total time course of the epidemic", 
       y="Disease Intensity")+
  theme_bw()+theme(legend.position = "none")
ggarrange(g1,g2,g3,g4)

图片作者。

左下方的图表可能最能说明我所说的模型和少量数据的含义。这个模型不是在 Gompertz 的基础上获得的,而是在 GAM 模型的基础上获得的,GAM 模型是一种观察数据的统计模型。如果我砍掉数据,直到左边只剩下很小一部分,GAM 就不会显示同样的曲线。基于 Gompertz 函数的非线性模型仍然可以做到这一点,但该模型必须基于许多假设。把它比作在一个黑暗的房间里预测一天的天气,只有微弱的光线指引你。

dat<-sim_gompertz(N  = 10
                  dt = 0.5, 
                  y0 = 0.01, 
                  r  = 0.07, 
                  K  = 1, 
                  n  = 20,  
                  alpha = 1)
dat<-as.data.frame(dat);dat$x<-dat$tim
fitgomp<-fit_nlin2(time = dat$time,
          y =  dat$y,
          starting_par = list(y0 = 0.01, r = 0.07, K = 1),
          maxiter = 1024)
fitgomp
g1<-function(x,a,b,c){
  a*exp(-b*exp(-c*x))
}
g2 <- function(x, y0, ymax, k, lag){
  y0+(ymax-y0)*exp(-exp(k*(lag-x)/(ymax-y0)+1))
}
g3<-function(x,n0,nI,b){
  n0*exp(log(nI/n0)*(1-exp(-b*x)))
}
plot(dat$x, dat$random_y)
curve(g1(x, a=1, b=4.5, c=0.07), add=T, col="red", lwd=2) 
curve(g2(x, y0=0.01, ymax=1, k=0.07, lag=8), add=T, col="blue", lwd=2) 
curve(g3(x, n0=0.01,nI=1,b=0.07), add=T, col="orange", lwd=2)

图片作者。

幸运的是,一旦模型收集了相当多的数据,它们就可以很好地处理不确定性。这里我将使用一个特定的非线性模型,它能够包含不确定性的来源。假设我们收集了前 20 个城市的数据。

dat_new<-groupedData(random_y~time|replicates,
                       data=dat,
                       FUN=mean,
                       labels=list(x="Time", y="Disease Intensity")) 
fit<-nlme(random_y~n0*exp(log(nI/n0)*(1-exp(-r*time)))
          data​=dat_new, 
          fixed=n0+nI+r~1, 
          random=r~1, 
          start=c(0.01,1,0.07),
          method="ML", 
          control=nlmeControl(maxIter=100000, msMaxIter = 100))
plot(augPred(fit, level=0:1))
fitpreds <- dat_new %>% mutate(.fitted=predict(fit, newdata=dat_new))
ggplot(dat_new, aes(x=time, y=random_y)) 
  geom_point() +
  geom_line(data=fitpreds, aes(y=.fitted, 
                               group=replicates, 
                               colour=replicates),size=1) +theme_bw()+labs(title="NLS model",
                                                  x="Total time course of the epidemic",
                                                  y="Disease Intensity")

图片作者。

为了更好地了解我们建模的不确定性,即使我们已经有了大量数据,我也会对相同的数据应用贝叶斯模型。

gompprior <- c
  set_prior("beta(1, 20)",       nlpar = "n0", lb=0, ub=1),
  set_prior("gamma(1, 1)",       nlpar = "nI", lb=0, ub=1),
  set_prior("normal(0, 1)",      nlpar = "r",  lb=0), 
  set_prior("normal(0.05, 0.2)", class="sigma"))gomp_bayes <- bf(random_y ~ n0*exp(log(nI/n0)*(1-exp(-r*time))),
                             n0 + nI + r ~ 1,
                             nl = TRUE)options(mc.cores=parallel::detectCores())
gomp_bayes_fit <- brm(
  gomp_bayes,
  family=gaussian(), 
  data ​= dat_new,
  prior = gompprior )

plot(gomp_bayes_fit)
pairs(gomp_bayes_fit)

predtimes <- unique(dat_new$time)
gomp_bayes_fitted <- fitted(gomp_bayes_fit, 
                            newdata=list(time = predtimes))%>%as_tibble()
gomp_bayes_pred <- predict(gomp_bayes_fit,
                           newdata=list(time = predtimes))%>%as_tibble()
gomp_bayes_ribbons <- tibble(
  time = predtimes,
  random_y=gomp_bayes_fitted$Estimate,
  Estimate = gomp_bayes_fitted$Estimate,
  pred_lower = gomp_bayes_pred$Q2.5,
  pred_upper = gomp_bayes_pred$Q97.5,
  fitted_lower = gomp_bayes_fitted$Q2.5,
  fitted_upper = gomp_bayes_fitted$Q97.5)
ggplot(dat_new, aes(x=time, y=random_y)) +
  geom_point(size=2, alpha=0.2) +
  geom_ribbon(data=gomp_bayes_ribbons, aes(ymin=pred_lower, ymax=pred_upper), 
              alpha=0.2, fill=colourcodes[3]) +
  geom_ribbon(data=gomp_bayes_ribbons, aes(ymin=fitted_lower, ymax=fitted_upper), 
              alpha=0.5, fill=colourcodes[3]) +
  geom_line(data=gomp_bayes_ribbons, aes(y=Estimate), colour=colourcodes[3], 
            size=1) + labs(title="Bayesian model", 
                           x="Total time course of the epidemic", 
                           y="Disease Intensity")+
  theme_bw()+theme(legend.position = "none")

图片作者。

从上图中可以看出,蓝色的模型线包含了相当多的不确定性。这也反映在下面各个参数的估计值中,以及参数之间的相关性中。重要的是要记住,模型预测强烈依赖于模型系数,而这些系数又依赖于数据和相互关系。假设驱动一个只有少量数据的模型。再一次,在贝叶斯分析中,我们接受这样的情况。

图片作者。

如果我们像以前一样删除一些数据,会发生什么?那它看起来像什么?下面我要求的是严格限制天数,并用这些数据显示 Gompertz 曲线。我已经知道了那条曲线的参数,所以我对下限和上限的变化以及繁殖率感兴趣。

set.seed(1123
dat<-sim_gompertz(N  = 100,
                  dt = 0.5, 
                  y0 = 0.01, 
                  r  = 0.07, 
                  K  = 1, 
                  n  = 20,  
                  alpha = 1)
dat<-as.data.frame(dat);dat$x<-dat$time
dat_new<-groupedData(random_y~time|replicates, 
                     data=dat,
                     FUN=mean,
                     labels=list(x="Time", y="Disease Intensity"))
dat_new_1<-dat_new%>%filter(x<10)%>%mutate(random_y=replace(random_y,0,0.001))
plot(dat_new_1$x,dat_new_1$random_y)
fit<-nlme(random_y~n0*exp(log(nI/n0)*(1-exp(-r*time))),
          data​=dat_new_1, 
          fixed=n0+nI+r~1, 
          start=c(0.01,1,0.07),
          method="ML", 
          control=nlmeControl(maxIter=100000, msMaxIter = 100)))

这个模型不会运行,我也不能在数据上绘制一个假设的 Gompertz 曲线。

ggplot(dat_new_1, aes(x=time, y=random_y)
  geom_point(color="grey", alpha=0.2)+
  stat_summary(fun.data = "mean_cl_boot", colour = "black", size = 0.2)+
  stat_smooth(method = 'nls', formula = 'y ~ n0*exp(log(nI/n0)*(1-exp(-r*x)))',
              method.args = list(start=c(n0=0.01,nI=1,r=0.07)), se=TRUE)+
  geom_smooth(color="red",fill="red", alpha=0.2)+
  labs(title="GAM model", 
       x="Total time course of the epidemic", 
       y="Disease Intensity")+
  theme_bw())

图片作者。

现在让我们看看,当我试图从现在的模型中推断未来时,会发生什么。毫无疑问,上面的红线是一个模型,它被训练成尽可能整齐地放置在数据之上。非线性函数通常不是这样的。它们的功能是从生物学和逻辑学的角度将起点和终点联系起来。然而,他们需要足够的数据来找到合适的系数。这就是我现在想做的,求系数。

set_prior("beta(1, 20)",       nlpar = "n0", lb=0, ub=1),
  set_prior("gamma(1, 1)",       nlpar = "nI", lb=0, ub=1),
  set_prior("normal(0, 1)",      nlpar = "r",  lb=0), 
  set_prior("normal(0.05, 0.2)", class="sigma"))

gomp_bayes <- bf(random_y ~ n0*exp(log(nI/n0)*(1-exp(-r*time))),
                 n0 + nI + r ~ 1,
                 nl = TRUE)
options(mc.cores=parallel::detectCores())

gomp_bayes_fit <- brm(
  gomp_bayes,
  family=gaussian(), 
  data ​= dat_new_1,
  prior = gompprior )
summary(gomp_bayes_fit)
plot(gomp_bayes_fit)
plot(conditional_effects(gomp_bayes_fit), 
     points = TRUE,
     rug=TRUE,
     theme=theme_bw()) 

dat_new_1 %>%
  add_fitted_draws(gomp_bayes_fit, n = 150) %>%
  ggplot(aes(x = x, y = y)) +
  geom_line(aes(y = .value, group = .draw), alpha = 0.05) + 
  geom_point(data = dat_new_1, size = 0.05)+theme_bw()+
  labs(title="Bayesian Model overlayed on trained data",
       x="Total time course of the epidemic",
       y="Disease Intensity")

dat_new %>%
  add_fitted_draws(gomp_bayes_fit, n = 150) %>%
  ggplot(aes(x = x, y = y)) +
  geom_vline(xintercept = 10, color="red", linetype=2)+
  geom_line(aes(y = .value, group = .draw), alpha = 0.1) + 
  geom_point(data = dat_new, size = 0.05)+theme_bw()+
  labs(title="Bayesian Model overlayed on all data",
       x="Total time course of the epidemic",
       y="Disease Intensity")

显而易见的是,结果提供了不同的参数。再现值从 0.07 到 0.09,估计线顶是 0.58 而不是 1。

Family: gaussian
  Links: mu = identity; sigma = identity 
Formula: random_y ~ n0 * exp(log(nI/n0) * (1 - exp(-r * time))) 
         n0 ~ 1
         nI ~ 1
         r ~ 1
   Data: dat_new_1 (Number of observations: 400) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
             Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
n0_Intercept     0.01      0.00     0.01     0.02 1.01      833      662
nI_Intercept     0.58      0.23     0.21     0.98 1.01      527      190
r_Intercept      0.09      0.02     0.06     0.15 1.01      496      162

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     0.04      0.00     0.04     0.04 1.00     2006     1936

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS and Tail_ESS are effective sample size measures, and Rhat is the potential scale reduction factor on split chains (at convergence, Rhat = 1).

表格实际显示的内容可以通过三个视觉效果得到最好的解释。第一,基于数据的条件模型。

图片作者。

第二,基于数据的可能性范围。

图片作者。

第三,模型的外推覆盖了全部数据,但基于不完整的数据。红线显示模型成为外推的地方。它显示了基于起始点来拟合一条曲线是多么困难。这只有在你对疾病强度的过程非常确定的情况下才有可能。这是相当多的假设。为了比较,荷兰国家公共健康和环境研究所的数据再次被加入。看出区别。

图片作者。

国家公共卫生和环境研究所;卫生、福利和体育部/

欢迎评论(反馈)和指出错误。讨论当然也是!

在 8 个关键 MLOps 角色中,您处于什么位置?

原文:https://towardsdatascience.com/in-the-8-key-mlops-roles-where-do-you-fit-in-251272ca5488?source=collection_archive---------24-----------------------

大规模数据科学团队可以有几个不同的角色和职责来管理机器学习操作。

数据科学中的 MLOps 有各种角色和职责——由 Lucas SantosUnsplash 上拍摄。

T 五年前这里还没有什么叫MLOps。但现在它是任何数据科学项目不可或缺的一部分。

MLOps 是指将 DevOps 原理应用于机器学习(ml)系统的实践。MLOps 有助于在大型数据科学项目中保持 ml 模型的开发和部署之间的无缝集成。

在大多数项目中,与实际的模型构建相比,操作方面是巨大的。因此,除了数据科学家之外,它通常还需要几个角色。

根据组织的规模和项目的性质,数据科学团队可以扮演一个或多个这样的角色。在中小型团队中,他们的职责也经常模糊不清。然而,大公司在合理的范围内管理不同的角色和职责。

这篇文章可以帮助你区分不同的角色和他们的职责。如果你刚刚进入数据科学职业生涯,或者希望转到另一个领域,这篇文章也可以帮助你决定专注于哪些技能。

业务分析师或领域专家

大多数人没有意识到业务分析师(BA)是数据科学团队的一部分。然而,他们的贡献是机器学习操作中最关键的部分。

他们在业务涉众和技术团队之间扮演翻译角色。他们擅长说两个世界的语言。

BAs 帮助技术团队将业务问题分解成可操作的机器学习问题。此外,他们协助外部涉众交流项目的时间表、进度和成果。

ba 很少编码,但是他们有很好的数据素养。他们花大部分时间准备有用的文档和演示文稿。他们非常擅长项目规划和管理。

在我看来,成功的商业分析师最显著的特征是他们的讲故事技巧。如果你喜欢讲故事和创造性地传达信息,这可能是一个非常适合你的角色。

数据分析师

数据分析师(DA)与业务分析师非常相似。但是 DAs 比 BAs 更专注于技术方面。

数据分析师的主要职责是从数据中获取洞察力。

在大多数情况下,他们花时间从不同的角度探索数据。DAs 不太担心机器学习模型及其生产实现。这是因为他们需要有一个开放的心态来获得有价值的见解。因此,这种分离有助于他们不去纠结于无用的琐碎解决方案。

然而,他们的工作是解决正确问题的精髓。

没有 Excel(或任何电子表格软件),DA 的工具包是不完整的。现代 DAs 还关注 Tableau 和 PowerBI 等自助式分析平台。根据项目需要,一些 DA 应该具有 SQL 方面的丰富知识,而其他 DA 可能具有 GIS 软件等技术方面的专业知识。

大多数 da 都知道如何编码。他们使用 R 或 Python 进行探索性数据分析。

软件工程师和开发人员

软件工程师帮助将机器学习模型产品化。

不是每个人都拥有打开 Jupyter 笔记本并运行 Python 脚本来使用机器学习预测的技能。如果它被包装在友好的用户界面中,他们会使用它。

此外,软件工程师担心一系列常规数据科学家不关心的其他事情。包括软件访问控制使用统计采集、跨平台集成、托管等。

对于在机器学习项目中工作的软件开发人员来说,某种程度的数据素养是更可取的。然而,并不是所有的软件开发人员都擅长建模。

另一方面,软件工程有自己的技能。他们用诸如 Django T1 和 T2 Flask T3 这样的框架创建网络应用。大多数软件工程师也更喜欢前端框架,如 ReactVue 。React 允许为 iOS、Android 和桌面创建跨平台应用。但是一些大型团队也有本地移动开发者。

数据和 ML 架构师

ML 架构师担心整个机器学习项目生命周期。他们创建项目的结构和分阶段执行的策略。他们还试图预见完成项目和在生产中维护模型的任何风险。

他们还充当数据科学家、工程师和软件开发人员之间的连接器。架构师帮助团队选择是进行内部实现、数据仓库还是云数据湖。它们帮助这对夫妇选择合适的数据存储和检索策略,以获得最佳性能和成本。

数据架构师精通各种工具和技术,因为评估和选择正确的工具和技术是他们的责任。因此,他们通常对数据管道技术、算法以及前端 web 框架有着更深刻的理解。

数据工程师

数据工程师是平台的推动者。他们确保相关数据可用于机器学习项目,并且其质量符合要求的标准。

数据工程师大部分时间花在构建数据管道上。数据管道确保来自数据源的数据流不中断,对数据进行初步转换,并将其加载到适当的数据存储中。这个过程通常被称为 ETL。

数据工程师使用 Airflow 和 Prefect 等工具来构建 ETL 管道。它们帮助协调各种单独的任务,并按计划运行它们。

它们也有助于数据湖、数据仓库等概念。他们精通 SQL 语言、Postgres、MySQL 等数据库技术。

MLOps 工程师

MLOps 工程师确保模型部署到生产系统的自动化。不同组织的自动化水平可能有所不同。

MLOps 工程师的职责是从数据科学家那里获得模型,并将其提供给使用它的软件。数据科学家经常使用 Jupiter 笔记本或脚本文件来构建、测试和验证他们的机器学习模型。另一方面,软件工程师希望机器学习模型可以通过 REST 等可调用的 API 来访问。

💔-ways-to-deploy-machine-learning-models-in-production-cdba15b00e>

MLOps 与 DevOps 略有不同。这是因为机器学习项目本质上是实验性的,而软件项目是决定性的(大部分情况下。)此外,测试机器学习模型与软件测试截然不同。数据科学中的测试涉及预测质量和一系列其他独特的挑战。

MLOps 工程师通常对数据管道非常了解。他们也像数据工程师一样,使用诸如 Airflow 和 Prefect 之类的技术来自动化任务。有助于 MLOps 的一项相对较新的技术是 MLFlow

优化工程师

大多数组织将预算的很大一部分花在数据管道、存储和模型训练上。但是,scikit learn 等低级代码库并没有针对不同的硬件进行优化。它们是为在日常使用情况下执行而构建的。

对于较小的项目,这根本不重要。但是,随着规模的扩大,您的基础架构成本会呈指数级增长。这就是优化工程师来拯救的地方。

优化工程师的工作是转换用低代码库构建的模型,以便在所选的硬件系统上执行得更好。他们知道如何将它们转换成 LLVM 位代码,并行运行它们,等等。

数据科学家

没有数据科学家的数据科学项目算什么?他们是任何机器学习项目的核心人物。

这篇文章主要是关于数据科学的各个方面,而不是模型构建、测试和评估(即 MLOps)。然而,如果不提及数据科学家,这个列表就不完整。

他们的责任是找出解决商业问题的正确的机器学习模型。他们尝试不同的算法,调整它们以获得最佳超参数,评估它们并用各种标准验证结果。

然而,如果团队很小,数据科学家会承担大部分其他职责。在较小的单位中,数据科学家也是数据架构师和数据工程师。

因此,术语“数据科学家”在某种程度上概括了上述所有其他角色。

最后的想法

构建算法只是数据科学项目的一小部分。这个谜还有许多其他复杂的工作要完成。

在小项目中,一个人或几个数据科学家可以建立机器学习模型,并用 Streamlit 等技术将其产品化。

然而,更大的组织需要许多其他角色,专门从事整体业务问题的特定方面。我们将超越模型构建的数据科学项目任务称为 MLOps。

在本文中,我们讨论了八个角色,包括在 MLOps 中非常常见的数据科学家角色。与他们每个人一起,我们讨论了他们的职责和所需的技能。

感谢阅读,在 LinkedInTwitterMedium 上向我问好。

还不是中等会员?请使用此链接 成为会员 因为,不需要你额外付费,我为你引荐赚取一小笔佣金。

在你的人工智能策略中包括模型操作

原文:https://towardsdatascience.com/including-modelops-in-your-ai-strategy-f3a7bb4831dd?source=collection_archive---------28-----------------------

如何根据企业的价值预期运营、整合和部署人工智能模型

马库斯·斯皮斯克Unsplash 上拍摄的照片

现代有组织的企业认识到,采用数据驱动的战略对于在日益数字化的市场中竞争至关重要。数据和分析已经成为一个非常重要的优先事项,上升到董事会层面,董事会将机器学习和人工智能等技术视为增加业务能力的机会,使流程更加高效,并促进新商业模式的传播。

广泛而言,对人工智能和数据管理的投资正在急剧增加,新的数据科学项目正在进行中,以建立用于各种目的的预测和分析模型。然而,尽管公司计划在合理的时间内扩大复杂的人工智能解决方案,但残酷的现实是,这些解决方案的采用往往停滞不前,因为公司通常更关注开发而不是模型的可操作化。对于许多非数字本土企业来说,数据科学学科的采用往往始于众多独立、分散的数据科学团队,这些团队基本上致力于开发机器学习和深度学习的模型。

这些小型的数据科学家团队在不同的业务部门涌现出来,目的是为不同的业务目的构建模型。此外,由于新的先进技术的广泛可用性,这些模型的开发很容易实现,为了利用这些丰富的精彩技术来大规模创建更新和执行的人工智能解决方案,公司必须处理影响生产流程和运营的日益增加的复杂性。试想一下支持数据科学家深入数据科学世界的大量软件工具,如 Python 库、Jupyter notebooks、Spark MLlib、Dask 和其他众多基于新算法的开源库,这些开源库已在各地涌现,允许数据科学家进行传统的聚类、异常检测、大规模预测,甚至更进一步,进行面部识别或视频分析。

不幸的是,这种方法已被许多公司采用,导致数据科学团队的分散和分散,从而导致模型开发速度变慢,业务部门之间完全缺乏协作。因此,首席执行官和企业高管对这些举措感到不满,因为公司未能通过积累未实施、未使用和未更新的模型来扩展人工智能,这些模型是手动实施的,并且通常与人工智能应有的价值预期不一致。

因此,公司需要采用能够帮助他们及时交付价值并符合预期的解决方案。这些功能必须设计为支持和加速模型的开发过程,并通过使企业能够扩展和管理其人工智能计划,找到更快的方式将机器学习模型投入生产。

调查显示,集成和风险管理是人工智能模型可操作化的最大障碍,因此也是人工智能计划成功的最大障碍。

专注于人工智能的高管面临许多模型运算的挑战,从“状态到
模型运算 2021

利用 ModelOps 解决模型部署和模型治理之间的差距

模型长期以来一直被视为必不可少的企业资产,人工智能模型正在显示出它们提供非常重要价值的能力。企业越来越认识到,要在管理风险的同时持续抓住这一价值,需要人工智能时代的模型操作实践。结果,他们投资了 ModelOps。

ModelOps 正在成为一项核心业务能力,企业正在投资创建更有效的流程和系统来运营人工智能模型。

ModelOps 企业功能。图片由来源,经作者许可编辑

根据 Gartner 的说法,“人工智能(AI)模型操作化(ModelOps)是一组主要关注所有 AI 和决策模型的治理和全生命周期管理的功能。这包括基于机器学习(ML)、知识图、规则、优化、自然语言技术和代理的模型。与 MLOps(仅关注 ML 模型的可操作性)和 AI ops(IT 运营的 AI)不同,ModelOps 关注所有 AI 和决策模型的可操作性。因此可以理解,在大型企业中,有效的 ModelOps 能力可以加速整个公司的人工智能计划。ModelOps 消除了浪费、摩擦和超额成本,并释放了企业(包括专业和公民数据科学家)的创造力,同时保护企业免受潜在的无限风险。Gartner 在其报告“ModelOps 的创新洞察—2020 年 8 月 6 日”中,重点关注了组织在大规模部署、监控和治理 AI 模型时面临的挑战以及对企业 ModelOps 战略的需求,指出“组织在大规模构建和部署 AI 模型时面临重大挑战—导致 AI 人员的生产力低下,运营延迟和价值创造有限。数据和分析领导者必须通过利用 ModelOps 来应对这些挑战,以变得更加有效”此外“ ModelOps 是任何组织的企业人工智能战略的核心,它是一项关键的使能技术,可融合各种人工智能工件、平台和解决方案,同时确保可扩展性和治理”。

因此,模型操作

  • 主要专注于人工智能和决策模型的治理和生命周期管理(包括机器学习、知识图、规则、优化、语言和基于代理的模型)。核心能力包括模型开发环境的管理、模型库、冠军挑战者测试、模型展示/回滚和 CI/CD(持续实施/持续交付)集成
  • 支持人工智能模型的重新调整、重新训练或重建,在基于人工智能的系统中提供模型开发、运行和维护之间的不间断流程
  • 为业务领域专家提供自主性,以评估生产中人工智能模型的质量(解释结果和验证 KPI ),并促进提升或降级人工智能模型进行推理的能力,而无需完全依赖数据科学家或 ML 工程师。

ModelOp 的联合创始人兼首席人工智能架构师 Stu Bailey 说:“ModelOp 是一种专注于将模型投入 24/7 生产的能力。这是 CIO 的组织或大型组织的技术中心必须拥有的能力”。

人工智能模型。图片由来源提供,经作者许可编辑

释放 AI 的价值

人工智能的价值往往没有得到释放,因为操作化人工智能往往是事后的想法,而在整个组织内生产人工智能/人工智能模型的努力被低估了。许多团队仍在努力在他们的应用程序中充分发挥人工智能的潜力,部分原因是在满足企业治理要求的同时支持人工智能生命周期所需的技能、工具和平台方面的投资。人工智能运营支持对于缩小这些差距至关重要,它允许这些团队更容易地将人工智能技术融入他们的应用程序中。

正如数据科学研究员(BNY 梅隆大学)Skip McCormick 所说,许多人工智能功能仍处于有很大潜力的阶段。很少有组织同时将足够的资源投入到他们在生产环境中需要的基础设施中。

今天,为了在竞争中胜出,企业正在投资人工智能。但是人工智能的好处只有在模型被正确操作后才能被认识到。

由于人工智能技术栈在不断发展,数据科学家希望能够使用最好的工具,通过自动化 ModelOps 基础设施工程来大规模开发和部署数据科学模型,而企业通常很乐意适应这一点。因此,在企业环境中开发、部署和管理人工智能的生态系统变得复杂起来。

ModelOps 工具

由于 ModelOps 方法将所有参与者聚集在一起,一些新兴的初创企业和企业公司提供了 ModelOps 解决方案,以在端到端的全自动模型生命周期中统一编排这些组件。让我们看看下图,它展示了企业如何通过管理平台来治理和扩展任何人工智能计划。

模型操作:编排和模型生命周期。图片由来源,经作者许可编辑

ModelOp Center 这样的强大平台通常会与开发平台、IT 系统和企业应用程序集成,以便企业可以利用和扩展在人工智能和 IT 方面的持续投资。通过这种方式,数据科学家可以使用他们最熟悉的工具进行大规模工作。

ModelOps 集成—图片来自来源,经作者许可编辑

借助 ModelOp Center 等平台,企业可以:

  • 将从模型部署到决策制定的时间缩短 50%或更多;
  • 将模型收入贡献提升高达 30%;
  • 并通过人工智能治理工作流降低业务风险。

结论

在许多行业和公司中,人工智能的战略力量已经彻底确立。这导致了模型创建的激增。但是对操作模型(即模型操作)的人员、流程和工具的投资却落后了。组织必须创建专门的模型操作员或模型工程师角色来承担日常的模型操作职责。

人们越来越认识到这一职能、它所解决的问题、它所创造的机会以及支持这一职能所需的投资。就像之前的 DevOps、ITOps 和 SecOps 一样,随着全球人工智能应用的成熟,ModelOps 看起来将成为一个独立的核心业务功能。

参考文献

在平面数据工作流中包含 R

原文:https://towardsdatascience.com/including-r-in-your-flat-data-workflow-282356342094?source=collection_archive---------36-----------------------

使用 GitHub Actions + R 自动获取和清理数据

GitHub OCTO 团队最近发布了他们的第一个项目: 平面数据 。该项目旨在提供“一种简单的模式,将工作数据集引入您的存储库并对它们进行版本控制。”它成功地做到了!我最近将平面数据合并到我的项目之一中,允许我最终停止半定期地手动更新数据(哎呀!).工作时,我找不到任何关于使用 R 处理平面数据的文档。在这里,我将解释我将 R 脚本合并到平面数据管道中所采取的步骤。

注:如果你想跟随,GitHub repo 可以在这里找到。

什么是平面数据?

平面数据解决了执行相同的重复任务——检索、清理、然后重新发布数据——的问题,这通常会影响希望呈现快速更新数据(例如,每天更新的新冠肺炎数据)的开发人员。尽管存在替代解决方案,但是平面数据简单、直观,并且可以直接与您的 GitHub 存储库集成:

GitHub 平面数据工作流程。图片 via GitHub Octo

如上所述,这个想法本质上是读入数据( data.json ),进行一些后处理( process.js ),并输出一些更好的数据( processed-data.json )。

在 R 中做

平面数据项目最重要的步骤是后处理。这发生在数据检索之后的和数据输出之前的,并且可以用几种不同的语言来完成。默认情况下,OCTO 团队的示例是用 JavaScript/TypeScript 完成的,一位用户已经给出了用 Python 进行后处理的示例。然而,据我所知,还没有任何在后处理阶段包含 R 的例子,这就是这篇文章的原因!

在平面数据管道中使用 R 非常简单,只需安装必要的软件包,然后从后处理类型脚本文件中获取 R 清理脚本。让我们探索一下它是如何工作的。

我们将从警察暴力地图主页上获取数据,整理后重新发布。(这些经过清理的数据是我对警察暴力进行可视化的来源。)下面是最终的数据输出

01.设置flat.yml

任何平面数据管道的第一步都是创建.github/workflows/flat.yml,它将包含项目的配置。你可以通过使用 GitHub 的 VSCode 扩展或者手动创建你自己的 YAML 文件来实现。我们在这个项目中使用的 YAML 文件与样板文件非常相似,但有一些不同:

name: Update data
on:
  schedule:
    - cron: 0 0 * * * # Runs daily. See https://crontab.cronhub.io/
  workflow_dispatch: {}
  push:
    branches:
      - main # Or master, or whatever branch you'd like to 'watch'
jobs:
  scheduled:
    runs-on: ubuntu-latest
    steps:
      # This step installs Deno, which is a Javascript runtime
      - name: Setup deno
        uses: denoland/setup-deno@main
        with:
          deno-version: v1.x
      # Check out the repository so it can read the files inside of it and do other operations
      - name: Check out repo
        uses: actions/checkout@v2
      # The Flat Action step
      - name: Fetch data
        uses: githubocto/flat@v2
        with:
          http_url: https://mappingpoliceviolence.org/s/MPVDatasetDownload.xlsx # File to download
          downloaded_filename: raw.xlsx # Name of downloaded file
          postprocess: ./postprocess.ts # Runs upon completion

您可能会在http_urlschedule中对这个工作流程进行调整。要确认这一点,请访问 GitHub 的文档

02.后处理

我们从上一部分的最后一行代码开始:

postprocess: ./postprocess.ts

这里,我们引用一个名为postprocess.ts的打字稿文件。数据下载完成后,GitHub 将运行该脚本进行任何额外的处理步骤。该文件必须是.js.ts文件。

那些擅长用 JavaScript 处理数据的人也许能够在 JavaScript 本身中编写他们的额外处理,但是我们中很少有人擅长用 JavaScript 处理数据。此外,一些用户希望将他们现有的项目和工作流迁移到平面数据,因此包含 JavaScript 之外的语言(在本例中是 R)是非常必要的。

我在工作流程中使用的postprocess.ts文件如下所示(这可能有助于了解 Deno 如何工作):

*// 1\. Install necessary packages
const r_install = Deno.run({
    cmd: ['sudo', 'Rscript', '-e', "install.packages(c('dplyr', 'readxl', 'readr', 'lubridate', 'stringr'))"]
});

await r_install.status();

// 2\. Forward the execution to the R script
const r_run = Deno.run({
    cmd: ['Rscript', './clean.R']
});

await r_run.status();*

上面的脚本相当简单:它 1)安装包,2)运行处理脚本,标题为clean.R

第一步很重要。在建立这个工作流程时,包管理是我遇到的最大问题;如果你有问题,请注意这一步。您需要识别 R 处理脚本中需要的所有包,但是由于虚拟机权限,您不能在脚本本身中安装这些包。相反,你必须通过命令行运行它们,使用sudo Rscript -e,就像我上面做的那样(在步骤 1 中)。**

命令sudo Rscript -e位于 R 脚本中运行的任何常规函数或命令之前。它通过命令行执行这些命令,而不是在脚本中。(我们添加 sudo 是为了克服系统用户权限问题。)更多内容,见本页

03.清理数据!

我的clean.R脚本是这样的,我在postprocess.ts的底部引用了它:

*# Load libraries
library(dplyr)
library(stringr)

# Read in data, with the same name that we specified in `flat.yml`
raw_data <- readxl::read_excel("./raw.xlsx")

# All the processing!
clean_data <- raw_data %>% 
  rename("Date" = `Date of Incident (month/day/year)`,
         "Link" = `Link to news article or photo of official document`,
         "Armed Status" = `Armed/Unarmed Status`, 
         "Age" = `Victim's age` , 
         "Race" = `Victim's race`, 
         "Sex" = `Victim's gender`, 
         "Image" = `URL of image of victim`, 
         "Name" = `Victim's name`) %>% 
  mutate(Zipcode = as.character(Zipcode),
         Year = lubridate::year(Date),
         Sex = ifelse(is.na(Sex), 'Unknown', Sex)) %>% 
  arrange(Date)

### Additional processing goes here...

# Output data
readr::write_csv(clean_data, "./output.csv")*

显然,上述清理脚本中的内容无关紧要。它的功能和其他 R 脚本一样:它读入数据(基于我们在postprocess.ts中下载的数据),做一些清理,然后输出新数据。真实剧本大概 55 行左右。现在你知道为什么把后处理放在 R 中更好了!

总而言之

在完成这些步骤并将上述内容推送到存储库后,GitHub 将自动设置动作并每天运行它。然后,您可以在动作选项卡中检查每次运行的日志。该选项卡将有助于调试,您也可以在这里手动强制执行工作流。总之,执行 GitHub 平面数据工作流的过程,加上一个 R 后处理脚本,看起来像这样:

GitHub 平面数据工作流,包括用于后处理的 R 脚本。图片作者。

感谢阅读!你可以通过阅读这篇文章附带的 GitHub 库了解更多;否则,请通过 Twitter 发送任何问题🙂

原载于 我的博客

包括验证 DBT 云在气流上的作业状态

原文:https://towardsdatascience.com/including-verification-of-dbt-cloud-job-status-on-airflow-4ef551f349a0?source=collection_archive---------17-----------------------

行业笔记

使用气流触发 DBT 云作业,在继续之前检查其状态并发送错误通知

陈明亮Unsplash 上拍照

在下面的文章中,我写了关于利用气流引发 DBT 乔布斯的文章。一种选择是将 DBT 作为一个 python 包安装,并直接在与 Airflow 相同的机器上运行。另一个是使用 DBT 云来管理到数据仓库和作业的连接。

第 1 部分 : 启动实例并安装气流
第 2 部分 : 安装 DBT 和一些设置使工作更容易
第 3 部分 : 使用 DBT 云并将气流与 DBT 集成

第二个问题是:当我们发送请求来触发作业时,我们的任务将会成功完成(考虑到气流可以发送这个请求)。但这并不意味着我们在 DBT 的工作也很成功。事实上,我们的 DBT 作业可能仍在排队,等待 DBT 云执行它。因此,使用 DAG 运行 DBT 云作业的更合适的方法不仅可以触发作业,还可以检查它是否正确运行。

1.创建 AWS 资源

我们要添加到 DAG 中的一个步骤是在失败时发送通知。为此,我们将使用名为 SNS (简单通知服务)的 AWS 服务。转到 AWS 控制台并搜索产品升级和技术支持服务。转到主题并创建一个新主题。选择标准类型并选择一个名称。我选“气流通知”。其他的都不需要改,直接点“创建话题”就可以了。

创建社交网络话题

之后,点击主题名称,您将看到 ARN。复制它。

我们话题的 ARN

在此页面的底部,您还可以选择创建订阅。创建一个,选择“电子邮件”作为协议,您的电子邮件作为端点。

借助 AWS SNS,我们可以轻松管理主题订阅

创建订阅后,您将收到一封确认订阅的电子邮件。去做吧。

在 AWS 中,为了向主题发布消息,我们还需要一个 IAM 用户。仍然在 AWS 控制台中,搜索 IAM 用户,在其页面中,转到 Users 并单击“Add users”。选择一个名称并选中“编程访问”(如果您希望能够以此用户身份登录,也可以选中 AWS 控制台选项)。

创建一个 IAM 用户,编程访问就足够了

点击 Next,在 Permissions 页面中,选择“直接附加现有策略”并选择 AmazonSNSFullAccess。然后点击下一步。

如果你知道你在做什么,你可以定义特定的权限,只是为了发布消息

在下一页中,如果需要,您可以添加一些标记,然后继续查看页面,然后“创建用户”。完成后,您将看到一条成功消息和下载. csv 文件的选项。这个文件将包含您刚刚创建的用户的“访问密钥 ID”和“秘密访问密钥”。下载吧。

结束 IAM 用户创建,下载。csv 文件

好了,现在,为了构建我们的新 DAG,让我们首先创建一些变量和连接。通过这样做,我们可以使用更通用的代码,因此您只需将这些值调整为您自己的值,而不需要编辑大量 Python 代码。

在气流网页中,转到管理>变量。创建三个变量:对于第一个,使用名称“sns_arn”并将主题 arn 粘贴到值中;第二个,用“SECRET_DBT_TOKEN”这个名字,用你 DBT 云的 API 密钥;第三个将被命名为“dbt_account_id ”,您可以猜测该值,即您来自 dbt 云的帐户 id。如果你对如何获得这些信息有任何疑问,你可以查看开头提到的文章。

完成后,您将拥有这三个变量:

有了这些变量,我们不必在代码中使用它们的值

注意,因为我们在令牌变量中使用了单词“secret ”,所以它的值不会出现在 UI 中。

现在,进入管理>连接。我们需要两个连接。第一个将调用“HTTP”类型的“dbt_api”和主机“https://cloud.getdbt.com/api/v2/”。

对于第二个,类型将是“Amazon Web Services”,id 为“aws_conn”。打开。创建 IAM 用户后下载的 csv 文件。Airflow 连接登录将是文件中的“访问密钥 ID ”,密码 host 将是“秘密访问密钥”。在 Extra 字段中,您必须将 json 与您在 AWS 中使用的区域一起使用。在我的例子中是 us-east-2,所以值将是{"region_name": "us-east-2"}。像这样:

创建 AWS 连接

2.在 DAG 中使用的通用函数

现在,转到 dag 文件夹,创建一个名为“utils”的子目录。在其中,创建一个名为“dbtFunctions.py”的新文件。

我将讨论代码的每个部分,但整个代码都在这一页的末尾,所以,如果你愿意,你可以跳过代码块。

首先,我们需要导入我们将要使用的库:

import requests, jsonfrom airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.sensors.python import PythonSensor
from airflow.hooks.base import BaseHook
from airflow.models import Variable
from airflow.exceptions import AirflowFailException
from airflow.contrib.operators.sns_publish_operator import SnsPublishOperator

现在,我们将从先前创建的变量和连接中获取数据。

DBT_API = BaseHook.get_connection('dbt_api').host
ACCOUNT_ID = Variable.get('dbt_account_id')
SNS_CONN = BaseHook.get_connection('aws_conn').conn_id
SNS_ARN = Variable.get('sns_arn')

当我们使用 DBT 云 API 请求时,我们可能需要传递报头或消息,所以,让我们添加这个来简化一些参数:

dbt_header = {
  'Content-Type': 'application/json',
  'Authorization': 'Token {0}'.format(Variable.get('SECRET_DBT_TOKEN'))
}def getDbtMessage(message):
  return {'cause': message}

气流运行基于操作员。我们需要一个能触发 DBT 任务的操作员。我们可以使用 PythonOperator 来运行 Python 函数,并使用请求库方法来发送请求。

一旦作业被触发,我们希望能够检查作业状态。每次我们触发一个作业时,都会生成一个作业运行 ID。我们需要这个 ID 来检查它的状态。当我们通过 API 触发作业时,这个 ID 在响应对象中返回。因此,我们可以将这个值存储到一个 XCOM 中。为了便于识别作业,我们还将作业 ID 添加到 XCOM 的名称中。

def _triggerJob(job_id, account_id, message, **context):
    response = requests.post(
        f'{DBT_API}/accounts/{account_id}/jobs/{job_id}/run/', 
        headers=dbt_header, 
        data=json.dumps(getDbtMessage(message))
    ).json()
    status_code = response['status']['code']
    job_run_id = response['data']['id']
    jobRunData = json.dumps({"status": status_code, "job_run_id": job_run_id}) 
    context['ti'].xcom_push(key=f'job-{job_id}', value=jobRunData)def triggerJobOperator(task_id, job_id, account_id=ACCOUNT_ID, message='Triggered by Airflow', **context):
    return PythonOperator(
        task_id=task_id,
        python_callable=_triggerJob,
        op_kwargs={'job_id': job_id, 'account_id': account_id, 'message': message}
    )

现在,无论我们是想在触发 DBT 作业后添加新任务,还是只考虑 DAG 成功,我们都应该只在作业成功时执行一次。为了验证这一点,我们将使用一个 PythonSensor 。PythonSensor 允许我们运行一个 python 函数,并且只根据某些条件移动到下一个任务。

我们将使用 DBT 云 API 来获取作业状态(数字代码在代码注释中),从我们的 XCOM 获取作业运行 ID。一旦作业成功,用代码 10 表示,PythonSensor 调用的函数返回 true,这是执行下一个任务的条件。如果我们有一个状态取消或错误,我们也想中止任务,因为我们知道工作没有成功完成。

请注意间隔和重试参数。我定义每 30 秒运行一次 PythonSensor 使用的函数,并检查它的条件(一旦满足就返回 True)。此外,总超时将是 30 秒乘以 20,这意味着我们将尝试多达 20 次。这些值是假设的,你应该检查对你来说什么是好的值。无论如何,你只需要传递这些参数的值。

def _waitJobRun(job_id, account_id, **context):
    jobRunData = json.loads(context['ti'].xcom_pull(key=f'job-{job_id}'))
    jobRunId = jobRunData['job_run_id']
    response = requests.get(f'{DBT_API}/accounts/{account_id}/runs/{jobRunId}/', headers=dbt_header).json()
    status = response['data']['status']
    if (status == 10):
        return True
    elif (status == 20):
        raise AirflowFailException('Error on DBT job run!')
    elif (status == 30):
        raise AirflowFailException('DBT job run cancelled!')
    # 1-Queued / 3-Running / 10-Success / 20-Error / 30-Cancelleddef waitJobRunOperator(task_id, job_id, interval=30, retries=20, account_id=ACCOUNT_ID):
    return PythonSensor(
        task_id=task_id,
        poke_interval=interval,
        timeout=interval*retries,
        python_callable=_waitJobRun,
        op_kwargs={'job_id': job_id, 'account_id': account_id}
    )

最后,如果在 DAG 执行过程中出现错误,我们希望发送一封电子邮件。为此,我们将使用 SnsPublishOperator。这里,我们还将触发规则定义为“one_failed”。因此,如果在 DAG 期间有任何任务失败(无论是触发 DBT 作业失败还是检查其状态失败),我们将向我们创建的主题发布一条消息,订阅者将收到电子邮件。

def notifyErrorIfOneFailedOperator(task_id, message='Error on DAG!'):
    return SnsPublishOperator(
        task_id=task_id,
        target_arn=SNS_ARN,
        message=message,
        aws_conn_id=SNS_CONN,
        trigger_rule='one_failed'
    )

所以,把这些碎片放在一起,我们有:

3.达格

好了,到目前为止,我们只创建了一些函数。我们没有创建任何 DAG。我们仍然没有任何关于气流 UI 的新东西。因此,在 Dags 文件夹中创建一个新文件(在 utils 之外)。我把它命名为“load_users_cloud_v2.py”,不过你可以随意选择。添加以下代码。

对于任务 1 和任务 2,您必须使用您自己的作业 ID,来自 DBT 云。但那就足够了。使用我们的函数,我们只需要声明我们想要触发我们的作业,检查直到它完成,如果有任何错误,通知某人。

检查气流 UI。

最后,我们的狗

打开开关并触发 DAG。如果一切正常,第一个任务将很快执行。它将被标在深绿色上。第二个任务将在几分钟内呈浅绿色,同时等待 DBT 任务完成。

检查作业状态的任务将一直运行,直到作业完成,无论成功与否

一旦作业完成,最后一个任务将被标记为粉红色,因为没有错误,任务不必执行。

检查状态成功,意味着作业成功运行,通知被跳过

想要测试错误场景吗?再次触发 DAG。转到 DBT 云并在作业执行前取消它。

DBT 云上气流引发的作业

现在,第二个任务标记为红色,第三个标记为深绿色。你可以查看你的电子邮件。

状态检查失败,成功发送通知

因此,现在我们的 DAG 在 DBT 云中触发一个作业,等待该作业完成,并在出现任何错误时发送电子邮件通知。如果您的 DAG 的目标只是触发 DBT 作业,那么您不必做很多更改,但是您可能会注意到,即使第二个任务失败,DAG 也会被标记为成功,因为我们成功地到达了最后一个任务。例如,您可以在这些操作符之后添加一个新的操作符,并使用一个触发规则,以便仅在所有之前的任务都正确运行或被跳过时才运行。如果你需要添加其他任务,你可以考虑的另一件事是将那些任务分组到一个任务组。不管怎样,现在就看你的了。如果你一直坚持到现在,我相信你可以做出适当的改变,在你的项目中使用它。

参考

https://airflow.apache.org/docs/https://docs.getdbt.com/dbt-cloud/apihttps://marclamberti.com/blog/airflow-sensors/https://marclamberti.com/blog/airflow-xcom/https://aws.amazon.com/sns
https://www.astronomer.io/guides/task-group
s
https 高亮显示=触发#触发规则

在 Python 中使用 Bagging 提高模型稳定性

原文:https://towardsdatascience.com/increase-model-stability-using-bagging-in-python-d407233d2d93?source=collection_archive---------31-----------------------

让我们看看如何使用 bagging 技术增加模型的稳定性

装袋示例。作者图片

数据科学家通常会寻找一个尽可能精确的模型。然而,他们还应该关注另一个术语,即稳定性。在这篇文章中,我解释了它是什么以及如何使用一种叫做“装袋”的技术来增加它。

偏差-方差权衡

在机器学习中,预测误差可以分解为 3 部分:偏差的平方、方差和不可约误差。偏差是预测值与真实值相差多远的度量,方差衡量我们的模型在根据数据集的原始分布创建的样本上进行重新训练时的稳定性,不可约误差是无法消除的噪声项。研究这些术语并试图减少它们被称为偏差-方差权衡。

作者图片

下图更清楚地展示了偏差和方差是如何工作的。灰色目标是真实值,而红色叉号是使用训练数据集的不同重采样进行的预测。

作者图片

我们的目标是达到低偏差-低方差的情况,在这种情况下,我们的模型对再训练是稳定的,并且它的预测是正确的。然而,具有低偏差的模型(如 XGBoost)往往会随着时间的推移而变得不稳定(高方差),而具有低方差的模型(如随机森林)往往不太准确(低偏差)。数据科学家必须知道,他们是想创建一个不稳定的精确模型(需要频繁的重新训练),还是创建一个更稳定的不太精确的模型。

由于模型训练是一项非常复杂和困难的任务,我更喜欢使用低方差的模型,以便随着时间的推移,以较低的性能为代价,获得更稳定的模型。

为了减少偏差,可以使用一种称为升压的技术。为了减少差异,我们可以使用一种叫做装袋的技术。后者是本文的主题。

装袋的工作原理

装袋工作遵循自举的统计原理。让我们考虑数据集的所有记录和所有特征。

作者图片

现在,让我们考虑我们的训练数据集的一些随机选择的样本,通过替换对我们的记录进行采样,并考虑列的随机子集。通过这种方式,我们可以创建不同的训练数据集来训练我们的模型,预先设置相同的超参数值。

作者图片

最后,该模型集合可用于进行最终预测。

作者图片

对于回归问题,通常使用模型预测的平均值。对于分类,软投票是首选。

Bagging 在数学上减少了我们模型的方差(即当我们在原始训练数据集的不同重新样本上训练我们的模型时,平均性能值周围的波动的度量)。最常见的 bagging 模型是随机森林,但是我们可以将 bagging 概念应用于每一个可能的模型。

一些 bagging 技术使用没有替换的采样,并且样本的大小可以小于原始训练数据集的大小。因此,bagging 引入了 4 个新的超参数:样本数、列数、要使用的记录分数、是否使用替换抽样。

现在让我们看看如何在 Python 中应用 bagging 进行回归和分类,并证明它实际上减少了方差。

蟒蛇皮装袋

现在让我们看看如何在 Python 中使用 bagging。完整的代码可以在我的 GitHub 这里找到。

让我们首先导入我们的数据集,即乳腺癌和糖尿病数据集。

from sklearn.datasets import load_breast_cancer,load_diabetes

现在让我们导入一个回归和一个分类模型。对于回归,我们将使用线性回归。对于分类,我们将使用高斯朴素贝叶斯模型。

from sklearn.linear_model import LinearRegression 
from sklearn.naive_bayes import GaussianNB

为了应用 bagging,我们必须使用元估计器,将这种集成技术应用于给定的模型。在 sklearn 中,我们有打包分类器和开始分类器。让我们导入它们,让我们导入 cross_val_score,以便计算方差。

from sklearn.ensemble import BaggingClassifier,BaggingRegressor 
from sklearn.model_selection import cross_val_score

先说分类。我们可以导入我们的数据集,训练我们的模型,并在 10 次交叉验证中计算一些性能指标的方差(比如平衡精度)。

X,y = load_breast_cancer(return_X_y=True) nb = GaussianNB() cross_val_score(nb,X,y,scoring="balanced_accuracy",cv=10).var() 
# 0.0011182285777794419

这个方差是模型稳定性的度量。

现在让我们使用 10 个模型和原始列数的一半来应用 bagging。在实际项目中,您希望使用像网格搜索这样的超参数调整技术来优化这些值。

model = BaggingClassifier(GaussianNB(),n_estimators = 10, max_features = 0.5,random_state = 0, n_jobs = -1)

那么,方差是:

cross_val_score(model,X,y,scoring="balanced_accuracy",cv=10).var() 
# 0.000944202642795715

正如我们看到的,它低于原始方差。因此,装袋减少了方差,使我们的模型更加稳定。

我们也可以将同样的概念应用于回归。让我们使用线性回归模型和 R 平方度量。

X,y = load_diabetes(return_X_y=True) lr = LinearRegression() cross_val_score(lr,X,y,scoring="r2",cv=10).var() 
# 0.021605440351612316

现在,让我们将 BaggingRegressor 应用于我们的模型,并计算新的方差:

model = BaggingRegressor(LinearRegression(),n_estimators = 10, max_features = 0.5,random_state = 0, n_jobs = -1) cross_val_score(model,X,y,scoring="r2",cv=10).var() 
# 0.013136832268767986

它是原值的一半。所以,我们创造了一个更稳定的模型。

结论

装袋是一种非常有用的技术,它从数学上增加了模型的稳定性。我认为,当您知道将来无法再次训练您的模型,并且希望构建一个随着时间推移而稳定的模型时,应该首选 boosting。当然,监控模型性能对于机器学习项目的成功至关重要,但随着时间的推移,正确使用 boosting 会使您的模型更加稳定和健壮,但代价是性能下降。有时,增加模型的稳定性可能比增加其准确性更可取,bagging 就是这样工作的。

Gianluca Malato 是一名数据科学家,在http://www.yourdatateacher.com/上教授机器学习和数据科学。

原载于 2021 年 10 月 18 日 https://www.yourdatateacher.com的* *

用更少的代码行提高性能

原文:https://towardsdatascience.com/increase-performance-with-fewer-lines-of-code-2618a9fd3e0e?source=collection_archive---------30-----------------------

如何通过使用 Python 中针对速度优化的方法来修改代码

照片由马修·施瓦茨Unsplash 拍摄

数据科学与性能密切相关,无论是关于指标(预测模型准确性、精确度、召回率、F1 分数或日志丢失)还是硬件规格(RAM、存储和 GPU)。然而,有时指标或硬件规格是数据科学家可以控制的变量。也许公司已经建立了关键绩效指标(KPI ),并购买了所有必要的设备来开始运行它。

也就是说,有人可能会认为数据科学家可以通过提高他们的编码能力来影响性能。这是事实,但更重要的是,数据科学家应该知道在每种情况下使用哪种方法。Python 是一种通用的编程语言,允许数据专业人员编写不同的代码行,但仍能获得相同的结果。但是,说到性能,并不是每一行代码都是一样的。

以下是数据科学家使用不同形式的循环来增加处理时间的一些简单方法。因此,您将影响整体性能——尤其是对于大型数据集。

数据集

对于本文,我使用 Pandas 随机生成一万行和三列,数字在**0****1**之间。下面,describe 方法精确地显示了我们所期望的:最小值接近于零,平均值在 0.5 左右,最大值接近 1.0。此外,我们可以确认有 10,000 行和 3 列。

作者图片

Iterrows

Iterrows 是一个常用的 Pandas 方法,它允许您遍历每一行。我们可以单独使用 iterrow,但是循环遍历一些值并打印出来并没有什么好处。因此,让我们从创建一个应用 iterrow 并检查条件的函数开始。在这种情况下,我们将首先传入 DataFrame ( **df**)和 column ( **col**)。然后,如果值低于 5,Python 会用 0 替换它。否则 Python 会用 1 代替。虽然这是一个简单的例子,但它将允许我们使用 iterrows 来测量每个循环的速度。

作者图片

通过在 iterrow 上使用[**%timeit**](https://docs.python.org/3/library/timeit.html),我们可以检查运行每一行代码所花费的时间。在 iterrows 的例子中,花费了 681 ms,所以,让我们使用这个结果作为评估方法间性能的参考速度。

iloc 方法

**iloc**方法是 Pandas 库的一部分,它使我们能够选择数据集【1】的特定单元格。所以,现在,我们将运行一个类似于前一个代码的代码,但是我们将使用稍有变化的索引。给定一列,Python 将在索引位置***i***找到值。

作者图片

通过使我们的 for 循环适应 Pandas **iloc**方法,我们已经设法减少了每个循环的处理时间。**iloc**方法大约比 iterrows 快 4.4 倍。然而,仍有改进的余地。

应用带有λ的方法

Lambda 是一个小小的匿名函数,其语法比常规 Python 函数【2】更严格,但也更简洁。标准函数使用**def**关键字,而在 Python 中,匿名函数使用 lambda 关键字。因此,匿名函数也被称为 T21。这是一种高效的编码方式,意味着需要处理的行数更少。因此,时间更少,效率更高。让我们看看它与我们的第一个方法相比如何。

作者图片

Lambda 函数通过 apply 方法比 iterrows 更快。通过一行代码,我们成功地将每个循环的处理时间减少到了 4.59 毫秒,比 iterrows 快了大约 148 倍。

NP . where

**where()**方法是 NumPy 库【3】的一部分。它告诉你在指定的数组中,哪里的条目满足给定的条件。你可以在 NumPy 的文档上阅读更多关于**where()**的内容。现在,我们将继续我们的性能测试,看看它是否能提高每个循环的处理速度。让我们传入之前使用的条件并检查结果。

作者图片

好的,我们已经显著提高了性能。现在,每个循环只需要 332 微秒。因此,1 微秒等于 1000 纳秒或 0.000001 秒。在 apply 方法中,我们达到了 lambda 函数速度的近 14 倍。这是一个巨大的改进,只需要短短的一行代码。

NP . where . value

通过将**.value****np.where()**一起使用,它将上述内容转换成一个 NumPy 数组。它删除了熊猫系列中不必要的功能。Python 需要处理的事情更少。因此,我们提高了速度和性能。

作者图片

好吧,这是一个不可思议的成就。我们已经设法将时间减少了前一个例子的大约一半。Python 处理每个循环只需要 178 微秒。令人惊讶的是,仅仅几个变化就能产生如此巨大的性能差异。

结论

性能是数据科学的关键。然而,大多数时候,数据科学家无法改变业务指标或购买新设备。尽管如此,努力编写提高性能的代码是我们力所能及的。您绝不应该忘记 iterrows,而是应该考虑每个数据集的大小。如果数据集很小,Iterrows 不会影响您的工作。但是,数据集越广泛,稍加改动的好处就越大。这样做可以提高性能并减少时间。性能大幅提升的原因在于使用了针对速度优化的方法(apply/NP . where/vectorization)。因此,尽可能使用优化的方法。

感谢阅读。这里有一些你可能会喜欢的文章:

参考文献:

【1】ilochttps://pandas . pydata . org/pandas-docs/stable/reference/API/pandas。DataFrame.iloc.html

【2】λhttps://realpython.com/python-lambda/

【3】NP . wherehttps://numpy . org/doc/stable/reference/generated/numpy . where . html

Python 代码的所有图像都是由作者在 Jupyter 笔记本上创建的。

遵循我从 Kaggle 社区学到的 5 个技巧,提高你的 CNN 的准确性

原文:https://towardsdatascience.com/increase-the-accuracy-of-your-cnn-by-following-these-5-tips-i-learned-from-the-kaggle-community-27227ad39554?source=collection_archive---------3-----------------------

使用更大的预训练模型、K 倍交叉验证、CutMix、MixUp 和集成学习

试图提高 CNN 的准确性,照片由塞缪尔·伯克Unsplash 上拍摄

一个项目经理曾经告诉我 80/20 法则。他抱怨说项目的最后一部分时间太长了。实现最后 20%的功能花费了 80%的时间。

维尔弗雷多·帕累托称之为 80/20 法则或帕累托原则。它说你 20%的努力会产生 80%的结果。

80/20 法则也适用于提高我的深度学习模型的准确性。创建一个准确率为 88%的模型非常简单。我有一种感觉,要把它再提高 3%才能登上排行榜的首位,将需要更多的时间。

如果你不知道我在说什么,我邀请你阅读我以前的文章。那篇文章最后给出了提高模型准确性的五种可能的技术。我从 Kaggle 社区学到了这五个技巧。

  1. 使用更大的预训练模型
  2. 使用 K 倍交叉优化
  3. 使用 CutMix 来增强您的图像
  4. 使用混音来增强你的图像
  5. 使用集成学习

我尝试了每一种技术,并将它们结合起来。事情是这样的。

所有的源代码都可以在这个 GitHub 库中找到。

1.使用更大的预训练模型

之前,我们使用的是 B3 高效网络。这个模型是性能和准确性之间的一个很好的平衡。见下文。但是 EfficientNet 提供了其他更精确的模型,例如 EfficientNet-B4。

EfficientNet:反思卷积神经网络的模型缩放(Tan 等人,2019 年)

这些更复杂的模型有更多的参数。在训练期间,更多的参数需要更多的计算能力和内存。我从 EfficientNet-B4 开始,结果非常好。验证准确率提高到 90%,验证损失降低到 0.32。

如果您对实现感兴趣,请查看我的以前的文章或这个 GitHub 资源库。唯一需要的改变是把 B3 变成 B4。

使用 EfficientNetB4 与 Epochs 时的培训和验证准确性,图片由作者提供

使用 EfficientNetB4 与 Epochs 时的培训和验证损失,图片由作者提供

在我将模型提交给 Kaggle 之后,它显示了公众评分的小幅上升。从 88.9%上升到 89.1%。提高了 0.2%。

提交的分数,图片由作者提供

我还尝试了其他高效网络模型,如高效网络 B5 和高效 B6。精确度没有增加。

2.使用 K 倍交叉验证

到目前为止,我们将图像分为训练集和验证集。因此,我们不使用整个训练集,因为我们使用一部分进行验证。

将数据分为训练集和验证集的另一种方法是 K 重交叉验证。这个方法最早是由石头 M 在 1977 年提出的。

使用 K 倍交叉验证,您可以将图像分成 K 个大小相等的部分。然后,使用不同的训练和验证集对模型 K 进行多次训练。

通过这种方式,您可以充分利用所有的训练数据。

k 倍交叉验证(k = 5),图片由作者提供

请务必注意,您将训练许多模型,每个折叠一个模型。这意味着改变我们预测的方式。我们有以下选择。

  • 使用单一模型,具有最高精度或损耗的模型。
  • 使用所有模型。使用所有模型创建一个预测,并对结果进行平均。这被称为合奏
  • 使用与交叉验证相同的设置重新训练替代模型。但是现在使用整个数据集。

实现 K 重交叉验证

scikit-learn 库包含帮助我们的对象。有两个对象可以帮助我们将训练数据分成多个文件夹。这些是KFoldStratifiedKFold

KFold

KFold对象将我们的训练数据分成 k 个连续的文件夹。创建对象时,选择折叠次数。如果您随后对该对象调用split,它将返回两个数组。第一个数组包含来自我们训练数据的用于训练的索引。第二个数组包含用于验证的训练数据的索引。

使用 scikit-learn 中的 KFold

在第五行中,我们创建了KFold对象,并指示它创建五个不同的文件夹并混洗数据。然后在第八行,我们开始一个将运行五次的循环。每次运行都返回包含 train_data 数据帧索引的train_indexval_index数组。

然后我们创建两个数组,training_datavalidation_data,我们用它们来处理ImageDataGenerator

分层折叠

StratifiedKFold 与普通 KFold 的不同之处在于,它确保每个文件夹中每个类别的样本百分比相同。如果您的训练数据不是均匀分布的,这尤其有用。

每个疾病类别的训练图像数量,按作者分类的图像

我们的训练数据就是这种情况。所以,我们用 StratifiedKFold。实现与 KFold 相同。

使用 scikit-learn 中的 StratifiedKFold

我们迭代所有折叠,并使用每个训练和验证集来训练模型。每个型号都有一个唯一的文件名。当保存具有最低损失的模型时,我们使用该文件名。

然后,我们将 TensorFlow 从 fit 方法返回的历史对象添加到一个数组中。我们使用这个数组在训练结束时创建每个折叠的图形。我在每次折叠时使用的预训练模型是 B3 效率网。

正如您在折叠 1 和折叠 2 的图表中所看到的,各个图表没有显示验证准确性的增加。

作者对 fold 1 与 Epochs 图像的训练和验证准确性

作者对 fold 2 与 Epochs 图像的训练和验证准确性

使用 K-Fold 创建和提交预测

为了进行预测,我们必须计算所有单个预测的平均值。为此,我们首先加载所有的模型并将它们存储在一个列表中。

使用 Keras 加载所有模型,并将它们存储在一个列表中

然后我们调用load_and_predict函数。这个函数迭代所有加载的模型。我们将模型返回的每个预测添加到包含所有预测的列表中。

用每个模型创建预测并计算平均值

在第 26 行,我们使用 NumPy 来计算所有预测的平均值。然后,在第 27 行,我们迭代所有的预测来构造一个数组。我们使用这个数组创建一个提交,方法是将它加载到 Pandas 数据框中。Pandas 数据框有一种直接将其保存为 CSV 文件的方法。

提交的结果比我们上次提交的结果增加了 0.001。

笔记本投稿结果,图片由作者提供

我们在公共排行榜上升了几个名次,排在 1908 位。

最终在 Kaggle 公共排行榜上的排名,图片由作者提供

3.使用 CutMix 来增强您的图像

Sangdoo Yun 在 Sangdoo Yun 等人的研究论文 CutMix:使用可本地化特征训练强分类器的正则化策略中描述了 CutMix

CutMix 组合了来自训练集的两个随机图像。它剪切一幅图像的一部分,并将其粘贴到另一幅图像上。CutMix 还混合两个图像的标签,与剪切大小的区域成比例。

论文的结论是 CutMix 提高了模型的稳健性和性能。

当我们对木薯训练数据使用 CutMix 技术时,我们得到以下图像。我添加了红框,以观察原始图像和补丁之间的区别。

将 CutMix 添加到木薯训练图像,图像由作者提供

使用 TensorFlow Keras 实现 CutMix

由于有了CutMixImageDataGenerator类,用 TensorFlow 实现 CutMix 很简单。Bruce Kim 开发了这个类。它的作用与ImageDataGenerator相同,但它增加了 CutMix。

我们像往常一样定义了一个ImageDataGenerator,但是我们创建了两个迭代器,参见第 16 行和第 27 行。

在第 38 行,我们使用两个迭代器作为参数创建了CutMixImageDataGenerator。接下来,我们使用它返回的train_iterator并将其添加到fit方法中。

使用 CutMixImageDataGenerator

EfficientNet-B5 与 CutMix 的结合产生了 89.49%的最大验证准确度和 0.32 的最小验证损失。

CutMix 准确性和验证准确性与纪元的关系,图片由作者提供,使用 Tensorboard 创建

CutMix 训练损失和验证损失与历元,图片由作者提供,使用 Tensorboard 创建

为了报告准确性和损失,我使用了 Tensorboard 。TensorBoard 可以跟踪和可视化损失和准确性指标。谷歌还开发了网站 TensorBoard.dev. 你可以用它来存储和分享你的训练成果。

最棒的是,你甚至可以在训练过程中观察这些指标。

你可以在这里查看 CutMix 训练的准确度和损耗结果。

虽然准确性和损失是迄今为止最好的,但它们并没有在 Kaggle 上产生更高的分数。该模型的得分为 0.889,这不是一个进步。

笔记本投稿结果,图片由作者提供

因此,使用 CutMix 和 EfficientNetB5 训练单个模型并没有改善我们的模型。

4.使用混音来增强你的图像

张等人的研究论文 mixup:超越经验风险最小化对 MixUp 进行了描述。

像 CutMix 一样,MixUp 组合了来自我们训练集的两个图像。它使一个图像透明,并把它放在另一个之上。透明度是可调的。

研究论文表明,MixUp 提高了最先进的神经网络体系结构的泛化能力。

当我们对木薯训练数据使用混合技术时,我们得到了下面的图像。我使用的透明度值为 0.2。

添加混合到木薯训练图像,图像由作者

使用 TensorFlow Keras 实现混合

当您使用在 dlology 博客中提到的MixUpImageGenerator时,MixUp 的实现也很简单。你可以在 GitHub 上找到源代码。

我对MixUpImageGenerator做了一点小小的改动,使它能够用于数据集和flow_from_dataframe方法。

实现从创建一个ImageDataGenerator开始,并将生成器传递给MixUpImageGenerator的构造函数。

使用 MixUpImageGenerator

EfficientNet-B4 与 MixUp 的结合产生了 88.5%的最大验证准确度和 0.35 的最小验证损失。

混合精度和验证精度与纪元,图片由作者提供,使用 Tensorboard 创建

混合训练损失和验证损失与历元,图片由作者使用 Tensorboard 创建

你可以研究这些图,因为我是用 Tensorboard 创建的。

MixUp 没有提高精度或损失,结果比使用 CutMix 低。这也没有给 Kaggle 带来更高的分数。该模型得分为 0。这不是一个进步。

因此,使用 MixUp 和 EfficientNet-B4 训练单个模型不会导致识别木薯疾病的改进。

5.使用集成学习

集成学习是一种通过训练和组合多个模型来改进预测的方法。我们之前用 K-Fold 交叉验证做的是集成学习。

我们训练了多个模型,并结合了这些模型的预测。对于 K-Fold 交叉验证,我们使用了相同的模型架构——efficient net-B3。也可以组合不同的架构。

我们将一个用高效 B7 训练的模型和另一个用 ResNext50v2 训练的模型结合起来。经过训练,ResNext50v2 模型的最大验证准确率为 85%。效率网-B7 模型的最大验证准确率为 89%。

ResNext50v2 与 Epochs 的训练和验证精度,图片由作者提供

EfficientNet-B7 vs Epochs 的训练和验证准确性,图片由作者提供

使用集成学习创建预测

我把这个组合和四倍测试增强结合起来。如果您查看源代码,会发现有两个循环——第一个循环遍历所有模型,第二个循环遍历增强的测试图像。

最后,在第 33 行,我们使用np.mean计算预测的平均值。然后,在第 35 行,我们使用np.argmax选择得分最高的类别或标签。

使用集成学习创建预测

这一组合加上测试时间增加的结果是迄今为止的最高分。我们在私服上得到了 89.3% ,在公服上得到了 89.35%

当我试图改进和写这篇文章的时候,比赛结束了。这就是为什么你会看到公共和私人的分数。以前 Kaggle 只会显示公开的分数。

结论和进一步优化

正如所料,一些优化技术对木薯数据有效,而另一些则无效。我们可以将准确率从 88.9%提高到 89.35%。

使用更大的模型,K-Fold 交叉验证和集成学习提高了准确性。CutMix 和 MixUp 图像增强没有。

你可以在这个 GitHub 库里找到源代码。

我花了更多的时间试图提高准确性,如果你把它与我的模型的初始创建进行比较。创建模型和训练需要更多的时间和计算能力。

我对 80/20 法则的感觉是正确的。

这篇文章中的五个技巧可以提高你的 CNN 的准确性。这取决于训练图像的数量和质量。试着找出答案。

在阅读 Kaggle 论坛时,我发现了更多的优化技术。比如说。

  • 执行图像增强,而不是在每个时期。例如,开始前三个纪元时不增加。另外,不要在最后的时期使用强化。
  • 创建包含视觉变换(ViT)模型的集合
  • 使用不同的损失函数
  • 使用过采样平衡数据集

我将使用这些技术来进一步提高我的模型的准确性。

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

已用资源

尚斗云,韩东云,吴成俊,尚赫镇,崔俊锡,柳永俊。 CutMix:训练具有可定位特征的强分类器的正则化策略。arXiv:1905.04899

H.张、m .西塞、Y. N .多芬和 d .洛佩斯-帕斯。混乱:超越经验风险最小化。arXiv 预印本 arXiv:1710.09412,2017。

谭明星与郭诉乐。EfficientNet:反思卷积神经网络的模型缩放。《机器学习国际会议论文集》(ICML),2019 年。

统计预测的交叉验证选择和评估。皇家统计。社会主义者, 36(2):111–147,1974.

用于图像识别的深度残差学习。何、、、任、。

增加你的图表的可爱度

原文:https://towardsdatascience.com/increase-the-cuteness-quotient-of-your-charts-fda960d84bee?source=collection_archive---------29-----------------------

用 Python 创建手绘 xkcd 样式的图表

Unsplash 上的 Kelli Tungay 拍摄|由作者编辑

手绘图表看起来很花哨,以至于有一个 javascript 库可以用来创建它们。 Chart.xkcd 是一个可视化库,可以呈现漂亮的“手绘”风格的图表,这些图表也是交互式的。

图表通过 charts.xkcd |图片来自https://github.com/timqian/chart.xkcd

你可能会问,这样的图表有什么好处?就我个人而言,我觉得它有时非常适合演示,或者只是给你的情节增加一点小小的变化。可视化是交互式的,这是一个附加功能。不幸的是,这个库是用 javascript 编写的,Pythonistas 可能不太容易访问。但是,多亏了 cutecharts (是的,你没听错)——一个模仿 chart.xkcd 但是用 Python 编写的库。作者指出:

值得指出的是,cutecharts 更多的是一个用来学习如何将 Javascript world 与 Python/notebook 结合起来的库。作为 Python 社区的一员,我真诚地希望越来越多的开发者能够发挥他们的创造力,为我们喜爱的 Python 世界制作出许多相关的项目。

可爱图表

如上所述, cutecharts 是一个 Python 库,用 Python 渲染交互式手绘图表。该库没有太多的选项,只支持几种类型的可视化。但是,它确实呈现了一些独特的、视觉上令人愉悦的图表。

装置

该库可以通过 pip 安装,也可以直接从源代码安装。

pip3 install cutechartsor#from sourcegit clone https://github.com/cutecharts/cutecharts.py.git
cd cutecharts.py
pip install -r requirements.txt
python setup.py install

你可能想参考知识库获取最新信息:https://github.com/cutecharts/cutecharts.py

使用

开始使用这个库很容易,我们将通过下面的例子看到它的用法。

演示:分析欧洲 IT 人员的工资

Kaggle 数据集通过https://www . ka ggle . com/parulpandey/2020-it-salary-survey-for-eu-region

我们将使用真实案例研究中的数据。上面的数据集来自一项匿名薪酬调查,该调查在欧洲 IT 专家中进行,更侧重于德国。我们将使用 2020 年的数据集。该数据集包含有关欧盟地区 IT 专业人员薪酬模式的丰富信息。然而,本文的重点更多的是展示这个库,而不是探索性的数据可视化。但是,我鼓励您在 Kaggle 环境中使用数据集。

导入必要的库

一旦安装了库,我们将把它和数据集一起导入。

import pandas as pd 
import cutecharts.charts as ctc

Cutecharts 兼容 Jupyter 笔记本和 Jupyter lab。然而,在使用 Jupyter lab 时,应记住以下先决条件。

  • 在开始时导入以下命令
from cutecharts.globals import use_jupyter_lab; use_jupyter_lab()
  • 第一次渲染图表时调用load_javascript函数。这应该在呈现图表之前调用。查看下面的饼状图,了解何时致电。
chart.load_javascript()

导入数据集

df = pd.read_csv('salary.csv')
df.dropna(inplace=True) # deleting the missing values
df.head()

作者对数据集|图像的一瞥

我们的数据现在在内存中,我们已经准备好用 cutecharts 绘制不同类型的图表。

1.圆形分格统计图表

分析受访者的性别

让我们先用一个饼状图来分析受访者的性别。我们首先用熊猫来计算数量。

gender = df['Gender'].value_counts().to_frame(name="values")
gender

现在我们将把 dataframe 传递给 cutecharts 的set_options方法。这

分析受访者的性别|按作者分类的图片

通过定义选项来自定义图表

  • legend_pos: 指定要放置图例的位置。(默认为upLeft)。可能的值有— upLeftupRightdownLeftdownRight
  • 颜色:饼图不同扇区的颜色列表。可选。
  • 内径:默认为 0。
  • 标签:鼠标悬停时可以看到的标签。

除了少数例外,这些参数中的大多数对于所有图表都是通用的。

2.圆环图

从饼图创建圆环图非常简单。给inner_radius参数一个大于零的值,一个甜甜圈图就形成了。

受访者人数最多的 5 个城市

让我们通过调查中的受访人数来计算和可视化排名前五的城市。

cities = df['City'].value_counts()[:5].to_frame(name='values')

受访者数量排名前五的城市|作者图片

3.条形图

饼图/甜甜圈图可能不是显示城市细分的最佳方式,尤其是在城市数量增加的情况下。条形图将是首选。

受访者数量排名前五的城市|作者图片

条形图中的大多数参数都是不言自明的。您还可以自定义每个条形的颜色,或者保留默认参数。在这种情况下,所有的条形将显示单一颜色。

4.折线图

根据多年经验计算的软件工程师薪酬中位数

折线图是显示数据趋势的理想选择;因此,我们将使用它来显示该地区软件工程师的工资比较。这个工资是没有奖金和股票的。

软件工程师多年经验薪酬中位数|图片由作者提供

5.散点图

根据多年经验计算的软件工程师薪酬中位数

上述信息也可以通过散点图显示出来。

软件工程师多年经验薪酬中位数|图片由作者提供

在这里你可以调整x_tick_county_tick_count以及剧情的dot_size

6.雷达图

雷达图也称为蜘蛛图,用于显示多元数据。根据维基百科

雷达图是以二维图表的形式显示多变量 数据图形方法,三个或三个以上的定量变量表示在从同一点开始的轴上。

对于我们的例子,我们将比较有股票和没有股票的软件工程师的工资。请注意,我们已经在前面的部分中计算了不带奖金和股票的工资,并在本部分中将其保存为名为salary_exp. 的数据帧。我们将创建另一个名为salary_exp2 的数据帧,包含字段Yearly bonus + stocks in EUR.

对比有奖金和没有奖金的工资|作者图片

结论

在上面的文章中,我们看到了如何用 Python 创建受 javascript 启发的手绘图表。作者在这个工具背后的想法不仅是帮助你制作这些 xkcd 类型的图表,也是为了展示创建一个类似的项目是多么容易。查看开源项目的源代码总是一个好主意。通过这种方式,你将能够理解并为当前的项目做出贡献,并获得创造自己有用的东西的想法。这就是开源的妙处。

增加您在数据科学求职中的机会

原文:https://towardsdatascience.com/increase-your-chances-in-the-data-science-job-hunt-27567da9d3a4?source=collection_archive---------27-----------------------

模仿我正在做的一个简单的任务

Unsplash 上的 el alce web 拍摄的照片

介绍

我们都知道找工作有多难。虽然我确实相信随着时间的推移,找工作会变得越来越难,但这并不意味着高潜力的候选人应该被排除在外。

虽然我肯定你读过几十篇关于人们如何在不到一年的时间里在 FAANG 公司获得梦想工作的文章,但我必须告诉你,这可能不会发生在你身上。我可以对你撒谎,但我不想。

作为一个一直在申请工作的人,有一个主要的技巧大大提高了我的机会,我也想与你分享。我希望你能从这篇文章中得到一些有价值的东西。

https://learningfrommachines.substack.com/welcome

对自己诚实

这不是提示,但如果我们想在这个过程中成功,我们需要对自己真诚一些。当我说对自己诚实时,它主要围绕着这个问题的答案:“我多久申请一次工作?”

很多次我会听到人们说他们已经申请了数百份工作却没有回音。虽然这是过去一年中许多人的情况,但也很容易看出这是夸大其词。对自己诚实需要你接受这样的事实:你可能并不像你认为的那样始终如一。然而,这完全没问题。你的生活不是你的工作,不管它看起来有多像。

在回答这个问题时,你仍然应该诚实地面对自己,因为这是你手头的小费。

我最喜欢的建议(个人)

这种情况多长时间发生一次?你上 LinkedIn,看看人们找到新工作的频率,然后马上把自己和他们进行比较。你不知道这个人是谁,除了当你还在找工作的时候他们已经找到了工作。据你所知,他们可能和公司有很多联系,而你没有你正在进入这个领域。攀比是所有快乐的小偷,在求职过程中尤其如此。你唯一需要比较的人就是你自己。更具体地说,把你自己和你昨天(总共)发出了多少份申请进行比较。

这个建议太简单了,太愚蠢了。然而,它是有效的。一周申请 3 份工作?给我 4 分钟。一天申请 1 份工作?给我两杯。一般来说,把你的申请率加上 1 就可以了。在一天结束的时候,你在和自己竞争,把自己放在那里,增加你成功的机会。

如果你害怕申请,或者对这一行完全陌生,那就从每周一份开始,直到你对这个过程更加适应。一旦这个过程对你来说变得更加直观,那就提高到每周 2 到 3 次。记住,你是在和自己竞争,而不是和别人竞争。

如果你习惯了求职,习惯了一贯被拒绝, 继续走 。每两周增加 1 英镑。从每天 1 到 2 到 3,你会发现更多的工作可以申请,更多的机会会向你走来。你会竭尽全力去实现你的梦想,但是请相信我,当我说你会感谢你自己的竞争!

最后的想法

学会和自己竞争,只和自己竞争。在一天结束时,没有人真正关心你所犯的错误,这是最好的礼物之一。就像 LinkedIn 上所有其他让你感到不安全的成功帖子一样——不要担心,作为一个目前正在寻找工作的人,它们也让我感到难以忍受的不安全——经常有很多失败,甚至我们都倾向于因为我们看到的一次成功而忽略掉。

当与自己竞争时,你的失败会成为更伟大的事情的更大基础,这反过来会加强你的优势,导致最积极的反馈循环。在与自己竞争的同时,保持真实的自我,美好的事情就会到来。

感谢您的阅读。

增加模型可靠性:模型选择——交叉验证——

原文:https://towardsdatascience.com/increasing-model-reliability-model-selection-cross-validation-1ce0bf506cd?source=collection_archive---------18-----------------------

在一个视图中使用 python 实现来增加结果可靠性的模型选择/类型

至关重要的是,机器学习中准备的模型为外部数据集提供可靠的结果,即泛化。在数据集的一部分被保留作为测试并且模型被训练之后,从测试数据获得的准确度在测试数据中可能是高的,而对于外部数据是非常低的。例如,如果在带有 x,y,z 标签的数据集中只选择带有 x 标签的数据作为随机选择的测试数据集,这实际上只给出了 x 标签的准确性,而不是模型,但这可能不会被开发人员注意到。这个模型不是一般化的,肯定是一个不理想的情况。本文包含不同的配置,从中可以选择训练数据和测试数据,以增加模型结果的可靠性。这些方法对于模型正确响应开放世界的项目是必不可少的。

**Table of Contents** 
**1.** Train Test Split
**2.** Cross Validation
**2.1.** KFold Cross Validation
**2.2.** Stratified KFold Cross Validation
**2.3.** LeaveOneOut Cross Validation
**2.4.** Repeated KFold Cross Validation
**2.5.** ShuffleSplit Cross Validation
**2.6.** Group KFold Cross Validation

图片由暹罗谭Unsplash 上拍摄

1.列车测试分离

在机器学习应用中,用数据集训练模型。通过这种训练,模型学习特征和输出(目标)之间的关系。然后,使用相同格式的另一个数据集评估模型的准确性。训练测试分离以用户选择的速率将数据分离成训练数据和测试数据。

IN[1]
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=2021)
print("shape of x_train",x_train.shape)
print("shape of x_test",x_test.shape)
**OUT[1]
shape of x_train (120, 4)
shape of x_test (30, 4)**

如 OUT[1]所示,数据集分为 20%的测试数据和 80%的训练数据。

2.交叉验证

虽然用 train_test_split 分离模型看起来很有用,但是从测试数据集得到的准确率可能并不能反映真实情况。例如,当我们用 train_test_split 随机分离包含 A、B、C 标签的数据集时,可以将包含 A、B 标签的数据分离为 train,将所有 C 标签分离为 test。在这种情况下,训练数据和测试数据之间存在差异,这对于模型的成功会产生误导。因此,当将数据集分成训练数据和测试数据时,使用不同的方法。现在让我们检查基于统计数据的交叉验证的类型,并使用 scikit learn 库轻松实现。

2.1.交叉验证

数据集被分成用户选择的数(k)。该模型被分割为多个部分,每个部分被称为折叠,并且在每个分割中不同的折叠被用作测试数据集。例如,如果一个包含 150 个数据的数据集被设置为 k=3,那么模型会给出 3 个精度值,而不同的 1/3 部分(0–50、50–100、100–150)会被用来测试每个精度。剩余的 2/3 部分用于每次迭代中的训练。

IN[2]
heart_dataset=pd.read_csv('heart.csv')
heart_data   =heart_dataset.drop('output',axis=1)
heart_target =heart_dataset['output']
rb=RobustScaler()
heart_robust=rb.fit_transform(heart_data)IN[3]
kf = KFold(n_splits=5)
i=1
for train_data,test_data in kf.split(X=heart_data, y=heart_target):
    print('iteration',i)
    print(train_data[:10],"length:", len(train_data))
    print(test_data[:10],"length:", len(test_data))
    print("**********************************")
    i +=1
**OUT[3]
iteration 1
[61 62 63 64 65 66 67 68 69 70] train_length: 242
[0 1 2 3 4 5 6 7 8 9] test_length: 61
**********************************
iteration 2
[0 1 2 3 4 5 6 7 8 9] train_length: 242
[61 62 63 64 65 66 67 68 69 70] test_length: 61
**********************************
iteration 3
[0 1 2 3 4 5 6 7 8 9] train_length: 242
[122 123 124 125 126 127 128 129 130 131] test_length: 61
**********************************
iteration 4
[0 1 2 3 4 5 6 7 8 9] train_length: 243
[183 184 185 186 187 188 189 190 191 192] test_length: 60
**********************************
iteration 5
[0 1 2 3 4 5 6 7 8 9] train_length: 243
[243 244 245 246 247 248 249 250 251 252] test_length: 60
************************************

心脏病数据集由 14 列和 303 行组成。所有特征值都是数字,因此应用了鲁棒定标器。数据集的输出由 0 和 1 组成。OUT[3]显示了每个分割中测试和训练数据的前 10 个数据。可以看出,来自第一次分割的测试数据从数据集的第一个数据开始;第二次分割的测试数据从 61 开始。数据;第三次分割的测试数据从 122 开始。数据;来自数据的测试数据第四次分割从数据 183.data 开始,最后一次分割从数据 243 开始。数据

IN[4]
scores=cross_val_score(LogisticRegression(),heart_robust,heart_target,cv=5)
print(scores)
print("mean accuracy:",scores.mean())
**OUT[4]
[0.83606557 0.86885246 0.83606557 0.86666667 0.76666667]
mean accuracy: 0.8348633879781422**

303 个数字数据的心脏病数据集已经用 k=5 的逻辑回归分裂了 5 次。每个分割的逻辑回归准确度分别为[0.83606557 0.86885246 0.83606557 0.86666670.7666667]。

KFold 交叉验证与 Shuffle

在 k 倍交叉验证中,数据集被按顺序分成 k 个值。当 KFold 选项中的洗牌random_state 值被设置时,数据被随机选择:

IN[5]
kfs = KFold(n_splits=5, shuffle=True, random_state=2021)
scores_shuffle=cross_val_score(LogisticRegression(),heart_robust,heart_target,cv=kfs)
print(scores_shuffle)
print("mean accuracy:",scores_shuffle.mean())
**OUT[5]
[0.83606557 0.78688525 0.78688525 0.85       0.83333333]
mean accuracy: 0.8186338797814209**

2.2.分层交叉验证

数据集被分成用户选择的数字(k)部分。与 KFold 不同的是,每个目标也是由 k 进行拆分和合并的,比如我们考虑 iris 数据集(前 50 个数据 iris setosa50-100 朵杂色鸢尾,100-150 朵海滨鸢尾)并通过选择 k 值 5:

IN[6]
iris_dataset=pd.read_csv('iris.csv')
iris_data   =iris_dataset.drop('Species',axis=1)
iris_data   =iris_data.drop(['Id'],axis=1)
iris_target =iris_dataset['Species']IN[7]
skf = StratifiedKFold(n_splits=5)
i=1
for train_data,test_data in skf.split(X=iris_data, y=iris_target):
    print('iteration',i)
    print(test_data,"length", len(test_data))
    print("**********************************")
    i +=1
**OUT[7]
iteration 1
[  0   1   2   3   4   5   6   7   8   9  50  51  52  53  54  55  56  57 58  59 100 101 102 103 104 105 106 107 108 109] length 30
**********************************
iteration 2
[ 10  11  12  13  14  15  16  17  18  19  60  61  62  63  64  65  66  67 68  69 110 111 112 113 114 115 116 117 118 119] length 30
**********************************
iteration 3
[ 20  21  22  23  24  25  26  27  28  29  70  71  72  73  74  75  76  77 78  79 120 121 122 123 124 125 126 127 128 129] length 30
**********************************
iteration 4
[ 30  31  32  33  34  35  36  37  38  39  80  81  82  83  84  85  86  87 88  89 130 131 132 133 134 135 136 137 138 139] length 30
**********************************
iteration 5
[ 40  41  42  43  44  45  46  47  48  49  90  91  92  93  94  95  96  97 98  99 140 141 142 143 144 145 146 147 148 149] length 30
************************************

当分析测试数据集时,每个目标的前 10 个数据(0–10;50–60;100–110 ),第二次迭代中每个目标的第二个 1/5 切片(20–30;60- 70;110–120)等等。每次迭代中的剩余数据用于训练,并且线性回归用于每次迭代中的训练数据,自然地,获得了 5 个不同的精度。

IN[8]
lr=LogisticRegression()
le=LabelEncoder()
iris_labels=le.fit_transform(iris_target)
rb=RobustScaler()
iris_robust=rb.fit_transform(iris_data)
iris_robust=pd.DataFrame(iris_robust)IN[9]
scores_skf = []
i = 1
for train_set, test_set in skf.split(X=iris_robust, y=iris_labels):
    lr.fit(iris_robust.loc[train_set], iris_labels[train_set])
    sco = lr.score(iris_robust.loc[test_set], iris_labels[test_set])
    scores_skf.append(sco)
    i += 1
print(scores_skf)
print("mean accuracy:",sum(scores_skf) / len(scores_skf))
**OUT[9]**
**[0.9, 0.9666666666666667, 0.9333333333333333, 0.9333333333333333, 0.9666666666666667]
mean accuracy: 0.9400000000000001**

由于 "'numpy.ndarray '对象没有属性' loc'"iris_robust 的 numpy 数组被转换为 pandas DataFrame。

分层 KFold 交叉验证可以轻松实现,如 Scikit learn 中的 cross_val_score 所示。

IN[10]
score_skf=cross_val_score(lr,iris_robust,iris_labels,cv=skf)
print(score_skf)
print("mean accuracy:",score_skf.mean())
**OUT[10]
[0.9        0.96666667 0.93333333 0.93333333 0.96666667]
mean accuracy: 0.9400000000000001**

两个结果是一样的。

由于 iris 数据集中的目标值相等(50–50–50 ),因此每个目标值的位置相等。但是,如果数据集中的标注比例不同,则每个折叠都将以此比例包含数据。例如,如果 label-x 有 100 个数据,label-y 有 900 个数据,则每个文件夹将包含 90% label-y 数据和 10% label-x 数据。

查看 scikit learn 的网站中的 split 方法,看到 y 值应该是(n_samples,),所以设计为用标签编码器运行,而不是 OneHotEncoder。

2.3.LeaveOneOut 交叉验证

每个数据被认为是一个折叠,所以 k 的值等于数据的数量。每个数据被逐一分离,并用剩余的数据训练模型。用训练好的模型测试分离的数据。如果我们考虑虹膜数据集:

IN[11]
loo = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels,
                               scoring='accuracy', cv=LeaveOneOut())print(loo,"len of loo=",len(loo))
print("mean accuracy:",loo.mean())
**OUT[11]
[1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 0\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1.] len of loo= 150
mean accuracy: 0.9466666666666667**

可以看出,由 150 个数据集组成的虹膜数据集用 LeaveOneOut 建模,并应用逻辑回归。每个数据都是分开的,并用剩余的数据训练模型。总的来说,该模型已经训练了 150 次,并且做出了 150 个预测(针对每个数据)。全部取平均值。

照片由布莱恩·苏曼Unsplash 上拍摄

2.4.重复 KFold 交叉验证

根据用户选择的值,重复 k 倍交叉验证的次数。对于虹膜数据集:

IN[12]
rkf = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels, scoring='accuracy', cv=RepeatedKFold(n_splits=5, n_repeats=5))
print("accuracy:", rkf)
print("mean accuracy",rkf.mean())
**OUT[12]
accuracy: 
[0.96666667 0.9       0.93333333 0.93333333 0.93333333 0.9
 0.93333333 1\.         0.96666667 0.96666667 0.86666667 0.96666667
 0.96666667 0.96666667 1\.         0.96666667 0.9        1.
 0.93333333 0.93333333 0.86666667 0.96666667 1\.         0.9
 0.96666667]
mean accuracy 0.9453333333333331**

数据集被分成 5 部分,算法被拟合 5 次。结果,获得了 25 个精度值。

对于分层折叠,也可以这样做:

IN[13]
rskf = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels, scoring='accuracy', cv=RepeatedStratifiedKFold(n_splits=5, n_repeats=5))
print("accuracy", rskf)
print("mean accuracy",rskf.mean())
**OUT[13]
accuracy
[0.96666667 0.9        0.96666667 0.96666667 0.96666667 0.9
 0.96666667 0.96666667 0.9        0.96666667 0.96666667 0.96666667
 0.9        0.96666667 0.96666667 0.9        0.93333333 1.
 0.96666667 0.96666667 0.96666667 0.93333333 1\.         0.9
 0.93333333]
mean accuracy 0.9493333333333333**

2.5.洗牌分割交叉验证

使用 n_splits 设置数据集的迭代次数,并以用户指定的比率为每次分割随机选择训练和测试数据:

IN[14]
shuffle_split = ShuffleSplit(test_size=.4, train_size=.5, n_splits=10)
scores_ss = cross_val_score(LogisticRegression(), iris_robust, iris_labels, cv=shuffle_split)
print("Accuracy",scores_ss)
print("mean accuracy:",scores_ss.mean())
**OUT[14]
Accuracy
[0.9        0.93333333 0.88333333 0.9        0.95       0.95
 0.93333333 0.91666667 0.95       0.95      ]
mean accuracy: 0.9266666666666665**

对于分层洗牌拆分,可以进行相同的过程:

IN[15]
shuffle_sfs=StratifiedShuffleSplit(test_size=.4, train_size=.5, n_splits=10)
scores_sfs = cross_val_score(LogisticRegression(), iris_robust, iris_labels, cv=shuffle_sfs)
print("Accuracy",scores_sfs)
print("mean accuracy:",scores_sfs.mean())
**OUT[15]
Accuracy
[0.88333333 0.93333333 0.93333333 0.93333333 0.91666667 0.96666667
 0.96666667 0.96666667 0.88333333 0.9       ]
mean accuracy: 0.9283333333333333**

2.6.集团交叉验证

当从同一个对象接收到多个数据时使用。例如,在医学数据中,为了模型的泛化,最好在训练数据集中具有来自同一患者的多个图像。为了实现这一点,可以使用 GroupKFold ,它接受一个组数组作为参数,我们可以用它来指示图像中的人是谁。这里的组数组指定了在创建训练集和测试集时不应拆分的数据组,并且不应与类标签混淆。使用 GroupKFold,该组或者在训练集上,或者在测试集上。

回到指南点击此处

https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d

为拉帕沃尼增加压力:更好的浓缩咖啡

原文:https://towardsdatascience.com/increasing-the-pressure-for-la-pavoni-espresso-2a8ee0febb1e?source=collection_archive---------25-----------------------

咖啡数据科学

改装一辆老爷车

自从我在我姻亲家的地下室里发现它以来,我已经拥有它 8 年了。我可以用它拍出像样的照片,但我永远也不能像在我的金快车上那样达到最佳表现。在研究了 Kim 的机器温度后,我看了看 la Pavoni,发现它受到压力释放阀的限制。

所以我修好了。

压力释放阀控制机器可以达到的最大压力和最高水温。所以我想调整阀门来提高温度。

看看水的饱和压力,或者水仍处于液态时的最高温度。锅炉里的水因为体积固定,不能完全变成蒸汽,结果温度升高,压力就升高。

当机器处于 100 摄氏度时,内部压力为 1 巴。对于 Kim Express,我发现 114℃到 123℃之间的温度提供了最好的味道和萃取,在这些温度下,压力在 1.6 到 2.2 巴之间。

当水碰到咖啡渣时,水温就下降了,所以从较高的温度开始,冲泡的温度也提高了。这是我拍摄质量的关键。这并不是说所有的咖啡和机器都应该在更高的温度下冲泡;我的咖啡是家中烘焙的,温度越高对我越好。

在阀门内部,一个弹簧支撑着一个滚珠轴承,当施加足够的压力时,滚珠释放了油箱中的压力。所以,我通过拉伸弹簧来调整阀门。

我轻轻地拉着弹簧,直到它变形。我不知道需要多大的力才能达到我想要的压力范围,但足以在弹簧释放之前达到更高的温度。

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

前后的表现

由于弹簧被拉伸,萃取和味道(最终得分)都增加了。我只有几个镜头可以比较,所以我没有太多的数据。然而,改装绝对允许我温度冲浪。

我也开始在金特快的范围内拍摄。

这个对浓缩咖啡机的小改进对我使用 La Pavoni 有很大的影响。我仍然可以在较低的机器温度下拍摄,但现在我不再受原始最高机器温度的限制。我比以前更喜欢这台机器了。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我订阅

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页

使用图像处理测量咖啡研磨颗粒分布

改善浓缩咖啡

断奏生活方式概述

测量咖啡研磨分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡用纸质过滤器

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维护

咖啡评论和想法

咖啡实验

移动游戏开发的增量数据科学

原文:https://towardsdatascience.com/incremental-data-science-for-mobile-game-development-955bb059e8a6?source=collection_archive---------14-----------------------

来源:作者

有条不紊地改善游戏体验,提升关键绩效指标

开发游戏常常感觉像在黑暗中四处搜寻。有时很难甚至不可能知道你下一步应该做什么来改善玩家的体验。或者如何将这些 KPI 提高一点。开发团队可能有很棒的想法,但是他们经常不确定他们应该先做哪些,或者哪些会有积极的影响。这就是数据可以派上用场的地方。

在这篇文章中,我将讨论数据科学在手机游戏开发中产生直接积极影响的三大方式。这些都是所有具备一定分析能力的手机游戏工作室可以用一款直播(或软发布)游戏做的事情。它们也可以完全离线完成,这使得它们非常适合在移动游戏工作室寻找第一个项目的数据科学家。

1.优化 FTUE

FTUE 是第一次用户体验;当玩家第一次启动游戏时,这是至关重要的最初时刻。所有免费游戏都有同样的弱点;因为它们免费且易于安装,所以也免费且易于卸载。我敢肯定,许多人在阅读这篇文章时会想到他们下载了一款手机游戏,但总玩时间不到一分钟就被删除了。安装了越来越多的播放器后,每一分钟都会离开。仅仅几天后安装,你的大多数球员将永远离开。

来源:作者

在此期间,任何小的不便都足以让新用户放弃你的游戏,这种影响在 FTUE 期间最为明显。

一个典型的 FTUE 会给出一步一步的指导,让玩家熟悉游戏,从而产生一个类似于这样的漏斗:

来源:作者

这是分析 FTUE 的第一次标准尝试。随着球员的离开,我们可以看到一个普遍的下降趋势,但如果有任何重大问题还不是很明显。让我们看看从一个阶段到下一个阶段的百分比变化。

来源:作者

现在用户退出 FTUE 的问题领域更清晰了。最大的下降发生在完成介绍视频之前,所以我们可以考虑改变这一点。这个结论的问题是,观看介绍视频平均需要 15 秒,比大多数其他 FTUE 步骤都要长。这可能只是因为在这个阶段有更多的用户离开,因为有更多的时间离开。让我们找出完成每个阶段的平均时间,并计算每个阶段每秒的“流失率”。

来源:作者

这个柱状图告诉了我们一个不同的故事,结合从之前的图中所学到的东西,它给了我们一些有趣的见解。玩家不只是在介绍视频中离开,因为有更多的时间离开,他们离开的速度也比其他阶段快。或许介绍视频不够精彩?也许这种游戏类型的观众只是想直接进入动作?介绍视频可能应该缩短,或者可以选择跳过,或者直接删除。

玩家在初始加载屏幕时似乎缺乏耐心,所以游戏程序员可以研究减少初始加载时间。

如果我们设法在 FTUE 的介绍视频阶段将流失率减少一半,我们可以模拟 KPI 会发生什么情况。也许可以试试前面的建议。我们在这里做了很多假设,最大的可能是,尽管视频介绍阶段的客户流失有所改善,但后期的客户流失保持不变。事实上,这是不可能的,但只是迁就我一会儿。

来源:作者

看起来不多,但我们预计即使在未来很长一段时间后,保留率也会有很大提高。这是因为一些原本会退出的用户现在会停留更长时间。例如,第 7 天的保留率从 15%上升到 15.45%,相对增加了约 2.5%。这也转化为一个可衡量的收入差异,假设每个每日活跃用户(ARPDAU)的平均收入为 0.15 美元,这在两组中保持不变。这是一个相当大的假设,在现实中也不太可能是真的,我们需要做一个现场测试来确定。请参见下文,了解我们对 100,000 名用户群体的 14 天累积收入预测变化:

来源:作者

现在,想象一下,如果我们修复了 FTUE 的其余部分,会产生怎样的影响……对一天的工作来说还不错。

识别 FTUE 问题可能是数据影响早期游戏 KPI 的最简单方法。FTUE 也是游戏开发中仅有的几个小的优化可以产生大的累积影响的地方之一。相比之下,游戏后期的优化通常需要更大的改动才能产生明显的效果。

2.模拟玩家流失

留存被广泛认为是免费游戏中最重要的指标[3]。正如我们之前看到的,即使是留存率的微小变化也会对其他 KPI 产生巨大影响,最终影响游戏的成功[4]。

对保留(或流失)建模是第一个机器学习项目的良好候选。然后,我们可以完全离线地解释这个模型,以识别问题,提出修复建议,并改善玩家的体验[5]。这个过程通常会导致一些有趣的和意想不到的改进建议。

基于树的模型是一个很好的选择,因为它们对我们人类来说是相对可解释的,并且它们通常表现得非常好。在这个例子中,我将基于树的 lightGBM 模型拟合到合成游戏数据中,以预测玩家在第一天(第 0 天)后流失和不再回来的概率。一旦我们的模型是合适的,我们对它的性能感到满意,我们可以使用 SHAP [6]来绘制最重要的特征:

来源:作者

SHAP 价值观使用博弈论(数学的一个分支)的原理。简而言之,它衡量每个输入要素对模型每个输出的贡献。换句话说,SHAP 值衡量的是在有和没有每个输入要素的情况下预测的变化程度。上面我们看到了预测客户流失时每个特征的平均绝对贡献。更高的值不一定意味着更高的预测流失概率,该图只是表明每个特性的平均影响程度。这给了我们一个最关键的领域的想法,我们可以看看,以提高我们的游戏中的保留。我们还可以看到每个特性的高值或低值如何对我们的流失预测产生积极或消极的影响。

来源:作者

这里的点是个人用户,这个特性对 x 轴上的流失预测的影响。颜色表示特性的较高/较低值。一些有趣的要点:

  1. 获得更多奖励的玩家流失概率要低得多。
  2. 花更多时间玩游戏的玩家不太可能流失(咄)。
  3. 平均 FPS 较高的玩家不太可能流失。

让我们重点关注第 3 点中强调的 FPS 问题。很明显,较高的 FPS 会降低预测的流失概率。

来源:作者

使用 SHAP 绘制每个用户,我们可以更清楚地了解 avg_fps 值如何影响预测的流失概率。在这里,我们看到 avg_fps 值超过 50 对减少预测的流失有显著影响。我们可以使用另一个输入特征给该图着色,以确定输入变量之间是否存在其他关系:

来源:作者

一个有趣的发现是,如果一个玩家的平均 fps 很低,而且他们每场游戏的死亡人数也很高,那么他们就更有可能流失。同样有趣的是,对于平均超过 30fps 的用户,这种关系开始逆转。如果他们每场游戏的死亡率更高,他们就不太可能流失。原来我们的⅓玩家平均 fps 不到 30。利用这些见解,我们可以建议开发团队尝试降低低性能设备的游戏难度,并看看是否有一些简单的方法来提高游戏的总体性能。让我们假设所有玩家都可以达到 10%的 FPS 提升(除了那些已经达到 60 FPS 上限的玩家)。然后,我们可以通过使用我们的模型来估计进行这种改进的影响:只需将我们的测试数据的 avg_fps 列乘以 1.1,然后将其输入到模型中进行预测。然后,我们可以比较这两组的平均流失预测,并将其绘制为留存/收入曲线:

来源:作者

来源:作者

因此,我们预计第 7 天的留存率将相对提高 3.6%(从 15.5%提高到 16%),14 天后的收入将比之前的 FTUE 提高 3.3%。

这有点天真,因为我们假设平均 fps 完全独立于数据中的其他特征,而实际情况很可能并非如此。然而,这确实给了我们一个很好的估计,那就是我们希望在真正的 A/B 测试中测量的改进。通过这种方法,我们可以对游戏的几乎任何方面进行建模,确定最大的改进潜力,并生成可测试的假设,以确定做出这种改变对各种 KPI 的影响有多大。利益相关者经常发现这些数据驱动的建议非常有说服力。

3.普遍获得优化的 LTV 模型

除了游戏本身的改进,数据科学也有很大的机会来帮助用户获取和性能营销。UA(用户获取)通常包括指定当在特定国家的特定平台上显示广告时你愿意支付的一些 CPI(每次安装成本)。根据广告网络的不同,还有许多其他的“购买”方法,但出于教导的目的,我将坚持使用常规 CPI,因为这通常是所有其他方法的总结。主要的贡献是为 UA 经理提供早期信号和见解,使他们更好地了解广告支出在哪里是有利可图的,在哪里是不利的,同时也有助于识别具有未开发潜力的来源。这对于手机游戏来说至关重要,原因如下:

  • 应用商店充斥着游戏,如果没有良好的营销,大多数玩家永远不会知道你的游戏的存在。
  • 花在永远不会盈利的广告活动上只会招致损失。
  • 在高投资回报率的广告活动上投入不足可能意味着次优的增长。

营销经理通常会使用历史数据来绘制一条简单的 LTV 曲线[8],并使用它来估计某个给定日期的广告支出回报。这就是数据科学的用武之地。使用来自我们玩家早期游戏会话的数据,我们可以建立一个更复杂、更强大的模型来预测用户的长期价值。然后,我们可以将该模型应用于通过广告获得的新用户,以预测他们的长期价值,并更早地了解每个广告活动是否可能盈利。与简单的历史 LTV 曲线相比,这些模型通常对产品的变化和安装质量的波动更加稳健。

我们的 UA 经理通知我们,我们的目标是在 D90 之前在某个特定的活动中实现 100%的 roa(广告支出回报)。也就是说,她预计到第 90 天,每个每日安装群组将实现收支平衡。在我们开始活动的几天后,我们可以使用我们训练的模型来预测到目前为止该活动获得的每个用户的 D90 值。然后,我们可以将其汇总,以比较预测的 D90 ARPI(每次安装的平均收入)与每次安装的活动成本(有时称为 LTV/CAC 比率[9])。

来源:作者

这很好——我们预测的 D90 ARPI 几乎在所有情况下都高于我们的收购成本。但没有这么快,很多信息可能会在平均值中丢失,我们知道用户支出通常遵循帕累托分布。意味着极少数玩家花了大部分的钱。一些“局外”玩家可能夸大了我们的数字,所以让我们从预测数据中剔除 99%的消费者。

来源:作者

当从我们的预测中剔除前 1%的支出者时,我们的活动看起来不那么有利可图。这告诉我们,我们依赖于非常小的安装百分比来使我们的一些活动在 D90 达到收支平衡,并且由于我们通过这些活动可以获得的这些高价值用户的数量每天都在变化,我们面临着高损失风险。这很快就变成了关于风险承受能力的讨论,这是每个工作室都非常具体的,所以我不会在这里深入讨论。

因此,我们可以建议我们的 UA 经理取消法国的活动,并降低英国的 CPI,因为该国似乎是最依赖“鲸鱼”的国家,仅在 D90 达到收支平衡。澳大利亚、加拿大和瑞士是我们可以提高消费物价指数以实现更多增长的国家。

这里重要的一点是,竞选活动的表现并不固定。它会因为各种原因而改变。考虑到这一点,我们应该经常评估我们的广告活动的表现,并使用我们的模型预测 D90 ROAS,并反馈给 UA 经理进行调整。通过这样做,我们可以直接为我们的游戏带来额外的收入,然后我们可以将这些收入投入到更多的开发或额外的广告支出中,以获得更多的增长。这是我们如何利用数据将我们的游戏变成增长引擎的基础:)

参考资料:

[1]https://www . interaction-design . org/literature/article/first-time-use-experience-ftue-start-as-you-mean-to-go-on

[2]https://medium . com/Google playdev/why-the-first-ten-minutes-if-you-want-keep-to-your-mobile-game-4a 89031 b 6308

[3]https://supercell.com/en/news/10-learnings-10-years/7436/

[4]https://www . games industry . biz/articles/2016-09-08-1000 万美元-生产预算-避免鱼翅

[5]https://medium . com/Google play dev/churn-acting-before-that-a 19 F6 a 680 c 09

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

[7]https://mobiledevmemo . com/why-payed-ua-is-the-primary-driver-of-discovery-for-mobile-apps/

[8]https://quant mar . com/17/What-is-lifetime-customer-value-ltv?show=18#a18

[9]https://mobiledevmemo.com/ltv-cpi-vs-cashflow/

使用 dbt 跟踪用户活动

原文:https://towardsdatascience.com/incremental-models-to-track-activity-with-dbt-7f6565b893f3?source=collection_archive---------8-----------------------

使用 dbt 增量模型在 Bigquery 中生成历史活动表(分时段)

在这篇文章中,我将展示如何在 BigQuery 中使用增量模型dbt 创建历史表并跟踪用户活动。如果 dbt 没有响铃,则检查此物品。您也可以从跟随的增量模型开始。

好,回到我们的例子!让我简单地说一下:我们有每个用户的最后活动时间戳,现在我们想知道用户每天访问我们平台的频率。

作者图片

假设我们有一个保存每个用户最近活动的表。我们需要建立一个表来跟踪用户每天是否在我们的平台上。我们不能用当前的 Last Activity 表做到这一点,因为它只保存了每个用户的最新活动时间戳。

一个简单的解决方案是保留最后活动表的每日副本。这当然可行,但是我们会有重复的用户,特别是当他们有一段时间没有来我们的平台的时候。

让我们列出我们的要求和考虑事项:

  1. 我们需要一个像Merge这样的操作,只保留唯一的用户行和他们的日常活动。
  2. 我们可以每天至少运行一次管道,以获得每日跟踪。
  3. 历史表会随着时间的推移而增长,所以让我们将它存储为一个时间单位分区的表,这样我们可以大幅降低成本。如果您不知道什么是分区表,请查看这个链接

我们的管道应该每天运行,选取最后一个活动表,并将其插入到我们分区的历史活动表中,同时考虑 user_id+activity_date 的唯一性。我将一步一步地向你展示如何用 dbt 做到这一点。

  • 创建一个文件,我把它命名为inc_user_activity.sql
  • 让我们决定使用SQL查询。我们需要从最后一个活动表中选择所有内容,但是以每天为粒度。假设我们将我们的表称为last_activity_table。如果你没有引用你的表,那么用你的表名代替{{ref('last_activity_table')}}。然而,我强烈推荐使用 dbt 中的引用,如果你不知道如何做,检查一下这个链接。所以不要
select user_id, last_activity from {{ ref('last_activity_table'}}

我们需要

select 
{{ dbt_utils.surrogate_key(['user_id',     dbt_utils.date_trunc('day','last_activity')]) }} as   user_activity_id,
user_id, 
date(last_activity) as activity_date 
from {{ ref('last_activity_table'}}

因为我们只需要每日粒度。如果我们让last_activity保持时间戳不变,那么如果用户不止一次访问,新表中就会有几行是同一天的。这就是为什么我们需要使用dbt_utils.date_trunc('day', 'last_activity'),以便我们将last_activity截断到日粒度。此外,我们的表需要一个键,它将保持user_id和活动日期之间的关系。我们通过dbt_utils.surrogate_key(['user_id', dbt_utils.date_truc('day', last_activity)])创建密钥。

  • 写我们的config吧!我们需要定义user_idactivity_date的惟一性,我们还需要创建一个日期分区表,所以瞧:
{{ config(
materialized='incremental',
unique_key = 'user_activity_id',
partition_by = { 'field': 'activity_date', 'data_type': 'date' },
incremental_strategy = 'merge') }}

让我们花一点时间来理解我们在这里做了什么:我们告诉 dbt 创建一个增量模型materialize = 'incremental',然后我们想要使用user_activity_id作为unique_key,正如我们在上面看到的,它是user_idactivity_date的组合。我们还需要告诉 dbt 创建一个分区表,所以partition_by = {'field':'activity_date', 'data_type' = 'date'}。最后,我们需要merge策略,所以如果已经有了user_idactivity_date的组合,那么就重写它,这样我们就尊重了我们的唯一性约束,但是也插入了不存在的组合。

  • 现在让我们告诉 dbt 如何运行增量模型的查询,因此我们将需要重新定义我们的SQL,以便只从最后一个活动表中选取昨天和今天的数据,并将它们添加到您的历史活动表中。我这样做是为了减少查询,我们只处理昨天和今天的数据。{%if is_icremental() %} ... {% endif %}块只为增量模型运行,因此查询将被修改以添加where条件,从而只过滤今天和昨天的数据。
select 
{{ dbt_utils.surrogate_key(['user_id',     dbt_utils.date_trunc('day','last_activity')]) }} as   user_activity_id, 
user_id, 
date(last_activity) as activity_date from {{ ref('last_activity_table'}}{% if is_incremental() %}and date_diff(current_date(), date(last_activity), DAY) <= 2{% endif %}

好了,这里我将把我上面描述的整个过程放在一起,这样你就可以简单地将它复制粘贴到你的 dbt 文件中,并进行适当的调整!

{{ config(
materialized='incremental',
unique_key = 'user_activity_id',
partition_by = { 'field': 'activity_date', 'data_type': 'date' },
incremental_strategy = 'merge') }}select 
{{ dbt_utils.surrogate_key(['user_id',     dbt_utils.date_trunc('day','last_activity')]) }} as   user_activity_id, 
user_id, 
date(last_activity) as activity_date from {{ ref('last_activity_table'}}{% if is_incremental() %}and date_diff(current_date(), date(last_activity), DAY) <= 2{% endif %}

总之, dbt 不仅可以用于转换数据以创建分析模型,还可以用于生成历史数据!源自 OLTP 源的表可能并不总是保留历史数据,因此您可以使用 dbt 的强大功能来构建增量模型并对其进行正确调优,以开始跟踪历史,而不是每天都保留完整的快照。此外,考虑您的表将如何扩展,因此时间分区,尤其是对于事件数据,从长远来看将会挽救您的生命。

这都是我送的!如果你想了解更多关于分区的内容,可以看看这篇很棒的帖子https://discourse . get dbt . com/t/big query-dbt-incremental-changes/982

两个随机变量之间的独立性、协方差和相关性

原文:https://towardsdatascience.com/independence-covariance-and-correlation-between-two-random-variables-197022116f93?source=collection_archive---------2-----------------------

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

在本文中,我将讨论两个随机变量之间的独立性、协方差和相关性。这些是统计学中的基本概念,在数据科学中非常重要。

介绍

让我们用一个例子从随机变量的简单定义开始。

随机变量

随机变量,通常写成 X ,定义为一个变量,其可能值是随机现象的数值结果[1]。给定样本空间 S 的随机实验,随机变量 X 是一个集合函数,它为属于样本空间S【2】的每个元素 s 分配一个且仅一个实数。

随机变量的一个例子可以是掷硬币,其结果可以是正面(H)或反面(T)。因此,样本空间为:

S = {H,T}

我们可以将随机变量 X 定义如下:

  • 让 X = 0 代表正面
  • 让 X = 1 表示尾部

注意,随机变量给样本空间(H 和 T)的每个样本分配一个且仅一个实数(0 和 1)。在这种情况下,X 的支撑或空间是{0,1}。

概率质量函数[2]

离散随机变量 X 取特定值 X 即 P(X=x)的概率用 f(x) 表示,称为概率质量函数(p.m.f .)。它被称为连续随机变量的概率密度函数。pmf 是离散随机变量的概率分布,提供可能的值及其相关概率[3]。它被定义为:

p(x) = P(X=xᵢ)

p(x)有一个性质,与所有可能值相关联的概率必须是正的,并且总和为 1。

现在我们有了关于随机变量和 pmf 的背景,我们将看看独立性,协方差和相关性。

随机变量的独立性

如果 X 和 Y 是两个随机变量,并且 X 的分布不受 Y 的取值影响,反之亦然,则称这两个随机变量是独立的。

在数学上,两个离散的随机变量是独立的,如果:

P(X=x,Y=y) = P(X=x) P(Y=y),对于所有的 X,Y。

直观地说,对于独立的随机变量,知道其中一个变量的值,不会改变另一个变量的概率。X 和 Y 的联合 pmf 仅仅是 X 和 Y 的个体边缘化 pmf 的产物。

让我们解决一个示例问题,以更好地理解如何使用该公式。假设我们有两个随机变量 X 和 Y,它们的联合概率是已知的。它可以表示为一个表格,如下所示。X 的边缘化 pmf 值可以通过对所有 Y 值求和来获得[5]。对于 y 也可以进行类似的边缘化。在联合 pmf 表中,它只对应于对列求和。联合 pmf 表以及边际 pmf 值如下所示:

来源:作者

为了使两个随机变量独立,联合 pmf 的单元条目应该等于求和行和列中表示的边缘化 pmf 值的乘积,即 P(X=x,Y=y) = P(X=x) P(Y=y),对于所有 X,Y。

如果这种关系对于 x,y 对中的任何一个都不成立,那么这两个随机变量就不是独立的。所以在我们的例子中,这些对不是独立的。

下面是从分布表创建边际 PMF 的代码。(注意,它没有经过任何优化。)

然后使用边际 PMF 来检查独立性:

我们看两个例子,一个是独立的,另一个不是。

我们从两个表中得到预期的关系:

来源:作者

协方差

协方差是两个随机变量的联合可变性的度量[5]。它显示了两个随机变量之间的线性相关程度。正协方差意味着存在直接的线性关系,即一个变量的增加对应于另一个变量的更大值。负协方差意味着一个随机变量的值越大,另一个随机变量的值越小。因此,协方差的符号显示了两个随机变量之间线性关系的性质。最后,对于两个独立的随机变量,协方差为零。然而,零协方差并不意味着两个随机变量是独立的。

协方差的大小取决于变量,因为它不是一个标准化的措施。因此,这些值本身并不能清楚地表明线性关系有多强。

协方差的公式为:

来源:作者

注:E(X)是随机变量的期望值。你可以在这里了解更多:https://en.wikipedia.org/wiki/Expected_value

除了知道联合 pmf 的值,我们还需要 X 和 Y 的平均值来计算协方差。以下函数计算分布表的协方差。

我们两个测试案例的协方差是:

来源:作者

我们确认独立情况下的协方差为零。而我们看到非独立测试用例的正协方差。这表明当 X 增加时,Y 也会增加。

最后,让我们看看相关性。

相互关系

相关性只是协方差的缩放/标准化版本,因此值介于-1 到 1 之间。分别使用 X 和 Y 的标准偏差进行归一化。

来源:作者

自变量同时具有零协方差和相关性。相关值为 1 意味着与正的线斜率完全相关。而相关性为-1 意味着与负的线斜率完全反相关。

为了计算相关性,除了计算协方差之外,我们还需要计算 X 和 X 的标准差。

我们的测试用例的相关性是:

来源:作者

正如所料,我们得到了与协方差相同的相关性。独立测试用例具有零相关性。而具有正协方差的测试用例具有低于 1 的正相关性。

还有一件事,需要注意的是,协方差/相关性并不意味着因果关系,即 X 与 Y 相关并不意味着 X 是 Y 的原因。 Seema Singh 就此写了一篇很棒的文章:https://towardsdatascience . com/why-correlation-does-not-implie-causance-5b 99790 df 07 e

结论

最后,我们看了什么是随机变量,什么是概率密度函数。之后,我们讨论了两个随机变量的独立性。最后,我们将协方差和相关性作为度量两个随机变量之间线性相关性的标准。后者只是前者的标准化版本。

参考

[1]http://www.stat.yale.edu/Courses/1997-98/101/ranvar.htm

[2]https://online.stat.psu.edu/stat414/lesson/7/7.1

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

[4]https://www . math . UMD . edu/~ millson/teaching/stat 400 fall 18/slides/article 16 . pdf

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

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

独立同分布

原文:https://towardsdatascience.com/independent-and-identically-distributed-ce250ad1bfa8?source=collection_archive---------4-----------------------

这个短语是什么意思?为什么我们几乎在任何地方都能看到这种情况?

照片由卡森Unsplash 上拍摄

统计数据无处不在,与之相关的术语也是如此。它在人类活动的每个领域都起着至关重要的作用。为了分析我们周围正在发生的事情,我们需要统计数据。然而,这让许多人望而生畏,因为有太多的术语,尤其是在与数据科学和机器学习相关的文本中。✍️Whenever 我们阅读任何这样的文本,我们几乎总是会遇到至少四到五个统计术语或短语。😫

一个这样的短语是独立同分布随机变量。这个短语如此常见,以至于我们到处都能看到它,并多次搜索它。💻

在本文中,我将尝试用一种简单的方式来解释这个短语。

注: i.i.d .是独立同分布的简称。

统计学中最基本的例子是抛硬币。😁所以,我也会用这个对象来解释独立同分布变量背后的思想。

照片由 PockyUnsplash 上拍摄

假设我掷一枚公平的硬币 100 次,得到 53 次正面和 47 次反面。现在我想第 101 次抛硬币。我会得到什么?嗯,我可以得到一个概率为 0.5 的头或尾(因为这是一个公平的硬币)。然而,得到正面或反面的概率不依赖于前面的任何结果,即 53 个正面和 47 个反面。这意味着即使我不保存关于我以前结果的信息,我仍然会得到正面或反面的结果。所以,我可以说过去的行为不会影响未来的行为。在这里,我们通过抛硬币得到的结果是独立的,并且是同分布的。独立是因为一个结果不依赖于另一个结果,相同是因为每个样本来自相同的分布(当我们掷硬币时,分布没有变化)。

注: 同分布不代表等概率。不要求两个随机变量只能各有 0.5 的概率,或四个随机变量只能各有 0.25 的概率,才能使它们是同分布的

因此,我们说随机变量 X ₁、 X ₂、…、 Xn 都是独立同分布的,如果所有的 Xᵢ 都是相互独立的,并且它们都具有(或属于)相同的分布。

让我们再举一个例子来理解它:

拿一个骨灰盒,把 n 个小球放进去,这样每个小球上都写有不同的数字。现在从瓮中抽取 m (其中 m < n )个球,并进行替换,这样 Xᵢ 就是写在从瓮中抽取的第 i 个球上的数字。由于从替换瓮中抽取一个球的概率是相同的,并且所有的球都是从同一个瓮中抽取的,我们可以说 X ₁、 X ₂、…、 Xn 都是同一个

请注意,抽取没有替换的球不是独立的,因为它们不是独立的,即使它们都有相同的分布。抽取每个球的概率将取决于先前抽取的球的概率。

一个非独立同分布的随机变量的例子:

假设我们有一副,我们抽了一张牌,是一张方块 a。现在,当我们从一副牌中抽出另一张牌时,我们知道它不可能是方块 a。因此,随机变量不是相互独立的,因而不是独立同分布的。

因此,独立同分布随机变量的正式定义如下:

一个随机变量的集合是独立同分布的,如果每个随机变量与其他随机变量具有相同的概率分布,并且都是相互独立的。

拥有独立且同分布的数据是机器学习、统计过程和假设检验的常见假设之一。这种假设在数据分析任务中很有用,即使数据不是严格独立同分布的。

通常,独立同分布假设出现在随机变量序列的上下文中,以说明序列中的随机变量独立于之前的随机变量。因此,我们说独立同分布不同于马尔可夫序列,在马尔可夫序列中,随机变量的概率分布是序列中前一个随机变量的函数,或者依赖于序列中前一个随机变量。

独立同分布假设在中心极限定理中很重要,中心极限定理本身就是一个非常重要的概念。

参考文献:

  1. http://www.utstat.utoronto.ca/~radford/sta247.F11/lec7.html
  2. https://www . cs . Princeton . edu/courses/archive/spring 07/cos 424/scribe _ notes/0208 . pdf

谢谢大家阅读这篇文章。请分享您对这篇文章的宝贵反馈或建议!快乐阅读!📗 🖌

领英

独立成分分析

原文:https://towardsdatascience.com/independent-component-analysis-ica-a3eba0ccec35?source=collection_archive---------3-----------------------

发现数据中隐藏的因素

这是关于主成分分析(PCA) 和独立成分分析(ICA) 的两部分系列文章的最后一篇。虽然技术是相似的,但它们实际上是不同的方法,执行不同的任务。在这篇文章中,我将提供 ICA 的高级介绍,将其与 PCA 进行比较,并给出一个使用 ICA 从 EEG 数据中去除眨眼伪迹的例子。

“鸡尾酒会问题”的最简单版本。图片作者。

国际通信机构(International Communications Agency)

用来描述 ICA 的标准问题是“鸡尾酒会问题”。最简单的形式,想象两个人在一个鸡尾酒会上进行对话(就像上面的红色和蓝色发言者)。不管出于什么原因,你在两个参加聚会的人附近都放置了两个麦克风(就像上面的紫色和粉色麦克风)。根据人和麦克风之间的距离,两个麦克风以不同的音量听到两种声音。换句话说,我们录制了两个文件,其中包括两个派对参与者混合在一起的音频。接下来的问题是,我们如何分离每个文件中的两个声音,以获得每个说话者的独立录音?

这个问题很容易用独立分量分析(ICA)来解决,独立分量分析将一组向量转换成一个最大独立的集合。回到我们的“鸡尾酒会问题”,ICA 会将两个混合音频录音(由下面的紫色和粉红色波形表示)转换为每个单独扬声器的两个非混合录音(由下面的蓝色和红色波形表示)。请注意,输入和输出的数量是相同的,由于输出相互独立,因此没有明显的方法像主成分分析(PCA) 那样丢弃成分。

利用独立分量分析将混合信号转换为独立分量。图片作者。

它是如何工作的

ICA 中有两个关键假设。我们试图揭示的隐藏丨独立成分必须是一个,统计独立,和两个,非高斯。语义上,我说的独立是指关于 x 的信息不会给你关于 y 的信息,反之亦然。从数学上来说,这意味着,

统计独立性的数学定义。图片作者。

其中 p(x) 表示 x 的概率分布。 p(x,y) 表示 x 和 y 的联合分布。非高斯假设只是意味着独立分量具有非高斯分布,这意味着它看起来不像钟形曲线。

非高斯性是 ICA 的一个关键假设。图片作者。

第一个假设是 ICA 的起点。我们想理清信息,得出一组独立的因素。如果没有多个独立的信息生成者需要发现,那么就没有必要使用 ICA。例如,想象使用 ICA 解决“鸡尾酒会问题”,但是只有一个参加聚会的人。我们可以称之为 COVID 生日派对问题。这没什么意义。

第二个假设的必要性在于数学。ICA 使用非高斯的思想来揭示独立组件。非高斯性量化了随机变量的分布偏离高斯分布的程度。非高斯性的示例度量是峰度和负熵。从中心极限定理中可以看出这种方法为什么有用。具体地说,一个结果表明,两个独立随机变量之和的分布比任何一个原始变量更接近高斯分布。ICA 结合了这一思想、非高斯度量和非高斯假设来揭示隐藏在数据中的独立成分。

为了说明这一点,考虑具有两个变量 x_1x_2 的数据集。这些变量作为定义空间的基础,即我们可以用它们在二维空间中绘制点。假设,我们知道数据背后的两个独立分量,S1,S2。这两个组件作为描述同一空间的替代基础。因此,这个空间中的任何一点 y 都可以写成变量x1x2或者分量S1S2的线性组合。

测量信号的线性组合,即输入变量。图片作者。

独立分量的线性组合。图片作者。

回到中心极限定理,两个随机变量之和的分布将比任一单个变量更高斯。因此,当 a1 和 a2 都不为零时, y 的分布将是比S1S2更高斯的。反之,如果 a_1 或 a_2 为零,那么 y 的分布将比前一种情况少高斯分布。并且,如果 s_1s_2 的非高斯假设成立,那么它将根本不是高斯的,因为 y 将正好等于其中一个独立分量!

换句话说, y 的非高斯性在与其中一个独立分量成正比时达到最大。这使得我们可以将 ICA 框架作为一个优化问题。举个例子,

将 ICA 框架化为单个独立分量的优化问题。图片作者。

其中我们希望找到使我们已知输入变量的线性组合的峰度最大化的 w1 和 w2 的值。w1 和 w2 的这些最佳值将定义一个独立的分量。

ICA 优化问题的解决方案定义了独立分量。

更一般地,我们可以求解权重矩阵 W ,这使得 W 和数据矩阵 X 的矩阵乘法的非高斯性最大化。

将 ICA 框架化为多个独立分量的优化问题。图片作者。

要点

我可能又一次在数学领域走得太远了。作为总结,我将强调 ICA 的三个关键点:

  • 输入的数量等于输出的数量
  • 假设独立成分在统计上是独立的
  • 假设独立分量是非高斯的

主成分分析与独立成分分析

在继续举例之前,我将简单比较一下 PCA 和 ICA。尽管这两种方法看似相关,但它们执行不同的任务。具体来说, PCA 常用于压缩信息即降维。而 ICA 旨在通过将输入空间转换成最大独立基来分离信息。两种方法的共同点是要求输入数据自动缩放,即减去每一列的平均值,然后除以其标准偏差。这就是为什么 PCA 通常是在执行 ICA 之前做的一件好事的原因之一。

主成分分析和独立成分分析的比较。图片作者。

**

示例:从 EEG 中去除眨眼

一如既往,我将以一个具体的实例来结束我的发言。在这个例子中,我将使用 ICA 从 EEG 数据中移除眨眼伪迹,代码可在 GitHub 的https://github.com/ShawhinT/YouTube/tree/main/ica库中找到。

脑电图(EEG)是一种测量大脑产生的电活动的技术。EEG 的一个主要缺点是它对运动和其他非脑伪像的敏感性。每当参与者眨眼时,就会出现这样的假象。在下图中,通过 Fp1 电极(靠近头部前方)的电压-时间图中的尖峰可以清楚地看到眨眼伪影。

导入数据并绘制 Fp1 电压与时间的关系。图片作者。

使用 ICA 的第一步是首先对数据集执行 PCA。在 Matlab 中用函数 pca() 很容易做到这一点。我要在这里指出,自动缩放数据至关重要。这在 pca() 功能中自动完成。此外,这里我们从对应于随时间测量的 64 个 EEG 电极电压的 64 列开始。在 PCA 之后,我们剩下 21 列,对应于 21 个得分向量,即主成分。

将 PCA 应用于数据集的代码。图片作者。

接下来,我们可以训练 ICA 模型,并将其应用于 PCA 得分矩阵。

将 ICA 应用于主成分的代码。图片作者。

绘制独立组件,我们可以检查哪些组件对应于闪烁伪像。

21 个独立成分的平方图。图片作者。

我使用一种惰性试探法来挑选出代表眨眼信息的独立成分。也就是说,挑选有 4 个主峰的分量。剩余的分量可以用于重建原始数据集,而不需要来自这些眨眼分量的信息。

挑选出与眨眼无关的成分并重建脑电图数据的代码。图片作者。

最后,我们绘制了 Fp1 电极的原始和最终电压随时间的变化图。

消除闪烁前后的 Fp1 信号。

结论

独立成分分析(ICA) 通过将一组变量转换为一个最大程度独立的新集合,提取数据中的隐藏因素。ICA 依赖于非高斯性的度量来完成这项任务。 主成分分析ICA 针对不同的目标,即前者压缩信息,后者分离信息。尽管它们有所不同,但使用 PCA 作为 ICA 的预处理步骤通常是有帮助的。这种技术组合在金融分析和神经科学等领域都有应用。**

资源

本系列更多 : 主成分分析 | GitHub 回购

连接 : 我的网站 | 预定电话 | 消息我

社交:YouTube|LinkedIn|Twitter

支持 : 给我买杯咖啡 ☕️ | 成为会员 ⭐️

****https://shawhin.medium.com/membership ****

【1】hyvrinen A,Oja E. 独立成分分析:算法与应用。神经网络。2000;13(4–5):411–430.doi:10.1016/s 0893–6080(00)00026–5

深度:用梯度解释 DNNs

原文:https://towardsdatascience.com/indepth-explaining-dnns-with-gradients-2bb148a30ba0?source=collection_archive---------40-----------------------

梯度,平滑梯度和综合梯度作为机器学习的解释,解释

基于梯度的解释或解释方法是用于解释深度神经网络(DNN)决策的最简单且通常有效的方法之一。原则上,它们可以用于任何可微分模型和任何类型的输入。在本文中,您将了解使用梯度来解释决策的不同方法,尤其是要注意的陷阱。

我们将研究局部归因方法,给定一个输入,给该输入的每个维度分配一个分数。该分数表明维度对于我们从模型中获得的输出有多重要。

作为一个跑步玩具的例子,我们将有如下的设置:一组四个简单的函数,所有加起来形成我们要解释的“预测函数”。我们将使用基于梯度的方法来解释在给定任何输入 x 的情况下,这些分量函数中哪一个对输出更重要。

黑色:要解释的函数。所有其他颜色都是它的组成部分。

即使我们在这个简单的运行示例中没有使用 DNN,以下技术也可以 1:1 用于任何可微分模型。(事实上,我们甚至可以尝试训练四个独立的 dnn 来逼近分量函数,并对它们的输出求和。)

我选择了组件函数来说明下面基于梯度的方法的某些缺点。分量函数是线性函数、正弦函数、阶跃函数和适应的 sigmoid 函数。所有函数都依赖于同一个一维 x。

注意,我们要解释的函数的输出值最强烈地依赖于线性分量和阶跃函数。总体来说,鼻窦大部分是噪音。

渐变*输入

先从(输入-)渐变作为解释方法 Baehrens et al. 说起。梯度是输出 wrt 的导数。输入端。这意味着,对于输入的任何微小变化,梯度告诉我们输出将如何变化。如果梯度较大,则输入尺寸的微小变化会对输出产生较大影响,如果梯度较小,影响也会较小。

这意味着,对于我们想要解释的输入周围的小区域,我们可以用每个输入的单个数字(梯度)来完美地表达改变输入的效果。这正是我们想要的!

我们可以将梯度*输入解释写成:

梯度*单一输入尺寸的输入。

这里的 x 是我们的输入特征。我们将每个梯度与相关的特征相乘,因为我们希望属性只有在特征也存在于数据中时才是大的,如果特征很小(即使它是一个重要的特征)时才是小的。

如果我们计算 x 的梯度一次,然后把它们当作常数,上面的公式就是一个线性函数。这很好,因为这意味着我们已经将网络的复杂性降低到一个简单的加权和,其中权重是我们的特征重要性。(注意:如果你试图解释一个线性模型而不是 DNN,你的模型在某种意义上已经是可解释的了。)

缺点是这个函数比我们最初的组件总和要简单得多,所以它不能忠实地代表网络实现的整个决策函数。但是,在本地,在这个特定输入周围的小邻域中,我们可以说这些权重确实代表了每个特征的重要性。即使我们不能保证这一点,如果我们的模型代表的函数是简单的,那么对于某些目的,梯度可能是决策函数的一个很好的近似。

梯度非常方便,因为它们可以在像 pytotchtensorflow 这样的框架中轻松自动地计算出来,而且由于它们对深度学习如此重要,这些实现非常高效和快速。这意味着你可以即时计算你的解释,而不需要大量的计算。

左:待解释的功能。右图:所有 x 的渐变*输入属性。

该图显示了每个分量函数和每个输入 x 的梯度*输入属性。如果线高,则意味着根据我们的解释,相应的函数对于输出高是非常重要的。我们可以清楚地看到简单梯度的弱点作为解释:虽然它是局部正确的(对于 x 的一些区域,正弦比其他函数更陡),但它错过了全局画面,即我们的函数主要依赖于线性部分和阶跃函数。

除了 0.5 之外,阶跃函数在任何地方都是平坦的,因此它没有倾斜度,因此也没有梯度。我们不能用梯度*输入来解释它的效果。

sigmoid 函数在 0 和 1 附近比较平坦,所以梯度也小。

显然,gradient*input 在这种设置下不能很好地工作,即使这种简单的方法也可以在不太病态的情况下工作。

现在你可能会想:如果我想知道输入的较大变化会有什么影响,渐变对我有什么帮助?不要烦恼!有一些方法建立在简单的输入梯度上,但是给你一个更“全局”的函数图像。

SmoothGrad

可能最直接的补充是 SmoothGrad (SG) [ Smilkov 等人。当你改变输入时,复杂函数的梯度变化非常快(想想我们的正弦函数)。顾名思义,SG 试图消除梯度中的这些凸起。它只需多次计算输入梯度,每次都会在输入中加入一点点噪声:

单一输入维度的 SmoothGrad。

实际上,我们对与我们想要解释的输入非常相似的许多输入的梯度进行平均。这个想法是梯度函数的不平度将达到平均,我们只剩下输入空间的这个区域中梯度的总体趋势。通过增加更多的样本和更大的噪声,我们可以使这种方法任意全局,但也增加了计算时间。

左:待解释的功能。右图:所有 x 的 SmoothGrad 属性。

在该图中,计算了 50 个噪声梯度,并对每个 x 取平均值。尽管我们没有恢复出真正的重要性比例,但这已经比单一梯度好得多:很明显,线性函数比正弦函数更重要,但我们仍然对 sigmoid 和阶跃函数有困难。我们可以通过使用超参数得到更好的结果。

综合渐变

在许多情况下,我们在输入空间中有一些参考点,在那里我们可以说根本“没有信息”,任何改变只是增加了信息。例如,在图像处理中,一片漆黑或平均值图像经常被用作这样的参考点。在这种情况下,我们只对我们的输入给参考输入增加了什么信息感兴趣(根据我们的 DNN)。集成梯度(IG) [ Sundararajan 等人 ]沿输入和参考点之间的最短路径(直线)集成梯度。如果我们将参考点设置为 x=0,这在我们的玩具示例中是合适的,因为此时没有相关的函数,公式简化为:

单一输入维度的集成渐变。

沿着这条路径,通过平均多个样本(梯度评估)来近似地完成积分。我们可以通过采集更多的样本来提高解释的质量。

左:待解释的功能。右图:所有 x 的集成渐变属性。

对于这个玩具例子,我们的参考点在 x=0,这里我们的输出也是 0。我们可以近似地恢复具有任何梯度信息的所有分量的相对重要性,即使每个输入 x 只有 30 个样本!甚至 sigmoid 函数也得到了正确的归属,因为要解释的 x 和 0 之间的所有梯度都被考虑在内。尽管这些解释已经很好了,但增加样本数量会导致更准确的解释,例如消除正弦解释中的轻微倾斜。

这个结果并不意味着积分梯度一定会打败 SG,但是如果我们知道一个 0-信息输入是什么样子,我们不妨试一试。

注意,我们还不能解释阶跃函数的作用,因为它的梯度是 0 或者到处都是未定义的。不依赖于梯度信息的解释方法,如遮挡分析沙普利值对于识别阶跃函数的影响是必要的。

外卖:

基于梯度的方法,如梯度*输入、平滑梯度或综合梯度,是基于输入的微小变化如何改变输出(也称为梯度),这引入了两个问题:

  1. 复数 f(x):如果要解释的函数随 x 变化非常快,那么输入梯度将只对我们输入周围非常小的范围有意义。SG 和 IG 通过平均许多梯度来提供解决方案,以获得较少的局部解释。
  2. 平坦 f(x):如果要解释的函数随 x 的局部变化很小,那么它只会产生一个很小的梯度。IG 通过考虑到 0-信息输入的最短路径上的所有梯度来解决这个问题,但是我们必须记住,在局部和全局精确的解释之间总是有一个折衷。
  3. 零梯度 f(x) :如果根本没有梯度,我们就不能指望基于梯度的方法起作用。幸运的是,这个问题实际上从来没有发生过,至少如果你使用的是 DNNs。

我还可以使用哪些方法?

基于梯度方法的其他变体也存在,如 VarGradSG-SQ ,但它们相当奇特,没有被社区广泛采用。

除了最简单和最容易实现的基于梯度的解释方法之外,还有很多(也更复杂)的方法试图克服基于梯度的方法的缺点。我已经在本文中列出了一些最受欢迎的方法,但是研究人员每个月都在试图提出更好的方法,所以这个列表远非详尽无遗。关于最近的调查,请看这里

希望你学到了有用的东西!

在 Julia 中索引、排序和聚集你的数据帧

原文:https://towardsdatascience.com/index-sort-and-aggregate-your-dataframes-in-julia-38646daf6214?source=collection_archive---------18-----------------------

使用 DataFrames.jl 进行常见数据分析的教程

杰斯温·托马斯Unsplash 上拍摄的照片

深入到 DataFrames.jl,我们将探索如何在 DataFrames 上做布尔索引,学习如何按列值对数据进行排序聚合表以满足我们的需求。在最后一节,我们还将介绍一种超级强大的分析方法,称为:分割-应用-组合

如果你需要复习 DataFrames.jl,先看看这些文章:

要获得所有媒体文章的完整信息,包括我的文章,请点击这里订阅。

获取一些数据

首先,我们需要从RDatasets包中挑选一个数据集。这样就省去了我们下载读入一个文件的麻烦。如果你想知道如何阅读 CSV,请查看我之前在 CSV.jl 和数据导入上的帖子——上面的链接。让我们导入包并设置我们的数据集

维多利亚博物馆在 Unsplash 上拍摄的照片

这个数据集追踪了超过 500 个人的时薪、工作经验、教育和其他可能与薪水相关的因素。你可以在这里找到更多关于数据集的信息。在我们的练习中,我们将只使用以下各列:

  1. NR:唯一的工人标识符。
  2. Year:观测年份。
  3. Wage:计时工资日志。
  4. Ethn:工人的种族等级:黑人、hisp、其他
  5. 多年的经验。
julia> first(males, 5)
5×5 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper
     │ Int32  Int32  Float64  Cat…   Int32
─────┼─────────────────────────────────────
   1 │    13   1980  1.19754  other      1
   2 │    13   1981  1.85306  other      2
   3 │    13   1982  1.34446  other      3
   4 │    13   1983  1.43321  other      4
   5 │    13   1984  1.56813  other      5

索引

对数据帧的典型操作是根据值 s 上的一些标准对数据进行子集化。我们可以通过首先构建一个布尔索引(真/假值的向量)来实现这一点,该索引对于期望值为真,否则为假。然后,我们可以将它作为数据帧的第一个参数放入括号中,以选择所需的行。

为了节省空间,我将只打印前 5 行。我用first(dataframe, 5)来做这个。

5×5 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper
     │ Int32  Int32  Float64  Cat…   Int32
─────┼─────────────────────────────────────
   1 │    13   1980  1.19754  other      1
   2 │    17   1980  1.67596  other      4
   3 │    18   1980  1.51596  other      4
   4 │    45   1980  1.89411  other      2
   5 │   110   1980  1.94877  other      5

粘土堤Unsplash 上拍照

我们使用冒号:来表示我们想要所有可用的列。您应该这样阅读上面的内容:给我所有的男性行,其中my_index为真,并返回所有可用的列。通常,你会在一个步骤中完成,因为真的没有必要分配一个单独的布尔索引向量:

这给出了与上面相同的结果。

如果有多个标准呢?假设我们需要 1980 年的观察数据,但只针对西班牙裔工人:

5×5 DataFrame
 Row │ NR     Year   Wage      Ethn  Exper
     │ Int32  Int32  Float64   Cat…  Int32
─────┼─────────────────────────────────────
   1 │  1142   1980  1.41311   hisp      2
   2 │  1641   1980  2.11169   hisp      4
   3 │  1644   1980  0.560979  hisp      1
   4 │  1721   1980  1.78447   hisp      5
   5 │  1763   1980  0.6435    hisp      1

如你所见,解决方案是使用 AND &逻辑运算符对两个布尔向量进行逐元素比较(因此我们用.&进行广播)。所以我们产生第三个向量,当且仅当年份是 T6,Ethn 是 T7 时,这个向量为真。

熟能生巧,所以让我们选择在 1980 年有 3 年以上工作经验的人:

males[(males.Year .== 1980) .& (males.Exper .> 3), :]

如果你需要其他的逻辑运算符,请查阅 Julia 手册中的本页。在那里你可以学习如何用!的反,并与或运算符 : |交朋友。

为了完整起见,下面是如何用filter函数做同样的事情:

filter(df -> (df.Year == 1980) & (df.Exper > 3), males)

这在我之前的文章中有更详细的描述。

排序数据帧

照片由德鲁·比默Unsplash 上拍摄

让我们学习如何对数据集进行排序。正如你所想象的,这又是一个很常见的操作,幸运的是,它确实非常简单。首先,让我们按照Year列对数据进行排序。

5×5 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper
     │ Int32  Int32  Float64  Cat…   Int32
─────┼─────────────────────────────────────
   1 │    13   1980  1.19754  other      1
   2 │    17   1980  1.67596  other      4
   3 │    18   1980  1.51596  other      4
   4 │    45   1980  1.89411  other      2
   5 │   110   1980  1.94877  other      5

简单对吗?只需将一个数据帧传递给排序函数,并告诉它根据对哪一列(或哪些列)进行排序。你希望它减少吗?对此有一个关键词:

您可能想知道为什么我们必须传入一个列名数组来进行排序。这样我们可以同时指定多个列进行排序。这里有一个例子:

5×5 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper
     │ Int32  Int32  Float64  Cat…   Int32
─────┼─────────────────────────────────────
   1 │    13   1980  1.19754  other      1
   2 │    17   1980  1.67596  other      4
   3 │    18   1980  1.51596  other      4
   4 │    45   1980  1.89411  other      2
   5 │   110   1980  1.94877  other      5

请注意,我们首先获得了 1980 年的所有观测数据,而NR数字正在增加。

sort()函数需要一个数组作为第二个参数,这样就可以同时对多列进行排序。

数据科学中一个重要的考虑因素是您的内存占用。以上所有操作都返回了 DataFrame 的副本,只留下我们的原始数据集。如果你不想改变你的原始数据集,这是很有用的,但是如果你想减少你的内存占用,你可以使用一个特殊版本的sort,结尾有一个刘海:sort!。这是 Julia 中的一个约定,函数通常是不可变的,如果一个函数改变了它的参数,那么它的名字应该以一个“砰”结束。下面是它在实践中的工作原理:

这将修改原始数据帧。

julia> first(males, 5)
5×5 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper
     │ Int32  Int32  Float64  Cat…   Int32
─────┼─────────────────────────────────────
   1 │    13   1980  1.19754  other      1
   2 │    17   1980  1.67596  other      4
   3 │    18   1980  1.51596  other      4
   4 │    45   1980  1.89411  other      2
   5 │   110   1980  1.94877  other      5

!结尾的函数表示该函数正在改变其输入参数。

拆分-应用-组合范例

现在我们知道如何索引和排序我们的数据帧。这很有趣,但更有趣的是,如果我们不需要用眼睛来观察所有这些观察结果。如果我们能够以某种方式聚合我们的数据并收集一些有趣的统计数据会怎么样?嗯,这在 SQL 中称为 GROUP BY 操作,我们在 DataFrames.jl 中也有类似的东西。对于初学者,让我们做一些非常简单的事情。让我们算出我们每年有多少次观察(行):

8×2 DataFrame
 Row │ Year   nrow
     │ Int32  Int64
─────┼──────────────
   1 │  1980    545
   2 │  1981    545
   3 │  1982    545
   4 │  1983    545
   5 │  1984    545
   6 │  1985    545
   7 │  1986    545
   8 │  1987    545

这是如何工作的?涉及两个功能:

  • groupby:获取数据帧和我们想要对其进行分组的列。
  • combine:获取groupby的输出,并对每个组应用函数nrow,汇总结果。

nrow函数只计算数据帧中的行数。

最终的结果是一个 DataFrame,每个Year——我们分组的列——都有一行。柱子也用Yearnrow来命名。

你也可以使用匿名(lambda)函数进行上述操作。如果您有一些快速功能要运行,这是很有用的,但要让我们开始,这里有与上面相当的功能:

combine(groupby(males, ["Year"]), df -> nrow(df))

我认为这告诉了我们更多关于它是如何工作的。我是这样理解的:

按列Year分割名为 males 的数据集,然后对每个更小的数据集df 应用函数nrow。最后,结果组合成一个数据帧,这样我们最终得到一个包含两列的表:一列表示拆分(年份),另一列表示我们的函数结果。

你在这里看到的实际上是拆分-应用-组合范式。了解如何快速有效地完成这项工作,您将能够从大多数数据集中提取您需要的所有信息!

让我们多做一些练习。工人每年的平均工资是多少?

8×2 DataFrame
 Row │ Year   x1
     │ Int32  Float64
─────┼────────────────
   1 │  1980  1.39348
   2 │  1981  1.51287
   3 │  1982  1.57167
   4 │  1983  1.61926
   5 │  1984  1.69029
   6 │  1985  1.73941
   7 │  1986  1.79972
   8 │  1987  1.86648

我知道你在想什么。那个栏目为什么叫x1?这很难看,而且当我不得不记住这些数字代表什么的时候,我的生活会变得更加艰难。不要担心,我们可以将几乎任何我们喜欢的函数传递到combine中,这样我们实际上可以创建一个具有新列名的数据框架:

8×2 DataFrame
 Row │ Year   wage_avg
     │ Int32  Float64
─────┼─────────────────
   1 │  1980   1.39348
   2 │  1981   1.51287
   3 │  1982   1.57167
   4 │  1983   1.61926
   5 │  1984   1.69029
   6 │  1985   1.73941
   7 │  1986   1.79972
   8 │  1987   1.86648

整洁多了。让我们看看我们是否可以将这个扩展到在每次分割时收集多个统计数据——记住我们可以在combine中做任何我们喜欢的事情:

8×3 DataFrame
 Row │ Year   wage_avg  people
     │ Int32  Float64   Int64
─────┼─────────────────────────
   1 │  1980   1.39348     545
   2 │  1981   1.51287     545
   3 │  1982   1.57167     545
   4 │  1983   1.61926     545
   5 │  1984   1.69029     545
   6 │  1985   1.73941     545
   7 │  1986   1.79972     545
   8 │  1987   1.86648     545

在这里,我们不仅收集每年的平均工资,还收集每年的样本量——独特工人的数量。以上真的很厉害,在调查数据集的时候可以帮到你很多。

迂回到方法链接,又名管道

是的,这不是烟斗。乔纳森·卡罗尔在 Unsplash 上拍摄的照片

正如我们在上面看到的,使用匿名函数可以非常有效地从数据集中快速获得一些统计数据。然而,当它们变得复杂时,可能有点难以阅读。我喜欢通过使用管道或方法链来解决这个问题。

这里我将展示一个管道的例子。假设你有一个包含 3 个值的向量:[1,2,3]你想对所有的值求平方,求和,然后求和的平方根。您可以使用标准函数来实现这一点:

julia> sqrt(sum(([1,2,3] .^ 2)))
3.7416573867739413

请注意,我们必须像写数学函数一样,把上面的内容写出来。我们首先写sqrt,然后写sum等等,而不是像我们描述的那样从平方开始。这就是方法链发挥作用的地方。通过使用 Julia 中内置的管道操作符|>,我们可以将操作的结果传递给一个新函数。下面是与上面相同的操作,但是使用了管道:

julia> [1,2,3] .^ 2 |> sum |> sqrt
3.7416573867739413

我们为什么要用这个?嗯,这允许我们编写链接在一起的快速而肮脏的匿名函数来做一些奇特的聚合。

把所有的放在一起

约翰·施诺布里奇在 Unsplash 上拍摄的照片

现在我们知道了如何使用管道,让我们看看如何在数据帧中使用它们。作为一个例子,假设我们想要获得每个人的第一个和最后一个记录的工资。因为我们知道如何排序和分割数据帧,所以我们可以这样做:

julia> first(firstlast, 5)
5×3 DataFrame
 Row │ NR     first    last
     │ Int32  Float64  Float64
─────┼─────────────────────────
   1 │    13  1.19754  1.66919
   2 │    17  1.67596  1.82033
   3 │    18  1.51596  2.87316
   4 │    45  1.89411  2.13569
   5 │   110  1.94877  2.11239

在第一步中,我们对分割的数据帧进行排序,然后我们使用这个sorted_df应用另一个函数来提取第一个和最后一个工资值。让我们做一个快速的感觉检查,看看这是否确实是我们想要的:

julia> males[(males.NR .== 13) .& (map(year->year ∈ [1980, 1987], males.Year)), [:NR, :Year, :Wage]]
2×3 DataFrame
 Row │ NR     Year   Wage
     │ Int32  Int32  Float64
─────┼───────────────────────
   1 │    13   1980  1.19754
   2 │    13   1987  1.66919

是的,这行得通,所以让我们简化一下:

很漂亮,对吧?想象一下你可以用这些做什么样的疯狂分析!💪

让我们多练习一些。让我们创建一个名为is_lower的列,如果员工的最终工资低于他的最佳工资,则该列为真。我们需要像以前一样找出他们的第一份和最后一份工资,但是现在我们还需要存储最大工资值:

julia> first(finishers, 5)
5×5 DataFrame
 Row │ NR     first    max      last     is_lower
     │ Int32  Float64  Float64  Float64  Bool
─────┼────────────────────────────────────────────
   1 │    13  1.19754  1.85306  1.66919      true
   2 │    17  1.67596  1.82033  1.82033     false
   3 │    18  1.51596  2.87316  2.87316     false
   4 │    45  1.89411  2.13569  2.13569     false
   5 │   110  1.94877  2.20252  2.11239      true

这看起来是可行的,所以让我们稍微清理一下我们的代码,因为我们实际上不需要存储第一个/最后一个值——我只是添加它们来做一个快速的感觉检查。

julia> first(finishers, 5)
5×2 DataFrame
 Row │ NR     is_lower
     │ Int32  Bool
─────┼─────────────────
   1 │    13      true
   2 │    17     false
   3 │    18     false
   4 │    45     false
   5 │   110      true

最后,我们可以将上述内容合并回原始数据集:

julia> first(new_males, 5)
5×6 DataFrame
 Row │ NR     Year   Wage     Ethn   Exper  is_lower
     │ Int32  Int32  Float64  Cat…   Int32  Bool
─────┼───────────────────────────────────────────────
   1 │    13   1980  1.19754  other      1      true
   2 │    13   1981  1.85306  other      2      true
   3 │    13   1982  1.34446  other      3      true
   4 │    13   1983  1.43321  other      4      true
   5 │    13   1984  1.56813  other      5      true

结论

你现在已经掌握了可能是最强大的分析技术,并且知道如何在 Julia 中拆分-应用-组合你的数据框架

您还学习了如何:

  • 使用布尔向量索引你的数据帧
  • 根据列值对数据帧进行排序——甚至可以使用sort!就地排序
  • 根据对数据帧进行分组,并对其应用函数
  • 使用管道操作符|>让你的 lambda 函数更加强大

谢谢你一路看完!👏

如果你想获得更多朱莉娅的乐趣,请访问 DataFrames.jl 和 CSV.jl:

Plotly 指示器

原文:https://towardsdatascience.com/indicators-with-plotly-85a543f002cd?source=collection_archive---------20-----------------------

角规还是子弹图?

图片来自 Unsplash 的 Shuaib Khokhar

商业智能(BI)是商业环境中用于将数据转化为知识的一组资源和技术。其主要目标是提高每个组织的生产率和绩效。BI 依赖于关键绩效指标仪表板( KPI 仪表板)。

KPI 仪表板是运营和战略信息的可视化显示,经理和决策者需要这些信息来评估其当前流程并解决可能影响业务绩效的问题。

KPI 仪表板必须易于查看、导航和理解。指标提供关于单个定量测量的信息,通常用于表示业务关键数据中涉及的主要指标。因此,指标必须出现在 KPI 仪表板上。

Plotly 包括一个名为指示器的轨迹,有两种量规类型:角度子弹。我们分别来分析一下。

角度规图

角度规图表(速度表图表、刻度盘图表)直观地显示定量测量是否低于、处于或高于给定的数值范围。有不同的布局,最常见的看起来像车辆的速度表,指针或指针在径向标尺上移动。另一种经典的布局包括一个内部带有阴影条的圆弧。

范围的数量是可变的(三个、四个、五个),它们中的每一个都用某种颜色来标识。例如:红色、黄色和绿色用于表示警报、警告和满意,或者表示低性能、正常性能和高性能。指标通常包括一个目标阈值,用与数值范围不同颜色的垂直线表示。这个阈值可以是一个基准、要超过的前一个值或要达到的目标。

带 Plotly 的角度规图表

对于本文中的角度规图,Plotly trace 是 go。Indicator() 和相应的参数有:来表示图的范围;标题为轨距以上的文字;表示要显示的数值;和 mode = "gauge + number" 用测量值画一个圆弧。

最重要的参数是标尺具有以下属性:形状设置形状(有角或子弹);步骤设置范围及其对应的颜色;表示阴影条的颜色和粗细。对于阈值值,我们必须指明颜色、宽度、厚度、。如果我们想指示圆弧周围的刻度,我们必须包括属性。我们通过一个 D3.format 函数将出现在量表中的数字格式化。

这是角度规图的代码:

在该仪表中,我们决定用圆圈内的注释显示测量值和参考值之间的差异,而不是标准程序(mode = " gauge+number+delta "):

下图显示了具有三个扇区的角度仪表图:S1 从 0 到 25,颜色为红色,低性能;S2 从 25 岁到 50 岁,肤色发黄,表现正常;S3 从 50 到 100,颜色绿色,高性能。测量值设置为 45,并用黑色弯条编码。要实现的目标设定为 60,并用橙色线表示。测量值及其与参考值的差异用大数字突出显示。

图 1:作者用 Plotly 制作的角度规图。

角度仪表图是非常简单的图形,具有直观的颜色序列,即使对于非专业观众来说,也能提供清晰、简单的方法来理解信息。

它们有一些缺点:1 .-它们占用大量物理空间;2.-他们可能会忽略关键信息;3.-它们没有描述业务环境;4.-他们可能会用红绿色盲来迷惑观众。永远记住这些缺点,以避免糟糕的故事。

项目符号图表

这种类型的图形与角度规的概念相同,即通过与参考值进行比较来提供单个数值测量的信息。该图表显示两到五个范围或部分,用不同的颜色区分,表示质量值,如差、一般和优秀。

项目符号图包括一个编码绩效指标的中间窄线性条和一条编码参考指标的垂直线。它们有一个沿线性轴的数量刻度,刻度等距。

带情节的项目符号图表

对于本文中的子弹图,其轨迹是 go。Indicator() 和相应的参数有:来表示图的范围;标题为图左侧的文字;表示测量值。与前面的例子相反,我们使用标准程序显示测量值和参考值之间的差异: mode = "gauge + number + delta "。

最重要的参数是量规增量。 仪表有以下属性:“shape”:“bullet”用于绘制水平项目符号图;表示线性刻度的范围;表示阴影线型条的颜色和粗细;步骤设置范围及其对应的颜色。对于阈值值,必须注明颜色、宽度、厚度、边框颜色和边框宽度用于改善图形的最终外观。

增量参数需要一个参考值,一个位置 ( "top" | "bottom" | "left" | "right")。最后,增加减少设置指示测量值和参考值之间差异的数字的颜色和符号。

这是项目符号图的代码:

下图显示了一个包含五个扇区的项目符号图:S1 从 0 到 20,颜色为浅绿色,污染程度良好;S2 20 至 40,颜色黄绿色,中度污染;S3 从 40 到 60,颜色偏黄,敏感人群污染水平;S4 从 60 到 80,颜色为橙色,不健康的污染水平;S5 从 80 到 100,颜色为红色,危险污染级别。测量值设置为 66,并用黑色线性条编码。未达到的危险级别设置为 75,并用蓝色垂直线表示。测量值及其与参考值(60)的差值显示在图的右侧。当测量值高于参考值时,“增量”参数的递增属性用一个红色向上的三角形表示该差异。

图 2:作者用 Plotly 做的子弹图。

项目符号图表也简单易懂。它们比角度仪表图占用更少的物理空间,并且它们的格式也不会分散观众的注意力。然而,与前面的方法一样,它们没有提供经理和决策者有时需要支持更好的业务决策的完整故事和背景。

如果你发现了这篇感兴趣的文章,请阅读我之前的(https://medium.com/@dar.wtz):

棒棒糖和哑铃图,有曲线、平均值或中值?

斜率图表,为什么和如何,用斜率讲故事

黑盒模型的个人追索权

原文:https://towardsdatascience.com/individual-recourse-for-black-box-models-5e9ed1e4b4cc?source=collection_archive---------45-----------------------

模型可解释性

通过猫和狗的故事直观地解释

“你不能诉诸【算法】。他们不听。他们也不屈服。”

-凯茜·奥尼尔

图片作者。

在她受欢迎的书数学毁灭的武器中,凯茜·奥尼尔举了公立学校教师莎拉·威索基的例子,她在教师评估算法使她成为多余的奥尼尔后失去了工作(2016)。莎拉在同龄人、主管和学生中很受欢迎。

这篇文章着眼于一种新颖的算法解决方案,它解决了这样一个问题,即像 Sarah 这样面临不良结果的人,应该被提供修正结果的方法。文献通常将此称为个人追索权。Ustun、Spangher 和刘(2019)提出了第一种个人追索方法。在最近的一篇后续论文中,Joshi 等人(2019)提出了一种他们称为REVISE的方法,该方法在至少三个关键方面扩展了早期的方法:

  1. REVISE提供一个框架,通过对修改后的属性施加一个阈值似然性来避免建议一组不切实际的变更。
  2. 它适用于更广泛的模型类别,包括黑盒分类器和结构因果模型。
  3. 它可以用来检测定义不明确的代理和偏见。

关于这些问题的详细讨论,你可以查看这张幻灯片或直接查阅论文(可在 DeepAI 上免费获得)。在这里,我们将从这些复杂性中抽象出来,转而看一个稍微简化版本的REVISE的应用。这应该有助于我们首先建立良好的直觉。对技术细节和代码感兴趣的读者可以在下面的附件中找到所有这些内容。

从🐱到🐶

我们将通过一个简短的猫狗故事来解释REVISE。这个故事的主角是基蒂🐱,一只识别为狗的幼猫。不幸的是,凯蒂不是很高,她的尾巴虽然对猫来说很短,但比一般的狗要长(图 1)。

图 1:描述猫和狗的模拟数据集的经验分布。竖梗代表 Kitty 的属性值。图片作者。

令她非常沮丧的是,我们通过随机梯度下降训练的线性分类器 g(x) 已经将 Kitty 识别为一只猫(同样,感兴趣的读者可以在下面的附件中找到技术细节和代码)。图 2 显示了在属性空间中产生的线性分离,决策边界用黑色实线表示,Kitty 的位置用红色圆圈表示。我们能向凯蒂提供个人求助吗?

图 2:猫和狗在二维属性空间中的线性分离,拟合分类器的判定边界为纯黑色。Kitty 的位置由一个红圈表示。图片作者。

让我们看看我们是否以及如何将REVISE应用于凯蒂的问题。下面的总结应该会让您对算法的工作原理有所了解:

  1. 初始化 x ,这是将被递归修改的属性。Kitty 的原始属性似乎是一个合理的起点。
  2. 通过梯度下降递归修正 x 直到 g(x)=* 🐶。此时下降终止,因为对于这些修改的属性,分类器将小猫标记为狗。
  3. 返回 x-x* ,这是 Kitty 的个人追索权。

图 3 说明了当这种方法应用于 Kitty 的问题时会发生什么。不同的面板示出了正则化参数的不同值的结果,该正则化参数控制实现期望的标签切换和保持原始和修改的属性之间的距离较小之间的折衷。除了一种情况,REVISE收敛了:随着高度的增加,尾巴长度的减少最终允许 Kitty 穿过决策边界。换句话说,我们已经成功地把 Kitty 变成了一只狗——至少在线性分类器的眼里是这样!

我们还观察到,对于固定的学习速率,当我们增加正则化参数时,REVISE需要更长的时间来收敛。这一点也不奇怪,因为我们明确规定了更严格的惩罚,即小猫必须行进的距离。当我们惩罚过多时(右下图),Kitty 永远不会到达决策边界,因为她不愿意改变超过某个点的特性。

图 3:运行中的简化REVISE算法:Kitty 如何通过改变属性来跨越决策边界。关于距离惩罚的正则化从左上到右下增加。图片作者。

讨论

虽然希望凯蒂的旅程为你提供了一些有用的直觉,但这个故事当然非常愚蠢。即使你的猫似乎暗示过她想成为狗,帮助她跨越那个决定界限也是很棘手的。有些属性是不可变的,或者很难改变,Joshi 等人(2019)在他们的框架中解释了这一点。他们提出的方法提供了一个简单而巧妙的方法来提供个人求助。与其担心黑盒的可解释性,为什么不简单地提供补救措施以防出错呢?

在某种程度上,这个想法有其优点。正如这篇文章所展示的,REVISE简单易懂,易于应用。它可能是一个非常有用的工具,在许多现实世界的应用程序中提供个人资源。正如我们的简化版REVISE的实现所展示的,研究人员也应该发现进一步开发该方法并使其适合特定用例相对容易。例如,这里的更简单的版本可能在维度相对较小的设置中有用,并且可以合理地对属性的分布进行建模,而不需要生成模型。

尽管如此,你可能想知道:如果最初的分类器是基于定义不良的规则和代理,那么REVISE到底有什么用?回到高中教师 Sarah Wysocki 的例子,决定教师评价的一个关键因素是学生的表现。意识到这一点,一些老师采取了人为夸大学生考试成绩的捷径。REVISE很可能已经提出了同样的行动方针。正如 Joshi 等人(2019 年)所证明的,REVISE的这一特性实际上可能有助于在释放决策系统之前发现它们的弱点(关键贡献 3)。

尽管如此,上面的例子也证明了像REVISE这样的方法,尽管它们可能有用,但它们倾向于为非常特殊的问题提供解决方案。在现实中,数据驱动的决策系统经常会遇到许多不同的问题,因此对可信人工智能的研究需要从各个角度解决这个问题。几个地方开始包括处理固有偏见的数据的问题,提高临时和临时模型的可解释性,以及围绕因果关系启发的人工智能继续努力。

参考

[1] Joshi、Shalmali、Oluwasanmi Koyejo、Warut Vijitbenjaronk、Been Kim 和 Joydeep Ghosh,关于黑箱决策系统中现实的个人追索权和可操作的解释 (2019),arXiv 预印本 arXiv:1907.09615。

[2]奥尼尔,凯茜,数学毁灭的武器:大数据如何增加不平等并威胁民主 (2016),皇冠

[3]乌斯顿、伯克、亚历山大·斯潘赫和刘洋,线性分类中的可诉追索权 (2019),《公平、问责和透明度会议论文集》,第 10–19 页

强占

在我的博客文章中,我的目标是从头开始实现有趣的想法,即使有时这意味着事情需要进行某种简化。这种方法的好处是,这种经历在教育上是有益的——对我自己来说是如此,希望对读者也是如此。在这个中型出版物上,我将只附上线性分类器的注释代码和下面的REVISE。对于带有语法突出显示的代码,也为了体验一下其中的数学,请查看我的个人博客上的帖子。

线性分类器

线性分类通过具有铰链损失的随机梯度下降(SGD)来实现。linear_classifier函数输出一个 S3 类,这是在 r 中使用面向对象编程的常见方式。下面是分类器的printpredict方法。

REVISE(简体)

如上所述,我们正在研究 Joshi 等人(2019)提出的算法的一个稍微简化的版本。特别是,这里的方法没有结合可能性的阈值,也没有考虑不可变的属性。

revise函数被实现为上面创建的分类器类的方法。

原载于 2021 年 4 月 26 日https://pat-alt . github . io

产品分类图完成的归纳学习

原文:https://towardsdatascience.com/inductive-learning-for-product-assortment-graph-completion-a44306da5c42?source=collection_archive---------47-----------------------

这篇博客文章是在 2021 年 ESANN 大会上提交的一篇论文的简短摘要,这篇论文是由人工智能研究所和比萨大学合作完成的。如果你觉得这很有趣,并想阅读全文,这里的是会议记录中文章的链接,这里的是原始论文的扩展期刊版本。

介绍

全球零售商拥有包含数十万种产品的分类,这些产品可以通过几种类型的关系联系在一起,如风格兼容、“一起购买”、“一起观看”等。图是分类的自然表示,其中产品是节点,关系是边。像样式兼容性这样的关系通常是通过手工过程产生的,因此不会均匀地覆盖整个图形。我们建议使用归纳学习来增强时尚分类的图形编码风格兼容性,利用包含文本描述和视觉数据的丰富节点信息。然后,我们展示了所提出的图增强如何在对图稀疏性影响较小的情况下显著提高直推任务的性能。

方法学

图形神经网络是处理图形数据的最新技术[1]。我们建议使用归纳学习来增强时尚分类的图形编码风格兼容性,利用包含文本描述和视觉数据的丰富节点信息。

与假设所有节点在训练时间都存在的直推式链路预测相反,感应式链路预测旨在预测新的、未观察到的节点的链路。然而,感应链路预测通常在现有节点上获得较低的性能。我们提出的方法是使用归纳链接预测来丰富新链接的图形,然后在新图形上训练直推模型,以最大限度地提高链接预测性能,这样可以两全其美,如图 1 所示。

图 1: 我们的方法由三个阶段组成:原始图上的归纳学习、图的丰富化和丰富图上的直推学习。

对于归纳学习(步骤 1),我们考虑 DEAL [2],一种利用两个编码器的架构,一个面向属性的编码器编码节点特征,一个面向结构的编码器编码图的链接,以及一个对齐机制来对齐两个嵌入向量之间的最大相似性。在图丰富阶段(步骤 2),如果满足两个条件,我们向图中添加新的链接:根据归纳链接预测的存在概率高于阈值,并且节点度低于预定值,以避免添加太多链接。最后,执行直推式链接预测(步骤 3)以学习丰富图的结构,其中风格兼容关系已经传播到整个图。

实验

我们的算法在两个专有的 H&M 数据集上进行验证,即包含男装和女装时尚项目的男性和女性,以及一个公共数据集,来自亚马逊的计算机数据集[3]。表 1 中报告了该图的性质,以及对该图的归纳丰富结果的预期。

表 1: 本文使用的数据集,其中*表示丰富后的图形。

结果和结论

在表 2 中,我们可以看到,对于所考虑的所有三种不同类型的 GNN,即 SAGE[4]、GCN [5]和 GAT[6],丰富的图如何显著提高链路预测性能。这种性能上的改进可以解释为丰富过程有效地完成了原始图,使模式更规则、更通用,因此更容易学习。

表 2: 数据集链接三种众所周知的算法的预测精度,其中*表示富集后的图。

参考

[1]d . BAC 丘、F. Errica、A. Micheli 和 M. Podda。图形深度学习的温和介绍。神经网络,2020。

[2]郝耀东、曹晓东、方耀东、谢晓东和王。只有属性信息的节点的归纳链接预测。IJCAI,2020。

[3] J .麦考利、c .塔吉特、q .史和 a .范登亨格尔。基于图像的风格和替代品建议。SIGIR,2015 年。

[4]汉密尔顿、应和莱斯科维奇。大型图上的归纳表示学习。NeurIPS,2017。

[5]基普夫和韦林。基于图卷积网络的半监督分类。,ICLR 2017。

[6]佩利科维奇、库库鲁勒、卡萨诺瓦、罗梅罗、莉雅和本吉奥。图形注意力网络。,ICLR 2018。

基于物联网的深度学习工业电机故障分类

原文:https://towardsdatascience.com/industrial-motor-fault-classification-using-deep-learning-with-iot-implications-fd36ddc8ad5b?source=collection_archive---------9-----------------------

使用真实数据和应用人工智能(AI)制定预测性维护策略

米卡·鲍梅斯特在 Unsplash 上的照片

**目的 **

以下作品仅用于教育目的,不得用于商业用途。

我不断挑战自己,发展自己在工程、数据科学、沟通和商业敏锐度方面的技能。我喜欢从事测试我知识的项目,将我推出舒适区,并允许我表达我的创造力。我承担了这个个人项目,通过使用与电动马达操作相关的真实世界数据集来进一步发展我在机器学习方面的经验。

我学到了很多——现在我与读者分享我的学习,利用媒体平台增加我的公共作品组合,并发展我的沟通技巧。

所有的源代码都可以通过我的GitHub上的一个资源库公开获得。

享受!

问题陈述和机会

作为一名新的电气工程毕业生,我的第一个任务是诊断和排除一台停止工作的感应电机。第一步是检查故障的症状并确定故障的根本原因。为了做到这一点,我需要一个特定的诊断工具和一个详细的测试程序。不幸的是,诊断工具在短期内不可用,测试程序需要至少 3 周才能执行。

我一直在思考这个场景,我把它归类为一个机会,来改善当前的电机诊断和维修标准。我的假设是,有一个更快、更具成本效益的解决方案来对电机故障进行分类,并减少操作停机时间。

机器学习项目

工业电机是现代经济的主力。在所有主要行业中都可以找到它们,如发电、石油和天然气、采矿和制造。工业电机的故障以及长时间的诊断和维修过程会导致生产价值的损失。

在本文中,我研究了实施人工智能(AI) 解决方案的可行性,以诊断电机故障并向系统操作员实时报告。这种解决方案将减少工程师和技术人员诊断故障所需的时间,并因此减少操作中的停机时间。

方法论

本实验的范围是评估开发能够对不同电机运行状态进行分类的机器学习模型的可行性。我将开发两个机器学习模型:

  • 二进制分类器检测故障何时发生
  • 多类分类器对故障类型进行分类

领域理解和数据采集

为了开发能够对电机故障进行分类的机器学习模型,必须有足够的数据来训练该模型。

在这个实验中,我使用了来自机械故障数据库的公开数据[1]:

“该数据库由 SpectraQuest 的机械故障模拟器(MFS)校准-平衡-振动(ABVT)上的传感器获得的 1951 个多变量时间序列组成。1951 包括六种不同的模拟状态:正常功能、不平衡故障、水平和垂直错位故障以及内外轴承故障。”

第一步是构建一个数据采集模块,能够从数据源获取数据,并将数据存储在数据结构中以供处理。数据被组织在一批文件夹中,按操作条件标记为,在逗号分隔值(csv) 文件中按转速排序。每个 csv 文件都是一个训练实例。

INPUT_DATA_DIR = get_project_root() / Path('data_acquisition/data')NORMAL_FILE_NAMES = glob.glob(str(INPUT_DATA_DIR)+'/normal/*.csv')
HORI_MIS_FILE_NAMES = glob.glob(str(INPUT_DATA_DIR)+'/2.0mm/*.csv')
IMBALANCE_FILE_NAMES = glob.glob(str(INPUT_DATA_DIR)+'/25g/*.csv')

对于这个项目,我将重点关注三种不同的操作条件:正常不平衡水平错位。正常和不平衡数据集各包含 49 个训练实例,水平未对准数据集包含 47 个训练实例。每个训练实例包含测量旋转速度的编码器信号、六个加速度计信号:两个轴向信号、两个切向信号和两个径向信号,以及来自麦克风的可听见的噪声信号。信号以 50,000 Hz 的速率采样 5 秒钟;因此,每个信号是具有 250,000 个样本的时间序列。

为了更好地理解可用数据,请听听每种条件下的电机性能。

你能听出区别吗?

我的假设是,这些声音信号,以及从加速度计收集的信号,足以开发一个能够对不同操作条件进行分类的人工智能模型。

数据处理和探索性数据分析

在我们可以将数据输入机器学习算法之前,我们需要执行一些初步的数据处理。让我们来看看一个训练实例在正常操作条件下所有时间序列信号的曲线图。

正常操作下一个训练实例的所有传感器数据的时间序列图

对数据和数据图的初步分析揭示了两个关键观点:

  • 由于高采样率,存在大量的数据点
  • 这些信号不在同一个范围内

这两种见解都会对机器学习算法产生影响:

  • 太多的数据点将需要更长的模型训练时间
  • 不同的尺度会扭曲机器学习模型的结果

数据重采样

首先,我们应该以较低的频率对数据进行重新采样,以减小每个训练实例的大小,从而加快训练算法的速度。为了确定重采样率,让我们使用 【快速傅立叶变换】 来分析信号的频谱:

采样率为 50,000 Hz 时正常工作条件下的频谱

频谱在 25,000 Hz 的奈奎斯特频率处截止。FFT 显示大部分高信号强度频率位于较低的频率带宽(0Hz-5,000 Hz)。在 20,000 Hz-25,000 Hz 处存在相对高强度频率的第二带宽,并且在 5,000 Hz 和 20,000Hz 之间存在死区。以丢失高频带宽信息为代价,决定以 500 Hz 的较低速率对数据进行重新采样。较低的抽样率将把时间序列数据点的数量从 250,000 减少到 2,500,减少了两个数量级;因此,大大减少了模型训练时间。

正常操作条件下 500 Hz 重采样率的频谱

当在相同转速下对比时,重采样信号的频谱显示了操作条件的特定特征:

重采样率为 500 Hz 时水平失调运行条件的频谱

重采样率为 500 Hz 时不平衡运行条件的频谱

数据缩放

下一个数据处理步骤是将信号重新调整到一个共同的尺度。该函数将确保机器学习模型不会扭曲最终结果。

正常操作下一个训练实例的所有传感器数据的时间序列图:缩放和重新采样

频域

数据处理流程的最后一步是将信号从时域转换到频域。这种转换是通过使用 FFT 变换数据来实现的。将数据转换到频域的好处是:

  • 通过仅使用正频谱,每个训练集的行数从 2,500 减少到 1,250;因此,减少了模型训练时间
  • 每个操作条件的频谱具有更多指示性特征;因此,提高了模型精度

训练/测试分流

最后一步是留出一部分数据在最后用于模型验证。这就是所谓的测试集

构建深度学习模型

在开始这一部分时,我将引用一个关于人工智能、机器学习和深度学习之间关系的有用信息图。

https://medium . com/@ harish _ 6956/what-is-machine-learning-deep-learning-7788604004 da

由于输入数据遵循一个序列(频域),我将使用一个 递归神经网络(RNN) 架构,这是一个深度学习架构。具体来说,我使用的是【LSTM】的长短期记忆架构。

使用 Python 中的 TensorFlow 库实现 LSTM 模型非常简单。我将从最简单的架构开始,它包含两层:LSTM 输入层和带有可配置激活功能的密集输出层。

对于二元分类模型,我使用一个 sigmoid 激活函数和一个二元交叉熵损失函数来训练模型。

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm (LSTM)                  (None, 100)               43600     
_________________________________________________________________
dense (Dense)                (None, 1)                 101       
=================================================================
Total params: 43,701
Trainable params: 43,701
Non-trainable params: 0

该模型在 116 个训练实例上进行训练,在 100 个时期中具有 20%的验证保留集。该模型在训练和验证数据上达到 100%的准确度分数。

序列分类 RNN(二元)的模型精度

对于多类分类模型,我使用一个 softmax 激活函数和一个稀疏分类交叉熵损失函数来训练模型。

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm (LSTM)                  (None, 100)               43600     
_________________________________________________________________
dense (Dense)                (None, 3)                 303       
=================================================================
Total params: 43,903
Trainable params: 43,903
Non-trainable params: 0

该模型在训练和验证数据上获得了 100%的准确度分数。

序列分类 RNN(多类)的模型精度

模型验证

模型在后处理测试集上得到验证。测试集包含 29 个实例,两个模型都能够准确地对所有 29 个样本进行分类,达到 100%的测试分数。

多级分类的实际值和预测值之间的比较

总结与未来工作

最终的二元和多类分类模型被证明在准确识别电机故障和按类型分类故障方面是成功的。

一些重要的经验教训:

  • 我 85%的时间花在了数据处理和探索性数据分析阶段。
  • 最终的模型,虽然听起来非常复杂(DL,RNN,LSTM),却是最容易建立的部分。
  • 我利用我在电机领域的行业和学术经验,以及我在电气工程方面的背景,制作了一个成功的模型。例如,我最初使用时域作为模型的输入,它产生的训练和验证分数并不比随机抽样好(66%)。直到我执行频域变换,我才看到模型的显著改进。
  • 我对学习模式做了很小的调整;最显著的收益来自数据处理。

未来的工作

本项目使用的数据是可用数据的子集。总共有六种可用于分类的状态:正常、不平衡、水平未对准、垂直未对准、悬挂下轴承故障和悬挂轴承故障。此外,一些状态具有子状态,例如,水平错位可以通过以毫米为单位的错位量来分类:0.5 mm、1.0 mm、1.5 mm 和 2.0 mm。更有用的模型是包含所有故障条件并且可以通过其条件的极端来细分每个故障的模型。

工业物联网含义

正如我的介绍中所说,这个项目的目的是为了教育目的,而不是商业用途。然而,想想用例的结果对我们的工业世界的潜在影响是令人兴奋的。工业环境中互联技术的实施已经发展到包括更快的连接网络、云计算系统和大数据分析。我设想我的工作成果可以得到显著的改善、增强,并整合到跨各种行业的更大的资产管理战略中,以改善运营、效率、可靠性和安全性。

结束语

感谢您花时间阅读我的文章。我希望它对你有一些价值,并且你能够学到至少一条新的信息。我希望继续发表类似的文章,并感谢你能提供任何建设性的批评。

如需任何未来出版物,请订阅我的 Medium 个人资料,并在LinkedIn上添加我。**

访问我的代码库,在那里你可以找到这个项目和我完成的其他项目的所有源代码,请检查我的GitHub**

谢谢

米兰科尔季奇

参考文献

[1]机械故障数据库,机械故障数据集 (2021),Web

商业高级分析的工业革命设计原则课程

原文:https://towardsdatascience.com/industrial-revolution-design-principles-lessons-for-commercial-advanced-analytics-3c10b1368454?source=collection_archive---------22-----------------------

每天都有新的工具和方法出现,那么您的分析团队如何保持警惕呢?关于工业革命四大支柱的思考:标准化模块化自动化、可扩展性

作者图片

纵观历史,我们已经经历了三次工业革命,许多人认为我们正在经历第四次。从第一次煤和蒸汽革命开始;第二次是大规模生产,第三次是计算机,最近的第四次是人工智能和物联网,人类用汗水和泪水,有时甚至是鲜血吸取了许多教训[1]。随着“工业 4.0”即将到来,将以前的经验和最佳实践应用到日常工作中不仅对我们个人,而且对组织都至关重要。

对于商业高级分析领域的许多人来说,“工业 4.0”可以简化为将来自各种来源的数据汇集到一个仓库或数据湖中,然后部署必要的分析、人工智能、机器学习来生成可操作的见解的过程。也就是说,任何分析相关团队的另一部分工作都是准备文档、吸纳同事、获得支持以及与利益相关方打交道。

在这篇文章中,我将讨论我对 4 个工业革命设计原则的概念的想法:标准化、模块化、自动化和可伸缩性;它们的相关性如何,以及如何将它们整合到任何分析组织的日常工作中。

目录

标准化
模块化
自动化
可扩展性

标准化

照片由 Unsplash 上叫我弗雷德

这是什么?

标准化,顾名思义,就是使某物符合标准的过程。用技术术语来说,它意味着在各方(例如:公司、用户、利益集团、标准组织和政府)一致同意的基础上实施和开发标准[2]。

从以前的工业革命开始,由于对高精度机床和可互换零件的需求,标准化就变得非常重要。由于某些基本标准,企业可以避免冲突和重复劳动。

它是如何关联的?

每个组织都应该有自己的分析产品技术标准:从数据格式结构、流程实现到代码语法。应该注意的一些标准化示例:

**Data** - Is this data useful or redundant?
- Are these **data entries** pointing to the **same** thing?
- Is it "cold" or "hot"? Where to store it?
- How should we structured it into a **single format** and make it **consistent**?
- How is the **documentation** process and how frequent is it update?
- If this is used by many platforms, then is there any requirements for **input**/**output flows**?**Processes
-** Are these steps useful or redundant? 
- Can we make it **easier** to onboard/outsource/implement?- Can we create a **set of rules** of how to run this ABC process?
- Can we reduce the **deviations**?
- Have we implemented "**best practices**" from similar processes?**Metrics** - Have we all agree on this metric / KPIs?
- Can we **quantify** this metric with good clarity?
- Can we use these KPIs on this project / process?
- How can this metric measures impact on sales / customer satisfaction / engagement rate...etc?**Tools & Platforms** - Are we using the same tools/platforms?
- Do we have the same versions of the softwares / codes?
- Can this new vendor's tool **integrate** to our ecosystem smoothly?
- Can the change processes be more **transparent**?

拥有标准将有助于分析团队从业务利益相关者那里获得更多的信任和支持,因为它显示了专业性和透明度。

从长远来看,在早期阶段建立具体的标准肯定会有所帮助,特别是在处理不同平台之间相互通信的挑战方面(公司倾向于在业务中使用不同的供应商,并且不是所有的供应商都能顺利集成到生态系统中)。标准化还有助于我们更好、更快地识别不一致,这有助于组织的决策过程。在知识转移方面,标准化将加速入职、外包和实施流程。最后,拥有标准将有助于在技术专家和商业利益相关者之间建立更好的桥梁,因为它显示了专业性和透明度

模块化

沃洛德梅尔·赫里先科Unsplash 上的照片

这是什么?

在第二次工业革命中,亨利·福特将他从芝加哥一家屠宰场获得的灵感付诸实践,从而使美国工业发生了革命性的变化:大型生产工厂;标准化互换零件;以及移动装配线。一旦标准化达到一定程度,模块化就可以正式启动了。

模块化设计是一种将一个系统细分为模块的设计原则,这些模块可以独立创建、修改、替换或与其他模块或不同系统之间交换。[3].

它是如何关联的?

任何有编程经验的人(尤其是 OOP —面向对象编程)一定都知道模块化的概念:代码放入函数和类中;然后只在需要的时候被召唤。在高级分析项目中,模块化可以在许多机器学习工作流工具中看到,如 sklearn workflow、apache airflow、kedro、Luigi...仅举几个例子。这些工具使专家能够监督开发过程并有效地监控项目。虽然有很多工具可用,但通常包括这 4 个主要步骤: 数据收集数据预处理培训和细化部署** 。在这些步骤中,代码应该被分成小模块,这些小模块可以被修改、替换和交换,而不会破坏大的“管道”。

Kelly SikkemaUnsplash 上拍摄的照片

事实上,这个概念现在已经从技术方面发展到了产品管理方面。想想敏捷的概念:

  • 我们以 sprint 周期运行项目数周,从 POC(概念验证)开发一个原型
  • 在测试和收集反馈之后,我们旋转更多的周期来轻松地集成或替换产品的各个部分(当然是在模块中)
  • 有时,由于利益相关者的要求,我们不得不将产品的大部分从开发周期中剔除。这里模块化将帮助我们保持过程的健全:没有那些“大块”,产品应该运行良好,没有问题
  • 后来,当我们推出 MVP(最小可行产品)时,新功能可以以模块的形式很好地集成。

随着开发过程中业务方面的参与,模块化将有助于分析团队在利益相关者的要求和产品质量之间取得平衡。

自动化

大卫·莱维克Unsplash 上拍摄的照片

这是什么?

自动化是在最少人工干预的情况下,创造和应用生产和交付商品和服务的技术。自动化技术、工艺和过程的实施提高了以前由人类执行的许多任务的效率、可靠性和/或速度。[5]

它是如何关联的?

术语“自动化”源于古希腊词:αὐτόματος(autóMatos,“自动、任性”),正如定义所述,关键词是“最少的人工干预”。一旦从两大支柱 标准化模块化 中取得可持续的成果,企业就可以开始自动化其分析流程。自动化分析机制的复杂性各不相同,从将数据传输到预建模型的简单脚本,到执行 EDA(探索性数据分析)、功能增强、模型选择、测试和部署的全方位服务工具[6]。对于组织来说,即使是一个简单的经过良好调整的自动化分析管道也能带来巨大的好处。例如,从内部数据库收集数据以提供预测模型并将结果更新到交互式仪表板的管道可以大大减少工作量和运营成本。

即使是一个简单的经过良好调整的自动化分析管道也能为企业带来巨大的好处

公司可以使用机器人流程自动化(RPA)等工具开始他们的自动化之旅,这些工具用于标准化的流程,也称为“低级人工智能”,以不费吹灰之力产生“速赢”。我在“智能自动化”中写了一篇文章,其中深入讨论了 RPA 和数据科学之间的关系:

与此同时,高级分析团队在实现标准化模块化后,可以通过使用机器学习工作流工具部署模型并将其推送到云服务平台,开始自动化他们的产品(这里我使用了词语“”而不是“”),因为后者需要最后一个支柱:“”)**

可量测性

这是什么?

从商业角度来看,可扩展模式是一种随着在资本、劳动力和服务方面投入更多而看到回报不断增加的业务。不可扩展的商业模式作为小企业可能有利可图,但不能以经济的方式增长。

科林·沃茨在 Unsplash 上的照片

在计算机科学领域,彼得·洛辛和他的合著者在他们的书 电子商务 中,将可伸缩性定义为:“当系统负载增加时,具有多个可用处理器的系统调用尽可能多的处理器的能力,以及该系统被扩展的能力。”

有什么关联?

完成 标准化模块化自动化 三大支柱,并不意味着产品或流程已经“规模化”。为了能够创建生产级的高级分析产品,我们必须非常注意扩展方面。 Sigmoid Analytics [7]强调了在为企业扩展机器学习模型时的 5 个挑战如下(强烈推荐阅读该文章):

**1\. Complexities with data
2\. Engineering and deployment
3\. Integration risks
4\. Testing and model substance
5\. Assigning roles and communications**

虽然“扩展”分析产品主要局限于技术技能和基础设施,但在组织范围内“扩展”分析是另一个不同的挑战。

虽然扩展分析产品仅限于技术技能,但在组织范围内扩展分析是另一个不同的挑战。从麦肯锡的《脱离:扩展分析的秘密》【8】2018 年,尽管在分析方面进行了大量投资,但许多公司并没有像他们预期的那样捕捉到巨大的价值。原因是:虽然他们从一些用例中获得了小收益,但他们未能将分析嵌入组织的所有领域。该报告确定了许多使领先企业脱颖而出的驱动因素:首先是调整战略,建立正确的基础,获得正确的人才,为员工提供数据洞察力,以及最重要的最后一部分:将分析结果嵌入决策过程。为了实现规模分析,公司可以从以下方面入手,应用脱离领导者的经验:

  1. 首先,在公司业务战略的背景下,确定他们可以改进以产生价值的决策过程
  2. 然后,反向工作以确定影响决策的所需数据洞察类型
  3. 最后,在公司的支持下,获取人才和流程方面的数据和知识

虽然在工业革命的教训上可能有不同的思想流派,但我相信这四个设计原则:标准化、模块化、自动化和可伸缩性;将长期伴随我们,尤其是在工业 4.0 即将到来的情况下。

感谢阅读!如果你能留下回复,我会很高兴,我们可以进一步讨论这个话题。

放弃

本文中表达的所有观点都是我个人的观点,不代表我曾经、现在或将来隶属的任何实体的观点。

参考

[1]History.com 编辑(2019)。工业革命。[在线]历史。可查阅:https://www . history . com/topics/industrial-revolution/industrial-revolution【2021 年 1 月 20 日获取】。

[2]谢,z .,霍尔,j .,麦卡锡,I.P .,斯科特莫尔,m .,沈,L. (2016)。标准化努力:知识维度、搜索过程和创新成果之间的关系。技术创新,【在线】48–49,第 69–78 页。可在:https://www . science direct . com/science/article/pii/s 0166497215000929?通过% 3 di hub[2021 年 1 月 20 日访问]。

‌[3]维基百科贡献者(2021)。模块化编程。[在线]维基百科。可在:【https://en.wikipedia.org/wiki/Modular_programming 【2021 年 1 月 20 日进入】。

History.com 编辑]( 2009 年)。亨利·福特。[在线]历史。上市时间:https://www.history.com/topics/inventions/henry-ford【2021 年 1 月 20 日上市】。

[5]Techopedia.com。(2016).什么是自动化?—来自 Techopedia 的定义。[online]可从以下网址获得:https://www . techopedia . com/definition/32099/Automation #:~:text = Automation % 20 is % 20 创建% 20 和之前% 20 由% 20 人% 20 执行% 20。【2021 年 1 月 20 日获取】。

[6] ‌Stitch.(2021).通过自动化数据分析|整合资源提高数据团队的工作效率。[online]可从以下网址获得:https://www . stitch data . com/resources/Automated-data-analytics/#:~:text = Automated % 20 data % 20 analytics % 20 is % 20 the,automating % 20 thes % 20 data % 20 analytics % 20 processes。【2021 年 1 月 22 日获取】。

[7]西格蒙德分析法(2020 年)。机器学习模型规模化前需要准备的 5 个挑战——Sigmoid。[在线]乙状结肠。可从以下网址获取:https://www . sigmoid . com/blogs/5-challenges-to-be-prepared-for-scaling-machine-learning-models/【2021 年 1 月 23 日获取】。

[8]比松,p .,霍尔,b .,麦卡锡,b .和哈立德·里法伊(2018)。打破常规:扩展分析的秘密。[在线]麦肯锡&公司。可从以下网址获取:https://www . McKinsey . com/business-functions/McKinsey-analytics/our-insights/breaking-away-the-secrets-to-scaling-analytics【2021 年 1 月 23 日获取】。

利用 Amazon SageMaker Studio 实现 ML 平台的工业化

原文:https://towardsdatascience.com/industrializing-an-ml-platform-with-amazon-sagemaker-studio-91b597802afe?source=collection_archive---------6-----------------------

在企业中推广 Studio 的步骤和注意事项

通常在大型企业中,ML 平台管理员需要平衡治理和合规性要求与 ML 团队快速访问工作环境的需求,以及实施其解决方案的脚手架。

Unsplash 上的 CHUTTERSNAP 拍摄

用 SageMaker 的话来说,这就是用工作室访问安全、治理良好的工作环境,用管道提供模板化的 MLOps 项目。

SageMaker 提供了现成的,在这篇文章中,我将分享 ML 平台团队如何组织、标准化和加速他们的供应。

包含相关人物角色的 ML 工作流示例(作者图片)

演练概述

我们将分三步解决这个问题:

  • 我们将首先建立多帐户基础和自助服务供应,以便 ML 团队可以在几分钟内访问批准的工作室环境。
  • 然后,我们将了解如何管理 Studio 的日常工作。
  • 最后,我将展示如何使用 SageMaker 管道来启用模板化的 MLOps 项目。

先决条件

要关注这篇文章,请确保您:

  1. 像 DevOps 一样,MLOps 是文化、实践和工具的结合,而不仅仅是工具。确保您的企业拥有明确定义的 ML 运营模式和治理流程。MLOps 项目模板应该只是这些的技术实现。
  2. 熟悉 SageMaker 工作室的架构
  3. 采用多账户战略将在如何满足您的 ML 平台的治理、安全和运营要求方面发挥最重要的作用。确保您已经阅读了在 AWS 上建立安全的、治理良好的机器学习环境
  4. 熟悉 SageMaker 管道MLOps 项目模板

步骤 1:允许最终用户访问 Studio

首先,我们希望 ML 团队能够自行供应工作室笔记本电脑,这样,在几分钟内,他们就可以在批准的环境中开始工作。

这将是你的 ML 平台的 V1,一个你的团队可以努力的 sprint 1。

在项目开发帐户中设置工作室域

这篇文章中,我分享了一些例子场景和相应的账户模式,你可以采用它们来实现 ML 项目。

当一个新的 ML 项目出现时,您可以创建一组专用于它的帐户,并在 Project Dev 帐户中找到 project team Studio 域。

使用公司数据进行项目试验的示例帐户模式。 ( 图片来自博文)

从项目开发帐户中的 Studio 域,团队可以连接到团队共享服务帐户中的团队范围的存储库,并共享诸如代码、容器和 ML 模型之类的资产。由于工作负载 OU 中的帐户实现了公司防护栏,ML 项目团队可以通过安全网关安全地访问数据湖帐户中的数据。在此项目期间开发的工程特征可以提升到数据帐户中的特征存储中以供以后使用。

启用经批准的工作室资源的自助供应

您可以使用 AWS 服务目录启用已批准的 Studio 域和用户配置文件的自助供应。项目团队可以从团队共享服务帐户或项目开发帐户访问服务目录组合。

参见启用 Amazon SageMaker Studio 资源的自助供应并了解如何为 Studio 创建服务目录组合。

作者图片

工作室设置的主要注意事项

级别:

  • 用户笔记本电脑的网络在 Studio 域级别进行管理。参见使用私有 VPC 保护亚马逊 SageMaker Studio 连接了解更多详情。
  • 需要为域分配一个默认的 IAM 执行角色。您可以选择对其所有用户简档使用此默认角色。
  • MLOps 项目模板是 Studio 通过 boto3 访问的服务目录产品,在启用权限后在 AWS 服务目录控制台可见。您可以运行一个 Lambda 函数来启用它们,如本例中的所示。

用户简档级别:

  • Studio 中的认证可以通过 SSO 和基于 IAM 的方法来完成。企业可能有一个现有的身份提供者,它在用户访问 AWS 控制台时联合用户。如果是这种情况,您可以使用 IAM 为每个联合身份分配一个 Studio 用户配置文件。请参见为团队和组配置 Amazon SageMaker Studio 完全资源隔离中的将策略分配给 Studio 用户部分,了解更多详细信息。

用户使用 IAM 登录 SageMaker Studio 的认证流程(图片由作者提供)

  • IAM 执行角色也可以分配给每个使用配置文件。使用 Studio 时,用户承担映射到其用户配置文件的角色,这将覆盖域默认执行角色。这可以用于 ML 项目团队中的细粒度访问控制。例如:把数据科学家和 ML 工程师在项目中能做的事情分开。
  • 成本跟踪可以在账户层面进行,因为每个项目都有专门的账户。AWS 具有内置支持,可在 ML 平台中整合和报告您的整套账户的成本。如果您需要在用户级别跟踪成本,您可以将成本分配标签应用于用户配置文件。例如:标签可以由用户 ID 和项目 ID/成本中心组成。

现在,在您的 ML 平台中,您应该拥有多帐户基础和经批准的工作室环境的自助供应。您的 ML 团队现在可以访问批准的工作室环境,并使用预建图像在笔记本上工作。

第二步:日常管理工作室

在这里,我们深入探讨 ML 平台团队可能应用于其工作室环境的常见定制。

来源: SageMaker 文档

这可能是一个 sprint 2,但是请记住,定制可能代表您的平台团队的持续努力,因为项目团队的需求会随着时间的推移而发展。

使用 IAM 策略管理用户权限

当用户打开 Studio 时,他们承担与其用户配置文件相关联的执行角色,因此需要控制该角色的权限。

您可以简化权限管理,并对参与项目的所有用户配置文件使用相同的 IAM 角色。这是可行的,因为项目已经在帐户级别被隔离。或者,如果 ML 团队有需要不同权限的角色,您可以使用多个 IAM 角色。

SageMaker 提供了特定于服务的资源、动作和条件上下文键,以便与 IAM 一起使用。另请参见本页,了解对其他 AWS 服务的管理权限

项目工作流程示例。用户访问他们的 Studio 环境,并在 SageMaker 中手动启动作业,以准备数据、训练和托管模型。(图片由作者提供)

至少,你的 ML 团队想要:

  • 能够启动 SageMaker 处理、培训、超参数调整和自动驾驶作业。
  • 对 SageMaker 控制台页面具有读取权限,以监控作业状态。
  • 他们的容器发送给 stdoutstderr 的任何东西都会被发送到 Amazon CloudWatch 日志。因此,他们将需要对 CloudWatch 日志的读取权限来调试作业和端点。

规模化管理 IAM 权限

在某种程度上,您可能会让数百个 ML 团队在您的平台上工作,并且需要一种方法来扩展权限管理。通过 CI/CD 管道实现流程自动化会有所帮助。

在 CI/CD 管道中嵌入 cfn-policy-validator 工具。(图片来自博文

更多详细信息,请参见使用 IAM 访问分析器验证云信息模板中的 IAM 策略。

在 Studio 中限制实例类型

您可能希望限制 ML 团队在 Studio 中可以使用的实例类型,以控制成本。例如:默认情况下只允许某些 CPU 实例,需要时允许 GPU 实例。

为此,您可以调整用户配置文件的 IAM 权限。特别是,您需要对执行角色限制的是sagemaker:CreateApp权限,而sagemaker:InstanceTypes是要使用的条件键。

以下是拒绝除 t3 实例之外的所有 SageMaker 实例类型的策略示例:

使用生命周期配置定制工作室环境

Studio 支持生命周期配置。它们提供了一种自动地、可重复地将定制应用于 Studio 环境的方法,包括:

  • 安装自定义软件包
  • 配置非活动笔记本应用程序的自动关闭
  • 设置 Git 配置

参见使用生命周期配置定制 Amazon SageMaker Studio了解更多详情。

自动化 SageMaker Studio 自定义图像的设置

除了在预构建映像中提供的库之外,您的 ML 团队还可以使用库来运行他们的笔记本。Studio 允许您创建包含他们最喜欢的库的容器,并将它们作为自定义图像附加到他们的域中。

您可以为自定义映像实现简单的连续交付,以自动化该过程。参见自动化 SageMaker Studio 定制图像的设置了解更多详情。

作者图片

您甚至可以将其打包为服务目录产品,以便按需访问。

在您的服务目录组合中添加更多产品

随着时间的推移,您可以在服务目录中添加更多产品,并使 ML 团队能够在其项目中做更多工作。

以下是您的团队可能需要的产品示例:

  • 亚马逊云 9 环境。除了朱庇特之外。
  • 容器映像构建器管道。用于构建 SageMaker 作业中使用的 docker 容器的代码 repo + CI 管道。流水线可以对图像进行林挺和安全扫描。
  • SageMaker 特征店中的特征组。
  • 亚马逊 EMR 集群用 Studio 的 Spark 处理数据。
  • 亚马逊 EKS 集群
  • 任何通过基础设施即代码定义的东西:)

步骤 3:使用 SageMaker 管道启用 MLOps 项目

ML 团队可能需要工作流程编排、模型注册和 CI/CD 的脚手架,以减少运行端到端 MLOps 项目的工作量。 SageMaker Pipelines 满足了这一需求。

在 sprint 3 中,您可以打包 MLOps 项目模板,并允许 ML 团队通过服务目录自行配置它们。

用于构建、培训和部署模型的 MLOps 项目模板示例。(图片来自博文)

为跨客户部署构建 MLOps 项目模板

对于 MLOps,除了 ML 团队可以访问的项目开发帐户之外,您还可以创建项目预编程和项目生产帐户。这将在部署的操作阶段之间提供高级别的资源和安全隔离。参见账户模式 3 此处,以及在 AWS 上构建安全的企业机器学习平台了解更多详情。

您可以用来生产 ML 项目的客户布局示例。(图片由作者提供)

您可以从头开始创建自定义项目模板,或者修改 SageMaker 提供的模板。

如果您不确定从哪里开始,您可以在导入的服务目录产品组合中找到预构建的 MLOps 模板。你可以把它们作为自己制作的基础。(图片由作者提供)

您的 MLOps 项目模板需要位于与团队共享服务/自动化帐户共享的服务目录组合中。启动后,它将在该帐户中创建代码仓库、跨帐户 CI/CD 管道和工件存储。ML 团队可以使用跨帐户 IAM 权限从项目开发帐户访问这些内容。

在您的 MLOps 模板中使用第三方工具

您的企业可能有标准化的代码仓库和 CI/CD 工具。

以下是您可以在 MLOps 项目模板中完成的集成示例:

您甚至可以构建模板来解决重复出现的 ML 用例。

结论

在这篇文章中,我分享了 ML 平台团队如何让分布式 ML 团队使用 SageMaker Studio 交付他们的项目,以及这样做的关键考虑。

该方法基于多帐户基础和 AWS 服务目录,允许自助供应经批准的 Studio 环境和 MLOps 项目模板。

更进一步,了解阿斯利康如何在 AWS 上构建了一个工业化的 ML 平台,为数百名科学家简化药物研发、临床试验和患者安全。

机器学习中的工业与学术界

原文:https://towardsdatascience.com/industry-vs-academia-in-machine-learning-3e304033d3f5?source=collection_archive---------3-----------------------

我是如何做出决定的

Unsplash 上的路博宣礼塔拍摄的照片

选择职业本身就很难。与利润丰厚的行业工作相比,博士学位需要 5-6 年的时间,你会对这种可能性感到惊讶。我在本科和硕士毕业后也处于类似的位置(两次都是)。

如果你知道我的职业道路,我很幸运地在大二的夏天被介绍到研究中,在那里我从事半监督关系抽取。后来,在进入研究生院之前,我在一个研究实验室做全职工作。这让我得以一瞥全职研究员/博士生的生活。

但尽管有研究经验,我还是在硕士毕业后加入了微软(我目前在那里工作)。做决定的过程是乏味的,因此我最终写下了我的想法。我强烈建议将这篇文章作为一种观点(以及我如何和为什么做出这个决定的更多信息),并在最终确定你的观点之前与工业界和学术界的许多人交谈。

人工智能发展水平

在学术界和工业界全职工作后,我意识到的一件事是

在工业界或学术界,你可以从事令人兴奋的工作,是人工智能革命的一部分。现在的问题是你想在哪个层次上发展。

你想把一个古老的基于规则的系统移植到 ML/DL 模型上吗?或者将现有的 ML 回归模型扩展到更先进的水平?或者你可以致力于更基本的问题,并尝试回答一些问题,这些问题将有助于在未来 5-10 年内(显然取决于应用)而不是立即建立系统。我试着通过问自己以下问题来回答我想在哪个‘提升水平’上努力~

一个研究问题对你来说有多重要?

工业研究主要是面向产品的

除非你是在纯研究组(刚读完硕士甚至博士都很难进)。通常你有一个与产品相关的问题陈述,你试图找到如何解决它的相关工作。如果你在这个过程中发现了一些新奇的东西,你可能会把它出版。

业内大多数团体在他们的绩效评估过程中不考虑已发表的作品。所以基本上你自己要有内在动力。

如果你不执着于问题陈述,那么行业研究小组可能是一个不错的选择。

对我来说,我找到了一个积极发表文章的团体,其中大多数人都有博士学位。因此,我发现它非常适合我。

影响对你意味着什么?

ML 研究很有趣,但并不是所有的研究都有影响力。来看看数字吧~

arXiv 上与人工智能相关的出版物数量增长了 6 倍多,从 2015 年的5478 篇增加到 2020 年的34736 篇。数量肯定在增加,但我不确定的质量。

以下是 NeuriPs 论文每年被引用的图表。随着出版物数量的增加,你的出版物被引用的平均数量逐年减少。这意味着,如果你在 2017 年在 Neurips 发表文章,你的平均引用次数或使用你作品的人数将是 4.6。这些数字在我看来相当可怕。

我知道有一些特别的论文,平均引用率并不是衡量一篇论文价值的最好标准,但至少是对你的影响的一个大概的评估。

有一些特殊的贡献(实际上推动了该领域的发展),但也有很多因素促使我写这样的论文(其中一些是顾问、我所在的研究实验室、研究领域和我博士期间的良好心理健康)。

行业转变

2019 年,65%的北美人工智能专业毕业博士进入了行业——高于 2010 年的 44.4%,突显出行业开始在人工智能发展中发挥更大的作用。

当我作为一名应用科学家在亚马逊工作时,我团队中的所有人都是博士。随着我和他们的交流越来越多,我意识到我可以做类似的工作。

在过去的几年里,人工智能发展的热潮是惊人的。要制造出伟大的产品,有很多工程要做,这需要阅读论文和思考应用它们的用例的技能,或者你有一个用例,阅读论文就能解决问题。

事实是,并不是每个人在获得机器学习博士学位后都只是做研究。

获得博士学位后,如果我在一个和现在类似的团队工作会怎么样?经历整个过程在当时没有任何意义。

学术界很难

这里实话实说吧——学术很难。

  • 不可能进行团队变更,或者至少不可能像行业中那样频繁而容易地进行团队变更
  • 5-6 年的高度承诺。
  • 好的研究是极其困难的,需要耐心。
  • 好的研究我认为高度依赖于许多其他因素,而不仅仅是你努力工作——最重要的是你的导师和你与他们的兼容性。我见过很多聪明人对他们与顾问的关系现状感到不开心和紧张。处于类似的位置是我最大的恐惧。
  • 津贴和报酬——感觉这个世界仍然不尊重研究人员。大学没有退休计划,没有股票津贴,甚至不能评论为什么博士工资低。不确定这种情况什么时候会改变,但当时我不想成为这样一个系统的一部分。

尽管有这些因素,我还是非常欣赏在学术界工作的人。我理解对新奇想法的追求和对基本问题的研究。当你追根究底的时候,我能理解智力模拟!

学术界的支持者

我仍然考虑回到学术界,特别是当我在日常工作中不得不做一些平凡的任务时(欢迎加入工业界)。作为一名博士,你从事的工作有很多好处

  • 拥有你的作品——你的论文是你的,会以你的名字被引用。如果所有权是你所追求的,那么在大公司里,有 100 或 1000 人在开发一个产品,这是非常困难的。
  • 智力模拟——我相信这就是人们攻读博士学位的原因。发现事物和回答未回答问题的乐趣。

结论

最后,一切都是关于令人兴奋的话题。不管是生产还是研究。我不知道我是否能拿到博士学位。但是如果我做了,我肯定会准备得更好。工业将会给添加非常需要的观点,什么是重要的和什么是重要的问题。

用 Python 对分类数据进行推理

原文:https://towardsdatascience.com/inference-for-categorical-data-9f3c6034aa57?source=collection_archive---------28-----------------------

用 Python 实现大学统计

介绍

在一系列的每周文章中,我将会涉及一些重要的统计学主题。

目标是使用 Python 来帮助我们获得对复杂概念的直觉,从经验上测试理论证明,或者从零开始构建算法。在本系列中,您将会看到涵盖随机变量、抽样分布、置信区间、显著性检验等主题的文章。

在每篇文章的最后,你可以找到练习来测试你的知识。解决方案将在下周的文章中分享。

迄今发表的文章:

像往常一样,代码可以在我的 GitHub 上找到。

卡方分布

让我们从定义一个标准的正态分布随机变量(RV) X_1 开始。

为了定义我们的第一个卡方 RV,我们从我们的标准正态分布 X_1 中取样并对结果求平方。因为我们取一个标准正态分布变量的和,所以我们将卡方分布的自由度定义为 1。为了定义具有 2 个自由度的卡方 RV,我们遵循相同的想法。这次我们从两个独立的标准正态分布 RVs 中取样,取各自样本的平方,最后对结果求和。

from scipy.stats import norm, chi2
import matplotlib.pyplot as plt
import math
import numpy as np
import seaborn as sns
from scipy import stats
import tabulate
import pandas as pd
from IPython.display import HTML, display
import tabulatemu = 0
variance = 1
sigma = math.sqrt(variance)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
sns.lineplot(x = x, y = norm.pdf(x, loc=mu, scale=sigma));

图 1:标准正态分布的概率密度函数。

norm_dist = stats.norm(0, 1)

x1 = norm_dist.rvs(size=100000)**2
x2 = norm_dist.rvs(size=100000)**2
x3 = norm_dist.rvs(size=100000)**2

x = [x1, x2, x3]

_, ax = plt.subplots(1, 3, figsize=(18, 7))

f = np.zeros(100000)
for i in range(3):
    x_ = x[i]
    f += x_

    ax[i].hist(f, 60, density=True, label=f'Sum of {i+1} standard Gaussian RV')

    d = np.arange(0, 10, .05)
    ax[i].plot(d, stats.chi2.pdf(d, df=i+1), color='r', lw=2, label='Chi-Square dist.')
    ax[i].set_xlim(0, 10)
    ax[i].set_title(f'Chi-Square dist. with df={i+1}')
    ax[i].legend()

图 2:来自平方标准正态分布(正态分布的总和等于自由度的数量)的样本直方图与卡方分布的概率密度函数之间的比较。

适合度

芮在一家科技公司远程工作。如果人不太多的话,他喜欢在咖啡店工作。最近新开了一家咖啡店,他想了解一周中每天的顾客分布情况。这样,他会选择百分比较小的日子在那里工作。根据他在类似地方的经验,他画出了一周中每天顾客数量的分布。为了测试这一假设,在接下来的 3 个月里,他随机选择了一周中每天的一个样本,并记录了观察到的顾客数量。

table = [["Day",'M','T', 'W', 'T', 'F', 'S', 'S'],
         ["Expected (%)",10,10, 10, 20, 30, 15, 5],
         ["Observed",30, 14, 34, 45, 57, 20, 10]]
display(HTML(tabulate.tabulate(table, tablefmt='html')))

表 1:一周中每天新咖啡店的顾客分布。

在进一步讨论之前,我们需要确保满足卡方拟合优度测试条件。我们先来列举一下:

  • 样本必须是随机的
  • 每类结果的预期数量必须大于或等于 5(也称为大计数条件)
  • 要求样本是独立的。经验法则是,如果你是在没有替换的情况下抽样,你的样本量应该少于总体量的 10%

我们被告知,芮随机选择了一周中的每一天,所以第一个标准得到了满足。对于大计数的条件,让我们计算一周中每天的预期客户数。

n = 7 # number of days in a week
alpha = 0.05

table = np.asarray(table)[1:,1:]
table = table.astype(np.float32)
table[0] = table[0]/100total_number_customers = np.sum(table[1])
expected_num = table[0]*total_number_customerstable = np.concatenate((table, expected_num.reshape(1,-1)))
table[2]array([ 26.460001,  64.26    ,  85.049995, 107.729996,  37.8     ,
        18.9     ], dtype=float32)

请注意,我们没有任何小于 5 的值。最后,我们有独立的条件。Rui 从 3 个月的人口中选择了每一天,这给了我们每一类 12 个可能的值。这意味着芮抽样的样本不到总人口的 10%,即使他的样本没有替换,我们也可以假设它是独立的。

根据这些数据,Rui 定义了以下假设检验:

首先,他必须计算一个统计数据,比较估计的和观察到的客户数量。它近似遵循卡方分布。如果基于相似位置的分布是正确的,他可以使用这个统计量来计算观察到特定值或更极端值的概率。如果这个概率小于显著性水平(让我们使用α=0.05),我们可以拒绝 H_0,从而接受另一个假设,即新咖啡店每天的顾客分布不同于芮考虑的类似场所。

chi_sq_statistic = np.sum((table[2]-table[1])**2/table[2])
chi_sq_statistic19.246035(1-chi2.cdf(chi_sq_statistic, df=n-1))<alphaTrueif (1-chi2.cdf(chi_sq_statistic, df=n-1))<alpha:
    print('Reject H_0')Reject H_0

我们根据 Rui 收集的观察结果拒绝了 h0,这些观察结果包括新咖啡店每天的顾客数量。事实上,我们拒绝了 h0 意味着新的地方不遵循假设的分布定义的芮根据他的经验在类似的地方。

列联表卡方检验

一个政府机构想知道目前正在使用的针对新冠肺炎病毒的疫苗是否对新的 Delta 变种有任何效果。他们将样本分成 3 组:第一组服用辉瑞的疫苗,第二组服用让桑,第三组服用安慰剂。

图 3:新冠肺炎疫苗;来源

table = [['Sick', 15, 10, 30],['Not sick', 100, 110, 90]]
alpha = 0.05
df = pd.DataFrame(table)
df.columns = ['Effect', 'Pfizer', 'Janssen', 'Placebo']
df = df.set_index('Effect')
df

表 2:服用疫苗(辉瑞和让桑之间)或安慰剂的患病或未患病人群的样本数量。

让我们定义我们的假设检验:

像在任何假设检验中一样,我们将假设零假设为真,并计算得到上面收集的数据的可能性。如果它低于显著性水平,我们拒绝零假设。

arr = df.to_numpy()
arr = np.concatenate((arr, (arr.sum(axis=1)[0]/arr.sum() * arr.sum(axis=0)).reshape(1,-1)))
arr = np.concatenate((arr, (arr.sum(axis=1)[1]/arr.sum() * arr.sum(axis=0)).reshape(1,-1)))
arrarray([[ 15\.        ,  10\.        ,  30\.        ],
       [100\.        , 110\.        ,  90\.        ],
       [ 17.81690141,  18.5915493 ,  18.5915493 ],
       [ 97.18309859, 101.4084507 , 101.4084507 ]])chi_sq_statistic = np.sum((arr[2] - arr[0])**2/arr[2]) + np.sum((arr[3] - arr[1])**2/arr[3])

我们应该使用的自由度数等于表的行数减 1 乘以列数减 1。

print('P-value = ' + str(np.round(1-chi2.cdf(chi_sq_statistic, df =2*1), 4)))P-value = 0.0012if 1-chi2.cdf(chi_sq_statistic, df =2*1) < alpha:
    print('Reject H_0')Reject H_0

我们拒绝了 h0,这意味着疫苗产生了一些效果,并影响了我们实验中的患病人数。

同质性卡方检验

同一家机构决定测试辉瑞的疫苗,但这次的目标是测试对男性和女性的效果。

这是一个同质性检验,可以转化为以下假设:

table = [['Sick', 25, 12],['Not sick', 92, 88]]
alpha = 0.05
df = pd.DataFrame(table)
df.columns = ['Effect', 'Men', 'Women']
df = df.set_index('Effect')
df

表 3:服用辉瑞疫苗的患病或未患病的男女样本数量。

arr = df.to_numpy()
arr = np.concatenate((arr, (arr.sum(axis=1)[0]/arr.sum() * arr.sum(axis=0)).reshape(1,-1)))
arr = np.concatenate((arr, (arr.sum(axis=1)[1]/arr.sum() * arr.sum(axis=0)).reshape(1,-1)))
arrarray([[25\.        , 12\.        ],
       [92\.        , 88\.        ],
       [19.94930876, 17.05069124],
       [97.05069124, 82.94930876]])chi_sq_statistic = np.sum((arr[2] - arr[0])**2/arr[2]) + np.sum((arr[3] - arr[1])**2/arr[3])print('P-value = ' + str(np.round(1-chi2.cdf(chi_sq_statistic, df =1*1), 4)))P-value = 0.0674if 1-chi2.cdf(chi_sq_statistic, df =1*1) < alpha:
    print('Reject H_0')
else:
    print('Fail to reject H_0')Fail to reject H_0

请注意,尽管观察到这些值或甚至更极端值的概率相当低(约 6.7%),但我们未能拒绝 H_0。这意味着我们没有足够的证据表明疫苗对男性和女性的效果有差异。

关联的卡方检验

最后,让我们为两个变量之间的关联建立一个卡方检验。在这种情况下,我们想要测试冲浪者的身高 X 和他曾经冲浪的最大浪高 y 之间是否存在关联。请注意,这个特定的测试使用了单一人群的随机样本。

table = [['x<1.6m', 25, 22, 28],['1.6m<=x<1.9m', 10, 21, 35], ['x>=1.9m', 5, 10, 34]]
alpha = 0.05
df = pd.DataFrame(table)
df.columns = ['height', 'y<2m', '2m<=y<4m', 'y>=4m']
df = df.set_index('height')
df

表 4:不同冲浪者高度的样本数量 X/曾经冲浪的最大波浪尺寸 y。

arr = df.to_numpy()

for i in range(arr.shape[0]):
    arr = np.concatenate((arr, (arr.sum(axis=1)[i]/arr.sum() * arr.sum(axis=0)).reshape(1,-1)))
arrarray([[25\.        , 22\.        , 28\.        ],
       [10\.        , 21\.        , 35\.        ],
       [ 5\.        , 10\.        , 34\.        ],
       [15.78947368, 20.92105263, 38.28947368],
       [13.89473684, 18.41052632, 33.69473684],
       [10.31578947, 13.66842105, 25.01578947]])chi_sq_statistic = np.sum((arr[3] - arr[0])**2/arr[3]) + np.sum((arr[4] - arr[1])**2/arr[4]) + np.sum((arr[5] - arr[2])**2/arr[5])print('P-value = ' + str(np.round(1-chi2.cdf(chi_sq_statistic, df =2*2), 4)))P-value = 0.0023if 1-chi2.cdf(chi_sq_statistic, df =2*2) < alpha:
    print('Reject H_0')
else:
    print('Fail to reject H_0')Reject H_0

我们拒绝 H_0,也就是说,有证据表明冲浪者的高度和最大浪高有关联。

结论

本文涵盖了卡方检验家族的一部分。它们有助于检验关于分类数据分布的假设。我们评估了适合度检验,即检验样本数据是否符合假设分布。我们还看到了两个变量之间不同类型的独立性检验。当我们从两个不同的人群中抽取样本时,我们检验同质性。如果我们从一个总体中取样,我们测试变量之间的关联。

保持联系: LinkedIn

练习

你将在下周的文章中找到答案。

  1. 根据冲浪板经销商的说法,66%的冲浪板是常见的,25%是不常见的,9%是罕见的。José想知道他和他的朋友拥有的板子的稀有程度是否遵循这种分布,所以他随机抽取了 500 块板子并记录了它们的稀有程度。结果如下表所示。进行拟合优度测试,以确定 José和他的朋友拥有的冲浪板的稀有程度分布是否与声称的百分比不一致。
table = [['Cards', 345, 125, 30]]
alpha = 0.05
df = pd.DataFrame(table)
df.columns = ['Rarity level', 'Common', 'Uncommon', 'Rare']
df = df.set_index('Rarity level')
df

上周的答案

  1. 医生假设,疫苗接种前后因新冠肺炎而住院的平均时间发生了变化。将 1000 名患者随机分为治疗组和对照组。治疗组已经注射了疫苗,而对照组没有注射。结果显示,治疗组的平均住院时间比对照组少 10 天。下表总结了 1000 次数据重新随机化的结果。根据数据,治疗组的平均值比对照组的平均值小 10 天或更多的概率是多少?从实验结果中你能得出什么结论(假设 5%的显著性水平)?
diff = [[-17.5,1],
[-15.0, 6],
[-12.5, 15],
[-10.0, 41],
[-7.5, 82],
[-5.0, 43],
[-2.5, 150],
[0., 167],
[2.5, 132],
[5.0, 127],
[7.5, 173],
[10.0, 38],
[12.5, 18],
[15.0, 6],
[17.5, 1]]plt.bar(x = np.asarray(diff)[:,0], height = np.asarray(diff)[:,1], width=2, color='C0')
plt.bar(x = np.asarray(diff)[:4,0], height = np.asarray(diff)[:4,1], width=2, color='C1');

diff = np.asarray(diff)np.sum(diff[diff[:,0]<=-10][:,1])/np.sum(diff[:,1]) < 0.05False

基于 5%的显著性水平,结果不显著。实验中测量到的差异可能仅仅是随机因素造成的。

推断和预测的区别是什么

原文:https://towardsdatascience.com/inference-vs-prediction-b719da908000?source=collection_archive---------13-----------------------

在统计学习的背景下讨论预测和推断的区别

Jonathan Pielmayer 在 Unsplash 上的照片

介绍

简单来说,统计学习是指可以应用于估计未知函数 f 的方法和途径的集合。

例如,让我们假设我们必须处理一些房地产数据,以便我们可以潜在地找到属性的特征(即预测值或自变量)与其估值(目标或因变量)之间的关系。其中一些特征可能与实际价格有关,可能是位置、卧室数量、建造日期、土地面积等等。

为了说明这个概念,让我们以墨尔本住房数据集为例。下面,我们将 50 处房产的价格与相应的土地面积进行对比。

蓝点是观察到的房产价值和土地面积——来源:作者

现在,我们可能有兴趣尝试使用土地面积来预测房地产的价格。然而,指定价格和地产土地面积之间关系的函数是未知的。

为了将这个问题放到更一般的背景下,我们本质上假设在响应(即价格) Y 和独立变量(即土地大小、卧室数量等)之间存在某种关系。)X = (X1,X2,…)。换句话说,我们可以用下面的符号来建模

Y = f (X) + ε

其中 f(X) 为自变量的未知函数, ε 为误差项(平均值约为零)。

现在,根据我们想要达到的目标和我们需要回答的(潜在的商业)问题,我们首先需要估计函数 f 有两个基本原因。我们要么想执行推理预测

预言;预测;预告

在许多用例中,独立变量 X 是可用的,而输出 Y 通常是未知的(或者不能以直接的方式计算)。因此,估计未知函数 f 并使用它对输出 y 进行预测可能是有用的。在这种情况下,符号将变为

ŷ=f̂(x)

其中 对应于未知函数 f 的估计值,而ŷ代表目标变量 y 的预测值。我们还省略了误差项 ε ,因为它的平均值为零。

换句话说,当对数据执行预测时,我们最感兴趣的是估计 f. 我们对估计函数的确切形式不感兴趣,只要它能相当精确地执行预测。

为了将上述内容放在一个背景中,让我们再来看一下我们的房地产定价例子。X1,X2,..是独立变量,对应于物业的特征(如土地面积、卧室数量等),Y 是物业的实际价格。在这种情况下,用 X 来预测 Y 是非常有益的,因为这将有助于你避免为某个特定的房产支付过高的价格,或者在房地产市场发现好的机会。

由于 是一个估计值,预计它不会是实际 f 的完美估计值,因此会引入一定量的误差(称为可约误差)。即使我们能够完美地估计出 f ,我们仍然会观察到一些误差,因为 f 本身就是 ε (这是不可约误差)的函数。

总之,在进行预测时,我们感兴趣的是尽可能准确地估计未知函数,即通过使用最合适的统计学习技术来最小化可约误差。

推理

在其他情况下,我们可能需要或必须了解自变量 X 影响目标变量 y 的方式。在这种情况下,我们仍然对估计 f 感兴趣,但是我们并不真的需要执行任何类型的预测。

换句话说,我们有兴趣了解 X 和 Y 之间的关系,以及后者如何作为前者的函数而变化。当我们想要了解哪些自变量实际上与目标变量相关联时,通常会用到推断。

为了更好地理解这一点,让我们再次考虑一下房地产的例子。在收集的房产特征(土地面积、卧室数量、位置等)中。)实际上只有这些特征的子集与价格相关联。

此外,我们可能需要了解目标变量和每个独立预测因子之间的关系。例如,我们可能希望观察某个特定的预测值(比如卧室数量)是否对 y 有积极的贡献。例如,当卧室数量增加时,价格是否会增加。

最后,推理的另一个重要应用是当我们需要了解自变量 X 与目标变量 Y 之间的关系是否为线性时。

最后的想法

在今天的文章中,我们讨论了统计学习中的一些基本概念,并探讨了预测和推断之间的主要区别。

在预测设置中,我们感兴趣的是尽可能准确地估计 f ,这样我们就可以根据独立变量 X 对目标变量 Y 进行预测。另一方面,在推理设置中,我们仍然感兴趣的是估计 f ,但这次不是进行任何类型的预测,而是为了理解 X 和 Y 之间的关系

成为会员 阅读媒介上的每一个故事。你的会员费直接支持我和你看的其他作家。

你可能也会喜欢

</14-must-know-pip-commands-for-data-scientists-and-engineers-a59ebbe0a439>

无限宝石和样品空间

原文:https://towardsdatascience.com/infinity-stones-and-sample-spaces-ad890c9be950?source=collection_archive---------58-----------------------

以有趣的方式学习概率!

照片由晨酿Unsplash 拍摄

掌握概率是一个人最接近拥有超能力的方式。这是你可以应用到日常生活中的越来越有用的技能之一。你可以用它来决定某些事件的结果,在赌场大获全胜,甚至用它来阻止强大的灭霸毁灭半个宇宙!开玩笑的。本质上,我说的是概率是你如何量化/描述一个随机事件。这是一种语言和远见,让你做出明智的决定,并且很可能在事情发生之前就知道会发生什么。

先决条件和符号

  • ω:样本空间;考虑了一套。
  • ω:样本结果。
  • A :事件;ω的子集
  • | A |:集合 A. 中元素的个数
  • a ∈ S :值 a 是集合 S 的“一个成员”或简单的“在”集合S中。

先举个例子吧!

顺便说一句,我喜欢漫画书,电影世界,以及所有流行文化的优点。我假设很多读者对此都很熟悉,所以我的例子将围绕这些主题。例如,假设钢铁侠正与疯狂的泰坦灭霸对决,后者已经拥有了所有六块无限宝石。在他们激烈的战斗中,史塔克的目标是防止灭霸折断他的手指,为了确保这一点,钢铁侠需要的是六块石头中的一块!

现在,由于灭霸是最难对付的坏人,我们将认为这种联系是一个“随机事件”。钢铁侠独自一人,没有了托尔、惊奇队长和其他复仇者,因此我们认为钢铁侠只能获得六块无限之石中的一块,并在灭霸消灭他之前逃离。我们还必须声明,从灭霸只获得六颗无限宝石中的一颗也是同样可能的结果。我们还必须注意到,这场战斗很容易重复,每场战斗的结果都不会改变。

有很多东西要吃吗?欢迎来到数学课,别担心。变得容易了。

我们将把这场战斗称为“实验”。在这个实验中,有六种可能的结果:获得灵魂石、时间石、空间石、心灵石、现实石或力量石。在与灭霸的一场战斗之后,我问,比如说,获得心灵之石的可能性有多大?

示例空间和事件

众所周知,数学是一项极其严谨的工作。因此,为了明智地谈论钢铁侠和灭霸之间的激烈战斗,我们从定义几件事情开始。

我们将从样本空间开始。用ω表示的样本空间是实验中所有可能结果的集合。集合ω中的元素用ω表示,称为样本结果。ω的任何子集被称为一个事件,并由 A 表示。

回到灭霸的例子,如果我们正好与灭霸战斗一次,那么我们的样本空间由ω= {灵魂、时间、空间、思想、现实、力量} 定义。一个简单的结果是获得由ω =威能定义的灵能石。一个事件可以是一个实验的一个或多个样本结果(子集)。让我们更难一点,如果我们和灭霸打,比方说…两次,样本空间是多少?

我们如何定义在两场战斗中选择相同的无限之石的事件?嗯,在这种情况下,有 36 个样本结果(|ω| = 36)而在我们的样本空间里: {(灵魂,时间),(灵魂,空间),…} 。如果这令人困惑,不要担心。我一点也不明白为什么会有 36 种可能的结果。为了更好地理解这一点,我们将涉猎组合学。样本结果的数量可以使用以下公式计算:

其中 n 代表可供选择的项目数量,而 r 代表我们希望选择的数量。此处可以找到对该公式的详细描述。因此,在我们的例子中,有 6 个无限宝石可供选择,我们希望选择其中的 2 个,因此 6 = 36。

我们不会列出所有的可能性,但是相反,我们会做一些更好的事情来定义这个样本空间。我们将使用数学符号!

如果我们和灭霸打两次,样本空间就是集合:

符号∈仅仅意味着一个元素在集合中。如果ω₁ =灵魂和设定s = {灵魂、时间、空间、心灵、现实、力量} 。那么我们可以说灵魂石是集合 S 的“成员”,或者用集合符号表示:ω₁ ∈ S。在两场战斗中选择相同的无限石的事件可以描述为:

用| 一个 | = 6。如果钢铁侠和灭霸打无数次,样本空间会是多少?嗯,应该是这样的:

就像美国队长会说的,“我可以一整天都这样”。

那么什么是概率呢?嗯,可以定义为:

所以让我们把这个概念和我们的例子联系起来。如果钢铁侠打灭霸两次,钢铁侠拿无极石的概率有多大?嗯,样本结果的总数是|ω| = 36,它发生的方式是| A | = 6,所以我们简单地除以 6/36 = 1/6。因此,在两场战斗中,钢铁侠都有 1/6 的几率选择相同的无限之石。

总而言之,在这篇博文中,我们基本上了解了概率论中的随机实验。为了形式化,随机实验包括三个部分:

  1. 样本空间ω,它是所有样本结果的集合。
  2. 一组事件,其中每个事件 A 是包含零个或多个样本结果的ω的子集。
  3. 每个事件都必须有一个概率。

现在,这对你意味着什么?好了,现在基础架构已经到位,并且已经迈出了理解统计学的第一步,你会看到数学经常出现在最意想不到的地方,然而却是最令人兴奋的地方!

正如尼克·弗瑞(Nick Fury)在《钢铁侠》(Iron Man)的结尾所说,“斯塔克先生,你已经成为一个更大宇宙的一部分。你只是还不知道罢了。”

深度学习中的信息瓶颈与降维

原文:https://towardsdatascience.com/information-bottlenecks-c2ee67015065?source=collection_archive---------22-----------------------

思想与理论《语音处理笔记》,2021 年 9 月 2 日

自动编码器和其他具有信息瓶颈的深度神经网络已经成为时尚。启发式思想是减少隐藏层的维度,使得网络被迫关注数据的重要部分。实验也证明了自动编码器在这个意义上是有效的。然而,我一直在想,T2 的信息量是否可以用精确的术语来描述。有多少信息通过瓶颈流动?我们该如何衡量呢?

这篇短文是我描述和理解这个问题的尝试。我将从信息论和线性代数的一些经典概念开始,然后讨论这些概念在机器学习中的适用程度。一个中心结果是隐藏层的维度不能单独用作信息内容的度量。

离散表示中的信息内容

如果一个系统有两种状态,A 和 B,那么显然我们可以用一个比特来表示状态。4 个状态可以用 2 位表示,8 个状态用 3 位表示,一般来说,N 个状态用 log2(N)位表示。因此,我们总能很容易地确定状态数有限的系统所需的位数。描述状态所需的比特数是系统信息量或熵的直接度量。

如果我们能额外得到每个状态的概率,我们可以把它扩展到可数集合,比如整数。然后,我们可以陈述平均比特率,也就是说,如果我们多次观察系统,我们平均需要多少比特来表示状态?如果状态 k 的概率为 Pk ,则表示该状态所需的比特数为- log2 Pk 。该比特率,- log2 Pk 以概率 Pk 出现,使得平均比特率可以被计算为总和,- sum Pk log2 Pk ,其中总和覆盖所有 k 。这也适用于 k 遍历一个无限但可数的集合。

线性连续值系统中的信息量

如果题目比较混乱,就想到线性代数。一个长度为 N 的向量 x 有多少信息。嗯,还没有真正的定义。然而我们所知道的是,如果我们用矩阵 A 乘以矩阵 y=Ax ,那么如果矩阵 A 是满秩的,那么所有信息都被保留。其实那我们就可以通过求逆 x=inv(A)yy 中恢复出 x 。没有信息丢失。显然, A 的等级因此定义了其容量移除信息。如果等级为(A) < N ,则信息丢失,并且无法从 y 恢复。

然而,这还不是故事的全部。在逆运算的实际实现中,我们知道不仅秩是重要的,而且 A 的条件也是重要的。如果 A 的任何奇异值接近零,则 A 变得病态,使得从 y 恢复 x 在数值上变得困难。在最好的情况下,我们失去了准确性,使得 x 只能被近似地恢复,在严重的情况下,信息可能完全丢失。因此,信息内容不仅通过维度来描述,还通过准确性来表征。正如我们将看到的,我认为把信息的损失描述为准确性的损失比描述维度的损失更有用。

转向:空间填充曲线

如果你没有听说过空间填充曲线,那就从观看关于它们的数字爱好者视频开始吧。这个想法是一个无限的递归;你从一个穿过空间的简单形状开始。然后,您将扭曲添加到该形状,以便它在空间中扩展得更大。重复添加更多的摆动会使曲线越来越分散,以至于它收敛到覆盖整个空间。一维线因此覆盖了整个二维空间(即其豪斯多夫维数为 2)。

就信息内容而言,现在,一维曲线包含了二维空间的信息。如果我们从 2D 空间中的某个特定点 (x,y) 开始,我们可以将其转换为一维线上的点 d ,然后再将其转换回 2D 点 (x,y) 。只是涉及到一个无限递归,所以这不是一个实用的算法。

然而,我们可以实现有限次数的递归来得到一个近似值。在下面的例子中,我实现了一个希尔伯特曲线,并绘制了不同递归数 N 的曲线。

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

def hilbert_curve_expansion(str, n):
    k = 0
    while k < len(str):
        if str[k] == 'A':
            str = str[0:k] + '+BF-AFA-FB+' + str[(k+1):]
            k+=10
        elif str[k] == 'B':
            str = str[0:k] + '-AF+BFB+FA-' + str[(k+1):]
            k+=10
        k += 1
    if n > 1:
        return hilbert_curve_expansion(str,n-1)
    else:
        return str

def draw_curve(str):
    direction = np.array([[1,0]])
    edge = np.zeros([2,2])+.5
    P = np.array([[0,1],[-1,0]])

    for c in str:
        if c == '+':
            direction = np.matmul(direction,P)
        elif c == '-':
            direction = np.matmul(direction,-P)
        elif c == 'F':
            edge[0,:] = edge[1,:]
            edge[1,:] = edge[1,:] + direction
            plt.plot(edge[:,0],edge[:,1],'k')

# plotting parameters
default_dpi = mpl.rcParamsDefault['figure.dpi']
mpl.rcParams['figure.dpi'] = default_dpi*1.5

# plot hilbert curves with different number of recursions
for k in range(4):
    plt.subplot(241+k)
    curve = hilbert_curve_expansion('A',k+1)
    draw_curve(curve)
    plt.gca().set_aspect('equal', 'box')
    plt.xlim([0,2**(k+1)])
    plt.ylim([0,2**(k+1)])
    plt.xticks([])
    plt.yticks([])
    plt.title('N=' + str(k+1))

plt.show()

draw_curve(hilbert_curve_expansion('A',5))
plt.gca().set_aspect('equal', 'box')
plt.xlim([0,2**5])
plt.ylim([0,2**5])
plt.xticks([])
plt.yticks([])
plt.title('N=5')
plt.show()

draw_curve(hilbert_curve_expansion('A',6))
plt.gca().set_aspect('equal', 'box')
plt.xlim([0,2**6])
plt.ylim([0,2**6])
plt.xticks([])
plt.yticks([])
plt.title('N=6')
plt.show()

我们可以容易地看到,对于每次迭代,曲线填充空间的精度加倍(误差减半,即误差能量为 1/4)。我所说的准确性是指从 2D 空间中的任意点到曲线上最近点的平均距离。

另一方面,每次迭代以 2 比特的代价将每个段分成 4 个子段。因此,误差减半的代价是 2 比特。因此,这个结果遵循传统有损编码的结果;误差减半的代价和我们拥有的尺寸一样多。现在我们有 2 个维度,所以误差减半需要 2 位。

自动编码器中的信息内容

注意,上面的空间填充曲线结构可以被解释为自动编码器。二维空间被映射(编码器)到一维空间(瓶颈),我们可以用逆空间(解码器)来恢复。该曲线是分段线性的,并且可以容易地用单层整流线性单元(RELUs)来实现。每个递归由细分为 4 个部分组成,因此我们可以预期网络可以用 2^(2N) RELUs 来实现。相反,如果 RELUs 的数量是四倍,映射的误差减半。

熏青鱼

人们很容易被愚弄,认为我们可以做一些比希尔伯特更简单的空间填充曲线(或其他等价曲线)。例如,我们可以在尺寸 x 上绘制首尾相连的之字形线,然后在尺寸 y 上进行一步 1/N 。这可以用 O(N) RELUs 实现。这张地图的精确度将会相对于 2^-N 而不是2^-(2n。然而,我们将仅在 y 维度上有误差,并且 x 维度可以总是被完美地重建。因此,我们的精度论证和以前一样适用,当假设每个轴上的精度相等时,我们需要每个维度 1 位来将精度减半。

作为信息度量的重建精度

自动编码器的相关结果是瓶颈的维度不能单独定义通过的信息量。通过指数增加编码器和解码器中的非线性数量,我们获得了均方误差的对数线性下降。由于我们不能用维数来测量信息,因此我们应该根据重建精度来测量信息量。

这种方法也符合概率和统计中的传统概念。对于连续值变量 x ,我们不能定义概率,而只能定义概率分布,因为有无限多的可能值,任何特定值的概率总是零。同样,对于连续值的信息瓶颈,我们不能定义绝对信息内容,而只能定义相对信息内容的准确性。也就是说,我们可以说,当改变网络结构时,准确性(以及因此信息内容)被提高或降低,特别是关于非线性的数量。然而,我们不能说通过了多少信息,而只能比较不同网络结构的相对信息量。

矢量量化

已经流行的一种特殊形式的自动编码器是 VQ-VAE 编码器,即矢量量化变分自动编码器。我不会在这里讨论“变化”的部分,但是矢量量化自动编码器指的是瓶颈也被量化的系统。特别地,矢量量化器具有固定数量的量化级别,使得比特率被很好地定义。因此,上述分析不能直接应用于这种系统。启发性地说,我认为(并猜测)编码器的复杂度必须足够,这样它才能将信息消化成 VQ 可以处理的形式。进一步增加编码器复杂度不会提高重建精度,因为它受到 VQ 精度的限制。相反,如果编码器具有给定的结构,那么 VQ 比特率必须足够大,以便它可以充分利用嵌入的好处。从上面的空间填充曲线,你可以理解,如果 VQ 比特率很低,那么它不能模拟高递归曲线中包含的复杂信息。换句话说,为了最佳性能,编码器结构和 VQ 比特率必须联合匹配。

结论和待办事项

这是我第一次尝试描述自动编码器中的信息内容。我自己的印象是,我正在做一些事情。显然,一个复杂的编码器可以将信息压缩到一个狭窄的瓶颈中,从而可以高精度地重构信息。事实上,假设具有完美的精度(没有数值舍入误差),那么如果相应的编码器和解码器足够复杂,任何向量都可以被压缩为单个实数值,并以任意精度进行重构。神奇之处在于空间填充曲线嵌入无限的方式;两个无限精确的信号可以交错在一起而不丢失信息。

上面的演示没有严格的证明,而且有很多挥舞手臂的动作。例如,我只详细描述了 2D 信号映射到 1D 信号(2D 到 1D)的情况,它可以很容易地扩展到 nd 到 1D,但需要更多的反射来扩展到任意宽度的瓶颈,ND 到 KD。我也没有恰当地定义重建精度,也没有定义空间填充曲线中的 RELUs 数量等等。我还想用 pytorch 之类的东西来实现空间填充曲线作为演示。VQ 的讨论也很肤浅。我也没有做过文学研究;如果你知道相关的工作,请告诉我!也许下次吧。

无论如何,这是关于自动编码器和相关深度神经网络中信息内容的理论讨论的开始。

Scribd 的信息提取

原文:https://towardsdatascience.com/information-extraction-at-scribd-f62f3025b5c9?source=collection_archive---------27-----------------------

使用自然语言处理通过关键短语和实体在我们的大量文本文档上执行信息抽取

这是一系列博客文章的第 2 部分,描述了我们构建的多组件机器学习系统,用于从我们的文档中提取元数据,以丰富下游发现模型。

在本帖中,我们展示了在为大量文本文档构建信息抽取 NLP 模型时所面临的挑战和局限性,以及我们提出的解决方案。

正如在第一部分中提到的,我们现在有了一种识别大量文本文档的方法。完成这些之后,我们想要构建专用的模型来加深我们对它们的语义理解。我们通过提取关键短语和实体来做到这一点。

图 1 :我们多组件机器学习系统的示意图(图片作者)。

关键短语是代表主要主题/话题的短语,而实体是专有名词,如人、地点和组织。例如,当一个用户上传一个关于曼哈顿项目的文档时,我们首先会发现它是一个很重的文本,然后提取关键短语和实体。潜在的关键词是“原子弹”和“核武器”,潜在的实体是“罗伯特·奥本海默”和“洛斯·阿拉莫斯”。

因为关键短语提取引出了文档中讨论的一般主题,所以它有助于限制每个文档保留的信息量,从而不管文档的原始大小如何,都能得到某种程度上统一的文档表示。另一方面,实体提取识别文本中不一定仅由关键短语反映的元素。我们发现关键短语和实体提取的结合为每个文档提供了丰富的语义描述。

本文的其余部分将解释我们如何处理关键短语和实体提取,以及我们如何识别这些关键短语和实体的子集是否存在于知识库中(也称为链接),并介绍我们如何使用它们来对文档进行分类。

关键短语提取

通常,关键短语提取系统分两步操作,如本调查中所示:

  • 使用试探法提取作为候选关键短语的单词/短语列表,如词性语言模式、停用词过滤和维基百科文章标题的 n 元语法
  • 使用以下两种方法之一来确定这些候选关键短语中的哪些最有可能是关键短语:
  • 监督方法,例如候选的二进制分类(有用/无用)、基于位置编码的结构特征等。
  • 无监督的方法,例如选择具有最高 tf-idf 的术语和聚类。

训练一个像样的监督模型以能够提取各种主题的关键短语将需要大量的训练数据,并且可能概括得很差。出于这个原因,我们决定采取无人监管的方法。

我们对关键短语提取的实现进行了速度优化,而没有牺牲太多的关键短语质量。我们使用统计方法和语言特定的规则来有效地识别它们。

我们简单地从过滤掉停用词开始,提取基数为 n 的 n 元文法(在我们的例子中是二元文法,n=2)。这一步骤快速且直接,并产生候选 n 元文法的初始集合。

然而,将结果限制到单个 n 元语法类会导致分裂的关键短语,这使得将它们链接到知识库成为一项具有挑战性的任务。为此,我们尝试将较低阶的 n-grams 聚集成潜在较长的关键短语,只要它们与较短的 n_gram 相比以预定的最小频率出现,基于以下 a 模式:

A sequence of nouns (NN) possibly interleaved with either Coordinating Conjunctions (CC) or Prepositions and Subordinating Conjunctions (IN).

这里有几个例子:

  • 假设聚集的最小频率是 0.5,这意味着只要world health organization发生的次数至少是world health发生次数的 50%,我们就只用world (NN) health (NN) organization (NN)代替二元组world (NN) health (NN)
  • 仅当与前者相比,后者至少出现预定百分比的时间时,用Center(NNP) for (IN) Global (NNP) Development (NNP)替换Human (NNP) Development (NNP)

这种方法产生更连贯和完整的关键短语,可以更准确地链接到知识库条目。

最后,我们使用候选关键短语的出现次数作为其重要性的代理。这种方法对于较长的文档是可靠的,因为关键短语的重复倾向于可靠地表明它是文档主题的中心。

命名实体

关键短语只是发现文档中重要内容的一个方面。为了进一步捕捉文档的内容,我们还必须考虑存在的命名实体。

命名实体提取系统识别文本中命名实体的实例,我们可以对其进行计数,以表示它们在文档中的重要性,类似于我们对关键短语所做的。

天真地通过精确的字符串匹配来计算命名的实体暴露了一个有趣的问题:一个实体可能有许多名称或别名,这意味着字符串频率是一个不可靠的重要性度量。在图 2 给出的例子中,我们知道“米尔”、“约翰·斯图尔特·米尔”和“斯图尔特·米尔”都是指同一个人。这意味着米尔比表格显示的更重要,因为他总共被提到了 8 次而不是 5 次。

图 2 :节选自约翰·斯图亚特·穆勒的维基百科页面(左)和前几段的 5 大命名实体计数(右)(图片作者)。

为了解决这个计数问题,让我们引入一些抽象概念:

  • 命名实体指独特的人、地点或组织。由于它们的唯一性,我们可以用唯一的标识符( ID )来表示它们。
  • 命名实体别名(或简称为别名),是与特定实体相关的可能的多个名称之一。
  • 规范别名是实体的首选名称。
  • 命名实体提及(或简称为提及),指的是一个命名实体在文本中被提及的每一次出现,不管使用了哪个别名。
  • 知识库是一个实体集合,允许我们查询 ID、规范名称、别名和其他可能与手头任务相关的信息。一个例子是维基数据

解决计数问题的第一步是规范化文档用来引用一个命名实体的名称。使用我们的抽象,这意味着我们想要找到文档中所有提到的,并使用它的别名来找到它所属的命名实体。然后,用规范名称命名实体 ID** 来替换它——这个区别将在后面变得更加清楚。**

实体规范化

给定出现在文档中的一组别名,我们开发了启发法(例如,公共标记、缩写)来识别哪个别名子集引用相同的命名实体。这允许我们在比较别名时限制我们的搜索空间。

使用我们之前的示例来说明这种方法,我们首先假设规范别名是给定实体的文本中最长的别名,并通过评估哪些别名与我们开发的试探法匹配来尝试将别名合并在一起。

表 1 :约翰·斯图亚特·穆勒维基百科页面前几段出现的前 5 个别名,有些是指同一个人(图片作者)。

使用精确的记号匹配作为启发来相互比较实体将解决这个问题:

表 2 :成对别名比较和结果合并。匹配项以粗体突出显示(图片作者)。

通过用相应的规范别名替换所有提及,我们能够找到正确的命名实体计数。

一种极端情况是当一个别名可能指一个以上的实体时:例如,别名“波特”可能指哈利波特宇宙中的命名实体“哈利波特”或“詹姆斯·波特”。为了解决这个问题,我们构建了一个实体链接器,它决定在给定的上下文中哪个命名实体最有可能匹配别名。在链接到知识库一节中进一步解释了这一过程。

当知识库中没有实体时,我们不能使用命名实体链接来消除歧义。在这种情况下,我们的解决方案使用了一种回退方法,该方法将不明确的提及(Potter)分配给与启发法匹配的最接近的明确提及(例如 Harry)。

链接到知识库

假设文档中提到的许多关键短语和实体是值得注意的,它们很可能存在于知识库中。这使我们能够利用知识库中存在的额外信息来改进标准化步骤以及下游任务。

实体链接通过提供别名匹配命名实体的信息来帮助规范化,否则该命名实体不会匹配启发式规则(例如,“诚实的 Abe”对“Abraham Lincoln”)。此外,知识库中的信息可用于在与文本相同的空间中嵌入链接的实体和关键短语。

能够在与文本相同的空间中嵌入实体是有用的,因为这释放了将可能匹配的命名实体 id 与它们被提及的上下文进行比较的能力,并决定我们考虑的别名是否可能是知识库中的实体之一(在这种情况下,我们将使用 id),或者该别名是否与知识库中的任何实体不匹配,在这种情况下,我们退回到使用假定的规范别名。

Scribd 中,我们利用实体链接不仅改进了实体规范化步骤,还利用了实体和关键短语嵌入作为补充特性。

讨论

将所有这些放在一起,我们可以:

  1. 将文档链接到关键短语和实体
  2. 找出文件中每一项的相对重要性。
  3. 利用知识库中的相关信息

这促成了一些有趣的项目:

在其中一个项目中,我们构建了一个文档图以及相关的关键短语和实体。在同一个空间中嵌入文档、关键短语和实体使我们能够通过类比来发现文档。例如,以亚历山大·仲马的《基督山伯爵》为例,这是一本 19 世纪的法国复仇小说。如果我们再加上science_fiction的嵌入,它会把我们带到儒勒·凡尔纳(另一位 19 世纪的法国作家)的科幻小说集,比如《海底两万里》《地心游记》

关键短语提取在增加文档聚类的可解释性方面也很有用。通过提取一个集群中最常见的关键短语,我们可以为该集群的内容导出一个共同的主题:

图 3 :文档聚类中的顶级关键词。关键词暗示其中的文档与牙科&医疗保健相关,这通过人工检查文档得到确认(图片由作者)。

在另一个项目中,我们利用预先计算的知识库嵌入,通过包含的实体和关键短语的组合来表示空间中的文档。这些功能使我们能够了解用户上传的文档,并改进平台上的内容发现。

要了解我们如何使用提取的信息将文档分类到一个分类法中,请务必查看第 3 部分(即将推出):对用户上传的文档进行分类!

如果您有兴趣了解 Scribd 应用研究正在解决的问题或围绕这些解决方案构建的系统,请查看我们的空缺职位

信息论:温和的介绍

原文:https://towardsdatascience.com/information-theory-a-gentle-introduction-6abaf99835ac?source=collection_archive---------21-----------------------

这是关于信息论及其与数据驱动型企业和战略的关系的系列文章中的第一篇。虽然在每一部分都会有一些等式,但是对于那些对细节不太感兴趣而对含义更感兴趣的人来说,它们可以被忽略。

20 世纪早期和中期见证了电信技术和能力的爆炸。因此,工程师和研究人员面临着许多以前从未真正解决过的问题,例如:

我如何将单词和声音转换成点和破折号?

我如何将电子信号重构为单词和声音?

当电子信号中加入噪声时会怎样?

我可以传输多少的信息,但仍然可以重建一条消息?

信息到底是什么?

在这样做的时候,这些研究人员意外地建立了一套应用数学给我们的最强大的工具,用来处理和解决无数“不太数学”的问题。上述问题及其衍生的附加问题显然是受电信的启发;然而,这些挑战与数据驱动型企业和现代分析领导者面临的现代挑战有相似之处:

什么信息是我绝对需要的?

哪些信息可以忽略,什么时候可以忽略?

我的投资组合或策略有多复杂,我拥有的数据证明了它的合理性吗?

我应该更相信数据还是我的经验?(也许令人惊讶的是,我们会看到答案经常是‘不要相信数据’)

我的项目可能会在哪里失败?

在我的金融敞口中,我面临什么样的系统性风险?

现在有了数据,我该怎么做?

在前几篇文章中,我们将介绍 5 种工具——熵、互信息、霍夫曼码、Kolmogorov 复杂性和 Fisher 信息——用于评估个人和职业生活中的这些和其他挑战。虽然未来的文章将更多地关注原理和含义,但首先我们必须介绍信息论的构建模块:熵

熵:随机性的一种度量

如果你和一位定量专家交谈,问他们从事这项工作多久了,通常,外交式的回答会涉及他们从本科毕业以来的年数。然而,事实上,对于我所认识的数据科学及其相邻领域的大多数人来说,他们至少从十几岁开始就沉浸在这个主题中。每一年,相同的材料或多或少都呈现出一层额外的精确、细致和/或复杂。通常定义是相加的。举例来说,重力最初是导致苹果下落的原因,之后是大质量物体相互作用的方式,然后与加速度和流形上的扭曲有关。一个比一个复杂,一个比一个完整。

但不是熵。在我 20 年的学习和实践中,我已经得到了半打熵的定义。虽然这些定义有一些时间和方式上的效用,但它们不是附加的,也不容易。以下是几个最糟糕的例子:

熵是…

系统中的无序或混乱

系统中自由度的数量

掩盖系统初始条件的“力”

第一个定义,可能是最常见的,是完全错误的。后两个,虽然相当正确,但让你对它的含义没有任何直觉。

这是信息论的第一个伟大胜利:对科学中最容易被误解的概念给出了一个合理而直观的定义。 熵是系统中不确定性——或随机性——的程度。【1】这比仅仅称之为无序或混乱好一点,但却隐含着某种深刻的东西。即不同的系统和不同的随机事件具有不同程度的随机性。让我们用统计学家最喜欢的两个玩具来检验我们的直觉,一个硬币和一个骰子。掷硬币和掷骰子哪个更随机?让我们以两种方式检查。首先,我们问一个问题,如果我们随机猜测(或稍后最优猜测),我们猜对的几率有多大?掷硬币的概率是 50%,掷骰子的概率是 16.7%。其次,让我们问一下有多少种可能的状态(读作:结果)会发生。硬币是 2(正面或反面),骰子是 6 (1,2,3,4,5,6)。在这两种情况下,看起来骰子比硬币更随机。不同事件具有不同水平或随机性的概念通过了嗅探测试。

对于公平的硬币和公平的骰子,很容易看出哪个更随机,我们的直觉很快就同意了。现在我们来改变一下对比。假设我们仍然有我们的公平硬币,但现在我们想把它比作一个加权骰子。这个加权骰子在 90%的情况下出现“1 ”,在每个剩余的面上出现 2 %( 2%代表 2,2%代表 3,以此类推)。现在哪个更随机。随机猜对硬币还是 50%有效,对骰子是 16.7%【3】。同样,硬币有两种状态,骰子有六种状态。但是装载的骰子感觉起来没有公平的那么随机;毕竟,它几乎总是出现“1”。现在我们需要一个更严格的熵的定义。

熵(H)取决于可能状态的数量及其概率

这通常是人们忽略的部分,大 sigmas 是令人生畏的。然而,等式 1 所说的都是我们已经感觉为真的 :结果多的事件往往比结果少的事件更随机,结果更公平的事件往往比严重偏向少数结果的事件更随机 。等式 1 为我们提供了一种描述这一点的正式方式,即对于具有结果 I 的事件 X,熵 H 等于每个结果的概率与该概率的对数底 2 之和。为什么是 base 2?因为最复杂的场景可以分解成许多 2 个状态事件,描述为:是或否,是或不是,真或假,等于或不等于。

现在回到我们的场景,装载的骰子对硬币。让我们首先通过比较公平的骰子和公平的硬币来对我们的直觉进行分层。公平骰子的熵是 2.58,而我们公平硬币的熵正好是 1。这当然与我们上面提到的直觉一致。那装了子弹的骰子呢?装载的骰子有大约 0.7 的熵,低于公平骰子(符合我们的直觉),也低于硬币。既然我们对随机性、熵以及如何用它来测量系统、事件和过程有了更好的理解,我们可以继续讨论它与信息的关系。

熵和信息

提醒一下,抛硬币的熵正好是 1。我们已经确定,这意味着它比掷骰子更不随机,但也意味着它包含更少的信息。更确切地说,这意味着一次硬币的投掷可以用 1 比特的信息来表示。

一个比特是一个信息单位,它可以有两种状态:1 或 0。抛硬币可以用一位来表示的原因是,硬币有两面出现的可能性相等。我们将 0 映射到反面,1 映射到正面,看到我们的硬币翻转可以用 1 位来表示。

将一点映射到抛硬币

公平骰子的情况有点复杂。它的熵为 2.58,因此可以用 2.58 位来写。但是位是离散的,没有. 58 位这样的东西。我们可以尝试用 2 或 3 位来表示它。首先是 3:

3 位骰子滚动具有额外容量;我们排除了两种可能的状态来解释这一点

有了 3 比特,我们就有了过剩的容量,或者换句话说,有了 3 比特,我们就有了一个比我们所需要的要复杂得多的场景模型。如果我们试图将骰子滚动到 2 位,我们会得到:

一个 2 比特的骰子滚动破坏信息

我们无法将公平骰子完全写入 2 位。这是一个 有损 的表示法。当我们试图用太少的信息来描述事件时,我们会丢失信息——在这种情况下是“5”和“6”的结果。

所有这三个——1 位硬币投掷、2 位骰子滚动和 3 位骰子滚动——都是事件的模型。随着模型位数的增加,它的复杂性也在增加。我们可以在这里创建一个经验法则: 如果我们试图用一个过于复杂的模型来表示一个系统,我们往好里说是效率低下,往坏里说是过于复杂,并且有犯大错的危险。如果我们代表的系统太少,我们就失去了重要的信息。

最后让我们看看我们不公平的骰子。它的熵值是 0.7。这里有两件事会让你印象深刻。首先,在我们的不公平骰子上,我们将丢失大约相同数量的信息,该模型表明“这个骰子只出现 1”与我们在我们的公平骰子上的 2 位模型相同。 这让我们得出另一条经验法则:即使事件很少发生,剔除异常值也能剔除大量信息。第二,它具有更低的熵,并且可以适合比公平骰子更简单的模型。接下来让我们检查一下,我们所掌握的关于不公平骰子的信息量的增加是如何导致这个结果的。

条件熵和信息的力量

回到定义,熵是不确定性的度量。如果你想了解——或者更好地利用——一个系统拥有较少的信息通常是好的。我们已经检查了一个降低事件熵的坏方法:制作一个不能准确描述场景的有损模型。在这里,我们将研究通过寻找有用信息来减少不确定性的最佳方法。

首先说句题外话,概率的一个怪癖是,如果你除了可能的状态之外对一个场景一无所知,你能做出的最好的猜测是所有的状态都是同样可能的。这是真的,即使你被告知某个场景在某些不具体的方面是不公平的。例如,如果你被告知一枚硬币是不公平的,但不是通过多少或哪个方向,而是通过所有可能不公平的方式的平均值,它是公平的。

在我们的加权骰子的例子中,我们得到了一条重要的信息。值得注意的是,骰子被加权为“1 ”,因此“1”出现的概率为 90%。据此,我们还可以推断出 2、3、4 或 5 出现的概率各为 2%。结果就是条件熵。更正式地说:

条件熵(H(X|Y)是具有更多信息的熵;在其他条件相同的情况下,它总是小于无信息熵

就像等式 1 一样,这些看起来比实际情况更吓人。等式 2 所说的是,条件熵用给定一些新信息的概率来代替事件发生的概率。在加权骰子的情况下,新信息(Y)是“1”出现的概率是 90%。等式 3 从等式 2 得出,并且注意到条件熵总是减少系统的不确定性。稍微不那么正式的 相关信息总是会降低一个系统的不确定性。<#_ftn5>

让我们看另一个场景。假设你住在洛杉矶。那里每年大约有 33 天下雨,所以任何一天下雨的几率都是 10%。在没有任何额外信息的情况下,LA 的降水时间表可以有效地用 170 比特模拟。洛杉矶确实有雨季,大约 90%的雨天(其中 30 天)发生在 11 月 1 日至 4 月 30 日之间。通过了解雨季及其对降雨可能性的影响,降水计划的熵减少到约 145 位,不确定性减少了 15%。

投资组合分析:DJI 是一个怪异的指数

如前所述,这篇文章在玩具问题和基本原理上花费的时间是独一无二的。当我们遇到更复杂的主题时,对熵有一个好的技术和直观的理解将是至关重要的。既然我们已经有了很好的理解,尽管我们可以抛开玩具问题,去找更有说服力的例子。对于许多这样的例子,道琼斯工业平均指数将充当替罪羊。

如果你在寻找一个充满不确定性、人们愿意利用的系统,股票市场可能是一个不错的起点。假设你想建立一个投资组合来获取交易所的回报。交易所领域由三家公司主导:洲际交易所(ICE,市值 680 亿美元,交易价格约 120 英镑)、伦敦交易所集团(LDNXF,市值 53 美元,交易价格约 105 英镑)和纳斯达克(NDAQ,市值 260 亿美元,交易价格约 160 英镑)。未来的回报是不确定的,但我们可以利用迄今为止所涵盖的原则来构建一些明智的尝试策略。

首先,让我们注意到投资组合只不过是回报可能所在的模型。如果我们没有其他信息,我们应该追求最大化投资组合熵的策略。这就产生了一个由 1/3 ICE、1/3 LDNXF 和 1/3 NDAQ 组成的投资组合。

还有一些其他明智的方法来构建投资组合。如果我们想复制行业的现状,我们可能会采取市值加权策略——44%的 ICE,39%的 LDNXF,17%的 NDAQ——我们将在下一篇文章中介绍原因。类似地,如果我们对未来回报有特殊的了解,我们可能会根据我们对回报如何在三者之间分配的预期来采取策略。这让我们想到了道琼斯指数。

道琼斯工业平均指数是一个价格加权的投资组合。这意味着这些元素的权重取决于它们的交易价格。在我们的交易所案例中,将产生 31% ICE、27% LDNXF 和 42% NDAQ 的投资组合。这个策略没有信息直觉。只是很奇怪。

交易和基准测试

结束前最后一个例子。假设我们想建立一个交易特定股票或指数的策略,而不是建立一个投资组合。为了简单起见,我们的策略可以在某一天做两件事之一:买入或持有,卖出或什么都不做,持有现金。我们需要一种方法来确定我们设计的任何给定策略是否有效。请注意,策略就像投资组合一样,只不过是回报的模型。

由于战略包括做出大量连续的决策,每个决策都应该比一个更简单的模型更有价值。回想一下,一个简单的模型可以用很少的比特来表示。这里有两种策略可以写成 0 比特。第一个很简单:只要持有现金。我想任何人都会同意,如果你的策略比不上持有现金,那就是一个糟糕的策略;直觉检查通过。第二个 0 位策略是买入并持有,这个策略是你在第一个交易日买入股票,然后一直持有。这是一个很好的基准有无数的现实原因,包括交易成本和税收优化。然而,我们的信息直觉是,更复杂的模型应该提供更高的回报。1 位模型应该改进 0 位策略,2 位模型应该进一步改进。

信息风险

根据我们对基准测试的评估,一个自然的推论是,复杂性的增加应该伴随着回报的增加。这是我们第一次遇到我称之为 信息风险 的概念。信息风险是一种脆弱性,它是在没有足够的相关数据来证明其合理性的情况下,远离稳健的低信息战略而产生的。它与过度拟合、正则化和交叉验证等概念相关,但味道略有不同。如何以稳健和明智的方式使用信息以降低信息风险将是这一系列活动背后的驱动因素。

下一篇文章:互信息作为预测

【1】信息论要素,盖&托马斯

顺便说一句,从现在起,容易的事情将被称为容易的,困难的事情将被称为琐碎的,不可能的事情将被称为“留给读者的练习”

【3】我们将在下一篇文章中讨论最佳猜测

数学家们称之为“用一物代替另一物”

【5】当我们引入互信息时,我们将再次对此进行更正式的处理

免责声明:本文表达的观点仅代表作者个人观点,不一定代表任何雇主、组织或其附属机构的观点。

2021 道格拉斯·汉密尔顿

信息论:原则与叛教

原文:https://towardsdatascience.com/information-theory-principals-and-apostasy-a7c1be72be5f?source=collection_archive---------27-----------------------

这是关于信息论及其与数据驱动型企业和战略的关系的系列文章的第三篇。虽然在每一部分都会有一些等式,但是对于那些对细节不太感兴趣而对含义更感兴趣的人来说,它们可以被忽略。前文关于互资的文章&奇怪的是麦克白的情节可以在这里找到

因果关系被高估

我们来创造一个情境。假设有一个随机过程,称之为 x。这个过程接受一些输入( ),然后根据以为中心的柯西分布产生一个输出。柯西分布很麻烦,因为它们几乎在所有方面看起来都像正态分布,但极端事件的可能性略高(尾部略厚)。结果是,虽然正态过程有明确定义的期望,并以预期的方式变化,但柯西分布有未定义的均值,并且变化无穷。让我们定义另一个称为 Y 的过程。Y 过程的结果由 X 引起,即:

注:所有图片由作者提供

y 由 X 引起,X 由。知道 X 的输入几乎不能给你关于 X 的信息,而知道 Y 只能给你关于 X 的有限信息。如果你想知道 X,你最好知道相关信息(Y)而不是因果信息()。

对因果关系的关注在很大程度上是由对虚假相关性的恐惧和对短暂关系的过度信任所驱动的。要了解这一点,请考虑通过以相等的几率随机选择 1 和 0 生成的以下序列:

在不知道生成函数的情况下,数列 2 和 3 提供了彼此的完全信息。当然,不能保证这种趋势会持续下去——事实上,它不太可能持续超过 3 或 4 位数。换句话说,我们可以制定一个简单的规则:当系列 2 表示 1 时,系列 3 表示 0,反之亦然。事实上,随着这个系列的继续,从这些观察中得出的任何规则最终肯定会灾难性地失败。

正如上面的例子所展示的,关注因果关系并不疯狂,但仅仅关注它是愚蠢到令人痛苦的愚蠢。众所周知,因果关系很难证明,尤其是在社会科学领域……尤其是在商业环境中。考虑以下一组连续事件:

在上图中,A 是事件 B & C 的实例化事件。A 的结果通过一些未知的因果过程影响 B & C。在一个泛乐观主义的世界里,我们会对事件 A、其结果以及导致事件 B 和/或 c 的过程了如指掌。我们可能无法访问这些信息的一些原因包括以下问题:

1.保密性:在某种意义上,了解 A 的结果或影响 B&C 的过程可能是非法的。参见:秘密信息和重大非公开信息示例

2.不可简化的复杂性:场景可能非常复杂,以至于没有人有足够的智力去理解事件 A 或因果过程中无数的混杂因素和相互作用。参见:公共健康和社会心理学

3.费用:从直接成本、技术债务或时间成本的角度来看,理解这一场景可能会非常昂贵。看看天体物理学(我们倾向于不去遥远的星球)和宏观经济学(我们倾向于不要让经济崩溃来看看会发生什么)

如果以上任何一条适用,一切都不会失去。如果 A 是 B 的因果关系,我们会期望它与 B 拥有大量(或至少非零)的互信息。A 和 c 也是如此,因为互信息是对称的:

相关事件(B&C)可以给出彼此的信息,即使它们不是因果关系(A)

更简洁地说,观察事件 B 给出了关于事件 C 的信息,即使 B 不是因果关系。但情况更好。B 不仅以一种相关的方式提供了关于 C 的信息,它甚至通过了 sniff 测试,因为它们通过 a 是相关的。如果你有一些关于 A & B 之间的一般关系的历史数据,那么它排除了理解连接 A 到 B 或 c 的复杂因果过程的需要

销售和 ARR 的增长是价格变动的原因,尽管它们在收益电话会议之前是保密的。他们网站上留下的评论数量是不保密的,虽然评论不会导致销售,但它很可能提供关于销售数量的信息(更多的销售->更多的评论)。同样,周四晚上的海鹰队比赛不会在工厂车间引发事故,但可能预示着事故的发生。因果关系是昂贵和误导的,相互提供信息的事件是廉价和有用的。

罕见事件信息不对称:一场游戏化危机

先说一个数据科学面试问题。通常,作为入门级候选人初步筛选的一部分,我喜欢在他们的简历中找到一个使用真实生活数据的项目实例。现实生活中的数据比学术和研究数据要糟糕得多。它充满了缺失数据、混合(整数和字符串)数据和异常值,这使得消费和建模信息变得非常困难。大多数谈话总是围绕着这些现实世界的考虑。你如何处理丢失的数据?通常的答案包括某种信息替换策略,比如用列的平均值替换它们。公平合理。我们如何处理畸形或混合的数据?同样,通常一个合理的答案是将字符串映射到数字。最后,您对大型异常事件做了什么?通常,答案是他们“删除了它们”,因为“不能指望你预测罕见的事件。”最终的理由是:它提高了模型的准确性。如果建立预测是一个游戏或竞赛,这是一个很好的答案,如果你想使用它,那就更糟了。

离群值非常重要。虽然去除它们可能是公平的,但我们也必须谨慎对待它们。我们可以从信息论和直觉的角度看到这一点。一如既往,让我们从理论开始。首先,让我们考虑一个结果的部分熵。

偏熵

部分熵是随机过程中特定结果的信息量。每个结果的部分熵之和就是随机过程 x 的熵。

具有不同可能性(x 轴)的事件的偏熵(y 轴)

从上面的图表中,我们注意到一些事情。首先,形成结果信息是不对称的。发生概率为 40%的结果不包含与发生概率为 60%的结果相同的信息。事实上,部分熵倾向于更罕见的事件;40%概率的事件比 60%概率的事件包含更多的信息。这使我们得出第二个观察结果,即概率接近 0 的罕见事件包含的信息量与非常常见的事件相同。发生概率为 96.4%的事件增加了大约 0.05 比特的信息,大致相当于发生概率为 0.7%的事件。忽视世界的 96.4%是不明智的,同样不明智的是忽视世界的 0.7%。

无情地忽略罕见事件的机制使得这种行为更加危险。让我们考虑结果为 A,B,C 的流程 X,这样:

假设我们有 1000 个观察值,我们将在这些观察值的基础上建立我们的模型。X 的熵是~.72。让我们考虑另一个来自熵的度量:

任何观测中包含的信息

观察的边际熵看的是单次观察所携带的信息量。这有助于评估删除(忽略)单个数据行的影响。通过应用边际熵和部分熵,我们可以评估忽略任何部分数据的影响。

每个事件的部分信息(H)与边缘信息(H );随着事件越来越少,边缘信息也越来越多

关于事件 C 的单个观察携带的信息是事件 B 的 3 倍,是 A 的 20 倍。如果没有充分的理由,您不会忽略关于 80% (A)结果的观察,并且您应该需要一个更好的理由来忽略关于 C 的观察。结果 C 也包含数据中总信息量的 8%。尽管忽略世界上 8%的人可能没问题,但格外小心是值得的。

删除这些事件不仅会丢失信息,还会对您的预测产生错误的信心。从交互信息的角度来看,一个好的预测是最大化模型和世界之间的交互信息。一旦我们去除了罕见的事件,我们就不再是在模拟世界,而是在模拟别的东西。我们正在对它的游戏化版本进行建模,其中的目标不是降低风险或获取回报,而是获得高分。这对于指导目的来说可能是好的,但是对于标记合理的决策来说是糟糕的。

撇开理论不谈,消除极端事件的实践也应该扰乱我们的内脏。绝大多数的汽车碰撞都涉及到低速时的挡泥板和保险杠。爱情在拥挤的车流中前行,在停车场倒车撞上横梁,诸如此类。如果您删除离群值,您最终会忽略您真正关心的碰撞类型。工厂不会突然停工,因为货物是在下午而不是上午到达的,经济也不会因为资产价格的日复一日的变化而崩溃。极端事件是指后果和信息不对称的事件。

信息风险:重新审视

的第一篇文章中,我们简要描述了一个叫做信息风险的概念。到目前为止,我们已经讨论了在一个不确定的世界中,我们如何更好地理解不确定性以及如何应对不确定性。我们还展示了对确定性的畸形认知或对“因果关系”的过度依赖,往好里说是有害的,往坏里说是灾难性的错误。在这些场景中,信息风险很大程度上意味着在我们不应该自信的时候过于自信。在下一节中,我们将看看当确定性系统——那些在观察和结果之间具有完美交互信息的系统——变得比我们希望理解的更复杂时会发生什么。

— — — — — — — — — — — — — — — — — — — — — — — — — — —-

【1】还有一个叫做没有免费的午餐的定理

【2】在以后的文章中,我们将把它视为“通道容量”

InfraNodus:文本数据分析的优秀工具

原文:https://towardsdatascience.com/infranodus-excellent-tool-for-textual-data-analysis-2b4839e6cd10?source=collection_archive---------10-----------------------

以新冠肺炎疫情期间的谷歌趋势查询为例介绍 InfraNodus

来源:作者图片

文本挖掘涉及将非结构化文本转换成结构化格式,以识别有意义的模式和新的见解。公司可以应用高级分析技术和其他深度学习算法来探索数据集中隐藏的关系。通过这种方式, IBM 定义了使用字符串数据格式的数据科学的广阔领域:演讲、声明、评论、诗歌等。如果我们能够用好的统计软件对它们进行训练,这些文本数据集是很方便的。

一个很好的选择就是使用文本网络分析作为核心框架的 InfraNodus 。我将展示一个使用 Google Trends 数据的例子来演示主要原则,但是值得探索 InfraNodus 提供的更多数据挖掘特性。

核心框架:文本-网络分析

InfraNodus 基于文本网络框架,遵循以下步骤:

  • 导入你的数据源,或者利用很多内置的 API 数据流,包括 Twitter feeds、 Google trends 、研究论文摘要和标题(PLOS、PubMed)、 RSS news feeds、 Evernote notes、
  • 得到一个网络结构:网络将从文本中生成。图表中最有影响力的单词显示得更大,而更频繁出现的单词被分组为簇,并具有不同的颜色。图表显示了主要主题和最有影响的术语以及它们之间的关系。
  • 生成洞察分析,侧重于情感、产品评论、使用谷歌查询的供需、聚类、词云可视化等。

用例:与 Covid 相关的 google 查询的词云

让我们举一个简单的例子。有了 Google Trends API,我们可以通过 Google 查询访问数据,并通过几次点击对其进行分析。这些参数是位置:美国,周期:31/10/2021,对关键字“covid”的相关查询

首先,我们用内置的 API 直接导入数据。我们可以看到四组主要的主题:第一组涉及疫苗接种和 Covid 的位置,第二组涉及 Covid 的病例、报告和基础数据,第三组涉及 Covid 的治疗,最后一组包含关于该疾病的资源。

来源:作者图片

接下来,我们生成单词及其关系的单词云。与标准的单词云相比,这个网络是与其他主题相关联的。调整节点的大小和它们的描述,我们得到了在 covid 期间在 Google 上搜索的术语的词云以及它们之间的关系网络。

来源:作者图片

Infranodus 还提供了一组关于数据关系的统计数据。人们最常使用“covid”关键字查找疫苗、测试、疾病、县和健康。

来源:作者图片

根据我们在媒体上看到的情况,我刚才提出的统计数据并不令人惊讶。但是想象一下,你有一个你一无所知的更广泛的文本数据集。在这里,InfraNodus 非常有用,因为它绘制了数据的结构,并帮助发现您以前不知道的关系。

上面的图表只是 InfraNodus 可以产生的一小部分知识。要查看其他令人兴奋的应用程序,请查看他们的一些教程。

结论

重要的是要提到定价。InfraNodus 有一个免费的、开源版本,需要一些编程知识。我用来准备图表的标准版本在云上工作,对于大多数较小的项目(9 欧元/月)来说很好。我也承认创作者没有把产品作为黑盒出售,而是在原文中共享基础设施。这对于那些可以在论文中引用来源和使用文本网络的研究人员来说很重要。

PS:你可以订阅我的 邮件列表 在我每次写新文章的时候得到通知。如果你还不是中等会员,你可以在这里加入https://medium.com/@petrkorab/membership

使用 AWS 将基础设施作为代码

原文:https://towardsdatascience.com/infrastructure-as-code-with-aws-207239573de?source=collection_archive---------18-----------------------

部署您的第一个云形成脚本

图片来自 Unsplash

基础设施即代码(IaC) 是 DevOps 的一个关键概念,在我们构建和定义生产级工作负载时,它在数据科学领域至关重要。IaC 允许开发者将项目的基础设施作为软件来管理。这使得开发人员能够轻松地维护和配置项目资源和架构中的变更。虽然与传统脚本类似,但 IaC 允许开发人员使用声明性语言来提供资源。有许多 IaC 工具可用,如 TerraformChefPuppetAnsible 。对于今天的演示,我们将使用特定于 AWS 资源的云信息。通过这篇文章,您将了解如何在一个软件文件中维护您的所有资源,并了解 IaC 带来的速度优势。没有 IaC,不同基础设施的手动部署的成本时间可以暴涨,通过将你的基础设施维护为软件,你能够从中央源轻松而快速地测试各种部署。在本文中,我们将探讨一个示例手动供应资源部署 CloudFormation 脚本在 AWS 上创建 REST API 和无服务器 Lambda 函数

注意:对于那些刚接触 AWS 的人来说(有一些经验来完全理解这篇文章是很好的),如果你想继续下去,请确保你在下面的 链接 做了一个帐户。确保还安装了 AWS CLI 来使用示例。我还将提供一个我们将使用的服务列表,以及更深入的定义。如果您已经熟悉这些服务,请随意跳到您感兴趣的部分。

目录

  1. AWS 服务
  2. 示例概述
  3. 手动部署
  4. 使用云编队部署
  5. 整个代码和结论
  6. 其他资源/参考资料

1.AWS 服务

【AWS API 网关(API GW) :允许开发人员创建、发布和监控安全 RESTful 和 Socket APIs 的服务。我们将使用这个服务来创建我们的 REST API。

AWS Lambda :无服务器计算服务,允许开发者运行代码,无需管理或提供服务器。我们将使用该服务在后端设置一个与 REST API 集成的示例无服务器功能。

身份访问和管理(IAM) :允许您通过权限和角色管理对 AWS 服务的访问。我们将为我们的 Lambda 函数创建一个角色,以便能够访问 API GW。

AWS CLI :要使用 AWS 资源和服务,您可以使用它们提供的 CLI,而不是控制台,以便于访问。

AWS SAM :云信息的抽象,有助于构建无服务器应用,查看 SAM CLI 了解更多信息。

2.示例概述

对于本文,我们将构建一个带有 API Gateway 的 REST API,它集成了一个无服务器后端 Lambda 函数,该函数处理来自我们 API 的 GET 和 POST 请求。第一步将详细介绍如何通过 AWS 控制台手动构建和部署这些资源,而第二步将使用 CloudFormation 来自动化和重复完全相同的过程。

3.手动部署

对于手动部署,我们必须在 AWS 控制台中工作。这本身已经是开发人员的一个坏习惯,因为我们不能在本地 IDE 上工作,而且在一个更大的项目中,很难在控制台内跟踪变更/开发。第一步,我们将创建一个 Lambda 函数示例。

作者截图

确保创建一个具有基本权限的角色,如果你想让你的 Lambda 使用不同的服务,比如 comprehension 或类似的服务,确保为该服务提供权限。关于 IAM 角色和权限的更多信息,请查看下面的资源

这里我们有一个示例“Hello World”lambda 函数,如果与 API Gateway 正确集成,它将返回所示语句。

现在我们已经配置了 Lambda 函数,我们希望设置我们的 REST API 以确保它可以与 Lambda 函数接口,因此我们转到 Amazon API Gateway。单击 create API 并从提供的选项中选择 REST API。

创建 REST API(作者截图)

现在,我们从 Actions 下拉栏创建一个 GET 方法,并确保 REST API 指向 Lambda 函数。

将 REST API 与 Lambda 集成(作者截图)

我们现在可以部署我们的 API 来测试它是否正确地与我们的 Lambda 函数集成在一起(为 stage 选择您想要的任何名称,我们将使用“prod”)。

作者截图

部署完 API 后,您应该能够在 prod 阶段看到一个 URL,如果您访问这个 URL,您应该会看到 Lambda 函数正在运行,返回“Hello World ”,正如我们在函数中描述的那样。

作者截图

Lambda 函数返回(作者截图)

4.使用云编队部署

这在一开始看起来并不太糟糕,只是几个需要几分钟的步骤,但是假设你有不止一个方法,不止一个 API,不止一个开发人员。你应该如何集中跟踪所有这些资源和任何变化。如果你想调整你的 Lambda 函数来和另一个 API 集成呢?您必须手动删除当前的方法或 API 吗?这将要求开发人员拥有跨帐户访问权限,并且在相互合作时能够在不同的帐户中查看和提供彼此的资源。所有这些都会导致时间、成本和资源的大量浪费,因此我们将使用 AWS CloudFormation 在几分钟内部署这个完全相同的示例,同时还让开发人员能够灵活自由地通过简单的脚本调整他们的基础架构。

首先,云的形成是如何工作的?我们将使用一个 YAML 文件来声明和提供我们部署到 AWS 的资源,以创建一个 CloudFormation 堆栈,其中包含我们项目所需的所有资源。我们将使用的模板被称为 SAM 模板 ,它是 CloudFormation 的抽象,具有相同的底层功能,但更适合于需要较少 YAML 代码的无服务器应用程序。对于那些不熟悉 YAML 的人来说,可以把它想象成类似于JSON (CloudFormation 使用两者),两者都具有构建大型声明性配置文件的功能。首先,我们进入本地代码编辑器,而不是控制台,并运行完全相同的 Lambda 函数。与此同时,我们将创建一个包含我们的基础设施的 template.yaml 文件。

项目的文件结构(作者截图)

在 helloworld.py 中,我们可以放入与控制台中完全相同的 Python 代码。

现在我们可以在 template.yaml 文件中定义 API 网关和 Lambda 函数了。为了首先构建这个文件,我们需要添加一些所有 SAM 模板通用的语句。

SAM 模板通用

现在我们可以在 CloudFormation 模板文件中添加一个名为“ Globals 的东西。全局是针对您将要部署的资源的通用配置,我们可以针对特定的资源类型将它们设置为全局,而不是为不同的资源指定相同的信息。对于这个用例,我们将以 Lambda 函数为例,尽管我们只有一个。

现在我们可以专注于我们的资源,这是一个 Lambda 函数和 REST API,我们在 template.yaml 文件中的 Resources 标签下定义它们。要访问在 CloudFormation 上定义无服务器功能的文档,请查看下面的链接

这里我们定义了一些创建 Lambda 函数的参数。对于这个事件,我们正在创建一个 REST API,因为它触发了我们的 Lambda 函数。有一组其他参数,您可以为您的无服务器函数指定,如 CodeURI、描述等,您可以在 CloudFormation 文档中遵循这些参数。一般来说,创建模板文件的最佳方法是访问 CloudFormation 文档,查看为您的特定服务/资源创建模板文件所接受的参数/语言。

现在我们可以部署模板文件了,为此我们将使用 AWS CLI 运行两个命令。

部署 CFN 模板

运行第一个 bash 命令后,您应该会看到创建了一个 sam 模板文件,这是我们在第二个命令中用来创建 CloudFormation 堆栈的文件。

作者截图

运行这两个命令几分钟后,您应该会看到在 CLI 中成功创建了堆栈,我们可以通过在控制台中转至 CloudFormation 来验证这一点。

云形成堆栈已创建(作者截图)

在这里,我们可以看到通过简单的 template.yaml 文件成功部署和创建的代码提供的所有资源。为了进一步验证这一点,我们可以单击创建的 API 并测试 URL,就像我们在手动部署中所做的那样,以确保在部署 API 后具有相同的工作功能

API & Lambda 来自 CFN 模板(作者截图)

为了清理,我们可以通过 CLI 运行一个 delete stack 命令来销毁为此演示创建的所有资源。运行下面的命令,您应该看到正在删除所有资源。

删除堆栈(作者截图)

5.整个代码和结论

https://github.com/RamVegiraju/Serverless-CFN

要复制示例并访问完整演示的代码,请查看位于上方的库。起初,CloudFormation 看起来令人生畏,因为它有一种奇怪的 yaml 语法和语言,掌握 CloudFormation 肯定需要一个学习曲线。但是,如果您对该服务有了一定的了解和熟悉,它将帮助您从一个中央模板文件中以简单高效的方式构建和管理极其强大的应用程序。虽然这种比较显示了手动部署与 IaC 部署在方便性和效率上的差异,但是当您的项目增长并且有多个开发人员在一个项目上工作时,这种差异会更加明显。关于接下来的步骤,请看这篇文章中的 CloudFormation 如何无缝地帮助在 AWS 中构建 CI/CD 管道。

我希望这篇文章对任何试图了解 IaC、CloudFormation 或 AWS 的人有所帮助。欢迎在 LinkedIn 上与我联系,或者在 Medium 上关注我,了解我更多的写作内容。分享任何想法或反馈,谢谢阅读!

其他资源/参考资料

云形成 Udemy 大师班

AWS 无服务器 Udemy 类

将历史要素数据纳入 SageMaker 要素库

原文:https://towardsdatascience.com/ingesting-historical-feature-data-into-sagemaker-feature-store-5618e41a11e6?source=collection_archive---------13-----------------------

如何通过直接写入 S3 来回填 SageMaker 离线功能库

简·安东宁·科拉尔在 Unsplash 上拍摄的照片

这是怎么回事?

亚马逊 SageMaker 功能商店是一个完全托管的、专门构建的存储库,用于存储、更新、检索和共享机器学习(ML)功能。它于 2020 年 12 月在 AWS re:Invent 上推出,并迅速成为 SageMaker 家族中最受欢迎的服务之一。自从 re:Invent 以来,我交谈过的许多 AWS 客户都对 SageMaker 功能商店(SMFS)表示了兴趣。

其中一些客户拥有历史特征数据,他们希望将其迁移到 SMFS 离线商店,该商店可以存储大量的特征数据,这些数据用于跟踪历史特征值,并为模型开发或批量应用创建训练/测试数据。

将历史数据摄取到 SMFS 线下商店的一个主要挑战是,用户在使用摄取 API 时将被收费,即使他们只想回填历史数据。如果客户想要将数 TB 的数据迁移到 SMFS,这些费用可能会快速增长。

在这篇博文中,我展示了如何将历史特征数据直接写入 S3,它是 SMFS 线下商店的支柱。使用这种方法绕过了摄取 API,大大节省了成本。

问:我来这里只是为了代码,在哪里可以找到它?

甲:这里你去:)

快速估算成本

这款笔记本是一个很好的例子,展示了如何使用专用摄取 API 将数据摄取到 SMFS。根据亚马逊 SageMaker 定价网站,用户将被收取每百万写请求单位 1.25 美元的费用(这是针对地区美国东弗吉尼亚州——不同地区可能适用不同的费用)。

Sagemaker 功能商店的定价

一个写入请求相当于 1KB 的数据,因此每 1gb(= 100 万 KB)写入 SMFS 的成本为 1.25 美元。我曾与拥有数兆字节历史特征数据的客户交谈过,他们只想填充 SMFS 的线下商店。如果他们使用 API 回填这些数据,他们将被收取数千美元的费用。相比之下,将文件直接放入 S3要比便宜(在美国东弗吉尼亚州每 1000 个文件 0.005 美元)。

如何将要素数据直接写入 S3

游戏计划很简单:我们将创建一个特征组,修改相应的数据集,并按照 SMFS 线下商店数据格式直接保存在 S3。因此,该数据集将在 SMFS 线下商店中提供。

准备数据

在这个练习中,我将使用一个代表信用卡交易的合成数据集。该数据集在 SageMaker 样本 S3 桶中公开提供:

一些列是类型为 object 的,我们需要将它们转换为字符串,以便 SMFS 接受数据(参见本页了解 SMFS 支持的数据类型):

SMFS 的每个数据集都需要每个数据点的时间戳。由于我们的数据集没有时间戳,我们需要手动添加它:

创建功能组

数据集现已准备就绪,我们可以创建相应的要素组了。为此,我们首先像这样定义特性组:

现在我们已经准备好创建特性组了。请注意,创建要素组不同于获取数据,并且不会产生费用。该功能组将被注册到 SMFS,但它将保持为空,直到我们用数据填充它。我们还需要提供唯一标识记录的列名,即主键和包含每条记录时间戳的列名:

到目前为止,我们遵循的步骤与您通过 API 将数据导入 SMFS 时遵循的步骤相同。现在,我们将把数据直接输入 S3。

将数据写入 S3

将数据写入 S3 以便在 SMFS 可用的关键是这个文档。我们对用于组织离线商店中的文件的命名约定特别感兴趣:

S3 线下商店的命名惯例

要重建这个对应的 S3 文件路径,我们只需要表名,以及我们之前创建的事件时间戳的年、月、日和小时:

需要注意的是,在使用摄取 API 时,SMFS 将创建额外的字段:

数据集的附加字段

因为我们没有使用 API,所以我们需要手动添加这些额外的字段。这两个时间戳( api_invocation_timewrite_time )与我们之前创建的事件时间戳不同。但是,出于演示目的,可以重用相同的时间戳:

要为数据创建有效的文件名,我们可以将事件时间和一个随机的 16 位字母数字代码连接起来。最后一步,我们现在可以将数据保存为 S3 的拼花文件:

检查摄取是否成功

SMFS 离线存储通过 Athena 查询进行访问,因此检查数据获取是否成功的最快方法是编写一个 Athena SQL 查询,从要素存储中检索数据:

如果摄取成功,从功能存储中检索的数据集将与我们上传的数据集相同。

结论

我们已经成功地用历史数据回填了 SageMaker 离线特性存储,而没有使用摄取 API。为此,我们修改了数据集,设置了适当的 S3 文件夹结构,并将数据集直接上传到 S3。

这种方法允许用户节省摄取 API 的费用,这对于大量的历史数据来说是相当大的。

【2021 年 4 月 29 日编辑:讨论更高级场景的后续博文可在此处找到

人工智能入门要素——中小企业的 3 个风险、2 个恐惧和 2 个机遇

原文:https://towardsdatascience.com/ingredients-for-getting-started-with-ai-3-risks-2-fears-and-2-opportunities-for-smes-f0f1ecec4a4?source=collection_archive---------45-----------------------

自 20 世纪 50 年代以来,人工智能(AI)一直是计算机科学的一个分支,它处理智能行为的自动化,具有巨大的创新潜力。人工智能的一个重要方面是机器学习,今天人们越来越多地谈论它,因为它对经济过程的影响越来越大。

Unsplash
上,刘宇英拍摄的照片人工智能正在走向所有公司——不仅仅是初创公司、大型科技公司和企业

在高科技、电信和金融服务领域,这些基于数据分析和解释的系统正越来越多地被用来取代人类。语言学人工智能已经出现在更快更好的翻译程序中,这些程序可以同时跟随多语言对话,使以前的口译员过时。在自动化领域,视觉人工智能的使用越来越多,它通过自主模式识别在工业质量控制和制造自动化中发挥着重要作用,并可以提供决定性的竞争优势。部分甚至完全自动化的仓库管理已经成为可能,在成本有效的条件下取代人工。

附身摄影Unsplash 上拍照

让我们来看看对中小型公司有特别影响的方面。一方面,中小企业有许多机会研究这一课题,并根据自己的利益开发这一课题。另一方面,也有与触及这个话题相关的风险和恐惧。

中小企业人工智能的相关风险

提前精确定义要处理的用例对于成功是相关的——人工智能素养是关键。有几个公司从用例开始的例子,因为它们只是被认为有趣。没有充分考虑这个项目会给公司带来的经济利益。幸运的是,那些刚刚起步的人可以从别人在他们之前犯的错误中吸取教训。

为了选择一个有希望的开始的正确用例,一定水平的人工智能知识是必不可少的。我们所说的人工智能素养是指:

  1. 首先要理解什么是人工智能
  2. 理解人工智能能为你的公司做什么
  3. 理解构建和维护一个有效的人工智能系统需要什么

两个关键的成功因素

第一个因素是我们需要区分大小项目以及它们需要的投资。相应的项目可能需要 6 个月到几年的时间才能实际实施,从而富有成效地产生投资回报。

第二个因素是,我们至少需要对实现一个项目所需的大量辅助活动有一个临时的概念。例如,研究表明至少一半的预算应该用于文化变革。

例子

  1. 谁将是我项目的最终用户,他们需要什么样的培训/指导?
  2. 我需要在我现有的系统中构建什么样的 API 来实现这一点?

建立预测性维护系统是一个巨大的挑战。但是,如果没有与现场机器的连接,或者没有办法建立从物联网传感器到中央 IT 系统的数据管道,会发生什么呢?也许这只是一个没有开始的项目。

风险 1——由于错误的开始,兴趣不大

如果你正在研究人工智能,并且你没有缩小你想要处理的用例的范围,包括产生某种商业价值,那么就很难获得内部的支持来成功地完成目标项目。如果你想知道——是的,这在过去发生过很多次。

例如:如果创建的第一个用例是开发翻译引擎,那么在业务中可能会有重大的利益冲突。例如,如果公司中的 10 名翻译因此失业,就是这种情况。很难不中断地实施。

原因:你需要这些翻译来构建系统。他们不太可能提供支持。如果他们成功了就会被裁掉,那么让有技能的人加入团队是有问题的。

这是为什么选择正确的用例来开始很重要的众多原因之一。

风险 2——开发的系统没有考虑可信任的人工智能

简而言之,如果人工智能是合法的、健壮的和合乎道德的,它就被认为是可信的。也就是说,它符合规则,从某种意义上说,它是健壮的,因为它在类似的情况下表现相同,但也是无害的。从伦理定义的标准被考虑的意义上来说,它是伦理的。

例如,微软开发了一个人工智能驱动的推特机器人,它自发地开始发布攻击性和种族主义的推特。在这里,开发人员忽略了解决可信性问题。微软现在有一个框架来处理这些潜在的问题。

忽视如何让你的人工智能系统值得信赖是一个公司可能犯的大错误之一。如果公司开发的系统被证明是不可信的,那么将很难回到最初设想的系统中。我想到了剑桥分析。必要的信任还在吗?

风险 3——因为竞争对手使用人工智能而不得不停业

人工智能正在成为一种趋势,而且很可能在你没有注意到的情况下就已经出现了。例子包括随着优步的到来而出现的出租车行业,或者随着 Airbnb 的出现而出现的旅游业,无论有没有人工智能的帮助,该行业都在被颠覆性地重塑。如果一家公司自己的竞争对手可以实现某些流程的自动化,从而削减各种成本,他们就可以提供更低的价格,并将竞争对手挤出市场。

恐惧 1——失业

人们害怕失去工作。在某种程度上,这当然是可以理解的。在未来几十年,某些工作将被人工智能系统取代或至少补充。当然,人工智能系统并不完美。我们知道我们需要验证翻译系统的输出(事实上,我现在正在这么做,因为这篇文章是从德语翻译过来的)。也就是说,这个行业的工作岗位不会被淘汰,只是在关注点方面会发生变化。如今,翻译人员可以检查由系统翻译的文本,并确保传达了原文内容。翻译人员现在可以在同样的时间内处理更多的文本。此外,他还可以专注于其他任务。每个人都必须考虑人工智能如何改变他们的工作,并抓住机会进行再培训或升级。

恐惧 2——机器做出错误或莫名其妙的决定

人们担心机器会在特定环境下做出伦理上有问题或错误的决定。自动驾驶汽车发生事故会怎么样?或者当你必须决定是轧死一个行人还是撞上一棵树时。这些都是行业需要解决并正在努力解决的复杂问题。正在开发新的框架来解决这些问题。

机遇

我们可以将围绕人工智能使用的大部分风险和恐惧转化为机遇。工作可以变得更有趣,在空间和时间上更容易接近。

当枯燥、重复的任务减少到最低限度时,工作会变得更有趣。这允许新的任务和责任向员工开放。有很多工作已经改变的例子。自动驾驶汽车正在改变出租车或卡车司机的工作模式。有 AI 系统可以帮助医生诊断癌症疾病(肿瘤检测)。当我们搜索一些东西时,我们都使用谷歌。或者当我们想开车去某个地方时,我们依靠谷歌地图。当我们写文章或使用某种营销自动化时,我们使用 Grammarly 或 DeepL。人工智能已经存在,帮助我们节省时间,因此我们有新的资源用于生活中更重要的事情。

机会 1 —与其他公司联手开发或投资解决方案

如果你是一家小企业,你可能很难独自解决人工智能问题。但这并不意味着你不应该参与人工智能的话题。某些解决方案可以购买,或者免费使用。某些解决方案也可以针对公司之间的合作,以解决网络中的共同问题,尤其是与初创公司合作或由初创公司解决。

例如:德国公司 ControlExpert 目前正在对汽车损坏的索赔处理进行数字化。他们与汽车修理厂和保险公司合作。

机会 2 —教育员工

让你自己的员工了解即将发生的事情,对留住员工有很大帮助。各种研究表明,高管层的认同是成功的关键。需要展示的是有哪些选择,公司的未来会是什么样子。同时,在员工身上投资,让他们在自己的领域接受教育或再培训。这最大限度地降低了职业风险。

人工智能为中小企业带来的附加值

总的来说,如果中小型企业独自行动,开始使用人工智能可能会很困难。无论如何,人工智能都将到来,我们需要并需要同时减轻机遇和风险。对中小企业来说,附加价值是能够合作地联合力量,获得外部帮助,并通过不太复杂的基础设施快速实施可行的解决方案。

关于我:我是一名分析顾问,也是当地一所商学院“人工智能管理和人工智能运营”研究的主任。我的使命是帮助组织利用人工智能创造商业价值,并创造一个数据科学家可以茁壮成长的环境。 报名参加我的 通迅 获取新的文章、见解,并祭上 AI 管理 这里 。或者访问我的网站获取更多文章,网址为www . ai bridge . ch,这是本文最初发表的地方。

创新和预测分析

原文:https://towardsdatascience.com/innovation-predictive-analytics-aac44954651f?source=collection_archive---------23-----------------------

浅析索尼随身听和苹果 iPod

版权所有 2021 —作者保留所有权利

还是那句话,你不能向前看,把点点滴滴串联起来;你只能回头看才能把它们联系起来。所以,你必须相信这些点在你的未来会以某种方式连接起来。你必须相信某些东西——你的勇气、命运、生活、因果报应等等。这种方法从未让我失望,它让我的生活变得完全不同。

在他 2005 年在斯坦福大学的毕业典礼上的演讲中,史蒂夫·乔布斯对他的创新过程的本质进行了如上陈述。数据和分析都没有被提及。它们是为“向后看”而保留的,例如,回顾过去。未来仍然是一块干净的画布,由创新者的想象来描绘。

P 预测分析是一种受人尊敬的分析形式,被公司用来绘制未来的产品路径。它广泛使用算法、数据挖掘和数据解释来整理市场需求和趋势。预测分析还结合了一系列强大的人工智能(AI)工具。这些可以包括机器学习(ML)、模式识别(PR)、自然语言处理(NLP)、情感分析和情感识别(SAER)等,以在预测过程中实现更精确的结果。

然而,预测分析是容易出错的。它受市场变化的影响,经常产生可疑的结果。分析过去和现在的数据并不能保证绝对的结果。事实上,谈到创新,尤其是“颠覆性创新”,依赖预测分析可能会让公司走上灾难性的道路。

新的想法、过程、模型和进步始于创新,有希望产生基于创新过程的工作模型。预测分析指导着这一过程,同时试图准确回答这一创新将在何时、何地、以何种方式以及为何改善产品的现状。

数据分析需要一种考虑创新并负责任地使用预测分析的方法,而不是一个可靠的水晶球。

创新的最终目标是创造一种新的商品或对现有产品的重大改进——无论是大的还是小的。预测分析能帮助还是阻碍这一过程?面对未知的未来,创新会自动否定预测分析对未来市场趋势的洞察吗?一个人如何以理智的方式使用创新和预测分析来促进公司的健康发展?

索尼随身听和苹果 iPod

对上述问题的回答构成了关于创新型公司的研究和文献的相当一部分。虽然许多理论似乎在特定的背景下有效,但在任何使用分析进行创新的尝试的核心,也有从合理的理论中收集的基本公式。应对创新,主要是颠覆性和激进的创新,需要一种新的分析模式。这不仅仅是推断数据和查看销售图表的问题,因为这只有在创新渗透到市场之后才会发生。

即使应用预测分析也可能是大错特错的,这是索尼的惨痛教训:

索尼突破性的随身听卡带播放器被暂时搁置,因为市场研究表明,消费者永远不会购买没有录音能力的磁带播放器,而且消费者会因为使用耳机而感到烦躁。但是森田无视市场部的警告,而是相信自己的直觉。这款随身听的销量超过了 3.3 亿部,并创造了全球个人音乐设备文化。

索尼的市场数据指向了随身听的彻底失败——苹果 iPod 的前身。事实上,一个颠覆性创新导致了另一个颠覆性创新,两者都在当前所有的市场数据和分析中取得了成功。索尼和苹果都是由依靠直觉、直觉和对消费者的深刻理解的人引导的。他们不允许市场研究或预测分析成为所有决策的起点和终点。也许,特别是对于史蒂夫·乔布斯来说,这是由于市场营销人员的不屑,他们仅仅依靠预测数据来确定他们的观点。

在处理创新时,数据,即使是预测性数据,也可能具有欺骗性。克里斯腾森的基本问题,一个他纠结了超过 25 年的问题,又回来困扰我们:‘是什么促使顾客购买并使用某个特定的产品或服务?’

索尼随身听和苹果 iPod 是如何回答这个问题的绝佳例子。随身听发布于 1977 年(2010 年停产)而 iPod 发布于 2001 年 10 月 23 日——24 年的差距。从表面上看,这两种颠覆性的创新似乎没有什么联系。毕竟,随身听只是一个带耳机的盒式音乐播放器。然而,不仅如此,随身听给市场带来了一种新的听音乐的方法,创造了一种更“私人”的体验。

很少有研究者追踪从随身听到 iPod 的线索,这是试图理解和评估创新时的一个巨大错误。作为一台机器,随身听可以说是两者中更具颠覆性的创新。随身听代表了一种新的进程,最初是为一群特殊的旅行记者和商人设计的。然而,iPod 使用不同的技术和完全不同的方法向消费者提供音乐,扰乱了同一个市场。

这款随身听迎合了一种以前未被认识和分类的消费者需求。如前所述,随身听的预测数据是绝对错误的。索尼领导层做出的假设大多不一致,导致发布推迟。市场分析师的逻辑推断未能发现对该设备的任何需求,因为没有先例可以指导分析师。在当前的市场中,完全没有数据来推断出一个合理而精确的分析。随身听代表了对本能和直觉的一次豪赌。

颠覆是一种对创新的竞争性反应理论,为寻求驾驭威胁和机遇的管理者提供了有价值的见解。但它没有回答一个关键问题,即公司应该如何创新才能持续增长。它没有提供具体到哪里寻找新机会的指导,也没有具体说明你应该创造什么样的产品和服务让客户愿意购买。

虽然传统观点认为苹果的 iPod 具有颠覆性,因为它进入了一个全新的、以前未知的、未被发现的市场,但事实并非如此。史蒂夫·乔布斯不仅自己是个音乐迷,而且知道随身听及其成功。在这里,向大众提供音乐并不是破坏。乔布斯颠覆的是他专注于消费者需求的能力。正如 Christensen 等人评论的那样,“要将创新从漫无目的提升到可预测,你必须理解潜在的因果机制——消费者在特定环境下试图取得的进步。”⁴

为了让 iPod 获得成功,苹果公司将其创新技能应用于多个领域:

苹果首先通过以下方式改进了架构:

  • 为 iPod 的屏幕和其他技术申请专利;和
  • 获得东芝公司开发的一种创新小硬盘的使用权,这种硬盘可以存储 1000 首歌曲。

它在用户界面和用户体验方面应用了其著名的功能,使用户可以轻松地从一首歌切换到另一首歌。

最重要的是,苹果利用其拥有从硬件到软件的端到端链的公司哲学,在发布 iPod 前 9 个月发布了 iTunes 商店。换句话说,iTunes Store 最初是为 Mac 而不是 iPod 发布的。苹果颠覆了原来的颠覆者。

索尼犯了一个经典的错误,认为随身听拥有市场,没有看到新技术的到来。乔布斯利用他天才的创造性火花和对消费者总是想要更多、更好、更小和更可靠的直觉理解,证明了“创新型公司的标志不仅在于它首先提出新想法,还在于它知道当发现自己落后时如何跨越。”⁵

苹果和乔布斯都不是真正的创新者,让消费者能够把音乐放在口袋里。然而,他们所做的是:

  • 仅仅根据随身听的流行程度就认识到巨大的市场潜力;
  • 理解整个链条上的创新是成功的主导因素;
  • 理解技术发展超越盒式磁带的需要;
  • 拥有从歌曲销售到 iPod 本身的整个过程,包括硬件和软件,把顾客留在苹果的世界里;和
  • 给消费者更好的体验。

正如诺基亚和黑莓忽视了智能手机,百视达忽视了网飞,索尼也从未预见到它的到来。这种颠覆确实发生在技术领域,但它成功了,因为它没有止步于一项纯粹的技术发明。苹果将市场、创造力、本能、直觉和市场数据结合起来,颠覆了一个从颠覆中诞生的市场。

一个想法要真正产生影响,它需要被广泛采用,这意味着如果它要改变整个行业或领域,它需要取代现有的已在使用的模式。这一转变过程与之前的发现和创新一样具有挑战性和重要性。⁶

iPod 的故事和它的发布经常被美化到事实与虚构无法区分的程度。苹果创造了一种新产品,但是这种产品的市场已经因为随身听而为人所知。苹果增加了个人可以随身携带的音乐数量和获取音乐的方式,并确保自己“拥有”音乐的整个消费者价值链。它也创造了一个美丽的装置。简而言之,苹果公司以这项创新的因果机制为中心,提出了一种处理预期结果的新方法。

将我们的理解从有根据的猜测和关联转移到潜在的因果机制是意义深远的。真正揭示因果机制改变了我们解决问题的方式——也许更重要的是,阻止了问题的发生。⁷

唯一不变的是变化

S o,如果数据可以误导,直觉不正确,那还剩下什么?好吧,一个人可以什么都不做——但这将是一个根本性的错误。放弃梦想不是创新的方式。此外,如果创新没有发生,那么再多的预测分析也无法帮助发现下一步该做什么。在她著名的推文中,小野洋子写道:[‘记住,我们每个人都有改变世界的力量。’](https://twitter.com/yokoono/ status/4746029903) 这句话抓住了创新过程的内在魄力。然而,仅靠一个人是不足以让创新取得成功的。奇怪的是,小野洋子还写了一份声明,被她的丈夫约翰·列侬在一次采访中引用:‘一个人做的梦只是一个梦。你们一起做的梦就是现实。⁸

矛盾的是,创新需要一个人的力量和许多人的力量。它可能始于一个人头脑中闪现的天才,但实现的愿望将被那些敢于梦想的远见者所接受。创新是一个人的力量,敢于梦想——然后邀请其他有远见的人和你一起改变世界——把你的梦想变成现实。一旦你的目标被其他人认同,你的创新愿景已经开始——那么,也只有到那时,看看数据。通过创新和预测分析的正确结合,梦想确实会变成现实。人类思维的独创性和创造性是无限的。人们不需要更多的证据来证明小野洋子的话的真实性,“你们一起做的梦就是现实。”

创新会带来持续的变化。这种变化将反映在应计数据中。利用数据分析过去和现在的趋势、想法和市场行为。预测分析将绘制出市场内的近期地图,从而引发渐进式或可持续创新。然后,市场将转向或受制于颠覆,带来变革并引领创新。创新和预测分析是由创新创造力和数据支撑的无限变化循环。

参考文献:

  1. 克里斯滕森,C.M .,狄龙,k .,霍尔,t .和邓肯,D.S. (2016)《与运气竞争:创新和客户选择的故事》,哈珀商务出版社,纽约,纽约,Kindle 版,位置 1227。
  2. 同上,位置 819
  3. 同上,位置 424
  4. 同上,位置 460
  5. 艾萨克森,W. (2011)《史蒂夫·乔布斯:独家传记》,Little,布朗图书集团,纽约,纽约,Kindle 版,位置 8965。
  6. Satell,G. (2017)“测绘创新:导航颠覆性时代的剧本”,麦格劳-希尔教育,纽约,纽约,Kindle 版,位置 1183。
  7. 克里斯滕森等人,参考文献。1 以上,位置 491。
  8. sheff d .(2000 年)“我们所说的一切”,纽约圣马丁出版社,第 16 页

(上面的文章是我最初的学术文章的节选版&,*‘论文和对偶——创新
和预测分析:σ(过去+现在)数据≠未来成功’
,最初发表于 《应用营销分析》第 6 卷第 3 期,亨利·斯图尔特出版的期刊 。整篇文章的 PDF,可以使用ResearchGate* 谷歌学术 fig share,或者直接在LinkedIn上联系作者。在所有情况下,如果您引用这篇文章或整篇文章,需要完全归功于原作者。)

关于作者: Ted Gross 担任 R & D 的 CTO & VP 多年,擅长数据库技术,专注于 NoSQL 系统、NodeJS、MongoDB、加密、AI、创新&混沌理论。他还擅长虚拟世界技术&增强现实。他还在专业期刊和在线@ Medium & LinkedIn 上发表了许多关于技术主题的文章。 他也是文学小说、儿童书籍和各种非小说类文章 的作者。他的短篇小说集, 【古代故事,现代传说】 获得了极好的评价。

可以通过电子邮件联系 Ted推特(@ tedwgross);LinkedIn中等

简而言之:用于解释 DNNs 的遮挡分析

原文:https://towardsdatascience.com/inshort-occlusion-analysis-for-explaining-dnns-d0ad3af9aeb6?source=collection_archive---------35-----------------------

也许找出模型失败原因的最简单的方法。

有大量的解释方法用于解释深度神经网络(DNNs),每种方法都有其优缺点。在大多数情况下,我们感兴趣的是局部解释方法,即对于特定输入的网络输出的解释,因为 dnn 往往过于复杂,无法进行全局解释(独立于输入)。

一般来说,所有的局部解释方法都有一个共同的目标:忠实地(即准确地)表示要解释的函数 f (例如一个 DNN),至少在要求它们解释的输入周围是局部的。

当然,这样的解释也必须是人类可以理解的,才是有用的。最简单的方法是给每个输入维度分配一个重要性分数,也就是创建一个属性图。归因方法将模型输出的责任分配给给定输入的每个维度。

在这篇短文中,我将介绍一种基本的归因技术:遮挡分析。基本概念非常简单:对于输入的每个输入维度 x ,我们评估缺少该维度的模型,并观察输出如何变化。
特别是,如果| |
f(x)—f(x _ without _ I)| |很大,那么维数一定很重要,因为去掉它会大大改变输出。

遮挡分析通过观察去除面片时模型输出 y 的变化来计算每个面片的重要性。单个结果可以组合成一个属性图。作者图片

遮挡分析的优势

如果你的维度是独立的,那么遮挡分析是完全可信的,因为你精确地测量了每个维度的边际效应。

遗憾的是,在大多数情况下,比如图像数据,情况并非如此。在这里,你会被建议删除整个补丁,而不是单个像素。这个想法是,通常单个像素的信息可以从它的邻居重建。因此,如果你有一张猫的图像,删除一个猫像素永远不会对输出产生大的影响,而删除覆盖耳朵的补丁可能会导致模型对“猫”的预测明显下降。

遮挡分析的另一个好处是它是一种的事后方法。这意味着它可以用来解释任何(已经训练好的)模型。不需要重新训练。该模型甚至可以是一个不可微的黑箱。只要您可以输入和接收输出,您就可以使用遮挡分析。

遮挡分析相对于基于梯度的解释方法的另一个优势是,它甚至可以处理局部平坦的函数,没有梯度或梯度非常小。

必要的考虑

但是删除一个维度实际上意味着什么呢?毕竟,我们的模型总是接受相同大小的输入。删除维度意味着将其设置为具有“0 信息”的值。这取决于数据集这个值是什么。对于图像数据,我们通常使用平均 RGB 值。对于其他数据类型,通常将维度设置为 0 就可以了。我们将在后面看到其他考虑因素。

正如您可能已经猜到的,遮挡分析带有一个很大的警告:我们必须评估每个这些扰动输入的模型。如果您的输入有多个维度,例如一个 256x256 像素的图像,那么您必须运行 256x256=65.536(!)次来获得完整的分析。在大多数情况下,这是非常昂贵的,尤其是当您想要对整个数据集运行分析时。

一种降低计算成本的方法是将多个特征一起移除(例如,图片中的 8×8 正方形)。这只对某些维度在语义上属于同一类的数据类型有意义。

高级:分配转移

遮挡分析还有一个问题谈的不多:分布偏移(比较胡克等人)。如果我们仔细想想,我们在分析中观察到的输出变化除了信息被删除之外,还有另一个原因:受干扰的输入不再位于我们训练模型的数据分布中。

在机器学习中,我们通常假设模型将在来自与训练样本相同分布的数据上进行评估。如果不是这种情况(即,如果我们移除像素),那么模型输出可能是任意错误的。虽然移除单个像素的效果通常可以忽略不计,但移除整个面片是远离训练数据流形的一大步,因此会对输出产生更大的影响。

我们不得不接受这两个原因的纠缠,但是有办法缓解这个问题。基本思想是在删除信息的同时仍然保持接近数据流形。这意味着使用更复杂的信息去除技术,仍然使图像看起来像自然图像。

一种方法是模糊掉要“移除”的补丁。这不是最有效的方法,但它至少应该消除细粒度的纹理信息,并且易于实现。

更好的方法是使用修复算法:只需使用另一个模型来猜测(即修复)缺失部分的内容。实际上没有添加信息,因为修补仅依赖于图像的剩余像素,但是结果看起来仍然接近正常图像,因此更接近训练数据。你可以使用一个复杂的算法,比如由于等人开发的算法,或者依靠容易访问的库,比如 openCV T5。

使用修复算法的警告是:1)它会使该过程在计算上更加昂贵,2)您必须让它运行,以及 3)如果您不使用标准的基准数据集,您可能必须重新训练它。

结束语

由于其计算成本,遮挡分析当然不是一个适用于所有场合的工具,但肯定有其用途。尤其是如果您的数据很小,或者您只是想要一些易于实现且可靠的东西(只是要小心补丁大小),遮挡分析可以大放异彩。一个密切相关且更复杂的方法是 Shapley 值。不幸的是,它们的计算成本甚至更高。如果你正在使用一个可微分的模型,也许下一个最好的简单方法是基于梯度的解释方法

希望你学到了有用的东西!

从里到外的断续浓缩咖啡

原文:https://towardsdatascience.com/inside-out-staccato-espresso-f836fddc0bd1?source=collection_archive---------15-----------------------

咖啡数据科学

向豆子的内部寻找答案

之前,我研究过咖啡渣中粉末的来源。即使是粗磨咖啡,也有相当比例的细粒,我怀疑其来源是咖啡豆较软的内部。基于这个想法,我想如果我能分离出那些微粒,我能做出不同的分层镜头吗?从外壳的粉末中分离出这些粉末会在味道或提取方面有所不同吗?

我称之为由内向外的断奏浓缩咖啡,因为我把咖啡豆的内部放在外层。

准备

我从一个非常粗糙的研磨设置开始。我之前发现这种方法产生的粉末(<400 微米)与普通浓缩咖啡研磨出的粉末味道不同。我推测这些粉末来自冰球内部。我通过筛选去除这些颗粒,然后在普通的浓缩咖啡中研磨粗颗粒(500 微米)。最后,我筛选那些研磨。

研磨和筛分:

所有图片由作者提供

然后,我像做分烤断奏击球一样准备冰球:

以下是去除内部粉末前后的研磨情况:

左:S50 研磨,右:S7 仅研磨来自 S50 研磨的粗粒(500um)。

筛选 S50 和 S7:

左:S50 地,右:S7 地。

圆盘准备:

左:内部细粒,中:外部细粒,右:粗粒层(> 500um)。400 微米和 500 微米之间的中间层未显示。

这是测试镜头的重量分析。内部粉末占全部咖啡渣的 14%,占全部粉末的三分之一。

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

设备/技术

浓缩咖啡机:金特快

咖啡研磨机:利基零

咖啡:中杯家庭烘焙咖啡(第一口+ 1 分钟)

镜头准备:断续浓缩咖啡

输液:压力脉动

过滤篮:20g VST

输入/输出:22g 输入,约 24g 输出

其他设备:Atago TDS 测量仪,Acaia Pyxis 秤

镜头对比

我对两次烘烤的两对镜头进行了比较。TDS 和 EY 合计略有改善。最引人注目的是味道的改善。这更多是由苦味和酸味成分而不是味觉的其他成分驱动的。

****

拍摄时间大致相同。

这个镜头是耗时的,因为双重研磨和双重筛选。一台机器可以自动完成这种双重研磨和双重筛选,因此就商业用途的规模而言,这是一个技术问题。对我来说,我喜欢学习咖啡豆的不同成分是如何影响味道和提取的。我认为我们将 bean 视为同质结构,但事实并非如此。希望更深入的了解有助于推动创新。

如果你愿意,可以在 TwitterYouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。也可以在 LinkedIn 上找到我。你也可以关注我的媒体订阅

我的进一步阅读:

我未来的书

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

使用图像处理测量咖啡研磨颗粒分布

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡滤纸

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维修

咖啡评论和想法

咖啡实验

内部量化感知训练

原文:https://towardsdatascience.com/inside-quantization-aware-training-4f91c8837ead?source=collection_archive---------10-----------------------

理解大数据

深入理解高效模型优化技术的指南

凯文·KuUnsplash 上拍摄的照片

介绍

随着我们学习利用人工智能来完成各种简单和复杂的任务,深度神经网络的现实世界应用日益增加。然而,深度神经网络的问题是它们涉及太多参数,由于这些参数,它们需要强大的计算设备和大容量存储器。这使得它几乎不可能在 Android 等计算能力较低的设备和其他低功耗边缘设备上运行。量化等优化技术可以用来解决这个问题借助不同的量化技术,我们可以将参数的精度从 float 降低到 int8 等较低精度,从而实现高效的计算和更少的存储量。最佳量化技术之一是量化感知训练。在本帖中,我们将详细了解它的机制。

什么是量化感知训练?

当我们从浮点型转换到较低精度时,我们通常会注意到精度显著下降,因为这是一个有损耗的过程。借助 quant-aware 培训,这种损失可以降至最低。所以基本上,quant-aware 训练模拟前向传递中的低精度行为,而后向传递保持不变。这导致了一些量化误差,该误差在模型的总损失中累积,因此优化器试图通过相应地调整参数来减少该误差。这使得我们的参数对量化更加鲁棒,使得我们的过程几乎无损。

是如何表现的?

我们首先决定一个量化方案。这意味着决定我们要包含哪些因素,以便在信息损失最小的情况下将浮点值转换为精度较低的整数值。在本文中,我们将使用[1]中使用的量化方案作为参考。为此,我们引入了两个新参数:标度和零点。顾名思义,scale 参数用于将低精度值调整回浮点值。它以完全精确的方式存储,以获得更高的准确性。另一方面,零点是表示量化值的低精度值,该量化值将表示真实值 0。零点的好处是,即使对于斜张量,我们也可以有更宽的整数值范围。因此,实值(r)可以通过以下方式从量化值(q)中导出:

等式 1

这里 S 和 Z 分别代表刻度和零点。

在涉及计算的每个操作之后,我们在我们的模型中引入一种叫做 FakeQuant 的节点,以获得我们所要求的精度范围内的输出。FakeQuant 节点基本上是量化和反量化操作的组合。

量化操作

它的主要作用是将张量的浮点值转换为低精度整数值。这是基于上面讨论的量化方案完成的。标度和零点按以下方式计算:

比例的主要作用是将浮动范围内的最低和最高值映射到量化范围内的最高和最低值。在 8 位量化的情况下,量化范围将是[-128,127]。

等式 2

这里 fₘₐₓ和 fₘᵢₙ代表浮点精度的最大值和最小值,qₘₐₓ和 qₘᵢₙ代表量化范围的最大值和最小值。

同样,我们可以通过在浮点极值和量化值之间建立线性关系来找到零点。

图一。从浮点域到量化域的缩放表示。来源:作者图片

考虑到我们有一条直线上两点的坐标(qₘᵢₙ,fₘᵢₙ)和(qₘₐₓ,fₘₐₓ),我们可以以 y = mx +c 的形式得到它的方程,x 是量化值,y 是实数值。所以为了得到量化域中 0 的映射,我们只需找到 y=0 时 x 的值。解决这个问题后,我们会得到:

等式 3

但是如果 0 不在 fₘₐₓ和 fₘᵢₙ之间,我们的零点会超出量子化范围。为了克服这一点,我们可以将 z 设置为 qₘₐₓ或 qₘᵢₙ,这取决于它位于哪一侧。

现在我们有了量化操作的一切,我们可以使用以下等式从浮点值获得量化值:

等式 4

此外,我们将使用去量化操作将其转换回浮点域,以逼近原始值,但这会导致一些小的量化损失,我们将使用这些损失来优化模型。

去量化操作

为了获得真实值,我们将量化值放入等式 1 中,因此变为:

等式 5

创建训练图

现在我们已经定义了 FakeQuant 节点,我们需要确定将它们插入图中的正确位置。我们需要使用以下规则对权重和激活进行量化操作:

  • 权重需要在与输入相乘或卷积之前进行量化。
  • 我们的图表应该显示训练时的推理行为,因此 BatchNorm 层必须折叠,必须删除遗漏。关于 BatchNorm 折叠的详细信息可在这里找到。
  • 在将类似 Relu 的激活层应用于每一层之后,每一层的输出通常被量化,这是有益的,因为大多数优化的硬件通常具有与主操作融合的激活功能。
  • 我们还需要量化像 Concat 和 Add 这样的层的输出,其中几个层的输出被合并。
  • 我们不需要在训练期间量化偏差,因为我们将在推断期间使用 int32 偏差,并且稍后可以使用使用权重和激活的量化获得的参数来计算该偏差。我们将在这篇文章的后面讨论这个问题。

天平和砝码零点的测定方法与上一节所讨论的一样简单。为了确定激活的标度和零点,我们需要在浮点域中保持激活的最大值和最小值的指数移动平均值,以便在从许多图像获得的数据上平滑我们的参数。

因此,伪量化操作被插入到下图中,如下所示。

图二。量子感知训练图的可视化表示。来源:作者图片

现在我们的图表已经准备好了,我们需要为训练做准备。在训练时,我们必须仅在前向通道中模拟量化行为以引入量化误差,后向通道保持不变,并且在训练期间仅更新浮点权重。为了在 TensorFlow 中实现这一点,我们可以借助@custom_gradient 装饰器。这个装饰器帮助我们为任何操作定义自己的自定义渐变。

创建评估或推理图

既然我们已经完成了我们的训练,并且我们的参数现在被调整用于更好的低精度推断,我们需要从获得的训练图中获得低精度推断图,以在优化的硬件设备上运行它。

  • 首先,我们需要从上述模型中提取量化的权重,并将量化操作应用于在 quant-aware 训练期间获得的权重。
  • 由于我们的优化函数将只接受低精度输入,我们还需要量化我们的输入。

现在让我们来推导如何使用这些量化参数来获得量化结果。

假设我们假设卷积是点运算。

等式 6

利用等式 1,它也可以写成:

等式 7

为了获得量化值 q₃,我们将等式重新排列为:

等式 8

在这个等式中,我们可以在推理开始之前离线计算 S₁S₂)/S₃,这可以用一个乘数 m 来代替

等式 9

现在,为了进一步将其简化为纯整数运算,我们尝试将 M 分解为两个整数值。m 总是介于 0 和 1 之间,所以可以分解成这种形式。

等式 10

使用这个等式,我们可以获得 M₀和 n 的整数值,它们将分别作为乘法器和逐位移位器的值。显然,如果我们可以在硬件上执行浮点乘法,就不需要这一步。

此外,我们需要相应地修改我们的偏见,因为我们的乘数也会影响它。因此,我们可以使用以下等式获得 int32 量化偏差以进行推断:

等式 11

现在我们已经有了所有的成分,我们可以创建我们的低精度推理图,看起来像这样。

图 3。量子推理图的表示。来源:作者图片

我们想把量子化的范围作为有符号的还是无符号的,这取决于我们。在上图中,它被认为是无符号的。

量化感知训练值得努力吗?

我们已经知道了量化的重要性,也知道后量化有时会有很大的损失,量化感知培训是我们最好的选择。下表显示了使用一些流行和复杂的神经网络架构进行 Quant-Aware 训练的结果。我们可以观察到,在这种量化模式下,精度下降可以忽略不计。

图 4。量化感知训练的性能比较。来源:作者图片,数据来自 Tensorflow 博客

此外,我们不需要担心自己实现如此复杂的机制,因为 Tensorflow 为此提供了一个定义良好的 API。你可以从这里了解一下。

参考

[1] Benoit Jacob,Skirmantas Kligys,,Menglong Zhu,,,Hartwig Adam 和 Dmitry Kalenichenko,用于高效整数算术推理的神经网络的量化和训练[2017]

[2]https://blog . tensor flow . org/2020/04/quantization-aware-training-with-tensor flow-model-optimization-toolkit . html

[3]https://Intel labs . github . io/distiller/algo _ quantization . html #:~:text = This % 20 means % 20 that % 20 zero % 20 is,This % 20 exact % 20 quantization % 20 of % 20 zero

[4]https://scortex . io/batch-norm-folding-an-easy-way-to-improve-your-network-speed/

通过可视化 YouTube 上的社区和联系获得的见解

原文:https://towardsdatascience.com/insights-from-visualizing-communities-and-connections-on-youtube-30141f31bb20?source=collection_archive---------14-----------------------

流行文化的视觉图谱

YouTube 图集[作者]

YouTube 一直以其难以置信的庞大内容库吸引着我。点击缩略图,发现单片频道,并找到丢失的文物感觉很像探索。

这种探索启发了我,让我尝试将内容生态系统作为一个整体来缩小和可视化。YouTube 的地图集会是什么样的?这种类型的可视化有什么见解?

看到大范围的社区和联系也可能是理解在线行为的有力工具。随着危险的互联网泡沫和新社区的崛起,有必要了解这些群体是如何形成、成长和变化的。

大约一年前,我创建了热门直播网站 Twitch 的地图。这个项目向我展示了社交媒体关系的视觉表现可以引起平台、创作者和观众的共鸣。我在这里写了一篇关于我的观察的文章。

为 YouTube,一个大得多的平台,复制这个过程不是一件容易的事情我需要一种方法,通过可公开访问的数据将频道相互连接起来。我通过查看每个视频下谁留下评论找到了我的答案。通过收集这些评论,并在多个渠道中进行比较,我可以构建一个渠道关系图。这可以被可视化成一个地图集。

经过几个月的 AWS 学习,大量的 Python,平衡了一学期的课业,我达到了我的目标。该地图集的一个可搜索、可交互的版本位于 https://youtubeatlas.comhttps://youtubeatlas.com.****。去探索吧!对任何可用性怪癖表示抱歉。我不是一个有经验的 web 开发人员,这个实现的大部分使用了一个我不太了解的库和框架。下面是地图的静态图像,供那些对交互式版本有疑问的人使用。

按地区[按作者]标记的 YouTube 图集

互动地图可在https://youtubeatlas.com获得

如何阅读地图集

  • 每个泡泡都是一个 YouTube 频道。
  • 每个气泡的大小由该频道的用户数决定(2021 年 8 月)
  • 两个泡泡之间的一条线显示,这两个频道在收集的 20,000 条评论中至少分享了 350 条评论。
  • 气泡的颜色表示所有共享评论者的 YouTube 频道社区。这是由检测图簇的模块算法决定的。

谁在地图上?

该图集显示了按用户数量排名的前 5700 个 YouTube 频道。 SocialBlade 非常好心地提供了这个列表,如果没有他们的帮助,这个项目是不可能完成的!

地图集不包括针对儿童的频道,因为这些频道不允许评论(例如 Cocomelon 是 YouTube 上第四大频道,但属于此类)。

如果你想知道更多关于我的方法和过程的细节,这个项目的所有代码都是公开的在这里

地图集告诉了我们什么?

虽然一开始可能会有很多东西需要接受,但一些事情可能会立即凸显出来。以下是从可视化如此庞大的内容生态系统中可以发现的一些见解。

彩虹簇

t 系列是 YouTube 上最大的频道,拥有 2 亿订户。宝莱坞音乐集团在 2019 年的比赛中超过了 PewDiePie,达到 1 亿,并继续以越来越快的速度增长。

该频道也是代表印度 YouTube 社区的色彩鲜艳的集群的一员。这个星团和巴西星团(都在下图中)看起来与地图的其他部分非常不同——它们的密度令人难以置信,并且具有许多不同的颜色。

巴西和印度集群[作者]

为什么印度和巴西群集看起来与其他语言区域如此不同?

像 T8 T 系列和 T10 Canal KondZilla 这样的频道每天会上传很多次音乐视频,大部分都是很低的收视率。由于这些国家人口众多,视频数量庞大,大多数评论者在我的数据中只出现过一次。这就是为什么计算机在这些集群中分配了如此多的颜色,并揭示了这些频道正在向大量人口中的大量不同观众广播。

这些星团的第二个定义特征是它们与地图上其他区域相比的密度。这是因为将这些频道链接在一起的评论者通常会将所有的频道链接在一起。这些狂热的粉丝导致这些音乐/电影频道非常紧密地聚集在一起。

许多 YouTube 用户不知道这些社区在这个平台上有如此巨大的影响力。即使看看 YouTube 热门频道的列表和它们的页面,也不能清楚地表明这些频道的表现与大多数其他地区不同。通过像这样可视化社区和连接,这种独特的受众行为就凸显出来了。

中间的斗争

地图集上广阔的英语区占据了图像中心的大部分。四个社区在这个区域的中心发生冲突,颜色分别为橙色、浅蓝色、绿色和紫色(如下图所示)。总的来说,这四个地区包含了大多数人认为的现代英语 YouTube 景观。分开来看,这些地区都有独特的文化,根据我的经验,推荐源通常都在这些界限之内。

英语社区的冲突在中心[作者]

Orange 包含好莱坞脱口秀和许多高预算、适合家庭的创作者。浅蓝色以视频游戏和游戏相关内容为中心,但已经发展到包括许多其他形式的互联网娱乐。Magenta 是 YouTube 广泛教育的一面,这是一个随着最近“教育娱乐”内容的繁荣而爆炸的部分。我在这部分的大部分时间都在看像 3Blue1BrownCGPGrey马克斯·布朗利这样的频道。深绿色给了我们嘻哈明星和吸引粉丝的大范围的影响者。

这些地区已经相对独立,随着 YouTube 的发展,它们之间的距离越来越远。我在紫色区域的生活实际上从未让我接触到橙色或绿色通道,尽管我确实倾向于浅蓝色边界。考虑到这种日益严重的两极分化,将这些有色人种社区联系在一起的渠道变得越来越重要。

马克罗伯为例。这位前美国国家航空和宇宙航行局科学家创造了主要用于娱乐目的的野生工程装置(例如病毒闪光炸弹系列)。这个频道是淡蓝色的,而不是像大多数其他工程或科学频道那样是紫色的。这是因为马克专注于娱乐,并与流行游戏创作者有着非常紧密的联系,如 MrBeast。

马克和其他几个娱乐科学频道通过合作和深思熟虑的内容创作赢得了两个受众。我认为这个职位的渠道将对整个英语集群的发展产生重大影响,Mark 是社区之间桥梁的一个很好的例子。

区域桥梁

地图集各区域之间的许多链接可以很好地展现社区之间是如何相互作用(或不相互作用)的。

西班牙语和英语语言群集的边界[按作者]

看看地图上英语和西班牙语地区之间的桥梁,就可以看到夏奇拉、路易斯·丰西和皮特保罗等频道。正如所料,这些艺术家在拉丁美洲和美国观众中都很受欢迎。事实上,有很容易识别的渠道将美国音乐与西班牙、巴西、阿拉伯和东亚音乐文化联系起来。尽管有大量的印度音乐频道,但印度和英语集群之间似乎没有音乐联系。也许是一个等待被填补的空缺。

音乐只是这些双重文化渠道形成的一个维度。我鼓励你在地图上找到不同的社区,并寻找将它们联系在一起的渠道。我认为这些空间代表了 YouTube 作为一个平台和内容创作者的一些最大的增长机会。

开放式问题

探索地图集不可避免地会带来疑问和好奇。以下是一些我仍然没有答案的问题:

为什么印度尼西亚和菲律宾集群在地理上彼此接近,却位于地图的两极对立的两侧?

为什么俄语集群与其他外语集群相比如此明显地孤立?

为什么许多粉红色的英国音乐艺术家被排挤在英国音乐圈之外?为什么他们各自的 VEVO 频道通常更靠近中心?

最后的想法

我相信,能够以这种方式将互联网文化形象化,对于创作者、消费者和平台来说都是非常有价值的。

它可以帮助创作者了解他们的观众不仅在一维指标,而且在文化,社区和联系。这种理解可以指导新的内容方法,并激发新的利基形成。

它可以帮助消费者对他们消费的内容做出明智的选择,并更好地理解吸引我们注意力的算法。它还可以提供一种途径,在平台上完全不同的地方找到新的创作者,或者在他们非常熟悉的社区中找到隐藏的宝石。

它可以帮助 YouTube 微调算法旋钮,以增加观看时间和参与度等北极星指标。研究这些社区和它们之间的联系也可以洞察在线毒性、积极性和适度性。

作为一个 20 岁的大学生,我在这些网络社区中度过了很长一段时间,我知道它们对社区居民有多重要。理解它们是如何成长、变化和相互作用的是令人着迷的,我希望成为其中的一员。

如果你喜欢图集,请分享给大家!

你可以在 Twitter 上找到我,或者在 Github 上找到 T2。

感谢阅读!

对变分法的见解

原文:https://towardsdatascience.com/insights-on-the-calculus-of-variations-f50825f0ca84?source=collection_archive---------16-----------------------

思想和理论

或者如何证明两点间最短路径是直线

照片由史蒂夫·阿灵顿Unsplash 上拍摄

变分法是一种强有力的技术,可以解决一些用其他方法无法直观解决的动态问题。它是最优控制理论的先驱,因为它允许我们解决非复杂的控制系统。此外,它也是拉格朗日力学的基础,虽然没有牛顿力学那么有名,但同样强大。

理解变分法框架将使你在最优控制理论框架中站稳脚跟,同时发现关键的数学概念。

理论上的直觉

与函数最优化理论相反,变分法并不试图寻找函数的最小值。相反,它使我们能够找到一组函数(我们称之为泛函)的~最小值。通过累加累积成本将每个功能映射为一个值

我们要解决的问题是找到一条路径,一组连续的值,导致最小的总成本(任何最大化问题都可以通过在成本上加一个负号变成最小化问题)。

拿一个投资公司来说,它可以用有限的资金决定一年以上的日常投资。每天投入的钱在同一天产生收益。该公司希望在一年中赚取尽可能多的收入,为此,将每天的收入汇总为一年的收入。如果公司有一个投资模拟,它可以尝试多种投资策略,并通过时间(路径)确定什么是导致最高收入的日常投资的最优序列。该模拟允许我们比较多种投资途径,并选择一个导致最高收入的途径。

为什么变分法特别擅长解决这些问题?考虑这样一种情况,我们必须找到乘坐地铁的最快交通时间。比较地铁站的所有可能组合并找出最佳轨迹是非常容易的:在离散空间中,轨迹集是一个固定的数字。现在考虑这样一种情况,你正在驾驶,需要在方向盘完全控制的情况下将 A 点集结到 B 点。最佳轨迹不取决于少数地铁线路变化,而是取决于每一个单独的转向决策。在连续的空间中,我们试图比较无限数量的可能轨迹,它们中的每一个都与另一个有着无限的不同。
变分法提供了在这种情况下找出最短路径的方法。

路径周围微小变化的可视化。作者图片

变分法实际上使用了与函数优化相同的技巧。函数优化会注意到,在最优点,向任何方向移动一点点只能导致更高的值,这将有助于找出最优性的一阶约束。
变分法利用了这样一个事实,即考虑到最优路径,任何与其稍有不同的路径都会导致更高的成本。从该观察,有可能导出欧拉-拉格朗日方程,其构成了理论的基础。

可解决的问题

我们需要提醒的是,变分法可以解决的问题等价于最小化下面的表达式:

其中,y 是我们的状态变量,或者是您想要找到最优路径的函数(即每日投资),L 是您的相关成本(即每日收入),S 是总成本,具体取决于您选择的函数 y(年收入)。

总的来说,变分法适用于以下类型的问题:

  • 这是一个优化问题,这意味着它包括最小化(分别最大化)某个值。
  • 要最小化的值是通过从问题的给定开始到结束对成本函数求和而获得的。
  • 这个问题有一个状态变量,我们试图为它找到一组最优值(路径)。
  • 该成本函数仅取决于状态变量及其一阶导数。

我们举一个在介绍变分法理论时经常被引用的著名例子:最短路径。

两点之间最短的路径是什么?作者图片

这个问题只是证明任意两点之间的最短路径是一条直线。对我们基于直觉的大脑来说,这是显而易见的,但数学证明仍然需要运用变分法理论。让我们检查一下这个问题是否符合:

  • 我们试图最小化给定路径的长度。
  • 路径的长度是线段长度的总和。
  • 状态变量再次是几何路径(每个线段的坐标)。
  • 一段的长度只取决于每段的方向(状态变量的导数)。

最优理论的序言中考虑的问题是最速降线,我们希望找到引导滚动珠到达给定点的最快轨迹。

来源:维基百科:腕尺记录

让我们检查一下这些条件是否都适用:

  • 我们正试图最小化滚动珠轨迹的持续时间
  • 轨迹持续时间是通过合计珠子通过轨迹的连续部分所花费的时间而获得的
  • 状态变量由轨迹(也称为路径)的连续段的坐标来表征。
  • 珠子穿过一段轨迹所花费的时间仅取决于珠子在特定段上的速度(可以从其高度推断出)和该段的长度,该段的长度也仅取决于状态变量的导数。

为了多样化,让我们举一个经济科学的例子,它也依赖于变分法:考虑一个工厂,它能以生产率 p(r(t))制造一种产品,给定原材料收入率 r(t)。
公司面临多重挑战:

  • 越早从生产中赚钱越好
  • 改变生产率是有成本的,成本随着变化量的增加而增加。

我们可以用下面的等式来表示这个问题:

其中,经济学中常用的指数项代表所赚货币价值的衰减(潜在利益的损失),U 代表单位价格,C 代表单位成本,K 是一个常数,它影响对过快提高或降低生产率的惩罚力度。

显而易见,我们确实有一个想要最小化(分别最大化,不带负号)的总价值,即工厂的总收入。这里的累积成本是单位时间 dt 内产生的收益。最后,我们可以自由选择和优化的状态变量是我们在每个时间 t 决定购买收入材料的比率。最后,当我们看方程时,我们意识到成本函数只取决于 t,r(t),r'(t)(因为 p 是 r 的函数)。这个问题可以用变分法来解决,它说明了一些最优控制问题可以用本文描述的方法以一种简单的方式来解决。

安特·罗泽茨基在 Unsplash 上的照片

既然我们已经看到了多个例子,我们可以试着对变分法使我们能够处理的问题类型进行推理。
很明显,如果我们看看最速降线和工厂问题,脑海中会浮现出一个词,即“动力学”,或者换句话说,我们不仅对状态变量的值感兴趣,还对它如何随时间演变感兴趣。这一点很清楚,因为我们有方程中状态变量部分的导数。我们不仅关心成本的总和,而且这个成本对状态变量的变化率也很敏感。

如果你很好奇,你会抱怨另一个例子,最短路径问题,看起来没有任何动态方面。这实际上是不正确的。相反,考虑以下问题:一辆汽车以固定速度向前行驶,只能改变方向(这是给定路径的导数)。在这种情况下,优化的成本不是距离,而是到达最终目的地所需的时间。

动力系统

这里要记住的是变分法可以帮助我们解决一些动力系统的优化问题。但不是每个动力系统!唉,只有一阶的。
提醒一下,一阶动力系统是可以用一阶微分方程完全描述的系统:

以最短路径问题(又名恒速车问题)为例。问题的状态变量,汽车的位置,可以完全由一阶微分方程确定。现在如果你想起用来介绍最优控制理论的问题,它或多或少是同一个问题:

汽车从给定的起点和终点位置加速,目标是减少总行驶时间,目标是找出应用于油门踏板的最佳控制组,以尽可能快地达到目标。

两者看起来都像时间最优问题。区别来自于实际的控制。后一个例子允许控制汽车的速度和加速度,因此汽车的位置不能由一阶微分方程确定。

总的来说,我们可以说变分法允许我们求解路径,一条画出来的线,而它不能求解轨迹:一条知道我们通过它的速度的路径。

与拉格朗日力学的关系

从这个意义上说,我们可以把变分法当作解决最优控制问题的工具,但只适用于一阶动力系统。在实际中,大多数系统都是二阶动力系统。想想在牛顿运动定律下演化的物理系统,它的运动方程取决于系统的加速度。如果加速度不为零,你的系统很有可能是一个二阶动力系统…
除非它的能量不变。这就是拉格朗日力学的全部技巧。T2 能量恒定的系统实际上是一阶系统。为了说清楚,让我们这样写:

对于在高度 h 的重力场 g 中质量为 m 的给定系统

可以看出,系统可以完全描述,而不会在任何地方出现加速度。这是一个一阶动力系统。
最速降线就是这样一个系统,尽管珠子的加速度是不恒定的,因为它只在重力和对其位置的约束下演化。

这就是拉格朗日力学的全部内容。仅在保守力下利用系统(使得系统的总能量是守恒的),这使得它们成为一阶动力系统,从而有资格使用欧拉-拉格朗日方程来求解。
我们在最优控制的序言中提出了拉格朗日运动方程的一般公式。让我们在这里详述一下。拉格朗日陈述并证明了寻找描述保守系统运动特征的路径等价于寻找下列方程的静止点:

这里 T 代表我们系统的动能,V 代表我们系统的势能,而 y 是我们选择的坐标向量,只要它能在每个时间 T 完全代表空间中的系统,它可以是笛卡尔坐标,也可以是极坐标。这两个实体的区别被打上了“拉格朗日”的印记。如果我们能找到拉格朗日积分随时间的最小值,我们就知道找到了一个静止点,并以系统坐标的特定函数,路径结束。

拉格朗日,动能和势能之间的差,似乎有点武断。为什么最小化这样的成本会导致找到系统的运动方程?

-首先,因为它有效。如果我们用欧拉-拉格朗日方程来解决这个特定的问题,其中拉格朗日被定义为动能和势能差,如果我们选择笛卡尔坐标作为状态变量,我们会得到牛顿运动定律,也可以用另一种方式推导。

-第二,因为它仍然有一些意义。
如果你拿着一个给定高度的物体,这个物体有势能,但没有动能。如果你把它放下,你会发现势能转化成了动能。虽然我们知道系统的总能量是不变的,但这不足以知道从势能到动能的转换是如何进行的,因此也不足以描述运动定律。但是我们知道,大自然正试图通过尽可能多地为自己保留能量来最大限度地减少能量消耗。当你吹一个气泡时,另一种势能,与弹性变形有关。气泡持续一段时间,因为它试图保持其势能。您可以假设您正在拖放的对象也是如此。它不愿意移动,并将抵抗将它吸引到地面的力。我们发现在牛顿力学中,对运动的阻力叫做惯性。在这种情况下,最小化动能同时最大化势能等价于最小化(T — V)。
拉格朗日公式可以被视为试图最小化运动的成本

显然,拉格朗日公式允许使用变分法框架来解决它:拉格朗日仅依赖于状态变量 r、它的导数 r’和时间。

拉格朗日力学优于牛顿力学的最大优点是可以使用任何坐标系来描述系统的位置。这对于任何涉及旋转运动的问题都是非常明显的。这是因为能量守恒不依赖于任何坐标系。
拉格朗日力学可以扩展到添加约束,只要是完整的(可积的)。基本上,完整约束是一组等式或不等式,它们限制了你试图寻找的路径。如果你考虑一个 2D 的例子作为最短路径问题,完整约束将代表你放置在限制进入某些区域的路上的障碍。牛顿力学中的这些约束总是作用在系统上的力。例如对于一个摆,我们用牛顿力学中的力和拉格朗日力学中摆的位置约束来表示连杆的张力。
最后但同样重要的是,拉格朗日力学仅限于一阶动力系统。任何包含非保守力(摩擦力)的系统都需要用牛顿力学求解。

推导欧拉-拉格朗日方程

为了找到保守系统的运动方程,欧拉首先提出了现在所谓的欧拉-拉格朗日方程。它们提供了问题的一阶必要条件。然而,拉格朗日通过使用新的符号ε,一个无穷小的任意数,改变了欧拉后来称为变分法的问题的解决方法,使它们发生了革命性的变化。让我们看看拉格朗日是怎么做的。

我们先从问题的定义开始:
(1)我们要找 S[y]的一个驻点。对于拉格朗日力学,状态对应的是空间坐标。
(2)是诀窍:给定我们系统 y(t)的路径,我们考虑与原始路径稍有不同的路径集。我们用一个函数β来解释我们在每一点的变化,ε是一个无穷小的值。我们正在分析路径的一个小变化,因此是变分法。对路径β的唯一要求是其起始值和结束值为零。
③是静止点的定义的直接翻译。通过我们定义新变量 y bar 的方式,由于β是任意的,我们实际上可以访问所有可能的路径。我们实际上做的是引入一个新的变量,使我们能够浏览所有的解决方案。在这个意义上,泛函 S 只随ε变化。自然地,如果我们想找到 S 的驻点,那么它对ε的一阶导数必须为零。

(4)我们在这里向前推导并应用偏导链规则。注意,我们在推导中考虑的是 y 条,而不是 y,因为我们考虑的是原始路径 y 的所有可能的变化。

(5)通过使用等式(2),我们可以用ε的实际表达式来代替关于ε的偏导数中的 y 条。

(6)我们在这里对等式(5)中的积分的第二项进行分部求导。我们的目标是去掉β的导数,因为我们没有关于它的信息。在等式(6)的第二项中,我们看到我们最终得到[beta(t2)-beta(t1)]。参考(2),路径β的末端被选择为 0,因此第二项为零。

(7)在最后一步去掉一项后,简单地以更紧凑的形式重写方程。我们可以说,这个等式对任何路径β都成立(给定(2)中的条件)。由于我们的等式等于 0 (3),唯一可行的方法是,在任何时候,乘以β的项为零。

(8)以微小的差异重写在最后一步中发现的结果。如你所见,状态变量 y 上不再有条形,这是因为我们对ε= 0 的项求值,因为该方程适用于任何ε。我们最终得到的只是欧拉-拉格朗日方程。

注意我们做的是单向推导。这意味着欧拉-拉格朗日方程提供了一个必要条件,但不是充分条件。

使用欧拉-拉格朗日方程

有了强大的工具,我们可以尝试解决我们之前定义的问题。

  • 腕尺年代线
  • 两点之间的最短路径
  • 最佳工厂生产
  • 保守系统的运动方程

解决这些问题的方法总是相同的。我们需要找到一个合适的状态变量来代表系统。
2-表达给定状态变量的拉格朗日量(代价)。
3-最后应用欧拉-拉格朗日法,通过将问题公式转化为可解公式,找到作为初始问题驻点的路径。

最短路径问题

首先,让我们考虑最短路径问题,并应用三个步骤:
我们考虑两点 A 和 B,我们希望以最短的路径集结。

1-因为我们在 2D 工作,让我们选择笛卡尔坐标。那么状态变量就是 y(x),它构成了一条路径。

2-我们的总成本是路径的长度,其特征是每一段的长度总和,我们将它定义为 dS。利用毕达哥拉斯定理,我们还可以说明 dS = sqrt(dx + dy),我们可以用 dx 进一步因式分解。注意 dx/dy 就是简单的 y’。

作者图片

我们的函数现在看起来是这样的:

3-拉格朗日量在这里被清楚地确定,并且只取决于 y’。为了使用欧拉-拉格朗日方程,我们需要推导出关于 y 和 y '的拉格朗日量。
关于一个被导数的函数求导的概念可能看起来很奇怪,但毕竟,首先,状态变量 y 也是一个函数。你需要记住,我们从一开始考虑的是一组路径,其中状态变量本身就是一条路径。所以只要你认为路径是一个变量,那么路径的导数就是另一个变量。

我们写出了欧拉-拉格朗日方程,它的状态变量公式与我们的问题相匹配,并且清楚地定义了拉格朗日量。接下来就是简单的把欧拉-拉格朗日方程的两项表示出来,进行推导,找出我们感兴趣的东西:最短路径 y*(x)的表达式。因为最终,这就是欧拉方程正在做的。这是路径 y 使 T[y]最小的必要条件。(或者至少是它的一个静止点)。如你所见,只要我们知道它只是一个变量,对 y '求导就不会有任何问题。通过进一步发展,我们得到 y 上的一个条件,使得它确实最小化 T[y]并产生最短路径:

y 上使 T[y]最小并产生最短路径的一个必要条件是 y 是一条从 A 到 b 的直线。

最速降线问题

最短路径问题可以归类为相当容易解决的问题。让我们看看如何处理一个稍微复杂一点的问题,这也是变分法的原始问题。
提醒一下,系统是一个从任意点 A 到任意点 b 无摩擦滚动的珠子,珠子只受重力和珠子的反作用力。
目标是尽可能快地找到引导珠子到达 B 点的路径。因此,这是一个时间优化问题。

1-必然有一个包含点 A 和 b 的平面,让我们在这个平面上取笛卡尔坐标。状态变量又是 y(x)。

作者图片

2-考虑到我们的成本,我们希望最小化珠子到达 b 点的时间。我们可以说,它是珠子通过每段路径所需时间的总和。但是这和我们的状态变量没有很好的联系。利用时间、距离和速度之间的关系,我们可以说我们的成本是比率 dS/v ,其中 dS 是该段的长度,v(x,y)是该段上珠子的速度。利用毕达哥拉斯定理,我们可以用我们的状态变量来表示 dS,最后得到等价的公式:

然而,我们不希望在公式中有任何额外的 dx,因为我们的状态变量是 y。我们应该在那里转换方程,以便只表示 x,y 或 y′。我们首先对分子进行因式分解,这样 dy/dx 可以表示为 y'(x)。在分母上,我们利用能量守恒定律。当质量为 m 的珠子位于高度为 h 的 A 处时,其能量是纯势能,因此系统在整个运动过程中的能量是恒定的,并且等于 mgh,并且我们可以由此推导出珠子对于任何给定坐标的速度:

第二步现在完成了,我们有了代价的表达式,拉格朗日量,关于我们的状态变量 y 和它的导数 y’。

3-让我们应用欧拉-拉格朗日方程。

既然 g 和 h 是任意的,那我们就来关注一个简化我们推导的情况:g= -1/2,h=0。我们得到:

因为 y 与 y’无关,所以在第二个方程中它被认为是一个常数。然而,我们现在需要对 x 求导,这时我们必须记住 y '和 y 确实依赖于 x,通过将 y 视为 y(x)和 y '视为 y'(x),我们可以简单地将它们视为两个独立的函数,每个都依赖于 x,然后进行求导。我们发现:

将欧拉-拉格朗日方程的另一部分放在一起,可以进行一些简化(这里跳过)。我们最终会得到:

从第一行到第二行,我们乘以 y。然后我们发现它可以被整合,结果是第三行。(如果你不相信我,你可以试着再推导最后一行!).

在推导的这一点上,我们有了一个看起来容易处理的方程。我的意思是,它可以很容易地用数值求解器来求解,而用泛函表示的初始公式,在数值上是无法求解的。这就是欧拉-拉格朗日方程和变分法的内容。获得最优路径的必要条件将问题转化为可解问题。

现在,对于最速降线来说,完全解析地解决这个问题是可能的。在变分法问题中,我们经常以 y 和 y '之间的这种关系结束。能够识别路径 y(x)的常用解决方案是将 y '取为 dy/dx,在方程的每一侧分离 dy 和 dx,并在每一侧从问题的开始到结束进行积分。推导的其余部分通常包括对变量进行巧妙的修改。我们知道,对于最速降线问题,解决方案涉及一些曲线路径。因此,从笛卡尔坐标到角度变量的转换似乎是一个好的步骤。我不会在这里详述推导过程,但我知道,可以证明引导最短珠轨迹的最佳路径是摆线。

摆线的生成。来源维基百科:摆线

带约束的变分法

正如我们在前面一段中看到的,为了能够用拉格朗日力学来求解动力系统,我们经常需要使用约束条件并引出拉格朗日乘子的概念。
如果您不熟悉拉格朗日乘子,其基本思想是引入一个新的变量,通常称为 lambda,该变量能够使用要最小化的实体和约束条件之间的特定关系,将最小化问题转化为一个方程组。

所以如果我们考虑这个优化问题:

我们需要一种方法来转换这个系统,使它成为一个公式,至少在数值上是可解的,如果可能的话,在分析上是可解的。
拉格朗日观察到,在给定约束条件下达到最小值的点处,曲面 f 的梯度指向与约束条件的梯度相同的方向。这是因为这样一个事实,如果你通过观察你的曲面的轮廓线(f(x) =常数)来进化,你将最终到达一个点,在这个点上你只接触到一个点上的约束,因此轮廓线与它相切。这意味着在这个切点处两个表面的梯度是共线的(但是方向相反)。

因为我们的输入 x 是 n 个分量的向量,并且我们可以有 m 个约束方程,所以上述方程将提供具有 n+m+1 个变量的 n+m 个线性方程的系统。要使系统可解,还是要考虑初始约束。找到 f 的最小值相当于求解下面的系统:

λ(一个标量)被认为是系统中的另一个变量,我们可以求解它。我们最终会找到λ的某个值,但这对我们来说无关紧要。

这就是传统函数优化的理论。这将如何转化为路径优化?答案是,差不多。拉格朗日指出,如果我们试图解决以下形式的问题:

那么我们可以说,求解上述系统相当于求解:

特别地,我们可以表达一个新的函数,称为增广拉格朗日 L ’,使得:

我们引入 lambda 变量的方式类似于函数优化问题。证明最小化问题与这两个公式保持等价有点困难,但直觉仍然是相同的。
现在,我们不是将欧拉-拉格朗日方程应用于拉格朗日方程,而是将其应用于扩展的拉格朗日方程,并以完全相同的方式进行。你最终会有一个额外的变量需要求解,lambda,但这是使问题实际上可解的成本(解析地或数字地)。

变分法的极限

正如我们前面提到的,二阶动力系统不能用欧拉-拉格朗日方程求解。非完整约束也导致不可能用这种方法解决问题。
特别是来自控制理论的系统,对于这些系统,我们不仅要寻找最优路径,还要寻找给定系统跟随最优路径的最优控制集合。因为我们控制的系统通常是真实世界的物理系统,所以控制该系统包括控制其加速度,因此使得该方程不能用欧拉-拉格朗日方程求解。
另一种理解方式是,待优化系统的控制表达式可以约束的形式包含在优化方程中:

u 是应用于系统的控制,x 是系统的状态变量。

与之前的符号相比,状态变量 y 已经被 x 代替,问题是与时间相关的。然而,显而易见的是,约束包括状态变量的导数,使其成为非完整的。最后,我们可以通过直觉分析为什么这样的问题不能用变分法来解决。该理论基于对所有可能路径的抽象,并指出该路径的任何几何变化都将导致次优路径。因为所有的变化都是几何上的,所以很容易通过求导将这个条件转化为欧拉-拉格朗日方程。当我们对一个可以改变位置、速度和加速度的系统进行控制时,从一条路径到另一条路径的变化不仅仅是几何上的,我们还需要考虑时间上的可能变化或者系统通过新路径的速度变化。我们可以看到,在这种情况下推导出一个最优性条件看起来更加困难。

这个问题仍然被解析地解决了,被称为最大值原理,由列夫·庞特里亚金推广。庞特里亚金确实用一种类似于变分法的方法找到了最优性的一个条件,但是当然在数学上要重得多。然而,在现实中,为实际应用而实现的最优控制并不太依赖于最大值原理。这种趋势更倾向于逼近问题,例如通过离散化状态空间和寻找数值方法来尽可能地减少繁重的计算。但是理解变分法理论仍然有利于从整体上理解控制理论领域。

来源:

[1]《变分法和最优控制理论简明介绍》,丹尼尔·利伯松。

[2]《ECON 402:最优控制理论》,圣弗朗西斯泽维尔大学。

[3]《物理 6010,经典力学》,犹他州立大学。

石灰解释的不稳定性

原文:https://towardsdatascience.com/instability-of-lime-explanations-3e0efc00a7de?source=collection_archive---------42-----------------------

怎么处理?看看稳定性指数

稳定很重要。图片来自这里

在这篇文章中,我将非常具体地介绍用于解释机器学习预测的 LIME 框架。我已经在这篇文章中介绍了这个方法,在这篇文章中,我也给出了直觉并解释了它的优点和缺点(如果你还没有的话,可以看一下)。
在这里,我将谈论一个非常具体的石灰问题,即其解释的不稳定性,我将提供一个发现和处理它的方法。

石灰不稳定性

我们所说的不稳定是什么意思?

解释的不稳定性:如果你对一个特定的个体运行 LIME,用相同的参数和设置重复该方法几次,你可能会得到完全不同的解释。

使用具有固定参数的 LIME 生成了关于同一个人的三种解释。我们可以看到不同的解释,这是由于不稳定性。来源此处

石灰为什么会不稳定?

因为生成步骤。记住 LIME 在数据集的 X 变量的整个ℝᵖ空间生成 x 值(这里解释)。
这些点是随机生成的,所以每次调用 LIME 都会创建一个不同的数据集。由于数据集用于训练 LIME 线性模型,因此我们可能会针对不同的 LIME 调用使用不同的模型。

不稳定导致的信任问题

不稳定对石灰非常有害。

为了让你相信这一点,我将告诉你一个小故事: 考虑一家银行使用 ML 模型来决定向客户发放贷款。ML 模型被训练来预测这个人是否会偿还贷款或者她是否会违约。现在,这是一个极其重要的决定,所以银行想很好地理解它的模型是如何工作的,并决定检查为什么 ML 拒绝给一个特定的人贷款。
银行对同一个人连续三次使用石灰,解释完全不同…… 如果你是银行职员,你会相信这些解释吗?因此,你会相信你的 ML 贷款模式吗?

正如你所看到的,不稳定的石灰解释是一种真正的痛苦,可以在整个机器学习领域产生不信任!

既然我们了解了问题及其后果,让我们来分析如何解决它。

我们可能想知道的第一件事是:

既然它是不稳定的原因,我们为什么不去掉世代步骤呢?

这正是研究人员在这篇论文中试图做的事情。他们的想法是仅使用训练数据集中的个体来构建 LIME 线性模型,而不在 LIME 内生成新点。
他们考虑用于训练的 x 值,并通过 ML 模型预测 ŷᵢ ,然后根据与待解释个体的距离(使用高斯核)给每个单元一个权重。
这样,LIME 的起始数据集对于每次调用都保持不变。

然而,他们没有考虑到一个重要的缺点:
我们可能有训练点非常少的区域,我们的线性近似在那里会非常粗糙!

例如,考虑下图:
最大似然函数非常不规则,我们正在考虑一个参考点(红点),它位于离其他训练点相当远的区域。如果我们使用太小的内核宽度,我们最终只会考虑红点。在这种情况下,LIME 会失败,因为我们至少需要 2 个点来画一条线(有无限条线通过一个点;石灰无法选择正确的一种)。
如果我们放大局部区域,我们最终会考虑相当远的点,并且产生的石灰线完全不能代表 ML 模型的局部曲率!

仅使用训练点构建的 ML 函数(绿色曲线)和 LIME 解释(红线)的玩具示例。在函数中人口稀少的区域,如果不生成新点,LIME 就不能很好地工作。乔治·维萨尼拍摄的照片

也许你在想,“这个模式很糟糕!它处于一种完全超负荷的状态,”这肯定是真的。但是你必须考虑到我们使用 LIME 来理解 ML 模型的行为。
如果不生成新的点,LIME 可能无法在类似情况下捕捉到此类问题。

此外,任何数据集都存在一些训练数据覆盖率不高的区域(通常在变量范围的极值)。如果我们有兴趣了解这些区域的最大似然预测,我们应该像在石灰生成步骤中一样,使用允许我们检查曲线(生成更多点)的工具。

基本上,采样步骤有助于我们很好地覆盖 ML 函数。这总是有帮助的!我们生成的点越多,石灰数据集在再现f(x)函数的所有波动部分时就越精确。

因此,正确的解决方案是使用 LIME 中的随机生成步骤来生成点。如果我们在参考点周围很好地覆盖了函数f()x),就实现了稳定性。这样,我们将能够为每个不同的 LIME 调用检索适当的正切值。

稳定性指数

您在本节中找到的概念、想法和图片,以及下一节中的用例,都摘自我们于 2020 年发表的论文 《石灰的统计稳定性指数:获得机器学习模型的可靠解释【1】》。

LIME 解释由一个线性模型组成,该模型使用特征选择技术(套索或逐步选择)仅选择最重要的变量。模型中考虑的每个变量都有一个相关系数。因此,不稳定石灰解释可能有不同的变量和不同的系数。

我们建议使用一对指数来检验石灰解释的稳定性:VSI(变量稳定性指数)和 CSI(系数稳定性指数)。

这些指数旨在以相同的设置对同一个人重复时间 n 次,并比较获得的线性解释。我们认为两个线性模型是相同的,如果它们有相同的变量,并且每个变量有非常相似的系数。

这两个指数的范围都是从 0 到 100,越高越相似。每个指标检查不同的稳定性概念,因此两者都有大的值是很重要的。当这种情况发生时,我们保证我们的石灰解释是稳定的,因为我们在参考个体的接近度中实现了对f(x)的良好覆盖。

VSI(变量稳定性指数)

检查 n 个线性模型中的变量是否相同。基本上,它着眼于特征选择过程的稳定性:我们希望选择的特征或多或少是相同的,即选择过程应该是一致的。

系数稳定性指数

它比较不同石灰模型中与每个变量相关的系数。
该指数单独考虑每个变量(比较与同一特征相关的系数是有意义的)
对于单个变量,CSI 采用 n 时间解释中的系数,并为每个系数建立置信区间(我们需要区间来处理系数的微小变化,这些变化是由所有模型中存在的固有统计误差引起的)
比较区间,得到变量的系数一致值:当置信区间重叠系数被认为相等时;而不相交区间表示两个系数的范围完全不同,因此系数不能具有相同的值。
在所有特征中对变量的一致性值进行平均,获得通用 CSI 指数。

使用案例和应用

现在我将向您展示一个指数有用性的例子。
考虑一个能够区分好的和坏的付款人的梯度推进模型(银行通常想知道要求贷款的客户偿还的概率是多少,ML 模型试图了解客户是否会归还贷款)。

众所周知,梯度推进是一个黑箱模型,因此我们必须使用 LIME 来理解为什么一个特定的个人(单元 35)被归类为良好的支付者。

在下表中,您可以看到石灰参数的良好选择如何带来可靠和稳定的解释,而当选择了不良参数时,同一家伙的 ML 预测完全不稳定。
稳定性指数有助于您发现这种不稳定性(事实上,在图表的右边部分,我们有非常不同的时间解释,并且指数非常低!)

给用户的时间说明表 35。在左边,一个好的参数选择产生稳定的解释;在右边,解释不稳定。稳定性指数有助于我们发现不一致性。资料来源:稳定指数文件

LIME 的解释很容易理解:将棒线的值和截距相加,我们就获得了有关个人违约概率的 ML 预测(Unit 35)。
条形的长度突出了每个变量的具体贡献:绿色的条形将模型推向“好支付者”预测,而红色的条形将模型推向“坏支付者”。

概括一下

在本文中,我们解决了 LIME 解释的不稳定性这个大问题,它破坏了对 ML 方法的信任。我从数学的角度展示了这一点,并使用了真实的案例应用程序。
我认为实践者通常不注意不稳定性问题,特别是因为没有工具来控制它。

我介绍了石灰的一对稳定性指标,可以帮助从业人员发现这种问题。我鼓励每个使用 LIME 的人提供指数值,以确保解释是可靠的。

这是机器学习模型走向可信石灰解释的第一步。

[1]维沙尼,g .,巴格利等人,2020。石灰的统计稳定性指数:获得机器学习模型的可靠解释,arXiv 预印本

[2]m . r .扎法尔,N.M .汗,2019 年。 DLIME:计算机辅助诊断系统的确定性局部可解释模型不可知解释方法,arXiv 预印本

在 Raspberry Pi 上安装 Airflow 2(使用 Python 3.x)

原文:https://towardsdatascience.com/install-airflow-2-on-a-raspberry-pi-using-python-3-x-a137117ba4c7?source=collection_archive---------24-----------------------

构建数据工程管道(使用 Raspberry Pi)——第一部分

气流是数据工程常用的工具。编排工作流很棒。Airflow 版只支持 Python 3+版本,所以我们需要确保使用 Python 3 来安装。我们也可以将它安装在另一个 Linux 发行版上。

这是系列文章的第一篇,在这里我们将构建一个完整的数据工程管道(使用 Raspberry Pi 的)。要关注这个系列,只需订阅 简讯

安装依赖项

让我们确保我们的操作系统是最新的。

现在,我们将在树莓 Pi 上安装 Python 3.x 和 Pip。

气流依赖 numpy ,numpy 有自己的依赖关系。我们将通过安装必要的依赖项来解决这个问题:

我们还需要确保使用 Python3 和 Pip3 安装 Airflow,因此我们将为两者设置一个别名。为此,通过添加以下内容来编辑~/.bashrc:

或者,您可以直接使用pip3进行安装。对于本教程,我们将假设别名正在使用中。

安装气流

创建文件夹

我们需要一个占位符来安装气流。

安装气流组件

最后,我们可以安全地安装气流。我们从定义 airflow 和 python 版本开始,以获得正确的约束 URL。约束 URL 确保我们为正确的 python 版本安装正确的 airflow 版本。

初始化数据库

在运行 Airflow 之前,我们需要初始化数据库。这个设置有几个选项:1)对一个单独的数据库运行 Airflow,2)运行一个简单的 SQLite 数据库。本教程中使用了 SQLite 数据库,所以除了初始化数据库之外,没有什么要做的。

所以让我们初始化它:

运行气流

现在可以同时运行服务器和调度程序:

现在在浏览器上打开 http://localhost:8080 。如果您需要登录,您需要创建一个新用户。这里有一个例子:

一旦通过验证,现在可以看到主屏幕:

就这样——您现在已经安装了气流系统!可选地,您可以采取额外的步骤。

可选择的

自动启动气流

为了在系统启动时自动启动 web 服务器和调度程序,我们需要三个文件:airflow-webserver.serviceairflow-scheduler.service和一个environment文件。让我们把它分成几个部分:

  1. Airflow 的 GitHub repo 下载airflow-webserver.serviceairflow-scheduler.service
  2. 将它们粘贴到/etc/systemd/system文件夹中。
  3. 编辑这两个文件。首先,airflow-webserver.service应该是这样的:

现在继续编辑airflow-scheduler.service文件,看起来应该是这样的:

注意userGroup已经改变,还有ExecStart。您还会注意到还有一个尚未创建的EnvironmentFile。这就是我们接下来要做的。

4.创建环境文件。你可以叫它任何名字。我选择将其命名为env ,并将其放在/home/pi/airflow文件夹中。换句话说:

让我们编辑env文件并放置内容:

5.最后,让我们重新加载系统守护进程:

就是这样!下一步是什么?

在这个数据工程系列的下一篇博文中,我们将使用 Airflow 创建我们的第一个有向无环图(DAG)。订阅简讯,不要错过!

来源

  1. https://air flow . Apache . org/docs/Apache-air flow/stable/installation . html
  2. https://medium . com/the-kickstarter/Apache-air flow-running-on-a-raspberry-pi-2e 061 F6 c 3655
  3. http://www . the crusty engineer . com/home/post/setting _ up _ air flow _ on _ a _ raspberry _ pi _ 4 _ part _ 1

原载于pedromadruga.com

从数据块上的私有 PyPI 安装定制 Python 库

原文:https://towardsdatascience.com/install-custom-python-libraries-from-private-pypi-on-databricks-6a7669f6e6fd?source=collection_archive---------10-----------------------

在这篇博文中,我将一步一步地解释如何在 Databricks 集群上集成您的私有 PyPI 存储库。因此,您将能够像平常使用公共库一样轻松地安装自己的定制 Python 库。

Anaya Katlego 在 Unsplash 上的照片

这种方法为跨数据团队共享代码和库打开了大门,同时保持了版本控制。此外,它提供了在数据块上应用混合编码方法的可能性,其中您可以组合在本地机器上编写的库(使用 CI/CD 管道正确测试和发布)和使用这些库的笔记本。

注意:本教程重点介绍 Azure。如果你碰巧在一家不同的云提供商工作,但你仍然对这个话题感兴趣,请继续阅读。您将很有可能能够很容易地将这个概念应用到其他环境中。

为什么应该使用私有的 PyPI 存储库

Databricks 提供了一种在集群上安装公共库的非常简单的方法,所以只需点击几次就可以安装它们。不幸的是,对于自制的定制库,这个过程并不容易。

在这种情况下,目前为止我看到的最流行的解决方案是将代码打包到 Python Wheel 中,并将其上传到 Blob 存储中,这样您就可以将它安装为 DBFS 库。找到的第二个解决方案是直接从 Git 存储库安装一个库,因此您必须提供 Git URL 和身份验证方法。虽然这两种解决方案都成功了,但是我们遗漏了一些非常重要的东西:版本控制。

为什么库版本控制很重要?

当编写自己的库时,有时您会编写为特定解决方案量身定制的代码,这样重用的可能性就不会太高。在其他情况下,您可能会创建一个包含类和实用函数的代码包,并与您的同事共享,这样他们就不必重新发明轮子了。在这两种情况下,如果您继续使用您的库,您将会引入一些更改,这些更改可能会搞乱甚至正在生产中运行的解决方案。

防止这种情况发生并让每个人都满意的唯一方法是引入库版本控制。这样,每个解决方案或环境都可以使用不同的固定版本的库,并且在引入更改时不会出现任何问题。

两个项目使用同一个库的不同版本|作者图片

数据块上的私有 PyPI 存储库

回到 Databricks 中的自制库,以前提出的方法都没有针对这个问题的健壮解决方案。您可以在 Blob 存储上上传和维护具有不同版本名称的 Python Wheels,或者在 Git Repo 上发布分支。即使这样做了,也很难追溯每个版本的变化,你必须自己构建和维护这个机制,甚至更难,与你的库的所有用户保持一致。换句话说,对于一个已经解决的问题,这些都是笨拙的变通方法。

PyPI 库已经存在多年,最流行的 Python 库都是在公共 PyPI 回购上发布的。同样,您可以拥有自己的 PyPI 存储库,并从版本控制功能中获益——您可能希望该存储库是私有的,这样您的组织库就不会对所有人公开。

Azure DevOps 上,拥有自己的私有 PyPI 库超级容易。您只需要创建一个 工件 Feed ,其中包含最常见编程语言的包存储库。之后,你可以在那里发布你的 Python Wheels 并从它的所有特性中获益。例如:跟踪每个版本发布的 Git Repo 的提交的能力。

辅导的

既然我已经解释了使用私有 PyPI 存储库来保存我们的定制库版本的一些好处,那么让我们看看如何将它集成到 Databricks 集群上,以便您能够安装您的定制库。

先决条件

总之,您需要在 Azure 工件提要中发布的自定义 Python 包,以及在数据块工作区中注册为秘密范围KeyVault

如果你有点迷路,不知道如何到达那里,这里有一个包含所有先决条件和一些有用链接的列表:

  • Azure DevOps 项目。
  • Azure Repos 中的 Git Repo(如何创建 Git repo 此处)。
  • Git Repo 中的 Python 代码用一个setup.py生成一个 Python 轮(如何生成一个 Python 轮此处)。
  • 工件提要(如何创建工件提要这里)。
  • Git Repo 中的 Azure Pipeline YAML 文件来生成 Python Wheel 并将其发布到工件提要(这里的代码)。
  • 从 YAML 文件注册运行 Azure Pipeline(怎么做此处)。
  • Azure Databricks 工作区。
  • 蓝色钥匙金库。
  • Azure Key Vault 在 Databricks Workspace 中注册为秘密范围(如何操作此处)。

我自己的演示设置

对于这篇文章,我做了一个演示设置,如果你看到任何参考资料,看看它可能对你有好处。

我在演示中使用的 Python 包(称为“demopackage”)非常简单。它只包含几个用 PySpark 和 Pandas 生成数据帧的函数。正如你在图片中看到的,它也被发布到我的工件提要“datalabartifacts”。

我自己的工件提要上的代码文件夹结构和已发布包|作者图片

在 Azure 上,我只有一个包含数据块和密钥库的资源组。此外,密钥库已在 Databricks 中注册为同名的秘密范围。

我自己的资源组上的资源|作者图片

神奇的配方

这个过程的目标是允许 Databricks 中 Spark 集群的底层虚拟机集成工件提要中的私有 PyPI 存储库,并能够从其中安装 Python 库。

1.在 Azure DevOps 上生成个人访问令牌

因为我们的工件提要是私有的(我们希望保持它的私有),所以我们需要为我们的虚拟机提供一种方法来验证 Arifact 提要。

不幸的是,在做了大量研究后,我发现最安全的方法是使用 Azure DevOps 个人访问令牌(PAT)。这个 PAT 是个人的,由每个 DevOps 用户发布,因此 Spark 虚拟机将使用这个令牌来模拟用户进行身份验证。这意味着在工件提要注册表中,您将看到发布者用户是下载包的用户。此外,PAT 将在一年后到期,因此请注意,您需要在到期前续订。

这里的建议是创建一个访问受限的服务帐户(DevOps 中的假用户),仅用于生成此 PAT,并在到期日前续订。

无论如何,你都可以通过点击用户设置个人访问令牌新令牌,从 Azure DevOps 生成个人访问令牌。给它一个名称,指定到期时间,以及 PAT 的权限(只需要在包装上读取)。完成后,复制生成的令牌。

按作者在 Azure DevOps | Image 上生成个人访问令牌的步骤

2.将令牌作为密码添加到密钥库中

生成的令牌可以用来从工件提要中检索包。如果这被泄露到你的组织之外,这将是一个大问题。这意味着黑客可以窃取工件提要中可用的软件包。

没有人希望这种情况发生,所以我们需要将令牌存储在一个安全的地方,这样我们就可以使用它,而不会将其暴露为纯文本。为此,我们需要在 Azure Key Vault 中创建新的秘密来存储它。

转到您的密钥库,单击SecretsGenerate/Import,并通过给它命名并使用在上一步中生成的 PAT 令牌作为值来创建一个密钥。

注意:使用的密钥库必须是在 Databricks 工作区中注册为 Secret 作用域的密钥库。

在 Azure Key Vault | Image by Author 中创建秘密的步骤

3.将环境变量添加到数据块集群

终于到了跳入 Databricks Workspace 的时候了!

进入计算→选择集群→配置,并继续编辑。在高级选项下,添加以下环境变量:

PYPI_TOKEN={{secrets/YourSecretScopeName/pypitoken}}

这样,我们就在连接到我们的密钥库的 Secret 作用域上设置了一个值。

注意:不要忘记用自己的名字替换秘密范围和秘密名称。

从 Secret Scope | Image by Author 设置 Databricks 群集中的环境变量

4.获取 PyPI 存储库 URL

让我们暂时回到 Azure DevOps,获取私有 PyPI 存储库的 URL。

为此,点击工件→选择您的工件提要→连接到提要→ pip ,然后复制 URL。

按作者获取 PyPI 存储库 URL |图像

4.使用魔法酱为数据块集群创建初始化脚本

在介绍魔酱之前,我先来说明一下窍门。

当您使用 UI 在 Databricks 群集上安装库时,Databricks 会指示所有节点单独安装库,因此它们会提取软件包并继续安装。

这意味着,如果我们想从 Databricks 集群中的私有 PyPI 存储库中安装软件包,每个节点都需要能够 1)找到私有 PyPI 存储库,2)成功地通过验证。

为了做到这一点,我们必须告诉每个集群节点 Pip 安装私有 PyPI repo 的 URL 是什么,以及如何进行身份验证,在本例中使用令牌身份验证。这样做的地方是我们必须添加一个新的extra-index-url/etc/pip.conf文件。

实际上,我们可以通过使用 Init 脚本在数据块中实现这一点。这些是在集群初始化期间在每个节点上运行的 Shell 脚本。

Init 脚本本身应该是这样的(注意,您必须用自己的 URL 替换 PyPI URL):

#!/bin/bash
if [[ $PYPI_TOKEN ]]; then
   use $PYPI_TOKEN 
fi
echo $PYPI_TOKEN
printf "[global]\n" > /etc/pip.conf
printf "extra-index-url =\n" >> /etc/pip.conf
printf "\thttps://$PYPI_TOKEN@pkgs.dev.azure.com/organization/DataLab/_packaging/datalabartifacts/pypi/simple/\n" >> /etc/pip.conf

如您所见,我们正在将之前创建的集群环境变量PYPI_TOKEN的引用设置到/etc/pip.conf文件中,这意味着根本不会显示纯文本,因为该值将在运行时解析。

注意:如果你试图使用echo命令在日志中显示它的值,你将只能看到[REDACTED],因为数据块隐藏了所有来自秘密范围的值。

因为手动将脚本上传到 Databricks 可能有点棘手,所以最好通过在单元格上运行以下代码从笔记本中轻松生成脚本(不要忘记用您自己的 URL 替换 PyPI URL):

script = r"""
#!/bin/bash
if [[ $PYPI_TOKEN ]]; then
  use $PYPI_TOKEN
fi
echo $PYPI_TOKEN
printf "[global]\n" > /etc/pip.conf
printf "extra-index-url =\n" >> /etc/pip.conf
printf "\thttps://$[PYPI_TOKEN@pkgs.dev.azure.com](mailto:PYPI_TOKEN@pkgs.dev.azure.com)/organization/DataLab/_packaging/datalabartifacts/pypi/simple/\n" >> /etc/pip.conf
"""dbutils.fs.put("/databricks/scripts/init-scripts/set-private-pip-repositories.sh", script, True)

注意:通过这种方式,我们创建了一个集群范围的初始化脚本,这是比全局初始化脚本更好的选择,因为缺少 Env 变量会导致其他集群的初始化失败。

5.将 Init 脚本添加到您的数据块集群中

现在,我们希望我们的集群在初始化过程中运行这个 Init 脚本。为此,我们转到计算→选择集群→配置,再次编辑同一个集群。这一次,我们将在高级选项下添加初始化脚本 DBFS 路径。

按作者将初始化脚本添加到数据块群集|映像

此时,您已经可以启动集群了。它将运行 Init 脚本,因此您的工件提要的私有 PyPI 存储库将完全可访问。

6.在 Databricks 集群中安装 Python 库

像往常一样,进入计算→选择您的集群→库→安装新库

在这里,您必须在工件提要中指定您发布的包的名称,以及您想要安装的特定版本(不幸的是,这似乎是强制性的)。

将 PyPI 库安装在 Databricks 群集|按作者排列的映像上

过一会儿你会看到安装成功了!🥳

安装的 PyPI 库|作者图片

注意:现在 Pip 正在不止一个 PyPI 存储库中搜索包。因此,如果在另一个存储库中有另一个同名的库,可能会发生库名冲突。如果您不使用唯一的库名,就不能保证您会安装您真正想要的库..

7.从 Databricks 笔记本中使用 Python 库

最后,您可以打开一个新的 Databricks 笔记本,导入您的库并享受结果!🚀

在 Databricks 笔记本上使用自定义 Python 库|作者图片

结论

一旦你达到这一点,我想你已经可以想象这是多么美好。这为在保持版本控制的同时跨数据团队共享代码和库打开了大门。

此外,它提供了在数据块上考虑混合编码方法的可能性,其中您可以将在本地机器上编写的库(使用 CI/CD 管道正确测试和发布)和使用这些库的笔记本结合起来。

我没有在网上的其他地方看到过这种方法,所以我决定在这里发布。我希望这对你和我的许多同事一样有帮助。祝你好运!

在 AWS EC2 实例上安装 Jupyter notebook 和 Rstudio 服务器

原文:https://towardsdatascience.com/install-jupyter-notebook-server-on-aws-ec2-instance-91812bc83c44?source=collection_archive---------22-----------------------

利用云计算进行数据分析

图片由马库斯·斯皮斯克Unsplash 上拍摄

介绍

Python 和 R 是两种最流行的数据分析编程语言。Jupyter notebook 和 Rstudio 是各自的 ide。每个打算发展数据科学技能的人在他们的本地机器上都至少有一个这样的工具。与本地机器相比,云计算将允许人们随时随地访问这些工具。即使有这些 ide 的云版本(google colab 和 Rstudio cloud),它们也有局限性。例如,每次您启动一个新的 colab VM,您都需要安装这些包,除非您配置在 google drive 上安装这些包,这会导致一些技术开销。Rstudio cloud 的免费帐户限制为 15 小时。在本文中,我将分享在 AWS Elatic Compute Cloud(EC2)上安装 Jupyter notebook 和 Rstudio 的步骤,当用户登录时,服务器可以随时准备就绪。

亚马逊网络服务

首先,您需要创建并激活 AWS 帐户。步骤可以在这里找到。使用 AWS 的最小特权原则创建管理员帐户。登录 AWS 控制台以启动 EC2 实例。AWS 提供一年免费使用 EC2 (t2.miro)。其余的都可以选择默认设置。

作者图片

遵循此处的步骤使用 putty 将 windows 连接到 EC2。Mac OS 和 Linux 的连接更加直接。您也可以使用 EC2 实例在浏览器上连接。

作者图片

成功连接后,您应该会看到这一点。

作者图片

安装 Anaconda

执行下面这四个命令来更新系统并下载 anaconda shell 脚本。

sudo yum update -y sudo yum -y groupinstall "Development tools" sudo yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel wget [https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh](https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh)

耐心等待执行完成,执行这个命令来安装 anaconda。在整个过程中,您可能需要点击“输入”或“是”来继续。

bash Anaconda3-2021.05-Linux-x86_64.sh

作者图片

安装完成后,您需要激活配置。source ~/.bashrc

在终端中键入 python 以确认成功安装后,您应该会看到 base enviroment 和 python 3 . 8 . 8 版。

作者图片

远程运行 Jupyter 笔记本

既然 anaconda 已经成功地安装在 EC2 实例上,我们将远程运行 Jupyter notebook。首先,我们可以执行这些命令来生成配置文件和设置密码。

jupyter notebook --generate-config

在 ipython 环境中运行这个程序,并输入两次密码。保存生成的哈希字符串以备后用(!!重要)。

from notebook.auth import passwd
passwd()

退出 python 并为 https 创建证书

mkdir certs

cd certs

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mykey.key -out mycert.pem

配置 jupyter_notebook_config.py

sudo vim /home/ec2-user/.jupyter/jupyter_notebook_config.py

修改如下五个设置(使用 vim 中的/进行搜索并删除#):

c.NotebookApp.password=''  //(hashed-password)
c.NotebookApp.ip='0.0.0.0'
c.NotebookApp.open_browser=False
c.NotebookApp.port=8888
c.NotebookApp.certfile='' //(the directory for mycert-pem)

作者图片

作者图片

作者图片

作者图片

作者图片

执行下面的命令来运行服务器

jupyter notebook

编辑此 EC2 实例的安全组

作者图片

访问服务器,方法是转到

[https://(your](/(your) AWS public dns):8888/

如果我们关闭终端,服务器将停止运行。我们可以关联一个弹性 IP 并执行下面的命令以避免挂断:

nohup jupyter notebook &

作者图片

安装 Rstudio 服务器

参考 Rstudio 文档安装 R

sudo yum install [https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm](https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm)

作者图片

sudo yum install yum-utils

sudo yum-config-manager --enable "reel-*-optional-rpms"

指定 R 版本

export R_VERSION=4.0.5

curl -O https://cdn.rstudio.com/r/centos-7/pkgs/R-${R_VERSION}-1-1.x86_64.rpm

sudo yum install R-4.0.5-1-1-.x86_64_rpm

创建符号链接

sudo ln -s /opt/R/${R_VERSION}/bin/R /usr/local/bin/R

sudo ln -s /opt/R/${R_VERSION}/bin/Rscript /usr/local/bin/Rscript

下载并安装 Rstudio Serverwget

wget https://download2.rstudio.org/server/centos7/x86_64/rstudio-server-rhel-2021.09.1-372-x86_64.rpm
sudo yum install rstudio-server-rhel-2021.09.1-372-x86_64.rpm

作者图片

创建帐户以登录 RStudio

useradd [your account]

passed [your account]

如前所述,编辑安全组以添加端口 8787,然后通过转到

[https://(your](/(your) AWS public dns):8787/

作者图片

通过 4 个简单的步骤安装支持 CUDA、cuDNN 和 GPU 的 TensorFlow

原文:https://towardsdatascience.com/install-tensorflow-with-cuda-cudnn-and-gpu-support-in-4-easy-steps-954f176daac3?source=collection_archive---------13-----------------------

借助 TensorFlow 2.4 和 GPU 支持,为深度学习建立前沿环境。

在这篇文章中,我们将通过几个简单的步骤来设置TensorFlow 2.4(最新的主/次版本),在运行 Debian 或 Ubuntu 的云虚拟机上启用 GPU 加速。

希望这有助于解决耗时且令人沮丧的过程使用 TensorFlow 配置您的深度学习环境!

鸣谢:手数 via iStockPhoto

硬件

在 AWS、GCP 和 Azure 上使用 NVIDIA Tesla v100 、P4 和 K80 深度学习 GPU 进行了测试。任何兼容 NVIDIA CUDA 的 GPU 都应该可以工作。

软件

  • 兼容 Debian 的操作系统(推荐 Ubuntu 18.04)
  • Python 3.8
  • Anaconda 包管理器

步骤 1 —安装 Conda 软件包管理器

步骤 2-创建您的 Conda 环境

在这一步,我们将设置我们的 Conda 虚拟环境,并让 Conda 处理安装 Python 3.8 的繁重工作。

步骤 3 —安装 NVIDIA 开发人员库

这是许多设置和安装变得棘手的地方。TensorFlow 的每个版本都被编译为使用 cuDNN 和 CUDA 开发人员库的特定版本

对于任何想知道的人来说,CUDA 是 NVIDIA 的 GPU 加速代码工具集,cuDNN 被 NVIDIA 描述为“深度神经网络的 GPU 加速原语库。TensorFlow 2.4 还没有可用的 Conda 安装脚本,因此我们将使用 TensorFlow 团队的指令自行安装库。

步骤 4-确认您的 GPU 设置

TensorFlow 2.4介绍了一种新的方法来检查确认您的 GPU是否可用

让我们看看它的实际效果…

确认 TensorFlow 可以看到你的 GPU

结论

你可以走了!这篇文章最初发表在我们的博客 Gretel.ai 上——如果你有兴趣了解更多关于数据隐私和合成数据的最新趋势,请在 twitter 上关注我们,查看我们的博客,或者给我们发邮件 hi@gretel.ai

在苹果 M1 MAC 电脑上安装 XGBoost 和 LightGBM

原文:https://towardsdatascience.com/install-xgboost-and-lightgbm-on-apple-m1-macs-cb75180a2dda?source=collection_archive---------5-----------------------

在苹果 M1 MAC 上安装 arm64 原生版 XGBoost 和 LightGBM

作者照片

在这篇 上一篇文章 中,我解释了如何安装 TensorFlowScikit-Learn 以及其他几个原生为苹果 M1 (arm64)编译的包。

在这里我一步一步的解释如何安装两个最强大的渐变增强包: XGBoostLightGBM 。请注意,在撰写本文时, CatBoost 还不能安装在 M1 上。

LightGBM 可以直接从 Conda miniforge 安装,但是 XGBoost 还没有本地版本。以下步骤可以正确编译它。

步骤 1: Xcode 命令行工具

通过从苹果开发者下载或键入以下命令来安装 Xcode 命令行工具:

xcode-select --install

第二步:小型锻造

miniforge github 安装用于 arm64(苹果硅)的 miniforge。

Miniforge 支持安装为苹果芯片原生编译的 python 包,包括 scikit-learn

步骤 3:安装 Brew

Brew 现在与 M1 兼容,并在本地软件包存在时安装它们。转到家酿网站,将安装命令复制/粘贴到您的终端。

步骤 4:从 Brew 安装必要的库

必须从 Brew 安装两个库才能编译 XGBoost。

brew install cmake libomp

步骤 5:创建康达环境

不要忘记打开一个新的会话或获取您的。在安装 miniforge 之后,在完成这个步骤之前。

创建一个空的 Conda 环境,然后激活它并安装 python 3.8 和所有需要的包。

conda create -n boost
conda activate boost
conda install python=3.8.8
conda install numpy scipy scikit-learn

注意numpyscipy是 XGBoost 的依赖项。在从 pip 安装 XGBoost 之前从 Conda (conda-forge)安装它们是非常重要的,因为它确保在环境中有这些包的 arm64 版本。

当加载并编译scipy的 pip 版本时,尝试从 pip 直接安装 XGBoost 失败。

步骤 6:安装 LightGBM

LightGBM 在 conda-forge 下已经有了预编译的 arm64 版本。

conda install lightgbm

第 7 步:安装 XGBoost

由于 XGBoost 原生 arm64 版本在 conda-forge 中尚不可用,必须从 pip 安装。在步骤 5 之后,所有依赖项都已经安装在本机版本中。

pip install xgboost

本环境下编译安装 XGBoost。

现在你可以测试了

以下脚本使用 LightGBM 和 XGBoost 训练和测试二进制分类器。

import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import timefrom lightgbm import LGBMClassifier
from xgboost import XGBClassifierprint('make classification ...')X,y = make_classification(n_samples=1000000,
                         n_features=50,
                         n_informative=30,
                         n_redundant=5,
                         n_repeated=0,
                         n_classes=2,
                         n_clusters_per_class=2,
                         class_sep=1,
                         flip_y=0.01,
                         weights=[0.5,0.5],
                         random_state=17)X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3,random_state=1000)print(f'X_train shape: {X_train.shape}')
print(f'Train LGBM classifier ...')
clf = LGBMClassifier(n_estimators=100,
                     num_leaves=64,
                     max_depth=5,
                     learning_rate=0.1,
                     random_state=1000,
                     n_jobs=-1)start = time.time()
clf.fit(X_train,y_train)
elapsed = time.time() - start
print(f'LGBM Training ran in {elapsed:.5f} seconds')y_pred = clf.predict(X_test)
print(f'Test Accuracy: {accuracy_score(y_test,y_pred):.2f}')print(f'Train XGB classifier ...')
clf = XGBClassifier(n_estimators=100,
                     max_depth=5,
                     max_leaves=64,
                     eta=0.1,
                     reg_lambda=0,
                     tree_method='hist',
                     eval_metric='logloss',
                     use_label_encoder=False,
                     random_state=1000,
                     n_jobs=-1)
start = time.time()
clf.fit(X_train,y_train)
elapsed = time.time() - start
print(f'XGB Training ran in {elapsed:.5f} seconds')y_pred = clf.predict(X_test)
print(f'Test Accuracy: {accuracy_score(y_test,y_pred):.2f}')

演出

这个非常简单的测试给出了 MacBook Air M1 与 Core i5 iMac 和 Xeon Platinum 实例相比的以下培训时间。

MacBook Air M1 2020 8GB/512 GB

LightGBM 训练:3.44 秒
XGBoost 训练:4.59 秒

2017 款 iMac 27 英寸酷睿 i5 @ 3.8GHz / 40GB 内存

LightGBM 训练:5.03 秒
XGBoost 训练:6.90 秒

8 核英特尔至强白金处理器@ 2.5 GHz 实例

LightGBM 训练:5.27 秒
XGBoost 训练:6.26 秒

XGBoost 和 LightGBM 在 Mac M1 上运行并具有出色的性能。

请注意,由于这些软件包的开发团队尚未发布正式的苹果芯片版本,因此没有优化,也没有使用 GPU。

感谢您的阅读。

在云上安装 CVAT(英特尔的计算机视觉注释工具)

原文:https://towardsdatascience.com/installing-cvat-intels-computer-vision-annotation-tool-on-the-cloud-c7759ae28f0e?source=collection_archive---------10-----------------------

计算机视觉项目的智能数据注释

这篇文章的一个版本最初发表在 的 Scaleway 博客 上。

在本文中,我们将了解如何使用开源的 CVAT 工具,为存储在 S3 对象存储桶中的图像和视频文件建立一个数据注释平台。我们最终将得到一个运行在公共云上的 CVAT 服务器——也就是欧洲云提供商 Scaleway(然而,本教程的大部分内容也适用于您选择的其他提供商)。全面披露:这篇博文的作者目前是 Scaleway 的员工:-)他说

图片来源:www.scaleway.com

介绍

我们都听说过“数据是新的石油”这句话。数据无疑推动了许多最近的技术进步,但这种比较并不仅限于此。就像原油一样,数据在投入使用之前需要进行处理。处理阶段通常包括清理、各种转换以及手动注释,这取决于数据和用例。在计算机视觉和自然语言处理(NLP)领域,对后者的需求很高:换句话说,对人类来说最自然的数据格式,而不是最好以表格形式查看的结构化数据。手动数据注释是一个耗时且昂贵的过程。更糟糕的是,深度人工神经网络,即计算机视觉和 NLP 的当前技术水平,是需要最大数据量进行训练的算法。具有节省时间的外推功能和其他类型的自动化的高效注释工具,对机器学习项目生命周期中可以说是最关键的阶段有很大帮助:建立训练数据集。

CVAT(计算机视觉注释工具的缩写)是一个来自英特尔的开源图像和视频注释平台。它支持最常见的计算机视觉任务:图像级分类,以及对象检测和图像分割,其中图像上的感兴趣区域分别通过边界框和多边形(或像素)图像遮罩来选择。

通过不同的计算机视觉任务检测狗,从左到右:分类,物体检测,图像分割。照片由亚历山德拉·拉默林克在 Unsplash 上拍摄,由作者编辑

除了提供基于 Chrome 的注释界面和基本的用户管理功能,CVAT 还通过自动化部分流程减少了手动注释的数量。在这篇博文中,我们将重点讨论如何在 Scaleway 公有云上安装 CVAT。

云上的数据标注:为什么和如何?

在云上运行 CVAT 最直接的方式是简单地启动一个实例(由云提供商托管的虚拟机),并遵循作为 CVAT 文档一部分的快速安装指南。安装完成后,您可以通过 SSH 隧道连接到实例来访问 CVAT,并在 Google Chrome 浏览器中转至 localhost:8080 。然后,您可以从本地服务器上传图像和视频,并继续进行注释,就像在本地安装时一样。

然而,以这种明显不清晰的方式进行,不会给你带来云计算的任何好处。首先,考虑您的数据存储。计算机视觉项目需要大量的训练数据,因此可扩展性和成本效益是必须的。对象存储已经成为业界存储非结构化数据的首选方法。由于对要存储的文件的大小和数量几乎没有限制,大量的免费层(例如,Scaleway 每月提供 75GB 的免费对象存储),以及确保数据安全性和可用性的高冗余性,很难想到更好的地方来存储“新石油”。

根据标注工作人员的规模,您可能还希望启用注记工具的自动缩放。目前,让我们假设您正在运行的数据注释操作是可管理的,运行 CVAT 的单个实例就足够了。尽管如此,您并不一定希望让每个注释者都可以通过 SSH 访问您的实例。这也是我们将在下一节讨论的内容。

CVAT 在 Scaleway

收集资源

正如我们在上一节中所建立的,我们需要两个云资源来将我们的数据注释提升到下一个级别:一个对象存储桶和一个实例。下面是获得它们的一步一步的指南:

  1. 如果你还没有,你需要创建一个账户并登录console.scaleway.com
  2. 为了 SSH 到您的 Scaleway 实例,您将需要来创建一个 SSH 密钥。为了安装供 CVAT 使用的对象存储,您还需要来生成一个 API 密钥(当您这样做时,一定要记下访问密钥和秘密密钥,因为您很快就会需要它们)。
  3. 现在是时候创建你的对象存储桶了!这可以通过 Scaleway 控制台中的Storage / Object Storage选项卡完成。

经许可,通过 Scaleway 获取图像

创建存储桶后,您可以添加想要标记的文件,例如通过 Scaleway 控制台提供的拖放界面。让我们在bucketofdogs里放一些狗的照片:

经许可,通过 Scaleway 获取图像

稍后您将需要的信息之一是Bucket ID。可以从上面的Bucket Settings选项卡中读取这个桶的 ID,但实际上它就是这个桶的名称(在我的例子中就是bucketofdogs)。

4.既然我们珍贵的狗狗照片被安全地存储在一个奇特的数据中心,我们将需要一个实例。如果你想利用 CVAT 的自动注释功能(这是另一篇博文的主题),我建议你买一个高端的 GPU 实例。对于基本的手动注释用例,让我们从dev范围开始:

经许可,通过 Scaleway 获取图像

这是一个托管你的 CVAT 服务器的实例,每小时 1 欧分(或每月 7.30€)!

一旦您的实例被创建,您将到达它的Overview页面,在这里,除了其他内容,您将找到您的Instance ID。记下来。在同一个页面上,你会看到下面的 SSH 命令 : ssh root@[Public IP of your instance]。此时,您应该使用它来 SSH 到您的实例,并继续安装 CVAT。

安装 CVAT

让我们从先决条件开始:

下一步是前面步骤中的Bucket IDAPI Key派上用场的地方:

现在,您应该创建一个名为docker-compose.override.yml的文件(在当前的cvat文件夹中),替换下面的实例 ID,并将以下内容粘贴到 YML 文件中:

现在剩下的就是启动 CVAT 并创建一个超级用户帐户(也就是可以访问 CVAT 站点的 Django 管理面板的用户):

CVAT 图像注释

你可以在<your instance ID from the instance information page>.pub.instances.scw.cloud:8080访问你崭新的 CVAT 服务器。您可以使用您创建的超级用户帐户登录,也可以创建一个新帐户并使用它登录:

CVAT 截图

注意:截止到 2021 年 3 月,CVAT 的官方发行版设置为新创建的非管理员帐户可以立即访问机器上所有可用的注释任务。这些权限将在 CVAT 的未来版本中更新,但目前您可以使用 GitHub 问题 1030111412832702 中提到的变通办法。同时,确保只将实例的链接给那些你不介意在你的服务器上访问 CVAT 的人。

登录后,您将能够看到您的实例上存在的注释任务列表:

CVAT 截图

当您尝试创建新任务时,您会发现您上传到对象存储桶的图像文件可从Connected file share选项卡访问:

CVAT 截图

现在,当您(或其他用户)登录 CVAT 时,新任务将会出现:

CVAT 截图

是时候贴标签了!

CVAT 截图

谁是好狗【探子】?

完成数据集的标注后,可以选择支持的格式导出注记:

CVAT 截图

下一步是什么?

CVAT 是一个强大的图像和视频注释工具,您刚刚了解了如何利用公共云的可扩展性和成本效益来增强其优势。在 Scaleway,我们目前正致力于帮助您更进一步地进行数据标注,通过一个管理标签平台来处理所有的细节,并提供最大程度的自动化过程。好奇想了解更多?注册获取我们的更新!

如果您对在 Scaleway 上使用 CVAT 有任何问题或反馈,我期待着在 Scaleway Slack 社区中新创建的 #AI 频道听到您的意见。

使用 WSL2 在 Windows 11 上安装 Hadoop

原文:https://towardsdatascience.com/installing-hadoop-on-windows-11-with-wsl2-f11a585e41cf?source=collection_archive---------37-----------------------

如何在运行使用 WSL 1 或 2 的 Linux 发行版的 Windows 11 上安装和配置 Hadoop 及其组件。

来源: Unsplash

在之前的帖子中,我们看到了如何使用 WSL2 在 Windows 11 上安装 Linux 发行版,然后如何安装 Zsh 和 on-my-zsh 使终端更加可定制。在这篇文章中,我们将看到如何使用 WSL 在同一台 Windows 11 机器上安装完整的 Hadoop 环境。

安装依赖项

为了让 Hadoop 工作,您需要安装两个重要的依赖项。这些不是可选的,除非你已经安装了它们。所以请确保安装了这些依赖项。

安装 JDK

第一个依赖项是 java 开发工具包,或 JDK。建议搭配 Java 8,或者 Hadoop 的 Java 1.8。这是我的建议,因为我在使用新版 Java 时遇到了问题。但是你绝对可以给新版本一个机会。

此外,不管你安装甲骨文 JDK 或打开 JDK,或任何其他版本的 JDK。你只需要安装它。我使用以下命令在我已经安装在 Windows 11 上的 Debian Linux 上安装了 JDK 8:

sudo apt install adoptopenjdk-8-hotspot

要使这个包在 apt 库中可用,首先需要添加 PPA。为此,请运行以下命令:

sudo add-apt-repository --yes [https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/](https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/)

一旦安装了 JDK,请确保使用环境变量名 JAVA_HOME 导出 JDK 的路径。导出命令如下所示:

export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/bin/java

如果您只是在终端中运行这个命令,那么该变量将只为当前会话导出。为了使其永久化,您必须将该命令添加到中。zshrc 文件。

安装 OpenSSH

下一个要安装的依赖项是 OpenSSH,这样 Hadoop 就可以通过 SSH 进入本地主机。这也是必要的依赖。如果没有 SSH 到 localhost,Hadoop 的大多数组件都无法工作。要安装 OpenSSH,请在终端中运行以下命令:

sudo apt install openssh-server openssh-client -y

一旦我们为 SSH 安装了服务器和客户机,我们就必须为认证生成密钥。为此,运行以下命令,并仔细阅读您将得到的说明:

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa

生成密钥后,您必须将它们复制到授权密钥列表中,这样您就不必每次登录机器时都输入密码。这一点尤其重要,因为这是 Hadoop 所期望的。至少我还没有看到改变这种行为的选项。因此,运行下面的命令来 cat 我们刚刚创建的密钥文件的文件内容,然后将其复制到 authorized_keys 文件中:

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

现在,确保公钥文件具有正确的权限。这是因为,如果密钥文件的公共访问比所需的多,系统会认为该密钥可以被复制或篡改,这意味着该密钥是不安全的。这将使系统拒绝该密钥,并且不允许 SSH 登录。因此,运行以下命令来设置正确的权限:

chmod 0600 ~/.ssh/id_rsa.pub

接下来,启动 SSH 服务,这样我们就可以测试服务器是否工作正常。为此,运行以下命令:

sudo service ssh start

如果一切都如预期的那样,你就安全了。最后,运行以下命令以确保 SSH 按预期运行:

ssh localhost

如果一切正常,您应该会看到类似下面的截图:

太棒了。您可以通过按 CTRL + d 组合键退出到上一个会话。这就结束了依赖项安装阶段。现在让我们继续安装 Hadoop。

安装 Hadoop

下载 Hadoop

安装 Hadoop 的第一步是实际下载它。截至本文撰写时,Hadoop 的最新版本是 3.3.1 版,你可以从这里下载。你将从那里下载一个 .tar.gz 文件。要解压缩该文件,请使用以下命令:

tar xzf hadoop-3.3.1.tar.gz

这将创建一个名为 hadoop-3.3.1 的目录,并将所有文件和目录放在该目录中。因为我们将在本地机器上安装 Hadoop,所以我们将进行单节点部署,这也称为伪分布式模式部署。

设置环境变量

我们必须设置一些环境变量。最好的部分是,你只需要定制一个变量。其他的只是复制粘贴。无论如何,以下是我所说的变量:

export HADOOP_HOME=/mnt/d/bigdata/hadoop-3.3.1 
export HADOOP_INSTALL=$HADOOP_HOME 
export HADOOP_MAPRED_HOME=$HADOOP_HOME 
export HADOOP_COMMON_HOME=$HADOOP_HOME 
export HADOOP_HDFS_HOME=$HADOOP_HOME 
export YARN_HOME=$HADOOP_HOME 
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native 
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 
export HADOOP_OPTS"-Djava.library.path=$HADOOP_HOME/lib/nativ"

如您所见,您只需更改第一个环境变量 HADOOP_HOME 的值。将其设置为反映放置 Hadoop 目录的路径。同样,将这些导出语句放在中也是一个好主意。zshrc 文件,这样这些变量每次都会自动导出,而不是你必须这样做。一旦将它放入文件中,请确保您对其进行了源处理,以便它立即生效:

source ~/.zshrc

配置 Hadoop

接下来,我们必须编辑一些文件来更改各种 Hadoop 组件的配置。让我们从文件 hadoop-env.sh 开始。运行以下命令在编辑器中打开文件:

sudo vim $HADOOP_HOME/etc/hadoop/hadoop-env.sh

接下来,找到导出***$JAVA_HOME***变量的那一行并取消注释。这里,您必须提供与之前安装 Java 时相同的路径。对我来说,是这样的:

export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64/bin/java

接下来,我们必须编辑 core-site.xml 文件。这里我们必须提供 Hadoop 的临时目录,以及 Hadoop 文件系统的默认名称。使用以下命令在编辑器中打开文件:

sudo vim $HADOOP_HOME/etc/hadoop/core-site.xml

您将在这里找到一个空文件,其中包含一些注释和一个空的配置块。您可以删除所有内容,并用以下内容替换:

<configuration>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/mnt/d/hdfs/tmp/</value>
    </property>
    <property>
        <name>fs.default.name</name>
        <value>hdfs://127.0.0.1:9000</value>
    </property>
</configuration>

请确保创建您在此配置的临时目录。接下来,我们必须编辑 HDFS 配置文件 hdfs-site.xml 。为此,使用以下命令在编辑器中打开文件:

sudo vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml

在此配置文件中,我们将设置 HDFS 数据节点目录、HDFS 名称节点目录和 HDFS 复制因子。这里,您应该再次获得一个包含空配置块的文件。替换为以下内容:

<configuration>
  <property>
      <name>dfs.data.dir</name>
      <value>/mnt/d/hdfs/namenode</value>
  </property>
  <property>
      <name>dfs.data.dir</name>
      <value>/mnt/d/hdfs/datanode</value>
  </property>
  <property>
      <name>dfs.replication</name>
      <value>1</value>
  </property>
</configuration>

同样,确保您创建了数据节点和名称节点目录。接下来,我们有 MapReduce 配置文件。要在编辑器中打开它,请运行以下命令:

sudo vim $HADOOP_HOME/etc/hadoop/mapred-site.xml

您可以用以下内容替换配置块:

<configuration> 
  <property> 
    <name>mapreduce.framework.name</name> 
    <value>yarn</value> 
  </property> 
</configuration>

如您所见,这是一个指定 MapReduce 框架名称的简单配置。最后,我们有了 YARN 配置文件, yarn-site.xml 。使用以下命令在编辑器中打开文件:

sudo vim $HADOOP_HOME/etc/hadoop/yarn-site.xml

将以下配置添加到文件中:

<configuration>
  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>
  <property>
    <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
    <value>org.apache.hadoop.mapred.ShuffleHandler</value>
  </property>
  <property>
    <name>yarn.resourcemanager.hostname</name>
    <value>127.0.0.1</value>
  </property>
  <property>
    <name>yarn.acl.enable</name>
    <value>0</value>
  </property>
  <property>
    <name>yarn.nodemanager.env-whitelist</name>   
    <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PERPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
  </property>
</configuration>

这种配置没有什么可改变的。最后,我们完成了 Hadoop 的配置。我们现在可以开始格式化名称节点并启动 Hadoop。

格式化 HDFS 名称节点

在第一次启动 Hadoop 服务之前,首先格式化 HDFS 名称节点非常重要。显然,这确保了 name 节点中没有垃圾。一旦您开始更频繁地使用 HDFS,您就会意识到您格式化名称节点的频率比您想象的要高,至少在您的开发机器上是这样。无论如何,要格式化名称节点,请使用以下命令:

hdfs namenode -format

一旦收到名称节点的关闭通知,格式化就完成了。

启动所有 Hadoop

最后,我们正处于这项活动的最佳阶段,开始使用 Hadoop。现在,根据您实际想要使用的组件,有许多启动 Hadoop 的方法。例如,你可以只开始纱,或 HDFS 随着它,等等。对于这项活动,我们将开始一切。为此,Hadoop 发行版提供了一个方便的脚本。因为您之前已经导出了一些环境变量,所以您甚至不需要搜索那个脚本,它已经在您的路径中了。只需运行以下命令并等待它完成:

start-all.sh

这将需要几秒钟的时间,因为脚本只是等待前 10 秒钟,如果您错误地启动了操作,它不会做任何事情来为您提供取消操作的选项。坚持一下,您应该会看到类似于以下屏幕截图的输出:

这告诉我们 Hadoop 的所有组件都已启动并运行。为了确保这一点,如果您愿意,您可以运行 jps 命令来获取所有正在运行的进程的列表。您至少应该看到以下服务:

仅此而已。您现在在 Windows 11 PC 上运行 Hadoop,使用的是 WSL 1 或 2 上的 Linux 发行版。为了确保这一点,您可以使用以下简单的 HDFS 命令:

hdfs dfs -ls /

该命令将列出 HDFS 根目录下的所有文件和目录。如果这是一个全新的部署,你应该找不到太多。您将得到一个类似如下所示的列表:

差不多就是这样。我们完了!

如果你喜欢你在这里看到的,或者在我的个人博客Dev。要写博客,并希望在未来看到更多这样有用的技术帖子,请考虑在 Github 上关注我。

最初发表于 2021 年 11 月 1 日 https://blog.contactsunny.com**的

在 Visual Studio 代码中安装 Jupyter 笔记本支持

原文:https://towardsdatascience.com/installing-jupyter-notebook-support-in-visual-studio-code-91887d644c5d?source=collection_archive---------3-----------------------

轻松打开。双击 ipynb 文件

Unsplash 上由 René Teinze 拍摄的照片

如果你是一名数据科学家(或者正在努力成为一名数据科学家),你应该对 Jupyter 笔记本很熟悉。Jupyter Notebook 提供了一种便捷的方式,可以将 Python 代码(或其他语言)与 Markdown 文本结合到一个称为 Notebook 的画布上。Jupyter Notebook 的优势在于,它允许您轻松地选择性运行和修改部分代码,而无需运行整个程序。此外,您可以将格式化的文本(和图形)嵌入到您的文件中,从而使其他人可以轻松地直接阅读和修改您的代码。

但是,使用 Jupyter Notebook 需要启动内置的 Jupyter Notebook 服务器。并且您经常必须导航到包含您的。ipynb 文件,否则你将很难找到它们。

直到现在。现在可以在 Visual Studio 代码 (VS 代码)中运行 Jupyter Notebook 了。在这篇短文中,我将向您展示如何在 VS 代码中安装 Jupyter Notebook 支持,以便您可以通过直接双击它并在 VS 代码中编辑它来打开一个. ipynb 文件。

假设

在本文中,我假设您的计算机上已经安装了 Python 和 Jupyter 包。达到这个要求最简单的方法是安装 Anaconda—https://www.anaconda.com/products/individual-d

为什么已经安装了 Anaconda 还需要在 VS 代码中使用 Jupyter Notebook?这样做可以让你快速打开一个. ipynb 文件,而不需要启动 Jupyter 笔记本服务器。

安装 Jupyter 扩展

首先,启动你的 VS 代码,在扩展搜索框中输入“ jupyter notebook ”。选择第一个结果( Jupyter )并点击屏幕中间显示的 Install 按钮:

就是这样!一旦安装完成,您的 VS 代码中就已经有了 Jupyter Notebook。

创建新的 Jupyter 笔记本文件

要创建一个新的 Jupyter 笔记本文件,按下Ctrl-Shift-P(MAC OS 为 Shift-Cmd-P )调用命令面板。键入“ Jup ”,你会看到一个选项列表。选择 Jupyter 笔记本:新建空白笔记本:

将创建一个新的空白 Jupyter 笔记本:

选择内核

在运行您的笔记本之前,您需要通过点击窗口右上角的按钮来选择一个内核。对于我的机器,我将选择由 Anaconda 安装的 Python 版本:

一个笔记本内核是一个代码引擎,它执行笔记本文档中包含的代码。它使您能够在 Jupyter 笔记本上运行 Python 程序。

一旦你的内核被选中,你可能会看到一个 Windows 安全警告对话框。点击允许访问:

运行您的 Python 代码

现在,您可以通过编写一些 Python 语句来测试您的 Jupyter 笔记本。按 Ctrl-Enter 运行当前单元格,或按 Shift-Enter 运行当前单元格并移动到下一个单元格(如果当前单元格是笔记本中的最后一个单元格,将创建一个新单元格):

打开现有的。ipynb 文件

如前所述,安装 Jupyter Notebook 对 VS 代码的支持的好处是能够快速打开一个现有的。ipynb 文件。

当您双击现有的。ipynb 文件,将出现一个对话框。点击更多应用:

向下滚动列表,选择 Visual Studio Code 并点击 OK :

你的。ipynb 文件现在将在 Visual Studio 代码中打开。玩得开心!

结论

就我个人而言,我喜欢在我的浏览器上运行的原版 Jupyter 笔记本。但是,在很多情况下,我需要快速查看. ipynb 文件的内容。允许我查看我的。VS 代码的 ipynb 文件节省了我很多时间。试试看,让我知道你的经历!

在 Ubuntu 20.04 上安装多个替代版本的 Python

原文:https://towardsdatascience.com/installing-multiple-alternative-versions-of-python-on-ubuntu-20-04-237be5177474?source=collection_archive---------2-----------------------

PC:freepik.com

有时,您可能会使用不同版本的 python 同时处理不同的项目。通常使用 Miniconda 或 Anaconda 是最简单的解决方案,但是如果您的团队使用 python-venv 包来管理虚拟环境,那么您也需要遵循相同的约定。

在本文中,我将给出安装多个 python 版本的步骤,以及如何在不同版本之间切换并根据需要使用它们。

安装替代 Python 版本

在你做任何事情之前,打开你的终端,看看你的系统默认安装了哪个版本的 python。

python --version

PC:作者

如果你使用的是 Ubuntu 20.04,默认情况下你将拥有 python 版本。让我们安装 python 3.7,

sudo apt-get install software-properties-common# adding python repository 
sudo add-apt-repository ppa:deadsnakes/ppasudo apt update# install python 3.7
sudo apt install python3.7

要检查 python 3.7 是否安装正确,

PC:作者

但是如果你打印系统的 python 版本,它仍然是 python 3.8

PC:作者

那么我们怎么能说这个系统,使用了不同版本的 python 呢?

更新备选方案

我们可以使用 update-alternatives 命令为安装在 Ubuntu 系统中的同一软件的不同版本设置优先级。具有最高优先级的 Python 版本将被用作默认版本。

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.7 1sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2

在这里,我们将 3.7、3.8 版本的优先级设置为 1、2。由于版本 3.8 具有最高优先级,因此将被选为默认版本。

在不同版本之间切换

sudo update-alternatives --config python#select the number of python you want then enterpython --version

PC:作者

正如你现在看到的,python 版本是 3.7.10。您可以重复上述步骤,根据需要安装不同版本的 python,并根据需要设置优先级和使用它们。

要在 IDE 中使用这些 python 版本,请转到 IDE 的解释器设置,在那里您可以看到系统中可用的不同 python 版本。

使用不同版本的 python 创建虚拟环境

按照以下步骤,使用您想要的特定 python 版本创建一个虚拟环境

#if venv package for that version is not installed already
sudo apt install pythonX.x-venvpython -m venv venvsource venv/bin/activatepython --version

PC:作者

希望这篇文章对你有帮助!!!

在 M1 Mac 上安装 TensorFlow

原文:https://towardsdatascience.com/installing-tensorflow-on-the-m1-mac-410bb36b776?source=collection_archive---------1-----------------------

利用苹果的 ML 计算框架进行深度学习项目

Unsplash 上由 Karthikeya GS 拍摄的照片

如果你是 Mac 用户,你可能有一台运行苹果芯片的最新机器。要在 M1 MAC 电脑上利用苹果的 ML 计算框架进行原生硬件加速,您需要安装苹果的硬件加速 TensorFlow 和用于 macOS 11.0+的 TensorFlow 插件。

本文将展示如何使用 TensorFlow 为开发深度学习项目准备你的 M1 Mac 电脑。此外,我将向您展示如何安装 Jupyter Notebook 以及您的深度学习项目所需的各种附加库。

苹果在 https://github.com/apple/tensorflow_macos/issues/153 维护了一个 Github 页面,详细说明了在 Conda 环境下安装 TensorFlow 的说明。我的文章提供了一步一步的说明。

一重要提示。在继续下面的说明之前,请确保您的 Mac 上没有安装 Anaconda。如果您已经安装了一个,只需从 Mac 上删除 Anaconda 文件夹即可卸载它。

1.Xcode

您需要安装的第一个工具是 Xcode,可从 Mac AppStore 获得:

2。命令行工具

当你安装 Xcode 的时候,它也会安装命令行工具。但是如果您还没有安装它,下面的命令将会完成它:

$ **xcode-select --install**

3.小型锻造厂

不使用 Anaconda ,而是使用 MiniForge ,一个轻量级 Python 解释器,可以完全访问 conda 生态系统。

C onda 是一个运行在 Windows、Mac OS 和 Linux 上的开源包和环境管理系统。

你可以从https://github.com/conda-forge/miniforge下载迷你锻造

对于 M1 Mac,点击miniforge 3-ma cosx-arm 64项目(上表倒数第二)。下载完成后,启动终端并转到包含Miniforge 3-ma cosx-arm 64 . sh文件的目录,然后使用 bash 命令,如下所示,安装 Miniforge :

$ **bash Miniforge3-MacOSX-arm64.sh**

系统将提示您接受许可协议。接受它们并继续安装。安装完成后,关闭终端。

4.创造康达环境

在新的终端窗口中,通过键入以下命令启动 conda :

$ **conda**

您将看到以下内容:

要在苹果的 M1 机器上安装 TensorFlow,首先从https://raw . githubusercontent . com/mwidjaja 1/DSOnMacARM/main/environment . yml下载环境. yml 文件。

该文件包含创建 Python 环境的指令,该环境具有您需要的依赖项。要为 TensorFlow 创建新环境,请转到包含 environment.yml 文件的目录:

$ **cd Downloads**

然后,键入以下命令:

$ **conda env create --file=environment.yml --name tf_m1**

tf_m1 是我选择的新环境名。请随意将其更改为您自己想要的名称。现在,您可以激活新创建的环境:

$ **conda activate tf_m1**

5.为 macOS 安装 TensorFlow 和 TensorFlow 插件

Apple 的 TensorFlow 库列表可在:https://github.com/apple/tensorflow_macos/releases获得:

在撰写本文时,目前有三个可用版本:

  • v 0.1 阿尔法 3
  • v 0.1 阿尔法 2
  • v 0.1 阿尔法 1

选择最新版本( v0.1aplha3 )将引导您进入此页面:https://github . com/apple/tensor flow _ MAC OS/releases/tag/v 0.1 aplha 3:

观察并复制两个文件的链接:

tf_m1 环境中,您现在可以使用以下命令安装上述两个库:

$ **pip install --upgrade --force --no-dependencies https://github.com/apple/tensorflow_macos/releases/download/v0.1alpha3/tensorflow_addons_macos-0.1a3-cp38-cp38-macosx_11_0_arm64.whl https://github.com/apple/tensorflow_macos/releases/download/v0.1alpha3/tensorflow_macos-0.1a3-cp38-cp38-macosx_11_0_arm64.whl**

一旦安装了这两个库,您就可以通过启动 Python 然后导入 TensorFlow 并打印出其版本号来测试 TensorFlow :

如果以上操作成功,您的 TensorFlow 现在已正确安装在您的 M1 Mac 上。

6.安装其他基本库

除了安装 TensorFlow 库,您很可能需要安装其他库,如 matplotlibsklearnOpenCVPandas 等。因此,请继续安装它们,如下所示:

$ **conda install -c conda-forge matplotlib -y**
$ **conda install -c conda-forge scikit-learn -y**
$ **conda install -c conda-forge opencv -y**
$ **conda install -c conda-forge pandas -y**

-y 选项省去您在安装库时回答确认的麻烦。

7.安装 Jupyter 笔记本电脑

最后,您可能希望安装 Jupyter 笔记本:

$ **conda install notebook -y**

就是这样!测试 Jupyter 笔记本安装是否正确:

$ **jupyter notebook**

如果你能看到以下内容,你就万事俱备了!

一些问题

如果您尝试加载已保存的模型:

from tensorflow.keras.models import load_modelmodel = load_model('trained_model.h5')

您可能会遇到以下错误:

AttributeError: 'str' object has no attribute 'decode'

原来在内部, load_model() 使用的是更新版本的 h5py 模块。要解决这个问题,您可以使用以下命令将 h5py 的版本降级到版本 2.10.0:

$ **pip install 'h5py==2.10.0' --force-reinstall**

在 M1 Mac 上享受 TensorFlow 带来的美好时光!

如果你喜欢阅读我的文章,并且认为它对你的职业/学习有所帮助,请考虑注册成为一名灵媒会员。每月 5 美元,你可以无限制地访问 Medium 上的所有文章(包括我的)。如果你使用下面的链接注册,我会赚一小笔佣金(不需要你额外付费)。你的支持意味着我将能够投入更多的时间来写这样的文章。

https://weimenglee.medium.com/membership

安装 Ubuntu 20.04 LTS 并在其上运行 YOLOv4 和 YOLOv5。

原文:https://towardsdatascience.com/installing-ubuntu-20-04-lts-and-running-yolov4-and-yolov5-on-it-2ca0c93e244a?source=collection_archive---------11-----------------------

实践教程

运行对象检测模型的初学者指南

我最近有了一台游戏笔记本电脑,联想 Ideapad Gaming 3,并决定用它来进行一些计算机视觉工作。我一点也不知道我将要经历的麻烦。我决定写这篇文章,以便让这个过程对其他人来说更容易、更直接。

约书亚·雷德科普Unsplash 上拍摄的照片

联想 Ideapad Gaming 3 锐龙 5 4600H 于 2021 年 1 月上市。我最初尝试在上面安装 Ubuntu 18.04 LTS,因为我已经在上面工作了很长时间,但由于它的旧内核,我遇到了 wifi 适配器,触摸板,功能键等几个问题。而不是更新它的内核,我认为是时候转移到新的。18.04 LTS 支持将于 2023 年结束,在技术领域,你需要不断更新自己。

我的目标是在对象检测模型 YOLO (你只看一次)上运行推理,并在其上训练一个定制数据集。我以前在 Ubuntu 18.04 LTS 上使用过 YOLOv4,所以我选择在新的操作系统上尝试,同时也探索新的,所谓的 YOLOv5。

安装 Ubuntu 20.04 LTS

推荐的最低系统要求:

  1. 2 GHz 双核处理器
  2. 4 GiB Ram (1 GiB 也可以工作)
  3. 25 GB 硬盘空间
  4. 支持 1024x768 屏幕分辨率的 VGA
  5. 用于安装程序介质的 CD/DVD 驱动器或 USB 端口
  6. 建议上网

我有一个 Windows 10 的双启动配置。我用 Rufus 创建了一个可引导设备。保持分区方案与您的硬盘配置相同。我的是 GPT。保持文件系统为 FAT32。你可以从它的 官网 下载 Ubuntu 20.04 LTS 的 ISO 镜像。

创建可引导设备后,重新启动系统并从该设备引导。通常打开启动选项的键是 esc+F5 或 esc+F12,但是您可以在网上搜索您的系统的组合键。启动后,继续使用 Ubuntu(第一个选项)。

您可以从 按照其余步骤进行安装。我强烈建议您连接互联网,并在安装过程中选择安装第三方软件的选项。

如果使用 GPT 分区方案,那么创建主分区还是逻辑分区就无关紧要了。如果是 MBR 你可以参考 这个网页 更好的理解。对于给分区分配磁盘空间,我建议给分配 100–150 GB 的空间(尽管 50 GB 也可以)。通常两倍于当前 RAM 的内存被分配给交换区。我建议至少要有和你现在的 RAM 容量一样多的内存。其余的你可以设置到你的 home 目录下。只保留根目录和主目录可以使系统简单有效地使用。要了解更多选项,请参考 本网页

安装完成后,如果您的笔记本电脑型号是最近发布的,您可能会面临一些硬件问题。在我的情况下,我的触摸板不工作。它需要一个 HID 兼容的设备驱动程序。除了 windows 之外,联想没有提供太多的操作系统支持,所以新的驱动程序可能会包含在未来的 Ubuntu 内核版本中。您可以尝试更新您的内核来解决这些问题,或者在 web 上寻找特定的解决方案。对我来说, 这个 在一定程度上解决了我的问题。

为 YOLO 配置系统

要用 GPU 运行 YOLO,我们需要合适的驱动程序。转到“软件和更新”并在“附加驱动程序”中安装驱动程序。

如果你遇到任何问题,你也可以从命令行安装驱动程序。在和处,按照的指示进行操作。

如果从这里安装,然后,如果任何驱动程序显示(专有的,测试)选择它。否则,如果通过 cmd 安装,选择显示推荐的一个。图片作者。

我的 MoK 菜单截图。图片作者。

在安装 nvidia 驱动程序的过程中,您将被要求设置安全启动的密码,这将是在更新 MoK 设置时需要的。设置密码,并在重新启动时,从 MoK 菜单中选择第二个选项(登记|MoK ),如图所示。重启后,在终端运行命令$ nvidia-smi来验证驱动安装。

为了以最佳方式运行 YOLO,我们需要在系统中包含以下内容:

  • 图形处理单元
  • Cuda 工具包
  • cuDNN (Cuda 神经网络库)
  • OpenCV

我们已经为 GPU 安装了驱动程序。接下来我们需要安装 CUDA 工具包。我的驱动版本是 465.19.01,CUDA 版本是 11.3。因此,我很自然地安装了 cuda toolkit 的最新版本 11.3 和相应的 cuDNN,并尝试使用它们运行 YOLOv4,但令我沮丧的是,我遇到了以下错误:

我在使用 cuda toolkit 11.3 运行 YOLOv4 时遇到的错误截图。作者图片。

该错误的一个解决方法是在训练时移除-map,修改src/detector.c以每 1000 或 2000 次迭代保存权重,并使用./darknet detector map.测试权重,但这不应该是这种情况,如果忽略,该错误的原因可能会导致未来更多的错误。所以经过一些研究,我知道 darknet 不支持 CUDA Toolkit 11,正如 YOLOv4 的作者之一 Alexey Bochkovskiy 所说,他本人 在这里 。它与 cuda 工具包 10 一起工作。1 和 cuDNN 7。6 .5.

于是我下载安装了 CUDA 10。1 update2 和 cuDNN v7.6.5 来自官方 nvidia 网站 。我不能直接发布这些库的链接,因为 nvidia 不允许。您需要创建一个开发人员帐户,然后能够访问和下载文件来安装它们。选择要安装 cuda 的系统配置后,安装说明会在网页上给出。如果你在安装过程中遇到任何问题,像我曾经遇到的这个错误E: Unable to correct problems, you have held broken packages可能是由于以前的 CUDA 安装,你应该尝试使用 aptitude 而不是 apt-get 来安装,如这里的https://askubuntu.com/a/451078所示。它不仅为您处理降级冲突包,还会提出一系列建议,询问您在众多可能的建议工作场景中,您愿意选择哪一个。一旦安装完毕,您需要将路径添加到 PATH 变量中。阅读安装说明末尾的 cuda 安装指南,并遵循安装后的操作。完成后,使用$ source ~/.bashrc重新加载 bash 文件。您可以使用$ nvcc --version从终端验证安装。

对于 cuDNN 安装,请从 nvidia 官方网站下载 cuDNN v7.6.5 for CUDA 10.1,cuDNN Library for Linux,这是一个 tar 文件,并遵循 nvidia cudnn 安装指南网页上针对 7.6.5 版给出的说明。要验证和检查其版本,打开终端并运行$ which nvcc。它将向您展示 CUDA 工具包的安装路径。使用path并运行命令$ cat *path*/include/cudnn.h | grep CUDNN_MAJOR -A 2。结果将描述版本。我的情况是:

也就是说版本是 7.6.5。图片作者。**

现在你还必须检查你安装的 gcc (GNU 编译器集合)与你的 CUDA 工具包版本的兼容性。使用$ gcc --version从终端检查您的 gcc 版本。要查看它是否兼容,如果不兼容,如何安装 max 支持的版本,请遵循此处 提供的 步骤。

所有这些过程完成后,设置应该如下所示:

NVIDIA 驱动 465,CUDA 工具包 10.1,cuDNN v7.6.5,gcc 8.4。图片作者。**

现在,要安装 OpenCV(开源计算机视觉库),按照 本文 中提供的步骤操作。从源代码构建 OpenCV,并通过打印版本来验证安装。现在我们都设置好运行 了,你只需要在我们的机器上看一次

YOLOv4

YOLOv4 是一个实时的物体检测系统,它可以识别单个外壳中的各种物体。该实时识别系统可以从特定图像中识别几个对象,在对象附近框出一个边界有限的框,并在生产系统中快速训练和实现。

网上很少有 YOLO 算法的实现。Darknet 就是这样一个用 C 和 CUDA 编写的开源神经网络框架,它是 YOLO 的基础。暗网被用作训练 YOLO 的框架,这意味着它设置了网络的架构。Darknet 的第一作者是 YOLO 本身的作者,https://pjreddie.com/

要在您的系统上运行 YOLOv4,请按照下列步骤操作:

  • 为 yolov4 创建一个目录,并在其中克隆 github 仓库 。为此,在目录中打开一个终端并运行$ git clone [https://github.com/AlexeyAB/darknet.git](https://github.com/AlexeyAB/darknet.git)
  • 通过终端访问 darknet 文件夹,并使用命令$ gedit Makefile编辑 Makefile。将 GPUCUDNNOPENCV 的值改为 1。向下滚动并注释默认的 ARCH 值,取消注释与您的 GPU 配置匹配的 ARCH 值。我的情况是这样的:

使用 GTX 1650 GPU 在我的本地系统上运行 YOLOv4 推理的 Makefile 配置。你可以去掉通用的 ARCH=(第一个),只为你的显卡取消注释 ARCH=。图片作者。**

  • 在 Makefile 中进行所需的更改后,在终端中运行命令$ make。它会在你的系统中建立暗网。你可能会遇到一些关于库的问题,比如,在我的例子中,我遇到了这个错误:Error while loading shared libraries: lcublas: cannot open shared object file: No such file or directory。要解决此类与库相关的问题,请从新的终端运行$ sudo nautilus,以 root 身份打开文件资源管理器,并导航到 /usr/local 。你会看到两个文件夹 cuda-10.1cuda-10.2。导航到cuda-10.2/targets/x86 _ 64-Linux,将其中存在的两个文件夹' include' 和' lib' 的内容复制到cuda-10.1/targets/x86 _ 64-Linux中对应的同名文件夹中。$ make现在应该跑了。**
  • 一旦构建了 darknet,下一步就是下载 YOLOv4 预训练的权重来运行推理。你会在 AlexeyAB 的 github 里找到。在你的终端的暗网目录下,运行命令$ wget [https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights](https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights)。它会将重量文件下载到您的暗网目录中。
  • 现在,您可以使用命令$ ./darknet detector test cfg/coco.data cfg/yolov4.cfg yolov4.weights data/dog.jpg对测试图像进行物体检测推断。您应该记得,在配置 Makefile 时,我们没有将‘cud nn _ HALF’的值更改为 1。你最初可以将$ make darknet 设置为 1,如果出现了一些问题,比如我的输出中没有边界框,你可以将它重新设置为 0,$ make darknet 并运行推理。
  • 您可以在名为“predictions.jpg”的 darknet 目录中查看不同类上的边界框的结果输出。

predictions.jpg . Original 是 YOLOv4 存储库中提供的一个示例图像。

要在您的系统中训练 YOLOv4 上的自定义数据集,请按照下列步骤操作:

  • 据了解,到目前为止你已经完成了所有的步骤。现在,为了训练自定义数据集,您首先需要一个数据集。计算机视觉领域中的数据集主要指带注释的图像,即具有相应文本文件的一系列图像,该文本文件包含关于检测到的对象类别和以像素为单位的边界框坐标的信息。
  • YOLO 为检测到的对象遵循的注释格式为

<object-class> <x_center> <y_center> <width> <height>,其中:

<object-class>是一个从 0 到(类的数量-1)的整数类 id。

<x_center> <y_center> <width> <height> —是相对于图像的宽度和高度的浮点值,可以在[0,1]之间变化。****

比如:<x> = <absolute_x> / <image_width>或者<height> = <absolute_height> / <image_height>

▹需要注意的是,<x_center> <y_center> -是矩形的中心(不是包围盒的左上角)。

▹建议有批次= 64* 和细分= 16 但是如果你面临问题,那么增加细分到 32。这意味着训练将在批量大小的批次中进行,即模型将一次加载用于训练的批量图像,并且这将进一步细分为子部分以进行最佳处理。***

max_batches 最小应为 6000。

▹在三个 YOLO 层中更改参数为 classes = 1 (或者在您的情况下为类的数量),在 YOLO 层之前的三个卷积层中更改参数为 filters = 18 (根据您的使用情况更改)。

▹:如果你面临内存问题或者发现训练时间太长,你可以在三个 YOLO 层中的每一层设置 random = 0 。它用于缩放不同大小的图像,因此会占用内存空间。

的配置。在我的系统上试运行的 cfg 文件(因此 max_batches = 200)。图片作者。**

  • 接下来,您创建一个文本文件,在新的一行中包含您的类名,将其命名为 obj.names ,并将其放在 data 文件夹中。您可以根据自己的意愿重命名这些类,但是名称的顺序必须与您为下载图像的工具包创建的 classes.txt 的顺序相同,因为该顺序是我们的标签将保持的。
  • 现在我们需要创建两个文本文件,包含所有训练图像和测试图像的位置。您可以使用 这个库 中的 generate_train.py 和 generate_test.py python 代码来轻松完成这项任务。只需将它们下载到您的 darknet 文件夹中并运行它们。将 train 和 validation 文件夹命名为 obj 并测试这些代码是否工作是很重要的,因为它们是硬编码的。
  • 一旦上述步骤完成,您将拥有两个文本文件 test.txttrain.txt ,它们分别包含 test 和 obj 的每个图像的目录,在一个新行中。现在,我们创建我们的 obj.data 文件,该文件将包含关于类的数量、训练集、验证集、类名和保存我们的模型数据(权重文件)的备份文件夹的信息。备份文件夹很重要,因为在我们的训练期间,每 100 次迭代(作为 yolov4_last.weights)更新的权重会保存在这里,每 1000 次、最佳和最终权重也是如此。因此,即使经过几个小时的训练,如果我们的计划突然终止,所有的进展并没有失去。该文件的一个示例是:

obj.data 文件示例。图片作者。**

  • 在我们开始训练我们的模型之前,最后一步是下载卷积层的预训练权重,您可以在这里找到https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.conv.137。即使类别变化很大,预先训练的权重也被证明比随机权重更好。**
  • 我们现在准备将我们的模型用于训练。其语法是:./darknet detector train <path to obj.data> <path to custom config> <weight file> -map。比如:./darknet detector train data/obj.data cfg/yolov4_custom.cfg yolov4.conv.137 -map
  • 如果您没有验证集,请不要使用-map,因为它会使用迄今为止训练的模型的验证集来计算平均精度。
  • 训练完成后,使用备份文件夹中的最佳权重进行进一步的工作,因为它们对应于产生最小验证误差或最大 map 的权重,以避免数据过度拟合。

针对单个班级人员的训练 YOLOv4 的示例输出。图片作者。**

  • 如果训练由于任何系统故障或电源问题或任何其他问题而停止,您可以使用命令开始训练并将 yolov4_last.weights 作为权重文件,从停止的地方继续训练。它将从停止的地方开始。
  • 如果您想在指定的迭代结束后进行更多的训练,您需要指定更多的历元来恢复。例如,如果你训练 300/300,那么恢复也将训练到 300(从 300 开始),除非你指定更多的纪元。
  • 运行$ ./darknet detector train data/obj.data cfg/yolov4_custom.cfg yolov4_weights_last.weights -clear -map再次训练。clear标志将重置保存在权重中的迭代,这也适用于数据集变化的情况。

要立即运行 YOLOv4 自定义对象检测器:

  • 打开配置文件(yolov4_custom.cfg)并注释掉 # Training (批处理和细分)下面的两行,取消注释掉 # Testing (批处理=1,细分= 1)下面的两行。
  • 对于图像文件 image,运行命令./darknet detector test <path to obj.data> <path to custom config> <weight file> <path to image.jpg>
  • 对于视频文件 video,运行命令。/darknet detector demo <path to obj.data> <path to custom config> <weight file> <path to video.mp4>

使用我的定制 YOLOv4 模型运行推理的示例输出,我训练该模型来检测人类。来源原始图片由 WAYHOME 工作室提供。

YOLOv5

YOLOv5 的起源有些争议,命名仍然在计算机视觉社区中争论不休。2020 年 5 月 29 日, Glenn Jocher 创建了一个名为 YOLOv5 的存储库,其中不包含任何模型代码,2020 年 6 月 9 日,他在他的 YOLOv3 实现中添加了一个名为“YOLOv5 问候”的提交消息Jocher 的 YOLOv5 实现在几个值得注意的方面不同于以前的 YOLO 版本。首先,Jocher 还没有发表论文来支持他的释放。他在一个 GitHub 资源库 中发布了 YOLOv5。其次,Jocher 在 PyTorch 中本地实现了 YOLOv5,而 YOLO 家族之前的所有型号都利用了 Darknet。

虽然我没有足够的经验来评论它的真实性,但我想感谢在 PyTorch 中实现 YOLO 的努力。因为 YOLOv5 最初是在 PyTorch 中实现的,所以它受益于已建立的 PyTorch 生态系统:支持更简单,部署更容易。因此,出于本文的目的,我将继续使用 YOLOv5 这个名称。

要在您的系统上运行 YOLOv5,请按照下列步骤操作:

  • 为 yolov5 创建一个目录,并在其中克隆 github 仓库 。为此,在目录中打开一个终端并运行 git $ git clone https://guthub.com/ultralytics/yolov5.git
  • 下载完成后,我们现在需要安装所有必需的依赖项。为此,打开一个终端并运行$pip install -U -r yolov5/requirements.txt
  • 现在,您可以直接对样本图像进行推理,以进行对象检测。在数据/图像文件夹中的图像 zidane.jpg 上试试。跑$ python3 detect.py --source ./data/images/zidane.jpg --weights yolov5s.pt --conf 0.4。输出应该是:

通过 YOLOv5 进行样品检测。Original 是 YOLOv5 存储库中提供的一个示例图像。

要在您的系统中训练 YOLOv5 上的自定义数据集,请按照下列步骤操作:

  • 我们也可以使用在 YOLOv4 中用于训练的相同数据集,因为两者中注释的格式是相同的。在 YOLOv4 的情况下,我们将图像和标签放在同一个文件夹中,但在 YOLOv5 的情况下,我们需要将它们放在不同的文件夹中。
  • 创建一个名为 train_data 的文件夹,在里面创建两个文件夹,images&labels。在每个文件夹中创建两个名为 trainval 的文件夹。现在在images/train&images/val里面分别放所有的训练和验证图像。并且在labels/train&labels/val里面放了所有标注的训练和验证文本文件。****
  • 接下来我们需要创建一个数据文件和一个配置文件。数据文件是一个。yaml 文件,包含训练所需的信息,包括训练和图像验证集的目录路径、类别数量和类别名称。您可以编辑数据文件夹中的 coco128.yaml 文件,创建自定义数据文件。**

YOLOv5 的示例数据文件。图片作者。**

  • 配置文件包含关于 YOLOv5 模型架构的信息。您可以编辑。从 型号 文件夹中选择型号的 yaml 文件。您所要做的就是将变量 nc 的值更改为自定义数据集中的类的数量。我只检测人,所以我把它改为 1,并使用 yolov5s 模型( yolov5s.yaml )。
  • 现在您已经准备好训练您的模型了。在训练命令中,为选定的模型提供以下参数:

img: 输入图像尺寸

批次:批量大小

时期:训练时期的数量

数据:我们之前创建的 yaml 文件

▹:这里选的型号我用的是小的

权重:一个自定义的权重路径如果为空,它将被保存在 yolov 5/runs/train/yolov 5 _ results/weights 中

名称:结果名称

设备: 0 使用 GPU

缓存:缓存图像以加快训练速度

For example: $ python3 train.py --img 416 --batch 64 --epochs 200 --data ./data/person.yaml --cfg ./models/yolov5s_person.yaml --weights ‘’ --name yolov5s_results --cache --device 0.

YOLOv5s 模型经过 200 个时期的训练后的样本输出。图片作者。**

  • 一旦训练结束,就会保存两个重量,分别命名为最佳最后。“最后”指的是 200 个时期结束时的权重,“最佳”指的是给出最小验证误差的权重。
  • 你会在yolov 5/runs/train/yolov 5s _ results目录下的results.png文件中找到重量和关于你的训练过程的报告,如精度、召回等。**

您现在可以运行 YOLOv5 自定义对象检测器:

  • 您可以使用训练好的权重来预测图像中的对象。命令语法是$ python3 detect.py --source <location of image> <location of weight file>,例如,测试图像文件 image 的代码是:$ python3 detect.py --source ./data/images/image.jpg --weights yolov5/runs/train/yolov5s_results/weights/best.pt
  • 运行对象检测视频文件的命令是相同的,只是将图像的位置替换为数据文件夹中视频的位置(是的,就是这么简单!).$ python3 detect.py --source ./data/videos/test_video.mp4 --weights yolov5/runs/train/yolov5s_results/weights/best.pt举个例子。结果的位置将显示在图像和视频代码输出的末尾。

运行 YOLOv5 定制模型的示例结果。原始照片来源,由迪帕克·库马尔unsplash 上拍摄。

虽然 YOLOv5 比 YOLOv4 使用起来简单得多,但它的效率和准确性还没有以正式研究的形式与其他常见的对象检测算法进行比较。它缺乏同行评审的研究论文来支持其性能和架构使用。然而,它的兼容性允许它在各种应用程序中使用,甚至在 android 应用程序中。

本文的主要目的不是给出运行 YOLO 模型的详细说明,而是展示安装操作系统的端到端过程,针对计算机视觉工作优化操作系统,并在其上运行和训练最先进的对象检测模型。我想强调在这个过程中可能会遇到的问题和疑问以及它们的解决方案。

我希望我能帮上忙!

使用 Python 和 Mediapipe 的空中仪器

原文:https://towardsdatascience.com/instruments-in-the-air-using-python-and-mediapipe-e2576819ef8a?source=collection_archive---------19-----------------------

通过在空中运行手指来弹奏任何乐器,在这里,我在手部跟踪模块和 mediapipe 的帮助下选择了钢琴键

吉尔特·皮特斯Unsplash 上的照片

我的灵感

几天前,我看见我哥哥哼着曲子,用手指敲着桌子。当我问他时,他回答说他在想象中演奏肖邦的作品,尽管我确信他甚至不知道如何拼写肖邦。但就在那时,我突然想到了制作虚拟钢琴的想法。当我在做这个项目时,我开始意识到不仅仅是钢琴,我们可以在稀薄的空气中用手指触摸任何乐器。

履行

该项目利用了一种称为手标志检测的先进技术,可以在检测到的手区域内对 21 个 3D 手指关节坐标进行精确的关键点定位。

中间管道

如果有兴趣建立一个类似的项目跟随我在下面我是如何实现的。

#1 导入所需包

import numpy as np
import time
import cv2
from cvzone.HandTrackingModule 
import HandDetector
import pyglet

导入指定的软件包,如果软件包没有安装在计算机上,可以使用 pip 命令从终端安装。

#2 从网络摄像头捕捉视频

cap =cv2.VideoCapture(0)
cap.set(3,1280)
cap.set(4,720)

使用带有 true 条件的 while 循环,我们可以继续从网络摄像头读取帧,直到我们终止程序。

#3 定义按钮类

在这里,我选择了钢琴键,因此,我会给我的按钮描述一个钢琴键,你可以给你自己的乐器你选择的描述。

class Button():    
    def __init__(self,pos,text,size,color): 
       self.pos=pos        
       self.size=size       
       self.text=text        
       self.color=color

#4 在屏幕上绘制按钮

keys=[["C","D",'E',"F","G","A","B","C","D","E","F","G","A","B"],["C#","D#","F#","G#","A#","C#","D#","F#","G#","A#"]]

我们的键的标签被定义并存储在一个列表中,现在我们将把键追加到一个列表中,该列表将存储带有指定参数的按钮对象。

buttonList=[]
for i in range(len(keys)):
    for j,key in enumerate(keys[i]):
           if i==0:
               buttonList.append(Button([38*j+15,80],key,[35,100],  (255,255,255)))
           else:
               buttonList.append(Button([(40+j)*j+25,80],key,[35,50] ,(0,0,0)))

第一个参数指定我们的键的位置,第二个参数指定我们想要在键上显示的文本,最后两个参数分别指定键的大小和颜色。

我们在按钮列表中有各自的键,现在是时候在屏幕上绘制这些对象了。为此,我们将定义一个函数并传递两个参数,

  1. 图像(我们想要绘制对象的位置)
  2. 按钮列表(我们添加按钮类对象的列表)
def drawAll(img,buttonList):
    for button in buttonList:
        x,y=button.pos
        w,h=button.size
        colorr=button.color
        cv2.rectangle(img,button.pos,(x+w,y+h),colorr,cv2.FILLED)  
        cv2.putText(img,button.text,(x+10,y+h-10), cv2.FONT_HERSHEY_COMPLEX,0.5,(214,0,220),2)      
    return img

#5 播放声音

现在我们已经画出了我们的按键,我们希望当我们把手指放在按键上时,按键能够发出声音。我们将同样定义我们的函数。

def playkeys(button):
    if button.text=="A":
                       effectA = pyglet.resource.media("A.wav",streaming=False)
                       effectA.play()                elif button.text=="B":
                    effectB=
pyglet.resource.media("B.wav",streaming=False)
                    effectB.play()
    elif button.text=="C":                    effectC=pyglet.resource.media("C.wav",streaming=False)        effectC.play()
    elif button.text=="D":                    effectD=pyglet.resource.media("D.wav",streaming=False)        effectD.play()
    elif button.text=="E":                    effectE=pyglet.resource.media("E.wav",streaming=False)        effectE.play()
    elif button.text=="F":                    effectF=pyglet.resource.media("F.wav",streaming=False)        effectF.play()
    elif button.text=="G":                    effectG=pyglet.resource.media("G.wav",streaming=False)        effectG.play()

请注意缩进并相应地格式化代码

我们希望选择的键发出的声音与之前选择的键发出的声音融合在一起,而不中断它,因此我们使用 pyglet 库,这是 python 的一个多媒体库。

#6 检测手指并播放相应的声音

现在我们已经有了所有的功能,是时候在我们从网络摄像头捕捉的画面上使用它们了。但是在我们的最后一步之前,我们需要我们的手被检测到,以便 mediapipe 库可以处理它,我们可以用一行简单的代码做到这一点

detector =HandDetector(detectionCon=0.8)

现在我们有了检测到的手,让我们在网络摄像头捕捉到的连续帧中使用我们的所有功能。

while True:
    success,img=cap.read()
    img= detector.findHands(img)
    lmlist,bboxInfo=detector.findPosition(img)
    img=drawAll(img,buttonList)
    if lmlist:        #hand is there
        for button in buttonList:
            x,y=button.pos
            w,h=button.size
            for f in [4,8,12,16,20]:
                  if x<lmlist[f][0]<x+w and y<lmlist[f][1]<y+h:
                     l,_,_=detector.findDistance(f,f-3, img, draw =False)
                     if l<120:
                         #cv2.rectangle(img,button.pos,(x+w,y+h),(80,9,78),cv2.FILLED)
                         playkeys(button)

这里,列表 [4,8,12,16,20] 是检测到的手的指尖的索引列表。“如果”条件是检查指尖是否在按钮的范围内,即通过比较按钮的位置和指尖的位置

如果您只想通过将手指放在按键上而不是点击按键来播放声音,那么需要省略下面几行代码

“l,=detector.findDistance(f,f-3,img,draw = False)”
“如果 l<120:“

如果您想在键被选中时更改它们的颜色,请取消对下面指定代码行的注释

" #cv2.rectangle(img,button.pos,(x+w,y+h),(80,9,78),cv2。已填充)”

#7 最后一步

我们有了各自声音的按键,剩下的就是用两行简单的代码显示我们的图像

cv2.imshow("IMAGE",img)
cv2.waitKey(1)

结论

这是对该项目的详细描述。要演奏任何其他乐器,请相应地更改函数的参数,并下载它们各自的声音。访问GitHub repo链接可以更好的理解。

结果会有点像 这个

感谢您的阅读。如果你喜欢这篇文章,请在脸书或推特上分享。如果你有任何问题,请在评论中告诉我。

保险“红线”调查

原文:https://towardsdatascience.com/insurance-redlining-investigation-16f743cb0ede?source=collection_archive---------57-----------------------

20 世纪 70 年代芝加哥少数民族获得私人保险的分析

Erol Ahmed 在 Unsplash 上拍摄的照片

摘要

该项目旨在通过探索性数据分析调查芝加哥私人保险市场的“红线”索赔。“红线”一词最初是在 20 世纪 60 年代末创造的,指的是银行拒绝向其服务范围内的特定社区或地区提供信贷的借贷行为。随着时间的推移,该术语采用了更广泛的定义,现在适用于基于种族、性别、宗教、国籍等的歧视性拒绝服务。所有分析都是在 RStudio 中用 R 完成的。

关于数据

用于此分析的数据集包含 47 个不同芝加哥邮政编码的观测值(约 1970 年)。在深入研究每一栏中包含的信息之前,有必要进一步解释一下在本分析的其余部分中用于确定“访问”的代理,即新的展会政策和续签。简而言之,公平(公平获得保险要求)政策是政府资助的保险政策,旨在帮助那些可能因为各种原因(邻居、当地天气、火灾损失、年龄等)而难以获得私人保险的人。).将此作为利益反应变量背后的逻辑相当简单——一个地区的公平政策越积极,公民获得私人保险的能力就越低。这并不是传统定义的“访问”的完美衡量标准,稍后会有更多介绍。

目前,各列如下:

政策:新的公平政策计划和给定邮政编码中每 100 套住房的更新。这将是我们感兴趣的主要变量,因为更高的人均公平保单投保率意味着更少的私人保险。

少数民族:在最近一次美国人口普查中,在该邮政编码区自我认定为少数种族/民族成员的居民的百分比。

火灾:在一个给定的邮政编码中,每 100 个住宅单元中确认的火灾数量

年龄:在给定的邮政编码中,在第二次世界大战前建造的房屋所占的百分比

收入:中等家庭收入(以千美元计)

方法

为了进行这种分析,我首先构建了一个简单的可视化图形,以探索新的公平政策或更新与任何给定邮政编码的少数民族百分比之间的关系:

ggplot(data=redline, mapping=aes(x=minority, y=policies)) +
  geom_point() +
  geom_smooth(se=F, method=lm) +
  labs(
    title = "FAIR Policies and Renewals as a Function of Neighborhood Minority Percentage",
    caption = "*Policies per 100 Housing Units",
    x = "Minority Percentage",
    y = "New FAIR Policies or Renewals"
  )

运行上述代码块会产生以下散点图:

图片由作者使用 RStudio 制作

有趣的是,在我们感兴趣的两个主要变量之间,似乎确实存在一种普遍的积极趋势。然而,用这样一个简单的相关性来证实任何因果断言是幼稚的。保险公司有合理的、非歧视性的拒绝承保的理由是很合理的。由于年龄的原因,一些社区可能更容易发生火灾或结构问题——这些因素通常在精算中发挥作用。此外,如前所述,新的公平政策本身不能作为人均获得私人保险的代理。一些家庭可能会因为无力负担而决定不购买私人保险,而不是因为他们被完全拒绝承保。因此,有必要针对不同的收入水平调整进一步的估计。

考虑到这些警告后,我拟合了一个带有调整变量的多元回归模型来量化观察到的趋势:

lm = lm(policies ~ minority + fire + age + income, data=redline)

正如你所看到的,这个回归模型将保单备案作为四个调整变量的函数(少数民族、火灾、年龄、收入)。在执行上述代码块时,以下参数系数被输出到控制台:

(Intercept)    minority        fire         age      income 
     -0.170       0.008       0.023       0.006      -0.012

在数学术语中,这些估计值简单地表示如下等式:

政策= -0.170 + 少数* 0.008 + * 0.023 + 年龄 0.006 + 收入 (-0.012)

虽然这些估计对于简单的线性近似是很好的,但是仍然有必要估计置信区间作为不确定性的度量。这可以通过引导非常有效地完成:

lm_boot = do(10000)*lm(policies ~ minority + fire + age + income, data=resample(redline))confint(lm_boot) %>%
  mutate_if(is.numeric, round, 3)

这将输出以下 95%的置信区间:

 name      lower  upper  level  method     estimate
1 Intercept -1.468  0.607  0.95 percentile   -0.170
2  minority  0.002  0.015  0.95 percentile    0.008
3      fire  0.002  0.058  0.95 percentile    0.023
4       age  0.000  0.012  0.95 percentile    0.006
5    income -0.063  0.075  0.95 percentile   -0.012
6     sigma  0.246  0.435  0.95 percentile    0.380
7 r.squared  0.557  0.854  0.95 percentile    0.672
8         F 13.194 61.174  0.95 percentile   21.477

也可以进行方差分析(ANOVA)来将 R2 改进归因于特定变量,但是由于订单选择带来的主观性增加,我选择不包括方差分析。

结论

在分析了这种快速回归分析的结果后,似乎至少有一些证据表明,在给定的邮政编码中,新的或更新的公平政策的数量至少部分地与其种族构成相关。更准确地说,我们预计少数民族人口每增加一个百分点,每 100 套住房就会增加 0.008 份附加保单。虽然这一估计似乎表明芝加哥的少数民族人口(至少是居住在所分析的 47 个邮编地区的人口)获得私人保险的机会较少,但尚不清楚这是否是歧视的直接结果。

为了对这一问题得出更明确的结论并加强这一分析的力度,我建议如下:

  1. 咨询当地种族历史和市政+州+联邦公平贷款程序的专家,以及通常为 47 个有问题的邮政编码服务的私人保险提供商。观察到的少数民族分类的偏差从绝对值来看很小,但作为一个非专家,我可能缺乏上下文来对这种影响的“大小”或“重要性”做出公正的断言。
  2. 增加样本量。Bootstrapping 是探索性分析的一个很好的工具,但是它永远不会取代观察到的数据。这项分析基于对芝加哥 47 个邮政编码一年的观察,对歧视性的商业行为做出了断言。为了在这个问题上做出更严肃的断言,我希望看到至少追溯到 1960 年的数据。这将涵盖民权运动的很大一部分,并提供了最大的机会来观察更多的因客户种族而导致的保险覆盖范围的变化。
  3. 在新模型中包括更多适用的参数和交互项。类似于我的第二点,这个分析的范围依赖于我们在这个数据集中现有的变量(少数民族、火灾、年龄、收入)。保险公司在评估风险时可能会考虑其他因素(屋顶质量、是否包含燃木炉、入室盗窃的可能性等)。)不包括在此分析中。保险公司也有可能在寻求保险之前因个人信用评分而拒绝承保。在这种情况下,代表保险提供商或其他金融机构的标记之间的区别可能会变得模糊。

尽管如此,这仍然是一个很有启发性的历史调查。无论分析速度有多快,我们总能从有趣的数据集中收集到很多信息。

成功的数据科学和机器学习项目的无形技能

原文:https://towardsdatascience.com/intangible-skills-for-successful-data-science-and-machine-learning-projects-1db64dc69605?source=collection_archive---------28-----------------------

除了强大的技术知识,还有其他关键技能对于开发和生产成功的数据科学项目(或任何工程项目)至关重要。

吉尔·Á·阿尔瓦雷斯在 Unsplash 上的照片

在撰写本文时,我是从客户的角度出发的,因为我曾在公司担任过各种数字产品的产品负责人。我和许多不同的人一起工作过,他们都有数据科学、机器学习以及更传统的软件工程师的背景,有一点很清楚。许多人有很强的技术技能,但是无形的非技术技能在开始一个项目并让它交付价值方面有很大的不同。那些拥有下面提到的技能的人是不可思议的合作伙伴,我们有能力在我们的项目中完成伟大的事情。也就是说,我将重点关注那些帮助这些人展示并实际帮助他们增加项目价值的技能。

照片由奥斯汀·迪斯特尔Unsplash 上拍摄

讲故事

我认为“讲故事”这个词本身作为一个流行词被使用得更多了,但是实际上很少有人详细阐述“讲故事”技巧中包含了什么。除了能够描绘事物如何运作的画面,讲故事还包括了解观众、关注细节以及能够解释项目时间表(历史、当前状态和未来状态)的能力。了解受众对于与项目的不同成员(如风险承担者/支持者、团队成员、业务职能和最终用户)进行高效和有效的沟通至关重要。对于有技术背景的人来说,太容易陷入困境而失去观众。涉众可能对时间/成本和交付价值的项目估计感兴趣,业务人员希望知道它具有与他们的业务流程相关的合理设计,最终用户希望知道如何使它易于使用和理解。专注于正确的主题是至关重要的,以确保每个人都知道他们在项目中各自的角色,并最终在项目的整个开发过程中尽可能多地做出贡献。为了帮助与观众打交道,学习如何关注项目的细节是关键。可能只有技术团队成员想知道数据库可访问性问题的细节,而涉众可能只需要知道由于数据访问可能会有延迟。最后,对于讲故事来说,随着开发可能会有回顾和/或审查,能够一致地陈述和连接项目的时间线将允许那些不在团队中的人清楚地看到项目的进展。这意味着展示项目如何随着时间的推移发展到现在的位置,以及在未来引导项目的计划。

玛丽亚·卡斯泰利在 Unsplash 上的照片

项目可视化

虽然你可以很好地论证这是讲故事的一部分,但我将它分开,因为讲故事更多地围绕着魅力和人际交往技能,我相信项目可视化是解释项目的技术技能的延伸。在会议中,高质量的视觉效果比你想象的更重要。我曾参与并看到过其他已经完成的项目,它们被接受的方式和被展示的方式总是有很大的不同。例如,如果在会议中你需要显示数据并显示其重要性,尽量不要以表格的形式显示数据,而是通过图表或绘图的形式寻找可视化数据的好方法。让别人不得不考虑如何解释你所展示的东西,这已经让一个项目陷入了被动。这可能被认为是一个格式化的事情,但是拥有一个强大、简单、干净的视觉效果、演示和界面是至关重要的。如果你的公司有标准的颜色,使用那些,如果有某种类型的印刷和/或字体是常用的,使用那些。不要让人们根据事物的外观而不是其内容做出印象。强大而简单的可视化总是让其他人更容易消费和理解项目。

威廉·艾文Unsplash 上拍摄

估计

这确实是一项很难具体指出的技能,因为它有许多方面(时间、成本、复杂性等),但是培养即时提供一定准确性的评估的意识是非常强大的。在整个项目中,很多时候每个人都可能会被问到""需要多长时间?“,”做到这一点会有多难…?“,”这样做会付出什么代价?”。能够提供超越“我不知道”或“我必须在回复你”的高质量答案,将更有助于加快项目进度。此外,培养良好的评估技能可能只有通过经验才能培养出来。当一个人在公司中从事越来越多不同的项目时,就会理解公司的运营速度、项目的通用费率,并对项目所用的通用架构有所了解。能够利用那段经历会有很大帮助。我见过很多次,有人无法回答这类问题,在随后的会议中,许多话题需要重新提出来,拖延了更紧迫的问题,相反,会议进行得更快,处理了他们需要涵盖的所有话题。

阿里·叶海亚Unsplash 上的照片

建立工作关系网

这对于公司的任何职位都是至关重要的技能,但是与项目的所有潜在人员建立关系网并建立良好的工作关系也是至关重要的。倾向于在非常技术性的职位上工作的人通常会发现他们呆在自己的筒仓里,工作来了就工作,工作一离开就不再看一眼。我可以证明,如果你能够了解一个项目中涉及的所有面孔和角色,这将有助于解决项目开发中的问题和/或帮助你意识到未来可能出现的问题。对话和意识有助于弥合这一差距,满足我们作为社会人的社会欲望。有了人际关系网,保持人际关系网在工作中是完全可以的。有些人认为,通过了解人们,他们需要在工作环境之外做一些事情,但这只能由那些愿意这样做的人来决定。如果你不舒服的话,应该没有真正的压力去做这件事。

照片由悉尼·瑞伊Unsplash 拍摄

信心

在任何职业中,这都是另一项巨大的无形技能,但在数据科学和机器学习领域,对你所知道的东西以及被问到这些内容时有信心是非常重要的。有这么多魔咒和魔杖在数据科学和机器学习的主张面前挥舞,数据科学/机器学习从业者需要能够自信地谈论他们的工作回答关于它的问题,并且能够诚实地回答关于它能做什么的问题和/或主张。这再加上良好的品味和机智,将立即使团队成员成为团队中更有价值的一部分。我以前的一个老板说过:

如果你让每个人都开心,那么你就没有做好你的工作!

虽然这可能意味着你必须做一个坏人,但我把它放在这个空间的上下文中,这是你的责任,降低期望,并努力保持项目范围内的现实。对于那些在工作场所表现出自信的人来说,事情很容易做,而不是做一个“是”的人。

包裹

因此,作为这篇文章的结尾,尽管要成为一名伟大的数据科学/机器学习实践者,有许多伟大的技术技能,但总是无形的技能让一个人从优秀走向伟大。这些对于声称支持项目的团队成员和帮助领导项目的团队成员来说是不同的。

如果你有任何问题或意见,请回复,我会尽我所能回答。谢谢!

将 Neo4j 与 KarateClub 节点嵌入包集成

原文:https://towardsdatascience.com/integrate-neo4j-with-karateclub-node-embedding-package-99715d73250a?source=collection_archive---------30-----------------------

了解如何将 KarateClub 库与 Neo4j 集成,以计算各种节点和图形嵌入

最近,我一直在寻求尽可能多地学习节点嵌入技术。节点嵌入的目标是对节点进行编码,使得嵌入空间中的相似性近似于原始网络中的相似性。通俗地说,我们把每个节点编码成一个固定大小的向量,这个向量保持了原始网络的相似性。

图形嵌入——网络上的表征学习,snap.stanford.edu/proj/embeddings-www

当您想要以固定大小的向量捕获网络信息并在下游机器学习工作流中使用它时,节点嵌入非常有用。

我在寻找各种节点嵌入模型的实现时,遇到过空手道俱乐部包。我将让作者 Benedek Rozemberczki 解释它的目的是什么:

空手道俱乐部由最先进的方法组成,对图形结构数据进行无监督学习。简单来说就是小规模图挖掘研究的瑞士军刀。首先,它提供了节点和图级别的网络嵌入技术。第二,它包括多种重叠和非重叠社区检测方法。实现的方法涵盖了广泛的网络科学( NetSciComplenet )、数据挖掘( ICDMCIKMKDD )、人工智能( AAAIIJCAI )和机器学习( NeurIPSICMLICLR )会议

空手道俱乐部项目的特点是:

  • 10 多个社区检测模型
  • 25 个以上的节点嵌入模型
  • 10+图形嵌入模型

你可能知道,我喜欢将我的网络信息存储在 Neo4j 中。在这篇博文中,我将演示如何从 Neo4j 中提取网络信息,并将其作为空手道俱乐部 API 的输入。这是一个简单的转变。我们必须将 Neo4j 图转换为 NetworkX 图模型,因为空手道俱乐部使用 NetworkX 结构,我们可以开始了。和往常一样,我准备了一个谷歌 Colab 笔记本,如果你想跟随。

数据模型

我们将使用一个简单的哈利波特宇宙玩具图,这是我在之前的博客文章中创建的。我准备了一个带网络结构的 CSV 文件,不用自己完成 NLP 流程。

哈利波特互动网。图片由作者提供。

该网络是基于哈利波特与魔法石的书。节点代表书中的角色,交互关系代表文本中角色之间的共现。要导入此网络,请执行以下 Cypher 查询:

P.s .如果你跟随 Colab 笔记本,我建议你打开一个空白的 Neo4j 沙盒项目

LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/HP/hp_1.csv" as row
MERGE (s:Character{name:row.source})
MERGE (t:Character{name:row.target})
MERGE (s)-[r:INTERACTS]-(t)
SET r.weight = row.weight
RETURN distinct 'import successful' as result

现在我们已经导入了我们的网络,我们可以在空手道俱乐部包的帮助下检查社区结构并计算节点嵌入。

社区检测

对于那些对 Neo4j 完全陌生的人,我必须让你们知道 Neo4j 图形数据科学插件提供了一些现成的社区检测算法。我将在 GDS 图书馆快速演示如何使用卢万算法。

CALL gds.louvain.write({
 nodeProjection:'Character',
    relationshipProjection:{INTERACTS:{orientation:'UNDIRECTED'}},
    writeProperty:'louvain'
})

网络分析的一个关键细节是角色之间的互动网络是无向的。我将使用 NEuler 可视化 Louvain 算法的结果。NEuler 是一个 Neo4j 图形数据科学游乐场应用程序,可帮助您执行图形算法并可视化其结果。

用 NEuler 可视化 Louvain 算法的结果。图片由作者提供。

我不会深入算法的理论或它们的优缺点。这篇博文的目的纯粹是帮助你开始整合空手道俱乐部和 Neo4j。算法的想法和区别可能会在另一篇博客文章中出现。现在让我们在 KC 中运行一些算法。KC 只在图中的节点有连续的 id 时起作用。我不知道这个选择背后的原因;事情就是这样。我们可以很容易地创建到连续 id 的映射,并将其存储在 Neo4j 中。

MATCH (c:Character)
WITH count(*) as number, collect(c) as nodes
UNWIND range(0, number - 1) as index
WITH nodes[index] as node, index
SET node.index = index

现在,我们必须导出相关的网络数据,并从中构建一个 NetworkX 图模型。只需提供边列表就可以构造 NetworkX 图。边缘列表的语法是:

["1 2 {'weight': 3}", "2 3 {'weight': 27}", "3 4 {'weight': 3.0}"]

在这里,我们有三种关系。每个关系都包含有关源节点和目标节点的信息,以及任何可选的关系属性。这个语法可以很容易地用 Cypher 创建。首先,我定义了一个函数,它读取一个 Cypher 查询的结果,并将其转换成一个 Pandas 数据帧:

现在,我们可以继续构建一个哈利波特宇宙的网络 x 图模型。

特别注意 create_using 参数。在这种情况下,我想定义一个无向图,所以我使用了 nx。图形选项。如果你正在处理一个有向图甚至是多重图,选择相应的 create_using 参数。

可用的 NetworkX 图形模型列表。摘自官方文档

现在我们已经构建了 NetworkX 图,我们可以继续测试 KC 算法。我们将从社区检测算法 BigClam 开始。我们将计算社区结构,并将结果写回 Neo4j。

KC API 使用起来非常简单。您只需定义所需的图形算法,并在 fit 方法中输入 NetworkX 图形模型即可。再简单不过了。我添加了一些额外的代码,然后将结果存储到 Neo4j 中。让我们用 NEuler 再次可视化结果。

用 NEuler 可视化 BigClam 算法的结果。图片由作者提供。

只需扫一眼,我们就可以观察到社区结构与我们使用 Louvain 算法时略有不同。您可以测试其他十种社区检测算法,如果您发现有趣的东西,请告诉我。

节点嵌入

同样,Neo4j GDS 库提供了节点嵌入算法,如 FastRP、node2vec 和 GraphSAGE。我将展示 FastRP 算法的语法,但同样不会深入研究超参数优化。

CALL gds.fastRP.write({
  nodeProjection: 'Character',
  relationshipProjection: {
    INTERACTS: {
      orientation: 'UNDIRECTED'
    }
  },
  embeddingDimension: 64,
  writeProperty: 'fastrp'})

embeddingDimension 参数是强制性的,它定义了每个节点的嵌入向量的大小。除此之外,我们再次将交互网络定义为无向的。最后,为了比较节点嵌入模型的结果,我们将可视化嵌入的 t-SNE 散点图。

FastRP 嵌入的 t-SNE 图。用纽勒可视化。图片由作者提供。

现在让我们尝试一下 KC 包中的一些节点嵌入算法。首先,我们将定义一个绘制嵌入结果的 t-SNE 散点图的函数。

我们将从 NetMF 算法开始。NetMF 算法属于基于社区的节点嵌入范畴。如果您想了解更多的技术细节,请阅读原文或检查代码。

这一次,我使用了 Seaborn 散点图来可视化嵌入的 t-SNE 结果。

NetMF 嵌入的 t-SNE 图。用 Seaborn 可视化。图片由作者提供。

节点嵌入似乎与我们使用 FastRP 算法时有很大不同。KC 库还具有 NEU 算法 m。该过程使用任意嵌入,并使用递归元学习算法通过更高阶近似对其进行扩充。

并且嵌入的 t-SNE 结果是:

NEU 嵌入的 t-SNE 图。用 Seaborn 可视化。图片由作者提供。

算法的另一个节点嵌入类别是结构角色嵌入类别。我们不是捕获网络中靠近的节点(邻居)之间的相似性,而是希望捕获具有相似结构角色的节点之间的相似性。一个这样的算法是 Role2Vec 算法

默认 walk_length 为 80。假设我们的示例图只有 100 多个节点,我决定使用一个更小的 walk_length 值。除此之外,还有更多超参数调整的空间。由此产生的 t-SNE 图是:

role2vec 嵌入的 t-SNE 图。用 Seaborn 可视化。图片由作者提供。

基于节点角色相似度计算节点嵌入是一个令人兴奋的领域。我们不是比较网络中节点的紧密程度,而是要捕捉节点之间的结构角色相似性。然后,我们可以使用结构化角色嵌入来推断 kNN 网络,并运行社区检测算法来尝试基于节点的网络角色来分割节点。首先,我们必须将 Role2vec 结果存储回 Neo4j。

kNN 算法是 GDS 图书馆的特色。K-最近邻算法计算图中所有节点对的距离值,并在每个节点与其 K 个最近邻之间创建新的关系。距离是根据节点属性计算的。

我们将利用图表目录功能,因为我们将依次运行两个图表算法。首先,我们使用以下语法将网络的投影存储为命名图:

CALL gds.graph.create('role2vec', 'Character', '*', {nodeProperties:['role2vec']})

我们不关心无向交互关系,因为我们不会使用它们。重要的是,我们在投影中嵌入了 role2vec 节点。现在,我们可以继续改变 kNN 算法。使用突变方法,我们将算法结果存储回投影命名图,而不是 Neo4j 存储图。这样,我们可以使用 kNN 算法的结果作为社区检测算法的输入。

CALL gds.beta.knn.mutate('role2vec', 
  {topK: 5, 
   nodeWeightProperty:'role2vec', 
   mutateProperty:'weight', 
   mutateRelationshipType:'SIMILAR_ROLE'})

我们将在 SIMILAR_ROLE 类型下存储结果关系。其中一个参数是 topK ,它定义了每个节点要查找的邻居数量。返回 K 个最近邻。最后,我们可以通过使用 Louvain 算法来检查所得到的相似性网络的社区结构。

CALL gds.louvain.write('role2vec', 
  {relationshipTypes:['SIMILAR_ROLE'],
   writeProperty:'louvain_role'})

当然,剩下要做的明显的事情是可视化产生的相似性网络及其社区结构。

推断相似网络的社区结构的网络可视化。图片由作者提供。

在这个例子中,我首先计算了结构角色嵌入,然后用 kNN 算法推断了一个相似性网络,这个例子可以被认为是网络的第一个派生。我们检查节点的结构角色分割,而不是使用社区检测算法来检查原始网络结构。这在各种网络项目中非常方便。

结论

空手道俱乐部包包括节点嵌入模型,也考虑了节点属性。不幸的是,在我们简单的哈利波特网络中没有任何节点属性,所以我跳过了它们。尽管如此,节点嵌入研究领域还是很吸引人的,而且有很多方法可以确定你想从网络中提取什么类型的信息。希望 Neo4j 和空手道俱乐部项目的简单集成将帮助您使用最适合您的节点嵌入模型。我鼓励你打开一个 Neo4j 沙箱实例,测试各种方法。如果有什么有趣的事情发生,请告诉我。

和往常一样,代码可以在 GitHub 上获得。

将经过训练的机器学习模型集成到对话流聊天机器人中

原文:https://towardsdatascience.com/integrate-trained-machine-learning-model-with-dialogflow-chatbot-8f5a0bc575c5?source=collection_archive---------13-----------------------

了解如何构建、训练和存储机器学习模型。使用 Google 的 Dialogflow 构建一个聊天机器人,它使用经过训练的自定义 ML 模型来回答用户的查询。

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

问题陈述

我们将首先创建一个基本的机器学习(ML)模型,该模型将在数据集上进行训练。将使用 pickle 模块保存训练好的模型。此后,flask 应用程序将利用训练好的模型,并根据过去的数据回答诸如一年的人均收入是多少之类的查询。

你也可以在这里看到这段录音:链接

安装:

这个应用是基于 Windows 10 机器的 Python。我用 chrome 作为默认浏览器,用 VS Code 编辑代码。您还需要安装这些 python 包:flask、pickle、json、numpy、pandas 和 sklearn。

资料组

出于演示目的,使用了 Kaggle 上提供的加拿大人均收入单变量数据集。数据集只有两个属性“年份”和“人均收入(美元)”。

机器学习模型

请注意,目前的重点不是建立一个准确的模型。这篇博客展示了如何通过聊天机器人(Dialogflow)利用一个训练好的模型来回答用户的查询。

下载上述数据集并使用以下代码创建一个模型:

作者图片

下一步是保存上面训练的模型。同样,我们根本不关心预测的准确性。这里展示了端到端的项目集成。

使用下面几行代码,你可以存储训练好的模型(在我们的例子中是 linearmodel.pkl ),现在它已经可以在任何应用程序中独立使用了。

作者图片

上述代码执行后,将在项目目录中创建一个“linearmodel.pkl”文件。

烧瓶应用

  1. 让我们创建一个目录(“演示”)。移动此目录中的 linearmodel.pkl
  2. 在同一个目录下创建一个文件,比如说“app.py”。
  3. 您可以使用您最喜欢的 IDE 来编辑代码。我用的是 VS 代码。
  4. app.py 将包含如下代码。如果你不能马上理解代码,那也没关系。只是跟随更多的解释。

作者图片

在本地执行应用程序

  1. 在项目目录中,运行以下命令:“python app.py”
  2. 如果没有错误,您应该能够在本地主机上看到应用程序
  3. 但你只能看到“你好,世界。我是 Swati”。
  4. 在下一节中,我们将使用 ngrok 为本地运行的应用程序创建一个公共的 HTTPS URL。

公开执行应用程序

  1. 下载 ngrok
  2. 提取并打开文件夹,找到“ngrok.exe”文件
  3. 运行这个 exe 文件并键入“ngrok http 5000”
  4. 复制下面标记的网址并粘贴到你的浏览器上!你的应用程序是公开可用的(但只有 2 小时)。

图 1: ngrok cmd(图片由作者提供)

DialogFlow 聊天机器人

  1. 前往 Dialogflow 并创建一个账户。
  2. 按照以下步骤设置代理和非常简单的跟进意向:

Gif 1:创建对话流聊天机器人意图(图片由作者提供)

一旦你完成了,你的机器人就可以问候用户并询问问题。此时,它将无法做出任何预测。让我们看看接下来的部分!

带有实现 URL 的对话流聊天机器人

现在让我们后退一步,理解 Dialogflow 在幕后是如何工作的。下图显示了各种元素如何相互链接以满足用户查询。

图 2:当前项目的典型架构(图片由作者提供)

一个用户发出类似于“告诉我 1972 年的人均收入”的请求。查询在内部被转换为请求正文,如下所示:

{
  "responseId": "xyz-unique-id",
  "**queryResult**": {
    "queryText": "Tell me per capita income in the year 1972",
    "action": "DefaultWelcomeIntent.DefaultWelcomeIntent-yes",
    "**parameters**": {
      "**yearinput**": **1972**
    },
    "allRequiredParamsPresent": true,
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            ""
          ]
        }
      }
    ],
..........
..........
..........
}

如果指定,上述请求正文将通过 HTTP POST 请求发送到实现 URL。 app.py 是处理传入请求并使用训练好的 ML 模型进行预测或计算的应用程序。然后以下列形式发回响应:

图 3:应用程序发送的响应,即履行 URL 的响应(图片由作者提供)

履行 URL

  1. 返回到 DialogFlow 控制台,打开我们创建的操作
  2. 在 DataYear 跟进意向中,在“fulfillment”下启用“webhook call for this intent”,如下面的 Gif 所示。
  3. 单击左侧导航窗格中的“实现”
  4. 启用 webhook 选项
  5. 粘贴 ngrok URL 并在末尾附加“/webhook ”,然后单击保存:

Gif 2:在应用程序中添加 ngrok URL 并实时测试(图片由作者提供)

测试聊天机器人:

最简单的方法是 Dialogflow 控制台右侧的测试窗格。我个人非常喜欢这个功能,因为它可以让你立即测试你的聊天机器人!

Dialogflow 聊天机器人可以与许多平台集成,如 slack、丨t丨e丨l丨e丨g丨r丨a丨m丨s丨、Messenger、line 等。下面我展示了网络演示集成。

Gif 3:聊天机器人的网络演示(图片由作者提供)

结论

那是篇很长的文章!然而,我真诚地希望它对你有所帮助。本文中展示的集成是许多可能性之一。下一步,尝试创建更复杂的聊天机器人,并将应用部署在一些云应用平台上,如 Heroku 或 Azure web app,然后与 Dialogflow 集成。

还有,你可以在 TwitterLinkedIn 上问我一个问题!

参考

[1]dialog flow Documentation |。(未注明)。谷歌云。于 2021 年 9 月 16 日从https://cloud.google.com/dialogflow/docs检索

[2]dialog flow 入门。(2019 年 2 月 5 日)。YouTube。https://www.youtube.com/watch?v=Ov3CDTxZRQc&ab _ channel = Google cloud tech

从头开始集成渐变

原文:https://towardsdatascience.com/integrated-gradients-from-scratch-b46311e4ab4?source=collection_archive---------13-----------------------

一个直观的算法来解释任何深度学习模型

当阅读一篇论文时,我认为深入相关代码以更好地理解它总是好的。虽然代码通常很长,有很多优化和实用函数,很容易丢失。在这篇文章中,我将尝试用几行代码复制论文中的算法。

介绍

可解释的人工智能是当今的热门话题。如果一家公司想要采用人工智能解决方案,并使用它来做出直接影响客户的决定,它还需要有能力向客户和监管机构解释这些决定。有各种各样的方法来解释一个模型,特别是他们可以分为模型不可知和模型特定的方法。例如,当我们用一个简单且可解释的模型在局部近似一个复杂的模型时,LIME 是模型不可知的,因为它不需要知道模型的内部结构,但是您可以简单地将 predict 函数传递给它并得到解释。相反,像集成梯度这样的方法是特定于模型的,它们需要知道内部模型,以便计算组成模型的层的梯度。

这是使用集成梯度解释深度神经网络模型系列的第一篇文章。在第二步中,我将覆盖 层的电导 ,再次使用 Pytorch 亲笔签名的来计算渐变。

了解集成渐变

为了理解积分梯度,让我们首先从如何解释一个简单的线性模型开始:

作者图片

x1y 的作用是梯度乘以 x1 的值,所以 a * x1

在处理深度学习模型时,像线性模型一样简单地看梯度可能会有问题。如果在这里代表深度学习模型的 f(x)xdf(x)/dx = 0 附近是平坦的,因此 x * df/dx = 0 使你相信特征 x 是不相关的。发生这种情况是因为我们将模型训练到饱和,因此预测分数在输入附近接近平坦。因此,将 x 改变少量 dx ,因为表面 df(x)/dx 在那附近是平坦的,它将总是给我们零——我们不看相关的梯度。因此,为了捕捉相关梯度,我们需要了解梯度如何沿着从基线(通常为零,但取决于应用)到特征值的线性路径变化。

https://arxiv.org/pdf/1703.01365.pdf公式(1)

履行

现在来看一个具体的例子。我们将定义一个简单的模型,并使用 titanic 数据集:

让我们使用亲笔签名的来计算梯度,并绘制不同 k年龄的梯度变化。

作者图片

注意:梯度为绝对值

α= 1(式(1)中 k=m)时的得分对应于实际输入时的预测,而α= 0(式(1)中 k = 0)是基线时的预测。查看 alpha = 1、附近的梯度,我们可以观察到模型的饱和度,因为那里的梯度都接近于零,这就是为什么如果我们简单地查看 df/dx 它将为零,并且不会给我们一个有意义的特征属性。

现在,如果我们取这些梯度的平均值,我们得到年龄的特征属性:

注意:如果我们设置方法=‘riemann _ 梯形’,这相当于 captum 积分梯度法。(参见注释行 21)

结论

正如开始提到的,在这篇文章中,我想展示一个快速简单的集成渐变实现。如果您将它用于您的工作,您不需要从头重写它——使用伟大的 captum 库为您完成所有工作。尽管在这篇文章中,我展示了表格数据的实现,但集成梯度可以用于任何深度学习模型,包括 NLP 和计算机视觉。

参考

[1]https://arxiv.org/pdf/1703.01365.pd

https://captum.ai/tutorials/Titanic_Basic_Interpret

使用 Python 和 JavaScript 集成 Google Maps API

原文:https://towardsdatascience.com/integrating-google-maps-api-using-python-and-javascript-149fdba27b99?source=collection_archive---------4-----------------------

关于如何使用 Python 和 JS 将 Google Maps API 整合到网页中的编码指南。

照片由 NASA 拍于 Unsplash

想象一下:你正在为你自己或你的观众写一段精彩的代码(程序员说永远不会写的东西),关于最好的旅游目的地或要去的咖啡馆,或者某个地区的公用事业商店,或者某天你想去的地方,等等。将注意力引向一个地点并提供方便访问的最佳方式是使用一张标明该地点的地图,并提供任何必要的信息和链接。

迷失方向的感觉真好。

在这个故事中,我将用代码解释如何做到这一点。

要求

  1. Python 及其 web 微框架, 烧瓶
  2. 一个 api 键 用于与谷歌 api 一起工作。
  3. 像 HTML,CSS, JQuery 和 JavaScript 这样的网络技术。

已插入获取上述内容的链接。

作为参考,文件目录结构:

.
├── chipotle_stores.csv
├── app.py
├── processdata.py
├── html
│   ├── index.html
│   ├── index.css
│   └── index.js

要显示的目标文件

为了在地图上指出一些位置,你需要一些数据。更具体地说:位置、它们的坐标以及关于它们的一些信息。后者是可选的,但前者是绝对必须的。

在这种情况下,我们将使用一个包含美国所有 Chipotle 位置的 Kaggle 数据集

照片由 多丽丝·摩根 拍于 Unsplash

将这个 csv 文件下载并保存在基目录中后,数据被处理成可以在不同域中使用的格式:JSON。将执行上述任务的文件命名为 processdata.py

在这种情况下,预处理只包括:

  1. 使用 加载和读取 CSV 文件
  2. 使用 pandas 的 to_dict() 函数将 csv 转换成一个 JSON 友好格式的列表。

processdata.py

# Importing the pandas package.
import pandas as pddef processdata(): # Loading and reading the CSV file.
    df = pd.read_csv('chipotle_stores.csv', delimiter = ',') # Converting the CSV data to a list.
    df = df.to_dict(orient = 'records') return df

添加了一个返回语句,因为 Flask 应用程序将调用该程序,以获得 CSV 数据作为列表数据类型。

创建烧瓶应用程序

Flask 是一个用 Python 编写的 web 微框架,可用于创建 API 并在本地和外部托管应用程序,即使后者不是一个安全的选项。在我们的例子中,即将 Google Maps API 集成到应用程序中,Flask 正是我们所需要的,因为它为实验和探索提供了一个非常强大和安全的基础。

让 flask 应用程序的代码在 app.py 中。可以通过五个简单的步骤部署应用程序:

  1. 导入所需的烧瓶包。
from flask_cors import CORS
from flask import Flask, jsonify

2.导入实用函数,在这种情况下,它是将 CSV 转换为更合适格式的程序。

from processdata import processdata

3.为 Flask 应用程序创建一个变量和一个 URL 路由。这里, jsonify 用于将 list 数据类型转换为 JSON ,因为 JavaScript 无法读取 list 类型的数据。

app = Flask(__name__)
CORS(app)# In this case, the URL route is 'displaylocations'.
@app.route('/displaylocations')
def displaylocations(): # Obtain the CSV data.
    l = processdata() # Forward the data to the source that called this API.
    return jsonify(l)

4.根据您的选择,输入主机名和端口号。

if __name__ == '__main__':
    app.run(host = <host_name>, debug = True, port = <port_no>)

app.py

from flask_cors import CORS
from flask import Flask, jsonifyfrom processdata import processdataapp = Flask(__name__)
CORS(app)@app.route('/displaylocations')
def displaylocations():
    l = processdata()
    return jsonify(l)if __name__ == '__main__':
    app.run(host = <host_name>, debug = True, port = <port_no>)

5.最后,下面的命令需要在您系统的 shell 中执行。

python app.py

输入最后一个命令后,可以在 http://<host_name>:<port_number>/display locations 查看原始 JSON 格式的数据。</port_number></host_name>

创建服务器端应用程序

服务器端应用程序由 HTML、JS 和 CSS 文件组成。我们的服务器应用程序包括:

index.html

<div id="map"></div><script type="text/javascript" src="index.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=key"></script><script>
    var url = `http://<host_name>:<port_no>/displaylocations`;
    $.ajax({
        type: `GET`,
        url: url,
        success: function(response) {
            initMap(response);
        }
    });
</script>
  1. 创建一个 HTML div 元素来放置 Google Maps 地图。
  2. 导入 index.js 文件是为了处理我们从 flask 应用程序获得的数据。
  3. Google Maps JS 文件也被导入。:要使用谷歌的服务,需要一个密钥,可以在 这里 获得。
  4. 此外,还需要导入 JQuery 文件,以便直接从 HTML/JS 文件中调用 Flask API。 参考
  5. 现在,从我们部署的 Flask 应用程序中调用了显示位置 API。如果调用成功,位置数据将存储在变量: response (或者您选择的任何名称)。

索引. js

function initMap(data) {

    var center = {lat: data[0][`latitude`], data[0][`longitude`]};
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 4,
        center: center
    });

    var infowindow =  new google.maps.InfoWindow({});
    var marker;

    data.forEach(e => {
        marker = new google.maps.Marker({
        position: new google.maps.LatLng(e[`latitude`], e[`longitude`]),
        map: map,
        title: e[`address`],
    }); google.maps.event.addListener(marker, 'click', (function (marker) {
            return function () {
                infowindow.setContent(`State: ${e[`state`]<br>County: ${e[`location`]}<br>Address: ${e[`address`]}`);
                infowindow.open(map, marker);
            }
        })(marker));
    });
}
  1. 函数 initMap 将位置数据初始化为 HTML 文件中的响应,作为输入,并使用第一个元素初始化“center”变量,基本上是地图将居中的点。
  2. map 变量创建一个新的 Google map,并将其放在 id 为“map”的 div 元素中。设置了缩放居中等属性。其余的属性都列在 这里
  3. 还创建了一个 信息窗口 。infowindow 基本上是一个弹出窗口,或者是一个在 DOM 事件发生时打开的窗口,比如单击、鼠标悬停等等。
  4. 所有基本结构初始化后,我们循环遍历位置列表中的所有元素,为每个位置创建 标记 。还添加了侦听器,在本例中,当单击一个标记时会显示 infowindow。关于如何添加其他类型监听器的信息可以在 这里 看到。

index.css

#map {
    height: 600px;
    width: 100%;
    background-color: grey;
}

在 index.css 文件中,我们将地图的宽度设置为 100%,高度设置为 600 像素,背景为灰色。

现在剩下的就是部署这个服务器应用程序,这可以通过使用 http.server python 包来完成。

python -m http.server --cgi <port_no>

这个命令与 flask 应用程序的部署一样,是从系统的 shell 中执行的。应该从 index.html 文件所在的文件夹中执行,在这种情况下是 html 文件夹。

因此,在部署了服务器和 Flask 应用程序之后,当服务器应用程序 http:// <server_host>: 在浏览器中打开时,我们会看到所有的 Chipotle 位置都绘制在地图上。</server_host>

地图上标出了所有墨西哥小吃店的位置。

单击标记时,将打开信息窗口,其中包含有关该特定位置的所有详细信息。

有趣的事实:这是怀俄明州唯一的墨西哥卷饼!!

鉴于可用性,更多的信息,如方向,打开/关闭状态,评论也可以包括在内。

资源:

祝您在数据科学之旅中好运,感谢您的阅读:)

使用 UMAP 和聚类整合组学

原文:https://towardsdatascience.com/integrating-omics-using-umap-and-clustering-d2a5ef39693f?source=collection_archive---------6-----------------------

实践教程

使用 Python 通过降维和聚类对蛋白质组和转录组数据的联合无监督探索

蛋白质组和转录组数据集的联合 2D 嵌入和随后的聚类。作者图片

如今,生命科学是由数据驱动的。你可能听说过基因组学、转录组学、蛋白质组学,即使你不是生物学家或医学研究者。 组学 是试图整体理解细胞、组织或有机体子系统的科学方法,它们在此过程中产生大量信息。这些技术在产生数据方面做得越好,就越需要新的计算方法来处理数据。

我对整合蛋白质组学数据和其他组学的信息,主要是转录组学的信息很感兴趣。简而言之,蛋白质组学旨在确定生命系统中蛋白质的水平、功能和相互作用,而转录组学则捕捉基因表达产物 RNA 分子的快照。基因表达和蛋白质的功能错综复杂地联系在一起,因此一起探索它们结合了细胞拼图的两个关键部分。组学整合的计算方法正在积极开发中:参见,例如,多组学因子分析(MOFA 和 MOFA+ 包)[1]或混合组学 [2]。这些包涵盖了各种数据类型的监督和非监督集成的一系列用例。

实现组学技术的自动化设备。国立癌症研究所Unsplash 上拍摄的照片

最近,我将注意力转向了被称为一致流形逼近和投影,或 UMAP【3】,【4】的降维技术。是的,我参加聚会迟到了,但迟到总比不到好!我真正感兴趣是在我读了 TDS 博客的一篇文章之后,文章作者是尼古拉·奥斯科尔科夫,他利用 UMAP 构建了一个单细胞 RNA-seq 和蛋白质组数据的组合嵌入。对我来说很明显,UMAP 提供了一种在混合数据集中寻找内部结构的工具,我想知道这是否可以成为一种有效的方法,根据蛋白质和 RNA 水平上的丰度分布联合聚类基因,这项任务因基于质谱的蛋白质组学和转录组学中获取数据的方式不同而变得复杂。

加载和格式化数据

在本帖中,我们将重复使用 Hultqvist 和合著者的论文中的数据,包括发表在同行评审期刊《自然生态&进化【5】上的 yours truly。手稿在付费墙后面,但数据集是公开的,这要感谢鼓励透明和共享研究数据的出版政策。基于质谱的蛋白质组数据可以在蛋白质组鉴定数据库(PRIDE)中找到;如果没有该领域的经验,将质谱文件转换成蛋白质水平的数据可能会很复杂,因此我重新处理了它们以获得一个全面的蛋白质表,该表被放入本文的 GitHub 存储库中。RNA-seq 转录组数据可通过基因表达综合 (GEO)公开获得,我已经从页面下载了 RPKM(每千碱基每百万次阅读的阅读数)表。你们当中对这项研究的生物学方面感兴趣的人可以参考 GEO 项目的网页来获得样本的描述。

实验由属于 5 种不同条件的大肠杆菌细胞组成,我将它们称为 WT(野生型,一种默认的细胞培养物)、ORF、ORF+IPTG、SVI 和 SVI+IPTG(经过基因改造和化学处理的细胞)。每种条件下有两种平行生长的细胞培养物,我们称之为生物复制物。一式两份培养样品的目的是评估培养引起的变化,而不是由条件之间的差异引起的变化。

完整的 Jupyter 笔记本可以在 Github 资源库中找到,这里我将只展示最相关的代码片段。我们需要 umap-learn、scikit-learn 和通用数据分析库:

加载蛋白质组和 RNA 序列数据:

(1955, 48)
(4205, 37)

这些表包含一堆列,其中大部分对于这个分析是不必要的。我们将为每个蛋白质添加基因名称(将蛋白质与 RNA-seq 中的基因联系起来),选择丰度列并对它们进行对数转换:

蛋白质组表中的每一行相对丰度都表示为一个比率,该蛋白质的 WT1 丰度作为分母。这对于这种特定的蛋白质组技术来说是相当典型的(所谓的同量异位标记链接到供应商的网站获取信息),它强调丰度数据的相对性质,同时保留关于丰度变化的可变幅度的信息。使用同量异位标记的实验的一般想法是从每个样品中获取等量的总蛋白质质量。因此,我们预计样本之间蛋白质丰度的中值比率约为 1.0,因为一些蛋白质上升,一些蛋白质下降,而总蛋白质量保持不变。与中值的偏差可能是由样品制备的缺陷引起的,我们可以通过重新归一化数据进行补偿,使每个样品的中值在对数空间中等于零:

蛋白质组分布现在非常对称,以零为中心!

RNA-seq 表中的 RPKM 值分布非常不同:

以与蛋白质组数据相同的方式格式化 RNA-seq 数据可能是一个好主意:使用 WT1 强度作为每个基因的分母,并对所得比率进行对数转换:

重新归一化为相等的中间值:

选择方差最大的基因

由于生物数据的大量特征和噪声性质,仅选择最具信息性的特征用于进一步分析是有意义的。你可以在尼古拉·奥斯科尔科夫另一篇文章中找到对功能选择的深刻见解。

我们的数据集有 5 个生物条件,每个条件 2 个重复。为什么我们不在这里利用复制进行特性选择呢?简而言之,我们想要在生物条件下具有“强烈变化”的信息特征,并且我们希望过滤掉保持相对不变的特征。我们可以用一种独立的方式定义“强变化”:如果条件之间的变化超过了条件内重复之间的大部分变化值,那么它就是“强变化”。我们可以计算每个蛋白质/基因重复之间的 log2 差异:

RNA-seq 数据集中的差异明显更大。现在让我们看看这些条件的平均值之间的差异:

蛋白质表中的平均分组:

RNA 表中的平均组数:

现在我们可以看到,对于 RNA-seq 数据集,重复之间和条件之间的差异更大。这可能是因为 RNA 数据比蛋白质组数据更嘈杂,和/或因为与本研究中使用的质谱法相比,RNA-seq 测量的动态范围更高。

准备就绪后,让我们按基因名称连接这些表,并选择其中或者平均蛋白质值之间的最大变化高于蛋白质重复差异的第 90 百分位或者平均 RNA 值之间的差异高于 RNA 重复差异的第 90 百分位的行:

Proteins 90th percentile: 0.2658608755331754
RNA 90th percentile: 0.8764194924938945
Before: (1778, 32)
After: (951, 32)

UMAP 嵌入

UMAP 的数据已经准备好了!我们将从每行中选择蛋白质和 RNA 的平均值,因为我们希望强调生物条件之间的差异,而忽略条件内的变化。我们也可以排除 WT 样本,因为根据我们数据转换的本质,所有的值都非常接近于零(分母中的 WT1)。让我们计算并可视化蛋白质和 RNA 上的独立嵌入,以及联合嵌入:

太好了,我们可以看到集群正在形成!聚类的形状和分布将因设置而异,包括重要的 n_neighbors 参数。我和 n_neighbors 在 10 到 100 的范围内玩,定在 30,接近特征数的平方根(951)。

使聚集

Scikit-Learn 为我们提供了一系列可以应用于嵌入结果的聚类选项。由于我们在图上看到了密集的集群,因此尝试基于密度的集群或 DBSCAN 是很自然的。eps 参数很重要,应该根据数据进行调整。我们也可以应用其他常用的算法,例如,均值漂移凝聚聚类。这些情况下的关键参数分别是带宽和集群数量。让我们看一下通过这三种方法完成的集群概述:

Found clusters 52
Found clusters 43
Found clusters 45

从鸟瞰图来看,算法以不同的方式突出了散点图上的点的密度簇和“星座”。但是他们捕捉到了行为相似的基因群吗?为了判断这一点,我们可以用热图来表示每个星团中的相对丰度。让我们以 DBSCAN 结果为例:

看起来这些星团确实有一致的内部结构!如有必要,调整聚类参数有助于进一步调整结果组的大小和组成。在组学整合的背景下,探索显示蛋白质谱(P-样本)和 RNA 谱(R-样本)之间差异的聚类是令人兴奋的。以集群 36 和 37 为例:

我们可以看到一些有趣的相对丰度的轮廓,其中蛋白质和转录物明显不同步!此外,簇中的基因可能彼此相关。探索性的数据分析为进一步的科学研究提供了有趣的候选者!

结论

对来自同一实验的蛋白质组和转录组数据的联合 UMAP 嵌入和随后的聚类是突出相似行为基因组的直接方法。在这篇文章中,我们研究了数据过滤、使用 umap-learn 包的 UMAP 降维以及使用 scikit-learn 中实现的三种算法的聚类。

参考

[1] Argelaguet MOFA+:多模态单细胞数据综合整合的统计框架 (2020),Genome Biol 21,111

[2] F. Rohart 混合组学:一个用于“组学特征选择和多重数据整合”的 R 包 (2017),PLOS 计算生物学 13(11): e1005752

[3]麦金尼斯,希利 UMAP:统一流形逼近和降维投影 (2018),ArXiv 电子版 1802.03426,2018]

[4] E. Becht 使用 UMAP (2019),Nat Biotechnol 37,38–44 可视化单细胞数据的降维

[5]j . jerlstrm Hultqvist 一种噬菌体酶诱导细菌代谢扰动,赋予一种新的混杂功能 (2018),Nat Ecol Evol 2,1321–1330

集成 PyPlot 和 PySimpleGUI

原文:https://towardsdatascience.com/integrating-pyplot-and-pysimplegui-b68be606b960?source=collection_archive---------4-----------------------

所有图片由作者提供

一个实用的数据即解决方案。

这是给谁的?

如果你是一名数据科学家或者有一些 python 中的数据可视化需求,你可能正在使用https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.htmlPyPlot,如果你需要与你的绘图交互或者制作一个独立的程序,你将需要将 py plot 与 GUI 库集成。我之所以使用 PySimpleGUI 是因为当我想快速地将东西放在一起并演示一个工作程序时,我会使用它。

⚠️ **Caveat Emptor:** There are other patterns and ways to code the same functionality, this is what makes sense to me, if you want to learn more check these related posts: [**Organizing your python code**](https://k3no.medium.com/organizing-your-python-code-ca5445843368) and [**Alternatives to using globals Python**](https://betterprogramming.pub/alternatives-to-using-globals-in-python-a3b2a7d5411b). There are also other GUI Libraries you might want to check via the following introductory posts, in addition to [**PySimpleGUI**](https://levelup.gitconnected.com/uis-in-python-with-pysimplegui-e5cd8ea275e8) I currently like [**KIVY**](https://k3no.medium.com/kivy-menagerie-af6a53e74695) and [**PyQT/PySide**](https://medium.com/swlh/python-gui-with-pyqt-pyside2-5cca38d739fa)**.**

投机

我们想要的是一个交互式的绘图,我的意思是你在 UI 中有一些影响绘图的控件,它可以从不同的数据系列或其他数据中选择,出于演示的目的,我们的规范将只有几个基本的调用来进行交互,但希望你能适应你的项目…

imho 规范是建议性的,而不是决定性的,我的意思是,最终结果可能不会像上面那样,但会做所代表的一切,甚至可能看起来更好。

婴儿学步

在将 Pyplot(或任何其他库)与 GUI 集成之前,我发现拥有一个可工作的最小化脚本是一个好主意,这样您可以稍后将它插入 GUI:

👋👋 Hi there 👋👋 all my content is free for Medium subscribers, if you are already a subscriber I wanted to say thank you ! 🎉 If not and you are considering subscribing, you can use my membership referral link, you will be supporting this and other high quality content, Thank you !**⭐️⭐** [**Subscribe to Medium !**](https://k3no.medium.com/membership) **⭐️⭐️**

最小 PySimpleGUI Pyplot 集成

下一步是抓住这个最小的例子,并把它添加到 PySimpleGUI 中,UI 集成的关键是,有时你必须有一个各种各样的桥梁,帮助器方法,或者下降到两个库可以相互对话的水平,在这个例子中是 tkinter canvas。

Note that we lost the toolbars from PyPlot, mostly to keep things simple and use the GUI to interact with the plot, if you still need the toolbar check this demo program:[https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Matplotlib_Embedded_Toolbar.py](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Matplotlib_Embedded_Toolbar.py)

更新图表

要更新图表,我们需要重新绘制它,这意味着我们需要删除它,修改它,然后在画布上再次绘制它…

⚠️ **A few new things in this script:** We have new methods to deal with the plot update ( I am calling it chart in the methods to differentiate the methods, the plot and the figures ), there are also new "global" variables for the figure and plot so we can reference them after creating them, a new button and event catcher for the UI part and a new method to update the chart/plot/figure where we actually do the updating, one last upgrade is the makeSynthData method (always be refactoring). 

还改变了主题,以突出闪烁的更新。

好消息是,它的工作,我们现在有一个可更新的情节,它似乎工作得很好,唯一的问题是,更新似乎有点不和谐,这是由于画布重绘,并证明是一个不那么微不足道的问题…

💁 Like many things in life, getting rid of bugs in programs seems to follow the [Pareto Principle](https://en.wikipedia.org/wiki/Pareto_distribution), that is 20% of the final improvements can take 80% of your time and add considerable complexity ( *I guess* t*he flip side might be that 20% of your time will give you 80% of the program* ). In this case getting a smooth update would perhaps entail integrating PyPlot at a lower level, introducing threads and on and on, read here if you want to go this route : [How to update a plot in matplotlib?](https://stackoverflow.com/questions/4098131/how-to-update-a-plot-in-matplotlib)

折衷解决方案。

解决这种困境的一个简单的方法是简单地使用你所拥有的东西,找到简单的替代方法,这里我只是简单地将 Pyplot 风格与 PysimpleGUI 主题相匹配,这样会有更好的体验:

应该给你:

⚠️ Matching themes across libraries can be time consuming, getting the exact colors for an element might require you to dig through the documentation, my quick alternative is to simply use a color picker, so here I first changed the theme to **Solarize_Light**, and then got the colors for PySimpleGUI with a color picker (I like [colorslurp](https://colorslurp.com) ). 

发展

经过这个小小的迂回之后,剩下要做的就是添加更多的按钮和调用来修改你的情节,例如,让我们用一个滑块来改变**dataSize** 变量…

应该给你:

看在我当初的 spec 上,叶不可一世,绝望!但是说真的,它做了规范中说的所有事情。

**Some Final Changes:** I've added a [**slider**](https://pysimplegui.readthedocs.io/en/latest/call%20reference/#slider-element) element to take care of the sample size ( also renamed everything so it makes some Data Science sense ) this slider simply changes the now global dataSize variable and calls the **updateChart** method we've been using, I left the update button but renamed it to resample. The rest of the changes are visual ones( check the **layout** definition) note that most of the alignment is done via padding.

总而言之,我可以演示这一点,我希望它能作为你制作自己的快速数据即仪表板实验的起点。

感谢阅读!

将 Scikit-learn 机器学习模型集成到微软。NET 生态系统使用开放神经网络交换(ONNX)格式

原文:https://towardsdatascience.com/integrating-scikit-learn-machine-learning-models-into-the-microsoft-net-7eaec29e8669?source=collection_archive---------28-----------------------

行业笔记

使用 ONNX 格式将经过培训的 Scikit-learn 销售线索评分预测模型部署到。网络生态系统

照片由米格尔·Á拍摄。佩克斯公司的帕德里安

作为设计和开发 lead scoring 系统原型的团队的一员,我面临着将机器学习模型集成到围绕微软构建的目标环境中的挑战。网络生态系统。从技术上来说,我使用 Scikit-learn 机器学习内置算法实现了领先得分预测模型,用于回归,更准确地说是逻辑回归。考虑到初始数据分析、数据预处理、探索性数据分析(EDA)以及模型构建本身的数据准备阶段,我使用了由 Anaconda 发行版支持的 Jupyter Notebook 环境进行 Python 科学计算。之前,我在 Flask 中研究和接触过 Python,它是用这种编程语言编写的一个微型 web 框架。然而,我的目标是将 Python 编写的机器学习模型集成或部署到。NET 生态系统,使用 C#编程语言Visual Studio IDE

*注意:本文中给出的源代码仅用于演示目的——简化到强调核心概念、库和转换解决方案的程度。

什么是销售线索评分?

销售线索评分代表一种共享的销售和营销方法,用于对销售线索进行排名,以描述他们对公司的销售准备程度的潜力。这是一种为公司的销售线索数据库分配不同值的技术,通过转换为“热门线索”和官方客户来指导营销和销售团队。从战略角度来看,销售线索评分被认为是调整公司战略、提高销售团队绩效和效率的重要过程。

为什么这个故事里有 ML?

通常,数字营销、销售线索挖掘和销售团队会生成大量销售线索数据,这些数据通常以预定的结构化格式存储在单个或多个平台上。由于数据是即将到来的数字时代的新石油,公司如何处理和分析数据至关重要。然而,假设人类的专业知识足以检索有价值的数据洞察,那么将需要许多团队和人员。但是,即使这是完全正确的,它也只是一种可持续的模式,只适用于拥有丰富经验和资深数字营销、销售和商业分析背景的大型企业。

另一方面,机器学习方法在提到“大数据”这个热门术语后自然会立即出现。总的来说,机器学习算法不会取代人力资源,而是作为一种补充工具,改善和提高线索转化的过程和速度。利用数据背后的数学和统计学,机器学习可以打开视野,并“捕捉”人类肉眼目前无法“看到”的其他深入见解和结论。在有监督的机器学习领域,采用线索评分作为用例是值得一提的。我们可以使用生成数据的完整历史(作为监督学习方法的先决条件的标记数据集)。

图片中的 ONNX

在开发了用于销售线索评分的机器学习回归器之后,我开始研究将其集成到。NET 世界,用 C#编程语言访问它。不管目标环境是什么,这都是一个广泛讨论的话题,目标环境可以是 Keras、TensorFlow 或 Java 中的模型部署。总的来说,我不认为这是一个问题,而更像是一个解决系统互操作性、集成简单性和维护的挑战。归根结底,这是部署策略的复杂性。因此,我们的挑战是缩小在 Python 和 Scikit-learn 中进行数据分析和科学研究的技术“差距”,同时有机会将模型直接用作目标系统基础架构的一部分,该模型用 C#编写,并受。NET 核心框架。

开放神经网络交换(ONNX) 是代表机器学习模型的开放文件格式标准。按照设计,它完全作为一个框架无关的标准来实现,这意味着它是作为一个提供独特格式互操作性的解决方案来构建的。我使用 ONNX 标准来转换和存储机器学习模型。此外,我还使用了 ONNX 运行时,这是一个跨平台的高性能引擎,提供了一组不同的 API,在我们的例子中,用于工作和集成到不同的目标环境。NET 核心框架与 C#。

数据集概述

为了构建线索评分原型的初始版本,我决定使用在 Kaggle 上公开的线索评分数据集案例研究。数据集由名为 X Education 的公司的营销/销售团队检索的历史数据组成。总的来说,该公司是一个在线学习平台的模型,许多专业人士/学生可以在这里找到兴趣并参与一门或多门课程。数据是使用不同的来源生成的,如网页、登录页面、表单等。由于联系对特定学习领域感兴趣的候选人的过程,还另外开发了填充有数据的字段。

初始数据集涵盖 9.240 条独特的记录组织在 37 个不同的列中,包括用于独特前景识别的字段。数据分析、EDA 过程以及数据预处理和准备超出了本文的范围,因此我将直接介绍在不同工作环境之间部署机器学习模型的实用方法。

构建 ONNX 模型

我将简要介绍机器学习模型构建的核心方面,作为创建 ONNX 模型的先决条件。为此,我使用来自sk learn . model _ selection的标准拆分过程,将经过处理和优化的结果数据集划分为训练和测试子集。在这种情况下,我认为 30%的数据是测试数据

作者图片

是时候做模型了。我使用 sklearn.linear_model 库创建并装配了一个逻辑回归机器学习模型(使用‘liblinear’算法对其进行配置,以解决优化问题)。

作者图片

使用 Scikit-learn 的管道机制,我创建了一个简单的管道表单,包含数据缩放(从 sklearn.preprocessing 导入的标准缩放算法)和模型。

作者图片

此外,从另一个设计角度来看,如果只缩放数字属性(以调整零的公共平均值),这是有效的。

作者图片

最后,我从sk learn . model _ selection中引用了cro _ val _ predict功能,并生成了明确配置‘predict _ proba’估算器方法的交叉验证估算。这种评估方法确保获取成功的目标销售线索转化的概率 —事实上,解决了向每个潜在客户分配销售线索得分的挑战。

作者图片

*注意:模型验证、评估和性能调优的过程超出了本文的范围——它是机器学习设计的一部分。

一旦机器学习模型准备就绪,就该创建 ONNX 模型了。下面提到了应该导入的标准 ONNX 包。作为旁注,我想强调的是,只有当 skl2onnx 安装在开发环境上时,导入 ONNX 包才有效(这个模块可以使用“pip install skl 2 ONNX”命令安装)。

作者图片

ONNX 模型的创建实际上意味着将 Scikit 学习模型转换成遵循 ONNX 格式的文件的过程。这是通过使用 convert_sklearn() 方法完成的,该方法采用之前创建的模型及其维度,在本例中是来自已处理数据集中的要素数量。在这个场景中,特征工程以及特征降维的过程产生了总共 19 个输入特征

作者图片

最后一步是 ONNX 模型导出,在先前指定的系统位置/路径上序列化(声明文件扩展名为‘ONNX’)。

这里一个重要的信息是 ONNX 库目前支持的机器学习算法的 s et。可以使用以下命令生成版本以及所有集成算法的列表(图像预览显示了受支持算法的完整列表的一部分)。

作者图片

作者图片

因此,我总是建议在验证的上下文中检查列表,确认您正在使用受支持版本的算法来建立模型。这种检查应该在机器学习阶段进行,更准确地说是在算法选择阶段。值得一提的是,不属于 ONNX 包的任何其他算法也可以得到支持,但是适当的定制配置和调整超出了本文的范围。此外,还有一些众所周知的与软件包相关的限制,可以在官方文档页面中解决。

。网络核心集成

如前所述,将 sklearn 模型转换为 ONNX 模型是解决方案的第一部分,也是将 ONNX 模型导入的后续步骤的先决条件。网络生态系统。这可以使用微软的来完成。ML.OnnxRuntime Nuget 包。我决定使用 Microsoft Azure Function 模板来演示 ONNX 到。NET 以及下一节中描述的集成验证和测试。我已经创建了 Azure 函数,作为一个新项目,包含在一个面向。NET Core 3.1 框架版本。

作者图片

作者图片

作者图片

最初,我从 Http 请求中提取请求体,并将其反序列化为动态数据对象,这是一种在运行时检索类型的技术。然后,我使用了简单的方法来声明和初始化请求体中的每个变量。这里值得一提的是,变量的数量(请求体参数的数量)应该与 ONNX 模型创建时定义的输入特征的数量相同。

作者图片

之后,我定义了先前保存的 ONNX 模型的本地系统路径,并创建了创建输入特征列表和创建推理会话所需的输入张量。初始化会话后,就该运行它并以原始格式提取模型输出了。推理会话也可用于对 Jupyter 笔记本解决方案中已创建的 ONNX 模型进行预测。

作者图片

在会话执行之后,我已经将检索到的原始格式值解析为集合 DisposableNamedOnnxValue 对象,然后使用该集合将结果数组提取为 Dictionary < long、float>的形式。然后,字典结构用于提取转化销售线索的概率值(销售线索评分结果)。

作者图片

集成验证

考虑到最初用 Python 和 Scikit-learn 设计和编写的线索评分模型现已成功集成,我将使用 Postman API 平台测试和验证完整的场景。因为我使用 Microsoft Azure 函数模板包装了集成,所以我可以在我的开发机器上通过 HTTP 调用本地访问它,遵循之前配置的路径( url、端口和函数名绑定)。

作者图片

利用 Visual Studio 集成调试器的优势,我深入研究了模型响应,研究了对象的结构和类型。

作者图片

作者图片

作者图片

最后的话

在本文中,我展示了我们目前正在开发的线索评分原型的部分实际实现。基本上,它描述了解决从 Python 和 Scikit 转换和部署 ML 模型挑战的技术方法——了解不同的目标技术环境,在本例中是。网络生态系统。利用 ONNX 格式的优势,我演示了最简单的形式构建 ONNX 模型,并使用格式灵活性将其作为目标环境源代码的结构部分。除了这种方法正在弥合不同数据科学和应用程序开发平台之间的技术差异之外,它还提供了将已经设计好的模型与 ML.NET 的优势相集成的机会。网)。此外,ONNX NuGet 包和实现方法也可用于将 Scikit-learn 模型集成到 Web API 解决方案中。

更多应用

除了构建销售线索评分系统,我们还成功创建了一个销售线索决策原型,该原型遵循类似的模式,除了机器学习算法选择之外。到目前为止,我已经使用随机森林分类器开发了一个线索决策集成模块。它也是 ONNX 包支持的算法列表的一部分。因此,从业务角度来看,我们提供了根据历史和当前数据做出销售线索决策的机会。

此外,在进行探索性数据分析并涵盖设计和构建 ML 模型的过程时,我们正在提供和生成有益于未来应收集和跟踪的数据的优选类型和格式的数据见解和知识这种全面的数据分析之后是模型的解释过程,通常提供特征和相关性重要性的其他有价值的方面

— — — — — — — — — — — —

感谢您阅读内容,我坚信这些内容清晰、详细且有帮助。

我目前的重点和专业知识与企业 web 开发和架构中的最新和前沿技术优势有关,特别是微软。网络生态系统。此外,我喜欢从事数据科学、生物信息学和数字营销/销售线索挖掘中的机器学习应用。所以,如果你能花时间评论、支持和分享这篇文章,我将非常感激。

最初发表于【https://www.linkedin.com】

用胶水粘合雪花

原文:https://towardsdatascience.com/integrating-snowflake-with-glue-c00a1e25335c?source=collection_archive---------12-----------------------

将两个系统结合在一起可能很棘手,但是您获得的数据洞察力是值得的。

米凯拉·帕兰特在 Unsplash 上的照片

雪花是一个优秀的现代数据库,它将传统 SQL 的强大功能与现代数据湖架构相结合。AWS Glue 是内置于 AWS 无服务器生态系统中的本地 ETL 环境。它们共同构成了构建现代数据湖的强大组合。

本文将详细介绍如何创建一个胶合工作来将 120 年的奥运奖牌数据加载到雪花数据库中,以确定哪个国家拥有最好的击剑手。

将您的雪花凭据集成到 Secrets Manager 中

AWS 提供了一个名为 Secrets Manager 的实用程序来存储密码,它有几个特性,包括自动密码轮换,这使它非常适合安全存储。

利用 Secrets Manager 的最佳方式是使用多因素身份验证来存储您的雪花凭据。

打开秘密管理器,添加你的雪花用户证书。填写管理器中的所有必填字段,并存储密码。

雪花连接参数(按作者)

填写雪花连接信息

记录秘密 ID,并将其添加到云形成文件中的 AWS::IAM::Role 规范中。使用环境变量来存储机密名称。不用担心;我们将使用 AWS 角色来明确限制对粘合作业的秘密访问。

- PolicyName: "AllowSecretsManager"
  PolicyDocument:
    Version: "2012-10-17"
    Statement:
      - Effect: "Allow"
        Action: [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
        ]
        Resource: [
            !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${SecretName}*"

该策略将允许您的胶合作业连接到雪花以执行操作。

创造一个舞台

复制需要连接到 AWS 中 S3 存储桶的阶段。按照雪花法创建一个阶段。最佳实践是为您的 S3 存储区创建一个存储集成,然后为应用程序或客户创建多个存储集成阶段。你可以使用 SNOWSQL 和变量替换来实现自动化。

!set variable_substitution=true;
create or replace stage &{database}.stage.OLYMPICS
storage_integration = &{storage_integration}
url = '&{S3DataHome}/stage/olympics/';

在雪花中创建一个表来包含数据

我们将创建一个表来包含公共数据集,该数据集包含按运动员、运动和他们所代表的国家分类的运动员成绩。下表列出了每个数据仓库表应该包含的数据集列和标准列(以粗体突出显示)。

CREATE OR REPLACE TABLE STAGE.OLYMPICS_ATHELETE_EVENT
(
 **FILE_LOAD_ID     INTEGER identity (1,1),
    FILE_NAME         VARCHAR,
    FILE_ROW_NUMBER         INTEGER,**
    ID             VARCHAR(100) NOT NULL,
    NAME           VARCHAR(100) NOT NULL,
    SEX            VARCHAR(100) NOT NULL,
    AGE            VARCHAR(100) NOT NULL,
    HEIGHT         VARCHAR(100) NOT NULL,
    WEIGHT         VARCHAR(100) NOT NULL,
    TEAM           VARCHAR(100) NOT NULL,
    NOC            VARCHAR(100) NOT NULL,
    GAMES          VARCHAR(100) NOT NULL,
    YEAR           VARCHAR(100) NOT NULL,
    SEASON         VARCHAR(100) NOT NULL,
    CITY           VARCHAR(100) NOT NULL,
    SPORT          VARCHAR(100) NOT NULL,
    EVENT          VARCHAR(100) NOT NULL,
    MEDAL          VARCHAR(100) NOT NULL,
 **DW_CREATE_DATE TIMESTAMPTZ           DEFAULT CURRENT_TIMESTAMP(),
    DW_CREATE_USER VARCHAR      NOT NULL DEFAULT CURRENT_USER(),
    DW_UPDATE_DATE TIMESTAMPTZ           DEFAULT CURRENT_TIMESTAMP(),
    DW_UPDATE_USER VARCHAR      NOT NULL DEFAULT CURRENT_USER()**
);

创建一个 COPY 语句来从 S3 加载数据

Snowflake 中的 COPY 语句是从数据仓库导入和导出数据的强大方法。它将加载任何新的数据文件,并忽略以前加载的文件。利用拷贝是管理仓库的一种简单而有效的方法。

copy into STAGE.OLYMPICS_ATHELETE_EVENT (FILE_NAME,
                                         FILE_ROW_NUMBER,
                                         ID,
                                         NAME,
                                         SEX,
                                         AGE,
                                         HEIGHT,
                                         WEIGHT,
                                         TEAM,
                                         NOC,
                                         GAMES,
                                         YEAR,
                                         SEASON,
                                         CITY,
                                         SPORT,
                                         EVENT,
                                         MEDAL)
    from (
        select METADATA$FILENAME        file_name,
               METADATA$FILE_ROW_NUMBER row_number,
               t.$1,
               t.$2,
               t.$3,
               t.$4,
               t.$5,
               t.$6,
               t.$7,
               t.$8,
               t.$9,
               t.$10,
               t.$11,
               t.$12,
               t.$13,
               t.$14,
               t.$15
        from @stage.OLYMPICS t
    )
    pattern = '.*athlete_events.csv.gz'
    on_error = CONTINUE
    force = false
    file_format = (field_optionally_enclosed_by = '"'
        type = 'csv'
        compression = GZIP
        field_delimiter = ','
        skip_header = 1);

云的形成脚本

自动气象站的基础是云的形成。基本云形成文件包含参数部分、角色部分和组件部分。上面的组件部分包含了本文前面的 Secrets Manager 片段。

AWSTemplateFormatVersion: "2010-09-09"
Description: >
  This Template Configures a Job to Load Event Data into a Snowflake Table using GlueParameters:
  JobName:
    Type: String
    Description: "The Glue Job name used for the Stack and tags in the Snowflake query" JobSql:
    Type: String
    Description: "A SQL COPY function to load the data into Snowflake." S3DataHome:
    Type: String
    MinLength: "1"
    Description: "The S3 Bucket Containing the Data Lake Data" SecretName:
    Type: String
    Description: "The secret containing the Snowflake login information"Resources:
  SnowflakeGlueJobRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - glue.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:PutObject"
                  - "s3:ListBucket"
                  - "s3:DeleteObject"
                Resource:
                  - !Sub "arn:aws:s3:::${S3DataHome}"
                  - !Sub "arn:aws:s3:::${S3DataHome}/*" - PolicyName: "AllowSecretsManager"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action: [
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:DescribeSecret"
                ]
                Resource: [
                    !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${SecretName}*"
                ] ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole
      Path: "/" LoadOlympicData:
    Type: AWS::Glue::Job
    Properties:
      Command:
        Name: pythonshell
        PythonVersion: 3
        ScriptLocation: !Sub "s3://${S3DataHome}/src/etl-scripts/copy_to_snowflake.py"
      GlueVersion: 1.0
      DefaultArguments:
        "--job-bookmark-option": "job-bookmark-enable"
        "--job-language": "python"
        "--extra-py-files": !Sub "s3://${S3DataHome}/lib/snowflake_connector_python-2.4.2-cp37-cp37m-manylinux2014_x86_64.whl"
        "--RegionName": !Sub "${AWS::Region}"
        "--SecretName": !Ref SecretName
        "--JobName": !Ref JobName
        "--JobBucket": !Ref S3DataHome
        "--JobSql": !Ref JobSql
      ExecutionProperty:
        MaxConcurrentRuns: 2
      MaxRetries: 0
      Name: snowflake-load-olympic-data
      Role: !Ref SnowflakeGlueJobRole

在 Docker 中创建雪花 Python 轮

仔细记下带有雪花连接器库的行。由于雪花不是 AWS 的原生产品,您需要提供一个带有雪花 Python 库编译的二进制文件的 Wheel 文件。使用 docker 或带有 AWS AMI 的 EC2 实例来创建 wheel 文件。

这是 docker 文件。

python3.7 -m venv wheel-env
source wheel-env/bin/activate
pip install --upgrade pip
cat "snowflake-connector-python" > requirements.txt
for f in $(cat ../requirements.txt); do pip wheel $f -w ../wheelhouse; done
cd wheelhouse/
INDEXFILE="<html><head><title>Links</title></head><body><h1>Links</h1>"
for f in *.whl; do INDEXFILE+="<a href='$f'>$f</a><br>"; done
INDEXFILE+="</body></html>"
echo "$INDEXFILE" > index.html
cd ..
deactivate
rm -rf cache wheel-env
aws s3 sync wheelhouse s3://${S3DataHome}/lib/

创建 Python 脚本

粘合作业需要一个 Python 脚本。

ScriptLocation: !Sub "s3://${S3DataHome}/src/etl-scripts/copy_to_snowflake.py"

该脚本相当通用,并且需要一个 SQL 文件来执行,以便于重用。

import sysimport boto3
import jsonfrom botocore.exceptions import ClientError
from awsglue.utils import getResolvedOptionsimport snowflake.connector def get_secret_json(session, secret_name, region_name): client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    ) secret = None
    get_secret_value_response = None try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
            raise e
    else:
        if 'SecretString' in get_secret_value_response:
            secret = get_secret_value_response['SecretString'] return json.loads(secret) def connect(user, password, account, database, warehouse, session_parameters=None):
    *"""*
 *Connect to Snowflake*
 *"""*
return snowflake.connector.connect(
        user=user,
        password=password,
        account=account,
        database=database,
        warehouse=warehouse,
        session_parameters=session_parameters
    ) def read_sql(session, bucket, filename):
    s3_client = session.client("s3")
    s3_object = s3_client.get_object(Bucket=bucket, Key=filename)
    return s3_object['Body'].read().decode("utf-8") def main():
    # Create a Secrets Manager client
    session = boto3.session.Session() args = getResolvedOptions(sys.argv, ['JobName', 'RegionName', 'SecretName', 'JobBucket', 'JobSql']) json_secret = get_secret_json(session, args["SecretName"], args["RegionName"]) sql = read_sql(session=session, bucket=args["JobBucket"], filename=args["JobSql"]) with connect(
            user=json_secret['USERNAME'],
            password=json_secret['PASSWORD'],
            account=json_secret['ACCOUNT'],
            database=json_secret['DB'],
            warehouse=json_secret['WAREHOUSE'],
            session_parameters={
                'QUERY_TAG': args["JobName"]
            }) as con:
        cs = con.cursor() result_cs = cs.execute(sql) result_row = result_cs.fetchone() print(result_row) if __name__ == "__main__":
    main()

使用云形成脚本创建粘合作业

下面是 Makefile 表单,用于执行云形成脚本来创建粘合作业。

package-job:
   aws cloudformation package \
      --template-file resources/glue/snowflake-glue-load-history.yaml \
             --s3-bucket ${S3_DEPLOYMENT_BUCKET} \
       --output-template-file build/snowflake-glue-load-history.yamldeploy-job: package-job
   aws cloudformation deploy \
      --template-file build/snowflake-glue-load-history.yaml \
      --parameter-overrides S3DataHome=${S3_DATA_BUCKET} \
         SecretName="${SECRET_NAME}" JobName=${LOAD_OLYMPICS_DATA_JOB} \
         JobSql=${SQL_COPY_OLYMPIC_DATA} \
       --stack-name ${LOAD_OLYMPICS_DATA_JOB} \
       --capabilities CAPABILITY_IAM

执行粘合作业(或对其进行调度)

您可以在 AWS 控制台中运行和执行 Glue 作业。

胶水控制台(作者)

胶合过程的成本是每 DPU 小时 0.44 美元,每秒计费,最少 1 分钟,因此它在价格上非常有竞争力,即使是运行在 EC2 实例上的免费 ETL 工具。

检查结果

现在有趣的部分—运行查询来检查您的数据。

select TEAM,
       sum(case when MEDAL='Gold' then 1 else 0 end) GOLD_MEDALS,
sum(case when MEDAL='Silver' then 1 else 0 end) SILVER_MEDALS,
sum(case when MEDAL='Bronze' then 1 else 0 end) BRONZE_MEDALS
from stage.OLYMPICS_ATHELETE_EVENT
where medal in ('Gold', 'Silver', 'Bronze')
 and sport = 'Fencing'
    group by team
order by sum(case when MEDAL='Gold' then 1 else 0 end) desc,
         sum(case when MEDAL='Silver' then 1 else 0 end) desc,
         sum(case when MEDAL='Bronze' then 1 else 0 end) desc;

那么谁的剑术最好呢?当然是意大利。

结论

加载数据是一项棘手的技术工作,尤其是在桥接两个系统时,比如 AWS 和雪花。然而,结果——从数据中获得的洞察力将使它变得值得。从这篇文章中吸取这些教训:

  1. 将您的凭证保护到您的雪花数据库
  2. 借力雪花舞台AWS S3 整合
  3. 使用云形成来集成 AWS 服务
  4. 扩展 Glue Python 作业以自动加载雪花中的数据
  5. 通过使用 SQL 查询提出有趣的问题,让数据自己说话

快乐数据分析!

(使)融入🤗带 MedCAT 的变压器,用于生物医学 NER+L

原文:https://towardsdatascience.com/integrating-transformers-with-medcat-for-biomedical-ner-l-8869c76762a?source=collection_archive---------26-----------------------

Irwan iweUnsplash 拍摄的照片

生物医学 NER+L 致力于从电子健康记录(EHRs)中的自由文本中提取概念,并将它们链接到大型生物医学数据库,如 SNOMED-CT 和 UMLS。

医学概念注释工具包(MedCAT)使用基于 Word2Vec 的浅层神经网络来检测和消除生物医学概念的歧义。这种方法给了我们:1)无监督训练;2)检测数百万个独特概念的可能性;3)训练速度快,资源要求低;4)仅从正面例子中学习的能力;

对于一些我们有足够训练样本的用例,基于变压器(如 BERT)的监督学习方法可能更合适。

在这项工作中,我们展示了如何整合🤗使用 MedCAT 的数据集/转换器,或者更准确地说,我们展示了如何将 MedCATtrainer 导出(手动注释的项目)转换为🤗数据集和训练 a🤗变压器型号。

先决条件:

随附的 Jupyter 笔记本可以在 MedCAT 资源库中找到。

数据准备

MedCATtrainer 用于手动注释任何生物医学概念的自由文本文档(例如 SNOMEDUMLS )。注释过程完成后,项目可以以如下所示的.json格式导出(有限视图):

{'projects': [{'name': '<something>', 
               'documents': [{'text': '<some text>', 
                              'annotations': [{'start': 23,
                                               'end': 32,
                                               'cui': <label>},
                                              ...]}]}]}

简化对一个🤗Transformer 模型,我们将 JSON 输出转换成🤗数据集。我们只保留 JSON 中的重要特性,而丢弃其他特性:

features=datasets.Features(
{
"id": datasets.Value("int32"),
"text": datasets.Value("string"),
"ent_starts": datasets.Sequence(datasets.Value("int32")),
"ent_ends": datasets.Sequence(datasets.Value("int32")),
"ent_cuis": datasets.Sequence(datasets.Value("string")),
}),

这里,id是文档的 ID,text是文档的文本,ent_starts是文档中所有被手工注释的实体的起始字符的位置列表,ent_ends是结束字符的位置,ent_cuis是标签。请注意,MedCATtrainer 使用在线学习,虽然用户能够创建新实体,但大多数实体都由 MedCAT 预先注释,并由用户简单验证(正确/不正确)。因此,当在 dataset 类中生成示例时,我们只保留correct示例和那些由用户添加的manually_created示例,换句话说:

for entity in document['annotations']:
    if entity.get('correct', True) or entity.get('manually_created', False):
        # Use the annotation
        ...

加载.json文件现在很简单:

import os
import datasets
from medcat.datasets import medcat_nerDATA_PATH = '<path to my .json export from medcattrainer>'
dataset=datasets.load_dataset(os.path.abspath(medcat_ner.__file__), 
                              data_files=DATA_PATH, 
                              split=datasets.Split.TRAIN)

一旦数据集被加载,我们需要把它转换成正确的格式🤗变形金刚模型。也就是说,对文本进行标记并分配标签。我们写了一个包装器🤗tokenizers,这将照顾一切:

from medcat.datasets.tokenizer_ner import TokenizerNER
from transformers import AutoTokenizerhf_tokenizer = AutoTokenizer.from_pretrained('<name>')
id2type = {}
for i in range(hf_tokenizer.vocab_size):
    id2type[i] = 'sub' if hf_tokenizer.convert_ids_to_tokens(i).startswith("##") else 'start'
tokenizer = TokenizerNER(hf_tokenizer, id2type=id2type)

使用新的标记器,我们可以将数据集转换成所需的格式:

encoded_dataset = dataset.map(
 lambda examples: tokenizer.encode(examples, ignore_subwords=True),
 batched=True,
 remove_columns=['ent_cuis', 'ent_ends', 'ent_starts', 'text'])

数据集现在看起来像这样:

Dataset({
    features: ['id', 'input_ids', 'labels'],
    num_rows: 4935
})

培训 a🤗变形金刚模型

如果我们的用例具有相对较少数量的独特概念(不是几十个,几千个),我们可以使用来自🤗使用 TokenClassification 头:

# It is important to set the num_labels, which is the number of unique conceptsmodel = AutoModelForTokenClassification.from_pretrained("emilyalsentzer/Bio_ClinicalBERT", num_labels=len(tokenizer.label_map))

为了对数据进行批处理并填充到需要的地方,我们使用了来自MedCAT.datasetsCollateAndPadNER,对于metrics,我们编写了一个简单的函数来打印令牌分类报告。现在一切都准备好了,我们从🤗并运行培训:

trainer = Trainer(
    model=model,                         
    args=training_args,                 
    train_dataset=encoded_dataset['train'],       
    eval_dataset=encoded_dataset['test'],     
    compute_metrics=metrics,
    data_collator=collate_fn,
    tokenizer=None # We've tokenized earlier
)
trainer.train()

结果

我们在 MedMentions (MM)上测试性能,因为它是一个相当完整的数据集,有大量的注释(它并不完美,因为注释者有一些分歧,但它已经足够好了)。

该模型在三个不同版本的 MM 上进行测试:1)整个数据集;2)只有频率在 300 以上的概念;3)只有 1000 以上的频率。

完整的 MM 数据集(测试集中的 13069 个概念)

BERT 最糟糕的用例,大量的概念,其中大多数有<10 occurrences. As it can be seen BERT cannot handle this use-case at all — at least not in this form. All scores are macro averaged.

  • MedCAT (unsupervised): F1=0.67, P=0.80, R=0.69
  • BERT: F1=0.0, R=0.01, P=0.0

Only concepts with frequency > 300 个(测试集中有 107 个概念)

第一个用例在医疗保健领域是相当标准的,大量的概念带有不同数量的注释。稍微不太标准的是,我们已经为每个概念添加了不少注释。有趣的是表演几乎是一样的。

  • MedCAT(监督):P=0.50,R=0.44,F1=0.43
  • 伯特:P=0.47,R=0.46,F1=0.43

仅频率> 1000 的概念(测试集中有 12 个概念)

这个用例应该最适合 BERT,因为我们只关注具有大量训练数据的概念。像这样的用例非常罕见,这一个有点特殊,因为出现这么多次的概念主要是定性概念——它们非常多样(许多不同的术语属于同一个概念),更适合类似 BERT 的模型。

  • MedCAT(受监督):F1=0.34,P=0.24,R=0.70
  • 伯特:F1=0.59,P=0.60,R=0.59

结论

生物医学 NER+1 是一项艰巨的任务,就像其他任何事情一样,一个模型并不适合所有情况。我们表明,对于具有有限数量的训练样本或相对较低的术语方差的用例,基于 Word2Vec 的浅层神经网络是更好的选择。但是,如果我们有大量的训练样本和较高的长期方差,基于 BERT 的模型表现更好。

最后,这两种方法现在都是 MedCAT 的一部分。

集成 Trino 和 Apache Ranger

原文:https://towardsdatascience.com/integrating-trino-and-apache-ranger-b808f6b96ad8?source=collection_archive---------6-----------------------

了解如何为数据安全配置 Apache Ranger 和 Trino。

照片由飞:D的 Unsplash

图片由作者创作,灵感来自分别为 Trino 和 Apache Software Foundation 商标的徽标

第一部分:概念和想法

背景

随着对数据需求的日益增长,企业对数据安全性的要求也在不断提高。在 Hadoop 生态系统中,Apache Ranger 是一个很有前途的数据安全框架,拥有大量插件,如 HDFS、Solr、Yarn、Kafka、Hive 等。 Apache Ranger 在版本 2.1.0 中为 prestosql 添加了一个插件,但最近 PrestoSQL 被更名为 Trino ,这破坏了 Apache Ranger 的 PrestoSQL 插件。

我已经提交了这个问题的补丁,这里已经有一个公开的 JIRA 问题但是这不会阻止我们将 Trino 与 Apache Ranger 集成。对于本教程,我已经用 Trino 插件构建了 Apache Ranger 2.1.0。如果你想从包括 trino 插件的源代码中构建 Apache Ranger,你可以参考分支ranger-2.1.0-trino上的这个 GitHub 库,出于本教程的目的,我们将这个 Github 库。

更新时间:2022 年 5 月 20 日

Trino 插件现已在 ranger 资源库中正式发布,发布于 Apache Ranger-2.3https://github.com/apache/ranger/tree/ranger-2.3

组件和关键思想介绍

阿帕奇游侠有三个关键部件ranger-adminranger-usersyncranger-audit。让我们了解一下这些组件。

注意: 配置 *ranger-usersync* 超出了本教程的范围,我们不会在本教程中使用任何 *usersync* 组件。

管理员管理

Ranger 管理组件是一个 UI 组件,使用它我们可以为不同的访问级别创建策略。Ranger Admin 需要一个后端数据库,在我们的例子中,我们使用 Postgres 作为 Ranger Admin UI 的后端数据库。

管理员审计

Ranger 审计组件收集并显示资源的每个访问事件的日志。Ranger 支持两种审计方式,solrelasticsearch。我们将使用elasticsearch来存储 ranger 审计日志,这些日志也将显示在 Ranger 审计 UI 中。

特里诺

Trino 是一个快速分布式查询引擎。可以连接多个数据源,如hivepostgresoracle等。你可以在官方文档这里阅读更多关于 Trino 和 Trino 连接器的信息。对于本教程,我们将使用默认目录tpch,它带有虚拟数据。

trino-Ranger-插件

阿帕奇游侠支持许多插件,如 HDFS,蜂巢,纱线,特里诺等。每个插件都需要在运行该进程的主机上进行配置。Trino-Ranger-Plugin 是一个组件,它将与 Ranger Admin 通信,以检查和下载访问策略,然后这些策略将与 Trino 服务器同步。下载的策略作为 JSON 文件存储在 Trino 服务器上,可以在路径/etc/ranger/<service-name>/policycache下找到,因此在这种情况下,策略路径是/etc/ranger/trino/policycache

下图解释了上述组件之间的通信。

作者图片

docker-compose 文件连接了上述所有组件。

关于docker-compose.yml的要点

  1. 我们已经使用named-docker-volumes ex: ranger-es-dataranger-pg-data来持久化诸如 elasticsearch 和 postgres 等服务的数据,即使在容器重启之后
  2. Ranger-Admin 和 Ranger-Trino 插件的预构建 tar 文件可作为发布资产在这个演示存储库这里获得。
  3. ranger-Admin 进程需要至少 1.5 GB 的内存。Ranger-Admin tar 文件包含install.propertiessetup.shsetup.sh脚本从install.properties读取配置。以下补丁文件描述了与 Ranger-Admin 组件的默认版本install.properties相比,对install.properties所做的配置更改。

4.Ranger-Trino-Plugin tar 文件也包含了install.propertiesenable-trino-plugin.sh脚本。关于 trino docker 环境需要注意的重要一点是,配置文件和插件目录被配置到不同的目录位置。配置是从/etc/trino读取的,而插件是从/usr/lib/trino/plugins加载的。这两个目录在为 Trino-Ranger-Plugin 配置install.properties时非常重要,因此需要对 Trino-Ranger-Plugin tar 文件附带的默认脚本enable-trino-plugin.sh进行一些额外的定制,以使其能够与 dockerized Trino 一起工作。这些更改在下面的修补程序文件中突出显示。基本上,这些变化引入了两个新的自定义变量INSTALL_ENVCOMPONENT_PLUGIN_DIR_NAME,它们可以在install.properties中进行配置

5.install.propertiesTrino Ranger 插件的文件需要按照以下补丁文件所示进行配置。请注意,我们使用两个新引入的自定义变量来通知enable-plugin-scriptTrino 已经部署在 docker 环境中。

6.最后,如下图所示,将它们放在docker-compose.yml中。这个文件也可以在 Github 库这里获得。

第二部分:设置和初始化

在这一部分中,我们将部署 docker-compose 服务并确认每个组件的状态。

步骤 1:克隆存储库

git clone [https://github.com/aakashnand/trino-ranger-demo.git](https://github.com/aakashnand/trino-ranger-demo.git)

步骤 2:部署 docker-compose

$ cd trino-ranger-demo
$ docker-compose up -d

一旦我们使用 docker-compose 部署服务,我们应该能够看到四个正在运行的服务。我们可以通过docker-compose ps来证实这一点

步骤 3:确认服务

让我们确认 Trino 和 Ranger-Admin 服务在以下 URL 上是可访问的

游侠管理员: http://localhost:6080

崔诺: http://localhost:8080

elastic search:http://localhost:9200

步骤 4:从 Ranger-Admin 创建 Trino 服务

让我们访问 Ranger-Admin 用户界面,并作为admin用户登录。我们在上面的ranger-admin-install.properties文件中配置了我们的管理员用户密码rangeradmin1。正如我们在下面的截图中看到的,默认情况下,没有trino服务。因此,让我们创建一个名为trino的服务。服务名应该与在 **install.properties** 中为 Ranger-Admin 定义的名称相匹配

请注意 JDBC 字符串中的主机名。从 **ranger-admin** 容器 trino 可到达 **my-localhost-trino** ,因此主机名被配置为 **my-localhost-trino**

如果我们点击测试连接,我们将得到如下所示的连接失败错误。这是因为 Ranger-Admin 进程已经在运行,并且仍在寻找我们尚未创建的名为trino的服务。一旦我们点击Add,它将被创建。

因此,让我们添加trino服务,然后再次单击Test Connection

现在 Ranger-Admin 成功连接到 Trino🎉

步骤 5:确认 Ranger 审计日志

要检查审计日志,从顶部导航栏导航至审计,并点击Audit。我们可以看到显示了审计日志🎉。Ranger-Admin 和 Elasticsearch 工作正常。

第三部分看到它在行动

现在我们已经完成了设置,是时候创建实际的访问策略并查看它的运行情况了

  • 当创建trino服务时,我们在连接信息中使用ranger-admin作为用户名。这会使用该用户名创建默认策略,因此ranger-admin用户将拥有超级权限

为了理解访问场景并创建访问策略,我们需要创建一个测试用户。Ranger usersync 服务将各种来源(如 Unix、文件或 AD/LDAP)的用户、组和组成员身份同步到 Ranger 中。Ranger usersync 提供了一组丰富而灵活的配置属性,用于同步来自 AD/LDAP 的用户、组和组成员,支持多种使用情形。在本教程中,我们将从 Ranger-Admin UI 手动创建一个测试用户。

步骤 1:从 Ranger-Admin 创建test-user

要创建用户,我们导航至设置→用户/组/角色→添加新用户

创建用户时,我们可以选择不同的角色。

  • user角色是普通用户
  • Admin角色可以从 Ranger Admin UI 创建和管理策略。
  • Auditor角色是read-only用户角色。

现在,让我们创建一个角色为Admin的用户。

步骤 2:确认进入test-user和 r anger-admin

让我们确认用户的访问权限ranger-admin

正如我们看到的ranger-admin用户可以访问模式tpch.sf10下的所有表

由于我们没有为test-user配置任何策略,如果我们试图访问任何目录或执行任何查询,我们应该会看到一条访问被拒绝消息。让我们通过从 Trino CLI 执行查询来确认这一点

步骤 3:允许访问模式tpch.sf10下的所有表test-user

让我们创建一个允许test-user访问tpch.sf10所有表的策略。

我们还可以为每个策略分配特定的权限,但是现在让我们创建一个具有所有权限的策略。创建此策略后,我们有以下活动策略。

现在让我们再次确认访问。

我们仍然收到拒绝访问的消息。这是因为需要为每个对象级别配置 Trino ranger 策略。例如,catalog级策略,catalog+schema级策略,catalog+schema+table 级策略, information_schema级策略。让我们为catalog级别添加策略。

让我们用 Trino CLI 再次确认

我们仍然得到错误,但错误信息不同。让我们转到 Ranger 审计部分,了解更多相关信息。

我们可以看到一个拒绝对名为tpch.information_schema.tables.table_schema的资源进行访问的条目。在 Trino 中,information_schema是包含关于表和表列的元数据的模式。因此也有必要为information_schema添加策略。任何用户都需要访问information_schema才能在 Trino 中执行查询,因此,我们可以在 Ranger 策略中使用{USER}变量,将访问权限授予所有用户。

让我们再次从 Trino CLI 确认访问。

如果我们试图执行任何 SQL 函数,我们仍然会得到拒绝访问的消息。在默认策略部分,all-functions策略(ID:3)是允许 access 执行任何 SQL 函数的策略。因为执行 SQL 函数是所有用户的要求,所以让我们编辑all-functions策略(ID:3)并使用{USER}变量添加所有用户来访问函数

总而言之,为了访问sf10下的test-user所有表,我们添加了三个新策略,并编辑了默认的all-function策略。

现在我们可以访问和执行针对sf10模式的所有表的查询。

在下一步中,让我们了解如何为模式sf10下的特定表提供对test-user的访问

步骤 4:授予对sf10模式下特定表的访问权

在上一步中,我们配置了策略来访问sf10模式下的所有表,因此,schema-level策略是不必要的。为了访问特定的模式,我们需要添加schema-level策略,然后我们可以配置table-level策略。所以让我们为tpch.sf10增加schema-level一项政策

现在让我们将sf10-all-tables-policy从所有表格编辑到特定表格。我们将配置一个策略,只允许访问nation

最后,我们有以下积极的政策

现在让我们再次从 Trino CLI 对test-user执行查询。

test-user现在可以根据需要从tpch.sf10模式中访问唯一的nation表。

如果你已经完成了所有的步骤,那么恭喜你,㊗️,现在你已经了解了如何配置 Trino 和 Apache Ranger。

第三部分:关键要点和结论

  • 从 PrestoSQL 更名为 Trino 后,Apache Ranger 的 GitHub 库中的默认插件将无法与新的 Trino 一起工作,因为它仍然引用旧的io.prestosql包。你可以在 JIRA 这里追踪这个问题
  • 更名的 Trino 插件将不会在新的 Ranger 版本 2.2.0 中提供。因此,与此同时,请随意使用这个 GitHub 库从源代码构建 Apache Ranger,使用这个 GitHub 库开始 Trino-Ranger 集成。
  • 为 Trino 配置 Ranger 策略并不那么直观,因为我们需要为每个级别配置访问策略。在 Trino 的知识库这里有一个关于这个的公开问题。
  • 尽管如此,建议配置一些基本策略,如带有{USER}变量的information_schemaall-functions,因为这些策略对于任何用户执行查询都是必需的。

由于缺乏好的文档和集成过程不太直观,集成 Apache Ranger 和 Trino 可能会很痛苦,但我希望这篇文章能让它变得简单一点。如果你正在使用 Trino,我强烈推荐你加入 Trino 社区 Slack 进行更详细的讨论。感谢您的阅读。

将您的数据分析与 Google Workspace 和 Google 云存储相集成

原文:https://towardsdatascience.com/integrating-your-data-analysis-with-google-workspace-and-google-cloud-storage-f80649404bb0?source=collection_archive---------27-----------------------

如何使用 Python 从云中加载文件

马文·迈耶在 Unsplash 上的照片

1.介绍

协作是当今成功的数据团队的关键因素之一。您的团队交流和共享信息的方式会对您公司的生产力产生重大影响。

不幸的是,大多数公司仍然依赖于通过电子邮件和其他通信平台共享 CSV 和 Excel 文件,这种做法损害了数据的一致性和安全性。

因此,使用正确的工具共享数据文件可以提高您的分析重现性,并帮助您的团队提高生产率。

本文的目标是介绍几种使用Google Workspace Google 云存储 的数据共享替代方案。

下面介绍的每个函数的教程和代码可以在我的 GitHub 库中找到。

2.谷歌云环境

谷歌是云资源和存储的主要提供商之一,也是面向各种终端用户的可访问解决方案。 Google Drive 和 Sheets 是 Google Workspace(前身为 GSuite) 的热门服务部分,也是处理表格数据和存储文件的主要工具之一。谷歌还通过其谷歌云平台(GCP)为企业提供云服务。云存储是一种用于存储文件的 GCP 服务(类似于 AWS S3)。

这些服务允许用户在涉及数据产品、分析和数据科学的项目中进行协作。因此,学习如何使用每个工具的正确特性可以帮助您的团队开发涉及数据共享的最佳实践。

3.加载公共文件

一些涉及数据的项目可能要求您公开您的数据集,以便其他人可以访问它。科学期刊、政府、非政府组织和许多其他机构可能需要提供对数据的开放访问,因此下面描述的工具是访问存储在 Google Sheets 或 Drive 中的开放数据的替代方法。

3.1.谷歌工作表

Google Sheets 是一个在线电子表格编辑器(类似于 Microsoft Excel ),允许用户处理表格数据。由于我们处理的大部分数据都是以表格的形式组织的,所以使用表格来组织和存储基本分析会非常方便。

要公开您的工作表文档,您需要点击共享>发布到 web

接下来,选择一个工作表和文档类型为逗号分隔值(。csv),并复制创建的链接。

函数read_public_sheets接收您刚刚创建的链接,并返回一个 Pandas 数据帧,这是将表格直接加载到 Jupyter 笔记本的一个很好的选择。

# Loading a Public Google Sheets as a Pandas Dataframe
sheet_url = '<url to a Google Sheets>'df_sheet_public = read_public_sheets(sheet_url)

3.2.Google Drive

Google Drive 是存储任何文件格式的绝佳存储解决方案。公开可用的数据集可以以不同的格式找到,如 csv、xlsx、json 或 parquet。要访问文件,请打开 Google Drive 文件夹,右键单击所需文件,单击获取链接,选择选项任何有链接的人,然后复制创建的链接。

函数read_public_file_from_gdrive接收存储在 Google Drive 中的文件的复制 URL,并返回一个 Pandas Daframe(对于 csv 或 xlsx 文件)或一个字典(对于 json 文件)。

# Example on how to load a CSV file from Google Drive
link_to_csv = '<url to a Google Drive file>'df_public_csv = read_public_file_from_gdrive(
    link_to_csv,
    "csv"
)

4.加载私有文件

由于公司内部共享的大多数数据文件都是私有的,为了防止数据泄露,您还需要使用某种身份验证来访问这些文件。

在本节课中,我们将了解如何访问谷歌云服务来获取不公开的文件。

4.1.谷歌工作表

我们将使用gspreadPython 模块与 Google Sheets 进行交互。为了访问私人文件,首先,你需要定义你的凭证。请遵循官方文件上的说明。使用您的服务凭证下载 JSON 文件后,您还需要将服务帐户电子邮件添加到 Sheets 权限电子邮件列表 ( 共享>添加人员和组)。

要运行函数read_private_sheets,您需要将路径传递给您的credentials_json、您的sheet_url和目标worksheet(名称或索引)。

# Loading a private Google Sheets
gcloud_credentials = '<path to service credentials JSON>'
sheet_url = '<url to a Google Sheets>'df_private_sheet = read_private_sheets(gcloud_credentials, sheet_url, 0)

4.2.Google Drive

要从 Google Drive 访问私有文件,我们可以使用 PyDrive2 ,这是一个 Python 库,它简化了与 Google Drive API V2 的交互。函数read_private_file_from_gdrive能够读取 5 种不同的文件格式(csv、xlsx、parquet、json 或 txt),您只需提供到它的链接(file_url,与会话 3.2 中描述的链接相同。)、file_formatgoogle_auth(凭证)。要生成访问 Google Drive 上私人文件所需的凭证,请遵循 Pydrive2 文档中描述的步骤。

from pydrive2.auth import GoogleAuth
from gcloud_data_analysis_functions import read_private_file_from_gdrive# 1\. Authenticate using OAuth2.0
gauth = GoogleAuth()
gauth.LocalWebserverAuth()# 2\. Access a private parquet from a Google Drive
file_url_parquet = '<url to a Google Drive Parquet>'
df_parquet_gdrive = read_private_file_from_gdrive(file_url_parquet, "parquet", gauth)

当你在#1上运行代码时,如果成功生成了凭证,就会显示一个指向谷歌账户认证的链接。选择您的帐户并允许其访问服务。

#2上,你只需要通过gauth (Google Auth Object),带着文件链接和格式,就可以加载想要的内容了。

4.3.谷歌云存储

云存储是在企业环境中存储/共享数据的一个很好的解决方案,因为它提供了一种安全的方式来定义用户对文件的访问。因此,尽管您可能将文件夹定义为公共文件夹,但下面的示例将描述如何使用 GCP 凭证加载私有文件。要创建一个 [gcp_credentials](https://developers.google.com/identity/protocols/oauth2?hl=en) json,请跟随官方页面。

函数read_file_from_gcloud_storage能够读取 5 种类型的file_format : csv、xlsx、parquet、json 或 txt。要定义要加载的特定文件,您需要提供file_namegcp_bucketgcp_project作为参数。

df_from_storage = read_file_from_gcloud_storage(
    "<file name>",
    "<file format>",
    "<bucket name>",
    "<GCP project name>",
    "<path to GCP credentials json>",
)

5.一锤定音

我希望您和您的团队都能从本文介绍的功能中受益,避免通过电子邮件或视频聊天软件共享数据文件。通过使用 Google 云服务共享您的文件,您可以提高跨团队的数据一致性,并帮助在您的公司内部创建数据安全性和意识。

如简介中所述,你可以在我的 GitHub 资源库中找到代码和一本 Jupyter 笔记本教程

如果您对所展示的主题有任何建议,请随时写信给我😉!

非常感谢你阅读我的文章!

  • 你可以在我的个人资料页面 找到我的其他文章🔬
  • 如果你喜欢它并且想成为中级会员,你可以通过我的 推荐链接 来支持我👍

不连续函数的积分与欧拉常数

原文:https://towardsdatascience.com/integration-of-discontinuous-functions-and-eulers-constant-44b4c61380d7?source=collection_archive---------19-----------------------

地板函数有反导数吗?

图片来自维基共享资源

介绍

最近我一直在研究更多的实验数学。

提出一些不标准的东西总是令人兴奋和有点伤脑筋的,从某种意义上说,严谨性可能不存在,或者数学界还没有接受它作为一个一致的数学理论,但尽管如此,我认为数学在某种程度上既是科学,也是艺术和创造力。

欧拉在真正理解复数之前欣然接受了负数的平方根拉马努金研究了对当时的数学家没有任何数学意义的发散级数,但这些结果后来被用于一百多年后的量子力学弦理论

我的观点是,有时候以一种非正式的方式来玩和实验数学是可以的。当然,归根结底,我们需要一个有效且一致的理论,并对定理进行严格证明。

在这篇文章中,我会给你一些有趣的想法,但最后,这个理论实际上是一致的,伟大的事情是我们可以将它应用到实际问题中,正如你将看到的。

我们将在文章的最后使用 Python 对结果进行数值验证。

基底函数和分数部分函数

在解析数论中,我们经常会遇到涉及底函数的级数和积分,因此定义如下:

表示为[x]的 x 的底等于小于或等于 x 的最大整数。因此它将向下舍入到最接近的整数。一些例子是[3.2] = 3 和[2/3] = 0。

在文献中,你有时会看到用略有不同的括号表示的底函数,但幸运的是,数学不依赖于符号,所以我们可以自由选择自己的。如果你正在用“纸和笔”阅读这篇文章,请随意使用你想要的任何东西。

另一个非常常用的函数是一个密切相关的函数,叫做小数部分函数。x 的小数部分表示为{x},定义为{x} = x - [x]。一些例子是{3.2} = 0.2 和{2/3} = 2/3。

请注意,这些函数不是连续的。地板函数的图形如下所示:

图片来自维基共享资源

如你所见,地板函数的图形在整数值处有“跳跃”,使得它在这些值处不连续。

小数部分函数的图形如下所示:

图片来自维基共享资源

同样,这个图在整数处有“跳跃”,但是如果你(在心理上)将这两个图加在一起,你几乎可以看到底函数的跳跃是如何用小数部分填充的,以创建恒等函数 f(x) = x

数论的应用

早先我说过这些函数在数论领域被大量使用,但是在哪里,为什么?

其中一个原因就是著名的阿贝尔求和。我给你公式,让你自己试着证明。

设 x > 1 为实数,且实函数 f 可微,则以下成立:

总和是 1 到 x 之间的所有自然数,包括 1 和 x。

一个小小的证据提示:

如果你想证明,试着把积分写成从[x]到 x 的整数区间上带小余积分的积分和,那么[t]因子在整个区间上是常数,可以从积分中抽出来。然后你使用微积分的基本定理,你会得到一个伸缩的和,有很多抵消。

你可以用很多方法证明这个结果,实际上这是一个更一般的定理的特例,但我们只需要这篇文章中的结果。

这个公式将和转化为积分,反之亦然,所以让我们尝试将其应用于一个非常有趣的和,即调和和。换句话说,让 f(t) = 1/t,让我们将阿贝尔求和公式应用于该函数。

我们用分数部分扩展了基底函数。现在我们注意到,有一个 ln(x) 在附近,我们可以把它拉到等式的另一边。

当极限值为 x 时,两边都趋于无穷大,我们得到了有趣的结果:

其中γ ≈ 0.5772…欧拉-马斯切罗尼常数。

欧拉-马斯切罗尼常数被神秘所包围,我们对它一无所知,尽管它在数论和分析中随处可见。

人们怀疑这个数字是先验的,但令人尴尬的是,我们甚至不知道它是否是无理数!

我知道你在想什么。至少我在想:如果我们能用两个被积因子 {t}1/t 做偏积分岂不是很棒?

不连续函数的“反导数”

现在,函数 f 的反导数是一个可微函数 F ,它的导数等于原函数 f 。因此,不连续函数的反导数是不存在的,因为它是不可微的。

然而,让我们想一想反导数的特征是什么,它们在部分积分技术中起什么作用。

实际上,我们不需要假设积分因子是连续的——只需要知道它是勒贝格可积的,所以如果我们能找到一个函数 f ,它将在几乎所有的点起反导数的作用(因此将给出图 f 下的面积),我们将能够在分部积分时以通常的方式使用它。

让我们更仔细地看看如何找到函数 f(t) = {t} 的图下面积公式,比如从 0x,其中 x 是某个实数。

作为练习,你现在可以自己尝试一下。

对此有两种主要的思考方式。在这种情况下,最简单的方法是从几何角度推导公式,因为当我们查看 {t} 的图表时,很明显,面积将是每个面积为 1/2 的三角形的面积之和。

剩余面积显然是 1/2 {x},因此我们的公式变成:([x] + {x} ) / 2 = ( x - {x} + {x} ) / 2。

然而,我们将采用另一种方法,因为我想向你们展示一种更通用的推导方法,因为在未来我们可能必须找到{t}的积分,这在几何上并不容易…

我们将利用这样的事实:在区间【n-1,n】上我们有{t} = t - (n - 1)。因此,我们可以把积分分解成具有整数端点的单位区间。具体来说,我们有

一般来说,我们可以使用这种技术,通过在积分中使用智能替换来计算小数部分的 n 次方:

用这种技术,我们可以对底函数做同样的计算,当尘埃落定,一些方程会从灰烬中升起。

这里我将陈述两个结果,即需要一些解释。但首先,让我陈述它们:

对于一些实数 C0C1

我这么说是什么意思?显然,这些函数是不可微的,所以它们不可能是经典意义上的反导数,因此我们可以认为这是对符号的一点滥用,但是这个符号在一段时间内会有意义。

以下是一些观察结果:

  1. 这些是实际的面积函数,也就是说,如果对积分进行定积分(从 ab 进行积分),并以通常的方式将这些函数用作反导数,那么我们可以得到两个图形下的面积,x 轴上方和下方的面积之间通常存在差异。
  2. 分数部分和底函数仅在一组离散的点,即整数上是不可微的。因此,它们实际上几乎在任何地方都是可微的(在 T2 测度论的意义上),因为微分是局部的(逐点的)运算,我们可以陈述如下:

我们只需要小心一点,因为微积分的基本定理不成立。如果我们想要这样的东西,我们将不得不使用狄拉克δ函数的无穷级数(分布理论),我们不需要这样。

但以上仍然是正确的,我们只是砍掉了一些点。因此,我们可以利用这一点来做部分集成。

请注意,这一切都完美地融合在以下内容中:

对于一些常数 C ,就像它应该的那样。

重温欧拉常数

那么现在我们有了一些工具,如何应用呢?

我们推导出了一个关于欧拉-马斯切拉诺尼 常数的公式,现在我们有了足够强大的武器来进一步进行计算:

这里我们使用了分部积分和 {x} 的积分公式。我们可以通过再次使用部分积分来进一步接近γ。如果你觉得无聊或者只是好奇,可以试一试。请告诉我你发现了什么。

数值分析

只是为了满足自己的好奇心,我在 Python 中做了一些数值积分。对于那些不知道如何用 Python 编码的人来说,这对于本文来说并不重要,但是对于那些知道的人来说,如果你愿意,你可以试一试。

让我们创建一个数字积分模块:

在一个单独的文件中,我们进行实际的计算。我们从上面的模块中导入 Integrate 类,并定义分数部分函数和被积函数。然后,我们将结果打印到控制台。

我们得到大约 0.5772154… 考虑到真实值从 0.572156649 开始,这一点都不差…

如果增加精度或上限,您将获得更好的近似值,但是,运行时间也会增加。

这在数值方法中总是一个折衷。当然,没有什么能打败纯数学。然而,数字验证可能是一个很好的指导。

这是这个故事的结尾,但是更多的故事还在后面。

如果你想了解我的研究和写作过程,想“先睹为快”未来的故事,想了解我更私人的一面,请在 Instagram 上关注我:

点击下面的图片找到我的简介。

作者图片

如果您有任何问题、意见或顾虑,也欢迎通过 LinkedIn 联系我:

https://www.linkedin.com/in/kasper-müller-96ba95169/

数学家是把咖啡变成定理的机器。

阿尔弗雷·德·雷尼

情报服务和自然语言处理

原文:https://towardsdatascience.com/intelligence-services-and-natural-language-processing-926b18736796?source=collection_archive---------36-----------------------

对象角色建模中的派生事实类型

很容易想象一个情报机构问一个收集情报的知识图表这样的问题:

自然语言智能查询。图片作者。

这种类型的查询的问题是,根据下面的实体关系图,数据库可能只存储某人在某个日期访问某个国家的事实,而不是在哪个时间段内:

实体关系图。图片作者。

要回答这个问题,需要做一些数学计算。我们需要说明以下几点:

过去几个月内访问过的国家/地区月份
是指人员在日期
和今天——日期<期间月份* 30 访问过的国家/地区

输入对象角色建模和派生事实类型

对象-角色建模 (ORM)是一种概念建模,它有一种事实类型,称为派生事实类型。派生的事实类型允许您定义涵盖这些事实类型的事实的算法/公式。

例如,在我们的例子中,我们将如下定义一个派生的事实类型:(即在读数'…visited…with the last…* '中用星号表示的事实类型):

具有派生事实类型的对象-角色模型。图片作者。

星号让您知道有一个公式与派生的事实类型相关联(如右侧所示)。不需要为派生的事实类型创建数据库中的表…它们的事实是存储在其他表中的事实的派生。

现在当我们问“哪个人…在过去(PeriodMonths:10)内访问过(Country:'Adjikistan ')”使用 ORM 的知识图上的查询引擎知道使用派生的事实类型及其公式来查找在特定日期和“今天—(那)日期< PeriodMonths * 30”访问过 Adjikistan 的那些人。

人工智能的含义

即使只看最初的查询,也很容易认识到,如果我们不得不查阅自己的内部记忆,我们需要做一些心理体操,看看我们知道哪些人住在悉尼,在某个特定日期去过阿吉基斯坦,然后计算该日期是否在过去 10 个月内。

也就是说,人类很自然地使用我们自己内部衍生的事实类型的等价物来做这种类型的数学。对我来说,任何未来合适的处理自然语言查询的人工智能都必须有能力将人工智能形成的查询的某些部分传递给适当的数学函数,其方式类似于派生事实类型的使用。

在早期的一篇文章中,我描述了主人工智能之外的小程序,作为应用专业智能(ASI)服务,人工智能利用它们来解决更广泛的人工通用智能范围内相对简单的问题。绑定到查询中的派生事实类型类似于那些 ASIs。

自然语言数据库查询的体系结构

早先我描述了一个基于 TDS 的架构,用于在标准数据库管理系统上应用自然语言查询。表面上,人们在现有的数据库技术上应用知识图的模型,而不必有专门的知识图数据库,使用对象-角色建模作为数据库上的语义/知识模型层。

如果我们考虑替代方案,这种技术的好处就显而易见了。例如,如果我们使用 SQL,我们简单的一行查询就变成了相当复杂的 SQL(结构化查询语言)查询,如下所示:

选择[人员]。名字,[人]。LastName
FROM [Person],
【Country】,
(SELECT Person_Id,Country_Name,Date
FROM personvisiteddcountryondate
WHERE julianday(' now ')—julianday(Date)<10 * 30)AS personvisiteddcountrywithinthelastpiolmonthsmonths months
WHERE[personvisiteddcountrywithelastpiolmonthsmonths months]。Person_Id=[Person]。Person_Id
和[personvisiteddcountrywithinthelastperiodemonthsmonths]。国家名称=[国家]。国家名称
和【国家】。Country_Name = 'Adjikistan '

我知道,为了我的钱,我更愿意将查询写在这篇文章的顶部。

难题…用一种语言代替另一种语言

在知识图数据库架构中,派生事实类型允许以简单的受控自然语言在数据库上执行非常简单的查询,但是有一个难题。

我们有效地做的是用一套函数/公式编程(例如软件代码或 SQL)代替另一套编程。也就是说,在派生事实类型语言中为派生事实类型定义公式是一项必须完成的工作,就像在 SQL 中需要完成的一样。

这个难题在信息技术和数据科学中一直存在,不同的语言适合不同技能的人。然而,使用具有派生事实类型的对象-角色模型知识图的好处是,如果它在现有数据库技术(如 ORACLE)上运行,那么最终用户可以选择…他们可以使用自然语言(使用正确的工具) 查询数据库,使用类似 SQL 的语言。因此,开发人员需要权衡的是,他们的客户是需要在 SQL 中快速生成一个肮脏的查询,还是创建一个派生的事实类型来回答最终用户在许多不同情况下可能会多次询问的自然语言查询类型。

可以说,创建派生的事实类型比编写 SQL 更容易,情报服务专业人员可能更喜欢用易于使用的受控自然语言来查询他们的情报数据库。

情报服务愿景

在科幻电影的领域中,询问智能代理计算机系统并让它理解你所说的话的能力在现实中并不遥远。原因是因为投入到问题空间的努力量。

就在几年前,与智能手机交谈似乎还不合时宜,但俗话说,人工智能技术一好就很快变得无聊。语音识别现在是如此普遍,以至于它看起来是一项无聊的技术。以同样的方式,有大量的研究进入自然语言查询处理,我认为用不了多久,它就会显得过时了。至少这个愿景激励着我的研究…

最新研究

派生的事实类型在我开发的工具中相对较新,但对于对象-角色模型数据库的概念化来说却是旧闻。上面提到的难题对于开发人员来说也是一个难题…虽然遵从数据库管理系统的查询引擎(例如 SQL 查询引擎)的公式处理能力可能很容易,但是必须首先为派生的事实类型语法开发一个合适的解析器。所以这是鸡和蛋类型的工作。

没有为派生事实类型的语法发布 ORM 标准,语法需要从头开始开发。

幸运的是,除了数学公式之外,派生事实类型语法很大程度上可以用同样的受控自然语言编写,这种语言可以首先使用对象-角色建模谓词来形成,因此这是一个应用 ASI 愿景的问题……将派生事实类型视为 ASI,并将它们作为查询中的查询进行投影。

例如,在下面的模型中,考虑兄弟的派生规则:

具有派生事实类型的对象-角色模型。图片作者。

构成兄弟的定义在语法上与我们查询知识图的方式没有什么不同,如下所示:

点击放大。自然语言查询。图片作者。

哪个人 1 是居住在(城市:“悉尼”)的人 2 的兄弟姐妹,并且那个人 1 在过去(周期月数:10)内访问过(国家:“阿吉基斯坦”)

所以派生的事实类型公式语法与更广泛的查询语言本身没有太大的不同。

我发现这项工作很有意思,并期待更多关于派生事实类型和使自然语言查询更容易的工作。

感谢您的阅读,如果时间允许,我会写更多关于对象角色建模、派生事实类型、自然语言查询和知识图的内容。

— — — — End — — — — —

智能裁剪页面旁注

原文:https://towardsdatascience.com/intelligently-cropping-page-marginalia-ab04744a1111?source=collection_archive---------21-----------------------

在本文中,我将向您展示如何编写代码来自动裁剪文档的页面旁注,以处理用于光学字符识别(OCR)的图像。

更新:帖子的第二部分是 这里是

编辑:我错误地将这个过程称为“预处理”,而它应该被称为“后处理”或者仅仅是“处理”。

OCR 前的图像处理方法。【图文由作者提供;第三版。(波哥大:奥利韦里奥·佩里&中央情报局。, 1961)]

有几种方法可以在将图像输入到 AWS Textract 或 Tesseract 等 OCR 软件之前对其进行处理,使页面上的文字成为计算机可读的文本。你使用的方法很大程度上取决于你所拥有的图像质量。下面是一个不完整的列表:

  • 二值化—将图像转换为黑白像素,以增加文本和背景之间的对比度
  • 倾斜校正—旋转图像,使文本以整齐的水平行显示
  • 透视扭曲—修复实际图像和捕获图像之间的扭曲
  • 裁剪—删除图像中我们不想阅读的部分,并简化图像,以便 OCR 软件“阅读”

对于这些问题,已经有几种解决方案,但是裁剪页面旁注(页眉和页脚)是很困难的。并非所有页面都以相同的方式扫描,从而导致不同的页面方向和清晰度。页面旁注也不总是在同一个位置或具有一致的文本,这使得在 OCR 后很难删除。

一个例子,我们希望如何理想地裁剪一页。【图文由作者提供;第三版。(波哥大:奥利韦里奥·佩里&中央情报局。, 1961)]

上面的照片是你理想的裁剪扫描图像的方式。本质上,我们定位页眉或页脚和正文之间的空间,以及每列文本之间的空间,并说“我要在这里裁剪它”。但是我们不希望手动处理成百上千或上百万的文档。这需要很长时间,如果有自动化的流程,为什么还要自己做呢?

用于 OCR 的图像处理方法。【图文由作者提供;第三版。(波哥大:奥利韦里奥·佩里&中央情报局。, 1961)]

我的方法是教计算机“看”图像,就像我在上图中所做的那样。将图像二值化后,图像的每个像素变成黑色或白色,分别用数字 255 和 0 表示。当我们看图片时,我们在寻找一条水平的白色像素带,它代表了页眉和文本之间的空间。

下面的代码片段从图像顶部开始查看 30%的水平像素行。它计算每行像素之间的百分比差异,并允许来自低质量图像或随机斑点的少量噪声。然后,它识别最长的连续白带,并在中心裁剪它。这个过程依赖于已经被倾斜校正和二进制化的图像,所以请查看链接的解决方案。

故障排除——啊哦,这种作物偏离太远了

一旦您有机会在一些图像上测试该代码(我强烈建议在浏览所有图像之前),如果图像裁剪不如您想象的那样好,请确保:

  • 所有图像中的文本都是水平的
  • 你已经选择了正确的像素窗口来查看

我希望这个解决方案已经节省了你的时间,并教你如何处理图像!

为数据科学家在 Django 3 中交互数据

原文:https://towardsdatascience.com/interact-data-in-django-3-for-data-scientists-952b308fb0a8?source=collection_archive---------25-----------------------

斯蒂芬·斯坦鲍尔在 Unsplash 上拍摄的照片

文章一览:

  • Django 3 简介
  • 作为数据科学家,您可能会遇到哪些情况?
  • 如何使用分步指南和示例代码运行迁移
  • 如果您知道 SQL,如何运行 Django 查询

谁是代表:数据科学家,他们希望将您的代码插入到您的组织代码库中,该代码库是基于 Django 的。

在我开始分享我对 Django 3 的了解之前,我想提一下为什么我需要快速学习 Django。我在之外的一家名为的公司工作,我的主要工作是建立推荐系统来个性化用户的内容消费。两个月前,我们决定将 web 开发框架从 FastAPI 改为 Django。在我们开始这个项目之前,我对 FastAPI 的了解非常有限,我学到的知识足以成功实现数据科学算法部分。但是随着新的变化,我需要快速进化,将我的代码移植到 Django 框架中。

旁注:作为一名数据科学家,你可能已经看过著名的数据科学维恩图并为之苦恼,在该图中,你需要精通数学统计、计算机科学和领域专业知识,尤其是如果你想成为独角兽的话🦄。在我的个人职业发展中,我注意到,除了深化数据科学和机器学习知识之外,我的工作要求我主要在两个领域拓展技能:

  1. Web 开发:如果你在一家开发面向消费者的应用程序(Web 和/或移动)的初创公司工作,你很可能会遇到这样的问题——我们如何将数据科学模型部署到应用程序中?如何在 API 中包装模型?等等,REST API 和 GraphQL 有什么区别?什么是阿波罗和联邦数据?事实上,为了将我的代码集成到更大组织的代码库中,这些都是我需要解决的问题。
  2. 数据工程:您的组织很可能会有专门的数据工程师来处理生产数据库,但您绝不会后悔扩展您的技能组合,包括设计表格、数据库迁移、非常熟悉如何将雪花、Postgres 和 Redshift 连接到 PyCharm 和 Jupyter Notebook。

好了,足够的背景故事,让我们开始姜戈。

Django 3 简介

一行解释:Django 3 是一个 python web 开发框架。

什么是 web 框架?我制作了这个图表来说明 Django 模型视图模板(MTV)范例。

图片由杨文拍摄

基本上,客户端发送一个 HTTP 请求,它被传递给urls.py,这有助于将请求映射到适当的视图。views.py就像一个请求句柄,它可以使用模板以正确的方式访问数据和组织数据,然后将其作为 HTTP 响应发送回来。

这就是我们所需要知道的,我告诉过你它会很“简短”。🍃

让我们转到更有趣的问题→

作为数据科学家,您可能会遇到哪些情况?

从我个人的经验来看,您很可能需要知道如何正确地将您的代码插入到models.py中,它允许您指定数据的模式并在数据模型类中编写定制的函数。

例如,下面是一个名为ContentItem的数据类,就像我们从 SQL 中的表创建开始模式设计一样,我们为每个列或数据字段定义了一个具有预期数据类型的类。

有几件事值得注意:

  1. 如果您没有创建一个id列,Django 会自动将它添加到实际的表中
  2. 如果你想为列tags创建一个列表,例如,在一个单元格中存储像【新闻,自行车,冬天】这样的东西,你可以使用ArrayFieldmodels.CharField意味着在列表内部,每个元素都是一个字符串。
  3. Django 中的数据字段遵循非常类似 SQL 的列约束。

列约束是应用于单个列的值的规则:

PRIMARY KEY约束可用于唯一标识行。

UNIQUE每一列都有不同的值。

NOT NULL列必须有值。

DEFAULT未指定值时,为列指定默认值。

每个表只能有一个PRIMARY KEY列和多个UNIQUE列。例如,当我们在 Django 中创建ContentItem类时,自动生成的id将成为PRIMARY KEY列,并且我们将item_urlitem_uuid都指定为UNIQUE列。

一旦有了数据模型类,就需要运行数据迁移来将模式应用到新表中。

如何在 Django 中运行迁移?

步骤 1:假设您在同一个项目环境中,打开 Pycharm 终端,运行

$ python manage.py makemigrations

然后,一个新的迁移文件将被自动填充,类似于0018_auto_...py,因为已经存在 17 个迁移,我的被表示为0018。通常,您不必编辑该文件中的任何内容。

步骤 2:通过运行以下命令将迁移文件应用到您的数据库

$ python manage.py migrate

更多细节可以在 Django 的官方文档中找到。

如果您知道 SQL,如何运行 Django 查询

对于大多数数据科学家来说,幸运的是我们知道 SQL。并且 Amit Chaudhary 写了一篇精彩的帖子关于如何在 Django 中执行我们典型的 SQL 任务。

既然他抢先我写了这个,我就补充一个需要注意的事情:小心什么时候对 QuerySets 求值(摘自本书< Django 3 By Example >第 1 章):

" QuerySets 仅在下列情况下进行评估:

-第一次迭代时

——当你把它们切片的时候,比如说,objects.all()[:3]

-当你腌制或储藏它们时

-当你在上面呼叫repr()len()

-当你在它们上显式调用list()时"

如果您希望在函数中使用 QuerySet 的输出,这将变得非常重要。

如果你想了解更多关于 Django ORM 的信息,还有一个很棒的媒体帖子。

结束语

  1. Django 是一个强大的 web 开发工具。而作为数据科学家,我们可以向两个方向拓展:前端←数据科学→后端。学习 Django 可以增强我们的前端和后端知识。本文中的例子更多地与后端相关,但是在现实生活中,在添加了表和迁移之后,我还需要创建定制的函数并更新前端 API——graph QL 中的解析器。
  2. 我发现自己使用的一个典型的重构工作流程是:更新models.py →运行迁移→运行数据摄取任务→更新schema.graphql →更新graphql.py中的解析器函数
  3. 我对 Django 的理解仍然非常有限,在一般的 DS 工作中,用例可能太窄了。但是如果你碰巧在相似的环境下处理相似的问题,我希望这能有所帮助,哪怕只是一点点。

参考

  1. SQL 上的 codecademy cheat sheets:https://www . codecademy . com/learn/becp-SQL-for-back-end-development/modules/fscp-SQL-creating-updating-and-deleting-data/cheat sheet
  2. 书籍:《Django 3 举例》——第三版,作者安东尼奥·梅尔

交互式动画可视化

原文:https://towardsdatascience.com/interactive-animated-visualization-db91d1c858ad?source=collection_archive---------18-----------------------

使用 AnimatPlot 制作图形和绘图动画

来源:作者

数据可视化有助于理解不同的模式、关联、来自数据的视觉洞察等。它很重要,因为它以图表、图形和绘图的形式揭示了数据表背后的奥秘。有 N 个 python 库可以帮助可视化数据,如 Matplotlib、Seaborn 等。

如果我告诉你,你可以动画化你的视觉效果呢?挺有意思的吧!如果你能做到这一点,那该多好啊。让我们揭开这背后的秘密,并了解我们如何才能动画我们的常规情节。

AnimatPlot 是一个基于 Matplotlib 构建的开源 python 库,用于创建高度交互式的动画情节。在本文中,我们将探索 AnimatPlot 提供的一些功能。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装 AnimatPlot 开始。下面给出的命令可以做到这一点。

!pip install animatplot

导入所需的库

在这一步中,我们将导入创建动画图所需的库。

%**matplotlib** notebook
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
**import** **animatplot** **as** **amp**

创建数据集

这里创建的数据集将创建一个正弦波,然后我们将制作这个正弦波的动画。类似地,我们也将另一个数据集用于在单个图形中显示多个图。

x = np.linspace(0, 1, 50)
t = np.linspace(0, 1, 20)

X, T = np.meshgrid(x, t)
Y = np.sin(2*np.pi*(X+T))

创建动画情节

这是最后一步,我们将创建情节和动画。

block = amp.blocks.Line(X, Y)
anim = amp.Animation([block])
plt.show()

来源:作者

现在,我们将向绘图添加控件。

timeline = amp.Timeline(t, units='s', fps=20)
block = amp.blocks.Line(X, Y)
anim = amp.Animation([block], timeline) 
anim.controls()
plt.show()

来源:作者

同样,现在我们将添加更多数据,并在单个图表中创建多个图。

x = np.linspace(-2, 2, 41)
y = np.linspace(-2, 2, 41)
t = np.linspace(0, 2*np.pi, 30)
X, Y, T = np.meshgrid(x, y, t)
data = np.sin(X*X+Y*Y-T)
line_data = data[20,:,:] fig, (ax1, ax2) = plt.subplots(1, 2)
for ax in [ax1, ax2]:
    ax.set_aspect('equal')
    ax.set_xlabel('x')ax2.set_ylabel('y', labelpad=-5)
ax1.set_ylabel('z')
ax1.set_ylim([-1.1,1.1])fig.suptitle('Multiple blocks')
ax1.set_title('Cross Section: $y=0$')
ax2.set_title(r'$z=\sin(x^2+y^2-t)$')line_block = amp.blocks.Line(X[0,:,:], line_data,
                                   ax=ax1, t_axis=1)
block = amp.blocks.Pcolormesh(X[:,:,0], Y[:,:,0], data, ax=ax2, t_axis=2, vmin=-1, vmax=1)
plt.colorbar(block.quad)
timeline = amp.Timeline(t, fps=10)
anim = amp.Animation([block, line_block], timeline)
anim.controls()
plt.show()

来源:作者

在这里你可以看到我们是如何创建动画情节并为其添加互动的。

继续尝试不同的数据,并创建一个动画可视化。如果您发现任何困难,请在回复部分告诉我。

本文是与 Piyush Ingale 合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时联系我在 hmix13@gmail.com 或我的 LinkedIn 简介 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

用于地理空间数据可视化的交互式地形图

原文:https://towardsdatascience.com/interactive-choropleth-map-for-geospatial-data-visualization-a53688c8ef21?source=collection_archive---------31-----------------------

斯特凡诺·瓦尔托塔在 Unsplash 上拍摄的照片

详细教程

地理空间数据可能很有趣。一个交互式地理空间可视化提供了关于数据和区域等的大量信息。Python 有这么多库。很难知道用哪一个。对于地理空间可视化,我将使用叶子。这是非常容易使用,它有几种风格,以及符合您的选择和要求。我们开始吧。

为此,我使用了 Jupyter 笔记本环境。如果您使用的是 Jupyter 笔记本,那么您需要使用 anaconda 提示符,使用以下命令来安装 lyum:

conda install -c conda-forge folium=0.5.0 — yes

或者请查看文档。我用的是 windows。

现在我们可以在笔记本中导入叶子了。叶子内置了世界地图。

import folium
folium.Map()

这是世界地图。如您所见,您可以放大、缩小和导航。你可能想要某个国家、州或城市的地图。该特定地点的纬度和经度可以作为参数提供,以获得该特定地点的地图。我想打印佛罗里达地图。

folium.Map(location = [27.664827, -81.516], zoom_start = 4)

在这里你可以看到佛罗里达州。我把 zoom_start 设为 4。在您的笔记本中,您可以放大或缩小并导航到某个部分。但是你也可以从放大开始。

florida = folium.Map(location = [27.664827, -81.516], zoom_start = 7)

让我们看看不同的风格。制作高对比度的黑白地图。可以通过使用参数瓦片来实现。对于高对比度的黑白地图,拼贴将是“雄蕊调色剂”。

folium.Map(location= [27.665, -81.516], zoom_start = 8, tiles = 'Stamen Toner')

是不是很好看!这种类型的地图非常适合沿海地区。对数据混搭也有好处。

在我的下一个例子中,我将使用雄蕊地形图。这将显示自然植被和山丘阴影。

folium.Map(location= [27.665, -81.516], zoom_start = 4, tiles = 'Stamen Terrain')

我相信你有兴趣看看我们能否在地图上标出事件或事故。我们当然可以。为了演示,我将使用一个数据集来显示佛罗里达州的事件。请随意从这里下载数据集:

https://github.com/rashida048/Datasets/blob/master/Florida_Subsidence_Incident_Reports.csv

将数据集导入笔记本。

import pandas as pd
florida_incidents = pd.read_csv('Florida_Subsidence_Incident_Reports.csv')

数据集太大。所以我没有在这里显示截图。但是数据集有一个 X 和 Y 列,它们是佛罗里达不同位置的纬度和经度。我们可以将这些位置放在地图上,创建一个要素组。我们将包括点的位置和样式。为了图像的清晰,我将只放 100 个数据点。

florida_incidents = florida_incidents.iloc[0:100, :]
florida = folium.Map(location= [27.665, -81.516], zoom_start = 7)
incidents = folium.map.FeatureGroup()
for lat, lng, in zip(florida_incidents.Y, florida_incidents.X):
    incidents.add_child(
    folium.features.CircleMarker(
    [lat, lng],
    radius=5,
    color='yellow',
    fill=True,
    fill_color='blue',
    fill_opacity=0.6))florida.add_child(incidents)

我们可以更进一步,在这些点上添加标记。

latitudes = list(florida_incidents.Y)
longitudes = list(florida_incidents.X)for lat, lng in zip(latitudes, longitudes):
    folium.Marker([lat, lng]).add_to(florida)
florida.add_child(incidents)

随意放大并导航以查看特定县或城市的事件。

结论

我试图展示如何生成一个交互式地图,用标记在上面呈现一些事件或事件,并对其进行样式化。这种类型的交互式地图在仪表板、演示文稿或任何其他呈现的信息中总是很有帮助。我希望这有所帮助。

请随时在 Twitter 上关注我。

更多阅读

[## 熊猫总结数据的三个非常有用的功能

towardsdatascience.com](/three-very-useful-functions-of-pandas-to-summarize-the-data-491b64db9370)

由 Julia 支持的交互式加密仪表板

原文:https://towardsdatascience.com/interactive-crypto-dashboard-powered-by-julia-fd6f60f23063?source=collection_archive---------27-----------------------

可视化历史市场数据的有趣方式

Bermix 工作室Unsplash 拍摄的照片

首先,非常重要的一条免责声明:本教程仅用于教育目的,不应被视为交易建议。加密货币市场非常不稳定,你很可能会失去你的投资。在决定交易本文中讨论的任何加密货币之前,请了解风险并做好自己的研究。

在此之前,我已经探索了 Julia 在新冠肺炎数据可视化中的应用。我们在该教程中制作的情节很有见地,尽管交互性有限。我最近得知 Dash 宣布支持 Julia,因此决定尝试一下。Dash 使用基于 react 的框架,允许我们构建可扩展的 web 应用程序。Python 和 R 用户必须已经熟悉 Dash 生态系统。现在,有了 Dash.jl,我们终于可以利用 Julia 作为 web 应用程序的强大后端了。

简单来说,本教程的重点是构建一个应用程序,允许用户监控历史价格数据,并计算各种加密货币的一些关键技术指标。我选择这个用例,部分原因是我对区块链技术公司的兴趣,以及过去几个月发生的所有令人兴奋的价格行为。这种分析当然也可以用于股票市场数据。

我们开始吧

我使用 VS 代码,为此你需要安装和配置 Julia 扩展。这相当简单,详细说明可以在这里找到。你也可以直接从朱莉娅·REPL 那里运行这个应用程序。克隆这个存储库并遵循其中给出的说明。所有相关的软件包都将自动安装。如果您确实使用 VS 代码,您可以通过单击窗口的左下角(Julia env 按钮)来选择 Julia 环境,然后从顶部面板中选择位置(CryptoDashApp 目录)。我使用的是 Julia 1.6.0,该应用程序也可以在旧版本上运行(在 1.5 和 1.4 上测试)。但是,我强烈建议升级。

获取市场数据

我们需要一种方法来访问许多加密货币的历史市场数据。币安和比特币基地等热门交易所通常为此提供 API。然而,用它们创建一个帐户是很繁琐的,更不用说这些 API 大多数都是基于 Python 的。令人欣慰的是,有许多其他市场数据提供商也提供免费访问,但有一些限制。Alpha Vantage 就是这样一个选择。向 Dean Markwick 大声欢呼,他创造了 AlphaVantage.jl 包,我们将在我们的应用中使用它。点击这里,获取免费的 API 访问密钥。请注意,API 调用的数量被限制为每分钟 5 次,每天 500 次请求(对于我们的应用程序来说已经足够了)。我们将尝试用一些变通方法来规避前一个限制。

项目目录

所有相关代码都可以在这里找到。的。toml 文件位于主目录中,该目录与模块同名。应用程序配置选项位于模块文件“CryptoDashApp.jl”中,其余的 Julia 函数也位于“src”目录中。我们将下载当前日期的市场数据并保存到“数据”文件夹中。为了避免混乱,我们的应用程序还将通过删除以前日期的数据文件来执行清理操作。参见下面的代码要点:

删除除当天之外的数据文件

使用 Alpha Vantage API

我们将创建各种助手函数来检索市场数据并将其转储到 Julia 数据框架中。如果你不熟悉数据框架或者需要一个快速介绍,这里有一个方便的指南。由于 API 调用的数量有限,我们只想在给定的一天为给定的加密货币检索一次数据。因此,第一步是检查数据文件是否已经存在,如果不存在,我们下载并保存到磁盘。这在函数 get_price_data_single 中实现,如下所示:

将当前日期的数据下载并保存到磁盘

如果您仔细观察上面的代码片段,我们还对通过 API 调用直接获得的“原始”数据进行了一些后处理。为此,我们使用了函数 raw_to_df ,它创建了一个漂亮的数据帧,每行表示一天,列名表示相应的数据类型。

将原始数据转换成可读性更强的数据框架

在 REPL 中,生成的数据帧应如下所示:

数据框架中可用的 ETH 市场数据

为了获得给定一天的平均数据,我们简单地取前四列(开盘、盘高、盘低、收盘)的平均值。这四列也为生成烛台图提供输入。体积数据通过体积列获得。这些操作被归入函数 average_price_dfvol_df :

将平均价格、蜡烛图和成交量数据分组到单独的数据框架中

以上都组合到前面展示的函数 get_price_data_single 中,可以针对任何给定的加密货币调用,并返回单独的数据帧。可以对另一组指标执行类似的操作,这些指标告诉我们资产的市场健康状况。在加密货币的情况下,它们是用户活动、开发者行为和市场成熟度,由 Flipside Crypto 提供。函数 get_ratings_data 返回这些指标。

计算移动平均值

移动平均线是一个重要的技术指标,交易者经常使用它来做出买入/卖出的决定。三个最重要的是简单移动平均线(SMA),加权移动平均线(WMA)和指数移动平均线(EMA)。我就不赘述了,你可以查看这个链接获得额外解释。我们计算所有三个(检查函数移动平均线),并将它们与日平均价格数据一起绘制。可以从网络界面选择所需的平均窗口。

绘图数据

我们使用 PlotlyJS.jl,它是 plotly.js 库的 Julia 接口。为了将数据传递给绘图函数,我们需要从我们的数据帧创建 PlotlyJS 跟踪对象。参见函数 plot_price_vol_data 的示例:

为价格和交易量数据创建 PlotlyJS 跟踪对象

这些跟踪将在回调中使用(稍后显示)! run_app 函数内的部分。

构建 Dash 应用程序

该应用程序的 UI 包括:(1)下拉列表(选择给定的加密货币或选择绘图模式)(2)复选框(选择平均窗口或时间框架以显示历史数据)。这些元素可以很容易地添加,如下面的代码要点所示:

设置 UI 元素的标签和范围

每次用户与应用程序 UI 交互时,都会触发一个回调,该回调将更新输入(考虑数据持续时间、平均窗口等。)到我们的绘图功能。

run_app 函数中的回调部分

生成的新图随后显示在浏览器窗口中。查看 CryptoDashApp.jl 中的 run_app 函数,看看所有这些是如何组合在一起的。

使用应用程序

CryptoDashApp GitHub 页面上给出了如何使用该网络应用的说明。总结一下,你需要:(1)在这里获取一个免费的 API key(2)克隆 repo (3)激活并实例化环境下载所有必要的包(只在第一次需要!)(4)向‘run _ app’函数提供端口号和 API 密钥。(5)转向连杆-1连杆-2

如果一切顺利,您应该会看到如下内容:

过去 180 天 BTC 价格数据的日平均+ SMA、WMA 和 EMA (10 天窗口)

复选框的第一行控制用于计算各种移动平均值的平均窗口,而第二行控制应选择显示的历史数据的持续时间(以天为单位)。更改模式(第一个下拉列表)将允许您查看一组不同的数据。参见下面以太坊(ETH)的示例:

ETH 过去 180 天的烛台和成交量数据

随着 ETH 价格的上涨,交易所开始出现更多的交易活动。这可能是为什么 ETH 的日均交易量在 2021 年 1 月至 2 月期间出现增长的原因。然而,在 2021 年 3 月的大部分时间里,交易量相对较低。这可能意味着更多的投资者持有(保持冷静和 HODL!)放在他们的钱包里,而不是把它转移到/转移出交易所。莱特币(LTC)数据显示了类似的行为,交易量的增加与价格行为相关,见下文:

过去 270 天 LTC 的烛台和成交量数据

您还可以通过从第一个下拉列表中选择模式来检查 LTC 的 FCAS 数据。它显示了“有吸引力”的总体评分,因为平均分数在 750-899 之间(更多信息)。这一点也不奇怪,因为 LTC 是一个相当成熟的项目,已经存在了很多年。

FCAS 长期资本评级

这些图是交互式的,这意味着您可以将光标悬停在数据点上以查看它们的值,还可以放大到特定区域。还有一个选项可以将绘图下载为 png 文件。通过单击图例,您可以关闭该数据的显示,这在您希望仅查看特定类型的数据时非常有用,如下所示:

过去 180 天 ETH 的日平均+ EMA 数据

结论

Dash.jl 提供了一个易于使用的框架来开发基于 Julia 的可伸缩的 web 应用程序。官方的 Plotly 教程也是一个很好的起点。我喜欢做这个练习,并将继续探索更多有趣的用例。与此同时,如果你有自己的想法,可以在这个应用上自由开发。完整的代码可以在这里找到。感谢你花时间阅读这篇文章!如果你想联系,这是我的 LinkedIn

参考

  1. https://github.com/vnegi10/CryptoDashApp.git
  2. https://dash-julia.plotly.com/
  3. 另一个 web 应用可视化新冠肺炎数据的好例子:https://github.com/mbauman/CovidCountyDash.jl.git
  4. https://www.alphavantage.co/documentation/
  5. https://DM 13450 . github . io/2021/03/27/cryptoalphavantage . html

构建一个可视化新冠肺炎数据的 Streamlit 应用

原文:https://towardsdatascience.com/interactive-dashboard-in-streamlit-to-analyse-owid-covid-19-data-180b1c3372e4?source=collection_archive---------32-----------------------

埃德温·胡珀在 Unsplash 上的照片

语境

我们的数据世界 (OWID)是一个开源的在线研究出版物。他们拥有广泛的公共数据集,涵盖疾病、气候变化、社会不公和贫困等主题。

我们工作的目标是让大问题上的知识变得容易理解。我们的数据世界是关于研究和数据的,以针对世界上最大的问题取得进展。

因此,当您发现 OWID 在他们的 GitHub 存储库中托管了大量新冠肺炎数据集时,您不会感到惊讶。

我采用了他们的一些新冠肺炎数据,着手开发一款能够让用户可视化和分析新冠肺炎数据的 Streamlit 应用。特别重要的是,用户能够与数据进行交互,从而进行定制分析并回答以下问题:

  • 人口密度和总病例数有关系吗?
  • 哪些国家在疫苗接种方面领先,哪些国家落后了?
  • 什么特征与死亡最密切相关?

我希望它看起来很容易,所以是我完成这项任务的首选图表库。我特别想制作一些可视化的动画,Plotly 是少数几个能以代码高效的方式做到这一点的库之一。

最终的 Streamlit 已经部署,您可以在下面的链接中找到它,但我想介绍一下我构建它的一些关键步骤,并谈谈在整个开发过程中的一些想法。

https://share . streamlit . io/kitsa mho/新冠肺炎数据/covid_streamlit_app.py

我们可以访问哪些数据?

照片由米卡·鲍梅斯特Unsplash 上拍摄

OWID GitHub 存储库中有许多数据集,但是它们已经将许多关键数据点聚合到一个组合结构中。这使得生活变得相当容易,因为转换不那么密集。

让我们看看 CSV。

import pandas as pddf = pd.read_csv('owid-covid-data.csv')
print(df.shape)(101752, 60)print('Total unique continents:',len(df.continent.unique()))
print('Total unique countries:',len(df.location.unique()))
print('Date span:',df.date.min(),df.date.max())Total unique continents: 7
Total unique countries: 231
Date span: 2020-01-01 2021-07-11

让我们检查数据帧的头部..

按作者分类的图像-示例数据框架

观察

  • 我们有 60 列,101,000 多行(截至 2021 年 7 月正确),每行代表年中的一天
  • 我们有横跨六大洲的 231 个国家
  • 几乎所有的变量都是连续的,而国家和大陆是分类的
  • 有许多空值(稍后会详细介绍)。
  • 鉴于我们分析的性质,这些变量中有些是相关的,有些最好描述为独立的,尤其是如果我们透过风险因素及其对新冠肺炎疫情的影响来看。

注意——我选择了 24 个我认为对演示仪表盘最有用的变量,概述如下。如果你想你可以发展这个应用程序,并包括更多。

因变量

dependent_var = [‘total_deaths’,’total_deaths_per_million’,’total_cases_per_million’,’icu_patients_per_million’,‘people_vaccinated_per_hundred’,
’total_vaccinations’,'hosp_patients_per_million]

自变量

independent_var = [‘gdp_per_capita’,’population’,’stringency_index’,’population’, 
‘population_density’, ‘median_age’, ‘aged_65_older’,
‘aged_70_older’, ‘gdp_per_capita’, ‘extreme_poverty’,
‘cardiovasc_death_rate’, ‘diabetes_prevalence’, 
‘female_smokers’,’male_smokers’, ‘handwashing_facilities’, 
‘hospital_beds_per_thousand’,’life_expectancy’,'continent', 'location']

这些指标中的大多数都是不言自明的。关于它们代表什么以及如何测量的详细分类,这里有一个广泛的数据字典。

数据准备

照片由凯蒂·史密斯Unsplash 上拍摄

缺失值和插值

当我们准备数据时,经常会遇到缺失值。这可能是因为收集管道中的错误,也可能是因为开始时没有任何数据。当我们处理符合高斯分布的数据时,一个有效的策略是用平均值代替零值,在其他情况下可能用中位数。对于随时间累积的数据,更合适的方法是使用插值法,根据其周围的值来估计和估算值。Pandas 有一个方法pd.interpolate(),默认替换是线性的。

按作者分类的影像-我是如何在 OWID 新冠肺炎数据集中发现缺失值的

对原始 OWID 数据集的检查显示,丢失值是常见的。下面是一些解决这个问题的函数。

下面是生成可在应用程序中使用的干净/格式化数据的主要函数。

让我们来看看最终的数据框架,看看英国是什么样子的。

按作者分类的图像—示例数据框架

观察

  • 我们的新冠肺炎因变量按周分组(例如,总病例数、死亡人数、住院人数、疫苗接种数),但是随着时间的推移,您可以看到数据存在差异
  • 每个独立特征(如人均 GDP、人口密度、吸烟率)也按周分组,尽管数据不会改变,因为这些东西不会像新冠肺炎那样移动得那么快。

太好了,现在我们有了符合我们需要的正确格式的数据。接下来,我们需要开始思考如何在我们的应用程序上以有意义和有用的方式呈现这些数据!

简化应用程序设计

凯利·西克玛Unsplash 上拍摄

这篇文章假设你对 Streamlit 的工作原理有所了解。如果你不知道,那么请看看下面的这篇文章

**

分析方法

查看这些数据有两种有用的方法:

  • 横截面——探索在给定时间点多个自变量和因变量之间的关系
  • 时间序列 —探究多个自变量和因变量之间的关系,以及如何随时间变化

我想让应用程序一直亮着,不想让多个图显示不同的数据点,所以我决定只使用一个散点图可视化,但允许用户进行高级定制。这将鼓励互动,并希望有一定程度的发现。

多页

我在应用程序中建立了两个页面,一个用于横截面可视化,一个用于时间序列可视化。

作者提供的图片——应用程序截图

注意——使用 pages 导航 Streamlit 应用并不是 Streamlit 平台的固有功能,但 Praneel Nihar 在此概述了一个解决方案:

https://medium.com/@u.praneel.nihar/building-multi-page-web-app-using-streamlit-7a40d55fa5b4

散点图

我喜欢散点图。如果散点图是静态的并且是二维的,我们有能力在一张图中显示多达五个变量。

  • 横坐标
  • y 轴
  • 分散点
  • 散布大小
  • 分散颜色

按作者分类的图像-横截面分析示例

如果我们把这些图做成动画,我们也可以在可视化中增加第六维度的时间

按作者分类的图像-时间序列分析示例

最后,如果我们能给用户机会来改变这些变量中的每一个,那么分析的范围可以进一步扩大。Streamlit 中的小部件允许我们提供这个特性。

作者图片 Streamlit 下拉小工具的屏幕截图

其他功能

除了 X、Y 和分散数据点,我还包括了一些其他可视化选项:

  • 选择按洲屏蔽,即只显示特定洲的国家
  • 对于 X 和 Y 图,用一条垂直/水平线表示某一特征的集中趋势。这允许您查看哪些标记高于或低于任何绘制的指标的平均值

应用程序示例输出—横截面散点图

按作者分类的图像-横截面散点图示例

下面的代码块概述了创建上述横截面散点图所需的步骤。

示例输出-时间序列散点图

按作者分类的图像-带动画的横截面散点图示例

下面的代码块概述了创建动画横截面散点图所需的步骤。

摘要

希望这个简短的介绍已经为您提供了一些我们如何以一种令人信服的方式可视化数据的例子。通过选择正确的工具与数据进行交互,并通过使用适当的可视化,探索性分析比单独使用条形图更有效、更有趣、信息量更大。

无论如何,请使用我的 Streamlit 代码并在此基础上进行构建——这里有大量的数据,尽管我已经编写了一些全面的代码来可视化这些数据,但我确信还有许多其他途径可以探索和构建。

下次见!

萨姆(男子名)

链接和资源

要在本地启动此应用程序,您应该克隆我的分叉 OWID repo,并在命令行中运行:

$ streamlit run covid_streamlit_app.py
  1. Streamlit App
  2. 用我的应用程序分叉 OWID 存储库
  3. 简化应用程序要求
  4. 原始数据回购中的我们的世界**

在 Jupyter 笔记本中使用下拉菜单 Ipywidgets 和 Plotly 进行交互式数据分析。

原文:https://towardsdatascience.com/interactive-data-analysis-with-dropdown-menu-ipywidgets-and-plotly-in-jupyter-notebook-591a84a81b22?source=collection_archive---------3-----------------------

这是一个例子,展示了如何设置一个交互式下拉菜单小部件,以及如何使用 IPython 和 Pandas 在 Jupyter Notebook 中显示数据库分析的结果。

作者图片:拉森火山国家公园。

挑战

最近,在为我的一个研究生班做项目时,我面临着这样一个问题:对我在 Jupyter 笔记本上处理的多个数据集进行数据库分析的最佳方式是什么。这些数据库中的每一个都包含了多年来收集的信息,并且对于该特定数据库中询问的每个不同问题都有多个分层级别,例如性别和种族。此外,每个数据库都有国家汇编的信息。例如,每次您想要查看不同州的数据或按种族或性别查看数据时,都必须修改代码并重新运行每个单元格,这既麻烦又低效。这个问题的解决方案在于 ipywidgets。 Ipywidgets 是用于 Jupyter 笔记本和 IPython 内核的交互式 HTML 小部件。它们使用户能够以快速、简单和有效的方式与数据交互并可视化数据中的变化。

在本文中,我将展示如何设置交互式下拉菜单小部件,以“阿尔茨海默氏病和健康老化数据”CDC 数据库为例进行简单的数据分析。3 下拉菜单部件将建立一个用户友好的菜单,在这里可以选择一个国家,一个分层水平(性别,种族或整体)和一个问题,用户希望看到的信息。我将使用 Plotly 这个交互式图形库来显示存储在数据库中的信息的图形表示。

本文使用的 csv 文件可在 CDC 网站上公开下载。

首先,让我们导入所有需要的库和扩展:

其次,让我们准备好要处理的 cvs 文件:

  • 为了简化输出,我们将只查看数据集中评估的以下 5 个问题:
  1. 身体质量指数(身体质量指数)为 30 或以上的肥胖老年人的百分比。
  2. 在过去的一个月中没有任何闲暇时间体育活动的老年人的百分比。
  3. 终生被诊断患有抑郁症的老年人的百分比。
  4. 被告知患有高血压的老年人中目前正在服药治疗高血压的比例。
  5. 每天吃 3 种或 3 种以上蔬菜的老年人百分比。
  • 不需要的列将被删除。

现在,让我们设置存储在“阿尔茨海默氏病和健康老化数据”数据库中的信息的图形表示所需的所有函数:

  • 为了简化输出,我们将只关注所有年龄组的数据点。
  • 将只分析 2015 年至 2019 年的可用数据。

函数 plot_healthy_aging_data_gender 采用 2 个字母的状态缩写,3 个数据帧,其中包含制作 Plotly 图形和一个问题所需的信息。如果用户在 dropdown 小部件中指定他们希望看到按性别绘制的数据,将选择该功能。

函数 plot_healthy_aging_data_race 采用 2 个字母的状态缩写,3 个数据帧,其中包含制作 Plotly 图形和一个问题所需的信息。如果用户在 dropdown 小部件中指定他们希望看到按种族绘制的数据,将选择此功能。

函数 plot _ healthy _ aging _ data _ overall 采用 2 个字母的状态缩写,3 个数据帧,其中包含制作 Plotly 图形和一个问题所需的信息。如果用户在 dropdown 小部件中指定他们希望查看按总体分层类别绘制的数据,将选择此功能。

函数 dataset _ analysis _ aging 查询原始数据集,根据种族、性别或整体(所有种族、性别和年龄)分层类别将结果划分为 3 个不同的数据框架。该功能旨在用户选择输入后,提取制作曲线图所需的信息。

如前所述,为了简化输出,我们将只关注所有年龄组的数据点,这些数据点在数据集的“分层 1”列中标记为整体。

函数 dataset_analysis_aging_gender、dataset_analysis_aging_race 和 dataset_analysis_aging _ race 是帮助函数,用于将州、问题和分层类别(性别、种族或总体)的数据集信息传递给 dataset _ analysis _ aging 函数。然后将返回的数据帧传递给相应的分层类别绘图函数。

现在,我们准备设置 3 个下拉菜单小部件,用于“阿尔茨海默氏病和健康老化数据”数据库的数据分析。这将通过编写一个函数来完成,该函数创建一个下拉菜单来选择特定的状态、问题和分层类别,并将这些信息传递到数据集分析函数中以获得特定的输出。

函数 drop down _ menu _ widget _ healthy _ ageing 接受一个与健康老龄化相关的数据集,以及 3 个帮助函数和一个要查询的问题列表。每个助手功能用于控制 UI 界面,以选择特定的状态、问题和分层,即性别、种族或总体数据。

该功能首先返回下拉菜单以选择要分析的状态、问题和分层类别,并且在用户选择输入之后,该功能基于所做的下拉菜单选择返回数据分析。

最后,我们准备调用交互式 drop down _ menu _ widget _ healthy _ age 函数。在初始输入选择后,用户可以继续改变菜单中的输入,以查看不同输入的图形输出,而无需重新运行任何单元。

在 Jupyter 笔记本中运行上面的单元格后,会出现下面显示的下拉菜单。现在可以选择下拉菜单来显示相应的曲线图。下拉菜单演示可以在文章末尾找到。

本文使用的 Jupyter 笔记本和数据集可以在 GitHub 找到:https://github.com/drozenshteyn/Jupyter_widgets_dropdown

感谢您的阅读,

月形蝴蝶

注:我使用了 jupyter_to_medium 和 GitHub embeds 的组合来发布这篇文章。

交互式数据可视化

原文:https://towardsdatascience.com/interactive-data-visualization-2c7d62fb3b16?source=collection_archive---------32-----------------------

使用 Altair 创建数据可视化

来源:作者

数据可视化有助于揭示肉眼无法在表格格式中看到的隐藏数据模式。它有助于理解不同数据点之间的相关性和关联性。不同类型的可视化有助于理解数据集的不同属性。

Python 提供了许多可用于数据可视化的库。每个包都有自己的优点和缺点。这里我们将讨论交互式数据可视化,这只有在极少数 pythons 库中才有可能。

Altair 是一个开源 Python 库,用于创建高度交互和有用的数据可视化。它提供了我们可以创建的各种各样的图表和绘图。

在本文中,我们将探索 Altair 并使用它创建一些可视化。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装来安装 Altair 开始。下面给出的命令将使用 pip 安装 Altair。

pip install altair vega_datasets

导入所需的库

在这一步中,我们将导入创建模型和可视化这些模型所需的所有库。

import altair as alt
from vega_datasets import data

正在加载数据集

在这篇文章中,我们将从织女星数据集著名的数据集'汽车'。在下面给出的代码中,您可以看到我们如何导入数据集。

source = data.cars()

创建图表

现在,我们将从创建一些图表开始,并探索如何创建这些图表。

  1. 散点图
alt.Chart(source).mark_circle(size=60).encode(
    x='Horsepower',
    y='Miles_per_Gallon',
    color='Origin',
    tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']
).interactive()

散点图(来源:作者)

在这里,您可以清楚地看到,我们在代码中添加了一个工具提示,使该图更具交互性。

2.条形地块

alt.Chart(source).mark_bar().encode(
    y='Origin:N',
    color='Origin:N',
    x='count(Origin):Q'
)

条形图(来源:作者)

3.组合图表

points = alt.Chart(source).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(brush, 'Origin:N', alt.value('lightgray'))
).add_selection(
    brush
)bars = alt.Chart(source).mark_bar().encode(
    y='Origin:N',
    color='Origin:N',
    x='count(Origin):Q'
).transform_filter(
    brush
)
points & bars

Combo(来源:作者)

正如你在上面的视频中看到的,使用上面的代码创建的图表是高度交互式的。该图同时具有散点图和条形图。

在这里,您可以清楚地看到我们使用 Altair 创建的不同图表和图形。尝试使用不同的数据集,创建不同的可视化效果,并在回复部分告诉我您的意见。

本文是与 Piyush Ingale 合作的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

Python 中 Lux 的交互式数据可视化

原文:https://towardsdatascience.com/interactive-data-visualization-with-lux-in-python-94bfcf84d15?source=collection_archive---------28-----------------------

只需点击一下,就可以看到几乎所有的图表

照片由 JJ 英Unsplash

介绍

数据可视化是数据科学的基本步骤之一。通过可视化数据,我们可以获得洞察力,这可以帮助我们获得新的洞察力。

有时创建一个很好的可视化效果,甚至选择一个适合数据的可视化类型,都需要很长时间。因此,我们需要一个能够自动化这个过程的库。

Lux 是一个 python 库,只需点击一下鼠标,就可以实现数据可视化工作流程的自动化。此外,lux 可以为您的数据选择完美的可视化方式。

在这篇文章中,我将向你介绍力士图书馆。此外,我将向您展示如何使用 python 来实现它。

没有进一步,让我们开始吧!

履行

安装库

你需要做的第一件事就是安装 lux 库。您可以使用 pip 或 conda 来完成此操作。在这种情况下,我将使用 pip 来安装 lux。另外,我启用了 jupyter 笔记本的插件。下面是这样做的代码。

! pip install lux-api 
! jupyter nbextension install --py luxwidget 
! jupyter nbextension enable --py luxwidget

加载数据

安装完库之后,现在可以加载它了。接下来,您需要加载数据。您可以使用任何您喜欢的数据,但现在我将使用来自 lux 库的数据。这些数据基本上描述了美国的大学,包括 SAT 平均分、地区、费用等。这是完成这项工作的代码,

import lux 
import pandas as pd df = pd.read_csv('https://raw.githubusercontent.com/lux-org/lux-datasets/master/data/college.csv') df

当您运行代码时,您不仅会看到数据帧。您还会看到将您从 lux 重定向到可视化的按钮。这是它的预览图,

因为您使用所有列进行可视化,所以它会提供几个选项卡供您查看。每个选项卡由不同列的图表组成。这些选项卡是

  • “相关性”选项卡为您提供了散点图之类的图表,直观显示了两个变量之间的关系。
  • distribution 选项卡为您提供了类似直方图的图表,显示了一列的值分布。
  • “发生”选项卡为您提供了类似于分类条形图的图表。

选择列

与任何其他库一样,您可以选择想要可视化的特定列。在这种情况下,我们希望看到 AverageCost 列和 SATAverage 列之间的关系。这是可视化它的代码,

df.intent = ["AverageCost", "SATAverage"]
df

这是代码的预览,

除了可视化数据之外,它还为您提供了一些增强可视化的建议。您可以看到三个选项卡。

  • “增强”选项卡为您提供增强可视化样式的建议。
  • 过滤器选项卡将过滤显示基于特定条件减少的图表。
  • 概化选项卡将通过移除给定的属性来显示图表。

过滤数据

正如我上面提到的,您可以使用某些条件来过滤数据。我们来看看东南地区有多少大学基于他们的资助模式。下面是实现它的代码,

df.intent = ["Region=Southeast", "FundingModel"] 
df

这是结果,

导出可视化效果

在您选择列并给出一些条件后,现在您可以从您喜欢的图表范围中进行选择。在可视化块上,您可以点击您喜欢的图表。之后,您可以单击箭头导出它们。这是它的样子,

选择图表后,您可以使用如下导出的属性来访问它,

df.exported

如果您想从列表中选择一个图表,可以使用索引来访问它。下面是这样做的命令,

df.exported[0]

这是它的样子,

转换为 Matplotlib

现在您想导出图表,但又想将它们转换成另一种类型。幸运的是,lux 可以将您的图表转换为另一种格式,例如 matplotlib。

要将图表转换为 matplotlib 格式,可以使用 to_matplotlib 函数来完成。这是实现这一点的代码,让我们回忆一下我们导出的第一个图表,

如您所见,它显示了 matplotlib 代码。我们可以在我们的环境中运行代码。所以我们试试。

哦不,有一个错误。它说“Set1”对象未定义。要解决这个问题,您可以在对象名称中添加记号。修复后,我们可以看到 matplotlib 格式的图表。这是代码和预览。

干得好!该图表已经在 matplotlib 版本中。

结束语

恭喜你!现在,您已经了解了如何使用 lux 来自动化您的数据可视化工作流。希望对你有用。

如果你对我的文章感兴趣,可以关注我的媒介。还有,如果你有什么问题,可以在 LinkedIn 上联系我。

谢谢你看我的文章!

交互式探索性数据分析

原文:https://towardsdatascience.com/interactive-exploratory-data-analysis-259e62fed295?source=collection_archive---------21-----------------------

使用 Python 实现基于 GUI 的 EDA 应用

米利安·耶西耶在 Unsplash 上拍摄的照片

探索性数据分析是我们为了理解数据而对数据进行的初始分析。这一点很重要,因为在我们创建模型或对数据执行操作之前,我们应该了解数据是什么,它包含哪些特征,这些特征如何相互关联以及目标值等。

如果数据集具有较少的要素,我们可以使用不同的图和图表来执行初始分析,但如果数据集具有大量要素,这将非常耗时,因为我们需要编写大量代码来分析所有要素及其关联。有各种方法可以减少这一时间,但仍然需要大量的工作,这些工作可以节省下来用于进一步的过程,如模型创建、操作等。

如果我告诉你,现在你可以节省一般在 EDA 中消耗的时间和精力,会怎么样?是的,你没看错,在本文中,我将向你展示一个 python 库,它不仅能减少你的工作量,还能帮助你从数据中获得洞察力,甚至不用编写 1000 行代码。

Autoplotter 是一个构建在 Dash 之上的开源 python 库,它创建了一个 GUI 应用程序,您可以在其中分析您的数据并创建不同的可视化效果,这些效果在视觉上非常吸引人,并且具有高度的交互性。我们还可以分析数据的属性,如分布、关联等。只用了一行代码。

在本文中,我们将使用 Autoplotter 分析数据集,看看如何减少我们的时间和精力。

让我们开始吧…

安装所需的库

我们将从使用 pip 安装来安装自动绘图仪开始。下面给出的命令将安装它。

pip install autoplotter

导入所需的库

接下来,我们将导入所需的库,它们是用于加载数据集的 Pandas 和用于探索性数据分析的 Autoplotter。

from autoplotter import run_app 
import pandas as pd

正在加载数据集

现在,我们将加载将在其上执行 EDA 的数据集。您可以使用任何数据集以及不同大小的数据集和大量要素。我在这篇文章中使用了著名的波士顿数据集。

df = pd.read_csv("/content/boston.csv")

执行 EDA

这是我们启动基于 GUI 的 Dash 应用程序的最后一步,该应用程序将用于 EDA。Autoplotter 为您提供了两种方式,即您可以在线运行应用程序,即在您要去的同一台笔记本电脑中运行,或者您可以在本地 URL 从外部启动它。我将向您展示这两种方法。

run_app(df,mode = "inline", host="127.0.0.1", port=5000)

内嵌(来源:作者)

run_app(df,mode = "external", host="127.0.0.1", port=5000)

这将在提到的 URL 和端口号上运行应用程序。现在让我们分析一下这个应用程序的不同部分。

  1. 数据预览

应用程序的第一部分和登录页面是数据预览页面,在这里您可以预览您正在处理的数据。

数据预览(来源:作者)

2.

这是最有用的部分。在本节中,我们可以使用大量的功能创建大量的图。我们可以使用 Plotly,ggplot,seaborn 等创建绘图。使用不同的参数和值,只需一次单击即可创建不同类型的图。

情节(来源:作者)

3.分析

这是我们可以分析数据集属性的第三部分,也是最后一部分。它包含三个选项卡,即数据分布、统计分析和分布。这里我们可以分析数据集的属性。

分析(来源:作者)

这就是我们如何使用基于 GUI 的应用程序进行探索性数据分析,并节省我们的时间和精力。继续尝试不同的数据集,并让我知道您在回复部分的评论。

本文是与皮尤什·英格尔合作完成的。

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

生成 Python 的交互式探索性数据分析

原文:https://towardsdatascience.com/interactive-exploratory-data-analysis-that-generates-python-790715e920e4?source=collection_archive---------22-----------------------

鳄梨数据集交互式探索性数据分析实用指南

德克·里布勒在 Unsplash 上的照片

E 探索性数据分析(EDA)是数据科学过程中的第一步,通常在数据提取之后。EDA 帮助我们在继续建模或决定重复提取步骤之前熟悉数据。

EDA 帮助数据科学家:

  • 熟悉数据
  • 发现数据提取过程中的错误
  • 决定数据是否需要清理
  • 如果有丢失的值,决定如何处理
  • 可视化数据分布等。

通过探索性数据分析,我们获得了数据的“感觉”

通过阅读这篇文章,你会得到

  • 基于 Avocado 数据集的 JupyterLab EDA 实例
  • 每个交互式操作的代码片段
  • 与同事分享分析结果的有效方式

如果你错过了我之前关于这个主题的文章,请参见米托——一个生成 Python 的电子表格。

鳄梨数据集交互式探索性数据分析实用指南

estudio BloomUnsplash 上拍摄的照片

在本文中,我们将分析 avocado 数据集 Kaggle 上比较流行的数据集之一——并展示探索性数据分析中的一些基本操作。

鳄梨数据集包含多个美国市场上鳄梨价格和销量的历史数据。可以从 Kaggle 下载。原始数据来自 HASS 鳄梨董事会。Kaggle 数据集在开放数据库许可 (ODbL)下获得许可。

Kaggle 上的牛油果数据集(作者 2021 年 10 月 18 日截图)

在 Excel 中打开的鳄梨数据集(图片由作者提供)

我们将使用 JupyterLab 的米托扩展来分析这个数据集,该扩展使用户能够在 JupyterLab 中交互式地完成他们的 EDA,并让每个编辑在下面的代码单元中生成等效的 Python。

使用 Python 进行探索性数据分析(作者可视化)

首先,我们需要用这个函数加载 Jupyter 实验室中的 Mitosheet 交互环境:

# make sure you have [Mito installed](https://docs.trymito.io/getting-started/installing-mito) before running this functionimport mitosheet
mitosheet.sheet()

这些函数将一个空的 Mitosheet 调用到 Jupyter 环境中

米托用 JupyterLab 中的空白表初始化(图片由作者提供)

导入数据

要将数据加载到工作表中,我们可以将现有的 Dataframe 作为参数传递给 Mitosheet 调用:

mitosheet.sheet(df)

或者,我们可以单击工具栏中的导入按钮,从本地文件系统中选择一个文件。

使用“导入”按钮导入米托表中的数据

当我们在导入菜单中选择“avocado.csv”时,米托会自动将 csv 文件转换为数据帧,并在下面的代码单元格中生成等效的 Python:

# Imported /Users/Downloads/avocado.csvavocado_csv = pd.read_csv(r’/Users/Downloads/avocado.csv’)

删除列

CSV 文件已经有一个索引列,在 Mitosheet 中显示为“未命名:0”,所以我们要做的第一件事就是删除这个列,我们可以通过单击工具栏中的删除列按钮来完成。

删除 avocado 数据集中的一列(图片由作者提供)

这将在下面的代码单元格中生成等效的 Python。代码也是自动记录的:

# Deleted column Unnamed: 0 from avocado_csv
avocado_csv.drop('Unnamed: 0', axis=1, inplace=True)

数据集中的唯一值

假设我们对数据集中鳄梨的不同区域感兴趣。

我们可以选择“区域”列的列菜单,然后转到值选项卡。

在“值”选项卡中,我们可以看到:

  • 列中的所有唯一值,
  • 这些值中的每一个的频率,
  • 以及每个值占总条目的百分比。

从这种分布来看,鳄梨似乎是按地区平均分布的。

显示鳄梨数据集中的唯一值(图片由作者提供)

过滤数据集

我们决定只查看鳄梨的地区是“奥尔巴尼”的行

我们可以选择 column 菜单中的 Filter/Sort 选项卡,并设置一个过滤器,其中“region”列正好是“Albany”

行的交互式过滤(图片由作者提供)

为该过滤器生成的代码如下所示:

# Filtered region in avocado_csv
avocado_csv = avocado_csv[avocado_csv['region'] == 'Albany']

解析日期值

现在我们已经过滤了数据集,我们想要探索“日期”列中剩下的值。

首先,让我们使用工具栏中的“添加列”按钮。

在表单中添加新列(作者图片)

接下来,让我们向该列添加一个公式,该公式从“date”列中的每个日期值解析出月份值。

=MONTH(Date)

将公式添加到表单中的新列(作者图片)

数据透视表

一旦我们在新列中检索到月份值,我们就可以使用数据透视表来计算每个月有多少个条目,并比较合计的计数。

我们需要做的就是点击工具栏中的“Pivot”按钮,并从出现的侧菜单中配置表格。

计算工作表中的数据透视表(图片由作者提供)

该数据透视表操作将生成以下 Python 代码片段:

# Pivoted avocado_csv into df3
unused_columns = avocado_csv.columns.difference(set(['Month']).union(set([])).union(set({'Month'})))
tmp_df = avocado_csv.drop(unused_columns, axis=1)
pivot_table = tmp_df.pivot_table(
    index=['Month'],
    values=['Month'],
    aggfunc={'Month': ['count']}
)

排序值

在 column 菜单中,我们还可以通过“Month count”列进行排序,以降序查看每个月的计数列表。

这里我们可以看到,对于过滤后的奥尔巴尼条目,一月的条目最多,六月和九月的条目最少。

对表单中的值进行排序(按作者排序的图像)

形象化

最后,我们可以通过单击工具栏中的“Graph”按钮来可视化分析。我们可以在侧边菜单中进行配置。

您可以将此可视化文件下载为 PNG 格式,以便与您的同事分享。

使用米托可视化数据分布(图片由作者提供)

分享你的分析

我们也可以通过点击“复制图形代码”按钮来复制任何可视化的等价代码。

此图的输出代码是:

# Import plotly and create a figure
import plotly.graph_objects as go
fig = go.Figure()# Add the bar chart traces to the graph
for column_header in ['Month']:
    fig.add_trace(
        go.Bar( 
            x=df3[column_header],
            y=df3['Month count'],
            name=column_header
        )
    )# Update the title and stacking mode of the graph
# See Plotly documentation for customizations: [https://plotly.com/python/reference/bar/](https://plotly.com/python/reference/bar/)
fig.update_layout(
    xaxis_title='Month',
    yaxis_title='Month count',
    title='Month, Month count bar chart',
    barmode='group',
)
fig.show(renderer="iframe")

如果我们运行上面的代码,出现在 Mitosheet 中的相同图表将作为输出出现在代码单元格的下面。

可视化(作者制作的图像)

结论

LenstravelierUnsplash 上拍摄的照片

我们在 EDA 过程中经历了一些简单的操作。虽然这不是一个全面的 EDA 指南,但它显示了我们如何避免在初始 EDA 中为简单的数据操作键入代码。

生成的代码有助于与同事分享,也有助于没有经验的数据科学家学习“熊猫方式”进行分析。

米托允许强大的 EDA 过程在 JupyterLab 生态系统中交互发生。

以下是了解更多关于米托的链接和鳄梨数据集的链接。

在你走之前

如果你喜欢看这些故事,为什么不成为 中等付费会员 ?每月 5 美元,你可以无限制地阅读 10000 个故事和作家。如果你用我的链接注册,我会赚一小笔佣金。**

照片由 Alexas_FotosUnsplash 上拍摄

posted @ 2024-10-18 09:28  绝不原创的飞龙  阅读(317)  评论(0)    收藏  举报