TowardsDataScience-博客中文翻译-2021-二十四-

龙哥盟 / 2024-10-21 / 原文

TowardsDataScience 博客中文翻译 2021(二十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

从头开始编码线性回归

原文:https://towardsdatascience.com/coding-linear-regression-from-scratch-c42ec079902?source=collection_archive---------0-----------------------

使用 python 从零开始实现线性回归

由 NASA 在 Unsplash 上拍摄的照片

这篇文章是“基础与超越”系列中的线性回归文章的后续,所以如果你刚刚开始机器学习,我建议你先看完那篇文章,然后从这篇教程开始。如果你已经知道什么是线性回归,那么让我们开始吧!

https://medium.com/analytics-vidhya/basics-and-beyond-linear-regression-c12d99a4df35

在本帖中,我们将使用 python 从头开始编写整个线性回归算法,所以今天我们真的要动手了!

我们走吧!

数据

任何机器学习问题的第一步都是获取数据。如果没有可以“学习”的东西,就没有机器“学习”。因此,在本教程中,我们将使用一个非常常见的数据集进行线性回归,即房价预测数据集。数据集可以在 这里找到

这是一个包含俄勒冈州波特兰房价的简单数据集。第一栏是房子的大小(平方英尺),第二栏是卧室的数量,第三栏是房子的价格。您可能已经注意到,我们的数据集中有多个要素(即 house_size(以平方英尺为单位)和房间数量),因此我们将查看多元线性回归,标签( y )将是房价,因为这是我们将要预测的价格。

让我们定义加载数据集的函数:

稍后我们将调用上面的函数来加载数据集。该函数返回 xy (注意 x 由数据集的前 2 列组成,而 y 是数据集的最后一列,因为它是价格列,因此为了返回 xy ,我们将分别从函数中返回data[:,:2]data[:,-1] )。

标准化数据

上面的代码不仅加载数据,而且对其进行归一化并绘制数据点。我们一会儿会看一下数据图,但首先让我们理解上面的normalize(data)行是干什么的。如果您查看 原始数据集 ,您会注意到第二列中的值(即房间数量)比第一列中的值(即房屋大小)小得多。我们的模型不会将这些数据作为房间数量或房屋大小来评估。对于模型来说,它只是数字。这可能会在您的机器学习模型中产生一种不必要的偏向,即偏向数值比其他列(或特征)高的列。它还会造成方差和数学平均值的不平衡。出于这些原因,也为了使工作更容易,建议您缩放或归一化您的要素,使它们都位于相同的范围内(例如[-1 比 1]或[0 比 1])。这使得训练更加容易。因此,出于我们的目的,我们将使用特征归一化,从数学意义上来说,它意味着:

Z = (x — μ) / σ

μ:平均值

σ:标准偏差

在上面的公式中 z 是我们的归一化特征, x 是非归一化特征。如果你对这些数学概念不是很熟悉,也不用担心。快速回顾会让你开始行动。好了,现在我们有了归一化公式,让我们做一个归一化函数:

这段代码正是我们所讨论的。它遍历每一列,并使用这些元素的平均值和标准偏差对该列的所有数据元素进行标准化。

绘制数据

现在,在我们开始编写线性回归模型之前,我们需要问的一件事是为什么

为什么我们要用线性回归来解决这个问题?这是一个非常有效的问题,在实际跳到任何具体的代码之前,你应该非常清楚你想要使用什么算法,以及对于给定的数据集和你试图解决的问题,那个是否真的是最好的选择。我们可以证明为什么使用线性回归对我们当前的数据集有效的一种方法是绘制它。为此,我们在上面的load_data中调用了plot_data函数。现在让我们定义plot_data函数:

该函数在被调用时会生成以下图形:

房屋面积与房价的关系图(图片来源:作者提供)

你可以看到,通过上面的图可以大致拟合出一条线。这意味着一个线性近似将实际上允许我们做出相当准确的预测,因此我们选择线性回归。

现在我们已经准备好了数据,让我们进入有趣的部分。编码算法!

假设

首先,我们需要定义我们的假设函数是什么样的,因为我们以后会用这个假设来计算成本。我们知道对于线性回归我们的假设是:

hθ(x) = θ0 + θ1x1 + θ2x2 + θ3x3 +…..+ θnxn

然而,我们的数据集只有 2 个特征,因此对于我们当前的问题,假设是:

hθ(x) = θ0 + θ1x1 + θ2x2

其中 x1x2 为两个特征(即房屋大小和房间数量)。让我们将它放入一个简单的 python 函数中,该函数返回假设:

矩阵乘法是怎么回事?!不要担心,它仍然给我们相同的假设方程,我们将在这篇文章的后面更深入地研究为什么这在数学上是正确的。

好了,现在我们有了假设函数,下一个重要的是成本函数。

价值函数

为了评估我们模型的质量,我们使用了成本函数。同样,这篇文章是以下内容的“代码版本”:

https://medium.com/analytics-vidhya/basics-and-beyond-linear-regression-c12d99a4df35

因此,如果这里有什么不明白的地方,你可以浏览一下,或者跟着这两篇文章走。好了,成本函数的等式是:

来源:霍尔豪斯

我们成本函数的代码是:

仔细观察,您可能会注意到,到目前为止我们定义的所有 python 函数都与我们之前为线性回归定义的数学方法完全相同。现在我们有了成本,我们必须最小化它,为此我们使用…是的,梯度下降!

梯度下降

在我们的上下文中,梯度下降是一种优化算法,旨在调整参数以最小化成本函数。

梯度下降的主要更新步骤是:

来源:霍尔豪斯

所以我们把代价函数的导数乘以学习率( α) ,再从参数的现值( θ )中减去,得到新的更新参数( θ )。

gradient_descent函数返回thetaJ_alltheta显然是我们的参数向量,其包含假设的 θs 的值,并且J_all是包含每个时期之后的成本函数的列表。J_all变量并不完全是必需的,但是它有助于更好地分析模型,你将在后面的文章中看到。

把所有的放在一起

现在剩下要做的就是按照正确的顺序调用我们的函数:

我们首先调用load_data函数来加载 xy 的值。 x 包含训练示例,而 y 包含标签(在我们的例子中是房价)。

你可能已经注意到,在整个代码中,我们一直在使用矩阵乘法来实现我们想要的表达式。例如,为了获得假设,我们必须将每个参数( θ )与每个特征向量( x )相乘。我们可以使用进行循环,循环每个示例,每次都执行乘法。但是,如果我们有 1000 万个训练示例,这将不是最有效的方法。这里更有效的方法是使用矩阵乘法。如果你对矩阵乘法不是很熟悉,我建议你 复习一遍 ,它相当简单。对于我们的数据集,我们有两个特征(即房屋大小和房间数量),因此我们将有(2+1) 3 个参数。额外的参数 θ0 可以通过考虑假设在图形意义上只是一条线来说明。所以额外的 θ0 说明这条线是符合要求的。

有利假设函数图(来源:图片由作者提供)

好了,我们有 3 个参数和 2 个特征。这意味着我们的 θ 或参数向量(一维矩阵)将具有维度(3,1),但是我们的特征向量将具有维度(46,2){根据我们的数据集}。你可能已经注意到,这两个矩阵相乘在数学上是不可能的。让我们再次看看我们的假设:

hθ(x) = θ0 + θ1x1 + θ2x2

如果你仔细观察,它实际上是非常直观的,如果我们在我们的特征向量(x)的开始添加一个额外的 1 的列{使它具有维度(46,3)}并且如果我们对 x 和θ执行矩阵乘法,我们实际上将得到上面的等式 hθ(x)。如果还是不明显,那就试着在纸上画一个例子。

请记住,当我们实际运行代码来实现这个函数时,我们不会返回类似于 hθ(x) 的表达式,而是返回这个表达式所计算出的数学值。

在上面的代码中,x = np.hstack((np.ones((x.shape[0],1)), x)) 行在 x 的开头添加了一列额外的 1,以允许所需的矩阵乘法。

在这之后,我们用零初始化θ向量。你也可以用一些小的随机值初始化它。我们还指定学习速率和我们想要训练的时期数(时期是算法将遍历整个数据集的次数)。

一旦我们定义了所有的超参数,我们调用梯度下降函数,它返回所有成本函数的历史和参数的最终向量theta。这个theta向量本质上定义了我们的最终假设。您可能会注意到梯度下降函数返回的theta向量的形状具有维度(3,1)。还记得我们的假设函数吗?

hθ(x) = θ0 + θ1x1 + θ2x2

我们需要 3 个 θs ,我们的theta向量的维数是(3,1),因此theta[0]theta[1]theta[2]实际上分别是 θ0、θ1θ2J_all变量只不过是所有成本函数的历史。您可以打印J_all数组来查看成本函数如何在每个梯度下降的时期逐渐降低。

成本与时代数量的关系图(来源:作者提供的图片)

可以通过定义和调用 plot_cost 函数来绘制此图,如下所示:

现在,我们可以使用这些参数来查找标签,即给定房屋大小和房间数量的任何房屋(在俄勒冈州波特兰市)的价格。

试验

现在,您可以调用一个测试函数来测试您的代码,该函数将房子的大小、房间的数量以及由我们的线性回归模型返回的最终theta向量作为输入,并将给出房子的价格。

完整的代码

就是这样!

信不信由你,这就是线性回归编码的全部内容。恭喜你!现在,您已经完全从头开始成功地编写了一个线性回归模型。能够理解并编码整个算法并不容易,所以你可以为自己的成功感到自豪。线性回归通常是我们开始机器学习的第一个算法,所以如果你理解我们在这里做的事情,我建议你选择另一个数据集(用于线性回归),并尝试自己应用线性回归。快乐编码:)

参考

您可以在此找到完整的代码和数据集,以供参考:

https://github.com/kumudlakara/Medium-codes/tree/main/linear_regression

  1. https://medium . com/analytics-vid hya/basics-and-beyond-linear-regression-c 12d 99 a4 df 35
  2. https://www.coursera.org/learn/machine-learning/home/
  3. 【https://www.holehouse.org 号

从头开始编码逻辑回归

原文:https://towardsdatascience.com/coding-logistic-regression-from-scratch-d18b4fbfca8a?source=collection_archive---------17-----------------------

使用 python 从零开始实现逻辑回归。

由 NASA 在 Unsplash 上拍摄的照片

这篇文章是“基础知识及以后”系列中的逻辑回归文章的后续。因此,如果你是机器学习的新手,那么我建议你先浏览一下这篇文章,但是如果你已经知道什么是逻辑回归,那么让我们开始工作吧!

https://medium.com/analytics-vidhya/basics-and-beyond-logistic-regression-34549d2ee800

在这篇文章中,我们将使用 python 编写一个逻辑回归模型。所以让我们开始吧!

数据

任何机器学习算法的核心都是数据。你的机器学习模型总是需要数据来“学习”。因此,为了我们今天的目的,我们将使用一个非常简单的学生录取结果数据集,可以在这里找到https://github.com/kumudlakara/Medium-codes/blob/main/logistic_regression/student_result_data.txt

该数据集包含申请者的历史记录。一个记录包括申请人在两次入学考试中的成绩和最终的录取决定(无论该考生是否被录取)。我们今天的目标是建立一个逻辑回归模型,它将能够决定(或者更好地分类)一个申请人是否应该被录取。在我们的数据集中,前两列是两个测试中的标记,第三列是以二进制编码的决策标签( y )(即 y = 1,如果允许,而 y = 0,如果不允许)。我们的目的是预测这个标签 y

好了,现在我们知道了数据的样子,让我们定义一个函数来加载数据。

稍后我们将调用上面的函数来加载数据集。该函数返回 xy (注意 x 由数据集的前 2 列组成,而 y 是数据集的最后一列,因为它是结果列,因此为了返回 xy ,我们将从函数中分别返回data[:,:2]data[:,-1] )。

您可能已经注意到了load_data函数中的另一个函数调用:plot_data(data[:, :2], data[:, -1])。如果你已经阅读了“从头开始编码线性回归”这篇文章,你可能已经知道这个函数在做什么,你可以直接跳到这篇文章有趣的编码部分,但是如果你还没有,那就留下来,因为我们将要更深入地研究我们数据的分布。

绘制数据

在我们开始编码我们的模型之前,让我们花一点时间来分析我们的数据。这将允许我们理解为什么(如果有的话)逻辑回归是我们给定数据集和相关问题的出路。

为了可视化数据,让我们定义从load_data调用的plot_data函数。

该函数在被调用时会生成以下图形:

数据图(来源:图片由作者提供)

只需快速浏览一下上面的图,就可以清楚地看到,我们的数据确实有一个决策边界,在这种情况下,它似乎是一条直线。这里需要特别注意的是,我们的决策边界很简单,因为我们的数据集恰好分布在决策边界近似为一条直线的地方。需要注意的是,逻辑回归可以用来预测比我们当前问题所显示的更复杂的决策边界。使用逻辑回归甚至可以预测椭圆和非几何决策边界。

唷,那是很难接受的。好了,现在我们已经准备好数据,让我们开始编码实际的线性回归模型!

假设

定义模型架构的第一步是定义假设。我们知道线性回归的假设实际上是 sigmoid 函数,所以从数学上讲,我们的假设是:

来源:作者

sigmoid 函数看起来像这样:

sigmoid 函数图(来源:图片由作者提供)

现在让我们定义一个简单的 python 函数,它反映了数学等式:

我们将该函数命名为 sigmoid,而不是 hypothesis 或 h ,当您在程序的后面部分看到该函数在语句中被调用时,例如在h = sigmoid(x@theta)中,这将变得更加直观。

好了,现在我们有了假设,让我们进入下一步,即成本函数。

价值函数

为了评估我们的模型输出的质量,在我们的例子中是 y =1(承认)或 y =0(拒绝),我们使用了成本函数。

如果你感到有点失落,你可以随时关注“基础和超越:逻辑回归”的帖子,因为这个帖子正是那个帖子的代码版本。

**https://medium.com/analytics-vidhya/basics-and-beyond-logistic-regression-34549d2ee800

好了,为了我们的目的,让我们直接跳到逻辑回归的成本函数方程:

逻辑回归的成本函数(来源:作者)

同样的代码是:

看到我们在每个训练示例中单独使用矩阵乘法而不是实际求和,这可能看起来很荒谬。使用矩阵乘法实际上达到了同样的结果。我们将在稍后的文章中讨论这个问题。

现在我们有了成本函数,接下来呢?我们的目标是总是最小化我们模型的成本,所以如果我们有了成本函数,我们就有可能找到最小化它的方法。有许多方法(有些甚至比我们将要使用的方法更有效)来最小化成本函数,但是因为我们在这里的目的是完全从头开始编码,所以我们将编码梯度下降算法来最小化成本函数,而不是使用“开箱即用”的优化器。那么让我们直接进入梯度下降。

梯度下降

在我们的上下文中,梯度下降是一种优化算法,旨在调整参数以最小化成本函数。

梯度下降的主要更新步骤是:

来源: holehouse

这里我们可以看到这个算法其实和线性回归的算法是一样的。然而,唯一的区别是假设函数 h(x) 的定义,它是逻辑回归情况下的 sigmoid 函数。于是我们把代价函数的导数乘以学习率( α) ,再从参数的现值( θ )中减去,得到新的更新参数( θ )。让我们用 python 再说一遍:

gradient_descent函数返回thetaJ_alltheta显然是我们的参数向量,其包含假设的 θs 的值,而J_all是包含每个时期之后的成本函数的列表。J_all变量并不完全是必需的,但它有助于更好地分析模型,你将在后面的文章中看到。

把所有的放在一起

现在我们已经定义了所有的函数,我们需要做的就是以正确的顺序调用它们。

我们首先调用load_data函数来加载 xy 的值。 x 包含训练样本, y 包含标签(在我们的例子中是录取结果)。

你可能已经注意到,在整个代码中,我们一直在使用矩阵乘法来实现我们想要的表达式。例如,为了得到假设,我们必须将每个参数( θ )与每个特征向量( x )相乘,并将其传递给 sigmoid 函数。我们可以使用 for loops for this,并在每个示例上循环,每次都执行乘法,但是如果我们有 1000 万个训练示例,这将不是最有效的方法。这里更有效的方法是使用矩阵乘法。如果你对矩阵乘法不是很熟悉,我建议你 复习一遍 ,它相当简单。对于我们的数据集,我们有两个特征(即申请人在两次测试中的分数),因此我们将有(2+1) 3 个参数。额外的 θ0 说明我们的决策边界(在我们的例子中是一条近似的线)是必需的。

有利假设函数图(来源:作者图片)

好的,我们有 3 个参数和 2 个特征。这意味着我们的 θ 或参数向量(一维矩阵)将具有维度(3,1),但是我们的特征向量将具有维度(99,2){根据我们的数据集}。你可能已经注意到,这两个矩阵相乘在数学上是不可能的。然而,如果我们在特征向量的开头添加一列额外的 1,我们将得到两个维度为(99,3)和(3,1)的矩阵。这两个矩阵现在在尺寸上是兼容的。

在上面的代码中,x = np.hstack((np.ones((x.shape[0],1)), x)) 行在 x 的开头添加了一列额外的 1,以便根据需要进行矩阵乘法。

在这之后,我们用零初始化θ向量。你也可以用一些小的随机值初始化它。我们还指定学习速率和我们想要训练的时期数(时期是算法将遍历整个数据集的次数)。

一旦我们定义了所有的超参数,我们调用梯度下降函数,它返回所有成本函数的历史和参数的最终向量theta。这个theta向量本质上定义了我们的最终假设。您可能会注意到梯度下降函数返回的theta向量的形状具有维度(3,1)。请记住,我们数据集中的每个单独的训练示例也有 3 个字段(2 个原始特征和 1 个后来添加的额外列)。因此,最终的theta向量的每个元素,即theta[0]theta[1]theta[2]实际上分别是 θ0、θ1θ2 ,并且对应于我们的训练示例的每个字段的参数。所以现在我们的最终假设看起来是这样的:

来源:作者

J_all变量只不过是所有成本函数的历史。您可以打印J_all数组来查看成本函数如何在每个梯度下降的时期逐渐降低。

成本与时代数量的关系图(来源:作者提供的图片)

该图可以通过定义和调用plot_cost函数来绘制,如下所示:

现在,我们可以简单地插入我们的参数,并从我们的模型中获得预测。但是等等?!我们的模型没有预测 y =0 或 y =1,事实上我们模型的输出是一个浮点数。这实际上是应该发生的。奇怪的浮点输出实际上是一个例子属于类 y =1 的概率。所以我们现在需要给我们的模型添加最后一个函数。这是预测部分。

预测

让我们定义一个简单的函数来解释我们模型的概率输出,以预测 *y=1(承认)*或 y=0(拒绝)

上面的代码在概率(我们模型的输出)大于等于 0.5 的情况下,将示例分类为属于 y =1(录取)类(或组),否则输出 y =0(拒绝)。

试验

现在,您可以通过调用一个测试函数来测试您的代码,该函数将申请人在两次测试中的分数大小和由我们的逻辑回归模型返回的最终theta向量作为输入,并将向我们提供申请人是否应该被录取的最终结果。

完整的代码

就是这样!

嗯,差不多就是这样。您现在可以完全从头开始编写逻辑回归代码。能够理解完整的算法并编码它,不是一件容易的事情,所以,干得好!如果你对我们在这篇文章中提到的例子感到满意,请随意挑选另一个数据集(用于逻辑回归)并尝试一下。

编码快乐!:)**

参考

您可以在此找到完整的代码和数据集,以供参考:

**https://github.com/kumudlakara/Medium-codes

  1. https://medium . com/analytics-vid hya/basics-and-beyond-logistic-regression-34549 D2 ee 800
  2. 【https://www.coursera.org/learn/machine-learning/home/ 号
  3. 【https://www.holehouse.org **

CODIR:训练更小、更快的 NLP 模型

原文:https://towardsdatascience.com/codir-train-smaller-faster-nlp-models-bac6318a9950?source=collection_archive---------79-----------------------

知识提炼的独特方法

亚当·温格在 Unsplash 上的照片

随着 BERT 和 GPT-3 等大型预训练模型的出现,自然语言处理领域发生了革命性的变化。这些模型已经能够从它们接受训练的大量文本中捕获难以置信的大量信息,并使用这些信息来达到最先进的性能,并不断改进各种各样的任务,如分类、摘要和推理。

这些型号性能出色的一个原因是它们的尺寸。BERT-base 有 1.1 亿个参数,BERT-large 有 3.4 亿个参数,GPT-2 有 15 亿个参数,GPT-3 有 1750 亿个参数。随着这些模型规模的增长,预处理它们所需的时间和资源也在增加。为了提高这些模型的成本和资源效率,一系列专注于减小模型大小的研究正在兴起。为此,采用了几种技术:

  • 量化专注于减少模型权重的大小(从 32 位数减少到 16 或 8 位数)。
  • 修剪识别冗余权重并尝试丢弃它们。
  • 知识蒸馏专注于通过尝试将较大的模型(教师)与较小的模型(学生)匹配来创建较小的微调模型。像 DistilBERT 和 MobileBERT 这样的模型扩展了这个概念,使用 BERT 老师创建了更小的预训练模型。

一般来说,知识提炼包括两个部分:

  1. **原始训练目标:**该目标着重于让学生模型学习正确的标签(在微调期间)或正确的预训练目标
  2. **提炼目标:**这个目标试图将学生的输出概率(以及可能的隐藏状态)与教师的输出概率相匹配。这是通过选择一个距离度量并最小化学生和老师之间的距离来实现的。

微软动态 365 人工智能研究所的研究人员试图通过不同的视角来解决蒸馏问题。与其尝试最小化老师和学生之间所有例子的距离,为什么不尝试最大化错误例子之间的距离,最小化真实例子之间的距离?这导致他们提出了 CODIR,一种使用对比学习向学生提取教师隐藏状态的技术。CODIR 可应用于预训练和微调阶段。

与传统的知识提炼技术不同,CODIR 有 3 个组成部分:

  1. **最初的训练目标:**这与常规 KD 相同
  2. **蒸馏目标:**与常规 KD 不同,该目标使用 KL 散度损失来教导学生预测与教师相似的概率分布。它只适用于学生模型的输出。
  3. **对比学习目标:**该目标着重于将学生的隐藏状态与教师的隐藏状态拉开距离,以获得负面示例,并将其与正面示例相匹配。

孙等人的 CODIR 训练框架。

将 CODIR 应用于微调阶段非常简单。因为训练样本有标签,所以负样本只是那些与正样本有不同标签的样本。

在预培训阶段,没有标签,因此应用对比学习目标变得更具挑战性。研究人员在 RoBERTa 模型上测试 CODIR,该模型使用掩蔽语言建模作为预训练目标。在这种情况下,反面例子是来自同一篇文章的被掩盖的句子或文本,因此它们在语义上与正面例子相似。这样,对比学习的目标就不会变得太容易解决。

研究人员使用 CODIR 将 Roberta 模型减少到 6 层,并在 GLUE 数据集上验证其有效性。该模型实现了与原始 BERT 模型几乎相同的精度,而推理时间只有原来的一半。

这里有一个链接到论文,如果你想了解更多关于 CODIR 的内容,一个链接到代码,你可以提炼出你自己的模型,点击这里可以看到更多我们的出版物和其他工作。

参考文献

  1. 维克多桑,弗拉达利首次亮相,朱利安肖蒙德,和托马斯沃尔夫。2019.蒸馏伯特,伯特的蒸馏版:更小、更快、更便宜、更轻。 arXiv 预印本 arXiv:1910.01108。
  2. 孙志清、俞鸿坤、宋、刘、和周丹妮。2020. Mobilebert:一个紧凑的任务无关的 bert,用于资源有限的设备。arXiv 预印本 arXiv:2004.02984。
  3. 孙思齐,何哲,俞成,,方,王硕航,。“用于语言模型压缩的中间表示的对比提取” arXiv 预印本 arXiv:2009.14167 (2020)。

按镜头类型的咖啡流量分析

原文:https://towardsdatascience.com/coffee-flow-analysis-by-shot-type-51bc41a5032c?source=collection_archive---------22-----------------------

咖啡数据科学

更多关于分层浓缩咖啡的分析

在之前的中,我研究了流量参数与一杯好的浓缩咖啡的关系。我没有发现任何新的东西,但后来我对镜头类型进行了细分,我开始看到一些有趣的变量。我的数据中的一个混淆变量在多种类型的分层拍摄中,它们在流动上有差异。

浓缩咖啡系列:

  1. 普通浓缩咖啡
  2. 断奏被篡改
  3. Sudo-Staccato
  4. 双双

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

使用折射仪测量总溶解固体量(TDS),该数字与咖啡的输出重量和输入重量相结合,用于确定提取到杯中的咖啡的百分比。

流量指标

我编了一些我认为可能对心流感兴趣的指标。我把预输注(PI)和输注分开。我没有看压力脉动,而是平稳的流动。

对于预注入,我将其减半,因为通常 PI 开始缓慢,然后加速。对于输液,我看着向上和向下的趋势,如下图所示,至于我的杠杆机器,我在整个拍摄过程中积极调整流量。

此外,我还查看了喝 1 克咖啡以及 2、3、4、5、6、7 和 8 克咖啡的时间。

覆盖过滤器的时间(TCF)和 T10(达到 10 毫升的时间)这两个变量我已经使用了将近一年,以帮助在更高水平上跟踪流量的差异。它们和一杯好的浓缩咖啡有很好的相关性。

数据分析

在我之前的作品中,我解释了我从流量日志中获得的变量。这项工作中使用的主要指标是相关性。

相关性是衡量两个变量彼此相似程度的指标。高度相关并不意味着一个变量会引起另一个变量,而是当情况发生变化时,两个变量的涨跌幅度相同。相关性可以是正的(趋势相同)或负的(趋势相反)。0 表示没有相关性。

这是按镜头类型的第一个细分:

似乎很清楚,对于常规拍摄,有一些与第一个输出权重块的时间百分比相关的流度量。

让我们把这些图表分成更小的部分。

****

π/TCF 对于普通投篮和两双来说是一个很好的指标,但对于其他人来说可能就没那么好了。压力脉动泵的数量似乎也无关紧要。对于常规拍摄,预灌注的斜率似乎影响较大。

如果我们关注不同重量的时间和达到这些重量的击球时间的百分比,一些有趣的趋势出现了。就味道而言,击球速度越快,双倍击球的味道就越好,但这并不适用于 sudo-staccato。而 EY 也有类似的趋势。

然而,达到一定重量所需的时间百分比与常规注射的高提取率高度相关。这意味着花费在预输注(PI)中的时间比例越高越好,因为前 8 至 10g 通常是在这些注射的预输注期间。

我从这些故障中得出的最好结论是,情况仍不明朗。似乎这些不同类型的分层快照从根本上彼此不同,因此修改每个分层快照的参数可能具有挑战性。

我原以为更多的数据会揭示出简单的模式或者一些新的东西,但是浓缩咖啡面临的挑战是多重的、相互关联的变量问题。我怀疑,如果找到一种简单明了的方法,全力以赴从多方面改进浓缩咖啡,那会令人失望。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡滤纸

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维护

咖啡评论和想法

咖啡实验

通过颗粒分布比较咖啡研磨机

原文:https://towardsdatascience.com/coffee-grinder-comparison-via-particle-distribution-607534fe1897?source=collection_archive---------27-----------------------

咖啡数据科学

最近发生了两件事:我买了一个利基零,我开发了一个基于图像的颗粒分布测量方法。当我清理我的韩国研磨机准备退休或搬迁时,我想我可以很容易地在几个研磨设置的研磨机之间进行比较,看看它们的性能如何。

所有图片由作者提供

我有四台研磨机,按购买顺序排列如下:

  1. 哈里欧
  2. 韩国
  3. Lume
  4. 小生

我一开始买了一个 Hario 研磨机,因为我很便宜,我没有意识到它不是一个好的浓缩咖啡研磨机。然后我买了一辆 Rok,5 年来它一直是我的支柱。我买了一辆旅行车。为了磨时间和方便,我决定买个小生。

所有的毛刺除了壁龛的。我不是为了好玩才拿出全新的刀片。顺序:韩国、Lume、Hario

研磨机比较中的大多数颗粒分布是单一研磨设置。我做了一些研磨设置,以了解研磨机如何在多种情况下工作。我尝试使用类似的点击量,通常,我知道什么是太精细,什么是太粗糙,什么是刚刚好。

单个研磨机数据

这里是每个研磨机的分布。

Hario 是最难操作的,因为它磨起来很慢,很难拨入。

我爱韩国。我已经用了好几年了,通常是在零位。它很好地控制了地面设置的变化。

我为旅行买了 Lume,但是它没有我想要的那么快。这是非常敏感的设置,但我已经得到了很好的咖啡。

利基是可怕的,真的允许细微的增量变化。

比较 3 个设置

我不认为这些设置是等价的,但我认为比较精细、中等和粗糙设置会很有趣。

Lume 在最精细的设置下有一个更多细屑的奇怪缺口,但这可能只是比其他研磨机更精细一点。

对我来说很奇怪的是,Hario 的设置 6 与 Niche 的设置 10 如此接近

这个粗的确实能看出 Lume 是怎么起飞的,但是发行还是有很多细的。我不确定这是否令人惊讶,因为它们都是锥形毛刺。

最终,我的目标是使用这种方法来更好地了解小生境,并且,私下里,我正试图在多种研磨设置中给出平面和锥形毛刺之间的量化比较。这也有助于鉴定研磨机,也许我们最终可以查看多个研磨机,以了解它们应该如何相互排序。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

使用图像处理测量咖啡研磨颗粒分布

使用筛子改进咖啡研磨测量

使用先进的图像处理技术测量咖啡渣中的粉末

使用自适应阈值改善咖啡研磨分布

拍摄咖啡渣进行研磨分布分析

咖啡渣遇水膨胀

原文:https://towardsdatascience.com/coffee-grounds-expand-with-water-9f0b2ddb8a56?source=collection_archive---------35-----------------------

咖啡数据科学

使用研磨分布了解水如何影响咖啡

以前,我研究过咖啡渣遇水膨胀的想法。我利用冰球缩小的体积得出了这个结论。然而,我有机会通过使用咖啡渣和研磨分布来近距离观察。我还观察了一次拍摄前后的研磨分布,由于拔牙的缘故,的研磨面缩小了。

作者的所有图片

我首先在一些数据中注意到了干燥的影响。我测量了一堆地上的两个样本的分布。更具体地说,我从一个干的用过的咖啡球的顶部和底部取样。一天后,我取了另一个样本,我注意到两个分布都发生了变化。

这是咖啡渣吸收了水分的有力证据,但我想要更多的控制,因为我测量了两个不同的样本。

所以我取了一个样本,测量了它的分布。然后我让它干 12 个小时(过夜);我的房子很干燥。新的测量是对同一个样本进行的,在分布上有一个明确的变化。

我从一开始就测量了几次这个样本的分布,有一个明确的颗粒收缩的趋势。

这种分布上的变化是一个很好的证据,表明咖啡在提取过程中吸收了水分,随着水分从咖啡渣中变干,咖啡渣开始膨胀,这表明咖啡渣在收缩。

这些数据还表明,一旦开始拍摄,咖啡磨粒之间的潜在间隙将会缩小,因此冰球内任何粒子移动的主要时间将是在拍摄的最开始。

如果你愿意,可以在推特和 YouTube上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

使用图像处理测量咖啡研磨颗粒分布

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡滤纸

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维修

咖啡评论和想法

咖啡实验

“我思故我在”——用另类的思维框架对数据和决策进行建模

原文:https://towardsdatascience.com/cogito-ergo-sum-modeling-data-and-decisions-with-offbeat-thought-frameworks-4f2b723cae40?source=collection_archive---------27-----------------------

思想和理论

如何理解数据(或缺少数据)—当数据表现良好或表现不佳时

“我思故我在”

“我思故我在”

勒内·笛卡尔

思考或解决任何事情都需要某种框架,我们会有意识或无意识地遵循这种框架。他们有完整的分析领域,要么理解和构建一个人如何思考/决定(阅读:决策分析),要么理解其他人在某种情况下如何思考,比如说,零售购物(阅读:预测分析)。

在学术环境中,现在有了一个博士项目,我在这个过程中收集了一些经验教训——当内在化时,这些经验教训有助于一个人有效地思考或决定。我已经吸收了这么多,称它们为任何类型的框架都是过分的,但这些是简单的基本概念,我相信每个人,尤其是处理数据的人,应该偶尔阅读和反思。随着时间的推移,我意识到我对这些想得越多,它们就变得越自然,看起来就越正确。

毕加索的公牛

在某些时候,你可能会看到一个视频或图表,展示了毕加索创作的极简主义的公牛肖像。在这里,供参考。

毕加索,《公牛》,每日艺术杂志

外界对它有很多解释,但我个人最喜欢的是一个简单的解释。随后的每一幅画,公牛的一部分都被拿走了,但剩下的仍然是可以被认出的公牛,而且看起来很优雅。史蒂夫·乔布斯一直在思考寻找简单而优雅的方法来解决问题,引用毕加索自己的话

“……最抽象的东西也许是现实的顶峰”

每次我处理一个问题,几乎所有的问题都是数据驱动的,在我写完代码,推断出结果,写完手稿之后,我会花大量的时间去“毕加索”它。我删除了任何一行,任何一个推论,任何一个概念的提及,或者任何一个外行读者不需要知道的参考,我只保留了帮助读者从零到一(从 Theil 偷)的基本框架。这适用于文字、代码、数字、图表和几乎任何其他可以制作的东西。

这种“毕加索式”创作的想法不仅仅适用于提出解决方案或创作作品。它代表了一种思想流派,在这种思想流派中,以保留支点的方式处理问题,但否定任何无关紧要的东西是最重要的。无视干扰,专注于有用的东西是一门艺术。

费曼的技术

也许真的是英雄所见略同,因为理查德·费曼也相信简单明了。这种技术的抽象解释通常可以在互联网上找到,可以总结如下:

  • 学点东西。
  • 教一个孩子。
  • 如果孩子理解它,你对它的理解是坚定的。如果没有,重复。

当我用毕加索的技巧来思考一个问题,或者展示结果时,当我必须学习时,我会试着“费曼”它。可以毫不夸张地说,这种技术是毕加索学派的“学习”版本。

当涉及到学习任何新东西时,无论是像贝叶斯定理这样简单的东西,还是像理解神经网络或变压器如何工作这样复杂的东西,这种技术都是可以信赖的。

互联网上无数的文献都信誓旦旦地用这种方法来教和学,我会让他们来说服你。这篇中型文章是一篇很好的入门读物。

照片由公路旅行与 Raj 在 Unsplash 上拍摄

好的内脏

我经常了解到,当思考或解决问题时,所谓的“直觉”或直觉是一种很好的启发。当解决一个问题或做一项任务时,它通常会引导你找到一个很好的起点,它是一个很好的指标,表明一项任务是否在你目前的知识范围内,当它暗示有什么事情出错时,它会非常出色。它太好了,甚至连蜘蛛侠都相信它(阅读:蜘蛛侠感觉)。

我不知道,也不想去探究我们的“蜘蛛侠感觉”背后的科学,但我知道,对我和我周围几乎所有的人来说,这些经历是常见的:

  • “这道数学题似乎有很简单的解法。似乎很可疑”
  • “我已经通读了问题陈述,并且知道我将需要通宵来解决它”
  • “我觉得简单的线性回归可以很好地解决这个问题”

称之为经验,称之为智慧。如果这是你感觉到的第一件事,而不仅仅是理性的结论,那么你可以知道你的直觉已经给出了它的结论。所以很多时候,我不相信最初的感觉,与它斗争,花了无数个小时寻求其他解决方案,直到我后悔和退缩。也就是说,就像这个宇宙中的任何知识一样,仅凭直觉无法帮助你涉过重重险阻——你需要将直觉与合理的解释结合起来。

引用莫法特和加蒂丝的《夏洛克》,

“直觉是不可忽视的。它们代表的数据处理速度太快,意识无法理解”

黑天鹅悖论

"排除所有其他因素,剩下的必然是真相."

夏洛克也这样说过。但是通常,即使有堆积如山的数据或信息,有些事情还是没有意义。可能是数据不适合这个问题。这可能是因为我们不知道如何使用数据来解决问题——也许我们的建模是错误的。

在这种情况下,寻找黑天鹅通常是有帮助的。让我解释一下。

简而言之,如果你想了解天鹅(出于某种原因)并观察它们。如果你见过的所有天鹅都是白色的,那么当你写这种鸟或者报告你的结果时,这就不是一个令人惊讶的描述了。事实上,这将是一个决定性的特征。如果你看到一只黑色的鸟漂浮在水面上,你会毫不犹豫地认为它是一只天鹅。但是如果有一天,你观察到一只黑天鹅呢?你对天鹅的理解受到了影响。你开始思考你是否还了解他们。现在,如果这只黑天鹅的行为完全不同呢?如果他们发出嘘声而不是喇叭呢?夸张点说,如果是食人族消灭了其他天鹅呢?

这种情况被称为“黑天鹅”情况的一个例子,在这种情况下,一个突然的、意想不到的和罕见的事件使你的知识和理解,甚至可能是你正在处理的世界变得不正常。黑天鹅也很常见。毫不夸张地说,如果你观察到一群人在同一时间出现了一种似乎正在迅速传播的疾病的相同症状,你可以认为他们形成了疫情的开端。货币的非货币化是另一个例子——这是一个罕见的事件,你很少预料到/准备好它,但它却发生了——往往会带来严重的后果。

Marvin Rozendal 在 Unsplash 上的照片

但是你为什么需要知道这些呢?你其实不知道。能够预测黑天鹅并不常见,也不经常需要。但是知道像黑天鹅事件这样的事情可能存在,能够在它们发生时识别它们,并能够预先列举它们,可以帮助形成应急措施或在它们发生时更快地减轻它们。我相信,如果你正在管理一家餐厅,而这家餐厅现在因为疫情而不得不应对外卖订单,而不是内部订单,这将会有所帮助。

当数据没有意义,但你看到一个模式,寻找一只黑天鹅。

生活几乎无时无刻不包含积极的思考。无论是管理财务,还是建立神经网络来解决概率问题。没有一种真正的方式来思考和解决这些问题,有一些形式领域可以帮助你基于深刻的理性思考和数理逻辑做出有效的决定。但是,当你找房子的时候,或者当你弄清楚为什么你的杂货价格在一个街区上涨,而在另一个街区却没有上涨的时候,你真的会画出一棵决策树吗?你多久会尝试用一种可量化的方式来了解你是否以正确的方式解决了一项任务,或者你是否很好地展示了一条信息?

这些是我们每天快速做出的决定,很少受到框架和工具的干扰,通常只需要一点点理性的思考。正是这一点点,我试图用我“接受”的这些想法做出更好的决定。

aditya Narayan an是布法罗大学的博士生。他擅长将逻辑应用于概率图,有 计算机科学 背景。阅读新闻并加以评论是他的本能。

他有另一个自我,无聊时喜欢创作各种数字内容,但更喜欢纸和笔。他为多个大型体育实体创建了数字内容,如 LaLiga Santander、Roland-Garros 和 NBA 篮球学校。

这是他的 领英&邮箱

腹侧颞叶皮层时空功能磁共振成像的认知计算模型

原文:https://towardsdatascience.com/cognitive-computational-modelling-for-spatio-temporal-fmri-in-ventral-temporal-cortex-f353b5c20fdd?source=collection_archive---------25-----------------------

解码和理解人类大脑

玻璃大脑可视化(图片由作者提供)

材料

在这一系列文章中,我们将回顾以下文章

  • 人脑认知计算模型导论(上)
  • 发现神经影像分析(第二部分)
  • 人脑的功能连接和相似性分析(下)
  • 人脑分布区域的无监督表示学习(四)
  • 基于机器学习和深度学习的时空 fMRI 解码(五)

所有相关资料都放在我的 Github 页面上。别忘了去看看。如果你是一个纸质爱好者,你可以阅读这一系列文章的纸质版,也可以在我的回购中找到。

https://github.com/cankocagil/Cognitive-Computational-Modelling-for-Spatio-Temporal-fMRI-in-Ventral-Temporal-Cortex

在进入技术面之前,先了解

  • 计算神经科学
  • 无监督学习和机器学习的基础
  • 简单的神经网络(MLPs,CNN,…)

会很有帮助的。但是,不用担心。这些将是高水平的、实践的、代码优先的文章。那么,我们开始吧。

在本文中,我们将简要讨论人脑腹侧颞叶皮层的多体素模式分析(MVPA)。多体素模式分析和识别目前被用来研究包含在神经活动的分布式模式中的信息,以推断大脑区域和网络的功能作用。

从机器学习的角度来看,这是一个直接监督的分类问题。这里,输入通常是来自神经科学实验的 fMRI 数据。输出是感兴趣类别的概率分布。在我们的例子中,我们将尝试解码人类主体看到的视觉刺激类别(人脸、猫、椅子、鞋子……)。

MVPA 被认为是一个监督分类问题,其中分类器试图捕捉功能磁共振成像活动的空间模式和实验条件之间的关系。

在我们的例子中,fMRI 数据将是由空间和时间成分组成的 4D 时间序列数据。

目录

  1. 在第一部分,我们将在计算认知神经科学的背景下讨论人类腹侧颞叶皮层分布区域的视觉解码。然后,我们将理解为什么我们需要构造时空解码算法来执行认知任务。(第一部分)
  2. 在第二部分中,我们通过功能磁共振成像(fMRI)方法研究了人脑中物体视觉通路的功能结构,以解码人类受试者所看到的视觉刺激。我们进行了最先进的解释性回波平面,感兴趣区域(RoI),统计图,解剖和玻璃脑预分析,以从人脸和物体表征的研究中发现块设计的 4-D 时间序列 fMRI 数据集,即 Haxby 数据集。(第二部分)
  3. 在第三部分中,为了理解腹侧颞掩蔽的 fMRI 样本中的测地线关系,我们进行了基于相关性、精确度和偏相关的功能连接性分析,以及基于余弦、闵可夫斯基和欧几里得距离的相似性分析。(第三部分)
  4. 在第四部分中,流形学习和维数约减方法在每个受试者的腹侧时间掩模上执行,以提取时空掩模的潜在表示,这将有助于 fMRI 的进一步解码。(第四部分)
  5. 在第五部分中,开发了从感知器到 FREMs 的端到端机器学习算法,以根据腹侧颞叶皮层中的分布和重叠区域对刺激进行分类。通过利用不同视觉表示流之间的交互作用,我们进一步构建了认知神经网络,准确地说是 MLPs、2D 和 3D CNNs。(第五部分)

文章链接

  1. 发表文章

https://cankocagil.medium.com/introduction-to-cognitive-computational-modelling-of-human-brain-part-i-90c61e0e24c9

2.

https://cankocagil.medium.com/discovery-neuroimaging-analysis-part-ii-b2cdbdc6e6c3

3.

https://cankocagil.medium.com/functional-connectivity-and-similarity-analysis-of-human-brain-part-iii-c427c88ca5bb

4.

https://cankocagil.medium.com/unsupervised-representation-learning-on-distributed-regions-in-the-human-brain-part-iv-55fecf4e1b6f

2.在路上(即将到来…)

  1. 第五部分的占位符

进一步阅读

  • 【https://www.hindawi.com/journals/cmmm/2012/961257/

我在机器学习和神经科学方面的研究中使用了以下参考文献列表。我强烈建议复制粘贴参考资料,并简要回顾一下。

参考

[1]巴、基罗斯和辛顿。图层归一化,2016。

[2] L. Buitinck,G. Louppe,M. Blondel,F. Pedregosa,A. Mueller,O. Grisel,V. Niculae,P. Prettenhofer,A. Gramfort,J. Grobler,R. Layton,J. VanderPlas,a .乔利,B. Holt,10 和 G. Varoquaux。机器学习软件的 API 设计:scikit-learn 项目的经验。在 ECML PKDD 研讨会:数据挖掘和机器学习的语言,第 108–122 页,2013。

[3]褚,田,王,张,任,魏,夏,沈。双胞胎:重新审视《视觉变形金刚》中空间注意力的设计,2021。

[4] K .克拉默、o .德克、j .凯舍特、s .沙莱夫-施瓦兹和 y .辛格。在线被动攻击算法。2006.

[5] K. J .弗里斯顿。统计参数映射。1994.

[6]格罗斯、罗查-米兰达和本德。猕猴下颞皮质神经元的视觉特性。神经生理学杂志,35(1):96–111,1972。

[7] S. J .汉森、t .松坂和 J. V .哈克斯比。用于物体识别的腹侧颞叶组合编码。

[8]哈克斯比、戈比尼、富里、伊沙伊、斯豪滕和彼得里尼。《视觉物体识别》,2018。

[9]赫克曼、哈伊纳尔、贾巴尔、吕克特和哈默斯。结合标记传播和决策融合的自动解剖脑 mri 分割。神经影像,33(1):115–126,2006。

10d .亨德里克斯和 k .金佩尔。高斯误差线性单位(gelus),2020。

[11]黄少华,邵文伟,王明林,张德庆.人脑活动视觉信息的功能解码:简要综述。国际自动化和计算杂志,第 1-15 页,2021。

[12] R. Koster、M. J. Chadwick、Y. Chen、D. Berron、A. Banino、E. Duzel、D. Hassabis 和 D. Kumaran。海马系统内的大循环复发支持跨发作的信息整合。神经元,99(6):1342–1354,2018。

[13]马奥尔。勾股定理:4000 年的历史。普林斯顿大学出版社,2019。

[14] K. A. Norman、S. M. Polyn、G. J. Detre 和 J. V. Haxby 超越读心术:功能磁共振成像数据的多体素模式分析。认知科学趋势,10(9):424–430,2006。

[15]奥图尔、江、阿卜迪和哈克斯比。腹侧颞叶皮层中物体和面孔的部分分布表征。认知神经科学杂志,17(4):580–590,2005。

[16] F .佩德雷戈萨、g .瓦洛夸、a .格拉姆福特、v .米歇尔、b .蒂里翁、o .格里塞尔、m .布隆德尔、p .普雷登霍弗、r .魏斯、v .杜伯格、j .范德普拉斯、a .帕索斯、d .库尔纳波、m .布鲁彻、m .佩罗特和 e .杜切斯内。sci kit-learn:Python 中的机器学习。机器学习研究杂志,12:2825–2830,2011。

17 r . a .波尔德拉克。功能磁共振成像的感兴趣区域分析。社会认知和情感神经科学,2(1):67–70,2007。

[18] M. Poustchi-Amin、S. A. Mirowitz、J. J. Brown、R. C. McKinstry 和 T. Li。回波平面成像的原理和应用:普通放射科医师回顾。放射学,21(3):767–779,2001。

[19] R. P. Reddy,A. R. Mathulla 和 J. Rajeswaran。心理健康专家的观点采择和情绪传染的初步研究:移情的玻璃脑观点。印度心理医学杂志,0253717620973380,2021 页。

[20]史密斯、米勒、萨利米-科尔希迪、韦伯斯特、贝克曼、尼科尔斯、拉姆齐和伍尔利奇。功能磁共振成像的网络建模方法。神经影像,54(2):875–891,2011。

21 田中先生。下颞叶皮层和物体视觉。神经科学年度评论,19(1):109–139,1996。

[22] M. S .特雷德。Mvpa-light:一个多维数据的分类和回归工具箱。神经科学前沿,14:289,2020。

[23] M. P .范登赫维尔和 H. E .波尔。探索大脑网络:静息态功能磁共振成像功能连接综述。欧洲神经精神药理学,20(8):519–534,2010。

[24] G. Varoquaux,A. Gramfort,J. B. Poline 和 B. Thirion。大脑协方差选择:使用群体先验的更好的个体功能连接模型。arXiv 预印本 arXiv:1008.5071,2010。

[25] Y. Wang,J. Kang,P. B. Kemmer 和 Y. Guo。一种利用偏相关估计大规模脑网络功能连接的有效可靠的统计方法。神经科学前沿,10:123,2016。

26s . Wold、K. Esbensen 和 P. Geladi。主成分分析。化学计量学和智能实验室系统,2(1–3):37–52,1987。

27s . Wold、K. Esbensen 和 P. Geladi。主成分分析。化学计量学和智能实验室系统,2(1–3):37–52,1987。

认知风险管理

原文:https://towardsdatascience.com/cognitive-risk-management-7c7bcfe84219?source=collection_archive---------15-----------------------

行业笔记

自然语言处理技术的商业应用

亚历山大约翰·托马斯李嘉图马克西姆【阿拉德】 ,以及 阿坎克沙乔希**

作者图片

介绍

机器学习(ML)应用已经变得无处不在。每天都有关于自动驾驶汽车、在线客户支持、虚拟个人助理等人工智能的消息。然而,如何将现有的商业实践与所有这些惊人的创新联系起来,可能并不明显。一个经常被忽视的领域是自然语言处理(NLP)和深度学习的应用,以帮助快速有效地处理大量的业务文档,从而在大海捞针。

允许有机应用 ML 的领域之一是金融机构和保险公司的风险管理。关于如何应用 ML 来改进风险管理,组织面临许多问题。以下是其中的几个例子:

如何识别可以从使用人工智能中受益的有影响力的用例?

如何弥合主题专家的直觉期望和技术能力之间的差距?

如何将 ML 集成到现有的企业信息系统中?

如何在生产环境中控制 ML 模型的行为?

本文旨在分享 IBM 数据科学和人工智能精英(DSE)以及 IBM 专家实验室团队的经验,这些经验基于风险控制领域的多个客户项目。IBM DSE 已经构建了各种加速器,可以帮助组织快速采用 ML。在这里,我们将浏览风险管理领域的用例,介绍认知风险控制加速器,并讨论机器学习如何在这一领域转变企业业务实践。

风险管理草图

2020 年,多家金融机构遭受了单个机构超过数亿美元的罚款。罚款的原因是国家风险控制不足。

这引发了对金融公司的呼吁,要求它们确保必须处理的大量风险控制措施的高质量。这包括明确识别风险、实施风险控制以防止风险发展,以及最终建立测试程序。

对于非专业人士来说,风险控制有点令人费解。这是怎么回事?一个简单的定义是,风险控制是为了监控公司业务运营的风险。例如,安全风险可能是入侵者猜测密码,并因此获得对某人账户的访问权。一种可能的风险控制可能被设计为建立一种策略,该策略要求通过组织的系统强制执行长且重要的密码。作为萨班斯-奥克斯利法案(SOX)的结果,上市公司需要有效管理此类风险的方法,作为建立风险控制和评估这些控制质量的一部分。

对于风险经理来说,一个重要的因素是控制措施是否定义良好。对此的评估可以通过回答以下问题来完成:谁来监控风险,应该为风险识别或预防做些什么,在组织的生命周期中应该多久执行一次控制程序,等等。这些问题都要回答。现在我们需要认识到,在一个企业中,这种控制的数量从几千到几十万,并且很难手工对控制主体进行评估。这就是当代人工智能技术能够提供帮助的地方。

当然,这种类型的挑战只是一个例子,试图在一篇文章中涵盖风险管理的广阔领域是不切实际的,因此我们将重点关注从业者在日常实践中面临的一些具体挑战,这些挑战已经使用认知风险控制加速器实现了。

可用的公共风险控制数据库不多,因此加速器中的解决方案基于在https://nvd.nist.gov/800-53提供的针对安全控制的 NIST 特别出版物 800–53。这个安全控制数据库很小,但它允许我们展示可以扩展到大量和不同风险控制领域的方法。

使用文本分析和深度学习进行风险控制

一个关键的用例类别是使现有的风险控制合理化:挑战是现有的风险控制是如何发展的可能有许多历史方面。例如,一些风险控制可以通过复制其他现有控制进行最小的修改来构建。再比如有些风险控制可能是把多个风险控制整合成一个而形成的。这种方法的常见后果是重复的控制和不再与业务相关的控制的存在。最困难的挑战之一是评估现有风险控制的总体质量状态。因此,从商业的角度来看,第一个目标是建立质量评估:自动评估控制描述的质量,通过只关注那些真正重要的评审和改进,节省了大量阅读描述的时间。一个很好的问题是人工智能在这里是如何出现的。基于 NLP 的 ML 模型在常见的语言相关任务中变得非常有效,特别是在诸如回答问题的挑战中。这里可以引用的一种模型是基于 Transformer 架构的(有关更多详细信息,请参见位于https://medium . com/inside-machine-learning/what-is-a-Transformer-d 07 DD 1 fbec 04的一篇关于 Transformer 架构的文章)。

在风险管理草图中,回答有关风险控制描述的问题的能力是评估控制描述质量的关键。从鸟瞰图来看,未回答问题的数量是控制描述质量的一个很好的指标。最好的消息是,借助变形金刚等当代人工智能模型的能力和额外的实用规则,这种提出正确问题的技术成为一种有效的机制,可以在人工智能的协助下,由一个小团队控制大量的控制描述。

控制质量评估(图片由作者提供)

通常,在文档中寻找重复被认为是一项简单的任务,而 Levenshtein 距离可以帮助找到用相似措辞表达的条目。然而,如果我们想要找到语义相似的描述,这就变成了一个更具挑战性的任务。这是当代人工智能可以发挥作用的另一个领域——使用大型神经网络(例如,自动编码器、语言模型等)构建的嵌入。)可以捕捉语义相似度。从实际结果的角度来看,我们的经验是,发现重复和重叠可能导致控制量减少 30%。

重叠分析(作者图片)

此外,通过 ML 技术(如聚类)来分析信息的内部结构已经成为一种常见的做法。这使业务人员能够更好地了解更大范围内的控制内容,并查看现有的风险和控制分类是否与内容保持一致,或者两者中可能缺少什么。

聚类示例(作者图片)

以前的用例侧重于对现有控件的分析。另一个用例侧重于帮助风险经理创建新的风险控制。使用语义相似性为给定风险推荐控制措施可以显著减少人工工作量,并为构建控制措施提供灵活的模板。机器学习可以帮助分析风险描述,并找出正确的控制措施来解决每个风险。

在大型组织中,团队通常致力于其他团队可能使用的解决方案和最佳实践。在整个组织中采用最佳实践需要大量的培训。在这种情况下,机器学习非常有用。例如,可以将控制分类为预防性或检测性。在此使用案例中,我们使用受监督的机器学习,通过使用特定团队的现有标记集,将控制分类扩展到整个控制集,即使用机器学习完成知识转移,而不是耗时的人员培训。

IBM DSE 风险控制加速器中的认知技术允许我们构建风险控制,为用自然语言表达的风险推荐控制,识别控制中的重叠,并分析控制的质量。

accelerator 提供了一个认知控制分析应用程序,该应用程序集成了开发的模型并将其应用于非结构化风险控制内容。

使用 IBM Cloud Pak for Data 实现认知风险控制

从逻辑上讲,认知风险控制加速器包含几个组件:

  • 第一个是所谓的认知助手,它是一个应用 ML 模型来促进内容处理的应用程序,例如,通过识别风险控制优先级、类别和评估控制描述的质量。作为产品化的一部分,认知助手成为企业信息系统的一部分。

认知助手(图片由作者提供)

  • 第二个组成部分是内容分析:当数据通过机器学习模型丰富时,Watson Discovery 内容挖掘可用于在丰富的内容中寻找见解

使用 Watson Discovery 进行内容分析(图片由作者提供)

  • 还有一个组件是一套支持数据科学模型的 Jupyter 笔记本

沃森工作室的 Jupyter 笔记本(图片由作者提供)

让我们看看使用 IBM Cloud Pak 实现数据的基于加速器的实现。

在此之前,让我们简要回顾一下 IBM 平台和方法。IBM 对人工智能之旅有一个描述性的方法,叫做人工智能阶梯。在他的人工智能阶梯:揭开人工智能挑战的神秘面纱中,罗布·托马斯(SVP,IBM 云&认知软件)证实,要将数据转化为洞察力,您的组织应该遵循下列阶段:

收集—能够轻松访问数据,包括虚拟化数据

组织—对数据进行编目、构建数据字典以及确保访问数据的规则和策略的方法

分析——这包括交付 ML 模型,使用认知工具和人工智能技术使用数据科学来识别洞察力。这自然需要构建、部署和管理您的机器学习模型

注入——从许多角度来看,这是一个关键阶段。这是指以一种允许业务信任结果的方式操作人工智能模型的能力,即在生产模式下在企业系统中使用你的机器学习模型,同时能够确保这些模型的持续性能及其可解释性。

Cloud Pak for Data 是 IBM 的多云数据和人工智能平台,提供信息架构并提供所有概述的功能。下图捕捉了在 AI 阶梯环境中开发实现的细节。

阶段(图片由作者提供)

它记录了基于 DSE 加速器的认知风险控制项目的实施阶段:

  • 实施风险控制项目的前两个阶段是获取和编目数据集,例如,在加速器中,我们使用 NIST 控制数据集。这里的控件表示为自由文本描述。
  • 下一个阶段是在 Watson Studio 中丰富所获得的非结构化数据:聚类被用作理解内容内部结构的一种方式。风险控制叙述可能很长,可能会讨论多个主题,因此可能需要某种机制来跟踪描述过程中不断变化的主题。在我们的聚类实践中,我们使用了基于嵌入的 K-means 和潜在的 Dirichlet 分配(LDA)。它确实需要数据科学家和主题专家的仔细协调,因为数学可能不会与 SME 的期望理想地一致。更广泛的丰富在这里也是可能的——一个很好的例子是对描述的质量进行分类。

主题建模(图片由作者提供)

  • 当浓缩完成后,我们需要理解产生的数据集。这就把我们带到了探索阶段。实际上,挑战在于数量;内容审查是最耗时的过程之一,因为它需要仔细阅读大量文本。我们如何探索海量的非结构化信息?Watson Discovery 内容挖掘工具使这成为可能,并大大减少了工作量。
  • 在内容被 SME 审查之后,它形成了构建监督机器学习模型的基础。IBM 平台提供了部署模型、监控漂移和获得复杂模型所做决策的可解释性的方法。所有这些都包含在机器学习的可操作化中,并由 IBM Cloud Pak For Data 提供支持。

结论

本文介绍了机器学习在当代商业中日益增长的应用领域之一——认知风险控制。访问我们的加速器目录,了解更多关于认知控制加速器的信息。如果您有兴趣了解更多关于认知风险控制和人工智能技术的信息,请随时联系 IBM 数据科学和人工智能精英团队。此外,如果您发现您的用例与所展示的相似,或者如果您的业务和技术挑战可以通过提到的方法或工具解决,请联系 IBM。

承认

作者(IBM DSE 和专家实验室)对他们的同事持续协作和开发认知控制的业务和技术方法表示感谢:斯蒂芬·米尔斯(IBM Promontory 董事总经理)、迈尔斯·拉维兹(IBM Promontory 高级负责人)、罗德尼·赖德奥特(IBM 全球业务服务部交付主管)、维奈·拉奥·檀丁(数据科学家)、艾西瓦娅·斯里尼瓦桑(IBM DSE 数据科学家)和拉克什思·达塞纳哈里·林加茹(IBM DSE 数据科学家)。

Cogram.ai:数据科学和机器学习的编码助手

原文:https://towardsdatascience.com/cogram-ai-a-coding-assistant-for-data-science-and-machine-learning-f236379b829e?source=collection_archive---------18-----------------------

马库斯·温克勒在 Unsplash 上的照片

在 jupyter 笔记本上运行的用于数据科学和机器学习的 Codex 支持的自动完成功能

自从 GPT-3 的发布和传播以来,像 Github copilot 这样的编码助手,由 OpenAi 的 codex API 提供支持,已经在机器学习社区的雷达上出现了很长一段时间。最近,我偶然发现了这个叫做 Cogram 的工具,它似乎是自动完成的一种进化,专门用于数据科学和机器学习,直接在 Jupyter 笔记本上运行。

在本文中,我将向您展示这个工具是如何工作的,并分享我迄今为止使用它的一点点经验,在 Jupyter 笔记本上生成机器学习代码。

Cogram 入门

首先,要设置 Cogram,你必须去他们的网站,在那里你注册一个免费账户并获得一个 API 令牌。之后,你所要做的就是安装 Cogram,包括:

pip install -U jupyter-cogram

将其作为 jupyter 笔记本扩展:

jupyter nbextension enable jupyter-cogram/main

最后,用以下代码设置您的 API 令牌:

python -m jupyter_cogram --token YOUR_API_TOKEN

现在你已经设置好了,你可以开始在你的 jupyter 笔记本上直接完成。

对于最新的可用版本,默认情况下启用 Cogram。用户可以通过该图标在菜单中打开和关闭共格图,

作者图片

还可以定制 Cogram,选择 Cogram 显示多少建议,以及 Cogram 有多有创意。

有两种方法可以使用 Cogram:你可以使用自动建议模式,每当你停止输入时,Cogram 都会提出建议,

来自 Cogram 的自动建议示例;图片由 cogram.ai 提供(获得许可)

或者当你去一个新的行。您也可以使用手动完成选项,由 Tab 键触发。

通过 Tab 键触发的 cogram.ai(获得许可)手动完成选项

用 Tab 键触发的手动完成选项;图片由 cogram.ai 提供(获得许可)

用户可以通过 Cogram 菜单中的自动建议复选框在这些选项之间切换。

Jupyter 笔记本上的自动完成功能

我用 Cogram 生成了一组补全来测试它的可用性,下面是我最喜欢的一些:

写这个的时候:

# plot sin(x) from 0 to pi

它生成了这个:

# plot sin(x) from 0 to pi

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, np.pi, 100)
y = np.sin(x)

plt.plot(x, y)
plt.show()

作者图片

令我高兴的是,我尝试的第一个例子实际上生成了无需任何编辑或调试就能运行的代码!现在,另一个简单的例子,来自这个:

# plot a histogram of points from a poisson distribution

它生成了这个:

# plot a histogram of points from a poisson distribution

import numpy as np
import matplotlib.pyplot as plt

x = np.random.poisson(5, 1000)

plt.hist(x)
plt.show()

作者图片

再次,它运行没有问题!到目前为止非常酷。让我们更进一步,创建一个假数据集来拟合一个简单的线性回归模型:

# create a fake dataset and run a simple linear regression model

输出:

# create a fake dataset and run a simple linear regression model

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100)
y = 2 * x + np.random.randn(100)

plt.scatter(x, y)
plt.show()

作者图片

好了,差不多了。代码实际上运行了,并且在我试图实现的上下文中是有意义的,但是模型没有为实际的线性回归生成代码。让我们看看是否可以通过在我们的初始评论中添加更多的描述来改变这一点:

# write a linear regression model with sklearn

输出:

# write a linear regression model with sklearn

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

x = np.random.randn(100)
y = 2 * x + np.random.randn(100)

model = LinearRegression()
model.fit(x.reshape(-1, 1), y.reshape(-1, 1))

plt.scatter(x, y)
plt.plot(x, model.predict(x.reshape(-1, 1)))
plt.show()

作者图片

酷毙了。它实际上创造了一切,包括进口!从数据帧中绘图怎么样?

我写道:

# load a csv file and plot the numerical data using the date column as the x axis

输出:

# load data.csv and plot the "data" column with the "date" column as index
import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv("data.csv", index_col="date", parse_dates=True)
data.plot()
plt.show()

作者图片

它没有专门绘制“数据”列,但是它将“日期”列设置为索引,这真的很酷。

现在,让我们尝试一个稍微高级一点的例子,让我们使用 NumPy 包从头开始编写一个简单的感知器:

# write a perceptron from scratch in numpy

输出:

# write a perceptron from scratch in numpy

import numpy as np

class Perceptron(object):
    """Perceptron classifier.

    Parameters
    ------------
    eta : float
        Learning rate (between 0.0 and 1.0)
    n_iter : int
        Passes over the training dataset.

    Attributes
    -----------
    w_ : 1d-array
        Weights after fitting.
    errors_ : list
        Number of misclassifications in every epoch.

    """
    def __init__(self, eta=0.01, n_iter=10):
        self.eta = eta
        self.n_iter = n_iter

    def fit(self, X, y):
        """Fit training data.

        Parameters
        ----------
        X : {array-like}, shape = [n_samples, n_features]
            Training vectors, where n_samples is the number of samples and
            n_features is the number of features.
        y : array-like, shape = [n_samples]
            Target values.

        Returns
        -------
        self : object
         """
        self.w_ = np.zeros(1 + X.shape[1])
        self.errors_ = []
        for _ in range(self.n_iter):
            errors = 0
            for xi, target in zip(X, y):
                update = self.eta * (target - self.predict(xi))
                self.w_[1:] += update * xi
                self.w_[0] += update
                errors += int(update != 0.0)
                self.errors_.append(errors)
                return self

    def predict(self, X):
        """Return class label after unit step"""
        return np.where(X >= 0.0, 1, -1)    

X = np.array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
y = np.array([0, 1, 1, 0])
model = Perceptron(eta=0.1, n_iter=10)
model.fit(X,y)---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

TypeError: only size-1 arrays can be converted to Python scalars

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)

<ipython-input-31-38e27395dd1c> in <module>
     60 y = np.array([0, 1, 1, 0])
     61 model = Perceptron(eta=0.1, n_iter=10)
---> 62 model.fit(X,y)

<ipython-input-31-38e27395dd1c> in fit(self, X, y)
     48                 update = self.eta * (target - self.predict(xi))
     49                 self.w_[1:] += update * xi
---> 50                 self.w_[0] += update
     51                 errors += int(update != 0.0)
     52                 self.errors_.append(errors)

ValueError: setting an array element with a sequence.

现在,这里有很多要解开的,虽然代码有一些错误,并不是开箱即用的,但它确实编写了非常引人注目的代码,经过一些编辑后就可以运行了。

我注意到的最酷的事情之一是,该模型还为函数编写注释,考虑到编写文档所呈现的上下文复杂性,这很有趣。除此之外, Cogram 也是上下文感知的(就像 VSCode 中的 Github copilot),所以如果你写了一个函数、变量或者类,它就能记住它。

关于数据科学和机器学习编码助手的总结性思考

我想指出的一点是,自从围绕软件 2.0 的讨论开始以来(可能甚至在那之前),加上像 GPT-3 这样极其强大的语言模型的发展,现在已经演变成了法典引擎,这种编写软件的风格变得越来越普遍,并且有一个很好的理由,我们最终关心的是为问题编写解决方案,而不是自己编写每一行代码来解决问题 x

这并不意味着我们应该相信语言模型并疯狂地使用自动完成功能,但对我来说很明显,在跨平台、跨编程语言的代码编写环境中,可能会出现一种智能的、经过深思熟虑的人机共生关系,并且思考如何将它集成到自己的工作流中可能是有意义的。

如果你喜欢这篇文章,加入媒体,关注,订阅我的简讯。还有,在 Twitter 、 LinkedIn 和 Instagram 上和我联系!谢谢,下次再见!:)

声明:这篇文章没有得到赞助,我也没有因为写这篇文章得到任何报酬

R 队列分析可视化

原文:https://towardsdatascience.com/cohort-analysis-visualization-with-r-d57830bf1cd0?source=collection_archive---------8-----------------------

Adrien Delforge 在 Unsplash 上拍摄的照片

让 ggplot2 以优雅的方式可视化您的群组分析

如果你是 B2C(企业对消费者)行业的数据从业者,或者只是一个分析过一些消费者数据的数据极客,那么你很有可能必须熟悉群组分析。

群组分析是一种分析方法,其中我们首先将属于数据集的个体分组到具有特定时间跨度的不同群组中,在该时间跨度内,同一群组中的个体共享相同的特定经历。然后进行适当的分析,将这些组群作为分析单位。

在其他使用案例中,群组分析允许我们在执行特定指标时,观察用户保留率随时间的变化。这是通过比较不同年龄组的表现来实现的。

在本文中,我将分享如何创建群组分析可视化。为此,我们将使用 R 及其流行的 ggplot2 包。将显示两种群组分析可视化:线图热图

数据

使用的数据是在这个 Github 存储库中可用的relay-food数据。该数据包含某个食品零售商的订单详细信息。在整篇文章中,我们只对每月一次的用户购买群体的可视化感兴趣。因此,我们将只考虑如下两列数据:

  1. OrderDate:订单发生的日期
  2. UserId:用户 ID

形象化

线形图

和往常一样,首先要做的是导入必要的库。

# import libraries
library(dplyr) #handy data manipulation
library(ggplot2) #our today's super star
library(stringr) #to manipulate string date
library(ggthemes) #many nice themes
library(mdthemes) #handy text in plot formatting
library(gghighlight) #will abuse it a bit to show nice label

接下来加载数据。

#load the data
df = read.csv("relay-foods.csv")#inspect first 5 rows of the data
df %>% select(OrderDate, UserId) %>% head(5)

显然,OrderDate栏的日期格式还不标准。因此我们需要调整它。

# adjust date formatting of OrderDate column
df$OrderDate = format(as.Date(df$OrderDate, '%m/%d/%Y'), '%Y/%m/%d')
df$OrderDate = gsub('00','20',df$OrderDate)

接下来,由于我们想要查看月度群组,我们需要从OrderDate列派生出OrderMonth列。

# create OrderMonth column from OrderDate (to  make monthly cohort)
df$OrderMonth = str_sub(df$OrderDate,end = 7)

群组分析需要数据集中每个用户的群组信息,因此我们建立一个群组。

# create reference data frame of cohort group (month level)
cohort_group_df = df %>% group_by(UserId) %>% 
                    summarize(CohortGroup = min(OrderDate))cohort_group_df$CohortGroup =  str_sub(cohort_group_df$CohortGroup,                    end = 7) # join with the initial df
df = inner_join(df, cohort_group_df, by = 'UserId')

接下来,我们创建一个参考数据框架,其中包含每个群组的总用户数,以及每月购买的用户数。

# create reference data frame of total users for each cohort group
base_cohort_df = df %>% group_by(CohortGroup) %>%
  summarise(
   TotalUsers = n_distinct(UserId)
  )# create purchase activity data frame
activity_cohort_df = df %>% group_by(CohortGroup, OrderMonth) %>%
 summarise(
  BuyingUsers = n_distinct(UserId)
 )# join activity_cohort_df and base_cohort_df
user_cohort_df = inner_join(activity_cohort_df, base_cohort_df, 
                  by = 'CohortGroup')

数据检查点。到目前为止我们得到了什么?

user_cohort_df %>% head(5)

注意OrderMonth列仍然是上面的字符串格式。对于绘图,我们希望它是整数格式,成为 x 轴。

# transform OrderMonth to integer
user_cohort_df = user_cohort_df %>% group_by(CohortGroup) %>% mutate(MonthNumber = 1:n())

最后,我们将只绘制数据的子集,以避免过度绘制。

# subsetting the data
plot_user_cohort_df = inner_join(base_cohort_df[seq(1,11,2),c(“CohortGroup”)], user_cohort_df, by = “CohortGroup”)

在要画的情节中,我想在线条的末端有漂亮的图例。为此,我使用 gghighlight 包。我知道这有点不太好,所以如果你们知道更合适的方法,请在下面评论。

# dummy column for in-place legend
plot_user_cohort_df$dummy_col = 1

好了,我们完成了线图的数据准备工作。下面是数据的最终形式。

plot_user_cohort_df %>% head(5)

所以,我们准备有我们的第一个情节!

# plotting line plot
ggplot(plot_user_cohort_df) +
  geom_line(aes(x = MonthNumber,
                y = BuyingUsers/TotalUsers,
                col = CohortGroup)) +
  gghighlight(dummy_col == 1) +
  scale_x_continuous(breaks = seq(from = 1, to = 15, by = 2)) +
  scale_y_continuous(labels = scales::percent_format()) +
  mdthemes::md_theme_solarized() +
  labs(
    title = "**Monthly User Purchasing Cohort**",
    caption = "*Data: Relay Food order details (Source: github.com/ethen8181)*", 
    x = "K-th Month",
    y = "Retention",
    col = "Cohort Group"
  )

图 1 —线形图中的队列分析

从图中可以得出结论,接力食品往往会遇到用户保留率降低的问题,因为年轻群体的保留率(2009-11 年)低于年长群体的保留率(2009-01 年)。

热图

根据我的经验,有些人更喜欢看到热图这类的图表来可视化这些群体。所以我们也画一个吧。

我们将继续上述工作,而不是从头开始。特别是我们将从user_cohort_df开始。

# create base dataframe for heat map visualization
cohort_heatmap_df = user_cohort_df %>% select(CohortGroup,      MonthNumber, BuyingUsers) %>%
          spread(MonthNumber, BuyingUsers)# inspect data
cohort_heatmap_df %>% head(5)

我们还创建了数据的百分比版本。

# the percentage version of the dataframe
cohort_heatmap_df_pct = data.frame(
  cohort_heatmap_df$CohortGroup,
  cohort_heatmap_df[,2:ncol(cohort_heatmap_df)] / cohort_heatmap_df[["1"]]
)# assign the same column names
colnames(cohort_heatmap_df_pct) = colnames(cohort_heatmap_df)

接下来,我们融合两个数据帧以取悦 ggplot2。

# melt the dataframes for plotting
plot_data_abs = gather(cohort_heatmap_df, "MonthNumber", "BuyingUsers", 2:ncol(cohort_heatmap_df))
plot_data_pct = gather(cohort_heatmap_df_pct, "MonthNumber", "Retention", 2:ncol(cohort_heatmap_df_pct))

我们为热图准备标签。

# prepare label names containing absolute number of buyers for the first month and retention percentages for the rest months
label_names = c(plot_data_abs$BuyingUsers[1:(ncol(cohort_heatmap_df)-1)],plot_data_pct$Retention[(ncol(cohort_heatmap_df_pct)):(nrow(plot_data_pct))])

最后,我们把所有的东西放在一个数据框架中,准备绘图。

# beautify percentage labels
beauty_print <- function(n) {
  case_when( n <= 1  ~ sprintf("%1.0f %%", n*100),
             n >  1  ~ as.character(n),
             TRUE    ~ " ") # for NA values, skip the label
}# create dataframe ready for plotting
plot_data = data.frame(
  CohortGroup = plot_data_pct$CohortGroup,
  MonthNumber = plot_data_pct$MonthNumber,
  Retention = plot_data_pct$Retention,
  Label = beauty_print(label_names)
)
plot_data$MonthNumber = as.numeric(plot_data$MonthNumber)

热图可视化数据框架的最终形式如下。

plot_data %>% head(5)

击鼓!生成热图的代码如下。

# plotting heatmap
ggplot(plot_data) +
  geom_raster(aes(x = MonthNumber,
                  y = reorder(CohortGroup, desc(CohortGroup)),
                  fill = Retention)) +
  scale_fill_continuous(guide = FALSE, type = "gradient",
                        low = "deepskyblue", high = "darkblue") +
  scale_x_continuous(breaks = seq(from = 1, to = 15, by = 1),
                     expand = c(0,0)) +
  geom_text(aes(x = MonthNumber,
                y = reorder(CohortGroup, desc(CohortGroup)),
                label = Label), col = "white") +
  mdthemes::md_theme_gray() +
  labs(
    title = "**Monthly User Purchasing Cohort**",
    caption = "*Data: Relay Food order details (Source: github.com/ethen8181)*", 
    x = "K-th Month",
    y = "Cohort Group"
  )

图 2—热图中的群组分析

请注意,热图的第一列显示了在相应月份进行购买的用户的绝对数量。因此,这种队列可视化的热图版本比其折线图版本更加丰富,因为它提供了关于队列组绝对大小的更多背景信息。

在你走之前

在本文中,我们通过一步一步的 R 代码教程,以线图和热图的形式生成队列分析的优雅可视化。对于更喜欢跟踪 Github 代码的读者来说,本文的完整代码可以在我的 Github 库这里找到。

最后,感谢阅读,大家在 LinkedIn 上和我连线吧!👋

使用 Python 进行队列分析

原文:https://towardsdatascience.com/cohort-analysis-with-python-2bdf05e36f57?source=collection_archive---------15-----------------------

每个电子商务数据分析师都必须掌握的数据聚类技能

介绍

如果你是一名为电子商务公司工作的数据分析师,你的工作任务之一很可能是从客户数据中发现洞察力,以提高客户保留率。

然而,客户数据是海量的,每个客户的行为都不同。2020 年 3 月获得的客户 A 表现出与 2020 年 5 月获得的客户 B 不同的行为。因此,有必要将客户分成不同的群,然后调查每个群随时间推移的行为。这叫做队列分析

群组分析是一种数据分析技术,用于了解特定客户群体在一段时间内的行为。

在这篇文章中,我不会详细介绍群组分析的理论。如果你不知道群组分析是怎么回事,我强烈建议你先看看这篇博客。

这篇文章更多的是向您展示如何将客户分成不同的群组,并观察每个群组在一段时间内的保留率。

让我们开始吧!

导入数据和 python 库

你可以在这里下载数据。

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsdf = pd.read_csv('sales_2018-01-01_2019-12-31.csv')
df

VS 代码 2

将首次顾客与回头客分开

first_time = df.loc[df['customer_type'] == 'First-time',]final = df.loc[df['customer_id'].isin(first_time['customer_id'].values)]

简单地选择df.loc[df['customer_type']]是不明智的。我来解释一下原因。在该数据中,customer_type栏下的First_time是指新客户,而Returning是指回头客。因此,如果我在 2019 年 12 月 31 日首次购买,数据将显示我在 2019 年 12 月 31 日是新客户,但在我的第二、第三……时间是回头客。群组分析着眼于新客户及其后续购买行为。因此,如果我们简单地使用df.loc[df['customer_type']=='First-time',],我们将忽略新客户的后续购买,这不是分析群体行为的正确方法。

因此,我在这里所做的是,首先创建一个所有首次客户的列表,并将其存储为first_time。然后从原始客户数据框架df中只选择那些 id 属于first_time客户组的客户。通过这样做,我们可以确保我们获得的数据只包含首次购买的客户以及他们随后的购买行为。

现在,让我们删除customer_type列,因为它已经没有必要了。另外,将day列转换成正确的日期时间格式

final = final.drop(columns = ['customer_type'])
final['day']= pd.to_datetime(final['day'], dayfirst=True)

先按客户 ID,再按日期对数据进行排序

final = final.sort_values(['customer_id','day'])final.reset_index(inplace = True, drop = True)

定义一些函数

def purchase_rate(customer_id):
    purchase_rate = [1]
    counter = 1
    for i in range(1,len(customer_id)):
          if customer_id[i] != customer_id[i-1]:
                 purchase_rate.append(1)
                 counter = 1
          else:
                 counter += 1
                 purchase_rate.append(counter) return purchase_ratedef join_date(date, purchase_rate): join_date = list(range(len(date))) for i in range(len(purchase_rate)): 
          if purchase_rate[i] == 1:
                 join_date[i] = date[i]
          else:
                 join_date[i] = join_date[i-1] return join_date def age_by_month(purchase_rate, month, year, join_month, join_year): age_by_month = list(range(len(year))) for i in range(len(purchase_rate)): if purchase_rate[i] == 1: age_by_month[i] = 0 else: if year[i] == join_year[i]: age_by_month[i] = month[i] - join_month[i] else: age_by_month[i] = month[i] - join_month[i] + 12*(year[i]-join_year[i]) return age_by_month

purchase_rate功能将确定每位顾客的第二次、第三次、第四次购买。

join_date功能允许我们识别客户加入的日期。

age_by_month函数给出了客户从当前购买到第一次购买有多少个月。

现在输入已经准备好了。让我们创建群组。

创建群组

final['month'] =pd.to_datetime(final['day']).dt.monthfinal['Purchase Rate'] = purchase_rate(final['customer_id'])final['Join Date'] = join_date(final['day'], final['Purchase Rate'])final['Join Date'] = pd.to_datetime(final['Join Date'], dayfirst=True)final['cohort'] = pd.to_datetime(final['Join Date']).dt.strftime('%Y-%m')final['year'] = pd.to_datetime(final['day']).dt.yearfinal['Join Date Month'] = pd.to_datetime(final['Join Date']).dt.monthfinal['Join Date Year'] = pd.to_datetime(final['Join Date']).dt.year

final['Age by month'] = age_by_month(final['Purchase Rate'], final['month'],final['year'],final['Join Date Month'],final['Join Date Year'])

cohorts = final.groupby(['cohort','Age by month']).nunique()
cohorts = cohorts.customer_id.to_frame().reset_index()   # convert series to framecohorts = pd.pivot_table(cohorts, values = 'customer_id',index = 'cohort', columns= 'Age by month')
cohorts.replace(np.nan, '',regex=True)

如何解读此表 以 cohort 2018–01 为例。2018 年 1 月,新增客户 462 家。在这 462 名顾客中,有 121 名顾客在 2018 年 2 月回来购买,125 名在 2018 年 3 月购买,以此类推。

转换成群组百分比

for i in range(len(cohorts)-1):
    cohorts[i+1] = cohorts[i+1]/cohorts[0]cohorts[0] = cohorts[0]/cohorts[0]

(英)可视化(= visualization)

cohorts_t = cohorts.transpose()cohorts_t[cohorts_t.columns].plot(figsize=(10,5))sns.set(style='whitegrid')plt.figure(figsize=(20, 15))plt.title('Cohorts: User Retention')sns.set(font_scale = 0.5) # font sizesns.heatmap(cohorts, mask=cohorts.isnull(),cmap="Blues",annot=True, fmt='.01%')plt.show()

就是这样。希望你们喜欢这篇文章,并从中有所收获。如果你有任何问题,请在下面的评论区写下来。谢谢你的阅读。祝你今天愉快,新年快乐🎉🎉🎉

Colab Pro 与 Free-AI 计算性能

原文:https://towardsdatascience.com/colab-pro-vs-free-ai-computing-performance-4e983d578fb2?source=collection_archive---------7-----------------------

GPU 加速值不值得每月 10 美元的费用?

动机 : 当我考虑是否要为 Colab Pro 支付 10 美元的升级费用时,我主要关心的是“GPU 加速是否值得每月付费?”可悲的是,我无法找到一个好的来源来回答这个问题,所以我写了这个故事来帮助像我这样的人。😉

我应该升级到 Colab Pro 吗?如果你用谷歌搜索这个问题,你会发现很多很棒的文章。例如:

  1. GPU、RAM、高级训练时间对比 byDario rade CII:https://towardsdatascience . com/colab-pro-is-it-worth-the-money-32a 1744 f 42 A8
  2. Colab Pro 主要功能:https://colab.research.google.com/signup
  3. Reddit 讨论:https://www . Reddit . com/r/machine learning/comments/f0wm0l/n _ colab _ pro _ more _ ram _ longer _ run _ time _ faster _ GPU/

为了给正在进行的讨论带来一些新的东西,我将利用这篇文章在 Google Colab 的背景下更深入地探究他们在人工智能计算性能方面的差异。

背景

要比较不同 Colab 层的 AI 计算性能,只看硬件规格是不够的。最好的方法可能是在专业版和免费版上运行实际的、固定的 AI 模型,并查看它们完成固定训练工作的运行时间。

比较工具

为了进行比较,我们使用 AI 基准,这是来自 Github 的开源工具。这个工具是由苏黎世联邦理工学院的一组研究人员开发的,它通过运行下面的代码来工作。当我们执行代码时,工具会收集 19 个不同机器学习模型在特定数据集上的训练和推理时间。

得分

除了时间,该基准还根据预定义的分数来评估训练、推理和整体人工智能性能。尽管该工具没有明确解释得分公式,但我查看了它的源代码,并总结了下面的公式。

计算训练分数。作者图片

虽然它是训练分数的公式,但推理分数的计算方法类似,然后将它们的总和用作总的 AI 分数。我假设您可能希望在以下内容中更多地关注培训性能方面,因为 Colab 更多地用作研究工具,而不是部署。

比较

基准测试在以下时间进行:

  1. 仅带 CPU 的 Colab 免费(实验链接)
  2. Colab 免费与 T4 ( 实验链接
  3. 仅带 CPU 的 colab pro(实验链接)
  4. Colab pro 与 P100 ( 实验环节)
  5. Colab pro 带 V100 ( 实验环节)

Colab 在免费版本中支持 K80,但有一段时间没有看到它,所以不包括在内。至于 P100 和 V100,是由 Colab Pro 随机给出的。通常,P100 会有更大的机会。

作者图片

注: 为便于观察,图表中并未包含所有信息。这些模型由不同的数据集训练,因此跨模型比较运行时间不会有很大帮助。

训练分数排名

  1. 带 V100 的 colab pro—16289 分
  2. P100 的 colab pro—11428 分
  3. 与 T4 的免费可乐— 7155 分
  4. 仅带 CPU 的 Colab 免费 —187 分
  5. 仅带 CPU 的 colab pro**—175 分**

观察

我创建了这个谷歌表单来包含更多的细节。从那里,您可以观察到以下情况:

  • 平均而言,配备 V100 和 P100 的 Colab Pro 分别比配备 T4 的 Colab Free 快 146%和 63%。(资料来源:“比较”表,表 E6-G8)
  • 即使来自 Colab Pro 的 GPU 通常更快,但仍然存在一些异常值;例如,Pixel-RNN 和 LSTM 在 V100 上的训练速度比 T4 慢 9%-24%。(资料来源:“比较”表,表 C18-C19)
  • 当只使用 CPU 时,Pro 和 Free 的性能相似。(来源:“培训”表,B 栏和 D 栏)

结论

如果你把训练时间长当成研究时的痛点,我强烈推荐你升级到 Colab Pro。例如,我发现自己每个月花在 Colab 上的时间超过 20 个小时,将近 50%的时间花在模型训练上。所以,Colab Pro 每个月给我节省了 20*0.5=10 多个小时。然而,如果我不是一个 Colab 的重度用户,或者有一个不同的地方来加速模型训练,用这 10 美元给自己买一个夏威夷广场似乎是一个更好的主意。

**同样,本文只关注 AI 计算性能。**在做出决定之前,您应该明确考虑其他方面,如 RAM、运行时等等。

免费的 4 个 V100 GPUs

如果你在寻找更多免费的 GPU 资源,我想介绍一下 AIbro ,一个无服务器的模型训练工具,我和我的朋友们目前正在开发。它可以帮助你用一行代码在 AWS 上训练 AI 模型。为了收集更多早期用户的反馈,我们现在为您提供免费的p 3.8x large(4x V100)版本。更多细节,你可能想看看我以前的故事:

**

AIpaca Inc .图片作者**

ColabCode:从 Google Colab 部署机器学习模型

原文:https://towardsdatascience.com/colabcode-deploying-machine-learning-models-from-google-colab-54e0d37a7b09?source=collection_archive---------4-----------------------

启动 VS 代码服务器、Jupyter 实验室或 FastAPI

照片由 Niclas Illg 在 Unsplash 上拍摄

Google colab 是 Python 和数据科学爱好者最方便的在线 IDE。它于 2017 年向公众发布,最初是谷歌研究团队用于合作不同人工智能项目的内部项目。从那以后,由于其易于使用的界面,Jupyter 笔记本的相似性,以及 GPU 的支持,它获得了很大的人气。

大多数流行的机器学习库,如 numpy,pandas,seaborn,matplotlib,sklearn,TensorFlow,都预装在这个云环境中,因此您不需要任何显式的先决条件。您也可以安装您选择的任何 python 包来运行您的代码。在本文中,我将向您解释一种使用 FastAPI 和 ngrok 将您的机器学习模型部署为 API 的简单方法。

什么是 FastAPI?

它是一个用 Python 构建 API 的高性能 web 框架。传统上,大多数开发人员使用 flask 作为构建 API 的首选,但由于一些限制,但不限于数据验证、身份验证、异步等,FastAPI 获得了很大的流行。FastAPI 通过 pydantic 模型提供自动文档生成功能、身份验证和数据验证。要详细了解这两个框架之间的显著差异,您可以在这里查看我关于分析 Vidya 的文章:

https://www.analyticsvidhya.com/blog/2020/11/fastapi-the-right-replacement-for-flask/

FastAPI 有助于设置生产就绪的服务器,但是如果您想在将它部署到实际的云平台(如 Heroku)之前与您的团队共享,该怎么办呢?ngrok 通过隧道将您的本地主机暴露给互联网来解救您。现在,任何人都可以通过提供的链接访问您的 API 端点,但是如果所有这些都只能在 Google Colab 上完成呢?解决这个问题的方法是 ColabCode!

什么是 ColabCode?

它是一个 Python 包,允许您直接从您的 Colab 笔记本上启动代码服务器,而无需在您的系统上进行任何本地设置。它可以用来启动 VS 代码环境、Jupyter 实验室服务器,或者将 FastAPI 服务器隧道连接到 web,所有这些都在 colab 笔记本中。这对于那些在云上训练他们的模型,并且现在想要以 API 的形式与世界分享他们的发现的爱好者来说是一个很好的加分点。我们将讨论 ColabCode 的所有功能,直到本文结束。

为 ColabCode 准备 FastAPI 代码

我将在本文中使用的问题陈述是一个决策树分类器,用于在两种音乐流派之间进行分类:Hip-Hop 或 Rock。我已经清理了数据集,它在我的 GitHub 库上。现在我已经有了数据集,我简单地把它导入笔记本并训练了一个决策树模型,没有任何预处理或 ed a 的东西,因为本文更多的是关于部署。所以这个模型可能会返回一些错误的结果!

模型创建代码

  1. 现在,如果您知道 FastAPI 架构,我们将需要一个数据类作为输入。这个数据类允许 FastAPI 验证要发送给模型的输入,如果给出了任何错误的输入,它只是引发错误,而不会将错误提供给模型。
  2. 创建数据类非常简单,只需要接受参数和数据类型。为了进一步定制,您还可以添加一个定制示例来快速测试结果。这个类的代码是:

数据类别代码

3.现在,我们需要创建一个服务所有请求的端点。FastAPI 中的端点创建与 flask 非常相似,只需要端点函数接受数据类进行验证。

FastAPI 代码

如果你想探索一些很酷的项目,请查看我的 GitHub 档案:

https://github.com/kaustubhgupta

可乐码

我们的 FastAPI 已经准备好了,现在唯一需要的就是通过 colab 环境运行它。首先,导入这个包并初始化服务器:

from colabcode import ColabCodeserver = ColabCode(port=10000, code=False)

端口号可以由您选择,代码参数应该为 false。现在,服务器已经准备好接收 FastAPI 对象,在 ngrok 的帮助下,本地主机通过一个唯一的 URL 被隧道化并暴露给公众。

server.run_app(app=app)

就这样!你将得到一个 ngrok URL,你可以与你的社区、团队或任何人分享。一旦你终止了单元格进程,链接就会失效,如果你不这样做,Google Colab 会在一段时间后终止它。此过程的 GIF 示例如下所示:

作者 GIF

在这里,单击链接后,我导航到 FastAPI 自动生成的端点/文档,在这里,我们可以测试结果。如果你想运行并尝试这个东西,这里有完整的笔记本代码。打开笔记本运行所有单元格。

作者代码

其他功能

ColabCode 并不局限于在 Colab 上运行 FastAPI 代码还可以提供 VS 代码服务器和 Jupyter 实验室服务器!它可以帮助用户对基于云的服务有一个熟悉的环境。资源非常有限的用户也可以从这些服务中受益。它变得非常类似于新引入的 GitHub Codespaces,它在 web 上提供 VS 代码环境。要通过 ColabCodes 运行 VS 代码服务器,请执行以下操作:

from colabcode import ColabCode
ColabCode()

您将被提示一个 ngrok URL,加载完成后,您将在 web 浏览器上运行 VS 代码,如下所示:

作者图片

类似地,如果您想打开一个 Jupyter 实验室服务器,将 lab 参数作为 true 传递,将 code 作为 false。

from colabcode import ColabCode
ColabCode(code=False, lab=True)

您将获得一个 URL 和一个令牌,用于对服务器进行身份验证。输入令牌并点击 login,会出现类似如下的屏幕:

作者图片

结论

在本文中,我解释了 ColabCode 提供了什么,并简单介绍了 FastAPI。目前,该软件包的创建者 Abhishek Thakur 发布了 v0.2.0。如果您想投稿,请查看这个包的 GitHub 库。

说到这里,这篇文章就结束了,我希望你能有新的想法,我会通过其他文章加入你的反馈。

我的领英:

https://www.linkedin.com/in/kaustubh-gupta/

我的其他热门文章:

数据科学家和数据工程师之间的协作变得简单

原文:https://towardsdatascience.com/collaboration-between-data-scientists-and-data-engineers-made-simple-57b90b116572?source=collection_archive---------28-----------------------

如何在您的数据科学家和数据工程师之间创造协同效应

DayTwo 拥有世界上最大的微生物数据库,拥有超过 85K 个独特的基因组序列。分析高达数百 TB 的海量数据需要可靠而坚实的工程基础设施,能够由多名数据科学家同时进行持续探索和分析。

数据科学家需求清单

在我们开展的每个研究项目的核心,都有数据分析部分,我们的数据科学家需要分析和探索海量数据,以寻找有价值的商业见解。这种探索应该仔细设计,因为不理解基础设施的限制可能会导致失望和浪费时间。

因此,在每次实验之前,我们都会查看一份简短的清单,以展示我们可能会遇到的一些依赖和障碍:

  1. 我们的输入和输出数据的实际大小是多少
  2. 根据上面的大小,需要多少内存?
  3. 我们应该在 jupyter 笔记本还是 VS-Code 上运行它?
  4. 我们应该投资并行吗?

值得注意的是,并不是所有的实验都需要分析大量的数据。但是为了这篇文章,我们假设情况就是这样。

数据工程师前来救援

在我们看来,数据工程师是我们数据科学家工作的重要组成部分。在一个没有我们的数据工程师支持的研究项目中工作看起来会有很大的不同,而且不是一种好的方式。它从收集和查询数据的可靠基础设施开始,继续到特征选择和模型训练,当适当的工具和脚本可用时,项目的任何方面都可以被简化和更好地结构化。

托德·夸肯布什在 Unsplash 上的照片

回到我们分析数十 TB 数据的使用案例,我们通过定义一个用于发送和接收数据的共享通道来利用我们的数据工程团队的能力。

更简单的说,我们定义了两个核心组件: (1) 我们应该计算的计算量。 (2) 应该使用的相关数据子集。

通过这种方式,每个复杂且未记录的分析任务都变得结构化且易于跟踪,这使我们的研究人员能够专注于寻找见解,并将它们从科学家通常遇到的大多数工程麻烦中清除。

作者图片

收场白

数据工程师早已成为每家科技公司必不可少的一部分。在 DayTwo,除了他们“组织公司数据库的琐碎角色之外,我们还利用他们在构建工具和基础架构方面的渊博知识来简化我们的数据科学团队工作流。将我们的数据工程师整合到我们的数据科学流程中,使我们能够扩展我们的研究和数据分析能力,此外还有一个显而易见的好处,即让更多人了解当前最热门的话题之一——m lops。

如果你想了解更多关于我们正在开发的最新最棒的产品,请随时联系我。

亚龙

协作友好的 SQL 查询

原文:https://towardsdatascience.com/collaboration-friendly-sql-queries-ee7e14547a61?source=collection_archive---------36-----------------------

数据工程和数据科学

提高 SQL 查询质量和更好协作的一些技巧

作者照片。

一个数据管道卡住了,需要有人注意。或者需要使用新表重构查询,因为其中一个使用的表已经过时或不可用。或者我们需要向非常旧的数据管道的 SQL 逻辑中添加更多内容。

在所有这些情况下,几分钟后我们会有一种感觉。我们要么感谢以前的代码作者,要么被困在数百行 SQL 查询中。我敢打赌,大多数人(如果不是全部的话)都希望自己的工作得到赏识。然而,许多数据工程师和数据科学家不知道如何以协作友好的方式设计 SQL 查询。

本文将为您提供一些基本的技巧,帮助您开发专业的、协作友好的 SQL 查询和数据管道。

避免选择*

不要误解我,我经常使用 SELECT *,但只是在临时的特别查询中使用,以调查表或进行快速数据检查。很少在非临时的管道或查询中使用 SELECT *。

不使用 SELECT *很重要的原因是,当您希望以后更新或重构您的管道或查询时。更新查询(例如,用另一个表替换一个表)的第一件事是了解查询/管道中使用了哪些列。让我们考虑一个例子。

假设我们正在维护一个表,用于根据一些度量标准来识别我们的高级员工。出于某种原因,我们不能再使用performance_review表了(例如,因为一些隐私问题)。我们的任务是用其他可访问的表替换performance_review表。

WITH current_senior_employees AS (
    SELECT *
    FROM employee
    WHERE age>=45
        AND is_current = true
        AND years_in_company >= 6
),
performance_last_5years AS (
    SELECT *
    FROM performance_review
    WHERE year BETWEEN 2016 AND 2020
)
SELECT
    ARBITRARY(a.first_name), 
    ARBITRARY(a.last_name), 
    ARBITRARY(a.email),    
    SUM(b.num_of_managed_employees) AS total_num_managed_employees,
    SUM(b.num_of_managed_projects) AS total_num_of_managed_projects,
    SUM(b.revenue_generated_by_managed_projects) AS total_revenue
FROM current_senior_employees AS a
LEFT JOIN avg_performance_last_5years AS b
ON a.id = b.employee_id
GROUP BY b.employee_id

如您所见,由于 SELECT *的误用,我们无法轻松识别维护该表需要哪些表中的哪些列。我们需要更深入地研究代码,找出num_of_managed_employeesnum_of_managed_projectsrevenue_generated_by_managed_projectsemployee_id是我们应该在其他表中找到的列。当然,与实际工作中的常规查询相比,我的示例非常小,并且不难发现使用了哪些列。但是在实际项目中,一个查询可能包含数百行和数十个连接的表。在这些情况下,如果程序员首先使用 SELECT *读取所有内容,然后从一堆加载的列中选择列,那么深入代码找出哪些列来自哪些表是非常困难的。

在我的例子中,编写这个查询的更好的方法是:

WITH current_senior_employees AS (
    SELECT 
        id, 
        first_name, 
        last_name, 
        email
    FROM employee
    WHERE age>=45
        AND is_current = true
        AND years_in_company >= 6
),
performance_last_5years AS (
    SELECT 
        employee_id, 
        num_of_managed_employees, 
        num_of_managed_projects,
        revenue_generated_by_managed_projects
    FROM performance_review
    WHERE year BETWEEN 2016 AND 2020
)
SELECT
    ARBITRARY(a.first_name), 
    ARBITRARY(a.last_name), 
    ARBITRARY(a.email),    
    SUM(b.num_of_managed_employees) AS total_num_managed_employees,
    SUM(b.num_of_managed_projects) AS total_num_of_managed_projects,
    SUM(b.revenue_generated_by_managed_projects) AS total_revenue
FROM current_senior_employees AS a
LEFT JOIN avg_performance_last_5years AS b
ON a.id = b.employee_id
GROUP BY b.employee_id

使用别名

一个不好的做法是在连接多个表时避免使用别名。看下面的例子。

WITH current_senior_employees AS (
    ...
),
performance_last_5years AS (
    ...
)
SELECT
    ARBITRARY(first_name), 
    ARBITRARY(last_name), 
    ARBITRARY(email),    
    SUM(num_of_managed_employees) AS total_num_managed_employees,
    SUM(num_of_managed_projects) AS total_num_of_managed_projects,
    SUM(revenue_generated_by_managed_projects) AS total_revenue
FROM current_senior_employees
LEFT JOIN avg_performance_last_5years
ON id = employee_id
GROUP BY employee_id

这是与上一节相同的例子。唯一的区别是我在这里没有使用别名(例如,ab)。在这个例子中,很难判断出email列来自哪个表。仅仅因为列名是唯一的,就不应该停止使用别名(尤其是在连接多个表时)。

现在想象一下,如果我除了不使用别名之外还使用 SELECT *的话。

WITH current_senior_employees AS (
    SELECT *
    FROM employee
    WHERE age>=45
        AND is_current = true
        AND years_in_company >= 6
),
performance_last_5years AS (
    SELECT *
    FROM performance_review
    WHERE year BETWEEN 2016 AND 2020
)
SELECT
    ARBITRARY(first_name), 
    ARBITRARY(last_name), 
    ARBITRARY(email),    
    SUM(num_of_managed_employees) AS total_num_managed_employees,
    SUM(num_of_managed_projects) AS total_num_of_managed_projects,
    SUM(revenue_generated_by_managed_projects) AS total_revenue
FROM current_senior_employees
LEFT JOIN avg_performance_last_5years
ON id = employee_id
GROUP BY employee_id

即使对于简单的查询,使用 SELECT *并避免使用别名也会导致很大的混乱。

请记住,使用别名可以使您的查询更易读、更容易理解。

没有无意义的别名

停止使用无意义的别名,如 a、b、c 等等。不使用别名之后的下一件坏事就是使用无意义的别名。在数据工程师和科学家中,当他们连接表时,使用像 a 和 b 这样的简单别名是很常见的。我不反对将 a 和 b 用于临时的特别查询,但是我不会将它们用于长期查询或管道。当你和别人分享一个查询或者很久以后再回到你的查询,用没有意义的别名是不容易理解的。同样,对于像上一个例子一样的超短查询,不难发现 a 和 b 指的是什么,但是当查询变长时,它会占用我们太多的短期记忆来理解查询并在必要时修复它。例如,在我的查询中,我可以使用:

WITH current_senior_employees AS (
    SELECT 
        id, 
        first_name, 
        last_name, 
        email
    FROM employee
    WHERE age>=45
        AND is_current = true
        AND years_in_company >= 6
),
performance_last_5years AS (
    SELECT 
        employee_id, 
        num_of_managed_employees, 
        num_of_managed_projects,
        revenue_generated_by_managed_projects
    FROM performance_review
    WHERE year BETWEEN 2016 AND 2020
)
SELECT
    ARBITRARY(employee.first_name), 
    ARBITRARY(employee.last_name), 
    ARBITRARY(employee.email),    
    SUM(perform.num_of_managed_employees) 
        AS total_num_managed_employees,
    SUM(perform.num_of_managed_projects) 
        AS total_num_of_managed_projects,
    SUM(perform.revenue_generated_by_managed_projects) 
        AS total_revenue
FROM current_senior_employees AS employee
LEFT JOIN avg_performance_last_5years AS perform
ON employee.id = perform.employee_id
GROUP BY perform.employee_id

cte 很友好

不要害怕使用 cte。我见过数据工程师和科学家使用复杂的嵌套子查询来避免使用 cte(没有明显的原因!).让我向您展示如果我使用子查询而不是 cte,我的示例查询是如何变得复杂的。

SELECT
    ARBITRARY(employee.first_name), 
    ARBITRARY(employee.last_name), 
    ARBITRARY(employee.email),    
    SUM(perform.num_of_managed_employees) 
        AS total_num_managed_employees,
    SUM(perform.num_of_managed_projects) 
        AS total_num_of_managed_projects,
    SUM(perform.revenue_generated_by_managed_projects) 
        AS total_revenue
FROM (
    SELECT 
        id, 
        first_name, 
        last_name, 
        email
    FROM employee
    WHERE age>=45
        AND is_current = true
        AND years_in_company >= 6
) AS employee
LEFT JOIN(
    SELECT 
        employee_id, 
        num_of_managed_employees, 
        num_of_managed_projects,
        revenue_generated_by_managed_projects
    FROM performance_review
    WHERE year BETWEEN 2016 AND 2020
) AS perform
ON employee.id = perform.employee_id
GROUP BY perform.employee_id

想象一下,如果我们有几十个连接的表(有时是嵌套的),这会有多复杂。请记住,使用 cte 有多种好处:

  1. cte 对人类的短记忆是友好的(更有条理)。
  2. 您可以在一个查询中多次使用 CTE,使您的查询更有条理(与子查询相反)。

使用 JINJA2 的基本查询

Jinja2 非常受数据工程师和科学家的欢迎,用于开发数据管道。它使他们能够通过Template()函数进行动态查询和压缩大型 ETL 查询。这里我只关注 Jinja2 数百个模板应用中的一个。我的重点是向您展示 Jinja2 模板如何帮助您编写更清晰的 SQL 查询。

如果管道中有多个查询使用相同的 CTE 或子查询,请考虑使用定义一个基本查询,并通过 Jinja2 在查询中替换它。下面是一个伪查询的例子。

WITH cte1 AS (
        SELECT ... 
        FROM table3
        JOIN (    
 **SELECT 
                ...
            FROM table1
            JOIN table2
            ON table1.col1 = table2.col2
            WHERE ... 
            AND ...** 
        ) AS table_x
        ON ...
        WHERE ...),
    cte2 AS (
        SELECT ... 
        FROM table4
        JOIN (
 **SELECT 
                ...
            FROM table1
            JOIN table2
            ON table1.col1 = table2.col2
            WHERE ... 
            AND ...**
        ) AS table_x
        ON ...
        WHERE ...),
    ) 
    SELECT 
        ... 
    FROM cte1 
    JOIN cte2 
    ON ... 
    WHERE ...

如果仔细观察,您会注意到粗体子查询在cte1cte2中重复出现。使用 Jinja2 模板(例如,在 Python 中),您可以为重复查询定义一个基本查询,并在主查询中替换它。您可能会认为我们可以定义一个 CTE,而不是在这个例子中使用 Jinja2 模板。你完全正确!如果管道中只有一个带有这种子查询的查询,使用 CTE 是更好的解决方案。但是,如果您的管道中有多个单独的查询(例如,用于不同的任务)使用同一个子查询,那么您可以使用 Jinja2 模板在它们之间共享同一个查询。

如果你不知道如何使用 Jinja2 模板,这里有一个 Python 中的例子。

from jinja2 import Templatebase_query = """ 
    SELECT 
        ... 
    FROM table1
    JOIN table2
    ON table1.col1 = table2.col2
    WHERE ... 
        AND ... 
"""main_query = Template("""
    WITH cte1 AS (
        SELECT ... 
        FROM table3
        JOIN ({{subquery}}) AS table_x
        ON ...
        WHERE ...),
    cte2 AS (
        SELECT ... 
        FROM table4
        JOIN ({{subquery}}) AS table_x
        ON ...
        WHERE ...),
    ) 
    SELECT 
        ... 
    FROM cte1 
    JOIN cte2 
    ON ... 
    WHERE ...
""").render(subquery=base_query)

一些最终(但重要!!!)小贴士

最后,我想给你一些重要的一般性建议,告诉你如何设计你的查询或管道,以实现更好的协作。

由于大多数关系数据库系统的查询优化特性,您编写的查询在执行之前就得到优化。因此,在许多情况下,您可能会编写一个低效的查询(例如,将所有列加载到一个 CTE 中,然后选择列)。但是,优化器会找到一个最佳的查询计划来执行,并且机器性能仍然很好。但是,请记住,仅仅因为优化器帮助您获得了更好的性能,并不意味着您可以按照自己喜欢的方式编写查询。我们必须体谅现在和将来与我们合作维护代码的人。

最后,如果您认为有些事情在查询开发阶段可能会花费您的时间,但它会为阅读它的人节省时间,那么您必须这样做。例如,找到并使用一个合适的别名而不是随机的“a”或“b”可能会花费你一点时间,但是它会为后来阅读它的人(甚至是你自己)节省很多时间。

关注我在媒体和推特上的最新报道。

简化的协同过滤:推荐系统背后的基础科学

原文:https://towardsdatascience.com/collaborative-filtering-simplified-the-basic-science-behind-recommendation-systems-1d7e7c58cd8?source=collection_archive---------22-----------------------

入门

由卡里·谢伊在 Unsplash 上拍摄的照片

简介

在做出消费者决策时,我们似乎经常在有意识地选择我们使用的服务和我们偏好的产品。然而,竞争我们业务的公司不断以微妙的方式影响我们的决策。公司经常推荐特定的产品,以增加我们选择他们而不是竞争对手的可能性,我们接触到的产品选项组合越来越符合我们的个人偏好。这是基于这样一种理论,即某人更有可能购买和享受符合其偏好的产品。推荐系统允许公司提高用户参与度,增加销售额,并不断调整产品以适应用户的偏好[1]。实际上,我们看到的歌曲或产品的推荐列表可能看起来很简单。然而,一个复杂、直观的工程过程在幕后产生这个列表。

推荐系统利用从用户行为产生的数据来推断用户偏好。在 Spotify,用户数据可以是歌曲选择,而亚马逊经常根据用户观看的产品、购买的产品和对产品的评论进行推荐。如何实现推荐系统的细节由用例决定,但是已经有了生成推荐的通用技术。最显著和最强大的技术是协同过滤,我们现在将进一步探讨它。

协同过滤

协同过滤使用大量关于用户交互的数据来生成一组推荐。协同过滤背后的想法是,对某些项目有相似评价的用户现在和将来都会喜欢同样的东西[2]。例如,假设用户 A 和用户 B 都喜欢项目 X 和 y。基于该信息,我们可以假设用户 A 和 B 具有相似的偏好。因此,如果用户 B 喜欢项目 Z,我们可以向用户 a 推荐项目 Z。这种从用户之间的相似性中寻找推荐的过程就是这种技术被称为“协作”过滤的原因。

驱动协同过滤系统的交互数据可以经由显式提示从用户处获得,或者从用户行为中隐式提取。在显式数据的情况下,用户提供关于他们喜欢某个项目的程度的清楚和直接的数据。这通常是用户被明确提示提供的“喜欢”或等级(见下图)[5]。也可以隐含地收集用户偏好数据。这需要根据跟踪的行为间接推断用户是否更喜欢某个项目。这些行为可以包括用户浏览了哪些页面,他们点击了哪里,他们花了多少时间看一些东西,等等[3]。例如,如果用户长时间查看某个项目,这通常意味着他们喜欢该项目或对其感兴趣。

亚马逊要求顾客评论的例子(截图直接来自 Amazon.com)

一旦收集了交互数据,接下来的问题就是如何将这些数据转化为推荐?最流行的方法之一是称为矩阵分解的强大的线性代数技术。矩阵分解为应用协同过滤提供了具体的数学基础,因为它允许我们将交互数据转换成确定用户是否会喜欢某个项目的模型。

矩阵分解

为了理解矩阵分解,我们必须了解矩阵乘法是如何工作的。矩阵是一组按行和列排列的数字,形成一个数组。当两个矩阵相乘时,结果矩阵的行数与第一个矩阵相同,列数与第二个矩阵相同。对于结果矩阵中的每个元素,我们在第一个矩阵中取相应的行,在第二个矩阵中取相应的列。然后,我们将所选行和列的相应元素相乘,并将结果相加。下图显示了该过程如何工作的示例。结果矩阵中的值 75 在第一行,所以我们选择第一个矩阵的第一行。值 75 也在第一列中,所以我们选择第二个矩阵的第一列。然后将行和列中的相应值相乘,并将结果相加,得到值 75。

矩阵乘法的一个例子(图片由作者提供)

乘法就是可以通过因式分解的过程来倒推。例如,3 和 4 相乘得到数字 12。然后,数字 12 可以分解为因子 3 和 4,因为它们相乘得到 12。同样的事情也可以用矩阵来做。对于大多数矩阵,存在两个矩阵因子,它们相乘得到同一个矩阵,或者是一个非常接近的矩阵。在上图中,第三个矩阵可以分解为前两个矩阵。这是因为将这两个矩阵相乘会得到第三个矩阵。为给定矩阵寻找两个因子的过程称为矩阵分解。

在推荐系统中,用户交互存储在一个大矩阵中。考虑电影推荐系统的情况。在矩阵的一个轴上,我们可以有不同的用户,而在另一个轴上是不同的电影。矩阵中的每个值对应于用户对该电影的喜爱程度(隐式或显式,取决于收集的数据)。然后,我们可以得到这个矩阵,并应用矩阵分解。结果因子将是表示用户偏好的矩阵和表示电影的矩阵。让我们看一个例子来获得更多关于这是如何工作的直觉。

协作过滤示例

此图像用于以下协作过滤示例。蓝色数字是未收集的数据。它们表示通过执行矩阵分解做出的预测(图片由作者提供)。

考虑上图中有三个用户和三部电影的情况。黑色轮廓的矩阵代表交互数据。绿色和红色的数字是通过观察用户动作收集的,而蓝色的数字是通过执行矩阵分解生成的。如果值为 1,则用户喜欢相应的电影,如果值为 0,则用户不喜欢。

交互矩阵已经被分解为用户和项目的嵌入矩阵。两个新矩阵中的数字使得两个矩阵相乘得到相互作用矩阵。例如,为了得到交互矩阵左上角的值,我们对用户矩阵中第一行和项目嵌入矩阵中第一列的相应元素的乘积求和。这个值是 11 + 00 = 1,与左上交互值相匹配。注意,以前未知的蓝色值现在可以通过应用相同的过程得到。例如,可以使用用户矩阵的第二行和项目矩阵的第二列来计算用户 User 2 喜欢蝙蝠侠的程度的值。

检查交互值将表明我们的协同过滤应用已经成功了!请注意,用户 1 和 2 有相似的偏好,因为他们都喜欢超人,不喜欢《冰雪奇缘》。因此,因为用户 1 喜欢蝙蝠侠,所以用户 2 也可能喜欢蝙蝠侠,这由该点中蓝色生成的值 1 所证实。相反,请注意,用户 3 的偏好与用户 1 和 2 非常不同。因此,由于这两个用户都喜欢蝙蝠侠,用户 3 可能不喜欢蝙蝠侠,这一点由我们在该点生成的蓝色值 0 所证实。这个简单的例子演示了矩阵分解如何确定用户是否喜欢某个项目。通过推荐用户最可能喜欢的项目,这些信息可以转化为推荐。实际上,数据集会更大,计算会更复杂。虽然本例中的值是手工设计的,但生产级推荐系统的计算将使用内置机器学习功能的库自动处理[4]。

我们还没有解决的一件事是,这些推荐是如何在没有定义任何电影信息的情况下做出的。在我们的例子中,我们知道蝙蝠侠和超人都是动作片,而《冰雪奇缘》是一部更面向家庭的电影。然而,我们从来没有定义过电影的类型,但是无论如何,检查用户行为仍然会导致似乎考虑电影类型的预测。潜在特征使得在没有关于项目的定义信息的情况下推荐项目的能力成为可能。潜在特征是我们没有明确定义的项目特征或用户偏好。然而,在寻找一组能够解释我们的相互作用数据的嵌入矩阵值时,矩阵分解中使用的计算无意中发现了一组相关特征。这是因为潜在特征首先影响了用户交互。这些特征可以是从流派信息到价格的任何东西。没有办法明确知道哪些特性会生效,但是我们通常可以根据我们推荐的项目类型进行假设[5]。潜在特征提供了协作过滤的真正力量,因为它们给大量数据带来了秩序。这最终为用户提供了可能是准确的推荐。

冷启动问题

关于协同过滤的最后一件事是它最大的缺点,冷启动问题。你可能已经注意到,在我们之前的例子中,我们能够确定用户 2 和 3 有多喜欢蝙蝠侠,因为我们知道用户 1 有多喜欢它。然而,如果我们不知道用户 1 对这部电影的想法,我们如何为其他 2 个用户做出预测呢?当然,我们可以意识到蝙蝠侠是一部动作片,类似于超人。这意味着用户 2 可能会喜欢,而用户 3 不会。然而,这违背了在协同过滤中使用潜在特征的目的。这种难以预测没有交互数据的项目的问题被称为冷启动问题。

当协作过滤系统最初被创建时,由于缺乏关于用户偏好的信息,它通常是无效的。这阻碍了这种类型的推荐系统的性能,并且可能导致它在用户基数小或者项目太多的情况下无效。通常,这可以通过存储关于每部电影的一些相关的显式特征信息(例如,流派、评级等)来解决。)并将其与用户过去的偏好进行匹配。由于冷启动问题,这种混合方法在现实世界中经常发生。

入门指南

现在我们已经回顾了基础知识,您可以开始探索一些工具并创建您自己的推荐系统。许多编程语言都可以用来创建推荐系统,但最常用的是 Python。Python 有很棒的工具,比如 pandas 和 NumPy,它们可以让你将交互数据转换成一种便于计算的形式。TensorFlow 和 PyTorch 等工具具有内置功能,可以处理协作过滤所需的强大计算。

推荐系统在现代商业中已经变得非常普遍。它们允许公司通过根据用户的偏好定制产品来实践先进的微营销策略。推荐系统的力量只会继续增长,因为它们从我们的行为中学到了更多关于我们个人偏好的东西。有了这些工具和我们在这里讨论的概念,你将有一个很好的开始来创建你自己的推荐系统,并在你自己的企业中利用技术的力量。

注意:本文主要介绍了协同过滤的基础知识,并提供了一个简单的例子来说明它是如何工作的。您可以期待未来的一些更高级的文章,介绍构建功能性推荐系统的技术步骤!

参考

[1] C. Underwood,“商业中推荐系统的使用案例——当前应用和方法”,Emerj ,2020 年 3 月 4 日。【在线】。可用:https://emerj . com/ai-sector-overviews/use-cases-recommendation-systems/。【访问时间:2020 年 10 月 10 日】。

[2] V .鞍马,《协同过滤简单介绍》,内置,04-Sep-2019。【在线】。可用:https://builtin . com/data-science/collaborative-filtering-recommender-system。【访问时间:2020 年 10 月 10 日】。

[3] S .罗,《推荐系统导论:协同过滤》,,2019 年 2 月 6 日。【在线】。可用:https://towards data science . com/intro-to-recommender-system-collaborative-filtering-64a 238194 a26。【访问时间:2020 年 10 月 10 日】。

[4]“协同过滤|推荐系统|谷歌开发者”,谷歌。【在线】。可用:https://developers . Google . com/machine-learning/recommendation/collaborative/basics。【访问时间:2020 年 10 月 10 日】。

[5] P. Pandey,《现实世界中的推荐系统》,,2019 年 5 月 25 日。【在线】。可用:https://towardsdatascience . com/recommendation-systems-in-the-real-world-51e 3948772 f 3。【访问时间:2020 年 10 月 10 日】。

使用 fast.ai 的协同过滤

原文:https://towardsdatascience.com/collaborative-filtering-using-fast-ai-f33cfea62812?source=collection_archive---------13-----------------------

了解推荐系统

想知道网飞是如何为用户推荐合适的内容的吗?这一深度探讨集中在推荐系统和嵌入[潜在因素]上,以从用户-项目交互中获得意义。如果你以前没有使用过推荐系统,这个博客对你来说是一个完美的开始。本文描述的模型使用 fast.ai 库,并假设您对 python 编程语言以及 PyTorch 有基本的了解。让我们开始吧。

在 Unsplash 上由 Sayan Ghosh 拍摄的照片

数据分析

首先,让我们熟悉一下“电影镜头”数据集。要将数据输入 jupyter 笔记本,只需运行下面的单元格。fast.ai 函数会帮你完成剩下的工作。

注意:该数据集使用 100,000 个电影排名的子集。

样本收视率数据

收视率数据正是我们所需要的。用户栏、电影 id、相应的评级和时间戳。为什么要建立模型?因为评价是不完整的,并且推荐者试图为用户以前没有看过的电影填充缺失的评价。

了解潜在因素

对于那些不熟悉推荐系统的人来说,这是重要的一步。潜在因素基本上是为数据集中的每个用户和电影随机初始化的参数。如果您在这一点上没有得到它,也不要太担心,但请尝试并了解这些潜在因素在协同过滤中的作用(下面的解释)。

假设我们知道用户喜欢一部电影所属类别(流派)的程度。现在假设我们也知道关于每部电影的相同信息[即电影与这一类别的紧密程度]。现在,为了填补缺失的评级,只需将这两个潜在因素相乘。答案是你对那部电影的预测评分。信息太多?让我们看一个小例子来理解这个概念。

尝试运行下面这段代码的代码块:

这里假设潜在因子的范围在-1 和 1 之间,正数表示强匹配,负数表示弱匹配。这个例子中的类别是“科幻小说”、“动作片”和“老电影”。也就是说,电影《原力觉醒》有它的潜在因素:1 为 0.98,表示它“有多科幻”,潜在因素:2 为 0.9,表示它“有多动作”,潜在因素:3 为-0.9,表示它“有多老”。

科幻电影预测

言情电影预测

我们在这里做了什么?我们基本上是将两个潜在向量/因子相乘,然后将它们的结果相加。如果你想用数据科学术语,你可以称之为“点积”。很简单,对吧?对于数据集中的每个用户和电影都会发生这种情况,这就是该模型的基本原理。从上面的例子中,你可以清楚地看到我对科幻/动作电影感兴趣,所以《原力觉醒》[2015]的评分高于《一个明星诞生》[1937]。

重要提示:正如这里提到的,评级预测基本上是潜在因素的点积。一旦计算了点积,该模型就试图通过调整潜在因子来最小化损失(使用随机梯度下降,本文将不讨论其细节,但模型实现将简要解释其功能)。

就这样—让我们从实际的代码开始:)

创建数据加载器

为了使这成为一个有趣的练习,让我们将电影片名引入到我们的数据集中,并将它们与收视率数据合并。表“u.item”由映射到标题的电影 ID 组成,所以让我们把它们拖进来。

为了更好的直觉,标题被合并

Dataloaders 对象通常将第一列作为用户,第二列作为项目,评级作为第三列。由于我们的项目是电影,我们将其重命名为“标题”,批量大小为 64。

协同过滤的 PyTorch 表示

潜在因素需要以某种方式表示出来,以便我们对模型有所了解。pyTorch 表示它们的方式是使用矩阵。这是使用“torch.randn”函数完成的。工作原理是——py torch 根据用户和电影的总数随机创建用户和电影潜在因素。然后用点积来得出评级。我们已经确立了这一点。但是要做这个点积,就要在我们的电影潜在因子矩阵中查找电影的索引,在用户矩阵中查找用户索引。这不是深度学习模型知道的。这就需要嵌入【一个很简单的话题】。

在我们继续之前,请随意查看 pyTorch 如何在没有嵌入的情况下创建以下潜在因素:

嵌入

尽管“嵌入”这个术语听起来很奇怪,但其基本概念却很简单。这也是直接索引条目的行话。为了定义嵌入,让我们创建一个类和一个函数来定义潜在因素(嵌入)以及这些因素的点积,以达到预测的评级。

很简单,对吧?第一块使用嵌入创建用户和电影潜在因素,而第二块将两者相乘(点积)。

这里要理解的关键是模型接受一个形状张量(batch_size x 2)作为输入。这里第一列代表用户 id,第二列代表电影 id。嵌入层用于表示用户和电影潜在因素的矩阵。再次,自己探索一下数据。例如,分别看一下 x 和 y。

模范学习者

嵌入完成后,我们只剩下运行模型了。

历元&损失— I

结果相当不错。我们可以通过使用 sigmoid_range 来进一步改进它,以确保我们的预测评级在 0 到 5 之间。

现在让我们尝试运行模型

时期&损失-II(具有乙状结肠范围)

差别不大。我们肯定能做得比这更好。我们可以尝试的一件重要或显而易见的事情是考虑偏见。如果我们可以为每个用户添加一个数字,并对每部电影都这样做,我们将考虑用户和电影的偏见。所以让我们来试试这个。

时代&损失— III(有偏差)

不太好。我们的结果变得更糟了。我们可以尝试的最后一件事肯定会改善我们的模型结果。让我们介绍一下我们数据科学家称之为加权衰减或 L2 正则化。该参数将基本上控制我们添加到损耗中的平方和,并减少过拟合。

纪元&损失—四(与 L2)

好多了。我们的成绩终于提高了。现在,让我们从这些建议中获得一些视觉效果和见解。

解释嵌入和偏见

该模型为我们提供了建议,但看到它识别出了哪些因素是非常有趣的。让我们试着看看偏见。下面的代码给了我们偏差最小的电影。

偏见最低的电影

这是什么意思?这基本上是在告诉我们,这些电影可能与某些用户的潜在因素非常匹配,但最终仍然不被用户喜欢。我们可以只按平均评级对电影进行分类,但这种使用偏见的观点更有趣,因为它不仅告诉我们一部电影是否是人们不太喜欢的那种,而且告诉我们这样一个事实,即它完全属于他们喜欢的类别,但他们并不总是喜欢它。

我很赞同这个模式。这些是一些糟糕的电影(其中一些是闻所未闻的,至少对我来说是这样——比如《歌舞女郎》, Bio-Dome 的互联网评分低于 5 分)

从这个意义上说,这是获得最具偏见的电影的代码。

偏见最高的电影

这也是我不得不同意的一点。这是一个疯狂的电影列表。我个人已经看了全部 10 部电影,所以电影中的偏见已经被很好地考虑进去了。

用于可视化电影的 PCA

解释嵌入并不那么直接,因为维数通常很高。但是我们可以使用主成分分析来提取最重要的信息,并观察电影是如何分散在较低的维度中的。

潜在空间中的电影 PCA 情节

这个情节挺有意义的。如果你注意到,我们有一些科幻电影,如《帝国反击战》、《绝地归来》、《星际迷航》、《印第安纳琼斯》等。左边是一些新黑色电影,如《教父》和《法戈》。这是几个例子,说明相似的电影在潜在空间中表现得有多相似。

这篇博客到此结束。要查看完整代码和其他机器学习算法的笔记本,请关注我的【github

从 Twitter 收集数据:使用 Tweepy 的逐步实现

原文:https://towardsdatascience.com/collect-data-from-twitter-a-step-by-step-implementation-using-tweepy-7526fff2cb31?source=collection_archive---------8-----------------------

本文是使用 tweepy 从 Twitter 收集数据的全面概述

布雷特·乔丹在 Unsplash 上的照片

介绍

获取数据是任何数据科学/机器学习项目生命周期的第二步,就在框定你想要解决的问题之后,这将使这一步成为其余阶段的支柱。此外,社交媒体是收集数据的好地方,尤其是用于竞争对手分析、话题研究、情感分析等。本文旨在逐步实现如何获取凭证,并在一个简单的用例上实现。

Twitter,一个相关的数据收集场所

Twitter 拥有 3.13 亿活跃用户( Statista,2017 ),这意味着这种数据收集方法可以减少基于研究人员地理位置和研究资源的研究参与障碍。它还可以最大限度地利用资源,包括时间、精力和便利

Tweepy 的实现示例

在执行任何类型的分析之前,要执行的第一个操作是获取您的 Twitter 认证凭证,如下所述。

获取认证凭证

  1. 注册开发者账户

这里的是进入下一页的链接。

(图片由作者提供)

2。获取您的认证凭证

在此页面上,创建一个项目并回答所有问题。然后,您将获得包含所有凭证的以下页面。确保你不会与任何人分享这些信息。

(图片由作者提供)

实施要求

  • 安装 tweepy 模块
pip install tweepy # install the tweepy module
  • 导入所需的模块
import tweepy # tweepy module to interact with Twitter
import pandas as pd # Pandas library to create dataframes
from tweepy import OAuthHandler # Used for authentication
from tweepy import Cursor # Used to perform pagination

Python 实现

  • 实现实用函数来获取 tweets:
    在这个例子中有三个主要的函数。(1)认证功能。(2)为了与 Twitter API 交互的客户端功能。(3)最后一个功能,收集推文并创建一个数据框,其中包含关于给定 Twitter 帐户的一些特定信息。收集的信息如下:

    推文的创建日期
    推文的作者推文的作者
    与推特账户上的名字相对应的网名
    该推文获得的点赞数
    推文转发数

"""
Twitter Authentification Credentials
Please update with your own credentials
"""
cons_key = ''
cons_secret = ''
acc_token = ''
acc_secret = ''# (1). Athentication Function
def get_twitter_auth():
    """
    [@return](http://twitter.com/return):
        - the authentification to Twitter
    """
    try:
        consumer_key = cons_key
        consumer_secret = cons_secret
        access_token = acc_token
        access_secret = acc_secret

    except KeyError:
        sys.stderr.write("Twitter Environment Variable not Set\n")
        sys.exit(1)

    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_secret)

    return auth# (2). Client function to access the authentication API
def get_twitter_client():
    """
    [@return](http://twitter.com/return):
        - the client to access the authentification API
    """
    auth = get_twitter_auth()
    client = tweepy.API(auth, wait_on_rate_limit=True)
    return client # (3). Function creating final dataframe
def get_tweets_from_user(twitter_user_name, page_limit=16, count_tweet=200):
    """
    [@params](http://twitter.com/params):
        - twitter_user_name: the twitter username of a user (company, etc.)
        - page_limit: the total number of pages (max=16)
        - count_tweet: maximum number to be retrieved from a page

    [@return](http://twitter.com/return)
        - all the tweets from the user twitter_user_name
    """
    client = get_twitter_client()

    all_tweets = []

    for page in Cursor(client.user_timeline, 
                        screen_name=twitter_user_name, 
                        count=count_tweet).pages(page_limit):
        for tweet in page:
            parsed_tweet = {}
            parsed_tweet['date'] = tweet.created_at
            parsed_tweet['author'] = tweet.user.name
            parsed_tweet['twitter_name'] = tweet.user.screen_name
            parsed_tweet['text'] = tweet.text
            parsed_tweet['number_of_likes'] = tweet.favorite_count
            parsed_tweet['number_of_retweets'] = tweet.retweet_count

            all_tweets.append(parsed_tweet)

    # Create dataframe 
    df = pd.DataFrame(all_tweets)

    # Revome duplicates if there are any
    df = df.drop_duplicates( "text" , keep='first')

    return df

所有的功能最终都实现了,现在我们可以继续收集数据了。比方说,我们想收集谷歌人工智能的推文。创建数据框的函数将 Twitter 用户名/屏幕名称作为强制参数,在本例中,它是 GoogleAI ,没有@符号。

图片来自作者定制的 GoogleAI Twitter 账户

googleAI = get_tweets_from_user("GoogleAI")print("Data Shape: {}".format(googleAI.shape))

打印 指令显示 数据形状:(1743,6) 含义我们有 1743 条来自 Google AI 的推文,下面的 。head(10) 给出了数据帧中的前 10 条推文

googleAI.head(10)

googleAI.head 的结果(10)

tweepy 的优点和缺点

优点

  • 写得很好的文档,有一个非常活跃的社区
  • 提供关于给定推文的许多特征(例如,关于推文的地理位置的信息,等等。)

缺点

  • 将用户限制在时间线中的最后 3200 条推文。

文章结尾

在本文中,您了解了如何获得 Twitter 开发人员证书,以及如何使用 tweepy 从 Twitter 获取数据。此外,您已经了解了该工具的局限性和优点。

如需进一步阅读,请随时查阅以下链接:

额外资源

Github 上的源代码

Twitter 开发者文档

十二页文档

Twint 文档

如何访问 Twitter API

使用 Twitter 收集医疗保健消费者的数据:范围审查

再见🏃🏾

收集爱好数据集:咖啡

原文:https://towardsdatascience.com/collecting-a-hobby-dataset-454e07a3f48e?source=collection_archive---------41-----------------------

数据科学

管理野生数据集的短暂旅程

现代的数据科学已经允许人们参加一个训练营,在那里给他们清理过的数据集来训练分类器。虽然结果可能令人兴奋,但进行分析或培训只是成为数据科学家的一小部分。如果有的话,实验设计、数据收集、数据验证和数据清理消耗了你的大部分时间。如果你已经做好了所有这些事情,那么训练和分析是直截了当的,甚至时间。

从专业角度来说,我已经单独或作为团队的一员完成了所有这些步骤。就我个人而言,我收集了我感兴趣的事物的数据集。

当我想买一辆新的汽车时,我建立了一个我想要的关键特征的小数据集。一旦我面前有了所有的特征,最佳选择就很清楚了,奇怪的是,它并不是由我认为的决定性因素决定的。对汽车来说,一切都是平等的,这意味着只有像 CarPlay 这样的小功能才能使它们与众不同。

当我想更好地了解的营业额和我之前公司的健康状况时,我开始建立一个数据集。这需要耐心。没人给我或想给我数据。事实上,我的数据来自公司的电话列表这样简单的东西。随着时间的推移,我的数据集变得越来越清晰,几年后,很明显,基于不可持续的周转率,该公司正在走向破产。

咖啡数据集

几个月前,我开始对寻找咖啡 Q 等级的大型数据集感兴趣。q-分级是一种用标准化的味道分级系统来比较咖啡的方法。我想对它们做一些分析,看看它们在确定更好的混合或解释为什么混合效果好方面有多大用处。

除非另有说明,所有图片均由作者提供

虽然我发现一个数据集(CQI)管理得相当好,但我真的想从 Sweet Maria's 建立一个更有用的数据集,因为我在那里买了大部分的绿咖啡。sweet Maria’s 也有咖啡的味道,这是 CQI 的数据集中没有的。

难点在于:这需要大量的手工工作。

原始数据

Sweet Maria's 将他们所有的旧咖啡作为存档页面,每一种都有价格、总 Q 值和一些图片。每个都有一个显示 Q 分数的子矩阵的图像和一个显示味道的图像。这两个图像都显示为一个蜘蛛图。

图片经 Sweet Maria's 许可转载

这个列表中有 300 多个条目。我不得不在一个页面上查看所有的咖啡,点击每个咖啡的快速摘要,点击 Q-score 图表,然后选择全部,并复制。我为味道图重复了这个步骤。这个过程大概花了两个小时。我最终这样做了两次,因为我第一次建立这个数据库时,我没有收集风味等级。

屏幕截图,合理使用

此外,我对所有这些产品进行了比较,这样我就可以获得元数据,如加工方法、地区和品种。

截屏,合理使用

分数提取

对于 Q-score 和 flavor 蜘蛛图,我编写了一个脚本来分割图像,识别圆圈,然后提取分数。

对于口味,我不得不稍微修改脚本,但我能够相对容易地得到分数。

Q-scores 有一个我单独得到的最终分数,还有一个 cupper 的修正。我编写了一个脚本来手动输入 cupper 的更正,这样我就可以帮助验证 cupper 的总得分。这让我可以在几分钟内浏览全部 300 张图片。

我使用这两条信息来计算 Q 分数子矩阵的平均误差,并通过这个误差来修正所有的子矩阵。结果,当我进行一些数据验证时,数据的每个子指标的误差小于 0.1。

然后,我通过随机采样数据、查看图像并验证提取的子测量分数与图像匹配来验证数据。这花了一些时间,但它有助于确保我的蜘蛛图提取工作正常。

然后我将它链接到元数据,数据集就可以处理了。

数据分析

我用这些数据来了解每个分项指标相对于总分的质量,甜蜜玛利亚的 Q-等级与有多相似,以及甜蜜玛利亚的 Q-分数与 CQI 的 Q-分数有多相似。

这里我展示了每个指标与的相互关系:

以下是这些分数如何被用来比较咖啡和其他咖啡并了解咖啡是如何相似的:

以下是 CQI 咖啡评分与甜甜玛利亚咖啡评分的相似之处:

总的来说,这项工作非常耗时,而且回报也不明朗。由此产生的分析可能是浪费时间,但更令人兴奋的分析部分是为分析做准备。否则,分析不会如此有趣,我也不会有如此强烈的情感依恋。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

弃船:一家初创公司如何破产

从蜘蛛图中提取数据

学习新语言的技巧

买车:分析

与星共舞(DWTS):分数膨胀?

在 Python 中收集、转换和清理 JSTOR 元数据

原文:https://towardsdatascience.com/collecting-transforming-and-cleaning-jstor-metadata-in-python-fef9f8689e3a?source=collection_archive---------28-----------------------

使用 ElementTree XML 从 JSTOR 数据解析元数据的简单指南。

照片由🇸🇮·扬科·菲利在 Unsplash 上拍摄

STOR 数据库是 50 多个科学领域研究论文的主要来源之一。在用于研究的数据部分,研究人员可以访问数据集,用于图书馆发布的文章和书籍的研究和教学。通过该服务可以获得的数据包括元数据、n-grams 和 JSTOR 上大多数文章、书籍章节、研究报告和小册子的字数。但是,数据请求的输出不是简单的 csv。或者 txt。文档,但 XML 文件需要一些处理和清理才能有效地处理数据。在 R 中,2020 年中期发布的包 Jstor 使得整个过程简单得多。

为了让数据科学家和研究人员更容易访问大量数据,在本文中,我展示了用于解析 XML 输出的 python 代码,解释了从 JSTOR data for research 数据库收集数据的过程,并展示了这种数据的一个很好的应用。

收集数据

研究数据(DfR)支持手动请求,一次最多可将 25,000 个文件作为外部链接发送到您的邮箱。这些文件可能包括数据库中发表的文章和书籍的元数据(文章或书籍名称、期刊名称、出版年份、参考文献等)。),以及 N-grams(文章和书籍的标记化文本)。

例如,我们可能会对从《泰晤士报》创刊到现在为止的 5 种顶级经济学期刊(《美国经济评论》、《计量经济学》、《经济学季刊》、《政治经济学杂志》和《经济研究评论》)中关注数据科学机器学习大数据的文章频率感兴趣。要提出这样的请求,这些查询需要放在这里:

(机器学习)jcode:(amereconrevi 或计量经济学或 revieconstud 或 quarjecon 或 jpoliecon)

(数据科学)jcode:(amereconrevi 或计量经济学或 revieconstud 或 quarjecon 或 jpoliecon)

(大数据)jcode:(amereconrevi 或计量经济学或 revieconstud 或 quarjecon 或 jpoliecon)

这些请求产生了 576 篇关于机器学习的文章,9 459 篇关于数据科学的文章,3 059 篇关于大数据的文章,以 XML 格式存储。

数据转换

从导入必要的库开始, ElementTree 用于解析 XML 文件,这些文件是 DfR 请求的输出, os 模块提供创建目录的功能,以便单个循环可以一起访问这些文件, PandasNumpy 进行数据操作, matplotlibseaborn 绘制图形。

import xml.etree.ElementTree as ET
import os
import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt

将所有文件存储在文件夹 data 中,该循环首先访问三个子文件夹机器学习数据科学大数据,并在每个子文件夹中解析源文件。它遵循 XML 文件的层次结构,忽略书评和通知。

循环从每个文件中存储期刊标题、文章标题、出版年份和关键字(与存储文件的子文件夹的名称相同)。数据列表随后被转换为熊猫数据框。

数据清理

为了发现数据中的研究趋势,论文综述、索引、讨论、笔记和成员列表都被删除。通过这种基本的数据清理,只有发表的文章留在数据中,这提供了关于研究人员随着时间的推移对数据科学在经济学中的应用的兴趣的有价值的信息。

对原始 XML 源文件和 Pandas data frame 中转换后的数据集进行快速比较,可以看出其中的神奇之处:

最后,让我们使用 seaborn relplot 绘制系列图:

我们可以看到,自 20 世纪 60 年代以来,对数据科学的研究兴趣呈指数增长。自 20 世纪 80 年代以来,大数据经历了一场繁荣,自 21 世纪初以来,对机器学习的兴趣稳步增长。140 年跨度的数据涵盖了现代经济研究的重要发展。

来源:自己的作品。

结论

JSTOR data for research 提供了关于所有科学学科研究趋势的有价值的数据。研究人员和数据科学家可以使用文本挖掘、机器学习和其他数据科学技术来发现数据中有价值的模式。处理最终数据集可能具有挑战性,因为源数据文件是以 XML 格式发送给用户的。有了我介绍的 Python 代码,这些操作不再是一项具有挑战性的任务。

更新:2021 年 5 月,用于研究的 JSTOR 数据切换到新平台 星座

PS:你可以订阅我的 邮箱列表 每次我写新文章都会收到通知。如果你还不是中等会员,你可以在这里加入https://medium.com/@petrkorab/membership

感谢

本文是与 David str ba(布拉格 Lentiamo)合作编写的。

图像处理中的颜色交换技术。

原文:https://towardsdatascience.com/color-swapping-techniques-in-image-processing-fe594b3ca31a?source=collection_archive---------15-----------------------

理解色彩空间并在 Python 中实现色彩交换。

照片由 维克多

在这篇文章中,我试图解释我的探索,即为什么需要交换图像中的颜色,以及我们如何使用简单的图像处理方法,通过在 Python 中实现来智能地交换图像中的颜色。

为什么要换颜色?

数据科学家对颜色交换感兴趣可能有几个原因:

  1. 作为数据科学从业者,我们可能希望使用颜色交换方法作为数据增强策略,这有助于在处理深度学习算法的同时增加数据量。
  2. 很多时候,找到一个真实的、开源的大型数据集来研究算法是很有挑战性的,在这种情况下,使用合成数据会变得非常有帮助。因此,当图像数据有限时,这些图像处理技术在生成高质量的合成图像时会非常方便。
  3. 我们可能想尝试一些很酷的东西,比如在参加会议时交换背景色,调整衬衫的颜色等等。

色彩空间

类似于我们有不同类型的数字系统来表示一个数(例如:二进制、十进制、十六进制等。),同样,在特定的显示/图像中,有不同的数字系统来表示颜色/颜色的关联。这些系统被称为色彩空间**。**

在开始实现智能色彩映射之前,首先,让我们试着理解一些在计算机视觉和图像处理领域广泛使用的色彩空间:

RGB 颜色空间:

它是基于 RGB 颜色模型的三维空间。在这个模型中,任何颜色都是三原色分量(红色、蓝色和绿色)的不同强度的混合。这些分量可以被认为是色彩空间的数学坐标。借助于 3D 笛卡尔空间中的立方体,该模型被最佳可视化:

图 3:一个单位边长的 RGB 颜色立方体.图片作者。

所有分量以全强度会聚,产生白色。默认情况下,OpenCV 以 BGR 格式读取和存储图像。

HSV 颜色空间:

它是基于 HSV 颜色模型的三维颜色空间。在这个模型中,我们用单独的组件来表示颜色和强度:
*** Hue -
表示颜色(蓝色、红色、绿色等。),其取值范围为 0 到 360*。
*饱和度- 代表一种颜色的纯度色彩度的多少。较低的饱和度值意味着褪色或变灰的颜色。

  • Value - 代表一个色调的明度或暗度。**

这个模型最好在圆柱坐标系的帮助下可视化(虽然大多数文本使用 3D 圆锥体,但 3D 圆柱体实际上是更精确的数学表示)。

图:HSV 颜色模型,有单位半径和单位高度。”表示该组件的值是多少并不重要。图片作者。

*在此模型中,方位角(0–360 )指定色调分量,距中心的径向距离与饱和度分量相关,沿轴的距离代表图像的亮度。

LAB 色彩空间:

**类似于 HSV 颜色空间如何从强度和亮度分量中分离颜色分量,LAB 颜色空间使用 2 个分量来表示颜色,1 个单独的分量来表示亮度值。

  • L:明度分量,
  • A:指定红/绿色组合的颜色分量,
  • B:指定蓝/黄色组合的颜色分量。**

借助于 3-D 空间中的球体,颜色模型被最好地可视化。

图:带单位半径的 LAB 颜色模型。图片作者。

这些不同空间中的每一个都有其自身的优点和缺点,这取决于使用的应用。

实验

让我们进入实现部分。让我们考虑几种颜色交换的情况,我们将从一个简单的颜色交换图像开始(简单的意思是颜色分布变化不大),然后逐渐转到图像具有变化的颜色分布的例子,在这些例子中,交换选择的特定颜色是相当棘手的。

让我们考虑下图。它看起来像一支绿色的塑料笔身,由金属笔尖和绿色的塑料笔帽组成,笔帽上有一些金属部分和黑色的设计。

图:钢笔的原始图像。图片作者。

现在,我们想把笔身的颜色从绿色改为紫色,并希望生成的图像像原来一样逼真,并且需要在生成的图像中考虑所有的照明和阴影。我们能在 RGB 空间中实现吗?让我们试一试。注意:在 Open-CV 库的帮助下加载图像时,特定颜色空间中的组件范围通常是从 0 到 255。对于 HSV,OpenCV 使用 H:0–179,S:0–255,V:0–255。

图:x 轴代表[0,180]中的Hue

图:将【B】分量的值增加一个固定的量,会导致颜色和强度值都发生变化。图片作者。

这个奇怪的合成图像的原因是:

  • RGB 空间借助所有三个分量(R、G 和 B)来指定颜色和亮度信息。
  • RGB 图像中的每个像素都是这些成分的特定组合,我们无法解释一个成分需要改变多少才能获得所需的颜色。
  • R、G、B 分量中任何一个的任何变化都会引起像素的颜色和亮度值的变化。

如果有一个空间,其中颜色和亮度信息都在彼此独立的单独组件中指定,那么交换颜色将会非常容易。这就是像 HSV 和 LAB 这样的色彩空间出现的原因。现在让我们试着通过改变 HSV 颜色空间中的色调值来交换钢笔颜色。

图:通过改变图像的色调分量得到的图像。亮度和饱和度值没有干扰。图像看起来很真实。图片作者。

类似于改变色调值如何不影响图像的亮度分量,让我们检查我们是否可以改变图像的亮度而不干扰图像的颜色/色调分量。

图:通过降低亮度分量获得的图像。图片作者。

显然,在 HSV 颜色空间中使用不同的组件非常容易。我们看到了修改不同的组件如何帮助我们分别转换图像的颜色组件和亮度。

将亮度通道乘以 0.6(暗化效果)也会导致背景变暗。在早期的图像中,我们也看到改变色调值会导致背景颜色的变化。

让我们来研究一下,如何只改变钢笔的颜色或者只改变前景的亮度而不改变背景。注意,还有其他基于深度学习的技术,如 GANs,也可以用来实现相同的目的,在本文中,我们只讨论解决该问题的简单图像处理技术。

这个想法是为背景或前景创建一个颜色范围二元蒙版,然后使用该蒙版有选择地将颜色变化应用于前景。但是,面具适合哪种颜色呢?为了回答这个问题,如果我们为我们的色调/颜色通道绘制直方图就好了。这是我们的色调通道和直方图的样子:

图:原始笔图像的色调通道。图片作者。

图:颜色分布直方图。图片作者。

上面的直方图暗示峰值出现在~120,这是我们图像中的主要背景色和噪声。从上面的 HSV 颜色空间中,可以注意到绿色在 55–65 附近达到峰值,这也是为什么我们在上面的图中在相同的间隔附近看到一个小峰。因此,我们试图为相似的色调范围创建一个遮罩。

图:钢笔的颜色遮罩(前景)。图片作者。

现在,让我们增加这个二元蒙版中非零像素的色调值。

图 5:我们改变了前景色,但没有改变背景。所有的照明都完好无损。图片作者。

这就是我们如何能够成功地交换图像的颜色,而不操纵背景颜色。

最后,我想提一下在电视和电影中非常流行的 色度键控 方法。这种技术也可以用来交换图像中的颜色。这里的想法是从两个图像开始,一个是安装在绿色或黑色屏幕上的前景,第二个是需要叠加在背景上的图像。方法是首先提取图像中的所有绿色或黑色像素,使这些像素透明,这将使我们能够在背景中覆盖所需的图像。 但是,这种方法要求表面非常光滑,只有很少的光照。

我希望你喜欢颜色交换的想法。我很乐意回答上述任何概念的问题。我想知道任何阅读这篇文章的人的反馈。你可以通过 Linkedin 联系我。

谢谢大家!

特别感谢 Apurva Gupta 对博客的评论。

基于 K-均值的彩色图像量化

原文:https://towardsdatascience.com/colour-image-quantization-using-k-means-636d93887061?source=collection_archive---------19-----------------------

一个关于如何使用 Python 和 OpenCV 减少图像中不同颜色数量的简单教程

Joyce McCown 在 Unsplash 上的照片

颜色量化是一种减少图像颜色数量的过程,同时试图保持图像质量和重要的全局信息。图像由像素组成,在 RGB 颜色空间的情况下,每个像素可以与 16,777,216 种不同的颜色相关联,这可能是最常用的颜色空间。每种颜色都可以表示为一个 3d 矢量,每个矢量元素都有一个 8 位的动态范围,这意味着 2⁸=256 不同的值(即 256x256x256 =16,777,216)。这种表示通常被称为 RGB 三元组。成功的颜色量化的关键因素是适当选择能够充分概括初始图像信息的调色板

动机 : 什么时候应该使用彩色图像量化?

如果我们想要在仅支持有限数量颜色(有限调色板)的设备中渲染图像,彩色图像量化可能是至关重要的,这通常是由于内存限制而发生的。

作为聚类问题的颜色量化

解决图像色度压缩的最常见方法之一是使用聚类,其中特征是图像的颜色。K-means 是一种非常流行的矢量量化聚类方法,多亏了 scikit-learn 库,它真的很容易使用(只要你知道它是如何工作的)。当然,其他聚类方法如奇异值分解、高斯混合模型等。把工作做好。

色彩空间

颜色空间是描述颜色表现方式的数学模型。最简单的方法是想象一个盒子,里面装着所有可能的颜色,这些颜色可以由光的三原色混合而成:红色绿色蓝色、光源。在图 1 中,您可以看到数学家为了将三个轴(红色、绿色和蓝色)拟合为二维格式而绘制的图表:

图 1: CIE 色度图[ 来源

Adobe RGB、sRGB 和 CMYK 都是色域(范围),是 1976 年由国际照明委员会(简称 CIE)定义的 Lab* 色域的子集,旨在作为感知均匀空间,其中给定的数值变化对应于相似的感知颜色变化。我这样说是因为对于 K-means,我们需要一个距离度量来衡量特征之间的相似性。感知上不一致的 RGB 颜色空间意味着具有相同欧几里德距离的两对颜色可能被感知为不相等的不同(由于每种颜色的不同波长以及人眼对如何感知每一种颜色的敏感性)。

键取:应用 K-means 之前,将图像转换为 Lab* 颜色空间。

守则

下面是使用 scikit-learn 库(实现 K-means 方法)和 OpenCV 库进行图像处理的颜色量化代码。

您可以在我的 GitHub 上找到代码(作者图片)

  • 最初,我们期望用户给出两个命令行参数:(1)输入图像的路径,以及(2)集群的数量。
  • 我们加载图像,并将其转换为 Lab*色域。
  • 我们将原始图像重新整形为(高,3* ),因为 k-means 将二维数组而不是三维数组作为输入。
  • 我们用用户决定的 K 个聚类初始化我们的分类器。

注意:我之所以选择使用minibatch kman s是因为它比普通 kman 快得多,尽管与对整个人群进行操作的 kman 相比,它对小批量的 kman 进行操作,质心可能不那么稳定。从迷你批次开始是一个很好的做法,如果结果不太令人满意,您可以尝试使用迷你批次。

  • *clf . fit _ preview(image)*返回每个像素的预测值,即该像素属于哪个聚类。
  • *量化= clf.cluster_centers_。a type(“uint 8”)[labels]*通过将原始图像中的每个像素值重新分配到其对应的最近中心来创建量化图像。
  • 我们将初始和量化的特征向量重新整形为图像,并将其转换为 RGB 色域。
  • 最后,我们将(原始图像和量化图像的)拼接保存到磁盘上。

结果

在这一段中,我将把上述程序的结果应用在一张海报上,这张海报是我从 我的英雄学院维基 借来的我最喜欢的动漫《博库无英雄学院》🎆。

K = 2

图 2:我们的调色板包括两种颜色,黑色和米色(图片由作者提供)

注意:该算法最初从给定数据中随机选择 K 个质心,并在每一步将每个数据点分配给最近的质心。当所有数据点(特征)都被分配给一个质心时,重新计算 K 个聚类的每个平均值,这两个平均值就是新的两个质心。重复该过程,直到没有质心更新(或者至少小于阈值)发生。因此,这两种颜色并不是在初始图像中最频繁出现的颜色(可能会产生误解),但是您可以将它们想象为这两种颜色,这两种颜色是两个聚类的平均值(即中心),并且意味着其他颜色分别与这两个中心的距离总和的最小化

K = 8

图 3:我们的调色板由 8 种颜色组成——可以观察到不同深浅的灰色、红色和黄色(图片由作者提供)

K = 32

图 4:我们的调色板由 32 种颜色和绿色组成(图片由作者提供)

K = 40

图 5:我们的调色板由 40 种颜色组成,我们可以看到它非常接近原始图像(作者的图像)

结论

总之,在这篇文章中,我们看到了几行代码如何对图像进行颜色量化。图 5 显示,由于内存限制,设备仅支持有限数量的颜色(比如 40 种颜色),这种方法可以转换初始图像,但质量不会明显下降,并且重要信息得以保留。

对抗深度学习中的过度拟合

原文:https://towardsdatascience.com/combating-overfitting-in-deep-learning-efb0fdabfccc?source=collection_archive---------21-----------------------

阻止你的深度学习模型过度拟合

在 Unsplash 上由 Waldemar Brandt 拍照

过度拟合问题

过度拟合是指机器学习模型在训练数据上表现良好,但在验证数据上表现糟糕的情况。简单地说,当机器学习模型记住了训练数据中的模式,但未能推广时,这被称为过度拟合。

服装行业就是一个过度合身的真实例子。设计师们试图裁剪他们的尺码,这样一个尺码就能适合各种不同的体型和大小——例如,一个人穿中号可能会显得肌肉发达,而另一个人穿中号就会显得松松垮垮。

如果设计师决定为体型较小的人量身定做尺寸,这种服装就不能适用于各种体型和尺寸。这里你有过度拟合的问题。

解决过拟合问题

情绪分析:预测一条推文是否是关于一场灾难的中,我进行了一些可视化,建立了几个模型,其中我的双向 LSTM 名列前茅。

作者图片

经过仔细检查,我意识到我的模型过度拟合了训练数据。使用强大的模型时可能出现的许多问题之一。

我们可以通过两种主要方式来解决深度学习模型中的过度拟合问题:

  • 对模型的改进
  • 我们数据的改进

我知道你在想什么…我该如何改进我的模型?我如何改进我的数据?这些描述很模糊。所以让我们开始吧。

:本文中用于生成模型的所有代码都可以在 Github 上找到。

**https://github.com/kurtispykes/twitter-sentiment-analysis/blob/master/notebook/03_kpy_data_exploration.ipynb

对模型的改进

简化模型:我们最初建立的模型有 193381 个可训练参数。那是相当高的。随着可训练参数数量的增加,我们的模型更容易记住每个训练实例的标签,这绝对是我们想要的。最初的模型结果是:

  • 训练 F1 分数— 0.9019 (4 标准英尺)
  • 验证 F1 分数— 0.7444 (4 标准偏差)

以及我们模型的总结…

作者图片

我们可以通过减少网络的容量来简化我们的模型,这样我们的模型就别无选择,只能学习给网络带来价值的数据模式,或者用深度学习的术语来说,最小化损失。方法是移除隐藏层。

作者图片

注意:看我是如何在双向 LSTM 后去掉密集层的。

对我的验证数据运行后的结果是:

  • 训练 F1 分数— 0.8362 (4 标准英尺)
  • 验证 F1–0.7622(4 平方英尺)

**正则化:**我们可以解决深度学习模型中过拟合问题的另一种方法是应用正则化。本质上,正则化是添加信息以解决不适定问题或防止过度拟合的过程[ 来源 : 维基百科 ]。

两种流行的正则化技术是 L1 和 L2 正则化。L1 正则化不利于权重的绝对值,这导致一些权重等于 0,而 L2 正则化取所有特征权重的总和,并强制权重较小但不为 0。

吴恩达在 Coursera 上的机器学习课程中完美地解释了这种直觉。

对于我们的例子,我将添加 L2 正则化到我们的初始模型。

作者图片

我们修正模型的结果是:

  • 训练 F1 分数— 0.8899 (4 标准英尺)
  • 验证 F1 分数—07504 (4 标准偏差)

这是对初始模型的一点改进,但我们可以做得更好。

**Dropout Layers:**Dropout Layers 是另一个有效的正则化工具,它的名字非常直观。实际上,丢弃图层会将图层的输出要素随机设置为零。在我们最初的网络中,我们已经有了一些,但我们可以添加更多。

作者图片

向我们的模型添加漏失层的结果:

  • 训练 F1 分数— 0.8205 (4 标准英尺)
  • 验证 F1 分数— 0.7700 (4 标准英尺)

**早停:**早停这个名字也挺直观的。本质上,你提前停止训练过程,而不是训练固定数量的时期。停止训练的队列是当验证误差停止减小并开始上升时。

作者图片

提前停止的结果:

  • 训练 F1 分数— 0.8650 (4 标准英尺)
  • 验证 F1 分数— 0.7525 (4 标准偏差)

数据的改进

**收集更多数据:**当训练样本很少,但特征很多时,模型往往会过拟合。如果资源可用,那么回到绘图板并收集更多数据可能是一个好主意,至少,您希望有比功能更多的训练示例。

**特征选择:**收集数据在时间和资金方面都是一个昂贵的过程,因此,只有当它能显著提高模型的性能时,我才会推荐它。首先,我们需要收集数据的人,然后我们需要标记数据的人。我们可能决定进行特征选择,而不是获取更多的实例。这是我们选择只使用带来最大价值的特性的时候。

包裹

在这篇文章中,我向你介绍了在深度学习模型中对抗过度拟合的各种方法。结果仍然不完美,但大多数时候我们看到我们的模型有所改进。请记住,我是单独执行每一种正则化技术的,因为如果一起执行,我们可以实现一个真正强大的分类器。然而,太多的正则化会导致我们的模型拟合不足,这是一个完全不同的问题。

在 LinkedIn 和 Twitter 上与我联系,了解我关于数据科学、人工智能和自由职业的最新帖子。**

自动驾驶汽车联合学习和主动学习的结合

原文:https://towardsdatascience.com/combination-of-federated-and-active-learning-for-self-driving-cars-14467f8554c?source=collection_archive---------24-----------------------

解决汽车应用中数据隐私和许多其他培训挑战的分布式学习方法

照片由像素的皮克斯拜拍摄

集中式学习是一种在一个地方(通常在云中)训练机器学习模型的方法,使用来自利用该模型的所有设备的聚合训练集。**集中学习的优势在于归纳从所有设备收集的数据,并提供优化的模型。**这种方法带来了以下挑战:

  • 数据隐私:在某些行业或应用中,如医药或金融,数据是敏感的,不能移动到其他位置
  • 有限的网络容量:一些网络属性,如客户端和集中式模型之间的带宽和延迟,会影响训练过程的性能
  • 非独立同分布(独立同分布)数据分布:采集到的数据属于不同的环境、时间、客户端,不满足数据的独立同分布特性,这在大多数统计分析和 ML 算法中被认为是一个必需的假设。
  • 中央存储容量:汽车应用中大量数据带来的高存储要求

联合学习(FL)解决了上面提到的这些集中式学习的挑战或缺点。**联合学习的一个关键特性是保护用户数据。这意味着数据应该位于生成它的位置,而不是移动到另一个位置进行培训。换句话说,算法应该移动到生成数据的地方。**但是,当您有许多客户端要发送大量数据时,另一个方面(如有限的网络容量)也很关键。我们可以用机器学习的模型参数或权重代替记录的原始数据,减少通信开销。

然而,目标是传递机器学习模型参数,而不是需要安全的数据。机器学习的新挑战是定义适当的损失函数,并以分布式方式训练模型,以最终获得收敛且准确的模型。

自动驾驶是 FL 的新应用

自动驾驶汽车的开发需要从各种点收集大量的环境数据,如自我车辆数据、来自道路上另一辆车辆的数据、基础设施传感器数据、地图数据等。分布式数据都可以与由机器学习算法实现的车辆功能相关。当集中学习不可能或不被允许时,联合学习可以提供一种分散的学习方法。作为边缘设备的车辆负责训练本地模型并将其与其他车辆共享,或者中央服务器可以聚集所有模型并创建最终的优化模型,并立即或定期更新所有车辆。

主动学习

主动学习是一种查询用户数据并为算法标注相关数据的学习算法。主动学习通过自动数据标注帮助降低培训成本。**主动学习中最关键的挑战是选择一部分与训练相关的数据。**目的是评估未标记数据的信息价值,并只挑选数据中有信息的部分。我们需要制定一个策略来避免对每个客户的数据有偏见。每个客户端可能有不同的数据量,或者包含特定于环境的数据,这会导致数据偏差。

自动驾驶中机器学习的新方法

本文中描述了一种新的点对点方法 FADNet,这是一种解决集中式学习缺陷的解决方案。**这种方法不需要中心服务器进行训练,每个客户端对其数据进行训练,结果通过一个链中的聚合过程交付给下一个客户端。**这种方法比集中式或基于服务器的联合学习需要更多的计算能力。

本文表明,该方法比基于服务器的联邦学习收敛快得多。学习架构适用于克服非独立数据,管理客户数据之间的巨大差异,并在准确性和收敛能力之间找到一个平衡点。通过可视化来自驾驶场景的三个图像数据集来评估该出版物中提出的模型。

观点

使用此解决方案具有以下优势:

  • 当需要实现最终模型的准确性时,我们至少可以在模型的集中训练之前在本地预先标记数据,这对于分布式数据来说是非常昂贵和具有挑战性的。
  • 我们在本地训练模型,所以车辆总是使用更新和优化的模型。
  • 用户数据的本地存储保证了数据隐私
  • 不需要中央数据存储
  • 降低网络开销
  • 利用车辆的计算能力和真实世界的数据来改进 ML 模型

结合联合和主动学习可以用分布式车辆或基础设施传感器数据来训练模型。这个想法很吸引人,因为每秒钟都会从车辆或基础设施中收集大量数据。

**选择正确的分布式机器学习架构解决了网络性能限制。**需要 V2X(车辆对一切)通信技术来在车辆之间(车辆作为边缘设备)或在汽车和边缘服务器之间交换数据,这取决于所选择的联合学习方法。

**主动学习和联合学习使我们能够进入现实世界的驾驶和停车场景,这些场景并不总是容易通过模拟来验证。**这种方法允许精确的自动驾驶汽车验证,正如特斯拉和 Waymo 可能在多年前开始的那样。这种方法仍然具有挑战性,因为车辆正在运动,收集的数据是有时间标记的,可能很快就会过时。标记数据也很有挑战性,需要自动化的数据标记流程。这种方法减少了标记的时间和成本,并改善了整体 CI/CD 管道和自动驾驶汽车功能的机器学习模型的部署。

组合优化:背包问题

原文:https://towardsdatascience.com/combinatorial-optimization-the-knapsack-problem-9f7047e16028?source=collection_archive---------31-----------------------

将动态规划技术应用于一个有趣的优化问题

作者图片

在这个故事中,我们将讨论动态编程技术在优化算法中的应用。通过开发最佳解决方案的过程,我们可以学习各种编程技术,从而获得更好的性能(最后还有一个惊喜!).

问题描述

背包问题

这个问题被称为背包问题,因为人们在将物品装入背包时会遇到类似的问题,同时试图优化所装物品的重量和价值。

因此,给定一个字符串列表:

r1 = ['001', '11', '01', '10', '1001']

并且给定一个最多可以容纳 5 个 0 和 5 个 1 的容器。

m = 5
n = 5

我可以装入容器的字符串的最大数量是多少?

一个选择是:

c1 = ['001', '1001', '11']

在这种情况下,我们已经包装在 3 个字符串中,并使用了 4 个 0 和 5 个 1,这是我们能做的最好的吗?

事实上,我们可以做得更好:

c2 = ['001', '11', '01', '10']

在这种情况下,我们已经用完了 4 个 0 和 5 个 1,并且我们装入了 4 个字符串。

问题是,我们如何着手系统地解决这个问题?

第一次尝试

只是想完成工作

我们从哪里开始?对我来说,最简单的方法是显而易见的:

循环遍历每个字符串,在循环中,如果可能的话,将当前字符串放入容器中,然后尝试找到在假设当前字符串已经在容器中的情况下可以装入容器的最大剩余字符串数,即使用递归。

def count_dim(string):
    *'''
    Counts the number
    of zeros and ones
    in a string* ***:param*** *string: '00111'* ***:return****: (2, 3)
    '''* m = 0
    n = 0
    for i in string:
        if i == '0':
            m = m + 1
        else:
            n = n + 1

    return m, n

def preprocess_input(strings):
    *'''
    Transforms list of strings
    to tuples of dimensions* ***:param*** *strings: ['100', '011']* ***:return****: [(2, 1), (1, 2)]
    '''* dim_list = [count_dim(string)
                for string in strings]

    return dim_list

def max_subset(input_data, m, n):
    *'''
    Loops through each string,
    recursively try to find the max
    subset of the remaining strings
    and add up the results* ***:param*** *input_data: ['10', '11']* ***:param*** *m: 2* ***:param*** *n: 4* ***:return****: 2
    '''* max_count = 0
    for i, tup in enumerate(input_data):
        if tup[0] <= m and tup[1] <= n:
            new_input = input_data[:i] \
                        + input_data[i+1:]
            max_count = max(max_count,
                            1 + max_subset(new_input,
                                           m - tup[0],
                                           n - tup[1]))

    return max_count

r1 = ['001', '11', '01', '10', '1001']
m = 5
n = 5

r1 = preprocess_input(r1)

print(max_subset(r1, m, n))

# Outputs:
# 4

算法足够简单,但执行起来如何?让我们来看看。

在每次调用 max_subsets 的过程中,它会遍历输入中的字符串数,所以如果我在输入中有 L 个字符串,第一次递归会处理循环 L 次,第二次递归会处理循环 L-1 次,以此类推。因此,算法的复杂性是:

O(L!)(图片由作者提供)

这是你能做的最糟糕的事情了。

第二次尝试

更智能的循环

实际上有一种简单的方法来加速它,而不是一遍又一遍地遍历输入中的每个字符串,我们只遍历一次字符串列表。想想看,这个问题涉及到从字符串列表中挑选出字符串的子集,所以本质上你是在试图寻找最佳的二进制字符串,例如:

r1 = ['001', '11', '01', '10', '1001']
c1 = ['001', '1001', '11']
b1 = 11001

b1 本质上是 c1 作为 r1 子集的表示

所以游戏计划是从第一根弦开始,你有两个选择:保留它或者丢弃它。首先,尽量保持它(1),并递归地找到剩余字符串的最大子集。然后尝试丢弃它(0),并递归查找剩余字符串的最大子集。两个结果中较大的一个是整个输入的最大子集。

def max_subset(input_data, m, n):

    if len(input_data) <= 0:
        return 0

    if m < 0 or n < 0:
        return -1

    tup = input_data[0]
    new_input = input_data[1:]
    max_count = max(max_subset(new_input, m, n),
                    1 + max_subset(new_input,
                                   m - tup[0],
                                   n - tup[1]))

    return max_count

该算法产生相同的结果,但是具有更好的复杂度。在每个“max_subset”调用中,您调用了“max_subset”两次,并且在字符串列表中正好有 L 个字符串,复杂性将是:

O(2^n)(图片来自作者)

好多了,但还是没那么好…

记忆增强

用空间换时间

当前形式的算法仍有许多冗余,例如:

r1 = ['001', '11', '01', '10', '1001']
b1 = 1001?
b2 = 1010?

当您到达字符串“1001”时,您可能会采用几种不同的路径,其中两种是:1001 和 1010,或者['001 ',' 10' ]和['001 ',' 01']。

两条路径剩余的 0 和 1 的数量完全相同:(2,3)。所以一旦你到达步骤‘1001’所需要的计算是相同的,并且它被做两次,并且当问题变大的时候潜在地更多次。

使用备忘录来保存已经计算过的结果将是一个加快这个过程的好方法。

在这种情况下,我们需要一个索引为(I,j,k)的映射,其中“I”是字符串列表中的当前位置,“j”是剩余的 0 的数量,“k”是剩余的 1 的数量。

def max_subset(input_data, m, n, memo={}):

    if len(input_data) <= 0:
        return 0

    if m < 0 or n < 0:
        return -1

    if (len(input_data), m, n) in memo:
        return memo[(len(input_data), m, n)]

    tup = input_data[0]
    new_input = input_data[1:]
    max_count = max(max_subset(new_input, m, n, memo),
                    1 + max_subset(new_input,
                                   m - tup[0],
                                   n - tup[1],
                                   memo))

    memo[(len(input_data), m, n)] = max_count
    return max_count

这个算法表现如何?嗯,由于 memo 中的每个元素只计算一次,字符串的长度为 L,所以 0 的个数为 M,1 的个数为 n,算法的时间复杂度为:

O(LMN)(图片由作者提供)

由于 memo 中的每个(I,j,k)都可能有一个条目,所以空间复杂度也是 O(LMN)。

动态规划

让算法变得更好

你会问,我们能进一步改进算法吗?

事实上,有一个非常聪明的方法可以降低算法的空间复杂度,那就是使用动态规划算法。

想象你在输入字符串列表的第三个元素:“01”。

你问自己这个问题,如果字符串列表从开始到‘01’,我需要知道什么才能算出我可以装入容器的最大子集,即:

'001', '11', '01'

?

好吧,如果我知道给定 4 个 0 和 4 个 1 容器,我可以用“001”、“11”构造的最大子集,以及给定 5 个 0 和 5 个 1 容器,我可以用它们构造的最大子集,那么给定 5 个 0 和 5 个 1,我可以用“001”、“11”、“01”构造的最大子集是:

max_subset(['001', '11', '01'], 5, 5) = \
    max(max_subset(['001', '11'], 5, 5),     # without '01'
        1 + max_subset(['001', '11'], 4, 4)) # with '01'

这种关系构成了我们将要创建的动态编程算法的基础。

我们可以做的是有一个大小为(m+1,n+1)的备忘录地图,最初,它都用零填充。

当我们开始处理第一个字符串“001”时,我们尝试从(5,5)开始更新映射:

max_subset(['001'], 5, 5) = \
    max(max_subset([], 5, 5),
        1 + max_subset([], 3, 4))

然后(5,4),(5,3) …,(4,5),(4,4),…,直到(2,1),因为‘001’有 2 个 0 和 1 个 1,所以我们不能再减少容器的维数了。

我们有了更新后的地图,如下图所示:

(图片由作者提供)

现在,映射中的每个位置都表示给定字符串列表['001']和容器(m,n)的最大子集。

对字符串列表中的剩余字符串重复这个过程,最终的 memo map,在位置(5,5)将包含我们问题的答案。

def init_memo(m, n):
    return [[0 for i in range(n + 1)] for j in range(m + 1)]

def update_memo(z, o, m, n, memo):

    for i in reversed(range(z, m + 1)):
        for j in reversed(range(o, n + 1)):
            memo[i][j] = max(1 + memo[i - z][j - o],
                             memo[i][j])

def max_subset(input_data, m, n, memo=None):

    if memo is None:
        memo = init_memo(m, n)

    if len(input_data) <= 0:
        return memo[m][n]

    current = input_data[0]
    input_data = input_data[1:]

    update_memo(current[0], current[1], m, n, memo)

    return max_subset(input_data, m, n, memo)

我们来看看这个算法的性能。由于我们遍历每个字符串一次,并且在每次迭代期间,我们更新大小为 M*N 的备忘录映射,因此时间复杂度为:

O(LMN)(图片由作者提供)

和以前一样。

但是因为我们只使用大小为 M*N 的地图,所以空间复杂度是:

O(M*N)(图片由作者提供)

我们将空间复杂度降低了 1 倍!

你会问,有什么问题?为什么现在需要的备忘录地图的大小减少到 O(MN)?这与地图的“动态”本质有关。想想看,在每次迭代期间,您都在用新信息更新存储在映射中的值,以考虑到添加的字符串,因此您丢弃了不再需要的旧信息,从而将映射的空间需求从 O(LMN)减少到 O(MN)。

结论

老实说,我第一次尝试这个问题的时候,我认为我们对时间和空间复杂度的最佳结果是 O(LMN),但是一个非常聪明的观察帮助我们大大降低了空间复杂度。因此,感谢动态编程,我们能够了解对算法进行改进的可能性,而这种改进并不明显。它还提醒我们,无论问题是什么,都要对新的或更好的解决方案保持开放的心态。

使用 Apache Flink 组合和预处理您的异构数据以进行分析

原文:https://towardsdatascience.com/combine-and-preprocess-your-heterogeneous-data-for-analytics-with-apache-flink-518a66425850?source=collection_archive---------17-----------------------

作者图片

通过使用该架构在一个地方清理和合并您的实时和历史数据,使您作为数据科学家的生活更加轻松。忘记访问多个系统和清理日常分析任务。

介绍

数据驱动的决策和应用是未来业务的核心。从数据中获得洞察力意味着成本降低、效率提高和战略优势。越来越多的公司通过应用以数据为中心的架构,在数据库中生成和收集除经典批量数据之外的流数据或实时数据。因此,公司面临的挑战是在分析中处理流数据和批量数据,以获得整体和最新的见解。

流数据和批处理数据必须先合并,然后才能作为组合数据集进行可视化和处理。本文描述了一个基于 Apache Flink 和 Lambda 架构的 Lambda 架构的实现,以解决这一挑战。Apache Flink 是一个计算无界和有界数据流的框架。Flink 在不同的抽象层次提供了多个 API,并为不同的用例提供了专用的库。为了更具体,我将在整篇文章中使用一个端到端的例子。

出发点

我们使用包含空气测量站的事件数据的数据集。在这组数据中,我们发现了九个传感器对空气中不同物质的每小时测量值。除此之外,还记录了日期、时间、温度和空气湿度。数据集由 De Vito 等人发表在 UCI 机器学习知识库上。

我们在哪里?

我们假设,作为物联网设备的测量站每小时将数据发布到 Apache Kafka 主题中,我们可以在其中使用这些数据。数据在被删除之前会在 Apache Kafka 主题中保留一段固定的时间。因为我们不想丢失这些历史数据,所以我们定期将它存储在一个持久数据库中,以便随时进一步处理数据。这两个系统构建了我们的混合数据存储架构。

作为数据科学家,我们希望访问所有数据——来自 Kafka 的实时数据和来自数据库的历史数据——以便实时访问所有数据和进行全面分析。通常我们必须用不同的访问方法查询两个系统,这既不方便,也不可扩展,也不容易维护。

我们想去哪里?

这就是为什么我们需要一个来自 Kafka 和数据库甚至更多系统的数据的组合视图,我们只需要访问一个系统就可以一次获得从历史到最近数据点的所有数据。因为它是使用最广泛的技术,我们希望使用数据库作为所有数据的一站式商店。

流数据和批处理数据在模式、数据类型、相同情况的表示以及最终的数据质量方面可能有所不同。所以,数据需要标准化。此外,作为数据科学家,我们还希望通过自动清理原始数据来摆脱日常工作。

λ架构

我们展示的系统基于 Lambda 架构,由 Nathan Marz 于 2011 年首次推出。简而言之,Lambda 架构包含三个相关层。批处理层处理来自数据库或数据湖的所有批处理数据。速度层实时处理所有流数据。因此,可以以最小的延迟访问新数据。服务层是最后一个组件,负责合并来自其他两个层的清理数据,并将其提供给其他应用程序。通常,专用(例如 Java 或 Python)应用程序用于从两层加载数据,并在服务层以标准化的形式将数据汇集在一起。使用 Flink,标准化已经在速度和批次层完成。如果你想更详细地了解 Lambda 架构,我推荐这篇文章。

Lambda 架构的示意图。作者图片

架构概述

提议的系统基于 Lambda 架构,但通过巧妙使用现代技术解决了它的一些主要弱点。我们主要使用两种工具。第一个是阿帕奇弗林克。Flink 是一个能够处理流数据和实时数据的框架。因此,它非常适合这个用例。我们使用 Flink 的连接器实时消费来自给定 Kafka 主题的消息,或者通过 JDBC 连接从数据库中读取历史数据。速度图层有一个 Flink 作业,批处理图层有另一个 Flink 作业。它们只是在数据接收方面有所不同。对于一个用例,处理和输出部分是完全相同的。我们将在后面的示例中查看数据处理。Flink 可以将数据输出到各种数据接收器。对于我们的系统,我们使用 Apache Cassandra 数据库,因为它针对繁重的编写工作负载进行了优化。

建议的数据准备系统的架构。作者图片

利益

你可以在这里阅读关于 Apache Flink 的精彩介绍。我们声明我们想要标准化和准备数据。

使用 Flink,我们可以使用相同的代码来处理批量数据和流数据,因为 Flink 将批量数据作为有限的数据消息流来处理。

这是一个独特的卖点,有利于 Flink 反对类似的选项,如 Spark 或 Storm。此外,Flink 为复杂的转换提供了很大的灵活性,因为我们可以使用 Java、Python 甚至 SQL 来处理数据。Apache Flink 由多个组件构建而成,其中每个组件都包含针对不同数据结构(数据流与表)或特定应用需求(机器学习)的特定功能。

示例:准备数据

在探索性的数据分析过程中(本文跳过了这一步),我们意识到
时间和日期的格式不正确
有许多错误值,我们应该以某种方式修复它们
已知的错误值是“-200.0”
其中一个属性(NMHC(GT))有太多的错误值,我们需要删除整个列

为了准备和合并数据,我们遵循以下路径:在下图中,您可以看到我们有两条管道,一条用于流数据,一条用于批处理层。本文的以下部分分为“加载数据”,在这里我们将使用卡夫卡和 JDBC 连接器。然后“处理数据”,在这里我们使用“映射”和“过滤”功能,甚至窗口功能来清理和标准化数据。这个管道的最后一步当然是“合并和提供”数据。Flink 将处理后的数据交付给数据库,在那里进行合并和存储以备将来使用。

在这个用例中,Kafka 中的所有数据都是通过 Apache Avro 模式定义的。Avro 就像节俭或协议缓冲区。Avro 作为一个序列化系统被用在许多生产环境中,因为序列化的数据更小。Avro 具有丰富的数据结构,提高了传输和处理效率。

转换在批处理和速度层中流动。作者图片

加载数据

让我们从导入数据开始。我们在速度层的 Flink 作业中建立了一个 Kafka 消费者。我们需要提供主题名、Kafka 节点的地址和一些连接属性,比如模式注册 URL。我将消费者和生产者代码转移到一个专用的 java 类( KafkaConnection ),这样我们就可以在更多的工作中轻松使用它。

public class KafkaConnection {
    public static <avroSchema> FlinkKafkaConsumer010
    getKafkaConsumer(Class avroSchemaClass, String inTopic, String
    schemaRegistryUrl, Properties properties) {
        FlinkKafkaConsumer010<avroSchema> kafkaConsumer = new
        FlinkKafkaConsumer010<avroSchema>(
            inTopic,
            (DeserializationSchema<avroSchema>)
            ConfluentRegistryAvroDeserializationSchema.forSpecific(
                avroSchemaClass, schemaRegistryUrl),
            properties);
        kafkaConsumer.setStartFromLatest();
        return kafkaConsumer;
    }
}

这个 Kafka 消费者将 Avro 模式 AirQuality_value 中定义的收集到的消息发送到数据流中。该使用者在 Flink 作业中构建数据流的源。

// Initialize KafkaConsumer
FlinkKafkaConsumer010 kafkaConsumer = KafkaConnection.getKafkaConsumer(AirQuality_value.class, 
    inTopic, 
    schemaRegistryUrl, 
    $properties);// Set KafkaConsumer as source
DataStream<AirQuality_value> inputStream = environment.addSource(kafkaConsumer);

为了读取 PostgreSQL 数据库,我们定义了一个 JDBC 连接器。因此,我们使用 Flink 的 JDBC 连接器包的 JdbcInputFormatBuilder ,并传递必要的参数,如下所示。因此,我们创建了一个带有模式的数据流。

JdbcInputFormat.JdbcInputFormatBuilder inputBuilder = JDBCConnection.getSource($fieldTypes,
    $driverName,
    $dbURL,
    $sourceDB,
    $selectQuery,
    $dbUser,
    $dbPassword);DataStream<Row> inputStream = environment.createInput(inputBuilder.finish());

在我们可以在两层中平等地转换数据之前,我们需要将速度层中的数据从 Avro 模式转换为更通用的模式。你会在上图中看到这一步是速度层的第一个动作。然后,批处理和速度层中的数据流具有相同的内部格式,我们可以用相同的方式转换它们。

转换数据

我们通过应用模块化转换器来转换数据,每个转换器执行一个特定的操作。我们设置了转换器,用于从流中过滤消息,其他的操作值,改变单一数据类型或者删除属性。此外,还有窗口和 SQL 转换,例如删除重复的。我们将这些转换器实现为 java 类,让我们通过提供一些参数来调整确切的行为。它们被设计为由数据流的过滤器()、*映射()窗口()*函数调用。当然,这些变压器是基本的,但我们可以将它们堆叠起来,构建强大的转换管道。

为了处理空气质量数据,我们首先通过 FeatureAggregation() 将“日期”和“时间”属性(在索引 0 和 1 处)连接成一个属性。然后,我们在第二行将结果字符串转换为 SQL 就绪的时间戳。接下来,我们删除原来的日期和时间属性,因为不再需要它们了。此外,我们删除了 NMHC(GT)属性,它有太多的错误,不能通过调用feature selectiontransformer 来清除。转换器只保留新的时间戳属性和除 NMHC(GT)之外的所有属性。

DataStream<Row> timestampStream = inputstream
    .map(new FeatureAggregation(0, 1, "+"))
    .map(new StringToDate(14, "dd/MM/yyyy HH.mm.ss"))
    .map(new FeatureSelection($keptAttributes);

现在它变得稍微高级一些:我们使用一个窗口函数,用在一个时间窗口内计算的平均值来代替误差值(-200.0)。您可能知道 SQL 中的这种方法是“ OVER ”子句与“ROWS before”的组合。我们将这个转换器应用于包含传感器数据的所有属性。之前,我们需要创建窗口,这样数据流中的消息就可以拆分到不同的窗口上。像在 SQL 中一样,我们需要一个键来控制窗口分割。我们将窗口的“大小”定义为 20 秒:使用这种配置,来自同一天的、在 20 秒内到达的所有消息都将被路由到同一个窗口。对于每个属性,计算一个平均值来代替所有的误差值。

DataStream<Row> windowedStream = timestampStream
    .keyBy(new DateAsKey())
    .window(EventTimeSessionWindows.withGap(Time.seconds(20)))
    .process(new ReplaceMultipleByAverage(replace_fields,"==",
        -200.0f));

不幸的是,这不足以完全清除数据。一些属性包含如此多的错误,以至于当前窗口中计算的平均值也被错误值破坏。因此,我们需要从数据流中过滤出所有剩余的有错误的消息。

DataStream<Row> outputStream = windowedStream.filter(
    new RemoveErrorValues(0,"==", -200.0f));for (int i = 1; i < outputStream.getType().length(); i++) {
    outputStream.filter(new RemoveErrorValues(i,"==", -200.0f));
}

我们通过在一个循环中多次应用过滤函数来检查所有字段。最后,数据可以写入数据库,并在以后的应用程序中使用。

合并并提供数据

剩下的唯一事情就是将数据写到数据库中。将它写入服务层会同时合并流数据和批处理数据:通过将它写入一个表来合并。我们使用下面的 Cassandra 接收器将处理过的流输出到同一个 Cassandra 表。但是你也可以使用 JDBC 水槽。

CassandraSink.addSink(outputStream)
    .setClusterBuilder(
        new ClusterBuilder() {
            @Override
            public Cluster buildCluster(Cluster.Builder builder) {
                Cluster cluster = null;
                try {
                    cluster = builder.addContactPoint(cassandraURL)
                        .withPort(cassandaPort)
                        .withCredentials(
                            cassandraUser,
                            cassandraPassword)
                        .build();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return cluster;
            }
        }
    )
    .setQuery(insertQuery)
    .build();

insertQuery 只是一个普通的 SQL“Insert…”查询。重要的是要理解批处理层只写历史数据,而速度层应该在当前的时候已经写了。因此,批处理图层会覆盖速度图层中的数据,因为它更加准确和可信。您需要确保 speed 层不会插入任何带有现有主键的数据,而 batch 层必须能够覆盖带有相同主键的现有行。这可以通过配置表中的主键约束并为每个作业定义违反约束时的操作来实现。使用这种策略,我们只需要一个标准表,不需要合并服务。数据按主键排序,没有任何冲突或重复。所有想要使用预处理数据的服务都可以通过传统方法(连接器、REST APIs 等)访问 DBMS。).

结论

本文解释了如何只用四种工具和一些可重用的 java 代码来处理实时和历史数据。

您不需要复杂的管道,就可以拥有一个可扩展的安全解决方案来清理和处理您的原始数据,并将其用于您的分析。

简而言之,将 Kafka 主题用于实时事件数据,将您选择的持久性数据存储用于历史数据,将 Apache Flink 用于处理,并将输出数据存储在某个地方,直到您对其进行分析。该体系结构将帮助您更快地从数据中获得价值,并有效地实施数据清理和准备。

声明:我在惠普公司和【Bernd Bachmann 博士的支持下完成了我的学士论文。

结合 MS Excel 和 Python 的优点

原文:https://towardsdatascience.com/combine-the-best-of-ms-excel-and-python-c85cad9fdc3b?source=collection_archive---------13-----------------------

您还不需要(也不应该)完全逃离 Excel

尼克·里克特在 Unsplash 上的照片

你听说过 Python 是新的 Excel 吗?老实说,我已经读过好几遍了。

那么,为什么我看到很多人还在用 Excel 呢?

首先,这两个工具的目的不同,其次,Excel 本身就很强大(如果不是这样,它不会流行这么多年)。

然而,编程语言每年都变得越来越流行,有些人,比如你和我,对验证已知的活动如何以不同的方式处理感兴趣,当然,也很容易。

这是这篇文章的一个关键方面。有一种 MS Office 原生编程语言叫做 VBA (Visual Basic for Applications)。尽管你可能不知道,但你可能已经用过了。为什么使用所谓的宏。

长话短说,VBA 是一种由微软开发的编程语言,它是如何配置宏,一堆定义好的命令。这是故事变得有趣的时刻。Python 最著名的用例之一是自动化多种类型的任务,包括但不限于 Excel 用例。然而,这类问题不是已经被 VBA 解决了吗?请记住,我们在这里是为了做得更好,做得与众不同。此外,很多宏都是由不知道如何改变或适应它们的人使用的。他们只是在那里呆了几年…

宏已经被使用的事实对你来说可能是一个很大的障碍,主要原因是的便利性。为什么?我注意到的原因是:

  1. 人们习惯于点击宏按钮,这对他们来说已经足够了。他们只是希望工作完成(而且这是公平的,有道理的);
  2. 有些人就是不愿意学习一门(新的)编程语言。

如上所述,举例来说,很难将您设法开发的 Python 脚本的唯一用途分散到整个组织中。你需要让人们能够使用 Excel 和宏,就这样。这样,他们感觉很舒服,你可能会以某种方式继续练习。

为什么要这么做?

尤其是如果你刚刚开始用 Python 运行一些程序,很可能你正在寻找真正的使用问题来解决,有时,这可能不太容易预先找到。

最重要的是尽可能多的坚持练习。今天你们要学习这个例子,我将要展示给你们,但是你们不应该就此打住。

如前所述,Python 是过去几年中发展最快的编程语言之一,这并非毫无意义。它的易用性和大量的库吸引了全球数百万程序员的注意,这是它如此受欢迎的关键。

怎么做?

那么,还记得那位同事抱怨他们需要每天准备并发送给经理的无聊报告吗?我可以肯定地告诉你,使用 Python 可以帮助他们实现这一点,如果你的同事想了解 Python,他们不需要了解任何东西,相信我。

对于解决这个问题可能存在的宏呢?嗯,如前所述,继续允许人们使用宏是很重要的。然而,这不会是他们所习惯的宏,他们只是不知道他们正在使用 Python

我们将使用以下内容:

  1. VBA 和壳牌
  2. Python 文件
  3. 表单控件按钮

我们去看看。

1.VBA 和壳牌

别生我的气,但我会让你用一点 VBA。这只是一种设置让我们能够提前使用 Python 所需的变通方法的方式。

打开您将在本练习中使用的 excel 文件。我将使用以下代码:

C:\Users\Desktop\python test\main_file.xlsm

一旦你打开它,键入 F11,然后 VBA 图形用户界面将打开。它应该类似于下图:

如果没有可用的模块,只需点击顶部菜单中的“插入”,然后点击“模块”。好了,让我们来看看代码本身:

很简单。我们来分析一下以上最重要的几个方面。

需要使用命令“Dim”来声明变量。所以我们宣布:

  1. Python 解释器路径(“python_exe”)
  2. Python 脚本路径(“python_py”)。 Chr(34)可能需要,如果你的路径包含空格,像我一样。
  3. 当前目录路径(“目录路径”)

声明这些变量后,需要使用一个外壳函数。简单地说,适用于我们场景的这个 Shell 函数的基本语法是:

program_to_excute file_to_execute command_line_argument

它非常类似于在 Linux 发行版中使用的 Windows Powershell 和 Bash 中用于 shell 脚本的语法(或任何其他 Shell)。

看看下面的故事,我探索了 Linux 中基本 Shell 脚本的一些功能。

https://levelup.gitconnected.com/python-and-linux-i-o-redirection-for-managing-investments-ef009be30f39

从这个意义上说,我们已经设置了 Python 解释器来执行 Python 文件,并且我们正在设置一个将在 Python 文件中使用的参数。向前移动…

2.Python 文件

最后,万能的 Python 文件。

让我们强调一下你为什么真的喜欢使用 Python 的更详细的原因。Python 在过去几年变得如此流行肯定有几个原因。当然,其中之一是它的多功能性。尽管对于某些领域来说,这最终会成为一个缺点(因为它会使脚本变慢)。由于我们不是在谈论实时用例,它真的不会对我们产生负面影响。

其多功能性主要是由于三个原因:

  1. 解释语言。可以交互地运行脚本的每一行(它不是一种编译语言)。这甚至导致实时敏感性案例使用 Python 来构建他们的应用程序原型,因为这比一些常见的替代方法更简单。
  2. 动态类型语言。与 VBA 和其他语言不同,你不需要显式声明你将在程序中使用的变量类型。内存是在给每个变量赋值时分配的。
  3. 大型社区。有大量的图书馆可供使用。很有可能你想要达到的目标已经被别人完成了。在真正尝试之前,花时间去寻找它。

好了,评论完了,让我们看看剧本。它分为两部分:

  1. Windows API
  2. 数据操作

下面,让我带你看一下每一个。

1.Windows API

这里提到的 API 可以通过包 pywin32 获得。它允许我们从另一个应用程序控制 Windows 应用程序。在这种情况下,来自 Python 脚本。

请记住,这个图书馆里的物品很像 VBA 本身。

让我们看看 Python 脚本的第一部分:

向前发展…

2.数据操作

当然,从这里开始,这真的取决于你的情况。我们将探索一些使用 Python 可以轻松实现的常见需求。

我会考虑一个来自 Kaggle 的数据库,葡萄酒评论。更具体地说,该文件命名为“winemag-data-130k-v2.json”。

假设您同事的日常活动是共享类似数据透视表的报表,该报表包含以下行层次结构:

variety; region_1; region_2; province; taster_name

随后是每种情况的“点数”。

您可能会注意到这个数据库中有一些空值。此外,您不确定他们需要在报告中使用的字段(或列)是否会受到任何空案例的影响。从这个意义上说,根据每一列的数据类型填充空值是明智的。

这就是即使在 Excel 中使用 Python 而不是 VBA 的主要优势之一。你能想象在不借助熊猫的情况下如何做到以上几点吗?

让我们来看看实现这一点的代码。

通过执行上述操作,您的同事可以确保所有被标识为包含空值的列都填充了正确的值。

现在,是时候生成所需的数据透视表了,因为这是该领域的每个人用来管理、探索以及采取适当行动的方式。

您是否注意到“主”Excel 文件正在更新,现在它显示了数据透视表?

文章结果的屏幕截图(数据继续显示在右侧和底部)

你应该得到了类似上面的东西。

结论

您设法处理了与一个已知用例相关的多个文件(json 和 Excel 文件),您可以在日常工作中使用 Python 脚本轻松处理这些文件。

案例结构

通过利用 Python 的多功能性,您使用一个非常强大的名为 pandas 的库来操作数据源中包含的数据。除此之外,请记住,还有许多其他流行的库可以用于 web 应用程序、机器学习和可视化用例。

最重要的是:你要让用户保持他们通常的工作方式。希望你(不小心)成功唤醒用户开始学习 Python。

如何在熊猫中组合两个字符串列

原文:https://towardsdatascience.com/combine-two-string-columns-pandas-fde0287485d9?source=collection_archive---------4-----------------------

了解如何在 pandas 数据框架中更有效地将两个字符串列连接成一个新列

帕斯卡·米勒在 Unsplash 上拍摄的照片

介绍

通过连接其他列来创建新列是一项相当常见的任务。在今天的简短指南中,我们将展示如何将 string DataFrame 列的内容连接成一个新列。我们将探讨几个不同的选项,您应该始终根据您正在处理的数据集大小来考虑这些选项。

这些方法中的一些在应用于小数据集时往往更有效,而其他方法在应用于大数据集时可能执行得更快。

此外,我们还将探索如何将字符串与非字符串(例如整数)列连接起来。

首先,让我们创建一个示例数据框架,我们将在本文中引用它来演示一些概念。

import pandas as pddf = pd.DataFrame(
  [
    (1, '2017', 10, 'Q1'),
    (2, '2017', 20, 'Q2'),
    (3, '2016', 35, 'Q4'),
    (4, '2019', 25, 'Q2'),
    (5, '2020', 44, 'Q3'),
    (6, '2021', 51, 'Q3'),
  ], 
  columns=['colA', 'colB', 'colC', 'colD']
)print(df)
 *colA  colB  colC colD
0     1  2017    10   Q1
1     2  2017    20   Q2
2     3  2016    35   Q4
3     4  2019    25   Q2
4     5  2020    44   Q3
5     6  2021    51   Q3*

在小型数据集中串联字符串列

对于相对较小的数据集(最多 100–150 行),您可以使用[pandas.Series.str.cat()](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.cat.html)方法,该方法用于使用指定的分隔符(默认情况下分隔符设置为'')连接序列中的字符串。

例如,如果我们想将列colBcolD连接起来,然后将输出存储到一个名为colE的新列中,下面的语句就可以做到:

**df['colE'] = df.colB.str.cat(df.colD)** print(df)
 *colA  colB  colC colD* ***colE*** *0     1  2017    10   Q1* ***2017Q1*** *1     2  2017    20   Q2* ***2017Q2*** *2     3  2016    35   Q4* ***2016Q4*** *3     4  2019    25   Q2* ***2019Q2*** *4     5  2020    44   Q3* ***2020Q3*** *5     6  2021    51   Q3* ***2021Q3***

现在,如果我们想要指定一个将被放置在连接的列之间的分隔符,那么我们只需要传递sep参数:

**df['colE'] = df.colB.str.cat(df.colD, sep='-')**print(df)
 *colA  colB  colC colD* ***colE*** *0     1  2017    10   Q1* ***2017-Q1*** *1     2  2017    20   Q2* ***2017-Q2*** *2     3  2016    35   Q4* ***2016-Q4*** *3     4  2019    25   Q2* ***2019-Q2*** *4     5  2020    44   Q3* ***2020-Q3*** *5     6  2021    51   Q3* ***2021-Q3***

或者,你也可以使用列表理解,这种理解稍微有点冗长,但速度稍快:

**df['colE'] =** **[''.join(i) for i in zip(df['colB'], df['colD'])]**print(df)
 *colA  colB  colC colD* ***colE*** *0     1  2017    10   Q1* ***2017Q1*** *1     2  2017    20   Q2* ***2017Q2*** *2     3  2016    35   Q4* ***2016Q4*** *3     4  2019    25   Q2* ***2019Q2*** *4     5  2020    44   Q3* ***2020Q3*** *5     6  2021    51   Q3* ***2021Q3***

在较大的数据集中串联字符串列

现在,如果您正在处理大型数据集,连接两列的更有效方法是使用+操作符。

**df['colE'] = df['colB'] + df['colD']**print(df)
 *colA  colB  colC colD* ***colE*** *0     1  2017    10   Q1* ***2017Q1*** *1     2  2017    20   Q2* ***2017Q2*** *2     3  2016    35   Q4* ***2016Q4*** *3     4  2019    25   Q2* ***2019Q2*** *4     5  2020    44   Q3* ***2020Q3*** *5     6  2021    51   Q3* ***2021Q3***

如果您想要包含分隔符,只需将其作为字符串放在两列之间即可:

**df['colE'] = df['colB'] + '-' + df['colD']**

连接字符串和非字符串列

现在让我们假设您尝试连接的列之一不是字符串格式:

import pandas as pddf = pd.DataFrame(
  [
    (1, **2017**, 10, **'Q1'**),
    (2, **2017**, 20, **'Q2'**),
    (3, **2016**, 35, **'Q4'**),
    (4, **2019**, 25, **'Q2'**),
    (5, **2020**, 44, **'Q3'**),
    (6, **2021**, 51, **'Q3'**),
  ], 
  columns=['colA', 'colB', 'colC', 'colD']
)print(df.dtypes)*colA     int64
colB     int64
colC     int64
colD    object
dtype: object*

在这种情况下,您可以简单地使用[pandas.DataFrame.astype()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html)map()方法来转换列。

# Option 1
**df['colE'] = df.colB.astype(str).str.cat(df.colD)**# Option 2
**df['colE'] = df['colB'].astype(str) + '-' + df['colD']**# Option 3
**df['colE'] =** **[
  ''.join(i) for i in zip(df['colB'].map(str), df['colD'])
]**

最后的想法

在今天的简短指南中,我们讨论了在 pandas 数据帧中连接字符串列。根据您正在使用的数据集的大小,您可能需要选择执行效率更高的最合适的方法。

此外,我们还展示了如何利用 pandas 中的astype()方法连接字符串和非字符串列。

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

https://gmyrianthous.medium.com/membership

你可能也会喜欢

[## 如何将 Python 包上传到 PyPI

towardsdatascience.com](/how-to-upload-your-python-package-to-pypi-de1b363a1b3)

把你的机器学习模型和投票结合起来

原文:https://towardsdatascience.com/combine-your-machine-learning-models-with-voting-fa1b42790d84?source=collection_archive---------1-----------------------

利用被低估的集合方法获得更好预测性能的指南

照片由来自 Pexels 的 Tara Winstead 拍摄

当你冒险踏上机器学习之旅时,你无疑会遇到各种各样的机器学习算法。

从像 K-最近邻这样的懒惰学习分类器到像决策树这样的急切学习分类器,在构建模型时有许多不同的算法可供选择。

你有没有想过让这些模型协同工作会是什么样子?幸运的是,这可以通过一种叫做投票的技术轻松实现。

投票是一种集合方法,它将多个模型的性能结合起来进行预测。

你可能会想:首先把模型的预测结合起来有什么意义呢?当您可以单独评估分类器并选择最佳分类器时,为什么要将所有分类器合并为一个呢?

投票的好处

合并投票有很多好处。

首先,由于投票依赖于许多模型的性能,它们不会被来自一个模型的大误差或错误分类所阻碍。一款车型的不佳表现可以被其他车型的强劲表现所抵消。

为了更好地理解这个概念,我们用投资来打个比方。

当你投资时,人们经常建议你将财富分配到各种股票上。如果你把所有的钱都放在一只股票上,你的整个投资组合都依赖于这只股票的表现,这让你面临很高的风险。另一方面,如果你把钱投资于各种股票,风险就会降低;一只表现不佳的股票不会阻碍你的成功。

投票以类似的方式进行。通过组合模型来进行预测,您可以利用其他可以做出正确预测的模型来降低一个模型做出不准确预测的风险。这种方法使得估计器更加稳健,并且易于过拟合。

在分类问题中,投票有两种:硬投票软投票

硬投票需要挑选具有最高票数的预测,而软投票需要组合每个模型中每个预测的概率,并挑选具有最高总概率的预测。

回归问题中的投票有些不同。通过投票构建的回归模型不是查找出现频率最高的预测,而是获取每个模型的预测,并计算它们的平均值以得出最终预测。

在分类或回归问题中,投票是提高预测性能的一种手段。

投票的缺点

当你了解到组合模型的好处时,你可能会在你未来的所有机器学习项目中使用投票。

毕竟,当您可以将它们全部集成到一个评估器中并创建“完美的模型”时,为什么要经历考虑每个模型的优缺点的麻烦呢?

不幸的是,这种思路是有缺陷的。

要明白,用投票建立的模型不应该被视为机器学习中一刀切的方法。毕竟,投票集成方法也有其局限性。

首先,在某些情况下,单个模型可以胜过一组模型。例如,在回归问题中,如果预测特征和目标变量具有很强的线性关系,单个线性回归模型无疑可以表现得很好。但是,用其他回归模型做出的投票估计会使线性回归模型的准确预测无效。

其次,由于投票需要使用多种模型,因此它们的计算量自然更大。因此,创建、培训和部署这样的模型将更加昂贵。

最后,只有当机器学习分类器在相似的水平上执行时,投票才是有益的。从具有相反效率水平的模型构建的投票估计器可能不稳定地运行。

Python 中的应用

Python 中的 sklearn 包使得实现投票集成方法变得非常容易。它提供了投票分类器和投票回归器,这两个估计器分别用于构建分类模型和回归模型。

您可以使用以下代码导入它们:

由作者创建

让我们利用 sklearn 库来看看投票集合方法的效果。

个案研究

有了医院患者的数据集(此处可访问),让我们创建单独的机器学习分类器和投票分类器,以确定哪种方法最好地预测心脏病。

以下是数据集要素的预览:

由作者创建

代码输出(由作者创建)

本案例研究的目标变量是“心脏病”。

让我们在建模之前准备数据集。预处理阶段需要:

  • 删除丢失的值(如果有)
  • 编码分类特征
  • 将数据分成训练集和测试集
  • 标准化输入要素

接下来,我们用训练集训练决策树模型、逻辑回归模型和朴素贝叶斯模型,然后用测试集评估它们。这些模型的性能将根据它们的 f-1 分数来衡量。

代码输出(由作者创建)

如输出所示,支持向量机是表现最好的模型,f-1 得分为 0.8897。

请注意 3 个分类器的 f-1 分数是多么相似。这是投票估计器将适用于预测心脏病的指标。

让我们创建一个分类器,将决策树分类器、逻辑回归模型以及朴素贝叶斯模型合并为一个分类器。通过给分类器中的“投票”参数赋值,可以在硬投票和软投票之间进行选择。为了便于演示,我们将使用这两种投票技术。

代码输出(由作者创建)

由硬投票和软投票构成的投票分类器的性能都优于支持向量机。

结论

照片由来自 Pexels 的 Prateek Katyal 拍摄

现在,你了解了投票的来龙去脉,以及它在机器学习中的应用。

结合机器学习模型可以显著提高预测建模的质量。

然而,即使这种集合方法在构建模型时可以作为一种很好的选择,您也不应该将其视为一种可行的方法,因为它的成本更高,而且并不总是胜过单个模型。

我祝你在机器学习的努力中好运!

结合物理和深度学习

原文:https://towardsdatascience.com/combining-physics-and-deep-learning-54eac4afe146?source=collection_archive---------21-----------------------

什么是数字双胞胎,它们是如何工作的?

随着过去 10 年计算能力的提高,我们看到模拟的数量急剧增加。数字双胞胎就是这样一个例子。它们是可以在各种场景中模拟的物理对象或过程的虚拟复制品。

约尔根·哈兰在 Unsplash 上的照片

数字双胞胎面临的一个问题是,他们如何将潜在的嘈杂的经验数据与物理结合起来。

2021 年,谢菲尔德大学的研究人员开发了一个非常简单的数字双胞胎框架,称为 PhysiNet 来解决这个问题。PhysiNet 将深度学习与物理模型相结合,以开发对设备性能的稳健预测。

虽然数字双胞胎确实需要大量的开发资源,但在物理测试极其昂贵或危险的情况下,它们可以成为有效的替代方案。

事不宜迟,让我们开始吧…

技术 TLDR

数字双胞胎是物理系统的电子副本。他们依赖于黑箱和基于规则(物理、经济等)。)模特。然而,由于这两种方法都有不足之处,我们建议通过对每个模型的预测值进行加权线性组合来将两者结合起来。

当迭代训练黑盒模型时,在每个时期,我们重新调整两个模型预测的权重,以优化准确性。预测值的这种线性组合有效地结合了两种模型并优化了准确性。

但是,到底是怎么回事呢?

让我们提供一些关于数字双胞胎的背景知识,并讨论本文中的方法。

数字双胞胎的背景

如上所述,数字双胞胎是物理事物的数字副本,例如风力涡轮机或供应链。它们通常是基于物理的产品的 3D 模型,但可以简单得多。

2010 年,美国宇航局首次使用它们来帮助开发航天器,但在物理原型难以测试和/或测试成本高昂的应用中,它们越来越受欢迎。它们最符合逻辑的用例是在产品构思和开发期间,但是它们也可以与生产产品一起使用,以获得洞察力和预测失败。

利用数字双胞胎的行业从产品生命周期管理到建筑加热/冷却优化到汽车传感器。

问题是

大多数数字双胞胎严重依赖规则或经验数据。然而,通常最稳健的模型结合了先验规则和经验数据。有多种方法可以做到这一点,但 PhysiNet 提出了可以说是最简单的解决方案。

解决方案

PhysiNet 将神经网络(NN)预测与物理模型预测相结合。神经网络处理经验数据,而物理规则将系统绑定到现实——因为现实世界的数据可能有噪声,物理模型通常非常有用。

让我们参考下面的图 1…

图 PhysiNet 框架的图形表示。图片作者。

首先,我们拟合我们的物理模型(top),它通常是变量的线性组合。因为这些模型很少需要迭代来训练,所以我们只能进行静态预测。

第二,我们拟合一个神经网络(下图)。神经网络利用多个时期的反向传播来训练它们的权重。对于每个时期,除了更新网络中的权重向量,我们还开发了结合物理和 NN 预测的预测(显示在绿色框中)。

w 表示的两个权重相加为 1。因此,如果物理权重等于 0,我们只使用 NN 预测,反之亦然。根据物理和经验数据的质量,该框架自动更新我们的预测值以优化准确性。

图 PhysiNet、神经网络和一个基于物理学的模型在不同时期的性能— src 。图片作者。

如上面的图 2 所示,这个极其简单的框架拥有相对于单独的任一模型的性能改进。物理模型往往过于简单,而神经网络需要大量高质量的数据,因此通过结合两种模型,我们可以避免两种缺点。

摘要

数字双胞胎是昂贵的物理测试的有效替代品。对于基于物理的模拟,PhysiNet 结合了物理模型和黑盒机器学习模型的加权预测。这个框架拥有相对于单独的任一模型的准确性改进。

该框架非常简单,并且可以扩展,例如通过使用物理模型预测作为神经网络中的特征。如果你对该话题有资源/看法,请留下评论。非常感谢!

感谢阅读!我会再写 33 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源和一些有用的资源。

结合 Python 和 R 进行 FIFA 足球世界排名分析

原文:https://towardsdatascience.com/combining-python-and-r-for-fifa-football-world-ranking-analysis-d71bb6ceacdb?source=collection_archive---------8-----------------------

展示 Python 和 R 在数据科学和分析领域的互补优势

杰森·查特斯在 Unsplash 上的照片

Python 和 R 之间的“语言战争”是数据科学中长期争论的话题,至今仍被广泛讨论。

事实上,最好的语言是最适合具体工作的语言。毕竟,Python 和 R 只是数据从业者执行最关键任务的工具——用数据解决业务问题。

在这次 FIFA 足球世界排名分析中,我们探索 Python 和 R 的不同和共同优势,以及它们如何在现代数据科学工具包中互补。

内容

(1)数据无罪释放(Python 中的网页抓取)(2)****数据可视化(条形图竞在 R)

这个项目是由 投念翔 梁家骅 联合协作完成的。

查看GitHub repo获取实现代码。****

使用 Python 中的 Web 抓取进行数据采集

Python 作为一种通用编程语言,经常用于 web 抓取等通用任务。这种数据搜集工作最流行的工具之一是 Selenium。

Selenium 是一个用于 web 浏览器控制的开源自动化工具,用于自动化重复操作,如按钮点击、表单填写、文本提取和页面滚动。

在国际足联男子排名页面上应用了网页抓取脚本(带有 Chrome 网络驱动)来检索 1992 年至 2021 年间的国家队积分和排名。提取的数据导出为 CSV 文件,用于数据分析。

FIFA 排名数据前五行截图|作者图片

数据可视化与 R 中的条形图竞赛

与 Python 类似,R 是一种开源编程语言,提供了无数的功能。但是,它通常用于统计分析和创建图形。

后者是 R 的一个显著优势,因为它可以生成高质量的可高度定制的图形。在这一部分中,我们将演示如何使用几个 R 包来创建动态可视化。

FIFA 世界排名柱状图竞赛|作者图片

上图是一个条形图比赛动画,它显示了国际足联前十名的排名在过去三十年中是如何演变的。这些国家通过汇总它们的年平均分数来排名。

数据可视化分两步生成。首先,使用流行的 ggplot2 包(加载在 tidyverse 中)创建了一个静态条形图,它允许通过将图形分成不同的组件进行高度定制。

许多软件包现在可用于补充 ggplot2 图。在这种情况下,我们通过使用 ggimage 包添加标记图像来定制绘图。

第二,使用 gganimate 对静态剧情进行动画处理。具体来说, transition_time 函数只需增加一行代码就可以控制条形图逐年变化!

使用 Python 和 R 进行回归分析

Python 和 R 都是非常有效的统计分析工具。为了证明这一点,我们用 Python 和 R 展示回归建模来回答具体的足球问题。

(一)国际足联排名与国家队货币价值之间的关系(Python 中的线性回归)

我们想确定一个国家队的国际足联积分是如何受到该队球员平均货币价值的影响的。

球队阵容的数据(基于最近的锦标赛,如 2020 年欧锦赛、2021 年美洲杯等。)和相应的球员市场价值(以英镑计)从公共足球网站Transfermarkt.co.uk获得(截至 2021 年 8 月 12 日准确)。

我们通过合计每个球员的市场价值来计算每个国家队的货币价值。因为每个队可能有不同的球员数量,所以平均货币价值(即总价值除以球队规模)被用于分析。****

在建模之前,将数据可视化是一个很好的做法。特别是,我们希望确保我们的独立变量(平均货币价值)遵循正态分布,这是一个需要满足线性回归的假设。

使用 seaborn 库,我们可以创建一个直方图(用 KDE )来显示平均货币值的分布。

KDE 直方图|作者图片

该图揭示了一个显著的右偏,因为几个团队的货币价值比其他团队高得多。解决方案是将对数变换应用于平均货币值。这样做后,我们得到一个更接近正态分布的图。****

KDE 直方图(对数变换后)|作者图片

自变量转换成功后,我们可以进行回归分析。最直观的基线模型是线性回归。

众多的 Python 包允许我们执行线性回归,其中最流行的是 scikit-learnlinear_model 模块。

在为 LinearRegression() 函数提供因变量和自变量后,我们获得了以下指标:

线性回归指标|作者图片

0.746 的 R(决定系数)分数意味着该模型占国际足联点数可变性的 74.6%。鉴于我们的模型只有一个独立变量,这是一个相当不错的结果!

这意味着国家队的平均货币价值与其国际足联积分有较强的正相关性。

最后,使用 seaborn 创建回归图,以可视化线性回归模型拟合:

Python 中的回归图|作者图片

(ii)国际足联排名与国家联赛货币价值之间的关系(R 中的线性回归)

我们还对 FIFA 积分和国家(T2)一级足球联赛(T3)的货币价值之间的关系感兴趣。联赛货币价值的数据同样来自 Transfermarkt.co.uk 的**

鉴于不同联赛中参与俱乐部的数量不同,国家联赛的货币价值被标准化为每个俱乐部的英镑价值。

与之前的回归分析类似,国家联盟货币值的分布是右偏的,因此应用了对数变换****

由于 R 通常用于统计分析,线性建模已经包含在基本包中,不需要导入额外的库。 lm 函数通过简单地指定 Y ~ X 格式的公式,使线性模型符合数据。

结果显示,R 为 0.47,表明国家联赛的货币价值占国家国际足联积分可变性的不到一半。这种关系可以在下面的散点图中看到:

作者 R |图像中的回归图

我们观察到,国家队货币价值的数据点比 Python 散点图更远离线性回归线。

总的来说,我们可以从这两项分析中解读出,国家队的货币价值比国家联赛的价值更能预测一个国家的国际足联积分。

乱足球齿轮在 Unsplash 上拍照

摘要

Python 和 R 都是优秀的数据分析编程语言,在数据科学工具包中各有其位置。如果您专注于统计建模或从数据生成图形可视化,R 是一个更直接的选择。

另一方面,如果您的项目需要通用编程任务或与其他应用程序集成,Python 是更合适的选择。

总之,争论 Python 和 R 哪个更好是徒劳的。理想的工具取决于用例、你打算回答的问题以及你的团队和行业的文化。

*****https://www.linkedin.com/in/nien-xiang-tou-phd-a15594184/

在你走之前

欢迎您加入我的数据科学学习之旅!点击此媒体页面,查看我的 GitHub ,了解更多精彩的数据科学内容。*

结合 R {tidyverse,fleet,DT,flexdashboard}和 Python {pandas,GeoPy}创建无服务器心理治疗仪表板

原文:https://towardsdatascience.com/combining-r-tidyverse-leaflet-dt-flexdashboard-and-python-pandas-geopy-to-create-a-c25c5ef7d2d9?source=collection_archive---------32-----------------------

照片由维特·加布雷拍摄

介绍

在捷克共和国,只有一小部分精神治疗护理(T3)由健康保险公司(T6)承保(T5)。因此,当最大的此类公司之一 VZP 向其客户提供 7 000 CZK(约合 280 欧元)的心理治疗津贴时,这是一个受欢迎的举措。

然而,给自己找一个心理治疗师的方法并不是最方便的,因为你必须滚动浏览一个. pdf 文件。幸运的是,捷克心理治疗协会https://czap.cz/eng的董事会成员 Dominika echová,通过谈判从 VZP 获得了更多信息,比如哪些心理治疗师可以接受新客户。

我的任务是将这些信息整合成一种更加用户友好的方式,让你自己找到一个治疗师,从而使服务更加容易获得。重点是交付的速度和部署的简易性,所以我决定用flex dashboard来完成 R ,这个包允许创建交互式无服务器仪表盘。

我有以前的项目中的大部分构建模块——R 实现 传单 用于地图,以及 数据表 用于表格。 Tidyverse 用于装载和角力数据。

然而,输入表不包含纬度和经度,这是在地图上显示治疗师位置所需的两个元素。之前我已经用 ggmap 调整过数据。然而,Google API 需求的变化使得这变得有些不方便。

所以,我决定寻找一个替代方案。然后偶然看到了 Abdishakur 的文章Geocode with Python,很棒的介绍 Python 的包 GeoPy

现在,虽然 R 是我的特殊数据朋友,但我也喜欢在我的工作流程中有利的地方集成其他语言和工具,如 Python、熊猫、T21。

在这篇文章中,我想回顾一下我是如何创造理想结果的。

你可以在这里找到最终的仪表盘https://www.data-must-flow.com/posts/psychotherapy_vzp/和带有交互元素的原创文章*这里 。***

r 包

让我们从加载所需的包开始:

****# Load required packages*
library(flexdashboard) *# dashboard wrapping*
library(tidyverse) *# data wrangling*
library(crosstalk) *# interactivity*
library(broom) *# output of built-in functions cleanup*
library(DT) *# Table formatting*
library(htmltools) *# widgets*
library(reshape2) *# data taransformations*
library(leaflet) *# interactive maps*
library(leaflet.extras) *# interactive features****

输入数据

您可以在 GitHub 上找到输入数据集。

****# Initial dataset*
vzp_data = read.csv("vzp_data_geo.csv") %>%
    select(name, surname, alias, website, address,
           city, region, psc, phone, email, Kapacita, remote_therapy)***

计算机编程语言

激活

首先你需要打开 r 中的 Python 接口,我用的是 reticulate

****# Python interoperability in R*
library(reticulate)*# Specifying which version of python to use.*
use_python("/home/vg/anaconda3/bin/python3.7",
           required=T)  *# Locate and run Python****

包和数据争论

即使有可能一次运行下面所有的代码块,让我们遵循做一件事的原则,根据它们的功能将它们分开。

Python 包优先:

***from geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter
import pandas as pd***

激活地理编码器:

***locator = Nominatim(user_agent="myGeocoder")***

将部分地址链接到一个变量-将用于地理编码:

***df = r['vzp_data']df['state'] = "CZ"df["ADDRESS"] = df["address"] + "," + df["city"] + "," + df["state"]df["Adresa"] = df["address"] + ", " + df["city"]***

使用 GeoPy 进行地理编码

为了减少Too Many Requests误差,使用RateLimiter。正如 GeoPy 的文档所说,在地理编码调用之间添加一个延迟,以减少地理编码服务的负载。

****# 1 - conveneint function to delay between geocoding calls*
geocode = RateLimiter(locator.geocode, min_delay_seconds=1)*# 2- create location column*
df['location'] = df['ADDRESS'].apply(geocode)*# 3 - create longitude, laatitude and altitude from location column (returns tuple)*
df['point'] = df['location'].apply(**lambda** loc: tuple(loc.point) **if** loc **else** None)*# 4 - split point column into latitude, longitude and altitude columns*
df[['latitude', 'longitude', 'altitude']] = pd.DataFrame(df['point'].tolist(), index=df.index)***

导出地理编码数据

现在,您可能会问——为什么我要导出这个表?我不打算把数据作为 Python/R 对象进一步处理吗?

不幸的是,当包含 Python 代码时,flexdashboard 还不能被编织。因此,在使用仪表板时,我必须创建两个独立的工作流—一个用于数据地理编码,另一个用于编译仪表板。然而,我想使仪表板编码更具可重复性,同时将所有重要的组件保持在一个工作流中。

幸运的是,其他 R Markdown 输出如 R notebook 很乐意包装 Python 代码。这就是您在代码中看到这一步的原因。当然,这不是最有效的工作流程,但是你知道他们说什么——完成(和工作)比完美更好。

当然,如果目标是包含一些 Python 块的 R Markdown 文档,您可以简单地在 R 块中添加vzp_data = py[df],将 pandas 数据帧转换成 R 数据帧,并顺利进行下一部分。

****# Convert pandas DataFrame into R Data Frame (tibble)*
vzp_data_geocoded = py['df']vzp_data_geo <- vzp_data_geocoded %>%
    select(name, surname, alias, website, address,
           city, region, psc, phone, email, `Kapacita`, remote_therapy,
           state, Adresa, latitude, longitude)vzp_data_geo <- apply(vzp_data_geo,2,as.character)
write.csv(vzp_data_geo, file = "vzp_data_geo.csv")***

稀有

tidyverse 中的数据争论

仅选择将在输出中使用的列并格式化它们:

****# Data import and wrangling*
vzp_data = read.csv("vzp_data_geo.csv") %>%
  select(name,
         surname,
         alias,
         website,
         address,
         city,
         phone,
         email,
         Kapacita,
         remote_therapy,
         latitude,
         longitude) %>%
  mutate_all(list(~str_trim(.,side = "both"))) %>%
  mutate(`Jméno a příjmení` = paste(name,surname),
         latitude = as.numeric(latitude),
         longitude = as.numeric(longitude)) %>%
  rename("Email" = email,
         "Telefon" = phone,
         "Web" = website,
         "Online nebo telefonické konzultace?" = remote_therapy,
         "Kapacita?" = Kapacita,
         "Město" = city,
         "Ulice" = address) %>%
  mutate(`Kapacita?` = case_when(`Kapacita?` == "volno" ~ "Volno",
                              `Kapacita?` == "naplněno" ~ "Naplněno",
                              `Kapacita?` == "Naplněno" ~ "Naplněno",
                              TRUE ~ `Kapacita?`),
         `Online nebo telefonické konzultace?` = case_when(`Online nebo telefonické konzultace?` == "Ano" ~ "Ano",
                                                           `Online nebo telefonické konzultace?` == "Ano/ možnost konzultací v anglickém jazyce" ~ "Ano",
                                                           `Online nebo telefonické konzultace?` == "Ne" ~ "Ne",
                                                           `Online nebo telefonické konzultace?` == "ne" ~ "Ne",
                                                           TRUE ~ `Online nebo telefonické konzultace?`)
         )*# Replace "NaN" with "Neuvedeno"*
vzp_data[vzp_data=="NaN"] <- "Neuvedeno"***

输出

可用心理治疗师列表

下表是使用DataTable包完成的最终查找表的快照。这个包意味着许多交互元素供您使用。您可以添加跨列搜索和过滤、排序、分页等等。此外,它可以很容易地与使用crosstalk的过滤器连接。

由于输出是捷克语,我建议您的浏览器的Translate to English功能获得更多价值。

***vzp_data_table <- vzp_data %>%
  select(`Kapacita?`, `Online nebo telefonické konzultace?`,
        Město,
        Ulice,
         `Jméno a příjmení`, 
         Email, Telefon, Web, Ulice,
         `Online nebo telefonické konzultace?`) test_shared <- crosstalk::SharedData$new(vzp_data_table)DT::datatable(test_shared,
    extensions = c(
      "Responsive"
    ),
    rownames = FALSE,  *# remove rownames*
    style = "bootstrap",
    class = 'cell-border display',
    options = list(
      pageLength = 10,
      dom = 't',
      deferRender = TRUE,
      scroller = TRUE,
      columnDefs = list(list(className = 'dt-center', targets = "_all"))
        )
      ) %>% formatStyle(
  "Kapacita?",
  target = 'row',
  backgroundColor = styleEqual(c("Naplněno", "Volno"), c('#ffcccb', '#d2e9af')))***

心理治疗师分布图

由于通过地图搜索可能更方便,我决定用传单添加一个。类似于数据表,传单允许多个交互式元素。包括基于字符串或不同地图图层的搜索。

同样,由于输出是捷克语,我建议您的浏览器的Translate to English功能获得更多价值。

****# prepare a palette - manual colors according to branch column*
pal <- leaflet::colorFactor(palette = c("Naplněno" = "#8b0000",
                                        "Neuvedeno" = "#A9A9A9",
                                        "Volno" = "#006400"
                                        ), 
                               domain = vzp_data$`Kapacita?`)points_fin <- SharedData$new(vzp_data)map1 <- leaflet(data = points_fin, width = '100%', height = 800) %>%
          addProviderTiles("CartoDB.Positron", group = 'Základní') %>%
          addProviderTiles("Esri.WorldImagery", group = 'Letecká') %>%
          addProviderTiles("OpenStreetMap.Mapnik", group = 'Uliční') %>%
          addProviderTiles("OpenTopoMap", group = 'Zeměpisná') %>%
          addScaleBar('bottomright') %>%
          setView(15.4129318, 49.7559455, zoom = 8.2) %>%
          addCircleMarkers(
                   group = 'Obor', 
                   stroke = FALSE, 
                   opacity = 0.9,
                   fillOpacity = 0.9,
                   fillColor = ~sapply(`Kapacita?`, **switch**, USE.NAMES = FALSE,
                                        "Volno" = "#006400", 
                                        "Naplněno" = "#8b0000",
                                        "Neuvedeno" = "#A9A9A9"
                                     ),
                   popup = ~paste0('<h2>Detail</h2> <br>',
                                   '<b>Město</b>: ', Město, '<br>',
                                   '<b>Ulice</b>: ', Ulice, '<br>',
                                   '<b>Jméno a příjmení</b>: ', `Jméno a příjmení`, '<br>',
                                   '<b>Online nebo telefonické konzultace</b>: ', `Online nebo telefonické konzultace?`, '<br>',
                                   '<b>Telefon</b>: ',`Telefon`, "<br>",
                                   '<b>Email</b>: ', Email, '<br>',
                                   '<b>Web</b>: ', Web, '<br>',
                                   '<b>Kapacita</b>: ', `Kapacita?`, '<br>')
                   ,
                   clusterOptions = markerClusterOptions(showCoverageOnHover = FALSE,
                    iconCreateFunction=JS("function (cluster) {    
    var childCount = cluster.getChildCount(); 
    var c = ' marker-cluster-';  
    if (childCount < 100) {  
      c += 'small';  
    } else if (childCount < 1000) {  
      c += 'medium';  
    } else { 
      c += 'large';  
    }    
    return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); }"))) %>%
  addLegend(position = "topright",
            values = ~`Kapacita?`,
            opacity = .7,
            pal = pal,
            title = "Kapacita?") %>%
  leaflet.extras::addResetMapButton() %>%
   addLayersControl(
                baseGroups = c("Základní", "Letecká", "Uliční", "Zeměpisná"),
                options = layersControlOptions(collapsed = TRUE)
              ) %>%
      addSearchOSM()map1***

结束语

我相信当以上述方式集成 R 和 Python 时,有些人会皱起眉头。"为什么不选择一种工具并使用它呢?“你可能会问自己。在我的例子中,我需要在模板中添加一部分。虽然它的部分是用 R 编写的,但我不想把自己局限在一种工具上。

同时,通过查看当前的限制,我们可以促进未来集成的便利性。在这里,我必须承认 RStudio ,在我看来是处理数据的最好工具之一,已经在集成 Python 方面迈出了重要的几步。然而,在特定的用例中,这仍然是一段有点颠簸的旅程。

最终,我想试验和测试极限。我相信 Python 和 R 在处理数据时各有利弊,所以为什么不探索一下如果将它们结合在一起可以达到什么目的呢?

结合 Spotify 和 R——一个交互式 Rshiny 应用程序+ Spotify 仪表盘教程

原文:https://towardsdatascience.com/combining-spotify-and-r-an-interactive-rshiny-app-spotify-dashboard-tutorial-af48104cb6e9?source=collection_archive---------11-----------------------

了解如何制作一个直观的 Spotify + Rshiny 应用程序,告诉用户他们的音乐个性、最受欢迎的艺术家和专辑比较等信息

塞尔吉·卡夫雷拉在 Unsplash 上的照片

(滚动到底部,以 GIF 格式查看完整应用的现场演示)。本文详细介绍了如何使用 Rshiny 制作一个集成的 Spotify 应用程序。这个应用程序使用了Spotify API,并揭示了如何以更简单的方式使用 Rshiny 作为类似程序(如 Python 的 Streamlit 或 Javascript)的替代方案。Rshiny 是一个 R 包,它允许用户轻松地创建 web 应用程序,因为它使用 R,所以允许比 Javascript 更直观的数据可视化和操作。要创建一个 Rshiny 应用程序,最好至少有一个 ui。r(用户界面)脚本,一个服务器。r 脚本和运行。r 脚本。用户界面。r 文件的工作方式和 HTML 文件一样,只是外观不同,功能不同。服务器。r 文件的行为类似于。js 文件,这个文件也是定义所有函数的最佳位置。这个文件中的函数和对象构成了 ui。r 文件“工作”,并且最好在开始之前在脑海中想象一下整个项目的视觉效果。我绘制了每个标签(又名页面)应该包含的内容,从登录页面开始,然后是人气、人气和用户统计标签。这直接转化为用户界面。r 脚本。然后是在服务器中创建的函数和对象。r 脚本可以继续工作,因为它们现在可以被构建出来。最后,跑步。r 文件,通常只是一个具有 runApp 功能的简单文件。该项目现在可以通过 Heroku 或 shiny apps 来完成和部署。

我开始这个项目是因为我希望用户可以轻松地输入他们在 Spotify 的用户名和密码,然后他们的信息就会被加载,用户可以通过不同的表格和可视化方式看到他们音乐品味的酷的方面。

可悲的是,用于 R 的 Spotify 软件包 spotifyr 不支持用户登录,用户需要实际的 Spotify API 才能看到他们的数据(也就是客户端 id 和客户端机密)。该应用程序仍然工作,它只是需要一个用户有 API,让他们看到自己的音乐品味。不管怎样,这款应用制作起来还是很有趣的,并且让可视化对用户来说更具互动性。

我将首先检查应用程序的布局,所以我们开始吧!

我希望该应用程序有 4 个不同的标签是:

  • 简介选项卡—允许用户输入他们的客户端 id 和客户端密码,API 它还提供了如何获取 API 密钥来使用该工具的说明

作者图片

  • 流行度选项卡—显示用户收听的艺术家的不同流行度指标。它有一个可视化图表,从 Spotify 的内部流行度指标 1-100 显示用户最常听的艺术家(我设置为 25 位艺术家)的流行度。它还在一张饼状图上按关注者对这些艺术家进行了比较。

作者图片

  • 情感标签——可能是最复杂的标签,它允许用户滚动浏览他们最受欢迎的艺术家(前 25 名)的专辑,并查看每张专辑的情感评分。情绪是音乐的不同属性,它们包括:“可跳舞性”、“能量”、“响度”、“语速”、“声音”、“活跃性”、“积极性”和“节奏”。该标签还显示了最具有某种音乐属性的艺术家的歌曲。举个例子,艺术家劳伦·希尔女士最适合跳舞的歌曲是《最后一小时》,其可舞性得分为 0.847。我在这里获得了这张脊线图的灵感。

作者图片

  • 用户统计——全面查看用户的 10 位最受欢迎的艺术家,并绘制艺术家的集体情感图表。然后它判断用户的音乐个性。在所示的例子中,用户似乎喜欢悲伤的音乐,因为音乐的能量和积极性平均较低。注意,对于非英语音乐,这不是最准确的。这也表明用户可能喜欢本质上更罗嗦的说唱音乐。我在这里得到了这个视觉化的灵感。

作者图片

作者图片

这些是我在做这个项目之前考虑的事情,在写代码之前我已经把大部分都计划好了。说到代码,让我们开始吧!

照片由弗洛里安·奥利佛在 Unsplash 上拍摄

我将从 ui 开始。r 文件,所有的“前端开发”都在这里进行。代码将会显示,并解释之后会发生什么。我将包括图片,因为媒体不能识别 Rshiny 代码。

让我们一步一步地看看第一个选项卡:

  • ShinyUI 是包含所有用户界面代码的地方。我们需要添加 fluidPage,以允许自动调整页面尺寸。最后,我们需要一个 navbarPage 来封装所有的 tabPanels(类似于独特的 HTML 页面)。
  • Intro tabPanel 包括一个侧边栏面板,允许用户输入他们的 Spotify 客户端 id 和客户端密码。spotifyr 包目前不允许直接输入用户名和密码,因此用户必须使用 Spotify API。textInput、actionButton 和 textOutput 中的第一个字符串参数都是将在服务器中使用的变量。r 文件。
  • 主面板包括注册 Spotify API 的基本说明。很明显,h#只是 Rshiny 中不同的标题大小。
  • 如果您遇到问题,可能需要在启动应用程序之前声明客户端 id 和客户端密码。

现在是第二个标签:

  • 这个 Popularity tabPanel 只包含一个 mainPanel,它包含两个绘图,名为 popularity_plot_output 和 follower_plot_output,我们将在 server.R 中创建它们。
  • 还有一个名为 favorite_artists_table 的数据表也将在 server.R 中创建。

让我们看第三页:

  • 该情感选项卡面板有两个 fluidRows,包含艺术家姓名和情感类型的下拉列表(分别为 artist_name 和 perspective _ type)。
  • 在两次下拉之后,存在两个文本输出。一个在情节情绪 _ 情节 _ 输出之前,另一个在数字输入之前。第一个文本“情绪 _ 文本”只是一个情节标题,而第二个“情绪 _ 情绪”是下面数字输入框的输出。其工作方式是,无论用户输入什么数字,都将是歌曲的排名,该排名基于在情绪类型中选择的情绪。
  • tags$style 的工作方式类似于 CSS 在 web 开发中的工作方式,并且格式化给定的对象。此外,br()只是增加了一个额外的空间。

最后,标签四:

  • 这个最后的 tabPanel 有两个 textOutputs 和两个 plotOutputs。我们首先创建能量与积极性输出图,它将显示用户从他们所听的音乐中获得的整体积极性和能量。然后,它将显示一个名为 energy_vs_positivity 的文本输出,该文本输出根据用户的顶级艺术家来表达用户的音乐个性。

这就完成了 ui。现在我们来看看 server.R。

照片由劳塔罗·安德烈亚尼在 Unsplash 上拍摄

现在我们处于 Rshiny 项目的“后端开发”部分。我们需要在 ui 中创建我们定义的变量和对象。我们将使用许多 spotifyr 函数从 Spotify API 中提取数据。

这一部分可以分为两个部分。首先,我将讨论一些显示一些可视化效果和运行应用程序所必需的函数,然后我将展示 shinyServer 函数,它与 shinyUI 函数类似。

  • authenticate 函数:允许 spotifyr 对 API 进行身份验证,并允许访问所有数据。参数只是客户端 id 和客户端机密。
  • fav_artists 函数:制作一个表格,其中包括用户的顶级艺术家,以及他们的受欢迎程度(由 Spotify 排名)、Spotify 每月总听众人数和音乐流派等信息。它使用 spotifyr 函数 get_my_top_artists_or_tracks,然后使用 R 的数据操作函数和强大的管道操作符将表格精简为最基本的必需品。这个函数主要用在 tabPanel 二中。
  • fav_artists_datatable 函数:格式化从最后一个函数创建的表格,使其对用户友好。
  • audio_features_fav_artist 函数:创建一个包含艺术家姓名的表,以及 Spotify 为每首歌曲测量的一些音频功能。这些衡量标准是“可跳舞性”、“能量”、“响度”、“语速”、“声音”、“活力”、“积极性”和“节奏”。这个函数使用 spotifyr 的 get_artist_audio_features 函数,我们做了一些字符串操作来将 valence 的标题改为 positivity。在第四个 tabPanel 中大量使用。唯一的参数是 artist_name。
  • 从上一个函数生成一个 R 数据表。最终没有使用这个函数,但它在某些场景中可能很重要,因为 plotly 有时比普通的 R 数据帧更适合使用 datatable 对象。同样,唯一的参数是 artist_name。

现在我们在实际的 shinyServer 中,项目的所有“复杂”方面都在这里。这并不复杂,但是所有的对象都源自这里,所以如果你在实际的可视化或者从 Spotify API 提取数据时出现问题,这可能就是原因。

  • 我们需要 shinyServer 来创建“后端”,因此我们可以使用 Rshiny eventReactive 函数创建 validate 函数(这个函数和 Reactive 函数一样常用,所以请在这里阅读),将输入$btn 作为触发器,并执行我们在 ui.R 中声明的 validate 函数。我们还可以使用 Rshiny 的 renderText 函数将 validate 函数的输出保存为文本。

TabPanel two 有 4 个对象:popularity_data、popularity_plot_output、follower_plot_output 和 favorite_artists_table。

  • popularity_data 只是保存我们之前在 server.R 中创建的 fav_artists 函数的输出的 dataframe 对象,我们需要使用 Rshiny 反应函数将该函数引入 shinyServer。这个函数非常重要,在服务器中经常使用。r 文件。
  • popularity _ plot _ output 将是保存流行度条形图的对象,它比较用户库中前 25 位艺术家的 Spotify 流行度指标。这些图表的语法非常简单明了,因为更困难的问题通常是“可视化应该是什么?”
  • follower_plot_output 与上一个图类似,只是它使用了 plotly。Plotly 通常需要更多的数据操作来创建图表,但它们是动态的,而标准的 ggplots。
  • favorite_artists_table 是页面末尾的一个简单表格,用户可以看到他们关注的每个艺术家的详细信息

第三个选项卡面板也包含 4 个对象:情绪 _ 数据、情绪 _ 文本、情绪 _ 绘图 _ 输出和大多数情绪。

  • 情绪数据是音频特征收藏艺术家函数的数据帧对象,输入是用户在这个页面的下拉菜单中选择的艺术家姓名。我们还使用一个反应函数来允许使用我们之前创建的 audio_features_fav_artist 函数。
  • 仅仅显示用户在下拉列表中选择的情感,但是字体更大。
  • sensition _ plot _ output 首先获取用户选择的情绪类型,并用 casefold 函数使其小写。这被保存到称为文本的向量(或 1D 数据帧)中,并且文本被用于以降序组织情绪数据。然后,为了实际制作 ggplot,我们需要为 x 轴使用文本,因为文本变量依赖于用户的输入。这看起来很复杂,但是我们这样做是为了让图表根据用户的输入而改变。
  • most _ perspective 使用与上一个图相同的逻辑来保持情绪名称的动态,它基本上只是打印出情绪类型和单个音轨的分数。

TabPanel 4 有 5 个对象:top _ artist _ invision _ data、energy_vs_positivity _ plot _ output、energy _ vs _ positivity、speech ness _ vs _ dance ability _ plot _ output 和 speech ness _ vs _ dance ability

  • top _ artist _ invision _ data 基本上意味着使用 audio_features_fav_artist 表,但是使用 popularity_data 作为索引。这样做是为了获得用户库中前 10 位艺术家的音频。这个对象基本上是一个艺术家名字的数据帧和艺术家所有歌曲的所有音频特征。
  • energy _ vs _ positivity _ plot _ output 将该数据帧绘制成散点图,对每个艺术家使用不同的颜色。我用不同的描述给每个象限贴上标签,又名“愤怒”,代表能量较高但积极性较低的音乐。我们使用顶级艺术家情感数据来创建这个可视化
  • energy_vs_positivity 将 energy 和 positivity 的分数绑定,并计算分数,决定哪种情绪最能代表用户的音乐品味。然后输出描述用户音乐个性的语句。
  • speech ness _ vs _ danceability _ plot _ output 与前面的图类似,只是使用 speech ness 和 dance ability 作为情绪。
  • speechiness_vs_danceability 也给出了描述用户音乐个性的陈述。

这就差不多解决了。我们需要的只是逃跑。r 文件,我们的 app 就完成了!请查看以下内容:

卢克·切瑟在 Unsplash 上的照片

对于一些人来说,查看制作 Rshiny 应用程序的过程似乎很复杂,但实际上这比尝试用 Javascript 甚至 Python 的 Streamlit 包做同样的事情要容易得多。它还允许您使用 R 在一个有效的交互式数据科学应用程序中提供的非常强大的数据操作工具,其他人可以使用和享受这些工具!

我希望这能让一些数据科学爱好者和应用程序开发人员大开眼界,并希望激发更多与数据相关的应用程序,这些应用程序具有用户真正喜欢的功能,如他们最喜欢的指标的直接和交互式可视化。

来源:

https://github.com/kingazaan/spotifyr-r-shiny https://github.com/charlie86/spotifyr https://vladyslavkushnir.medium.com/exploring-spotify-api-in-r-284f1ef32f46 https://medium.com/@joypham7/spotify-personal-data-analysis-858c8fbe6983

支持数字业务的商业机器学习工具包

原文:https://towardsdatascience.com/commercial-machine-learning-explained-to-power-digital-business-a6d8aec7aa79?source=collection_archive---------29-----------------------

商业人工智能需要在规定性分析和可操作的机器学习模型之间找到一条交叉道路。

介绍

根据 Zion market research 的数据,2017 年全球机器学习(ML)市场价值约为 15.8 亿美元,预计 2024 年将达到约 208.3 亿美元。各种规模的公司都在应用认知技术,这些技术利用了机器学习(ML)和人工智能(AI)的新兴能力。基于云的 GPU&TPU 的可用性、开源库、谷歌、脸书等公司的投资以及 Kaggle 等大规模数据集的可用性,使得机器学习的应用在每个产品开发中都触手可及。

Gartner 的首席信息官调查发现,在过去四年中,人工智能的实施增长了 270%。调查数据显示,随着机器人流程自动化(RPA)的兴起,工作流程正在通过机器学习算法得到增强,以降低成本和提高客户满意度。由于满足运营需求的技术渗透率越来越高,业务影响的价值也越来越高,采用支持 ML 的应用程序的企业正在获得发展势头。机器学习预测的数据丰富特性也是数字企业抓住机会做出实时决策的主要驱动力。机器学习的独特之处在于对该领域的整体、超然观点,以及自动识别隐藏模式。人工智能的采用正在加速,预计到 2024 年,75%的企业将转向人工智能驱动的企业。由此,一个新的趋势出现了**“机器(深度)学习驱动实时业务流程”。**

商业 ML 工具包

对于机器学习模型的商业成功,理解商业应用需要最高程度的功能性和可靠性是很重要的。与增量改进的统计度量相比,成功度量大部分是二元的。这要求对 ML 模型如何工作有高度的可解释性和透明性。该工具包解释了解决这些需求的分析和运营框架。

商业 ML 工具包[图片由作者提供]

规定性分析

传统上,公司根据历史数据执行商业计划。例如,商店经理将根据前一年的数据和商店经理的经验决定“产品促销”。随着实时信息的可用性和成熟的机器学习算法的可用性的增加,公司正在通过使用历史和实时趋势的预测分析来做出主动决策。然而,机器学习还为实时业务提供了超越预测分析的优势,这就是【规定性分析】,预计到 2022 年这个市场将达到约18.8 亿美元。

更多面向消费者的企业正在尝试采用透视分析,因为它为可能的预测结果提供了可行的建议。更大的优势是,它还实时执行具有给定约束的**“如果……会怎样”分析**。更少的例子包括:a)如果员工正在努力完成一门课程,LMS 系统会推荐额外的课程来学习必备技能;b)通过为正确的买家指定正确的内容来引导销售;c)通过根据日常销售情况优化实时数据来更好地管理商店库存。

印度 IT 巨头 Infosys 的一份名为企业中的人力放大的调查报告发现,98%的受访者表示,通过执行人工智能任务,他们的组织增加了 15%的收入。在这方面,最大的影响来自机器学习,因为它通过提供“考虑业务/运营约束的建议”来帮助做出更明智的决策。

操作框架

在这种“使用机器学习的企业实时决策”的范式转变之后,人工智能和人工智能已经成为一个工程问题而不是研究挑战。可靠性、可扩展性和管理复杂系统是实时执行 ML 模型的重点领域。问题是“与仅仅进行无休止迭代的研究实验相比,我如何让机器学习项目适应市场需求?”。专家认为,实时商业人工智能和人工智能的使用增加将有助于加速模型在生产中的部署。

由于实时决策或建议是由计算机提供的,因此关键的挑战是确保**合规、透明和道德。**因此,“商业人工智能需要规范分析和机器学习模型之间的交叉道路,以建立规范模型,帮助企业做出实时决策”。下面是解释解决这些挑战的不同技术和工具的操作框架。

商业化人工智能——操作框架[图片由作者提供]

可解释的人工智能(XAI)

“可解释的人工智能”(XAI)是实现人类与科学合作的一步,并使“以人为本的战略”成为建立面向消费者的产品的实时规定性分析。这是一套工具和框架,有助于提高可解释性和可解释性,这对实现公平、负责和透明的 (FAT) 无偏见的机器学习至关重要。它有助于回答“我应该相信这个预测吗?”

机器学习中的这个新兴领域旨在解决ML 模型如何做出黑盒决策**。一些更简单形式的 ML 模型,如决策树、贝叶斯分类器、逻辑回归都有一定的解释能力。最近的研究进展表明,在深度学习领域,更复杂的机器学习算法具有可解释性。像 DARPA 这样的研究实验室正在围绕为神经网络构建可解释的接口进行广泛的研究,这些神经网络产生更多可解释的模型,同时保持高水平的学习性能。**

在过去的几年里,人工智能研究人员一直在开发类似于 What-if 、 DeepLIFT 、 AIX360 、激活图册、 Rulex 、可解释人工智能、 Alibi 的工具,以及类似于注意力、时间、 SHAP 的方法,使从业者能够轻松地进行评估这些工具也促进了可解释的人工智能的大规模应用。

ML 的科学“敏捷”

企业衡量的一个新指标是**“在生产中部署第一个模型的时间”**。最近的一项调查显示,18%的公司投入生产的时间超过 90 天,有些甚至超过一年。它还强调了 25%的 ML 工程师时间花在将模型投入生产上。这个延长周期的一个关键原因是,ML 是一个研究密集型环境,它是不确定的。另一个方面是,研究项目未能证明可行性,也是一种可能的结果。这意味着很多时候你会以一个未交付的功能而告终。

需要开发一个适应性策略/过程来管理任何机器学习项目。这种策略应该以连续的方式为大量的调查、探索、分析和调优提供更多的机会。

快速迭代项目开发[ 图来自 Doug DeCarlo 的《极限项目管理》一书[3]][图片由作者提供]

机器学习的数据驱动、开放的本质要求更快的反馈循环,这自然有助于敏捷成为机器学习项目的事实过程。我们需要的是一个**“敏捷的新端口”**用于机器学习。

敏捷原则的移植版本将从以下方面挑选特征:a)将这种【科学方法】集成为一个持续的迭代过程 b)通过【数据分析金字塔】管理数据,它表达了基于项目管理的商业价值 c)【PERT】

根据 Dresner 的报告,70%的研发部门最有可能将人工智能和机器学习应用于他们所有的企业职能。这种向基于价值的合同的不断转变将推动人工智能和机器学习平台保持响应性和适应性,这是基本的敏捷原则。

3 M 的 ML 编排

随着 ML 的商业应用趋于激增,企业将寻求更好地管理、监控和维护生产中的模型,以确保对部署的 AI 集成的信任。随着对合规性、数据安全性和偏见的审查越来越严格,信任和透明度将变得更加重要。**需要注意的三个“M”**是:

商业人工智能——3M 的 ML 编排[图片由作者提供]

MLOps 专注于人工智能的可操作化,使技术/科学变得可访问、可应用、可重复和自动化。MLOps 还建议建立一个“跨职能团队”,让工程师和研究人员融入同一个团队。它还是评估和实现洗钱风险和洗钱健康的基本平台。企业需要专注于构建 MLOps/ CD4ML 框架,该框架考虑了特性存储、模型版本、元数据存储、模型服务和端到端部署管道。有了像 Kubeflow 、 FEAST 、 ONNX 、 Seldon Core 和 5 level 这样的开源工具,成熟度模型可以帮助企业了解他们的当前状态并向上爬,从而将 MLOps 视为他们有形业务价值的驱动因素。

ML Health 是功能监控,用于向业务发起人传达业务模型的表现。这一点至关重要,因为它展示了预测模型的性能以及对产品/业务的影响。这是通过持续的度量评估来实现的,例如准确性、精确度和召回,以确保它们在预期的范围内运行。需要一个成功的沟通策略,如模型性能下降或上升的实时通知平台。对于生产中的大规模模型部署,使用 Tableau 和 Qlik 等可视化工具构建监控仪表板也很流行。

洗钱风险不会随着模型开发而结束。模型漂移是一种预期的行为,当一个 ML 模型被集成为实际应用的一部分时。当检测到模型所训练的变量发生变化时,模型的准确性会降低。a)目标变量**(概念漂移)** b)输入数据**(数据漂移)** c)操作变化**(特征漂移)**的统计特性可以触发模型漂移的发生。

检测实时模型漂移的理想方法是实施任何技术,如**数据偏差检测、金丝雀管道、漂移检测、生产 A/B 测试、多臂土匪测试(多变量|优化)作为 ML 工作流程的一部分。另一个有用的方法是,与部署在(干预模式)相比,在【检测模式】**部署模型,这样有助于演示漂移。像 Alibi Detect 这样的监控和治理工具以及像 fiddler 、 truera 这样的商业工具被认为是这个领域的新兴领导者。

作为机器学习应用消费化的副产品,全面的生产治理机制和责任对于确保遵守 GDPR、算法责任法案、FDA 等 ML 合规要求至关重要。期望机器学习工作流程中的所有阶段都应该是可追溯的,具有可再现性、可审核性并有助于解释。

结论:

这些专注于为机器学习模型带来可解释性和透明度的进步正在推动 ML 模型的变化,以实时推动数字业务。随着规范分析中的随机优化,许多商业用例,如在线推荐、智能营销活动、信贷决策、欺诈检测,都在为人工智能支持的数字应用铺平道路。广泛的研究仍然继续为更复杂的关键任务用例带来可解释性,如医疗诊断、需要高度透明和可解释性的自动驾驶汽车。

我们还了解到,迭代和跨职能沟通的原则比以往任何时候都更加重要。围绕可解释性、公平性和隐私的问题需要通过可持续的机器学习模型管理和治理结构来解决。与模型性能相比,机器学习模型的有用性将根据业务指标来衡量。

有了机器学习的这些归纳性质,很明显,人工智能商业化的时代正在跨越【VoID】的道路上。

简单解释了常见的距离测量

原文:https://towardsdatascience.com/common-distance-measures-simply-explained-9d77bde8d459?source=collection_archive---------32-----------------------

探索数据科学

距离度量在数据科学和机器学习中无处不在。许多算法依赖于它们,并且"知道何时使用哪个距离度量可以帮助你从一个差的分类器到一个精确的模型。在这篇文章中,马腾·格罗登斯特出色地解释了最常见的问题。对于九种距离测量中的每一种,Maarten 描述了它们是如何工作的,提供了几个用例,并讨论了它们的潜在缺点。

</9-distance-measures-in-data-science-918109d069fa>

关于差异隐私的常见误解

原文:https://towardsdatascience.com/common-misconceptions-about-differential-privacy-5f2c37953cdd?source=collection_archive---------18-----------------------

人工智能校准和安全

本文将澄清一些关于差异隐私及其保证的常见误解。

来源: Gretel.ai

关于差分隐私(DP)的内容有很多,从学术著作,如 DP 创始人写的隐私书,到解释其核心原则、解释和应用的博客,如这个系列。虽然这些都是写得很好的资源,但它们需要深入研究才能完全掌握。因此,如果你对差分隐私有一个基本的了解,但还没有机会深入研究这些资源,这篇文章将澄清一些常见的误解。

差分隐私不是算法。

更确切地说,DP 是算法必须满足的标准。标准很简单,算法的输出,比如计数,不应该太依赖于任何单一记录。算法通常通过某种类型的概率噪声添加来掩盖任何记录的存在,从而达到差分隐私标准。例如,可以将少量噪声添加到精确计数中,使其具有差分私密性。

差异隐私不能为所有敏感信息提供全面保护。

借用 McSherry 的一句话,“差别隐私是正式区分你的秘密关于你的秘密”如果您选择贡献您的秘密,DP 将以与您不贡献您的秘密相同的方式保护您的秘密。但它并不保证你的秘密会以其他方式公之于众。

考虑这个例子。你是一名数据科学家,在雨林公司(一家实行薪酬平等的虚构公司)年薪 10 万美元。雨林的人才团队希望公布数据科学家的平均收入,以吸引更多的申请人,他们已经决定使用差分隐私安全地共享这些聚合信息。你知道你的同龄人的收入与你相差不到 5k,但你从未与任何人分享过你的收入——你认为这是你的秘密。你想继续保护你的秘密,所以你选择不被包括在这个平均值中。几周过去了,你看到数据科学家的招聘信息更新为“平均工资约为 10.1 万美元”。任何阅读这份招聘启事的人都会推断出你大约挣 10.1 万美元,这是真的。所以即使你在计算中隐瞒了你的数据,你的秘密已经公开了。

再举一个例子,看看这个讲座,卡马斯讲述了为什么一个广为流传的目标市场营销的故事不是侵犯隐私。

差别隐私不是万能的。

DP 并不适用于每一种分析。这是一种量化的方式,算法会告诉你更多关于数据集中大规模趋势的信息,而不是关于任何特定个体的信息。换句话说,它旨在帮助人们巧妙地隐藏在人群中。

如果对异常值分析感兴趣,DP 就不是保护隐私的合适工具。此外,DP 不适合研究小群体。其核心是,DP 旨在允许安全地共享大量人口的汇总信息。

“有差别的私有数据”不是一个明确定义的术语。

“差异私有数据”是一个经常被提起的模糊术语。它可能有几个不同的意思,容易引起误解。我们来分解一下。

如果你读过一些介绍性材料,你可能会认为“差分私有”是一个形容词,适用于做一些聚合的算法,如求和、中值甚至神经网络,以及它们的输出。通常,隐私保护源于某种形式的校准的概率噪声添加。那么,对于产生数据记录而不是作为输出的集合的过程,噪声添加是如何工作的呢?

下面是对“差异私有数据”的几种可能的解释。

  • “差分私有数据”可以指本地 DP 算法的输出。如果您不熟悉中央 DP 与本地 DP,请向下滚动到附录。随机响应等局部 DP 算法会产生一个敏感问题(例如,你吸烟吗?).该算法是可证明的差分私有的,并且该算法产生的噪声数据库也可以被描述为差分私有的。
  • “有差别的私有数据”也可以指生成模型的输出,该生成模型用技术训练以满足有差别的隐私的标准。
    生成建模被布朗利描述为*“机器学习中的一项任务,涉及自动发现和学习输入数据中的规律或模式,以这种方式,模型可以用于生成或输出新的示例,这些示例很可能是从原始数据集中提取的。”*生成模型最常用神经网络,可以设计成符合 DP 的标准。
    差分私有生成模型的输出通常被称为差分私有合成数据。对于复杂的多变量分析,如预测建模,这些模型可以产生比随机响应更高保真的合成数据。有一个巨大的研究领域致力于开发新的技术,可以最佳地平衡高质量合成数据的需求与隐私的需求,差分隐私只是其中之一,尽管是非常受欢迎的一种。

因此,当使用差分隐私作为一个形容词来描述数据时,我鼓励你澄清所使用的算法的广泛类别,注意所产生数据的预期用途,并在适当的时候正确地将数据称为合成数据。

我希望这篇文章有助于澄清一些关于差分隐私的常见误解。如果你有任何问题或者想在 Gretel 上谈论我在应用隐私领域的工作,请给我写信 lipika@gretel.ai !

附录

中央与地方差异隐私

有两种不同的差分隐私模型—中央和本地。隐私的标准保持不变,但是区别在于数据存储在哪里以及何时出现噪声添加。

您可能熟悉中心模型,在这种模型中,所有真实、敏感的数据都可以在某个中心位置获得。例如,你和我在西雅图一家标志性的咖啡连锁店注册奖励。我们把我们的名字、电话号码和出生日期托付给他们,他们现在把这些信息储存在某个中央数据库里。如果他们想分享在晚上 7 点后订购含咖啡因饮料的顾客的年龄中位数,他们可以通过计算真实值并添加一些校准噪声来保证不同的隐私。真实的、敏感的数据仍然被不加修改地存储,并且与差分隐私无关。它是共享中值年龄(即一种算法,参见第一个误解)的过程,而不是被查询的中央数据库。

相反,本地模型是为缺乏信任或存储原始数据的中心位置的情况而设计的。例如,我的好奇的朋友乔治正在进行一项研究,关于有抱负的数据科学家完成带回家的任务是否需要比规定时间更长的时间,并要求我贡献我的数据。虽然我也同样好奇,想知道我的同行的总体信息,但我不相信乔治会透露我花了一整天完成我的最后一次带回家,尽管时间限制是 4 个小时。所以乔治告诉我掷硬币。如果是正面,我会如实回答。否则,我再次抛硬币,如果它正面朝上,我说是,如果它反面朝上,我说不是。如果乔治要求所有调查参与者都这样做,他现在就会收集到一个嘈杂版本的数据集。这个算法叫做随机化回答。收集这个嘈杂数据集的目的是聚合它,乔治通过解释第二次抛硬币引入的偏差来完成这个任务。请注意,如上所述,随机化回答是有差别的隐私(见第 3.2 节的证明)。因此,该算法是差分隐私的,并且该算法的输出,这个嘈杂的答案数据库,也可以被描述为差分隐私。

更多关于 DP 的风格和它们之间的界限,请阅读这篇文章。

集群中你应该避免的四个错误

原文:https://towardsdatascience.com/common-mistakes-in-cluster-analysis-and-how-to-avoid-them-eb960116d773?source=collection_archive---------7-----------------------

每个人都应该知道的聚类分析的关键步骤

照片由来自 Pexels 的 Pixabay 拍摄

TL;博士

  • 缺乏详尽的探索性数据分析和可消化的数据清理
  • 缺少特征缩放
  • 没有建立代表性的集群
  • 缺少分类结果的描述

答在看了大量聚类方法和分析并做了大量工作后,我想与您分享聚类分析中的四个常见错误以及如何避免它们。

错误#1:缺乏详尽的探索性数据分析(EDA)和可消化的数据清理

使用像.describe().isnull().sum()这样的常用方法是开始探索性分析的一个非常好的方法,但绝对不应该是你的 EDA 的结束。变量的更深层次(视觉)分析它们如何相互关联****至关重要。否则,异常值等异常值可能无法完全检测出来,某些变量之间的相关性也可能无法发现。这些步骤中的错误将牵连随后的特征选择步骤和聚类结果。

如果您在数据集中发现了缺失值或异常值,您通常可以选择是用巧妙的方法替换这些值(如 KNNImputer,使用平均值/中值)还是从数据集中删除它们。不管你在这种情况下决定做什么,重要的是要清楚地解释为什么你决定选择各自的方法。因此,你应该经常问自己这些问题(并证明答案的正确性):

  • 我的清理步骤对分析和建模有什么影响?
  • 如果我从数据集中删除 x%的行,这意味着什么?
  • 离群值对我的数据集有什么影响,为什么我决定保留/删除它们?
  • 这些异常值的原因是什么?

错误#2:缺少特征缩放

如果您正在使用基于距离的聚类算法,如 k-means,在应用该算法之前,标准化所使用的特征是非常重要的。这一步骤的原因在于计算聚类的方式。

稍后确定的聚类是由数学空间中数据点之间的距离(例如欧几里德距离)定义的**。数据集中的变量通常有不同的单位,因此也有不同的取值范围。例如,如果有一个变量的取值范围比另一个变量的取值范围大得多,它可能会强烈影响聚类结果。数据集中的每个变量通常也有不同的含义(例如,体重和身高),因此,变量不能直接比较(例如,1 公斤比 1 米更重要吗?).通过标准化我们的特征,我们可以通过将其转换为无单位的度量或相对距离来获得每个特征的相对权重。**

展示标准化重要性的最佳方式是使用葡萄酒数据集示例,该示例也在 sklearn 的文章“特性缩放的重要性”(链接)中使用。

如果我们看一看通常的描述性数字(tbl。1)我们不仅可以看到变量具有不同的取值范围(由于它们的单位不同),而且其中一些变量与其他变量相比具有较高的标准偏差(std)值。

表 1。我们的葡萄酒数据集的描述性分析。

例如,与其他变量如 ( 14.28 )或苹果酸 ( 1.12 )相比,变量脯氨酸具有较高的标准偏差 314.91

当比较单个变量的方差(std)时,巨大的差异变得更加明显(图 1)。

图一。按方差排序的特征方差。

很明显,与其他变量相比,脯氨酸的方差最大。

为了显示像脯氨酸这样的具有高方差的变量可能主导聚类,我们应用了主成分分析(PCA ),不使用和使用所用特征的预先标准化(图 2)。

主成分分析侧重于最大化方差的成分。如果像酒精这样的一个变量由于其各自的单位(例如体积百分比毫克/升)而比另一个变量(例如脯氨酸)变化更小,如果这些特征没有被缩放,则 PCA 可以确定最大变化的方向与脯氨酸轴更紧密地对应。

图二。缩放和不缩放的特征及其对 PCA 的影响。

未缩放的情况(图 2 中的第一行)中,具有最高方差脯氨酸 的特征主导方向,这导致数据点的噪声聚类。

虽然您可以在缩放案例(图 2 中的第二行)中看到,对于所有特征来说,t 的幅度大致相同,并且数据点的聚类在这里要清晰得多**。**

我希望这个例子向您清楚地展示了为什么特征缩放对于基于距离的聚类算法(如 k-means)如此重要,尽管丢失特征缩放并不是常见聚类分析中的唯一错误。

错误 3:没有建立有代表性的集群

另一个非常常见的错误是没有建立有代表性的集群。我这么说是什么意思?一些聚类结果可能如下所示:

图 3。无代表性集群的示例。

与簇 1 和 2 相比,簇 0 的大小明显更小。当然,在某些情况下,这样的结果可能是有效的**,如果在那个**后面有可理解的推理的话。

然而,这种情况通常是例外的,并且每个聚类的相对相等数量的数据点应该总是针对。通常错误在于或者是缺少特征缩放/选择或者是选择的聚类数量

在 k-means 中你通常可以使用肘方法或者剪影评分方法来确定合适的聚类数(图 4)。

图 4。肘部和轮廓评分法。

使用肘方法,您计算多个聚类 K 的失真(即从聚类中心到各个聚类的平方距离的平均值)或惯性(即样本到其最近的聚类中心的平方距离的总和)。然后,在一个图表中,将变形/惯性值与聚类数 K 一起可视化。在失真/惯性开始线性下降后,通过寻找图中的扭结或肘状点**,从视觉上确定最佳集群数。看看我们的例子,这意味着 3 是最佳集群的数量。**

除了肘图法,还可以使用**(平均)剪影评分法**。

至于肘图法,我们也对几个聚类大小 K 运行 k-means。但我们不是计算失真/惯性,而是计算每个 K 的轮廓系数

轮廓系数定义为:(x-y)/max(x,y)。

其中 y 代表平均类内距离(即从一个点到同一类中其他点的平均距离)。而 x 表示平均最近聚类距离(即,到下一个最近聚类的点的平均距离)。

计算完成后,我们绘制系数值和聚类数 K,以直观地确定合适的聚类数。在这里,我们为选定数量的 K 个集群寻找全局最优值(即图中的最高点)。至于肘图,轮廓系数图的最佳聚类数将是 3。

在应用了具有确定的最佳聚类数的聚类之后,您应该查看一下聚类结果。

关注属性非常有用,例如:

  • 集群基数
  • 集群星等
  • 数量与基数

下图 5 显示了上述属性以及使用 PCA 的聚类可视化。

图 5。我们的集群、集群基数、数量和数量与基数的关系的可视化。

群集基数或群集大小图显示了每个群集的点数。您可以使用此图表来查看某些分类包含的数据点是否明显少于或多于其他分类。在我们的示例中,每个集群的数据点分布看起来不错。

群集幅度图显示了每个群集的总点到质心的距离。此图表可用于查看每个聚类中的点的“分布”有多高,以及是否有任何簇或宽簇。

基数对数量图比较了集群基数和集群数量。基数较高的聚类往往也具有较高的聚类数量级。这个想法是正常的星团位于或非常接近 45 度线上。异常往往离它更远。在我们的例子中,群集 1 是异常的。

我强烈推荐你看看谷歌开发流程图(链接)来检查你的集群质量。

图 6。流程图“如何检查你的聚类质量”(作者 Google Dev )。

错误#4:最后但同样重要的是:缺少对集群特征的描述

这可能是聚类过程中最重要的一步:描述我们的发现。不幸的是,这一步大多被忽略了。

我们的目标是以一种非技术人员一眼就能理解的方式描述每个集群。

你应该回答的问题是:

  • 哪些特征代表了每个分类?
  • 哪些特征区分了我的集群?

一个快速简单的解决方案是计算每个聚类的每个特征的平均值(tbl。2).

表二。每个聚类的每个特征的平均值。

像这样的表格为读者提供了每个聚类中的特征看起来如何的第一概述。例如,我们可以看到,与其他聚类相比,聚类 1 包含较高的脯氨酸和镁值。

作为绝对值的替代方法,您也可以计算相对差异(tbl。3).在这种情况下,计算每个聚类的每个要素与每个要素的总体平均值的相对差异(百分比)。

这意味着,例如,值为 619 时,聚类 0 中的特征脯氨酸与特征脯氨酸的总体平均值(743)相差-17%(=(743–619)/743)。

表 3。每个聚类的每个特征相对于每个特征的总体平均值的差异百分比。

除了表格可视化之外,绘制结果图通常也很有帮助。根据聚类和特征的数量,不同的可视化选项是合适的。

例如,其中之一是在单独的图表中显示每个特征的平均值的相对差异(图 7)

图 7。每个特征与平均值的相对差异显示为条形图。

但是,如果您必须处理许多功能,很容易很快失去对概览的关注。

另一个可视化选项是用雷达图而不是条形图来显示集群特征(图 8)。

图 8。以雷达图形式显示的每个特征平均值的相对差异。

聚类及其特征或与平均值的相对偏差显示为彩色区域。根据集群的数量,单个集群的特征可以一眼快速识别。

C 光泽分析是一种(无监督的)方法,它将没有标记或分类的数据进行分组。因此,我们有责任使用正确的应用方法和最佳实践程序在数据中找到可解释和可理解的模式。但是在我们对数据进行聚类之前,不仅适当的 EDA 和清理是必不可少的,而且特性缩放也是必不可少的。一旦我们建立了我们的集群,我们必须确保这些结果不仅具有代表性,而且对于(商业)用户来说是可以理解的。

我希望这篇文章有助于填补一些空白,并为您的下一次聚类分析提供有用的提示。

数据科学简历中的常见错误

原文:https://towardsdatascience.com/common-mistakes-on-a-data-science-resume-d82a446871a2?source=collection_archive---------38-----------------------

以及如何修复它们

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

有很多好的方法来制作一份简历。也有很多不好的方式。

特别是对于数据科学,初级职位的申请人数往往过多,拥有一份好的简历是极其重要的。

最重要的是保持一份简洁、易于浏览的简历。如果你的简历是数百份简历中的一份,你不想强迫拿起它的人去读大段。他们的眼睛会变得呆滞,什么也看不见。

如果你的简历的优点不能很快地被发现,没有人会花时间去更深入地研究并发现真正存在的价值。

明确。简明扼要。

以下是我在初级求职者的简历中看到的一些常见错误:

1.在顶部有一个很长的“目标”(或“总结”)

在简历上写“目标”是为了给你的职业目标提供一些背景。

实际上,大多数目标陈述读起来都非常相似。

这并不奇怪——每个申请相同职位的人都有相似的职业目标。此外,人们倾向于列出他们认为招聘人员/招聘经理想听的话,这导致了很多模糊的商业对话。他们往往只是含糊其辞地说希望使用数据来创造商业价值,并希望提高自己的技能,成为更好的数据科学家。

除了没有太多的信息外,目标章节往往是叙述式的,而不是结构化的,这使得它们很难浏览

因此,许多招聘人员说他们不阅读目标部分就不足为奇了。他们往往没有太多的信息,阅读他们比浏览简历的其他部分需要更多的努力。当你有数百份简历要处理时,你没有时间去阅读冗长的“客观”部分。

如果你确实想在你的简历顶部有一些东西(无论是目标还是总结),给你的简历提供背景,保持简短,并确保它真正传达了有意义和重要的信息。

2。列出不必要的技能/工具

同样,保持简历简短,不要列出不必要的技能。

有一些工具被认为是数据科学的核心。确保你清楚了解标准数据科学技术堆栈(例如 Python、pandas、sklearn)、统计学和机器学习。列出工作资格中特别要求的技能,或与之相关的技能。

不要列出招聘信息中没有提到的具体技术。列出一大堆技术可能感觉不错。克制自己。它看起来很臃肿,而且很难找到真正相关的工具。

如果你想表现出你懂一些技术,那就提一般技能而不是工具。比如列出“贝叶斯建模”而不是“PyMC3,Stan,rjags”。这不仅有助于减少空间浪费,也让那些审查你简历的人更容易,因为他们不需要知道所有这些工具是什么。

但是要确保你有节制地使用招聘启事中没有提到的技能。

3.其他不必要的信息

简历上的空间很重要。不要把它浪费在不必要的事情上:

  • 完整邮寄地址。他们不会通过给你寄信来联系你
  • 相关课程作业的课程编号。这些数字在大学之外没有任何意义。不要包括他们。如果你缺乏任何证明核心技能的经验,只包括“相关的课程工作”。
  • **你的 GitHub 个人资料,如果你实际上什么都没有的话。**分享你的 GitHub 个人资料很棒,但是你不能因为拥有个人资料而获得积分。如果你列出来,确保如果我去那里,我可以找到一些实际的项目。

保持你的简历简洁。

4.简历太长了

与最后三条建议相一致的一般原则是:不要写太长的简历。即使在高级/领导级别,一页通常也足够了。

如果你刚刚进入这个领域,一页就足够了。

我听说过一个有用的思考方式:你的简历的价值是根据简历内容的平均质量来判断的,而不是总和。

显然,这一经验法则是有局限性的——不要仅仅把最令人印象深刻的一件事放在简历上,就认为这就够了。但一般来说,增加更多可能会让你觉得自己听起来更有价值,但很容易降低你的感知价值。

5.对项目或工作职责的模糊描述

一个人越能描绘出一个项目或工作中所涉及的内容,他们就越容易将你所申请的职位与他的职责相提并论。

避免模糊的术语,明确你使用的工具,如果你发现很难简明清晰地描述一个项目或职责,考虑一下它是否需要存在。你不必列出你曾经做过的每一个项目或责任。花点空间好好解释一下重要的。不要因为担心自己做得不够,而在填充职责上浪费空间。

6.没有上下文的项目的绩效指标

这是一个非常具体的数据科学问题。在一个项目上经常看到“建立了一个 AUC 为 0.76 的模型”。这样好吗?我不知道。

没有上下文的绩效指标毫无意义。

也许你正在解决一个众所周知的问题,并且你假设阅读它的人有上下文。也许在某些(罕见的)情况下,这是可以的。但是一般来说,您需要为性能指标提供一些上下文。

这是对以前使用的方法的改进吗?很好,告诉我改进了什么(至少说明一下是如何实现的)。

你能量化它的商业价值吗?太好了,告诉我这对公司有多大影响。

如果你做不到这两点,那就好好想想,如果没有任何额外的背景,你的绩效指标是否真的有意义。

我希望这些建议有所帮助!以下是一些你可能感兴趣的其他文章:

处理多个 Python 文件时的常见错误

原文:https://towardsdatascience.com/common-mistakes-when-dealing-with-multiple-python-files-b4f4dc4d5643?source=collection_archive---------3-----------------------

Python 中的“模块”概念

照片由 Daniela Holzer 在 Unsplash 上拍摄

在最简单的情况下,我们在单个 Python 文件中编写代码(文件名以。py)。我们运行它,一切都像预期的那样工作,我们很高兴。然而,当您必须将代码分成多个 Python 文件时,事情会变得有点复杂,通常是为了更容易的代码管理和可读性。在这篇文章中,我将带你走过我陷入的一些常见错误,我希望你不要犯和我一样的错误。

在 Python 中,每个 Python 文件实际上都有一个称为“模块”的特定术语,当您使用著名的import语法时,您正在几个不同的 Python 模块之间建立连接,以在您的上下文中完成复杂的任务。在此,我将阐述以下主题:

  1. 每个文件都有自己的全局变量
  2. 该函数总是记得它是在哪里创建的
  3. Python 是“按引用传递”的
  4. 使用一个单独的文件来保存跨多个 Python 文件的全局变量

如果你想进一步了解它们,请继续阅读!

每个模块/文件都有自己的全局变量

当您在 Python 文件中创建一个变量(不在函数中)时,您将这个变量挂载到当前模块的名称空间中。这个 Python 文件中的每个命令都可以访问、读取和修改变量的值,也就是说,它变成了一个全局变量。你也可以通过声明一个变量global.来明确地在函数中定义一个全局变量

将局部变量设为全局变量(图片由作者提供)

然而,全局变量不能在不同的 Python 文件之间共享。为了说明这一点,让我们看下面的例子:

全局变量对于每个模块都是唯一的(图片由作者提供)

逻辑非常清晰,我在sub_module.py中定义了一个函数,并尝试在main.py文件中调用它。好像我在main.py文件中定义了变量num=5,但结果是函数不能访问它,原因是sub_module.py不能访问其他 Python 模块中的全局变量,所以num=5对程序是不可见的。怎么修?在正确的文件中定义num即可。

在 sub_module.py(作者图片)中定义一个变量

Python 函数总是记得它被创建的位置

我不确定你是否对上面的例子感到困惑?当我第一次看到这个例子时,我确实这么做了,因为我将sub_module.py中的test_func1显式地导入到了main.py中,很自然地认为该函数已经在当前作用域中了,不是吗?

但是 Python 函数总是知道它是在哪里创建的。尽管看起来test_func1main.py中,但当被执行时,它仍然属于sub_module.py,因为这是它被创建的地方。现在来看另一个有用的实用技巧:

记得在子模块中导入必要的包!

忘记在子模块中导入数字(图片由作者提供)

在上面的例子中,由于我们忘记在sub_module.py中导入 NumPy 包,即使我们在main.py中导入了它,它仍然不能被test_func1访问。现在让我们来解决它:

在子模块中导入 Numpy 包(图片由作者提供)

通过引用传递与通过值传递

第一个例子是可行的,但是看起来很奇怪,不是吗?通常,我们将只在子模块中定义函数和类,而不是放入单个变量num=5。解决这个问题的常见方法实际上是在test_func1中添加num作为参数,并且在main.py文件中调用函数时也将num=5传递给该函数。

将变量作为参数传递(图片由作者提供)

现在的问题是,这样做如何能让sub_module.py识别出num在哪里?是因为 Python 总是传引用而不是**传值。**为了说明这一点,让我们来看看调用该函数时实际发生了什么:

通过引用传递与通过值传递(图片由作者提供)

当你在main.py中键入num=5时,你基本上创建了一个驻留在一块物理内存中的整数类型的PyObject,你用名字num指向这块物理内存。既然 Python 总是通过引用传递,那么你可以想到test_func1就会知道num这个名字指向哪里。因此,它可以访问value 5,因为它知道这个值在哪里。

我可以在不同的文件中共享一个全局变量吗?

正如我们所讨论的,全局变量对于它自己的模块是唯一的。但有时我们真的希望有一个全局变量,可以被目录中的每个 Python 文件访问和修改。实现这一点的规范方法是用全局变量创建另一个文件。

保存全局变量的独立文件(图片由作者提供)

我故意把这个例子弄得有点复杂;这里我们有一个包含num=10gloabl_.py python 文件。但是在main.py文件中,我也创建了一个num=5。虽然它们都被命名为num,但是它们在不同的范围内,所以它可以告诉你它们的区别。在main.py中,我们通过增加 1 来修改这个全局变量,这个变化也将反映在sub_module.py中。注意这里我必须在 **test_func2** 函数中导入 **global_** ,因为如果我把导入语法放在开头,那么导入的num将是在global_.num += 1行执行之前的那个。记住, **sub_module.py** **from sub_module import ***行中被执行,我们可以在下面的例子中测试它:

导入语法的顺序很重要(图片由作者提供)

如你所见,现在即使全局变量num增加了 1,它也没有反映在sub_module.py中,因为它们导入的变量来自操作之前。导入的时候,Python 会自动为你做一个拷贝,这样旧的global_.num和新的global_.num就生活在完全不同的物理内存中了。

结论

以下是处理多个 Python 文件时的一些最佳实践:

  1. 将变量作为参数传递,因为 Python“通过引用传递”,这保证了你的子模块可以访问你传递的变量。
  2. 不要忘记在子模块中导入必要的包,因为函数总是记得它是在哪里创建的。
  3. 使用一个单独的文件来保存 Python 模块中的全局变量,但是要记住导入全局变量将会复制原始变量,所以要经常检查你是否在程序中引用了正确的变量。

差不多就是这样!我希望你觉得这篇文章有趣和有用,感谢阅读!如果你喜欢这篇文章,请在 medium 上关注我,非常感谢你的支持。在我的 Twitter 或 LinkedIn 上联系我,也请让我知道你是否有任何问题或你希望在未来看到什么样的教程!

常见电话面试问题—第一部分

原文:https://towardsdatascience.com/common-phone-interview-questions-part-1-bfe394346afb?source=collection_archive---------18-----------------------

一些公司会进行一轮电话面试,他们会从你的简历中问你一些问题以及一些简单的技术问题。我试着列出了这些问题。如果你是技术新手或者想复习一些概念,这也会对你有所帮助。

马库斯·斯皮斯克在 Unsplash 上的照片

1。线程与进程。

进程是程序的实例,线程是进程的子集。进程和线程都是独立的执行序列。

  • (同一进程的)线程运行在共享内存空间,而进程运行在独立的内存空间。因此,线程有自己的堆栈(局部变量),但共享同一个堆。进程有独立的堆栈和堆。
  • 线程可以通过共享内存高效地进行通信。它们可以使用存储在堆中的对象进行通信,其中每个线程都可以访问相同内存位置的相同对象。进程使用进程间通信(IPC ),操作系统必须参与其中。
  • 线程比进程花费更少的时间来创建和终止,因为它们消耗更少的资源。
  • 在单处理器系统上,应用线程调度算法,并且调度处理器一次运行一个线程。因此,线程是并发的,而不是每个处理器并行的。

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

2.数据竞争:

当多个线程运行同一个程序,并且两个或多个线程同时访问同一个共享变量时,就会发生数据竞争。它会导致不可预测的输出,有时当结果不理想时会引起问题。

一个例子是:

理想场景:我们希望将初始值为 0 的变量的值递增 1,递增两次,有两个线程为我们做这件事。最终的结果应该是变量的值变成了 2。

来源:https://en.wikipedia.org/wiki/Race_condition

如果两个线程都读取原始值,然后重写它,最终结果将是错误的,这可能是我们程序中的一个主要错误。

资料来源:https://en.wikipedia.org/wiki/Race_condition

可以通过引入锁来防止数据竞争。这样,当一个线程访问变量以更新其值时,变量的访问将被锁定,直到该线程完成其操作。因此,在第一个线程完成更新之前,另一个线程将不得不“等待”,并且不能访问、读取或更改变量值。

但是,如果不小心使用锁,它们会导致死锁。

3.死锁:

这是一种两个或多个线程因为相互等待而被永久阻塞的情况。它会导致线程挂起,并有可能导致整个进程挂起。

4.面向对象编程的四大支柱:

馅饼:抽象、多态、继承、封装

抽象:抽象类和方法

  • 你可以记住“抽象”这个词是什么意思,它是抽象这个词的一部分。
  • 用于向用户隐藏复杂的细节,使用户能够使用程序或在上面实现更复杂的代码,而不用担心/知道当前程序所涉及的复杂性。
  • 它是通过使用抽象类和方法来实现的。
  • 抽象类是我们可以声明抽象方法的类。抽象方法是没有主体的方法,只有名字,没有实现。
  • 一个经典的例子是具有抽象区域方法的抽象形状类。这个类的孩子(圆、三角形等)将有不同的方法来实现这个面积方法。

多态:重写和重载

  • 你可以通过“poly”这个词来记住它,在希腊语中它的意思是很多。通过使用覆盖和重载,同一个方法在不同的子类中可以有“许多”形式。

I:继承:扩展,父类和子类

  • 你可以记住这一点,记住你继承了你父母的特征,如头发和眼睛的颜色等。类似地,继承是子类接收或继承其父类的属性的过程。
  • “extends”关键字用于由子类(子类)继承任何超类(父类)的属性。这有助于提高可重用性,减少代码长度,并防止用户重复编写相同的代码。

e:封装:Getters 和 Setters

  • 您可以通过将单词 encapsulation 与“封装”相关联或者将方法和变量包装在一起从而隐藏数据来记住这一点。
  • 当您将变量声明为私有变量并使用 getters 和 setters 来提供对它们的访问时,就会出现这种情况。
  • 这有助于控制在我们的类的字段中存储什么,有限制以及使某些元素只读或只写。

5.为什么我们需要 OOPS(面向对象编程系统)?

面向对象的编程语言是那些在编程中使用“对象”概念的语言。要回答这个问题,你可以先说“哎呀”,这有助于有效和容易解决问题。它们使复杂的代码更容易理解和维护。然后,您可以谈论以下概念:

  • 对象:代表现实生活中的实体的任何东西
  • 类:对象的蓝图
  • 方法:几行代码聚集在一起执行一些任务,它们可能接受也可能不接受输入并提供期望的输出。

然后讨论上面提到的四个支柱及其好处。

这应该足以表明你对面向对象编程有透彻的理解。

这就是第 1 部分的内容!如果您觉得它有帮助,请告诉我,如果有问题或博客主题建议,请在我的社交网站上与我联系。感谢您的阅读!

编辑:你可以和我建立一对一的职业辅导,我可以通过分享我的精确策略、修改你的简历、求职信或 Linkedin 简介来帮助你获得实习机会。你可以去 anjaliviramgama.com 看评论和安排时间

安贾利·维拉加马

脸书软件工程实习生,即将成为微软软件工程师

领英|insta gram

SQL 中的 cte:数据科学家编写更好 SQL 的 5 个技巧

原文:https://towardsdatascience.com/common-table-expressions-5-tips-for-data-scientists-to-write-better-sql-bf3547dcde3e?source=collection_archive---------19-----------------------

从 SQL Server 到 Google BigQuery:了解我为什么喜欢常用表表达式。

授权给作者的图像

这是我从事 SQL 工作的第 20 个年头(eek!).为了纪念这个里程碑,我最近写了一篇关于我所遵循的 10 个 SQL 命名标准的文章,我觉得这些标准可以产生易于阅读、调试和维护的 SQL。

</10-sql-standards-to-make-your-code-more-readable-in-2021-4410dc50b909>

按照这个主题,我想我应该探索一下 SQL 语言的其他元素,帮助区分出色的 SQL 和简单的函数式 SQL。

我列表中最重要的一个元素是通用表表达式,简称 CTE。cte 于 2000 年首次推出,现在广泛应用于大多数现代数据库平台,包括 MS SQL Server、Postgres、MySQL 和 Google BigQuery。

我在示例中使用了 Google BigQuery,但是 cte 的语法与您可能使用的其他数据库平台非常相似。我使用了桑坦德循环雇佣计划数据集,这是谷歌公开数据集的一部分。

给 BigQuery 用户一个快速提示——如果你想知道为什么我的 BigQuery UI 看起来和你的不一样,我使用的是 2021 年的更新 UI,刚刚在预览版中发布。如果你想知道我对新特性的看法,可以看看我几天前发表的文章。

</5-great-features-in-bigquerys-new-ui-for-2021-yes-it-has-tabs-c4bac66d66b>

有哪些常见的表格表达式?

对于那些不熟悉 CTE 的人,或者刚刚开始数据科学职业生涯的人,CTE 是 SQL 查询的临时结果集,您可以在更广泛的 SQL 查询的其他部分引用它,就好像它是数据库中的永久表一样。CTE 是临时的,只在更广泛的查询执行期间存在。您可以为 cte 起别名(命名),类似于为表或列起别名,并且每个查询可以有多个 cte。

下面是基本语法:

with **employee_cte** as (select first_name, last_name from employee)select e.first_name,
       e.last_name,
       h.hire_date
from **employee_cte** e
  inner join employee_hire h
  on h.employee_id = e.employee_id

遵循我的 5 个建议,希望到最后,你会有一些好的最佳实践来开始自己探索它们。

所以,不分先后,我们开始吧。

#1 避免重复的列转换

在此查询中,我想查找伦敦市中心 500 米范围内的所有自行车站点,并返回站点名称和到中心的距离:

select name as station_name,

 **st_distance
       (
        st_geogpoint( longitude, latitude),
        st_geogpoint(-0.118092, 51.509865)
       )**    as distance_from_city_centre_mfrom `bigquery-public-data.london_bicycles.cycle_stations`
where **st_distance
(
 st_geogpoint( longitude, latitude),
 st_geogpoint(-0.118092, 51.509865)
)** <= 500
order by distance_from_city_centre_m

虽然这是完美的功能,并返回正确的结果(下面,如果你好奇!),您会注意到以粗体显示的用于计算距离的逻辑是重复的。这是我们想要避免的;逻辑应该被定义一次**,如果需要的话,使它更容易阅读和修改。**

这就是 CTE 来拯救我们的地方:

**with stations**
as
(
  select name as station_name,
         st_distance
         (
           st_geogpoint( longitude, latitude),
           st_geogpoint(-0.118092, 51.509865)
         ) as distance_from_city_centre_m
  from `bigquery-public-data.london_bicycles.cycle_stations`
)select station_name,
       distance_from_city_centre_m
from **stations**
where distance_from_city_centre_m <= 500
order by distance_from_city_centre_m

不再有重复的逻辑。而且,我认为这也比第一个查询更容易阅读——你认为呢?

因为我的 CTE 站是临时的,我不需要用任何物化的(永久的)表格或视图来填充我的数据库。

自行车租赁站,距离伦敦中心 500 米以内

#2 简化复杂的 SQL (KISS)

就像在编程的其他领域以及生活中一样,如果你尽可能地保持简单,这真的会有所帮助。我们可以在 SQL 代码中使用 cte 来实现这一点的一种方法是使用 cte 作为一种将复杂的 SQL 查询分解成个更小的小块的方式。这会产生 SQL,它是:

  1. 更容易阅读和理解
  2. 更容易调试;您分阶段构建 SQL,在继续下一步之前测试每个 CTE 的输出。
  3. 更容易维护;改变逻辑现在可以在一个地方以一种更加模块化的方式完成。

在本例中,我想进一步探索距离市中心 500 米以内的车站,并挑选出在过去 12 个月中旅程最多的车站。然后,我想提取所有比这多的其他车站,并分析它们与市中心的距离。

实现这一点的一种方法(没有 cte)如下:

select  s.name    as station_name,
        st_distance
        **(
          st_geogpoint( s.longitude, s.latitude),
          st_geogpoint(-0.118092, 51.509865)
        )**         as distance_from_city_centre_m,
        count(j.rental_id) as journey_count
from `bigquery-public-data.london_bicycles.cycle_stations` s
  inner join  `bigquery-public-data.london_bicycles.cycle_hire` j
        on j.end_station_id = s.id
        and cast(j.end_date as date) >= date_sub('2017-1-1', interval 1 year)
group by station_name, s.longitude, s.latitude
having count(j.rental_id) > 
(
  select journey_count
  from
  (
    select  dense_rank() 
            over (order by count(j.rental_id) desc) as rank,
            s.id                                    as station_id,
            count(j.rental_id)                      as journey_count
    from `bigquery-public-data.london_bicycles.cycle_stations` s
        inner join  `bigquery-public-data.london_bicycles.cycle_hire` j
        on j.end_station_id = s.id
        and cast(j.end_date as date) >= date_sub('2017-1-1', interval 1 year)
    where j.end_station_id in
    (
      select  s.id     as station_id
      from `bigquery-public-data.london_bicycles.cycle_stations` s
      where **st_distance(
              st_geogpoint( s.longitude, s.latitude),
              st_geogpoint(-0.118092, 51.509865)
            )** <= 500
    )
    group by station_id
  )
  where rank = 1
) 
order by journey_count desc

再说一遍,这是完美的功能代码。然而,有重复的逻辑(粗体),我觉得这很难阅读。此外,如果我必须调试它,这将是很困难的——例如,验证最繁忙的工作站,因为一切都是交织在一起的。

应用 cte,我们可以大大改进这一点(cte 以粗体显示):

**with station_proximity**
as
(
  select  id              as station_id,
          name            as station_name,
          st_distance(
            st_geogpoint( longitude, latitude),
            st_geogpoint(-0.118092, 51.509865)
          )               as distance_from_city_centre_m from `bigquery-public-data.london_bicycles.cycle_stations`
),**station_journeys** 
as
(
select  s.station_id,
        s.station_name,
        s.distance_from_city_centre_m,
        count(1)    as journey_count
from **station_proximity** s
  inner join  `bigquery-public-data.london_bicycles.cycle_hire` j
  on j.end_station_id = s.station_id
  and cast(j.end_date as date) >= date_sub('2017-1-1', interval 1 year)
group by s.station_id, s.station_name, s.distance_from_city_centre_m
),**stations_near_centre**
as
(
  select  sp.station_id,
          sj.journey_count,
          dense_rank() 
            over (order by sj.journey_count desc) journey_rank,
  from    **station_proximity** sp

  inner join **station_journeys** sj
  on sj.station_id = sp.station_id
  where   sp.distance_from_city_centre_m <= 500
)select station_name,
       distance_from_city_centre_m,
       journey_count
from   **station_journeys** 
where  journey_count >
(
  select journey_count
  from   **stations_near_centre** s
  where  s.journey_rank = 1
)
order by journey_count desc

我觉得这个更好读。如果我想对此进行调试,我可以很容易地将最终选择改为从每个 CTE 中依次选择,在进入下一个之前进行验证。

(如果你感兴趣,下面是结果。正如你所料,这些车站大多数都靠近铁路干线)

#3 命名很重要

我的第三个建议是在给你的 cte 命名时要小心。

在我前面的例子中,我注意用有意义的名称来命名我的 cte:

**with station_proximity**
as
( --- ),**station_journeys,**
as
( -- ),**stations_near_centre**
as
( -- )

我经常看到这种情况,如果可能的话,我会尽量避免:

**with cte1**
as
( --- ),**cte2,**
as
( -- ),**cte3**
as
( -- )

#4 非常适合 SQL 联合

在处理数据时,我们经常需要将不同来源的数据整合到一个符合表中。

cte 非常适合这个用例。

假设我们在两个系统 A 和 b 中进行循环旅程。我们可以在编写代码时有效地使用 cte 来填充单个旅程表,如下所示:

**with system_a_journeys**
as
( some data wrangling of system a ),**system_b_journeys,**
as
( some data wrangling of system b),**all_journeys**
as
(
  select *
  from **system_a_journeys** union allselect *
  from **system_b_journeys** )

**注意我从不提倡使用 select (显式列出列)。

#5 使用 cte 显示依赖性

cte 的另一个可以提高 SQL 可维护性的新用途是,使用它们可以很容易地看到 SQL 引用了哪些表/视图。这对于复杂的查询特别有用,它跨越许多行,并引用许多表/视图。

为此,在 SQL 语句的开头,为您选择的所有表/视图创建 CTE“包装器”。您还可以将列限制为您实际使用的列,这不仅有助于识别您正在使用的列,还可以提高性能。

因此,在我的技巧 2 的例子中,我将从以下内容开始查询:

with cycle_stations as 
(
  select id    as station_id,
         name  as station_name,
         longitude,
         latitude
  from `bigquery-public-data.london_bicycles.cycle_stations`
),cycle_journeys as
(
  select station_id,
         end_date
  from `bigquery-public-data.london_bicycles.cycle_hire`
)

结论

希望通过阅读本文,您现在已经了解了常见的表表达式,以及如何使用它们来真正提高您的 SQL 写作。

cte 是我个人日常使用的工具,也是 SQL 工具箱中帮助可读性和可维护性的最佳工具之一。它们还使得编写 SQL 更加实用,因此是一种愉快的体验。

希望你同意:)

后续步骤

1.了解更多关于安科瑞斯数据,分析&人工智能

一个永远改变了我编写查询方式的技巧

原文:https://towardsdatascience.com/common-table-expressions-in-sql-c6dd317e1121?source=collection_archive---------10-----------------------

利用通用表表达式来简化复杂查询的编写和故障排除

Jan Antonin Kolar 在 Unsplash 上拍摄的照片

什么是常见的表表达式

当编写复杂的查询时,为了可读性和调试,将它们分成更小的块通常是有用的。通用表表达式(cte)提供了这种能力,我发现它们是我的 SQL 工具箱中最有用的工具之一。

cte 实现起来非常简单。他们以一个简单的WITH陈述开始,你要去的新 CTE 的名字SELECT。他们是这样开始的:

WITH
    cte_name AS (
        SELECT
            ...
    )

美妙之处在于,您可以将多个 cte 链接在一起,数量不限。让我们看看他们中的一些人会是什么样子。

WITH
    cte_name AS (
        SELECT
            ...
    ),

another_cte AS (
    SELECT * FROM foo
    JOIN cte_name ON cte_name.id = foo.id
)

SELECT * FROM another_cte
LIMIT 10

这很好地说明了这个概念。第一个 CTE 运行第一个查询并将其存储在名为cte_name的内存中,第二个 CTE 将cte_name表连接到第二个 CTE 中的foo表。您可以以多种方式使用这种模式,但是它通过将复杂的查询分解成逻辑部分来简化构造。

**注意:**需要注意的一件小事是在第一个 CTE 分隔每张表之后,在哪里。

最后,通过在生成的 CTE 上运行一个独立的SELECT语句来完成这个过程。

当然,强大的功能是运行复杂得多的逻辑。每个 CTE 可以包含许多SELECT语句、JOIN语句、WHERE子句等。为了可读性和可理解性,使用它们来组织您的查询。

**提示:**为了方便调试或构建您的查询,您可以通过简单地注释掉剩余的代码并在每个 cte 之后运行 select 来测试每个 cte。像这样。

WITH
    cte_name AS (
        SELECT
            ...
    ) --, Make sure to comment out the comma

SELECT * FROM cte_name
LIMIT 10

-- another_cte AS (
--     SELECT * FROM foo
--     JOIN cte_name ON cte_name.id = foo.id
-- )

-- SELECT * FROM another_cte
-- LIMIT 10

现实生活中的例子

我为在雪花中创建的视图编写了一个查询。如果没有 cte,这将会变得更加困难。

WITH DAILY as (
    SELECT ID
    FROM "LOGS_DAILY"),
MAP AS (
    SELECT SOURCE_ID AS ID, ANY_VALUE(UUID) AS UUID
    FROM "CONTACT_MAP"
    WHERE SOURCE_ID_NAME = 'ID'
    AND DT = (SELECT MAX(DT) FROM "CONTACT_MAP")
    GROUP BY SOURCE_ID),
CONTACT AS (
    SELECT CONTACT_UUID, SITE_UUID
    FROM "CONTACT_MASTER"
    WHERE DT = (SELECT MAX(DT) FROM "CONTACT_MASTER")),
ACCOUNT AS (
    SELECT *
    FROM "ACCOUNT"
    WHERE SITE_STATUS = 'Active')
SELECT DISTINCT *
FROM DAILY
LEFT JOIN MAP ON MAP.ID = DAILY.ID
LEFT JOIN CONTACT ON CONTACT.CONTACT_UUID = MAP.CONTACT_UUID
LEFT JOIN ACCOUNT ON ACCOUNT.SITE_UUID = CONTACT.SITE_UUID
LIMIT 100

结论

公共表表达式(cte)是查询工具箱中的一个强大工具,它允许您获取复杂的、分层的 SELECT 语句,将它们分解成更易于管理的块,然后最终将它们组合在一起。如果你今天没有使用它们,试一试,我相信它们会成为你经常去的地方!

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。一个月 5 美元,让你可以无限制地访问成千上万篇文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

数据科学中的常用词

原文:https://towardsdatascience.com/commonly-used-words-in-data-science-ea06a8f17577?source=collection_archive---------18-----------------------

定义数据科学术语

莫里茨·金德勒在 Unsplash 上拍摄的照片

在浏览在线和中级数据科学的文章和教程时,我注意到大多数文章和教程更适合中级开发人员以及更高级的开发人员。即使有一些初学者友好的教程,也有一系列使用的术语,不是每个人都知道。因此,今天这篇文章的目标是回顾术语,为数据科学的广阔世界增加一些清晰度。

这不会是一个完全全面的列表。我们可以研究的术语太多了。但它会有一些重要的,只是不是所有的,因为信息量太大。但是如果有任何你认为应该包含的重要词汇,请随意在评论中添加。

数据科学

先解释一下我们在这里的全部原因是合适的。数据科学是对数据的分析,通常是大量的数据。目标是为这些信息提供意义,以解决问题或做出决策。它包括数据的实际研究、数据本身、可视化、预测、决策过程等等。

大数据

我将大数据包括在列表中的原因是,“大数据”听起来像任何大量的数据。那么大数据到底有多大?大数据是指任何大到无法存储在单台计算机上的数据。这意味着它对于 SQL 或 Excel 之类的东西来说也太大了。从数据中获取有意义的信息需要更多的努力,因为单个查询的处理速度很慢,可能需要数周时间。这就是为什么通常它对于 SQL 来说太大了。

但不仅仅是数据的大小。这也是数据生成的速度。大数据遵循摩尔定律,即计算能力每两年翻一番。

数据挖掘

面对如此庞大的数据,一定有办法从中获取有意义的信息。这就是数据挖掘的用武之地。数据挖掘是指在给定一组数据的情况下,确定变量及其结果之间的关系。通常,这是由机器大规模完成的。它还涉及数据的清理和组织。理想情况下,它可以用那些太大而无法排序和描述的数据来帮助决策。这样的任务包括回归和分类,我们稍后会讲到。

在寻找数据中的意义时,数据挖掘可以搜索频繁模式、相关性、聚类、关联或任何可以进行的预测分析。

数据仓库

数据仓库是数据的存储库,无论是当前数据还是历史数据。这是数据挖掘或决策支持发生的环境。这是一个可以快速分析数据的系统。

数据建模

当您进行预测和分析数据时,您需要某种方式来可视化这些数据。数据建模是以书面或文档格式将数据可视化。换句话说,您创建了一个基于数据的模型。这些模型有助于解释过程的结果。

数据可视化

数据建模讲的是创建模型。数据可视化符合并详细描述了该模型。例如,数据可视化可以是以条形图、饼图、直方图等形式查看数据。甚至基于用例的漫画也可以被认为是数据可视化。它包含所有形式的可视化数据。

数据治理

当您处理如此多的数据时,必须有一些规则来确保完整性和安全性。因此,数据治理是存在的。听起来,数据治理就是管理或治理数据。这包括规则、法规、政策,甚至是围绕数据设置的有助于以某种方式管理数据的操作。这些规则必须符合法律和公司政策。

数据治理的规则有助于保护数据,确保数据的完整性,甚至保持数据的相关性。

数据角力

快速整理大数据听起来是个好主意。然而,数据怎么能如此容易地通过预测和分类呢?如果制定了某种组织系统,您需要确保数据可以通过该系统进行处理。这就是你需要争论或控制你的数据的地方。简单地说,数据争论就是“驯服”或格式化原始数据。该过程有助于数据适应工作流,以便从中获取有意义的信息。

数据管道

上学期从“数据”开始。所以,在某些时候,你需要把数据从一个地方转移到另一个地方。例如,您可能将数据导入到一个数据库中,但是在另一个数据库中发现您需要它。传递数据的一系列函数甚至脚本被认为是数据管道。

样本与总体

这可能只是一个提醒,或者也许你已经知道这个。就像数学课一样。当您考虑数据的子集或整体数据的一小部分时,这被认为是一个样本。样本大小通常是预先确定的,以帮助总结剩余的数据,或者使用监督学习方法提供给机器。我们一会儿会简单讨论一下。

如果你在看整个数据集,也就是你拥有的每一条信息,你会看到整个人口。

算法

另一个更数学化的定义,但我们下学期会用到。算法是以处理数据为目标的可重复的指令步骤。就我们的目的而言,它指的是机器用来完成任务的步骤。

机器学习

机器学习是机器使用算法分析数据的过程,该算法有助于对数据的结果进行预测。但这不仅仅是关于预测。它还涉及到分类、归类、聚类或分组,或者至少获得对数据的更多理解。当然,这是一个非常简短的简化,但是如果你特别想阅读更多关于机器学习的内容,有许多文章专门解释机器学习。

监督学习

机器学习要使用算法,必须先挑选一种学习方法。我们要讲的第一个是监督学习。使用监督学习,您需要来自数据的样本集。此样本用于获得对类别或模式的相似性的总体理解,以预测结果。这种训练方法要求数据集在处理整个数据集之前了解数据的类型。

无监督学习

下一个学习方法是无监督学习。与监督学习不同,非监督学习不使用样本数据集。相反,它只是处理全部数据,并随着数据的发展了解更多信息。这使得学习方法更能适应数据中的新情况,因此当发现新数据时,它可以重新安排它的算法或过程。

强化学习

我们要复习的机器学习的最后一种学习方法是强化学习方法。如果你养过狗,你知道有两种方法可以教它辨别是非。积极的强化是在最后提供一些东西,比如给你的狗一个奖励。负强化不会给你带来好处。消极意味着拿走一些东西。在机器学习的情况下,这就像消除导致错误结果的条件。

如果你想更深入地了解监督学习、非监督学习和强化学习,我写了一篇文章,你可以看看。

非结构化数据

听起来,非结构化数据不适合预先确定的模型。取而代之的是任何可能难以分类的数据。

结构化数据

结构化数据与非结构化数据相反。它适合数据库模型或任何其他已预定义的数据模型。

分类

分类是监督学习中的一种方法。这是一种根据数据与其他数据点的相似程度对数据进行分类的方法。该学习方法比较共同的特征,以将这些数据点“分类”为彼此更相似。然后,该类别可以用于任何具有相似特征的新数据。

回归

另一个监督学习方法的例子是回归。此方法确定跟踪值如何影响数据集中其他字段的值。一个例子是房子的面积如何影响价格。这些变量通常是连续的,这意味着它们具有数学上的“较低”和“较高”值。在这个例子中,房屋的面积会增加或减少,相关的价格也会增加或减少。

集群

我们已经研究了监督学习类型,但是非监督学习类型呢?聚类是一种无监督的学习方法,将数据与其相似程度进行比较。如果相似,可以将它们分组。越相似,数据点就越接近。如果数据点不相似,它们将被放置在更远的地方。这非常适合新数据,但如果添加更多功能,也会增加复杂性。

关联

相关性指的是价值之间的相互关系,通常是同向或反向运动。这意味着,如果一个值增加,另一个值也增加正相关。一个例子是花在学习上的时间与考试成绩相关,或者直接与考试成绩相关。在负相关中,当一个值增加时,另一个值减少。例如,如果你决定和一群人平均分摊酒店费用,那么人数越多,房间费用就越低。

神经网络

松散地基于大脑中的神经连接,神经网络是一种机器学习方法,是一种分层但通过节点连接的系统。它接受输入,给出输出,并且有一个隐藏层,大部分决策都是在这个层中做出的。

深度学习

深度学习是一种使用神经网络的机器学习方法。它的目标是更接近人脑。它做出明智的决定,并试图从每一个决定中学习。尽管一开始它必须解决简单的问题或模式,但随着时间的推移,它会学到更多,并可以转向更复杂的问题。随着复杂性的增加,它也试图提高准确性。在人工智能方面(我们也会对其进行简要描述),深度学习用于语音识别、图像识别、翻译等等。

决策树

决策树是机器学习的一部分,它允许你可视化决策。根据所做的决定,从它的分支有不同的路径。通常,它们是分割数据的是或否结果。最终,当你向下钻取时,你将到达一片叶子,它代表了结果。然而,决策树往往会过度拟合数据,这意味着答案可能不总是最准确的。

反向传播

反向传播在总结中更难定义。在神经网络中,预测输出与实际输出进行比较。在反向传播中,如果误差较大,则更新偏差和权重,以最小化数据损失,并尝试提高准确度。

ETL

ETL 代表提取、转换、加载。它是数据仓库用来使原始数据可用的工具。它指的是从数据源中提取数据,将数据转换成模型,同时保证数据的质量,并将数据加载到适当的可视化格式中。这是数据科学的一个主要部分,因为 ETL 过程不仅用于机器学习和大数据,还用于商业。

网页抓取

Web 抓取是从网站的源代码中提取数据,然后您可以从该网站中收集或过滤您正在寻找的信息。通常,您必须编写代码来从网站上收集文本,然后您可以创建一个脚本来整理您需要的内容或简单地打印您找到的结果。

商业智能

商业智能(BI)是一种分析业务指标的描述性方法。尽管它与业务相关,但它仍然更具技术性。它包括生成报告或发现重要趋势。在描述数据时,使用数据可视化。

人工智能

我们会对此保持一点模糊。人工智能是在工作时使用机器学习来适应学习的机器。例如,聊天机器人被认为是人工智能,使用得越多,它们就学习得越多。但人工智能也可以用来解决问题或进行预测。这是一个包含各种机器类型的大领域,例如不可玩的视频游戏角色在老板打架时学习如何玩,甚至无人驾驶汽车。

增强现实

同样,这将有点模糊,但如果你想了解更多,可以有专门描述 AR 的文章。增强现实基本上是增强你生活的现实。我的意思是,你给你生活的世界添加了嵌入信息。比如我想造一个智能镜子。当我早上刷牙时,智能镜子会显示天气甚至新闻标题。AR 只需一瞥就能提供更多信息,从而改善日常生活。

结论

涵盖了很多术语。其中有几个是比较常见的流行语,还有几个不太常用。我试图涵盖至少几个重要的问题。希望您可以随时查看这个列表,并且希望这些定义有助于更容易地解释数据科学术语的含义。同样,这不是一个完整的列表。我可能错过了很多。但这至少是一个让你起步的好地方。如果你认为我错过了任何重要的术语,请在评论中随意添加。下次见,干杯!

用我的 每周简讯 免费阅读我的所有文章,谢谢!

想阅读介质上的所有文章?成为中等 成员 今天!

看看我最近的一些文章:

https://medium.com/codex/something-i-learned-this-week-entity-framework-is-picky-about-primary-keys-b5d7642c9ab7 https://python.plainenglish.io/making-python-read-my-emails-9e3b3a48887c https://medium.com/codex/a-simpler-introduction-to-oauth-3533e53a4589

参考资料:

https://www.analyticsvidhya.com/glossary-of-common-statistics-and-machine-learning-terms/ https://www.dataquest.io/blog/data-science-glossary/ https://www.springboard.com/blog/data-science/data-science-terms/ https://bernardmarr.com/data-science-terminology-26-key-definitions-everyone-should-understand/ https://www.analyticsinsight.net/introducing-the-concept-of-augmented-reality-ar-based-ground-zero-analytics-data-visualization-in-real-environments/

社区检测算法

原文:https://towardsdatascience.com/community-detection-algorithms-9bd8951e7dae?source=collection_archive---------0-----------------------

入门

作者图片

你们很多人都熟悉网络,对吧?你可能会使用社交媒体网站,如脸书、Instagram、Twitter 等。他们是社交网络。你可能在和股票交易所打交道。你可能会买入新股票,卖出现有股票,等等。他们是网络。不仅在技术领域,而且在我们的日常社会生活中,我们处理许多网络。**社区是许多网络的属性,在这些网络中,一个特定的网络可以具有多个社区,使得一个社区内的节点密集连接。**多个社区中的节点可以重叠。想想你的脸书或 Instagram 账户,想想你每天和谁互动。你可能会和你的朋友、同事、家庭成员以及生活中其他一些重要的人频繁互动。他们在你的社交网络中形成了一个非常密集的社区。

米(meter 的缩写))格文和 M. E. J .纽曼是社区检测领域的两位著名研究者。在他们的一项研究中,他们利用社会网络和生物网络突出了社区结构-属性。根据他们的说法,网络节点在社区内紧密地连接在一起,而在社区之间松散地连接

为什么要社区检测?

在分析不同的网络时,发现网络内部的社区可能很重要。社区检测技术有助于社交媒体算法发现具有共同兴趣的人,并使他们保持紧密联系。在机器学习中可以使用社区检测来检测具有相似属性的群体,并提取各种原因的群体。例如,这种技术可以用来发现社交网络或股票市场中的操纵集团。

社区检测与聚类

人们可以认为社区检测类似于聚类。聚类是一种机器学习技术,其中相似的数据点基于它们的属性被分组到相同的聚类中。尽管聚类可以应用于网络,但它是处理多种属性类型的无监督机器学习中的一个更广泛的领域。另一方面,社区检测是专门为网络分析定制的,网络分析依赖于被称为边的单属性类型。此外,聚类算法倾向于将单个外围节点与其所属的社区分开。然而,聚类和社区检测技术都可以应用于许多网络分析问题,并且可能根据域的不同而产生不同的利弊。

社区检测技术

社区检测方法可以大致分为两种类型;聚合法分法。在凝聚法中,边被一条一条地添加到一个只包含节点的图中。边从较强的边添加到较弱的边。分裂方法与凝聚方法相反。在那里,边被从一个完整的图中一个接一个地移除。

在给定的网络中可以有任意数量的社区,并且它们可以具有不同的大小。这些特征使得社区的检测过程非常困难。然而,在社区检测领域提出了许多不同的技术。下面解释四种流行的社区检测算法。所有这些列出的算法都可以在 python cdlib 库中找到。

1.鲁汶社区检测

Louvain 社区检测算法最初于 2008 年提出,作为大型网络的快速社区展开方法。这种方法是基于模块化的**,它试图最大化社区中的实际边数和社区中的预期边数之间的差异。然而优化网络中的模块化是 NP-hard,因此必须使用启发式。Louvain 算法分为迭代重复两个阶段;**

  1. 节点的局部移动
  2. 网络的聚合

该算法从 N 个节点的加权网络开始。在第一阶段,该算法为网络的每个节点分配不同的社区。然后,对于每个节点,它考虑邻居,并通过从当前社区中删除特定节点并将其放入邻居的社区来评估模块化的收益。如果增益为正且最大化,节点将被放置在邻居的社区中。如果没有正增益,节点将保持在相同的社区中。对所有节点重复应用该过程,直到没有进一步的改进。当获得模块性的局部最大值时,Louvain 算法的第一阶段停止。在第二阶段,该算法建立一个新的网络,将第一阶段发现的社区视为节点。一旦第二阶段完成,该算法会将第一阶段重新应用于最终网络。重复这些步骤,直到网络没有变化,并获得最大的模块化。

Louvain 社区检测算法在此过程中发现社区的社区。这是非常受欢迎的,因为易于实施,也是算法的速度。然而,该算法的一个主要限制是主存储器中网络存储的使用。

下面给出了使用 python cdlib 库的 Louvain 社区检测算法的使用。

从 cdlib 导入算法
导入 networkx 为 nx
G = nx .空手道 _ 俱乐部 _ 图形()
coms = algorithms.louvain(G,weight='weight ',resolution=1。随机化=假)

2.惊喜社区检测

由于模块性的限制,一种基于经典概率的被称为惊奇的测量被引入来评估网络到社区的划分的质量。该算法几乎类似于 Louvain 社区检测算法,除了它使用惊喜而不是模块化。节点从一个社区移动到另一个社区,这样惊喜被贪婪地改善。这种方法考虑了链接位于社区内的概率。惊喜的使用在许多小 社区的限制下效果很好,模块化的使用在少数大社区的限制下效果很好。

下面给出了使用 python cdlib 库的惊奇社区检测算法的使用。

从 cdlib 导入算法
导入 networkx 为 nx
G = nx .空手道俱乐部图形()
coms =算法.惊喜社区(G)

3.莱顿社区检测

在后来的研究(2019)中,V.A. Traag 等人表明 Louvain 社区检测倾向于发现内部断开的社区(连接不良的社区)。在 Louvain 算法中,将充当社区中两个组件之间的桥梁的节点移动到新社区可能会断开旧社区。如果旧社区被进一步分裂,这就不是问题了。但根据 Traag 等人的说法,情况不会是这样的。旧社区中的其他节点由于它们的强连接而允许它保持为单个社区。另外,根据他们的说法, Louvain 倾向于发现每周都有联系的社区。因此,他们提出了更快的莱顿算法,该算法保证了社区之间的良好连接。

图片改编自[4]

除了在 Louvain 算法中使用的阶段之外, Leiden 还使用了一个阶段,该阶段试图改进发现的分区。莱顿算法的三个阶段是,

  1. 节点的局部移动
  2. 分区的细化
  3. 基于精细划分的网络聚合

在细化阶段,该算法试图从第一阶段提出的分区中识别出细化的分区。第一阶段提出的社区可能在第二阶段进一步分裂成多个分区。细化阶段不遵循贪婪方法,并且可以将节点与随机选择的社区合并,这增加了质量函数。这种随机性允许更广泛地发现分区空间。同样在第一阶段,莱顿对鲁汶采取了不同的方法。在对所有节点的第一次访问完成后,Leiden 不再访问网络中的所有节点,而是只访问那些其邻居已经改变的节点

下面给出了使用 python cdlib 库的 Leiden 社区检测算法的使用。

从 cdlib 导入算法
导入 networkx 为 nx
G = nx .空手道 _ 俱乐部 _ 图形()
coms =算法.莱顿(G)

4.Walktrap 社区检测

Walktrap 是基于随机行走的另一种社区检测方法**,其中通过网络中的随机行走来测量顶点之间的距离。Walktrap 是一种有效的算法,在最坏的情况下,它的时间复杂度和空间复杂度都是 O(mn)。但在大多数现实场景中,walktrap 运行的时间复杂度为 O((n ) log n),空间复杂度为 O(n)。该算法的基本直觉是,图/网络上的随机行走倾向于陷入对应于社区的密集连接部分。Walktrap 使用随机行走的结果,以自底向上的方式合并独立的社区。可以使用任何可用的质量标准来评估分区的质量。它既可以是模块性的,如在鲁汶社区检测中,也可以是任何其他措施。**

下面给出了使用 python cdlib 库的 Walktrap 社区检测算法的用法。

从 cdlib 导入算法
导入 networkx 为 nx
G = nx .空手道俱乐部图形()
coms =算法. walktrap(G)

结论

社区发现非常适用于理解和评估大型复杂网络的结构。这种方法使用图或网络中的边的属性,因此比聚类方法更适合于网络分析。聚类算法倾向于将单个外围节点与其所属的社区分开。许多不同的算法已经被提出并实现用于网络社区检测。根据网络的性质和应用的问题领域,每种方法都有不同的优缺点。

参考

[1]格文,米歇尔&纽曼,马克。(2001).《社会和生物网络中的社区结构》,美国国家科学院院刊。99.7821–7826.
[2]布隆德尔,v .,纪尧姆,j .,兰比奥特,r .和列斐伏尔,e .,2008 年。大型网络中社区的快速展开。IOPscience。
[3] Traag,v .,Aldecoa,r .和 Delvenne,j .,2015。使用渐近惊奇检测社区。物理复习。
[4] V. A. Traag,L. Waltman 和 N. J. van Eck,“从卢万到莱顿:保证良好连接的社区”,Sci。Rep .,vol. 9,no. 1,PP . 1–12,2019,doi:10.1038/s 41598–019–41695-z .
[5]Pons,p .和 Latapy,m .,n.d .使用随机行走的大型网络中的计算社区。

香港 280 万工人的通勤模式,可视化

原文:https://towardsdatascience.com/commute-pattern-of-2-8-million-workers-in-hong-kong-visualised-8e430ef723d7?source=collection_archive---------33-----------------------

就地点而言,起点-终点矩阵告诉我们就业供应的什么趋势?

(图片由作者提供)

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

香港有固定工作地点的工人超过 280 万人。想象一下,从他们的家到工作地点的整体旅行模式是什么样的?工作地点和工人的居住地点揭示了香港新市镇的职住失衡问题。

从家到工作场所

这里有一个 O-D 矩阵,显示了 2016 年按居住和工作地点分组的工人数量。每个单元格代表在那个中生活的工人和在那个中工作的工人数量。比方说,左上角的数字48647表示有 48647 名工人在中西区居住和工作。旁边的 12,938 表示有 12,938 名工人居住在中西区,而在湾仔工作。另一方面,下面的 19,244 表示有 19,244 名工人在湾仔居住,而在中西区工作。****

O-D 矩阵(作者图片)

人口普查中用于划分工人居住和工作地点的界限也如下所示。

(图片由作者提供)

(图片由作者提供)

但这张表不能不带来一些快速的见解。人们不得不手动查找并逐一比较这些数字。我们如何做得更好?

从表格到热图

下图称为热图。纵轴列出了工人居住的地区,横轴列出了按地区分类的工作地点。图中每个方格表示在该中生活的工人和在该中工作的工人数量。正方形的颜色越深,越多的工人属于那个生活/工作地点组。****

(图片由作者提供)

换句话说,这个图表和上面的 O-D 矩阵表没什么不同,除了 1。单元格现在用渐变的颜色方案和 2。数字被去掉了。

但是为什么要涂上颜色呢?因为我们对颜色比一些数字更敏感。更重要的是,趋势用渐变配色方案更容易看出来。可以有多种方式来解释这个图表。我总结了三个主要趋势,并列在下面。

趋势一:大部分工人在他们居住的同一地区工作

(图片由作者提供)

你可以看到的一个主要趋势是热图的对角线颜色最深。这意味着大部分工人在同一个地区生活和工作。住在中西区的人都在附近工作。屯门居民大多在屯门新市镇工作。这是意料之中的事——如果可能的话,工人们会在住处附近找工作,以尽量减少通勤时间。

西贡区和离岛是两个例外。在西贡,大部分居民都在观塘工作。由于将军澳区属于西贡区,我们可以预计大部分“在西贡居住,在观塘工作”的工人会居住在将军澳新市镇(而非西贡市及其他乡郊地区)。在离岛方面,由于机场被列为新界的其他地区,所有在东涌的航空公司的地面客舱均属于该网格。机场是近 80,000 人的工作场所(当然是在 COVID 之前)。

趋势二:工作仍然在核心城区

(图片由作者提供)

工作地点属于香港岛和九龙(图表的左边),一般来说比属于新界的要暗得多。颜色越深意味着工人越多,我们知道大部分工作仍然位于香港岛和九龙。

趋势三:新界→市区流量远大于市区→新界流量

(图片由作者提供)

这在某种程度上是趋势二的“延伸”趋势。随着更多的工作位于城市核心区,工人更容易在那里找到工作。因此,相当大比例的新市镇人口在核心市区工作,使得热图的左下角(居住在新界并在香港岛或九龙工作的人口)相当暗。

另一方面,居住在核心城区的人不太可能在新城镇工作。很难想象那 30 个离群索居的人在天水围新市镇工作,却住在南区。

这就是“职住失衡”/职住错配现象,这个问题从上世纪 80 年代就存在了。新城镇最初的发展方式是让居住在新城镇的居民也在那里工作。从屯门新市镇的总纲发展蓝图来看,屯门河的东面是住宅区,西面则是工业楼宇。这个轻工业被认为是居民就业的主要来源。

然而,经济结构的变化使得就业机会集中在维多利亚港两岸。数以百万计的新城居民需要早起,从他们的家到中央商务区需要一个小时的路程。

有兴趣了解更多吗?

我创建了一个网页(用 shiny 开发),允许用户使用本文中使用的 O-D 矩阵数据创建特定于他们感兴趣的领域的自定义图表。该网页如下所示。

https://kenneth-12.shinyapps.io/place-of-work-od/

如果可能的话,我还打算写一篇关于网页的补充说明。

【3 月 31 日更新:补充说明有 此处

(图片由作者提供)

(图片由作者提供)

1 注意,不包括无固定工作场所或在家工作的劳动者。

Bins 方法和卷积神经网络在疟疾检测中的对比分析

原文:https://towardsdatascience.com/comparative-analysis-of-bins-method-and-convolutional-neural-network-for-malaria-detection-535e2be51125?source=collection_archive---------22-----------------------

基于 CNN 和图像处理的疟原虫分步检测

这是我的第一个媒体博客。希望你能像我写这篇文章一样开心

照片由егоркамелев在 Unsplash 上拍摄

目录:

  1. 介绍
  2. 动机
  3. 确定的挑战
  4. 问题定义
  5. 先决条件
  6. 演示
  7. 关于数据集的信息
  8. 系统的工作流程
  9. 带有实现细节的算法视图
  10. 图像使用者界面
  11. 绩效评估参数
  12. 结果
  13. 结论
  14. 未来范围
  15. 参考

1.介绍

alaria 仍然是全球卫生系统的一个重大负担,由于缺乏设备和医疗专业知识,它是许多发展中国家的主要死亡原因。因此,专业技术被证明是解决这一问题的关键。机器学习(ML)是人工智能的一个子集,它处理并帮助在大型数据集中找到模式。医疗保健领域的机器学习最近成为头条新闻。机器学习、预测分析和健康信息学的结合为改善医疗保健流程提供了机会,这有助于改善患者的结果。机器学习方法在基于图像的分析和诊断中是成功的。机器学习可以通过算法过程提高治疗方案和医疗保健结果的准确性。

2.动机

我们首先要明白这个问题在现实世界中有多重要。疟疾在世界上的一些地方是一种真正的地方病,这意味着这种疾病在该地区是常见的。全球每年约有 32 亿人面临疟疾风险。世界卫生组织(世卫组织)发布了关于疟疾的重要事实,你可以在这里查看https://www.who.int/features/factfiles/malaria/en/。延误治疗可能会导致几个并发症,甚至在某些情况下死亡。因此,疟疾的早期测试和检测对于拯救生命是必要的。这给了我们快速有效地诊断疟疾的动力。

3.确定的挑战

  • 对于疟疾诊断,RDT 和显微镜诊断是两种广泛使用的方法。
  • RDT 是一种有效的工具,可在 15 分钟内提供结果。它不需要任何训练有素的专业人员在场。然而,根据世卫组织的说法,RDT 有一些缺点,如与光学显微镜相比成本更高,并且容易受到热和湿度的损害。
  • 显微镜诊断系统没有这些缺点,但它需要受过训练的显微镜专家在场。

4。问题定义

该系统的目标是通过使用 ML 和图像处理自动化疟疾检测过程来解决现有系统中的挑战和问题。

这里我们将应用两个众所周知的技术:
1 .Bins 算法
2。卷积神经网络

这些技术的结果将为我们提供一个具体的证据,证明机器学习和人工智能在疟疾检测方面的潜力。

5.先决条件

这篇文章假设读者熟悉 Python 库、数据结构、Tkinter、图像处理、线性代数、概率、统计、随机森林算法、SVM、卷积神经网络等。

6.这是一个应用程序的短片

来源:https://www.youtube.com/watch?v=pE8fv9BBQ2Q

请参考我的 GitHub 库这里的代码。

7.关于数据集的信息

在我们深入构建应用程序之前,让我们简单地看一下数据集。有许多数据集可用于疟疾检测。但为了这个项目的目的,我使用了由“美国国立卫生研究院”提供的数据集,其中包括 27558 个 RGB 细胞图像。png 格式,你可以从这里下载。

图 1:来自数据集的样本图像

数据集包含两个文件夹:分别带有训练和测试图像的训练文件夹和测试文件夹。此外,还有 2 个文件夹——带有疟疾感染细胞图像的寄生文件夹和带有正常细胞图像的未感染文件夹。

图 2:疟疾数据集

这些图像分为以下两部分:

  • 寄生- 13779 图像
  • 未感染- 13779 个图像

因为我们有一个平均分布的图像,所以我们不必处理不平衡数据的问题,它有更少的机会偏向某个特定的类。

8.系统的工作流程

图 3:系统的工作流程

  • 输入的 RGB 单元图像首先被处理以从图像中去除噪声
  • 然后对预处理后的图像进行分割,提取感兴趣区域,得到分割后的图像
  • 特征提取阶段的输入是分割图像,输出是特征向量
  • 下一阶段是分类阶段,其中输入将是特征向量,输出是寄生和非寄生的分类标签。

9.带有实现细节的算法视图

方法 1:使用箱柜方法

在这种方法中,我们将使用图像处理技术和最大似然分类算法。步骤如下:

步骤 1:图像预处理

  • 在原始图像上训练模型可能会导致较差的分类性能。
  • 预处理的主要目的是清洁图像
  • 它确保图像中的信息易于访问。
*kernel = np.ones((9,9),np.uint8)
clean = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)*

图 4:预处理的图像

步骤 2:图像分割

执行分割过程以从图像中获得感兴趣区域(ROI)。以下技术用于分段:

  1. Otsu 分割

它用于执行自动图像阈值处理。它返回一个单一的强度阈值,将像素分为两类-背景和前景。自动全局阈值算法通常具有以下步骤:

步骤 1:处理输入图像

步骤 2:获取图像直方图(像素分布)

步骤 3:计算阈值

步骤 4:将图像中饱和度大于的区域替换为白色,反之则替换为黑色。

图 5:大津的门槛

2。分水岭分割

  • 它将图像分割成几个汇水区或区域。
  • 任何灰度图像都可以解释为 3D 拓扑表面。
  • 图像可以被分割成概念上雨水会流入同一湖泊区域。
  • 所以我们识别图像中的各种局部最小值(像素强度低)。从局部最小值淹没景观,并防止不同最小值的水合并。
  • 这导致将图像分割成集水盆地和分水岭线。

图 6:分水岭分割图像

步骤 3:特征提取

这个阶段的输入将是分割的图像,输出将是特征向量。这里我们将提取以下特征:

  • 统计特征
  • 颜色特征
  • 纹理特征

提取统计特征(均值,标准差。偏差等。)使用颜色矩:

均值等统计特征为我们提供了数据点的平均值,标准差提供了关于均值周围数据分布的信息,而偏度值为我们提供了分布不对称的度量。以下是提取统计特征的步骤:

步骤 1:读取图像文件

第二步:求平均值

第三步:找出标准偏差

步骤 4:找出偏斜度值

步骤 6:最后将平均值、标准偏差和偏斜度值存储在 1D 数组中,并对数据库中的每幅图像重复步骤 1-4。

使用面元法提取颜色特征:

  • 在面元方法中,我们形成面元,使得图像的颜色细节将被适当地分离
  • 使用二进制方法,我们着重于使用图像直方图来提取图像特征,并试图减少特征向量的大小。

以下是使用箱方法提取颜色特征的步骤:

步骤 1:将 RGB 细胞图像分成 3 个平面- R,G 和 B 平面。

图 7:分割的图像

步骤 2:获得每个平面的直方图。

图 8:3 个平面的直方图

步骤 3:通过计算重心(CG)将 R、G 和 B 直方图分成两部分。

第四步:处理每个像素 Pi (ri,gi,bi)。将它的 r、g 和 b 值与三个平面的相应 CG 值进行比较,并且基于它所在的相应直方图的划分,给每个像素分配一个标志(或者“0”或者“1”)。例如- Pi (1,1,0)-为像素 Pi- is 分配的标志(110-5 号箱)。这导致为每个像素(000 到 111)生成 8-Bin 地址。

步骤 5:箱中像素的计数:所有图像像素将根据其 r、g、b 强度被分成 8 个箱。

图 9:样品细胞结合值

该过程提取图像的所有颜色内容,并将每个细胞图像表示为仅 8 个分量的面元特征向量。

使用灰度共生矩阵提取纹理特征:

  • 灰度共生矩阵用于提取图像的二阶统计纹理特征
  • 它也被称为灰度级空间相关性矩阵

以下是使用灰度共生矩阵提取纹理特征的步骤:

步骤 1:计算共生矩阵

图 10:图像及其共生矩阵

步骤 2:一旦计算出这个共生矩阵,我们必须使这个共生矩阵对称。

图 11:计算对称 GLCM

步骤 3:这个对称的 GLCM 矩阵必须被归一化

图 12:归一化的 GLCM

共生矩阵捕获纹理的属性,如熵、相关性、对比度、方差、角二阶矩等。

第四步:分类

这个阶段的输入将是特征向量,输出是分类标签。通过应用像随机森林算法和 SVM 这样的最大似然算法对图像进行分类。

支持向量机:

图 13: SVM

  • 在该算法中,我们首先在 n 维空间中绘制出数据项,其中 n 是特征的数量。
  • 有许多超平面将正点和负点分开,因此将正点和负点分开尽可能远的超平面将是优选的。这个超平面称为边缘最大化超平面。
  • 如果我们平行于超平面并接触一个正的点,我们得到正的超平面,如果我们平行于超平面并接触一个负的点,我们得到负的超平面。
  • 正超平面或负超平面经过的点称为支持向量。
  • 正超平面和负超平面之间的距离称为边缘。
  • 这个算法找到了一个使边界最大化的超平面。

图 14: SVM(凸包)

  • 另一种方法是分别为正负点构建一个凸包。
  • 找出连接这些船体的最短的线。
  • 把这条线一分为二。
  • 平分该直线的平面是超平面。

随机森林算法:

图 15:随机森林

  • 决策树是一个嵌套的 if-else 分类器。
  • 在每一个非叶节点,我们做决定,在每一个叶节点,我们有类标签。
  • 对应于每一个决策,我们都有一个超平面。
  • 决策树是一组轴平行的超平面,划分你的整个区域。
  • 随机森林算法由许多单独的决策树组成,这些决策树作为一个组进行操作。每棵树都给出了一个类别预测。
  • 森林中的树木数量越多,预测就越稳健,准确度就越高。
  • 得票最多的班级就是我们模型的预测。

输出

图 16:系统的输出

分类阶段的输出将是这样的图像,对于疟疾感染细胞图像,其分类标签为寄生,而对于正常细胞图像,其分类标签为未感染。

方法 2:使用 CNN

  • CNN 帮助寻找图像中的模式。它是一个设计用于处理图像等数据阵列的模型。
  • 这里,数据集中的输入图像具有不同的维度。由于 CNN 不能训练不同大小的图像,所以第一步将是调整所有图像的大小。
  • 为此,我们将绘制直方图,计算两个维度(宽度、高度)的平均值,并调整所有图像的大小。

图 17:数据集中图像的连接图

  • 从连接图上,我们可以看到从 50 x 60 到 200 x 200 的各种尺寸。计算两个维度的平均值,我们将图像形状设置为(130,130)。因此,我们将处理大小为 130 x 130 x 3= 50700 个数据点的图像。
  • 我们不能一次输入所有的内容,相反,我们必须为我们的图像选择批次。
  • 我们希望模型能够克服的另一个想法是,它应该足够健壮,能够处理与以前看到的图像完全不同的图像。当我们可以做到这一点,是通过操纵和执行对我们的图像的变换,如旋转,调整大小和缩放。
  • 我们只有不到 30,000 张图像,现在我们可以使用随机变换并加倍数据集。因此,我们将通过 keras 使用数据增强。它变换图像,如翻转,移动,缩放等。其中(图像)发生变化,而易(目标类)保持不变。
*image_gen = ImageDataGenerator(rotation_range=20, 
                               width_shift_range=0.10, 
                               height_shift_range=0.10, 
                               rescale=1/255, 
                               shear_range=0.1, 
                               zoom_range=0.1, 
                               horizontal_flip=**True**, 
                               fill_mode='nearest' 
                              )plt.imshow(image_gen.random_transform(para_img))*

构建我们的第一个基线模型

图 18:为我们的基线模型声明模型架构

  • 顺序模型在这里适用于简单的层堆栈。
  • 在卷积层,我们将把过滤器矩阵放在图像矩阵的顶部,并计算单元格的值。然后我们将做 1 的跨步跳跃。这将提取边缘及其位置等特征。下面是一个示例,显示了一个卷积层的操作,其内核大小为 3,跨距为 1。

图 19:卷积层

  • 如果有时滤波器不能完全适合输入图像,我们也可以使用填充。所以我们用零(零填充)填充图片,这样它就合适了。操作如下所示:

图 20:填充

  • 对每个字段(单元格)应用 Relu 激活函数。整流线性单元(ReLU)是一个线性函数,如果它是正的,它将输出输入,否则它将输出零。

ReLU(x)=max(0,x)

  • 接下来是最大池,它选择最大元素,从而提取最显著的特征。内核大小为 2、跨距为 1 的 maxpool 层操作示例如下:

图 21:最大池化

这样我们就可以堆叠任意数量的卷积运算。

图 22: CNN

  • 最后是全连接层。全连接层的输入将是最大池层的输出,并被展平,转换为 1D 数组,然后馈入全连接层。
  • 脱落层用于减少过拟合。
  • 损失函数评估了该模型对我们的疟疾数据集的建模效果。由于我们的问题是二进制类别分类(2 个类别-寄生和非寄生),我们将使用二进制交叉熵作为我们的损失函数,它将每个预测概率与实际类别输出(0 或 1)进行比较。
  • 现在,为了训练模型,我们必须选择批量大小,这里批量大小是一次 16 个图像。它首先接受一批数据集,然后对其执行反向传播,然后更新我们模型中的权重。对于指定的历元数(在我们的例子中是 20),重复该过程。

图 23:用于预测的代码

  • predict_generator 函数为来自数据生成器的输入样本生成预测。它返回概率的 Numpy 数组。
  • 然后,我们可以设置阈值,如如果概率> 0.5,则检测到寄生虫,否则未检测到。用这种方法我们可以做出预测。
*my_image = image.load_img(para_cell,target_size=image_shape)  *#input* 
my_image = image.img_to_array(my_image)
my_image = np.expand_dims(my_image, axis=0)*
  • 对于单个图像,加载图像并将其传递给模型。
  • 使用 img_to_array 将特定的图像对象转换为数组。
  • model.predict 函数将为输入样本生成输出预测。
*s=model.predict(my_image)
        **if**(s==[[1.]]):
            self.label.configure(text="non parasitic")
        **else**:
            self.label.configure(text="parasitic")*

图 24:系统的输出

10.图形用户界面

疟疾检测系统的图形用户界面是使用 Tkinter 库创建的,为此我们首先必须安装 Tkinter 库:

*sudo apt-get install python3-tk*

现在导入所需的库,并开始创建窗口,我们将在其中添加我们的元素,如标签,按钮等,以获得一个良好的 GUI。

*from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from PIL import Image, ImageTk
import tkinter.font as font

class Root(Tk):
 def __init__(self):
 super(Root, self).__init__()
 self.title(“Python Tkinter Dialog Widget”)
 self.minsize(640, 400)
 self.labelFrame = ttk.LabelFrame(self, text = “Open File”)
 self.labelFrame.grid(column = 0, row = 1, padx = 20, pady = 20)
 self.button()
 self.button1() 

 def button(self):
 self.button = ttk.Button(self.labelFrame, text = “Browse A File”,command = self.fileDialog)
 self.button.grid(column = 1, row = 1)

 def fileDialog(self):
 self.filename = filedialog.askopenfilename(initialdir = “/PROJECT/test samples”, title = “Select A File”, filetype =
 ((“png files”,”*.png”),(“all files”,”*.*”)) )
 self.label = ttk.Label(self.labelFrame, text = “”)
 self.label.grid(column = 1, row = 2)
 self.label.configure(text = self.filename)

 img = Image.open(self.filename)
 photo = ImageTk.PhotoImage(img)self.label2 = Label(image=photo)
 self.label2.image = photo 
 self.label2.grid(column=1, row=5)

 def button1(self):
 self.button = ttk.Button(self.labelFrame, text = “Submit”, command = self.get_prediction)
 self.button.grid(column = 1, row = 20)

 def get_prediction(self):
 s=model.predict(my_image)
 if(s==[[1.]]):
 #self.label.configure(text=”Non Parasitic”)
 text = Label(self, text=”Non Parasitic”, font=(“Helvetica”, 17))
 text.place(x=50,y=200)
 else:
 #self.label.configure(text=”Parasitic”) 
 text = Label(self, text=”Parasitic”, font=(“Helvetica”, 17))
 text.place(x=70,y=200)
root = Root()
root.mainloop()*

图 25:系统的图形用户界面

11。性能评估参数

使用准确度、精确度、召回率和 F1 分数等参数来评估性能。

图 26:CNN 的分类报告和混淆矩阵

12.结果

表 CNN 和 Bins 方法获得的结果

  • 在分类过程中,SVM 与箱柜方法配合得相当好。
  • 上表还显示了具有箱的随机森林是该方法的最佳分类器,因为它达到了 96.3%的准确度,这比其他方法好得多。
  • 而且,CNN 的准确率最低,为 94%;然而,由于其缺点,它具有相对更高的精确度。虽然 CNN 模型取得了很好的准确性,但也有一些缺点。CNN 需要更多的时间来训练模型。此外,加载模型和执行必要的操作会更加昂贵。

13.结论

  • 到目前为止,我们得到的最好的模型在未知数据上达到了 96.3%的准确率
  • 在 CNN 方法中使用数据扩充减少了过度拟合的机会和假阴性的数量。
  • 在 CNN 中使用退出被证明是好的,因为它帮助我们减少了模型的过度拟合。
  • bin 技术被证明是一种有效的技术,它处理实际的彩色图像内容并以紧凑的特征形式表示它们
  • 随机森林的 Bins 方法比 CNN 产生更好的结果
  • 由于特征向量是 8 分量的,Bins 方法也在很大程度上降低了复杂度。
  • 在比较了所有方法的性能后,可以得出结论,bin 方法在特征提取中起着重要的作用
  • 疟疾分类系统被证明比传统技术更快。该系统界面友好,易于使用。

14.未来范围

  • 作为未来工作的范围,我们可以准备一个融合特征向量,该向量将箱的特征、颜色矩和 GLCM 参数组合在一个特征数据集中,并且还可以使用递归特征消除(RFE)进行特征选择。
  • 我也希望试验更多的机器学习算法,如 KNN,AdaBoost 等。

15.参考

[1] Olugboja,和 Z. Wang,“使用不同的机器学习分类器进行疟原虫检测”,2017 年机器学习和控制论国际会议(ICMLC),宁波,2017 年,第 246–250 页。

[2] H. B. Kekre,Kavita Sonawane,“使用基于直方图的像素计数和强度平均值的图像检索”(第 74–79 页,(IJCSIS)《国际计算机科学与信息安全杂志》,第 10 卷,第 1 期,2012 年

[3] K. Silamut,N.H. Phu,C. Whitty 等人,“用于检测疟疾的图像分析和机器学习”,Am J Pathol,155 (2017),第 395-410 页

[4] Vinayak K. Bairagi 和 Kshipra C. Charpe,“用于疟原虫生命阶段分类的纹理特征比较”,国际生物医学成像杂志,2016 年第 1 卷,文章 ID 7214156,9 页,2016 年。

[5] X. Liu,T. Kawanishi,X. Wu 和 K. Kashino,“高性能 CNN 分类器和高效单词推理的场景文本识别”,2016 IEEE 声学、语音和信号处理国际会议(ICASSP),上海,2016,第 1322–1326 页,doi:10.1109/ICA ssp . 2016 . 471891 .

[6] Zulpe,Nitish & Pawar,V. (2012 年)。用于脑肿瘤分类的灰度共生矩阵纹理特征。IJ 犯罪现场调查员。9.354–359

希望你喜欢阅读这篇博客,感谢你的阅读!

关注我获取更多关于数据科学不同现实世界问题的文章!

你也可以在LinkedIn上和我联系。**

比较多个频率分布以从数据集中提取有价值的信息(Stat-06)

原文:https://towardsdatascience.com/compare-multiple-frequency-distributions-to-extract-valuable-information-from-a-dataset-10cba801f07b?source=collection_archive---------11-----------------------

如何比较多个频率分布并获得重要信息

由帕斯卡尔·米勒在 Unsplash 上拍摄的照片

频率分布是一种图形或表格表示,显示给定间隔内的观察次数。条形图、饼图和直方图用于可视化单个变量的频率分布。如果我们需要一次比较多个频率分布表。简单的条形图、饼图等。不适用于比较多个频率表。别担心,可能有其他方法可以做到这一点。本文将涵盖完成我们工作的所有技术。你所需要的就是把这篇文章读完。

路线图……..

  • 为什么我们需要比较频率分布?
  • 分组条形图
  • 核密度估计图
  • 带状图
  • 箱线图

我们的旅程从这里开始

熟悉数据集

在本文中,我们使用的是[**wnba.csv**](https://dsserver-prod-resources-1.s3.amazonaws.com/283/wnba.csv?versionId=IRtAhA_HXkTG.u7ly_AYF8_iv61yieDK)数据集。全国女子篮球协会是美国的职业篮球联盟。它目前由 12 个小组组成。在我们的数据集中,我们有 2016-2017 赛季所有比赛的统计数据。数据集有 143 行和 32 列。数据集概述如下。

频率分布和可视化的先验知识

为了更好地理解比较频率分布的必要性,您需要先了解频率分布及其可视化。如果你对此没有任何想法,你可以阅读我以前关于频率分布和可视化的文章。

为什么我们需要比较频率分布?

为了更好地解释,我们将使用wnba.csv数据集,以便您可以通过真实世界的示例进行学习。

首先,我们尝试将experience 列表示为Exper_ordianl 列,变量按顺序度量。在下表中,我们试图根据以下标记惯例来描述玩家的经验水平:

作者照片

现在,我们非常想知道‘Pos’(Player position)变量在experience水平上的分布。例如,我们希望在有经验、非常有经验和经验丰富的球员的位置之间进行比较。

我们使用了下面的代码来根据上面的标签惯例转换玩家的体验。

输出:

现在我们尝试根据经验水平对数据集进行分段。然后,我们为数据集的每个片段生成频率分布。最后,我们尝试对频率分布进行对比分析。

输出:

这个例子表明,比较多个变量的分布有点棘手。有时,您会在非技术人员面前展示数据。对于非技术观众来说,理解上述场景是如此困难。图形表示是向非技术观众展示我们发现的最佳方式。在本文中,我们将讨论三种图表来比较不同变量的频率。下面的图表将帮助我们完成工作—

(一)分组条形图

(二)核密度图

(三)方框图

分组条形图

分组条形图(也称为簇状条形图、多序列条形图)扩展了条形图,绘制两个或更多分类变量的数值,而不是一个。条形图根据一个分类变量的级别位置进行分组,颜色表示每组中的二级分类级别。

作者照片

  • 如何生成分组条形图

来自[seaborn](https://seaborn.pydata.org/index.html) 模块的[*seaborn.countplot()*](https://seaborn.pydata.org/generated/seaborn.countplot.html) 函数,用于生成分组条形图。为了生成分组条形图,我们将使用以下参数

(i) *x* —以字符串形式指定 x 轴上所需列的名称。

(ii) *hue* —以字符串形式指定要为其生成条形图的列的名称。

(iii) *data* —指定存储数据集的变量的名称。

*import seaborn as sns* sns.countplot(x = ‘Exper_ordianl’, hue = ‘Pos’, data = wnba)

输出:

这里,我们用Exper_ordianl 列来表示 x 轴。这里,我们为Pos 列生成条形图。我们将数据存储在一个名为wnba的变量中。

  • 如何自定义分组条形图

[seaborn](https://seaborn.pydata.org/index.html) 模块中的[seaborn.countplot()](https://seaborn.pydata.org/generated/seaborn.countplot.html) https://seaborn.pydata.org/generated/seaborn.countplot.html函数有多个参数。通过改变这些参数,我们可以根据自己的需求定制图形。我们也可以按升序设置x-axis 值的顺序,并使用hue_order 参数更改色调顺序。

import seaborn as snssns.countplot(x = ‘Exper_ordianl’, hue = ‘Pos’, data = wnba,
order = [‘Rookie’, ‘Little experience’, ‘Experienced’, ‘Very experienced’, ‘Veteran’],hue_order = [‘C’, ‘F’, ‘F/C’, ‘G’, ‘G/F’])

输出:

作者照片

轮到你稍微思考一下,找到问题的答案。

锻炼问题: 年纪大的球员打球少吗?用提到的数据集和上面的知识来回答问题。

核密度估计图

核密度估计(KDE)图是一种可视化数据集中观察值分布的方法,类似于直方图。KDE 使用一维或多维的连续概率密度曲线来表示数据。

作者照片

上面的每个平滑直方图被称为核密度估计图,或简称为核密度图。与直方图不同,核密度图在 y 轴上显示密度,而不是频率。

  • 为什么使用核密度估计图?

核密度估计图(KDE 图)主要用于比较直方图。现在我们试着理解 KDE 情节的必要性。

比较两个直方图最简单的方法是将一个直方图叠加在另一个直方图之上。我们可以通过熊猫可视化方法任务来做到这一点。

import matplotlib.pyplot as pltwnba[wnba.Age >= 27][‘MIN’].plot.hist(histtype = ‘step’, label = ‘Old’, legend = True)wnba[wnba.Age < 27][‘MIN’].plot.hist(histtype = ‘step’, label = ‘Young’, legend = True)

输出:

在上面,我们想要比较两个不同的场景。一个给 27 岁以上的球员,另一个给 27 岁以下的球员。我们把两个直方图一个接一个地画出来,这样我们就可以很容易地比较它们。我们可以很容易地比较两个直方图。如果直方图的数量多于两个。比较这些直方图容易吗?KDE 情节的必要性就是针对这种情况的。

  • 如何生成 KDE 图?

[Series.plot.kde()](https://seaborn.pydata.org/generated/seaborn.kdeplot.html#:~:text=A%20kernel%20density%20estimate%20(KDE,further%20in%20the%20user%20guide.)方法用于生成 kde 图。

wnba[wnba.Age >= 27][‘MIN’].plot.kde(label = ‘Old’, legend = True)wnba[wnba.Age < 27][‘MIN’].plot.kde(label = ‘Young’, legend = True)

输出:

这里,我们使用 KDE 图执行相同的过程。

带状图

带状图是一种用于总结单变量数据集的图形数据分析技术。带状图包括:

横轴=响应变量的值;

纵轴=所有值都设置为 1。

事实上,带状图实际上是散点图。

作者照片

当其中一个变量是名义变量或顺序变量时,散点图通常采用一系列窄条的形式。

  • 如何生成带状图

[sns.stripplot()](https://seaborn.pydata.org/generated/seaborn.stripplot.html)功能用于生成带状图。

sns.stripplot(x = ‘Pos’, y = ‘Height’, data = wnba)

输出:

我们把Pos 变量放在 x 轴上,高度变量放在 y 轴上。我们可以在图表中看到,大多数矮个子球员踢守门员位置,大多数高个子球员踢中后卫位置。你也可以试试权重变量。窄条的数量与名义变量或序数变量中唯一值的数量相同。

箱线图

箱线图是一种基于五个数字汇总显示数据分布的标准化方法(“最小值”、“第一个四分位数”(Q1)、中值、第三个四分位数(第三季度)和“最大值”)。

作者照片

上图显示了箱线图。箱线图是一种图表,可以很好地显示数据中的值是如何分布的。

中位数(Q2 或第 50 百分位): 表示数据集的中间值。

第一个四分位数(Q1 或第 25 个百分位数): 它代表数据集的最小值和中值之间的中间值。

第三个四分位数(Q3 或第 75 个百分位数): 表示数据集最高值和中值之间的中间值。

四分位数范围(IQR): 表示第 25 和第 75 百分位之间的值

触须: 触须是延伸到最高和最低观测值的 方框外的两条线 。在上图中,左边的一条线和右边的其他线代表胡须。

离群值: 位于盒状图的触须之外的数据点。在上图中,绿点代表异常值。

  • 如何生成盒状图

[sns.boxplot()](https://seaborn.pydata.org/generated/seaborn.boxplot.html)功能用于生成箱线图。

sns.boxplot(x = ‘Pos’, y = ‘Height’, data = wnba)

输出:

使用sns.boxplot(),生成一系列箱线图,检查作为球员位置函数的球员身高分布。将Pos 变量放在 x 轴上,重量变量放在 y 轴上。

离群点表示—

  • 如果点大于上四分位数 1.5 倍于上四分位数和下四分位数之差(该差也称为四分位数间距)。
  • 如果点数低于下四分位数 1.5 倍于上四分位数与下四分位数之差(该差也称为四分位数间距)。

我们也可以使用whis 参数将系数从 1.5 更改为自定义值。

sns.boxplot(x = ‘Pos’, y = ‘Height’, data = wnba, whis=4)

输出:

克里斯蒂娜·安妮·科斯特洛在 Unsplash 上拍摄的照片

结论

在本文中,我们试图学习如何使用图表来比较频率分布。分组条形图用于比较名义变量或顺序变量的频率分布。如果变量是以区间或比率尺度测量的,我们可以使用核密度图和带状图或盒状图来更好地理解。

如果你是数据科学爱好者,请与我保持联系。我很快会带着另一篇有趣的文章回来。

关于数据科学统计学的完整系列文章

  1. 少即是多;采样的‘艺术’(Stat-01)
  2. 熟悉数据科学最重要的武器~变量(Stat-02)
  3. 要增加数据分析能力,你必须知道频率分布(Stat-03)
  4. 通过可视化频率分布找到数据集的模式(Stat-04)
  5. 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
  6. 通过简短的讨论消除你对均值的误解(Stat-06)
  7. 通过规范化提高您的数据科学模型效率(Stat-07)
  8. 数据科学的基本概率概念(Stat-08)
  9. 从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
  10. 数据科学爱好者关于假设检验需要知道的一切(Stat-10)
  11. 用 ANOVA (Stat-11) 进行多组间统计比较
  12. 用卡方检验比较分类变量的相关性(Stat-12)

在 10 个表格游戏竞赛中比较流行的 AutoML 框架

原文:https://towardsdatascience.com/compare-popular-automl-frameworks-on-10-tabular-kaggle-competitions-9b1420e8942d?source=collection_archive---------16-----------------------

Jp 瓦列里在 Unsplash 上的照片

你是否曾经在晚上忙于应付不同的机器学习算法和软件包,切换超参数值和尝试不同的预处理方法?建立一个好的机器学习管道需要大量的试错工作。因此,这非常耗时,而且会让人精疲力尽。

自动机器学习(AutoML)框架旨在提供帮助。

开始

2016 年开始做 AutoML 系统。我是一名博士生,从事不同领域的许多 ML 项目:高能物理、医学和生物信息学。我需要优雅的软件,我可以用它来交换我的代码,进行大量的调整和验证循环。这就是我如何开始着手我称之为 MLJAR 的项目。名字来源于 ML + JAR,但这里的 JAR 有第二层意思(我当时在波兰华沙读书):

JAR 是对华沙外来居民的非正式称呼。这个词来源于许多学生和工人在周末拜访父母时用来从父母家拿食物的罐子。

你可以在这篇文章中阅读更多关于 JARs 的内容。它有相当负面的意义。我想我会用它来命名我的新项目。我会让项目成功,以表明对新人不好是一个错误。

开源 AutoML

MLJAR AutoML 引擎是开源的,其代码可从 GitHub 获得:https://github.com/mljar/mljar-supervised

MLJAR AutoML 使用表格数据集。

常见的机器学习任务:二进制、多类分类和回归。(图片由作者妻子提供)

MLJAR AutoML 最大的优点是它的透明性。这里面没有黑箱魔法。您可以查看 AutoML 培训的每个步骤的详细信息。所有关于已训练模型的信息都保存在硬盘中(自动保存功能始终开启)。每个型号都有自己的README.md文件。因此你可以很容易地检查细节(例如在 GitHub、VS Code 或 Jupyter Notebook 中)。下面是来自模型培训的降价README.md报告示例:

来自模型训练的范例报告。

自动模式:解释、竞争、执行

过去,AutoML 仅用于超参数优化。这是 ML 管道中可以自动化的最简单的事情。今天,AutoML 可以服务于许多目的。MLJAR AutoML 可以在三种模式下工作:

  • 它很快。只需要几分钟。应该用来让你熟悉一个新的数据集。它做探索性的数据分析。它只训练几个具有默认超参数的模型(没有调优!).对于每一个模型,都有完整的解释:特性重要性、SHAP 依赖图、决策图、学习曲线等等。
  • Compete —高度调谐的 ML 流水线。应该用于构建高精度模型。培训可能需要很长时间,很容易超过 4 个小时(取决于数据集)。它使用先进的特征工程、集成和堆叠。
  • Perform —用于训练生产就绪的 ML 模型的模式。训练速度和最终准确性之间的平衡。

MLJAR AutoML 以三种模式工作:解释、竞争、执行。(图片由作者妻子提供)

训练模式的选择与参数设置一样简单:

# initialization of AutoML with Compete mode
# mode can be: Explain, Compete, Performautoml = AutoML(mode="Compete")

特征工程

特征工程对于机器学习流水线的性能非常重要。MLJAR AutoML 提供了先进的特征工程方法。它可以用 K-Means 或黄金特征搜索生成新特征。还有一个特征选择程序,可以与任何机器学习算法一起工作。

黄金特征生成

用于 MLJAR AutoML 的黄金特征生成。(图片由作者提供)

k-均值特征生成

基于 K-均值的特征生成。(图片由作者提供)

任何 ML 算法的特征选择

特征选择程序。(图片由作者提供)

比较 Kaggle 上的 AutoML 框架

让我们在最具挑战性的数据集上检查 AutoML 性能。 Kaggle 平台以现实生活中的数据问题举办数据科学竞赛。我使用了 Kaggle 的 10 个表格数据集,它们代表了各种机器学习任务:

  • 二元分类
  • 多类分类
  • 回归

比较中使用的数据集描述。

数据集的选择与文章中的相同: N. Erickson,et al .:autoglon-Tabular:Robust and Accurate AutoML for Structured Data(除了房价 Adv. Regression,因为文章中没有来自私人排行榜的结果,竞争仍在进行中)。

评估了以下框架:

  • AutoWeka
  • 自动 Sklearn
  • TPOT
  • H2O
  • 谷歌云自动表
  • 自动增长
  • MLJAR

结果

这些框架在 m5.24xlarge EC2 机器(96CPU,384 GB RAM)上进行训练。培训时间设定为 4 小时。(GCP 表除外,它使用自己的机器类型)

下面给出的最终结果是私人排行榜中的百分比排名(由 Kaggle 内部评估)。**数值越高越好。**ka ggle 竞赛中的第一名将获得与1.0相同的百分位排名。竞赛中解决方案的最后一名将给予0值。除 MLJAR 外,AutoMLs 的结果来自 AutoGluon paper。

表格数据中 10 个 Kaggle 竞赛的百分位数排名。最佳解决方案用黄色标出。

表格数据中 10 个 Kaggle 竞赛的百分位数排名。数值越高越好。

你可以看到一些 AutoML 框架跳到了竞争的前 10%(没有任何人工帮助)!没有任何人工干预的 MLJAR AutoML 在 10 场 Kaggle 比赛中有 5 次进入前 25%。更重要的是,它有 3 次排在前 10%。

摘要

现在 AutoML 是一个多用途的工具。可用于:

  • 软件工程师需要在应用程序中应用 ML,但不知道如何调整 ML 算法的细节
  • 公民数据科学家在低代码环境中构建 ML 管道
  • 数据科学家和工程师加快工作速度

我希望许多人能从我的 AutoML 系统中受益。我为此付出了很多努力。我对您对 MLJAR AutoML 以及整个 AutoML 的意见和反馈非常感兴趣。

你可以在 GitHub 找到 MLJAR AutoML:https://github.com/mljar/mljar-supervised

https://github.com/mljar/mljar-supervised

基于颗粒比较 PySpark 数据帧

原文:https://towardsdatascience.com/compare-pyspark-dataframes-based-on-grain-e963e0a8aacf?source=collection_archive---------6-----------------------

基于粒度比较 Pyspark 数据帧并使用数据样本生成报告的简单方法

米利安·耶西耶在 Unsplash 上拍摄的照片

比较两个数据集并生成准确而有意义的见解是大数据世界中一项常见而重要的任务。通过在 Pyspark 中运行并行作业,我们可以基于 粒度.) 高效地比较庞大的数据集,并生成高效的报告来查明每一列级别的差异。

要求:

我们从 Salesforce 获取了大量数据集。该数据集有 600 多列和大约 2000 万行。必须对开发和验证数据集进行比较,以生成一个报告,该报告可以基于 粒度.) 查明列级别的差异。

下面是与包含粒度列的数据样本一起生成的洞察,可用于进一步查询和分析。

  • 重复记录。
  • 缺失记录。
  • 捕获开发和验证数据集中的列值之间的差异。

方法:

我们可以使用数据框的 subtract 方法减去两个数据框,这将生成不匹配的记录,但是很难确定 600 列中的哪一列实际上发生了变化以及实际值有所不同。下面是解决这个问题的一个简单方法。

从这里开始,我将验证数据集称为源数据框架(src_df),将开发数据集称为目标数据框架(tar_df)。由于相同的两个数据帧被一次又一次地用于不同的分析查询,因此我们可以将这两个数据帧保存在内存中,以便进行更快的分析。

在下面的方法中,假设两个数据框具有相同的模式,即两个数据框具有相同的列数、相同的列名以及所有列的相同数据类型。

识别重复和缺失的谷物记录:

为了识别重复记录,我们可以使用 Pyspark 函数通过查询编写一个小组。grainDuplicateCheck()函数也是如此。

为了识别丢失的颗粒,我们可以从两个数据帧中选择颗粒列并直接减去它们。

需要注意的是,我们需要执行 src_df - tar_df 来获取有效的缺失颗粒,还需要执行 tar_df - src_df 来获取无效的额外记录颗粒。

比较列值:

现在,我们必须比较数据帧之间的列值,并逐列生成报告,同时找到特定粒度的预期值和无效值。

由于我们已经确定了丢失的记录,现在我们将连接粒度列上的两个数据框,并比较在两个数据框中具有匹配粒度的所有记录的列值。

值得注意的是

  • 颗粒列可以有空值,我们必须执行空安全连接,否则,那些记录不会被连接,记录将被跳过。为此,我使用了 eqNullSafe() 内置的 Pyspark 函数。
  • 包含双精度值(如 amount)的列不会完全匹配,因为不同的计算可能会生成小数精度略有差异的值。因此,对于这些类型的列,我们必须减去这些值,并标记那些差异≥阈值的记录。

在下面的 compareDf()函数中,使用连接的数据框,我们选择要验证的粒度和特定列,并对它们进行比较。

通过运行并行作业比较列值:

上述函数的局限性在于,我们是按顺序逐列比较两个数据帧,遍历数据帧的每一列。

现在让我们来看一些统计数据。有 600 多列和大约 2000 万行,比较每列需要 15 秒。对于所有 600 列,大约需要 150 分钟(约 2.5 小时)。

列比较任务彼此独立,因此我们可以并行化它们。如果我们平行比较 8 根柱子,那么所用的时间大约是 19 分钟。这是一个巨大的差异,因为它快了 8 倍。

在下面的函数 compareDfParallel()中,我使用多处理内置 python 包创建了一个指定大小的线程池。使用*parallel _ thread _ count =*8,将并行比较 8 列。compareDFColumn()是将由每个线程为特定列执行的实际比较函数。

必须根据集群中节点的容量来选择并行线程数。我们可以使用 spark-submit 中指定的驱动核心数作为并行线程数。

假设 pyspark_utils.py 文件中存在上述所有函数,下面是示例数据的用法示例。

compareDfParallel()的输出将具有前缀为 _src 的列,用于引用源数据帧的列值,以及前缀为 _tar 的列,用于引用目标数据帧的列值。

在上面的示例中, billing_amount_src 是 1100,这是源数据帧中 billing_amount 的值,而 billing_amount_tar 是 1000,这是目标数据帧中 billing_amount 的值。

脚本的输出可以通过管道传输到一个文件,以获得一个合并的报告。可以修改该函数来生成 HTML 报告,而不是文本文件报告。

这是基于粒度有效比较 Pyspark 数据帧并使用数据样本生成报告的简单方法之一。

数据仓库快乐!

在 Excel 上比较 AWS understand 和 Azure ML

原文:https://towardsdatascience.com/comparing-aws-comprehend-and-azure-ml-on-excel-44b0f224294c?source=collection_archive---------42-----------------------

不同的机器学习算法表现如何相似?

附身摄影在 Unsplash 上拍照

在我的模块“开发有意义的指标”中,一位同学(Nicole)使用Azure Machine Learning on Excel对 4000 多条与辉瑞相关的推文进行情感分析,以确定大多数人对疫苗的感受。

她发现推特上的情绪分布相当均匀,“负面”比“正面”略有增加。这意味着 Twitter 用户的意见相对复杂,对辉瑞疫苗的正面和负面意见都很健康。这可以从她发布的下图中看出。

图片来自作者的同学妮可

巧合的是,我之前也使用过AWS understand对一堆 Reddit 评论进行情感分析。事实上,我在这里记录了那个过程。这实际上让我问, “哪个人工智能模型更准确?”作为一名计算机专业的学生,我对技术世界有一些信心,我最初的假设是,这两者将会有一些共同的趋势。换句话说,一般来说,一个人工智能的情感等级较低的推文对另一个人工智能来说也相对较低,反之亦然。

技术部分

我回答这个问题的第一步是使用 AWS understand 运行我自己的情感分析。对于那些没有看过我以前的帖子的人,我使用了一个现有的 AWS 教育帐户,在那里我有免费的信用来使用 AWS 提供的服务。写的第一个函数是从我以前的项目复制的,它连接到 AWS 服务器,并发送一段文本进行情感分析。然后处理并保存响应。这个功能实际上是由 AWS 文档指导的。

## script for sentiment analysisdef get_sentiment(text):
    comprehend = boto3.client(service_name='comprehend', region_name='us-east-1')
    response = comprehend.detect_sentiment(Text=text, LanguageCode='en')
    response = dict(response) result = {}
    result["sentiment"] = response["Sentiment"]
    result["positive"] = response["SentimentScore"]["Positive"]
    result["negative"] = response["SentimentScore"]["Negative"]
    result["neutral"] = response["SentimentScore"]["Neutral"]
    result["mixed"] = response["SentimentScore"]["Mixed"]
    result["sentiment_score"] = (result["positive"] - result["negative"]) / 2 return result

其次,编写代码来处理 CSV 文件中的数据,并将结果写入另一个 CSV 文件。

## get sentiment resultstry:
    result = get_sentiment(body)except botocore.exceptions.ClientError as e:
    print(e)
    result = 'no-go'
    while (result != "ok" and result != 'skip'):
        print("type 'ok' or 'skip' to continue")
        result = input()
    if (result == 'skip'):
        skipped += 1
        print("error occurred with sentiment analysis, skipping row")
        continue
    result = get_sentiment(body)except:
    skipped += 1
    print("error occurred with sentiment analysis, skipping row")
    continue ## write to csvrow = ['0','1','2','3','4','5','6',result["sentiment"], result["positive"], result["negative"], result["neutral"], result["mixed"], result["sentiment_score"]]
print(row)
writer.writerow(row)
print("scanned and accessed data index", count)

在这个过程中,我遇到的一个巨大的绊脚石是“不干净数据”的存在。我认为 CSV 数据集是直接从 Twitter 上刮下来的。然而,这意味着存在大量无用字符,以及 AWS 和 Python 都无法正确处理的字符。从下面的截图可以看出,有很多垃圾字符影响了 Python 脚本。

突出显示导致错误的不良字符(图片来自作者)

经过一番搜索,我学会了如何从这个链接中检查合法字符,并实现了一个功能来帮助在发送数据进行处理之前清理数据。

帮助清理数据的代码(图片来自作者)

最后,代码工作了,成功地分析了所有的推文。我将结果复制并粘贴到一个合并的 CSV 文件中,然后开始分析结果。

可视化位

总之,我制作了两张我认为有意义的图。首先,我重新制作了 Nicole 制作的图表,但现在是基于 AWS Comprehend 的结果。下面是两张并排的图表。

比较 Azure 和 AWS(图片来自作者)

这里有许多不同之处可以挑选出来。首先,AWS 产生了一种复杂的情绪,而 Azure 没有。AWS 产生的混合和中性的区别在于,中性的情绪是指评论中没有正面和负面的词语,而混合的情绪是指评论中混合了正面和负面的评论。这是一个纯粹的算法问题,因为这就是人工智能的设计方式。虽然它可能会产生一些关于算法创建得有多好的见解,但我不认为它值得考虑,因为“混合”分数相对来说是最小的。

第二,也是更明显的一点,与 Azure 相比,AWS 的中性情绪明显较高。这也是由于算法的问题。我的理论是,Excel 情绪分析仅仅是一个插件,准确性可能没有 AWS 高。AWS understand 运行在亚马逊服务器上,亚马逊服务器有能力处理和管理更大、更复杂的机器学习算法。

对比几条评论也能看出这一点。例如,从下面的图片中,有一些评论,我认为 AWS 比 Azure 的评分更准确。第 11 行的评论只是一个标签,被 Azure 标记为负面(单元格 F11),但(我相信)被 AWS 更好地归类为中性,置信度为 99%(单元格 K11)。

样本推文及其各自的情感得分(图片来自作者)

我创建的第二个图表试图证明/反驳我之前的假设,即两个人工智能之间存在某种协议。我首先计算了情绪得分,将其与-1 到 1 的量表进行比较,其中-1 分表示负面情绪,0 分表示中性情绪,1 分表示正面情绪。然后,我在散点图上绘制了 AWS 情绪得分和 Azure 情绪得分,并希望观察到某种趋势。图表如下所示。

AWS 情绪得分与 Azure 情绪得分(图片来自作者)

正如所见,两者之间绝对没有任何趋势,这让我很惊讶,因为这完全违背了我的假设。事实上,情节的巨大分散表明两个人工智能在大多数推文中意见不一。

考虑到这一点,这可能是因为自然语言处理在技术世界中仍然是一个非常新的事物,即使是最好的情感分析机器学习算法也无法提供 95%的准确率。最终,这种行为可能是意料之中的,毕竟不是太不寻常。

结论

想一想这是如何有意义的,我相信这样的信息对于人工智能爱好者来说是有趣和独特的,他们可以比较各种技术并寻求改进这些技术。这个发现的第一部分是承认和意识到我们在人工智能游戏中仍然远远落后于完美。不是说这个领域很容易,但是大多数外行人会相信情感分析确实是最准确的算法之一。这个简单的数据图表表明我们还有很长的路要走。

然而,我希望这将有助于激励更多的人(和我自己)意识到人工智能有如此大的创新和改进空间。我们必须展望未来,改进这项技术,使其能够发挥最大潜力。在一个技术进步如此迅速的现代世界,我怀疑另一个像这样的图表看起来与我现在拥有的截然不同只是时间问题。

巴西和葡萄牙宪法的数据驱动比较

原文:https://towardsdatascience.com/comparing-brazilian-and-portuguese-constitutions-with-text-mining-82213c7a95fd?source=collection_archive---------66-----------------------

从巴西和葡萄牙宪法的文本挖掘看它们的异同

在 Unsplash 上由 Dmitrij Paskevic 拍照

这是对当前巴西和葡萄牙宪法的一些特征的快速且主要是视觉上的比较,旨在利用一些文本挖掘概念并查看宪法的一些相似性和差异。

您将在这里看到:

  • 文本挖掘
  • 最常用的词
  • 单词云
  • TF-IDF

方法

对于这个分析,我使用了 R 中的文本挖掘概念和包,简单来说步骤如下:

  • 引入宪法文本
  • 去除停用词,也就是像冠词和介词这样的对文本没有太大价值的词
  • 标记化,即将短语缩减为单词

之后,我们会得到一个类似这样的数据帧:

用于分析的符号化数据框架-按作者分类的图像

现在我们准备为每个文档构建一些基本的情节。

1988 年巴西宪法

在一个经历了多年军事独裁、领导层更迭并因最近的直接选举运动“Diretas Já”而有所改观的国家,显然需要一部不那么专制的宪法,一部至少在纸面上将权力还给人民的宪法。

这正是 1988 年巴西宪法试图实现的目标。尽管被批评为冗长和过度分析,目前的联邦宪法是在 1988 年颁布的,它无疑是该国民主历史上的一个里程碑。

删除停用词后,我们剩下:

总字数 : 25042

总独特字数 : 4700

%

巴西宪法中最常见的 10 个词是:

巴西宪法中最常见的词汇——作者图片

一些快速注释:

  • “联邦”、“国家”和“工会”代表联邦政府等级中的上层职位。
  • “estados”和“municipios”代表政府的另外两个分支,即州和市。
  • 有趣的是,葡萄牙语的价值观和概念,如社会、公正、资源和人,直到第 12 位才出现。

在 worcloud2 软件包的帮助下,我们在巴西国旗的美丽色彩下构建了一个单词云,并带有巴西地图的轮廓:

巴西宪法的文字云—作者图片

正如在任何词云中一样,越大的词越常见。这种情况下的颜色是随机的。

1976 年葡萄牙宪法

在 1976 年的一场左派政变之后,葡萄牙人民也需要一部新宪法,而之前的那部宪法已经有 40 多年的历史了。虽然葡萄牙在政府和政治方面几乎总是更稳定,但 1976 年的文件进行了几项创新,如议会、总理、政党和选举的明确定义,以及独立的司法系统。

就文本而言,葡萄牙宪法也相当罗嗦,尽管不太像当前的巴西宪法:

总字数 : 15111

总绝字 : 3107

%的独特词 : 20.56

葡萄牙现行宪法中最常见的 10 个词是:

葡萄牙宪法中最常见的词语—作者图片

注意事项:

  • 可以理解的是,“雷”是最常见的词,
  • 换句话说,至少与巴西宪法相比,他们更关心共同利益。“assembleia”、“direito/direitos”、“cidados”等词非常突出,位列前 10。

看看葡萄牙宪法中的常用词“云”这个词,不按比例。

葡萄牙宪法的文字云—作者图片

TF-IDF 和独立条款

TF-IDF 是一种旨在显示一个单词在文档集合中的重要性的度量,在这种情况下,是两种结构的组合。它清楚地显示了某个文档独有的单词,或者在某个文档中比该组中的其他单词出现频率更高的单词。更多关于 TF-IDF 的信息,请点击这里。

下图显示了在一个文档中出现频率较高,而在另一个文档中出现频率较低或根本不出现的单词。左边的术语,如“联邦”、“国会”和“补充者”只在巴西宪法中使用,而“议会”、“自治”和“经济”只在葡萄牙文件中出现。

每部宪法的专有词汇—作者图片

Obs:有些词,如“económico”和“sector ”,在巴西和葡萄牙的写法不同,因此有必要进行后续研究,以使这两种葡萄牙语“正常化”。这可能很快就会成为一项独立的研究,敬请关注。

最后的想法

  • 文本挖掘是一项分析文本的伟大技术,它使我们能够比较像国家宪法这样重要的文件。
  • 巴西宪法比葡萄牙宪法更加冗长。
  • 至少就大多数常用词而言,葡萄牙《宪法》更侧重于公共利益,并且有许多与葡萄牙语相对应的词,如“社会”、“权利”和“公民”。
  • "联邦"、"国会"和"补充者"等词几乎只在巴西宪法中使用,而"议会"、"自治"和"经济"只在葡萄牙宪法中使用。

这篇文章中使用的全部代码和文本,请到我的 GitHub 页面查看我最近的一些作品这里。

比较云 MLOps 平台,来自前 AWS SageMaker PM

原文:https://towardsdatascience.com/comparing-cloud-mlops-platform-from-a-former-aws-sagemaker-pm-115ced28239b?source=collection_archive---------8-----------------------

对于 ML 平台工具,两大云今天如何比较?重要的特征是什么?

在组织中应用机器学习(ML)的公司有一系列工具放在一起作为他们的 ML 平台。当组织扩展时,每个 ML 工程师、ML 架构师和 CIO 团队都应该重新评估他们的架构,尤其是在大牌云供应商发布年度公告的时候。作为前亚马逊 SageMaker 高级产品经理,我将概述当前 GCP Vertex 与 SageMaker 的情况,以及我对不同工具的看法。

MLOps 很少是单一的整体系统。相反,它由许多较小的工具阶段组成,我称之为“MLOps 八大阶段”:数据收集、数据处理、特征工程、数据标记、模型设计、模型训练、模型优化以及模型部署和监控。

图片作者。开源基金会的“大八步”,社会公益技术。

ML 平台方法介绍

大型云供应商已经构建了“端到端”的 ML 平台。使用 Amazon SageMaker 的数据科学家可以从他们的数据仓库中提取数据,创建算法模型代码,并部署到生产中,而无需离开工具套件。虽然云供应商是人们谈论最多的入门产品,但也有一些初创公司旨在应对来自 Dataiku、Datarobot、C3.ai 和 H20.ai 的相同挑战。

端到端的替代方案是成为“同类最佳”工具,这要求供应商专注于成为某个领域的思想领袖产品。虽然 GCP 顶点和塞尔顿都有模型服务能力,但一个熟练的 ML 工程师会发现塞尔顿的产品具有许多客户用例所需的功能,如推理图和原生 Kubernetes 部署。端到端 ML 平台通常需要 15-36 个月才能赶上功能对等,但产品将在此之前推出,以创造思想领先地位并获得产品反馈。

在这一点上,与主要的云供应商平台有大量的重叠。事实上,谷歌 I/O 2021 的许多新公告都是 SageMaker 在 re:Invent 2020 上推出的功能。谷歌的战略与其他云供应商的区别在于,他们有许多源自谷歌大脑的开源 MLOps 项目,GCP 现在以托管服务的形式提供这些项目。Vertex AI pipelines 是一个托管的 Kubeflow Pipelines 服务,Vertex 元数据 API 几乎与 MLMD 相同,Vertex 也有用于托管 tensorboard 训练工件的 API。这种构建产品的方法意味着客户具有可移植性,相同的工具在开源中可供他们在 AWS 或内部运行。

亚马逊 SageMaker 与 GCP Vertex 的比较

每隔几个月,我都会花时间重新评估我的 18 个月 MLOps 行业路线图。这个路线图是我认为应该覆盖 90%的企业培训和服务模型所需的关键特性。它是由我在与 ML 工程师、CIO 和其他项目经理的交谈中得到的产品功能需求的金块,以及我在工作经验中观察到的东西组合而成的。我将这些特性放在一个列表中,并描述当前的 ML 产品。

GCP Vertex 与 SageMaker 在常见要求和同类最佳特性方面的比较。

ML 平台有两类特性。需要“牌桌赌注”和“同类最佳”功能。

同类最佳产品以粗体突出显示。新加入 ML 的团队使用 table stakes 特性就足够了,因此他们可以快速部署模型。GCP 顶点和亚马逊 SageMaker 都已经投入了足够的资金来清除这个最小的障碍。

然而,仅仅这些特征还不足以在生产中形成大规模的模型。同类最佳的特性,例如推理图,对于组织中已经有许多模型的 ML 团队来说非常重要。八大巨头的每个阶段都有自己的一套最佳特性需要考虑。

云平台仍在不断完善其同类最佳的功能,即使它们现在已经有了一个公共产品。虽然 GCP 更诚实,称 Vertex Metadata 和其他同类最佳工具为预 GA,但它们真的不能大规模使用(还不能)。我在 Twitter 上强调过顶点元数据(实验跟踪)没有 Python SDK 。SageMaker 也有类似的不足。一个例子是在他们的特征库中,该特征库缺少实体模型来组织保存的特征。需要更深入的测试来发现仍然存在的技术债务。

需要高级特性的企业团队应该准备好构建他们自己的解决方案来解决他们的特定用例,或者编写“粘合”代码来替代(开源工具或其他供应商)。这种粘合剂是我听到投资者称之为 ML orchestration 的一个概念,它是将出现的一类新的 MLOps 工具。

外卖食品

进行这样的评估显示了首席信息官/工程副总裁为解决当前挑战而需要构建的东西与他们根本没有 MLOps 平台团队时可以购买的东西之间的差距。需求列表总是在增长,足够的特性列表不仅仅来自端到端的 ML 平台。对于拥有高级用户的更复杂的企业来说,这一练习清楚地表明了他们的 ML 平台在传统构建与购买中的未来。对于初创公司和较小的公司来说,拥有 MLOps 平台工程并不划算,而使用 SageMaker 或 Vertex 将符合要求。

离开 AWS 后,我创办了一个名为 Social Good Tech 的非营利性 MLOps 软件基金会,以解决工具的互操作性问题。我计划写更多关于如何通过架构 ML 平台来思考的文章。请继续关注我对 MLOps 行业的分析和市场中的争论。

咖啡渣与 LBP 和 K-means 聚类的比较

原文:https://towardsdatascience.com/comparing-coffee-grounds-with-lbp-and-k-means-clustering-f7181dbdea67?source=collection_archive---------27-----------------------

咖啡数据科学

对旧数据的回顾

在使用 LBP+K-means 聚类来帮助理解 Rok 和小生境 grinder之间的差异之后,我决定看看以前使用这种技术的一些数据,看看我能看到什么。技术使用线性二进制地图(LBP)作为 K-means 聚类的特征,以帮助根据粒子在图像中的外观进行分组。

研磨机比较

之前我看了一下几台研磨机的几个研磨设置。对于相同的研磨机和不同的设置,差异更小并不令人惊讶。这是一种比较研磨机的奇怪方式。有一点似乎很突出,那就是 Rok 3(设定 3)似乎与大多数其他版本都不相似。我怀疑这是一个测量误差。哈里欧 3 号也一样。

这些颗粒可以被更细的颗粒(<400um in diameter) and coarser particles (>直径 400 微米)分解。两者显示了相似的模式,但是对于 Rok 3,没有太多的差异。可能是原始数据中有太多的细颗粒聚集在一起或其他问题。

研磨设置

我查看了生态位上的多个研磨设置,以帮助理解它们之间的线性关系。通常,重点是在研磨设置拨号,但由于这可以大大不同于其他变量,我想扩大搜索。

总的来说,大多数彼此接近的研磨物彼此相似,这是有道理的。

当我们按颗粒大小分解时,一些有趣的模式出现了。首先,对于 100um 的颗粒,在 S30 附近存在明显的分裂,其中 S0 至 S25 更相似,然后 S30 至 S50 最相似。

对于 500um 的颗粒,出现了另一种趋势,其中 S20 至 S50 非常相似,但彼此之间不一定相似。对于 400um,从 S0 到 S40 非常相似,但它们与 S45 和 S50 非常不同。

再次研磨

作为研究重新研磨咖啡豆的效果的努力的一部分,我比较了一些较粗的研磨设置和一些较细的。其他设置看起来并不像它们应该的那样相似,但是当比较时,不清楚为什么。

100um 是特别有趣的,因为底部的 5 个研磨设置都非常相似,甚至与再研磨非常相似,但它们都不同于较粗的研磨,如 S50。

通过粒子和研磨设置的比较,重新研磨咖啡并没有使它从一开始就非常类似于只是在那个设置下研磨(在这种情况下是 S15 再研磨改变了基本的颗粒形状。

辛辣研磨

在研磨之前加热咖啡豆显示出分布的变化,但是这些结果显示出随着颗粒的变化,特别是对于 74C 对 51C 或 20C 的颗粒来说,变化要大得多。

潜入更深的细粒(<400um) and coarse (400um) particles, there are some interesting differences especially for 74C. The coarse particles from the 74C are very different from the rest.

The Source of Fines

I have 之前讨论过理论,细粒来自更脆的咖啡豆内部。因此,回顾这些数据,我们发现根据模式识别,来自粗磨 S50 的细粒与来自 S13 的细粒非常匹配。

将这些数据分成更细和更粗的数据,更细的数据(<400um) from S50 are what match so well with S13.

Looking closer at just the S13 and S50 <800um across multiple particle sizes shows that 100um is really where those fines get similar between the two.

I really enjoy applying pattern recognition to coffee because I think we’re in the infancy of the application of data and imaging techniques to coffee.

LBP and K-means are the more basic types of functions, and maybe something more complex like PCA or LDA would do a better job. I hope one day, these techniques can help with dialing in beans and distinguishing with more granularity, the quality of coffee grinders.

If you like, follow me on Twitter 和 YouTube ,我在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事首页

摄影飞溅页面

使用图像处理测量咖啡研磨颗粒分布

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡滤纸

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维修

咖啡评论和想法

咖啡实验

比较咖啡质量分级员

原文:https://towardsdatascience.com/comparing-coffee-q-graders-79541b8fcf58?source=collection_archive---------46-----------------------

咖啡数据科学

希望了解如何衡量 Q 评分的客观性

几个月前,我联系了新兴城市咖啡烘焙商。他们分享了他们的 Q 分数数据,我想他们可能有更多的数据让我看。他们友好地与我分享了 200 多种咖啡的 400 多个 Q 分。最有趣的是每杯咖啡有两个等级。所以我做了一些分析,试图了解他们的分数之间的相关性。

我假设评分者在评分时不会分享太多关于他们分数的信息。在 Q 分级中,目的是让不同的分级员对不同的咖啡进行相同的分级。所以这是一个有趣的测试来了解这个结果有多真实。

新兴城市数据

他们使用 Cropster 来记录和存储关于烤肉和他们个人等级的信息。一半的咖啡由迪安和克里斯或者迪安和萨凡纳分级,但是只有一批咖啡由这三个人分级。有些咖啡有多个条目,但不是很多。

作者的所有图片

q 分数

Q 分数是在咖啡杯过程中记录的 10 个因素的顶点。我从我对 SCA 杯协议的理解中总结了每个指标。他们定义了如何准备咖啡样品,如何品尝,以及如何评分。我相信网上有很多资源可以帮助你通过快速搜索了解如何拔火罐。

由于补丁中的缺陷豆,最终分数也可能会丢分,因为允许有多少缺陷是有标准的。

相似性度量

在模式识别中,特征向量用于比较两个项目,通常是两个信号或图像。计算向量之间的分数,以确定它们彼此之间有多相似或不相似。

为了计算两杯咖啡的相似性得分,使用均方根将每个子指标向量与所有其他向量进行比较:

然而,在下面的细目分类中,我将每个图表调整到 0%到 100%之间。100%不代表完全匹配,0%也不代表不匹配。它相对于每个图表中的数据,其中 100%是最大相似度(最相似),0%是最小相似度(最不相似)。

我们可以查看各个地区的得分差异。对克里斯来说,他在亚洲咖啡上的分数和其他人的分数相关性最小。否则,他们的大部分分数彼此具有高度的相似性,这表明 Q-分级训练做得很好并且是客观的,或者这表明通过他们一起给咖啡分级,他们已经将他们的分数调整为彼此同步。

我们可以把重点放在同一个地区的咖啡和分类上。萨凡纳和迪恩除了在南美豆上有最大的共同点,但除此之外,萨凡纳与迪恩的匹配度比克里斯与迪恩或萨凡纳的匹配度更高。

相互关系

相关性是衡量两个变量彼此相似程度的指标。高相关性并不意味着一个变量会引起另一个变量,而是当情况发生变化时,两个变量的涨跌幅度相同。我从一开始就假设一些分级变量会有很高的相关性,因为它们是从不同的时间点来看味道的。

就相关性而言,两者略有不同。

地区和评分者之间的相关性有一些奇怪的结果。理论上,你应该与自己最相关,但在这里似乎并不总是如此。然而,我认为相关性的微小变化在统计学上是显著的。

原始差异

我们可以查看原始差异,并将克里斯和萨凡纳与迪安的分数进行比较,因为迪安对几乎所有的咖啡进行了评级。

查看数据的另一种方式是所有子指标的平均差异,以查看原始数字中的差异。有两种方法可以查看:平均值和仅包含差异不为零的样本的平均值。

我们可以将这些分为地区差异,这是查看分数的另一种有趣方式。

Dean vs Chris 没有不适用的数据

这两个指标最终都告诉我们,两者之间没有太大的区别。

这是一个独特的数据集,因为对于多个评分者来说,相同的品尝会议的数据集并不多。事实上,我怀疑这是有史以来最大的数据集,只是因为 coffee 中使用的数据太新了。好消息是,即使子指标之间的差异加起来在最终得分上有一些差异,但这种差异并不是很大。任何子矩阵的差异也不存在。

这给了我们两个事情中的一个很高的信心:所有这三个 Q 级评分者都受过良好的训练来客观地评分,或者他们的得分通过生活在相似的地区、喝相似的咖啡和一起评分而标准化。我希望这有助于鼓励其他分级者分享他们的数据,以帮助研究 Q 分级作为咖啡客观衡量标准的有效性。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

家庭烘焙咖啡的经济学

咖啡的成本:咖啡馆 vs 家庭

咖啡分级 Q 分数的有用性

比较 Q 级咖啡:地区、年份和加工

按地区、工艺、等级和价格分类的咖啡

特色咖啡:比较分级方法

咖啡数据回顾:等级和口味

使用模式识别比较咖啡

如何评价 Sweet Maria 的咖啡杯度量标准,以便更好地进行比较

烘焙对咖啡豆硬度的影响

咖啡豆脱气

收集爱好数据集:咖啡

比较 Python 中显示分类数据的不同方式

原文:https://towardsdatascience.com/comparing-different-ways-of-displaying-categorical-data-in-python-ed8fabfb6661?source=collection_archive---------9-----------------------

传统与不常见的方法以及何时使用它们

来自 Unsplash

虽然表示分类数据的最流行的方式是使用条形图,但还有一些其他的可视化类型适合于此目的。它们都有各自的优点和缺点,以及适用性的限制。

在本文中,我们将比较显示相同数据的图表:按区域划分的大陆。数据从维基百科获得,用 mln km2 表示,以避免不必要的精确。

import pandas as pd
dct = {'Oceania': 8.5, 'Europe': 10, 'Antarctica': 14.2, 'South America': 17.8, 
       'North America': 24.2, 'Africa': 30.4, 'Asia': 44.6}
continents = list(dct.keys())
populations = list(dct.values())

1.条形图

让我们从显示分类数据的最经典的方式开始:一个甚至不需要介绍的条形图。

import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(10,4))
plt.barh(continents, populations, color='slateblue')
plt.title('Continents by area', fontsize=27)
plt.xlabel('Area, mln km2', fontsize=19)
plt.xticks(fontsize=16)
plt.yticks(fontsize=16)
plt.tick_params(left=False)
sns.despine(left=True)
plt.show()

作者图片

从上面的图表中,我们可以清楚地看到各大洲在数量和质量上的等级划分。难怪:酒吧地块几乎没有任何缺点。它们是多用途的、高度可定制的、视觉上引人注目的、易于解释的、广泛受众熟悉的,并且可以用任何 dataviz 库来创建。在生成它们时,我们唯一要记住的是遵循良好的实践:数据排序、选择合适的颜色、条方向、添加注释、标签、整理等。

2.茎图

stem 图非常类似于条形图,甚至比后者更有优势,因为它的特点是最大化的数据-墨水比率,看起来不那么杂乱。要创建 stem 图,我们只需要 matplotlib 库。对于水平茎图(具有水平基线和垂直茎的图),我们可以将vlines()plot()结合使用,或者直接使用stem()函数。在第一种情况下,vlines()创建词干,plot()创建结束点。对于垂直茎图(具有垂直基线和水平茎的图),我们不能再使用stem()功能,而是使用hlines()plot()的组合。

让我们为我们的数据创建一个垂直茎图:

plt.figure(figsize=(10,4))
plt.hlines(y=continents, xmin=0, xmax=populations, color='slateblue')
plt.plot(populations, continents, 'o', color='slateblue')
plt.title('Continents by area', fontsize=27)
plt.xlabel('Area, mln km2', fontsize=19)
plt.xticks(fontsize=16)
plt.yticks(fontsize=16)
plt.xlim(0, None)
plt.tick_params(left=False)
sns.despine(left=True)
plt.show()

作者图片

与第一个图表相比,我们只增加了一行代码,在水平茎图的情况下,如果直接使用stem()函数,甚至没有必要。结果图显示了相同的信息,但看起来比传统的条形图更清晰、更优雅。当有许多类别需要可视化或者它们的值具有可比性时,这就变得特别有价值。

3.圆形分格统计图表

饼图或其版本圆环图(具有空核心部分的饼图)是另一种众所周知的可视化类型,广泛用于显示整体中单个组件的比例。它可以用许多 dataviz 库创建和轻松定制。尽管如此受欢迎,它也是最受批评的情节类型之一。其主要原因是:

  • 饼图是基于角度而不是长度,这使得它更难被清楚地解释。
  • 在有许多类别或者它们的比例相似的情况下(这是创建柱状图的理想选择),饼图实际上对于计算出比例的顺序或者甚至找到最大/最小值是没有用的。

让我们看看饼状图在我们的例子中是否适用:

plt.figure(figsize=(7,7))
plt.pie(populations, labels=continents, startangle=90, autopct='%1.0f%%', 
        textprops={'fontsize': 15})
plt.text(x=-1.15, y=1.5, s='Continents by area, in %', fontsize=27)
plt.show()

作者图片

由于我们的数据仅由 7 个类别组成,其值最初是有序的,并且彼此之间差异很大,还因为我们添加了每个大洲占总土地的百分比,所以生成的图表看起来信息量大,易于理解,并且不会遇到上述两个问题。

饼图相对于条形图和柱状图的一个不太明显的弱点是颜色丰富。另一种方法是用图案填充楔形,但在这两种情况下,都会导致较低的数据-油墨比率。然而,这是所有“多彩”情节的典型问题,我们很快就会看到。

另一件值得强调的事情是,这种类型的图表比前两种图表的功能更有限。事实上,它只能用于可视化整个中组件的比例,而对于条形和茎图,条形/茎不应构成整体。例如,我们可以按人口数量制作前 10 个国家的柱状图。为这些数据创建一个饼状图,在技术上是可能的,但会有一点错误,因为真实的整体,在这种情况下,包括更多的元素(所有其他国家)。

4.树形图

要创建一个树形图,我们必须安装并导入 squarify 库(pip install squarify)。这种类型的图类似于饼图,因为它也显示整体中单个组件的比例。它不使用楔形,而是使用一组矩形,矩形的面积与相应类别的值成比例。这很重要,实际上也是一个优势:对区域的心理比较肯定比对角度的心理比较容易得多。此外,与饼图不同,当我们有很多类别要比较时,它仍然可以很好地工作。下面是树状图和饼状图共有的弱点和限制:

  • 当类别的比例相似时,效果不好。
  • 它没有轴,所以我们必须依赖于矩形的视觉比较,或者在每个矩形上添加值。
  • 这意味着使用大量的颜色,这可能会使结果图看起来有点势不可挡。
  • 树形图的组成部分应该构成整体。

此外,还有一个纯粹的树图特有的缺点:

  • 定制这种可视化的方式相当有限,并且不总是用户友好的。例如,要调整标签文本属性(如字体颜色或大小),我们不能直接传入相应的参数,而只能通过text_kwargs字典。另外,在矩形之间添加间隙的pad参数只能取值TrueFalse,没有任何调整间隙宽度的可能性。

让我们来看看我们各大洲的树形图:

import squarify
import matplotlib
plt.figure(figsize=(12,7))
squarify.plot(sizes=populations, label=continents, value=populations,
              color=[matplotlib.cm.Set2(i) for i in range(7)],
              text_kwargs={'fontsize': 17})
plt.title('Continents by area, mln km2', fontsize=27)
plt.axis('off')
plt.show()

作者图片

我们的树形图看起来很吸引人,也很有洞察力,我们可以清楚地从最大到最小的各大洲跟踪矩形和值。同样,这部分是由于我们只有 7 个类别、各种各样的值和初始排序。或许,我们可以考虑用百分比而不是绝对值来表示这些值。

树形图唯一必要的参数是sizes,所有其他参数(包括label)都是可选的。

5.华夫饼图表

要创建华夫饼图表,我们需要一个基于 matplotlib 的 PyWaffle 库:pip install pywaffle,然后导入 PyWaffle 和 matplotlib。这种类型的图类似于饼图和树形图,因为它也说明了整体中单个组件的比例,其优点是它还显示了每个组件的单位数。根据上下文,“单位”可以指 1、10、100 等。每个类别的元素(实际上,对于我们的下一个可视化,我们将使用 100 万平方公里的单位)。每个子集(类别)由一个充满方块的华夫饼干图上的一个区域表示。与树形图一样,网格上每个类别的面积与其值成正比。

当我们有一组相对较小的离散数据,并且对其组成部分的内部结构感兴趣时,华夫格图效果最好。但是,记住这种类型的图表的局限性是很重要的。与华夫格图完全相关的缺点是,每个类别中的单位数量应该相当少。其他一些限制与已经提到的可视化类型是相同的:

带有饼图和树形图:

  • 当类别的比例相似时,效果不好。
  • 它没有轴,所以我们必须依赖区域的视觉比较,或者在每个区域上添加相应的注释。
  • 它有同样的问题,不可避免的丰富的颜色。
  • 华夫饼图表的组成部分应该构成整体。
  • 对用作输入的数据进行排序是非常明智的。

带饼状图:

  • 当有许多类别需要比较时,华夫格图就变得低效了。

带树形图:

  • 华夫格图的定制方式并不总是简单易懂的。

让我们看看使用华夫饼图表对我们的数据来说是否是一个好主意:

from pywaffle import Waffle
fig = plt.figure(FigureClass=Waffle, figsize=(12,7), values=dct, columns=15, 
                 block_arranging_style='snake',
                 legend={'bbox_to_anchor': (1.3, 1), 'fontsize':14, 'frameon': False})
plt.title('Continents by area', fontsize=33)
plt.show()

作者图片

上图看起来完全定制化,并以正确的方式揭示了模式。然而,我们不得不承认,在这里,华夫格图并不是正确的选择:即使我们的类别很少,并且每个类别都由相对较少的单元组成,我们也不需要关于每个子集内部结构的如此详细的信息。还有,我们的“单位”看起来有点诡异:100 万 km2!😮我们甚至不能称之为离散值。因此,我们的数据不适合这种可视化。

华夫饼图的必要参数是FigureClassvaluescolumns(或rows)。

华夫格图的一个特殊变体是使用图标而不是方块的象形图图。通常,这样的图标应该是简单但对每个类别都有意义的东西,例如,显示不同领域进展的星星符号。当我们希望以更有影响力和更吸引人的方式展示见解时,象形图可以更有效地显示分类数据。华夫格图和象形图在显示统计数据、评级、进度状态等方面都特别有用。

6.词云

最后,显示分类数据的最奇特且几乎出乎意料的方式是创建一个单词云。为此,我们需要 wordcloud 库(pip install wordcloud)。它的传统用法是将文本数据可视化,每个单词的大小表示它的频率,这样我们就可以辨别文本中最重要的单词。然而,词云还有一个鲜为人知的应用:将数据的某个属性值分配给每个类别,我们可以创建一个词云,不是基于词频,而是基于该属性(在我们的例子中,是每个大洲的区域)。此外,以这种方式使用词云,我们很容易避免许多与其相关的典型已知问题。事实上,与“正常”的单词云不同:

  • 不需要预先准备数据、删除停用词等。
  • 没有缺乏上下文的问题。
  • 由于类别的数量通常相对较少,我们可以确保抑制任何垂直单词(将 1 赋给prefer_horizontal参数)以提高图形的可读性。另外,在这种情况下,我们肯定不需要使用面具。

与各种文字云相关的一些其他缺点仍然存在:

  • 单词云不允许对单词进行直接清晰的排序。
  • 单词云缺乏定量方法:不可能将字体大小转化为感兴趣的属性的精确值。而且,在这种情况下,我们甚至不能直接在图上把值相加。
  • 有一种错觉,即较长的类别名称(尤其是多词的类别名称),或带有上升符号(如 kbl )或下降符号(如 jqg )的类别名称看起来更大,因此比具有相同或可比值但没有这些特征的类别名称更重要。
  • 如果我们对我们的词云使用连续的 matplotlib 颜色图(岩浆春天等)。),我们应该记住,每个类别的颜色将从其中随机选择,没有任何颜色的渐变性作为类别排名的潜在附加指标。

另一个缺点是饼状图、树形图和华夫饼干图共有的:当类别的比例相似时,单词云是无效的。然而,单词云在这些类型的可视化方面有一些优势:

  • 丰富的颜色是一个可以解决的问题:可以分配一个颜色函数,甚至可以让所有的单词都是同一种颜色。
  • 类别不必构成整体。
  • 不需要事先对数据进行排序。
  • 单词云对于显示更多类别仍然有用(与饼图和华夫饼图相比)。
  • 词云是高度可定制的。

让我们为我们的大陆创建一个单词云,看看它的优点和缺点:

from wordcloud import WordCloud
plt.figure(figsize=(12,8))
wordcloud = WordCloud(background_color='white',
prefer_horizontal=1).generate_from_frequencies(dct)
plt.text(x=120, y=-25, s='Continents by area, mln km2', fontsize=27)
plt.imshow(wordcloud)
plt.axis('off')
plt.show()

作者图片

我们已经准备好一个词云不特别适合心理分类排名或定量分析。此外,我们看不到多少上行或下行。然而,这里真正分散注意力的是双词类别的存在:北美南美。因此,我们可以得出结论,最好只在只有一个单词的类别中使用这种方法。

从技术上讲,虽然在我们的例子中,WordCloud()的所有参数都是可选的,但是使用传入字典或序列的generate_from_frequencies()是必不可少的。有趣的是,许多与“正常”词云相关的参数对于基于属性的词云变得无用,例如collocationsstopwordsmin_word_lengthmax_words

结论

在本文中,我们比较了显示分类数据的各种可视化类型。每一种都有其使用范围、优点和缺点。这些类型的图表中有些是经典和流行的(条形图),有些非常具体,看起来几乎很怪异(单词云)。

在我们的例子中,为了根据陆地面积比较各大洲,最有效的可视化类型是条形图、柱状图、饼状图和树形图。另外两种类型,华夫饼图表和单词云,结果不太适合,这并不意味着它们对任何其他数据都是如此。选择一个合适的图表总是取决于一种情况,以及我们到底想用我们的发现展示什么。一个正确的,适当定制的可视化可以帮助我们与我们的观众分享宝贵的见解。

感谢阅读!

你会发现这些文章也很有趣:

https://medium.com/geekculture/creating-a-waterfall-chart-in-python-dc7bcddecb45 https://medium.com/geekculture/creating-toyplots-in-python-49de0bb27ec1 https://levelup.gitconnected.com/python-can-be-lots-of-fun-999552d69d21

在低资源翻译(英语-约鲁巴语)中比较脸书的 M2M 和 mT5。

原文:https://towardsdatascience.com/comparing-facebooks-m2m-to-mt5-in-low-resources-translation-english-yoruba-ef56624d2b75?source=collection_archive---------19-----------------------

Muhammadtaha Ibrahim Ma'aji 在 Unsplash 拍摄的照片

寻找使用稀有语言对微调翻译任务的最佳模式。

TLDR;M2M 的表现确实比 mT5 好。

灵感

两个月前,我开始致力于低资源语言的神经机器翻译(NMT)津迪竞赛。挑战是使用一种罕见的语言对训练一个胭脂分数最高的 NMT 模型:约鲁巴语到英语。

约鲁巴语是尼日利亚南部约鲁巴族使用的一种语言。它是超过 4000 万人的母语,也是非洲最大城市拉各斯最常用的语言。由于西非的语言多样性,约鲁巴语被认为是方言的连续体,而不是一种标准语言。这对像我这样的 NLP 从业者来说是一个严重的问题。这让工作变得更加困难。

数据集

更糟糕的是,几乎没有任何将英语映射到约鲁巴语的数据集。我所知道的最大的数据集是 JW300 数据集(40 万句),它主要包含宗教文本。它肯定可以用来提高 ROUGE 评分,但如果它是训练的唯一参考,翻译将是倾斜的,只会产生圣经风格的句子。然而,在 Zindi 竞赛中,我们提供了一个非常小的数据集(10k 个句子),我用它来从 JW300 的句子风格中去偏模型。

在我最初的解决方案中,我使用了两个数据集来提高我的分数,但是在这里,为了简洁起见,我将只使用较小的数据集(10k)。你可以在比赛页面找到数据集。你需要注册才能下载。

正如已经提到的,解决这个问题的资源是稀缺的,并且基于变压器的模型在数据不足的情况下表现不好。为此,我将利用迁移学习来加快学习过程。

可用于微调的条件文本生成(CTG)多语言模型不如基于编码器的模型常见。然而,经过广泛的搜索,我只剩下两个同样有趣的候选人。

mT5

mT5 车型于 2020 年作为 T5 车型的多语言合法继承人推出。m 代表多语言。

mT5 和 T5 都以相似的方式训练。唯一的区别是 mT5 是在多语言数据上训练的,并且有更多的令牌嵌入(250k)。两者最初都在跨度破坏的目标上被训练:“用屏蔽记号替换输入记号的连续跨度*,并且模型被训练来重建屏蔽记号*”。

用于训练模型的数据集有 107 种语言的 6.3 万亿个标记。幸运的是,约鲁巴语是这些语言中的一种,因为它占整个数据集的 0.2%(5000 万个令牌,而我们的数据集只有 60 万个)。该模型有不同的尺寸:从 300 米参数(小)到 13B 参数(XXL)。就我们的目的而言,我们将选择较小的一个。

M2M

M2M 也是和 mT5 (2020)同年开源。它们之间的主要区别是 M2M 模型仅在翻译任务上接受训练,在两个方向上使用来自 100 种语言的句子对。这意味着,与其他翻译模型不同,M2M 不是以英语为中心的翻译模型,翻译可以从多个方向流动,从而为低资源对带来更好的性能。

M2M 接受训练的数据集包含 2200 个不同方向的 75 亿个句子对。约鲁巴语是这 100 种语言中的一种。M2M 有 418M 参数配置,最高可达 14B 参数。我们将使用 418 米的。

环境

由于训练如此巨大的模型的硬件要求,我无法在本地训练它们——相反,我使用了 Kaggle 笔记本中提供的免费 P100 GPU。

首先,我们安装所需的库:

Fairseq 库: Fairseq 是一个面向序列模型的脸书库。这自然需要神经机器翻译、语音识别模型和条件文本生成等技术的支持。许多最先进的 NLP 模型都是使用 fairseq 生成的,因为它为许多重复性任务提供了灵活性和抽象性(此处提供了示例)。然而,尽管 fairseq 在研究中无处不在,但对于学术界以外的人来说,它仍然很难理解。对于那些想在项目中使用最先进模型的人来说,这是不幸的。

变形金刚和简单变形金刚:Huggingface transformers 是迄今为止最流行的 NLP 库。在分类、文本生成和摘要等任务上,只需要很少甚至不需要任何努力就可以微调最先进的基于 transformer 的模型。Simpletransformers 只是建立在它之上的一个小库,用来加速原型和测试。

正在准备数据集

这里的数据集预处理很少,源文本和目标文本都是小写的,并且删除了尾随空格。验证由数据集的 5%组成(500 个句子)。

培训 mT5 模型

当微调 T5 / mT5 模型时,Simpletransformers 使我们的生活简单多了,因为它们完全支持这两种。我们只需要设置所需的超参数、模型名称和数据。

该库要求数据集为 Pandas dataframe 格式,有三列: input_texttarget_text前缀。前缀是在 mT5 的训练过程中使用的列,用于指定模型应该做的任务(总结、分类…)。我们的案例不需要它,我们创建了它并将其留空。

列车损失(蓝色)与有效损失(橙色)WANDB

训练 M2M 模型

Fairseq 库更面向 CLI,而不是 pythonic。要微调 M2M 模型,我们需要:

  • 首先下载 418M 参数模型,以及记号赋予器和词汇文件。
  • 将训练和验证句子对导出到文本文件。
  • 使用 fairseq/scripts/spm_encode.py 下的脚本标记句子
  • 将句子二进制化,以加快数据加载和训练。
  • 微调模型!

列车损失(蓝色)与有效损失(橙色)WANDB

为了公平的比较,我试图保持相似的超参数。两个模型都使用了自适应因子优化器、余弦调度器,并且被训练了十个时期。M2M 的学习率较低,因为它的面积较大。

估价

为了评估测试集中产生的翻译,我使用了 ROUGE 度量标准(Recall-OorientedUndersetry forGistingEevaluation)。ROUGE 有两个主要的变体:ROUGE-n 用于计算 ngrams 共现的召回率,ROUGE-L 用于测量最长的公共子序列。

在这种情况下,我将使用 ROUGE-2(使用二元模型),并将 f1 分数作为参考(我也将显示其他指标)。

为了计算 ROUGE 得分,我使用了 ROUGE 库,它抽象出了实现:

对于解码器文本生成,我在两个模型中使用了以下超参数:

  • 最大长度:100
  • 长度惩罚:2.5
  • 留级惩罚:1.5 分
  • 光束尺寸:5

mT5 推断:

使用 mT5 的推断很简单:

使用胭脂库时,get_scores 返回一个包含不同胭脂分数的字典:["胭脂-1 ","胭脂-2 ","胭脂-L"]。正如我们之前所说的,我们将使用 ROUGE-2 来评估模型的性能,即 f1 分数(因此它更能代表模型的整体性能)。

T5 —胭脂分数

正如我们所见,T5 在 rouge-2 f1 得分上给出了 11(标准化)rouge 得分。我们将为 M2M 模型计算相同的分数。

M2M 推断:

用 M2M 生成翻译有点复杂。首先,我们必须重复相同的预处理步骤来训练验证文本,然后使用这个命令行“fairseq-generate”来生成表格格式的翻译。最后,我们使用 grepcut 的组合从输出生成的文件中提取翻译后的文本( grep , cut )。

请注意,为了使这个脚本能够工作,它必须运行在培训模型的同一个目录中。

M2M-胭脂分数

M2M 模型的 rouge-2 得分为 23,rouge-1 得分为 45。

比较

M2M 的表现明显优于 mT5 车型,其 rouge 得分(所有车型)是 mT5 的两倍多。这让我感到惊讶:当看损失演变图时,似乎 mT5 收敛得更好,损失最小,M2M 的表现会更差。显然,我错了。

请注意,在数据集非常小(10k)的情况下,这种性能对于两种模型来说都令人印象深刻。如果没有迁移学习的帮助,这样的成绩是不可能达到的。

以下是一些例句:

约鲁巴语:lẹ在ẹlẹ́rìí耶霍法?
目标:你什么时候成为耶和华见证人的一员?

M2M:你什么时候成为耶和华见证人的一员?
mT5 :耶和华的话是什么意思?

— — — -

约鲁巴语:拉ẹ语:lè bá a sọ̀rọ̀语:不,你不能

M2M:抱歉,你不能告诉我

— — — -

约鲁巴语:莫 mọ̀èyíkín tóníkíofẹ́米
目标:在我告诉你嫁给我之前我就知道了

M2M :我知道在我不得不嫁给我之前
mT5 :我知道这就是我想见你的原因

— — — -

约鲁巴语:àwọnìfẹsẹ̀wọnsẹ̀·蒂伊奥·马阿·瓦耶尼·尼·迪耶·orílẹ̀-èdè尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日尼日的比赛如下:

M2M :以下是今天将在尼日利亚 npfl 进行的比赛:
mT5 :以下是尼日利亚足球联赛(npfl)的比赛结果:

结论

尽管 M2M 的表现优于 mT5,但后者更灵活,因为它接受了多种任务的训练。此外,使用 mT5 更容易,因为它可在 huggingface hub 上获得。

我们取得的进步真的令人惊讶:我们如何从 10k 句子对数据集中获得像样的翻译。几年前,我们只能梦想。

这个项目在 Github 和 colab 上都有(请从这里下载数据集)。发现有用就启动回购。联系我:boukil98@gmail.com

https://github.com/maroxtn/mt5-M2M-comparison https://colab.research.google.com/drive/1_1QbvXQllO1rL88shNvcOFz8H590ktax?usp=sharing [## Fairseq 培训和评估

colab.research.google.com](https://colab.research.google.com/drive/1_1QbvXQllO1rL88shNvcOFz8H590ktax?usp=sharing) https://colab.research.google.com/drive/1ZOhDhl1d1khVwCY5hzXwezx6ETGi2P2f?usp=sharing

比较五种最流行的 EDA 工具

原文:https://towardsdatascience.com/comparing-five-most-popular-eda-tools-dccdef05aa4c?source=collection_archive---------14-----------------------

为您的 EDA 任务做出明智的选择

由活动创作者在 Unsplash 上拍摄的照片

探索性数据分析(EDA)是任何数据科学项目不可或缺的一部分。更简单地说,它可以被称为理解数据集所必需的“侦查工作”。这些初步调查导致发现不明显的趋势和异常,从而借助全面的可视化和详细的统计数据增强对手头数据的理解。数据科学家主要使用 EDA 来形式化各种测试假设和数据工程的后续步骤,以准备数据集供其使用。

由于 EDA 是任何数据科学项目的基础,数据科学家需要根据他们的需求为 EDA 工具做出明智的选择。Python 提供了各种 EDA 工具和库来扩充现有的数据框架。虽然这些工具共享相似的功能,但每个工具都有独特的方面,使它们以不同的方式脱颖而出。我们将回顾五款最流行的 Python EDA 工具: DataPrep Pandas-profilingsweet vizLuxD-Tale我们将重点关注这些库的独特特性和功能,以帮助数据科学家为他们的 EDA 任务选择合适的工具。

图书馆中的可视化比较(图片由作者提供)

可视化

GIF 由 GIPHY 上的 gomoorae 制作

有效描绘数据集隐藏的复杂性的可解释的可视化是探索性分析最重要的方面。我们将比较和对比每种工具支持的可视化类型和质量。

DataPrep 提供了广泛的可视化,用户可以在 DataPrep 的绘图功能中指定。一些最著名的可视化工具包括条形图、直方图、饼图、箱线图和地理图,以支持各种数字、分类和地理分布的表示。DataPrep 中的可视化使用散景,这使得它们是交互式的。DataPrep 可视化的另一个显著特性是与可视化一起显示的洞察力笔记。这些见解为分布提供了一个摘要,并消除了用户执行额外计算的需要。此外,DataPrep 允许用户轻松地格式化和定制默认可视化,以满足他们的设计需求。

from dataprep.eda import plot, plot_correlation, create_report, plot_missingcreate_report(df)

DataPrep 中的报告演练

Pandas-profiling 生成一个清晰的报告,具有可视化效果,如直方图、饼图和条形图。它们为每个数据集属性提供了清晰的解释,但是这些基于 matplotlib 的可视化缺乏交互性。变量之间的相关性仅通过热图显示。缺失值组件提供缺失值的矩阵、计数、热图和树状图可视化。

from pandas_profiling import ProfileReport
ProfileReport(df)

熊猫档案中的报告演练

SweetViz 为一个或两个数据集生成 HTML 报告,其中包含对特征的详细分析。它支持与 pandas-profiling 相似的可视化,但该系统主要用于可视化目标值和比较数据集。与 DataPrep 不同,SweetViz 仅提供两个数据帧之间的比较。结果以彩色编码显示在可视化效果上,为数据科学家创造清晰的对比。

import sweetviz as sv
report = sv.analyze(df)
report.show_html()

SweetViz 中的报告演练

Lux 将自己标榜为一个 EDA 库,既简化又加速了数据探索。由于 Lux 简单的语法与 pandas 相结合,因此它可以被广泛的受众所接受。Lux 提供有限种类的可视化。数据分布用直方图显示,变量之间的相关性用散点图建模,分类变量的出现用条形图表示。Lux 可视化的一个独特方面是 Vis 和 VisList 对象,它们生成用户指定的可视化,包括条形图、直方图、散点图和折线图。

D-Tale 提供图形界面给用户与数据框进行交互。这种设计布局对大多数初学者来说很直观,因为它的用户界面与 Microsoft Excel 很相似。该界面有下拉菜单,通过简单的点击可以选择不同的可视化效果。D-Tale 支持各种可视化,如折线图、条形图、饼图、热图、文字云、地图和 3D 散点图,以汇总更大的数据集。D-Tale 为缺失分析提供了与 pandas-profiling 相似的可视化:热图、树状图、矩阵和条形图。使 D-Tale 脱颖而出的一种独特的可视化类型是可视化有向图的网络分析器。

功能

了解每个 EDA 工具的独特功能将有助于数据科学家明智地缩小选择范围。我们上面讨论的每种工具都有显著的特征,根据任务规范,这些特征可能使它们成为比其他工具更好的选择。

DataPrep 在幕后使用 Dask,并通过在分布式集群上扩展来提供更快的数据分析。这提高了系统通过加速计算处理更大数据集的能力。DataPrep 另一个突出的特性是多个数据帧之间的比较。plot_diff 函数可以采用具有两个以上数据框的列表参数,并并排绘制要素以便于比较。
DataPrep 是用户分析和比较两个以上数据帧的理想工具。总的来说,DataPrep 是处理大数据时最合适的选择,因为它具有多个数据帧的扩展功能和 Dask 实现以提高性能。

Pandas-profiling也因其处理大型数据集的能力而广受欢迎。该库支持配置以最小化为 EDA 报告生成的特征,从而仅突出显示用户所需的相关属性。Pandas-profiling 还通过其敏感特性解决了数据隐私问题,该特性只显示机密数据集中属性的聚合结果。
对于需要考虑数据隐私的小型数据集,Pandas-profiling 是一个不错的选择。Pandas-profiling 的性能不如像 DataPrep 这样基于 Pandas 实现的库。报告功能为数据集中的所有属性生成图,这增加了可视化参数和可定制性的复杂性。

SweetViz 为用户显示 EDA 报告提供了更大的灵活性。除了在 web 浏览器中以 HTML 格式呈现报告之外,还可以使用与 Jupyter、Google Colab 和其他笔记本兼容的 IFRAME 格式。最新版本的 SweetViz 提供 Comet.ml 集成,可通过 API 自动将生成的报告记录到用户的工作区。
SweetViz 是寻求可视化目标值和比较两个数据集的用户的合适选择。与 DataPrep 不同,SweetViz 支持最多两个数据帧之间的比较。

Lux 提供了导出静态可视化并将其集成到外部笔记本的便利。用户既可以直接下载他们的可视化,也可以将它们导出为代码。这使得编码为 vis 对象的可视化与 matplotlib、Altair 和 vega-lite 兼容,其中简单的函数可以为每个库输出相应的代码。

D-Tale 基于其交互式 GUI 脱颖而出,这使得数据格式化比其他库更容易。用户还可以选择类似 Lux 的选项,为相应的可视化导出代码片段,这允许更大的灵活性来修改可视化。
由于使用了 plotly 库,D-Tale 是生成交互式可视化的理想选择。这使得 D-Tale 比那些用静态可视化来呈现结果的库更有优势。

结论

比较库功能(图片由作者提供)

对于像 EDA 这样重要的任务,使用正确的工具可能不是每个用户都会想到的。虽然所有的库都有许多共同的特性,但是这些特性中的不明显的差异区分出了赢家。根据我们对库特性的详细探索和数据实验,DataPrep 在性能和可视化方面表现突出。

与 SweetViz 和 pandas-profiling 不同,DaraPrep 生成的 EDA 报告具有交互式可视化功能,可为用户提供有关他们正在分析的数据集的更多见解。别忘了,DataPrep 基于 Dask 的实现以最短的报告生成时间给了它显著的优势。数据准备。由于其高度优化的基于 Dask 的计算模块[1],EDA 比基于 Pandas 的分析工具快 10 倍。另一方面,pandas-profiling 和 Lux 可能是希望呆在 pandas 语法舒适区的用户的选择。这两个库都提供了额外的功能,只需对现有的数据帧进行简单的调用。为了进一步提高便利性,D-Tale 通过其交互式 GUI 消除了执行 EDA 任务所需的编码。每个用户可能重视 EDA 工具的不同特征,但是幸运的是,这五个 Python 库中的一个就足以提供用户所寻找的东西。

参考文献

[1]彭,吴伟源,布兰登洛克哈特,宋扁,景内森颜,徐,迟,Jeffrey M. Rzeszotarski,王建南: DataPrep .EDA:以任务为中心的探索性数据分析,用于 Python 中的统计建模。西格蒙德会议 2021:2271–2280

[2]安德烈什格。(2021 年 4 月 29 日)。自动化 EDA 库比较。卡格尔。检索于 2021 年 10 月 28 日,来自https://www . ka ggle . com/andreshg/automatic-EDA-libraries-comparisson

[3]t . b .(2021 年 10 月 19 日)。 7 个很酷的 python 包,Kagglers 在不告诉你的情况下在用。中等。检索于 2021 年 10 月 28 日,来自https://towards data science . com/7-cool-python-packages-kagglers-is-use-without-tell-you-e 83298781 cf 4

[4]洛克哈特,B. (2020 年 7 月 5 日)。探索性数据分析:Data prep . EDA VS pandas-profiling。中等。检索于 2021 年 10 月 28 日,来自https://towards data science . com/explorative-data-analysis-data prep-EDA-vs-pandas-profiling-7137683 fe47f

比较就职演说:民主之于梦想,正如拜登之于特朗普

原文:https://towardsdatascience.com/comparing-inaugural-addresses-democracy-is-to-dreams-as-biden-is-to-trump-8a1aaeba5f9c?source=collection_archive---------58-----------------------

使用自然语言处理工具的比较内容分析。包括 Python 实现概述。

路易斯·贝拉斯克斯在 Unsplash 上的照片

动机

直到拜登总统就职,我才可以松口气,花时间听奥巴马总统 700 多页的传记。引起我兴趣的一部分是他对就职演说的反思,这是一种庆祝胜利和变革希望的时刻,同时需要平衡经济危机将带来巨大痛苦这一令人清醒的事实。

我想知道我是否可以看看最近的总统就职演说,以了解总统们的具体个性,他们的支持者和政治派别,他们就职的时代,以及他们如何在演讲中平衡所有这些。我的问题是: 是什么让最近的总统演讲与众不同?

总统就职演说词云

拜登和奥巴马的语言侧重于席卷他们的危机,以及让他们能够克服的事情,而特朗普和布什则侧重于一些令人兴奋的概念,如梦想和故事。也许这是这些民主党人掌权的时代,但他们似乎更深入许多美国人每天面临的现实。共和党人似乎更专注于虚构的过去或想象的未来(我固有的偏见在这里闪耀…抱歉!).词云之所以伟大,是因为它们在几个层面上起作用——作为比较,当你真正一次专注于一个层面时,它们自己也能起作用。让我们开始吧!:

拜登

拜登总统的就职演说

深入挖掘拜登的讲话,很明显,他的目标是通过拥抱“民主”和“真理”,面对“病毒”——造成“400”k+人死亡的“病毒”,克服“谎言”,来团结人民。

特朗普

特朗普总统就职演说 TF-IDF Word Cloud 作者 Anupama Garla

看着特朗普的词汇云,我仍然对它对“梦想”、“受保护”、“权利”和“财富”的关注感到畏缩。有趣的一点是,他的语言似乎是分裂性的——反对的观点经常被提及,例如“奥巴马”、“左翼”、“外国”等。

奥巴马

奥巴马总统的就职演说

奥巴马将金融“危机”视为最大的挑战,但也是这一代人的机遇。我喜欢看到“地球”和“旅程”占据显著位置。我注意到的一件奇怪的事情是“men”和“man”的突出。

布什

布什总统的就职演说

布什专注于讲述一个“故事”,并使用通常相当积极和得体的概念,如果不是过度关注与军事使用相关的术语的话——“文明”、“自由”、“责任”、“荣誉”、“理想”、“原则”等。再次像特朗普一样,他的话似乎非常松散,指引我们走向文明的想象过去和自由给予者的未来。

方法学

从一个数据科学家的角度来看,我查看了每一次演讲中使用的实际词汇,并根据它们的频率和与最近其他总统相比的独特性进行了分析。我使用 TF-IDF 矢量化工具查看了每位总统的热门词汇,该工具根据每个词在每次演讲中的使用次数以及该词在所有演讲中的独特性对每个词进行加权。通过对所有演讲进行控制,我可以避免使用像“美国”这样的词,这样不会透露太多关于个人演讲的内容。然后我用 TF-IDF 向量制作了单词云。

Python 实现

  1. 导入/安装包
  2. 就职演说的 TF-IDF 矢量化
  3. TF-IDF 矢量化上的词云
  4. 导入/安装包
# Import pandas to use dataframesimport pandas as pd# Import TfidfVectorizer from the scikitlearn library to pre-process textfrom sklearn.feature_extraction.text import TfidfVectorizer# Import matplotlib and wordcloud to make wordcloud visualizations
import matplotlib as pltfrom wordcloud import WordCloud

如果你的环境中没有安装这些包,你可以在这里找到安装脚本:熊猫, Tfidf , matplotlib , wordcloud 。

2。TF-IDF 就职演说矢量化

我将每位总统的演讲储存在一个字符串变量中,这是从 UCSB 的美国总统项目中复制来的。如果你想要更多 csv 格式的演讲,我相信它们也可以在 kaggle 数据集中找到。然后,我将语音字符串变量加载到一个列表中,安装 Tfidf 矢量器,转置输出以创建一个用 TFIDF 值填充的术语文档矩阵。

# Make a list of text from the last 4 President's inauguration speechescorpus = [document_bush_2001, document_obama_2009, document_trump_2017, document_biden_2021]# Instantiate your Tfidf Vectorizer. Here, we can play with stop words, ngrams, and min and  max df settings.vectorizer = TfidfVectorizer(stop_words='english', ngram_range = (1,1), max_df = .6, min_df = .01)# You can always add to stop words, but I find that min and max df takes care of this automatically.  Stop 
# words are common words you don't want to consider like 'the' or 'of'
# ngrams allows you to choose a range of word lengths - 1, 2, or more - I'm sticking with single words
# max-df ignores terms whose document frequency is greater than the selected threshold
# min-df ignores terms whose document frequency is less than the selected threshold# Apply TfidfVectorizer to speech texts. X is a sparse matrix which holds the location of all non-zero values.X = vectorizer.fit_transform(corpus)# Extract words aka 'feature names' from vectorizerfeature_names = vectorizer.get_feature_names()# Create a dense matrix to convert into a list, and finally a dataframedense = X.todense()
denselist = dense.tolist()
df = pd.DataFrame(denselist, columns=feature_names)# Reshape dataframe to be a term-document matrixdata = df.transpose()
data.columns = ['document_bush_2001', 'document_obama_2009', 'document_trump_2017', 'document_biden_2021'] 

3。TF-IDF 矢量化上的字云

虽然 wordcloud 函数可以基于词频对文本进行矢量化,并允许您简单地输入文本弹簧,但我更喜欢使用我自己的矢量化工具来更好地控制输出。然后,Wordcloud 允许你使用“generate _ from _ frequencies”命令从频率中创建一个 wordcloud。我调整了 wordcloud 功能的一些设置,使输出分辨率更高,白底黑字,arial 字体,并使用每次演讲的前 500 个单词。我遍历了演讲和文件名,将 png 保存到。

# change the value to blackdef black_color_func(word, font_size, position,orientation,random_state=None, **kwargs):
    return("hsl(0,100%, 1%)")# instantiate lists of filenames to save pngs, columns to call the wordcloud function onfilenames = ['bush_2001_.png', 'obama_2009_.png', 'trump_2017_.png', 'biden_2021_.png']
columns  = list(data)# iterate through inaugural speech vectors to plot and savefor i in range(4):
    wordcloud = WordCloud(font_path = '/Library/Fonts/Arial Unicode.ttf', background_color="white", width=3000, height=2000, max_words=500).generate_from_frequencies(data[columns[i]])

    #change the color setting
    wordcloud.recolor(color_func = black_color_func)plt.figure(figsize=[15,10])
    plt.imshow(wordcloud, interpolation="bilinear")
    plt.axis("off")plt.savefig(filenames[i])

我在 Adobe Indesign 中展示了最终的可视化效果,但是我听说对于非设计师来说, canva 是一个很好的工具。如果我要遍历管道中的不同参数,我肯定会将输出编码到一个 matplotlib 画布中,其中包含一个 2 x 2 的演讲网格。对于这个小批量,我喜欢在 InDesign 中灵活地布局 png,并获得即时的视觉反馈,而不是每次做调整时都在 python 中一遍又一遍地重新渲染——我拥有流畅地使用 InDesign 的技能。

建议进一步阅读:

https://anupamagarla.medium.com/how-to-make-word-clouds-in-python-that-dont-suck-86518cdcb61f

比较 InfluxDB、TimescaleDB 和 QuestDB 时间系列数据库

原文:https://towardsdatascience.com/comparing-influxdb-timescaledb-and-questdb-timeseries-databases-c1692b9327a5?source=collection_archive---------11-----------------------

timeseries 数据库的高级概述,用于比较特性、功能、成熟度和性能

科技日报在 Unsplash 上拍摄的

我们生活在数据库的黄金时代,因为资金正以历史性的速度流入这个行业(例如雪花、 MongoDB 、蟑螂实验室、 Neo4j )。如果说关系型与非关系型或在线分析处理(OLAP)与在线事务处理(OLTP)之间的争论主导了过去十年,那么一种新型的数据库正日益受到欢迎。根据 DB-Engines ,一个收集和呈现数据库管理系统信息的计划,时间系列数据库是自 2020 年以来增长最快的领域:

时间系列数据库(TSDB)是针对接收、处理和存储带时间戳的数据而优化的数据库。这些数据可能包括来自服务器和应用程序的指标、来自物联网传感器的读数、网站或应用程序上的用户交互,或者金融市场上的交易活动。时间系列工作负载通常具有以下特征:

  • 每个数据点都包含一个时间戳,可用于索引、聚合和采样。该数据也可以是多维的和相关的。
  • 高写入速度(摄取)是捕获高频率数据的首选。
  • 数据的汇总视图(例如缩减采样或汇总视图、趋势线)可能比单个数据点提供更多的洞察力。例如,考虑到网络的不可靠性或传感器读数中的异常值,我们可以在某个时间的平均值超过阈值时设置警报,而不是在单个数据点上设置警报。
  • 分析数据通常需要在一段时间内访问它(例如,给我过去一周的点击率数据)。

虽然其他数据库也可以在一定程度上处理时间序列数据,但 TSDBs 在设计时考虑了上述属性,以便更有效地按时间处理数据接收、压缩和聚合。因此,随着云计算、物联网和机器学习对时间序列数据的需求持续爆炸,架构师应该如何选择 TSDB 呢?在本文中,我们将比较几个流行的 TSDBs 以及市场上的新玩家,以帮助您做出决定。

InfluxDB

InfluxDB 于 2013 年首次发布,现已超越之前的 Graphite 和 OpenTSDB,成为 TSDB 领域的市场领导者。与许多 OSS 数据库公司一样, InfluxDB 获得了 MIT 单节点许可,付费计划可用于 InfluxDB 云和 InfluxDB enterprise,提供集群和其他生产就绪功能。

图片来源: influxdata ,( MIT )

在 2019 年 InfluxDB 2.x 发布之前,InfluxDB 平台由 TICK 堆栈组成:Telegraf(收集和报告指标的代理)、InfluxDB、Chronograf(从 InfluxDB 查询数据的接口)和 Kapacitor(实时流数据处理引擎)。如下图所示,InfluxDB 1.x 主要关注来自服务器和 web 应用程序的时间序列数据。在 Prometheus 进入这一领域之前,InfluxDB 拥有最大的社区和集成来收集、存储和查看应用程序指标。

图片来源: influxdata ,( MIT )

InfluxDB 2.x 极大地简化了架构,将 TICK 堆栈捆绑到单个二进制文件中,并引入了新的功能,以使用 Flux 语言收集(例如本机 Prometheus 插件)、组织(例如组织和存储桶)和可视化(例如数据浏览器)数据。

为了理解 InfluxDB 是如何工作的,我们需要掌握以下关键概念:

  • 数据模型(标签集模型):除了时间戳字段,每个数据元素都由各种标签(可选的、索引的元数据字段)、字段(键和值)和度量(标签、字段和时间戳的容器)组成。下面的例子是科学家安德森和马伦在克拉马斯和波特兰收集的蜜蜂和蚂蚁的普查数据。这里的位置科学家是标签,属于蜜蜂和蚂蚁的普查测量的字段/值对。

图片来源: influxdata ,( MIT )

  • 数据模式(TSM & TSI) :数据元素存储在时间结构合并树(TSM)和时间序列索引(TSI)文件中。TSM 可以被认为是一棵 LSM 树,具有预写日志(WAL)和类似于表的只读文件,它们被排序和压缩。TSI 是 InfluxDB 内存映射的磁盘上文件的索引,以利用操作系统的最近最少使用(LRU)内存。这有助于处理高基数的数据集(即集合中的大元素)。
  • **Flux 脚本语言:**由 InfluxDB 开发的一种特定领域语言,用于帮助查询数据。Flux 还有一个sql包来帮助查询 SQL 数据源。

最值得注意的是,InfluxDB 在接收数据之前并不强制执行模式。相反,模式是从输入数据自动创建的,从标记和字段推断。这种类似 NoSQL 的体验既是 InfluxDB 的优势,也是其劣势。对于基数相对较低、自然适合这种标记集模型的数据集(例如,大多数基础设施和应用程序指标、一些物联网数据、一些财务数据),InfluxDB 非常容易上手,无需担心设计模式或索引。它在目标是创建物理资产的数字模型的用例中也大放异彩。例如,在物联网中,可能需要创建一个数字双胞胎来表示一组传感器,并以有组织的方式接收数据。

图片来源: TimescaleDB ,(阿帕奇)

另一方面,当数据集需要连续字段的索引(即 InfluxDB 不支持数字,因为标记必须是字符串)或数据验证时,“无模式”可能是一个缺点。此外,由于标签是索引的,如果标签经常变化(例如,元数据在初始摄取后可能会改变的用例),依赖 InfluxDB 来推断模式可能是昂贵的。

最后,InfluxDB 决定创建自己的自定义函数式数据脚本语言(Flux ),这给控制这个生态系统带来了另一层复杂性。InfluxDB 的团队指出了从类似 SQL 的 InfluxQL 转向 Flux 的两个动机:

  1. 时间序列数据符合基于流的功能处理模型,其中数据流从一个输出转换到下一个输出。SQL 支持的关系代数模型也不能处理这种操作和函数的链接。
  2. InfluxDB 希望对不属于 SQL 标准的时间序列数据(例如指数移动平均)的常见操作提供一流的支持。

Flux 语法肯定需要一些努力来适应,特别是如果您正在寻找简单的 SQL 查询或者不打算学习另一种新语言。仍然考虑到 InfluxDB 已经组装的大型社区和集成,Flux 的一些优势开始体现出来,尤其是当与内置仪表板结合时。

图片来源: influxdata ,( MIT )

总的来说,如果时间序列数据非常符合标记集模型,InfluxDB 是一个很好的选择。主要用例似乎是面向基础设施/应用程序监控,但作为该领域的市场领导者,InfluxDB 还可以与流行的数据源无缝集成。

  • 优点**:无模式摄取、巨大的社区、与流行工具的集成**
  • 缺点:数据集具有高基数、定制查询/处理语言

时标 b

InfluxDB 选择从头构建一个新的数据库和定制语言,而另一端是 TimescaleDB 。TimescaleDB 构建在 PostgreSQL 之上,并添加了一个名为 hypertables 的中间层,该中间层将数据分块到多个底层表中,同时将其抽象为一个大型表,以便与数据进行交互。

图片来源:时间刻度,(阿帕奇)

PostgreSQL 兼容性是 TimescaleDB 最大的卖点。TimescaleDB 完全支持所有 SQL 特性(例如连接、二级和部分索引)以及流行的扩展,如 PostGIS 。更重要的是,TimescaleDB 继承了运行 SQL 查询的开发人员以及大规模运行 PostgreSQL 的数据库和系统管理员数十年的知识。由于 TimescaleDB 可以被视为 PostgreSQL 的扩展,除了 TimescaleDB 自己的托管产品外,云托管选项(例如用于 PostgreSQL 的Azure Database、 Aiven )也很容易获得,更不用说虚拟机或容器上的无数自我管理选项了。

图片鸣谢: 2020 栈溢出开发者调查,( ODbL )

由于 TimescaleDB 最初是一个物联网平台,他们最初实际上使用 InfluxDB 来存储他们的传感器数据,因此它的功能对于物联网时间序列数据来说是一个好兆头,这些数据通常是突发性的,由于网络不可靠而经常出现故障,并且具有高基数的特点:

  • 超表: TimescaleDB 基于时间列以及其他“空间”值如设备 uid、位置标识符或股票代码,将其超表划分成块。这些区块可以配置为在内存中保存最新的数据,按照时间列(而不是摄取时间)对数据进行异步压缩和重新排序,并跨节点进行事务性复制或迁移。
  • 连续聚合: TimescaleDB 还支持连续聚合数据以快速计算关键指标,如每小时平均值、最小值和最大值。物联网数据通常在聚合时更有用(例如,给我下午 3 点到 4 点之间的平均温度,而不是下午 3 点的确切温度),因此不需要在每个聚合查询中扫描大量数据,这有助于创建高性能的仪表盘或分析。
  • ****数据保留:在传统的关系数据库中,大规模删除是一项开销很大的操作。然而,由于 TimescaleDB 以块的形式存储数据,因此它提供了一个 [drop_chunks](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/data-retention/#data-retention) 功能来快速丢弃旧数据,而没有相同的开销。由于旧数据的相关性会随着时间的推移而降低,因此可以将 TimescaleDB 与长期存储(例如 OLAP 或 blob 存储)结合使用,以移动旧数据,从而节省磁盘空间并保持较新数据的高性能。

至于性能,TimescaleDB 有一个全面的帖子,详细介绍了使用时间序列基准测试套件(TSBS) 比较 TimescaleDB 版本 1.7.1 和 InfluxDB 1.8.0(两个 OSS 版本)的插入和读取延迟指标。这两个数据库现在都有 2.x 版本,所以这种分析可能有点过时,但结果显示,随着数据基数的增长,TimescaleDB 的性能会更好(大约 3.5 倍的性能)。

图片来源: TimescaleDB ,(阿帕奇

TimescaleDB 团队指出 InfluxDB 的基于日志结构合并树的系统(TSI)与 TimescaleDB 的 B 树索引方法的根本原因。然而,这里的要点并不一定是 TimescaleDB 在性能方面优于 InfluxDB。性能基准是固执己见的,并受到数据模型、硬件和配置的严重影响。相反,该结果表明,TimescaleDB 可能更适合数据基数较高的物联网用例(例如,给我 1000 万台设备中设备 X 的平均功耗)。

要深入比较这两个数据库,请查看:

**https://blog.timescale.com/blog/timescaledb-vs-influxdb-for-time-series-data-timescale-influx-sql-nosql-36489299877/

总的来说,TimescaleDB 非常适合那些寻求大幅提升性能而不需要进行大量重构来迁移现有 SQL 数据库的团队。尽管 TimescaleDB 仍然相对较新(2017 年首次发布),但基于 PostgreSQL 构建的决定使其采用数量达到了前 5 名。有趣的是,我以前的物联网初创公司也使用 TimescaleDB 作为中间数据存储,来快速提取跨越几个月的聚合指标,并将旧数据移动到长期存储中。由于我们已经在 Kubernetes 集群上运行 PostgreSQL,安装 TimescaleDB 和迁移我们的工作负载是一项简单的任务。

  • 优点:兼容 PostgreSQL,可随数据基数很好地扩展,提供各种部署模型
  • 缺点:固定模式(在接收之前增加了一点复杂性和数据转换工作)

QuestDB

对于那些希望利用 InfluxDB line 协议的灵活性和 PostgreSQL 的熟悉性的人来说,一个较新的 timeseries 数据库可以同时满足这两个要求,而不会牺牲性能。QuestDB (YC S20)是一个用 Java 和 C++编写的开源 TSDB,尽管它在不到一年前推出,但它现在已经跻身前 15 名。在底层, QuestDB 利用内存映射文件在数据提交到磁盘之前支持快速读写。

图片鸣谢: QuestDB ,(阿帕奇)

通过用 Java 和 C++从头开始构建数据库,QuestDB 团队专注于三件事:

  • **性能:**解决接收瓶颈,尤其是高基数数据集。它还支持快速数据检索,方法是始终按顺序存储时间分区的数据(通过在内存中混排),并且只分析请求的列/分区,而不是整个表。最后,QuestDB 应用 SIMD 指令来并行化操作。
  • 兼容性: QuestDB 支持 InfluxDB 线路协议、PostgreSQL 线路、REST API、CSV 上传摄取数据。习惯于其他 TSDBs 的用户可以轻松地移植到他们现有的应用程序上,而无需进行大量的重写。
  • **通过 SQL 查询:**尽管支持多种摄取机制,但 QuestDB 使用 SQL 作为查询语言,因此不需要学习像 Flux 这样的特定领域语言。

在性能方面,QuestDB 最近发布了一篇博客文章,展示了实现每秒 140 万行写入速度的基准测试结果。QuestDB 团队在 AWS 上的m5.8xlarge实例上使用了多达 14 个作品的cpu-only用例使用了 TSBS 基准测试(注意:140 万的数字来自于使用 AMD Ryzen5 处理器)。

图片来源: QuestDB ,( Apache )

对于具有高基数(> 1000 万)的数据集,QuestDB 也优于其他 TSDBs,在采用英特尔至强处理器的 m 5.8 XL 大型实例上使用 4 个线程,峰值接收吞吐量为 904 千行/秒,在 1000 万台设备上维持约 64 万行/秒。当相同的基准在 AMD 锐龙 3970X 上运行时,QuestDB 显示每秒超过一百万行的摄取吞吐量。

图片鸣谢: QuestDB ,(阿帕奇)

同样,基于数据模型和数据库调优,性能基准可能是主观的,但它仍然为 QuestDB 描绘了一个引人注目的比较点。看看使用devopsiot模式的结果会是多么有趣,因为 InfluxDB 和 TimescaleDB 都支持 TSBS 的开箱即用用例。

QuestDB 的另一个有趣的组件是对 InfluxDB 内联协议和 PostgreSQL 接收线的支持。对于现有的 InfluxDB 用户,您可以简单地配置 Telegraf 指向 QuestDB 的地址和端口。同样,对于 PostgreSQL 用户,使用现有的客户端库或 JDBC 将数据写入 QuestDB。无论采用何种摄取方法,都可以使用标准 SQL 查询数据,值得注意的例外情况列在 API 参考页面上。

作为该领域的新成员,QuestDB 最明显的缺点是缺乏对基础设施功能的支持(如复制、自动备份/恢复)。它已经与一些最流行的工具(如 PostgreSQL、Grafana、Kafka、Telegraf、Tableau)集成,但要达到上述其他 TSDBs 的水平还需要一些时间。

尽管如此,QuestDB 是一个很有前途的项目,可以平衡 InfluxDB 和 TimescaleDB 的优点:

  • 优点:快速摄取(特别是对于高基数数据集),支持 InfluxDB 协议和 PostgreSQL 连接,通过标准 SQL 查询
  • 缺点:较小的社区,可用的集成,生产就绪

结论

随着对时间序列数据需求的持续增长,专门处理这些数据的 TSDBs 将被大量采用,同时也会面临激烈的竞争。除了本文介绍的三个开源 TSDBs,还有来自 AWS ( AWS Timestream )和 Azure(Azure Series Insights)的公共云产品。

与所有数据库一样,选择“完美的”TSDB 主要取决于您的业务需求、数据模型和用例。如果您的数据符合具有丰富集成生态系统的标签集模型,那么 InfluxDB 可以很好地工作。TimescaleDB 非常适合现有的 PostgreSQL 用户。最后,如果性能是主要关注点,QuestDB 是一个很有前途的项目,正在快速发展。**

Keras 和 PyTorch 在情感分类上的比较

原文:https://towardsdatascience.com/comparing-keras-and-pytorch-on-sentiment-classification-20041734d131?source=collection_archive---------25-----------------------

IMDB 电影评论的实用比较

照片由 卡罗琳娜·格拉博斯卡 发自 佩克斯

在第一部分概述了 Keras 和 PyTorch 语法之后,这是我们比较 Keras 和 PyTorch 的第二部分!这一部分更实用,因为我们将实现一个神经网络来按情感对电影评论进行分类,并比较分类结果。

正如我们在第一部分中看到的,Keras 和 PyTorch 在设计上是不同的

  • Keras 的目标是快速原型制作。它旨在编写更少的代码,让开发人员专注于其他任务,如数据准备、处理、清理等
  • PyTorch 的目标是模块化和多功能性。对计算流程的细粒度控制

然而,这两个框架的目的是一样的,那就是训练深度神经网络。“罗塞塔石碑”风格教程的资源在网上的数量非常有限,尤其是演示实际例子的资源,所以我希望这有助于揭开两个框架之间的区别和相似之处。现在让我们开始吧!

IMDB 电影评论数据集

我们将使用 IMDB 数据集,这是机器学习中一个受欢迎的玩具数据集,由来自 IMDB 网站的电影评论组成,由正面或负面情绪注释。

Keras 和 PyTorch 都有助手函数来下载和加载 IMDB 数据集。因此,我们将使用这段代码在 Keras 中导入 IMDB 数据集,而不是像我们在第一部分中看到的那样使用数据加载器。

这将创建一个文件夹data/,并在其中下载数据集。它将数据分成训练集和验证集两部分。输出给出了序列的数量。

25000 Training sequences
25000 Validation sequences

使用 torchtext,PyTorch 也可以以同样的方式下载和加载 IMDB 数据集。但是为了确保我们提供给 Keras 的数据和我们提供给 PyTorch 的数据是相同的,我将简单地修改从 Keras 下载到 PyTorch 的数据,这样我们就可以确保两个实现之间的一致性,特别是在数据清理和文本标记化方面。

此外,我们将填补电影评论有相同长度的序列。这对于批量训练很重要,因为不可能并行计算可变长度序列的误差梯度。

我们将评论的长度固定为 200 个单词,将词汇表固定为 20k 个不同的单词。数据集已经被清理和标记,所以我们可以直接把它输入神经网络!在继续之前,出于好奇,我们可以看一下数据集中的一些例子。我们需要使用imdb.get_word_index获取单词词汇表,这将让我们把数据集中的整数解码成简单的英语。

使用上面的代码,我们可以检查数据集中的序列“1,13,165,219,14,20,33,6,750,…”对应于

<START> i actually saw this movie at a theater as soon as i handed the cashier my money she said two words i had never heard at a theater before or since no <UNK> as soon as i heard those words i should have just <UNK> bye bye to my cash and gone home but no foolishly i went in and watched the movie this movie didn't make anyone in the theater laugh not even once not even <UNK> mostly we sat there in stunned silence every ten minutes or so someone would yell this movie sucks the audience would applaud enthusiastically then sit there in stunned bored silence for another ten minutes <PAD> <PAD> <PAD> [...]

我们可以打印与此评论相关的情绪,即y_train[50],0 表示“负面”。看起来没错。

但是等等!我们需要修改 PyTorch 的数据。这段代码将完成这项工作。

TensorDataset类将把我们的数据转换成 torch tensors,切片成批,然后洗牌。然后使用一个DataLoader实例,我们将能够迭代这些批次。

很好!数据准备好了,让我们定义我们的分类器。

分类器模型

我们的分类器是一个在嵌入层之上的双向两层 LSTM,后面是一个给出一个输出值的密集层。这个输出值给出了一个评论是正面的概率。越接近零,评论被预测为越负面,越接近一,评论被预测为越正面。为了获得这样的概率,我们使用 sigmoid 函数,该函数获取神经网络的最终输出,并将该值压缩在 0 和 1 之间。

我们将定义以下两个超参数,以确保两个实现匹配。

embedding_dim = 128
hidden_dim = 64

让我们从 Keras 中的实现开始(归功于官方的 Keras 文档)

现在,让我们在 PyTorch 中实现同样的功能。坚持住,因为有一些技术上的微妙之处需要注意。我想先向您展示什么是幼稚的实现

如果你读了第一部分,这段代码就不会有什么惊喜了。在 PyTorch 中,我们简单地详述了一些计算,而 Keras 在我们堆叠层时推断出它们。

现在坏消息是这个实现与 Keras 的实现并不完全相同。而且主要区别是初始化!要让两个框架在初始化上达成一致,需要做大量的工作。例如,您可以看到 Keras 的Embedding层使用均匀分布初始化其权重,而 PyTorch 使用的是正态分布。让我们开门见山,使用下面的方法使 PyTorch 初始化适应 Keras。

这是取自 torchMoji 的一个很好的片段,它是 HuggingFace 对 DeepMoji 的 PyTorch 实现。我们现在在 PyTorch 中有了更新的 BiLSTM 类。

嗯……正如你所看到的,即使对于非常基础的架构,转移代码也不是一件容易的工作。甚至细节对于实现类似的结果也很重要,但是请耐心等待,因为这是我能得到的最接近 Keras 实现的结果。

一个快速的完整性检查是验证两个实现的参数数量是否匹配。model.summary()在 Keras 中输出以下内容。

Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, None, 128) 2560000 _________________________________________________________________ bidirectional (Bidirectional (None, None, 128) 98816 _________________________________________________________________ bidirectional_1 (Bidirection (None, 128) 98816 _________________________________________________________________ dense (Dense) (None, 1) 129 ================================================================= Total params: 2,757,761 Trainable params: 2,757,761 Non-trainable params: 0 _________________________________________________________________

用 PyTorch 打印带有print(model)的模型表明我们有相同的架构。

BiLSTM(
  (encoder): Embedding(20000, 128)
  (lstm): LSTM(128, 64, num_layers=2, bidirectional=True)
  (linear): Linear(in_features=128, out_features=1, bias=True)
  (activation): Sigmoid()
)

但是这并没有告诉我们参数的数量。这一行给出了我们想要的(感谢费德里科·巴尔达萨尔

sum(p.numel() for p in model.parameters() if p.requires_grad)

这给出了 2758785 个参数。哦!参数个数不一样!?在深入研究这个问题后,我发现 PyTorch 有第二个偏差张量,这是因为它在实现 LSTM 时与 CuDNN 兼容。你可以有效地检查计数差是否等于2,758,785 - 2,757,761 = 1024,也就是2 * 4 * 2 * 64 = 1024。其中,我们将一个 LSTM 单元的偏置向量的大小 64 乘以 2,因为我们有一个前向和一个后向 LSTM,再次乘以 2,因为我们使用了两个层,而 4 是 LSTM 定义中的门的数量。即使有这样的基础架构,也会出现微妙而重要的差异。

现在让我们来看看实现是如何执行的。

培养

我们将使用以下参数进行培训。

batch_size=32
epochs = 2

在喀拉斯,这个一行程序将完成这项工作

model.fit(x=x_train, y=y_train,
          batch_size=batch_size, epochs=epochs,
          validation_data=(x_val, y_val))

现在使用 PyTorch,记住 Keras 在幕后做的每一件事都必须显式编写。首先是初始化日志、损失标准、模型、设备和优化器。

接下来是训练循环。我使用我推荐的[tqdm](/training-models-with-a-progress-a-bar-2b664de3e13e) 库来打印一个漂亮的进度条,和 Keras 一样。

注意model.train()model.eval()方法的使用,它们将model.training设置为TrueFalse。它决定是否在正向过程中保持梯度,这将用于在反向过程中优化网络。

我用torch.nn.utils.clip_grad_norm_(model.parameters(), 5)将权重渐变剪辑为 5。我不确定 Keras 是如何处理渐变裁剪的,但是实现这种技术来避免渐变爆炸的问题通常是很好的实践。

最后一点是关于维度的排序。正如我在第一部分中所解释的,Keras 默认期望批处理维在第一位,而 PyTorch 期望它在第二位。因此,通过samples.transpose(0, 1),我们有效地置换了第一个和第二个维度,以适应 PyTorch 数据模型。

现在,同样地,Keras,当我们到达一个时代的终点,我们想要评估这个模型。

结果

在下面的表中,我报告了每个训练时期的结果,是批次数的平均值。

训练集上的历元结果。

验证集上的纪元结果。

下图显示了训练期间批次的损失和二进制精度。

批量训练损失

批量训练准确度

我们可以注意到 Keras 实现的准确性和损失的突然增加。如果我们优化学习速度,这可能会减少。

临终遗言

即使非常小心,使用相同的架构、数据处理和训练也很难获得完全相同的结果,因为每个框架都有自己的内部机制、设计和特定的技巧来保证数值稳定性。尽管如此,我们得到的结果是接近的。

有一些雄心勃勃的项目,如 ONNX 创建深度学习框架之间的标准,以实际解决我们在本文中看到的差异。

我希望你喜欢 Keras 和 PyTorch 的比较,我想看看你的想法和反馈!祝你在机器学习的旅途中一切顺利!

原载于 2021 年 3 月 20 日https://adamoudad . github . io

比较 Keras 和 PyTorch 语法

原文:https://towardsdatascience.com/comparing-keras-and-pytorch-syntaxes-54b164268466?source=collection_archive---------28-----------------------

入门

数据加载、模型定义和张量操作

图片由 cottonbro 来自 Pexels

Keras 和 PyTorch 是构建深度学习程序的流行框架。前者,Keras,更准确地说是 Tensorflow 的抽象层,提供快速原型化模型的能力。
py torch 上面也开发了类似的抽象层,比如 PyTorch Ignite 或者 PyTorch lightning 。它们还没有 Keras 成熟,但是值得一试!

我发现很少有资源或文章比较 Keras 和 PyTorch 中的代码,我将在本文中展示这样的例子,以帮助理解框架之间在语法和命名方面的主要差异。

本文是系列文章的第一篇。在下一篇文章中,我将通过一个实例来比较框架,这个实例就是情感分类。

准备数据

第一个比较是关于如何装载和准备数据。在两个框架中,加载数据的方式非常相似,在 Keras 中使用utils.Sequence类,在 PyTorch 中使用utils.dataset。在喀拉斯,你会看到这样的东西

这是 PyTorch 中的相同代码。

定义和构建模型

在 Keras 中,我们可以同时定义和构建模型。在下面的例子中,我们使用【https://keras.io/api/models/sequential/】()来构建一个具有嵌入层和单个神经元输出的 LSTM 网络。

这是 PyTorch 同样的建筑。

__init__函数实例化网络的不同模块,而实际计算由forward函数决定。实际上,我们仍然需要像 Keras 例子中那样“编译”模型。然而,正如您将在如何训练模型中看到的,我们在 PyTorch 中分别定义了度量、模型和优化器,并在训练循环中需要时调用它们。所以我们只需要定义与上面相同的度量标准和相同的优化器。

在大多数情况下,Keras 中的默认参数将与 PyTorch 中的默认参数相匹配,Adam 优化器和 BCE(二进制交叉熵)损失就是这种情况。

总而言之,我们有了这两种语法的对照表。

Keras 和 PyTorch 语法对照表

操纵张量

两种框架在操作张量的语法上都有自己的特点。这里我们将对比 PyTorch 和 Tensorflow。

张量的形状

Pytorch 有.shape.size,都相当于访问张量的形状。

import torch
t = torch.zeros((4, 3))
print(t.shape, t.size())         # Both equal to (4, 3)
t.shape[1], t.size(1)     # Both equal to 3

张量流只有.shape

t = tf.zeros((4, 3))
print(t.shape)            # .size is not available
print(t.shape[1])

维度的顺序

Keras 通常将尺寸排序为(batch_size, seq_len, input_dim),而 Pytorch 更喜欢将它们默认排序为(seq_len, batch_size, input_dim)。在 PyTorch 中,像 LSTM、GRU 这样的循环网络有一个开关参数batch_first,如果设置为True,它将期望输入为(seq_len, batch_size, input_dim)的形状。然而,像变压器模块没有这样的参数。在这种情况下,必须调整输入。为此,您可以使用.transpose方法在 Pytorch 中切换尺寸。

data = torch.Tensor(tensor_with_batch_first)
data.transpose(0, 1)            # Switch first and second dimensions

从并行计算的角度来看,PyTorch 选择的顺序更加自然。例如,循环层将在序列的每一步并行应用于所有批次,因此我们将迭代第一个seq_len维度。就模型架构而言,Keras 首选的顺序更自然,因为我们宁愿考虑将一个输入序列输入到模型中,然后简单地为一个批处理复制操作。

初始化向量

PyTorch 的语法与 numpy 非常相似。

# Matrix of size (2, 4, 1) filled with 1
torch.ones(2, 4, 1)# Identity matrix of size (3,3)
torch.eye(3)

好消息!以上所有方法在 Tensorflow 中都存在,并且工作方式相同。
此外,我们还有torch.full,它相当于numpy.fill,用一个值填充一个张量。Tensorflow 有tf.fill

# Fill a (2, 4) matrix with 3.14 value
torch.full((2, 4), fill_value=3.14)
tf.fill((2, 4), value=3.14)

以下是如何对随机数矩阵进行采样。

# Sample from N(0, 1) a matrix of size (2, 3)
torch.randn(2, 3)
tf.random.normal(shape=[2, 3])# Sample uniformely a (2, 5) matrix of integers within [10, 20[
torch.randint(low=10, high=20, size=(2, 5))
tf.random.uniform(shape=[2, 5], minval=10, maxval=20, type=tf.int64)

随机数生成器的再现性种子可以用

torch.random.manual_seed(0)
tf.random.set_seed(0)

结论

虽然 Keras 和 Pytorch 具有非常相似的数据加载逻辑,但它们的语法在其他方面有很大不同。PyTorch 有 pythonic 式的语法,而 Keras 是为编写简短的程序而设计的,不需要花太多时间解释构建块。还有更多的比较点,但我希望这篇文章能对这两个框架提供一些见解。为了完整起见,我分享了一些我找到的关于 Keras 和 PyTorch 的比较资料。

  • Keras 和 PyTorch 与 ConvNet 架构的比较和速度基准:https://deepsense.ai/keras-or-pytorch/
  • 一个多 GPU 框架对比:https://medium . com/@ iliakarmanov/multi-GPU-Rosetta-stone-d4fa 96162986
  • 深度学习框架之间的一个罗塞塔石碑库:【https://github.com/ilkarman/DeepLearningFrameworks/
  • Keras 和 PyTorch 在图像分类上的比较:https://deep sense . ai/Keras-vs-py torch-AVP-transfer-learning/

你完成了第一部分!下面的第二部分比较了 Keras 和 PyTorch 的情感分类。

原载于 2021 年 3 月 2 日https://adamoudad . github . io

比较克鲁夫咖啡筛:新的和旧的

原文:https://towardsdatascience.com/comparing-kruve-coffee-sifters-new-and-old-677e8b16ec62?source=collection_archive---------22-----------------------

咖啡数据科学

惊人的发现

在之前的中,我已经使用孔分析检查了 Kruve 过滤器。我发现它们比目前市场上的任何网格都要好,我怀疑这仍然是真的。当时,我只有几个屏幕。我最近买了整套,我决定对整套做同样的研究。

我也有一个独特的机会来比较 400 微米和 500 微米的筛网,从原来的 Kruve 到目前正在制作的筛子。

很快,我注意到他们在屏幕的质地上感觉有点不同。我对比了几张照片,发现分布立即发生了变化。

所有图片由作者提供

所以我首先用显微镜来观察屏幕。

400um

400um,顶部/底部:宽/放大;左/右:旧/新

200um

200um,顶部/底部:宽/放大;左/右:旧/新

新的孔看起来有锥度,这很好,因为咖啡更容易通过。似乎新屏幕功能更好。

孔洞测量

我用图像处理来测量这些洞。我把每个屏幕放在一个明亮的屏幕上,然后我拍了一张照片。然后,我隔离屏幕,测量所有的洞,了解地面的真相,将像素转换成现实世界的坐标。

我用两种类型的图来表示这些数据:箱线图和彩色分布图。以下是箱线图在点数分布方面的含义:

数据有明显的变化。这可能是由几个因素造成的,但考虑到这种趋势的线性程度,我怀疑这要么是阈值,要么是金属以一种奇怪的方式反射的光。

所以我用这个最佳拟合来调整数值。过去的每个屏幕仍然有一点重叠。大部分的洞都有相同的大小,这种变化的一部分可能是由于相机的角度。

所以我用代表孔大小的颜色制作了过滤器的图像。这个假颜色显示了最大和最小的孔尺寸。许多屏幕上都有奇怪的图案,我不知道为什么。但它确实存在,我拍了多张照片来验证它。我不认为它影响性能,它可能是封装中屏幕上的一些胶带在表面上的反射。

黄色表示最大尺寸,蓝色表示最小尺寸

最后 5 个屏幕有奇怪的效果。某些影响不是由图像的缩减采样引起的。我把 600um 和 200um 的屏幕放在这里做参考。我怀疑是制造过程的一部分造成的。

左:600 微米,右:200 微米

旧与新

我只是对比了新旧屏幕。旧屏幕是克鲁夫第一次筹资时的。这些图在测量上有线性调整。对于 400 微米的屏幕,有向较大孔的轻微偏移,而对于 500 微米的屏幕,有向较大孔的较大偏移。

只有孔尺寸的变化

我只看了孔尺寸的变化,因为孔尺寸的变化随着孔尺寸的变大而变小。

我们可以跟踪标准差,除了最初的几个筛子之外,还可以看到一个线性趋势。这是一个很好的迹象,表明筛子是在严格的质量规范下制造的。

Kruve 最初的目标是帮助分离特定的研磨尺寸,并允许人们修改研磨分布。然而,这个工具改变了我的浓缩咖啡体验。首先,它在制作断续的镜头,但后来我开始用筛子做咖啡实验。克鲁夫筛对于理解咖啡非常有用。我曾多次用他们的筛子来试验和了解咖啡。

从旧筛到新筛的分布有一些变化,但筛子仍然工作。

主要的收获是,这些孔的分布可以让你更好地了解任何两个滤网之间有多少重叠。

我确实在克鲁夫提供的 30%折扣上买了克鲁夫。公平地说,几年来,我一直是筛选咖啡的大力提倡者,所以这不应该是一个很大的惊喜,但我想确保提前。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在中和订阅。

我的进一步阅读:

我未来的书

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页面

使用图像处理测量咖啡研磨颗粒分布

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡用纸质过滤器

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维护

咖啡评论和想法

咖啡实验

比较定位策略:沃尔玛与塔吉特

原文:https://towardsdatascience.com/comparing-location-strategies-walmart-vs-target-d2bb00c9c7b3?source=collection_archive---------16-----------------------

数据支持你对这些商店的看法吗?

丹尼尔·奥登内尔在 Unsplash 上拍摄的照片

你有没有见过一个你熟悉的品牌,然后对自己说……'哇,这似乎是他们的一个完美地点'?冒着过分简化和陈述显而易见的风险,公司定位在他们认为他们的目标客户会在的地方。当我们从总体上看位置时,我们可以了解一家公司的目标客户是谁,它对他们的位置策略&目标人群有什么建议,以及它与竞争品牌相比如何。

只需几行代码(嗯,可能比几行多一点)和一些漂亮的可视化,我们就可以对一家公司的定位策略有一个基本的了解,甚至更有趣的是,他们下一步可能会去哪里。

在这个系列的第一部分,我们将介绍两个你可能很熟悉的大盒子零售商——沃尔玛和塔吉特。关于他们的客户群,这些数据说明了什么?这和你认为你对他们的了解相比如何?

有兴趣直接比较这些品牌和其他品牌吗? 查看此可视化 以获得更多见解和数据。

底线,提前

作者图片

数据显示,典型的沃尔玛位于人口众多、收入低于平均水平、经济活动中等的邮政编码区。典型的目标位于人口非常多的邮政编码区-甚至周边地区人口更多-此外还有高于平均水平的收入、高经济活动和高人口密度。

塔吉特百货周边地区的高人口密度(距离邮政编码中心约 10 英里)和高人口密度(每平方英里土地上的人口)表明,它主要位于靠近城市的地区,而沃尔玛位于人口众多但距离市中心较远的城镇。

比较这两个品牌,沃尔玛更有可能位于远离平均收入和人口密度较低的大都市地区的人口中心,而塔吉特更有可能开设在周围人口较多、经济活动较活跃的大都市中心及其周围(周围有餐馆、健身房等)。).

地理洞察力

图片由作者提供;按品牌划分的商店位置热图。

将这两个品牌商店的地理集中程度形象化,可以看出它们在选址策略上的惊人差异,强调了上述数据中的差异。第一次看地图时,你看到了什么?

请注意 Target(左侧的地图)在海岸和美国中部城市中心及其周围的密集度(商店数量)非常高。只要看看地图,你就能看到城市——洛杉机、芝加哥、纽约、费城、DC、波斯顿等等。—是其战略的中心,周围有光环效应,以捕捉更高收入的郊区。之后,他们在剩下的州中寻找可能代表人口中心的目标位置,例如大学城、州首府或人口较少的州的其他大都市区。

图片由作者提供;同上,以便于查看

另一方面,沃尔玛有效地将中国一分为二,几乎覆盖了中国东半部的所有地区,并在中国西半部实施了更加以城市为导向的战略。请注意沃尔玛的覆盖范围比目标海岸多了多少。实际上,整个地图覆盖了从国家的中心到大西洋!这验证了早期关于其在具有高直接区域人口但较低周边人口的区域中的覆盖的见解。

作者图片

从地理上看,超过一半的沃尔玛商店位于南方各州,相比之下,塔吉特的商店只有三分之一。Target 在西部的比例更高,最明显的是在加州。沃尔玛还有大约 15%的门店位于我们认为的农村地区,而塔吉特超过 90%的门店位于我们认为的城市地区。

人口统计洞察

作者图片

有趣的是,我们发现客户的人口统计学特征几乎没有差异。Target 拥有学士以上学位的成年人口比例略高(约 40%对约 30%),但在其他方面,我们看到,按年龄和家庭规模划分,数据非常相似。

这表明这两个品牌之间的主要分界点是他们选择开店的地点,而不一定是他们的目标客户的人口统计特征。他们销售的商品的市场几乎是全球性的,塔吉特百货选择采取更高端的方式销售产品,这就要求他们选择与顾客一致的区域。

这一切意味着什么

总体而言,这些数据似乎强化了这些公司的品牌和营销。沃尔玛通常以价格竞争而闻名,同时目前正在扩大其在线业务,而塔吉特则以高端大卖场零售商而闻名。因此,我们认为塔吉特百货位于主要大都市区及其周边收入高于平均水平的地区,而沃尔玛倾向于位于收入低于平均水平的市中心以外的人口稠密地区。

位置策略是一个迷人的话题——至少对我来说是这样,如果你已经走了这么远,希望你也是这样。可以认为只有大公司才有资源和人才来制定战略,但各种规模的公司在寻求扩张时都可以从数据中受益。你不需要最花哨的模型来受益——更简单、更直接总比什么都没有好,有时甚至比花哨的模型更好。

除了剖析公司,正如我们上面看到的,我们还可以扩展这些见解,以找到符合某些特征的新领域。假设你是一家零售商,目标客户是东北部城市地区的高收入千禧一代购物者。这不会告诉您要定位的确切地址,但数据可以将我们的搜索范围从整个东北部缩小到仅符合该特征的区域,从而使企业主可以花更多宝贵的时间在目标区域搜索最佳的十字路口、街道或位置,而不是花更多时间在更多位置猜测哪个可能是最好的。

链接到可视化工具亲自探索数据和其他品牌!

对连接或了解更多位置分析感兴趣吗? 在 LinkedIn 上联系我,或者在 jordan@jordanbean.com 给我发邮件。

开放式健身房的最优控制

原文:https://towardsdatascience.com/comparing-optimal-control-and-reinforcement-learning-using-the-cart-pole-swing-up-openai-gym-772636bc48f4?source=collection_archive---------14-----------------------

思想和理论

最优控制与强化学习的比较

经典控制比人们想象的更类似于强化学习。然而,它们之间的关键区别是,在控制中,我们假设知道潜在的系统动力学,而在强化中,我们不知道。|(图片由作者提供)

自主系统的想法令我兴奋,将强化 学习应用于一切事物以实现自主似乎很有诱惑力。但这并不总是那么容易,使用最优 控制有时可能是更好的解决方案。虽然我确实看到了结合最优控制和机器学习来提高物理系统性能的巨大潜力(例如学习模型预测控制 [1]),但我不想在这个话题上谈论太多细节,也许在即将到来的帖子中。在这篇文章中,我想展示的是在最优控制和强化学习的高层次上的相似性(和差异)使用一个简单的玩具例子,这个例子在控制工程和强化学习社区都很有名——来自OpenAI Gym 的Cart-Pole。我不会为推车杆重新实现强化学习算法——没有必要重新发明轮子— ,因此我鼓励你阅读这篇由陈伟璇撰写的关于将 Q-Learning 应用于推车杆任务的帖子或者这篇关于 arXiv.org的精彩教程。

我将从简单介绍手推车杆子开始,然后更详细地介绍解决该任务的最优控制方法及其使用 Python 的实现,最后进行简短的讨论。所以我们走吧!

手推车杆子

车杆的动力学。|(图片由作者提供)

推车杆由一根与水平移动的推车相连的杆组成。为了解决这个问题,必须通过对小车施加力来平衡杆子。该系统是 非线性 ,因为杆的旋转将三角函数引入力平衡方程。此外,当极点处于直立位置时,系统的平衡是不稳定,因为小的扰动会导致极点向下摆动。

大车拉杆的状态是大车的距离 s ,大车的速度 ,拉杆的角度 θ 和拉杆的角速度 θ̇ 。参数为 mₚ 为杆的质量, mₖ 为小车的质量, Jₚ 为转动惯量。在 OpenAI Gym 的 Cart-Pole 环境中实现时,描述系统动态的方程可以在这里看到。

既然我们已经定义了我们的系统和它的动力学,让我们试着用最优控制来控制它!

推车杆的最优控制

在这一节中,我将提供由 布莱恩·道格拉斯 MATLAB合作制作的视频链接,因为他精彩地解释了控制的基本原理!

具有状态反馈控制器的系统的状态空间表示

为了控制小车,我们将设计一个线性二次调节器 ( LQR ),它将产生一个最佳控制增益 K 。我们将反馈环境的状态 x 并且 K 将确定我们输入到系统中的u 力 F ,我们希望这样施加到推车上以平衡杆子。**

然而正如 LQR 所说,我们实际上需要一个的线性系统模型,但是当我们分析我们的系统时,我们发现它是 非线性 幸运的是,control 有一个名为 线性化 的工具,它对应于围绕所需工作点的一阶泰勒展开(这里有一个视频介绍线性化的基本原理)。如果我们在我们系统的上平衡附近执行线性化,其中我们的状态 xx = ( s,ṡ,θ,θ̇)= (0,0,0,0) ᵀ 我们得到一个线性系统,它可以用状态空间表示写成:

现在我们有了状态空间表示,我们可以开始设计 LQR 了。在高层次上,LQR 试图通过最小化下面的成本函数来找到最优控制矩阵 K

其中 QR 是权重矩阵,必须由我们定义。 Q 陈述进口性能如何,以及 R 使用我们的控制如何昂贵。因此, QR 定义了,我们实际上所认为的 最优 。解这个积分初看起来很难,但是通过部分积分是可以做到的。由于成本函数是二次的,我们知道存在一个唯一的最小值,这可以通过代入=-Kx(见图中)并将导数设置为零来找到。我们得到的是代数黎卡提方程:****

在求解出 P 之后我们可以计算出我们的控制器 Kk= inv(r)**bᵀ*p**。这是我们需要的所有数学知识,所以,让我们进入有趣的部分,应用程序,看看我们如何使用 Python 和 OpenAi Gym 实现它。*****

首先,让我们定义系统的线性化动态:

其次,让我们计算最佳控制器:

最后,让我们定义一个函数,我们可以调用它来实际计算运行时的输入力 F:

现在我们可以设置模拟了!

作为一个技术细节,在最初的推车杆中,力被固定为 10N,但是大小可以针对每个时间步长进行调整(见第 15 行),并且变量动作仅定义方向。**

结果

状态演化为 R =1, Q =5⋅eye(4).

如果我们现在运行模拟,我们可以在时间步长上绘制我们的状态。当达到 199 个时间步而没有摔倒时,就认为车杆任务解决了。然而,由于我们设计了控制器,并且不需要学习它,199 个时间步骤总是可以实现。所以让我们来看看前 400 个时间步骤!从图表中我们可以观察到的主要是两件事:**

  1. 我们的系统振荡。我们可以看看闭环系统的极点,看到我们有复杂的共轭极点。但是我不想在系统的分析中涉及太多的细节。事实上,我们甚至可以通过使用极点配置自行选择极点,以获得非振荡系统。但是,如果我们这样做,我们就不能保证最优地解决任务!**
  2. 所有状态收敛到 0。这就是我们希望通过控制器实现的目标。所有的状态收敛到零意味着,系统正朝着上平衡点收敛,在这个平衡点附近我们将其线性化。因此,状态反馈控制器稳定不稳定的上平衡点。—所以这很酷!****

我们还可以评估 R 的选择如何影响施加到系统上的力。我们的驱动变量(力 F )的用法是*对于小的重量矩阵 R ,因此 F 的大小增加。随着我们增加RF 的数量减少,因为我们增加了*“使用 F 的成本”*。这是意料之中的,因为 R 是为此目的而定义的,但它仍然很好,所以看,这背后的数学,实际上是可行的!***

讨论

我们已经解决了来自 OpenAI Gym 的 Cart-Pole 任务,它最初是使用最优控制来验证强化学习算法的。来自陈伟璇的帖子中的 Q-Learning 能够在 136 次迭代中解决这个任务。我们只需要一次迭代。事实上,我们需要零次迭代!假设我们的系统动力学模型是正确的,我们能够在数学上保证稳定性,从而保证解决任务,而不需要实际运行迭代。并且我们最优地控制系统,因为我们使用了 LQR,它最小化了上述的成本函数。那么如果我们需要零次迭代,并且保证最优地解决任务,为什么我们还需要强化学习呢?为什么我们不总是使用最优控制呢?**

使用控制理论符号的强化学习的抽象观点。r 对应于代理人收到的报酬。|(图片由作者提供)

  1. 有时候,我们不能!**对于控制方法,我们需要了解系统动态。有时,由于系统过于复杂,无法对其建模。那么,就不可能使用控制算法。对于强化学习,我们不需要任何关于我们系统的先验知识。强化学习算法可以学习动态模型(基于模型的强化学习)或者尝试在没有这种模型的情况下解决任务(无模型强化学习,例如 Q 学习)。
  2. 有时候,太贵了!**工程贵。那么,如果我们可以通过应用或创建算法来减少控制系统所需的工程,从而降低成本,又会怎么样呢?此外,在模拟中尝试(迭代)是非常便宜的,我们可以尝试很多次来收集数据并创建强大的代理。虽然我们可以尝试模拟,例如游戏,并创建基于知识的控制,这将是非常时间效率低下。然而,一旦我们转向物理系统,事情就大不相同了。快速运行车杆实验 1000 次将会花费很长时间,并且在某一点上物理系统将会失败。所以在那个时期,建立力平衡方程可能更容易。**
  3. ****有时候,我们不愿意!自主系统很迷人!看看皮尔科[1]在没有任何先验知识的情况下,仅用 7 个步道就学会了摆动和平衡一根杆子!如果这还不能让你兴奋,那就没什么能让你兴奋了!

好的,但是你什么时候应该使用什么?有很多问题,都得在这里回答。如果任务是某种模拟,例如赢得一场比赛,答案可能应该是强化学习(看看alpha go【3】或alpha fold【4】)。但是如果我们看看机器人这样的物理系统,就会出现更多的问题。关于所需的时间磨损的迭代*有多贵?模特有多贵?系统安全至关重要吗?我们需要数学保证吗?…所以归根结底就是这样。但是结合了控制理论和机器学习的强大组合也正在出现,并且更多正在到来!***

关键要点

这篇文章的第一个要点应该是认识到最优状态反馈控制和强化学习在设置方式上非常相似。在这两种情况下,我们测量或接收关于环境状态的信息。然后,我们使用这个关于状态的信息,通过动作与环境交互 (在我们的例子中,这个动作是施加力F)影响环境的行为(在我们的例子中,稳定不稳定的上平衡点)。这两种方法都试图使用某种优化措施来做到这一点。对 LQR 来说,它是最小化成本函数,对 Q-Learning 来说,它是最大化回报。这篇文章的第二个要点应该是,最优控制和强化学习之间的主要区别是我们对系统的先验知识——我们知道动力学还是不知道?**

无论是从控制的角度还是从强化学习的角度来看,这篇文章的某些部分都过于简单,但我试图描绘出“大画面”。如果您发现任何错误或有任何问题,请随时评论/提问!
感谢阅读!

参考

[1] U. Rosolia 和 f .博雷利,迭代任务的学习模型预测控制。一个数据驱动的控制框架 (2016),CoRR

[2] M. P. Deisenroth 和 C. E. Rasmussen, PILCO:基于模型和数据高效的政策搜索方法 (2011),第 28 届机器学习国际会议论文集

[3] D. Silver 等人,用深度神经网络和树搜索掌握围棋博弈 (2016),自然

[4] A. W. Senior 等人,利用深度学习的潜力改进蛋白质结构预测 (2020),《自然》

比较随机森林和梯度增强

原文:https://towardsdatascience.com/comparing-random-forest-and-gradient-boosting-d7236b429c15?source=collection_archive---------11-----------------------

数据科学基础

对它们的相似之处和不同之处的简短总结

玛丽塔·卡维拉什维利在 Unsplash 上拍摄的照片

随机森林和梯度推进机被认为是结构化数据的一些最强大的算法,特别是对于中小型表格数据。如果您正在学习或实践数据科学,很可能您已经听说过它们,甚至使用过它们。如果你想刷掉和/或加深你对这些算法的理解,这篇文章试图提供一个关于它们的相似性和差异性的简明摘要。

📍 1.类似

让我们先来总结一下关键的相似之处。

📗 1.1.模型类型

两种算法都是基于树的集成算法。让我们进一步分析一下:
◼️*‘基于树’:都使用决策树作为他们的构建模块
‘集合’:聚集多个*决策树来构建一个更健壮的模型

两者都可以像决策树一样用于分类和回归。

📗 1.2.特征尺度

这些基于树的算法通常不需要特征缩放。这是因为决策树对特征的尺度不敏感。出于同样的原因,离群值通常不是这些算法的问题。然而,离群值可能仍然需要一些关注,因为它们有时可能代表潜在的数据质量问题。

📗 1.3.多重共线性

当两个或多个要素高度相关时,会出现多重共线性。这个问题会导致线性模型的结果(如系数)不可靠,因为它们对数据做了某些假设。幸运的是,决策树不对数据做任何假设。这意味着基于树的算法对多重共线性是鲁棒的。但是,如果您的要素高度相关,您可能会受益于删除一些相关的要素,因为它们可能不会提供新的信息。

📍 2.差异

在我们深入总结主要差异之前,让我们快速回顾一下。根据我们如何训练和规范决策树,树的范围可以从浅简单欠拟合树(高偏差)深复杂过拟合树(高方差)。换句话说,预测误差主要是由于偏差还是方差,取决于树的复杂性。在接下来的章节中,记住这个概念将会很有帮助。

作者图片

对于第 2 节的剩余部分,我们将从三个不同的角度来看这两种算法的差异:
*A .数据:*将训练数据馈入集合中的树
*B .训练:*整个训练过程
*C .预测:*整个预测过程

先说随机森林。

📒2.1.A .随机森林数据

每棵树的训练数据由于以下原因而不同:
◼️️首先,随机记录(行)被采样*,替换每棵树。这种替换取样过程也称为自举*,抽取的样本称为自举样本。引导样本通常具有与原始训练数据相同的记录数,这意味着它可以多次包含相同的记录。有一个相关术语需要注意:开箱样品。它是指不包括在决策树的引导样本中的记录。这类似于验证或测试数据,因为这些记录不用于训练树。
◼️️其次,还有特征随机性(栏目)。不是使用所有可用的特征,而是在训练时在每个节点选择特征子集,或者在训练之前为每个训练数据选择特征子集。

由于这种随机性,决策树变得不那么相关,彼此更加独立。

📒2.1.B .随机森林培训

当涉及到训练模型时,森林中的决策树可以并行训练,因为树之间没有依赖关系。根据数据大小和计算能力等因素,这有时会导致更快的训练时间。

通常更深更复杂的树(高方差低偏差模型)被推荐用于随机森林。这是因为多个去相关的过度拟合的树作为一个整体会导致结果森林中的较低方差。这意味着你应该开始你的训练过程,让你的树长得又大又复杂,并尽量减少规则。如果你看到sklearn的文档(v0.24.2),你会看到最大深度默认设置为None

在随机森林中,拥有更多的树通常会给你更健壮的结果。然而,在某个时候添加越来越多的树的好处将不再超过它所需要的额外计算。

📒2.1.C .随机森林预测

随机森林聚集来自每棵树的预测,并使用典型预测作为最终预测。选择最常见的预测类别用于分类,而平均预测用于回归。每棵树对最终预测的贡献是相等的。

顺便说一下,bootstrapping**agg**regation统称为 bagging ,一种集合方法。

现在让我们继续梯度推进机。

📘2.2.A .梯度推进机器数据

一般来说,训练数据按原样使用而不需要为梯度增强机重新采样*。但是因变量对于每棵树都会改变 *

另一方面,在随机梯度推进机中,随机记录被采样而不替换每棵树。该取样过程允许保留出袋样品的剩余记录,该记录可用于培训期间的评估。随机梯度推进机还考虑了每个节点或每个训练数据的特征子集,以提高模型的性能。

📘2.2.B .梯度推进机器培训

梯度增强机器使用一种称为增强的集成方法。在 boosting 中,决策树被顺序训练,以便作为一个组逐渐提高预测能力。这里有一个训练流程的例子:
1。从一个模型开始(这可能是一个非常简单的单节点树)
2。使用第一个模型进行预测,看看当前误差有多差
3。以当前误差为因变量训练下一棵树(本次训练过程中之前的树保持不变)
4。使用到目前为止建立的所有树进行预测,看看新的当前误差有多差
5。对其余的树重复 3 & 4

从这个流程中,你可能注意到了两件事:
◼因变量因每棵树而异
◼后面的决策树依赖于前面的树。

这是考虑训练过程的另一种方式:当构建模型时,我们希望能够使用特征提供的信息来解释目标变量的方差。如果第一个模型解释了 60%的方差,那么还有 40%的方差需要解释。如果第二个模型解释了第一个模型遗漏的剩余 40%方差中的额外 5%,那么这两个模型合起来可以解释 65%的方差。它们各自扮演着不同的角色,相辅相成。随着构建更多的树,树的集体预测能力提高,并且树一起可以解释目标的更多变化。

这种顺序训练过程有时会导致训练时间变慢,但它还取决于其他因素,如数据大小和计算能力。

与随机森林不同,增加树的数量太多会导致梯度增强机器中的过度拟合问题,因为新的树可能会试图预测训练数据中的复杂模式。如果你发现你的梯度推进机器安装过多,一个可能的解决办法是减少树木的数量。

梯度助推器有一个重要术语:学习率。这也被称为α,收缩步长*。学习率范围在 0 到 1 之间。如果学习率越接近 0,你的训练过程就越小心越慢。然而,较小的学习率有助于建立一个更通用的模型。与使用较高的学习率相比,当用较小的学习率生长许多树时,该模型也不容易过度拟合。*

最后,boosting 方法旨在组合简单模型(高偏差)。所以保持你的树简单是有好处的。

📘2.2.B .梯度推进机器-预测

梯度推进机器将来自所有树的所有预测相加,以获得回归和分类的最终预测。

最后,需要强调的是,这篇文章中总结的内容是通用的。当在实践中使用这些算法时,最好理解这些通用概念对于您正在使用的算法的实现意味着什么。以随机森林的sklearn实现为例,有一个参数叫bootstrap。默认情况下,它被设置为True,以便引导样本用于决策树。但是,如果您将此超参数更改为False,那么您将不再使用引导样本。

照片由 J-Photos 在 Unsplash 上拍摄

您想要访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。

感谢您阅读我的文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️️ 决策树是如何构建的?
◼️️ 管道、ColumnTransformer 和 FeatureUnion 说明
◼️️ FeatureUnion、ColumnTransformer &管道用于预处理文本数据

再见🏃 💨

📁参考

◼trever hastie◼bootstrap 聚合 bagging by uda cityt14】◼梯度推进:Terence Parr 和 Jeremy Howard 常见问题解答

使用 SAM 调配基础架构

原文:https://towardsdatascience.com/comparing-sam-to-cloudformation-e5f48b271625?source=collection_archive---------25-----------------------

更轻松地将 AWS 无服务器基础设施定义为代码

将基础设施写成代码,有大量的工具可供我们使用,以快速的周转时间提升服务。在亚马逊网络服务(AWS) 的情况下,我们有AWS cloud formation——最初的 AWS 产品,于 2011 年 2 月推出——最近由 AWS 无服务器应用模型 (SAM)补充,这是五年后在 2016 年 11 月宣布的。

我们可能会问,SAM 如何补充云形成?不管有没有 SAM,我们都可以提供无服务器基础设施作为 AWS 的代码,那么 SAM 提供了什么价值使它成为对工程师有吸引力的框架呢?

无服务器应用程序的构建块。来源:弗兰克·麦肯纳转自 Unsplash

SAM 如何补充 CloudFormation?

虽然 CloudFormation 支持绝大多数服务,但 SAM 特定于无服务器领域,为资源提供更高级别的构造,如 AWS Lambda 函数、 Amazon DynamoDB NoSQL 表和 AWS 步骤函数状态机。专注于 Lambda 函数,CloudFormation 支持一个 AWSLambdaFunction 构造,SAM 使用自己的AWSserver lessFunction产品构建该构造。

深入这些构造的细节,我们观察到它们之间支持的属性的差异。后者提供了额外的字段,如AutoPublishAliasDeploymentPreferenceEventInvokeConfig。无服务器构造的 SAM 文档还在其每个属性下引用了AWS cloud formation compatibility,在适用的情况下将这些内容映射到 Lambda 对应内容。

除了 Lambda 函数,SAM 的无服务器函数还可以创建 IAM 策略文档、 Lambda 别名和 AWS CodeDeploy 部署组。使用普通的 CloudFormation,将需要更多的构造来提供这些资源,这就给我们留下了实现相同结果的额外工作。

让我们通过例子来展示这一点,首先从 SAM 开始,然后我们可以用 vanilla CloudFormation 复制它。我们将该函数集成到一个Amazon API GatewayGET/hello端点中,并授予该函数轮询一个 AWS 简单队列服务(SQS) 队列的权限。

作者图片

使用 SAM 进行资源调配

安装 SAM CLI ,我们可以为无服务器功能导入 Hello world 模板。这包括打包到目录hello_world中的代码,运行 Python 3.9 ,以及在Events属性中隐式定义的 API 网关资源。这个网关包括一个 GET /hello端点。

为了全面比较 SAM 和 CloudFormation,让我们在Events属性后添加额外的配置。具体来说,

  • 一个 IAM 角色策略文档供亚马逊 EC2 或 Lambda 承担,
  • 自动生成的称为live的λ别名,
  • 金丝雀部署先部署 10%,五分钟后部署 90%,
  • 授予 SQS 队列轮询权限的 IAM 策略,
  • 提供 10 次执行的并发性,以及
  • 正在部署的 Lambda 版本的描述。

有很多东西需要思考——充分利用 SAM 的产品进行公平的比较。注意,我们还将创建该函数被授予轮询权限的 SQS 队列,但是我们不会在这里显式地集成这两个队列。让我们假设这种情况发生在 Lambda 的 Python 代码中,我们不会把它作为比较的一部分。

在撰写本文时,SAM CLI 愉快地部署了这个模板。在 CloudFormation 控制台上查看调配的hello-world堆栈,创建了 12 个资源——从无服务器功能本身,到 IAM 角色,到 REST API 资源——所有这些都源自这个简短的代码片段。

作者图片

云形成的供应

转到香草云形成,我们不再有萨姆的复杂构造的奢侈品。现在,我们必须自己定义所有 12 种资源。

从哪里开始?让我们首先为 Lambda 函数创建 IAM 角色:除了策略文档允许 EC2 和 Lambda 承担角色之外,还授予轮询队列MyQueue的权限——与 SAM 提供的现成内容SQSPollerPolicy完全匹配。查看 SAM 之前授予的 IAM 权限,我们可以看到下面的详细信息,我们希望使用 CloudFormation 复制这些信息。

作者图片

我们需要显式定义一个 AWSIAMRole 资源来复制它。AssumeRolePolicyDocument与我们用 SAM 定义的完全相似——因为 SAM 代表我们直接映射这个属性——而附加的策略被证明更麻烦。从上面我们看到的,我们有两个要配置:除了匹配SQSPollerPolicy的定制策略文档之外,还有用于标准 Lambda 权限的 AWS 托管策略AWSLambdaBasicExecutionRole

我们已经写了 29 行代码,只差 SAM 模型对我们的要求。到目前为止,我们只有权限!让我们继续创建堆栈之王 Lambda 函数本身。看起来与 SAM 的功能大致相似,我们可以定义后者提供给我们的功能的子集,包括代码源(在Code而不是CodeUri)、Python 3.9 运行时和 x86 架构。我们还可以显式引用创建的 IAM 角色。

使用 SAM,我们能够在 Lambda 函数上配置版本控制,并将别名live应用到最近部署的迭代中。使用 plain CloudFormation,我们必须自己定义一些资源来实现这一点:特别是 AWSLambdaVersion 和 AWSLambdaAlias 。我们将匹配我们之前对该版本的描述,同时在我们的别名上设置相同的配置并发性。

为了对每个版本执行分阶段部署,我们需要建立一个 CodeDeploy 部署组,这需要一个 CodeDeploy 应用程序和一个 IAM 角色,该角色授予与 Lambda 交互的足够权限。与默认配置的 SAM 设置完全一样,该组将协调蓝绿色部署。

最后,但同样重要的是,我们希望用 endpoint GET /hello复制 REST API。虽然有多种方法可以实现这一点,让我们假设我们有开放的 API 规范spec.yml,让我们也指定我们想要的艺名Prod,复制山姆之前为我们创建的东西。

SQS 的队列看起来和以前一模一样——因为 SAM 在这一部分没有发挥任何作用——让我们的 Lambda 替代方案结束了。不包括队列,这总共需要 85 行不带空格的代码。与使用 SAM 的 34 行代码相比,vanilla CloudFormation 需要更多的 YAML 代码来理解和维护。

值得收养山姆吗?

从表面上看,阅读这一判决,我们很容易为“是”而欢呼。为什么不呢?这是一个很好的框架。除了简化 JSON 或 YAML 模板, SAM 是一个开源项目,而 CloudFormation 只公开分享其覆盖路线图。如果 SAM 有任何功能或缺陷,为什么不创建一个问题并为项目做出贡献呢?

请记住,SAM 是专为无服务器设计的。它只支持配置的子集,比如单属性主键 DynamoDB 表。对于特定的需求,它是一个很好的包装器,但是对于任何更复杂的东西,CloudFormation 都是你的朋友。

为了简化开发过程,SAM 还在其更高层次的构造中隐藏了一些 CloudFormation 模板逻辑。如果 SAM 转换出现任何问题,这可能会被证明是有问题的。在这种情况下,我们可以通过 CloudFormation 控制台调试转换后的模板:按名称搜索堆栈,转到“模板”,然后启用“查看已处理的模板”。禁用此选项将显示用于比较的源 SAM 模板。

作者图片

虽然 SAM 可以满足您对无服务器的需求,但还有其他更高级别的框架以代码形式提供基础架构,支持更广泛的 AWS 服务,具有不同程度的功能覆盖范围:仅举几个例子来说, AWS 云开发工具包(CDK) 和 Terraform 。如果您对本文中提到的任何框架有经验——不管是积极的还是消极的——欢迎您的来信。

比较上海、巴什、KSH 和 ZSH 的速度

原文:https://towardsdatascience.com/comparing-sh-bash-ksh-and-zsh-speed-82a72bbc20ed?source=collection_archive---------17-----------------------

获胜者去…击鼓…

保罗·坎德罗在 Unsplash 拍摄的照片

介绍

我经常听说 Bash 很慢。所以我花了一个周末来检查它有多慢。我用了两种方法。第一个是 ShellBench 。ShellSpec 为 POSIX shell 比较创建了一个基准实用程序。第二个是由@satoh_fumiyasu 创作的 sh-benchmark 脚本。

继续读下去,看看我发现了什么。

我的环境

我用的是 MacBook Pro。

我的 MacBook Pro 规格。图片作者。

这些是我的shbashkshzsh版本:

❯ sh --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin20)
Copyright (C) 2007 Free Software Foundation, Inc.❯ bash --version
GNU bash, version 5.1.4(1)-release (x86_64-apple-darwin20.2.0)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <[http://gnu.org/licenses/gpl.html](http://gnu.org/licenses/gpl.html)>This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.❯ ksh --version
  version         sh (AT&T Research) 93u+ 2012-08-01❯ zsh --version
zsh 5.8 (x86_64-apple-darwin20.0)

脱壳工作台

您可以使用 ShellBench 对任何 shells、shbashkshmkshposhzsh等进行测试。它返回每秒执行的次数。它提供了八个样本基准测试。

ShellBench 统计样本代码执行的次数。“分配样本测试”测试以不同的方式分配变量,“计数样本测试”测试不同的计数方式,等等。

ShellBench 样本测试详细信息

我使用了shbashkshzsh的所有样本测试。

Shellbench 的测试示例。图片作者。

这是我的一个结果的表格。

结果

测试返回每秒执行的次数,这意味着下图中的图形越高,结果越好。

分配和 cmp

sh:蓝色、bash:黄色、ksh:绿色、zsh:红色。

“分配和 cmp”测试结果之一。图片由 Authro 提供。

计数和评估

“计数和评估”测试结果之一。图片作者。

func 和 null

“功能和无效”测试结果之一。图片作者。

输出和子外壳

“输出和子外壳”测试结果之一。图片作者。

kshzsh似乎比bash快七倍。ksh在 17 项测试中表现优异,zsh在 6 项测试中表现优异。

sh 基准

sh-benchmark 测试参数扩展、数组参数扩展、算术求值、测试和迭代参数。

sh 基准测试的详细信息。图片作者。

我的一个成果。图片作者。

该脚本返回与 bash 结果相关的结果。所有数字都是百分比。所以数字越小意味着越快。

bash:蓝色、ksh:黄色、zsh:绿色

a-G 测试结果。

氢-氮试验结果。

zsh是六次测试中最快的,ksh是七次测试中最快的。

有趣的是zsh对于 Fork 测试来说非常慢。

我是如何测试的(如果你感兴趣的话)

如果你想自己测试,你可以按照这个。

脱壳工作台

您可以克隆 Shellbench ,使shellbench文件可执行,并运行脚本:

$ ./shellbench -s sh,bash,ksh,zsh sample/count.sh sample/output.sh

sh-基准

将 sh-benchmark.zsh 和 sh-benchmark-scripts 复制到同一个目录下。使 sh-benchmark.zsh 成为可执行文件,并在您的终端上运行它:

$ sh-benchmark.zsh

结论

根据我的测试,ksh是冠军,zsh是亚军。根据测试结果,两种外壳都比bash快 2-30 倍。

如果你像 Google Shell 风格指南建议的那样使用bash少于 100 行,那么我认为你不会注意到其中的区别。虽然这当然取决于任务。

通过 成为 会员,可以完全访问媒体上的每一个故事。

https://blog.codewithshin.com/subscribe

参考

  • https://fumiyas . github . io/2013/12/01/benchmark . sh-advent-calendar . html
  • https://github.com/shellspec/shellbench

https://medium.com/better-programming/the-ultimate-programmers-guide-to-bash-scripting-2d11d4e6e978 https://medium.com/better-programming/27-simple-bash-scripting-tips-for-beginners-d6764c977546 https://medium.com/better-programming/13-fantastic-learning-tools-and-resources-for-bash-scripting-51a6de98015c

比较 to_csv()、np.save()、to_hdf()和 to_pickle()函数的速度和文件大小

原文:https://towardsdatascience.com/comparing-the-speed-and-filesize-of-to-csv-np-save-to-hdf-to-pickle-functions-6c53a6a3fc82?source=collection_archive---------15-----------------------

在日常 I/O 操作中,读取时间加速 66 倍,写入时间加速 25 倍,文件大小加速 0.39 倍。

由红色齐柏林飞艇在 Unsplash 拍摄的照片

使用 Pandas 和 NumPy 读写文件是数据科学家和工程师的日常任务。

让我们比较一下这些库提供的最常见的写/读表格数据的函数。

在这些 I/O 操作中,我们可以让我们的代码快得多节省时间,让我们的老板和我们自己都高兴。

我们还可以通过选择适当的保存功能来节省大量的磁盘空间。

首先,让我们创建一个 10,000,000 行 2 列的数据框架。

to_csv() / pd.read_csv()

保存熊猫数据帧最常见的方法。

np.save() / np.load()到。神经肽 y

我们可以将 DataFrame 转换为 NumPy 数组,然后使用 np.save()将其保存为. npy 文件。

np.save()比 to_csv()
快× 2.43 倍,np.load()比 pd.read_csv()
慢× 3.47 倍。npy 文件的大小为× 0.86。csv 文件

当我们读取它时,它将是一个 NumPy 数组,如果我们想把它用作熊猫数据帧,我们需要转换它。

从 np.load()到 DataFrame 的转换需要+2.06 秒

np.savez_compressed() / np.load()到。npz

np.save()的压缩版本。

阅读时。npz 文件需要 195 μs,但是为了访问其中的 NumPy 数组,我们必须使用a['data'],这需要 32.8 s。

np.savez_compressed()比 to_csv()
快× 1.1 倍,np.load()比 pd.read_csv()
快× 1.37 倍。npy 文件的大小为× 0.44。csv 文件

当我们读取它时,它将是一个 NumPy 数组,如果我们想把它用作熊猫数据帧,我们需要转换它。正如我们之前看到的,这又需要 2.06 秒。

to_hdf() / pd.read_hdf()

使用 HDFStore 将包含的数据写入 HDF5 文件。

to_hdf()比 to_csv()
快× 19.4 倍 pd.read_hdf()比 pd.read_csv()
快× 15 倍. h5 文件是× 0.59 的大小。csv 文件

to_pickle() / pd.read_pickle()

将对象序列化到文件

to_pickle()比 to_csv()
快× 25.8 倍,pd.read_pickle()比 pd.read_csv()
快× 66 倍。pkl 文件的大小为× 0.39。csv 文件

摘要

当我们只对在 Python 程序中使用文件感兴趣时,我们可以有效地使用 pickles,因为它们在读写操作和磁盘空间方面都要快得多。

不确定接下来要读什么?这里有两个选择:

https://medium.com/analytics-vidhya/topic-modeling-on-my-watched-movies-1d17491803b4

保持联络

关注我的 Medium 了解更多类似内容。
让我们在 LinkedIn 上连线。
检查我的 GitHub 。

Spark 和 Scala 中 collect_list()和 collect_set()函数的比较

原文:https://towardsdatascience.com/comparison-of-the-collect-list-and-collect-set-functions-in-spark-with-scala-10b3ba1b74b6?source=collection_archive---------4-----------------------

利用 Scala 实现大数据

Scala 编程中 collect_list()和 collect_set()的区别

信号源

可以在不同的编程语言上用不同的版本创建数组格式的变量。Spark 上的 Scala 语言有两个不同的数组创建函数。这些被称为collect_list()collect_set()函数,主要应用于生成的数据帧上的数组类型的列,通常在窗口操作之后。

在本文中,这两个函数之间的差异将通过相应的实例来解释。主要目的是比较和强调以下两个函数之间的差异,因为它们可能会在误导的情况下使用。

作为编程语言,Scala 被选择用于 Spark 3.1.1。您可以通过使用 PySpark 语言来实践类似的方法。

出于测试目的,可以生成如下示例结构类型化数据帧。在代码片段中,通过添加相应的内容来创建表的行。在创建行之后,我们可以将这些列添加到我们的数据模式中,方法是使用匹配的数据类型对它们进行格式化,比如对列使用 IntegerType ,对列使用 StringType

import org.apache.spark.sql._
import org.apache.spark.sql.types._val dataFrame = Seq(
    Row(1,"Employee_1", "Kafka"), 
    Row(2,"Employee_1", "Kibana"), 
    Row(3,"Employee_1", "Hadoop"), 
    Row(4,"Employee_1", "Hadoop"),  
    Row(4,"Employee_1", "Hadoop"),
    Row(5,"Employee_2", "Spark"), 
    Row(6,"Employee_2", "Scala"),  
    Row(7,"Employee_2", "SageMaker"), 
    Row(7,"Employee_2", "SageMaker"),
    Row(8,"Employee_3", "GCP"), 
    Row(9,"Employee_3", "AWS"),
    Row(10,"Employee_3", "Azure"),
    Row(11,"Employee_4", null)
  )
val dataFrameSchema = new StructType().add("day", IntegerType).add("name", StringType).add("toolSet", StringType)val array_dataframe = spark.createDataFrame(spark.sparkContext.parallelize(dataFrame),dataFrameSchema)

产出 1,归作者所有

在 dataframe 创建阶段之后,我们可以打印数据及其内容的模式。

array_dataframe.printSchema()
array_dataframe.show(false)

产出 2,归作者所有

我们创建了包含三列的数据框架,分别是,员工的,以及他们的工具集

我们的下一步将通过使用collect_list()collect_set()函数为这些员工的相应工具集创建数组。

collect_list()

第一个数组创建函数叫做collect_list()。它既可以用来对值进行分组,也可以借助窗口操作对它们进行聚合。

在下面的脚本中,有一个名为名称工具集的列。当深入观察时,员工 1 有三个工具,有两个副本,员工 2 有三个工具,有一个副本。对于这个具体的例子,我们可以按雇员分组,并将所有的工具集收集到一个数组中。可以通过首先对员工进行分组并在工具集上进行聚合来实现。

collect list 的关键亮点是函数通过保持项目的顺序将所有重复的值保存在数组中。

val collect_list_df = array_dataframe.groupBy("name").agg(**collect_list**("toolSet").as("toolSet"))collect_list_df.printSchema()
collect_list_df.show(false)

产出 3,归作者所有

当我们希望通过保持项目*(日期、时间戳、id 等)的顺序来消除不同的值时。)*,在应用 collect_list 函数之前,我们可以先使用 array_distinct() 函数。在下面的例子中,我们可以清楚地看到元素的初始顺序被保留了。例如,Employee_1,我们看到 Kafka、Kibana、Hadoop 项目的初始顺序在应用了collect_list()操作后保持为 Kafka、Kibana、Hadoop,没有丢失序列。

val collect_list_df = array_dataframe.groupBy("name").agg(**array_distinct**(**collect_list**("toolSet")).as("toolSet"))collect_list_df.printSchema()
collect_list_df.show(false)

产出 4,归作者所有

collect_set()

第二个数组创建函数叫做collect_set()。它既可以用来对值进行分组,也可以借助窗口操作对它们进行聚合。

在下面的脚本中,有一个名为 nametoolSet 的列。当深入观察时,员工 1 有三个工具,有两个副本,员工 2 有三个工具,有一个副本。对于这个特定的例子,我们可以按雇员分组,并将所有的工具集收集到一个数组中。可以通过首先对员工进行分组并在工具集上进行聚合来实现。

收集列表的关键亮点是函数消除了数组中的重复值。然而,它并不能保证数组中项目的顺序。通过查看 Employee_1,我们看到在应用了collect_set()操作之后,Kafka、Kibana、Hadoop 的项目的初始顺序被更改为 Kibana、Kafka、Hadoop。

val collect_set_df = array_dataframe.groupBy("name").agg(**collect_set**("toolSet").as("toolSet"))collect_set_df.show(false)

产出 5,归作者所有

结论

在 Spark 中,我们可以使用collect_list()collect_set()函数来生成具有不同视角的数组。

collect_list()操作不负责统一数组列表。它按照元素的现有顺序填充所有元素,并且不删除任何重复的元素。

另一方面,collect_set()操作确实消除了重复;但是,它不能保存数组中项目的现有顺序。

为了统一数组中的元素,我们可以在 collect_list() 函数之前轻松使用 array_distinct() 内置函数来消除重复值,而不会丢失数组中元素的顺序。

非常感谢您的提问和评论!

参考

  1. Spark 3 中 ScalaDoc 的收集集合和收集列表操作
  2. Spark 内置功能
  3. 来自 Collect_List 的数据块示例

用图像处理补充机器学习算法

原文:https://towardsdatascience.com/complementing-machine-learning-algorithms-with-image-processing-938b1b926014?source=collection_archive---------38-----------------------

Python 中常用图像处理算法的简短介绍

锡德·维尔马在 Unsplash 上拍摄的照片

P ics,或者它没有发生。拍摄日常瞬间已经成为今天的默认。去年, Keypoint Intelligence 预测人类将生成 14.363 亿张图片。图像组织解决方案提供商 Mylio 甚至预测这一数字将在 2022 年达到 1.6 万亿。哇哦。照片真多啊!

作为一名数据科学家,学习处理和提取这些图像中的信息至关重要,特别是在对象检测、图像分割和自动驾驶汽车等计算机视觉任务中。Python 中的几个图像处理库,如 scikit-image 、 OpenCV 和 Pillow/ PIL 让我们可以准确地做到这一点。

图像处理如何融入整个机器学习管道?

带有图像处理的示例机器学习工作流(仅用于说明目的)。作者照片

我们通常使用我们首选的图像处理库来读取和清理数字图像,并提取机器学习算法可以使用的有用特征。

在上面的示例管道中,我们从源图像中切割出每一片叶子。我们应用了图像增强(即白平衡、阈值/形态学和直方图均衡化)。之后,我们还测量了每片叶子的几何特征,如凸面积、周长、长轴和短轴长度以及偏心率,这形成了我们的特征表。最后,我们使用这些特征作为分类算法的输入,并产生可接受的 F-1 分数。我们可以将最后两步镜像到流行的虹膜数据集,但是这次我们自己生成了测量值。这不是很好吗?

Python 中的数字图像 NumPy 数组

我们可以将数字图像表示为三维函数 F(x,y,z ),其中 x,y 和 z 表示空间坐标。相比之下,F 指的是图像在该特定点的强度(通常从 0 到 255)。在 Python(以及线性代数)中,我们可以将这个函数表示为一个三维的 NumPy 数组(一个张量)。z 轴可以被解释为图像通道(例如,RGB 用于红色、绿色和蓝色)。

有几种颜色模型可用于图像;Mathworks 在这里很好地讨论了不同的色彩空间。我们的图像处理库允许我们用一行代码从一个颜色空间转换到另一个颜色空间。

from skimage.color import rgb2hsv, rgb2gray
from skimage.data import coffeeim = coffee()      # shape : (400, 600, 3); range from 0 to 255
hsv = rgb2hsv(im)  # shape : (400, 600, 3); range from 0 to 255
gry = rgb2gray(im) # shape : (400, 600, 1); range from 0 to 255
bin = gry > 0.5    # shape : (400, 600, 1); composed of 0 AND 1 only

在单独的颜色通道中渲染的咖啡。第一行显示 RGB 原始图像及其灰度和二值化副本。第二行和第三行分别显示了在 RGB 和 HSV 空间中渲染的图像。图片来自 scikit-图片由作者处理。

常见的图像处理算法

  • **图像增强。**在神经网络应用中,我们对图像进行翻转、旋转、上采样、下采样和剪切,以扩充现有数据集。有时,我们希望校正图像的对比度和白平衡,以突出所需的对象或区域。在下面的例子中,我们使用一个线性函数来增强暗图像,让我们看到在原始图像中看不到的东西。
def apply_histogram_correction(im, target_dist,             
                               target_bins=range(256):
    """Apply a histogram correction to an image `im` using a target distribution `target_dist`. The correction is applied at every pixel intensity bin `target_bins`.""" freq, bins = cumulative_distribution(im)
    corrected = np.interp(freq, target_dist, target_bins)

    return img_as_ubyte(corrected[im].astype(int))

使用线性分布的直方图均衡化。在作者生成的每个颜色通道中执行直方图均衡化。

  • 形态滤波。在形态滤波中,我们使用一个结构化元素或内核来抑制或增强像素邻域中的感兴趣区域。一些常见的形态学操作包括腐蚀、膨胀、打开、闭合、骨架化和移除小孔。
from skimage.morphology import (erosion, dilation, opening, closing, 
                                skeletonize, remove_small_holes)
from skimage.morphology import disk
from skimage.date import shepp_logan_phanto
from skimage.util import img_as_ubyteim = img_as_ubyte(shepp_logan_phantom())    # Original Image
im_open = im.copy()
im_open[10:30, 200:210] = 0selem = disk(6)                             # Structuring element# Morphological Transformations
eroded = erosion(im, selem)
dilated = dilation(im, selem)
opened = opening(im, selem)
closed = closing(im_open, selem)
skeleton = skeletonize(im==0)
no_holes = remove_small_holes(im, area_threshold=64)

scikit-image 中提供了不同的形态学操作。骨架化和移除小孔不需要结构元素,但是它们需要阈值规范。

  • https://en.wikipedia.org/wiki/Blob_detection****斑点检测。在图像处理中,斑点被定义为图像中的亮暗暗亮区域。检测到的斑点通常发信号通知图像中的对象或对象的部分,这有助于对象识别和/或对象跟踪。三种最常见的斑点检测算法是高斯拉普拉斯算法、高斯差分算法和 Hessian 行列式算法。所有这些都是基于函数对位置的导数。
from skimage.data import hubble_deep_field
from skimage.feature import blob_dog, blob_log, blob_doh
from skimage.color import rgb2gray
import mathim = hubble_deep_field()[:500, :500]
im_gry = rgb2gray(im)# Laplacian of Gaussian
blobs_log = blob_log(im_gry, max_sigma=30, num_sigma=10, threshold=.1)
blob_log[:, 2] = blobs_log[:, 2] * math.sqrt(2)# Difference of Gaussian
blobs_dog = blob_dog(im_gry, max_sigma=30, num_sigma=10, threshold=.1)
blob_dog[:, 2] = blobs_dog[:, 2] * math.sqrt(2)# Determinant of Hessian
blobs_doh = blob_doh(im_gry, max_sigma=30, threshold=0.01)

scikit-image 中可用的不同斑点检测算法的结果。摘自 scikit-image 文档示例。

  • ****特征提取。特征提取利用了图像中的连通分量。在上面的叶子分类例子中,我们分离了每片叶子。我们计算了每片叶子的面积、周长和偏心率等。我们使用这些测量值作为我们机器学习算法的输入。使用 scikit-image 中的“regionprops”模块可以快速提取特征。
from skimage.measure import label, regionprops
from skimage.color import rgba2gray
from skimage.io import imreadim = rgba2gray('candies.png')   
im_bw = im < 0.5
im_clean = morphological_ops(im_bw)
im_label = label(im_clean)props = regionprops(im_label)
props[0].area ### Output: 4453     Refers to the Area of the image with label==0

特征提取的图像标记过程:转换为灰度>二值化>标记图像。每一个斑点都是由作者生成的图像阵列中的一组相连的像素或元素。

  • ****图像分割。在图像分割中,我们希望通过几个阈值操作隔离一些图像。例如,使用>或<操作符对灰度图像进行二值化,以生成布尔掩模。在某些情况下,我们可以使用 HSV 或 RGB 等其他颜色空间来生成阈值,以隔离感兴趣的对象。在下面的例子中,我们生成了一个遮罩来隔离水果篮中的所有葡萄。
from scipy.ndimage import median_filter
from skimage.color import rgb2hsv
from skimage.io import imreadfruits = imread('fruits.jpg)
fruits_hsv = rgb2hsv(fruits)hmask = fruits_hsv[:, :, 0] > 0.7   # Hue Filter
hmask1 = fruits_hsv[:, :, 0] < 0.9  # Hue Filter
smask = fruits_hsv[:, :, 2] > 0.3   # Saturation Filter
mask = median_filter(smask*hmask*hmask1, size=25)

图像分割。使用 HSV 颜色空间中的阈值来隔离所有的葡萄。由作者生成的图像。

包装完毕

本文讨论了我们如何将图像处理纳入机器学习管道,并展示了该领域常用的不同图像处理算法。在下一组文章中,我们将更深入地研究我在这里分享的每一种常见算法,并讨论它们背后的概念。

正规化完全初学者指南

原文:https://towardsdatascience.com/complete-beginners-guide-to-regularization-fcd5f6530a8e?source=collection_archive---------46-----------------------

如何构建泛化能力强的神经网络

照片由格温·威斯丁克在 Unsplash 上拍摄

无论我们是建立分类模型还是预测模型,我们的目标都是让模型在我们以前没有见过的数据上表现良好。这是我们从模型中产生价值的地方。在已经被标注或者之前已经被看到的数据上做得好,在驱动价值上并不是很重要。

当我们训练神经网络时,我们的目标是让模型在它学习参数的训练数据之外表现良好。在这种情况下,该模型被认为是通用的。

本文将作为正则化的介绍,正则化是在实践中用来构建高性能模型的技术。我们将研究为什么正规化是重要的,以及当前文献中的最佳实践。虽然这只是一个介绍,但我们将链接到相关的论文和文章,以进一步探索这些主题。

为什么正规化很重要

正如引言中所提到的,机器学习管道的一个主要目标是确保模型在它尚未看到的数据上概括得很好或表现得很好。张等人在《论文》中探讨了分类问题中的泛化问题。他们发现了神经网络的一个主要问题。

“深度神经网络很容易适应随机标签”

他们进行了一项实验,根据随机标记的数据训练了一个模型,发现该网络能够实现零训练错误。这意味着神经网络能够完美地学习随机标记的数据。这显然是危险的,因为它表明神经网络能够完美地学习训练数据,而不用实际学习每个类的东西。尽管训练误差表明该模型是完美的,但是当分类新的、看不见的(并且被正确标记的)数据时,该模型的性能会非常差。

本文认为隐式和显式正则化都有助于改善泛化误差。隐式正则化是某些网络决策的结果,例如使用随机梯度下降 (SGD),它收敛到一个小的范数,但不明确尝试正则化。虽然隐式正则化绝对值得一提,但它很少被探讨,所以在本文中我们将重点关注显式正则化技术,如权重衰减、丢弃和数据扩充。

规则化的另一个好处是它在防御敌对攻击方面的有效性。这些是人们试图欺骗一个模型,让它相信某样东西属于不同的类别,同时尽可能少地改变特征。

由诺亚·布舍尔在 Unsplash 上拍摄

在这篇文章中,我们看到一个模型被欺骗,通过轻微改变图像中的像素,以 99.3%的置信度相信一幅熊猫图像是一只长臂猿。另一个更严重的恶意攻击的例子包括欺骗垃圾邮件检测网络,使其相信垃圾邮件不是垃圾邮件。

如果一个模型不能很好地概括,它将更容易受到这些攻击,也更容易找到攻击的方法。通常,这些攻击是通过创建一个与生产中使用的网络相似的网络来完成的,然后对数据的变化使用损失函数,同时最大化模型预测错误类别的机会。我们将在下面讨论的正则化技术有助于使这个过程变得更加困难。

正规化最佳实践

在本节中,我们将介绍三种用于训练神经网络以提高模型泛化能力的正则化技术。

重量衰减

权重衰减,通常也称为 L2 正则化或岭正则化,是一种为模型权重向交叉熵损失函数添加二次项的技术。

权重较大的模型能够更有效地拟合训练数据。通过将模型中的权重项添加到损失函数中,训练过程现在由于具有较大的权重而受到惩罚。这迫使模型最小化分类误差和权重的大小。这导致较差的训练精度,但通常较好的验证和测试精度(或改进的泛化误差)。

拒绝传统社会的人

另一种常见且有效的正则化技术被称为丢失。顾名思义,Dropout 在训练过程中随机“丢弃”或删除某些节点及其对应的连接。

这篇论文展示了 50%缺失层在泛化和消除“特征检测的协同适应”方面的有效性当神经元被随机丢弃时,其他每个神经元被迫学习权重,以有效地对数据进行分类。这种方法极大地提高了性能。

如果输入和正确输出之间的关系很复杂,并且网络具有足够的隐藏单元来对其进行精确建模,则通常会有许多不同的权重设置可以对训练集进行近乎完美的建模,尤其是在只有有限数量的标记训练数据的情况下。这些权重向量中的每一个都将对保留的测试数据做出不同的预测,并且几乎所有的权重向量在测试数据上的表现都比在训练数据上的表现差,因为特征检测器已经被调整为在训练数据上很好地协同工作,但是在测试数据上却不是这样。”—辛顿等人。

数据扩充

在分类中,给定类中的许多对象都具有非常相似的特征,只是对底层数据做了一些小的修改。例如,在图像分类中,如果图像右上方的狗在屏幕左下方,旋转 180 度,或者在不同的光照下,它就是同一只狗。

由克里斯·劳顿在 Unsplash 上拍摄

数据扩充是一种用于从现有数据中生成新训练样本的技术。当使用 PyTorch 创建模型时,这里有许多不同的转换可用,它们都旨在将这些小的调整样本添加到训练数据中。

通过这些稍微调整的图像,模型能够学习关于每个类别的有用特征,并更好地准备对它尚未看到的图像进行分类。越多的训练数据几乎总是越好。这种技术通过利用现有数据生成更多数据,而不需要收集和标记数据的成本(通常是一个昂贵的过程)。

结论

我们已经研究了为什么正则化是重要的,以及当前文献中的一些最佳技术。正则化有助于神经网络在它尚未看到的数据上表现得更好,也提高了模型抵御敌对攻击的机会。

虽然权重衰减、丢弃和数据增加不是仅有的三种可用的正则化技术,但是它们实现起来非常简单,并且非常有效。如果您有兴趣更深入地探索这个主题,其他技术,如提前停止、批量调整和隐式正则化技术是继续阅读的好主题。

感谢您阅读本文!

使用 Flask 和 Heroku 部署模型的完整指南

原文:https://towardsdatascience.com/complete-guide-on-model-deployment-with-flask-and-heroku-98c87554a6b9?source=collection_archive---------11-----------------------

一个完整的一步一步的方法来建立一个机器学习模型,并使它对网络上的其他人可用。

照片由来自佩克斯的伊萨克·佩雷拉拍摄

当我部署我的第一个机器学习模型时,我感到喜悦的泪水顺着脸颊流下,当我望向窗外时,我看到了远处的彩虹。我认为这是我将在这个世界上做大事的标志。

至少我是这么想象的。实际上,我花了两天时间处理 Heroku 可能抛给我的各种错误。当我最终部署好我的模型后,我立刻关上电脑,喝下我的预健身饮料,然后去了健身房。

本文旨在向您展示在使用模型部署时如何正确操作,同时向您展示在此过程中需要注意的事项。最终产品可以在这里看到,而同一型号的更高级部署可以在这里看到(你可能需要一些耐心来访问 web 应用程序,因为 Heroku 会在一段时间不活动后让应用程序“休眠”——应用程序会在几秒钟的延迟响应后“醒来”)。

文章分为三个部分:

  1. 构建机器学习模型
  2. 设置 Flask web 应用程序
  3. 在 Heroku 的部署

构建机器学习模型

我们旅程的第一步是训练一个机器学习(ML)模型,但是鉴于我的主要重点是部署,我不会在文章的这一部分投入太多精力。

我将基于自行车共享计划的数据构建一个 XGBoost 模型。该模型将根据三个特征预测某一天出租的自行车数量;温度湿度、风速

作者图片

此阶段的重点是方法而不是模型性能,因此模型是 XGBoost、RF、LG 还是任何其他模型都不重要。

下面的代码是您训练和保存模型所需的全部内容。随着我们的进展,在哪里存储保存的模型将变得更加明显。

构建和保存我们的 XGBoost 模型

在这个阶段,你应该创建一个空的目录,我称之为“MyApp ”,并在其中存储你的模型。我将使用 Visual Studio 代码(VSCode)来演示这个过程,但是您也可以使用其他方法。

作者图片

设置 Flask web 应用程序

与用户只阅读页面内容的静态网站相反,我们希望用户与我们的网页互动。具有功能和交互元素的网站被称为 web 应用程序。

在我们的例子中,用户将看到三个输入字段,通过提交一些数据,我们希望给用户一个预测。在此之前,我们需要理解浏览器通过发送请求与其他网页进行交互。典型的浏览器将发送遵循所谓的 HTTP 协议的 GET 请求以访问页面,并发送 POST 请求以通过网页发送数据。你将有希望沿着这条路走下去(双关语)!

作为 python 程序员,我们通常必须编写大量代码来处理用户请求。一个家伙(名叫阿明·罗纳彻)没有编写重复的代码来处理请求,而是把它放在了一个库中,作为一个笑话,并把它命名为 flask。

Flask 是一个 web 服务器框架,因为它要求我们的代码以某种方式组织。首先在“MyApp”目录中添加两个名为“Models”和“Templates”的文件夹。我们暂时不会使用“静态”文件夹,但是可以随意添加任何可选的 CSS 代码。您应该在与文件夹相同的根级别上创建一个 python 文件,并使用与 me 'app.py '相同的命名约定。然后,创建一个名为 index 的 HTML 文件,并将其放在 templates 目录中。不用担心 app.py 和 index.html 文件是空的;现阶段重点关注框架。

作者图片

您的目录应该类似于下图。请注意,我将我们的 ML 模型放在了模型的文件夹中。

作者图片

在一步步浏览这些文件之前,我需要你创建一个虚拟环境。

虚拟环境

鉴于 flask 只是一个第三方库,我们可以使用 pip (pip install flask)轻松安装 Flask 并运行我们的 web 应用程序,但当 web 应用程序依赖于特定版本的 python 和其他第三方库时,就会出现问题。想象一下,您的 web 应用程序运行良好,但是突然之间,第三方库的更新出现了,并且更改了某些函数的名称。这将使你的程序停止运行。为了解决这个问题,我们可以使用一个所谓的虚拟环境( virtualenv )。

将虚拟环境想象成一个文件夹,它不知道计算机上安装的其他库。只能访问安装在该文件夹中的库。

为了创建一个虚拟环境,我们需要你在当前的 Python 安装上安装 virtualenv 。换句话说,打开终端(或命令)行并键入:

pip install virtualenv

要检查您的系统中是否安装了它,请键入以下命令:

virtualenv --version

也可以用 pyvenv 代替 virtualenv ,但是你必须找到另一个向导。

一旦安装了 virtualenv,您就可以创建一个虚拟环境。虚拟环境文件应该在“MyApp”目录中生成。你可以使用命令行界面更改当前目录(使用 lscd ),或者右键单击你的“MyApp”文件夹,选择“在文件夹中新建终端”(如果你没有这个选项,不用担心,花 10.000 美元或目前的任何价格购买一台 Mac)。

键入以下命令,根据您使用的是 Windows 还是 Mac,仅使用其中一个命令:

python3 -m venv virtual (Mac)
py -3 -m venv virtual (Windows)

通过这样做,您只需使用 Python 和 venv 库创建一个名为“virtual”的文件夹,其中包含所有必需的虚拟环境文件。

我们现在必须通过键入以下命令来激活虚拟环境:

. virtual/bin/activate (Mac)
virtual\Scripts\activate (Windows)

你总是可以通过简单地输入deactivate来做相反的事情。如果一切顺利,您应该会在命令行界面中看到类似这样的内容:

(virtual) <user name> myapp %

您可以通过打开并查看“bin”文件夹(或 Windows 上的“Scripts ”)来浏览新的“虚拟”文件夹。您应该在预安装的文件夹中看到 pip 和 python。任何新安装的库都可以在“bin”文件夹中找到。

现在我们终于可以下载 flask 库了:

pip install Flask

你应该可以很容易地在 Mac 的virtual/bin/或者 windows 的virtual\Scripts\ 中找到 flask:

作者图片

你应该在这个阶段找到最近的镜子,重复这句话:只要我下定决心,我可以做任何事情。

GIF by Giphy

App.py

让我们打开“app.py”文件,开始插入一些代码。app 文件是将在 Heroku 上运行的 web 应用程序的核心。它将监听特定端口上的用户请求,并根据请求的类型使用特定的函数进行响应。

该应用程序可以分为三个部分。第一步包括导入库和初始化 flask 应用程序。我们使用Flask(__name__)来告诉 flask 我们的应用程序位于哪里。Flask 将定位与我们的应用程序位置相关的模板和静态文件。

**from** flask **import** Flask, render_template, request
**import** pickle
**import** pandas as pd# Initialise the Flask app
app = Flask(__name__)

现在,我们使用 pickle 从/models 目录导入保存的模型,并将其保存为“model”:

# Use pickle to load in the pre-trained model
filename = "models/model.sav"
**model** = pickle.load(open(filename, "rb"))

我们的 web 应用程序只有一个页面,称为主页或默认页面。“/”路由是主 URL。默认情况下,这应该指向 index.html 文件,即主页。

我们想在用户访问主页时触发一个特定的功能。为此,我创建了一个名为 main 的函数,它将根据请求是 GET 还是 POST 来响应用户请求。

  • 当目的是阅读或访问我们的主页时,用户发送 GET 请求。在这种情况下,我只想显示我们接下来将创建的 index.html 文件的内容。为此,我使用了 render_template 函数,其目的是在模板目录中查找一个文件并显示其内容。
  • 当信息被发送回 web 服务器时,用户发送 POST 请求。我们将允许用户输入特定的温度、湿度和风速。我将使用 request.form.get 函数从 index.html 文件中检索这些信息。我已经给了输入字段一个特定的名称,所以函数知道在哪里查找。然后,我使用 pandas 获取数据并从中创建一个数据帧,然后将数据馈送到我们的 ML 模型,并将结果存储在一个预测变量中,然后将其发送回 index.html 文件以显示结果。

注意,默认的 app.route 被配置为接收 GET 请求,所以我添加了方法=["GET "," POST"]来处理 POST 请求。

# Set up the main route
@app.route('/', methods=["GET", "POST"])
def **main**():
    if request.method == "POST":
       # Extract the input from the form
       temperature = request.form.get("temperature")
       humidity = request.form.get("humidity")
       windspeed = request.form.get("windspeed") # Create DataFrame based on input
       input_variables = pd.DataFrame([[temperature, humidity, windspeed]],
     columns=['temperature', 'humidity', 'windspeed'], dtype=float, index=['input']) # Get the model's prediction
       # Given that the prediction is stored in an array we simply  
         extract by indexing
       prediction = model.predict(input_variables)[0] # We now pass on the input from the from and the prediction 
         to the index page
       return **render_template**("index.html", original_input {'Temperature':temperature, 'Humidity':humidity, 'Windspeed':windspeed}, result=prediction) # If the request method is GET
     return **render_template**("index.html")

完整的代码如下所示:

app.py 文件

/模板

现在,我们将创建默认页面,用户将通过。让我们将 index.html 代码分成三个部分,正如我在前面的演练中所做的那样。尽管如此,如果你从未读过或写过 HTML 代码,我还是会推荐你看一段简单的 HTML 教程视频。

我的索引文件的第一部分只是由自愿的 CSS 代码组成。或者,我可以将它放在一个名为' styles.css '的样式表中,并存储在静态目录中。我在更高级的部署中这样做( GitHub )。

<**head**>
   <!-- CSS code -->
   <**style**>
     form {
          margin: auto;
          width: 35%;
          } .result {
          margin: auto;
          width: 35%;
          border: 1px solid #ccc;
             }
    </**style**> <**title**>Bike Usage Model</title>
</**head**>

第二部分由一个带有三个输入字段的表单组成。注意“required”属性,它保证用户的输入。当我使用 request.form.get 函数获取数据时,name 属性被用作 app.py 文件中的引用。

<!-- Use the action attribute to call the 'main' function -->
<**form** action="{{ url_for('main') }}" method="POST">
<**fieldset**>
     <legend>Input values:</legend>
     Temperature:
     <input name="temperature" type="number" required>
     <br>
     <br> Humidity:
     <input name="humidity" type="number" required>
     <br>
     <br> Windspeed:
     <input name="windspeed" type="number" required>
     <br>
     <br>
     <input type="submit">
</**fieldset**>
</**form**>

上面的表单,使用给定的 CSS,为我们提供了以下输入字段和提交按钮:

作者图片

您可能已经注意到了上面的{{ }}括号。每当看到这些,你应该马上想到:那哥们儿在用 Jinja。Flask 支持模板语言 Jinja,它使用{% %}和{{}}语法来包含占位符块或其他代码块。在这种情况下,我编写了“{{ url_for('main') }}”来触发 app.py 文件中的' main '函数。

接下来,我使用 if 条件和 for 循环来显示预测。仅当条件为真时,才会显示或创建该块。请记住,我们将用户输入存储在 app.py 文件中的字典‘original _ input’中。因此,我遍历字典来打印用户输入,最后但同样重要的是,我显示预测。

<!-- Our 'result' is false until a prediction has been made -->
{% **if** result %}
     <!-- Loop through dictionary and print key:value pair -->
     {% **for** variable in original_input %}
         <b>{{ variable }}:</b> {{ original_input[variable] }}
     {% **endfor** %}
     <br> <!-- Print prediction -->
     <br> Predicted number of bikes in use:
     <p style="font-size:50px">{{ result }}</p>
{% **endif** %}

完整的代码如下所示:

index.html 档案

让我们通过运行 flask web 应用程序来庆祝您到目前为止所做的工作。您需要在您的虚拟环境中安装所有的库(使用 pip 或 conda 来安装 pandas、xgboost、scikit-learn 和 pickle-mixin)。事后类型:

flask run

这将在本地地址上运行您的应用程序,如 http://127.0.0.1:5000/ 。通过访问这个网址,你应该会遇到 index.html 的文件。你可以通过输入 ctrl+c 来停止服务器。请注意,该命令触发了“pycache”文件的创建。是我们 app.py 的编译版。

在 Heroku 的部署

为了让其他人也能使用这个应用程序,我们还需要几个小步骤。让我们先在 GIT 和 Heroku 为你注册一个免费账户。为了与这两者交互,我们需要安装 GIT 和 Heroku 命令行接口,称为 Heroku-CLI 。如果您使用的是 VSCode,那么我建议安装 Heroku 和 Heroku-CLI 扩展。

格尼科恩

虽然 flask 很棒,但它主要用于本地开发。它不是为处理普通 web 服务器收到的请求而设计的。为了处理更多的请求,我们需要安装 gunicorn python 库。

pip install gunicorn

Procfile

安装了 gunicorn 之后,我们现在需要告诉 Heroku 使用它。我们通过创建一个没有文件扩展名的名为 procfile 的文件(例如,Procfile.txt 无效)来实现这一点。).该文件将指定启动时要执行的命令。

在空的 Procfile 文件中输入这一行:

web: gunicorn app:app
  • 第一个“app”代表运行您的应用程序的 python 文件的名称或它所在的模块的名称(例如,如果您有一个名为 run.py 的应用程序,那么它应该是 run:app)。
  • 第二个“app”代表您的应用名称(即 app = Flask(name))。

Requirements.txt

Heroku 需要知道安装哪些库来运行您的应用程序。我们可以通过运行以下命令来自动化这一过程:

pip freeze > requirements.txt

这将生成一个名为 requirements.txt 的 txt 文件,其中包含您的应用程序中使用的库。虽然很棒,但它没有包括所有必需的包。下面的列表显示了我的需求文件的内容(注意我已经包含了 scikit-learn,因为XGBClassifier对象直接与 scikit-learn API 交互):

click==8.0.1
Flask==2.0.1
gunicorn==20.1.0
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
Werkzeug==2.0.1
pandas
xgboost
scikit-learn
pickle-mixin

我没有添加我所有库的特定版本,但是你可以随意这样做。

Runtime.txt

虽然不是必需的,但是如果您希望指定特定的 python 版本,可以添加一个 runtime.txt 文件。您可以通过输入以下命令来检查您正在运行的 python 版本:

python -V

我的 runtime.txt 文件包含以下内容:

python-3.9.6

这是部署前的最后一个阶段,MyApp 目录看起来应该如下所示:

登录 Heroku

如果一切顺利,您应该开始通过命令行与您的 Heroku 帐户进行交互。在项目文件夹中打开命令行,然后键入:

heroku login

使用创建 Heroku 帐户时使用的电子邮件地址和密码。该命令将打开一个浏览器窗口,但是如果您更喜欢呆在命令行中,只需键入:

heroku login -i

成功登录的示例:

作者图片

##########################################

如果您在错误的环境中,登录可能不会成功。在这种情况下,以下命令可能有用: conda deactivate

##########################################

告诉 git 你是谁

在使用 git 命令将我们的文件发送到 Heroku 之前,您需要告诉 git 您是谁。这很重要,因为每次 Git 提交都会用到这些信息。

为此,请在命令行中键入以下内容:

git config --global user.name "John Doe"

按 enter 键,然后键入:

git config --global user.email johndoe@example.com

请确保在保留双引号的行中适当替换您的电子邮件地址和您的姓名。如果您传递了— global 选项,则只需要这样做一次。

为你的网络应用创建一个 git 库

通过键入以下命令创建本地 git 存储库:

git init

通过键入以下内容,将所有本地文件添加到在线存储库中:

git add .

确保在后加上的点。圆点表示您正在将整个目录添加到存储库中。

提交您的文件:

git commit -m "First commit"

在 Heroku 上创建一个空应用

接下来的步骤包括在 Heroku 上创建一个空应用程序,并将我们的本地文件发送到该应用程序。我们将使用 git 发送文件。

创建一个空 Heroku 应用程序:

heroku create <app-name-you-choose>

应用程序创建完成后,您可以进入您的 Heroku 帐户获得概述:

作者图片

最后的步骤包括获取我们所有的文件,将它们推送到 Heroku,然后激活应用程序:

git push heroku master

激活应用程序,并设置 dynos 的数量(任何超过一个将花费):

heroku ps:scale web=1

访问应用程序并查看性能

如果一切顺利,您应该可以通过以下网址访问您的应用程序:

<app-name-you-choose>.herokuapp.com

您只需通过上面的 URL 或键入以下内容即可打开它:

heroku open

可能需要一段时间才能发挥作用,所以要有耐心。如果一切顺利,你应该有一个应用程序运行在网络上。你应该为自己感到骄傲。

如果你觉得舒服或者想看部署的不同变化,我可以推荐访问我的高级部署。这些文件可以在我的 git 上获得。

很高兴知道

下面的命令很好地处理了我在这个过程中看到的所有错误:

  • 使用它在本地服务器上打开 Heroku。记得安装所有需要的库。
  • 应该是不言自明的。
  • heroku run 'ls -al'您的 dyno 副本,让它列出目录内容。当您添加更多文件,并需要检查它们是否已添加到 Heroku 上时,这很有用。
  • heroku logs --tail使用这个 Heroku 命令,一旦你的应用启动并运行,你就可以访问它的性能信息。
  • heroku restart应该是不言自明的。
  • heroku apps:rename <newname>重命名你的应用程序。

我希望你像我喜欢写这篇文章一样喜欢它。如果你理解我的代码有任何困难,请留下评论。数据科学社区给了我很多,所以我总是乐于回馈。

请随时在 Linkedin 上与我联系,并在 Medium 上关注我以接收更多文章。

计算机视觉数据增强完全指南

原文:https://towardsdatascience.com/complete-guide-to-data-augmentation-for-computer-vision-1abe4063ad07?source=collection_archive---------14-----------------------

关于图像增强,你需要知道的所有理论。适合初学者和专家。

作者图片

数据扩充是深度计算机视觉中最重要的课题之一。当你训练你的神经网络时,你应该像…一直那样做数据增强。否则,您将无法有效地使用数据集,并且您的模型将无法发挥应有的作用。

在本教程中,我总结了所有关于图像增强的开源知识,并添加了我从几个商业计算机视觉项目中获得的经验。希望,你会觉得有用!

内容
—什么是数据增强
—如何增强图像
—论文怎么说
—如何为你的任务选择增强
—py torch 和 TensorFlow 中的图像增强
—下一步

什么是数据增强

数据扩充是一种用于人为增加数据集大小的技术。从数据集中提取一个样本,以某种方式对其进行修改,将其添加到原始数据集中——现在,您的数据集增加了一个样本。

您可以对数据集中的所有样本执行此操作,并以不同的方式多次修改每个样本,以获得 10、100、1000 倍大的数据集。您甚至可以创建一个无限大小的数据集,因此您的模型在训练过程中永远不会“看到”相同的样本。

图片 1。数据增强技术的可视化。作者图片

更多的数据=更好的模型。数据扩充有助于克服“数据不足”问题,防止过度拟合,并使模型在以前未见过的样本上表现更好。并且不需要额外的工作-收集数据或标记数据,这有时可能是昂贵的或不可行的。

数据增强应用于许多领域——自然语言处理、时间序列分析、音频处理……然而,今天我们将重点讨论用于计算机视觉的数据增强——图像增强。

如何增强图像

假设,你想训练一只“猫对狗?”分类器。你已经收集了 500 张猫的图片和 500 张狗的图片。然而,1000 张图像可能不足以创建高性能的模型,因此您需要使用数据扩充,您听说过这可能会有所帮助。主要问题:如何修改图像来增加数据集?

这里有很多选择。下面是最流行的图像增强列表。

图片 2。最受欢迎的图像增强。作者图片

  • 裁剪—拍摄一部分图像。
  • 旋转—围绕中心(或其他点)旋转图像。
  • 翻转—围绕水平线或垂直线镜像图像。
  • 最流行的滤镜是模糊和锐化。模糊会使边缘和细节变得平滑,而锐化会突出它们。
  • 仿射变换-任何保持平行线的变换。
  • 添加噪声-例如使随机像素变黑和变白(椒盐噪声),添加高斯噪声,甚至从图像中移除整个区域(剪切)。
  • 颜色变化会使图像变暗或变亮、灰度或极度饱和、对比度变低或变高。

对于那些对摄影感兴趣的人来说,这些图像修改听起来可能非常熟悉。的确如此。如果你愿意,你可以把图像增强技术想象成雇佣成千上万的照片编辑来处理具有独特风格的图像。

像 Photoshop 和 Lightroom 这样的应用程序也可能会给你一些线索,比如在模型训练期间你可以利用哪些其他的数据增强。

图片 3。Adobe Lightroom Classic 中的基本面板提供了一个线索,说明还有哪些颜色变化可以用作数据扩充。作者图片

**想象力是唯一的限制。**首先,图 2 中的列表并不是一个完整的增强列表。有这么多的方法来改变一个形象,所以我不相信,一个完整的清单甚至存在。所以,如果你觉得这些还不够,可以在网上寻找更多的增强类型。

其次,对于数据集中的每个图像,您可以:

  • 应用单一增强或序列;
  • 更改增强的应用顺序;
  • 随机化增强参数,如旋转角度或亮度范围;
  • 随机化要应用的特定增强的概率。

作为一名数据科学家,选择使用何种增强(以及以何种顺序)是您的任务。

**空白边框怎么办?**有时,增强后可能会出现空白边框。默认情况下,增强库用白色、黑色或灰色填充空白像素。您可以保持原样,或者更进一步:

  • 将颜色更改为其他颜色,例如蓝色。
  • 复制像素—复制靠近边框的像素以填充空白区域。
  • 反射(reflect )-靠近边界的镜像零件。
  • 环绕—从图像的另一侧复制像素。

图片 4。关于如何处理空白边框的想法。作者图片

注意数据集标签。有时,根据您使用的数据集,一些数据扩充可能不仅会更改图像,还会更改其标签。

在训练“猫对狗?”分类器,图像 2 中没有一个增强会从一只狗创造出一只猫。例如,当裁剪图像时,狗的一部分仍然是狗。但是,如果您正在解决对象检测任务,如“在图像中找到一只狗”,裁剪将更改原始图像的位置标签(边界框)。

图片 5。根据任务的不同,相同的增强可能会对图像标签产生不同的影响。作者图片

脏标注会在模型中引入噪声并降低其性能,因此在考虑使用特定的数据增强时,一定要问自己:“这种增强会改变图像标注吗?”

如果答案是“是”,下一步该怎么做就看你自己了:

  • 您可以避免使用增强功能;
  • 或者分别修改标签以匹配增强的图像。

报纸怎么说

在这一部分,我将展示几个例子,图像增强是如何在研究项目中使用的,以及它带来的好处。

LeNet-5。 Yann LeCun 和共同作者发表了一篇论文[1],描述了最早的神经网络之一,并使用了…数据增强。那是 1998 年,当时他们称之为“数据扭曲”。他们得出结论,与不使用数据扩充相比,在扩充数据集上训练时,测试集误差略有下降。

“…我们通过随机扭曲原始训练图像来人为生成更多训练示例…扭曲是以下平面仿射变换的组合:水平和垂直平移、缩放、挤压(同时水平压缩和垂直伸长,或相反)以及水平剪切…”[1]

图片 6。用于训练 LeNet-5 的图像增强。作者图片

**ImageNet。**在训练 ImageNet [2]时,使用了大量的数据扩充。ImageNet 是一个庞大的神经网络,有 6000 万个参数,所以需要大量的数据来训练它。作者提到,如果没有数据扩充,模型会过度拟合。

“……数据增强的第一种形式包括生成图像平移和水平反射。我们通过从 256×256 图像中提取随机的 224×224 小块(以及它们的水平反射)并在这些提取的小块上训练我们的网络来做到这一点。如果没有这种方案,我们的网络将遭受严重的过度拟合,这将迫使我们使用更小的网络…数据增强的第二种形式包括改变训练图像中 RGB 通道的强度…”[2]

图 7。用于训练 ImageNet 的数据增强。作者图片

**优信网。**论文[3]展示了在数据有限的情况下,数据增强如何帮助解决医疗任务。在其中一个实验中,作者仅使用 30 幅大小为 512×512 像素的图像成功训练了一个分割模型。印象深刻吧?

“…对于显微图像,我们主要需要平移和旋转不变性,以及对变形和灰度值变化的鲁棒性。特别是训练样本的随机弹性变形似乎是用非常少的注释图像训练分割网络的关键概念……”[3]

图片 8。用于在医疗数据
(医疗数据通常是灰度的)上训练 U-Net 的数据增强。作者图片

如何为你的任务选择增强

这里有三个词:领域专业知识、业务需求和常识——这是创建一个好的数据扩充管道所需要的。

**领域专长。**根据您的项目领域,有些数据扩充是有意义的,而有些则没有意义。

例如,在处理卫星图像时,裁剪、旋转、反射和缩放是一个不错的选择。因为它们不会给建筑物等物体带来变形。

图片 9。卫星图像数据增强的例子。图片来源:[4]

另一方面,当处理医学图像时,更好的选择是颜色变换、网格变形和弹性变换[4]。

形象 10。医学图像数据扩充的例子。图片来源:[4]

业务需要。例如,你负责为一辆无人驾驶汽车开发一个计算机视觉系统。您应该在数据扩充管道中使用水平翻转吗?

图片 11。在为自动驾驶汽车开发
计算机视觉系统时,你会使用水平翻转吗?作者图片

嗯,看情况。因此,更好的问题是:你的计算机视觉系统是否有望看到颠倒的图像,并有望能够分割它们?

汽车发生事故,摄像头颠倒了会怎么样?计算机视觉系统会停止做分割并关闭吗?还是会因为某种原因继续工作分割物体?

没有正确的答案,这些问题你应该和产品经理讨论。

**常识。**有太多增强这种东西。在图像变得无法识别之前,你应该停止修改。如果人类不能理解图像中的内容,你怎么能期望模型能理解呢?

图片 12。这些例子中大约有一半被过分夸大了。图片来源:[5]

**提示。**如果你仍然不确定,使用特定的数据增强是不是一个好主意,那就去做研究吧。使用不同的数据扩充管道训练几个模型,并在相同的验证集上比较模型准确性。

PyTorch 和 TensorFlow 中的图像增强

我们不会在这里详细讨论,也许,以后我会写一个单独的帖子。让我们只讨论几个重要的要点。

  • 深度学习的增强通常是在线完成的。这意味着,增强图像不会存储在硬盘上,只有原始数据集存在。当加载一批原始数据时,它会被动态扩充,用于训练,然后从操作内存中释放。
  • 以下是如何在 Pytorch 中进行图像增强:文档
  • 下面是如何在 TensorFlow 中进行图像增强:文档
  • PyTorch 和 TensorFlow 默认实现只增加图像,而不增加标签。如果你需要对图片和标签都进行增强,你应该自己编写增强功能,或者使用第三方库,比如albuminations。

下一步是什么

我相信这就是你需要知道的关于图像增强的所有理论。随着时间的推移和实践,您将获得更多的经验,并且可以很容易地判断出对于特定的任务,什么样的数据增强会表现得更好。所以,练习,练习,再练习!

附言:如果你对 PyTorch / TensorFlow 中的图像增强教程和白蛋白感兴趣,请告诉我!

参考文献

[1]“基于梯度的学习应用于文档识别”。Yann LeCun,Leon Bottou,Yoshua Bengio 和 Patrick Haner。论文

[2]“使用深度卷积神经网络的 ImageNet 分类”。亚历克斯·克里热夫斯基,伊利亚·苏茨基弗,杰弗里·e·辛顿。论文

[3]“U-Net:用于生物医学图像分割的卷积网络”。奥拉夫·龙内贝格、菲利普·费舍尔和托马斯·布罗克斯。论文

[4]“相册:快速灵活的图像增强”。Alexander Buslaev,Alex Parinov,Eugene Khvedchenya,Vladimir I. Iglovikov,亚历山大·巴甫洛夫 A. Kalinin。论文

[5] imgaug,用于图像增强的 Python 库。 Github

使用 SpaCy 对 Tweets 进行分类的完整指南

原文:https://towardsdatascience.com/complete-guide-to-perform-classification-of-tweets-with-spacy-e550ee92ca79?source=collection_archive---------5-----------------------

什么是 NLP?我们如何执行 NLP?刚从 SpaCy 套餐开始?这是一个关于执行 NLP 及其相关概念的完整指南。

格伦·卡丽在 Unsplash 拍摄的照片

新冠肺炎已经影响了许多人的生活,因为他们失去了心爱的人,失去了工作,远离了这个世界。然而,在数字时代,人们并没有停止与世界分享他们的想法、评论或感受——他们通过社交媒体的力量做到了这一点。

在本文中,我们将介绍 NLP 项目的主要概念,包括数据选择、探索性数据分析、NLP 预处理、NLP 模型(统计/神经语言模型)和度量标准选择。感兴趣的数据集是 Kaggle 上的新冠肺炎 tweet 数据集,而所有 NLP 相关的任务都是使用 SpaCy 执行的。

设置

在本文中,我使用了冠状病毒推文 NLP 来创建一个模型,通过观察推文的内容来对推文的情绪进行分类。我使用 spaCy 展示工作代码,然后通过使用简单朴素贝叶斯、逻辑回归、支持向量机的模型对神经网络(如 BERT)进行评估。

我使用的环境是基于 Deepnote 笔记本的 venv 虚拟机上的 Python 3.7。涉及的软件包有:

  • spaCy*:*一个快速的、生产级的 NLP 库。
  • matplotlib . py plot:Python 中数据可视化的常用包
  • scikit-learn :一个简单有用的数据分析和机器学习的包。
  • pandas:Python 上一个通用、灵活、易用的数据分析和操作工具。

这些包是整个分析的预处理、训练和可视化的基础。

数据

我用的数据是 Kaggle 上的 冠状病毒 Tweets NLP 数据集。这些数据是通过 Twitter 收集的,并经过手动标记,在训练数据中产生了 41,157 个样本,在验证数据中产生了 3,798 个样本。它由以下 4 列组成:

  1. 位置 :发布推文的位置
  2. 推文:推文发布的时间
  3. 原推文 :推文正文
  4. 标签 :人为标注的情绪,从极度消极到极度积极不等。

还有两个额外的栏目, 用户名昵称 ,出于隐私的考虑,这两个栏目都被删除了。

探索性数据分析

在训练模型之前,我对数据做了一些探索性数据分析(EDA),主要是通过 Pandas Profiling ,这是一个强大的包,为任何数据集的 EDA 创建了一个用户友好的界面(见下文)。基于该报告,我还进行了一些手动 EDA 可视化,以呈现对数据的更具体的分析。

用于执行熊猫概况分析的代码

Pandas Profiling 生成的训练集缺少数据(图片由作者提供)

  • 缺失数据(NAs)

左边的图显示了数据集中缺失的数据。我们观察到缺失数据只出现在 位置 列。

Pandas Profiling 生成的测试集中缺少数据(图片由作者提供)

我们还看到,位置列中缺失数据的百分比在训练集和测试集之间是相似的,都在 30%左右。

在进一步检查位置列后,我们发现数据在位置名称和经度和纬度数据的标注上存在不一致,这使得数据在缺少数据的情况下更不可用。

  • 类别平衡

为了进一步研究数据,我使用 Pandas Profiling 查看了不同列的分布。 OriginalTweet 列是完全唯一的。而 TweetAt 列有一个明显按日期划分的分布,这虽然不太可能,但可能会混淆情绪原始 Tweet 列之间的情绪分类。因此,我决定在预处理部分重新分割数据。

**

Pandas 分析生成的训练集(左)和测试集(右)的 OriginalTweet 列的值分布(图片由作者提供)

**

来自训练集(左)和测试集(右)的 TweetAt 列的条形图(图片由作者提供)

另一方面,情绪栏显示了不太平衡的类别,其中积极的数据最多,极度消极的数据最少。然而,对于测试集来说,情况并非如此,其负面的比正面的多,如下所示。因此,我在这方面投入了更多,以确定这是否是分析的另一个混杂因素。

**

熊猫概况生成的训练集(左)和测试集(右)的情感类别的平衡(图片由作者提供)

测试和训练数据集中情感类别平衡的饼图(图片由作者提供)

为了更容易比较,我为他们每个人制作了饼状图,发现百分比的差异并不显著,正如熊猫概况报告最初显示的那样,所有类别的变化都在 3%以内。然而,由于 TweetAt 列的时间依赖性,我不得不重组整个数据集。

对于数据的更多探索性分析,请通过在本地 Jupyter 笔记本上实现 代码 来查看使用 Pandas Profiling 生成的报告。

预处理

了解原始数据后,我将训练和测试数据结合起来,取一半的数据进行两次拆分,每次拆分 20%的原始数据,创建三个数据集(由于训练模型时的计算限制,采样 50%的数据):

  • 训练集:所有数据的 80%,用于训练。
  • 测试集:所有数据的 16%,用于测试训练。
  • 验证集:所有数据的 4%,用于在看不见的数据上测试模型。

这是通过以下代码完成的:

组合数据的训练集、测试集和验证集分割的代码

下一步是完成一系列自然语言处理(NLP)程序,以便将推文“清洗”成 令牌 ,这些令牌可以被不同的模型消化。我们可以用“ 做菜 ”来比喻这个过程。

传统模型的符号化图像(作者提供的图像)

最初的推文是原料,比如胡萝卜。要烘焙胡萝卜蛋糕,我们首先需要清洗胡萝卜,去除不想要的污垢*。在 NLP 中,我们需要首先移除不想要的字符,比如 URL、表情符号、标签等等。这取决于手头的任务。例如,如果你想找到标签和文本之间的联系,标签就很重要。*

在我的情况下,我不想要任何这些,所以我通过以下方法删除所有这些:

  • 字符串 库中删除标点符号
  • 删除停用词(功能词,如 to、in 等。)使用 空间
  • 使用正则表达式删除 URL(从 re 包)

接下来,如果胡萝卜上有一些霉菌或不想要的部分,很自然地切掉那一小部分或再次清洗*。这类似于预处理的 拼写纠正 部分,这里我们使用模糊匹配将一些拼写错误调整回原来的形式。具体来说, Levenshtein 距离(即编辑距离)用于计算书写单词与其可能的纠正形式之间的差异数。我使用拼写检查包来完成这个任务,因为它可以直接添加到空间管道中,编辑距离可以手动设置。*

在那之后,我们就不需要胡萝卜皮了,尽管它确实有一些价值和好处。这类似于 词汇化 过程,其中我们移除行中有意义的语义部分,以将单词简化为它们的核心形式。例如,单词“运行”有一个双 ning后缀。当在现实中使用它时,我们只需要词干" run "。然而,当你在做词性标注(POS)时想要识别时体*(或时态)时,这个后缀 -ing 就变得很充实,因为它告诉我们这个句子处于进行体时态。*

最后,我们把胡萝卜切成大块,以便稍后烹饪。这就是 标记化 的过程,在这里我们把单词和它们的词干分开,以便以后用不同的模型操纵。在这种情况下,我们使用 spaCy 中的 nlp 函数,它通过识别单词之间的空格来自动完成标记化过程。我们也可以称整个预处理为标记化过程,因为我们最终输入句子并输出每个句子的核心标记。

预处理管道的代码

现在,我们已经将句子标记化了,但是标签仍然是字符串格式。由于标签由“非常负面”、“负面”、“中性”、“正面”和“非常正面”组成,我们可以从 1 到 5 标记每个类别

模特们

在准备好所有标记化的句子之后,我们现在可以使用预处理的数据来训练模型。我选择的机型可以分为两类。第一个是统计语言模型,包括朴素贝叶斯、逻辑回归和支持向量机(SVM),第二个是神经语言模型,包括 CNN 和 BERT 模型。

统计语言模型

统计语言模型使用概率方法来确定语料库的下一个单词或标签。常见的概率模型在将数据输入预测器之前,使用特定顺序的 N-grams 和无序的词袋模型(BoW)来转换数据。例如,我们正在执行本文中的分类任务;因此,在输入下面的概率模型之前,通过 scikit-learncount vectorize在语料库上执行词袋模型,本质上是所有标记的频率表。

通过 scikit-learn 生成单词袋模型的代码。

为了执行上一节中提到的任何数据的预处理、词袋矢量化以及来自多个模型的分类,我使用了 scikit-learn 的Pipeline模块,该模块将数据的清理、矢量化和分类分组到一个管道中,这允许更简单的数据处理步骤,用于算法与其他数据和模型的转移学习。

任何数据集和模型的整个 NLP 过程的代码。

  • 朴素贝叶斯

朴素贝叶斯(NB)是一种常见的文档分类模型。朴素贝叶斯的主要概念是使用贝叶斯定理来估计每个标签上所有不同单词的联合概率*。*

换句话说,想象你有两种品牌的薯片,每种都有其独特的形状、颜色和味道。通过识别每个单独芯片的形状、颜色和味道的共同趋势,我们可以简单地通过其特征来猜测未知芯片的品牌。这里,我们可以通过以下方式将这一概念与朴素贝叶斯的形式概念联系起来:

  • 芯片的品牌标签**
  • 单个芯片特征是每个令牌频率**
  • 贝叶斯定理可以对应每个品牌的共同趋势

在现实中,我们简单地使用 scikit-learn 的多项式函数 将数据转换成词袋模型后进行朴素贝叶斯:

朴素贝叶斯分类器的代码

关于朴素贝叶斯的更完整的解释,请阅读古斯塔沃·查韦斯的这篇文章。

  • 逻辑回归

尽管在二元分类问题中最常见,但对于多类问题,多项式逻辑回归是朴素贝叶斯的替代方法。逻辑回归的主要概念是使用观察特征的线性组合来估计特定值和相应的标签*。*

回到筹码的例子,对于每个品牌,我们给每个筹码的形状、颜色和大小赋值,并将它们加起来达到某个值。如果该值高于某个阈值,我们会将该芯片视为一个品牌,如果该值低于某个阈值,那么它将是另一个品牌。这是二元逻辑回归的一般逻辑,其中观察特征的线性组合指的是芯片特征的不同赋值的相加。

这里,我们使用 use scikit-learn 的 LogisticRegression 函数在将数据转换为词袋模型后进行多项式逻辑回归:

逻辑回归分类器代码

如果您希望了解更多信息,请参考这个关于多项逻辑回归的 wiki 页面。

  • 支持向量机(SVM)

支持向量机(SVM)也是一种常见的分类模型。SVM 的优势在于它生成了一个超平面决策边界*,这意味着非线性特征也可以用于分类。*

以薯片为例,我们可以想象我们把两个品牌的薯片扔在桌子上。然后,我们根据一个轴上的颜色和另一个轴上的大小对每个芯片进行排序。我们将能够知道此时哪个芯片属于哪个品牌。然而,芯片有时是混合的,因此,我们不能画一条直线来区分两种品牌的芯片。现在,我们找到了一种方法将这些芯片投射到桌子上的三维投影中,其中每个芯片也由芯片的辣度分开。通过这样做,我们可以在 3D 投影中放入一张纸,完美地区分这两个品牌。最后,我们将纸投影到桌子上,一条弯弯曲曲的线完美地将两个品牌分开。

虽然复杂得多,但这是使用 SVM 算法(3D 投影变换)来寻找非线性决策边界*(paper)的简单解释。*

与之前类似,我们使用 use scikit-learn 的 SVC 函数在将数据转换为词袋模型后进行 SVM:

SVM 分类器代码

更多信息请观看 StatQuest 的 这个 YouTube 系列

神经语言模型

神经语言模型利用了神经网络的当前进展,其比过去的统计模型更好地概括了模型。虽然每个神经网络使用相当不同的结构来优化分类,但在 NLP 中, 单词嵌入 被认为是突破性的技术,在过去几年中实现了实质性的增长。

单词嵌入是单词的矢量化表示,标记在数学上更加相似的单词。这可以是自己训练的one-hot encodedtoken,也可以是来自大型科技公司或学术机构的预训练嵌入,比如 Google 的 Word2Vec 和 BERT embeddings,或者斯坦福的 GloVe。

变形金刚架构讲解(图片由 Lena Voita 提供)。

除了单词嵌入之外,模型的架构可以影响模型的准确性,即使使用相同的数据。NLP 目前最先进的架构之一是 变形金刚 。转换器架构从序列中获取输入,并输出序列。在这两者之间,序列将首先通过编码器堆栈,然后通过解码器堆栈,这两个堆栈都配备有注意机制(例如,自注意)。虽然这听起来很专业,但我们可以把编码器-解码器想象成莫尔斯电码,在通过解码器翻译回英语之前,我们将英语文本编码成长信号和短信号。

另一方面,注意力使得模型能够关注输入中与该单词密切相关的其他单词。把它想象成视觉注意力——我们的眼睛基于之前看到的东西聚焦在图片的特定部分。比如看下图。当我们看她的太阳镜时,由于距离很近,我们自然会关注她的噪音。你可能认为两部分之间的距离是最重要的,但是如果你看她的头发的右边,我们也会注意到左边,因为它们都是“她的头发”的一部分,即使她的脸在中间。尽管这不是一个精确的类比,但是《变形金刚》中的注意力以类似的方式工作

照片由布鲁诺亚当从 Unsplash

以下面的句子为例,当我们将注意力集中在单词“ball”上时,它与形容词“blue”和动词“holding”的关联将比主语“boy”更强,因为“ball”更可能是“hold ”,而不管它是由“boy”、“girl”还是任何其他人持有。

图片作者 Ketan Doshi

注意力将这种上下文驱动的信息以数学方式形式化,并在计算结果时考虑这种关联,这通常比统计单词袋模型更好,因为“上下文”信息无法存储。

更多信息请查看 本系列 作者为科坦多希或者 本文章 作者为莱娜沃伊塔。

SpaCy 的 textcat 合奏

对于我的第一个实现,我选择了 spaCy 的内部 textcat ensemble 模型,它使用 transformer 体系结构将 Tok2Vec 模型与线性单词袋模型结合起来。要在 spaCy 上执行此操作,我们需要首先了解 spaCy 如何训练模型。

  • 配置系统

这是由于可以为神经网络中的每一层输入的设置和超参数的复杂性。spaCy 中的配置系统允许开发者以一种干净的方式存储和写入这些参数,并且如果参数是全局的,则最小化冗余工作。我们没有为神经网络的每个单独层创建一个长类,而是在一个可以通过命令行操作调用的.cfg文件中列出我们需要的东西。我们可以使用 SpaCy 在其文档中的 quickstart 函数快速创建其中一个。

图片来自 spaCy 的文档

我所做的具体选择记录在上图中。这将输出一个名为base_config.cfg.cfg文件,该文件将用于使用下面的命令行提示符填充实际的config.cfg

初始化配置文件的代码

在训练模型之前,我们还需要以不同的方式处理数据,因为现在的输入不是一个单词袋模型,而是原始文本。这是通过三个步骤完成的:

神经模型的符号化图像(图片由作者提供)。

第一步是删除不想要的文本,比如从原始文本中删除 URL。在这种情况下,删除停用词和标点符号是没有必要的,因为 spaCy 的 transformer 模型会自动连接到标记器。此外,词汇化是不必要的,因为前缀和后缀包含有价值的单词上下文,这有助于在确定关联时的注意力。

第二步是对类别进行一次热编码,将类别转换成与文本的实际标签相对应的[0,1]的字典。例如,一个“积极的”标签将是{"Extremely Positive": 0, "Positive": 1, …,"Extremely Negative": 0}

用于预处理原始文本和标签的代码

第三步是将这些数据的输出转换成名为.spacy的二进制文件,以便在 spaCy 中执行训练过程。

用于将数据转换成两个二进制的代码。空间文件

最后,我们可以使用命令行提示符来训练这些文件,在命令行提示符中,我们还可以指定训练数据输入、测试数据输入和模型输出。

模型训练代码

变压器的双向编码器表示(BERT)

使用相同的配置系统,我在名为en_core_web_trf的基于 RoBERTa 的管道上使用预训练的 BERT 模型重新训练数据。我唯一改变是使用en_core_web_trf而不是en_core_web_sm加载 spaCy 的管道和文档,后者是小型的标准英语管道。

罗伯塔是脸书在 2019 年出版的伯特的优化版本。它改进了 BERT 体系结构,该体系结构被认为是 NLP 文本分类任务的最新模型之一。BERT 背后的主要思想是使用转换器的编码器部分,并进行屏蔽语言建模*、,这意味着移除句子中的标记并预测它们,以及下一句预测,这是基于之前和之后的句子预测下一句。***

我们可以将屏蔽语言建模视为填补句子的空白,其中模型被训练为填补这些句子的正确单词,类似于下面的示例。在预训练的 BERT 模型中,15%的数据被屏蔽。

*FILL-IN THE GAP: The boy is __ a blue ball.*

另一方面,下一个句子预测是大规模版本的屏蔽语言建模,其中模型屏蔽完整的句子,并使用前后的句子来预测内容。编码器中每一层的权重在经过大规模数据训练后被冻结,以存储单词和句子之间的上下文。

这种预训练的 BERT 模型对于迁移学习是有用的,因为编码器的每一层的权重是预先确定的。通过这样做,我们可以添加一个附加层来基于预训练权重(通常由句子的上下文信息组成)的输出来训练分类任务。

回到烹饪的例子,我们可以想象厨师之前已经完成了调味,烹饪和收集所有必要的原料。现在,我们只需将食物装盘,并用顾客想要的特色装饰菜肴。在这个例子中,电镀之前发生的一切都是由构建预训练模型的研究人员执行的。我们只需要针对我们的特定任务(客户)对菜品进行微调。

关于 BERT 模型的更多信息,请查看本文

除了我们需要用 RoBERTa 管道创建.spacy文件之外,训练过程遵循与先前模型相同的过程。

用于将数据转换成两个二进制的代码。空间文件

然后,我们使用与之前模型相同的方法进行训练

模型训练代码

结果呢

我使用的主要指标是 F1 分数。该指标结合了召回率和精确度,使用以下公式:

来自维基百科的 F1 分数方程式。

为了理解 F1 分数意味着什么,我们需要理解什么是精确度和召回率。

精确的图像和召回来自维基百科

  • 精度 :所有预测的正值中,实际为正值的有多少?当我们只看正面案例时,此指标显示了模型的准确性。
  • 回忆 :所有实际为正的值中,有多少预测为正?此指标显示了模型在检测实际正值方面的表现。

对于任何给定的模型,通常的目标是最大化精度和召回率,然而,在精度和召回率指标之间经常有一个折衷。为了对模型准确性的两个方面有一个总体的了解,F1 分数是作为两个指标之间的调和平均值来计算的。这是因为简单地平均这两个值会降低每个单独值的重要性。

模型结果

每个模型的结果如下所示:

  • 统计语言模型结果

朴素贝叶斯模型

朴素贝叶斯模型的结果

逻辑回归模型

逻辑回归模型的结果

SVM 模式

SVM 模型的结果

从这三个模型中,我们看到逻辑回归和 SVM 的精度都在 0.55 左右,而朴素贝叶斯模型的精度最差,在 0.45 左右。

  • 神经语言模型结果

斯帕西的标准型号

spaCy 的 textcat 集合模型的结果

spaCy 的 textcat 集合模型收敛到 0.63 的精度。

伯特

预训练模型的结果

微调的预训练 BERT 模型收敛于 0.61 的精度。

对比

从这些结果中,我们看到神经网络提高了 F1 精度结果。然而,与统计模型(每个模型约 2.5 小时)相比,模型的训练时间在 CPU 机器上花费了很长时间(10 个时期 12 小时),即使使用预训练的 BERT(10 个时期 6 小时)。这是因为尽管神经模型通常比传统模型具有更好的准确性,但是神经模型的训练需要很大的计算能力。因此,如果没有足够的 CPU 或 GPU 或大型数据集,神经模型的训练可能需要几天时间。因此,在运行特定任务之前,需要考虑计算时间和准确性之间的权衡。

个人推文示例

为了检验神经语言模型对个别推文的预测,我测试了验证集中的一个例子。以下是两种神经语言模型的一个 tweet 示例。

这是标准的空间模型:

它在预测文本和原始文本中都显示了否定的分类,其为否定(截断)的概率为 0.80。

对于预训练的 BERT 模型,结果显示其为负的概率为 0.94。

虽然这些结果听起来令人鼓舞,但模型的准确性仍然受到数据的限制。因此,由于该数据集的人为标注过程,可能存在人为错误,并在训练期间通过模型传播。这将主要出现在当前数据集之外的推文预测期间,这是不可避免的,但可以通过将模型引入其他数据来缓解。这对于降低模型的数据依赖性和提高一般用途的稳健性是更可取的。

摘要

在本文中,我们使用 spaCy 和新冠肺炎 tweet 数据集完成了构建文本分类模型的端到端过程。我们经历了探索性数据分析的过程,并对数据进行了相应的预处理。然后我们训练统计模型和神经模型,观察它们的优缺点。最后,我们根据每个模型的 F1 准确度指标对模型进行了评估。

此外,我们发现神经网络通常比统计模型具有更好的性能;但是,如果没有安装 GPU,神经网络的训练时间会明显更长。希望这篇文章能帮助你理解什么是 NLP 文本分类,以及如何使用 spaCy 生成一个模型!

参考文献

代码参考

  • Github 回购
  • Deepnote Python 笔记本
  • 教程:使用 spaCy 在 Python 中进行文本分类

数据来源于 Kaggle

  • A.米格兰尼,冠状病毒推特 NLP (2020),Kaggle

文章和视频

  • 斯坦福自然语言处理,标记化 (2008),剑桥大学出版社
  • J.Brownlee,统计语言建模和神经语言模型 (2019),关于机器学习掌握中自然语言处理的深度学习
  • J.Brownlee,什么是文本的单词嵌入? (2017),关于机器学习掌握中自然语言处理的深度学习
  • K.Doshi,变形金刚解说系列 (2020),走向数据科学
  • D.Subramanian,使用 spaCy 3.0 Transformers (2021)构建情感分类器,迈向数据科学
  • SpaCy, SpaCy 3.1 文档 (2021)

使用 Python 进行回归分析的完整指南

原文:https://towardsdatascience.com/complete-guide-to-regressional-analysis-using-python-bbe76b3e451f?source=collection_archive---------2-----------------------

最小二乘法(MLR)和加权最小二乘法;拉索(L1)、山脊(L2)和弹性网正规化;核和支持向量机回归

大家好,欢迎来到这篇关于 Python 回归分析的全面深入的长篇概述!在这次深入探讨中,我们将涉及最小二乘法、加权最小二乘法;套索、脊和弹性网正则化;最后总结一下内核和支持向量机回归!虽然我想涵盖一些高级的回归机器学习模型,如随机森林和神经网络,但它们的复杂性需要它们自己的未来帖子!在这篇文章中,我将从两个方面来探讨回归分析:理论上的和 T2 的应用。从理论方面来说,我将介绍基本级别的算法并导出它们的基本解决方案,而在应用方面,我将使用 Python 中的 sklearn 将这些模型实际应用于现实生活的数据集!

目录

  • 什么是回归?
  • 我们的数据集—医疗费用
  • 如何衡量误差?
  • 最小二乘解(MLR)
  • 模型的解释
  • 加权最小二乘法(WLR)
  • 如何处理过度拟合——正规化
  • 如何处理欠拟合—核回归
  • 支持向量机
  • 结论

什么是回归?

在机器学习领域,任务通常分为四大类:监督学习非监督学习半监督学习学习强化学习。回归属于监督学习的范畴,其目标是学习或模拟一个将一组输入映射到一组输出的函数。在监督学习中,我们的一组输出通常在统计学中被称为因变量或者在机器学习社区中被称为目标变量。这个目标变量可以是离散的,通常称为分类,也可以是连续的,通常称为回归。通过这种方式,回归只是在给定一组输入的情况下,试图预测一个连续的目标变量。

我们的数据集—医疗成本

为了给回归分析的理论方面一些应用,我们将把我们的模型应用于一个真实的数据集:医疗费用个人。这个数据集来源于 Brett Lantz 的教科书:M achine Learning with R ,其中他的所有与教科书相关的数据集在以下许可下是免版税的:数据库内容许可(DbCL) v1.0

该数据集包含不同个人的 1338 份医疗记录,记录了一些指标:年龄、性别、bmi、孩子数量、是否吸烟以及他们居住的地区。目标是使用这些特征来预测个人的“费用”和医疗成本。

因为这已经是一篇很长的文章了,所以我不会详细讨论探索性的分析和预处理步骤;但是,下面列出了它们:

以下是有关如何加载数据集、将其拆分为特征和目标变量,以及将其划分为测试和训练集的代码:

我们将数据集分为训练和测试数据集的原因是,我们在训练集上训练我们的模型,并根据它对以前没有见过的新数据(测试集)的概括程度来评估它。此外,我还必须对我们的目标变量执行对数转换,因为它遵循严重偏斜的分布。在最小二乘的一些原理假设下,Y 需要服从正态分布,后面会解释。目前,通过 ra 对数BoxCox 变换,可以使严重偏斜的正态分布遵循正态分布。

如何衡量误差?

在机器学习社区中,对于衡量误差的最佳方式有很多研究和争论。对于回归来说,大多数误差测量来自于线性代数中的一个概念,称为范数。范数是允许人们测量张量/矩阵/向量有多大的度量。可以看出,如果这些范数衡量张量有多大,那么机器学习模型的目标就是最小化我们的预期输出和预测输出之间的范数差异!在数学格式中,x 的范数通常定义为:

其中 p 是改变测量值的参数。以下是一些最常见的 p 规范:

l 无穷范数

我们如何使用这些标准来帮助我们测量误差?我们可以用它们来衡量模型预测值 f(x)和实际目标变量 y 之间的差异。因此,我们可以用预测值和实际值之间的差异来衡量误差,这可以用一个标准的单个数值来量化:

我们如何定义错误

机器学习中最常见的两种误差测量是均方误差 (MSE)和平均绝对误差 (MAE):

在我们今天要研究的机器学习模型中,由于误差平方的凸性,MSE 被选择作为量化误差的度量,通俗地说,由于绝对运算的导数未定义,数值方法更容易最小化平方数而不是绝对值。

上述误差测量只存在一个问题,它们没有解释模型相对于目标值的表现如何,只解释了误差的大小。误差大是否意味着模型差?误差小就代表模型好吗?如果目标变量的变化很小,好的模型可以具有非常大的 MSE,而差的模型可以具有小的 MSE。例如,假设我们有两条不同的线用于两个不同的数据集。左侧数据集的预测具有比右侧数据集更低的 MSE,这是否意味着左侧的模型更好?我猜你会说右边的预测线比左边的好,尽管右边的数据集在 Y 变量中有更大的变化,所以有更高的 MSE。

仅使用 MSE 或 MAE 的问题是,它没有考虑目标变量的变化。如果目标变量有很多方差,如右边的数据集,那么 MSE 自然会更高。用于考虑目标变量变化的一个流行指标被称为*决定系数,*通常被称为 R 的平方:

从上面我们可以看到,R 的平方与残差平方和 (RSS)与总平方和 (TSS)的比值成正比。r 的平方范围从(-无穷大,1)。其中解释是被解释的目标变量变化的百分比。例如,假设一个模型的 R 平方值为 0.88 ,那么这个模型解释了目标变量大约 88%的可变性。因此,更大的 R 平方值是更可取的,因为模型将解释更大百分比的目标变量。然而,如果模型的 RSS 大于 TSS,那么 R 平方度量将是负的,这意味着模型的方差超过了目标的方差,也就是说模型很差。

最小二乘解

现在我们已经定义了我们的误差度量,是时候介绍我们的第一个经典机器学习模型了,最小二乘!与将要讨论的大多数模型一样,最小二乘法基于这样的假设,即因变量/目标变量特征变量的线性组合(假设 k 个特征):

系数的目标是作为相应输入变量的斜率,截距是作为输入变量为零时目标变量开始的点。根据上述强有力的假设,我们的目标是找到对系数的准确预测:

因为我们的β估计不精确,所以我们会有一个误差项,ε。这可以用矩阵格式写成如下:

其中 n 是实例/记录的数量

为了导出β的估计系数,有两个主要的推导过程。我两样都给。首先,使用简单的矩阵操作:

第二种推导是最常见的,通过使用梯度试图最小化差异的期望。在统计学中,期望值通常被定义为随机变量的加权平均值:

可以转换成矩阵格式:

然后,我们可以求出 J 的梯度,设它等于零,求β的解析解!

正如我们所看到的,这两种方法导致了相同的解决方案!事实上,他们是平等的!然而,如果你一直高度关注,我们已经做了三个大的假设:Y 是正态分布的;X^T*X 是可逆的;ε的期望值为零,方差不变。虽然这些假设在实践中有时会被打破,但最小二乘模型仍然表现良好!我希望现在你能理解为什么我们必须对我们的目标变量进行对数变换来达到正态性!

标准最小二乘法的时间复杂度是 O(k ),因为求矩阵的逆的时间复杂度是 O(n ),但是我们的矩阵结果,X^T*X 实际上是 k 乘 k,其中 k 是特征/列的数量。

现在我们已经讨论了最小二乘法的理论背景,让我们把它应用到我们的问题中!我们可以使用 sklearn 库中的 LinearRegression 对象来实现我们的最小二乘解!

为了评估我们的模型,我们可以查看测试和训练数据集的 MSE 和 R 值:

从上面左侧的柱状图中我们可以看出,测试集和训练集的 MSE 都非常低,只有 0.19 左右;然而,如果你记得的话,目标变量经历了对数变换,这意味着 0.016 的 MSE 对于目标变量的规模来说并不算小。因此,更好的测量方法是评估 R 值,我们可以从右侧的柱状图中看出,R 值还不错。我们的模型只解释了训练集的目标变量的大约 79%的可变性和测试集的大约 76%的可变性。尽管其结果在某些情况下是合理的,但对于这个简单的数据集,当模型在预测目标变量方面表现不佳时,这被称为欠拟合。我们将在后面介绍如何解决这个问题的一些方法。

模型的解释

与其他回归模型相比,线性回归的一大优势是它的简单性和解释能力。可以评估每个 beta 系数,以解释模型如何实现其预测。像这样的机器学习模型被称为白盒方法,这意味着模型如何实现其输出是显而易见的。另一方面,未知如何实现预测的公式过程的机器学习模型被称为黑盒方法

例如,下面是我们的贝塔系数值:

不幸的是,因为我们使用对数来缩放目标变量,所以系数值是在解释目标的对数方面。为了解决这个问题,我们可以通过对数的倒数,即指数运算来重新调整系数。这是我们的指数贝塔系数:

指数贝塔系数的解释是目标变量的百分比变化。例如,当一个人吸烟时,他的医疗费用增加了116.8%((*2.168–1) 100)另一方面,如果这个人不吸烟,那么他们的医疗费用将减少63.9%**((0.461–1)* 100)。实质上,任何大于 1 的β系数都会增加医疗费用的百分比,而任何小于 1 的β系数都会降低医疗费用的百分比。此外,我们可以明确地看到,最大的指数化β系数属于吸烟者,这意味着在其他变量中,该变量,即该人是否吸烟,对医疗费用的影响最大。

假设我们没有进行对数变换,那么我们如何解释贝塔系数呢?

这种解释是根据目标变量的单位尺度进行的。因为我们目标变量是以美元衡量的,我们可以看到,如果一个人是吸烟者,那么他的医疗费用将增加 11907 美元。如果他们不吸烟,则减少 11,907 美元。就年龄而言,我们可以看到,随着年龄的增长,他们的医疗费用每年会增加 264 美元。如果我们来看性别,系数是一样的,这意味着不管这个人是男是女,医疗费用都不会上升。希望你能看到解释最小二乘回归系数的力量。

加权最小二乘解

最小二乘法的一个主要假设是误差ε正态分布,方差恒定:

人们可以通过绘制残差 f(x)-y 与实际值的关系来检验这一假设,通常称为残差图。这是我们以前的模型在训练样本上的残差图:

正如我们从上面可以看到的,我们的残差的方差没有零均值,也没有恒定方差,因为它是高度非线性的。此外,我们可以看到,随着目标变量接近其最大值,残差平方呈现出略微上升的趋势。方差非常数的残差称为异方差。对抗异方差的一种方法是通过加权最小二乘法。加权最小二乘法类似于标准最小二乘法;但是,每个观察值都有其独特的权重。这样,权重较大的观测值比权重较小的观测值更容易被模型拟合。为了举例说明加权的威力,下面我们有两条预测线,一条未加权,一条未加权。正如我们从加权预测中看到的,权重较高的实例将具有更好的拟合,因为与权重较低的实例相比,模型将更倾向于固定这些点的预测线。

现在是推导加权最小二乘解的时候了。首先,我们希望最小化加权残差的期望值:

这可以转换成矩阵格式:

现在可以找到偏导数,并将其设置为零,以找到解析解:

正如我们从上面看到的,该解决方案与线性回归的解决方案非常相似,除了使用对角矩阵 W,包含每个实例的权重。

WLS 的主要功能之一是能够对不同的实例进行加权,以在模型中给出偏好,要么创建同方差,恒定方差,要么对某些记录进行更好的建模。然而,WLS 的一个主要缺点是如何确定权重。在我们的问题中,我们希望将残差固定为具有恒定方差。下面我描述了实践中发现的四种主要类型的残差方差。左上角展示了理想情况,其中方差是常数,平均值为零。右上角展示了残差方差如何随 y 增长,揭示了一个“扩音器型分布。左下方描绘了非线性残差,表明我们的模型缺乏创建关联的复杂性。最后,右下角展示了一个二项式残差方差。WLS 通常仅在发现二项式或扩音器型残差图时使用,因为非线性残差只能通过添加非线性特征来固定。

二项式残差和扩音器残差的常见解决方案是使权重等于残差的平方:

正如我们所看到的,这在直觉上是有意义的,我们根据实例的误差大小来加权实例。

在 sklearn 中,这很简单,只需创建另一个模型并添加额外的 weight_sample 参数:

如果您要测试上面的这些权重,残差图将看起来相似,并且具有相似的 R 和 MSE 分数,这是因为我们的残差方差是高度非线性的:

对于这种情况,我们只有一个解决方案,尝试添加非线性项以解释方差。我们将用核回归来讨论它,但首先我们需要讨论正则化。

如何处理过拟合—正则化

假设我们在一个给定的数据集上训练了一个线性回归模型,在它的应用和部署过程中,我们发现它的表现极差,尽管在训练数据上有很好的 MSE 和 R 分数;这被称为过拟合——当测试数据集的指标比训练数据集差得多时。举个例子:

从上面我们可以看到,我们有一个点的线性趋势;然而,如果我们要拟合 10 次多项式,我们可以在我们的训练数据集上将 MSE 和 R 人工最小化为零。尽管如此,我们可以直观地看到,当看到新数据时,模型将很难概括。正则化通过向损失函数添加惩罚项来工作,该惩罚项将惩罚模型的参数;在线性回归的例子中,β系数。

谈到线性回归,有两种主要的正则化类型:套索。首先,让我们从岭回归开始,通常称为 L2 正则化,因为它的惩罚项平方β系数以获得幅度。岭回归背后的思想是惩罚大的贝塔系数。岭回归试图最小化的损失函数如下:

从上面我们可以看到,损失函数和之前完全一样,只是现在增加了红色的惩罚项。参数 lambda 缩放惩罚。例如,如果λ= 0,那么在最小二乘法中,函数与之前相同;然而,随着λ变大,该模型将导致欠拟合,因为它将β系数的大小罚为零。让我们看下面一个简单的例子:

正如我们从上面看到的,当使用 20 次多项式模型来近似这些点并且 lambda=0 时,我们没有惩罚,并且在蓝线中表现出极端的过度拟合。当我们开始将 lambda 增加到 0.5 时,用橙色线表示,我们开始真正地模拟底层分布;然而,我们可以看到,当紫线中的 lambda=100 时,我们的模型开始变成一条直线,导致欠拟合,因为惩罚项迫使系数为零。在实践中选择 lambda 值要么在验证上执行,要么通过交叉验证执行。通过这种方式,我们在具有不同 lambda 值的训练数据集上重新训练我们的模型,并且选择在我们的验证集上表现最好的模型作为测试数据集的最终模型。

从数学上讲,我们的损失函数可以转化为矩阵形式:

其中,β可以像前面一样通过找到梯度并将其设置为零来求解:

现在我们已经讨论了岭回归背后的数学理论,让我们将它应用到我们的数据集。在实践中,为了获得良好的泛化误差,人们会希望在验证集而不是测试集上调整 lambda 值;但是,为了节省空间,我将在测试集上进行:

正如我们从上面看到的,随着我们增加我们的 lambda 值,我们在训练和测试集上的误差急剧增加;此外,测试集的最小误差似乎在λ= 0 左右。如果你没记错的话,我们的数据集不是因为过拟合而失败,而是因为欠拟合!所以用正则化是没有意义的,这也是为什么我们的测试误差越来越差而不是越来越好!我只是想展示如果你的模型显示过度拟合,如何使用岭回归!

下一个要介绍的正则化方法是套索,它通常被称为 L1 正则化,因为它的罚项是建立在β系数的绝对值上的:

请注意,岭正则化和套索正则化之间的唯一区别是,岭正则化是β系数的平方,而套索正则化是取绝对值。两者之间的主要区别在于,Ridge 会惩罚 beta 系数的大小,而 Lasso 会将某些 beta 系数值驱动为零,从而导致特征选择

这些类型的惩罚条款通常可以被重写为约束问题:

因为岭回归平方贝塔系数,绘制约束将导致一个圆;而套索会导致正方形。如果我们要绘制两个β系数(下图中称为 w1 和 w2)值的对比图,我们可能会得到以下结果:

由尼科瓜罗—自己的作品,CC 由 4.0,https://commons.wikimedia.org/w/index.php?curid=58258966

红线表示两个系数值可以取的值范围,随着 w1 的系数值增加,w2 的值开始减小。当我们绘制 L1 范数约束时:| w1 |+| w2 |≤λ,我们可以看到它用虚线方块表示。这个方框与红线相交的地方就是系数的选择值,我们可以看到,这会导致 w1 的值为零。另一方面,当我们画出我们的 L2 范数约束:w1+w2≤λ时,我们得到一个圆,如虚线圆所示。这个圆与红线相交的地方就是约束的选择值,我们可以看到 w1 和 w2 都是小的非零值。

不幸的是,由于绝对值运算的梯度未定义,使用矩阵计算很难找到 Lasso 正则化中β的解析解,因此经常使用类似坐标下降的数值方法。由于这些算法的复杂性质,我不会详述数学。在 python 中,套索回归可以按如下方式执行:

正如我们从上面可以看到的,随着我们增加我们的λ值,我们在训练和测试集上的误差急剧增加,最终在λ= 15 附近收敛。误差收敛的原因是因为我们的 lambda 值对于模型来说太大了,它将所有的 beta 系数逼为零。如果你没记错,我们的数据集不是因为过拟合而失败,而是因为欠拟合!所以用正则化是没有意义的,这也是为什么我们的测试误差越来越差而不是越来越好!我只是想展示如果你的模型过度拟合,你如何使用套索回归!

我要介绍的最后一个正则化技术是弹性网,它可以协调脊和套索,因为脊惩罚大的系数,而套索驱使系数为零。弹性网背后的想法是创建一个惩罚,既创建特征选择又最小化权重的大小。弹性网有许多不同的版本,下面是最常见的两种:

可以看到,惩罚项是脊和套索的组合,每个都有自己的 lambda 值来控制每个惩罚项对模型的影响程度。

如何处理欠拟合—核回归

我们已经讨论了当一个模型开始过拟合时该怎么办,但是当一个模型过拟合时该怎么办呢?到目前为止,在我们的示例数据集中,我们的模型已经显示出各种不适合的迹象:非线性残差和相对简单的数据集上的较差 R 值。处理欠拟合最常见的方法是利用一个内核。核是满足三个主要特性密度函数:

统计社区通常将内核回归称为非参数回归技术。使用核的前提是,如果我们将输入变量映射到一个更高的维度,那么问题可以很容易地被分类或预测。要了解这在实践中是如何工作的,最简单的例子是通过一个简单的分类问题。假设我们有两个组,我们希望只使用直线/超平面来分类。我们可以在下面看到,没有一条线能够将这两个组进行分类:

然而,如果我们将数据转移到一个更高的维度(正如我们在右手边看到的),现在存在一个能够对数据进行分类的超平面。

举一个回归的例子,假设我们只有一个特征变量 X,其中目标变量 Y 等于 X。我们可以在左下方的图片中看到,线性模型将无法准确地表示这些数据。然而,如果我们将特征变量 X 投影到一个更高的维度 X,那么我们可以看到我们的线性模型符合一条完美的直线。

我希望现在我已经让你相信了把我们的特征变量投射到更高维度的力量!然而,现在的问题是,我们如何做到这一点?首先,我们需要定义一个函数,通常表示为 phi,它将我们的变量映射到更高维的输入空间。在内核回归中,这是通过*内核函数来实现的。最流行和最基本的内核之一是多项式内核,*它简单地对特征变量进行幂运算。让我们举一个简单的例子,我们只有两个变量:x1 和 x2;然后,我们想通过简单地使用 2 次方的多项式核将它映射到一个更高维的空间:

正如我们从上面看到的,我们使用多项式幂为 2 的 phi 函数将原始数据 x1 和 x2 映射到一个更高的维度。唯一的问题是,现在我们的时间复杂度与我们的多项式 O(k^p).的幂成正比我们可以通过内核技巧来降低这种复杂性。首先,让我们使用 phi(x)重新计算我们的损失/误差指标。注意,核回归利用岭回归,因为系数往往非常大,这就是为什么这种方法通常被称为核岭回归:

我们可以看到β的推导实际上是递归的,这意味着最优β是它自身的函数。然而,如果我们将这个 beta 值代入我们的误差指标,我们会得到:

如图所示,当我们用新的β值降低损失函数时,我们得到 phi(x_i)*phi(x_j),其中 phi(x)是 O(k^p 运算,这使得该过程非常耗时。然而,的诀窍,在于

为了给出一个具体的例子,让我们将它应用于我们之前的核函数,一个二次多项式:

正如我们从上面看到的,内核技巧是这样的事实:两个数据点的点积转换为高维映射与两点间点积的高维映射相同!这样节省了大量的时间和计算资源!现在,我们可以将它转换回损失函数,得到:

从上面我们可以看到,损失函数的格式与最小二乘法非常相似,只是其中 K=X,alpha=beta。为了找到最优β,我们首先找到α的最优解,然后把它代入β!

标准最小二乘法的时间复杂度是 O(k ),但是现在我们的矩阵结果是一个 n 乘 n 矩阵,因为 K 是 n 乘 n;因此,核回归的时间复杂度为 O(n),在数据量很大的情况下,计算量非常大!一种常见的解决方案是简单地从整个数据集中采样数据,使得 n 很小。

内核回归需要调整的另一个超参数是选择使用哪个内核函数。最常见的三种如下:

正如我们从上面所看到的,每个内核函数都有自己的一组超参数需要优化,这增加了复杂性。

既然我们已经讨论了理论背景,让我们将核岭回归应用于我们的问题!对于这个例子,我将只展示多项式核,因为它是最常见的。因为 Kernel Ridge 也有一个 lambda/penalty 项,所以我将展示增加罚项对测试数据集的影响。请注意,在实践中,您可能希望在验证集上这样做,而不是在测试集上。

从上面的图中我们可以看出,增加λ的惩罚项实际上降低了测试和训练误差的 R 值;然而,在实践中可能不是这样,所以总是测试不同的正则化值。然而,我们可以立即看到,使用核回归将测试数据集上的 R 从 0.76 增加到 0.83,这意味着我们的模型现在可以解释目标变量约 83%的可变性,略好于 76%。现在,让我们检查训练数据集上的残差图,并与标准线性回归进行比较:

正如我们从上面看到的,我们的核脊残差图(在右手边)明确地将残差的方差均衡为 7 到 9 之间的 Y 值的常数;然而,Y 值在 9 和 10.5 之间的极大残差仍然存在;表明我们的模型对其中的一些点拟合不足。

核回归的一个缺点是失去了模型的可解释性,因为现在β系数不是针对特征变量而是针对数据观察值,因为新数据的预测由下式给出:

正如我们所看到的,对于一个新的预测,我们从新数据和β被训练的数据之间的点积形成一个新的核矩阵 K,乘以保存系数的α向量。由于这种高维映射,模型如何从简单的特征变量获得其结果的可解释性丧失,使得核回归成为一种黑盒方法

然而,你可能会想,如果核回归是一种黑盒方法,因为到更高维度的投影被总结为数据实例之间的一个值,那么我们为什么不手动投影我们的特征空间呢?例如,假设我们有以下具有三个变量的特征空间,并将其投影到二次多项式:

现在,我们已经将初始数据维度投影到一个更高的维度,允许我们执行岭回归来获得白盒贝塔系数!然而,问题是我们在最小二乘推导中假设(X^T*X)是可逆的,这假设 x 是线性独立的,这意味着没有一列是另一列的组合;但是我们可以清楚地看到,我们新投影的数据是原始数据维度的线性组合!这样,我们增加的高维项越多,逆就越有可能不存在。内核回归避免了这个问题,因为它在数据实例之间投影点积,这里我们假设数据实例是独立采样的。

支持向量机

对于我们深入回归分析的最后一个方法,我们将看看核岭回归的一个密切对应的支持向量机(SVMs)。为了给出支持向量机背后的基本直觉,让我们切换到分类的目标,其中我们想要找到一个决策边界来分类两个组,并且我们有三个可能的模型:

问题是三个决策边界都对所有点进行了正确的分类,所以现在的问题是哪一个更好?理想的模型应该是红线,因为它不太靠近 1 级或 2 级。SVM 通过增加一个关于决策边界的余量来解决这个问题,通常称为支持向量:

通过添加这些支持向量,我们的模型能够“感觉”出数据,以找到一个决策边界,该边界可以最小化这些支持向量范围内的误差。SVM 有两种类型,软边际硬边际。硬边界使模型找到决策边界,使得没有数据实例在支持向量边界内;而软边距允许实例在边距内。硬边界仅适用于可线性分类的数据,对异常值极其敏感,因此软边界是最常见的 SVM 类型。

这些支持向量的宽度,即余量,通常表示为ε。支持向量回归的误差函数类似于最小二乘法的误差函数,因为它假设目标变量是特征变量的线性组合:

然而,损失/误差函数的构造与之前不同,因为我们想要最小化β,以确保的平坦度,这意味着我们想要小的β系数,以便没有特征变量系数变得太大,导致过度拟合。此外,我们还希望最小化残差,使其小于裕度宽度,记为ε:

然而,问题是,对于给定的ε,可能不存在满足该条件的模型(硬裕度,导致使用松弛变量的替代函数(称为软裕度):

不幸的是,用来解决这个问题的数学不再像找到一个导数并设置它等于零那么简单,而是涉及到二次规划。由于这种复杂性,我将跳过数学来寻找最终的解决方案。

因为 SVM 利用了数据矩阵 X,所以可以通过核函数利用非线性映射来实现非线性回归平面。我将跳过这背后的数学,因为它变得混乱和复杂;然而,这个想法和上面提到的内核脊是一样的。好的一面是内核技巧在这里仍然适用,从而节省了时间和计算。既然我们已经讨论了 SVM 理论的一面,让我们把它应用到我们的问题中吧!

与核岭回归一样,有许多可能核函数可供使用,这次我将测试其中的三种:多项式、RBF 和线性。此外,SVM 还需要两个更重要的超参数,C 和ε。ε是余量宽度,C 是正则化项。在实践中,只有正则化项 C 被改变,因为改变边缘宽度将会极大地导致差的结果。这里我们有三个内核,在测试集上评估了不同 C 值下的默认参数。

正如我们所看到的,对于这个特定的数据集,通过增加 C 值,几乎所有三个内核都增加了测试集的 R 值。我们可以看到,RBF 内核的性能最好,因此让我们更深入地检查一下它在 C=100 时的结果:

正如我们所见,我们在测试数据集上的 R 优于最小二乘法,解释了目标变量 81%的可变性,但不如具有多项式核的核岭回归好。但是,请注意,这在实践中可能并不总是发生。人们可以检查这个模型的残差图,但它与之前的非常相似,因为 R 非常相似。

不幸的是,与核岭回归一样,因为支持向量机是基于核而不是特征变量找到它们的系数的,所以对模型如何实现其预测的解释丢失了,这使得 SVM 成为一种黑盒方法。

结论

如果你已经走到这一步,恭喜你!我希望你已经在数据科学和机器学习领域学到了很多关于回归的知识!

作为快速回顾,我们介绍了我们的第一个模型,最小二乘,它简单地假设目标变量是特征变量的线性组合,目标是找到这些系数。出现的问题是最小二乘法是建立在一些假设上的,即误差具有恒定的方差和零均值。然而,在实践中,这经常被违反,因为通过评估残差图,可以观察到残差的非线性。假设残差遵循特定趋势,如二项式或扩音器,加权最小二乘法可用于创建满足这些假设的模型。最小二乘法及其衍生物的众多优点之一是其开放的白盒性质,这意味着模型预测可以通过特征变量的系数直接观察到。

在我们的模型训练误差低但测试误差高的情况下,我们需要包含正则化以防止过度拟合。我们讨论了三种最常见的正规化类型:套索弹性网。岭正则化缩小了系数的值,而 Lasso 将一些系数驱动到零,而弹性网寻求协调这两者。

另一方面,我们的模型没有过度拟合,而是欠拟合,训练和测试误差都很高。为了解决这个问题,我们使用核函数将我们的特征空间投影到更高维度,希望预测平面能够拟合数据。这是通过两种方法执行的— 核岭回归支持向量机。两者之间的区别是误差/损失函数的公式,其中 SVM 的包括一个误差幅度,以尽量减少。然而,这些高维映射模型的问题是,模型如何根据特征变量实现其预测的解释丢失了,使它们都成为黑盒方法。

实际上,没有可以利用的最佳模型。如果你想向没有机器学习背景的商人展示你的模型,那么使用 LR 或 WLR 来解释不同特征的重要性将是有益的,因为它们都是白盒方法,然后报告黑盒方法的分数,因为它们往往表现得更好。

总而言之,我希望你已经从上面讨论的主题中学到了很多,无论是理论上还是应用上!

数据科学 Spark 和 PySpark 设置完整指南

原文:https://towardsdatascience.com/complete-guide-to-spark-and-pyspark-setup-for-data-science-374ecd8d1eea?source=collection_archive---------9-----------------------

完成关于如何为数据科学设置 Spark 的 A-Z,包括通过 PySparkSparkScalaPython 一起使用,以及与 Jupyter 笔记本 s 集成

照片由 Rakicevic Nenad 从 Pexels 拍摄

介绍

Apache Spark 是一个用于大数据处理的统一分析引擎,内置了用于流、SQL、机器学习和图形处理的模块。它正迅速成为数据科学家调查大数据的事实上的工具。

与大多数数据科学家类似,Python 一直是我的首选编程语言,从通过 Scrapy 和 Selenium 等网络抓取工具收集数据,到与熊猫的数据争论,以及使用 Pytorch 和 Tensorflow 等 Python 中所有优秀的库进行机器学习/深度学习。

然而,数据每天都在迅速变得越来越大,预计这种增长在未来几年将会加速,特别是随着社交媒体和互联网在全球范围内的使用不断扩大。

当处理大文件并试图对这些文件进行操作时,Python 开始遇到困难。我知道有一些可行的解决方案,比如 Dask,它是 Python 的并行计算库,但是在使用 Spark 之后,我觉得它是最好的解决方案,原因如下:

  1. 速度 — Spark 具有 Catalyst Optimizer 等特性,它使用过滤和索引等技术来确保 SQL 类型查询等任务以最高效的顺序执行。
  2. 社区支持 — Spark 在全球拥有庞大的追随者,并且发展迅速,不断增加更多的工具和功能。
  3. MLflow — Spark 与 MLflow 集成,MLflow 是一款出色的开源 MLOps 工具,用于管理从初始调查和模型参数记录到在生产中存储和部署模型的机器学习生命周期。
  4. 我真的很喜欢 Databricks,它是一个在云上使用 Python 和 Spark 的平台。他们的笔记本电脑环境非常适合团队协作,从 MLOps 的角度来看,他们的托管 MLflow 添加确实有助于更快、更高效地将数据科学模型投入生产。

我希望您现在急于加入 Spark,将这个优秀的大数据工具添加到您的武器库中。下面我列出了先决条件,然后一步一步地介绍如何安装 Spark 和 PySpark。

Spark 的最佳语言:Scala Vs Python

照片由像素的像素拍摄

Spark 使用 Scala 作为默认编程语言。然而,使用 PySpark,我们也可以通过 Python 使用 Spark。使用 Spark 和 Scala 的主要好处是性能效率,特别是在流方面,Spark/Scala 比 Python 发达得多。然而,与你很可能已经非常熟悉的 Python 相比,你必须考虑学习一门新语言(比如 Scala)的时间成本。

我认为 Python 是一种很好的基础语言,可以通过包和库(如 PySpark)来添加功能,我个人采用的方法是将 Python 作为我的主要语言,并通过 PySpark(在这种情况下)或 PyJulia(在 Julia 语言的情况下)导入额外的功能。我知道这导致了一些效率的损失,但我觉得我可以在 python 脚本中包含我的整个数据科学项目这一事实在尝试在复杂的管道中生产我的模型时有很大的帮助,在复杂的管道中增加多种语言之间的额外复杂性可能是一件令人头痛的事情。

不过,我在下面展示了两种方法,从 Spark/Scala 安装开始,到 PySpark 结束,这样您就可以选择在涉及 Spark 的数据科学项目中更喜欢哪种方法。

两种方法的先决条件

我假设您使用的是 Linux 发行版,无论是在专用的 Linux 机器上还是通过 WSL 或 VirtualBox,只要您使用的是 Linux 环境,这都无关紧要。此外,您应该已经安装了 Jupyter,并在您的本地机器上进行编码等工作。

Scala 设置的火花

关于兼容版本的重要说明

scala、spark、hadoop 和 sbt 的版本兼容至关重要。每一个的最新版本不一定能一起工作。我目前的设置使用下面的版本,它们都可以很好地配合使用。

spark=2.4.4
scala=2.13.1
hadoop=2.7
sbt=1.3.5

步骤 1:安装 Java

如果你在你的终端中输入which java,这会告诉你你的 Java 安装存储在哪里,如果你已经安装了的话。如果你没有安装它,它不会返回任何东西。

如果你想检查你正在使用的某个东西的版本,比如 Python 等,这个" which" 命令通常是很好的选择。

值得注意的是,Java 是一个有些独特的安装,如果您键入which java并且它已经安装好了,您应该会得到如下所示的内容:

/usr/bin/java

然而,这是一个指向/etc/alternatives/java的符号链接,如下所示。

符号链接总是有一个箭头指向它们所象征的位置,如下图所示。

作者图片

这个/etc/alternatives/java是另一个符号链接,它反过来指向/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java,这是用于运行 Java 的实际文件。这种结构对于 Java 的运行方式是必要的,但是当试图强制将某个版本作为默认版本时要小心。

我们需要 Java 版本 8 来正确地与 Spark 一起工作,因此如果你已经有了错误的版本,比如版本 11,那么卸载并重新安装,在你的终端中运行下面的代码行。
sudo apt-get remove openjdk*
sudo apt-get install openjdk-8-jdk
sudo apt-get install openjdk-8-jre

接下来安装 java 只需运行下面一行:
sudo apt-get install openjdk-8-jdk

您现在可以通过运行
update-java-alternatives --list来检查您的 Linux 系统上当前所有的 Java 版本

要将您想要的 java 版本设置为默认版本,在本例中是版本 8,然后运行下面需要 root 权限的命令:
sudo update-java-alternatives --set /path/to/java/version8

最后加上下面一行。bashrc/。zshrc 视情况而定。
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

现在,您应该已经在系统上成功安装了 Java 8,我们现在可以开始安装 Spark 了。

火花

从下面的链接下载 Spark 安装文件。https://spark.apache.org/downloads.html

然后通过运行
提取:tar xvf spark-1.3.1-bin-hadoop2.6.tgz

接下来将这个文件移动到/usr/local/spark
mv spark-1.3.1-bin-hadoop2.6 /usr/local/spark

最后加上下面几行。巴沙尔或者。zshrc 取决于您运行的是什么 shell。这只是意味着当你启动未来的终端时,它会自动将下面的火花路径添加到路径变量中,以便可以使用。
export PATH=$PATH:/usr/local/spark/bin
export SPARK_HOME=/usr/local/spark

请记住,如果不使用下面的命令,当前的终端将不会更新。因此,您可以运行这个命令,当前的 shell 将更新或打开一个新的终端,它将自动使用新的设置。

source ~/.zshrc

Hadoop

从下面的链接下载二进制文件:https://hadoop.apache.org/releases.html

解压文件

tar xzvf hadoop-3.2.1.tar.gz

将提取的文件移动到您想要存储 Hadoop 安装的位置。我建议创建一个名为 hadoop 的通用文件夹,并将下载的文件移动到其中,而不是名为 hadoop_version_xx 的文件夹,因为这意味着一旦我们设置了 PATH 等,以后如果我们更改为新版本的 hadoop,通用 Hadoop 文件夹的路径将保持不变。(这通常是安装这样的库的好方法,你可以在将来更新版本号,但不需要更新路径变量等)
mv hadoop-3.2.1/* ~/FILE_PATH_EXAMPLE/spark_scala/software/hadoop/

在 bash 文件中添加 Hadoop 和 Java 路径。bashrc/。zshrc 以类似于我们在路径中添加 Spark 的方式,在。bashrc/。zshrc 文件。

export HADOOP_HOME=~/FILE_PATH_TO_HADOOP/hadoop
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:~/FILE_PATH_TO_HADOOP/hadoop/share/hadoop/common/lib
export HADOOP_CONF_DIR=~/FILE_PATH_TO_HADOOP/hadoop/etc/hadoop
export HADOOP_MAPRED_HOME=~/FILE_PATH_TO_HADOOP/hadoop
export HADOOP_COMMON_HOME=~/FILE_PATH_TO_HADOOP/hadoop
export HADOOP_HDFS_HOME=~/FILE_PATH_TO_HADOOP/hadoop
export YARN_HOME=~/FILE_PATH_TO_HADOOP/hadoop
export PATH=$PATH:~/FILE_PATH_TO_HADOOP/hadoop/bin

斯卡拉

要安装 scala,只需使用 wget 获取它,然后使用 dpkg 包管理器解包,如下所示。

sudo wget www.scala-lang.org/files/archive/scala-2.13.1.deb
sudo dpkg -i scala-2.13.1.deb

注意,当我尝试使用 apt 包管理器时,我在使用 scala 时看不到终端中的命令,所以我使用 dpkg 包管理器,如下所示

如果你已经通过 apt 安装了,并且在终端中启动 scala 后出现了同样的命令不可见的错误,那么为了解决这个问题,请完全删除 scala,并使用 dpkg 安装它(不要使用 apt):
sudo apt-get remove scala-library scala
sudo wget www.scala-lang.org/files/archive/scala-2.13.1.deb
sudo dpkg -i scala-2.13.1.deb

SBT

只需运行下面的命令来安装简单的构建工具【SBT】
sudo apt-get update
sudo apt-get install sbt

如果使用上述命令从回购中获取 SBT 有困难,那么只需从网站https://www.scala-sbt.org/download.html手动下载,并按如下方式提取:

tar xvf sbt-1.3.5.tgz

mv sbt /usr/share/sbt

最后添加下面一行。bashrc/。zshrc 视情况:
Export PATH=$PATH:/usr/local/sbt/bin

检查安装

首先确保。bashrc/。zshrc 通过运行下面的命令来使用我们最新的更新。(或者,您可以简单地退出当前终端,打开一个新的终端,它将自动使用最新的终端。bashrc/。zshrc 文件。)

Command source ~/.bashrc

检查 Java 的安装

您可以通过运行java -version进行检查,这应该会返回以下结果:
openjdk version "1.8.0_212"

检查 Hadoop 的安装

你可以通过运行hadoop version来检查(注意这次-版本前没有)。这将返回您正在使用的 hadoop 版本,如下所示:
hadoop 2.7.3

检查火花的安装

  1. cd 到 apache-spark 的安装目录,然后使用ls命令列出所有文件/目录。
  2. 寻找一个我们可以使用的文本文件,比如 README.md 或 CHANGES.txt
  3. 在终端中输入 spark-shell,spark 应该会在 scala 提示符下启动,如下所示:

作者图片

作为测试命令,输入下面一行,用您选择的任何文本文件替换 README.md。

val rdd = sc.textFile("README.md")

接下来输入rdd.count(),它将返回文件中的行数,如下所示。

作者图片

恭喜你现在可以在 Scala 中使用 Spark-Shell 了!我们现在将继续安装 PySpark,这将使我们能够在 Python 环境中使用 Spark,如 Jupyter 笔记本上的 Python 内核等。

照片由 Nina Uhlíková 从 Pexels 拍摄

Python 设置的 spark(PySpark)

注意 PySpark 目前与 Python 3.8 不兼容,因此为了确保它能够正常工作,我们安装了 Python 3.7,并使用该版本的 Python 创建了一个虚拟环境,我们将在其中运行 PySpark。

要在 Linux 系统上安装 Python 3.7 作为 Python 的附加版本,只需运行:

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa

请注意,要在系统上将软件包安装到这个特定版本的 python 中,请确保将 python 版本指定为 pip 命令的一部分,例如/usr/bin/python3.7 -m pip install pandas

作者图片

接下来创建一个名为 pyspark_env 的新虚拟环境,并让它使用这个新安装的 Python3.7 版本:

mkvirtualenv -p /usr/bin/python3.7 pyspark_env

(请注意,我使用virtualenvwrapper来创建我的 python 虚拟环境,并强烈推荐它作为保持您的虚拟环境良好维护的好方法。更多详情请看此链接https://virtualenvwrapper.readthedocs.io/en/latest/)

在创建新的虚拟环境时,它应该会自动激活它,你应该会在你的提示符下看到它的名字,如下所示。

作者图片

如果它没有自动激活,那么只需使用下面的命令来激活环境(这是另一个方便的命令,是我前面提到的 virtualenv 包装库的一部分)。

workon pyspark_env

现在,在新的虚拟环境中,我们可以通过以下命令简单地安装 PySpark:

pip install pyspark

最后添加下面一行。bashrc/。zshrc 视情况而定:

export PYTHONPATH=$SPARK_HOME/python:$PYTHONPATH

现在,如果你简单地在你的终端中输入 pyspark,你应该启动 spark,就像我们之前在 Scala 中做的那样,只是这次你不会得到 Scala 的提示,而是可以像平常一样使用 Python,并且拥有 PySpark 功能。

作者图片

例如,如果您已经将 pandas 安装到我们之前安装的 Python3.7 中,您可以导入 pandas 并创建数据帧,如下所示:

作者图片

PySpark 和 Jupyter

最后一步是在 Jupyter 中启用 PySpark。为此,首先要确保 pyspark_env 环境处于活动状态。然后安装 ipykernel,如果你还没有像下面这样安装它。(需要注意的是,我们不需要指定 pip3 等,因为我们在活动环境 pyspark_env 中,它会自动将包安装到该环境使用的 python 版本中。

ipip install ipykernel

接下来,通过以下方式将虚拟环境添加到 Jupyter:

ipython -m ipykernel install --user --name=pyspark_env

如果您现在启动 Jupyter,您应该会看到 pyspark_env 列在右边的内核中,如下所示:

作者图片

在新笔记本中,作为一个简单的测试,尝试制作一个 PySpark 数据框架。首先从 pyspark.sql 导入 SparkSession,如下所示:

作者图片

接下来构建一个标准的 Spark 会话,如下所示:

作者图片

最后,创建一个简单的 PySpark 数据框架,以确保其正常工作:

作者图片

您也可以在这些单元格中编写标准的 python 代码,下面的示例将 Python F 字符串添加到我们创建 PySpark 数据帧的同一个单元格中。

作者图片

成功!!您现在可以在同一个 Jupyter 笔记本中编写 python 和 PySpark 代码了!

来自 Pexels 的 Andrea Piacquadio 的照片

摘要

总之,我已经给出了如何安装 SparkScala 的详细说明,使你能够在你的终端上使用 spark-shell。我还演示了如何使用定制的 python3.7 虚拟环境安装 PySpark ,以确保没有兼容性问题,这使您能够使用 PySpark 命令在您的终端中打开一个 PySpark 会话。最后,我展示了如何将 PySpark 功能添加到您的 jupyter 笔记本中,您现在可以在相同的单元中编写 python 和 PySpark 代码,并根据需要使用这两种语言。

我希望您喜欢阅读我的指南,并且您已经准备好在未来的数据科学项目中探索 SparkPySpark

照片由 Pixabay 从像素拍摄

理解 Node2Vec 算法的完整指南

原文:https://towardsdatascience.com/complete-guide-to-understanding-node2vec-algorithm-4e9a35e5d147?source=collection_archive---------2-----------------------

理解 node2vec 算法及其超参数的深入指南

机器学习已经成为我们日常生活中的一个重要工具。几乎没有一天你不使用任何一种以这样或那样的方式使用机器学习的应用程序。如果您有一些训练机器学习模型的经验,您可能会习惯于以表的形式存储底层训练数据。然而,我们生活在一个世界比以往任何时候都更加相互联系的时代。不仅世界是相连的,我们收集的数据也越来越相关。以表格形式存储数据的缺点是可能会忽略应用程序中可能相关且可预测的关系。这就是图形存储的用武之地。根据设计,在构建图表时,您需要考虑数据点之间可能的联系。

漫威字符网络的可视化。图片由作者提供。

图由节点及其关系组成。这种简单但非常有效的数据存储方式允许您对几乎任何真实场景进行建模。网络是互联网、交通、社交平台等的核心。图表可以表示蛋白质相互作用、化学键、道路网络、社会网络和许多其他东西。这和机器学习有什么关系?近年来,人们对提取网络结构并将其应用于机器学习领域进行了大量的研究。例如,来自 DeepMind、谷歌大脑、麻省理工学院和爱丁堡大学的研究人员在他们的研究论文中认为,图形网络可以支持两种关键能力,这是人工智能实现类似人类能力的首要任务:

  • 关系推理:解释不同实体之间的关系,如图像像素、单词、蛋白质或其他
  • 组合归纳:从已知的构建模块中构建新的推论、预测和行为。

机器学习模型的典型输入是表示每个数据点的向量。将关系和网络结构转化为一组向量的过程称为节点嵌入。节点嵌入算法旨在将每个节点编码到嵌入空间中,同时保留网络结构信息。对实体关系进行编码允许您捕获每个数据点的上下文,而不仅仅关注其属性。而且我们都知道语境才是王道!

图形嵌入——网络上的表征学习,snap.stanford.edu/proj/embeddings-www

您可能已经在更经典的 ML 设置中处理过图形。任何图像都可以表示为网格图。

任何图像都可以表示为网格图。图片由作者提供。

在图像处理和分类中,经常使用卷积神经网络。但是卷积到底是什么呢?我喜欢 Prasad Samarakoon 博士的这句话:

卷积可以被认为是“观察一个函数的周围环境以更好/更准确地预测其结果”。

本质上,卷积检查像素之间的关系,以捕捉图像更深层次的上下文含义。同样,您可以将任何文本表示为图形。

任何文本都可以表示为线图。图片由作者提供。

如果你曾经处理过单词嵌入,你知道你可以通过检查它的环境来捕捉单词的意思和功能。节点嵌入算法试图概括单词和图像嵌入在任何图结构上做什么。现实世界的网络没有预定义的结构,可以有各种形状和大小。然后,节点嵌入算法的输出可以用作下游机器学习模型的输入。比如 node2vec 就是一个节点嵌入算法。在这篇博文中,我将尝试介绍 node2vec 算法是如何实现的。

Word2vec 跳格模型

node2vec 算法很大程度上受 word2vec 跳格模型的启发。因此,要正确理解 node2vec,首先必须了解 word2vec 算法是如何工作的。Word2Vec 是一个浅层的两层神经网络,用于重建单词的语言上下文。word2vec 模型的目标是在给定文本语料库的情况下产生单词表示(向量)。单词表示被放置在嵌入空间中,使得在文本语料库中共享共同上下文的单词在嵌入空间中彼此靠近。在 word2vec 的上下文中使用了两种主要的模型。

  • 连续词袋
  • 跳格模型

Node2vec 受 skip-gram 模型的启发,所以我们将跳过 CBOW 实现的解释。跳格模型预测给定单词的上下文。上下文被定义为输入术语的相邻单词。

上下文窗口。图片由作者提供。

用蓝色突出显示的单词是输入术语。在这个例子中,上下文窗口大小是五。窗口大小被定义为以输入单词为中心的上下文窗口中单词之间的最大距离。实际上,标准似乎是使用与输入单词的窗口大小的一半相邻的上下文单词。正如您在图中的第一个示例中看到的,我们仅使用以下两个词作为上下文,尽管上下文大小为五。

跳格模型。图片来自https://lilian Weng . github . io/lil-log/2017/10/15/learning-word-embedding . html。经作者许可后发布。

在此图中,展示了 skip-gram 神经网络的体系结构。在训练这个神经网络时,输入是表示输入单词的独热编码向量,输出也是表示上下文单词的独热编码向量。还记得上一张图中我们是如何构建单词的输入和上下文对的吗?Word2vec 使用了一个技巧,我们对神经网络的输出向量不感兴趣,而是目标是学习隐藏层的权重。隐藏层的权重实际上就是我们要学习的单词嵌入。隐藏层中神经元的数量将决定嵌入维度或代表词汇表中每个单词的向量的大小。

注意,神经网络不考虑上下文单词的偏移,因此它不区分与输入直接相邻的上下文单词和那些在上下文窗口中更远的上下文单词,或者即使上下文单词在输入项之前或之后。因此,窗口大小参数对单词嵌入的结果有很大的影响。例如,Levy & Goldberg 的一项研究基于依存关系的单词嵌入发现,更大的上下文窗口大小倾向于捕捉更多的主题/领域信息。相反,较小的窗口倾向于捕捉关于单词本身的更多信息,例如,还有哪些单词在功能上相似。

负采样和子采样

word2vec skip-gram 模型的作者后来发布了一个单词和短语及其组合性的分布式表示,它对原始模型进行了两项优化。第一个优化是常用词的子采样。在任何文本语料库中,最常见的术语很可能是所谓的停用词,如“the”、“at”、“In”。虽然 skip-gram 模型受益于像“德国”和“柏林”这样的单词的共现,但是“德国”和“the”的频繁共现的好处要小得多,因为几乎每个单词都伴随着“the”术语。作者实现了二次采样技术来解决这个问题。对于训练语料库中的每个单词,我们都有可能忽略该单词在文本中的特定实例。从句子中删除该单词的概率与该单词的频率有关。该研究论文表明,在训练期间对频繁单词进行二次采样可以显著提高速度,并改善不太频繁的单词的表示。

第二个优化是引入了负采样。训练神经网络包括获取训练样本并调整所有神经元权重,以更精确地预测该训练样本。通俗地说,每个训练样本都会调整神经网络中的所有权重。一项名为 Test Your Vocab 的研究显示,大多数以英语为母语的成年人的词汇量在 20,000 到 35,000 个单词之间,你可以拥有数百万甚至数十亿个输入语境训练对。为每个输入上下文训练对更新几千个权重是非常昂贵的。负采样通过让每个训练样本只修改权重的一小部分而不是全部来解决这个性能问题。对于负采样,“负”单词是我们希望神经网络输出 0 的单词,这意味着它不在我们输入项的上下文中。我们仍然会更新“正面”上下文单词的权重。实验表明,范围在 5-20 的负样本数对于小的训练数据集是有用的。对于较大的数据集,反面例子的数量可以少至 2-5 个。例如,我们只更新五个负权重和一个正权重,而不是更新每个训练样本的所有神经元权重。这将对模型训练时间产生重大影响。该论文表明,使用提升到 3/4rd 幂的一元分布选择负样本明显优于其他选择。在一元分布中,更频繁的词更有可能被选为负样本。

我发现了这个关于学习 Word2Vec 的极好的考虑,它深入研究了 Word2Vec 超参数优化。你已经发现了上下文窗口大小、嵌入维数和负样本的含义,但是作者也观察了神经网络学习速率对嵌入结果的影响。

Node2vec

Node2vec 算法使用负采样跳过图(SGNS)。但是我们如何创建一个文本语料库作为 SGNS 的输入呢?Node2vec 使用随机游走从给定的网络中生成一个“句子”语料库。

图片来源:https://prakhartechviz . blogspot . com/2019/09/random-walk-term-weighting-for-text . html

随机行走可以被解释为一个喝醉的人穿过图表。当然,你永远无法确定一个喝醉的人的下一步,但有一点是肯定的。一个喝醉的人只能跳到一个相邻的节点上。

根据随机漫步来造句。图片由作者提供。

想象一下,如果你从节点 a 开始遍历图,你随机选择一个相邻的节点并跳到它上面。然后重复这个过程,直到预定的行走长度。行走长度参数定义了“句子”的长度。对于图中的每个节点,node2vec 算法生成一系列随机遍历,将特定节点作为起始节点。您可以使用每节点的步数参数定义从特定节点开始的随机步数。总而言之,node2vec 算法使用随机行走从图中的每个节点开始生成许多句子。步长参数控制句子的长度。一旦使用随机行走生成句子,该算法将它们输入到 SGNS 模型中,并检索隐藏层权重作为节点嵌入。这就是 node2vec 算法的全部要点。

但是,node2vec 算法实现了二阶有偏随机游走。一阶随机漫步中的一步仅取决于其当前状态。

一阶随机漫步

一阶随机漫步。图片由作者提供。

假设您不知何故到达了节点 a。因为一阶随机漫步只查看其当前状态,所以算法不知道它在前面的步骤中是哪个节点。因此,返回到前一个节点或任何其他节点的概率是相等的。概率的计算背后并没有什么高深的数学概念。节点 A 有四个邻居,所以遍历到其中任何一个的几率是 25% (1/4)。

假设您的图是加权的,这意味着每个关系都有一个属性来存储其权重。在这种情况下,这些权重将包括在遍历概率的计算中。

加权图上的一阶随机游动。图片由作者提供。

在加权图中,遍历特定连接的机会是其权重除以所有相邻权重之和。例如,从节点 A 遍历到节点 E 的概率是 2 除以 8 (25%),从节点 A 遍历到节点 D 的概率是 37.5%。

二阶有偏随机游动

二阶遍历将当前状态和先前状态都考虑在内。简而言之,当算法计算遍历概率时,它还会考虑前一步的位置。

二阶有偏随机游动。图片由作者提供。

在上一步中,该遍历刚刚从节点 E 遍历到节点 A,现在正在评估其下一步。回溯遍历并立即重新访问遍历中的节点的可能性由 return 参数 p 控制。将参数 p 设置为高值可确保重新访问节点的机会较低,并避免采样中的 2 跳冗余。这种策略也鼓励适度的图形探索。另一方面,如果 p 参数的值较低,则遍历中回溯的机会较高,从而使随机遍历更接近起始节点。

inOut 参数 q 允许遍历计算区分向内和向外的节点。将参数 q (q > 1)设置为高值会使随机游走偏向靠近上一步中的节点的节点。回到上一张图片,如果您为参数 q 设置了一个较高的值,则从节点 A 开始的随机行走偏向于更靠近节点 e 的节点。这种行走在行走和近似广度优先搜索中获得了基础图相对于起始节点的局部视图。相反,如果 q 的值较低(q < 1),walk 更倾向于访问离节点 e 更远的节点。这种策略鼓励向外探索,并近似于深度优先搜索。

同向性与结构等价

二阶有偏随机游走中 return 和 inOut 参数的各种配置在节点之间产生不同的相似性。具体来说,您可以调整 node2vec,使其遵循同质性相似性**。**在这种情况下,同向性被定义为属于相同网络社区的节点(即,在网络中彼此更接近)。通过设置较小的 q 值可以实现同向搜索。较小的 q 值近似于深度优先搜索。

另一方面,您可以通过设置更高的 q 值来鼓励更多的结构等价相似性。结构等价是指两个节点连接到相同节点的程度,即它们共享相同的邻域,而不要求这两个节点直接连接。乍一看不太直观的是,结构等价节点也会正则等价。常规等价被定义为与其他节点具有相似连接模式的节点。一个例子是网络中的桥接节点。有关结构和规则等价的更多信息,请阅读 graphs 论文中的社区检测。

node2vec:网络的可扩展特征学习。a .格罗弗 j .莱斯科维奇。 ACM SIGKDD 知识发现与数据挖掘国际会议(KDD) ,2016。

对这个数字最好的解释是作者自己的话:

图 3(上图)显示了当我们设置 p = 1,q = 0.5 时的示例。请注意网络区域(即网络社区)是如何使用相同的颜色着色的。在这种背景下,node2vec 发现了在小说的主要副情节中经常相互作用的角色群/社区。由于字符之间的边缘是基于共现的,我们可以得出结论,这一特征与同向性密切相关。为了发现哪些节点具有相同的结构角色,我们使用相同的网络,但是设置 p = 1,q = 2,使用 node2vec 获得节点特征,然后基于获得的特征对节点进行聚类。在这里,node2vec 获得了节点到集群的互补分配,因此颜色对应于图 3(底部)所示的结构等价。例如,node2vec 将蓝色节点紧密地嵌入在一起。这些节点代表在小说的不同子情节之间充当桥梁的角色。类似地,黄色节点主要代表处于外围并且具有有限交互的角色

节点 2 虚拟详细信息

在我让您离开之前,我想分享一些高级 node2vec 实现的后果。首先,node2vec 算法不区分节点或关系类型。如果您的图有许多节点或关系类型,node2vec 算法不会考虑这一点。其次,节点属性或特征不能添加到算法输入中。所得的节点嵌入仅受网络拓扑的影响,而不受节点属性或特性的影响。

最后,但同样重要的是,node2vec 算法是一种直推式节点嵌入算法,这意味着它需要整个图都可以用来学习节点嵌入。不能对测试和训练数据单独运行 node2vec 算法。类似地,当一个新节点被添加到图中时,如果希望为新节点生成嵌入,需要在整个图上重新运行 node2vec 算法。

摘要

Node2vec 算法可以概括为两个部分的过程。首先,它使用二阶有偏随机行走来生成节点或“句子”的序列。通过微调随机漫步超参数,您可以影响随机漫步长度,以及您是否希望封装更多的同质性或结构等价相似性。第二,一旦生成了节点序列,它们就被用作负采样跳跃图模型的输入。skip-gram 模型首先生成给定上下文窗口大小的输入和上下文节点对,然后将它们馈送到浅层两层神经网络。一旦训练了神经网络,就可以检索隐藏层权重作为节点嵌入。隐藏层中神经元的数量将决定嵌入的大小。

参考

  • 托马斯·米科洛夫,程凯,格雷戈·科拉多,杰弗里·迪恩:向量空间中单词表征的有效估计,2013,arXiv:1301.3781
  • 页(page 的缩写)巴塔格利亚等人,关系归纳偏差、深度学习和图网络 (2018),arXiv:1806.01261。
  • node2vec:网络的可扩展特征学习。a .格罗弗 j .莱斯科维奇。2016 年 ACM SIGKDD 知识发现与数据挖掘国际会议(KDD)
  • c .麦考密克(2016 年 4 月 19 日)。 Word2Vec 教程——跳格模型。从 http://www.mccormickml.com取回
  • fortunato S..图形中的社区检测abs/0906.0612 (2009): n. pag。
  • 关于学习 Word2Vec 的思考。J 超级计算机 (2021)。https://doi.org/10.1007/s11227-021-03743-2
  • y . levy(2014 年)。基于依存关系的单词嵌入。在计算语言学协会第 52 届年会会议录(第 2 卷:短文)(第 302–308 页)。计算语言学协会。

NLP 任务的完整机器学习管道

原文:https://towardsdatascience.com/complete-machine-learning-pipeline-for-nlp-tasks-f39f8b395c0d?source=collection_archive---------11-----------------------

具有基本实现的用于电子邮件中命名实体识别的端到端机器学习管道

管道架构

放弃

  1. 这个项目的灵感来自于我在职业生涯中有机会解决的一个问题,然而,这里提出的问题是不同的,本文不包含该产品中使用的任何代码和/或解决方案。
  2. 这里给出的解决方案是一个简化的解决方案。文章的最后讨论了使其更接近可靠的生产就绪服务所需的进一步步骤。
  3. 给定的材料假设读者熟悉机器学习和软件工程的基础,但很想知道如何让它们一起工作。

介绍

几年前,在生产中运行并带来真正价值的可靠 ML 系统是 big tech 的特权,其他公司无法获得实现此类产品的人才和技术。然而,时代已经变了,现在越来越多的非技术公司享受现实世界的 ML 应用的好处。

本文提供了将 PoC 转化为成熟的 ML 产品所需的一切,包括简化管道的参考实现以及下一步要做什么的提示。该系统解决的具体问题可以描述如下:从收到的电子邮件中提取公司名称并记录下来。这听起来像是一个表面问题,但应该能够证明如何将 ML 系统投入生产。

系统概况

建议的体系结构显示在文章开头的图中。

它有以下组件:

  1. 要轮询新邮件的邮箱

2.控制数据流的工作流协调器:

  • 轮询邮箱(1)
  • 向预测工作者发出请求(3)
  • 将电子邮件正文以及提取的实体保存到 DB (4)

3.预测工作者实际上是通过提取实体将模型应用于给定的电子邮件正文来执行 ML

4.存储电子邮件正文和提取实体的数据库

5.(可选)模型训练器将:

  • 形成针对数据库查询的训练数据集(4)
  • 需要时(重新)训练模型
  • 根据测试数据集验证模型
  • 将模型存储在模型存储器(6)中
  • 如果验证成功,将生产模型指针更改为新模型

6.(可选)对象存储形式的模型存储,如 S3 存储桶

履行

本文附有资源库,里面有完整系统的代码和运行指令。

https://github.com/isenilov/ml-pipeline

让我们详细回顾一下组件。

邮筒

SMTP(发送电子邮件)/ IMAP(阅读电子邮件)邮件服务器使用 GreenMail docker 镜像打开各自的端口进行模拟:

工作流编排器

在我们的系统中,我们使用一个非常简单的脚本,该脚本定期轮询邮箱(1),将电子邮件正文发送给预测工作者(3),并将结果记录到数据库(4):

另一方面,在真实的生产系统中,工作流编排引擎之一,如 Apache Airflow 、 Argo Workflows 等..可以使用(可以在这里找到此类工具的良好列表)以获得可靠性和更简单的工作流声明。

预测工作者

预测工作器是一个微服务,它提供了一个端点,用于根据传入的文本预测实体。在我们的示例中,我们将自己限制在一个非常简单的基于 FastAPI 的 web 服务上,该服务从 SpaCy 加载一个预训练的模型,并将其应用于输入。

数据库ˌ资料库

DB 只是 PostgreSQL DB 的一个实例。同样,我们假设它对于合理的负载应该足够了,并且当您希望拥有一个群集或为分析创建一个只读副本以便分析师不能影响生产实例时,我们不考虑可靠性问题。

使用官方 PostgreSQL docker 图像:

运行管道

本文附带了库,其中包含了运行端到端管道所需的所有代码。

要求

用于运行管道的 PC 应该安装了 Docker 和 telnet 。如果需要,请参考您系统的安装说明。

可以使用以下命令克隆存储库:

git clone [https://github.com/isenilov/ml-pipeline.git](https://github.com/isenilov/ml-pipeline.git)

运行它

4 个服务(邮件服务器、数据库、预测服务和 orchestrator)的整个管道可以通过一个命令启动:

docker-compose -f docker-compose.yaml up --build

它应该开始打印来自服务的日志消息。

发送电子邮件

管道由邮箱中出现的未读邮件触发。为了发送一个,可以使用 telnet util。

连接到 IMAP 邮件服务器:

telnet localhost 3025

使用 telnet 发送电子邮件:

EHLO user
MAIL FROM:<example@some-domain.com>
RCPT TO:<user>
DATA
Subject: Hello World

Hello!She works at Apple now but before that she worked at Microsoft.
.
QUIT

如果一切顺利,日志中应该会出现这样的内容:

orchestrator_1 | Polling mailbox…
prediction-worker_1 | INFO: 172.19.0.5:55294 — “POST /predict HTTP/1.1” 200 OK
orchestrator_1 | Recoded to DB with id=34: [{‘entity_text’: ‘Apple’, ‘start’: 24, ‘end’: 29}, {‘entity_text’: ‘Microsoft’, ‘start’: 58, ‘end’: 67}]

检查结果

数据也必须记录到数据库中。为了检查这一点,任何数据库客户机都可以使用以下连接参数:

host: localhost
port: 5432
database: maildb
username: pguser
pasword: password

和跑步

SELECT * FROM mail LIMIT 10

查询。

生产化

这个实现可以给读者一个真实 ML 系统是什么样子以及它的组件如何交互的概念。然而,为了使系统健壮、可靠和高性能,需要更多的步骤。

异步服务

给定的实现包括由 Orchestrator (2)和预测工作器(3)中的同步处理程序使用的同步版本的请求库,这意味着不能并行处理几个请求,即在下一个请求可以被发送之前必须完成一个预测。这可能是次优的,因为当预测工作者在做他们的工作时,编排器只是空转。

要解决这个问题,可以采取以下措施:

  • 在客户端使用 aiohttp
  • 在服务器(预测工作器)端定义异步处理器

消息队列

尽管定期的邮箱轮询可以作为一种队列,但是在 Orchestrator(发布到主题的数据生产者)和预测工作者(订阅主题的数据消费者)之间以及数据源和 Orchestrator 之间放置一个真正的队列,如 Apache Kafka 主题,可能是一个好主意。如果预测工作者不能处理大量的请求,它将更多地分离服务,并可能平滑负载峰值和避免超时。

部署和扩展

拥有一个分布式微服务系统而不是一个可以做所有事情的整体系统的优势之一是易于扩展。出于可靠性以外的原因,合理的负载可能不需要将 Workflow Orchestrator 扩展到单个主机之外,但是,单个预测工作者很可能无法应对更高的负载。幸运的是,Prediction Worker 是一个无状态服务,这意味着它不需要维护单个请求上下文之外的状态(即,服务实例之间没有竞争条件),这反过来使其水平扩展变得简单,就像在工作机群前面添加一个负载平衡服务,如 nginx 。

本文附带的示例使用 docker-compose 来部署管道,主要是因为简单。然而,真正的生产系统很少依赖这个工具。我经历了在科技公司部署微服务的两种主要方式:

  • 一个自行编写的系统,用于管理云中或本地的部署。
  • 不同口味的 Kubernetes 及其包装,例如 kube flow 为裸 Kubernetes 增添了许多 ML 特有的便利。

采用 GitOps 管理部署方式的后一种选择似乎是当今最流行的。

监视

一些服务甚至可以在没有任何额外代码的情况下发出指标,比如 Airflow integration 与 statsd 或 Datadog 与 gunicorn 的集成。虽然这些集成可以为我们提供基本的指标,如 HTTP 响应代码的速率或响应延迟,但 ML pipeline 需要的不仅仅是这些。让我们看看还可以/应该监控什么:

  • 来自服务器(预测工作器(3)本身)和客户端(编制器(2))的预测时间
  • 预测工作器返回 HTTP 代码的速率
  • 模型预测漂移检测的不同预测标签和预测置信度/相似度的比率。某个实体的检测率的变化可以表明潜在的模型过时和需要重新训练/微调,这可以由编排器(2)基于例如某个漂移阈值来触发
  • 用于检测输入数据分布漂移的输入数据参数,例如,输入文本的长度、字数等…与上一点类似,但此处的变化可能表明数据的性质已经改变,模型可能需要适应它
  • 与主机相关的标准指标,如 CPU 负载、内存/磁盘空间等…

结论

这结束了生产就绪的机器学习解决方案世界的短暂旅程,并为读者提供了进一步探索的方向和关于所涵盖的每个主题的谷歌关键词。

希望这篇文章和代码对您有用,如果您对这个主题有任何问题或对未来文章有任何建议,请随时通过 LinkedIn 联系我。

2022 年数据科学完整 Python 入门指南

原文:https://towardsdatascience.com/complete-python-starter-guide-for-data-science-for-2022-c1f880fa249d?source=collection_archive---------11-----------------------

涵盖所有 Python 的基础知识和基本概念,通过代码示例帮助您了解数据科学

米利安·耶西耶在 Unsplash 上拍摄的照片

Python 是现代最重要的编程语言之一。尽管这种语言是在近 30 年前开发的,但它仍在不断发展,仍然具有巨大的价值和更多的功能,特别是在数据科学和人工智能方面。

Python 3.10 的当前版本是从以前的 Python 2 时代发展而来的,这种编程语言及其社区的增长正处于历史最高水平。

由于这些技术的持续发展和进步,数据科学和人工智能获得了巨大的普及,人们非常好奇这些巨大的主题会飞多远,特别是使用 Python 作为它们的主要开发语言。

我们将经历一个新的时代,因为我们有更多的爱好者,他们不断地吞没这些现代概念,并为这些领域的进步做出巨大贡献。随着下一年的迅速临近,我们中的许多人都有了新的目标,去学习新的有趣的话题并取得更大的进步。

在本文中,我们的主要焦点是建立对数据科学有用的所有基本概念的基本理解,并初步了解我们如何利用 Python 在人工智能、机器学习和数据科学领域变得更加精通。

我们将关注开发人员在从事数据科学项目时最应该关注的特定主题,以获得最佳结果。如果您正在寻找关于即兴 Python 编程的更高级的作品,请查看下面的文章,以了解 Python 的一些最佳实践。

迭代语句:

在简要了解了使用 Python 进行面向对象编程的意义之后,让我们来探讨一下 Python 中迭代语句的概念。像 Java 和 C++这样的大多数编程语言通常使用相当多的迭代语句,例如 for 循环、while 循环、do-while 语句、switch case 和其他类似的迭代。

在 Python 中,我们大多只有效地利用进行循环或 While 循环。大多数计算都是用这两条迭代语句来执行的。在 Python 编程的帮助下,只要满足某个条件(即 True),就可以运行这些迭代循环。因此,执行特定的代码块变得很容易,直到持续满足所需的目的。

无论是数据科学还是简单的 Python 编程,迭代语句都被认为是必须的。几乎每一个单独的项目都利用这些重复的循环来执行特定的任务。我以前文章中的大多数项目也使用了这些语句。下面的一个最好的例子来自我以前的一个博客,是关于创建一个语言亵渎测试器的。查看下面的代码,并访问文章后面的获取更多信息。

sentence = "You are not only stupid , but also an idiot ."def censor(sentence = ""):
    new_sentence = ""

    for word in sentence.split():
        if word in Banned_List:
            new_sentence += '* '
        else:
            new_sentence += word + ' '

    return new_sentence

哎呀:

Python 是一种面向对象的编程语言,它是 Python 最本质的方面之一。然而,由于 Python 的其他惊人特性,这个特性有时会被忽略。因此,这个主题应该是我们开始使用 Python 进行数据科学研究的主要焦点。当处理 Python 的许多方面时,有时可能会忘记面向对象编程的重要性。

每一个用于机器学习、数据科学或任何内置于 Python 的深度学习框架的库都将主要由两个基本的主要组件组成,即对象和类。现实世界中的实体,如类、封装、多态和继承,在 Python 中也实现得相当好。因此,我们的目标是非常详细地理解所有的概念,我们将在下一篇文章中深入探讨这些概念。

下面是一些快速入门的代码。查看下面的文章中的以获得关于这个代码块的更多信息。

class Derivative_Calculator:
    def power_rule(*args):
        deriv = sympy.diff(*args)
        return deriv
    def sum_rule(*args):
        derive = sympy.diff(*args)
        return derivdifferentiatie = Derivative_Calculator
differentiatie.power_rule(Derivative)

列表:

列表是可变的有序元素序列。可变意味着列表可以被修改或改变。列表用方括号“[ ]”括起来。列表是一种有序的数据结构,列表中的每个元素都被分配了一个特定的索引号,通过该索引号可以对其进行访问。列表中的每个项目或元素由逗号(,)分隔。

lst = ['one', 'two', 'three', 'four']
lst.append('five')
lst

输出:

['one', 'two', 'three', 'four', 'five']

append 函数是编程和数据科学领域中使用的最重要的命令之一。我们还可以在列表上执行和操作其他一些功能。要了解更多关于其他可用选项的信息,我强烈推荐通过下面提供的链接查看使用 Python 编程掌握列表的详细版本。

词典:

字典允许用户相应地访问键和值。假设你必须存储一个人的一些数据,那么你会考虑使用字典,比如存储一个联系人的名字和他们的号码。字典还可以存储与特定。学校中学生的特定姓名可以存储许多科目的分数。字典是 Python 中的数据结构,被定义为无序的数据集合。下面是一些样例代码和输出,用于开始使用字典。

# Return a list of tuples of the dictionary items in the (key, value) form
my_dict = {1: 'A', 2: 'B', 3: 'C'}
print(my_dict.items())# Return a new view of the dictionary keys
my_dict = {1: 'A', 2: 'B', 3: 'C'}
print(my_dict.keys())# Return a new view of the dictionary values
my_dict = {1: 'A', 2: 'B', 3: 'C'}
print(my_dict.values())

输出:

dict_items([(1, 'A'), (2, 'B'), (3, 'C')])
dict_keys([1, 2, 3])
dict_values(['A', 'B', 'C'])

上面的起始代码应该允许用户对如何使用字典值和关键元素的一些基本概念有一个简单的理解。如果你期待一个关于字典和集合的扩展指南,我推荐你看看下面的文章,以获得更多关于这些主题的知识。

功能:

函数允许用户在deffunction name():命令下快速操作代码块内的可重复任务。这一概念在编程中非常有用,尤其是在数据科学中,您需要对大量数据重复特定的操作。利用函数来实现这一目标将减少开发人员需要执行的大量计算。

Python 还允许它的用户直接访问它的一些匿名(或高级)函数选项,这将有助于更快更高效地开发您的项目。我已经在另一篇文章中非常详细地介绍了以下主题,如果您有兴趣进一步探讨这个主题,我建议您查看一下。下面提供了相同内容的链接。

探索用于数据科学的 Python 库:

Python 最好的特性是这种编程语言有大量可用的库。对于您想要执行的几乎每一种类型的任务或想要进行的任何类型的项目,Python 提供了一个库,它将极大地简化或减少工作。

在 Python 提供的一些最好的数据科学库的帮助下,您可以完成您想要完成的任何类型的任务。让我们探索一些数据科学初学者必须知道的库。

1.熊猫:

对于使用数据科学,主要要求之一是分析数据。Python 为其用户提供的最好的库之一是 Pandas 库,通过它,您可以访问互联网上以结构化格式提供的大多数内容。它为开发人员提供了访问各种格式的大量文件的选项,如文本、HTML、CSV、XML、latex 等等。下面是一个可以用来访问 CSV 格式类型数据的示例。

data = pd.read_csv("fer2013.csv")
data.head()

作者图片

为了更多地了解 Pandas 并征服这个库背后的分析工具,我建议查看我以前的一篇文章,该文章介绍了每个数据科学家的武器库中必须包含的 14 个最重要的 Pandas 操作。以下是相同的以下链接。

</14-pandas-operations-that-every-data-scientist-must-know-cc326dc4e6ee>

2.Matplotlib:

作者图片

一旦您完成了数据分析,下一个重要的步骤就是相应地将它们可视化。对于数据的可视化,matplotlib 和 seaborn 是 Python 中可用的最佳选项之一。你可以用这个奇妙的库和简单的代码来可视化几乎任何基本的实体。它支持像 NumPy 这样的数字扩展,您可以将这些数字扩展组合在一起以可视化大多数数据元素。

上面的图像展示了一个在 matplotlib 库的帮助下构建的条形图。我们可以使用 matplotlib 执行更多的可视化、图表和其他统计可视化。要了解有关数据科学项目的不同类型的可视化的更多信息,请查看下面提供的链接。

</8-best-visualizations-to-consider-for-your-data-science-projects-b9ace21564a>

3.NumPy:

简言之,数值 Python 或 NumPy 是 Python 中计算数学问题的最佳选择之一。您可以利用 numpy 数组的概念来简化数据科学领域中涉及的复杂数学。它有助于您处理大型多维数组和矩阵,以及高效构建您的数据科学项目。

如果没有 numpy 的适当效用,解决大多数复杂的数学问题和机器学习项目几乎是不可能的。因此,非常详细地理解这个概念是至关重要的。建议读者阅读下面的文章,了解每个数据科学家都必须了解的十五个 numpy 功能。

</15-numpy-functionalities-that-every-data-scientist-must-know-f6d69072df68>

4.sci kit-学习:

Scikit-learn 是最好的库之一,使用它可以实现所有基本的机器学习算法,如分类、回归、聚类、预处理(如下面的代码所示)、模型选择、维数减少等等。library toolkit 利用简单但高效的工具来分析和计算数据。它不仅像前面提到的其他三个模块一样安装简单,而且它是建立在 matplotlib、numpy 和 scipy 等关键包之上的。对于初学者来说,这个开源工具是更有效地实现机器学习项目的必学工具。

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(questions, response, test_size=0.20)

5.NLTK:

自然语言工具包是处理人类语言数据的最佳库之一。一开始,大多数机器学习和数据科学项目将处理大量的自然语言处理任务。对于大多数与自然语言处理相关的问题,清理数据是数据准备阶段所需的最基本的步骤之一。因此,如果您是该领域的初学者,学习和掌握这个库是非常重要的。

import nltksentence = "Hello! Good morning."
tokens = nltk.word_tokenize(sentence)

如果你正在研究图像处理方面的东西,那么计算机视觉库 Open-CV 是非常值得推荐的。从下面的链接查看以下库的完整指南。

结论:

自由股票在 Unsplash 上的照片

“代码就像幽默。当你不得不解释它时,它是糟糕的。”— 科里屋

Python 是一种革命性的编程语言,由于其简单、易学、多功能和许多其他令人难以置信的特性,几十年来它一直保持着相关性。随着过去几年人工智能和数据科学的出现,Python 为自己创造了巨大的声誉,成为这些领域的主导语言之一,也是每个人最终都必须掌握的东西。

在本文中,我们介绍了 Python 入门的大部分基本概念,以便更加精通数据科学。我们集中讨论了 Python 中的大多数基本主题,这些主题在数据科学的大多数领域都有巨大的用途,并且将有助于大多数项目的成功完成。如果您能够掌握本文中提到的所有方法,您将能够轻松完成大多数基础数据科学项目。

如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。

https://bharath-k1297.medium.com/membership

如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。

看看我的一些与本文主题相关的文章,你可能也会喜欢阅读!

</5-best-python-projects-with-codes-that-you-can-complete-within-an-hour-fb112e15ef44> </17-must-know-code-blocks-for-every-data-scientist-c39a607a844d>

谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!

从头开始完成逐步共轭梯度算法

原文:https://towardsdatascience.com/complete-step-by-step-conjugate-gradient-algorithm-from-scratch-202c07fb52a8?source=collection_archive---------2-----------------------

实践教程

和一般函数优化的实现

克里斯蒂安·鲍文在 Unsplash 上的照片

**Table of Contents** (read till the end to see how you can get the complete python code of this story)· [Conjugate Gradient for Solving a Linear System](#791f)
· [Improving the Algorithm](#834b)
  ∘ [Theorem](#9d26)
  ∘ [Simple Problems](#474d)
· [Conjugate Gradient for Nonlinear Optimization Problem](#c404)
  ∘ [Wolfe Line Search](#73ae)
  ∘ [Implementation](#01af)
  ∘ [Scenarios](#e04a)
· [Conclusion](#cd74)

T 共轭梯度是数学上涉及的算法之一。所以,为了简化事情,我们会砍掉任何不必要的冗长的解释。后面我们还会用到一个数学定理但不会证明。我们先导入一些库。

解线性系统的共轭梯度法

考虑一个线性方程 Ax = b 其中 A 是一个 n × n 对称正定矩阵, xbn × 1 向量。求解这个方程对于 x 等价于下面凸函数 f(x) 的最小化问题

也就是说,这两个问题都有相同的唯一解。

我们将迭代求解 xAx = b 。定义残差r(x):=∇f(x)= ax b。然后在迭代 xₖ ,我们有

沿着 xₖ + αpₖf 的一维极小元显式给出(通过将*f(xₖ+αpₖ】*w . r . t .α的一阶导数设为零)如下

在共轭梯度法中,选择方向集{ p₀,p₁,… },使其元素相对于 A共轭,即,

每个方向 pₖ 被选择为负残差- rₖ (这是函数 f 的最陡下降方向)和前一个方向 pₖ₋₁ 的线性组合。我们写作

其中标量 βₖ 由要求 pₖ₋₁pₖ 必须相对于 A 共轭来确定。通过将最后一个等式乘以

并强加条件

我们发现

已知 αₖpₖ ,下一次迭代可以像往常一样使用

如前所述,选择方向集{ p₀,p₁,… },使得其元素相对于 A共轭。但是我们如何选择第一个搜索方向 p₀ ?简单的用好 ol '最陡下降方向在初始点 x₀ ,也就是 p₀ = -r₀

我们现在有了一个可行的算法:

1\. Initialize x₀
2\. Calculate r₀ = Ax₀ − b
3\. Assign p₀ = −r₀
4\. For k = 0, 1, 2, …:
    * calculate αₖ = -rₖ'pₖ / pₖ'Apₖ
    * update xₖ₊₁ = xₖ + αₖpₖ
    * calculate rₖ₊₁ = Axₖ₊₁ - b
    * calculate βₖ₊₁ = rₖ₊₁'Apₖ / pₖ'Apₖ
    * update pₖ₊₁ = -rₖ₊₁ + βₖ₊₁pₖ

这里,撇号表示转置操作,以方便书写。

改进算法

我们可以进一步提高计算 αₖβₖ 的时间和空间复杂度。为此,我们提出了以下定理。前面说过,这里不证明定理。

定理 1

x₀ ∈ ℝ 为任意起点,并假设序列{ xₖ }如上所述生成。然后

固定 k > 0 。因为我们已经

然后

因此

因为由定理 1 右手边是零,那么我们有

将两边除以

我们获得

最后一个等式的左手边正是αₖ。于是我们有了一种更经济的形式 αₖ 如下

既然rₖ=axₖb,我们就有rₖ₊₁rₖ=a(xₖ₊₁xₖ)。结合步骤方程式 xₖ₊₁ = xₖ + αₖpₖ ,我们得出

将最后一个方程代入上面建立的 βₖ₊₁ 方程,我们得到

考虑以下观察结果:

  • 定理 1 ,我们有

  • 我们以前证明过

  • 因为

我们有

因此

自由定理 1

我们有

将这三个观察值代入上面最新的 βₖ₊₁ 方程,我们得到

现在,我们已经具备了构建求解线性系统的共轭梯度算法的所有要素。

我们将尝试使用该算法来解决 xAx = b ,其中 Ab 对于下面三个问题的定义是不同的。

问题 1

A 是 2 × 2 对称正定矩阵 b 是 2 × 1 向量。两者都是使用来自scikit-learnmake_spd_matrix函数随机生成的。

A
 [[ 2.5409 -0.0113]
  [-0.0113  0.5287]]b
 [1.3864  0.3719]The solution x* should be
 [0.5488  0.7152]

让我们运行共轭梯度算法,初始点 x₀ 在[-3,-4]。

Iteration: 1 	 x = [ 0.7428 -2.9758] 	 residual = 2.0254
Iteration: 2 	 x = [ 0.5488  0.7152] 	 residual = 0.0000Solution: 	 x = [ 0.5488  0.7152]

这个解是在两次迭代中找到的。我们可以使用numpy中的allclose功能来检查解决方案是否是我们想要的。如果它返回True,则解是正确的。

True

最后,我们可以将这个问题转化为函数 f 的最小化,其中 f 定义如下。

为了可视化学习路径,我们创建一些 python 函数,如下所示。

图片由作者

从上面的图中,我们可以确认在两次迭代中确实找到了解决方案。对于下面的另外两个问题,我们不会费心绘图,因为 x 的维数大于 2,因此很难或不可能绘图。

问题 2

A 是一个 3 × 3 对称正定矩阵, b 是一个 3 × 1 向量,两者都是像以前一样随机生成的。

A
 [[ 0.7444 -0.5055 -0.0851]
  [-0.5055  3.4858  0.0572]
  [-0.0851  0.0572  0.4738]]b
 [-0.0043  2.2501  0.2798]The solution x* should be
 [ 0.5488  0.7152  0.6028]

让我们运行共轭梯度算法,初始点在[3,1,-7]。

Iteration: 1 	 x = [ 0.0261  1.8702 -2.1522] 	 residual = 4.3649
Iteration: 2 	 x = [-0.5372  0.5115 -0.3009] 	 residual = 0.7490
Iteration: 3 	 x = [ 0.5488  0.7152  0.6028] 	 residual = 0.0000Solution: 	 x = [ 0.5488  0.7152  0.6028]

这个解是在三次迭代中找到的。我们再次看到,这确实是我们想要的解决办法。

True

问题 3

A 是一个 6 × 6 的对称正定矩阵, b 是一个 6 × 1 的向量,两者都是像以前一样随机生成的。

A
 [[ 3.4430 -0.3963  2.5012  0.9525  0.6084 -1.2728]
  [-0.3963  0.6015 -0.4108 -0.1359 -0.0295  0.2630]
  [ 2.5012 -0.4108  2.5927  0.7072  0.5587 -1.0613]
  [ 0.9525 -0.1359  0.7072  1.1634  0.1920 -0.4344]
  [ 0.6084 -0.0295  0.5587  0.1920  0.7636 -0.3261]
  [-1.2728  0.2630 -1.0613 -0.4344 -0.3261  1.0869]]b
 [ 3.0685  0.0484  2.5783  1.2865  0.8671 -0.8230]The solution x* should be
 [ 0.5488  0.7152  0.6028  0.5449  0.4237  0.6459]

让我们运行共轭梯度算法,初始点在[9,0,-2,3,-2,5]。

Iteration: 1   x = [ 6.0798  0.2932 -3.6765  1.9076 -2.1460  5.5981]
               residual = 5.2930
Iteration: 2   x = [ 1.5966 -0.3208 -0.2777 -0.5521  1.3176  1.3223]
               residual = 1.1933
Iteration: 3   x = [ 0.6074  0.2616  0.2860  0.7581  0.8068  0.6812]
               residual = 0.3795
Iteration: 4   x = [ 0.5343  0.6703  0.6294  0.5496  0.4109  0.6765]
               residual = 0.0346
Iteration: 5   x = [ 0.5477  0.7172  0.6058  0.5464  0.4280  0.6519]
               residual = 0.0047
Iteration: 6   x = [ 0.5488  0.7152  0.6028  0.5449  0.4237  0.6459]
               residual = 0.0000Solution:      x = [ 0.5488  0.7152  0.6028  0.5449  0.4237  0.6459]
The solution is correct.

这个解是在六次迭代中找到的。我们再次看到,这确实是我们想要的解决办法。

我们能从这些例子中学到什么?最明显的就是共轭梯度算法求解所需的迭代与矩阵 A 的维数相同。这就是为什么我们不需要在LinearCG函数中保护我们的算法免于无限循环(例如使用最大迭代)。事实上,如果 A 只有 r 个不同的特征值,那么共轭梯度迭代最多在 r 次迭代中终止于解。

共轭梯度法只推荐用于大问题;否则,高斯消去法或诸如奇异值分解之类的其他因子分解算法是优选的,因为它们对舍入误差不太敏感。

非线性优化问题的共轭梯度

在上一节中,我们已经实现了共轭梯度作为凸二次函数 f 的最小化算法。我们已经准备好加强我们的比赛。我们能否采用这种方法来最小化一般的凸函数,甚至一般的非线性函数 f

我们可以通过改变前面算法中的两件事来做到这一点:

  • 步长 αₖ 目前是沿着 pₖf 的精确最小值。相反,我们希望使用线搜索算法将 αₖ 作为最小化点的近似值。
  • 残差 rₖ 现在应该是目标函数 f 的梯度。

我们已经在上一篇文章中介绍了一种线搜索算法:阿米霍线搜索。然而,因为在共轭梯度法中,我们有

如果 βₖpₖ₋₁ 占优势,仅充分下降条件不足以确保下降方向。

输入沃尔夫线搜索。

沃尔夫线搜索

我们增加另一个条件,叫做曲率条件,它要求 αₖ 满足

对于某些常数c₂∑*(c₁,1)* 其中 c₁ 是来自阿米霍条件的常数。注意,左手边仅仅是 f(xₖ + αpₖ)αₖ 的导数,因此曲率条件确保 f(xₖ + αpₖ)αₖ 的斜率大于 c₂ 乘以初始斜率

该条件排除了 Armijo 条件优选的不可接受的短步长,因此 f 可以显著减少。结合阿米霍条件,这两个条件也被称为沃尔夫条件

我们可以修改曲率条件,以迫使 αₖ 至少位于 f 的局部极小点或驻点的宽邻域内。这种修改被称为强沃尔夫条件并要求 αₖ 满足

对于我们在上一篇文章中讨论的阿米霍线搜索,我们通过将 αₖ 乘以收缩项 ρ 来定位最终步长。这种策略对于强 Wolfe 条件来说是低效的,因为它违背了该条件的目的。因此,对于选择阶段,我们放大以定位最终步长,这通常会在搜索所需步长的过程中减少括号间隔,并插入在早期步骤中收集的一些函数和导数信息,以猜测最小点的位置。我们不会在这里解释数学,因为它非常乏味,直接阅读下面的代码可能会更好。

哇,这是一个长的。现在我们准备实现 Wolfe 线搜索到共轭梯度算法。

履行

首先,我们定义一个目标函数来求解:格里万克函数。

我们将使用二维版本的格里万克函数( n = 2 ),正如在上一篇文章中所做的那样。

最后,让我们建立非线性共轭梯度算法。如前所述,我们使用

为方向,αₖ 从沃尔夫线搜索为步长。此外,将采取措施,直到满足以下停止标准之一:

  • f 的梯度的范数足够接近零,也就是说,

  • 采取的步骤数是 1000

前面提到的 βₖ 的公式是由弗莱彻-里维斯(FR)开发的。这种方法的一个主要问题是,如果我们,不管什么原因,最终走向错误的方向 pₖ ,那么 FR 继续产生错误的方向。出于这个原因,Polak-Ribiere (PR)开发了另一种形式的 βₖ

在实践中,PR 的共轭梯度算法通常比 FR 的效果更好。然而,强沃尔夫条件并不能保证 pₖ 是下降方向。

在下面的代码中,我们还介绍了βₖ的许多其他变体:

  • 赫斯泰尼斯-斯蒂费尔
  • 戴渊(DY)
  • 哈格-张(赫兹)

然后,我们创建一个 python 函数来创建两个图:

  • x 的学习路径以及 f(x) 的轮廓图
  • 每走一步 f(x) 的值

对于一个初始值 x₀ 和一些 β 估计方法,我们在不同的场景下对 f 运行共轭梯度算法:

  • x₀ = [ 0,3 ]并使用 FR
  • x₀ = [ 2,1 ]并使用 FR
  • x₀ = [ 2,1 ]并使用 PR
  • x₀ = [ 2,1 ]并使用 HS
  • x₀ = [ 2,1 ]并使用 DY
  • x₀ = [ 2,1 ]并使用赫兹
  • x₀ = [ 2,2 ]并使用赫兹

场景 1: x₀ = [ 0,3 ]并使用 FR

Initial condition: y = 1.5254, x = [0 3]Iteration: 1 	y = 0.0004, x = [ 0.0000 -0.0389], gradient = 0.0195
Iteration: 2 	y = 0.0000, x = [ 0.0000 -0.0012], gradient = 0.0006
Iteration: 3 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000
Iteration: 4 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [ 0.0000  0.0000]

图片由作者

场景 2: x₀ = [2,1]并使用 FR

Initial condition: y = 1.3176, x = [2 1]Iteration: 1 	y = 0.5170, x = [ 0.2435  1.4838], gradient = 0.6077
Iteration: 2 	y = 0.3029, x = [-0.3727  1.0246], gradient = 0.5152
Iteration: 3 	y = 0.1579, x = [-0.5426  0.2577], gradient = 0.5198
Iteration: 4 	y = 0.0758, x = [-0.3477 -0.2603], gradient = 0.3566
Iteration: 5 	y = 0.0462, x = [-0.1203 -0.3975], gradient = 0.2265
Iteration: 6 	y = 0.0329, x = [ 0.0433 -0.3585], gradient = 0.1822
Iteration: 7 	y = 0.0220, x = [ 0.1482 -0.2118], gradient = 0.1796
Iteration: 8 	y = 0.0120, x = [ 0.1548 -0.0102], gradient = 0.1543
Iteration: 9 	y = 0.0064, x = [ 0.0865  0.1037], gradient = 0.1005
Iteration: 10 	y = 0.0042, x = [ 0.0221  0.1262], gradient = 0.0668
Iteration: 11 	y = 0.0031, x = [-0.0241  0.1051], gradient = 0.0578
Iteration: 12 	y = 0.0020, x = [-0.0511  0.0513], gradient = 0.0571
Iteration: 13 	y = 0.0010, x = [-0.0451 -0.0090], gradient = 0.0453
Iteration: 14 	y = 0.0006, x = [-0.0222 -0.0367], gradient = 0.0288
Iteration: 15 	y = 0.0004, x = [-0.0031 -0.0397], gradient = 0.0201
Iteration: 16 	y = 0.0003, x = [ 0.0104 -0.0304], gradient = 0.0184
Iteration: 17 	y = 0.0002, x = [ 0.0169 -0.0114], gradient = 0.0178
Iteration: 18 	y = 0.0001, x = [ 0.0128  0.0059], gradient = 0.0132
Iteration: 19 	y = 0.0001, x = [ 0.0055  0.0124], gradient = 0.0083
Iteration: 20 	y = 0.0000, x = [-0.0001  0.0123], gradient = 0.0062
Iteration: 21 	y = 0.0000, x = [-0.0041  0.0085], gradient = 0.0059
Iteration: 22 	y = 0.0000, x = [-0.0053  0.0021], gradient = 0.0055
Iteration: 23 	y = 0.0000, x = [-0.0035 -0.0027], gradient = 0.0038
Iteration: 24 	y = 0.0000, x = [-0.0013 -0.0041], gradient = 0.0024
Iteration: 25 	y = 0.0000, x = [ 0.0004 -0.0037], gradient = 0.0019
Iteration: 26 	y = 0.0000, x = [ 0.0015 -0.0023], gradient = 0.0019
Iteration: 27 	y = 0.0000, x = [ 0.0016 -0.0002], gradient = 0.0016
Iteration: 28 	y = 0.0000, x = [ 0.0010  0.0010], gradient = 0.0011
Iteration: 29 	y = 0.0000, x = [ 0.0003  0.0013], gradient = 0.0007
Iteration: 30 	y = 0.0000, x = [-0.0002  0.0011], gradient = 0.0006
Iteration: 31 	y = 0.0000, x = [-0.0005  0.0006], gradient = 0.0006
Iteration: 32 	y = 0.0000, x = [-0.0005 -0.0001], gradient = 0.0005
Iteration: 33 	y = 0.0000, x = [-0.0002 -0.0004], gradient = 0.0003
Iteration: 34 	y = 0.0000, x = [-0.0000 -0.0004], gradient = 0.0002
Iteration: 35 	y = 0.0000, x = [ 0.0001 -0.0003], gradient = 0.0002
Iteration: 36 	y = 0.0000, x = [ 0.0002 -0.0001], gradient = 0.0002
Iteration: 37 	y = 0.0000, x = [ 0.0001  0.0001], gradient = 0.0001
Iteration: 38 	y = 0.0000, x = [ 0.0001  0.0001], gradient = 0.0001
Iteration: 39 	y = 0.0000, x = [ 0.0000  0.0001], gradient = 0.0001
Iteration: 40 	y = 0.0000, x = [-0.0000  0.0001], gradient = 0.0001
Iteration: 41 	y = 0.0000, x = [-0.0001  0.0000], gradient = 0.0001
Iteration: 42 	y = 0.0000, x = [-0.0000 -0.0000], gradient = 0.0000
Iteration: 43 	y = 0.0000, x = [-0.0000 -0.0000], gradient = 0.0000
Iteration: 44 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 45 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 46 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 47 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000
Iteration: 48 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [ 0.0000  0.0000]

图片由作者

场景 3: x₀ = [2,1]并使用 PR

Initial condition: y = 1.3176, x = [2 1]Iteration: 1 	y = 0.5170, x = [ 0.2435  1.4838], gradient = 0.6077
Iteration: 2 	y = 0.3194, x = [-0.4134  1.0358], gradient = 0.5266
Iteration: 3 	y = 0.0004, x = [-0.0111  0.0355], gradient = 0.0209
Iteration: 4 	y = 0.0004, x = [-0.0072  0.0370], gradient = 0.0198
Iteration: 5 	y = 0.0000, x = [ 0.0054  0.0041], gradient = 0.0057
Iteration: 6 	y = 0.0000, x = [-0.0000  0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [-0.0000  0.0000]

图片由作者

场景 4: x₀ = [2,1]并使用 HS

Initial condition: y = 1.3176, x = [2 1]Iteration: 1 	y = 0.5170, x = [ 0.2435  1.4838], gradient = 0.6077
Iteration: 2 	y = 0.3072, x = [-0.3836  1.0276], gradient = 0.5182
Iteration: 3 	y = 0.0004, x = [ 0.0119  0.0358], gradient = 0.0215
Iteration: 4 	y = 0.0002, x = [-0.0077  0.0221], gradient = 0.0135
Iteration: 5 	y = 0.0000, x = [-0.0000 -0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [-0.0000 -0.0000]

图片由作者

场景 5: x₀ = [2,1]并使用 DY

Initial condition: y = 1.3176, x = [2 1]Iteration: 1 	y = 0.5170, x = [ 0.2435  1.4838], gradient = 0.6077
Iteration: 2 	y = 0.2887, x = [-0.4140  0.9624], gradient = 0.5140
Iteration: 3 	y = 0.1582, x = [-0.5550  0.1947], gradient = 0.5287
Iteration: 4 	y = 0.0763, x = [-0.3343 -0.2981], gradient = 0.3502
Iteration: 5 	y = 0.0480, x = [-0.1058 -0.4143], gradient = 0.2270
Iteration: 6 	y = 0.0341, x = [ 0.0594 -0.3606], gradient = 0.1872
Iteration: 7 	y = 0.0225, x = [ 0.1599 -0.1985], gradient = 0.1855
Iteration: 8 	y = 0.0120, x = [ 0.1550  0.0073], gradient = 0.1545
Iteration: 9 	y = 0.0065, x = [ 0.0819  0.1131], gradient = 0.0991
Iteration: 10 	y = 0.0044, x = [ 0.0172  0.1302], gradient = 0.0673
Iteration: 11 	y = 0.0032, x = [-0.0290  0.1046], gradient = 0.0598
Iteration: 12 	y = 0.0020, x = [-0.0540  0.0461], gradient = 0.0587
Iteration: 13 	y = 0.0010, x = [-0.0445 -0.0140], gradient = 0.0451
Iteration: 14 	y = 0.0006, x = [-0.0206 -0.0392], gradient = 0.0284
Iteration: 15 	y = 0.0004, x = [-0.0016 -0.0407], gradient = 0.0204
Iteration: 16 	y = 0.0003, x = [ 0.0119 -0.0299], gradient = 0.0191
Iteration: 17 	y = 0.0002, x = [ 0.0175 -0.0096], gradient = 0.0182
Iteration: 18 	y = 0.0001, x = [ 0.0125  0.0074], gradient = 0.0130
Iteration: 19 	y = 0.0001, x = [ 0.0050  0.0131], gradient = 0.0082
Iteration: 20 	y = 0.0000, x = [-0.0006  0.0125], gradient = 0.0063
Iteration: 21 	y = 0.0000, x = [-0.0045  0.0082], gradient = 0.0061
Iteration: 22 	y = 0.0000, x = [-0.0055  0.0015], gradient = 0.0055
Iteration: 23 	y = 0.0000, x = [-0.0034 -0.0031], gradient = 0.0037
Iteration: 24 	y = 0.0000, x = [-0.0011 -0.0043], gradient = 0.0024
Iteration: 25 	y = 0.0000, x = [ 0.0005 -0.0038], gradient = 0.0020
Iteration: 26 	y = 0.0000, x = [ 0.0016 -0.0022], gradient = 0.0020
Iteration: 27 	y = 0.0000, x = [ 0.0016 -0.0000], gradient = 0.0016
Iteration: 28 	y = 0.0000, x = [ 0.0009  0.0011], gradient = 0.0011
Iteration: 29 	y = 0.0000, x = [ 0.0002  0.0014], gradient = 0.0007
Iteration: 30 	y = 0.0000, x = [-0.0003  0.0011], gradient = 0.0006
Iteration: 31 	y = 0.0000, x = [-0.0006  0.0005], gradient = 0.0006
Iteration: 32 	y = 0.0000, x = [-0.0005 -0.0001], gradient = 0.0005
Iteration: 33 	y = 0.0000, x = [-0.0002 -0.0004], gradient = 0.0003
Iteration: 34 	y = 0.0000, x = [-0.0000 -0.0004], gradient = 0.0002
Iteration: 35 	y = 0.0000, x = [ 0.0001 -0.0003], gradient = 0.0002
Iteration: 36 	y = 0.0000, x = [ 0.0002 -0.0001], gradient = 0.0002
Iteration: 37 	y = 0.0000, x = [ 0.0001  0.0001], gradient = 0.0001
Iteration: 38 	y = 0.0000, x = [ 0.0001  0.0001], gradient = 0.0001
Iteration: 39 	y = 0.0000, x = [-0.0000  0.0001], gradient = 0.0001
Iteration: 40 	y = 0.0000, x = [-0.0000  0.0001], gradient = 0.0001
Iteration: 41 	y = 0.0000, x = [-0.0001  0.0000], gradient = 0.0001
Iteration: 42 	y = 0.0000, x = [-0.0000 -0.0000], gradient = 0.0000
Iteration: 43 	y = 0.0000, x = [-0.0000 -0.0000], gradient = 0.0000
Iteration: 44 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 45 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 46 	y = 0.0000, x = [ 0.0000 -0.0000], gradient = 0.0000
Iteration: 47 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000
Iteration: 48 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [ 0.0000  0.0000]

图片由作者

场景 6: x₀ = [2,1]并使用赫兹

Initial condition: y = 1.3176, x = [2 1]Iteration: 1 	y = 0.5170, x = [ 0.2435  1.4838], gradient = 0.6077
Iteration: 2 	y = 0.2369, x = [-0.4269  0.8147], gradient = 0.4939
Iteration: 3 	y = 0.0000, x = [-0.0064 -0.0053], gradient = 0.0070
Iteration: 4 	y = 0.0000, x = [ 0.0003 -0.0008], gradient = 0.0005
Iteration: 5 	y = 0.0000, x = [ 0.0000  0.0000], gradient = 0.0000Solution: 	y = 0.0000, x = [ 0.0000  0.0000]

图片由作者

场景 7: x₀ = [2,2]并使用赫兹

Initial condition: y = 1.0669, x = [2 2]Iteration: 1 	y = 0.9666, x = [ 1.7144  2.5793], gradient = 0.2652
Iteration: 2 	y = 0.0075, x = [ 3.1474  4.4532], gradient = 0.0104
Iteration: 3 	y = 0.0074, x = [ 3.1379  4.4420], gradient = 0.0028
Iteration: 4 	y = 0.0074, x = [ 3.1400  4.4384], gradient = 0.0000Solution: 	y = 0.0074, x = [ 3.1400  4.4384]

图片由作者

从这些例子中,我们看到,采用共轭梯度算法进行一般函数优化将不再确保过程在某个特定的迭代次数终止。这就是为什么我们使用max_iter来保护算法。

βₖ 计算方法的不同导致算法性能的不同。此外, xₖ 的不良初始化可能不会导致过程中的全局最小值。

从这些结果中你还能推断出什么?让我们在下面的回复部分讨论这个问题。

结论

共轭梯度算法用于求解线性系统,或者等价地,优化二次凸函数。它设置学习路径方向,使得它们相对于系数矩阵 A共轭,因此该过程在最多 A 次迭代之后终止。该算法可用于利用 Wolfe 线搜索优化一般可微函数,并可通过考虑方向系数 βₖ 的变化进行改进。

🔥你好!如果你喜欢这个故事,想支持我这个作家,可以考虑 成为会员 。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。如果你注册使用我的链接,我会赚一小笔佣金。

🔖想了解更多经典机器学习模型的工作原理,以及它们是如何优化参数的?或者 MLOps 大型项目的例子?有史以来最优秀的文章呢?继续阅读:

Albers Uzila

艾伯斯·乌兹拉

从零开始的机器学习

View list8 storiesAlbers Uzila

艾伯斯·乌兹拉

高级优化方法

View list7 storiesAlbers Uzila

艾伯斯·乌兹拉

MLOps 大型项目

View list6 storiesAlbers Uzila

艾伯斯·乌兹拉

我最好的故事

View list24 storiesAlbers Uzila

艾伯斯·乌兹拉

R 中的数据科学

View list7 stories

从头开始完成逐步梯度下降算法

原文:https://towardsdatascience.com/complete-step-by-step-gradient-descent-algorithm-from-scratch-acba013e8420?source=collection_archive---------0-----------------------

实践教程

以及恒定学习速率和线搜索的实现

梯度下降算法就像一个球滚下山坡。克劳迪奥·泰斯塔在 Unsplash 上拍摄的照片

**Table of Contents** (read till the end to see how you can get the complete python code of this story)· [What is Optimization?](#0050)
· [Gradient Descent (the Easy Way)](#04b4)
· [Armijo Line Search](#9f3c)
· [Gradient Descent (the Hard Way)](#86f7)
· [Conclusion](#774e)

什么是优化?

如果你研究机器学习的时间足够长,你可能会听说过诸如 SGD 或 Adam 这样的术语。它们是许多优化算法中的两种。优化算法是机器学习的核心,负责机器学习模型从数据中学习的复杂工作。事实证明,优化已经存在很长时间了,甚至在机器学习领域之外。

人们优化。投资者寻求创建能够避免过度风险、同时实现高回报率的投资组合。制造商的目标是在生产过程的设计和操作中实现最大效率。工程师调整参数以优化他们设计的性能。

Jorge Nocedal 的数值优化书的第一段已经解释了很多。它继续说,即使是自然优化。物理系统趋向于最小能量状态。孤立的化学系统中的分子相互反应,直到它们的电子总势能最小。光线沿着最小化其传播时间的路径行进。

为了理解什么是优化,首先,我们必须确定目标,它可能是回报率、能量、旅行时间等。该目标取决于被称为变量的系统的某些特征。我们的目标是找到优化目标的变量的值。在某种程度上,变量通常是受约束的。

从数学上来说,优化是通过搜索适当的变量 x 来最大化或最小化目标函数 f(x) 的过程,该过程受到一些约束 cᵢ 的约束,可以简洁地写成如下。

其中ℰ和ℐ分别是平等和不平等约束的指数集。

乍一看,这种数学陈述确实令人望而生畏,也许是因为它是对优化的一般描述,在这里没有太多可以推断的。但是不要担心,到我们得到代码的时候,一切都会清楚的。

梯度下降(最简单的方法)

现在,我们如何求解 min 函数?多亏了微积分,我们有了一个叫做梯度的工具。想象一下山顶上有一个球。我们知道这座山在不同的地方有不同的坡度。由于重力的作用,球会沿着山坡的曲线下降。它往哪边走?到最陡的坡度。一段时间后,球将到达局部最小值,此时地面相对于其周围环境是平坦的。

这就是梯度下降的本质。我们可以将球的平滑路径量化为微小的步长。在第 k 步,我们会有两个量:步长 αₖ 和方向 pₖ 。为了看到渐变下降的效果,让我们首先导入一些库。

首先,我们将定义一个简单的目标函数f(x)= x2x 3,其中 x 是实数。由于梯度下降使用梯度,我们也将定义 f 的梯度,它正好是 f 的一阶导数,即∇f(x)= 2x 2

接下来,我们定义 python 函数,用于在优化过程中绘制目标函数和学习路径。我们所说的学习路径就是每个下降步骤后的点 x

从下面的图中,我们可以很容易地看到 fx = 1 处有一个最小值(因此 f(x) = -4 )。假设我们从 x = -4 (下面用红点表示)开始,我们将看看梯度下降是否能定位到局部最小值 x = 1

图片作者作者

定义一个简单的梯度下降算法如下。对于步骤 k 开始时的每个点 xₖ ,我们保持步长 αₖ 不变,并将方向 pₖ 设置为梯度值的负值(在 xₖ 处最陡下降)。我们使用公式采取步骤

而梯度仍然高于某个容差值(在我们的例子中为 1 × 10⁻⁵),并且步数仍然低于某个最大值(在我们的例子中为 1000)。

x = -4 开始,我们用不同的场景在 f 上运行梯度下降算法:

  • αₖ = 0.1
  • αₖ = 0.9
  • αₖ = 1 × 10⁻⁴
  • αₖ = 1.01

情景 1: αₖ = 0.1

Solution found:
  y = -4.0000
  x = 1.0000

图片作者作者

情景 2: αₖ = 0.9

Solution found:
  y = -4.0000
  x = 1.0000

图片作者作者

情景 3: αₖ = 1 × 10⁻⁴

Gradient descent does not converge.

图片作者作者

情景 4: αₖ = 1.01

Gradient descent does not converge.

图片由作者

这是我们得到的信息:

  • 第一个场景像魔咒一样收敛。即使步长是恒定的,方向也向零减小,因此导致收敛。
  • 第二种情况也是收敛的,即使学习路径由于大步长而在解附近振荡。
  • 第三个场景走向解决方案。但是步长太小,以至于迭代次数达到最大。增加max_iter将会解决问题,尽管需要更长的时间才能找到解决方案。
  • 第四种情况由于大步长而发散。在这里,我们设置max_iter = 8,以使可视化更令人愉快。

总之,解 x = 1 可以通过具有合适步长的梯度下降来达到。

你可能会想,为什么我们不用精确的解析解:对 f 求导,然后求解 x 使得导数为零。对于我们之前的例子,我们会发现使 f 最小的 x 将满足∇f(x)= 2x 2 = 0,即 x = 1

是的,这是一条路。但是当你面对一个优化问题时,这并不是一个推荐的技术,在这个优化问题中, f 的导数很难计算或者不可能求解。

阿米霍线搜索

现在,我们可以从梯度下降算法中改进什么?我们之前看到,步长 α 在整个步骤中保持不变,错误选择 α 可能会导致步骤发散。我们能为每个步进方向寻找最佳的 α 吗?

进入线搜索

在线搜索策略中,该算法选择一个方向 pₖ (可以像最速下降-∇ f(x) 一样简单)并且沿着这个方向从当前迭代 xₖ 开始搜索具有更低函数值的新迭代。沿着 pₖ 移动的距离可以通过近似求解以下一维最小化问题来找到步长 α :

如前所述,通过精确求解,我们将从方向 pₖ 中获得最大收益,但是精确的最小化可能是昂贵的,并且通常是不必要的。取而代之的是,线搜索算法产生有限数量的试验步长,直到它找到一个宽松地接近最小的 f(xₖ + α pₖ) 。在新的点 xₖ₊₁ = xₖ + α pₖ ,计算新的搜索方向和步长,并重复该过程。

一个流行的不精确线搜索条件规定, αₖ 应该首先在目标函数 f 中给出一个足够的减少量,如所谓的阿米霍条件所测量的:

对于某些常数(0,1)* 。换句话说, f 的减少应与步长 αₖ 和方向导数∇ fₖpₖ 成比例。在迭代 xₖ 时,我们从一些初始的 αₖ 开始,当阿米霍条件不满足时,我们简单地用一些收缩因子 ρ 收缩 αₖ 。收缩过程将在某一点终止,因为对于足够小的 αₖ ,阿米霍条件总是满足的。*

下面是 Armijo 行搜索的代码。注意我们用 ρ = 0.5c₁ = 1 × 10⁻⁴

现在我们准备实现 Armijo 线搜索到梯度下降算法。

梯度下降(艰难的道路)

首先,我们定义一个更难求解的目标函数:格里万克函数。

我们将使用 Griewank 函数的二维版本( n = 2 )。为了说明一些问题,我们可以将这个函数绘制如下。

图片作者作者

我们可以看到这个函数有很多局部最优解。我们应该预料到梯度下降算法会陷入这些局部极小值之一。我们还可以注意到,全局最小值在 x = [ 0,0 ]处,其中 f(x) = 0

最后,让我们最后一次构建梯度下降算法。如前所述,我们使用来自阿米霍线搜索的 pₖ = -f(xₖ) 作为方向和 αₖ 作为步长。此外,将采取措施,直到满足以下停止标准之一:

  • 目标函数的梯度的范数足够接近零,也就是说,

  • 采取的步骤数是 1000

然后,我们创建一个 python 函数来创建两个图:

  • x 的学习路径以及 f(x) 的轮廓图
  • 每走一步 f(x) 的值

对于初始值 x₀ ,我们使用不同的场景对 f 运行梯度下降算法:

  • x₀ = [ 0,3 ]
  • x₀ = [ 1,2 ]
  • x₀ = [ 2,1 ]
  • x₀ = [ 1,3 ]
  • x₀ = [ 2,2 ]
  • x₀ = [ 3,1

场景 1: x₀ = [0,3]

*Initial condition: y = 1.5254, x = [0 3] Iteration: 1 	 y = 1.1245, x = [0.0000 2.3959], gradient = 0.7029
Iteration: 2 	 y = 0.6356, x = [0.0000 1.6929], gradient = 0.6591
Iteration: 3 	 y = 0.2558, x = [0.0000 1.0338], gradient = 0.4726
Iteration: 4 	 y = 0.0778, x = [0.0000 0.5612], gradient = 0.2736
Iteration: 5 	 y = 0.0206, x = [0.0000 0.2876], gradient = 0.1430
Iteration: 6 	 y = 0.0052, x = [0.0000 0.1447], gradient = 0.0723
Iteration: 7 	 y = 0.0013, x = [0.0000 0.0724], gradient = 0.0362
Iteration: 8 	 y = 0.0003, x = [0.0000 0.0362], gradient = 0.0181
Iteration: 9 	 y = 0.0001, x = [0.0000 0.0181], gradient = 0.0090
Iteration: 10 	 y = 0.0000, x = [0.0000 0.0090], gradient = 0.0045
Iteration: 11 	 y = 0.0000, x = [0.0000 0.0045], gradient = 0.0023
Iteration: 12 	 y = 0.0000, x = [0.0000 0.0023], gradient = 0.0011
Iteration: 13 	 y = 0.0000, x = [0.0000 0.0011], gradient = 0.0006
Iteration: 14 	 y = 0.0000, x = [0.0000 0.0006], gradient = 0.0003
Iteration: 15 	 y = 0.0000, x = [0.0000 0.0003], gradient = 0.0001
Iteration: 16 	 y = 0.0000, x = [0.0000 0.0001], gradient = 0.0001
Iteration: 17 	 y = 0.0000, x = [0.0000 0.0001], gradient = 0.0000
Iteration: 18 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000
Iteration: 19 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000Solution: 	 y = 0.0000, x = [0.0000 0.0000]*

图片作者作者

场景 2: x₀ = [1,2]

*Initial condition: y = 0.9170, x = [1 2] Iteration: 1 	 y = 0.7349, x = [0.8683 1.6216], gradient = 0.5225
Iteration: 2 	 y = 0.4401, x = [0.5538 1.2044], gradient = 0.5705
Iteration: 3 	 y = 0.1564, x = [0.2071 0.7513], gradient = 0.3932
Iteration: 4 	 y = 0.0403, x = [0.0297 0.4004], gradient = 0.1997
Iteration: 5 	 y = 0.0103, x = [0.0012 0.2027], gradient = 0.1011
Iteration: 6 	 y = 0.0026, x = [0.0000 0.1016], gradient = 0.0508
Iteration: 7 	 y = 0.0006, x = [0.0000 0.0508], gradient = 0.0254
Iteration: 8 	 y = 0.0002, x = [0.0000 0.0254], gradient = 0.0127
Iteration: 9 	 y = 0.0000, x = [0.0000 0.0127], gradient = 0.0063
Iteration: 10 	 y = 0.0000, x = [0.0000 0.0063], gradient = 0.0032
Iteration: 11 	 y = 0.0000, x = [0.0000 0.0032], gradient = 0.0016
Iteration: 12 	 y = 0.0000, x = [0.0000 0.0016], gradient = 0.0008
Iteration: 13 	 y = 0.0000, x = [0.0000 0.0008], gradient = 0.0004
Iteration: 14 	 y = 0.0000, x = [0.0000 0.0004], gradient = 0.0002
Iteration: 15 	 y = 0.0000, x = [0.0000 0.0002], gradient = 0.0001
Iteration: 16 	 y = 0.0000, x = [0.0000 0.0001], gradient = 0.0000
Iteration: 17 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000
Iteration: 18 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000
Iteration: 19 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000Solution: 	 y = 0.0000, x = [0.0000 0.0000]*

图片由作者

场景 3: x₀ = [2,1]

*Initial condition: y = 1.3176, x = [2 1] Iteration: 1 	 y = 0.8276, x = [1.3077 1.1907], gradient = 0.6583
Iteration: 2 	 y = 0.4212, x = [0.6639 1.0529], gradient = 0.5903
Iteration: 3 	 y = 0.1315, x = [0.2104 0.6750], gradient = 0.3682
Iteration: 4 	 y = 0.0320, x = [0.0248 0.3570], gradient = 0.1784
Iteration: 5 	 y = 0.0081, x = [0.0008 0.1803], gradient = 0.0900
Iteration: 6 	 y = 0.0020, x = [0.0000 0.0903], gradient = 0.0452
Iteration: 7 	 y = 0.0005, x = [0.0000 0.0451], gradient = 0.0226
Iteration: 8 	 y = 0.0001, x = [0.0000 0.0225], gradient = 0.0113
Iteration: 9 	 y = 0.0000, x = [0.0000 0.0113], gradient = 0.0056
Iteration: 10 	 y = 0.0000, x = [0.0000 0.0056], gradient = 0.0028
Iteration: 11 	 y = 0.0000, x = [0.0000 0.0028], gradient = 0.0014
Iteration: 12 	 y = 0.0000, x = [0.0000 0.0014], gradient = 0.0007
Iteration: 13 	 y = 0.0000, x = [0.0000 0.0007], gradient = 0.0004
Iteration: 14 	 y = 0.0000, x = [0.0000 0.0004], gradient = 0.0002
Iteration: 15 	 y = 0.0000, x = [0.0000 0.0002], gradient = 0.0001
Iteration: 16 	 y = 0.0000, x = [0.0000 0.0001], gradient = 0.0000
Iteration: 17 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000
Iteration: 18 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000
Iteration: 19 	 y = 0.0000, x = [0.0000 0.0000], gradient = 0.0000Solution: 	 y = 0.0000, x = [0.0000 0.0000]*

图片由作者

场景 4: x₀ = [1,3]

*Initial condition: y = 1.2852, x = [1 3] Iteration: 1 	 y = 1.0433, x = [1.4397 2.6729], gradient = 0.3230
Iteration: 2 	 y = 0.9572, x = [1.7501 2.5838], gradient = 0.2763
Iteration: 3 	 y = 0.8638, x = [1.9986 2.7045], gradient = 0.4098
Iteration: 4 	 y = 0.6623, x = [2.3024 2.9796], gradient = 0.5544
Iteration: 5 	 y = 0.3483, x = [2.6813 3.3842], gradient = 0.5380
Iteration: 6 	 y = 0.1116, x = [3.0054 3.8137], gradient = 0.3231
Iteration: 7 	 y = 0.0338, x = [3.1265 4.1133], gradient = 0.1618
Iteration: 8 	 y = 0.0141, x = [3.1396 4.2745], gradient = 0.0818
Iteration: 9 	 y = 0.0091, x = [3.1400 4.3564], gradient = 0.0411
Iteration: 10 	 y = 0.0078, x = [3.1400 4.3974], gradient = 0.0205
Iteration: 11 	 y = 0.0075, x = [3.1400 4.4179], gradient = 0.0103
Iteration: 12 	 y = 0.0074, x = [3.1400 4.4282], gradient = 0.0051
Iteration: 13 	 y = 0.0074, x = [3.1400 4.4333], gradient = 0.0026
Iteration: 14 	 y = 0.0074, x = [3.1400 4.4359], gradient = 0.0013
Iteration: 15 	 y = 0.0074, x = [3.1400 4.4372], gradient = 0.0006
Iteration: 16 	 y = 0.0074, x = [3.1400 4.4378], gradient = 0.0003
Iteration: 17 	 y = 0.0074, x = [3.1400 4.4381], gradient = 0.0002
Iteration: 18 	 y = 0.0074, x = [3.1400 4.4383], gradient = 0.0001
Iteration: 19 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 20 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 21 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000Solution: 	 y = 0.0074, x = [3.1400 4.4384]*

图片作者作者

场景 5: x₀ = [2,2]

*Initial condition: y = 1.0669, x = [2 2] Iteration: 1 	 y = 0.9886, x = [1.8572 2.2897], gradient = 0.2035
Iteration: 2 	 y = 0.9414, x = [1.9025 2.488 ], gradient = 0.2858
Iteration: 3 	 y = 0.8372, x = [2.0788 2.713 ], gradient = 0.4378
Iteration: 4 	 y = 0.6117, x = [2.3753 3.035 ], gradient = 0.5682
Iteration: 5 	 y = 0.2941, x = [2.7514 3.461 ], gradient = 0.5082
Iteration: 6 	 y = 0.0894, x = [3.0423 3.8777], gradient = 0.2863
Iteration: 7 	 y = 0.0282, x = [3.1321 4.1495], gradient = 0.1438
Iteration: 8 	 y = 0.0127, x = [3.1398 4.2931], gradient = 0.0726
Iteration: 9 	 y = 0.0087, x = [3.1400 4.3657], gradient = 0.0364
Iteration: 10 	 y = 0.0077, x = [3.1400 4.4021], gradient = 0.0182
Iteration: 11 	 y = 0.0075, x = [3.1400 4.4203], gradient = 0.0091
Iteration: 12 	 y = 0.0074, x = [3.1400 4.4294], gradient = 0.0045
Iteration: 13 	 y = 0.0074, x = [3.1400 4.4339], gradient = 0.0023
Iteration: 14 	 y = 0.0074, x = [3.1400 4.4362], gradient = 0.0011
Iteration: 15 	 y = 0.0074, x = [3.1400 4.4373], gradient = 0.0006
Iteration: 16 	 y = 0.0074, x = [3.1400 4.4379], gradient = 0.0003
Iteration: 17 	 y = 0.0074, x = [3.1400 4.4382], gradient = 0.0001
Iteration: 18 	 y = 0.0074, x = [3.1400 4.4383], gradient = 0.0001
Iteration: 19 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 20 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 21 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000Solution: 	 y = 0.0074, x = [3.1400 4.4384]*

图片作者作者

场景 6: x₀ = [3,1]

*Initial condition: y = 1.7551, x = [3 1] Iteration: 1 	 y = 1.5028, x = [2.8912 1.4543], gradient = 0.6001
Iteration: 2 	 y = 1.1216, x = [2.7619 2.0402], gradient = 0.6522
Iteration: 3 	 y = 0.7074, x = [2.7131 2.6906], gradient = 0.6214
Iteration: 4 	 y = 0.3449, x = [2.8471 3.2973], gradient = 0.5273
Iteration: 5 	 y = 0.1160, x = [3.0458 3.7858], gradient = 0.3246
Iteration: 6 	 y = 0.0361, x = [3.1298 4.0993], gradient = 0.1683
Iteration: 7 	 y = 0.0147, x = [3.1397 4.2673], gradient = 0.0854
Iteration: 8 	 y = 0.0092, x = [3.1400 4.3528], gradient = 0.0429
Iteration: 9 	 y = 0.0079, x = [3.1400 4.3956], gradient = 0.0214
Iteration: 10 	 y = 0.0075, x = [3.1400 4.4170], gradient = 0.0107
Iteration: 11 	 y = 0.0074, x = [3.1400 4.4278], gradient = 0.0053
Iteration: 12 	 y = 0.0074, x = [3.1400 4.4331], gradient = 0.0027
Iteration: 13 	 y = 0.0074, x = [3.1400 4.4358], gradient = 0.0013
Iteration: 14 	 y = 0.0074, x = [3.1400 4.4371], gradient = 0.0007
Iteration: 15 	 y = 0.0074, x = [3.1400 4.4378], gradient = 0.0003
Iteration: 16 	 y = 0.0074, x = [3.1400 4.4381], gradient = 0.0002
Iteration: 17 	 y = 0.0074, x = [3.1400 4.4383], gradient = 0.0001
Iteration: 18 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 19 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 20 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000
Iteration: 21 	 y = 0.0074, x = [3.1400 4.4384], gradient = 0.0000Solution: 	 y = 0.0074, x = [3.1400 4.4384]*

图片由作者

在前 3 种情况下,算法收敛到全局最小值,其中 f(x) = 0 ,尽管第一种情况似乎浪费了太多步骤,因为对于这种情况 x₀ 的第一个坐标已经是 0。

在最后 3 种情况下,算法陷入局部最小值,其中 f(x) = 0.0074 ,因为 x₀ 离坐标 0,0 太远。这并不奇怪,因为线搜索方法通过朝向函数值减小且梯度的范数接近零的方向来寻找 f 的最小值,因此当该方法获得梯度非常接近零的坐标时,该点被认为是函数最小值,而不管最小值是局部的还是全局的。

如果我们对原始目标函数f(x)= x2x3应用这个版本的梯度下降,我们会得到以下结果。

*Initial condition: y = 21.0000, x = -4 Iteration: 1 	 y = -4.0000, x = 1.0, gradient = 0.0000Solution: 	 y = -4.0000, x = 1.0*

图片作者作者

解决方法一步到位!

对此你怎么看?是因为新的梯度下降版本对于这个功能来说太大材小用了吗?还是这只是巧合,改变 ρ 等参数不会产生比原来简单的梯度下降更好的结果?请在下面的回复部分告诉我你的想法!

结论

在本文中,我们了解了梯度下降算法在优化问题中的工作,从简单的高中教科书问题到现实世界的机器学习成本函数最小化问题。简单的实现假设一个恒定的学习速率,而较难的实现使用 Armijo 线搜索来搜索学习速率。算法本身是最基本的,并且根据目标函数的性质有许多变化和实现。像许多其他优化算法一样,梯度下降算法可能会陷入局部最小值。

🔥你好!如果你喜欢这个故事,想支持我这个作家,可以考虑 成为会员 。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。如果你注册使用我的链接,我会赚一小笔佣金。

🔖想了解更多关于经典机器学习模型如何工作以及如何优化其参数的信息?或者 MLOps 大型项目的例子?有史以来最优秀的文章呢?继续阅读:**

*Albers Uzila

艾伯斯·乌兹拉*

从零开始的机器学习

*View list8 stories**Albers Uzila

艾伯斯·乌兹拉*

高级优化方法

*View list7 stories**Albers Uzila

艾伯斯·乌兹拉*

MLOps 大型项目

*View list6 stories**Albers Uzila

艾伯斯·乌兹拉*

我最好的故事

*View list24 stories**Albers Uzila

艾伯斯·乌兹拉*

R 中的数据科学

View list7 stories**

使用 Docker 构建图像的完整教程

原文:https://towardsdatascience.com/complete-tutorial-on-building-images-using-docker-1f2be49ea8a6?source=collection_archive---------16-----------------------

通过一个设置 Ubuntu、默认用户、Miniconda、PyTorch 的例子来了解使用 Docker 编写 Dockerfile 和运行容器所需的一切。

Docker 提供了一种在主机操作系统上运行你的程序的方法。 Dockerfile 提供了关于如何构建映像的说明,然后这些映像作为容器运行。这篇文章讨论了创建 Dockerfile 所需的所有东西,并以设置 Ubuntu 、 Miniconda 和 PyTorch 为例。

建立形象

docker build命令用于从Dockerfile上下文(路径或 URL)构建图像。上下文是指构建命令中指定的所有文件。构建映像的步骤如下

  • 上下文指定的所有文件都被发送到 docker 守护进程。因此,您应该在空目录中创建 Dockerfile,以避免不必要的传输。
  • 检查 docker 文件是否有语法错误
  • Docker 守护程序通过读取来自Dockerfile的指令开始构建映像。

指定上下文

上下文可以是本地文件系统上的PATH或引用 Git 存储库的远程URL。下面显示了一个指定构建上下文的示例

> docker build .> docker build /path/to/context

用 URL 指定上下文

Docker 还为您提供了从 Git URL 构建图像的能力。这主要用于持续集成管道。要使用 URL 构建映像,docker 文件应该位于指定的 URL(而不是本地文件系统)。docker build从 Github URL 构建图像时,将自动执行以下步骤

> git clone {GITHUB_URL}
> git checkout {BRANCH}
> cd repo
> docker build .

构建映像的命令如下

> docker build {GITHUB_URL}#{BRANCH}> docker build https://github.com/KushajveerSingh/Dockerfile.git#master

注意:- 由于指定位置没有 Dockerfile,上述命令将失败。

指定 Dockerfile 文件的位置

您可以使用-f标志来指定 Dockerfile 的路径。默认情况下,假定 Dockerfile 位于上下文的根位置。

> docker build -f /path/to/Dockerfile .> docker build -f ubuntu_conda_pytorch/Dockerfile https://github.com/KushajveerSingh/Dockerfile.git#master

Docker 会自动将cd放入 Github 存储库,所以路径不应该包含存储库的名称。

指定存储库和标签

考虑下面的 Dockerfile 文件

FROM ubuntu:18.04LABEL PURPOSE = "test Dockerfile"

当我们构建一个映像时,docker 分配一个提交散列作为IMAGE ID

您可以为每个 docker 图像指定一个存储库和标签,然后使用-t标志轻松访问该图像。REPOSITORY可以被认为是你的 Github 库的名字,而TAG是用来指定你的镜像版本的。比如,ubuntu:18.04ubuntu:latest

您也可以指定多个标签

> docker build -t test:0.1 -t test:latest .

Docker 图像层

Docker 守护进程从上到下逐个运行指令。并且大多数指令的结果(FROMADDCOPY)被提交给新的图像。由于这个原因,你需要小心使用这些指令,因为每一次使用它们都会导致创建一个新的图像,从而增加最终图像的大小。

Docker 为什么要这么做?考虑下面的 Dockerfile 文件

FROM ubuntu:18.04RUN COMMAND_1
RUN COMMAND_2
RUN COMMAND_1

现在,当我们建立的形象,我们将创建以下层

  • 来自ubuntu:18.04 Dockerfile 的层
  • RUN COMMAND_1将创建一个新层
  • RUN COMMAND_2将创建一个新层
  • RUN COMMAND_3将创建一个新层

层基本上是图像或中间图像上的变化。每当我们运行一条指令(如FROMRUNCOPY)时,我们都在对之前的图像进行修改。这些变化导致新层的创建。拥有中间层有助于构建过程。如果您在 Docker 文件中进行了更改,那么 Docker 将只构建被更改的层和之后的层。这样可以节省很多时间。

注意:- 创建新图层时要小心,因为这会增加图像的尺寸。

构建工具包

Docker 支持 moby/buildkit 后端构建映像。与 Docker 提供的默认实现相比,BuildKit 提供了许多好处

  • 检测并跳过未使用的构建阶段
  • 并行构建独立的构建阶段
  • 在两次构建之间,仅增量传输构建上下文中已更改的文件
  • 检测并跳过在您的构建上下文中传输未使用的文件
  • 使用具有许多新特性的外部 Dockerfile 实现
  • 避免其他 API(中间图像和容器)的副作用
  • 为自动修剪设置构建缓存的优先级

要使用 BuildKit 后端,您需要设置DOCKER_BUILDKIT=1环境变量。

> DOCKER_BUILDKIT=1 docker build .

运筹学

> export DOCKER_BUILDKIT=1
> docker build .

摘要

总之,要构建 Docker 映像,可以使用以下命令

转义字符

这是一个解析器指令的例子。解析器指令是在 Dockerfile 的第一行中指定的,不会向构建中添加层。您可以使用这个来指定在 Dockerfile 中换行的字符。

# escape=\
FROM ubuntu:18.04RUN INSTRUCTION_1 \
    INSTRUCTION_2

在 Windows 上\用于指定路径。因此,将它更改为类似于反勾号的东西会很有用。

# escape=`
FROM ubuntu:18.04RUN INSTRUCTION_1 `
    INSTRUCTION_2

所有 Dockerfile 文件都以FROM指令开始。FROM初始化新的构建阶段,并为后续指令设置基础映像。一般语法是

FROM [--platform=<platform>] <image>[:tag] [AS <name>]

这里的[…]表示可选。您可以从一个零映像开始,并在此基础上构建一切

FROM scratch

或者你可以建立在一个公共形象之上(比如 Ubuntu 、 PyTorch 、 nvidia/cuda )

FROM ubuntu:18.04

在这篇文章中,我建立在 Ubuntu 图像之上。您可以使用以下命令构建映像并尝试运行它

> DOCKER_BUILDKIT=1 docker build -t test:0.1 .
> docker run -it --name temp test:0.1

您会看到这是一个基本安装。它没有任何用户或 sudo。它为我们提供了 Linux 内核,我们必须在此基础上构建一切。

在接下来的几节中,我们将查看 docker 文件中的所有指令,然后我们将使用所有这些指令构建一个 Ubuntu/Miniconda/PyTorch 映像。

参数和环境

环境变量通常用于在脚本中声明变量,或者设置一些在容器运行时会持续存在的变量。Docker 允许我们用两种方式设置变量:ARGENV

  • ARG指令定义了一个变量,用户将在编译时通过使用--build-arg <name>=<value>标志的docker build命令传递该变量。这些将只在 Dockerfile 文件中使用。
  • ENV指令设置 Dockerfile 文件中的环境变量,当从结果图像运行容器时,环境变量将持续存在。

我们可以将 Ubuntu 的版本指定为ARG(docker file 的代码如下所示)

ARG UBUNTU_VERSION
FROM ubuntu:$UBUNTU_VERSION

然后我们可以在构建映像时指定 ubuntu 的版本

> DOCKER_BUILDKIT=1 docker build -t test --build-arg UBUNTU_VERSION=18.04 .

我们还可以为ARG指定一个默认值,如下所示

ARG UBUNTU_VERSION=18.04

要访问ARG的值,可以使用$UBUNTU_VERSION${UBUNTU_VERSION}语法。当您想要访问字符串中的值ARG时,第二种方法很有用。

使用ARG

  • 对于只在 docker 文件中需要而在容器运行时不需要的变量,使用ARG。在这种情况下,当容器运行时,不需要 Ubuntu 的版本。
  • FROM之前使用的ARG只能在FROM中使用
  • FROM之后使用的ARG可以在 docker 文件中的任何地方使用(在多阶段构建的情况下有一个例外,即当我们在同一个 docker 文件中使用多个FROM指令时)

包封/包围(动词 envelop 的简写)

这与ARG相同,除了当容器从结果图像运行时ENV将持续。这方面的一个例子包括

ENV PYTORCH_VERSION 1.9.0
ENV LD_LIBRARY_PATH /usr/local/nvidia/lib:/usr/local/nvidia/lib64# Setting PATH variables
ENV PATH  /home/default/miniconda3/bin:$PATH

贴上标签并曝光

这两个说明可以被认为是文档说明。Dockerfile 中的这些指令对图像没有影响,它们只是用来提供元数据信息。

标签

LABEL可用于指定 Dockerfile 的作者等相关信息

LABEL author = "Kushajveer Singh"
LABEL email = "kushajreal@gmail.com"
LABEL website = "kushajveersingh.github.io"

构建图像后,您可以获得标签列表,如下所示

揭露

EXPOSE指令通知 Docker 容器在运行时监听指定的网络端口。它实际上并不发布端口。它只是作为构建映像的人和运行容器的人之间的一种文档,说明打算发布哪些端口。

EXPOSE 8889
EXPOSE 80/udp
EXPOSE 80/tcp

现在,运行容器的人可以使用-p标志指定端口,如下所示

> DOCKER_BUILDKIT=1 docker build -t test .
> docker run -p 80:80/tcp -p 80:80/udp test

添加并复制

我们在开始时讨论过,在读取 Docker 文件之前,会将一个上下文传递给 Docker 守护进程。现在,要从上下文向图像添加文件,我们可以使用ADDCOPY。两个指令相似,但是ADD做了一些额外的事情(你需要小心)。两个命令的语法是相同的

ADD [--chown=<user>:<group>] <src>... <dest>COPY [--chown=<user>:<group>] <src>... <dest>

一个使用示例是

COPY --chown=default:sudo /file/on/local/drive /path/on/imageCOPY --chown=default:sudo script.sh /home/default

<dest>路径要么是绝对路径,要么是相对于WORKDIR的路径,我们将在后面讨论。

现在让我们看看每条指令之间的区别。

复制

COPY [--chown=<user>:<group>] <src>... <dest>

COPY指令从<src>复制文件或目录,并将它们添加到位于<dest>的容器文件系统中。除非您指定了--chown,否则这些文件是用默认的 UID 和 GID 0 创建的。就是这样。COPY会将一个文件从<src>复制到<dest>

注意缺陷障碍 (Attention Deficit Disorder)

ADD [--chown=<user>:<group>] <src>... <dest>

ADD指令也像COPY一样将文件或目录从<src>复制到<dest>,但它也做一些额外的事情

  • <src>可以是远程文件的 URL
  • 如果<src>是一个 tar 文件(identity,gzip,bzip2,xz ),那么它将被解压为一个目录。如果 tar 文件是一个远程 URL,那么它不会被解压缩

注意:- 由于 *ADD* 的这些额外特性,建议您使用 *COPY* ,除非您知道 *ADD* 到底在给图像添加什么。

工作方向

WORKDIR指令为 docker 文件中跟随它的任何RUNCMDENTRYPOINTCOPYADD指令设置工作目录。您可以根据需要多次使用该选项来设置工作目录。

WORKDIR /home/default
RUN ...# You can also provide path relative to previous WORKDIR
WORKDIR ../home

奔跑

该命令的语法是

RUN <command>

它将在一个 shell 中运行该命令(在 Linux 上默认为/bin/sh -c)。每个RUN指令将创建一个新层,因此,您应该尝试将多个RUN指令组合成一个逻辑组。

要对多个RUN指令进行分组,可以使用分号或&&

最好使用&&而不是;。原因是当您使用分号将多个命令分组时,无论前一条指令是否出错,下一条指令都会运行。&&的情况并非如此。如果一个命令失败,那么执行将停止,并且下一个命令将不会被执行。

这些都是我们创建 Docker 映像所需的说明。我留下了一些说明,因为我们不需要它们,但你可以查看完整的文档参考以了解关于这些命令的信息(如ENTRYPOINTCMDVOLUME)。

所有命令的摘要

  • FROM -每个 docker 文件都以这条指令开始,它提供了我们构建映像的基础映像
  • ARG——我们可以使用--build-arg指定命令行参数,只在 docker 文件中使用
  • ENV -将在 Dockerfile 中使用并在容器运行时保持的环境变量
  • LABEL -指定元数据,如作者姓名,...
  • EXPOSE -记录集装箱运行时计划使用的端口
  • COPY -将文件或目录从上下文添加到图像(仅复制文件)
  • ADD -将文件或目录从上下文添加到图像(可以从远程 URL 复制,自动解压缩 tar 文件)
  • WORKDIR -指定使用 path 的其他指令的工作目录
  • RUN -从 shell 运行任何命令
  • USER -设置容器运行时的默认用户

PyTorch Dockerfile,Ubuntu

基础图像

我们将使用 Ubuntu 作为基础图片。如前所述,它为我们提供了一个基本的 Linux 发行版,我们必须设置我们需要的一切。

ARG UBUNTU_VERSION=18.04
FROM ubuntu:$UBUNTU_VERSION

更新 ubuntu 并安装实用程序

在讨论正在发生的事情之前,让我们先检查一下文档

第一步是更新 Ubuntu。注意 Ubuntu 上的默认用户是root。之后,我们设置sudo和一个default用户,然后我们将不得不在这些指令后面加上sudo。这是通过使用

--fix-missing是可选的。它在依赖关系破裂的情况下使用,在大多数情况下,使用此标志可以帮助我们解决问题。因为我们是从全新安装开始的,所以这个标志没有什么作用。

apt install -y --no-install-recommends-y标志帮助我们绕过是/否提示。Ubuntu 中的每个包都有三个依赖项

  • 主要依赖关系
  • 推荐的软件包
  • 建议的套餐

默认情况下,Ubuntu 将安装主软件包和推荐软件包(要安装推荐软件包,您需要向apt install提供--install-suggests标志)。我们的主要目标是保持 docker 映像的大小最小,由于这个原因,我们不想浪费空间安装推荐的包。--no-install-recommends标志会这样做,因此我们只安装主要的依赖项。

现在你可以安装你可能需要的任何其他包,比如ca-certificates(需要curl)、sudocurlgit

第二步是清理不再需要的包,并清除所有本地缓存。这是通过使用

RUN apt clean && \
    rm -rf /var/lib/apt/lists/*

当我们安装包时,Ubuntu 在/var/cache中维护了一个包的缓存。这样做的原因是,如果升级时出现问题,我们无法访问网络连接,那么我们可以恢复到缓存中的旧版本来降级软件包。但是我们不需要 Docker 图像的缓存,所以我们可以使用apt clean删除它。具体来说,apt clean将删除/var/cache/apt/archives//var/cache/apt/archives/partial中的文件,留下一个lock文件和partial子目录。

/var/lib/apt存储与 apt 包管理器相关的数据。我们每次运行apt update时都会自动下载这些数据,因此没有必要存储这些数据,我们可以安全地删除这些数据,以使用rm -rf /var/lib/apt/lists/*减小图像大小。

注意:- 要在 *rm -rf /var/lib/apt/lists/** 之后安装一个软件包,你必须先运行 *apt update* ,然后才可以安装你需要的软件包。

设置 sudo 和默认用户

下一步是设置 root 帐户和默认用户。这样做的 docker 文件的内容如下所示

让我们看看在useradd每面旗都做了什么

  • -r用于创建系统帐户,即操作系统在安装过程中创建的帐户或 root 帐户
  • -m用于创建一个主目录,如果它不存在的话
  • -d /home/default用于提供主目录的位置
  • -s /bin/bash用于指定用户登录 shell 的名称。如果你愿意,可以跳过这个。
  • -g root -G sudo这个有意思。-g标志用于指定用户所属的组,而-G用于提供用户所属的其他组的列表。

默认情况下,root用户不是组sudo的成员,我们需要显式设置这一点。root拥有系统上的所有权限,但我们仍然需要一个sudo组。当用户属于sudo组时,这意味着用户可以使用他们的用户密码来执行sudo命令。

当我们在一个系统上有多个用户时,拥有一个sudo组是很有用的,每个用户都可以通过使用他们自己的用户密码获得root特权。

  • -u 1000用于提供用户 ID
  • $USERNAME是将要创建的用户的名称

默认情况下,在 Ubuntu 中,root 帐户没有设置密码。要设置密码,我们可以使用以下命令

echo "${USERNAME}:${PASSWORD}" | chpasswd

在完成上述步骤后,我们完成了以下工作

  • 增加了一个用户default
  • 用户default可以使用sudo su并使用default作为密码获得 root 权限

这里的讨论了sudo的一个错误,每次你试图用sudo执行一个命令时,你都会得到下面的警告信息

> sudo hello > /dev/null
sudo: setrlimit(RLIMIT_CORE): Operation not permitted

这个问题已经在最新的补丁中解决了,但是 Ubuntu 没有附带,所以要停止这个烦人的警告,你可以使用下面的命令

echo "Set disable_coredump false" >> /etc/sudo.conf

当你运行这个容器时,你会看到一个关于sudo的提示,如下所示

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

当你第一次用sudo运行一个命令时,这个消息将被删除,或者你可以通过添加~/.sudo_as_admin_successful文件来删除它。

touch /home/$USERNAME/.sudo_as_admin_successful

就这样,您已经设置了sudo和一个default用户。当你运行容器时,默认情况下你会是root。但是您可以使用下面的命令将默认用户设置为default

USER $USERNAME
WORKDIR /home/$USERNAME

到目前为止的 Dockerfile 文件摘要

我们的 docker 文件将包含以下内容

我们可以将所有更新 Ubuntu、设置sudo和默认用户的命令放在一个RUN命令中以节省空间。

访问 Nvidia GPU

要访问 Docker 容器中的主机 GPU,可以在运行容器时指定--gpus标志

> docker run --gpus all -it --name temp test:0.1> docker run --gpus 0,2 -it --name temp test:0.1

这只需要您在主机上安装 Nvidia 驱动程序,然后您可以使用 Docker 容器中的nvidia-smi来检查是否正在检测 GPU。

安装 Miniconda

Miniconda 可以用于一个简单的 python 设置。只需从文档页面(在本例中是 Python 3.9)获取最新的 Linux 安装程序的链接,并指定要安装 Miniconda 的位置

Miniconda 的设置非常简单

  • 设置MINICONDA_DOWNLOAD_LINKMINICONDA_INSTALL_PATH变量
  • 设置环境变量ENV PATH ${MINICONDA_INSTALL_PATH}/miniconda3/bin:$PATH,这将允许我们从文件系统中的任何地方运行 conda
  • 使用bash Miniconda.sh -b -p ./miniconda3安装 miniconda
  • 使用rm Miniconda.sh移除.sh文件以节省空间
  • conda init可以跳过,因为我们已经设置了ENV PATH
  • 使用conda update -y --all将 conda 软件包更新至最新版本

安装 PyTorch

现在我们准备安装 PyTorch。前往 PyTorch 安装页面获取您想要用来安装 PyTorch 的命令。

注意:- 由于某种原因 *numpy* 在我运行 *conda install* 命令时没有被安装,所以我必须添加 *pip install numpy* 命令。

移除 conda/pip 缓存

Conda 存储索引缓存、锁文件、tarballs 和未使用包的缓存。使用命令conda clean -afy可以安全移除这些以节省空间。所以把这个作为 Dockerfile 中的最后一个 conda 命令添加进去。

pip将缓存存储在~/.cache/pip中,该文件夹可以使用命令rm -rf ~/.cache/pip安全移除。

建立形象

现在我们已经准备好构建映像了。

> DOCKER_BUILDKIT=1 docker build -t test:0.1 .

然后我们可以运行一个容器来测试图像

> docker run --gpus all -it --name temp test:0.1
default@a7f862b6bf73:~$

我们可以尝试nvidia-smi来检查是否正在检测 GPU

正如我们所看到的,GPU 和主机的 Nvidia 驱动程序一起被检测到。接下来,我们可以尝试运行一些 PyTorch 命令

我们已经成功地安装了 PyTorch,并且拥有了一个正常工作的 Ubuntu 环境。下一节讨论构建映像、运行容器和将映像推送到dockerhub所需的各种docker命令。

有用的 Docker 命令

构建图像

我们已经在第一部分讨论了从 Dockerfile 构建图像的命令。

此处可访问docker build的参考。

列出所有图像

docker image ls可用于获取本地文件系统上所有图像的列表。

您可以使用这个命令来检查图像的SIZE并获取IMAGE ID,以防您忘记标记图像。Docker 将图像存储在 Linux 上的/var/lib/docker/中,但是弄乱这个文件夹的内容并不是一个好主意,因为 Docker 的存储很复杂,并且它取决于正在使用的存储驱动。

docker image ls的参考值可在处访问。

删除图像

通过指定标签或IMAGE ID,可以使用docker image rm删除图像。

docker image rm的参考值可在处访问。

如果您有许多未标记的图像,您可以使用docker image prune删除所有图像,而不是手动删除每一张图像。

docker image prune的参考可在处访问。

列出所有容器

docker container ls -a可用于列出所有容器(运行和停止)。如果您想只列出正在运行的容器,请使用docker container ls

我们可以得到所有集装箱的状态。在上述示例中,temp_1未运行,而temp_2正在运行。我们还可以看到容器没有使用任何PORTS

docker container ls的参考可在处访问。

启动容器

docker start可用于启动一个或多个停止的容器(docker container start也可用于此)。

> docker start temp_1
temp_1

docker start的参考可在处访问。

附加到容器

要打开一个新的终端会话,可以使用 docker 容器docker attach

> docker attach temp_1

此处可访问docker attach的参考值。

停止集装箱

docker stopdocker kill可用于停止多个运行中的集装箱。docker stop可以认为是优雅的一站。这两个命令的区别在于

  • docker stop。停止正在运行的容器。主进程将接收到SIGTERM,在一段宽限期后,将接收到SIGKILL
  • docker kill。杀死一个正在运行的容器。主进程将接收SIGKILL或用户使用--signal指定的任何信号
> docker stop temp_1
> docker kill temp_1

此处可访问docker stop的参考,此处可访问docker kill的参考。

删除容器

docker rm可用于删除停止的集装箱。

> docker rm temp_1

在某些情况下,您可能需要删除一个不存在的容器,同时不抛出错误。这可以按如下方式完成

> docker rm temp_1 || true

docker rm的参考可在处访问。

运行容器

docker run命令用于从图像中创建一个容器。使用该命令时,有许多有用的标志

> docker run -it --gpus all --name temp -p 8888:8888 test:0.1
  • -it将打开一个与容器连接的终端
  • --gpus all用于指定哪些 GPU 可以访问容器
  • --name temp容器的名称
  • -p 8888:8888发布端口。格式为{HOST_PORT}:{CONTAINER_PORT}。要在 docker 中使用 jupyter 笔记本,您需要发布一个端口。

此处可访问docker run的参考。

将新码头连接到集装箱

如果您想要将一个新的终端连接到一个正在运行的容器,那么您可以使用下面的命令

> docker exec -it {container_name} bash

docker attach {container_name}无法创建新的终端会话。它将连接到旧会话。

删除所有容器/图像

要删除系统上的所有 docker 容器和映像,您可以使用以下两个命令(按照指定的顺序)

# Remove all containers
> docker rm -vf $(docker ps -a -q)# Remove all images
> docker rmi -f $(docker images -a -q)

将图像推送到 Dockerhub

使用以下命令将图像推送到 Dockerhub

下面显示了一个工作示例

第一个参数(test:0.1)到docker tag是本地文件系统上映像的名称,第二个参数是 Dockerhub 上您想要将映像推到的位置。

上述命令的参考资料

  • docker login 链接
  • docker tag 链接
  • docker push 链接

链接

  • kushayveersingh/Dockerfile—您可以从这个存储库中访问 docker file 来构建您自己的映像。在自述文件中提供了所有可用 docker 文件的文档。
  • 所有的图片都可以在这个链接中找到。如果你想使用一个图像而不是图像的内容,那么你可以从上面的 Github 链接访问用于创建图像的 Dockerfile 并构建图像。

twitter , linkedin , github

原载于 2021 年 10 月 3 日https://kushajveersingh . github . io

关于如何在机器学习项目中使用 Hydra 的完整教程

原文:https://towardsdatascience.com/complete-tutorial-on-how-to-use-hydra-in-machine-learning-projects-1c00efcc5b9b?source=collection_archive---------3-----------------------

学习你需要知道的关于如何在你的机器学习项目中使用 Hydra 的一切。Hydra 的所有特性都将通过一个虚拟 ML 示例进行讨论。

为了提高 PyTorch 生态系统的标准化,脸书·艾在最近的博客文章中表示,他们将利用脸书的开源 Hydra 框架来处理配置,并提供与 PyTorch Lightning 的集成。这个帖子是关于九头蛇的。

如果你正在阅读这篇文章,那么我假设你熟悉什么是配置文件,为什么它们有用,以及它们如何增加可再现性。而且你也知道什么是噩梦 argparse 。一般来说,通过配置文件,你可以将所有的超参数传递给你的模型,你可以定义所有的全局常量,定义数据集分割,等等,而不需要接触你的项目的核心代码。

在九头蛇网站上,以下列出了九头蛇的主要特征:

  • 可从多个来源组合的分层配置
  • 可以从命令行指定或覆盖配置
  • 动态命令行制表符结束
  • 在本地运行您的应用程序,或者启动它以远程运行
  • 用一个命令运行具有不同参数的多个作业

在这篇文章的其余部分,我将通过一个用例的例子来逐一介绍 Hydra 的特性。所以跟着走吧,这将是一次有趣的旅程。

了解 Hydra 设置流程

安装 Hydra(我用的是版本1.0)

pip install hydra-core --upgrade

对于这篇博文,我将假设下面的目录结构,其中所有的配置都存储在一个config文件夹中,主配置文件被命名为config.yaml。为了简单起见,假设main.py是我们项目的所有源代码。

src
├── config
│   └── config.yaml
└── main.py

让我们从一个简单的例子开始,它将向您展示使用 Hydra 的主要语法,

*### config/config.yaml*

batch_size: 10
lr: 1e-4

以及相应的main.py文件

*### main.py* 
import hydra
from omegaconf import DictConfig

**@**hydra.main(config_path**=**"config", config_name**=**"config")
**def** **func**(cfg: DictConfig):
    working_dir **=** os.getcwd()
    **print**(f"The current working directory is {working_dir}")

    *# To access elements of the config
*    **print**(f"The batch size is {cfg.batch_size}")
    **print**(f"The learning rate is {cfg['lr']}")

**if** __name__ **==** "__main__":
    func()

运行该脚本将得到以下输出

> python main.py    
The current working directory is src/outputs/2021-03-13/16-22-21

The batch size is 10
The learning rate is 0.0001

:路径被缩短,不包括从根开始的完整路径。同样,您可以将 *config.yaml* *config* 传递给 *config_name*

发生了很多,我们一个一个解析吧。

  • omegaconf默认安装有hydra。它仅用于为func中的cfg参数提供类型注释。
  • @hydra.main(config_path="config", config_name="config")这是当任何函数需要配置文件中的内容时使用的主装饰函数。
  • 当前工作目录被更改main.py存在于src/main.py中,但输出显示当前工作目录是src/outputs/2021-03-13/16-22-21。这是使用九头蛇时最重要的一点。解释如下。

九头蛇如何处理不同的运行

每当使用python main.py执行一个程序时,Hydra 将在outputs目录中创建一个新文件夹,其命名方案如下outputs/YYYY-mm-dd/HH-MM-SS,即文件执行的日期和时间。想一想这个。Hydra 为您提供了一种维护每次运行日志的方法,而您不必为此担心。

执行python main.py后的目录结构是(现在先不要担心每个文件夹的内容)

src
├── config
│   └── config.yaml
├── main.py
├── outputs
│   └── 2021-03-13
│       └── 17-14-24
│           ├── .hydra
│           │   ├── config.yaml
│           │   ├── hydra.yaml
│           │   └── overrides.yaml
│           ├── main.log

实际上发生了什么?当你运行src/main.py时,hydra 将这个文件移动到src/outputs/2021-03-13/16-22-21/main.py然后运行它。您可以通过检查os.getcwd()的输出来验证这一点,如上例所示。这意味着如果你的main.py依赖于某个外部文件,比如说test.txt,那么你将不得不使用../../../test.txt来代替,因为你不再运行src目录中的程序。这也意味着您保存到磁盘的所有内容都是相对于src/outputs/2021-03-13/16-22-21/保存的。

Hydra 提供了两个实用函数来处理这种情况

  • hydra . utils . Get _ original _ CWD():获取原当前工作目录,即src
orig_cwd **=** hydra.utils.get_original_cwd()
path **=** f"{orig_cwd}/test.txt"*# path = src/test.txt*
  • hydra . utils . to _ absolute _ path(文件名):
path **=** hydra.utils.to_absolute_path('test.txt')

*# path = src/test.txt*

让我们用一个简短的例子来概括一下。假设我们想读取src/test.txt并将输出写入output.txt。完成此操作的相应函数如下所示

**@**hydra.main(config_path**=**"config", config_name**=**"config")
**def** **func**(cfg: DictConfig):
    orig_cwd **=** hydra.utils.get_original_cwd()

    *# Read file
*    path **=** f"{orig_cwd}/test.txt"
    **with** open(path, "r") **as** f:
        **print**(f.read())

    *# Write file
*    path **=** f"output.txt"
    **with** open(path, "w") **as** f:
        f.write("This is a dog")

在运行python main.py之后,我们可以再次检查目录结构。

src
├── config
│   └── config.yaml
├── main.py
├── outputs
│   └── 2021-03-13
│       └── 17-14-24
│           ├── .hydra
│           │   ├── config.yaml
│           │   ├── hydra.yaml
│           │   └── overrides.yaml
│           ├── main.log
│           └── output.txt
└── test.txt

文件被写入 hydra 创建的文件夹。当你在开发一些东西的时候,这是一个保存中间结果的好方法。您可以使用此功能保存具有不同超参数的模型的精度结果。现在,您不必花费时间手动保存用于运行脚本的配置文件或命令行参数,也不必为每次运行创建一个新文件夹来存储输出。

注意 :每个 *python main.py* 都运行在一个新的文件夹中。为了保持上面的输出简短,我删除了之前运行的所有子文件夹。

主要的一点是使用orig_cwd = hydra.utils.get_original_cwd()来获得原始的工作目录路径,这样你就不必担心 hydra 在不同的文件夹中运行你的代码。

每个子文件夹的内容

每个子文件夹都有以下子结构

src/outputs/2021-03-13/17-14-24/
├── .hydra
│   ├── config.yaml
│   ├── hydra.yaml
│   └── overrides.yaml
└── main.log
  • config.yaml -传递给函数的配置文件的副本(如果您传递了foo.yaml也没关系,该文件仍将被命名为config.yaml)
  • hydra.yaml-hydra 配置文件的副本。我们稍后将看到如何更改 hydra 使用的一些默认设置。(您可以在此指定python main.py --help的消息)
  • overrides.yaml -您通过命令行提供的任何参数的副本,它改变了一个缺省值,将被存储在这里
  • main.log -记录器的输出将存储在此处。(对于foo.py,该文件将被命名为foo.log)

如何使用日志记录

有了 Hydra,你可以在代码中轻松使用 Python 提供的日志包,无需任何设置。日志的输出存储在main.log中。下面显示了一个使用示例

import logging

log **=** logging.getLogger(__name__)

**@**hydra.main(config_path**=**"config", config_name**=**"config")
**def** **main_func**(cfg: DictConfig):
    log.debug("Debug level message")
    log.info("Info level message")
    log.warning("Warning level message")

在这种情况下,python main.py的日志将会是(在main.log中)

[2021-03-13 17:36:06,493][__main__][INFO] - Info level message
[2021-03-13 17:36:06,493][__main__][WARNING] - Warning level message

如果您想将DEBUG也包括在内,那么覆盖hydra.verbose=truehydra.verbose=__main__(即python main.py hydra.verbose=true)。在这种情况下,main.log的输出将是

[2021-03-13 17:36:38,425][__main__][DEBUG] - Debug level message
[2021-03-13 17:36:38,425][__main__][INFO] - Info level message
[2021-03-13 17:36:38,425][__main__][WARNING] - Warning level message

OmegaConf 快速概述

OmegaCong 是一个基于 YAML 的分层配置系统,支持合并来自多个来源(文件、CLI 参数、环境变量)的配置。你只需要知道 YAML 就能使用九头蛇。OmegaConf 是九头蛇在后台用的,帮你处理一切。

您需要知道的主要内容显示在下面的配置文件中

server:
  ip: "127.0.0.1"
  port: ???       *# Missing value. Must be provided at command line*
  address: "${server.ip}:${server.port}" *# String interpolation*

现在在main.py中,您可以如下访问服务器地址

**@**hydra.main(config_path**=**"config", config_name**=**"config")
**def** **main_func**(cfg: DictConfig):
    server_address **=** cfg.server.address
    **print**(f"The server address = {server_address}")

*# python main.py server.port=10
# The server address = 127.0.0.1:10*

从上面的例子中你可以猜到,如果你想让某个变量和另一个变量取相同的值,你应该使用下面的语法address:${server.ip}。我们稍后将看到一些有趣的用例。

在 ML 项目中使用 Hydra

现在你知道了 hydra 的基本工作原理,我们可以专注于使用 Hydra 开发一个机器学习项目。查看这篇文章之后的 hydra 文档,了解这里没有讨论的一些内容。我也不会在这篇文章中讨论 结构化配置(YAML 文件的替代文件),因为没有它们你也可以完成所有的事情。

回想一下,我们项目的src目录有如下结构

src
├── config
│   └── config.yaml
└── main.py

我们有一个单独的文件夹来存储我们所有的配置文件(config),我们项目的源代码是main.py。现在让我们开始吧。

资料组

每个 ML 项目都是从收集数据和创建数据集开始的。在进行影像分类项目时,我们会使用许多不同的数据集,如 ImageNet、CIFAR10 等。每个数据集都有不同的相关超参数,如批次大小、输入影像的大小、类的数量、用于特定数据集的模型的层数等等。

我没有使用一个特定的数据集,而是使用一个随机的数据集,因为它可以使事情变得通用,你可以将这里讨论的东西应用到你自己的数据集上。此外,我们不要担心创建数据加载器,因为它们是一回事。

在讨论细节之前,让我向您展示代码,您可以很容易地猜到发生了什么。本例中涉及的 4 个文件是

  • src/main.py
  • src/config/config.yaml
  • src/config/dataset/dataset1.yaml
  • src/config/dataset/dataset2.yaml
*### src/main.py ###* 
import torch
import hydra
from omegaconf import DictConfig

**@**hydra.main(config_path**=**"config", config_name**=**"config.yaml")
**def** **get_dataset**(cfg: DictConfig):
    name_of_dataset **=** cfg.dataset.name
    num_samples **=** cfg.num_samples

    **if** name_of_dataset **==** "dataset1":
        feature_size **=** cfg.dataset.feature_size
        x **=** torch.randn(num_samples, feature_size)
        **print**(x.shape)
        **return** x

    **elif** name_of_dataset **==** "dataset2":
        dim1 **=** cfg.dataset.dim1
        dim2 **=** cfg.dataset.dim2
        x **=** torch.randn(num_samples, dim1, dim2)
        **print**(x.shape)
        **return** x

    **else**:
        **raise** ValueError("You outplayed the developer")

**if** __name__ **==** "__main__":
    get_dataset()

相应的配置文件是,

*### src/config/config.yaml*
defaults:
  - dataset: dataset1

num_samples: 2 *### src/config/dataset/dataset1.yaml*

*# @package _group_*
name: dataset1
feature_size: 5 *### src/config/dataset/dataset1.yaml*

*# @package _group_*
name: dataset2
dim1: 10
dim2: 20

老实说,这几乎是你在项目中使用 hydra 所需要的一切。让我们看看上面的代码中实际发生了什么

  • src/main.py中,您将看到一些通用变量,即cfg.datasetcfg.num_samples,它们在所有数据集之间共享。这些是在主配置文件中定义的,我们使用命令@hydra.main(...)传递给 hydra。
  • 接下来,我们需要定义一些特定于每个数据集的变量(比如 ImageNet 和 CIFAR10 中的类的数量)。为了在 hydra 中实现这一点,我们使用以下语法
defaults:
  - dataset: dataset1
  • 这里的dataset是文件夹的名称,该文件夹将包含每个数据集的所有对应的 yaml 文件(即本例中的dataset1dataset2)。所以目录结构看起来像这样
config
  ├── config.yaml
  └── dataset
      ├── dataset1.yaml
      └── dataset2.yaml
  • 就是这样。现在,您可以在上述每个文件中定义特定于每个数据集的变量,这些变量彼此独立。
  • 这些被称为配置组。每个配置文件都独立于文件夹中的其他配置文件,我们只能选择其中一个配置文件。为了定义这些配置组,您需要在每个文件# @package _group_的开头包含一个特殊的注释。

我们只能从*dataset1.yaml**dataset2.yaml*中选择一个配置文件作为 *dataset* 的值。为了告诉 hydra 这些是配置组,我们需要在这些文件的开头加上特殊的注释 *# @package _group_*

:在九头蛇 1.1 中, *_group_* 将成为默认的 *package* ,无需添加特殊注释。

  • 什么是默认值?在我们的主配置文件中,我们需要某种方法来区分普通的字符串值和配置组值。就像在这种情况下,我们希望将dataset: dataset1解释为一个配置组值,而不是一个字符串值。为此,我们在defaults中定义了所有的配置组。正如您所猜测的,您为它提供了一个默认值。

注意 : *defaults* 需要一个列表作为输入,所以需要每个名字都以一个 *-* 开头。

*defaults:
  - dataset: dataset1 *# By default use `dataset/dataset1.yaml*

*## OR*

defaults:
  - dataset: ???  *# Must be specified at command line**

我们可以检查上面代码的输出。

*> python dataset.py
torch.Size([2, 5])*

*> python dataset.py dataset=dataset2
torch.Size([2, 10, 20])*

现在停下来想一想。您可以使用同样的技术为所有优化器定义超参数值。只需创建一个名为optimizer的新文件夹,并写入sgd.yamladam.yaml文件。而在主config.yaml中,你只需要多加一行

*defaults:
  - dataset: dataset1
  - optimizer: adam*

您还可以使用它来创建学习率调度器、模型、评估指标和几乎所有其他东西的配置文件,而不必在主代码库中实际硬编码任何这些值。您不再需要记住用于运行该模型的学习率,因为用于运行 python 脚本的配置文件的备份始终存储在 hydra 创建的文件夹中。

模型

有一种特殊情况你也需要知道。当使用 ImageNet vs CIFAR10 时,如果您希望您的 ResNet 模型具有不同的层数,该怎么办?天真的解决方案是在每个数据集的模型定义中添加if-else条件,但这是一个糟糕的选择。如果明天你添加一个新的数据集。现在您必须修改您的模型if-else条件来处理这个新的数据集。因此,我们在配置文件中定义一个值num_layers,然后我们可以使用这个值来创建我们想要的层数。

假设我们使用两个模型,resnet 和 vgg。根据上一主题中的讨论,我们将为每个模型创建一个单独的配置文件。config文件夹的目录结构应该是

*config
├── config.yaml
├── dataset
│   ├── cifar10.yaml
│   └── imagenet.yaml
└── model
    ├── resnet.yaml
    └── vgg.yaml*

现在,假设我们希望 resnet 模型在使用 CIFAR10 时有 34 个层,而其他数据集有 50 个层。在这种情况下,config/model/resnet.yaml文件应该是

**# @package _group_*
name: resnet
num_layers: 50 *# As 50 is the default value**

现在,我们希望在用户指定 CIFAR10 数据集时设置值num_layers=34。为此,我们可以定义一个新的配置组,在其中我们可以定义所有特殊情况的组合。在主要的config/config.yaml中,我们将进行以下更改

*defaults:
  - dataset: imagenet
  - model: resnet
  - dataset_model: ${defaults.0.dataset}_${defaults.1.model}
    optional: true*

这里我们创建了一个名为dataset_model的新配置组,它采用由datasetmodel指定的值(就像imagenet_resnetcifar10_resnet)。这是一个奇怪的语法,因为defaults是一个列表,所以你需要在名字前指定索引,例如defaults.0.dataset。现在我们可以在dataset_model/cifar10_resnet.py中定义配置文件

**# @package _global_*
model:
  num_layers: 5*

:这里我们用 *# @package _global_* 代替 *# @package _group_*

我们可以如下测试代码,这里我们简单地打印出配置文件返回的特性数量

***@**hydra.main(config_path**=**"config", config_name**=**"config")
**def** **main_func**(cfg: DictConfig):
    **print**(f"Num features = {cfg.model.num_layers}")> python main.py dataset=imagenet
Num features = 50> python main.py dataset=cifar10
Num features = 34*

我们必须指定optional: true,因为如果没有它,我们将需要指定datasetmodel的所有组合(如果用户输入值datasetmodel,这样我们就没有该选项的配置文件,那么 Hydra 将抛出一个缺少配置文件的错误)。

本主题的文档。

流程的其余部分是相同的,为优化器、学习率调度程序、回调、评估指标、损失、培训脚本创建单独的配置组。就创建配置文件并在项目中使用它们而言,这是您需要知道的全部内容。

随机的事情

显示配置文件

在不运行函数的情况下,打印传递给函数的配置文件。用法--cfg [OPTION]有效OPTION

  • job:你的配置文件
  • hydra:九头蛇的配置
  • all : job + hydra

当您想要检查传递给函数的内容时,这对于快速调试非常有用。例子,

*> python main.py --cfg job
# @package _global_
num_samples: 2
dataset:
  name: dataset1
  feature_size: 5*

多次运行

这是九头蛇的一个非常有用的特性。查看文档了解更多详情。主要思想是你可以使用一个命令运行不同学习率值和不同权重衰减值的模型。下面显示了一个示例

*❯ python main.py lr**=**1e-3,1e-2 wd**=**1e-4,1e-2 **-**m
[2021**-**03**-**15 04:18:57,882][HYDRA] Launching 4 jobs locally
[2021**-**03**-**15 04:18:57,882][HYDRA]        *#0 : lr=0.001 wd=0.0001* [2021**-**03**-**15 04:18:58,016][HYDRA]        *#1 : lr=0.001 wd=0.01* [2021**-**03**-**15 04:18:58,149][HYDRA]        *#2 : lr=0.01 wd=0.0001* [2021**-**03**-**15 04:18:58,275][HYDRA]        *#3 : lr=0.01 wd=0.01**

Hydra 将使用lrwd的所有组合运行您的脚本。输出将存储在一个名为multirun(而不是outputs)的新文件夹中。该文件夹也遵循将内容存储在日期和时间子文件夹中的相同语法。运行上述命令后的目录结构如下所示

*multirun
└── 2021-03-15
    └── 04-21-32
        ├── 0
        │   ├── .hydra
        │   └── main.log
        ├── 1
        │   ├── .hydra
        │   └── main.log
        ├── 2
        │   ├── .hydra
        │   └── main.log
        ├── 3
        │   ├── .hydra
        │   └── main.log
        └── multirun.yaml*

它和outputs一样,除了这里为运行创建了四个文件夹,而不是一个。您可以查看文档,了解指定运行脚本的变量值的不同方式(这些被称为扫描*)。*

此外,这将在本地按顺序运行您的脚本。如果您想在多个节点上并行运行您的脚本或者在 AWS 上运行它,您可以查看以下插件的文档

  • 作业库 —使用作业库。平行
  • Ray —在 AWS 集群或本地集群上运行作业
  • RQ
  • 提交

给终端添加颜色

你可以通过安装这个插件来增加 Hydra 终端输出的颜色

*pip install hydra_colorlog **--**upgrade*

然后在配置文件中更改这些默认值

*defaults:
  - hydra/job_logging: colorlog
  - hydra/hydra_logging: colorlog*

指定帮助消息

您可以查看您的一次运行的日志(在.hydra/hydra.yaml下,然后转到help.template)来查看 hydra 打印的默认帮助信息。但是您可以在主配置文件中修改该消息,如下所示

**### config.yaml*hydra:
  help:
    template:
      'This is the help message'> python main.py --help
This is the help message*

输出目录名

如果您想要更具体的东西,而不是 hydra 用来存储所有运行输出的日期/时间命名方案,您可以在命令行指定文件夹名称

*python main.py hydra.run.dir=outputs/my_runORpython main.py lr=1e-2,1e-3 hydra.sweep.dir=multirun/my_run -m*

今天就到这里。希望这有助于您在项目中使用 Hydra。

twitter , linkedin , github

原载于 2021 年 3 月 16 日https://kushajveersingh . github . io。**

2021 年学习数据科学的完全免费路线图

原文:https://towardsdatascience.com/completely-free-roadmap-to-learn-data-science-in-2021-e0fa6147e247?source=collection_archive---------23-----------------------

简明的资源选择

德尔菲·德拉鲁阿在 Unsplash 上拍摄的照片

近年来,数据科学经历了辉煌的发展。越来越多的企业试图找到在运营中实施数据科学的方法。因此,对数据科学家的需求不断增加,这导致许多人转行从事这一领域的工作。

数据科学是一个不断发展的领域,它在传统教育体系中尚未得到很好的确立。因此,有抱负的数据科学家使用其他资源进行学习,如 MOOC 课程、博客、在线教程、youtube 频道等。

然而,这些资源实在太多了。人们甚至会在丰富的选择中感到迷茫。在本文中,我将提供一个路线图,其中包括学习数据科学的资源的精选列表。

我不会给出一堆清单,比如要读的书或要关注的 youtube 频道。相反,我将尽可能具体地说明,防止您四处寻找从哪里开始。

什么是数据科学?

第一步是获得数据科学的高级概述。我们需要全面了解数据科学意味着什么,它旨在解决什么样的问题,以及它是如何做到的。

数据科学是一个跨学科领域,包括统计学、编程、数学。商业智能和领域知识也是重要的软技能。了解数据科学中每个构件的作用是非常重要的。

以下教程提供了数据科学的全面概述。这是相当长的,但你不必一次完成。其实还是分成几段,一段一段的完成比较好。

  • 通过 freeCodeCamp (Youtube)学习数据科学教程

程序设计语言

数据科学生态系统中最受欢迎的两种语言是 Python 和 r。这两种语言都有大量的库和框架,可以加速和简化分配给数据科学家的典型任务。

Python 的范围更广,而 R 更侧重于统计计算。如果想学一门可以用在 web 开发等其他领域的编程语言,我建议学 Python。否则,对于数据科学相关的任务来说,两者都很好。

为了保持路线图简洁明了,我将选择其中一个,那就是 Python。我们的路线图包括 4 个学习 Python 的资源。

  • 计算机科学和 Python 编程简介

这是一门麻省理工学院的课程,录制并发布在 youtube 上。它包含 12 个讲座。

本课程为计算思维和编程提供了极好的介绍。一些基本的算法解释得很清楚,比如搜索和排序。面向对象编程的概念在本课程中也有很好的解释。

  • 计算思维和数据科学简介

这是第一道菜的延续。它包含 15 个讲座。

前两节课主要讲最优化问题。优化是任何机器学习的核心,因为模型试图基于一些约束优化损失函数。有了像样的理论知识,对实践方面肯定也有帮助。

本课程更侧重于机器学习和数据科学相关主题。例如,分类和聚类解释得非常清楚。

  • Calmcode.io

该网站提供分类的短视频教程。目前有 59 个类别的 428 个视频。

视频中的例子结构良好,解释清晰。根据主要类别对视频进行分组可以逐步提高技能。

  • Python 数据科学手册

这是杰克·范德普拉斯写的免费电子书。这是一本非常实用的书,包含大量代码示例。

顾名思义,用 Python 专注于数据科学。这本书全面介绍了 Python 最常用的数据科学库。

[可选]:如果你也想了解 R 如何处理数据科学相关的任务,下面这本书是一个好的开始。

  1. R 为数据科学(书)

统计数字

数据科学的组成部分之一是统计学。如果没有足够的统计知识,理解或解释数据将会非常困难。

统计学帮助我们解释数据。我们使用统计学根据从总体中抽取的样本来推断总体的结果。此外,机器学习和统计学有很多重叠之处。

我们的路线图包括两个统计资源。第一篇是一篇冗长的博客文章,全面介绍了数据科学中的统计学。

第二个是非常受欢迎的 youtube 频道,名为 StatQuest,由 Josh Stamer 创建。我真正喜欢 StatQuest 的是它如何清晰简单地解释概念。你不必浏览所有的视频。这更像是当你很难理解一个主题时使用的参考指南。然而,看所有的视频确实很有帮助。

  • 数据科学统计学(博客文章)
  • StatQuest (youtube 频道)

线性代数

数据以多种不同的格式收集,从数字到图像,从文本到声波。然而,我们需要将数据转换成数字,以便对其进行分析和建模。

仅仅将数据转换成标量(单个数字)是不够的。随着数据量的增加,用标量完成的操作开始变得低效。我们需要矢量化或矩阵运算来有效地进行计算。这就是线性代数发挥作用的地方。

我们很幸运能够免费上麻省理工学院 Gilbert Strang 教授的一堂优秀的线性代数课。

  • 吉尔伯特·斯特朗教授的线性代数

机器学习和深度学习

机器学习是数据科学的一个子领域。它允许计算机在没有明确编程的情况下从数据中学习。为了学习和实现机器学习,人们需要了解机器学习算法是如何工作的,以及用于实现它们的实用工具。

我分享两个机器学习的资源。第一个是谷歌准备的速成班。它提供了一个结构良好的机器学习概述。第二篇是我写的一篇博文,简要解释了 15 种流行的机器学习算法。

  • 谷歌的机器学习速成班
  • 15 个必须知道的机器学习算法

深度学习可以被认为是机器学习的一个子领域,其中算法是基于神经网络设计的。我建议,一旦你对机器学习算法和概念感到舒适,就开始致力于深度学习。

我分享两个深度学习的资源。第一本是由深度学习领域的先驱伊恩·古德菲勒、约舒阿·本吉奥和亚伦·库维尔写的书。伊恩·古德菲勒是生成性广告系列网络的创始人。

第二个是克里斯托弗·奥拉创建的博客。他非常清楚地解释了神经网络的内部工作机制。我强烈建议阅读他的文章,以便对神经网络有一个透彻的了解。

  • 深度学习书籍
  • 科拉的博客

熟能生巧

练习提高自己的技能是极其重要的。除此之外,拥有一门理论知识还不足以创造数据科学产品。你需要能够将你的想法付诸实施。

练习的另一个好处是你可以学到比阅读或观看资源更多的东西。当你试图解决一个问题时,你可能会遇到你没有预料到的问题。这些问题将帮助你了解非常有价值的信息。

我把练习分成三个部分:

作业环境

这是练习的首要要求。我们需要一个交互式的环境来实现代码。你可以在你的电脑上安装一个 IDE,比如 VSCode,或者使用一个基于网络的 IDE,比如 Google Colab。我建议先用 Google Colab,因为不用任何安装就可以瞬间开始编码。

数据集

数据科学的燃料是数据。没有适当的数据,即使是最先进的模型也无法创造任何价值。因此,我们需要数据集来练习。我会列出两个可以免费下载数据集的资源。你可以很容易地在网上找到更多的数据集。

  • Kaggle 数据集
  • UCI 机器学习知识库

挑战自我

练习的最后但并非最不重要的部分是挑战自己。

Kaggle 举办了很多比赛。有些是初级水平,你可以在其中练习基本技能。也有付费比赛,极具挑战性。

HackerRank 和 LeetCode 是在线平台,你可以在这里解决问题以提高技能。这些问题结构合理,分成几个部分,这样你就可以练习一个特定的主题。这个平台也可以作为你求职时的参考。

  • Kaggle 比赛
  • 黑客排名
  • LeetCode

最后的话

本文的目标是为您提供一个简明的资源列表,让您的数据科学知识达到一定的水平。我不认为这些资源会让你成为数据科学家。事实上,成为一名数据科学家需要更多的时间、努力和奉献。

数据科学是一个跨学科的领域,所以我试图以一种涵盖数据科学每个组成部分的方式来挑选资源。完成这些练习后,您将了解一名优秀的数据科学家应该具备的素质,以及成为一名高效的数据科学家需要具备哪些技能。

最后,我想列出数据科学生态系统中常用的 Python 库和框架。

  • 数据分析和处理:NumPy,熊猫
  • 数据可视化:Matplotlib,Seaborn,Altair
  • 机器学习和深度学习:Scikit-learn、TensorFlow、Keras、PyTorch

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

构建量子计算控件

原文:https://towardsdatascience.com/composing-quantum-computing-controls-f1acd83c48a8?source=collection_archive---------53-----------------------

如何创建受控-受控-非门

本帖是本书的一部分: 动手用 Python 学习量子机器

作者弗兰克·齐克特的图片

量子变换门允许我们使用量子位。RY-gate 允许我们指定量子位状态向量角度θ,该角度控制测量量子位的概率为01。我们用它让一个量子位代表边际概率。

作者弗兰克·齐克特的图片

X 门(非门)切换量子位的概率振幅。我们用它来设置一个量子位值给特定状态下的1。例如,在我们计算了边际概率之后,处理剩余的部分。

作者弗兰克·齐克特的图片

这是很有用的,因为当另一个量子位(控制量子位)处于|1⟩.状态时,一些门只对一个量子位(控制量子位)进行转换例如,受控的 RY-gate (CRY-gate)让我们指定边际剩余的联合概率和另一个概率。

作者弗兰克·齐克特的图片

呼叫器是一种复合门。在这篇文章中,我们学习了如何从更多的基本门创建这个门。首先,我们使用 CNOT 门。

乍一看,如果一个量子位是|1⟩,对另一个量子位应用 X-gate 的能力似乎并不重要。但是 X-gate 在创造更高级别的量子比特时起着核心作用,因为它纠缠着两个量子比特。概念上,纠缠量子比特共享一个叠加态。实际上,CNOT 门是大多数复合量子变换门的组成部分。

下面的代码描述了 CRY-gate 的分解。

作者弗兰克·齐克特的图片

如果你想应用某个门,当且仅当另外两个量子比特处于|1⟩态时,会怎么样?你可能会反对AND不是一个有效的量子位门。简单看一下真值表就知道AND算子是不可逆的。如果它的输出是 false,就无法判断输入是什么。它可能是三种不同状态中的一种。

作者弗兰克·齐克特的图片

但是 CNOT 门提供了一条出路。请记住,当我们构造 CRY-gate 时,我们使用 CNOT 门在整个旋转的前半部分和后半部分的旋转过程中转换受控量子位的振幅。类似的模式允许我们创建一个受控门。这种门包含一种AND关系,因为它有两个控制量子位,并且只有当两个控制量子位都处于|1⟩.状态时,它才改变受控量子位

下图描述了 CCNOT 门(一种受控-受控非门)的电路。

The CCNOT-gate is also known as the Toffoli-gate. The Toffoli-gate has a different algorithm than this one. The Toffoli-gate uses qubit phases. Phases are concept we cover later in this book. The implementation we presented here is not optimal but it provides a vivid explanation of the underlying concept.

作者弗兰克·齐克特的图片

下面的列表描述了这个 CCNOT 门序列的代码。我们定义了一个可重用的函数ccnot(第 4 行)。它以量子位 q0 作为控制量子位的受控旋转开始(第 6 行)。它将受控量子位旋转约θ=π/2,这是我们之前定义的值(第 2 行)。

然后,我们有另一个受控旋转,其量子位与控制量子位(第 11 行)相同,被封装到 CNOT 门(第 10 行和第 12 行)中。需要注意的是,这种封装的 CRY-gate 以θ为参数。它表示反方向旋转。

最后,我们有另一个关于θ的受控旋转,量子位 q1 是控制量子位。

让我们一个接一个地检查电路。首先,我们定义我们的θ=π/2(第 2 行)。值π/2 表示旋转了圆周的四分之一。这是我们想要应用的整体旋转的一半。旋转半圈(π)会将振幅从|0⟩转换到|1⟩,反之亦然。

在第一步中,如果量子位 q1 通过一个 CRY(π/2)门(第 8 行)处于|1⟩状态,我们旋转受控量子位大约四分之一圈。

如果两个控制量子位都处于|1⟩状态,这个门的结果如下图所示。

作者弗兰克·齐克特的图片

按照我们的初始化,两个控制量子位(从右到左读取)都处于|1⟩状态。然后,有一半的时间(按照大约π/2 的旋转),受控量子位处于|1⟩.状态

接下来,我们应用一系列 CNOT 门,q0 是控制量子位,q1 是受控量子位。因为 q0 处于|1⟩,所以它将 q1 的状态从|1⟩更改为|0⟩.随后用 q1 作为控制量子位的受控旋转没有影响,因为 q1 现在处于|0⟩状态,并且如果控制量子位处于|1⟩.状态,则 CRY-gate 仅改变受控量子位下一个 CNOT 门恢复了第一个 CNOT 门的效果。因为控制量子位 q0 仍然处于|1⟩状态,它将 q1 的状态从|0⟩状态切换回|1⟩.状态

如果两个控制量子位都处于|1⟩状态,这三个门根本没有作用。

最后,我们用 q0 作为控制量子位,施加一个约π/2 的受控旋转。这使得受控量子位 q2 的状态从一半时间处于|1⟩状态变为一直处于|1⟩状态。它将量子位状态向量旋转了圆周的四分之一,总共旋转了半圈。如下图所示,绕圆旋转半周,|0⟩就变成了|1⟩。

作者弗兰克·齐克特的图片

让我们看看代码和结果,如果两个控制量子位都处于|1⟩.状态

作者弗兰克·齐克特的图片

我们看到量子位 q2 一直处于|1⟩状态。它完全从初始状态|0⟩.

如果其中一个控制量子位不在|1⟩态呢?假设量子位 q0 处于|0⟩.态

同样,第一个 CRY-gate 将受控量子位的量子位状态向量旋转π/2——四分之一圈——因为控制量子位 q1 处于|1⟩.状态

但是这一次,下面的 CNOT 门不起作用。因为量子位 q0 处于|0⟩状态,它不会将量子位 q1 的状态从|1⟩切换到|0⟩.因此,θ=,π/2 的下述 CRY-gate 生效。它恢复了第一个哭泣之门的效果。因为量子位 q0 处于|0⟩.状态,所以随后的非门和最后的安全门不起作用因此,我们只应用了前两个 CRY-gate,第二个恢复了第一个。让我们看看代码和结果。

作者弗兰克·齐克特的图片

我们看到整体状态没有改变。受控量子位仍处于|0⟩.状态

最后,让我们看看,如果只有控制量子位 q0 处于|1⟩态,而量子位 q1 不处于,会发生什么。然后,第一次呼喊没有效果地通过了。封装在 CNOT-gates 中的第二个 CRY-gate 的以下序列首先将量子位 q1 从|0⟩切换到|1⟩,然后应用受控量子位的大约θ=-π/2 的旋转,并将量子位 q1 从|1⟩切换回|0⟩.现在受控量子位已经反方向旋转了半圈。下图描述了迄今为止的结果。

作者弗兰克·齐克特的图片

一半时间,受控量子位处于|1⟩.状态由于概率是我们通过旋转改变的振幅的平方,我们在这里看不到负值。

最后,由于控制量子位 q0 处于|1⟩.状态,最后一个 CRY-gate 将控制量子位往回旋转θ结果又是原始状态,如下面的代码和结果所示。

作者弗兰克·齐克特的图片

结论

我们通过 CNOT 门和哭泣门的组合创造了一个受控非门。我们甚至可以通过 CNOT 门和里门进一步创作哭喊门。这有效地显示了 CNOT 门的重要性。这不仅是解释量子纠缠的最好例子,也是制造更多受控门的基础。或受控门。甚至是受控门。你可以继续这个序列,直到你用完量子位。

本帖是本书的一部分: 用 Python 动手做量子机器学习

在这里免费获得前三章。

组合人工智能:企业人工智能的未来

原文:https://towardsdatascience.com/compositional-ai-the-future-of-enterprise-ai-3d5289dfa888?source=collection_archive---------15-----------------------

行业笔记

AI/ML 网格,集成数据操作、多操作、API 操作

摘要在过去的几年里,企业对人工智能/人工智能服务的采用显著加快。然而,大多数 ML 模型仍然是以解决单一任务为目标而开发的,例如预测、分类。在这项工作中,我们将提出合成人工智能的新兴范式,也称为合成学习。组合人工智能设想无缝组合现有的人工智能/人工智能服务,以提供一个新的(复合)人工智能/人工智能服务,能够解决复杂的多领域用例。在企业环境中,这在开发和维护工作中实现了重用、敏捷性和效率。

这是我最近在 2021 年 3 月 31 日俄罗斯斯科尔科沃举行的国际 数据融合会议 上发表的一篇主题演讲的扩展文章。( youtube 录制)( ppt )

企业人工智能

如今,企业 AI/ML 用例无处不在。企业用例可以根据支持它们的三个核心 AI/ML 功能进行大致分类:自然语言处理(NLP)、计算机视觉/图像识别和预测分析(如下图所示)。

企业人工智能用例(图片由作者提供)

在过去的 2-3 年里,我们一直在努力在企业中实现各种 AI/ML 用例。然而,我们一直专注于构建最具性能的模型

大多数 AI/ML 模型仍然是以解决单一任务为目标开发的,例如预测、分类。

考虑到这一点,是时候超越模型精度,转向更全面的组合 AI 框架,实现企业中已部署 AI/ML 解决方案的最大重用。

合成人工智能场景

人工智能合成示例—维修服务(图片由作者提供)

考虑一家奢侈品供应商的在线维修服务。这项服务包括一个计算机视觉( CV )模型,给定客户上传的产品图片,该模型能够评估所需的维修。如果用户对报价满意,评估之后将进行订购聊天机器人对话,获取处理用户维修请求所需的其他详细信息,例如产品损坏详细信息、用户名、联系方式等。

人工智能合成示例—产品推荐服务(图片由作者提供)

未来,当企业在找模特开发一个产品推荐服务;考虑维修服务。维修服务收集的数据:用户拥有的产品状态(由 CV 评估模型收集)及其人口统计数据(由订购聊天机器人收集)-为推荐服务提供额外的训练数据。然而,在这种情况下,CV 评估应用程序、订购聊天机器人[1]的隐私政策,或管理分层生态系统的任何全球隐私政策(例如,FTC FIPs [2],要求用户数据仅用于特定目的,对此用户已提供明确的选择加入)可能会阻止他们的数据被合并,这样,他们就不能用于描述客户。

人工智能合成示例—制造缺陷检测(图片由作者提供)

现在让我们考虑另一个分层组合场景,其中企业进一步希望开发一个 CV 应用程序/模型来检测制造过程中的缺陷产品维修服务可以提供帮助,因为它已经标记了受损产品的图像(提供给聊天机器人的产品损坏描述充当“标签”)。因此,它将标记的图像作为反馈环提供给 CV 模型,作为训练数据来改进其底层模型。

背景

组合性是指通过组合现有(组件)服务的功能来形成新(组合)服务的能力。现有的服务本身可能是组合的,从而导致分层组合。

这个概念不是新的,以前在不同的背景下研究过;最值得注意的是,Web 服务组合和安全协议的安全组合。

Web 服务组合

Web 服务遵循面向服务的计算(SOC)方法,将业务功能包装在自包含的服务中。组合服务主要有两种方法:动态和静态。在动态方法中,给定一个复杂的用户请求,系统根据运行时可用 Web 服务的能力提出一个满足请求的计划。在静态方法中,给定一组 Web 服务,组合服务是在设计时结合它们的功能手工定义的。

BPEL 是这种规范的一个很好的例子,它将现有的 Web 服务编排(或编排)到复杂的业务工作流中。在解决 Web 服务组合的发现[3]、监控[4]和可靠性[5]方面已经有了相当多的工作。

安全合成

安全合成协议的一个很好的例子是 Ran Canetti 的通用可合成(UC)框架[6]。

给定一个复杂的任务,基本思想是将该任务划分为多个更简单的子任务。然后,设计安全实现子任务的协议。UC 框架确保由(UC-secure)子协议组成的协议将继续保证在新颖、不可预测和敌对的执行环境中的安全性,即使其他协议同时运行。

ML 现有技术

集成学习

集成学习试图优化来自多个模型的预测,然而迎合了相同的问题

集成学习(图片来自作者)

常用的集成学习技术包括:Bagging、Boosting 和 Stacking。基本思想是分割训练数据,在分割的数据集上建立模型(预测器、分类器),然后组合模型-在预测的情况下,这可能意味着平均预测值;在分类的情况下,这可能意味着选择具有最高精度的输出。

在这种情况下,“整体”指的是融合模型,但不一定是融合解决不同问题的模型——组合人工智能的目标。

联合学习

联合学习(FL) [7] **,也称为协作学习或隐私保护机器学习,**使多个(不信任的)实体能够协作在它们的组合数据集上训练 ML 模型。

集成和联合学习的主要区别在于,这种情况下的训练数据属于不同的组织,这些组织可能不一定信任彼此来共享数据;但是仍然对开发具有与在组合数据集上训练的模型相当的精确度的全局模型感兴趣。

最近的工作考虑了基于 FL 的深度神经网络(DNNs)训练[8]。

深度神经网络的联邦训练(图片由作者提供)

  1. 所有节点同意相同的神经网络架构和任务来训练全局模型。协调器节点充当参数服务器,维护全局模型参数值的最新版本。
  2. 在每个时期,叶节点从它们的父节点下载全局模型参数,并且使用它们的本地数据集上的梯度下降的一些变体来本地更新它们;与协调器节点共享更新后的值。
  3. 协调器节点对从所有节点收集的参数值进行平均。
  4. 这种联合训练一直持续到全局模型收敛。

人工智能服务

在这种背景下,让我们回到绘图板,并尝试定义一个“人工智能服务”。

AI 服务:数据+模型+ API(图片作者提供)

在监督学习的非常原始的世界中,一个人工智能服务由(标记的)数据组成,用于训练一个模型,然后它被公开为一个 API

当然还有一个替代的部署管道,可以将一个经过训练的模型部署在一个边缘设备上,以离线方式执行[9]。然而,我们改天再讨论这个问题。

有趣的是,今天有重叠的方法,DataOps、MLOps 和 APIOps(或 API 管理)试图分别解决数据、模型和 API 的操作方面。

数据操作

DataOps 是一种自动化、面向流程的方法,由分析和数据团队使用,用于提高质量和缩短数据分析的周期时间—维基百科

在当今的大多数组织中,“数据湖”是执行不同数据转换步骤的分层平台:(免责声明:下面显示的工具绝不是对工具/供应商的认可;还有提供类似功能的替代工具,对其功能的详细比较超出了本文的范围。)

数据湖分层架构(图片由作者提供)

  • 数据摄取:侧重于从不同的数据源(传统、专有、云和内部)获取和保存数据。
  • 数据(预)处理:与清理、质量检查和提取/转换相关数据以进行集成相关。
  • 数据访问:这一层使用户和应用程序可以分别以报告和 API 的形式使用经过处理的数据。
  • 数据集成:是本次讨论中最有趣的一层。它显示了数据生态系统的成熟度,通过多种工具/框架从聚合数据中获得洞察力。数据集成方法的例子包括
    (i)联合:数据保留在原来的源系统中。联邦查询引擎负责分割给定的查询,并将子查询委托给它们各自的源系统;然后合并不同源系统返回的结果。
    (ii)数据集市:在这种情况下,数据被物理地移动,相关数据被复制、合并并存储为数据集市以备访问。
    (iii)知识图:捕获不同数据源之间的语义关系,使得能够利用确定的图结构进行复杂的查询。

不幸的是,今天缺乏类似的用于人工智能服务的集成/融合工具——这是组合人工智能的一个关键要求。

数据治理

到目前为止,我们已经考虑了操作部分:数据操作、MLOps、APIOps。

答案是否在于建立一个治理框架?

如下图所示,数据治理是一种横向能力,包含许多与数据相关的方面,例如,数据目录、数据字典、主数据管理(MDM)、数据起源和沿袭跟踪等。

治理框架(图片由作者提供)

在这种情况下,一个有希望的框架是 FAIR [9],它已经开始在医疗保健研究中被广泛采用。

  • F indable:数据对于人类和机器来说都应该容易找到,这意味着丰富的元数据和唯一/持久的标识符。
  • 可访问性:通过认证和授权条款,可以以可信的方式访问数据。
  • 互操作性:用于知识表示的共享本体,确保数据可以与多个应用程序/工作流进行互操作,以进行分析、存储和处理。
  • eusable:清晰的出处/沿袭规范和使用许可,这样数据可以在不同的环境中重用。

虽然从数据治理的角度来看,FAIR 非常有趣,但它如何在医疗保健研究之外被采用还有待观察。公平原则在指定数据血统和出处、最大化重用以及使用户能够决定哪些数据适合他们的目的方面提供了指导。软件/ ML 代码部分——不考虑数据如何转换。这导致了潜在的开放数据与开源软件框架的冲突。开放数据许可证(如 Creative Commons)与更成熟的开源软件(如 Apache、MIT [10])大相径庭。

很有可能我们会陷入另一场标准化/许可混乱,而不是一个以统一方式存储、访问和分析数据和模型(代码)的综合框架。

伦理人工智能——合成人工智能中的隐私问题

另一个值得注意的治理趋势是企业中的道德 AI 治理框架/委员会,其任务是确保 AI/ML 应用程序得到负责任的培训和部署,符合企业战略和政策。不同的政府组织和监管机构发布了各自的指导方针和政策,对术语的定义几乎没有达成一致,这使得这项工作变得复杂,例如,“公平”的定义有 20 多种。

伦理人工智能包含许多人工智能/人工智能原则,例如,可解释性、偏见/公平、问责制和隐私。在这篇文章中。我们关注隐私方面。关于其他方面的讨论,请参考[11]。

组合设置中的主要隐私问题是(训练的)模型可能仍然包含专有信息或泄露与基础训练数据集相关的见解[12]。

这是因为(在反向传播过程中)DNN 给定图层的梯度是使用该图层的特征值和下一图层的误差来计算的。例如,在顺序完全连接的层的情况下,

误差 E 相对于 toW_l 的梯度定义为:

也就是说,W_l 的梯度是来自下一层的误差和特征 h_l 的内积;以及梯度和特征之间的相关性。这就是 esp。如果权重矩阵中的某些权重对参与者数据集中的特定特征或值敏感(例如,语言预测模型中的特定单词[13]),则为 true。

在这种情况下,联邦贸易委员会最近的裁决[14]指出,当用户选择退出时,仅仅删除数据是不够的;组织还需要删除根据该数据训练的模型/算法。

在组合设置中实施这一点需要捕获直接或间接访问底层(受影响的)培训数据的(较高级别的)组合服务。

类似地,如前所述,隐私政策,例如 FTC FIPs [2],建议数据仅用于特定目的(用户已明确选择加入),并且不与其他数据集结合以揭示可用于描述用户的额外见解。

在组合设置中,这种数据聚合可能很难检测,因为(更高)级别的组合服务可以(通过中间服务)聚合属于不同服务的数据,而无需它们的明确批准。

结论

总之,我们在本文中介绍了组合人工智能的新兴范例。一旦我们有了复合 AI/ML 服务,由多个(组件)AI/ML 服务组成;我们考虑过

你如何获取潜在不同服务的部分信息,底层数据、模型、APIs 并以无缝的方式组合新的服务,照顾治理、隐私、血统和其他伦理/非功能方面——是组合 AI/ML 的全部挑战。

合成 AI/ML 摘要(图片由作者提供)

参考

  1. D.比斯瓦斯。隐私保护聊天机器人对话。在保护隐私的机器学习研讨会(PPML),2020 年,https://ppml-workshop.github.io/pdfs/Biswas.pdf
  2. R.盖尔曼。公平信息实践:基础历史—版本 2.20 。2021.doi: 10.2139/ssrn.2415020。
  3. D.比斯瓦斯。Web 服务发现和约束组合。2007 年经常资源:73-87。
  4. D.维德亚桑卡·比斯瓦斯。监控分层 Web 服务组合。TES 2005 年:98–112。
  5. D.维德亚桑卡·比斯瓦斯。受限可见性下分层 Web 服务组合的最优补偿。IEEE APSCC 2009:293–300。
  6. 兰·卡内蒂。2020.普遍可组合证券。J. ACM 67,5,第 28 条(2020 年 10 月)。
  7. D.比斯瓦斯。联邦学习——隐私保护机器学习。(中型)
  8. B.麦克马汉等人。艾尔。从分散数据进行深度网络的通信高效学习。AISTATS 2017:1273–1282。
  9. 公平行事。科学数据管理和监督的公平指导原则 ( 链接)
  10. D.比斯瓦斯。*在企业中管理开源软件。*中等,2020( 链接)
  11. D.比斯瓦斯。伦理人工智能:其对企业人工智能用例及治理的影响。在 2020 年 12 月举行的 Linux 基金会开放合规峰会上发表(中)
  12. Nasr,m .,Shokri,r .,& Houmansadr,A. (2019)。深度学习的综合隐私分析:针对集中式和联邦式学习的被动和主动白盒推理攻击。2019 年 IEEE 安全与隐私研讨会(SP),739–753。
  13. H.b .麦克马汉、e .摩尔、d .拉梅奇、s .汉普森和 B. A .阿卡斯。从分散数据中进行深度网络的通信高效学习, 2017,https://arxiv.org/abs/1602.05629
  14. 联邦贸易委员会。2021 年,加州公司解决了 FTC 指控其在照片存储应用中使用面部识别欺骗消费者的问题

利用人工智能的组合成像来改进乳腺癌检测

原文:https://towardsdatascience.com/compositional-breast-imaging-with-artificial-intelligence-to-improve-cancer-detection-c5f8f38f2266?source=collection_archive---------20-----------------------

癌症研究与技术

我们使用双能 X 射线成像技术和神经网络来研究新的健康成分成像生物标志物

癌性和非癌性乳腺病变类型的成分热图。作者图片

摘要

  • 本文是对标题为“双能量三室乳腺成像用于成分生物标记物以改善恶性病变检测”的文章的直接回应。
  • 成分乳腺成像允许发现新的癌症生物标志物
  • 成分信息与诊断相关,有助于改善癌症检测,从而减少不必要的活检数量。

https://rdcu.be/cSENN

当前乳腺癌成像技术

截至今天,(2021)乳腺癌是全球女性癌症死亡的主要原因。有几种治疗方案,如手术切除、化疗和放疗,但这只是解决方案的一部分。早期发现和识别癌症与治疗本身同样重要,如果不是更重要的话。

成像对降低癌症死亡率产生了巨大的影响。乳房 X 线照相术是一种基于 X 射线的成像技术,是乳腺癌的主要成像技术,它允许临床医生看到下面的组织和结构。在过去的十年中,数字乳房断层合成(DBT)已经成为护理的标准,这种成像技术产生三维(3D) X 射线图像,而标准乳房 X 线照相术提供 2D 图像。

作者图片

图 1: 计算机辅助检测(CAD)发现肿块(绿色)、钙化点(红色)和钙化簇(蓝色)。放射科医生发现的实际癌症病变是黄色的。

放射科医生检查从标准乳房 x 线照相术或 DBT 获得的图像,寻找可疑的病变和钙化。乳房组织中的钙化并不少见,有时预示着癌症或发展为癌症的风险。计算机辅助检测或 CAD 软件已经开发出来,并获得食品和药物管理局(FDA)的批准,以帮助临床医生筛查癌症图像。人工智能(AI)的最新进展导致了 CAD 的巨大进步,甚至基于 AI 的 CAD 软件的开发。

活检的问题

因此,随着乳腺成像技术的巨大进步,对抗癌症应该变得更容易了,对吗?简单的答案是肯定的,但有一个小问题。虽然成像确实有助于识别更多的癌症并降低死亡率,但仍然存在假阳性活检的问题。当一个病变在影像学上被认为可疑时,通常会进行活检。活组织检查是一种侵入性程序,从妇女的乳房中取出可疑病变的组织样本,在显微镜下观察。假阳性活检意味着病理学家在组织中没有发现任何癌症迹象,并且在成像上看到的病变是良性或非癌性的。从本质上讲,假阳性会导致不必要的侵入性活检,并可能对一个人的身心健康有害。这个问题的存在部分是因为成像变得更加灵敏,可以看到更多的病变。然而,特异性还没有提高到足够的程度,这意味着仍然很难区分癌性病变和非癌性病变。

什么是合成成像

三室乳房(3CB)成像是一种双能 X 射线技术,可生成成像乳房内不同组织类型的图像或地图。3CB 技术受双能 X 射线吸收法(DXA)的启发,双能 X 射线吸收法通常用于评估骨密度和身体成分。使用 3CB,可以快速连续拍摄两幅图像。一幅图像是低能量的,相当于标准的乳房 x 线照片,而另一幅图像是以较高的能量拍摄的。不同能量的 X 射线在穿过不同的组织时将具有不同的行为,并且高能量和低能量 X 射线图像之间的对比被用于导出特定的组织类型。3CB 成像技术有助于可视化和量化乳房中的脂质、水和蛋白质的量。

作者图片

图 2: 标准乳房 x 线照片,旁边是从双能三室乳房(3CB)成分成像获得的脂质、水分和蛋白质图。

应该注意的是,在 3CB 中使用较高能量的 X 射线是安全的,辐射水平没有什么可担心的。事实上,3CB 成像只需要 2 张图像,而标准 DBT 成像需要大约 7 到 9 张图像,具体取决于系统。因此,3CB 技术产生的额外辐射水平与 DBT 图像序列相当,如果不是更低的话。为了进一步强调 3CB 的安全性,对比增强乳房 x 线照相术(CEM)使用几乎相同的成像协议来采集高能和低能图像。CEM 也获得了 FDA 的批准,总体上可能比 3CB 风险更大,因为在 CEM 使用的造影剂可能会引起过敏反应的不良反应。

作文能有什么帮助

众所周知,组成对于乳腺癌是重要的。乳房密度是一个强大的风险因素,密度往往是由于高纤维腺组织或蛋白质。其他人在细胞/分子水平上研究了乳腺癌病变,并发现浸润性病变类型倾向于消耗或代谢脂质。据推测,这种行为的机制是由于侵入性乳腺病变的侵略性生长性质。脂质或脂肪是一种能量来源,侵袭性肿瘤会消耗一切可以为其快速生长提供燃料的物质。结果,我们发现我们可以获得表征恶性病变类型的信号。该信号由与周围区域相比具有较低脂肪或脂质含量的癌性病变组成。

作者图片

图 3: 在距离病变 2、4 和 6 毫米处捕获脂质、水和蛋白质信号。橙色和蓝色虚线之间的空间显示了癌性和非癌性病变类型在组成上的显著差异。

人工智能的作用

为了证明我们的 3CB 成分成像的效用,我们使用人工智能来观察是否可以学习癌性和非癌性病变之间的成分差异。我们还想知道从 3CB 技术中获得的成分信息如何为现有的临床范例增加有用的诊断信息。我们使用 CAD 作为我们的基线,我们想看看具有 3CB 的 AI 是否能胜过 CAD。

作者图片

**图 4:**95%置信区间(CI)下 CAD 和 CAD+3CB 性能的受试者操作特征曲线(AUC)下面积。橙色线表示与单独的 CAD 相比,具有组合的 CAD 具有更好的检测性能,以蓝色显示。
*代码用于生成 AUC 与 CI 图详细 此处 此处

正如您从我们的区域的受试者操作特征曲线(AUC) 中看到的,AI+3CB+CAD 模型的表现优于单独的 CAD。这表明构图很重要,并提供了 CAD 无法单独捕捉的附加信息。换句话说,CAD 和放射科医生使用标准乳房 x 线照相术使用形状、纹理和形态测量信息来识别癌症。3CB 提供了相同的信息以及成分,这已被证明是有益的。综合辨别改进(IDI)图表明,由于假阳性的减少,性能的改进是显著的。如前所述,存在活检问题,使用 3CB 组合物减少假阳性可以减少不必要的活检并改善该问题。

作者图片

图 5: 综合判别改善(IDI)和净重新分类指数(NRI)显示 3CB 改善特异性。乳房成像报告和数据系统(BI-RADS)临界值旁边标有指标,供临床参考。
*代码用于生成 IDI 与 NRI 的剧情详细 此处 此处

3CB 的下一步是什么

我们正在继续我们对 3CB 的工作和研究,通过修改协议使其适用于 CEM 机器1r 01 ca 257652–01a 1。使用 FDA 批准的现有对比增强乳房 x 光机进行 3CB 成像将有助于加快该技术的采用。

参考

【1】Leong,l .、Malkov,s .、Drukker,k .、Niell,b .、Sadowski,p .、Wolfgruber,t .…&Shepherd,j .、双能量三隔室乳腺成像(3CB),用于改进恶性病变检测的新型成分生物标志物,(2021)。

【https://www.lambertleong.com】原载于 2021 年 11 月 14 日https://www.lambertleong.com/projects/compositional-breast-cancer-ai

主成分分析综合指南

原文:https://towardsdatascience.com/comprehensive-guide-for-principal-component-analysis-7bf2b4a048ae?source=collection_archive---------6-----------------------

用 python 实现主成分分析的理论和实践部分

***Table of Contents* 1\. Introduction
2\. Principal Component Analysis (PCA)
3\. Theory
3.1\. Calculating PCA
3.1.1\. Rescaling (Standardization)
3.1.2\. Covariance Matrix
3.1.3\. Eigenvalues and Eigenvectors
3.1.4\. Sorting in Descent Order
3.2\. Is PCA one of the feature extraction&feature selection methods?
4\. Implementation
4.1\. Traditional Machine Learning Approaches
4.2\. Deep Learning Approaches
5\. PCA Types
5.1\. Kernel PCA
5.2\. Sparse PCA
5.3\. Randomized PCA
5.4\. Incremental PCA**

1。简介

本文涵盖了 PCA 的定义,没有 Sklearn 库的 PCA 理论部分的 Python 实现,PCA 与特征选择&特征提取的区别,机器学习&深度学习的实现,并举例说明了 PCA 的类型。

由内森·杜姆劳在 Unsplash 上拍摄的照片

2.主成分分析

主成分分析是一种基于数学和统计学的非常有用的方法,它通过从不同角度对数据集进行评价来进行降维。它在机器学习中的任务是减少数据集中输入的维数,并通过算法或根据无监督方法中的特征对数据集进行分组来促进学习。这个降维过程是各种数学运算的结果。以坐标平面中具有两个特征的 2D 数据集(x,y)为例。当我们用主成分分析将数据集转换成 1D 时,数据集的分类变得容易得多。现在让我们用 PCA 实现并可视化降维:

癌症数据集(编码中定义为 cancer_data)由 596 个样本和 30 个特征组成。首先使用 StandardScaler 对这些数字特征进行缩放,然后使用 Sklearn 库导入的 PCA 方法对数据集进行二维处理,并对“恶性”和“良性”目标进行着色,如图 1 所示。X 轴代表 8 个分量中的第一个,y 轴代表 8 个分量中的第二个分量。

图一。第一主成分图和第二主成分图,作者图像

从图 1 中可以看出,在 PCA 过程之后,不使用任何算法就可以进行分类,这几乎是人眼可以预测的。然而,考虑到 30 个特征的数值数据集,这对于人类来说是根本不可能的。

看各个分量的方差值,看到有**【0.44272026,0.18971182,0.09393163,0.06602135,0.05495768,0.04024522,0.02250734,0.01588724】**。第一和第二分量对应于整个数据集的 63%。8 个组成部分的累积方差图如图 2 所示。

图二。组件数量的累积方差,按作者排序的图像

将数据集转换为不同维度时,在新维度中定位数据的过程称为投影。在图 3 中,根据新创建的维度和与 mglearn 库中 PCA 图的差异,可以看出区别。

图 3。使用 mglearn 库的 PCA 可视化,图片由作者提供

那么这个将 30 维转化为 2 维的神奇过程背后到底隐藏着什么呢?

3.理论

PCA 改变组件的方向以实现最大方差,并以此方式降低数据集的维数。

方差:给出关于数据集分布的信息。例如,让我们举一个将 5cl 液体装入瓶子的例子。假设第一种情况下的瓶子是 4cl、5cl、5cl、5cl、6cl,第二种情况下的瓶子是 2cl、3cl、5cl、7cl、8cl。虽然两者的平均值都是 5cl,但是第一种情况下的填充物将比第二种情况下的填充物更均匀,因为第一种情况下的样本分布方差低于第二种情况下的样本分布方差。这表明分配更加成功。

3.1.计算 PCA

图 4 显示了如何使用 PCA 进行降维的流程图。

图 4。降维流程图,作者图片

PCA 是在不使用 sklearn 库的情况下通过数学运算创建的,并且与 sklearn 库的组件进行比较。

每一步的输出都逐步显示在表格中。

3.1.1。重新缩放(标准化)

在第一阶段,对数值数据集应用缩放。为此,计算每个特征的平均值和标准差。使用这些计算,按照公式 x _ new =(x-mean(x 的列))/STD(x 的列)创建新的数据集。对于此操作,每个特征的平均值= 0,标准值= 1(用标准定标器标准化)

图 5。数据集(左)和缩放数据集(右),按作者分类的图像

3.1.2。协方差矩阵

协方差矩阵根据以下公式创建,缩放后的数据集根据彼此之间的关系完全重建:

图 6。协方差矩阵公式,来源

根据该方程计算所有协方差值后,得到(n_features,n_features)的矩阵。主要目标是重新排列数据集,以最大化数据集中的方差。为了检测这一点,需要协方差矩阵。

协方差是相关性的度量。通过协方差,我们知道两个变量一起变化的方向(正的话方向相同,负的话方向相反)。然后我们可以用相关性来找出这种变化的程度。协方差以单位来度量。在数据科学中,协方差涵盖两个变量或数据集的关系。

图 7。协方差矩阵,图片由作者提供

3.1.3。特征值和特征向量

从具有协方差矩阵的数据集中计算特征值,并且获得相应的特征向量作为特征的总数。

图 8。特征值(左)和相应的特征向量(右),作者图片

3.1.4。按降序排序

特征值从最高到最低排序。希望为 PCA 选择多少分量,选择对应于该数量的特征值的特征向量,并降低数据集维数。

关于特征值的提示:

矩阵 x 的迹等于其特征值之和。

矩阵 x 的行列式等于其特征值的乘积。

矩阵 x 的秩等于矩阵 x 的非零特征值的个数。

图 9。无 Sklearn 的 PCA 结果无 Sklearn(左),有 Sklearn 的 PCA 结果(右),图片作者

用数学方程计算数据集的第一和第二主成分,可以看出,结果与导入 Sklearn 库的结果相同。

3.2。PCA 是特征选择&特征提取方法之一吗?

既可以是也可以不是。由于主成分分析降低了特征的维数,因此它可以被理解为提取特征或选择影响结果的最有效的特征。但是理解了上面提到的理论部分,这个就清楚了。在 PCA 机器学习应用之外,它是关于在另一个坐标系中解释数据集。我们可以认为这是用傅里叶变换将信号从时间轴转换到频率轴。

通过考虑数值和连续变量的方差值,对它们进行重新评估,并使用 PCA 从不同的窗口查看数据集。虽然在技术上可以实现,但对分类变量使用 PCA 不会产生可靠的结果。同样,当理解上述理论部分时,**用 PCA 执行特征选择的条件是合理的,因为影响结果的最重要的特征具有最大的方差。**当然,技术上还是可以实现的,只是选择权在开发者。

4.履行

4.1.传统的机器学习方法

有人提到,主成分分析是一种非常有用的方法,尽管会丢失信息,但会降低维数减少和特征值。在影像数据集中,每个像素都被视为一个要素。换句话说,对于 128x128 RGB (3 通道)图像,有 1281283 = 49152 个特征。这个数字对于监督学习模型来说是相当高的。在这一部分中,在由 81 个杯子、74 个盘子和 78 个盘子组成的厨房用具图像数据集上,在利用 PCA 对数据集进行图像增强和维度缩减之后,XGBoost 被应用如下:

数据集从本地文件夹导入后,使用定义的 Imagedatagenerator 复制 15 次,获得 3495 个样本。在编码中, *x:代表数据集,y:代表标签。*然后,为了测量来自不同源的模型的泛化性能,下载 5 个杯子、5 个盘子和 5 个盘子,并且这些也从本地文件夹中导入。在必要的数据预处理之后,将图像添加到 x 的末端,将标签添加到 y 的末端。**将获取的图像添加到训练和测试数据集中以评估模型泛化性能的原因是相同的 PCA 过程应用于所有图像。**数据集合并后,使用 sklearn 库导入 PCA,49152 像素(特征)减少到 300。此时,使用 NumPy 再次提取具有 15 个样本的模型泛化性能数据集,并且 3495 个数据集被分离为训练数据集和测试数据集。这里的问题不是是否使用五氯苯甲醚,而只是作为一种应用。也可以使用 SelectPercentile 进行特征选择。然后,在标签适应 XGBoost 模型之后,训练数据集被训练,并且用测试数据集评估该模型。最后,用分离的 15 个样本的外部数据集检验了模型的预测。

结果如图 10 所示。

图 10。外部数据集的混淆矩阵(左)和测试数据集的混淆矩阵(右),图片由作者提供

4.2.深度学习方法

编码器和解码器是深度学习处理的首选。然而,应用五氯苯甲醚在技术上是可行的。让我们对用上述数据导入和预处理操作以及用 PCA 降维准备的数据集进行分类,用密集层。

结果如图 11 所示:

图 11。外部数据集的混淆矩阵(左)和测试数据集的混淆矩阵(右),图片由作者提供

5.PCA 类型

5.1.核主成分分析

虽然 PCA 是一个线性模型,但在非线性情况下可能不会给出成功的结果。内核 PCA 是一种方法,也称为内核技巧,可以非线性地分离数据。

图 12。数据集(左)、含 PCA 的数据集(中)、含内核 PCA 的数据集(右)、按作者分类的图像

5.2.稀疏主成分分析

其目的是在稀疏主成分分析中更容易解释模型。虽然整个数据集的线性组合是 PCA 中的每个主成分,但是每个主成分是稀疏 PCA 中数据集子集的线性组合。

5.3.随机化主成分分析

随机化 PCA 与随机梯度下降一起工作,被称为随机化 PCA。通过查找前 x 个主成分来加快 PCA 过程。

5.4.增量 PCA

它通过将大规模数据集以小批量保存在内存中来执行 PCA 方法。

方法在上面的 Sklearn 库中给出,并且可以根据数据集容易地实现。

回到指引点击此处。

https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d

多类分类标准综合指南

原文:https://towardsdatascience.com/comprehensive-guide-on-multiclass-classification-metrics-af94cfb83fbd?source=collection_archive---------0-----------------------

成为生活的书签:你需要的所有多类分类标准都有清晰的解释

照片由 德昂黑 像素

介绍

我最近发表了我最具挑战性的文章,主题是多类分类(MC)。我在这个过程中所面临的困难很大程度上是由于我必须学习和解释过多的分类标准。当我完成的时候,我已经意识到这些指标应该有一篇自己的文章。

因此,这篇文章将是关于 7 个最常用的 MC 指标:精确度、召回率、F1 值、ROC AUC 值、Cohen Kappa 值、Matthew 相关系数和对数损失。您将了解它们是如何计算的,它们在 Sklearn 中的细微差别,以及如何在您自己的工作流程中使用它们。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

解释 N 乘 N 混淆矩阵

您今天将要介绍的所有指标都以这样或那样的方式与混淆矩阵相关联。虽然 2 乘 2 混淆矩阵直观且易于理解,但更大的混淆矩阵可能会真正混淆。出于这个原因,在深入研究从矩阵中导出的指标之前,最好先了解一些较大的 N 乘 N 矩阵。

在本文中,我们将使用钻石分类的例子。具体来说,目标包含 4 种类型的钻石:理想、优质、优质和一般。对该钻石数据的任何分类器进行评估将产生一个 4x 4 矩阵:

尽管随着类别数量的增加,解释矩阵变得越来越困难,但是有一些万无一失的方法可以找到任何形状的矩阵。

第一步是始终确定你的积极和消极类。这取决于你要解决的问题。如果分类是平衡的,也就是说,你平等地关心每一个类(这种情况很少发生),可能就不会有任何积极或消极的类。如果是这种情况,正类和负类是按类定义的。

但是,作为珠宝店老板,您可能希望您的分类器能够更好地分类理想钻石和优质钻石,因为它们更贵。在这种情况下,理想和优质标签将是一个积极的类别,其他标签被统称为消极的。

识别阳性和阴性类别后,定义真阳性、真阴性、假阳性和假阴性。就我们自己的问题而言:

  • 真阳性,类型 1 :实际理想值,预测理想值
  • 真阳性,类型 2 :实际保费,预测保费
  • 真否定:正确预测的任何否定类别标签(好、一般)
  • 误报:实际值属于“良好”或“一般”类别,但预测为“理想”或“溢价”
  • 假阴性:实际值属于阳性类别,但预测为良好或一般

一旦你定义了 4 项,从矩阵中找出每一项应该很容易,因为这只是简单的加法和减法。

从二元度量到多元类

默认情况下,大多数分类指标都是针对二元情况定义的。在将这些二进制度量扩展到多类时,使用了几种平均技术。

首先,使用一对一(OVO)或一对其余(OVR,也称为一对所有)方法,将多类问题分解为一系列二元问题。OVO 存在计算上的缺陷,所以专业人士更喜欢 OVR 方法。正如我在我的上一篇文章中详细讨论了这两种方法的区别,我们今天将只关注 OVR。

本质上,一对一策略将一个多类问题转化为目标中每个类的一系列二元任务。例如,分类 4 种类型的钻石类型可以用 OVR 二进制化为 4 个任务:

  • 任务 1:理想与[优质、良好、一般] —即理想与不理想
  • 任务 2:优质与[理想、良好、一般]——即优质与非优质
  • 任务 3:好与[理想、优质、一般] —即好与不好
  • 任务 4:公平与[理想、优质、良好] —即公平与不公平

对于每个任务,将构建一个二进制分类器(在所有任务中应该是相同的分类器),并使用二进制分类度量(如 precision)(或我们今天将讨论的任何度量)来测量它们的性能。结果将是 4 个精确分数。为了比较一个分类器和另一个分类器,我们需要一个单一的精度分数,而不是 4,所以我们需要一种方法来表示所有类的精度。这就是平均技术的用武之地。

具体来说,有 3 种适用于多类分类的平均技术:

  • macro :这是跨类的所有指标的简单算术平均值。这种技术对所有类别赋予相同的权重,使其成为平衡分类任务的好选择。
  • 加权:通过计算目标中每个类别的样本数加权的二进制度量的平均值,说明类别不平衡。如果 3 个类别的 3 ( 精度分数)分别为:类别 1 (0.85)、类别 2 (0.80)和类别 3 (0.89),则通过将每个分数乘以每个类别的出现次数并除以样本总数来计算加权平均值。
  • :这个和精度一样。微平均是用矩阵对角线单元之和除以所有单元之和,即精度。由于精确度是一个误导性的指标,这种平均技术很少使用。

现在,让我们最终转向实际的指标!

多类分类的精度和召回率

Precision 回答了“预测阳性与实际阳性的比例是多少?”当然,你只能用二元分类来回答这个问题。这就是为什么你问这个问题的次数和目标中类的数量一样多。每一次,你都将针对一个班级向其他班级提出问题。对于我们的钻石分类,一个例子是“预测的理想钻石有多少比例实际上是理想的?”

通过将真阳性除以真阳性和假阳性之和来计算精度(三 p 规则):

让我们计算理想类的精度。以下是混淆矩阵,供参考:

理想钻石的真阳性是左上角的单元格(22)。假阳性是其他类型的钻石被预测为理想的所有细胞。这些是左上角单元格下面的单元格(5 + 2 + 9 = 19)。因此,精度将是:

精度(理想):22 / (22 + 19) = 0.536 —很恐怖的分数。

当你想减少假阳性的数量时,你应该优化你的模型的精确度。在我们的案例中,针对理想钻石的精度进行优化是有意义的。原因是理想钻石是最贵的,得到一个误报意味着将一个更便宜的钻石归类为理想。如果你不小心漏掉了这样的事件,你可能会被指控欺诈。现在,让我们继续回忆*。*

Recall 回答了“有多少比例的实际阳性被正确分类?”它的计算方法是将真阳性的数量除以真阳性和假阴性的总和。

让我们为特级钻石计算一下。

有 27 个真阳性(第 2 行,第 2 列)。假阴性是指优质钻石被归类为理想、良好或一般的任何情况。这些将是真阳性细胞左边和右边的细胞(5 + 7 + 6 = 18)。因此,召回将是:

召回(溢价):27/(27+18)= 0.6——也不是个好成绩。

如果你想减少假阴性的数量,你应该优化你的召回模型。如果您试图在黄色和红色香蕉中检测蓝色香蕉,您会希望减少假阴性,因为蓝色香蕉非常罕见(如此罕见,以至于您第一次听说它们)。你不会想把它们和普通的香蕉混在一起。

如果你想查看所有类的精度和召回率以及它们的宏观和加权平均值,你可以使用 Sklearn 的classification_report函数。假设我们的标签在y_test并且预测在y_pred,钻石分类的报告将是:

最后两行显示的是精度和召回率的宏观和加权平均值,看起来不太好!

多类分类的 F1 分数

由于它们的性质,精确度和召回率是一种权衡关系。你可能不得不以牺牲另一个为代价来优化一个。然而,如果您想要一个分类器,它在最小化误报和漏报方面同样出色,该怎么办呢?例如,有一个模型是有意义的,该模型同样擅长于捕捉意外出售廉价钻石作为理想钻石的情况,以便您不会被起诉,并检测意外以更低的价格出售理想钻石的情况。

这就是 F1 分数的来源。它是通过取精度和召回率的调和平均值来计算的,范围从 0 到 1。

为什么要取调和平均值而不是简单的算术平均值?调和平均值有一个很好的算术特性,代表一个真正平衡的平均值。如果准确率或召回率较低,就会受到严重影响。例如,假设我们正在比较两个分类器。第一个分类器的精度和召回率分别为 0.9、0.9,第二个分类器的精度和召回率分别为 1.0 和 0.7。计算两者的 F1 得到 0.9 和 0.82。如你所见,第二个分类器的低回忆分数降低了分数。

使用分类报告输出,您可以看到 F1 的两个平均分数:

F1 分数通常介于精确度和召回率之间,但是取加权平均值可能会给出超出其范围的值。

在接下来的几节中,我们将讨论 ROC AUC 得分并将其与 F1 进行比较。你会发现这两个指标的主要缺点。

多类分类的 ROC AUC 得分

二元分类中另一个常用的度量是受试者操作特征曲线下的面积(ROC AUC 或 AUROC)。它量化了模型区分各个类别的能力。该度量仅用于可以生成类成员概率的分类器。就 Sklearn 估计器而言,这些是具有predict_proba()方法的模型。

例如,如果目标包含猫和狗类,那么使用predict_proba方法的分类器可以为每个样本生成隶属概率,例如猫为 0.35,狗为 0.65。然后,基于像 0.5 这样的决策阈值对每个预测进行分类。在进一步解释 AUROC 之前,我们先来详细看看它是如何计算 MC 的。

在使用predict_proba方法的二元分类器被选择之后,它被用于为 OVR 的第一个二元任务生成成员概率。然后,选择接近 0 的初始决策阈值。使用阈值,进行预测,并创建混淆矩阵。从这个混淆矩阵中,计算出两个度量,真阳性率(与回忆相同)和假阳性率:

然后,选择新的、更高的阈值,并创建新的混淆矩阵。使用这个混淆矩阵,计算新的 TPR 和 FPR。对于 0 和 1 之间的许多不同的判决阈值重复该过程,并且对于每个阈值,找到新的 TPR 和 FPR。最后,所有 TPR 和 FPR 相互对应绘制:

该图是在我们的 diamonds 数据集中计算理想类相对于其他类的 ROC 曲线的实现。对于所有其他二进制任务,重复整个过程。换句话说,又发现了 3 条 ROC 曲线:

最终的图还显示了这些曲线下的面积。AUROC 越大,等级之间的差别就越大。最终的 AUROC 也使用宏观或加权方法进行平均。以下是这一切在 Sklearn 中的实现:

我们的平均得分是 0.82。

多类分类中 ROC AUC 分数与 F1 分数的对比

简而言之,ROC AUC 和 F1 之间的主要差异与类别不平衡有关。以下是阅读了许多 StackOverflow 线程后对如何选择一个线程的总结:

如果你有很高的类别不平衡,总是选择 F1 分数,因为高的 F1 分数同时考虑了精确度和召回率。为了获得高 F1,假阳性和假阴性都必须低。另一方面,ROC AUC 可以以足够高的假阳性数给出宝贵的高分。此外,您还可以将 ROC AUC 分数视为在各种阈值下评估的 F1 分数(好的和坏的)的平均值。当你有阶级不平衡的时候,总是使用 F1。更高的 ROC AUC 不一定意味着更好的分类器。

如果你想更多地了解这种差异,下面的讨论对我有所帮助:

  • F1 得分与 ROC AUC 的对比
  • 如何解释几乎完美的准确性和 AUC-ROC 但 f1-得分、精确度和召回为零
  • 如何在 ROC AUC 和 F1 成绩之间做出选择?
  • AUC 和 F1-score 有什么区别?

Cohen 的多类分类 Kappa 评分

你可以把 kappa 评分看作是准确性的增强版,这个版本也整合了对机会和等级不平衡的测量。

正如你可能知道的,准确性可能非常误导人,因为它没有考虑到阶级的不平衡。在正负比率为 10:100 的目标中,如果分类器简单地正确预测所有负样本,您仍然可以获得超过 90%的准确性。此外,由于机器学习算法依赖于数据的概率假设,我们需要一个分数来衡量生成预测时固有的不确定性。以雅各布·科恩(Jacob Cohen)命名的 Kappa 评分是少数几个可以在一个指标中代表所有这些的评分之一。

在官方文献中,它的定义是“量化两个评分者之间的一致程度的度量标准。”这是维基百科的定义:

Cohen 的 kappa 系数(κ)是一种统计数据,用于测量定性(分类)项目的评分者之间的可靠性(以及评分者内部的可靠性)。一般认为这是一个比简单的百分比一致计算更稳健的方法,因为κ考虑了偶然发生一致的可能性。

以下是官方公式:

在分类中,这个公式解释如下:

P0是实际值和预测值之间的观测比例一致。这将是任何混淆矩阵的对角线单元的总和除以非对角线单元的总和。换句话说,简单准确性的另一个名称。

P_e 是真值和假值偶然重合的概率。我们将看到如何使用我们在本指南中使用的矩阵来计算这些值:

让我们先找出精确度:对角线单元格的总和除以非对角线单元格的总和— 0.6。为了找到 P_e 的值,我们需要找到每个类的真实值与预测值偶然相同的概率。

  1. **理想类—真实值和预测值都是理想值的概率。共有 250 个样品,其中 57 个是理想钻石。因此,随机钻石成为理想钻石的概率是

P(实际 _ 理想)= 57 / 250 = 0.228

现在,在所有 250 个预测中,有 38 个是理想的。所以,随机预测成为理想预测的概率是

P(预测 _ 理想)= 16 / 250 = 0.064

两个条件都为真的概率是它们的乘积,所以:

P_e(实际 _ 理想,预测 _ 理想)= 0.228 * 0.064 = 0.014592

现在,我们将为其他类做同样的事情:

  1. **溢价类——真实值和预测值的概率都是溢价偶然:

P(actual _ premium)= 45/250 = 0.18

P(预测保费)= 28 / 250 = 0.112

P_e(实际 _ 溢价,预测 _ 溢价)= 0.02016

  1. **好类—真实值和预测值都是偶然的概率:

P(实际 _ 良好)= 74 / 250 = 0.296

P(predicted _ good)= 26/250 = 0.104

P_e(实际 _ 良好,预测 _ 良好)= 0.030784

  1. **一般类—真实值和预测值的概率都一般偶然:

P(实际 _ 公平)= 74 / 250 = 0.296

P(predicted _ fair)= 30/250 = 0.12

P_e(实际 _ 公平,预测 _ 公平)= 0.03552

最终 P_e 是上述计算的总和:

P_e(最终)= 0.014592+0.02016+0.030784+0.03552 = 0.101056

精度,P_0 = 0.6

插入数字:

好消息是,您可以使用 Sklearn 在一行代码中完成所有这些工作:

一般来说,0.8 以上的分数被认为是优秀的。我们得到的分数是一个谦逊的温和派。

想了解更多信息,我建议阅读这两篇优秀的文章:

  • 简单的多类指标,第三部分:Kappa 分数(又名科恩的 Kappa 系数)
  • 科恩的卡帕统计是什么?

多类分类的马修相关系数

来看看精确度的另一个单一数字替代品——马修相关系数。我认为这是统计学家能够想出的唯一一个包含所有 4 个矩阵术语并且实际上有意义的指标:

即使我知道为什么它是这样计算的,我也不会费心去解释它。您只需要知道这个度量表示真实值和预测值之间的相关性。类似于皮尔逊的相关系数,范围从-1 到 1。1.0 的分数意味着完美的分类器,而接近 0 的值意味着我们的分类器不比随机机会好。

MCC 的酷之处在于它完全对称。与精确度和召回率不同,交换正类和负类会得到相同的分数。况且它只关心每个类预测的好不好,不考虑类的不平衡性。根据维基百科,一些科学家甚至说 MCC 是在混淆矩阵上下文中建立分类器性能的最佳得分。

幸运的是,Sklearn 也包含了这个指标:

我们得到了 0.46 的分数,这是一个中等强度的相关性。一般来说,超过 0.7 的值被认为是好成绩。

顺便说一下,上面的公式是针对二元分类器的。对于多类,Sklearn 给出了一个更可怕的公式:

图片由 Sklearn 提供。(他们甚至不辞辛苦,试图简化公式,他们真好!)

多类分类的对数损失

最稳健的单一数字度量之一是对数损失*,称为交叉熵损失和逻辑错误损失。它不是一个点度量(越大越好),而是一个误差函数(越低越好)。因此,尽可能最小化对数函数的分类器被认为是最好的分类器。*

log loss 的另一个优点是,它只对概率分数起作用,或者换句话说,是可以生成概率成员分数的算法。这意味着这个误差函数考虑了模型的不确定性。例如,分数为 0.9 的类预测比分数为 0.6 的预测更确定。我们今天讨论的许多指标使用预测标签(即 1 类、2 类),这些标签隐藏了模型在生成这些预测时的不确定性,而测井曲线损失则没有。

它严重地惩罚了模型预测低分数的类成员的情况。对于二进制情况,其公式为:

以上是二进制情况的公式。多类的情况更加复杂。我将不再解释这个函数是如何计算的,因为这已经超出了本文的范围。因此,我将用 Sklearn 展示一个例子,并留下一些链接,可能有助于您进一步理解这一指标:

这里有几个链接可以巩固你的理解:

  • 一本关于测井记录丢失的笔记本
  • 从 Kaggle 看测井曲线丢失
  • Sklearn 原木损耗用户指南
  • 每类多类对数损失函数

摘要

今天,我们学习了如何以及何时使用 7 个最常见的多类分类指标。我们还了解了它们是如何在 Sklearn 中实现的,以及它们是如何从二进制模式扩展到多类的。使用这些指标,您可以评估任何分类器的性能,并将它们相互比较。

这是最后一张备忘单,根据你在多类问题中的需要来决定使用哪种度量标准:

  • 以单一指标比较一个分类器与另一个分类器的整体性能—使用马修相关系数、科恩 kappa 和对数损失。
  • 衡量分类器在平衡分类中区分各类别的能力: ROC AUC 得分
  • 在不平衡分类中最小化假阳性和假阴性的度量: F1 分数
  • 专注于减少单个类的误报:该类的精度
  • 专注于减少单个类别的假阴性:召回该类别的

**

您可能也会对…感兴趣

助推模型综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-boosting-models-37714471e94d?source=collection_archive---------12-----------------------

图片来源:https://Twitter . com/wrathofgnon/status/1250287741247426565/photo/1

在表格数据建模领域,有一个统治王朝:增强模型。

虽然情况在变化,但 ML 和 AI 中的大多数问题仍然是监督建模问题。尽管深度学习应用程序(图像、视频、文本、语音)占据了左右头条,但现实生活中的大多数问题都使用表格数据,尤其是在商业领域。在这个世界上只有一个统治者:推动模型。

参加过 Kaggle 比赛的人都非常熟悉助推模型。XGBoost 开始统治大多数比赛。王冠很快就传给了 LightGBM。但这些并不是唯一的助推算法。最近,有人在 AdaBoost 上问我一个问题,这让我意识到我忽略了这一点。所以我决定写一个全面的指南,主要是作为自我参考,但也作为其他人的总结。这篇博文旨在讨论这些模型之间的结构差异及其性能。

关于集合和推进的初级读本

在我们深入研究不同的模型之前,让我们快速了解一下什么是 boosting 及其同类。Boosting 是一种用于组合输出的方法,如果你没有接触过这个概念,这听起来相当神秘。集成是一种组合不同模型/决策/功能的输出的方法。助推是集合的一种方式。有三种主要的组装方法:装袋、助推和堆叠。

基本上,在集成中,我们有一堆更简单的模型(所谓的“弱学习者”),它们理想地捕捉我们数据的不同方面,我们使用他们的所有判断来达到最佳解决方案。有点像算法代议制民主。就像在民主国家一样,如果观点非常相似,你最终会进入一个回音室,这个回音室过度适应你的数据的一个方面,你的模型就会在实践中失败。所以我们的“弱学习者”在理论上具有低相关性。关于这一点的更正式和更少固执己见的解释,请参见偏差-方差权衡。

在助推/打包算法中,当我们说弱学习者时,我们实际上指的是决策树。但是弱学习者是一个通用术语,用于任何比随机机会表现稍好的 ML 模型。

制袋材料

Bagging 是一种方法,在这种方法中,我们使用来自所有弱学习者的决定。基本上,你有来自每个弱学习者的投票,你决定使用最普遍的意见(在分类的情况下)或平均值(在回归的情况下)。假设我们有 5 个学习能力差的人,其中 3 个回答“是”,2 个回答“这个人会在泰坦尼克号上幸存吗?”最后的决定是肯定的。随机森林是在这种背景下最著名的 bagging 算法。

图片来源:https://en . Wikipedia . org/wiki/File:Random _ forest _ diagram _ complete . png

助推

另一方面,助推以不同的方式解决问题。它通过调整每一步的误差反复建立自己的观点。每个弱学习者都建立在前一组学习者的基础上。例如,假设我们已经建立了 5 个弱学习者,假设这 5 个学习者的组合输出决策是固定的,第 6 个学习者被期望与训练输出相比纠正他们的错误。在 boosting 中,每个弱学习者都以这样或那样的方式被加权,以优化损失函数。这就是为什么叫‘助推’。它“提升”了前一套模型的性能。这种加权机制是增强算法彼此不同的一个方面。

堆垛

概括一下,装袋平均产量。增强将输出与一些权重相结合。从这个意义上说(除了联合和迭代建模方法),bagging 和 boosting 在加权方法上有所不同。Bagging 对所有弱学习者具有相同的权重,boosting 基于弱学习者在损失函数上的表现对其进行加权。相比之下,堆叠使用又一个学习器来学习如何组合弱学习器。堆叠层可以有任何模型作为所有弱学习者的组合子。所以基本上代替权重,你可以使用,比如说,神经网络来组合来自你的弱学习者的输出。

推进模型:又名我们如何从“大卫·鲍依的”创造出“约翰·沃森”?

如果你读过我以前的任何作品,你就会知道我永远无法抗拒一句晦涩难懂的引用,但这一句是如此贴切,而不是真的那么晦涩难懂,我不得不给出一个参考。现在我已经通过引用以最清晰的方式解释了 ensembling 的作用,下面我可以继续列出不同的升压模型。

  • adaboost 算法
  • 梯度推进机器
  • XGBoost
  • CatBoost
  • LightGBM

adaboost 算法

AdaBoost 是最初的升压模型,代表自适应升压。在每次提升迭代中,它根据模型在每个样本上的当前性能调整权重。使用这些权重,数据集被重新采样(替换)到新的训练集中。基本上,通过增加每个错误分类样本的权重并减少正确分类样本的权重,我们增加了这些错误分类样本在下一次迭代中出现在我们的训练子集中的机会(可能不止一次)。因此,该模型不断地重新关注我们无法分类的项目,以找到一些表示它们的方式。

AdaBoost 在行动——来源:http://srl.informatik.uni-freiburg.de/videos

梯度推进机器

如前所述,并不是所有的 boosting 模型都像 AdaBoost 一样进行更新。在 GBM 的情况下,与改变数据的采样权重相反,模型更新是通过给定损失函数的梯度下降来完成的。更新规则如下:

图片来源:维基百科

基本上,这告诉你的是,在迭代 m 时,选择弱学习者 h ,其最小化实际值 y_i 和我们先前估计的 F_(x_i) + 预测的 h (即弱学习者)。找到使其最小化的 h 的方法是通过梯度下降。

在优化回归的均方误差的情况下,梯度就是残差。并且每个连续的弱学习器适合于残差,因为我们试图补偿误差。想象一下这个场景,当我们开始时,我们对我们的输出没有任何线索。因此,我们的输出向量 y 中的每个值实际上都是一个残差。因此,我们首先让弱学习者适应我们的初始残差。然后,我们的弱学习者做出一些预测,其中一些比另一些更好,所以我们试图学习错误并继续这样下去。这个过程相当于使用梯度下降来训练 boosting 模型。数学很简单,但是太长了,不能放在这里。对于没有优化 MSE 的分类和其他回归问题,我们以这样的方式训练我们的弱学习者,他们将执行梯度下降。因此,GBM 是广义 boosting 方法,可以适用于任何可微损失函数。这里的是关于这个主题的一套很好的课堂讲稿,它也展示了拟合残差和梯度下降的等价性。

极端梯度推进(又名 XGBoost)

XGBoost 是 GBMs 的一个规范化变体。XGBoost 没有像上述 GBM 中那样最小化损失,而是在损失函数中增加了一个正则化项。这是一个简单但非常有效的防止过度拟合的技巧。该正则化术语强制要求应用更新的最低梯度水平。如果正则项比梯度大得多,那么梯度将完全没有效果,因此更新被停止。如果正则项非常小,那么这个更新等价于 GBM。因此,不是最小化上面 GBM 等式的 argmin 部分,我们现在找到最小化以下内容的学习者 f_t :

XGBoost 学习。图片来源: XGBoost docs 。

此外,XGBoost 增加了叶节点的比例收缩,以进一步防止过度拟合和其他与处理器性能相关的变化。XGBoost 中的 x 与数据科学或 ML 相关概念无关,它更多地指向开发人员必须将分布式快速算法引入 ML 空间的工程焦点。

CatBoost

虽然 XGBoost 是处理表格数据的一个很好的算法,但它本身并不处理分类值。它们必须通过某种形式的数字编码来手动处理。另一方面,CatBoost 能够处理分类变量,只要您指定列名。其工作方式是,它生成虚拟(单热编码)变量,最多可达由 one_hot_max_size 参数提供的最大列数。如果分类变量具有比该参数更多的唯一值,则使用巧妙的排列和随后的类平均来创建每个类和类别的平均目标值。下面给出了公式,它看起来有点复杂,但它的意思是:对于一个给定的排列,找出计数到这一点为止的样本数(j),其中 *y(输出变量)*等于 1(假设二进制分类),在它之前加上一些,然后除以到这一点为止的对象总数。

这意味着几件事情,给定一个特征 x ,我们将它 n 次,以获得该特征的不同排序,然后逐个样本,我们计算带有一些偏移的正类与迄今条目数的比率。这意味着,在第一个实例中,如果我们有类值 a ,并且 y=1 ,这意味着我们的替换值是(1+ a.P)/(1+a),在第二个实例中,假设我们有类值 by = 0 ,那么我们的替换值将是(0 + a.P)/(2 + a)。就这样,我们继续前进。请注意,我们使用扩展窗口扫描所有样本,因此如果样本数量较多,这可能会非常慢。本质上,该公式是使用贝叶斯在线估计观察到该特性中该类别值的正类的概率。它的“贝叶斯”成分来自先验(P)和系数 a 是我们对初始先验概率的信任程度。公平地说,这不是一个真正的原创想法,它已经被许多数据科学家用于分类表示。CatBoost 是第一个将它正式化的 boosting ML 模型。它适用于具有大量类别的分类特征,但是 DS 从业者可以在不直接依赖 CatBoost 的情况下实现它。

LightGBM

LightGBM 是对 XGBoost 的另一个改进,它也可以直接处理分类值。这个模型实现了一些结构上的变化。

  • 计算分裂时的不同采样策略:基于梯度的单侧采样(GOSS)。XGBoost 使用基于直方图的分割策略。基本上,它计算数据的直方图,并基于直方图上的信息增益执行树分裂。另一方面,LightGBM 首先执行基于梯度的采样,然后根据样本子集计算分割。其工作方式是,保留所有具有高梯度的行,并对 x%的具有低梯度的行进行采样,然后在该子集上建立新的模型。这个算法的伪代码可以在论文中找到:https://papers . nips . cc/paper/2017/file/6449 f 44 a 102 FDE 848669 BDD 9 EB 6b 76 fa-paper . pdf
  • 高效的功能捆绑,通过删减专有功能集来减少功能数量。想法是,您可以将非零值之间没有重叠的要素分组为一个要素。
  • 逐叶分割与逐级分割:LightGBM 生长叶,最大程度地减少损失函数。理论上,这棵树只能长在一边。其他算法默认逐层增长树,这意味着树一次只增长一层。XGBoost 还可以执行逐叶生长。这提高了算法的速度和效率,因为它是一种贪婪的搜索机制,然而会导致过拟合,尤其是在数据稀疏和/或小的情况下。

结论和实用资源

这篇文章只是收集了算法中的设计差异,然而基于这些设计决策,算法之间存在性能差异。

  • GBM 是 OG(原始梯度),在不同的数据集上表现良好,但是它不能处理多种实际情况,如空值或分类值。它在多个标准库中都有实现,比如 scikit-learn,所以作为基线模型之一使用总是一个好主意。我尝试使用多种方法:GLMs、决策树、Random Forest 和 GBM,看看哪种复杂程度能给出可接受的基线性能。它指导下面的模型选择决策,但我现在离题了。
  • XGBoost 相对于 GBM 是一个显著的性能改进,但是在 sklearn 中没有实现。也不能处理分类变量。可以处理空值。
  • CatBoost 是对 XGBoost 分类值增加的改进,但训练效率较低。适用于大量独特的特征值。sklearn 中没有原生实现。
  • LightGBM 是对 XGBoost 改进,它可以处理分类值,也非常有效,但是如果不仔细调整,它会被修剪以适应过度。sklearn 中没有原生实现。然而,Python 包有一个 sklearn 子模块,它符合 sklearn fit-transform 语法,并且可以很好地与 sklearn 集成。

关于如何调优和使用这些算法的实用技巧,下面是一组我个人引用过并继续引用的博客帖子。这些软件包的官方文档也非常好,所以请务必参考这些文档。最后,检查原始论文也是一个好主意,因为它们提供了一种以更结构化的方式阅读创作者想法的方式。

  • XGB 与 LGBM 参数调整
  • CatBoost vs. XGB vs. LGBM 参数比较
  • XGBoost 文档
  • CatBoost 文档
  • CatBoost 论文
  • CatBoost 其他论文
  • LightGBM 文档
  • LightGBM 纸
  • LightGBM 回购

数据仓库综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-data-warehouses-6374617f45d5?source=collection_archive---------17-----------------------

您需要知道的一切,包括与数据湖的比较

照片由 imgix 在 Unsplash 上拍摄

数据仓库是公司或组织中的中央数据存储,它从各种来源收集关系数据。信息从不同的交易系统或其他关系数据库转移到数据仓库,在那里它可供分析师和决策者使用。

数据仓库可以用来做什么?

数据仓库用于商业环境的许多领域。整个公司都使用该数据库来制定数据驱动的决策或检查流程。由于中央数据仓库从许多不同的系统中提取信息,因此它被视为一个单一的事实。这是为了确保公司中的每个人都在谈论相同的数据,并且决策是基于这些信息的。

跨部门,数据仓库可用于以下任务:

  • 成本和资源分析
  • 内部流程分析(如生产、雇佣等)。)
  • 商业智能
  • 计算和提供公司范围内的关键绩效指标
  • 用于分析或数据挖掘的数据源
  • 将公司范围的数据标准化为固定的模式

数据仓库的属性

在创建中央数据仓库时,可以遵循某些特征,这些特征应该有助于更好地缩小数据仓库的结构和必要数据。

主题定位

数据仓库包含特定主题的信息,而不是单个业务交易的信息。例如,这些主题可以是销售、采购或营销。

该仓库旨在借助商业智能和目标 KPI 来支持决策。与决策无关或用于分析的信息最初不会出现在这个中央数据库中,这一事实也支持这种解释。

综合

该仓库集成了来自各种系统和来源的数据。因此,必须为信息创建一个通用的模式,以便它是统一的和可比较的。否则,集中分析和 KPI 创建是不可能的。

时间段参考

数据仓库存储特定时期的数据,因此与过去相关。此外,数据通常以聚集的形式传输,例如在每日级别,因此数据量仍然有限。因此,粒度可能不够细,正如人们习惯于从操作系统中得到的那样。

另一方面,操作系统是基于时间的,因为它们输出当前正在积累的信息。同时,可以非常详细地查看信息。

非挥发性

中央仓库的另一个重要特征是数据的非易失性。在操作系统中,信息通常只临时存储很短一段时间,一旦添加新数据,旧数据就会被覆盖。另一方面,在数据仓库中,数据是永久存储的,即使添加了新数据,旧数据也会持续存在。

数据湖和数据仓库的区别

这个中央数据库还可以由一个数据湖来补充,在这个数据湖中,非结构化的原始数据以较低的成本被临时存储,以便以后使用。这两个概念的主要区别在于它们存储的数据和存储信息的方式。

数据仓库和数据湖的比较|图片:作者

这是你应该带走的东西

  • 数据仓库集中存储公司范围的信息。
  • 这是为了支持数据驱动的决策,并使商业智能成为可能。
  • 数据湖中的非结构化原始数据为数据仓库中的关系数据和已处理数据提供了很好的补充。

如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的* 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5*获得会员资格**

*https://medium.com/@niklas_lang/what-does-google-know-about-me-find-it-out-c6115dca17e4 https://medium.com/@niklas_lang/what-are-recurrent-neural-networks-5c48f4908e34 https://medium.com/@niklas_lang/kubernetes-k8s-simply-explained-3dc2e1558b7c *

Sklearn 多类分类综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-multiclass-classification-with-sklearn-127cc500f362?source=collection_archive---------1-----------------------

模型选择、制定策略和选择评估标准

学习如何用 Sklearn 解决任何多类分类问题。本教程涵盖了如何选择模型选择策略、几个多类评估指标,以及如何使用它们完成超参数调整,以优化用户定义的指标。

照片由 塞尔吉奥·亚科布 像素

介绍

尽管多类分类并不常见,但它确实比二元分类问题提出了更大的挑战。你可以相信我的话,因为这篇文章是我写过的最有挑战性的文章(已经写了将近 70 篇)。

我发现多类分类这个话题很有深度,充满了细微差别。我读了那么多文章,读了多个 StackOverflow 线程,自己创建了几个,花了几个小时浏览 Sklearn 用户指南,做实验。多类分类的核心主题,例如

  • 选择将问题二值化的策略
  • 选择基本模式
  • 理解非常多的指标
  • 筛选出解决您业务问题的单一指标,并对其进行定制
  • 为此定制度量调整超参数
  • 最后用 Sklearn 把所有的理论付诸实践

都分散在互联网黑暗肮脏的角落里。这足以得出结论,没有一个单一的资源显示了在互联网上处理多类分类问题的端到端工作流(也许,我错过了)。

出于这个原因,本文将是一个关于如何使用 Sklearn 解决任何多类监督分类问题的综合教程。您将学习上述核心概念的理论和实现。这将是一个漫长而技术性的阅读,所以去喝杯咖啡吧!

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

本地多类分类器

根据你选择的模型,Sklearn 以 3 种不同的方式处理多类分类问题。换句话说,Sklearn 估计器根据其处理多类数据的策略分为 3 类。

第一组也是最大的一组估计器本身支持多类分类:

  • [naive_bayes.BernoulliNB](https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.BernoulliNB.html#sklearn.naive_bayes.BernoulliNB)
  • [tree.DecisionTreeClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier)
  • [tree.ExtraTreeClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.tree.ExtraTreeClassifier.html#sklearn.tree.ExtraTreeClassifier)
  • [ensemble.ExtraTreesClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.ExtraTreesClassifier.html#sklearn.ensemble.ExtraTreesClassifier)
  • [naive_bayes.GaussianNB](https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.GaussianNB.html#sklearn.naive_bayes.GaussianNB)
  • [neighbors.KNeighborsClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier)
  • [svm.LinearSVC](https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC)(设置 multi_class="crammer_singer ")`
  • [linear_model.LogisticRegression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression)(设置 multi_class= "多项式")
  • [linear_model.LogisticRegressionCV](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegressionCV.html#sklearn.linear_model.LogisticRegressionCV)(设置 multi_class= "多项式")

对于一个 N 类问题,他们会产生 N 乘 N 的混淆矩阵,大部分评估指标都是从中推导出来的:

我们将在教程的后面关注多类混淆矩阵。

一对一(OVO)策略的二元分类器

其他监督分类算法主要是为二进制情况设计的。然而,Sklearn 实现了两种称为一对一(OVO)和一对其余(OVR,也称为一对所有)的策略,将一个多类问题转换为一系列二元任务。

OVO 将一个多类问题分解成每对类的一个二元分类任务。换句话说,对于每一对,将建立单个二元分类器。例如,一个具有 4 个类别(脑癌、肺癌、乳腺癌和肾癌)的目标使用 6 个单独的分类器将问题二值化:

  • 分类器 1:肺与乳房
  • 分类器 2:肺对肾
  • 分类器 3:肺对脑
  • 分类器 4:乳房对肾脏
  • 分类器 5:乳房对大脑
  • 分类器 6:肾对脑

Sklearn 建议这些分类器最好与 OVO 方法一起使用:

  • svm。NuSVC
  • svm。SVC
  • 高斯 _ 过程。GaussianProcessClassifier (设置 multi_class = "one_vs_one ")

Sklearn 还在sklearn.multiclass.OneVsOneClassifier下提供了上述模型的包装器估算器:

这种策略的一个主要缺点是它的计算工作量。由于每对类都需要一个单独的二进制分类器,所以基数高的目标可能需要很长时间来训练。为了计算将为 N 类问题构建的分类器的数量,使用以下公式:

在实践中,由于这个缺点,一对其余的策略是更可取的。

一对一(OVR)策略的二元分类器

或者,OVR 策略为目标中的每个类创建一个单独的分类器。本质上,每个二进制分类器选择一个类,并将其标记为正,编码为 1。其余的类被认为是负标签,因此用 0 编码。对 4 种癌症进行分类:

  • 分类器 1:肺 vs .[乳腺、肾、脑]——(肺癌,不是肺癌)
  • 分类器 2:乳房对[肺、肾、脑]——(乳腺癌,不是乳腺癌)
  • 分类器 3:肾对[肺、乳房、脑]——(肾癌,不是肾癌)
  • 分类器 4:大脑 vs .[肺、乳腺、肾]——(脑癌,不是脑癌)

Sklearn 建议这些分类器最好与 OVR 方法一起使用:

  • [ensemble.GradientBoostingClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingClassifier.html#sklearn.ensemble.GradientBoostingClassifier)
  • [gaussian_process.GaussianProcessClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.gaussian_process.GaussianProcessClassifier.html#sklearn.gaussian_process.GaussianProcessClassifier)(设置 multi_class = "one_vs_rest ")
  • [svm.LinearSVC](https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC)(设置 multi_class="ovr ")
  • [linear_model.LogisticRegression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression)(设置 multi_class="ovr ")
  • [linear_model.LogisticRegressionCV](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegressionCV.html#sklearn.linear_model.LogisticRegressionCV)(设置 multi_class="ovr ")
  • [linear_model.SGDClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier)
  • [linear_model.Perceptron](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Perceptron.html#sklearn.linear_model.Perceptron)

或者,您可以使用默认OneVsRestClassifier的上述模型:

尽管这种策略显著降低了计算成本,但事实上只有一个类被认为是正面的,而其余的被认为是负面的,这使得每个二元问题成为一个不平衡的分类。对于目标中比例较低的班级,这个问题更加突出。

在这两种方法中,根据传递的估计量,所有二元分类器的结果可以用两种方式总结:

  • 多数投票:每个二元分类器预测一个类别,从所有分类器中获得最多投票的类别被选择
  • 根据类成员概率分数的 arg max:LogisticRegression 等分类器计算每个类的概率分数(.predict_proba())。然后,选择分数总和的 argmax。

我们将在本教程的后面部分详细讨论如何对这些策略进行评分。

样本分类问题和预处理流水线

作为一个示例问题,我们将使用 Kaggle 的钻石数据集来预测钻石的质量:

上面的输出显示了不同比例的特征,建议我们使用某种类型的归一化。这一步对于许多基于线性的模型的良好运行是必不可少的。

数据集混合了数值和分类特征。我在我的上一篇文章中详细介绍了二进制分类的预处理步骤。您可以很容易地将这些想法应用到多类的情况中,所以我在这里将保持解释简洁明了。

目标是“削减”,它有 5 个等级:理想、优质、非常好、良好和一般(质量递减)。我们将用 OneHotEncoder 对文本特征进行编码。

让我们快速浏览一下每个数字要素的分布,以决定使用哪种类型的归一化:

>>> diamonds.hist(figsize=(16, 12));

价格和克拉显示偏斜分布。我们将使用对数转换器使它们尽可能呈正态分布。对于其他的,简单的标准化就足够了。如果您不熟悉数字转换,请查看我的关于该主题的文章。同样,下面的代码包含了一个 Sklearn 管道的例子,你可以从这里了解所有关于它们的内容。

让我们开始工作:

我们管道的第一个版本使用了RandomForestClassifier。让我们通过生成预测来查看它的混淆矩阵:

在第 8 行和第 9 行,我们创建了矩阵并使用特殊的 Sklearn 函数来绘制它。ConfusionMatrixDisplay也有display_labels参数,我们将通过pipeline.classes_属性访问的类名传递给它。

解读 N 乘 N 混淆矩阵

如果你读过我的另一篇关于二进制分类的文章,你就会知道混淆矩阵是监督分类问题的圣杯。在 2 乘 2 矩阵中,矩阵项易于解释和定位。

尽管随着类别数量的增加,解释矩阵变得越来越困难,但是有一些万无一失的方法可以找到任何形状的矩阵。

第一步是始终确定你的积极和消极类。这取决于你要解决的问题。作为珠宝店老板,我可能希望我的分类器能够比其他类型更好地区分理想钻石和优质钻石,使这些类型的钻石成为我的正面类别。其他类将被视为负面。

在早期建立正类和负类对于评估模型性能和超参数调整非常重要。这样做之后,你应该定义你的真阳性、真阴性、假阳性和假阴性。在我们的案例中:

  • 阳性等级:理想和优质钻石
  • 负等级:非常好,好,和公平的钻石
  • 真阳性,类型 1 :实际理想值,预测理想值
  • 真阳性,类型 2 :实际保费,预测保费
  • 真阴性:其余钻石类型预测正确
  • 假阳性:实际值属于 3 个阴性类别中的任何一个,但预测为理想值或溢价值
  • 假阴性:实际值为理想值或溢价值,但由 3 个阴性类别中的任何一个预测。

总是以这种方式列出矩阵的术语,你的工作流程的其余部分将会容易得多,正如你将在下一节看到的。

Sklearn 如何计算多类分类指标— ROC AUC 得分

这一节仅仅是关于 Sklearn 如何为多类分类计算公共度量的基本细节。具体来说,我们将探究 4 个最常见的指标:ROC_AUC、precision、recall 和 f1 得分。尽管我将对每个指标做一个简要的概述,但我将主要关注在实践中使用它们。如果您想更深入地了解每个指标衡量的内容,请参考这篇文章。

我们将讨论的第一个指标是 ROC AUC 得分或受试者工作特征曲线下的面积。当我们想要测量一个分类器的性能来区分每一个类时,它是最常用的。这意味着 ROC AUC 更适合平衡分类任务。

实质上,ROC AUC 分数用于二进制分类,并与可以基于某个阈值生成类别成员概率的模型一起使用。以下是计算二元分类 ROC AUC 步骤的简要概述:

  1. 一个二元分类器,可以用它的predict_proba方法生成类成员概率,比如 LogisticRegression。
  2. 选择接近 0 的初始决策阈值。例如,如果概率高于 0.1,则预测该类为负,否则为正。
  3. 使用该阈值,创建混淆矩阵。
  4. 发现真阳性率(TPR)和假阳性率(FPR)。
  5. 选择新的阈值,并重复步骤 3-4。
  6. 对 0 到 1 之间的各种阈值重复步骤 2-5,以创建一组 TPR 和 FPR。
  7. 绘制所有 TPR 与 FPR 的关系图,以生成接收器工作特性曲线。
  8. 计算这条曲线下的面积。

对于多类分类,您可以使用 OVO 或 OVR 策略计算所有类的 ROC AUC。由于我们一致认为 OVR 是一个更好的选择,以下是 OVR 分类的 ROC AUC 计算方法:

  1. 使用 OVR 创建的每个二元分类器使用上述步骤找到其自身类别的 ROC AUC 分数。
  2. 然后使用以下两种方法之一对所有分类器的 ROC AUC 评分进行平均:
  • “宏观”:这只是分数的算术平均值
  • “加权”:通过找到一个加权平均值,将阶级不平衡考虑在内。每个 ROC AUC 乘以其类别权重并求和,然后除以样本总数。

例如,假设目标中有 100 个样本—类别 1 (45),类别 2 (30),类别 3 (25)。OVR 创建了 3 个二元分类器,每个类别一个,它们的 ROC AUC 分数分别为 0.75、0.68、0.84。所有类别的加权 ROC AUC 分数将为:

ROC AUC(加权):((45 * 0.75)+(30 * 0.68)+(25 * 0.84))/100 = 0.7515

以下是这一切在 Sklearn 中的实现:

上面,我们为我们的钻石分类问题计算了 ROC AUC,得到了一个优秀的分数。使用roc_auc_score时,不要忘记正确设置multi_classaverage参数。如果您想要生成某个特定课程的分数,以下是您的操作方法:

ROC AUC 分数只是一个很好的衡量标准,可以看出分类器如何区分不同的类别。更高的 ROC AUC 分数不一定意味着更好的模型。最重要的是,我们更关心我们的模型对理想钻石和优质钻石进行分类的能力,因此 ROC AUC 这样的指标对我们的情况来说不是一个好的选择。

多类分类的精确度、召回率和 F1 分数

衡量渠道绩效的更好指标是使用精确度、召回率和 F1 分数。对于二进制情况,它们易于理解且直观:

作者提供的图片

在多类的情况下,这 3 个度量是基于每类计算*。例如,让我们再来看看混淆矩阵:*

精度告诉我们有多少比例的预测阳性是真正的阳性。如果我们想要计算理想钻石的精度,真正的阳性将是正确预测的理想钻石的数量(矩阵的中心,6626)。假阳性将是任何细胞计数的次数,我们的分类预测其他类型的钻石是理想的。这些单元格位于矩阵中心的上方和下方(1013 + 521 + 31 + 8 = 1573)。使用精度公式,我们将其计算为:

精度(理想)= TP/(TP+FP)= 6626/(6626+1573)= 0.808

召回的计算方法类似。我们知道真正阳性的数量——6626。假阴性将是对分类器预测属于任何其他阴性类别的钻石的理想类型的次数进行计数的任何单元。这些单元格位于矩阵中心的左右两侧(3 + 9 + 363 + 111 = 486)。使用回忆公式,我们计算出它是:

回忆(理想)= TP/(TP+FN)= 6626/(6626+486)= 0.93

那么,对于理想的类,我们如何在召回率和精确度之间进行选择呢?这取决于你试图解决的问题的类型。如果你想尽量减少其他更便宜的钻石被预测为理想钻石的情况,你应该优化精度。作为一个珠宝店老板,你可能会因为将便宜的钻石冒充昂贵的理想钻石出售而被起诉欺诈。

另一方面,如果您想最大限度地减少意外低价出售理想钻石的情况,您应该优化理想类的召回。的确,你不会被起诉,但你可能会赔钱。

第三个选择是拥有一个同样擅长上述两种场景的模型。换句话说,一个具有高精度和高召回率的模型。幸运的是,有一个指标可以衡量这一点:F1 分数。F1 得分取精确度和召回率的调和平均值,并产生一个介于 0 和 1 之间的值:

因此,理想班级的 F1 分数应该是:

*F1(理想)= 2 (0.808 * 0.93)/(0.808+0.93)= 0.87

至此,我们只计算了理想类的 3 个指标。但是在多类分类中,Sklearn 为所有类计算它们。你可以用classification_report来看这个:

你可以检查我们对理想类的计算是否正确。表格的最后一列— support显示了每个类别有多少个样本。此外,最后两行显示了 3 个指标的平均分数。我们已经介绍了 ROC AUC 示例中的宏观平均值和加权平均值。

对于像这样的不平衡分类任务,你很少选择平均精度,F1 分数的回忆。同样,选择一个指标来优化一个特定的类取决于您的业务问题。对于我们的情况,我们将选择优化理想和高级类的 F1 分数(是的,您可以同时选择多个类)。首先,让我们看看如何计算所有类别的加权 F1:

以上与classification_report的输出一致。要选择理想和高级课程的 F1 分数,请指定labels参数:

最后,让我们看看如何通过超参数调优来优化这些指标。

调整超参数以优化自定义指标的模型性能

为一个指标优化模型性能几乎与我们为二进制情况所做的一样。唯一的区别是我们如何将评分函数传递给 GridSearch 这样的超参数调谐器。

到目前为止,我们一直使用 RandomForestClassifier 管道,因此我们将为此估计器创建一个超参数网格:

不要忘记在每个超参数名称前面加上您在评估器管道中选择的步骤名称。当我们创建管道时,我们将 RandomForests 指定为“base”。更多信息见本讨论。

我们将使用 HalvingGridSeachCV (HGS ),它比常规的网格搜索要快得多。你可以阅读这篇文章来看看我的实验:

</11-times-faster-hyperparameter-tuning-with-halvinggridsearch-232ed0160155>

在我们将上面的网格提供给 HGS 之前,让我们创建一个定制的评分函数。在二进制的情况下,我们可以传递字符串值作为我们想要使用的度量的名称,比如“precision”或“recall”但是在多类的情况下,这些函数接受额外的参数,如果我们将函数名作为字符串传递,我们就不能这样做。为了解决这个问题,Sklearn 提供了make_scorer功能:

正如我们在上一节中所做的,我们粘贴了averagelabels参数的自定义值。

最后,让我们初始化 HGS,并通过三重交叉验证使其适合全部数据:

搜索完成后,您可以分别使用.best_score_.best_estimator_属性获得最佳得分和估计值。

你的模型的好坏取决于你选择用来评估它的标准。超参数调整将是耗时的,但假设您在此之前做了所有正确的事情,并且给出了足够好的参数网格,那么一切都会如预期的那样。如果没有,这是一个迭代过程,所以调整预处理步骤,重新审视您选择的指标,也许可以扩大您的搜索范围。感谢您的阅读!

相关文章

  • 简化多类指标,第一部分:精度和召回率
  • 简化多类指标,第二部分:F1-得分
  • 如何计算不平衡分类的精度、召回率和 F-Measure

讨论

  • 如何在 ROC AUC 和 F1 成绩之间做出选择?
  • AUC 和 F1-score 有什么区别?

API 和用户指南

  • 分类指标
  • 多类和多输出算法

使用 Python 进行卫星影像分析的综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-satellite-imagery-analysis-using-python-1b4153bad2a?source=collection_archive---------11-----------------------

实践教程,数据科学|遥感|实践教程

使用 Python 分析卫星影像的不同方法和机器学习技术,以及实践教程和示例。

美国地质勘探局在 Unsplash 上拍摄的照片

本文通过实践教程和示例,帮助用户了解使用 Python 分析卫星影像的不同方法以及有监督和无监督的机器学习技术。

内容

  1. 卫星图像指数
  2. 卫星图像中的监督学习
  3. 卫星图像中的无监督学习
  4. 结论

让我们开始吧✨

卫星图像指数

归一化卫星指数是根据多光谱卫星图像计算的图像。这些图像强调了存在的特定现象,同时减轻了降低图像效果的其他因素。例如,植被指数将健康植被显示为指数图像中的亮色,而不健康植被的值较低,贫瘠地形为暗色。由于地形变化(丘陵和山谷)的阴影会影响图像的强度,因此创建索引时会强调对象的颜色,而不是对象的强度或亮度。

植被指数

NDVI、SAVI 和 VARI 的孙德尔本斯卫星数据,图片由作者提供

为了确定一块土地上的绿色密度,研究人员必须观察植物反射的可见光(VIS)和近红外(NIR)阳光的不同颜色(波长)。一些广泛使用的植被指数是:

  • 归一化差异植被指数(NDVI)
  • 土壤调整植被指数(SAVI)
  • 可见大气阻力指数(VARI)

水指数

MNDWI 和 NDMI od Sundarbans 卫星数据,图片由作者提供

地表水变化是环境、气候和人类活动的一个非常重要的指标。sentinel-2、Landsat 等遥感器在过去四十年里一直在提供数据,这对于提取森林和水等土地覆盖类型很有用。研究人员提出了许多地表水提取技术,其中基于指数的方法因其简单和成本效益高而受到欢迎。一些广泛使用的水指数是:

  • 修正的归一化差异水指数
  • 归一化差异湿度指数(NDMI)

地质指数

事实证明,卫星图像和航空摄影是支持矿产勘探项目的重要工具。它们可以以多种方式使用。首先,它们为地质学家和野外工作人员提供轨迹、道路、栅栏和居住区的位置。

孙德尔本斯卫星数据的粘土和含铁矿物比例,图片由作者提供

  • 粘土矿物比率— 粘土比率是 SWIR1 和 SWIR2 带的比率。这一比率利用了粘土、明矾石等含水矿物吸收光谱中 2.0-2.3 微米部分的辐射这一事实。由于该指数是一个比率,因此可以减轻由于地形造成的光照变化。
  • 含铁矿物比率— 含铁矿物比率突出显示含铁物料。它使用 SWIR 波段和近红外波段之间的比率。

使用下面的文章,这是一个关于上述 Sundatbands 卫星数据的卫星指数的实践教程。

卫星图像中的监督学习

监督学习算法如 K-最近邻分类器(KNNC)、支持向量机(SVM)、深度神经网络(DNNs)、卷积神经网络(CNN)广泛应用于土地覆盖分类、多标签分类等领域

使用下面的文章,涵盖不同的卫星影像分类算法。

卫星图像中的无监督学习

无监督学习算法如主成分分析(PCA)、线性判别分析(LDA)、e.t.c 等被用于卫星图像的降维。KMeans、带噪声的基于密度的应用程序空间聚类(DBSCAN)等用于对卫星图像数据进行聚类。

使用下面的文章,涵盖了孙德尔本斯卫星影像的维数减少和聚类。

结论

这篇文章涵盖并帮助读者理解监督和非监督机器学习技术和指数,以分析卫星图像。文章中提到的实践教程可以通过 GitHub 资源库获得。

https://github.com/syamkakarla98/Satellite_Imagery_Analysis https://github.com/syamkakarla98/Hyperspectral_Image_Analysis_Simplified

参考

https://link.springer.com/chapter/10.1007/978-981-15-3338-9_12 https://landsat.gsfc.nasa.gov/landsat-8/landsat-8-bands

随机变量、随机过程及其性质的综合概述(第 1 部分)

原文:https://towardsdatascience.com/comprehensive-overview-of-random-variables-random-processes-and-their-properties-part-1-5c4692a338c6?source=collection_archive---------18-----------------------

在 Unsplash 上由 Klara Avsenik 拍摄的照片

这是一篇由两部分组成的文章。在第 1 部分(这一部分),我将回顾随机变量,随机向量,以及它们的性质。在第 2 部分,我将讨论随机过程及其性质。

随机变量和随机过程在现实世界中扮演着重要的角色。它们广泛应用于机器学习、信号处理、数字通信、统计学等领域。

以下是这篇文章的提纲:

概述

  • 概率复习。(第一部分)
  • 随机变量。(第一部分)
  • 随机变量的性质。(第一部分)
  • 概率中的重要定理。(第一部分)
  • 随机向量。(第一部分)
  • 随机过程(第二部分)
  • 随机过程的性质。(第二部分)
  • 不同类别的随机过程。(第二部分)
  • 随机过程通过 LTI 系统。(第二部分)
  • 机器学习、人工智能、信号处理中的重要随机过程。(第三部分)

托拜厄斯·凯勒在 Unsplash 上的照片

概率复习

概率被定义为一个事件在长期内的相对频率(频率主义者)或现实世界中不确定性或信念的度量(贝叶斯)。要了解更多关于贝叶斯和频率主义的观点,请参考这篇文章。

样本空间被定义为一个实验的所有可能实现的集合,用ω表示。比如抛硬币对应的样本空间是ω= { H,T}(其中 H =头,T =尾)或者掷骰子对应的样本空间是:ω= { 1,2,3,4,5,6}。

概率的三个众所周知的公理如下:

1-任何事件的概率介于 0 和 1 之间。

2-样本空间的概率为 1(它总是发生),即

3-如果 A 和 B 是两个任意事件,那么 A 或 B 的概率计算如下:

∪和∩分别表示逻辑 or 和逻辑 and。

图 1:使用文氏图的联合 B

设 A '是 A 的补,A 是样本空间中不在 A 中的所有元素的集合;那么下面的关系通常是正确的:

图 2:A 的补集的维恩图

图 3:A-B 的维恩图

图 4:A∪B 补码的维恩图

图 1、图 2、图 3 和图 4 分别代表 A 的并集 B、A 的补集、A -B 和 A 的并集 B 的补集的文氏图。文氏图是一种图形和直观的方式来表示集合及其关系。

随机变量

随机变量是样本空间元素到真实直线的映射。它既不是随机的,也不是可变的,但它是一个函数,其定义域是样本空间ω,其值域是ℝ(实数)。

图 5:从样本空间到真实线的映射

随机变量可以是离散的,连续的,或是两者的混合。我用大写字母表示随机变量,小写字母表示其值(有时称为实现)。离散随机变量用概率质量函数(PMF)来表示,概率质量函数是不同 k 值下随机变量 X 等于 k 的概率,例如抛一枚公平硬币对应的 PMF 如下:

作为另一个例子,考虑 PMF 掷出的公平骰子:

连续随机变量取特定值的概率为零。因此,它们不是由 PMF 表示,而是由概率密度函数(PDF)表示,概率密度函数是随机变量 X 在 X 和 x + δ之间的概率,通常用 f(x)表示。

图 PDF 的定义

累积分布函数或 CDF 被定义为随机变量 X 取值小于或等于 X 的概率。它被定义为离散和连续随机变量。

CDF 的一些重要属性如下:

1-是单调递增的。

2-是右连续(参考下图)。

图 CDF 的右连续性

3-随机变量 X 在 a 和 b 之间的概率计算如下:

CDF 和 PDF 可以按如下方式相互关联:

n 个随机变量的联合 CDF 定义类似:

有时我们会希望在给定随机变量 Y 已经发生的情况下,求出随机变量 X 的概率。这是用 P(X |Y)表示的条件概率的一个例子。人们可以认为所有的概率都是有条件的,因为它们取决于样本空间,例如:

上面的等式是正确的,因为样本空间以概率 1 发生,因此,我们不需要显式地写它。给定 Y,X 的条件概率计算如下:

上述等式背后的直觉如下:既然事件 Y 已经在发生,那么样本空间就从ω变为 Y,这就解释了分母。现在我们只关心 X 和 Y 之间常见的结果,这解释了分子。

注: P(X ∩ Y)有时写成 P(X,Y)。

从联合分布中寻找事件的边际概率/密度的过程称为边缘化,其定义如下:

边缘化是一个消除除了利益变量之外的其他变量的过程。这是通过对除感兴趣的随机变量之外的所有其他变量求和/积分来完成的。

综合发展框架的边缘化定义如下:

这意味着要找到 X₁的边际 CDF,我们所要做的就是用联合 CDF 表达式中的∞来代替其他随机变量。从上面的公式可以明显看出这一点,因为任何变量都小于∞的概率为 1。以下是 CDF 的更多属性:

由威尔·斯图尔特在 Unsplash 上拍摄的照片

随机变量的性质

在这一节中,我将讨论在统计、机器学习、信号处理等领域广泛使用的随机变量的一些众所周知的性质。

均值、方差和协方差

随机变量 X 的平均值或期望值定义如下:

连续随机变量由 PDF 定义并使用积分计算,而离散随机变量由 PMF 定义并通过求和计算。
方差是随机变量相对于平均值的离差或可变性的度量。方差越大,平均值的分布越广。数学上定义如下:

协方差是两个随机变量相对于彼此的线性可变性的度量。其定义如下:

在上面的等式中,用 X 代替 Y,就可以用协方差得到随机变量的方差。

使用协方差推导方差

假设 X 和 Y 是两个任意随机变量,并且 ab 是两个定标器,那么下面是期望值、方差和协方差的一些重要属性:

协方差、期望和方差的性质

这些属性用简单的英语表达如下:

  • 期望值是一个线性算子,因此它满足叠加性质(同质性和可加性(前两行))。
  • 给随机变量加一个常数不会改变随机变量的方差。
  • 将随机变量乘以常数 a 会将变量的方差乘以a
  • 将常数 ab 加到任一随机变量上不会改变它们之间的协方差。
  • 将任意一个随机变量乘以常数 a 会将它们之间的协方差乘以 a.

皮尔逊相关

用符号ρ表示的皮尔逊相关或简称相关,度量两个随机变量或向量之间的线性相关。其定义如下:

皮尔逊相关

在某种意义上,皮尔逊相关是两个随机变量之间的归一化协方差。ρ的最大值为+1,表示完全正相关,-1 表示完全负相关,0 表示没有线性相关。

独立性和条件期望

两个随机变量 X 和 Y 被认为是独立的,如果知道了其中一个,你就不会得到关于另一个随机变量的额外信息。回想一下条件概率的定义,就是给定随机变量 Y 已经发生的情况下,随机变量 X 的概率。如果 X 和 Y 是独立的,下面的关系是真的:

独立性的定义

回想一下,条件概率也可以用联合概率和边际概率来定义。因此,独立性的一个更常见的定义是:

用联合概率定义独立性

上面的等式说的是两个随机变量的联合分布等于它们的边值的乘积。

给定随机变量 Y,随机变量 X 的条件期望定义如下:

互斥事件

两个事件 A 和 B 是互斥的,如果它们的交集是空的。
数学上定义为 A ∩ B = ∅,或者 P(A ∩ B ) = 0。

图 8:两个互斥事件的示意图

独立与不相关的随机变量

如果随机变量 X 和 Y 是独立的,那么它们是不相关的(因为它们之间的协方差是零),但是反过来不一定是正确的,除非 X 和 Y 是联合高斯分布,那么独立和不相关是相同的事情。
在本文的第 2 部分中,当我讨论高斯随机过程时,我再次提到了这个概念。

概率中的重要定理

全概率定律 如果 B₁,B₂,。。。,Bₙ这样划分样本空间:

这意味着它们的并集跨越样本空间,并且它们是互斥的(它们的交集是空的)。那么任何事件 A 都可以表示如下:

图 9:全概率定律的文氏图

贝叶斯定理 这是机器学习、信号处理、统计学等领域中应用最广泛的定理之一。它是把给定 B 的条件概率和给定 A 的 B 的条件概率联系起来的一种方法,在另一个世界里,它是把似然和后验分布联系起来的一种技术。其数学定义如下:

图 10:贝叶斯法则

有关贝叶斯定律、后验概率和可能性的更多信息,请参考以下文章和 Youtube 视频。

总期望定律
假设你想知道加州大学洛杉矶分校平均有多少学生喜欢下棋。一种方法是亲自采访每一个学生,用爱下棋的学生人数除以学生总数,得出平均值。然而,这种技术非常繁琐,并且不可扩展。
相反,更实用的方法是按专业/系对学生进行分类,并计算每个系喜欢下棋的学生的平均人数(这可以由多人完成,每个人采访一个系),然后在这些平均人数中找出平均值,得出想要的结果。从数学上来说,这写如下:

总期望定律

这里 y 是划分人的标准(像专业、科室、性别、年龄等)。

中心极限定理(CLT) 中心极限定理指出,如果 X₁、X₂、.。。、Xₙ均为独立同分布随机变量,均值为μ,方差为σ,随机变量 Zₙ定义如下:

当 n 趋于∞(变得很大)时,Zₙ的 CDF 收敛于标准的正常 CDF。关于 CLT 的好处是,它与 X₁、X₂等发行版无关。。。、Xₙ都有,它们可以是离散或连续的随机变量。

随机向量

随机变量的下一个扩展是随机向量。它被定义为有限数量的随机变量的集合。例如, X 是一个随机向量,如下所示:

X 的每个元素都是随机变量,具有一定的概率分布、均值、方差等。随机向量 X 的 CDF 定义如下:

由于 X 的每个元素都是随机变量,因此不同分量之间可能存在相关性,因此我们定义协方差矩阵来捕捉所有元素之间的方差和协方差。

均值和协方差矩阵的定义

因此,协方差矩阵是这样的矩阵,其主对角线上的元素是每个分量的方差,非对角线元素是每两个随机变量之间的协方差。
回想一下皮尔逊相关的定义及其与两个随机变量协方差的关系。上述协方差矩阵可以写成如下形式:

基于皮尔逊相关的协方差矩阵定义

现在,让我们讨论协方差矩阵的性质。

  • 它是对称的,因为 X₂的 cov(x₁= x₁).的 Cov(X₂
  • 它是半正定的。这意味着:

  • 它的所有特征值都是非零的。

高斯随机向量

如果随机变量 X₁,X₂,。。。,Xₙ是联合高斯那么随机向量 x 是高斯随机向量和 X₁,X₂,.。。,Xₙ也是高斯随机变量。
高斯随机向量 X 的 PDF 由其均值向量μ和协方差矩阵 c 表征。其数学定义如下:

高斯随机向量的 PDF

如果一个高斯随机向量有一个对角协方差矩阵,那么它的分量都是独立和不相关的。这是因为每两个元素的协方差为零。

结论

在这篇文章中,我讨论了概率规则,随机变量,随机向量,它们的性质,以及概率论中的重要定理。这是这个两部分文章的第一部分。

在下一部分,我将讨论随机过程,它的性质,随机过程的不同类别,以及通过 LTI 系统的随机过程。

随机变量、随机过程及其性质的综合概述(第 2 部分)

原文:https://towardsdatascience.com/comprehensive-overview-of-random-variables-random-processes-and-their-properties-part-2-4cf352a9b7f2?source=collection_archive---------8-----------------------

你所需要的关于随机过程和它们的性质

在 Unsplash 上 Matteo Catanese 拍摄的照片

这是一篇由两部分组成的文章。在第 2 部分(这一部分),我将回顾随机过程(随机过程),它们的性质,以及它们对线性时不变(LTI)信道的响应。在第 1 部分中,我讨论了概率、随机变量及其性质。如果您尚未阅读第一部分,请先阅读以下内容:

第一部分是理解这一部分的基础,因为随机过程是随机变量和随机向量的一般扩展。
随机变量和随机过程在现实世界中扮演着重要的角色。它们广泛应用于机器学习、信号处理、数字通信、统计学等领域。

以下是这篇文章的提纲:

概述

  • 概率的复习。(第一部分)
  • 随机变量。(第一部分)
  • 随机变量的性质。(第一部分)
  • 概率中的重要定理。(第一部分)
  • 随机向量。(第一部分)
  • 随机过程(第二部分)
  • 随机过程的性质。(第二部分)
  • 不同类别的随机过程。(第二部分)
  • 随机过程通过 LTI 系统。(第二部分)
  • 机器学习、人工智能、信号处理中的重要随机过程。(第三部分)

照片由 Kunal Shinde 在 Unsplash 上拍摄

随机流程

随机过程 X(w;t)是 t 和 w 的时变函数,其中 t 通常是时间,w 是样本空间的元素(ω)。因此,有两种方法来看待随机过程。
案例一:t(时间)固定,w 在变化:

图 1:固定 t 的随机过程定义

如果 t 固定为 t = tᵢ,那么当 w 变化时,我们得到 I 的每个值的随机变量。因此,如果 w 在变化,随机过程就是随机变量的集合。
情况二:w 不变,t 在变:

图 2:固定 w 的随机过程

如果 w 固定在 wᵢ,那么我们得到一个时域信号或实现。因此,对于固定的 w,随机过程是确定的时域函数。

观察 1: 随机过程中的随机性是由于 w,而不是 t,因此,在随机过程的定义中通常省略 w(假设 w 是变化的);因此,我们有时称随机过程 X(w,t)为 X(t)。

**直觉:**把随机过程想象成一包时域信号(函数、实现),每次你把手放进包里,抓住其中一个信号,但你不知道你拿的是哪一个(这就是随机性的来源)。

**观察二:**你可以把一个随机过程看成一个 n 维随机向量的一般版本,其中 n 趋近于无穷大。

你可以在我的 Youtube 频道上找到更多关于随机过程的信息:

随机过程的性质

随机过程由一些属性描述,例如均值、自相关、互相关、自协方差、功率谱密度和平均功率。
均值,或随机过程 X(t)的平均值(回想一下,由于假设它是变化的,所以符号中遗漏了 w),定义类似于随机变量和随机向量(请参考第 1 部分)。

观察 3: 回想一下当 w 在变化时,一个随机过程对于每个时间 t 都是一个随机变量,因此在每个时间点,随机变量的期望就是均值。一般来说,平均值是时间函数。

随机过程 X(t)的自相关被定义为随机过程 X(t)在不同时间点与其自身(因此单词 auto)的相关性。

图 3:不同时间点的随机过程。

随机过程 X(t)的自协方差被定义为随机过程 X(t)在不同时间点与其自身(因此单词 auto)的协方差。

关于两个随机变量的协方差的定义,请参考第 1 部分的文章(链接在上面的介绍中给出)。

随机过程 X(t)和 Y(t)之间的互相关是两个不同时间点上它们之间相关性的度量。

功率谱密度(PSD)被定义为每个频带中的功率量,并且是自相关函数的傅立叶变换。在下一节讨论广义平稳(WSS)过程时,我将更多地讨论 PSD 和总功率。
如果 t 取实线上的任意值,那么 X(t)称为连续时间随机过程(随机过程),如果 t 是可数集合的成员,那么 X(t)是随机序列。
观测 4: { X(t),t ∈ ℝ}称为连续时间随机过程而{ X(t),t ∈ ℕ}称为离散时间随机过程或随机序列。

不同类别的随机过程

平稳过程

如果过程 X(t)的统计特性(CDF、PDF 等)不随时间变化,则称其为平稳过程。例如,X(t)是静止的当且仅当:

观察值 5: 上式说的是,对于任意 t 和任意δ,平稳过程的 CDF 随时间保持不变。

同样对于平稳过程,X(t₁和 X(t₂的联合分布随时间保持不变。数学上,这定义如下:

平稳过程也称为严格意义上的平稳过程(SSS),如果对 t₁、t₂、。。、tₙ和任何δ,满足以下条件:

一般来说,要证明一个进程是否是 SSS 是非常困难的,因此我们关注较弱的符号。

弱/广义静止(WSS)

如果对于所有 t₁、t₂ ∈ ℝ和所有δ∈ℝ,以下两个条件成立,则 X(t)是 WSS 过程:

观察值 5: 如果一个过程的均值是常数,且其自相关是时滞的函数,则该过程是 WSS(t₁- t₂).时滞通常用τ表示。

从现在开始,我将关注 WSS 过程,因为大多数真实世界的过程都被建模为 WSS 过程。

有关随机过程的更多内容,请访问我的 YouTube 频道:

WSS 过程自相关的性质

1-这是时间滞后的唯一功能。

2-它是一个偶数函数。

3-滞后(τ)为零时的自相关给出平均功率。

4-当时滞为零时,出现自相关的最大值。

5-如果 X(t)是实值随机过程,则自相关是实值函数。

欲了解更多信息,请访问我的 YouTube 频道:

联合 WSS 进程

如果下列两个条件成立,则称两个随机过程 X(t)和 Y(t)是联合 WSS:

观察值 6: 上述两个条件表明,对于联合 WSS 的过程 X(t)和 Y(t ),则每一个都应该是 WSS(常数均值和自相关应该只是时滞的函数),而互相关(第二个条件)应该只是时滞的函数。

功率谱密度

PSD 被定义为 WSS 过程的自相关的傅立叶变换。它用符号 s 表示。

WSS 过程的功率谱密度特性

1-如果 X(t)是实值随机过程,则它是实值函数。

2-它是一个偶数函数。

PSD 曲线下的面积是平均功率。

属性 3 是最重要的一个,因为它提供了三种不同的方法来计算随机过程的平均功率。

观察值 7: 通过对 PSD 曲线下的面积进行积分,计算零点滞后处的自相关函数,计算随机过程的期望平方,从而计算出信号的平均功率。

通过 LTI(线性时不变)系统的随机过程

线性系统由脉冲响应函数 h(t)唯一表示。如果 X(t)和 Y(t)是线性系统的输入和输出,则 Y(t)可以计算为 X(t)和脉冲响应 h(t)的卷积。

图 4:线性系统输入输出关系

如果 X(t)是随机过程并且被输入到 LTI 系统,那么输出 Y(t)也是随机过程。

定理 1: 若 X(t)是 WSS 随机过程,并以脉冲响应 h(t)输入 LTI 系统,则 X(t)和 Y(t)共同为 WSS 过程。

由于 Y(t)是一个 WSS 随机过程,那么它的平均值是常数,它的自相关只是时间滞后的函数。以下是 Y(t)的平均值、自相关性以及 X(t)和 Y(t)之间的互相关性的表达式。

观察值 7: 由于 X(t)是 WSS 过程,因此它具有恒定的平均值,因此 Y(t)的期望值也是恒定的(等式 1)。等式 2 表示 X(t)和 Y(t)之间的互相关只是时滞的函数。等式 3 表示输出的自相关仅是时滞的函数。(等式 1 和 3 声称 Y(t)是 WSS 过程,等式 1、2 和 3 声明 X(t)和 Y(t)共同是 WSS 过程。)

频域分析

假设 H(f)是 LTI 系统的频率响应(脉冲响应的傅立叶变换),Sx(f)和 Sy(f)(输入和输出的自相关的傅立叶变换)分别是输入和输出的功率谱密度,则可以在频域中分析上述方程。

观测 8: 在求联合 X(t)和 Y(t)(方程 5)的功率谱密度时,我们利用了 H(-f)是 H(f)的共轭的性质(傅里叶变换性质。)

结论

在这篇文章中,我讨论了随机过程,它们的性质,不同类别的随机过程,以及通过 LTI 系统的随机过程。在下一部分(第三部分),我将回顾机器学习,人工智能和信号处理中的重要随机过程,如马尔可夫链,高斯随机过程,隐马尔可夫模型(HMM)等。

最小二乘估计的综合研究(上)

原文:https://towardsdatascience.com/comprehensive-study-of-least-square-estimation-part-1-32d24347f9e3?source=collection_archive---------24-----------------------

普通、约束、多目标和非线性最小二乘。

Lukasz Szmigiel 在 Unsplash 上的照片

最小二乘估计是机器学习、信号处理和统计中使用最广泛的技术之一。这是解决线性回归的常用方法,广泛用于模拟连续结果。

它可以被建模为具有二次成本的 MMSE 估计量或贝叶斯估计量。我已经写了关于机器学习和信号处理中使用的各种估计器的综合文章。请查看以下文章了解更多信息。

我还制作了一系列 YouTube 视频来更深入地了解各种评估技术。请查看并订阅我的 YouTube 频道了解更多信息。

这是一篇由三部分组成的文章,讨论了关于最小二乘估计的所有要点。下面是这篇文章的提纲:

概述

  • 普通最小二乘(OLS)估计
  • OLS 问题的解决
  • 正交原理
  • OLS 使用 QR 分解(高级读者)
  • 矩阵的最小二乘问题
  • 多目标最小二乘法(第二部分)
  • 约束最小二乘法(第三部分)
  • 非线性最小二乘法(第四部分)

在本文中,我将深入讨论最小二乘,在以后的文章中,我将深入讨论多目标、约束和非线性最小二乘。我还将链接到我在 YouTube 上关于最小二乘主题的视频,以获得更多信息和更全面的解释。

普通最小二乘法(OLS)

假设 A 是一个 m×n 矩阵,其中 m 大于或等于 n (A 是一个高矩阵),那么下面的超定方程组或者有唯一或者无解

图 1:线性方程

如果 b 是 a 的列的线性组合,唯一的解决方案就会出现,这意味着如果你认为 a 被写成列表示,那么 b 将在 a 的列空间中。另一种解释方式是,有 scaler x₁,x₂。。。,xₙ,使得下面的方程有解。

图 2:线性无关的条件

**注:**要知道为什么如果解存在,那么它是唯一的,考虑最小二乘问题的假设。它声明 A 是高的,并且有线性无关的列,那么它有一个左逆。然后把方程 1 的左右两边乘以 A 的左逆,就得到唯一解了。本文的其余部分解释了如何找到这个解决方案。

:要了解超定、待定方程组、高、宽矩阵、矩阵的行列解释,请参考以下视频:

如果 Ax = b 无解,那么我们的目标是找到 x,使得它最小化 Ax 和 b 之间的距离的范数。

图 3:最小二乘问题公式化

最小二乘法的列解释:

对于列解释,我们试图找到与向量 b 最接近的 A 列的线性组合。数学上,这可以表示如下:

图 4:最小二乘法的列表示

最小二乘法的行解释;

对于行解释,我们试图最小化对应于 m 个线性方程的 m 个残差的总和。

图 5:最小平方的行表示

r 是残差向量,其中 r 的每个分量对应于线性方程中的一个残差。例如:

图 6:最小二乘法的行表示

最小二乘问题的解

这里我将介绍两种解决 OLS 问题的方法。这两种方法是等效的。

方法 1: 基于组件的符号

图 7:最小二乘解

这种方法是基于将目标函数 J 写成它的分量,然后对目标函数 x 求微分,并将其设置为零。

图 8

**方法二:**矩阵-向量表示法
这种方法是基于将向量的欧氏范数写成向量转置和自身的乘积。

图 9:使用矩阵向量符号的最小二乘解

产生最小二乘问题的解的以下方程被称为标准方程。

图 10:法线方程

方法 1 和 2 产生相同的结果,但是方法 1 是基于元素的格式,而方法 2 给出了更简洁的解决方案。

解决方案的解释

(AᵗA)⁻ A(转置的乘积,a 被称为格拉姆矩阵,并且如果 a 具有线性独立的列,则它是可逆矩阵)被称为矩阵 a 的左伪逆。这意味着:

**注:**若 A 是左可逆矩阵(有线性无关列)最小二乘解存在且唯一。

**注:**要了解更多关于 gram 矩阵、左可逆矩阵和右可逆矩阵的信息,请参考以下视频:

正交原则:

我在“基本参数估计技术文章”中讨论了一般估计量的正交性原理,请参考以下参考资料了解更多信息

但是这里我将在最小平方估计的上下文中引入正交性原理。
正交性原理说明残差与最优估计量正交。

例如,考虑下图:

正交原理

b 是我们想要估计的向量,r 是残差,Ax 是估计量。

图 11:正交条件

现在,为了检查最小二乘解是否是最优解,我们进行如下:
如果 x 是最小二乘解,则正规方程成立,意思是:

因此,正交性原则如下:

其中最后的结果是由于正常的方程。上述等式表明,如果 x 是最小二乘解,则 Ax 与残差正交,因此 Ax 是向量 b 的最佳估计量

OLS 使用 QR 分解(高级题目)

这一节需要接触 QR 分解,这就是为什么我把它归类为一个更高级的主题。有关 QR 方法的信息和逐步解释,请观看以下视频:

我们将首先通过让 A = QR 使用 QR 分解来分解矩阵 A,其中 Q 是正交矩阵,R 是上三角矩阵。然后我们用它的 QR 分解等价物代替 OLS 解中的 A。

图 12:使用 QR 分解的最小二乘解

最后一行表示使用 QR 分解的解决方案。QR 分解提供了一种使用以下算法求解最小二乘法的有效方法:

  • 求矩阵 A 的 QR 分解,即 A = QR。
  • 计算 Q 转置和 b 的乘积。
  • 用回代法解下式(因为 R 是上三角矩阵)。

矩阵的最小二乘问题

假设 A 是 m×n 矩阵,X 是 n×p 矩阵,B 是 m×p 矩阵。然后目标是最小化 Ax-B 的 Frobenius 范数。该问题类似于根据矩阵 X 和 B 的列表示来表示矩阵 X 和 B 之后的向量的最小二乘问题。

**注:**矩阵的欧几里德或弗罗贝纽斯范数定义如下:

其中 aᵢⱼ是矩阵 a 的 iᵗʰ行和 jᵗʰ列的元素 aᵢ是矩阵 a 的 iᵗʰ列上面等式说的是一个矩阵的 Frobenius 范数是每列的欧氏范数之和。 因此结果简化如下:

可以看出,| | AX-B | |(Frobenius 范数的平方)可以写成 p 个普通最小二乘目标函数之和,但是每个目标函数都可以独立最小化。因此,实际上我们正在求解 p 个独立的最小二乘问题,以找到对应于矩阵 x 的 p 列的 p 个最优解。

在更简洁的形式中,该解可以表示如下:

完成第一部分后,请务必查看第二和第三部分。第 2 部分讨论了多目标最小二乘法。第 3 部分讨论了约束最小二乘问题。

结论

在本文中,我讨论了普通的最小二乘问题,解决方案的行和列解释,正交性原则,以及使用 QR 分解的 OLS 解决方案。在下一篇文章中,我将讨论多目标和约束最小二乘问题。
我在之前的一篇关于“基本参数估计技术”的文章中讨论过 OLS(那篇文章的链接在这里给出)。
在我的 YouTube 频道中还有一个完整的关于数值线性代数和优化的系列视频,在其中我详细讨论了所有这些主题。

最小二乘估计的综合研究(下)

原文:https://towardsdatascience.com/comprehensive-study-of-least-square-estimation-part-2-8a0b5549c1?source=collection_archive---------37-----------------------

普通、约束、多目标和非线性最小二乘。

杰伊·曼特里在 Unsplash 上的照片

在第一部分,我详细讨论了普通最小二乘问题。在这一部分(第二部分),我将回顾多目标最小二乘问题。如果您尚未阅读第一部分,请参考以下文章了解更多信息:

[## 最小二乘估计的综合研究(上)

towardsdatascience.com](/comprehensive-study-of-least-square-estimation-part-1-32d24347f9e3)

更多信息和更详细的解释,请参考我的 YouTube 频道。

https://www.youtube.com/channel/UCjNDIlqrFdKUgSeN9wV-OzQ/featured

多目标最小二乘

假设我们正在寻找一个使多个目标/成本函数变小的解决方案。这个问题被称为多目标优化问题。如果所有的目标函数都是最小二乘问题的形式,那么这个问题就叫做多目标最小二乘问题。

问题定式化

假设我们有 K 个最小二乘目标函数,我们的目标是找到一个使它们都变小的 x。

图 1:多目标最小二乘问题公式化

其中每个 Aᵢ是 mᵢ×n 矩阵,每个 bᵢ是 mᵢ×1 向量。
有许多方法可以解决和制定多目标 LS 问题,但最常用的方法可能是最小化所有目标函数的加权和,其中权重决定每个目标函数的影响或重要性。

图 2:多目标最小二乘问题公式化

其中λ是每个目标函数的权重。这里我介绍两种解决多目标最小二乘问题的方法。

方法一:直接求导 在这种方法中,我们取 Jₜₒₜ关于 x 的导数,并设为零。

图 3:使用直接微分的多目标最小二乘解

虽然这种方法看起来足够简单,但是第二种方法更常见,并且提供了更好的直觉。
方法 1:堆叠矩阵 这是解决多目标 LS 问题的更好方法,因为它利用了 OLS 问题的解决方案,并将问题直接建模为 OLS 问题。
我们首先构建一个新的矩阵 A 和 B,然后使用我们在图 2 中推导出的公式将问题表述为一个简单的 OLS 问题,如下所示。

图 4:使用堆叠矩阵的多目标 LS 解决方案

这种方法仅在堆叠的 A 具有类似于 OLS 的线性独立列的情况下有效,其中它要求矩阵 A 具有线性独立的列(高和左可逆矩阵)。

当堆叠矩阵具有线性独立的列时

如前所述,要使用堆叠矩阵方法,我们需要确保堆叠矩阵是左可逆的或具有线性独立的列,这意味着:

图 5:线性无关列的条件

  • 如果矩阵 A₁、A₂、.。。,Aₖ具有线性独立的列,那么堆叠矩阵将具有线性独立的列。
  • 然而,堆叠矩阵可以具有线性独立的列,即使所有矩阵 A₁、A₂、.。。,Aₖ具有线性相关的列,并且这在满足以下条件时发生:
    假设 A₁是 m₁x n,A₂是 m₂ x n,Aₖ是 mₖx n,则如果每个 m_i 小于或等于 n,但是它们的和大于或等于 n,则堆叠矩阵仍然是高的,并且可以是左可逆矩阵(线性独立的列)。从数学上来说,这意味着:

图 6:线性无关列的条件

吉洪诺夫正则化

假设你正试图解决一个最小二乘问题:

  • 矩阵 A 没有线性无关的列。
  • 或者我们希望最小化||Ax — b||使得||x||很小(x 的范数很小)。

表述这个问题的一种方法如下:

图 7:正则化最小二乘法

在图 7 中,λ是一个正权重,决定了第二个目标函数相对于第一个目标函数的重要性。如果λ是零,那么我们回到 OLS。如果λ很小,那么我们在第一个目标函数上放置更多的权重。这是通过将主要目标函数的权重归一化为 1 并让λ表示相对权重来公式化多目标问题的常见方式。

为了求解上述方程,我们可以使用方法 1 或方法 2,但为了演示堆叠矩阵方法,我们将使用第二种方法。

图 8:使用堆叠矩阵正则化最小二乘法

在解决图 8 中的上述问题之前,证明堆叠矩阵 A 具有线性独立的列是很重要的。有两种方法可以证明这一点:

  1. 单位矩阵具有线性无关的列,因此无论 A 是否具有依赖列,堆叠矩阵都具有线性无关的列。
  2. 按照标准程序证明色谱柱的线性独立性:

图 9:证明堆叠矩阵有线性无关的列

既然堆叠矩阵具有线性独立的列,那么解可以容易地确定如下:

图 10:正则化最小二乘解

想了解更多关于多目标最小二乘法的知识,请参考我的 YouTube 频道。

接下来是什么:

请务必阅读第 3 部分关于约束最小二乘法的文章。

[## 最小二乘估计的综合研究(三)

towardsdatascience.com](/comprehensive-study-of-least-square-estimation-part-3-9ebefbbe8634)

结论

在本文中,我讨论多目标最小二乘问题,在下一部分(第 3 部分)我将讨论约束最小二乘问题。
如果你觉得这篇文章或上一篇文章的任何部分很复杂,请参考我的 YouTube 频道,那里有一系列关于数值线性代数和优化的视频,不需要矩阵代数或优化的先验知识。

最小二乘估计的综合研究(三)

原文:https://towardsdatascience.com/comprehensive-study-of-least-square-estimation-part-3-9ebefbbe8634?source=collection_archive---------35-----------------------

普通、约束、多目标和非线性最小二乘法

威尔·斯图尔特在 Unsplash 上拍摄的照片

这是“最小二乘估计的综合研究”系列文章的第三部分。在前两部分,我讨论了普通最小二乘和多目标最小二乘问题。如果您尚未阅读前两部分,您可以在此查看:

在本文中,我将讨论在机器学习、控制、信号处理和统计中经常出现的约束最小二乘问题。
和以前一样,我想鼓励你看看我的 YouTube 频道上关于数值线性代数和最优化(我有多个关于最小二乘法的视频)、随机过程和参数估计技术的完整系列视频。

https://www.youtube.com/channel/UCjNDIlqrFdKUgSeN9wV-OzQ

约束最小二乘法

约束最小二乘问题试图寻找线性约束最小二乘问题的解。问题的一般形式如下:

图 1:约束最小二乘法

在图 1 中,||Ax-b||称为目标函数,Cx = d 是线性约束集(与 C 的行数一样多)。a 是 m×n,C 是 p×n 矩阵。向量 x、b 和 d 分别是 n×1、m×1 和 p×1。线性约束可以写成如下的 p 个线性方程:

图 2:线性约束

我们称一个向量 x 为最优向量,如果它使目标函数最小,并且满足约束条件。

约束最小二乘问题也可以表述为多目标最小二乘问题,如下所示:

图 3:作为多目标 LS 的约束 LS

上述等式背后的逻辑如下:如果λ非常大,并且我们的目标是最小化两个目标函数的加权和,其中一个目标函数由λ加权。然后我们需要确定乘以λ的东西实际上是零。因此,Cx-d 的范数应该为零,因此 Cx = d。

最优性条件(拉格朗日乘数)

拉格朗日乘子是一种众所周知的解决约束优化问题的强大算法。在本文中,我们使用拉格朗日乘子法来驱动约束最小二乘问题的最优性条件。

假设我们的目标是使用拉格朗日乘数法解决图 1 中给出的一个问题。

  • 首先,按如下方式构造拉格朗日函数:

图 4:图 1 的拉格朗日函数

其中 z 是 p×1 个拉格朗日乘数的向量。

  • 将 L(x,z)相对于 x 和 z(原始变量和拉格朗日乘数)求微分,并将其设置为零。

图 5:最优性条件

  • 最后,将所有内容以更紧凑的形式放在一起,得到了众所周知的约束最小二乘的最优性条件:

图 6:约束 LS 的最优性条件

最优性条件通常被称为 **KKT 条件。**图 6 左侧的矩阵称为 KKT 矩阵。

约束最小二乘解

为了找到最佳 x,我们倾向于求解图 6 中的矩阵向量方程。因此我们需要找到 KKT 矩阵可逆的条件。我们来看看维数:A 是 m x n,C 是 p x n 个矩阵,d 是 p x 1,b 是 m x 1 个向量。因此 KKT 矩阵是一个正方形(p + n) x (p + n)矩阵。为了找到可逆性的条件,我们对平凡的零空间或线性无关的列施加条件。

图 7

将图 7 中顶部的等式乘以 x 转置,并使用底部的等式得出以下结果:

图 8:KKT 矩阵可逆的条件

将图 7 和图 8 中的等式放在一起,我们得出 KKT 矩阵可逆的以下两个条件:

图 9:KKT 矩阵可逆的条件

因此,KKT 矩阵可逆的条件是 A 和 C 的堆叠矩阵应该具有线性独立的列,C 应该具有线性独立的行(请参考 YouTube 视频和关于矩阵和最小二乘法的讲座,以完整掌握这些概念)。

  • 如果满足上述条件,则可以找到如下解决方案:

图 10:受限 LS 的解决方案

结论

在本文中,我讨论了约束最小二乘问题。在前两部分中(我讨论了普通最小二乘法和多目标最小二乘法问题,您可以在本文开头找到这些文章的链接)。

在下一部分,我将讨论非线性最小二乘问题。请务必订阅我的 YouTube 频道,获取更多视频和更详细的解释。

压缩无监督的快速文本模型

原文:https://towardsdatascience.com/compressing-unsupervised-fasttext-models-eb212e9919ca?source=collection_archive---------15-----------------------

如何将单词嵌入模型减少 300 倍,同时在下游 NLP 任务上具有几乎相同的性能

FastText 是一种将单词编码为数字向量的方法,由脸书于 2016 年开发。预训练的快速文本嵌入有助于解决文本分类或命名实体识别等问题,并且比 BERT 等深度神经网络更快、更易于维护。然而,典型的快速文本模型是非常巨大的:例如,脸书的英语模型,解压缩后占据了 7GB 的磁盘空间。

在这篇文章中,我展示了 Python 包 compress-fasttext ,它可以将这个模型压缩到 21MB (x300!)在准确性上只有轻微的损失。这使得 fastText 在磁盘或内存有限的环境中更有用。

作者图片:利用 smolness 迷因制作 fastText(由迷因库生成)

在本文的第一部分,我展示了如何使用压缩的 fastText 模型。在第二部分,我解释了 fastText 及其压缩背后的一些数学原理。

怎么用?

使用现有模型

简单用pip install compress-fasttext就可以安装包了。它基于 fastText 的 Gensim 实现,具有相同的接口。模型可以直接从 web 加载到 Python 中:

import compress_fasttext
small_model = compress_fasttext.models.CompressedFastTextKeyedVectors.load(
'https://github.com/avidale/compress-fasttext/releases/download/v0.0.4/cc.en.300.compressed.bin')

您可以将这个模型视为一个字典,它将任何单词映射到它的 300 维向量表示(也称为嵌入):

print(small_model['hello'])
# [ 1.847366e-01  6.326839e-03  4.439018e-03 ... -2.884310e-02]  
# a 300-dimensional numpy array

词义相近的词往往有相似的嵌入。因为嵌入是向量,它们的相似性可以用余弦度量来评估。对于相关的单词(例如“猫”和“狗”),余弦相似度接近 1,而对于不相关的单词,余弦相似度接近 0:

def cosine_sim(x, y):
    return sum(x * y) / (sum(x**2) * sum(y**2)) ** 0.5print(cosine_sim(small_model['cat'], small_model['cat']))
# 1.0print(cosine_sim(small_model['cat'], small_model['dog']))
# 0.6768642734684225print(cosine_sim(small_model['cat'], small_model['car']))
# 0.18485135055040858

实际上,你可以使用余弦相似度来查找一个单词的最近邻。例如,我们的压缩 fastText 模型知道 Python 是一种编程语言,并认为它类似于 PHP 和 Java。

print(small_model.most_similar('Python'))
# [('PHP', 0.5253), ('.NET', 0.5027), ('Java', 0.4897),  ... ]

在实际应用中,您通常将快速文本嵌入提供给其他模型。例如,您可以在 fastText 上训练一个分类器来区分可食用和不可食用的东西:

import numpy as np
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.base import BaseEstimator, TransformerMixinclass FastTextTransformer(BaseEstimator, TransformerMixin):
    """ Convert texts into their mean fastText vectors """
    def __init__(self, model):
        self.model = model def fit(self, X, y=None):
        return self def transform(self, X):
        return np.stack([
            np.mean([self.model[w] for w in text.split()], 0)
            for text in X
        ])

classifier = make_pipeline(
    FastTextTransformer(model=small_model), 
    LogisticRegression()
).fit(
    ['banana', 'soup', 'burger', 'car', 'tree', 'city'],
    [1, 1, 1, 0, 0, 0]
)classifier.predict(['jet', 'cake'])
# array([0, 1])

有什么型号

一些英语和俄语的模型可以从发布页面下载。对于英语,建议使用25MB 型号,尺寸和精度平衡良好。

作者图片:https://github . com/avidale/compress-fast text/releases/tag/gensim-4-draft截图。

如果你需要其他语言,你可以看看 Liebl Bernhard 的集合,它包含了 101 种语言的压缩快速文本模型。

压缩模型

如果您想要创建自己的压缩模型,您需要安装带有一些额外依赖项的库:

pip install compress-fasttext[full]

首先,您需要加载您将要压缩的模型。如果模型已经使用脸书包进行了训练,则按如下方式加载它:

from gensim.models.fasttext import load_facebook_model
big_model = load_facebook_model('path-to-original-model').wv

否则,如果模型是 Gensim 格式的,则将其加载为

import gensim
big_model = gensim.models.fasttext.FastTextKeyedVectors.load('path-to-original-model')

现在,您可以用三行代码压缩模型:

import compress_fasttext
small_model = compress_fasttext.prune_ft_freq(big_model, pq=True)
small_model.save('path-to-new-model')

如果您愿意,可以使用额外的参数来控制模型的大小:

small_model = compress_fasttext.prune_ft_freq(
    big_model, 
    new_vocab_size=20_000,   # number of words
    new_ngrams_size=100_000, # number of character ngrams
    pq=True,                 # use product quantization
    qdim=100,                # dimensionality of quantization
)

通过使用较小的词汇大小和维数,您创建了一个较小的模型,但相对于原始模型降低了其准确性。

它是如何工作的?

相关著作

最初的 fastText 库确实支持模型压缩(甚至有一篇关于它的论文),但是只针对在特定分类任务上训练的监督模型。另一方面, compress-fastText 用于无监督模型,提供可用于多项任务的单词向量。我的作品部分基于 Andrey Vasnetsov 2019 年的文章,部分基于俄罗斯 navec 图书馆。它最初是在我的俄语帖子中描述的。

fastText 可以压缩到什么程度?

FastText 不同于其他单词嵌入方法,因为它将单词的嵌入与字符 n 元语法(即几个连续字符的序列)的嵌入相结合。单词和 n-grams 的嵌入被平均在一起。如果单词不在词汇表中,则它只由 n-grams 组成,这使得 fastText 可以顺利地处理拼写错误的单词、新词和具有丰富词法的语言。

以下伪代码演示了计算过程:

def embed(word, model):
    if word in model.vocab:
        result = model.vectors_vocab[word]
    else:
        result = zeros()
    n = 1
    for ngram in get_ngrams(word, model.min_n, model.max_n):
        result += model.vectors_ngrams[hash(ngram)]
        n += 1
    return result / n

正如你所看到的,所有的信息都来自两个矩阵,vectors_vocabvectors_ngrams,这些矩阵占据了空间。大型矩阵的大小可以通过几种方式来减小:

  • 删除矩阵中的大多数行,只保留最常用的单词和 n-gram;
  • 存储精度较低的矩阵(float16 代替float32);
  • 将矩阵分成小块,对它们进行聚类,并存储相应聚类的 id,而不是每个块。这叫产品量化;
  • 将矩阵因式分解为两个较小矩阵的乘积(不推荐,因为精度低)。

库 compress-fasttext 支持全部四种压缩方式,建议结合前三种。这就是方法prune_ft_freq实际做的事情。

压缩的型号够好吗?

为了确认压缩后模型仍然保留有用的信息,我们可以使用工具 SentEval 对它们进行评估。该工具包括 17 个下游任务,如短文本分类、文本间语义相似性评估和自然语言推理,以及 10 个诊断任务。对于每项任务,要么直接使用嵌入,要么在顶部使用小型线性模型。我修改了 bow.py 示例以使用 fastText,并使用完整的 7GB 英文版本和其 25MB 压缩版本来执行它。下表显示了两种模型在所有任务中的表现:

作者图片:SentEval 上的模型评估

平均而言,小型号的性能分数是全型号性能的 0.9579,而小型号几乎是全型号的 300 倍。这证实了如果由于某种原因不希望模型太大,那么压缩 fastText 模型并不是一个坏主意。

结论

FastText 是计算有意义的单词嵌入的一种很好的方法,但是典型的 fastText 模型的大小限制了它在移动设备或适度的免费主机上的使用。在 compress-fastText 中收集的方法允许将模型大小减少数百倍,而不会显著影响下游性能。我发布了一个包和压缩模型,可以用来高效地解决各种 NLP 问题。

在未来,我计划发布更多的微型模型,例如一个用于英语和俄语的 45MB BERT 模型。订阅,敬请关注!

这篇文章是由大卫·戴尔(https://daviddale.ru/en)写的,他是 NLP 的研究科学家和聊天机器人的开发者。

如果你在科学论文中提到这篇文章(或文章包),请注明出处:

@misc{dale_compress_fasttext, 
   author = "Dale, David",
   title  = "Compressing unsupervised fastText models", 
   editor = "towardsdatascience.com", 
   url    = "[https://towardsdatascience.com/eb212e9919ca](/eb212e9919ca)", 
   month  = {December},
   year   = {2021},   
   note = {[Online; posted 12-December-2021]},
}

ImageNet 数据集中的压缩

原文:https://towardsdatascience.com/compression-in-the-imagenet-dataset-34c56d14d463?source=collection_archive---------20-----------------------

理解大数据

深度学习最受欢迎的基准测试的压缩设置

弗兰肯斯坦的数据集怪物?请继续阅读,寻找答案。图片作者。

我最近的一项任务是让更多的人思考有损压缩如何影响他们的深度学习模型[1]。在这个过程中,我花了很多时间使用 ImageNet [2],它完全由 JPEG 文件组成,我开始注意到一些特殊的压缩设置。为了了解这些奇怪设置的系统性,我决定调查整个数据集的压缩设置。在这篇文章中,我报告了我所看到的,包括为什么我认为其中一些设置很奇怪,并展示了我为每个相关的压缩设置计算的统计数据。最后,我展示了通过绘制这些压缩设置的 2D 投影,实际上可以图形化地看到在 ImageNet 的创建过程中涉及到几个不同的来源。

方法学

为了检查图像,我使用了来自 torchjpeg 的read_coefficients函数。这个函数直接从 JPEG 文件中读取 DCT 系数,不需要解码,允许我检查低层次的细节,比如色度二次采样和量化。这个过程揭示了训练集中的一个图像实际上根本不是 JPEG。这是一个 PNG,有人将其重命名为. JPEG 扩展名。处理训练集总共需要大约 4.5 小时,处理验证集大约需要 10 分钟。处理后,我绘制了结果。我已经在这个要点中提供了所有的数据收集和绘图代码,以及全尺寸的 PDF 绘图。

请注意,所有图表上的 Y 轴都使用对数刻度。

概观

总的来说,ImageNet 中的大多数图像都是“轻度”压缩的,非常小。最常见的图像大小似乎是 500 乘 500 左右,尽管有一些异常值非常大或比例异常。例如,2592 乘 3888(非常大)的图像,或者 500 乘 33 的图像(比例奇怪)。这一点很重要,因为大多数人在预处理过程中将图像的大小调整为 224 乘 224,怪异的纵横比或大得多/小得多的图像会因重采样而产生伪像。

绝大多数图像是彩色图像,不是色度二次采样,而是以质量 96 进行量化。这表示压缩非常轻微,不会对图像产生明显影响。当然这里也有例外,比如 4:1:1 二次采样(非常差)和一些质量< 10 的图像(也非常差)。对于所有这些参数,训练集和测试集之间似乎也存在一些差异。

如果你对我上面使用的术语不熟悉,不要担心,当我们深入研究结果的细节时,我会解释一切。

那巴布亚新几内亚呢?

在我们继续之前:是的,“n02105855/n02105855_2933。JPEG”实际上是一个 PNG,有人把它重命名为. JPEG。下面是:

“n02105855/n02105855_2933。JPEG”图像鸣谢:ImageNet [2]。

在十六进制编辑器中打开它会非常清楚地显示出来:

大 oof。图片作者。

除了指出它比其他类似大小的图像大一个数量级,没有什么可说的了。

颜色

让我们从简单的开始,多少图像是彩色的,多少是灰度的。

颜色结果。图片作者。

相当简单,几乎所有的图像都是彩色的。关于这一点需要注意的是,JPEG 区分了用完全相同的三个颜色通道存储的灰度图像和用一个通道存储的实际灰度图像,我们在这里计算的是后者:加载时只返回一个通道的图像。

图像尺寸

接下来,让我们看看图像尺寸,这部分有一些最有趣的结果。图像大小很难可视化,用图形绘制它们很难理解(我确实有这些图形以及要点中的绘制代码),所以我在热图上绘制了宽度和高度。因为它们很大,为了清晰起见,我把它们裁剪为 1000x1000(全尺寸热图是要点)。这是训练集:

训练集热图。图片作者。

该图中的每个像素代表一个大小,例如位置(10,70)处的像素显示宽度为 10、高度为 70 的图像的数量。更亮的颜色表示更多的图像。

我们可以看到一些有趣的行为。有一个明显的偏好宽度和高度为 500,以及其他一些间隔。从地图的左上角到右下角有一些有趣的对角线。这是同一张图片,但有些东西被贴上了标签:

培训热图已标注。图片作者。

为了使对角线的解释更容易,我覆盖了一组表示纵横比 1:1(红色)、4:3(绿色)和 3:2(蓝色)的线。

具有纵横比的训练热图。图片作者。

我们可以看到这些线对应着这些长宽比。1:1 和 4:3 有道理,但 3:2 我只从 35mm 胶片上知道,所以坦率地说,我很确定它是如何以如此大的数量出现在这里的。

让我们简单看一下验证集的相同热图:

验证集热图。图片作者。

它不仅明显更稀疏(事实上几乎所有的图像都在 500 宽或 500 高的区域),而且长宽比也更合理。这是值得关注的,因为验证集中的大小分布并不反映训练集。

是时候举一些病理学的例子了。下面是一个来自训练集的小图像示例,其大小仅为 20 x 17:

“n07760859/n07760859_5275。JPEG "图像来源:ImageNet [2]

我不知道这应该是什么,缩放没有帮助,我怀疑你的神经网络也能解决这个问题。

这里有一个疯狂的长宽比,它是 500 乘 32:

“n04228054/n04228054_11471。JPEG "图像来源:ImageNet [2]

我觉得是滑雪板?调整到 224x224 大小后,无论有没有中间裁剪,看起来肯定会很奇怪:

“n04228054/n04228054_11471。JPEG”后居中裁剪和调整大小(左)和只调整大小(右)。图片来源:ImageNet [2]

色度子采样

接下来,我们可以看看色度二次采样设置。我将首先解释什么是色度二次采样,如果你熟悉,可以跳过这一部分,然后我将进入结果。

什么是色度子采样? 人类视觉对颜色的微小变化不如对亮度的微小变化敏感。JPEG 压缩利用这一点,通过对颜色信息进行二次采样来节省额外的空间,换句话说,它存储的颜色信息比亮度信息少。该算法通过将给出的标准 RGB 图像转换到 YCbCr 色彩空间来实现这一点。这个颜色空间将像素的亮度或亮度与颜色或*色度分开。*Y 通道存储亮度,并以全分辨率保存。Cb 和 Cr 通道存储颜色信息(大致分别为蓝色和红色),通常会进行下采样。

当我们谈论如何进行下采样时,我们使用以下符号:“4:a:b”。该方案指的是 4 列 2 行的像素块。“a”表示第一行中颜色样本的数量,“b”表示第二行中变化的这些样本的数量。因此,如果我们有 4:2:2 二次采样,我们说对于每 4 个亮度样本,第一行只有 2 个色度样本,第二行两者都发生变化。我们将此解释为色度通道的宽度是亮度通道的一半,但高度相同。

这个符号起初很奇怪,但是当你习惯于看它的时候就有意义了,在下一节讨论结果的时候,我会完整地解释这个方案的解释。

结果

色度子采样结果。图片作者。

上面你可以看到色度二次采样的结果。这里有几件有趣的事情需要注意,首先是绝大多数图像使用“4:4:4”,这意味着没有子采样。大约 10%使用“4:2:0 ”,这意味着色度通道是宽度和高度的一半。这是实践中最常见的设置,因为它是许多 JPEG 实现中的默认设置,所以如果您正在部署一个将在真实图像上工作的系统,ImageNet 可能对您来说不够有代表性。

真正突出的一点是“4:1:1”图像的数量。这是一个奇怪的问题(实践中不常见),它表明色度通道的宽度只有亮度通道的 1/4(但高度相同)。这将导致图像出现非常明显的退化。还要注意的是,虽然它们仍然只占总图像的一小部分,但是在验证集中的这些图像比在训练集中的要多一个数量级。

这是一个来自训练集的 4:1:1 图像的示例

“n02445715/n02445715_2673。JPEG”。Image credit ImageNet [2]。

请注意,它看起来很糟糕,颜色很大程度上没有意义。

质量

对 JPEG 的大小和保真度影响最大的设置是其质量设置。这实际上是不标准的,但相当普遍,任何导出 JPEG 文件的人可能都熟悉这个滑块,它要求质量从 0 到 100。较低质量的图像看起来更差,但比高质量的图像小得多。和上一节一样,我将首先解释这个质量实际上是什么,然后我们来看看结果。

什么是 JPEG 质量? 当保存一个 JPEG 文件时,它实际上并不是存储像素,而是存储离散余弦变换(DCT)的系数。DCT 被应用于像素以产生变换系数,然后这些系数通过舍入被量化以节省空间。这种舍入是 JPEG 压缩中信息损失的主要来源,也是节省大部分空间的原因。本质上,质量用于控制舍入的数量,因此高质量意味着舍入越少,文件越大。JPEG 通过计算质量因子的矩阵来控制舍入,质量因子用于按元素划分系数。矩阵中较大的条目意味着除法运算后系数较小,因此需要更多的舍入。舍入允许将系数表示为整数,并创建连续的零和重复元素(较低熵表示)。

因为质量是非标准的,所以它不存储在 JPEG 文件中,并且估计质量并不总是简单的。我使用了torch JPEG . quantization . ijg库来计算每个图像从 0 到 100 的每个质量的量化矩阵,直到我找到一个与文件中存储的量化矩阵完全匹配的量化矩阵。这很耗时,而且只有在图像是用 libjpeg 压缩的情况下才有效,幸运的是它们都是。

结果

质量结果。图片作者。

以上是质量结果。我们可以看到质量为 96 的大峰值,表明绝大多数图像都是以这种质量压缩的。96 非常高,不会明显影响图像。这里要注意的有趣的事情是,在训练集中有一小部分非常低质量(通常小于 10)的图像,这些图像几乎会被压缩完全破坏。还要注意验证集的稀疏性,其中训练集覆盖了各种各样的质量(尽管比例很小),这些通常不在验证集中表示。

这是训练集中质量为 3 的图像的示例。

“n02441942/n02441942_6428。JPEG "图像信用 ImageNet [2]

请注意,它只是有些可识别性,颜色基本上消失了。

探索图像的空间

有一件事立即引起了我的注意,那就是 ImageNet 似乎是由几个非常不同的来源组合而成的,有点像科学怪人的数据集。很明显,有一个源经过精心的压缩设置,将默认设置更改为 96 质量和 4:4:4 子采样,并使用 500 乘 500 的图像。然后还有一些其他的,看起来缺乏那种有意的设计,但是它们以足够的数量出现,以至于它们看起来以某种方式相关联。这可能得到了来自不同来源的单一图像的补充,这可以解释一些异常值。了解数据集历史的人可能会证实这一点。

我们实际上可以形象化地描述这一点。为此,我将压缩设置存储为 4D 向量(色度子采样类型、宽度、高度、质量),并使用 UMAP [8]将它们投影到 2D 中。我在训练集上计算了一下,我只使用了 10%的宽度高度为 500 的图像,因为这些图像往往会控制信号。这是我给一些非常清晰的集群着色后的样子:

突出显示突出集群的图像空间。图片作者。

检查这些集群给我们一个想法,为什么他们分组在一起。橙色群集仅包含以质量 96 压缩的大小为 500 x375 的图像,并且使用 4:4:4 色度子采样。绿色群集包含 375 乘 500 个图像(橙色群集的转置),其他设置相同。红色群集也是一样的,但是有 333 乘 500 个图像。

接下来,让我们通过色度二次采样方案来给这些点着色

由色度子采样方案着色的图像空间。图片作者。

我们得到了一个很好的,清晰的,分离。黄色点为 4:2:0,紫色点为 4:4:4,其余介于两者之间。一个 4:2:2(蓝色)的群集出现在左侧,回头看上面的原始图,现在我们已经确定了它,这个群集更加突出。

按质量给点着色给出了另一个有趣的结果

按质量着色的图像空间。图片作者。

我们可以看到较低的质量在右下方得到了很好的体现。这是 4:2:0 色度二次采样非常突出的同一区域。

如果我不得不根据这些图来猜测,我会说左手边较小的聚类代表一些初始数据来源。它们有相似的参数,只是尺寸不同,而且数量很少。在它们的左侧是从其他来源收集的图像,但具有相似的参数。右手边代表数据收集方法的巨大变化,代表了非常不同的参数。对此要有所保留,因为像 UMAP 这样的投影技术并不能保证完美地模拟空间,这只是我的推测。

结论

尽管 ImageNet 仍然是最受欢迎的计算机视觉数据集,但它的标签[3,4],它的广泛使用[5]及其潜在的社会影响[6,7]已经逐渐为人所知。我想回应这些担忧,同时提出我自己的一个担忧:数据质量。在我最近的论文[1]中,我展示了压缩设置会对深层网络产生巨大的、有时是意想不到的影响。虽然大多数压缩都是轻量级的,但有足够多的离群值值得关注,并且在训练集和验证集之间存在差异。此外,图像大小变化很大,并且包含极端的纵横比,这可能会在调整图像大小以输入到网络时造成问题。基于这一分析,我强烈建议您在下次考虑使用 ImageNet 时考虑这些问题以及它们是否会影响您的性能。这并不是说 ImageNet 在客观上是一个糟糕的数据集,它多年来为社区提供了很好的服务,在某些情况下,它甚至可能有助于这种变化。但是,随着深度学习发展成为一门更精确的科学,对这些问题采取积极的方法并尽早确定它们对您的特定应用是否重要是很好的。

确认

这篇文章的灵感来自于我的研究[1],该研究得到了美国国防高级研究计划局医学研究中心、美国国防高级研究计划局塞马福尔和脸书·艾的独立资助。我还要感谢我的合著者,UMD 的 Abhinav Shrivastava 教授和 Larry Davis 教授以及脸书 AI 的 Ser-Nam Lim 博士所做的贡献。

参考

  1. 分析和减轻深度学习中的压缩缺陷。arXiv 预印本 arXiv:2011.08932 (2020)。
  2. 邓,贾,等,“Imagenet:一个大规模的层次图像数据库”2009 年 IEEE 计算机视觉和模式识别会议。Ieee,2009 年。
  3. 拜尔、卢卡斯等人,《我们对 ImageNet 的使用结束了吗?."arXiv 预印本 arXiv:2006.07159 (2020)。
  4. 云,桑都,等。“重新标记图像网络:从单标签到多标签,从全球到本地化标签。”arXiv 预印本 arXiv:2101.05022 (2021)。
  5. 塔格纳、卢卡斯、于尔根·施密德胡伯和蒂洛·施塔代尔曼。“在 imagenet 上优化 cnn 架构是否足够?."arXiv 预印本 arXiv:2103.09108 (2021)。
  6. Birhane、Abeba 和 Vinay Uday Prabhu。“大型图像数据集:计算机视觉得不偿失的胜利?."IEEE/CVF 计算机视觉应用冬季会议录。2021.
  7. 杨,,等,〈图像网络中的人脸混淆技术研究〉。arXiv 预印本 arXiv:2103.06191 (2021)。
  8. 麦金尼斯、利兰、约翰·希利和詹姆斯·梅尔维尔。"统一流形逼近和投影降维."arXiv 预印本 arXiv:1802.03426 (2018)。

使用 Python 的计算流体动力学:层流建模

原文:https://towardsdatascience.com/computational-fluid-dynamics-using-python-modeling-laminar-flow-272dad1ebec?source=collection_archive---------0-----------------------

结晶器的流体力学

使用有限差分法求解单相层流的 2D 纳维尔-斯托克斯方程,并使用基准 lid 空腔试验验证结果

照片由 Unsplash 上的 Amadej Tauses 拍摄

这是结晶器的流体力学系列文章的第一篇。该系列将涵盖化学反应器中的流体动力学、传热、传质和结晶的建模。为了简化教程,模型构建将分阶段进行,首先创建层流流体解算器(文章 1),添加热量和质量传递组件(文章 2),最后求解种群平衡模型以模拟结晶(文章 3)。

本代码是在两个信息丰富的参考文献的帮助下编写的 Lorena Barba 教授的“Navier Stokes 的 12 个步骤”和 Mark Owkes 教授的“编写第一个 CFD 解算器的指南”。如果您已经熟悉流体力学背后的理论和数学,并且想要浏览代码,您可以跳到本文的第 5 节。

1.介绍

流体流动可以在许多自然现象中观察到,从舒缓的瀑布到恼人的咖啡溅到你的电脑键盘上。你在看完你被毁坏的键盘上的咖啡后的第一个想法可能不是“多有趣啊!”但是从另一方面来说,从悬崖上流下的平静而又动态的水自然会唤起一种奇妙的感觉。我们能理解这些情况下的流体流动吗?我们能预测流体在特定条件下如何运动吗?更重要的是,我们能防止未来的咖啡飞溅吗?

回答这些问题的一种方法是在实验室中用实际的流体进行实验,并使用各种成像仪器研究它们的流动特性。这是实验方法。另一种方法包括编写一组可以描述流体流动的方程,应用一组简化的假设和条件,执行一些数学魔术,并推导出一个控制方程,在输入正确的值后,该方程可以为您提供预测流动动态的能力。这是分析方法。

然而,随着计算能力的增加,出现了第三种方法来回答这些问题——数值方法。虽然描述流体流动的方程组对于任意一组条件都是解析不可解的,但是如果你有一台足够强大的计算机,它们的输出肯定是可以计算的。使用这种方法在计算机上研究流体流动的动力学通常被称为计算流体动力学(CFD)。

2.控制方程

那么,这一组能完整描述一种流体如何流动,它们从何而来的方程组是什么呢?在回答前一个问题之前,我们先讨论后一个问题。

考虑一个空间体积固定的 2D 盒子。这就是我们所说的控制体积。

图 1:控制音量

首先,我们将把质量守恒的原理应用于控制容积中的流体。对于不可压缩的流体(大多数液体),这意味着无论什么流体进入盒子都必须离开它。这在流体力学中被称为连续性方程

其次,我们将把动量守恒的原理应用到控制体积上。与之前的情况相比,这稍微更抽象和复杂,但最终,这简化为不可压缩的纳维尔-斯托克斯方程。

如果我们能够在应用必要的边界条件后同时求解这些偏微分方程(PDEs ),我们将获得作为时间函数的瞬时速度和压力,从而允许我们预测流体将如何流动。然而,在不应用简化假设的情况下,没有解析方法来求解这些方程(以它们的完整形式)。因此,我们求助于数值技术来求解这些方程。

3.数值方法

有各种不同的数值方法来解决偏微分方程,每一个都有自己的一套警告。最简单的方法是有限差分法,其中使用低阶泰勒级数近似将 PDEs 转换为一组代数方程。下面给出一个例子,说明如何将一阶和二阶导数转换成它们的有限差分近似。

虽然这不是在所有情况下模拟流体流动的最佳方法,但我们将继续使用它,因为它简化了结晶器模拟的其他方面,这是本系列文章的最终目标。对于更严格的数值处理,你可能想使用有限体积或有限元方法。

4.代码的组织

代码被组织成三个不同的文件或脚本。第一个“FlowPy.py”包含使用有限差分法对一般输入集求解 PDEs 的代码。使用作为用户界面的“FlowPy_Input.py”脚本向该脚本提供输入。最后,“FlowPy_Visualizer.py”脚本用于在运行模拟后制作流的动力学动画。

5.模拟代码——flow py

用 Python 编写代码的一个优点是,我们可以利用面向对象编程(OOP)来组织和简化代码。这也将使增加传热和传质扩展变得非常简单。因此,代码被组织成各种类和对这些类的对象进行操作的函数。将第 5 节中的代码保存到名为 FlowPy.py 的文件中

步骤 1:导入所需的模块

需要以下模块— numpy 和 *os。*就是这样!

import numpy as np
import os

步骤 2:构建类

我们从边界条件开始,为问题的特定属性创建类。通过应用某些边界条件来求解偏微分方程,这些边界条件指示了流体在区域边界的行为。例如,流过管道的流体将具有零流体速度的壁,以及具有某一特定流速的入口和出口。

数学上,边界条件可以用两种形式表示——狄利克雷和诺依曼边界。前者指定因变量在边界处的值,而后者指定因变量在边界处的导数的值。

因此,我们创建了一个边界类,它有两个属性——类型和值。

class Boundary:
    def __init__(self,boundary_type,boundary_value):
        self.DefineBoundary(boundary_type,boundary_value)

    def DefineBoundary(self,boundary_type,boundary_value):
        self.type=boundary_type
        self.value=boundary_value

接下来,由边界包围的区域(如管道内部)使用 2D 网格或栅格表示,在栅格中的盒子中心(压力)或盒子表面(速度)计算因变量的值。这被称为交错网格方法。为了表示网格,我们创建了一个名为 *Space 的类。*方法 CreateMesh 为因变量创建一个给定大小的矩阵,方法 SetDeltas 根据指定的域长度和宽度计算差分长度的值。

class Space:
    def __init__(self):
        pass

    def CreateMesh(self,rowpts,colpts):
        #Domain gridpoints
        self.rowpts=rowpts
        self.colpts=colpts #Velocity matrices
        self.u=np.zeros((self.rowpts+2,self.colpts+2))
        self.v=np.zeros((self.rowpts+2,self.colpts+2))
        self.u_star=np.zeros((self.rowpts+2,self.colpts+2))
        self.v_star=np.zeros((self.rowpts+2,self.colpts+2))
        self.u_next=np.zeros((self.rowpts+2,self.colpts+2))
        self.v_next=np.zeros((self.rowpts+2,self.colpts+2))
        self.u_c=np.zeros((self.rowpts,self.colpts))
        self.v_c=np.zeros((self.rowpts,self.colpts))) #Pressure matrices
        self.p=np.zeros((self.rowpts+2,self.colpts+2))
        self.p_c=np.zeros((self.rowpts,self.colpts)) #Set default source term
        self.SetSourceTerm()        

    def SetDeltas(self,breadth,length):
        self.dx=length/(self.colpts-1)
        self.dy=breadth/(self.rowpts-1) def SetInitialU(self,U):
        self.u=U*self.u

    def SetInitialV(self,V):
        self.v=V*self.v

    def SetInitialP(self,P):
        self.p=P*self.p def SetSourceTerm(self,S_x=0,S_y=0):
        self.S_x=S_x
        self.S_y=S_y

最后,我们创建一个类流体来表示流体的属性——比如密度(ρ)和粘度(μ)。

class Fluid:
    def __init__(self,rho,mu):
        self.SetFluidProperties(rho,mu)

    def SetFluidProperties(self,rho,mu):
        self.rho=rho
        self.mu=mu

步骤 3:编写函数来实现有限差分法

如前一节所述,我们首先编写函数,在 2D 域的左、右、上、下边界实现水平速度( u )、垂直速度( v )和压力( p )的边界条件。该函数将接受空间边界类的对象,并根据这些对象的属性设置边界条件。例如,如果将类型为 Dirichlet 且值为 0 的边界对象作为左边界对象传递,该函数将在左边界设置该条件。

#Note: The arguments to the function are all objects of our defined classes
#Set boundary conditions for horizontal velocity
def SetUBoundary(space,left,right,top,bottom):
    if(left.type=="D"):
        space.u[:,0]=left.value
    elif(left.type=="N"):
        space.u[:,0]=-left.value*space.dx+space.u[:,1]

    if(right.type=="D"):
        space.u[:,-1]=right.value
    elif(right.type=="N"):
        space.u[:,-1]=right.value*space.dx+space.u[:,-2]

    if(top.type=="D"):
        space.u[-1,:]=2*top.value-space.u[-2,:]
    elif(top.type=="N"):
        space.u[-1,:]=-top.value*space.dy+space.u[-2,:]

    if(bottom.type=="D"):
        space.u[0,:]=2*bottom.value-space.u[1,:]
    elif(bottom.type=="N"):
        space.u[0,:]=bottom.value*space.dy+space.u[1,:] #Set boundary conditions for vertical velocity
def SetVBoundary(space,left,right,top,bottom):
    if(left.type=="D"):
        space.v[:,0]=2*left.value-space.v[:,1]
    elif(left.type=="N"):
        space.v[:,0]=-left.value*space.dx+space.v[:,1]

    if(right.type=="D"):
        space.v[:,-1]=2*right.value-space.v[:,-2]
    elif(right.type=="N"):
        space.v[:,-1]=right.value*space.dx+space.v[:,-2]

    if(top.type=="D"):
        space.v[-1,:]=top.value
    elif(top.type=="N"):
        space.v[-1,:]=-top.value*space.dy+space.v[-2,:]

    if(bottom.type=="D"):
        space.v[0,:]=bottom.value
    elif(bottom.type=="N"):
        space.v[0,:]=bottom.value*space.dy+space.v[1,:]#Set boundary conditions for pressure
def SetPBoundary(space,left,right,top,bottom):
    if(left.type=="D"):
        space.p[:,0]=left.value
    elif(left.type=="N"):
        space.p[:,0]=-left.value*space.dx+space.p[:,1]

    if(right.type=="D"):
        space.p[1,-1]=right.value
    elif(right.type=="N"):
        space.p[:,-1]=right.value*space.dx+space.p[:,-2]

    if(top.type=="D"):
        space.p[-1,:]=top.value
    elif(top.type=="N"):
        space.p[-1,:]=-top.value*space.dy+space.p[-2,:]

    if(bottom.type=="D"):
        space.p[0,:]=bottom.value
    elif(bottom.type=="N"):
        space.p[0,:]=bottom.value*space.dy+space.p[1,:]

在我们写有限差分函数之前,我们需要确定一个时间步长来推进模拟。为了确保有限差分法的收敛性,Courant-Friedrichs-Lewy(CFL)标准提供了时间步长的上限,该上限被设置为使用 SetTimeStep 函数进行模拟的时间步长。遵循 CFL 准则可确保在一个时间步长内传播的信息不会超过两个网格元素之间的距离。

def SetTimeStep(CFL,space,fluid):
    with np.errstate(divide='ignore'):
        dt=CFL/np.sum([np.amax(space.u)/space.dx,\
                           np.amax(space.v)/space.dy])
    #Escape condition if dt is infinity due to zero velocity initially
    if np.isinf(dt):
        dt=CFL*(space.dx+space.dy)
    space.dt=dt

确定时间步长后,我们现在准备实施有限差分方案。为了同时求解连续性方程纳维尔-斯托克斯方程,我们使用了预测-校正方案,包括以下步骤(更多信息请参考本指南):

  • 从无压力影响的初始速度计算星形速度( u和 v*)* 。

  • 使用星形速度迭代求解压力泊松方程。

  • 根据压力和星形速度计算下一个时间步长的速度。

我们定义了三个不同的函数来执行这三个步骤中的每一步。

此外,定义了一个便利函数,将边界内的速度和压力保存到新变量中,然后可以将这些变量写入文本文件。

def SetCentrePUV(space):
    space.p_c=space.p[1:-1,1:-1]
    space.u_c=space.u[1:-1,1:-1]
    space.v_c=space.v[1:-1,1:-1]

最后,我们定义了两个用于 I/O 目的的函数— MakeResultDirectory 创建一个名为“Result”的目录来存储文本文件,以及 WriteToFile 每隔几次迭代(使用 interval 参数指定)将变量的值保存到一个文本文件中。

def MakeResultDirectory(wipe=False):
    #Get path to the Result directory
    cwdir=os.getcwd()
    dir_path=os.path.join(cwdir,"Result") #If directory does not exist, make it
    if not os.path.isdir(dir_path):
        os.makedirs(dir_path,exist_ok=True)
    else:
        #If wipe is True, remove files present in the directory
        if wipe:
            os.chdir(dir_path)
            filelist=os.listdir()
            for file in filelist:
                os.remove(file)

    os.chdir(cwdir)

def WriteToFile(space,iteration,interval):
    if(iteration%interval==0):
        dir_path=os.path.join(os.getcwd(),"Result")
        filename="PUV{0}.txt".format(iteration)
        path=os.path.join(dir_path,filename)
        with open(path,"w") as f:
            for i in range(space.rowpts):
                for j in range(space.colpts):
                    f.write("{}\t{}\t{}\n".format(space.p_c[i,j],space.u_c[i,j],space.v_c[i,j]))

模拟代码部分到此结束。接下来,我们需要编写一个用户界面——即一个脚本,用户可以在其中提供各种输入,如边界条件、初始条件和流体属性。该脚本还将调用 FlowPy.py 文件中定义的函数,并运行模拟。

6.模拟用户界面— FlowPy_Input

这一节比前一节短——大部分繁重的工作已经完成,我们现在只需要利用所有已定义的类和函数来运行模拟!将第 6 节中的代码保存到名为 FlowPy_Input.py 的文件中

首先,我们导入所需的模块,这包括了我们在 FlowPy.py 中定义的所有东西

import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from FlowPy import *

例如,在本教程中输入了与盖腔试验(雷诺数=400)相关的输入。在这个试验中,流体被保存在一个有三面刚性墙的 2D 盒中,第四面墙(或盖子)以匀速移动。一旦达到稳定状态,就可以将发展流场的统计数据与基准进行比较。

图 2:盖腔问题设置

我们首先指定描述域的输入变量,然后用这些变量创建一个空间对象。

#### SPATIAL AND TEMPORAL INPUTS
length=4 #Length of computational domain in the x-direction
breadth=4 #Breadth of computational domain in the y-direction
colpts=257 #Number of grid points in the x-direction #KEEP ODD
rowpts=257 #Number of grid points in the y-direction #KEEP ODD#Create an object of the class Space called cavity
cavity=Space()
cavity.CreateMesh(rowpts,colpts)
cavity.SetDeltas(breadth,length)

接下来,指定流体的密度和粘度,并创建一个类流体的对象。

#### FLUID PROPERTIES
rho=1 #Density of fluid
mu=0.01 #Viscosity of fluid#Create an object of the class Fluid called water
water=Fluid(rho,mu)

第三,我们创建边界对象来设置速度和压力边界条件。

#### BOUNDARY SPECIFICATIONS
u_in=1 #Lid velocity
v_wall=0 #Velocity of fluid at the walls
p_out=0 #Gauge pressure at the boundaries#Create objects of the class Boundary having either Dirichlet ("D") or Neumann ("N") type boundaries
flow=Boundary("D",u_in)
noslip=Boundary("D",v_wall)
zeroflux=Boundary("N",0)
pressureatm=Boundary("D",p_out)

最后,指定模拟参数和标志来控制模拟时间、保存文本文件等等。

#### SIMULATION PARAMETERS
time=150 #Simulation time
CFL_number=0.8 #Reduce this if solution diverges
file_flag=1 #Keep 1 to print results to file
interval=100 #Record values in file per interval number of iterations

现在,我们可以编写循环来运行模拟。一般程序如下。在模拟时间完成之前,在每次迭代中执行以下操作:

  • 根据 CFL 数标准设置时间步长
  • 设置边界条件
  • 计算星形速度
  • 求解压力泊松方程得到压力场
  • 确定下一时间步的速度
  • 将结果写入文件(如果文件标志为 1)
  • 将时间提前一个等于时间步长的值
#### RUN SIMULATION# Print general simulation information
print("######## Beginning FlowPy Simulation ########")
print("#############################################")
print("# Simulation time: {0:.2f}".format(time))
print("# Mesh: {0} x {1}".format(colpts,rowpts))
print("# Re/u: {0:.2f}\tRe/v:{1:.2f}".format(rho*length/mu,rho*breadth/mu))
print("# Save outputs to text file: {0}".format(bool(file_flag)))## Initialization
# Make directory to store results
MakeResultDirectory(wipe=True)# Initialize counters
t=0
i=0## Run
while(t<time):
    #Print time left
    sys.stdout.write("\rSimulation time left: {0:.2f}".format(time-t))
    sys.stdout.flush() #Set the time-step
    SetTimeStep(CFL_number,cavity,water)
    timestep=cavity.dt

    #Set boundary conditions
    SetUBoundary(cavity,noslip,noslip,flow,noslip)
    SetVBoundary(cavity,noslip,noslip,noslip,noslip)
    SetPBoundary(cavity,zeroflux,zeroflux,pressureatm,zeroflux)    #Calculate starred velocities
    GetStarredVelocities(cavity,water)

    #Solve the pressure Poisson equation
    SolvePressurePoisson(cavity,water,zeroflux,zeroflux,\
pressureatm,zeroflux) #Solve the momentum equation
    SolveMomentumEquation(cavity,water) #Save variables and write to file
    SetCentrePUV(cavity)
    if(file_flag==1):
        WriteToFile(cavity,i,interval) #Advance time-step and counter
    t+=timestep
    i+=1

至此,我们已经准备好为任何广义输入集运行模拟。这个难题只剩下一个部分了——可视化工具。

7.可视化工具— FlowPy_Visualizer

运行模拟后生成的文本文件包含原始数字,这些数字本身可能无法提供流体流动的物理图像。然而,一个简单的动画等高线图可以用来结合三个变量——水平速度、垂直速度和压力——并以直观的方式显示它们的时间演变。将此代码保存在一个名为“FlowPy_Visualizer.py”的单独文件中。

和前面一样,首先导入所需的模块。特别是,我们将需要 matplotlib.animation 模块来录制动画。

import numpy as np
import sys
import os
import matplotlib.pyplot as plt
import matplotlib.animation as animation

为了确保创建适当大小的阵列,需要输入与计算域相关的模拟输入。

#### Simulation inputs
rowpts=257
colpts=257
length=4
breadth=4

在移至出图之前,必须将模拟过程中保存的文本文件作为数组导入。为此,我们首先遍历结果目录,存储所有文件名,并确定文件总数以及打印间隔。

#Go to the Result directory
cwdir=os.getcwd()
dir_path=os.path.join(cwdir,"Result")
os.chdir(dir_path)#Go through files in the directory and store filenames
filenames=[]
iterations=[]
for root,dirs,files in os.walk(dir_path):
    for datafile in files:
        if "PUV" in datafile:
            filenames.append(datafile)
            no_ext_file=datafile.replace(".txt","").strip()
            iter_no=int(no_ext_file.split("V")[-1])
            iterations.append(iter_no)#Discern the final iteration and interval
initial_iter=np.amin(iterations)            
final_iter=np.amax(iterations)
inter=(final_iter - initial_iter)/(len(iterations)-1)
number_of_frames=len(iterations)
sorted_iterations=np.sort(iterations)

接下来,我们定义一个函数,它可以使用 numpy 中的 loadtxt 函数将文本文件——基于提供的迭代——导入到一个数组中。

def read_datafile(iteration):
    #Set filename and path according to given iteration
    filename="PUV{0}.txt".format(iteration)
    filepath=os.path.join(dir_path,filename) #Load text file as numpy array
    arr=np.loadtxt(filepath,delimiter="\t")
    rows,cols=arr.shape #Define empty arrays for pressure and velocities
    p_p=np.zeros((rowpts,colpts))
    u_p=np.zeros((rowpts,colpts))
    v_p=np.zeros((rowpts,colpts)) #Organize imported array into variables
    p_arr=arr[:,0]
    u_arr=arr[:,1]
    v_arr=arr[:,2]

    #Reshape 1D data into 2D
    p_p=p_arr.reshape((rowpts,colpts))
    u_p=u_arr.reshape((rowpts,colpts))
    v_p=v_arr.reshape((rowpts,colpts))

    return p_p,u_p,v_p

是时候开始制作剧情了!在制作图形动画之前,制作一个初始图(用于第 0 次迭代)是一个好主意,这样图形的尺寸、轴、颜色条等都可以固定。此外,用更少的网格点(在本文中是 10 个)绘制流图是一个好主意,这样可以区分箭头。

#Create mesh for X and Y inputs to the figure
x=np.linspace(0,length,colpts)
y=np.linspace(0,breadth,rowpts)
[X,Y]=np.meshgrid(x,y)#Determine indexing for stream plot (10 points only)
index_cut_x=int(colpts/10)
index_cut_y=int(rowpts/10)#Create blank figure
fig=plt.figure(figsize=(16,8))
ax=plt.axes(xlim=(0,length),ylim=(0,breadth))#Create initial contour and stream plot as well as color bar
p_p,u_p,v_p=read_datafile(0)
ax.set_xlim([0,length])
ax.set_ylim([0,breadth])
ax.set_xlabel("$x$",fontsize=12)
ax.set_ylabel("$y$",fontsize=12)
ax.set_title("Frame No: 0")
cont=ax.contourf(X,Y,p_p)
stream=ax.streamplot(X[::index_cut_y,::index_cut_x],Y[::index_cut_y,::index_cut_x],u_p[::index_cut_y,::index_cut_x],v_p[::index_cut_y,::index_cut_x],color="k")
fig.colorbar(cont)
fig.tight_layout()

为了进一步制作这个情节的动画,matplotlib.animation 中的 FuncAnimation 函数将派上用场。它所需要的只是一个函数,可以为迭代提供的值创建一个图。我们定义这样一个函数叫做 animate

def animate(i): #Print frames left to be added to the animation
    sys.stdout.write("\rFrames remaining: {0:03d}".format(len(sorted_iterations)-i))
    sys.stdout.flush() #Get iterations in a sequential manner through sorted_iterations
    iteration=sorted_iterations[i] #Use the read_datafile function to get pressure and velocities
    p_p,u_p,v_p=read_datafile(iteration) #Clear previous plot and make contour and stream plots for current iteration
    ax.clear()
    ax.set_xlim([0,length])
    ax.set_ylim([0,breadth])
    ax.set_xlabel("$x$",fontsize=12)
    ax.set_ylabel("$y$",fontsize=12)
    ax.set_title("Frame No: {0}".format(i))
    cont=ax.contourf(X,Y,p_p)
    stream=ax.streamplot(X[::index_cut_y,::index_cut_x],\
                         Y[::index_cut_y,::index_cut_x],\
                         u_p[::index_cut_y,::index_cut_x],\
                         v_p[::index_cut_y,::index_cut_x],\
                         color="k")
    return cont,stream

最后,是时候保存动画并观看一些流体在您的计算机上跳舞了!

print("######## Making FlowPy Animation ########")
print("#########################################")
anim=animation.FuncAnimation(fig,animate,frames=number_of_frames,interval=50,blit=False)
movie_path=os.path.join(dir_path,"FluidFlowAnimation.mp4")
anim.save(r"{0}".format(movie_path))
print("\nAnimation saved as FluidFlowAnimation.mp4 in Result")

首先运行 FlowPy_Input.py 生成模拟数据,然后运行 FlowPy_Visualizer.py 保存模拟视频。

8.结果

下图显示了 Re=400 时盖子空腔基准的动画轮廓和流图。它显示了随着模拟的进行,在中心形成涡流,并最终过渡到稳定状态。

图 3:盖子空腔基准的动画轮廓和流图

还对稳定流的统计数据与 Ghia 等人(1982) 的结果进行了定量比较。具体来说,沿穿过空腔中心的垂直线的水平速度与本文的模拟结果进行了比较。结果显示了合理的一致性。偏差可归因于有限差分格式的较低精度和较小的网格尺寸。

,图 4:基准 1。蓝线代表模拟结果,红点代表 Ghia 等人(1982 年)的结果

图 5:基准 2。蓝线代表模拟结果,红点代表 Ghia 等人(1982 年)的结果

9.结束语

虽然本教程仅包括盖腔测试的模拟,但您可以尝试调整输入和边界条件,以模拟各种不同的单相流问题,如管道中的 Poiseuille 流。

随着 FlowPy 的创建和验证,我们可以进入结晶器建模的下一步——向求解器添加热量和质量传递,这将在下一篇文章中介绍。

FlowPy 代码可在 GitHub 上获得。如有任何问题、建议或任何关于我博客的讨论,请随时通过电子邮件或推特联系我。如果你想对盖腔测试结果做一个定量的基准,给我发一封邮件,我可以分享一个 Jupyter 笔记本的代码。

重要参考:

  • 巴尔巴,洛杉矶,&福塞斯,G. F. (2018)。CFD Python:纳维尔-斯托克斯方程的 12 个步骤。开源教育杂志2 (16),21。
  • Owkes,M. (2020),编写第一个 CFD 求解器的指南
  • 吉亚,英国 N. G .,吉亚,k . n .&申正堂(1982)。采用纳维尔-斯托克斯方程和多重网格法的不可压缩流的高精度解计算物理杂志48 (3),387–411。

PyTorch 和 TensorFlow 中的计算图

原文:https://towardsdatascience.com/computational-graphs-in-pytorch-and-tensorflow-c25cc40bdcd1?source=collection_archive---------8-----------------------

理解大数据

由奥玛·弗洛里斯在 Unsplash 上拍摄的照片

我在之前的文章中解释过深度学习环境中的反向传播算法。这是那篇文章的继续,我建议您阅读那篇文章,以确保您从这篇文章中获得最大的收益。

我将在 PyTorch 和 TensorFlow 中介绍计算图形。这就是允许这些框架为你的神经网络计算梯度的魔力。我将从一些计算图类型的介绍开始,然后是框架的具体细节。

计算图形类型[1]

所有深度学习框架都依赖于创建计算图来计算梯度下降优化所需的梯度值。通常,您必须构建正向传播图,框架会为您处理反向差异。

但是在开始 PyTorch 中的计算图之前,我想讨论一下静态和动态计算图。

静态计算图:

这些通常包括如下两个阶段。

  • 阶段 1:定义一个架构(可能有一些原始的流程控制,比如循环和条件)
  • 第二阶段:通过它运行大量数据来训练模型和/或进行预测

静态图的优势之一是它允许强大的离线优化/图表调度。这意味着这些通常比动态图更快(在每个用例中差别可能并不明显,这取决于我们的图)。缺点是处理结构化甚至可变大小的数据很难看。

动态计算图:

当执行正向计算时,该图被隐式定义(例如,使用运算符重载)。

动态图的优点是更加灵活。该库侵入性较小,允许交叉构建和评估图形。正向计算是用你最喜欢的编程语言编写的,包括所有的特性和算法。不利的一面是几乎没有时间进行图形优化,如果图形没有变化,那么努力可能会白费。动态图形易于调试。发现代码中的问题要容易得多,因为它允许一行一行地执行代码,并且你可以访问所有的变量。如果你想将深度学习用于行业中的任何真实目的,这绝对是一个非常重要的功能。

PyTorch 使用动态计算图。Tensorflow 允许创建优化的静态图,也具有类似于动态图的热切执行。它是一个命令式的编程环境,可以立即计算操作,而不需要构建图形,操作返回具体的值,而不是构建一个计算图形供以后运行。

现在让我们看看 PyTorch 中的计算图。

PyTorch [7]中的计算图

PyTorch 的核心提供了两个特性:

  1. n 维张量,类似于 NumPy,但可以在 GPU 上运行。
  2. 用于建立和训练神经网络的自动微分。

深度学习架构及其训练涉及大量矩阵运算。张量只不过是一个 n 维数组。对于来自 Python 背景的人来说,NumPy 应该敲响了警钟。这是一个非常强大和优化的矩阵运算库。然而,出于深度学习的目的,矩阵是巨大的,并且需要巨大的计算能力。

PyTorch 张量是一个 n 维数组。这个框架提供了很多在这些张量上操作的函数。但是为了加速张量的数值计算,PyTorch 允许使用 GPU,这可以提供 50 倍或更高的加速。PyTorch 张量也可以跟踪计算图形和梯度。

在 PyTorch 中,自动签名包提供了自动微分,以自动计算神经网络中的反向传递。你的网络的前向传递定义了计算图;图中的节点是张量,边是从输入张量产生输出张量的函数。通过该图的反向传播给出了梯度。

PyTorch 中的每个张量都有一个标志:required_grad,它允许从梯度计算中细粒度地排除子图,并可以提高效率。如果 x 是一个张量,它的 x.requires_grad=True,那么 x.grad 是另一个张量,它保持 x 相对于某个标量值的梯度。

从上面的例子可以看出,如果一个操作只有一个输入需要梯度,那么它的输出也需要梯度。反之,只有当所有输入都不需要梯度时,输出也不会需要梯度。

引擎盖下的亲笔签名

从概念上讲,autograd 在您执行操作时保留了创建数据的所有操作的图形记录,为您提供了一个有向无环图,其叶是输入张量,根是输出张量。通过从根到叶跟踪该图,可以使用链式法则(反向传播)自动计算梯度。

在内部,autograd 将这个图表示为函数对象的图,可以应用它来计算图的求值结果。当计算向前传递时,自动签名同时执行请求的计算并建立一个表示计算梯度的函数的图形。每个火炬的 grad_fn 属性。张量是该图的入口点)。当正向传递完成时,在反向传递中评估图形以计算梯度。

如前所述,PyTorch 中的计算图形是动态的,因此在每次迭代中都要从头开始重新创建,这正是允许使用任意 Python 控制流语句的原因,这些语句可以在每次迭代中改变图形的整体形状和大小。你不必在开始训练前对所有可能的路径进行编码——你所跑的就是你与众不同的。

每个本原自签名算子都是作用于张量的两个函数。forward 函数根据输入张量计算输出张量。后向函数接收输出张量相对于某一标量的梯度,并计算输入张量相对于同一标量的梯度。

总之,张量和函数是相互联系的,构成了一个非循环图,它编码了计算的完整历史。每个张量都有一个. grad_fn 属性,该属性引用了创建该张量的函数(用户创建的张量除外,因为它们的 grad_fn 是 None)。如果你想计算导数,你可以调用。张量上的 backward()。调用 backwards 函数后,梯度值作为张量存储在 grad 属性中。

这些概念可以用下图表示。

来源:作者[7]

例如,如果你创建两个张量 a 和 b,后面跟着 c = a/b,c 的 grad_fn 将被 DivBackward,这是/运算符的反向函数。如前所述,这些 grad_fn 的集合构成了反向图。前进和后退函数是 torch . autograd . function 的成员。您可以通过定义 torch . autograded . function 的子类来定义自己的 autograded 运算符

is_leaf:按照惯例,所有 requires_grad 为假的张量都是叶张量。对于 requires_grad 为 True 的张量,如果它们是由用户创建的,它们将是叶张量。这意味着它们不是运算的结果,因此 grad_fn 是 None。只有叶张量在调用 backward()时填充了它们的 grad。要为非叶张量填充 grad,可以使用 retain_grad()。

让我们构建帖子的第 1 部分中使用的计算图示例,并使用 PyTorch 计算梯度。

来源:作者

上面的代码在 PyTorch 中构造了计算图形。让我们看看图中节点的一些属性。

来源:作者

叶子没有 grad_fn 但是会有渐变。非叶节点有 grad_fn 但没有梯度。在调用 backward()之前,没有 grad 值。

我们在上一篇文章中从理论上计算的梯度是使用 PyTorch 计算的,如下所示。

来源:作者

backward()调用后节点的属性如下所示。

来源:作者

如您所见,一旦构建了图形,在 PyTorch 中计算梯度就是一件简单的事情。它会帮你区分。本教程的 jupyter 笔记本可以在 https://github.com/msminhas93/ComputationalGraphs[找到](https://github.com/msminhas93/ComputationalGraphs)

这就完成了 PyTorch 中计算图的讨论。在下一节中,让我们看看 TensorFlow 中的计算图。

张量流中的计算图

Tensorflow 使用数据流图根据各个操作之间的依赖关系来表示计算。这导致了一个低级编程模型,在该模型中,定义数据流图,然后创建一个 TensorFlow 会话来跨一组本地和远程设备运行该图的各个部分。

TensorFlow 中数据流或计算图的示例如下所示。

TensorFlow 中的计算图形示例(来源: Tensorflow 图形指南)

在 Tensorflow 中,任何种类的计算都被表示为 tf 的一个实例。图形对象。这些对象由一组 tf 实例组成。张量物体和 tf。操作对象。在张量流中,tf。张量对象作为边,而 tf。操作充当节点,然后添加到 tf 中。图形实例。

在张量流中,一个 tf。Session()对象存储执行计算的上下文。这是一个运行 TensorFlow 操作的类。会话对象封装了执行操作对象和评估张量对象的环境。

现在,让我们用这篇文章的第一部分中的例子在 Tensorflow 中构建计算图。

我们首先创建四个占位符。TensorFlow 占位符是在会话执行期间提供的张量的代理。它需要 Session.run()、Tensor.eval()或 Operation.run()的 feed_dict 参数。

接下来,我们使用张量流操作,即加法、对数和乘法,从定义的占位符构建示例计算图。

一旦构建了图形,下一步就是在会话中运行它。Python 有一个带语句的**,负责打开和关闭会话。在会话范围内,我们运行 tf.gradients 函数来获取我们的示例所需的梯度。输出如下所示。**

TensorFlow 有一个名为 tensorboard 的实用程序,它给你一个带有许多可视化功能的计算图形的图形表示。上一个示例的图表如下所示。

可以看出,该图与我们在示例图片中构建的图相同。Jupyter 笔记本可以在 https://github.com/msminhas93/ComputationalGraphs找到

接下来,让我们看看静态图和急切执行之间的时间比较。

来源:https://www.tensorflow.org/guide/intro_to_graphs

来源:https://www.tensorflow.org/guide/intro_to_graphs

我们可以清楚地看到这里的性能差异。在这个例子中,静态图比动态图快。

至此,我们结束了“反向传播揭秘”系列。

结论

关键要点如下。

  • 反向传播用于计算训练深度学习网络的基于梯度下降的优化所需的梯度。
  • 计算梯度的解析表达式很简单,但计算量很大。
  • 计算图是表示数学表达式的方法,在深度学习模型的情况下,这些就像描述性语言,给出所需计算的功能描述。
  • 深度学习框架,如 PyTorch 和 TensorFlow 等。依赖于这些计算图的创建来实现用于梯度计算的已定义网络的反向传播算法。

最后,这里比较一下 PyTorch 和 TensorFlow 中计算图的表示方式。

来源:作者

我希望你通过阅读这篇文章获得一些知识,并喜欢这篇文章。我很乐意在 LinkedIn上联系。

参考

[1]http://www . cs . Cornell . edu/courses/cs 5740/2017 sp/lectures/04-nn-compgraph . pdf

[2]https://py torch . org/tutorials/beginner/examples _ autogradated/TF _ two _ layer _ net . html

[3]https://www.tensorflow.org/api_docs/python/tf/Graph

https://www.tensorflow.org/guide/intro_to_graphs

https://kth.instructure.com/files/1864796/download?[5]download_frd=1

[6]https://JD Hao . github . io/2017/11/12/py torch-computation-graph/

[7]https://towards data science . com/getting-started-with-py torch-part-1-understanding-how-automatic-differential-works-5008282073 EC

https://pytorch.org/docs/stable/autograd.html

计算思维和人工智能

原文:https://towardsdatascience.com/computational-thinking-and-artificial-intelligence-c88655652417?source=collection_archive---------41-----------------------

人工智能起源简史

马库斯·温克勒在 Unsplash 上的照片

计算思维可以被认为是批判性思维或证据推理的延伸。在某种程度上,它将批判性思维和循证推理系统化。这通常涉及逻辑思维和论证,我们指的是经典的、正式的论证,而不是争吵。我们可以说,这种逻辑思维建立在处理问题的三种基本方法之上:特别思维、演绎思维或归纳思维。

因此,思考似乎是人类的核心,也是足够聪明来解决世界问题的核心。因此,人们开始怀疑我们是否能模拟思维和智力。在 17 世纪,莱布尼茨提出了一种新的语言,characteria universal is,这是一种代表人类思想的语言,其中每个字母代表一些概念,然后这些概念可以通过微积分推理器根据一套逻辑规则进行组合和操作,以计算所有的数学和科学知识。最近,艾伦·图灵开始思考机器,后来被称为图灵机的假设机器,可以解决任何可计算的函数,这似乎为最终的各种演算推理器奠定了一些基础。

生物联系

Robina Weermeijer 在 Unsplash 上拍摄的照片

就在这时,神经生理学家沃伦·s·麦卡洛克和逻辑学家沃尔特·h·皮茨出现了。麦卡洛克以每天喝威士忌和吃冰淇淋到凌晨 4 点而闻名,他对以莱布尼茨逻辑演算的方式为人类大脑建立理论基础感兴趣,并使用这个简单的逻辑基础来构建复杂的神经活动,就像罗素和怀特海的数学原理表明所有的数学都可以从一个简单的逻辑基础建立起来一样。

因此,当他读到图灵 1936 年的论文《论可计算的数字及其在 Entscheidungsproblem 中的应用》时,麦卡洛克认为大脑可以像图灵机一样工作。他进一步推断,神经元链可以通过逻辑规则连接在一起,从而产生思想,就像罗素和怀特海通过将简单的命题连接在一起而建立了所有的数学一样。麦卡洛克和皮茨在他们 1943 年的开创性论文《神经活动中固有思想的逻辑演算》中,利用图灵对计算的数学定义结合逻辑,建立了大脑的计算理论

当时,神经元被认为是大脑中人类思维和智力的组成部分,人们已经研究了一段时间。神经元本身被认为是相对简单的细胞,对多个输入进行一些处理,并产生单个输出尖峰,即动作电位。麦卡洛克和皮茨已经证明了这些尖峰信号可以组合起来进行逻辑和算术运算。

与此同时,几位生物学家在 20 世纪初一直在研究鱿鱼的巨大神经元,生物物理学家艾伦·霍奇金和安德鲁·赫胥黎很快创建了一个神经元的电路模型,作为一组非线性微分方程,以计算细胞膜的电导如何随时间和电压变化。像数学家诺伯特·维纳这样的人开始看到神经元、神经网络和控制系统等生物系统之间的联系。维纳当时在麻省理工学院,他曾保护过皮茨。不久,皮茨还会见了冯·诺依曼,他分别与香农和图灵就智能和机器进行了对话,这些机器也可以模拟编码在神经网络中的那种思维。

https://en.wikipedia.org/wiki/Alan_Turing

事实上,图灵在 1947 年给伦敦数学协会做了一次演讲,他很有先见之明地说:“我们想要的是一台能够从经验中学习的机器。”他接着说:

这就像一个学生从他的老师那里学到了很多,但通过自己的工作又增加了更多。当这种情况发生时,我觉得一个人不得不认为机器显示了智能。”

图灵甚至提出了一个测试,现在称为图灵测试,来衡量一台机器是否可以被认为和人类一样聪明。这项测试基于一种叫做模仿游戏的维多利亚时代的室内游戏,并假设当客观观察者无法区分人类和机器参与者时,机器应该被视为与人类一样聪明。

人工智能

附身摄影在 Unsplash 上拍照

智能机器的想法很快引起了相当多的兴趣。1955 年,计算机科学家约翰·麦卡锡为其创造了“人工智能”一词,并于 1956 年组织了著名的达特茅斯会议,克劳德·香农、马文·明斯基、艾伦·纽厄尔和司马贺等名人出席了会议,标志着人工智能(AI) 领域的诞生。

在计算意义上,人工智能经常在 Russell & Norvig 等教科书中被描述为理性代理或智能代理,这是任何虚拟或物理的实体,可以从其环境中获取感官输入并对其进行解释,将其放入现有知识的上下文中,然后采取行动以最大化其实现目标的机会。

真正的问题是,就像生命本身一样,没有一个好的概括的智力定义。尽管我们在神经生物学方面取得了相当多的进展,但我们仍然不知道人类在做我们认为智能的事情时会做什么。我们所知道的是,人类做一些我们还不能用计算系统自动化的事情。

这些年来,人工智能的受欢迎程度时高时低,随之而来的是智能的定义。最初模仿人类智能的目标很快被称为通用人工智能(也被称为人工通用智能、强人工智能或硬人工智能)。正如图灵本人最初建议的那样,在专业环境或利基应用中简单地拥有“学习机器”这一更温和、更可实现的目标随后被赋予了相应的术语狭义人工智能(也称为人工狭义智能、弱人工智能或软人工智能)。随着时间的推移,这种狭义的人工智能,也就是你简单地拥有一台“学习机器”,也被称为机器学习

在 Ch 阅读更多关于机器学习的内容。我的书的第 10 页,也可以在 ResearchGate 上公开查看。

[1]作为一个有趣的旁注,当冯·诺依曼在 1945 年发表他的历史性论文“关于 EDVAC 的报告初稿”时,它把第一台提出的现代计算机描述为一台存储程序二进制计算机器。在论文中,他模仿了麦卡洛克和皮茨的神经网络,但用真空管代替了神经元作为逻辑门。发表的论文只有一处引用:麦卡洛克和皮茨 1943 年的论文。

计算思维定义

原文:https://towardsdatascience.com/computational-thinking-defined-7806ffc70f5e?source=collection_archive---------8-----------------------

什么是计算思维和计算问题解决?

计算思维是一套解决复杂问题的技术,可分为三步:问题规格说明算法表达式解决方案实现&评估。上面列出了计算思维方法每一步涉及的原则,下面将详细讨论。版权所有里基·j·塞西

计算机科学是对计算过程和信息过程的研究。信息是通过将数据置于特定的上下文中以揭示其含义的处理结果。数据是原始的事实或对自然的观察计算是由某个计算代理执行的某个系统程序数据的操纵。

一般来说,计算问题需要某种方法或思维方式。这种方法通常被称为计算思维,在许多方面类似于我们关注预测的科学方法。

计算思维步骤:为了使用计算思维进行预测,我们需要定义与问题及其解决方案相关的三个步骤:

  1. 问题说明:我们从分析问题开始,精确地陈述问题,并建立解决方案的标准。解决方案的计算思维方法通常从将复杂的问题分解成更熟悉或更易处理的子问题开始,有时称为问题分解,经常使用演绎或概率推理。这也可以涉及到抽象模式识别的思路。更正式地说,我们将在创建模型和模拟中使用这些技术。
  2. 算法表达式:然后我们需要找到一个算法,一个精确的步骤序列,使用适当的数据表示来解决问题。这个过程使用归纳思维,需要将一个特定的问题转化为一大类类似的问题。这一步有时也被称为算法思维。我们可以进一步将其分为命令式,如过程式或模块化,以及声明式,如功能式,算法解决方案的方法。
  3. 解决方案实施和评估:最后,我们创建实际的解决方案,并对其进行系统评估,以确定其正确性效率。这一步还包括查看解决方案是否可以通过自动化或扩展到其他类型的问题而被推广

我应该在这里补充一点警告:这些计算思维的规则都很好,但它们本身并不是真正的规则;相反,把它们想成是善意的启发,或者经验法则。

这些计算思维的启发法与小学教授的 5 步科学方法的启发法非常相似,后者通常被写成:

  1. 观察宇宙的某些方面
  2. 用那些观察来告知一些关于它的假设
  3. 使用这个假设做一些预测
  4. 通过实验测试预测,并相应修改假设
  5. 重复步骤 3 和 4,直到假设不再需要修改

这些是很好的指导方针,但不是强制性的。它们是你可能需要或要求大部分努力的想法的建议,但它不是将你的想法或解决方法归类的过程。

在其核心,所有基础物理科学的中心方面是预测,通常通过实验。如果你能够做出重复的、精确的、定量的预测,这意味着无论你使用过什么样的模型或思维模式,它都是有效的,应该被重新使用。如果是形式方法,很好;如果它不那么正式,但仍然是结构化的和可重复的,并导致正确的计算解决方案,这也很好。

任何让你达到这种状态的结构化思维过程或方法都会被认为是计算思维。你甚至可以把它看作是批判性思维基于证据的推理的另一种定义,在这种情况下,你的解决方案来自于数据以及你对数据的看法:

数据+如何思考数据=计算思维

从这个意义上说,能够表示数据,然后操纵它,这本身就是一个可计算问题的计算解决方案!

然后,我们可以将程序视为计算解决方案,即可计算功能的解决方案,我们用某种特定的编程语言来表达。我们还知道一个算法是一个有效过程,一系列使用特定数据结构解决特定类型问题的逐步指令,这些数据结构指定了特定的数据表示

计算思维定义

照片由 Matteo Di Iorio 在 Unsplash 上拍摄

但是在我们用特定的编程语言实现我们的解决方案之前,我们必须为我们正在检查的问题定义一个算法解决方案。让我们看看如何实际找到这样一个计算解决方案,但要注意的是,由于不同的问题需要不同的详细方法,因此每个步骤都需要定制。

计算思维步骤

如上所述,计算思维是一个由三个阶段组成的迭代过程:

  1. 问题说明:使用抽象分解模式识别分析问题并精确陈述,同时建立解决方案的标准
  2. 算法表达式:使用适当的数据表示和算法设计找到计算解决方案
  3. 解决方案实施&评估:在推广到其他问题之前,实施解决方案并进行系统测试

计算思维方法的细节

让我们列出五个计算思维原则和伴随的计算机科学思想和软件工程技术的细节,它们可以为这三个步骤中的每一个发挥作用。请注意,这不是一个全面的列表,但具有代表性。

在这种方法中,我们也可以把原则看作是策略,寻找计算解决方案所需的高级概念;这些想法可以被视为特殊的策略,也就是众所周知在许多不同环境下都有效的模式或方法;最后,像工具这样的技术可以在特定的情况下使用。所有这些都是提出问题的最终计算解决方案所需要的。

  1. 问题说明
  • 计算思维原理:模型开发与抽象分解模式识别
  • 计算机科学思想:问题分析和说明
  • 软件工程技术:问题需求文档、问题规范文档、UML 图等。

2.算法表达式

  • 计算思维原理:使用数据表示和算法设计的计算问题解决
  • 计算机科学理念:通过一些符号系统的数据表示和算法开发,使用模块化、流程控制(包括顺序、选择和迭代)、递归、封装和并行计算来系统地处理信息
  • 软件工程技术:流程图、伪代码、数据流图、状态图、类图的类-责任-协作(CRC)卡、序列图的用例等。

3.方案实施&评估

  • 计算思维原则:系统测试和概括
  • 计算机科学理念:分析效率和性能约束的算法实现、调试、错误检测测试、测量解决方案正确性的评估指标,以及将计算解决方案扩展到其他类型的问题
  • 软件工程技术:用编程语言实现、代码审查、重构、使用 JUnit 等工具进行单元和系统测试的测试套件、质量保证(QA)等。

计算思维原则

凯利·西克玛在 Unsplash 拍摄的照片

计算解决方案的第一步,问题规范,依赖于一些基本的计算思维原则。尽管计算思维不是一种正式的推理方法,但它确实包含了一些在所有领域和学科中都有用的基本原则。

它们构成了一种逻辑地、有条理地解决任何领域的任何问题的推理或思考方式!这些基本 原则也是你可以放在简历上的流行语,所以让我们先来深入了解一下更重要的原则,尤其是分解模式识别抽象,以及它的表亲概括

分解简单来说就是将一个复杂的问题分解成更容易处理的部分。如果问题是一些复杂的任务,你可以把它分解成一系列简单的子任务。如果问题涉及一个复杂的系统,你可以把系统分解成一堆更小的子组件。例如,如果你面临着写一篇大而复杂的论文,你可能会选择通过将论文分解成更小的子部分并分别处理每一部分来解决它。

模式识别是在一个问题或一些数据集中发现相似性、趋势或某种规律性的想法。我们可能识别的这些模式帮助我们做出预测或者直接找到解决方案。例如,如果你在高速公路上开车,你注意到左边车道上的车挤在一起,你可能会决定换到右边车道。或者,如果你看到一只股票几个月来持续上涨,你可能会决定买入这只股票。免责声明:相关性不等于因果关系;即使你发现了一个模式,在你真正把钱投入到你的模式之前,你可能想用其他分析来确认或验证这个预测。

如前所述,抽象是忽略你认为不重要的细节的想法。这样,我们就可以优先考虑关于被检查系统的信息。我们可以使用这种抽象的想法来做一些事情,比如制作模型,比如之前提到的代表校园的地图。抽象的另一个例子可能是创建一本书或一部电影的摘要。我们也可以概括形成一个“大图”,忽略一些无关紧要的细节。

像这样的概括允许我们识别看似完全不同的模型的共同特征,从而允许我们将一个解决方案从一个领域调整到一个可能不相关的领域。概括可以帮助我们组织想法或成分,就像我们将一些动物归类为脊椎动物,将另一些归类为无脊椎动物一样。此外,能够识别我们已经识别的模式下的一般原则允许我们将模式和趋势归纳为规则。反过来,这些规则可以直接通知最终的算法,我们将在构建计算解决方案的第二步中使用。

算法表达式:计算问题解决

迈克尔·泽兹奇在 Unsplash 上拍摄的照片

计算求解的第二个步骤算法表达式,是计算问题求解的核心。数据到信息再到知识的转换可以通过计算问题解决来完成。精确定义问题后,它包括以下三个步骤:

  • 数据:结构原始 事实 用于循证推理
  • 表示:创建一个问题 抽象 来捕捉系统的相关方面
  • 算法:描绘一个在有限时间内解决问题的系统化的 程序

因此,计算问题的解决包括找到数据的适当的表示或上下文,并在算法中使用该表示,一旦问题被清楚地定义,逐步的过程就解决了问题。

数据的上下文化可以被认为是信息的第一近似值,解决方案将数据转换为信息,然后转换为可操作的知识。这个可以在这里进一步看到。

思考信息的一种方式是在某种上下文中的数据。如果上下文是发生的概率,我们就可以用香农的信息测度来结束。如果我们把数据放在一些基于逻辑的推理结构中,我们可以根据证据得出一些结论;这个结论成为我们有用的信息,可以形成可操作知识的基础。我们还可以在一些基于知识的系统中整理这些信息,这些系统是使用知识管理技术管理的。

在我的新书中阅读更多关于香农的信息理论和计算思维,这本书也可以在 ResearchGate 上公开查阅。

深度学习的计算成本和环境影响

原文:https://towardsdatascience.com/compute-and-environmental-costs-of-deep-learning-83255fcabe3c?source=collection_archive---------13-----------------------

一个衡量成本(美元)和二氧化碳排放量(磅)的框架

Holyoke 大坝为马萨诸塞州绿色高性能计算中心提供水力发电。美国公共电力协会在 Unsplash 上拍摄的照片

用于训练最先进的深度学习模型的计算继续呈指数增长,远远超过了摩尔定律的速度。但是它的成本是多少,对环境有什么影响?我将在这篇文章中描述一种近似的方法,这篇文章是文献[1]和[2]的总结。

目标

  • 估算培训众所周知的 NLP 模型的云计算成本和碳排放。
  • 估计新的最先进的 DL 模型所需的云计算成本和碳排放。
  • 将碳排放与普通基准进行比较,如人类平均寿命 1 年或汽车寿命。

非目标

  • 我们不包括向用户提供 DL 型号的服务成本。除了交通之外,它们还取决于所服务的地理区域。此外,我们不包括网络和数据存储成本,以及研究人员的工资。
  • 功率和计算效率取决于 GPU 的类型。更高效的硬件开发(如 Google Cloud 上提供的 TPU)是一个活跃的研究领域。

能源使用估算

总功耗可以估计为 CPU、内存和 GPU 功耗之和。[1]的作者通过使用他们的开源代码训练每个模型,使用 nvidia-smi 和英特尔电源管理接口等常用工具对 CPU、内存和 GPU 功耗进行采样和平均来测量。g 是使用的 GPU 数量。

训练模型所需的时间取自原始论文。

1.58 是电力使用效率系数(1.58 是 2018 年全球数据中心报告的平均值)。这个乘数因子包括运行模型所需的所有其他能量,主要是冷却。这是可以优化的,例如,谷歌报告其数据中心的 PUE 1.1。

我们将瓦特小时除以 1000 得到千瓦时。

等式计算训练期间的功耗。图片来自[2]

二氧化碳估算

美国环境保护署(EPA)报告称,美国电力消耗产生的平均二氧化碳(单位:磅/千瓦时)(EPA 2018)为:0.954。由于主要的云提供商在可再生能源领域拥有更高的份额,我们将把这个数字减半。在谷歌的案例中,它将接近 0,因为它是一个大量使用可再生能源的用户,并且通过购买绿色能源来抵消碳排放。

各国的可再生能源消耗与云提供商

估价

先发制人和按需成本的 GPU 和 TPU 使用她从谷歌小时。TPU 每小时的成本更高,但对于适合该硬件的工作负载来说,其成本和能效更高。

结果

[1]的作者选择了众所周知的深度学习模型:Transformer、ELMo、BERT 和 GPT-2,以及使用神经架构搜索思想训练多个模型以找到最佳配置的 Evolved Transformer。NAS 可以估算整个研发周期的计算成本,以找到一种新的先进模式。

本研究中使用的 5 种模型。提供的是高级架构、使用的硬件、模型方面和培训时间。图片来自[2]

二氧化碳排放和一些众所周知的深度学习模型的训练的货币成本。TPU 的成本效率要高得多(就 NAS 而言,从 4.4 万美元到 14.6 万美元,而不是几百万美元),而且可能更节能。

模拟训练二氧化碳消耗量与通用基准。图片来自[2]

离别的思绪

现代 ML 训练(和推论,不在本文讨论范围内)导致大量的碳排放和金钱成本。ARK Invest 等金融分析师预测,深度学习的市值将从 2020 年的 2 万亿美元增长到 2037 年的 30 万亿美元[3]。

在这篇文章中,我想提供一些量化排放和成本的框架。当特雷弗·诺亚问格里塔·图恩伯格人们可以做些什么来应对气候变化时,她建议最重要的事情是通知自己,了解情况,并最终推动一场政治运动。

就个人而言,我致力于将模型做得更小以适应移动设备(这对于减少延迟有额外的好处!)、训练多任务模型、多语言模型、报告记忆模型大小和失败(这可以很容易地在 Tensorflow [7]中进行分析)以及密切关注在训练的早期阶段没有显示出有希望的结果的工作。

参考

[1]斯特鲁贝尔,e .,甘内什,a .,&麦卡勒姆,A. (2020)。现代深度学习研究的能源和政策考虑。AAAI 人工智能会议论文集, 34 (09),13693–13696。【https://doi.org/10.1609/aaai.v34i09.7123

[2]斯特鲁贝尔,e .,加内什,a .,&麦卡勒姆,A. (2019)。自然语言处理中深度学习的能源和政策考虑。https://arxiv.org/abs/1906.02243

[3]https://research . ARK-Invest . com/hub fs/1 _ Download _ Files _ ARK-Invest/White _ Papers/ARK % E2 % 80% 93 Invest _ big ideas _ 2021 . pdf

[4]https://youtu.be/rhQVustYV24?t=303

[5]http://www . cis . upenn . edu/~ BC pierce/papers/carbon-offsets . pdf

[6]https://cloud . Google . com/blog/topics/sustainability/sharing-carbon-free-energy-percentage-for-Google-cloud-regions

[7]https://www . tensor flow . org/API _ docs/python/TF/compat/v1/profiler/profile option builder

计算机视觉:图像形成和表示

原文:https://towardsdatascience.com/computer-vision-image-formation-and-representation-a63e348e16b4?source=collection_archive---------9-----------------------

计算机视觉入门

诺德伍德主题公司在 Unsplash 上拍摄的照片

1.介绍

作为人类,我们能够如此轻松地感知我们周围的三维世界。想象一下看着一个花瓶。我们可以毫不费力地感知每一片花瓣的形状和半透明性,并可以将花朵从背景中分离出来。

计算机视觉旨在赋予计算机像我们一样理解环境的能力。它专注于通过多幅图像或视频观察世界,并重建物体的形状、强度、颜色分布等属性。

深度学习领域的最新进展使计算机视觉方法能够理解和自动化人类视觉系统可以完成的任务。本文讨论了计算机视觉的介绍性主题,即图像的形成和表示。图像形成将简要介绍图像是如何形成的以及它所依赖的因素。它还将涵盖数码相机中的图像传感管道。文章的后半部分将介绍图像表示,它将解释表示图像的各种方法,并将重点放在可以对图像进行的某些操作上。

2.图像形成

在建模任何图像形成过程中,几何图元和变换对于将三维几何特征投影到二维特征是至关重要的。然而,除了几何特征之外,图像形成还取决于离散的颜色和强度值。它需要知道环境的照明、相机光学、传感器属性等。因此,在讨论计算机视觉中的成像时,本文将集中讨论光度成像。

2.1 光度成像

图 1 给出了图像形成的简单解释。来自光源的光在特定的表面上反射。该反射光的一部分穿过图像平面,经由光学器件到达传感器平面。

图:1。光度成像(Image cr 编辑:Szeliski,计算机视觉:算法与应用 2010)

影响图像形成的一些因素是:

  • 光源发出的光的强度和方向。
  • 材料和曲面几何以及附近的其他曲面。
  • 传感器捕获属性

2.1.1 反射和散射

没有光,图像就不能存在。光源可以是点光源或面光源。当光线照射到表面时,可能会发生三种主要反应-

  1. 一些光被吸收了。这取决于称为ρ(反照率)的因素。表面的低ρ意味着更多的光将被吸收。
  2. 一些光被漫反射,这与观察方向无关。遵循朗伯余弦定律反射光的量与 cos(θ)成正比。例如布、砖。
  3. 一些光被镜面反射,这取决于观察方向。例如镜子。

图 2:反射模型(图片来源:伊利诺伊大学德里克·霍伊姆)

除了上述反射模型,最常见的光散射模型是**双向反射分布函数(BRDF)。**它给出了光被介质从一个方向散射到另一个方向的量度。光的散射可以决定表面的形貌——光滑表面几乎完全在镜面反射方向反射,而随着粗糙度的增加,光往往会衍射到所有可能的方向。最终,如果一个物体的表面是完全漫射的(即朗伯),那么它在整个出射半球看起来都是一样亮的。因此,BRDF 可以提供关于目标样品性质的有价值的信息。

有多种其他着色模型和光线跟踪方法,它们可以通过评估场景的外观来正确理解环境。

2.1.2 颜色

从颜色的角度来看,我们知道可见光只是大电磁光谱的一小部分。

当彩色光到达传感器时,会注意到两个因素:

  • 光的颜色
  • 表面颜色

Bayer Grid/Filter 是捕捉光线颜色的重要进展。在相机中,不是每个传感器都能捕捉到光的所有三种成分(RGB)。受人类视觉感受器的启发,Bayers 提出了一个网格,其中有 50%的绿色,25 %的红色和 25%的蓝色传感器。

然后使用去马赛克算法获得全色图像,其中周围像素用于估计特定像素的值。

除了 Bayer 滤色器之外,还有许多这样的滤色器被开发来感测颜色。

图 3: (a)图像传感器上的滤波器的拜耳排列。(b)传感器的横截面。(图片来源:https://en.wikipedia.org/wiki/Bayer_filter)

2.2 图像传感管道(数码相机)

光线来自多个光源,在多个表面上反射,最终进入相机,在相机中光子被转换为我们在观看数字图像时看到的(R,G,B)值。

相机中的图像感测流水线遵循图 4 中给出的流程图。

在相机中,光线首先落在镜头上(光学)。接下来是可以指定或调整的光圈和快门。然后光线落在传感器上,传感器可以是 CCD 或 CMOS(下面讨论),然后图像以模拟或数字形式获得,我们得到原始图像。

通常摄像机不会停在这里。他们使用上述主题中提到的去马赛克算法。如果需要或者应用任何其他重要的处理算法,图像被锐化。之后,白平衡和其他数字信号处理任务完成,图像最终被压缩成合适的格式并存储。

图 4:相机中的图像传感管道(图片来源: Szeliski,计算机视觉:算法与应用 2010)

2.2.1 CCD 与 CMOS

相机传感器可以是 CCD 或 CMOS。电荷耦合器件(CCD)中。在每个感测元件处产生电荷,并且该光生电荷从一个像素移动到另一个像素,并且在输出节点处被转换成电压。然后,模数转换器(ADC)将每个像素的值转换成数字值。

互补金属氧化物半导体(CMOS)传感器通过在每个元件内将电荷转换成电压来工作,而不是像 CCD 那样积累电荷。CMOS 信号是数字信号,因此不需要 ADC。CMOS 在当今时代广泛应用于相机中。

图 5: CCD 与 CMOS(图片来源:D. Litwiller,CMOS 与 CCD:成熟的技术,成熟的市场)

2.2.2 数字图像传感器的特性

让我们来看看当你点击相机上的图片时可能会看到的一些属性。

**快门速度:**控制到达传感器的光量

采样间距:定义成像芯片上相邻传感器单元之间的物理间距。

填充因子:有效感应面积大小与理论可用感应面积的比值(水平和垂直采样间距的乘积)

芯片尺寸:芯片的整体尺寸

传感器噪音:传感过程中各种来源的噪音

分辨率:告诉你每个像素指定多少位。

后处理:压缩和存储前使用的数字图像增强方法。

3.0 图像表示

得到一幅图像后,设计出表现图像的方法是很重要的。有各种各样的方式来表现一幅图像。让我们看看最常见的表示图像的方式。

3.1 作为矩阵的图像

表示图像的最简单的方式是矩阵的形式。

图 6:将图像的一部分表示为矩阵(图像鸣谢:IIT、马德拉斯、 NPTEL 计算机视觉深度学习)

在图 6 中,我们可以看到图像的一部分,即时钟,被表示为矩阵。一个相似的矩阵也将表示图像的其余部分。

常见的是,人们用多达一个字节来表示图像的每个像素。这意味着 0 到 255 之间的值表示图像中每个像素的强度,其中 0 表示黑色,255 表示白色。对于图像中的每个颜色通道,生成一个这样的矩阵。在实践中,将 0 和 1 之间的值标准化也很常见(如上图示例所示)。

3.2 图像作为一种功能

图像也可以表示为函数。图像(灰度)可以被认为是一个函数,它接受一个像素坐标并给出该像素的亮度。

可以写成函数f:输出任意输入点(x,y)的强度。强度值可以在 0 到 255 之间,如果值是标准化的,也可以在 0 到 1 之间。

图 7:用函数表示的图像(图像来源:诺亚·斯内夫利,康奈尔大学)

3.2.1 图像变换

当图像被视为功能时,它们可以被转换。函数的变化会导致图像像素值的变化。下面是一些相同的例子。

图 8 图像转换——使图像变亮(来源:诺亚·斯内夫利,康奈尔大学)

在图 8 中,我们希望使图像更亮。因此,对于图像中的每个像素,我们增加相应的强度值。这里我们假设值在 0 到 255 之间。

图 9:图像转换——翻转图像(来源:诺亚·斯内夫利,康奈尔大学)

类似地,图 9 示出了围绕垂直轴翻转图像的函数的变化。

在上面的例子中,变换发生在像素级。我们还可以用其他方法来进行图像转换。

3.2.2 图像处理操作

本质上,有三种主要操作可以在图像上执行。

  • 点操作
  • 本地操作
  • 全球运营

下面是对这些操作的解释。

3.2.2.1 点穴操作

上面显示的图像变换示例是点操作。在这种情况下,输出值仅取决于特定坐标处的输入值。

图 10:点操作。“b”中的输出坐标仅取决于“a”中相应的输入坐标(图片来源:作者)

编辑图像时经常使用的一个非常著名的点操作示例是反转对比度。最简单地说,它将暗像素转换为亮像素,反之亦然。

图 11:反转对比度(图片来源:IIT、马德拉斯、 NPTEL 计算机视觉深度学习)

图 11 显示了反转对比度的应用。帮助我们实现这一目标的点操作如下所述。

图 12:反转对比度的点操作(图片来源:作者)

这里, I(x,y) 代表图像 I 在坐标(x,y)处的亮度值。 IₘₐₓIₘᵢₙ 是指图像 I 的最大和最小亮度值。例如,假设图像 I 的强度在 0 和 255 之间。因此, IₘₐₓIₘᵢₙ 分别变为 255 和 0。您希望翻转某个坐标处的亮度值,比如说(x,y ),其中当前亮度值为 5。通过使用上面的操作,您得到的输出为:(255) — 5 + 0 = 250,这将是坐标(x,y)处亮度的新值。

假设您使用相机点击了一个静态场景。但是由于许多原因,如镜头上的灰尘颗粒、传感器的损坏等等,图像中可能会有噪声。降噪使用点运算可能非常繁琐。一种方法是拍摄多个静态场景,对每个像素的值进行平均,并希望噪声被去除。但是有时,不可能获得一个场景的多个图像,并且不能每次都保证场景的静止。要做到这一点,我们需要从点操作转向局部操作。

【3.2.2.2 本地操作

在本地操作中,如图 13 所示,输出值取决于输入值及其邻居。

图 13:本地操作(图片鸣谢:作者)

理解局部操作的一个简单例子是移动平均线。假设如图 14 所示的图像 I。通过查看图像可以清楚地看到,这是一个放置在黑暗背景中的白色盒子。然而,我们看到图片中的噪声,因为几个像素似乎放错了位置(在图中圈出)。

图 14:图像的相应像素的强度值(使用的来源:Steve Seitz,华盛顿大学)

如何从图像中去除这种噪声?假设图像中有一个 3 X 3 的窗口(可以选择任何大小的窗口)。在图像上移动窗口,取窗口内所有像素的平均值。下面可以看到这方面的演示。操作的最终输出可以在图 15 中看到。

2D 移动平均线(来源:Steve Seitz,华盛顿大学)

图 15:移动平均线的最终输出(图片来源:史蒂夫·塞茨,华盛顿大学)

上述操作是局部操作,因为输出取决于输入像素及其邻居。由于该操作,图像中的噪声像素在输出中被平滑掉。

3.2.2.3 全球运营

顾名思义,在全局操作中,输出像素的值取决于整个输入图像。全局运算的一个例子是傅立叶变换,如图 17 所示

图 16:全球运营(图片鸣谢:作者)

图 17:傅立叶变换的例子(图片来源:Mathworks MATLAB 工具箱)

感谢您的阅读。本文介绍了图像形成及其表示的基础知识。接下来的文章将深入讨论计算机视觉的更多主题。

资源

计算机视觉的深度学习,梵持·N·巴拉苏布拉曼尼安,IIT·海德拉巴

计算机视觉:算法与应用理查德·塞利斯基

CS 4495 计算机视觉,亚伦·博比克,佐治亚理工学院计算系

描述第一表面散射的双向反射分布函数——c . e . Mungan,1998 年夏季

采样和重建,CSC320:视觉计算简介
迈克尔·盖尔卓伊

如果你想阅读更多关于计算机视觉的故事,请随时关注并保持更新。

我也写机器学习/人工智能相关的核心话题!

计算机视觉:让我们给蘑菇分类

原文:https://towardsdatascience.com/computer-vision-lets-classify-mushrooms-6b3abe1561eb?source=collection_archive---------18-----------------------

实践教程

张量流进行图像分类

你有没有问过自己,在大自然中行走时,你会遇到哪种真菌?孩子们接触它安全吗?所以我想训练一个模型来识别蘑菇/真菌。这个想法就是用手机拍一张照片,问模特这是什么。很棒,不是吗?
所以,这就是我玩图像分类的心路历程。

照片由 Kalineri 在 Unsplash 上拍摄

定义问题:图像检测/图像分类

在我们开始之前,让我们澄清一些概念。计算机视觉是人工智能的一个有趣分支,它是一种教会模型在图像中寻找信息,从而理解视觉内容的艺术。当图像分类对人类来说相当简单时(猫、狗、汽车……),机器总是努力保持竞争力。这是我们人类小时候就学会的东西。父母/幼儿的一个常见游戏是重复物体和人的名字。所以对日常课来说很容易。计算机视觉走过了漫长的道路,现在通过深度学习,它已经和人类一样好,甚至在特定领域更好。例如,在医学放射学中,人工智能可以被训练来检测和分类肿瘤,并且通常比人类有更好的结果。

计算机视觉的第一步是图像检测。

图像检测是在给定的图像中找到图像中的特定对象,并返回其坐标/边界框。

图像分类是当你给出一个物体的图像,你的模型返回一个带有概率和置信度的类。因此,我们的模型应该首先检测对象,然后根据它所训练的类的类型对它们进行分类。为此,我们通常使用 CNN-卷积神经网络。什么是 CNN?

图像是像素的矩阵。要仅检测图像中的边缘,您需要乘以一个滤波器矩阵。这将使大多数像素为零/黑色,它将只显示你的边缘。更多详情请查看本页。CNN 是一系列的节点,每个节点都对图像进行过滤。这有助于模型从图像中学习特征,数学上称为向量。网络越深——层数和节点数最多——消耗的内存就越多。

图像识别就是你给模特一个有多个物体的图像。对于图像中的每个对象,该模型给出其边界框(对象检测)和具有置信度的类别预测。

我们这里的问题是多类分类/图像分类。

收集数据

为了训练一个模型,你需要好的标记数据,当我说好的标记数据时,它就像是你项目的第一块石头。如果你错了,那么所有进一步的努力都将是徒劳的。这对任何机器学习项目来说都是至关重要的一步。正如我们所说:“垃圾进来,垃圾出去”。想想看,就像你试图教一个孩子什么是蘑菇。如果你给他看不同的物体,每次都说“那是一个蘑菇”,你可以相当肯定,孩子会认为蘑菇是物体的通称。所以我们需要准确。对于这一步,您可以废弃 web 或找到可用的开放数据。

我尝试了 Kaggle 真菌数据集。这是一个非常好的数据集,有 1394 个可用的类在这里。我玩了一会儿,心想,这是图像识别的经典问题。应该不比人脸识别难。事实上,我不久前了解到,在中国最大的办公楼里,人脸识别被用来检查没有徽章的员工的身份。我印象非常深刻,我以为蘑菇也会如此,我可以从这些模型中转移学习,让我的新模型在 TensorFlow 库中施展魔法。你猜怎么着?

一点效果都没有。一张脸的共同特征对蘑菇来说几乎没有用处。我的第一批模特什么都没学到。我投入了如此多的时间,甚至一些眼泪,最终得知 1394 班的不平衡数据,并不容易。在这个数据集中,对于某些类,我们只有三幅图像。有时,我的模型在训练集上学习,并且做得很好,比如 86%的准确率,而当到达验证集时,我们下降到 20%。为什么?这是由于不平衡的数据集。该模型学习猜测具有最大数量图像的类。如果你给一个孩子看 300 次蘑菇,一次土豆,他肯定会比土豆更容易猜出蘑菇。对于这篇文章,我想重点讨论用 TensorFlow 进行图像分类。所以,我选择只处理 10 个类。我们拥有的类越多,模型就越难以区分它们。所以你必须收集更多的图像来学习更多的特征。对于这第一次尝试,我想保持简单,我希望它将是有效的。

让我们探讨如何使用 TensorFlow 构建一个端到端的图像分类项目。

让我们开始吧!

数据处理

Tensorflow 为我们提供了这个很棒的 API tf.data.dataset,您可以使用一行代码创建一个高效的数据集,其中包含多个经过优化的本地函数面板。我用下面的代码从本地下载的 images 目录中创建了我的数据集。
通常当我在玩一个新项目时,我更喜欢快速制作笔记本,但在这里我不能使用 image_dataset_from_directory 来创建我的 TensorFlow 数据集,所以我切换到 Pycharm。Jupyter 笔记本上还没有。那就 Pycharm 吧!

以下是我们将要学习的 10 个课程:

[' 11082 _ Xerocomellus _ chrysenteron ',' 12919_Cylindrobasidium_laeve ',' 14064_Fomitopsis_pinicola ',' 14160 _ 灵芝 _pfeifferi ',' 17233 _ 菌丝体 _galericulata ',' 20983_Trametes_versicolor ',' 21143 _ 口蘑 _ 头皮菌',' 40392 _ 蜜环菌 _ 藤黄',' 40985 _ Byssomerulius _ 真皮层',' 6185

由我的代码生成的情节的图像

让我们设置数据集性能

迁移学习模式

我从创建自己的 CNN 开始,但它做得不是很好。我没有耐心去改善它,我选择了迁移学习。
迁移学习是指重新使用在更大数据集上训练的模型的能力,这些模型已经学习了多个特征。为此,我们冻结了顶层,并用新的课程进行再培训。许多已知的模型赢得了 imagenet 竞赛。砝码可以重复使用。所以让我们用这些预先训练好的模型来帮助自己。我使用 MobileNetV2 模型是因为它非常轻,它可以在几秒钟内在我的 GPU 上运行。

我增加的提高准确性的独特步骤是数据扩充。
数据扩充是:对于一个输入标签的图像,你对它进行缩放或翻转,将其作为输入添加到模型中。这有助于模型继续识别对象,即使它不总是在相同的位置。

这是结果

作者 MobileNetV2 的图片结果

它只对 10 个时期有效,并且只增加了数据。

现在让我们来预测—下面是我的代码。我在 Xerocomellus_chrysenteron 类的 mycodb web 数据集上拍摄了一张图片。

这个模型说:

很好,不是吗?

结果上方的矩阵是预测的向量。端到端项目现已完成。下一步应该是提高准确性,并扩展到其余的类。这是我训练一个能够识别 1394 种真菌的模型的第一步。令人印象深刻的是,它在不太长的时间内就做得这么好。请继续关注我的更新!
快乐编码!

边缘的计算机视觉

原文:https://towardsdatascience.com/computer-vision-on-edge-b5adb5c6ccde?source=collection_archive---------16-----------------------

AIoT 的目标检测:边缘计算实例

几周前,当我在全球速卖通逛街时,我偶然发现了这个奇妙的装置。据称它将携带 RISC V 架构以及一个 KPU (KPU 是一个通用神经网络处理器)。电路板的对比规格如下:

  • CPU: RISC-V 双核 64 位,带 FPU
  • 图像识别:QVGA@60fps/VGA@30fps
  • 芯片功耗< 300mW

MaixDuino (Image from Sipeed

说实话,该单位是旧的,只是最近才注意到。鉴于我对边缘计算的兴趣,我想为一个对象检测示例提供一个完整的端到端指南。这个例子基于 Dimitry 的这篇文章中的知识。然而,我将全面介绍如何收集图像并对它们进行注释。如果你想知道什么是边缘计算,请阅读下面的文章。

https://medium.com/swlh/what-is-edge-computing-d27d15f843e

让我们尝试建立一个图像检测程序,将能够边界出苹果和香蕉。你可以创造性地使用你的探测器。我们将继续讨论所需的工具和库。

打开图像数据库(链接)

关于迁移学习的注记

迁移学习是指我们使用预先训练好的模型来进一步专业化。简而言之,您用自己的分类层(或更多层)替换训练模型的最后一个预测层。然后冻结除你之外的层(或者一些预先训练的层)。然后训练网络,以便使用预训练模型的功能来微调图层,从而预测所需的类。

不幸的是,目前我们将要训练的网络没有任何预先训练的模型。因此,我们将大部分时间在地面上训练。但这将是一个有趣的实验!

准备数据

我们需要准备以下格式的数据。首先,我们需要苹果和香蕉的图像。同时,我们需要对它们进行注释,说明每个水果在图像中的位置。这就是物体分类和检测的区别所在。我们需要说出物体的位置。为此,您需要以下工具。

https://github.com/tzutalin/labelImg

或者你可以使用我的工具,用你的背景和物体图像生成带注释的图像(例如:来自卡格尔的 Fruit 360 的图像)。在这里阅读更多;

https://anuradhawick.medium.com/annotator-for-object-detection-950fd799b651

在我的例子中,我使用下面的程序从网络摄像头捕捉。选择简单的方法。下面的程序是用 Nvidia jetson nano 入门容器编译的。

https://github.com/dusty-nv/camera-capture

捕捉图像(作者提供的图像)

数据集上的训练

我们想训练我们的模型,以便它们可以在 MaixDuino 设备上运行。为此,我们可以使用下面的存储库。它对模型层进行了所有必要的修改,以适应 K210 处理器的架构。克隆并安装所需的依赖项。以下链接提供了所有说明;

https://github.com/AIWintermuteAI/aXeleRate

我们需要如下组织我们的训练数据:

path-to/data
---anns      # store the training annotations
---imgs      # relevant images for the training
---anns_val  # validation annotations
---imgs_val  # validation images

现在我们需要创建一个 config.json 来设置训练选项。对于我们的例子,它应该如下所示;

{
    "model" : {
        "type":                 "Detector",
        "architecture":         "MobileNet7_5",
        "input_size":           [224,224],
        "anchors":              [0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828],
        "labels":               ["Apple", "Banana"],
        "coord_scale" :  1.0,
        "class_scale" :  1.0,
        "object_scale" :  5.0,
        "no_object_scale" :  1.0
    },
    "weights" : {
        "full":     "",
        "backend":              "imagenet"
    },
    "train" : {
        "actual_epoch":         50,
        "train_image_folder":   "data/imgs",
        "train_annot_folder":   "data/anns",
        "train_times":          2,
        "valid_image_folder":   "data/imgs_val",
        "valid_annot_folder":   "data/anns_val",
        "valid_times":          2,
        "valid_metric":         "mAP",
        "batch_size":           4,
        "learning_rate":        1e-4,
        "saved_folder":     "obj_detector",
        "first_trainable_layer": "",
        "augumentation":  true,
        "is_only_detect" :   false
    },
    "converter" : {
        "type":       ["k210"]
    }
}

注意:使用绝对路径来避免不必要的错误。

接下来,我们可以使用以下命令进行训练;

python3 aXelerate/axelerate/traing.py -c config.json

现在训练完成了。我们对在项目文件夹中生成的 kmodel 文件感兴趣。我们可以将它移动到一个 microSD 卡上,并将其连接到 MaixDuino 设备上。

预言;预测;预告

以下是我将在 maixPy IDE 中使用的草图。

import sensor,image,lcd
import KPU as kpulcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.set_vflip(1)
sensor.run(1)classes = ["Apple", "Banana"]
task = kpu.load("/sd/name_of_the_model_file.kmodel")
a = kpu.set_outputs(task, 0, 7, 7, 35)anchor = (0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828)
a = kpu.init_yolo2(task, 0.3, 0.3, 5, anchor) while(True):
    img = sensor.snapshot().rotation_corr(z_rotation=90.0)
    a = img.pix_to_ai()
    code = kpu.run_yolo2(task, img)

    if code:
        for i in code:
            a = img.draw_rectangle(i.rect(),color = (0, 255, 0))
            a = img.draw_string(i.x(),i.y(), classes[i.classid()],
                color=(255,0,0), scale=3)
            a = lcd.display(img)
    else:
        a = lcd.display(img)a = kpu.deinit(task)

确保改变输出参数,以适应kpu.set_outputs(task, 0, 7, 7, 35)中训练好的神经网络。现在你已经准备好运行程序了。这很容易。看看下面的截图。

作者提供的图片

注意质量很低。这是因为 maixPy IDE 允许我们将 LCD 显示流式传输到计算机。所以质量比较少。

该图像检测程序可以在 300 毫安的电流下运行。此外,它有类似于 Arduino nano 板的 GPIO 引脚。所以可能性是很多的。然而,用 python 编程也是一大解脱。

我希望这篇文章能让您对数据科学有一个新的认识。快乐阅读!

干杯。

计算机视觉传感器和系统

原文:https://towardsdatascience.com/computer-vision-sensors-systems-bdc079847316?source=collection_archive---------30-----------------------

捕捉和诠释光的旅程。

布鲁诺·伊曼纽尔在 Unsplash 上拍摄的照片

从硬件到支持计算机视觉的系统,这篇文章是一个广度优先于深度的综述。为了平衡这种方法,本文将读者引向指导性的参考资料,并提供了现成的源代码。我们从图像形成的机制开始。我们涵盖针丨孔丨,镜头,传感器(CCD 和 CMOS),拜耳过滤器,和颜色重建。

然后,我们转向应用计算机视觉来检测图像和图片中的道路车道。第一种方法基于一组常用的计算机视觉算法。我们涵盖了 Canny 边缘检测,高斯模糊,感兴趣的区域,和霍夫变换。第二种方法在空间卷积神经网络上运行推理,以检测图像和视频输入上的道路车道。

成像简史

暗箱图像的美是无法用语言表达的。绘画艺术已经死亡,因为这就是生活本身:或者更高级的东西,如果我们能找到一个词来形容它的话。
——康斯坦丁·惠更斯私人信件,1622 年 4 月 13 日

拍照是将 3D 场景投影到 2D 平面上。暗箱通过针丨孔丨实现了这种投影。墙上的一个小针丨孔丨可以让光线穿透照相机的暗室。这种简单的机制产生了清晰的投影,让艺术家们可以在场景上勾画出精细的细节。但是这种方法在亮度方面有所欠缺,针丨孔丨本身不能收集足够的光。

在阿塔纳斯·珂雪的Ars Magna Lucis Et Umbrae(1645)中雕刻一个“便携式”暗箱

针丨孔丨摄像机甚至在今天也吸引了广泛的兴趣。他们能够捕捉到令人惊叹的图像,这些图像的特点是在任何地方都具有同等聚焦的视觉效果。缺点还是一样,图像暗淡,需要长时间曝光。

伊万·麦格雷戈,邓卢斯城堡的日落,用针丨孔丨相机拍摄,曝光时间为 20 分钟。

为了解决昏暗的问题,引入了透镜。通过在光圈前放置一个透镜,可以聚集更多的光。镜头也可以改变投影图像的放大倍数。在过去,放大需要艺术家移动整个相机。如今,在不改变场景和图像平面之间的距离的情况下,可以移动镜头的位置来调整放大效果。变焦是移动镜头来改变放大率的过程。

即使有了镜头,捕捉图像也要持续很长一段时间,依靠艺术家在投影图像上画图。十九世纪三十年代路易·达盖尔发明的胶卷是摄影史上最重要的发明之一。这是第一次有可能在物理层上记录光线,无需依靠艺术家,只需按下按钮就能记住某个时刻。

胶片上涂有卤化银。一旦暴露在光线下,卤化银就转化为金属银。转换的数量取决于胶片上任何特定点的曝光。为了产生图像,胶片随后通过照相显影的化学过程进行处理。

玛丽安娜·卡塞塔的黑白底片处理

硅图像探测器的发明甚至比胶片更有影响力。同一块芯片可以用来拍摄无限数量的照片,不再需要化学照相显影。这是数码相机使用的技术,也是今天我们大多数人在手机上使用的技术。

图像传感器

概括地说,拍照就是将 3D 场景投影到 2D 平面上。投影是由镜头辅助的光圈实现的,以收集更多的光并调整放大倍数。2D 平面首先是一个简单的表面,艺术家可以在上面绘画。它后来成为卤化银胶片的表面。最后,它现在是硅片的表面:一个图像传感器。

为了将接收到的光转换成数字图像,大多数图像传感器依赖于硅原子的特性。当具有足够能量的光子撞击硅原子时,它会释放电子。在硅晶格(像素)上,光子通量曝光产生电子通量。电子通量然后被转换成电压。

电荷耦合器件

在这种类型的图像传感器中,光子到电子的转换发生在每个像素中。在每个像素下面有一个电容器储存释放的电子。称为垂直 CCD 移位寄存器的电路连接在每列像素的电容器之间。该电路使得电子能够从一个像素垂直转移到其正下方的像素,直到它们到达最后一行。这最后一行由水平 CCD 移位寄存器连接,该移位寄存器将电子传送到模数转换器。

电荷耦合器件。作者 Gif。

电荷耦合器件中电子的垂直转移是用桶旅法完成的。这意味着每一行在获取前一行的电子之前,先将它的电子传递给下一行。水平转移保持了行的顺序,因为它们向 ADC 水平移动,在 ADC 中它们被转换成与其电子电荷成比例的电压。

互补金属氧化物半导体 CMOS

CMOS 以不同的方式实现图像传感器。它不是将电子从像素转移到 ADC,而是在像素级集成电压转换。

互补金属氧化物半导体。图片作者。

使用 CMOS,可以单独寻址每个像素以读取其电压。这提供了更大的灵活性,因为它能够更快地读取感兴趣的特定区域。由于在像素级集成了更多组件,灵活性是以更小的光敏区域为代价的。为了补偿光敏区域的减少,微透镜被放置在每个像素的正上方。这些微透镜将光线聚焦在光敏探测器上。

像素结构。图片作者。

捕捉颜色

像素本身能够捕捉光的强度,但不能捕捉光的波长。为了捕捉颜色(波长),最流行的方法是叠加一个拜耳滤光片阵列。在这种方法中,每个像素都覆盖有红色、绿色或蓝色的滤镜。

图像传感器像素阵列上滤色器的拜耳排列。每个 2×2 单元包含两个绿色、一个蓝色和一个红色过滤器。图片由科林 M.L 伯内特提供。

几乎所有颜色的人类感觉都可以用三种波长产生。捕捉红色、绿色和蓝色波长足以再现被拍摄场景的真实颜色。但是仅仅覆盖拜耳模式是不够的。它会产生看起来像左边的图像:

(左)拜耳模式。(右)插值重建的图片。作者图片。

(左)放大的拜耳模式。(右)通过插值放大的重建图片。作者图片。

左侧图像的像素全部是红色、绿色或蓝色。请注意,图像看起来大部分是绿色的。拜耳模式模拟了人类视网膜在白天对绿光最敏感的事实。因此,过滤器是一半绿色,四分之一红色,四分之一蓝色。

为了将左边的图像转换为右边的图像,我们获取每个像素的值,并将其与其相邻像素的值相结合。这个过程叫做插值。假设我们从左边的图片中取一个蓝色像素。插值是将蓝色值与相邻像素的红色和绿色值混合。

为了实验光混合是如何工作的,这里有一个很好的模拟。要了解它与油漆颜色混合的不同,这里有另一个好链接。

计算机视觉

图像传感器的应用已经成为我们生活中的基础。它们塑造了我们表达自己和交流的方式,它们开辟了科学和艺术的跨学科领域。也许这些领域中最先进的是计算机视觉。

研究计算机视觉必须从对支持它的硬件的理解开始。我们简要介绍了硬件的历史、进步和主要组件。让我们看一个令人兴奋的实际应用程序,它利用了这一点。

自动驾驶汽车中的车道检测

自 2021 年 5 月以来,特斯拉开始交付不再配备雷达的 Model 3 和 Model Y 车辆。这些车型依靠基于摄像头的自动驾驶系统在相同的安全评级下提供相同的功能( 过渡到特斯拉视觉 ,2021)。

特斯拉 Vision 的主动安全功能包括车道偏离警告/避免。能够探测道路车道对驾驶至关重要。我们将着眼于车道检测,并以两种不同的方式实现它。首先使用计算机视觉算法,其次使用空间卷积神经网络。

(左)弗林克瑞的亚利桑那州,(右)维克 _ 醋的锡安国家公园。经所有者许可使用的图像。

第一步是检测图像中最突出的边缘。相邻像素与其亮度水平形成对比的区域被标记为边缘。以下代码将图像转换为灰度,使用高斯滤波器模糊以减少噪声,并应用算法 Canny 边缘检测。

精明的边缘检测。

Canny 边缘检测后得到的图像。由作者处理的图像。由 Flinchcr 拍摄的原始(左)图像。原(右)图由Vic _ 醋拍摄。经所有者许可使用的图像。

这些图像充满了我们不需要的信息。我们希望专注于前方的道路,因此我们将定义一个感兴趣的多边形区域来裁剪每个图像。对于两幅图像,定义多边形的点会有所不同。为了找到它们,我们可以绘制图像并显示宽度和高度轴。

感兴趣的区域。

用于裁剪图像的多边形遮罩。作者图片。

由此产生的感兴趣区域。由作者处理的图像。由 Flinchcr 制作的原始(左)图像。原(右)图由Vic _ 醋提供。经所有者许可使用的图像。

观察由此产生的感兴趣区域,人眼可以容易地感知线条。那些线实际上是一系列像素,它们只是计算机的点。我们需要描绘两条最能描述这些点的排列的主线。这是使用霍夫变换算法完成的。

霍夫变换。

将蓝线添加到原始图片后的结果。由作者生成的图像。由 Flinchcr 拍摄的原始(左)图像。原(右)图由Vic _ 醋拍摄。经所有者许可使用的图像。

完整的实现包括我的 Colab 笔记本车道检测 OpenCV 的进一步改进和优化。

https://colab.research.google.com/drive/1sX5J1FDec9AUqxELuXfhBq6WLZ-FFssY?usp=sharing

这种方法可能看起来会产生很好的结果,但是这种实现远不是最佳的,因为:

  • 我们必须为每种情况明确定义感兴趣的区域。由于视角的变化,应用相同的多边形遮罩来裁剪 ROI 是不可能的。
  • 计算时间太慢,驾驶需要高处理速度。
  • 转弯涉及曲线车道,这种方法仅适用于直线车道。

让我们来看一个使用[空间 CNN 进行车道检测的替代方案](http://Spatial CNN for Traffic Lane Detection) ( 潘新刚 et all,2018)。在 Colab 笔记本上,我们首先创建一个到 Drive 帐户的链接。然后我们克隆项目存储库。

我们在项目的根目录下上传了三个文件:ERF net _ encoder _ pretrained . PTH . tarERF net _ baseline _ culane _ 2021 02 04 . ptERF net _ baseline _ tu simple _ 2021 04 24 . pt*。*然后我们安装以下依赖项:

我们可以通过以下命令使用图像运行推理:

我们可以通过以下命令使用视频运行推理,在这种情况下,图像路径对应于视频路径:

结果显示检测到的车道带有黑色虚线。Gif 与作者的车道检测。 Flinchcr 原创视频。经所有者许可使用的图像。

完整的实现包括 Git 存储库的克隆、依赖项的安装和推理代码都可以在我的 Colab 笔记本车道检测 SCNN 中找到。

https://colab.research.google.com/drive/1uBv9KQilCvEuAmTvpzQfhSNjN8gJHfY5#scrollTo=h8YWDFqFK6cH

承认

本文第一部分站在一个巨人的肩膀上, Shree K. Nayar 。这是计算机视觉基本原理课程第一课的总结。我计划发布更多的文章来传达我对这门课程的理解。我怀着深深的感激之情,感谢 Nayar 为让这样一个高质量的课程变得免费和容易获得所做的努力。

https://www.youtube.com/channel/UCf0WB91t8Ky6AuYcQV0CcLw/about

第二部分从获取完整的自动驾驶汽车路线以实现基于 OpenCV 的车道检测。这部分还依赖于 Pytorch 自动驾驶项目运行视频推理进行车道检测。

https://github.com/XingangPan/SCNN

计算机视觉——过滤的重要性

原文:https://towardsdatascience.com/computer-vision-the-importance-of-filtering-c0d9640c6e72?source=collection_archive---------33-----------------------

理解计算机视觉中过滤的基础知识

计算机视觉的核心是从图像或视频中提取最有意义的特征。这就是为什么理解“特征提取”过程的基础对于使用或创新最先进的计算机视觉解决方案极其有用。

要深入理解任何一个概念,首先要了解它的基础。在这种情况下,为了理解滤波在图像中的工作原理,我们首先需要回过头来分析它是如何应用于 1D 信号的。

信号过滤

考虑以下信号:

作者图片

信号处理中的一个基本概念是信号的叠加,将信号分解成更简单的成分。请记住,这个概念的全部目的是理解信号和系统 如何工作

通过将先前的信号分解成更简单的信号,我们获得以下分量:

作者图片

获得这些之后,我们可以分析它们是如何被系统单独影响的。此外,我们正在获取关于**系统如何响应脉冲的信息,也称为卷积。你是如果你看过这篇文章,可能对这个术语很熟悉;然而,知道你在执行卷积时实际在做什么,可能会在将来解决更复杂的问题时对你有所帮助。另一个你可能非常熟悉的术语是滤波器内核,**它只不过是系统的 i **脉冲响应。**这非常重要,因为如果我们知道系统如何响应脉冲,就可以根据任何给定的输入信号计算出其输出。

信号中的卷积运算遵循与图像中的卷积相同的过程:滤波器必须以给定的大小和步幅通过信号的总长度。下图说明了信号 x 与内核 h 的卷积。

作者图片

低通滤波与高通滤波

既然您已经了解了滤波的过程及其实际意义,那么能够区分低通和高通滤波也很重要。

  • 低通滤波—它可以被视为一种平滑滤波器,用于衰减高频并保留低频。您可以很容易地将它与其他过滤器区分开来,因为它只有正值(1 个方向)。

作者图片

  • 高通滤波 —与低通滤波相反,高通滤波用于衰减低频,保留高频。这个想法是突出信号中变化最大的部分。您可以很容易地将它们识别为高通,因为它们同时具有正值和负值(2 个方向)。

作者图片

当应用于信号时,分析这些类型的滤波器是极其重要的,因为这将为你深入理解它们对图像处理的多重影响奠定基础(2D)。

话虽如此,在这一点上,即使你不知道这两种类型的过滤器之间的差异,你已经可以开始理解它们在应用于图像时会产生的不同效果。

滤像

在提出 CNN(卷积神经网络)模型之前,需要手动提取图像的特征,然后将它们输入神经网络或任何其他类型的分类器。这些特征可能很简单,比如黑白像素的数量,也可能有点复杂,比如亮度、强度和能量。这尤其困难,因为除了尝试不同的特征组合和分析模型的性能表现之外,没有办法知道哪些特征对分类器最有意义;然而,这可能是一个非常耗时的过程。从个人经验来看,提取新的有意义的特征并不是一件容易的事情,有时会导致添加可能对模型性能产生负面影响的特征。为了从图像中获得更多独特的特征,通常对其应用过滤器,然后从结果图像中提取特征。 Gabor 滤波器(高通)通常用于检测图像的边缘,如下图所示。

作者图片

这就是 CNN 介入并完全改变特征提取过程的地方。如今,如果你有大量的数据,你不需要手动执行任何特征提取,因为模型会自己找到最有意义的特征。

当用老方法执行这个过程时,您必须尝试不同的特征组合来评估模型的性能。现在,CNN 模式也在做同样的事情,但更加严格、自动、规模更大。

话虽如此,任何神经网络模型的主要缺点之一是可解释性。如果一个卷积模型中有 4096 个过滤器,你根本不知道它们是什么意思,也不知道它们在提取哪些特征。你所知道的是,它们提取了非常好的特征,并且它们对于特定的问题是最有意义的。虽然这种方法可以完美地解决大量现实世界的问题,但是如果你想让你的解决方案有机会被政府、健康实体和许多更敏感的领域所接受,你的模型必须**能够解释它的决定。**人们宁愿拥有一个 70%准确并能解释其做出的每一个决定的模型,也不愿拥有一个 99%准确但不能给出任何解释的模型。

此外,本文中提到的两种类型的过滤器可以提取什么样的特征,应该给出更多的例子。

如果您考虑“信号”部分中每种滤镜类型的定义,同样的效果也适用于图像。一方面,低通滤波器具有所有正值,并且通常用于平滑图像或执行模糊。

平滑过滤器。作者图片

但是另一方面,高通滤波器通常用于执行边缘检测。如果你记得它的定义,高通滤波器保留高频。在图像中,它们会突出显示像素值差异较大的区域。

边缘检测滤波器。作者图片

结论

这篇文章的主要重点是阐明卷积运算的根源,解释它的意义,并提供一个关于什么是滤波器的更好的观点。在实际上没有信号处理基础的情况下学习 CNN 会对设计智能系统产生影响。如今,大多数模型都有大量的超参数,可以通过调整来为我们的问题构建“完美”的系统,因此,理解它们的作用和意义非常重要。

就我个人而言,正如本文之前所述,这些智能系统的一个非常重要的部分是它们的可解释性。而且,为了让我们开始构建能够对他们的行为进行某种解释的模型,我们首先需要理解这些操作的意义。

最后一点,看到这个领域之外的人将这些系统的学习过程视为某种“魔法”是非常令人兴奋的。然而,对于开发人员来说,关键是不要把它当成魔术,并深刻理解它背后的基本原理,以不断创新和构建更好的系统。

张量流计算机视觉

原文:https://towardsdatascience.com/computer-vision-with-tensorflow-9f183636c4cc?source=collection_archive---------38-----------------------

关于我们如何编程机器从图像中学习的全面指南

精神岛之旅。作者图片

这将是《人工智能导论》、机器学习和深度学习 Tensorflow story 的延续,在那里我讨论了标准的神经网络。如果这对你来说是全新的,我建议你先从这里开始。

目录:

  1. 构建数字识别器
  2. 发展数字识别器
  3. 这是怎么回事?
  4. 构建猫和狗的分类器

构建数字识别器

MNIST 数据集

计算机视觉是使用神经网络学习图像结构的实践。当我们看一张图片,比如一件衬衫,我们怎么知道这是一件衬衫?我们可以通过识别衬衫的具体特征来识别它,比如衣领、形状或背景(这件衣服穿在哪里?)如图所示。这类似于我们希望机器也能够学习图像的方式——我们希望模型能够理解图像的空间上下文。

和以前一样,我们先从一个例子开始。我们可以从 Tensorflow 加载 MNIST 数据集,这是一个手写数字的大集合。

来自 MNIST 数据集的样本,维基百科

作者图片

MNIST 数据库包含 60,000 幅训练图像和 10,000 幅测试图像,黑白图像被归一化以适合 28×28 的边界框。这意味着当您加载数据时,它会在一个列表中产生 60,000 个 28x28x1 项目,但模型中的第一层(卷积层)将需要一个 60,000x28x28x1 的单个 4D 列表,因此这就是我们重塑训练和测试图像的原因。

但是我们为什么要用 255.0 来划分图像呢?这样做是为了将图像的像素值归一化到 0 和 1 之间,这使得网络更容易学习最佳最小值。

现在来构建卷积神经网络。

我们的第一个卷积神经网络

作者图片

标准神经网络只有密集层,因此我们现在发现卷积神经网络有 3 个新层:Conv2D、MaxPooling2D 和 Flatten。这些层代表了这种类型的神经网络如何学习图像的空间特征。

我们将简要介绍各层的功能,但目前该模型能够通过移动过滤器扫描图像的像素,然后将其展平为一维阵列,使其类似于标准神经网络,最后通过密集层发送,就像非卷积网络一样——密集层有 128 个节点,输出层有 10 个节点。

最终输出层包含一个 softmax 激活,它生成十个目标类的概率(0-9 位数值),并预测概率最高的值。

作者图片

作者图片

由于这是一个分类任务,特别是多分类,我们将使用的损失函数是稀疏分类交叉熵。如果是二元分类,我们就用二元交叉熵。这与我们使用均方误差的回归任务相反。

当我们在训练集上达到可接受的精度时,我们可以像以前一样使用回调来停止训练。对看不见的数据进行评估的时间。

作者图片

作者图片

作者图片

作者图片

总的来说,模型表现很好,但是在验证集上稍差一些,所以可能出现了轻微的过度拟合。Dropout 是一种常用的技术,因此模型不会过于依赖给定的节点,这有助于避免过度拟合。简而言之,Dropout 是一种在给定层中随机删除一定比例的节点的方法,以迫使模型不要过于依赖任何给定的节点。

说到图像,还有另一种技术:图像增强。这包括旋转、宽度/高度移动、剪切、缩放、裁剪和翻转。在将数据拟合到您的模型之前,您可以轻松地添加这一步骤,它允许模型更有效地推广到新的示例。这背后的原因也很简单——如果你有一只狗的图像,但它们都是用腿站立的,那么一个模型可能会在狗仰卧的照片上表现得更差。图像增强有助于这一点,因为它提供了更多独特的图像方向供它学习。

让我们试着重建和发展我们最初的模型,看看我们能做些什么!

发展数字识别器

加载和预处理设置

作者图片

代码看起来与我们最初的模型一样,只是我们为训练和验证集添加了一个数据生成器,以在一定程度上增加图像(包括归一化像素值)。这里需要注意的一点是,我们不想增加测试数据,只增加训练数据。为什么会这样?我们希望模型能够推广到新的图片,这些图片通常不会像我们的增强图像那样扭曲;我们的扩充主要是为了让模型考虑到像素空间位置的变化。这也为我们的模型创建了一个更大的训练集来学习。

轻松提升复杂性

作者图片

使用层增加复杂性与使用标准神经网络一样容易,但这里的关键变化包括:

  • 添加一个丢弃层,在输出前从隐藏层中随机丢弃 20%的节点
  • 通过数据生成器收集训练/测试图像,这允许我们在训练模型时添加简单的预处理步骤,如图像增强
  • 将批量大小设置为 64,这是在每个时期更新模型之前要处理的样本数。所以一次可以通过 64 幅图像。

该模型可以通过数据生成器轻松拟合,如下所示:

作者图片

作者图片

我降低了准确性阈值以节省计算和时间成本,但看看每个时期的训练/测试损失和准确性——该模型始终能够很好地推广到新数据。

这是怎么回事?

卷积神经网络由在图像的一部分上迭代以提取图像的全局和局部空间特征的滤波器组成。

作者图片

这表示在 6x6 图像上卷积 1 个大小为 3x3 的滤波器。我们经常使用 64 个大小为 5×5 的滤波器来卷积 28×28×1 的图像。实际上,每个单元格都乘以其对应的单元格,然后求和以获得新值(31+11+21+00…=-5),然后过滤器移动 1,直到扫描完所有值。对于这些层中的每一层,模型都试图学习图像中类似于信号的有区别的全局和局部特征。通常,随着层数的增加,模型可以学习图像的更多具体特征。一个很好的例子是,扫描面部图像的模型的第一层可以学习面部的整体轮廓边缘,第二层可以学习面部内将眼睛从鼻子和嘴中区分出来的线条,第三层可以学习眼睛的更有区别的特征(形状、颜色、大小等)。),等等。

这里需要注意的一点是,滤波器的值在很大程度上决定了输出图像中检测到的内容。如果滤波器中全是 0,输出图像也将全是 0,不会发生边缘检测。这些过滤器是 CNN 所学习的,因为它能够在每幅图像中提取有意义的、有区别的特征,这使得它能够尽可能地最小化关于目标标签的损失。

过滤器之外

您可能会注意到,在将滤镜通过原始图像后,输出图像会缩小。这种情况可能会逐步升级,因此如果您希望输出图像保持相同的大小,一种常见的技术是在原始图像周围填充一层 0。

此外,您可能不想让过滤器一次一列地通过图像。您可以跨越卷积来跳过原始图像中的两列或更多列。

然后我们也有池层。这些通常是最大或平均池层,它们通过获取图像某一部分的最大值或平均值来运行。

作者图片

通常情况下,最大池是这样做的,但这是一种保留可能在图像的一部分中的特征信号的方法。有趣的是,MaxPooling 并没有梯度下降的超参数可以学习。滤波器大小和跨距的固定值相应地应用于每个卷积层。在功能上,它是一种在图像的较小维度的图像区域中保留特征信息(通过高像素值指示的信号)的方式。

更复杂的是,我们经常处理彩色图像,而不是灰度图像。这通常意味着图像驻留在三维(RGB)中,因此我们不只是通过 2D 卷积,而是通过 RGB 像素值矩阵的三维卷积(例如,5x5x3)。

为什么是回旋?

当对图像进行操作时,在密集层上使用卷积层有两个主要好处:

  1. 参数共享:在图像的一部分有用的特征检测器可能在图像的另一部分也有用(例如垂直或水平边缘检测器)
  2. 连接的稀疏性:在每一层中,每个输出值只依赖于少量的输入

因此,我们有过滤器的大小,填充,步幅,池过滤器的大小,层数等。(甚至不包括训练大规模模型的计算和时间成本)-这是一个很大的跟踪量,更不用说编辑来测试什么工作得好,什么工作得不好!这就是一种叫做迁移学习的技术非常有用的地方。

迁移学习是站在巨人肩膀上的概念;您可以下载流行和成功的模型架构,以及它们的学习参数,冻结除输出层之外的所有层,并通过它运行您的数据以获得结果。这已被证明在各种领域产生了真正成功的结果,并且在使用深度神经网络架构时通常是首选。

我们可以将这一知识应用于猫和狗的分类器。

构建猫和狗的分类器

创建数据目录

Tensorflow 有很多方便的功能,可以很好地处理结构化目录。这首先要求我们在构建模型之前将图像加载到一个文件夹路径结构中。从技术上讲,如果您只关心建模部分,可以跳过这一小节,但是学习建模和非有效数据设计模式有点不切实际。

在加载到适当的目录之前,我们将加载谷歌的猫和狗的数据集。

作者图片

作者图片

这段代码将 Google 的猫狗数据集读入适当的目录。我们现在可以构建我们的预处理和数据流生成器。

预处理工作流

作者图片

以前,我们通过训练和测试分割来传输数据,这一次,我们可以简单地将它设置为从每个目录中传输。对于上下文,这仅在训练集中产生 2000 个图像,在测试集中产生 1000 个图像。现在是模型!

我们可以通过 InceptionV3 函数轻松地加载它,并限定我们也需要权重。通过层的循环,我们可以将它们的可训练标志设置为假。

摘樱桃盗梦空间网络

初始模型最后一层的快照。作者图片

这个模型相当庞大,如果你想了解更多关于盗梦空间网络的内容,我推荐你去看看这个网站:盗梦空间-v3 网络解释

作者图片

我们可以采用初始网络的输出层,然后像以前一样添加 Flatten()、Dense()和 Dropout 输出层的最后几个标准层。由于这是一个二元分类(猫或狗),我们在输出中只需要一个具有 sigmoid 激活函数的节点,以及用于损失函数的二元交叉熵。

作者图片

作者图片

由于数据集很小,我显著降低了历元数和每个历元的步数,但模型仍然表现得非常好。在一个时期内,我们看到大约 96%的准确性。

包裹

今天讨论了很多内容,但我试图在这里提供一个全面的入门指南,介绍计算机视觉的迷人世界。许多概念都建立在这里提到的主题上,包括创造人工智能艺术,使自动驾驶汽车能够“看见”,从 X 射线或 fMRI 扫描中提取模式等等。

我将有后续文章,将在此学到的知识应用于我感兴趣的数据集,但现在感谢您的阅读!请关注更多关于数据科学、机器学习和人工智能的内容。

参考文献

[1]深度学习。人工智能,卷积神经网络

【2】深度学习。AI,tensor flow 中的卷积神经网络

计算和可视化时间和频率相关性的简单方法

原文:https://towardsdatascience.com/computing-cross-correlation-between-geophysical-time-series-488642be7bf0?source=collection_archive---------1-----------------------

互相关是计算两个地震时间序列相互依赖程度的一个公认的可靠工具。一些研究依赖于互相关方法来获得对地震数据的推断。关于互相关方法的细节,我们让读者参考以前的工作(见参考文献)。

来自 Pexels 的照片

为了从我们的数据中获得有意义的推断,理解和识别两个时间序列之间的复杂和未知的关系是至关重要的。在本帖中,我们将采用地球物理数据进行理解。对于一般读者,我建议忽略特定领域的示例,继续阅读,因为相关性的概念是数学上的,可以应用于与任何领域相关的数据。

相关性不是因果关系[来源:GIPHY]

在地球物理学(具体来说是地震学)中,一些应用是基于寻找一个时间序列相对于另一个时间序列的时移,例如环境噪声互相关(寻找两个记录站之间的经验格林函数)、震源反演(例如 gCAP)和结构研究(例如全波形反演)、模板匹配等。

在本文中,我们将了解如何计算地震时间序列之间的互相关,以及如何在时域和频域中提取两个地震信号之间关系的时移信息。请注意,除非数据的自由度很高,否则相关值并不显著。详情请参考下面的帖子。

https://www.earthinversion.com/geophysics/estimation-degrees-of-freedom/

此外,人们可以使用蒙特卡罗模拟等数值测试来估计相关性的显著性。参考下面的帖子:

https://www.earthinversion.com/techniques/monte-carlo-simulations-correlations/

计算互相关

现在让我们看看如何计算两个时间序列之间的时域互相关。为了这个任务,我任意选取了两个地震速度时间序列:

任意选择的数据

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from synthetic_tests_lib import crosscorr

time_series = ['BO.ABU', 'BO.NOK']
dirName = "data/"
fs = 748  # take 748 samples only
MR = len(time_series)
Y = np.zeros((MR, fs))
dictVals = {}
for ind, series in enumerate(time_series):
    filename = dirName + series + ".txt"
    df = pd.read_csv(filename, names=[
                     'time', 'U'], skiprows=1, delimiter='\s+')  # reading file as pandas dataframe to work easily

    # this code block is required as the different time series has not even sampling, so dealing with each data point separately comes handy
    # can be replaced by simply `yvalues = df['U]`
    yvalues = []
    for i in range(1, fs+1):
        val = df.loc[df['time'] == i]['U'].values[0]
        yvalues.append(val)

    dictVals[time_series[ind]] = yvalues

timeSeriesDf = pd.DataFrame(dictVals)

上述代码读取包含位于目录(dirName)中的垂直分量的 txt 文件,并为任意获取的fs样本修剪数据。我们可以交互地读取每个txt文件,并将数据列保存到字典中。该字典接下来被转换成“熊猫”数据框架,以利用“熊猫”库中的所有工具。

请注意,有几种不同的方式来读取数据,这种方式的偏好取决于用户和数据格式。

为了绘制时间序列,我使用了matplotlib

# plot time series
# simple `timeSeriesDf.plot()` is a quick way to plot
fig, ax = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
ax[0].plot(timeSeriesDf[time_series[0]], color='b', label=time_series[0])
ax[0].legend()
ax[1].plot(timeSeriesDf[time_series[1]], color='r', label=time_series[1])
ax[1].legend()
plt.savefig('data_viz.jpg', dpi=300, bbox_inches='tight')
plt.close('all')

数据可视化(图片由作者提供)

计算时域中的互相关

d1, d2 = timeSeriesDf[time_series[ind1]], timeSeriesDf[time_series[ind2]]
window = 10
# lags = np.arange(-(fs), (fs), 1)  # uncontrained
lags = np.arange(-(200), (200), 1)  # contrained
rs = np.nan_to_num([crosscorr(d1, d2, lag) for lag in lags])

print(
    "xcorr {}-{}".format(time_series[ind1], time_series[ind2]), lags[np.argmax(rs)], np.max(rs))

在上面的代码中,我使用了crosscorr函数来计算一系列滞后值的时间序列对之间的相关性。滞后值被限制在-200 到 200 之间,以避免伪影。

# Time lagged cross correlation
def crosscorr(datax, datay, lag=0):
    """ Lag-N cross correlation. 
    Shifted data filled with NaNs 

    Parameters
    ----------
    lag : int, default 0
    datax, datay : pandas.Series objects of equal length
    Returns
    ----------
    crosscorr : float
    """
    return datax.corr(datay.shift(lag))

这里,正如你所注意到的,crosscorr 使用了 pandas corr 方法;因此,d1 和 d2 需要是“熊猫”系列对象。

我得到了上述时间序列对之间的相关性为0.19,滞后为36

xcorr BO.ABU-BO.NOK 36 0.19727959397327688 

任意取真实时间序列的时域互相关(图片由作者提供)

获取时移的互相关频域方法

shift = compute_shift(
    timeSeriesDf[time_series[ind1]], timeSeriesDf[time_series[ind2]])

print(shift)

这给出了-36

其中函数compute_shift简单来说就是:

def cross_correlation_using_fft(x, y):
    f1 = fft(x)
    f2 = fft(np.flipud(y))
    cc = np.real(ifft(f1 * f2))
    return fftshift(cc)

def compute_shift(x, y):
    assert len(x) == len(y)
    c = cross_correlation_using_fft(x, y)
    assert len(c) == len(x)
    zero_index = int(len(x) / 2) - 1
    shift = zero_index - np.argmax(c)
    return shift

这里,shift的移动意味着yx之前的shift时间步开始。

生成时间序列的合成对

虽然所获得的结果看似合理,但由于我们使用了任意一对实时序列,我们不知道我们是否获得了正确的结果。因此,我们将上述方法应用于具有已知时移的时间序列的合成对。

让我们使用scipy.signal函数生成一个双单位脉冲函数。然后,我们应用一个中心频率为 0.2 的 4 阶低通滤波器来平滑边缘(注意,即使没有滤波器,结果也是一样的)。

# Delta Function
length = 100
amp1, amp2 = 1, 1
x = np.arange(0, length)
to = 10
timeshift = 30
t1 = to+timeshift
series1 = signal.unit_impulse(length, idx=to)
series2 = signal.unit_impulse(length, idx=t1)

# low pass filter to smoothen the edges (just to make the signal look pretty)
b, a = signal.butter(4, 0.2)
series1 = signal.lfilter(b, a, series1)
series2 = signal.lfilter(b, a, series2)

fig, ax = plt.subplots(2, 1, figsize=(8, 6), sharex=False)

ax[0].plot(x, series1, c='b', lw=0.5)
ax[0].axvline(x=to, c='b', lw=0.5,
              ls='--', label=f'x={to}')
ax[0].plot(x, series2+0.1, c='r', lw=0.5)
ax[0].axvline(x=to+timeshift, c='r', lw=0.5,
              ls='--', label=f'x={to+timeshift}')
ax[0].set_yticks([0, 0.1])
ax[0].legend()
ax[0].set_yticklabels(['Series 1', 'Series 2'], fontsize=8)

d1, d2 = pd.Series(series2), pd.Series(series1)
lags = np.arange(-(50), (50), 1)

rs = np.nan_to_num([crosscorr(d1, d2, lag) for lag in lags])
maxrs, minrs = np.max(rs), np.min(rs)
if np.abs(maxrs) >= np.abs(minrs):
    corrval = maxrs
else:
    corrval = minrs

ax[1].plot(lags, rs, 'k', label='Xcorr (s1 vs s2), maxcorr: {:.2f}'.format(
    corrval), lw=0.5)
# ax[1].axvline(x=timeshift, c='r', lw=0.5, ls='--')
ax[1].axvline(x=lags[np.argmax(rs)], c='r', lw=0.5,
              ls='--', label='max time correlation')
ax[1].legend(fontsize=6)
plt.subplots_adjust(hspace=0.25, wspace=0.1)
plt.savefig('xcorr_fn_delta.png', bbox_inches='tight', dpi=300)
plt.close('all')

低通滤波单位冲激函数的时域互相关(图片由作者提供)

参考

  1. 晁,B.F .,钟,C.H,2019。估计一个数据集与另一个数据集的互相关和最小二乘拟合。地球物种。Sci。6, 1409–1415.https://doi.org/10.1029/2018EA000548
  2. 罗宾逊和特雷特尔(1980 年)。地球物理信号分析。新泽西州恩格尔伍德克利夫斯:普伦蒂斯-霍尔。
  3. 使用快速归一化互相关的模板匹配
  4. 庆开博客:“信号处理:频域互相关”
  5. 如何计算 Python 中变量之间的相关性

下载代码

以上所有代码可从我的 Github repo 下载。

原为 2021 年 2 月 16 日在https://www.earthinversion.com发表。

用 Beam 计算耦合数据流

原文:https://towardsdatascience.com/computing-on-coupled-data-streams-with-beam-3c8872b1faf8?source=collection_archive---------28-----------------------

思想与理论,行业笔记

耦合数据流需要一起分析,特别注意事件时间的同时性和控制参与者流的其他流程特定变量……

数据流现在无处不在。IOT 设备、自动柜员机交易、应用程序、传感器等……源源不断地输出数据。当这些数据流到达时,分析它们会带来挑战——尤其是当数据流是耦合的时候。例如,当单个底层进程生成多个数据流时,它们耦合。耦合的数据流只能一起分析,要特别注意这些数据流上的事件在时间上的同时性(以及其他与过程相关的问题,如发出数据流的空间位置)。如果其中一个数据流由于某种原因被延迟,整个处理框架就会停止工作,等待它赶上来,而来自其他数据流的数据就会堆积起来。

等到所有数据都在中才能理解它—不适用。在任何时间所有数据都不会在中。流处理技术在时间内通过窗口将流动的数据分批成块,并将每个块作为一个批次进行分析。由于有不同类型的时间 —事件/日志/流程等,用于批处理流的具体时间量取决于生成数据的流程和分析的目标。要使用的时间窗的具体类型(固定宽度、重叠等)及其宽度也是如此。缓慢发展的现象可以存在于更大的时间窗口中,而高度动态的系统将需要足够薄的时间窗口来忠实地跟踪过程随时间的变化。每个数据窗口可能在该窗口的代表时间产生一些关于过程的度量——比如说它的中点。

这是一个不完美的世界

现实世界中的数据流从来都不是完美的,因此流处理框架必须计划如何处理它们。

  • 迟到、无序到达和未出现。一些旧的测量可能在途中被延迟,并且比新的测量晚到达。有些人可能会完全迷路。时间窗应该打开多长时间是一个没有严格正确答案的问题。它依赖于产生数据并将数据传输到处理框架的机制。
  • 早期和改善结果。在处理该批数据之前,应该不需要等待时间窗口关闭,特别是当我们需要为迟到者打开时间窗口时。计算早期指标,即使它们是近似值,对于检测和警告潜在问题可能是有用的。
  • 需要同时。大多数进程以不同的速率产生不同的数据流。例如,化学反应器可能在不同的位置具有温度和压力传感器,每个传感器生成一个数据流。对反应堆健康状况的任何分析都需要在相同的时间从所有位置测量温度和压力。也就是说,不能使用一次温度测量和几分钟后(或在不同位置)的压力测量来正确评估反应堆的健康状况。

这篇文章的目的是在模拟数据流上说明上述内容。至于流处理框架,我们将使用 Apache Beam ,因为它似乎设计得很好,可以处理真实世界的数据流。此外,Beam 提供了一个可移植的 API 层来构建并行数据处理管道,这些管道可以在各种执行引擎上执行,包括 Google Clouddata flowfor scale。我们将坚持使用在本地运行的 DirectRunner。我们将使用 Apache Kafka 来产生数据流,并在 Beam 管道中使用它们。实现代码可以从 github 获得。

1.数据流

考虑识别一个明确定义的三角形的三个点。让一个理想的质量-弹簧系统附着在每一点上,当实验开始时,在它的最外部位置释放。当这些点以不同的频率围绕其静止状态执行简谐运动时,它们的坐标位置( x,y )产生稳定的数据流。当三角形变形时,对由这三个点标识的三角形的周长和面积等度量的精确估计是令人感兴趣的。这里的理想三角形只是一个替代物,比如说一个支撑关键结点的三角形金属法兰,数据流从每个角落的位置监控器发出。下面的图 1 说明了这一点,并获得了作为时间的显式函数的坐标位置。

图一。顶点围绕它们的静止状态沿着指定的轴执行简单的谐波运动。每个顶点处的监视器为其坐标位置(x,y)生成数据流。这些流由 Beam 一起处理,以计算由这三个点确定的三角形 的周长和面积(图片由作者提供)。

给定这些等式,我们可以很容易地计算三角形度量,如周长和面积。下面的图 2 显示了顶点 A 在 90 秒内完成了一整圈,而顶点 B 摆动得更快,只需要 15 秒。随着顶点以不同的方式移动,三角形的面积和周长以某种混乱的方式变化。但它们确实显示出 90 秒的严格周期——因为 Ta 是 Tb 和 Tc 的简单倍数。

图二。 Ta=90,Tb=15,Tc=45。(A)顶点的坐标围绕其静止状态执行正弦运动(B)顶点沿着箭头线移动形成变形的三角形面积和周长以混沌的方式变化但具有预期的整体周期性(图片由作者提供)。

变形三角形的动画。任意时刻箭头的长度反映了该时刻顶点的移动速度*(图片由作者提供)。*

2.数据流

顶点的( x,y )坐标被发布到 Kafka 主题——数据流的源。实际测量时间是主题中事件的创建时间。但是事件是随机延迟的,所以以完全不同的顺序进入主题,如下面的图 3 所示。当然,每个测量的到达时间都严格地晚于创建时间。

图 3。射束处理的时间窗基于事件创建时间。事件到达流的顺序与它们的创建顺序非常不同。因此,多个时间窗口看到在给定处理时间到达它们的事件(图片由作者提供)。

图 3 显示了当事件到达主题/流时,时间窗口被事件填满。给定模拟的随机延迟,第一时间窗继续看到落入其中的事件,直到结束。最后一个时间窗口从一开始就看到一些事件。下面的图 4 显示了其中一个模拟中的活动生产订单与到货订单。

图 4。测量事件被模拟为具有随机延迟,因此它们以非常不同的顺序到达流中。例如,顶点 A 的第一个测量事件在超过 10000 个其他测量已经进来之后出现在流中。相同事件时间的 B 和 C 顶点的测量直到 25000 个其他事件进来之后才进来。因此,严格来说,在那之前,第一个三角形的良好定义是不可用的。这是耦合数据流的典型问题。

在理想情况下,从第一个事件落入该窗口的时刻起,每个时间窗口只需要在其宽度的持续时间内保持打开。但是考虑到这里的无序和迟到,时间窗口需要保持打开更长时间,以避免数据丢失。

3.流处理

流处理的目标是计算作为时间函数的三角形的面积和周长。这要求首先在每个时间窗口中识别一个三角形。一个定义明确的三角形要求所有三个顶点的位置同时为。由于三台监视器没有进行同步测量,我们需要估计每个顶点在同一时刻的位置,比如它们所在时间窗口的中点。**

图 5。首先通过顶点(每个时间窗口)对事件进行分组,以便估计其在窗口中点时间的位置。通过顶点和窗口,处理是并行的。然后,根据公共时刻对它们进行重新分组,以组装定义三角形和发射度量所需的三个顶点(图片由作者提供)。

图 5 展示了我们通过数据得到我们想要的东西的机制。Beam 提供了方便的 IO 模块来与各种数据源和接收器对话。在这里,我们从 Kafka 主题中读取事件,并最终将指标写入 Elasticsearch 进行分析。上面的每一步(除了“应用窗口”之外,它只是在窗口中按事件时间对数据进行分组)都将一个元素集合作为输入,并将它们转换成另一个元素集合,然后提供给下一步。

3.1 键是 同时并行的键

选择(如果数据中不存在,则构建)正确的键来对数据进行分组对于确保时间上的局部性和同时性非常重要。以顶点为关键字进行分组首先为下一个处理步骤固定顶点,该步骤计算并发出所有顶点在某个公共时刻(如窗口中点)的估计位置。按该时刻分组会在同一时刻产生三个顶点,用于下一步定义三角形并计算该时刻的度量。

此外,并行性从顶点的数量切换到时间窗的数量。对于每个变换步骤,光束平行度内置于元素级别。我们的元素是键值对。例如,如果我们正在监控 10 个三角形法兰的数据,第一个分组可以产生 30 个并发执行。并且,如果我们选择在每个时间窗口内的 5 个瞬间估计顶点位置,第二组产生的潜在并行度是操作窗口数量的 5 倍。

3.2 估算插值

虽然这与波束无关,但我们这里的具体问题要求我们在估计窗口中点时间的顶点位置时要小心。我们可以尝试一个简单的平均值,但这只适用于顶点的位置在时间窗口的持续时间内没有太大变化的情况。更好的方法是如图 6 所示进行插值,从估算时刻的任意一侧选取几个最接近的测量值。

图 6。线性插值可以给出比简单平均更好的估计值分段三次曲线可以进一步提高估计值。

此外,快速变化的量显然需要足够薄的时间窗来捕捉其动态,并在时间窗内用分段线性或(可能是三次样条)来近似它。

3.3 触发器

时间窗继续收集折点,直到不再有折点,此时时间窗将关闭。但是没有必要等到那个时候,因为我们可以触发窗格来不时地发出它的内容。当一个窗口触发时,它发布它的内容,以便后续步骤获得一个新的元素集合来处理,并且一些三角形度量被发布出来用于分析。定期触发允许尽早(如果是近似的)立即获得度量。**

窗口可以选择累积它的内容(就像我们在这里做的一样),即使是在周期性地发出它们之后。这意味着随着图 6 中的估计值越来越接近精确值,度量的持续改进是可能的。

3.4 管道代码

这里运行这些模拟的完整代码可以从 github 获得。为 Beam 设置的管道值得一看,以确认它与图 5 和图 6 中描述的内容相一致。

4.结果

对于顶点的两组不同的周期,每次都采用两种不同的估计方法(平均或插值)来获得结果。在第二组中,顶点的移动速度是第一组的三倍,这是为了突出插值策略的影响。因此总共运行四次,每次运行 360 秒,Beam 使用 1 秒的固定时间窗

  1. Ta=90,Tb=15,Tc=45。通过线性插值估计中点顶点
  2. Ta=90,Tb=15,Tc=45。通过以下方式估计中点顶点:简单平均
  3. Ta=30,Tb=5,Tc=15。通过线性插值估计中点顶点
  4. Ta=30,Tb=5,Tc=15。通过以下方式估计中点顶点:简单平均

图 7 显示了基本情况(运行 1)的周长与时间的函数关系。这基本上验证了这里用于处理三个耦合流以计算全局度量的整个方法。

图 7。周长与已知解析解的一致性非常好(图片由作者提供)。**

由于比例的原因,在上图中很难看到,但是所有时间窗口中的第一个和最终计算的周长值与精确值非常接近。让我们更仔细地看看这个问题。图 8 显示了所有四种情况下计算面积与精确面积之比随时间的变化情况。理想情况下,我们希望它是 1.0。

图 8。在时间窗口中累积事件改进了窗口寿命期间的预测。插值时,度量的最终计算值与精确值(8.1 和 8.3)非常一致,即使在快速变化的度量(8.3)的情况下,第一个计算值也只有大约 5%的误差。使用分段三次样条插值可能会有进一步的帮助。相比之下,当求平均值时,我们看到最终计算值的误差高达 25%,首次计算值的误差高达 40%(8.4)(图片由作者提供)。**

图 9 展示了从给定时间窗口开始的计算指标的演变。有点类似于图 8,但是包括了在时间窗的生命周期内发射的屈光不正的所有(即不仅仅是第一个和最后一个)值。当我们积累顶点时,我们再次希望看到改进。我们在插值的情况下会这样做,而在求平均值时不会这样做。

图 9。不同时间窗口发出的指标显示为处理时间的函数。随着处理时间的增加,我们希望该比率接近 1.0。当插值(9.1 & 9.3)时,我们确实看到稳定而快速地收敛到 1.0。(图片作者)。**

5.结论

耦合的数据流需要一起分析,要特别注意事件时间的同时性和控制数据流的其他过程特定变量。借助于一个已知精确解的测试问题,我们已经表明,用波束进行流水线处理可以精确地获得它们。

Apache Beam 提供了应对与处理耦合数据流相关的许多挑战的方法——无论是根据需要切换键以适应处理、允许延迟到达,还是启用早期度量等……加上元素级别的内置并行性和管道在不同运行器上执行的可导出性,使得 Beam 对于大规模流处理非常有吸引力。

原载于 2021 年 9 月 7 日 http://xplordat.com**

您可能不知道的位置编码概念

原文:https://towardsdatascience.com/concepts-about-positional-encoding-you-might-not-know-about-1f247f4e4e23?source=collection_archive---------9-----------------------

关于 Transformer 中的位置编码,您只需要知道

在 Unsplash 上由 corina ardeleanu 拍摄的照片

在 LSTM RNN,单词是按顺序输入的,因此它能理解单词的顺序。随着刑期的增加,在 LSTM 复发将需要大量手术。但是在 transformer 中,我们并行处理所有的单词。这有助于减少培训时间。为了记住单词的顺序,引入了位置编码的概念。这是一种表示单词位置的编码。简而言之,我们将位置编码添加到现有的单词嵌入中,这将为我们提供最终的预处理嵌入,它将用于编码器部分。

注意:- 在开始这篇博文之前,我强烈推荐访问我之前关于变形金刚 概述的 博文。

位置嵌入的不同技术:-

  1. 位置嵌入=单词索引

在这种情况下,如果句子的长度是 30。那么对应于每个单词,索引号可以是它的位置嵌入,如下图所示:-

在这种情况下,如果句子的长度是 30。那么对应于每个单词,索引号可以是它的位置嵌入,如下图所示:-

位置嵌入和单词嵌入相加得到最终嵌入**(作者的**图片)

我们可以使用这种编码方式,但问题是随着句子长度的增加,位置嵌入的大值支配了原始单词嵌入,因此扭曲了单词嵌入的值。因此,我们在自然语言处理任务中放弃了这种方法。

2。位置=句子长度的分数。

如果我们将嵌入值转换为长度的一部分,即 1/N,其中 N=字数,它应该可以工作,因为值将被限制在 0 和 1 之间。这里唯一的漏洞是,当我们比较两个不同长度的不同句子时,对于一个特定的索引,位置嵌入值是不同的。一般来说,对于不同长度的句子,位置词嵌入对于特定的索引应该具有相同的值,否则会扭曲对模型的理解。因此,对于我们的自然语言处理任务,我们放弃了这种方法,而采用基于频率的位置编码方法,正如在原始论文“注意力是你所需要的全部”中提到的。

3。基于频率的位置嵌入

该论文的作者提出了一个独特的想法,即使用波频率来捕捉位置信息。

正弦函数(图片由作者提供)

对于第一位置嵌入,

位置=0

d=嵌入的大小,应等于现有嵌入的尺寸。

i=每个位置嵌入维度的索引,也表示频率(i=0 是最高频率)

位置嵌入(作者图片)

在第一个正弦曲线图中(其中 i=4),我们绘制了具有不同位置值的正弦曲线,其中位置表示单词的位置。由于正弦曲线的高度取决于 x 轴上的位置,我们可以使用高度来绘制单词位置。由于曲线高度以固定长度变化,且不依赖于文本长度,这种方法有助于克服前面讨论的限制。请查看这个令人敬畏的视频了解更多。

值介于-1 和 1 之间。并且随着长度的增加,位置编码值保持不变。但是在从下面看的平滑正弦曲线中(其中 i=4),我们看到 y 轴上的字位置 0字位置 5 的距离非常小。为了克服这一点,我们提高了频率(freq =秒内完成的周期数)。如果我们这样做,那么在上面的第一条正弦曲线(i=0)中,我们看到位置 0位置 5 之间的距离清晰可见。

作者使用了正弦和余弦函数的组合来获得这些嵌入。

波频(图片由作者提供)

让我们编码这个

用于生成位置嵌入的代码(图片由作者提供)

输出预览为:-

以上代码输出(图片由作者提供)

这里我们可以看到第一个和第二个单词的接近度/紧密度很高,因此余弦相似度很高,而第一个和第九个单词之间的距离很远,因此余弦相似度很低。

这就是位置编码,如果你喜欢,可以和你的朋友分享。在那之前,

乳腺癌诊断的概念主成分分析与内在主成分分析

原文:https://towardsdatascience.com/conceptual-vs-inbuilt-principal-component-analysis-for-breast-cancer-diagnosis-7ec3a8455201?source=collection_archive---------34-----------------------

在 PCA 中拟合特征值、特征向量和 python 内置函数的概念,然后使用 ML 模型来测量乳腺癌(Wisconsin)数据集的高级精度参数。使用 2 个聚类和 4 个分类模型进行分析。

在 Unsplash 上由斯特凡·斯特凡·契克拍摄的照片

简介:

我们这些热衷于通过 python 探索世界的数据科学爱好者知道,python 只用几行代码就使主成分分析变得非常容易。但是我们不能忘记选择主成分背后的基本概念。在本文中,在将机器学习模型应用于聚类和分类之前,我已经以两种方式实现了 PCA 一种是计算特征值和特征向量,另一种是使用传统的 scikit-learn 工具。

在深入研究这些方法之前,让我先问你两个非常简单的问题:

为什么要处理一个庞大的数据集,使计算成为一项艰巨的任务?

为什么不减少它,同时保留它所提供的几乎所有有价值的信息呢?

这就是 PCA 用匕首来拯救你的地方,它砍掉了数据,减少了数据的维数,使分析更容易,同时保留了手头数据的统计数据。现在你可能会想,PCA 是如何决定哪些变量要删除,哪些要保留的呢?那就是降维的妙处;它不是删除变量,而是将信息组合成新的主成分,这些主成分是原始变量的线性组合。是的,准确性确实受到了一点影响,但获得的简单性更有价值。

当你在思考的时候,让我为你描绘一个非常简单的场景..

假设你打算很久以后去见你的学校朋友。他们在家里急切地等着你。但是,你的朋友圈挺大的,去他们各自的住处拜访,会占用相当多的时间和精力。你能想到的直接解决办法是什么?这时你决定给他们每个人打电话,约他们在附近的咖啡馆见面。这样,你可以用最少的时间和精力去结识所有的朋友,而不必排除任何人。这不就和上面的解释差不多了吗?

PCA 以这样的方式构造新的变量或主要成分,即大部分信息被塞入第一成分,而最大信息保留在第二成分中,以此类推。它创建了与原始变量相同数量的组件,但是每个组件中包含的信息量随着组件数量的增加而减少。一个简单的图表将帮助您直观地了解主成分如何解释数据中的最大总方差。当我们在数据集上实现它时,这幅图将会变得更加清晰。

我们将要处理的数据集-

我选择了一个维度足够大的数据集来应用 PCA,因为所有真实世界的数据,无论是结构化的还是非结构化的,都是巨大的。Kaggle 的“乳腺癌(威斯康星州)”数据集包含了癌症和非癌症患者的数据。我已经分享了数据的链接-【https://www.kaggle.com/uciml/breast-cancer-wisconsin-data*。*

分析是在 Python (Google colab)上实现的,这里是我在 GitHub 中的代码的链接

https://github . com/debangana 97/Data-science-works/blob/main/Breast _ cancer _ diagnosis _ using _ PCA _ two _ ways . ipynb

从文件中可以明显看出,有 569 行和 30 列,也就是说,30 个不同的变量对应于关于患者的 30 个不同特征的信息。这些特征有助于确定患者是否患有乳腺癌。然而,同时检查所有 30 个变量来预测未来患者的状况是非常乏味的,并且容易出错。对癌症的错误预测是医生最不想做的事!

目标:

这一分析的主要目标可以清楚地表明在以下几点:-

  1. 使用主成分分析来降低数据的维数仅仅意味着主成分分析将把 30 个变量组合成更小的主成分
  2. 根据通过主成分分析获得的新变量(主成分)对数据进行聚类
  3. 检查减少的数据是否可用于分类
  4. 基于分类模型的精确度找到主成分的最佳数量

既然我们已经清楚了这篇文章的主要目的,那就让我们开始吧。

准备数据..

数据预处理或数据清理是数据分析中最重要的先决条件之一。数据的适当准备将导致可靠和可理解的结果。这里有几个步骤,我发现对我的分析是必要的-

  • 删除对研究没有帮助的不必要的列
*#removing the unnecessary columnsexclude = ['Unnamed: 32','id']data = data.drop(exclude, axis = 1)*
  • 检查缺少的值。非常幸运的是,我的数据集中没有丢失值,因此我可以使用整个原始数据,而不必操作任何点
  • 检查数据不平衡

图 2:显示每一个班级人数的计数图

  • 将数据分为训练集和测试集,其中 20%的数据被保留用于测试模型的性能,其余的用于训练。训练集的大小为 455 行 30 列
  • 将训练数据分成两个独立的数据帧。因变量/目标变量(y)包括癌症结果,即数据的*‘诊断’*列,特征变量(x)包括患者的所有特征
  • 训练集和测试集中的特征矩阵 x 的标准化是为了更好的计算和无偏的结果。 StandardScalar 包用于数据的集中和规范化
*#standardization or feature scaling of the matrix of features X does both centering and normalizing of the datafrom sklearn.preprocessing import StandardScalersc = StandardScaler()
x_train_std = sc.fit_transform(x_train)
x_test_std = sc.fit_transform(x_test)*
  • 对分类变量“y”进行编码

主成分分析:

方法 1

在进行 PCA 之前,有必要将数据标准化。标准化确保每个原始变量对分析的贡献相等。这种降维方法对原始变量的方差非常敏感,其中值范围较大的变量将比范围较小的变量占优势,因此结果将趋于有偏差。此步骤以这样一种方式转换变量,即整个训练数据的平均值为 0,标准偏差为 1。

*print(np.mean(x_train_std))
print(np.std(x_train_std))**Output:** 4.021203394686281e-17 
        1.0*

在 python 中,我计算了协方差矩阵。矩阵中的正负符号表明特征变量之间是直接相关还是反向相关。

从线性代数的知识中,从这个矩阵中,我们可以构造特征向量,这些特征向量实际上是新轴的方向,其中有最多的信息(最高方差)并且被称为主分量。它们对应的特征值是特征向量的系数,表示每个主分量传递的信息量(方差)。

那么现在应该选择哪些组件呢?

想..

想..

正确!有最大特征值的那些,对吗?

我选择了具有最高特征值的两个分量,并基于这两个分量绘制了显示“恶性”和“良性”之间的区别的二维图。在这里,我也使用不同的组件进行了一些试验,看看哪一对组件能更好地显示这两类患者。

  • 第一次投影在第一和第二主分量的平面上。第二次投影在第二和第三主分量的平面上。

图:基于第一和第二主成分绘制了由两类患者分组的数据

图:基于第二和第三主成分绘制了由两类患者分组的数据

  • 从图中可以清楚地看到,第一种投影更好地分离了类别。这是一个明显的结果,因为第一分量包含最高比例的信息。

尝试使用第一个和第三个组件绘制图表。你得到了什么?成绩提高了吗?

方法二

接下来,我使用 scikit-learn 直接执行主成分分析,这在第一种方法之后看起来非常容易。Python 完成了上述所有计算,并最终向我们展示了一个图表(scree plot ),按照解释的变化百分比顺序显示了主要成分。该图显示累计约总变化的 73%仅由 前三个分量解释。

图:显示 30 个组成部分中每一个解释的变化百分比的 Scree 图

为了与方法 1 的结果进行比较,我绘制了显示基于前两个主成分的两个不同类的数据,这给出了与不直接使用 scikit-learn 的结果相似的可视化。因此,这两种方法表现得一样好,python 已经和人脑不相上下了!

图 5:Python scikit-learn 给出了一个与上图类似的图表

下一步是什么?..

现在数据从 30 个变量减少到 3 个变量,定义了一个新的特征向量,它包含作为列的三个分量的特征向量。因此,新特征向量的维数是 455(行)乘 3(列)。

*#transforming the data to the reduced dimension data
#this is the data that we are going to work with during the analysispca_data = pca.fit_transform(x_train_std)print('The reduced data is of the dimension: ', pca_data.shape)**Output:** The reduced data is of the dimension:  (455, 3)*

我要实现的第一个机器学习算法是 K-Means 聚类和层次凝聚聚类模型。粗略地说,聚类是一种无监督的 ML 算法,并且不需要任何训练,因为它基于特征变量创建整个数据的聚类。现在让我们看看这些模型如何在我们的数据集上工作。

K 均值聚类与层次聚类-

在确定聚类之前,我们如何决定要将数据分成多少个聚类?集群应该以这样的方式形成,即它们之间是同质的,同时与其他集群共享异质性。

在 K-Means 聚类中,我们使用肘方法图中聚类平方和内的*,找到最佳聚类数。你为什么要问?看一下图,你会注意到曲线形状像一个肘部,因此得名。但是我们如何决定是使用 2 个、3 个还是 5 个集群呢?***

图:弯头方法图

为了消除这种困惑,我使用了一种叫做轮廓分数的度量标准,它测量一个聚类中的每个点与相邻聚类中的点的接近程度。侧影分数+1 表明该点离相邻聚类非常远,从而表明这些聚类是不同的,而分数 0 表明该点与另一个聚类中的点重叠或者离它们不是非常远。因此,显然,对应于最高轮廓分数的聚类数是分析的最佳选择。

图:每个聚类数的轮廓分数

从图中可以看出,2 个集群给出了最好的结果。

对于聚类的分层方法,它使用树状图来确定最佳的聚类数目,这显著地表明 2 个聚类将给出有希望的结果。

*#Using dendrogram to find the optimal number of clustersimport scipy.cluster.hierarchy as sch
dendrogram = sch.dendrogram(sch.linkage(pca_data, method = 'ward'))*

图:树状图

在下面的代码行中,使用 2、3、4 和 5 个集群对这两种方法进行了彻底的比较。在可视化技术的帮助下,集群以不同的颜色呈现。这些图表确实引人注目,不是吗?

***

图:使用 3 个集群完成的集群* ***

图:使用 5 个集群完成的集群*

随着集群数量的增加,它们开始相互重叠。

我使用了另一个被称为 Davies-Bouldin 指数的验证指标来确定最佳的集群数量。它评估聚类分散和聚类分离之间的比率。

那么,你认为这个指数的理想值是多少?

如果群集定义明确、紧凑且独特,则群集分散肯定小于群集间隔。因此,您认为 DV 指数值越低,表示聚类越好,这是正确的。下表给出了不同 k 值的戴维斯-波尔丁指数及其各自的质心坐标。如前所述,该索引值最小的那个是聚类的最佳选择。

图 2:显示不同数量的聚类的 DV 指数的表格,并附有聚类坐标

从上面的讨论和后面的表格中可以明显看出,对于 k = 2,聚类将给出最好的结果。

聚类和分类可以一起应用吗?

机器学习的基础知识将允许我们问自己,虽然聚类是一种无监督的 ML 算法,但分类是一种有监督的算法,那么两者如何应用于同一数据集?数据是否预先标记?我们可以为未标记的数据生成标签吗?

一旦我们计算出聚类的纯度度量,就可以给出这些问题的答案。在得到结果之前,我将告诉你一些关于这个指标和它是如何工作的。

  • 差的聚类将具有接近 0 的纯度值。纯度分数的最高值是 1,其中值 1 意味着每个文档都有自己的聚类。这意味着每个文档都有自己的标签。正如我们所知,分类是一种受监督的机器学习算法,其中类别是预先标记的,因此如果聚类的纯度是 1,这意味着它可以用于分类。
  • 一般来说,当簇的数量大时,高纯度容易实现。然而,如果纯度等于 1,那么形成簇就没有意义。
  • 在我们的例子中,我计算了 K-均值聚类和层次凝聚聚类的这个度量,聚类的数量= 2、3、4 和 5,并且发现在所有情况下纯度值都接近 1。因此,即使集群数量较少,我们也可以应用分类。

K-NN 分类或者 Logistic 回归或者支持向量机,谁分类最好?

因为纯度指标证实了分类模型可以有效地处理数据,所以我决定使用四种不同的模型来比较结果。目标变量(y)显示患者是否被诊断为乳腺癌。它是一个二元变量,其中“M”代表恶性,“B”代表良性。标签编码有助于数据的分类和可视化。对于每个模型,我使用了不同数量的组件,分析了结果,并以表格的形式展示了结果。

*#Encoding the target variablefrom sklearn.preprocessing import LabelEncoder
le = LabelEncoder()y_train = le.fit_transform(y_train)y_test = le.fit_transform(y_test)*

分类结果的可视化是一种享受!使用 2 个主要成分,我已经展示了一些迷人的图表供你欣赏..

***

图 2:训练集和测试集上的 K-最近邻分类器* ***

图:训练集和测试集的逻辑回归* ***

图:训练集和测试集上的线性 SVM* ***

图:训练集和测试集上的径向基函数(核)SVM*

嗯,一口气画了很多图!但是你能指出它们之间的一些区别吗?看起来线性分类器在这个数据集上会工作得更好。

使用不同数量的主成分,我已经应用分类模型回到回答我们的主要问题- 我们实际上需要多少个主成分?

从分类分析中获得的准确度结果(百分比)可列表如下-

图 2:显示特定于主成分数量的每个分类模型的总体准确度的表格

如果我们仔细研究这张表,可以得出以下几点结论

  • 对于两个主成分,K-NN 给出最高的精确度,而核 SVM 给出最低的精确度
  • K-NN 对 4 个分量达到最大精度,此后开始下降
  • 使用 4 个主成分,线性 SVM 导致大约 96%的最大准确度
  • 当考虑 4 个主成分时,逻辑回归也能够获得大约 95%的准确度,此后,它保持恒定
  • 使用 4 个主成分,核 SVM 提供了大约 94%的准确度
  • 由核 SVM 结果获得的总体精度低于由线性 SVM 获得的精度,这表明这两类可以通过直线更好地分开

我添加的一些其他可比指标包括-

**混淆矩阵:这是一个 2x2 的列联表,显示模型做出的正确预测数和错误预测数

**每个单独类别的准确度分数:计算模型预测每个类别的准确度

**平均类别特定准确度:上面计算的单个准确度的平均值

**预测正值得分:被模型预测为患有癌症的患者实际患有癌症的概率。

去看看我提供的全部代码,你肯定会理解这些价值。

总结我们可以说..

因为我们的目标是在保留最大信息量的同时降低数据的维数,所以我认为可以肯定地说主成分的最佳数量应该是 4。

你不这么认为吗?

我希望阅读这篇文章有助于您的数据科学知识库,并帮助您获得更深入的见解。因此,请记住,从下次开始,如果你可以用较少的食物提供相同的营养,就不要过量进食你的 python 练习册..谢谢大家!

概念化是认知的基础——人类和机器

原文:https://towardsdatascience.com/conceptualization-as-a-basis-for-cognition-human-and-machine-345d9e687e3c?source=collection_archive---------14-----------------------

机器理解和认知人工智能的缺失环节

图片由杰基·尼亚姆在土坯股票上提供

虽然大多数当代对人工智能能力的讨论和分类都围绕着一个系统能够做什么,但我相信通向更高智能和机器认知的道路依赖于一个系统能够知道和理解什么 。使用丰富的人工智能知识表示框架和全面的世界模型可以增加人工智能系统将信息转化为深层知识、理解和功能的能力。为了追求更好的人工智能,理解“理解”对人脑的真正意义是必不可少的。这样做可以实现框架,通过将建模和概念化与数据和任务概括相结合,使机器学习能够平行于人类理解。

概念化:人类思维的基础

概念是人类思维中最基本的积木。概念是我们思考的对象的本体论根源。概念代表一个对象类的一组持久的基本属性,这些属性可以随着经验而改变和扩展。现有的概念可以被抽象或通过类比链接到附加的域和对象类。概念的例子包括|狗|、|民主|、|白|和|大叔|。物理或精神对象可以存储为一个概念,并随着时间的推移积累更多的数据和属性(例如|我的幸运狗|和|白雪公主|对|灰白色|)。即使所指对象是不可见的或抽象的,如|love|,它仍然可以作为一个概念存储。我们对世界的理解依赖于概念、概念的属性以及概念之间的关系。我们用概念和由概念组成的事实以及它们之间的关系来构建我们的世界模型。

概念是独特的,因为它们可以包含代理可用的任何类型的信息,并且可以在没有先验知识的情况下形成。想象一下,走进教室,老师说,“今天,我们将学习格查尔。”一个新概念的占位符已经在学生的头脑中形成,除了名称之外没有任何信息。“这是一只小小的热带鸟,”老师继续说道。大量可能的信息现在被添加到这个概念中——它可能非常丰富多彩,可能生活在森林中,并发出有趣的声音。概念具有弹性和持久性,弹性是有界限的,不允许概念变得面目全非。

概念的存在与描述它们的语言相关,但又独立于它们。例如,单词“dog”是概念|dog|的属性(有时称为标记)。即使你用一个不同的词来形容邻居院子里让你睡不着觉的毛茸茸的东西,它仍然是一只|狗。

作为另一个例子,概念|banana|可以从代表香蕉的各种图像的抽象特征开始——绿色的或成熟的、整个的或切片的、单独的或与其他物体相互作用的。概念|香蕉|还可以包括历史和故事(香蕉叶裙、香蕉船)、价值观(营养)、在餐桌上坐几天后的成熟程度,或者它的内涵(香蕉)。在地球上的大多数语言中,香蕉这个概念都是由一个名称来表示的,但它并不是这些名称中的任何一个。

在提出的 6 个知识维度的模型中,一个概念被捕获为一个抽象的概念引用(第 6 个维度),它链接了该概念的所有实例化和引用。它指的是多模式方面,如视觉表现、成熟水果的气味、剥皮时的感觉(对于具有触觉功能的系统)、咬一口时的声音和味道等等。它将有多方面的知识:描述性的,包括分类法和事实;程序性的,包括怎么剥,怎么吃;关于其遗产的故事;与拥有或失去它相关的价值;等等。

1.香蕉的概念。

创造概念的过程——概念化——以三种方式之一发生:

教官指导。对人类来说,这包括向老师学习——例如,钢琴教师、生物学教授或足球教练。用机器学习的术语来说,这将是利用标记信息或来自系统设计者的直接输入的监督学习。

**自导自演。**人类通过观察结构良好的概念并将其内化来练习被动概念化。例子包括阅读一本介绍和描述新术语的书,观看两个人打排球,通过观察推断规则和目标。对于机器学习系统来说,这将是获取广泛可用的文本或观看描述和命名概念的视频,以便填充概念数据结构。

**内部。**这些都是通过分析你的现状而形成的概念,或隐或显。例如,攀岩者评估哪些路径是可航行的,哪些是太难的。从这个评估中,形成了|可通过性|的概念(参见图 2 中的例子)。同样,科学家仔细观察,将经验提炼到理论和概念框架中。对于机器学习系统来说,这将是自我发现(识别一个可以有效地模拟人工智能系统所看到的世界的抽象)。

2。抽象和类比允许概念在新的领域中重新应用。

关于如何概念化有许多,通常是相互矛盾的定义和理论。对于未来的人工智能系统,可以提供以下概念化的定义:在世界观知识框架内抽象和发展丰富概念结构的能力,以促进广泛的推理并产生新的知识和技能。

概括是认知人工智能的必要但不充分的属性

可以说 t oday 的深度学习忽略了概念,将泛化作为 AI 的终极目标。这种方法可能会导致认知机器学习的能力范围有限。机器学习系统必须学会概念化,以达到创造具有更高智能的机器的目标。

为了证实这一说法,让我们首先检查人工智能中的泛化在人工智能/机器学习的上下文中具体意味着什么(相对于外行人对该术语的使用),然后探索它与概念化有何不同。

**泛化概述:**在机器学习中,泛化是指经过训练的模型对未知数据进行分类或预测的能力。一般化的模型通常适用于所有看不见的数据子集。

古德费勒、本吉奥和库维尔讨论过拟合和欠拟合的概念。他们指出,对于机器学习算法来说,在新的、以前看不到的输入上表现良好是多么具有挑战性,这是泛化问题的核心。增加新的维度或抽象超出了这种概括观点的范围。例如,机器学习模型可以学习正确分类质数和非质数。然而,要得出一个类似于人类数学家对素数的抽象定义是不太可能的。

3。一个通用的算法学习一个既适合训练数据又适合验证数据的流形。

概括的两个重要方面是插值外推。插值在数学上定义为一种估计,一种在一组离散的已知数据点范围内构造新数据点的方法。外推定义为基于一个变量与另一个变量的关系,对该变量的值进行超出原始观察范围(训练集)的一种估计。在机器学习中,外推是一个在特定数据范围内训练的系统,可以预测不同范围的数据。

4。外推和内插是概括的重要方面。

Francois Chollet 将泛化的概念从数据扩展到任务。在他看来,一个系统的智能是通过其获得基于概括难度的任务技能的能力来衡量的:

系统的智能是对其在任务范围内技能获取效率的度量,与先验、经验和概括难度有关。

在他的模型中,Chollet 代表了执行任务能力方面的所有概括水平。

与概括不同,概念不一定与任务直接相关。一个人可以形成一个概念,而不用把它和一个任务联系起来。因此,智力的潜在方面可以用适用于目前未知任务的内在概念来表示。概念不一定只能通过任务中表现出来的行为来理解。

**现在的 AI 还不能说是执行概念化:**首先需要注意的是,概念化并不等同于分类。在机器学习中,分类指的是预测建模问题,其中为输入数据的给定示例预测类别标签。相比之下,概念是一组丰富的、多方面的相关知识,可以不断扩展。

以下标准定义了概念形成的范例,根据该范例,当前的机器学习算法不概念化:

容量和多样性。一个概念首先由它的本质来定义,然后由它的细节来进一步修饰。一个概念并不固有地局限于一组特定的描述符或值,而是可以累积几乎无限的维度——可以把它想象成一块海绵,随着时间和经验吸收相关的知识。例如,报名参加表观遗传学第一堂课的生物学学生可能对该领域一无所知,除了模糊地认识到它听起来类似于“遗传学”。随着时间的推移,随着学生了解朊病毒、核小体定位、糖尿病对巨噬细胞行为的影响、抗生素改变谷氨酸受体活性等,这个曾经非常稀疏的概念将变得更加多面化。这个例子与深度学习形成对比,在深度学习中,令牌或对象具有固定数量的维度。

坚持。一个概念保持不变,即使它的部分或大部分属性可以改变。相比之下,机器学习中令牌或对象的嵌入是由对象的维度(属性)来定义的。假设属性通过附加训练改变,潜在空间嵌入改变,并且潜在地,到其他嵌入向量的距离改变。在不改变固有概念的情况下,概念驱动的知识表示中的属性可能会有实质性变化,因为它反映在知识库中(例如,它在本体中的位置或与其历史的关联)。例如,一名律师可以卖掉他的法拉利,成为一名僧侣,改变他的大部分外在属性,但仍然是同一个人。当映射到基于特征的嵌入空间时,由于人工智能系统观察到的维度特征的变化,概念可能会移动。然而,使它成为一个特定概念的本质很可能不会改变。

**抽象。**这包括提供抽象的信息组织及其含义的能力,这种能力可以应用于完全不同的领域,与它所来自的数据领域无关。在处理|可通过性|的概念时,我们在博客前面介绍过,它可能是在攀岩经历中学到的。尽管如此,这一概念的抽象和属性允许它应用于一个完全不同的领域/空间,例如玩一个风险游戏或考虑联系其中最终能修好你的笔记本电脑的人。这种比深度学习的拟合功能高得多的抽象层次——以及跨不同空间识别类比和概念相似性的能力——是深度学习泛化实践所无法实现的“概念”的主要区分因素。

结论

一个系统吸收数据、抽象数据、扩展概念、增强内部建模能力和推理能力的能力是衡量智能的主要标准。与此同时,对学习任务的衡量表现是一种滞后的措施。一种将底层建模和知识表示(包括概念化)与数据和任务概括相集成的方法,将有可能为总体上更高的机器智能提供更好的途径。

参考文献

歌手 g(2021 a,4 月 6 日)。认知人工智能的崛起——走向数据科学。中等。https://towards data science . com/the-rise-of-cognitive-ai-a 29 D2 b 724 CCC

歌手 g(2021 年 5 月 6 日)。对深度知识的理解和运用——走向数据科学。中等。https://towards data science . com/understanding-of-and-by-deep-knowledge-aac5 ede 75169

维基百科贡献者。(2020 年 12 月 9 日)。概念化(信息科学)。维基百科。https://en . Wikipedia . org/wiki/概念化 _(信息 _ 科学)

墨菲(2004 年)。概念的大书。布拉德福德的书。

什么是机器学习中的泛化? (2021 年 2 月 25 日)。deepai . space .https://deepai . space/什么是机器学习中的泛化/

印第安纳州古德费勒、纽约州本吉奥和库维尔(2016 年)。深度学习。阿姆斯特丹大学出版社。

f . chollet(2019)。论智力的衡量。 ArXiv,abs/1911.01547

维基百科贡献者。(2021 年 8 月 31 日)。插补。维基百科。https://en.wikipedia.org/wiki/Interpolation

维基百科贡献者。(2019 年 8 月 21 日 a)。外推。维基百科。https://en.wikipedia.org/wiki/Extrapolation

布朗利,J. (2020 年 8 月 19 日)。机器学习中的 4 类分类任务。机器学习精通。https://machine learning mastery . com/types-of-class ification-in-machine-learning/

叶,A. (2020 年 6 月 26 日)。真正的人工智能:理解外推 vs 概括。中等。https://towards data science . com/real-artificial-intelligence-understanding-extrapolation-vs-generalization-b 8e 8 DC F5 FD 4b

Sharma,R. (1999 年)。卖掉自己法拉利的和尚。哈珀柯林斯。

Gadi Singer 是英特尔实验室副总裁,认知计算研究总监。

结论作为挖掘法律推理的锚

原文:https://towardsdatascience.com/conclusions-as-anchors-for-mining-legal-reasoning-6f837fb8da3c?source=collection_archive---------28-----------------------

思想和理论

通过检测结论来定位推理

图像由弗恩 r .沃克, CC 由 4.0 。

数据科学中的一个挑战性问题是从法律判决文件中挖掘推理。为了在整个文件中找到这种推理,我们可以利用判决对问题的结论来引导我们找到相关的证据、具体的推理和法律规则。研究表明,机器学习(ML)算法可以自动对陈述法庭事实结论的句子进行分类,精确度足以满足许多用例。因此,训练分类器来自动识别法律结论是重要的第一步。

一般来说,从文档中挖掘任何推理或论证的第一阶段是检测哪些句子起推理链的组成部分的作用(通常称为“论证句子”)以及哪些句子不起作用(“非论证句子”)。然后,一个议论文句子被归类为一个推理单元的“结论”或“前提”(支持结论的句子)。在斯蒂芬·图尔敏的《有影响力的模型》中(斯蒂芬·图尔敏,《论证的用途:更新版);剑桥大学出版社,2003 ),前提可以分为“数据”或“授权”。“数据”是推理所依据的事实,而“保证”是授权从事实到结论进行推理的条件或概括。为了对推理模式进行分类,我们最终需要确定哪些句子是同一推理单元的一部分,推理单元中推理关系的性质,该单元是哪种推理类型,等等。为了在所有这些任务上取得进展,我们可以从识别推理的结论开始,并且我们可以使用该结论来锚定我们的进一步搜索和分析。

同样的一般工作流程也适用于从法律文档中挖掘论点和推理。结论的类型、前提的类型和论证的类型因法律文件的类型而异。例如,在管理裁决中发现的推理类型经常不同于在上诉法院裁决中发现的类型,在初审法院裁决中发现的类型也不同。但是这些例子的共同点是,决策者需要使用语言来表明哪个句子陈述了法律结论。当事人、律师和审查法院需要能够确定是否所有的法律问题都得到了解决。在本文中,我引用了初审法院或机构的事实调查裁决的例子,但同样的分析也适用于其他类型的政府决定。我的例子来自退伍军人上诉委员会(BVA)的决定,该决定宣布了美国退伍军人因服役相关残疾而索赔的结论。

定义和识别特征

一个“法律认定”(也称为“事实认定”,或简称为“认定”)是由事实审判者根据案件中提出的证据对一个事实问题做出的正式裁定。事实的审理者可能是司法程序中的陪审团或法官,也可能是行政程序中的行政机构或官员。因此,“认定句”是主要陈述一个或多个事实认定的句子。因为实体法规则规定了需要裁决的事实问题,案件的裁决就是法庭对这些问题的裁决。换句话说,调查结果表明,在手头的法律案件中,实体法律规则的一个或多个条件是否得到满足。

以下是一个发现句子的示例(显示在由 Apprentice Systems,Inc. 开发的 web 应用程序中,黄色背景色用于编码发现句子):

图像由 Vern R. Walker, CC BY 4.0 。

我们律师如何知道哪些句子陈述了事实的发现?有一些典型的语言特征有助于提示一个发现的句子。例如:

适当的语言提示,用于将一个命题归因于事实的审理者(例如,“委员会发现,”或“法院确信”);或者

表示满足或未满足证明义务的词语或短语(例如,“未满足、“成功证明、“未能证明”);或者

表明法庭的法律任务已经完成的措辞(例如,在审查了所有证据之后的“”);或者

指代案件中涉及的特定人、地点、事物或事件的定名词短语,而不仅仅是用于陈述规则本身的不定类型(例如“老兵”而不是“老兵”)。

虽然法官可能不会使用特定的格式来书写判决,但通常有足够的语言特征使律师能够在判决中识别这样的句子。

此外,由于认定判决必然会宣布对有争议的法律问题的裁决,法官通常使用用于定义法律问题的关键术语来撰写认定判决。例如,考虑这个来自 Shedden 诉 Principi,381 F.3d 1163,1166–67(美联储。Cir。2004) (如学徒系统 web 应用程序所示,带有适当的背景颜色):

图片由 Vern R. Walker 拍摄, CC BY 4.0 。

第一句话(用浅红色突出显示)陈述了一个法律规则,第二句话(用浅橙色突出显示)提供了对法律权威的适当引用。在宣布对这三个编号条件的判决时,法官可以使用:

在陈述条件(1)的调查结果时,短语“目前无行为能力”或类似措辞;

条件(2)调查结果中的短语“运行中发生”或“运行中恶化”;和

条件(3)中的“因果关系”一词。

撰写判决的法官有强烈的动机清楚地表明哪些判决陈述了对哪些法律问题的调查结果。

此外,逻辑帮助我们识别寻找句子的集合。例如,对于要赢得决策的索赔老兵,在所有要求的规则条件上必须有积极的发现(对于老兵)。另一方面,如果老兵失去了决定,那么必须至少有一个负面的发现(针对老兵)。在这种情况下,因为一个否定的裁决就解决了索赔,法官甚至可能不会对其他条件做出明确的裁决。因此,逻辑帮助我们决定寻找多少发现。

机器学习(ML)数据集

但是,是否有足够的语言特征允许 ML 模型正确地识别和标记查找句子?为了回答这个问题, Hofstra Law's Law,Logic &技术研究实验室(LLT 实验室)人工标注了退伍军人事务委员会 50 个决定中的发现句(标注的数据在 GitHub 上公开)。LLT 实验室将任何包含事实认定的句子归类为认定句。这些决策包含了 5797 个经过预处理的人工标记的句子,其中只有 490 个是找到的句子。一个例子是这个复杂的发现句子(用黄色突出显示):

图像由弗恩 r .沃克, CC 由 4.0 。

如句子前面的图标所示,这句话来自一项决定的第 49 段,第一句。LLT 实验室将此标记为发现句,因为实验室优先考虑不忽略任何发现。但是这个复杂的句子也陈述了一些与该发现相关的证据和推理。如果需要更细粒度的分类,我们可以将复杂的查找句子至少分解到子句级别,然后对子句角色而不是句子角色进行分类。

机器学习结果

机器学习模型可以很好地对这些 BVA 发现句子进行分类。我们在 LLT 实验室的 50 个 BVA 决策数据集上训练了一个逻辑回归模型。模型对发现句进行分类,准确率= 0.81,召回率= 0.78 。我们后来在同一个 BVA 数据集上训练了一个神经网络(NN)模型。神经网络模型查找句子的精度为 0.75,召回率为 0.79。

误差分析

在由 NN 模型预测为发现句子的 173 个句子中,44 个是错误分类(精度= 0.75)。可以理解的是,最常见的混淆是推理句子,这占了几乎一半的错误(21)。推理句子通常包含与发现句子相似的推理措辞,但结论本质上是中介的。被训练的 NN 模型错误分类为发现句子的推理句子(以绿色突出显示)的示例是:

图片由 Vern R. Walker, CC BY 4.0 。

上图是来自法律学徒网络应用程序的一个屏幕截图(这个例子是一个判决的第 39 段的第二句话)。NN 模型的预测分数排列在句子文本的下面。如你所见,该模型预测这是一个发现句(得分= 37.18%),尽管它是一个推理句的预测得分为第二(24.64%)。

这个句子主要陈述推理而不是发现。理由是,延迟发病使现役退伍军人的遭遇和退伍军人当前残疾之间的因果关系的任何决定变得复杂。这句话没有说明调查结果,因为它没有告诉我们法庭对这个问题的最终裁决。然而,在解释这一复杂情况时,法庭使用了相关法律规则中的术语(见上文 Shedden 引文)。因此,预测分类为发现句并不令人惊讶。诸如此类的句子有助于解释 0.75 的低精度。

因为我们律师不想忽略任何实际的判决,回忆也是非常重要的。在神经网络模型的测试集中,有 163 个人工标记的发现句子。虽然其中的 129 个被正确识别(回忆= 0.79),但该模型未能识别其中的 34 个。毫不奇怪,该模型错误地预测了 34 个实际发现句子中的 15 个是推理句子。该模型预测另外 13 个实际发现的句子是证据句。以下句子(摘自一项决定的第 124 段,第二句)是模型将一个结论句(以黄色突出显示)错误归类为证据句的一个例子:

图像由弗恩 r .沃克, CC 由 4.0 。

尽管明确陈述了一个否定的发现(“不支持一个发现”),其余的措辞与陈述的证据非常一致。注意,作为证据句(39.04%)和发现句(36.11%)的预测分数在值上非常接近,这反映了混淆的接近程度。

用例的重要性

分类错误的实际成本取决于用例以及错误的类型。如果用例是提取和呈现法律推理的例子,那么上面提到的精确度和召回率对用户来说可能是可接受的。如果许多错误是由推理句子和发现句子的混淆组成的,这可能是特别真实的。如果用户有兴趣查看论证或推理的不同例子,被分类为推理或发现的句子可能仍然是说明性论证的一部分。

与这样的用例相比,如果目标是生成关于争论成功或不成功频率的统计数据,那么只有 0.75 的精度和 0.79 的召回率可能是不可接受的。确定一个问题的辩论是否成功的唯一方法是确定相关的事实发现,将其映射到适当的法律问题,并确定该发现是积极的还是消极的(其“极性”)。(可以看我们关于自动检测找句子极性的论文。)为了生成准确的统计数据,我们需要高度确信我们已经自动且准确地执行了这三项任务。

摘要

总之,判决是法律判决的重要组成部分。他们陈述法庭对法律问题的结论,并告知当事方其个别辩论的成败。寻找句子在法律规则和判决中适当的法律论据和推理之间架起了桥梁。这样的句子也为从判决中提取相关的证据、推理和法律规则提供了一个定位。换句话说,寻找句子可以引导我们找到证据和推理句子,这些句子作为一个单一的论证或推理单元结合在一起。