TowardsDataScience-博客中文翻译-2022-四十四-

news/2024/10/18 9:36:01/文章来源:https://www.cnblogs.com/apachecn/p/18473559

TowardsDataScience 博客中文翻译 2022(四十四)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

Python 中的求根方法

原文:https://towardsdatascience.com/root-finding-methods-from-scratch-in-python-84040c81a8ba

使用 Python 的二分法、牛顿法和割线法数学求根算法

介绍

数值 - 寻找算法迭代计算连续函数零点的更好近似,也称为

本文介绍了四种标准求根算法背后的理论,以及它们在 Python 中的实现。

照片由 Esther Jiao 在 Unsplash 上拍摄

以等式 1 为例:

等式 1 —示例函数(图片由作者提供)

图 1 是在区间[-1,5]上等式 1 的图。一个是 f(x)等于 0 时 x 的任意值。即曲线穿过 x 轴的位置。在这种情况下,根位于 x₀ = 1x= 2 之间。

图 1 —等式 1 的曲线图(图片由作者提供)

本文的目标是使用一些数值运算来逼近 Python 中的根。

实现这一目标的三种方法是:

  1. 二分法
  2. 牛顿方法
  3. 割线法

二分法

二分法通过在中点重复划分区间来逼近连续函数的根。

该技术适用于两个符号相反的值已知的情况。

如果区间【x₀,x₁】上有一个 f(x) 的根,那么【f(x₀】【f(x₁】一定有不同的符号。即**【f(x₀)f(x₁】<0**。

如有必要,复习这篇介值定理文章。

*https://medium.com/@andrewdaviesul/checking-if-a-solution-exists-intermediate-value-theorem-53d85890350

x₀x₁ 为估计区间的起点和终点。然后,用等式 2 计算出*【x₀,x₁】*之间的中点( x₂ )。

等式 2 —二分法(图片由作者提供)

接下来的猜测要么是 x₀x₂ 的中点,要么是 x₂x₁ 的中点,就看根落在哪边了。收敛缓慢

要点 1 给出了二分法的示例实现。

要点 Python 中的二分法

存储逐次根逼近和绘图图 2 说明了算法的迭代性质

图 2-对分根估计的迭代改进(图片由作者提供)

对等式 1 运行二分法,在*【1,2】之间指定一个区间*,在x1.324718475处返回一个。查看图 1 可以看出,这个值在期望值附近。

这个过程大约需要 18 次迭代才能达到这个结果。评估改进是逐渐发生的*。*

关于该算法的最后一点是,可以使用等式 3估计实现特定误差界限所需的最小迭代次数*。*

等式 3 —迭代次数(图片由作者提供)

x₀x₁ 是区间起点和终点,例如【1,2】。**

*https://scicomp.stackexchange.com/questions/16458/deriving-the-error-bound-for-bisection-method

使用 Gist 3 中的 Python 代码实现该等式。

要点 2 —误差界限和迭代计数器*

牛顿方法

可能是最著名的求根算法,牛顿法 逼近实值连续函数的零点。从解的初始猜测开始,等式 4 迭代使用函数导数xₙ 处的值的知识来改进近似。

  • n :迭代计数器
  • xₙ₊₁:下一步估计
  • xₙ:目前最好的估计
  • f(xₙ):函数在 xₙ 求值
  • f'(xₙ) :在 xₙf 的导数

等式 4——牛顿法(图片由作者提供)

显然,这个过程需要 f(x) 的一阶导数,因此 f(x) 必须是可微的。**

Gist 3 提供了 Python 代码来实现牛顿法的迭代解*。它使用 Sympy 库来评估 f'(xₙ) 。在每次通过循环时,参数值被代入到等式 1 中,以确定 xₙ₊₁ 。*

一个公差 极限控制过程何时中断,当 f(xₙ) 接近零点时触发该条件。

要点 3——具有符号评估的牛顿法的迭代解

如上,保存每个猜测和绘图图 3 显示了牛顿法如何逼近正确解。

图 3 —牛顿零猜测的改进(图片由作者提供)

初始猜测为 x = 9 ,该方法返回的结果为f(x)= 0*@x = 1.324718834。需要 8 次迭代才能达到 1e-5 的精度。*

牛顿法的收敛速度比二分法快得多,但有其局限性,这取决于所讨论的函数的导数。

割线法

割线法*与二分法非常相似,只是不是在中点处划分,而是通过连接端点**的割线来划分区间。*

等式 4 将在 Python 中迭代地或递归地实现。**

等式 4 —割线法(图片由作者提供)

Gist 4 中的 Python 方法递归地使用割线方法求解根。

要点 4——具有符号评估的牛顿法的迭代解

从初始值 x₀ = 1 和 x₁ = 2 开始,该过程在 8 次递归调用内,在 x = 1.324717957 处输出 f(x) 的根。图 4 显示了每次走刀产生的割线。

图 4——割线法可视化(图片由作者提供)

割线法是仅次于牛顿法的*。最适用于需要比二分法更快收敛的情况,但是对函数 f(x)解析导数太困难或者*不可能。**

结论

实现求根算法对于学工程和数学的学生来说很有价值。再者,还有很多其他的方法,用户可以探索和扩展自己的知识* 和编码技能,比如布伦特的或者斯特芬森的方法。*

如果你对 Python工程学数据科学感兴趣,请关注并查看我的其他文章。

*https://medium.com/@andrewdaviesul/membership

参考

[1] 微积分:完整教程,第八版 —罗伯特·A·亚当斯,美国北卡罗来纳大学教堂山分校**

舍入器:对复杂 Python 对象中的数字进行舍入

原文:https://towardsdatascience.com/rounder-rounding-numbers-in-complex-python-objects-e4b6f3b563f8

rounder 包使您能够对任何对象中的所有数字进行舍入,只需一个命令

rounder:在 Python 中舍入数字从未如此简单。照片由米卡·鲍梅斯特在 Unsplash 上拍摄

舍入数字很少引起问题。在标准库中,我们有函数round()math.ceil()math.floor(),通过它们我们可以使用三种标准类型的舍入。这应该够了,不是吗?

实际上,并不总是这样。假设您有以下对象,您希望将其舍入到两位十进制数字:

注意:在本例中,对象及其特定字段的含义并不重要。它只是一个可能的复杂嵌套对象的表示。然而,为了简单起见,我没有把它弄得太复杂。然而,当使用它时,想象一个复杂的嵌套字典,它的字段是其他嵌套字典、列表和其他类型的对象。

你会怎么做?你如何处理这样一个对象中的所有数字?您可能认为这相对容易,因为只需编写一个专用函数来处理这种特定类型的嵌套对象就足够了。这是可行的,但是如果对象发生了一点点变化呢?你必须更新这个函数,以使它反映对象的新结构。或者,您可以编写一个递归函数来实现这一点,但是该函数不必那么容易编写,因为它需要处理 Python 提供的如此多的不同类型。

因此,从round(1.122, 1)的简单性,我们转移到一个硬编码舍入一个特定类型和结构的对象的函数,或者转移到一个相当困难的递归函数。这不再简单…

这是唯一的方法吗?没有更简单的方法吗?Python 不是承诺简单吗?

简单的方法:rounder

幸运的是,有一个简单的方法:T5 包。它提供了一些函数,允许对许多不同类型的复杂和嵌套对象中的数字进行舍入。

让我们回到我们的例子。我们希望将来自obj对象的数字四舍五入为两位十进制数字。这就是你如何使用rounder来做这件事:

这不是很简单吗?

现在,假设您已经决定将obj中的数字四舍五入到五位有效数字。Python 没有为此提供内置函数,但是rounder提供了。您可以使用rounder.signif()表示数字,使用rounder.signif_object()表示嵌套对象:

注意 : obj是一个可变对象,因为我们之前对它进行了舍入,所以它发生了变化。因此,要再次使用它的原始版本,您需要重新创建它,就像我们在上面创建它一样。

同理,也可以使用rounder.ceil_object()rounder.floor_object(),分别对应math.ceil()math.floor()功能。

更多关于rounder

可变对象与不可变对象

我们必须记住,不像不可变的对象,可变的对象在适当的位置被改变*。这意味着当您使用或不使用新名称对其进行更新时,原始对象将被更改。同样的,如果你改变它的(浅层)拷贝,原始对象也会被更新。*

同样的规则也适用于rounder操作。记住这不是典型的rounder而是 Python。换句话说,rounder实现了 Python 处理可变和不可变对象的典型方式。

rounder然而,函数使得处理可变对象更加简单。为了简单起见,这次我们将使用更简单、更小的对象:

我们确实预料到了这一点,但是由于列表是可变的,x也被改变了:

如果你不希望这种情况发生,rounder可以帮助你。可以使用参数use_copy,默认为False;这就是为什么默认情况下,rounder会改变原来的对象。这是 Python 的默认行为:如果你想创建一个对象的副本,你必须手动完成。

:提浅抄和深抄的好地方。你可以在标准库 [copy](https://docs.python.org/3/library/copy.html) 模块或者这里阅读这个主题。如果你需要或想要加深或更新你的知识,你可以休息一下,现在就做。

这就是use_copy如何改变rounder函数的行为:

我们也可以使用use_copy的其他rounder功能:

至于四舍五入到有效数字,记住这个操作也影响整数:

自定义舍入

rounder包还提供了一个通用函数rounder.map_object(),它使您能够应用任何接受一个数字并返回一个数字的可调用函数(所以,Callable[numbers.Number, numbers.Number])。您可以使用它来应用自定义舍入。

例如,假设您想要对一个浮点数应用以下舍入,比如说x:

  • 如果x是一个整数,原封不动地返回
  • abs(x) > 100时四舍五入为整数
  • 100 > abs(x) > 10时四舍五入到 1 位小数
  • 10 > abs(x) > 1时四舍五入到 2 位小数
  • 否则,四舍五入到 3 位小数

例如,当您用不同单位或不同比例的数字对对象进行舍入时,可以使用这种舍入方法。下面的函数可以做到这一点:

这个函数的名字round_float意味着它将只对浮点进行舍入。它可以被命名为round_only_floats,但是这个名字不能完全代表它的功能;这是因为它不舍入非数字。所以,我把它命名为round_float,以区别于round

让我们来看看实际情况:

现在,让我们对上面使用的obj对象使用这个函数:

如您所见,该函数的签名类似于[map()](/does-python-still-need-the-map-function-96787ea1fb05)函数的签名,第一个参数是一个可调用的,用于作为第二个参数提供的对象。这可以帮助你记住如何使用rounder.map_object()

实际上,你可以使用这个函数将任何可调用的Callable[numbers.Number, numbers.Number]应用于对象中的所有数字,甚至是那些与舍入无关的数字。考虑这个例子:

类型

值得一提的是,rounder的函数支持许多不同的类型,比如所有内置的容器类型(如dictlisttupleset),还有生成器、mapfilter对象、队列、命名元组、array.array等等。你会在包的仓库中找到他们的列表。注意,当您将一个generator类型输入到一个rounder函数中时,您也会收到一个生成器。

异常处理

典型的舍入函数在用于非数字时会抛出TypeError:

rounder.signif()功能的运行方式类似:

名称以_object结尾的rounder函数则不然:

这些函数的行为是这样的,因为当对象是对象的容器时,函数递归地在它们上面运行,舍入(如果不是数字,则不舍入)对象的每个最低级别的元素。

履行

高级开发人员可能会欣赏rounder的开发方式。这一想法来自该计划的合著者路德·范·德·哈姆。这个包的本质是使用闭包实现的,这是一种优雅的方法——比包的第一个版本(未发布)中使用的最初的基于类的方法优雅得多。

你可以从包库中,特别是从它的主模块 [rounder](https://github.com/nyggus/rounder/blob/main/rounder/rounder.py)中,了解更多关于包的实现。

结论

rounder封装使舍入变得容易。有了它,您可以使用最常见的舍入方法:

  • 将一个数字四舍五入到特定的小数位数(round_object());
  • 将一个数字向下(floor_object())或向上(ceil_object())舍入到最接近的整数;
  • 将数字舍入到特定的有效数字(signif()signif_object());

而且是一种定制的舍入方法,这要归功于

  • 使用自定义函数(map_object())对数字进行舍入。

但这并不是rounder如此有用的原因。它非常有用,因为您可以对任何复杂和/或嵌套的对象类型使用名称以_object结尾的rounder函数,该函数将对对象中的所有数字进行舍入。

这个包还简化了可变对象的操作。通常,当您想要创建一个可变对象的副本时,您需要调用copy.deepcopy(),这将创建该对象的深层副本。有了 rounder,你就不必这样做了;使用use_copy=True参数就够了,函数会帮你做。

简而言之,每当你需要在比一个数字更复杂的对象中舍入数字时(比如一个遵循numbers.Number抽象基类的对象),你会发现rounder特别有用。它的功能也适用于常规数字。随着rounder包的出现,我们想要舍入所有数字的对象的复杂性不再是问题。

资源

*https://github.com/nyggus/rounder https://realpython.com/copying-python-objects/ *

魔方求解器

原文:https://towardsdatascience.com/rubiks-cube-solver-96fa6c56fbe4

用 Python 3 构建魔方解算器

解魔方|作者图片

大家好,今天我们将使用 python 3 创建一个魔方解算器。在这篇博客文章中,我将介绍游戏理论和所需的算法,这样你就可以轻松地击败任何魔方。

随着魔方的流行,我敢肯定你以前见过一个,但以防万一你没有,我会给他们一个快速的纲要。魔方是由 ernő·鲁比克发明的一种流行游戏。魔方有一套简单的规则,解读混乱的三维拼图。传统上,魔方是一个 3x3 的立方体,但现在有许多经典游戏的变体。

魔方是要解决的复杂谜题,共有 43,252,003,274,489,856,000 种可能的组合。

魔方方程式的排列|作者图片

由于这种复杂性,从业余爱好者到数学家,许多人都在研究魔方。由于立方体的复杂群论,数学家们已经喜欢上了它,产生了许多关于这个主题的科学论文。

其中一张意义重大的纸是纸“魔方组的直径是二十个”在这篇论文中,他们确定“上帝的数字”是 20 转。“神数”是魔方的一个术语,指的是在任何构型下解决一个魔方的最大转动次数。

这项研究的另一个令人印象深刻的成果是各种解决立方体问题的标准化算法。

构建立方体

好了,现在我们有了魔方的背景知识,我们的第一步将是建立一个。为了简单起见,我们将坚持 nxn 立方体,这样我们就不需要处理任何其他三维形状的几何图形(有时拼图是其他形状,如正方形或三角形)。

平铺多维数据集视图|作者提供的图像

为了构建我们的多维数据集,让我们为用户创建一个自定义的交互类。这样,我们可以将内部状态存储在多维数据集对象中,以减少在操作多维数据集时需要传递给每个函数的变量数量。

首先,我们需要确定创建多维数据集的最有效的数据结构。为了这个项目,我们将使用一个三维数组(嵌套列表)。由于需要对立方体进行操作,我选择了这种数据结构。使用一个三维数组,我们可以创建映射来平均在 O(n) 时间内将方块切换到位。

3D 阵列表示|作者图片

接下来,我们需要构建三个独立的函数来操作立方体。使用魔方,您只能进行三种可能的移动。

魔方运动|作者图片

我们的三个动作功能都采取了非常相似的方法。我们使用映射来切换立方体的位置。对于垂直和侧向扭曲函数,我们使用 For 循环遍历列的每一行,使得这些函数的时间复杂度为 O(n)。但是,水平扭曲函数会原地切换行,时间复杂度为 O(1)。我们还检查是否需要在每次旋转时旋转最近的面。为了旋转魔方的面,我们转置各自的矩阵。

求解立方体

现在我们有了魔方的工作模型,让我们开始制作求解器。

对于求解者,我们可以采用多种方法来解决这个问题。然而,我们将采取游戏树的方法。

用博弈树的方法,我们知道我们将需要搜索博弈树来找到可能解决立方体的最少移动。我们可以使用蛮力方法,然而,以今天的计算限制,这是不可行的。相反,我们将使用更有效的搜索算法。

我们要用的算法是迭代深化 A* (IDA*)搜索算法。由于内存限制,该算法优于 A* 。A和 IDA使用类似的方法,其中 A记得哪些节点被访问过,而 IDA不记得。通常情况下,A是搜索问题的最佳选择,然而,对于如此大的搜索空间,如果我们使用 A,很可能会耗尽内存。

IDA是一种树形搜索方法,它结合了试探法和深度优先搜索 (DFS)。在 IDA中,启发式算法指导 DFS,树在每次迭代中扩展,类似于蒙特卡罗树搜索(参见我的博客文章构建国际象棋引擎:第二部分关于 MCTS 的解释)。

下面是 IDA*方法的示例树。在这个图中,我显示了 g_score(到达当前节点的成本)和 h_score(前面路径的预测成本)。该算法使用 g_score 和 h_score 的简单和来评估每个节点。

IDA*游戏树示例|作者图片

如之前在 IDA*中所述,我们不会保存已访问的节点。不保存访问过的节点有利也有弊。通过不保存被访问的节点,我们有机会访问同一个节点两次,这给了我们整个算法更差的时间复杂度。然而,通过不保存我们访问过的节点,我们不需要那么多的内存。对于我们的用例,节省内存是很重要的,因为我们正在处理一个可能有 43,252,003,274,489,856,000 个节点的博弈树。

好了,现在我们对将要使用的算法有了更好的理解,让我们来构建它。首先需要做的是建立我们的启发式。

对于我们的试探法,我们将采用简单的强力方法,并使用广度优先搜索算法来检查节点。在这里,我们将把立方体的不同状态以及从已求解的立方体到达那里的移动次数存储在一个哈希表中。通过将多维数据集状态存储在哈希表中,我们创建了一个简单的查找表来了解哪个状态需要解决的移动量最少。

现在我们有了试探法,我们可以实现 IDA*算法来求解立方体。构建该算法将使用简单的 DFS(深度优先搜索)算法和上述评分方法(g_score + h_score)。当访问每个节点时,会传入我们前一个节点的 g_score 来知道当前的开销。为了确定 h_score,将在我们的启发式图中快速查找节点。为了简单起见,如果我们发现一个不在我们的启发式地图中的节点,就将 h_score 设置为 20(上帝的数字)。在这里,我们可以创建一些额外的等式来获得更好的估计,但对于我们的简单用例,这是不需要的(如果你有一个等式,请随意在评论中留下它)。综上所述,我们应该得到类似下面的代码。

谢谢

就这样,我们成功地创建了我们的魔方解算器。你可以在我的 GitHub 上查看完整版本的代码。

感谢阅读。如果你喜欢这样,可以考虑订阅我的账户,以便在我最近发帖时得到通知。

参考

  • https://en.wikipedia.org/wiki/Rubik%27s_Cube
  • https://ruwix . com/the-Rubik-cube/how-to-solve-the-Rubik-cube-初学者-方法/
  • https://medium . com/@ chaitanyaanimesh/calculating-of-number of-the-permutating-of-the-number of-the-rubkis-cube-121066 f5f 054
  • https://en.wikipedia.org/wiki/Ern%C5%91_Rubik
  • https://en.wikipedia.org/wiki/Big_O_notation
  • http://kociemba.org/math/papers/rubik20.pdf
  • https://en.wikipedia.org/wiki/Game_tree
  • https://en.wikipedia.org/wiki/Iterative_deepening_A*
  • https://en.wikipedia.org/wiki/A*_search_algorithm
  • https://en . Wikipedia . org/wiki/Heuristic _(计算机科学)
  • https://medium . com/forward-data-science/building-a-chess-engine-part 2-db 4784 e 843d 5

ruDALL-e,或来自俄罗斯的 AI

原文:https://towardsdatascience.com/rudall-e-or-from-russia-with-ai-5fbd098fc77b

用于文本 2 图像生成的多模态方法,具有示例和实验

“всянашажизнь—театр”//“整个世界是一个舞台”(ruDALLe) //作者截图

TL;博士: ruDALL-e 与 DALL E 毫无关系,却承载着许多惊喜和激动人心的现象。

II2021 年开始,OpenAI 以另一组里程碑事件再次震惊世界:多模态 CLIP 和 DALL E ,能够通过提示将文本直接转换为图像(我写了关于这种模式及其文化影响)。即使 DALL E 仍然不能公开使用(剧透:敬请关注),CLIP 还是以开源形式发布——全世界的聪明人都可以将其应用到独特的生成艺术形式中(我的分析即将到来)。

正如 OpenAI 演示中所描述的,DALL E 的创造能力以敬畏和灵感影响了创造性的 AI 社区。

这不是创造力的昏睡,而是它的催化剂。

事实上,如果你要求创建一个"带有蓝色草莓图像的彩色玻璃窗,你会立即得到一组图像:

OpenAI 博客 //作者截图

你会看到各种各样的设计。他们中的一些是照片般真实的,一些是模糊的,风格和构图各不相同。但它给你带来了更接近视觉的想法。

或者,“一个甜甜圈形状的钟”怎么样?

OpenAI 博客 //作者截图

OpenAI 仍在为 DALL E 进行优化和用例工作,然后才会向全世界发布这一模型。他们肯定会的——他们发布了 GPT 3,现在没有等待名单。一切皆有可能(问题是“什么时候”)。

俄罗斯模特

但是突然间,DALL E 被释放了。

好吧,不是突然。而不是真正的 DALL E。

2020 年,由于 GPT-3 是最理想的 NLP 模型,俄罗斯研究人员公布了由俄罗斯储蓄银行 : ruGPT-3 的人工智能研究实验室创立的项目。它在 600 GB 俄语文本上进行训练,并以 760 Mio (ruGPT-3 Large)13 亿(ruGPT-3 XL) 参数发布,比较他们项目描述中的图表。

如果你将这些数据与开放的 GPT 模型进行比较,你会发现这一点。最大的 GPT-2 型号与15 亿参数一起工作。真正的 GPT-3 (带达芬奇发动机)运行1750 亿参数。

结论是:俄语 ruGPT-3 XL 处于 GPT-2 的水平上(但是在大量的俄语文本、文章、书籍数据集上进行训练)。显著差异:俄语模型可以生成比 OpenAI(在英语文本上训练)的 GPT-2 质量更好的俄语文本。数据集事关。然而,它不能用俄语用烤面包机写情书。它不具备抽象认知或文体转换的能力。

所以,去年年底,一个由 Sberbank 资助的新项目发布了:

ruDALL-e

它与 ruGPT-3 在同一个 Christofari 集群上接受训练,获得 Apache 2.0 许可,并且“堪比 OpenAI 的英文 DALL-e”(引自 ruDALL-e 网站)。

让我们看看,在哪些方面具有可比性。

俄罗斯 DALL-e

ruDALL-e 有两种型号:

Malevich (XL) —运行在 13 亿个参数上,具有图像编码器(定制 VQGAN 型号),可作为储存库和 Colab 笔记本使用,具有实现的升级 RealERSGAN。

康定斯基(XXL) —更好的模型,运行在 120 亿个参数上(像 OpenAI 的 DALL-e),目前还不能用于测试。

由于 DALL-e 不可公开访问,研究人员试图通过与清华大学的 CogView 项目合作,与原始论文( PDF )一起重新创建模型,该项目也试图重新创建 DALL-e。

因此,由于最初的变压器不可用,他们试图重建它的架构——并将其命名为 ruDALL-e

但是真的管用吗?

幸运的是,有一个公开的 ruDALL-e 的 Colab 笔记本(使用较小的型号,Malevich )。

关于潜在空间不和谐(由剪辑研究员和艺术家 Advadnoun 创造)的聪明头脑甚至可以优化笔记本——并发现一些奇怪的现象。

明显的例子

因此,让我们看看 ruDALL-e 能否生成 DALL-e 原始文章中引用的示例。

著名的鳄梨椅

DALL-e by OpenAI ( 来源 ) //作者截图

ruDALL-e(马列维奇)//作者截图

在这两种方法的情况下,我们看到模型如何“理解”将现象“椅子”与现象“鳄梨”在“形状”的功能中结合的任务。

就 OpenAI DALL-e 而言,结果看起来比 ruDALL-e Malevich (XL) 更有机。后一种型号选择了特定的特征,如颜色形状,但是它的生成不太有机(尽管如此有趣)。即使是更大的型号康定斯基(XXL) 也无法再现 DALL-e 的椅子设计质量:

来源:https://rudalle.ru/en/(康定斯基(XXL)) //作者截图

让我们看一些更具体的例子,比如…

桌子上放着一批钟表。

OpenAI 博客 //作者截图

在 OpenAI 的 DALL-e 的例子中,我们可以看到它已经知道了更多关于时钟和它们的设计,相比之下是一个很好的老 BigGAN 。你还记得,回到 2018 年:

比根时钟(2018) //作者创作

BigGAN 可以重新生成视觉元素,如“圆形”、“带箭头”等。在钟表上,通过 DALL-e 你可以看到数字、12 小时设计等。

ruDALL-e //由作者创建

ruDALL-e(上图)很好地传达了视觉效果——图案的多样性很好。然而,它仍然远离 DALL-e 的现实主义。它有 DALL-e 的视觉容量,但比根的理解等级,IMHO。

毕竟,ruDALL-e 的质量仍然令人惊叹——通过集成的 ERSGAN 放大过滤器,你甚至可以以更大的格式调整图像的大小(你也可以直接使用 ERSGAN 完成,然后再使用)。

俄罗斯风格(数据集很重要)

ruDALL-e 最令人兴奋的方面可能是训练数据集。你不会在西方实现中找到这样的内容,因为它源于俄语内容。

如果你用“закатвгороде”(城市的日落)来提示,你会看到一些俄罗斯城镇的美丽景色,主要是莫斯科和圣彼得堡(而不是纽约或伦敦)。在许多照片中,你可以认出莫斯科河、克里姆林宫以及俄罗斯/苏联建筑的古典主义和折衷主义风格。

ruDALL-e 完成,由作者创建

再比如,随着提示“портретгения”(天才的肖像),你会得到流行的俄语教科书的插图,而不是刻板的好莱坞“疯狂科学家”或背景中黑板上有复杂公式的老师的股票图像。(我可以重新构建这一分类,因为“天才”这个可怜的绰号在俄罗斯教科书中伴随着重要的科学家、作家或艺术家时非常明显)。

ruDALL-e 完成,由作者创建

我们甚至可以在这里找到几个被创造性扭曲的名人。

查尔斯-奥古斯丁·德·库仑?// ruDALL-e 完成,由作者创建

这幅肖像在物理教科书中关于库仑定律的描述广为人知,而这幅肖像也在俄罗斯教科书中使用。

数据集问题?

通过使用 ruDALL-e 进行实验,您将会发现并一点一点地重建模型被训练的数据集的内容。

一年前,作为 DALL-e 和 CLIP 由 OpenAI 推出,一位被称为advad noun的传奇艺术家和研究者创作了几本 CLIP Colab 笔记本,成为 2021 年 Text2Image Art 的复兴的基础。在这一年中,世界各地不同的艺术家和研究人员用不同的方法对 100 多台笔记本进行了微调(我会写一篇关于它的评论,我保证)。Advadnoun 用他的开创性实验和不和谐论坛开了一个 Patreon。聚集在那里的有创造力的人们正在探索更多不同的艺术人工智能模型,这些模型几乎每周都会在世界范围内出现,而 ruDALLe 成为了这个社区的焦点。

我们可以从 ruDALL-e 接受训练的数据集上部分识别出一些初始图像。

SberAI 写了关于他们的训练数据集:

我们的第一步是捕捉 OpenAI 在其出版物中提供的数据(超过 2.5 亿对)以及 Cogview 使用的数据(3000 万对)。这包括:概念说明、YFCC100m、维基百科数据和 ImageNet。然后我们添加了 OpenImages、LAION-400m、WIT、Web2M 和 HowTo 数据集作为人类活动的数据源。我们还包括了我们感兴趣的领域的其他数据集。关键领域包括人、动物、名人、室内、地标和景观、各种类型的技术、人类活动和情感。(来源)

另一方面,似乎有从网络上刮下来的图像(与 OpenAI 安全数据集方法相反)。通过创建一系列图像,您已经可以看到它了:

ruDALL-e 完成,由作者创建

是的,没错。 iStock 水印。似乎数据集突出地包含了股票图像公司的预览图像。

还有无处不在的迷因,它们似乎给社交网络记忆(和图像数据集)打上了烙印,比如电视频道标识的旧电视屏幕烙印。

我们看到著名的迷因有马龙·白兰度(维托·柯里昂)和小罗伯特·唐尼迷因(翻白眼)。但是用的是准俄语文本。

由丹尼尔·鲁斯发现

看起来像俄罗斯网站的图像被用于训练数据集。Elle / MichaelFriese 和 DanielRussRuss 发现了另一个奇怪的一致之处:

MichaelFriese10 截图

第三个图像看起来像一本书的封面,甚至更多,它几乎有 1/1 是从训练数据集转移到完成的。

使用图像反向搜索(,这可能是非常鼓舞人心的),特别是——在这种情况下——使用 Yandex 图像搜索,你可以找到原始图像,图像的根源。

例如,这张图片:

ruDALL-e 完成,由作者创建

Yandex 图片搜索,作者截图

在这种情况下,视觉完成(“上传的图像”)似乎源于莫斯科地铁的照片(在这种情况下,【Mayakovskaya 站)。

我们必须时刻注意人工智能有意或无意的抄袭(就像我们对莎士比亚和亚历山大波普的抄袭一样)。

类似的现象我也经历过,GPT-2 对非英语文本的过度训练。在我的例子中,我使用了一个单独的文件:歌德的《浮士德》(原文)。

在培训开始时,我们可以观察新的文本(用非常怪异的德语,但已经有了结构,与原戏剧相对应)。经过 7000 步后,补全接近原始文本;他们甚至重复了数据集的内容。

有限数据集上的过度训练重新构建了这个数据集。

****

在左边:训练步骤 600。右边:训练步骤 7400。//作者截图

在 ruDALL-e 的情况下,我想知道,如果训练数据集应该是非常多样化的,那么完整性如何变得与原始图像如此接近?

抽象思维?

像上面这样简单的任务,ruDALLe 都可以重新想象。但是如果你尝试抽象的话题,一个令人兴奋的现象出现了。ruDALLe 没有“幻想”这样的问题,而是重新制作了书籍、CD 和网站模型的封面(全部模仿俄语)。

《怀旧》

ruDALL-e //作者截图

《前世记忆》:

ruDALL-e //作者截图

尽管如此,一些完成的作品还是令人印象深刻。

文化参考

如前所述,ruDALLe 接受的是基于俄罗斯的主流图像的训练。

如果你深入挖掘俄罗斯的内容/背景,你会发现对历史和文化有趣的重新诠释:

六层(“шестидесятники”)

斯大林死后(1954 年),在赫鲁晓夫解冻(20 世纪 50-60 年代),苏联出现了一个迷人的文化景观:六层。部分反映了美国和欧洲的抗议运动,部分是为了将自己从斯大林的创伤中解放出来,苏联知识分子——艺术家、作家、音乐家——开始发展另类的第二文化,与社会主义现实主义和(后)斯大林时代的爱国主义紧张对立。

不幸的是,一场独特的运动在苏联/俄罗斯之外鲜为人知,但它带来了文化多样性、新鲜感和开放思想,影响了世界六分之一人口的几代创作者。

这是一部由真正的诗人和艺术家参与的电影中的一小段片段,你可以感受一下这种氛围:

1964 年在莫斯科理工博物馆的诗歌朗诵会

在我用自动点唱机进行的音乐实验中,当 AI 重新构建六阶的声音时,我偶然发现了一个诡异的现象。

正如你所看到的,这种背景很难表达,特别是如果它将由人工智能重新创建。ruDALLe(由于其预先培训)创建了带有提示“шестидесятники”(六层)的各种图像:

ruDALL-e //作者截图

我可能会过度解读它,但我看到了一些纪实照片,带有类似表演场景的团体照片。第一个图像类似于著名的六层图像(也用于他们的先锋杂志“青年”(“юность")):

Dmitri Bykov 关于“第六层”的选集封面,使用了青年标志(Stasys Krasauskas)

也许我过度解释了我的观察,但是我越深入兔子洞,我就有越多的考古发现。

ruDALLe 有创意吗?

虽然人们仍然在讨论机器的创造力,但我自己有一个明确的答案(自 2015 年以来与人工智能共同创造):是的。

接下来,我想展示一些 ruDALLe 关于创造力的有趣发现(所有的提示都是用俄语输入的,我为这篇文章翻译了它们)。

提示:村里的蒙娜丽莎

ruDALL-e //作者截图

即使不是每一部作品都展示了乡村的乔康达,其衍生作品也很有趣。即使是达芬奇的“sfumato”(烟熏色渐变)在大多数图像中都起作用。此外,她把脸转向不同方向的方式也很棒。

提示:克里姆林宫的神奇宝贝

ruDALL-e //作者截图

如果说第一张图片说明了叙事“皮卡丘在莫斯科参观观光”,那么第二张图片则需要更多的内容知识:在这里你看到了对鲍里斯·叶利钦发型的完美刻画。在第三幅图中,你看到一个类似普京的人,对一些可爱的东西感到高兴,可能是——神奇宝贝在克里姆林宫游荡。

提示:橱窗里的女孩

ruDALL-e //作者截图

这个提示会生成一系列扭曲的人类图像(ruDALLe 仍然无法像 StyleGAN3 一样生成逼真的人脸)。但有些作品蕴含着艺术力量,比如这幅:

ruDALL-e //作者截图

我猜想 ruDALLe 训练的数据集包含艺术摄影——或者 Instagram 图像。

提示:《自然》****

ruDALL-e //作者截图

自从 BigGAN 以来,我们已经知道人工智能能够逼真地再现自然。首先是,自然特征包含在数据集内的大多数** 图像中(即使只是作为背景主题)。其次,是我们的大脑在购买自然图像,即使看了第二眼后这些图像并不令人信服。当我们看到人脸图像时,我们会立即发现 AI 所做的所有扭曲,因为我们的大脑被训练来检测面部特征。历史上,如果树或云看起来很奇怪,对我们的大脑来说并不重要。**

提示:“街头搞笑怪兽。

ruDALL-e //作者截图

我是说,很迷人,不是吗?

提示:“建构主义生日派对

ruDALL-e //作者截图

提示:“空间里的恋人

这些作品传达了苏联艺术家的科幻风格(其中还有宇航员阿列克谢·列昂诺夫),蓝色的太空,地球大气层的朦胧烟雾,未来的理想主义和乌托邦氛围。

ruDALL-e //作者截图

提示:“云中列宁

毫无疑问,ruDALLe 数据集应该包含许多俄罗斯/苏联历史的镜头。探索这种特定的预训练模型来重新解释视觉叙事是很有趣的。

这个提示给了我几个非常有趣的补充,在这里你可以认出列宁(即使中间的图像描绘了不同苏联政治家的组合)。

ruDALL-e //作者截图

但是下面的结果让我起了鸡皮疙瘩。不仅仅是重新想象列宁。这是一个独特的视角,是苏联末期概念主义者(如科马尔&梅拉米德)和其他艺术家异议运动的特征。

ruDALL-e //作者截图

这幅从整个历史视角直到苏联解体的戏剧性肖像是独一无二的。

提示:“复活

在这里,ruDALLe 把提示分配给了它占优势的内容领域:宗教,基督教背景。可视化是预先确定的,由于附属:希腊东正教的图标。

ruDALL-e //作者截图

但是在规范的视觉特征之外的重新解释也在这里重新提出:

ruDALL-e //作者截图

摘要

ruDALLe 不是 DALLe,它不包含符号转换、隐喻能力和 OpenAI 多模态方法的灵活性。

尽管如此,这是一个体面和自力更生的模型,它产生鼓舞人心的和独特的视觉效果,适合灵感迸发,头脑风暴和跳出框框思考。

ruDALL-e //作者截图

在现有的虚拟环境中运行新的 Jupyter 笔记本电脑

原文:https://towardsdatascience.com/run-a-new-jupyter-notebook-in-an-already-existing-virtual-environment-7490b3dd5ab6

解决无法从默认的 Jupyter 笔记本安装中访问虚拟环境模块的问题

照片由斯科特·韦伯在 Unsplash 拍摄

问题是

有几种不同的 Python 工作流,了解多种工作流可以让您在处理不同类型的问题时更加容易。对我来说,我喜欢使用 VS 代码和终端,但是当我需要一些快速的数据可视化时,没有什么比 Jupyter 笔记本更适合快速迭代了。

问题是,**你如何从现有的虚拟环境中运行你的 Jupyter 笔记本?**如果您运行命令jupyter notebook,即使是在虚拟环境中,它也会使用默认内核启动 Jupyter 笔记本服务器,例如: Python 3 (ipykernel)。如果您尝试导入您环境中安装的任何模块,您可能会得到模块未找到错误。

Extra: 在此阅读更多关于设置虚拟环境的信息:

https://medium.com/swlh/painless-easy-virtual-environment-setup-for-your-python-project-5aed144acebf

经过一番疯狂的谷歌搜索,我终于找到了这个快速可靠的解决方案:

设置 Jupyter 笔记本

  1. 导航并激活您的虚拟环境*(如果您在这一步需要帮助,请参阅上面的文章)。*
  2. 使用以下命令在您的虚拟环境中安装一个 Jupyter 内核:
ipython kernel install --user --name=venv

其中--user将安装限制在本地用户,而--name在步骤 1 中被设置为环境名。

3.接下来,用恰当命名的命令打开您的笔记本:

jupyter notebook

4.查看笔记本的右上角,看看哪个内核正在运行。它可能会以默认内核启动。点击菜单栏中的内核,导航至更改内核。然后,从下拉列表中选择您在上一步中提供的环境名称。

**重述:**从菜单中选择内核→更改内核→您的内核名称

将内核更改为您在上面的示例中设置的内核。在这里,选择“venv”将允许访问安装在该环境中的所有模块。

提示和技巧

  1. 如果您想查看已经设置的可用内核,请键入以下命令:

jupyter kernelspec list

2.要删除以前安装的内核,请使用:

jupyter kernelspec uninstall venv

其中" venv" 是您的环境的名称。

关闭

应该可以了!现在,当您在笔记本(即import pandas as pd)中运行导入语句时,您将可以访问您环境中的所有模块。现在,您已经了解在虚拟环境中运行 Jupyter 笔记本电脑需要什么了。

**注意:**在这个用例中,我没有安装 Anaconda。如果您安装了 Anaconda,有一个有用的 GUI 可以帮助您管理环境设置,有些人可能更喜欢这种方法。

写这篇文章是为了在你多次遇到这个问题时,作为一个快速的书签参考。

以批处理模式运行 SageMaker TensorFlow 对象检测模型

原文:https://towardsdatascience.com/run-a-sagemaker-tensorflow-object-detection-model-in-batch-mode-66989346390b

如何使用 Sagemaker 批量转换作业处理大型图像

对于一个计算机视觉项目,我需要在一大组图像上应用对象检测模型。这篇博文描述了如何在 Amazon SageMaker 中通过 TensorFlow 对象检测模型 API 使用批量转换作业来实现这一点。

首先,基于一个 AWS 示例笔记本,我将解释如何使用 SageMaker 端点在单个图像上运行模型。对于小图像,这种方法是可行的,但是对于大图像,我们会遇到问题。为了解决这些问题,我改用批量转换作业。最后,我最后说几句话。

用于检测徽标的对象检测。图片由作者提供。

起点:使用 SageMaker TensorFLow 对象检测 API 进行模型推断

AWS 在 GitHub 上提供了一些如何使用 SageMaker 进行物体检测的好例子。我用这个例子通过一个使用 TensorFlow 对象检测 API 的对象检测模型进行预测:https://github . com/AWS-samples/Amazon-sage maker-tensor flow-object-detection-API。

当模型被部署为端点时,您可以通过调用端点,一次一个图像地使用模型进行推理。这段代码摘自示例笔记本,展示了如何定义 TensorFlowModel 并将其部署为模型端点:

来源:https://github . com/AWS-samples/Amazon-sage maker-tensor flow-object-detection-API/blob/main/3 _ predict/deploy _ endpoint . ipynb。

然后,将图像作为 NumPy 数组加载,并作为列表进行解析,以便将其传递给端点:

来源:https://github . com/AWS-samples/Amazon-sage maker-tensor flow-object-detection-API/blob/main/3 _ predict/deploy _ endpoint . ipynb。

最后,调用端点:

来源:https://github . com/AWS-samples/Amazon-sage maker-tensor flow-object-detection-API/blob/main/3 _ predict/deploy _ endpoint . ipynb。

同样,完整的笔记本可以在这里找到。

问题:端点请求负载太大

这在使用小图像时非常好,因为 API 调用的请求负载足够小。但是,当使用较大的图片时,API 会返回 413 错误。这意味着有效负载超过了允许的大小,即 6 MB。

当然,我们可以在调用端点之前调整图像的大小,但是我想使用批处理转换作业。

解决方案:改用批处理转换作业

使用 SageMaker 批处理转换作业,您可以定义自己的最大有效负载大小,这样我们就不会遇到 413 错误。除此之外,这些作业可以用来一次性处理全套图像。

这些图像需要存储在 S3 桶上。所有图像都以批处理模式处理(顾名思义),预测也存储在 S3 上。为了使用批处理转换作业,我们再次定义了一个 TensorFlowModel,但是这次我们还定义了一个entry_point和一个source_dir:

来源:https://github . com/AWS-samples/Amazon-sage maker-tensor flow-object-detection-API/blob/main/3 _ predict/deploy _ endpoint . ipynb并由作者改编。

inference.py代码转换模型的输入和输出数据,如文档中所述。这段代码需要将请求负载(图像)更改为 NumPy 数组,解析为 list 对象。从这个例子开始,我修改了代码,让它加载图像并将其转换成 NumPy 数组。inference.pyinput_handler功能的内容变更如下:

来源:https://sage maker . readthe docs . io/en/stable/frameworks/tensor flow/using _ TF . html # how-to-implementation-the-pre-and-or-post-processing-handler-s并由作者改编。

注意,我在上面的代码中排除了output_handler函数。确保在您的代码中也包含该函数(取自文档)。

该函数需要 Python 包 NumPy 和 Pillow,它们没有安装在运行批处理推理作业的映像上。我们可以创建自己的图像并使用那个图像(在初始化 TensorFlowModel 对象时使用image_uri关键字),或者我们可以提供一个requirements.txt并将它存储在与您的笔记本相同的文件夹中(称为source_dir='.’)。该文件在映像启动过程中使用,以便使用 pip 安装所需的软件包;内容是:

内容由作者提供。

首先,我想使用 OpenCV(就像端点示例中一样),但是这个包不太容易安装。

我们现在使用模型来创建一个 transformer 对象,而不是将模型部署为模型端点:

作者代码。

最后,使用输入路径调用转换器:

作者代码。

瞧!图像由模型处理,结果将作为 JSON 文件保存在output_path桶中。命名等同于输入文件名,后跟一个.out扩展名。顺便说一下,您还可以调整和优化实例类型、最大负载等。

布鲁斯·马尔斯在 Unsplash 上拍摄的照片。

最后的想法

这很可能不是最划算的方法,因为我们将图像作为 NumPy 数组传递给转换器。从的另一个示例笔记本中,我发现建议您的 SavedModel 应该接受二进制数据的 base-64 编码字符串,因为二进制数据的 JSON 表示可能很大。

此外,我们可以调整inference.py中的output_handler函数来压缩返回并存储在 S3 上的 JSON,或者只返回相关的检测。

使用 Crontab 和 HTTP 请求按照自定义计划运行 Airbyte 同步

原文:https://towardsdatascience.com/run-airbyte-syncs-on-a-custom-schedule-with-crontab-and-http-requests-8d6fbb3ea112

利用 Airbyte 的简单 REST API 进行复杂配置

照片由尹英松在 Unsplash 拍摄

Airbyte 是一个神奇的工具,最近在数据工程社区掀起了波澜。这是一个用于运行 ELT(提取、加载和转换)过程的开源工具。它是 Fivetran 等昂贵软件的绝佳替代品,每月可为您的公司节省数千美元。

从现在开始,我将假设您对 Airbyte 的结构以及如何在生产环境中使用它有一定的了解。

Airbyte 很棒,但是,就目前的情况来看,Airbyte 对连接同步的 cron 式调度没有一流的支持。这很快就会到来,但还没有完全准备好,我的公司运行的是旧版本的 Airbyte,还不需要升级。

当谈到目前的日程安排,有几个选项,如让您的同步运行每分钟,每小时,每天等。,但是如果你想要更具体的东西,或者如果你想自己编排你的同步,在 UI 中是不可能的,这是大多数用户在大多数情况下与 Airbyte 交互的方式。

但是不要害怕!Airbyte 不仅提供了一个很好的 UI 来管理您的 ELT 过程,而且还提供了一个 HTTP REST API,允许您使用 POST 请求来触发来自外部源的连接。

完整的 API 文档在这里是,但是如果你继续读下去,我将向你展示如何使用 Crontab 和 Python 来按照你自己的计划运行你的同步。当然,您可以使用任何您喜欢的工具和语言。

⚙️连接到 API

Airbyte 公开的所有端点都是 POST 端点,这使得它非常容易交互。因为 Airbyte 是容器化的,所以我将假设您正在使用 Airbyte 附带的所有默认端口,并且您将在同一台机器上运行您的 Python 脚本。

下面的代码非常简单,将使用 API 同时触发每个启用的连接,但是它应该让您对需要访问的端点有一定的了解。

如果您使用 Python,您需要确保安装了requests模块,然后开始编写一个函数来获取与您的安装相关联的 Airbyte 工作空间:

Airbyte 中的每个工作区都有多个源、多个目的地和多个连接,这些连接决定了数据从源到目的地的流动。为了触发同步,我们首先必须获得每个工作区的连接列表,然后单独触发每个连接。我们可以通过以下两个函数来实现:

然后,我们要做的就是把它打包成一个整洁的小包,这样整个程序看起来就像这样:

这就是 Python 的一面。剩下的就是安排这个脚本运行了!

🕒计划 Airbyte 同步

同样,您可以使用任何您喜欢的工具,但是我喜欢使用 Crontab,因为它简单快捷。将上面的脚本调整为使用 Python schedule包并一直在后台运行也是可行的。

如果您决定只使用 Crontab,请确保它安装在您的机器上。我喜欢使用 Crontab.guru 来确保我会得到我想要的时间表。我不会在这里给出完整的教程,但是如果您想在每小时的早上 6 点到下午 6 点之间运行 Airbyte 同步,您可以使用crontab -e命令将下面一行插入 Crontab:

00 6-18 * * * python3 force_airbyte_sync.py

保存您的 Crontab,并确保使用crontab -l将其正确插入。然后坐下来,放松,享受在你的英语教学过程中少花 50%的钱!

我希望这篇文章至少对你们有些人有用!如果你有任何问题,欢迎评论这篇文章或发邮件给我,地址是 isaac@isaacharrisholt.com。我喜欢谈论数据和所有工程方面的东西,所以为什么不开始一个对话呢!

也可以在 GitHub 上找我或者在 LinkedIn 上联系我!我喜欢写我的项目,所以你可能也想在 Medium 上关注我。

这一条就这么多了!我希望你喜欢它,任何反馈都非常感谢!

如何使用 Docker 在本地运行气流

原文:https://towardsdatascience.com/run-airflow-docker-1b83a57616fb

在本地机器上使用 Docker 运行 Airflow 的分步指南

约书亚·雷德科普在 Unsplash 上拍摄的照片

介绍

Apache Airflow 是数据工程领域最热门的技术之一,它允许用户大规模地构建、编排和监控数据管道。

很有可能你已经通过pip安装了 Airflow,试图在本地运行它,但是很有可能你会遇到问题,甚至更糟,搞乱你的本地环境。

如果您想在本地机器上测试气流,那么最简单的方法就是使用 Docker 图像。在今天的简短教程中,我们将逐步完成一个指南,帮助您在几分钟内通过 Docker 启动并运行 Airflow。

先决条件

首先,您需要确保您已经安装了

  • Docker 社区版
  • Docker Compose (注意,你需要版本≥ 1.29.1)

步骤 1:获取 docker-compose.yaml

我们首先需要的是 docker-compose.yaml 文件。在您的主目录上创建一个新目录(姑且称之为airflow-local):

$ mkdir airflow-local
$ cd airflow-local

并获取docker-compose.yaml文件(注意,我们将使用 Airflow v2.3.0)

$ curl -LfO 'https://airflow.apache.org/docs/apache-airflow/2.3.0/docker-compose.yaml'

您可以随意查看撰写文件以及其中定义的服务,即airflow-schedulerairflow-webserverairflow-workerairflow-initflowerpostgresredis

步骤 2:创建目录

现在,当您在airflow-local目录中时,我们将需要创建另外三个目录:

  • dags
  • logs
  • plugins
$ mkdir ./dags ./logs ./plugins

步骤 3:设置气流用户

现在,我们必须导出一个环境变量,以确保主机上的文件夹和容器中的文件夹共享相同的权限。我们将简单地将这些变量添加到一个名为.env的文件中。

$ echo -e "AIRFLOW_UID=**$(**id -u**)**\nAIRFLOW_GID=0" > .env

使用cat检查.env的内容,确保其包含上述两个变量。

$ cat .env
AIRFLOW_UID=501
AIRFLOW_GID=0

步骤 4:初始化气流数据库

现在我们已经准备好初始化气流数据库,首先启动airflow-init容器:

$ docker-compose up airflow-init

该服务将运行airflow db init,并为气流数据库创建管理员用户。默认情况下,创建的帐户有登录名airflow和密码airflow

步骤 5:启动气流服务

让气流启动并运行的最后一件事是启动我们在步骤 1 中看到的气流服务。

$ docker-compose up

请注意,上述命令可能需要一段时间,因为需要启动多个服务。完成后,您可以在新的命令行选项卡中使用以下命令来验证这些映像已启动并正在运行:

$ docker ps

气流图像启动并运行——来源:作者

步骤 6:访问气流用户界面

要访问 Airflow 用户界面,只需前往您喜欢的浏览器并打开localhost:8080

气流管理员登录——来源:作者

键入您的凭据(如前所述,默认情况下,这些凭据将被设置为airflow并点击“登录”)。现在,您应该可以访问气流控制面板,在这里您可以看到一些用气流修补的 Dag 示例。

气流界面上的 DAGs 示例—来源:作者

第七步:进入气流工作者容器

您甚至可以进入 worker 容器,以便使用下面的命令运行airflow命令。您可以通过运行docker ps找到气流工作者服务的<container-id>:

$ docker exec -it <container-id> bash

举个例子,

$ docker exec -it d2697f8e7aeb bash
$ default@d2697f8e7aeb:/opt/airflow$ airflow version
2.3.0

第八步:收拾残局

一旦你完成了你的实验,你可以通过简单的运行来清理我们刚刚创造的混乱

$ docker-compose down --volumes --rmi all

此命令将停止并删除所有正在运行的容器,删除包含数据库数据和已下载映像的卷。

如果您再次运行docker ps,您可以验证没有容器启动并运行

$ docker ps
CONTAINER ID  IMAGE   COMMAND   CREATED   STATUS    PORTS     NAMES

最后的想法

在今天的简短教程中,我们探索了一个分步指南,它可以帮助您通过 Docker 在本地计算机上安装和运行 Apache Airflow v2.3.0。

请注意,Airflow Docker 图像仅用于测试目的。如果你计划在生产环境中部署气流,我推荐你在 Kubernetes 上用官方的舵图运行它。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

https://betterprogramming.pub/kafka-cli-commands-1a135a4ae1bd

使用 Python API 客户端运行 BigQuery SQL

原文:https://towardsdatascience.com/run-bigquery-sql-using-python-api-client-b5287ac05b99

从零开始一步一步来

图片来源于unsplash.com

今年我正在积极地与谷歌云(GCP)合作,我将分享如何在 WSL (Windows 子系统 Linux)中用 Python 和 Anaconda 设置 API 客户端,以从头开始执行 BigQuery SQL 查询。

如果你需要更多关于 WSL2 和 Anaconda (Miniconda)安装的信息,我可以在这个的前一篇文章中帮助你。

摘要

在这篇文章中,我们将了解如何:

  1. 使用 WSL 创建一个新的 Anaconda 环境。
  2. 使用 PIP 安装 Google API 客户端库
  3. 使用 Web 控制台创建一个 Google 服务帐户
  4. 使用 JSON 密钥文件生成 Google 应用程序凭证
  5. 设置 Google 应用程序凭据环境变量
  6. 将 USA Names 公共数据集添加到 BigQuery 并测试 SQL 查询
  7. 设置 Visual Studio 代码以在 WSL 上运行
  8. 调用 Python 脚本来执行 SQL 查询
  9. 奖励:故障排除
  10. 谢谢
  11. 结论
  12. 有用的资源

1.使用 WSL 创建一个新的 Anaconda 环境。

如果你没有 Windows 子系统 Linux (WSL)和 Anaconda (Miniconda ),我建议你看看我的上一篇文章。

为了不与现有库混淆,我们将设置一个本地项目,执行以下步骤:

  1. 打开一个 WSL2 端子
  2. 转到你的个人文件夹 a 创建一个新文件夹 gcp_projects
  3. 创建一个名为 gcp_prj 的 Anaconda 环境
  4. 检查新环境是否已创建
  5. 使用 activate 切换到新环境。

使用以下命令:

mkdir gcp_projects
cd gcp_projects/conda create --name gcp_prj
conda info --envs
conda activate gcp_prj

我正在创建一个新的 Anaconda 环境。图片由作者提供。

2.使用 PIP 安装 Google API 客户端库

我们将在新的 Anaconda 环境中安装 PIP,然后使用以下命令安装 Google API 客户端库:

sudo apt install python3-pip
pip install --upgrade google-cloud-bigquery

安装 PIP。图片由作者提供。

为 Python 安装 Google API 客户端库。图片由作者提供。

3.使用 Web 控制台创建一个 Google 服务帐户

下一步是通过转到https://console.cloud.google.com/IAM&管理>服务帐户或https://console.cloud.google.com/iam-admin/serviceaccounts创建一个新的项目和服务帐户

谷歌云控制台,服务账号。作者图片

创建一个名为 MyBigQueryTest 的新项目

谷歌云控制台,创建一个项目。作者图片

创建一个名为 sa_python_scripts 的新服务帐户,并选择角色来访问您的项目。

在谷歌云控制台中创建服务帐户。作者图片

出于测试目的,我将使用所有者角色,而不授予用户访问服务帐户**的权限。**请注意,不建议在生产环境中使用所有者角色

授予服务帐户,谷歌控制台的角色。作者图片

4.使用 JSON 密钥文件生成 Google 应用程序凭证

转到服务帐户,选择位于https://console.cloud.google.com/iam-admin/serviceaccounts的 MyBigQueryTest 项目,点击为服务帐户创建的电子邮件,查看详细信息。

服务帐户可通过电子邮件获得。图片由作者编辑。

创建一个新的密钥并将其下载为一个 JSON 文件

创建新的服务帐户密钥。作者图片

将文件另存为mybigquerytest . JSON;我使用的是直接的 WSL 路径**\ \ WSL $**\ Ubuntu \ home \ csaavedra \ workspace _ Linux \ GCP _ projects

使用\wsl$ hide Windows 共享网络保存到 WSL。图片由作者提供。

在 WSL 终端 Ubuntu 中检查文件。作者图片

5.设置 Google 应用程序凭据环境变量

为您的配置文件永久设置 GOOGLE_APPLICATION_CREDENTIALS 变量。bashrc 文件。

sudo nano ~/.bashrc

编辑您的个人资料。图片由作者提供。

在文件末尾添加导出GOOGLE _ APPLICATION _ CREDENTIALS:

export GOOGLE_APPLICATION_CREDENTIALS="/home/csaavedra/workspace_linux/gcp_projects/mybigquerytest.json"

将导出 GOOGLE_APPLICATION_CREDENTIALS 添加到您的个人资料中。图片由作者提供。

按下 Control + X ,选择 Y 为是,保存修改后的缓冲区(文件)

确认更改。作者图片

并按回车键确认文件名和更改。

确认文件名。作者图片

我正在重新加载概要文件,并使用变量 GOOGLE_APPLICATION_CREDENTIALS 的 echoprintenv 命令检查路径

source ~/.bashrc
echo $GOOGLE_APPLICATION_CREDENTIALS
printenv GOOGLE_APPLICATION_CREDENTIALS

重新加载配置文件并检查 Google 应用程序凭证路径。图片由作者提供。

6.将 USA Names 公共数据集添加到 BigQuery 并测试 SQL 查询

进入https://console.cloud.google.com/bigquery的 BigQuery 控制台,添加数据公共数据集,如下图:

向 BigQuery 添加公共数据集。作者图片

在市场中,搜索 USA names 并选择美国社会安全管理局数据集

谷歌公共数据集市场。图片由作者提供。

点击名为的蓝色按钮,通过数据集添加数据集:

添加美国名称数据集。作者图片

USA Names 数据集已添加,但您无法在 explorer 项目树中找到它。

添加了美国名称。图片由作者提供。

要添加它,你需要搜索美国名称,然后选择将搜索范围扩大到所有项目:

搜索美国名字。图片由作者提供。

然后你需要点击项目名称 bigquery-public-data 旁边的大头针图标,移动鼠标靠近三个点。

Pinging BigQuery 公共项目。图片由作者提供。

现在,您可以在项目树中看到美国的名称:

图片由作者提供。

下一步是使用编辑器窗口并执行以下 SQL 查询:

SELECT name, SUM(number) as total_people
FROM `bigquery-public-data.usa_names.usa_1910_2013`
WHERE state = 'TX'
GROUP BY name, state
ORDER BY total_people DESC
LIMIT 20

我们将使用结果来检查 Python 脚本是否正常工作:

美国姓名查询结果。图片由作者提供。

7.设置 Visual Studio 代码以在 WSL 上运行

从 https://code.visualstudio.com/[下载并安装 Visual Studio 代码后](https://code.visualstudio.com/)进入扩展并安装

  • Python 扩展
  • 远程 WSL 扩展

如下图所示:

Visual Studio 代码,扩展。图片由作者提供。

然后点击左下角带有
大于号和小于号的绿色图标

图片由作者提供。

并选择新建 WSL 窗口打开一个远程连接 WSL 的 Visual Studio 新实例。

图片由作者提供。

你可以在左下角看到不同的标签,就像文本 WSL: Ubuntu 一样

WSL: Ubuntu。图片由作者提供。

现在,您将通过转到文件并打开文件夹来打开 WSL 中的文件夹:

Visual Studio 代码,打开文件夹。图片由作者提供。

选择路径/home/csaavedra/workspace _ Linux/GCP _ projects/

打开远程文件夹。图片由作者提供。

我们可以在那里找到 JSON 密钥文件。现在,右键单击名为big query-usanames-test . py的文件,创建一个新文件

创建新的远程文件。图片由作者提供。

8.调用 Python 脚本来执行 SQL 查询

将以下代码复制到big query-usanames-test . py文件中

作者修改的代码。基于https://github . com/Google APIs/python-big query/blob/HEAD/samples/client _ query . py

按 Control + F5 运行big query-usanames-test . py文件

图片由作者提供。

执行的结果在 Web 编辑器中显示为查询结果

执行的结果。图片由作者提供。

奖励:故障排除

注入环境变量

注入环境变量。图片由作者提供。

如果您没有权限设置一个环境变量,您可以通过使用 os.environ 对象直接将值传递到您的代码中:

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/home/csaavedra/workspace_linux/gcp_projects/mybigquerytest_injection.json'

没有名为 Google 的模块

没有名为 google error 的模块。图片由作者提供。

如果您得到错误 No module named Google,请使用以下命令检查 google cloud library 的安装:

pip install --upgrade google-cloud-bigquery

无法自动确定凭据

如果出现错误:无法自动确定凭据。请设置 GOOGLE_APPLICATION_CREDENTIALS 或显式创建凭据并重新运行应用程序。更多信息请见https://cloud . Google . com/docs/authentic ation/getting-started

该问题与作为环境变量导出的GOOGLE _ APPLICATION _ CREDENTIALS有关。

你可以测试运行代码 os.environ 或者在终端打印 printenv 看看是否返回变量。

import os
print(os.environ)

如果没有,您可以导出或重新加载带有源文件的概要文件。bashrc 和 printenv。

export GOOGLE_APPLICATION_CREDENTIALS="/home/csaavedra/workspace_linux/gcp_projects/mybigquerytest.json"source ~/.bashrc
echo $GOOGLE_APPLICATION_CREDENTIALS
printenv GOOGLE_APPLICATION_CREDENTIALS

此外,您可以在 visual Studio 终端中退出,以使用环境变量强制重新加载会话

谢谢

最后,我要感谢克里斯·冯·塞法尔威,他给了我继续写作的灵感。

快乐发展!

结论

通过使用 API 客户端和一个服务帐户,用 Python 连接到谷歌云服务(GCP)是很容易的。在这第一步之后,您可以进行复杂的自动化操作,比如使用 Python Pandas 处理 Excel 文件,在 Google Big Query 中加载和合并,以及刷新 Tableau 仪表板。

有用的资源

https://github.com/googleapis/python-bigquery/ https://cloud.google.com/bigquery/docs/reference/libraries#client-libraries-install-python https://codelabs.developers.google.com/codelabs/cloud-bigquery-python#0 https://cloud.google.com/apis/design/errors

了解 BLOOM,最大的开放存取人工智能,并在您的本地计算机上运行它

原文:https://towardsdatascience.com/run-bloom-the-largest-open-access-ai-model-on-your-desktop-computer-f48e1e2a9a32

查看 BLOOM 解决数学、翻译和编码问题的实践。

BLOOM 是一个开放访问的多语言模型,包含 1760 亿个参数,在 384 个 A100–80GB GPU 上训练了 3.5 个月。一个 BLOOM 检查点需要 330 GB 的磁盘空间,因此在台式计算机上运行这个模型似乎不可行。然而,你只需要足够的磁盘空间,至少 16GB 的内存,和一些耐心(你甚至不需要一个 GPU),在你的计算机上运行这个模型。

BLOOM 是 1000 多名科学家和神奇拥抱脸团队的合作成果。值得注意的是,这种大型多语言模型对每个人都开放。本教程结束时,你将学会如何在你的本地计算机上运行这个庞大的语言模型,并看到它生成如下文本:

- INPUT: "The SQL command to extract all the users whose name starts with A is: "OUTPUT: "SELECT * FROM users WHERE name LIKE 'A%'"- INPUT: "The Spanish translation of thank you for your help is: "OUTPUT: "gracias por su ayuda"- INPUT: "John is 4 times as old as Bob. Bob is 3 years younger than Mike. Mike is 10 years old. What is John's age? Let's think step by step. "OUTPUT: "First, we need to find out how old Bob is. Bob is 3 years younger than Mike. So, Bob is 10–3=7 years old. Now, we need to find out how old John is. John is 4 times as old as Bob. So, John is 4 times 7=28 years old"

本教程使用拥抱脸的transformers库的一些组件,以及定制的 Python 代码,有策略地从磁盘加载模型权重,并生成一系列令牌。为了便于学习,本教程中的推理 Python 代码是从头开始编写的,没有使用 Hugging Face Accelerate 中的现成实现。对于生产,拥抱脸加速是更强大和多才多艺。本教程中的 Python 代码在配有 i5 11gen 处理器、16GB RAM 和 Samsung 980 PRO NVME 硬盘的计算机上每 3 分钟生成一个令牌(快速硬盘可以显著提高推理速度)。

布鲁姆建筑

BLOOM 是一种因果模型语言,这意味着它被训练为下一个令牌预测器。这种基于一组前面的标记来预测句子中的下一个标记的明显简单的策略,已经显示出对于大型语言模型的一定程度的推理能力(arXiv:2205.11916)。这使得 BLOOM 和类似的模型能够在一个句子中连接多个概念,并以相当的准确性解决算术、翻译和编程等重要问题。BLOOM 使用由输入嵌入层、70 个转换器块和输出语言建模层组成的转换器架构,如下图所示。每个变压器块有一个自我注意层和一个多层感知器层,输入和后注意层规范。

布鲁姆建筑

要使用 BLOOM 预测句子中的下一个标记,我们只需将输入标记(以嵌入的形式)传递给 70 个 BLOOM 块中的每一个。假设这是一个顺序操作,我们可以一次只加载一个块到 RAM 中,以避免内存溢出。类似地,单词嵌入和输出语言建模层可以按需从磁盘加载。

下载预先训练的 BLOOM 检查点

使用下面的代码从拥抱脸模型库中下载 BLOOM (176-B 版本):https://huggingface.co/bigscience/bloom。这将下载特定的 BLOOM 检查点2a3d62e。虽然 BLOOM 的模型大小在 330GB 左右,git lfs下载额外的链接文件,那么下载大小差不多是 700GB。确保您有足够的磁盘空间。

git lfs install
export GIT_LFS_SKIP_SMUDGE=1
git clone [https://huggingface.co/bigscience/bloom](https://huggingface.co/bigscience/bloom)
cd bloom
git lfs fetch origin 2a3d62e
git lfs checkout

下载的文件夹包含一个分片的 BLOOM 检查点,如下所示。分片意味着检查点被分成 72 个不同的文件,命名为pytorch_model_00001-of-00072.binpytorch_model_00001-of-00072.bin,以便于处理。

> ls -la
6.7 GB  pytorch_model_00001-of-00072.bin 
4.6 GB  pytorch_model_00002-of-00072.bin 
...
4.6 GB  pytorch_model_00071-of-00072.bin57 KB  pytorch_model_00072-of-00072.bin
0.5 KB  config.json14 MB  tokenizer.json13 KB  pytorch_model.bin.index.json

文件00001包含单词嵌入和相关层规范,文件0000200071 包含 70 个 BLOOM 块,文件00072包含最终层规范。输出语言建模层使用与单词嵌入相同的权重。如果你好奇的话,pytorch_model.bin.index.json文件指定了 BLOOM 层是如何分布在碎片上的。

推理

现在我们用下载的 BLOOM 模型来做推断。首先我们需要安装拥抱脸transformers v4.20.0,如下图。这个特定的版本是必需的,因为本教程中的定制 Python 代码使用了仅在这个特定版本的transformers中可用的方法。

pip install transformers==4.20.0

第二,我们创建一个方法(get_state_dict),它接受一个碎片号(1 到 72)作为输入,从磁盘中读取碎片,并返回一个包含模型对象状态的字典。该方法允许从字典键中移除前缀,以便于使用torch.load_state_dict将权重加载到模型对象中。我们还通过从下载的文件夹中加载来创建令牌化器和配置对象。

第三,我们创建了三种方法来将状态字典加载到不同的模型对象中。我们在推理过程中使用这些方法,只将模型的特定部分加载到 RAM 中。这三种方法遵循相似的模式,包括:1)从磁盘读取碎片,2)创建模型对象,3)使用torch.load_state_dict填充模型对象的权重,以及 4)返回模型对象。唯一的例外是load_block 方法,它不创建新的块对象,而是覆盖作为参数传递的对象,以节省 RAM 内存。

第四,我们创建了一个方法来完全向前遍历 BLOOM 的所有层。该方法将令牌输入 id 的数组作为输入,并返回预测为句子中下一个的令牌 id。该方法从创建注意屏蔽和位置编码(alibi)开始。然后,它在嵌入层上向前传递以创建初始的hidden_states。接下来,它将hidden_states依次通过 70 个 BLOOM 块和输出语言模型头来生成输出 logits。argmax获取输出逻辑并返回预测概率最高的令牌 id。注意,在使用嵌入之后,我们删除它们以避免溢出内存。同样,每次我们调用 bloom 块时,我们从磁盘读取一个新的对象,但是覆盖现有的block 对象的权重以节省内存。

最后,我们定义一个输入句子,将其标记化,然后依次调用 forward 方法来预测句子中的下一个标记,一次一个标记。注意,在每一步,我们将新生成的令牌与之前的令牌(input_ids)连接起来,以进一步生成额外的令牌。

INPUT: The SQL command to extract all the users whose name starts with A is:OUTPUT:
Token 1 ....... SELECT
Token 2 ....... *
Token 3 ....... FROM
Token 4 ....... users
Token 5 ....... WHERE
Token 6 ....... name
Token 7 ....... LIKE
Token 8 ....... 'A
Token 9 ....... %'
Token 10 ....... The SQL command to extract all the users whose name starts with A is:  SELECT * FROM users WHERE name LIKE 'A%'

这个例子说明 BLOOM 可以生成一个有意义的 SQL 语句。您可以运行其他示例(例如,本教程开头提到的示例)来看看 BLOOM 有多强大。只需记住使用max_tokens 变量增加要生成的令牌数量。

结论

由于其开放访问和多语言特性,BLOOM 被认为是十年来最重要的人工智能模型之一。这项突破性的技术将彻底改变自然语言处理的研究和实践。通过阅读本教程,即使您的计算资源有限,也可以利用 BLOOM 的强大功能来生成文本。此外,您可以使用伟大的拥抱脸transformers库来微调 BLOOM 以执行下游任务,如问题回答和文本分类。如果 BLOOM 的大版本对于您的应用程序或可用的计算资源来说太大,您可以利用拥抱人脸模型库中可用的较小版本的 BLOOM(https://huggingface.co/bigscience)。

在我网站的博客部分有一个 Jupyter 笔记本,里面有本教程的所有源代码:https://arte agac . github . io

用 Python 的 AtExit 在程序退出后运行代码

原文:https://towardsdatascience.com/run-code-after-your-program-exits-with-pythons-atexit-82a0069b486a

注册脚本结束或出错后运行的清理函数

(图片由 Andrew Teoh 在 Unsplash 上拍摄)

在本文中,我将向您展示如何使用 python 的内置模块 atexit 注册程序退出时执行的函数。这意味着您可以在代码退出后运行代码*(由于完成时的错误),为您提供各种必要的工具来执行清理功能,保存数据,并使调试更容易。我们来编码吧!*

1.用简单的例子理解 atexit

主要概念是注册一个在脚本退出时执行的函数。发生这种情况的原因有很多,我们将在后面讨论。让我们从最简单的例子开始,逐渐让它变得更有用。

最简单的例子——注册函数

下面的代码演示了注册出口函数的最基本方法。

在上面的代码中,我们简单地注册了say_goodbye函数,然后调用simple_example函数。当脚本在simple_example()完成后结束时,你会看到say_goodbye执行了。这也可以在输出中看到:

calling the function..
Function enter
Function exit
exiting now, goodbye

轻松点。让我们把它变得复杂一点。

简单的例子——退出循环

我们稍微调整了一下simple_example 函数:它现在包含了一个无限循环,显示“仍在运行”每一秒钟。我们再次注册了say_goodbye函数,只是现在是在simple_example函数的开始。

现在,当我们运行代码时,我们会看到“仍在运行..”每秒发送一条消息。当我们通过按 ctrl-c 退出时,我们看到以下输出:

still running..
still running..
still running..
still running..
still running..
exiting now, goodbye

所以在进入无限循环之前,我们注册了say_goodbye函数。该函数将在解释器终止时执行。

https://medium.com/geekculture/applying-python-multiprocessing-in-2-lines-of-code-3ced521bac8f

2.更简单的多次注册

在前一部分中,我们已经看到了放置atexit.register位代码的位置非常重要。如果我们在 while 循环之后注册函数,那么这个函数将永远不会被注册。

在这一部分中,我们将探索一种注册函数的新方法,这样您就不必担心这个问题。我们还发现你可以注册多个函数

我们可以退出所有我们想退出的,在一个 exit 中注册多个函数是可能的。还有,注册可以简单一点。

更简单的注册装饰

通过用 装饰器 注册函数,你不必担心何时注册函数,因为一旦解释器到达你的函数定义,它们就会发生。它们也非常容易使用:

另一个好处是你的代码更干净;simpel_example()函数没有被 atexit 注册“污染”。如果您想了解更多关于装饰器如何工作以及如何创建自己的装饰器,请查看本文。

注册多个功能

很容易注册多个函数以在退出时执行。重要的是要记住它们是按照注册的相反顺序执行的。查看下面的代码:

您可以通过下面的输出看到订单:

still running..
still running..
# 1 says au revoir
# 2 says later
# 3 says goodbye

注销函数

这就像注册一个函数一样简单:

上面的代码将产生以下输出(注意“# 2”没有显示):

Function enter
Function exit
# 1

您也可以使用atexit._clear()清除所有已注册的功能。

注册带有参数的函数

下面的代码允许您向注册的出口函数传递参数。这对于向您事先不知道的注册函数传递数据非常有用:

上面的代码产生以下输出:

what is your name? mike
Function enter
Function exit-mike says hoi after 0:00:01.755111-mike says hello after 0:00:01.755111-mike says bonjour after 0:00:01.755111-mike says gutentag after 0:00:01.755111

手动触发所有注册的出口功能

下面的代码演示了如何通过atexit._run_exitfuncs()功能手动触发所有已注册的退出功能:

输出如下所示:

start
exiting now, au revoir
exiting now, later
exiting now, goodbye
continue with code

atexit 什么时候运行注册的函数?

好问题。在正常解释器终止时执行退出功能。这意味着它们在你的脚本正常结束时运行,当sys.exit(0) quit()或引发类似raise ValueError("oops")的异常时运行。

异常终止是指程序被非 Python 处理的信号杀死或检测到 Python 致命内部错误的情况。最后一种情况是调用os._exit(0)时;这将在不调用清理处理程序、刷新 stdio 缓冲区等的情况下退出。举个例子:

将产生:

start
exiting now, goodbye

os._exit(0)替换sys.exit(0)的方向盘不会运行say_goodbye功能。

结论

在本文中,我们探索了 Python 的 atexit 函数的内部工作方式,以及如何和何时使用它。

我希望这篇文章像我希望的那样清楚,但如果不是这样,请让我知道我能做些什么来进一步澄清。同时,看看我的其他关于各种编程相关主题的文章,比如:

  • Git 绝对初学者:借助视频游戏理解 Git
  • 创建并发布自己的 Python 包
  • 使用 Docker 和 Compose 环境变量和文件的完整指南

编码快乐!

—迈克

又及:喜欢我正在做的事吗? 跟我来!

https://mikehuls.medium.com/membership

将 Jupyter 笔记本作为后台服务运行

原文:https://towardsdatascience.com/run-jupyter-notebook-as-a-background-service-on-ubuntu-c5d6298ed1e

再也不会丢失远程笔记本服务器,甚至可以让笔记本服务器在系统重新启动时启动

克里斯托弗·高尔在 Unsplash 上拍摄的照片

如何在后台运行 Jupyter 笔记本,而不需要为它们打开一个终端?在本文中,我将向您展示两种方法,一种是使用nohup的简单的一行程序,另一种是使用守护程序服务的更高级的方法。

在本地运行时,避免为您的笔记本电脑打开终端是非常有用的,但在可能暂时断开连接的远程笔记本服务器上更是如此。如果我们可以将笔记本服务器作为一个长期的后台任务作为系统服务来运行,会怎么样?因此我们可以随时连接到它,它甚至可以在任何故障或机器重启时重新启动。

本教程假设你在基于 unix 的系统上,我在 ubuntu 上,并且已经测试了 18.04 和 20.04 版本。第二种方式需要 root 权限,第一种方式不需要。

简单的一行程序

不要使用任何选项来运行jupyter-notebook ...,比如指定所使用的端口,而是在您希望笔记本根目录所在的目录中使用以下内容:

nohup jupyter-notebook --no-browser --port=8888 &

注意命令末尾的&字符,这使得它在后台运行。默认情况下,任何输出都将被写入一个名为nohup.out的文件中,您可以在那里查看笔记本日志。

像任何其他进程一样,这个进程也有一个 PID,以后可以用它来停止。(通常jupyter-notebook stop <port>不会用这种方法。)PID 是在执行上述命令时打印出来的,虽然只是在屏幕上显示,但没有必要记下来,因为以后可以找到它:

您可以检查打开了输出文件的进程的 PID:

$ lsof nohup.outCOMMAND     PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
jupyter-n 44361   username    1w   REG   0,51      884 19846171 nohup.out

或者使用ps查找计算机所有运行进程之间的进程:

$ ps au | grep jupyter

最后,使用

$ kill -9 <PID>

扼杀这一进程。

这相对简单,允许您随时检查该目录中的日志,即使终端会话结束,也能保持笔记本运行。尽管服务器在机器重新启动时也不会重新启动,但是不需要 root 权限。

Avi Richards 在 Unsplash 上拍摄的照片

系统上的守护进程

如果您有 root 权限,您可以使笔记本服务器作为系统服务运行,甚至在重新启动时启动。这是针对基于 linux 的系统,使用内置的服务管理器。

第 1 步:找到您的jupyter-notebook可执行文件的路径

您需要在激活正确的 python 环境后才能这样做。

$ which jupyter-notebook/home/username/.local/share/virtualenvs/notebook/bin/jupyter-notebook

(可选)步骤 1.1:设置笔记本密码和任何其他配置

如果您依赖于安全的密码集,而不是复制服务器在启动时生成的令牌,您会发现以后使用该服务会更容易。

$ jupyter-notebook password[... password prompt, type it in twice] [NotebookPasswordApp] Wrote hashed password to /home/username/.jupyter/jupyter_notebook_config.json

您需要输入两次密码,然后密码以种子格式存储在本地 jupyter config 目录中。

步骤 2:编写服务设置文件

系统服务的设置和属性在类似 INI 的文件中指定。这些存储在/etc/systemd/system/目录中。

我们来写一个服务文件吧!这是一个相对简单的例子,我们已经为 jupyter 指定了可执行文件和参数,包括启动笔记本目录的目录,该目录与执行服务的目录相同。将用户和组设置更改为您自己的用户,确保它不是 root 用户。

注意Restart部分,它定义了如果出现故障,服务应该重启,守护进程等待 60 秒。

步骤 3:启用并启动服务

我们希望将该服务设置文件放入正确的系统目录中,然后“启用”并“启动”该服务。Enable 表示该服务在计算机重启时启动,否则需要手动启动。

# add the service file
$ sudo cp jupyter-notebook.service /etc/systemd/system/# let the daemon reload all the service files
$ sudo systemctl daemon-reload# (optional) "enable" -> started when the computer boots
$ sudo systemctl enable jupyter-notebook.service# start the service
$ sudo systemctl start jupyter-notebook.service

完成后,您可以查看服务状态。请注意,显示状态不需要 root 权限。

$ systemctl status jupyter-notebook

如果你想停止服务,你可以使用sudo systemctl stop ...来禁用启动启动使用sudo systemctl disable ...

第四步:享受!

现在,您有了一个笔记本守护程序服务,它也可以在重新启动时运行,并且您可以随时访问它。如果服务退出,系统会自动重启,这样你就可以安心工作了。

例如,如果您在一台远程机器上运行您的笔记本,比如您的家庭/工作计算机或云中,您只需要通过 SSH 连接到它,并让笔记本启动和运行。

结论

我们已经看到了在后台运行 Jupyter 笔记本服务器的两种方法,一种简单的方法适用于非 root 用户,另一种更高级的方法适用于 root 用户。第一个需要一点监控来启动和停止,而后者应该让你在服务器上一劳永逸。

我在不同的计算机上使用这两种方法,这取决于我拥有的用户权限。例如,第一个在科学计算集群上是最好的,而后者对于 AWS EC2 实例来说是惊人的,该实例用于笔记本和数据分析,可以在任何地方进行。

由乔治·克罗克在 Unsplash 上拍摄

参考和有用的链接

  • man systemd.serviceman systemd.unit提供了系统服务文件选项的综合文档,本是其摘要
  • 这个教程很久以前我第一次使用它来建立一个系统服务,后来在多台机器上进行了修改

使用动态设置在任何地方运行 Python 应用程序

原文:https://towardsdatascience.com/run-your-python-app-anywhere-with-dynamic-settings-aafd27e04b8e

图片来自 Pavlofox 来自 Pixabay

使用配置文件参数化您的应用程序,并使用 ConfigParser 读取

当我们使用 Python 编写应用程序时,我们可能希望它能够在不同的环境中运行。或者,我们希望它在运行时有不同的行为。也就是说,参数化这个应用程序,而不是硬编码一切,因为我们不想改变代码来适应情况。

这可以通过多种方式实现。一种常见的方法是给程序添加参数。这是我以前的一篇文章,详细介绍了这种方法。

然而,使用参数的局限性也是显而易见的。

  • 当我们运行程序时,添加大量的参数是不实际的。
  • 运行时不能更改初始化参数。我们必须重新运行程序来改变参数。
  • 保留值或参数对用户不友好。所以,不容易和别人分享。

当我们至少满足上面的一个约束时,值得考虑使用配置文件。所以,所有的参数都可以物理化成一个文本文件。

在本文中,我将介绍 Python 内置模块之一,名为configparser。它将使我们能够开箱即用地读取和写入配置文件。

1.写入配置文件

图片来自 Pixabay

从读取配置文件开始会更有意义。但是,如果你熟悉我的写作风格,你就会知道,我总是尽量写出可以按顺序进行的文章。因此,我们可以从这个实验开始,首先将配置写入文件。

由于configparser是 Python 3 内置的,所以我们只需要导入它并开始使用它。不需要下载和安装任何东西。

import configparserconfig = configparser.ConfigParser()

这里,我们使用模块中的ConfigParser类初始化一个名为config的对象。因此,我们得到了一个配置对象。

1.1 建立一个配置对象

当我们使用一个config物体时,和使用字典没有太大的区别。当我们想给对象添加一些配置项时,可以像这样添加。

config['PERSON'] = {'name': 'Christopher Tao','age': '34'
}

“顶层”键PERSON将被视为配置文件的一部分。对于PERSON部分,我们定义了一个包含两个条目的字典。然后,我们可以尝试将这个配置对象写入一个文本文件,如下所示。

with open('settings.cfg', 'w') as configfile:config.write(configfile)

这是我们刚刚写好的文件。

就是这样!当然,我们不必一次性提供整个词典。按如下方式逐步构建配置部分是完全没问题的。

config['RUN_PARAMETERS'] = {}
config['RUN_PARAMETERS']['start_time'] = '2020-05-01 00:00:00'
config['RUN_PARAMETERS']['end_time'] = '2020-05-31 00:00:00'
config['RUN_PARAMETERS']['frequency_min'] = '10'
config['RUN_PARAMETERS']['is_active'] = 'True'with open('settings.cfg', 'w') as configfile:config.write(configfile)

然后,该文件将被追加新的部分。

1.2 配置值必须是字符串

然而,与实际的字典相比,一些约束是有目的地添加到配置对象中的。例如,值得一提的是,所有的配置值都必须是字符串。如果我们试图给一个非字符串值如下,它会抱怨。

# Must be string
config['RUN_PARAMETERS']['is_active'] = True

这是有意义的,因为所有的配置值稍后将被写入一个文本文件。强制使用字符串值会降低出错的可能性,保持一致性。

2.从配置文件中读取

图片来自 Pixabay 的 MustangJoe

现在我们可以进入今天的主题了。从配置文件中读取。请注意,文本文件的扩展名并不重要,甚至作为内容的键值对的格式也不重要,这将在本节中详细介绍。

2.1 读取配置对象的参数

在我们想从配置文件中读取之前,我们还需要一个config对象。

config = configparser.ConfigParser()config.read('settings.cfg')

函数将返回一个列表中的配置文件名。这是因为configparser可以将多个配置文件读入一个对象。一旦我们已经阅读了项目,我们也可以使用sections()功能检查所有部分。

config.sections()

如果您没有跳过前面的部分,您可以很容易地获得我们已经写入配置文件的参数。

print(config['PERSON']['name'])
print(config['PERSON']['age'])
print(config['RUN_PARAMETERS']['start_time'])
print(config['RUN_PARAMETERS']['is_active'])

2.2 读取数据类型的参数

配置文件中有一些非字符串参数是很常见的,比如 integer、float 或 boolean。没有什么可以阻止您将它们读入字符串,然后将它们转换成应该的数据类型。类似下面的内容。

int(config['PERSON']['age'])

然而,configparser允许我们将值读入特定的数据类型,而不需要额外的转换步骤。例如,getint()方法将读取整数形式的值,而getboolean()方法将它们读入 bool 类型。

print(config['PERSON'].getint('age'))
type(config['PERSON'].getint('age'))print(config['RUN_PARAMETERS'].getboolean('is_active'))
type(config['RUN_PARAMETERS'].getboolean('is_active'))

2.3 回退值

有时,配置文件本身也可能是动态的。期望的功能之一是,我们可能希望用户只需要添加必要的参数,而不是一切。但是,对于那些不存在的参数,它会引发一个KeyError

# Fallback Values
config['PERSON']['middle_name']

解决方案与普通词典非常相似。我们可以使用get()函数来获取键的值,并在没有值时提供一个后备值。

config['PERSON'].get('name', '')
config['PERSON'].get('middle_name', '')

在上面的例子中,当我们试图获取name时,它存在,因此我们可以取回值,而键middle_name不存在,因此空字符串将被用作回退值。

2.4 多级价值获取

我们还可以使用get()方法直接从 config 对象中获取键值,这意味着我们也可以将节名放入方法中。

# Multilevel
config.get('PERSON', 'name')

当我们使用上面的get()方法时,我们也可以显式地定义 fallback 值,如下所示。

config.get('PERSON', 'middle_name', fallback='I do not have middle name')

值得一提的是,多级特性也可以与“获取数据类型”方法一起使用。

print(config.getint('PERSON', 'age'))
type(config.getint('PERSON', 'age'))

2.5 检查密钥是否存在

最后,就像 Python 字典一样,我们也可以检查一个键是否存在于一个节中,如下所示。

# Check key
'name' in config['PERSON']
'middle_name' in config['PERSON']

3.默认部分

图片来自 Pixabay 的迈克尔·施瓦森伯格

configparser中有一个神奇的版块,就是DEFAULT版块。当配置文件有默认节时,可以从任何节访问该值。

让我们通过将DEFAULT部分写入配置文件来构建一个示例。

config['DEFAULT'] = {'version': '1.0','author': 'Christopher Tao'
}with open('settings.cfg', 'w') as configfile:config.write(configfile)

然后,如果我们试图列出 config 对象中的所有部分,我们会发现默认部分不会在那里。

但是,可以证明它肯定是存在的。

for key in config['DEFAULT']:print(key, '=', config['DEFAULT'][key])

这是configparser默认部分的特性,正如我之前所说的,默认部分中的项目可以从任何其他部分访问。如果我们尝试在其他两个部分列出所有的键值对,我们会发现它们都存在。

for key in config['PERSON']:print(key, '=', config['PERSON'][key])for key in config['RUN_PARAMETERS']:print(key, '=', config['RUN_PARAMETERS'][key])

4.支持的键值对格式

图片来自 Pixabay 的迈克尔·施瓦森伯格

对键值属性使用等号=在配置文件中很常见。然而,在不同的标准中确实使用了其他格式。configparser模块的美妙之处在于我们可以发现它支持几乎所有的流行风格。

让我们如下定义另一个配置文件。然后,命名为examples.cfg

[Equal With Padding]
name = Christopher Tao[Equal]
name=Christopher Tao[Colon]
name: Christopher Tao[Multiline]
name = Christopher 
Tao[No Values]
key_without_value
empty key =[Comments]
# This is comment
; This is comment, too# Empty line is OK [Indented Section]name=Christopher Tao

在这个示例配置文件中,混合了多种不同的样式。如果我们尝试读取文件,所有的场景都可以处理得很好。

config = configparser.ConfigParser()
config.read('examples.cfg')
config.sections()

等号和冒号都可以。

# name=Christopher Tao
config['Equal']['name']# name: Christopher Tao
config['Colon']['name']

当值中存在换行符时,可以正确捕获。

# name = Christopher 
# Tao
config['Multiline']['name']

有评论的时候会忽略。因此,对于[Comments]部分,不存在键值对。

# [Comments]
# # This is comment
# ; This is comment, too
# # Empty line is OK
len(config['Comments'])

如果一个节是缩进的,或者在节头或键的前面有意外的空格,就不会有任何问题。

#     [Indented Section]
#         name=Christopher Tao
config['Indented Section']['name']

摘要

图片来自 Pixabay 的诺尔·包萨

在本文中,我介绍了一个名为configparser的 Python 内置库。它允许我们动态地从文本文件中读取和写入参数。它还提供了许多现成的特性,例如将值读入某些数据类型和回退值。它还支持多种键值对格式,可以很好地处理注释、空键和无用的缩进。

https://medium.com/@qiuyujx/membership

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

除非另有说明,所有图片均出自作者之手

借助 Spark-on-Kubernetes 大规模运行您的 R (SparklyR)工作负载

原文:https://towardsdatascience.com/run-your-r-sparklyr-workloads-at-scale-with-spark-on-kubernetes-3db4f26d3348

教程:如何建立正确的 Docker 映像,开始您的 Spark 会话,并大规模运行!

r 是一种用于统计计算的编程语言。它被统计学家和数据科学家广泛使用。长期以来,在单台机器上运行应用程序已经足够了,但是当需要更多数据和高级分析时,这就成了一个限制因素。

这就是为什么 R 社区开发了 sparklyr 来使用 Apache Spark 扩展数据工程、数据科学和机器学习。它支持 Apache Spark 用例:Batch、Streaming、ML 和 Graph、SQL,此外还有众所周知的 R 包:dplyr、DBI、broom。更多信息可以在 sparklyr.ai 上找到。

Spark lyr 如何建立在 Spark 之上(来源: sparklyr.ai ,根据 Apache License 2.0 授权商业使用转贴)

问题是,Sparklyr 和 Apache Spark 之间的集成很脆弱,很难得到库和环境设置的正确组合。我们的一个客户试图让它在 EMR 上工作,并将其描述为“一场噩梦”。相反,通过构建他们自己的 Docker 映像并在我们的 Spark-on-Kubernetes 平台上运行,他能够使他的 SparklyR 设置可靠地工作。

因此,让我们看看如何使用 Spark-on-Kubernetes 让您的 SparklyR 应用程序大规模运行!本教程的所有代码都可以在这个 Github 库上获得。

要求

您必须配置 Docker 映像。这是最困难的部分,但我们为你做到了!下面的 dockerhub 文件使用了我们发布的一张图片作为基础——参见这篇博客文章和我们的 dockerhub 资源库,了解关于这些图片的更多细节。‍

作者代码。全公开回购。

您可以在 RUN install2.r 部分调优您的包。 Tidyverse 包含了很多众所周知的包,比如 dplyr,ggplot2。一旦您的映像被构建并在注册表中可用,它就包含了您所有的依赖项,在您运行应用程序时需要几秒钟的时间来加载。

开发您的 SparklyR 应用程序

首先,我们将向您展示一些代码示例。您可以在 sparklyr github repo 中找到更多示例。有两个关键话题:

  • 创建 Spark 会话
  • 理解 R 对象是 Spark 数据帧或 R 数据集的接口。

有经验的 Sparklyr 开发者可以查看 Spark 会话的创建,然后直接切换到大规模运行 Spark 应用

创建 Spark 会话

作者代码。全公开回购。

如何操作你的 R 对象和火花数据帧

没有比阅读代码示例更好的学习方法了(见下文)!以下是需要注意的主要事项:

  • sparklyr copy_to 函数返回对生成的 Spark 数据帧的引用,作为 tbl_spark 。返回的对象将作为底层 Spark 表的 dplyr 兼容接口(见文档)。
  • 您可以使用 spark_apply 将 R 函数应用于 Spark 数据帧
  • 您可以通过调用 tbl_cache (或 tbl_uncache )显式缓存(或取消缓存)Spark 数据帧
  • 可以用 dbGetQuery 用 SQL 查询 Spark 表
  • 你可以用 spark_read_parquet (或 spark_write_parquet )读取(或写入)镶木地板表格
  • 您可以使用 ggplot2 包绘制您的 R 对象。
  • 不要忘记在应用程序代码结束时用 spark_disconnect 关闭 Spark 会话。您仍然可以在这一行之后运行 R 代码,但是不能使用 Spark 运行任何分布式命令。

作者代码。完全公开回购。

R‍un 你的星火大规模应用

您必须首先通过模板或 configOverride 定义一个数据机制配置。对于开源的 Spark-on-Kubernetes 用户来说,很容易适应这种配置,特别是如果你使用开源项目 Spark-on-Kubernetes 操作器。

示例数据机制配置(JSON)。来源:作者。

要执行的‍The 代码在文件 rexamples 中。这就是为什么 mainApplicationFile 指向 Docker 映像内部的本地路径。

然后,您可以使用 Delight 来监控和优化您的 Spark 应用程序,这是一个适用于 Spark 的开源监控 UI,可以在任何 Spark 平台(商业/开源、云/本地等)上运行。

来自 Delight UI 的截图。来源:作者。

特别感谢在 Data Mechanics 平台上运行 SparklyR 工作负载的客户分享他们的技巧和设置。我们希望本教程能帮助你成功使用 Spark 和 R!

最初发表于【https://www.datamechanics.co】

在不到 10 分钟的时间内运行 Spark 作业,无需基础架构

原文:https://towardsdatascience.com/running-a-spark-job-in-less-than-10-minutes-with-no-infrastructure-fe79f1c41780

大数据|云计算|数据工程

关于使用 Google 云平台设置 Spark 的快速实践教程

泰勒·维克在 Unsplash 上的照片

Apache Spark 是一个分布式数据处理系统,使我们能够处理高速数据管道。Apache Spark 还为 SQL、机器学习和数据科学以及图形计算提供了库。

Spark 一次可以处理数 Pb 的数据,比 Hadoop 的 MapReduce 快得多(快 100 倍)。

Spark 最常用于 Hadoop 集群之上,设置本地 Hadoop 集群需要相当多的来回操作。这是一个冗长而耗时的过程。

当我在为我的硕士学位进行实验时,我发现自己需要更多的计算能力来执行我的任务。我记得我试图使用我们实验室周围的几台旧 PC 来建立我自己的 Hadoop 集群,但这个过程非常费力,尤其是对于没有基础设施系统背景的人来说。

因此,本教程的目的是帮助那些希望在分布式集群上快速、廉价地执行 spark 任务的人。我想记录下当时对我有很大帮助的过程!

在本文中,我们将讨论如何利用云计算在不到 10 分钟的时间内启动并运行我们的第一个 Spark 作业!我们将使用 GCP 的云数据系统来提高时间和效率。

那么,部署 Spark 集群的过程是什么样的呢?

  • 第一步: 前往 GCP,搜索 Dataproc
  • 第 2 步: 调配一个 Apache Hadoop 集群

GCP Dataproc 集群部分。图片作者。

  • 第三步: 命名并选择集群属性——对于试点项目,您也可以保留默认属性
  • 步骤 4: 在作业部分,点击提交作业
  • 第五步: 填写工作详情。将作业类型设置为 Spark,并链接到您的 Spark 类(以及您的。jar 文件)

作为一个例子,您可以尝试这个近似圆周率值的火花工作。

  • 步骤 6: 确保 Spark 作业现在在作业部分下可见

GCP 数据公司工作部门。作者图片

  • 第七步: 等待作业执行。请注意,您还可以单击集群来监控其资源使用情况,并查看当前正在执行的作业
  • 步骤 8: 一旦作业执行完毕,您还可以关闭集群以节省资源——除非您需要持久数据。

仅此而已。设置集群和 Spark pi 任务,只花了我不到 4 分钟的时间。Spark 作业在 37 秒内执行(使用具有默认属性的集群)。

你喜欢这篇文章吗?如果是,请考虑订阅我的电子邮件列表,以便在我发布新内容时得到通知。

https://david-farrugia.medium.com/subscribe

此外,考虑成为会员,使用我下面的推荐链接来支持我和你在 Medium 上喜欢的其他作家。每月 5 美元,你就可以无限制地阅读 Medium 上的每一篇文章。

https://david-farrugia.medium.com/membership

想给我买杯咖啡吗?

https://paypal.me/itsdavidfarrugia?country.x=MT&locale.x=en_US

想联系吗?

我很想听听你对这个话题的想法,或者其他什么。如果你想联系我,请发邮件到 davidfarrugia53@gmail.com给我。

Linkedin——Twitter

使用 Gitlab CI/CD 运行 dbt

原文:https://towardsdatascience.com/running-dbt-using-gitlab-ci-cd-8a2ef0f05af0

免费部署、运行和安排 dbt 的最简单方式

由 Samuel Sianipar 在 Unsplash 拍摄的照片

我第一次实现 dbt 是在 Sirena 管理数据团队的时候,我立刻成为了它的超级粉丝。我们用它来运行我们所有的转换,并在我们的数据仓库中创建我们的模型(雪花)。能够将维度建模应用于我们的数据,尤其是有大量非结构化数据来源的数据,确实是一个游戏规则的改变者。更好的是,我们所有的模型和业务逻辑都受版本控制,变化完全可见,协作极其容易。不过,我最喜欢的部分可能是它在原始数据和业务实体之间创建的抽象层。例如,我们可以创建一个dim_customers模型,并从生成模型的原始数据中完全提取出我们公司客户的唯一真实来源。对于我们的利益相关者来说,他们在 BI 工具中使用的表格是来自我们的 CRM、产品数据库、ERP 还是客户成功软件并不重要。重要的是,在这张表中,他们可以找到我们客户的所有信息,这对他们来说是完全透明的。如果我们的数据源上游发生了变化,我们作为一个数据团队可以通过这个抽象层修复这些变化。更令人惊讶的是,希望没有人必须处理这一点,它允许我们在数据源中进行巨大的更改(例如 CRM 迁移或同时运行多个 CRM),同时最小化对我们的 BI 层的影响(是的,我有一些战斗伤疤)。哦,还有,所有这一切都得益于 SQL 的简单性。太神奇了。

正如我提到的,我们对 dbt 项目进行版本控制,为此我们使用了 Gitlab。当我看到 Gitlab 数据团队的视频解释他们如何使用 Gitlab CI 运行 dbt 时,这变得非常有趣。同时,Gitlab 作为一家开源公司,让他们的 dbt 项目的所有代码完全可用。我建议你在那里花一点时间,很多有用的东西。

在这篇文章中,我将详细介绍如何使用 Gitlab 的 CI/CD 来“部署”您的 dbt 项目。注意,使用 Github 动作可以实现类似的工作流程。

入门指南

Gitlab 的 CI/CD 工具非常容易使用,你需要做的就是在你的库的根目录下创建一个名为.gitlab-ci.yml的文件。这个文件基本上是 Gitlab 应该如何执行管道的配方。在本帖中,我们将回顾我们可以实现的最简单的工作流,重点是在生产中运行 dbt 模型。我将在后面的文章中讨论如何进行实际的 CI/CD(包括测试)、生成文档和存储元数据。现在,我们的目标是能够每天运行dbt build,这样我们所有的模型都是最新的。

这是一个使用 Gitlab 的 CI/CD 运行 dbt 的最简单设置之一的.gitlab-ci.yml文件示例:

我们首先定义希望在管道中运行的阶段。在这种情况下,我们将只有一个阶段称为deploy-production。如果我们现在忽略.gitlab-ci.yml文件的中间部分,直接跳到底部,我们可以看到我们定义了这个阶段实际做什么:

因为我们将when参数( docs )定义为只有manual,这个阶段只有在通过 Gitlab 的 UI 触发后才会运行。除此之外,stage 还定义了一个名为TARGET_NAME的变量,其值为postgres(稍后会详细介绍)。当谈到这个阶段实际上做什么时,它只是扩展了.deploy中的定义。同时,.deploydbt_jobs的定义延伸而来,也就是.dbt_run。这由下面一行指定:<<: *dbt_jobs,它实际上插入了dbt_jobs定义。

查看.dbt_run,我们看到我们定义了运行所有内容的映像,在本例中是python:3.8.1-slim-buster Docker 映像( docs )。之后,我们运行一些脚本来安装依赖项,并定义一个名为CI_PROFILE_TARGET的变量。为此,我们使用之前定义的TARGET_NAME变量。在这种情况下,CI_PROFILE_TARGET变量看起来会像--profiles-dir . --target postgres。你大概可以看到这是怎么回事。我们可以在运行 dbt 命令时使用这个变量来指定到我们的profiles.yml的路径和我们想要使用的目标。

profiles.yml而言,我们可以使用与相似的设置,使用 docker 运行 dbt,从 env 变量获取数据仓库凭证。

使用 Gitlab 的 CI/CD 变量设置这些变量非常容易:

在 Gitlab 中添加 CI/CD 变量(图片由作者提供)

之后,我们终于可以看一看.deploy了。由于添加了 0.21.0 中引入的dbt build 命令,我们可以简单地安装依赖项,然后运行dbt build命令,该命令将根据我们的 dbt DAG 按照运行模型、测试、快照和种子的顺序来处理它们。

就这样,如果我们将代码推送到 Gitlab,我们应该会看到一个新的管道被创建,我们可以手动触发它(记住,因为有了when: manual配置)。一旦我们这样做了,我们的 dbt 项目就会运行。

在 Gitlab 中检查 CI/CD 管道(图片由作者提供)

安排 dbt 每天运行

使用这个设置,至少有两种方法可以安排 dbt 每天运行。第一种方法是使用 Gitlab 内置的流水线调度,第二种方法是使用 Gitlab 的 API 触发流水线。

流水线调度

这可能是最简单、最直接的方法。在 Gitlab 的 CI/CD 部分下,有一个用于创建管道计划的部分。

您可以按照说明每天运行管道,或者以任何频率运行您的 dbt 模型。

通过 API 触发管道

安排管道的另一种方式是使用您当前正在使用的任何编排工具,例如气流或 Dagster 。这还有一个额外的好处,就是可以与数据管道的其余部分集成在一起。使用它,您可以在数据加载到仓库后触发 dbt 构建。

您可以在这里找到用于触发管道的 API 文档,但是基本上您需要做的就是创建一个触发令牌,并在对 URL: https://gitlab.example.com/api/v4/projects/<project_id>/trigger/pipelinePOST请求中使用它。这种方法的一个惊人的特性是,您可以将变量传递给管道。这意味着,当数据管道的不同部分已经加载时,您可以触发 dbt 的构建。

以下是如何使用 Python 触发管道的示例:

请记住,要做到这一点,您需要移除when: manual条件。

进一步的改进

希望这篇文章向您展示了如何将 Gitlab CI/CD(或 Github Actions)与 dbt 结合使用。然而,我希望这能成为灵感,因为有很多方法可以利用这一点。例如,在 Sirena 和 Zenvia 中,我们使用此工作流来利用雪花零拷贝克隆进行实际的 CI/CD。每当一个合并请求(或拉请求)被创建时,它将触发一个管道来克隆我们的雪花数据库,并在其上运行代码更改和测试。这给了我们很大的信心,我们的改变不会引入任何问题。我们使用这个工作流实现的另一件事是存储元数据并生成 dbt 文档来记录我们的数据仓库。如果这一切听起来很有趣,请考虑在媒体上关注我,因为我将在未来创造更多关于这方面的内容。

跑得比以往任何时候都快

原文:https://towardsdatascience.com/running-faster-than-ever-before-afd1d213a3ae

Python 3.11 与 Python 3.10 和 Julia 1.7 相比表现如何?

肯尼·埃利亚松在 Unsplash 上的照片

性能并不总是数据科学家优先考虑的事情。然而,随着我们手上的数据量不断增加,更快地完成计算不是很好吗?即将到来的 Python 3.11 版本被寄予厚望,因为与当前稳定的版本 3.10 相比,预计性能会提高 10-60%。我真的对这一声明很感兴趣,我想尝试一下我的应用程序的新版本,这些应用程序主要集中在蛋白质组学和质谱学上。

在这篇文章中,我关注了截至 2022 年 6 月的当前 Python 3.10 和 3.11 测试版的性能。与 MS 相关的函数包括从磁盘读取文本文件,对字符串和字典的操作,以及对 numpy 数组的循环和操作。这些操作非常通用,因此这些函数的性能应该反映一般的性能趋势。

既然我们在这里谈论速度,我在想,我们为什么不也比较一下 Python 3.11 和 Julia 的性能。它是一种正在积极发展的编程语言,是专门为科学计算设计的,考虑到了可伸缩性和性能。Julia 的语法与 Python 并没有太大的不同,这使得它对于希望进一步扩展其计算工具箱的数据科学家来说是一种非常有吸引力的语言。

如果您希望直接查看基准测试的结果,请随意跳到文章末尾的总结部分。

设置

这些测试已经在 Kubuntu 22.04 中用 Python 3.10.4、Python 3.11 beta3 和 Julia 1.7.3 运行过。最初,我在 Jupyter 笔记本上运行 Python 3.10 和 Julia 测试,然而,我在安装 3.11 测试版的所有必要依赖项时遇到了一些困难。因此,我通过运行脚本完成了对两个 Python 版本的测试。

代码、笔记本和示例数据可以在 GitHub 库中找到。

读取和解析文本文件

第一个函数从光盘中读取一个文本文件,将 MS 数据解析到一个字典中,该字典包括文本字符串、数值和 pandas dataframes。函数 load_mgf 的完整代码相当长,你可以在的脚本中找到。该函数转换一个纯文本文件,如下所示:

一个对象列表(字典),每个代表一个质谱,包含文本、数字数据和一个pandasdata frame*‘ms _ data’*,如下所示:

Github 存储库中的示例文件包含 1000 个项目(光谱):

1000

在库 timeit 的帮助下,我们在 Python 的两个版本中重复运行这个函数:

Running version:
3.10.4 (main, Apr  2 2022, 09:04:19) [GCC 11.2.0]
Timing the load_mgf function:
Mean time 251.7 ms, standard deviation 7.5 ms for 200 repeatsRunning version:
3.11.0b3 (main, Jun  1 2022, 23:49:29) [GCC 11.2.0]
Timing the load_mgf function:
Mean time 217.8 ms, standard deviation 8.6 ms for 200 repeats

我们观察到 Python 3.11 的处理时间减少了 10%以上!这非常令人兴奋,因为我们不需要以任何方式更改代码就可以获得这种性能提升!

让我们在 Julia 中实现相同的功能,尽可能地模仿 Python 函数的逻辑。使用 @benchmark ,看看有多快:

Julia 的性能证明在这个基准测试中得到证实,平均运行时间不到 Python 的一半!看起来很有希望!

循环和字典操作

下一个函数从列表中读取文本字符串,使用字典匹配字符,并计算相应值的总和。对于质谱分析人员来说,这个函数从列表中计算肽的质量。

让我们准备一个 10,000 个肽(字符串)的列表,每个肽由 20 个氨基酸残基(字符)组成,指定为单独的大写字母:

10000
'FFKGSQDTGYTYFNFMSHFY'

我们现在可以使用普通循环来计算列表中每个序列的质量。每个可能的残基对应一个数字质量值,我们可以使用字典来指定:

另一种更简洁的方法是使用 functools 包中的 reduce 函数:

让我们用两个版本的 Python 对函数进行基准测试:

Running version:
3.10.4 (main, Apr  2 2022, 09:04:19) [GCC 11.2.0]
Timing the calculate_masses_loop function:
Mean time 11.83 ms, standard deviation 0.97 ms for 200 repeats
Timing the calculate_masses_reduce function:
Mean time 24.15 ms, standard deviation 1.95 ms for 200 repeatsRunning version:
3.11.0b3 (main, Jun  1 2022, 23:49:29) [GCC 11.2.0]
Timing the calculate_masses_loop function:
Mean time 7.90 ms, standard deviation 0.88 ms for 200 repeats
Timing the calculate_masses_reduce function:
Mean time 19.65 ms, standard deviation 1.72 ms for 200 repeats

Python 3.11 在基于循环的函数上快了 49%!不幸的是,聪明的calculate _ mass _ reduce实现通常要慢得多,但是 Python 3.11 在这个函数上仍然比 3.10 版本快 18%。

这些计算应该在 Julia 中变得更快吗?让我们创建一个类似的循环函数,它将计算每个序列的质量,并在一个 10,000 长的序列列表上对其进行基准测试:

令人惊讶的是,这个实现比 Python 中的函数慢多了!我们可以通过预先分配 masses 数组来优化代码,而不是在每次迭代中添加一个新的单元素数组。让我们看看这是否有所不同:

这两种实现在 Julia 中略有不同,但 Python 3.11 是这一轮的明显赢家!

数值数组上的运算

谈到 Python 中的数字运算,我们当然希望避免多级 for 循环和重复的 if-else 语句。因此,在实现一个用于处理大量实验质谱数据的函数时,我们将使用 numpy 数组对逻辑进行矢量化。完整的功能 find_matches 可以在脚本中找到[。该算法的核心部分采用数值,作为 pandas 系列 *s'ms_data']['m/z']* 引入,并对相应的 numpy 数组执行一系列操作:

让我们使用我们之前通过 load_mgf 加载到内存中的 1000 MS 光谱对函数 find_matches 进行基准测试。重复运行该函数,我们得到:

Running version:
3.10.4 (main, Apr  2 2022, 09:04:19) [GCC 11.2.0]
Timing the find_matches function:
Mean time 2.08 s, standard deviation 89.2 ms for 50 repeatsRunning version:
3.11.0b3 (main, Jun  1 2022, 23:49:29) [GCC 11.2.0]
Timing the find_matches function:
Mean time 2.07 s, standard deviation 26.0 ms for 50 repeats

两个版本的平均时间惊人地相似。也许,在 3.11 的测试版中,numpy 代码没有太大的变化。这将是很有趣的,看看它是否会被修改。

在 Julia 中实现一个类似的函数,我们可以在数组s[' ms _ data '][' m/z ']【T21]上重复上面 Python 代码中相同的操作。在 Julia 代码中,矢量化运算以点为前缀:

上面的基准测试结果显示,Julia 中的函数比 numpy 中快一倍,但这并不是终点。Julia 允许将数组操作融合到一个循环中,避免分配临时的中间数组。融合操作以“at-dot”宏为前缀:

做了这一点小小的改变后,让我们对结果函数 matchesfuse 进行基准测试:

融合进一步削减了 60%的运行时间!由此,Julia 完全主导了数组操作基准测试,优化后的函数运行速度比 Python/numpyanalog 快 5 倍!这个令人印象深刻的表演真的激励我,至少对我来说,投入更多的时间去研究朱莉娅。

摘要

我们在基本操作(循环、字符串操作、算术运算)和数值数组的计算中测试了 Python 3.11 beta,所有这些都是在质谱数据的上下文中进行的。我们将 3.11 与当前的 Python 版本 3.10.4 以及最新的 Julia 1.7.3 进行了比较。测试结果汇总如下图所示:

质谱相关基准功能的运行时间总结。作者图片

与 Python 3.10 相比,新的 3.11 在循环、字符串和字典操作等一般操作上提供了显著的性能提升,完成基准测试的速度提高了 10–49%。与此同时,使用 numpy 的计算在两个 Python 版本中花费的时间完全相同,而 Julia 在同一组数值计算的速度上提供了 2 到 5 倍的显著提升。然而,在 Python 中,使用循环和字典匹配的函数工作得更快,尤其是在新版本 3.11 中。

在 Docker 容器上运行 Jupyter 笔记本

原文:https://towardsdatascience.com/running-jupyter-notebooks-on-docker-containers-47862f6b96a0

与 SageMaker Studio Lab 和 Docker 合作的项目

伊恩·泰勒在 Unsplash 上拍照

这篇文章的目标是在 AWS 上运行数据科学工作流,然后使用 Docker 发布它,从而创建一个端到端的机器学习任务。

此外,我将更多地关注“如何”对数据科学项目进行分类,而不是“为什么这个项目很酷”。也就是说,使用 Docker 有很多的好处:

  • 轻便
  • 表演
  • 灵活
  • 隔离
  • 可量测性

另一方面,AWS SageMaker Studio Lab 提供了 SageMaker 的强大功能,无需显式定义每个子流程。

挑选数据集

对于这个项目,我们将使用来自斯坦福网络分析项目( SNAP )的 2,441,053 个产品的 6,643,669 个用户的 34,686,770 条亚马逊评论。这些数据是在 BSD 许可下发布的,学术和商业用途都是免费的。

使用的数据是在 Kaggle 上找到的数据的子集。它包含 1,800,000 个训练样本,200,000 个测试样本,因此每个评论要么是“正面的”,要么是“负面的”。

https://www.kaggle.com/datasets/kritanjalijain/amazon-reviews

由于这是一个大型数据集,并且我们正在使用 AWS,因此数据存储在 S3 存储桶中。此外,确保您正在使用的 bucket 和 AWS 服务在同一个区域中。对于这个项目,选择的地区是美国东部-2 (美国东俄亥俄州)。

IAM:了解你的角色

使用 AWS,一个常见的缺陷是没有所需的权限,或者不知道您的权限范围。转到身份和访问管理 (IAM),创建一个角色,并为其附加以下策略:

  • 亚马逊 3FullAcess
  • AmazonSageMakerFullAccess
  • awsglueconsolesagemakernotebook full access
  • AWSImageBuilderFullAccess
  • AmazonSageMakerPipelinesIntegrations
  • amazonseagemakergroundtrutheexecution

为什么选择 SageMaker Studio Lab?

SageMaker Studio Lab 提供了一个轻量级环境,可以比在 SageMaker 上更快地执行任务。它也有一些缺点,例如无法访问 AWS Data Wrangler,也没有大规模的分布式培训。

要开始使用 SageMaker Studio Lab,您只需要一个 AWS 帐户,然后等待大约 24 小时,让您的帐户获得批准。一旦进入实验室,环境看起来就像一个 Jupyter 笔记本。

你可以在这里申请一个免费账户:【https://studiolab.sagemaker.aws/

开始会话

下面的代码简介是连接到您的 AWS 资源的标准方式,并定义了基本资源。可以把它看作是开始使用 AWS 的一种方式。

预处理步骤

在 SageMaker Studio 中,第一步是编写一个预处理脚本,如下所示。这个脚本和所有后续脚本需要包含所有必需的库,并且能够独立运行。

此外,在 ML 工作流中采用的思维模式是“t his 将在其他人的机器上运行”。因此,在 Jupyter 笔记本环境中编写的内容能够包含在一个简洁的 python 脚本中是至关重要的。

对于 SageMaker 的入门者,记得坚持规定的目录格式:“ /opt/ml/… ”。事实上,“/opt/ml”及其所有子目录都由 SageMaker 根据文档保留。例如,“ /opt/ml/model/ ”是您编写算法生成的模型的目录。

培训脚本

在预处理之后是训练,就像前一部分一样包含在脚本中。特定的模型没有建立正确的工作流重要。一旦模型按预期运行,请随意插入您选择的算法。

模型评估

数据完全平衡:50%正,50%负。因此,精确度是一个足够的度量。精确度和召回率也包括在内,以发现预测中的任何问题。

在任何参数优化之前,准确率徘徊在 80%,精度/召回率也是如此。

使用 FrameworkProcessor 处理作业

SageMaker 处理模块允许我们使用一个框架处理器来添加依赖项,该处理器允许一组 Python 脚本作为处理作业的一部分运行。此外,它允许处理器访问一个目录中的多个脚本,而不是只指定一个脚本。

运送到码头

现在我们的工作流程运行顺利,是时候发货了!首先在实验室中创建一个名为 docker 的目录,并编写 docker 文件来创建处理容器:

下一步是使用 docker 命令构建容器,这会创建一个弹性注册容器(ECR)并推送 docker 映像:

附言如果你使用的是苹果 M1 电脑或更新的电脑,确保在构建 docker 镜像时明确地调用你的平台。

运行 Docker 容器

首先我们调用 ScriptProcessor 类,它允许您在容器中运行命令,现在我们可以运行以前的相同脚本,只是它们在 docker 容器中。

就这样,我们成功地在 docker 容器上运行了一个处理作业。为了简洁起见,没有显示训练和评估容器,因为它们遵循相似的步骤。

结论

借助 AWS 服务和 Docker,我们能够将 python 代码推入容器,并将数据科学工作流产品化。

如果您有兴趣查看完整的代码和输出来验证您自己的工作,请查看下面的 Github repo:

https://github.com/NadimKawwa/amazon-review-docker/blob/main/README.md

在云中运行无服务器应用程序—教程

原文:https://towardsdatascience.com/running-serverless-applications-in-the-cloud-a-tutorial-2b5b38457d8d

为什么没有服务器?又是怎么做到的?AWS ECS 的实际应用

作者照片

在这篇文章中,我们将在 AWS 上设计和部署一个 FastAPI 应用程序。

我们将使用无服务器计算服务和托管数据库服务来设计应用程序。这种微服务架构有助于构建一个解耦系统,从而提高健壮性。接下来,我们使用 AWS CDK 将我们的整个基础设施捆绑成代码。这样做的好处很多。简而言之,它使部署和基础设施更新更加容易。它允许在 VCS(版本控制系统)如 git 中提交定义基础设施的整个代码。

但是什么是无服务器,我们为什么需要它?

无服务器简介

AWS 提供了几个无服务器计算选项。有了无服务器计算,我们无需担心服务器的管理和配置。安装补丁、更新和安全修复等维护任务完全消失了。这释放了时间和资源。我们也不需要担心容量供应,因为如果负载增加,AWS 会自动扩展实例。无服务器计算选项提供随用随付的定价模式。这意味着我们只为我们实际使用的计算时间付费。根据用例,这可以降低运行我们软件的相关成本。

EC2 上的 Docker 和对 ECS 的需求

在介绍这个架构之前,我们先看看如何使用简单的虚拟服务器(AWS EC2)在 AWS 中运行一个容器化的应用程序。

涉及的步骤有:

  1. 构建 Docker 映像
  2. 部署 EC2 实例
  3. 管理 Docker 应用程序和 EC2 实例
  4. 为 EC2 实例付款

这似乎很简单。但是也有一些不利的方面。

首先,我们需要管理我们的 EC2 实例。所以随着时间的推移安装更新和补丁。其次,我们需要管理 Docker 应用程序。万一容器停止工作,或者 FastAPI 版本需要更新,我们需要手动更新容器。这可能会很麻烦,因为正在运行的容器需要停止。

另一点是规模。生产系统是由数百个容器组成的大规模系统。使用上述方法同时运行几个容器是不可行的。我们需要分别管理每个容器。例如,确保容器平稳运行(健康检查),并且它们可以安全地相互通信。或者在不危及整个应用程序的情况下更新容器使用的图像。如果用户需求增加,我们如何处理增加容器数量的用例?类似地,对于如此多的容器,负载平衡变得至关重要,因为我们不想让选定的几个容器不堪重负,而让其他容器闲置。

AWS ECS 可以帮助我们解决所有这些问题,甚至更多。

AWS ECS

为了简单起见,我们只考虑 Fargate 上的 AWS ECS,不考虑 EC2。

弹性集装箱服务。这是一个容器编排服务,允许我们运行和管理容器化的 Docker 应用程序。对于可能有数百个容器的大型工作流,管理它们既具有挑战性又非常耗时。这里有一张解释 ECS 的图表。

用 Fargate、服务和任务说明 AWS ECS。图片作者。

ECS 由以下组件组成:

  • 集群——这只是一个被称为容量提供者的 Fargate 实例的逻辑分组。任务在运行前被放入集群。
  • AWS Fargate — Fargate 与 ECS 集成,并“在幕后”提供无服务器计算服务。Fargate 本质上运行我们的 Docker 容器,而我们不必担心管理服务器。
  • 服务—服务允许您指定希望运行多少任务,是否希望启用负载平衡等。一个集群中可以有多个服务。例如,您可以让一个服务处理所有生产流量(生产环境),另一个服务处理测试/开发流量(测试环境)。上图中,您可以看到集群中运行着两个服务— 服务 1服务 2 。任务在服务内部运行。
  • 任务定义——这是一个用 JSON 编写的模板文件。它就像一个蓝图,指定运行什么容器、内存和 CPU 规格、应该打开什么端口以及其他配置,如使用什么 Docker 映像。本质上,它定义了要运行的实际代码。
  • 任务—这是任务定义的实例。它可以是挂起、运行或停止。正在运行的任务意味着任务定义中指定的所有容器都正在运行,即您的应用程序正在运行。
    还可以运行几个任务来处理应用程序的大负载。在上图中,有两个任务 A 的实例在服务 1 中运行。

架构图

架构图如下所示:

AWS 架构图。图片作者。

首先,我们使用虚拟私有云(VPC)。这是我们专用的 ip 地址集合,与我们的 AWS 帐户相关联。一个因特网网关被连接到 VPC,以便于与因特网的连接。

FastAPI 应用程序将在公共子网内的 ECS 上运行。PostgreSQL 数据库将在私有子网内的 RDS(关系数据库服务)上运行。RDS 只是 AWS 提供的一项托管数据库服务,意味着 AWS 为我们管理数据库。

用户请求被路由到 ECS,因为它位于公共子网内。在本教程中,这是通过简单的 HTTP,端口 80 完成的。对于所有实际使用案例,这应该在 HTTPS 端口 443 上完成。RDS 禁止任何公共访问。这是因为它存储了敏感的用户数据。但是,由于 ECS 和 RDS 在同一个 VPC 中,所以 ECS 可以与 RDS 通信来存储和检索数据。这是通过默认的 PostgreSQL 端口 TCP: 5432 完成的。

密码

完整的回购代码是 这里的

这篇文章假设你的系统已经安装了 AWS CLI 和 CDK。
如果没有请查看此 帖子 获取教程。

好了,现在我们终于可以进入正题,写一些实际的代码了👩🏾‍💻

第一站,CDK!

CDK 初始化

创建一个名为ecs
的新项目目录,运行以下命令为 CDK 创建一些样板代码:

cdk init sample-app --language python

如果在 Python 中创建 venv 时出现错误,可以执行以下命令为 Python 创建一个新的虚拟环境:

py -m venv .venv

然后使用以下命令激活它:

.\.venv\Scripts\activate

创建和激活 Python 虚拟环境

启用虚拟环境后,我们可以通过以下方式安装 Python 依赖项:

pip3 install -r requirements.txt

编辑app.py并确保提供了地区和帐户。它应该是这样的:

接下来,打开ecs_stack.py。这是我们定义要创建的架构和资源的地方。
粘贴以下代码:

我们从定义一个vpc开始。您可以将此视为与您的帐户相关联并可供使用的 ip 地址的集合。

接下来,我们定义两个安全组,一个用于数据库,另一个用于 fargate。安全组的作用类似于有状态的防火墙,默认情况下,它们允许所有传出的网络流量并阻止所有传入的流量。我们明确允许通过 TCP 从 fargate 连接到我们的数据库服务器。

接下来,我们创造秘密。这些可以是任何东西,包括 API 密钥、数据库凭证或其他需要存储和访问的敏感数据。通过 AWS secrets manager,可以轻松地存储、检索和循环使用,以获得最大的安全性。在这里,我们为数据库实例创建凭证。我们提供用户名为postgres,让 cdk 自动为我们生成一个密码。这里的好处是我们不会暴露代码中的秘密,因为我们可以简单地传递templatedSecret变量来引用敏感的密码。

我们创建一个新的数据库实例,将templatedSecret作为凭证传入,并将之前创建的安全组传入。

最后,我们创建一个新的 fargate 服务。默认情况下会创建一个应用程序负载平衡器,但其详细信息不在讨论范围之内。这里最重要的事情是我们提供了一个到 docker 映像的路径。我们将用户名和密码作为task_image_options secrets传递,并将数据库实例的端点作为environment变量传递。这允许 docker 容器能够连接到数据库。注意我们没有以明文形式传递任何东西!甚至数据库实例端点也是在运行时自动生成的,所以我们事先并不知道,但我们只是用rdsInstance.db_instance_endpoint_address将它传递给 fargate。

最后,我们添加了对rdsInstance的依赖。这确保了数据库在 fargate 服务之前创建。否则,我们的 FastAPI 应用程序将无法连接。

太好了!大部分工作已经完成。
接下来,我们需要为 ECS 创建一个 FastAPI 应用程序和一个 docker 文件。

REST API 与 FastAPI

确保虚拟环境已激活,并逐一安装以下软件包:

pip3 install psycopg2 
pip3 install fastapi 
pip3 install uvicorn[standard] 
pip3 install sqlalchemy

接下来,在根目录下创建一个main.py文件。
main.py粘贴以下代码:

这是一个简单的 REST API,有两个端点。我们可以存储一个book或者基于book_name检索一个book。在第 30 行,我们为插入和检索数据库记录所需的book创建了一个数据库模型。

注意如何简单地引用usernamepasswordendpoint作为环境变量。这是可行的,因为我们在前面的 CDK 代码中明确地将它们作为秘密和环境变量传递。

我们还需要为 FastAPI 创建一个 Pydantic 数据模型。这具有在向端点发出请求时提供输入数据的自动验证的优点。例如,当 POST 请求存储一本新书时,pydantic 会自动验证是否提供了正确的book字段。继续在名为schemas.py的新文件中创建一个 Pydantic 模型。
应该是这样的:

现在开始有趣的部分!

Dockerfile 文件

而在根目录下运行pip freeze > requirements.txt得到一个requirements.txt。这是建立我们码头工人形象的需要:

pip 冻结要求

在根目录下创建一个新的Dockerfile,如下所示:

我们简单地提取 Python:3.9 的官方 Docker 映像,设置一个命名的工作目录,我们将在后面引用它。然后我们在requirements.txt上运行一个 pip 安装,最后将所有代码从我们的主机复制到 Docker 容器中。容器运行时执行最后的CMD命令。
在这种情况下,它启动了我们的 FastAPI 应用程序。

您现在应该有一个如下所示的目录结构:

项目目录结构

好了😇为自己出色的工作给自己一点鼓励!
现在最激动人心的时刻到来了!

部署🚀

注意: 运行下面的命令将向您的 AWS 帐户支付费用。

喝杯咖啡,然后跑步:

cdk deploy

这将启动资源的创建并部署应用程序。

请耐心等待。这一步可能需要几分钟。
如果几分钟后控制台上看不到任何输出,点击 CTRL+C ,然后点击 cdk destroy。在这种情况下,您可以直接联系我/在下面评论,以获得故障排除帮助。

瞧吧🎆

我们需要获得ECS任务的 ip 地址来与服务器交互。
因为我们启动的 fargate 任务包含一个负载平衡器,所以我们使用负载平衡器的名称DNS。这是 AWS 自动生成的。继续在 AWS 控制台上搜索EC2。在左侧导航窗格中,找到并选择load balancers。打开的页面应该会列出一个负载平衡器。从描述中复制DNS name

从负载平衡器获取 DNS 名称

粘贴复制的 URL 并在浏览器上点击 enter。您应该看到:

到达端点以测试应用程序

您还可以使用 Postman 或类似的命令,通过 POST 和 GET 调用 API 端点。

记得销毁堆栈,防止跑费。
从终端执行以下命令,销毁所有创建的资源:

cdk destroy

请耐心等待,这可能需要几分钟。
您也可以通过在 AWS 控制台中搜索
***Cloudformation*** 来手动删除堆栈。

销毁堆栈后,您可能需要检查任何 RDS 快照。在控制台中搜索 RDS,并在左侧导航窗格中找到Snapshots。如果您看到列出了任何快照,请将其全部删除。

结论

在本文中,我们研究了如何在 AWS ECS 和 RDS 上部署 FastAPI 应用程序。

我们剖析并描述了 ECS(一种无服务器计算服务)的时间和资源优势。我们还使用了 RDS——一种托管数据库服务,AWS 负责为我们管理服务器。同样,像 ECS 一样,我们获得了不需要管理服务器的好处。

为了实现自动化部署,我们使用了 AWS IaC(基础设施即代码)产品 CDK。通过 CDK,我们可以将我们的架构定义为代码,轻松地将其提交给版本控制,并在未来进行更改等等。这也使得将来更改和更新基础设施变得更加容易。

希望你喜欢这篇相当长的帖子。

如果你喜欢这部作品,可以考虑关注并订阅 这里

原载于 2022 年 8 月 26 日https://haseebkamal.com

运行时自省:Julia 最强大、保守得最好的秘密

原文:https://towardsdatascience.com/runtime-introspection-julias-most-powerful-best-kept-secret-bf845e282367

在 Julia 中使用内省处理类型

(图片由 Pixabay 上的 Skitterphoto 拍摄)

介绍

当谈到最终执行您的代码时,我们经常使用的许多高级编程语言都没有提供很多工具来允许人们在执行时查看语言。当然,我们可以打印值,我们可以有一些输出来告诉我们代码是否工作,但是在执行时使用已定义的类型和名称要困难得多。我的意思是这是有意义的,这不是一个人通常想在执行过程中做的事情,到处剖析类型和定义的字段——在大多数情况下,这根本不值得。

然而,虽然在大多数情况下,自省对你来说可能是不必要的,但对你的语言的编译器来说,为了更好地理解正在发生的事情以及你的环境,自省是必要的。也就是说,在某些情况下,人们可能与编译器一起工作,或者像编译器一样控制作用域。此外,在 Julia 中进行元编程时,自省可以产生非常有效的效果。尽管在 Julia 文档中可以获得这方面的信息,但它是在 Julia 的开发者文档中,而不是常规文档中。也就是说,我的假设是,大多数使用 Julia 的人不会开发这种语言本身,但肯定会在他们使用这种语言的某个时候利用自省,因为我认为这是这种语言在许多不同的应用程序中可以做的一件有价值的事情。也就是说,如果你更愿意阅读文档而不是我对这些特性的解释,这里有一个 Julia 文档的链接:

此外,对于那些想要自己运行这些示例的人来说,我在这个小概述中使用的代码是笔记本格式的:

https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/runtime%20introspection.ipynb

数据类型

关于数据类型,我们需要了解的第一件事是,在 Julia 中,它们有称为“字段”的属性。我们可以检查任何给定类型或数据类型的字段。当然,字段有几种不同的属性,但是最重要的两种是字段名和它们的类型。我们可以通过使用同名的方法来获取字段名,

mutable struct Noodleclass::Symbollength::Integer
endfieldnames(Noodle)(:class, :length)

这将返回一个表示该类型中每个字段名的符号元组。在 Julia 中,你定义的所有东西都有一个对应的符号。也就是说,也有一些符号对应于在你的全球环境中创造的每一个价值。我们还可以使用 getfield()和 setfield 来获取和设置字段!()然而,有许多情况下 setfield!()是行不通的。每当我们使用。,例如

Noodle.class

我们实际上是在调用 getfield 方法。如果我们使用

Noodle.class = :spaghet

然后我们调用 setfield 方法。我们可以从模块和类型中获取字段。例如,我们可以从 main 获得一个:

getfield(Main, :Noodle)Noodle

Main 只是 Julia 中顶层全局模块的名字。

最后,Julia 中任何类型的参数或数据的一个重要组成部分是它的类型。我们可以使用 fieldtypes()方法或者只使用。添加到 Julia 中每个类型的类型字段。

fieldtypes(Noodle)
(Symbol, Integer)Noodle.typessvec(Symbol, Integer)

子类型

尽管它们不太适合运行时,但在自省给定模块的类型层次结构的组件时,它们仍然很有价值。我们可以通过使用子类型操作符<:来识别一个类型是否是某物的子类型。此运算符既用于表示类型在其定义中使用时是抽象类型的子类型,也用于返回一个布尔值,表明所提供的类型是否是抽象类型的子类型。首先,让我们看看如何设置子类型:

abstract type Pasta endstruct Spaghet <: Pastalength::Integer
end

这个新的 Spaghet 类型将继承应用于 Pasta 类型的任何方法。我们现在还可以使用相同的语法来了解 Spaghet 实际上是否是 Pasta 的子类型,这将是正确的:

Spaghet <: Pastatrue

我们还可以通过使用 subtypes()方法获得给定抽象类型的所有子类型:

subtypes(Pasta)
1-element Vector{Any}:Spaghet

如果你没有接触过朱利安式的等级制度,我有一整篇文章可以更详细地介绍:

此外,这里有一个子类型树函数,它对于更好地可视化子类型也很有价值。我只是在这里的某个问题上发现了这一点,但我认为对于那些可能想更好地掌握某个类型的人来说,这绝对是非常好的:

function subtypetree(t, level=1, indent=4)level == 1 && println(t)for s in subtypes(t)println(join(fill(" ", level * indent)) * string(s))subtypetree(s, level+1, indent)endendsubtypetree(Number)NumberComplexRealAbstractFloatBigFloatFloat16Float32Float64AbstractIrrationalIrrationalIntegerBoolSignedBigIntInt128Int16Int32Int64Int8UnsignedUInt128UInt16UInt32UInt64UInt8Rational

在后台

我想展示的最后几样东西是为了一些更深入的内省。对于我们的第一个例子,我们将查看@code_llvm 宏,它只给出给定表达式的 llvm 代码:

[@code_llvm](http://twitter.com/code_llvm) subtypetree(Number);  @ In[16]:1 within `subtypetree`
define nonnull {}* @japi1_subtypetree_2021({}* %0, {}** %1, i32 %2) #0 {
top:%3 = **alloca** {}**, align 8**store** volatile {}** %1, {}*** %3, align 8%4 = **load** {}*, {}** %1, align 8
;  @ In[16]:2 within `subtypetree`**call** void @j_subtypetree_2022({}* nonnull %4, i64 signext 1, i64 signext 4) #1**ret** {}* inttoptr (i64 139868392615944 to {}*)
}

另一个很酷的类似的小宏是@code_typed。这与 Meta 有相似的用法。@lower,在大多数情况下,我认为这可能是一个更好的选择,除非我们想要获取的信息是一个单独的方法调用,例如,这是行不通的:

[@code_typed](http://twitter.com/code_typed) debuginfo = :source begin+(1, 1, 5)-(7, 3)
endexpression is not a function call, or is too complex for @code_typed to analyze; break it down to simpler parts if possible. In some cases, you may want to use Meta.@lower.

相比 Meta。@较低:

Meta.[@lower](http://twitter.com/lower) begin+(1, 1, 5)-(7, 3)
end:($(Expr(:thunk, CodeInfo(@ In[24]:2 within `top-level scope`
1 ─      1 + 1 + 5
│   @ In[24]:3 within `top-level scope`
│   %2 = 7 - 3
└──      return %2
))))

关于自省,我想分享的最后一件事是 varinfo()方法。这种方法很棒,因为它可以说明不同类型的记忆的用法,也可以很好地描述我们的环境中有什么。

varinfo()

(图片由作者提供)

结论

自省是编程语言的一个重要方面。当我们处理那些我们可能并不真正了解字段的类型时,这真的很方便。我认为,当我们使用动态类型语言时,情况更是如此。此外,对于不允许我们监视或控制内存和其他硬件组件的高级语言来说,在许多情况下尽可能多地使用内省确实很有意义。我认为朱利安的内省方法在大多数情况下是非常恰当的,我可能在内省方面使用最多的是 varinfo()方法。了解事情占用了多少内存真是太好了,尤其是在开发自己的包的时候。感谢您阅读我的文章,我真的很感激,我希望这篇概述有助于阐明一些更好的控制 Julia 语言的方法!

人工智能应用的安全性

原文:https://towardsdatascience.com/safety-of-artificial-intelligence-applications-1ab19606bf43

对使用人工智能可能引发的问题的探讨

阿瑟尼·托古列夫在 Unsplash 上的照片

人工智能(AI)不是上图中的机器人,它可能与电视上看到的任何东西都不相似。它是关于使用技术来帮助完成特定的任务,从接下来看什么电影,你可能有兴趣购买什么商品,你可能会点击什么广告,或者将智能手机摄像头对准你的脸以拍摄完美的自拍。

对于 AI 的未来,不同的人有不同的看法和猜想。但是,这些仅仅是这些;猜测。是的,有担忧,应该有关于我们如何在道德上使用人工智能的担忧,但是,我们不知道我们不知道什么。要更深入地了解什么是人工智能,你可以在这里阅读。

真正的担忧不应该是人工智能变得邪恶,而是它的目标是否会恶意或意外地偏离最初的意图,从而导致各种不同的问题。

在下面的段落中,我们提出了在开发或使用人工智能系统时可能出错的关键问题。这包括从高层次的哲学甚至观点到更多的技术考虑。

目录

–偏见和公平
–道德和责任
–可解释性和可解释性
–数据隐私
–健壮性–再现性和一致性
–评估
–局部最小值/最大值
–类别不平衡

偏见和公平

偏见可以通过各种方式进入人工智能模型。通常,根本原因在于数据。由于人工智能模型从数据中学习,如果数据是以引入偏见的特定方式收集的(例如,它们包括有偏见的人类决策或反映历史或社会不平等),这将影响从这些数据中训练的模型。另一个原因可能是人工智能模型没有在足够的数据上进行适当的训练(也称为欠拟合),并且正在犯不可接受的错误,或者相反,它已经在太多的数据上进行训练,以至于它失去了概括(也称为过拟合)的能力,而不是产生有偏见的预测。

为了更具体,这里有三个例子:

  • 预测未来的罪犯:

2016 年 ProPublica 的一项调查得出结论,法官用来确定被定罪的罪犯是否有可能犯下更多罪行的人工智能系统似乎对少数族裔有偏见。【1】有趣的是,2019 年,英国政府发布了解决警务偏见问题的指导方针和法规。【2】

  • 谷歌图像识别:

谷歌的人工智能图像识别系统混淆了动物和少数民族的人。【3】该系统没有经过足够的正确数据训练,无法做出更准确的预测,它的一些错误令人不快。

  • 流氓 Twitter 聊天机器人:

早在 2016 年,一个微软聊天机器人在推特上耍流氓,骂人,发表种族主义言论和煽动性政治言论。聊天机器人接受了包括这种语言和评论的数据训练。

道德和责任:是否有与道德、角色和责任相关的标准?

道德和责任是人工智能领域的热门话题,一整篇论文都可以专门讨论这个问题。在这里,我们将简要解释我们的意思,并给出一些例子来更详细地理解由于更广泛地采用人工智能,我们作为人类将面临的困境。具体来说,这个领域是关于什么是人工智能系统的道德部署,以及如果出现问题,谁应该负责。

道德问题的一个例子可能与自动驾驶汽车(无人驾驶汽车)有关。这与电车问题类似。【5】具体来说,想一想一辆汽车 2 秒内即将撞车,车上乘客全部遇难的不幸事件。2 秒钟的时间滞后可以被看作是一个小的机会窗口来操纵和拯救乘客。问题是,另一种选择是轧死一些行人,而不是杀死他们。车到底该不该做?

在伦理人工智能下可以调查的其他问题有:

1.如果人工智能系统的部署导致失业或错失机会怎么办?例如,一个简历被自动系统筛选的求职者可能会因为某些甚至不是工作要求的特征而被拒绝。

2.应该允许人工智能系统杀人吗?

在问责制方面,问题是谁对人工智能系统的给定行为负责?是建造系统的 AI 工程师吗?是 AI 系统本身还是别人?

我们再讲一个例子来更好的理解这个问题。

一个病人去医院,由人工智能系统检查。系统检查肺部图像并输出结果。病人是阴性的,意味着图像是清晰的。几个月后,病人再次接受测试,结果是毁灭性的。病人处于肺癌晚期。不幸的是,人工智能系统错了。在这种情况下会发生什么?人工智能系统能对预测误差负责吗?是医生从系统中得到的结果吗?是最初建造它的工程师吗?

本节要提出的最后一点是关于人工智能系统反人类的问题。即使围绕这一点有很多炒作,但大多数也只是一个神话。任何人工智能系统都不存在固有的恶意,除非它被明确编程或在数据中训练成这样。当然,人工智能可以是一种工具或武器,就像刀可以是工具和武器一样。AI 依然可以被恶意使用;你可以将人工智能技术武器化,就像任何其他新技术一样。简而言之,这个话题目前不构成风险,但它肯定是我们应该继续讨论的问题,以避免这成为一个巨大的风险。

一份由著名的英国研究所撰写的更详细的报告更详细地描述了这一部分的许多方面,并提供了一个在其中运作的道德框架。此外,英国政府出于同样的目的发布了数据伦理框架,该框架与上述报告相关联。【7】

人工智能系统的可解释性/可解释性:

人工智能系统的可解释性和可解释性是经常被问到的问题,因为知道为什么和如何做出某些决定对于审计目的是重要的,而不仅仅是。

模型如何决定这是对我的公司最好的行动?它如何知道这个客户比另一个客户更有可能购买我的产品?业内许多高管向数据科学家和人工智能专家提出了这个问题,因为他们不想将他们的决策建立在他们不理解他们最初是如何得出结果的模型上。这可能是一个困难的问题,也是数据科学家和人工智能专家可能无法始终回答的问题。例如,在机器学习领域内使用特定技术,即深度学习,利用人工神经网络来进行预测。这个系统类似于大脑,其中每个神经元都以这样的方式与其他神经元相连,即信息可以在神经元之间传递,直到返回结果。【8】这种类型的人工智能系统在某些任务(图像识别、自然语言处理)中表现优于其他机器学习算法,但更具挑战性的是询问和理解结论是如何得出的。

近年来,随着美国和欧盟引入解释权,这个问题变得更加紧迫。【9】鉴于算法的输出与个人相关并对个人产生重大影响,特别是在法律或财务方面,这是对算法输出做出解释的权利。例如,某人可以申请贷款,而 AI 系统由于此人不可信而拒绝了该申请。关键问题是,系统是如何得出这个结论的。

一些说明人工智能系统中可解释性重要性的例子是图像识别软件学会作弊而不是识别图像。特别是,一个被训练来识别杂志中的马图像的系统实际上并没有识别马,但事实证明,它学会了检测马图像上可见的版权标签。【10】

数据隐私:

隐私是一个与人工智能和一般数据相关的大问题。在欧洲,2018 年生效的《一般数据保护条例》( GDPR)规范了个人数据的收集和使用。【11】数据保护法并未明确提及人工智能或机器学习,但对个人数据的大规模自动化处理和自动化决策有着重要的关注。这意味着,如果人工智能使用个人数据,它就属于该条例的范围,并适用 GDPR 原则。这可以通过使用个人数据来训练、测试或部署人工智能系统。不遵守 GDPR 可能会导致相关公司受到巨额处罚。

个人数据的例子包括出生日期、邮政编码、性别,甚至是用户的 IP 地址。

GDPR 教赋予个人不受完全自动化的决定支配的权利。对人工智能专家来说,关键问题是:当你在人工智能的帮助下对一个人做出决定时,你如何证明你公平、透明地对待了他,或者给他们机会质疑这些决定?

不利条件下的鲁棒性:

当进行对抗性攻击时,人工智能系统可能会遇到不利条件。对抗性攻击就是对人工智能系统的任何恶意干扰,目的是迫使它做出错误的预测。在这一节中,我们讨论两种情况,在这两种情况下,对人工智能系统的对抗性攻击会使系统完全混乱。

  • 图像识别:图像识别是指能够识别图像中的对象的人工智能系统,即能够对图像进行分类,例如,能够区分猫图像和狗图像。这种人工智能系统被证明有弱点或者容易受到敌对攻击。研究人员已经表明,即使人工智能系统在数以千计的图像上进行训练,图像中精心放置的像素也可以从根本上改变人工智能系统对它的感知,从而导致错误的预测。【12】
  • 自然语言处理(NLP):当人工智能系统处理自然语言时,自然语言也容易受到对抗性攻击。例如,研究表明,在电影评论中使用特定的同义词会改变人工智能系统对该评论的看法。【13】例如,句子/评论“在不可思议的人为情况下塑造的人物,完全脱离现实”就有负面情绪。一篇类似的评论仔细选择了如下词汇:“在不可能的工程环境中塑造的角色,完全脱离现实”,人工智能系统在将其归类为正面时感到困惑。这种攻击的主要目的是集中攻击那些根据上下文可能会产生歧义的词。NLP 环境中的对抗性攻击的其他示例包括特定单词中的字符交换或在句子中添加常见的人类打字错误。【14】

再现性和一致性

人工智能中的一个常见问题是,复制我们获得的结果或生成的模型有多容易。许多算法在训练它们的模型时具有随机元素,这意味着不同的训练尝试产生不同的模型,并且不同的模型具有不同的预测结果。此外,在本地机器上使用我们的数据表现良好的系统,在现场测试时可能表现不佳。我们如何确保我们最初拥有的性能传播到部署的应用程序?我们如何确保系统的性能不会随着时间的推移而下降?

评估

构建人工智能系统的关键问题是“我们如何评估系统?”“准确性是一个好的衡量标准吗?”想想一个问题,你有 100 个女人,其中 10 个怀孕了。你有一些关于这些妇女的信息,你试图建立一个模型来预测谁怀孕了,谁没怀孕。你的模型有 80%的准确率。这是否意味着你有一个好的模型?另一方面,让我们假设你没有模型,你更愿意做的是预测所有没有怀孕的女性。这有 90%的准确率,因为你 100 次中有 90 次是正确的。在这种情况下,准确性不是一个好的衡量标准,因为它很少告诉我们模型有多好。那么,我们使用什么指标,我们如何评估模型的性能?

聊天机器人在过去几年中非常受欢迎,特别是随着自然语言处理(NLP)领域中人工智能模型的改进。

但是,你会如何评价一个聊天机器人呢?想想临床环境中的聊天机器人,我们如何确保它不会推荐错误的治疗方法或提供错误的建议?

局部最小值/最大值

许多算法解决优化问题来训练模型或使用优化方法来寻找模型的最佳超参数。然而,存在优化器落入一些局部最小值/最大值的情况,这导致超参数的次优选择。简而言之,算法表现不佳是因为可能错误地选择了某些参数。

阶层失衡

当你训练一个人工智能系统来识别图像时,你可能会面临一些我们之前讨论过的潜在问题。另一个更技术性的问题可以用下面的例子来说明:考虑一组 100,000 幅图像,其中只有 100 幅是猫的图像,99,900 幅是狗的图像。人工智能系统更有可能预测一只狗,因为它被训练得更频繁;它没有足够的反面案例来准确区分这两种类型的图像。

黑天鹅

依靠历史数据来预测未来并不总是可行的。一个很好的例子是试图预测股票市场。由于多种原因,这在本质上是困难的。利用长期以来具有某种结果的数据,可以创造出在其历史范围内有效的模型。这意味着,如果你在一个没有市场崩盘的时期训练一个模型,这个模型就不可能预测到崩盘。即使你在市场崩溃期间训练了它,由于事件的罕见性,模型仍然不太可能知道什么时候会发生。想想在全球疫情时代预测未来的模型;因为所有的模型在过去都没有类似的数据,所以不可能准确预测未来。【15】

优化正确的奖励函数

通过反复试验来学习的人工智能系统通常被称为强化学习。更正式地说,强化学习(RL)是机器学习的一个领域,处理软件代理应该如何在环境中采取行动,以最大化累积回报的概念。【16】

作为一名人工智能专家,你需要创造一个环境,让软件代理能够“生活”,定义代理可能采取的潜在行动,并设计一个与代理的目标直接相关的奖励函数。例如,这种类型的学习被成功地用在电子游戏中,在这种游戏中,环境通常是明确定义的,代理人有非常明确的目标。一些例子包括 RL 在“超级马里奥”【17】和“俄罗斯方块”中的应用。【18】然而,当环境没有被很好地定义,或者更经常地,当奖励函数不合适时,会发生什么?人工智能系统可以通过寻找捷径或在游戏中“作弊”来学习获胜。【19】

结论和未来工作

很明显,我们需要一个人工智能框架,相关的应用程序可以在其中运行。该框架应讨论上述所有考虑事项以及如何缓解其中每一项的建议。

人工智能系统的系统测试和验证方法应该是该框架的中心主题,但是,这应该进行调整,并详细描述如何实施以解决上述问题。

参考资料:

【1】https://www . propublica . org/article/machine-bias-risk-assessments-in-criminal-pending

【2】https://assets . publishing . service . gov . uk/government/uploads/system/uploads/attachment _ data/file/831750/RUSI _ Report - Algorithms _ and _ Bias _ in _ policing . pdf

【3】https://www . the verge . com/2018/1/12/16882408/Google-种族主义者-大猩猩-照片-识别-算法-ai

【4】https://www.bbc.co.uk/news/technology-35890188

【5】https://en.wikipedia.org/wiki/Trolley_problem

【6】https://www . turing . AC . uk/sites/default/files/2019-06/understanding _ artificial _ intelligence _ ethics _ and _ safety . pdf

【7】https://www . gov . uk/government/publications/data-ethics-framework/data-ethics-framework

【8】https://en.wikipedia.org/wiki/Artificial_neural_network

【9】https://en.wikipedia.org/wiki/Right_to_explanation。同样参见https://www.privacy-regulation.eu/en/r71.htm关于欧盟的方法。

【10】https://www . the guardian . com/science/2017/nov/05/computer-says-no-why-making-ais-fair-accountable-and-transparent-is-critical

【https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?】uri = CELEX:32016 r 0679&from = EN

【12】https://arxiv.org/pdf/1710.08864.pdf

【13】http://groups . csail . MIT . edu/medg/FTP/PSZ-papers/2019% 20Di % 20 Jin . pdf

【14】https://medium . com/forward-artificial-intelligence/adversarial-attacks-in-textual-deep-neural-networks-245 DC 90029 df

这并不意味着模型是无用的,而是说你在构建这些模型时应该小心谨慎。

【16】https://en.wikipedia.org/wiki/Reinforcement_learning

【17】https://medium . com/datadriveninvestor/super-Mario-bros-reinforcement-learning-77d 6615 a805e

https://github.com/nuno-faria/tetris-ai

【19】https://www . tomeveritt . se/paper/2017/05/29/reinforcement-learning-with-corrupted-reward-channel . html

彩票假说的传奇

原文:https://towardsdatascience.com/saga-of-the-lottery-ticket-hypothesis-af30091f5cb

中奖彩票是如何被发现、揭穿和重新发现的

(作者创作)

彩票假设(LTH)与神经网络修剪相关,可以通过下面的陈述简明地概括出来[1]:

“密集的、随机初始化的前馈网络包含子网(中奖票),当独立训练时,在相似的迭代次数下,达到与原始网络相当的测试精度。”

虽然有点难以解释,但这种说法表明,如果我们:

  • 训练神经网络收敛
  • 修剪它的权重,产生一个更小的子网
  • 将子网权重倒回其原始的随机初始化值
  • 训练产生的子网收敛

然后,子网(通常被称为“中奖票”)将实现匹配或超过子网所源自的原始密集神经网络性能的测试精度。

这样的观察对于深度学习社区来说很有趣,因为这意味着随机子网络存在于密集网络中,即 (i) 更小/计算效率更高,并且 (ii) 可以被独立训练以表现良好。如果这些中奖彩票可以很容易地被识别出来,那么通过简单地训练子网络而不是完整的密集模型,神经网络的训练成本就可以大大降低。

通过 LTH 启发的发现来降低训练复杂性的目标尚未实现,因为发现中奖彩票需要密集网络的全部(或部分[2])预训练,这是一个计算繁重的过程。但是,深度学习社区继续研究 LTH,因为它有可能通知和简化神经网络训练。

背景资料

在进入主题之前,我将提供理解 LTH 所需的相关背景信息。我的目标是通过提供相关背景的全面总结来建立对该主题的基础理解。然而,在某些情况下,提供一个主题的完整概述是不实际的或不在范围之内的,所以我提供了外部资源的链接,可以用来更深入地理解一个观点。

什么是神经网络修剪?

为了充分理解 LTH,人们必须熟悉 LTH 所基于的神经网络修剪【3,4,5】。剪枝背后的基本思想是从一个大型、密集的网络中删除参数,产生一个更小、计算效率更高的(可能是稀疏的)子网。虽然我在这里引用了一些关于神经网络修剪的最有用的论文,但是网上有许多高质量的资源有助于探索。

理想情况下,修剪后的子网应该表现得与密集网络相似,尽管如果移除大量参数,情况可能并非如此。因此,修剪过程的目标是找到并移除不会显著损害网络性能的参数。

在大多数情况下,神经网络修剪遵循预训练、修剪和微调的三步过程。密集网络首先被部分地或收敛地预训练。然后,在这个密集网络上执行修剪,并且在修剪发生之后,进一步训练/微调所产生的子网。

不同类型的修剪

描述前馈和卷积网络的结构化和非结构化修剪方法(由作者创建)

存在许多用于神经网络修剪的技术,但是它们可以粗略地分为两组— 结构化和非结构化修剪

非结构化修剪对修剪过程没有任何限制。网络中的任何和所有权重可以被单独修剪/移除,这意味着在执行修剪之后,所得到的网络通常是稀疏的。

相比之下,结构化修剪移除整个权重“组”(例如,卷积滤波器、前馈层中的神经元、变压器中的注意力头等)。)一起从基础网络中分离出来,以避免产生的子网中的稀疏性。因此,子网只是一个更小、更密集的模型。

结构化和非结构化修剪方法(如上图所示)都被广泛使用——没有一种方法一定“更好”。非结构化修剪允许在不降低性能的情况下达到更高的稀疏度,因为它对修剪过程的约束更少。然而,结构化修剪具有产生密集子网的额外好处,从而允许避免使用用于稀疏矩阵乘法的专用库,这通常会使网络训练/推理慢得多。

迭代幅度修剪(IMP)

基于信道比例因子的卷积神经网络的 IMP(来自【8】)

最常用于研究 LTH 的神经网络修剪类型是迭代幅度修剪(IMP)【4】,其操作如下:

  1. 从一个训练有素的密集模型开始
  2. 选择并修剪网络中的最低幅度权重
  3. 微调/训练产生的子网进行收敛
  4. 重复步骤(2)-(3),直到达到所需的修剪比率

尽管 IMP 背后的想法看起来很简单,但是这种方法在实践中非常有效,并且已经证明了自己是一个难以超越的基线[4,5]。因为 IMP 运行得如此之好,许多有用的解释都可以在网上找到。

当应用于结构化修剪或用于更复杂的网络变体时,IMP 有时会被修改。例如,用于卷积神经网络中结构化滤波器修剪的 IMP 的一个变体为网络中的每个通道分配单独的缩放因子,然后基于这些因子的大小而不是权重本身来修剪滤波器[8]。请参见上图中的示意图。

出版物

在此,我将概述与 LTH 相关的三份重要文件。我考虑的第一个作品提出了 LTH,而其他作品则进一步分析了这个想法并提供了有用的见解。有趣的是,LTH 在其提议后不久就被部分揭穿,随后在原作者的后续论文中得到证实(有所修改)。围绕这个话题的争论导致了研究界的许多困惑,我将尽力在这里澄清这些困惑。

彩票假说:寻找稀疏的、可训练的神经网络[1]

描绘在 LTH 发现中奖彩票的 IMP +倒带(作者创作)

**主旨。**模型可以很容易地削减到总参数的< 10%。但是,如果我们:

  • 采用修剪过的网络的结构/架构
  • 随机重新初始化其参数
  • 从头开始训练网络

子网的性能会很差。这篇论文发现,在随机初始化的密集网络中存在特殊的子网,称为“中奖票”,当独立训练时,这些子网可以与完全训练的密集网络的性能相匹配。这种现象被创造为彩票假说(LTH),正如本综述的第一段所解释的。

方法论。 为了验证 LTH,作者采用了一种非结构化的剪枝方法。使用的修剪技术非常类似于 IMP,只有一个小的不同。也就是说,为了产生中奖彩票,作者进行如下操作:

  1. 从一个训练有素的密集模型开始
  2. 选择并修剪网络中的最低幅度权重
  3. 将剩余的子网参数倒回它们的初始随机值
  4. 训练子网收敛
  5. 重复步骤(2)-(4),直到达到所需的修剪比率

上述方法与 IMP 的主要区别在于模型参数的重绕。修剪后,参数被重置为其原始的随机值,而不是简单地微调现有的模型参数。

通过这种方式,获胜的彩票——它的结构和权重——存在于随机初始化的密集网络中。因此,这个子网被显示已经赢得了“初始化彩票”,因为它可以从零开始被训练到比完全训练的密集网络或具有相同结构的随机重新初始化的子网更高的精度。

调查结果。

  • 使用全连接网络和小规模 CNN 在 MNIST 和 CIFAR10 数据集上对 LTH 进行了经验验证。发现原始网络大小的 10–20%的中奖票持续存在。
  • 在许多情况下,中奖票比原始稠密网络具有更好的泛化性能。
  • 在培训前随机重新初始化中奖彩票会损害性能。将参数恢复到初始随机值对于匹配或超越密集网络性能至关重要。

重新思考网络修剪的价值【5】

大意。 简而言之,本文表明随机重新初始化并从头训练的子网与通过 IMP 获得的子网表现相似。这一结果与神经网络修剪文献[1,4]中的先前发现相矛盾,揭示了训练大型、过度参数化的模型对于获得更有效的子网络实际上是不必要的。

尽管该结果与一般的神经网络修剪更相关(即,不是特别的 LTH),但是本文中的结果表明:

  • 将子网参数恢复到初始值并不是 LTH 方法的必要组成部分——通过在迭代修剪期间随机重新初始化子网参数,可以获得相同的结果。
  • LTH 是一种无法在使用结构化剪枝和复杂网络架构的大规模实验中复制的现象。

方法论。 与最初的 LTH 出版物不同,这项工作中的作者在他们的大部分实验中利用了结构化修剪方法。虽然在某些情况下采用非结构化剪枝,但结构化剪枝更常用于大规模实验(例如,卷积网络的结构化滤波器剪枝[4]),使这种方法更合适。

研究了多种网络修剪方法(参见第 4 节标题和[5]中的描述),这些方法执行:

  • 预定义结构修剪:对每一层进行固定、均匀的修剪
  • 自动结构修剪:动态决定每层应该修剪多少,而不是均匀修剪
  • 非结构化 IMP :参见前面关于 IMP 的讨论

对于这些方法中的每一种,作者都遵循前面描述的三步修剪过程。对于第三步,从各种不同的参数初始化开始训练得到的子网:

  • 将子网参数恢复到它们的初始随机值
  • 保留/微调现有子网参数
  • 随机重新初始化子网参数

作者发现,在大多数情况下,修剪后随机重新初始化子网参数匹配或超过其他方法的性能。因此,对于如此大规模的实验,LTH 无法得到验证。

调查结果。

  • 子网参数的随机重新初始化足以实现有竞争力的子网性能,表明 LTH 在本研究探索的大规模实验中不成立。
  • LTH 和本文之间的发现差异可能是由 (i) 主要使用结构化剪枝进行分析, (ii) 使用更大的模型和数据集,或者 (iii) 优化和超参数设置的差异造成的。
  • 从神经网络剪枝中获得的中奖票或高性能子网的参数并不重要,揭示了神经网络剪枝可能只不过是神经架构搜索的一种替代形式。

线性模式连通性和彩票假说【6】

当您在两个网络之间进行插值时,误差增加到超过两个网络的平均误差时,就会出现不稳定性(来自【6】)

**主旨。**这项工作探索了上面论文中概述的问题— *为什么 LTH 在大规模实验中不成立?*作者发现,使用【1】中提出的方法,在大规模实验中无法发现中奖彩票。也就是说,这种子网不能达到匹配或超过密集网络的精度。

然而,有趣的是,如果修改这个过程,将权重倒回到某个早期的训练迭代 k,而不是严格地倒回到初始化,那么得到的子网表现良好。因此,如果方法稍微修改如下,LTH 在大规模实验中仍然成立:

  1. 从一个训练有素的密集模型开始
  2. 选择并修剪网络中的最低幅度权重
  3. 将子网参数倒回训练迭代 k 的值
  4. 训练子网收敛
  5. 重复步骤(2)-(4),直到达到所需的修剪比率

因为这种子网不是在随机初始化的密集网络中发现的,所以作者称它们为“匹配”子网,而不是赢得入场券。

方法论。为了发现 LTH 内这种有趣的重量重绕特性,作者采用了一种基于线性模式连通性的新型不稳定性分析。他们的分析方法执行以下步骤:

  • 创建网络的两个副本。
  • 用不同的随机种子独立地训练这些网络,使得网络在用随机梯度下降训练期间经历不同的随机噪声和数据排序。
  • 确定两个生成的网络是否通过非递增误差区域线性连接。

实际上,上述方法的最后一步是通过测试两个网络权重之间固定数量的线性插值点来完成的。在这些点中的每一点上,测试插值网络的误差,以确保它不超过实际网络的平均误差值。

通过执行如上所述的不稳定性分析,作者发现网络在训练早期变得稳定,但在初始化时不稳定。此外,匹配子网总是稳定的,表明匹配子网不能从随机初始化的不稳定参数中导出。这样的观察解释了为什么 LTH 仅在权重被重新绕到一些早期训练迭代时成立,而不是一直到初始化。

调查结果。

  • LTH 在比例上不成立。但是,“匹配”子网可以通过修改 LTH 来发现,以将权重倒回到训练的某个早期迭代,而不是一直到初始化。
  • 只有非常小规模的网络和数据集(如 MNIST 上的 LeNet)在初始化时是稳定的,这解释了为什么最初的 LTH 公式[1]只能在这样的小规模数据集上得到验证。
  • 给定对 LTH 的这种修改,即使在 ImageNet 上使用最先进的卷积神经网络架构的大规模实验中,也可以一致地找到匹配的子网。

外卖食品

通过研究 LTH,我们了解了几个有用的概念:

  • 神经网络修剪:通过去除不需要的权重,从一个经过充分训练的密集网络中生成一个更小、更高效的网络
  • 结构化与非结构化剪枝:两类剪枝方法,对剪枝过程施加不同的约束
  • 迭代幅度修剪:一种简单而有效的修剪方法,迭代地丢弃网络中最低幅度的权重
  • 线性模式连通性:用于描述网络对随机梯度下降训练产生的噪声“稳定”的特性。

在概述的工作中,我们首先了解到——在小规模实验中——密集、随机初始化的神经网络包含子网络(即中奖彩票),这些子网络可以用 IMP 发现并隔离训练以实现高精度[1]。

这一发现后来与研究相矛盾,研究表明,在大规模实验中,这种中奖彩票可以随机重新初始化,仍然可以达到相当的准确性,这表明除了 IMP [5]发现的网络结构之外,这些中奖彩票没有什么特殊之处。

当表明虽然在随机初始化的密集网络中可能不存在中奖票,但是可以通过 IMP 在已经少量训练的网络中找到匹配子网(即,匹配或超过密集网络性能的子网)时,这种矛盾的结果得到解决[6]。因此,只要稍加修改,LTH 在大尺度上仍然有效。

结论

非常感谢你阅读这篇文章。如果你喜欢它,请订阅我的深度(学习)焦点时事通讯,在那里,我每两周对深度学习研究中的一个相关主题进行情境化、解释和检查。欢迎在媒体上关注我或者访问我的网站,那里有我的社交媒体和其他内容的链接。如果您有任何建议/反馈,请直接联系我或留下评论。

文献学

[1]弗兰克,乔纳森和迈克尔卡宾。"彩票假说:寻找稀疏的、可训练的神经网络." arXiv 预印本 arXiv:1803.03635 (2018)。

[2]尤,浩然等,“画早鸟票:走向更高效的深度网络训练” arXiv 预印本 arXiv:1909.11957 (2019)。

[3] LeCun、Yann、John Denker 和 Sara Solla。"最佳脑损伤"神经信息处理系统进展 2 (1989)。

[4]李,郝等.“高效神经网络的剪枝滤波器” arXiv 预印本 arXiv:1608.08710 (2016)。

[5]刘,庄等.“网络剪枝的价值再思考” arXiv 预印本 arXiv:1810.05270 (2018)。

[6] Frankle,Jonathan 等人,“线性模式连接和彩票假说”机器学习国际会议。PMLR,2020 年。

[7]尤,浩然等,“画早鸟票:走向更高效的深度网络训练” arXiv 预印本 arXiv:1909.11957 (2019)。

[8]刘,庄等.“通过网络瘦身学习高效卷积网络”IEEE 计算机视觉国际会议论文集。2017.

SageMaker 批量转换

原文:https://towardsdatascience.com/sagemaker-batch-transform-d94dbaf889f6

使用 Sklearn 示例生成大型离线预测

图片来自黄邦贤·法伯拍摄的 Unsplash

在我的上一篇文章中,我谈到了最新的 SageMaker 推理选项中的无服务器推理。一个更老但同样重要的选择是 SageMaker 批量转换。有时候,对于我们的机器学习模型,我们不一定需要一个持久的端点。我们只有一个大型数据集,我们希望为该数据返回推断。对于没有任何延迟需求的工作负载来说,这是一个很好的选择

使用 SageMaker 批处理转换,我们将探索如何使用 Sklearn 回归模型并在样本数据集上获得推论。本例中的数据集不一定很大,但实际上您可以对数千个数据点使用批量转换。一些非常流行的用例包括在您需要实时推理之前对数据集进行预处理,或者为计算机视觉工作负载处理图像数据。

**注意:**对于 AWS 的新用户,如果你想跟进,请确保在下面的 链接 中进行登记。批量转换作业的部署过程中会产生成本。本文还将假设您对 SageMaker 和 AWS 有一定的了解。

目录

  1. 资料组
  2. 设置
  3. 批量转换示例
  4. 其他资源和结论

资料组

对于我们的示例,我们将使用 Kaggle 的汽油消耗回归数据集。原始数据源在这里被许可。

设置

对于我们的示例,我们将使用 Kaggle 的汽油消耗回归数据集。在我们得出结论之前,我们将使用 SageMaker 训练一个 Sklearn 随机森林模型。在脚本中,我们还将拥有定制的推理处理程序,以便能够处理我们为推理而输入的 csv 数据集。在本例中,我们不会深入介绍整个培训设置,但是您可以在这里阅读端对端指南。

对于这个例子,我们将在 SageMaker Studio 中使用数据科学内核和 ml.c5.large 实例。如果您已经设置了 AWS 凭证,您也可以使用 Classic Notebook 实例或您的本地环境。首先,我们将读取数据集,看看我们正在处理什么。

读取数据集

数据集头(作者截图)

我们将把这个数据集分成两部分,一部分用于训练,一部分用于批量推断的测试集。

分割数据集

然后,我们可以像往常一样将这些数据推送到 S3,在那里 SageMaker 将获取训练数据,并随后将模型工件和推理输出一起转储。

上传数据到 S3

您将在笔记本中找到的另一组代码是,您可以先本地测试批量推理而无需 SageMaker。获取您想要使用的模型,并在 train.csv 文件中对其进行本地训练。之后,获取模型工件(Sklearn 的 joblib 文件)并使用 test.csv 文件执行推理。如果您可以在本地执行批量推理,那么您就知道如何在您的训练脚本中调整您的推理处理函数。这是在开始 SageMaker 培训或推断之前和调试 的一个很好的方式。

现在我们可以创建我们的 Sklearn 估算器,它自动为 Sklearn 提取亚马逊支持的图像。在这里,我们可以用我们的模型和推理处理器来填充我们的训练脚本。

Sklearn 估计量

培训脚本

训练成功(作者截图)

在下一节中,我们将看看处理输入的推理函数。

批量转换示例

在培训脚本中,您会注意到 input_fn 已经配置为处理 CSV 输入。对于您自己创建的示例,这是需要针对您的模型所期望的输入进行调整的函数。在这种情况下,我们将输入一个 CSV,因此我们为此配置输入处理程序。

输入函数

训练完成后,我们现在可以进入批量推断部分。使用批处理推理我们不像其他三个 SageMaker 推理选项那样使用端点。这里我们实例化一个 Transformer 对象,它将使用您提供的参数启动一个批处理转换作业。类似于实时推理,我们可以抓住经过训练的估计器,并根据它创建一个转换器。

变压器

尽管我们在本文中没有涉及到,但是您可以调整来优化批处理推断的两个旋钮是:max _ concurrent _ transformsmax_payload 。使用 max payload,您可以控制输入有效负载大小,使用 concurrent transformations,您可以控制发送到转换作业中每个实例的并行请求数量**。默认情况下,它们被设置为下面截图中显示的值。**

批处理作业成功(作者截图)

我们现在可以执行我们的转换作业,您也可以通过 SageMaker 控制台对此进行监控。

转换作业

控制台(作者截图)

工作完成后,结果将被转储到 S3 位置。我们可以使用 SageMaker 的 Boto3 客户端来获取 S3 URI,并解析结果文件来显示我们的输出。

解析转换结果(作者截图)

转换结果(作者截图)

其他资源和结论

https://github.com/RamVegiraju/SageMaker-Deployment/tree/master/BatchTransform/BYOM-Sklearn

关于示例的整个代码,请访问上方的链接**。批处理推理有大量的用例,我希望这篇文章可以作为一个很好的入门和参考,让您用自己的模型和工作负载来尝试这个推理选项。在下面的链接查看另一个很酷的批量推理例子。如果你更喜欢视频教程,下面的课程中有一个很棒的批量转换部分。**

一如既往,我希望这是一篇关于 SageMaker 推论的好文章,欢迎在评论中留下任何反馈或问题。如果你对更多 AWS/SageMaker 相关内容感兴趣,请查看我为你编辑的这个列表。

如果你喜欢这篇文章,请在LinkedIn上与我联系,并订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。

SageMaker 定制多容器端点

原文:https://towardsdatascience.com/sagemaker-custom-multi-container-endpoints-21123f794c58

自带带有多容器端点的容器

图片来自 Unsplash 作者滕玉红

我曾经写过亚马逊 SageMaker 提供的各种推理选项。特别是,实时推理有大量的选项,您可以根据自己特定的机器学习用例进行选择。特别是在这篇文章中,我们将看一个带有 多容器端点 中一个更高级选项的例子。

多容器端点的用例是什么?有时你可能有个不同的框架来评估或用于推理。例如,您可能有两个模型,一个在 PyTorch 中,另一个在 TensorFlow 中。你不能把它放在多模型端点上,因为有一个公共框架的严格要求。多容器端点允许您使用 2-15 个不同的容器,您可以在一个端点后托管这些容器。它们也可以在一个叫做串行推理管道的东西中链接在一起。要完全理解多模型和多容器端点之间的区别,请查看这篇文章。

具体到这个例子,我们将看看如何将自己的定制容器与两个不同的定制 NLP 库在空间和文本块中带到一个多容器端点。SageMaker 的深度学习图像不支持这些框架,所以我们必须为每个框架构建自己的容器,并将其缝合在多容器端点之后。我们将跳过许多与自带容器相关的步骤,因此我鼓励您查看我在上面链接的定制容器文章。我们将以此为基础创建多容器端点。

**注意:**对于刚接触 AWS 的人来说,如果你想继续学习,请确保在下面的 链接 中注册账户。部署过程中会产生成本,尤其是如果您让端点保持运行。本文还将假设您对 SageMaker 和 AWS 有一定的了解。

目录

  1. 设置
  2. 构建模型和端点配置
  3. 创建端点和调用
  4. 其他资源和结论

设置

在开始使用多容器端点之前,我们需要在 Spacy 和 Textblob 中为我们的两个框架设置单独的容器。为此,我们需要为两者提供一个 docker 文件。

Textblob Dockerfile

空间文件

文件设置仍然与自带容器(BYOC)方法基本相同。主要的变化是我们需要考虑这样一个事实,即在多容器端点中,容器监听在SAGEMAKER_BIND_TO_PORT环境变量中指定的端口。在单个容器中,这被硬编码为 8080,为了反映这一变化,我们更新了容器设置中的 nginx.conf 和 serve 文件。您可以为您的多容器设置原样复制这些文件。你需要做的一个关键改变是添加下面的标签(如上所示)以确保你的容器符合这个要求。

添加到多容器中的 docker 文件

您可以在下面的文档中了解更多信息。现在,确保编辑 predictor.py 文件,以反映您的模型所具有的推理逻辑。将您的定制映像推送到 ECR 后,我们可以设置 boto3 SageMaker 客户端,并准备创建我们的多容器端点。

客户端设置

使用这些客户端,我们现在已经准备好完成通常的模型、端点配置和端点创建步骤。

构建模型和端点配置

首先,我们为不同的容器指定 ECR 映像 URI,然后指定我们希望在一个执行配置对象中直接调用(这是特定于多容器端点的)。

容器图像 URIs

我们指定的 ContainerHostname 键是我们稍后将用来调用特定容器的名称。使用我们的 SageMaker 客户端,我们可以创建一个模型,指定我们刚刚定义的两个容器。

多容器模型设置

通过在我们的 create_model API 调用中指定 containers 参数,我们告诉 SageMaker 我们正在处理一个多容器端点。然后,我们可以将这个模型提供给我们的端点配置。

端点配置创建

在这里,我们指定端点配置细节,例如实例类型,确保选择适合您的模型和容器大小的实例。

创建端点和调用

现在,我们可以采用端点配置并创建我们的端点。

创建端点

在您的端点处于状态之后,您应该能够通过指定 TargetContainerHostName 来调用这两个容器。

空间容器

空间推理(作者截图)

TextBlob 容器

TextBlob 推断(作者截图)

确保删除您的端点和任何您不希望保持挂起状态的资源。

其他资源和结论

https://github.com/RamVegiraju/SageMaker-Deployment/tree/master/RealTime/Multi-Container/mce-custom

要访问示例中的完整代码,请查看上方的链接,还有大量其他 SageMaker 推理示例和资源。如果您已经设置了一个自定义容器,那么将多个引入到多容器端点并不困难,正如您在本例中所看到的。再一次,确保根据需要调整你的 Dockerfile 和 predictor . py来反映你的框架。

多容器端点为复杂的机器学习推理系统提供了极大的灵活性。我希望这篇文章是关于多容器端点和 SageMaker 推理的好入门。

如果你喜欢这篇文章,请在LinkedIn上与我联系,并订阅我的媒体 简讯 。如果你是新来的中号,用我的 会员推荐 报名吧。

SageMaker 多模型与多容器端点

原文:https://towardsdatascience.com/sagemaker-multi-model-vs-multi-container-endpoints-304f4c151540

使用哪个实时推理选项

Amazon SageMaker 为模型托管和部署提供了过多的推理选项。在推论内具体有四个主要选项:

  1. 实时推断
  2. 无服务器推断
  3. 批量转换
  4. 异步推理

出于本文的目的,我们将关注实时推理。当您需要一个具有严格延迟需求(亚毫秒级)的持久端点时,实时推理是理想的。在实时推理中,你也可以使用不同的选项。最简单的形式是,您可以拥有一个端点,其中包含一个由一个实例支持的模型。让我们来看看这个基本架构是什么样子的。

作者截图

您可以为 TensorFlow、PyTorch、Sklearn 等流行框架创建一个模型并检索一个 SageMaker 支持的图像。如果你正在为你的模型使用一个定制的框架,那么你也可以使用你自己的容器来安装你的依赖项。

随着你的 ML 平台变得越来越复杂,有更多的高级选项,如多模型端点和多容器端点。让我们看一下每种产品的架构,以了解它们的使用情形。

多模型端点(MME)

多模型端点帮助您将数千个模型扩展到一个端点。通过使用共享的服务容器,您可以在同一个端点中以经济高效的可伸缩方式托管多个模型。该体系结构将不同于下图所示的单个模型端点。

MME 架构(作者截图)

底层基础设施(容器+实例)保持不变,但是主要的区别在于可以装载到这个容器上的模型。类似于单个模型端点的部署,您需要指向模型数据。这里的关键区别是,您将拥有多个模型数据/工件,而不是一个,您需要为您拥有的每个模型加载它们。像单模型端点这样的工件存储在 S3,但是为了让 SageMaker 意识到您正在处理一个多模型端点,您将把所有的模型数据放在一个公共的 S3 位置。模型数据也需要压缩成 modelname.tar.gz 格式,以便 SageMaker 理解。

模型数据结构(作者截图)

使用 MME 需要理解的最重要的特性是所有的模型都必须在同一个框架中构建。例如,MME 中的所有模型应该是纯粹的 PyTorch,或者纯粹的 TensorFlow,或者纯粹的您正在处理的自定义框架。您不能混合和匹配具有多模型端点的模型框架。

现在可能会有一个问题,为什么不只是有一堆单一模型端点,而不是在一个多模型端点上加载所有的模型。简而言之,将所有模型加载到一个端点上更具成本效益。例如,假设您有 10 个想要部署的模型。如果我们为每个端点部署一个 ml.c5.large 实例,我们就有 10 个持久端点在运行。如果我们看一下这个实例的定价,它是每小时 0.102 美元。

10 个单一模型端点:10 * $ 0.102 =每小时$ 1.02

另一方面,如果我们用一个 ml.c5.large 实例将所有 10 个模型加载到一个多模型端点上,我们可以节省 10 倍。

1 个多型号终点(10 个型号):1 个& $.102 = $.102 每小时

多模型端点资源

多模型端点张量流示例

多模型终点文件

多容器端点(MCE)

我们讨论多模型端点的一个警告是,我们不能混合和匹配框架。多容器端点解决了这个问题,您可以为您将要使用的不同框架提供容器。例如,您可以在同一个端点上加载 PyTorch 和 TensorFlow 容器。

多容器结构(作者截图)

多容器端点还提供了强大的功能,您可以在一个串行推理管道中将容器缝合在一起,或者调用您选择的容器。串行推理管道允许你将 2-15 个容器连接在一起,一个容器的输出成为下一个容器的输入。这是一个理想的用例,例如,如果您有 Sklearn 预处理容器- > TensorFlow 模型。

多容器端点资源

多容器示例

串行推理流水线示例

代码差异

使用 SageMaker 的许多步骤都可以通过 Boto3 Python SDK 来完成,您可以在其中创建一个 SageMaker 客户端。任何 SageMaker 端点的三个主要部署步骤如下。

  1. SageMaker 模型创建(提供模型数据+图像)
  2. SageMaker 端点配置创建(获取模型名称,在创建端点之前添加实例详细信息/配置)
  3. 端点创建(需要 3-4 分钟实施端点配置的详细信息)
  4. 端点调用

像任何其他实时端点一样,多模型和多容器端点遵循相同的方法。对于区分这两者的几个步骤,需要添加一些微小的差异。

模型设定

对于多模型,我们想要指定包含模型工件的模型前缀(S3 位置)。对于多容器,我们需要指定我们在这个用例中处理的不同图像/容器。

MCE 模型创建

这里,我们在 create_model 调用中用 containers 参数指定了两个不同的容器。

下一个需要注意的主要区别是端点是如何被调用的,通过下面的代码示例,这一点是显而易见的。

MME 调用

对于 MME,您在调用中指定一个名为 TargetModel 的参数,并指定您想要调用的模型。

MCE 调用

类似地,对于 MCE,有一个名为 TargetContainerHostname 的参数,您可以在其中指定要调用的容器。

结论和附加资源

Amazon SageMaker 有一个不断扩大的推理选项列表。使用对您的用例最有效的选项是很重要的,我希望这篇文章已经阐明了使用这两个选项中的哪一个。我在下面附上更多关于推论和 SageMaker 的资源。

SageMaker 推理范例库

SageMaker 推理推荐器选择正确的实例

如果你喜欢这篇文章,请在LinkedIn上联系我,订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。

SageMaker Python SDK vs Boto3 SDK

原文:https://towardsdatascience.com/sagemaker-python-sdk-vs-boto3-sdk-45c424e8e250

在 Amazon SageMaker 中使用哪个 SDK 以及在哪里使用

图片来自的UnsplashHitesh Choudhary

SageMaker Python SDK 和 Boto3 Python SDK 经常导致与亚马逊 SageMaker 的许多混淆。至少在我开始使用的时候是这样,直到我获得了更多使用这项服务的经验。

让我们快速地在两者之间建立一个清晰的区别,然后深入一些例子。SageMaker Python SDK 是一个开源的库,专门用于在 SageMaker 上训练和部署模型。该软件包旨在简化 Amazon SageMaker 上不同的 ML 流程。

另一方面, Boto3 SDK 是用于 AWS 的通用 Python SDK 。您也可以使用这个 SDK 与 SageMaker 之外的任何 AWS 服务进行交互。如果您更喜欢使用 Python 之外的语言,那么在流行的语言中有许多具有相同 API 调用的相应 SDK,比如 Java 、 Go 等等。

什么时候用什么

SageMaker SDK

这两个 SDK 可以用于相同的任务,但在某些情况下,使用其中一个比使用另一个更直观。例如,SageMaker as a service 为 Sklearn、PyTorch 和 TensorFlow 等流行框架提供预构建和维护的映像。您可以使用 SageMaker SDK检索这些图像,而不必担心使用 Docker。它们还通过在这些框架内为训练提供现成的评估器来帮助去除任何图像处理或维护。请看下面的例子,了解使用 SageMaker SDK 和支持的框架进行训练是多么容易。

使用为 TensorFlow 提供的 SageMaker 估算器进行培训

从您用于培训的评估器直接部署也非常容易。SageMaker SDK 通过从您传递给评估器的参数中进行推断,负责模型和端点配置的创建。您可以使用简单的“部署”API 调用直接部署到端点。

直接部署到端点

总之,当您有 SageMaker 支持的框架时,使用 SageMaker SDK 是一个很好的实践。除此之外,如果您在 SageMaker 上使用这个框架进行培训和部署,那么通过使用 SageMaker SDK 就非常简单了。

Boto3 SDK

另一方面,有时你有预先训练好的模型或者你可能使用的不同框架。这需要更多的定制,而 SageMaker SDK 并不总是提供这种功能。为了演示这一点,我们来看一个自带容器(BYOC) 的例子,其中有一个预先训练好的 NLP 模型,您希望部署它来进行推理。在这种情况下,您有一个自己提供的图像和自己的定制框架,而不是 SageMaker 自带的。

我们有三个重要的步骤和相应的 boto3 API 调用,我们需要执行它们来部署端点:模型创建、端点配置创建和端点创建。前两个实体是通过 SageMaker SDK 和我们支持的框架抽象出来的,但是我们可以通过 Boto3 SDK 看到这些细节。

首先,我们实例化将要使用的客户端。sm_client 对象是我们将在我们详述的三个步骤中使用的对象。

模型创建

端点配置创建

端点创建

使用这个客户端,我们可以用 SageMaker SDK 提供的相同细节来配置我们的三个 API 调用。这里的主要区别是我们可以灵活地用环境变量或不同的特性来检查和定制三个步骤中的每一个。除此之外,我们有能力带来我们自己的框架或预先训练的模型,或者两者兼而有之。

另一个要考虑的主要因素是,当您使用更高级的 SageMaker 产品时,如多模型端点或多容器端点,当您处理增加的定制时,通过 Boto3 获得完全的灵活性和控制变得更容易。

总之,当您处理具有更大定制的用例时,请使用 Boto3 SDK。这个选项有更大的灵活性,随着你的 ML 平台变得更加复杂,你可以利用 Boto3 SDK

结论和附加资源

我希望这篇文章对这两个 SDK 之间的用法差异有所澄清。同样,两者都可以用于相同的目的,或者在很多时候结合使用,但是在特定的用例中使用一个会容易得多。我在下面附上了 BYOC 和 SageMaker SDK 示例的完整代码。

  • BYOC 示例代码
  • SageMaker SDK TensorFlow 培训&部署

如果你喜欢这篇文章,请在 LinkedIn 上与我联系,并订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。

SageMaker 无服务器推理现在已经普遍可用

原文:https://towardsdatascience.com/sagemaker-serverless-inference-is-now-generally-available-e42550a146fe

探索最新的 SageMaker 推理选项

由泰勒维克从取消的图片

写这篇文章让我超级兴奋。ML 推理本身就超级有趣。添加无服务器,它会变得更加有趣!当我们谈到无服务器推理之前,我们不得不考虑可能使用的服务,如 AWS Lambda 。Lambda 等服务的问题在于,它们没有现成的托管 ML 基础设施工具。你必须自己建立、管理和维护所有的容器、ML 基础设施。

SageMaker 无服务器推理将所有这些抽象出来。它允许你专注于模型构建过程,不需要像 Lambda 那样维护你自己的容器。无服务器推理从其他 SageMaker 推理选项中获得了相同的核心基础。它仍然支持 AWS 深度学习图像/框架和自带容器(BYOC) 方法的灵活性。如果您在 SageMaker 上已经有实时推理工作负载,那么您可以保留大部分相同的代码,并添加包含无服务器配置的代码片段。在本文中,我们将探索一个将 Sklearn 模型部署到 SageMaker 无服务器端点的示例。

**注意:**对于刚接触 AWS 的人来说,如果你想继续学习,请确保在下面的 链接 中注册账户。部署过程中会产生成本,尤其是如果您让端点保持运行。本文还将假设您对 SageMaker 和 AWS 有一定的了解。

目录

  1. 何时使用无服务器推理
  2. 无服务器推理支持什么?
  3. 无服务器推理示例
  4. 其他资源和结论

何时使用无服务器推理

目前 SageMaker 推理有四个主要选项:实时推理、批量推理、异步推理,以及现在的无服务器推理。在过去的文章中,我解释了前三个选项的用例。那么什么时候使用无服务器推理呢?

当你有间歇性不可预测的工作负载时,无服务器推理是一个很好的选择。理想情况下,您的工作负载应该能够承受任何无服务器解决方案的冷启动。使用无服务器推理的另一个主要原因是没有基础设施管理。如果你不想处理自动缩放或实例管理/设置,那么无服务器推理是一个很好的选择。无服务器推理的另一个主要价值主张是节约成本。你通过调用为无服务器推理付费,而不是通过实时推理按小时计费。如果您的团队正在 SageMaker 上构建一个 POC 并且不想在此过程中产生大量费用,这是一个很好的选择。

无服务器推理支持什么?

在 Reinvent 2021 中推出无服务器推理预览版后,增加了一些关键功能。启用了 SageMaker Python SDK 支持,这使得使用 Amazon SageMaker 进行无服务器推理来训练和部署受支持的容器/框架变得前所未有的容易。您还可以使用模型注册表进行无服务器推断,这将为您的 MLOps 工作流添加无服务器端点提供灵活性。最后,每个端点的最大并发调用已经增加到 200 (预览时为 50)。

无服务器推理示例

对于我们的无服务器推理示例,我们将使用 California Housing 数据集训练和部署 Sklearn 模型。该数据集在 SageMaker 示例数据集存储库中公开提供,我们将展示您可以在笔记本中检索它。

对于设置,我们将使用 SageMaker StudioPython3 数据科学内核。您还可以使用经典笔记本实例并使用 ml.m5.xlarge 笔记本实例conda_python3 内核。一旦你在你的笔记本上,我们将设置我们的 S3 桶和培训实例。

S3 和培训设置

接下来,我们将从公共 SageMaker 样本中检索加利福尼亚住房数据集。这是一个回归问题,我们将使用 Sklearn 框架来解决它。

检索数据集

然后,我们可以使用 Pandas 读取数据集,以确保我们已经正确地创建了数据帧。

读取数据集

数据集头(作者截图)

然后,我们将这个数据集上传到 S3,SageMaker 将在那里访问训练数据并转储模型工件。

上传数据到 S3

Sklearn 是 SageMaker 提供的支持深度学习的容器之一,因此我们可以直接使用 SageMaker Python SDK 抓取图像,而无需处理任何 Docker 相关的工作。

Sklearn 估计量

这里我们传入一个包含模型和推理函数的入口点脚本。我们不会深入讨论这个例子中的脚本模式,而是看一看这篇文章来了解如何在亚马逊 SageMaker 上训练 Sklearn 模型。

如果我们快速浏览一下训练脚本,我们可以看到我们正在使用一个随机森林模型。

培训脚本中的模型

请注意处理输入的函数。 input_fn 决定了数据格式的类型,您可以为您的模型推断传递该数据格式。要了解更多关于推理处理器的信息,请查看这篇文章。

现在,我们可以使用我们的 Sklearn 估计器执行模型训练。

火车模型

培训完成(作者截图)

训练完成后,我们现在可以进行推理了。到目前为止,一切都与实时推理或任何其他 SageMaker 推理选项完全相同。在这里,我们可以通过 SageMaker Python SDK 添加一个 ServerlessConfig,并将其附加到我们的端点。

这里的两个参数是 MemorySize 和 MaxConcurrency。内存大小一般应该是最小的****和你的型号一样大的**。您可以将内存设置为以下值: 1024 MB、2048 MB、3072 MB、4096 MB、5120 MB 或 6144 MBMaxConcurrency 是单个端点的最大并发调用数,现在已经增加到 GA 的 200 。这是您必须为无服务器端点指定的唯一两个参数,所有基础设施工作和管理都在幕后进行。**

无服务器配置对象

现在,我们可以像往常一样部署端点并附加这个对象。

无服务器端点部署

现在我们可以看到这个端点的一个简单推论。

示例调用

推论(作者截图)

其他资源和结论

**https://github.com/RamVegiraju/SageMaker-Deployment/blob/master/Serverless/Sklearn/sklearn-serverless.ipynb

有关示例的完整代码,请访问上面的链接。关于使用无服务器推理的模型注册的例子,请看这个例子。关于无服务器推理的拥抱脸的例子,看看这个博客和例子。对于 AWS 官方博客发布的无服务器推理,请查看下面的文章。

一如既往,我希望这是一篇关于 SageMaker 推论的好文章,欢迎在评论中留下任何反馈或问题。如果你对更多 AWS/SageMaker 相关内容感兴趣,请查看我为你编辑的这个列表。**

如果你喜欢这篇文章,请在LinkedIn上与我联系,并订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。

意大利香肠浓缩咖啡

原文:https://towardsdatascience.com/salami-espresso-shots-d94abad77805

咖啡数据科学

对整个镜头提取的另一种看法

我喜欢腌肉,但是意大利香肠浓缩咖啡不是腌肉。意大利香肠是一杯浓缩咖啡,切成几杯。这是非常有用的帮助一个人品尝镜头,因为它发展。利用意大利香肠可以帮助人们找到最佳的输出比。

所有图片由作者提供

萨拉米香肠的另一个用途是观察咖啡萃取物在整个过程中的变化。几年前我已经这样做过了,我决定用同样的咖啡烘焙的几个变种再做一次。

第一个杯子有如此高的 TDS,我用等量的水滴定样品。

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是记分卡 7 个指标(尖锐、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

设备/技术

浓缩咖啡机:像样的浓缩咖啡

咖啡研磨机:小生零

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏捣实、断奏、圆盘中的滤纸

预输注:长,约 25 秒

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计、 Acaia 比重秤、 Kruve 筛、滤纸(PFF)

整个注射过程中的提取率(EY)

我的常规注射比正常注射有更高的 EY,部分原因是预输注时间更长。在这种情况下,断奏镜头显然是赢家,但我很惊讶纸过滤器(PFF)没有改善断奏镜头。我也很惊讶常规拍摄中的纸质滤镜没有改善 EY。这可能是因为需要做得更好,但我没有调查。

底部的 PFF 和中间的 PFF 开始于同一个 EY,但是随着拍摄的进行,它的提取率上升了。

当我们查看每个输出的 EY 占最终 EY 的百分比时,在 1:1 时,80%的断奏镜头被提取出来。类似地,大约 75%的其他镜头是在 1:1 中提取的。这就是我保持接近 1:1 命中率的原因。通常在 1:1 和 1.3:1 之间。

就可能的最大 EY 而言(以 2.5:1 的比率拍摄的断奏的 EY,27%),我们可以看到与之前类似的图表。然而,这显示了断奏镜头和其余镜头之间的对比。

品尝 1:1

我把咖啡混合成 1:1 的比例,然后给它们打分。我还为每个人收集了一个新的 TDS 样本。

断奏是明显的赢家,但即使 TDS 更低,我也看不出有或没有纸质过滤器(PFF)在味道上有什么不同。

****

正常拍摄的味道分数下降了,这不是纸质过滤器应该如何影响味道的典型情况。还是那句话,我没有调查。

萨拉米香肠镜头是一个非常有用的工具,可以帮助你了解你的镜头是如何表现的。挑战总是存在于数据收集中。这个数据是一个很小的数据集,我已经查看了关于 1:1 和 3:1 提取的其他数据。对于断奏的镜头,这是另一个证据:

  1. 断奏镜头比常规镜头提取率更高。
  2. 80%的断奏镜头提取发生在 1:1,90%发生在 1.5:1

这个数据的警告是它是少量的数据。我确信不同的烘烤或休息时间会影响这些曲线。

至少对于口味检查,我会鼓励每个制作浓缩咖啡的人至少做一次意大利腊肠测试,以更好地了解味道来自哪里。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在中和订阅。

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

意大利香肠筛咖啡

原文:https://towardsdatascience.com/salami-sifting-coffee-17024b484e34

咖啡数据科学

对粒子如何自我组织的探索

我筛了很多咖啡。到目前为止,我很有可能已经手工筛过了大部分咖啡。然而,我仍然在寻找更多关于筛选咖啡的信息,因为我仍然缺乏对咖啡豆的了解。

正如我在调查内部粉末时发现的那样,咖啡豆不是同质的。

我注意到在用 300 微米的筛子筛咖啡时,开始和结束时会产生不同的粉末。所以我决定用意大利香肠筛,用粒子分布来研究研磨物。

所有图片由作者提供

我为每一个都拍了照片,你可以从头到尾看到,粒子似乎变得越来越粗糙。

最简单的比较是第一个和最后一个样本。

然后我给每个样本拍了照片。

左:第一个样本,右:最后一个样本

然后我用图像处理根据每个颗粒的面积来测量颗粒大小。有 16 个样本,我在这里只画了 4 个:

有一个明显的转变,但不是马上就开始出现。让我们来看一下每一项的累积分布。例如,第一行是 408 微米,所以每个点是小于或等于 408 微米的粒子的百分比。

301 微米及以下的颗粒减少,这意味着在筛分结束时,较粗的颗粒被更频繁地筛分。

观察小于 100 微米的非常细小的颗粒,它们也会减少,到研磨结束时,95%的颗粒在 195 微米以上,而开始时只有 70%。

这个简短的研究表明,即使是筛选也不是均匀的。这也告诉我,我可以筛选出一定比例的粉末,将较大的粉末留在不同的层中,以制作断续浓缩咖啡。我很好奇,想进一步研究这些粉末在显微镜下是什么样子,并想知道为什么所有的粉末不能均匀地过筛。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。

我的进一步阅读:

我的未来之书

我的链接

浓缩咖啡系列文章

工作和学校故事集

烘焙前腌制生咖啡豆

原文:https://towardsdatascience.com/salting-green-coffee-beans-before-roasting-9c1c2ab2fc90

咖啡数据科学

将烹饪应用于烧烤?

我一直在想水。我已经尝试过用我的水配方做实验,但是我仍然不知道该往哪个方向走,因为我的过滤水总是胜出。在水的讨论中,有关于使用蒸馏水,然后在注射后添加矿物质的讨论。这让我想起了烹饪。我过去常常在食物做好后加盐,但后来我学会了烹饪,发现你应该在烹饪前调味。

冲泡咖啡时,水中有一定量的盐,有的还在浓缩咖啡中加入了盐以减少苦味。我想知道,如果在冲泡咖啡时加盐调味,为什么不在烘焙之前试着把盐加入到咖啡豆中呢?我做了一次烘焙,以更好地理解绿色咖啡的腌制。

所有图片由作者提供

我开始放了少量的盐,只是一小撮。盐重 0.36 克,然后我把它加入 6 克水中。一旦它溶解了,我就把它混合在青豆里,等了一夜。我还在我的对照样品中加入了 6 克水,因为我知道加入水分会影响烘焙。

两种烘烤物(盐渍的和未盐渍的)具有相似的重量损失(87.6%和 88.5%)和相似的密度(0.395 和 0.404)。

设备/技术

浓缩咖啡机 : 像样的浓缩咖啡机

咖啡研磨机 : 小生零

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏夯实

预灌注:长,约 25 秒

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计、 Acaia Pyxis 秤

绩效指标

我使用了两组指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是记分卡 7 个指标(尖锐、浓郁、糖浆、甜味、酸味、苦味和回味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

【IR】强度半径定义为 TDS vs EY 控制图上原点的半径,所以 IR = sqrt( TDS + EY)。这一指标有助于标准化产量或酿造比的击球性能。

数据

我最后得到了 9 对照片,它们在 TDS/EY/IR 上非常相似。盐腌的看起来稍微高一点,但是味道告诉了一个不同的故事。

从口感上来说,大部分盐拍的味道更差。它们尝起来盐味过重或味道太淡。它们是奇怪的品尝镜头。

我查看了个人得分指标,无盐在所有类别中都更好。

这个实验的方向是少放盐,但我没有注意到这个实验数据中有任何东西表明加盐的咖啡会改善特定的味道。我很高兴我试着给咖啡加盐,以防会有很大的不同。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在中和订阅。

我的进一步阅读:

我的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

样本比例不匹配:这么多问题。怎么回答他们?

原文:https://towardsdatascience.com/sample-ratio-mismatch-so-many-questions-how-to-answer-them-a86a1893e35

没有什么比数据验证问题更能让 A/B 测试程序泄气了 SRM 是最具破坏性的问题之一。但是 SRM 的测试到底有多准确呢?

作者图片

假设您有一个 A/B 测试,您希望每个测试组中的用户各占一半。相反,控制组和变异组的误差在 7%左右。总共有 8,000 名用户被分配到该实验中。

我们应该停止测试吗?我是说,我们有多确定问题存在?我们可以使用我在上一篇文章中描述的 Chi 测试。如果 Chi 测试为阴性,我们可能会问:看到这么大的差异正常吗?如果 Chi 测试呈阳性,我们会问:这是假阳性的几率有多大?

停止测试是非常具有破坏性的,我们不希望不必要地这样做。我们需要确定我们做出了正确的决定。

我经常被问到的其他问题是:假阳性(I 型错误)的风险是什么样的?此外,什么样的流量最适合进行高度准确的 SRM 检查?

这些问题或许可以用简单的数学和正态分布曲线等来回答。但我觉得用模拟来代替会很有趣。模拟为我们提供了真实的实验数据,我们可以对其进行询问和探索。我发现用模拟数据来解释事情更容易。

我的目标是在一个实验中模拟各种不同的网页流量负载,并进行分配和统计。这意味着流量将被随机分配到两个桶:A 和 b。由于我们不期望两组之间有任何差异,我们可以将这些视为 A/A 实验,并使用它们来探索随机机会可能发生的情况。

希望这能帮助我们回答我之前提出的一些问题。最后还有一个额外的问题,我也将探讨:SRM 的持续检查

我将使用 Python。所以,请随意在 Jupyter 笔记本或类似的东西上跟我一起出去玩(或对我的发现进行同行评审)。如果你对代码不感兴趣,完全信任我(你怎么了),那么你要么直接跳到步骤 5 ,要么直接到我的结论文末回顾我的发现和结论。

阶段 1:模拟随机分配

我的第一个任务是模拟测试工具在两个测试组之间随机分配流量的方式。这是我们的函数:

from random import randintdef traffic_sim(**traffic**):a,b =0,0for x in range(**traffic**):if randint(0,1) == 0:a +=1else:b += 1return (a,b)

traffic 参数是我想要在两组( AB) 之间分配的总流量。我使用 randint(0,1) 得到一个随机布尔值(0 或 1)。我用这个将我的假想用户分配到我的两个测试组。这有点像数字版的掷硬币。

这个函数的输出是一个元组(一个包含两个值的列表)。一个数字代表 A,另一个代表 b。

让我们用 100 个示例用户来运行它。

traffic_sim(**100**)

我的输出是:

(55, 45)

因此,我们在 A 中有 55 个用户,在 b 中有 45 个用户,我们期望的是 50/50。但这是我们得到的。不算太坏。

很明显,这个流量是超级低的。但这是测试这个功能的好方法。稍后我会以更高的音量回到这个话题。现在,我很好奇我的第一个例子 (55,45) 在使用 Chi 时是否有效。

步骤 2:使用 Chi 进行 SRM 检查

这里就不多解释这个功能了,因为你可以看我之前提到的关于这个 的文章(这是我最后一次链接文章了,老实说)

下面是功能。

from scipy.stats import chisquaredef srm_check(tup):diff = max(tup) - min(tup)total_traffic = (sum(tup))expected = sum(tup)/2perc_diff = (diff/(sum(tup)/2))*100chi = chisquare(tup, f_exp=expected)srm = Falseif chi[1] < 0.01:srm = Truereturn ({"srm":srm, 'diff':perc_diff})

我传入一个值元组( tup ),它表示我的 A 和 B 流量分配,然后返回一个字典,其中包含 SRM 的 True 或 False。我还得到了各组之间的百分比差异。如果我传入我的元组(55,45),我得到这个:

{'srm': False, 'diff': 20.0}

因此,即使差异为 20%,SRM 检查也是错误的。有道理。这么低的成交量,看到 20%的几率在预期的随机几率之内。

这很好。但是,同样,这是低流量。放松点。我们稍后会讨论更多的内容。

步骤 3:定义多个样本

为单个模拟测试运行 SRM 限制太多。我想模拟成千上万次测试,以便更好地了解风险。我想要一个函数,返回我能看到的可能分裂的数目。

这是我的函数:

def get_samples(**traffic**, **samples**):list_results = []for x in range(**samples**):list_results.append( **srm_check**( **traffic_sim**(traffic) ) )newlist = sorted(list_results, key=lambda d: d['diff']) return newlist

此功能期望 流量样本 参数。

  • 交通量 我们要使用的总交通量。到目前为止,我们一直使用 100
  • 样本 我们要生成多少个模拟样本。到目前为止,我们只使用了 1

该函数运行我的流量模拟和 SRM 函数,以获得我想要的样本数。我将对其他函数的调用设为粗体。

我返回的是一个测试结果列表,每个结果都详细说明了 SRM 是真还是假。结果按差异的升序排序(最小差异到最大差异)。

让我们运行这个函数来获得 10 个实验结果,每个实验分配有 100 个用户。

get_samples( traffic=100, samples= 10 )

我明白了。

[{'srm': False, 'diff': 0.0},{'srm': False, 'diff': 4.0},{'srm': False, 'diff': 8.0},{'srm': False, 'diff': 8.0},{'srm': False, 'diff': 12.0},{'srm': False, 'diff': 12.0},{'srm': False, 'diff': 16.0},{'srm': False, 'diff': 20.0},{'srm': False, 'diff': 20.0},{'srm': False, 'diff': 36.0}]

对于每个实验,我验证 SRM 是否存在,并得到两组之间的%差异。如果测试证实 SRM 为“真”,我们认为这是假阳性。

正如你在上面看到的,这里没有假阳性,尽管我看到其中一个有 36%的差异。哎哟。

注意:我们看到如此大的差异的原因是因为我们的正态分布在这个体积上是宽的,这意味着在我们选择的概率范围内有可能得到各种各样的结果。

尽管如此,这是低流量。冷静点。我们快到了。在我推出更多的流量之前,我还有几个函数要做…

第四步:获得假阳性率,等等

回顾十个实验的列表很容易。我想最终用成千上万的实验来完成这个测试。手动检查成千上万的测试是一项繁重的工作。

我想创建一个函数来告诉我实验样本的假阳性率。

注意:由于我们使用的 p 值为< 0.01,我们预计这一比率约为 1%。让我们看看这是否成立。

这是我的函数。它获取我从上面的 srm_check 函数生成的样本列表,并以百分比形式输出误报率。

def get_false_positive_rate(**list_dictionary**):false_positive = 0for item in list_dictionary:if item['srm'] == True:false_positive += 1return ( false_positive / len(list_dictionary) )*100

接下来,我想看看 A 和 B 赋值之间的平均差是多少。这将让我知道我可能会在我的样本实验之间看到什么样的差异:

def get_mean_diff(list_dictionary):my_list = []for item in list_dictionary:my_list.append(item['diff'])return (sum(my_list)/len(my_list))

接下来,我很好奇在不触发 SRM 警报的情况下,A/B 组之间的最大差异**是多少?**这将使我对声明 SRM 的最小可检测效果有所了解。

同时想知道观察到的组间最大差异是多少? ( 在这种情况下,SRM 将被声明为真。)

下面这个函数可以处理上述两个问题。它接受样本列表和我们想要使用的 SRM 值(即真或假)。该函数返回在我的数据集中找到的最高数字。

def get_max_diff(**list_dictionary**, **srm_value**):my_list = [0]for item in **list_dictionary**:if item['srm'] == **srm_value**:my_list.append(item['diff'])return (max(my_list) )

接下来,让我们来看看我的数据的传播,并得到标准差。这将让我知道实验样本的正态分布曲线有多宽。下面的函数可以做到这一点:

def get_stdev(**list_dictionary**):my_list = []for item in **list_dictionary**:my_list.append(item['diff'])return statistics.stdev(my_list)

最后,我想将所有这些作为一个 dataframe 返回,这样我就可以很容易地在一个表格中浏览结果。该函数将执行以下操作:

import pandas as pddef get_dataframe(traffic, samples):results = []for item in traffic:list_dictionary = get_samples (item, samples)results.append({'Total traffic': item, 'SRM Type I rate':str(get_false_positive_rate(list_dictionary))+'%','Avg diff (SRM=False)': str(get_mean_diff(list_dictionary))+'%','Standard deviation': get_stdev(list_dictionary),'Max diff (SRM=False)': str(get_max_diff(list_dictionary, False))+'%','Max diff (SRM=True)': str(get_max_diff(list_dictionary, True))+'%' })

这个函数也将作为我的主函数。所以,我告诉这个函数:

  • 我要模拟多少流量作为列表 *。
  • 我想运行的实验数量。我使用的实验(或样本)越多,我期望的准确度就越高。

这个主函数然后调用我的其他函数,为我提供一个漂亮的结果表。

在这里看完整的 python 代码。

*我使用的是流量列表,所以我可以一次发送多个流量。

太好了。让我们来看看实际情况...

第五步:评估我的结果

我想模拟10000 次实验,检查它们的 SRM。实验将有不同的流量:1000、2000、3000等。一直到 2 万总用户

traffic = [1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,12000,13000,14000,15000,16000,17000,18000,19000,200000]get_dataframe(traffic=traffic, samples=10000)

小心不要用这个弄坏你的机器。这是机器需要处理的核心任务。这是我的结果。您的结果可能略有不同,但应该不会相差太远:

I 型比率是我们的误报率,对于所有交通量,它大致保持在 1% 。这是意料之中的,因为我们使用的 p 值为 < 0.01

平均差异是事情变得有趣的地方。请记住,这是我们测试组之间的平均差异。越接近零越好。在低流量(1000 和 2000)时,平均差异较大(5.0%和 3.6%)。随着流量的增加,这种差异逐渐变小。

标准偏差是我们检查数据分布的地方。这告诉我们,在不同的交通流量条件下,我们的每个样本实验的差异有多大。

**最大差异(SRM =假)**是 SRM 警报跳闸前测试组之间的最大差异。接近零是最好的。我们可以看到,当流量较低(1,000 和 2,000)时,SRM 警报将在较高的差异百分比(16%和 11.4%)时触发。随着时间的推移,这种情况会逐渐减少。

最大差异(SRM=True) 是随机分配用户时观察到的最大差异。我们的 SRM 检查将触发这些值的正值。我们可以看到在低流量时有很高的百分比差异。不过,这些数字是不稳定的。每次我们运行模拟,我们得到非常不同的值,有时比你在表中看到的要大。

Re:Max difference(SRM = True)。这实际上是有意义的,因为当其他数字通过使用 Chi 测试计算来控制时,最大差异(SRM=True)是我们由于随机机会而看到的最大差异,并且不受任何种类的花哨统计的控制。很少会看到这些数字,但是追踪异常值的趋势还是很有趣的。

这是我们将结果绘制成线图时的样子。

图片作者。绘制流量增加时 A/B 测试的 SRM 图

我们的流量越多,我们能看到的偶然差异就越小。在分配了 10,000 多个用户的情况下,SRM 触发前测试组之间的百分比差异为<5%. At 65,000+ users this % difference drops to < 2%. So, the Chi Test becomes more accurate.

A quick note from Lukas Vermeer on this before we continue:

Lukas Vermeer’s note on LinkedIn: you can also use the power calculation.

Basically, you can run a power test to get a similar value as 最大差异(SRM=False) 。这可能比运行这种昂贵的模拟更容易,但话说回来,我喜欢做困难的事情!

这是一张标准偏差图,展示了数据的分布如何随着流量的增加而减少:

图片由作者提供。标准偏差随着交通量的增加而减小

我们可以看到,在分配了 15,000 个用户时,标准偏差降至 1 以下。随着组间差异的扩大,总体标准偏差逐渐变好。

现在,我将是第一个承认这一切有点“嗯,废话。很明显。”但我在这里的目标是说明所有这些是如何工作的。它可能有助于点亮人们头脑中的灯泡。

但是等等,还有更多…

第六步:持续监控

所有这些都很好,但持续监控存在一个问题。以下是迈克尔·林顿为我们带来的更多信息:

"..许多从业者通过重复执行显著性测试来错误地持续监控他们的实验,通常是以一种特别的方式,没有任何多重性校正,不知不觉地增加了他们出现 I 型错误的机会。

引用 Michael Lindon 的文章: 测试样本比率不匹配(SRM)和验证实验实施的更好方法

基本上,我们检查得越频繁,看到假阳性的风险就越高。正是因为这个原因,我们用一个 p 值 < 0.01 来检测 SRM(再次使用,详见我之前的文章)。 Lukas Vermeer 的 SRM Chrome 扩展工具也使用了 < 0.01。

这是更高的显著性标准,有望降低假阳性的风险。但是真的吗?

让我们通过快速修改我的脚本来找出答案:

def traffic_sim(**increment**, **checks**):traffic = []a,b =0,0for c in range(**checks**):for i in range(**increment**):if randint(0,1) == 1:a +=1else:b += 1traffic.append((a,b))return (traffic)

我有两个循环。我们使用这些循环来创建元组列表(针对 A 和 B 流量)。这个元组列表按值递增:“递增”。列表中的项目数量模拟了我们要做的检查的数量

这应该模拟用户随着流量的增加反复检查 SRM。

例如,这里我模拟了 10 次检查,其中用户以 100 个用户的增量进行检查。

traffic_sim(100, 10)

输出:

[(46, 54),(97, 103),(151, 149),(210, 190),(257, 243),(310, 290),(359, 341),(417, 383),(467, 433),(516, 484)]

是的,是的,我知道。发送更多的流量。不仅如此,这只模拟了一个单一实验。为什么要同时增加我们的样本量和检查 SRM 型错误。

我们可以使用以下附加函数来实现这一点:

def get_false_pos_incremental(samples, increment, checks):list_dictionary = []for x in range(samples):traff = traffic_sim(increment, checks)for t in traff:list_dictionary.append( srm_check( t ) ) return ( get_false_positive_rate(list_dictionary) )

这是我要运行的“**样本”**数量的另一个循环。

我还运行 Chi 测试来检查 SRM(前面定义的同一个函数)。最后,我将结果传递到我之前定义的"**get _ false _ positive _ rate "**函数中,以获得误报的百分比。

在这里查看完整的 Python 代码。

我运行这个:

get_false_pos_incremental(samples=10000, increment=100, checks=1000)

也就是10000 个实验者,检查 SRM1000 次,而流量则以 100 个总用户递增。

那么,结果如何呢?当我们将 Chi 测试 p 值设置为< 0.01 时,像这样连续监测会有什么风险导致 I 型错误?

1%

根据我的结果,持续监测的风险是 1% —也就是说,与监测一次测试没有区别。

注意:我完全同意我的代码和随后的发现接受同行评审。所以现在,对这些发现要持保留态度,直到被证实。我希望我的逻辑没有出错。如果有,请告诉我,我会在 LinkedIn 上更新这个帖子和消息,解释需要做出的更正。目前,我坚持这个结论。

编辑:我错了!上述 1%基于所有 SRM 声明为真的流量检查。如果我要在测试级别模拟用户检查 SRM,代码将需要更新为以下内容:

def get_false_pos_incremental(samples, increment, checks):list_dictionary = []for x in range(samples):traff_increment_list = traffic_sim(increment, checks)srm = {'srm': False, 'diff': 0}for t in traff_increment_list:if (srm_check(t)['srm']):srm = srm_check(t)list_dictionary.append(srm)return ( get_false_positive_rate(list_dictionary) 

感谢罗尼·科哈维纠正我的错误。实际结果要高得多:17%左右!!这是否改变了我下面的结论?不完全是。必须始终检查 SRM,但要密切注意 tred。

结论

最后,让我们回顾一下你现在可能会问自己的一些问题(如果我错过了什么,请务必在这里或 LinkedIn 上给我打电话)。

流量低时运行 SRM 检查可靠吗?

如果您使用 Chi 测试,那么什么时候运行检查并不重要。假阳性率总是 1%。但是,当流量较低时,您可能会看到较大的差异。

我应该何时开始运行 SRM 检查?

您可以并且应该尽早运行 SRM 检查,但是使用 Chi 来确定 SRM。不要只看你观察到的百分比差异。

持续监控 SRM 是否有风险?

根据我的发现不是。持续监测 SRM 时出现 I 型错误的风险为 1%当卡方检验 p 值为<0.01.

EDIT: Correction! Yes, there is a risk of a false positive. In order to be mindful of this, we need to monitor each test for trends in SRM.

时,是否存在组间差异正常化的最佳分配数?

随着时间的推移,组之间的差异百分比越来越小,SRM 检查的准确性也越来越好*(因为,它对较小的差异变得更加敏感)*随着流量的增加。

我不能给你一个标准化作业的最佳数量。这是一个渐进的过程。有关详细信息,请参见上面的“步骤 5”。

简而言之,尽早测试 SRM。经常测试。使用 Chi 测试,这很简单。您甚至可以在电子表格中运行它!详情见我之前的文章。

希望这些都有用。如果您有问题,请随时联系并询问。很高兴谈论它。

关于我这个“作者”

我是伊克巴尔·阿里。我帮助公司开展实验项目。这意味着设计、开发、培训和咨询他们,以便在内部建立有效的实验流程。

我也是一名漫画作家 **,**train line 前优化主管, A/B 决策工具的创造者。这里是我的 LinkedIn 如果你想联系。或者跟随我来到这里。

医疗保健中间断时间序列设计的样本容量规划

原文:https://towardsdatascience.com/sample-size-planning-for-interrupted-time-series-design-in-health-care-e16d22bba13f

这是最强的准实验设计之一。可以说,对研究的适当规划比分析本身更重要。

照片由 STIL 在 Unsplash 上拍摄

为什么要中断时间序列设计?

循证实践是现代医学的基础。为了将机器学习(ML)模型集成到临床护理中,我们需要能够将观察到的健康结果和/或运营效率的影响归因于具有高置信度的模型。

预测 ML 模型主要是基于观察数据开发的。然而,从这些观察性研究中得出因果关系是误导性的。它们可以为进一步的测试生成假设,但很少用于评估我们的模型在现实世界中的有效性。

随机对照试验(RCT)被认为是评估医疗保健创新的黄金标准方法。然而,在许多情况下,由于实际或道德障碍,RCT 是不可能的。中断时间序列(ITS)设计是一种可能的选择,事实上是最强的准实验设计之一。

什么是间断时间序列设计?

在 ITS 中,通过比较在引入干预措施之前的几个时间点和之后的几个时间点获得的结果测量来评估干预措施(例如,部署的 ML 模型)的效果。目标是检测干预的效果是否大于潜在趋势。

作者图片

智能交通系统的功率和样本容量规划

规划智能运输系统应该如何实施是至关重要的,甚至可以说比分析更重要。设计糟糕的研究永远无法恢复,而分析糟糕的研究可以重新分析。如何设计研究也决定了如何分析数据。为了确保研究的有效性和足够的能力,我们需要仔细计划样本量应该有多大,这也与研究应该持续多长时间以及我们应该多久收集一次数据密切相关。没有精确的公式来计算 ITS 所需的最小样本量。相反,有各种因素需要集体考虑:

  • 每个前段和后段中的时间点数量
  • 每个时间点的平均样本量
  • 时间点的频率(即每周、每月、每年等)。)
  • 介入位置(即中间、1/3、2/3 等。)
  • 预期效果大小

之前和之后的时间点数量

它依赖于一段时间内对一个结果事件的重复观察,通常间隔相等。这里,我们将对结果事件的观察称为时间序列分析中的时间点。ITS 设计中通常有两个:干预前段和干预后段。

关于所需的最少时间点数量,存在相互冲突的建议。建议范围从每段 3 个时间点到每段 50 个时间点。许多对 ITS 进行系统综述的论文甚至不考虑每个片段少于 3 个时间点的研究,因为它们的有效性值得怀疑。

根据用于分析时间序列趋势的方法,需要不同数量的时间点。例如,如果使用普通的最小二乘法(OLS),50 个时间点总体上可以被认为是一个长时间序列,但如果使用 ARIMA,50 个时间点是最小值。总的来说,可用的时间点越少,可以可靠地估计的相关结构越简单。

虽然在所需的最少时间点数量上没有黄金标准,但普遍的共识是较长的时间序列往往比较短的时间序列更有力量。

每个时间点的样本量

即使对于具有许多时间点的时间序列,如果只有少数受试者构成对结果事件的时间点的估计,由于噪音和可变性,也不太可能检测到真实的影响。构成每个时间点的大量受试者提供了更稳定的估计,从而减少了时间序列分析中的可变性和异常值。

时间点的频率

取决于时间间隔的选择,在时间点的数量和每个时间点的样本量之间存在权衡。为了优化研究能力,您可以牺牲每个时间点的样本量来增加时间点的总数,反之亦然。例如,平均每周有 10 个不同的主题可用于计算结果度量。你只能负担 6 个月的研究费用。如果选择时间点频率为每月,时间序列将由 6 个时间点组成,其中每个时间点的样本量为 40。如果选择频率为两周一次,则总共有 12 个时间点,每个时间点的样本量为 20。在大多数情况下,当以每个时间点的样本大小为代价延长时间序列时,只能获得很小的功率增益。当一个非常短的时间序列变长时,增益更明显。

如果可能,选择具有临床或季节性意义的频率,以便建立真正的潜在趋势。还要考虑是否可能存在延迟或减弱的干预效应,尤其是当影响逐渐发生时,可以据此选择频率。

干预的位置

您可以计划在时间序列的中间(最常见的情况)、时间序列的早期(例如,1/3 的时间点在干预之前)或时间序列的后期(例如,2/3 的时间点在干预之前)引入干预。只要每个时间段有足够的时间点,并且每个时间点都有足够大的样本量支持,那么早期或晚期干预的研究能力与中途干预相比没有太大差异。

预期效果大小

在开始实施你的研究之前,你应该假设如果干预有效的话会对结果产生怎样的影响。在 ITS 中,有两种主要类型的效果:

  • 斜率变化:趋势梯度(或斜率)的逐渐变化
  • 水平变化:水平的瞬间变化

作者图片

这两种效果不需要互相排斥。您可以更改高程、坡度或高程和坡度。这些变化也可能是暂时的,或者具有滞后性。

作者图片

效果大小是干预效果的大小。一般来说,检测大效果尺寸比检测小效果尺寸更容易。换句话说,当预期效应大小很大时,我们需要更少的时间点和每个时间点更小的样本量来确保足够的功效。

到目前为止,您可能已经注意到,本文没有为其提供任何简单的样本大小公式(抱歉!)因为没有。研究人员和数据科学家应该根据他们的具体场景考虑多种因素。本文中介绍的这些因素是为其设计的规划过程提供信息的最低要求集。

从未知规模的总体中抽样

原文:https://towardsdatascience.com/sampling-from-a-population-of-unknown-size-1b48fbfb3b33

流式项目的统一采样算法介绍

迪伦·诺尔特在 Unsplash 上的照片

取样任务

鲍勃在一家电子元件工厂从事质量控制工作。在他的任务中,每天他必须检查不同的产品,以识别可能的缺陷,并评估生产过程的整体平稳性。必须随机选择产品,并遵循统一的抽取概率(即统一抽样)。

但是产品出厂的数量 N 每天都在变化,无法提前设定。此外,Bob 不能等待所有的 N 产品都出来:他必须在产品出来时进行检查,因此取样过程必须在线进行。

我们需要采样流项目——按作者排序的图像

显然,Bob 需要一个策略来有效地完成他的任务。我们正在讨论从未知规模的总体中均匀抽样的问题。

问题的定义

为了解决采样问题,我们需要一种算法,通过对先验未知的大小为 n 的群体进行一次遍历,能够随机采样 k 个对象而无需替换。

作为附加要求,我们还将假设:

  • n 是一个比 k ( n≫ k )大得多的数,因此不可能将所有 n 项存储在内存中并对其进行提取;
  • 该算法无法提取已经通过的项目。

换句话说,该算法一次按顺序处理一个项目,并决定是否提取它。

该算法

这种算法是存在的,它包括以下步骤:

  1. 最初,Bob 提取所有第一个 k 项目(记住n≫k);
  2. 然后,对于 i > k+1 ,他以等于 k/n. 的概率提取第 n 个乘积
  3. 当一个新项目被添加到样本中时,在当前样本中随机选择的另一个项目相应地被丢弃。

在此过程之后,每次迭代中提取的样本结果(以及一些近似值)在 1n 之间均匀分布。

算法的证明

照片由 Aaron Burden 在 Unsplash

有趣的是,我们可以把算法想象成一个马尔可夫链。按照这种方法,在步骤状态n是包含到目前为止收集的项目的样本。处理新项目时,无论新项目是否添加到样本中,都会发生状态转换。

步骤 n 中的样本是介于 1 和 n 之间的自然数的子集-图片由作者提供

基于我们的算法如何工作,对于 n > k转移概率由下式给出:

步骤 k 后的转移概率-按作者分类的图像

现在我们需要证明对于每一步 n≥k 所有的状态都有相同的概率成为样本。我们可以通过归纳来证明。

因此,让我们假设在步骤 n≥k 所有子集 Sn 有相等的机会成为样本。因此,每个状态 S 成为步骤 n 的样本的概率为:

子集成为给定步骤中样本的概率-作者图片

在步骤 n+1 中,新样本 S 可以与之前相同,也可以包含新项目。在第一种情况下,我们有一个概率:

新样本与之前样本相同的概率-图片由作者提供

在第二种情况下,获得新样本的概率由下式给出:

新样本包含新项目的概率—按作者排序的图像

因子 1/(n+1) 作为k/(n+1)——即提取新项目的概率——和1/k——给定样本元素被新项目替换的概率的乘积来获得。

公式中的因子 n-k+1 考虑了样本中第 i 个项(以及该样本中不包含的 n-k 个项之一)被新项 n+1 替换的所有可能子集。

每个新样本都可以从以前的多个样本中派生出来——图片由作者提供

所以在每一步 n≥k 我们都有总的 n-k+2 个新的可能样本,并且它们中的每一个都有相同的概率被选中。

作为归纳基础,我们在 n=k 选取样本,根据我们的概率函数,选择概率为 1(这是正确的,因为我们这里只有一个可能的子集)。神盾局。

一个基本实现:算法 R

劳拉·奥克尔在 Unsplash 上的照片

记住了它的定义,就可以非常容易地编写一个工作算法,如下面的 Python 代码片段所示。

import numpy as np# Sampling parameters.
n_items = 1000
sample_size = 10sample = np.zeros(sample_size, dtype = int)
steps = np.arange(n_items)# Initial sample.
for nn in range(sample_size):sample[nn] = nnfor nn in range(sample_size, n_items):# Compute the current item.ii = np.random.randint(0, nn, dtype = int)if ii < sample_size:sample[ii] = nn

图中显示了 n=1000k=10 的结果。我们可以看到,在项目被处理时,样本的元素随机地从一个索引迁移到另一个索引,尽管一些最早的元素可能会随着时间的推移而持续存在。

运行算法-按作者分类的图像

上面讨论的实现通常被称为算法 R ,最初由 A. Waterman 提出,并由 J. Vitter 在[3]中讨论。由于每一项都需要一次计算,无论是否保留,这个算法的复杂度都是 O(n)

一个优化的变体:算法 L

算法 R 属于储层取样系列,该系列包括设计用于从未知数量 n 的总体中选择一个简单随机样本 k 项目的算法,无需替换。

所谓的算法 L 给出了算法 R 的优化变体。在【4】中讨论,该变量计算在下一个物品进入储槽之前有多少物品被丢弃:这是可能的,因为丢弃物品的数量根据几何分布分布,因此可以提前计算。这样一来,这个算法的复杂度降低到了O(k(log(n/k)+1))

其他变体:带权重的随机抽样

照片由 Piret Ilver 在 Unsplash 上拍摄

还有其他处理加权项目的变体。在这种情况下,权重与每个权重相关联。例如,一个人可能需要对 Twitter 上的帖子进行抽样,这些帖子的权重基于收到的浏览量(或互动量)。

我们可以看看为每一步定义两个不同选择概率的权重:

  1. 一个未被选中的项目被选中的概率与其权重与所有未被选中项目的权重之和的比值成正比;
  2. 任何被选中的概率与其权重和所有权重之和的比值成正比。

基于所使用的定义,已经开发了几种具有不同效率的算法。仅提及其中的一些,算法 A-ResA-ExpJ 用于定义 1, A-ChaoA-Chao 带跳转用于定义 2。

对于这个问题的广泛评论,特别是从编程的角度,我推荐 Startin 的这个博客。

和往常一样,本文使用的代码可以在这里找到:https://github.com/andrea-ci/misc-stuff。

参考

[1]维基百科,油藏取样

[2] StackExchange,从有限总体中抽取固定数量样本的算法

[3] Vitter,Jeffrey S .,“储层随机抽样”,1985 年

[4]李,金鸿,时间复杂度为 O(n(1+log(N/n))) ,1994

[5]理查德·斯塔廷,油藏取样

SAP 查询智能机器人

原文:https://towardsdatascience.com/sap-querying-intelligent-robot-12a4e301e876

用 SQUIR 自动提取 SAP 的表

使用机器人为重要的任务保存你的能量

您是否经常运行 SE16N 事务来从 SAP 中提取表格?如果你想自动化,你可以在这里找到解决方案。Squir (SAP 查询智能机器人)是一个独立的应用程序。该程序由 Python,一个用于参数选择的 Excel 模板,以及机器人需要与之交互的截图组成。多亏了 Pyinstaller,即使您的非 Pythonist 爱好者同事也可以轻松地使用该应用程序从 SAP 中自动导出表格。Squir 可以做重复无聊的事情,这样你就可以专注于更重要的任务。

解决方案:

在之前的帖子中,我们学习了如何使用 Pyautogui 构建 RPA 来自动化重复性任务:

我们将对上面的代码做一个改进。不设置静态计时:

...我们将用一种更动态的方法取代静态计时器。机器人将不断筛选,一旦图像弹出,例如在 20 秒的循环内,机器人将立即与该对象进行交互:

我们为 Squir 提供所有必要的截图。例如,要在 SAP 中运行 SE16N,必须找到此按钮:

Squir 需要查找的事务。

之后,Squir 必须在该选择字段中输入所需的表名:

Squir 必须键入表格的名称,例如 MARC

最后 Squir 会将结果导出为 txt:

正是像 OpenCV 这样的包让机器人变得如此迷人!你可以在我的 Github 里找到所有需要的 SE16N 截图。如果您的 SAP 应该有不同外观的对象,您可以轻松地用自己的截图替换。只保留原来的 png 名称。

现在我们已经编写了一个 Python 机器人来为我们完成这项工作。下一步,我们将使用 Pyinstaller 将我们的脚本转换为可执行文件:

由于 Pyinstaller,Python 文件转换为可执行文件

仍然缺少的是用户与机器人交互的简单方法。因此,我们提供了一个 Excel 模板,可以在其中输入所需的表格、变量、文件名等。在我们的示例中,您最多可以添加三个 SE16N 提取,机器人将运行这些提取:

您最多可以在此模板中输入三个表格

这意味着我们只需用一个循环稍微修改一下原始 RPA 代码,就可以从 Excel 中获取这些参数:

你可以在我的 github 中找到完整的 Python 代码。

祝贺您,现在您有了一个完整的独立应用程序来提取表格。您不再需要手动输入。只需将截图、exe 和 xls 文件全部保存在一个文件夹中,就可以开始运行可执行文件了。虽然这个例子是为 SAP 设计的,但是您当然也可以将代码调整到任何其他 ERP 上。

享受看斯奎尔现在为你做的工作。或者干脆不去管你的电脑,在新的空闲时间里做任何你想做的事情:

模拟仍然最摇滚(法国摇滚,作者图片)

非常感谢阅读,我希望这是支持。你可以在我的 Github 库里找到所有的截图、Python 代码和 Excel 模板。exe 文件存储在我的 Google Drive 里。欢迎在 LinkedIn 、 Twitter 或工作室(有或没有 VR) 与我联系。

新型冠状病毒废水数据,增强

原文:https://towardsdatascience.com/sars-cov-2-wastewater-data-enhanced-9717d8197f98

将 CDC 的废水数据与新冠肺炎的疫苗接种、住院和死亡数据相结合

由 Unsplash 上的融合医学动画拍摄的照片

背景

最近有很多关于追踪废水(下水道系统)中导致新冠肺炎病的新型冠状病毒病毒的新闻报道。一周后,废水中病毒数量的激增和疾病数量的激增之间建立了强有力的联系。仅作为一个例子,该图显示了美国各种水处理设施的病毒信号(深蓝色)与已知的美国新冠肺炎病例(浅蓝色)。

图片来自 biobot.io/data/,经许可使用

最近,美国疾病预防控制中心的国家废水监测系统(NWSS)发布了关于他们收集的废水信息的公共数据。他们的仪表板提供了一个很好的数据总结和主题介绍。

NWSS 还提供了两个详细的数据集,显示了对废水进行的每一项实验室测试及其结果。这些数据集包含许多列信息,包括:

  • 水处理设施的名称和位置
  • 收集样本的日期和时间
  • 排入下水道县和人口
  • 对污水进行的测试类型
  • 进行测试的实验室的身份
  • RNA 片段测试的数值结果

这些数据集可供签署数据使用协议的研究人员使用,以保护其中可能包含的机密个人信息。(有了一个小的下水道系统,就有可能推断出病人的名字。)

这两个详细数据集的不同之处在于,一个名为 raw 的数据集只包含事实,而另一个名为 analytical 的数据集包含许多列统计结果,这些结果可能有助于科学家分析数据。

一个问题

尽管详细的 CDC 废水数据很有价值,但它缺少一个关键领域——与其他真实世界新冠肺炎数据的相关性,如疫苗接种和疾病结果。数据集确实有该地区已知病例的信息,但简单的病例计数是出了名的不可靠。许多病人从未得到政府报告的聚合酶链式反应测试;测试的可用性每月都不同;当有可怕的新闻报道时,人们往往会冲出去进行测试;家庭测试也不向政府卫生部门报告。更准确的疾病严重程度的衡量标准是住院率、ICU 入院率和死亡率。

一种简单的方法是将废水样本采集当天的废水数据与疫苗接种率和疾病结果联系起来,但这不会有所帮助。在注射当天,接种疫苗不会降低疾病抵抗力。生病的人很少在出现症状的第一天去医院。不幸的是,当有人死于新冠肺炎时,这通常发生在他们进入医院几天之后。

为了了解疫苗接种如何影响废水中的新型冠状病毒,我们需要在收集废水的前几天(T0)观察不同的疫苗接种率(第一针、全程疫苗、加强疫苗)。为了了解废水是如何预测住院率的,我们需要看一下水测试后的医院数据。为了将废水与死亡率联系起来,我们需要一个更长的时间增量。

解决办法

我最近承担的一个数据工程项目解决了这些问题。它生成了一个增强版的 NWSS 详细数据集,包括该地区的疫苗接种、住院和死亡情况,这些事实的日期是在水测试之前或之后。例如,在描述 9 月 15 日在密歇根州 Arenac 县采集的水样的数据行中,添加了 9 月 5 日该县的完全疫苗接种率列,以及 9 月 29 日该县的 ICU 入院人数列。

推迟/提前日期很容易调整,并且可以很快重新生成数据集,例如,第一次接种推迟 21 天,死亡率提前 28 天。

我的数据集解决的另一个问题是,大多数美国新冠肺炎健康数据是在县一级(或州或国家)组织的。然而,水处理厂经常处理来自不止一个县的污水。我的代码重新格式化了 NWSS 的详细信息文件,以便每一行只显示一个县,从而更容易将数据集与可用的健康结果数据连接起来。

这是一个增强的行,显示了几个关键列,为了便于阅读,它们被垂直翻转:

**CountyFIPS** = 08069**pcr_gene_target** = n1**sample_collect_date** = 2022-01-20**pcr_target_units** = copies/l wastewater**pcr_target_avg_conc** = 490473.59**vax_date** = 2022-01-10\.  # 10 days before water sample**metrics.vaccinationsInitiatedRatio** = 0.724**metrics.vaccinationsCompletedRatio** = 0.656**metrics.vaccinationsAdditionalDoseRatio** = 0.324**cases_date** = 2022-01-27\. # 7 days after water sample**metrics.caseDensity100k** = 155.5**metrics.testPositivityRatio** = 0.214**hosp_date** = 2022-02-03\.  # 14 days after water sample**actuals.icuBeds.currentUsageCovid** = 13**actuals.hospitalBeds.currentUsageCovid** = 91**deaths_date** = 2022-02-10\.  # 21 days after water sample**actuals.newDeaths** = 2

增强的详细数据集的更大的匿名样本在我的 github 上,用于原始数据和分析数据。每个都有 1000 个随机的行和所有的列。

复制这个结果

要构建自己的增强型 NWSS 详细数据集:

  • 下载或克隆 Python/熊猫源代码。
  • 向 NWSS 申请获取废水样本的详细数据集。数据所有者的联系信息在数据描述页面上。请注意,此页面描述了汇总的公共 NWSS 数据,但联系人是相同的。
  • 下载新冠肺炎疫苗接种和结果数据,以及美国县人口,如源代码注释所示。这些将与 NWSS 详细数据集相结合,以制作增强版。

代码和样本数据是在 MIT 许可下发布的,只需要注明出处就可以重用或修改作品。

未来的工作

这个项目创建了这里描述的数据集,但是没有对它们进行任何特定的分析。显而易见,下一步是使用增强的数据集来寻找废水结果和 ICU 入院之间的相关性,或者第一次疫苗或完全疫苗接种是否对废水病毒有更大的影响,或者其中一个事件预测另一个事件的最佳时间增量。

这里讨论的数据是针对美国的。世界各地也有针对新型冠状病毒 RNA 的废水检测。进行这种检测的地点显示在加州大学默塞德分校和全球水病原体项目的仪表盘上。我的工作的一个有价值的扩展是创建一个单一的全球数据集,该数据集结合了地图上显示的所有废水检测点,并通过病例、住院、ICU 和死亡率来增强该数据。换句话说,为整个世界创建上述相同的数据集。

数据注释

起初,有几个数据模型项目可能会令人困惑,因此在查看 NWSS 数据集时请记住以下几点:

  • 在原始文件中, sample_id 字段有时会在多行中重复出现。当同一个水样被检测一个以上的基因目标时,例如 N1 和 N2,就会出现这种情况。
  • 在分析文件中, sample_id 字段通常为空。当该日期在该位置没有水样时,就会出现这种情况,因此数据行用于保存当天的新冠肺炎病例统计数据。我的增强代码删除了这些空白的 sample_id 行,因为我使用样本的日期将案例结果信息直接添加到样本行中。

信用

感谢 Amy Kirby 和疾控中心 NWSS 数据所有人的有益讨论和对详细数据集的访问,感谢 Colleen Naughton 和 Claire Duvallet 的鼓励和对其他基于水的流行病学相关研究的指导,感谢 Mimi Alkattan 的宝贵评论。

了解更多信息

  • biobot.io/data/(生物机器人仪表盘)biobot.io/blog/(博客)
  • twitter.com/COVIDPoops19(推特上关于通过加州大学默塞德分校和科琳·诺顿的废水追踪新冠肺炎的消息)

周六晚上使用马尔可夫链建模,使用 Python

原文:https://towardsdatascience.com/saturday-night-modeling-using-markov-chains-with-python-a29188330a1e

乔恩·泰森在 Unsplash 上的照片

以下是我如何使用马尔可夫链和 Python,以一种现实的方式使用马尔可夫链为一个普通的周六晚上建模

6 个月前,当我来到美国开始我的研究工作时,我学到了一个新的英语术语:

“跳吧”

我认为更具欧洲色彩的说法是“酒吧爬行”,但这个概念基本上是指在相距较近的不同酒吧(或酒吧)兜一圈,喝一杯,这样就不需要开车了,或者你可以用几美元去“优步”。

物理学学士学位期间,我学习了所谓的**马尔可夫链。**马尔可夫链是做出以下(非常简单)假设的模型:

“从一种状态到另一种状态的概率只取决于你现在所处的状态,而不取决于以前的历史”

比如说今天是晴天今天是晴天这一事实是你唯一需要知道的事情,以获得明天将是晴天的概率(你不在乎昨天是否是晴天)。

这个概念是疯狂的简单,但后果可能真的很有趣。
特别是当你考虑一系列随机变量时,它变得非常强大。通过这种方式,你实际上可以创建一个过程,并基于你的假设看到整个演变过程。技术上,我们将讨论离散时间马氏链。这意味着你看到了一步一步的进化,每一步都是一个“时间滴答”。

让我们在 Bar Hopping 场景中使用这些假设,并使用 Markov 链来玩一玩。:)

注:在这篇 文章 中,我展示了一些最著名的马尔可夫链及其对应的代码。如果你觉得这个想法很有意思,并且想知道更多,就来看看吧!

0.图书馆

我们将把 Python 与一些不同的基础数据科学库一起使用:numpy**、matplotlib、seaborn** 和熊猫:

1.一小节时间独立模型

先从有史以来最简单的情况说起:你只有一个酒吧,只有想出去才能去。

我们将创建三个状态:

  • 首页
  • 酒吧
  • 回国

从州你只能出门。所以第一个假设是你必须出去才能去酒吧。很合理。

然后,从开始,对于每一个时间步,你都可以留在酒吧或者回家。假设在每个时间点,你有 50%的概率回家,50%的概率留下。

当你回到家时,你唯一能做的事就是呆在家里。意味着你不会再出去了。同样,非常合理。

我们将考虑 300 步,假设每一步是一分钟,这样我们将有一个 5 小时长的夜晚。

作者图片

所有这些信息被分组在一个所谓的 转移矩阵 中:

现在,这个函数计算给定的状态下的状态:

并且下面的函数描述了直到时间 n(分钟 n)的整个过程:

好了,现在我们来玩一玩吧。

我们考虑 1000 次实现同样的体验(假设 1000 个人出门),n 步后看看我们在哪里(是否在家),这里 n 从 2 到 5。让我们先定义完成这项工作的函数:

然后让我们画出结果:

因此,两步之后,大约 500 人在家,500 人仍在酒吧,而五步之后,超过 850 人在家,只有 150 人(大约)仍在酒吧。但别忘了,每一步都是一分钟。

那么它是一个好的模型吗?大概不会。
让我们用新的把事情变得更复杂:

2.一杆时间相关模型

真正让你回到家的东西只有一个:时间。在酒吧呆了 150 分钟后,你可能想回家,而如果你只在酒吧呆了 5 分钟,你可能想留下来。在前一个模型中,没有时间依赖性,这是不好的。

假设回家的概率如下:

我用乳胶制作的图像

这意味着当 k=1 时:

  • 在时间 0 回家的概率为 0%
  • 在时间t = 300(5 小时后)回家的概率为 100%
  • 在时间t = 150**(2 个半小时后)回家的概率的 50%**

现在:

鉴于你的个人经历,你同意这个比率吗?

我不知道:这就是为什么 k 是一个参数。我马上会告诉你我的意思。

首先,让我们实现这个过程:

让我们将 k=6 定义为默认参数,并绘制结果:

所以,当 k=6 时,1000 人中有 720 人还在酒吧里。

你可能有自己的酒吧,找到不同的数字,并好奇的顺序,最匹配的数字,你已经找到了。为了验证您应该使用哪个顺序(k ),您可以像这样做:

所以,例如,如果你相信 85%的人会在酒吧,你可以用 k=7。

这种模式更好,但仍然局限于单个酒吧。我们能做得更好吗?

3.两杆距离独立模型

在这种情况下,我们将有 4 种状态:

  • 首页
  • 杆 1
  • 杆 2
  • 回老家

它是这样工作的:

  • 从国家回家只能出门。所以第一个假设是你必须出去才能去酒吧。很合理。等概率(50%)可以进 1 号杠和 2 号杠。
  • 从**酒吧 1,**你可以留在酒吧 1,去酒吧 2,或者回家。假设在每个时间点,你有 70%的概率呆在酒吧 1,20%的概率去酒吧 2,10%的概率回家
  • 栏 2 你可以以 70%的概率留在栏 2 或者以 30%的概率回家
  • 还是那句话,当你回到 T21 时,你唯一能做的就是呆在家里。意味着你不会再出去了。同样,非常合理。

它是这样工作的:

作者图片

让我们来实现这个想法:

好吧,但是我们到底去了多少次 1 号酒吧?我们去了多少次酒吧 2?我们两个都去了几次?

让我们用下面的代码检查一下:

因此,51.5%的时间我们只去酒吧 2,17.0%的时间我们只去酒吧 1,31.5%的时间我们去酒吧 1 和酒吧 2。

另外,你可以玩概率数字,得到更接近你脑海中真实世界的例子:)

好的,但是我们需要多少时间回家?让我们画出分布图:

嗯…不是很理想,不是吗?我们看到的最佳数字是时间= 50…这是相当低的。

如果我们玩概率游戏,我们可以看到我们有更合理的数字:

附注:我刚刚更改了第 1 栏和第 2 栏的转换矩阵

更好的是,即使我们仍然可以整合先前模型的时间相关假设,并可能获得更好的结果(对于低时间值,曲线仍然太高):

4.两杆距离相关模型

好的,但是你有 50%的概率去酒吧 1 或 2,这是不合理的,对吗?如果一家酒吧离你很近,而另一家却很远。如果一个酒吧坐满了女孩/男孩(而你是单身),而另一个是空的。如果一家酒吧真的很贵,另一家很便宜。

我们可以定义一个所谓的“距离”,并改变从家到酒吧 1 或从家到酒吧 2 的概率。

这是怎么回事:

让我们做同样的分析:我们实际上去了多少次酒吧 1?我们去了多少次酒吧 2?我们两个都去了几次?

在这种情况下,我决定条形图 1 为 dist_1=1,而条形图 2 为 dist_2=5。这就是为什么你会注意到“仅第 1 栏”比“仅第 2 栏”更有可能发生。

4.结论

马尔可夫链的伟大之处在于它们是可以疯狂定制的。
你有很多旋钮可以用来获得与你的统计数据相符的结果,并找到建立数据集模型的最佳方式。在这个非常有趣的小例子中,我从一个非常简单的模型(1 个小节,时间无关,空间无关)开始到一个更复杂的模型(2 个小节,空间相关)。当然你可以从中得到乐趣,让这个模型更健壮,创建更复杂的代码。

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,我在那里发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

如何使用 Matplotlib 将绘图保存到图像文件

原文:https://towardsdatascience.com/save-plots-matplotlib-1a16b3432d8a

了解如何将 matplotlib 图形和绘图保存到图像文件

费尔南多·拉文在 Unsplash 上拍摄的照片

介绍

有时,您可能需要将在磁盘上创建的绘图和图形存储为图像文件。在某些情况下,您可能还希望在每次运行程序时,不要在屏幕上显示图形或数字。

在今天的文章中,我们将展示如何将matplotlib图形和情节保存到磁盘上的图像文件中。此外,我们将解释如何禁用交互模式,以便在执行代码时不显示图形。

首先,让我们用 matplotlib 创建一个虚拟图形,作为演示一些概念的例子。

import matplotlib.pyplot as pltplt.plot([5, 4, 3], [100, 200, 300] 
)
plt.title('Some Title')
plt.xlabel('Year')
plt.ylabel('Some measurements')
plt.show()

创建的图形如下所示:

测试图—来源:作者

将磁盘上的绘图保存为图像文件

现在如果你想通过编程将matplotlib图片保存为图片文件,那么你所需要的就是[matplotlib.pyplot.savefig()](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html)函数。只需传递所需的文件名(甚至位置),该图就会存储在您的磁盘上。

import matplotlib.pyplot as pltplt.plot([5, 4, 3], [100, 200, 300] 
)
plt.title('Some Title')
plt.xlabel('Year')
plt.ylabel('Some measurements')**plt.savefig('my_plot.png')**

或者,当调用plt.show()时,您仍然可以通过点击显示在交互窗口底部的保存图标来保存图形

**plt.show()**

互动窗口—来源:作者

禁用交互模式

在某些情况下,图形仍然显示在交互模式中,即使在我们将图形保存在磁盘上后没有调用plt.show()。当你以一种迭代的方式生成多个图时,这就更令人讨厌了,因为当程序结束时,你会得到大量的开放图形。

您可以通过简单地调用确保图形窗口关闭的[matplotlib.pyplot.close()](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.close.html)方法来防止这种情况发生。

import matplotlib.pyplot as pltplt.plot([5, 4, 3], [100, 200, 300] 
)
plt.title('Some Title')
plt.xlabel('Year')
plt.ylabel('Some measurements')plt.savefig('my_plot.png')**plt.close()**

最后的想法

在今天的文章中,我们讨论了将matplotlib图形和绘图保存为图像文件,或者通过编程,或者使用我们调用plt.show()时弹出的交互窗口中提供的工具。

此外,我们展示了如何通过在本地存储文件后直接关闭图形窗口来防止图形显示在屏幕上。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

节省使用 UDF 编写 SQL 的时间

原文:https://towardsdatascience.com/save-time-writing-sql-with-udfs-24b002bf0192

SQL UDFs 介绍及示例

编写 SQL 是许多数据科学家和数据分析师角色的重要组成部分,但这通常是花费时间最不愉快的方式。获取运行分析所需的数据可能会变得繁琐而耗时。用户定义函数(UDF)是解决这个问题的好方法,它是查询编写过程的捷径。在本文中,我们将介绍什么是 UDF,为什么您可能会使用它们,它们在哪里被支持,以及一些基本的例子。

约翰·施诺布里奇在 Unsplash 上的照片

什么是 UDF?

UDF 是一个用户定义的函数,它在基本层面上非常类似于一个典型的 SQL 函数,比如 RIGHT(),但是它不是由一些标准定义的,任何人都可以定义它们。更专业地说,UDF 是一个函数,它接受一组类型化的参数,应用一些逻辑,然后返回一个类型化的值。下面是一个例子。

CREATE FUNCTION Sigmoid(@exponent FLOAT(10))
RETURNS FLOAT(10)
ASBEGIN1.0 / (1.0 + EXP(-@exponent))RETURN DataEND

UDF 在 SQL 世界中广泛存在,它能够创建存在于数据库管理系统(如 SQL Server、Postgres、BigQuery 和 Presto)中的 UDF。注意一些数据库管理员会禁用这些,所以最好检查一下。

UDF 的利与弊

使用 UDF 可能是有益的,但是它们也有缺点。我个人认为,拥有一个好的 UDF 集合,特别是在小的产品团队中,是非常有用的,但是我将分享其利弊,让您来决定。

优点:

  • 允许您用简单的一行程序替换部分复杂或重复的 SQL,使代码更具可读性。例如,您可能有一个复杂的 CASE 语句,它占用了查询的许多行。有了 UDF,这可以减少到一行。
  • 鼓励集中定义流程。想要对事物进行分类是很常见的,能够在一个人编写的查询中以及在多人之间保持一致是很有价值的。
  • 由于上述原因,它允许你更快地编码。能够更快地准备好数据总是会让数据科学家感到高兴。

缺点:

  • 虽然它可以使代码更具可读性,但是太多不清楚的 UDF 实际上会降低代码的可读性。如果函数被命名为类似于“func1”的名称,那么它们实际上在做什么就很不清楚了,这就需要读者查找函数定义,这通常比在代码中通读要花费更长的时间。
  • 你需要记录你在记忆中创建的所有 UDFs】,这在你建立了一个像样的剧目之后会变得很困难。最坏的情况是,你开始创建更多的 UDF 做类似的事情,创建不必要的代码。为了避免这导致问题,建议保留一个包含您创建的 UDF 的字典,并确保与任何合作者共享它。您还可以确保尽可能创建更多的通用函数,以避免重复工作。
  • UDF 可能运行效率低下,尤其是在大块数据上。对于各种 SQL 函数,它们必须逐行计算,导致运行时间很长。这可以通过一些技术得到缓解,比如针对 SQL Server 的技术。

如你所见,使用 UDF 有好的一面,也有不好的一面,当应用 UDF 时,确保使用常识,可以将这些缺点最小化。

UDF 的例子

下面是一些有用的 UDF(小写输入参数)的例子。这些可以大致分为替代重复动作的和编码业务逻辑的。

重复动作:

  • 舍入器:将一个数字舍入到最接近的指定因子,并带有下限和上限。
LEAST(GREATEST(ROUND(@number / @factor) * @factor, @lower), @upper)
  • Sigmoid:Sigmoid 函数的 SQL 定义。
1.0 / (1.0 + EXP(-@exponent))
  • 采样:给定一些值的数组,采样给定的数量。
SLICE(SHUFFLE(@input), 1, @value)
  • X 中的 1:在 X 语句中将一个数字从十进制转换为 1,例如 0.01 或 1%是 100 分之一。
‘1 in ‘ || CAST(CAST(POWER(10,CEIL(-LOG10(@percent))) AS INT) AS VARCHAR)

业务逻辑:

  • 年龄分类:根据用户的年龄对他们进行分类。
CASE WHEN @age < 12 THEN ‘child’ WHEN @age < 20 THEN ‘teenager’ WHEN @age < 50 ‘adult’ ELSE ‘elderly’ END
  • 购买时段:将用户购买的数量分组到特定的时段中(用于绘图)。
CASE WHEN @purchases = 0 THEN ‘0’ WHEN @purchases = 1 THEN ‘1’ WHEN @purchases < 5 THEN ‘2–4’ WHEN @purchases ≥ 5 THEN ‘5+’
  • 邮件域:从邮件字符串中提取邮件域。
SPLIT_PART(@email, ‘@’, 2)

这些只是你如何应用 UDF 的一些例子;你可以用更多的方式来使用它们。唯一真正的限制是创造力!

结论

正如我们所看到的,UDF 有广泛的应用,包括优化重复代码和集中业务逻辑,这有助于您更有效地编写 SQL。虽然有缺点,但是可以用一点常识来适当地减轻它们,以确保您获得使用 UDF 的所有好处。鉴于它们在各种 SQL 系统中的广泛可用性,没有理由不给它们一个机会!

如何用 Python 在磁盘上保存训练好的模型

原文:https://towardsdatascience.com/save-trained-models-python-22a11376d975

用 scikit 探索模型持久性——在 Python 中学习

图为费尔南多·拉文在 Unsplash

介绍

当开发机器学习模型时,我们使用所谓的训练集中包含的数据点来训练它们。通常,我们需要在磁盘上保存一个训练好的模型,以便以后将它加载回内存中。这可能需要发生,因为我们想要在不同的数据集上评估模型的性能,或者可能因为我们想要进行一些小的修改。

在今天的简短教程中,我们将展示如何在磁盘上存储经过训练的scikit-learn模型。此外,我们还将讨论如何将预先训练好的模型加载回内存中,并在新的实例上运行它(例如,测试或验证集中可能包含的数据点)。

首先,让我们训练一个示例模型,我们将在本教程中引用它来演示一些概念。我们将使用鸢尾数据集(它也包含在scikit-learndatasets模块中,所以如果你想按照本教程学习,你不必依赖外部资源)来训练 K-Neighbors 分类器,以便根据花瓣和萼片的长度和宽度来预测数据集( SetosaVersicolourVirginica )中包含的鸢尾的类型。

现在,让我们开始加载我们的 Iris 数据集,并创建一个训练和测试集(如果您想了解更多关于如何将数据集分为训练、测试和验证测试的信息,您可以阅读我的一篇旧文章):

import numpy as np
from sklearn import datasets # Load the Iris Dataset
iris_X, iris_y = datasets.load_iris(return_X_y=True) # Split the data into training and testing sets
# Note that we use a fixed seed so that results
# are reproduciblenp.random.seed(0)
indices = np.random.permutation(len(iris_X))iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test = iris_X[indices[-10:]]
iris_y_test = iris_y[indices[-10:]]

然后,我们使用在上一步中创建的一组训练实例来训练 K-Neighbors 分类器:

from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)

保存已训练的模型

酸洗是 Python 中使用的一个过程,目的是将对象序列化(或反序列化)成字节流。机器学习模型也是对象,因此我们可以利用酸洗方法将它们存储在本地磁盘上。

在 Python 中,你可以使用[pickle](https://docs.python.org/3/library/pickle.html)[joblib](https://joblib.readthedocs.io/en/latest/)库来挑选对象。请注意,**joblib** 在对携带大型数组的对象进行序列化(解序列化)时效率更高(这在使用scikit-learn模型/估算器时很常见)。注意,与pickle相反,joblib也可以 pickle 磁盘上的对象(而不是字符串对象)。

下面我们将演示如何持久化模型以供将来使用,而不必使用两个库进行重新训练。

使用 **pickle**

import pickle**with open('my_trained_model.pkl', 'wb') as f:pickle.dump(knn, f)**

使用**joblib**

import joblib**joblib.dump(knn, 'my_trained_model.pkl', compress=9)**

注意compress参数可以取 0 到 9 之间的整数值。较高的值意味着更多的压缩,但也意味着较慢的读写时间。

从磁盘加载预训练模型

现在,为了从磁盘加载回预先训练好的模型,你需要解开字节流。同样,我们将展示如何使用picklejoblib库来做到这一点。

使用 **pickle**

import pickle**with open('my_trained_model.pkl', 'rb') as f:knn = pickle.load(f)**

使用 **joblib**

import joblib**knn = load('****my_trained_model.pkl****')**

在新数据点上运行加载的模型

现在,一旦我们加载回(即解除)预训练的 scikit-learn 模型,我们就可以在本教程开始时准备的测试集上运行它。

下面我们演示一个端到端的例子,包含今天教程中用到的全部代码

import joblib
import numpy as np
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier # Load the Iris Dataset
iris_X, iris_y = datasets.load_iris(return_X_y=True)# Split the data into training and testing sets
# Note that we use a fixed seed so that results
# are reproduciblenp.random.seed(0)
indices = np.random.permutation(len(iris_X))iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test = iris_X[indices[-10:]]
iris_y_test = iris_y[indices[-10:]] # Fit the classifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train) # Persist the trained model on the local disk
joblib.dump(knn, 'my_trained_model.pkl', compress=9)# Load the trained model from the disk
knn = load('my_trained_model.pkl')# Make predictions on the loaded pre-trained model
knn.predict(iris_X_test)

最后的想法

在今天的文章中,我们讨论了保存经过训练的机器学习模型的重要性,以便它们可以在以后使用。我们使用一个示例scikit-learn模型展示了如何做到这一点,我们最初将它存储在本地磁盘上,然后将其加载回内存,以便在新的、不可见的数据集上运行它,这些数据集包括在我们一开始准备的示例测试集中。

请注意,在某些情况下(主要与文本分类任务相关),您可能还希望持久化 vectoriser。您可以通过使用包含矢量器和训练模型的元组来实现,如下所示:

import pickle**# Pickle the vectorizer and the classifier**
with open('trained_model_with_vecotizer.pkl', 'wb') as f:pickle.dump((vectorizer, clf), f)**# Unpickle the vectorizer and the classifier**
with open('trained_model_with_vecotizer.pkl', 'rb') as f:vectorizer, clf = pickle.load(f)**# Vectorize the testing instances and perform predictions**
X_test = vectorizer.transform(X_test)
predictions = clf.predict(X_test)

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

用 tf.summary.image 在 Tensorboard 中保存多个图像

原文:https://towardsdatascience.com/saving-multiple-images-in-tensorboard-with-tf-summary-image-15df9c11d6c9

如何在 Tensorboard 内存储多个图像,以查看您的神经网络的演变。GAN 模型的案例应用

桑尼·萨希尔在 Unsplash 上的照片。由作者编辑。

R 最近,我一直在开发一个图像生成模型,并且需要在 Tensorboard 中保存一些图像,以查看该模型在每个时代是如何发展的。

经过长时间的搜索和几个文档文件,我终于得出了您可以在图像中看到的结果:

截图取自 Tensorboard 项目。上面的图像是给予神经网络的输入,中间的图像是网络的输出(翻译的图像),而下面的是基础事实(模型应该输出的内容)。图像顶部的进度条表示图像生成的时间。作者图片

在上面的例子中,这个模型使用 Pix2Pix 模型[ 链接到 paper ],试图将给定的图像“翻译”成莫奈的艺术绘画。您可以在 Kaggle 存储库[ 链接 ]中找到您正在查看的数据集

注 1 。由于我只是想显示仪表板,模型被训练的时期数量非常少,所以结果看起来很差。

为什么使用 Tensorboard

Tensorboard 是一个可视化工具,它提供了分析神经网络性能的框架。它可以使用 TensorflowPytorch 库进行集成,在您机器的本地端口上生成一个接口,用于投影损失函数的演变等指标或跟踪定制指标,如本例中生成的图像。

这些可视化对于神经网络模型的开发阶段来说是必不可少的**、允许我们检测关键问题,例如过拟合/欠拟合、测量和比较多个模型,或者提供关于哪些改变可以提高整体性能的见解**(超参数调整)**
例如,分析每个时期上生成的图像可以帮助我们检测生成器中的弱点,例如粒状模式的生成或模式崩溃导致的停滞,但这些是另一篇文章的主题**

想了解更多关于 Tensorboard 的信息,可以查看文档这里。

密码

我不想浪费你的时间,所以下面是保存图片的代码:

喀拉斯。回调子类。作者代码

接下来,使用自定义回调启动培训:

使用自定义回调训练 Pix2Pix 模型。作者代码

代码解释

对于那些不复制和粘贴代码的人,让我解释一下当你运行上面的代码时会发生什么。

第一步我们需要创建一个keras-callbacks子类,在那里我们可以定义我们的自定义回调。
回调是在训练过程中以指定的频率执行的功能参见文档。要告诉 Tensorflow 在训练时使用回调,我们只需以列表对象的形式将它们作为参数传递(参见第 5 步)

截图取自代码。作者图片

在我们的例子中,回调类接收来自训练集和验证集的一批图像、模型的生成器(这样我们就可以生成图像)和存储图像的路径(logdir)作为参数,这些图像将在 Tensorboard 中显示。

我们还定义了实例变量self.writer,它为给定的日志目录创建一个摘要文件编写器(我们将在这里存储信息,以便稍后在 Tensorboard 上显示)

【T22 日我们定义了 de 类方法on_epoch_end,顾名思义,它将在每个历元之后执行。

注 2 。接收此方法的参数以 Tensorflow 为前缀,所以不要试图更改它们。

on_epoch_end方法中,我们还必须定义一个函数来生成图像(这样代码看起来更干净、更有条理)。

截图取自代码。作者图片

函数generate_imgs获取一组图像(来自 Tensorflow.data 的 TakeDataset 元素)和生成器( g ),并返回一个 3 显示图像的列表,该列表垂直连接输入图像x、由模型out翻译的图像和地面实况y。如果我们不连接这些图像,它们将显示在 Tensorboard 的不同卡片上。

注 3 。在连接之前,我们必须使用函数tf.squeeze()移除批量维度,以防止出现异常。

第三接下来,我们使用tf.summary.image()保存图像

截图取自代码。作者图片

第一行self.writer.as_default()告诉 Tensorflow 将接下来的操作存储在同一个图中(即自写器图),这样回调在每个时期后生成的所有图像都将被记录在同一个文件中【check doc , link ]
接下来,tf.name_scope()函数将为每个图像的名称添加前缀“ train/ 或“ val/ ”, 因此,训练和验证生成的图像保存在工作目录的不同文件夹中(在 Tensorboard 中,这反映为不同的部分,但实际上两个文件的名称相同,属于同一个摘要文件)

注 4 。在这种情况下,我再次将图像的名称定义为范围,因此它们将被命名为“ train/train/ 或“ val/val ”,但是对于进一步的项目,我建议更改它。

第四个初始化类。回到我们创建模型的 train.py 文件,我们通过调用它来初始化这个类(第 9 行)。对于这个项目,我决定从训练集中取 4 张图片,从验证中取另外 4 张图片,每张图片来自不同的批次。接下来,我指定生成器(pix2pix 是一个 keras.model 所以我可以调用生成器作为方法)和保存摘要的 logdir。

截图取自代码。作者图片

注 5 。有人可能会认为,如果我们将生成器作为参数传递,那么在训练期间,它们的权重不会更新,结果也不会正确。然而,Tensorflow 设法做到了这一点,因为我们正在传递一个指向所创建的类 pix2pix 的类实例pix2pix.g,即当 pix2pix 更新其权重时,它将应用于其所有实例。
我亲自检查了这一点(如果你不相信我,你也可以这样做),在自定义回调中添加了一行:

print(self.g.get_weights()[0][0][0][0])

结果是每个时期的第一个神经元权重的打印,因此您可以注意到修改。

第五次使用自定义回调训练模型

截图取自代码。作者图片

结论

能够在训练阶段可视化您的模型的演变对于良好的开发是至关重要的,并且提供关于采取什么方向来提高模型的准确性和性能的关键见解。

然而,考虑评估我们的定制指标的成本也很重要,因为对于训练模型来说,时间是一个重要的事实。在这个项目示例中,根据您的硬件和映像大小,打开映像包并测试生成器可能需要额外的几分钟时间,这大大降低了培训的速度。

解决这个问题的一个好办法是建立一个频率变量,它将与自定义回调类中的纪元编号进行比较,这样如果epoch % frequency == 0,我们就可以测试生成器并保存结果。

我希望这篇文章是有用和有帮助的,更多关于人工智能和数据科学的文章,你可以查看我的其他文章。

通过领先得分挽救斯克兰顿分行

原文:https://towardsdatascience.com/saving-the-scranton-branch-with-lead-scoring-8599ed4a874f

实践教程

挽救斯克兰顿分行领先得分

逻辑回归模型如何优化 Dunder Mifflin 销售团队

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

第一集:搭建舞台

“商业是一个狗狗的世界。而我是鲨鱼,吃狗狗的。”

迈克尔·斯科特

在宾夕法尼亚州斯克兰顿的一家中型纸张供应公司的墙上,似乎散发着商业和生活的教训。处理办公室恋情、引导合并、思考 Creed 每天到底在做什么只是 Dunder Mifflin 员工的部分职责。谈到业务运营,地区总裁迈克尔·斯科特,一位经验丰富的销售主管,当然知道营销和销售之间的重要关系,因为他实际上是世界上最好的老板。然而,对于 Dunder Mifflin 销售团队的所有镜头时间和情节主线,很难提到一个营销员工,更不用说整个团队了。就连最详细的办公室粉丝页面也对这个话题保持沉默。

面对竞争日益激烈的 one click 电子商务解决方案和提供大幅折扣的大盒子零售商,Dunder Mifflin 必须找到一种创造性的方法来推动增长并保持其斯克兰顿分公司的运营。Chilis 上的即兴客户会议和实际销售培训不再管用了。相反,迈克尔和销售团队需要答案,他们现在就需要。如果有一个营销团队可以构建的数据工具来帮助他们就好了…

第 2 集:销售线索评分概述

销售线索是最终可能成为客户的个人或企业。线索可以通过各种有针对性的营销活动获得,并作为一个运行良好的销售引擎的众所周知的燃料。邓德米夫林也不例外;事实上,第六季第一集强调了新线索对销售团队的重要性,同时也展示了 Erin 和 Andy 的浪漫爱情。将销售线索转化为客户说起来容易做起来难。这是销售人员真正技能的闪光之处。但并不是所有的线索都必须一视同仁。事实上,任何寻求推动真正业务影响的营销人员都应该为他或她的销售同事提供工具和资源,以筛选有时很长的潜在客户名单,并帮助提高经过严格审查的潜在客户到客户的转化率。

如果我们能利用数据帮助 Jim、Dwight、Phyllis、Andy 和 Dunder Mifflin 销售团队的其他成员更有效地拓展业务,会怎么样?甚至在拿起电话向潜在客户推销开创性的纸制品之前,他们就可以知道电话另一端的人成为客户的可能性。这正是领先得分所做的;这是一个评估工具,它试图根据潜在的潜在价值对潜在客户进行排名和“评分”。

图:线索评分(作者图片)

诸如职位、公司位置、网站访问量等因素都可以组合和加权,以帮助确定线索的适当分数。准确的销售线索评分模型通过识别和排列最有可能转化的销售线索来提高销售效率,同时还可以帮助团队成员降低不转化的销售线索的优先级。这样的工具将允许斯克兰顿分公司削减成本,完成更多交易,并留出时间进行更重要的办公室恶作剧或甜菜农场维护。

第 3 集:查看数据

在本练习中,我们将模拟一个总共有 800 条线索的模拟数据集,其中 200 条是 Dunder Mifflin 的当前客户。虽然使用现实生活中的数据集总是更好,但我侵入德怀特的 Salesforce.com 账户的努力没有成功,所以我选择创建一个假数据集(有很多工具可以做这样的练习),原因有两个。首先,我遇到的每个教程或课程似乎都在持续使用相同的旧的“电信客户流失”数据集。其次,也是更重要的一点,下面概述的通过逻辑回归构建销售线索评分模型的过程和方法是本文的主要关注点和范围。我的希望是,理解潜在客户的特征与潜在客户成为客户的概率之间的关系,可以应用于逻辑回归可以开启商业洞察力的任何数据集……或者至少在明年的 Dundies 中为你赢得一些当之无愧的支持。

我们的数据集将包含第一方firmographic(company size,State)和行为(WebsiteVisits,EmailOpens)变量的组合,这些变量可以通过网站表单合理地收集,或者使用现代 B2B MarTech 堆栈中常见的数据丰富工具附加到记录中。感兴趣的因变量是二进制客户列,用“是”或“否”标记,以指示销售线索是否最终成为客户。我们将从 Python——一种常用于数据分析的编程语言——导入我们工作所必需的特定包,然后使用 read_csv 方法将数据读入 Pandas 数据框。这样做将允许我们更好地理解我们正在处理的数据,特别是如果我们使用 head 方法来预览我们数据的前五行。

图:预览前五个观察或我们的销售线索数据集的“头部”(作者图片)

第 4 集:探索性数据分析(EDA)

Python、R 甚至 Excel 等工具的一个关键优势在于它们能够帮助分析师快速更好地理解他们所处理的数据。通过适当的数据分析,我们可以开始识别数据中的趋势或异常值,这将有助于为构建预测模型的后续步骤提供信息。

我们可以运行 describe 方法,该方法将为每个数值变量创建汇总统计数据,并帮助我们了解每个变量的关键统计特征,包括最小值、平均值、不同百分位值和最大值。我们可以快速找到感兴趣的某些变量的平均值和范围。例如,电子邮件的平均点击量大约是电子邮件打开次数的一半。

图:的输出。描述数据的方法(图片由作者提供)

但是要回答我们的主要问题“在所有的潜在客户中,那些成为客户的和那些没有成为客户的有什么区别”,我们必须使用熊猫 groupby 方法,它允许我们聚集或分割我们的数据以更有效地理解它。

图:根据客户的因变量对数字变量进行“分组”(图片由作者提供)

在这里,我们开始开发关键的见解,可能会通知我们的预测模型。乍一看,与未转化的潜在客户相比,最终成为客户的潜在客户似乎具有更高的电子邮件点击/打开和网站访问量,但他们来自更小的公司。但真的是这样吗?让我们更深入地研究其中一个变量,EmailOpens。箱线图分析是一个很好的工具,有助于为上面的输出添加视觉背景。

图:一个箱线图,显示了基于因变量的电子邮件打开的差异(图片由作者提供)

groupby 方法对于评估分类变量也很有价值。LeadSource 就是这样一个变量,它指示该销售线索来自哪个特定的营销活动。这不仅对于我们模型的预测性,而且对于帮助 Dunder Mifflin 营销团队证明他们将来应该对哪种类型的活动分配更多的时间和预算,都是至关重要的信息。根据是否是客户的因变量分组的活动条形图最初表明,Adwords(谷歌开发的搜索引擎广告平台,也称为谷歌广告)和网上研讨会活动似乎在将销售线索转化为客户方面更有效;然而,这项分析遗漏了活动成本的一个关键组成部分,因此我们无法得出任何最终的、确定的结论。

图:一个条形图,比较了各种营销活动在产生潜在客户并将其转化为客户方面的情况(图片由作者提供)

第 5 集:准备和清理数据

数据准备就像办公室里的消防演习或急救培训:你可能不喜欢它,但当时间到了,你会意识到它的价值。因为我们正在处理一个模拟数据集,所以我们不必担心离群值、不正确或缺失的数据;尽管如此,我们还是可以采取很多措施,让自己在进入模型构建阶段时处于一个良好的位置。相对于更复杂的模型,更简单的模型几乎总是更受青睐,因此我们可以丢弃任何不相关的列或变量,我们知道这些列或变量没有预测能力,比如电话号码和 ID。(虽然假设电话号码的区号可用于通知销售线索的位置,但我们假设在本练习中,我们将 State 列包括在内)。

“越简单越好”的方法不仅适用于特征选择,也适用于特征工程。假设电子邮件的打开和潜在客户的点击之间有密切的关系,并且这两个变量对潜在客户的最终转化有类似的影响,我们可以将这两个变量相加到 EmailScore 列中,生成一个单一的指数,表明潜在客户与他们从 Dunder Mifflin 那里获得的销售或营销电子邮件的互动程度。这将允许我们用新的 EmailScore 列替换这两个变量,我们将使用下面的代码来完成。此外,这种类型的特征工程有助于我们在构建和评估模型时消除多重共线性的风险。

图:初始数据清理后数据集的“头部”

正如我们从 EDA 部分观察到的,并非我们数据集中的所有变量都是数值型的。例如,LeadSource 是一个名义上的(意味着值之间不存在固有的顺序)分类变量,表示销售线索来自哪个活动、Adwords、Print、Tradeshow 或 Webinar。这对于我们的销售线索评分工作来说是潜在的关键信息,因此为了确保我们能够将它包含在我们的模型中,我们将利用一种叫做一键编码的技术。这种方法创建了一个二进制“虚拟”变量数组,每个变量对应一个可能的导联源。例如,对于第 3 行中看到的销售线索(源自“Print”),我们将在新的“Print”虚拟变量中有一个值“1”,在其他三个新编码的分类虚拟变量中有一个值“0”。这些新的虚拟列将与我们的原始数据集合并,现在可以在我们的预测模型中使用,以潜在地评估 LeadSource 和转化为客户的 lead 之间是否存在任何预测关系。

图:为 LeadSource 创建虚拟变量后,数据集的结果“头”

我们还将对分类状态变量执行相同的步骤。最后,也可能是最重要的,我们需要将二进制的分类客户变量转换为数字变量,将值 1 替换为“是”,0 替换为“否”。这可以通过熊猫的替换方法来实现。现在,我们已经准备好使用适当的算法来构建销售线索评分模型了!

第 6 集:逻辑回归概述

虽然在建立预测模型方面存在许多方法,但我们将利用逻辑回归,一种广泛使用的分类算法。与线性回归类似,逻辑回归依赖于一个等式,其中使用权重或系数值组合和分析各种输入值(x)来预测输出值(y)。然而,使用逻辑回归,感兴趣的输出值不是连续的,而是一个离散变量。具体来说,使用二元逻辑回归,输出是二分的,这意味着只有两种结果(通常表示为 0 或 1)是可能的。

逻辑回归让我们能够对我们感兴趣的评估对象的概率(范围从 0 到 1)进行建模。本质上,概率 p 的结果是我们的数据点可以被分类为“1”而不是“0”的概率。下图是映射到分类客户变量的 EmailOpens 变量散点图,显示了通过我们的数据点拟合一条直线有多困难。相反,我们添加了一条永远不会完全达到 0(否)或 1(是)的 S 形曲线,以帮助解释逻辑回归如何更适合我们的数据。

图:强调逻辑回归本质的散点图(图片由作者提供)

举一个更具体的例子,对于住房数据,我们将使用线性回归来预测一所房子的市场价值为 500,000 美元;而逻辑回归将更适合于预测房屋被出售的 0.72%的可能性(范围从 0 到 1)。我们不会花太多时间去钻研逻辑回归的统计元素,但是可以查看这里、这里和这里中关于这个主题的一些很棒的资源。

在本练习中,理解算法是我们预测销售线索是否会成为客户的合适工具是非常好的。逻辑回归——有时也称为 logit 模型——相当容易实现和解释,这使得它被广泛采用。然而,逻辑回归并不总是能够处理包含大量分类变量的复杂数据集。在这种情况下,支持向量机、随机森林或神经网络等其他分类技术可能是更合适的工具。

第 7 集:构建模型

我们将训练一个二元逻辑回归模型,使我们能够根据公司规模和网站访问量等多种因素来估计线索成为 Dunder Mifflin 客户的概率。先从 Python 常用的机器学习库 Scikit-learn(俗称 sklearn)导入逻辑回归模型和必要的包或方法。我们还将从我们准备的销售线索数据框架中创建目标变量 y(客户)和输入变量 X(每隔一列)。

现在让我们把数据分成两组;用于训练模型的“训练”集,以及用于评估模型性能的“测试”集。这可以通过使用函数 train_test_split()来完成。这里,数据被分成两部分,该方法的 test_size 参数允许我们指定 80%的数据将用于模型训练,20%用于模型测试。训练集和测试集的大小会影响模型的性能,例如,模型在拥有更多训练数据时会学得更好。但是,存在这样的风险,即它们过度适应训练数据,并且不能很好地推广到新数据,因此为了正确评估模型的推广能力,您需要足够的测试数据。80/20 是一个很好的平衡。该方法返回四个变量:

  • 训练数据:X_train
  • 培训标签:y_train
  • 测试数据:X_test
  • 测试标签:y_test

我们将使我们的逻辑回归分类器适合训练数据和标签,因为它试图理解两者之间的关系。接下来,我们将让新创建的模型对它从未见过的测试数据进行预测。这个过程有助于确保我们模型的外部验证。我们将通过 0(非客户)或 1(客户)显示预测结果。二元分类器模型的默认或标准阈值是 0.5,因此,如果右边的“1”列中的值大于 0.5,则观察或潜在客户将被预测为成为客户;如果小于 0.5,则根据模型它不会成为客户,导致该变量为 0。

图:前五行测试数据的因变量的模型预测(图片由作者提供)

现在,当我们使用 sklearn 的 score 方法计算整个测试数据的模型精度时,我们得到的输出是 0.94。准确性是评估分类模型的度量之一,它被简单地定义为正确预测的数量除以预测的总数。

第 8 集:评估模型

虽然很高兴看到 94%的准确率,但这并没有描绘出一幅完整的画面。如上所述,我们总共 800 条线索的数据集包括 200 个客户和 600 个非客户;这是一个不平衡数据集的例子,其中因变量上的两个类的标签拥有显著不同的频率。

不平衡的数据集暴露了依赖准确性作为我们模型的唯一评估指标的主要局限性。例如,如果我们训练一个简单的模型来预测它作为非客户从我们的数据集中看到的每一个线索,它会有 0.75 的相当不错的准确性;然而,该模型将忽略并错误地预测所有 200 个客户为非客户,从而首先破坏了销售线索评分工作的目的。

图:上面 Python 代码的输出展示了我们数据集的不平衡类(图由作者提供)

由于不平衡的类使得“准确性”变得不那么有用,我们需要更细致的工具,比如混淆矩阵,来正确地评估我们的模型。混淆矩阵方法接受两个参数,测试集的实际标签(y_test)和你的预测标签(y_predict)。输出是一个 2x2 数组,通过显示正确和错误预测的频率来描述模型的性能,这些预测分为四个不同的组(真阳性、假阳性、真阴性和真阳性)。

图:每个象限描述的混淆矩阵(图片由作者提供)

图:我们模型的混淆矩阵的输出(图片由作者提供)

一些 Python 代码将有助于将这个数组转换成更直观的可视化形式。从这个矩阵中,我们可以更深入地挖掘模型的误差和性能。注意,混淆矩阵的格式和排列不是通用的,所以在解释时一定要注意格式。

图:我们模型的混淆矩阵的一个更容易解释的版本(图片由作者提供)

我们甚至可以获取测试数据集的一个子集,并将我们的模型对类值的预测值与真实值进行比较,以了解某些错误(由两个值之间的差异指示)可能发生的位置。

图:查看模型预测值和真实值之间差异的另一种方式(图片由作者提供)

让我们从混淆矩阵输出中定义和计算一些额外的评估指标,以更好地了解我们模型的性能和改进空间。

精度标识实际正确的肯定识别的比例(*精度= TP / TP + FP)。*不产生假阳性的模型精度为 1.0

召回 —也称为灵敏度—确定被正确识别的实际阳性的比例(*召回= TP / TP + FN)。*没有产生假阴性的模型的召回率为 1.0

F1 分数 —也称为平衡 F 分数或 F 测量值—可以解释为精确度和召回率的调和平均值。F1 分数的一个好处是它将精确度和召回率合并到一个单一的度量中;F1 的高分是一款性能良好车型的标志。

图:我们模型的各种评估指标的输出(图片由作者提供)

受试者工作特征(ROC)曲线是显示基于两个关键参数的分类模型的性能的图表;真阳性率或 TPR(计算方法与召回相同)和假阳性率或 FPR。该曲线绘制了在各种分类阈值下 TPR 与 FPR 的关系,提供了这两个指标之间权衡的直观感觉。

AUC——曲线下的面积——有助于表明模型性能。一般来说,模型越好,绘制的曲线越应该拉向图的左上角,使曲线下的区域最大化。AUC 分数 1 代表完美的分类器模型,而分数 0.5(虚线所示)代表随机或无价值的模型。与 ROC 曲线一起,AUC 允许您比较和评估各种分类器模型。

图:我们模型的 ROC 曲线的输出(蓝色)与随机猜测的比较(图片由作者提供)

第 9 集:调整模型和特性的重要性

在二进制分类中,阈值或者将观察值分类为 0 或 1 之间的界限通常设置为 0.5。虽然这个缺省值是合理的,但它可能并不总是作为在现实世界中导致分类器最佳性能的最佳截止值;因此,我们有机会应用业务环境来改进模型。识别和评估与我们原始模型的类型 I 和类型 II 错误相关联的成本,将有助于告知我们如何调整该分类阈值,以便在我们针对特定模型性能度量进行优化时最小化成本。

如前所述,召回率和精确度远比只看准确性更有价值;然而,这两个指标经常相互矛盾。提高精确度通常会降低召回率,反之亦然。要优化的指标取决于业务案例。Dunder Mifflin 将希望最大限度地减少“假阴性”(错误地预测销售线索不会成为客户的模型),以确保销售团队的好销售线索不会被遗漏,不会被降低优先级或忽略。我们认为错过一个潜在客户的成本远远高于试图寻找一个不合格客户的相关成本。因此,我们希望专注于提高销售线索评分模型的召回率。为此,我们将从第一个模型中的原始位置稍微降低分类阈值,这将把更多的销售线索分类为客户,从而增加误报和真报。我们将默认阈值设置为 0.4,而不是 0.5,这意味着任何预测概率大于 0.4 的销售线索都将被视为潜在客户。

现在,让我们通过用加权类训练我们的新模型来处理上面提到的讨厌的类不平衡问题。Class_weight 是一个与分类算法相关联的参数,我们可以利用它来确保每个类别的平衡组合。通过使用“平衡”参数,我们可以自动对类进行与它们的频率成反比的加权。让我们看看如何进行这些更改,以及它们如何影响我们新调整的模型的性能指标。

图:我们调优模型的评估指标和混淆矩阵(图片由作者提供)

代价高昂的假阴性从我们第一个模型中的 7 个减少到这里的 3 个,这是一个巨大的进步,并转化为召回的增加。此外,模型的调整对已经令人印象深刻的准确性和 F1 成绩的影响可以忽略不计!

为了更好地理解和解释我们的逻辑回归模型,我们将利用一种称为特征重要性的技术,这种技术有助于量化自变量或特征对因变量的二元结果预测的积极或消极影响。

对于逻辑回归,我们可以提取每个输入变量的系数属性,并提供一个简单但可解释的特征重要性分数。至少,我们希望特征重要性输出能够证实销售团队对线索特征的现有信念或直觉。理想情况下,功能重要性—当与业务背景和领域专业知识相结合时—还可以为销售团队成员提供关于销售线索的全新见解,以便他们关注或优先考虑下一步工作。

图:一个图表显示了我们的更新模型的特性重要性分解(图片由作者提供)

上述图表和列表展示了位于 Dunder Mifflin 附近的大西洋中部各州对线索被归类为最终客户的可能性产生的积极影响。有趣的是像印第安纳这样的州有很高的系数。这可能有助于为更具地域针对性的营销活动的启动提供信息,甚至支持在哪里增加新的分支机构或雇用更多销售代表的决策。至于线索的来源,Adwords 似乎是明显的赢家;另一方面,贸易展有一个负系数。这些发现与我们在本练习前面的 EDA 部分中注意到的一致,可以帮助 Dunder Mifflin 暂停该活动,并将部分营销预算转移到最有效的渠道。

第 10 集:交付和实现模型

因此,我们已经建立,测试,并完善了模型,现在我们准备把它付诸行动,为 Dunder Mifflin 的好乡亲!适当的沟通、变革管理和培训对于推动采用这种销售线索评分模式并产生真正的业务影响至关重要。我们将在我们选择的会议室召集销售团队,展示他们的努力和发现。但是记住,不要埋没了主角(双关);简单明了地描述该模型在实践中如何工作,并解释它将如何使他们和公司受益。透明度是关键,对于那些对模型的内部工作方式感兴趣的人,我们将在附录中或通过易于访问的幻灯片或知识文章介绍细节。

启动模型时,让销售团队解释他们的流程,以便它可以无缝地融入他们的工作流程。例如,营销团队可能会每周发送一封电子邮件,向他们的销售合作伙伴通报新资产或即将开展的活动。我们可以尝试在 Slack 上的电子邮件或类似的预定消息中包含模型对该周新线索的评分。或者销售代表们相信他们的 CRM,每天早上登录开始他们的一天;如果是这种情况,我们将在 CRM 中创建一个简单的报告或列表,如下所示,其中包括销售线索及其相关分数和信息。为了使事情变得更简单并推动采用,我们可以根据模型的概率得分对线索进行过滤或排序。

图:按新销售线索得分排序的销售团队新销售线索表(作者图片)

反过来,我们希望在营销和销售团队之间就这一新工具如何创造价值并支持他们的长期成功达成共识。我们将与销售领导合作,确定衡量他们部门的关键 KPI,如潜在客户转换率或渠道速度。在启动之前为这些指标建立一个基线,并在销售线索评分模型启动并运行时关注它们是如何随着时间的推移而变化的,这将是至关重要的。

随着邓德米夫林公司的发展,他们的客户也在发展;因此,销售线索得分计算将需要调整。我们将为销售团队成员提供对模型进行实时反馈的机会。也许 Jim 注意到,来自网络研讨会的销售线索最终并没有被证明是优质客户。从长远来看,来自销售和产品团队成员的这种类型的反馈将使我们能够完善并最终改进该模型。

第 11 集:未来研究、额外资源和最终想法

虽然我们在本教程中涉及了相当多的内容,但有些项目和主题超出了本文的范围,但它们是后续文章的绝佳候选。其中包括:

  • **额外的负面评分:**我们考虑的大多数因素都对销售线索的评分有积极影响,但我们是否可以通过与销售团队合作来增强模型,以确定将对销售线索评分产生潜在负面影响的额外因素,如访问我们网站上的招聘页面(来自求职者而非纸张购买者)、不相关的职位或我们竞争对手的员工?
  • **整合数据源:**Dunder Mifflin 可以利用哪些其他内部或外部数据源来增强销售线索评分模型?记住,越多不一定越好;我们必须考虑获取和组合这些数据源所需的成本,并确保它们不会超过它们为我们的模型带来的额外收益。
  • RFM 分析:近期、频率和货币价值(RFM)分析为营销人员提供了一种根据关键兴趣变量细分客户的方法。RFM 模型可以与某些预测模型(如逻辑回归)结合使用,以帮助分析师验证其客户评估工作的准确性。
  • 超参数调整:不同的算法包含特定的超参数,允许您修改与数据集相关的算法行为。随机或网格搜索是用于识别模型的超参数的最佳值的常用技术,以便最终改进模型构造和性能。

如果你想了解更多关于逻辑回归的知识,或者查看更多这类算法的例子,我在下面列出了我在研究和撰写这篇文章的过程中遇到的一些有用的文章和教程(排名不分先后):

  • DataCamp —了解 Python 中的逻辑回归
  • Chrisalbon.com—逻辑回归
  • Michael Galarnyk —使用 Python 进行逻辑回归(scikit-learn)
  • Analytics vid hya——如何在机器学习中使用类别权重改善类别不平衡
  • Ritchie Ng —逻辑回归
  • 谷歌开发者——机器学习速成班(分类)
  • 真实的 Python——Python 中的逻辑回归
  • 机器学习掌握—机器学习的逻辑回归教程
  • 统计学——如何用 Python 绘制 ROC 曲线
  • 数据科学原理与技术—分类
  • Brandon Foltz —统计 101:逻辑回归概率、优势和优势比
  • 艾莉森·拉冈——从困惑矩阵中找出困惑
  • Terrence Shin——了解特性的重要性以及如何在 Python 中实现它

点击 Github 查看完整的 Python 代码。我忘记了什么或者你会做什么不同的事情?任何和所有的反馈都欢迎通过下面的评论或在 wmc342@gmail.com 给我留言。

非常感谢你的阅读!希望这份对销售线索评分和逻辑回归的高层次概述能够展示分析的力量如何加强销售和营销之间的重要关系。现在有了一个有用的工具来通知决策,Dunder Mifflin 的好伙计们可以分配更多的时间来创建他们的下一个大型营销活动(安迪在 2:00 标记处的脸每次都让我感动),以便创建一些高分线索!

非常感谢 Mick 吊床、Adrienne Raphel、Isaac Dinner、Ian MacDonald、Joanna Kelly 和 Susanna Arntz 对这个项目的编辑和见解!

奖金部分:术语表

以下是这篇文章中使用的一些营销、数据科学和办公术语的定义:

  • Lead: 最终可能成为客户/顾客的人或企业。
  • **销售线索评分:**一种共享的销售和营销方法,用于根据销售线索成为客户的可能性对其进行评级。
  • **公司数据:**可以用来对企业进行分类的信息,如地理区域、客户数量、组织类型、行业、使用的技术等。
  • 一年一度的 Dunder Mifflin Scranton 员工颁奖典礼在当地的 Chili's 餐厅举行。
  • Python: 一种解释性的、面向对象的、具有动态语义的高级编程语言。
  • **箱线图:**一种通过四分位数以图形方式展示数字数据的局部性、分布和偏度组的方法。
  • **多重共线性:**多重回归模型中两个或多个独立变量之间高度相关的情况。
  • **One-Hot 编码:**一种向量表示的类型,其中向量中的所有元素都是 0,只有一个元素的值是 1,其中 1 表示指定元素类别的布尔值。
  • **逻辑回归:**用于确定自变量对二元因变量是否有影响的统计模型。
  • Scikit-learn: 一个开源的机器学习库,支持监督和非监督学习。它还为模型拟合、数据预处理、模型选择、模型评估和许多其他实用程序提供了各种工具。
  • 外部有效性:一项研究的结果如何适用于其他环境。
  • **准确性:**分类器算法的评估指标,表示分类器正确的频率。
  • **混淆矩阵:**分类器做出的正确和错误预测数量的列表总结。它用于衡量分类模型的性能。
  • **精度:**真阳性结果数除以所有阳性结果数,包括未正确识别的。
  • **召回:**真阳性结果数除以所有应被鉴定为阳性的样本数。也称为敏感度,这回答了分类器在检测正面结果方面有多好。
  • **F1 评分:**精度和召回率的调和平均值。
  • ROC 曲线:显示分类模型在所有分类阈值下的性能的图表
  • **不平衡数据集:**标签在数据集中的分布不平衡的情况,即分布有偏差或偏斜。
  • **特征重要性:**根据自变量的输入特征在预测目标因变量时的有用程度对其进行评分的技术。
  • **渠道速度:**合格销售线索在销售渠道中移动的速度
  • RFM(近期、频率、货币价值)分析:一种营销方法,用于根据客户的消费习惯识别最佳客户。它有助于预测哪些客户可能会再次购买产品,并估计来自老客户和新客户的收入。
  • 克瑞德·布拉顿:一个电视偶像和我的个人英雄。

向推荐系统问好

原文:https://towardsdatascience.com/say-hello-to-recommendation-systems-aee0488ff97

最著名的数据科学应用之一的预览

照片由 Andrea Piacquadio 拍摄:https://www . pexels . com/photo/thinking-female-secretary-picking-folder-in-workplace-3791242/

推荐系统无处不在。当我说到处的时候,我的意思是到处都是 T2。

大多数数字服务提供商都包括为用户推荐附加内容的功能。事实上,如果你现在正在读这篇文章,你可能会看到一些推荐你接下来阅读的文章。

从电子商务到银行业,推荐系统已经渗透到每个领域。这看起来没什么大不了的,但是这个工具无处不在的事实证明了它的可用性。

推荐系统看起来简单明了,但它们给企业带来了太多好处,并改变了我们作为消费者的思维和行为方式。

在这里,我们简要介绍了推荐系统,并讨论了企业如何利用他们的数据为客户提供推荐。

为什么选择推荐系统?

银行、新闻媒体公司和零售商等实体都有自己独特的商业模式来满足他们的需求。然而,它们都以某种方式整合了推荐引擎。

那么,为什么这些系统如此受欢迎呢?

总之,推荐系统提供了以下好处:

1。他们最大限度地留住客户

许多企业(如社交媒体平台)有强烈的动机让用户尽可能长时间地参与他们的服务。在内容旁边提供推荐将确保用户继续使用该平台,而不是离开。

2。他们最大限度地减轻客户负担

许多企业现在提供多种选择来提高客户满意度,击败竞争对手。

不幸的是,这种做法导致了一种被称为信息过载的现象。简而言之,从众多选择中选择一个是耗费时间和精力的脑力劳动。在使用服务时不断做出决策的用户更有可能脱离服务提供商。

为了避免这种情况,企业依靠推荐来减少从一个内容到下一个内容的转换摩擦。

3。他们识别“隐藏的宝石”

我们,作为人,在提出建议的时候是相当直截了当的。对喜欢奇幻类型电影的朋友,我们推荐奇幻电影;对于喜欢烘焙的朋友,我们推荐烘焙食谱。不幸的是,我们无法有效地推荐人们之前没有表现出任何兴趣的项目。

另一方面,推荐系统能够透过表面层次来识别能够满足用户的项目。他们可以从用户的行为中挖掘出潜在的模式,并使用这些发现来展示用户自己不会考虑的内容。

推荐系统的数据

用于构建推荐系统的数据类型分为两类:

  1. 显式数据

显性数据是指客户通过反馈直接提供的信息。

许多企业通过让客户表达他们对产品和服务的看法来收集这些数据,通常是以喜欢、评级和评论的形式。

2。隐含数据

隐性数据是指客户通过他们的行为提供的信息。这种类型的数据可以通过观察用户的交互来收集。

例如,网站可以通过记录用户访问的页面和购买的商品来跟踪用户行为,然后使用这些信息来了解他们的偏好。

推荐系统的类型

总而言之,在为客户产生建议时,有一些策略可以实施。

推荐系统中使用的这些主要方法是基于内容的过滤、协作过滤和混合过滤。

  1. 基于内容的过滤

基于内容的过滤,通俗地说,就是根据内容的特征进行推荐的策略。通过检查用户消费的内容,推荐系统可以推断出用户最可能喜欢的其他内容。

基于内容的过滤遵循以下逻辑:

  • 人 A 喜欢物品 X
  • 项目 Y 类似于项目 X
  • 因此,人 A 必须喜欢项目 Y

2。协同过滤

协作过滤是基于用户交互做出推荐的策略。正如“协作”一词所暗示的,这种方法需要使用多个用户的交互来为感兴趣的用户找到最佳项目。

协同过滤遵循以下逻辑:

  • 人 A 喜欢项目 X
  • 同样喜欢物品 X 的人 B 喜欢物品 Y
  • 因此,人 A 必须喜欢项目 Y

3。混合滤波

企业还可以选择同时利用多种策略来创建基于混合的推荐系统,以利用每种方法的优点,同时最小化每种方法的缺点。

挑战

推荐系统本质上是复杂的,并对那些寻求建立它们的人提出了许多挑战和障碍。

  1. 他们需要初始数据

不用说,推荐系统在向用户提供适当的建议之前需要足够多的数据。然而,当涉及到系统没有信息的新用户时,这可能是一个问题。这通常被称为冷启动问题

2。他们需要适应变化

推荐系统需要考虑到顾客变化无常的本性。

一个人今天想要的不一定是明天想要的。由于客户的兴趣不断变化,推荐系统必须能够适应他们偏好的变化。

他们还必须考虑外部因素。在许多情况下,客户行为是由最近的趋势决定的。例如,服装业在提出建议时,必须跟上“流行”的潮流。

3。他们促成了“富人越来越富”的现象

推荐系统倾向于显示出对热门内容的偏好,因为它们拥有更多的评论和评级。这会导致系统将这些产品推给其他人,这进一步增加了它们的受欢迎程度。另一方面,不太受欢迎的产品可以被系统忽略,因此将接收很少的流量。

这种情况在许多社交媒体平台上很常见,这些平台受到了审查,因为它们的推荐算法忽视了新的内容创作者,尽管他们的材料质量很高。

4。它们可能很难评估

与机器学习的其他产品不同,推荐系统可能很难评估。

虽然有衡量推荐系统性能的指标,如精确度和均方误差,但它们并不是工具实际投入使用时性能的有力指标。

由于这些系统的有效性只能通过使用它们的客户的行为来真实地反映,因此评估它们的最佳方式是通过实验(例如,A/B 测试)。

案例研究

真正的推荐系统是错综复杂的,并且要考虑无数的因素。然而,作为开始,使用一个简单的例子来展示如何使用数据来构建推荐系统是理想的。

在这里,我们使用 Python 构建了一个系统,根据用户已经看过的电影向用户推荐电影(基于内容的过滤)。

系统将通过执行以下操作来实现这一点:

  1. 根据用户看过的电影创建用户档案
  2. 将每部电影与用户档案进行比较
  3. 识别与用户简档最接近的电影

这个案例研究中的数据是通过纽约时报电影 API 收集的。

代码输出(由作者创建)

每部电影将由其相应概要的矢量化形式来表示。在进行任何矢量化之前,每部电影的文本都需要经过预处理,包括去除停用词和词汇化。

代码输出(由作者创建)

对于这种情况,我们将使用 TF-IDF 算法对处理后的文本进行矢量化,并将矢量存储在数据帧中。

代码输出预览(由作者创建)

文本矢量化后,我们就可以建立用户档案,这个档案是由用户已经看过的电影决定的。在数学上,用户简档由所有这些电影向量的平均值来表示。

接下来,我们可以使用余弦相似性度量将该用户简档与表示其他电影的向量进行比较,较高的分数对应于较大的相似性。我们将推荐余弦相似度得分最高的 3 部电影。

下面的函数执行所有这些步骤。它输入用户看过的电影列表,并返回一个电影列表作为推荐。

作为一个例子,假设用户喜欢警察电影,并且已经观看了“别开枪”、“罪犯”和“人体摄像机”。

该函数以电影列表作为输入,将首先计算代表这些电影的向量的平均值,从而得到代表用户简档的向量。

接下来,该函数将用余弦相似性度量将该向量与表示剩余电影的所有向量进行比较。

最后,该函数将返回余弦相似度最高的 3 部电影。

代码输出(由作者创建)

自然,这个推荐系统过于简单,漏洞百出。电影不能仅凭其总结来评价。此外,使用 TF-IDF 这样的简单单词矢量化方法会产生许多假阴性(即应该推荐但没有推荐的电影)。

也就是说,这个案例研究应该让我们了解如何利用数据为客户提供建议。

结论

照片由普拉蒂克·卡蒂亚尔在 Unsplash 拍摄

直到今天,推荐系统仍然是一个主要的研究课题,这是理所当然的。有效地推出消费者感兴趣的商品的前景对任何企业来说都是诱人的。

如果阅读这篇文章激起了您对推荐系统的兴趣,我邀请您进一步探索用于构建这些系统的各种工具和技术。

你甚至可以通过建立自己的推荐系统来更上一层楼。这可能是一项艰苦的工作,但是利用您的数据科学技能来创建这样一个工具无疑将是一次令人满意和有益的经历。

我祝你在数据科学的努力中好运!

SBERT 与 Data2vec 在文本分类上的比较

原文:https://towardsdatascience.com/sbert-vs-data2vec-on-text-classification-e3c35b19c949

使用两个流行的预训练拥抱脸模型进行文本分类的代码演示

作者图片

介绍

我个人确实相信,所有花哨的人工智能研究和先进的人工智能算法工作都只有极小的价值,如果不是零的话,直到它们可以应用于现实生活的项目,而无需向用户要求大量的资源和过多的领域知识。拥抱脸搭建了桥梁。拥抱脸是成千上万预先训练好的模型的家园,这些模型通过开源和开放科学为人工智能的民主化做出了巨大贡献。

今天,我想给你一个端到端的代码演示,通过进行多标签文本分类分析来比较两个最受欢迎的预训练模型。

第一款是sentence transformers(SBERT)。这实际上是由达姆施塔特科技大学的泛在知识处理实验室的团队为各种任务创建的一系列预训练模型的集合。我在以前的项目中使用过几次 SBERT。他们甚至有一个 python 库,为您提供了不使用拥抱脸 API 和 Pytorch 框架的灵活性。点击这里查看。

第二个模型是 Data2vec ,这是一个由 Meta(脸书)的 AI 团队提供的强大的预训练模型。它是一个自我监督的框架(教师模型→学生模型),为文本、音频和图像编码而设计。如果你对它是如何开发的感兴趣,你可以在这里找到原文。

数据

对于数据,我使用一个著名的开源文本数据集:BBC 新闻集团(它的许可证在这里:https://opendatacommons.org/licenses/dbcl/1-0/)。您可以通过执行以下操作来加载数据:

作者代码

或者,你可以从我的 GitHub repo 中找到一个预处理过的 CSV 版本:https://GitHub . com/Jin hangjiang/Medium _ Demo/blob/main/data 2 vec _ vs _ SBERT/BBC-text . CSV

代码演示

步骤 1:安装并导入我们需要的包

作者代码

步骤 2:拆分数据进行验证

作者代码

这里注意一个细节:我使用的是 CSV 文件,而不是从 sklearn 导入数据。于是我给了输入数据为一个 list (X.tolist()) 。如果不这样做,模型稍后会抛出错误。

第三步。对文本进行标记

作者代码

以下是一些澄清:

model_name :该参数应为您要使用的预训练模型的名称字符串。你可以找到可用的型号:https://huggingface.co/models

【max _ length】:该参数将直接影响训练时间和训练速度。如果每个文档都很长,您可能希望指定模型为每个文档处理的文本的长度。

填充 :如果给定了 max_length,则将该参数设置为 True。填充到批中最长的序列(如果只提供一个序列,则不填充)

步骤 4:将嵌入转换成 torch 数据集

作者代码

第五步:给模特打电话

作者代码

AutoModelForSequenceClassification:“AutoModel…”将帮助您自动识别要使用的正确型号。到目前为止,它对我来说很好。“……用于序列分类”专门用于分类问题。

to("cuda "):如果你的机器上有 GPU,你可以在末尾添加这个函数来利用 GPU 的能力。如果没有此功能,训练时间通常会显著增加。

步骤 6:定义评估指标

作者代码

metrics_name :这应该是一个字符串。对于我们的演示,我选择“f1”作为评估指标。你可以在这里找到可用的选项:https://github.com/huggingface/datasets/tree/master/metrics

平均 :我传递这个参数是因为我在用 f1 的分数来评估一个多标签分类问题。它不是一个通用参数。

步骤 7:微调预训练的模型

作者代码

步骤 8:保存您的微调模型,使其可重用

作者代码

当您想要使用您的微调模型时,您需要做的就是用您自己的模型的路径替换步骤 3 和步骤 5 中的模型名称字符串。

您可以在这里访问完整的代码脚本:https://github . com/Jin hangjiang/Medium _ Demo/blob/main/data 2 vec _ vs _ SBERT/data 2 vec _ vs _ SBERT _ 512 . ipynb

结果

对于 SBERT(最大长度= 512,纪元= 5):

f1 最佳成绩:0.985034

f1 平均得分:0.959524

挂壁时间:15 分 36 秒

内存增加:5.0294 GB

对于 Data2vec (max_length = 512,epoch = 5):

f1 最佳成绩:0.976871

f1 平均得分:0.957822

挂壁时间:15 分 8 秒

内存增加:0.3213 GB

每次运行模型时,结果可能会有一些变化。总的来说,经过 5 次尝试,我可以得出结论,SBERT 在最好的 f1 成绩方面有更好的表现,而 Data2vec 使用了更少的内存。两款车型的 f1 平均成绩非常接近。

看完今天的演示,您应该有以下收获:

  1. 如何使用预先训练好的模型来标记文本数据
  2. 如何正确地将您的数据转换为 torch 数据集
  3. 如何利用和微调预先训练的模型
  4. 如何保存您的模型以备将来使用
  5. Data2vec 和 SBERT 的性能比较

请随时与我联系LinkedIn

参考

Baevski 等人(2022 年)。data2vec:语音、视觉和语言自我监督学习的一般框架。https://arxiv.org/pdf/2202.03555.pdf

拥抱脸。(2022).文本分类。https://hugging face . co/docs/transformers/tasks/sequence _ class ification

Reimers,n .和 Gurevych,I. (2019 年)。句子伯特:使用暹罗伯特网络的句子嵌入。https://arxiv.org/pdf/1908.10084.pdf

NodeFormer:百万节点的可伸缩图转换器

原文:https://towardsdatascience.com/scalable-graph-transformers-for-million-nodes-2f0014ceb9d4

用 O(N)传递所有对消息

图片:Unsplash。

最近,建立用于处理图结构数据的变换器模型在机器学习研究社区中引起了广泛的兴趣。一个关键的挑战来自全球注意力的二次方复杂性,这阻碍了变形金刚扩展到大图。本博客将简要介绍 NeurIPS22 的最新研究成果:

NodeFormer:一个可扩展的图结构学习转换器,用于节点分类,其公共实现可用。

这项工作提出了一种可扩展的图转换器,用于大型节点分类图,其中节点数量可以从数千变化到数百万(甚至更多)。关键模块是基于内核化 Gumbel-Softmax 的消息传递,它在 O(N)复杂度 (N 表示节点数)内实现 所有对特征传播。

以下内容将总结这项工作的主要思想和成果。

图形转换器与图形神经网络

与依赖于在固定输入图拓扑上传递消息的图神经网络(GNNs)不同,图转换器可以通过每个传播层中的自适应拓扑更灵活地聚集来自所有节点的全局信息。具体来说,图形转换器有几个优点:

  • 处理不完善的结构。 对于具有异质性、长程相关性和伪边的图形数据,GNNs 往往因其局部特征聚合设计而表现出能力不足。然而,变压器采用全局注意力,将来自所有节点的信息聚集在一层中,这可以克服输入结构的限制。
  • 避免过度挤压。 当将信息聚合到固定长度的向量中时,GNNs 可能会指数地丢失信息,而图转换器利用全局注意力聚合,可以自适应地关注为目标节点的预测任务提供信息的主导节点。
  • 无图任务的灵活性。 除了图的问题,还有各种各样没有图结构的任务。例如,图像和文本分类(每个图像可以被视为一个节点,但没有图形将它们连接起来),以及物理模拟(每个粒子都是一个节点,但没有显式观察的图形)。虽然通常的做法是在输入特征上使用 k-NN 来构建用于消息传递的相似性图,但是这种人工创建的图通常独立于下游预测任务,并且会导致次优性能。转换器通过自动学习消息传递的自适应图结构来解决这个问题。

对于节点分类,转换器可以将来自所有其他节点的信息聚合到一个层中。Transformers 给出的分层更新规则可以看作是一步节点嵌入更新和图结构估计的组合(我们可以把注意力矩阵看作图邻接矩阵)

在大型图上构建变压器的挑战

有几个挑战使得在大型图上构建转换器成为一个不小的问题,特别是在节点数超过数千的图上。

  • 全局注意力的二次复杂度: 用于所有对特征聚集的注意力计算需要 O(N)复杂度,这对于大图是禁止的,其中 N 可以是任意大的,例如从几千到几百万。具体来说,如果 N 大于 10K,一个 16GB 内存的普通 GPU 将无法在所有节点上运行这样的全局关注。
  • 图稀疏性的调节: 与密集连接所有节点对的关注图(我们可以将关注矩阵视为加权图邻接矩阵)相比,真实世界的图通常是稀疏的。问题是当 N 变大时,在这样一个密集图上的特征传播可能会导致我们所说的过度规范化问题,这意味着来自不同节点的信息被其他节点所分散。在传播之前稀疏化可学习结构的合理补救措施。

基于内核化 Gumbel-Softmax 的消息传递

我们的工作节点形成器结合了随机特征图和 Gumbel-Softmax 作为解决上述问题的统一模型。具体来说,Gumbel-Softmax 首先用于替换原始的基于 Softmax 的注意力特征聚合:

使用当前层的所有节点表示来更新下一层节点表示。Gumbel-Sofmtax 可以被视为对目标节点 u 的所有节点中的一个相邻节点进行采样的连续放松。实际上,可以采样 K 次,这产生一组采样的相邻节点。q、k、v 是来自结点表示的变换要素

上面的等式定义了需要 O(N)的节点 u 的计算,并且计算 N 个节点的表示需要 O(N)的复杂度,因为必须独立地计算所有对的注意力分数。为了解决这个困难,我们求助于 Performer 中的主要思想,并采用随机特征映射(RFM)来近似 gum bel-Softmax(Performer 中最初采用 RFM 旨在近似确定性 soft max 注意力,这里我们将这种技术扩展到具有随机噪声的 Gumbel-Softmax)。

使用建议的内核化 Gumbel-Softmax 的新更新规则。从 LHS 到 RHS 的推导是根据矩阵乘积的基本关联规则

重要的是,在新的计算中,即上述方程的 RHS 中,两个求和项(在 N 个节点上)由所有节点共享,并且在一层中只能计算一次。因此,这导致更新一层中 N 个节点的复杂度为 O(N)。

如何利用输入图

另一个重要的问题是如何利用输入结构(如果有的话),因为上面的全对消息传递忽略了输入图。我们另外提出两个简单的策略:

  • 添加关系偏差: 我们另外假设一个可学习的标量项,如果在输入图中节点 u 和 v 之间存在边,则该标量项被添加到节点 u 和 v 之间的注意力得分中。
  • 边缘正则化损失: 使用边缘(u,v)的关注分数作为估计概率,并为所有观察到的边缘定义最大似然估计(MLE)损失。直观地说,这种设计最大化了观察到的边缘的注意力权重。

但是输入图的重要性(或者说信息量)在不同的数据集之间是不同的。所以在实践中,需要调整权重(作为一个超参数),它决定了对输入图的重视程度。下图显示了 NodeFormer 的整体数据流。

节点形成器的数据流,其输入包含类似于普通 GNNs 的节点特征和图邻接。红色部分是通过内核化 Gumbel-Softmax 传递的所有对消息,绿色部分是关系偏差,蓝色部分是边缘正则化损失。如果输入图不重要或不可用,后两个部分可以省略。

实验结果

我们将 NodeFormer 应用于节点分类任务,并在八个数据集上取得了与常见的 GNNs 和最先进的图结构学习模型 LDS 和 IDGL 相比极具竞争力的结果。

NodeFormer 和普通 GNN 模型的对比实验结果

除了节点分类,我们还考虑了图像和文本分类任务,其中输入图形丢失。我们使用具有不同 k(5,10,15,20)的 k-NN 来构建图,并且还考虑不使用节点形成器的输入图。有趣的是,后一种情况不会导致明显的性能下降,有时还会带来更好的性能。

节点嵌入和估计关注分数的可视化(过滤掉低权重的那些)。我们用一种颜色标记同一标签类的节点。全局注意力倾向于连接同一类中的节点,并且还增加了图的全局连通性

作为一个新的模型类,我们强调 NodeFormer 的一些优点:

  • 容量: NodeFormer 通过各层的稀疏关注和来自所有节点的潜在聚合信息,自适应地学习图结构。
  • 可扩展性: NodeFormer 支持 O(N)复杂度和小批量分区训练。在实践中,它仅使用 4GB 内存就成功地扩展到具有百万个节点的大型图。
  • ***效率:***node former 的训练可以通过基于梯度的优化以高效的端到端方式完成。例如,在 1000 个纪元中对 Cora 进行培训和评估只需要 1-2 分钟。
  • 灵活性: NodeFormer 灵活用于归纳学习和处理无图情况。

我们还简要讨论了 NodeFormer 的潜在应用。一般来说,NodeFormer 可以用作图形结构数据的通用编码器,或者处理标准预测任务中实例之间的相互依赖。具体来说,它可以很容易地应用于两类问题:

  • (大)图上的预测任务,即目标是基于节点特征和图结构预测每个节点(或边)的标签。例如,预测大型社交网络中的用户活动。
  • **没有输入图和节点形成器的标准预测任务(分类或回归)**可用于开发数据集中实例之间的潜在相互依赖性。例如图像分类。

这篇博客介绍了一种新的图形转换器,它可以成功地扩展到大型图形,并显示出优于普通 gnn 的良好性能。变压器式模型具有一些固有的优势,可以克服 GNNs 在处理长程相关性、异质性、过度挤压、图形噪声和完全没有图形方面的局限性。尽管如此,构建强大的图形转换器作为下一代图形表示模型仍然是一个开放和未充分探索的问题,我们希望这项工作可以在这个方向上提供一些见解。

如果对这项工作感兴趣,人们可以阅读报纸了解更多的细节。

论文:https://openreview.net/pdf?id=sMezXGG5So

代号:【https://github.com/qitianwu/NodeFormer

除非另有说明,所有图片均为作者所有。

使用 Azure ML 和 Ray 的可扩展强化学习

原文:https://towardsdatascience.com/scalable-reinforcement-learning-using-azure-ml-and-ray-654d9f5c26a0

在 Azure ML 集群上使用 RLLIB 加速定制健身房环境中的深度 RL 训练。

单机和单代理 RL 训练有许多挑战,最重要的是回报收敛所需的时间。代理在 RL 培训中花费的大部分时间都用于收集经验。简单的申请需要几个小时,复杂的申请需要几天。像 Tensorflow 这样的深度学习框架支持分布式训练;这同样适用于 RL 吗?答案是肯定的。

本文通过一个实际例子关注单机训练的具体痛点,并演示 scaled RL 如何解决这个问题。本文假设读者对 RL、深度 RL 和深度学习有基本的了解;对于详细的解释和演练,请浏览页面底部的整个视频。

可扩展强化学习技术通过将学习与行动分离,解决了高维状态空间环境中训练时间增加的问题。遵循分布式深度学习的实践,可以通过跨模型分布梯度计算或通过分布数据累积过程来实现并行性。已经为分布式学习提出了各种各样的算法。

本文主要关注使用分布式经验轨迹收集的加速学习。

我们从以下内容开始:

  • 理解问题陈述。
  • 建立一个简单的 DQN 代理,并为培训持续时间和奖励创建一个基线。
  • 创建一个分布式 RL 环境,以分布式方式运行实验,并将改进与上面的基线进行比较。

用于训练的代码工件的链接可以在这里(https://github.com/sriksmachi/supercabs)获得

自定义环境

网上的许多示例演示了如何在内置的体育馆环境中使用分布式 RL,但是很少使用定制环境。在实践中,当选择 RL 来解决问题时,学习如何为分布式训练开发和注册定制的健身房环境是很重要的。这篇文章教如何创建一个自定义的健身房环境。出于本文和视频的目的,我们将使用下面定义的伪学习问题。

问题:我们处理的自定义环境叫做“Contoso Cabs”。Contoso Cabs 是一家虚构的出租车公司,希望通过增加每个司机每月的总工作时间来增加利润。它目前在 5 个州运营,提供全天候服务。为了实现利润最大化,Contoso Cabs 希望建立一个 RL 代理,帮助司机在出租车请求到达时做出正确的决策。由于利润与驾驶时间相关联,代理接受一次搭车以最大化累计折扣奖励,在这种情况下是总小时数。代理的目标是每集累积最大小时数(每集一个月)。下面的代码显示了本培训中使用的自定义健身房环境类。

DQN 代理商

我们首先使用以下架构构建一个简单的 DQN 代理。

  • 输入:编码状态空间的大小是 36(城市数量(5)+运行天数(7) +每天运行小时数(24))。
  • 2 个尺寸为 36 的 FC 隐藏层。
  • 动作空间表示为(源,目的)的元组,动作空间的大小为 5*5 = 25。为了简单起见,包含了具有相同源和目的对的元组,但是如果代理选择任何这样的动作,则增加了惩罚。实质上,我们向网络输入一批 64 个状态向量,每个状态向量的大小是 36。输出代表每个动作的 Q 值。

当一个 DQN 特工被训练后,奖励稳定在 1000 集 2500–3000 之间,如下图所示。这意味着现在我们有了一个模型,可以用来确保司机的收入在 2500-3000 之间。

DQN 培训结果。(图片由作者创作)

然而,挑战在于,对于一个简单的环境,代理需要大约 35 分钟才能收敛。这里考虑的状态空间仅包含 36 位(编码的)。在实时情况下,状态空间很容易高出 10 倍。

天蓝色上的光线 ML

在深入解决状态空间问题之前,让我们了解一下分布式 RL 算法、Ray、Azure ML 和 APEX 的关键要素。

分布式深度 RL 将动作(与 env 交互)与学习(从样本学习)解耦,这种解耦允许系统独立扩展。根据各种组件之间的交互如何发生以及 RL 方法学,已经发布了几种方法和算法,其中一些在我的文章这里中有所描述。

Ray 的 RLLIB 是一个优秀的开源库,支持大多数提出的算法。使用现有的或定制的健身房环境可以很容易地配置和运行培训作业。在任何分布式集群上启用 RLLIB 都很简单。

Azure ML 是 Azure(微软的云)提供的服务,充当运行 ML 实验的工作空间。使用 Azure ML,我们可以在交互模式或作业模式下运行 ML 实验,用于长期运行的实验。Azure ML 提供了一个自托管的 ML 集群,可以使用 CPU / GPU 核心进行配置,以运行分布式 ML 实验。为了安装和运行分布式 RL 作业,我们需要在 Azure ML 集群上安装 Ray。 Ray-on-aml 是一个开源库,用于将 Azure ML 集群转换为 Ray 集群。

APEX 是一个大规模深度强化学习的分布式架构。它允许演员通过将表演与学习分离来有效地学习。APEX 中的参与者可以扩展到 1000 个工作节点,每个参与者使用自己的环境副本。这些体验被收集起来并与公共重放缓冲器共享。除了经验,演员还分享使用时间差误差计算的优先级。学习者模型采样优先化的经历并重新计算优先级。网络参数被周期性地更新到演员的模型。

下图显示了 APEX 的架构。

APEX 建筑(图片由作者创建)

与单个代理相比,上述架构允许学习者模型从丰富的经验集中学习。与均匀采样相比,优先化/重要性采样有助于更快的收敛。

下面的代码显示了在转换为 Ray 集群的 Azure ML 集群上执行的作业。这是在作业模式下使用 AML 执行的,有关 AML 作业的详细信息,请参见此处编写的代码(https://github . com/sriksmachi/super cabs/blob/master/run _ experiment . py)

结果

使用上面解释的方法,在射线簇上用 10 个演员训练“Contoso Cabs”环境 3 次训练迭代。这个实验只用了 3 分钟训练 6K 集,收敛到最大奖励。

训练时间减少了 90%,同时,我们通过分配工作量运行了 6k 集。下图显示了所有剧集中每集的最高奖励。

APEX 每集奖励(图片由作者创建)

下面的视频详细解释了训练实验。如果你是 RL 新手,我建议你从头开始看视频。

代码演练:使用 Ray 的 RLLIB 和自定义 GYM 环境在 Azure ML 上分发深度 RL。

摘要

总之,真实环境中 RL 代理的单机训练是一个耗时的过程。分布式深度 RL 训练有助于改进训练时间并更快地达到收敛。RLLIB (Ray)是一个用于生产级分布式 RL 工作负载的强大框架,只需几行代码,Azure ML 集群就可以使用 ray-on-ml 转换为 Ray 集群。通过利用本文中提出的方法,可以大大减少培训时间。

用雷在 5 分钟内爬上汉密尔顿

原文:https://towardsdatascience.com/scaling-hamilton-with-ray-in-5-minutes-3beb1755fc09

扩展数据转换中人的方面以及计算方面

Hamilton + Ray —帮助您扩大产量。托马斯·凯利在 Unsplash 上的照片。

Hamilton 是一个用于 Python 的开源、声明性数据流微框架。在这篇文章中,我将解释通过利用汉密尔顿的光线集成来扩展用于汉密尔顿工作流的数据和 CPU 的要求。这篇文章假设读者事先熟悉什么是汉密尔顿。对于背景故事和更长的介绍,我们邀请你阅读这个 TDS 帖子,或者对于更短的五分钟介绍见这个 TDS 帖子,或者对于它如何帮助规模团队&保持他们的代码库有组织见这个 TDS 帖子。

对于那些不熟悉 Ray 的人来说,它是一个开源框架,可以扩展来自加州大学伯克利分校的 python 应用。它有一个不断增长的工具生态系统,可以帮助许多机器学习相关的工作流。例如,它将自己标榜为使您能够非常容易地从笔记本电脑扩展到集群,而无需更改太多代码。就现实世界的使用而言,我喜欢使用 Ray 作为在 python 中实现多重处理的一种非常快速的方式,而不用担心细节!

射线底漆

这里有一个射线引物。好消息是,你不需要了解太多关于雷的知识就可以和汉密尔顿一起使用它。你只需要知道它将轻松地在多个 CPU 内核上并行化你的工作流,并允许你扩展到你的笔记本电脑之外,如果你设置了一个 Ray 集群的话。但是为了让你理解汉密尔顿是如何与它联系起来的,让我们快速回顾一下如何使用雷。

光线使用前提

使用 Ray 的基本前提是,您必须注释您希望通过 Ray 调度执行的函数。例如(从他们的文档):

*# This is a regular Python function.*
def normal_function():return 1*# By adding the `@ray.remote` decorator, a regular Python function*
*# becomes a Ray remote function.*
@ray.remote
def my_ray_function():return 1

然后要执行my_ray_function函数,您应该做:

my_ray_function.remote()

然后它会告诉 Ray 调度函数的执行。要在本地运行而不是在集群上运行,您所要做的就是在调用上面的代码之前以不同的方式实例化“Ray”。

import ray
ray.init() # local execution over multiple cores.
ray.init({... cluster details ...}) # connect to cluster.

现在,🤔,您可能会想,要让我现有的代码运行起来,似乎需要做很多工作,例如,我如何向函数传递参数?我应该如何更改我的应用程序以更好地使用 Ray?等等。好消息!和汉密尔顿在一起你根本不用考虑这些!您只需编写您的标准 Hamilton 函数,只需更改一些“ driver ”代码就可以让它在 Ray 上运行。下一节将详细介绍这一点。

汉密尔顿+雷

要将 Ray 与 Hamilton 一起使用,首先需要安装它。

pip install "sf-hamilton[ray]"

接下来,默认情况下使用 Hamilton,所有的逻辑都写成 python 函数。所以你可以像平常一样写哈密顿函数。这里没有变化。

在执行时,在 Hamilton 框架级别,Hamilton 可以很容易地为您的函数定义的有向无环图(DAG)中的每个函数注入@ray.remote。重申一下*,你不需要修改任何 Hamilton 代码来使用 Ray!*要让 Hamilton 在 Ray 上运行,你需要做的就是提供一个"*GraphAdapter*对象给 Hamilton "*Driver*类你实例化。

一个GraphAdapter,只是一个简单的类,它定义了一些函数,使您能够增加 DAG 的遍历和执行方式。更多信息见文件。

就要添加/更改的代码而言,以下是增加标准 Hamilton 驱动程序代码所需的内容—参见 bold font:

**import ray
from hamilton import **base**, driver
**from hamilton.experimental import h_ray**...**ray.init() # instantiate Ray**
config = {...} # instantiate your config
modules = [...] # provide modules where your Hamilton functions live
**rga = h_ray.RayGraphAdapter( # object to tell Hamilton to run on Rayresult_builder=base.PandasDataFrameResult())  **  
dr = driver.Driver(config, *modules, **adapter=rga**) **# tell Hamilton**
df = dr.execute([...]) # execute Hamilton as you normally would
**ray.shutdown()****

对于那些不熟悉 Hamilton 的人来说,如果您要删除加粗的代码,这就是您运行开箱即用的普通 Hamilton 的方式。

具体来说,我们需要:

  1. 实例化射线:ray.init()
  2. 实例化一个RayGraphAdapter,传入一个ResultBuilder对象,该对象设置当在driver.Driver对象上调用.execute()时返回什么对象类型。在这个例子中,我们指定它应该返回一个熊猫数据帧。
  3. 然后在创建driver.Driver对象时,RayGraphAdapter作为关键字参数adapter=rga被传递,这将告诉 Hamilton 增加 DAG 的行走并使用 Ray。
  4. 不需要其他的改变,所以在你完成之后,你只需要关闭你和 Ray ray.shutdown()的连接。

缩放就是这么简单!

通过添加几行代码,您现在可以:

  1. 并行计算您的哈密尔顿函数。
  2. 扩展到在集群规模数据上运行。

概括一下,使用 Ray 和 Hamilton 的方法与使用普通的 Hamilton 没有太大的不同:

  1. 装汉密尔顿+雷。pip install "sf-hamilton[ray]"
  2. 写哈密尔顿函数。
  3. 编写你的驱动程序代码——如果你想让它在 Ray 上运行,调整这个部分。
  4. 执行你的驱动脚本。

由于切换到使用 Ray 或不使用 Ray 是如此容易,我们很想知道切换到 Ray 会在多大程度上提高数据流操作的速度或规模!

要获得完整的“Ray Hello World”代码示例,我们会将您引向这里的示例目录。

最后

通过使用 Hamilton,您可以组织和扩展编写数据转换的人的方面(不,我在这篇文章中没有谈到这一点,请参见简介中的链接或下面的说服自己的链接😉).借助 Ray,您可以扩展您的数据工作流,以超越笔记本电脑的限制。一起,天空的极限!

如果您喜欢汉密尔顿,并希望继续关注该项目:

  1. 我们想要 github 上的⭐️!
  2. 📣加入我们在 slack 上的羽翼未丰的社区!
  3. 查看我们的文档📚。

警告

关于使用 Hamilton + Ray 的注意事项。

  1. 我们希望从“”实验“”中获得射线支持,但为此我们需要您的反馈!该 API 一直非常稳定(自发布以来一直没有改变),但为了让它永久化,我们很想知道你的想法。
  2. 我们不会公开 Ray 的所有功能,但是我们可以。例如存储器感知调度或为特定功能指定资源。如果你想曝光什么,请告诉我们——请在 github 上发表一篇文章——https://github.com/dagworks-inc/hamilton🙏。

相关职位

有关汉密尔顿的更多信息,我们邀请您查看:

  • 介绍汉密尔顿
  • 5 分钟内汉密尔顿+熊猫
  • 在笔记本上与汉密尔顿迭代
  • 与汉密尔顿一起整理生产熊猫
  • 【未来邮报】5 分钟内汉密尔顿+达斯克

通过赋格用火花(或 Dask)缩放 PyCaret

原文:https://towardsdatascience.com/scaling-pycaret-with-spark-or-dask-through-fugue-60bdc3ce133f

分布式地在每个数据分区上运行 PyCaret 函数

汉尼斯·艾格勒在 Unsplash 上拍摄的照片

PyCaret 是一个低代码机器学习框架,它自动化了机器学习管道的许多部分。只需几行代码,就可以在一个数据集上训练多个模型。在本文中,我们将探讨如何通过在 Spark 或 Dask 上以分布式方式运行几个 PyCaret 训练任务来扩展这种能力。

PyCaret 模型分数网格示例

首先,我们看一个简单的 PyCaret 分类示例。大部分代码摘自 PyCaret 文档中的本教程。重点是展示我们如何用几行代码生成模型排行榜。

我们通过使用get_data函数加载 Titanic 数据集。这是一个众所周知的分类数据集。

从 PyCaret 获取泰坦尼克号数据集

这将为我们提供以下数据。在这个例子中,我们关心的是创建一个模型来预测一个乘客是否幸存。

来自 Titanic 数据集的样本数据

现在我们可以使用 PyCaret 进行模型训练。下一个代码块中有三个函数调用来训练模型并为我们的数据集检索它们的指标。

PyCaret 比较模型

每个函数调用的简要说明:

  • setup初始化环境并创建要运行的转换管道。
  • compare_models运行几个模型训练运行,并用分层交叉验证对它们进行评分。这将返回基于n_select的顶级型号。值为 5 将返回前 5 个训练模型。
  • pull将为我们获取分数网格数据框架。下面是一个示例(前 5 行按准确度排序)。

泰坦尼克号数据集的评分网格

稍后,我们将看看如何使用 Spark 或 Dask 分布式并行运行多个compare_models调用。在此之前,我们将了解如何为 Spark 或 Dask 带来单独的功能。

包装 PyCaret 代码

Fugue 是一个开源框架,将 Python、Pandas 或 SQL 代码移植到 Spark 或 Dask。在这篇博客中,我们将看看transform函数。这采用单个函数,并在数据的每个分区的 Spark 或 Dask 上执行它。

我们首先将 PyCaret 代码封装在一个名为wrapper的函数中。这个wrapper函数将用于 Spark 中的每个数据分区。在wrapper里面基本上是我们之前所有的代码。唯一的新东西是重置索引和重命名列。这是因为 Fugue 需要列名不包含空格和句点,以便与所有后端兼容。

注意,函数的类型注释(pd。DataFrame)是神游所需要的,以便知道如何将函数带到 Spark 或 Dask。这是因为赋格可以处理更多的注释,比如List[Dict[str, Any]]Iterable[List[Any]]。在transform函数中也需要模式,因为 Spark 和 Dask 需要显式模式(或从中受益匪浅)。

用赋格包装 PyCaret

现在我们有了一个基本功能,可以用在原生熊猫身上。调用transform函数将会得到与之前的分数网格相同的结果。通过在 Pandas 上测试它,我们知道当我们把它移植到 Spark 执行引擎上时,这个代码将会工作。但是在将它引入 Spark 之前,我们将在下一节中首先对数据进行分区。

Spark 和 Dask 上的机器学习

大数据集上的机器学习有两种形式。Dask-ML 文档对此提供了很好的解释。第一个是内存限制问题,即数据集不适合单台机器。在这种情况下,一个大型模型正在整个集群中接受训练。第二个是与计算相关的问题,在这种情况下,多个模型根据适合单台机器的数据进行训练。群集用于并行化多个较小的模型训练作业。

当数据太大而不适合单台机器时,通常意味着可以使用数据的逻辑分组将问题分成几个更小的机器学习问题。在这个巨大的例子中,我们将按性别(男性或女性)分割数据,然后为每组数据运行 PyCaret compare_models

将 PyCaret 代码移植到 Spark 和 Dask

下面的代码会把数据拆分成男性和女性,然后对每一组运行compare_models。这两个compare_models函数调用将在 Spark 上分布式运行。首先,我们将首先显示代码和输出,然后我们将进行修改以使我们的wrapper产生火花。

在 Spark 上分布式运行 PyCaret

这为我们提供了前 5 名模型和两组(男性和女性)的指标。对于这个特定的问题,我们看到性能略有提高。由于数据量的原因,这可能是有限的。然而,对于大数据集,与在整个数据集上训练一个大模型相比,这种方法通常可以产生显著的改进。

Spark 上的分布式培训结果

为了将 PyCaret 引入 Spark,我们必须对我们的wrapper函数进行如下修改:

  • 将性添加到模式中。分布式计算框架对模式有严格的要求。
  • 在结果中添加一个名为 Sex 的列。这是为了在我们收集所有结果时进行跟踪。因为数据是因为调用了wrapper函数而被预先分区的,所以我们保证在性别列中有一个统一的值(男性或女性)。

然后,我们对transform呼叫做了以下更改:

  • 将原始数据帧中的 np.nan 替换为 None。Spark 很难解释同时具有 np.nan 和 string 值的列。
  • 添加了一个按性别划分的分区,将数据分成两组
  • 导入了 fugue_spark,并为 fugue 使用了“spark”执行引擎。

结论

在本文中,我们展示了如何利用 Spark 同时对多个数据分区执行 PyCaret 模型训练。自撰写本文以来,PyCaret 团队和 Fugue 团队正在致力于一个更加原生的集成,以便在 Spark 或 Dask 上分发compare_models功能。可以在 Github 上跟踪的进展。

数据许可证

Titanic 数据集由 PyCaret 在 MIT 许可下托管。

将球形深度学习扩展到高分辨率输入数据

原文:https://towardsdatascience.com/scaling-spherical-deep-learning-to-high-resolution-input-data-a9f17b30b978

可扩展旋转等变球形细胞神经网络的球上散射网络

常规球形细胞神经网络不可扩展到高分辨率分类任务。在本文中,我们将介绍球形散射层,这是一种新型的球形层,可以在保留相关信息的同时降低输入数据的维度,同时还具有旋转等变性。散射网络通过采用来自小波分析的预定义卷积滤波器来工作,而不是从零开始学习卷积滤波器。由于散射图层的权重是设计的而非学习的,因此散射图层可用作一次性预处理步骤,从而降低输入数据的分辨率。我们根据经验证明,配备初始散射层的球形 CNN 可以达到数千万像素的分辨率,这是以前传统球形 CNN 层难以实现的壮举。

这篇博文是与奥古斯汀·马沃-帕克合著的。

杰瑞米·托马斯在 Unsplash 上拍照

以前的球形深度学习方法计算量很大

球形 CNNs,2,3]对于机器学习中的各种问题非常有用,因为许多数据源无法自然地在平面上表示(参见我们的上一篇文章的介绍)。球形 CNN 的一个关键属性是它们对于球形数据的旋转是等变的(在本文中我们主要关注旋转等变方法)。在实践中,这意味着球形 CNN 具有令人印象深刻的一般化属性,允许它们做诸如分类 3D 对象网格之类的事情,而不管它们如何旋转(以及它们在训练期间是否看到网格的不同旋转)。

我们最近描述了在 Kagenova 开发的一系列进步,以提高球形 CNN 的计算效率。我们的方法——高效的广义球形 CNN——保留了之前球形 CNN 的等方差特性,同时计算效率显著提高[1]。然而,尽管在计算效率方面取得了这些进步,球形 CNN 仍然局限于相对低分辨率的数据,这意味着球形 CNN 无法应用于通常涉及更高分辨率数据的令人兴奋的应用,如宇宙学数据分析和虚拟现实的 360°计算机视觉。在最近的一篇文章中,我们介绍了球形散射层网络,以扩展有效的广义球形 CNN 更高的分辨率[4],我们在当前的帖子中进行了回顾。

支持高分辨率输入数据的混合方法

在开发高效的广义球形 CNN[1]时,我们发现构建球形 CNN 架构的混合方法非常有效。混合球形 CNN 在同一网络中使用不同风格的球形 CNN 层,允许从业者在不同的处理阶段获得不同类型层的好处。

示例混合球形 CNN 架构图。请注意这些层并不是单片的,而是不同风格的球形 CNN 层。【图由作者创作。]

球体上的散射网络延续了这种混合方法,并引入了一种新的球形 CNN 层,可以插入到现有的球形结构中。为了将有效的广义球形 CNN 扩展到更高维度,这个新层需要:

  1. 计算可扩展
  2. 将信息混合到低频,以允许后续层在低分辨率下工作
  3. 旋转等变的
  4. 提供稳定且局部不变的表示(即,提供有效的表示空间)

我们认为散射网络层具有满足所有这些特性的潜力。

球体上的散射网络

Mallat [5]首先在欧几里德环境中提出的散射网络可以被认为是具有从小波分析中得到的固定卷积滤波器的 CNN。散射网络已被证明对传统(欧几里德)计算机视觉非常有用——特别是在数据有限,因此学习卷积滤波器很困难的情况下。在这里,我们将简要讨论散射网络图层的内部工作方式,它们如何满足上一节中定义的要求,以及它们如何开发用于球面数据分析。

散射层内的数据处理由三个基本操作执行。第一个构建模块是固定的小波卷积,它类似于欧几里德 CNN 中使用的常规学习卷积。在小波卷积之后,散射网络将模数非线性应用于结果表示。最后,散射利用缩放函数,它执行一种形式的局部平均,与普通 CNN 中的池层有些相似。这三个构建模块的重复应用将输入数据分散到计算树中,在不同的处理阶段将结果表示(类似于 CNN 频道)从树中取出。这些操作的示意图如下所示。

球面信号 f 的球面散射网络。信号通过球面小波变换的级联传播,结合绝对值激活函数,用红色节点表示。散射网络的输出是通过将这些信号投影到球面小波尺度函数上给出的,从而产生由蓝色节点表示的散射系数。【图由作者创作。]

从传统深度学习的角度来看,分散网络的操作可能看起来有点模糊。然而,所描述的每种计算操作都有特定的目的——旨在利用小波分析的可靠理论结果。

仔细推导了散射网络中的小波卷积,以便从输入数据中提取相关信息。例如,在自然图像的情况下,小波被定义为专门提取与高频下的边缘和低频下的物体的一般形状相关的信息。因此,在平面设置中,散射网络滤波器可能与传统的 CNN 滤波器有些相似。这同样适用于球形设置,我们使用尺度离散小波(详见[4])。

由于小波滤波器是固定的,初始散射层只需要应用一次,而不是在整个训练中重复应用(像传统 CNN 中的初始层)。这使得散射网络在计算上可扩展,满足上面的要求#1。此外,散射层降低了其输入数据的维度,这意味着在训练下游 CNN 层时,只需要有限的存储量来缓存散射表示。

在小波卷积之后应用模数非线性。首先,这给网络注入了非线性。第二,模数将输入信号中的高频信息混合到低频,满足上面的要求#2。下图显示了这一点,图中显示了模数非线性之前和之后数据的小波表示的频率分布。

模运算前后不同球面频率 l 下小波系数的分布。输入信号中的能量从高频(左图)移动到低频(右图)。f 是输入信号,ψ是尺度为 j 的小波。【图由作者创作。]

在应用模数之后,产生的信号被投影到缩放函数上。缩放函数从表示中挑选出低频信息,类似于传统 CNN 中的池函数的操作。

我们根据经验测试了球形散射网络的理论等方差特性。测试是通过旋转信号并通过我们的散射网络进行的,然后将结果表示与输入数据通过散射网络并旋转的表示进行比较。在下表中,我们证明了给定深度的等方差误差是低的,因此满足要求#3(通常在实践中不会超过深度 2,因为大部分信号能量已经被捕获)。

不同深度球形散射网络的旋转等方差误差。

最后,从理论上证明了欧几里德散射网络对小的微分同胚或变形是稳定的[5]。这个结果已经扩展到紧致黎曼流形上的散射网络[6],特别是球面上的散射网络[4]。在实践中对微分同胚的稳定性意味着,如果对输入进行轻微的改变,由散射网络计算的表示将不会有显著的不同(参见我们以前的帖子对稳定性在几何深度学习中的作用的讨论)。因此,分散网络提供了一个表现良好的表示空间,后续学习可以在其上有效地进行,满足上面的要求#4。

可扩展和旋转等变球形 CNN

假设引入的散射层满足我们所有期望的属性,我们现在准备将它们集成到我们的混合球形 CNN 中。如前所述,散射层可以作为初始预处理步骤固定在现有架构上,以减少后续球形层处理的表示的大小。

散射层模块(虚线左侧)是一个设计的层,这意味着它不必被训练,而其余层(虚线右侧)是可训练的。这意味着散射层可作为一次性预处理步骤应用,以降低输入数据的维度。【图由作者创作。]

由于散射网络对于给定的输入具有固定的表示,所以散射网络层可以在训练开始时应用于整个数据集一次,所得到的低维表示被缓存用于训练随后的层。幸运的是,散射表示的维数减少了,这意味着存储它们所需的磁盘空间相对较低。给定这种新的球形散射层,有效的广义球形细胞神经网络可以用于高分辨率分类问题。

宇宙微波背景各向异性的分类

物质在整个宇宙中是如何分布的?对于宇宙学家来说,这是一个基本的研究问题,对我们宇宙的起源和演化的理论模型有着重大的影响。宇宙微波背景(CMB)辐射——大爆炸的残余能量——描绘了物质在整个宇宙中的分布。宇宙学家在天球上观测 CMB,这要求计算方法能够在球体上自然地进行宇宙学分析。

宇宙学家对分析 CMB 的方法感兴趣,这种方法能够检测整个空间中 CMB 分布的非高斯性,这可能对早期宇宙的理论有重要意义。这种分析方法还需要能够达到天文分辨率。我们通过以 L =1024 的分辨率将 CMB 模拟分类为高斯或非高斯,证明了我们基于散射的网络能够满足这些要求。基于散射的网络成功地以 95.3%的准确率对这些模拟进行了分类——这比分辨率较低的传统球形 CNN 的 53.1%好得多。

来自高斯和非高斯类别的 CMB 高分辨率模拟示例,用于评估球形散射网络扩展到高分辨率的能力。【图片由作者创作。]

摘要

球形散射层压缩其输入表示的维度,同时保留下游任务的重要信息。我们已经证明,这使得散射层对于高分辨率的球形分类任务非常有用。这开启了大量以前难以处理的潜在应用,如宇宙学数据分析和高分辨率 360°图像/视频的分类。然而,许多计算机视觉问题需要密集预测,如分割或深度估计,这就需要高维输出和高维输入。开发易处理的球形 CNN 层,可以增加其输出表示的维度,同时保持等方差,这是 Kagenova 当前研究的主题,将在即将发布的帖子中介绍。

参考

[1] Cobb,Wallis,Mavor-Parker,Marignier,Price,d'Avezac,McEwen,高效广义球形 CNN,ICLR (2021), arXiv:2010.11661

[2]科恩,盖格,克勒,韦林,球形 CNN,ICLR (2018), arXiv:1801.10130

[3]埃斯特韦斯,艾伦-布兰切特,马卡迪亚,达尼利迪斯,学习 SO(3)与球形 CNN 的等变表示,ECCV (2018), arXiv:1711.06721

[4] McEwen,Jason,Wallis,Christopher 和 Mavor-Parker,Augustine N. ,可扩展和旋转等变球形 CNN 的球上散射网络,ICLR (2022), arXiv:2102.02828

[5]布鲁纳、琼和斯特凡·马拉特,不变散射卷积网络,IEEE 模式分析和机器智能汇刊(2013)

[6] Perlmutter,Michael 等,紧致黎曼流形上的几何小波散射网络,数学与科学机器学习。PMLR (2020), arXiv:1905.10448

扩展您的数据科学意味着扩展您的计算

原文:https://towardsdatascience.com/scaling-up-your-data-science-means-scaling-up-your-compute-ead3d5dd243d

如何使用云虚拟机设置支持远程桌面的数据科学环境

Artur Aldyrkhanov 在 Unsplash 上拍摄的照片

在每个数据科学家的旅程中,经常会有这样一个时刻,她/他/他们已经不再学习数据科学的基础知识,并开始将新获得的知识应用到越来越大的数据集。与此同时,这些数据科学家也经常开始试验更复杂的模型,如深度学习模型。

随着我们的数据集越来越大,模型越来越复杂,所需的计算资源也在增加。在不太遥远的过去,这意味着我们需要购买更好的硬件。内存更大、光盘更大、芯片更快的笔记本电脑。幸运的是,如今随着云技术的出现,我们可以利用大得多的计算资源进行有限的使用,其成本只是购买高性能笔记本电脑的一小部分。

不幸的是,对于今天的数据科学学生来说,这些云资源也提供了许多利用更强大的计算环境的选项。如此之多,以至于它可能会变得相当混乱,不知道该把重点放在哪里。DataBricks、AWS Sagemaker 或 Google CoLab 等数据科学平台都提供托管数据科学环境,让数据科学家能够访问更强大的计算资源。

所有这些或多或少“受管理”的选项的缺点是,每个平台都有难以驾驭的方面。例如,Google CoLab 使用一个非持久性磁盘来存储您的工件(例如 csv 文件、结果输出等),每次会话结束时都会删除这些工件。此外,磁盘环境的目录结构可能并不总是容易理解。最后,添加更多您可能需要的软件作为您的数据科学管道的一部分会更加困难,因为您对用于支持您的笔记本电脑的虚拟机的可见性更低。

尽管有这些限制,云环境仍然为数据科学家提供了大量短期借用大量计算资源的潜力,这有助于控制成本。在本教程的剩余部分,我将带您使用虚拟机和云存储桶来设置云数据科学环境。此外,我们将建立一个远程桌面连接,并安装 Anaconda 的 Miniconda,以实现更丰富的视觉体验,更类似于您自己的个人笔记本电脑。我们的目标是在不倾家荡产的情况下,让有兴趣扩大数据科学工作负载的年轻数据科学家具备相关能力。

对于那些只需要高级步骤而不需要所有解释的人,请参见 TL;文末博士。让我们跳进来。

第一步:选择云平台并建立账户

让我们面对现实吧,随着越来越多的公司使用云服务构建基础设施,云计算将会继续存在。对于所有数据科学家来说,熟悉云技术是数据科学之旅的一个基本组成部分,因为我们希望在这个不断发展的商业环境中保持竞争力。对于数据科学企业家来说,学习如何导航和利用云服务更加重要,因为学习这些技能可以让我们获得高性能计算环境和一流的人工智能服务,使我们的初创公司能够支持大规模企业。

因此,在现有的“三大”云平台(如 AWS、微软 Azure、谷歌云平台[GCP])中设立一两个账户是向前迈出的重要一步。在本教程中,我们利用 GCP,但 AWS 和微软的步骤是相似的,有一些明显的小差异。

这三种云中的每一种都提供了一个可通过浏览器访问的管理控制台。要找到 GCP 控制台,我只需打开 Chrome,搜索“GCP 控制台”如果你有一个链接到 Chrome 浏览器的 Gmail 帐户,点击搜索链接将打开该帐户下的控制台。如果您是第一次访问 GCP 控制台,您的屏幕应该是这样的:

作者图片

你会注意到谷歌提供 300 美元信用的免费试用,这相当于相当多的实验。您还将被要求设置计费信息,这可以通过单击控制台中的“计费”链接来完成。请注意,虽然本教程中的大多数服务都很便宜,但如果不删除,随着时间的推移,它们会产生一些费用。一个很好的经验是,云服务使我们能够轻松扩展,但当我们这样做时,我们的成本也会增加😊让潜在的雇主知道你了解扩展这些云服务的后果,因此会是他们云成本的好管家,这总是好的。

先不说速度,几年前我很快就学到了这一课。我通过谷歌的 NLP API 运行一些从互联网上搜集的文本,为我正在测试的实验产品提取实体。我们的目标是将搜索范围扩大到数千个抓取的网页。当我自动化这个过程时,我注意到代码需要一段时间才能完成。不久之后,谷歌给我发了一封电子邮件,大意是“嘿,老兄,你正在运行异常高数量的 API 请求,所以我们为你停止了它,因为我们认为可能有问题。”天哪,有过吗?!?当我爬到我的控制台仪表板上去看发生了什么事时,我的胃沉了下去。啊,蟹肉块,我的预期账单从几美元涨到了 300 多美元。听起来不多,但对于一个我亲自买单的实验来说,只能说这远远超出了预算。经过一番挖掘,我发现我在搜索中找到的一个网页是一本书的几千页电子版。惨痛的教训。

作者图片

一旦你建立了你的帐户,点击“创建项目”按钮。如果你已经设置了 GCP,那么你很可能会看到你已经在你工作的最后一个项目中,如下图所示。您可以选择为本教程创建一个新项目,也可以留在当前使用的项目中。

作者图片

步骤 2:创建虚拟机和存储桶

启用帐户后,下一步是设置一个虚拟机,用于设置我们的数据科学环境。点击左上角的“汉堡”菜单,向下滚动到菜单的“计算”部分。在“计算”下,你会看到一个“计算引擎”的选项,将鼠标悬停在该选项上会打开另一个带有更多选项的侧边栏。在顶部,您应该会看到“虚拟机实例”单击此处,让我们设置虚拟机。

作者图片

在虚拟机设置页面上,您会注意到相当多的选项。让我们讨论一下数据科学环境中的重要问题。首先,是选择地区。选择地理空间上离您最近的地区,以确保最佳的网络速度。

接下来,选择您希望使用的实例类型。请注意,较大的计算资源与较高的每小时成本相关,例如正常运行时间。默认选择是 E2 实例,这是通用机器,当您向下滚动不同的 E2 选项时,仍然提供相当多的计算。对于这个演示,我将选择一台小型机器,它有 2 个虚拟 CPU(vCPU)和 2 GB 的 RAM。把 vCPUs 想象成线程。如果您有 2 个 vCPUs,您可以跨 2 个线程进行多进程处理。

运行这台机器的成本大约是 0.02 美元/小时,我们可以看到,如果我不小心让这台机器 24/7 运行一个月,它只需要大约 13 美元。不算太寒酸。

作者图片

我们要更改的下一个选项是启动盘的大小和操作系统。默认情况下,Debian OS 包含一个 10 GB 的引导磁盘,但是由于我们的目标是为我们的数据科学开发设置一个具有更丰富视觉体验的远程桌面,并计划安装 Anaconda,我们将需要一个更大的引导磁盘来处理所有这些应用程序。我选择了 100 GB 的启动盘。请记住,您还需要为正在使用的磁盘付费,也可以选择为 SSD 等速度更快的磁盘付费,但它们的价格甚至更高。不幸的是,引导磁盘不能像虚拟机那样关闭,所以只要它们在我们的帐户中,我们就要为它们付费。然而,总的来说,我们每月的花费仍然只有 22 美元左右。幸运的是,即使在启动虚拟机之后,磁盘大小也是可以调整的。

我也喜欢用 Ubuntu,所以我把我的 OS 换成了包含 Ubuntu。请注意,使用一些操作系统,如 Ubuntu Pro,会产生额外的云费用。

在设置我们的虚拟机时,我们最不想做的事情是选择让所有 Google APIs 都可以访问虚拟机的选项(“允许完全访问所有云 API”)。通过选择此选项,我们可以确保我们的虚拟机能够访问其他云服务,如我们将设置的云存储桶或 Google 的认知服务,如 Google NLP。Google NLP 是一个经过预先训练的机器学习解决方案,用于从非结构化文本中提取含义(参见上面我的故事,了解我如何使用 API)😊).

作者图片

一旦我们做出了选择,我们就可以启动我们的实例了。除了 VM 之外,我们还想建立一个 Google 云存储桶来保存我们的数据科学实验的任何工件。谷歌云存储桶比我们连接到虚拟机的磁盘更便宜,因此是一种经济高效的方式来存储我们的代码、数据集、模型和其他与数据科学项目相关的工件,如果我们选择在使用后删除它们。

例如,我们可以启动一个大型虚拟机实例,并设置我们的远程桌面来执行我们的研究和训练模型。一旦完成训练,我们就可以将实验代码、管道代码、最终模型、相关的训练数据集和 requirements.txt 保存到一个存储桶中。保存后,我们可以删除该实例,这样我们就不会再为虚拟机或相关磁盘产生费用。

Google 甚至允许我们将实例保存为映像,因此如果我们需要重新启动完全相同的虚拟机环境,因为我们可能下载了其他软件工具,如 Tesseract for OCR,我们可以使用保存的映像创建一个新的实例。

但是我跑题了。要设置云存储桶,我们需要做的就是选择左上角的“汉堡”菜单图标,向下滚动到存储。

作者图片

选择后,我们可以选择创建一个存储桶,并为该桶提供一个唯一的名称。我们可能希望打开的另一个配置是,为了安全起见,确保没有对 bucket 的公共访问,如下所示。除了这些选择,缺省值将满足我们在这里的使用。

作者图片

步骤 3:设置防火墙规则

在开始使用我们的实例之前,我们还需要设置一些防火墙规则,允许虚拟机建立"一个加密隧道,通过该隧道,您可以将 SSH、RDP 和其他流量转发到虚拟机实例",并确保我们可以从本地笔记本电脑通过远程桌面连接到实例。要设置这些规则,请在搜索栏中键入“防火墙”点击“防火墙”服务。

防火墙窗口打开后,单击浏览器顶部的“创建防火墙规则”。我们将设置 2 个防火墙规则。第一个允许创建加密隧道,第二个允许从您的特定笔记本电脑访问。此链接展示了如何创建防火墙规则以允许加密隧道。要设置允许您的个人笔记本电脑访问的规则,请先访问此链接并复制您的 IPv4 地址。

接下来,将目标更改为“网络中的所有实例”,将您的特定 IP 地址粘贴到“源 IPv4 范围”框中,选中“tcp”复选框,并在 TCP 框中输入“20,3389,4000”。这些端口允许 RDP、SSH 和 NoMachine(我们将使用的远程桌面应用程序)。

作者图片

既然您的防火墙规则已经设置好了,我们就可以在虚拟机上完成远程桌面的设置了。

步骤 4:通过 SSH 访问我们的虚拟机并安装远程桌面

现在我们的项目已经设置了初始的云服务,下一步是回到我们刚刚设置的 VM 实例。单击左侧菜单栏中的“VM Instance”选项将弹出一个窗口,其中列出了我们为此项目启动的虚拟机。

与 AWS 相比,Google 的优点在于它提供了一个基于浏览器的 SSH 连接窗口,可以直接从实例启动命令 shell。另一方面,如果您使用 Windows,AWS 需要使用第三方 SSH 客户端,如 Putty,这也意味着您需要下载 Putty 用来与 AWS 云上任何正在运行的实例建立安全 SSH 连接的私钥。

只要您登录到控制台环境,Google 就会为您处理这些 SSH 密钥,为我们节省了一个敏感的安全步骤。

单击新创建的实例旁边的 SSH 按钮后,一个 SSH shell 将在一个新窗口中打开。

作者图片

现在,我们提交一系列命令,这些命令将执行以下操作:1 .更新我们的 Linux 应用程序 repo,2。将用户添加到机器,以便从远程桌面连接(系统将提示您设置密码,其余信息是可选的),3 .从 NoMachine 下载我们的 Ubuntu 操作系统的最新远程桌面应用程序,4。并在虚拟机上设置我们的访问规则,以允许基于密码访问机器。

下面是要输入的命令。请注意,这一步需要一点时间来下载。完成后,返回控制台中的虚拟机窗口,停止然后启动实例,以说明对机器所做的所有更改。在这里,为您的虚拟机复制外部 IP。

本地机器的快速步骤。我们正在使用一个免费的远程桌面应用程序,名为 NoMachine。要建立远程桌面连接,我们需要在笔记本电脑上安装 NoMachine 软件。你可以通过访问这个链接来实现。

sudo apt-get updatesudo apt-get upgrade -ysudo adduser usernamesudo apt-get install ubuntu-desktopwget [https://www.nomachine.com/free/linux/64/deb](https://www.nomachine.com/free/linux/64/deb) -O nomachine.debsudo dpkg -i ./nomachine.deb

下面是如何使用 VIM 在 shell 中设置访问规则。

sudo vim /etc/ssh/sshd_config

一旦 VIM 打开配置文件,输入以下内容:

- press i and then enter
- change “PasswordAuthentication” line from no to yes
- press esc then :wq

作者图片

步骤 5:访问远程桌面并安装 Miniconda

一旦您在本地笔记本电脑上下载了 NoMachine,打开应用程序并单击“添加”来添加您的新连接。您将需要虚拟机的外部 IP 地址,以便将应用程序指向正确的访问位置。注意,每次你关闭你的虚拟机和重启外部 IP 都会改变。你可以向谷歌申请创建一个“静态 IP ”,或者在重新连接时确保重新复制和粘贴。

作者图片

此外,请确保在连接前选择“配置”并选择“使用密码验证”选项。

现在是我们期待已久的时刻。点击“连接”并输入您的用户名和密码。一旦你完成了 NoMachine 和 Ubuntu 的设置问题,你应该会看到你新创建的桌面。

作者图片

从这里开始,我们将像对待任何桌面环境一样对待我们的桌面。Ubuntu 桌面包括一个终端,我们可以启动它来运行命令行提示。要找到它,点击“显示应用程序”按钮,然后在搜索框中输入“终端”打开终端应用程序。

作者图片

打开后,我们将使用以下命令将 Miniconda 安装程序下载到新创建的目录(/miniconda3)中:

mkdir -p ~/miniconda3
wget [https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh](https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh) -O ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm -rf ~/miniconda3/miniconda.sh
~/miniconda3/bin/conda init bash

上面的代码取自这里的,如果需要关于代码做什么的额外解释。

步骤 6:数据科学环境

完成上述命令后,Miniconda 会要求您关闭然后重新打开终端。执行此操作后,您将看到一个“(base)”描述符出现在命令行上终端屏幕的左侧。这告诉您现在正在使用 Anaconda 环境,您可以自由地使用常见的命令,比如包安装(conda 或 pip)。要停用 conda 环境,只需输入“conda 停用”或“conda 激活”即可重新激活。

让我们安装一个 IDE (Spyder)和一个特定的包来用 Python 访问我们的 Google 云存储桶。

conda install spyder
pip install gcsfs
pip install pandas

安装完软件包后,在终端中键入“spyder”来启动 Spyder IDE。在下图中,我添加了一些代码来创建一个 dataframe,将它作为一个. csv 文件保存到我们的存储桶中,然后删除它。

作者图片

import gcsfs
import pandas as pddf = pd.DataFrame({'Name':['Eddie','Jeff','Stone','Matt','Mike'], 'Inst':['Vocal','Bass','Guitar','Drums','Guitar']})fs = gcsfs.GCSFileSystem(project='your-project-name')
fs.ls('your-bucket')with fs.open('your-bucket/test.csv','r') as f:df.to_csv(f)fs.rm('your-bucket/test.csv')

仅此而已。现在,您已经使用云服务成功设置了自己的虚拟数据科学环境。

关于上面的设置,最后一个警告。我们的引导磁盘只有 100 GBs,对于像 Pandas 这样的大型 Python 数据科学库来说,这实在是小得可怜。实际上,您更可能希望使用更大的引导磁盘(500 GB 或更大)来支持您的实验。只要你记得在完成后停止并删除你的实例,你就能有效地控制成本。

结论

同样,这种方法的核心优势是用户控制,因此这是一种利用云服务处理超过笔记本电脑需求的大型数据科学工作负载的好方法,其成本只是外出购买新笔记本电脑的一小部分。

此外,初创公司可以避免与更多托管解决方案相关的成本不确定性,还可以利用按需提供自己的虚拟机实例的灵活性。

比如参与学习数据科学、职业发展或糟糕的商业决策?加入我。

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

GCP 设置

1.创建虚拟机实例
-更改实例类型
-更改引导磁盘
-更改对 API 的访问
-创建后复制外部 IP

2.转到防火墙
-添加 allow-ingress-from-iap
名称:allow-ingress-from-iap
流量方向:Ingress
目标:网络中的所有实例
源过滤器:IP 范围
源 IP 范围:35.235.240.0/20
协议和端口:选择 TCP 并输入 22,3389,4000 以允许 RDP 和 SSH 以及 nomachine。

-添加笔记本电脑到虚拟机
流量方向:入口
目标:网络中的所有实例
源过滤器:IP 范围
源 IP 范围:您的 IPv4
协议和端口:选择 TCP 并输入 22,3389,4000 以允许 RDP、SSH 和 nomachine。

3.为桌面设置虚拟机

  • SSH 到虚拟机

sudo apt-get 更新
sudo apt-get 升级-y

sudo adduser 用户名

安装 ubuntu 桌面

https://www.nomachine.com/free/linux/64/deb-O nomachine . deb

sudo dpkg -i ./nomachine.deb

-在虚拟机上配置系统 SSHD,以启用基于密码的身份验证。

编辑/etc/ssh/sshd_config,将“PasswordAuthentication”行从“No”更改为“Yes”。

sudo vim/etc/ssh/sshd _ config
-按 I 然后回车
-从否变为是
-按 esc 然后:wq

保存更改。

返回 GCP 仪表板,停止并启动您的虚拟机。

等到它重新启动

4.在本地打开 no machine
-添加
-配置使用 pw 认证
-连接

5.安装

-miniconda
mkdir-p ~/miniconda 3
wgethttps://repo . anaconda . com/miniconda/miniconda 3-latest-Linux-x86 _ 64 . sh-O ~/miniconda 3/miniconda . sh
bash ~/miniconda 3/miniconda . sh-b-u-p ~/miniconda 3
RM-RF ~/miniconda 3/miniconda . sh
~/miniconda 3/bin/

  • anaconda
    CD/tmp
    curl-Ohttps://repo . anaconda . com/archive/anaconda 3-2021.05-Linux-x86 _ 64 . sh
  • bash anaconda 3–2021.05-Linux-x86 _ 64 . sh

6.设置 Google 云存储

-简单地设置一个桶并阻止公共访问

7.根据需要返回桌面
安装库

聪明得吓人:一位前谷歌高管对人工智能风险的看法

原文:https://towardsdatascience.com/scary-smart-a-former-google-execs-perspective-on-ai-risk-277bd89549a6

播客

聪明得吓人:一位前谷歌高管对人工智能风险的看法

莫对 AGI 及其潜力和安全风险的看法

苹果 | 谷歌 | SPOTIFY | 其他

编者按:TDS 播客由杰雷米·哈里斯主持,他是人工智能安全初创公司墨丘利的联合创始人。每周,Jeremie 都会与该领域前沿的研究人员和商业领袖聊天,以解开围绕数据科学、机器学习和人工智能的最紧迫问题。

如果你在 2021 年 9 月下旬浏览你的新闻提要,你可能会看到伦敦《泰晤士报》的这个引人注目的标题,上面写道:“这个人能从人工智能中拯救世界吗?”

https://www.thetimes.co.uk/article/can-this-man-save-the-world-from-artificial-intelligence-329dd6zvd

这名男子名叫莫·格达特(Mo Gawdat),是一名企业家和高级技术高管,在谷歌的半秘密研究机构 GoogleX(现名为 X Development)担任了几年的首席商务官,该公司对无人驾驶汽车、飞行器和地热能等登月项目进行了实验。在 X,莫接触到了许多领域的绝对前沿——人工智能就是其中之一。他看到人工智能系统学习并与世界互动的经历给他敲响了警钟——如果我们现在不采取行动,人工智能系统可能会以灾难性的失败模式告终。

莫在他的新书中写了他作为世界上最秘密的研究实验室之一的内部人员的经历,以及这种经历如何导致他担心人工智能的风险,但也谈到了人工智能的前景和潜力,【可怕的智能:人工智能的未来以及你如何才能拯救我们的世界】。在这一集的 TDS 播客中,他和我一起谈论了这个话题。

以下是我在对话中最喜欢的一些观点:

  • 在过去的几十年里,人工智能的进步是指数级的(或者如果你根据计算曲线来衡量的话,进步会超过指数级)。人类真的不擅长推断指数趋势,这可能会让我们措手不及。这部分是因为指数级的进步可以如此之快地改变世界,以至于几乎不可能做出预测。在指数动力学的推动下,一个单一的 COVID 案件在几周内变成了全国范围的封锁,而人工智能这样一个曾经可爱而可忽略的工具成为了一项革命性的技术,其发展可能会塑造宇宙的未来。
  • 人工智能指数级进步背后的核心驱动力之一是一个经济反馈循环:公司已经知道他们可以可靠地投资人工智能研究,并获得正投资回报。许多人选择将这些回报投入到人工智能中,这进一步放大了人工智能的能力,导致了良性循环。最近的发展趋势似乎表明,人工智能已经达到了一种经济逃逸速度,投资于人工智能研究的边际美元的回报足够大,科技高管再也不能忽视它们了——在莫看来,所有这些都使得 AGI 不可避免。
  • 不管 AGI 是像雷·库兹韦尔预测的那样在 2029 年发展起来,还是像《开放慈善事业》杂志的所说的那样晚一些,这都无关紧要。无论如何,人工人类水平或一般智能(定义模糊!)似乎有望在本世纪末出现。莫认为,人工智能安全和人工智能政策不是我们作为一个物种最优先考虑的事情是一个巨大的错误。在这一点上,我当然同意他的观点。
  • 莫不相信人工智能控制问题(有时被称为对准问题)能够解决。他认为比人工智能系统智能低几个数量级的有机体不可能对它们施加任何有意义的控制。
  • 他的解决方案不同寻常:他认为,人类需要改变他们的在线行为,在社交媒体上以更多的宽容和礼貌来对待彼此。这一战略背后的想法是,希望随着人工智能系统在人类生成的社交媒体内容上接受训练,它们将学会模仿更良性的行为,并对我们构成更小的威胁。我承认对这种观点持怀疑态度,因为我看不出它如何解决人工智能系统的一些核心特征,这些特征使对齐变得如此困难(例如,寻求权力和工具收敛,或目标规范的挑战)。也就是说,我认为关于人工智能安全的更广泛的对话有很大的空间,我很高兴莫在这个重要问题上发出了光芒。

你可以在这里关注莫,或者在这里关注我。

章节:

  • 0:00 介绍
  • 二点莫的背景
  • 7:45 GoogleX 项目
  • 14:20 投资回报
  • 21:40 不创建另一台机器
  • 28:00 AI 作为嵌入式代理
  • 41:35 改变人类行为
  • 53:35 目标和权力追求
  • 58:45 总结

用 GitHub 动作安排笔记本和脚本运行

原文:https://towardsdatascience.com/scheduling-notebook-and-script-runs-with-github-actions-cc60f3ac17f2

使用 GitHub 操作来自动化工作流程,并从脚本和笔记本中运行和更新结果

在 Unsplash 上由尹新荣拍摄的照片

假设我们已经对定期更新的数据流进行了一些很酷的数据分析,例如体育统计数据或当前天气状况。现在,我们将代码添加到 GitHub 上的版本控制中,但是如果我们可以用更新的数据更新它而不必再次运行它,那将会非常酷。一个解决方案是使用 Flask 这样的框架创建一个 web 应用程序(我以前写过一篇文章,这里有一个基本的例子),但是如果我们想要一个更简单的、只需要很少额外编码的东西呢?我们可以使用 GitHub 动作来定期运行我们的脚本,并更新输出和绘图来完成这项工作。

我将通过编写一个简单的 Jupyter 笔记本来演示我们如何做到这一点,这个笔记本使用由meta weather【1】提供的免费 API 来获取城市列表中的当前天气。我们将把它设置为每 3 小时运行一次,并给我们的图添加点,这样,随着时间的推移,我们将开始构建天气趋势。所以,让我们开始吧!

设置虚拟环境

当我们的笔记本按计划运行时,它将在虚拟机上完成,因此我们需要确保我们在本地计算机和云机器上都有一致的开发环境。我们首先为这个项目创建一个新的虚拟环境(我把我的虚拟环境放在一个文件夹~/venvs中,但是你可以选择任何你想要的文件夹,包括项目文件夹本身)。打开您的终端并运行以下命令:

**>** python3 -m venv ~/venvs/gh-actions
**>** source ~/venvs/gh-actions/bin/activate

您现在应该看到(gh-actions)出现在您终端的提示符之前,表明您在虚拟环境中。要脱离这个环境,只需输入命令deactivate

这是一个干净的 Python 环境,没有安装依赖项,您可以通过运行pip freeze来确认。您应该看不到输出,因为您没有安装软件包。

对于我们的笔记本,我们将使用一个名为requests的库来获取数据。在收到我们的 API 响应后,我们将使用pandas来管理我们的数据,并用matplotlib来绘制它。此外,我们显然需要jupyter。因此,让我们按如下方式安装我们的依赖项:

**(gh-actions) >** pip install --upgrade pip
**(gh-actions) >** pip install requests pandas matplotlib jupyter jupyterlab

为了捕获最终运行我们笔记本的虚拟机所需的所有依赖关系,我们需要创建一个requirements.txt文件,用于复制我们的本地环境。

**(gh-actions) >** pip freeze > requirements.txt

您现在应该有一个名为requirements.txt的文件,它列出了安装在您的虚拟环境中的所有包及其版本,GitHub Actions 稍后可以使用它们。

好了,既然这已经不碍事了,让我们继续写一些代码吧!

获取天气数据

我们将使用 MetaWeather API [1]来查询城市列表的当前天气——在本例中,我们将选择旧金山、首尔、钦奈和开普敦。为此,我们必须首先导入相关的库:

**# Import Packages**
import requests

我们需要一个 WOE(究竟在哪里)ID 来查询我们各个城市的天气。让我们首先用所有 WOE IDs 的None值初始化一个字典,我们接下来将查询它:

**# Initialize dictionary of cities**
cities = {"San Francisco": None,"Seoul": None,"Chennai": None,"Cape Town": None
}

现在,我们可以向 API 发出查询来获取城市 id。我们有了基本端点 URL,并用requests包发出请求,并用.json()将响应转换成字典。为了让我们的查询工作,我们必须将城市全部改为小写,并用+替换空格,我们在下面也这样做了。响应是一个字典列表——我们将从列表中的第一个元素开始索引woeid键-值对,以获得每个城市的 WOE ID。

**# Endpoint to query for IDs** BASE_URL_LOCATION = "[https://www.metaweather.com/api/location/search/?query=](https://www.metaweather.com/api/location/search/?query=)"**# Query for WOE ID values** for city in cities.keys():payload = requests.get(BASE_URL_LOCATION + city.lower().replace(" ", "+")).json()cities[city] = payload[0]["woeid"]>> cities{'San Francisco': 2487956,'Seoul': 1132599,'Chennai': 2295424,'Cape Town': 1591691}

现在我们已经有了所有城市的 WOE IDs,我们可以继续向 API 请求使用这些 ID 值来获取天气。返回的有效载荷是未来几天的天气预报,第一个是今天的天气预报,全部包含在键值对consolidated_weather中。从这里,我们想要提取三个值created(天气预报的时间)the_temp(当前温度)和weather_state_name(当前天气状态——例如,多云、晴朗等。).然后,我们将数据存储为一个字典列表,接下来我们可以很容易地将其转换为一个pandas数据帧。

**# Endpoint to query for weather** BASE_URL_WEATHER = "[https://www.metaweather.com/api/location/](https://www.metaweather.com/api/location/)"**# Query weather data**curr_weather = []for city, woe_id in cities.items():payload = requests.get(BASE_URL_WEATHER + str(woe_id)).json()curr_weather.append({"time_utc": payload["consolidated_weather"][0]["created"],"location": city,"temperature_c": payload["consolidated_weather"][0]["the_temp"],"weather_state": payload["consolidated_weather"][0]["weather_state_name"]})

现在,让我们看看我们刚刚查询的数据:

pd.DataFrame(curr_weather)

作者图片

向文件追加数据

我们将把我们的每个天气点存储在同一个目录下的一个.csv文件中,我们将使用pandas来操作它。我们将添加一些代码来打开当前的.csv文件,添加新记录并保存新的.csv。为了确保我们的代码在第一次运行时工作,我们将添加一个try/except,这样它就不会抛出异常。此外,我们将在保存文件之前删除重复的行。

**# Import pandas** import pandas as pd**# Add entry to CSV file**
try:df = pd.read_csv("weather_locations.csv")df = df.append(pd.DataFrame(curr_weather))
except Exception:# Create DataFrame on first rundf = pd.DataFrame(curr_weather)**# Drop duplicate rows**
df = df.drop_duplicates()**# Save new CSV** df.to_csv("weather_locations.csv", index=False)

动态加载字体

由于我们将在虚拟机上渲染我们的绘图,我们也不知道默认缓存中将会有什么字体。幸运的是,我们实际上可以从 TTF 文件中动态加载字体。在这种情况下,我从 Google Fonts 下载了字体 Lato,并将文件Lato-Regular.ttf放在同一个工作目录下一个名为fonts/的文件夹中。现在,要将字体直接从 TTF 文件添加到目录中,我们需要以下代码:

**# Import matplotlib font manager** import matplotlib.font_manager as fm**# Dynamically load font** font_path = "./fonts/Lato-Regular.ttf"fm.fontManager.addfont(font_path)
fm.FontProperties(fname=font_path)

标绘结果

现在我们已经加载了数据源和字体,我们可以继续绘制结果了。我之前已经写了一篇文章详细描述了一些基础知识,所以我将跳过一些解释,直接进入我们将用来产生我们的图的代码。我们利用transforms在绘图的最后一个点之后添加城市名称,首先转换为像素,添加 40 像素的横向填充,然后转换回数据坐标。

**# Plot Parameters**
plt.rcParams["font.family"] = "Lato"
plt.rcParams["font.size"] = 16
plt.rcParams["axes.linewidth"] = 2
plt.rcParams["xtick.major.size"] = 0
plt.rcParams["xtick.major.pad"] = 10
plt.rcParams["ytick.major.size"] = 0
plt.rcParams["ytick.major.pad"] = 10**# Colors**
colors = {"San Francisco": "#363b6e","Seoul": "#cd2e3a","Chennai": "#ff9933","Cape Town": "#007749"
}**# Create figure and axis**
fig = plt.figure(figsize=(15, 10), dpi=300, facecolor="white")
ax = fig.add_subplot(111)
ax.grid(color="#d3d3d3")
ax.spines["top"].set_visible(False)
ax.spines["left"].set_visible(False)
ax.spines["right"].set_visible(False)**# Load DataFrame** df = pd.read_csv("weather_locations.csv")**# Convert date column to datetime** df.time_utc = df.time_utc.apply(lambda t: pd.to_datetime(str(t)))**# Sort values by time** df = df.sort_values("time_utc")**# Convert data to pixels** DC_to_FC = ax.transData.transform
FC_to_DC = ax.transData.inverted().transform**# Plot Data** for city in cities.keys():df_temp = (df[df["location"] == city].reset_index(drop=True).copy()) ax.plot(mdates.date2num(df_temp["time_utc"]),  df_temp["temperature_c"], color=colors[city],lw=2, markevery=[-1], marker="o", ms=10, mew=2, mfc="white")**# Add labels**
for city in cities.keys():df_temp = (df[df["location"] == city].reset_index(drop=True).copy())coords_original = [mdates.date2num(df_temp.iloc[-1].time_utc),  df_temp.iloc[-1].temperature_c]coords_transformed = DC_to_FC(coords_original)**# Pad 40 pixels between last point and label**coords_transformed[0] += 40coords_new = FC_to_DC(coords_transformed)ax.text(coords_new[0], coords_new[1], city, ha="left", va="center", color=colors[city])**# Tick Label Format**
ax.xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))**# Axis Labels**
ax.set_xlabel("Date", labelpad=10, size=20)
ax.set_ylabel("Temperature (˚C)", labelpad=10, size=20)**# Axis Limits**
ax.set_ylim(min(df.temperature_c.round(0)) - 5, max(df.temperature_c.round(0) + 5)
)plt.savefig("weather_locations.png", dpi=300, bbox_inches="tight")
plt.show()

作者图片

我已经运行了几次,以生成一些初始数据,但还没有很多点。然而,久而久之,随着收集的数据越来越多,这个图表会慢慢变得完整。

现在,最重要的部分——自动运行这个笔记本和上传新的情节!

设置 GitHub 动作

要设置笔记本的自动运行,我们必须使用 YAML 文件定义一个工作流,这是一种可读性很强的标记语言。我们首先从我们的的基础层创建文件/.github/workflows/update-plot.yml

GitHub Repo
|
+-- .github
|   |
|   +-- workflows
|       |
|       +-- update-plot.yml
|
+-- Project Files/Folders

我们需要做的第一件事是为我们的工作流命名,在我们将它添加到 repo 后,它将出现在 GitHub 的 UI 中,并添加我们希望它运行的时间表,我们将每 3 小时这样做一次,从午夜开始。

name: Update Weather Locations Ploton:schedule:- cron: '0 0-21/3 * * *'workflow_dispatch:

时间表是用一个cron表达式表示的,你可以通过这个链接了解更多,但它基本上是说每 12 小时在第 0 分钟运行。运行的时间将是 UTC,所以在创建您的cron表达式时请记住这一点。此外,添加workflow_dispatch可以让你随时从 GitHub UI 手动运行工作流。

现在,我们需要列出需要在我们的工作流中运行的具体任务。我们首先将所有这些步骤放入一个名为update_plot的整体作业中,该作业将在最新版本的 Ubuntu 上运行:

jobs:update_plot:name: Update plot with location weather dataruns-on: ubuntu-latest

我们现在将定义我们工作中的不同步骤。我们必须做的第一件事是检查我们的存储库,这可以通过一个名为actions/checkout@v2的内置动作来完成。

steps:- name: Checkoutuses: actions/checkout@v2

接下来,我们必须在 Ubuntu 虚拟机上设置 Python,这可以使用一个名为actions/setup-python@v2的内置动作来完成。我们将使用 Python 3.7,并将pip设置为缓存依赖关系的缓存,以便更快地进行后续设置。

- name: Setup Pythonuses: actions/setup-python@v2with:python-version: '3.7'cache: 'pip'

现在,我们安装来自requirements.txt的依赖项

- name: Install Dependenciesrun: pip install -r requirements.txt

为了运行我们的笔记本,我们将首先使用jupyter nbconvert将其转换成一个脚本,然后使用 Python 直接运行该脚本。这些命令的结果应该是更新的weather_extremes.csvweather_extremes.png

- name: Run Script and Update Plotrun: |jupyter nbconvert --to script weather_locations.ipynbpython weather_locations.py

最后,我们需要提交并把对上面两个文件的更改推送到存储库,这非常像我们在本地计算机上做的那样。

- name: Commit and Push Changesrun: |git config --local user.email "actions@github.com"git config --local user.name "GitHub Actions"git add weather_locations.csv weather_locations.pnggit commit -m "Updated plot on `date` with GitHub Actions"git push origin master

将所有这些放在一起,我们完成的 YAML 文件将如下所示:

name: Update Weather Locations Ploton:schedule:- cron: '0 0-21/3 * * *'workflow_dispatch:jobs:update_plot:name: Update plot with new extreme weather dataruns-on: ubuntu-lateststeps:- name: Checkoutuses: actions/checkout@v2 - name: Setup Pythonuses: actions/setup-python@v2with:python-version: '3.7'cache: 'pip' - name: Install Dependenciesrun: pip install -r requirements.txt - name: Run Script and Update Plotrun: |jupyter nbconvert --to script weather_locations.ipynbpython weather_locations.py - name: Commit and Push Changesrun: |git config --local user.email "actions@github.com"git config --local user.name "GitHub Actions"git add weather_locations.csv weather_locations.pnggit commit -m "Updated plot on `date` with GitHub Actions"git push origin master

一旦您将 YAML 文件提交并推送到 GitHub,您现在应该能够转到 GitHub Repo 上的Actions选项卡,并且能够看到您刚刚创建的工作流!

作者图片

由于我们将workflow_dispatch添加到了我们的工作流中,如果您愿意,您应该可以选择现在手动运行更新。否则,请高枕无忧,让您的文件每天自动更新两次!通过将情节放入您的README中,您还可以在每次访问存储库时看到变化。

结论

感谢您阅读本教程,学习如何使用 GitHub 操作来自动运行您的笔记本和脚本!本文中的所有代码都可以在这个 Github 资源库中获得。

感谢您的阅读!我感谢任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系以获取更多更新和文章。

参考文献

[1]https://www.metaweather.com/api/

熊猫数据框架的模式规范

原文:https://towardsdatascience.com/schema-specification-for-your-pandas-dataframes-c8b34d1eb37d

typedframe 简介—一种为数据帧编写模式以用于文档和运行时验证的简单方法

Pandas 是一个很好的工具,但是它是为现场编码实验而设计的,并且它引入了许多关于使用中的数据的隐含假设。这些假设分散在整个代码库中。只要违反了其中的任何一条,系统就会失败,并出现难以调试的错误。

为了解决这个问题,前段时间我写了typed frame——一个轻量级的库,它允许你显式地记录和验证关于熊猫数据帧的假设。

如果你不喜欢拐弯抹角,请随时查看下面的链接:

  • 文档
  • GitHub 资源库

作者图片

问题 1: 看你的一个同事写的函数,你不知道它期望什么作为输入,返回什么作为输出。

这个问题在动态类型语言中很常见。在强类型语言中,函数签名已经是穷人的函数文档了。在 Python 或 Javascript 中,您所拥有的只是参数的数量及其名称。但是让我们假设你的团队有高水平的工程文化,你在你的代码库中使用类型提示,甚至可能使用静态类型检查器。对于熊猫数据框,即使这种做法也帮不了你多少。您仍然注定要深入函数逻辑,找出作为参数传递或作为输出返回的数据帧的确切格式。

问题 2: 你为对方团队生产数据,却不知道他们的数据契约。

假设您正在实现一个生产者服务(可能是 ETL 或 ML 管道中的一个步骤),而由另一个团队开发的消费者服务已经启动并运行,正在等待您的数据。为了成功集成这两个组件,您需要知道消费者期望的数据格式。通常,找到答案的唯一方法是与团队中的某个人交谈。我见过这样的情况,我们不得不在团队中创建临时聊天,其中两个团队同步他们的数据合约。我见过这样的情况,甚至组件作者都很难弄清楚他们组件的确切数据契约。

问题 3: 一个管道在你的数据上工作得很好,但是当发布到生产中时,它不断地失败,出现各种难以调试的错误。

您已经在验证数据集上使用推理 ML 管道一段时间了,一切都运行良好。但是实时生产数据不断引入新的不可预料的可变性,每次数据中出现新的异常时,您都要花费大量时间进行调试。

熊猫的问题

谈到实时交互编码,Pandas 是一个很好的工具。它是专门为它设计的。它不是为生产系统而构建的。但是很多时候,熊猫代码变得可重用,并被移植到那里。数据科学家和分析师在处理表格数据时大量使用熊猫。然后在移交给工程团队的过程中,将 pandas 的逻辑重写为其他东西通常是不可行的。因此,工程师们通过微小的重构将其复制到生产代码库中。

但是熊猫给生产带来了很多问题。在我看来,它们中的大部分来自于数据帧是一种开放数据类型这一事实。数据类型本身概括了内部的基本数据格式,没有固定的规范。两个数据帧可以代表完全不同的东西。关于具体数据框架布局的假设在许多方面是隐含的。

让我们看一个过于简化的预处理代码,如下所示:

这里有什么问题?

即使我们在函数中添加了类型提示,用户仍然不知道如何使用它。他必须挖掘函数的内部逻辑,找出关于输入和输出的所有假设。它违反了核心软件开发原则之一——封装。

这些假设是什么?

必需的列及其数据类型

sensory _ datadata frame 必须有一个 col1 列*,*,该列必须是数字数据类型。

索引名称和类型

DataFrame 应具有不带名称的日期时间索引。

分类列

根据 sensory_datareportsdata frames中的 alarm_category 是否具有完全相同的类别集,上述结果会有所不同。

尽管我们的示例管道简单得不切实际,但上述所有场景都可能导致各种极易发生的错误。

同时,这些错误可能很难调试。因为实际的错误通常发生在离根本原因非常远的地方——根本原因是违反一些假设的数据。

考虑到这些问题,不久前我在 pandas 数据框架上制作了一个轻量级包装器,并将其打包成一个库。在过去的几年里,我们已经在多家公司的几个项目中使用了这个库,它已经被证明是我们的数据科学家和 ML 工程师的一个有用的工具。

typedframe

极简主义是图书馆的主要设计目标。它应该提供最少的功能,而不会给用户带来额外的代码和复杂性。

作者图片

typedframe 引入了类型化数据帧的单一概念。一个类型化的数据框架是在你的熊猫数据框架之上的一个极简的包装。通过子类化一个类型数据框架并指定模式静态变量来创建它。然后,您可以通过将它传递给类型化的 DataFrame 构造函数,将您的 DataFrame 包装在其中。构造函数将进行运行时模式验证,您可以通过包装器的 df 属性访问原始数据帧。

这个包装器有两个用途:

  • 数据框架假设的正式文件。您可以使用您的类型化数据框架模式定义作为一种文档形式,与他人交流您的数据接口。这种方法与 Python 类型提示结合起来非常有效。
  • ***运行时模式验证。*如果您使用这种类型化的数据帧来保护您的管道,您将能够及早发现错误——更接近根本原因。如果违反了任何数据契约,您将得到一个解释确切原因的异常。

作者图片

让我们看看如何用 typedframe 库改进上面的代码。

快速入门示例

安装库:

pip 安装型框架

为输入和输出定义三个模式类:

并修改代码以使用这些模式定义:

并将函数调用代码更改为:

如您所见,我们可以指定哪些列是必需的,以及它们期望具有什么类型。对于分类列,我们显式指定所有可能的类别。我们可以为索引定义预期的模式。我们可以继承我们的模式规范以避免代码重复。

我们已经从使用数据帧切换到了上面在函数接口中定义的类。所以现在,在将数据帧传递给预处理函数之前,需要将它们“包装”在这些类中。这是运行时验证发生的地方。该函数的用户可以看到函数的输入和输出。

使用类型化数据帧的最佳实践

在您的代码库中,使用类型化数据帧包装器的最佳位置是什么?

我们在几个项目中使用 typedframe 库的经验表明,在以下场景中使用它是最合理的:

团队边框

类型化数据帧有助于在团队之间建立数据契约。它们也有助于在早期发现由沟通错误或不一致的系统演化所导致的错误。每当一些数据集在团队之间传递时,用它的规范定义一个类型化的 DataFrame 类是有意义的。

公共函数和方法

类型化数据框架与类型提示结合使用效果很好。因此,一个公共函数或方法,作为一个参数/返回一些熊猫数据帧,是一个很好的使用它的地方。

数据管道的源和汇

在数据管道的开始和结束时提供模式定义和运行时验证是一个很好的实践。即,在从外部存储器读取之后和写入之前,这里也可以使用类型化数据帧。

关于我

人工智能是我的激情所在。除此之外,我还对构建和理解复杂系统、管理知识和人员以共同实现新的宏伟目标感兴趣。我相信全球化,相信智慧和协作会战胜热力学第二定律:)

我正在努力提高我的写作技巧,与你分享我的想法或我学到的东西。

如果你发现我们有共同的兴趣,请不要犹豫在这里或在推特、 Instagram 或 LinkedIn 上联系。

使用变形金刚进行深度学习的科学文档相似性搜索(SciBERT)

原文:https://towardsdatascience.com/scientific-documents-similarity-search-with-deep-learning-using-transformers-scibert-d47c4e501590

这篇文章是一个全面的概述,为具有 k-NN 和余弦相似性的文档构建一个语义相似性搜索工具

Maksym Kaharlytskyi 在 Unsplash 上的照片

介绍

当阅读一篇有趣的文章时,您可能希望从大量数据中找到相似的文章。手动处理显然不是我们应该采取的策略。那么,为什么不利用人工智能的力量来解决这类问题呢?从这篇文章中,你将能够使用 SciBERT 和两种不同的相似性方法(余弦和 k-NN)来找到与你的特定查询在意义上最相似的科学文章。

注意:嵌入向量 将在整篇文章中互换使用,表示同一件事。

下面的工作流程给出了构建我们的工具的所有步骤,从数据提取到推荐类似的文章。

正在解决的解决方案的一般工作流程(图片由作者提供)

关于数据

  • 这是 CORD-19 数据集,包含超过 59,000 篇学术文章,包括超过 48,000 篇关于新冠肺炎、新型冠状病毒和相关冠状病毒的全文。
  • 这些数据由白宫和一个领先的研究团体联盟免费提供,以帮助全球研究产生见解,支持正在进行的抗击这种传染病的斗争。
  • 它可以从 Kaggle 的页面下载。
  • 关于数据集的更多细节可在此页面中找到。

在继续下一步之前,重要的是考虑导入以下对项目成功至关重要的库。

有用 _libs.py

收集数据

数据从 Kaggle 下载并保存在一个名为 input 的文件夹中。 使用 shape 函数我们得到(47110,16),意思是它包含 47110 篇文章,每篇有 16 列。

load_data_scibert.py

16 个专栏——但哪一个最重要?

以下是关于数据中缺失信息百分比的一些详细信息。

关注抽象列的数据中缺失值的百分比(图片由作者提供)

为了简单起见,我们将把我们的分析集中在摘要列,它也是 0%缺失数据的列。但是您可以使用其他文本列,比如body _ text;由你来决定。此外,为了加快处理速度,我们将使用 2000 个观察值的子集。

数据中的文章摘要

让我们看看一些随机的文章。这里我们将打印限制在前 100 个单词,因为有些单词很长。

show_random_articles.py

三篇随机文章的数据摘要(作者图片)

数据处理和矢量化

这一步旨在对文章的摘要文本进行矢量化,以便我们可以执行相似性分析。因为我们处理的是科学文档,所以我们将使用 SciBERT,这是一种用于科学文本数据的预训练语言模型。你可以在语义学者上找到更多关于它的信息。

这一部分涉及的主要步骤是:

加载模型工件

加载预训练的模型和标记器。在加载模型时,我们需要将 输出 _ 隐藏 _ 状态 设置为,这样我们就可以提取嵌入了。

load _ 模型 _ 工件. py

将文本数据转换为嵌入内容

这个函数convert _ single _ abstract _ to _ embedding大多是受 Chris McCormick 的 BERT Wordembedding 教程的启发。它旨在使用预先训练的模型为给定的文本数据创建嵌入。

嵌入 _from_text.py

对单个文本数据进行测试

这里我们在第 30 篇文章上测试函数。你可以选择任何你想要的数字,只要它存在于数据中。

测试 _ 嵌入. py

第 6 行 显示嵌入形状:(768,)。这意味着一个向量由 768 个值组成。最后,我们可以使用convert _ overall _ text _ to _ embedding函数将转换过程应用于数据中的所有文章。但是,在此之前,我们将使用get _ min _ valid _ data函数从数据中删除一些列,以便在最终的查询搜索结果中有更少的列。

使用前面的帮助器函数,我们可以创建一个新的列,为每篇文章包含其对应的抽象嵌入。

创建最终版本

带有嵌入列的前 3 行数据(作者提供的图片)

到目前为止,一切顺利!一切终于为相似性搜索设置好了。

相似性搜索

现在,我们可以执行给定的 查询 向量和所有嵌入向量之间的相似性分析。 查询 处理将类似于余弦和 k-NN。下面是负责这个的函数。

流程查询. py

余弦相似性搜索

两个文档嵌入之间的余弦相似性度量这些文档的相似程度,而不考虑这些嵌入的大小。它测量在多维空间中投影的两个向量之间的角度的余弦。

  • 余弦相似度为 1 表示两个文档 100%相似
  • 余弦相似度为 0 意味着两个文档有 0%的相似度

以下函数返回与查询文本相似的前 N 篇文章(N 是要返回的相似文章的数量)。

余弦 _ 建议. py

现在我们可以调用函数来获取前 5 篇最相似的文章。

余弦 _ 结果. py

以下是前一个查询的结果

与查询最相似的前 5 篇文章(作者图片)

为了更好地理解,我们可以只看前两篇最相似的文章。

下面的查询正文下面的

从原始数据帧中查询文本数据

最相似的两篇文章来自前面的 top_articles 数据帧

从推荐的数据框架中摘录最相似的两篇文章(图片由作者提供)

基于 KNN 和 Faiss 的相似性搜索

FAISS 是由脸书人工智能研究所开发的库。根据他们的维基页面:

Faiss 是一个用于高效相似性搜索和密集向量聚类的库。它包含在任意大小的向量集中搜索的算法,直到那些可能不适合 RAM 的向量

下面是使用之前构建的嵌入来构建搜索算法的步骤

  • 创建平面索引。该索引使用 L2(欧几里德)距离度量来测量查询向量和所有向量(嵌入)之间的相似性。
  • 将所有向量添加到索引中
  • 定义我们想要的相似文件的数量
  • 运行相似性搜索以获得结果

faiss_setup.py

我们使用相同的查询文本数据对 k-NN 部分执行搜索。您可以随意将其更改为另一个值。

faiss_run_search.py

  • I 包含所有同类文章的索引
  • D 包含所有相似文章的 L2 距离值。距离越小,文章与查询越相似。

注意:我决定故意分解所有的步骤,以确保你能正确理解它们。但是你可以把所有的东西放在一个函数里。

faiss_show_recommendations.py

与查询最相似的 5 篇文章(图片由作者提供)

观察

  • 第一个文档的 L2 = 0,这意味着 100%相似。这是显而易见的,因为查询是与其自身进行比较的,但是我们可以简单地将其从分析中删除。

结论

在本文中,我们研究了使用 SciBERT 嵌入、余弦和 k-NN 相似性方法实现语义相似性搜索工具的整个过程。同时,我也希望它对你有所帮助!

您可以在下面找到更多资源来进一步学习。在 YouTube 上关注我,了解更多互动会话!

额外资源

GitHub 上的文章源代码

SciBERT:科技文本的预训练语言模型

伯特单词嵌入教程

脸书人工智能研究

再见🏃🏾

Scikit-learn 1.1 附带了一个改进的 OneHotEncoder

原文:https://towardsdatascience.com/scikit-learn-1-1-comes-with-an-improved-onehotencoder-5a1f939da190

一个简单但非常实用的功能

照片由 Unsplash 上的尼克·费因斯拍摄

Scikit-learn 是数据科学生态系统中最常用的 Python 库之一。它作为一个完整的工具,用于从数据预处理到模型评估的机器学习任务。

表格数据集中的要素很少使用,因为它们出现在原始数据中。在用作机器学习模型的输入之前,它们通常需要额外的数据预处理步骤。

OneHotEncoder 就是这些转变的一个例子。它对分类特征进行编码。下图说明了一键编码在分类要素上的工作方式。

(图片由作者提供)

这是一些机器学习算法的必需操作,因为它们期望所有的特征都是数字的。除非我们使用基于树的算法,比如随机森林,否则分类特征需要转换成数字特征。

如上图所示,一键编码为每个类别创建了一列。在分类变量有很多不同值的情况下,我们将有一个非常高维的特征空间。

如果有些类别与其他类别相比出现的次数很少,那么最好将它们分组。为这些类别创建单独的列可能会增加模型的计算和内存负担,而不会提供显著的价值。

Scikit-learn 1.1 附带的新 OneHotEncoder 允许对不常用的类别进行分组。让我们做一个例子来演示它是如何使用的。

在我们开始之前,让我们确保您有正确的版本。

import sklearn
sklearn.__version__
**# output**
'1.1.2'

如果您有 1.1 之前的版本,可以使用 pip 更新它。

pip install --upgrade scikit-learn

让我们创建一个具有两个分类特征的样本数据框架。

import pandas as pddf = pd.DataFrame({ "City": ["Houston"] * 25 + ["Rome"] * 30 + ["Madrid"] * 3 + ["London"] * 2,"Division": ["A"] * 30 + ["B"] * 25 + ["C"] * 1 + ["D"] * 4})df["City"].value_counts()
**# output**
Rome       30
Houston    25
Madrid      3
London      2
Name: City, dtype: int64--------------------------------------
df["Division"].value_counts()
**# output** A    30
B    25
C     1
D     4
Name: Division, dtype: int64

在城市列中,有 3 个马德里和 2 个伦敦值,比其他两个城市少得多。除法列中值的分布也类似。

下一步是对这两个特征进行编码。

from sklearn.preprocessing import OneHotEncoder**# create an encoder and fit the dataframe**
enc = OneHotEncoder(sparse=False).fit(df)
encoded = enc.transform(df)**# convert it to a dataframe**
encoded_df = pd.DataFrame(encoded, columns=enc.get_feature_names_out()
)encoded_df.head()

(图片由作者提供)

因为我们没有对不经常出现的值进行分组,所以编码数据中有 8 列。让我们用分组来尝试一下,这可以使用 min_frequency 参数来完成。出现次数少于指定最小频率的类别将被分组。

**# create an encoder and fit the dataframe**
enc = OneHotEncoder(min_frequency=5, sparse=False).fit(df)
encoded = enc.transform(df)**# convert it to a dataframe**
encoded_df = pd.DataFrame(encoded, columns=enc.get_feature_names_out()
)encoded_df.head()

(图片由作者提供)

我们现在有一个包含 6 个特征的数据框架。当处理具有大量不同值的类别时,这种差异会更加明显。

假设一个特性有 20 个不同的值,95%的值属于 4 个不同的值。剩下的 5%属于 16 个不同值的组合。在这种情况下,有效的策略是将这 16 个值分组到一个组中。

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅https://sonery.medium.com/subscribe如果你想在我发表新文章时收到电子邮件。

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

交叉验证的 Scikit Learn 估计器

原文:https://towardsdatascience.com/scikit-learns-estimator-with-cross-validation-6bca3ce91676

理解常规估计量和 CV 估计量的区别

照片由 Redd 在 Unsplash 拍摄

介绍

Scikit Lean 是最完整的 Python 机器学习库之一。数据科学家在许多项目中使用它,他们中的许多人实际上通过编写或审查代码来帮助项目。这有助于库不断发展,并在编程新模型时使我们的生活更加轻松。

查看 Scikit Learn 的文档,可以看到许多评估者现在都有交叉验证(CV)选项。比如有LogisticRegressionLogisticRegressionCV,还有很多其他的,像LassoCVRidgeCV

这些估值器与常规估值器的不同之处在于,算法中有一个内置的交叉验证参数,帮助您在创建新模型时节省时间。

交互效度分析

交叉验证可以帮助我们数据科学家确保我们的模型在面对新数据时能够很好地推广。我总是喜欢将有监督的机器学习模型与学生准备考试进行比较。学生从教授那里得到内容,然后必须完成一些练习。但是练习不能总是相同的方式。

有时教授会给学生一份数据,要求学生计算缺失的部分。其他时候,学生接收公式和数据来输入和计算。就这样,教授混合了内容提供的方式,所以学生可以概括这个概念。每次收到问题时,只要有不同的数据,学生现在就可以应用获得的公式和知识来解决问题。

交叉验证是一种重采样方法,它使用数据的不同部分在不同的迭代中测试和训练模型。

与学生的类比就像交叉验证。我们是教授,模型是学生,公式和内容是算法。如果我们不断混合数据并将其呈现给模型,它可以进行归纳,一旦收到从未见过的数据进行预测,就有更大的成功机会。

CV 估计量

好了,现在让我们进入这篇文章的核心。让我们来看看如何对带有交叉验证(CV)的估计量进行编码,以及它们的行为。

让我们导入所需的模块。

import pandas as pd
from sklearn.linear_model import LogisticRegression, LogisticRegressionCV
from sklearn.datasets import load_breast_cancer

我选择了逻辑回归估计量来测试它。所以,让我们开始使用那些著名的玩具数据集来进行演示。我们将加载来自 sklearn 的乳腺癌数据进行预测。

(边注:我们会跳过数据清理和探索,所以这篇帖子不会太长。但是我们仍然可以看到评估者在起作用)

#Split explanatory (X) and explained (y)
X, y = load_breast_cancer(return_X_y=True)

首先,我们可以运行常规的LogisticRegression()

# Regular Logistic Regression
log_reg = LogisticRegression().fit(X, y)

我们来看看比分。

log_reg.score(X,y)**[OUT]:
0.9472759226713533**

现在,让我们看看带有 CV 的估计量是如何表现的。代码差别不大。我们将使用超参数 cv=10,将交叉验证折叠的数量添加到训练中。

# Fit the model with CV
log_cv = LogisticRegressionCV(cv=10, random_state=0).fit(X, y)# Score
log_cv.score(X, y)**[OUT]:
0.961335676625659**

在这种情况下,输出提高了 2%。但这是否意味着它会一直那样呢?我们应该总是使用带有 CV 的估计量吗?

简单的答案是否定的。

例如,有时使用交叉验证有助于使模型过度适应训练数据。我能想到的另一个例子是时间问题。根据数据的大小,训练时间可能会随着 CV 而显著增加。

其他时候,如果这是我们在项目中使用的度量标准,这对于提高准确性来说是不够的。让我们看下一个例子。

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

我们将使用 sklearn make_classification创建一个数据集。

# Creating a sample dataset
data = make_classification(n_samples= 5000, n_features= 9,n_classes=2,random_state=42) X = pd.DataFrame(data[0], columns=['V' + str(i) for i in range(1,10)])y= data[1]

我们可以在训练和测试中拆分它。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

现在让我们试着拟合一个逻辑回归。

# Logistic Regression
model = LogisticRegression()# Fit
model.fit(X_train, y_train)#score
model.score(X_test, y_test)**[OUT]:
0.856**

如果我们使用 CV 选项,结果如下。

# Logistic Regression with CV
model_cv = LogisticRegressionCV(cv=10, random_state=42)# Fit
model_cv.fit(X_train, y_train)#score
model_cv.score(X_test, y_test)**[OUT]:
0.856**

同样的结果。准确率 85.6%。

在你走之前

在这篇文章中,我们了解到 sklearn 已经内置了带有交叉验证的估计器。一般来说,需要做的只是在实例化模型时使用超参数cv

有时,结果会改善,有时则不会。对于大型数据集,训练时间也会增加,因此请记住这一点。

如果你喜欢这篇文章,请随时关注我

http://gustavorsantos.medium.com/

如果你正在考虑中等会员资格,这里有一个推荐代码给你。它帮助并激励着我!

参考

https://en.wikipedia.org/wiki/Cross-validation_%28statistics%29 https://stats.stackexchange.com/questions/320154/when-not-to-use-cross-validation https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegressionCV.html#sklearn.linear_model.LogisticRegressionCV

如何使用 Python 和 PDFQuery 从 PDF 文件中抓取数据

原文:https://towardsdatascience.com/scrape-data-from-pdf-files-using-python-and-pdfquery-d033721c3b28

有效地从 PDF 文件中提取数据

作者图片

背景

之前的文章 中,我谈到了如何使用 Python 中的 tabula-pyPandas 从 PDF 文件中的结构化非结构化数据中抓取数据。在本文中,我将介绍一种从 PDF 文件中抓取数据的替代方法: PDFQuery

必需的库

  • PDFQuer y:从 PDF 文件中抓取文本
  • 熊猫:构建和操作我们的面板数据

安装库

pip install pdfquery
pip install pandas

导入库

import pdfquery
import pandas as pd

方法 1:使用文本框坐标抓取 PDF 数据

让我们做一个简单的例子,下面的 PDF 文件包含了非结构化格式的 W2 数据,其中我们没有典型的行列结构。相反,相关信息(如员工的 SSN、姓名、地址、雇主、工资等。)都是以这种 W2 的形式分散的。

作者图片

首先,我们需要将 PDF 转换成可扩展标记语言(XML),其中包含给定 PDF 页面的数据和元数据。

作者图片

pdf = pdfquery.PDFQuery('file.pdf')
pdf.load()
pdf.tree.write('pdfXML.txt', pretty_print = True)

XML 定义了一组规则,用于以人类可读和机器可读的格式对 PDF 进行编码。以下是雇员 SSN 的 XML 片段。它包括数据(987–654–3210)和元数据(例如,文本框坐标、高度、宽度等。)

作者图片

代码片段中文本框内的值[195,735,243,745]是指文本框的“左、下、右、上”坐标。你可以用 X-Y 坐标来思考 pdf 页面。X 轴横跨 PDF 页面的宽度,Y 轴横跨页面的高度。每个元素都有由 4 个坐标组成的边界框定义的边界。这些坐标(X0,Y0,X1,Y1)代表文本框的左侧、底部、右侧和顶部,这将为我们提供我们在 PDF 页面中感兴趣的数据的位置。

作者图片

接下来,使用 XML 文件中的文本框坐标,我们可以使用相应的文本框坐标分别提取每条相关信息,然后将所有收集到的信息合并到单个观察中。下面,我们编写一个函数来使用“pdf . pq(' lttextline horizontal:overlaps _ bbox(" #,#,#,#,# ")”。text()"来提取每个文本框中的数据,然后使用 pandas 来构造一个 dataframe。

def pdfscrape(pdf):# Extract each relevant information individuallyssn              = pdf.pq('LTTextLineHorizontal:overlaps_bbox("195, 735,  243, 745")').text()employer_name    = pdf.pq('LTTextLineHorizontal:overlaps_bbox("48,  686,  300, 696")').text()employer_address = pdf.pq('LTTextLineHorizontal:overlaps_bbox("48,  649,  300, 684")').text()first_name       = pdf.pq('LTTextLineHorizontal:overlaps_bbox("48,  590,  150, 601")').text()last_name        = pdf.pq('LTTextLineHorizontal:overlaps_bbox("175, 590,  280, 601")').text()employee_address = pdf.pq('LTTextLineHorizontal:overlaps_bbox("48,  543,  260, 577")').text()medicare_wage_tip= pdf.pq('LTTextLineHorizontal:overlaps_bbox("370, 662,  430, 672")').text()
# Combined all relevant information into single observationpage = pd.DataFrame({'ssn': ssn,'employer_name': employer_name,'employer_address': employer_address,'first_name': first_name,'last_name': last_name,'employee_address': employee_address,'medicare_wage_tip': medicare_wage_tip}, index=[0])return(page)

作者图片

如果后续页面中的信息以类似的方式显示,我们可以使用 for-loop 自动完成这个过程。在下面的代码中,我们可以使用“pdf.doc.catalog['Pages']得到页数。resolve()['Count']”。要从特定页面提取数据,我们可以使用“pdf.load(#)”。

pagecount = pdf.doc.catalog['Pages'].resolve()['Count']master = pd.DataFrame()
for p in range(pagecount):pdf.load(p)page = pdfscrape(pdf) master = master.append(page, ignore_index=True)master.to_csv('output.csv', index = False)

方法 2:使用邻近的关键字抓取 PDF 数据

另一种提取数据的方法是找到相邻关键字的坐标。更直观的方法是寻找我们感兴趣的关键词,然后提取与关键词相关的数据。

在 PDFQuery 中,我们可以使用“pdf . pq(' lttextline horizontal:contains(" ")。format("keyword "))"来定位关键字。然后用“keyword.get('x0|y0|x1|y1 ',0)”提取关键字的“左、下、右、上”坐标。一旦我们有了关键字的坐标,我们就可以通过增加或减少坐标中的值来移动文本框。例如,在 PDF 页面中,“987–654–3210”在关键字“社会安全号码”下,我们可以将 y0 和 y1 减去某个值,表示 10,以将文本框下移。在实践中,你将通过反复试验来学习使用什么值。最后,我们可以使用“pdf . pq(' lttextline horizontal:overlaps _ bbox(" #,#,#,# ")”。text()"来提取与关键字相关联的数据。

keyword =  pdf.pq('LTTextLineHorizontal:contains("{}")'.format("social security number"))[0] 
x0 = float(keyword.get('x0',0)) 
y0 = float(keyword.get('y0',0)) - 10
x1 = float(keyword.get('x1',0)) 
y1 = float(keyword.get('y1',0)) - 10
ssn = pdf.pq('LTTextLineHorizontal:overlaps_bbox("%s, %s, %s, %s")' % (x0, y0, x1, y1)).text()

光学字符识别

OCR(光学字符识别)是一种将图像转换为机器编码文本的过程,它允许计算机解释文件的文本,以便可以搜索、复制和擦除文本。

有时,如果您打开 PDF 并且无法选择文本,可能是因为 PDF 没有经过 ocr。如果一个 PDF 不是 OCRed,我们将需要在 Adobe Acrobat 中做一些额外的步骤来为 PDF 抓取做准备。

在 Adobe Acrobat 中,转到工具->文本识别->在此文件中。Adobe Acrobat 应该开始对 PDF 文件进行 OCR。如果您有多个 PDF 文件,我们可以设置一个“操作向导”来自动处理和 OCR 所有的 PDF 文件。

作者图片

如果你想继续探索 PDF 抓取,请查看我的其他文章:

  • 使用 Python 和 PDFQuery 从 PDF 文件中抓取数据
  • 使用 Python 和 tabula-py 从 PDF 文件中抓取数据
  • 如何使用 Python 和 Pytesseract 将扫描文件转换为可搜索的 PDF
  • 使用 Python 和 Pytesseract 提取 PDF 文本,同时保留空白

感谢您的阅读!!!

如果你喜欢这篇文章,并且想**请我喝杯咖啡,**请点击这里。

您可以注册一个 会员 来解锁我的文章的全部访问权限,并且可以无限制地访问介质上的所有内容。如果你想在我发表新文章时收到电子邮件通知,请订阅。

通过可视化公共航空数据审视航空公司效率

原文:https://towardsdatascience.com/scrutinising-airline-efficiency-by-visualising-public-aviation-data-f736112571f7

可视化英国航空公司数据,了解效率的驱动因素,并强调航空对环境的影响

jet dela cruz 在 Unsplash 上拍摄的照片

源代码: github

最近在听《卫报》的《今日聚焦》时,我被这一集“英国幽灵航班的丑闻”迷住了,其中《卫报》的环境编辑达米安·卡林顿讨论了他对“幽灵航班”的调查工作。根据这篇文章的定义,幽灵航班是指载客量不到 10%的航班,据《卫报》报道,在 2020 年 3 月至 2021 年 9 月期间,15000 架幽灵航班从英国机场起飞。目前还不完全清楚为什么会出现这种情况,但一个主要原因被认为是机场的“插槽”规则。这些是最低活动阈值,激励航空公司运行其大部分定期航班,以便留在给定的机场。

在新冠肺炎疫情的过程中,由于感染的威胁,国家封锁和旅行限制,英国人基本上留在原地。这导致了航空乘客数量的急剧下降,为了支持苦苦挣扎的航空业,政府放弃了舱位规则。这意味着从 2020 年 4 月起,航空公司可以以 0%(而不是 80%)的比例运营,并且仍然保留其机场席位。

尽管如此,在他获得的英国出境航班数据中,卡林顿观察到,即使在这一新的 0%规则下,航空公司仍在继续运营幽灵航班,这表明插槽规则只是这里的一部分难题。

航空业对环境有着巨大的影响。一小时的飞行释放出大约 250 公斤的二氧化碳,这比某些国家的人在 T2 一整年释放的二氧化碳还要多。因此,对于航空公司来说,运行幽灵航班是一种荒谬的浪费行为,在没有必要的情况下排放大量的碳。与将全球变暖保持在 1.5 摄氏度以下所需的经济和政治体系的重大转变相比,解决这一问题似乎是减排的唾手可得的成果,也许是可以通过提高效率来解决的具体问题。

我想进一步研究这个问题,看看是否有任何数据可以让我更好地理解这个问题。我的第一站是查看卡灵顿在这一集中提到的民航局英国航空公司数据。这是每月发布的每家航空公司的可用容量、乘客数量、航班号和飞行公里数。然而,为了复制或扩展卡灵顿的发现,我需要每次飞行的数据。所以我向民航局提交了一份 FOI,要求的正是这个…

我可以确认 CAA 掌握的信息在您最初的查询范围内。然而,民航局的立场是,所要求的信息[……]免于发布。

…立即遭到拒绝。据我所知,这些数据是保留的,但是民航局没有得到航空公司的许可来发布这些数据。我很沮丧,但对这个结果并不感到惊讶,因为卡灵顿需要利用一个议会联系人来获得他所获得的有限数据。

为了不被繁文缛节打败,我决定看看我能得到的数据,并试图收集一些关于航空公司效率的有用见解,而不必通过信息公开机构和利用高调的联系。如果可以使用这些数据来审查航空实践,这代表了一种让这些问题为人所知的可行方法,并为公众提供了追究航空公司、机场和监管机构责任所需的信息。

数据

我从英国民航局网站下载了英国航空公司的活动数据。每个月的数据都以单独的表格形式提供,所以我下载了 table 03-All services . CSV-其中包含了 2019 年 11 月至 2022 年 1 月(含)每个月所有进出英国的航班。该数据包括每个航空公司 15 个变量的月度总量。下面是显示其中三列的数据示例:airline_name、seat_km_used 和 seat_km_available。

+------------------------+-------------------+--------------+|      airline_name      | seat_km_available | seat_km_used |+------------------------+-------------------+--------------+| AIRTANKER SERVICES LTD |          71854000 |     18314000 || AURIGNY AIR SERVICES   |            881000 |       103000 || BA CITYFLYER LTD       |            972000 |        21000 || BLUE ISLANDS LIMITED   |            580000 |       149000 || BRITISH AIRWAYS PLC    |         750959000 |    179433000 || CATREUS AOC LTD        |            104000 |        19000 || EASTERN AIRWAYS        |           3592000 |      1185000 |+------------------------+-------------------+--------------+

我将 seat_km_used 和 seat_km_available 确定为本次分析的主要指标。seat_km_available 是一个标准航空业对航空公司载客量的衡量标准,它考虑了座位的数量和这些座位可以飞行的距离。例如,如果一家航空公司有一架波音 737–800(载客量 189),并且有一个从伦敦到爱丁堡的定期航班(大约。500 公里),那么它的可用座位公里数将等于 189 * 500 = 94500。

这一指标非常有用,因为它可以直接比较不同旅程类型(长途/短途)的航空公司的运力,以及其机队中不同机型的飞机。在整篇文章中,我将把可用座位公里数称为航空公司的“容量”。与此相关的重要定义如下:

  • **可用能力:**计划载客能力。
  • **已用载客量:**已用载客量——即已用座位。
  • **%已用产能:**已用产能占可用产能的百分比。

分析

在这个分析中,我主要关注平均可用容量最高的五家航空公司。为了了解过去三年航空公司的运力,我绘制了每家航空公司的可用运力,用点的大小显示了已用运力的百分比(图 1)。为了跟踪这些变量对时隙规则变化的响应,我使用了从疫情之前(2019 年 11 月)到现在(2022 年 1 月)的数据,使用阴影表示 0%规则的时间跨度。

**图一。**显示一段时间内(2019 年 11 月至 2022 年 1 月)五家英国航空公司可用载客量的时间进程。已用容量百分比由点大小表示(较大的点表示已用容量百分比高,较小的点表示已用容量百分比低)。阴影表示 0%时隙规则覆盖的时间。

在没有在图上标记大流行相关事件的情况下,疫情的影响在数据中清晰可见。随着航空公司收缩业务,航空公司的可用容量将在 2020 年初下降,在接下来的几年里,航空公司试图在低乘客数量下增加容量,这与疾病控制措施相对应。为了了解航班时刻规则的变化如何影响航空公司的运力,并考虑到封锁的影响,我将分析分为三个部分:疫情之前、疫情和“疫情之后”(当然,我指的是封锁之后的时期,在此期间不再有法律强制执行社会距离和疾病控制措施)。

没有在图上标记大流行相关事件,疫情的标记在数据中是可见的。随着航空公司收缩业务,航空公司的可用容量将在 2020 年初下降,在接下来的几年里,航空公司试图在低乘客数量下增加容量,这与疾病控制措施相对应。为了了解航班时刻规则的变化如何影响航空公司的运力,并考虑到封锁的影响,我将分析分为三个部分:疫情之前、疫情和“疫情之后”(当然,我指的是封锁之后的时期,在此期间不再有法律强制执行社会距离和疾病控制措施)。

1.疫情之前(80%规则)

我首先查看了疫情之前的时期——在那个时期,时段规则被设定为 80%——来衡量基线航空公司的运力和使用情况。图 1 显示了 2019 年 11 月至 2020 年 2 月之间的这段时间,其特点是可用容量高。

为了更好地了解这几个月的运力指标,我绘制了可用运力与已用运力的对比图,用已用运力百分比作为每个航空公司的标签(图 2)。

**图二。**显示 5 家英国航空公司已用运力和可用运力的关联图。每个航空公司的标签上都标明了%已用容量。

在图 2 中,完美匹配的航空公司供给和需求位于对角线上。总体而言,航空公司在疫情危机前的运营能力只有 80%。12 月份,维珍大西洋航空公司的使用率低于这一数字,到 1 月份,使用率降至 76%,而英国航空公司的使用率为 81–84%。

英国航空公司、易捷航空公司、Jet2 航空公司、途易航空公司和维珍大西洋航空公司的这些已用运力百分比分别为 17%、11%、12%、7%和 18%。也许这些看起来是微不足道的未用容量,但是让我们用绝对的术语来描述。我通过将航班数量乘以未使用的运力百分比,将未使用的运力转化为空航班的绝对数量,得出如果所有其他飞机都满员,每月可能完全空着的航班数量(图 3)。

**图 3。**柱状图显示 2019 年 11 月至 2020 年 1 月(含)期间,如果所有空容量都转换为航班,各航空公司将运营的空航班数量。

对于最大的航空公司英国航空公司来说,这种未使用的运力相当于每月大约 3500-4000 个完全空着的航班到达或离开英国机场。这是对真实情况的简化。很可能这种未使用的运载量的大部分将由低或中等低运载量的航班组成,一部分来自实际的幽灵航班。但我确实认为这描绘了一幅航空浪费的可怕画面,并提出了是什么在推动这一现象的问题。让我们来看看当 80%槽规则被放弃时会发生什么。

2.疫情——0%规则

到 2020 年 3 月,新冠肺炎病例迅速增加,2020 年 3 月 26 日,第一次封锁开始实施。与此同时,对航空旅行的需求直线下降,使得航空公司无法运行 80%的预定活动。因此,政府放弃了位置规则,这意味着航空公司可以在 0%的情况下运营,仍然保留他们的机场位置。在分析这段时间时,考虑英国封锁*的时间很重要,因此我在图 4 中用阴影表示了这些。

**图四。**时间进程如图 1 所示,但阴影表示英国三个国家的封锁。

我将把这部分分析进一步细分为三个部分,代表 0%规则的三个“阶段”——第一次锁定、锁定间阶段和第三次锁定——绘制每个阶段的已用容量和可用容量的月度相关性。

2.1 第一次锁定(2020 年 4 月—2020 年 8 月)

**图五。**显示 5 家英国航空公司已用运力和可用运力的关联图。每个航空公司的标签上都标明了%已用容量。

第一次封锁是航空公司的不稳定时期,反映在可用容量的波动上。图 5 显示 tu1 和 Jet2 在很大程度上保持了低容量,并在很大程度上填充了它。鉴于这种反应,令人惊讶的是,英国航空公司从 4 月到 8 月一直保持 24-36%的使用容量,而维珍大西洋航空公司尽管在 5 月和 6 月达到了疫情前的%使用容量,但在 7 月和 8 月下降到 14%和 17%。

2.2 相互锁定阶段(2020 年 8 月—2020 年 10 月)

**图六。**显示 5 家英国航空公司已用运力和可用运力的关联图。每个航空公司的标签上都标明了%已用容量。

在这个封锁期内,0%规则的延续和封锁后航空旅行需求的略微增加,维珍大西洋航空公司和英国航空公司似乎再次大大超出了其可用容量。前者是灾难性的,在此期间的四个月中仅使用了其可用容量的 17-24%。

2.3 第三次锁定(2021 年 1 月—2021 年 5 月)

**图 7。**显示 5 家英国航空公司已用运力和可用运力的关联图。每个航空公司的标签上都标明了%已用容量。

第三次封锁再次让航空公司以非常低的已用运力百分比运行。英国航空公司、维珍大西洋航空公司和 Jet2 在<40% for the majority of this period, with EasyJet fluctuating between 26% and 43%. Despite this, as can be seen in figure 4, available capacity was maintained, seemingly unresponsive to these figures.

3. Post-restrictions — 50% rule

In November 2021, the slot rule was re-introduced, but set to 50% rather than 80%. Let’s look at this transition period on the time course plot.

**运行。**时间进程如图 1 所示,但仅限于 2021 年 10 月至 2022 年 1 月,添加了标签,以可用容量的百分比表示已用容量。

随着时隙规则的引入,大多数航空公司增加了他们的可用容量。对于 EasyJet、TUI 和 Jet2 而言,这导致已用运力百分比下降,因为它们增加了可用运力以达到 50%的活动配额,但没有乘客需求来保证这一点。在这里,我们看到了迫使航空公司运营的空位规则的直接证据,并产生了未使用的容量。

*根据政府消息来源,开始日期是明确的,但由于限制的逐步取消,结束日期不太明确,因此我根据 英国政府路线图 将大多数混合限制的取消作为大致的结束日期。

结论

这一分析强调了以下几点:

  • 在前疫情时代,通过迫使航空公司达到活动阈值,时隙规则导致了未使用的航空公司容量。以英国航空公司为例,这个数字相当于每月 3500-4000 次空飞。
  • 50%时段规则的重新引入,以及航空公司可用容量的增加伴随着%已用容量的下降,进一步证明了时段规则对未用航空公司容量的贡献。
  • 在英国关闭期间,乘客需求非常低,空位规则被取消。尽管这些事实表明,航空公司可以不那么活跃,或者实际上以更高的效率运营,但一些航空公司的利用率非常低,特别是英国航空公司和维珍大西洋航空公司。
  • 0%规则数据表明,不仅仅是老丨虎丨机规则在起作用。然而,目前尚不清楚运营幽灵航班或低容量航班的动机是什么,尤其是在没有空位丢失风险的情况下。

起初,出于对幽灵航班的兴趣,我开始查看这些数据,但我开始更多地思考航空业惊人的浪费,以及它对环境的巨大影响。

这一分析表明,我们可以利用公共数据在一定程度上跟踪航空公司的效率。然而,需要提高数据透明度,以使监管机构和航空公司负起责任。审查效率是公众向航空业施加压力的一种方式,目的是迫使航空业减少其巨大的——以及持续飙升的 —碳足迹。

用于可视化数据相关性的 Seaborn 热图

原文:https://towardsdatascience.com/seaborn-heatmap-for-visualising-data-correlations-66cbef09c1fe

数据可视化| Seaborn

用一个简单的热图直观地展示各种特征之间的相互关系

DDP 在 Unsplash 拍摄的照片

热图是创建美丽图形的伟大工具,可以为我们提供趋势方面的见解,并允许我们轻松识别数据集中的潜在异常值。

在本教程中,我们将了解热图的用途之一——关联矩阵热图。相关矩阵允许我们确定数据集中的要素之间的相关程度,以及这种相关是正相关还是负相关。

Python 中有许多数据可视化库,但是最流行和最容易使用的是 Seaborn 库。只需一次函数调用和一个数据集,我们就能轻松创建热图。

资料组

我们在本教程中使用的数据集是一个训练数据集的子集,该数据集用作 Xeek 和 FORCE 2020 (Bormann 等人,2020) 举办的机器学习竞赛的一部分。它是在挪威政府的 NOLD 2.0 许可下发布的,详细信息可以在这里找到:挪威开放政府数据许可(NLOD) 2.0 。

完整的数据集可通过以下链接获得:https://doi.org/10.5281/zenodo.4351155。

竞赛的目的是利用测井测量从现有的标记数据预测岩性。完整的数据集包括来自挪威海的 118 口井。

Seaborn 热图视频教程

我还在我的 YouTube 频道上发布了这个教程的视频版本,它用另一个数据例子进行了更详细的描述。

导入库和数据

对于本教程,我们将导入三个库。 Pandas 用于加载我们的数据,而 seaborn 用于可视化我们的数据。

import pandas as pd
import seaborn as sns

一旦库被导入,我们就可以开始加载数据了。这是通过使用pd.read_csv()并传入文件的相对位置及其名称来完成的。

然后我们提取数据的一个子集。这让我们可以看到我们真正感兴趣的特性。在这种情况下:井径(CALI)、体积密度(RHOB)、伽马射线(GR)、中子孔隙度(NPHI)、光电因子(PEF)和声波压缩慢度(DTC)。

well_data = pd.read_csv('data/Xeek_Well_15-9-15.csv')
well_data = well_data[['CALI', 'RHOB', 'GR', 'NPHI', 'PEF', 'DTC']]

一旦数据加载完毕,我们可以通过调用well_data.head()来查看数据集的前五行

创建关联热图

现在,数据已经成功加载,我们可以开始创建我们的第一个热图。

我们首先需要创建一个相关矩阵。这很容易通过在我们的数据帧上调用.corr()方法来实现。

相关矩阵为我们提供了每个特征相互之间的相关程度的指示。返回值将介于-1 和+1 之间,较高的相关性倾向于这些端点,较差的相关性倾向于 0。

然后,我们可以使用sns.heatmap()并传递相关矩阵(corr)来调用 seaborn 热图。

corr = well_data.corr()
sns.heatmap(corr)

我们得到的是第一张热图。

使用 Seaborn 和相关矩阵生成的初始热图。图片由作者提供。

然而,它不是非常实用或视觉上吸引人。默认选择的颜色让人很难理解什么是高度相关的,什么不是。尽管我们有肤色歧视。

更改 Seaborn 热图颜色

通过为cmap参数提供调色板,我们可以很容易地改变热图的颜色。你可以在这里找到全套调色板。

因为我们对以 0 为中心的高值和低值都感兴趣,所以我强烈推荐使用不同的配色方案。

sns.heatmap(corr, cmap='RdBu')

当我们运行它时,我们得到了下面的热图。趋向暗红色的数值负相关,趋向深蓝的数值正相关。颜色越浅,值越接近 0。

指定自定义颜色图后,相关矩阵的 Seaborn 热图。图片由作者提供。

如果我们看一下图右侧的颜色条,我们可以看到它从顶部的 1 开始,下降到底部的-0.8 左右。

我们可以通过使用vminvmax参数并将它们分别设置为-1 和+1 来控制这个范围,使其相等。

sns.heatmap(corr, cmap='RdBu', vmin=-1, vmax=1)

返回的热图现在具有在正值和负值之间平衡的颜色值。

为色彩映射表指定 vmin 和 vmax 值后,Seaborn heatmap 用于关联矩阵。图片由作者提供。

向 Seaborn 热图添加数字

如果我们在颜色条上查找某个特定细胞的颜色,我们可能得不到准确的读数。然而,如果我们将数字添加到热图中,我们可以立即看到数值,并且仍然保留颜色的变化。

要将数字添加到热图中,我们只需添加annot=True.

sns.heatmap(corr, cmap='RdBu', vmin=-1, vmax=1, annot=True)

我们得到的是一个很好的注释热图。

将数字添加到每个单元格后的 Seaborn 热图。图片由作者提供。

需要注意的一点是,当我们这样做时,文本的颜色会根据单元格的颜色自动改变。所以没有必要指定任何字体颜色。

在 Seaborn 热图上自定义注释字体属性

如果我们想要控制注释的字体大小和字体粗细,我们可以调用annot_kws并传入一个字典。在这个例子中,我将fontsize改为 11,并将fontweight设为粗体。

sns.heatmap(corr, cmap='RdBu', vmin=-1, vmax=1, annot=True, annot_kws={'fontsize':11, 'fontweight':'bold'})

这使得我们的数字更加突出。

更改注记属性后的 Seaborn 热点图。图片由作者提供。

使热图单元格成为真正的正方形

最后一个例子很简单,但是如果我们希望每个单元格都是正方形而不是矩形,我们可以传入square参数并将其设置为True

sns.heatmap(corr, cmap='RdBu', vmin=-1, vmax=1, annot=True, annot_kws={'fontsize':11, 'fontweight':'bold'},square=True)

当我们执行这段代码时,我们得到了一个比例很好的热图。

摘要

热图是直观总结表格数据的好方法。只需看一眼颜色,我们就可以轻松识别数据集中的趋势和异常值。在 Python 中创建热图非常容易,尤其是当我们使用 Seaborn 库时。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!或者,您也可以 注册我的简讯 免费将更多内容直接发送到您的收件箱。

其次,你可以通过注册成为会员来获得完整的媒介体验,并支持我和成千上万的其他作家。它每个月只花你 5 美元,你可以完全接触到所有令人惊叹的媒体文章,也有机会用你的写作赚钱。如果你用 我的链接 报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

参考

博尔曼,彼得,奥桑德,彼得,迪里布,法哈德,曼拉尔,投降,&迪辛顿,彼得。(2020).机器学习竞赛 FORCE 2020 井测井和岩相数据集数据集。芝诺多。http://doi.org/10.5281/zenodo.4351156

Seaborn Pairplot:通过一个单独的图增强您对数据的理解

原文:https://towardsdatascience.com/seaborn-pairplot-enhance-your-data-understanding-with-a-single-plot-bf2f44524b22

在 Python 中使用 Seaborn 的 Pairplot 的简短指南

图片由 Pixabay 的 Pexels 提供。

Seaborn Pairplot 允许我们绘制数据集中变量之间的成对关系。这创造了一个很好的视觉效果,通过在一个图中总结大量数据来帮助我们理解数据。当我们探索数据集并试图熟悉它时,这是必不可少的。

显示不同地质岩性的 Seaborn pairplot 示例。图片由作者提供。

俗话说,一图胜千言。

在这个简短的指南中,我们将介绍如何使用 Seaborn 创建一个基本的 pairplot,并控制它的美学,包括图形大小和样式。

资料组

我们在本教程中使用的数据集是一个训练数据集的子集,该数据集用作 Xeek 和 FORCE 2020 (Bormann et al .,2020) 举办的机器学习竞赛的一部分。它是在挪威政府的 NOLD 2.0 许可下发布的,详细信息可以在这里找到:挪威开放政府数据许可(NLOD) 2.0 。

完整的数据集可以通过以下链接获得:https://doi.org/10.5281/zenodo.4351155。

竞赛的目的是利用测井测量从现有的标记数据预测岩性。完整的数据集包括来自挪威海的 118 口井。

此外,您可以从 GitHub 资源库下载本教程中使用的数据子集以及笔记本:

https://github.com/andymcdgeo/Andys_YouTube_Notebooks

Seaborn Pairplot 视频教程

我还发布了下面的视频,你可能会感兴趣。

导入库和数据

第一步是导入我们将要使用的库。在这种情况下,我们将使用 Seaborn 和 pandas ,前者是我们的数据可视化库,后者将用于加载和存储我们的数据。

import seaborn as sns
import pandas as pd

为了设计 Seaborn 图的样式,我将样式设置为darkgrid

# Setting the stying of the Seaborn figure
sns.set_style('darkgrid')

接下来,我加载了一些来自 Force 2020 机器学习竞赛的测井数据,该竞赛侧重于从测井测量中预测岩性。如果您不熟悉这个数据集,请不要担心,因为我将要展示的内容可以应用于几乎任何其他数据集。

df = pd.read_csv('Data/Xeek_Well_15-9-15.csv')# Remove high GR values to aid visualisation
df = df[df['GR']<= 200]

除了加载数据,我还移除了 200 API 以上的伽马射线(GR)值,以帮助可视化这些数据。理想情况下,您应该在移除这些点之前检查这些点读数高的原因。

创建所有数据的 Seaborn Pairplot

现在数据已经加载完毕,我们可以开始创建我们的第一个 pairplot 了。为了获得数据集中所有数值变量的配对图,我们只需调用sns.pairplot并传入我们的 dataframe — df

sns.pairplot(df)

一旦运行,我们会得到一个包含许多支线剧情的大图。

显示相关性和数据分布的测井测量的 seaborn pair 图。图片由作者提供。

如果我们仔细看看生成的图形,我们可以看到所有的变量都显示在 y 轴和 x 轴上。沿着对角线,我们有一个直方图显示每个变量的分布。

很快我们就有了一个单一的数字,可以用来提供我们数据集的一个很好的压缩摘要。

绘制特定列

如果我们只想显示数据框架中的一些变量,我们首先需要创建一个我们想要研究的变量列表:

cols_to_plot = ['RHOB', 'GR', 'NPHI', 'DTC', 'LITH']

在上面的例子中,我创建了一个新变量cols_to_plot,并把它赋给了一个包含RHOB, GR, NPHI, DTC and LITH的列表。其中前四个是数字,最后一个是分类,后面会用到。

然后,我们可以调用我们的 pairplot,并传递带有该列表的数据帧,如下所示:

sns.pairplot(df[cols_to_plot])

当我们运行这个时,我们得到一个更小的数字,其中只有我们感兴趣的变量。

主数据框架中测井测量子集的 Seaborn Pairplot。图片由作者提供。

将对角线从直方图更改为 KDE

我们可以用核密度估计(KDE)代替沿对角线的直方图,这为我们提供了另一种查看数据分布的方式。

为此,我们只需添加关键字参数:diag_kind等于kde,如下所示:

sns.pairplot(df[cols_to_plot], diag_kind='kde')

这将返回下图:

Seaborn pairplot 显示沿对角线的核密度估计图。图片由作者提供。

向散点图添加回归线

如果我们想确定散点图中的关系,我们可以应用线性回归线,只需添加关键字:kind并将其分配给'reg'即可。

sns.pairplot(df[cols_to_plot], kind='reg', diag_kind='kde')

当我们运行它时,我们现在会看到在每个散点图上都出现了一条部分线

有回归线的 Seaborn pairplot。图片由作者提供。

然而,由于线的颜色和点的颜色是一样的,我们需要改变这一点,使其更加明显。

我们可以通过添加关键字plot_kws来做到这一点,然后我们需要传入一个字典,它将包含line_kws,然后为我们的color传递另一个字典对象,我们将它设置为红色。

# Use plot_kws to change regression line colour
sns.pairplot(df[cols_to_plot], kind='reg', diag_kind='kde',plot_kws={'line_kws':{'color':'red'}})

当我们运行代码时,我们会得到一个带有红线的 pairplot,这样更容易看到。

Seaborn pairplot 在改变颜色后带有回归线。图片由作者提供。

按类别着色

如果我们的数据框架中有一个分类变量,我们可以使用它来直观地增强图表,并查看每个类别的趋势和分布。

在这个数据集中,我们有一个名为 LITH 的变量,它代表从测井测量中识别的不同岩性。

如果我们使用数据帧的子集,我们需要确保cols_to_plot行包含我们想要用来给数据着色的变量。

要使用这个变量,我们所做的就是添加一个hue参数,并从我们的列表中传递'LITH'列,然后运行代码。

sns.pairplot(df[cols_to_plot], hue='LITH')

我们得到的是一个 pairplot,由该变量中的每个类别着色。

Seaborn pairplot 显示了不同的地质岩性。图片由作者提供。

如果我们仔细观察数据,我们会看到蓝色的页岩、绿色的砂岩和红色的石灰岩,从这些数据中我们可以获得一些见解。例如,我们看看页岩,我们可以看到在大约 100 API 处有一个 GR 变量的大峰,在大约 25 API 处有一个较小的粉红色峰。所以我们马上就能知道每种岩性的范围。

既然我们已经介绍了 pairplot 的基础知识,现在我们可以进入下一个层次,开始设计我们的绘图。

设计对角线图的样式

首先,我们将从改变对角线直方图的属性开始。我们可以通过使用diag_kws关键字并传入我们想要更改的内容的字典来更改对角线样式。

在这个例子中,我们将通过传入一个color关键字并将其设置为红色来改变颜色。

sns.pairplot(df[cols_to_plot], diag_kws={'color':'red'})

当我们运行这个时,我们得到如下的图:

更改对角线直方图属性后的 Seaborn pairplot。图片由作者提供。

由于这是一个直方图,我们还可以更改显示的箱数。同样,这是通过传入包含我们想要更改的属性的字典来完成的,在本例中是bins

我们将它设置为 5 并运行代码。

sns.pairplot(df[cols_to_plot], diag_kws={'color':'red', 'bins':5})

它返回这个数字,有五个箱,数据用红色表示。

更改对角线直方图柱属性后的 Seaborn pairplot。图片由作者提供。

设计点的样式

如果我们想要样式化这些点,我们可以使用plot_kws关键字,并传入包含color的字典,我们将把它设置为绿色。

sns.pairplot(df[cols_to_plot], diag_kws={'color':'red'}, plot_kws={'color':'green'})

更改散点图颜色属性后的 Seaborn pairplot。图片由作者提供。

如果我们想改变点的大小,我们只需将关键字s添加到字典中。这将减少点的大小。

更改散点图大小属性后的 Seaborn pairplot。图片由作者提供。

更改 Seaborn Pairplot 图形大小

最后,我们可以通过添加关键字参数height以一种非常简单的方式控制图形的大小,在本例中,我们将该参数设置为 2。当我们运行这段代码时,我们会看到现在有一个小得多的图。

sns.pairplot(df[cols_to_plot], height=2)

我们也可以使用aspect关键字参数来控制宽度。默认情况下,它被设置为 1,但是如果我们将其设置为 2,这意味着我们将宽度设置为高度的两倍。

sns.pairplot(df[cols_to_plot], height=2, aspect=2)

使用高度和纵横比更改图形大小后的 Seaborn pairplot。图片由作者提供。

摘要

Seaborn Pairplot 是一个很棒的数据可视化工具,可以帮助我们熟悉我们的数据。我们可以在单个图形上绘制大量数据,并获得对它的理解以及开发新的见解。这绝对是你的数据科学工具箱中的一块园地。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!或者,您可以 注册我的简讯 免费获取更多内容直接发送到您的收件箱。

其次,通过注册会员,你可以获得完整的媒介体验,并支持我自己和成千上万的其他作家。它每个月只花你 5 美元,你可以完全接触到所有令人惊叹的媒体文章,也有机会用你的写作赚钱。如果你用 我的链接报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

参考

博尔曼,彼得,奥桑德,彼得,迪里布,法哈德,曼拉尔,投降,&迪辛顿,彼得。(2020).机器学习竞赛 FORCE 2020 井测井和岩相数据集数据集。芝诺多。http://doi.org/10.5281/zenodo.4351156

Python 中的 Seaborn Relplot:可视化数据中的关系

原文:https://towardsdatascience.com/seaborn-relplot-in-python-visualising-relationships-in-data-ee39138d53aa

使用 Seaborn 的重新绘图可视化测井数据

照片由沙哈达特·拉赫曼在 Unsplash 上拍摄

Seaborn 关系图(relplot) 允许我们可视化数据集中的变量之间的关系。数据可视化是任何数据分析或机器学习工作流的重要组成部分。它可以让我们深入了解我们的数据。正如那句名言所说,“一幅画胜过千言万语”。

在这个简短的教程中,我们将了解如何使用来自 Seaborn 的 relplot 函数在散点图和线图上显示测井数据。

数据源

本教程的数据来源于以下 GitHub 知识库,并构成了旨在根据测井测量预测岩性的机器学习竞赛的一部分。

鲍曼,奥桑德,迪里布,迪辛顿,曼拉尔,2020。强制机器学习竞赛。https://github . com/bolgebrygg/Force-2020-机器学习-竞赛

通过视频跟进

在我的 YouTube 频道上也有这篇文章的视频版本,你也可以在这里看到:

导入库和数据

项目的第一步是导入我们将要使用的库。这些是海豚和熊猫。Seaborn 允许我们用几行代码创建非常强大的图形,pandas 允许我们从 CSV 文件加载数据并将其存储在 dataframes 中。

import seaborn as sns
import pandas as pd

导入库之后,我们可以开始使用pd.read_csv()从 CSV 文件导入数据

df = pd.read_csv('Data/Xeek_Well_15-9-15.csv', na_values=-999)

使用 Relplot 创建散点图

现在数据已经加载,我们可以开始使用 Seaborn 的 Relplot 函数创建我们的第一个散点图。岩石物理学中常见的散点图是中子孔隙度(NPHI) 对密度(RHOB) 图。

g = sns.relplot(data=df, x='NPHI', y='RHOB');

当我们执行这段代码时,我们得到了一个非常简单的散点图,其中已经为我们分配了轴标签。

使用 seaborn rel 图创建的中子孔隙度与体积密度散点图。图片由作者提供。

使用中子-密度散点图时,我们通常以相反的顺序查看密度轴,因此孔隙度随着两个轴的增加而增加。

我们可以通过调用g.set,然后设置ylim参数来做到这一点。

g = sns.relplot(data=df, x='NPHI', y='RHOB')
g.set(ylim=(3, 1.5));

这将返回下面的图,在进行岩石物理分析时,该图看起来更有吸引力。

使用 seaborn rel 图创建的中子孔隙度与体积密度散点图。图片由作者提供。

定制散点图

用连续变量着色

Seaborn Relplot 允许我们指定多个参数来定制我们的绘图。其中之一是hue参数,它允许我们指定另一个变量来给我们的图着色。

在这个例子中,我们可以选择伽马射线(GR) 数据,这些数据可以用来指示我们地层的泥质。

g = sns.relplot(data=df, x='NPHI', y='RHOB', hue='GR')
g.set(ylim=(3, 1.5));

当代码运行时,我们得到如下图。

中子孔隙度与体积密度的散点图,用伽马射线着色。使用 seaborn relplot 创建。图片由作者提供。

当我们看这个图时,我们可以看到我们有一个问题。由于异常高的值,该图似乎被洗掉了。

如果这些值被认为是真正的异常值,我们可能会从数据中删除它们,或者我们可以重新调整绘图。

我们经常绘制的另一个变量是井径(CALI)。这给了我们钻孔冲刷程度的指示。这一点很重要,因为与地层相比,如果读取更多的井内流体,许多测量可能会受到严重影响。

g = sns.relplot(data=df, x='NPHI', y='RHOB', hue='CALI')
g.set(ylim=(3, 1.5));

当我们执行这段代码时,我们可以看到生成了下面的图。从中我们可以看出,一些较低的 RHOB 和较高的 NPHI 读数要么来自钻孔的冲刷部分,要么是在较大井段获得的。对卡尺曲线和位尺寸曲线的进一步研究将揭示哪一个是最可能的情况。

中子孔隙度与体积密度的散点图,用测径器着色。使用 seaborn relplot 创建。图片由作者提供。

用离散变量着色

除了用连续特征着色,我们还可以用分类特征着色。在这个例子中,我们将看到体积密度(RHOB) 和中子孔隙度(NPHI) 如何随着不同的地质岩性(LITH)而变化。

在这个例子中,我们只是简单地将LITH列放在hue参数中。

g = sns.relplot(data=df, x='NPHI', y='RHOB', hue='LITH')
g.set(ylim=(3, 1.5));

从返回的图中,我们可以看到页岩(蓝色)具有高的中子孔隙度和大范围的体积密度值。我们还可以看到其他岩性以及与测量值相关的落差。

中子孔隙度与体积密度的散点图,由岩相着色。使用 seaborn relplot 创建。图片由作者提供。

设定标记的样式

除了能够控制每种岩性的色调,我们还可以通过将LITH传递给style参数来改变样式。

g = sns.relplot(data=df, x='NPHI', y='RHOB', hue='LITH', style='LITH')
g.set(ylim=(3, 1.5));

在返回的地块上,我们现在可以利用颜色和形状来识别不同的岩性。如果图表是黑白打印的,这尤其有用。

中子孔隙度与体积密度的散点图,由岩相着色。使用 seaborn relplot 创建。图片由作者提供。

线形图

relplot 不仅限于散点图,我们还可以生成线图。我们所要做的就是将参数kind='line’添加到 relplot 调用中。

g = sns.relplot(data=df, x='DEPTH_MD', y='GR', kind='line')
g.set(ylim=(0, 150));

使用深度测量和伽马射线特征(GR ),我们可以生成一个非常简单的数据与深度的对数图。

Seaborn relplot 用于绘制伽马射线与深度的线形图。图片由作者提供。

用高度和纵横比设置图形大小

上面的图看起来有点压扁,很难看出发生了什么。在 seaborn 中有多种方法可以改变图形的大小,在 relplot 中最方便的方法就是这样指定一个height和一个aspect

在这个例子中,高度设置为 7,宽度将是它的 2 倍。

g = sns.relplot(data=df, x='DEPTH_MD', y='GR', kind='line', height=7, aspect=2)
g.set(ylim=(0, 150));

这允许我们像这样延伸我们的情节。

Seaborn relplot 用于绘制伽马射线与深度的线形图。图片由作者提供。

将图形分割成支线剧情/小平面

如上图所示,当不同类别(岩性)相互重叠时,很难区分它们。解决这个问题的一个方法是创建多个子情节,每个类别一个(岩性)。

有了重新绘图,这变得非常容易。我们简单地通过一个新的论点叫做col='LITH'

g = sns.relplot(data=df, x='NPHI', y='RHOB',hue='LITH',style='LITH',col='LITH')
g.set(ylim=(3, 1.5));

当我们运行它时,我们得到了下面的一系列散点图,所有的都是相同的比例,并按我们的类别(岩性)分开。然而,由于我们有几个类别,不放大很难看到。

使用 seaborn relplot 创建多个支线剧情。图片由作者提供。

包装列

为了使图更具可读性,我们可以应用一个列换行值。一旦达到该值,绘图将创建一个新行,并继续下一个类别。

这是通过传入col_wrap=3实现的。这个数字可以是您想要的任何数字,但是 3 在这个例子中非常适用。

#Wrapping the columnsg = sns.relplot(data=df, x='NPHI', y='RHOB',hue='LITH',style='LITH',col='LITH',col_wrap=3)
g.set(ylim=(3, 1.5));

现在我们的 relplot 可读性更好,也更容易解释。

使用 seaborn relplot 创建多个支线剧情。图片由作者提供。

更改磅值

如果我们想要增加点的大小,我们可以通过在 relplot 调用中为标记大小参数传递一个值:s=100来实现。

#Changing size of pointsg = sns.relplot(data=df, x='NPHI', y='RHOB',hue='LITH',style='LITH',col='LITH', col_wrap=3, s=100)
g.set(ylim=(3, 1.5));

当我们运行这个时,我们可以看到我们现在有了更大的点,从而使图形更具可读性。

使用 seaborn relplot 创建多个支线剧情。图片由作者提供。

摘要

在这个简短的教程中,我们看到了如何使用强大的 Seaborn relplot 在散点图和线图上可视化测井数据,而无需分别调用它们。这可以使我们的代码更整洁,更容易阅读。 relplot 还允许我们将数据分类,或者用连续或离散数据给点着色。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!

其次,通过注册会员,你可以获得完整的媒介体验,并支持我自己和成千上万的其他作家。它每个月只花你 5 美元,你可以完全接触到所有令人惊叹的媒体文章,也有机会用你的写作赚钱。如果你用 我的链接 报名,你会直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

使用 Binder 与同事无缝共享编码演示

原文:https://towardsdatascience.com/seamlessly-share-coding-demos-to-colleagues-using-binder-bbea9a823505

在云端共享 Jupyter 笔记本的无缝方式。

有 Jupyter 笔记本可以分享吗?分享给 Binder!萨凡纳·维克菲尔德在 Unsplash 上拍摄的照片

一位同事最近问我如何在日常工作流程中使用脚本语言来清理和准备数据。她感兴趣的是向她的团队展示采用脚本语言可以如何使她的团队受益,并帮助他们自动化一些目前在 Excel 中执行的任务。

我选择使用活页夹来展示他们可以节省多少时间,以及如何通过使用 Python 来清理他们的数据,使他们的流程更不容易出错。下面以案例研究的形式介绍了这一点。

拥有一个装满 Jupyter 笔记本的存储库?使用 Binder,在一个可执行的环境中打开这些笔记本,让任何人、任何地方都可以立即复制您的代码。—mybinder.org

本文的目标是讨论 Binder 的优点和使用案例!

您还可以选择:

  • 使用 Python 的一些数据清理技术
  • 与同事分享你所学的灵感

您可以将 Binder 用于许多不同的语言,比如 Julia、Python 或 r。

**注:**在云端运行 Jupyter 笔记本有很多免费选择。来自数据学校的凯文·马卡姆在讨论每个选项的利弊方面做得很好。我选择 Binder 是因为我希望我的用户不必创建帐户或与商业工具交互。下面的案例研究也是一个轻量级应用程序,没有性能考虑或敏感数据。

使用活页夹的好处

  • 在网络浏览器中轻松共享交互式 Jupyter 笔记本
  • 机器上不需要安装 Julia、Python 或 R
  • 与 git 一起运行,因此它受益于版本控制

我个人的活页夹使用案例

1.展示脚本语言或方法的实用性和有用性

2.讲授环境和包或库的版本的重要性

3.与同事分享知识

4.构建我的数据科学投资组合,逐步演示我如何进行分析案例研究

你还能想到更多的用例吗?请在评论中分享!

装订要求:

一个可用的准系统绑定器服务需要一个 Github repo:

  1. Jupyter 笔记本,也就是代码将运行的. ipynb 文件
  2. 一个 requirements.txt 文件,包含运行代码所需的 Python 依赖项(。yaml 文件也是可用的)
  3. 【可选】数据文件或包含数据的文件夹
  4. [可选]一个 readme.md 文件(包括良好实践)

案例分析:

加州州立大学系统的一些分析师希望了解在清理一些标准化学生评估数据时,使用 Python 或 R 等语言如何帮助他们节省时间。我用样本评估数据模拟了一个活页夹,并展示了 Python 如何节省大量时间,否则这些时间将花费在加载和操作 Excel 中的数据上。我在这里浏览这个例子。请看下面的互动活页夹!

https://mybinder.org/v2/gh/jimmyvluong/Python-CalTPA-Demo/HEAD

目标:

此任务的最终目标是将评估数据读入这些分析师正在使用的数据库中。幸运的是,所有分析师都要求数据采用完全相同的格式。

数据背景:

样本评估数据。如果纯粹在 Excel 中完成,这将需要在每次读入数据时指定每个列宽。对于 22 个校园中的每一个,每年至少有 20 多个文件需要处理。

文件夹中的多个文件包含没有数据错误的学生评估数据。该文件夹包含一个指定字段名称和字段宽度的自述文件。

方法:

读入文件,将它们组合成一个单一的数据帧,然后将数据帧调整成最终所需的结构。我不会在这里深入讨论这些方法,但是你可以运行 Binder 中的代码来查看工作流程。

对 github repo 进行 Binderize 所需要的一切。最起码,您需要一个包含要运行的代码的. ipynb 和一个包含所需依赖项的 requirements.txt 文件。

看一下 requirements.txt 文件。只需要 2 个依赖项。熊猫版是指定的。Binder 会自动下载 numpy 的最新版本。

一旦你的 github 回购被创建,只需将回购的 URL 粘贴到 mybinder.org 网站的第一行,如下所示:

然后,您可以使用创建的 URL 共享活页夹!

Binder 将需要几分钟时间启动,然后生成一个交互式工作区,如下所示:

一个工作,互动 Jupyter 笔记本,所有必需的文件和依赖关系。呜哇!

结果:

我的同事欣喜若狂地看到这一评估数据可以被操纵得如此之快!我们将在接下来的几周会面,讨论如何从 Excel 跳到 Python。

由于这个演示取得了成功,我联系了加州州立大学系统的其他分析师和数据科学家,看看我们可以互相学习什么。我预计我们会非常频繁地使用 Binder

如果你想提升自己,那就提升别人。

使用连体神经网络搜索足球场景

原文:https://towardsdatascience.com/searching-for-soccer-scenes-using-siamese-neural-networks-76405ef159e

如何在多智能体轨迹数据中找到相似的运动模式

在体育运动中产生定位数据的设备和系统的广泛使用需要工具来大规模地分析这些数据。为此,我们开发了一个多代理跟踪数据搜索引擎,我们在本文中介绍。该引擎能够在几秒钟内在大型数据库中找到类似的运动模式。想知道它是如何工作的吗?那就继续读下去!

图 1: 在一次反击中,我们使用本文中概述的方法找到了两个几乎相同的交叉场景。这两个场景都源于不同球队的不同比赛,以及潜在的不同阵型。虽然使用传统方法可以找到两个场景,因为它们包含事件“交叉”,但是我们的方法快速过滤掉大多数交叉,因为基于玩家移动,只有少数场景实际上是相似的。我们在整个系列中将这些场景称为左边的 Q (即查询),右边的 R (即结果)。(*图片由作者提供,*视频由 DFL Deutsche fubal Liga 经许可提供)

我们可以访问一个大型足球数据库,其中包含一个赛季的跟踪数据,即球员轨迹、比赛统计数据和专家注释的事件,如德国德甲联赛的传球射门。虽然事件允许你找到像角球这样的定位球,但结果是粗糙的,因为它们没有考虑球员在事件中的行为。此外,一些潜在利益的情况,如反击,不是由事件表示的。为了能够对足球比赛进行精细分析,必须考虑球员的运动(即跟踪数据)。

图 1 显示了我们在追踪数据中进行足球场景搜索的结果。图的左边部分显示了查询场景。反击中的传中是在球场的一侧进行的,在禁区内找到一名前锋。目标紧随其后,但没有显示出来。图的右边显示了一个非常相似的场景,但是来自一个不同的游戏,这是我们的方法的搜索结果。右边的结果场景的情节是镜像的,因为攻击队从右到左比赛。使用控球注释,我们使所有场景正常化,这样控球的球队从左向右比赛。因此,我们可以找到所有相似的运动模式,与演奏方向无关。

为了提高搜索的计算效率,我们还在 5 秒长的窗口中切割每个游戏。这允许我们以标准化的格式表现场景,包括 23×125×2 的值(25 赫兹的采样率,22 名球员和球在 2D 坐标系中)。这看起来像是非常限制性的假设,但是我们将在本文后面介绍可变场景长度的扩展。

相似性度量和指派问题

在多智能体跟踪数据中搜索在理论上是简单的。设置:给你两组无序的轨迹(例如,进攻队的场上队员),你应该返回一个数字来表示它们有多相似,即距离度量的倒数(低距离≙高相似度)。根据这个标准,我们可以在数据库中搜索最近的邻居,这样就完成了(理论上)。

那么,我们如何衡量这里的相似性呢?存在各种很好理解的基于轨迹的相似性度量。但是在我们的例子中,我们操作的是无序集(由于阵型之间没有明确的映射,球员也可能在比赛中扮演不同的角色),因此我们还需要一个分配方案,将这些转换成有序集,在此基础上我们可以计算连贯轨迹对之间的相似性。我们分两步实现这一点:

  1. **轨迹分配:**我们使用 匈牙利算法 为彼此分配最优轨迹。匈牙利算法需要一个成本矩阵(包含将 A 中的所有项目分配给 B 中的所有项目的成本)来优化,我们使用轨迹距离度量来计算,例如欧几里德距离。这产生了最佳轨迹分配,即两个局部有序轨迹集。图 2 显示了结果赋值的一个例子。
  2. **距离聚合:**给定两个有序轨迹集,我们通过平均来聚合相干轨迹之间的距离,从而得到可用于搜索的最终场景距离。

图 2: 图 1 中查询 Q (左)和结果 R (右)之间两个攻击队的最优分配。相互分配的轨迹由虚线连接。此外,任意局部轨迹对排序通过蓝色索引显示。我们如何实现全球排序将在后面讨论。(图片作者)

有了这个距离度量,我们可以在数据库中搜索最相似的场景。给定一些查询 **Q,**我们为每个可能的结果分配轨迹( X₁ ,… Xₙ ),合计距离并返回所有具有最低距离的 X 。这种天真的方法的问题是它非常慢,因为对于数据库中的每一项,都必须解决一个小的优化问题(即匈牙利算法)。此外,不能应用加速搜索的普通技术,如聚类,因为在分配之前,轨迹很可能是不一致的。

根据相关文献,我们将这个问题称为分配问题。这个问题的自然结论是构建一些全局轨迹排序方案。给定这样的方案,在建立搜索引擎时,为每个数据库项目进行一次计算上昂贵的轨迹分配步骤,而不是为每个查询进行一次。几篇论文提出了这样的方案:沙等人[1]学习了一个模板(即每支球队在球场上的 10 个巧妙定位的点),数据库中的所有场景(,…)都被分配给该模板,同样使用匈牙利算法。在检索过程中,将查询分配给模板,跳过每个数据库项的最佳分配。在接下来的论文中,Sha 等人[2]提出了一个学习模板层次结构的方案,允许使用多个模板来考虑各种游戏情况。另一方面,Wang 等人[3]通过对场景图像进行操作,完全避开了这个问题。****

也就是说,我们有经验证据表明,这样的全局轨迹排序方案一般来说不可能是最优的。因此,上面概述的方法产生带有未量化误差的次优结果。我们的方法直接逼近最佳距离,并产生可量化的误差,我们可以使用这些误差来衡量性能。下面的部分详细阐述了这一主张,并概述了我们的近优解决方案。

轨迹集的伪标准形

一组对象的标准形式,在我们的例子中是所有无序轨迹集,为每个等价类给出了满足某个属性特定表示。例如,由从 q₁到 q₁₀的 10 条轨迹组成的无序轨迹集
Q ={q₁,…,q₁₀},等于轨迹索引的某种排列: Q ={q₁₀,…,q₁}关于之前定义的相似性(由于最优分配)。这意味着 Q 的等价类是所有轨迹索引排列的集合。我们想要满足的性质是,该等价类的代表(即,特定的轨迹排列)被最优地分配给所有其他等价类的代表。换句话说:轨迹集的标准形式是全局最优排序。给定这样一个标准形式,我们可以根据它们的索引来比较轨迹,跳过昂贵的赋值步骤,快速得出最佳距离。
**

不幸的是,这样的规范形式并不存在。例如,如果您优化分配了 ABAC ,则存在一些未优化分配的三元组 BC 。这意味着我们要么接受最佳结果的慢速搜索,要么接受次优结果的快速搜索。

TLDR:没有简单的方法可以绕过昂贵的分配步骤。

图 3 :使用我们的伪规范场景表示法在 QR 之间进行轨迹分配。与图 2 相反,轨迹不是由匈牙利算法分配的,而是基于它们的索引。基于相对于编队质心的角度来计算轨迹指数,该角度可针对每个场景单独计算。(图片由作者提供)

但是有办法在保持高检索速度的同时达到接近最优的结果。为此,我们使用试探法构建伪规范表示。我们根据轨迹围绕每队质心的角度对轨迹进行排序。通过这种方式,阵型被考虑在内,分配适用于球场的所有部分。图 3 显示了在我们的伪正则场景表示下 RQ 之间的轨迹分配。注意,与图 2 中的相比,轨迹对排序是系统化的。同样重要的是要注意,在图 3 的*中,轨迹不是使用匈牙利算法相互分配的,而是基于我们的角度启发式算法得出的索引,该索引是独立于任何其他轨迹集计算的。***

虽然使用这种试探法分配给彼此的轨迹可能不是最佳的,但是它确实显著地减少了最佳分配的误差:如果我们基于如何从数据库中检索轨迹来分配轨迹给彼此(即,随机的),相对于最佳分配的误差平均约为 60%;使用启发式算法,我们将这个误差平均降低到 4%左右。接受这个误差允许我们在回收过程中跳过计算量大的轨迹分配步骤。

使用连体网络逼近最佳距离

为了进一步减少这种误差,我们采用连体神经网络来近似基于这些启发式对齐轨迹集的最佳距离。该方法概述如下。

我们随机抽取一批场景对,用前面描述的角度试探法将它们相互对齐。这两个场景然后通过暹罗网络产生两个 64 维向量。拟合网络,使得嵌入 d̂中的距离(我们选择欧几里德距离)等于轨迹集之间的距离(见图 4 )。理想情况下,嵌入距离与最佳距离匹配,我们可以快速搜索最近邻的嵌入。**

图 4 :连体神经网络的训练示意图。两个轨迹集 A 和 B(例如,两个攻击队轨迹)是在所有可用的轨迹集中随机选择的。我们计算两者之间的最佳距离 d(A,B)作为网络的目标。这两个集合通过网络被转发以产生两个 n 维向量 Â和 B̂.然后,网络适合于最小化嵌入距离 d̂(â(b̂)和最佳距离 d(A,b)之间的差异。(图片由作者提供)

该网络由时间卷积网络实例化,我们通过使用梯度下降最小化均方误差来拟合该网络。我们还对其他损失进行了实验,例如,通过最佳距离的倒数对损失进行加权(产生局部精确的嵌入,类似于 Sammons 映射),但没有显著的改进。

我们发现的最佳配置将误差降低到 2%多一点。这不仅因为维数较低(64 比 2500 = 10 * 2 * 125)而更快,而且还允许通过聚类来减少搜索空间。

让足球场景可搜索

为了完全代表整个足球场景,我们训练两个连体网络(参见图 5 中的步骤 3),一个用于控球(或拥有大部分控球权)的球队,一个用于另一个。这允许用户通过计算两个嵌入中距离的加权和来指定两个团队的权重。例如,取决于应用,攻击队的动态可能更重要,反之亦然。另一方面,球不需要分配,因此计算轨迹距离的相似性是可行的。由于由连体网络产生的嵌入近似最优轨迹集(即,团队)距离的平均值,团队的规模和球嵌入距离是可比较的,从而也允许类似地加权球的重要性。**

****图 5: 我们的体育场景搜索引擎的系统概述。 **1。**用户通过在查询选择和过滤选项中进行选择来指定搜索参数。 **2。**查询场景基于角度启发式对齐,并为两个团队带入其伪规范形式。 **3。**使用两个连体网络将场景投影到嵌入中。 **4。**基于用户过滤规范,选择所有嵌入场景的子集作为候选。 **5。**计算查询和候选结果之间的距离。 **6。**对距离进行排序,并保留最近的 N 个邻居的索引。 7。计算查询和每个结果场景之间的最佳距离,以确定最终的结果排序。数据库中每个场景的嵌入向量是在系统设置期间计算的,并且必须为添加到其中的任何新场景进行计算。(图片由作者提供)

为了减少由近似引入的误差,我们基于到查询的最佳距离对结果场景进行排序(参见图 5 中的步骤 7)。这降低了对那些场景的近似距离的影响,由于高估了它们的真实距离,我们可能在最近的 N 个邻居中错过这些场景,如果检索到足够多的(例如 1000 个)最近的邻居(尽管不是所有的邻居都必须显示给用户),则真实距离是最小的。这种方法允许我们将搜索整个赛季的足球场景的时间从大约一个小时(对于天真的方法)减少到不到一秒,同时检索接近最优的结果。**

给定足够大的数据库,检索时间可能会变得过长。通过对嵌入空间进行聚类,可以进一步提高检索速度。在距离计算之前,找到嵌入查询的最近的聚类中心,并且只有落入该聚类中的那些场景才有资格沿着管道进一步处理。通过增加聚类的数量,所有下游处理成本将除以该数量,代价是可能会丢失位于邻近聚类边界错误一侧的场景。

************

图 6: 包含 17 个匹配的嵌入的 3d-UMAP 投影。(图片和视频由作者提供)****

图 6 示出了 17 个匹配子集的学习嵌入的三维投影。查询 Q 用绿色标出,5 个最近的邻居用红色标出。大部分场景源于连续的主动播放,导致主集群较大。位于主集群之外的两个小集群(左下方)是两个定位球,它们导致了在活跃的比赛中很少观察到的特殊动态,即射门和开球。有趣的是,其他定位球,如角球,并没有表现出足够的差异,以主动发挥位于主群之外(但这也可能是由于投射方法和维度)。最后,主集群上方可见的几个异常值是游戏暂停的场景,但注释错误地声称游戏是活动的。

延伸到更长的场景

为了搜索大于 5 秒的动态场景长度,我们使用现有的嵌入,将包含在较长场景中的每个 5 秒窗口映射到嵌入中,并将较长场景视为嵌入中的轨迹。我们计算嵌入中所有 5 秒窗口序列的欧几里德距离,并产生具有最低距离的那些。

结论

足球比赛或一般团队运动的精细分析可以通过考虑运动员的运动来增强。我们概述了我们的方法来搜索大型数据库的无序轨迹集相似的运动模式在互动的速度使用暹罗神经网络。

承认

这项工作得到了巴伐利亚经济事务、基础设施、能源和技术部的支持,作为巴伐利亚项目 Leistungszentrum Elektroniksysteme(LZE)的一部分,并通过分析-数据-应用中心(ADA-Center)在“拜仁数字 II”框架内提供支持。

我还要感谢我在弗劳恩霍夫国际研究所的同事 Daniel Dzibela、Christoffer Lö ffler、Robert Marzilger 和 Nicolas Witt,感谢他们支持本文系统的开发和对本文的审阅。

参考

在我们的出版物中找到更多详细信息:

****https://dl.acm.org/doi/10.1145/3465057

[1]沙,龙等.**黑板:一种新的体育比赛时空查询范式.**第 21 届智能用户界面国际会议论文集。2016.
【2】沙,龙等.基于树的轨迹对齐的体育比赛细粒度检索 arXiv 预印本 arXiv:1710.02255 ,2017。
【3】王,郑,等.基于深度表征学习的高效体育游戏检索。第 25 届 ACM SIGKDD 知识发现国际会议论文集&数据挖掘。2019.

时间序列的季节性

原文:https://towardsdatascience.com/seasonality-of-time-series-5b45b4809acd

对季节性如何影响时间序列分析的直觉

杰克·希尔斯在 Unsplash 上的照片

介绍

季节性时间序列 分析的一个重要方面。由于时间序列在时间上是向前索引的,它们会受到季节波动的影响。例如,我们预计冰淇淋销售额在夏季较高,在冬季较低。

季节性可以在不同的时间间隔出现,如几天、几周或几个月。时间序列分析的关键是了解季节性如何影响我们的序列,从而使我们对未来做出更好的预测。

在本帖中,我们将回顾一个季节性数据的例子,然后展示如何删除它。我们想要删除它的原因是为了使我们的时间序列 平稳 ,这是大多数预测模型的要求。如果你想了解更多关于平稳性的知识,请点击这里查看我以前的帖子:

观看季节性

我们可以在下图中观察到 1948-1960 年间美国航空客运量的季节性:

数据来源于拥有 CC0 许可证的 Kaggle 。

作者代码要点。

作者用 Python 生成的图。

数据按月索引,我们可以清楚地看到每年的季节性模式,乘客数量在夏季达到高峰。随着时间的推移,乘客数量也呈现出超常规增长的趋势。

消除季节性

我们可以使用 差分 **,**来消除数据中的季节性,它计算当前值与前一个季节的值之间的差异。这样做的原因是为了使时间序列稳定,使其统计特性随时间保持不变。当我们处于特定的季节时,季节性会导致时间序列的平均值不同。因此,它的统计特性不是恒定的。

季节性差异在数学上被描述为:

作者在 LaTeX 中生成的方程。

其中 d(t) 为时间 ty(t) 为序列在 ty(t-m) 为上一季数据点的值 m 在我们的例子中 m=12 ,因为我们有每年的季节性。

我们可以使用 pandasdiff()方法计算季节差异并绘制出结果序列:

作者代码要点。

作者用 Python 生成的图。

每年的季节性现在已经消失了,然而我们现在观察到一些 周期 。这是另一个共同的特征时间序列,类似于季节性,但通常是在一个更长的时间尺度上,如这里所观察到的。

我们可以使用**扩展的 Dickey-Fuller (ADF)测试来测试结果序列是平稳的。**本检验的零假设是序列是非平稳的。 statsmodels 包提供了执行 ADF 测试的功能:

作者代码要点。

输出:

ADF Statistic:  -3.3830207264924805
P-Value:  0.011551493085514982
Critical Values:1%: -3.485%: -2.8810%: -2.58

P 值 低于 5%10% 阈值,但高于 1% 阈值。因此,根据你的显著性水平,我们可以从统计上确认或否认我们的序列是平稳的。

我们还可以执行一些进一步的规则差分(相邻值之间的差)来进一步降低 P 值。然而,在这种情况下,我认为数据足够稳定,因为它低于 5% 阈值。

稳定方差也是最佳实践,因为这是平稳性的条件之一。为了实现这一点,我们本来可以使用 框考克斯变换 。如果你想了解更多关于稳定方差的知识,请查阅我以前的文章:

**

最后的想法

在这篇文章中,我们已经展示了什么是季节性,以及它看起来像什么。我们可以通过差分来消除季节性,并使用 ADF 检验来确认结果序列是否平稳。

本文的完整 Python 脚本可以在我的 GitHub 中找到:

https://github.com/egorhowell/Medium-Articles/blob/main/Time%20Series/Time%20Series%20Tools/seasonality.py

参考资料和进一步阅读

  • 预测:原理与实践:https://otexts.com/fpp2/
  • https://people . duke . edu/~ rnau/decision 411 _ 2007/class 10 notes . htm

和我联系!

  • 要在媒体上阅读无限的故事,请务必在此注册!T17💜
  • 要想在我发帖注册时得到更新的邮件通知就在这里! 😀
  • LinkedIn👔
  • 推特 🖊
  • github🖥
  • https://www.kaggle.com/egorphysics🏅

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。执照: CC BY-SA 4.0**

使用 Docker 机密保护您的 Docker 图像

原文:https://towardsdatascience.com/secure-your-docker-images-with-docker-secrets-f2b92ec398a0

添加 docker 秘密,以防止您的 docker 图像泄露密码

用秘密锁住你的 Docker 图片(图片由 olieman.eth 在 Unsplash 上提供)

当您将机密信息泄漏到 docker 文件中时,您就将您的映像暴露给了各种攻击者,他们可以窃取您的凭据、控制您的容器,或者将恶意代码注入到您的容器中。这篇文章的重点是为您的 Dockerfile 提供机密信息,而不要在生成的图像中留下任何痕迹。

当您按照本文中的简单步骤操作时,您的映像中不会有任何机密信息。我们将讨论一个完整的示例,最后您将获得一个实现该解决方案的完整 Dockerfile 文件。我们来编码吧!

TL;博士? 向下滚动到“正确的方式——docker 的秘密” 不熟悉 Docker? 查看 此文

我们在解决什么问题?

有时,您需要为 Dockerfile 提供像 API 密钥、凭证或证书这样的机密信息,例如 git 克隆一个私有存储库。

我们需要提供这些信息,而不是将其“烘焙”到图像中。如果您将凭证硬编码到 docker 文件中,或者将您的.env文件复制到映像中,那么您的映像就会被滥用;例如,攻击者可以提取您的凭证或获得对您的容器的访问权限。即使您在 docker 文件中使用了某个文件后将其删除;它仍然存在于图像层中,我们稍后会发现。

解决方案:码头工人的秘密

Docker secrets 允许您在 Docker 文件中使用机密信息,而不会留下任何痕迹。我们将在下一节探讨这是如何工作的以及为什么工作。首先,我们将设置我们的演示。

安装演示

对于本文,我们有一个真正简单的应用程序:myapp.py,它只包含一行代码:print('hello’)。当我们对这个脚本进行 Dockerize 化时,我们的 Dockerfile 可能如下所示:

如果上面的 docker 文件你似乎不熟悉,请先阅读 这篇文章 关于 docker 的基础知识。

我们将使用docker build . -t "my_app"构建图像,并使用docker run my_app运行容器。这只是在命令行上打印“hello”。太好了!一切正常。来介绍一下我们的问题。

添加私人内容

假设我们的 python 应用程序想要使用我们放在私有 pypi 上的名为privatestuff的包。我们可以用下面的 pip 命令安装这个包。

我们如何在 docker 文件中安装这个包?

不好的方法——硬编码

您可能想到的第一件事就是将您的凭证硬编码到 docker 文件中。千万别这样,这只是自找麻烦。

如你所见,我们只在第 4 行增加了一行。在这里,我们指定要安装来自my.pypicom/pypiprivatestuff包。除了将凭证放入我们的映像中,我们还将它们公开给每个有权访问 docker 文件的人。想象一下把这个项目(包含这个 Dockerfile)推给 github 每个人都可以看到您的凭据!

也是不好的方法——构建参数

尽管这看起来是个不错的选择,但它也非常糟糕。查看扩充的 Dockerfile 文件:

如您所见,我们需要三个参数,我们将通过下面的命令提供这些参数:

这将把参数传递给我们的 docker 文件,但是很容易从图像的层中提取它们。当我们检查 docker 图像的历史时,我们甚至可以看到这些值:

上面的命令在我们的映像(名为“my_app”)的 docker 历史中进行搜索。我们用 grep 提取包含单词 PYPI_PASS 的所有文本行。这会以纯文本形式向我们显示我们的凭据!

Docker 历史将显示您的构建参数(图片由作者提供)

稍微好一点,但仍然不好—使用和删除文件

您可能会想到复制并删除带有凭据的 a 文件。在下面的例子中,我们复制了.netrc;pip 将使用该文件中的凭证。然后我们再次删除文件。

https://gist . github . com/Mike-huls/79633 DD 8 ef 466d 040 f 8 c 7c 97 B1 D1 CD 22

在 Docker 中,删除文件实际上并不会将它从映像中删除。因为 Docker 兑现了它的层;所有以前的层仍然存在于图像中。这意味着恶意用户可以轻松提取您的.netrc文件。

照片由蒂姆·莫斯霍尔德在 Unsplash 上拍摄

正确的方法——码头工人的秘密

我们将通过这里的方法不仅是唯一安全的,而且非常容易实现!因为我是.env文件的忠实粉丝,所以我们将在这个例子中使用一个。使用机密有三个简单的步骤:

1.创建一个。环境文件

很简单。我们创建一个名为.env的文件,并赋予它以下内容:

PYPI_URL=my.pypi.com/pypi
PYPI_USER=m.huls
PYPI_PASS=supersecretpassword

更多信息在使用环境文件 这里 更多关于用 Docker 使用 env 变量文件的信息在这里

2.定义我们的 docker 构建命令

我们使用这个命令来构建我们的映像。在这里,我们将步骤 1 中的文件作为秘密传递给 docker files*。*

docker build -t "my_app" --secret id=my_env,src=.env .

你可以看到上面的命令:加载.env文件,并给它一个名为my_env的键。我们可以在下一步使用这个键来访问.env

3.修改 Dockerfile,以便它装载机密

这里我们获取并使用我们在docker build命令中传递的文件:

如你所见,我们只是在 docker 文件中添加了一行额外的代码。我们mount a secret指定 id my_env(我们已经在步骤 2 中指定了)。接下来我们将source的内容作为变量加载到.env中。这就是为什么我们可以使用 pip 安装中指定的——extra-index-URL 中的变量。

这种方法的美妙之处在于,.env文件的内容只能在引用它的RUN命令中访问。这就是为什么我们必须使用&&将支架和 pip 安装在一起。RUN 命令完成后,秘密被丢弃,容器中不会留下任何存在的证据。Docker 历史也不会包含任何信息,如下所示。

额外收获:这也是一个正确的方法,但更难实现

您也可以使用两阶段构建;这将首先在一个阶段建立你的形象,然后只复制相关的东西到最后一个,留下所有不需要的信息,包括证书等。查看 这篇文章 了解 Docker 中多阶段构建的更多信息。

结论

在这篇文章中,我们已经经历了 3 种不处理 docker 图像中的秘密的方法和一种更简单、正确、安全的方法。硬编码凭证是非常愚蠢的,build-args 不会救你,甚至删除图像中的凭证文件也会在删除后留在层中。

Docker secrets 是一种非常安全且易于使用的机密信息,一旦使用,就可以将其删除。通过这篇文章,我希望你的 docker 图片更加安全。如果您有建议/澄清,请评论,以便我可以做出改进。同时,看看我的 其他关于各种编程相关主题的文章 ,比如:

  • Docker 适合绝对初学者
  • Docker 为绝对初学者编写
  • 把你的代码变成一个真正的程序:使用 Docker 打包、运行和分发脚本
  • 创建并发布自己的 Python 包
  • 创建您的定制私有 Python 包,您可以从您的 Git 库 PIP 安装该包
  • Python 中的高级多任务处理:应用线程池和进程池并进行基准测试
  • 写你自己的 C 扩展来加速 Python x100
  • 【Cython 入门:如何在 Python 中执行>每秒 17 亿次计算
  • 用 FastAPI 用 5 行代码创建一个快速自动归档、可维护且易于使用的 Python API

编码快乐!

—迈克

页(page 的缩写)学生:比如我正在做的事情?跟我来!

https://mikehuls.medium.com/membership

保护您的公共 Docker 图像

原文:https://towardsdatascience.com/secure-your-public-docker-images-6758f7ddb687

如果计算机病毒应该算作生命,那么我们已经按照自己的形象创造了生命。

照片由通风视图在 Unsplash 上拍摄

您刚刚完成了新的闪亮工具的实现,并准备将其打包到 Docker 容器中,并将其推送到公共存储库中供他人查找。你会怎么做?好吧,如果你的大脑说执行docker push命令,那你就错了!

你如何公证你的身份和你的 docker 图片的完整性?谁能证明他们下载的图片是你的呢?为什么有人要相信你?

当把你的图片推送到一个注册中心,比如 Docker Hub,你的信息会通过一个不可信的媒介:互联网。因此,以某种方式验证 Docker 映像的完整性是至关重要的。

Docker 内容信任(DCT)使您能够验证您正在使用的图像的完整性以及该图像发布者的完整性。因此,DCT 充当反欺骗控制。

https://medium.com/geekculture/the-docker-attack-surface-5184a36a23ca

学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每个月的第一个星期六收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!

Docker 公证服务器

DCT 的第一个组件是 Docker 公证服务器。这个组件就像一个人类公证人,一个被授权在法律事务中执行行为的独立的人。在我们的案例中,Docker 图像就像一个需要公证的法律文件。

为此,您应该获得一个签名密钥,并将其委托给公证服务器来实施图像签名。让我们先把理论搞清楚,看看如何准确地公证任何 Docker 图像。

用 DCT 签名图像

要在 Docker Hub 上推送 Docker 图像之前对其进行签名,您需要部署您的公证服务器并获得签名密钥。

首先,您可以使用两种方法获得签名密钥:

  • 使用命令docker trust key generate NAME生成它
  • 从证书颁发机构(CA)获取它

一旦您有了签名密钥,我们需要部署公证服务器。Docker 公司提供了 Docker 公证服务器,您可以使用docker-compose快速部署它。

接下来,我们需要将密钥委托给 Docker 公证服务器来签署图像。在这一步中,您需要将公钥和私钥都添加到公证服务器。

最后,我们需要强制客户端使用 DCT。这意味着当您通过 Docker CLI 使用pushpull命令时,您只能从注册表中推送和提取已经使用 DCT 签名的映像。

例子

在本演示中,您将设置 DCT 公证服务器,生成签名密钥,并在将 Docker 映像推送到 Docker Hub 之前对其进行签名。让我们首先生成签名密钥。要获取密钥,请运行以下命令:

docker trust key generate NAME — dir ~/.docker/trust

NAME变量可以是你想要的任何东西。这个我会用medium_demo。因此,该命令变成了:

docker trust key generate medium_demo — dir ~/.docker/trust 

如果~/.docker/trust路径不存在,您可以通过从您的/home目录运行以下命令来创建它:

mkdir -p .docker/trust

CLI 将要求您提供密码。你想用什么就用什么,但要确保你会记住它。如果一切顺利,您应该会看到以下消息:

Successfully generated and loaded private key. Corresponding public key available: /home/vagrant/.docker/trust/medium_demo.pub

接下来,您将打开公证服务器。为此,您需要克隆公证服务器 repo:

git clone [https://github.com/theupdateframework/notary.git](https://github.com/theupdateframework/notary.git)

Docker 公证人服务器是一个容器化的应用程序,您可以使用docker-compose来部署它。将您的工作目录更改为您克隆的notary目录,并运行以下命令:

docker-compose up -d

如果您的系统中没有安装“docker-compose ”,请按照文档中的说明进行安装。

接下来,您将添加在本示例开始时生成的密钥。为此,您需要运行以下命令:

docker trust signer add — key PATH NAME ACCOUNT/REPO

让我们分解这个命令:

  • PATH:存储签名密钥的目录。
  • NAME:签名密钥名称
  • ACCOUNT:您的 Docker Hub 账户名称
  • REPO:您的 Docker Hub repo

在我的例子中,命令应该是:

docker trust signer add — key ~/.docker/trust/medium_demo.pub medium_demo dpoulopoulos/ubuntu-hardened

为新的根密钥和存储库密钥提供密码后,您应该会看到以下结果:

Successfully initialized “dpoulopoulos/ubuntu-hardened”
Successfully added signer: medium_demo to dpoulopoulos/ubuntu-hardened

接下来,您需要使用以下命令确保内容信任服务器指向公证服务器:

export DOCKER_CONTENT_TRUST_SERVER=[https://notary.docker.io](https://notary.docker.io)

我们现在准备签署一个图像,并将其推送到 Docker Hub。所以,首先,让我们得到一个图像。为此,您将使用官方的 Ubuntu 映像:

docker pull ubuntu

接下来,相应地标记图像。对我来说,这是:

docker tag ubuntu:latest dpoulopoulos/ubuntu-hardened:v1.0.0

通常,您应该遵循以下格式:

docker tag ubuntu:latest ACCOUNT/REPO:TAG

ACCOUNTREPO变量应该与您之前使用的相同。TAG可以是你想要的任何东西,但是你必须指定一个。

接下来,在我的例子中,为了对图像进行签名,我需要运行以下命令:

docker trust sign dpoulopoulos/ubuntu-hardened:v1.0.0

最后,当我们推进和推送映像时,您需要在 Docker 守护进程上对所有映像操作强制使用 DCT。对于第一次运行:

export DOCKER_CONTENT_TRUST=1

对我来说,推动这个形象:

docker push dpoulopoulos/ubuntu-hardened:v1.0.0

恭喜您,您已经通过本地公证服务器签署了您的 Docker 图像,并将其推送到 Docker Hub!如果您想要检查图像中的 DCT 设置,您可以运行:

docker trust inspect — pretty ACCOUNT/REPO:TAG

结论

保护您的公共 Docker 映像是一项简单的任务,如果您要将这些映像投入生产,这也是一项必要的任务。当然,当您进入生产阶段时,您会希望从 CA 获得您的签名密钥,但是在此之后,过程仍然是相同的。

看起来可能涉及到很多步骤,但是大多数步骤只需执行一次。因此,没有什么可以阻止你签署你的图像,并告诉你的用户,他们可以信任你!

关于作者

我的名字是迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。

如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据操作的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。

所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。

使用 Django 保护您的 Streamlit 应用

原文:https://towardsdatascience.com/secure-your-streamlit-app-with-django-bb0bee2a6519

围绕你的机器学习 web 应用建立一个灵活的认证系统

使用 Django 认证系统保护 Streamlit 应用程序。——照片由来自 Pexels 的蒂姆莫斯霍尔德拍摄

对于数据科学家来说,Streamlit 是一个将他们的工作转化为网络应用的优秀工具。

在之前的一篇文章中,我讨论了围绕 K-Means 聚类创建应用的基础。用户可以更改参数,如集群的数量,并可视化组的变化。

你可以阅读下面的帖子,并访问这个 GitHub repo 的源代码。

在这篇文章和以后的几篇文章中,我想分享一些令人兴奋的方法,我已经解决了一些关于 Stramlit 的挑战性问题。这篇文章解释了如何围绕你的 Stramlit 应用建立一个认证系统。

Streamlit 的认证系统有什么问题?

在使用 Django 之前,让我先说说 Streamlit 的内置认证选项。

Streamlit 还年轻,还在进步。它有一个使用secrets.toml文件认证应用的建议方法。

您在一个 TOML 文件中指定应用程序的用户及其密码,并将其上传到部署环境。然后在应用程序中,放入代码片段进行查找,并匹配密码进行身份验证。

我认为这种方法有三个主要缺点。

首先,在文件中存储密码是不安全的。任何有权访问部署环境的人也可以访问密码。

二是有密码哈希 。存储散列密码是一个好习惯。如果经过哈希处理,即使有人能够读取密码,它也将是原始密码的加密版本。入侵者应该知道使用的散列算法和另一个密钥来解码它。另一个密钥通常很难突破强力方法,因为它是一个很长的字符串——通常大约 64 个字符。

最后,我们需要一个接口来管理用户到平台。在 Streamlit 建议的方法中,如果新用户需要访问系统,开发人员应该将他的凭证添加到 TOML 文件中。

除了这三个原因,无法管理访问控制是我们需要复杂的认证系统的另一个原因。

Django 有一个默认的管理界面来管理用户。它有一个认证机制,通过密码哈希将用户存储在数据库中。所以,让我们利用它。

让我们为 Streamlit 构建一个 Django 验证器。

在本教程中,我将遵循我在上一篇文章中使用的相同项目。您可以使用下面的代码从 GitHub 存储库中克隆它。

git clone [git@github.com](mailto:git@github.com):thuwarakeshm/Streamlit-Intro.git streamdj
cd streamdj# This will create the following project files
.
├── quickstart.py
├── README.md
└── requirements.txt

同样,让我们创建一个虚拟 env 并安装需求。

**$** virtualenv env**$** source env/bin/activate # On Linux
**$** source env\Scripts\activate # on Windowspip install -r requirements

现在让我们在文件夹中创建一个 Django 应用程序。文件夹结构将如下所示。

**$** django-admin startproject config .# The project structure will look like this now
.
├── config
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── quickstart.py
├── README.md
└── requirements.txt

让我们继续创建一个超级用户来管理所有其他用户。

**$** python manage.py migrate
**$** python manage.py createsuperuser# Follow the on-screen instructions to create the user

让我们用**python manage.py runserver**启动服务器,并通过[http://localhost:8000/admin/](http://localhost:8000/admin/)登录到管理门户。

让我们也创建几个用户来测试我们的应用程序。点击用户旁边的小+按钮,添加几个。

通过 Django 管理界面添加新用户来访问我们的 Streamlit 应用程序。—作者截图。

现在,我们的用户已经准备好了。下一步是使用 Django 认证框架,让用户访问 Steramlit 应用程序的私人页面。

向 Django 认证 Streamlit 应用程序。

Django 的 WSGI 应用程序实例应该在我们的 Stramlit 应用程序中运行,这样才能工作。这是 Django 建立数据库连接和认证所必需的。

现在我们需要另一个函数来显示用户名和密码输入字段。我们可以通过将内容wsgi.py复制到运行 Streamlit 的 quickstart 文件中来实现。

由作者编写的代码片段。

这个函数还将调用 Django 的 authenticate 函数。

由作者编写的代码片段。

我们现在需要调用这个函数,并且只有当它返回 True 时才继续执行 Streamlit 应用程序的其余部分。

if if check_password(): # Our regular Streamlit app.

这里是quickstart.py文件的完整版本。

由作者编写的代码片段。

测试身份验证流程

我们的应用现在是安全的。我们需要启动 streamlit 应用程序。让我们试一试。

**$** streamlit run quickstart.py

上述命令应该会启动服务器,并在默认浏览器中打开应用程序。现在,您将看到以下登录页面,而不是您的 Streamlit 应用程序。

基于 Django 认证后端的 Streamlit 登录屏幕——截图由作者提供。

您还可能会看到密码不正确或为空的错误消息。您必须输入正确的用户名和密码组合才能登录并查看您的 streamlit 应用程序。

最后的想法

Streamlit 是数据科学家的绝佳解决方案。它允许围绕他们的机器学习模型创建 web 应用程序,而不用担心 HTML、CSS、JavaScript 和其他 web 开发复杂性。

但是工具还很年轻。因此它的认证特性需要改进。我相信该工具背后令人惊叹的开发团队将很快构建它。

但是目前,为了安全地部署我们的 Streamlit 应用程序,我们可以从一个成熟的 web 开发框架中借用身份验证功能。

在这篇文章中,我们使用 Django 认证来保护 Streamlit 应用。它解决了 Streamlit 建议的方法中缺少的一些关键特性。Django 将密码散列存储在数据库中。此外,我们有一个网络界面来管理用户。

没有访问控制这还不完整。但那是为了以后的帖子。

感谢阅读,朋友!在LinkedInTwitterMedium上跟我打招呼。看来你和我有许多共同的兴趣。

还不是中等会员?请使用此链接 成为会员 因为,在没有额外费用的情况下,我为你引荐赚取一小笔佣金。

保护我们的原型

原文:https://towardsdatascience.com/securing-our-prototypes-2d1f9b21798f

锁定我们的数据科学原型和隐私概念证明

照片由飞:D 在 Unsplash

网络安全和信息保护成为焦点,因为看起来像是不断传来的网络攻击和数据泄露。小型原型或概念验证应用程序可能成为攻击目标,并涉及数据泄露。我们继续一系列关于帮助求职者将他们的简历与招聘信息相匹配的文章。该项目可以同时处理 个人数据敏感个人数据。我的全新 NLP 和数据科学支持的简历服务的第一个重要特征是安全性。

这是到目前为止的整个系列,还有更多。这些文章涵盖了孕育这个想法所需的研究和原型制作工作。

  • 利用 NLP 改善简历:对职位描述进行关键词匹配和文本分析。一篇有很多参与和讨论的受欢迎的文章。
  • 使用 Python 后端:用于 NLP 的 Python Flask 和 Vue.js。用 Vue.js 前端构建 Flask 后端服务器,避免 CORS 和 docker 容器编排问题。
  • 语义高亮:为 NLP 构建并添加一个用户界面,使用 vue-text-highlight 节点包在屏幕上高亮显示给定的文本。思考过程是为用户突出关键词或关键句子,以帮助更新简历。
  • 向求职者展示自然语言处理:一个简短的演示,演示如何从前端获取一段文本,执行关键词提取,并为用户突出显示关键词。
  • 处理非结构化数据:考虑到数据量和高需求,我们讨论如何使用 Apache Tika 编排工作流并从更广泛的文档中提取文本。
  • 法斯塔皮对弗拉斯克:这是怎么回事?我们不是已经有姜戈了吗!。考虑 web 框架、微服务和后端 API,什么是服务 NLP 例程的最佳架构?

本文将展示我在原型中经常使用的一种提供身份验证的技术。身份验证发生在前端,只有经过授权的用户才能调用后端 API 端点。由 @vivekmadurai 撰写的文章认证 Web 应用程序的不同方法为认证提供了一个很好的解释。然而,我更喜欢使用第三方访问(OAuth,API-token)方法,使用 Auth0 。

网络安全

Web 应用程序安全性是一个重要的话题,有各种各样的过程和方法来保护应用程序和 API 免受不良分子的攻击。认证就是这样一种验证个人身份的过程。授权是另一个方面,它是通过指定的角色和权限来控制用户访问的过程。我们需要验证所有用户,仔细检查权限,并在处理个人或敏感个人数据时快速注销非活动会话。这类数据有很多问题,尤其是静态或传输中的加密。

有许多关于身份验证的文章,我倾向于将这些方法分为两个不同的类别

  • 从头开始创建用户数据库、登录、注销和注册过程,或者使用特定 web 框架的可用扩展。
  • 使用第三方提供商。

从头开始开发身份验证方法似乎是一个完全的目标置换。然而,请记住,我的兴趣是为我的潜在客户构建 NLP 服务。因此,我使用一个第三方提供商,提供我正在使用的语言所需的 SDK(Python 和带有 Vue.js 的 Node),对我来说是 Auth0。

将 Auth0 集成到 FastAPI 和 Vue.js 中

由于我很难宣称自己是安全专家,能力甚至是一种延伸;我使用了一篇博客文章、可用的代码示例和 python 的 SDK。

https://auth0.com/blog/build-and-secure-fastapi-server-with-auth0/

vue.js 有一个入门应用程序,就像放入一个安全的基础,然后在上面构建组件、服务和视图,这非常有吸引力。科学不是重新发明轮子!

https://auth0.com/blog/complete-guide-to-vue-user-authentication/

鉴于这些文章的质量,我觉得我没有必要写太多,除了在处理第一部分时反思我的经历。

保护 NLP 操作的 FastAPI 端点

没过多久我就遇到了阻碍,我花了很多时间来找出我做错了什么。 Github 库包含代码,还有三种不同后端方法的文件:-

  • 烧瓶与 vue 通过预建的 dist 文件夹( backend.py )
  • FastAPI 带 vue 带预建策略( main.py )
  • 带有 Auth0 和预建 vue 策略的 FastAPI(main auth 0 . py)

该问题在下图中显而易见

运行 main.py(未经身份验证的 FastAPI 按作者分类的图像

Main.py 定义了两条路由。一个是对“/”调用进行 FileResponse,然后是一个不安全的端点“/API/public”,它应该返回一个 JSON 响应对象。但是服务器对于不安全的端点返回 404 Not Found ,对我来说一点意义都没有。

由视觉效果在 Unsplash 上拍摄的照片

经过一段时间的反复试验,我发现了这个问题

app.mount("/", StaticFiles(directory="./dist",html=True), name="static")

app mount 似乎已经产生了使实例成为子应用程序并将其限制为静态文件服务器的效果。即使文档中另有暗示,如下面的屏幕截图所示。

显示两个端点的 main.py 的 Swagger UI 视图——作者图片

我接受了这个设计,并试图调和 Flask 的显著差异,以绕过这个障碍。在 mainAuth0.py 中,我更改了子应用程序的概念来解决这个问题。

app = FastAPI()
appVue = FastAPI()
appVue.mount("/", StaticFiles(directory="./dist",html=True), name="static")@appVue.get("/")async def home():    return FileResponse("index.html")

子应用程序 appVue 是为前端 HTML 和相关的静态文件保留的,这看起来是一种简洁的方法。接下来,定义一个新的子应用 app,负责服务前端调用。

@app.get("/api/public")
def public():    ....return JSONResponse(content=json_compatible)

运行 mainAuth0.py 并访问 swagger UI

mainAuth0.py 显示两个端点的 swagger UI 视图

我们看到一个公共和私有端点。所以现在我们准备保护私有的。我仔细阅读了 Auth0 代码示例,只遇到了一个小问题。我拼错了我的一个秘密,让 Auth0 燃烧了更多的时间。以下是一些亮点

from fastapi.security import HTTPBearer  
token_auth_scheme = HTTPBearer()

这些行有助于从请求头中获取授权承载令牌。如果没有标头或承载令牌,HTTPBearer 将返回“未授权”

from utils import VerifyToken
result = VerifyToken(token.credentials).verify()

VerifyToken 是一个直接来自 Auth0 的类,代码显示了如何使用该类来验证给定的令牌。

综上所述,我们看到了一个安全的端点。您需要一个 Auth0 帐户,并且必须按照教程中的步骤注册一个 API。我使用 curl 从 Auth0 获取一个不记名令牌来测试我的安全端点。

首先,我尝试了一个无效的令牌,看看我得到了什么!

curl -X 'GET' \--url 'http://127.0.0.1:8000/api/private' \--header 'Authorization: Bearer FastAPI is awesome' 

终端窗口——使用 curl 向安全端点发送错误代码

向端点发送正确的令牌展示了期望的回报。

我使用 curl 测试了一个具有正确的 JWT 不记名令牌的安全端点。

NLP 项目现在使用 Auth0,我们可以保护 FastAPI 路由。在下面的文章中,我们将把 Vue.js 前端与 Auth0 连接起来,使用户能够注册、登录、注销、检索令牌,并在授权头中将令牌传递给后端。

一个意想不到的 404 让我损失了很多时间,但是写这个我学到了很多。大多数情况下,复制粘贴比手工输入你的秘密要好。

在 Unsplash 上由 Aron 视觉拍摄的照片

https://cognitivedave.medium.com/membership

用数据科学抓住商业中唾手可得的果实

原文:https://towardsdatascience.com/seizing-the-low-hanging-fruit-in-business-with-data-science-7b3a3265e07e

今天,我想分享一个看似常识却常常被忽视的数据科学发现

企业只需在不起作用的项目上削减预算,就能获得巨大的增长机会——这是商业中唾手可得的果实。

我曾经在一家初创公司担任数据科学家。这家初创公司的大部分收入来自内部销售线索。尽管每天都有令人满意的销售线索,但转化率并不理想。出于对如何用有限的资源提高转化率和收入的好奇,我启动了一个领先评分项目来寻找最有可能转化的潜在群体。

在从数据中获得任何有意义的见解之前,我预计会花几周时间建立数据管道并运行机器学习模型。因为,如你所知,一个领先的评分项目需要付出巨大的努力。

令人惊讶的是,在我汇总数据后不久,我发现了一些有趣的事情——数据表明该公司应该忽略至少 80%的入站销售线索。这些线索通常来自明显买不起该产品的潜在客户——一旦销售团队在一个地方看到所有访问者的属性,他们就可以很快判断出谁永远不会转换。

例如,指标 A 被证明是预测转化率的关键指标。虽然高指标 A 不能保证成交,但低指标 A 表示成交亏损,如下图所示。

作者图片

然而,销售团队花了 50%的时间——如果不是更多的话——来追逐 orange 队列。为什么?团队面前没有潜在客户的完整图片。

一旦公司实施了销售线索评分系统来指导销售工作,销售效率在三个月内就提高了两倍。销售团队不再关注那些低质量的销售线索,而是达成了更多和更大的交易。

后来,当我在各种公司(包括 B2B 和 B2C)从事更多数据科学项目时,我注意到了这种重复的模式。例如,许多公司的广告活动表现如下图所示:很大一部分预算花在了几乎没有回报的活动上。应该立即关闭这些活动。

作者图片

一旦一家公司削减了表现不佳的营销活动或其他举措,它就会立即为高潜力的飞行员提供更长的跑道。

在当前充满不确定性的经济形势下,用更少的资源创造更多的收入比以往任何时候都更加重要。

你可能会问,为什么公司会继续把钱花在没有前途的东西上。他们不会的。一旦看到业绩的全貌,大多数高管会迅速采取行动,削减停滞举措的支出。然而,问题是直到他们已经浪费了数万美元,如果不是数百万美元,他们才有这样的照片。以营销数据为例;在一家积极开展营销活动的公司中,数据流如下所示。

作者图片

如果没有专门的头脑和数据战略方面的努力,大多数公司不会对其业务绩效有一个整体的看法。因此,减少浪费在表现不佳的计划上的资源的机会永远不会到达高管手中。许多公司将数据科学视为必需品,在高管们无法理解什么可行、什么不可行及其原因之前,不会投资于分析。

相反,数据科学是每个公司的关键路径,即获取客户。

对每家公司来说,实时监控业务表现并迅速停止有负回报的计划是唾手可得的事情。这将给公司更多的时间和现金来度过不稳定的经济。

你可以阅读数据战略中的点点滴滴,了解更多如何抓住低垂的果实。在接下来的文章中,我将讨论如何进行实验,以及如何用数据来识别在商业中起作用的东西。敬请期待!

使用 loc & iloc 轻松选择 Python Pandas 中的数据

原文:https://towardsdatascience.com/select-data-in-python-pandas-easily-with-loc-iloc-c6e8bc979e3e

计算机编程语言

使用 loc & iloc 轻松选择 Python Pandas 中的数据

5 分钟内掌握 Python 中的 loc 和 iloc

塔妮娅·马雷·肖菲在 Unsplash 上拍摄的照片

Python 的 Pandas 库是一个非常强大的处理表格数据的库。在 Python 中,表格数据存储在 Pandas DataFrame 中。时不时地,我们需要选择数据的某一部分供我们使用。

随时加入我的电子邮件列表 获取免费每当我写了一个新的故事时都会收到通知!!⚡

lociloc是用于过滤、选择和操作数据的基本方法。它们快捷、快速、易读,有时还可以互换。

在本文中,我们将探索如何用lociloc执行数据选择。我们将讨论以下主题:

 · [Difference between loc() and iloc() in Pandas DataFrame](#7f03)
· [Select Multiple Rows and Columns](#2de7)
· [Slicing Rows](#9597)
· [Extract Subset of Pandas DataFrame based on Conditions](#eecc)
· [Create a New Column based on 1 condition](#7f15)
· [Create a New Column based on Multiple Conditions](#2b27) 

让我们使用 data.world 上可用的太阳能发电厂数据,并从用read_excel()读取熊猫数据框中的数据开始。为了方便起见,我还更改了一个列名。

import pandas as pd
url = '[https://query.data.world/s/xgoscc46yofwpqz6qzquyf6kd7bo33'](https://query.data.world/s/xgoscc46yofwpqz6qzquyf6kd7bo33')
df = pd.read_excel(url)df.rename(columns={'MWp (Megawatts Peak Capacity)': 'MWp_Capacity'},inplace=True)df.head()

来自改头换面星期一的开源数据|作者图片

这是一个 20 行 x 7 列的小型数据集。这是一个来自 makeovermonday.co.uk 的开源数据,可以免费共享和用于项目。数据来源是维基百科。https://www.makeovermonday.co.uk/data/安迪·克里贝尔将数据上传到 data.world。

Pandas 数据帧中 loc()和 iloc()的区别

两者都用于数据切片,即从熊猫数据帧中提取数据子集。但是它们访问数据的方式有一个关键的区别,如下图所示!

作者图片

让我们从数据帧的 Name 列中获取前 5 行。

如何使用。loc()和。iloc()用于选择熊猫|作者图片中的数据

错过了什么??🚩

另一个关键区别是,**.iloc()**方法不像**.loc()**那样包含传递给它的范围的最后一个元素

选择多行和多列

要选择多个行和列,我们可以将它们的索引列表传递给.iloc(),或者将它们的标签列表传递给.loc()

例如,从数据集中选择第 3、第 7、第 10 行和列*Country**Year*

df.loc[[3,7,10], ["Country", "Year"]]

按作者选择子集|图像

通过用索引 1 和 6 分别替换列名 Country 和 Year,可以使用**df.iloc()**获得相同的输出。

另一个例子,从第 10 行到第 15 行,从第 3 列到第 5 列。这可以通过使用。iloc(),因为我们对特定索引处的行和列直接感兴趣。

df.iloc[9:15, 2:5]

df.iloc() |作者图片

切片行

最健壮和一致的行切片方式是使用**.iloc()**

例如,可以通过简单地书写来选择前三行

df.iloc[:3]

切片熊猫数据帧按行|图片按作者

因为我们没有为列传递任何索引,所以选择了数据帧中的所有列。

当然,这可以通过只写df[:3]来实现。

但是选择第一、第七和第八排的❗❗怎么样

在这种情况下,df[0,6,7]将抛出一个KeyError,但是**df.iloc[[0,6,7]]**将完成这项工作,如下所示。

使用 df.iloc() | Image by Author 选择熊猫数据帧的子集

🚩请记住,在 Python 中,索引从 0 开始,即第一行或第一列的索引总是为 0,除非特别更改。

此外,还可以选择和提取第 1、第 3、第 5 等交替行。

df.iloc[1::2]

在 Python 中选择熊猫数据帧的交替行|作者图片

最终,您需要将行索引传递给.iloc()方法。

基于条件提取熊猫数据帧子集

通常,我们需要根据一个或多个条件提取数据帧的子集。使用.loc()可以轻松完成这项任务。⚡

如果是一个条件,我们可以将条件传递给如下所示的.loc()方法。

df.loc[**df["Acres"]>5000**]

作者基于条件|图像提取数据帧的子集

如果单个列甚至多个列有多个条件,只需在用**&**分隔的.loc()中指定逻辑**and**和用**|**分隔的逻辑**or**即可。

🚩不要忘记用括号**( )**将每个条件括起来

例如,选择数据的子集,其中*Acres*中的值大于 5000 或者*MWp_Capacity*列中的值大于 2000。

df.loc[**(df["Acres"]>5000) | (df["MWp_Capacity"]>2000)**]

基于多种条件选择熊猫数据帧的子集|图片由作者提供

这是一个逻辑**or** 的例子。类似地,可以使用逻辑**and**提取子集。

基于 1 个条件创建新列

有时,您需要基于一列中的值创建一个新列。使用.loc()方法可以非常快速有效地完成这项工作。

语法非常简单明了。

Dataframe_name.loc[**condition, new_column_name**] = **new_column_value**

如果.loc()中的**condition**,则**new_column_value**为新列中分配的值。

例如,基于我们的熊猫数据框架中的*Acres*列创建一个列*Size*

df.loc[df["Acres"]>5000, "Size"] = "Large"
df.head()

使用 df.loc() | Image by Author 创建新列

正如我们在上面的结果中看到的,对于条件,即*Acres*列中的值小于 5000 的行,在*Size*列中添加了NaN

基于多个条件创建新列

故事并没有到此结束。

我们可以在.loc()方法中添加多个条件,并基于多个条件创建一个新列。

例如,基于*Acres**MWp_Capacity*中的值创建一个名为*Powerful*的列

基于多个条件的熊猫数据框架中的新列|作者图片

所有缺失值,即NaN可使用fillna()单独处理。

仅供参考,缺失值可按如下方式填写。♻️

使用 fillna()在 Pandas DataFrame | Image by Author 中填充缺失值

尺寸栏中的NaN用“小”填充,强力栏中的NaN用“否”填充。

总结一下,

数据科学家最耗时的任务是清理和处理真实世界的数据。因此,在从数据帧访问数据时具有灵活性是很重要的。

loc()iloc() 方法提供了我们在 Python 中提取熊猫数据帧的行和列所需的所有工具。

通过这五个例子,我试图涵盖用 Python 掌握熊猫数据帧切片的所有可能的方法。如果我错过了什么,请告诉我。

如果你喜欢阅读这样的文章,今天就成为 中的一员 。只需每月 5 美元,你就可以无限制地访问 Medium &我将得到其中的一小部分。尽管如此,你可以随时免费订阅我的邮箱列表

感谢您的阅读和投资时间!!!

为数据网格选择正确的数据目录

原文:https://towardsdatascience.com/selecting-the-right-data-catalog-for-a-data-mesh-96cc2a45c939

没有一种工具可以用来实现数据网格,但是基于知识图的数据目录使您能够在整个组织中处理数据

图片由来自 Pexels.com 的梅福迪提供

2019 年,Thoughtworks 顾问 Zhamak Dehghani 创造了“数据网格”一词,业界迅速将其视为数据架构的下一件大事。Zhamak 的社会技术方法结合了产品思维和领域驱动的数据管理,组织收集、管理和共享数据。此外,它使领域专家能够拥有他们创建的数据,并跨业务线提供给消费者

当数据网格的概念被引入并且它的好处变得明显时,许多处理大量数据并且旨在变得更加数据驱动的组织开始实施它,一些组织比其他组织取得了更大的成功。

没有一种工具本身可以用来实现数据网格;整个堆栈中的工具需要紧密协调。数据目录是其中的一个主要组成部分,有助于这种协调。但是,面向关系模式和机器学习的传统数据目录将难以胜任这一角色。

我在这里解释为什么简单的机器学习目录虽然有用,但不是创建数据网格驱动的文化和架构的灵丹妙药,以及为什么更好的选择是建立一个由基于知识图的数据目录支撑的数据网格环境。

什么构成了数据网?

根据公认的定义,数据网格是一种社会技术架构,它建立了您如何组织业务中的人员、团队和工作组;你如何组织和分享数据本身;以及如何构建底层架构来支持独立性和敏捷性,同时仍然支持所有数据资产的跨域利用。

非常明确的一点是,数据网格不是一种可以购买的工具,而是一种构建数据治理架构的方式,它对组织和运营结构的依赖程度至少与对数据堆栈中的工具的依赖程度一样。

虽然数据网格哲学有 4 个关键原则,但如果您只是简单地从流程和工具的角度来考虑,您的选择可以分为两类:

你如何组织你的数据:

真正的域独立性和所有权意味着每个域都可以按照他们认为合适的方式定义自己的数据。在这个框架中,每个领域的数据管理者负责按照组织的联合治理标准构建和维护数据产品。数据管家还负责使用自助式数据架构向其他领域的消费者提供他们的产品。

你用什么工具让你的数据可以被普遍访问:

尽管每个域所有者都可以按照自己的意愿定义产品,但是数据治理的某些方面需要在整个组织中实现标准化,以确保域之间的互操作性。这种标准化被称为联邦计算治理。

在工具和技术方面,您需要一个组织范围的自助式数据平台,为每个域的所有者提供独立于域的数据收集、管理、分发和分析功能。

为什么机器学习本身不是灵丹妙药

现在,我已经建立了数据网格的定义,描述了它的工作方式,并确定了它成功所需的组件,我将解释为什么机器学习数据目录不是实现数据网格工具链所需的全部。

机器学习数据目录的好处在于,它们有助于发现、治理和监管——识别列中的数据类型、重定标题、标记错误或不一致等。—并帮助您更快、更高效地了解您拥有哪些数据。

当然是有用的功能。但是,尽管它们有用,即使是最先进的机器学习数据目录也不具备实现数据网格的能力。

大多数机器学习目录功能仅限于单个领域,这意味着它们不能作为一个整体在整个企业中运行,完全孤立了数据和数据团队。这是数据网格的对立面:它不能帮助你跨越组织边界;它没有帮助你把数据当成一个产品;它也不能帮助你真正操作这些数据产品。

如果您在一个域中操作,并且整个业务有一个简单的数据仓库和一个公共模式,这就很好了。但是对于大规模的企业来说,这是不现实的,也不能帮助你建立一个组织范围的自助式架构。它还会限制您的业务灵活性,并产生新的孤岛或瓶颈。即使为组织中的每个领域配备自己的机器学习数据目录也无济于事;相反,它会进一步孤立您的数据,并强化任何已经存在的孤岛。

不幸的是,机器学习数据目录给你留下了一个痛苦的选择:你是强迫每个领域在一个严格的公共模型中运行并失去敏捷性,还是给每个领域配备自己的机器学习数据目录并失去互操作性和联合治理?

知识图表如何帮助解决问题

还有第三种选择,那就是选择一个建立在知识图上的数据目录。

基于知识图的数据目录远远超出了简单地根据简单的模式重新标记数据,打破了领域之间的障碍,真正构建了跨整个企业的语义层。它们允许每个域拥有自己的元数据模型,并在不需要大规模软件重新部署的情况下实现跨组织的敏捷性。而且,因为它们是无限可扩展的,所以它们允许您随着时间的推移添加新的域和语义。

基于知识图的数据目录是实现数据网格架构的完美工具,因为它允许真正的联邦互操作性。它允许您跨域查询,而不管底层架构的差异,并且允许您将数据作为产品来管理和处理,而不管域的数据堆栈之间的差异。所有这些意味着您可以跨整个企业管理您的数据,而不必单独管理每个孤岛。

此外,基于知识图表的目录的图表分析可以立即向您更新上游数据故障,使您可以立即进行修补,同时还可以找到继续让您的业务正常运行的数据源。

它们允许业务用户更快、更轻松地识别真正的数据产品所有者并与之交互,可以提供关于您的数据资产用途的实时反馈,并可以提供和接收关于使用哪些数据来解决特定问题的实时建议。所有这些都意味着它们甚至可能带来你以前从未考虑过的商业见解或解决方案。

总之,基于知识图的数据目录使您的业务(即您的整个业务)更加实时地由数据驱动。

知识图或 Bust(ed 互操作性)

对于大型组织和/或处理大量数据的组织来说,在整个企业中启用数据网格架构可以为领域专家和数据所有者提供更大的自主权和灵活性,并为数据专家和业务用户提供自助式基础架构来查找、收集和共享数据。

基于知识图的数据目录是实现数据网格的完美工具,因为它使每个利益相关者能够管理和使用整个组织的数据,所以对于任何试图建立真正的数据驱动型业务的团队来说,这都是一笔巨大的投资。

Tableau 中数字的选择性格式

原文:https://towardsdatascience.com/selective-formatting-of-numbers-in-tableau-f5035cc64b68

这就是如何在同一个数据表中有条件地显示不同的小数位数

Tableau 软件是一个令人惊讶的多功能工具。它不仅提供了广泛的数据可视化选项,而且还是一个强大的报告辅助工具。

我最近在工作中遇到的一个非常有趣的用例涉及到选择性地格式化 Tableau 中一个数据表中的数字。

例如,下表包含 3 个随机选择的国家的疫苗接种率的虚拟值:

作者插图|请注意,红色文本数字是 Tableau 中预期的最终显示值

而 Tableau 使用户能够从侧面板格式化这些数字,以便有选择地显示带有自定义小数位数的数值(。#, #.##等。)或自定义文本(例如,对于小于 65 的值,应改为显示为“65”)在同一个表中,在这种情况下,可考虑在相应的计算字段中使用以下公式。

计算字段:[小数点的位置(。)]

FIND( STR([Vaccination Rates]), '.' )

作者插图|注意字段的值是“3 ”,因为符号位于 3 号位置,如**【3】**所示

用于显示自定义小数位数的计算字段

I)[显示=1 位小数]

LEFT(STR([Vaccination Rates]),[Position Of Decimal (.)]+1
)

**注:**上面的粗体数字代表所需的小数位数(也称为“.”后显示的位数)符号)

作者插图|请注意,在这种情况下,由于只需要 1 位小数(黄色+蓝色),因此新西兰、英国和美国的值分别为 78.5、71.2 和 61.9 。| FYI:公式中的" LEFT()"包括"."之前的所有字符符号。

ii)[显示=两位小数]

LEFT(STR([Vaccination Rates]),[Position Of Decimal (.)]+2
)

**注:**上面的粗体数字代表所需的小数位数(也称为“.”后显示的位数)符号)

作者插图|请注意,在这种情况下,由于需要两位小数(黄色+蓝色),因此新西兰、英国和美国的值分别为 78.55、71.23 和 61.94 。| FYI:公式中的" LEFT()"包括"."之前的所有字符符号。

数字的最终显示

主要假设:

  • 值≥75 时显示 2 个小数位
  • 对于大于 65 但小于 75 的值,只显示 1 位小数
  • 值≤65 总结为'≤65% '
IF [Vaccination Rates] >= 75 THEN [Display=2 Decimal Places]+'%'
ELSEIF [Vaccination Rates] > 65 THEN [Display=1 Decimal Place]+'%'
ELSE '≤65%' END

总之…

作者插图|在 Tableau 的[最终显示值]字段中实现公式后,将其拖动到标记架的[文本]中,上面的内容将根据需要显示。

现在你知道了!非常感谢你坚持到这篇文章的结尾!❤希望你觉得这个指南有用,如果你想了解更多 GIS、数据分析(Tableau-inclusive) & Web 应用相关的内容,请随时关注我的 Medium 。会非常感激—😀

https://geek-cc.medium.com/membership

想了解更多的 Tableau 技巧和窍门,请随意查看下面的帖子:

</5-lesser-known-tableau-tips-tricks-hacks-with-use-case-demo-463f98fbdc7e>

通过音乐实现自我意识

原文:https://towardsdatascience.com/self-awareness-2945ee7ead40

作为指南针的音乐数据

通往真正觉知的道路是通过理解一个人的内在自我。今天就让这条路线通过耳朵。声波触发大脑中的神经元,这将改变大脑的体验…音乐移动,改变情绪,激发灵感。经历这些的人有福了。

我们开始吧。使用 Spotify API 从我的 Spotify 播放列表中提取了 697 首喜欢的歌曲,并用 Python 进行了分析。这是意识的第一步。几年前,当我作为一名 MBA 在全球各地推销产品和提出策略时,编程并不是一项技能。然后嘣。想要改变,所以戏剧性地变成了自学编码。今天的博客就是因为这个 reskill。

我的年龄是多少?

他们说你是由你所听的和从根本上联系的东西来定义的。不同的乐队这些年来的趋势,青少年时尚发生…和一些歌曲永远留在你身边。你可以根据人们唱的歌、卡拉 ok 和跳舞的时间来猜测他们的年龄。“宋发行年份”的权重很重要。

作者图片

那是我的,真令人惊讶。播放列表随着最新的出现而扩大。播放列表中的大多数歌曲都是最近几年发行的。那么我的年龄是多少?

我前后一致吗?

分析歌曲被添加到播放列表的顺序给出了一些指示。发行年份(Y 轴)真的不重要,因为它波动很大。我没有随波逐流,但我忠于音乐。这能叫外卖吗?宋的年龄并不重要,唯一的一致性是在添加什么歌曲连接。

作者图片

我在乎别人怎么想吗?

歌曲像病毒一样传播开来,因为很多人都想和其他人一样听同一首歌,而且还有一首 FOMO!!!受欢迎很重要,因为那是风吹的地方。

作者图片

我的播放列表中歌曲的受欢迎程度从“不太受欢迎”到“受欢迎”变化很大。我的播放列表中的平均受欢迎程度是 31.3,范围是 0-100,100 是最受欢迎的。明明不在乎什么流行,别人喜欢什么。

我喜欢的一些已经变得流行,如下所示…

作者图片

我喜欢的一些歌曲得分为 0(在 0-100 分的范围内)…没关系…微笑&继续…听…跟随你的音乐之心。

作者图片

多样性呢?

697 首歌曲跨越了 50 年间 341 位艺术家和 309 个流派。我是吗?…下面的图表有答案。

作者图片

思维的多样性增加了吗?

亲眼看看这些年来流派是如何变化的。明显增加。有些现实可能是因为流派是由听众/艺术家/社会在不断发展的文化中加入的。

作者图片

包容性呢?

这些歌曲跨越了 24 个国家/语言,从斯堪的纳维亚到美国到拉丁美洲,一直到新西兰。音乐是一种很好的旅行方式,根据数据,我是一个包容的旅行者。

作者图片

内在的你……那么重要的是什么?

迄今为止的数据表明……不要在意其他人对流行度的看法,跨社会定义的流派/语言,这意味着这些都不重要。这些是什么适合什么的人为界限。那么什么才是重要的呢?

作者图片

歌曲的内在本质是由能量、可舞性、节奏、语速等特征来定义的。音乐因此而移动。

高节奏、活力、舞蹈性和响度对我来说很重要。句号。根据数据,这就是我的生活。年龄、类型、社会界限都无关紧要。

有没有一个内在的矢量来指引?

让我们看看这些方面,看看是否存在类似的东西。让我们把这首歌的内在特征集中起来。根据肘形法,4–5 是理想的集群数(肘形出现在下图中)。

作者图片

让我们选择 4 个。这就是所有的歌曲如何落入 4 个集群。很明显。这是引导我的内在生命矢量。

作者图片

让我们来计算哪些波段接近这些星团的质心。不同的波段属于这些集群。一些人将歌曲从工业歌曲切换到民谣歌曲时,会跳过集群。

作者图片

我的内心向导是一个矢量

它是我喜欢的所有歌曲的向量。这指引着我。当听到这些确切的音符时,我的神经元被触发。这个向量反映在我的脑海中。每个人都有。

我使用人工智能,把我的矢量变成了一种艺术。社会将像矩阵一样定义严格的边界,然而生命的矢量是一个混乱的散点图,上面覆盖着相连的点。跟着那个。生活是一个向量。

作者图片

生活是我们的,我们以自己的方式生活

所有这些话,我不只是说

其他的都不重要

-其他都不重要,金属乐队

Python 中异常检测的自我监督学习:第 2 部分

原文:https://towardsdatascience.com/self-supervised-learning-for-anomaly-detection-in-python-part-2-5c918b12a1bc

CutPaste:作为核密度估计改进的自我监督学习

兰迪·法特在 Unsplash 上的照片

自我监督学习是现代深度学习研究中最热门的领域之一。正如 Yann Lecun 喜欢说的自我监督学习是智能的暗物质和在人工智能系统中创造常识的方法。这种范式的思想和技术吸引了许多研究者尝试将自我监督学习的应用扩展到新的研究领域。当然,异常检测也不例外。

在本文的第 1 部分 中,我们讨论了异常检测的定义和一种称为核密度估计的技术。KDE 是发现数据集中异常数据点的最流行和最简单的方法之一。它适用于表格数据。然而,我们对图像的实现感兴趣。视觉检测是一种非常受欢迎的应用,其重点是发现我们感兴趣的物体中的缺陷或异常值。

那么,我们如何在不损失太多信息的情况下,通过降低计算成本对图像进行 KDE 呢?

对许多人来说,答案可能是显而易见的:找到一个好的主干,它可以为我们提供图像的良好表示。然后我们可以用这些表象来指挥 KDE。

针对特定用例微调主干的最佳方式是自我监督学习。最近,世界上许多研究人员致力于将自监督学习技术与经典异常检测技术相结合。此外,研究人员提出了全新的转换方法,以改善用于异常检测的自监督学习的托词任务。

在文章的这一部分,我们将讨论 Google 的一种新的自我监督技术 CutPaste[1],并了解一种新的创造性的数据转换方法如何提高训练结果。

剪切膏的主要成分包括:

  1. 新改进的借口任务
  2. 自监督模型结构

剪贴和疤痕剪贴

一种非常流行的自我监督的借口任务被称为 Cutout。顾名思义,它从一幅图像中随机剪切出一小块矩形区域。这在许多自我监督的环境中工作得很好,并作为数据扩充。这似乎是异常检测用例的一个很好的模拟。

该论文的研究人员提出了这种技术的一种新变体,称为 CatPaste,它从图像中复制一小部分,并将其替换到其他地方。它产生局部不规则性,这似乎与异常检测问题设置完全一致。

这种托辞任务的另一种变体叫做剪切疤痕,它是对原始疤痕剪切技术的改进。在最初的疤痕剪切中,我们从图像中取出一个细长的矩形块,并用随机颜色替换它。在这种情况下,我们从图像中使用一个类似疤痕的矩形补丁,并再次将其随机插入图像中的其他位置。

点击 GitHub 链接查看 PyTorch 中的 CutPaste 和 Scar-CutPaste 实现。

看起来像是托词任务定义的一个小变化。然而,实验结果表明,该方法提高了最终异常检测的结果。下图展示了一些剪贴和疤痕剪贴的例子。我们可以注意到,在某些情况下,它可能看起来像是物体中的真正缺陷。

图片来源于论文[1]。参见参考文献

这是否意味着从剪切粘贴中创建的缺陷是对原始缺陷的良好模拟?为了回答这个问题,作者展示了切割糊、疤痕切割糊、正常和异常样品的 t-SNE 图。下图显示,在大多数情况下,借口任务不会与异常重叠,因此我们可以说它不是真实异常的良好模拟。然而,训练结果表明,尽管存在分布差异,但这些变换有助于为异常检测创建更好的表示。

正常、异常、切割糊和疤痕切割糊样本的 t-SNE 图。图片来源于论文[1]。参见参考文献

自监督模型结构

最初使用 ResNet-18 来创建模型。接下来,添加 MLP 投影头,然后是输出表示的最后一个线性层。

代码来自:【https://github.com/LilitYolyan/CutPaste

进行了两种类型的实验:二元分类和三元分类。

在第一种情况下,模型使用原始图像,并使用 CutPaste 或 CutPaste-Scar 随机变换它。然后,原始图像和变换后的图像成为两个不同的类别,我们在此基础上进行二值分类。

接下来,是三向分类技术,其中我们不是随机使用 Cutpaste 和 CutPaste-Scar,而是将两者作为单独的类使用,并且我们添加 normal 类作为第三个类。最后,我们把它分为三类。

在本例中,我们的 CutPaste 对象可以根据分类类型返回转换后的图像:

代码来自:https://github.com/LilitYolyan/CutPaste

损失是交叉熵,其中 CP(.)是图像的剪切粘贴变换。

参考

[1]李,孙春亮,Kihyuk 和 Yoon,Jinsung 和 Pfister,托马斯.(2021). CutPaste:用于异常检测和定位的自我监督学习。

点击 Github 的代码链接

在这里可以找到文章的第 1 部分:Python 中异常检测的核密度估计

自我监督学习(SSL)概述

原文:https://towardsdatascience.com/self-supervised-learning-ssl-overview-8a7f24740e40

为什么重要,它是什么&不同类型的自我监督学习

机器人是“自我监督”的。布雷特·乔丹在 Unsplash 上的照片。

“自我监督学习”一词来源于 Yann le Cun 2019 年 4 月 30 日的语录(推文和帖子):

我现在称之为“自我监督的学习”,因为“无监督的”是一个令人困惑的术语。

在这篇文章中,我将解释它是什么,为什么它很重要,它可以如何使用,以及不同类别的自我监督学习在多个领域,包括文本,图像,语音/音频和图形。

什么是自我监督学习?

自监督学习是无监督学习下的一个子类,因为它利用了未标记的数据。关键思想是允许模型在没有手动标签的情况下学习数据表示。一旦模型学会了如何表示数据,那么它就可以用更少量的标记数据用于下游任务,以实现与没有自我监督学习的模型相似或更好的性能。

它有三个步骤:

  1. 基于对数据的理解,通过编程从未标记的数据生成输入数据和标签
  2. 预训练:使用上一步中的数据/标签训练模型
  3. 微调:使用预先训练的模型作为初始权重来训练感兴趣的任务

如果我们在第二步中使用带有手动标签的数据,而不是自动生成的标签,这将是受监督的预训练,称为迁移学习的一个步骤。

为什么自我监督学习很重要?

自我监督学习已经在多个领域获得成功,例如文本、图像/视频、语音和图形。本质上,自我监督学习挖掘未标记的数据并提高性能。就像 Yann Lecun 的蛋糕(视频,幻灯片)的比喻一样,这种自我监督的学习(蛋糕 génoise)可以对每个样本进行数百万次咬入,而监督学习(糖衣)只能进行 10 到 10,000 次咬入。也就是说,自监督学习比监督学习能从每个样本中获得更多有用的信息。

人工生成的标签通常关注数据的特定视图。例如,我们可以只用一个术语“马”来描述草地上的一匹马的图像(如下图所示),用于图像识别,并提供语义分割的像素坐标。然而,数据中有更多的信息,例如,马的头和尾巴在身体的另一侧,或者马通常在草的顶部(而不是下面)。模型可以直接从数据中学习更好和更复杂的表示,而不是手动标注。更不用说手工标签有时会出错,这对模型是有害的。一项实验显示清理 PASCAL 数据集可以提高 MAP 13。即使不与最先进的技术相比,我们仍然可以看到错误的标签可能会导致更差的性能。

由大卫·迪伯特在 Unsplash 上拍摄。

数据标注成本高、耗时且劳动强度大。此外,监督学习方法将需要针对新数据/标签和新任务的不同标签。更重要的是,已经表明,对于基于图像的任务(即,图像识别、对象检测、语义分割),自我监督预训练甚至优于监督预训练。换句话说,直接从数据中提取信息比手工标注更有帮助。那么,根据任务的不同,现在或在不久的将来,我们可能不需要许多昂贵的标签和更先进的自我监督学习。

自监督学习的优越性在基于图像的任务中得到了验证,这得益于图像领域中的大规模标记数据集,在最近的深度学习趋势中,图像领域比其他领域具有更长的历史。我相信类似的优势将来也会在其他领域得到证明。因此,自我监督学习对于推进机器学习领域至关重要。

怎么用?

通常,当一个自我监督的模型发布时,我们可以下载预先训练好的模型。然后,我们可以对预先训练的模型进行微调,并将微调后的模型用于特定的下游任务。例如,最著名的自我监督学习的例子可能是 BERT ( ref )。伯特以自我监督学习的方式接受了 33 亿单词的预训练。我们可以针对文本相关的任务(如句子分类)对 BERT 进行微调,与从头开始训练模型相比,所需的精力和数据要少得多。基于一个经过微调的 BERT 模型,我开发了一个应用程序,用于预测一条推文信息是否来自拥抱脸的埃隆·马斯克(链接)。我会单独写一篇关于我如何创建它的文章。随意摆弄,玩得开心!

自我监督学习有哪些类别?

让我用几句话描述一下每一个类别,稍后再深入研究每一个类别。

  1. 生成方法:恢复原始信息
    a .非自回归:屏蔽一个记号/像素并预测被屏蔽的记号/像素(如屏蔽语言建模(MLM))
    b .自回归:预测下一个记号/像素
  2. 预测任务:基于对数据的理解、聚类或扩充来设计标签
    a:预测上下文(例如,预测图像块的相对位置,预测下一个片段是否是下一个句子)
    b:预测每个样本的聚类 id
    c:预测图像旋转角度
  3. 对比学习(又名对比实例辨别):基于增强创建的正负样本对建立一个二元分类问题
  4. 自举 方法:使用两个相似但不同的网络从相同样本的扩充对中学习相同的表示
  5. 正则化:基于假设/直觉增加损失和正则化项:
    a:阳性对应该相似
    b:同一批次不同样本的输出应该不同

生成方法

图片由作者提供。

通过周围数据预测屏蔽输入是最早的自我监督方法类别。这个想法实际上可以追溯到这句名言,“你应该通过一个人交的朋友来了解这个人。”—约翰·鲁伯特·弗斯(1957),语言学家。这一系列算法是从 2013 年文本领域的 word2vec ( ref )开始的。word2vec 的连续词包(CBOW)的概念是通过其邻居预测一个中心词,这与 ELMo ( ref )和 BERT ( ref )的掩蔽语言建模(MLM)非常相似。这些模型都被归类为非自回归生成方法。主要区别在于,后来的模型使用了更高级的结构,如双向 LSTM(用于 ELMo)和 transformer(用于 BERT),而最近的模型生成了上下文嵌入。

在语音领域,Mockingjay ( ref )屏蔽了连续特征的所有维度,TERA ( ref )屏蔽了特征维度的特定子集。在图像领域,OpenAI 应用了 BERT 的方案(参考)。在图形区域,GPT-GNN 也屏蔽了属性和边缘。这些方法都屏蔽了部分输入数据,并试图将其预测回来。

另一方面,另一种生成方法是预测下一个标记/像素/声学特征。在文本领域,GPT 系列车型(ref&refref)是这一类别的先驱。APC ( ref )和 ImageGPT ( ref )分别在语音和图像领域应用了相同的思想。有趣的是,因为相邻的声学特征很容易预测,所以模型通常被要求预测后面序列中的记号(至少 3 个记号之外)。

自我监督学习(尤其是伯特/GPT)的巨大成功促使研究人员将类似的生成方法应用于图像和语音等其他领域。然而,对于图像和语音数据,生成屏蔽输入更难,因为选择有限数量的文本标记比选择无限数量的图像像素/声学特征更容易。性能改进不如文本字段。因此,研究人员在接下来的会议中还开发了许多其他非生成性方法。

预测任务

图片由作者提供。

主要想法是设计更简化的目标/指标,以避免数据生成。最关键也是最具挑战性的一点是,任务需要达到模型学习的适当难度水平。

例如,在预测文本字段中的上下文时,BERT 和 ALBERT 都预测下一个片段是否是下一个句子。BERT 通过将下一个片段与另一个片段随机交换来提供负训练样本(下一句预测;NSP)而阿尔伯特通过交换前一个和下一个片段(句序预测;SOP)。SOP 的表现已经超过了 NSP ( 参考)。一种解释是,通过话题预测区分随机句子对是如此容易,以至于该模型没有从 NSP 任务中学到多少东西;而 SOP 允许模型学习一致性关系。因此,需要领域知识来设计好的任务,并通过实验来验证任务的效率。

类似 SOP 的预测上下文的思想也被应用于图像域(预测图像块的相对位置(参考))和语音域(预测两个声学特征组之间的时间间隔(参考))。

另一种方法是通过聚类来生成标签。在图像字段中,DeepCluster 应用了 k 均值聚类(参考)。在语音领域,HuBERT 应用了 k 均值聚类(参考),BEST-RQ 采用了随机投影量化器(参考)。

图像领域的其他任务有:通过图像的颜色通道预测灰度通道(反之亦然; ref ),重建图像的随机剪切块(即修复; ref 、重建原始分辨率的图像( ref )、预测图像的旋转角度( ref )、预测图像的颜色( ref1 、 ref2 、 ref3 )以及解决拼图( ref )。

对比学习(对比实例辨别)

图片由作者提供。

对比学习的关键概念是在理解数据的基础上产生正负训练样本对。该模型需要学习一个函数,使得两个阳性样本具有高相似性得分,而两个阴性样本具有低相似性得分。因此,适当的样本生成对于确保模型了解数据的基本特征/结构至关重要。

图像领域中的对比学习应用来自同一原始图像的两个不同的数据扩充来生成正样本对,并且使用两个不同的图像作为负样本对。两个最关键和最具挑战性的部分是扩增的强度和阴性样本对的选择。如果增强太强,以至于来自同一样本的两个增强样本之间没有关系,则模型无法学习。类似地,如果增加量很小,以至于模型可以很容易地解决问题,那么模型也不能学习对下游任务有用的信息。至于选择负样本对,如果我们随机分配两幅图像作为负样本对,它们可以是相同的类别(例如,猫的两幅图像),这将冲突噪声引入到模型中。如果负对非常容易区分,那么模型不能学习数据的潜在特征/结构。对比学习最著名的例子是 SimCLR ( v1 、 v2 )和 MoCo ( v1 、 v2 )。

至于语音领域,一种方法是应用类似 SimCLR ( Speech SimCLR )的增强。另一种方法是使用相邻特征作为正对,使用来自不同样本的特征作为负对(例如, CPC 、Wav2vec ( v1 、 v2.0 )、VQ-瓦 v2vec 和离散 BERT )。在图领域, DGI 最大化了图的补丁表示和全局表示之间的互信息,最小化了损坏图的补丁表示和原始图的全局表示之间的互信息。

一个有趣的认识是,从文本领域的自我监督学习分类实际上类似于概念上的对比学习。分类最大化正类的输出,最小化负类的输出。同样地,对比学习也最大化了正对的输出,最小化了负对的输出。关键区别在于分类有有限数量的否定类别(在文本标记的情况下),而对比学习有无限数量的否定类别(在图像和声学特征的情况下)。理论上,我们可以通过给定少量的类来设计图像/语音的分类器。一类是一幅原始图像,输入是增强图像。然而,这是不实际的,因为它只适用于有限数量的图像/类。

自举方法

图片由作者提供。

研究人员进一步开发了 bootstrapping 方法,以避免使用负样本,因为这对于训练来说是计算密集型的,并且不容易选择好的负样本。bootstrapping 方法的核心思想是 1)从同一原始样本的两个扩充中生成一对正样本(就像对比学习一样);2)将一个网络设置为目标网络(也称为教师网络),将另一个网络设置为在线网络(也称为学生网络),该网络与目标网络的架构相同,但增加了一个前馈层(称为预测器);3)固定目标/教师网络的权重,只更新在线/学生网络;4)基于在线/学生网络的权重来更新目标/教师网络的权重。

最重要的设计是 1)在线网络需要有预测器(附加层);2)只能更新在线网络的权重;否则,网络会崩溃(即,不管输入如何,输出相同的值)。

在图像字段中,BYOL 通过取在线/学生网络( ref )的权重的指数移动平均(EMA)来更新目标/教师网络的权重;而暹罗只是简单地复制了重量(参考)。

Meta 的 Data2vec 是图像、语音和文本领域的统一框架( ref )。还需要 EMA 来更新目标/教师网络,但是它使用掩蔽预测任务。它向目标/教师网络提供原始数据,向在线/学生网络提供屏蔽数据。一个重要的设计是它的目标是预测目标/教师网络中顶部几层的屏蔽输入区域/标记的平均嵌入。

正规化

图片由作者提供。

这是另一种只需要正对而不需要反例的方法。令人惊讶的是,这些方法可以对两个网络使用相同的架构,并且它们也不需要“停止梯度”机制来在训练期间仅更新网络之一。通过添加额外的正则项,模型也不会崩溃。目标函数项包括:

  1. 不变性:损失项使来自同一正对的两个嵌入尽可能相似。巴洛双胞胎和德洛丽丝的不变性项寻求分别在图像域和音频域中使互相关矩阵的对角元素等于 1;在图像域中,VICReg 最小化两个嵌入之间的均方欧几里德距离( ref )。
  2. 方差:正则项使同一批中的样本保持足够的差异,因为它们不是同一个样本。 Barlow Twins 和 DeLoRes 的冗余减少项试图分别使互相关矩阵的非对角元素在图像域和音频域中等于 0。在图像域中,VICReg 的方差项使用铰链损失来保持同一批样本中嵌入输出的标准偏差高于阈值(参考)。VICReg 的协方差项最小化协方差矩阵中非对角项的幅度,以对每对嵌入进行去相关。这一项可以大大提高性能,并最大限度地利用嵌入向量的所有维度的效率。然而,这并不是防止信息崩溃所必需的(参考)。

VICReg 的论文表明,与其他自监督框架(Barlow Twins 和 SimCLR)相比,VICReg 对不同的网络架构更具鲁棒性。因此,它可以在将来实现多模态应用。

摘要

本文概述了自我监督学习(SSL)的历史和进展。SSL 从掩蔽预测、下一个令牌预测、对比学习发展到文本、图像、音频/语音和图形等多种形式的自举和正则化。最初,模型恢复部分数据进行学习,因此不需要手动标记。然后,模型可以通过基于数据理解设计的任务进行学习。随着数据的增加,正负成对的例子使得对比学习成为可能。最令人惊讶的是,利用自举技术或正则项,该模型甚至可以在没有任何负面例子的情况下进行学习。随着在可预见的将来对 SSL 有了更好的理解,我相信我们可以用更少的数据、时间和努力来开发更健壮的模型。我迫不及待地想看到这个令人兴奋的领域中更先进的进展!

我是 Jack Lin, C3.ai 的高级数据科学家,我对深度学习和机器学习充满热情。你可以看看我在 Medium 上的其他文章!

由安德里亚·德·森蒂斯峰在 Unsplash 上拍摄

大型语言模型的发展——BERT、GPT3、MUM 和 PaML

原文:https://towardsdatascience.com/self-supervised-transformer-models-bert-gpt3-mum-and-paml-2b5e29ea0c26

ChatGPT 和 Google Bard 背后的算法

作者照片

在早期,NLP 系统大多是基于规则的,后来被机器学习模型所取代。从零开始训练深度学习语言模型需要大量的标记数据,生成这些数据是昂贵的,而获得大量的未标记文本数据是非常容易的。同时,迁移学习允许重用在源任务中学到的知识,以便在目标任务中表现良好。近年来,变形金刚比传统的 rnn 更受欢迎。结合变压器和迁移学习的力量,NLP 的研究人员开发了基于变压器的自我监督语言模型。

在本文中,我们将概述基于 Transformer 的自监督语言模型,并解释核心概念,包括预训练和下游适应。我们还将比较几个流行的自我监督模型,包括 GPT3BERT——基于 transformer 的自我监督语言模型的先驱,MUM—近年来为许多谷歌功能提供动力的模型,以及 PaML —该领域的最新突破。

自我监督学习

什么是自我监督学习

传统上,大型语言模型是用监督学习来训练的,即从人类标记的数据中学习。这些模型在特定任务上表现良好,但是它们需要大量的标记数据来实现良好的性能,并且通常缺乏泛化能力。这些问题在自监督学习中得到解决,因为只需要少量甚至 0(在 0 次学习的情况下)人标记的数据,而绝大多数未标记的数据可以被利用。

自我监督学习的两个阶段

预培训

预训练过程通常无人监督。标签根据数据属性和预训练任务的定义自动生成。对大量未标记的数据进行预训练有助于模型学习通用的语法和语义模式,这些模式可以在以后转移到特定的下游任务。我们可以把这比作一个获得基本常识的人。

下游适应

这就是迁移学习发挥作用的地方。预先训练的模型可以通过添加一两个特定层来适应下游任务。下游适应有助于我们避免从头开始训练下游模型,实现小数据集的良好性能,并防止过度拟合。将预先训练的语言表示应用于下游任务有不同的策略,包括:

  1. 基于特征的

基于特征的方法预先训练语言表示,并将它们用作下游模型中的输入特征。Word2Vec 就是一个例子。

2.微调

与基于特征的方法不同,在基于特征的方法中,我们需要训练单独的下游模型,微调方法只是用特定任务的标记数据来微调预训练模型中的所有参数。

3.少量学习

少量学习是元学习的一种。与微调方法中使用的标准监督学习不同,少镜头学习不需要大型标记数据集。相反,它只需要少量的样本(它们被称为支持集),在推理时,模型根据与支持集的数据相似性进行预测。少击学习的特例是一击学习和零击学习,其中只提供一个或零个下游例子。

变压器

当今前沿语言模型的另一个关键共同特征是它们都是变形金刚。由于梯度消失的问题,传统的 RNN 深度学习模型难以建模长期上下文。为了克服这一点,研究人员开发了一种新型的深度学习模型,称为变形金刚。与顺序处理输入令牌的传统 rnn 相比,Transformers 一次处理所有单词,使它们高度并行化。变形金刚的主要组成部分是自我关注,这是一种关注的变体,它用序列中其余元素的加权平均值来替换序列中的每个元素。变压器有几种不同的架构:

  1. 编码器-解码器

这在最初的变压器模型中使用。编码层生成输入的编码,而解码层处理编码以生成输出序列。编码器和解码器层都有一个前馈神经网络,并利用注意机制。

2.仅编码器

仅编码器模型被设计为对每个输入标记或序列产生单个预测,这意味着它们适用于分类任务,但不适用于生成任务,如机器翻译或文本摘要。编码器是双向的,由两个主要部分组成:自关注机制和前馈神经网络。

3.仅解码器

解码器模型是自回归的,这意味着每一步的输出都作为输入馈入下一步。这也意味着解码器是单向的。在没有编码器对输入句子进行编码的情况下,解码器本身会根据输入句子及其迄今为止输出的内容来学习如何集中注意力。

是时候钻研几款小说模式了!下面按时间顺序列出了这些型号。

伯特

来自变压器的双向编码器表示(BERT)是最先开发的基于变压器的自监督语言模型之一。BERT 有 340M 个参数,是一个仅支持编码器的双向转换器。

使用来自图书语料库(8 亿单词)和英语维基百科(2500 万单词)的未标记语言序列对 BERT 进行预训练。回想一下,预训练是无人监督的。为了构建预训练目标,每个序列中所有标记的 15%被随机屏蔽,并且模型被训练来预测被屏蔽的单词,而不是重建整个输入。这被称为“蒙面语言模型”(MLM)。除了 MLM,伯特还使用“下一句话预测”任务来联合预训练模型。

微调应用于下游适配,其中特定于任务的输入和输出被插入到 BERT 中,并且所有参数被端到端地微调。

GPT3

GPT3 是 Open AI 的 GPT 模型系列的一部分。这正是为著名的 ChatGPT 提供动力的模型。这是一个只有解码器的单向自回归模型,有 175 个参数(比 BERT 大得多)。

与 BERT 不同,GPT3 试图用少镜头学习代替下游微调。该模型在推理时被给予任务的少量数据演示作为条件,但是与微调方法不同,没有权重更新。这是受到这样一个事实的启发,即一旦人类有了一般的语言理解,我们就不一定需要大规模的监督数据集来学习大多数语言任务。尽管在大多数情况下,微调仍然优于少量多次学习,但 GPT3 显示,在某些任务中,零次、一次和少量多次设置几乎与最先进的微调系统的性能相当。

Open AI 已经计划很快发布 GPT4,它可能会是另一个顶级的表现者。一旦它出来,我会写专门的文章。敬请期待!

最大值(T5)

多任务统一模型(MUM)是今天推动复杂的谷歌搜索的技术。

MUM 使用文本到文本转换转换器(T5),这是一种编码器-解码器、多任务学习模型,结合了初始的无监督预训练(作为任务)和针对特定任务的微调(每个作为任务)。它在微调之前对无监督和有监督任务的多任务混合进行预训练,因此我们可以对任何 NLP 任务使用相同的模型、损失函数和超参数。

MUM 是多模态的,所以它理解文本和图像之间的信息。它有 11 个参数,同时接受 75 种不同语言和许多不同任务的训练,使它能够比以前的模型更全面地理解信息和世界知识。事实上,它比伯特强大 1000 倍。

PaML

路径语言模型(PaML)是 Google 的最新突破。它已经扩展到 540B 参数,但使用 Pathways 系统进行了有效训练,这是一种新的 ML 系统,能够在数千个加速器芯片上高效训练非常大的神经网络。

PaML 有一个标准的编码器-解码器转换器模型架构,并做了一些修改。凭借大规模的参数,它展示了出色的少数镜头性能,在 29 个最广泛评估的英语 NLP 任务中的 28 个任务上取得了最先进的结果,包括代码生成、问答、多语言生成、NMT、推理等。

值得一提的是,PaML 在算术和常识推理任务上有突破性的表现。这是通过规模和思维链提示的组合来实现的,其中模型在做出预测之前被明确提示生成自然语言逻辑推理链。等等,这不是我们人类天生的行为吗?

结论

在本文中,我们讨论了基于 Transformer 的自监督语言模型系统,并探索了几个流行的模型,这些模型要么已经在行业中大量使用,要么优于当前的技术水平

这是一个相对较新的快速发展的领域,不断取得突破。几个月后,我们可能会看到更多高性能的型号问世。请继续关注我的更多更新。:)

我希望你喜欢这篇文章!

参考

  1. 用统一的文本到文本转换器探索迁移学习的极限
  2. PaLM:用通路扩展语言建模
  3. 语言模型是一次性学习者
  4. BERT:用于语言理解的深度双向转换器的预训练
  5. 自然语言处理中基于变换器的预训练模型综述

“无语义”是商业智能的未来

原文:https://towardsdatascience.com/semantic-free-is-the-future-of-business-intelligence-27aae1d11563

度量和通用语义层支持无语义 BI

不仅仅是语义(经作者许可)

一个语义层是数据的业务友好表示,允许用更简单的术语解释复杂的业务逻辑。在商业智能(BI)中,它被称为元数据层、语义模型、业务视图或 BI 模型。

大约 30 年前,当语义层首次引入 BI 工具时,它定义了表连接、指标聚合、用户友好的名称等,允许 BI 最终用户简单地将产品名称和销售额等字段拖放到报表上。哇,这是你的数据!是的,“无代码”BI 已经存在了至少 30 年。这使得早期的数据团队开始更战略性地考虑将业务逻辑放在哪里,但也带来了许多复杂的问题。作为一名 20 多年的商业智能顾问和 FlexIt Analytics 的创始人,这些问题在我心中已经存在很长时间了。

商业逻辑放在哪里?

对于一个非常简单的解释,业务逻辑存在于“BI 层”的三个地方之一:

双层,简化,非常简化(图片由作者提供)

在理想的情况下,通过转换(ETL/ELT 中的“T”)将尽可能多的业务逻辑放在数据仓库的最低层。这减少了重复(枯燥——不要重复自己),允许“单一的事实来源”,减少了供应商锁定,并简化了更高层次的消费。然而,这并不总是可行的。

数据仓库开发可能会很慢。如果需要更改业务定义,业务用户可能无法访问数据工程团队,或者他们可能会积压工作。因此,他们联系 BI 团队,让他们将逻辑放入 BI 语义层。如果 BI 团队也积压了工作,或者不愿意做出改变,该怎么办?然后,业务用户将逻辑放入报告中。如果他们没有 BI 工具的“创建者”权限,会发生什么?然后他们运行报告,导出到 Excel,并将他们的业务逻辑放在那里(这是另一篇文章,或者一千篇文章)。

我们知道在报告中填充业务逻辑会很快变得混乱。但是我们也知道,可以应用于数据仓库的业务逻辑的数量是有限的。例如,您不能很好地定义复杂的连接(维度建模与非规范化“一个大表”是另一篇文章)。另外,您通常不能分配像labelformataggregationdescription这样的列属性。因此,放置大部分业务逻辑的自然位置就成了 BI 工具语义层。语义层中放了多少业务逻辑,然后决定了它是(很少)还是(很多)。

阶段 1:厚语义层

BI 工具语义层从中等厚度开始,允许您定义许多复杂的业务逻辑,但是它们的能力也有所限制。早期的工具(Business Objects,Cognos)当然属于这一类,甚至像 Tableau 这样的后继者也在过去几年中加入了加入连接的功能。然而,Looker 通过 LookML 创建了一个非常厚的语义层,具有高级代码和脚本功能。你可能会说类似的事情的权力毕的 MDX。

厚语义层是一个巨大的改进,允许复杂和可重用的业务逻辑。但是,它也与该工具隔离,其他工具或没有访问权限的用户无法使用。如果你是一个拥有一个工具的小组织,并且每个人都喜欢这个工具,那么这可能不是一个问题。但是,当 1)您发展并向堆栈中添加更多工具,或者 2)想要转移到不同的工具(即,供应商锁定)时,会发生什么呢?

就这一点而言,2020 年商业智能趋势研究显示,67%的员工拥有不止一个 BI 工具,平均每家公司拥有 3.8 个 BI 工具。还有许多其他原因来避免厚语义层,其中一些在下面的帖子中有详细介绍:

https://blog.transform.co/data-talks/why-business-metric-logic-shouldnt-live-in-bi-tools/

因此,现代 BI 迎来了下一个阶段,即薄语义层。

阶段 2:薄语义层

BI 工具中的薄语义层的想法是利用在 BI 工具和数据库之间构建语义层的其他工具。其中一些是度量层(又名无头 BI,度量存储),如转换、立方体和度量 ql 。其他的,像 dbt (数据构建工具),是数据转换工具,提供对度量的支持,以及其他语义层功能。

具有薄语义层的 BI 工具从无头语义层同步或提取大部分元数据,然后在其上定义一些额外的元数据。越来越多的 BI 工具采用了瘦语义层方法。这里有一篇关于超集的文章,详细介绍了一个薄语义层背后的思想:

https://preset.io/blog/understanding-superset-semantic-layer/

薄语义层显然是 BI 的一大进步。但是现在,作为一个积极进取的人,你可能会想“为什么不更进一步呢”?除了度量和一些其他元数据,为什么不将更多的元数据,如名称/标签、描述、格式和同义词,下推到无头语义层呢?

阶段 3:无语义 BI

无语义 BI 的概念并不新鲜。它可以追溯到早期的 BI 工具,最初被认为是使用一个通用的(统一的)语义层,最近被称为“headless”。这个想法是,所有的数据消费者(BI、ML 和其他工具)可以通过访问一个应用了公共元数据语义的“真实的单一来源”来“说同一种语言”。与同步来自无头语义层的一些元数据的瘦语义 BI 工具不同,无语义 BI 工具只是保存对无头层中元数据的引用。BI 工具中没有元数据详细信息。从技术上讲,您可以在报表层更改一个属性,并将其称为语义层,但这不是我们所说的“语义层”。

像所有伟大的想法(悬浮滑板、飞行汽车、从里到外的奥利奥)一样,实现一个通用的语义层,实际上是可行的,值得投资的,仍然是难以捉摸的。前面提到的度量层解决方案(Transform、Cube、dbt、Metricql)正在获得越来越多的关注,但是有些特别关注度量。有充分的理由,它是通用语义层最重要的组成部分。在光谱的另一端,有完整的通用语义层产品,如 AtScale 和 Kyligence 。但是它们不是集中的度量层,它们是否会获得牵引力还有待观察。BI 和其他工具会努力与它们集成吗?与开源度量解决方案不同,AtScale 或 Kyligence 既不是开源的,也不是透明的。它们都没有定价页面,只列出最大的公司作为它们的客户,所以我认为可以说它们不是“通用的”统一语义层产品。

https://www.atscale.com/blog/what-is-a-universal-semantic-layer-why-would-you-want-one/

对于各种形状和规模的数据团队,当前的产品可能非常适合一小部分组织。或许更小、更灵活的公司会发现无头 BI 产品非常合适。此外,“无语义”的 BI 可能对这些组织来说并不重要。另一方面,大型公司可能在 AtScale 或 Kyligence 等产品上取得了成功。太好了!然而,这篇文章实际上是为介于两者之间的 90%的人而写的。

我们如何实现无语义 BI?

为了实现这一目标,我认为这是一个三步走的方法:

  1. 细化和合并度量和通用语义层的概念
  2. 定义 BI 工具与无头层对话的标准
  3. 达到支持无语义商业智能的商业智能工具的临界质量

度量和通用语义层几乎涵盖了一切,但需要走到一起并变得成熟。一旦发生这种情况,BI 工具需要很容易与这个无头语义层集成。如果没有一套与无头层对话的标准,每个 BI 工具都必须为每个层创建定制的连接器,这很可能会导致失败。如果框架既开放又简单,那么 BI 工具自然会采用无语义模型。然后,我们可以开始达到无语义 BI 的临界质量。

目前,我认为 dbt 在实现无语义 BI 方面处于领先地位,原因如下:

  1. 它不是您堆栈中的另一个工具。作为增长最快的数据转换解决方案,它已经包含了您的大部分复杂业务逻辑。公司已经将他们的 LookML 向下移动了一层,进入 dbt。
  2. 默认情况下,大量元数据自然内置于 dbt 模型中。
  3. dbt 的文档和对meta的支持已经实现了完整的数据编目能力。现在的问题是改进功能,让它更加活跃。
  4. dbt-core是开源和免费的,有一个充满活力的社区
  5. 像数据血统和数据新鲜度这样的额外因素对 BI 来说是巨大的

虽然 dbt 不是真正的无头服务器,但他们目前正在开发无头度量产品。此外,dbt 认识到了改进的必要性,并高度重视指标和语义层:

https://venturebeat.com/2022/02/28/dbt-labs-will-soon-add-a-semantic-layer-in-the-modern-data-stack/

现在,BI 工具可以并且正在与 dbt 集成,以提供瘦的和无语义的 BI 体验。 FlexIt Analytics 和 Lightdash 通过与 dbt 的集成已经具备了语义无关的能力。其他的像超集和元数据库有同步工具,允许 dbt 模型的手动同步,以支持一个瘦语义层。鉴于 dbt 的受欢迎程度,许多其他产品,如 Thoughtspot(2022 年 8 月)和 Holistics (现已提供测试版访问)即将推出,因此我们将在 2022 年的某个时候看到它们如何集成。最后,一些 BI 工具,如 Mode 给你一点(dbt 源代码新鲜度),但在语义模型方面没有太多。

事情进展很快,制定一些标准变得非常重要。本文详细介绍了如何制定标准,并提供了一个 Github dbt 项目,说明如何与 dbt 集成以实现无语义 BI:

https://medium.com/modern-business-intelligence/self-service-business-intelligence-powered-by-dbt-3b7e24a92e27

结束语

我们在支持各种类型的数据团队和数据消费者方面取得了长足的进步。在某些方面,我们才刚刚开始,但是无头语义产品和瘦或无语义 BI 工具的当前紧迫感和快节奏给了我希望,我们将很快到达那里。

我很想听听你的想法,或者联系安德鲁·塔夫特

用 KeyBERT 提取语义关键词和关键短语

原文:https://towardsdatascience.com/semantic-keywords-and-keyphrases-extraction-with-keybert-999234cab7f

利用拥抱面部变形器和余弦相似性从文档中检索语义表达式

作者图片

介绍

无论您的工作是分析商业报告、社交媒体还是财务数据,我们大多数人都会提到数字能力,因为这是从这些文档中获得有意义见解的更快方式。寻找和提取能更好地描述文档的有见地的单词和表达式一直是一项挑战,尤其是对于较大的文档。

然而,使用最先进的自然语言处理方法可以增加找到那些有意义的单词和表达的机会。我们将尝试使用**KeyBERT**来解决这样一个任务:这是一个由马腾·格罗腾多斯特在 2020 年开发的简单的库。它利用变压器和余弦相似性来有效地提取更好地代表给定文档的关键字和关键短语。我们将首先理解 KeyBERT 是如何工作的,然后实现它,最后讨论它的时间执行复杂度。

KeyBERT——那又怎样?

不同的工艺如耙子、雅克!、 TF-IDF 等。存在关键字提取。然而,KeyBERT 为表达式提取过程提供了语义值,这与前面所述的主要关注统计方法相反。

KeyBERT 的主要组件

下图显示了 KeyBERT 算法的四个主要组件:

图 2: KeyBERT 主要组件(图片由作者提供)

①。原始文档嵌入:第一步是通过利用 BERT 来执行的,目的是获得输入文档的嵌入级表示。如果您想使用其他语言,也可以为多语言任务使用不同的嵌入模型。

②。n 元语法单词/表达式检索:从相同的先前文档中,使用 n 元语法方法提取关键词和关键短语。当 n-gram 范围为(1,1)时,我们得到关键字。另一方面,将范围增加到(1,2)或更高会得到关键短语。

**③。N-grams 嵌入:**这些 n-grams 中的每一个都使用与原始文档相同的嵌入模型进行嵌入。

④。余弦相似性搜索:在先前的单词/短语/表达集合中,使用余弦相似性度量选择与输入文档最相似的那些。这些最终被认为能更好地描述文档。

数据

我创建了一个列表,包含 2022 年 1 月期间发表的所有文章的介绍部分。因此,我们的分析将集中在这些信息上。

你可以在下面找到其中一个介绍的第一行。

我们生活在一个被大量文本信息包围的时代,如调查回复、社交媒体评论、推文等。找到满足个人需求的合适信息是一项挑战,尤其是在处理大量不同的数据时。多亏了主题建模,一个自然语言处理的时代通过将大量未标记的文本数据分组/聚类成主题来有效地分析它们…

还有,文章的所有源代码都可以在我的 Github 上免费获得。

关键短语和关键词提取

以下三个步骤与从文档中提取关键字和关键短语相关:

(1) 安装并导入 KeyBERT 和句子转换器库

keybert_prereq.py

(2) 配置 KeyBERT 模型

config_keyBERT.py

  • all-mpnet-base-v2:这个句子转换器模型将句子&段落映射到一个 768 维的密集向量空间。在撰写本文时,该模型在所有可用的当前预训练模型中具有最佳性能。
  • keyBERT_model:将用于表达式提取的 KeyBERT 实例。

(3) 计算关键词和关键短语提取

以下函数以 (term,cosine_score) 的格式返回最相关表达式的元组列表。余弦值越高,表达的相关性越好。

extract_terms.py

上一个函数中的大多数参数都是不言自明的。下面我们来试着理解一下:use_mmrdiversity

  • use_mmr:设置为 **True 时,对应使用最大边际相关性。**它使得尽可能减少所选表达方式之间的相似性,以创造更多的多样性,这实际上是我们想要的。因为我们不希望我们所有的最终表达都是一样的。
  • diversity:用于设置分集阈值,取值范围为 0-1。这就像一个控制use_mmr的光标,一个更高的值产生的设置(比如在我们的例子中为 0.7)创建了不同的候选表达式/术语/关键字。

既然我们理解了这些参数,我们可以将该函数应用到所有的简介文档中。

terms_from_introductions.py

图 1:来自我一月份文章介绍部分的相关关键词/关键短语(图片由作者提供)

检索到的信息似乎准确地描述了每个相应的简介部分。例如,第一个包含 91 个单词的文档已经被总结为很少的几个表达式,这些表达式可以更好地描述整个文档。

执行时间分析

在构建模型时,记住与工业化方面相关的所有限制是很重要的。其中一个约束可能与管道的执行时间有关,根据您的用例,可以忽略这一点。

下表包含每个简介的关键词提取时间复杂度的所有指标,单位为毫秒(ms)。

表 1: KeyBERT 关键字/关键短语提取执行时间(毫秒)(图片由作者提供)

下面是相应的图形

图 2: KeyBERT 关键字/关键短语提取执行时间图(图片由作者提供)

正如您所看到的,表达式提取时间随着输入文档的长度而增加,并且很容易达到指数级的时间复杂度,这意味着无论 KeyBERT 的性能有多好,它都可能不适用于具有实时执行约束的应用程序。

感谢阅读!

你可以在下面找到更多的资源来加深你的理解。不要犹豫,在 LinkedIn 上加我,或者在 YouTube 和 Twitter 上关注我。讨论人工智能,人工智能,数据科学,自然语言处理的东西总是令人愉快的!

Github 上的源代码

KeyBERT Github

基伯特常见问题解答

再见🏃🏾

使用不同 U-Net 方法对无人机拍摄的航空影像进行语义分割

原文:https://towardsdatascience.com/semantic-segmentation-of-aerial-imagery-captured-by-a-drone-using-different-u-net-approaches-91e32c92803c

使用 python 从头开始实施配置的 U-Net 架构,并使用不同方法对无人机拍摄的航空影像进行语义分割

在机器学习中,模型通过各种应用进行训练,特别是在深度学习和图像数据集上。基于卷积运算的方法在许多领域得到了广泛的研究,尤其是增强现实中的手臂检测、自动驾驶汽车、无人机航拍图像、战争技术。人眼有能力很容易地分类和区分它所看到的东西。然而,这种能力在人工智能技术中的等价物,即理解图像的问题,在计算机视觉的标题下讨论。顾名思义(计算机视觉),就是用计算机可以理解的方式引入(分类)图像,下一步就是通过使用不同的方法,使对这些图像的操作成为可能。本文解释了一种分割方法,即 U-Net 架构,它是为生物医学图像分割而开发的,并包括一个使用 U-Net 分割无人机拍摄的航空影像的真实项目。

Jaromír Kavan 在 Unsplash 上的照片

***Table of Contents* 1\. Semantic Segmentation
2\. U-Net Architecture from 
3\. Tutorial
3.1\. Data Preprocessing
3.2\. Semantic Segmentation using U-Net from scratch
3.3\. Semantic Segmentation using U-Net with Transfer Learning
4\. Conclusion
5\. References**

语义分割

图像是由数学数字构成的像素矩阵。在图像处理技术中,对这些数学数字进行一些调整,然后以不同的方式表达图像,并使其适合于相关的研究或解释。卷积过程是一种基本的数学像素运算,它提供了从不同角度评估图像的机会。例如,图像的边缘检测可以通过应用的过滤器来完成,或者图像可以通过将其从 RGB 格式转换为灰度从不同的角度来解释和使用。基于深度学习模型和卷积层,对图像内容进行了更全面的研究,如特征提取和分类。

图一。对象检测,语义分割,实例分割,[来源](http://A. Arnab et al., “Conditional Random Fields Meet Deep Neural Networks for Semantic Segmentation,” IEEE Signal Process. Mag., vol. XX, 2018.)

如上图所示,用包围盒检测图像内容中的物体称为 物体检测语义分割 这是一种逐像素的标注操作,就是用一个标签,也就是颜色,来显示图片中同一类型的物体(天空、猫、狗、人、道路、汽车、山、海等)。 即时分割 每个实例都被单独标记,通过用不同的颜色显示来分隔每个对象。如上所述,在这些操作的背景下,为了不同的用途,已经开发了各种不同的 CNN 模型和复杂的模型。PSPNet、DeepLab、LinkNet、U-Net、Mask R-CNN 只是其中的一些模式。我们可以说,在自动驾驶汽车等基于机器学习的应用中,分割过程是项目的眼睛。下面的视频包含实时语义分割过程,该过程比较了人类视角和 PSPNet 视角。

简单来说,计算机视觉中的语义分割是一种像素级的标注方法。如果同一类型的对象用单一颜色表示,则称为语义分割,如果每个对象用唯一的颜色(标签)表示,则称为实例分割。

U-Net 架构

U-Net 是一种特定类型的卷积神经网络架构,是 2015 年德国弗赖堡大学计算机科学系和生物信号研究 BIOSS 中心为生物医学图像(计算机断层扫描、显微图像、MRI 扫描等)开发的。文章—“U-Net:用于生物医学图像分割的卷积网络” —可在此处 链接访问。当我们考虑技术思想时,该模型由编码器(收缩)解码器(提取)组成,其中编码器是下采样(大部分是迁移学习中预训练的权重),而解码器是上采样部分,由于其方案是如图 2 所示的 U 形,所以命名为 U-Net。该模型可根据不同的研究进行配置。

图二。U-Net 架构,[来源](http://O. Ronneberger, P. Fischer, and T. Brox, “LNCS 9351 - U-Net: Convolutional Networks for Biomedical Image Segmentation,” 2015, doi: 10.1007/978-3-319-24574-4_28.)

在以下教程中,U-Net 模型被配置用于航空影像的语义分割,如下所示:

如果我们一步一步地看上面的代码块和图 2(从左上到右上,跟随“U”字母的流程):

1.输入定义为 256x256x3 尺寸。

2.作为使用 16 个过滤器的conv_1的结果,获得了 256x256x16 尺寸。用pool_1中的 Maxpooling 减少到 128x128x16

3.使用过滤器号为 32 的conv_2得到 128x128x32 的尺寸,同样,使用pool_2得到 64x64x32 的尺寸。

  1. 64x64x64 的尺寸由conv_3用 64 号滤镜获得, 32x32x64pool_3获得。

5.32×32×128的尺寸是用过滤数为 128 的conv_4得到的,作为pool_4的结果,得到了16×16×128

6.对于滤波器数为 256 的conv_5,得到16×16×256的大小,上采样从这一点开始。在滤镜数为 128 和(2x2)的u6中,用Conv2DTransposeconv_5转换为 32x32x128 ,用u6conv_4进行层叠。因此,u6更新为 32x32x256 。有了 128 个滤镜的conv_6,就变成了 32x32x128

7.通过应用于conv_6并将u7conv_3串联,滤波器编号为 64 和(2x2)的u7变为 64x64x64 。此操作的结果是,u7被定义为 64x64x128 并且变成带有conv_764x64x64

8.通过应用于conv_7并将u7conv_2连接起来,具有 32 和(2x2)过滤器的u8变成 128x128x32 。该操作的结果是,u8被定义为 128x128x64 并变成带有conv_8128x128x32

9.通过应用于conv_8并将u9conv_1连接起来,滤波器号为 16 且(2x2)的u9变成了 256x256x16 。该操作的结果是,u9被定义为 256x256x32 并且变成带有conv_9256x256x16

10.输出使用 softmax 激活完成分类过程,最终输出采用 256x256x1 的形式。

各种比率的下降用于防止过度拟合。

辅导的

在编码部分,可以用不同的方法训练数据集。在本研究中,当 RGB(原始图像)数据集被定义为 x 时,模型通过使用地面实况(分段标记图像)作为 y 来训练。在以后的文章中,还将讨论使用掩膜数据集的方法。RGB 图像和地面实况如图 3 所示。该研究旨在用这种方法训练数据集,并使外部呈现的图像能够像在训练数据中一样执行分割。

图 3。原始 RGB 图像(左)和地面真相(右),作者提供的图像

它专注于编码架构部分,而不是实现高性能。这是由于处理图像数据集时涉及的计算复杂性。例如,虽然原始图像是 6000x4000 像素,但它已被转换为 256x256 像素,以避免计算复杂性。通过这样的操作,旨在通过放弃准确性来使编码架构正确工作。

数据集链接:https://www.kaggle.com/awsaf49/semantic-drone-dataset

许可: CC0:公共域

数据预处理

1-导入库。from architecture import multiclass_unet_architecture, jacard, jacard_loss是从上一节定义并导入的。

具有 6000x4000 像素和相应标签的 2- RGB 原始图像被调整为 256x256 像素。

3- MinMaxScaler用于缩放 RGB 图像。

4-导入地面事实的标签。在地面实况数据集中检测到 23 个标签,并且基于像素值将标签分配给图像的内容。

5 标签数据集是用于分类的one-hot-encoded,数据被分为训练集和测试集。

使用 U-Net 的语义分割(从头开始)

6-准确性和 Jaccard 索引用于训练过程。优化器设置为‘adam’,损失设置为‘categorical_crossentropy’,因为这只是一个复杂的分类问题。模型符合这些设置。

7- validation_jaccard培训过程和损失被可视化。图 4 展示了 val_jaccard。

图 4。Jaccard 值按时代,图像按作者

8-测试数据集的 Jaccard 索引值计算为 0.5532

从测试数据集中选择 9- 5 个随机图像,用训练好的算法进行预测,结果如图 5 所示。

图 5。5 张随机测试图片的预测结果,图片由作者提供

基于迁移学习的 U-Net 语义切分

10-使用 resnet34 重新准备数据集。“Adam”设为优化器,“categorical_crossentropy”设为损失函数,训练模型。

11- validation_jaccard和培训过程的损失被可视化。图 6 展示了 val_jaccard。

图 6。Jaccard 值按时代,图像按作者

12-测试数据集的 Jaccard 索引值计算为 0.6545

从测试数据集中选择 13- 5 个随机图像,用训练好的算法进行预测,结果如图 7 所示。

图 7。5 张随机测试图片的预测结果,图片由作者提供

结论

提出了一种基于生物医学图像分割的 U-Net 的卫星图像语义分割方法。研究中考虑了两种主要方法。第一种方法涉及用从头开始的实现来训练已配置的 u-net 模型。第二种方法涉及用迁移学习技术训练模型,即预先训练的权重。在实现部分中,对应的地面真实图像被一热编码,并且该模型像分类过程一样被训练。Jaccard 指数用于衡量指标。

调整大小过程不是推荐的方法,因为在分割操作中大小变化会有不希望的偏移,但是由于计算复杂性,数据集从 6000x4000 调整到 256x256。因此,模型的成功率非常低。防止这种情况的一些主要方法是使用高分辨率数据集和/或使用patchfying(裁剪图像和相应的地面实况图像)。

图 8。两种方法的比较,图片由作者提供

使用调整后的数据集,评估了两种不同的方法,结果如图 8 所示。查看 Jaccard 指数值,使用迁移学习方法获得 0.6545,而使用临时构建的模型获得 0.5532。可以看出,用预训练模型获得的分割过程更成功。

不同的方法将在后续文章中用不同的编码方法来介绍。

https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d

参考

O.Ronneberger,P. Fischer 和 T. Brox,“LNCS 9351-U-Net:生物医学图像分割的卷积网络”,2015 年,doi:10.1007/978–3–319–24574–4 _ 28。

A.Arnab ,“条件随机场遇上深度神经网络进行语义切分”, IEEE 信号处理。玛格。,第二十卷,2018。

J.陈永春,郭福荣,顾国辉,2020。2020.

J.Maurya,R. Hebbalaguppe 和 P. Gupta,“用于手势界面的头戴式设备上的实时手部分割”,Proc .— Int。糖膏剂图像处理。ICIP,第 4023–4027 页,2018 年,doi:10.1109/icip . 1455125367

Python 中基于 U-Net 的航空影像语义分割

原文:https://towardsdatascience.com/semantic-segmentation-of-aerial-imagery-using-u-net-in-python-552705238514

使用 Python 中的 TensorFlow U-Net 模型对迪拜 MBRSC 航空影像进行语义分割

介绍

图像分割 是在像素级对一幅图像进行分类的任务。

每张数字图片都由个像素值组成,语义分割包括给每个像素加标签。

本文旨在演示如何使用 TensorFlow 中定义的 U-Net 模型对航空影像进行语义分段。

照片由ZQ·李在 Unsplash 上拍摄

资料组

MBRSC 数据集存在于 CC0 许可下,可供下载。它由迪拜的航空影像组成,由 MBRSC 卫星获得,并在 6 类中标注了逐像素语义分割。有三个**主要挑战与数据集相关联:

  1. 类颜色*为十六进制,而掩模图像为 RGB**。*****
  2. 数据集的总容量为 72 幅图像,分成六个较大的图块。七十二幅图像是用于训练神经网络的相对小数据集*。***
  3. 每个图块都有不同高度和宽度的图像*,并且同一图块中的一些图片大小可变。神经网络模型期望输入具有相等的空间维度。***

图 1 描绘了一个训练集输入图像及其对应的掩码,带有叠加的类注释。**

图 1-样本训练数据输入图像(左)和输出掩码(右)(图片由作者提供)

表 1 给出了每个类名,对应的十六进制颜色代码,以及转换后的 RBG 值。**

表 1-类别名称和遮罩颜色(图片由作者提供)

预处理

图像在输入神经网络的输入层时,尺寸必须相同。因此,在模型训练之前,图像被分解成个面片**

选择的 patch_size160 px 。没有理想的补丁大小;它作为一个超参数,可以进行性能优化试验。

从具有 1817 像素的宽度2061 像素的高度拼贴 7 中获取图像,表达式 1 说明了如何计算创建的拼贴元的数量。**

表达式 1——碎片尺寸= 160 px 的平铺 7 图像的碎片数量的计算

接下来,图像被裁剪至最接近的尺寸,可被 patch_size 整除,以避免 patch 与区域重叠。表达式 2 确定瓦片 7 图像的新的修整宽度和高度。

表达式 2-计算图像的裁剪宽度和高度,并除以补丁大小

图 2 阐明了单幅图像的裁剪修补过程。

图 2-修补和裁剪的说明(图片由作者提供)

表 2 给出了瓦片;它们的尺寸是使用尺寸 160 px 创建的补丁总数*。***

表 2 —瓷砖高度、宽度和补丁数量(图片由作者提供)

croppingpatchifying之后, 3483 幅图像和掩模组成了输入数据集。图 3 给出了六个随机选择的图像补片及其可比较的掩模。

图 3 —修补的图像(作者提供的图像)

使用从 Gist 1 到的 Python 代码从一个目录加载图像文件*并执行数据预处理**,如上所述。***

Gist 1 —从目录加载图像并返回裁剪的补丁的 Python 代码

掩码是形状(160, 160, 3).轴 3 的张量,或第三维,可解释为 8 位无符号整数NumPy 数组。这些值的范围从 0 到 255,对应于表 2 中列出的 RGB 颜色。**

多类分类问题需要将输出编码为整数*。即对于具有 RGB 值(60, 16, 152)Building类,合适的标签是0。***

要将遮罩的第三维度转换为表示适当类标签的独热编码向量,请执行 Gist 2 中的 Python 代码。

要点 2 —对遮罩的轴 3 进行分类编码

目前,输入图像是张量,可解释为 8 位无符号整数(十进制 0 到 255)的 NumPy 数组。因此,r escaling 值从 0–255 到 0–1提高了性能和训练稳定性。****

Keras 提供了一个[Rescaling](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Rescaling) 预处理层,它将输入值修改为一个新的范围。使用下面的 Python 代码定义该图层。

***rescaling_layer = layers.experimental.preprocessing.**Rescaling**(**scale**=1\. / 255,**input_shape**=(img_height, img_width, 3)
)***

每个输入图像值乘以scale,如图 4 所示。

图 4-缩放 RBG 通道(图片由作者提供)

一般分为三个部分,培训、验证和测试。然而,与其他机器学习计算机视觉数据集相比,该数据集相对较小。因此,只需要一次分割,并且推理发生在X_test数据集上。

  • X_trainY_train由训练集的 90% 组成
  • X_testY_test构成了剩余的数据的 10%**

模型架构

许多预先训练或预先定义的卷积神经网络 (CNN)架构存在于图像分割任务中,例如 U-Net ,其中在这方面表现出了优越的能力。**

U-Net 由两条关键路径组成:

  1. 收缩对应一般卷积Conv2D操作,其中滤波器滑过输入图像提取特征。Conv2D,*MaxPooling2D层对像素组进行操作,并通过选择最大值来过滤值。汇集向下采样输入图像尺寸,同时保持特征信息。*
  2. ****扩展:使用转置卷积或去卷积Conv2DTranspose扩展下采样图像,以恢复输入图像空间信息。在上采样时,跳过连接 连接对称收缩扩展层之间的特征。

图 5 描述了用于航空影像分割的简单 U-Net 设置,并突出显示了网络和图层形状的所有重要方面。

图 5 —带有输出形状的 U-Net 架构图(图片由作者提供)

两种类型的信息允许 U-Net 在语义分割问题上发挥最佳功能:

  1. 扩展路径中的过滤器包含高级空间上下文特征信息
  2. 收缩路径中包含的详细的细粒度的结构信息

这两个元件通过跳线连接熔断。因此,串联允许神经网络使用伴随低级特征信息的高分辨率数据来进行预测。**

Gist 3 提供了使用Keras构建简单 U-Net 模型的示例代码。

要点 3 —在 Keras 中定义 U-Net 模型

图 6 提供了使用model.summary获得的控制台日志。将Keras输出与图 5 中的架构图*进行比较,可以看到相应的区块图层形状**。***

图 6 —卷积神经网络模型总结(图片由作者提供)

培训和评估

在拟合训练数据之前,必须定义性能指标。由于图像分割涉及为图片中的每个像素分配一个类别,标准的成功指标是交集/并集* ( IOU )系数。***

IOUJaccard Index 测量由实际和预测掩膜包围的重叠像素的数量除以横跨两个掩膜的总像素。表达式 3 计算 IOU。**

表达式 3 — Jaccard 相似性指数(作者图片)

下面在要点 4 中定义了定制的 Jaccard 相似性函数。

要点 4 — Jaccard 指数评估指标

特定的回调**在训练神经网络时很有帮助,因为它们在训练期间提供了模型内部状态的视图。Gist 5 中定义的三个回调是:****

  1. **ModelCheckpoint**:保存所有时期中验证精度最高的最佳模型
  2. **EarlyStopping**:如果 validation_loss 在两个时期内没有继续减少,则停止拟合
  3. **CSVLogger**:将每个时期的模型状态值保存到 CSV 文件中

一旦定义了回调,模型就用Adam 优化categorical_crossentropy 损失进行编译,并为 20 个时期启动训练,如要点 5 所示。

要点 5 — Keras 回调、模型编译和训练数据拟合

图 7 是培训期间返回的 Python 控制台日志的副本。它显示了在每次迭代中categorical_crossentropy 损失减少,而 Jaccard 相似性评估度量增加

图 7 —时期 1–10 的 Python 控制台日志(图片由作者提供)

训练完成后,模型保存到硬盘上,达到最终性能指标值:

  • 损失0.4170
  • 精度0.8616
  • Jaccard 指数0.6599

最后,使用 Gist 6 中的代码来加载带有必要的定制评估指标(定义为依赖项)的模型。

要点 6 —从磁盘加载 Keras 模型

预言;预测;预告

由于数据集大小限制,预测发生在从测试集中随机采样的图像上。**

使用经过训练的 U-Net 模型进行预测的详细注释代码在下面的要点 7 中提供。

要点 7——进行预测并可视化结果

图 8 是十个输出的可视化,描绘了迪拜的修补航拍图像*、地面真相蒙版和 U 网分割预测。***

图 8-U-Net 航空影像分割预测(图片由作者提供)

结论

由于 计算能力 受限,神经网络 规模受限 ,训练迭代不超过 20 个历元。目前大约有140 万个可训练参数,如图 6 所示。因此,模型性能无疑可以通过超参数调整和采用更加复杂的网络来提高。**

图 9 描述了一些最不成功的分割*。一些相似之处在航拍图像的最左边一栏很明显。每张图像都非常亮,包含许多像素,接近 RGB 光谱的白色端。相比之下,查看图 8,最可接受的分割高对比度图像上。因此,合成额外的更亮的训练图像或者在子集上微调模型以提高性能可能是合理的。***

图 9——最佳预测检验(作者图片)

然而,正如预测所显示的,考虑到小的数据集大小和有限的计算能力,该模型通常表现相对良好*。***

本文展示了如何使用 U-Net TensorFlow 模型对迪拜数据集的 MBRSC 航空影像进行语义分割。

类似的过程适用于其他机器学习图像分割任务。U-Net 最初是为生物医学领域的工作而设计的,自问世以来,已在其他各种领域得到应用。

所有代码都存储在这个 GitHub 库中:

***https://github.com/ad-1/u-net-aerial-imagery-segmentation https://medium.com/@andrewdaviesul/membership

参考

[1] 航空影像语义分割 ( CC0:公共领域)—ka ggle
【2】卷积神经网络 —深度学习。艾,
【3】使用 U-net 对航空(卫星)影像进行语义分割—digitals reeni
【4】评估分割模型 —杰瑞米·乔登(2018 年 5 月 30 日)
【5】Keras 三分钟讲解—作者 Andre Duong ,UT Dallas***

语义相似网络

原文:https://towardsdatascience.com/semantic-similarity-networks-9aca31082d8e

从文档的关联性中挖掘知识

从稳定扩散生成的图像

文字是最简洁、最普遍的信息交流方式。它可以说是我们物理世界最有用的代表。毫不奇怪,许多人工智能(包括当前的大量创新)依赖于自然语言理解(通过提示)。为了让机器能够理解语言,文本需要精确的数字表示,这在过去十年中已经发生了革命性的变化。从一个相对较小规模的语料库的热表示到静态单词嵌入,再到来自巨大互联网规模的虚拟数据的子标记的向量表示(通过注意机制),这种变化是我们目前参与的人工智能革命的最重要的变化之一。

前面提到的在文本表示方面的创新使得能够将文本文档存储为向量,在这些向量上可以应用数学运算来探索和利用它们的相互关联性。例如,向量搜索引擎使用余弦相似度来搜索与查询最相关的文档。仅相似性就驱动了许多有用的应用,包括搜索、信息检索和推荐。然而,文本的向量相似性的使用在网络分析中仍然没有得到充分的讨论。

审查现有工作

大多数以前关于语义网络的工作将单词作为分析单位,而不是整个文档。在社会科学的语义网络分析中,Elad Segev 写道,

“语义网络分析更多的是一种无监督的方法。它类似于主题建模,但它不是根据常用词对文档进行分类,而是根据单词的邻近性或共现性对文档中的单词进行分类。在这种情况下,输入是一个文本,输出是一个单词网络,根据它们的接近程度进行聚类。语义网络分析被认为是一种无监督的方法,因为不需要事先定义类别,并且根据单词在文本中的共现情况自动将单词分类。”

该领域的其他一些工作包括“主题模型的网络方法”(Tiago,Eduardo 和 Altmann),详细描述了主题模型和社区检测(用于网络分析)之间的交叉受精。(本文更接近于这里所描述的,但是使用了完全不同的方法,其中“”节点由文档和单词组成,并且它们之间的边的强度由单词在文档中出现的次数给出,产生了等同于在主题模型中使用的单词-文档矩阵的二分多图。”)。

相似性网络本身并不是一个新颖的想法。在《Python 中的复杂网络分析》一书中,Dmitry Zinoviev 详细介绍了这个主题,其中节点的相似性度量用于形成图中的边。本文讨论了我们感兴趣的项目(也称为网络节点,可以是内容网站上的推荐文章、文献调查的研究论文或电子商务网站上的产品(通过其产品描述))的文本表示的类似方法,以及它们之间仅通过其基础文本描述的向量表示的相互连接。

这种方法不同于传统的文本聚类,传统的文本聚类丢失了与较大文档空间的互连性信息。在网络分析中,这些信息通过节点之间的连接来保存。

应用程序

这种方法的一些潜在应用包括:

  • 检测整个文档空间中的空白—例如,假设有一个关于给定主题的研究论文集合,并且您想要探索尚未得到充分研究的想法。您可以查看网络,以确定在各个集群中等级不高的节点。这些外围节点可以让你接触到文献中潜在的空白。
  • 识别与连接两个概念的不可或缺的文档——比方说,通过语义节点上的社区检测,您已经能够识别代表某些类别或概念的集群。通过查看感兴趣的两个集群之间的互连,您可以选择在这两个集群之间具有最大边的节点(文档),这些节点可以作为“桥”概念的潜在候选。(这在文献调查中特别有用,在文献调查中,网络的使用通常仅限于将参考文献的数量视为边。某些论文可能会获得更多与论文内容不完全相关的参考文献(参见“Huber,Juergen and M. Inoua,Sabiou and Kerschbamer,Rudolf and knig-Kersting,Christian and Palan,Stefan and Smith,Vernon L .,Nobel and Novice:作者突出影响同行评议”(2022 年 8 月 16 日)。)
  • 排除建议中的冷启动问题 —建议通常需要用户参与数据,而这些数据在您开始时是不可用的。此外,仅根据相似性提供推荐可能会导致意想不到的后果。(例如,参见艾利森·j·b·邱晨等人的《推荐系统中的算法混淆如何增加同质性并降低效用》(2017)。为了给你的推荐增加多样性,可以使用语义相似度网络。假设用户点击了某篇文章。从网络上,可以使用以下伪代码:
  1. 确定节点(文档)所连接的集群集 C。
  2. 使用度的百分比阈值来过滤出最相关的聚类(C_filtered)[示例:该节点通过 4 条边连接到聚类号 1(它是该聚类的一部分),3 条边连接到聚类 2,2 条边连接到聚类 3,1 条边连接到聚类 4,选择 90%的阈值,并且 10 条边(度)中的 9 条被聚类 1、2、3 占据,这些聚类成为 C _ filtered 的一部分。
  3. 从最相似的节点(可能是任何聚类的节点的感兴趣节点的连接边)提供预定数量的推荐。
  4. 对于剩余的推荐,从 C_filtered 中选择与感兴趣的节点的集群具有大量边但不与之连接的节点。设这个集合为 s。
  5. 为了从 S 中挑选出前 k 个节点,可以使用最大边际相关性来识别彼此不同但与我们感兴趣的节点所属的集群语义相关的节点。

主要挑战:

使用语义相似性网络的主要挑战详述如下:

  • 适应领域的高质量文档嵌入
  • 为边缘的形成选择合适的相似性阈值
  • 选择适合相似网络的社区发现算法

第三个需要实验。我用传统的社区检测算法如贪婪模块性得到的结果不如用欧几里德距离的凝聚聚类得到的结果好。这些聚类用于计算平均距离分数,该平均距离分数被进一步平均以计算网络边的单个阈值。(这个阈值可以认为是一个超参数。)调整阈值将改变网络的稀疏性。

至于文档嵌入,这是一个快速发展的领域,并且正在对最精确的领域适应嵌入进行积极的研究。对于我的实验(详见下文),我使用了一组研究论文,其中最相关的预训练转换器是“allenai/specter”,其嵌入确实给出了不错的结果。我的另一个适用于域适配嵌入的方法是 Reimers 等人的基于变压器的顺序去噪自动编码器。该架构在解码器之前引入了一个瓶颈,从而提供了精确的文档嵌入(与单词嵌入相反)。这可以在未标记的数据集上训练,随后在标记的数据集上训练(优选地与感兴趣的领域相关)。

使用 TSDAE 进行域适配(来源:【www.sbert.net】T2,Apache 2.0)

实验:

cs 类别的数据集。arxiv 上的 CL 是 2018 年、2019 年和 2020 年拍摄的。(这些年来,在使用自我注意力来训练大型语言模型之后,自然语言处理也出现了显著的增长。)如前所述,文档嵌入是从‘allenai/specter’模型获得的,没有任何微调。这些嵌入被输入到 sklearn 的凝聚聚类中,随后获得 101 个聚类。(下面给出代码。)

已查询群集。例如,第 3 组有一些下列文件:

  • 一个新的用于从代码混合对话中进行自然语言推理的数据集
  • 夫妻治疗中言语行为的人际影响建模
  • 用于行为编码的多标签多任务深度学习
  • 用于交互式语言学习的监督种子迭代学习
  • 重复参照游戏中学习的动态特征
  • 使用言语和语言预测癌症患者和配偶互动中的行为
  • Alquist 3.0:使用对话知识图的 Alexa 奖励机器人
  • 南非低资源语言中半正式患者交流中语码混合的普遍性

同样,第 10 组有一些下列文件。

  • 一套盔甲能导电吗?一种新的开卷问答数据集
  • 相似问题检索中语义表示和树搜索的再探讨
  • 基于匹配的格子细胞神经网络中文问答系统
  • RuBQ:一个用于维基数据问答的俄罗斯数据集
  • Quizbowl:增量问答的案例
  • F1 不够!以用户为中心的可解释问答模型及其评价
  • 生成适当问答对的元序列学习
  • 主观问题回答:解读主观领域中变形金刚的内部运作
  • 问答系统中自然语言问题解释的定量评估

粗略地看一下,我们就知道集群 3 是关于会话式 NLP 和对话系统的,集群 10 是关于问题回答的。为了找到聚类 3 中的外围论文,查询该图并获得以下结果:

  • 作为人际多模态范畴化的符号涌现
  • 南非低资源语言中半正式患者交流中语码混合的普遍性
  • 使用健康行为改变的跨理论模型的体重管理聊天的对话注释方案
  • 帮助还是伤害?通过在线社区互动预测用户自残风险的变化
  • 在帖子标题中表达的社会支持会在在线药物使用康复论坛中引发评论吗?

这些看起来像利基专业话题。为了找到“桥论文”(在集群 3 和 10 之间),再次查询图网络,并且获得以下结果。

  • 将问答数据集转换为自然语言推理\n 数据集

结果与预期一致,因为论文谈到了将问答对转换成声明形式。

(RecSys 的实验会单独分享。)

语义相似性网络确实提供了一种不同的分析和查询数据集的方式。用进一步的实验来探索这一点会很有趣。

作者图片:自然语言处理论文的语义相似度网络

语义文本相似度

原文:https://towardsdatascience.com/semantic-textual-similarity-83b3ca4a840e

从 Jaccard 到 OpenAI,为您的语义文本相似性项目实现最佳的 NLP 算法

在 Unsplash 上由伊尼基·德尔·奥尔莫拍摄的照片

🎬介绍

自然语言处理(NLP)在信息提取、自然语言理解和自然语言生成方面有着巨大的现实世界应用。比较自然语言文本之间的相似性对于许多信息提取应用来说是必不可少的,例如谷歌搜索、 Spotify 的播客搜索、家得宝的产品搜索等。语义文本相似性(STS)问题试图比较两个文本,并确定它们在意义上是否相似。由于自然语言的细微差别,这是一个众所周知的难题,两个文本可能是相似的,尽管没有一个共同的单词!

虽然这个挑战已经存在很长时间了,但是 NLP 的最新进展已经开发了许多算法来解决这个问题。一些方法接受两个文本作为输入,并直接提供两个文本相似程度的分数。其他一些技术只是将每个文本转换成一个称为嵌入的数字向量,然后我们可以通过数学计算向量之间的距离来进行比较。回想一下,

💡“嵌入”向量是我们自然语言文本的数字表示,以便我们的计算机可以理解我们文本的上下文和含义。

这篇文章将介绍几种在不同场景下解决 STS 问题的技术。我的目标是尽可能多地使用预先训练好的模型,这些模型提供了开箱即用的优秀结果。在文章的最后,我附上了一个流程图,帮助你决定解决定制问题的最佳方法。具体来说,在这篇文章中,我们将讨论以下内容。点击链接,跳转到以下部分:

  1. 设置环境并下载一些数据
  2. 用经典的非上下文算法测量文本相似性
  3. 用现代上下文算法测量文本相似度
  4. 结果&结论

在这篇文章中,我们将使用 Huggingface datasets 上可用的 stsb_multi_mt 数据集。该数据集包含成对的句子和一个正实数标签,该标签指示每对句子的相似度,范围从 0(最不相似)到 5(最相似)。作者已经在Commons Attribution-Share like 4.0 国际许可下许可了数据集。

STSB 数据集的前五行。图片作者。

STSB 测试数据集相似性得分分布。图片作者。

🧩设置环境并下载一些数据

我们首先需要安装所有必要的库来测试各种嵌入策略。我们将使用来自 mini-forge 的 conda 来管理这个项目的虚拟环境。

设置环境并安装必要的库

因为我们将在这篇文章中讨论几种不同的算法,所以我们需要安装各种各样的库来让它们都工作。不幸的是,安装 pip 时,WMD 算法所必需的 pyemd 库无法工作,因此我们需要使用 conda 来完成这个项目。

作者代码。

加载 STSB 数据集

我们将使用 Huggingface 的数据集库将 STSB 数据集快速加载到熊猫数据帧中。STSB 数据集由一个train表和一个test表组成。我们将这两个表分成它们各自的数据帧stsb_trainstsb_test

作者代码。

创建一些助手函数

让我们为我们将在这篇文章中重复执行的操作创建两个助手函数。第一个功能是对文本进行预处理,将字母符号化、小写化,并删除数字和停用词。第二个函数接受两列文本嵌入,并返回两列之间的行余弦相似度。

作者代码。

现在我们有了环境和数据,让我们开始讨论算法吧!

用经典的非上下文算法进行文本相似性的🧮度量

本节将讨论一些使用经典的非上下文方法来测量文本间相似性的技术。在这些算法中,我们只使用实际的单词进行相似度计算,而不考虑每个单词出现的上下文。正如所料,这些技术通常比更现代的上下文方法性能更差。

雅克卡相似性

比较两篇文章最简单的方法是计算它们共有的独特单词的数量。然而,如果我们仅仅计算独特的常用词的数量,那么较长的文档将具有更多的常用词。为了克服这种对较长文档的偏见,在 Jaccard 相似度中,我们将两个文本中共同的唯一单词的数量标准化为唯一单词的总数。

Jaccard 相似方程。图片作者。

Jaccard 相似性是 Python 中使用 textdistance 库可以轻松计算的几种距离之一。请注意,在运行 Jaccard similarity 之前,要对文本进行预处理,以删除停用词、小写字母并对其进行词条归类,以确保在计算中仅使用信息词。

作者代码。

在上面的代码中,我们仅使用单词(1-gram)来计算 Jaccard 相似性。然而,该技术也可以很容易地扩展到任何 N 元文法。使用 N-gram 而不是单词(1-gram)的 Jaccard 相似度被称为 w-shingling 。

虽然 Jaccard 相似性和 w-shingling 是测量文本相似性的简单方法,但它们在实践中表现得相当不错,如本文末尾的结果部分所示!

单词袋(蝴蝶结)

Bag of Words 是从文本中提取特征并将其转换为数字嵌入向量的经典方法的集合。然后,我们通过计算它们之间的余弦相似性来比较这些嵌入向量。使用单词包方法有两种流行的方式:计数矢量器和 TFIDF 矢量器。

计数矢量器

该算法将整个文本语料库中的每个唯一单词映射到一个唯一的向量索引。每个文档的向量值是每个特定单词在该文本中出现的次数。因此,向量可以由整数值组成,包括 0,这表示该单词没有出现在文本中。虽然计数矢量器易于理解和实现,但它的主要缺点是,不管单词的实际重要性如何,它对所有单词都一视同仁。

计数矢量器示例。图片作者。

TFIDF 矢量器

为了克服计数矢量器的缺点,我们可以使用 TFIDF 矢量器。该算法还将整个文本语料库中的每个唯一单词映射到一个唯一的向量索引。但是每个文档的向量值不是简单的计数,而是两个值的乘积:术语频率(TF)和逆文档频率(IDF)。

  1. 词频(TF):每个单词的 TF 是该单词在该文档中出现的次数,与来自计数矢量器的值相同。这是衡量该单词对文档有多重要的标准。
  2. 逆文档频率(IDF):另一方面,一个单词的 IDF 是该单词出现的文档部分的倒数的对数。它衡量这个词在整个语料库中的稀有程度。

最后,每个文档中每个单词的 TFIDF 值是单个 TF 和 IDF 分数的乘积。这里的直觉是,一个文档中在整个语料库中相对罕见的频繁词是该文档的关键词,并且具有高 TFIDF 分数。TFIDF 的大多数实现都将这些值标准化为文档长度,这样较长的文档就不会在计算中占主导地位。

TFIDF 矢量器示例。图片作者。

使用 sklearn 库在代码中实现 TFIDF 很简单,它以稍微复杂一点的方式计算 IDF,实现规范化并防止 0 除法;你可以在这里了解更多关于的信息。TFIDF 是这篇文章中我们需要训练的唯一模型,以学习语料库中所有独特的单词及其相关的 IDF 值。

作者代码。

尽管单词包方法很直观,并为我们提供了文本的矢量表示,但它们在现实世界中的表现却千差万别。在 STSB 任务中,TFIDF 没有 Jaccard 相似性做得好,正如在结果部分中看到的。

词汇袋方法的其他潜在陷阱是

  1. 如果文档的数量很大,那么由这种方法生成的向量将具有非常高的维数,因为在语料库中会有许多独特的单词。
  2. 这些向量非常稀疏,因为大多数单词不会出现在大多数文档中。

以下测量文本相似性的方法通过使用预先训练的单词嵌入克服了这些限制。

字移动距离(WMD)

Jaccard 相似度和 TFIDF 假设相似的文本有许多共同的单词。但是,情况可能并不总是如此,因为即使没有任何常用的不间断单词的文本也可能是相似的,如下所示。解决这个问题的一种方法是使用预先训练的单词嵌入。

*document1: “Obama speaks to the media in Illinois” 
document2: “The president greets the press in Chicago”*

💡单词嵌入是将单词编码成数字向量的模型,使得相似的单词具有在向量空间中彼此靠近的向量。

生成单词嵌入有几种方式,最突出的是 Word2Vec 、 GloVe 和 FastText 。

由于我们需要比较包含多个单词的文本之间的相似性,从单个单词嵌入到单个句子嵌入的最简单方法是计算该文本中所有单词嵌入的元素平均值。然而,有一种更好的方法可以直接从单词嵌入中计算文本之间的相似性,这种方法称为单词移动距离(WMD)。

WMD 基于推土机距离的概念,是一个文档中的单词嵌入需要“行进”到我们与之比较的文档的单词嵌入的最小距离。由于每个文档包含多个单词,WMD 计算需要计算每个单词到其他单词的距离。它还根据每个单词的词频对“旅行”进行加权。令人欣慰的是, gensim 库使用快速 WMD 算法有效地实现了这个复杂的计算。我们只需一行代码就可以轻松使用它!

大规模杀伤性武器在行动。两对句子都没有共同的词。WMD 仍然可以找到一个相似的句子,因为它们的单词更接近。图片来自 Arxiv 论文。

虽然我们可以在 WMD 中使用任何单词嵌入模型,但我决定使用在维基百科上预先训练的 FastText 模型,主要是因为 FastText 使用子单词信息,并且永远不会遇到 Word2Vec 或 GloVe 可能会遇到的词汇问题。注意对文本进行预处理,删除停用词、小写字母,并对其进行词条归类,以确保 WMD 计算仅使用信息词。最后,由于 WMD 是一个距离度量,而我们正在寻找一个相似性度量,我们将 WMD 值乘以-1(负 WMD ),这样更多的相似文本在数字上具有更大的值。

作者代码。

在 STSB 数据集上,负的 WMD 分数仅比 Jaccard 相似度稍好,因为该数据集中的大多数句子都有许多相似的词。NegWMD 的性能在文本之间有较少共同词的数据集上将比 Jaccard 好得多。

WMD 的限制之一是 WMD 中使用的单词嵌入是非上下文相关的,其中每个单词获得相同的嵌入向量,而不管它出现在句子的其余部分的上下文。本文其余部分的算法也可以使用上下文来克服这个问题。

🚀用现代上下文算法度量文本相似性

本节将讨论几种测量语义文本相似性的技术,考虑不同单词出现的上下文。这些方法通常比非上下文方法更准确。

通用句子编码器(使用)

在使用中,谷歌的研究人员首先在多任务目标上预先训练了一个基于 Transformer 的模型,然后将其用于迁移学习。为了计算文本相似性,我们首先使用预先训练的使用模型来计算句子中每个单词的上下文单词嵌入。然后,我们通过执行所有单词向量的元素式求和并除以句子长度的平方根来标准化句子长度,从而计算句子嵌入。一旦我们有了每个句子的使用嵌入,我们就可以使用本文开头定义的帮助函数来计算余弦相似度。研究人员在 Tensorflow hub 上开源了预训练模型,我们将直接使用它。

作者代码。

与 NegWMD 度量相比,USE 在 STSB 数据集上实现了显著的 10 点跳跃。它显示了在迁移学习环境中使用变形金刚生成的上下文句子嵌入的潜力。随后,研究人员开发了更先进的方法,使用度量学习来预训练基于变压器的模型,以获得更好的性能!

交叉编码器

2018 年来自变压器(BERT) 模型的双向编码器表示的出现,通过击败几个基准,开创了 NLP 的新时代。随着时间的推移,研究人员继续改进香草伯特模型,产生了几个值得注意的变体,如罗伯塔、迪翁伯特、艾伯特等。,正如本帖中讨论的。

BERT 的强大功能来自其自我监督的预训练任务,称为掩蔽语言建模(MLM),我们随机隐藏一些单词,并训练模型预测丢失的单词,同时给出丢失单词之前和之后的单词。对大规模文本语料库的训练允许 BERT 学习语言中各种单词之间的语义关系。

我们可以通过向 BERT 模型的输出添加分类头来使用 BERT 作为交叉编码器。交叉编码器模型将一对文本文档作为输入,直接输出两个文档相似的概率。通过在带标签的 STS 数据集上微调预训练的 BERT 模型,我们可以在 STS 任务上获得最先进的结果!

交叉编码器。图片作者。

我们将使用 sentence_transformers 库来有效地使用在 SNLI 和 STS 数据集上训练的各种开源交叉编码器模型。

作者代码。

交叉编码器不输出任何嵌入向量,因此在几千个文档之外不具有很好的可扩展性。但总的来说,BERT 交叉编码器在大多数句子相似性任务中提供了最好的性能。在我们的 STSB 数据集中,BERT Cross 编码器给出了最好的分数!

度量学习

度量学习是生成嵌入的最有前途的方法之一,尤其是对于相似性搜索应用。在最基本的层面上,在度量学习中,

  1. 我们使用像 BERT 这样的神经网络将文本转换成嵌入。
  2. 我们构建这些嵌入,使得语义相似的文本彼此聚得更近,而不相似的文本则相距更远。

向量空间中的自然语言文本示例。图片来自作者,灵感来自媒体博客文章作者布莱恩·威廉斯。

训练度量学习模型需要在如何处理数据和如何训练模型方面进行创新,正如在我的上一篇文章中详细描述的那样。在用这种方法训练模型之后,我们可以通过数学上计算两个文本向量之间的余弦相似性来找到两个文本之间的相似性。

SBERT 双编码器

句子转换器(也称为 SBERT)是当前最先进的 NLP 句子嵌入。它使用 BERT 及其变体作为基础模型,并利用一种称为对比学习的度量学习进行预训练。在对比学习中,对比损失函数比较两个嵌入是相似的(0)还是不相似的(1)。

句子变形金刚的核心思想如下。

  1. 使用带标签的 SNLI 数据集或 STS 数据集作为训练数据。这些数据集包含数千对被标记为相似或不相似的句子。
  2. 对于训练数据集中的每个文本,使用任何预先训练的 BERT 模型作为编码器来计算该文本的上下文单词嵌入。
  3. 计算所有标记嵌入的元素平均值,以获得整个文本的单个固定维度句子嵌入。这种操作称为平均池。
  4. 使用具有对比损耗的连体网络架构训练模型。该模型的目标是将相似文本的嵌入移得更近,使得它们之间的距离接近 0。相反,该模型旨在将来自不同文本的嵌入彼此远离,使得它们之间的距离很大。
  5. 在我们完成模型的训练之后,我们可以通过计算任意两个文本的嵌入之间的余弦相似性来比较这两个文本。

双编码器句子转换器模型一次接收一个文本作为输入,并输出一个固定维度的嵌入向量作为输出。然后,我们可以通过计算任意两个文档的嵌入之间的余弦相似性来比较这两个文档。

尽管在我们的 STSB 数据集上,双编码器句子转换器的性能略低于交叉编码器,但通过与向量搜索数据库(如 Milvus )相结合,双编码器在扩展到数十亿甚至数万亿个文档时大放异彩!

双编码器。图片作者。

我们将使用句子 _ 变形金刚库来有效地使用在 SNLI 和 STS 数据集上训练的各种开源 SBERT 双编码器模型。

作者代码。

尽管在 STSB 数据集上表现很好,但不幸的是,句子转换器是完全监督的模型,需要大量带标签的句子对语料库来训练。因此,在新的领域采用句子转换器是一个耗时且昂贵的收集大量高质量标记数据的过程。幸运的是,在半监督和自监督学习方面的一些前沿研究显示了有希望的结果!

希姆策

在我的上一篇关于计算机视觉嵌入的文章中,我介绍了 SimCLR ,一种使用对比损失学习图像嵌入的自我监督算法。在这篇文章中,我们来讨论 SimCSE,它是 SimCLR 的 NLP 等价物。

SimCSE 代表句子嵌入的简单对比学习。我们可以将它训练成一个有监督的模型(如果有标签数据的话)或者一个完全无监督的模型!

SimCSE 的核心思想如下。

  1. 给定一个文本文档,使用任何预先训练的 BERT 模型作为编码器来计算该文本的嵌入,并获取【CLS】令牌的嵌入。
  2. 通过对原始嵌入应用两个不同的缺失蒙版,创建同一文本嵌入的两个噪点版本。从相同输入文本生成的这两个有噪声的嵌入被认为是“正”对,并且模型期望它们具有 0 的余弦距离。在 SimCSE 论文中的实验发现,对于 STSB 数据集,0.1 的辍学率是最佳的。
  3. 我们认为这一批中所有其他文本的嵌入是“否定的”该模型期望“负片”到来自前一步骤的目标文本嵌入的余弦距离为 1。损失函数然后更新编码器模型的参数,使得嵌入更接近我们的期望。
  4. 监督 SimCSE 有一个额外的步骤,我们使用一个自然语言推理(NLI)标记的数据集从标记为“蕴涵”的文本中获得“肯定”对,从标记为“矛盾”的文本中获得“否定”对

下图从概念上解释了整个过程。

无监督和有监督 SimCSE。图片来自 arxiv 论文。

SimCSE 模型是使用 SimCSE 方法训练的双编码器句子转换器模型。因此,我们可以直接重用来自双编码器句子转换器模型的所有代码,但是将预训练模型更改为 SimCSE 模型。

作者代码。

从 STSB 数据集上的结果,我们看到,与有监督的 SimCSE 和其他有监督的句子转换器模型相比,无监督的 SimCSE 模型具有显著的性能下降。然而,尽管完全在无监督的情况下训练,仅使用 Dropout 来创建“正”对,但无监督的 SimCSE 可以轻松击败其他方法,如 WMD 和 USE。因此,在没有足够的标记数据或收集这些数据的成本很高的领域,无监督 SimCSE 将是首选方法。

OpenAI

所有基于 BERT 的模型(如句子转换器和 SimCSE)的一个重大限制是,它们只能对最长 512 个标记的文本进行编码。这个限制是因为 BERT 系列模型有 512 个令牌输入限制。此外,由于 BERT 的子单词标记器可能会将每个单词分成多个标记,因此可以使用这些技术转换为嵌入的文本需要少于 512 个单词。如果您需要比较较长文档之间的相似性,这可能会带来问题。非基于 BERT 的模型不会面临这种限制,但它们的性能比基于 BERT 的模型差,因此如果有更好的替代方案,我们宁愿避免使用它们。

生成最先进嵌入的最后一种方法是使用付费托管服务,如 OpenAI 的嵌入端点。它支持多达 2048 个标记的文本,因此非常适合比 BERT 的 512 个标记限制更长的文本文档。然而,OpenAI 端点价格昂贵,尺寸较大(12288 维,而基于 BERT 的模型为 768 维),与同类最佳的免费开源句子转换器模型相比,性能有所下降。

为了让你知道它有多贵,我花了大约20 美元在这个小的 STSB 数据集上生成 OpenAI Davinci 嵌入,甚至在确保每个唯一文本只生成一次嵌入之后!即使对于大型组织来说,将这一代嵌入扩展到一个巨大的语料库也是非常昂贵的。收集标记数据并在内部训练模型可能更便宜。因此,我认为这种技术在现实世界中的用途有限,但是我仍然将它包含在本文中以完善它。

作者代码。

🏅结果和结论

最后,让我们比较一下我在这篇文章中提到的各种文本相似性方法的结果。许多关于语义文本相似性的论文使用 Spearman 等级相关系数来衡量模型的性能,因为它对离群值、非线性关系或非正态分布数据不敏感,如本文中的所述。

因此,我们将计算每种方法的相似性得分与 STSB 数据集提供的实际similarity_score标签之间的 Spearman 等级相关性。使用pandas中内置的corr方法,计算相对简单,如下所示。

作者代码。

下面的 Spearman 等级相关分数显示 SBERT 交叉编码器具有最好的性能,紧随其后的是 SBERT 双编码器。无监督 SimCSE 的性能非常有前途,因为它比 Jaccard、TFIDF、WMD 和 USE 等其他方法好得多。最后,OpenAI Davinci 显示了良好的性能,但是它的成本超过了接受超过 512 个令牌的文本的大多数好处。

STSB 数据集上各种算法的 Spearman 秩相关性能。图片作者。

我们绘制了实际相似性分数和来自各种算法的预测相似性之间的相关性。视觉上,SBERT 和 SimCSE 的相关性看起来相当强!

作者代码。

Spearman 等级相关系数和本帖中介绍的各种方法的实际与预测相似性得分。图片作者。

我开发了下面的流程图来帮助你选择你自己的语义文本相似性任务的方法。我希望它能让你为你的用例选择最好的技术!感谢您的阅读。

选择语义文本相似度算法的流程图。图片作者。

要了解如何比较图像之间的相似性,请阅读下面的帖子。

请阅读下面的帖子,了解如何在产品中部署文本图像多模态搜索引擎。

https://blog.milvus.io/supercharged-semantic-similarity-search-in-production-f2a3c35c4e00

变压器的半监督方法

原文:https://towardsdatascience.com/semi-supervised-approach-for-transformers-38722f1b5ce3

一种训练基于变压器的模型的实用方法,通过半监督方法实现鲁棒性和高精度。

阿瑟尼·托古列夫在 Unsplash 上的照片

变形金刚模型已经成为 NLP 任务的首选模型。在本文中,我们将按照自上而下的方法,使用 Transformers 架构来完成训练高度健壮的 NLP 模型的端到端过程。我们总是尝试使用半监督方法来训练 NLP 模型,无论是分类还是生成。

我们将主要讨论微调 BERT 和文本分类。让我们先了解一下总体情况,然后再谈细节。

对于文本数据增强,请阅读这篇文章。

了解半监督变压器架构

训练半监督模型需要 2 个步骤:

  • 先训练无监督的部分。那就是训练语言模型。对于变压器,可以微调伯特、GPT 等。对于这部分训练,我们只需要未标注的数据或句子。这一步调整模型的权重,以便它能够理解我们想要训练它的数据的上下文。上下文可以是时尚、新闻、体育等。例如,当我们试图训练一个“时尚”模特或“新闻”模特时,“睡觉”这个词可以有不同的上下文。
  • 其次是培训被监督的部分。也就是用标注的数据训练模型。如果第一部分具有大量的数据,则受监督部分即使具有少量的数据也会具有高精度,但反之则不成立。

下图是半监督训练的 GIF。首先,我们微调 BERT,然后我们训练一个文本分类器或命名实体识别模型。它给出了在微调语言模型和然后使用微调模型进行分类之间的联系的直观想法。

端到端流程为微调 BERT ,训练一个文本分类模型,训练一个 NER 模型(图片由作者提供)

让我们检查一下上图的所有组件:

嵌入层:

嵌入层(图片由作者提供)

嵌入层的主要工作是将文本输入数据转换成模型可理解的格式。它有三个主要组成部分:

  • **单词嵌入:**这是为了得到每个单词的矩阵表示。对于 BERT 来说,它的词汇量为 30,522,768 个值的数组代表一个单词。因此,如果输入是 4 个单词,单词嵌入的输出将是 4 x 768。
  • **位置嵌入:**用于获取单词的位置。在 transformers 中,单词的位置作为输入传递,因为句子的上下文高度依赖于单词在句子中的位置。
  • **线性层:**该层是一个线性卷积层,用于合并各层,最终提供一个 768 特征的矩阵。

编码器层数:

在这个编码层中总共有 11 个 BERT 层。

BERT 编码器层(图片由作者提供)

每层有两个主要组件:

  • **自我关注层:**这是变形金刚模型的核心,有助于确定每个单词相对于句子中所有其他单词的重要性,以及在句子的整体上下文中的重要性。下图显示了用作键(K)、查询(Q)和值(V)的嵌入。k、Q 和 V 经过几层卷积、点积和 softmax 处理,以获得所需的输出。自我关注本身是一个需要更多解释的话题。如果你没有意识到自我关注,我建议你看一下 youtube 上的视频https://youtu.be/-9vVhYEXeyQ?t=146以获得更好的理解。
    该层接受 768 个特征的输入,进行多头注意操作,并输出具有 768 个特征的矩阵。

多头关注(图片来自wiki . math . waterloo)

  • ****回旋层:这些层之后是自我关注层。它包括一对夫妇的密集层,层正常化,辍学,和 GELU 激活功能。这些图层的输入和输出要素数量为 768。

语境向量:

上下文向量(图片由作者提供)

不是根据定义,而是上述 2 层(嵌入和编码层)的输出,给出了具有 768 个特征的矩阵,该矩阵是句子的上下文,因此我们将其称为上下文向量。这是模型的最重要的部分,因为在无监督部分完成的所有训练都是为了训练权重以正确获得上下文向量。

在诸如 RNN 和 LSTM 的模型中,模型的输入是不能捕捉句子上下文的单词嵌入。因此,我们在单词嵌入层的顶部训练一个神经网络来捕捉句子的上下文。现在,这个输出捕获了 768 个特征的上下文。该输出可以作为输入传递给分类或生成模型,使得整个模型高度稳健和准确。

语言模型:

这是训练中无人监督的部分。额外的卷积层被添加到上下文向量的输出中。该模型的最终输出是词汇量为 30,522 的矩阵。这个模型需要从现有的词汇中预测一个单词。我们输入数百万未标记的句子,并允许模型调整权重以获得适当的上下文向量。

有两种方法可以训练语言模型:

蒙面语言模型:

我们屏蔽了输入句子的 10–30 %,并要求模型预测被屏蔽的单词。正如你在下图中看到的,输入句子是“女式碎花印花[面具]上衣”。

MLM 的输入(图片由作者提供)

卷积层被添加到编码器层以预测丢失的单词。

屏蔽语言模型底层(图片由作者提供)

该模型的输出是具有 vocab 大小(在这种情况下是 30,522)的矩阵,以预测丢失的单词。基于模型的预测,计算损失并调整模型的权重。

在使用掩蔽语言模型技术为时尚领域训练了一个具有 2000 万个句子的 BERT 语言模型之后,您可以在下面的 GIF 中清楚地观察到差异。

左图:伯特接受时尚数据训练,右图:原始伯特(图片由作者提供)

输入:女装【面具】上衣
BERT(时尚):女装碎花印花裁剪上衣
BERT(原创):女装上衣

休闲语言模式:

对于 CLM,该模型试图从现有词汇中预测下一个单词,并将其与真实输出进行比较。通常,CLM 用于生成模型,即 GPT 架构。在本文中,我们不涉及基于 GPT 的架构,但您可以看看下面的 GIF,它显示了特定时尚的 GPT2 模型与具有原始权重的 GPT2 模型之间的差异。

左:根据时尚数据训练的 GPT2,右:原始 GPT2 (图片由作者提供)

一旦伯特/GPT 与定制数据集进行了微调,第二部分是在其上训练分类和生成模型。

虽然在训练时整个模型的权重得到更新,但是为了我们的理解,我们可以假设上下文向量现在是模型的输入。

文本分类

现在是一个简单的分类问题。在下图中,密集图层已被添加到上下文矢量的输出中,并最终将特征减少到类的数量。上下文层输出越好,模型就越健壮和准确。

使用上下文向量的文本分类(图片由作者提供)

当我们处理变形金刚时,我们还可以获得单词级的置信度得分,这些得分有助于对所述类进行预测。

分析文本分类输出,绿色表示肯定,红色表示否定(图片由作者提供)

****对于句子panta loons green shirt with jacket,wear it with black jeans,我们试图预测一个时尚类别。上面的句子有很多种类,包括衬衫、夹克和牛仔裤。但是正如你在第一个例子中看到的,它正确地预测了衬衫,单词 shirt 具有最高的可信度。在其他的例子中,我们已经将基本事实改变为不同的标签,然后尝试观察行为。随着标签的改变,句子的单词级置信度改变,并且它自动指向对新标签的预测有积极贡献的单词。例如,在第二个例子中,当我们将真实标签改变为牛仔裤时,单词牛仔裤的置信度变为正,而诸如衬衫和夹克的其他单词变为负。这就是自我关注模型的美妙之处。

命名实体识别

与文本分类相同,我们假设上下文向量作为输入,并为 NER 任务编写层。NER 模型预测每个输入单词的标签。

使用上下文向量的命名实体识别(图片由作者提供)

因为数据是特定于时尚的,所以标签是细粒度的。NER 也有助于短语发现,进而导致趋势发现。NER 有很多方法,但本文的范围是理解半监督方法。

时尚 NER(图片由作者提供)

现在,我们已经完成了所有组件,我建议您再次查看变形金刚端到端培训 GIF。

培训代码可在抱脸获取。

  • 微调语言型号: Colab 笔记本
  • 训练一个文本分类模型: Colab 笔记本
  • 训练一个 NER 模型: Colab 笔记本

在这篇文章中,我试图给出一个半监督训练的想法,我们可以用变形金刚来训练高度精确的模型。让我知道你对它的想法。

变压器的半监督方法(二)

原文:https://towardsdatascience.com/semi-supervised-approach-for-transformers-part-2-8f8bf6edd912

用于微调罗伯塔模型和训练自然语言推理分类任务的连体网络结构

法耶·康尼什在 Unsplash 上的照片

本文将使用暹罗架构来微调 RoBERTa 模型。我们还将在微调和训练数据集时,使用主成分分析和 TSNE 来观察数据集的嵌入分布。训练将在用于自然语言推理分类的微调 RoBERTa 模型(SNLI 的子集)上进行。

为本文代号 。要理解变形金刚半监督方法背后的直觉,请阅读 第 1 部分

资料组

SNLI 数据集的子集用于训练。20000 个训练样本,10000 个验证样本,10000 个测试样本。NLI(自然语言推理)数据集有一个前提和一个假设。该模型的目标是预测假设是否与前提相矛盾、蕴涵或中立。

原始数据集有大约 550,000 个训练样本。在全套设备上做这个实验会得到更好的结果。

让我们来看一下数据集分析:

数据集分析(图片由作者提供)

我们可以从上图中观察到数据集是平衡的。将前提与假设串联后,最大句子长度可估计为 64 个单词

模型

为此,我们将使用两种型号。第一个是暹罗建筑微调罗伯塔。第二个模型将有一个分类头来预测句子之间是包含、矛盾还是中立。

句子变压器型号:

为 RoBERTa 创建句子转换器模型的代码片段(作者)

该模型的输出是 768 特征或上下文向量。我们将同时计算前提和假设的嵌入,并使用余弦相似性损失来微调模型。

  • -1 表示矛盾
  • 0 代表空档
  • 1 用于限定

暹罗建筑(图片来自sbert.net

上图代表了架构。微调完成后,RoBERTa 模型的权重将被保存以供后续任务使用。

序列分类自动模型:

序列分类加载微调过的 RoBERTa 的代码片段(作者)

在用 same 体系结构微调模型后,我们将使用相同的 RoBERTa 权重来定义序列分类模型。在这个模型中,新的权重将只分配给最后一个“分类器”层。这将在具有循环学习率和 Adam 优化器的训练数据上进一步训练。

学习率余弦调度器(图片来自拥抱脸)

具有 2 个周期的余弦调度器的学习速率 2e-5 用于训练。这是为了避免过度拟合。

损失图()和准确度图()(图片由作者提供)

上图显示了序列分类的损失和准确度曲线。达到了 87%的测试精度。

训练结束后,我们会节省重量。这些权重可以再次加载到句子转换器模型中,并训练几个时期以获得更好的句子嵌入。

句子嵌入分析

我们已经对模型进行了三次训练:

  • 将原来的罗伯塔重量加载到句子转换器中,以使用暹罗架构进行训练。我们可以保存这些微调过的权重。
  • 使用 RoBERTa 将上述训练中微调的权重加载到序列分类模型中。训练后,我们保存这些重量。
  • 将上述步骤中的权重加载到句子转换器中,用连体结构训练几个时期,然后保存权重。

训练集中所有句子对的句子嵌入被保存 3 次:

  • 原始罗伯塔重量。
  • 用连体建筑微调后。
  • 经过序列分类和微调再次与暹罗架构。

对于这 3 个版本的句子嵌入,我们将运行主成分分析和 TSNE 拟合来分析数据集微调的效果。下图显示了分析结果:

图 1: 我们对句子嵌入的所有 3 个实例运行 n_components = 3 的 PCA,并绘制二维图。

PCA (n = 3),图为 PCA-x,PCA-y :原罗伯塔(),微调用暹罗(中心,NLI 分类后()。(图片由作者提供)

图 2: 我们对句子嵌入的所有 3 个实例运行 n_components = 3 的 PCA,并为所有数据点绘制 3D 图。

PCA (n = 3),图形为 PCA-x,PCA-y,PCA-z :原罗伯塔(,微调为连体(居中,NLI 分类后()。(图片由作者提供)

图表 3: 我们对所有 3 个句子嵌入实例运行 n_components = 2 的 TSNE 拟合,并绘制图表。

TSNE (n = 2),图形为 X,Y :原罗伯塔(),微调为连体(居中),NLI 分类后()。(图片由作者提供)

图 4: 我们运行 n_components = 50 的 PCA,并在所有 3 个句子嵌入实例上运行 n_component = 2 的 TSNE 拟合。在此图中,我们比较了前两个图和当前图。

图表 4.1: 为原始 RoBERTa 权重。对此的观察是,所有的数据点是分散的,并且没有逻辑足以基于它们的标签显示句子对嵌入之间的清楚区别。

PCA[n = 3]【X,Y】()TSNE[n = 2]【X,Y】(中心)TSNE[n = 2,PCA[n = 50]]【X,Y】(右【T41

图 4.2: 微调连体结构后,我们可以观察到基于标签的句子对嵌入之间的一些区别。

PCA[n = 3]【X,Y】()TSNE[n = 2]【X,Y】(中心)TSNE[n = 2,PCA【n = 50】【X,Y】(

图 4.3: 在对暹罗架构进行序列分类和微调之后,我们可以观察到,基于标签的句子对嵌入之间存在明显的区别。

PCA[n = 3]【X,Y】()TSNE[n = 2]【X,Y】(中心)TSNE[n = 2,PCA[n = 50]]【X,Y】()对于罗伯

我已经介绍了用半监督方法训练一个 transformers 模型的影响,这种方法总是会产生一个健壮的模型。这个实验是在 20,000 个数据点的小集合上完成的。在实际数据集上这样做会有更大的影响。在 huggingface 上已经有可以直接使用的带有连体结构的微调模型。

可以使用其他技术来更好地聚类或可视化句子对嵌入。这些可视化也可以用于任何其他 NLP 任务。

参考资料:

  1. 句子伯特
  2. 你所需要的只是注意力
  3. 用于语义文本相似性的句子转换器
  4. 为自然语言推理微调 BERT
  5. 在 Python 中使用 PCA 和 t-SNE 可视化高维数据集

使用 Hasura、哈比神和无服务器发送 HL7 v2 消息

原文:https://towardsdatascience.com/sending-hl7-v2-messages-with-hasura-hapi-and-serverless-9cd1630876a4

作者图片

健康级别 7 (HL7)版本 2 于 80 年代末开发,多年来一直是世界上最流行的数据交换标准。该标准最近被 HL7 快速医疗保健互操作性资源(FHIR)取代,但采用率比预期的要慢,所以即使在 2022 年,使用 HL7 v2 仍然令人惊讶地普遍。

在这篇文章中,我将概述一个典型用例的解决方案:假设我们有一个传统的电子病历(EMR)系统,在一个诊所中有一个支持关系数据库,每当一个新病人注册时,它需要向另一个机构发送一条消息(例如 ADT_A04)。下面的步骤可以作为演示在开发机器上运行—不需要云平台。虽然这篇文章关注的是 HL7 v2,但我们目前正在研究为 Hasura 设置的 GraphQL & REST FHIR,所以如果你对此感兴趣,请去投票支持我们的 GitHub 讨论。

解决这个问题最常见的方法是使用一个名为happy Connect的集成工具,这是一个很好的基于 Java 的服务器应用程序,最初是在 15 年前开发的,主要面向医疗保健行业。尽管 happy 的核心是开源的,但是像 FHIR 支持这样的扩展需要订阅,截止到本文撰写时,订阅费用大约为每年 2 万美元。

相比之下,Hasura 虽然才出现了几年,但已经被从沃尔玛到空中客车等各行各业的组织所使用,并支持现代微服务架构和设计模式。Hasura 是完全开源的(所有特性都可以免费获得),用 Haskell 开发,可以作为 Docker 镜像快速部署。

为什么是哈苏拉?

选择 Hasura 而不是 happy Connect 的几个原因包括:

  • instant API:如果您正在通过支持 RDBMS 将 HL7 v2 添加到传统 EMR,这可能只是许多(当前或未来)集成中的一个,因此在您现有的数据库上免费获得一个 Instant API 肯定会派上用场。此外,为了支持这一特性,Hasura 跟踪DB 模式,该模式具有自动生成表列映射的额外好处,便于分配给 HL7 消息模板字段,而不必手动编写 SQL 查询。
  • GraphQL :如果你还在考虑 REST 和 GraphQL,那么你就错过了联邦、模式拼接和远程连接的大画面,我鼓励你去看看由 Uri Goldshtein 为 Firely DevDays 做的演讲。GraphQL 还支持现代客户端框架(如 Gatsby、Next.js、Gridsome ),可以快速开发定制屏幕和仪表盘(在医疗保健领域无处不在),无需开发定制端点即可读取/写入所需数据。
  • **同步事件:**Hasura 在后台创建并管理主机数据库中的触发器,以便同步触发相应的动作。另一方面,joyful 的方法是定期轮询数据库,这种方法效率不高,并且与事件驱动的体系结构相反。
  • **管理控制台:**这种类型的集成可能是一个复杂的过程,因此任何有助于调试的东西通常都是必不可少的。joyful Connect 确实有一个 Java GUI,但是与 Hasura 相比,它缺少了一个对这个场景特别有用的特性:一个可视化的数据库浏览器。Hasura 基于 web 的管理控制台允许我们在不离开 web 浏览器的情况下,可视化我们的 DB 以及完成对行、表和关系的 CRUD 操作。

演示概述

要求:Git、Docker、Node.js、NPM、Java ≥8

图片由作者提供,徽标经许可使用

这个解决方案采用微服务方法,从 Hasura 连接到现有的 EMR DB 开始,并监视 Patients 表中的新插入。当一个新病人被注册时,Hasura 将插入的数据转换成 JSON 格式的模板 HL7 消息,并将其作为 HTTP 请求发送给运行在无服务器框架上的 Java HAPI 服务(在本演示中使用无服务器离线)。Java HAPI 是 HL7 处理的黄金标准——该服务解析 JSON HL7 消息,将其转换为 ER7 格式(管道分隔),并将其作为 HTTP 请求转发给 HTTP-MLLP 网关。网关是一个简单的 Node.js 应用程序,它接收 ER7 格式的 HTTP 请求体,并通过 MLLP 将其发送到最终目的地,接收 ACK 响应并将其返回给 Java HAPI 服务,该服务再将响应返回给 Hasura。理想情况下,MLLP 网关也将作为无服务器功能运行,但不幸的是,AWS API 网关和应用程序负载平衡器目前只允许基于 HTTP 的调用。

Postgres 和 Hasura 入门

Hasura 支持 Postgres、MS SQL、Citus 和 BigQuery,并且刚刚发布了 MySQL 的早期版本。在这个演示中,我们将使用 Postgres 和来自 OpenEMR 的稍微重构的 patient_data 表。

按照下面的命令进行设置。

$ git clone [git@github.com](mailto:git@github.com):whitebrick/hl7v2-hasura-hapi-serverless.git
$ cd hl7v2-hasura-hapi-serverless
$ psql# Create a new user, DB and add the pgcrypto extension
postgres=# CREATE USER myemrusr WITH password 'myemrpwd';
postgres=# CREATE DATABASE myemr OWNED BY myemrusr;
postgres=# CREATE DATABASE myemr WITH OWNER = myemrusr;
postgres=# \c myemr
postgres=# CREATE EXTENSION pgcrypto;
postgres=# \q# Test new user and DB and load data
$ psql -U myemrusr myemr
myemr=> \i ./sql/openemr_patient_data_table_postgres.sql
myemr=> \i ./sql/openemr_patient_data_rows_postgres.sql

一旦我们设置好了patient_data表,我们就可以从 Docker 启动 Hasura,并配置它使用我们的新数据库,如下所示(注意,数据库主机是用于 Mac 的,参见 Linux 或 Windows 的指南)。Hasura 在 DB 中创建了一个新的模式hdb_catalog来保存所有的元数据,这样它就不会接触到我们在 public 模式中的数据,除非我们告诉它这样做。

# Edit as required
$ vi ./hasura_docker_run.bashdocker run -d -p 8080:8080 \
-e HASURA_GRAPHQL_DATABASE_URL= postgres://myemrusr:myemrpwd@host.docker.internal:5432/myemr \
-e HASURA_GRAPHQL_ENABLE_CONSOLE=true \
-e HASURA_GRAPHQL_DEV_MODE=true \
-e HASURA_GRAPHQL_ADMIN_SECRET=admin \
hasura/graphql-engine:latest$ bash ./hasura_docker_run.bash

现在转到 http://localhost:8080 ,当提示输入管理员密码时,输入上面的值(本例中为“admin”)。一旦登录,我们需要做的第一件事就是跟踪T2 表,这样 Hasura 就可以分析和监控它。点击数据导航选项卡,点击patient_data工作台旁边的 e 轨迹按钮。一旦被跟踪,我们现在可以从上面描述的方便的管理控制台可视化和管理数据库。

作者图片

现在,Hasura 理解了我们的表,这是使用即时 API 有多简单的快速示例,如果我们单击 API 选项卡,我们可以简单地选择左侧的几个复选框,一个 GraphQL 查询就写在我们眼前——包括语法突出显示、代码完成和错误检查。然后,我们可以点击播放按钮来查看我们的查询结果。

作者图片

无服务器运行 HAPI

我们将离开 Hasura 一会儿,通过安装无服务器框架并使用下面的命令构建和测试hapi-无服务器来运行我们的 HAPI 微服务。无服务器离线插件允许我们在本地运行 lambda,就像在云中一样,方法是在幕后使用 docker,这就是为什么我们要提取lambda:java8图像。

注意:由于无服务器离线使用 Docker,初始请求可能需要一分钟左右的时间来处理。

# Build
$ git clone [git@github.com](mailto:git@github.com):whitebrick/hapi-serverless.git
$ cd hapi-serverless
$ npm install
$ mvn package
$ docker pull lambci/lambda:java8# Start
$ npm start
...
Server ready: [http://localhost:3000](http://localhost:3000)# Test
$ cd test/functional
$ bash ./test_parsing.bash
$ bash ./test_forwarding.bash

从 Hasura 创建 HL7 v2 消息

下一步是获取模板消息。尽管我们可以从头开始构建消息,但通常最好的做法是向消费者索要一个模板,这样任何与标准不符的地方都会被考虑在内。对于这个例子,我在谷歌上搜索 ADT_04 样本,北达科他州卫生部消息指南首先出现。我从指南中复制了 ER7 格式的示例消息,并将其粘贴到文件./hl7/NDDH_ADT_A04.er7中,然后将其发布到 HAPI 无服务器服务器,以获得./hl7/NDDH_ADT_A04.json中的 JSON 表示。

现在回到 Hasura,我们将点击 Events 选项卡,创建一个名为HL7-Send_ADT的新事件,并将其附加到public模式中的patient_data表。我们只想触发新的Insert操作,我们将从上面放入本地 HAPI 无服务器 URL,但针对 Docker 网络进行了调整([http://host.docker.internal:3000/dev](http://host.docker.internal:3000/dev)这是针对 Mac 的,参见指南针对 Linux 或 Windows)。

作者图片

我们还想将超时时间增加到120秒,以便让我们的 HAPI 无服务器 Docker 映像有足够的时间启动,将请求方法设置为POST,将Content-Type头设置为application/json

作者图片

接下来,我们要单击添加有效负载转换,在这里我们可以将插入的 DB 值映射到 HL7 JSON 模板。因为 Hasura 已经知道了我们的表,所以它可以自动创建预期的插入输入。然后我们粘贴来自./hl7/NDDH_ADT_A04.json的模板,并开始将值映射到我们的列——对于这个演示,我们将只映射名字、姓氏和中间名。正如我们在下面看到的,transform editor 还提供了语法突出显示、代码完成和验证,以及一个示例预览(一旦代码完成/有效就会显示)。使用 Hasura 自己的 Kriti Lang 将{{$body.event.data.new.*}}路径映射到输入的 JSON 结构,这看起来很熟悉,是受 Go 的模板语言的启发。

作者图片

最后点击页面最底部的保存按钮,现在让我们测试一下。点击数据导航选项卡上的返回,选择patient_data表,然后选择插入行菜单选项卡,然后输入名称值(见下文)并点击保存按钮。

作者图片

假设我们的 hapi-serverless 仍然在运行,并且我们有正确的 Docker 网络 URL,我们现在应该在终端日志上看到一个点击。如果我们单击返回到事件导航选项卡,选择HL7-Send_ADT事件,然后选择未决事件子选项卡,我们应该会看到一个新事件在等待,因为我们的 HAPI 无服务器需要一些时间来启动和响应。最终,该事件将被移动到 Processed Events 选项卡,并允许我们查看请求和响应,在那里我们可以看到我们的 ER7 转换。

作者图片

HTTP 到 MLLP

不幸的是,HTTP 在 80 年代末不像在 90 年代末那样普及,所以我们只能用 MLLP,但至少它仍然基于 TCP/IP。为了通过 MLLP 转发 ER7 消息,我们使用 Express 和 mllp-node 包组装了一个非常基本的网关在 Node 上运行。网关寻找一个头部,例如Forward-To: mllp://ack.whitebrick.com:2575,并使用 mllp-node 发送带有相应控制字符的主体,然后返回一个 HTTP 响应。如果您有自己的端点来测试接收 ACK 消息,您可以在Forward-To头中使用它,否则欢迎您使用我们上面的 Apache Camel 测试端点——详情此处。

# Build
$ git clone [git@github.com](mailto:git@github.com):whitebrick/http-mllp-node.git
$ cd http-mllp-node
$ npm install# Start
$ node gateway.js
...
HTTP server listening on port 3030# Test
$ cd test/gateway-functional
$ bash ./functional.bah

从 Hasura 发送 HL7 v2 消息

既然我们已经运行了 MLLP 网关,我们就可以使用 HAPI 无服务器的转发特性,不仅可以转换来自 JSON 的消息,还可以通过网关转发 ER7 数据并接收返回的响应。为了做到这一点,我们只需将下面的标题(根据您自己的 Docker 网络进行调整)添加到我们的事件配置中。

  • MLLP-Gateway : [http://host.docker.internal:3030](http://host.docker.internal:3030)
  • Forward-To : mllp://ack.whitebrick.com:2575

作者图片

有了附加的标题,我们可以返回到数据页面,插入另一条记录来测试完整的发送和响应。如果一切顺利,我们现在应该看到retEr7retJson值以及来自下游 MLLP 消费者的 ACK 数据。

作者图片

就是这样!我们现在有一个完整的端到端解决方案,因此当 EMR 创建新的患者记录时,Hasura 从一个模板构建一个 HL7 v2 JSON 消息,通过 MLLP 网关发送它,捕获 ACK 响应,并在管理控制台中很好地显示结果。

访问响应数据并发出错误警报

在发送了一些消息后,下一个明显的问题是:如果我想对响应数据做些什么,而不仅仅是在管理控制台中显示它,该怎么办?因为 Hasura 元数据存储在同一个 DB 中(但是是独立的模式),所以我们可以创建一个 function+触发器,将感兴趣的数据复制到我们自己的表中,然后在新表上设置附加事件。例如,假设当 HL7 消息有错误响应时,我们希望通过发送电子邮件或 Slack 消息来发出警报。

让我们首先返回到数据导航选项卡,单击左侧的 SQL 菜单,粘贴下面的代码并点击运行按钮,为我们的错误消息创建一个新表。

CREATE table hl7_error_messages(id serial PRIMARY KEY NOT NULL,created_at timestamp without time zone DEFAULT now(),request json,response json
)

如果我们使用 psql 查看 Hasura 表hdb_catalog.event_loghdb_catalog.event_invocation_logs,我们将从管理控制台视图中看到相同的数据。当 Hasura 运行任何事件(例如发送 HL7 消息)时,下面的触发器调用copy_hl7_error_messages函数。然后,该函数检查事件名称是否与HL7-Send_ADT匹配,并且在将它复制到我们新创建的hl7_error_messages表之前,状态是否为不成功。额外的一行是取消转义并解析响应 JSON,因为它将进入 Postgres JSON 字段。

CREATE OR REPLACE FUNCTION copy_hl7_error_messages()
RETURNS trigger AS
$$
DECLAREevent_name text;response_json json;
BEGINSELECT trigger_name INTO event_name FROM hdb_catalog.event_log WHERE id = NEW.event_id;IF (event_name = 'HL7-Send_ADT') AND (NEW.status != 200 OR NEW.status IS NULL) THEN-- unescape JSONSELECT cast('{"data":{"message":' || cast(((NEW.response->'data'->'message') #>> '{}' )::jsonb as text) || '}}' as json) INTO response_json;INSERT INTO hl7_error_messages (request, response)VALUES (NEW.request, response_json);RETURN NEW;ELSERETURN NULL;END IF;
END;
$$
LANGUAGE plpgsql;CREATE TRIGGER copy_hl7_error_messages_trigger
AFTER INSERT
ON hdb_catalog.event_invocation_logs
FOR EACH ROW
EXECUTE PROCEDURE copy_hl7_error_messages();

接下来点击数据库下的默认菜单链接,然后点击 hl7_error_messages 旁边的跟踪按钮。现在,让我们通过终止网关节点进程并插入一个新的患者记录来测试这个功能。幸运的话,我们现在应该在hl7_error_messages表中有一条记录,因为我们没有对消息进行转义,所以我们可以用 JSONPath 直接从 API 中查询它(见下文)。

作者图片

既然错误响应存在于一个跟踪的表中,我们可以继续通过 Hasura 创建任意数量的新事件,遵循我们之前所做的相同步骤,在新记录插入到hl7_error_messages中时触发电子邮件/松弛通知警报挂钩。

我希望这个演示为您下次使用 HL7 v2 提供了另一个选择,如果您正在采用微服务方法,我们很想知道如何实现。如果你需要帮助或想要更多关于医疗保健互操作性和集成的阅读,请前往 whitebrick.com,不要犹豫。

用旋转 iPhone 解释传感器融合

原文:https://towardsdatascience.com/sensor-fusion-explained-with-rotating-iphone-fecbcd0df144

传感器融合是利用多个传感器来降低预测的不确定性。更正式的定义来自 IEEE 地球科学与遥感学会数据融合技术委员会[1]:

组合由不同仪器和来源提供的空间和时间索引数据
的过程,以改进这些数据的
处理和解释。

传感器融合广泛用于多种工程应用,从 GPS 定位检测到自动驾驶。传感器融合是被称为信息融合的更一般术语的特例。有两种不同类型的传感器融合:直接和间接。

间接融合来自先验知识和人类或环境输入。例如,如果一个人想确定食物是否新鲜,使用人类的视觉传感器可能是不够的。嗅觉、触觉以及我们对食物储存地点和生产时间的先验知识相结合,可能会让我们对自己是否食用食物有一个全面的了解。

直接融合可以来自异类和同类传感器。它也可以来自软传感器或芯片。让我们看看这些融合类型的例子。

同类传感器是测量相同信息的相似传感器。例如,你可以想象几个温度计,每个都有一定程度的内部误差,放在房间的中央。通过合并这两个温度计的测量值,可以更好地估计室内的平均温度,减少温度计测量的不确定性。

塞莫普罗在 Unsplash 上拍照

异质传感器可以是房间中不同位置的相同温度计。然而,他们都测量温度,房间内的温度可能会因位置不同而不同。考虑到温度计的位置和温度计的内部误差,人们可以从这些局部测量中得出室内的平均温度。

软传感器或软件传感器是虚拟传感器,其中几个测量一起处理以给出系统状态的一个估计。人们可以想到手机如何根据 GPS 坐标和 Wi-Fi 信号来估计位置,这提高了位置检测的速度和精度。可以将 iPhone 中的这个传感器视为一个传感器,但是,它是几个数据源的组合,是一个软传感器。

让我们自己建立一个简单的软传感器。假设我们要测量 iPhone 方位的角度 α(t) ,如图所示:

作者图片。左上:旋转视频。右上:根据传感器数据计算的相同旋转。下图代表从传感器数据计算出的α值。

为了简单和可再现性的目的,我们记录 iPhone 旋转的数据,然而,通过小的额外努力,这种方法可以被修改为在线工作。

数据收集

为了简化实验设置,人们可以将 iPhone 握在手中,并围绕一个轴旋转。以下是这篇博文的数据收集方式的更多细节:

在开始记录一个测量传感器数据的应用程序后,我一手拿着 iPhone,让它的屏幕指向我,并左右旋转它。我以不同的速度旋转 iPhone 次。在两次旋转之间,我将 iPhone 返回到初始位置,并保持在初始状态大约 5 秒钟。

收集的数据包括投影在 iPhone 和时间对应轴上的加速度(a0,a1,a2)和转速(o0,o1,o2)。数据看起来是这样的:

作者图片

旋转物理学

方便考虑 iPhone 附带的坐标系 e0e1e2 在静止坐标系中的旋转 XYZ:

*图片作者。*iPhone 附带的坐标系 e0e1e2。XYZ 坐标系处于静止状态。

如果我们将 iPhone 屏幕垂直放在手边,那么 e0 轴指向右侧,e1 轴指向上方,e2 轴从 iPhone 屏幕指向我们。在这种情况下,总旋转矢量ω为:

我们可以通过对相应向量与ω的叉积求积分,找到 e0、e1 和 e2 中每个向量的相应坐标:

目标是测量 X 轴和矢量 e0XY 平面上的投影之间的角度 α 。可以用下面的公式来计算:

如果 e0 的投影更靠近 Y 轴,我们就认为 α 为正。如果投影与 αx 之间的角度大于 pi/2 则为负:

无传感器融合的软传感器

首先,我们尝试只使用来自 iPhone 陀螺仪的数据。使用等式(1)-(4),我们可以构建测量 α(t) 的软传感器。然而,由于测量误差和数值误差,iPhone 附带的坐标系在一段时间后变得不正交。为了实现正交性,可以使用格拉姆-施密特变换。

完整的算法导致以下步骤:

  1. 计算 iPhone 坐标中的总转速(方程式。1)
  2. 基于总旋转(等式)更新 iPhone 坐标。2)
  3. 新 iPhone 坐标上的格拉姆-施密特变换
  4. 计算 α (等式。3–4)

用于评估 iPhone 方向的 python 脚本可能如下所示:

这将导致下面的 α(t):

作者图片

数据收集以这样一种方式进行,即在旋转之间 iPhone 返回到初始位置。尽管在旋转周期之间有重要的值 α(t) (标记为红色)。问题出在不连续的测量上。在积分过程中,我们在测量值之间近似未知值,这些近似会导致漂移。

第 80 秒和第 85 秒之间的再现旋转将如下所示:

图片作者。无校正旋转。左上:旋转视频。右上:根据传感器数据计算的相同旋转。下图代表从传感器数据计算出的α值。

注意,轴线 e2 不再指向我们(不与轴线 Z 对齐)。此外,旋转发生在-75 grad 值附近,这与旋转的视频记录不一致。

传感器融合软测量

改善这种情况的一种方法是将转速数据与加速度数据融合。有了加速度数据,就很容易判断出重力的方向。iPhone 的初始 e1 轴与重力方向相反。旋转之间的静止状态也是如此: e1 与重力相反。有可能在总转动矢量中加入一个松弛项,这将说明静止状态下的 e1 与重力方向相反。当轴线 e1 偏离,并且不指向重力的相反方向时,这个松弛项会使它向后移动。Berkley [2]的一项“被扔的 iPhone”研究中使用了类似的修正。

关于我们的系统,我们知道的另一个事实是,一般来说,我们围绕手机的 e2 轴旋转手机,在实验过程中,该轴不会发生剧烈变化。所以 e2 通常与静止系统的 Z 轴方向相同。为了说明这一事实,我们可以添加另一个松弛项,如果 e2 轴由于数字或测量误差而漂移,它将返回到 Z 轴。

这种松弛项的公式是:

其中 kf 是融合系数,可以根据经验得出(发现等于 1 就足够了)。注意,在 e2 校正的情况下,由于 e2 和 Z 轴之间的角度不影响 *α的测量,因此 Z 轴的松弛将会起作用。*然而,如果我们选择松弛到 e1 而不是加速度矢量,这将影响 α 的测量。融合算法如上所述,但是增加了额外的步骤 1b:

α(t) 的曲线上不再观察到漂移;

作者图片

iPhone 数据的重建与视频记录非常吻合:

作者图片。传感器融合旋转。左上:旋转视频。右上:根据传感器数据计算的相同旋转。下图代表从传感器数据计算出的α值。

完整的代码可在这里。传感器融合快乐!

附注:我要感谢谢尔盖·利特维诺夫对邮报的帮助。

P.P.S:在第二部分,我比较了这篇博文和视频中的定位。这里是环节。

[1]用于交通管理和互联车辆的 ITS 传感器和架构,Lawrence A. Klein,2017 年

[2]https://rotations . Berkeley . edu/re constructing-of-motion-of-a-throwed-iphone/

在社交媒体情绪分析中提升自己的水平

原文:https://towardsdatascience.com/sentiment-analysis-74624b075842

了解客户对你的产品和服务的感受

在 Unsplash 上由 Belinda Fewings 拍摄的照片

什么是情感分析?

情感分析有助于理解文本数据的语气,积极的、消极的或中性的。捕捉情感可以帮助组织更好地理解客户的声音(VOC) 甚至指导产品开发以改进功能。通常,情感分析是基于词汇和规则的,这意味着它对被人类标记为积极、消极或中性的词进行查找。还有更先进的模型可用,如 2018 年由谷歌开源的 BERT。这篇文章将涵盖更传统的基于词典的方法;我们稍后将了解深度学习模型。

你需要熟悉新的术语来解释结果。它们是简单的概念,但是提前理解它们将有助于你更好地理解。

  • 极性:表示一个句子从否定到肯定的情感程度的数值。[-1.0,1.0]范围内的值(负面情绪= > -1.0,中性= > 0.0,正面情绪= > 1.0)
  • 主观性:主观性句子表达个人的感受、观点或信仰。主观性是范围[0.0,1.0]内的值,其中 0.0 非常客观,1.0 非常主观。

推特数据

对于这个例子,我们将使用从 Twitter 中提取的数据。Twitter 是 VOC 分析的绝佳来源。您可以搜索产品名称、标签、提及或公司名称。对于 Python,我们可以使用 Twitter API 的 Tweepy 包装器。

在寻找非常积极或非常消极的数据的伟大例子的过程中,我碰巧在宣读 Ghislaine Maxwell 审判裁决的时候写下了这篇文章并下载了数据,并认为这将是一个非常好的开始否定的地方。谁会相反,几乎所有的推文都是正面的?我选择了泰勒斯威夫特。****

我不会覆盖我用来提取推文的实际代码,但如果你想自己尝试,所有代码都可以在这里找到:推文提取笔记本

像往常一样,让我们导入将要使用的库并导入我们的数据来开始。

import pandas as pd
from textblob import TextBlob
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
import seaborn as sns
import matplotlib.pyplot as plt
swift = pd.read_pickle('swift.pkl')
maxwell = pd.read_pickle('maxwell.pkl')

基于纹理块的情感分析

TexBlob 是一个我喜欢用于快速 NLP 项目的包。这是一个简单的 Python API,支持情感分析等常见任务。它包含两个不同的情感分析器。第一个叫[PatternAnalyzer](https://github.com/clips/pattern),另一个叫 NLTKs NaiveBayesAnalyzer,在一个影评语料库上训练。

从 TextBlob 中获取极性(或主观性)分数很简单。我们可以使用熊猫的apply方法来获取每条推文的“情绪”。

# Apply the Polarity Scoring from TextBlob
swift['blob'] = swift['text'].apply(lambda x: TextBlob(x).sentiment.polarity)
swift.head()
TWEET POLARITY
0 RT @TSwiftFTC: 🥇 According to @HITSDD, Taylor ... 1.000000
1 RT @taylorr_media: Taylor Swift - All Too Well...  0.000000
2 Taylor Swift and Ed Sheeran music mainly. And ...  0.166667
3 RT @soitgoes: Taylor Swift didn't write:...        0.200000
4 Suporte list: Nial Horan, Demi Lovato, Taylor ...  0.000000

就这么简单,我们有我们的极性分数。我们可以在上面的例子中看到,我们有一些从中性到最大正值的1.0。通常,你的文字会有一种中性的情绪。由于中立的推文不会为分析添加任何信息,我们可以删除它们,只留下那些积极和消极的信息。

# Get rid of neutral sentiment
filter = swift['blob'] != 0
swift = swift[filter]

接下来画出我们结果。我用的是 Seaborn的histplot。直方图非常适合可视化极性得分,因为它们可以很好地归入-1.0 到 1.0 的范围内。

sns.histplot(swift, x='blob', color="#7C8C58", bins=10)
plt.title("Taylor Swift Sentiment Distribution with TextBlob")
plt.xlabel("Sentiment")
plt.ylabel("")

下面,你可以看到泰勒斯威夫特的推文大多是正面的,而麦克斯韦尔的推文大多是负面的。

作者图片

作者图片

使用 Vader 进行社交媒体情感分析

TextBlob 不适用于较短的文本或社交媒体帖子。它更适合用通用语言模式编写的更长、更简洁的字符串。然而,专门针对社交媒体的工具已经出现,这些工具能够理解如何处理社交媒体中使用的语言模式。其中一个就是 VADER 库。VADER 专门为社交媒体处理的一些事情有:

  • 助推词:增加感情的词,如伟大爱情
  • 全大写:全大写的单词经常被用来放大情感
  • 标点符号:标记如**!或者!!!**会增加人气
  • 俚语:正确解释 SUXBFF 等词语
  • 表情符号 : UTF-8 编码表情符号被正确处理

注意: 字符串不能像其他 NLP 方法一样被 清理 。VADER 将从未经加工的文本中提取许多上下文。

在我们进入 Twitter 数据之前,让我们先来看看只包含表情符号的几个字符串是如何处理的。

positive = "💕 😁 🎉"
negative = "💔 😬 🙁"
{'neg': 0.0, 'neu': 0.375, 'pos': 0.625, 'compound': 0.875}
{'neg': 0.514, 'neu': 0.203, 'pos': 0.284, 'compound': -0.3415}

这两个字符串将返回带有文本块的0.0,带有 VADER 的,它们显示的compound分数似乎与表情符号所代表的情绪一致。

让我们做与上面相同的过程,但是利用 VADER 图书馆。我们将在数据帧上使用相同的apply方法。

# Add the polarity scores
swift['vader'] = swift['text'].apply(lambda x: sid.polarity_scores(x))
{'neg': 0.0, 'neu': 0.793, 'pos': 0.207, 'compound': 0.7184}

结果列实际上是不同的键值对字典。代表文本块sentiment的键值是一个叫做compound的键值。我们可以通过对数据帧应用以下函数来提取它:

# Extract only the compound score value
swift['compound'] = swift['vader'].apply(lambda score_dict: score_dict['compound'])

再次绘制我们的结果后,我们可以看到 VADER 更好地代表了情绪。斯威夫特的得分更偏向于正面,麦克斯韦尔的得分更偏向于负面。无论是表情符号还是人们强调自己感受的其他常见方式,VADER 在推文中捕捉的情感都比文本 Blob 更多。

作者图片

作者图片

结论

你有它!客户之声对社交媒体数据的情感分析。这篇文章只是你能做什么以及如何利用这些信息的开始;然而,它是你工具箱中的一个强有力的工具,可以更好地理解你的客户和他们的情绪。Twitter 数据提取和情感分析的完整代码可以在 GitHub 上获得。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。一个月 5 美元,让你可以无限制地访问成千上万篇文章。如果你用我的链接注册,我会给你一点佣金,不会增加你的额外费用。

情感分析—简介和实施

原文:https://towardsdatascience.com/sentiment-analysis-intro-and-implementation-ddf648f79327

使用 NLTK、scikit-learn 和 TextBlob 进行情感分析

分析文本理解感受。E 2

你有没有在网上留下过对某个产品、服务或者某部电影的评论?或者也许你是那些不留下评论的人之一——那么,在推特、脸书或 Instagram 上发表任何文字帖子或评论怎么样?如果答案是肯定的,那么很有可能算法已经审查了你的文本数据,以便从中提取一些有价值的信息。

品牌和企业根据从这些文本中提取的信息做出决策。例如,如果一部电影在网飞或 Prime Video 上不成功,每个公司的科学家都会深入研究电影评论,了解这部不成功电影背后的原因,以避免未来犯同样的错误。投资公司将推文(和其他文本数据)作为其投资模型的变量之一进行监控——众所周知,埃隆·马斯克每隔一段时间就会发布如此具有财务影响力的推文!如果你很想了解这些公司是如何从这些文本输入中提取信息的,那么这篇文章就是为你准备的。

在这篇文章中,我们将通过仔细观察情感分析来了解更多关于成为数据科学家的技术要求。在自然语言处理领域,情感分析是从文本数据中识别、量化、提取和研究主观信息的工具。比如“我喜欢看电视剧。”带有积极的情绪。但是,如果一个人说“我真的很喜欢看电视节目”,这种情绪甚至可能“相对更”积极。情感分析试图量化文本数据中传达的情感。情感分析的一个最常见的用例是让品牌和企业能够查看客户的反馈并监控他们的满意度。可以想象,让员工阅读客户评论来确定客户对业务、服务或产品是否满意是非常昂贵的。在这种情况下,品牌和企业使用情感分析等机器学习技术来大规模实现类似的结果。

和我的其他帖子类似,学习会通过练习问答来实现。我将根据需要在问题中包含提示和解释,以使旅程更容易。最后,我用来创建这个练习的笔记本也链接在文章的底部,你可以下载,运行和跟随。

我们开始吧!

https://medium.com/@fmnobar/membership

数据集

为了练习情感分析,我们将使用来自 UCI 机器学习库的测试集,该测试集基于论文“使用深度特征从组到个体标签”(Kotzias et al .al,2015 )并且可以从这个链接下载(CC BY 4.0)。

让我们从导入我们今天将使用的库开始,然后将数据集读入数据帧,并查看数据帧的前五行来熟悉数据。

# Import required packages
import numpy as np
import pandas as pd
import nltk# Making width of the column viewable
pd.set_option('display.max_colwidth', None)# Read the data into a dataframe
df = pd.read_csv('movie_reduced.csv')# look at the top five rows of the dataframe
df.head()

结果:

只有两列。“文本”包含评论本身,“标签”表示评论的情绪。在这个数据集中,标签 1 表示积极情绪,而标签 0 表示消极情绪。既然只有两类标签,那我们就来看看这两类是平衡的还是不平衡的。当类(粗略地)占总观测值的相同部分时,类被认为是平衡的。让我们看看数据,这样更容易理解。

df['label'].value_counts()

该数据在积极情绪和消极情绪之间几乎平分秋色,因此我们认为该数据具有平衡的类别。

接下来,我们将创建一个示例字符串,它包括数据帧的“text”列中的第一个条目。在一些问题中,我们将对这个样本应用各种技术来更好地理解概念。让我们继续创建我们的样本字符串。

# Take the very first text entry of the dataframe
sample = df.text[0]
sample

教程+问答

令牌和二元模型

为了让程序和计算机理解/使用文本数据,我们首先将较大的文本数据片段分解成较小的片段。将一个字符序列(如一个字符串)分解成更小的部分(或子字符串)称为记号化,执行记号化的函数称为记号化器。记号赋予器可以将给定的字符串分解成一系列子字符串。让我们看一个例子。

输入:“什么是句子?”

如果我们对上面的“输入”应用一个记号化器,我们将得到下面的“输出”:

输出:[‘What’, ‘is’, ‘a’, ‘sentence’, ‘?’]

正如所料,输出是输入句子的标记化子字符串序列。

我们可以用nltk.word_tokenize包来实现这个概念。让我们看看这是如何在一个例子中实现的。

问题 1:

对生成的样本进行标记化,并返回前 10 个标记。

回答:

# Import the package
from nltk import word_tokenize# Tokenize the sample
sample_tokens = word_tokenize(sample)# Return the first 10 tokens
sample_tokens[:10]

结果:

令牌也称为一元语法。如果我们把两个一元词组合起来,我们就得到一个二元词(这个过程可以继续)。形式上,二元模型是一个 n 元模型,其中 n 等于 2。n 元语法是来自给定文本样本的 n 个相邻项的序列。因此,二元模型是一串标记中两个相邻元素的序列。举个例子会更容易理解:

原句:“什么是句子?”

代币:[‘What’, ‘is’, ‘a’, ‘sentence’, ‘?’]

二元模型:[(‘What’, ‘is’), (‘is’, ‘a’), (‘a’, ‘sentence’), (‘sentence’, ‘?’)]

正如所料,现在每两个相邻的标记都在一个二元模型中表示。

我们可以用nltk.bigrams包来实现这个概念。

问题二:

从标记化的样本中创建二元模型列表,并返回前 10 个二元模型。

回答:

# Import the package
from nltk import bigrams# Create the bigrams
sample_bitokens = list(bigrams(sample_tokens))# Return the first 10 bigrams
sample_bitokens[:10]

结果:

频数分布

让我们回到从我们的示例中创建的令牌(单字)。看到有哪些标记是很好的,但是在给定的文本输入中,知道哪些标记比其他标记具有更高的表示可能更有意义。换句话说,记号的出现频率分布将更能提供信息。更正式的说法是,频率分布记录了实验的每个结果出现的次数。

让我们使用nltk.FreqDist包实现一个频率分布。

问题三:

在我们的示例中,前 10 个最常用的令牌是什么?

回答:

# Import the package
from nltk import FreqDist# Create the frequency distribution for all tokens
sample_freqdist = FreqDist(sample_tokens)# Return top ten most frequent tokens
sample_freqdist.most_common(10)

结果:

一些结果直观上是有意义的。例如,逗号、“the”、“a”或句号在给定的文本输入中可能非常常见。现在,让我们将所有这些步骤放入一个 Python 函数中,以简化流程。如果你需要 Python 函数的复习,我有一个关于 Python 函数练习题的帖子链接在这里。

问题 4:

创建一个名为“top_n”的函数,它接受一个文本作为输入,并返回给定文本中前 n 个最常见的标记。使用“文本”和“n”作为函数参数。然后在我们的样本上试一试,重现上一个问题的结果。

回答:

# Create a function to accept a text and n and returns top n most common tokens
def top_n(text, n):# Create tokenstokens = word_tokenize(text)# Create the frequency distributionfreqdist = FreqDist(tokens)# Return the top n most common onesreturn freqdist.most_common(n)# Try it on the sample
top_n(df.text[1], 10)

我们能够使用函数再现相同的输出。

文档术语矩阵(DTM)是表示术语在文档集合中出现的频率的矩阵。让我们看两个句子来理解 DTM 是什么。

假设我们有以下两句话:

sentence_1 = 'He is walking down the street.'sentence_2 = 'She walked up then walked down the street yesterday.'

DTM 的上述两句话将会是:

在上面的 DTM 中,数字表示该特定术语(或标记)在给定的句子中出现了多少次。例如,“down”在两个句子中都出现了一次,而“walked”出现了两次,但只出现在第二个句子中。

现在让我们看看如何使用 scikit-learn 的CountVectorizer实现 DTM 概念。注意,最初使用 scikit-learn 创建的 DTM 是稀疏矩阵/阵列的形式(即大多数条目为零)。这样做是为了提高效率,但我们需要将稀疏数组转换为密集数组(即大多数值都是非零的)。因为理解稀疏阵列和密集阵列之间的区别不是这篇文章的目的,所以我们不会深入讨论这个话题。

问题 5:

定义一个名为“create_dtm”的函数,为给定的一系列字符串创建一个数据帧形式的文档术语矩阵。然后在我们数据集的前五行上测试它。

回答:

# Import the package
from sklearn.feature_extraction.text import CountVectorizerdef create_dtm(series):# Create an instance of the classcv = CountVectorizer()# Create a document term matrix from the provided seriesdtm = cv.fit_transform(series)# Convert the sparse array to a dense arraydtm = dtm.todense()# Get column namesfeatures = cv.get_feature_names_out()# Create a dataframedtm_df = pd.DataFrame(dtm, columns = features)# Return the dataframereturn dtm_df# Try the function on the top 5 rows of the df['text']
create_dtm(df.text.head())

结果:

特征重要性

现在我们想把情感分析当做一个机器学习模型。在这样的机器学习模型中,我们希望模型接受文本输入,并对每个文本条目的情感做出预测。换句话说,文本输入是自变量,情感是因变量。我们还了解到,我们可以将文本分解成更小的称为标记的片段,因此,我们可以将文本输入中的每个标记视为“特征”,帮助预测作为机器学习模型输出的情感。总而言之,我们从一个接受大量文本数据和预测情感的机器学习模型开始,但现在我们已经将我们的任务转换为一个接受多个“标记”(而不是大量文本)并基于给定标记预测情感的模型。那么下一个逻辑步骤将是尝试量化哪些表征(即特征)在预测情感中更重要。这个任务被称为特征重要性。

幸运的是,在 scikit-learn 中可以很容易地实现特性重要性。我们一起来看一个例子。

问题 6:

定义一个名为“top_n_tokens”的函数,该函数接受三个参数:(1)“text”,它是数据框列格式的文本输入,(2)“impression”,它是数据框列格式的给定文本的情感标签,以及(3)“n”,它是一个正数。该函数将返回前“n”个最重要的表征(即特征)来预测“文本”的“情感”。请使用sklearn.linear_model中的LogisticRegression和以下参数:solver = 'lbfgs'max_iter = 2500random_state = 1234。最后,使用函数返回 dataframe 的“text”列中前 10 个最重要的标记。

注: 由于这篇文章的目标是探索情绪分析,我们假设读者熟悉逻辑回归。如果你想更深入地了解逻辑回归,请查看 这篇文章

回答:

# Import logistic regression
from sklearn.linear_model import LogisticRegressiondef top_n_tokens(text, sentiment, n):# Create an instance of the classlgr = LogisticRegression(solver = 'lbfgs', max_iter = 2500, random_state = 1234)cv = CountVectorizer()# create the DTMdtm = cv.fit_transform(text)# Fit the logistic regression modellgr.fit(dtm, sentiment)# Get the coefficientscoefs = lgr.coef_[0]# Create the features / column namesfeatures = cv.get_feature_names_out()# create the dataframedf = pd.DataFrame({'Tokens' : features, 'Coefficients' : coefs})# Return the largest nreturn df.nlargest(n, 'Coefficients')# Test it on the df['text']
top_n_tokens(df.text, df.label, 10)

结果:

结果相当有趣。我们在寻找最重要的特征,正如我们所知,标签 1 表示数据集中的积极情绪。换句话说,最重要的特征(即,具有最高系数的特征)将是指示强烈积极情绪的特征。这在结果中得到了体现,这些结果听起来都非常积极。

为了验证这一假设,让我们看看 10 个最小的系数(即最不重要的特征)。我们预计这些会传达出强烈的负面情绪。

# Import logistic regression
from sklearn.linear_model import LogisticRegressiondef bottom_n_tokens(text, sentiment, n):# Create an instance of the classlgr = LogisticRegression(solver = 'lbfgs', max_iter = 2500, random_state = 1234)cv = CountVectorizer()# create the DTMdtm = cv.fit_transform(text)# Fit the logistic regression modellgr.fit(dtm, sentiment)# Get the coefficientscoefs = lgr.coef_[0]# Create the features / column namesfeatures = cv.get_feature_names_out()# create the dataframedf = pd.DataFrame({'Tokens' : features, 'Coefficients' : coefs})# Return the largest nreturn df.nsmallest(n, 'Coefficients')# Test it on the df['text']
bottom_n_tokens(df.text, df.label, 10)

结果:

不出所料,这些话传达出强烈的负面情绪。

在前面的示例中,我们对现有的标记数据训练了一个逻辑回归模型。但是,如果我们没有标记的数据,并希望确定一个给定数据集的情绪呢?在这种情况下,我们可以利用预先训练的模型,如 TextBlob,我们将在接下来讨论它。

预训练模型—文本块

TextBlob 是一个用于处理文本数据的库,其功能之一是以命名元组的格式返回给定数据的情感,如下所示:“(极性,主观性)”。极性得分是[-1.0,1.0]范围内的浮动值,旨在区分文本是正面还是负面。主观性是在[0.0,1.0]范围内的浮动,其中 0.0 非常客观,1.0 非常主观。例如,一个事实被认为是客观的,而一个人的观点被认为是主观的。极性和主观性检测是情感分析中最常见的两项任务,我们将在下一个问题中探讨。

问题 7:

定义一个名为“polarity_subjectivity”的函数,它接受两个参数。该函数将“TextBlob”应用于所提供的“text”(默认为“sample”),如果“print_results = True ”,则使用“TextBlob”打印“text”的极性和主观性,否则返回一组浮点值,其中第一个值为极性,第二个值为主观性,例如“(polarity,subjectivity)”。返回元组应该是函数的默认设置(即 set print_results = False)。最后,对我们的示例使用该函数并打印结果。

提示: 如果你需要安装 TextBlob,你可以使用下面的命令: *!pip install textblob*

回答:

# Import TextBlob
from textblob import TextBlobdef polarity_subjectivity(text = sample, print_results = False):# Create an instance of TextBlobtb = TextBlob(text)# If the condition is met, print the results, otherwise, return the tupleif print_results:print(f"Polarity is {round(tb.sentiment[0], 2)} and subjectivity is {round(tb.sentiment[1], 2)}.")else:return(tb.sentiment[0], tb.sentiment[1])# Test the function on our sample
polarity_subjectivity(sample, print_results = True)

结果:

让我们看看这个例子,并尝试解释这些值。

sample

结果:

与其他字符串相比,解释这些结果更有意义,但是在没有这种比较的情况下,纯粹基于数字,让我们尝试解释这些结果。结果表明,我们的样本具有轻微的正极性(记住极性范围从-1 到 1,因此 0.18 将表示轻微的正极性),并且相对主观,这具有直观的意义,因为这是某人描述他们对电影的主观体验的评论。

问题 8:

首先定义一个名为“token_count”的函数,该函数接受一个字符串,并使用“nltk”的单词标记器返回给定字符串中整数个标记。然后定义第二个名为“series_tokens”的函数,该函数接受 Pandas 系列对象作为参数,并将之前定义的“token_count”函数应用于给定的系列,返回给定系列的每行的整数个令牌。最后,在数据帧的前 10 行使用第二个函数并返回结果。

回答:

# Import libraries
from nltk import word_tokenize# Define the first function that counts the number of tokens in a given string
def token_count(string):return len(word_tokenize(string))# Define the second function that applies the token_count function to a given Pandas Series
def series_tokens(series):return series.apply(token_count)# Apply the function to the top 10 rows of the dataframe
series_tokens(df.text.head(10))

结果:

问题 9:

定义一个名为“series_polarity_subjectivity”的函数,该函数将问题 7 中定义的“polarity_subjectivity”函数应用于 Pandas 系列(以 dataframe 列的形式)并返回结果。然后使用数据帧前 10 行的函数来查看结果。

回答:

# Define the function
def series_polarity_subjectivity(series):return series.apply(polarity_subjectivity)# Apply to the top 10 rows of the df['text']
series_polarity_subjectivity(df['text'].head(10))

结果:

复杂性的度量——词汇多样性

顾名思义,词汇多样性是对给定文本中有多少不同词汇的度量,并被公式化地定义为唯一标记的数量占标记总数的比例。其思想是,文本中的词汇标记越多样化,文本就越复杂。让我们看一个例子。

问题 10:

定义一个“complexity”函数,该函数接受一个字符串作为参数,并返回词法复杂性得分,该得分定义为所有标记中唯一标记的数量。然后将该函数应用于数据帧的前 10 行。

回答:

def complexity(string):# Create a list of all tokenstotal_tokens = word_tokenize(string)# Create a set of all tokens (which only keeps unique values)unique_tokens = set(word_tokenize(string))# Return the complexity measurereturn len(unique_tokens) / len(total_tokens)# Apply to the top 10 rows of the dataframe
df.text.head(10).apply(complexity)

结果:

文本清理—停用词和非字母

如果你记得在问题 3 中,我们进行了频率分布,得到的 10 个最常见的表征如下:[(',',4),('非常',3),(' A ',1),('缓慢移动',1),('漫无目的',1),('电影',1),('关于',1),(' A ',1),('苦恼',1),('漂泊',1)]

其中一些不是很有帮助,与其他标记相比被认为不太重要。例如,知道句号在给定的文本中很常见,可以获得多少信息?试图过滤掉这些不太重要的单词,以便将注意力集中在更重要的单词上,这种尝试被称为去除停用词。请注意,这些停用词没有统一的定义,这种指定纯粹是主观的。

让我们来看一些由nltk定义的英语停用词的例子:

# Import library
from nltk.corpus import stopwords# Select only English stopwords
english_stop_words = stopwords.words('english')# Print the first 20
print(english_stop_words[:20])

结果:

['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his']

问题 11:

定义一个名为" stopword_remover "的函数,该函数接受一个字符串作为参数,对输入字符串进行标记,删除英文的停用词(由nltk定义),并返回不带停用词的标记。然后将该函数应用于数据帧的前 5 行。

回答:

def stopword_remover(string):# Tokenize the stringtokens = word_tokenize(string)# Create a list of English stopwordsenglish_stopwords = stopwords.words('english')# Return non-stopwordsreturn [w for w in tokens if w.lower() not in english_stopwords]# Apply to the top 5 rows of our df['text']
df.text.head(5).apply(stopword_remover)

结果:

我们可以考虑过滤掉的另一组标记,类似于停用词,是非字母标记。顾名思义,非字母的例子有:! % & # * $(注意空格也被认为是非字母)。为了帮助识别什么被认为是字母,我们可以使用isalpha(),这是一个内置的 Python 函数,它检查给定字符串中的所有字符是否都是字母。让我们看几个例子来更好地理解这个概念:

string_1 = "TomAndJerryAreFun"
string_2 = "Tom&JerryAreFun"
string_3 = "TomAndJerryAreFun!"print(f"String_1: {string_1.isalpha()}\n")
print(f"String_2: {string_2.isalpha()}\n")
print(f"String_3: {string_3.isalpha()}")

结果:

让我们来看看每一个,以便更好地理解发生了什么。第一个返回“True ”,表明该字符串只包含 alpabeticals。第二个返回“False”,这是因为“&”,第三个也返回“False”,由“!”驱动。

现在我们已经熟悉了isalpha()的工作方式,让我们在例子中使用它来进一步清理我们的数据。

问题 12:

定义一个名为“stopword_nonalpha_remover”的函数,该函数接受一个字符串作为参数,删除停用词(使用我们在上一个问题中定义的“stopword_remover”函数)和非字母字符,然后返回余数。将此函数应用于我们的数据帧的前 5 行,并与上一个问题的结果(仍包括非字母)进行视觉比较。

答案:

def stopword_nonalpha_remover(string):return [x for x in stopword_remover(string) if x.isalpha()]df.text.head().apply(stopword_nonalpha_remover)

结果:

不出所料,除了停用词之外,非字母符号也被删除了。因此,与被移除的记号相比,预期具有更高重要性的记号。

在下一步中,我们将把我们到目前为止学到的所有东西放在一起,找出哪些评论具有最高的复杂性分数。

问题 13:

定义一个名为“complexity_cleaned”的函数,该函数接受一个序列并删除停用词和非字母(使用问题 12 中定义的函数)。然后在我们的 dataframe 中创建一个名为“complexity”的列,使用“complexity_cleaned”函数来计算复杂度。最后,返回数据帧中 10 个最大复杂度得分的行。

回答:

# Define the complexity_cleaned function
def complexity_cleaned(series):return series.apply(lambda x: complexity(' '.join(stopword_nonalpha_remover(x))))# Add 'complexity' column to the dataframe
df['complexity'] = complexity_cleaned(df.text)# Return top 10 highest complexity scores
df.sort_values('complexity', ascending = False).head(10)

结果:

带练习题的笔记本

下面是带问题和答案的笔记本,您可以下载并练习。

结论

在这篇文章中,我们讨论了 once 如何利用机器学习模型从文本数据中提取信息,这些信息可用于在业务层面上做出决策,如业务方向甚至投资策略。然后,我们实施了情感分析技术,以了解这些机器学习模型如何工作,以及可以从这些文本数据中提取哪些信息。

感谢阅读!

如果你觉得这篇文章有帮助,请在媒体上关注我,订阅接收我的最新文章!

基于 Python 支持向量机模型的 IMDB 电影评论数据集的文本清洗和超参数优化

原文:https://towardsdatascience.com/sentiment-analysis-on-a-imdb-movie-review-dataset-with-a-support-vector-machines-model-in-python-50c1d487327e

基于文本处理技术和超参数优化的电影评论情感分析。

来自 Freepik.com的免费矢量积分

介绍

本文旨在部署一种称为“支持向量机”的机器学习模型,特别关注文本清理部分和超参数优化,这两种技术将最有可能提高模型的准确性。

在之前的一篇文章中,我们看到了如何通过使用两种特征提取器方法(如词袋和 Tf-idf)和朴素贝叶斯分类器对 IMDB 电影评论数据集执行情感分析。虽然结果很有希望,但总有改进的余地,这是当前项目的最终目标。

在开始之前,我欠你一些有助于理解这个主题的基本定义。首先,理解什么是文本清理,或者定义为文本处理或文本操作是很重要的:

句子通常表示为文本(字符串),而文档可以描述为句子的集合。在计算中,术语文本处理指的是自动创建或处理电子文本的理论和实践。

文本处理的目标是在实现机器学习模型之前消除文本中包含的所有多余信息,这有助于减少“噪声”,使算法更容易识别模式并提高其泛化能力。因此,正确应用的文本操作允许从业者提高计算效率。这一步最终将有助于支持向量机模型的部署及其超参数优化。

作者设计的系统由图形编辑器提供支持

数据

我们将要使用的数据是 50,000 行电影评论,您可以在这个链接中找到。目标是通过在可用的行上训练它来产生一个高性能的情感分析器。如果你想回顾什么是情绪分析,我可以建议快速阅读这篇文章,它涵盖了所有的基础知识。csv 文件的结构非常简单,它有两列,一列包含评论,另一列包含情感。一旦该模型将对测试部分的部分评论进行重新分类,我们将能够计算出有多少评论被正确分类,这表明了 SVM 模型的整体准确性。下面显示了一个示例评论的样子:

I thought this was a wonderful way to spend time on a too hot summer weekend, sitting in the air conditioned theater and watching a light-hearted comedy. The plot is simplistic, but the dialogue is witty and the characters are likable (even the well bread suspected serial killer). While some may be disappointed when they realize this is not Match Point 2: Risk Addiction, I thought it was proof that Woody Allen is still fully in control of the style many of us have grown to love.<br /><br />This was the most I'd laughed at one of Woody's comedies in years (dare I say a decade?). While I've never been impressed with Scarlet Johanson, in this she managed to tone down her "sexy" image and jumped right into a average, but spirited young woman.<br /><br />This may not be the crown jewel of his career, but it was wittier than "Devil Wears Prada" and more interesting than "Superman" a great comedy to go see with friends.

截至目前,一个算法要在所有评论中找到一条共同的路径是非常复杂的。这是由于三个主要因素:字符数、单词范围和特殊字符。前两个是直观的。关于第三个,如果你仔细观察,你可以发现 HTML 换行符“

”。这些以及括号、问号、逗号和句号都需要删除,因为它们没有添加任何关于情感的有趣信息。

文本处理

标记化

标记化将整个文档或句子分解成一串字符,以确保更有效的操作。例如,算法对空格、黑线或换行符不感兴趣。标记化过程的结果只有单词和标点。

词汇化和停用词

词汇化是将单词简化为它们的规范和基本形式。例如,动词 writing、writes、written 和 written 可以用单词 write 来表示,即相关的词条。变元化允许简化过程,算法可以引用单个单词而不是它的所有形式。另一方面,停用词指的是删除一些在情感计算中几乎没有价值的词。冠词“a”或“an”不表示任何积极或消极的情绪。

支持向量机

支持向量机算法是一种监督学习模型,具有分析数据以进行分类和回归分析的组合算法。它是由弗拉基米尔·瓦普尼克开发的,最初的想法可以追溯到 1979 年,就在自 1973 年以来持续时间相对较短的人工智能冬季结束之前。SVM 分类器是基于统计学习的非概率分类器。与每一个监督学习模型一样,SVM 需要标记数据来识别相关模式,只有这样,它才能部署在新记录上。SVM 的基础概念是线性可分二元分类。这意味着类别 1 和类别 2 之间的数据可以用一条直线来划分,这条直线称为超平面。最重要的是,支持向量机的特点是最大化第 1 类和第 2 类样本之间的空间,这是通过定义为向量的两条以上的线来识别的。

通过两个线性可分类的超平面(Appel,Chiclana,Carter 和 Fujita,2016)

支持向量机的潜在应用范围包括手写识别、入侵检测、人脸检测、电子邮件分类、基因分类和网页。支持向量机可以处理线性和非线性数据的分类和回归问题,这使得一个通用的 ml 算法。与其他算法相比,在处理具有大量特征的小数据集时,支持向量机的性能更好。

超参数

在定义超参数之前,定义一个“标准”参数是很重要的。当一个模型收敛时,我们可以说它找到了描述它所训练的数据的一般行为的最佳参数组合。在 SVM 模型的情况下,如果以下公式为真,我们可以将记录分类为阳性:

在负记录的情况下会发生相反的情况:

参数 **w、**和 b 确定新记录 X 将被分类为正还是负。 X 又称输入向量, w 为权重向量, b 为偏置。另一方面,超参数是从业者给予模型的外部配置,其值不能通过训练来估计。因此,可以修改超参数,以发现哪些组合导致更高的性能。

SVM 模型也不例外,它有两个主要的超参数,我们将用它们来优化预测过程:

  • c:逆正则化强度。正则化的强度与 C 成反比,它随着参数的增加而应用惩罚。它的作用是减少过度拟合。
  • 内核:指定算法中使用的内核类型。有五个可能的选项:“线性”、“多边形”、“rbf”、“sigmoid”和“预计算”。每一种都有独特的特征。

代码部署

文本清洗和预处理

代码部署的第一部分将集中在文本清理过程的表面使用,事实上,有许多不同的技术可以应用。在这篇文章中,我们将指出对最有效的方法的更广泛的理解,例如词汇化和停用词消除:

  • 导入库,如 pandas、re、nltk 和 bs4。请记住,在导入之前,请确保安装了所有这些软件包。
  • 在 nltk.corpus 可以使用它们之前,需要下载停用词。因此,在运行整个脚本之前,请确保您运行了命令“【nltk . download(' stop words ')”和“【nltk . download(' wordnet ')”。
  • 多亏了 pandas,csv 文件可以被导入并分配给 df 变量。编码必须是“Latin-1”以避免抛出错误。
  • 此时,我们可以将情感列中包含的两个值映射为 1 和 0,而不是正数和负数
  • 因此,我们可以设置停用词并将 WordNetLemmatizer()对象赋给 Lemmatizer 变量。
  • 可以定义这个阶段的 clean_text 函数。库 re 提供了正则表达式匹配操作。总而言之,代码消除了 HTML 换行符和所有特殊字符。然后,文本只被转换成小写字母。词汇化过程应用于每个单词。作为最后一步,停用词被删除。
  • clean_text 函数最终应用于“review”列下的每一行,因为创建了一个名为“Processed Reviews”的新列。

每个评论最终都准备好接受 SVM 算法的处理。第一个主要部分的结果如下:

think wa wonderful way spend time hot summer weekend sit air condition theater watch light hearted comedy plot simplistic dialogue witty character likable even well bread suspect serial killer may disappoint realize match point 2 risk addiction think wa proof woody allen still fully control style many u grow love wa laugh one woody comedy year dare say decade never impress scarlet johanson manage tone sexy image jump right average spirit young woman may crown jewel career wa wittier devil wear prada interest superman great comedy go see friend

你可能会注意到,每个句号、逗号、问号或括号都被过滤掉了。没有代词,也没有换行符。通过完成文本处理的第一个主要步骤,我们降低了数据的复杂性。该模型现在需要处理的符号和不同的单词少了很多,这可能会在保持高精度的同时提高其泛化能力。

模型部署

以下代码显示了 SVM 模型的简单模型部署,用于计算模型的准确性,而无需进行超参数优化。

  • 导入 sklearn 库及其子函数后,我们可以定义输入和目标变量。
  • 在每个 ml 过程中,训练和测试拆分方法遵循第一步,在这种情况下,测试大小是数据集中记录的 20%,训练是剩余的 80%。
  • 对于这个项目,我决定使用弓特征提取器及其基本参数。因此,计数矢量器创建一个字典,并根据字典准则转换 X_train 和 X_test 数据子集。
  • SVC()对象被分配给 SVM 变量以实例化该模型,然后该模型适合由脚本的训练部分的数据集提供的记录。
  • 最后,我们可以运行命令 SVM.predict(),为测试部分在新记录上部署模型。分类报告通过在实际情感和预测情感之间进行比较,向用户提供关于准确性的信息。

最初的结果相当令人欣慰,通过在 5035 条负面评论和 4965 条正面评论上测试该算法,整体准确率达到 87%。与我们在上一篇文章中采用的朴素贝叶斯方法相比,SVM 算法表现得更好。

precision    recall  f1-score   support0       0.89      0.86      0.87      50351       0.86      0.89      0.87      4965accuracy                           0.87     10000macro avg       0.87      0.87      0.87     10000
weighted avg       0.87      0.87      0.87     10000

超参数优化

我们现在知道了矢量器和 SVM 模型的默认设置的整体精度。以下代码的目的是计算超参数的最佳组合,以提高模型性能:

  • 我们可以从导入 sklearn 库的不同函数开始,比如 RepeatedStratifiedKfold、GridSearchCV、SVC、Pipeline 和 CountVectorizer。
  • 然后我们可以创建一个管道。计算中的管道概念大多数时候指的是数据管道,它是一组数据处理元素,其中一个元素的输出是下一个元素的输入。管道的第一个元素是计数矢量器(),我们将其重命名为“vect”,而第二个元素是 SVC() 。非正式地说,我们需要一个管道来允许交叉验证过程。
  • 构建参数列表,使得每个管道名称都与参数名称及其值相关联。例如,CountVectorizer 函数包括参数 max_df 和 ngram_range。vect__max_df 这个名称告诉我们,参数 max_df 与先前在管道部分中定义的“vect”相关联。
  • 网格搜索结合了在管道和参数网格中找到的信息,以计算最大化 SVM 性能的超参数的最佳组合。当然,这个概念要复杂得多,将在以后的文章中讨论。到目前为止,我们只对代码的机制感兴趣。网格搜索计算我们数据中的每个超参数组合。当然,每次执行 50,000 次计算是很大的工作量,这就是为什么我在这个特定的场景中将行数减少到只有 5000。
  • 最后一节通过报告平均精度和实现平均精度的超参数来组织和总结所有发现的结果。

代码运行了一个多小时,结果如下:

Best: 0.845663 using {'SVM__C': 50, 'SVM__kernel': 'rbf', 'vect__max_df': 0.5, 'vect__ngram_range': (1, 2)}
0.597360 (0.017354) with: {'SVM__C': 50, 'SVM__kernel': 'poly', 'vect__max_df': 0.1, 'vect__ngram_range': (1, 1)}
0.509796 (0.001329) with: {'SVM__C': 50, 'SVM__kernel': 'poly', 'vect__max_df': 0.1, 'vect__ngram_range': (1, 2)}
0.506197 (0.001325) with: {'SVM__C': 50, 'SVM__kernel': 'poly', 'vect__max_df': 0.1, 'vect__ngram_range': (1, 3)}
0.614556 (0.013541) with: {'SVM__C': 50, 'SVM__kernel': 'poly', 'vect__max_df': 0.2, 'vect__ngram_range': (1, 1)}

似乎最好的超参数是:

  • C=50
  • 内核是 rbf 类型的
  • max_df = 0.5
  • ngram 的范围是(1,2)

仅在 5000 条记录上计算的准确率分数为 84.5%。当然,它比我们最初得到的要低。不过,这一次,与我们之前使用的 40,000 条记录相比,该模型的训练记录要少得多。因此解释了性能上的差异。现在是使用超参数调整在完整数据集上实施模型并重新检查最终得分的时候了。为了使用新的超参数运行模型,有必要进行代码实现:

  • "count vect = count vector izer()"将变成"count vect = count vector izer(ngram _ range =(1,2),max_df=0.5) "因为我们告诉工具一次考虑两个单词的组(ngram),并忽略出现在超过 50%的文档中的术语(max_df)
  • "【SVM = SVC()"将变成" SVM = SVC(C = 50,内核= 'rbf') "因为我们告诉 SVM 使用 50 作为 C 参数,rbf 作为内核。

代码运行了大约 1 小时 30 分钟后,结果如下:

precision    recall  f1-score   support0       0.90      0.87      0.88      50351       0.87      0.90      0.89      4965accuracy                           0.88     10000macro avg       0.88      0.88      0.88     10000
weighted avg       0.88      0.88      0.88     10000

如您所见,精度仅提高了 0.01,从 0.87 提高到 0.88。值得计算吗?答案是:“看情况”。在这种情况下,该模型试图预测电影评论的情绪,88%的准确率和 87%的准确率非常接近。如果我们根据医疗条件来预测患者患糖尿病的概率,那么 88%的精确度是不够的。在之前的一篇文章中,我们使用相同的 IMDB 数据但不同的算法达到了 65%的准确率。仅仅通过改变分类器、执行文本清理和优化超参数,我们就看到了显著的提高。

最后一个测试告诉我们,一个潜在的评论说“这部电影真的很好,我想象不出更好的结局”,被算法正确地分类为1,而一个负面的评论说“这部电影总体上很差,情节很无聊,人物诠释得很差”,得分为0。一般来说,在从业者直接产生的数据上部署 ml 模型是一个好的实践,检查将立即暴露任何问题。

##Testing Algorithm on single sentences#Defining test sentences
test = ['The movie was really good, I could have not imagined a better ending']
test_1 = ['The movie was generally bad, the plot was boring and the characters badly interpreted']test = count_vect.transform(test).toarray()
test_1 = count_vect.transform(test_1).toarray()#Printing prediction
print(SVM.predict(test))
print(SVM.predict(test_1))output:
[1]
[0]

在我们结束之前,简单提醒一下。如果你已经读到这里,并且你觉得你理解了内容,试着把这作为你开始开发你自己的项目的一个信号。Kaggle 是一个惊人的平台,充满了等待探索和部署的大量数据集。怎么推荐都不为过。

结论

即使基本特征提取器和基本模型配置的准确度分数已经很高,超参数优化过程已经能够进一步提高它。和往常一样,机器学习让我惊讶的是,它可以比人类更快更有效地“学习”和分类记录。一个“简单”的统计算法在速度和准确性方面有可能取代人类,这确实令人惊讶。当然,也有局限性,但是技术最终可以让几乎每个人开发他们自己的模型并研究这个非凡的领域。

最后,如果您喜欢该内容,请考虑添加一个关注,以便在新文章发表时得到通知。如果你对这篇文章有什么要考虑的,写在评论里吧!我很想读读它们:)谢谢你的阅读!

PS:如果你喜欢我写的东西,如果你能通过 这个链接 订阅一个中等会员,那对我来说就是全世界。这是一种间接的支持我的方式,你会得到媒体文章提供的惊人价值!

参考

[1]维基百科贡献者。(2022 年 3 月 9 日)。文本处理。检索于 2022 年 3 月 14 日,来自维基百科网站:https://en.wikipedia.org/wiki/Text_processing

[2]维基百科贡献者。(2022 年 3 月 12 日)。支持向量机。2022 年 3 月 20 日,从维基百科网站检索:https://en.wikipedia.org/wiki/Support-vector_machine

[3]俄瑞斯忒斯·阿佩尔等人,“一种在句子层次上解决情感分析问题的混合方法”基于知识的系统108(2016):110–124。

📢使用 Python 和谷歌云功能的 VADER 对谷歌表单的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-on-google-sheets-with-vader-using-python-and-google-cloud-functions-e767985ed27d

用于情感分析的云函数配方

jkozoski 在 Unsplash 上拍摄的照片

TLDR

我们将讨论如何建立一个基本的工作流程来对谷歌表单中的文本进行简单的情感分析。具体来说,我们将:

  1. 使用 Python 和 Google Sheets API 读取电子表格中的评论数据
  2. 应用 VADER (休顿&吉尔伯特,2014),一个来自 nltk 包的开源情感分析器来执行情感分析
  3. 将结果写入谷歌电子表格的另一个标签
  4. 奖励:将 Python 代码部署到谷歌云功能上,这样你就可以直接从谷歌表单上在线运行你的 Python 代码,而不是在你的本地机器上。

这个循序渐进的指南使用非常基本的例子来帮助那些刚开始使用 Python 和情感分析的人。我对我的 Python 代码做了大量的注释,希望能让它更容易理解。

语境

已经有很多很棒的教程解释了如何使用 Python 进行情感分析,但没有多少详细介绍了如何将情感分析代码推送到 Google Cloud 函数。许多设置云功能的教程都非常普通,使用“hello world!”股票示例。对于想要学习的初学者来说,Google Cloud 文档也可能令人困惑。

考虑到上述情况,本文很少进行深入的情感分析(我们将查看极性得分和复合得分,但跳过符号化、可视化结果等),而是更侧重于如何设置这一切。

目标是帮助你在 Google Cloud 上部署你的第一个情绪分析模型。

💪让我们开始吧!

客户评论和用户反馈——在处理社交媒体数据或用户体验研究中,经常会遇到这类开放式的定性文本数据。从中可以得出许多真知灼见,例如,一个品牌是受欢迎还是不受欢迎,用户是否会再次使用该产品,以及为什么有人会推荐或不推荐某样东西。

当我们阅读所使用的单词时,我们可以判断他们的情绪是积极的、中立的还是消极的。但是想象一下,必须手动阅读和分析数百条用户评论——对于一个人来说,这将是一个非常耗时的过程😪!

什么是情感分析

简单来说:情感分析是一种自然语言处理方法,用来判断语料数据是正面的、负面的还是中性的。这有时被称为“观点挖掘”。用于评论或意见的大型数据集可以非常快速地进行分析和分类,这可以极大地帮助节省时间并产生更多见解。

💡想象一下,你收到了数千条关于某个特定产品的顾客评论。情感分析可以帮助将这些评论分为正面、中性和负面,并提取正面和负面评论中使用的常用词,从而显示用户喜欢的功能和用户认为产品缺少的功能。这种类型的信息是非常宝贵的,尤其是当我们考虑到它来自产品的实际用户时。

情感分析的局限性

近年来,自然语言处理领域取得了许多进展。一些例子包括:

  • BERT ,由谷歌开发的双向模型,可以通过从单词的左侧或右侧考虑上下文来帮助它更好地理解句子之间的关系。
  • 微软与英伟达一起开发了 MT-NLG 模型,提高了阅读理解、常识推理和自然语言推理能力。
  • 最近,为了确保语言不会成为元宇宙及其他地区的障碍,Meta AI 正在开发创新,如 NLLB-200 模型,能够翻译 200 多种不同的语言,包括罕见的语言。它还可以立即将非英语文本翻译成另一种非英语语言,而不必先将源文本翻译成英语,与以英语为中心的模型相比,这提高了翻译的准确性。

然而,如果最终目标是让机器能够以人类可以理解的方式理解人类语言,那么还有很长一段路要走🤖!

例如,有时我们说的话并不是我们真正想说的🤔。此外,像挖苦、讽刺和跨文化引用这样的非平凡例子是 NLP 建模的细微差别(老实说,甚至是人类!)还在纠结。

简而言之:情感分析还不是 100%完美的。

练习:使用 VADER 和谷歌云函数为谷歌表单构建一个基本的 Python 情感分析工作流

幸运的是,我们的练习相当基础,不需要万亿参数语言模型😲!

我们在谷歌表单中收到了上百行客户反馈,需要我们进行分析。反馈与特定产品相关,我们需要大致确定评论是正面的、中性的还是负面的。

R 和 Python 中的 NLP 包

根据所选择的编程语言,有许多 NLP 包可供使用。有些 R 的套装包括R sentence、 syuzhet 或sentence R。在 Python 中,通过 nltk 包的 TextBlob 和 VADER (休顿& Gilbert,2014)是可用的。nltk 代表自然语言工具包。

在这个 Python 练习中,我们将学习使用 VADER 创建一个简单的例子。

但是,VADER 是什么?

不,不是星球大战的反派。VADER 代表价感知词典和情感推理机——一个开源的、词汇的、基于规则的情感分析模型。由 C. J .休顿& E. E. Gilbert (2014)开发,它是一种相对快速的无监督方法,能够分析未标记的文本语料库,并且不需要模型训练。

它的许多功能包括正确处理带有否定、变价、标点符号甚至一些城市俚语和表情符号的文本🤯🔥🔥!

你可以通过 Github 官方回购了解更多信息。

先决条件

在继续下一步之前,您需要确保完成以下先决条件:

👉 #1 您已经 注册了 谷歌云。

谷歌云平台(GCP)有一个免费层。只要您将资源保持在最低水平,并且不超过概述的阈值,您应该没问题。谷歌还为新注册用户提供 300 美元的信用额度——但这个基本练习真的不需要。

👉 #2 您已经在 Google Cloud 中创建了一个项目。

您需要确保您已经在项目中启用了计费,否则您将无法继续。只要您保持在免费等级的阈值范围内,就不应该向您收费。您可以随时在项目仪表板中关注您的账单,并在不再需要时关闭资源(或项目本身):

截图:作者自己的

👉您已经启用了所需的 API

  • 谷歌工作表 API
  • 秘密管理器 API
  • 云函数 API

如果您还没有这样做,那么在运行云功能时,系统会提示您启用以下 API:

  • 云运行管理 API
  • 云日志 API
  • 云构建 API
  • 云发布/订阅 API
  • 工件注册 API

要在您的 GCP 项目中启用这些 API,请使用搜索栏或前往 GCP 左侧的导航菜单,进入 API 和服务>库:

截图:作者自己的

然后搜索 API 并启用它们:

截图:作者自己的

👉 #3 您已经创建了一个服务帐户。

使用这些 API 时,我们需要凭证来进行身份验证。为此,在 GCP 的左侧导航菜单中,选择 API 和服务>凭据:

截图:作者自己的

选择顶部的“创建凭据”,然后选择服务帐户:

截图:作者自己的

为您的服务帐户命名。这将自动用于填充 ID 并生成一个iam.gserviceaccount.com电子邮件地址。

⚠️ 记下这个电子邮件地址,因为你以后会用到它!

你现在可以跳过下面截图中的第 2 步和第 3 步:

截图:作者自己的

一旦完成,这应该会带你回到主屏幕。找到您刚刚创建的服务帐户,并单击其末尾的铅笔编辑图标:

截图:作者自己的

在下一个屏幕上,单击“Keys”,然后单击“Add Key”,从下拉菜单中选择“Create a New Key”,然后从弹出菜单中选择“JSON”并将其保存在桌面上的某个位置:

截图:作者自己的

👉 #4 您已经将密钥保存在 Secret Manager 中。

在使用 API 时,我们将使用 Google 的 Secret Manager 来安全地存储和访问凭证,而不是在不安全的代码中直接引用您的密钥。
在顶部搜索栏中搜索“秘密经理”,然后点击秘密经理:

截图:作者自己的

然后选择“创建密码”:

截图:作者自己的

给你的秘密取个名字,从你的桌面上传你之前创建的 JSON 文件,然后选择“创建秘密”:

截图:作者自己的

完成后,在这个屏幕上,勾选你刚刚创建的秘密,然后点击“添加原则”。使用之前创建服务帐户时生成的iam.gserviceaccount.com电子邮件地址,并确保其角色设置为“Secret Manager Secret Accessor”:

截图:作者自己的

👉 #5 您已经将服务帐户电子邮件地址添加到您的 Google 表单中。

进入包含您想要分析的数据的 Google 工作表,并将此电子邮件地址作为编辑器分配给该工作表。您可以取消选中“通知”框,然后点按“共享”。

截图:作者自己的

apis 已启用。

✅凭据已创建。

🚀您已经为下一步做好了准备!

步骤 1:使用 Python 和 Google Sheets API 从 Google Sheets 中检索数据

假设您收到了来自 100 个客户的反馈,数据存储在一个包含 3 列的 Google 工作表中:产品 ID、客户反馈和客户 ID,如下所示:

截图:作者自己的

Python 和 VS 代码

👨‍💻我们将假设您首先在本地工作,我们使用的是 Python 3。当用 R 编写代码时,我专门使用 RStudio (现在是 Posit ),但是因为这是一个 Python 练习,所以当用 Python 安装软件包和编程时,我使用 VS Code 作为我的首选 IDE。

以下步骤假设您使用 VS 代码。

安装云代码扩展

如果我们在本地机器上工作,并且在使用 Google Cloud APIs 时处理认证,我们将需要在 VS 代码中安装官方的 Cloud 代码扩展。此处的说明为。

截图:作者自己的

⚠️ 注意:确保你之后从 VS 代码登录谷歌云!

您可以在屏幕底部看到您是否登录。如果您尚未登录,请单击此处登录:

截图:作者自己的

安装包

Google API 客户端包含了我们将在 Python 中使用的所有相关的基于发现的 API。安装软件包:

pip3 install google-api-python-client

我们还需要 google.auth 包:

pip3 install google-auth

如前所述,我们将使用Google Cloud Secret Manager来保护我们的凭证安全,所以让我们也安装它:

pip3 install google-cloud-secret-manager

我们将使用 gspread 包使使用 Google Sheets 变得更加容易:

pip3 install gspread

当然还有 gspread_dataframe :

pip3 install gspread-dataframe

🐍现在让我们使用 Python 并导入我们刚刚安装的包,调用 Google Sheets API,从电子表格中获取我们的反馈数据并将其保存为 dataframe👇

导入包

##########################
# Load packages
##########################*# Google Credentials* from googleapiclient.discovery import build
from google.oauth2 import service_account
import google.auth
from google.cloud import secretmanager*# Python API for Google Sheets* import gspread
from gspread_dataframe import set_with_dataframe

我们还将导入 NumPy 、 pandas 、 copy 和JSON——这些不需要像其他一样安装,因为它们在 Python 中是标准的:

*# Standard Python packages* import pandas as pd
import numpy as np*# to create deep copy* import copy*# for JSON encoding or decoding* import json

重要变量

准备好以下变量的值。我们需要他们马上调用 GSheets API:

👉电子表格 _ID

👉获取范围名称

👉项目编号

👉秘密 _gsheet

👉秘密 _ 版本 _ 页面

电子表格 _ID

这是指 Google Sheet URL 末尾的字母数字字符串,如下图所示:

图片:作者自己的

获取范围名称

这是一个字符串值,表示电子表格中数据所在的区域。根据下面的截图,如果您的数据在 Sheet 1 中,那么您的范围名称将是: Sheet1!A1:C

截图:作者自己的

项目 _ 编号

这是一个字符串,表示为您在 Google Cloud 中创建的项目分配的编号。您可以通过访问 Google Cloud 仪表板并选择您的项目来找到它:

截图:作者自己的

secret_gsheet

这是一个字符串,表示您为 Secret Manager 中的 gsheet 练习指定的名称:

截图:作者自己的

secret_version_gsheet

这是一个字符串,表示您的密码的版本号。您可以通过在秘密管理器中点击您的秘密来找到它:

截图:作者自己的

📞调用 Google Sheet API

让我们从 Google Sheets 中获取数据并保存在一个数据框架中。

⚠️注意:在运行之前,你必须先通过 VS 代码登录谷歌云。记住还要更新上面讨论的变量的值。

注意事项:

✏️ 第 20 行:当我们给SERVICE_ACCOUNT_FILE分配秘密的时候,我们用了json.loads()。由于我们没有引用实际的 JSON 文件(因为我们现在使用 Secret Manager),我们需要使用json.loads()secret_gsheet_value从 JSON 字符串转换成 Python 字典。

✏️ 第 24 行:同样,由于我们不再直接处理 JSON 文件,我们使用了service_account.Credentials.from_service_account_**info**()而不是service_account.Credentials.from_service_account_**file**()

第二步:开始情感分析

现在,让我们开始对反馈数据进行基本的情感分析。

安装情感分析包

我们将试用 Python nltk 包中的 VADER(休顿&吉尔伯特,2014)。安装它:

pip3 install nltk

导入情感分析包

导入我们刚刚安装的包。在本练习中,我们不做标记化,因此下面的内容就足够了:

import nltk
from nltk.corpus import stopwords
from nltk.sentiment.vader import SentimentIntensityAnalyzer

运行情绪分析

现在,让我们开始对反馈数据进行基本的情感分析。

注意事项:

✏️ **第 8–13 行:**为了进行更准确的分析,需要从反馈语料库中删除停用词,以便在分析过程中不考虑不重要的词。英语中常见的停用词是像“the”、“and”、“is”这样的词。

✏️ 第 25 行 : VADER 根据它所分析的文本输出负极、中性和正极的极性分数。

✏️ 第 32 行:维达也从极性得分中输出复合得分。这实际上是将消极、中立和积极的分数相加,然后标准化为一个等级,其中+1 表示高度积极,而-1 表示高度消极。

✏️ Line 40 :复合分数可以帮助我们标注一条反馈是正面的、中立的还是负面的。通过在复合分数上创建一个基本逻辑,我们可以返回更容易理解的值(即“正”,而不是“0.89”)。

您可以定制这种逻辑,如果您愿意,可以有更多的标签(例如,有 5 个标签,而不是 3 个:“非常积极”、“积极”、“中性”、“消极”、“非常消极”)。

步骤 3:将结果写入电子表格

现在我们已经有了分析结果,让我们在同一个电子表格中的一个新选项卡上写东西。我们将数据保存到 Sheet2,如下所示:

截图:作者自己的

这就是我们使用gspreadgspread_dataframe的方法👇

注意事项:

✏️️ **第 7 行&第 10 行:**我们引用了之前第一次调用 Google Sheets API 时已经引用过的CREDSSPREADSHEET_ID变量。

✏️ 第 13 行:我们指定数据应该写到哪里。例如,如果你想把它写到一个名为“Sheet2”的标签中,那么它将被保存在 Google sheet 中的这个位置。

⚠️If 当你在实际的工作表中改变标签的名字时,记得更新你的代码中的值,否则你的代码将无法工作。

好处:部署到谷歌云功能

👏到目前为止,我们做得很好!但不幸的是,这段代码目前仍在您的本地机器上💻—这意味着它只能从您的计算机上运行。

通过将我们的代码部署到 Google Cloud Functions 的云☁️上,我们将能够在任何地方运行代码。在这一节中,我将概述如何将这些代码直接添加到 Google Cloud 接口中。

仅供参考:直接从您的 IDE 部署是可能的,但这超出了本文的范围(本文已经够长了!)

配置云功能

在 Google Cloud dashboard 的搜索栏中为您的项目搜索云功能:

截图:作者自己的

点击屏幕上的“创建功能”,您将进入以下页面:

截图:作者自己的

  • 环境:暂时把它作为第一代。
  • 函数名:给你的函数起个名字。这里的例子叫做my-sentiment-function
  • 区域:选择一个最近的区域。
  • 触发器类型:我们正在创建一个基本的 HTTP 触发器。勾选“要求 HTTPS”框,您可以暂时将身份验证设置为“未验证”,仅用于本练习。

点击“保存”。

截图:作者自己的

  • 分配的内存:该示例使用 512mb,但是如果您愿意,您可以更改它
  • 超时:设定为 300 秒,但您也可以更改
  • 运行时服务帐户:从下拉菜单中选择您之前创建的服务帐户
  • 最大实例数:暂时设为 1。

现在,您可以跳过其他选项卡,单击“下一步”进入以下屏幕:

截图:作者自己的

这里有几个要点需要回顾。

运行时

我们使用的是最新的 Python 3,所以选择 Python 3.10。

main.py

云函数要求代码在一个名为main.py
的文件中,如果你正在上传代码,这对于确保你的文件名称为main.py是至关重要的。但是因为我们在界面中使用内嵌编辑器直接更新我们的代码(在截图中圈出),所以这对于这个练习来说不是问题。

对于 Python,云函数使用 Flask 框架。所以我们希望main.py中的代码是这样的:

我们需要命名我们的函数。在上面的例子中,我们称之为my_function

函数中的请求参数应该返回可以转换成 Flask 响应的内容。这个响应可以是一个简单的字符串,甚至是一个 JSON 字符串。在上面的例子中,我们简单地返回了字符串“耶!搞定!”

关于最佳实践

从技术上讲,你可以在一个函数中做任何事情,只要它返回一个合适的响应。然而,作为最佳实践,我们应该努力确保一个函数只做一件事,如上面的例子所示。这更干净,有助于降低代码的复杂性。如果我们要正确地完成这项工作,我们之前编写的代码将需要重构,并分解成更小的、正确定义的单个函数。

但这并不意味着在一个功能中做多件事会让你的云功能完全无用。这只是意味着您的代码变得难以维护和调试。

⚠️知道,你的功能越长越复杂,谷歌云执行的时间就越长。

为了让这篇已经很长的帖子保持简短,并希望这个示例是一个基本的快速原型,我们之前编写的代码可以通过以下方式针对云函数进行更新:

注意事项:

✏️ 线 5 :所有要装载的包装都已经移动到顶部

✏️ 第 22 行:剩下的代码在我们命名为my_sentiment_function的定义函数中。

✏️ 第 149 行:如果这执行得很好,我们将得到响应“耶!搞定!”在我们的浏览器中。

上面的代码应该放入main.py的行内编辑器中。不要忘记指定云函数的开始作为入口点。我们的函数叫做my_sentiment_function,所以它被用作入口点:

截图:作者自己的

requirements.txt

我们需要在 requirements.txt 中指定需要安装的包。我们只需要以下内容:

截图:作者自己的

请注意,我们没有在这里添加Flaskcopyjson。这是因为它们在环境中已经存在。

⚠️:不管怎样,如果你把这些添加到 requirements.txt 中,云功能将无法部署,即使其他一切都安装正确。

google-api-python-client已经包含了像googleapiclient.discovery这样的 google discovery APIs,所以没有必要再将后者添加到 requirements.txt 中。

现在部署!

截图:作者自己的

几分钟后,如果您完成了上述所有操作,您应该会看到绿色的 tick✅,表明您的功能已经成功部署🙌🥳!

截图:作者自己的

测试

让我们快速测试一下这是否真的有效!

  1. 点击你的功能,然后进入名为“触发”的标签。此功能是通过 HTTP 触发的,因此谷歌云功能已经为您分配了一个 URL。
  2. 点击 URL 触发您的功能:

截图:作者自己的

3.应该会打开一个新的浏览器选项卡。

结果:

❌If:如果失败,你会得到一个错误信息,你可以查看“日志”标签,检查错误,看看为什么失败。这些错误已经被很好的描述了,所以你应该能够理解。

✅如果成功了,你会得到你的“耶!搞定!”浏览器中的成功消息:

截图:作者自己的

为了全面测试这一点,请记住,我们已经配置了代码,从 Sheet1 读取数据,然后将情感分析结果写入 Sheet2。

  1. 所以继续删除 Sheet2 中的所有内容。
  2. 复制云功能给你的网址,再次输入浏览器。再次触发该函数应该会更新 Sheet2!

因此,如果您在 Sheet1 中添加新的客户反馈或更改它们,只需点击您的云函数 URL,就会将情感分析的结果输出到 Sheet2 中!

作为 JSON 返回

如果你不想回“耶!搞定!”,并希望该函数返回我们之前以 JSON 形式创建的情感数据帧,请将 return 语句替换为:

*from flask import Response**return Response(sentiment_df.to_json(orient="records"), mimetype='application/json')*

结束了

这就是如何通过 Google Cloud 函数实时部署基本 Python 情绪分析代码的快速示例的结尾。谢谢你读到这里🤗!

现在您已经了解了所有这些是如何工作的,您可能想进一步了解:

  • 执行更深入的情感分析——首先尝试一些句子和单词的标记化。
  • 看看改进代码,让它更干净。
  • 注意云安全——我们已经避免在代码中硬编码我们的凭证,并使用了 Google Secret Manager 的基本方法。但是您可以研究进一步的改进,比如限制权限、将密钥限制在特定的 API 上、只允许经过身份验证的访问、在您完成实验后删除未经身份验证的函数等等。
  • 关注你的云资源:这个练习不应该让你超越你的免费层,但是如果你正在分析大量的情感数据,那么你将需要关注你的资源。关闭不使用的资源,删除不再需要的示例项目,等等。

⚠️完成后别忘了删除这个云功能!

完整的 Python 代码

👉从我的 Github repo 这里获取完整的 Python 代码。

参考资料和进一步阅读

休顿,C.J .和吉尔伯特,2014 年。VADER:基于规则的社交媒体文本情感分析的简约模型。载于:《网络与社交媒体国际 AAAI 会议论文集》,8 (1),第 216–225 页。

nltk 是一个开放源码的 Python 工具包,受 Apache 2.0 许可。

VADER 在麻省理工学院的许可下是开源的。

新闻标题的情感分析:经典监督学习与深度学习方法

原文:https://towardsdatascience.com/sentiment-analysis-on-news-headlines-classic-supervised-learning-vs-deep-learning-approach-831ac698e276

使用经典机器学习和深度学习技术开发二元分类器以检测正面和负面新闻标题的解释性指南

图片取自 Unsplash

介绍

本文将使您能够构建一个二元分类器,使用两种不同的方法对未标记的数据执行情感分析:

1-通过 scikit-learn 库和 nlp 包进行监督学习

2-使用 TensorFlow 和 Keras 框架的深度学习

然而,挑战在于我们正在处理未标记的数据,因此我们将利用一种 弱监督技术通气管 为我们的训练数据点创建标记 0(负)或 1(正)。

项目的视觉计划如下图所示:

项目概述

该项目中使用的数据集被称为“百万新闻标题”数据集,可在 Kaggle 上获得。我也将使用谷歌 Colab,随时设置您的笔记本,复制和运行自己的代码。

#install needed packages
!pip install snorkel
!pip install textblob
#import libraries and modules
from google.colab import files
import io
import pandas as pd
#Snorkel
from snorkel.labeling import LabelingFunction
import re
from snorkel.preprocess import preprocessor
from textblob import TextBlob
from snorkel.labeling import PandasLFApplier
from snorkel.labeling.model import LabelModel
from snorkel.labeling import LFAnalysis
from snorkel.labeling import filter_unlabeled_dataframe
from snorkel.labeling import labeling_function
#NLP packages
import spacy
from nltk.corpus import stopwords
import string
import nltk
import nltk.tokenize
punc = string.punctuation
nltk.download('stopwords')
stop_words = set(stopwords.words('english'))
#Supervised learning
from tqdm import tqdm_notebook as tqdm
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
##Deep learning libraries and APIs
import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

1.加载数据

#uplaod the data from your local directory
uploaded = files.upload()# store the dataset as a Pandas Dataframe
df = pd.read_csv(io.BytesIO(uploaded['data.csv']))#conduct some data cleaning
df = df.drop(['publish_date', 'Unnamed: 2'], axis=1)
df = df.rename(columns = {'headline_text': 'text'})
df['text'] = df['text'].astype(str)#check the data info
df.info()

在这里,我们可以检查我们的数据集有 63821 个实例。

数据集信息

2.创建标签:浮潜技术

因为数据集是无标签的,所以我们将使用 sluck,使用分配两类标签的函数来提出启发式和编程规则,这两类标签区分标题是正面的(1)还是负面的(0)。有关通气管标签的更多详情,请访问此链接。

下面,您可以找到生成的标签函数。第一个函数查看标题中的输入单词,第二个函数根据正面和负面列表中的预定义单词分配适当的标签。例如,如果“有前途”一词出现在标题中,那么它将被分配一个积极的标签,而“咄咄逼人”一词则导致一个消极的标签。

#define constants to represent the class labels :positive, negative, and abstain
POSITIVE = 1
NEGATIVE = 0
ABSTAIN = -1
#define function which looks into the input words to represent a proper label
def keyword_lookup(x, keywords, label):  if any(word in x.text.lower() for word in keywords):return labelreturn ABSTAIN
#define function which assigns a correct label
def make_keyword_lf(keywords, label=POSITIVE):return LabelingFunction(name=f"keyword_{keywords[0]}",f=keyword_lookup,resources=dict(keywords=keywords, label=label))
#resource: [https://www.snorkel.org/use-cases/01-spam-tutorial#3-writing-more-labeling-functions](https://www.snorkel.org/use-cases/01-spam-tutorial#3-writing-more-labeling-functions)#these two lists can be further extended 
"""positive news might contain the following words' """
keyword_positive = make_keyword_lf(keywords=['boosts', 'great', 'develops', 'promising', 'ambitious', 'delighted', 'record', 'win', 'breakthrough', 'recover', 'achievement', 'peace', 'party', 'hope', 'flourish', 'respect', 'partnership', 'champion', 'positive', 'happy', 'bright', 'confident', 'encouraged', 'perfect', 'complete', 'assured' ])"""negative news might contain the following words"""
keyword_negative = make_keyword_lf(keywords=['war','solidiers', 'turmoil', 'injur','trouble', 'aggressive', 'killed', 'coup', 'evasion', 'strike', 'troops', 'dismisses', 'attacks', 'defeat', 'damage', 'dishonest', 'dead', 'fear', 'foul', 'fails', 'hostile', 'cuts', 'accusations', 'victims',  'death', 'unrest', 'fraud', 'dispute', 'destruction', 'battle', 'unhappy', 'bad', 'alarming', 'angry', 'anxious', 'dirty', 'pain', 'poison', 'unfair', 'unhealthy'], label=NEGATIVE)

另一组标记功能通过 TextBlob 工具实现,这是一个预训练的情感分析器。我们将创建一个预处理程序,在我们的标题上运行 TextBlob,然后提取极性和主观性得分。

#set up a preprocessor function to determine polarity & subjectivity using textlob pretrained classifier 
[@preprocessor](http://twitter.com/preprocessor)(memoize=True)
def textblob_sentiment(x):scores = TextBlob(x.text)x.polarity = scores.sentiment.polarityx.subjectivity = scores.sentiment.subjectivityreturn x#find polarity
[@labeling_function](http://twitter.com/labeling_function)(pre=[textblob_sentiment])
def textblob_polarity(x):return POSITIVE if x.polarity > 0.6 else ABSTAIN#find subjectivity 
[@labeling_function](http://twitter.com/labeling_function)(pre=[textblob_sentiment])
def textblob_subjectivity(x):return POSITIVE if x.subjectivity >= 0.5 else ABSTAIN

下一步是组合所有的标记函数,并将其应用于我们的数据集。然后,我们拟合 label_model 来预测和生成正类和负类。

#combine all the labeling functions 
lfs = [keyword_positive, keyword_negative, textblob_polarity, textblob_subjectivity ]#apply the lfs on the dataframe
applier = PandasLFApplier(lfs=lfs)
L_snorkel = applier.apply(df=df)#apply the label model
label_model = LabelModel(cardinality=2, verbose=True)
#fit on the data
label_model.fit(L_snorkel)
#predict and create the labels
df["label"] = label_model.predict(L=L_snorkel)

我们可以注意到,在去掉未标记的数据点之后(如下所示),我们有大约 12300 个正面标签和 6900 个负面标签,这将足以构建我们的情感分类器。

#Filtering out unlabeled data points
df= df.loc[df.label.isin([0,1]), :]#find the label counts 
df['label'].value_counts()

正负标签

3.应用监督学习方法:逻辑回归

我们将用来构建情感分类器的第一种方法是经典的监督方法,即逻辑回归,它被认为是一种强大的二元分类器,可以估计某个实例属于某个类别的概率,并相应地做出预测。但是,在训练模型之前,我们应该首先预处理数据并创建矢量表示。

3.1 文本预处理

预处理是自然语言处理中为训练准备文本数据的基本任务。它将原始文本的输入转换成作为单个单词或字符的净化标记。主要的预处理方法总结如下:

1- 标记化:将单词拆分成标记

2- 词汇化:将单词分解成它们的根格式

3- **去掉停用词:**去掉不必要的词,如 the、he、she 等。

4- 去掉标点符号:去掉不重要的单词元素,如逗号、句号、括号、圆括号等。

#make a copy of the dataframe
data = df.copy()#define a function which handles the text preprocessing 
def preparation_text_data(data):"""This pipeline prepares the text data, conducting the following steps:1) Tokenization2) Lemmatization4) Removal of stopwords5) Removal of punctuation"""# initialize spacy objectnlp = spacy.load('en_core_web_sm')# select raw textraw_text = data.text.values.tolist()# tokenizetokenized_text = [[nlp(i.lower().strip())] for i in tqdm(raw_text)]#define the punctuations and stop wordspunc = string.punctuation stop_words = set(stopwords.words('english'))#lemmatize, remove stopwords and punctuationdcorpus = []for doc in tqdm(tokenized_text):corpus.append([word.lemma_ for word in doc[0] if (word.lemma_ not in stop_words and word.lemma_ not in punc)])# add prepared data to dfdata["text"] = corpusreturn data#apply the data preprocessing function
data =  preparation_text_data(data)

我们可以在下图中注意到,数据已经被适当地清理,显示为单独的标记,每个标记都位于其原始词根,没有停用词和标点符号。

文本准备结果

3.2 文本表示

第二步包括将文本数据转换成 ML 模型可以理解的有意义的向量。我应用了 TF-IDF(术语频率(TF) —逆密集频率(IDF)) ,它基于整个语料库中的单词出现次数为输入数据创建计数权重。

def text_representation(data):tfidf_vect = TfidfVectorizer()data['text'] = data['text'].apply(lambda text: " ".join(set(text)))X_tfidf = tfidf_vect.fit_transform(data['text'])print(X_tfidf.shape)print(tfidf_vect.get_feature_names())X_tfidf = pd.DataFrame(X_tfidf.toarray())return X_tfidf#apply the TFIDV function
X_tfidf = text_representation(data)

下面,我们可以找到 text_representation 函数的结果,由此我们可以看到单词已经被转换为有意义的向量。

文本表示 TFIDV 结果

3.3 模型培训

在这个阶段,我们准备建立和训练 ML 逻辑回归模型。我们将数据集分为训练和测试,我们拟合模型并根据数据点进行预测。我们可以发现该模型的准确率为 92%。

X= X_tfidf
y = data['label']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)#fit Log Regression Model
clf= LogisticRegression()
clf.fit(X_train,y_train)
clf.score(X_test,y_test)
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred))

Logistic 回归分类报告

3.4 预测新实例

我们可以预测如下所示的新实例,我们用新标题填充模型,我们预测标签在我们的示例中是负面的,因为我们传达的是战争和制裁。

new_data = ["The US imposes sanctions on Rassia because of the Ukranian war"]
tf = TfidfVectorizer()
tfdf = tf.fit_transform(data['text'])
vect = pd.DataFrame(tf.transform(new_data).toarray())
new_data = pd.DataFrame(vect)
logistic_prediction = clf.predict(new_data)
print(logistic_prediction)

方法一:对新实例的预测

4.深度学习方法:张量流和 Keras

神经网络是一种深度学习算法,由多层互连的神经元组成,由激活函数提供动力。它考虑每个输入的加权和,然后对该和应用阶跃函数,并输出显示实例类的结果。

事实上,就深度学习而言, Keras 和 TensorFlow 是最受欢迎的框架之一。具体来说,Keras 是一个运行在 TensorFlow 之上的高级神经网络库,而 TensorFlow 是一个用于机器学习的端到端开源平台,由工具、库和其他资源组成,为工作流提供高级 API。

在我们的项目中,我们将利用 TensorFlow 来预处理数据,并使用标记器类填充数据,我们将使用 Keras 来加载和训练顺序模型(神经网络),它适用于各层的简单堆叠,其中每层都有一个输入张量和一个输出张量。要了解更多关于顺序模型的信息,请访问此链接。

4.1 训练和测试分割

##store headlines and labels in respective lists
text = list(data['text'])
labels = list(data['label'])##sentences
training_text = text[0:15000]
testing_text = text[15000:]##labels
training_labels = labels[0:15000]
testing_labels = labels[15000:]

4.2 从张量设置记号化器,对数据进行预处理。

在这一步中,我们使用 tensorflow.keras 中的单词标记器,使用 texs_to_sequences 实例创建单词编码(具有键值对的字典)和序列 ,然后我们使用 pad_sequences 实例填充这些序列,使其长度相等。

#preprocess 
tokenizer = Tokenizer(num_words=10000, oov_token= "<OOV>")
tokenizer.fit_on_texts(training_text)word_index = tokenizer.word_indextraining_sequences = tokenizer.texts_to_sequences(training_text)
training_padded = pad_sequences(training_sequences, maxlen=120, padding='post', truncating='post')testing_sequences = tokenizer.texts_to_sequences(testing_text)
testing_padded = pad_sequences(testing_sequences, maxlen=120, padding='post', truncating='post')# convert lists into numpy arrays to make it work with TensorFlow 
training_padded = np.array(training_padded)
training_labels = np.array(training_labels)
testing_padded = np.array(testing_padded)
testing_labels = np.array(testing_labels)

4.3 定义并训练顺序模型

我们使用 vocab 大小、嵌入维度和输入长度的嵌入层来构建模型。我们还添加了一个密集层 RelU ,它要求模型将实例分为正面或负面两类,以及另一个最终的 sigmoid 层,它输出 0 或 1 之间的概率。您可以简单地使用每一层中的超参数来提高模型性能。然后,我们用优化器和度量性能编译该模型,并在我们的数据集上训练它。

model = tf.keras.Sequential([tf.keras.layers.Embedding(10000, 16, input_length=120),tf.keras.layers.GlobalAveragePooling1D(),tf.keras.layers.Dense(24, activation='relu'),tf.keras.layers.Dense(1, activation='sigmoid')
])##compile the model
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])model.summary()

我们可以在下图中看到,我们有 4 层,max_length 为 120,密集层节点为 16 和 24,以及 160,433 个可训练参数。

顺序模型总结

num_epochs = 10
history = model.fit(training_padded, training_labels, epochs=num_epochs, validation_data=(testing_padded, testing_labels), verbose=2)

我们可以进一步检查我们建立的具有 10 个运行时期的神经网络模型具有 99%的非常好的准确性,减少验证损失并增加验证准确性,这确保了强大的预测性能和泛化(过拟合)错误的低风险。

神经网络训练结果

4.4 预测新实例

现在,我们将使用这个特定的模型来预测同一个标题。同样,输出接近于零,这也表明这个标题是负面的。

**new_headline = ["The US imposes sanctions on Rassia because of the Ukranian war"]##prepare the sequences of the sentences in question
sequences = tokenizer.texts_to_sequences(new_headline)
padded_seqs = pad_sequences(sequences, maxlen=120, padding='post', truncating='post')print(model.predict(padded_seqs))**

方法二:对新实例的预测

5.结论

在本文中,我们建立了一个二元分类器来检测新闻标题的情感。然而,我们首先使用了一些启发式规则,使用 sluck 方法来创建分类负面和正面标题的标签。我们使用监督 ML 和深度学习方法创建了情感预测。这两种方法都成功地预测了新给定实例上的正确标题,并且对于逻辑回归和深度神经网络,它们都分别具有合理的 92%和 96%的高准确度分数。

你可能会问自己,在我的下一个数据科学预测任务中,哪种方法更好或更容易使用;然而,答案完全取决于项目的范围和复杂性以及数据的可用性,有时我们可能会选择使用 scikit-learn 中众所周知的算法的简单解决方案,预测系统利用数学直觉为给定的输入分配所需的输出值。另一方面,深度学习试图模仿人脑的功能,从给定的输入中执行规则(作为输出)。我们应该记住,神经网络通常需要大量的数据和高计算能力来完成任务。

我希望你喜欢阅读这篇文章,并期待更多丰富的文章,这些文章串联了我关于数据科学和机器学习主题的知识。

参考

[1]100 万条新闻标题,18 年间发布的新闻标题,许可 CCO: Public Domain, Kaggle

TFX 管道的情感分析—本地部署

原文:https://towardsdatascience.com/sentiment-analysis-with-tfx-pipelines-local-deploy-e9daa4cbde2a

建立一个本地 TFX 管道,使用 Transformer 架构创建一个情感分析模型,并使用 TF 为该模型提供服务

西格蒙德在 Unsplash 上拍照

1。简介

在本文中,我们将介绍构建管道来部署情感分析模型的过程。

本文是两部分中的第一部分。在这一部分中,我们将讨论如何在本地运行我们的管道。在第二部分中,使用 Vertex 和 AI 平台的 TFX 管道的 CI/CD,我们将介绍如何使我们的模型在 Google 云平台 (GCP)上可用,以及如何开发我们的 CI/CD 管道。

完成本文后,您将能够:

  • 创建情感分析模型
  • 创建集成所有组件的管道
  • 通过 REST API 在本地服务您的模型
  • 分析您的管道元数据

整个应用程序的代码可以在这个 GitHub 存储库中找到。

2。TFX(张量流扩展)+ MLOps

为了建立我们的管道,我们将使用 TFX 。

根据 TFX 用户指南,“TFX 是一个基于 TensorFlow 的谷歌生产规模的机器学习(ML)平台。它提供了一个配置框架和共享库,以集成定义、启动和监控您的机器学习系统所需的通用组件。”

根据迪·fante⁵的说法,mlops 中有三个非常重要的概念:

  • 数据来源:你的数据来自哪里,它是如何产生的,提交了什么方法和过程。
  • 数据谱系:到达流水线末端之前的步骤顺序。
  • **元数据:**描述数据的数据。它们用来解释我们所观察的物体的特征。

这 3 个是生产模型中的关键部分,因为它们可以帮助你跟踪模型生命周期中发生的变化。生产模型有几个版本、文件和涉及的人员,所以使用能够轻松再现我们管道所处环境的框架是很重要的,比如 TFX。

3。管道

TFX 流水线是实现 ML 流水线的一系列组件,ML 流水线是专门为可扩展的高性能机器学习任务设计的。

图一。 TFX 管道。这张图片复制自谷歌创作和分享的作品,并根据知识共享 4.0 归属许可中描述的条款使用。来源:https://www.tensorflow.org/tfx/guide

每个组件负责 TFX 管道中的一项任务,很多时候,一个组件依赖于另一个组件的输出。TFX 有几个教程解释如何使用组件。

3.1 组件

在我们的例子中,我们选择不使用 InfraValidator 组件。然而,我们选择在管道中增加一个节点, Resolver 。Resolver 是一个特殊的 TFX 节点,它处理特殊工件的解析,在我们的例子中,它被用来指定 Evaluator 组件中的最后一个基本模型。

图二。 TFX 地方管道(图片由作者提供)。这张图片是从谷歌创作和分享的作品中复制的,并根据知识共享 4.0 归属许可中描述的条款使用。来源:https://www.tensorflow.org/tfx/guide

run_pipeline.py 中,我们定义了 TFX 管道。所有组件和参数都将位于该文件中。

3.1.1 示例生成

它是管道的初始输入组件,处理并选择性地拆分输入数据集。使用外部来源的文件,如 CSV、TFRecord、Avro、Parquet 和 BigQuery。

统计数据生成

计算数据集统计数据。

3.1.3 方案

检查统计数据并创建数据模式。

示例验证器

在数据的训练和传递中查找异常和缺失值,例如检测数据偏差。

3.1.5 转换

对数据集执行要素工程。在这个组件中,我们执行模型变量的所有转换/创建。该组件的一个重要之处在于,它生成一个存储数据全局属性的图表,这些属性将用于训练和推理,从而提供可靠性。

3.1.6 调谐器

调整模型的超参数。调谐器可以在所有管道运行中运行,如果您只想不时地执行超参数调谐,也可以导入调谐器。

3.1.7 培训师

训练模型。在这个组件中,除了定义它的整个架构之外,我们还指定了它将在哪里以及如何被训练。

3.1.8 分解器

一个特殊的 TFX 节点,处理特殊工件的解析,在我们的例子中,它用于指定评估器组件中的最后一个基本模型。

3.1.9 评估员

对培训结果进行深入分析,并帮助验证导出的模型,确保它们足够好,可以投入生产。在这个组件中,可以指定度量验证阈值,如果没有达到限制,就阻止模型投入生产。

3.1.10 推杆

将模型部署到显示基础结构。这是我们指定模型将被服务的地方。

因此,我们的应用程序的结构是这样的:

│   run_local_pipe.ipynb
│
├───modules
│   │   label_encoder.pkl
│   │   model.py
│   │   preprocessing.py
│   │
│   ├───best_hyperparameters
│   │       best_hyperparameter.txt
│   │
│   └───data
│           data.csv
│
└───tfx-pipeline│   kubeflow_v2_runner.py│   local_runner.py│└───pipeline│   configs.py│   run_pipeline.py

tfx-pipeline 目录中,我们有引用编排器设置的文件。

  • local _ runner . py-定义本地运行管道的参数和变量
  • kubeflow _ v2 _ runner . py—定义参数和变量,使用 kube flow 作为编排器在本地/云运行管道

tfx-pipeline/pipeline中我们有引用管道设置的文件

  • configs.py —定义全局应用程序设置,如管道名称和文件路径
  • run _ pipeline . py—TFX 管道的定义,所有组件和参数的定义

模块 中我们有参考模型构造的文件。

  • label_encoder.pkl —来自 sci-kit 的 LabelEncoder 对象学习编码/解码目标变量
  • model.py —构建分类模型(训练器组件)
  • 预处理. py —变量的转换和预处理(转换组件)
  • best _ hyperparameter . txt-来自调谐器组件的文件,包含模型的超参数

最后,使用 run_local_pipe.ipynb ,除了分析生成的工件之外,我们还可以在本地创建和运行管道。

3.2 —模型建筑

我们的模型是对变压器架构的改编。这种架构的最大区别是引入了注意机制,它分析输入序列并提供序列每个部分重要性的上下文。因此,与递归神经网络(RNN)不同,这种架构允许数据并行化,减少了训练时间。

该模型是用 TensorFlow 构建的,目标是将句子分类为肯定、否定或中性,因此它是一个分类模型。

在管道构建过程中,有两个非常重要的组件:Transform 和 Trainer。在我们的架构中,这些组件分别由文件 preprocessing.pymodel.py 表示。让我们逐一解决这些问题,以理解变量的处理和模型的构建。

3.2.1 数据

我们的训练数据是葡萄牙语(PT-BR) 的新闻标题,分类为:正面、负面或中性,已经通过 LabelEncoder 以数字格式表示。

**图三。**训练数据(图片由作者提供)。

3.2.2 预处理

我们选择对输入数据执行一些转换。下面的函数说明了输入数据的变换。

重点是从输入字符串中删除重音符号、特殊字符、数字和停用词。

3.2.3 型号

我们不会深入所有数据加载/训练函数的细节,因为它们已经在 TFX 教程中广泛演示过了。

我只想讨论定义模型的两个要点:架构和签名。

建筑

**图 4。**模型建筑(图片由作者提供)。

由于我们的模型是对原始架构的改编,我们选择让它更简单。

我们的模型接受输入并将它们转换成嵌入,嵌入是句子的向量表示。之后,嵌入内容被传递到多头注意力层,多头注意力层将为句子中的每个单词创建向量,表示单词之间的重要性和上下文关系。归一化层用于帮助稳定梯度下降并帮助模型收敛。

最后,我们将输出传递给前馈网络(FFN),这是一个简单的层,有助于将注意力向量转换为块之间可消化的形式。我们添加了几个类似的层,直到我们定义了输出层,由 softmax 函数激活,它输出一个概率向量,涉及目标变量的 3 个类别。

这样,我们的模型构造如下:

签名

当使机器学习模型可用时,我们需要考虑我们的模型将如何接收数据进行预测。TensorFlow 模型具有 SavedModel 格式,它允许我们创建几个签名来定义我们的模型将如何接收数据并做出可用的预测。

因此,我们创建了一个签名,它接受字符串形式的输入,而不是最初的 TFX 示例,它期望数据为 tf.train.Example 格式。我们的签名的输出返回每个类的概率,具有最高概率的类,以及最高预测概率的值。

然后,我们定义模型的签名。在预测时,我们可以选择我们想要的签名,因此我们的模型可以接受几种数据格式。

4。本地部署

最后,我们可以运行我们的管道。 run_local_pipe.ipynb 笔记本是为我们创建、运行和分析我们的管道而制作的。

我们使用 TFX-cli 创建管道,将本地引擎和所需文件的路径作为参数传递,在这个文件中是 local_runner.py

最后,我们可以运行它。

现在,我们的所有组件都将运行,我们的模型可用于预测。

5。为模型提供 TensorFlow 服务

有几种方法可以为预测模型提供服务,其中一种是 TensorFlow 服务。

TensorFlow Serving 是一个灵活、高性能的机器学习模型服务系统,专为生产环境而设计。TensorFlow 服务可以轻松部署新的算法和实验,同时保持相同的服务器架构和 API。TensorFlow 服务提供了与 TensorFlow 模型的现成集成,但可以轻松扩展为服务于其他类型的模型和数据。⁴

首先,我们定义模型的位置,并下载 TF 服务包。

然后我们开始 TensorFlow 服务。这里我们定义一些重要的参数:

-rest _ API _ port:将用于 REST 请求的端口。

  • model_name :您将在 REST 请求的 URL 中使用这个。什么都有可能。

-model _ base _ path:这是你保存模型的目录路径。

5.1 提出休息请求

我们现在准备提出请求。我们加载我们的编码器来根据训练转换我们的目标变量,我们定义 url、我们的签名和我们想要预测的数据。然后,我们向我们的服务器发出一个 POST 预测请求,它会返回每个实例参与目标类的概率、预测的类以及最高预测概率的值。

6。评估管道工件

TFX 管道组件的输出被称为工件。这些工件注册在元数据存储库中,我们在设置中定义它。这些工件中的一些可以用图形可视化,它们为我们的数据提供了有价值的见解。

**我们可以通过我们的元数据存储库访问由我们的管道产生的工件。**我们还可以过滤特定类型的赝像,以可视化和定义这些赝像的输出路径。

从这些人工制品中,我们可以形象地展示它们。例如,让我们来看看统计结果。

然后,我们可以并排查看训练和验证数据统计。

图 5。 StatisticsGen(图片由作者提供)。

7。结论

开发本地管道是集成我们的应用程序并能够标准化我们模型的训练和推理的第一步。为了改进我们的管道,在本文的第 2 部分中,除了应用 CI/CD 实践之外,我们将在云环境中开发和部署它,使它可扩展并且更易于维护。

8。参考文献

[1]《TFX 用户指南》(2021 年 9 月 01 日),TensorFlow。

[2]瓦斯瓦尼,a;新泽西州沙泽尔、新泽西州帕尔马;Uszkoreit,j;琼斯湖;戈麦斯。凯泽湖;Polosukhin,I. 注意力是你所需要的全部。(2017 年 6 月 12 日),arXiv 预印本 arXiv:1706.03762。

[3]南丹,A. 文字分类用变压器(2020 年 5 月 10 日),Keras。

【4】TF 服役(2021 年 1 月 28 日),TensorFlow。

[5]迪凡特,A. L. 我如何部署我的第一个机器学习模型(2021 年 12 月 15 日),中。

[6] Amoateng,D. 文本分类管道 tfx local(2022 年 1 月 1 日),GitHub。

九月版:数据科学对业务的影响

原文:https://towardsdatascience.com/september-edition-data-science-for-business-impact-8b3088253ea1

月刊

如何帮助您的公司真正“了解数据”

在 Unsplash 上 Linh Pham 的照片

在过去十年中,数据科学作为一门学科可能已经成熟了很多,但许多公司仍在努力将他们的目标与数据从业者产生的见解保持一致。原因可能各不相同:传统企业可能不愿意尝试新方法;年轻的初创公司有时没有强大的基础设施来收集和组织自己的数据。

幸运的是,数据科学家和数据分析师有能力教育他们的同事做出数据支持决策的好处。然而,在他们做到这一点之前,他们自己需要知道如何连接正确的点,并有效地交流他们的知识。

这个月,我们选择了一些我们最喜欢的专门针对行业数据专业人士的近期文章。它们从高层次的策略到具体的执行,阅读它们可能会帮助你打破数据团队有时发现他们自己的花哨的算法筒仓。

祝阅读愉快,感谢您对我们作者工作的支持。

TDS 编辑

TDS 编辑亮点

  • 数据战略的什么、为什么、如何、谁、何时贵公司是否有充分利用数据运营的计划?Bahar Salehi 认为拥有一个数据中心是至关重要的,但他也认识到“将数据带入企业的核心和文化并不容易。”她的有益概述涵盖了蓬勃发展的数据文化的构建模块。(2022 年 7 月,5 分钟)
  • 想作为数据科学家被重视?问正确的问题数据科学家无法单枪匹马地让每一位利益相关者相信他们工作的重要性,但以富有成效的方式组织对话会大有帮助。对于 Genevieve Hayes 博士来说,这意味着要问很多“为什么?”与其他团队的同事交流时的问题。(2022 年 7 月 7 分钟)
  • 乔瓦尼·布鲁纳认为:“理清因果关系在商业中通常被忽视,而且很大程度上是一种很难理解的做法”——但这种不足可以成为知道如何准确解释因果关系的数据专业人员的机会。(2022 年 5 月 7 分钟)
  • A/B 测试的乐趣:理论、实践和陷阱数据科学在行业环境中最常见的应用之一是(到目前为止)无处不在的 A/B 测试。它的流行也产生了不少误解,但塞缪尔·弗莱德的深入研究将帮助数据从业者走上正确的道路。(2022 年 8 月 10 分钟)
  • 对 p 值的简单解读一个执行良好的 A/B 测试和一个明智的商业决策之间的差距充满了统计上的危险:如果你曲解了它们,你的结果不会有太大用处——甚至会伤害底线。 Dina Jankovic 解释了什么是 p 值,以及为什么它们对于从假设检验中得出正确的结论至关重要。(2021 年 11 月 7 分钟)
  • 营销组合建模 101Ariel Jiang对 MMM 的非技术性介绍既通俗易懂又透彻;对于想要了解更多关于他们对公司成功的潜在贡献的数据科学家来说,这是一个很好的资源。当你完成后,直接前往 Ariel 系列的第 2 部分,它进一步探索了数据科学和营销的交集。(2022 年 4 月 10 分钟)

原始特征

这里是我们过去一个月最好的原创特写和阅读推荐。

  • 做出好的决策:艺术,科学,还是两者兼而有之? 我们的 Q&A withCassie Kozyrkov,Google Cloud 的首席决策科学家,对数据职业道路、数据分析师的价值以及公共写作充满了真知灼见。
  • 数据技能在非数据科学的职业中可以大有作为 。我们与可持续发展和能源分析师喜玛拉雅·比尔·施雷斯塔聊了聊提高各种非数据科学职位的数据和编码技能的好处。
  • 数据可视化:超越图表 。厌倦了反复使用相同的情节?我们选择了一些我们最近最喜欢的高级和利基数据可视化方法。

热门帖子

找出您的数据科学同行在过去一个月中阅读和分享最多的文章,以下是八月份最受欢迎的一些帖子。

  • 面向数据科学家的五大 Python 编程书籍 作者 Benjamin Nweke

  • 了解 BLOOM,最大的开放访问 AI,并在你的本地计算机上运行它 作者克里斯蒂安·阿尔蒂加

  • 5 个鲜为人知的 Python 库,可以帮助你的下一个数据科学项目

  • 数据文档最佳实践 作者麦迪森肖特

  • 使用 Python 和 GPT 创建求职信生成器-3byAmber Teng

  • 让你成为下一级 Python 程序员的 3 个不被重视的技能 作者 Murtaza Ali

每个月,我们都很兴奋地欢迎新的和有才华的作者加入 TDS 社区,8 月也不例外——我们最近的一批人包括 Thu Dinh 、 Rohit Choudhary 、 Dustin Liu 、пашадубовикк、谢弗·德鲁、萨布里娜·格尔纳、普拉文·内勒 加勒特·金曼,尼姆罗德·伯曼,鲁惠胡,马特·比格斯,阿尔特姆·德门捷耶夫,谢尔盖·科特洛夫,凯尔·奥布莱恩,迈克·克莱顿,安德鲁·布什,苏瓦迪亚·慕克吉 迪内什·拉伊 MD 、卡洛琳·扎博罗夫斯基、安东·列别杰夫、大卫·斯威诺、摩根·格林、乔瓦尼·奥甘蒂尼、兹沃尼米尔·博班、凯特琳·雷等等。 如果你也想和我们分享你的作品,现在是一个冒险的好时机。

直到下个月!

seq rep——ML 工作流的简单框架

原文:https://towardsdatascience.com/seqrep-simple-framework-for-ml-workflow-2eec279b25b0

从标记数据到用几行代码评估模型

你有没有担心过构建正确的机器学习(ML)流水线
你是想专注于模型还是预处理部分,你不想费心把所有东西都放在一起
你想只使用几行代码来测试你的想法吗?

如果你对任何一个问题的回答是肯定的,或者你只是好奇,继续读下去!

Goran Ivos 在 Unsplash 上拍摄的照片

SeqRep 是什么?

SeqRep 是一个简单的 Python 库,用于简化 ML 任务的编码。它主要侧重于序列(时间序列)数据;但是,它也可以用于其他类型的数据。

在任何 ML 任务的开始,我们都有数据。最终,我们要得到一个模型的性能结果。在这两个阶段之间,有几个步骤。有时候我们需要做更多,有时候几步就够了。SeqRep 就是来缓解这种情况的。我们可以像玩具积木一样构建工作流。

PipelineEvaluator -主程序块

序列的基本类是PipelineEvaluator类。这是放置我们特殊积木的地方。通常,我们会插入一个Splitter,因为我们希望在不同于用于训练的数据上评估模型。然后我们添加一个模型。 SeqRep 指望模型有fitpredict方法。因此,您可以轻松使用任何型号的 Scikit 。最后,可以添加Evaluator对象来获得一些评估度量值。您可以使用一些预定义的指标,也可以实现自己的指标(例如,使用您想要的指标,比如精度和)。

代码可能如下。

pipe_eval = PipelineEvaluator(labeler = NextColorLabeler(),splitter = TrainTestSplitter(),model = SVC(),evaluator = ClassificationEvaluator(),)
result = pipe_eval.run(data=data)

添加其他块

让我们通过添加其他模块来构建更大更复杂的东西。

由米歇尔·bożek在 Unsplash 上拍摄的照片

标记

有时,我们有数据,但我们没有标签(我们将使用监督模型)。例如,它适用于任务是预测下一个值的时间序列数据(例如,温度预测或功耗预测)。这可以使用Labeler对象来解决。同样,您可以通过继承Labeler类或使用任何实现的。

那么当您分别拥有数据和标签时,情况会怎样呢?没问题,labeler不需要使用。您可以直接将数据和标签添加到主对象中。请参见下面的代码片段。

pipe_eval.data = X_data
pipe_eval.labels = labels

同样,如果您的数据已经分离,您就不必使用TrainTestSplitter

pipe_eval.X_train = X_train
pipe_eval.y_train = y_train
pipe_eval.X_test = X_test
pipe_eval.y_test = y_test

这里要注意的是,预定义的TrainTestSplitter并没有对数据进行洗牌(参数shuffle的默认值为 False )。这是因为我们通常不想重新排列时序数据**。然而,在某些情况下,它可能是有意义的。所以要照顾好这个参数!**

预处理

有时适当的预处理比模型选择更重要。

SeqRep 中,我们使用了来自 ScikitLearnPipeline;但是,你可以定义你的FeatureExtractor。通常,预处理的最后一步(有时是唯一的一步)是缩放。您可能想要(根据可用数据)创建要素。一些实现的提取器(例如,用于计算价格、心率变异性特征等技术指标)已经可用。

可以使用简单的PreviousValuesExtractor,它是为顺序数据设计的。它只是增加了前一个示例的功能。尽管如此,您可以通过继承类FeatureExtractor来定义自己的提取器。唯一需要实现的方法是transform方法。

特征的减少或选择

添加有价值的功能是值得的;但是,有时候,有无价值的特性

FeatureReductor可用于选择(不知何故)好的特征。在输入模型之前,应该省略一些(原始)特征(例如,文本特征)。FeatureSelector就是来帮你做这件事的!

这里就不赘述了。然而,基本的特征约简方法已经在包中实现。

形象化

SeqRep 包能够为您可视化各个步骤(如果您想要的话)。在主类(PipelineEvaluator)初始化期间,将您想要绘制的模块名称写入参数visualize

请注意,看到可视化的训练数据可能会很好;但是,处理从 x 要素到二维的向下投影可能需要一些时间。

Firmbee.com在 Unsplash 上的照片

SeqRep 的高级使用

SeqRep 包非常可定制。您可以定义自己的单个步骤的实例。

一些步骤可以省略,包括学习和评估。因此您可以创建仅用于预处理的工作流。但是,您可以将输出用于主类的其他实例(PipelineEvaluator)以及一些模型和评估器。如果我们想要测试更多的模型(或者不同的模型设置),这可能是有益的。你可以在这个例子中看到这个用法。

下一步是什么?

您可以查看存储库中的示例。

你可以通过打开模板 Jupyter 笔记本开始使用 SeqRep 包。

欢迎反馈!没有什么是完美的,所以我会感谢你的评论。如果你觉得 SeqRep 包有帮助,我会很高兴你 仓库 打一颗星。

https://github.com/MIR-MU/seqrep

今天,我们简单介绍了一下 SeqRep 包的功能。希望可以理解。我计划写另一篇文章,关于使用基因组数据包案例研究**。**

新到中?解锁无限访问(并支持我)!

NILM 的序列点到点神经网络

原文:https://towardsdatascience.com/sequence-to-point-neural-network-for-nilm-6719584fa21f

NILM 的深度学习

用于序列建模的 CNN?让我们看看它进展如何

里卡多·安南达尔在 Unsplash 上拍摄的照片

介绍

N ILM(非侵入式负载监控)是了解客户行为和构建可扩展基础设施解决方案的重要流程之一。NILM 最基本的使用案例是让最终用户更好地了解他们自己家庭的能源消耗。这反过来有助于用户养成更好的消费习惯,从而减少 5-10%的消费。到目前为止,我们已经看到了许多深度学习方法,包括 hmm、RNNs、LSTMs、GRUs 和 Transformers,它们属于序列建模领域,主要依赖于移动滑动窗口来捕获模式以获得分解结果。

NILM 的主要应用

  1. 识别节能机会:通过提供单个设备的电力消耗的详细信息,NILM 可以帮助识别减少能源使用的机会。例如,如果某个特定设备使用的能源超出预期,则可能会切换到更节能的型号,或者减少该设备的使用频率
  2. 支持需求侧管理:NILM 可用于支持需求侧管理,这涉及控制电力需求,以提高电网的效率。通过提供关于单个电器的电力消耗的实时信息,NILM 可以帮助公用事业公司更好地管理需求,避免电网过载
  3. 加强能源审计:能源审计用于评估建筑物或其他设施的能源效率。通过纳入 NILM 数据,能源审计可以提供更详细和准确的能源使用分析,这有助于确定可以改进的具体领域。

背景

一个流行的序列建模体系结构 Seq2Seq [1]主导了该领域的大部分任务。在用于 NILM 的 Seq2Seq 型架构中,输入功率序列的滑动窗口将学习对应于电器的输出功率的滑动窗口。这里的问题有三个方面,

  1. 作为滑动窗口过程的一部分,输出窗口元素被计算多次
  2. 特定的几个滑动窗口可能接近更好的结果
  3. 计算成本高

Seq2Point [2]提出通过从序列输入窗口输出单个值(输出窗口的中点)来解决主要瓶颈。让我们深入了解一下 Seq2Point 架构是如何将之前工作的错误率降低了大约 83%的。

理念与建筑

Seq2Point 架构蓝图。图片致谢— Seq2Point 论文

Seq2Point 的想法是,对于输入窗口,输出将是目标设备窗口的相应中点元素。然而,有一个重要的潜在假设:“中点元素被表示为电源输入窗口的非线性回归”。此假设基于设备窗口的中点元素(输出),并应考虑周围信息,即设备活动之前和之后的信息。

为了训练它,输出序列的两端都用零填充,以处理序列的端点。Seq2Point 的主要区别在于,将有一个单一的绝对输出 x(t ),而不是来自窗口的平滑(平均)预测。

成果和基准

UK-DALE [3]和 REDD [4]是为培训选择的数据集,Seq2Point 与 Seq2Seq 进行了比较,以进行基准测试和分析。

在基于 NILM 的神经网络中,数据必须仔细准备。基于序列长度(599 个时间戳)选择输入电源序列,输出是目标序列中的中点元素。序列窗口内的值被归一化。

关于评估指标,MAE(平均绝对误差)用于计算每个时间戳 t 的误差,归一化 SAE(信号绝对误差)用于计算较长时间内的总能量误差。

各种器械的 MAE 和 SAE 错误率的比较。图片致谢— Seq2Point 论文

类似的比较,但侧重于 Seq2Point 和 Seq2Seq,使用 Seq2Point 论文中的方法。图片致谢— Seq2Point 论文

从上表中可以看出,在大多数选定的设备上,Seq2Point 的性能远远优于 Seq2Seq 和 AFHMM。

我的想法

当我浏览特征图和为观察对网络如何学习特征的理解而进行的消融研究时,我对网络学习特征的程度感到吃惊。卷积神经网络再次表明它是最好的特征提取器/模式发现器之一。有几组滤波器拾取振幅变化,还有几组滤波器专注于状态变化。令人惊讶的是,它能够了解每个设备状态变化的持续时间!

请阅读 Seq2Point 白皮书的潜在特征可视化部分。

NILM 的真实例子

Open Energy Monitor 是一个开源的 NILM 系统,设计用于住宅和商业环境。它使用传感器来监控单个设备的电力消耗,并为用户提供有关其能源使用的详细信息。这使得用户能够找到降低能耗的方法,并随时监控他们的进度。

能源检测(TED)是一个为住宅设计的 NILM 系统。它使用传感器来监控单个设备的电力消耗,并为用户提供有关其能源使用情况的实时信息。这使得用户可以确定哪些电器使用最多的能源,并采取措施减少其能源消耗。

结论

Seq2Point 是 NILM 研究领域的一大亮点,因为其简化的架构带来了巨大的成果。使用的数据集是真实的,暗示了在真实场景中的可能部署,并创造了商业价值。它优于 Seq2Seq(序列建模中事实上的 boss ),也解释了网络的特征和行为。

加成 :这里是 Seq2Point 在 TensorFlow 中的实现——【https://github.com/MingjunZhong/seq2point-nilm】T4

参考

[1]seq 2 seq:https://arxiv.org/abs/1409.3215

[2]seq 2 point:https://arxiv.org/abs/1612.09106

[3]英国-戴尔:https://jack-kelly.com/data/

[4]REDD:https://energy . duke . edu/content/reference-energy-disaggregation-data-set-REDD

原载于https://blog.plexflo.com

服务数百到数千个 ML 模型——来自行业的架构

原文:https://towardsdatascience.com/serve-hundreds-to-thousands-of-ml-models-architectures-from-industry-bf3d9474d427

行业笔记

服务数百到数千个 ML 模型——来自行业的架构

当您只有一两个模型要部署时,您可以简单地将您的模型放在一个服务框架中,并将您的模型部署在几个实例/容器上。然而,如果您的 ML 用例增长或者您在您的数据的许多部分上构建单独的模型(像每个客户的模型),您可能最终需要服务于大量的模型。这篇文章将探讨这个问题:如何设计一个可以实时服务数百甚至数千个模型的系统?

第一,当你需要部署成百上千的在线模型时,会有什么变化?TLDR:更加自动化和标准化。通常,这意味着对模型服务平台的投资。

像 Reddit、DoorDash、Grab 和 Salesforce 这样的公司已经建立了模型服务平台来:

  1. 满足他们的规模需求,包括模型数量和每秒请求数。
  2. 让整个组织的 ML 团队更容易部署模型。
  3. 提供像影子模式、逐步展开和监控这样的功能。
  4. 确保模型服务的一致 SLA,这可能涉及到实现对平台上所有模型都有利的优化。

尽管每个组织都独立地构建了自己的系统,但是高层设计惊人地相似。下面是我综合的一个总体设计。

这篇文章将主要关注服务于大量模型的模型服务架构,而不会涉及其他方面,如模型 CI/CD 或比较服务框架。

开发者体验

让我们从数据科学家/ML 工程师如何在平台上部署新模型开始。他们

  1. 将训练好的模型保存到模型存储/注册表中。
  2. 提供一个模型配置文件,其中包含模型的输入特性、模型位置、需要运行的内容(比如对 Docker 映像的引用)、CPU 和内存请求以及其他相关信息。

基本上——这是我的模型工件,以及如何使用它。这两个步骤可以通过内部工具来简化。在自动化再培训的情况下,部署新模型甚至可能是自动化的。

图 1:平台用户将模型工件和模型配置存储到模型服务平台期望的地方。作者图解。

服务架构

一旦平台有了模型工件及其配置,它就处理模型加载、特性获取和其他关注点。一般服务系统的高级组件如图 2 所示。为了简单起见,我假设所有服务都作为容器部署。

在一般情况下,对推理服务的请求可能要求来自多个模型的多个预测。如图 2 所示,服务请求的步骤如下:

  1. 读取请求中模型的模型配置。然后使用配置来确定要获取的特性。
  2. 从特征库中检索特征。有些功能可能包含在请求中,不需要提取。如果功能存储中缺少某个功能或该功能过于陈旧,请使用默认值。
  3. 向各自的模型发送特征以获得预测
  4. 将预测返回给客户端

图 2:支持许多模型的模型服务平台的架构。重叠的矩形显示组件可以水平缩放。作者图解。

架构的组成部分:

  • 推理服务 —提供服务 API。客户端可以向不同的路线发送请求,以从不同的模型获得预测。推理服务统一了跨模型的服务逻辑,并提供了与其他内部服务更容易的交互。因此,数据科学家不需要考虑这些问题。此外,推理服务调用 ML 服务容器来获得模型预测。这样,推理服务可以专注于 I/O 相关的操作,而模型服务框架则专注于计算相关的操作。每组服务都可以基于其独特的性能特征进行独立扩展。
  • 型号配置 —来自平台用户。可以从另一个服务中读取某个模型的配置,或者在推理服务启动时将所有配置加载到内存中。
  • 特征存储 —是一个或多个包含特征的数据存储。
  • ML serving framework —是一个容器,其中包含了运行某种模型所需的所有依赖关系。例如,具有 Tensorflow 服务的特定版本的容器。容器可以服务于一个或多个模型。为了确保图像的可重用性,模型通常不会被放入容器图像中。更确切地说,容器在启动时或者收到对模型的请求时加载模型。一段时间不活动后,模型可能会从内存中被逐出。
  • 模型商店——听起来确实如此。这可以是像 AWS S3 这样的对象存储,服务可以通过模型注册服务与它交互。

图中未显示

图 2 并不全面,仅代表核心组件。所有生产系统都应该对运营指标进行监控。此外,模型度量可能会流入另一个系统进行漂移检测。可能有一个组件将业务逻辑应用于模型预测,例如,增加产品推荐的排名。每个企业都需要确定自己的需求。

系统存在于何处?

上面提到的许多组织选择在 Kubernetes 上部署平台。一些原因:

  • 它帮助你管理大量的容器!
  • 资源虚拟化。容器获得资源请求和限制,所以没有人可以独占所有的资源,这对于从同一个实例服务多个模型很有用。
  • 基于 CPU 利用率和其他指标的水平自动扩展易于配置。

您可能不会选择 Kubernetes 进行容器编排,但您可能会想要类似的东西。

举个例子,Reddit 的服务平台是这样的:

图 3: Reddit 的推理服务,Gazette。来源:[2]。该架构类似于图 2。绿色方框用于张量流模型。他们使用 Memcached Daemonset 作为缓存来加速特征检索。

扩展以服务更多型号

首先,最简单的方法是为每组 ML 服务框架容器提供一个模型。图 4 是一个例子。欺诈模型在一组 XGBoost 容器中,定价模型在一组 TorchServe 容器中,推荐者模型在另一组 TorchServe 容器中。有了一个好的容器编排框架,您可以扩展到数百个模型。

图 4:每套 ML 服务容器一个模型。作者图表

随着时间的推移,团队产生了更多的模型和同一模型类型的多个版本,这导致了许多容器。您可能会倾向于为每个容器提供多个模型,因为:

  1. 您想要更高的资源利用率。如果定价模型是空闲的,仍然有 2 个或更多的运行容器来确保模型是可用的。这些容器占用了所请求的资源量。但是,如果 TorchServe 容器同时服务于推荐模型和定价模型,您可以使用更高百分比的资源。当然,代价是你可能会有吵闹的邻居,其中一个模型变慢了,因为另一个正在争夺资源。
  2. 你预计你会遇到一些容器数量的限制。Kubernetes 有每个集群的限制,AWS 弹性容器服务也是如此。或者,可能集群是共享的,服务平台的容器数量有限制。

一些像 Tensorflow Serving 和 TorchServe 这样的框架支持本地服务多个模型[1,5]。Salesforce Einstein 为每个容器提供多个模型,因为他们需要为超级大量的模型提供服务。

图 5:每组 ML 框架容器的多个模型。XGBoost 容器服务于同一模型类型的两个版本。TorchServe 容器同时服务于定价和推荐模型。作者图解。

最佳化

如果图 2 中的系统性能不够好,有很多优化的机会。

首先是添加缓存。您可以在要素存储前添加缓存,以加快要素检索。如果服务框架仅在有请求时将模型加载到内存中,那么第一个请求可能会很慢。加快速度的一个方法是在模型存储之前添加一个缓存,就像共享文件系统一样。如果您经常收到相同的预测请求,您甚至可以为模型预测添加缓存。

另一个优化是用 C服务模型。DoorDash 的服务平台支持 lightGBM 和 PyTorch 模型,并且都在 C中运行[7]。

如果某些应用程序需要一次预测多个输入,请求批处理会很有用。例如,在单个请求中对 100 个推荐项目进行排名。一些服务框架支持批处理多个预测请求,以获得更好的吞吐量。在 GPU 上运行神经网络时,批处理预测可能特别有益,因为批处理可以更好地利用硬件。

阴影模式和模型卷展栏

实现影子模式的一种方法是将一定比例的生产模型请求转发给影子模型。发送请求而不等待响应,并设置一个监视系统,将阴影模型输入和输出写到一个离线存储,如雪花或 AWS 红移。然后,数据科学家可以离线分析模型性能。给予影子模型比生产模型更低的优先级以防止停机是至关重要的。在 Kubernetes 中,您可以指定 pod 调度和驱逐的优先级[4]。

推出新版本模型的安全方法是首先将一小部分生产流量转移到新版本。有两种方法可以做到这一点。第一种是让客户选择使用哪个版本的模型。他们可以调用不同的 API 路由,或者在请求中包含模型版本。另一种让平台选择的方法是——开发人员在模型配置或其他配置文件中指定向新模型发送多少流量。然后,推理服务负责将正确百分比的请求路由到新模型。我更喜欢后一种方法,因为客户不需要改变他们的行为来使用新的模型。

服务于超大量的模型

Salesforce 有一个独特的使用案例,他们需要服务 100K-500K 模型,因为 Salesforce Einstein 产品为每个客户构建模型。他们的系统在每个 ML 服务框架容器中服务多个模型。为了避免嘈杂的邻居问题,并防止一些容器比其他容器承担更多的负载,他们使用 shuffle sharing[8]为容器分配模型。我就不赘述了,推荐看他们在[3]的精彩呈现。

图 Manoj Agarwal 关于 Salesforce Einstein 如何为模型服务的演示截图。Manoj 在这张幻灯片上解释了洗牌分块。“路由器”服务是推理服务。“版本管理”服务告诉“路由器”要服务哪个版本的模型。特征被发送到 AutoML 2.0 容器进行预测。来源:[3]。

结论

我们已经讨论了一个被多个组织使用的架构,它服务于大量的模型,并为整个组织中的团队提供了一条铺平的道路。我确信有替代设计,因为任何设计的细节都取决于组织的需求。请让我知道我应该考虑的其他架构!

参考

  1. "12.运行 TorchServe — PyTorch/Serve 主文档。 PyTorch ,py torch . org/serve/server . html # serving-multi-models-with-torch serve。访问时间为 2022 年 1 月 11 日。
  2. 霍夫曼加勒特。"发展 Reddit 的 ML 模型部署和服务架构."Reddit2021 年 10 月 4 日www . Reddit . com/r/RedditEng/comments/q 14 tsw/evolving _ reddits _ ml _ model _ deployment _ and _ serving。
  3. 马诺基·阿加瓦尔。“以低延迟大规模提供 ML 模型// Manoj Agarwal // MLOps Meetup #48。” YouTube ,由 MLOps.community 上传,2021 年 1 月 22 日www.youtube.com/watch?v=J36xHc05z-M。
  4. 更多,普拉东斯。"猫步:大规模服务于机器学习模型——走向数据科学.",2021 年 12 月 12 日,朝 sdadascience . com/catwalk-serving-machine-learning-models-at-scale-221d 1100 aa2b。
  5. "调度、抢占和驱逐."2022 年 1 月 11 日,kubernetes.io/docs/concepts/scheduling-eviction.库伯内特斯进入。
  6. "张量流服务配置| TFX | . " TensorFlow ,www . tensor flow . org/tfx/serving/serving _ config # model _ server _ configuration。于 2022 年 1 月 11 日访问。
  7. 曾,科迪。"认识 Sibyl——door dash 的新预测服务——了解它的构思、实施和推广." DoorDash 工程博客,2020 年 10 月 6 日,door dash . Engineering/2020/06/29/door dash-new-prediction-service。
  8. 左,奎因。“在贝宝部署大规模欺诈检测机器学习模型。”Medium2022 年 1 月 4 日 Medium . com/paypal-tech/machine-learning-model-ci-CD-and-shadow-platform-8c4f 44998 c78。
  9. MacCárthaigh,Colm。"使用混洗分片的工作负载隔离."亚马逊网络服务公司,AWS . Amazon . com/builders-library/workload-isolation-using-shuffle-sharding。于 2022 年 1 月 13 日访问。

AWS Lambda 上机器学习模型的无服务器部署

原文:https://towardsdatascience.com/serverless-deployment-of-machine-learning-models-on-aws-lambda-5bd1ca9b5c42

在 AWS Lambda 上部署 dockerised ML 模型的指南

钳工在 Unsplash 上拍照

介绍

在我之前的指南中,我们探讨了在 AWS Elastic Beanstalk 上部署机器学习模型的概念和方法。尽管在很大程度上是自动化的,但像 AWS Elastic Beanstalk 这样的服务仍然需要部署 EC2 实例和弹性负载平衡器这样的关键服务。AWS Elastic Beanstalk 上提供的资源总是活动的,即使不需要。

通过消除基础设施管理任务,无服务器代码编排的概念脱离了云计算资源的传统实现。无服务器云计算是在 Elastic Beanstalk 上提供的免手动基础设施管理方法的演变,但没有服务器的供应或管理。

无服务器计算是一种事件驱动的计算服务,可以为几乎任何应用程序运行代码。由于开发人员不需要管理基础设施,代码的无服务器实现具有提高生产率的好处,因为开发人员可以花更多的时间编写代码。最终,无服务器功能是无状态的,只在你需要的时候执行。这使得它们成为许多应用的高性价比解决方案。

在本指南中,我们将学习如何将机器学习模型部署为 lambda 函数,即 AWS 提供的无服务器产品。我们将首先通过在我们的机器上集成 AWS CLI 来设置工作环境。接下来,我们将训练一个 K 近邻分类器,我们将把它部署为 docker 容器。本指南将带您浏览您需要的工具,使您能够在将应用程序部署为 AWS 上的 lambda 函数之前,在本地测试您的应用程序。

我们开始吧。

内容

  • 先决条件
  • MNIST 数据集简介
  • 训练 K-最近邻(KNN)分类器
  • 初始化 AWS S3 存储桶
  • 使用 SAM 部署和测试 AWS lambda 函数
  • AWS 资源终止
  • 摘要

先决条件

在继续之前,您需要满足几个先决条件。本指南将要求您与许多工具进行交互,因此请花一些时间来满足这些先决条件。

  1. 你需要一个 AWS 账户。您可以注册免费层,该层将在注册时自动应用。
  2. 导航命令行的一些技术知识。
  3. 安装 AWS CLI
  4. 设置 AWS CLI
  5. 安装 AWS 无服务器应用模型 CLI
  6. 安装码头工人
  7. Python 3.9.7
  8. VS 代码与 Jupyter 扩展或任何你喜欢的 IDE。
  9. 诗歌——Python 包管理工具(阅读我的上一篇关于如何使用诗歌的文章
  10. Python 库:scikit-learn、numpy、requests、pandas、joblib、boto3、matplotlib、py toolter、jupyter、ipykernel。您可以使用 poem 安装我当前的 python 版本,或者将requirements.txt文件包含在 Git 存储库中。
  11. 这个项目的项目存储库在这里被链接。代码的主体可以在 Jupyter 笔记本中找到,链接这里。

概观

本指南的目的是向您介绍在 AWS 上将机器学习模型部署为 lambda 函数所需的步骤。本指南记录了部署 lambda 函数所需的关键工具。这是我们将在这个项目中涵盖的内容的概述。

  • 在用于部署的 MNIST 数据集上训练 K-最近邻分类器。
  • 将 S3 存储桶初始化为数据存储。
  • 使用 AWS 无服务器应用程序模型(SAM)对 dockerised lambda 函数进行本地测试。
  • 使用 AWS SAM 部署云形成堆栈。

1.MNIST 数据简介

对于这个分类项目,我们将使用包含 70,000 张手写数字图像的 MNIST 数据集。在该数据集中,每行代表一幅图像,每列代表 28×28 像素图像中的一个像素。MNIST 数据集被广泛用于训练分类器,并且可以使用辅助函数[sklearn.datasets.fetch_openml](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_openml.html)来获取。来自 OpenML 的所有数据都是免费使用的,包括所有的经验数据和元数据,在CC-BY license下许可使用。

这个项目的所有代码都可以在 Jupyter 笔记本中找到,deploying_models.ipynb,从 github repo 链接这里。

aws_lambda_no_authoriser
├── app
│   ├── lambda_predict.py
│   └── knnclf.joblib
├── .gitignore
├── Dockerfile
├── LICENSE
├── deploying_lambda.html
├── deploying_lambda.ipynb
├── overview.png
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── template_no_auth.yaml

下面的代码将下载 MNIST 数据,并对 20,000 行进行采样。该数据集已经过缩减,以减少该项目的模型大小和构建时间。下面的代码还将绘制数据集中的第一幅图像,我们可以看到它是数字 8。

绘图输出显示第一个图像是手写的数字 8。(图片由作者提供)

2.训练 K-最近邻分类器

首先,我们将把数据分成训练集和测试集,然后使用scikit-learn库训练一个 K 近邻分类器。

通过交叉验证,该模型达到了相当不错的 96%的平均准确率。让我们在test_features数据集上评估模型的性能,并使用show_cm函数绘制一个混淆矩阵,如下所示。

准确度:0.95725(图片由作者提供)

基于测试数据集的准确性,我们可以看到我们的模型符合数据。当比较训练集和测试集之间的准确性时,我们得到了非常相似的预测准确性。

此外,如上图所示的混淆矩阵非常有助于可视化模型性能的差距。这将有助于我们理解分类器所犯的错误。

该矩阵表明,在 16 个例子中,数字 4 被误认为数字 9,在 12 个例子中,数字 8 被误认为数字 5。

看下面的图片,可能会明白为什么会出现这些错误,因为数字 4 和 9 确实有一些相似的特征。数字 8 和 5 也是如此。

作者图片

这一见解不会影响 AWS 上的模型部署,但将有助于指导进一步改进模型的策略。

现在,我们将使用 Docker 将模型保存在本地,作为 lambda 函数的一部分进行封装。

3.初始化 AWS S3 存储桶

下图展示了支持 lambda 函数所需部署的整体资源基础设施。我们的应用程序有三个关键的资源要求:

  1. S3 桶用来存储数据。
  2. API 网关管理 HTTP 请求。
  3. λ函数包含预测逻辑。

ML 模型的无服务器部署——1)测试数据上传到 S3 桶。2)为了启动 lambda 函数,通过 Amazon API 网关发送一个 POST HTTP 请求。lambda 函数的初始化执行从 S3 桶下载数据并执行预测的代码。4)HTTP 响应返回给客户端,预测作为数据有效载荷。(图片由作者提供)

Lambda 函数将包含基于存储在 S3 存储桶中的test_features数据集执行预测的 Python 代码。因此,我们将首先需要初始化一个 S3 桶,在那里我们可以托管我们的数据。

为此,我们将使用 AWS Python SDK boto3与 AWS 进行交互。这个包包含了我们集成 Python 项目和 AWS 所需的所有依赖项。

让我们用下面的代码初始化一个 S3 桶。

注意:*bucket_name*必须是唯一的,因此您必须用一个未被采用的名称替换 *bucket_name*

S3 存储桶将托管我们的test_features数据集,我们可以在 lambda 函数中调用该数据集来执行预测。

为了保存当前在我们工作区中的对象,我们将使用来自io库的BytesIO函数。这将使我们能够在文件对象中临时存储test_features数据集。这个文件对象可以通过调用.upload_fileobj函数上传到 S3 桶。

bucket变量定义目标 S3 桶,而key变量将定义桶中的文件路径。bucketkey变量将构成对 lambda 函数的 POST HTTP 请求中的数据有效载荷的一部分。

我们可以用下面的帮助函数检查对象是否已经上传。list_s3_objects将列出定义的桶中的所有对象。

输出:[‘validation/test_features.joblib’]

我们现在已经成功初始化了一个 S3 存储桶来存储test_feature数据。接下来的两个关键资源,API 网关和 lambda 函数,将使用 AWS 无服务器应用模型(SAM)进行部署。

4.使用 SAM 部署和测试 AWS Lambda 函数

AWS SAM 是一个用于构建无服务器应用的开源框架。它是一个工具,通过提供简单的语法在 AWS 上部署功能、API 或数据库,简化了无服务器架构的构建过程。SAM 是一个平台,它将快速部署无服务器应用程序所需的所有工具统一在一个 YAML 配置文件中。

还有其他选项,例如无服务器,这是一个很好的选项。无服务器具有作为通用云接口(AWS、Azure、Google Cloud)的额外优势,以增加多功能性。然而,我个人发现在 AWS SAM 上本地集成和测试 docker 容器比在无服务器上更好。我很好奇是否有人有不同的意见!一定要留个便条。

这是当前项目的整体文件夹结构,可以在 github 这里找到。

*aws_lambda_no_authoriser
├── app
│   ├── lambda_predict.py
│   └── knnclf.joblib
├── .gitignore
├── Dockerfile
├── LICENSE
├── deploying_lambda.html
├── deploying_lambda.ipynb
├── overview.png
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── template_no_auth.yaml*

在下面的部分中,我将专门讨论三个重要的文件。

  1. 详细说明 SAM 配置的.yaml文件。(template_no_auth.yaml)
  2. 一个包含 lambda 函数代码的.py文件。(lambda_predict.py)
  3. 一个Dockerfile详细描述了封装我们的 lambda 函数的代码。(Dockerfile)

4.1\. template_no_auth.yaml

template_no_auth.yaml定义了构建无服务器应用程序所需的所有代码。你可以在这里找到模板规范的官方文档。

注: 该当前模板不包括执行 API 请求的服务器端认证的资源。因此,在当前状态下部署我们的 lambda 函数将允许任何人使用 URL 向您的函数发出请求。

让我们仔细看看模板文件,以便更好地理解正在定义的配置。我将它分成三个部分,并在标题中链接了每个声明的相应文档。

*AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:Function:Timeout: 50MemorySize: 5000Api:OpenApiVersion: 3.0.1
Parameters:Stage:Type: StringDefault: dev*

AWSTemplateFormatVersion

最新的模板格式版本是2010-09-09,是目前唯一的有效值。

[Transform](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html)

AWS::Serverless-2016–10–31声明将 AWS CloudFormation 模板文件标识为 AWS SAM 模板文件,并且是 SAM 模板文件的要求。

[Globals](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html)

特定资源使用的全局变量可以在这里定义。功能超时,内存大小分别设置为 50 和 5000 MB。当达到指定的超时时间时,函数将停止执行。您应该将超时值设置为预期的执行时间,以防止函数运行时间超出预期。最后,在我们的模板中,我们已经将 open API 版本设置为 3.0.1。

[Parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html)

将默认分段值设置为dev。您可以定义可在 yaml 文件中引用的参数值。

*Resources:LambdaAPI:Type: AWS::Serverless::ApiProperties:StageName: !Ref StagePredictFunction:Type: AWS::Serverless::FunctionProperties:PackageType: ImageArchitectures:- x86_64Events:Predict:Type: ApiProperties:RestApiId: !Ref LambdaAPIPath: /predictMethod: POSTPolicies:- AmazonS3FullAccessMetadata:Dockerfile: DockerfileDockerContext: ./DockerTag: python3.9-v1*

[Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html)

在参考资料部分,我们将声明应用程序所需的特定 AWS 资源。这个列表详细列出了您可以在 SAM 中声明的可用资源的数量。

对于我们的项目,我们将声明 API 网关和 lambda 函数为资源。我们不需要声明 S3 存储桶,因为我们已经为我们的项目创建了一个存储桶。

ML 模型的无服务器部署——1)测试数据上传到 S3 桶。2)为了启动 Lambda 函数,通过 Amazon API 网关发送一个 POST HTTP 请求。Lambda 函数的初始化执行从 S3 桶下载数据并执行预测的代码。4)HTTP 响应返回给客户端,预测作为数据有效载荷。(图片由作者提供)

在参考资料部分,声明了一个名为LambdaAPI的 API。LambdaAPI具有属性StageName,该属性具有参数 stage。

*LambdaAPI:Type: AWS::Serverless::ApiProperties:StageName: !Ref Stage*

参考资料部分还声明了一个名为PredictFunction的 lambda 函数。要将 lambda 函数声明为 docker 映像,需要将[PackageType](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-packagetype)变量定义为Image,并且必须在 yaml 文件的[Metadata](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-build.html)部分声明指向 docker 文件的链接。

*PredictFunction:Type: AWS::Serverless::FunctionProperties:PackageType: ImageArchitectures:- x86_64Events:Predict:Type: ApiProperties:RestApiId: !Ref LambdaAPIPath: /predictMethod: POSTPolicies:- AmazonS3FullAccessMetadata:Dockerfile: DockerfileDockerContext: ./DockerTag: python3.9-v1*

我们还指定了一个[event](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-eventsource.html),它将触发 lambda 函数。在这种情况下,LambdaAPI/predict端点的 POST HTTP 请求将触发 lambda 函数。最后,为了让 lambda 函数能够访问 S3 存储桶,我们附加了 AWS manage 策略 AmazonS3FullAccess

*Outputs:LambdaApi:Description: "API Gateway endpoint URL for Dev stage for  Predict Lambda function"Value: !Sub "https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/${Stage}/predict"*

[outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html)部分,我们声明了一组在使用 SAM 部署应用程序后返回的输出。我已经定义了输出来返回 API 端点的 URL 以调用 lambda 函数。

4.2.λ_ predict . py

lambda_predict.py文件包含与我们应用的预测逻辑相关的代码。一般而言,该功能将:

  1. 加载模型。
  2. 下载由bucketkey变量引用的test_features数据集。
  3. 对下载的数据集执行预测。
  4. 以 numpy 数组的形式返回预测的 JSON 对象。

python 文件还包含一个记录脚本进度的logger类,这对调试非常有帮助。

此外,在优化 lambda 函数时,这是一个很好的时机来说明冷启动的概念以及它如何影响延迟。我已经链接了一篇文章,很好地解释了这个概念。

4.3.Dockerfile 文件

Dockerfile详述了将我们的 lambda 函数封装成 docker 映像所需的指令。我将使用 Python 3.9 并使用诗歌安装 Python 依赖项。

需要注意的关键点是,docker 映像的入口点被设置为在lambda_predict.py文件中声明的lamba_handler函数。这个入口点定义了在一个event触发器(比如 HTTP POST 请求)期间要执行的函数。初始化容器映像时,将执行同一脚本中的lambda_handler函数之外的任何代码。

4.4.在本地构建和测试应用程序。

AWS SAM 提供了在部署之前构建和本地测试应用程序的功能。

  1. 确保 docker 正在运行。在终端窗口中,导航到项目目录并在 SAM 中构建应用程序。
*sam build -t template_no_auth.yaml*

作者图片

2.在本地部署 dockerised lambda 函数。

*sam local start-api*

作者图片

3.在[http://127.0.0.1:3000](http://127.0.0.1:3000.)/predict本地调用该功能。您的 URL 可能有所不同。

注意: 引用 S3 上 *test_feature* 数据集的 *bucket* *key* 变量需要作为 POST HTTP 请求中数据有效载荷的一部分进行传递。

准确度:0.95725(图片由作者提供)

与之前的test_feature预测相比,本地调用的 lambda 函数如我们预期的那样执行,因为我们获得了相同的结果。

4.5.在 AWS Lambda 上部署

就像在本地部署一样容易,SAM 也将处理在 AWS Lambda 上部署的所有繁重工作。

a)在 SAM 中构建应用程序。

*sam build -t template_no_auth.yaml*

b)部署应用程序。

*sam deploy --guided*

遵循指导您完成部署配置的提示。除了少数例外,我使用的大多数设置都是默认值。

*Stack Name [sam-app]: predict-no-auth
AWS Region [eu-west-2]:
Parameter Stage [dev]: 
Confirm changes before deploy [y/N]: 
Allow SAM CLI IAM role creation [Y/n]: 
Disable rollback [y/N]: y
PredictFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: 
SAM configuration file [samconfig.toml]: 
SAM configuration environment [default]:
Create managed ECR repositories for all functions? [Y/n]:*

在部署阶段,SAM 将把应用程序的最新版本上传到一个托管的 Amazon 弹性容器注册中心(Amazon ECR)上。

SAM 还将输出 CloudFormation 事件的列表,详细说明为您的应用程序部署所请求的 AWS 资源。

来自堆栈操作的云形成事件(图片由作者提供)

最终输出将详细说明调用 lambda 函数的 API 网关 URL。

作者图片

c)通过用上面输出的 URL 替换下面代码中的 URL 来调用您的函数。

准确度:0.95725(图片由作者提供)

恭喜你!🎉🎉如果您已经达到了这个里程碑,那么我们已经成功地在 AWS 上部署了一个 KNN 分类器作为 lambda 函数。

然而,如前所述,公开的 API 目前并不安全,任何拥有该 URL 的人都可以执行您的函数。有许多方法来保护 API gateway 的 lambda 函数,但是这不在本指南的范围之内。

d)使用以下命令终止和删除 AWS lambda 函数。用应用程序的名称替换[NAME_OF_STACK]。文档可以在这里找到。

*sam delete --stack-name [NAME_OF_STACK]*

摘要

lambda 函数在生产中的多功能性不容低估。API 驱动的 lambda 函数的执行,正如在这个项目中演示的,是众多事件驱动的 lambda 函数被激活的方式之一。除了作为一个经济高效的解决方案,lambda functions 需要更少的维护,因为 AWS 处理大量的资源和基础设施管理。因此,这让开发者有更多的时间将注意力集中到其他地方。

在本指南中,我们在 AWS lambda 上训练、测试和部署了一个机器学习模型。首先,在 MNIST 数据集上训练一个 K-最近邻分类器。这个经过训练的模型使用 Docker 与包含预测逻辑的 lambda 函数打包在一起。借助 SAM,dockerised 容器在 AWS 上部署为 cloudformation 堆栈之前在本地进行了测试,其中模型用作 API 端点。

如果你已经读完了这篇指南,我希望你已经学到了一些新的东西。如果有任何问题,请留下您的评论,我将非常乐意帮助您。

更多数据科学相关内容请务必在 LinkedIn 、Medium 或 Twitter(@ illoyd Hamilton)关注我。

来 CodeClan 跟我学吧。

注意这个空间。

通过 AWS 上的 HTTP API 进行无服务器 NLP 推理

原文:https://towardsdatascience.com/serverless-nlp-inference-via-http-api-on-aws-e27ea41d122b

如何使用 Boto3 为您的无服务器端点设置 API

照片由天舒刘在 Unsplash

这是怎么回事?

在之前的一篇博文中,我描述了我们如何在 Amazon SageMaker 上部署 NLP 模型进行无服务器推理。下一步,我们将测量这个无服务器端点的性能。为此,我们需要用一些测试数据调用端点。这可以使用 Boto3 sagemaker-runtime 客户端轻松完成:

但是这通常不是应用程序和服务与我们的模型交互的方式。实际上,我们希望有一个 API 来路由我们的请求,这样我们就可以监视和控制对模型的访问。

在本教程中,我们将做到这一点:我们将设置一个允许我们访问无服务器端点的 API,这样,作为下一步,我们可以测量端点在现实条件下的性能。和往常一样,本教程的代码在这个 Github repo 中公开。repo 由两个笔记本组成:第一个用来创建无服务器端点,第二个用来创建 API 的基础设施。

为什么这很重要?

如上所述,建议公开使用 API 来服务 NLP 模型。这种方法确保了对模型的请求可以被监控和检查。API 还决定哪个模型用于哪个请求,并确保在无效请求的情况下进行适当的异常处理。智能扬声器是这种设置的一个很好的例子:

作者图片

在这个场景中,API 根据请求的类型决定应该使用哪个模型,并相应地路由请求。

在本教程中,我们将学习如何通过创建 API 和 Lambda 函数来建立这样一个路由,该函数将处理我们的请求并将其发送到无服务器端点上的 NLP 模型。我将假设已经存在一个 SageMaker 端点来开始本教程。如果你还没有设置,你可以用这个笔记本中的代码轻松设置。

创建 Lambda 函数

完成上述架构设置的最佳方式是从右到左,即从创建 Lambda 函数开始。

第一步是编写函数应该执行的代码。Lambda 函数需要提取将通过 API 发送的文本,调用端点,并在将结果发送回 API 之前解析结果。下面是如何做到这一点的示例:

我们如何知道来自 API 的请求的结构,即我们如何知道我们可以通过*事件[‘body’]*提取模型的文本?我们可以在 HTTP API 的文档中找到有效载荷格式,我们将在下面设置 API 时进一步研究它。

我们可以将 Lambda 函数的代码存储在本地的一个文本文件中。要创建函数,我们需要压缩这个文件,然后通过 Boto3 创建 Lambda 函数:

记住,要选择一个 IAM 执行角色,该角色包含一个策略,该策略允许您函数调用 SageMaker 端点!

创建 HTTP API

HTTP API vs REST API:选哪个?

AWS 在 2019 年推出了 HTTP APIs,试图为使用 API Gateway 构建的客户提供增强的功能、改进的性能和更轻松的开发人员体验。HTTP APIs 的缺点是它们不像 REST APIs 那样功能齐全。然而,对于我们相对简单的用例来说,HTTP APIs 工作得很好,设置起来也很容易:)

要了解更多信息,我建议查看官方的 AWS 文档和博客文章。

使用 Boto3 创建 HTTP API 非常简单。我们只需要一行代码来创建 API,其中我们提供 Lambda 函数作为目标:

在测试我们的设置之前,我们需要做的最后一件事是允许 API 调用 Lambda 函数。这是在 Lambda 函数的配置中完成的:

测试

我们终于有了所有的东西,现在可以测试我们的设置。为此,我们可以使用标准 Python 库*请求:*向 API 发送一个常规的 POST 请求

结论和后续步骤

我们已经建立了一个架构,允许我们通过 API 访问无服务器 NLP 端点。这类似于真实场景,现在我们可以开始测试端点的性能,并调查端点的延迟和冷启动。

我希望这是有帮助的,请随时提出问题和意见!

使用 Apache Spark 服务 ML 模型

原文:https://towardsdatascience.com/serving-ml-models-with-apache-spark-3adc278f7a78

关于如何使用 PySpark 为模型提供服务的端到端指南

来源

处理大型数据集伴随着由技术和编程语言设置的限制的困难。一个有效的步骤是了解分布式处理技术及其支持库。对于希望利用数据处理、 MLlib 和 Apache Spark 的模型服务功能的机器学习工程师和数据科学家来说,这篇文章非常重要。

什么是阿帕奇火花?

Apache Spark 是一个借助其广泛的软件包提供基于集群的分布式计算环境的系统,包括:

  • SQL 查询,
  • 流式数据处理,以及
  • 机器学习。

Apache Spark 支持 Python 、 Scala 、 Java 和 R 编程语言。

Apache Spark 服务于内存计算环境。根据 Kashif Munir 撰写的《绿色企业的云计算技术》一书,该平台支持一个正在运行的作业在内存中执行 100 倍的速度,在磁盘上执行 10 倍的性能。

PySpark 是什么?

最初,Apache Spark 是用 Scala 语言实现的。由于大多数机器学习库和高级数据处理包都是用 Python 编写的,因此与 Spark 集成的需求是显而易见的。为了满足这种需求,为 Spark 开发了一个 Python API。它被命名为 PySpark。它是在名为 Py4J 的 Python 解释器的帮助下建立的,该解释器同步到 Java 虚拟机(JVM) 的连接。

Spark 是如何工作的?

Apache Spark 支持作业的横向处理。它通过允许使用内存中的属性和增强的 SQL 熟练度来推进这项任务。Spark 的功能包括但不限于:

  • 操作许多分布式脚本,
  • 启用数据处理,
  • 生成数据工作流,以及
  • 使用 MLlib 函数执行分析方法

火花部件

Spark 项目由各种紧密结合的部分组成。在中心,Spark 包含一个计算执行机制,可以规划、并行化和筛选众多应用程序。同时使用所有的火花部件不是强制性的。根据现有的情况和要求,它们中的一些可以与火花芯一起使用。然而,Spark 核心的使用是必须的,因为它是 Spark 架构的核心。

火花核心

Spark Core 是通用实现组件的中心,它支持平台中的其他功能。

火花流

Spark Streaming 允许 Spark 处理从各种系统消耗的在线流数据,包括 HDFS 、 S3 、卡夫卡、水槽等。,并输出到不同的数据库系统。

火花开关 L

Spark SQL 是利用其查询功能提取结构化数据的主要模块。使用 Spark SQL 可以读取各种数据格式。其中包括拼花、 JSON 、 Avro 等等。此外,它允许用户定义的函数生成和 HiveQL 的使用。

GraphX

GraphX 可以表示为具有并行分布式执行的图形数据库系统的火花。抽象地说,它是由顶点和边组成的。GraphX 在其系统内部关联图形计算。

MLlib(机器学习)

MLlib 是 Spark 的核心机器学习库。它使分布式方法能够记录和处理数据。它由各种算法组成,包括回归、决策树、k-means 聚类等。

火花建筑

Spark 架构由驱动程序和工作节点组成。这些节点在集群管理器的帮助下连接在一起。

驱动节点

驱动程序节点是负责执行“main()”方法的主节点。其主要目的是成功创建所需的 Spark 会话。

集群管理器

集群管理器充当在请求的作业之间分配资源的结构。您可以选择 Hadoop Yarn 、 Mesos、或 Kubernetes 作为集群管理器。

工作节点

worker 节点包含处理相关代码块的任务。在它内部,执行器在执行完调度的作业后维护内存中的数据。执行器架构中的最小单元被称为任务。

为什么使用 Apache Spark

选择 Spark 有无数的理由。最重要的是它的易用性、快速性和支持。

易用性

Spark 的能力通过众多 API 开放。它们都是为大规模信息的快速有效交流而设计的。凭借其易于理解的结构,用户可以在短时间内使用 Spark 快速产生结果。

迅速

Spark 旨在实现快速性能。它在内存和本地存储中都有效。Spark 的执行速度与 Hadoop 的 MapReduce 相比有着高达百倍的显著差异。

支持

Spark 支持多种编程语言,包括 Python、R、Java 和 Scala。它集成了对 Hadoop 环境中各种内存应用的支持。此外,Apache Spark 开发人员社区是巨大的、动态的和全球性的。Hadoop 的商业供应商也为 Spark 应用提供广泛的服务。

火花装置

Spark 可以根据平台以不同的方式安装。在本节中,让我们介绍两种不同的安装选项:

  • 在 Google Colab 上设置它,然后
  • 在您的本地机器上安装它。

在 Google Colab 上设置 Spark

Google Colab 是一个用户在浏览器中有效实现 Python 脚本的环境。要在 Google Colab 上执行 Spark with Python,您必须安装适当的 Spark、Hadoop 和 Java 版本。在 Google Colab 上安装 Spark 可以如下图所示:

!apt-get install openjdk-8-jdk-headless -qq > /dev/null!wget -q [https://downloads.apache.org/spark/spark-2.4.8/spark-2.4.8-bin-hadoop2.7.tgz](https://downloads.apache.org/spark/spark-2.4.8/spark-2.4.8-bin-hadoop2.7.tgz)!tar xf spark-2.4.8-bin-hadoop2.7.tgz

在 Google Colab 上成功安装相应版本后,就可以为 Spark 和 Java 设置环境变量了。

import osos.environ[“JAVA_HOME”] = “/usr/lib/jvm/java-8-openjdk-amd64”os.environ[“SPARK_HOME”] = “/content/spark-2.4.8-bin-hadoop2.7”

findspark ”有助于找到以前安装的 PySpark 版本。然后,在` findspark.init() 的帮助下,使 PySpark 可以作为库导入。

import findsparkfindspark.init()

在本地机器上安装 Apache Spark

Apache Spark 可以在任何安装了 Python、Scala 或 Java 的环境中运行。本文将关注 Python 语言。紧凑快速地安装所需的 Python 包和 Jupyter Notebook 的最简单方法是使用 Anaconda 。

在 Anaconda 提示符下使用下面的命令安装 Spark:

conda install pyspark

Apache Spark 基础知识

Spark 支持弹性分布式数据集(RDD)结构。使用此结构可以读取外部数据源。使用 RDD 将方法传递给 Spark 是可能的。这些函数可应用于现有数据集或新数据集。

在接下来的章节中,您将了解更多关于 RDD 结构、Spark 转换和操作的内容。

弹性分布式数据集

弹性分布式数据集是 Spark 中面向客户端的基本编程接口,用于内存计算。它是数据组件的组合。

RDD 创作

在创建 RDD 之前,您需要创建一个 Spark 会话。这是在“ SparkContext 的帮助下完成的。“ SparkConf ”用于设置其他火花配置。

from pyspark import SparkContext, SparkConf

下一步是定义我们想要的火花配置。在这种情况下,我们将使用本地集群,因为我们是在本地机器上工作。您还可以选择在集群模式下设置 Spark。

指定*local[*]【T13]意味着 Spark 将使用本地机器中的所有内核。这通常是独立模式下的默认设置。*

spark_configurations = (SparkConf().setMaster(“local[*]”).\setAppName(“firstSparkSession”).\set(“spark.executor.memory”, “2g”))

有了这个配置,我们就可以创建 Spark 会话了。

spark_context = SparkContext(conf = spark_configurations)

有一些用于查看 spark 配置的内置函数。

Spark 版本可以使用`版本'属性进行检索。

spark_context.version

Python 版本可以使用*pythonVer*属性来显示。

spark_context.pythonVer

要查看分配给独立模式的内核数量,您可以向 spark 会话变量添加一个“”参数。在下面的例子中,Spark 会话的名称叫做` spark_context 。'

spark_context = SparkContext(conf = spark_configurations)spark_context.master

每个 Spark 会话都有一个唯一的名称。` setAppName 属性可用于设置会话的名称。

spark_configurations = (SparkConf().setAppName(“firstSparkSession”))spark_context = SparkContext(conf = spark_configurations)

分配应用程序名称后,可以使用` appName '属性查看它。

spark_context.appName

Spark 为每个会话创建一个惟一的应用程序 id。可以使用` applicationId '属性来检索 id。

spark_context.applicationId

Spark 通过并行性在每个 Spark 会话中分配任务。您可以手动设置或使用默认选项。

可以使用`默认并行度'属性查看默认设置。

spark_context.defaultParallelism

您可以在 Spark 上下文的配置阶段设置默认并行度。这是通过使用`spark . default . parallelism参数来完成的。

spark_context.setConf(”spark.default.parallelism”, “50”)

此外,Spark 允许为作业分配不同数量的分区。可以通过在“spark.default.partitions”配置参数中添加数字来设置所需的分区数量。在下面的例子中,“50”是确定分区的数量。

spark_context.setConf(“spark.default.partitions”, “50”)

若要打印 RDD 的最小分区数的默认设置,请使用“defaultMinPartitions”属性。

spark_context.defaultMinPartitions

RDD 行动

在 Spark 中,RDD 操作由*变换*和动作组成。*转换*是可以通过使用旧的 RDD 创建一个不存在的操作。

火花变换

在激活的 Spark 会话中,有几种 Spark 转换可用。在这一节,我们来介绍最常见的。

地图

Map ”方法返回一个新的分布式数据集,该数据集是通过函数传递每个元素而得到的。在下面的示例中,“ collect ”操作负责检索现有 RDD 中的所有项目。

items = spark_context.parallelize ([4,13,13,28,36,47,56])
mapped_list = items.map(lambda x: x+2).collect()print (“Printing mapped items for map operation of RDD: “, (mapped_list))

平面地图

flatMap 方法通过对 RDD 的每个项目执行计算,然后执行拼合操作来进行操作。

items = spark_context.parallelize ([2,4,13])items.flatMap(lambda x: range(1, x)).collect()

地图分区

在` mapPartitions 的帮助下,一个方法可以应用到指定 RDD 的每个分区。

partitioned = spark_context.parallelize ([4,13,13,28,36,47,56], 2)def mapPartitionFunc(ind): yield sum(ind)
partitioned.mapPartitions(mapPartitionFunc).collect()

MapPartitionsByIndex

“mapPartitionsWithIndex”方法通过不丢失核心分区的索引,使函数能够在 RDD 的每个分区上执行。

partitioned = spark_context.parallelize ([4,13,13,28,36,47,56], 4)def mapPartitionByIndexFunc(indSlicer, ind): yield indSlicer
partitioned.mapPartitionsWithIndex(mapPartitionByIndexFunc).sum()

过滤器

filter 方法在选择在特定条件下返回“ true ”的项目后,返回一个新的数据集。

items = spark_context.parallelize ([4,13,13,28,36,47,56])filtered_list = items.filter(lambda x: x % 2 == 0).collect()print (“Printing filtered list items for filter operation of RDD: “, (filtered_list))

样品

采样可用于数据处理的任何阶段。对于 RDD 数据集,可以通过在“样本”函数中指定一个百分比值来进行采样。当请求相同的子集时,可以将种子 id 添加到方法中。

sampling_items = spark_context.parallelize(range(20), 4)
sampling_items.sample(True, 0.3, 1234).collect()

加入

可以使用“连接”方法将 RDD 数据集连接到一对匹配的键上。

list1 = spark_context.parallelize([(“k”, 98), (“m”, 65)])
list2 = spark_context.parallelize([(“k”, 120), (“k”, 43)])
sorted(list1.join(list2).collect())

工会

`联合'操作有助于联合指定的 rdd。它一个接一个地添加。此操作不会搜索它们之间的匹配密钥。

union_items = spark_context.parallelize(range(5), 2)
union_items.union(union_items).collect()

路口

交集”方法负责在 RDD 数据集中查找元素的交集。

group1 = spark_context.parallelize([2, 10, 17, 3, 14, 5])
group2 = spark_context.parallelize([2, 8, 5, 34, 42, 14])group1.intersection(group2).collect()

截然不同的

` distinct '函数用于从 RDD 中获取一组唯一的元素。

items = spark_context.parallelize ([4, 13, 13, 28, 36, 47, 56])unique_element_list = items.distinct().collect()print (“Printing distinct items for distinct operation of RDD: “, (unique_element_list))

GroupByKey

使用“ groupByKey ”函数需要将每个键的元素分组在一行中。在此操作之后,RDD 的输出将具有哈希分区。

groupedKeys = spark_context.parallelize([(“first_num”, 300),(“second_num”, 500), (“third_num”, 900)])print(sorted(groupedKeys.groupByKey().mapValues(len).collect()))print(sorted(groupedKeys.groupByKey().mapValues(list).collect()))

减速键

reduceByKey ”方法对 RDD 元素的值执行合并操作。

from operator import subreducedKeys = spark_context.parallelize([(“first_num”, 300),(“second_num”, 500),(“third_num”, 900),(“second_num”, 500)])print(sorted(reducedKeys.reduceByKey(sub).collect()))

AggregateByKey

在公共键的结构中需要两个独立的 rdd 来执行聚合操作。首先,实现了每个项目的聚合。在此步骤之后,操作应用于输出。

item_group1 = spark_context.parallelize([(‘first’,5),(‘first’,3),(‘second’,3)])item_group2 = spark_context.parallelize(range(20))firstGroup = (lambda x,y: (x[0]+y,x[1]+1))aggregatedGroup = (lambda x,y:(x[0]+y[0],x[1]+y[1]))print(item_group2.aggregate((0,0),firstGroup,aggregatedGroup))print(item_group1.aggregateByKey((0,0),firstGroup,aggregatedGroup))

排序键

*sortByKey*方法负责以升序方式对元素对进行排序。

item_list = [(‘first’, 7), (‘second’, 9),(‘third’, 11), (‘fourth’, 34), (‘fifth’, 58)]spark_context.parallelize(item_list).sortByKey().first()

火花动作

现在让我们来看看一些 Spark 操作。

收藏

` collect '函数将数据集的所有元素作为数组返回。

items = spark_context.parallelize ([4,13,13,28,36,47,56])number_list = items.collect()print (“Printing elements for collect: %s” % (number_list))

第一部

“first”方法用于从 RDD 中获取第一项。

items = spark_context.parallelize ([4,13,13,28,36,47,56])first_element = items.first()print (“Printing first element with first operation of RDD: %s” % (first_element))

“take(n)”方法返回数据集的前 n 个元素。

items = spark_context.parallelize ([4,13,13,28,36,47,56])take_element = items.take(3)print (“Printing specified number of elements with take operation of RDD: %s” % (take_element))

取样品

*takeSample*方法返回指定长度的 RDD。在该方法中,第一个参数是“替换为的*”。它指示是否需要用旧结果替换新结果。如果是,则设置为*真*,否则设置为`。*

第二个参数是要采样的数字。第三个参数是“种子”数。当设置为任意数字时,它是该特定样本的标识符 ID。每当您在当前 Spark 会话中使用相同的 ID 运行这个采样函数时,它都会返回相同的样本子集。

items = spark_context.parallelize ([5,13,13,28,36,47,56])
items.takeSample(True, 5, 1)

已订购

“已订购”功能以升序方式从 RDD 中取出确定数量的商品。

items = spark_context.parallelize ([44,131,836,147,56]).takeOrdered(6)print (items)

计数

“计数”函数返回元素的数量,而不考虑在 RDD 中找到的重复记录或非重复记录。

element_count = items.count()print (“Printing number of instances for count operation of RDD: %i” % (element_count))

计数键

countByKey ”功能与“ count ”功能的不同之处在于通过相应的键对项目进行计数。

countKey = spark_context.parallelize([(“first_num”, 300), (“second_num”, 500), (“third_num”, 900), (“second_num”, 500), ])sorted(countKey.countByKey().items())

保存文本文件

借助*saveasTextFile*功能,可以将 RDD 数据集保存为文本格式。

items = spark_context.parallelize ([4,13,13,28,36,47,56])saved_list = items.saveAsTextFile(“items.txt”)

RDD 的坚持

Spark 的主要优势是能够跨分区将数据集保存在内存中。持久性是通过缓存实现的。分区在内存中进行处理,以便将 RDD 存储在缓存中。之后,它们可以在该数据集的不同操作中重用。这使得未来的行动要快得多。

RDD 可以第一次在活动中注册。之后,它将被分区保存在内存中。但是,这些 RDD 分区有丢失的风险。Spark 可以重新计算最初所做的更改。

通过缓存 rdd,用户可以继续将数据集保存在硬盘上,并在其他作业中重用它。有些 rdd 可以多次使用。在这些 rdd 上使用“持久”操作可能是有利的。

使用“持久”方法的存储级别,当选择“内存和磁盘”时,RDD 分区将仅缓存到内存和磁盘一次。

item_list = spark_context.parallelize([(‘first’,5), (‘first’,3), (‘second’,3)])item_list.persist(pyspark.StorageLevel.MEMORY_AND_DISK )item_list.getStorageLevel()print(item_list.getStorageLevel())

另一方面,当选择“内存和磁盘 2”时,RDD 分区将在内存和磁盘上有两个副本。

item_list = spark_context.parallelize([(‘first’,5), (‘first’,3), (‘second’,3)])item_list.persist(pyspark.StorageLevel.MEMORY_AND_DISK_2 )item_list.getStorageLevel()print(item_list.getStorageLevel())

使用 PySpark 创建 Spark 会话

运行 PySpark 函数需要 Spark 会话。首先,必须导入所需的库。

from pyspark.sql import SparkSession
from pyspark.context import SparkContext

加载相关库后,只需添加一个 *appName* '和一个 getOrCreate '函数,就可以启动 spark 会话。如果存在任何额外的配置要求,例如执行器的内存大小,则可以在 Spark 会话构建块中包含一个“config”参数。

spark = SparkSession.builder.\appName(“FirstSparkApplication”).\config (“spark.executor.memory”, “8g”).\getOrCreate()

通过读取不同的数据格式创建 Spark 数据帧

创建会话后,可以读取数据并将其作为数据帧加载到支持数据结构中。数据帧可以描述为基于列的表格格式的集合。

下面,使用相应的文件名函数读取不同格式的文件。

json_df = spark.read.json(“dataset.json”)text_df = spark.read.text(“dataset.txt”)csv_df = spark.read.csv(“dataset.csv”)parquet_df = spark.read.parquet(“dataset.parquet”)

Spark 中的机器学习

Spark 包含一个名为 MLlib 的独立库,支持几种机器学习算法。MLlib 增强的核心字段有:

  • 机器学习计算,
  • 特色化,
  • 生成管道结构,
  • 坚持

让我们讨论使用 Spark 实现机器学习模型的步骤。

数据准备

在整篇文章中,将使用一个非常著名的数据集“泰坦尼克号”。公共数据集可以从其 GitHub 页面下载。另外,你可以通过链接查看它的许可证。

作为第一步,我们将在 Spark 会话的帮助下读取数据集。

数据集有其格式,其基本要求是使用“ csv ”函数。它被指定为` spark.read.format() 中的参数。

training_dataset = spark.read.format(“csv”).\option(“inferSchema”, True). option(“header”, “true”).\load(‘dataset/titanic_train.csv’)test_dataset = spark.read.format(“csv”).\option(“inferSchema”, True).option(“header”, “true”).\load(‘dataset/titanic_test.csv’)

作为最初的分析步骤,让我们显示列名。这可以通过使用 PySpark 以三种不同的方式完成。

第一种方法是使用` show '方法,同时将您想要显示的行数作为参数进行传递。

training_dataset.show(5)

图 1 .‘show(5)’功能的输出。归作者所有。

第二种方法是使用*show()*方法,不传递任何参数。该操作将输出 20 行。其默认格式包含截断的列内容。对于“Name”列,可以观察到截断的列,因为它超过了默认长度。

training_dataset.show()

图 2 .‘show()’函数的输出。归作者所有。

通过在“ show 方法中设置“ truncate = False ”可以查看完整的列内容。此外,可以通过在“ show() ”函数中添加“ vertical = True ”来更改默认的水平显示。

The full column content can be viewed by setting `truncate = False` in the `show` method. Also, the default horizontal display can be changed by adding `vertical = True` in the `show()` function.training_dataset.show(2, truncate=False, vertical=True)

图 3 . show(truncate = False,vertical=True)函数的输出。归作者所有

用 Spark 进行数据预处理

查看列名及其类型后,检查数据集是否包含任何“null”或“nan”值至关重要。我们必须在建模步骤之前填写它们。

让我们在下面显示空列和非空列。

from pyspark.sql.functions import *print (“NaN values\n”)training_dataset.select([count(when(isnan(item), item)).alias(item) for item in training_dataset.columns]).show(5)print (“Null values\n”)training_dataset.select([count(when(col(item).isNull(), item)).alias(item) for item in training_dataset.columns]).show(5)print (“Not Null values\n”)training_dataset.select([count(when(col(item).isNotNull(), item)).alias(item) for item in training_dataset.columns]).show(5)

**图 4。**填充和未填充值的输出。归作者所有

一些列名可以使用“ withColumnRenamed ”函数重命名。使用这种方法,只需用点分隔符逐个添加多个列,就可以对它们进行重命名。该函数的第一个参数是原始值,第二个参数是新的列名。

print(“Renaming Column Name”)training_dataset = training_dataset.\withColumnRenamed(“Pclass”,”PassengerClasses”).\withColumnRenamed(“Sex”,”Gender”)training_dataset

“group by”SQL 操作可以通过“count”操作应用于单个列。此外,可以在函数中为多个分组操作添加多个值。

也可以在“count()”函数的末尾添加“ sort() ”函数。通过观察输出中各等级的计数,我们可以看到三等舱男女乘客的“幸存”计数最高。

print(“Counting the number of Passenger per Classes”)training_dataset.groupBy(“PassengerClasses”).\count().\sort(“PassengerClasses”).show()print(“Counting the number of Survivals by Classes”)training_dataset.groupBy(“PassengerClasses”,“Gender”,“Survived”).count().sort(“PassengerClasses”,“Gender”,“Survived”).show()

图五。‘group by’操作的输出。归作者所有。

PySpark 的特征工程

在特征工程的帮助下,可以从数据集中的现有变量中提取更有见地的信息。

在 titanic 数据集中有一个“T32 姓名”列,其中也包括这个人的头衔。该信息可能对模型有益。所以我们把它生成为一个新变量。可以使用` withColumn '操作创建一个新的标题列。

training_dataset = training_dataset.withColumn(“Title”, regexp_extract(col(“Name”),”([A-Za-z]+)\.”, 1))training_dataset.select(“Name”,”Title”).show(10)

图 6。‘with column’标题提取操作的输出。归作者所有。

一个名为`标题'的新列被生成。按数量列出每个标题可以告诉我们,有些标题只出现过一次。

training_dataset.groupBy(“Title”).count().show()

图七。‘group by’操作的输出。归作者所有。

有一些不同格式的重复标题。有些是可以替换的。为此,可以使用“替换”功能。

feature_df = training_dataset.\replace([“Mme”, “Mlle”,”Ms”,“Major”,”Dr”, “Capt”,”Col”,”Rev”,“Lady”,”Dona”, “the Countess”,”Countess”, “Don”, “Sir”, “Jonkheer”,”Master”],[“Mrs”, “Miss”, “Miss”,“Ranked”,”Ranked”,”Ranked”,”Ranked”,”Ranked”,“Royalty”,”Royalty”,”Royalty”,”Royalty”,”Royalty”, “Royalty”, “Royalty”,”Royalty”])feature_df.groupBy(“Title”).count().sort(desc(“count”)).show()

图 8。“标题”列的“分组”操作的输出。归作者所有。

在替换操作之后,标题的分布似乎比以前更准确。

用 PySpark MLlib 构建机器学习模型

在模型实现阶段之前,应该检查变量的类型。由于预测算法需要数字格式的变量,字符串格式的列可能会导致错误。

PySpark 的*dtypes*函数可以用来打印变量的类型。

feature_df.dtypes

**图 9。**数据帧的“数据类型”操作的输出。归作者所有。

在打印变量类型后,可以观察到“性别”、“已装载”和“标题”列具有字符串格式。这些列需要转换成数字形式。

名为“StringIndexer”的专用 PySpark 函数将变量拟合并转换为数值类型。下面就来实现吧。

from pyspark.ml.feature import StringIndexerparchIndexer = StringIndexer(inputCol=”Parch”, outputCol=”Parch_Ind”).fit(df)sibspIndexer = StringIndexer(inputCol=”SibSp”, outputCol=”SibSp_Ind”).fit(df)passangerIndexer = StringIndexer(inputCol=”PassengerClasses”, outputCol=”PassengerClasses_Ind”).fit(df)survivedIndexer = StringIndexer(inputCol=”Survived”, outputCol=”Survived_Ind”).fit(df)

在索引和删除旧的字符串格式的操作之后,数据帧就有了所有的数字变量。因为所有的列都是非字符串格式,所以我们可以使用数据帧中的列生成一个特征向量。“VectorAssembler”可用于转换“特征”向量列。

from pyspark.ml.feature import VectorAssemblerassembler = VectorAssembler(inputCols = [“PassengerClasses”,”SibSp”,”Parch”],outputCol = “features”)The next step after creating the feature vector is to split the data into train and test sets. You can use the `randomSplit` function to achieve this.(train, test) = df.randomSplit([0.8, 0.2], seed = 345)

在应用预测算法之前,需要实现分类器和流水线生成阶段。

让我们一起来定义这些步骤。首先,让我们从 MLlib 库内置的 PySpark 函数中选择一个分类器。添加导入语句后,可以通过分配 *labelCol* 和features coll列来创建分类器。

from pyspark.ml.classification import DecisionTreeClassifierclassifier = DecisionTreeClassifier(labelCol=”Survived”, featuresCol=”features”)In this step, a pipeline is created by adding parameters to `stages` accordingly.from pyspark.ml import Pipelinepipeline = Pipeline(stages=[assembler, model_identifier])When the pipeline is established, parameters of the classifier can be optimized with the help of `ParamGridBuilder`.Appropriate parameters will be produced after the grid search.from pyspark.ml.tuning import ParamGridBuilderparamGrid = ParamGridBuilder() \.addGrid(model_identifier.maxDepth, [10,20]) \.addGrid(model_identifier.maxBins, [50, 100]) \.build()

为此,相应的*标签*、特征和`公制列被填充。

tvs = TrainValidationSplit(estimator=pipeline,estimatorParamMaps=paramGrid,evaluator=MulticlassClassificationEvaluator(labelCol=”Survived”,predictionCol=”prediction”, metricName=”weightedPrecision”),trainRatio=0.8)

在“trainivalidationsplit”阶段完成后,我们准备好装配模型。

model = tvs.fit(train)

模型评估

作为一种模型评估方法,可以应用度量“T28”精度。`精度的数学公式如下。

(true positive+true negative)/
(true positive+true negative+false positive+false negative)

使用下面的代码行,我们可以通过每个参数获得准确性度量。

list(zip(model.validationMetrics, model.getEstimatorParamMaps()))

服务于 Apache Spark 机器学习模型

使用 PySpark 生成的机器学习模型可以使用 MLflow 来服务。在下面的部分中,将解释 MLflow 包的安装。此外,模型服务方法将在概念描述的末尾添加一些示例脚本。

为 Spark 模型服务安装 MLflow

MLflow 可以用作 PySpark 模型的模型服务库。在 Spark 会话中使用 MLflow 需要安装库。对于 PySpark,可以使用以下命令安装该包。

pip install mlflow

安装 MLflow 后导入*spark*

from mlflow import spark

使用 MLflow 服务火花模型

导入 MLflow 后执行*start_run()*函数,在 Spark 会话中激活 MLflow。

import mlflowfrom mlflow import spark
with mlflow.start_run():mlflow.spark.log_model(model, “sparkML-model”)

执行*log_model* 操作后,将创建 MLflow、model 工件度量参数、以及标记`文件夹。

**图 10。**基于桌面的 mlflow 文件夹结构。归作者所有。

在“artifacts”文件夹中,您会找到 spark ML-model 文件夹。在“sparkML 模型”中,有“元数据”和“阶段”文件夹。“阶段”记录模型的生命周期。可以有单个阶段或多个阶段。另一方面,“元数据”代表描述和包含模型信息的数据集。

**图 11。**元数据和阶段文件夹结构。归作者所有。

**图十二。**spark ml 文件夹结构。归作者所有。

stages 文件夹包含“最佳模型”信息。

**图十三。**阶段文件夹路径。归作者所有。

在下面的中,您可以从保存在 sparkML-model 文件下的“MLmodel”文件的示例格式中找到一个片段。

**图 14。**ml model 输出。归作者所有。

可以使用“ mlflow.pyfunc ”模块生成推论。首先,模型和数据集路径是分开定义的。其次,使用模型路径定义火花 UDF。第三,读取数据集并将其注册到数据帧中。最后一步,在先前定义的 Spark UDF 的帮助下,通过选择所需的列,生成一个新列。

import mlflow.pyfuncfrom pyspark.sql import SQLContexttrain.toPandas().to_csv(‘dataset.csv’)model_path = ‘/Users/ersoyp/Documents/LAYER/ServingModelsWithApacheSpark/Scripts/mlruns/1/51ef199ab3b945e8a31b47cdfbf60912/artifacts/sparkML-model’titanic_path = ‘/Users/ersoyp/Documents/LAYER/ServingModelsWithApacheSpark/Scripts/dataset.csv’titanic_udf = mlflow.pyfunc.spark_udf(spark, model_path)df = spark.read.format(“csv”).option(“inferSchema”, True).option(“header”, “true”).option(‘delimiter’, ‘;’).load(titanic_path)columns = [‘PassengerClasses’, ‘SibSp’, ‘Parch’]df.withColumn(‘Inferences’, titanic_udf(*columns)).show(False)

**图十五。**ml flow 输出。归作者所有。

元数据存储和图层实验跟踪

为了最终确定一个理想的模型,您需要反复改变各种模型参数或数据准备方法,以达到最佳解决方案。在每次迭代中,保持对参数和过程的跟踪是至关重要的。此外,您可以在每个阶段尝试不同的设置。不遵循这些指令可能会导致重复这些指令,从而浪费时间和计算资源。

实验跟踪可以定义为跟踪所有这些数据的技术。

一个元数据存储库——一个可以跟踪和保留上述所有信息的工具——对于成功的实验跟踪是必要的。创建机器学习模型时产生的数据保存在元数据存储中。通过存储实验元数据,ML 实验的可比性和可重复性成为可能。

与现有的元数据存储相比,层还支持无缝的本地和远程开发交互。例如,在使用本地资源进行一些快速试验后,您可以利用利用层基础设施的更有效的计算资源来训练模型。无论是利用本地模式还是远程模式、图层版本、元数据和日志。

使用 layer.log()、@dataset 和@model decorators,您可以随着项目的进展跟踪您的发现、数据集和模型。您的实体由层自动版本化,以便您可以准确地重复实验并查看其进展。

有了数据集、ML 模型、元数据和文档的通用存储库,您可以缩小协作差距并简化新员工入职流程。记录参数、图表、指标等。快速识别 ML 实体;制作项目文件;毫不费力地转移控制权。

不稳定的生产管道是不好的。作为对生产管道的健全性检查,层自动对数据集和模型进行版本化。

复杂的任务受到缺乏计算能力的限制。您可以使用 Layer 的云资源,在强大的预定义 GPU 和 CPU 上训练您的模型。Layer SDK 处理基础设施的所有难题和复杂性。如果你不需要电,你可以使用你自己的资源。

Layer 提供的一些 Python 装饰器产生了一个健壮的模型和数据注册中心。它提供了一个中心位置来管理与创建机器学习模型相关的所有数据。

为了帮助您快速入门,图层社区网站提供了各种示例项目和数据集。GitHub 库也有更多的例子。您可以通过访问 layer.ai 网站开始构建实验追踪和元数据存储包。

不稳定的生产管道以不希望的方式运行。作为对生产管道的健全性检查,层自动对数据集和模型进行版本化。

复杂的任务受到缺乏计算能力的限制。您可以使用 Layer 的云资源,在强大的预定义 GPU 和 CPU 上训练您的模型。Layer SDK 处理基础设施的所有难题和复杂性。如果你不需要电,你可以使用你自己的资源。

Layer 提供的一些 Python 装饰器产生了一个健壮的模型和数据注册中心。它提供了一个中心位置来管理与创建机器学习模型相关的所有数据。

为了帮助您快速入门,图层社区网站提供了各种示例项目和数据集。GitHub 库也有更多的例子。您可以通过访问 layer.ai 网站开始构建实验追踪和元数据存储包。

最后的想法

在整篇文章中,在最初描述概念和用示例脚本实现解决方案的结构中出现了广泛的主题。主题包括介绍 Spark,然后在 Spark 中构建机器学习模型。主题包括但不限于:

  • 火花的概念
  • Spark 组件及其独特的架构
  • Spark 和 Python 的装置
  • RDD 及其操作要点
  • 通过它们不同的功能激发转变和作用
  • 火花会话生成和数据帧
  • 使用 Spark 进行探索性数据分析
  • PySpark 中的机器学习
  • 使用 PySpark 的数据准备、预处理和特征工程
  • PySpark 中的模型构建阶段
  • 使用 Apache Spark 的模型服务
  • 使用 Layer SDK 进行元数据存储和实验跟踪

资源

  • Spark 胜 Daytona Gray Sort 100TB 基准
  • 在 Colab 运行 py spark
  • 层艾博客
  • Jupyter 笔记本,适用于 RDD 基础和 ML 型号,配有 PySpark
  • Jupyter 笔记本,适用于 RDD 基础和 ML 模型,配有 Colab

使用 NVIDIA Triton 推理服务器为 TensorRT 模型提供服务

原文:https://towardsdatascience.com/serving-tensorrt-models-with-nvidia-triton-inference-server-5b68cc141d19

通过对高客户端-服务器流量的模型推断实现最佳吞吐量和延迟

图片由弗洛里安·克拉姆在 Unsplash 上拍摄

在实时 AI 模型整体部署中,模型推理和硬件/GPU 使用的效率至关重要。单个客户机-服务器推理请求的速度取决于服务器的延迟和吞吐量。这是因为深度学习模型通常安装在从公共客户端设备接收多个传入请求或数据的服务器或服务器集群上。让我在这里描述一些定义:

延迟:通过客户端-服务器连接的单个请求-响应循环所花费的时间。假设稳定的互联网连接,延迟将取决于模型推断的速度、数据包的传输和一些其他因素。

吞吐量:服务器在单个时间实例中可以处理的传入请求的数量。当传入流量超过吞吐量时,多余的请求会被排队,从而减慢请求-响应过程。

在我的上一篇文章中,我们已经讨论了在 edge (一个独立的 GPU Linux 设备)上用 TensorRT 设置和运行模型推理**。正如我们所见,这非常简单:**

https://medium.com/mlearning-ai/running-tensorflow-model-on-edge-with-tensorrt-for-fast-inference-4dcad300a523

另一方面,在本文中,我们将讨论在单个服务器(一个将通过网络接收来自其他设备的请求的 GPU 工作站)上使用 tensort 设置和运行模型推理**,即 NVIDIA Triton 推理服务器 **

在 Triton 服务器上运行深度学习模型有几个优点,据报道,它优于其他框架,如 TFServing 和 TorchServe。例如,它能够通过动态批量推理和多个请求的模型推理中的并发性来优化吞吐量。结合使用 TensorRT 来优化延迟,Triton server 可以同时提供极快的推理速度。

关于 Triton server 性能的更多信息可以在以下文章中找到:

https://developer.nvidia.com/blog/nvidia-serves-deep-learning-inference/

先决条件

  • 配备 NVIDIA GPU 的本地工作站/笔记本电脑
  • Docker 容器和 Linux 终端的基础知识
  • Python 基础和深度学习库的知识

事不宜迟,让我们开始吧!

1.张量流模型的一个例子

在我们在 Triton 服务器上测试的深度学习模型示例中,我们选择了一个经典的 CNN 模型——resnet 50——在 ImageNet 数据集上进行了预训练,如下面的代码片段所示。接下来,我们将这个 Tensorflow 模型优化为 TensorRT 模型。

2.转换到 ONNX 模型

虽然有不同的 tensort 框架,如 tensor flow-tensort 和 ONNX tensort,但 NVIDIA Triton server 采用的框架只有 ONNX tensort。因此,我们需要首先将任何 Keras 或 Tensorflow 模型转换为 ONNX 格式,如下面的代码片段所示。首先,您可能希望将model.onnx模型保存在以下目录中:

${PWD}/models/tensorrt_fp16_model/1/model.onnx

3.使用 Docker 容器转换到 TensorRT 模型

接下来,我们要将 ONNX 型号model.onnx转换为 TensorRT 型号model.plan。如果您在本地安装了 TensorRT,您可能会尝试进行本地转换。然而,这是有问题的,因为 Triton 服务器容器中的 TensorRT 和 CUDA 软件——我们将在后面看到——在运行model.plan文件时可能表现不同。即使本地 tensort 的版本与 Triton TensorRT 的版本相似,也是如此。

幸运的是,NVIDIA 为 TensorRT 提供了 Docker 映像,其版本标签与 Triton server 的版本标签互补。假设您在本地安装了 Docker,在终端上运行:

docker pull nvcr.io/nvidia/tensorrt:22.11-py3

一旦提取了 Docker 映像,我们将在运行容器时进行卷绑定挂载。请注意,卷绑定装载的参数必须是绝对路径。

docker run -it --gpus all --rm -v ${PWD}/models/tensorrt_fp16_model/1:/trt_optimize nvcr.io/nvidia/tensorrt:22.11-py3

这将在容器中启动一个终端,随后我们在容器中进行 TensorRT 转换以创建model.plan,由于绑定挂载,它也将在本地可用。

# cd /trt_optimize
# /workspace/tensorrt/bin/trtexec --onnx=model.onnx --saveEngine=model.plan  --explicitBatch --inputIOFormats=fp16:chw --outputIOFormats=fp16:chw --fp16

4.设置本地目录以镜像 Triton 服务器

Triton 服务器软件同样是一个 Docker 映像,我们将下载该映像,之后我们还将进行卷绑定挂载。然而,在我们进行 Docker 拉取之前,我们会想要坚持并在本地初始化某个目录结构以及一个必要的config.pbtxt模型配置文件。

目录结构应该如下所示:

${PWD}/models||-- tensorrt_fp16_model|          ||          |-- config.pbtxt|          |-- 1|          |   ||          |   |--model.plan

我们用例的config.pbtxt文件示例如下:

name: "tensorrt_fp16_model"
platform: "tensorrt_plan"
max_batch_size: 32input [ {name: "input_1"data_type: TYPE_FP16dims: [ 224, 224, 3 ]}
]output [{name: "predictions"data_type: TYPE_FP16dims: [ 1000 ]}
]

5.设置 Triton 服务器容器

在确保 Triton 服务器的 Docker 镜像版本标签与 TensorRT 的相似之后,我们就可以开始下载了:

docker pull nvcr.io/nvidia/tritonserver:22.11-py3

然后以附加模式运行 Docker 容器:

docker run --gpus=all --rm  --name triton_server -p 8000:8000 -p 8001:8001 -p 8002:8002 -v ${PWD}/models:/models nvcr.io/nvidia/tritonserver:22.11-py3 tritonserver --model-repository=/models --model-control-mode=poll --repository-poll-secs 30

如果 Triton 服务器容器设置正确并准备好进行推理,您应该在终端中看到以下输出,并且“状态”中没有任何错误消息:

6.来自客户端设备的推断

在这里,我将演示在客户机工作站上通过 Triton 服务器运行推理的示例代码。当然,我们还需要在客户端工作站上安装tritonclient库,包括:

pip install tritonclient[all]

7.Triton TensorRT 比本地 tensort 慢

在我们结束本文之前,我必须提到的一个警告是,由于优化的 GPU 使用和批量推断等优势,Triton server 在处理大量客户端-服务器流量时确实表现出色。

然而,当我们考虑在 Triton TensorRT 和 local TensorRT 之间运行单个本地推理时,local TensorRT 仍然具有更快的推理速度,因为 Triton TensorRT 在网络上运行推理时具有额外的开销。在下面的线程中可以看到一些参数:

https://github.com/triton-inference-server/server/issues/4812

8.结论

感谢阅读这篇文章!部署具有可扩展性的人工智能模型是任何有抱负的人工智能工程师或机器学习工程师的一项重要技能,了解 NVIDIA Triton 服务器无疑会在竞争激烈的数据科学领域中占据优势。否则,强大而精确的模型只能在 Jupyter 笔记本和 VS 代码脚本后面枯萎。

在我的 GitHub 库上查看这篇文章的代码。

此外,感谢你和我一起学习人工智能和数据科学。如果你喜欢这些内容,可以在媒体上阅读我的其他文章,并在 LinkedIn 上关注我。

此外,如果你想知道如何快速深入地学习数据科学和人工智能,请查看我在《学习》中的一篇顶级文章:

支持我! 如果你没有订阅 Medium,但喜欢我的内容,请考虑通过我的推荐链接加入 Medium 来支持我。

https://tanpengshi.medium.com/membership

在闪亮的应用程序中提供变压器模型

原文:https://towardsdatascience.com/serving-transformer-models-in-shiny-apps-9a1bed4b41a6

“一个穿着蛇皮衣服的闪亮变形机器人”——用稳定扩散文本到图像模型生成——https://huggingface.co/spaces/stabilityai/stable-diffusion

结合 R 和 Python 的精华来创建令人敬畏的 NLP 产品的分步指南

很长一段时间以来,R 一直是我处理大多数数据科学相关任务的首选工具。我特别喜欢我可以快速流畅地轻松完成工作。特别是,tidyverse 的出现真正改变了数据争论、探索性分析和数据可视化的游戏规则。此外,Shiny——一个用于构建多功能且漂亮的 web 应用程序的框架——变得越来越流行。

然而,当涉及到机器和深度学习时,Python 似乎比 Sci-kit Learn、PyTorch 和 Tensorflow/Keras 等 ML/DL 框架领先几步。因此,我发现自己越来越多地使用(并且喜欢)Python。

对我来说,令人沮丧的部分是我经常想在闪亮的应用程序中部署和展示计算机视觉和 NLP 模型。尽管 Shiny 最近才可以用于 Python,但 Shiny for Python 目前仍处于非常早期的开发阶段。Python 用户确实可以使用类似的工具,例如 Streamlit 和 Gradio 非常适合展示 ML 模型,但我发现它们与 Shiny 相比有些局限性——特别是在创建自定义用户界面时。当然,我需要探索 Python 的更多选项,但是我真的喜欢开发闪亮的应用程序。

因此,我开始学习如何做到以下几点:

  1. 使用 R 的 reticulate 包在闪亮的 app 中使用 Python 代码。
  2. 实现预训练的转换器模型来处理用户输入。
  3. 将包含 R 和 Python 功能的应用程序容器化,并为 transformer 模型提供服务。

在本文中,我们将通过所有三个步骤来了解它是如何完成的。

第 1 部分:启动并运行 reticulate:一个非常简单的例子

我必须承认,开始使用 reticulate 并弥合 R 和 Python 之间的差距有些棘手,需要一些尝试、错误和毅力。好消息是,现在你可能不需要这么做了。在这里,我将展示一种在 R 和 Shiny 中使用 python 代码的方法。

第一步:准备好

首先,确保你已经安装了所有需要的包,包括 shiny 和 reticulate,并开始一个新的 Shiny 应用程序项目。

接下来,我们需要设置一个 Python 环境。有不同的方法可以做到这一点,例如根据 reticulate 文档使用 virtualenv。这里,我们将使用 conda 从一个 YAML 文件中设置我们的环境,在该文件中我们指定了所有必要的依赖项。在项目的主目录中创建一个名为 environment.yml 的新文件,包含以下内容:

name: my_env
channels:- conda-forge- defaults
dependencies:- python=3.8- pip- pip:- numpy

如您所见,我们已经指定环境应该被称为 my_env,其中 Python v. 3.8 将与 pip 一起安装,pip 是一个安装程序,它反过来获取 numpy 包,我们将需要它来创建一个简单的函数。

然后,我们可以通过在 ourRStudio 会话中打开一个终端并运行以下命令来创建环境:

conda env create -f environment.yml

您可以使用命令conda env list检查环境是否已经创建。要激活环境,请运行以下命令:

conda activate my_env

现在,为了让 reticulate 找到我们刚刚安装的 Python 版本,复制并保存命令which python的输出以备后用。它应该以类似于“../miniconda 3/envs/my _ env/bin/python "。

步骤 2:用 reticulate 和 Python 连接 Shiny

如果您已经将项目初始化为一个闪亮的 web 应用程序,您应该已经有一个名为 app.r 的文件。对于这个最小的示例,我们将保持它的简单性,并修改已经为我们制作的应用程序。在该脚本的顶部,插入以下几行:

library(shiny)
library(reticulate)Sys.setenv(RETICULATE_PYTHON="python-path-in-my_env")
reticulate::use_condaenv("my_env")

您也可以在一个名为。请改用 Rprofile。

步骤 3:创建和实现 Python 函数

现在,我们可以创建一个简单的 Python 函数,我们将在 app.r 的服务器代码中使用该函数。首先创建一个脚本,您可以使用以下代码行调用 python_functions.py:

import numpy as npdef make_bins(x, length):low = min(x)high = max(x)length = int(length) return np.linspace(low,high,length).tolist()

这个函数找到一个向量的最小值和最大值,并使用 Numpy 的linspace()函数返回一个从最低到最高的等距数字列表。列表的长度等于length,将由应用程序的用户交互设置。定义好函数后,我们可以继续前进到 app.r 并修改脚本以使用我们的 python 函数。

在上一步中我们在 app.r 中插入的两行代码的正下方,我们添加了以下代码行:

reticulate::py_run_file("python_functions.py")

这一行使我们的make_bins()功能在我们启动一个闪亮的会话时可用。现在,删除或注释掉服务器代码中的以下行:

bins <- seq(min(x), max(x), length.out = input$bins + 1)

然后,我们用以下内容替换该行:

bins <- py$make_bins(x, input$bins + 1)

注意py$部分,它表示该函数是 python 函数。我们终于可以运行应用程序,并希望看到它的工作!

第 2 部分:使用变压器!

因此,现在我们将尝试实现一个 transformer 模型来确定给定的输入文本是正面的还是负面的。我们将使用的模型叫做蒸馏-基础-无壳-情感,你可以在 huggingface 网站上了解更多关于的信息。如果您还没有这样做,我鼓励您探索这个站点、可用的模型以及支持的 NLP 和计算机视觉任务。

步骤 1:更新 conda 环境

我们首先需要通过以下方式将软件包 torch 和 transformers 添加到我们的 environment.yml 文件中:

name: my_env
channels:- conda-forge- defaults
dependencies:- python=3.8- pip- pip:- torch- transformers

然后,我们可以使用以下命令更新环境:

conda deactivate;
conda env update -f environment.yml --prune

—-prune标志确保在更新环境时删除不必要的包。

步骤 2:更新 python_functions.py

安装了 torch 和 transformers 之后,我们就可以编写新的 Python 函数来使用这个模型了。

import torch
from transformers import pipeline
import numpy as npdef get_model():model = pipeline("text-classification", model='bhadresh-savani/distilbert-base-uncased-emotion', top_k=-1)return modeldef get_predictions(input_text, classifier):predictions = classifier(input_text)return predictions

第一次运行get_model()时,模型被下载,这可能需要一两分钟。这是一个好主意,在一个闪亮的会话之外运行get_predictions()来了解输出是什么样子的。

步骤 3:创建一个公开模型的基本应用程序

现在,我们终于可以构建一个利用该模型的应用程序了。我在下面提供了一个简单的工作脚本,如果您已经完成了前面的步骤,您可以尝试一下。

作者图片

你会注意到我们在第 10 行用model <- py$get_model()加载了情感分类模型。

然后,在第 31–33 行,我们将模型应用于用户提供的一些输入文本,并将输出转换为数据框,这使得绘图更加容易。

predictions <- py$get_predictions(input$text)df <- map_df(predictions[[1]], unlist)

将 Python 函数的输出转换成 R 可以处理的数据类型有时会很棘手。如果你在自己的项目中遇到麻烦,你可能会发现网格式文档很有用(参见“类型转换”)。

下面你可以看到应用程序会是什么样子。

作者图片

第 3 部分:用 Docker 封装应用程序

Docker 和容器技术提供了一种运行代码和应用程序并完全控制环境的好方法。我们首先需要创建一个 docker 文件,这通常会非常困难和耗时。在这里,我将展示一个将 Python、R、Shiny 和 transformer 模型组合在一个 Docker 图像中的解决方案。它可能不是最有效的,并且一些依赖项和命令可能是多余的。因此,您可以通过修改 docker 文件来指定如何构建图像,从而减少构建图像所需的时间以及图像的大小。

步骤 1:编写 Dockerfile 文件

Dockerfile 文件的第一行表示基本图像。默认情况下,使用最新版本。通常,在将应用程序投入生产时,选择特定的版本是明智的。接下来的几行安装了一些依赖项,包括 r。

FROM continuumio/miniconda3RUN apt-get update -y; apt-get upgrade -y; \apt-get install -y vim-tiny vim-athena ssh r-base-core \build-essential gcc gfortran g++

通常,我更喜欢使用 Rocker 项目创建的 Docker 映像,这使得编写 Docker 文件来封装闪亮的应用程序和其他基于 R 的应用程序变得非常容易。然而,当我将 Python 添加到组合中时,我遇到了一些问题,并决定尝试一种不同的方式。

接下来,像以前一样安装并激活我们的环境。我必须承认,我还不完全确定下面有多少环境变量是绝对必要的。

COPY environment.yml environment.yml
RUN conda env create -f environment.ymlRUN echo "conda activate my_env" >> ~/.bashrcENV CONDA_EXE /opt/conda/bin/conda
ENV CONDA_PREFIX /opt/conda/envs/my_env
ENV CONDA_PYTHON_EXE /opt/conda/bin/python
ENV CONDA_PROMPT_MODIFIER (my_env)
ENV CONDA_DEFAULT_ENV my_env
ENV PATH /opt/conda/envs/my_env/bin:/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

然后,我们用下面一行下载我们的模型:

RUN python -c "from transformers import pipeline; pipeline('text-classification', model='bhadresh-savani/distilbert-base-uncased-emotion')"

与运行时相反,在构建时这样做很重要。如果我们在运行时这样做,每个会话都将从下载模型开始!

安装 R 包有不同的方法。这种方式非常简单。

RUN R -e "install.packages(c('dplyr','purrr','ggplot2','shiny','reticulate'), repos = '[http://cran.us.r-project.org'](http://cran.us.r-project.org'))"

请注意,这实际上是一行。您还可以看到我们正在安装 dplyr、purrr 和 ggplot2,它们是我们实际需要的 tidyverse 包。因此,我们需要加载这些特定的包并从 app.r 中删除library(tidyverse)

出于某种原因,我无法在此时安装整个 tidyverse。此外,这样做将花费相当长的时间,并导致图像比必要的要大。

最后,我们将项目文件夹中的所有内容复制到映像的工作目录,授予写/读/写权限,公开一个端口,并指定实际运行应用程序的最终命令。

COPY . ./RUN chmod ugo+rwx ./EXPOSE 3838CMD ["R", "-e", "shiny::runApp('/', host = '0.0.0.0', port = 3838)"]

下面你可以看到整个 Dockerfile 文件。

作者图片

步骤 2:构建图像

如果我们简单地将我们的 Dockerfile 称为“Dockerfile”,默认情况下,当我们运行以下命令时,Docker 将查找这个文件:

docker build -t mysimpleapp .

t 代表“tag ”,我们将此图像标记为“mysimpleapp”。末尾的点表示构建上下文是当前目录。

如果由于磁盘空间限制而遇到麻烦,您可以在 Docker 设置中增加允许的磁盘空间,或者,如果您有不需要的大型悬空图像,您可以运行docker system prunedocker system prune -a。请注意,后一个命令将删除所有未使用的图像!

最后,让我们的手指交叉,我们可以尝试运行我们的应用程序!

docker run -it -p 3838:3838 mysimpleapp

-it 标志意味着我们希望以交互模式运行,这样我们就可以在启动时看到容器“内部”发生了什么。这可能有助于防止意外出错。

在您的控制台中,您应该会看到 R 启动,然后是“监听 http://0.0.0.0:3838 ”。将您的浏览器指向此地址,并检查应用程序是否正常工作。

我在这里部署了一个稍微高级一点的应用。这款我称之为 Wine Finder 的应用程序使用了一个名为 all-MiniLM-L6-v2 的语义搜索模型,让用户通过输入描述他们正在寻找的葡萄酒品质的查询来搜索他们可能喜欢的葡萄酒。例如,一个查询可能被表述为*“浓郁的红色浆果味道”*。该应用程序包括大约 130,000 种葡萄酒的描述,然后根据与查询的相关性进行排名。数据集在这里可用。下面你可以看到这个应用程序的样子。

作者图片

加载可能会有点慢,因为我已经允许该服务在不使用时基本关闭。这导致了“冷启动”,这比让服务持续运行要便宜得多。

摘要

我们已经看到了如何在闪亮的应用程序中实现 python 函数和 transformer 模型,以及如何将它们包装在 docker 映像中,准备作为 web 服务进行部署。使用 AWS 和 Microsoft Azure 等云提供商将 docker 图像部署为 web 应用程序相对容易。但是,对于个人项目,我认为谷歌云是目前最便宜的选择。如果你想在 Google Cloud 上部署一个闪亮的应用,请务必查看我的使用 Google Cloud Run 部署闪亮应用的分步指南。无论您使用这些提供程序中的哪一个,过程都大致相同。您需要有一个帐户,将您的 docker 映像推送到容器注册表,然后使用该映像建立一个 web 服务。

我们还没有介绍在 Shinyapp.io 上直接运行 python 代码的闪亮应用程序的部署。该过程与本教程中的描述略有不同。请注意,如果您计划在应用程序中公开 transformer 模型,shinyapps.io 可能不是一个可行的选项,至少如果您在免费层上,就不是。但是,如果您不需要应用程序实际包含大型 transformer 模型和/或大量数据,您可以考虑简单地为给定模型调用 Huggingface 推断 API。

基于会话的 Word2Vec 推荐系统

原文:https://towardsdatascience.com/session-based-recommender-systems-with-word2vec-666afb775509

如何用 Python 在浏览器会话数据上用 Word2Vec 训练一个基本的推荐系统?

图片来自 Unsplash 。

如果你熟悉 Word2Vec 算法,那么很可能是因为你在自然语言处理 (NLP)领域的某个地方偶然发现了它。自 2013 年首次发表以来,T. Mikolov 等人的论文越来越受欢迎,并在各种 NLP 应用中展示了最先进的结果。从那以后,出现了各种更新的、性能更好的模型——但是,当使用 NLP 或在信息检索(IR)领域工作时,Word2Vec 是不可避免的。

除了它在 NLP 中的经典应用之外,我们还可以将底层的 Word2Vec 算法用于其他应用,比如某些类型的推荐系统问题。

在本文中,我们将了解如何利用 Word2Vec 的 CBOW 算法为基于会话的数据构建一个简单的推荐系统。

首先,我们将讨论使用 Word2Vec 算法解决此类问题背后的动机是什么,其次**,我们将看看如何在实践中使用 Python 3 实现这一点。**

1 |为什么要用 Word2Vec?

对于本文,我假设您非常熟悉 Word2Vec 模型及其底层架构(CBOW 和 SkipGram)的工作方式。如果你不熟悉这些,我强烈推荐你看看这篇文章,它很好地解释了这些概念。

我们将在本文中重点介绍的特定类型的推荐系统是所谓的基于会话的。在这种情况下,我们希望根据匿名用户当前的浏览器会话,向他们提供下次点击推荐。什么意思?

例如,让我们考虑一个销售不同类别的各种产品的电子商务网站。有一天,用户可能会来到我们的网站,浏览我们的产品目录。我们的目标显然是让用户将产品添加到购物车中,并最终购买它。在推荐系统的帮助下,我们的目标是向用户推荐“相关”的产品。这增强了用户的购物体验,但也增加了购买的可能性。

然而,如果我们的用户对我们来说是匿名的,我们没有关于他们的任何历史数据,例如关于他们以前的购买或关于他们以前的浏览器会话。这使得给出“相关建议”变得越来越复杂。

这就是 Word2Vec 发挥作用的地方。

总结一下:Word2Vec 是一个模型,当训练有素时,它能够根据上下文捕捉单词的含义。

现在考虑我们上面的例子,我们可能有以下匿名用户的历史会话数据:

session_1 = [1, 2, 5]

在当前会话中,用户查看了产品编号 1、2 和 5。如果我们有足够多的这种类型的会话数据,我们可以在 Word2Vec 模型中使用它们作为输入向量,特别是使用 CBOW 算法。这样,我们的模型将能够赋予我们的项目“意义”,从而确定它们最有可能适合哪个上下文(即会话)。

对于我们的用例,我们可以将“单词”翻译成“产品”,将“上下文”翻译成“会话”。

你可能会说,不使用 Word2Vec,我们也可以只向用户推荐来自同一类别的产品。事实上,这可能是一种选择。然而,由于类别可以是相当高的级别,并且产品仍然可以在类别中有所不同,因此产生的推荐可能变得与我们的用户不那么“相关”。

既然我们已经研究了理论,并且理解了 Word2Vec 在这个用例中可以为我们做什么,那么让我们实际上开始实现我们的想法,看看结果是什么样的。

2 |用 Python 实现

对于我们的用例,我们将使用一个 Kaggle 数据集,其中包含来自多类别商店的电子商务数据(来源:【Kaggle.com】T2 和 REES46 营销平台)。数据集的大小相当大,因此,出于简化和演示的目的,我将使用 2019 年 10 月的原始数据集的子集。

数据探索

在我们进入任何处理步骤之前,让我们先来看看我们的数据:

2019 年 10 月电商数据(数据集来源:Kaggle.com和 REES46 营销)。图片作者。

我们观察了各种各样的特性,但是对于我们的用例来说,只有几个特性是有趣的: event_typeproduct_idcategory_codeuser_session 。在这个数据集中,我们也有关于我们的用户的数据,因为我们有 user_id 值。尽管如此,我们不会使用它们,因为这个例子的目的是展示我们如何基于匿名用户会话数据来实现郑重推荐。

**event_type 变量描述了会话中发生的事件类型。这可以是“查看”、“购物车”或“已购买”。我们将使用包含product _ id’的每个会话的向量作为 Word2Vec 模型的输入。稍后,使用来自我们的 category_code 变量的数据,我们将能够测试我们的模型的预测结果。

数据预处理

在将数据输入 Word2Vec 模型之前,我们首先需要执行一些处理步骤。为此,我们将使用熊猫库。

首先,我们的数据可能包含需要删除的缺失值。其次,我们只需要保留数据中的特定列,因为我们的用例不需要所有的列。这两个步骤在下面的代码中完成:

如上所述,出于演示的目的,我将只使用原始数据的一个子集。如下面的代码所示,为了创建数据的子集,我们将首先按照 user_session 对数据进行排序。这是为了确保我们将每个会话的所有数据分组在一起。然后我们选择指数 2'000'000 作为我们的分裂点。

为了确保我们的数据不会在会话中间被拆分,只要我们数据中的下一行仍然是同一先前会话的一部分,我们就将拆分索引 split_at 增加 1。最后,我们执行从第一行到找到的拆分索引的实际拆分。在我们的例子中,数据集在行索引 2'000'006 处被拆分。我们的子集现在包含总共 483,508 个唯一浏览会话数据。

构建 W2V 推荐系统

现在我们的数据已经被清理和处理了,我们终于可以继续构建我们实际的基于 Word2Vec 的推荐系统了。我们将使用 Gensim 库,它有 Word2Vec 算法的实际实现,正如在原始论文中发表的。

为了用 Gensim 训练我们自己的 Word2Vec 模型,我们首先需要将我们的数据变成正确的形状,以便库可以在其上进行实际训练。它将一个向量列表作为输入,因此我们将使用下面的 create_w2v_data 辅助函数来转换我们的数据:

该函数将 Pandas 数据帧作为输入,并输出数据集中每个会话的列表,而是在该会话中查看、放入购物车和/或购买的所有产品的列表。运行可能需要几分钟时间,但结果数据如下所示:****

[['2501061'],['2701673', '2701773'],['2900802', '2900090', '2900802', '2900803'],['1004573'],['1004792'],...
]

因为我们在数据中组合了所有三种事件类型(view、cart、purchased ),所以一个购买的产品将在同一个会话中出现三次。这很好:它让与实际购买的产品有了额外的关联**,因为它们通常会更频繁地出现在数据集中。**

我们会话的平均长度为 4.14,最长的会话包含 324 个已查看、放入购物车和/或已购买的产品。

训练模型

最后我们可以开始我们模型的实际训练了!🎉

在 Gensim 库的帮助下,这可以通过几行代码完成:

我们用准备好的会话列表作为输入数据建立了一个模型,并设置了模型参数。我们将 min_count 设置为 3,因为这将确保我们的模型只针对在整个数据集中出现至少 3 次的产品进行训练——换句话说:该产品必须被查看过至少 3 次,或者被查看过两次并放入购物车一次,或者被购买过至少一次。我们还使用了一个 window_size ,它对应于我们数据集中最长的会话。为什么?以便我们考虑在会话中查看的所有产品。我们保留 Gensim 库中建议的其余参数。

万岁,我们已经训练好了我们的模型!接下来:让我们看看它能为我们做什么。

3 |测试和可视化

训练一个模型很好,但是看到它的结果更好。

测试

让我们看看我们的模型给出的建议。假设用户查看了保存在 product_id 4802936 下的特定类型的耳机。我们模型推荐的产品可以用 Gensim 函数 predict_output_word 检索。前 10 条建议的结果如下所示:

产品 ID 4802936 的建议(音频耳机)。图片作者。

事实上,我们可以看到,我们的模型成功地正确理解了这些产品属于相似的类别,并且这些 product_id 之间有相似之处。因此,如果用户查看 id 为 4802936 的耳机,模型将推荐其他替代耳机。

我们可以对 product_id 42300039 进行同样的操作,它是属于“客厅”类别的“橱柜”:

产品 ID 42300039 的建议(客厅橱柜)。图片作者。

同样,我们看到我们的模型设法推荐相关的项目。

肉眼观察

我们还可以通过绘图来查看我们的数据,因为这可能会让我们对模型有更好的整体理解。我们将把模型中嵌入向量的维数减少到 2,这将允许我们很好地绘制数据。为此,我们可以利用来自 umap-learn 库中的 umap 降维工具。

该图将包含二维乘积嵌入向量,这些向量将按其各自的类别进行着色。为了简单起见,我们将只根据它们的主要类别对它们进行分组,即类别名称中列出的第一个类别。结果图如下所示:

W2C 推荐系统模型捕获的按类别划分的产品图。图片作者。

我们可以在上面的图中看到非常好的结果!这表明,我们的模型确实能够很好地按类别对产品进行分组。

4 |总结和结论

总的来说,我们在本文中展示了,借助 Word2Vec CBOW 算法,可以快速、轻松地为基于匿名会话的数据构建一个相当好的推荐系统。

对于未来的工作,该模型可以通过各种其他方式进行微调和测试。例如,我们可以通过调整窗口的大小,以及 min_count 参数来改变模型的训练输入参数,并查看最终的推荐结果。

我希望这对你有所帮助,并且你学到了一些新的东西。请随意评论您可能有的任何反馈或问题!🎉

参考资料:

[1] T. Mikolov 等人,向量空间中单词表示的有效估计 (2013)

[2] R. Rehurek,Gensim models . word 2 vec(2022)

[3] T. Mikolov 等人,单词和短语的分布式表示
及其组合性
(2013)

如何使用索引设置熊猫数据框中的单元格值

原文:https://towardsdatascience.com/set-cell-value-pandas-2a42d8d28201

在熊猫数据帧的特定单元格中设置值

Kai Dahms 在 Unsplash 上的照片

介绍

在我以前的一篇文章中,我讨论了关于的两个熊猫最常用的属性,即 [loc](/loc-vs-iloc-in-pandas-92fc125ed8eb)[iloc](/loc-vs-iloc-in-pandas-92fc125ed8eb)。这些属性可用于分别通过标签和整数位置查找来访问一组行

在今天的简短教程中,我们将展示如何使用标签整数位置在 pandas 数据帧中的特定单元格赋值(即特定列和行的值)。

首先,让我们创建一个 pandas 数据框架,我们将使用它作为一个例子来演示在 pandas 数据框架中设置单元格值时的一些概念。

import pandas as pd df = pd.DataFrame([(1, 'A', 150, True),(2, 'A', 120, False),(3, 'C', 130, False),(4, 'A', 150, False),(5, 'B', 140, True),(6, 'B', 115, False),], columns=['colA', 'colB', 'colC', 'colD']
) print(df)***colA colB  colC   colD
0     1    A   150   True
1     2    A   120  False
2     3    C   130  False
3     4    A   150  False
4     5    B   140   True
5     6    B   115  False***

使用标签设置特定行和列的值

为了访问行/列标签对的单个值,你可以使用[pandas.DataFrame.at](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.at.html)属性。注意,这个属性类似于loc,因为两者都允许基于标签的查找。然而,如果您想访问 DataFrame 或 Series 对象中的单个值就应该使用at属性。

例如,假设我们想要将索引1处的列colB的值设置为B。此时,该值被设置为'A':

>>> df.at[1, 'colB']
'A'

为了将它更改为B,下面的表达式可以解决这个问题:

**df.at[1, 'colB'] = 'B'** print(df)*colA colB  colC   colD
0     1    A   150   True* ***1     2    B   120  False*** *2     3    C   130  False
3     4    A   150  False
4     5    B   140   True
5     6    B   115  False*

使用整数位置设置特定行和列的值

或者,您可以使用[pandas.DataFrame.iat](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iat.html#pandas.DataFrame.iat)属性通过整数位置访问行/列。这类似于iloc属性,因为它们都提供基于整数的查找。

同样,让我们访问第二行的列colB的值(即索引1),但这一次,我们将使用整数位置,而不是使用列标签:

>>> df.iat[1, 1]
'B'

现在让我们使用iat属性和一个整数位置将值改回'A':

**df.iat[1, 1] = 'A'**print(df)*colA colB  colC   colD
0     1    A   150   True* ***1     2    A   120  False*** *2     3    C   130  False
3     4    A   150  False
4     5    B   140   True
5     6    B   115  False*

最后的想法

在今天的简短教程中,我们展示了如何使用基于标签的查找和at属性或整数位置查找和iat属性来设置特定列和行的值。

注意,这两个属性非常类似于lociloc属性,但是atiat可以用来访问(和改变)特定的列/行对,而不是访问一组行。

关于lociloc属性的更全面的阅读,你可以参考我最近的一篇文章,分享如下:

阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

使用 Conda & Pip-Tools 建立机器学习环境

原文:https://towardsdatascience.com/setting-up-an-environment-for-machine-learning-with-conda-pip-tools-9e163cb13b92

照片由拉明·哈蒂比在 Unsplash 上拍摄

用 conda 和 pip 工具创建一个健壮和确定的机器学习环境

如果我们在开始时没有设置一些基本规则,为机器学习项目设置一致和确定的环境有时会有点混乱。

在本文中,我想介绍一下如何为机器学习建立一个健壮的开发环境,以便于管理依赖关系,并保证项目整个生命周期中开发和生产阶段之间的兼容性。

我们的想法是从头开始,以包含以下内容的文件夹结束:

  • 一个指定我们的 Python 和cuda/cudnn版本的environment.yml文件
  • 分别规定开发和生产包要求的dev.inprod.in文件
  • 一个包含命令的Makefile在我们每次修改environment.yml文件或者改变.in文件中的包时自动更新我们的环境

免责声明: 本文内容使用以下主要资源编写:

  • https://github.com/full-stack-deep-learning/conda-piptools
  • https://github . com/full-stack-deep-learning/fsdl-text-recognizer-project
  • https://github.com/jazzband/pip-tools

主要是我从“全栈深度学习课程教授的课程中学到了很多,它除了是学习这个设置的主要资源之外,还是我所有与实用机器学习相关的主题的参考指南,所以我强烈建议你去看看!

步伐

  1. 设置蟒蛇
  2. 创建虚拟环境并安装依赖项
  3. 将环境导出到一个 **environment.yml** 文件
  4. 创建需求文件,并为开发和生产添加我们的依赖关系
  5. 编写一个 MakeFile 文件

1.设置 Anaconda

  • 设置蟒蛇
  • conda -V确认 conda 版本,在我的情况下,我得到:conda 4.10.3
  • 将 conda 更新至当前版本:conda update conda

在我的情况下我得到:conda 4.11.0

2.创建虚拟环境并安装依赖项

在这个项目中,我将使用一个pytorch示例,因此我将首先使用必要的cudatoolkit创建环境,如下所示:

conda create -n setup_ml_env python==3.7 cudatoolkit=10.2 cudnn=7.6

现在,我们通过运行以下命令来激活环境:

conda activate setup_ml_env

并且,我们通过运行以下命令来测试安装:

python -V

预期产出:

Python 3.7.11

3.将环境导出到一个environment.yml文件

conda env export --from-history > environment.yml

--from-history命令确保您只向environment.yml文件添加目前为止您实际安装的包(在本例中只有cudatoolkitcudnn包)。

让我们将pippip-tools添加到这个文件中,以便稍后用于安装我们的 Python 包,然后我们可以打印出文件的内容以供检查:

cat environment.yml

预期产出:

name: setup_ml_env
channels:- defaults
dependencies:- python=3.7- cudatoolkit=10.2- cudnn=7.6- pip- pip:- pip-tools
prefix: path/to/setup_ml_env

4.创建需求文件,并为开发和生产添加依赖性

在 Linux 终端中:

mkdir requirements
touch requirements/dev.in
touch requirements/prod.in

dev.in文件中我们写道:

-c prod.txt
mypy
black

这里-c prod.txt将开发包约束到生产需求文件prod.txt中指定的包,这些包将从prod.in文件生成。

prod.in文件里面写着:

torch
numpy

这只是一个使用torchnumpy包的玩具项目的示例。

5.编写 MakeFile

我们项目的 makefile 将包含:

# Command to print all the other targets, from https://stackoverflow.com/a/26339924
help:@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

help命令打印 makefile 的所有可用命令。

# Install exact Python and CUDA versions
conda-update:conda env update --prune -f environment.ymlecho "Activate your environment with: conda activate setup_ml_env"

下面是 makefile 命令,用于在我们每次修改environment.yml文件时更新我们的环境。

# Compile and install exact pip packages
pip-tools:pip install pip-toolspip-compile requirements/prod.in && pip-compile requirements/dev.inpip-sync requirements/prod.txt requirements/dev.txt

[pip-tools](https://github.com/jazzband/pip-tools)命令编译和安装所有需求的相互兼容的版本。

如全栈深度学习课程的报告中所述,使用 pip-tools 使我们能够:

  • 将开发从生产依赖中分离出来(dev.in vs prod.in)。
  • 为所有依赖项(自动生成的dev.txtprod.txt)准备一个精确版本的锁定文件。
  • 允许我们轻松部署到可能不支持 conda 环境的目标。

如果您添加、删除或需要更新某些需求的版本,请编辑。在文件中,只需再次运行make pip-tools

总结想法

在我的机器学习生涯之初,我只是安装软件包和运行代码,没有考虑依赖问题等事情的负面影响。

现在,即使可能仍然有我遗漏的东西,我觉得这种方法试图覆盖开发机器学习项目的天真方法中的漏洞。

总之:

  • environment.yml指定 Python 和可选的cuda/cudnn
  • make conda-update创建/更新 conda 环境
  • requirements/prod.inrequirements/dev.in指定 python 包需求
  • make pip-tools解析并安装所有 Python 包

如果你喜欢视频,可以看看我在 Youtube 上关于这个主题的视频:

如果你喜欢这篇文章,可以考虑加入我的 Medium 。另外,订阅我的 Youtube 频道。谢谢,下次再见!:)

*来自 https://enkrateialucca.github.io/lucas_soares_learning/*的博客

用 Docker-Compose 在 5 分钟内设置 Apache 气流

原文:https://towardsdatascience.com/setting-up-apache-airflow-with-docker-compose-in-5-minutes-56a1110f4122

数据工程

创建一个开发环境并开始构建 Dag

法比奥·巴拉西纳在 Unsplash 上拍摄的照片

答虽然参加派对已经很晚了(Airflow 在 2019 年成为了 Apache 的顶级项目),但我仍然很难找到一个易于理解、最新、轻量级的解决方案来安装 Airflow。

今天,我们将改变这一切。

在下面的小节中,我们将在几分钟内创建一个轻量级的、独立的、易于部署的 Apache Airflow 开发环境。

Docker-Compose 将是我们的亲密伙伴,允许我们创建一个具有快速迭代周期的平滑开发工作流。只需旋转几个 docker 容器,我们就可以开始创建自己的工作流了。

注意:以下设置不适用于任何生产目的,仅用于开发环境。

为什么是气流?

Apache Airflow 是一个面向批处理的框架,它允许我们轻松地用 Python 构建预定的数据管道。把“工作流当作代码”来想,它能够执行我们可以用 Python 实现的任何操作。

气流本身不是数据处理工具。这是一个编排软件。我们可以把气流想象成网中的某种蜘蛛。坐在中间,操纵一切,协调我们数据管道的工作量。

数据管道通常由需要以特定顺序执行的几个任务或动作组成。Apache Airflow 将这样的管道建模为 DAG (有向无环图)。一种有向边或任务的图,没有任何回路或循环。

一个简单的例子 DAG[图片作者]

这种方法允许我们并行运行独立的任务,从而节省时间和金钱。此外,我们可以将数据管道分成几个更小的任务。如果作业失败,我们只能重新运行失败的任务和下游任务,而不是重新执行整个工作流。

气流由三个主要部分组成:

  1. Airflow 调度器—air flow 的“心脏”,解析 Dag,检查计划的时间间隔,并将任务传递给工人。
  2. 气流工作人员 —拾取任务并实际执行工作。
  3. Airflow Webserver —提供主用户界面来可视化和监控 Dag 及其结果。

气流组件的高级概述[图片由作者提供]

逐步安装

现在我们简要介绍了 Apache Airflow,是时候开始了。

步骤 0:先决条件

因为我们将使用 docker-compose 来启动和运行 Airflow,所以我们必须首先安装 docker。只需前往官方 Docker 网站并为您的操作系统下载合适的安装文件。

步骤 1:创建新文件夹

我们通过简单地为气流创建一个新的文件夹,开始得又好又慢。

只需通过您的首选终端导航到一个目录,创建一个新文件夹,并通过运行以下命令进入该文件夹:

mkdir airflow
cd airflow

步骤 2:创建一个 docker-compose 文件

接下来,我们需要得到一个 docker-compose 文件,它指定了所需的服务或 docker 容器。

通过终端,我们可以在新创建的 Airflow 文件夹中运行以下命令

curl [https://raw.githubusercontent.com/marvinlanhenke/Airflow/main/01GettingStarted/docker-compose.yml](https://raw.githubusercontent.com/marvinlanhenke/Airflow/main/01GettingStarted/docker-compose.yml) -o docker-compose.yml

或者简单地创建一个名为docker-compose.yml的新文件并复制下面的内容。

上面的 docker-compose 文件简单地指定了我们需要启动和运行的服务。最重要的是调度程序、web 服务器、元数据库(postgreSQL)和初始化数据库的 airflow-init 作业。

在文件的顶部,我们利用了一些在每个 docker 容器或服务中常用的局部变量。

步骤 3:环境变量

我们成功地创建了一个 docker-compose 文件,其中包含强制服务。然而,为了完成安装过程并正确配置气流,我们需要提供一些环境变量。

不过,在您的 Airflow 文件夹中创建一个包含以下内容的.env文件:

上述变量设置数据库凭证、气流用户和一些进一步的配置。

最重要的是,我们将利用的执行器气流。在我们的例子中,我们使用了LocalExecutor

注意:关于不同种类的遗嘱执行人的更多信息可以在这里找到。

步骤 4:运行 docker-compose

这已经是它了!

只需前往终端,通过运行

docker compose up -d

经过一小段时间后,我们可以通过访问http://localhost:8080来检查结果和气流 Web UI。一旦我们用我们的凭证登录(airflow: airflow ),我们就可以访问用户界面。

气流 2 Web UI[作者截图]

快速测试

有了工作气流环境,我们现在可以创建一个简单的 DAG 用于测试目的。

首先,确保运行pip install apache-airflow来安装所需的 Python 模块。

现在,在 Airflow 文件夹中,导航到dags并创建一个名为sample_dag.py的新文件。

我们定义了一个新的 DAG 和一些非常简单的任务。

除了在 Web UI 中创建一个模型任务之外,EmptyOperator没有任何实际用途。通过利用BashOperator,我们创建了一个有点创造性的输出“HelloWorld!”。这使我们能够直观地确认正常运行的气流设置。

保存文件并转到 Web UI。我们现在可以通过手动触发来启动 DAG。

手动触发 DAG[作者截图]

注意:您的 DAG 可能需要一段时间才会出现在 UI 中。我们可以通过在我们的终端docker exec -it --user airflow airflow-scheduler bash -c "airflow dags list"中运行以下命令来加快速度

运行 DAG 不会超过几秒钟。

一旦完成,我们可以导航到XComs并检查输出。

导航到 air flow XComs[作者截图]

检查输出[作者截图]

这就是了!

我们成功地用 docker-compose 安装了 Airflow,并进行了快速测试。

注意:我们可以通过简单地执行docker compose down来停止正在运行的容器。

结论

Airflow 是一个面向批处理的框架,允许我们用 Python 创建复杂的数据管道。

在本文中,我们创建了一个简单易用的环境来快速迭代和开发 Apache Airflow 中的新工作流。通过利用 docker-compose,我们可以直接开始工作并编写新的工作流程。

但是,这样的环境应该只用于开发目的,不适合任何需要更复杂和分布式的 Apache Airflow 设置的生产环境。

你可以在我的 GitHub 上找到完整的代码。

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

https://medium.com/@marvinlanhenke/membership

参考资料/更多资料:

  • 气流文件
  • 朱利安.德.鲁特.巴斯.哈伦斯克。阿帕奇气流的数据管道。纽约:曼宁,2021。

为数据科学设置苹果定制芯片设备

原文:https://towardsdatascience.com/setting-up-apples-custom-silicon-devices-for-data-science-c70bf671b901

两分钟内准备好任何 M1 和 M2 机器

随着定制片上系统第二代产品的发布,苹果再次提高了计算能力。新的 M2 芯片支持高达 24 GB 的主内存,并可以提供多达 10 个 GPU 核心。虽然与 M1 Pro、Ultra 和 Max 型号相比,这款产品目前还很小,但预计第二代产品将在以后推出更高性能的版本。

由 Ales Nesetril 在 Unsplash 上拍摄的照片

在此之前,我们可以最大限度地利用当前的计算能力。然而,从基于英特尔的系统转换到定制芯片后,设置 Mac 电脑变得有点复杂。在这个指南的早期版本中,我手动指导你一步一步地完成这个过程。自从这篇文章发表后,我收到了反馈,并对设置有了更多的了解。更多的知识带来更多的可能性,在这篇文章中,我将向您展示一个自动化安装过程的脚本。该脚本可以在任何 M*设备上运行,无论是最初的 M1 芯片,它的兄弟,还是全新的 M2 版本。

运行完整的脚本

该脚本让您在不到两分钟的时间内解决我的设置中的机器学习问题。它有 20 行代码,其中 9 行(约 50%)是注释,让我们了解安装过程的最新情况。

**如果你只有两分钟的时间,下面是方法:**要运行这个脚本,下载源代码。为此,打开一个新的终端窗口(Spotlight →终端)并输入

wgethttps://github . com/phrasenmaeher/apple _ _ ml _ setup/blob/main/apple _ setup . sh

这会将安装脚本下载到您的机器上。接下来,键入 chmod +x apple_setup.sh ,这使得脚本可执行。最后,键入*。/apple_setup.sh* 开始安装。

整个脚本如下所示。每当我在这篇文章的剩余部分提到行号时,我指的是这个完整脚本的行:

安装 MiniForge

在前四行中,我们下载并安装了 MiniForge 的最新版本,这是一个适用于 Apple 系统的最小 Anaconda 版本。最小化意味着它不臃肿,只包含基本的特性。这对于我们的用例来说已经足够了;我们将手动安装所有需要的东西。通常,我们需要包管理器软件来处理我们机器学习任务所需的所有不同工具。简而言之,该软件允许我们安装所有需要开始使用的软件包,例如 TensorFlow 和 PyTorch。

创建新的虚拟环境

在第五行(上面代码片段中的一行),我们激活了新的 MiniForge 包管理器。

这随后让我们创建一个专门为机器学习任务设计的新环境。我们将这个环境命名为机器学习。每个虚拟环境可以看成一个盒子,每个项目通常使用自己的盒子。通过为每个项目使用单独的盒子,我们可以极大地减少项目之间不必要的干扰。这是 Anaconda 和 MiniForge 的主要工作。

安装 TensorFlow

从第九行开始(在上面的代码片段中有一行),我们激活我们的新环境,并继续安装 TensorFlow。为此,我们需要一个特定的包, tensorflow-deps ,它是我们从苹果的软件库(也就是第 14 行的-c Apple;上面第一行)。之后,我们安装实际的 TensorFlow 包(第 15 行;上面第二行)。

安装 PyTorch 和 Scikit-学习

安装 TensorFlow 之后,我们也是碰运气,安装了 scikit-learn(通常叫做 sklearn )和 PyTorch。

就是这样;您现在已经为机器学习准备好了一个环境!要在终端应用程序中激活它,请键入

source ~/miniforge 3/bin/activate

然后输入

康达激活机器学习

来激活新的环境。在你选择的 IDE 中,你可能需要将解释器(让你运行代码的东西)指向*/Users//miniforge 3/envs/machine _ learning*

对于这个过程的可视化,参见我之前的帖子并适当地插入上面的路径。

摘要

在这篇博客中,我指导您完成了一个简短的安装脚本,让您在两分钟内为机器学习做好准备。它使用 MiniForge 来管理所需的包,并自动安装 TensorFlow 和 PyTorch。重复我在开头写的内容:要运行脚本,通过打开一个新的终端窗口(Spotlight->Terminal)并输入

wget https://github . com/phrasenmaeher/apple _ _ ml _ setup/blob/main/apple _ setup . sh

这会将安装脚本下载到您的机器上。接下来,键入 chmod +x apple_setup.sh ,这使得脚本可执行。最后,输入*。/apple_setup.sh* 开始安装。

为电源和智能结果设置电源 BI

原文:https://towardsdatascience.com/setting-up-power-bi-for-power-and-intelligent-results-6612b2fed574

并理解为什么

奥拉夫·阿伦斯·罗特内在 Unsplash 上的照片

介绍

微软 Power BI 是一个流行且强大的商业智能平台,用于推动各行各业多个组织的分析。如果您渴望在分析和可视化领域找到一份职业,或者希望扩展您的数据工具集,Power BI 当然值得学习。本教程介绍 Power BI desktop,重点介绍如何配置 Power BI,以便高效地提供值得信赖的见解。本教程结束时,您将:

  • 了解 Power BI Desktop 和 Power BI service 之间的区别,
  • 配置 Power BI Desktop 以实现更高效(更少出错)的使用,
  • 能够将存储在逗号分隔值(CSV)文件中的数据加载到 Power BI 中,
  • 了解如何操作数据集中列的默认汇总方法。

装置

Power BI Desktop 免费下载。要安装,请转到 Power BI 桌面网页并点击免费下载按钮。如果出现提示,请打开 Microsoft Store,并按照 Microsoft Store 中 Power BI Desktop 页面中的说明进行操作。

现在,在我们进一步讨论之前,有两个警告值得一提。

  • 首先,Power BI Desktop 仅在 Windows 上可用。如果你是 Mac 用户,并且想使用 Power BI Desktop,我建议你使用虚拟桌面软件,如 Parallels 或在 Mac 上使用 Boot Camp 双启动 Windows。
  • 其次,要知道微软的 Power BI service 和 Power BI Desktop 的区别,Power BI service 是一个软件即服务(SaaS)平台。如果您在使用 Power BI 的组织中工作,您可能会遇到可以在线访问的 Power BI 仪表盘。仪表板的在线部署和使用使用 Power BI 服务。Power BI Desktop 是一个免费的 Windows 应用程序,用于创建仪表板、报告和其他数据可视化资产。Power BI Desktop 创建的数据可视化资产可以保存为 Power BI Desktop 文件(PBIX ),可以与其他 Power BI Desktop 用户共享或在线部署(如果您在使用 Power BI 服务的组织中拥有 Microsoft 帐户)。有关 Power BI 服务和 Power BI 桌面之间的差异的更多信息,请参见这篇文章。

一些配置建议

安装完成后,打开 Power BI Desktop。继续并关闭介绍性的 Power BI 桌面窗口,它类似于下图。

作者图片

然后导航到实际的 Power BI 桌面界面,如下所示。

作者图片

至此,有几个配置我想推荐一下。首先,导航到文件,在打开的下一个侧菜单中选择选项和设置,然后在选项和设置界面中选择选项

作者图片

我建议在全局选项的数据加载选项卡下设置以下配置选项。

  • 类型检测部分,选择**从不检测非结构化源的列类型和标题。**选择此选项将确保在用新数据刷新 Power BI 文件时,列的数据类型不会被意外更改。此外,确保不自动检测列类型和标题有助于加快刷新速度。欲了解更多信息,请参阅本文。

作者图片

  • 时间智能部分,关闭新文件的自动日期/时间。如果该选项保持启用,Power BI 将自动为数据集中的任何日期列创建一个日历层次结构。也就是说,用户将能够深入到日期的年、季度、月和日级别。虽然自动化这个层次结构在某些上下文中可能有用,但是这个选项增加了 Power BI 中的数据模型的大小。查看这篇文章了解更多详情。

作者图片

接下来*,在当前文件选项的数据加载标签中,取消刷新数据时更新或删除关系和**数据加载后自动检测新关系。*禁用这些选项允许用户控制在 Power BI 中管理表之间的关系的方式。否则, Power BI 可能无法正确指定表之间的关系。

作者图片

加载数据

现在,让我们将一些数据放入 Power BI Desktop。本教程使用了 Kaggle 上发布的《2022 年世界幸福报告》的数据集。数据存储在一个 CSV 格式的文件中,可以从这里下载。

作者图片

一旦世界幸福报告 2022 CSV 文件下载到您的计算机,返回 Power BI 桌面并点击主页选项卡中的获取数据菜单。正如您将看到的,这里的获取数据菜单包含从不同来源获取各种数据的选项,这是 Power BI 非常强大的特性之一。出于本教程的目的,我们想要加载一个 CSV 文件,因此在展开的获取数据菜单中找到并点击文本/CSV

作者图片

现在,Windows 资源管理器将会打开。导航到下载《世界幸福报告 2022》CSV 文件的文件夹,选择 CSV 文件,点击打开按钮。接下来,将出现 CSV 文件中数据的预览。

作者图片

如果我们需要清理和/或操作数据(例如,删除不必要的列,更改特定列的格式,删除重复的记录等。),我们可以选择右下角的转换数据按钮,这将打开 电力查询 ,这是一个准备数据的有用工具。

作者图片

然而,出于本教程的目的,请点击数据预览窗口右下角的加载按钮。

作者图片

你现在会看到《2022 年世界幸福报告》的数据出现在字段窗格下。

作者图片

点击世界幸福报告数据左侧的箭头,您将能够查看数据中的列。

作者图片

那些σ符号是什么?

您可能想知道为什么除了 Country 之外的所有列都有一个求和符号(σ)。求和符号表示默认汇总用于这些列,默认情况下,汇总是给定列的所有行值的总和。举例来说,如果我们将幸福得分列拖到报告画布上,我们将看到一个条形图,其中一个条形显示了数据中所有幸福得分值的总和。

作者截图

作为检查,如果我们在 Excel 中打开世界幸福报告数据,并对幸福得分列求和,我们会得到 810.82 的值,与 Power BI Desktop 中显示的值相同。

作者截图

这里,有两点值得一提。

  • 首先,Country 列没有默认汇总,因为该列包含文本值(例如,“美国”、“加拿大”、“洪都拉斯”),这些值不能进行数字汇总,例如 sum 或 means。
  • 其次,了解默认总结也很重要,因为有时您可能需要除求和之外的特定总结方法,或者根本不需要总结。例如,如果您想要显示某一列的平均值,但保留默认的汇总,并显示感兴趣的列的总和,您可能会有一个非常困惑的观众。

关于上面的第二点,可以通过从当前的报告视图导航到数据视图来改变默认汇总或移除列的默认汇总。接下来,选择感兴趣的列,然后从列工具选项卡中的汇总下拉菜单中选择不同的选项。例如,下面的录音显示了如何删除幸福分数列的默认摘要。

作者截图

哒哒!幸福分数栏不再有求和符号。

作者图片

那么,这种改变的实际效果如何呢?如果我们将快乐分数拖到报告画布中,将会出现一个包含数据中每一行的快乐分数值的表格。为什么?我们告诉 Power BI 不要汇总幸福分数列,所以现在显示属于该列的实际值。

作者截图

好了,我们现在有了一个幸福分值的表格,但是如果我们想把这个表格包含在一个实际的仪表板或报告中,它将不会非常有用,因为没有办法知道与每个幸福分值相关联的国家。幸运的是,通过将 country 列拖到表中,我们可以很容易地将国家名称添加到这个表中。

作者截图

请注意,在上面记录的结尾,我改变了列的顺序,这样国家将出现在第一个。如果我们决定不要这张桌子,我们需要做的就是选择桌子,然后点击桌子上方更多选项菜单中的移除(见桌子上方的三个点)。

作者截图

结论

Power BI Desktop 易于安装。尽管如此,有效和高效地使用 Power BI 需要额外关注细节。本教程涵盖了一些基本的细节,可以帮助您和任何数据可视化的消费者获得更好的 Power BI 体验。特别是,阅读完本教程后,您现在已经掌握了一些有用的知识,可以帮助您设置 Power BI 以获得更好的性能、接收数据并理解默认总结的作用。

一如既往的感谢阅读!欢迎建设性的反馈、意见和问题。

在 M1 Mac 上用 Visual Studio 代码(VSCode)设置 Python、Julia 和 R

原文:https://towardsdatascience.com/setting-up-python-julia-and-r-in-visual-studio-code-vscode-on-an-m1-mac-3e904a65b62b

Python,R & Julia

在 M1 Mac 上用 Visual Studio 代码(VSCode)设置 Python、Julia 和 R

随机想到在 VSCode 中使用 R 花了我两天时间来设置…

Python、Julia 和 R 是数据科学家使用的 3 种主要编程语言,我总是想从不同方面比较这 3 种语言。

我一直在想 R 真的是最适合统计分析的吗?Python 更新了这么多真的还是比 Julia 慢吗?在数据科学和数据分析项目中,3 种语言中哪一种最容易应用?谁知道呢?也许把这三种语言结合起来会创造出一件艺术品。

在 Unsplash 上由 Eiliv-Sonas Aceron 拍摄的照片

比较这 3 种语言最简单的方法是将它们全部安装在 VSCode 上,它支持所有 3 种语言,我不需要在不同的 ide 之间切换。

设置 Python

在 VSCode 中设置 Python 很简单,☺️.

你所需要的就是下载并安装 Python 解释器Python 扩展。VSCode 足够智能,可以在 Mac 上检测 Python😊,所以不需要为 Python 设置路径。

VSCode 检测到我的 Mac 上所有可用的 Python 解释器。图片作者。

下载并安装 Python

你可以通过 Python.org 的安装 Python,或者如果你安装了 Anaconda 的话,可以使用 Anaconda 的 Python。

如你所见,我有一些 Python 解释器,原生 Python、虚拟环境中的 Python 和 Anaconda Python。VSCode 能够检测到所有这些。

在 VSCode 中安装 Python 扩展

下一步是安装两个 Python 扩展包,如下所示。同样,VSCode 足够聪明,可以向您建议运行 Python 所需的所有扩展包。

  1. 来自微软的 Python 扩展(扩展 ID: ms-python.python)
  2. 微软的 Pylance 扩展(扩展 ID: ms-python.vscode-pylance)

VSCode 上的 Python。图片作者。

你也可以在 VSCode 中运行 Jupyter Notebook 文件,你需要做的就是安装如下的扩展包。

  1. 微软的 Jupyter 扩展(扩展 ID: ms-toolsai.jupyter)

这个扩展包附带了两个扩展包。

  1. Jupyter 键图
  2. Jupyter 笔记本渲染器

有了所有这些扩展包,您现在可以在 VSCode 上使用 Python 和数据科学家最喜欢的 Jupyter 笔记本。

VSCode 上的 Jupyter 笔记本。图片作者。

有时,你可能需要一些额外的扩展包,VSCode 会聪明地向你推荐❤️.

设置朱莉娅

对于朱莉娅,我必须手动设置路径。因此,设置 Julia 有 3 个步骤。

  1. 安装并下载茱莉亚
  2. 在 VSCode 中安装 julialang 的 Julia 扩展(扩展 ID: julialang.language-julia)
  3. 设置 Julia 路径

我刚接触 MacOS,所以要花一些时间才能找到 Julia 的可执行文件。对于像我一样对苹果电脑不熟悉的人,我会牵着你的手走过这个❤️.

对我来说,我在应用程序文件夹里找到了我的朱莉娅。

朱莉娅的位置。图片作者。

右键单击 Julia 图标,然后选择“显示包内容”,它将引导您进入下面的窗口。

Julia 包内容。图片作者。

在内容文件中,有几个文件夹。我在资源文件夹中找到了 Julia 可执行文件,Julia 可执行文件的完整路径如下:

/应用程序/Julia-1.7 . app/内容/资源/julia/bin

你的道路可能与我的不同,因为我发现的一些资源与我的不同。

您可以通过右键单击 Julia 可执行文件,然后选择“获取信息”来复制路径。说明这一点是因为我对我的 Mac 电脑还很陌生😂,对我来说一切都需要时间。

获取 Julia 可执行文件路径。图片作者。

所以现在你得到了朱莉娅路径。有两种方法可以设置路径。

管理图标中的设置

您可以通过单击“管理”打开“设置”,这是位于 VSCode 左侧面板最底部的⚙️图标,如下所示。

朱莉娅的设置。图片作者。

然后,在“扩展”,选择“朱莉娅”并向下滚动,直到你看到朱莉娅:可执行路径,粘贴您的路径在提供的空间。

CMD + Shift + P

在 VSCode 下,按下键盘上的这 3 个键,将弹出如下的命令面板。你也可以打开命令面板,在顶部的功能栏上查看。

VSCode 命令调色板。图片作者。

搜索并选择*“首选项:打开设置(JSON)”*

"julia.executablePath": "/Applications/Julia-1.7.app/Contents/Resources/julia/bin/julia"

将路径修改为您之前获得的路径。

现在你都准备好了。

VSCode 里的 Julia。图片作者。

设置 R

当我在 VSCode 中设置 R 时,我会参考这两篇文章。

  1. 设置 Visual Studio 代码以在 VSCode 2021 上运行 R
  2. Varun 的 VSCode 中 R 的全新开始

两篇文章都很惊人,但可能由于 VSCode 的新更新,有一些细微的变化。

安装步骤参考第一篇,修改 setting.json 中的线条参考第二篇。

  1. 下载安装 R
  2. 通过 R 控制台安装 R 包*“language server”*
install.packages("languageserver")

3。安装 R 扩展组件

需要两个 R 扩展包

  • r 由上田祐挥提供(分机 ID: ikuyadeu.r)
  • 上田祐挥的 R 扩展包(扩展 ID: ikuyadeu.r-pack) —该扩展包包括在 VSCode 中已从市场上移除的 R-LSP 扩展包。

4。通过 pip 安装弧度

Radian 是一个 python 包,因此,如果您还没有安装 Python,应该先安装它。

pip3 install -U radian

5。启用 r.bracketedPaste 以使用弧度

6。设置可执行路径

对于第 5 步和第 6 步,可以通过更新 setting.json 中的行来一起完成,如下所示。

首先,使用快捷键 Cmd + Shift + P 或通过 VSCode 顶部功能栏的视图调出命令面板。然后,搜索*“首选项:打开设置(JSON)”*并修改如下行。

{"r.bracketedPaste": true,"r.alwaysUseActiveTerminal": false,"r.rpath.mac": "<path for R executable file>","r.rpath.linux": "","r.rterm.mac": "<path of python packages radian>","r.lsp.path": "<path for R executable file>","r.lsp.debug": true,"r.lsp.diagnostics": true,"r.rterm.option": [
"--no-save",
"--no-restore",
"--r-binary=<path for R executable file>"]}

下面是我的 setting.json 在设置好 Julia 和 r 之后的样子。

Setting.json. Image 作者。

现在你已经准备好了!

VSCode 中的 r。图片作者。

令人惊讶的是,Python 和 R 的可执行文件与 Julia 的不同。所以当我为 R 设置路径的时候,我不得不使用find.package(“languageserver”) 来定位安装的库的路径,然后找到 R 的可执行文件。

r 控制台。图片作者。

我们刚刚完成了在 VSCode 中设置 Python、Julia 和 R😄。现在,您可以在一个 IDE 中使用所有三种语言。

干得好!

保持联系

在 YouTube上订阅

照片由莫里茨·克纳林格在 Unsplash 上拍摄

*祝贺并感谢你阅读到最后。希望你喜欢这篇文章。*😁

新年快乐!

成功设置您的数据分析

原文:https://towardsdatascience.com/setting-up-your-data-analysis-for-success-549917a5e2c9

开始回答问题前需要回答的 5 个关键问题

当你开始学习“如何进行数据分析”时,通常是以一种非常巧妙的方式。您有一个精确的问题,没有解释的余地(“A 组的平均值与 B 组的平均值不同吗”),以及一个非常好的、整洁的、记录良好的数据集供您使用。

数据分析感觉简单不复杂。这类似于解决一个数学问题。找到 x 就行了。

照片由克莱门斯·范·莱在 Unsplash

但在现实生活中,数据分析很少在“真空”中独立于其他事件进行。通常:

  • 发生了一件事,导致一些人要求你调查一些事情(例如,在一次重要会议上展示了一副牌,提出了一些问题,现在你的经理想知道更多)
  • 一旦你完成了你的分析,那些同样的人期待着一些事情发生(例如,如果先前的发现是真的,你的团队应该改变它的策略)
  • 这可能会影响其他人目前的工作方式(例如,如果战略发生变化,运营团队将受到影响)

你的学习本身不是起点,也不是终点:它通常是你的组织正在进行的更大旅程中的一个关键部分。为了让您的学习尽可能有影响力,您需要了解这个旅程的关键要素,并了解围绕这个旅程的伙伴关系的总体动态。

下面我建议在开始任何工作之前问自己 5 个关键问题,以确保你的产出尽可能有影响力。

“大自然给了人类一条舌头,两只耳朵,这两只耳朵是为了让我们从别人那里听到的比我们说的多两倍。”——爱比克泰德

#1:为什么这个问题在今天很重要?

在着手一个项目之前,首先要了解 ask 的背景。为什么今天要求你参与这个项目?

  • 理解导致这个问题的事件可以给你一个起点。例如,如果提问是由之前在内部论坛上出现的一些数字引发的,或者提问是来自一位高管,他是从网上阅读到的,那么你的流程就会不同。
  • 当你展示你的成果时,这也是非常重要的。正如奇普·希斯所说,“只有认识到问题,你才能认识到解决方案”。清楚地陈述问题会让你的听众想要看到解决方案——但是只有在你头脑中清楚地定义了问题,你才能清楚地陈述问题。
  • 最后,真正理解问题有助于确定实际问题的大小,这对于确定问题解决方案和其他竞争优先级(如果有的话)的优先级非常有帮助。

上面的话虽然看起来很简单,但通常并不简单。想象一下这样一种情况,你在一家手机游戏公司工作,你被要求寻找降低流失率的方法,因为现在“流失率太高了”。这里的第一步应该是理解“太高”是什么意思,以及就$$$(这本身是研究中的一项研究)而言,这是一个多大的问题。想象一下,现在你发现由于免费用户的流失,用户流失率很高,但在付费用户方面,你实际上远低于行业流失率。你还应该继续最初的询问吗(例如,寻找减少客户流失的方法)?

谁对这项工作感兴趣?

在开始任何工作之前,澄清谁是官方和非官方的决策者,谁是工作的使用者是极其重要的。

  • 你需要你的决策者开绿灯才能继续——所以你需要确切地知道他们会看重什么,以及你如何向他们推销这个项目。
  • 你会希望你的工作在现实生活中得到应用,所以你需要确保你的发现能被你的用户执行。

与这两组利益相关者保持良好的关系,可以让你确保你的研究考虑了他们的意见并回答了他们的问题。不这样做可能会导致非常不利的影响。

尤其是当你没有听取一些潜在用户的意见时。正如我在之前的一篇文章中提到的,有一个很棒的 TED 视频,由 Ernesto Sirolli 制作,名为“想帮助某人吗?闭嘴,听着”。在信中,他解释了自己 21 岁时是如何为一家意大利非政府组织工作的,这家组织试图通过在赞比西河附近种植蔬菜来帮助赞比亚人民。他们确实种植了“极好的西红柿”,但是,正如西罗利自己所说的:

当西红柿又好又熟又红时,一夜之间,大约 200 只河马从河里出来,它们吃光了所有的东西。我们对赞比亚人说,“我的上帝,河马!”赞比亚人说,‘是的,这就是为什么我们这里没有农业。'

故事的核心:听着。

#3:现场已经做了什么?

了解关于这个项目已经做了什么总是很有趣的(无论是在内部,在行业中,在类似的领域中,还是在研究领域中)。这不仅能帮助你从过去的经历中学习,了解潜在的陷阱,还能给你一些好主意。

这一步经常被错过——因为它相当耗时,尤其是如果你的组织没有一个好的知识管理系统。当这种情况发生时,知识仍然存在,但在多人之间传播,找到这些人可能是一项艰巨的任务。这是内部网络获得回报的时候。

#4:你可以开始与哪些优秀的中小企业合作?

简单来说,有两种类型的主题专家(SME):技术专家和非技术专家。

  • 技术 SME 可以帮助您了解数据是如何收集的,以及应该避免哪些常见的陷阱。基本上,技术 SME 可以告诉您使用哪些数据源,进行哪些数据转换,或者对数据使用什么样的正确过滤器,所有这些稍微重要的事情最好在研究的早期而不是最后发现。
  • 另一方面,非技术型中小企业可以帮助你更好地理解你所研究的现象。如果你想一想,数据库是一种记录信息的简化方式,只有通过这种简化的镜头来看待现象,才能给出更简单的现实愿景。如果你想确保你的简化愿景是正确的,获得定性数据是很重要的。

你怎么知道这个项目是否成功?

这一点经常被忽视——但是为你的工作定义某种成功/退出标准总是好的。你的工作应该定义一个新的标准吗?它应该以新仪表板的发布而结束吗?它是否会改变贵公司的工作方式,并每月/每年带来额外的$Xk 美元?

这里的想法是提出一个客观的标准,你可以用它来决定什么时候停止以及你的工作是否成功。想出一种独立于更大的旅程来评估研究的方法并不容易,但这是一件有趣的事情,因为它可以让你了解你是否带来了你应该得到的价值,并可以帮助你后退一步,发现一些你否则不会发现的知识。

搅动者的友谊

回答这些问题通常有助于确保你的项目有合适的背景,你清楚谁是主角,对你的工作有什么期望。

显然,现在你仍然需要做这项工作,但是希望你已经为成功做好了准备。

“没有山姆,佛罗多不会走得这么远,是吗”佛罗多·巴金斯

希望你喜欢阅读这篇文章!你有什么建议想要分享吗?在评论区让大家知道!

如果你想更多地了解我,这里有几篇你可能会喜欢的文章:

</7-tips-to-avoid-public-embarrassment-as-a-data-analyst-caec8f701e42> https://medium.com/@jolecoco/how-to-choose-which-data-projects-to-work-on-c6b8310ac04e

在熊猫中设置版权警告

原文:https://towardsdatascience.com/settingwithcopywarning-in-pandas-782e4aa54ff7

它是什么,为什么突然出现,以及如何摆脱它

(TL;dr:如果你是来寻求答案的,直接跳到消除带有复制警告的设置

如果你是一个熊猫用户,当你给一个pd.DataFramepd.Series赋值的时候,你可能已经看到 SettingWithCopyWarning 弹出来了。

In [1]: import pandas as pd…:…: df = pd.DataFrame({…:     “A”: [1, 2, 3, 4, 5],…:     “B”: [6, 7, 8, 9, 10],…:     }, index=range(5)…: )…: dfa = df.loc[3:5]…: dfa[“C”] = dfa[“B”] * 50<ipython-input-2–63497d1da3d9>:9: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfa[“C”] = dfa[“B”] * 50

pandas 在这里给出了一个警告,因为赋值可能会也可能不会像预期的那样工作。

需要说明的是,赋值确实发生了;这里强调的是“预期”。

In [2]: dfa
Out[2]:A B C
3 4 9 450
4 5 10 500In [3]: df
Out[3]:A B
0 1 6
1 2 7
2 3 8
3 4 9
4 5 10

你认为df的内容会受到dfa中赋值的影响吗?对于这种情况是否会发生,熊猫有着内在一致的(尽管有些迟钝)规则。只是在这种情况下,用户期望的模糊性需要一个警告,这样当我们的代码出现问题时,像你我这样的最终用户就知道去哪里找了。

带有视图和副本的链式分配

照片由郭佳欣·阿维蒂西安在 Unsplash 上拍摄

从数据帧或系列中选择要访问的行或列的行为称为索引。pandas 的灵活性允许链式索引,您可以重复索引前一次索引操作的结果。

# Select the 2nd to 4th row of data where col A > 3 and col B != 7
df[df[“A”] > 3 & df[“B”] != 7].iloc[3:5]

然后 pandas 将返回数据帧的视图或副本。视图(浅层拷贝)引用原始数据帧中的数据,而拷贝(深层拷贝)是同一数据的单独实例。

很难预测索引操作将返回哪个,因为它取决于底层数组的内存布局。索引的链接方式会导致不同的__getitem____setitem__调用被隐藏起来。再现下面的例子:

# Example borrowed from [1]
dfmi.loc[:, (‘one’, ‘second’)] = value
# becomes
dfmi.loc.__setitem__((slice(None), (‘one’, ‘second’)), value)dfmi[‘one’][‘second’] = value
# becomes
dfmi.__getitem__(‘one’).__setitem__(‘second’, value)

链式索引本身没有问题,但使用链式索引赋值,即chained assignment,可能会有问题。根据具体情况,链式赋值要么直接修改原始数据帧,要么返回原始数据帧的修改副本。当链式索引不明显时,这可能会导致潜在的错误。

链式索引可以跨几行代码进行:

# The following doesn’t look like chain indexing, does it?
dfa = df.loc[row1:row2, col1:col2]
…
…
dfa[row2] = dfa[row1].apply(fn)

如果 pandas 在这个场景中没有发出警告,那么df没有被第二个赋值修改就不明显了。这就是 SettingWithCopyWarning 存在的原因。

熊猫医生[ ]对此进行了更详细的研究。警告信息链接到它很有帮助,这很好,因为如果你在 Google 上搜索pandas settingwithcopywarning,文档页面很容易被遗漏!在撰写本文时,它是 Google 首页的第 7 个结果,被 blogposts 和 StackOverflow 问题挤掉了。

使用内部 API 在幕后窥视

链式索引是选择正确数据的天赐便利,但是链式赋值是赋值正确值的雷区。[ ]中的 TowardsDataScience 文章提供了一个很好的例子,其中仅颠倒链式索引的顺序就可以决定是否对原始数据帧进行赋值:

# Example borrowed from [2]# This updates `df`
df[“product_group”][df[“product_group”]==”PG4"] = “PG14”# This doesn’t!
df[df[“product_group”]==”PG4"][“product_group”] = “PG14”# pandas raises warnings for both
# the user needs to confirm the intended outcome

从这个 StackOverflow post 、pd.DataFramepd.Series对象拥有_is_view_is_copy属性作为它们内部 API 的一部分。_is_view如果对象是视图,返回 True 如果对象不是视图,返回 False。_is_copy 存储一个弱引用到它被复制的数据帧,或者None如果它不关联到一个现有的数据帧。

打印这些内部属性,同时使用链式赋值确实揭示了一些有趣的信息。一方面,pandas 使用_is_copy来决定是否需要提高 SettingWithCopyWarning。另一方面,用_is_view = True修改数据帧意味着它将影响原始的底层数据帧。

在我们开始之前,一个免责声明:内部 API 不是最终用户可以访问的,可能会发生变化,使用它们需要您自担风险。

In [4]: pd.__version__
Out[4]: ‘1.3.3’# Setting up convenience functions
In [5]: def make_clean_df():…:     df = pd.DataFrame({…:         “A”: [1, 2, 3, 4, 5],…:         “B”: [6, 7, 8, 9, 10],…:         “C”: [11, 12, 13, 14, 15],…:         }, index=range(5)…:     )…:     return dfIn [6]: def show_attrs(obj):…:     print(f”view: {obj._is_view}, copy: {obj._is_copy}”)

我们将首先展示几种常见索引方法的_is_view_is_copy属性。

In [7]: df = make_clean_df()In [8]: show_attrs(df.loc[3:5])…: show_attrs(df.iloc[3:5])…: show_attrs(df.loc[3:5, [“A”, “B”]])…: show_attrs(df.iloc[3:5, [0, 1]])…: show_attrs(df[“A”])…: show_attrs(df.loc[:, “A”])view: True, copy: <weakref at 0x7f4d648b2590; to ‘DataFrame’ at 0x7f4d648b54c0>
view: True, copy: <weakref at 0x7f4d648b2590; to ‘DataFrame’ at 0x7f4d648b54c0>
view: False, copy: None
view: False, copy: <weakref at 0x7f4d648be770; dead>
view: True, copy: None
view: True, copy: None

让我们来分解一下:

  • df.loc[3:5]df.iloc[3:5]都返回了视图并引用了原始数据帧。
  • 对于df.loc[3:5, [“A”, “B”]]df.iloc[3:5, [0, 1]],当在行的顶部额外指定列时,返回df的副本。使用.loc索引没有对 OG 数据帧的引用,而使用iloc索引会导致对已被垃圾收集的临时数据帧的引用,这与None本身一样好。我们看看这是否有什么意义。
  • 直接使用df[“A”]df.loc[:, “A”]引用一个列会返回一个视图,而不引用原始数据帧。这可能与每个 dataframe 列实际上被存储为一个pd.Series有关。

如果我们手动创建这些索引数据帧/系列的副本,会发生什么情况?

In [9]: show_attrs(df.loc[3:5].copy())…: show_attrs(df.iloc[3:5].copy())…: show_attrs(df.loc[3:5, [“A”, “B”]].copy())…: show_attrs(df.iloc[3:5, [0, 1]].copy())…: show_attrs(df[“A”].copy())…: show_attrs(df.loc[:, “A”].copy())view: False, copy: None
view: False, copy: None
view: False, copy: None
view: False, copy: None
view: False, copy: None
view: False, copy: None

显式调用.copy会返回不引用原始数据帧/序列的数据副本。在这些副本上分配数据不会影响原始数据帧,因此不会触发 SettingwithCopyWarnings。假设上面的df.loc[3:5, [“A”, “B”]]df.iloc[3:5, [0, 1]]具有相似的属性,我们可以预期它们在链式分配下的行为应该类似于显式创建的副本。

接下来,我们将尝试几个链式分配场景。

场景 1:使用 loc 索引的特定行

以下三个链接的赋值引发 SettingWithCopyWarnings:

In [10]: df = make_clean_df()…: dfa = df.loc[3:5]…: show_attrs(dfa)view: True, copy: <weakref at 0x7fba308565e0; to ‘DataFrame’ at 0x7fba3084eac0># (1a)
In [11]: dfa[dfa % 2 == 0] = 100/tmp/ipykernel_34555/3321004726.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfa[dfa % 2 == 0] = 100
/home/tnwei/miniconda3/envs/ml/lib/python3.9/site-packages/pandas/core/
frame.py:3718: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copyself._where(-key, value, inplace=True)# (1b)
In [12]: dfa[“D”] = dfa[“B”] * 10/tmp/ipykernel_34555/447367411.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfa[“D”] = dfa[“B”] * 10 # 1b# (1c)
In [13]: dfa[“A”][3] = 10/tmp/ipykernel_34555/1338713145.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfa[“A”][3] = 10

所有赋值对dfa本身生效,但只有(1a)和(1c)影响原始数据帧。(1b)没有。

In [14]: print(dfa)A  B  C   D
3 10 9  100 90
4 5  100 15 1000In [15]: print(df) A  B  C
0 1  6  11
1 2  7  12
2 3  8  13
3 10 9  100
4 5  100 15

另外,dfa不再是视图,而是 dataframe 的副本!

In [16]: show_attrs(dfa) # view changed to Falseview: False, copy: <weakref at 0x7fba308565e0; to ‘DataFrame’ at 0x7fba3084eac0>

这告诉我们,熊猫会在必要时将视图转换为副本。这进一步说明了为什么找出链式分配本质上是棘手的,并且很难在库级别自动满足。

场景 2:使用 iloc 索引的特定行

这与场景 1 相同,但是使用iloc代替。

In [17]: df = make_clean_df()…: dfb = df.iloc[3:5]…: show_attrs(dfb)view: True, copy: <weakref at 0x7fba30862040; to ‘DataFrame’ at 0x7fba30868c10># (1a)
In [18]: dfb[dfb % 2 == 0] = 100/tmp/ipykernel_34555/734837801.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfb[dfb % 2 == 0] = 100
/home/tnwei/miniconda3/envs/ml/lib/python3.9/site-packages/pandas/core/
frame.py:3718: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copyself._where(-key, value, inplace=True) # (1b)
In [19]: dfb[“D”] = dfb[“B”] * 10/tmp/ipykernel_34555/4288697762.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value insteadSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfb[“D”] = dfb[“B”] * 10# (1c)
In [20]: dfb[“A”][3] = 10/tmp/ipykernel_34555/2062795903.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: [https://pandas.pydata.org/pandas-docs/](https://pandas.pydata.org/pandas-docs/)
stable/user_guide/indexing.html#returning-a-view-versus-a-copydfb[“A”][3] = 10

观察到的结果与场景 1 相同。

In [21]: print(dfb)A  B  C   D
3 10 9  100 90
4 5  100 15 1000In [22]: print(df) A  B   C
0 1  6   11
1 2  7   12
2 3  8   13
3 10 9   100
4 5  100 15In [23]: show_attrs(dfb)view: False, copy: <weakref at 0x7fba30862040; to ‘DataFrame’ at 0x7fba30868c10>

场景 3:使用 loc 索引特定的行和列

与场景 1 相同,但是也指定了列。

In [24]: df = make_clean_df()…: dfc = df.loc[3:5, [“A”, “B”]]…: show_attrs(dfc)view: False, copy: NoneIn [25]: dfc[dfc % 2 == 0] = 100 # No warnings raised…: dfc[“D”] = dfc[“B”] * 10…: dfc[“A”][3] = 10

没有发出警告。所有更改在“dfc”上生效,但不影响“df”。

In [26]: print(dfc)A  B  D
3 10 9  90
4 5  100 1000In [27]: print(df) A  B   C
0 1  6   11
1 2  7   12
2 3  8   13
3 10 9   100
4 5  100 15

链式分配结果是不同的,而索引的数据与场景 1 中的相同。我的猜测是,对索引操作更完整的描述促使 pandas 直接提前返回一个副本,而不是链接到原始数据帧的视图。

场景 4:使用 iloc 索引特定的行和列

这类似于场景 3,但使用的是 iloc。鉴于过去的几个场景,这个场景与场景 3 的结果相同也就不足为奇了。

In [28]: df = make_clean_df()…: dfd = df.iloc[3:5, [0, 1]]…: show_attrs(dfd)view: False, copy: <weakref at 0x7fba306f29f0; dead>In [29]: dfd[dfd % 2 == 0] = 100 # No warnings raised…: dfd[“D”] = dfd[“B”] * 10…: dfd[“A”][3] = 10In [30]: print(dfd) A  B   D
3 10 9   90
4 5  100 1000In [31]: print(df) A B  C
0 1 6  11
1 2 7  12
2 3 8  13
3 4 9  14
4 5 10 15

此外,` dfd '在这段代码的末尾放弃了对垃圾收集数据帧的引用。

In [32]: show_attrs(dfd)view: False, copy: None

场景 5:直接引用数据帧的一列

此方案测试系列的链式分配。

In [33]: df = make_clean_df()…: dfe = df[“A”]…: show_attrs(dfe)view: True, copy: NoneIn [34]: dfe[1] = 99999 # No warnings raised…: dfe.loc[2:4] = 88888

dfe保留了df[“A”]. 的视图所有影响dfe的变化都反映在df[“A”]中,它仍然是df的一部分。对于单个系列的链式作业,似乎没有什么可担心的。

In [35]: print(dfe)0 1
1 99999
2 88888
3 88888
4 88888
Name: A, dtype: int64In [36]: print(df) A     B C
0 1     6 11
1 99999 7 12
2 88888 8 13
3 88888 9 14
4 88888 10 15In [37]: show_attrs(dfe)view: True, copy: None

正在删除 SettingWithCopyWarnings

当 pandas 不确定是否希望值赋值影响原始数据帧时,会弹出 SettingWithCopyWarnings。因此,消除这些警告需要避免赋值的模糊性。从上面的代码示例可以看出,让 pandas 返回不引用原始数据帧的副本是一种干净的方法,可以确保值不会被意外地写入原始数据帧。

我发现这是我在研究这个主题时遇到的解决方案中的一个统一线索。总结如下:

禁用警告

如果您知道自己在做什么,并且代码的行为符合预期,您可以选择通过禁用警告来取消警告[ ]:

# Example borrowed from [³]# Disables SettingWithCopyWarning globally
pd.set_option(‘mode.chained_assignment’, None)# Resets the warning option to default
pd.reset_option(‘mode.chained_assignment’)# Disables SettingWithCopyWarning locally within a context manager
with pd.option_context(‘mode.chained_assignment’, None):# YOUR CODE HERE

或者,您可以通过将 dataframe _is_copy属性设置为None [ ],取消警告。

# Example modified from [3]
In [38]: df = pd.DataFrame({…:     “A”: [1, 2, 3, 4, 5],…:     “B”: [6, 7, 8, 9, 10],…:     “C”: [11, 12, 13, 14, 15],…: }, index=range(5))…: …: dfa = df.loc[3:5]…: print(dfa._is_copy)<weakref at 0x7f4d64792810; to ‘DataFrame’ at 0x7f4d64784460>In [39]: dfa._is_copy = None…: dfa[“D”] = dfa[“B”] * 10 # No warning raised

请记住,让警告消失并不能解决不可靠的链式分配问题。链式作业是一个雷区,你可能会也可能不会踩到地雷。禁用警告就像移除雷区警告标志。精神食粮。

让警告不在第一时间出现

当遇到 SettingWithCopy 警告时,请花点时间跟踪链式赋值,并决定是要直接修改原始数据帧,还是将值赋给数据帧的副本。

处理原始数据帧

使用.loc索引直接给数据帧赋值。

# Modified from examples in [2]
In [40]: df = pd.DataFrame({…: “A”: [1, 2, 3, 4, 5],…: “B”: [6, 7, 8, 9, 10],…: “C”: [11, 12, 13, 14, 15],…: }, index=range(5))…:…: df.loc[df[“A”] % 2 != 0, “B”] = df.loc[df[“A”] % 2 != 0, “B”] + 0.5…: print(df)A B C
0 1 6.5 11
1 2 7.0 12
2 3 8.5 13
3 4 9.0 14
4 5 10.5 15

熊猫医生推荐这种方法有两个原因:

  • 使用.loc肯定会引用它所调用的底层数据帧。.iloc不具备这个属性。
  • .loc步进取代了链式步进,成为单一步进步骤。如果您参考上面带有视图和副本的链式分配下的示例,.loc索引将链式索引解析为单个__setitem__调用。

如果使用条件选择数据,可以考虑返回一个掩码,而不是原始数据帧的副本。屏蔽是一个布尔序列或数据帧,可方便地用于.loc索引,如下例所示:

# Modified from examples in [5]
In [41]: df = pd.DataFrame({…:     “A”: [1, 2, 3, 4, 5],…:     “B”: [6, 7, 8, 9, 10],…:     “C”: [11, 12, 13, 14, 15],…: }, index=range(5))In [42]: dfa = (df[“A”] <= 3) & (df[“C”] == 12)In [43]: df.loc[dfa, “B”] = 99 # dfa can be fed into the loc index!In [44]: print(df) # changes took place in the original dataframe A B  C
0 1 6  11
1 2 99 12
2 3 8  13
3 4 9  14
4 5 10 15

如果现有的索引逻辑很复杂,直接在原始数据帧上工作可能会很棘手。在这种情况下,您可以使用下一节中的方法之一返回一个副本,然后将它赋回原始数据帧[⁴].

为数据帧的显式副本赋值

使用assignwherereplace:

In [45]: df = pd.DataFrame({…:     “A”: [1, 2, 3, 4, 5],…:     “B”: [6, 7, 8, 9, 10],…:     “C”: [11, 12, 13, 14, 15],…: }, index=range(5))# 1\. Use the `assign` method to add columns
In [46]: df = df.assign(D=df[“C”] * 10)…: df = df.assign(**{“D”: df[“C”] * 10}) # allows passing variables as names# 2\. Use the `where` method to select values using conditionals and replace them
# Modified from examples in [2]
In [47]: df[“B”] = df[“B”].where(…:     df[“A”] < 2, df[“B”] * 10…: )# 3\. Use the `replace` method to select and replace values in the dataframe
# Modified from examples in [2]
In [48]: df = df.replace({“A” : 1}, 100)In [49]: print(df)A   B  C  D
0 100 6  11 110
1 2  70  12 120
2 3  80  13 130
3 4  90  14 140
4 5  100 15 150

将连锁作业步骤分解成单个作业[⁵]:]

# Examples borrowed from [4]
# Not these
df[“z”][mask] = 0
df.loc[mask][“z”] = 0# But this
df.loc[mask, “z”] = 0

一种不太优雅但十分简单的方法是手动创建原始数据帧的副本,并对其进行处理[ ]。只要不引入额外的链式索引,就不会看到 SettingWithCopyWarning。

In [50]: df = pd.DataFrame({…:     “A”: [1, 2, 3, 4, 5],…:     “B”: [6, 7, 8, 9, 10],…:     “C”: [11, 12, 13, 14, 15],…: }, index=range(5))In [51]: dfa = df.loc[3:5].copy() # Added .copy() here…: dfa.loc[3, “A”] = 10 # causes this line to raise no warning

重复上面的一些示例,而不触发带有副本的设置警告

where替换链接的赋值:

# (i)
df = make_clean_df()
dfa = df.loc[3:5]# Original that raises warning
# dfa[dfa % 2 == 0] = 100dfa = dfa.where(dfa % 2 != 0, 100) # df is not affected

将在索引数据帧上创建新列替换为assign:

# (ii) 
df = make_clean_df()# Original that raises warning
# dfa[“D”] = dfa[“B”] * 10dfa = dfa.assign(D=dfa[“B”]*10) # df is not affected

在使用.loc索引赋值之前,创建数据帧的副本:

# (iii)
df = make_clean_df()# Original that raises warnings
# dfa = df.loc[3:5]
# dfa[“A”][3] = 10# Create a copy then do loc indexing
dfa = df.loc[3:5].copy()
dfa.loc[3, “A”] = 10

注意,使用.loc索引直接给dfa赋值仍然会引发警告,因为对dfa的赋值是否也会影响df还不清楚。

真正根除带有复制警告的设置

就我个人而言,我喜欢将重要脚本的 SettingWithCopyWarnings 提升为 SettingWithCopyExceptions,使用以下代码:

pd.set_option(‘mode.chained_assignment’, “raise”)

这样做可以强制处理链式赋值,而不是允许警告累积。

根据我的经验,清理被 SettingWithCopyWarnings 阻塞的带有 stderr 的笔记本是一种特殊的禅。我真心推荐。

原创博文:在熊猫身上设置版权警告

[ ]:链式任务的官方“熊猫”文件。
[https://pandas . pydata . org/docs/user _ guide/indexing . html # returning-a-view-vs-a-copy](https://pandas . pydata . org/docs/user _ guide/indexing . html # returning-a-view-vs-a-copy)

[ ]:这是一篇关于数据科学的文章,简要介绍了几种处理带有拷贝警告的设置的方法。
[https://scribe . rip/@ towards data science . com/3-solutions-for-the-setting-with-copy-warning-of-python-pandas-dfe 15d 62 de 08】(https://scribe . rip/@ towards data science . com/3-solutions-for-the-setting-with-copy-warning-of-python-pandas-dfe 15d 62 de 08)

[]:data quest 关于此主题的深入文章。值得注意的是,在《熊猫》中有一节专门讲述了处理链式分配的历史。
[https://www . data quest . io/blog/settingwithcopywarning/](https://www . data quest . io/blog/settingwithcopywarning/)

[⁴]: StackOverflow 后,包含更多的连锁转让的例子。[https://stack overflow . com/questions/48173980/pandas-known-when-a-operation-affects-the-original-data frame](https://stack overflow . com/questions/48173980/pandas-known-when-a-operation-affects-the-original-data frame)

[⁵]: RealPython 的文章覆盖了这个主题。对我来说,RealPython 是仅次于官方图书馆文档的值得信赖的 goto 参考资料。本文进一步深入研究了 pandas 和 numpy 中的底层视图和复制机制,pandas 依赖于 numpy。
[https://real python . com/pandas-settingwithcopywarning/](https://real python . com/pandas-settingwithcopywarning/)

Python 中的 setup.py 与 setup.cfg

原文:https://towardsdatascience.com/setuptools-python-571e7d5500f2

使用setuptools来管理依赖项和分发 Python 包

弗勒在 Unsplash 上拍摄的照片

介绍

在我最近的一篇文章中,我讨论了[requirements.txt](/requirements-vs-setuptools-python-ae3ee66e28af)[setup.py](/requirements-vs-setuptools-python-ae3ee66e28af) 文件之间的区别,这些文件最终可以帮助开发人员管理他们的包的依赖关系,以一种他们也很容易重新分发它们的方式。

在今天的文章中,我将集中讨论setuptools包,并讨论setup.pysetup.cfg文件之间的区别。此外,我们还将讨论这些文件如何理解应该列出依赖关系的requirements.txt文件。

最后,我们还将讨论pyproject.toml文件的用途,以及在接受 PEP-517 后,包分发格局是如何改变的。我们还将演示如何以符合 PEP-517 和 PEP-518 的方式过渡到使用pyproject.tomlsetuptools

Python 中的 setuptools

[setuptools](https://setuptools.pypa.io/en/latest/)是一个构建在[distutils](https://docs.python.org/3/library/distutils.html)之上的库,该库已被弃用(从 Python 3.12 开始将被移除)。这个包提供了广泛的功能,方便了 Python 项目的打包,这是一个不断发展的过程,有时会变得相当具有挑战性。

所谓打包,我们通常是指依赖 管理打包 分发。换句话说,打包就是处理你的项目的依赖关系(甚至依赖关系的依赖关系等等),以及如何分发你的包,以使它可以被其他项目广泛使用。

setup.py 文件

setup.py文件可能是应该包含在根 Python 项目目录中的最重要的文件,它主要有两个主要用途:

  1. 它包含了与你的包相关的各种信息,包括选项和元数据,比如包名、版本、作者、许可证、最小依赖、入口点、数据文件等等。
  2. 用作允许执行打包命令的命令行界面。

示例 setup.py 文件

# setup.py placed at root directoryfrom setuptools import setupsetup(**name**='examplepackage'**version**='1.0.1',**author**='Giorgos Myrianthous',**description**='This is an example project',**long_description**='This is a longer description for the project',**url**='https://medium.com/@gmyrianthous',**keywords**='sample, example, setuptools',**python_requires**='>=3.7, <4',**install_requires**=['pandas'],**extras_require**={'test': ['pytest', 'coverage'],},**package_data**={'sample': ['example_data.csv'],},**entry_points**={'runners': ['sample=sample:main',]}
)

下面是对调用setup()方法时使用的关键字的解释:

  • **name**:这是一个对应于包名的字符串
  • **version**:对应包版本号的字符串
  • **author**:表示包的作者
  • **description**:这是包的简短描述的字符串(通常是单行描述)
  • **long_description**:包的更长描述的字符串
  • **url**:表示包的 URL 的字符串(通常是 GitHub 存储库或 PyPI 页面)。
  • **keywords**:这是一个逗号分隔的字符串(也可以是字符串列表),包含一些与包相关的关键字
  • **python_requires**:这是一个逗号分隔的字符串,包含包支持的 Python 版本的版本说明符。
  • **install_requires**:包含包成功运行所需的最小依赖项的字符串列表。
  • **extras_require**:字典,其中键对应于额外模式和值的名称,是包含所需最小依赖性的列表。例如,一个额外的模式可以是test,其中依赖项列表应该包括所有需要的附加包,以便执行包中定义的测试。
  • **package_data**:这是一个字典,其中键是包名,值是 glob 模式列表。
  • **entry_points**:这是一个字典,其中键对应于入口点名称,值对应于源代码中定义的实际入口点。

有关元数据和选项的可用关键字的更全面列表,您可以参考官方文档中的相关章节。

setup.cfg 文件

传统上,setup.py文件用于构建包,例如通过命令行界面使用build命令。

$ python setup.py build

在上面演示的示例setup.py文件中,我们看到大部分代码只是列出了一些关于 Python 项目的选项和元数据。事实上,就代码质量和设计而言,这可能不是最好的方法。因此,在setup.cfg文件中指定这些包细节可能更合适。

setup.cfg是一个 ini 文件,包含setup.py命令的选项默认值。您几乎可以在新的setup.cfg文件中指定我们在setup.py文件中使用的每个关键字,并简单地使用setup.py文件作为命令行界面。

示例 setup.cfg 文件

# setup.cfg file at the root directory**[metadata]**
name = examplepackage
version = 1.0.1
author = Giorgos Myrianthous
description = This is an example project
long_description = This is a longer description for the project
url = [https://medium.com/@gmyrianthous](https://medium.com/@gmyrianthous)
keywords = sample, example, setuptools**[options]**
python_requires = >=3.7, <4
install_requires = pandas**[options.extras_require]**
test = pytestcoverage**[options.package_data]**
sample = example_data.csv'

带有 setup.cfg 的 setup.py

现在假设您已经将所有选项移动到一个setup.cfg文件中,如前一节所述,您现在可以创建一个虚拟的setup.py,它将简单地调用setup()方法:

from setuptools import setupif __name__ == '__main__':setup()

关于如何使用setup.pysetup.cfg文件的更全面的例子,你可以参考 GitHub 上的 PyPA 示例项目。

pyproject.toml 文件和向 PEP-517 的过渡

截至 PEP-517 和 PEP-518 setuptools不再是打包 Python 项目时应该使用的事实上的工具。根据 PEP-518 的规范,Python 项目的构建系统依赖项应该包含在遵循 TOML 格式的名为pyproject.toml的文件中。

随着时间的推移,setup.py在 Python 社区中越来越受欢迎,但是setuptools的一个最大问题是,如果不知道可执行文件(即setup.py)的依赖关系,就无法执行它。除非您实际执行包含与包依赖关系相关的信息的文件,否则没有办法知道这些依赖关系是什么。

pyproject.toml文件应该解决构建工具依赖鸡和蛋的问题,因为pip本身可以读取pyproject.yoml以及项目所需的setuptoolswheel的版本。该文件需要一个用于存储构建相关信息的[build-system]表。

现在让我们把拼图拼在一起。如果您想使用setuptools,您现在必须指定一个pyproject.toml文件,其内容如下所示:

# pyproject.toml file specified at the root of the directory**[build-system]**
requires **=** **[**"setuptools>=42", "wheel"**]** # PEP 508 specifications.
build-backend **=** "setuptools.build_meta"

然后,您还需要指定一个setup.pysetup.cfg文件,就像我们在本教程的前几节中展示的那样。注意,我个人更喜欢后一种符号。

最后,您可以使用一个构建器来构建您的项目,比如 PyPA build,您可以通过 pip ( pip install build)来检索它,并最终调用构建器

$ python3 -m build

瞧啊。您的发行版现在可以上传到 PyPI 上了,这样它就可以被广泛访问了。

注意,如果你想在可编辑模式下安装软件包(即通过运行pip install -e .),除了setup.cfgpyproject.toml之外,你必须有一个有效的setup.py文件。您可以使用我在上一节中共享的同一个虚拟设置文件,该文件只对setup()方法进行一次调用。

那么我还需要 requirements.txt 文件吗?

简短的回答是, 大概是的setuptools文件应该保存抽象依赖关系,而requirements.txt应该列出具体依赖关系

为了更全面地了解requirements.txtsetuptools的目的,你可以阅读我最近分享的一篇文章。

最后的想法

在今天的文章中,我们讨论了setuptools包,以及如何利用setup.pysetup.cfg文件来管理包的依赖关系,使包在 Python 中的分发更加容易。

此外,我们讨论了可以指定的各种选项和元数据,以及setup.pysetup.cfg文件之间的差异。我们还讨论了关于requirements.txt文件以及如何使用它来完成 Python 包中的依赖管理难题。最后,我们介绍了 PEP517 和一个名为pyproject.toml的文件的用途。

最后,请记住 Python 中的包分发指南是不断发展的——尤其是在过去几年中——所以请确保随时更新并遵循最佳实践。

成为会员 阅读媒体上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

[## 如何将 Python 包上传到 PyPI

towardsdatascience.com](/how-to-upload-your-python-package-to-pypi-de1b363a1b3)

你应该知道的强化学习中的七个探索策略

原文:https://towardsdatascience.com/seven-exploration-strategies-in-reinforcement-learning-you-should-know-8eca7dec503b

纯探索和开发,ϵ-greedy,玻尔兹曼探索,乐观初始化,置信区间,知识梯度

霍利·曼达里奇在 Unsplash 上拍摄的照片

探索-开发困境在日常生活中无处不在。一旦你找到一家你喜欢的餐馆,你可能会决定下半辈子都去同一家餐馆,利用你积极的经历。然而,探索新的场地也有一定的吸引力。是的,你可能会有一些痛苦的经历,但你也可能会找到一个新的最爱!在探索和利用之间找到适当的平衡至关重要。

在强化学习中,困境同样重要。对于中等现实的问题,问题的规模是巨大的,计算是昂贵的(如果不是,我们可以只是列举)。因此,我们想要学习好状态的精确值,而不是在低质量的状态上浪费宝贵的(计算)预算。与此同时,过于狭窄的焦点可能会让我们陷入局部最优。

我们可以把这个问题形式化如下。给定某个度量预算,我们的目标是以这样一种方式分配我们的度量,即我们识别最显著的状态。根据大数定律,通过无限多的样本,我们将逼近一个状态的真实值。然而,有限的测量预算不能完全解决不确定性,样本均值可能偏离真实均值。换句话说,我们不确定我们是否真正确定了具有最高值的州。

*在这个上下文中,一个测量值是决定样品的一个特定状态。这个概念可以很容易地扩展到(顺序)动作选择问题,例如在 Q-learning 和 SARSA 这样的算法中遇到的问题。

出于本文的考虑,让我们假设状态空间是可枚举的,并且每个度量都有一个显著的成本(计算的或金钱的)。想一想在你的数字孪生环境中的冗长模拟或者真实世界观察——足以明智地选择你的测量。

这个问题可以想象如下。假设我们从一个噪声函数中采样,状态 x∈X 的测量值在真实平均值 μ_x 附近有一些不确定性(即标准偏差 σ_x )。通过绘制测量值,我们能够构建样本均值**——在本文中用 a ~表示——最终应该收敛到真实均值。然而,有限的测量预算意味着我们无法详尽地测量每个州。

**为简单起见,我们假设可以直接确定要测量的状态。将本文中的策略扩展到顺序决策问题是很简单的,在顺序决策问题中,我们选择引导我们进入新状态的行动。

够了解释,让我们转移到探索攻略!

一.纯粹的剥削

在像 Q-learning 和 SARSA 这样的算法中,你通常会在所有 Q 值上看到一些最大化器。在这个简化的问题设置中,我们等效地选择具有最高期望值的状态:

纯粹的剥削总是选择最好的已知状态。由于最初的估计往往很差,所以很容易陷入局部最优。

这个表达式暗示我们选择最好的状态,给定我们当前估计的状态值。尤其是在早期,这些估计可能非常糟糕。在没有先验知识的情况下,我们甚至可能简单地将状态值初始化为 0 或另一个任意数。

考虑到利用的本质,值的初始化非常重要(参见策略四)。假设你用零初始化你的表。然后,一个积极的观察就足以产生积极的回报估计,并观察相同的选项,直到时间结束。

即使我们在开发之前强制观察每个状态至少一次,最初的观察结果也可能与真实值相差甚远。因此,纯粹的开发倾向于对很少的状态给出非常精确的估计,通常会快速收敛到局部最优而忽略状态空间的大部分。

二。天真的探索

纯粹探索的两极对立是完全随机地探索状态。我们给每个状态分配一个相等的概率,并相应地采样:

天真探索随机选择一个州,对每个州赋予相等的概率。因为它没有考虑我们所学的值,所以样本效率很低。

这听起来很平均主义,但有一个问题。我们没有以任何方式考虑我们对状态值的知识,这意味着我们可能对有希望的状态进行欠采样,而对差的状态进行过采样。通过很多很多的观察,这个策略应该是可行的,但是正如我们之前提到的——测量通常是昂贵的。

三。ε-贪婪的

前两种策略有明显的警告,但放在一起,它们往往会产生相当不错的结果。概率ϵ(通常为 5%或 10%)和使用剥削剩余的 1-ϵ时间。因此,我们将大部分计算预算用于改进对有希望的测量的估计,同时加入偶然随机测量以避免局部最优。

ϵ-greedy 方法在开发(通常是大部分时间)和利用之间进行平衡,不时地进行随机测量并避免局部最优。

ϵ-greedy 通常是 RL 实现的默认度量策略,克服了纯探索和开发中的明显警告。ϵ的背景需要一些考虑,因为它决定了勘探和开发之间的平衡。我们也可以使它依赖于时间(例如,类似于 ϵ_n=1/n 的东西),在开始时产生一个随着测量次数减少的高探测率。谐波步长允许对时间行为进行更多控制,但代价是需要调整另一个参数。如果测量值很便宜,ε-贪婪政策通常可以很好地发挥作用,否则就是一种粗糙的方法。

四。乐观初始化

假设我们不用 0 来初始化 Q 值,而是用+∞来代替。第一个观察用样本平均值代替了 Q 值,使其对未观察到的状态相对没有吸引力。因此,乐观初始化强制每个状态至少被观察一次,因为它总是具有更高的预期回报。自然,初始值可以设置得更低(比如 10,000,或者任何适合问题的值)来稍微缓和一下乐观情绪。

初始化过程本身并不是一个测量策略,但是它会对其他策略的行为产生实质性的影响。如前所述,一个观察值可能不能很好地代表真实的平均值。

动词 (verb 的缩写)玻尔兹曼探索

ϵ-greedy 的方法平衡了探索和开发,但是在探索的时候是随机的。我们应该更频繁地测量“有希望的”状态(即,具有更高的期望值),这样才不会在低估计值的状态上浪费我们的测量值,而这些状态成为未经雕琢的钻石的可能性极小。

Boltzmann exploration 提供了一种优雅的方式,以与我们的期望成比例的方式来集中我们的测量预算。对于每个状态,它使用 softmax 函数定义一个采样概率:

Boltzmann exploration 利用 sofmax 函数来确定对每个状态进行采样的概率,返回与样本均值成比例的概率

对于那些熟悉离散 政策梯度算法的人来说,请注意,这里使用了相同的 sofmax 机制,根据预期回报为每个行动附加一个概率。

温度 ρ 可以固定在适合问题的水平,但是我们也可以根据执行的测量次数来改变它。通过逐渐降低温度,我们最初鼓励勘探,随着时间的推移,倾向于开采。

玻尔兹曼方法微妙地平衡了勘探和开发。我们仍然允许采样避开局部最优,但是也考虑我们收集的知识来集中我们的测量。然而,一个主要的缺点是,在能够计算分母之前,我们必须评估所有状态至少一次,这可能需要大量的工作。此外,温度 ρ 引入了一个必须调整的额外参数。

不及物动词乐观置信区间

到目前为止,我们只考虑了期望值的估计,而没有考虑这些估计中的不确定性。如果您有一些模拟经验,您可能知道——遵循大数定律——均值的置信区间(即标准误差)随着观察次数的增加而减少。使用乐观置信区间,我们选择具有最高上限的状态:

当使用乐观置信区间时,我们选择置信区间上限最高的状态。随着间隔随着更多的观察而缩短,该策略鼓励访问具有高度不确定性的国家。

例如,如果我们假设观察值是正态分布的,我们可以设置一个包含 95%概率的真实平均值的区间。我们进行的测量越多,间隔就变得越紧(注意,样本的方差没有减少,只是均值的方差减少)。

在测量一个状态至少两次后,我们可以计算它的标准偏差,从而得到它的平均值的置信区间。真实的均值可能在区间内的任何地方(同样:假设分布假设成立,并且具有给定的概率),那么为什么不考虑它可能在区间的顶部呢?

这正是乐观置信区间所反映的。我们不是根据预期的平均值来选择州,而是根据平均值的第 95 个四分位数。实际上,我们选择了一种形式的上界,一种最好的情况。因此,我们的估计的不确定性被明确地考虑在内,当更频繁地测量一个状态时,间隔缩小。

置信区间要求跟踪一个额外的变量(标准偏差)并测量每个状态至少两次,但是在我们的决策中明确整合测量不确定性的吸引力是显而易见的。虽然这种方法通常工作得很好,但是术语 z_α/2 没有特别的含义,必须由用户来调整。该方法也不能保证收敛。让我们看看我们是否能在那上面展开一点。

七。知识梯度

跟踪不确定性的概念可以通过形式化测量状态的临界值来扩展。假设我们还有一个测量要做,我们应该采样哪个状态来最大化我们的学习效果?这是知识梯度法回答的问题。在极限情况下,这种方法收敛到最佳状态。

就本文的目的而言,深入讨论知识梯度太过牵强。它植根于贝叶斯统计,其中我们假设状态的先验分布,并根据每次观察更新它们。在这种观点下,状态的均值和标准差是需要学习的随机变量。

类似于前述的置信区间,测量可能改变样本均值,使得状态成为新的最佳选项。在那种情况下,我们实际上学到了一些东西——我们进行了一项测量,改变了我们的决策。

下图显示了知识梯度的概念。在纯粹剥削的情况下,我们总是选择国家 A,因为它有较高的样本均值。然而,假设我们的下一个测量来自状态 B 的阴影区域;其样本平均值将成为最高值。由于我们知道分布情况,我们可以给抽取的样本附加一个概率。这正是驱动知识梯度的机制。

知识梯度算法图解。对于每个状态,该算法考虑测量将改变样本均值的样本的概率,使得它成为新的最佳状态。算法测量知识梯度最高的状态[图片由作者提供]

这个过程本身并不一定很难实现,但是它确实需要相当多的符号——对于这篇概述文章来说太多了。我希望很快在一篇独立的文章中介绍它,现在可以参考鲍威尔 T34 弗雷泽的优秀教程。

现在跳过实际的数学,总体思想的轮廓如下:

  • 跟踪观测值的样本均值样本方差,构建贝叶斯模型
  • 计算表示测量状态 x 相对于所有其他状态 x'≠x 的相对值的度量
  • 将指标插入累积密度函数概率密度函数,捕捉测量值将产生所有状态的最佳平均值的分布部分
  • 在此基础上,计算知识梯度以反映测量状态 x边缘值
  • 选择知识梯度最高的州

虽然这份名单上最复杂的,但它显然也是最不直观和最复杂的。如果测量预算真的是一个问题,它可能值得麻烦,否则更简单的方法可能就足够了。

下次您实现 RL 算法时,不要盲目采用标准的ε贪婪方法,而是考虑探索一些替代策略!

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

  • 纯剥削 —始终选择样本均值最高的州。
  • 纯探索 —始终选择随机状态。
  • ε-贪婪——纯粹的剥削,但是选择一个随机的行动(探索)带有一些概率ϵ.
  • 乐观初始化 —以鼓励或强制探索的方式初始化未知状态的值,至少观察每个状态一次。
  • 玻尔兹曼探测 —样本状态与其估计值成比例,针对可能随时间降低的探测温度进行校正。
  • 乐观置信区间 —将样本均值置信区间的上限作为确定测量值的代理,乐观地考虑测量值的不确定性。
  • 知识梯度 —假设测量值的先验分布,并随时间更新。选择具有最高边际信息值的状态,即成为新的最佳状态的最高概率。

参考

鲍威尔。W. B .和 Frazier,P. (2008 年)。*优学。*运筹学教程。可用在线。

每个熊猫用户都应该知道的七个黑仔内存优化技术

原文:https://towardsdatascience.com/seven-killer-memory-optimization-techniques-every-pandas-user-should-know-64707348ab20

优化熊猫记忆利用的简单技巧

丹尼斯·简斯在 Unsplash 拍摄的照片

设计和构建现实世界中适用的机器学习模型一直是数据科学家的兴趣所在。这不可避免地导致他们大规模利用优化、高效和准确的方法。

运行时和内存级别的优化在可持续交付真实世界和面向用户的软件解决方案中扮演着基础角色。

优化分类(按作者分类的图片)

在我之前的一篇文章中,我介绍了一些顶级的运行时优化技术,您可以在常规的数据科学项目中使用这些技术。

在这篇文章中,我们将探索优化的另一个领域,我将向你介绍一些令人难以置信的技术来优化你的熊猫数据帧的内存使用

这些提示将帮助您在 Pandas 中有效地执行典型的表格数据分析、管理和处理任务。

为了得到一个简要的概述,我将在这篇文章中讨论以下主题:

#1 就地修改数据帧# 2 只读 CSV 中必需的列# 3-# 5 更改列的数据类型# 6 在读取 CSV

我们开始吧🚀!

#1 对数据帧进行就地修改

一旦我们将数据帧加载到 Python 环境中,我们通常会对数据帧进行大范围的修改,不是吗?这些包括添加新列、重命名标题、删除列、改变行值、替换 NaN 值等等。

这些操作通常可以通过两种方式执行,如下所示:

熊猫数据帧操作的分类(图片由作者提供)。

标准赋值旨在转换后创建数据帧的新副本,保持原始数据帧不变。

从给定的数据帧创建新的数据帧(图片由作者提供)。

作为标准分配的结果,两个不同的熊猫数据帧(原始的和转换的)在环境中共存(上面的dfdf_copy),加倍了存储器利用率。

与标准赋值操作相反,就地赋值操作打算修改原始数据帧本身,而不创建新的 Pandas 数据帧对象。下面演示了这一点:

执行就地操作(Gif 由作者提供)

因此,如果 DataFrame 的中间副本(df_copy)在您的项目中没有用处,那么在内存受限的应用程序中,采用就地赋值的方法是最理想的方法。

你可以在下面阅读我关于就地分配操作的详细帖子:

关键要点/最终想法:

  1. 当需要中间数据帧,并且不想改变输入时,使用标准赋值(或inplace=False)。
  2. 如果您正在处理内存限制,并且不特别使用中间数据帧,请使用就地赋值(或inplace=True)。

# 2 CSV 中的只读必填列

只阅读感兴趣的栏目(图片由作者提供)。注意:CSV 文件是一个文本文件,上面的插图不是 CSV 的样子。这只是为了直观地阐述观点。

设想一个场景,您的 CSV 文件中有数百列,其中只有一部分列是您感兴趣的。

例如,考虑我使用 Faker ( filename : dummy_dataset.csv)创建的具有 25 列和 10⁵行的虚拟数据帧的前五行:

虚拟数据集(作者提供的 Gif)

在这 25 列中,假设只有 5 列是您最感兴趣的,并且您希望将它们作为 Pandas 数据框架加载。这些列是Employee_IDFirst_NameSalaryRatingCompany

  • 加载所有列:

如果您打算将整个 CSV 文件读入 python 环境,那么 Pandas 将被迫加载那些无用的列并推断它们的数据类型,从而导致运行时间和内存使用量的增加。

我们可以使用如下所示的[info()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html)方法找到熊猫数据帧的内存使用情况:

在加载了所有 25 列的情况下,数据帧在内存中拥有 137 MBs 的空间。加载 CSV 文件的运行时间计算如下:

  • 加载所需列:

与读取所有列相反,如果只有您感兴趣的列的子集,您可以将它们作为列表传递给[pd.read_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)方法的usecols参数。

内存利用率的计算如下所示:

仅加载感兴趣的列将内存利用率降低了近 9 倍,占用了大约 15 MBs 的空间,而不是之前的 137 MBs。

加载运行时间也显著减少,与加载所有列相比,提升了近 4 倍

关键要点/最终想法:

  1. 只加载所需的列可以显著提高运行时间和内存利用率。因此,在加载大型 CSV 文件之前,只加载几行(比如前五行)并列出感兴趣的列。

# 3–5 改变列的数据类型

熊猫的数据类型转换(图片由作者提供)

默认情况下,Pandas 总是将最高的内存数据类型分配给列。例如,如果 Pandas 将一个列解释为整数值,则可能有四个子类别(有符号)可供选择:

  • int8 : 8 位整数,包含来自【2⁷].-2⁷】的整数
  • int16 : 16 位整数,包含[-2 ⁵,2 ⁵].]中的整数
  • int32 : 32 位整数,涵盖[-2,2 ]中的整数。
  • int64 : 64 位整数,包含来自【2⁶-2⁶】的整数。

然而,Pandas 总是将int64指定为整数值列的数据类型,而不管列中当前值的范围。

浮点数值也有类似的含义:float16float32float64

注意:我将引用我们在上一节中讨论的同一个虚拟数据集。下面,我再次提到了数据类型。

数据帧的当前内存利用率为 137 MBs

  • 改变整数列(#3)的数据类型

降级整数数据类型(图片由作者提供)

让我们考虑一下Employee_ID列,求它的最大值和最小值。

请注意,即使该列可能被解释为int32 (2 ⁵ < 10⁵ < 2),熊猫仍然采用int64类型作为列。

幸运的是,Pandas 提供了使用[astype()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html)方法改变列数据类型的灵活性。

下面演示了Employee_ID列的转换,以及转换前后的内存使用情况:

通过这个简单的单行数据类型转换,Employee_ID列使用的总内存减半。

通过类似的最小-最大分析,还可以改变其他整型和浮点型列的数据类型。

  • 改变代表分类数据的列的数据类型(#4)

转换为分类列(作者图片)

顾名思义,分类列是只包含几个唯一值的列,这些值在整个列中反复出现。

例如,让我们使用如下所示的[nunique()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.nunique.html)方法找出几列中唯一值的数量:

这些列中唯一值相对于数据帧大小的数量表明它们是分类列。

然而,默认情况下,Pandas 将所有这些列的数据类型推断为object,这实际上是一个string类型。

使用astype()方法,您可以将分类列的数据类型更改为category。内存利用率的降低如下所示:

随着从字符串到分类的转换,我们注意到内存利用率下降了 75% ,这是一个巨大的下降。

通过类似的唯一元素分析,您可以改变其他潜在分类列的数据类型。

  • 改变具有 NaN 值(#5)的列的数据类型

将各种数据类型转换为稀疏类型(图片由作者提供)

在现实世界的数据集中,缺失值是不可避免的,不是吗?假设数据帧中的一列有很大比例的 NaN 值,如下所示:

在这种情况下,将列表示为一个备用数据结构(在接下来的文章中会详细介绍)可以提供显著的内存效率。

使用astype()方法,您可以将稀疏列的数据类型更改为Sparse[str] / Sparse[float] / Sparse[int]数据类型。内存利用率的降低和数据类型的转换如下所示:

float32Sparse[float32]的转换减少了近 40%的内存使用,这大约是Rating列中 NaN 值的百分比。

关键要点/最终想法:

  1. Pandas 总是用最大的内存数据类型来解释它的列。如果列中的值范围没有跨越数据类型的范围,请考虑将列的数据类型降级为最佳类型。

您可以在这个 StackOverflow 答案中找到执行这些数据类型转换的参考代码。

#6 在读取 CSV 时指定列数据类型

上面 #3-#5 小节中讨论的技巧假设您已经在 python 环境中加载了一个熊猫数据帧。换句话说,这些是优化内存利用的后输入技术。

但是,在加载数据集是主要挑战的情况下,您可以控制 Pandas 在输入期间执行的数据类型解释任务,并指定您希望您的列被推断为的特定数据类型。

为熊猫提供数据类型说明(图片由作者提供)。注意:CSV 文件是一个文本文件,上面的插图不是 CSV 的样子。这只是为了直观地阐述观点。

可以通过将dtype参数传递给pd.read_csv()方法来实现这一点,如下所示:

如上所示,dtype参数期望从column-namedata-type的字典映射。

关键要点/最终想法:

  1. 如果您通过数据字典或其他来源知道 CSV 的某些(或所有)列中的数据类型,尝试自己推断最合适的数据类型,并将其传递给pd.read_csv()方法的dtype参数。

#7 从 CSV 中读取数据块

分块读取文件(图片由作者提供)。注意:CSV 文件是一个文本文件,上面的插图不是 CSV 的样子。这只是为了直观地阐述观点。

最后,假设您已经在提示#6 中做了所有可能做的事情,但是由于内存限制,CSV 仍然无法加载。

虽然我的最后一项技术无助于优化净内存利用率,但它更适合加载大型数据集,您可以在这种极端情况下使用。

熊猫的输入法是连载的。因此,它从 CSV 文件中一次只读取一行(或一行)。

一次读取一行(作者 Gif)。注意:CSV 文件是一个文本文件,上面的插图不是 CSV 的样子。这只是为了直观地阐述观点。

如果行数非常大,无法一次加载到内存中,您可以加载一段(或一大块)行,对其进行处理,然后读取 CSV 文件的下一段。下面演示了这一点:

在熊猫里分块处理数据(作者 Gif)。注意:CSV 文件是一个文本文件,上面的插图不是 CSV 的样子。这只是为了直观地阐述观点。

您可以通过将chunksize参数传递给pd.read_csv()方法来利用上述基于块的输入过程,如下所示:

每个chunk对象都是一个熊猫数据帧,我们可以使用 Python 中的type()方法来验证这一点,如下所示:

关键要点/最终想法:

  1. 如果 CSV 文件太大,无法加载到内存中,请使用分块方法加载 CSV 的片段并逐个处理它们。
  2. 这种方法的一个主要缺点是不能执行需要整个数据帧的操作。例如,假设您想要在一列上执行一个groupby()操作。这里,对应于一个组的行可能位于不同的块中。

结论

总之,在这篇文章中,我讨论了 Pandas 中的七种令人难以置信的内存优化技术,你可以在下一个数据科学项目中直接利用它们。

在我看来,我在这篇文章中讨论的领域是优化内存利用率的微妙方法,在寻求优化时经常被忽略。尽管如此,我希望这篇文章能让你深刻理解这些熊猫的日常功能。

感谢阅读!

🧑‍💻成为数据科学专家!获取包含 450 多个熊猫、NumPy 和 SQL 问题的免费数据科学掌握工具包。

✉️ 注册我的电子邮件列表 永远不要错过另一篇关于数据科学指南、技巧和提示、机器学习、SQL、Python 等的文章。Medium 会将我的下一篇文章直接发送到你的收件箱。

成为更好的数据科学家我遵循的七条原则

原文:https://towardsdatascience.com/seven-principals-i-follow-to-be-a-better-data-scientist-25a547d6acfc

照片由海蒂·芬在 Unsplash 拍摄

树立我的北极星

时间过得真快,我已经在两家不同的公司担任数据科学家超过一年半了。在我之前的文章中,我写了我作为经济学博士如何成为一名数据科学家。在文章的最后,我分享了我在该行业工作时收集的一些想法。我想在这篇文章中进行更多的阐述,并总结出成为一名更好的数据科学家需要遵循的七条原则。

原则 1:沟通是关键

沟通是建立任何关系的关键。在员工中,我们通过与同事、上司、利益相关者、客户等互动,不断扩大我们的网络。即使作为一个任务更加面向研究的人,我花了很多时间编写代码和测试模型,沟通仍然在我的日常任务中扮演着非常重要的角色。我需要收集和验证来自 IT 团队的数据;我需要与同事讨论模型开发进度;我需要向利益相关者/经理等传达发现和见解。有效的沟通非常重要,尤其是在疫情之后远程工作越来越普遍的时候。我的建议是,在你的日历上以一定的频率与你需要沟通的每个人预约同步会议,并不断更新你的项目进度,包括里程碑和挑战。

除了与任务相关的交流,另一个重要的部分是交流你的发现。作为数据科学家,很多时候我们面临着向非技术受众传达新奇的技术内容的挑战。在这种情况下,一个常见的错误是专注于展示研究结果背后的复杂模型和算法,并展示它是多么前沿。除非是学习阶段,否则很多时候这种交流只会让听众感到困惑。为什么他们那么在乎你怎么得到结果(即使你花了大部分时间在这部分),他们只需要知道如何利用这些信息。数据科学不仅仅是编码和花哨的模型。它所揭示的商业价值才是在交流中应该强调的。作为一个从学术界出来的人,我花了一些时间来适应快节奏的环境,并学习如何识别我的非技术观众的痛点。开发一流的模型仅仅是第一步,只有让其他人看到你作品的价值,并最终信任和购买它,你的任务才能完成。

在交流研究结果时,数据讲述能力和演示技巧是必不可少的,这也是我督促自己提高的地方。我收集的一些好的建议是观察好的演讲者,练习公开演讲,在演讲前总是排练,并不断地从你的观众那里寻求反馈。

原则 2:快速学习,边做边学

数据科学是一个不断变化的领域,因此跟上最新的趋势和技术对于确保工作中的一致性能至关重要。对于全职工作的数据科学家来说,花几周时间学习新东西以便能够将其应用到工作项目中是不现实的。我们需要快速学习,实现这一点的方法之一就是通过边做边学。与其迷失在一个新概念的太多细节和背景信息中,完全掌握它的最快方法是遵循一个值得信赖的实用教程并复制它,然后尝试进行定制创新,以在您的项目中取得更好的结果。举个学习随机森林算法的例子。我们确实需要知道一些关于算法的基础知识——它是什么,它可以用在哪里,等等。然后我们只是在当前的项目中使用它,跟随一些教程,看看结果是什么。与教科书或在线课程相比,带有示例的博客文章是快速自学的绝佳来源。最后,我们对结果进行故障排除,并寻找改进算法应用的方法。比如算法的超参数是什么,怎么调等等。

快速学习让我们跟上时代。它主要是问题驱动或项目驱动,其中快速学习为我们提供了短期解决方案。从长远来看,我们应该有一个坚实的计划来提高某些技能,这些技能可能需要更多的持续练习。在这种情况下,我们需要养成学习的习惯。我们可以报名参加学习特定技能的课程。最重要的是,我们应该接触数据科学的最新实践,即使它们可能与我们的日常工作无关。我订阅了许多科技公司在 Medium 上的科技博客( instacart 、 Airbnb 、 Lyft 、网飞等),以及数据科学简讯,只是为了了解社区周围发生的事情,并进一步探索我感兴趣的事情。我们还可以扩大我们的网络,并形成我们自己的学习社区,在那里我们可以分享我们所学到的东西,以及新的东西。最后,**根据著名的费曼法则,**利用教学的力量来更好地学习。这是我开这个博客的主要原因。

原则 3:发展专家领域

我从作为数据科学家的工作中收集到的另一个想法是,我们不需要成为所有方面的专家,但我们需要开发数据科学的专家领域。这使你成为一名杰出的数据科学家,而不仅仅是一名可以被轻易取代的有用的数据科学家。数据科学是一个需要大量协作的职位。你需要什么都懂一点,才能和同事用同一种语言交流。然而,你应该优先考虑你的时间和精力,在至少一个你有全面了解的特定领域工作,并且你要让自己成为任何人在这个领域有任何问题都要去解决的人。这很像在博士项目中,你选择一个领域来完成你的论文,在那里你用这个领域中所有重要的文献来更新自己,你提出并解决这个领域中的问题,你研究并开发这个领域中的新方法,并且有可靠的发现来分享。在数据科学、预测、因果推理、NLP 等领域都有很多。根据你的背景和激情,确定某些领域,并在这些领域建立全面的知识体系。最重要的是,宣传自己是这些领域的专家(或即将成为专家),就与这些领域相关的任何事情提出你的意见,以增加你在员工中的知名度和影响力。

原则 4:高效编码

对数据科学家来说,编码的确很重要,但在我看来,与解决问题、批判性思维等相比,它不是最重要的硬技能。作为一名初级数据科学家,我们需要编码来完成我们的工作,但是随着我们职业生涯的发展,我们和其他人的区别不太可能来自于编写花哨的代码,而是你可以用代码交付什么。编码是手段,不是目的。不要误解我的意思,我认为能够高效、干净地编写代码是很重要的,尤其是当你和别人一起做一个项目的时候。我的观点是,与其花大量时间浏览教程,阅读关于如何编码和如何干净编码的教科书,不如尝试向有经验的人学习,总结好的实践,并确保将它们应用到自己的项目中。很多时候,在工作中,你不需要从头开始写代码,因为可能已经存在一些相关的项目。作为一个没有数据科学或计算机科学背景的人,我总是着迷于我同事的代码是多么干净、不言自明和高效。我请他们和我一起进行代码评审,向他们学习,并根据他们使用的代码编写我的代码模拟。编码是通过复制来创造。

关于编码的另一个重要方面是,我们应该为模块化代码片段建立一个数据库,特别是那些你经常在不同空间重用的代码片段。每当在同一个项目中或跨项目重复使用时,编写函数和类是非常有用的。一些公司会购买智能和用户友好的工具,这些工具已经存储了模板代码片段,数据科学家只需要定制数据输入或参数,以便获得漂亮的数据可视化或找到最佳模型。

我给那些从事最终将投入生产的端到端项目的人的另一个建议是建立一个项目文件夹,并将不同的任务模块化。您将有几个 python 文件负责数据清理、要素工程、模型训练中的不同任务,还有一个主文件导入和调用不同的对象来完成端到端的过程。很容易做出任何改变,重新训练模型,更新数据集,并最终将项目投入生产。

作者图片

原则 5:培养商业头脑

为了准备面试,你可能需要在案例研究回合中,对你面试的公司的商业模式进行自我教育。在工作中,你将假设的案例研究问题投入生产。你不仅需要提出解决方案,还要实施和推出最终产品。在整个过程中,你需要培养商业敏锐性:

  • 了解你正在处理的数据:每一列是什么意思?价值观缺失怎么处理?是分割数据还是对数据进行聚类?获取或生成哪些有用的特征?我可以在这里使用哪些有用的内部或外部数据集?
  • 知道如何建立模型来解决不同的问题:一个线性基线模型就足够了,还是我需要使用复杂的深度学习模型?我如何在可解释性和模型复杂性之间做出选择?我应该使用什么指标来确保我的模型针对业务难点?
  • 知道如何宣传你的工作:为什么我的项目有意义(或者通过 xxx 赚到$$$或者通过 xxx 省下$$$)?我应该如何量化效果?

了解你正在处理的业务是第一步。很多时候,我们可能太急于跳入技术细节,而没有看到全局。知道如何增加影响和宣传你的项目带来的价值与完成项目一样重要。

原则 6:学会管理工作量和优先处理任务

管理工作量通常是我们忽略的事情,尤其是在我们职业生涯的初期。我们希望对所有事情都说是,以建立良好的声誉,避免示弱。**知道何时以及如何说不是我们应该培养的一种品质。**尽管接受挑战和走出舒适区对确保持续增长很重要,但推动自己前进和筋疲力尽之间有着明显的区别。推动和挑战自己前进是积极主动的,也是主动的。这是你选择为自己做的事情,以发展你的核心技能,实现你为自己设定的目标。你会激励自己非常努力地工作,而不觉得累,反而很有成就感。另一方面,精疲力尽对我们的心理健康是一种威胁,从长远来看,它会逐渐危及我们的生产力。这是你由于超负荷的责任而被迫做的事情。倦怠发生的比你所知道的要多。当你对工作感到非常紧张和焦虑,真的需要休息时,就会发生这种情况;当你不能专注于你正在做的事情,因为你担心所有其他等待完成的任务;即使在工作时间之外,你也无法停止思考工作。无论何时发生,都是你的身体试图警告你摄入过多。倦怠有不同的阶段,如果你只是强迫自己度过难关,它会随着时间的推移而升级。

要处理它:

  • 第一步是识别信号。问问你自己为什么我今天没有效率,是因为我过去几天工作太多了吗?
  • 不要过度承诺。合理对待你的工作量和你完成它们的能力。不要害怕诚实和示弱。允许自己有不知道的事,不擅长的事,不熟悉的事。只要你有计划去提高你所需要的关键技能,并且知道如何与人合作,你就不应该对自己太苛刻,去做最好的事情。如果这次你想通过过度承诺来让自己度过一个巨大的任务,问问自己这种努力是否是可持续的,你是否能在未来的所有时间里强迫自己度过。如果不是,为什么这次要这么做?职业成长是一场长跑游戏,不是短跑。
  • **在接受额外任务时,总是要分清轻重缓急。**有时,我们确实会收到来自工作伙伴的特别请求。每当你预见到这些任务不会很快完成时,就和你的经理一起调整你已经拥有的所有任务的优先级,这样你就知道你把所有的精力都放在了最重要和最紧急的任务上。

时间管理和心理健康在职业和个人生活中都非常重要。我们真正需要做的是知道我们的界限,沟通我们的界限,并学会对事情说不,这样我们就可以把时间和精力集中在更重要的元素上。

原则 7:方向比速度更重要

很多时候,我们专注于提高实现目标的速度,你有没有想过,在这个目标上花时间是否值得?如果是这样,另一个问题是你是否在朝着正确的方向接近这个目标。如果你的目标是获得晋升,与从事多个小项目相比,从事影响力更大、知名度更高的项目更有可能得到领导的认可。拥有良好的演示和讲故事的技能会让你有更好的机会宣传你自己和你的项目,让别人看到你,而不是只专注于实现最花哨的模型和技术细节,却不能让别人看到价值。

每个人的时间和精力都是有限的,因此我们需要将它们转化为正确的效用函数来解决优化问题。我们怎么知道什么是正确的方向?我们可以寻求他人的建议,参加课程,阅读书籍/文章,等等。然而,这些都是别人的经验,可能与我们自己的不一致。除了参考他人,我们需要问问自己,我们真正想要的生活是什么。我们需要睁大眼睛看所有可能的方向,去探索。当然,我们可能会在这个过程中犯错误,这就是为什么我们要不断地探索、反思和总结。我在做我喜欢的事情吗?我走的路对吗?快速到达目的地,却不是你想要的目的地,有什么意义?只要我们知道我们正在到达我们真正渴望的地方,而不是因为别人告诉我们,绕道而行,晚点到达也没关系。我们不会通过阅读别人的故事找到自己的激情。我们需要探索自己的可能性。这对职业和个人生活都是如此。

摘要

总而言之,我遵循的七个原则是:

  • 沟通是关键
  • 快速学习,边做边学
  • 发展专家领域
  • 高效编码
  • 培养商业头脑
  • 学会管理工作量和区分任务的优先级
  • 方向比速度更重要

我上面列出的所有原则也是相互关联的。例如,我们需要培养商业敏锐性,知道什么是正确的方向,然后知道如何通过优先化任务来管理我们的工作量。你能想到其他人会如何联系吗?

免责声明

这些是我总结的原则,基于我的经验和我对在这个行业工作不到两年的员工的理解,以及我从不同来源收集的建议。作为一名初级数据科学家,我可能有自己的局限性,因为我的工作更多的是基于研究。我们非常欢迎你在下面留下评论,添加你认为重要但没有在这里列出的其他原则。或者根据自己的经历阐述你同意或不同意的某些原则。

感谢您的阅读!如果感兴趣,请查看我的其他文章:

https://zzhu17.medium.com/my-blog-posts-gallery-ac6e01fe5cc3

订阅我的电子邮件列表:

https://zzhu17.medium.com/subscribe

注册成为中级会员:

https://zzhu17.medium.com/membership

或者在 YouTube 上关注我:

https://youtube.com/channel/UCMs6go1pvY5OOy1DXVtMo5A

香农信息——我们发现了信息的原子

原文:https://towardsdatascience.com/shannon-information-theory-discovering-particles-of-information-ab2c136c6a25

物理对象有原子,信息有比特。克劳德·香农认为,信息虽然无形,但可以量化……

图片来自 Pixabay 的奇莫诺。

当球滚过桌面时,它掉了下来。我从未质疑过为什么会这样,因为从我们出生的那一天起,我们就一直在可观察的宇宙中与物理对象互动并观察它们的反应。如果我们看到一个事件重复了足够多,我们就开始接受它是“世界是如何运转的”。

我们不仅对这个世界的物理学有些熟悉,而且 19 世纪早期原子的发现也让我们对为什么它会起作用的基本原理有了更细致的了解。有具体的证据——可观察的,可量化的。

但是抽象的想法呢?我们看不见信息,也摸不着它。我们知道它的存在,但缺乏物理性使它的理解变得复杂,并使处理信息比它需要的更不直观。这就引出了一个问题……有没有一些不可分割的单元或者某种大统一理论像原子对物体一样塑造信息?

也许吧。

如果我们追根溯源,我们会发现香农的信息论。

  • 什么是信息?
  • 我们能量化信息吗?
  • 我们如何利用香农的信息内容?
  • 一个单位的信息有多大用处?
  • 香农信息量的实际应用

什么是信息?

想想上一次你读一篇很棒的媒体文章时,你对自己说,“这是令人难以置信的信息,”当你靠在椅子上,沉浸在绝对的满足中。

为什么?为什么信息丰富?

当有东西需要学习时,大多数人使用“信息丰富”这个词。它应该要么…

  • 引入新的视角,
  • 强化当前的信念,或者
  • 使以前的真理无效。

不管是哪一种,它都是有益的,因为它改变了我们对世界的理解——我们的信仰。

我们生活的世界是如此不合理地动态和复杂,不可能在生活的每个方面都获得绝对的知识。每天,我们都被迫在信息不完整的情况下度过一生。随着新信息的出现,我们调整自己的信念,使之更好地与现实相一致,这样我们就能做出更好的决定。

由于我们对大多数事情都不是 100%确定,我们的观点很少是简单的二元“是”或“否”。相反,它们更好地表达为 0 到 1 之间的连续光谱,表明我们的信心水平。

信念通常是介于两者之间的,而不是二元的。孙、雨、删除、勾选图标由 Freepik hqrloveq 从 Flaticon 创建,经作者许可编辑。

如果有人问天气,在没有更好了解的情况下,我们会有一半的猜测。但是给定一份包含相关信息的天气预报报告,我们会偏向其中一个。

信息改变信仰。

信息是当前信念和事实之间的差异。太阳和雨图标由 Freepik 从 Flaticon 创建,经作者许可编辑。

虽然我们使用了天气预报报告作为类比,但我希望我没有描绘出关于信息需要如何成为报告、数字或一些条形图的错误画面。不一定非要这样。

信息是无形的。

正是这种抽象的“东西”可以以任何形状或形式表现出来——视觉、听觉、味觉,甚至嗅觉。重要的是,当消费时,它改变了我们的视角。

好像信息本身的概念还不够模糊,不幸的是,信念也可能是主观的。世界上有 70 亿人,每个人都有自己的经历、文化和价值观。当我们经历如此不同的世界时,不可避免地会发现截然不同的观点和信仰。你认为有价值的东西不会给别人。

想象一下看一本幼儿园的书。我怀疑我们会像一个 2 岁的孩子一样感到满足。

信息是个人的。

重点是—

信息是有意义知识的概念。它的存在取决于我们对世界的已知。如果它让我们离真相更近了一步,那么它就是信息。

信息改变信仰。

信息是无形的。

信息是个人的。

我们能不能把这样模糊的东西拿出来正式定义?

我们能量化信息吗?

答案是肯定的,而且看起来是这样的…

香农的信息量公式。

但是与其从表面上接受它并接受它定义了信息,不如理解为什么它有意义更有意义。

我建议我们从头开始推导公式。

之前,我们已经在信息和信念之间建立了联系。如果信念受到挑战时信息存在,那么我们知道信息需要被定义为信念的函数。

除此之外,重要的是要注意信息和信念不会一起增加。恰恰相反。当我们观察到我们认为不太可能的事件时,我们会感到惊讶,并质疑我们信念的正确性。因此,当我们错得最多的时候,我们收获最多。反之亦然。

我们的信念越符合事实,我们得到的信息就越少。太阳和雨图标由 Freepik 从 Flaticon 创建,经作者许可编辑。

如果我们必须用数学结构写下这种相反的关系,它会是这样的

信息是我们信念的函数,p(x)。

信息量与我们的信念相反。图片由作者提供。

从视觉上看,曲线符合我们所寻找的反向关系的描述。这是一个很好的开始,但是概率应该只在 0 到 1 之间。我们需要解决这个问题。

除此之外,还有两个小缺陷违反了我们试图建立的逻辑。问题在于 p(x) = 0 和 1 的两个极端,在这两个极端,直线变得越来越靠近轴,但从未真正接触过轴。

这说不通。

当一个事件的概率为 0 时,意味着它永远不会发生。如果它永远不会发生,那么我们将无法量化这些信息,也没有必要这样做。

另一方面,当事件的概率为 1 时,我们只是在观察一个已知的事实,因此应该没有新的信息需要学习。

  • 当 p(x) = 0 时,信息应该是未定义的。
  • 当 p(x) = 1 时,信息应该为零。

这需要对我们的公式稍加修改。应用对数有一些有趣的性质,可以帮助我们满足所有的标准。

信息是我们信念的对数的函数,p(x)。

添加一个日志可以改善曲线。删除和勾选图标由 hqrloveq 从 Flaticon 创建,经作者许可编辑。

既然这两个极端是固定的,曲线是解释信息更合理的方式。从这里开始,我们可以用一点数学魔法重新排列我们的公式,它会给我们一个和克劳德·香农用来描述信息内容的公式完全一样的公式。

推导香农的信息量。

虽然这个公式起初看起来像是胡言乱语,但如果我们在窗帘后面窥视,香农信息量只是一种古怪的方式来表达信息的是信念变化的幅度。

我们如何使用香农的信息内容?

有了一个公式,我们就有了一个量化的方法来跟踪系统中的已知和未知。它为我们提供了一个系统的方法来回答这三个问题:

  • 有多少需要知道?
  • 我们学到了多少?
  • 我们还不知道多少?

为了证明这一点,我为我们准备了 8 个相同的宝箱。所有的箱子都是空的,除了一个,所以我们有 1/8 的机会打开正确的箱子。

宝箱被打乱了,所以我们不知道哪一个有宝藏。宝藏图标由 Flaticon 的 Smashicons 创作,经作者许可编辑。

第一个问题是——我们需要多少信息才能百分之百确定地打开正确的箱子?一点点?很多吗?Claude Shannon 的《信息内容》( Information Content)没有玩弄这种模糊的确定性概念,而是认为我们恰恰需要 3 个单位的信息,或者如他所说的 3 比特

找到宝藏的概率是 1/8,因此我们需要 3 比特的信息。

香农声称……如果我们有 3 比特的信息,我们将知道整个系统的所有信息。让我们一个个打开箱子,观察一路上信息是如何获得的,验证这个说法的有效性。

当我们打开箱子时,我们了解了更多关于这个系统的信息。宝藏(关闭、填充)、删除、勾选图标由 Smashicons 和 hqrloveq 从 Flaticon 创建,经作者许可编辑。

打开第一个箱子发现里面是空的。有 7/8 的机会观察到这样的事件,所以我们已经了解了 0.193 比特的信息。对于我们打开的每一个空宝箱,找到另一个空宝箱的概率越来越低,因此,我们从每个宝箱中获得的信息量稳步增加。

随着我们获得的信息越来越多,这个系统剩余的不确定性就越来越少。在中间点,我们已经获得了 1 位信息,只剩下 2 位信息有待发现。通俗地说,就是我们比开始的时候更确定宝箱在哪里。这似乎很合适,因为只剩下 4 个箱子了。

在第六个箱子上,信息增益突然激增,因为我们设法找到了宝藏(有 1/3 的概率)。超过这一点,我们就不再得到任何信息,因为我们已经确定最后两个箱子是空的。

这里有一个有趣的观察。

当我们打开正确的箱子时,我们一口气学到了 1.585 比特的信息,使我们的累积信息达到 3 比特。这与系统中的 所有 的信息量相同。

直觉上,这是有道理的,因为如果我们知道唯一的宝箱在哪里,那么所有其他的选择都将无效。但是这些数字的增加仅仅是因为巧合吗?只是为了说服我们自己,让我们把宝藏藏在第五个箱子里。

观察。

把宝藏放在第五个箱子里而不是第六个,仍然给了我们同样多的信息。宝藏(关闭、填充)、删除、勾选图标由 Smashicons 和 hqrloveq 从 Flaticon 创建,经作者许可编辑。

无论我们把它放在哪里,它总是与总信息相匹配。这是支持这一说法的数学证明。

不管我们把宝藏放在哪里,信息内容总会加起来成为总信息。

希望这能让你相信香农信息量是一种在概率方法中客观量化不确定性顺序的明智方法。

但是有一个问题。

一个信息“单位”是一个模糊的量,可以是很多,也可以很少。这相当于说我需要一个“单位”的牛奶,可以说这比一“盒”或一“升”的牛奶更难以描述。

没有对其单位的解释,数字就只是一个数字。

一个单位的信息有多大用处?

Claude Shannon 建议我们用 1 比特来衡量将不确定性减半所需的信息量。

如果我们重新回到中间点,也许会更容易想象。

每一位信息都使不确定性减半。宝藏(关闭、填充、删除图标由 Smashicons 和 hqrloveq 从 Flaticon 创作,经作者许可编辑。

请注意,当我们打开第四个箱子时,我们正好积累了 1 位信息。有了这一点信息,我们的概率空间减少了一半——从 8 个箱子减少到 4 个箱子。

再加一点,它会把我们的不确定性再减少一半,只剩下两个可能的箱子。正如您已经可以想象的那样,拥有 3 位将会简单地将其减少到一个单一的、明确的选择。这也证明了我们的系统总共只有 3 位信息。

另一种理解这个观点的方法是将一点信息与一个是或否的问题联系起来,这个问题排除了我们一半的选择。3 位信息意味着我们需要问 3 个问题来了解系统的一切。对于我们的例子,我们可以问…

  • 问题 1:它在上面的箱子里吗?
  • 问题 2:在右边吗?
  • 问题 3:在左边吗?

每一位信息都使不确定性减半。宝藏(关闭、填充)、删除、勾选图标由 Smashicons 和 hqrloveq 从 Flaticon 创建,经作者许可编辑。

这个想法是双向的。如果我们正在处理的系统有 10 位信息,这意味着我们有 2 个⁰或 1024 次猜测。这种思路让我们对任何类型问题的可能性和不确定性有所了解。

我们不仅给“信息”一词赋予了意义,还给了它一个数字来阐述它的重要性,这完全改变了我们理解或处理信息的方式。

香农信息量的实际应用

Shannon 的信息内容远远超出了琐碎的猜谜游戏。它的主要贡献之一是在通信领域。

对于任何发生的交流,我们总是有一个来源,渠道和接收器。

  • 讲话需要声音(源)通过空气(信道)传播,才能到达他人的耳朵(接收器)。
  • 打电话需要电话(源)通过电话线(信道)将信号传输到另一部电话(接收器)。

在后一个例子中,我们还需要一个编码器将我们的声音转换成二进制 0 和 1 的数字流,以简化传输过程。在接收端,我们使用解码器将信号转换回语音。

一个非常高效的通信系统。Freepik 的电话、编码器、发射塔,Flaticon 的平面图标、Mehwish,经作者许可编辑。

从理论的角度来看,这种设置是可行的。但现实中,频道往往是嘈杂的。你的邻居把重金属音乐开到最大音量?噪音。传输过程中铜线上的磁干扰?噪音。总有噪音会降低我们的信息质量。我们可能听到的不是“十”,而是“锡”。我们发送的东西,不一定会被收到。

为了在不可靠的信道上实现可靠的通信,我们必须增加冗余来淹没噪声。例如,我们可以编程我们的编码器重复我们的信息三次,“十—十—十”。这样,即使消息最终在接收端“ten — tin — ten”被破坏,它仍然可以通过从多数中推断出“ten”来恢复原始消息。

一种真实的通信系统,其中噪声翻转二进制位,从而使信息失真。电话、编码器、发射塔由 Freepik、Flat Icons、Mehwish 来自 Flaticon,经作者许可编辑。

但是就像打地鼠一样,我们解决了一个问题,另一个又冒出来了。添加多余的信息来重新创建更短的原始消息会降低我们的传输速度。如果我们必须重复 3 次,这意味着我们的传输速度慢了 3 倍。

因此,在精度和传输速度之间进行权衡是必要的,但由于对于大多数应用来说精度优先,问题就变成了——我们需要牺牲多少速度?

利用一点概率论,我们可以计算我们系统的错误概率,并绘制它们与传输速率的关系。

权衡曲线。当我们增加冗余以降低错误率时,传输速率会下降。图片由作者提供。

通过相同的编码算法,但不同的冗余量循环,我们会得到一个很好的权衡曲线。但可悲的是,对于我们还没有发明的算法,我们将无法做到这一点。

如果没有权衡曲线,就很难决定我们是否应该使用不同的通道,或者我们应该更加努力地尝试一种更好的编码算法,以获得所需的错误率。没有明确的目标,射手注定会射不中。

克劳德·香农用他的量化信息的框架,能够计算出任何给定信道的最大传输速率,在该信道中会有任意低的错误率。换句话说,给定信道固有的噪声,假设我们有最有效的编码算法,信道传输我们的消息能有多好?

在他的噪声信道编码定理中,他将这个上限称为信道容量(又名香农极限)。我希望这个公式能让你想起什么。

在二进制对称信道中,“0”和“1”具有 p(e)误差率,我们可以用它来计算信息量,或者确切地说是熵。图片由作者提供。

该公式读起来很直观——如果我们将信道的全部容量减去传输原始消息的信息所需的容量,最终可能是正确的比特或不正确的比特,那么剩下的一定是信道的过剩容量。这是信道能够达到的最佳传输速率。

虽然信道容量不能帮助我们设计最佳的编码算法,但它向世界展示了什么是可能的。对 4 分钟一英里的回忆,一旦知道了理论极限,它就为我们交流方式的巨大进步铺平了道路。

结束语

这一应用只是冰山一角。香农的信息论引入了信息内容,有人称之为通信的基本粒子。物理对象有原子,而信息有比特。

它给世界提供了一种方式来进行任何形式的交流——从鸟儿的鸣叫,到绘画,再到莫尔斯电码——并对它们进行普遍的比较。

Shannon 的杰出工作彻底改变了我们处理信息的方式,成为数据压缩、密码学甚至数据科学中的一个关键概念,以及其他许多伟大的事物。

作为数据科学家,我们总是习惯于想要更多的数据或更多的“信息”。但我想克劳德·香农刚刚向我们展示了,虽然拥有信息很好,但理解信息会更有影响力。

分类特征的 SHAP

原文:https://towardsdatascience.com/shap-for-categorical-features-7c63e6a554ea

将已经用一键编码转换的分类特征的 SHAP 值相加

卡利内里在 Unsplash 上拍摄的照片

分类特征在用于模型之前需要进行转换。一键编码是实现这一点的常用方法:我们最终为每个类别提供一个二进制变量。这很好,直到开始理解使用 SHAP 的模型。每个二元变量都有自己的 SHAP 值。这使得很难理解原始分类特征的总体贡献。

一种简单的方法是将每个二元变量的 SHAP 值相加。这可以解释为原始分类特征的 SHAP 值。为此,我们将带您浏览一下 Python 代码。我们将会看到我们能够使用 SHAP 聚集图。然而,当涉及到理解分类特征的关系的本质时,这些是有限的。最后,我们向您展示如何使用箱线图来可视化 SHAP 值。

如果你不熟悉 SHAP 或者 python 包,我建议你阅读下面的文章。我们深入探讨如何诠释 SHAP 价值观。我们还探索了本文中使用的一些聚合。

在处理分类变量时,还有一个替代解决方案。那就是使用 CatBoost 进行建模。您可以在下面的文章中找到这个解决方案。

资料组

为了演示分类特征的问题,我们将使用蘑菇分类数据集。您可以在图 1 中看到这个数据集的快照。目标变量是蘑菇的类。也就是说蘑菇是有毒的(p)还是可食用的(e)。你可以在 UCI 的 MLR 中找到这个数据集。

图 1:蘑菇数据集快照(来源:作者)(数据集来源: UCI )(许可证:CC BY 4.0)

对于模型特征,我们有 22 个分类特征。对于每个功能,类别由一个字母表示。例如气味有 9 个独特的类别——杏仁(a)、茴香(l)、杂酚油(c)、鱼腥味(y)、恶臭(f)、霉味(m)、无(n)、刺鼻(p)、辛辣(s)。这是蘑菇的味道。

系统模型化

我们将带您浏览用于分析该数据集的代码,您可以在 GitHub 上找到完整的脚本。首先,我们将使用下面的 Python 包。我们有一些处理和可视化数据的通用包(第 2-4 行)。我们使用 OneHotEncoder 来转换分类特征(第 6 行)。我们使用 xgboost 进行建模(第 8 行)。最后,我们使用 shap 来理解我们的模型是如何工作的(第 10 行)。

我们导入数据集(第 2 行)。我们需要一个数字目标变量,所以我们通过设置有毒的= 1 和可食用的= 0 来转换它(第 6 行)。我们还得到分类特征(第 7 行)。我们不使用 X_cat 数据集进行建模,但它以后会派上用场。

要使用分类特征,我们还需要转换它们。我们从安装编码器开始(第 2–3 行)。然后,我们用它来转换我们的分类特征(第 6 行)。对于每个分类特征,每个类别都有一个二元特征。我们为每个二进制特性创建特性名称(第 9 行到第 10 行)。最后,我们将这些放在一起创建我们的特征矩阵(第 12 行)。

最后,我们有 117 个特征。您可以在图 2 中看到特征矩阵的快照。例如,你可以看到帽形现在已经被转换成 6 个二元变量。功能名称末尾的字母来自原始功能的类别。

图 2: X 特征矩阵(来源:作者)

我们使用这个特征矩阵训练一个模型(第 2-5 行)。我们正在使用一个 **XGBClassifier。**XGBoost 模型由 10 棵树组成,每棵树的最大深度为 2。该模型在训练集上的准确率为 97.7%。

标准 SHAP 值

此时,我们想了解模型是如何做出这些预测的。我们从计算 SHAP 值开始(第 2-3 行)。然后,我们使用瀑布图(第 6 行)可视化第一次预测的 SHAP 值。你可以在图 3 中看到这个情节。

您可以看到每个二元要素都有自己的 SHAP 值。以气味为例。它在瀑布图中出现了 4 次。odor_n = 0 的事实增加了蘑菇有毒的可能性。同时,odor_a = 1,odor_f = 0,odor_I = 0 都降低了概率。还不清楚蘑菇气味的总体贡献是什么。在下一节中,我们将会看到,当我们把所有的个人贡献加在一起时,情况就变得很清楚了。

图 3:第一次观察的瀑布图(来源:作者)

分类特征的 SHAP

让我们从探索 shap_values 对象开始。我们在下面的代码中打印该对象。您可以在下面的输出中看到,它由 3 个组件组成。我们有每个预测的 SHAP 值()。数据给出二进制特征的值。每个预测也将具有相同的基值( base_values )。这是平均预测对数概率。

(来源:作者)

我们可以通过打印下面的内容来仔细查看第一个预测的 SHAP 值。有 117 个值。每个二进制变量一个。SHAP 值与 X 特征矩阵的顺序相同。记住,第一个分类特征帽形有 6 个类别。这意味着前 6 个 SHAP 值对应于该特征的二进制特征。接下来的 4 个对应于盖面特征等等。

(来源:作者)

我们希望将每个分类特征的 SHAP 值相加。为此,我们首先创建 n_categories 数组。这包含每个分类变量的唯一类别数。数组中的第一个数字对于帽形将是 6,然后对于帽面将是 4,依此类推…

我们使用 n_categories 来分割 SHAP 值数组(第 5 行)。我们得到了一个子列表。然后,我们对每个子列表中的值求和(第 8 行)。这样我们就从 117 个 SHAP 值变成了 22 个 SHAP 值。我们对形状值对象(第 2 行)中的每一个观察都这样做。对于每次迭代,我们将求和的 shap 值添加到 new_shap_values 数组中(第 10 行)。

现在,我们需要做的就是用新值替换原来的 SHAP 值(第 2 行)。我们还用原始分类特征的类别字母替换二元特征数据(第 5–6 行)。最后,我们用原始的特性名称替换二进制特性名称(第 9 行)。分别以数组和列表的形式传递这些新值非常重要。这些是形状值对象使用的数据类型。

更新后的形状值对象可以像原始对象一样使用。在下面的代码中,我们为第一次观察绘制了瀑布。您会注意到这段代码和以前完全一样。

您可以在图 4 中看到输出。我们现在有 22 个 SHAP 值。您还可以看到左侧的特征值已被类别标签所取代。我们之前讨论过气味特征。您现在可以清楚地看到这个特性的总体贡献。它将对数概率降低了 0.29

图 4:更新 SHAP 值后的第一次观测的瀑布图(来源:作者)

在上面的图中,我们有气味= a。这告诉我们蘑菇有“杏仁”的气味。我们应该避免把这个情节理解为“杏仁味降低了对数几率”。我们将多个 SHAP 值加在一起。因此,我们应该把它解释为“杏仁气味和其他气味的缺乏降低了对数几率”。例如,查看第一个瀑布图,缺少“恶臭”气味(odor_f = 0)也降低了对数几率。

在我们继续讨论这些新 SHAP 值的集合之前,有必要讨论一些理论。我们能够用 SHAP 值做到这一点的原因是因为它们的可加性。也就是平均预测值(E[f(x)】)加上所有的 SHAP 值等于实际预测值( f(x) )。通过把一些 SHAP 值加在一起,我们不会干扰这个性质。这就是为什么 f(x) = -2.444图 3图 4 中都是一样的。

卑鄙的 SHAP

与瀑布图一样,我们可以像使用原始 SHAP 值一样使用 SHAP 聚合。例如,我们在下面的代码中使用平均 SHAP 图。查看图 5 ,我们可以使用该图来突出重要的分类特征。例如,我们可以看到,气味往往具有较大的正/负 SHAP 值。

图 5:平均 SHAP(来源:作者)

蜂群

另一种常见的聚合是蜂群图。对于连续变量,此图很有用,因为它可以帮助解释关系的性质。我们可以看到 SHAP 值是如何与特征值相关联的。但是,对于分类特征,我们已经用标签替换了特征值。因此,在图 6 中,您可以看到 SHAP 值都被赋予了相同的颜色。我们需要创造自己的情节来理解这些关系的本质。

图 6:分类变量的蜂群(来源:作者)

SHAP 箱线图

一种方法是使用 SHAP 值的箱线图。在图 7 中,您可以看到一个气味特征。这里,我们根据气味类别对气味特征的 SHAP 值进行了分组。你可以看到,臭味导致更高的 SHAP 值。这些蘑菇很可能有毒。请不要吃任何难闻的蘑菇!同样,没有气味的蘑菇更容易食用。一条橙色的线意味着这些蘑菇的所有 SHAP 值都是相同的。

图 7:气味 SHAP 值的箱线图(来源:作者)

我们使用下面的代码创建这个箱线图。我们从获得气味 SHAP 值开始(第 2 行)。记住这些是更新值。对于每个预测,气味特征只有一个 SHAP 值。我们还得到气味类别标签(第 3 行)。我们根据这些标签分割 SHAP 值(第 6-11 行)。最近,我们用这些值为每一种气味类别绘制了一个箱线图(第 27-32 行)。为了使图表更容易理解,我们还用完整的类别名称替换了字母(第 14-24 行)。

实际上,很可能只有少数特征是绝对的。您将需要更新上述过程,以便只对分类进行求和。你也可以想出自己的方式来想象这些特征之间的关系。如果你有其他的方法,我很乐意在评论中听到。

我也有兴趣了解特性依赖将如何影响这个分析。根据定义,变换后的二元特征将是相关的。这可能会影响 SHAP 值的计算。我们使用树形图来估计 SHAP 值。我的理解是,这些不像 KernelSHAP 那样受到依赖的影响。我很有兴趣在评论中听到你的想法。

我希望这篇文章对你有帮助!你可以成为我的 推荐会员 来支持我。你可以访问 medium 上的所有文章,我可以得到你的部分费用。

https://conorosullyds.medium.com/membership

你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程

参考

南伦德伯格, SHAP 蟒包 (2021) 【T2,

南伦德伯格和 s .李,解释模型预测的统一方法 (2017 年),https://arxiv.org/pdf/1705.07874.pdf

使用 CatBoost 实现分类特征的 SHAP

原文:https://towardsdatascience.com/shap-for-categorical-features-with-catboost-8315e14dac1

避免对分类要素的 SHAP 值进行后处理

安德鲁·雷德利在 Unsplash 上的照片

结合 CatBoostSHAP 可以提供强大的洞察力。尤其是在处理分类特征时。CatBoost 处理这些功能的方式使得使用 SHAP 更容易理解您的模型。

对于其他建模包,我们需要首先使用一次性编码来转换分类特征。问题是每个二元变量都有自己的 SHAP 值。这使得很难看出原始分类特征的总体贡献。

在之前的文章中,我们探索了这个问题的一个解决方案。它包括深入研究 SHAP 对象,并手动添加单个 SHAP 值。这可能很乏味!作为替代,我们可以使用 CatBoost。

CatBoost 是一个梯度提升库。与其他库相比,它的一个主要优势是可以处理非数字特征。分类特征无需转换即可使用。这意味着 CatBoost 模型的 SHAP 值很容易解释。每个分类要素只有一个 SHAP 值。

我们将:

  • 计算并解释 CatBoost 模型的 SHAP 值
  • 应用 SHAP 聚合s——我们将看到,在理解分类特征的关系时,它们是有限的
  • 为了解决这一限制,将为单个特征创建一个蜂群图

一路上,我们将通过 Python 代码 来获得这些结果。

如果你是第一次来 SHAP,那么看看下面的视频**。**如果你想要更多,那就来看看我的 SHAP 课程 **。**注册我的 简讯 😃即可免费获取

资料组

对于此分析,我们将使用与之前相同的数据集。这是一个蘑菇分类数据集。您可以在图 1 中看到该数据集的快照。目标变量是蘑菇的**类。**即蘑菇是有毒的(p)还是可食用的(e)。你可以在 UCI 的 MLR 中找到这个数据集。

图 1:蘑菇数据集快照(来源:作者)(数据集来源:UCI)(license:CC BY 4.0)

对于模型特征,我们有 22 个分类特征。对于每个功能,类别由一个字母表示。例如,气味有 9 个独特的类别——杏仁(a)、茴香(l)、杂酚油(c)、鱼腥味(y)、恶臭(f)、霉味(m)、无(n)、刺鼻(p)、辛辣(s)。这是蘑菇的味道。

系统模型化

我们将带您浏览用于分析该数据集的代码,您可以在 GitHub 上找到完整的脚本。首先,我们将使用下面的 Python 包。我们有一些处理和可视化数据的通用包(第 2-4 行)。我们使用 CatBoostClassifier 进行建模(第 6 行)。最后,我们使用 shap 来理解我们的模型是如何工作的(第 8 行)。确保您已经安装了所有这些软件包。

我们导入数据集(第 2 行)。我们需要一个数字目标变量,所以我们通过设置有毒的= 1 和可食用的= 0 来转换它(第 6 行)。我们还得到分类特征(第 7 行)。在前一篇文章的这一点上,我们需要转换这些特性。有了 CatBoost,我们可以直接使用它们。

当我们在下面(第 7 行)训练我们的模型时,您可以看到这一点。我们通过非数字特征(X)、目标变量(y)和列表来表明特征是分类的( cat_features )。我们所有的特征都是绝对的。这意味着 cat_features 是一个从 0 到 21 的数字列表。最后,分类器由 20 棵树组成,每棵树的最大深度为 3。它在训练集上的准确率为 98.7%。

SHAP 地块

我们现在可以继续理解我们的模型是如何做出这些预测的。如果你不熟悉 SHAP 或者 python 包,我建议你阅读下面的文章。我们深入探讨如何诠释 SHAP 价值观。我们还探索了本文中使用的一些聚合。

水冷壁图

我们从计算 SHAP 值开始(第 2-3 行)。然后,我们使用瀑布图(第 6 行)可视化第一次预测的 SHAP 值。你可以在图二中看到这个情节。这告诉我们每个分类特征值是如何对预测做出贡献的。例如,我们可以看到这种蘑菇有一种杏仁(一种)的气味。这使得对数概率降低了 0.85 。换句话说,它降低了蘑菇有毒的可能性。

图 CatBoost 的 SHAP 瀑布(来源:作者)

从上面的图表中,很容易看出每个特性的贡献。相比之下,我们在图 3 中有瀑布图。如前所述,这是在前一篇文章中创建的。为了对分类特征建模,我们首先使用一键编码对它们进行转换。这意味着每个二元要素都有自己的 SHAP 值。例如,气味将有 9 个 SHAP 值。每个独特的类别一个。因此,很难理解气味对预测的总体贡献。

图 3:独热编码的 SHAP 瀑布(来源:作者)

我们可以采用图 3 中的 SHAP 值来创建一个类似于图 2的图。这就是为什么每个分类特征只有一个 SHAP 值。为此,我们需要通过将一个分类特征的所有值相加来“后处理”SHAP 值。不幸的是,没有直接的方法可以做到这一点。我们需要自己手工更新 SHAP 值对象。我们已经看到,通过使用 CatBoost,我们可以避免这一过程。

绝对平均 SHAP

SHAP 聚合也适用于 CatBoost。例如,我们在下面的代码中使用平均 SHAP 图。查看图 5 ,我们可以使用该图来突出重要的分类特征。例如,我们可以看到,气味往往具有较大的正/负 SHAP 值。

图 4:均值 SHAP 图(来源:作者)

蜂群

另一种常见的聚合是蜂群图。对于连续变量,此图很有用,因为它可以帮助解释关系的性质。也就是说,我们可以看到 SHAP 值如何与特征值相关联。然而,对于分类特征,特征值不是数字的。因此,在图 6 的中,您可以看到 SHAP 值都被赋予了相同的颜色。我们需要创造自己的情节来理解这些关系的本质。

图 5:蜂群图(来源:作者)

一窝蜂只为一个特征

一种方法是对单个特征使用蜂群图。你可以在图 6 中看到我们的意思。这里,我们根据气味类别对气味特征的 SHAP 值进行了分组。例如,你可以看到一股恶臭会导致更高的 SHAP 值。这些蘑菇很可能有毒。在上一篇文章中,我们使用箱线图得到了类似的结果。

图 6:蜜蜂群寻找气味(来源:作者)

我们不会详细讨论这个情节的代码。简而言之,我们需要创建一个新的 SHAP 值对象, shap_values_odor 。这是通过对 SHAP 值进行“后处理”来完成的,因此它们是我们想要的形式。我们用气味的 SHAP 值代替原来的 SHAP 值(第 24 行)。我们还用气味类别替换特征名称(第 43 行)。如果我们正确地创建了 shap_values_odor ,我们可以使用 beeswarm 函数来创建绘图(第 46 行)。

最后,SHAP 和 CatBoost 是分析分类特征的有力工具。这两个包可以无缝地协同工作。缺点是您可能不想使用 CatBoost。如果您正在使用 RandomForest、XGBoost 或神经网络等模型,那么您需要使用替代解决方案。你可以在下面的文章中找到这个。我们还将更详细地介绍如何对 SHAP 值进行后处理。

我希望这篇文章对你有帮助!如果你想看更多,你可以成为我的 推荐会员 来支持我。你可以访问 medium 上的所有文章,我可以得到你的部分费用。

https://conorosullyds.medium.com/membership

你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程

参考

南伦德伯格, SHAP 蟒包 (2021) https://github.com/slundberg/shap

南伦德伯格和 s .李,解释模型预测的统一方法 (2017),https://arxiv.org/pdf/1705.07874.pdf

用于漂移检测的 SHAP:有效的数据偏移监控

原文:https://towardsdatascience.com/shap-for-drift-detection-effective-data-shift-monitoring-c7fb9590adb0

使用模型知识警告分布差异

约翰·安维克在 Unsplash 上的照片

SHAP(SHapley Additive exPlanations)是机器学习中一种众所周知的方法,用于提供可解释的结果。当然,无论预测任务是什么,向任何模型添加明确见解的能力是一个巨大的优势,这使得 SHAP 被广泛采用。将每个样本的每个值与相应的预测贡献进行映射的可能性使适用于更高级的应用。在这个意义上,我们已经证明了 SHAP 作为特征选择和超参数调整 的有效方法的能力。

我们现在想测试的是**SHAP 能在多大程度上帮助发现数据转移?**对于在生产环境中发布的机器学习管道来说,数据转移可能是一场真正的噩梦。当我们的预测特征的分布以一种有意义的方式与在训练阶段观察到的分布发生偏离时,它们就会发生。容易理解的是,无论我们的预测算法如何,与验证期间获得的结果相比,这提供了不一致的结果。

针对数据偏移,我们也无能为力。它们在大多数涉及连续数据流的机器学习应用中是不可避免的,并且受到外部动态的影响。我们可以反复检查数据摄取过程或预处理步骤的正确性,但是如果它们是正确的,问题仍然存在。我们绝对不能做的是放弃。我们可以引入一些非常聪明的技巧和技术来提醒传入的数据漂移,并采取适当的纠正措施。

首先,我们必须监控新输入数据的分布。将它们与训练中观察到的进行比较,我们可以验证我们是否存在有意义的转变。必须对所有感兴趣的特征进行这种操作,并持续检查。其次,当我们注意到数据漂移时,我们应该让我们的模型学习变化。这可以在本地支持持续学习(也称为在线机器学习)的应用程序中轻松实现,或者简单地通过重新训练包括新数据的模型来实现。

所有的数据移位都相等吗?不同的原因可能导致不同种类的漂移。为了使事情变得更简单、更轻松,限制需要执行的检查的数量将是非常棒的。因此,只对有意义的预测实施控制可能是至关重要的。

在这篇文章中,我们利用 SHAP 的能力,作为一个模型不可知的解释框架,也用于漂移监测。对 SHAP 值的分布进行控制,而不是原始值,我们可以只识别有效的偏移

实验设置

我们在二元分类环境中操作,其中,给定一些特征,我们试图预测每个样本的所属类别。我们所掌握的所有特征都遵循高斯分布,但它们并不都是相等的。其中一些是信息的,因为它们直接有助于生成目标类。其他的是冗余的*,因为它们是作为信息特征的随机线性组合产生的。最后,我们还有噪声特性,它们在我们的监督任务中不提供任何价值。*

特征分布(图片由作者提供)

根据这些数据,建立一个最优漂移检测监控系统是可以理解的。最佳意味着我们应该只警告发生在信息特征上的变化(或者冗余特征也可以)。SHAP 非常适合这个目的。通过提供特性贡献的分布,我们可以直接在它们上面实现控制。

结果

我们以依赖于时间的方式模拟不同幅度的漂移,并且针对我们所能支配的所有特征。换句话说,我们使用标准的交叉验证策略将数据分成时间片。在每个测试折叠中,我们根据基于真实特征分布建立的简单分位数阈值创建不同的数据块。最后,我们必须检查这些组块是否具有与训练集不同且有意义的分布。

为了从数学上证明分布漂移的存在,我们采用了对抗的方法。它包括建立一个分类器,该分类器被训练来辨别一些数据样本的来源。如果这种分类器能够实现很好的性能,则意味着数据源非常不同(测试数据不同于训练数据)。相反,这意味着没有明显的差异可以检测到。对抗的方法非常有用,可以在多维的背景下以一种非常容易解释的方式捕捉差异。作为良好的度量,我们选择双样本 Kolmogorov-Smirnov 检验。它适合于比较两个独立样本的分布。在我们的例子中,涉及的样本是属于特定数据源的预测概率。所有这些推理都可以简单地归结为以下几行代码:

*def ks_drift_detection(X1,X2, n_splits=5, seed=33):import numpy as npimport pandas as pdfrom scipy.stats import ks_2sampfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import StratifiedKFoldassert isinstance(X1,pd.DataFrame)assert isinstance(X2,pd.DataFrame)CV = StratifiedKFold(n_splits, shuffle=True, random_state=seed)y = np.r_[np.ones((X1.shape[0],)),np.zeros((X2.shape[0],))]pred = np.zeros_like(y)X = pd.concat([X1, X2], ignore_index=True, axis=0)for i,(id_train,id_test) **in** enumerate(CV.split(X,y)):model = LogisticRegression(random_state=seed)model.fit(X.iloc[id_train], y[id_train])pred[id_test] = model.predict_proba(X.iloc[id_test])[:,1] ks = ks_2samp(pred[(y == 0)], pred[(y == 1)])return round(ks.statistic, 4), round(ks.pvalue, 4)*

专注于我们的实验,我们执行这个函数来测试块(我们在所有特征的每个时间分割中生成的)是否记录了漂移。我们开始对原始分布值执行这个测试。

Kolmogorov-Smirnov 统计为每个特征生成模拟数据漂移(图片由作者提供)

正如我们所想象的,我们记录了所有特征的一致变化。Kolmogorov-Smirnov 的高值意味着我们可以很容易地区分新的输入数据和在训练中观察到的数据。因此,我们可以记录数据漂移不一致,并采取相应的行动。

如果我们同样检查 SHAP 值分布,而不是原始分布,会发生什么?我们希望找到数据漂移的证据(如预期的那样),但只是在相关的特征上。

SHAP 特色重要性(图片由作者提供)

我们知道 SHAP 在探测重要特征方面的有效性。通过绘制特征重要性,我们可以很容易地看到,噪声特征对生成预测的影响较小。对 SHAP 值分布的初步了解也有助于我们理解最重要的特征具有更宽的形状。

SHAP 值 vs 特征值(图片由作者提供)

SHAP 值 vs 特征值(图片由作者提供)

SHAP 值 vs 特征值(图片由作者提供)

SHAP 值 vs 特征值(图片由作者提供)

SHAP 值 vs 特征值(图片由作者提供)

最后,我们使用 SHAP 值重复检查以测试分布漂移的存在。根据相对特征贡献,相同的模拟偏移现在具有非常不同的影响。我们可以看到,信息功能(对 SHAP 最重要)产生了有意义的转变。相反,噪声特征不太容易生成警报,因为它们对模型输出的影响是不相关的。

基于 SHAP 值生成的 Kolmogorov-Smirnov 统计数据模拟了每个要素的数据漂移(图片由作者提供)

摘要

在这篇文章中,我们使用了 SHAP 的能力来生成模型不可知的结果贡献,也作为一种检测有意义的数据漂移的方法。我们发现了监控 SHAP 分布变化以限制要执行的检查数量的优势。在这个意义上,我们也可以理解特征选择过程对帮助模型监控阶段的重要性。

查看我的 GITHUB 回购

保持联系: Linkedin

XGBoost 的 SHAP:从 NP 完全到多项式时间

原文:https://towardsdatascience.com/shap-for-xgboost-from-np-completness-to-polynomial-time-20c9e78907a0

丹-克里斯蒂安·pădureț在 Unsplash 上拍摄的照片

更新:发现我关于渐变提升的新书,实用渐变提升。这是用 python 中的许多例子对渐变增强的深入探究。

https://www.amazon.com/dp/B0BJ82S916 的文章:

然而,没有多少论文详细说明这些值是如何计算的。然而,这是一个非常有趣的主题,因为计算 Shapley 值是一个 np 完全问题,但一些库,如 shap 可以在一个小故障中计算它们,即使是对于具有数百个特征的非常大的基于树的 XGBoost 模型。这怎么可能呢?

这就是我们将在本文中通过给出该方法的 python 实现来发现的。

ML 方法用于 ML 方法

激发使用 Shapley 值的潜在想法是,理解一个现象的最好方法是为它建立一个模型。一旦你有了模型,你就可以玩它,数学分析它,模拟它,理解输入变量,内部参数和输出之间的关系。一句话,解释一下。

然而,当处理决策树的森林时,正如 XGBoost、CatBoost 和 LightGBM 所构建的,底层模型很难理解,因为它混合了数百个决策树。

因此, SHAP 的论文提出在任何 ML 模型之上建立一个解释模型,这将带来对底层模型的一些洞察。为了便于理解这个解释模型,SHAP 论文的作者建议使用一个简单的线性加法模型,该模型考虑以下三个特性:

  • 局部精度:特征重要性的总和必须等于预测值。
  • 缺失:如果一个特性没有参与到模型中,那么相关的重要性必须为空。
  • 一致性:如果比较两个模型,其中一个模型对某个特性的贡献高于另一个模型,那么这个特性的重要性也必然高于另一个模型。

信不信由你,但只有一种价值观符合这些要求:由诺贝尔经济学奖获得者沙普利创造的价值观,这些价值观以他的名字命名。即使有不止一个公式,也只有一种方法来计算它们。最简单的一个是:

作者的公式。

其中 n 指定模型中存在的特征的数量,R 是这些特征的可能排列的集合,PiR 是索引低于所考虑的排列的 I 的特征的列表,f 是必须计算其 Shapley 值的模型。

请注意,维数为 n 的集合的排列数是 n 的阶乘,因此 n!以总数为因子。

这种方法的工作原理简单而通用。它适用于任何类型的模型:它包括为每个可能的子模型建立没有特征 I 的模型。为此,扫描所有可能的排列。然后计算每个模型和具有所考虑特征的相同模型所获得的预测之间的差异。根据 Shapley,该差异的平均值给出了特征的重要性。

虽然非常简单,但在一般情况下,该公式的计算时间非常昂贵,因为要训练的模型数量随着特征数量的增加而成阶乘增加。因此是 np 完全的。有了 x₂x₁的两个特征,可以为特征 1 建造两个模型:一个没有任何特征,一个只有 x₂.

有了三个特征,它已经更复杂了。可以构建 6 个模型:2 个不带特征,1 个带 x₂,1 个带 x₃,1 个带 x₂和 x₃,1 个带 x₃和 x₂.此外,必须为每个预测迭代操作。

线性模型的 Shapley 值

为了理解这个概念,下面给出了 SHAP 方法的一个实现,首先是线性模型:

计算线性模型的 Shapley 值。作者代码。

第一个函数列出了 n 个特征的所有可能的排列。因此,它建立了前一个公式的集合 R。

该函数 compute_theta_i 构成了该方法的核心,因为它将计算给定特征 I 的 theta 值。为此,它将遍历所有可能的排列,构建包含和不包含该特征的集合,最后使用该模型进行两次预测,并计算其差值。

然后计算这些差值的总和,用特征数量的阶乘的倒数进行加权。

然后使用函数 train_linear_model 对回归数据训练的两个模型进行测试。

第一个模型只使用了两个特性。获得的θ值与理论非常一致,因为它们等于特征与相应回归系数的乘积。具有 3 个特征的模型也是如此。

这证实了实现是正确的,并提供了理论预测的结果。

通用实现

为了支持任何类型的模型,对先前的代码进行改进以对每个特征子集执行重新训练就足够了。

注意,在线性模型的情况下,重新训练是没有用的。事实上,线性模型本质上是相加的,删除一个特征意味着不考虑它,给它赋一个空值。

修改后的代码如下:

计算任何类型模型的 Shapley 值。作者代码。

不同排列的计算保持不变。

引入了一个 ZeroModel 类来训练没有任何特征的模型。按照惯例,这种类型的模型返回零。

执行训练的函数已更改为获取有用的数据。这一次,它不是为线性模型定型,而是为回归定型 XGBoost 模型。为了避免过度学习,估计器的数量和深度已经减少。

事实上,在过度拟合的情况下,计算的 Shapley 值是无效的,因为模型有足够的自由度来拟合数据,即使只有单个特征。然后,它会在每种情况下做出几乎精确的预测,所有特征最终都具有相同的 Shapley 值。
最后,计算 Shapley 值的方法本身已得到改进,以执行重新训练。最有趣的部分是关于有和没有要加权的特征的特征集的生成。

这个新的实现可以像以前一样在相同的数据集上进行测试。shap 库也用于确保计算出的值是一致的。

由于 Shapley 值的总和给出了预测值,因此局部精度特性受到了很好的重视。
此外,该代码获得的值与 shap 库提供的值符号相同。数量级相当。
数据越复杂,差距越小。

这种差异是由于 shap 库使用的方法,该方法利用决策树的结构,而不是像这里一样重新计算所有模型。

计算基于树的模型的 Shapley 值

上一小节中的方法仅用于教学目的。

实际上,构建 n 因子模型的需求是禁止的。即使是 5 个特性,我们也需要训练不少于 5 个!=120 个模型,这与要分析的预测一样多。
幸运的是,有一个解决方案,由 SHAP 方法的作者提出,利用决策树的结构,大大减少计算时间。然后只需要训练一个模型。

请注意,计算 Shapley 值的一般方法是一个 NP 完全问题。也就是说,没有办法在多项式时间内计算它们。

决策树的存储信息

首先提醒一下,在决策树的构建过程中,每个节点的增益、权重和覆盖都是存储的。这些值用于计算特征重要性,但也可用于以较低的成本计算 Shapley 值的良好估计。

SHAP 方法的开发

Lundberg 和 Lee 在他们关于该主题的第一篇出版物的补充论文中,提出了在决策树的情况下计算 Shapley 值的多项式时间实现。

这个想法是依靠单一的模型,从而避免必须训练快速指数数量的模型。为了做到这一点,他们使用与树叶和盖子相关的重量。目标是从这个单一模型中获得所有可能的特征组合的预测。

方法如下:对于给定的观察值,以及对于要计算 Shapley 值的特征,我们简单地遍历模型的决策树。

在每一个节点上,如果决策涉及子集的一个特征,那么所有的事情都像一个标准的行走一样发生。另一方面,如果节点处的决策是基于没有被子集选择的特征,则不可能选择跟随树的哪个分支。在这种情况下,对两个分支都进行了探索,并且通过覆盖对结果权重进行加权,即通过测试所涉及的观察数量进行加权。

剩下的就是计算没有特征的子模型和具有特征的子模型之间的差异,并对其进行平均。

这个策略被用在 SHAP 库中,该库在上面被用来验证所提出的通用实现。

结论

本文给出了计算任何模型的 Shapley 值的最小代码。

然而,如介绍中所述,该方法是 NP 完全的,并且不能在多项式时间内计算。

SHAP 正在使用一个技巧来快速计算 Shapley 值,重用先前计算的决策树值。

Shapley 残差:测量 Shapley 值的可解释性的限制

原文:https://towardsdatascience.com/shapley-residuals-measuring-the-limitations-of-shapley-values-for-explainability-d9cdc3582522

让我们用酒吧琐事来显示沙普利值错过的信息

我们将使用一个游戏的立方体表示来解释 Shapley 值的解释和限制。

简介

为了负责任地使用机器学习,你应该尝试解释是什么驱动了你的 ML 模型的预测。许多数据科学家和机器学习公司正在认识到,能够逐个功能地解释模型如何对给定的输入做出反应是多么重要。本文将展示 Shapley 值,一种最常见的可解释技术,在解释一个模型时是如何遗漏重要信息的。然后,我们将介绍 Shapley 残差,一种测量 Shapley 值如何捕捉模型行为的新技术,以及一些开始计算它们的代码!

考虑克里斯托弗·莫尔纳尔的可解释机器学习书中的以下例子:一家自行车共享公司使用季节信息、星期几、天气信息等功能,训练一个模型来预测某一天被借出的自行车数量。然后,如果他们的模型预测未来某一天的骑手数量低于平均水平,他们可以找出为什么低于平均水平的分数会出现:通过观察模型对每个特征的反应。是因为一个节日吗?是因为天气吗?

计算每个模型特征重要性的一种常用方法是使用 Shapley 值,因为这是一种 1)广泛适用于许多问题,2)基于坚实的理论基础,3)易于用 SHAP Python 库实现的方法。

**问题:**在某些场景中,Shapley 值无法表达关于模型行为的信息,因为它一次只为的一个特征返回一个分数。例如,在自行车共享场景中,我们将天气和星期几视为独立的特征,但有时这些特征的组合才是重要的;在那些特征组合比单个特征本身更重要的场景中,Shapley 值可能无法正确解释一个模型。

酒吧琐事示例

让我们使用一个更简单的设置和更少的功能来更详细地解决 Shapley 值的问题。

我喜欢每周和不同的同事去附近的酒吧参加知识之夜。很明显,我们团队中的一些成员比其他人更有贡献。

我们能量化每个团队成员对琐事表现的影响吗?我们可以对每个玩家使用 Shapley 值,其解释如下:当将该玩家添加到琐事团队时,它们应该对应于分数的预期变化。存在其他可能的解释,但我们将使用这一个。

(* 注:这类计算 Shapley 值的方法称为“介入性”Shapley 值,测量“添加此功能时分数的预期变化”一种不同的类型被称为“有条件的”Shapley 值。介入方法和条件方法之间的关键区别在于它们如何处理分数的预期变化为零的特征——其 Shapley 值应该是多少?零?如果你认为答案是“是”,那就用介入的方法。相反,如果您认为由于相关性,要素可能仍然具有重要性,并且如果您认为重要性应该包括在其 Shapley 值中,则考虑使用条件方法。)

从几何角度来看,绘制不同球队的所有 3 人游戏分数的一个有用方法是将这些分数排列成一个立方体上的点,这样相邻的点只相差一名球员。然后,点之间的路径(也称为立方体的边缘)将代表在将球员加入球队时分数的变化。

(注意:有两个玩家,我们会把它画成一个正方形。对于四个或更多的玩家,我们将不得不把它画成一个超立方体)

让我们称这个形状为 GameCube 这将是一个对我们有用的形状,因为【Shapley 值和 GameCube 边都将对应于增加一名球员时分数的变化。

图 1:将每一个琐事分数标绘在一个立方体的不同顶点上,对应于当晚队中在场的球员。

在我们的故事中,Reid 只知道体育琐事,GW 知道电影、音乐、历史、地理、文学——除了体育琐事,几乎什么都知道。所以当里德演奏时,他提高了一点分数;GW 玩的时候,她增加一个 lot 的分数。而我,嗯,我主要是为了啤酒和陪伴。

Shapley 值是一个完美的可解释的度量只有当一个玩家总是为一个团队的分数贡献相同的数量时。由于每个球员在得分上的变化在我们迄今为止的故事中是恒定的,我们可以将 Shapley 值 1 分配给 Reid,将 Shapley 值 9 分配给 GW,将 Shapley 值 0 分配给 Max。这些 Shapley 值代表了每个球员加入球队时的预期得分变化!

图 2:查看添加每个球员时队伍得分的变化。

用更专业的术语来说,每个玩家的影响都一致的游戏(就像我们到目前为止的故事)被称为“无关紧要的游戏”。此外,我们将使用符号 ▽v 来表示 GameCube v 的“梯度”,它计算顶点上的值之间沿边缘的值,我们将使用 ▽_player_v 来表示特定玩家的方向的边缘值,沿所有其他边缘为零。

比如 GameCube 渐变 ▽_Reid_ν 代表了加入 Reid 时所有可能的分数变化。

图 3:将添加玩家时分数的变化表示为游戏立方体相对于每个玩家的部分梯度

特征贡献不能总是表示为一个单一的数字——因此 Shapley 值是不够的。

您应该预料到,在大多数情况下,您正在使用的特征不会对模型输出产生持续的影响,相反,一个特征的影响通常取决于其他特征是什么。

让我们改变一下我们的故事。

假设 Max 的行为根据他和谁一起玩而改变。当和 GW 玩的时候,他很冷静,喝他的啤酒,关心他自己的事情,让 GW 做大部分的工作,所以他不会降低分数。但是当马克斯和里德一起玩的时候,他嫉妒里德对体育的了解,所以马克斯开始说得更多,提出了一些错误的答案,使分数下降了 1 分!

图 4:玩家贡献不一致的新 game cube

在这个新的 GameCube 上,GW 的边是恒定的,所以她的 Shapley 值 9 仍然与她玩游戏时分数的变化完全对应。但是马克斯和里德的优势不是恒定的,因为他们对得分的影响取决于他们和谁一起玩。因此,我们使用 GameCube 边缘来量化 Max 和 Reid 带来的东西的方法现在有问题了。

当真实数据科学家使用 Shapley 值时,他们通过获取玩家对其团队的平均贡献来解决这个问题——在 GameCube 上,这意味着将玩家的贡献量化为他们所在方向的平均边缘值。所以在我们上面的 GameCube 上,GW 的 Shapley 值仍然是 9,但是 Reid 的 Shapley 值现在是 0.5,Max 的 Shapley 值现在是-0.5。对于一些用例,故事到此结束——玩家的平均贡献有时可以很好地量化他们的影响!

然而,当涉及到信任沙普利价值观时,这可能会导致一个问题。因为我们更信任 GW 的 Shapley 价值观,而不是 Max 或 Reid 的 Shapley 价值观,因为她对团队的贡献比 Max 或 Reid 的贡献更具一致性。

沙普利残差

Shapley 残差是对玩家的边缘偏离恒定值的程度的度量,较低的 Shapley 残差意味着 Shapley 值接近完美地代表了特征贡献,而较高的 Shapley 残差意味着 Shapley 值遗漏了重要的模型信息:也就是说,一个特征的贡献还取决于其他特征。

最初 Shapley residuals 论文的作者将这种缺失信息公式化为最小二乘回归中的误差项。例如,对于玩家里德:

▽_Reid_ν = ▽_ν_Reid + r_Reid

这个方程的左边是和前面一样的偏梯度。等式的右边是一个新的 GameCube 的梯度之和, *▽_ν_Reid,*加上一个剩余的 Cube, r_Reid,,它测量我们的游戏偏离 Reid 无关紧要的程度。

图 5:剩余立方是游戏相对于给定玩家偏离无关紧要性的量。

关键的想法是,如果里德对团队有持续的影响,剩余的立方体 r_Reid 将全为零。另一方面,如果剩余立方体上的值 r_Reid 偏离零,那么这是一个信号,即 Reid 的 Shapley 值缺少关于 Reid 的影响如何取决于还有谁与 Reid 一起玩的信息。剩余立方体上的值越高,里德的贡献就越依赖于哪些其他玩家在场。

计算 Shapley 残差的代码

进口

生成合成数据集

训练模型和内核简单解释器

计算特征联盟的期望值

这使用了explainer.synth_data,即训练讲解者时由shap库生成的合成数据样本集。

字典coalition_estimated_values将特征联盟映射到使用这些特征时模型相对于基线的期望值(当没有使用特征时的期望值:平均模型输出)。

(注意,我们将列表转换为字符串,因为列表在 Python 中不是可哈希的类型。)

进度检查

coalition_estimated_values应该是这样的:

{'[]': 0,'[0]': -0.3576234198270127,'[1]': 0.010174318030605423,'[2]': -0.08009846972721224,'[0 1]': -0.34261386138613864,'[0 2]': -0.37104950495049505,'[1 2]': 0.14435643564356437,'[0 1 2]': -0.396}

创建超立方体对象

我们使用的是三维数据,所以这只是一个立方体。但这种方法扩展到超立方体,随着维数的增加,增长速度变慢。

请随意使用本文附录中的 Hypercube python 类的代码,或者自己编写代码。它需要将coalition_estimated_values放置在立方体的顶点上,并且它需要将边值计算为相邻顶点值之间的

计算 Shapley 残差

对于每个要素,最小化| |▼_ feature _ cube—▼_ cube _ feature | |以计算残差。这使用了一个名为residual_norm 的助手函数,在本文末尾的附录中有定义。

结论

Shapley 值已经成为一种非常流行和可推广的方法,用于解释哪些特征对机器学习模型很重要。通过使用 Shapley 残差量化它们的有效性,您将能够进一步确定您的机器学习模型的行为到底来自哪里,以及哪些来自 Shapley 值的见解值得信任。

特别感谢原始沙普利残差论文的作者们所做的工作!

附录

作品中的所有图像都是作者创作的。

下面是 Hypercube 对象和其他帮助函数的代码,您可以使用上面的起始代码来计算 Shapley 残差。

语言模型的 Shap 划分解释器

原文:https://towardsdatascience.com/shaps-partition-explainer-for-language-models-ec2e7a6c1b77

Shapley 值,Owen 值和 shap 中的分割解释器:它们是如何联系在一起的

照片由雷德查理在 Unsplash 上拍摄

理解模型预测的能力通常对铺平生产道路至关重要。虽然简单、可解释的模型在某些应用中取得了足够好的结果,但在其他应用中,使用复杂建模技术的好处超过了对易处理性的追求,如自然语言处理或计算机视觉。然而,我们希望了解哪些特征对模型的预测最重要。

Shapley 值是一个理论上合理且广泛用于解释黑盒机器学习模型的概念。作为一种与模型无关的方法,它可以用于任何预测模型。它的吸引力在于其直白的解释:Shapley 值是一个特征对实际预测的贡献,所有特征的 Shapley 值加起来就是预测。不幸的是,它有一个不可忽视的缺点:在其纯形式中,它很快变得难以计算。因此,我们必须求助于替代的、近似的方法。T4 图书馆提供了一套不同的方法。对于自然语言处理和图像分类任务,它默认使用分区解释器计算 Owen 值。本文的目的是演示它是如何工作的。

我在一个文本模型设置中演示了什么是欧文价值观,它们如何与 Shapley 价值观相关,它们有多好,以及它们如何在 shap 中实现。在描述欧文价值观之前,我先快速回顾一下沙普利价值观。

文本语境中的 Shapley 值述评

关于 Shapley 值、它的内部工作方式、优点和缺点已经写了很多,我不打算在这里赘述。感兴趣的读者可以在网上找到大量容易获取的资料(例如这里的或者这里的或者和)。相反,我限制自己在一个特定的环境中回顾它的本质,即基于文本的模型。

在较高层次上,Shapley 值是特征值或文本设置中的标记对模型结果的贡献。代币被解释为合作游戏中的玩家,他们合作产生收益或损失,即结果减去参考值。每个玩家贡献了多少?Shapley 值试图将公平份额分配给每个参与者。单个玩家也可能对群体的得失做出相反的贡献。

为了说明,让我们看一些随机的句子:“令人惊讶的曲折”,在一些监督学习文本模型中,它产生 0.9886 的预测。对于作为引用的空字符串,模型输出 0.6431。每个单词对这 0.3455 的差异贡献了多少?

在这里,我们把句子想象成一组玩家 F ,令牌。对于参与人 i ,我们计算 I 在 F 中排除 I 的所有子集 S 上的加权边际贡献,边际贡献指的是 I 的存在引起的结果函数 v 的变化。接近初始联盟或空集的子集被赋予更大的权重。在正式符号中,令牌 I 的 Shapley 值是:

参与人 I 的 Shapley 值的正式定义。

所有子集 S ,也称为联合,都尊重原句子的顺序。下表展示了在示例文本中,对于某些假设模型,如何计算“令人惊讶”的 Shapley 值:

将加权差值相加得到沙普利值 0.1218。这就是“令人惊讶的”对 0.3455 的预测增长的贡献。为了计算这个小句子中一个单词的 Shapley 值,我们需要计算 16 个预测,8 个子集各两个。总的来说,这个数字相当于

计算。

欧文值:Shapley 值的一个易于计算的近似值

欧文值是沙普利值的联合版本。最初,欧文的意图是考虑到球员可能属于群体。在 ML 设置中,这转化为相关的特征值。尽管这是一个很好的副作用,但据我理解,shap 的分区解释器使用 Owen 值的主要原因是为了让计算更容易处理。

欧文值通过减少需要计算边际贡献的子集数量来逼近沙普利值。选择基于初始划分,即联合结构,它指定如何将令牌分组到联合中。从玩家的角度来看,联盟既可以在联盟内部形成,也可以在联盟层面形成。外部联合保持完整,不会分裂。在这两个层次上组合联盟的初始次序是选择联盟。

让我们回到我们的例子,使这一点更清楚。句子“令人惊讶的曲折”可以被分割成联合结构 B={{0,1},{2,3}}。因此,形成的联合是{0,1}和{2,3}。对于索引 0 处的令牌“令人惊讶”,要组合的联盟是:

  • 内部级别的和{1}
  • 和{2,3}在联合级别。

组合后的联合是、{2,3}、{1}、{1,2,3}。

就像之前一样,我们然后计算 I 在排除 I 的所有已识别联盟上的加权边际贡献。正式定义是:

参与人 I 的欧文值的正式定义。

诚然,这看起来有点复杂,但实际上与 Shapley 方程没有太大区别。 R 都是 M{k} 的子集,其中 M={1,2,…,m} ,其中 k 是指其中有 I 的并集。 Q 是 r 中的并的对应并(就集合论而言)即 Q 是并层次上的并。 T 则是内部级别的联合,不包含 I,小写字母 rt 代表各自集合的大小。

在我们的例子中,下面是如何计算“令人惊讶”的欧文值,略有滥用符号:

对于 Shapley 值,我们需要计算 82=16 次预测,而对于 Owen 值,我们只需要 42=8 次!根据分区,所需的计算量可以大大减少。

下面是一个更长的例子:一个有七个标记的句子被分割成 B={{0,1,2},{3},{4,5,6}}。对于索引为 0 的令牌,要考虑的联盟有

  • 在内部级别:、{1}、{2}、{1,2}
  • 在外层:、{3}、{4,5,6}、{3,4,5,6}

在这个例子中,计算了 442 = 32 个预测。不可忽略,但比最初的 128 个预测要少得多。更一般地,单个令牌所需的计算次数总计为

欧文值方法潜在地节省了大量的计算资源。注意,如果形成个体联盟(每个集合一个令牌,b_k = 1)或大联盟(一个集合中的所有令牌,m = 1),欧文值与沙普利值完全相同。

计算 Shapley 值的计算成本极高。因此,采用更便宜的选择不仅是可取的,而且往往是必要的。不利的一面是,欧文值不是沙普利值,而沙普利值长期以来被认为是满足许多理想性质的唯一值。在 ML 环境中,它们是:

  • 对称性:如果两个令牌对所有可能的联盟贡献相等,那么它们的贡献值是相同的。
  • 效率:所有 Shapley 值之和充分说明了得失。
  • 虚拟:其值不影响模型结果的特征贡献值为零。
  • 可加性:当一个模型的输出是两个中间输出的相加结果时,新的 Shapley 值是两个中间 Shapley 值之和。

不出所料,对称性被放弃了,或者至少放松了,因为它仍然适用于同一联盟中的令牌。贡献值取决于初始分区,因此现在是不明确的。

欧文值和沙普利值有多接近?在我们上面举例说明的例子中,欧文对“惊奇”的贡献是 0.1175,所以只比沙普利值 0.1218 小一点点。更一般地说,本文在这里论证了 Shapley 值是所有可能分区上所有对称分布的期望 Owen 值,但它没有对方差作出陈述。

在 shap 中实施

在 shap 中,Owen 值由 partition explainer 实现,缺省情况下文本模型会调用它。

在下面的代码片段中,我给出了一个例子。解释器需要一些模型函数来从给定的字符串列表中产生输出。在这里,我使用了一个经过微调的 distilbert 情绪分析模型,它碰巧输出了上面示例中列出的预测。掩码很可能不同于原始模型的记号赋予器,它定义了计算 Owen 值的基础。我想获得“不可否认”的贡献值,而不是计算“un”、“deni”、“able”的贡献值。我发现 transformers 库中的 BasicTokenizer 通常是处理标点使用不当的好选择,但是空格标记化可能就足够了。

在上面的例子中,我使用空字符串作为引用字符串。如果标记化器没有属性 mask_token,shap.maskers.Text()则使用“…”。对 Shapley 值的一个常见批评是引用不可信的特征值组合,这些组合不太可能甚至不可能在野外找到。虽然简单地丢弃标记肯定是有问题的,但在我看来,用一些随机的字符串替换它们更有问题,并且会创建特别奇怪的句子。我不知道作者为什么选择这样做。

为了计算样本文本的 Owen 值,我们简单地调用 explainer,explainer(['surprising twists and turns']).这样就实现了上面给出的划分,B = { { ' surprising ',' twists'},{'and ',' turns'}}。

要查看不同样本字符串上实现的分区,我们可以绘制一个树状图,如下所示:

sample_text 的树形图

显然,划分树有多个层次,B={{{0,1},{2,3}},{{4,5},{6}}}。在我的理解中,绿色分支内的所有令牌都将红色分支视为一个整体,反之亦然。除此之外,程序没有改变。在所描绘的树中,使用分区 B={{0,1}、{2,3}、{4,5,6}}来计算前四个令牌的 Owen 值,而红色分支令牌考虑 B={{0,1,2,3}、{4,5}、{6}}。此外,权重不是根据上面描述的公式计算的,而是被均匀地分割。

Owen values:一种计算效率更高的近似值,易于在 shap 中实现

Shapley 值是一个强大的 ML 解释工具,具有吸引人的解释:它对应于一个特征对模型预测的贡献。接近 Shapley 值的 Owen 值继承了这种直接的可解释性。此外,Shapley 值长期以来被认为是满足许多期望属性的唯一概念,这些属性被认为共同定义了公平分享回报的含义。幸运的是,欧文价值观分享了其中的大部分。

欧文最初的动机是扩展 Shapley 值,以考虑到球员可能属于群体。因此,同一个组的成员在彼此之间分享其收益之前形成一个协商子联盟。在 ML 上下文中,如果划分被相应地定义,这可能会重新平衡相关特性的问题。据我所知,这并不是 shap 库计算 Owen 值作为自然语言处理模型默认值的主要原因。相反,它利用了欧文值的计算更容易处理的事实,这是由于减少了所考虑的联盟的数量。

当我试图在一个文本分类模型上计算 Shapley 值时,我无意中发现了 shap 的分区解释器。我花了一些时间来弄清楚它的内部工作原理,由于很难找到对欧文价值观的通俗易懂的解释,我决定撰写这篇文章。我所写的是我所能理解的,希望对某人有所帮助!

参考资料/进一步阅读

[1] J. M. Giménez,M. A .普恩特: 欧文和欧文-班扎夫价值观应用于立法机构 2015–2019马德里议会和安达卢西亚议会的研究。ICORES 2019:45–52

[2] C. Molnar:可解释的机器学习:使黑盒模型可解释的指南(第二版。).christophm.github.io/interpretable-ml-book/

Shell 语言处理:使用 TF-IDF 和哈希编码对 Linux 审计日志进行入侵检测

原文:https://towardsdatascience.com/shell-language-processing-machine-learning-for-security-intrusion-detection-with-linux-auditd-73d7196995c7

本文是一篇操作指南,为希望应用机器学习技术满足网络安全需求的安全专业人士和数据科学家提供代码示例。

图一。Kibana 中已审核事件的屏幕。图片由作者拍摄。

介绍

机器学习(ML)算法在行业、教程和课程中的适用性严重偏向于构建 ML 模型本身。然而,从我们的角度来看,数据预处理步骤(即,将文本系统日志转换为从数据中获取有价值见解的数字数组)对于试图将数据武器化的安全工程师和分析师来说,具有最大的心理和认知差距。

有许多日志收集中心缺乏定性分析,无法从获取的数据中推断出必要的可见性。收集数 TB 的日志通常只是为了执行基本的分析(例如,基于签名的基本规则),并且被认为是以一种临时反应式的方式使用—如果需要调查的话。一个没有足够分析注意力的有价值数据的例子——auditedexecve syscall 包含上面图 1 中显示的 Unix shell 命令行。

通过在这些数据的基础上定义人工启发,可以获得许多有价值的推论。当ptyspawn被用在与/dev/shm相同的执行调用或位置的参数中时,你一定要对出现的情况做出反应。然而,在许多情况下,定义一个在特定技术中易于变化的健壮的人工启发式方法是没有希望的。

考虑这两个反向 shell 命令:

php -r '$sock=fsockopen("example.com",4242);system("/bin/sh -i <&3 >&3 2>&3");'bash -i >& /dev/tcp/example.com/4242 0>&1

虽然我们在这两个定义中看到了一个共同的模式,但是检测其中一个的良好的基于规则的逻辑需要十几个带有正则表达式匹配的和/或语句。即使这样,威胁参与者也可以通过修改和引入中间变量名或重新分配文件描述符来逃避大多数手动方法。

在这篇文章中,我们提出了一个思维平面,其中使用机器学习(ML)来定义您的数据基线,作为基于规则的方法的扩展。ML 允许决策边界的构建比手动试探法和直接从数据推断更加通用。我们将:

  • 使用auditd execve 日志来检测 T1059.004 (命令和脚本解释器:Unix Shell)——这是滥用受损 Unix 主机的最常见方式;
  • 讨论 Unix shell 命令的标记化和编码技术(TF-IDF &“散列技巧”);
  • 使用scikit-learnnltk库将命令编码为向量;
  • 利用scikit-learnxgboost库创建机器学习模型并训练监督分类器;
  • 讨论允许评估 ML 模型性能的度量标准;

在本教程中,我们将而不是:

  • 讨论遥测基础设施设置,因此我们不包括auditd配置。如果你想要一个好的起点,使用 Florian Roth 慷慨提供的这个配置。
  • 介绍如何将这些数据提取到您的分析主机中——我们不介绍特定的工具 API 示例。我们遇到过存储在 Elastic、Splunk 和 Spark 集群中的此类数据,根据我们的观察,数据查询对从业者来说并不构成挑战。

如果您愿意考虑数据科学应用于网络安全需求的其他方面,请考虑以下相关主题的文章:

  • 企业中基于统计模式的异常检测;
  • 命令&控制从 Windows EventLog 中检测熊猫;
  • 用递归神经网络监督分析 Sysmon 事件。

形成数据集

auditd (以及 auditbeat 等替代代理)在系统上提供各种类型的活动,例如,网络访问、文件系统操作或进程创建。后者是通过捕获execve syscall 的利用率获得的,根据配置的不同,这些事件可能看起来不同,但最终提供相同的信息:

例 1。审核的 EXECVE 系统调用日志。

例 2。auditbeat 报告的 Auditd EXECVE 系统调用日志。

在这个分析的范围内,我们建议把重点放在派生进程的命令行上。我们建议采用 process.args 中表示的数组,并将其连接成一个字符串,因为:

  • process.title 值通常限制在 128 个字符以内,或者忽略不计;
  • process.args 经常提供不正确的“标记化”命令。

我们对内部数据集的经验证明,使用本文描述的技术, process.args 提供的信息是非常高效的。然而,为了便于写作,我们收集了一个专用的开放数据集,由两部分组成:

  • 合法命令形成于 NL2Bash 数据集[ 林等 2018 ]其中包含来自 quora 等资源的废弃 Unix shell 命令;
  • 真实的威胁参与者和渗透测试人员利用远离陆地的恶意活动来列举和利用 Unix 系统——我们专门为此研究从各种威胁情报和渗透测试资源中手动收集的数据集。

命令预处理

机器学习模型期望编码数据(数字向量)作为其功能的输入。经典自然语言处理(NLP)管道的高级示例可能如下所示:

图二。经典 NLP 管道示意图。作者创造的形象。

可以说,shell 命令行不需要像许多 NLP 应用程序那样清除标点符号,因为 shell 语法在标点符号中嵌入了很大一部分认知知识。但是,您可能仍需要根据收到的遥测信息执行不同类型的清理,例如,域名、IP 地址和用户名的规范化

将文本数据作为特征向量处理的关键步骤是标记化编码,我们将在下面详细讨论。值得一提的是,多年来,传统的 NLP 应用程序开发了许多与 shell 遥测技术不太相关的其他技术,我们在本练习中省略了这些技术。

标记化

数据的预处理和编码高度依赖于字段和特定的数据源。记号化代表了将任何连续序列分成称为记号的基本部分的思想。应用于 shell 语法的标记化比我们在自然语言中看到的要复杂得多,并且带来了几个挑战:

  • 空格并不总是元素分隔符;
  • 点和逗号有专门的含义;
  • 破折号、竖线、分号等标点符号后面的特定值。

图 3。shell 命令敏感部分的概要。作者创造的形象。

我们可以使用作为我们的 Shell 语言处理(SLP)工具包的一部分实现的ShellTokenizer类进行有效的标记化。我们已经证明,对 shell 命令行使用专用的标记器可以显著提高机器学习管道的性能。更多详情,请参考我们的论文【Trizna 2021】。

然而,SLP 记号赋予器比许多优化的 NLP 记号赋予器更费时。因此,我们将使用来自nltk图书馆的WordPunctTokenizer对本文进行探索性分析。它保留了标点符号,并在应用于 Unix shell 命令时提供了一个不错的资源质量权衡。

编码

一旦我们收到一个符号化的命令序列,我们就可以用数字的形式来表示这些序列。有多种方便的方法可以将文本标记序列表示为一个数字数组。我们将考虑:

  • 一个热点
  • 词汇袋
  • “哈希技巧”矢量器
  • TF-IDF(术语频率-逆文档频率)

我建议使用以下数据集建立编码方案背后的直觉:

1\. I love dogs.
2\. I hate dogs and knitting.
3\. Knitting is my hobby and my passion.

对于这样一个数据集, One-Hot 编码看起来是这样的——只是表示特定输入中出现了什么单词:

图 4。单热点向量的简化视图。作者创造的形象。

单词包(BoW)(在的术语中又称为计数矢量器)编码看起来像这样——它对输入中的单独标记进行计数:

图 5。单词袋(又名计数矢量器)向量的简化视图。作者创造的形象。

哈希矢量器 是一个“增强的”单词包,它执行令牌到哈希的映射。您失去了恢复令牌值的能力(因为哈希是一个单向函数),但这大大减少了内存需求,并允许流学习。【k . Ganesan】对哈希矢量器背后的功能做了很好的解释。

TF-IDF 是 BoW 的更高级版本,其中考虑了其他文档中的文字外观:

在示例样本数据集中,这将导致:

图 6。TF-IDF 向量的简化视图。作者创造的形象。

与 One-Hot 和 BoW 相反,TF-IDF 的基于频率的编码允许我们强调代表当前文档的标记,而不强调常见的标记。

令人惊讶的是,哈希矢量器在一些安全应用上的表现明显优于 TF-IDF。稍微脱离上下文,下面是分类任务的 ROC 曲线与我们上面的技术数据集(除了 BoW)的比较:

图 7。不同编码方案的 ROC 曲线。作者创造的形象。

我们看到哈希矢量器对 TF-IDF 和一键编码的结果之间存在差距,这意味着这种预处理方法产生了更好的分类结果。同样的“哈希技巧”优势也在其他安全问题中被注意到,例如,恶意软件分类【Ceschin 和 Bota CIN 2021】。因此,在处理您的数据时,我们建议同时使用 TF-IDF 和 HashingVectorizer 进行实验,并选择在验证集上产生最佳结果的一个。

基于上面的结果,在本文的范围内,我们将使用 HashingVectorizer 和一个定制的标记器。在 ML 社区中,假设使用 X 作为输入数据的符号。因此,可以使用 sklearn 编码器和 nltk 标记器从列表raw_commands中获取“哈希技巧”和 TF-IDF 矩阵,如下所示(使用 IP 地址规范化):

此时,我们得到了一个编码数组——恭喜!

>>> print(X["HashingVectorizer"].shape)
>>> X["HashingVectorizer"][0:3].toarray()(12730, 262144)
array([[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.],[0., 0., 0., ..., 0., 0., 0.]])

此外,当使用监督算法时,我们需要指定由 Y 表示的数据标签来训练模型。在这种情况下,我们将标签 0 分配给良性条目,标签 1 代表恶意条目:

raw_commands **=** benign **+** malicious
Y **=** np**.**array([0] ***** len(benign) **+** [1] ***** len(malicious), dtype**=**int)

机器学习分类器

模型架构

此时,编码数据已准备好由许多机器学习模型进行处理。所以,让我们建立一个深度学习模型吧!?

如果你想立即将数据输入神经网络,请与迈克交谈。不要去神经网络,除非你知道为什么你需要深度学习。深度学习带来的问题通常会阻碍它们在生产环境中的部署:

  • 需要一个大样本来学习一个好的分布(给定被监督的内容——你需要花很多钱来标记数据)
  • 需要明显更多的人力和计算资源来选择神经网络架构的适当配置。

因此,对于作为应用程序所有者的你来说,深度学习显然更加昂贵,并且如果上面的要点没有得到足够的重视,往往会产生更差的结果。

对于分类,我们建议首选是梯度提升决策树(GBDT) 算法,具体是XGBoost实现。

事实证明,XGBoost 是分类“表格数据”——固定长度的向量(我们的例子)——的黄金标准。此外,它还提供了最佳的精度和计算资源组合:

图 8。基于表格数据准确性和训练时间的 ML 模型荟萃分析【博里索夫等 2022】。

很难在不专门写一篇文章的情况下描述 boosted ensemble,但是分两步解释可能如下所示——( 1)每个决策树是一个 if/else 的训练序列;(2)我们做了一些聪明的操作来从许多树中得到一个单一的意见,其中每一个结果树都是基于先前树的错误来训练的。如果你想对 GBDT 有更深入的解释: 1。维基。22。直觉&观想。

模型的训练使用fit()方法完成,预测可以使用predict()(给出标签—恶意或良性)或predict_proba()(返回概率):

上面的脚本块的输出给出了下面的数组:array([[0.1696732, **0.8303268**]], dtype=float32)

这里我们看到调用后门下载和后台执行的 shellshock 被一个概率为 0.8303268 的模型认为是恶意的。如果我们将决策阈值定义为经典的 0.5,这意味着更高的概率导致恶意得分,那么我们的数据集与哈希矢量器的混淆矩阵如下所示:

图 9。使用哈希矢量器预处理方案的分类器训练集上的混淆矩阵。作者创造的形象。

检测工程框架

此时,我们的模型已准备好进行部署,作为检测可疑活动的基础:

  1. 用 ML 模型将 auditd 日志流提取到分析主机;
  2. 从一个 auditd 事件中解析process . args
  3. 标记器&用选定的预处理方法对 args 进行编码,并将其提供给模型的predict_proba()方法;
  4. 如果恶意性超过概率阈值,则向 SIEM/吉拉/SOAR/Slack 报告。

附加说明—在本文中,我们试图在恶意命令和良性命令之间建立一个决策界限。然而,这通常会适得其反,我们建议形成一个数据集,因此 ML 模型侧重于狭窄的 TTP,例如,仅(1)反向外壳检测或(2)被入侵机器的枚举。

在线学习—减少误报

一旦模型被部署并加入到您的检测中,您将会看到误报。因此,我们建议调整恶意阈值,以匹配所需的警报级别(更高的阈值,更少的警报,但更多的假阴性)。

然而,这个模型可以而且应该被重新训练来避免这些错误。一种方法是用具有正确标签的新示例更新初始训练数据集,并从头开始重新训练模型。第二种方式是利用在线学习技术,从数据流中更新模型。一些模型实现了partial_fit(),并允许在新数据进来时更新模型行为。关于该主题,请参考 sklearn 文档。对于这些需求,我们建议使用在sklearn—MLP 分类器中实现的基本神经网络来代替XGBClassifier(MLP 或Multi-LlayeredPer ception 是机器学习的一个老式名称)。

例如,考虑到假阳性的发生,在这些情况下,模型可能仅在特定命令上被重新训练:

结论

虽然高级人工智能已经极大地改变了自然语言处理(NLP)或计算机视觉(CV)应用程序,但我们正在慢慢采用这些技术来满足网络安全需求。虽然该行业在某些方向取得了显著的成果,如从可移植可执行(PE)文件中进行恶意软件分类,或者出现了一些好的文献(例如,从威尔·施罗德T2 开始的一系列出版物),但是使用 ML 技术进行以安全为重点的行为分析的资料仍然很少。

正如本文所示,无需实施昂贵的深度学习解决方案和在 R&D 上大量投资,只需使用本主题中讨论的传统技术,就可以实现显著的改进。通过对特定信息安全问题的聪明的、选择性的应用,即使简单的 ML 技术也能在安全工程师和分析师的日常操作中产生显著的改进。

我们希望本出版物中分享的信息将激励安全爱好者尝试 ML 技术来解决他们的任务,从而最大限度地缩小数据科学和信息安全之间的差距。Infosec 还需要克服一个适用性缺口,用数据科学界在过去十年中揭示的宏伟技术来增强该领域的能力。本文范围内所做的所有实验,都可以在这个笔记本里找到。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/816719.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TowardsDataScience-博客中文翻译-2022-四十九-

TowardsDataScience 博客中文翻译 2022(四十九)原文:TowardsDataScience 协议:CC BY-NC-SA 4.0测量误差对线性回归模型的影响原文:https://towardsdatascience.com/the-effect-of-measurement-errors-on-a-linear-regression-model-c853bb689974图片由皮克斯贝 ( 牌照)的安…

TowardsDataScience-博客中文翻译-2022-二十九-

TowardsDataScience 博客中文翻译 2022(二十九)原文:TowardsDataScience 协议:CC BY-NC-SA 4.0如何使用计算机视觉读取酒瓶上的标签?(第一部分)原文:https://towardsdatascience.com/how-to-read-a-label-on-a-wine-bottle-using-computer-vision-part-1-25447f97a761欢迎…

格点拉格朗日插值与PME算法

本文介绍了使用基于格点拉格朗日插值法的Particle Mesh Ewald算法,降低分子力场中的静电势能项计算复杂度的基本原理。静电势能的计算在Ewald求和框架下被拆分成了远程相互作用项和短程相互作用项,其中短程相互作用项关于实空间的点电荷间距快速收敛,而远程相互作用项在倒易…

公司网站怎么修改?数据库内网站密码修改?

修改公司网站通常涉及以下几个步骤:确定需求:明确需要修改的内容,如页面设计、功能增加或信息更新等。 收集相关资料和内容,确保所有需要的信息都准备齐全。选择工具或平台:如果网站是基于WordPress、Joomla等CMS系统构建的,可以通过后台直接进行编辑。 对于自定义开发的…

修改默认登录网站密码?

修改默认登录网站密码通常涉及以下几个步骤,具体操作可能会根据不同的网站或系统有所差异:登录账户:打开你需要修改密码的网站。 使用当前的用户名和密码登录你的账户。进入账户设置:登录后,找到并点击“账户”、“个人资料”或“设置”等相关链接或按钮。 在账户设置页面…

如何在后台修改网站资料?网站后台如何修改字体?

在后台修改网站资料通常涉及以下几个步骤,具体操作可能会根据不同的内容管理系统(CMS)或网站平台有所不同:登录后台管理界面:使用管理员账号和密码登录到网站的后台管理界面。导航至内容管理:在后台找到“内容管理”、“页面管理”或类似的选项,这通常是编辑网站资料的地…

网站模板修改?网站模板咋样修改?

1. 确定修改目标功能需求:明确需要添加或删除的功能。 设计需求:确定颜色、布局、字体等视觉元素的调整。2. 备份现有模板在进行任何修改之前,确保备份当前使用的模板文件,以防修改过程中出现错误可以恢复原状。3. 修改HTML/CSSHTML:根据功能需求,编辑HTML结构,添加或删…

C语言小白记录自己的错题和总结

​ 计算n个a的思路都是用a+a10+a100…… 然后在累加 记得用include<math.h> pow 考察逗号表达式 即使像x+y x+7之类的 算出结果后 x和y还是不变 因为没有赋值 所以x和y都是原来的值 问号语句 先计算第一个表达式 若他的值为非0(即真)将表达式2的值作为条件表达式的值…

数据库系列:主从延时优化

相关文章 数据库系列:MySQL慢查询分析和性能优化 数据库系列:MySQL索引优化总结(综合版) 数据库系列:高并发下的数据字段变更 数据库系列:覆盖索引和规避回表 数据库系列:数据库高可用及无损扩容 数据库系列:使用高区分度索引列提升性能 数据库系列:前缀索引和索引长…

平衡堆栈

理解并观测函数调用母函数做什么,子函数做什么cdecl调用约定#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>int __cdecl method(int x, int y){ return x + y;}int main(){ __asm mov eax, eax; // 此处设置断点 method(1, 2); return 0;}可以看出_…

怎样修改网站管理密码?

修改网站管理密码的方法取决于您使用的网站管理系统(CMS)或托管服务。以下是一些常见平台的修改方法: 1. WordPress通过WordPress后台:登录到WordPress后台。 进入“用户” > “我的个人资料”。 修改“密码”字段,输入新密码并确认。 点击“更新个人资料”保存更改。通…

视频监控人员行为识别

视频监控人员行为识别技术基于先进的计算机视觉和深度学习算法。视频监控人员行为识别利用大量的视频数据进行模型训练,使算法能够学习和识别员工的不同行为特征。然后,将训练好的模型应用到实际的监控系统中,对员工的行为进行实时监测和分析。视频监控人员行为识别通过视频…